From c80f76f187106f646444083fcf2ab0352538378a Mon Sep 17 00:00:00 2001 From: Joyce Siqueira <98593770+the-right-joyce@users.noreply.github.com> Date: Tue, 29 Aug 2023 13:37:16 +0200 Subject: [PATCH 001/633] update polkadot, substrate, cumulus readme (#1182) * update readmes * temporary ReadMe for the Polkadot SDK * delete welcome readme * update links on substrate readme * update links on polkadot readme * update links on cumulus readme * update overseer feature comment Co-authored-by: Liam Aharon * Update cumulus/README.md Co-authored-by: Liam Aharon * Update cumulus/README.md Co-authored-by: Liam Aharon * Update polkadot/README.md Co-authored-by: Liam Aharon * Update polkadot/README.md Co-authored-by: Liam Aharon * Update polkadot/README.md Co-authored-by: Liam Aharon * update gitlab links Co-authored-by: Liam Aharon * terminal friendly convention --------- Co-authored-by: Liam Aharon --- cumulus/README.md | 271 ++++++++++++++++++++++++++++++++++++++++++-- polkadot/README.md | 264 ++++++++++++++++++++++++++++++++++++++++-- substrate/README.md | 45 ++++++-- 3 files changed, 559 insertions(+), 21 deletions(-) diff --git a/cumulus/README.md b/cumulus/README.md index 59e0cff015d..419e293a0ab 100644 --- a/cumulus/README.md +++ b/cumulus/README.md @@ -1,13 +1,270 @@ -Dear contributors and users, +# Cumulus ☁️ -We would like to inform you that we have recently made significant changes to our repository structure. In order to streamline our development process and foster better contributions, we have merged three separate repositories Cumulus, Substrate and Polkadot into a single new repository: [the Polkadot SDK](https://github.com/paritytech/polkadot-sdk). Go ahead and make sure to support us by giving a star ⭐️ to the new repo. +[![Doc](https://img.shields.io/badge/cumulus%20docs-master-brightgreen)](https://paritytech.github.io/cumulus/) -By consolidating our codebase, we aim to enhance collaboration and provide a more efficient platform for future development. +This repository contains both the Cumulus SDK and also specific chains implemented on top of this +SDK. -If you currently have an open pull request in any of the merged repositories, we kindly request that you resubmit your PR in the new repository. This will ensure that your contributions are considered within the updated context and enable us to review and merge them more effectively. +If you only want to run a **Polkadot Parachain Node**, check out our [container +section](./docs/container.md). -We appreciate your understanding and ongoing support throughout this transition. Should you have any questions or require further assistance, please don't hesitate to [reach out to us](https://forum.polkadot.network/t/psa-parity-is-currently-working-on-merging-the-polkadot-stack-repositories-into-one-single-repository/2883). +## Cumulus SDK -Best Regards, +A set of tools for writing [Substrate](https://substrate.io/)-based +[Polkadot](https://wiki.polkadot.network/en/) +[parachains](https://wiki.polkadot.network/docs/en/learn-parachains). Refer to the included +[overview](docs/overview.md) for architectural details, and the [Connect to a relay chain how-to +guide](https://docs.substrate.io/reference/how-to-guides/parachains/connect-to-a-relay-chain/) for a +guided walk-through of using these tools. -Parity Technologies \ No newline at end of file +It's easy to write blockchains using Substrate, and the overhead of writing parachains' +distribution, p2p, database, and synchronization layers should be just as low. This project aims to +make it easy to write parachains for Polkadot by leveraging the power of Substrate. + +Cumulus clouds are shaped sort of like dots; together they form a system that is intricate, +beautiful and functional. + +### Consensus + +[`parachain-consensus`](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/client/consensus/common/src/parachain_consensus.rs) +is a [consensus engine](https://docs.substrate.io/v3/advanced/consensus) for Substrate that follows +a Polkadot [relay chain](https://wiki.polkadot.network/docs/en/learn-architecture#relay-chain). This +will run a Polkadot node internally, and dictate to the client and synchronization algorithms which +chain to follow, +[finalize](https://wiki.polkadot.network/docs/en/learn-consensus#probabilistic-vs-provable-finality), +and treat as best. + +### Collator + +A Polkadot [collator](https://wiki.polkadot.network/docs/en/learn-collator) for the parachain is +implemented by the `polkadot-parachain` binary (previously called `polkadot-collator`). + +You may run `polkadot-parachain` locally after building it or using one of the container option +described [here](./docs/container.md). + +### Relay Chain Interaction +To operate a parachain node, a connection to the corresponding relay +chain is necessary. This can be achieved in one of three ways: +1. Run a full relay chain node within the parachain node (default) +2. Connect to an external relay chain node via WebSocket RPC +3. Run a light client for the relay chain + +#### In-process Relay Chain Node +If an external relay chain node is not specified (default behavior), then a full relay chain node is +spawned within the same process. + +This node has all of the typical components of a regular Polkadot node and will have to fully sync +with the relay chain to work. + +##### Example command +```bash +polkadot-parachain \ + --chain parachain-chainspec.json \ + --tmp \ + -- \ + --chain relaychain-chainspec.json +``` + +#### External Relay Chain Node +An external relay chain node is connected via WebsSocket RPC by using the +`--relay-chain-rpc-urls` command line argument. This option accepts one or more +space-separated WebSocket URLs to a full relay chain node. By default, only the +first URL will be used, with the rest as a backup in case the connection to the +first node is lost. + +Parachain nodes using this feature won't have to fully sync with the relay chain +to work, so in general they will use fewer system resources. + +**Note:** At this time, any parachain nodes using this feature will still spawn a +significantly cut-down relay chain node in-process. Even though they lack the +majority of normal Polkadot subsystems, they will still need to connect directly +to the relay chain network. + +##### Example command + +```bash +polkadot-parachain \ + --chain parachain-chainspec.json \ + --tmp \ + --relay-chain-rpc-urls \ + "ws://relaychain-rpc-endpoint:9944" \ + "ws://relaychain-rpc-endpoint-backup:9944" \ + -- \ + --chain relaychain-chainspec.json +``` + +#### Relay Chain Light Client +An internal relay chain light client provides a fast and lightweight approach +for connecting to the relay chain network. It provides relay chain notifications +and facilitates runtime calls. + +To specify which chain the light client should connect to, users need to supply +a relay chain chain-spec as part of the relay chain arguments. + +**Note:** At this time, any parachain nodes using this feature will still spawn +a significantly cut-down relay chain node in-process. Even though they lack the +majority of normal Polkadot subsystems, they will still need to connect directly +to the relay chain network. + + +##### Example command +```bash +polkadot-parachain \ + --chain parachain-chainspec.json \ + --tmp \ + --relay-chain-light-client \ + -- \ + --chain relaychain-chainspec.json +``` + +## Installation and Setup +Before building Cumulus SDK based nodes / runtimes prepare your environment by +following Substrate [installation instructions](https://docs.substrate.io/main-docs/install/). + +To launch a local network, you can use [zombienet](https://github.com/paritytech/zombienet) +for quick setup and experimentation or follow the [manual setup](#manual-setup). + +### Zombienet +We use Zombienet to spin up networks for integration tests and local networks. +Follow [these installation steps](https://github.com/paritytech/zombienet#requirements-by-provider) +to set it up on your machine. A simple network specification with two relay chain +nodes and one collator is located at [zombienet/examples/small_network.toml](zombienet/examples/small_network.toml). + +#### Which provider should I use? +Zombienet offers multiple providers to run networks. Choose the one that best fits your needs: +- **Podman:** Choose this if you want to spin up a network quick and easy. +- **Native:** Choose this if you want to develop and deploy your changes. Requires compilation +of the binaries. +- **Kubernetes:** Choose this for advanced use-cases or running on cloud-infrastructure. + +#### How to run +To run the example network, use the following commands: +```bash +# Podman provider +zombienet --provider podman spawn ./zombienet/examples/small_network.toml + +# Native provider, assumes polkadot and polkadot-parachains binary in $PATH +zombienet --provider native spawn ./zombienet/examples/small_network.toml +``` + +### Manual Setup +#### Launch the Relay Chain + +```bash +# Clone +git clone https://github.com/paritytech/polkadot-sdk + +# Compile Polkadot +cargo build --release --bin polkadot + +# Generate a raw chain spec +./target/release/polkadot build-spec --chain rococo-local --disable-default-bootnode --raw > rococo-local-cfde.json + +# Alice +./target/release/polkadot --chain rococo-local-cfde.json --alice --tmp + +# Bob (In a separate terminal) +./target/release/polkadot --chain rococo-local-cfde.json --bob --tmp --port 30334 +``` + +#### Launch the Parachain + +```bash +# Clone +git clone https://github.com/paritytech/polkadot-sdk + +# Compile +cargo build --release --bin polkadot-parachain + +# Export genesis state +./target/release/polkadot-parachain export-genesis-state > genesis-state + +# Export genesis wasm +./target/release/polkadot-parachain export-genesis-wasm > genesis-wasm + +# Collator1 +./target/release/polkadot-parachain --collator --alice --force-authoring --tmp --port 40335 --rpc-port 9946 -- --chain ../polkadot/rococo-local-cfde.json --port 30335 + +# Collator2 +./target/release/polkadot-parachain --collator --bob --force-authoring --tmp --port 40336 --rpc-port 9947 -- --chain ../polkadot/rococo-local-cfde.json --port 30336 + +# Parachain Full Node 1 +./target/release/polkadot-parachain --tmp --port 40337 --rpc-port 9948 -- --chain ../polkadot/rococo-local-cfde.json --port 30337 +``` + +#### Register the parachain + +![image](https://user-images.githubusercontent.com/2915325/99548884-1be13580-2987-11eb-9a8b-20be658d34f9.png) + + +## Asset Hub 🪙 + +This repository also contains the Asset Hub runtimes. Asset Hub is a system parachain +providing an asset store for the Polkadot ecosystem. + +### Build & Launch a Node + +To run an Asset Hub node, you will need to compile the `polkadot-parachain` binary: + +```bash +cargo build --release --locked --bin polkadot-parachain +``` + +Once the executable is built, launch the parachain node via: + +```bash +CHAIN=asset-hub-westend # or asset-hub-kusama +./target/release/polkadot-parachain --chain $CHAIN +``` + +Refer to the [setup instructions](#manual-setup) to run a local network for development. + +## Contracts 📝 + +See [the `contracts-rococo` readme](parachains/runtimes/contracts/contracts-rococo/README.md) for details. + +## Bridge-hub 📝 + +See [the `bridge-hubs` readme](parachains/runtimes/bridge-hubs/README.md) for details. + +## Rococo 👑 +[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is becoming a +[Community Parachain Testbed](https://polkadot.network/blog/rococo-revamp-becoming-a-community-parachain-testbed/) +for parachain teams in the Polkadot ecosystem. It supports multiple parachains with the +differentiation of long-term connections and recurring short-term connections, to see +which parachains are currently connected and how long they will be connected for +[see here](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/parachains). + +Rococo is an elaborate style of design and the name describes the painstaking effort that +has gone into this project. + +### Build & Launch Rococo Collators + +Collators are similar to validators in the relay chain. These nodes build the blocks that +will eventually be included by the relay chain for a parachain. + +To run a Rococo collator you will need to compile the following binary: + + +```bash +cargo build --release --locked --bin polkadot-parachain +``` + +Once the executable is built, launch collators for each parachain (repeat once each for chain +`tick`, `trick`, `track`): + +```bash +./target/release/polkadot-parachain --chain $CHAIN --validator +``` + +You can also build [using a container](./docs/container.md). + +### Parachains + +* [Asset Hub](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-statemint-rpc.polkadot.io#/explorer) +* [Contracts on Rococo](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-contracts-rpc.polkadot.io#/explorer) +* [RILT](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo.kilt.io#/explorer) + +The network uses horizontal message passing (HRMP) to enable communication between +parachains and the relay chain and, in turn, between parachains. This means that every +message is sent to the relay chain, and from the relay chain to its destination parachain. diff --git a/polkadot/README.md b/polkadot/README.md index 59e0cff015d..8f0809c9fc7 100644 --- a/polkadot/README.md +++ b/polkadot/README.md @@ -1,13 +1,263 @@ -Dear contributors and users, +# Polkadot -We would like to inform you that we have recently made significant changes to our repository structure. In order to streamline our development process and foster better contributions, we have merged three separate repositories Cumulus, Substrate and Polkadot into a single new repository: [the Polkadot SDK](https://github.com/paritytech/polkadot-sdk). Go ahead and make sure to support us by giving a star ⭐️ to the new repo. +Implementation of a node in Rust based on the Substrate framework. -By consolidating our codebase, we aim to enhance collaboration and provide a more efficient platform for future development. +> **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. -If you currently have an open pull request in any of the merged repositories, we kindly request that you resubmit your PR in the new repository. This will ensure that your contributions are considered within the updated context and enable us to review and merge them more effectively. +[substrate-repo]: https://github.com/paritytech/substrate -We appreciate your understanding and ongoing support throughout this transition. Should you have any questions or require further assistance, please don't hesitate to [reach out to us](https://forum.polkadot.network/t/psa-parity-is-currently-working-on-merging-the-polkadot-stack-repositories-into-one-single-repository/2883). +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). -Best Regards, +## Installation -Parity Technologies \ No newline at end of file +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 +commands as the `root` user. + +```bash +# Import the security@parity.io GPG key +gpg --recv-keys --keyserver hkps://keys.mailvelope.com 9D4B2B6EB8F97156D19669A9FF0812D491B96798 +gpg --export 9D4B2B6EB8F97156D19669A9FF0812D491B96798 > /usr/share/keyrings/parity.gpg +# Add the Parity repository and update the package index +echo 'deb [signed-by=/usr/share/keyrings/parity.gpg] https://releases.parity.io/deb release main' > /etc/apt/sources.list.d/parity.list +apt update +# Install the `parity-keyring` package - This will ensure the GPG key +# used by APT remains up-to-date +apt install parity-keyring +# Install polkadot +apt install polkadot + +``` + +## Building + +### Install via Cargo + +Make sure you have the support software installed from the **Build from Source** section below this +section. + +If you want to install Polkadot in your PATH, you can do so with: + +```bash +cargo install --git https://github.com/paritytech/polkadot-sdk --tag polkadot --locked +``` + +### 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: + +```bash +git checkout +./scripts/init.sh +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: + +```sh +cargo install --path . --locked +``` + +#### Build from Source with Docker + +You can also build from source using [Parity CI docker image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux): + +```bash +git checkout +docker run --rm -it -w /shellhere/polkadot \ + -v $(pwd):/shellhere/polkadot \ + paritytech/ci-linux:production cargo build --release +sudo chown -R $(id -u):$(id -g) target/ +``` + +If you want to reproduce other steps of CI process you can use the following +[guide](https://github.com/paritytech/scripts#gitlab-ci-for-building-docker-images). + +## Networks + +This repo supports runtimes for Polkadot, Kusama, and Westend. + +### Connect to Polkadot Mainnet + +Connect to the global Polkadot Mainnet network by running: + +```bash +./target/release/polkadot --chain=polkadot +``` + +You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). + +[telemetry]: https://telemetry.polkadot.io/#list/Polkadot + +### Connect to the "Kusama" Canary Network + +Connect to the global Kusama canary network by running: + +```bash +./target/release/polkadot --chain=kusama +``` + +You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). + +[telemetry]: https://telemetry.polkadot.io/#list/Kusama + +### Connect to the Westend Testnet + +Connect to the global Westend testnet by running: + +```bash +./target/release/polkadot --chain=westend +``` + +You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). + +[telemetry]: https://telemetry.polkadot.io/#list/Westend + +### 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. + +## 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 +``` + +Then, grab the Polkadot source code: + +```bash +git clone https://github.com/paritytech/polkadot-sdk.git +cd polkadot +``` + +Then build the code. You will need to build in release mode (`--release`) to start a network. Only +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 +``` + +You can run the tests if you like: + +```bash +cargo test --workspace --release +``` + +You can start a development chain with: + +```bash +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 +``` + +### Development + +You can run a simple single-node development "network" on your machine by running: + +```bash +cargo run --bin polkadot --release -- --dev +``` + +You can muck around by heading to and choose "Local Node" from the +Settings menu. + +### Local Two-node Testnet + +If you want to see the multi-node consensus algorithm in action locally, then you can create a local +testnet. You'll need two terminals open. In one, run: + +```bash +polkadot --chain=polkadot-local --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' +``` + +Ensure you replace `ALICE_BOOTNODE_ID_HERE` with the node ID from the output of the first terminal. + +### Monitoring + +[Setup Prometheus and Grafana](https://wiki.polkadot.network/docs/maintain-guides-how-to-monitor-your-node). + +Once you set this up you can take a look at the [Polkadot Grafana dashboards](grafana/README.md) +that we currently maintain. + +### Using Docker + +[Using Docker](doc/docker.md) + +### Shell Completion + +[Shell Completion](doc/shell-completion.md) + +## Contributing + +### Contributing Guidelines + +[Contribution Guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md) + +### Contributor Code of Conduct + +[Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CODE_OF_CONDUCT.md) + +## License + +Polkadot is [GPL 3.0 licensed](LICENSE). diff --git a/substrate/README.md b/substrate/README.md index 59e0cff015d..6ed64ac82ee 100644 --- a/substrate/README.md +++ b/substrate/README.md @@ -1,13 +1,44 @@ -Dear contributors and users, +# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.md) [![Stack Exchange](https://img.shields.io/badge/Substrate-Community%20&%20Support-24CC85?logo=stackexchange)](https://substrate.stackexchange.com/) +

+ +

-We would like to inform you that we have recently made significant changes to our repository structure. In order to streamline our development process and foster better contributions, we have merged three separate repositories Cumulus, Substrate and Polkadot into a single new repository: [the Polkadot SDK](https://github.com/paritytech/polkadot-sdk). Go ahead and make sure to support us by giving a star ⭐️ to the new repo. +Substrate is a next-generation framework for blockchain innovation 🚀. -By consolidating our codebase, we aim to enhance collaboration and provide a more efficient platform for future development. +## Getting Started -If you currently have an open pull request in any of the merged repositories, we kindly request that you resubmit your PR in the new repository. This will ensure that your contributions are considered within the updated context and enable us to review and merge them more effectively. +Head to [docs.substrate.io](https://docs.substrate.io) and follow the +[installation](https://docs.substrate.io/install/) instructions. Then try out one of the +[tutorials](https://docs.substrate.io/tutorials/). Refer to the [Docker instructions](./docker/README.md) to quickly run Substrate, Substrate Node Template, Subkey, or to build a chain spec. -We appreciate your understanding and ongoing support throughout this transition. Should you have any questions or require further assistance, please don't hesitate to [reach out to us](https://forum.polkadot.network/t/psa-parity-is-currently-working-on-merging-the-polkadot-stack-repositories-into-one-single-repository/2883). +## Community & Support -Best Regards, +Join the highly active and supportive community on the +[Substrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. +Please do report bugs and [issues here](https://github.com/paritytech/polkadot-sdk/issues) for anything you suspect requires action in the source. -Parity Technologies \ No newline at end of file +## Contributions & Code of Conduct + +Please follow the contributions guidelines as outlined in +[`docs/CONTRIBUTING.md`](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md). +In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CODE_OF_CONDUCT.md). + +## Security + +The security policy and procedures can be found in +[`docs/SECURITY.md`](https://github.com/paritytech/polkadot-sdk/blob/master/docs/SECURITY.md). + +## License + +- Substrate Primitives (`sp-*`), Frame (`frame-*`) and the pallets (`pallets-*`), binaries (`/bin`) +and all other utilities are licensed under [Apache 2.0](LICENSE-APACHE2). - Substrate Client +(`/client/*` / `sc-*`) is licensed under [GPL v3.0 with a classpath linking +exception](LICENSE-GPL3). + +The reason for the split-licensing is to ensure that for the vast majority of teams using Substrate +to create feature-chains, then all changes can be made entirely in Apache2-licensed code, allowing +teams full freedom over what and how they release and giving licensing clarity to commercial teams. + +In the interests of the community, we require any deeper improvements made to Substrate's core logic +(e.g. Substrate's internal consensus, crypto or database code) to be contributed back so everyone +can benefit. -- GitLab From dcda0e50f544c47634f4d994d41692e13a222294 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 29 Aug 2023 13:39:41 +0200 Subject: [PATCH 002/633] Fix build profiles (#1229) * Fix build profiles Closes https://github.com/paritytech/polkadot-sdk/issues/1155 Signed-off-by: Oliver Tale-Yazdi * Manually set version to 1.0.0 Signed-off-by: Oliver Tale-Yazdi * Use workspace repo Signed-off-by: Oliver Tale-Yazdi * 'Authors and Edition from workspace Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.toml | 81 +++++++++++++++++-- cumulus/bridges/bin/runtime-common/Cargo.toml | 6 +- cumulus/bridges/modules/grandpa/Cargo.toml | 4 +- cumulus/bridges/modules/messages/Cargo.toml | 4 +- cumulus/bridges/modules/parachains/Cargo.toml | 4 +- cumulus/bridges/modules/relayers/Cargo.toml | 4 +- .../modules/xcm-bridge-hub-router/Cargo.toml | 4 +- .../chain-asset-hub-kusama/Cargo.toml | 4 +- .../chain-asset-hub-polkadot/Cargo.toml | 4 +- .../chain-bridge-hub-cumulus/Cargo.toml | 4 +- .../chain-bridge-hub-kusama/Cargo.toml | 4 +- .../chain-bridge-hub-polkadot/Cargo.toml | 4 +- .../chain-bridge-hub-rococo/Cargo.toml | 4 +- .../chain-bridge-hub-wococo/Cargo.toml | 4 +- .../primitives/chain-kusama/Cargo.toml | 4 +- .../primitives/chain-polkadot/Cargo.toml | 4 +- .../primitives/chain-rococo/Cargo.toml | 4 +- .../primitives/chain-wococo/Cargo.toml | 4 +- .../primitives/header-chain/Cargo.toml | 4 +- .../bridges/primitives/messages/Cargo.toml | 4 +- .../bridges/primitives/parachains/Cargo.toml | 4 +- .../primitives/polkadot-core/Cargo.toml | 4 +- .../bridges/primitives/relayers/Cargo.toml | 4 +- cumulus/bridges/primitives/runtime/Cargo.toml | 4 +- .../bridges/primitives/test-utils/Cargo.toml | 4 +- .../xcm-bridge-hub-router/Cargo.toml | 4 +- cumulus/client/cli/Cargo.toml | 4 +- cumulus/client/collator/Cargo.toml | 4 +- cumulus/client/consensus/aura/Cargo.toml | 4 +- cumulus/client/consensus/common/Cargo.toml | 4 +- cumulus/client/consensus/proposer/Cargo.toml | 4 +- .../client/consensus/relay-chain/Cargo.toml | 4 +- cumulus/client/network/Cargo.toml | 4 +- cumulus/client/pov-recovery/Cargo.toml | 4 +- .../Cargo.toml | 4 +- .../client/relay-chain-interface/Cargo.toml | 4 +- .../relay-chain-minimal-node/Cargo.toml | 4 +- .../relay-chain-rpc-interface/Cargo.toml | 4 +- cumulus/client/service/Cargo.toml | 4 +- cumulus/pallets/aura-ext/Cargo.toml | 4 +- cumulus/pallets/collator-selection/Cargo.toml | 6 +- cumulus/pallets/dmp-queue/Cargo.toml | 4 +- cumulus/pallets/parachain-system/Cargo.toml | 4 +- .../parachain-system/proc-macro/Cargo.toml | 4 +- .../pallets/session-benchmarking/Cargo.toml | 6 +- cumulus/pallets/solo-to-para/Cargo.toml | 4 +- cumulus/pallets/xcm/Cargo.toml | 4 +- cumulus/pallets/xcmp-queue/Cargo.toml | 4 +- cumulus/parachain-template/node/Cargo.toml | 4 +- .../pallets/template/Cargo.toml | 4 +- cumulus/parachain-template/runtime/Cargo.toml | 4 +- cumulus/parachains/common/Cargo.toml | 4 +- .../assets/asset-hub-kusama/Cargo.toml | 4 +- .../assets/asset-hub-polkadot/Cargo.toml | 4 +- .../assets/asset-hub-westend/Cargo.toml | 4 +- .../bridges/bridge-hub-rococo/Cargo.toml | 4 +- .../collectives-polkadot/Cargo.toml | 4 +- .../emulated/common/Cargo.toml | 4 +- .../pallets/parachain-info/Cargo.toml | 4 +- cumulus/parachains/pallets/ping/Cargo.toml | 4 +- .../assets/asset-hub-kusama/Cargo.toml | 4 +- .../assets/asset-hub-polkadot/Cargo.toml | 4 +- .../assets/asset-hub-westend/Cargo.toml | 4 +- .../runtimes/assets/common/Cargo.toml | 4 +- .../runtimes/assets/test-utils/Cargo.toml | 4 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 4 +- .../bridge-hub-polkadot/Cargo.toml | 4 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 4 +- .../bridge-hubs/test-utils/Cargo.toml | 4 +- .../collectives-polkadot/Cargo.toml | 4 +- .../contracts/contracts-rococo/Cargo.toml | 4 +- .../glutton/glutton-kusama/Cargo.toml | 4 +- .../runtimes/starters/seedling/Cargo.toml | 4 +- .../runtimes/starters/shell/Cargo.toml | 4 +- .../parachains/runtimes/test-utils/Cargo.toml | 4 +- .../runtimes/testing/penpal/Cargo.toml | 4 +- .../testing/rococo-parachain/Cargo.toml | 4 +- cumulus/polkadot-parachain/Cargo.toml | 4 +- cumulus/primitives/aura/Cargo.toml | 4 +- cumulus/primitives/core/Cargo.toml | 4 +- .../primitives/parachain-inherent/Cargo.toml | 4 +- cumulus/primitives/timestamp/Cargo.toml | 4 +- cumulus/primitives/utility/Cargo.toml | 4 +- cumulus/test/client/Cargo.toml | 4 +- cumulus/test/relay-sproof-builder/Cargo.toml | 4 +- .../Cargo.toml | 4 +- cumulus/test/runtime/Cargo.toml | 4 +- cumulus/test/service/Cargo.toml | 4 +- cumulus/xcm/xcm-emulator/Cargo.toml | 4 +- polkadot/Cargo.toml | 81 +------------------ polkadot/cli/Cargo.toml | 2 +- polkadot/core-primitives/Cargo.toml | 2 +- polkadot/erasure-coding/Cargo.toml | 2 +- polkadot/erasure-coding/fuzzer/Cargo.toml | 2 +- polkadot/node/collation-generation/Cargo.toml | 2 +- polkadot/node/core/approval-voting/Cargo.toml | 2 +- polkadot/node/core/av-store/Cargo.toml | 2 +- polkadot/node/core/backing/Cargo.toml | 2 +- .../node/core/bitfield-signing/Cargo.toml | 2 +- .../node/core/candidate-validation/Cargo.toml | 2 +- polkadot/node/core/chain-api/Cargo.toml | 2 +- polkadot/node/core/chain-selection/Cargo.toml | 2 +- .../node/core/dispute-coordinator/Cargo.toml | 2 +- .../node/core/parachains-inherent/Cargo.toml | 2 +- .../core/prospective-parachains/Cargo.toml | 2 +- polkadot/node/core/provisioner/Cargo.toml | 2 +- polkadot/node/core/pvf-checker/Cargo.toml | 2 +- polkadot/node/core/pvf/Cargo.toml | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- .../node/core/pvf/execute-worker/Cargo.toml | 2 +- .../node/core/pvf/prepare-worker/Cargo.toml | 2 +- polkadot/node/core/runtime-api/Cargo.toml | 2 +- polkadot/node/gum/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/jaeger/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/metrics/Cargo.toml | 2 +- .../network/approval-distribution/Cargo.toml | 2 +- .../availability-distribution/Cargo.toml | 2 +- .../network/availability-recovery/Cargo.toml | 2 +- .../network/bitfield-distribution/Cargo.toml | 2 +- polkadot/node/network/bridge/Cargo.toml | 2 +- .../node/network/collator-protocol/Cargo.toml | 2 +- .../network/dispute-distribution/Cargo.toml | 2 +- .../node/network/gossip-support/Cargo.toml | 2 +- polkadot/node/network/protocol/Cargo.toml | 2 +- .../network/statement-distribution/Cargo.toml | 2 +- polkadot/node/overseer/Cargo.toml | 2 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- .../node/subsystem-test-helpers/Cargo.toml | 2 +- polkadot/node/subsystem-types/Cargo.toml | 2 +- polkadot/node/subsystem-util/Cargo.toml | 2 +- polkadot/node/subsystem/Cargo.toml | 2 +- polkadot/node/test/client/Cargo.toml | 2 +- .../node/test/performance-test/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 2 +- .../node/zombienet-backchannel/Cargo.toml | 2 +- polkadot/parachain/Cargo.toml | 2 +- polkadot/parachain/test-parachains/Cargo.toml | 2 +- .../test-parachains/adder/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../parachain/test-parachains/halt/Cargo.toml | 2 +- .../test-parachains/undying/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/primitives/test-helpers/Cargo.toml | 2 +- polkadot/rpc/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- .../common/slot_range_helper/Cargo.toml | 2 +- polkadot/runtime/kusama/Cargo.toml | 2 +- polkadot/runtime/kusama/constants/Cargo.toml | 2 +- polkadot/runtime/metrics/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/polkadot/Cargo.toml | 2 +- .../runtime/polkadot/constants/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/rococo/constants/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- .../runtime/test-runtime/constants/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/runtime/westend/constants/Cargo.toml | 2 +- polkadot/statement-table/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/utils/staking-miner/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- polkadot/xcm/xcm-builder/Cargo.toml | 2 +- polkadot/xcm/xcm-executor/Cargo.toml | 2 +- .../xcm-executor/integration-tests/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- .../node-template/pallets/template/Cargo.toml | 2 +- .../bin/node-template/runtime/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 6 +- substrate/bin/node/cli/Cargo.toml | 6 +- substrate/bin/node/executor/Cargo.toml | 6 +- substrate/bin/node/inspect/Cargo.toml | 6 +- substrate/bin/node/primitives/Cargo.toml | 6 +- substrate/bin/node/rpc/Cargo.toml | 6 +- substrate/bin/node/runtime/Cargo.toml | 6 +- substrate/bin/node/testing/Cargo.toml | 6 +- .../bin/utils/chain-spec-builder/Cargo.toml | 6 +- substrate/bin/utils/subkey/Cargo.toml | 6 +- substrate/client/allocator/Cargo.toml | 6 +- substrate/client/api/Cargo.toml | 6 +- .../client/authority-discovery/Cargo.toml | 6 +- substrate/client/basic-authorship/Cargo.toml | 6 +- substrate/client/block-builder/Cargo.toml | 6 +- substrate/client/chain-spec/Cargo.toml | 6 +- substrate/client/chain-spec/derive/Cargo.toml | 6 +- substrate/client/cli/Cargo.toml | 6 +- substrate/client/consensus/aura/Cargo.toml | 6 +- substrate/client/consensus/babe/Cargo.toml | 6 +- .../client/consensus/babe/rpc/Cargo.toml | 6 +- substrate/client/consensus/beefy/Cargo.toml | 6 +- .../client/consensus/beefy/rpc/Cargo.toml | 6 +- substrate/client/consensus/common/Cargo.toml | 6 +- substrate/client/consensus/epochs/Cargo.toml | 6 +- substrate/client/consensus/grandpa/Cargo.toml | 6 +- .../client/consensus/grandpa/rpc/Cargo.toml | 6 +- .../client/consensus/manual-seal/Cargo.toml | 6 +- substrate/client/consensus/pow/Cargo.toml | 6 +- substrate/client/consensus/slots/Cargo.toml | 6 +- substrate/client/db/Cargo.toml | 6 +- substrate/client/executor/Cargo.toml | 6 +- substrate/client/executor/common/Cargo.toml | 6 +- .../client/executor/runtime-test/Cargo.toml | 6 +- substrate/client/executor/wasmtime/Cargo.toml | 6 +- substrate/client/informant/Cargo.toml | 6 +- substrate/client/keystore/Cargo.toml | 6 +- .../client/merkle-mountain-range/Cargo.toml | 6 +- .../merkle-mountain-range/rpc/Cargo.toml | 6 +- substrate/client/network-gossip/Cargo.toml | 6 +- substrate/client/network/Cargo.toml | 6 +- substrate/client/network/bitswap/Cargo.toml | 6 +- substrate/client/network/common/Cargo.toml | 6 +- substrate/client/network/light/Cargo.toml | 6 +- substrate/client/network/statement/Cargo.toml | 6 +- substrate/client/network/sync/Cargo.toml | 6 +- substrate/client/network/test/Cargo.toml | 6 +- .../client/network/transactions/Cargo.toml | 6 +- substrate/client/offchain/Cargo.toml | 6 +- substrate/client/proposer-metrics/Cargo.toml | 6 +- substrate/client/rpc-api/Cargo.toml | 6 +- substrate/client/rpc-servers/Cargo.toml | 6 +- substrate/client/rpc-spec-v2/Cargo.toml | 6 +- substrate/client/rpc/Cargo.toml | 6 +- substrate/client/service/Cargo.toml | 6 +- substrate/client/service/test/Cargo.toml | 6 +- substrate/client/state-db/Cargo.toml | 6 +- substrate/client/statement-store/Cargo.toml | 7 +- substrate/client/storage-monitor/Cargo.toml | 6 +- substrate/client/sync-state-rpc/Cargo.toml | 6 +- substrate/client/sysinfo/Cargo.toml | 6 +- substrate/client/telemetry/Cargo.toml | 6 +- substrate/client/tracing/Cargo.toml | 6 +- .../client/tracing/proc-macro/Cargo.toml | 6 +- substrate/client/transaction-pool/Cargo.toml | 6 +- .../client/transaction-pool/api/Cargo.toml | 6 +- substrate/client/utils/Cargo.toml | 6 +- substrate/frame/alliance/Cargo.toml | 6 +- substrate/frame/asset-conversion/Cargo.toml | 6 +- substrate/frame/asset-rate/Cargo.toml | 4 +- substrate/frame/assets/Cargo.toml | 6 +- substrate/frame/atomic-swap/Cargo.toml | 6 +- substrate/frame/aura/Cargo.toml | 6 +- .../frame/authority-discovery/Cargo.toml | 6 +- substrate/frame/authorship/Cargo.toml | 6 +- substrate/frame/babe/Cargo.toml | 6 +- substrate/frame/bags-list/Cargo.toml | 6 +- substrate/frame/bags-list/fuzzer/Cargo.toml | 6 +- .../frame/bags-list/remote-tests/Cargo.toml | 6 +- substrate/frame/balances/Cargo.toml | 6 +- substrate/frame/beefy-mmr/Cargo.toml | 6 +- substrate/frame/beefy/Cargo.toml | 6 +- substrate/frame/benchmarking/Cargo.toml | 6 +- substrate/frame/benchmarking/pov/Cargo.toml | 6 +- substrate/frame/bounties/Cargo.toml | 6 +- substrate/frame/broker/Cargo.toml | 6 +- substrate/frame/child-bounties/Cargo.toml | 6 +- substrate/frame/collective/Cargo.toml | 6 +- substrate/frame/contracts/Cargo.toml | 6 +- .../frame/contracts/primitives/Cargo.toml | 6 +- .../frame/contracts/proc-macro/Cargo.toml | 6 +- substrate/frame/conviction-voting/Cargo.toml | 6 +- substrate/frame/core-fellowship/Cargo.toml | 6 +- substrate/frame/democracy/Cargo.toml | 6 +- .../election-provider-multi-phase/Cargo.toml | 6 +- .../test-staking-e2e/Cargo.toml | 7 +- .../election-provider-support/Cargo.toml | 6 +- .../benchmarking/Cargo.toml | 6 +- .../solution-type/Cargo.toml | 6 +- .../solution-type/fuzzer/Cargo.toml | 6 +- substrate/frame/elections-phragmen/Cargo.toml | 6 +- substrate/frame/examples/Cargo.toml | 6 +- substrate/frame/examples/basic/Cargo.toml | 6 +- .../frame/examples/default-config/Cargo.toml | 6 +- substrate/frame/examples/dev-mode/Cargo.toml | 6 +- .../frame/examples/kitchensink/Cargo.toml | 6 +- .../frame/examples/offchain-worker/Cargo.toml | 6 +- substrate/frame/examples/split/Cargo.toml | 6 +- substrate/frame/executive/Cargo.toml | 6 +- substrate/frame/fast-unstake/Cargo.toml | 6 +- substrate/frame/glutton/Cargo.toml | 6 +- substrate/frame/grandpa/Cargo.toml | 6 +- substrate/frame/identity/Cargo.toml | 6 +- substrate/frame/im-online/Cargo.toml | 6 +- substrate/frame/indices/Cargo.toml | 6 +- .../Cargo.toml | 6 +- substrate/frame/lottery/Cargo.toml | 6 +- substrate/frame/membership/Cargo.toml | 6 +- .../frame/merkle-mountain-range/Cargo.toml | 6 +- substrate/frame/message-queue/Cargo.toml | 6 +- substrate/frame/multisig/Cargo.toml | 6 +- .../frame/nft-fractionalization/Cargo.toml | 6 +- substrate/frame/nfts/Cargo.toml | 6 +- substrate/frame/nfts/runtime-api/Cargo.toml | 6 +- substrate/frame/nicks/Cargo.toml | 6 +- substrate/frame/nis/Cargo.toml | 6 +- substrate/frame/node-authorization/Cargo.toml | 6 +- substrate/frame/nomination-pools/Cargo.toml | 6 +- .../nomination-pools/benchmarking/Cargo.toml | 6 +- .../frame/nomination-pools/fuzzer/Cargo.toml | 6 +- .../nomination-pools/runtime-api/Cargo.toml | 6 +- .../nomination-pools/test-staking/Cargo.toml | 6 +- substrate/frame/offences/Cargo.toml | 6 +- .../frame/offences/benchmarking/Cargo.toml | 6 +- substrate/frame/paged-list/Cargo.toml | 6 +- substrate/frame/paged-list/fuzzer/Cargo.toml | 6 +- substrate/frame/preimage/Cargo.toml | 6 +- substrate/frame/proxy/Cargo.toml | 6 +- substrate/frame/ranked-collective/Cargo.toml | 6 +- substrate/frame/recovery/Cargo.toml | 6 +- substrate/frame/referenda/Cargo.toml | 6 +- substrate/frame/remark/Cargo.toml | 6 +- substrate/frame/root-offences/Cargo.toml | 6 +- substrate/frame/root-testing/Cargo.toml | 6 +- substrate/frame/safe-mode/Cargo.toml | 6 +- substrate/frame/salary/Cargo.toml | 6 +- substrate/frame/scheduler/Cargo.toml | 6 +- substrate/frame/scored-pool/Cargo.toml | 6 +- substrate/frame/session/Cargo.toml | 6 +- .../frame/session/benchmarking/Cargo.toml | 6 +- substrate/frame/society/Cargo.toml | 6 +- substrate/frame/staking/Cargo.toml | 6 +- .../frame/staking/reward-curve/Cargo.toml | 6 +- substrate/frame/staking/reward-fn/Cargo.toml | 6 +- .../frame/staking/runtime-api/Cargo.toml | 6 +- .../frame/state-trie-migration/Cargo.toml | 6 +- substrate/frame/statement/Cargo.toml | 6 +- substrate/frame/sudo/Cargo.toml | 6 +- substrate/frame/support/Cargo.toml | 6 +- substrate/frame/support/procedural/Cargo.toml | 6 +- .../frame/support/procedural/tools/Cargo.toml | 6 +- .../procedural/tools/derive/Cargo.toml | 6 +- substrate/frame/support/test/Cargo.toml | 6 +- .../support/test/compile_pass/Cargo.toml | 6 +- .../frame/support/test/pallet/Cargo.toml | 6 +- substrate/frame/system/Cargo.toml | 6 +- .../frame/system/benchmarking/Cargo.toml | 6 +- .../frame/system/rpc/runtime-api/Cargo.toml | 6 +- substrate/frame/timestamp/Cargo.toml | 6 +- substrate/frame/tips/Cargo.toml | 6 +- .../frame/transaction-payment/Cargo.toml | 6 +- .../asset-conversion-tx-payment/Cargo.toml | 6 +- .../asset-tx-payment/Cargo.toml | 6 +- .../frame/transaction-payment/rpc/Cargo.toml | 6 +- .../rpc/runtime-api/Cargo.toml | 6 +- .../frame/transaction-storage/Cargo.toml | 6 +- substrate/frame/treasury/Cargo.toml | 6 +- substrate/frame/try-runtime/Cargo.toml | 6 +- substrate/frame/tx-pause/Cargo.toml | 6 +- substrate/frame/uniques/Cargo.toml | 6 +- substrate/frame/utility/Cargo.toml | 6 +- substrate/frame/vesting/Cargo.toml | 6 +- substrate/frame/whitelist/Cargo.toml | 6 +- substrate/primitives/api/Cargo.toml | 6 +- .../primitives/api/proc-macro/Cargo.toml | 6 +- substrate/primitives/api/test/Cargo.toml | 6 +- .../primitives/application-crypto/Cargo.toml | 6 +- .../application-crypto/test/Cargo.toml | 6 +- substrate/primitives/arithmetic/Cargo.toml | 6 +- .../primitives/arithmetic/fuzzer/Cargo.toml | 6 +- .../primitives/authority-discovery/Cargo.toml | 6 +- substrate/primitives/block-builder/Cargo.toml | 6 +- substrate/primitives/blockchain/Cargo.toml | 6 +- .../primitives/consensus/aura/Cargo.toml | 6 +- .../primitives/consensus/babe/Cargo.toml | 6 +- .../primitives/consensus/beefy/Cargo.toml | 6 +- .../primitives/consensus/common/Cargo.toml | 6 +- .../primitives/consensus/grandpa/Cargo.toml | 6 +- substrate/primitives/consensus/pow/Cargo.toml | 6 +- .../primitives/consensus/slots/Cargo.toml | 6 +- substrate/primitives/core/Cargo.toml | 6 +- substrate/primitives/core/hashing/Cargo.toml | 6 +- .../core/hashing/proc-macro/Cargo.toml | 6 +- .../primitives/crypto/ec-utils/Cargo.toml | 6 +- substrate/primitives/database/Cargo.toml | 6 +- substrate/primitives/debug-derive/Cargo.toml | 6 +- substrate/primitives/externalities/Cargo.toml | 6 +- .../primitives/genesis-builder/Cargo.toml | 6 +- substrate/primitives/inherents/Cargo.toml | 6 +- substrate/primitives/io/Cargo.toml | 6 +- substrate/primitives/keyring/Cargo.toml | 6 +- substrate/primitives/keystore/Cargo.toml | 6 +- .../maybe-compressed-blob/Cargo.toml | 6 +- .../merkle-mountain-range/Cargo.toml | 6 +- substrate/primitives/metadata-ir/Cargo.toml | 6 +- .../primitives/npos-elections/Cargo.toml | 6 +- .../npos-elections/fuzzer/Cargo.toml | 6 +- substrate/primitives/offchain/Cargo.toml | 6 +- substrate/primitives/panic-handler/Cargo.toml | 6 +- substrate/primitives/rpc/Cargo.toml | 6 +- .../primitives/runtime-interface/Cargo.toml | 6 +- .../runtime-interface/proc-macro/Cargo.toml | 6 +- .../test-wasm-deprecated/Cargo.toml | 6 +- .../runtime-interface/test-wasm/Cargo.toml | 6 +- .../runtime-interface/test/Cargo.toml | 6 +- substrate/primitives/runtime/Cargo.toml | 6 +- substrate/primitives/session/Cargo.toml | 6 +- substrate/primitives/staking/Cargo.toml | 6 +- substrate/primitives/state-machine/Cargo.toml | 6 +- .../primitives/statement-store/Cargo.toml | 6 +- substrate/primitives/std/Cargo.toml | 6 +- substrate/primitives/storage/Cargo.toml | 6 +- .../primitives/test-primitives/Cargo.toml | 6 +- substrate/primitives/timestamp/Cargo.toml | 6 +- substrate/primitives/tracing/Cargo.toml | 6 +- .../primitives/transaction-pool/Cargo.toml | 6 +- .../transaction-storage-proof/Cargo.toml | 6 +- substrate/primitives/trie/Cargo.toml | 6 +- substrate/primitives/version/Cargo.toml | 6 +- .../primitives/version/proc-macro/Cargo.toml | 6 +- .../primitives/wasm-interface/Cargo.toml | 6 +- substrate/primitives/weights/Cargo.toml | 6 +- .../ci/node-template-release/Cargo.toml | 4 +- substrate/test-utils/Cargo.toml | 6 +- substrate/test-utils/cli/Cargo.toml | 6 +- substrate/test-utils/client/Cargo.toml | 6 +- substrate/test-utils/derive/Cargo.toml | 6 +- substrate/test-utils/runtime/Cargo.toml | 6 +- .../test-utils/runtime/client/Cargo.toml | 6 +- .../runtime/transaction-pool/Cargo.toml | 6 +- substrate/test-utils/test-crate/Cargo.toml | 6 +- substrate/utils/binary-merkle-tree/Cargo.toml | 6 +- substrate/utils/build-script-utils/Cargo.toml | 6 +- substrate/utils/fork-tree/Cargo.toml | 6 +- .../utils/frame/benchmarking-cli/Cargo.toml | 6 +- .../frame/frame-utilities-cli/Cargo.toml | 6 +- .../utils/frame/generate-bags/Cargo.toml | 6 +- .../generate-bags/node-runtime/Cargo.toml | 6 +- .../frame/remote-externalities/Cargo.toml | 6 +- substrate/utils/frame/rpc/client/Cargo.toml | 6 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 6 +- substrate/utils/frame/rpc/support/Cargo.toml | 4 +- substrate/utils/frame/rpc/system/Cargo.toml | 6 +- .../utils/frame/try-runtime/cli/Cargo.toml | 6 +- substrate/utils/prometheus/Cargo.toml | 6 +- substrate/utils/wasm-builder/Cargo.toml | 6 +- 445 files changed, 1140 insertions(+), 1150 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab10fe5bb75..48081ad14a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,9 @@ +[workspace.package] +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/polkadot-sdk.git" +license = "GPL-3.0-only" + [workspace] resolver = "2" @@ -448,15 +454,78 @@ members = [ "substrate/utils/wasm-builder", ] -[workspace.package] -authors = ["Parity Technologies "] -edition = "2021" -repository = "https://github.com/paritytech/polkadot-sdk.git" -license = "GPL-3.0-only" -version = "1.0.0" +[profile.release] +# Polkadot runtime requires unwinding. +panic = "unwind" +opt-level = 3 + +# make sure dev builds with backtrace do +# not slow us down +[profile.dev.package.backtrace] +inherits = "release" + +[profile.production] +inherits = "release" +lto = true +codegen-units = 1 [profile.testnet] inherits = "release" debug = 1 # debug symbols are useful for profilers debug-assertions = true overflow-checks = true + +# The list of dependencies below (which can be both direct and indirect dependencies) are crates +# that are suspected to be CPU-intensive, and that are unlikely to require debugging (as some of +# their debug info might be missing) or to require to be frequently recompiled. We compile these +# dependencies with `opt-level=3` even in "dev" mode in order to make "dev" mode more usable. +# The majority of these crates are cryptographic libraries. +# +# If you see an error mentioning "profile package spec ... did not match any packages", it +# probably concerns this list. +# +# This list is ordered alphabetically. +[profile.dev.package] +blake2 = { opt-level = 3 } +blake2b_simd = { opt-level = 3 } +chacha20poly1305 = { opt-level = 3 } +cranelift-codegen = { opt-level = 3 } +cranelift-wasm = { opt-level = 3 } +crc32fast = { opt-level = 3 } +crossbeam-deque = { opt-level = 3 } +crypto-mac = { opt-level = 3 } +curve25519-dalek = { opt-level = 3 } +ed25519-dalek = { opt-level = 3 } +flate2 = { opt-level = 3 } +futures-channel = { opt-level = 3 } +hash-db = { opt-level = 3 } +hashbrown = { opt-level = 3 } +hmac = { opt-level = 3 } +httparse = { opt-level = 3 } +integer-sqrt = { opt-level = 3 } +keccak = { opt-level = 3 } +libm = { opt-level = 3 } +librocksdb-sys = { opt-level = 3 } +libsecp256k1 = { opt-level = 3 } +libz-sys = { opt-level = 3 } +mio = { opt-level = 3 } +nalgebra = { opt-level = 3 } +num-bigint = { opt-level = 3 } +parking_lot = { opt-level = 3 } +parking_lot_core = { opt-level = 3 } +percent-encoding = { opt-level = 3 } +primitive-types = { opt-level = 3 } +reed-solomon-novelpoly = { opt-level = 3 } +ring = { opt-level = 3 } +rustls = { opt-level = 3 } +sha2 = { opt-level = 3 } +sha3 = { opt-level = 3 } +smallvec = { opt-level = 3 } +snow = { opt-level = 3 } +substrate-bip39 = { opt-level = 3 } +twox-hash = { opt-level = 3 } +uint = { opt-level = 3 } +wasmi = { opt-level = 3 } +x25519-dalek = { opt-level = 3 } +yamux = { opt-level = 3 } +zeroize = { opt-level = 3 } diff --git a/cumulus/bridges/bin/runtime-common/Cargo.toml b/cumulus/bridges/bin/runtime-common/Cargo.toml index f9d69aec16c..6c0f576a7dd 100644 --- a/cumulus/bridges/bin/runtime-common/Cargo.toml +++ b/cumulus/bridges/bin/runtime-common/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "bridge-runtime-common" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" -repository = "https://github.com/paritytech/parity-bridges-common/" +authors.workspace = true +edition.workspace = true +repository.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/modules/grandpa/Cargo.toml b/cumulus/bridges/modules/grandpa/Cargo.toml index 2f04ed47480..87eda6b29a7 100644 --- a/cumulus/bridges/modules/grandpa/Cargo.toml +++ b/cumulus/bridges/modules/grandpa/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "pallet-bridge-grandpa" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/cumulus/bridges/modules/messages/Cargo.toml b/cumulus/bridges/modules/messages/Cargo.toml index 53ba7a3ff5b..5eecdb147fa 100644 --- a/cumulus/bridges/modules/messages/Cargo.toml +++ b/cumulus/bridges/modules/messages/Cargo.toml @@ -2,8 +2,8 @@ name = "pallet-bridge-messages" description = "Module that allows bridged chains to exchange messages using lane concept." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/modules/parachains/Cargo.toml b/cumulus/bridges/modules/parachains/Cargo.toml index 203b855f568..50a838edf56 100644 --- a/cumulus/bridges/modules/parachains/Cargo.toml +++ b/cumulus/bridges/modules/parachains/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "pallet-bridge-parachains" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/modules/relayers/Cargo.toml b/cumulus/bridges/modules/relayers/Cargo.toml index 116257c94fb..3a7a57e1801 100644 --- a/cumulus/bridges/modules/relayers/Cargo.toml +++ b/cumulus/bridges/modules/relayers/Cargo.toml @@ -2,8 +2,8 @@ name = "pallet-bridge-relayers" description = "Module used to store relayer rewards and coordinate relayers set." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml index fb347232a3c..4f244a9e6a7 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -2,8 +2,8 @@ name = "pallet-xcm-bridge-hub-router" description = "Bridge hub interface for sibling/parent chains with dynamic fees support." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml index 9bc7c46e07e..557f56bfb62 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ b/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-asset-hub-kusama" description = "Primitives of AssetHubKusama parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml index b5b5fcde4e2..6fe9ffab44b 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ b/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-asset-hub-polkadot" description = "Primitives of AssetHubPolkadot parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index af916665814..865cead3c87 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-bridge-hub-cumulus" description = "Primitives of BridgeHubRococo parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index d6d92ebb578..92b0c9bf447 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-bridge-hub-kusama" description = "Primitives of BridgeHubRococo parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index cb5ebf3b478..7468d5be60d 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-bridge-hub-polkadot" description = "Primitives of BridgeHubWococo parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index cb11afff7af..8dde903701c 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-bridge-hub-rococo" description = "Primitives of BridgeHubRococo parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml b/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml index 7302d9ff76d..c93cdad5110 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml +++ b/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-bridge-hub-wococo" description = "Primitives of BridgeHubWococo parachain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-kusama/Cargo.toml b/cumulus/bridges/primitives/chain-kusama/Cargo.toml index 4ad39858df3..e404bdb3d94 100644 --- a/cumulus/bridges/primitives/chain-kusama/Cargo.toml +++ b/cumulus/bridges/primitives/chain-kusama/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-kusama" description = "Primitives of Kusama runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-polkadot/Cargo.toml b/cumulus/bridges/primitives/chain-polkadot/Cargo.toml index 3cec5d267ea..4d9bf8c182f 100644 --- a/cumulus/bridges/primitives/chain-polkadot/Cargo.toml +++ b/cumulus/bridges/primitives/chain-polkadot/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-polkadot" description = "Primitives of Polkadot runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-rococo/Cargo.toml b/cumulus/bridges/primitives/chain-rococo/Cargo.toml index 9a2eb106909..72c6d4c03b6 100644 --- a/cumulus/bridges/primitives/chain-rococo/Cargo.toml +++ b/cumulus/bridges/primitives/chain-rococo/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-rococo" description = "Primitives of Rococo runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/chain-wococo/Cargo.toml b/cumulus/bridges/primitives/chain-wococo/Cargo.toml index d3be18aa064..f7feb7f96eb 100644 --- a/cumulus/bridges/primitives/chain-wococo/Cargo.toml +++ b/cumulus/bridges/primitives/chain-wococo/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-wococo" description = "Primitives of Wococo runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/header-chain/Cargo.toml b/cumulus/bridges/primitives/header-chain/Cargo.toml index 8b59a2be896..a7b53b0336d 100644 --- a/cumulus/bridges/primitives/header-chain/Cargo.toml +++ b/cumulus/bridges/primitives/header-chain/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-header-chain" description = "A common interface for describing what a bridge pallet should be able to do." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/messages/Cargo.toml b/cumulus/bridges/primitives/messages/Cargo.toml index 1e9e4db087e..b1fa6d575ae 100644 --- a/cumulus/bridges/primitives/messages/Cargo.toml +++ b/cumulus/bridges/primitives/messages/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-messages" description = "Primitives of messages module." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/parachains/Cargo.toml b/cumulus/bridges/primitives/parachains/Cargo.toml index 1e4acc6c501..978296954bb 100644 --- a/cumulus/bridges/primitives/parachains/Cargo.toml +++ b/cumulus/bridges/primitives/parachains/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-parachains" description = "Primitives of parachains module." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/polkadot-core/Cargo.toml b/cumulus/bridges/primitives/polkadot-core/Cargo.toml index 33829e7a96c..2563adaf219 100644 --- a/cumulus/bridges/primitives/polkadot-core/Cargo.toml +++ b/cumulus/bridges/primitives/polkadot-core/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-polkadot-core" description = "Primitives of Polkadot-like runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/relayers/Cargo.toml b/cumulus/bridges/primitives/relayers/Cargo.toml index 56edea067dc..bc674d4cb77 100644 --- a/cumulus/bridges/primitives/relayers/Cargo.toml +++ b/cumulus/bridges/primitives/relayers/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-relayers" description = "Primitives of relayers module." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/runtime/Cargo.toml b/cumulus/bridges/primitives/runtime/Cargo.toml index 0d6b9fb400c..f6134d6e332 100644 --- a/cumulus/bridges/primitives/runtime/Cargo.toml +++ b/cumulus/bridges/primitives/runtime/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-runtime" description = "Primitives that may be used at (bridges) runtime level." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/test-utils/Cargo.toml b/cumulus/bridges/primitives/test-utils/Cargo.toml index 5ab4d22a7b5..c379c6792cb 100644 --- a/cumulus/bridges/primitives/test-utils/Cargo.toml +++ b/cumulus/bridges/primitives/test-utils/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bp-test-utils" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index dccb36af6de..df2b00563de 100644 --- a/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-xcm-bridge-hub-router" description = "Primitives of the xcm-bridge-hub fee pallet." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index f22d82f5be2..40c53ae919a 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-client-cli" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] clap = { version = "4.3.24", features = ["derive"] } diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 2866793a21b..1d87efa443c 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-client-collator" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] parking_lot = "0.12.1" diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 030ab705f16..8239a498746 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -2,8 +2,8 @@ name = "cumulus-client-consensus-aura" description = "AURA consensus algorithm for parachains" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 738434b910b..26d7ba1b142 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -2,8 +2,8 @@ name = "cumulus-client-consensus-common" description = "Cumulus specific common consensus implementations" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index a4384c3859c..f7edbc695e3 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -2,8 +2,8 @@ name = "cumulus-client-consensus-proposer" description = "A Substrate `Proposer` for building parachain blocks" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] anyhow = "1.0" diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index ef74a0830b5..ba077f62403 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -2,8 +2,8 @@ name = "cumulus-client-consensus-relay-chain" description = "The relay-chain provided consensus algorithm" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index a17d2a8e329..99a567a950c 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "cumulus-client-network" version = "0.1.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Cumulus-specific networking protocol" -edition = "2021" +edition.workspace = true [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index b44a8023b98..2ce903fd352 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "cumulus-client-pov-recovery" version = "0.1.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Cumulus-specific networking protocol" -edition = "2021" +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 20f46a7a95a..c198b22cad4 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -1,8 +1,8 @@ [package] -authors = ["Parity Technologies "] +authors.workspace = true name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 54bd8e87cde..b81cc1b4780 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -1,8 +1,8 @@ [package] -authors = ["Parity Technologies "] +authors.workspace = true name = "cumulus-relay-chain-interface" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] polkadot-overseer = { path = "../../../polkadot/node/overseer" } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index c3914573aab..39056d6b651 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -1,8 +1,8 @@ [package] -authors = ["Parity Technologies "] +authors.workspace = true name = "cumulus-relay-chain-minimal-node" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] # polkadot deps diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 2356e747333..1056efd2dc8 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -1,8 +1,8 @@ [package] -authors = ["Parity Technologies "] +authors.workspace = true name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index 0c557dc9ca7..b53bdbdfc81 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-client-service" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] futures = "0.3.28" diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index 31be147bcdf..a804edb58b3 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-aura-ext" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "AURA consensus extension pallet for parachains" [dependencies] diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 6937eb47439..1aba84aa29c 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["Parity Technologies "] +authors.workspace = true description = "Simple pallet to select collators for a parachain." -edition = "2021" +edition.workspace = true homepage = "https://substrate.io" license = "Apache-2.0" name = "pallet-collator-selection" readme = "README.md" -repository = "https://github.com/paritytech/cumulus/" +repository.workspace = true version = "3.0.0" [package.metadata.docs.rs] diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 06fe46505c5..db654b4c132 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 3058d992beb..6dab4f75d7d 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-parachain-system" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Base pallet for cumulus-based parachains" [dependencies] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 2b5b339d9da..58a4a97e049 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Proc macros provided by the parachain-system pallet" [lib] diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index e2356f06590..a28971d66d3 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "cumulus-pallet-session-benchmarking" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/cumulus/" +repository.workspace = true description = "FRAME sessions pallet benchmarking" readme = "README.md" diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index 5716b2dd7b7..6a3fe59b402 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-solo-to-para" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Adds functionality to migrate from a Solo to a Parachain" [dependencies] diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 7acf53ba9d4..42a9d52993c 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true name = "cumulus-pallet-xcm" version = "0.1.0" diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 21ba4a2a935..919749c0f45 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 2f7acdf01d8..d85fd5a6178 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Anonymous"] description = "A new Cumulus FRAME-based Substrate Node, ready for hacking together a parachain." license = "Unlicense" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/cumulus/" -edition = "2021" +repository.workspace = true +edition.workspace = true build = "build.rs" [dependencies] diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index 841bb72c107..e06f836c3be 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -5,8 +5,8 @@ description = "FRAME pallet template for defining custom runtime logic." version = "0.1.0" license = "Unlicense" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -edition = "2021" +repository.workspace = true +edition.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 46958a6bc46..b321d6e3160 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Anonymous"] description = "A new Cumulus FRAME-based Substrate Runtime, ready for hacking together a parachain." license = "Unlicense" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/cumulus/" -edition = "2021" +repository.workspace = true +edition.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 901c818cded..1b790dd5b6f 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "parachains-common" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Logic which is common to all parachain runtimes" [package.metadata.docs.rs] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 83209e7e46c..6c3cf42ff35 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-hub-kusama-integration-tests" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Asset Hub Kusama runtime integration tests with xcm-emulator" [dependencies] 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 index 93cd66cf4db..e3c49d4f200 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-hub-polkadot-integration-tests" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Asset Hub Polkadot runtime integration tests with xcm-emulator" [dependencies] 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 1225cf8763c..548c9a5f407 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 @@ -1,8 +1,8 @@ [package] name = "asset-hub-westend-integration-tests" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Asset Hub Westend runtime integration tests with xcm-emulator" [dependencies] 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 fb3905c3c73..c4aba4f9110 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 @@ -1,8 +1,8 @@ [package] name = "bridge-hub-rococo-integration-tests" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" [dependencies] diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index cee67639e27..1d0069dfd00 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "collectives-polkadot-integration-tests" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Polkadot Collectives parachain runtime integration tests based on xcm-emulator" [dependencies] diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index d27e809e51b..47c5f96fd80 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "integration-tests-common" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Common resources for integration testing with xcm-emulator" [dependencies] diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 39af628676a..4ed11e39439 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true name = "parachain-info" version = "0.1.0" publish = false diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 46bfd5a1c21..e214081ab04 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true name = "cumulus-ping" version = "0.1.0" diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 7fceb9a2f20..e085ee24c60 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-hub-kusama-runtime" version = "0.9.420" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Kusama variant of Asset Hub parachain runtime" [dependencies] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index 5f82c07acca..b008b21b12d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-hub-polkadot-runtime" version = "0.9.420" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Asset Hub Polkadot parachain runtime" [dependencies] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index fe823e878f5..51df6591488 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-hub-westend-runtime" version = "0.9.420" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Westend variant of Asset Hub parachain runtime" [dependencies] diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 3c31fa08275..cdb7b87dacb 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "assets-common" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Assets common utilities" [dependencies] diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 46175482d3d..46b82b3ebb2 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "asset-test-utils" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Test utils for Asset Hub runtimes." [dependencies] 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 7f92c2ada37..f29ee82b7cb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bridge-hub-kusama-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Kusama's BridgeHub parachain runtime" [build-dependencies] 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 1d45e3ae524..87afb20eb90 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bridge-hub-polkadot-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Polkadot's BridgeHub parachain runtime" [build-dependencies] 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 ba60b110b87..95bf4c16967 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bridge-hub-rococo-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Rococo's BridgeHub parachain runtime" [build-dependencies] diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 3c4f38ec817..147166f2168 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bridge-hub-test-utils" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Utils for BridgeHub testing" [dependencies] diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index c19b5397080..59046ff1209 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "collectives-polkadot-runtime" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Polkadot Collectives Parachain Runtime" [dependencies] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 5576e4e233a..266437a4821 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "contracts-rococo-runtime" version = "0.2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index f7fc1602dd0..4973021d300 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "glutton-runtime" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 1dfad06616a..2cd09d3a9eb 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "seedling-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 0a28b9393a8..d7afc8be864 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "shell-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 788f1105a28..94b73d5e39d 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "parachains-runtimes-test-utils" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Utils for Runtimes testing" [dependencies] diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 8fdf31e6dbf..acaaadf04dd 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Anonymous"] description = "A parachain for communication back and forth with XCM of assets and uniques." license = "Unlicense" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/cumulus/" -edition = "2021" +repository.workspace = true +edition.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index d5a61fd8a81..6e9f9f3039c 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "rococo-parachain-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Simple runtime used by the rococo parachain(s)" [dependencies] diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index cda50206357..8ae7a1f25f3 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "polkadot-parachain-bin" version = "1.0.0" -authors = ["Parity Technologies "] +authors.workspace = true build = "build.rs" -edition = "2021" +edition.workspace = true description = "Runs a polkadot parachain node which could be a collator." [[bin]] diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index f03495c1906..791ec17378a 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-primitives-aura" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 5ca60ce0749..fdbef574773 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-primitives-core" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index ffcc0a47cc2..39b70f20a97 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] async-trait = { version = "0.1.73", optional = true } diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index e26c02f2b07..6b0d3d4a4dc 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-primitives-timestamp" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Provides timestamp related functionality for parachains." [dependencies] diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 7302d28f024..27f3996b885 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-primitives-utility" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 07df643a20e..5d8c6643c3c 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-client" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index aa95d71d225..e044b92f7c4 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-validation-worker-provider/Cargo.toml b/cumulus/test/relay-validation-worker-provider/Cargo.toml index 4ae5f230126..eaa1ce8dc47 100644 --- a/cumulus/test/relay-validation-worker-provider/Cargo.toml +++ b/cumulus/test/relay-validation-worker-provider/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-relay-validation-worker-provider" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" [dependencies] diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index e8131fa5787..9fe4c55bbd7 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-runtime" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 42bf4d29413..ad007c509ff 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-service" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [[bin]] name = "test-parachain" diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 4d6bf1422b0..8560b6401f7 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -2,8 +2,8 @@ name = "xcm-emulator" description = "Test kit to emulate XCM program execution." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 925d6589dc0..48bc0877c0f 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -14,11 +14,11 @@ path = "src/bin/prepare-worker.rs" name = "polkadot" description = "Implementation of a `https://polkadot.network` node in Rust based on the Substrate framework." license = "GPL-3.0-only" -rust-version = "1.64.0" # workspace properties +rust-version = "1.64.0" readme = "README.md" authors.workspace = true edition.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] color-eyre = { version = "0.6.1", default-features = false } @@ -49,86 +49,9 @@ polkadot-core-primitives = { path = "core-primitives" } [build-dependencies] substrate-build-script-utils = { path = "../substrate/utils/build-script-utils" } - [badges] maintenance = { status = "actively-developed" } -# The list of dependencies below (which can be both direct and indirect dependencies) are crates -# that are suspected to be CPU-intensive, and that are unlikely to require debugging (as some of -# their debug info might be missing) or to require to be frequently recompiled. We compile these -# dependencies with `opt-level=3` even in "dev" mode in order to make "dev" mode more usable. -# The majority of these crates are cryptographic libraries. -# -# If you see an error mentioning "profile package spec ... did not match any packages", it -# probably concerns this list. -# -# This list is ordered alphabetically. -[profile.dev.package] -blake2 = { opt-level = 3 } -blake2b_simd = { opt-level = 3 } -chacha20poly1305 = { opt-level = 3 } -cranelift-codegen = { opt-level = 3 } -cranelift-wasm = { opt-level = 3 } -crc32fast = { opt-level = 3 } -crossbeam-deque = { opt-level = 3 } -crypto-mac = { opt-level = 3 } -curve25519-dalek = { opt-level = 3 } -ed25519-dalek = { opt-level = 3 } -flate2 = { opt-level = 3 } -futures-channel = { opt-level = 3 } -hash-db = { opt-level = 3 } -hashbrown = { opt-level = 3 } -hmac = { opt-level = 3 } -httparse = { opt-level = 3 } -integer-sqrt = { opt-level = 3 } -keccak = { opt-level = 3 } -libm = { opt-level = 3 } -librocksdb-sys = { opt-level = 3 } -libsecp256k1 = { opt-level = 3 } -libz-sys = { opt-level = 3 } -mio = { opt-level = 3 } -nalgebra = { opt-level = 3 } -num-bigint = { opt-level = 3 } -parking_lot = { opt-level = 3 } -parking_lot_core = { opt-level = 3 } -percent-encoding = { opt-level = 3 } -primitive-types = { opt-level = 3 } -reed-solomon-novelpoly = { opt-level = 3 } -ring = { opt-level = 3 } -rustls = { opt-level = 3 } -sha2 = { opt-level = 3 } -sha3 = { opt-level = 3 } -smallvec = { opt-level = 3 } -snow = { opt-level = 3 } -substrate-bip39 = { opt-level = 3 } -twox-hash = { opt-level = 3 } -uint = { opt-level = 3 } -wasmi = { opt-level = 3 } -x25519-dalek = { opt-level = 3 } -yamux = { opt-level = 3 } -zeroize = { opt-level = 3 } - -[profile.release] -# Polkadot runtime requires unwinding. -panic = "unwind" -opt-level = 3 - -# make sure dev builds with backtrace do -# not slow us down -[profile.dev.package.backtrace] -inherits = "release" - -[profile.production] -inherits = "release" -lto = true -codegen-units = 1 - -[profile.testnet] -inherits = "release" -debug = 1 # debug symbols are useful for profilers -debug-assertions = true -overflow-checks = true - [features] runtime-benchmarks = [ "polkadot-cli/runtime-benchmarks" ] try-runtime = [ "polkadot-cli/try-runtime" ] diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index f82e7cd6259..2da40193e96 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-cli" description = "Polkadot Relay-chain Client Node" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 2d2be24f35f..29c6be44454 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-core-primitives" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index 867b1c3bf8b..f74a8803882 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-erasure-coding" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/erasure-coding/fuzzer/Cargo.toml b/polkadot/erasure-coding/fuzzer/Cargo.toml index 21b579e6752..862b148cc5b 100644 --- a/polkadot/erasure-coding/fuzzer/Cargo.toml +++ b/polkadot/erasure-coding/fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erasure_coding_fuzzer" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index 590b5a7114c..e2870dc2cc8 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-collation-generation" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 593f6bff4c8..307d9947a96 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-approval-voting" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index fc4b3226369..efbbb27754e 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-av-store" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index cb9fdd88bcc..0005f6f6a30 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-backing" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index de2d7622e81..c2df6cc709e 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-bitfield-signing" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 6c93f912271..3935c91d897 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-candidate-validation" description = "Polkadot crate that implements the Candidate Validation subsystem. Handles requests to validate candidates according to a PVF." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index 36e9236fe74..2178be028bd 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-chain-api" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 3bff1b875b0..57ba7908315 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-chain-selection" description = "Chain Selection Subsystem" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 5698114d278..c49bd507127 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-dispute-coordinator" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 19b5d7acb87..515d70dad82 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-parachains-inherent" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 5166534cf6f..9fa17ec0c15 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-prospective-parachains" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 25d624aa3f7..dc791417166 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-provisioner" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 9d2fe6c8b6e..783ac19009a 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-pvf-checker" description = "Polkadot crate that implements the PVF pre-checking subsystem. Responsible for checking and voting for PVFs that are pending approval." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 872ab0107cb..eb61b4ccb0e 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-pvf" description = "Polkadot crate that implements the PVF validation host. Responsible for coordinating preparation and execution of PVFs." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index f9f900a0fec..ded8f0dc63b 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-pvf-common" description = "Polkadot crate that contains functionality related to PVFs that is shared by the PVF host and the PVF workers." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 2bc62863ab5..5ef7c8e8e87 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-pvf-execute-worker" description = "Polkadot crate that contains the logic for executing PVFs. Used by the polkadot-execute-worker binary." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 61d2fd97156..dfa87e4d240 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-pvf-prepare-worker" description = "Polkadot crate that contains the logic for preparing PVFs. Used by the polkadot-prepare-worker binary." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index de165ebcc5c..b16a501686d 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-runtime-api" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/gum/Cargo.toml b/polkadot/node/gum/Cargo.toml index 1bd0026b4f4..01ed34f7a73 100644 --- a/polkadot/node/gum/Cargo.toml +++ b/polkadot/node/gum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tracing-gum" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index e7262008499..fc057c76975 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tracing-gum-proc-macro" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index baee1d0be24..7b4b5e1c8bc 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-jaeger" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index a0f9361f0f0..6f39368168f 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-test-malus" description = "Misbehaving nodes for local testnets, system and Simnet tests." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index 746b4c84201..3b6a67abc13 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-metrics" description = "Subsystem metric helpers" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 9638c53d318..e19a1b83a62 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-approval-distribution" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index 60fe8fb9bd7..581192e9560 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-distribution" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index d6d79d3fc24..bf95fb1e9f4 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-recovery" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index ff5b5c267a8..32b0ba2545e 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-bitfield-distribution" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index f4da50ffe02..df8e881234d 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-network-bridge" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index d15d20fcb7c..ac6284b305b 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-collator-protocol" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 24ae7ba25bc..ece89f34c88 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-dispute-distribution" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 5549aa1f736..a5bfda73833 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-gossip-support" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 076df31be7e..2a56f197b85 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-network-protocol" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index def7632e6ba..4c835bc3a68 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-statement-distribution" description = "Statement Distribution Subsystem" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 982ccc7ff24..2ebe2e9e074 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-overseer" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index c7c32398551..fcd7d4b3af9 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-primitives" description = "Primitives types for the Node-side" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index a1f1fdf1eab..3c89f1d2a54 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-service" rust-version = "1.60" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index e05c9194b39..98b0d182a61 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -2,7 +2,7 @@ name = "polkadot-node-subsystem-test-helpers" description = "Subsystem traits and message definitions" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 4f2d753b799..7ca3a0faf31 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-subsystem-types" description = "Subsystem traits and message definitions" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 87a823da909..d243a90a2bd 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-subsystem-util" description = "Subsystem traits and message definitions" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml index 368a194091f..9b77359517c 100644 --- a/polkadot/node/subsystem/Cargo.toml +++ b/polkadot/node/subsystem/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-subsystem" description = "Subsystem traits and message definitions and the generated overseer" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index fd189b3b040..bc4ff74be4b 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-test-client" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/test/performance-test/Cargo.toml b/polkadot/node/test/performance-test/Cargo.toml index 3c3a5f083a6..0c5192571b2 100644 --- a/polkadot/node/test/performance-test/Cargo.toml +++ b/polkadot/node/test/performance-test/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-performance-test" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 9f8329f5f4e..2c8f0649669 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-test-service" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 627de13124a..3d59a4a3cdd 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -3,7 +3,7 @@ name = "zombienet-backchannel" description = "Zombienet backchannel to notify test runner and coordinate with malus actors." readme = "README.md" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 209c7d5cfd1..b51ed8e9ecf 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -4,7 +4,7 @@ description = "Types and utilities for creating and working with parachains" authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] # note: special care is taken to avoid inclusion of `sp-io` externals when compiling diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index fdc3c7f2924..a30be9c678a 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-parachains" description = "Integration tests using the test-parachains" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index dc45f2f4ace..49e10dbd492 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -4,7 +4,7 @@ description = "Test parachain which adds to a number as its state transition" build = "build.rs" edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" authors.workspace = true publish = false diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index b96d27e6ab7..f706156d0cd 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -2,7 +2,7 @@ name = "test-parachain-adder-collator" description = "Collator for the adder test parachain" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/parachain/test-parachains/halt/Cargo.toml b/polkadot/parachain/test-parachains/halt/Cargo.toml index 14af139ee78..cb2918273eb 100644 --- a/polkadot/parachain/test-parachains/halt/Cargo.toml +++ b/polkadot/parachain/test-parachains/halt/Cargo.toml @@ -3,7 +3,7 @@ name = "test-parachain-halt" description = "Test parachain which executes forever" build = "build.rs" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index e49fad6275e..2766fb4e8a6 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -3,7 +3,7 @@ name = "test-parachain-undying" description = "Test parachain for zombienet integration tests" build = "build.rs" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index dd445910d9c..c5eae3802c6 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -3,7 +3,7 @@ name = "test-parachain-undying-collator" description = "Collator for the undying test parachain" edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" authors.workspace = true publish = false diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 24fdc56b32e..520d10261be 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-primitives" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/primitives/test-helpers/Cargo.toml b/polkadot/primitives/test-helpers/Cargo.toml index 1f9a434e48c..8215b842ba4 100644 --- a/polkadot/primitives/test-helpers/Cargo.toml +++ b/polkadot/primitives/test-helpers/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-primitives-test-helpers" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index 4de538a8508..b5f155b5a65 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-rpc" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 2f26a928c2e..484eb826f29 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-common" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index 4420ee488ab..30d5dc84e9d 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "slot-range-helper" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index e91eccd69da..3d7d1c9c5cb 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kusama-runtime" build = "build.rs" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/kusama/constants/Cargo.toml b/polkadot/runtime/kusama/constants/Cargo.toml index f89fee42742..e8daac10cf4 100644 --- a/polkadot/runtime/kusama/constants/Cargo.toml +++ b/polkadot/runtime/kusama/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kusama-runtime-constants" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index 6ff79b7d7d6..567a0655661 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-metrics" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 91f40f2ba9f..73f95c09292 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-parachains" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 125add700f7..1cd5abfdd6d 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-runtime" build = "build.rs" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/polkadot/constants/Cargo.toml b/polkadot/runtime/polkadot/constants/Cargo.toml index 2b7f8ccaceb..554b72f2317 100644 --- a/polkadot/runtime/polkadot/constants/Cargo.toml +++ b/polkadot/runtime/polkadot/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-constants" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index f23cdd028f1..e552920243d 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rococo-runtime" build = "build.rs" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index 174e4e83a5e..b1eb3f48f65 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rococo-runtime-constants" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index b3c9a59827b..8e212673a39 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "polkadot-test-runtime" build = "build.rs" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/test-runtime/constants/Cargo.toml b/polkadot/runtime/test-runtime/constants/Cargo.toml index 30b2a09a949..d83e92a6ce8 100644 --- a/polkadot/runtime/test-runtime/constants/Cargo.toml +++ b/polkadot/runtime/test-runtime/constants/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-runtime-constants" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 86cb7c037e8..a0410dc7d3c 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "westend-runtime" build = "build.rs" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index e792a56a546..779b2cb3110 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "westend-runtime-constants" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 65fb21708c2..91ca2015af3 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-statement-table" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 819a16d5c35..de5ec422ff4 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-voter-bags" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index bb48c82f0b7..3e5ccdb44d3 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "remote-ext-tests-bags-list" publish = false -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml index f3d4a693e11..5ca528235a5 100644 --- a/polkadot/utils/staking-miner/Cargo.toml +++ b/polkadot/utils/staking-miner/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "staking-miner" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index d33b1bf5de1..ba1944ebe85 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "xcm" description = "The basic XCM datastructures." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 062584becf6..416f5c4bd6e 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-xcm-benchmarks" authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 294919f2e18..63a616281d8 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-xcm" authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index a821a73669e..a5c50a48007 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -3,7 +3,7 @@ name = "xcm-procedural" authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [lib] proc-macro = true diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 315f63d8556..ea44ce9aa73 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -4,7 +4,7 @@ description = "Tools & types for building with XCM and its executor." authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] impl-trait-for-tuples = "0.2.1" diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index df961f178a2..7a7eb75a80e 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -4,7 +4,7 @@ description = "An abstract and configurable XCM message executor." authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] impl-trait-for-tuples = "0.2.2" diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index ecd7096c58d..d1db6cccddc 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -4,7 +4,7 @@ description = "Integration tests for the XCM Executor" authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" publish = false [dependencies] diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index 901ca49d0f7..cde85649778 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "xcm-simulator" description = "Test kit to simulate cross-chain message passing and XCM execution" -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 8c876aec29e..06635938e1a 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -4,7 +4,7 @@ description = "Examples of xcm-simulator usage." authors.workspace = true edition.workspace = true license.workspace = true -version.workspace = true +version = "1.0.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index ae090a06871..f585d506456 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "xcm-simulator-fuzzer" description = "Examples of xcm-simulator usage." -version.workspace = true +version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index fc3fa64da99..834668468f7 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" -edition = "2021" +edition.workspace = true license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/substrate/bin/node-template/pallets/template/Cargo.toml b/substrate/bin/node-template/pallets/template/Cargo.toml index 5c5482c8f78..3e6acc5ceab 100644 --- a/substrate/bin/node-template/pallets/template/Cargo.toml +++ b/substrate/bin/node-template/pallets/template/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" description = "FRAME pallet template for defining custom runtime logic." authors = ["Substrate DevHub "] homepage = "https://substrate.io" -edition = "2021" +edition.workspace = true license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 80af8a7d62b..65d0cfca59c 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" -edition = "2021" +edition.workspace = true license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index bef67b995be..c98547a33d6 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-bench" version = "0.9.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node integration benchmarks." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 41e2399f89e..01e8d871665 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "node-cli" version = "3.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Generic Substrate node implementation in Rust." build = "build.rs" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" default-run = "substrate-node" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.wasm-pack.profile.release] diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml index e98d6fa36c1..bed63697b56 100644 --- a/substrate/bin/node/executor/Cargo.toml +++ b/substrate/bin/node/executor/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-executor" version = "3.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node implementation in Rust." -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index b14dc1c719e..59700bca36e 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-inspect" version = "0.9.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node block inspection tool." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index c8b058c4a15..77bf7ad4676 100644 --- a/substrate/bin/node/primitives/Cargo.toml +++ b/substrate/bin/node/primitives/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-primitives" version = "2.0.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node low-level primitives." -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index d2daa115764..ec8d16bd27d 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-rpc" version = "3.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node rpc methods." -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index f4a6f6b9c46..09c1fd9c6f3 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "kitchensink-runtime" version = "3.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate node kitchensink runtime." -edition = "2021" +edition.workspace = true build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 89af222df59..f5a39693301 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "node-testing" version = "3.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Test utilities for Substrate node." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 4baa403e1b2..0c8bc3b32dc 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "chain-spec-builder" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" publish = false diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index b9cc4d3c264..5c1124d3984 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "subkey" version = "3.0.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Generate and restore keys for Substrate based chains such as Polkadot, Kusama and a growing number of parachains and Substrate based projects." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index 4d529fd93b4..ffbfe14e86c 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-allocator" version = "4.1.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Collection of allocator implementations." documentation = "https://docs.rs/sc-allocator" readme = "README.md" diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index b4ce9ee2970..43545095c0e 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-client-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate client interfaces." documentation = "https://docs.rs/sc-client-api" readme = "README.md" diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 2a28f9836d6..ef2fdcfd485 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-authority-discovery" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate authority discovery." readme = "README.md" diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index d8c6cd0f314..b65a5917955 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-basic-authorship" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Basic implementation of block-authoring logic." readme = "README.md" diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 3a6a0ea184d..ff2f9635b7a 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-block-builder" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate block builder" readme = "README.md" diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 32f74f13ab5..e032e24e721 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-chain-spec" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate chain configurations." readme = "README.md" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 537f8aee6ab..8b8210fe04f 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-chain-spec-derive" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Macros to derive chain spec extension traits implementation." [package.metadata.docs.rs] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index a8da74ead7e..7b827d897e0 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-cli" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate CLI interface." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 49fd61c2d15..bc9648f683a 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-aura" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Aura consensus algorithm for substrate" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index 81477cfc99a..d9588794535 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-babe" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "BABE consensus algorithm for substrate" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-consensus-babe" readme = "README.md" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index a16ec11e0b8..0735cac21e7 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "RPC extensions for the BABE consensus algorithm" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index d76abc61f6d..a5706724ebe 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "sc-consensus-beefy" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index e814f3487b4..1480d87064c 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "RPC for the BEEFY Client gadget for substrate" homepage = "https://substrate.io" diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index a66a88135f9..c9b3f221ecc 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-consensus" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Collection of common consensus specific imlementations for Substrate (client)" readme = "README.md" diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index 8d94bf988c5..07de83980bc 100644 --- a/substrate/client/consensus/epochs/Cargo.toml +++ b/substrate/client/consensus/epochs/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-epochs" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Generic epochs-based utilities for consensus" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 8ef1ee928d0..bf6549c6244 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-consensus-grandpa" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Integration of the GRANDPA finality gadget into substrate." documentation = "https://docs.rs/sc-consensus-grandpa" readme = "README.md" diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 50ea8aa21a3..fe8f17405d9 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "RPC extensions for the GRANDPA finality gadget" -repository = "https://github.com/paritytech/substrate/" -edition = "2021" +repository.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" readme = "README.md" homepage = "https://substrate.io" diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index bd3a030757a..a6430fdf1de 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-manual-seal" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Manual sealing engine for Substrate" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index 23e4cecb626..ef32425685b 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-consensus-pow" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "PoW consensus algorithm for substrate" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index a29979541e3..52c528c3028 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "sc-consensus-slots" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Generic slots-based utilities for consensus" -edition = "2021" +edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index 025d0cac212..cb9560b6cb6 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-client-db" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Client backend that uses RocksDB database as storage." readme = "README.md" diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 877e91c2021..9f41b742373 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-executor" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A crate that provides means of executing/dispatching calls into the runtime." documentation = "https://docs.rs/sc-executor" readme = "README.md" diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index 3dda7363b74..e84b9f9c85b 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-executor-common" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A set of common definitions that are needed for defining execution engines." documentation = "https://docs.rs/sc-executor-common/" readme = "README.md" diff --git a/substrate/client/executor/runtime-test/Cargo.toml b/substrate/client/executor/runtime-test/Cargo.toml index 2b397b61689..046e59c08e0 100644 --- a/substrate/client/executor/runtime-test/Cargo.toml +++ b/substrate/client/executor/runtime-test/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "sc-runtime-test" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index 36c2940eb3a..fee1afc9666 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-executor-wasmtime" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute." readme = "README.md" diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 33f991d4c67..e077f4e11a5 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-informant" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate informant." -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index cc5a16dd111..9ead4265a84 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-keystore" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Keystore (and session key management) for ed25519 based chains like Polkadot." documentation = "https://docs.rs/sc-keystore" readme = "README.md" diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 092bf1701d4..ae60fd1ce89 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "mmr-gadget" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "MMR Client gadget for substrate" homepage = "https://substrate.io" diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index c00aeb91eda..38aea978597 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "mmr-rpc" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Node-specific RPC methods for interaction with Merkle Mountain Range pallet." [package.metadata.docs.rs] diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 8680a60d015..73d2d3fa051 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -3,10 +3,10 @@ description = "Gossiping for the Substrate network protocol" name = "sc-network-gossip" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-gossip" readme = "README.md" diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 620d74dc0f5..e8d847e1419 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate network protocol" name = "sc-network" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network" readme = "README.md" diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index 54a665088f7..412d603163d 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate bitswap protocol" name = "sc-network-bitswap" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-bitswap" [package.metadata.docs.rs] diff --git a/substrate/client/network/common/Cargo.toml b/substrate/client/network/common/Cargo.toml index 634e4cdc68e..65c8e1d71c7 100644 --- a/substrate/client/network/common/Cargo.toml +++ b/substrate/client/network/common/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate network common" name = "sc-network-common" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-sync" [package.metadata.docs.rs] diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index abe1ccba08b..f426cda7fc8 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate light network protocol" name = "sc-network-light" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-light" [package.metadata.docs.rs] diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index ed9cc76d900..adfb2d6a05f 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate statement protocol" name = "sc-network-statement" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-statement" [package.metadata.docs.rs] diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index 0bbc1350518..f10dd7869bb 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate sync network protocol" name = "sc-network-sync" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-sync" [package.metadata.docs.rs] diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index 1d18aa30a1b..09f8f1fa9ef 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -3,11 +3,11 @@ description = "Integration tests for Substrate network protocol" name = "sc-network-test" version = "0.8.0" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index d5a0f28a799..5e42465974b 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate transaction protocol" name = "sc-network-transactions" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-network-transactions" [package.metadata.docs.rs] diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 63425d08879..83397f52879 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate offchain workers" name = "sc-offchain" version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/client/proposer-metrics/Cargo.toml b/substrate/client/proposer-metrics/Cargo.toml index e64a6a678bf..b6b4452ecc6 100644 --- a/substrate/client/proposer-metrics/Cargo.toml +++ b/substrate/client/proposer-metrics/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-proposer-metrics" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Basic metrics for block production." readme = "README.md" diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 50db70f2860..c13ca207cea 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-rpc-api" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate RPC interfaces." readme = "README.md" diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 70db49390db..94a0d815f2e 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-rpc-server" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate RPC servers." readme = "README.md" diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index b63291ef393..c93006753af 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate RPC interface v2." readme = "README.md" diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index bd3e7950301..c7e9977cb25 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-rpc" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate Client RPC" readme = "README.md" diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index a9e9f2e8139..4a7539aa8a5 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-service" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate service. Starts a thread that spins up the network, client, and extrinsic pool. Manages communication between them." readme = "README.md" diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index 3a423abce7a..670312e4161 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-service-test" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/state-db/Cargo.toml b/substrate/client/state-db/Cargo.toml index b8d238c6a2d..c5e8272637d 100644 --- a/substrate/client/state-db/Cargo.toml +++ b/substrate/client/state-db/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-state-db" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "State database maintenance. Handles canonicalization and pruning in the database." readme = "README.md" diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index 84cb0d38ef3..371d6736916 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-statement-store" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate statement store." readme = "README.md" @@ -29,4 +29,3 @@ sc-keystore = { path = "../keystore" } [dev-dependencies] tempfile = "3.1.0" env_logger = "0.9" - diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 6361a3bce81..48ee1b03561 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "sc-storage-monitor" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "Storage monitor service for substrate" homepage = "https://substrate.io" diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index e2ac87701af..6babb1f5c9a 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-sync-state-rpc" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "A RPC handler to create sync states for light clients." -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 4f6df49a57f..7301f28921c 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-sysinfo" version = "6.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A crate that provides basic hardware and software telemetry information." documentation = "https://docs.rs/sc-sysinfo" readme = "README.md" diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 4ca21daf6cc..5817dc207a1 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sc-telemetry" version = "4.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Telemetry utils" -edition = "2021" +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sc-telemetry" readme = "README.md" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index aa7bcbe1338..1cbb50f6d83 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -2,10 +2,10 @@ name = "sc-tracing" version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Instrumentation implementation for substrate." readme = "README.md" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 4ae836e6083..23dc9557a4b 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Helper macros for Substrate's client CLI" [package.metadata.docs.rs] diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 644465f7db1..6f56378c699 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-transaction-pool" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate transaction pool implementation." readme = "README.md" diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index a39401e27aa..65d32dc60f4 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-transaction-pool-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Transaction pool client facing API." [dependencies] diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index fe6351c9d62..885b1d26a8e 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sc-utils" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "I/O for Substrate runtimes" readme = "README.md" diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index a518ad69eff..f1ad9af50ef 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-alliance" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://docs.substrate.io/" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "The Alliance pallet provides a collective for standard-setting industry collaboration." readme = "README.md" diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 48f6ee6d062..62e71663c5b 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-asset-conversion" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME asset conversion pallet" readme = "README.md" diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 6cc2fffd85a..479631e7dd1 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -4,9 +4,9 @@ version = "4.0.0-dev" description = "Whitelist non-native assets for treasury spending and provide conversion to native balance" authors = ["William Freudenberger "] homepage = "https://substrate.io" -edition = "2021" +edition.workspace = true license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 9c0726d6508..24c7a3b32b8 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-assets" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME asset management pallet" readme = "README.md" diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index ca5ed366910..1b4eabaf0cf 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-atomic-swap" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME atomic swap pallet" readme = "README.md" diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 6a97d027b63..3d2879bb89f 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-aura" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME AURA consensus pallet" readme = "README.md" diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index c21a4f2356b..d1e37777ada 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-authority-discovery" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for authority discovery" readme = "README.md" diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 060d86daaea..ff089a8e7ad 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -2,11 +2,11 @@ name = "pallet-authorship" version = "4.0.0-dev" description = "Block and Uncle Author tracking for the FRAME" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 5ec78e313d7..e610d34197b 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-babe" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Consensus extension module for BABE consensus. Collects on-chain randomness from VRF outputs and manages epoch transitions." readme = "README.md" diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 919b8749b2b..4d6f3d768aa 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-bags-list" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet bags list" [package.metadata.docs.rs] diff --git a/substrate/frame/bags-list/fuzzer/Cargo.toml b/substrate/frame/bags-list/fuzzer/Cargo.toml index 5cdc763ffce..9944c886554 100644 --- a/substrate/frame/bags-list/fuzzer/Cargo.toml +++ b/substrate/frame/bags-list/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-bags-list-fuzzer" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzzer for FRAME pallet bags list" publish = false diff --git a/substrate/frame/bags-list/remote-tests/Cargo.toml b/substrate/frame/bags-list/remote-tests/Cargo.toml index a7f9871a894..b7408e08d55 100644 --- a/substrate/frame/bags-list/remote-tests/Cargo.toml +++ b/substrate/frame/bags-list/remote-tests/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet bags list remote test" publish = false diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index 6ca0cf9473e..8d0fc96fe59 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-balances" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage balances" readme = "README.md" diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index afd7928d707..82970ca385c 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-beefy-mmr" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" description = "BEEFY + MMR runtime utilities" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true homepage = "https://substrate.io" [dependencies] diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 53f8305aff2..ddee3c6fe8e 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "pallet-beefy" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "BEEFY FRAME pallet" homepage = "https://substrate.io" diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 7964258af64..8b47a1f948b 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-benchmarking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Macro for benchmarking a FRAME runtime." readme = "README.md" diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index d1e20c63720..3a08c7a67e1 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-benchmarking-pallet-pov" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Pallet for testing FRAME PoV benchmarking" [package.metadata.docs.rs] diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index a2f6054dd12..2fab40b3ef5 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-bounties" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage bounties" readme = "README.md" diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 286eca09f66..edb3c5f63bb 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -2,11 +2,11 @@ name = "pallet-broker" version = "0.1.0" description = "Brokerage tool for managing Polkadot Core scheduling" -authors = ["Parity Technologies "] +authors.workspace = true homepage = "https://substrate.io" -edition = "2021" +edition.workspace = true license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index 07dd737d3d9..b2ca01e3781 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-child-bounties" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage child bounties" readme = "README.md" diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 6f957233090..c9180d2bc71 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-collective" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." readme = "README.md" diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index f1bbe38a878..8d6a9fd9cdb 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "pallet-contracts" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for WASM contracts" readme = "README.md" include = ["src/**/*", "README.md", "CHANGELOG.md"] diff --git a/substrate/frame/contracts/primitives/Cargo.toml b/substrate/frame/contracts/primitives/Cargo.toml index 4796ace915b..8a845f6db44 100644 --- a/substrate/frame/contracts/primitives/Cargo.toml +++ b/substrate/frame/contracts/primitives/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-contracts-primitives" version = "24.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A crate that hosts a common definitions that are relevant for the pallet-contracts." readme = "README.md" diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index 8a63875f2a9..afc6ce281bb 100644 --- a/substrate/frame/contracts/proc-macro/Cargo.toml +++ b/substrate/frame/contracts/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Procedural macros used in pallet_contracts" [package.metadata.docs.rs] diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index c3e07700b8e..6efa631cd97 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-conviction-voting" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for conviction voting in referenda" readme = "README.md" diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index f27791f9c9f..62e0186cd5c 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-core-fellowship" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Logic as per the description of The Fellowship for core Polkadot technology" readme = "README.md" diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 71cd78913eb..d686684b638 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-democracy" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for democracy" readme = "README.md" diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index 49b25b49290..b4a3337e418 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "PALLET two phase election providers" [package.metadata.docs.rs] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index f6bc8e60677..f2072b81723 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-election-provider-e2e-test" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME election provider multi phase pallet tests with staking pallet, bags-list and session pallets" publish = false @@ -36,4 +36,3 @@ pallet-bags-list = { path = "../../bags-list" } pallet-balances = { path = "../../balances" } pallet-timestamp = { path = "../../timestamp" } pallet-session = { path = "../../session" } - diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index d6d785e6ac4..09e1794965c 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-election-provider-support" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "election provider supporting traits" [package.metadata.docs.rs] diff --git a/substrate/frame/election-provider-support/benchmarking/Cargo.toml b/substrate/frame/election-provider-support/benchmarking/Cargo.toml index 42a10a7f5e6..a8c56b425fd 100644 --- a/substrate/frame/election-provider-support/benchmarking/Cargo.toml +++ b/substrate/frame/election-provider-support/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Benchmarking for election provider support onchain config trait" [package.metadata.docs.rs] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 3dbb9b1f16d..bc0127e91ba 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "NPoS Solution Type" [package.metadata.docs.rs] 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 2871010c640..1bf4196e825 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzzer for phragmén solution type implementation." publish = false diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 327af3f3ba5..2dfe8e42151 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-elections-phragmen" version = "5.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet based on seq-Phragmén election method." readme = "README.md" diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 78bb819959a..b072416b612 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-examples" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "The single package with various examples for frame pallets" [package.metadata.docs.rs] diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index 03179affbde..cb3bc3f2c82 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-example-basic" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example pallet" readme = "README.md" diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 38aea49b232..3a6b56b57fa 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-default-config-example" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example pallet demonstrating derive_impl / default_config in action" readme = "README.md" diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index 4d8e3118687..8cd3fda6712 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-dev-mode" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example pallet" readme = "README.md" diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index a152ee911ed..26018ad7d97 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-example-kitchensink" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example kitchensink pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index ca42a6948a0..f33de594a2d 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-example-offchain-worker" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example pallet for offchain worker" readme = "README.md" diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index e5070cd1a13..e8714009c5e 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-example-split" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME example splitted pallet" readme = "README.md" diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 4cc6102263d..b3961009123 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-executive" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME executives engine" readme = "README.md" diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index efdcf72ba05..a2aa769620c 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-fast-unstake" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME fast unstake pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index cd609f9a626..c1dc926ff5e 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-glutton" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for pushing a chain to its weight limits" readme = "README.md" diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 5fcb4f98176..116e786a6c8 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-grandpa" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for GRANDPA finality gadget" readme = "README.md" diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 6063b89df0f..533e8e68374 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-identity" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME identity management pallet" readme = "README.md" diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 9cbf0c1635b..5f612c229f0 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-im-online" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME's I'm online pallet" readme = "README.md" diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index 6b1af69cc6d..2018c7a063e 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-indices" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME indices management pallet" readme = "README.md" diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index d84c22c5aec..57d4da45268 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Insecure do not use in production: FRAME randomness collective flip pallet" readme = "README.md" diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index a3828fa1719..6b6109fbc53 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-lottery" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME Participation Lottery Pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index adf1c500de1..52d8ee560f7 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-membership" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME membership management pallet" readme = "README.md" diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 92638f202b1..3a21f5bc86f 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-mmr" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME Merkle Mountain Range pallet." [package.metadata.docs.rs] diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 655c88c39f2..81f929c8f07 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -1,11 +1,11 @@ [package] -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true name = "pallet-message-queue" version = "7.0.0-dev" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to queue and process messages" [dependencies] diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 8846fa2c23c..83b9a09b1f3 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-multisig" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME multi-signature dispatch pallet" readme = "README.md" diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 1edbf2952c2..0e6b85ee76e 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nft-fractionalization" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to convert non-fungible to fungible tokens." readme = "README.md" diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 33fb1398211..67113b656fd 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nfts" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME NFTs pallet" readme = "README.md" diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index b4485f6c127..9c0d817723d 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Runtime API for the FRAME NFTs pallet." readme = "README.md" diff --git a/substrate/frame/nicks/Cargo.toml b/substrate/frame/nicks/Cargo.toml index 9756a06c580..c8e8fa0467a 100644 --- a/substrate/frame/nicks/Cargo.toml +++ b/substrate/frame/nicks/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nicks" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for nick management" readme = "README.md" diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index 3ca1960e89e..c8465285ffa 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nis" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for rewarding account freezing." readme = "README.md" diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index cae46420fef..d666437e42e 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-node-authorization" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for node authorization" [package.metadata.docs.rs] diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 01e998a5216..4923af0ab0c 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nomination-pools" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME nomination pools pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index d9ddc828679..6375411b7e2 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME nomination pools pallet benchmarking" readme = "README.md" diff --git a/substrate/frame/nomination-pools/fuzzer/Cargo.toml b/substrate/frame/nomination-pools/fuzzer/Cargo.toml index 7dde8733e3f..b9d0a6197f8 100644 --- a/substrate/frame/nomination-pools/fuzzer/Cargo.toml +++ b/substrate/frame/nomination-pools/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nomination-pools-fuzzer" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzzer for fixed point arithmetic primitives." documentation = "https://docs.rs/sp-arithmetic-fuzzer" publish = false diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml index c3ca47e824c..c3aa8035c95 100644 --- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml +++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Runtime API for nomination-pools FRAME pallet" readme = "README.md" diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index 70117daa60a..a44d885d653 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-nomination-pools-test-staking" version = "1.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME nomination pools pallet tests with the staking pallet" publish = false diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 49a9db38a8e..7e9b093a038 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-offences" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME offences pallet" readme = "README.md" diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 91425154106..141ea0cb466 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME offences pallet benchmarking" readme = "README.md" diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index a145ef306cf..f3165a2f5f9 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -2,11 +2,11 @@ name = "pallet-paged-list" version = "0.1.0" description = "FRAME pallet that provides a paged list data structure." -authors = ["Parity Technologies "] +authors.workspace = true homepage = "https://substrate.io" -edition = "2021" +edition.workspace = true license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/paged-list/fuzzer/Cargo.toml b/substrate/frame/paged-list/fuzzer/Cargo.toml index f78247f2abe..a6f499d0da1 100644 --- a/substrate/frame/paged-list/fuzzer/Cargo.toml +++ b/substrate/frame/paged-list/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-paged-list-fuzzer" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzz storage types of pallet-paged-list" publish = false diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index e9588887ac8..e56110c1eae 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-preimage" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for storing preimages of hashes" [dependencies] diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 9618ec006e7..ba30bd147bd 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-proxy" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME proxying pallet" readme = "README.md" diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 613da42cb17..9788b1df630 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-ranked-collective" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Ranked collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." readme = "README.md" diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index e3d292e2477..38cecd5c44a 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-recovery" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME account recovery pallet" readme = "README.md" diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index a155a8a4b01..6c0e86db346 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-referenda" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for inclusive on-chain decisions" readme = "README.md" diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index cfd34209c1a..cf98ae2794a 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-remark" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Remark storage pallet" readme = "README.md" diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index c2df0a79e69..fa3cf981d7c 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-root-offences" version = "1.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME root offences pallet" readme = "README.md" diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index 9e0c0d38511..8c6c2dc46ef 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-root-testing" version = "1.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME root testing pallet" readme = "README.md" publish = false diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index cbb5f08b6cd..a934092ee53 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-safe-mode" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME safe-mode pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index e1a3a36a7c5..89b92fa7e7b 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-salary" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Paymaster" readme = "README.md" diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index b9b296cd1ea..3ad49ef5e66 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-scheduler" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME Scheduler pallet" readme = "README.md" diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index 5c5f655b32c..5bd23ce22ce 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-scored-pool" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for scored pools" readme = "README.md" diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 4d81e102f18..fa72d6c7278 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-session" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME sessions pallet" readme = "README.md" diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index f4138c077e5..df423e162e9 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-session-benchmarking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME sessions pallet benchmarking" readme = "README.md" diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 9e2bbe3b354..c112e2bbb8c 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-society" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME society pallet" readme = "README.md" diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index e9873ba6580..491d19008da 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-staking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet staking" readme = "README.md" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index bdffe96d97e..dc845848161 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Reward Curve for FRAME staking pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/staking/reward-fn/Cargo.toml b/substrate/frame/staking/reward-fn/Cargo.toml index cf77299f5ba..25f4c33dd62 100644 --- a/substrate/frame/staking/reward-fn/Cargo.toml +++ b/substrate/frame/staking/reward-fn/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Reward function for FRAME staking pallet" [package.metadata.docs.rs] diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml index b2972d35b68..5f49df254ce 100644 --- a/substrate/frame/staking/runtime-api/Cargo.toml +++ b/substrate/frame/staking/runtime-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "RPC runtime API for transaction payment FRAME pallet" readme = "README.md" diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 82585622297..8ba57fc8f71 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-state-trie-migration" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet migration of trie" [package.metadata.docs.rs] diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index 18f1ec45f98..eded681c47c 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-statement" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for statement store" [package.metadata.docs.rs] diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 6bc8086a452..a75a0c504f9 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-sudo" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for sudo" readme = "README.md" diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 24247894739..fa85181b31e 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-support" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Support code for the runtime." readme = "README.md" diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index d08b3fc2b4e..a25216ea9aa 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-support-procedural" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Proc macro of Support code for the runtime." [package.metadata.docs.rs] diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 4d2e4c8756f..3a56f29eb19 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-support-procedural-tools" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Proc macro helpers for procedural macros" [package.metadata.docs.rs] diff --git a/substrate/frame/support/procedural/tools/derive/Cargo.toml b/substrate/frame/support/procedural/tools/derive/Cargo.toml index 193df53f129..68e85a2060d 100644 --- a/substrate/frame/support/procedural/tools/derive/Cargo.toml +++ b/substrate/frame/support/procedural/tools/derive/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-support-procedural-tools-derive" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Use to derive parsing for parsing struct." [package.metadata.docs.rs] diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index e5057d5d986..1519d3f5cc3 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "frame-support-test" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 444d3fbb5a8..9c165cd03e8 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "frame-support-test-compile-pass" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 279e0fc5ae3..8aae80362d3 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "frame-support-test-pallet" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 0fd09dabd9b..32bcc796f60 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-system" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME system module" readme = "README.md" diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 8a03e75fa21..0bd9299f783 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-system-benchmarking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME System benchmarking" readme = "README.md" diff --git a/substrate/frame/system/rpc/runtime-api/Cargo.toml b/substrate/frame/system/rpc/runtime-api/Cargo.toml index b4dcc396097..81b6d946d46 100644 --- a/substrate/frame/system/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/system/rpc/runtime-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Runtime API definition required by System RPC extensions." readme = "README.md" diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index e2ae1c5dee8..a39c79892d1 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-timestamp" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME Timestamp Module" documentation = "https://docs.rs/pallet-timestamp" readme = "README.md" diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 947276bb43e..63b5c5cefff 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-tips" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage tips" readme = "README.md" diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 4206966de06..6fe9c7eb7e3 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-transaction-payment" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage transaction payments" readme = "README.md" diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 1155d9c39cd..3ce7aa0a31b 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-asset-conversion-tx-payment" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Pallet to manage transaction payments in assets by converting them to native assets." readme = "README.md" diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 3e5a5e36aba..d89336fbf9f 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "pallet to manage transaction payments in assets" readme = "README.md" diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index b0183d812b9..8a0052e0337 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "RPC interface for the transaction payment pallet." readme = "README.md" diff --git a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 76adc50608e..af098fd34ed 100644 --- a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "RPC runtime API for transaction payment FRAME pallet" readme = "README.md" diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index 1a28d46c5bf..1f2773f6285 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-transaction-storage" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Storage chain pallet" readme = "README.md" diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 039f2b402a6..f5bcb17b406 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-treasury" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet to manage treasury" readme = "README.md" diff --git a/substrate/frame/try-runtime/Cargo.toml b/substrate/frame/try-runtime/Cargo.toml index 7869e0143cb..1bb3283b1de 100644 --- a/substrate/frame/try-runtime/Cargo.toml +++ b/substrate/frame/try-runtime/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-try-runtime" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for democracy" [package.metadata.docs.rs] diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 13d2b6a1dae..356693d90f0 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-tx-pause" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME transaction pause pallet" readme = "README.md" diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 77affc50b0b..b0c063a83e7 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-uniques" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME NFT asset management pallet" readme = "README.md" diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index e4b73f5094f..1f803b6ca5b 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-utility" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME utilities pallet" readme = "README.md" diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index f16150d9580..18e3a4aeaa1 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-vesting" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for manage vesting" readme = "README.md" diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index fade1e29e56..ec78b03c08b 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pallet-whitelist" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME pallet for whitelisting call, and dispatch from specific origin" [package.metadata.docs.rs] diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index 1f23bbed8be..c5611b22017 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-api" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate runtime api primitives" readme = "README.md" diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 862cf00fdd6..c415813b978 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-api-proc-macro" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Macros for declaring and implementing runtime apis." documentation = "https://docs.rs/sp-api-proc-macro" diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 70079b8f1b0..0cc3ce7969c 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-api-test" version = "2.0.1" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 75b3ed35025..0eea63fefcb 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-application-crypto" version = "23.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Provides facilities for generating application specific crypto wrapper types." license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sp-application-crypto" readme = "README.md" diff --git a/substrate/primitives/application-crypto/test/Cargo.toml b/substrate/primitives/application-crypto/test/Cargo.toml index 4b3c9f2c66f..a6f4f108c8f 100644 --- a/substrate/primitives/application-crypto/test/Cargo.toml +++ b/substrate/primitives/application-crypto/test/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "sp-application-crypto-test" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Integration tests for application-crypto" license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 13ede731b0b..ba7f6f8e176 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-arithmetic" version = "16.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Minimal fixed point arithmetic primitives and types for runtime." documentation = "https://docs.rs/sp-arithmetic" readme = "README.md" diff --git a/substrate/primitives/arithmetic/fuzzer/Cargo.toml b/substrate/primitives/arithmetic/fuzzer/Cargo.toml index 76b0ef26649..eded5a954c5 100644 --- a/substrate/primitives/arithmetic/fuzzer/Cargo.toml +++ b/substrate/primitives/arithmetic/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-arithmetic-fuzzer" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzzer for fixed point arithmetic primitives." documentation = "https://docs.rs/sp-arithmetic-fuzzer" publish = false diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 1a45f08c19b..024711bd94a 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-authority-discovery" version = "4.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Authority discovery primitives" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/block-builder/Cargo.toml b/substrate/primitives/block-builder/Cargo.toml index d80fa29f352..269eb539532 100644 --- a/substrate/primitives/block-builder/Cargo.toml +++ b/substrate/primitives/block-builder/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-block-builder" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "The block builder runtime api." readme = "README.md" diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 9a3110d7d84..418f9458985 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-blockchain" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate blockchain traits and primitives." documentation = "https://docs.rs/sp-blockchain" readme = "README.md" diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 25a66d9b9b9..55c81bd71ec 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-consensus-aura" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Primitives for Aura consensus" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index efa455b8df7..ba011c84ea5 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-consensus-babe" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Primitives for BABE consensus" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 72ca99f3c34..2c38917999f 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-consensus-beefy" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "Primitives for BEEFY protocol." [package.metadata.docs.rs] diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 6e929dabb5b..284e00b272e 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-consensus" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Common utilities for building and using consensus engines in substrate." documentation = "https://docs.rs/sp-consensus/" readme = "README.md" diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index fb9b708706d..bf2ae2921a4 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-consensus-grandpa" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Primitives for GRANDPA integration, suitable for WASM compilation." documentation = "https://docs.rs/sp-consensus-grandpa" readme = "README.md" diff --git a/substrate/primitives/consensus/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index 457de67137d..cc4e961dbb6 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-consensus-pow" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Primitives for Aura consensus" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index aae9fa354bb..faf5a9ee956 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-consensus-slots" version = "0.10.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Primitives for slots-based consensus" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 12360472a4e..4300c6a08fa 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-core" version = "21.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Shareable Substrate types." documentation = "https://docs.rs/sp-core" diff --git a/substrate/primitives/core/hashing/Cargo.toml b/substrate/primitives/core/hashing/Cargo.toml index a4ddb6363f7..bd22bd79e7d 100644 --- a/substrate/primitives/core/hashing/Cargo.toml +++ b/substrate/primitives/core/hashing/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-core-hashing" version = "9.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Primitive core crate hashing implementation." documentation = "https://docs.rs/sp-core-hashing" diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index ffb546b0715..d3a74d4bb81 100644 --- a/substrate/primitives/core/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-core-hashing-proc-macro" version = "9.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "This crate provides procedural macros for calculating static hash." documentation = "https://docs.rs/sp-core-hashing-proc-macro" diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 2af95948a95..3ee9fea6a36 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-crypto-ec-utils" version = "0.4.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Host function interface for common elliptic curve operations in Substrate runtimes" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/database/Cargo.toml b/substrate/primitives/database/Cargo.toml index b1105f88ba5..430895236d4 100644 --- a/substrate/primitives/database/Cargo.toml +++ b/substrate/primitives/database/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-database" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate database trait." documentation = "https://docs.rs/sp-database" readme = "README.md" diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index bbac79a8465..bd35939a8b9 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-debug-derive" version = "8.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Macros to derive runtime debug implementation." documentation = "https://docs.rs/sp-debug-derive" diff --git a/substrate/primitives/externalities/Cargo.toml b/substrate/primitives/externalities/Cargo.toml index 7468237c2a0..417eb363867 100644 --- a/substrate/primitives/externalities/Cargo.toml +++ b/substrate/primitives/externalities/Cargo.toml @@ -2,10 +2,10 @@ name = "sp-externalities" version = "0.19.0" license = "Apache-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate externalities abstraction" documentation = "https://docs.rs/sp-externalities" readme = "README.md" diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index d1ee4ae0e70..fb92f0223d0 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-genesis-builder" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate GenesisConfig builder API" readme = "README.md" diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 49bc15690d7..d3ac94aa5fb 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-inherents" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Provides types and traits for creating and checking inherents." documentation = "https://docs.rs/sp-inherents" readme = "README.md" diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index d9bd1d5923f..4793938617e 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-io" version = "23.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "I/O for Substrate runtimes" documentation = "https://docs.rs/sp-io" readme = "README.md" diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 5c206da6bb7..1ab78eeed45 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-keyring" version = "24.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Keyring support code for the runtime. A set of test accounts." documentation = "https://docs.rs/sp-keyring" readme = "README.md" diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index a3744d38d2e..ff7c27bf565 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-keystore" version = "0.27.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Keystore primitives." documentation = "https://docs.rs/sp-core" diff --git a/substrate/primitives/maybe-compressed-blob/Cargo.toml b/substrate/primitives/maybe-compressed-blob/Cargo.toml index 67f93c51727..da4c412c452 100644 --- a/substrate/primitives/maybe-compressed-blob/Cargo.toml +++ b/substrate/primitives/maybe-compressed-blob/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Handling of blobs, usually Wasm code, which may be compresed" documentation = "https://docs.rs/sp-maybe-compressed-blob" readme = "README.md" diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index b986eda2a44..4d985e7a784 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-mmr-primitives" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Merkle Mountain Range primitives." [package.metadata.docs.rs] diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index d3ec0abaff6..d17c654aaf3 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-metadata-ir" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Intermediate representation of the runtime metadata." documentation = "https://docs.rs/sp-metadata-ir" diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index da253efdc99..00b4bd14b7d 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-npos-elections" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "NPoS election algorithm primitives" readme = "README.md" diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 733b0e51060..8a36cea3b2e 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Fuzzer for phragmén implementation." documentation = "https://docs.rs/sp-npos-elections-fuzzer" publish = false diff --git a/substrate/primitives/offchain/Cargo.toml b/substrate/primitives/offchain/Cargo.toml index 4a3549e9db8..5f8821b43c7 100644 --- a/substrate/primitives/offchain/Cargo.toml +++ b/substrate/primitives/offchain/Cargo.toml @@ -3,10 +3,10 @@ description = "Substrate offchain workers primitives" name = "sp-offchain" version = "4.0.0-dev" license = "Apache-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/panic-handler/Cargo.toml b/substrate/primitives/panic-handler/Cargo.toml index e73cfa98ca4..428062757c1 100644 --- a/substrate/primitives/panic-handler/Cargo.toml +++ b/substrate/primitives/panic-handler/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-panic-handler" version = "8.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Custom panic hook with bug report link" documentation = "https://docs.rs/sp-panic-handler" readme = "README.md" diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index 273c39e7c94..d2bbaeff3d2 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-rpc" version = "6.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate RPC primitives and utilities." readme = "README.md" diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index dc1efcd2dff..69a0d112a16 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-runtime-interface" version = "17.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate runtime interface" documentation = "https://docs.rs/sp-runtime-interface/" readme = "README.md" diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 4b50dfe2a7a..3488e4f50bf 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "This crate provides procedural macros for usage within the context of the Substrate runtime interface." documentation = "https://docs.rs/sp-runtime-interface-proc-macro" diff --git a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index ec047c279ec..8e06aac851f 100644 --- a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-runtime-interface-test-wasm-deprecated" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml index ad577454dde..de0d6f9a13e 100644 --- a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-runtime-interface-test-wasm" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/primitives/runtime-interface/test/Cargo.toml b/substrate/primitives/runtime-interface/test/Cargo.toml index 417578105cb..feb6a454af1 100644 --- a/substrate/primitives/runtime-interface/test/Cargo.toml +++ b/substrate/primitives/runtime-interface/test/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-runtime-interface-test" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" publish = false homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 99315ef07ec..7f31f0930b1 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-runtime" version = "24.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Runtime Modules shared primitive types." documentation = "https://docs.rs/sp-runtime" readme = "README.md" diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index a4326dab7ba..9a5e77c9dc2 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-session" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Primitives for sessions" readme = "README.md" diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index dcbce7ccfd0..9f67446969d 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-staking" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A crate which contains primitives that are useful for implementation that uses staking approaches in general. Definitions related to sessions, slashing, etc go here." readme = "README.md" diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index f9793f8ddef..3ab21308c3c 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-state-machine" version = "0.28.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Substrate State Machine" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sp-state-machine" readme = "README.md" diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 875e8825b6b..cf41d9f8299 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-statement-store" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "A crate which contains primitives related to the statement store" readme = "README.md" diff --git a/substrate/primitives/std/Cargo.toml b/substrate/primitives/std/Cargo.toml index 4c58d147c7a..2283a4a97a4 100644 --- a/substrate/primitives/std/Cargo.toml +++ b/substrate/primitives/std/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-std" version = "8.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Lowest-abstraction level for the Substrate runtime: just exports useful primitives from std or client/alloc to be used with any code that depends on the runtime." documentation = "https://docs.rs/sp-std" readme = "README.md" diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 1f18a49befc..01a9b9b650a 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-storage" version = "13.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true description = "Storage related primitives" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true documentation = "https://docs.rs/sp-storage/" readme = "README.md" diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 3b5dc6b4f55..a5d7b518a69 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-test-primitives" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 224ec542c6b..7de2a7d904d 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-timestamp" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate core types and inherents for timestamps." readme = "README.md" diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index 045c17627ab..0f7e217ec38 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -2,10 +2,10 @@ name = "sp-tracing" version = "10.0.0" license = "Apache-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Instrumentation primitives and macros for Substrate." readme = "README.md" diff --git a/substrate/primitives/transaction-pool/Cargo.toml b/substrate/primitives/transaction-pool/Cargo.toml index c78c3a31720..d1d38ffa1af 100644 --- a/substrate/primitives/transaction-pool/Cargo.toml +++ b/substrate/primitives/transaction-pool/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-transaction-pool" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Transaction pool runtime facing API." documentation = "https://docs.rs/sp-transaction-pool" readme = "README.md" diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index 1683fea2549..9efff2892bd 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Transaction storage proof primitives" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 58a0f5f9659..31eb009328c 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-trie" version = "22.0.0" -authors = ["Parity Technologies "] +authors.workspace = true description = "Patricia trie stuff using a parity-scale-codec node format" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true license = "Apache-2.0" -edition = "2021" +edition.workspace = true homepage = "https://substrate.io" documentation = "https://docs.rs/sp-trie" readme = "README.md" diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 1e4449d4c44..bcd701c2f6e 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-version" version = "22.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Version module for the Substrate runtime; Provides a function that returns the runtime version." documentation = "https://docs.rs/sp-version" readme = "README.md" diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 676c9d9b44a..e7cec134ed5 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-version-proc-macro" version = "8.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Macro for defining a runtime version." documentation = "https://docs.rs/sp-api-proc-macro" diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 6f7322612e8..92f884e3fd2 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-wasm-interface" version = "14.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Types and traits for interfacing between the host and the wasm runtime." documentation = "https://docs.rs/sp-wasm-interface" readme = "README.md" diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index edbf68a8253..467cb145c94 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sp-weights" version = "20.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Types and traits for interfacing between the host and the wasm runtime." documentation = "https://docs.rs/sp-wasm-interface" diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 1fc35b63b1d..5cd90a25f6c 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "node-template-release" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0 WITH Classpath-exception-2.0" homepage = "https://substrate.io" publish = false diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index f568223dbf1..977d1f69405 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-test-utils" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate test utilities" publish = false diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index a5f83ff9a2c..9c4167c9b6e 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -2,11 +2,11 @@ name = "substrate-cli-test-utils" description = "CLI testing utilities" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 1a65c60ab89..1ee3e74fdd1 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -2,11 +2,11 @@ name = "substrate-test-client" description = "Client testing utilities" version = "2.0.1" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/test-utils/derive/Cargo.toml b/substrate/test-utils/derive/Cargo.toml index b5d73b8e993..8299f6db048 100644 --- a/substrate/test-utils/derive/Cargo.toml +++ b/substrate/test-utils/derive/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-test-utils-derive" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate test utilities macros" publish = false diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 0a9406e8af9..654479f5fdd 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "substrate-test-runtime" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/test-utils/runtime/client/Cargo.toml b/substrate/test-utils/runtime/client/Cargo.toml index 657f648ecf2..40cfa8ab1b7 100644 --- a/substrate/test-utils/runtime/client/Cargo.toml +++ b/substrate/test-utils/runtime/client/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-test-runtime-client" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index 2e4628ffcfa..cb6ee6d79f4 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-test-runtime-transaction-pool" version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/test-utils/test-crate/Cargo.toml b/substrate/test-utils/test-crate/Cargo.toml index e42e2d7e9ea..bb68c9f18ed 100644 --- a/substrate/test-utils/test-crate/Cargo.toml +++ b/substrate/test-utils/test-crate/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-test-utils-test-crate" version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true publish = false [package.metadata.docs.rs] diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index fc7566ab240..6bb1d5f0f1e 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "binary-merkle-tree" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate" +repository.workspace = true description = "A no-std/Substrate compatible library to construct binary merkle tree." homepage = "https://substrate.io" diff --git a/substrate/utils/build-script-utils/Cargo.toml b/substrate/utils/build-script-utils/Cargo.toml index 35096f282ef..ab15d5552c2 100644 --- a/substrate/utils/build-script-utils/Cargo.toml +++ b/substrate/utils/build-script-utils/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-build-script-utils" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Crate with utility functions for `build.rs` scripts." readme = "README.md" diff --git a/substrate/utils/fork-tree/Cargo.toml b/substrate/utils/fork-tree/Cargo.toml index ece7cac8fd3..eea500641fe 100644 --- a/substrate/utils/fork-tree/Cargo.toml +++ b/substrate/utils/fork-tree/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "fork-tree" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Utility library for managing tree-like ordered data with logic for pruning the tree while finalizing nodes." documentation = "https://docs.rs/fork-tree" readme = "README.md" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index b3181dff15e..7238aa2ba32 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-benchmarking-cli" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "CLI for benchmarking FRAME" readme = "README.md" diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 4fa2356b2e7..4e6392d5102 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-frame-cli" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "cli interface for FRAME" documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" diff --git a/substrate/utils/frame/generate-bags/Cargo.toml b/substrate/utils/frame/generate-bags/Cargo.toml index 798f5211226..471f18b4ab4 100644 --- a/substrate/utils/frame/generate-bags/Cargo.toml +++ b/substrate/utils/frame/generate-bags/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "generate-bags" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Bag threshold generation script for pallet-bag-list" [dependencies] diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index c29d3272628..c72912aeafc 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "node-runtime-generate-bags" version = "3.0.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Bag threshold generation script for pallet-bag-list and kitchensink-runtime." publish = false diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 01c7af61e60..49f9fac11f6 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "frame-remote-externalities" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "An externalities provided environment that can load itself from remote nodes or cached files" [package.metadata.docs.rs] diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index cf6d3c4dedb..d0f323c096f 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-rpc-client" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Shared JSON-RPC client" [package.metadata.docs.rs] diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index b09b0c578f3..d82377593c7 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Node-specific RPC methods for interaction with state trie migration." readme = "README.md" diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 091732d9bf9..5cc4f6cbc09 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -5,10 +5,10 @@ authors = [ "Parity Technologies ", "Andrew Dirksen ", ] -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Substrate RPC for FRAME's support" [package.metadata.docs.rs] diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 8009d6b2f2d..77c3b7eeee3 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "FRAME's system exposed over Substrate RPC" readme = "README.md" diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index ff8ee73d1a7..01b655cea8a 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "try-runtime-cli" version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true description = "Cli command runtime testing and dry-running" [package.metadata.docs.rs] diff --git a/substrate/utils/prometheus/Cargo.toml b/substrate/utils/prometheus/Cargo.toml index e84a6f4b303..bf999a66111 100644 --- a/substrate/utils/prometheus/Cargo.toml +++ b/substrate/utils/prometheus/Cargo.toml @@ -3,10 +3,10 @@ description = "Endpoint to expose Prometheus metrics" name = "substrate-prometheus-endpoint" version = "0.10.0-dev" license = "Apache-2.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true readme = "README.md" [package.metadata.docs.rs] diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 2e57a4b73fa..73586ebe614 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "substrate-wasm-builder" version = "5.0.0-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Utility for building WASM binaries" -edition = "2021" +edition.workspace = true readme = "README.md" -repository = "https://github.com/paritytech/substrate/" +repository.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -- GitLab From fa3b84286089da5c3be5b867c4432db634edc5cb Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 29 Aug 2023 09:30:09 -0300 Subject: [PATCH 003/633] Add instruction limit when decoding XCMs (#1227) * Add instruction limit when decoding XCMs * Make the instruction limit a constant * Use vec for buffer * ".git/.scripts/commands/fmt/fmt.sh" * Go back on std * Use BoundedVec's Decode implementation * ".git/.scripts/commands/fmt/fmt.sh" * Use an actual BoundedVec to decode XCMs * Change comment location * ".git/.scripts/commands/fmt/fmt.sh" * Remove unused imports * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- polkadot/xcm/src/v3/mod.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 36086795786..ef3306d276f 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -22,14 +22,16 @@ use super::v2::{ }; use crate::{DoubleEncoded, GetWeight}; use alloc::{vec, vec::Vec}; -use bounded_collections::{parameter_types, BoundedVec}; +use bounded_collections::{parameter_types, BoundedVec, ConstU32}; use core::{ convert::{TryFrom, TryInto}, fmt::Debug, result, }; use derivative::Derivative; -use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; +use parity_scale_codec::{ + self, Decode, Encode, Error as CodecError, Input as CodecInput, MaxEncodedLen, +}; use scale_info::TypeInfo; mod junction; @@ -60,13 +62,23 @@ pub const VERSION: super::Version = 3; /// An identifier for a query. pub type QueryId = u64; -#[derive(Derivative, Default, Encode, Decode, TypeInfo)] +// TODO (v4): Use `BoundedVec` instead of `Vec` +#[derive(Derivative, Default, Encode, TypeInfo)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] -#[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(Call))] pub struct Xcm(pub Vec>); +const MAX_INSTRUCTIONS_TO_DECODE: u32 = 100; + +impl Decode for Xcm { + fn decode(input: &mut I) -> core::result::Result { + let bounded_instructions = + BoundedVec::, ConstU32>::decode(input)?; + Ok(Self(bounded_instructions.into_inner())) + } +} + impl Xcm { /// Create an empty instance. pub fn new() -> Self { @@ -1426,4 +1438,17 @@ mod tests { let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); assert_eq!(new_xcm, xcm); } + + #[test] + fn decoding_fails_when_too_many_instructions() { + let small_xcm = Xcm::<()>(vec![ClearOrigin; 20]); + let bytes = small_xcm.encode(); + let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); + assert!(matches!(decoded_xcm, Ok(_))); + + let big_xcm = Xcm::<()>(vec![ClearOrigin; 64_000]); + let bytes = big_xcm.encode(); + let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); + assert!(matches!(decoded_xcm, Err(CodecError { .. }))); + } } -- GitLab From 7c69d1444184a0da9bad065842eb83db11ee9304 Mon Sep 17 00:00:00 2001 From: Joyce Siqueira <98593770+the-right-joyce@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:47:44 +0200 Subject: [PATCH 004/633] update contribution guidelines, remove redundant files (#1181) * update contribution guidelines, remove redundant files * removing doc ref labels, updating links on contribution * add manifest formatting * update title Co-authored-by: Oliver Tale-Yazdi * update links to the new repo * terminal friendly convention * update doc guideline format --------- Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi --- cumulus/docs/documentation.md | 1 - docs/CODE_OF_CONDUCT.md | 76 +++++++ docs/CONTRIBUTING.md | 128 +++++++++++ .../DOCUMENTATION_GUIDELINE.md | 201 +++++++++++++----- .../docs => docs}/PULL_REQUEST_TEMPLATE.md | 8 +- {polkadot => docs}/SECURITY.md | 55 +++-- docs/STYLE_GUIDE.md | 180 ++++++++++++++++ polkadot/CODE_OF_CONDUCT.md | 52 ----- polkadot/CONTRIBUTING.md | 46 ---- substrate/docs/CODE_OF_CONDUCT.md | 52 ----- substrate/docs/CONTRIBUTING.md | 134 ------------ 11 files changed, 581 insertions(+), 352 deletions(-) delete mode 100644 cumulus/docs/documentation.md create mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 docs/CONTRIBUTING.md rename substrate/docs/DOCUMENTATION_GUIDELINES.md => docs/DOCUMENTATION_GUIDELINE.md (56%) rename {substrate/docs => docs}/PULL_REQUEST_TEMPLATE.md (73%) rename {polkadot => docs}/SECURITY.md (69%) create mode 100644 docs/STYLE_GUIDE.md delete mode 100644 polkadot/CODE_OF_CONDUCT.md delete mode 100644 polkadot/CONTRIBUTING.md delete mode 100644 substrate/docs/CODE_OF_CONDUCT.md delete mode 100644 substrate/docs/CONTRIBUTING.md diff --git a/cumulus/docs/documentation.md b/cumulus/docs/documentation.md deleted file mode 100644 index 383f7ff3c40..00000000000 --- a/cumulus/docs/documentation.md +++ /dev/null @@ -1 +0,0 @@ -Was moved [here](https://github.com/paritytech/labels/blob/main/docs/doc_cumulus.md) \ No newline at end of file diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..1a9f21de775 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers +pledge to making participation in our project and our community a harassment-free experience for +everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level +of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit + permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +### Facilitation, Not Strongarming + +We recognize that this software is merely a tool for users to create and maintain their blockchain +of preference. We see that blockchains are naturally community platforms with users being the +ultimate decision makers. We assert that good software will maximize user agency by facilitating +user-expression on the network. As such: + +* This project will strive to give users as much choice as is both reasonable and possible over what + protocol they adhere to; but +* Use of the project's technical forums, commenting systems, pull requests and issue trackers as a + means to express individual protocol preferences is forbidden. + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are +expected to take appropriate and fair corrective action in response to any instances of unacceptable +behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, +code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to +ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is +representing the project or its community. Examples of representing a project or community include +using an official project e-mail address, posting via an official social media account, or acting as +an appointed representative at an online or offline event. Representation of a project may be further +defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting +the project team at . The project team will review and investigate all complaints, +and will respond in a way that it deems appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary +or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at +https://contributor-covenant.org/version/1/4 + +[homepage]: https://contributor-covenant.org diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000000..fa850f6bdc2 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,128 @@ +# Contributing + +The `Polkadot SDK` project is an **OPENISH Open Source Project** + +## What? + +Individuals making significant and valuable contributions are given commit-access to the project. +Contributions are done via pull-requests and need to be approved by the maintainers. + +## Rules + +There are a few basic ground-rules for contributors (including the maintainer(s) of the project): + +1. **No `--force` pushes** or modifying the master branch history in any way. + If you need to rebase, ensure you do it in your own repo. No rewriting of the history + after the code has been shared (e.g. through a Pull-Request). +2. **Non-master branches**, prefixed with a short name moniker (e.g. `gav-my-feature`) must be + used for ongoing work. +3. **All modifications** must be made in a **pull-request** to solicit feedback from other contributors. +4. A pull-request **must not be merged until CI** has finished successfully. +5. Contributors should adhere to the [house coding style](./STYLE_GUIDE.md). +6. Contributors should adhere to the [house documenting style](./DOCUMENTATION_GUIDELINES.md), when applicable. + +## Merge Process + +### In General + +A Pull Request (PR) needs to be reviewed and approved by project maintainers. +If a change does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged +`A1-insubstantial` and merged faster. +If it is an urgent fix with no large change to logic, then it may be merged after a non-author +contributor has reviewed it well and approved the review once CI is complete. +No PR should be merged until all reviews' comments are addressed. + +### Labels: + +The set of labels and their description can be found [here](linktobeinserted) + +### Process: + +1. Please use our [Pull Request Template](./PULL_REQUEST_TEMPLATE.md) and make sure all relevant + information is reflected in your PR. +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 + 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 + `T13-documentation`. The docs team will get in touch. +5. If your PR changes files in these paths: + + `polkadot` : '^runtime/polkadot' + `polkadot` : '^runtime/kusama' + `polkadot` : '^primitives/src/' + `polkadot` : '^runtime/common' + `substrate` : '^frame/' + `substrate` : '^primitives/' + + It should be added to the [security audit board](https://github.com/orgs/paritytech/projects/103) + and will need to undergo an audit before merge. +6. PRs will be able to be merged once all reviewers' comments are addressed and CI is successful. + +**Noting breaking changes:** +When breaking APIs, the PR description should mention what was changed alongside some examples on how +to change the code to make it work/compile. +It should also mention potential storage migrations and if they require some special setup aside adding +it to the list of migrations in the runtime. + +## Reviewing pull requests: + +When reviewing a pull request, the end-goal is to suggest useful changes to the author. +Reviews should finish with approval unless there are issues that would result in: +1. Buggy behavior. +2. Undue maintenance burden. +3. Breaking with house coding style. +4. Pessimization (i.e. reduction of speed as measured in the projects benchmarks). +5. Feature reduction (i.e. it removes some aspect of functionality that a significant minority of users rely on). +6. Uselessness (i.e. it does not strictly add a feature or fix a known issue). + +The reviewers are also responsible to check: + +a) if a changelog is necessary and attached + +b) the quality of information in the changelog file + +c) the PR has an impact on docs + +d) that the docs team was included in the review process of a docs update + +**Reviews may not be used as an effective veto for a PR because**: +1. There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. +2. It does not fit well with some other contributors' longer-term vision for the project. + +## Helping out + +We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate +state of a PR. Please familiarise yourself with them. Best way to get started is to a pick a ticket tagged +`[easy](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD0-easy)` +or `[medium](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD1-medium)` +and get going or `[mentor](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AC1-mentor)` +and get in contact with the mentor offering their support on that larger task. + +**** + +### Issues + +If what you are looking for is an answer rather than proposing a new feature or fix, search +[https://substrate.stackexchange.com](https://substrate.stackexchange.com/) to see if an post already +exists, and ask if not. Please do not file support issues here. +Before opening a new issue search to see if a similar one already exists and leave a comment that you +also experienced this issue or add your specifics that are related to an existing issue. +Please label issues with the following labels: +1. `I*` issue severity and type. EXACTLY ONE REQUIRED. +2. `D*` issue difficulty, suggesting the level of complexity this issue has. AT MOST ONE ALLOWED. +3. `T*` Issue topic. MULTIPLE ALLOWED. + +## Releases + +Declaring formal releases remains the prerogative of the project maintainer(s). + +## UI tests + +UI tests are used for macros to ensure that the output of a macro doesn’t change and is in the expected format. +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 diff --git a/substrate/docs/DOCUMENTATION_GUIDELINES.md b/docs/DOCUMENTATION_GUIDELINE.md similarity index 56% rename from substrate/docs/DOCUMENTATION_GUIDELINES.md rename to docs/DOCUMENTATION_GUIDELINE.md index 0f83f5e6445..82361732959 100644 --- a/substrate/docs/DOCUMENTATION_GUIDELINES.md +++ b/docs/DOCUMENTATION_GUIDELINE.md @@ -1,8 +1,11 @@ # Substrate Documentation Guidelines -This document is only focused on documenting parts of substrate that relates to its external API. The list of such crates can be found in [CODEOWNERS](./CODEOWNERS). Search for the crates that are auto-assigned to a team called `docs-audit`. +This document is focused on documenting parts of substrate that relate to its +external API. The list of such crates can be found in [CODEOWNERS](./CODEOWNERS). +Search for the crates auto-assigned to the `docs-audit` team. -These are crates that are often used by external developers and need more thorough documentation. These are the crates most concerned with FRAME development. +These crates are used by external developers and need thorough documentation. +They are the most concerned with FRAME development. - [Substrate Documentation Guidelines](#substrate-documentation-guidelines) - [General/Non-Pallet Crates](#generalnon-pallet-crates) @@ -21,6 +24,7 @@ These are crates that are often used by external developers and need more thorou - [Storage Items](#storage-items) - [Errors and Events](#errors-and-events) +--- ## General/Non-Pallet Crates @@ -28,18 +32,25 @@ First, consider the case for all such crates, except for those that are pallets. ### What to Document? -The first question is, what should you document? Use the following filter: +The first question is, what should you document? Use this filter: 1. In the crates assigned to `docs-audit` in [CODEOWNERS](./CODEOWNERS), -2. All `pub` item need to be documented. If it is not `pub`, it does not appear in the rust-docs, and is not public facing. - * Within `pub` items, sometimes they are only `pub` in order to be used by another internal crate, and you can foresee that this will not be used by anyone else other than you. These need **not** be documented thoroughly, and are left to your discretion to identify. - * Reminder: `trait` items are public by definition, if the trait is public. -3. All public modules (`mod`) should have reasonable module-level documentation (`//!`). +2. All `pub` items need to be documented. If not `pub`, it doesn't appear in the +rust-docs, and is not public facing. + + * Within `pub` items, sometimes they are only `pub` to be used by another + internal crate, and you can foresee that this won't be used by anyone else. + These need **not** be documented thoroughly. + + * Reminder: `trait` items are public by definition if the trait is public. +3. All public modules (`mod`) should have reasonable module-level documentation (`//!`). #### Rust Docs vs. Code Comments -Note that anything starting with `///` is an external rust-doc, and everything starting with `//` does not appear in the rust-docs. It's important to not confuse the two in your documentation. +Note that anything starting with `///` is an external rust-doc, and everything +starting with `//` does not appear in the rust-docs. +It's important to not confuse the two in your documentation. ```rust /// Computes the square root of the input, returning `Ok(_)` if successful. @@ -55,70 +66,124 @@ pub fn sqrt(x: u32) -> Result { } ``` +--- + ### How to Document? -There are a few very good sources that you can look into: +There are good sources to look into: -- https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html -- https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html -- https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate +- [Rust Documentation Guide](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html) +- [Documentation in Rust Book](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments) +- [Guide on Writing Documentation for a Rust Crate](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate) -As mentioned [here](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#writing-documentation-comments) and [here](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate), always start with a **single sentence** demonstrating what is being documented. All additional documentation should be added *after a newline*. Strive to make the first sentence succinct and short. The reason for this is the first paragraph of docs about an item (everything before the first newline) is used as the excerpt that rust doc displays about this item when it appears in tables, such as the table listing all functions in a module. If this excerpt is too long, the module docs will be very difficult to read. +As mentioned [here](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#writing-documentation-comments) and [here](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate), +always start with a **single sentence** demonstrating what is documented. All additional +documentation should be added *after a newline*. Strive to make the first sentence succinct +and short.The reason for this is the first paragraph of docs about an item (everything +before the first newline) is used as the excerpt that rust doc displays about +this item when it appears in tables, such as the table listing all functions in +a module. If this excerpt is too long, the module docs will be very difficult +to read. About [special sections](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#special-sections), we will most likely not need to think about panic and safety in any runtime related code. Our code is never `unsafe`, and will (almost) never panic. -Use `# Examples as much as possible. These are great ways to further demonstrate what your APIs are doing, and add free test coverage. As an additional benefit, any code in rust-docs is treated as an "integration tests", not unit tests, which tests your crate in a different way than unit tests. So, it is both a win for "more documentation" and a win for "more test coverage". - -You can also consider having an `# Error` section optionally. Of course, this only applies if there is a `Result` being returned, and if the `Error` variants are overly complicated. - -Strive to include correct links to other items in your written docs as much as possible. In other words, avoid `` `some_func` `` and instead use ``[`some_func`]``. -Read more about how to correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). - - -> While you are linking, you might become conscious of the fact that you are in need of linking to (too many) foreign items in order to explain your API. This is leaning more towards API-Design rather than documentation, but it is a warning that the subject API might be slightly wrong. For example, most "glue" traits[^1] in `frame/support` should be designed and documented without making hard assumptions about particular pallets that implement them. +Use `# Examples as much as possible. These are great ways to further +demonstrate what your APIs are doing, and add free test coverage. As an +additional benefit, any code in rust-docs is treated as an "integration tests", +not unit tests, which tests your crate in a different way than unit tests. So, +it is both a win for "more documentation" and a win for "more test coverage". + +You can also consider having an `# Error` section optionally. Of course, this +only applies if there is a `Result` being returned, and if the `Error` variants +are overly complicated. + +Strive to include correct links to other items in your written docs as much as +possible. In other words, avoid \`some_func\` and instead use \[\`some_fund\`\]. +Read more about how to correctly use links in your rust-docs +[here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) +and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). +Strive to include correct links to other items in your written docs as much as +possible. In other words, avoid `` `some_func` `` and instead use +``[`some_func`]``. + +> While you are linking, you might become conscious of the fact that you are +in need of linking to (too many) foreign items in order to explain your API. +This is leaning more towards API-Design rather than documentation, but it is a +warning that the subject API might be slightly wrong. For example, most "glue" +traits[^1] in `frame/support` should be designed and documented without making +hard assumptions about particular pallets that implement them. + +--- #### TLDR -0. Have the goal of enforcing `#![deny(missing_docs)]` mentally, even if it is not enforced by the compiler 🙈. -1. Start with a single, clear and concise sentence. Follow up with more context, after a newline, if needed. +0. Have the goal of enforcing `#![deny(missing_docs)]` mentally, even if it is +not enforced by the compiler 🙈. +1. Start with a single, clear and concise sentence. Follow up with more context, +after a newline, if needed. 2. Use examples as much as reasonably possible. 3. Use links as much as possible. -4. Think about context. If you are explaining a lot of foreign topics while documenting a trait that should not explicitly depend on them, you have likely not designed it properly. +4. Think about context. If you are explaining a lot of foreign topics while +documenting a trait that should not explicitly depend on them, you have likely +not designed it properly. + +--- #### Proc-Macros -Note that there are special considerations when documenting proc macros. Doc links will appear to function _within_ your proc macro crate, but often will no longer function when these proc macros are re-exported elsewhere in your project. The exception is doc links to _other proc macros_ which will function just fine if they are also being re-exported. It is also often necessary to disambiguate between a proc macro and a function of the same name, which can be done using the `macro@my_macro_name` syntax in your link. Read more about how to correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). +Note that there are special considerations when documenting proc macros. Doc +links will appear to function _within_ your proc macro crate, but often will no +longer function when these proc macros are re-exported elsewhere in your +project. The exception is doc links to _other proc macros_ which will function +just fine if they are also being re-exported. It is also often necessary to +disambiguate between a proc macro and a function of the same name, which can be +done using the `macro@my_macro_name` syntax in your link. Read more about how to +correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) +and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). +--- ### Other Guidelines -The above five guidelines must always be reasonably respected in the documentation. +The above five guidelines must always be reasonably respected in the +documentation. -The following are a set of notes that may not necessarily hold in all circumstances: +The following are a set of notes that may not necessarily hold in all +circumstances: +--- #### Document Through Code -You should make sure that your code is properly-named and well-organized so that your code functions as a form of documentation. However, within the complexity of our projects in Polkadot/Substrate that is not enough. Particularly, things like examples, errors and panics cannot be documented only through properly-named and well-organized code. - -> Our north star is self-documenting code that also happens to be well-documented and littered with examples. +You should make sure that your code is properly-named and well-organized so that +your code functions as a form of documentation. However, within the complexity +of our projects in Polkadot/Substrate that is not enough. Particularly, things +like examples, errors and panics cannot be documented only through properly- +named and well-organized code. +> Our north star is self-documenting code that also happens to be well-documented +and littered with examples. -* Your written documents should *complement* the code, not *repeat* it. As an example, a documentation on top of a code example should never look like the following: +* Your written documents should *complement* the code, not *repeat* it. As an +example, a documentation on top of a code example should never look like the +following: - ```rust +```rust /// Sends request and handles the response. trait SendRequestAndHandleResponse { } ``` -In the above example, the documentation has added no useful information not already contained within the properly-named trait and is redundant. +In the above example, the documentation has added no useful information not +already contained within the properly-named trait and is redundant. +--- #### Formatting Matters -The way you format your documents (newlines, heading and so on) makes a difference. Consider the below examples: +The way you format your documents (newlines, heading and so on) makes a +difference. Consider the below examples: ```rust /// This function works with input u32 x and multiplies it by two. If @@ -141,18 +206,32 @@ fn multiply_by_2(x: u32) -> u32 { .. } // More efficiency can be achieved if we improve this via such and such. fn multiply_by_2(x: u32) -> u32 { .. } ``` +They are both roughly conveying the same set of facts, but one is easier to +follow because it was formatted cleanly. Especially for traits and types that +you can foresee will be seen and used a lot, try and write a well formatted +version. -They are both roughly conveying the same set of facts, but one is easier to follow because it was formatted cleanly. Especially for traits and types that you can foresee will be seen and used a lot, try and write a well formatted version. - -Similarly, make sure your comments are wrapped at 100 characters line-width (as defined by our [`rustfmt.toml`](../rustfmt.toml)), no **more and no less**! The more is fixed by `rustfmt` and our CI, but if you (for some unknown reason) wrap your lines at 59 characters, it will pass the CI, and it will not look good 🫣. Consider using a plugin like [rewrap](https://marketplace.visualstudio.com/items?itemName=stkb.rewrap) (for Visual Studio Code) to properly do this. +Similarly, make sure your comments are wrapped at 100 characters line-width (as +defined by our [`rustfmt.toml`](../rustfmt.toml)), no **more and no less**! The +more is fixed by `rustfmt` and our CI, but if you (for some unknown reason) +wrap your lines at 59 characters, it will pass the CI, and it will not look good +🫣. Consider using a plugin like [rewrap](https://marketplace.visualstudio.com/items?itemName=stkb.rewrap) (for Visual Studio Code) to properly do this. [^1]: Those that help two pallets talk to each other. +--- + + ## Pallet Crates -The guidelines so far have been general in nature, and are applicable to crates that are pallets and crates that're not pallets. +The guidelines so far have been general in nature, and are applicable to crates +that are pallets and crates that're not 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 examples of adhering these guidelines. +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. + +--- ### Top Level Pallet Docs (`lib.rs`) @@ -204,15 +283,24 @@ For the top-level pallet docs, consider the following template: //! ``` -This template's details (heading 3s and beyond) are left flexible, and at the discretion of the developer to make the best final choice about. For example, you might want to include `### Terminology` or not. Moreover, you might find it more useful to include it in `## Overview`. -Nonetheless, the high level flow of going from the most high level explanation to the most low level explanation is important to follow. +This template's details (heading 3s and beyond) are left flexible, and at the +discretion of the developer to make the best final choice about. For example, +you might want to include `### Terminology` or not. Moreover, you might find it +more useful to include it in `## Overview`. + +Nonetheless, the high level flow of going from the most high level explanation +to the most low level explanation is important to follow. + +As a rule of thumb, the Heading 2s (`##`) in this template can be considered a +strict rule, while the Heading 3s (`###`) and beyond are flexible. -As a rule of thumb, the Heading 2s (`##`) in this template can be considered a strict rule, while the Heading 3s (`###`) and beyond are flexible. +--- #### Polkadot and Substrate -Optionally, in order to demonstrate the relation between the two, you can start the pallet documentation with: +Optionally, in order to demonstrate the relation between the two, you can start +the pallet documentation with: ``` //! > Made with *Substrate*, for *Polkadot*. @@ -224,6 +312,8 @@ Optionally, in order to demonstrate the relation between the two, you can start //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github ``` +--- + ### Dispatchables For each dispatchable (`fn` item inside `#[pallet::call]`), consider the following template: @@ -251,14 +341,27 @@ pub fn name_of_dispatchable(origin: OriginFor, ...) -> DispatchResult {} Consider the fact that these docs will be part of the metadata of the associated dispatchable, and might be used by wallets and explorers. +--- + ### Storage Items -1. If a map-like type is being used, always note the choice of your hashers as private code docs (`// Hasher X chosen because ...`). Recall that this is not relevant information to external people, so it must be documented as `//`. -2. Consider explaining the crypto-economics of how a deposit is being taken in return of the storage being used. -3. Consider explaining why it is safe for the storage item to be unbounded, if `#[pallet::unbounded]` or `#[pallet::without_storage_info]` is being used. +1. If a map-like type is being used, always note the choice of your hashers as +private code docs (`// Hasher X chosen because ...`). Recall that this is not +relevant information to external people, so it must be documented as `//`. + +2. Consider explaining the crypto-economics of how a deposit is being taken in +return of the storage being used. + +3. Consider explaining why it is safe for the storage item to be unbounded, if +`#[pallet::unbounded]` or `#[pallet::without_storage_info]` is being used. + +--- ### Errors and Events -Consider the fact that, similar to dispatchables, these docs will be part of the metadata of the associated event/error, and might be used by wallets and explorers. +Consider the fact that, similar to dispatchables, these docs will be part of +the metadata of the associated event/error, and might be used by wallets and +explorers. -Specifically for `error`, explain why the error has happened, and what can be done in order to avoid it. +Specifically for `error`, explain why the error has happened, and what can be +done in order to avoid it. diff --git a/substrate/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md similarity index 73% rename from substrate/docs/PULL_REQUEST_TEMPLATE.md rename to docs/PULL_REQUEST_TEMPLATE.md index d2bb22f6e24..15482d9e85a 100644 --- a/substrate/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -2,7 +2,11 @@ ✄ ----------------------------------------------------------------------------- -Thank you for your Pull Request! 🙏 Please make sure it follows the contribution guidelines outlined in [this document](https://github.com/paritytech/substrate/blob/master/docs/CONTRIBUTING.md) and fill out the sections below. Once you're ready to submit your PR for review, please delete this section and leave only the text under the "Description" heading. +Thank you for your Pull Request! 🙏 Please make sure it follows the contribution +guidelines outlined in [this document](CONTRIBUTING.md) and fill out the +sections below. Once you're ready to submit your PR for review, please delete +this section and leave only the text under the "Description" heading. + # Description @@ -25,7 +29,7 @@ Cumulus companion: (*if applicable*) # Checklist - [ ] My PR includes a detailed description as outlined in the "Description" section above -- [ ] My PR follows the [labeling requirements](https://github.com/paritytech/substrate/blob/master/docs/CONTRIBUTING.md#merge-process) of this project (at minimum one label for each `A`, `B`, `C` and `D` required) +- [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` 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) diff --git a/polkadot/SECURITY.md b/docs/SECURITY.md similarity index 69% rename from polkadot/SECURITY.md rename to docs/SECURITY.md index db81bcaab4d..b6559efdf97 100644 --- a/polkadot/SECURITY.md +++ b/docs/SECURITY.md @@ -1,10 +1,17 @@ + + # Security Policy -Parity Technologies is committed to resolving security vulnerabilities in our software quickly and carefully. We take the necessary steps to minimize risk, provide timely information, and deliver vulnerability fixes and mitigations required to address security issues. +Parity Technologies is committed to resolving security vulnerabilities in our +software quickly and carefully. We take the necessary steps to minimize risk, +provide timely information, and deliver vulnerability fixes and mitigations +required to address security issues. ## Reporting a Vulnerability -Security vulnerabilities in Parity software should be reported by email to security@parity.io. If you think your report might be eligible for the Parity Bug Bounty Program, your email should be sent to bugbounty@parity.io. +Security vulnerabilities in Parity software should be reported by email to +security@parity.io. If you think your report might be eligible for the Parity +Bug Bounty Program, your email should be sent to bugbounty@parity.io. Your report should include the following: @@ -15,33 +22,49 @@ Your report should include the following: - reproduction - other details -Try to include as much information in your report as you can, including a description of the vulnerability, its potential impact, and steps for reproducing it. Be sure to use a descriptive subject line. +Try to include as much information in your report as you can, including a +description of the vulnerability, its potential impact, and steps for +reproducing it. Be sure to use a descriptive subject line. -You'll receive a response to your email within two business days indicating the next steps in handling your report. We encourage finders to use encrypted communication channels to protect the confidentiality of vulnerability reports. You can encrypt your report using our public key. This key is [on MIT's key server](https://pgp.mit.edu/pks/lookup?op=get&search=0x5D0F03018D07DE73) server and reproduced below. +You'll receive a response to your email within two business days indicating +the next steps in handling your report. We encourage finders to use encrypted +communication channels to protect the confidentiality of vulnerability reports. +You can encrypt your report using our public key. This key is [on MIT's key server](https://pgp.mit.edu/pks/lookup?op=get&search=0x5D0F03018D07DE73) +server and reproduced below. -After the initial reply to your report, our team will endeavor to keep you informed of the progress being made towards a fix. These updates will be sent at least every five business days. +After the initial reply to your report, our team will endeavor to keep you +informed of the progress being made towards a fix. These updates will be sent +at least every five business days. Thank you for taking the time to responsibly disclose any vulnerabilities you find. ## Responsible Investigation and Reporting -Responsible investigation and reporting includes, but isn't limited to, the following: +Responsible investigation and reporting includes, but isn't limited to, the +following: - Don't violate the privacy of other users, destroy data, etc. -- Don’t defraud or harm Parity Technologies Ltd or its users during your research; you should make a good faith effort to not interrupt or degrade our services. -- Don't target our physical security measures, or attempt to use social engineering, spam, distributed denial of service (DDOS) attacks, etc. +- Don’t defraud or harm Parity Technologies Ltd or its users during your + research; you should make a good faith effort to not interrupt or degrade our + services. +- Don't target our physical security measures, or attempt to use social + engineering, spam, distributed denial of service (DDOS) attacks, etc. - Initially report the bug only to us and not to anyone else. -- Give us a reasonable amount of time to fix the bug before disclosing it to anyone else, and give us adequate written warning before disclosing it to anyone else. -- In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to us or our users. Otherwise your actions might be interpreted as an attack rather than an effort to be helpful. +- Give us a reasonable amount of time to fix the bug before disclosing it to + anyone else, and give us adequate written warning before disclosing it to + anyone else. +- In general, please investigate and report bugs in a way that makes a + reasonable, good faith effort not to be disruptive or harmful to us or our + users. Otherwise your actions might be interpreted as an attack rather than + an effort to be helpful. ## Bug Bounty Program -Our Bug Bounty Program allows us to recognise and reward members of the Parity community for helping us find and address significant bugs, in accordance with the terms of the Parity Bug Bounty Program. A detailed description on eligibility, rewards, legal information and terms & conditions for contributors can be found on [our website](https://paritytech.io/bug-bounty.html). - - - - - +Our Bug Bounty Program allows us to recognize and reward members of the Parity +community for helping us find and address significant bugs, in accordance with +the terms of the Parity Bug Bounty Program. A detailed description on +eligibility, rewards, legal information and terms & conditions for contributors +can be found on [our website](https://paritytech.io/bug-bounty.html). ## Plaintext PGP Key diff --git a/docs/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md new file mode 100644 index 00000000000..eb3399880f5 --- /dev/null +++ b/docs/STYLE_GUIDE.md @@ -0,0 +1,180 @@ +--- +title: Style Guide for Rust in the Polkadot-SDK +--- + +Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` +then you will adhere to most of these style guidelines automatically. + +# Formatting + +- Indent using tabs. +- Lines should be longer than 100 characters long only in exceptional circumstances and certainly + no longer than 120. For this purpose, tabs are considered 4 characters wide. +- Indent levels should be greater than 5 only in exceptional circumstances and certainly no + greater than 8. If they are greater than 5, then consider using `let` or auxiliary functions in + order to strip out complex inline expressions. +- Never have spaces on a line prior to a non-whitespace character +- Follow-on lines are only ever a single indent from the original line. + +```rust +fn calculation(some_long_variable_a: i8, some_long_variable_b: i8) -> bool { + let x = some_long_variable_a * some_long_variable_b + - some_long_variable_b / some_long_variable_a + + sqrt(some_long_variable_a) - sqrt(some_long_variable_b); + x > 10 +} +``` + +- Indent level should follow open parens/brackets, but should be collapsed to the smallest number + of levels actually used: + +```rust +fn calculate( + some_long_variable_a: f32, + some_long_variable_b: f32, + some_long_variable_c: f32, +) -> f32 { + (-some_long_variable_b + sqrt( + // two parens open, but since we open & close them both on the + // same line, only one indent level is used + some_long_variable_b * some_long_variable_b + - 4 * some_long_variable_a * some_long_variable_c + // both closed here at beginning of line, so back to the original indent + // level + )) / (2 * some_long_variable_a) +} +``` + +- `where` is indented, and its items are indented one further. +- Argument lists or function invocations that are too long to fit on one line are indented + similarly to code blocks, and once one param is indented in such a way, all others should be, + too. Run-on parameter lists are also acceptable for single-line run-ons of basic function calls. + +```rust +// OK +fn foo( + really_long_parameter_name_1: SomeLongTypeName, + really_long_parameter_name_2: SomeLongTypeName, + shrt_nm_1: u8, + shrt_nm_2: u8, +) { + ... +} + +// NOT OK +fn foo(really_long_parameter_name_1: SomeLongTypeName, really_long_parameter_name_2: SomeLongTypeName, + shrt_nm_1: u8, shrt_nm_2: u8) { + ... +} +``` + +```rust +{ + // Complex line (not just a function call, also a let statement). Full + // structure. + let (a, b) = bar( + really_long_parameter_name_1, + really_long_parameter_name_2, + shrt_nm_1, + shrt_nm_2, + ); + + // Long, simple function call. + waz( + really_long_parameter_name_1, + really_long_parameter_name_2, + shrt_nm_1, + shrt_nm_2, + ); + + // Short function call. Inline. + baz(a, b); +} +``` + +- Always end last item of a multi-line comma-delimited set with `,` when legal: + +```rust +struct Point { + x: T, + y: T, // <-- Multiline comma-delimited lists end with a trailing , +} + +// Single line comma-delimited items do not have a trailing `,` +enum Meal { Breakfast, Lunch, Dinner }; +``` + +- Avoid trailing `;`s where unneeded. + +```rust +if condition { + return 1 // <-- no ; here +} +``` + +- `match` arms may be either blocks or have a trailing `,` but not both. +- Blocks should not be used unnecessarily. + +```rust +match meal { + Meal::Breakfast => "eggs", + Meal::Lunch => { check_diet(); recipe() }, +// Meal::Dinner => { return Err("Fasting") } // WRONG + Meal::Dinner => return Err("Fasting"), +} +``` + +# Style + +- Panickers require explicit proofs they don't trigger. Calling `unwrap` is discouraged. The + exception to this rule is test code. Avoiding panickers by restructuring code is preferred if + feasible. + +```rust +let mut target_path = + self.path().expect( + "self is instance of DiskDirectory;\ + DiskDirectory always returns path;\ + qed" + ); +``` + +- Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, + consider trade-offs between efficiency on one hand and reliability, maintenance costs, and + security on the other. Here is a list of questions that may help evaluating the trade-off while + preparing or reviewing a PR: + - how much more performant or compact the resulting code will be using unsafe code, + - how likely is it that invariants could be violated, + - are issues stemming from the use of unsafe code caught by existing tests/tooling, + - what are the consequences if the problems slip into production. + +# Manifest Formatting + +> **TLDR** +> You can use the CLI tool [Zepter](https://crates.io/crates/zepter) to +> format the files: `zepter format features` + +Rust `Cargo.toml` files need to respect certain formatting rules. All entries +need to be alphabetically sorted. This makes it easier to read them and insert +new entries. The exhaustive list of rules is enforced by the CI. The general +format looks like this: + +- The feature is written as a single line if it fits within 80 chars: + +```toml +[features] +default = [ "std" ] +``` + +- Otherwise the feature is broken down into multiple lines with one entry per + line. Each line is padded with one tab and no trailing spaces but a trailing + comma. + +```toml +[features] +default = [ + "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong", + # Comments go here as well ;) + "std", +] +``` \ No newline at end of file diff --git a/polkadot/CODE_OF_CONDUCT.md b/polkadot/CODE_OF_CONDUCT.md deleted file mode 100644 index 400c9b3901e..00000000000 --- a/polkadot/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,52 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -### Facilitation, Not Strongarming - -We recognise that this software is merely a tool for users to create and maintain their blockchain of preference. We see that blockchains are naturally community platforms with users being the ultimate decision makers. We assert that good software will maximise user agency by facilitate user-expression on the network. As such: - -* This project will strive to give users as much choice as is both reasonable and possible over what protocol they adhere to; but -* use of the project's technical forums, commenting systems, pull requests and issue trackers as a means to express individual protocol preferences is forbidden. - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://contributor-covenant.org/version/1/4 - -[homepage]: https://contributor-covenant.org diff --git a/polkadot/CONTRIBUTING.md b/polkadot/CONTRIBUTING.md deleted file mode 100644 index d82b80bd8d2..00000000000 --- a/polkadot/CONTRIBUTING.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributing - -## Rules - -There are a few basic ground-rules for contributors (including the maintainer(s) of the project): - -- **No `--force` pushes** or modifying the Git history in any way. If you need to rebase, ensure you do it in your own repo. -- **Non-master branches**, prefixed with a short name moniker (e.g. `gav-my-feature`) must be used for ongoing work. -- **All modifications** must be made in a **pull-request** to solicit feedback from other contributors. -- A pull-request _must not be merged until CI_ has finished successfully. -- Contributors should adhere to the [house coding style](https://github.com/paritytech/substrate/blob/master/docs/STYLE_GUIDE.md). - -### Merging pull requests once CI is successful - -- A pull request that does not alter any logic (e.g. comments, dependencies, docs) may be tagged [`insubstantial`](https://github.com/paritytech/polkadot/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3AA2-insubstantial) and merged by its author. -- A pull request with no large change to logic that is an urgent fix may be merged after a non-author contributor has reviewed it well. -- All other PRs should sit for 48 hours with the [`pleasereview`](https://github.com/paritytech/polkadot/pulls?q=is:pr+is:open+label:A0-pleasereview) tag in order to garner feedback. -- No PR should be merged until all reviews' comments are addressed. - -### Reviewing pull requests - -When reviewing a pull request, the end-goal is to suggest useful changes to the author. Reviews should finish with approval unless there are issues that would result in: - -- Buggy behavior. -- Undue maintenance burden. -- Breaking with house coding style. -- Pessimization (i.e. reduction of speed as measured in the projects benchmarks). -- Feature reduction (i.e. it removes some aspect of functionality that a significant minority of users rely on). -- Uselessness (i.e. it does not strictly add a feature or fix a known issue). - -### Reviews may not be used as an effective veto for a PR because - -- There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. -- It does not fit well with some other contributors' longer-term vision for the project. - -## Releases - -Declaring formal releases remains the prerogative of the project maintainer(s). - -## Changes to this arrangement - -This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. - -## Heritage - -These contributing guidelines are modified from the "OPEN Open Source Project" guidelines for the Level project: diff --git a/substrate/docs/CODE_OF_CONDUCT.md b/substrate/docs/CODE_OF_CONDUCT.md deleted file mode 100644 index 400c9b3901e..00000000000 --- a/substrate/docs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,52 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -### Facilitation, Not Strongarming - -We recognise that this software is merely a tool for users to create and maintain their blockchain of preference. We see that blockchains are naturally community platforms with users being the ultimate decision makers. We assert that good software will maximise user agency by facilitate user-expression on the network. As such: - -* This project will strive to give users as much choice as is both reasonable and possible over what protocol they adhere to; but -* use of the project's technical forums, commenting systems, pull requests and issue trackers as a means to express individual protocol preferences is forbidden. - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://contributor-covenant.org/version/1/4 - -[homepage]: https://contributor-covenant.org diff --git a/substrate/docs/CONTRIBUTING.md b/substrate/docs/CONTRIBUTING.md deleted file mode 100644 index cbaf6206e78..00000000000 --- a/substrate/docs/CONTRIBUTING.md +++ /dev/null @@ -1,134 +0,0 @@ -# Contributing - -The `Substrate` project is an ***OPENISH Open Source Project*** - -Contributors are invited to our `#frame-contributors` channel on the Polkadot Discord for support and coordination: -[![Discord](https://img.shields.io/discord/722223075629727774?style=for-the-badge&logo=discord&label=Discord)](https://dot.li/discord) - -## What? - -Individuals making significant and valuable contributions are given commit-access to a project to contribute as they see fit. A project is more like an open wiki than a standard guarded open source project. - -## Rules - -There are a few basic ground-rules for contributors (including the maintainer(s) of the project): - -1. ***No `--force` pushes*** or modifying the master branch history in any way. If you need to rebase, ensure you do it in your own repo. No rewriting of the history after the code has been shared (e.g. through a Pull-Request). -2. ***Non-master branches***, prefixed with a short name moniker (e.g. `gav-my-feature`) must be used for ongoing work. -3. ***All modifications*** must be made in a ***pull-request*** to solicit feedback from other contributors. -4. A pull-request **must not be merged until CI** has finished successfully. -5. Contributors should adhere to the [house coding style](STYLE_GUIDE.md). -6. Contributors should adhere to the [house documenting style](DOCUMENTATION_GUIDELINES.md), when applicable. - -## Merge Process - -**In General** - -A Pull Request (PR) needs to be reviewed and approved by project maintainers unless: - -* it does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged [`insubstantial`](https://github.com/paritytech/substrate/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3AA2-insubstantial) and merged by its author once CI is complete. -* it is an urgent fix with no large change to logic, then it may be merged after a non-author contributor has approved the review once CI is complete. - -**Labels TLDR:** - -* `A-*` Pull request status. ONE REQUIRED. -* `B-*` Changelog and/or Runtime-upgrade post composition markers. ONE REQUIRED. (used by automation) -* `C-*` Release notes release-criticality markers. EXACTLY ONE REQUIRED. (used by automation) -* `D-*` Audit tags denoting auditing requirements on the PR. - -**Process:** - -1. Please tag each PR with exactly one `A`, `B`, `C` and `D` label at the minimum. -2. When tagging a PR, it should be done while keeping all downstream users in mind. Downstream users are not just Polkadot or system parachains, but also all the other parachains and solo chains that are using Substrate. The labels are used by downstream users to track changes and to include these changes properly into their own releases. -3. Once a PR is ready for review please add the [`A0-please_review`](https://github.com/paritytech/substrate/pulls?q=is%3Apr+is%3Aopen+label%3AA0-please_review+) label. Generally PRs should sit with this label for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. -4. If the first review is not an approval, swap `A0-please_review` to any label `[A3, A5]` to indicate that the PR has received some feedback, but needs further work. For example. [`A3-in_progress`](https://github.com/paritytech/substrate/labels/A3-in_progress) is a general indicator that the PR is work in progress. -5. PRs must be tagged with `B*` labels to signal if a change is note worthy for downstream users. The respective `T*` labels should be added to signal the component that was changed. `B0-silent` must only be used for changes that don’t require any attention by downstream users. -6. PRs must be tagged with their release importance via the `C1-C7` labels. The release importance is only informing about how important it is to apply a release that contains the change. -7. PRs must be tagged with their audit requirements via the `D1-D9` labels. -8. PRs that introduce runtime migrations must be tagged with [`E0-runtime_migration`](https://github.com/paritytech/substrate/labels/E0-runtime_migration). See the [Migration Best Practices here](https://github.com/paritytech/substrate/blob/master/utils/frame/try-runtime/cli/src/lib.rs#L18) for more info about how to test runtime migrations. -9. PRs that introduce irreversible database migrations must be tagged with [`E1-database_migration`](https://github.com/paritytech/substrate/labels/E1-database_migration). -10. PRs that add host functions must be tagged with with [`E3-host_functions`](https://github.com/paritytech/substrate/labels/E3-host_functions). -11. PRs that break the external API must be tagged with [`F3-breaks_API`](https://github.com/paritytech/substrate/labels/F3-breaks_API). -12. PRs that change the mechanism for block authoring in a backwards-incompatible way must be tagged with [`F1-breaks_authoring`](https://github.com/paritytech/substrate/labels/F1-breaks_authoring). -13. PRs that "break everything" must be tagged with [`F0-breaks_everything`](https://github.com/paritytech/substrate/labels/F0-breaks_everything). -14. PRs should be categorized into projects. -15. No PR should be merged until all reviews' comments are addressed and CI is successful. - -**Noting relevant changes:** - -When breaking APIs, it should be mentioned on what was changed in the PR description alongside some examples on how to change the code to make it work/compile. - -The PR description should also mention potential storage migrations and if they require some special setup aside adding it to the list of migrations in the runtime. - -**Reviewing pull requests:** - -When reviewing a pull request, the end-goal is to suggest useful changes to the author. Reviews should finish with approval unless there are issues that would result in: - -1. Buggy behavior. -2. Undue maintenance burden. -3. Breaking with house coding style. -4. Pessimization (i.e. reduction of speed as measured in the projects benchmarks). -5. Feature reduction (i.e. it removes some aspect of functionality that a significant minority of users rely on). -6. Uselessness (i.e. it does not strictly add a feature or fix a known issue). - -**Reviews may not be used as an effective veto for a PR because**: - -1. There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. -2. It does not fit well with some other contributors' longer-term vision for the project. - -### Updating Polkadot as well - -***All pull requests will be checked against either Polkadot master, or your provided Polkadot companion PR***. That is, If your PR changes the external APIs or interfaces used by Polkadot. If you tagged the PR with `breaksapi` or `breaksconsensus` this is most certainly the case, in all other cases check for it by running step 1 below. - -To create a Polkadot companion PR: - -1. Pull latest Polkadot master (or clone it, if you haven’t yet). -2. Override substrate deps to point to your local path or branch using https://github.com/bkchr/diener. (E.g. from the Polkadot clone dir run `diener patch --crates-to-patch ../substrate --substrate` assuming substrate clone is in a sibling dir. If you do use diener, ensure that you _do not_ commit the changes diener makes to the Cargo.tomls.) -3. Make the changes required and build Polkadot locally. -4. Submit all this as a PR against the Polkadot Repo. -5. In the _description_ of your _Substrate_ PR add "Polkadot companion: [Polkadot_PR_URL]" -6. Now you should see that the `check_polkadot` CI job will build your Substrate PR against the mentioned Polkadot branch in your PR description. -7. Someone will need to approve the Polkadot PR before the Substrate CI will go green. (The Polkadot CI failing can be ignored as long as the Polkadot job in the _substrate_ PR is green). -8. Wait for reviews on both the Substrate and the Polkadot PRs. -9. Once the Substrate PR runs green, a member of the `parity` Github group can comment on the Substrate PR with `bot merge` which will: - * Merge the Substrate PR. - * The bot will push a commit to the Polkadot PR updating its Substrate reference. (effectively doing `cargo update -p sp-io`) - * If the Polkadot PR origins from a fork then a project member may need to press `approve run` on the Polkadot PR. - * The bot will merge the Polkadot PR once all its CI `{"build_allow_failure":false}` checks are green. - Note: The merge-bot currently doesn’t work with forks on org accounts, only individual accounts. - (Hint: it’s recommended to use `bot merge` to merge all substrate PRs, not just ones with a Polkadot companion.) - -If your PR is reviewed well, but a Polkadot PR is missing, signal it with [`E6-needs_polkadot_pr`](https://github.com/paritytech/substrate/labels/E6-needs_polkadot_pr) to prevent it from getting automatically merged. In most cases the CI will add this label automatically. - -As there might be multiple pending PRs that might conflict with one another, a) you should not merge the substrate PR until the Polkadot PR has also been reviewed and b) both should be merged pretty quickly after another to not block others. - -## Helping out - -We use [labels](https://paritytech.github.io/labels/doc_substrate.html) to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. The best way to get started is to a pick a ticket tagged [`easy`](https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ1-easy) or [`medium`](https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ2-medium) and get going or [`mentor`](https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ6-mentor) and get in contact with the mentor offering their support on that larger task. - -## Issues -Please label issues with the following labels: - -1. `I-**` or `J-**` Issue severity and type. EXACTLY ONE REQUIRED. -2. `U-*` Issue urgency, suggesting in what time manner does this issue need to be resolved. AT MOST ONE ALLOWED. -3. `Z-*` Issue difficulty. AT MOST ONE ALLOWED. - -## Releases - -Declaring formal releases remains the prerogative of the project maintainer(s). - -## UI tests - -UI tests are used for macros to ensure that the output of a macro doesn’t change and is in the expected format. 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 output there is the `.maintain/update-rust-stable.sh` script. This can be run with `.maintain/update-rust-stable.sh CURRENT_STABLE_VERSION` -and then it will run all UI tests to update the expected output. - -## Changes to this arrangement - -This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. - -## Heritage - -These contributing guidelines are modified from the "OPEN Open Source Project" guidelines for the Level project: https://github.com/Level/community/blob/master/CONTRIBUTING.md -- GitLab From b13a3187f2b18d1ed1821670f11dc0c70399bb50 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:00:17 +0200 Subject: [PATCH 005/633] [ci] Add DAG (#1244) * [ci] Add DAG * add dag * add more dag and disable deny * test cancel pipeline * fix clippy --- .gitlab-ci.yml | 1 - .gitlab/pipeline/build.yml | 16 +++++++++++++--- .gitlab/pipeline/check.yml | 11 ++++++++++- .gitlab/pipeline/test.yml | 30 ++++++++++++++++++++++++------ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b9b3cd2d63f..0e3050d129b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -233,7 +233,6 @@ include: PR_NUM: "${PR_NUM}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" - branch: "as-improve" remove-cancel-pipeline-message: stage: .post diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 684f6dd5c25..0364c360760 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -82,8 +82,11 @@ build-staking-miner: extends: - .docker-env - .common-refs - - .run-immediately - - .collect-artifacts + # - .collect-artifacts + # DAG + needs: + - job: build-malus + artifacts: false script: - time cargo build --locked --release --package staking-miner # # pack artifacts @@ -269,8 +272,11 @@ build-linux-substrate: extends: - .docker-env - .common-refs - - .run-immediately - .collect-artifacts + # DAG + needs: + - job: build-linux-stable + artifacts: false variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" @@ -320,6 +326,10 @@ build-linux-substrate: build-subkey-linux: extends: .build-subkey + # DAG + needs: + - job: build-staking-miner + artifacts: false # tbd # build-subkey-macos: # extends: .build-subkey diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 4e1cd833040..efd57ba1d86 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -32,7 +32,8 @@ cargo-fmt-manifest: - zepter format features --check allow_failure: true # Experimental -cargo-deny-licenses: +# FIXME +.cargo-deny-licenses: stage: check extends: - .docker-env @@ -132,6 +133,10 @@ check-runtime-migration-polkadot: check-runtime-migration-kusama: stage: check + # DAG + needs: + - job: check-runtime-migration-polkadot + artifacts: false extends: - .docker-env - .test-pr-refs @@ -152,6 +157,10 @@ check-runtime-migration-westend: check-runtime-migration-rococo: stage: check + # DAG + needs: + - job: check-runtime-migration-westend + artifacts: false extends: - .docker-env - .test-pr-refs diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index cbba5dfe422..a83ab8c2bfa 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -160,7 +160,10 @@ test-rustdoc: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: test-doc + artifacts: false variables: SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings" @@ -173,7 +176,10 @@ cargo-check-all-benches: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: cargo-hfuzz + artifacts: false script: - time cargo check --all --benches @@ -202,7 +208,10 @@ test-deterministic-wasm: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: test-frame-support + artifacts: false script: - .gitlab/test_deterministic_wasm.sh @@ -289,7 +298,10 @@ test-frame-support: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: test-frame-examples-compile-to-wasm + artifacts: false variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. @@ -328,7 +340,10 @@ test-frame-examples-compile-to-wasm: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: test-full-crypto-feature + artifacts: false variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. @@ -439,7 +454,10 @@ cargo-hfuzz: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: check-tracing + artifacts: false variables: # max 10s per iteration, 60s per file HFUZZ_RUN_ARGS: > -- GitLab From 3f0d28c8367a070a2ae624f5ca8e8c15e219a66b Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 29 Aug 2023 11:25:04 -0300 Subject: [PATCH 006/633] bump `zombienet` to latest version (#1231) * bump zombienet to latest version * add env var * fix upgrade node text, env var for downloading artifacts --- .gitlab-ci.yml | 2 +- .gitlab/pipeline/zombienet/cumulus.yml | 1 + .gitlab/pipeline/zombienet/polkadot.yml | 3 ++- .gitlab/pipeline/zombienet/substrate.yml | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e3050d129b..c6fbc17a182 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.59" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.65" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index ca96828a1a5..3347eda1baa 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -31,6 +31,7 @@ LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/cumulus/zombienet/tests" COL_IMAGE: "docker.io/paritypr/test-parachain:${DOCKER_IMAGES_VERSION}" FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + RUN_IN_CONTAINER: "1" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: always diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 82dd13cd290..e4c56a7d620 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -34,6 +34,7 @@ GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/polkadot/zombienet_tests" FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + RUN_IN_CONTAINER: "1" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: always @@ -146,7 +147,7 @@ zombienet-polkadot-misc-0002-upgrade-node: - echo "Overrided poladot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - BUILD_LINUX_JOB_ID="$(cat ./artifacts/BUILD_LINUX_JOB_ID)" - - export POLKADOT_PR_BIN_URL="https://gitlab-stg.parity.io/parity/mirrors/polkadot-sdk/-/jobs/${BUILD_LINUX_JOB_ID}/artifacts/raw/artifacts/polkadot" + - export POLKADOT_PR_ARTIFACTS_URL="https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/${BUILD_LINUX_JOB_ID}/artifacts/raw/artifacts" - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" - echo "local-dir ${LOCAL_DIR}" diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 9a461ca4170..9fb2f161ad7 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -24,6 +24,7 @@ GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/substrate/zombienet" FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + RUN_IN_CONTAINER: "1" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: always -- GitLab From cd10c46146679bea7ac66ff230eefe642ae69fa7 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 29 Aug 2023 17:35:36 +0200 Subject: [PATCH 007/633] Cleanup some files (#1166) * Remove .cargo folders Signed-off-by: Oliver Tale-Yazdi * Remove rustfmt.toml Signed-off-by: Oliver Tale-Yazdi * Hide rustfmt.toml file Signed-off-by: Oliver Tale-Yazdi * Merge .gitignore files Signed-off-by: Oliver Tale-Yazdi * Update commit hash after history-rewrite Signed-off-by: Oliver Tale-Yazdi * Try to hot-fix license scanner Signed-off-by: Oliver Tale-Yazdi * Update .gitignore Co-authored-by: Chevdor * Undo changes to check-license Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Chevdor --- .gitignore | 43 +++++++++++++++++++++++++------- rustfmt.toml => .rustfmt.toml | 0 cumulus/.cargo/config.toml | 33 ------------------------ cumulus/.gitignore | 11 -------- cumulus/.rustfmt.toml | 28 --------------------- polkadot/.cargo/config.toml | 33 ------------------------ polkadot/.gitignore | 16 ------------ polkadot/rustfmt.toml | 28 --------------------- substrate/.cargo/config.toml | 33 ------------------------ substrate/.git-blame-ignore-revs | 4 +-- substrate/.gitignore | 30 ---------------------- substrate/rustfmt.toml | 24 ------------------ 12 files changed, 36 insertions(+), 247 deletions(-) rename rustfmt.toml => .rustfmt.toml (100%) delete mode 100644 cumulus/.cargo/config.toml delete mode 100644 cumulus/.gitignore delete mode 100644 cumulus/.rustfmt.toml delete mode 100644 polkadot/.cargo/config.toml delete mode 100644 polkadot/.gitignore delete mode 100644 polkadot/rustfmt.toml delete mode 100644 substrate/.cargo/config.toml delete mode 100644 substrate/.gitignore delete mode 100644 substrate/rustfmt.toml diff --git a/.gitignore b/.gitignore index b71c270d736..bd7f34b4810 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,38 @@ -target/ -**/target/ +!polkadot.service +.cargo-remote.toml +.direnv/ +.DS_Store +.env* .idea +.local .vscode -.DS_Store -/.cargo/config -polkadot_argument_parsing -**/node_modules -**/chains/ +.wasm-binaries +*.bin *.iml -.env +*.orig +*.rej +*.swp **/._* - +**/.criterion/ +**/*.rs.bk +**/chains/ +**/hfuzz_target/ +**/hfuzz_workspace/ +**/node_modules +**/target/ +**/wip/*.stderr +/.cargo/config +/.envrc +artifacts +bin/node-template/Cargo.lock +nohup.out +polkadot_argument_parsing +polkadot.* +pwasm-alloc/Cargo.lock +pwasm-libc/Cargo.lock +release-artifacts +release.json +rls*.log +runtime/wasm/target/ +substrate.code-workspace +target/ diff --git a/rustfmt.toml b/.rustfmt.toml similarity index 100% rename from rustfmt.toml rename to .rustfmt.toml diff --git a/cumulus/.cargo/config.toml b/cumulus/.cargo/config.toml deleted file mode 100644 index 4796a2c2696..00000000000 --- a/cumulus/.cargo/config.toml +++ /dev/null @@ -1,33 +0,0 @@ -# -# An auto defined `clippy` feature was introduced, -# but it was found to clash with user defined features, -# so was renamed to `cargo-clippy`. -# -# If you want standard clippy run: -# RUSTFLAGS= cargo clippy -[target.'cfg(feature = "cargo-clippy")'] -rustflags = [ - "-Aclippy::all", - "-Dclippy::correctness", - "-Aclippy::if-same-then-else", - "-Aclippy::clone-double-ref", - "-Dclippy::complexity", - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::unit_arg", # styalistic. - "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::derivable_impls", # false positives - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::extra-unused-type-parameters", # stylistic -] diff --git a/cumulus/.gitignore b/cumulus/.gitignore deleted file mode 100644 index 225be857745..00000000000 --- a/cumulus/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -**/target/ -.idea -.vscode -.DS_Store -/.cargo/config -polkadot_argument_parsing -**/node_modules -**/chains/ -*.iml -.env -**/._* diff --git a/cumulus/.rustfmt.toml b/cumulus/.rustfmt.toml deleted file mode 100644 index e2c4a037f37..00000000000 --- a/cumulus/.rustfmt.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Basic -edition = "2021" -hard_tabs = true -max_width = 100 -use_small_heuristics = "Max" - -# Imports -imports_granularity = "Crate" -reorder_imports = true - -# Consistency -newline_style = "Unix" - -# Format comments -comment_width = 100 -wrap_comments = true - -# Misc -chain_width = 80 -spaces_around_ranges = false -binop_separator = "Back" -reorder_impl_items = false -match_arm_leading_pipes = "Preserve" -match_arm_blocks = false -match_block_trailing_comma = true -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true diff --git a/polkadot/.cargo/config.toml b/polkadot/.cargo/config.toml deleted file mode 100644 index 4796a2c2696..00000000000 --- a/polkadot/.cargo/config.toml +++ /dev/null @@ -1,33 +0,0 @@ -# -# An auto defined `clippy` feature was introduced, -# but it was found to clash with user defined features, -# so was renamed to `cargo-clippy`. -# -# If you want standard clippy run: -# RUSTFLAGS= cargo clippy -[target.'cfg(feature = "cargo-clippy")'] -rustflags = [ - "-Aclippy::all", - "-Dclippy::correctness", - "-Aclippy::if-same-then-else", - "-Aclippy::clone-double-ref", - "-Dclippy::complexity", - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::unit_arg", # styalistic. - "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::derivable_impls", # false positives - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::extra-unused-type-parameters", # stylistic -] diff --git a/polkadot/.gitignore b/polkadot/.gitignore deleted file mode 100644 index 61ef9e91a55..00000000000 --- a/polkadot/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -**/target/ -**/*.rs.bk -*.swp -.wasm-binaries -runtime/wasm/target/ -**/._* -.idea -.vscode -polkadot.* -!polkadot.service -.DS_Store -.env - -artifacts -release-artifacts -release.json diff --git a/polkadot/rustfmt.toml b/polkadot/rustfmt.toml deleted file mode 100644 index e2c4a037f37..00000000000 --- a/polkadot/rustfmt.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Basic -edition = "2021" -hard_tabs = true -max_width = 100 -use_small_heuristics = "Max" - -# Imports -imports_granularity = "Crate" -reorder_imports = true - -# Consistency -newline_style = "Unix" - -# Format comments -comment_width = 100 -wrap_comments = true - -# Misc -chain_width = 80 -spaces_around_ranges = false -binop_separator = "Back" -reorder_impl_items = false -match_arm_leading_pipes = "Preserve" -match_arm_blocks = false -match_block_trailing_comma = true -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true diff --git a/substrate/.cargo/config.toml b/substrate/.cargo/config.toml deleted file mode 100644 index 4796a2c2696..00000000000 --- a/substrate/.cargo/config.toml +++ /dev/null @@ -1,33 +0,0 @@ -# -# An auto defined `clippy` feature was introduced, -# but it was found to clash with user defined features, -# so was renamed to `cargo-clippy`. -# -# If you want standard clippy run: -# RUSTFLAGS= cargo clippy -[target.'cfg(feature = "cargo-clippy")'] -rustflags = [ - "-Aclippy::all", - "-Dclippy::correctness", - "-Aclippy::if-same-then-else", - "-Aclippy::clone-double-ref", - "-Dclippy::complexity", - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::unit_arg", # styalistic. - "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::derivable_impls", # false positives - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::extra-unused-type-parameters", # stylistic -] diff --git a/substrate/.git-blame-ignore-revs b/substrate/.git-blame-ignore-revs index c99a3070231..aae391d6d83 100644 --- a/substrate/.git-blame-ignore-revs +++ b/substrate/.git-blame-ignore-revs @@ -10,6 +10,6 @@ # # You should add new commit hashes to this file when you create or find such big # automated refactorings while reading code history. If you only know the short hash, -# use `git rev-parse 1d5abf01` to expand it to the full SHA1 hash needed in this file. +# use `git rev-parse 7b56ab15b4` to expand it to the full SHA1 hash needed in this file. -1d5abf01abafdb6c15bcd0172f5de09fd87c5fbf # Run cargo fmt on the whole code base (#9394) +7b56ab15b4a8e06df5eefc17e600e3c1419aede5 # Run cargo fmt on the whole code base (#9394) diff --git a/substrate/.gitignore b/substrate/.gitignore deleted file mode 100644 index 65059279f3a..00000000000 --- a/substrate/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -**/target/ -**/*.rs.bk -*.swp -.wasm-binaries -pwasm-alloc/target/ -pwasm-libc/target/ -pwasm-alloc/Cargo.lock -pwasm-libc/Cargo.lock -bin/node/runtime/wasm/target/ -**/._* -**/.criterion/ -.vscode -polkadot.* -.DS_Store -.idea/ -nohup.out -rls*.log -*.orig -*.rej -**/wip/*.stderr -.local -**/hfuzz_target/ -**/hfuzz_workspace/ -.cargo-remote.toml -*.bin -*.iml -bin/node-template/Cargo.lock -substrate.code-workspace -.direnv/ -/.envrc diff --git a/substrate/rustfmt.toml b/substrate/rustfmt.toml deleted file mode 100644 index f6fbe80064f..00000000000 --- a/substrate/rustfmt.toml +++ /dev/null @@ -1,24 +0,0 @@ -# Basic -hard_tabs = true -max_width = 100 -use_small_heuristics = "Max" -# Imports -imports_granularity = "Crate" -reorder_imports = true -# Consistency -newline_style = "Unix" -# Format comments -comment_width = 100 -wrap_comments = true -# Misc -chain_width = 80 -spaces_around_ranges = false -binop_separator = "Back" -reorder_impl_items = false -match_arm_leading_pipes = "Preserve" -match_arm_blocks = false -match_block_trailing_comma = true -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true -edition = "2021" -- GitLab From 562557a9489d25e398bfc7c2b02138d99da11ea9 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 29 Aug 2023 18:47:05 +0300 Subject: [PATCH 008/633] sc-consensus-beefy: reuse instead of recreate GossipEngine (#1262) "sc-consensus-beefy: restart voter on pallet reset #14821" introduced a mechanism to reinitialize the BEEFY worker on certain errors; but re-creating the GossipEngine doesn't play well with "Rework the event system of sc-network #14197". So this PR slightly changes the re-initialization logic to reuse the original GossipEngine and not recreate it. Signed-off-by: Adrian Catangiu --- substrate/client/consensus/beefy/src/lib.rs | 66 ++++++++------- .../client/consensus/beefy/src/worker.rs | 83 ++++++++++++------- 2 files changed, 87 insertions(+), 62 deletions(-) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 0b3baa007c1..72df3cab855 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -255,36 +255,42 @@ pub async fn start_beefy_gadget( let mut finality_notifications = client.finality_notification_stream().fuse(); let mut block_import_justif = links.from_block_import_justif_stream.subscribe(100_000).fuse(); + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + // Default votes filter is to discard everything. + // Validator is updated later with correct starting round and set id. + let (gossip_validator, gossip_report_stream) = + communication::gossip::GossipValidator::new(known_peers.clone()); + let gossip_validator = Arc::new(gossip_validator); + let gossip_engine = GossipEngine::new( + network.clone(), + sync.clone(), + gossip_protocol_name.clone(), + gossip_validator.clone(), + None, + ); + + // The `GossipValidator` adds and removes known peers based on valid votes and network + // events. + let on_demand_justifications = OnDemandJustificationsEngine::new( + network.clone(), + justifications_protocol_name.clone(), + known_peers, + prometheus_registry.clone(), + ); + let mut beefy_comms = worker::BeefyComms { + gossip_engine, + gossip_validator, + gossip_report_stream, + on_demand_justifications, + }; + // We re-create and re-run the worker in this loop in order to quickly reinit and resume after // select recoverable errors. loop { - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - // Default votes filter is to discard everything. - // Validator is updated later with correct starting round and set id. - let (gossip_validator, gossip_report_stream) = - communication::gossip::GossipValidator::new(known_peers.clone()); - let gossip_validator = Arc::new(gossip_validator); - let mut gossip_engine = GossipEngine::new( - network.clone(), - sync.clone(), - gossip_protocol_name.clone(), - gossip_validator.clone(), - None, - ); - - // The `GossipValidator` adds and removes known peers based on valid votes and network - // events. - let on_demand_justifications = OnDemandJustificationsEngine::new( - network.clone(), - justifications_protocol_name.clone(), - known_peers, - prometheus_registry.clone(), - ); - // Wait for BEEFY pallet to be active before starting voter. let persisted_state = match wait_for_runtime_pallet( &*runtime, - &mut gossip_engine, + &mut beefy_comms.gossip_engine, &mut finality_notifications, ) .await @@ -306,7 +312,7 @@ pub async fn start_beefy_gadget( // Update the gossip validator with the right starting round and set id. if let Err(e) = persisted_state .gossip_filter_config() - .map(|f| gossip_validator.update_filter(f)) + .map(|f| beefy_comms.gossip_validator.update_filter(f)) { error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); return @@ -318,10 +324,7 @@ pub async fn start_beefy_gadget( runtime: runtime.clone(), sync: sync.clone(), key_store: key_store.clone().into(), - gossip_engine, - gossip_validator, - gossip_report_stream, - on_demand_justifications, + comms: beefy_comms, links: links.clone(), metrics: metrics.clone(), pending_justifications: BTreeMap::new(), @@ -335,12 +338,13 @@ pub async fn start_beefy_gadget( .await { // On `ConsensusReset` error, just reinit and restart voter. - futures::future::Either::Left((error::Error::ConsensusReset, _)) => { + futures::future::Either::Left(((error::Error::ConsensusReset, reuse_comms), _)) => { error!(target: LOG_TARGET, "🥩 Error: {:?}. Restarting voter.", error::Error::ConsensusReset); + beefy_comms = reuse_comms; continue }, // On other errors, bring down / finish the task. - futures::future::Either::Left((worker_err, _)) => + futures::future::Either::Left(((worker_err, _), _)) => error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", worker_err), futures::future::Either::Right((odj_handler_err, _)) => error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_err), diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 0d3845a2703..a239e34030c 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -313,6 +313,16 @@ impl PersistedState { } } +/// Helper object holding BEEFY worker communication/gossip components. +/// +/// These are created once, but will be reused if worker is restarted/reinitialized. +pub(crate) struct BeefyComms { + pub gossip_engine: GossipEngine, + pub gossip_validator: Arc>, + pub gossip_report_stream: TracingUnboundedReceiver, + pub on_demand_justifications: OnDemandJustificationsEngine, +} + /// A BEEFY worker plays the BEEFY protocol pub(crate) struct BeefyWorker { // utilities @@ -322,11 +332,8 @@ pub(crate) struct BeefyWorker { pub sync: Arc, pub key_store: BeefyKeystore, - // communication - pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, - pub gossip_report_stream: TracingUnboundedReceiver, - pub on_demand_justifications: OnDemandJustificationsEngine, + // communication (created once, but returned and reused if worker is restarted/reinitialized) + pub comms: BeefyComms, // channels /// Links between the block importer, the background voter and the RPC layer. @@ -475,7 +482,7 @@ where if let Err(e) = self .persisted_state .gossip_filter_config() - .map(|filter| self.gossip_validator.update_filter(filter)) + .map(|filter| self.comms.gossip_validator.update_filter(filter)) { error!(target: LOG_TARGET, "🥩 Voter error: {:?}", e); } @@ -495,7 +502,11 @@ where if let Some(finality_proof) = self.handle_vote(vote)? { let gossip_proof = GossipMessage::::FinalityProof(finality_proof); let encoded_proof = gossip_proof.encode(); - self.gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); + self.comms.gossip_engine.gossip_message( + proofs_topic::(), + encoded_proof, + true, + ); }, RoundAction::Drop => metric_inc!(self, beefy_stale_votes), RoundAction::Enqueue => error!(target: LOG_TARGET, "🥩 unexpected vote: {:?}.", vote), @@ -603,7 +614,7 @@ where metric_set!(self, beefy_best_block, block_num); - self.on_demand_justifications.cancel_requests_older_than(block_num); + self.comms.on_demand_justifications.cancel_requests_older_than(block_num); if let Err(e) = self .backend @@ -632,7 +643,7 @@ where // Update gossip validator votes filter. self.persisted_state .gossip_filter_config() - .map(|filter| self.gossip_validator.update_filter(filter))?; + .map(|filter| self.comms.gossip_validator.update_filter(filter))?; Ok(()) } @@ -752,12 +763,14 @@ where err })? { let encoded_proof = GossipMessage::::FinalityProof(finality_proof).encode(); - self.gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); + self.comms + .gossip_engine + .gossip_message(proofs_topic::(), encoded_proof, true); } else { metric_inc!(self, beefy_votes_sent); debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", vote); let encoded_vote = GossipMessage::::Vote(vote).encode(); - self.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); + self.comms.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); } // Persist state after vote to avoid double voting in case of voter restarts. @@ -783,7 +796,7 @@ where // make sure there's also an on-demand justification request out for it. if let Some((block, active)) = self.voting_oracle().mandatory_pending() { // This only starts new request if there isn't already an active one. - self.on_demand_justifications.request(block, active); + self.comms.on_demand_justifications.request(block, active); } } } @@ -796,7 +809,7 @@ where mut self, block_import_justif: &mut Fuse>>, finality_notifications: &mut Fuse>, - ) -> Error { + ) -> (Error, BeefyComms) { info!( target: LOG_TARGET, "🥩 run BEEFY worker, best grandpa: #{:?}.", @@ -804,7 +817,8 @@ where ); let mut votes = Box::pin( - self.gossip_engine + self.comms + .gossip_engine .messages_for(votes_topic::()) .filter_map(|notification| async move { let vote = GossipMessage::::decode_all(&mut ¬ification.message[..]) @@ -816,7 +830,8 @@ where .fuse(), ); let mut gossip_proofs = Box::pin( - self.gossip_engine + self.comms + .gossip_engine .messages_for(proofs_topic::()) .filter_map(|notification| async move { let proof = GossipMessage::::decode_all(&mut ¬ification.message[..]) @@ -828,12 +843,12 @@ where .fuse(), ); - loop { + let error = loop { // Act on changed 'state'. self.process_new_state(); // Mutable reference used to drive the gossip engine. - let mut gossip_engine = &mut self.gossip_engine; + let mut gossip_engine = &mut self.comms.gossip_engine; // Use temp val and report after async section, // to avoid having to Mutex-wrap `gossip_engine`. let mut gossip_report: Option = None; @@ -847,18 +862,18 @@ where notification = finality_notifications.next() => { if let Some(notif) = notification { if let Err(err) = self.handle_finality_notification(¬if) { - return err; + break err; } } else { - return Error::FinalityStreamTerminated; + break Error::FinalityStreamTerminated; } }, // Make sure to pump gossip engine. _ = gossip_engine => { - return Error::GossipEngineTerminated; + break Error::GossipEngineTerminated; }, // Process incoming justifications as these can make some in-flight votes obsolete. - response_info = self.on_demand_justifications.next().fuse() => { + response_info = self.comms.on_demand_justifications.next().fuse() => { match response_info { ResponseInfo::ValidProof(justif, peer_report) => { if let Err(err) = self.triage_incoming_justif(justif) { @@ -878,7 +893,7 @@ where debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - return Error::BlockImportStreamTerminated; + break Error::BlockImportStreamTerminated; } }, justif = gossip_proofs.next() => { @@ -888,7 +903,7 @@ where debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - return Error::FinalityProofGossipStreamTerminated; + break Error::FinalityProofGossipStreamTerminated; } }, // Finally process incoming votes. @@ -899,18 +914,21 @@ where debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - return Error::VotesGossipStreamTerminated; + break Error::VotesGossipStreamTerminated; } }, // Process peer reports. - report = self.gossip_report_stream.next() => { + report = self.comms.gossip_report_stream.next() => { gossip_report = report; }, } if let Some(PeerReport { who, cost_benefit }) = gossip_report { - self.gossip_engine.report(who, cost_benefit); + self.comms.gossip_engine.report(who, cost_benefit); } - } + }; + + // return error _and_ `comms` that can be reused + (error, self.comms) } /// Report the given equivocation to the BEEFY runtime module. This method @@ -1146,18 +1164,21 @@ pub(crate) mod tests { ) .unwrap(); let payload_provider = MmrRootProvider::new(api.clone()); + let comms = BeefyComms { + gossip_engine, + gossip_validator, + gossip_report_stream, + on_demand_justifications, + }; BeefyWorker { backend, payload_provider, runtime: api, key_store: Some(keystore).into(), links, - gossip_engine, - gossip_validator, - gossip_report_stream, + comms, metrics, sync: Arc::new(sync), - on_demand_justifications, pending_justifications: BTreeMap::new(), persisted_state, } -- GitLab From 6bb9ad4b1a1135383c27a04bdc14d901c5ca3733 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Tue, 29 Aug 2023 17:49:00 +0200 Subject: [PATCH 009/633] PRCR - temporary disabled Audit rule (#1239) @the-right-joyce has requested to disable the Audit rule until we can fix the problem that it always request reviewers (even if the user belongs to the `prevent-review-request` field. --- .github/pr-custom-review.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index a453336bddb..d37ea4cf095 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -14,22 +14,6 @@ rules: - ci - release-engineering - - name: Audit rules - check_type: changed_files - 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$ - all_distinct: - - min_approvals: 1 - teams: - - locks-review - - min_approvals: 1 - teams: - - polkadot-review - - min_approvals: 1 - teams: - - srlabs - - name: Core developers check_type: changed_files condition: -- GitLab From 62f0a729cf579319a50a8f6466db45decbbd9337 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:49:16 +0300 Subject: [PATCH 010/633] chainSpec: Stabilize chainSpec methods to V1 (#1206) * chainSpec: Stabilize chainSpec methods to V1 Signed-off-by: Alexandru Vasile * chainSpec/api: Remove unstable documentation Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: James Wilson --- .../client/rpc-spec-v2/src/chain_spec/api.rs | 24 +++++-------------- .../rpc-spec-v2/src/chain_spec/chain_spec.rs | 6 ++--- .../rpc-spec-v2/src/chain_spec/tests.rs | 6 ++--- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_spec/api.rs b/substrate/client/rpc-spec-v2/src/chain_spec/api.rs index 66c9f868047..b12ba6791d7 100644 --- a/substrate/client/rpc-spec-v2/src/chain_spec/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_spec/api.rs @@ -24,30 +24,18 @@ use sc_chain_spec::Properties; #[rpc(client, server)] pub trait ChainSpecApi { /// Get the chain name, as present in the chain specification. - /// - /// # Unstable - /// - /// This method is unstable and subject to change in the future. - #[method(name = "chainSpec_unstable_chainName")] - fn chain_spec_unstable_chain_name(&self) -> RpcResult; + #[method(name = "chainSpec_v1_chainName")] + fn chain_spec_v1_chain_name(&self) -> RpcResult; /// Get the chain's genesis hash. - /// - /// # Unstable - /// - /// This method is unstable and subject to change in the future. - #[method(name = "chainSpec_unstable_genesisHash")] - fn chain_spec_unstable_genesis_hash(&self) -> RpcResult; + #[method(name = "chainSpec_v1_genesisHash")] + fn chain_spec_v1_genesis_hash(&self) -> RpcResult; /// Get the properties of the chain, as present in the chain specification. /// /// # Note /// /// The json whitespaces are not guaranteed to persist. - /// - /// # Unstable - /// - /// This method is unstable and subject to change in the future. - #[method(name = "chainSpec_unstable_properties")] - fn chain_spec_unstable_properties(&self) -> RpcResult; + #[method(name = "chainSpec_v1_properties")] + fn chain_spec_v1_properties(&self) -> RpcResult; } diff --git a/substrate/client/rpc-spec-v2/src/chain_spec/chain_spec.rs b/substrate/client/rpc-spec-v2/src/chain_spec/chain_spec.rs index 99ea34521f5..75fe14fd8be 100644 --- a/substrate/client/rpc-spec-v2/src/chain_spec/chain_spec.rs +++ b/substrate/client/rpc-spec-v2/src/chain_spec/chain_spec.rs @@ -46,15 +46,15 @@ impl ChainSpec { } impl ChainSpecApiServer for ChainSpec { - fn chain_spec_unstable_chain_name(&self) -> RpcResult { + fn chain_spec_v1_chain_name(&self) -> RpcResult { Ok(self.name.clone()) } - fn chain_spec_unstable_genesis_hash(&self) -> RpcResult { + fn chain_spec_v1_genesis_hash(&self) -> RpcResult { Ok(self.genesis_hash.clone()) } - fn chain_spec_unstable_properties(&self) -> RpcResult { + fn chain_spec_v1_properties(&self) -> RpcResult { Ok(self.properties.clone()) } } diff --git a/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs b/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs index 74aec01a211..9326fd5f3b7 100644 --- a/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -36,7 +36,7 @@ fn api() -> RpcModule { #[tokio::test] async fn chain_spec_chain_name_works() { let name = api() - .call::<_, String>("chainSpec_unstable_chainName", EmptyParams::new()) + .call::<_, String>("chainSpec_v1_chainName", EmptyParams::new()) .await .unwrap(); assert_eq!(name, CHAIN_NAME); @@ -45,7 +45,7 @@ async fn chain_spec_chain_name_works() { #[tokio::test] async fn chain_spec_genesis_hash_works() { let genesis = api() - .call::<_, String>("chainSpec_unstable_genesisHash", EmptyParams::new()) + .call::<_, String>("chainSpec_v1_genesisHash", EmptyParams::new()) .await .unwrap(); assert_eq!(genesis, format!("0x{}", hex::encode(CHAIN_GENESIS))); @@ -54,7 +54,7 @@ async fn chain_spec_genesis_hash_works() { #[tokio::test] async fn chain_spec_properties_works() { let properties = api() - .call::<_, Properties>("chainSpec_unstable_properties", EmptyParams::new()) + .call::<_, Properties>("chainSpec_v1_properties", EmptyParams::new()) .await .unwrap(); assert_eq!(properties, serde_json::from_str(CHAIN_PROPERTIES).unwrap()); -- GitLab From 430edd75351e82ea3f814c05fbbbe0cb860e6d27 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 29 Aug 2023 20:36:45 +0300 Subject: [PATCH 011/633] Relax genesis config to not require `Default` impl (#1221) Co-authored-by: Oliver Tale-Yazdi --- substrate/frame/support/src/genesis_builder_helper.rs | 5 ++++- substrate/frame/support/src/traits/hooks.rs | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/src/genesis_builder_helper.rs b/substrate/frame/support/src/genesis_builder_helper.rs index d4144a4d9fd..b2594d183ec 100644 --- a/substrate/frame/support/src/genesis_builder_helper.rs +++ b/substrate/frame/support/src/genesis_builder_helper.rs @@ -25,7 +25,10 @@ use sp_runtime::format_runtime_string; /// Get the default `GenesisConfig` as a JSON blob. For more info refer to /// [`sp_genesis_builder::GenesisBuilder::create_default_config`] -pub fn create_default_config() -> sp_std::vec::Vec { +pub fn create_default_config() -> sp_std::vec::Vec +where + GC: BuildGenesisConfig + Default, +{ serde_json::to_string(&GC::default()) .expect("serialization to json is expected to work. qed.") .into_bytes() diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index 6163c048e75..4453a3fb755 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -442,7 +442,7 @@ pub trait Hooks { /// A trait to define the build function of a genesis config for both runtime and pallets. /// /// Replaces deprecated [`GenesisBuild`]. -pub trait BuildGenesisConfig: Default + sp_runtime::traits::MaybeSerializeDeserialize { +pub trait BuildGenesisConfig: sp_runtime::traits::MaybeSerializeDeserialize { /// The build function puts initial `GenesisConfig` keys/values pairs into the storage. fn build(&self); } @@ -452,7 +452,7 @@ pub trait BuildGenesisConfig: Default + sp_runtime::traits::MaybeSerializeDeseri #[deprecated( note = "GenesisBuild is planned to be removed in December 2023. Use BuildGenesisConfig instead of it." )] -pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { +pub trait GenesisBuild: sp_runtime::traits::MaybeSerializeDeserialize { /// The build function is called within an externalities allowing storage APIs. /// Thus one can write to storage using regular pallet storages. fn build(&self); -- GitLab From 9acb06717e09d842068da15a433489496c3e732b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 29 Aug 2023 21:23:38 +0200 Subject: [PATCH 012/633] Fix `test-rustdoc` (#1266) * Fix `test-rustdoc` * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- polkadot/core-primitives/src/lib.rs | 2 +- .../node/core/parachains-inherent/src/lib.rs | 2 +- .../node/core/pvf/common/src/executor_intf.rs | 4 ++-- polkadot/node/network/bridge/src/rx/mod.rs | 2 +- polkadot/node/network/bridge/src/tx/mod.rs | 2 +- .../protocol/src/authority_discovery.rs | 4 ++-- .../node/network/protocol/src/peer_set.rs | 4 ++-- polkadot/node/primitives/src/disputes/mod.rs | 4 ++-- polkadot/node/primitives/src/lib.rs | 8 +++---- polkadot/node/service/src/benchmarking.rs | 2 +- polkadot/node/service/src/overseer.rs | 2 +- .../node/test/client/src/block_builder.rs | 2 +- polkadot/parachain/src/lib.rs | 5 +++-- polkadot/primitives/src/v5/mod.rs | 6 +++--- .../common/src/assigned_slots/migration.rs | 6 +++--- polkadot/runtime/common/src/elections.rs | 3 ++- polkadot/runtime/common/src/lib.rs | 2 +- polkadot/runtime/common/src/purchase.rs | 2 +- .../parachains/src/assigner_on_demand/mod.rs | 4 ++-- .../runtime/parachains/src/configuration.rs | 21 +++++++++++-------- polkadot/runtime/parachains/src/dmp.rs | 6 +++--- polkadot/runtime/parachains/src/hrmp.rs | 10 ++++----- .../runtime/parachains/src/inclusion/mod.rs | 6 +++--- polkadot/runtime/parachains/src/lib.rs | 8 ------- .../parachains/src/paras_inherent/misc.rs | 2 +- .../parachains/src/runtime_api_impl/v5.rs | 5 ++--- polkadot/utils/staking-miner/src/opts.rs | 8 +++---- polkadot/xcm/xcm-builder/src/pay.rs | 2 +- .../xcm-builder/src/process_xcm_message.rs | 2 +- .../procedural/src/pallet/expand/storage.rs | 8 ++++--- 30 files changed, 71 insertions(+), 73 deletions(-) diff --git a/polkadot/core-primitives/src/lib.rs b/polkadot/core-primitives/src/lib.rs index aa01cf8dfc4..a74cdef3ad7 100644 --- a/polkadot/core-primitives/src/lib.rs +++ b/polkadot/core-primitives/src/lib.rs @@ -60,7 +60,7 @@ pub type Hash = sp_core::H256; /// Unit type wrapper around [`type@Hash`] that represents a candidate hash. /// -/// This type is produced by [`CandidateReceipt::hash`]. +/// This type is produced by `CandidateReceipt::hash`. /// /// This type makes it easy to enforce that a hash is a candidate hash on the type level. #[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, Default, PartialOrd, Ord, TypeInfo)] diff --git a/polkadot/node/core/parachains-inherent/src/lib.rs b/polkadot/node/core/parachains-inherent/src/lib.rs index 3063147fb13..1de3cab32be 100644 --- a/polkadot/node/core/parachains-inherent/src/lib.rs +++ b/polkadot/node/core/parachains-inherent/src/lib.rs @@ -19,7 +19,7 @@ //! Parachain backing and approval is an off-chain process, but the parachain needs to progress on //! chain as well. To make it progress on chain a block producer needs to forward information about //! the state of a parachain to the runtime. This information is forwarded through an inherent to -//! the runtime. Here we provide the [`ParachainInherentDataProvider`] that requests the relevant +//! the runtime. Here we provide the [`ParachainsInherentDataProvider`] that requests the relevant //! data from the provisioner subsystem and creates the the inherent data that the runtime will use //! to create an inherent. diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 42ed4b79c76..79839149ebd 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_intf.rs @@ -141,7 +141,7 @@ impl Executor { /// # Safety /// /// The caller must ensure that the compiled artifact passed here was: - /// 1) produced by [`prepare`], + /// 1) produced by `prepare`, /// 2) was not modified, /// /// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. @@ -171,7 +171,7 @@ impl Executor { /// # Safety /// /// The caller must ensure that the compiled artifact passed here was: - /// 1) produced by [`prepare`], + /// 1) produced by `prepare`, /// 2) was not modified, /// /// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 002919c5b0e..51d248ca2d4 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -92,7 +92,7 @@ impl NetworkBridgeRx { /// discovery service. /// /// This assumes that the network service has had the notifications protocol for the network - /// bridge already registered. See [`peers_sets_info`](peers_sets_info). + /// bridge already registered. See [`peer_sets_info`]. pub fn new( network_service: N, authority_discovery_service: AD, diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index e0ca633547f..1b386ce1239 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -65,7 +65,7 @@ impl NetworkBridgeTx { /// discovery service. /// /// This assumes that the network service has had the notifications protocol for the network - /// bridge already registered. See [`peers_sets_info`](peers_sets_info). + /// bridge already registered. See [`peer_sets_info`]. pub fn new( network_service: N, authority_discovery_service: AD, diff --git a/polkadot/node/network/protocol/src/authority_discovery.rs b/polkadot/node/network/protocol/src/authority_discovery.rs index 0cf11b93d18..beb5409d4ac 100644 --- a/polkadot/node/network/protocol/src/authority_discovery.rs +++ b/polkadot/node/network/protocol/src/authority_discovery.rs @@ -30,12 +30,12 @@ use sc_network::{Multiaddr, PeerId}; /// Needed for mocking in tests mostly. #[async_trait] pub trait AuthorityDiscovery: Send + Debug + 'static { - /// Get the addresses for the given [`AuthorityId`] from the local address cache. + /// Get the addresses for the given [`AuthorityDiscoveryId`] from the local address cache. async fn get_addresses_by_authority_id( &mut self, authority: AuthorityDiscoveryId, ) -> Option>; - /// Get the [`AuthorityId`] for the given [`PeerId`] from the local address cache. + /// Get the [`AuthorityDiscoveryId`] for the given [`PeerId`] from the local address cache. async fn get_authority_ids_by_peer_id( &mut self, peer_id: PeerId, diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index b6f8c9dec23..c2163783c2c 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -197,7 +197,7 @@ impl IndexMut for PerPeerSet { /// Get `NonDefaultSetConfig`s for all available peer sets, at their default versions. /// -/// Should be used during network configuration (added to [`NetworkConfiguration::extra_sets`]) +/// Should be used during network configuration (added to `NetworkConfiguration::extra_sets`) /// or shortly after startup to register the protocols with the network service. pub fn peer_sets_info( is_authority: IsAuthority, @@ -288,7 +288,7 @@ pub struct PeerSetProtocolNames { } impl PeerSetProtocolNames { - /// Construct [`PeerSetProtocols`] using `genesis_hash` and `fork_id`. + /// Construct [`PeerSetProtocolNames`] using `genesis_hash` and `fork_id`. pub fn new(genesis_hash: Hash, fork_id: Option<&str>) -> Self { let mut protocols = HashMap::new(); let mut names = HashMap::new(); diff --git a/polkadot/node/primitives/src/disputes/mod.rs b/polkadot/node/primitives/src/disputes/mod.rs index ae8602dd5fc..500b705be95 100644 --- a/polkadot/node/primitives/src/disputes/mod.rs +++ b/polkadot/node/primitives/src/disputes/mod.rs @@ -263,9 +263,9 @@ impl SignedDisputeStatement { self.session_index } - /// Convert a [`SignedFullStatement`] to a [`SignedDisputeStatement`] + /// Convert a unchecked backing statement to a [`SignedDisputeStatement`] /// - /// As [`SignedFullStatement`] contains only the validator index and + /// As the unchecked backing statement contains only the validator index and /// not the validator public key, the public key must be passed as well, /// along with the signing context. /// diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 4cebc23ad31..baab07a9ba2 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -463,8 +463,8 @@ impl CollationResult { /// Collation function. /// /// Will be called with the hash of the relay chain block the parachain block should be build on and -/// the [`ValidationData`] that provides information about the state of the parachain on the relay -/// chain. +/// the [`PersistedValidationData`] that provides information about the state of the parachain on +/// the relay chain. /// /// Returns an optional [`CollationResult`]. #[cfg(not(target_os = "unknown"))] @@ -498,7 +498,7 @@ impl std::fmt::Debug for CollationGenerationConfig { } } -/// Parameters for [`CollationGenerationMessage::SubmitCollation`]. +/// Parameters for `CollationGenerationMessage::SubmitCollation`. #[derive(Debug)] pub struct SubmitCollationParams { /// The relay-parent the collation is built against. @@ -634,7 +634,7 @@ pub struct ErasureChunk { } impl ErasureChunk { - /// Convert bounded Vec Proof to regular Vec> + /// Convert bounded Vec Proof to regular `Vec>` pub fn proof(&self) -> &Proof { &self.proof } diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 6955bc6d969..cfe1c873c05 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Code related to benchmarking a [`crate::Client`]. +//! Code related to benchmarking a node. use polkadot_primitives::AccountId; use sc_client_api::UsageProvider; diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 1c49577508f..33127b638e5 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -139,7 +139,7 @@ where pub overseer_message_channel_capacity_override: Option, /// Request-response protocol names source. pub req_protocol_names: ReqProtocolNames, - /// [`PeerSet`] protocol names to protocols mapping. + /// `PeerSet` protocol names to protocols mapping. pub peerset_protocol_names: PeerSetProtocolNames, /// The offchain transaction pool factory. pub offchain_transaction_pool_factory: OffchainTransactionPoolFactory, diff --git a/polkadot/node/test/client/src/block_builder.rs b/polkadot/node/test/client/src/block_builder.rs index 0987cef55c1..b4ff050ff15 100644 --- a/polkadot/node/test/client/src/block_builder.rs +++ b/polkadot/node/test/client/src/block_builder.rs @@ -41,7 +41,7 @@ pub trait InitPolkadotBlockBuilder { /// Init a Polkadot specific block builder at a specific block that works for the test runtime. /// /// Same as [`InitPolkadotBlockBuilder::init_polkadot_block_builder`] besides that it takes a - /// [`BlockId`] to say which should be the parent block of the block that is being build. + /// `Hash` to say which should be the parent block of the block that is being build. fn init_polkadot_block_builder_at( &self, hash: ::Hash, diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs index 7bead231483..913d887e4a8 100644 --- a/polkadot/parachain/src/lib.rs +++ b/polkadot/parachain/src/lib.rs @@ -27,10 +27,11 @@ //! instance and exports a function `validate_block`. //! //! `validate` accepts as input two `i32` values, representing a pointer/length pair -//! respectively, that encodes [`ValidationParams`]. +//! respectively, that encodes [`ValidationParams`](primitives::ValidationParams). //! //! `validate` returns an `u64` which is a pointer to an `u8` array and its length. -//! The data in the array is expected to be a SCALE encoded [`ValidationResult`]. +//! The data in the array is expected to be a SCALE encoded +//! [`ValidationResult`](primitives::ValidationResult). //! //! ASCII-diagram demonstrating the return data format: //! diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v5/mod.rs index 59fb6c927b2..825d733c5f5 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v5/mod.rs @@ -1009,7 +1009,7 @@ impl OccupiedCore { pub struct ScheduledCore { /// The ID of a para scheduled. pub para_id: Id, - /// DEPRECATED: see: https://github.com/paritytech/polkadot/issues/7575 + /// DEPRECATED: see: /// /// Will be removed in a future version. pub collator: Option, @@ -1735,8 +1735,8 @@ pub struct SessionInfo { /// /// Therefore: /// ```ignore - /// assignment_keys.len() == validators.len() && validators.len() <= discovery_keys.len() - /// ``` + /// assignment_keys.len() == validators.len() && validators.len() <= discovery_keys.len() + /// ``` pub assignment_keys: Vec, /// Validators in shuffled ordering - these are the validator groups as produced /// by the `Scheduler` module for the session and are typically referred to by diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index 884d67222d2..ea331fc2121 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -63,9 +63,9 @@ pub mod v1 { } } - /// [`VersionUncheckedMigrateToV1`] wrapped in a - /// [`frame_support::migrations::VersionedRuntimeUpgrade`], ensuring the migration is only - /// performed when on-chain version is 0. + /// [`MigrateToV1`] wrapped in a + /// [`VersionedRuntimeUpgrade`](frame_support::migrations::VersionedRuntimeUpgrade), ensuring + /// the migration is only performed when on-chain version is 0. #[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedRuntimeUpgrade< 0, diff --git a/polkadot/runtime/common/src/elections.rs b/polkadot/runtime/common/src/elections.rs index 5fd3971180f..340e5c6e4ac 100644 --- a/polkadot/runtime/common/src/elections.rs +++ b/polkadot/runtime/common/src/elections.rs @@ -18,7 +18,8 @@ /// Implements the weight types for the elections module and a specific /// runtime. -/// This macro should not be called directly; use [`impl_runtime_weights`] instead. +/// This macro should not be called directly; use +/// [`impl_runtime_weights`](crate::impl_runtime_weights!) instead. #[macro_export] macro_rules! impl_elections_weights { ($runtime:ident) => { diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 61968e48832..46a9f7d12cd 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/src/lib.rs @@ -100,7 +100,7 @@ parameter_types! { } /// Parameterized slow adjusting fee updated based on -/// https://research.web3.foundation/Polkadot/overview/token-economics#2-slow-adjusting-mechanism +/// pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment< R, TargetBlockFullness, diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 72795a733ea..2520c459591 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -132,7 +132,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A [new] account was created. + /// A new account was created. AccountCreated { who: T::AccountId }, /// Someone's account validity was updated. ValidityUpdated { who: T::AccountId, validity: AccountValidity }, diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index 5a60201e4fa..0c9813d144f 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -263,8 +263,8 @@ pub mod pallet { Pallet::::do_place_order(sender, max_amount, para_id, AllowDeath) } - /// Same as the [`place_order_allow_death`] call , but with a check that placing the order - /// will not reap the account. + /// Same as the [`place_order_allow_death`](Self::place_order_allow_death) call , but with a + /// check that placing the order will not reap the account. /// /// Parameters: /// - `origin`: The sender of the call, funds will be withdrawn from this account. diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index accc01a2b18..fc24ac18ed5 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -94,8 +94,8 @@ pub struct HostConfiguration { /// /// If PVF pre-checking is enabled this should be greater than the maximum number of blocks /// PVF pre-checking can take. Intuitively, this number should be greater than the duration - /// specified by [`pvf_voting_ttl`]. Unlike, [`pvf_voting_ttl`], this parameter uses blocks - /// as a unit. + /// specified by [`pvf_voting_ttl`](Self::pvf_voting_ttl). Unlike, + /// [`pvf_voting_ttl`](Self::pvf_voting_ttl), this parameter uses blocks as a unit. #[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))] pub validation_upgrade_cooldown: BlockNumber, /// The delay, in blocks, after which an upgrade of the validation code is applied. @@ -113,14 +113,15 @@ pub struct HostConfiguration { /// been completed. /// /// Note, there are situations in which `expected_at` in the past. For example, if - /// [`paras_availability_period`] is less than the delay set by - /// this field or if PVF pre-check took more time than the delay. In such cases, the upgrade is - /// further at the earliest possible time determined by [`minimum_validation_upgrade_delay`]. + /// [`paras_availability_period`](Self::paras_availability_period) is less than the delay set + /// by this field or if PVF pre-check took more time than the delay. In such cases, the upgrade + /// is further at the earliest possible time determined by + /// [`minimum_validation_upgrade_delay`](Self::minimum_validation_upgrade_delay). /// /// The rationale for this delay has to do with relay-chain reversions. In case there is an /// invalid candidate produced with the new version of the code, then the relay-chain can - /// revert [`validation_upgrade_delay`] many blocks back and still find the new code in the - /// storage by hash. + /// revert [`validation_upgrade_delay`](Self::validation_upgrade_delay) many blocks back and + /// still find the new code in the storage by hash. /// /// [#4601]: https://github.com/paritytech/polkadot/issues/4601 pub validation_upgrade_delay: BlockNumber, @@ -229,7 +230,8 @@ pub struct HostConfiguration { pub pvf_voting_ttl: SessionIndex, /// The lower bound number of blocks an upgrade can be scheduled. /// - /// Typically, upgrade gets scheduled [`validation_upgrade_delay`] relay-chain blocks after + /// Typically, upgrade gets scheduled + /// [`validation_upgrade_delay`](Self::validation_upgrade_delay) relay-chain blocks after /// the relay-parent of the parablock that signalled the validation code upgrade. However, /// in the case a pre-checking voting was concluded in a longer duration the upgrade will be /// scheduled to the next block. @@ -240,7 +242,8 @@ pub struct HostConfiguration { /// To prevent that, we introduce the minimum number of blocks after which the upgrade can be /// scheduled. This number is controlled by this field. /// - /// This value should be greater than [`paras_availability_period`]. + /// This value should be greater than + /// [`paras_availability_period`](Self::paras_availability_period). pub minimum_validation_upgrade_delay: BlockNumber, } diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index 490c2fa1cd0..bc7491a2c61 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -81,9 +81,9 @@ impl From for SendError { } } -/// An error returned by [`check_processed_downward_messages`] that indicates an acceptance check -/// didn't pass. -pub enum ProcessedDownwardMessagesAcceptanceErr { +/// An error returned by [`Pallet::check_processed_downward_messages`] that indicates an acceptance +/// check didn't pass. +pub(crate) enum ProcessedDownwardMessagesAcceptanceErr { /// If there are pending messages then `processed_downward_messages` should be at least 1, AdvancementRule, /// `processed_downward_messages` should not be greater than the number of pending messages. diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index a3ce6e2d8a3..3a4d2df4b68 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -149,17 +149,17 @@ pub struct HrmpChannel { pub recipient_deposit: Balance, } -/// An error returned by [`check_hrmp_watermark`] that indicates an acceptance criteria check -/// didn't pass. -pub enum HrmpWatermarkAcceptanceErr { +/// An error returned by [`Pallet::check_hrmp_watermark`] that indicates an acceptance criteria +/// check didn't pass. +pub(crate) enum HrmpWatermarkAcceptanceErr { AdvancementRule { new_watermark: BlockNumber, last_watermark: BlockNumber }, AheadRelayParent { new_watermark: BlockNumber, relay_chain_parent_number: BlockNumber }, LandsOnBlockWithNoMessages { new_watermark: BlockNumber }, } -/// An error returned by [`check_outbound_hrmp`] that indicates an acceptance criteria check +/// An error returned by [`Pallet::check_outbound_hrmp`] that indicates an acceptance criteria check /// didn't pass. -pub enum OutboundHrmpAcceptanceErr { +pub(crate) enum OutboundHrmpAcceptanceErr { MoreMessagesThanPermitted { sent: u32, permitted: u32 }, NotSorted { idx: u32 }, NoSuchChannel { idx: u32, channel_id: HrmpChannelId }, diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index e60aac0080c..ceec7d718e8 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -416,10 +416,10 @@ enum AcceptanceCheckErr { OutboundHrmp(hrmp::OutboundHrmpAcceptanceErr), } -/// An error returned by [`check_upward_messages`] that indicates a violation of one of acceptance -/// criteria rules. +/// An error returned by [`Pallet::check_upward_messages`] that indicates a violation of one of +/// acceptance criteria rules. #[cfg_attr(test, derive(PartialEq))] -pub enum UmpAcceptanceCheckErr { +pub(crate) enum UmpAcceptanceCheckErr { /// The maximal number of messages that can be submitted in one batch was exceeded. MoreMessagesThanPermitted { sent: u32, permitted: u32 }, /// The maximal size of a single message was exceeded. diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index 056eef35426..64365f17b7e 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -63,8 +63,6 @@ pub trait FeeTracker { } /// Schedule a para to be initialized at the start of the next session with the given genesis data. -/// -/// See [`paras::Pallet::schedule_para_initialize`] for more details. pub fn schedule_para_initialize( id: ParaId, genesis: paras::ParaGenesisArgs, @@ -73,8 +71,6 @@ pub fn schedule_para_initialize( } /// Schedule a para to be cleaned up at the start of the next session. -/// -/// See [`paras::Pallet::schedule_para_cleanup`] for more details. pub fn schedule_para_cleanup(id: primitives::Id) -> Result<(), ()> { >::schedule_para_cleanup(id).map_err(|_| ()) } @@ -90,8 +86,6 @@ pub fn schedule_parachain_downgrade(id: ParaId) -> Result<(), } /// Schedules a validation code upgrade to a parachain with the given id. -/// -/// This simply calls [`crate::paras::Pallet::schedule_code_upgrade_external`]. pub fn schedule_code_upgrade( id: ParaId, new_code: ValidationCode, @@ -100,8 +94,6 @@ pub fn schedule_code_upgrade( } /// Sets the current parachain head with the given id. -/// -/// This simply calls [`crate::paras::Pallet::set_current_head`]. pub fn set_current_head(id: ParaId, new_head: HeadData) { paras::Pallet::::set_current_head(id, new_head) } diff --git a/polkadot/runtime/parachains/src/paras_inherent/misc.rs b/polkadot/runtime/parachains/src/paras_inherent/misc.rs index e77b26b9e12..dac9e6e256d 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/misc.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/misc.rs @@ -40,7 +40,7 @@ impl IndexedRetain for Vec { } /// Helper trait until `is_sorted_by` is stabilized. -/// TODO: https://github.com/rust-lang/rust/issues/53485 +/// TODO: pub trait IsSortedBy { fn is_sorted_by(self, cmp: F) -> bool where diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs index cd157968973..bac1268f53b 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs @@ -345,7 +345,7 @@ pub fn on_chain_votes() -> Option>::on_chain_votes() } -/// Submits an PVF pre-checking vote. See [`paras::Pallet::submit_pvf_check_statement`]. +/// Submits an PVF pre-checking vote. pub fn submit_pvf_check_statement( stmt: PvfCheckStatement, signature: ValidatorSignature, @@ -353,8 +353,7 @@ pub fn submit_pvf_check_statement( >::submit_pvf_check_statement(stmt, signature) } -/// Returns the list of all PVF code hashes that require pre-checking. See -/// [`paras::Pallet::pvfs_require_precheck`]. +/// Returns the list of all PVF code hashes that require pre-checking. pub fn pvfs_require_precheck() -> Vec { >::pvfs_require_precheck() } diff --git a/polkadot/utils/staking-miner/src/opts.rs b/polkadot/utils/staking-miner/src/opts.rs index ecffe453101..4cf4d0a7651 100644 --- a/polkadot/utils/staking-miner/src/opts.rs +++ b/polkadot/utils/staking-miner/src/opts.rs @@ -88,10 +88,10 @@ pub(crate) struct MonitorConfig { /// /// `--submission-strategy always`: always submit. /// - /// `--submission-strategy "percent-better "`: submit if the submission is `n` percent + /// `--submission-strategy "percent-better percent"`: submit if the submission is `n` percent /// better. /// - /// `--submission-strategy "no-worse-than "`: submit if submission is no more than + /// `--submission-strategy "no-worse-than percent"`: submit if submission is no more than /// `n` percent worse. #[clap(long, default_value = "if-leading")] pub submission_strategy: SubmissionStrategy, @@ -190,8 +190,8 @@ pub(crate) enum Solver { /// Possible options: /// * --submission-strategy if-leading: only submit if leading /// * --submission-strategy always: always submit -/// * --submission-strategy "percent-better ": submit if submission is `n` percent better. -/// * --submission-strategy "no-worse-than": submit if submission is no more than `n` +/// * --submission-strategy "percent-better percent": submit if submission is `n` percent better. +/// * --submission-strategy "no-worse-than percent": submit if submission is no more than `n` /// percent worse. impl FromStr for SubmissionStrategy { type Err = String; diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index e36d26e425b..ae0f9ee3403 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -193,7 +193,7 @@ pub struct LocatableAssetId { pub location: MultiLocation, } -/// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAsset`] +/// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`] /// value using a fixed `Location` for the `location` field. pub struct FixedLocation(sp_std::marker::PhantomData); impl, AssetKind: Into> Convert diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index 8130d173293..808cf5521d3 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -26,7 +26,7 @@ use sp_std::{fmt::Debug, marker::PhantomData}; use sp_weights::{Weight, WeightMeter}; use xcm::prelude::*; -/// A message processor that delegates execution to an [`XcmExecutor`]. +/// A message processor that delegates execution to an `XcmExecutor`. pub struct ProcessXcmMessage( PhantomData<(MessageOrigin, XcmExecutor, Call)>, ); diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index 1a941f6cb3f..c01f0f3926a 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -22,7 +22,6 @@ use crate::{ Def, }, }; -use itertools::Itertools; use quote::ToTokens; use std::{collections::HashMap, ops::IndexMut}; use syn::spanned::Spanned; @@ -443,11 +442,14 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { let cfg_attrs = &storage.cfg_attrs; - // If the storage item is public, just link to it rather than copy-pasting the docs. + // If the storage item is public, link it and otherwise just mention it. + // + // We can not just copy the docs from a non-public type as it may links to internal + // types which makes the compiler very unhappy :( let getter_doc_line = if matches!(storage.vis, syn::Visibility::Public(_)) { format!("An auto-generated getter for [`{}`].", storage.ident) } else { - storage.docs.iter().map(|d| d.into_token_stream().to_string()).join("\n") + format!("An auto-generated getter for `{}`.", storage.ident) }; match &storage.metadata { -- GitLab From ebf6e66b026abcb9dda95d271be5d21192bd5698 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 29 Aug 2023 21:30:18 +0200 Subject: [PATCH 013/633] Revive Dependabot (#1264) Closes https://github.com/paritytech/polkadot-sdk/issues/1174 Configures dependabot to run daily but group some dependencies together that I assume to be sember abiding. Signed-off-by: Oliver Tale-Yazdi --- .github/dependabot.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..3277a6e4607 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +version: 2 +updates: + # Update github actions: + - package-ecosystem: github-actions + directory: '/' + labels: ["A1-insubstantial", "R0-silent"] + schedule: + interval: daily + # Update Rust dependencies: + - package-ecosystem: "cargo" + directory: "/" + labels: ["A1-insubstantial", "R0-silent"] + schedule: + interval: "daily" + groups: + # We assume these crates to be semver abiding and can therefore group them together. + known_good_semver: + patterns: + - "syn" + - "quote" + - "log" + - "paste" + - "*serde*" + - "clap" + update-types: + - "minor" + - "patch" -- GitLab From ee78e3a2a6f2d4bd05de9b925a34cf53f23baf1d Mon Sep 17 00:00:00 2001 From: Maksym H <1177472+mordamax@users.noreply.github.com> Date: Tue, 29 Aug 2023 20:32:24 +0100 Subject: [PATCH 014/633] fix licenses (#1267) --- .github/workflows/check-licenses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index e0bdf908a16..e213acd4988 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - repo: [polkadot, substrate, cumulus] + repo: [polkadot] steps: - name: Checkout sources uses: actions/checkout@v3 -- GitLab From 1c7ef1f23283bf4878410d4bc2d9c643fa34a279 Mon Sep 17 00:00:00 2001 From: Lulu Date: Tue, 29 Aug 2023 21:40:33 +0200 Subject: [PATCH 015/633] Set test crates to nopublish (#1240) * Set test crates to nopublish * Don't publish more crates * Set even more crates to nopublish --------- Co-authored-by: Oliver Tale-Yazdi --- cumulus/bridges/primitives/test-utils/Cargo.toml | 1 + cumulus/parachain-template/node/Cargo.toml | 1 + .../emulated/assets/asset-hub-kusama/Cargo.toml | 1 + .../emulated/assets/asset-hub-polkadot/Cargo.toml | 1 + .../emulated/assets/asset-hub-westend/Cargo.toml | 1 + .../emulated/bridges/bridge-hub-rococo/Cargo.toml | 1 + .../emulated/collectives/collectives-polkadot/Cargo.toml | 1 + cumulus/parachains/integration-tests/emulated/common/Cargo.toml | 1 + cumulus/parachains/runtimes/assets/test-utils/Cargo.toml | 1 + cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml | 1 + cumulus/parachains/runtimes/test-utils/Cargo.toml | 1 + cumulus/parachains/runtimes/testing/penpal/Cargo.toml | 1 + cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml | 1 + cumulus/test/client/Cargo.toml | 1 + cumulus/test/relay-sproof-builder/Cargo.toml | 1 + cumulus/test/relay-validation-worker-provider/Cargo.toml | 1 + cumulus/test/runtime/Cargo.toml | 1 + cumulus/test/service/Cargo.toml | 1 + cumulus/xcm/xcm-emulator/Cargo.toml | 1 + polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 1 + 20 files changed, 20 insertions(+) diff --git a/cumulus/bridges/primitives/test-utils/Cargo.toml b/cumulus/bridges/primitives/test-utils/Cargo.toml index c379c6792cb..fc6e5859141 100644 --- a/cumulus/bridges/primitives/test-utils/Cargo.toml +++ b/cumulus/bridges/primitives/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] bp-header-chain = { path = "../header-chain", default-features = false } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index d85fd5a6178..f4fdfc64fac 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -8,6 +8,7 @@ homepage = "https://substrate.io" repository.workspace = true edition.workspace = true build = "build.rs" +publish = false [dependencies] clap = { version = "4.3.24", features = ["derive"] } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 6c3cf42ff35..7c870e0220c 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Asset Hub Kusama runtime integration tests with xcm-emulator" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } 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 index e3c49d4f200..174091d881b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true 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 } 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 548c9a5f407..798ba7d3f3a 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 @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Asset Hub Westend runtime integration tests with xcm-emulator" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } 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 c4aba4f9110..e81e7a19489 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 @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index 1d0069dfd00..accb04db7f3 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true 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 } diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 47c5f96fd80..e14969deeab 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Common resources for integration testing with xcm-emulator" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 46b82b3ebb2..baf66a15872 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Test utils for Asset Hub runtimes." +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 147166f2168..18a8d56a60e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Utils for BridgeHub testing" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 94b73d5e39d..76ce2b9907e 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Utils for Runtimes testing" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index acaaadf04dd..cd36927afec 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -7,6 +7,7 @@ license = "Unlicense" homepage = "https://substrate.io" repository.workspace = true edition.workspace = true +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 6e9f9f3039c..361f7759199 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Simple runtime used by the rococo parachain(s)" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 5d8c6643c3c..4e07be3368e 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-test-client" version = "0.1.0" authors.workspace = true edition.workspace = true +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index e044b92f7c4..c987a2b66c9 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-test-relay-sproof-builder" version = "0.1.0" authors.workspace = true edition.workspace = true +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-validation-worker-provider/Cargo.toml b/cumulus/test/relay-validation-worker-provider/Cargo.toml index eaa1ce8dc47..b7c59e83299 100644 --- a/cumulus/test/relay-validation-worker-provider/Cargo.toml +++ b/cumulus/test/relay-validation-worker-provider/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true build = "build.rs" +publish = false [dependencies] diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 9fe4c55bbd7..dbfe9f46b1b 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-test-runtime" version = "0.1.0" authors.workspace = true edition.workspace = true +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index ad007c509ff..2869af94a77 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-test-service" version = "0.1.0" authors.workspace = true edition.workspace = true +publish = false [[bin]] name = "test-parachain" diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 8560b6401f7..58666ec39ec 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -4,6 +4,7 @@ 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/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index f585d506456..bfc96656bcf 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -5,6 +5,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -- GitLab From 844eda7626d1b60424563ad09ce2ad44e7db7e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 29 Aug 2023 22:42:54 +0200 Subject: [PATCH 016/633] pallet-scheduler: Send `CallUnavailable` event if the call isn't present (#1161) The event was already send before, but it was done at the wrong position. The pull request all changes the `execute_dispatch` signature to highlight that there is only one error type. Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Javier Viola --- substrate/frame/scheduler/src/lib.rs | 27 +++++++++--------- substrate/frame/scheduler/src/tests.rs | 39 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 3538331bbd4..f4b5521755b 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -1096,7 +1096,14 @@ impl Pallet { let (call, lookup_len) = match T::Preimages::peek(&task.call) { Ok(c) => c, - Err(_) => return Err((Unavailable, Some(task))), + Err(_) => { + Self::deposit_event(Event::CallUnavailable { + task: (when, agenda_index), + id: task.maybe_id, + }); + + return Err((Unavailable, Some(task))) + }, }; let _ = weight.try_consume(T::WeightInfo::service_task( @@ -1106,15 +1113,7 @@ impl Pallet { )); match Self::execute_dispatch(weight, task.origin.clone(), call) { - Err(Unavailable) => { - debug_assert!(false, "Checked to exist with `peek`"); - Self::deposit_event(Event::CallUnavailable { - task: (when, agenda_index), - id: task.maybe_id, - }); - Err((Unavailable, Some(task))) - }, - Err(Overweight) if is_first => { + Err(()) if is_first => { T::Preimages::drop(&task.call); Self::deposit_event(Event::PermanentlyOverweight { task: (when, agenda_index), @@ -1122,7 +1121,7 @@ impl Pallet { }); Err((Unavailable, Some(task))) }, - Err(Overweight) => Err((Overweight, Some(task))), + Err(()) => Err((Overweight, Some(task))), Ok(result) => { Self::deposit_event(Event::Dispatched { task: (when, agenda_index), @@ -1162,11 +1161,13 @@ impl Pallet { /// /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the /// call itself). + /// + /// Returns an error if the call is overweight. fn execute_dispatch( weight: &mut WeightMeter, origin: T::PalletsOrigin, call: ::RuntimeCall, - ) -> Result { + ) -> Result { let base_weight = match origin.as_system_ref() { Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(), _ => T::WeightInfo::execute_dispatch_unsigned(), @@ -1176,7 +1177,7 @@ impl Pallet { let max_weight = base_weight.saturating_add(call_weight); if !weight.can_consume(max_weight) { - return Err(Overweight) + return Err(()) } let dispatch_origin = origin.into(); diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 477df5579dc..25a60732e06 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1878,3 +1878,42 @@ fn reschedule_named_last_task_removes_agenda() { assert!(Agenda::::get(when).len() == 0); }); } + +/// Ensures that an unvailable call sends an event. +#[test] +fn unavailable_call_is_detected() { + use frame_support::traits::schedule::v3::Named; + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); + let hash = ::Hashing::hash_of(&call); + let len = call.using_encoded(|x| x.len()) as u32; + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let bound = Bounded::Lookup { hash, len }; + + let name = [1u8; 32]; + + // Schedule a call. + let _address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + // Ensure the preimage isn't available + assert!(!Preimage::have(&bound)); + + // Executes in block 4. + run_to_block(4); + + assert_eq!( + System::events().last().unwrap().event, + crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into() + ); + }); +} -- GitLab From b4ee6f2aa9b13086f9324fbb6407642d9a2fab7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:20:35 +1000 Subject: [PATCH 017/633] Bump chrono from 0.4.26 to 0.4.27 (#1286) Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.26 to 0.4.27. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.26...v0.4.27) --- updated-dependencies: - dependency-name: chrono dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- substrate/client/cli/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/tracing/Cargo.toml | 2 +- substrate/utils/frame/generate-bags/Cargo.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40aaf2d0d9e..781e464d125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2366,9 +2366,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2376,7 +2376,7 @@ dependencies = [ "num-traits", "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 7b827d897e0..6eebe095729 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" -chrono = "0.4.10" +chrono = "0.4.27" clap = { version = "4.2.5", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 5817dc207a1..452715c449a 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -chrono = "0.4.19" +chrono = "0.4.27" futures = "0.3.21" libp2p = { version = "0.51.3", features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"] } log = "0.4.17" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index 1cbb50f6d83..f2e7cd11627 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" atty = "0.2.13" -chrono = "0.4.19" +chrono = "0.4.27" lazy_static = "1.4.0" libc = "0.2.121" log = { version = "0.4.17" } diff --git a/substrate/utils/frame/generate-bags/Cargo.toml b/substrate/utils/frame/generate-bags/Cargo.toml index 471f18b4ab4..ac22197c5ac 100644 --- a/substrate/utils/frame/generate-bags/Cargo.toml +++ b/substrate/utils/frame/generate-bags/Cargo.toml @@ -17,5 +17,5 @@ pallet-staking = { path = "../../../frame/staking" } sp-staking = { path = "../../../primitives/staking" } # third party -chrono = { version = "0.4.19" } +chrono = { version = "0.4.27" } num-format = "0.4.3" -- GitLab From 2f49252bcdb450c36f83a6dacdececc7b5d8e32c Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 30 Aug 2023 14:28:03 +1000 Subject: [PATCH 018/633] Rename `VersionedRuntimeUpgrade` to `VersionedMigration` (#1187) * rename VersionedRuntimeUpgrade to VersionedMigration * doc lint * rename test filename --------- Co-authored-by: Oliver Tale-Yazdi --- .../common/src/assigned_slots/migration.rs | 6 ++--- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/src/migration.rs | 6 ++--- substrate/frame/society/Cargo.toml | 2 +- substrate/frame/society/src/migrations.rs | 7 +++-- substrate/frame/support/src/migrations.rs | 26 +++++++++---------- substrate/frame/support/src/traits/hooks.rs | 2 +- ...time_upgrade.rs => versioned_migration.rs} | 12 ++++----- 8 files changed, 31 insertions(+), 32 deletions(-) rename substrate/frame/support/test/tests/{versioned_runtime_upgrade.rs => versioned_migration.rs} (94%) diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index ea331fc2121..6a84ea3ccc4 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -64,10 +64,10 @@ pub mod v1 { } /// [`MigrateToV1`] wrapped in a - /// [`VersionedRuntimeUpgrade`](frame_support::migrations::VersionedRuntimeUpgrade), ensuring - /// the migration is only performed when on-chain version is 0. + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. #[cfg(feature = "experimental")] - pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedRuntimeUpgrade< + pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, MigrateToV1, diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 63a616281d8..f98741d01bd 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -32,7 +32,7 @@ xcm-builder = { path = "../xcm-builder" } [features] default = [ "std" ] -# Enable `VersionedRuntimeUpgrade` for the migrations that is currently still experimental. +# Enable `VersionedMigration` for the migrations using the experimental feature. experimental = [ "frame-support/experimental" ] std = [ "bounded-collections/std", diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 08809f0d2f2..e28ca56563c 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -63,10 +63,10 @@ pub mod v1 { /// Version checked migration to v1. /// - /// Wrapped in VersionedRuntimeUpgrade so the pre/post checks don't begin failing after the - /// upgrade is enacted on-chain. + /// Wrapped in [`frame_support::migrations::VersionedMigration`] so the pre/post checks don't + /// begin failing after the upgrade is enacted on-chain. #[cfg(feature = "experimental")] - pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedRuntimeUpgrade< + pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, VersionUncheckedMigrateToV1, diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index c112e2bbb8c..1510e17b8b5 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -34,7 +34,7 @@ sp-io = { path = "../../primitives/io" } [features] default = [ "std" ] -# Enable `VersionedRuntimeUpgrade` for the migrations that is currently still experimental. +# Enable `VersionedMigration` for migrations using this feature. experimental = [ "frame-support/experimental" ] std = [ "codec/std", diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index 4685167dcbc..b50b0e088a6 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -93,12 +93,11 @@ impl< } } -/// [`VersionUncheckedMigrateToV2`] wrapped in a -/// [`frame_support::migrations::VersionedRuntimeUpgrade`], ensuring the migration is only performed -/// when on-chain version is 0. +/// [`VersionUncheckedMigrateToV2`] wrapped in a [`frame_support::migrations::VersionedMigration`], +/// ensuring the migration is only performed when on-chain version is 0. #[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV2 = - frame_support::migrations::VersionedRuntimeUpgrade< + frame_support::migrations::VersionedMigration< 0, 2, VersionUncheckedMigrateToV2, diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 19eec194a76..6fc1834f01a 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -28,9 +28,9 @@ use sp_std::marker::PhantomData; /// /// Make it easier to write versioned runtime upgrades. /// -/// [`VersionedRuntimeUpgrade`] allows developers to write migrations without worrying about -/// checking and setting storage versions. Instead, the developer wraps their migration in this -/// struct which takes care of version handling using best practices. +/// [`VersionedMigration`] allows developers to write migrations without worrying about checking and +/// setting storage versions. Instead, the developer wraps their migration in this struct which +/// takes care of version handling using best practices. /// /// It takes 5 type parameters: /// - `From`: The version being upgraded from. @@ -39,11 +39,11 @@ use sp_std::marker::PhantomData; /// - `Pallet`: The Pallet being upgraded. /// - `Weight`: The runtime's RuntimeDbWeight implementation. /// -/// When a [`VersionedRuntimeUpgrade`] `on_runtime_upgrade`, `pre_upgrade`, or `post_upgrade` -/// method is called, the on-chain version of the pallet is compared to `From`. If they match, the -/// `Inner` equivalent is called and the pallets on-chain version is set to `To` after the -/// migration. Otherwise, a warning is logged notifying the developer that the upgrade was a noop -/// and should probably be removed. +/// When a [`VersionedMigration`] `on_runtime_upgrade`, `pre_upgrade`, or `post_upgrade` method is +/// called, the on-chain version of the pallet is compared to `From`. If they match, the `Inner` +/// equivalent is called and the pallets on-chain version is set to `To` after the migration. +/// Otherwise, a warning is logged notifying the developer that the upgrade was a noop and should +/// probably be removed. /// /// ### Examples /// ```ignore @@ -54,7 +54,7 @@ use sp_std::marker::PhantomData; /// } /// /// pub type VersionCheckedMigrateV5ToV6 = -/// VersionedRuntimeUpgrade< +/// VersionedMigration< /// 5, /// 6, /// VersionUncheckedMigrateV5ToV6, @@ -70,7 +70,7 @@ use sp_std::marker::PhantomData; /// ); /// ``` #[cfg(feature = "experimental")] -pub struct VersionedRuntimeUpgrade { +pub struct VersionedMigration { _marker: PhantomData<(Inner, Pallet, Weight)>, } @@ -85,7 +85,7 @@ pub enum VersionedPostUpgradeData { Noop, } -/// Implementation of the `OnRuntimeUpgrade` trait for `VersionedRuntimeUpgrade`. +/// Implementation of the `OnRuntimeUpgrade` trait for `VersionedMigration`. /// /// Its main function is to perform the runtime upgrade in `on_runtime_upgrade` only if the on-chain /// version of the pallets storage matches `From`, and after the upgrade set the on-chain storage to @@ -98,7 +98,7 @@ impl< Inner: crate::traits::OnRuntimeUpgrade, Pallet: GetStorageVersion + PalletInfoAccess, DbWeight: Get, - > crate::traits::OnRuntimeUpgrade for VersionedRuntimeUpgrade + > crate::traits::OnRuntimeUpgrade for VersionedMigration { /// Executes pre_upgrade if the migration will run, and wraps the pre_upgrade bytes in /// [`VersionedPostUpgradeData`] before passing them to post_upgrade, so it knows whether the @@ -158,7 +158,7 @@ impl< ) -> Result<(), sp_runtime::TryRuntimeError> { use codec::DecodeAll; match ::decode_all(&mut &versioned_post_upgrade_data_bytes[..]) - .map_err(|_| "VersionedRuntimeUpgrade post_upgrade failed to decode PreUpgradeData")? + .map_err(|_| "VersionedMigration post_upgrade failed to decode PreUpgradeData")? { VersionedPostUpgradeData::MigrationExecuted(inner_bytes) => Inner::post_upgrade(inner_bytes), diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index 4453a3fb755..6acecb8928d 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -359,7 +359,7 @@ pub trait Hooks { /// done. This is helpful to prevent accidental repetitive execution of this hook, which can be /// catastrophic. /// - /// Alternatively, `migrations::VersionedRuntimeUpgrade` can be used to assist with + /// Alternatively, [`frame_support::migrations::VersionedMigration`] can be used to assist with /// this. /// /// ## Implementation Note: Runtime Level Migration diff --git a/substrate/frame/support/test/tests/versioned_runtime_upgrade.rs b/substrate/frame/support/test/tests/versioned_migration.rs similarity index 94% rename from substrate/frame/support/test/tests/versioned_runtime_upgrade.rs rename to substrate/frame/support/test/tests/versioned_migration.rs index 93d87df8ca1..a0766f6bec2 100644 --- a/substrate/frame/support/test/tests/versioned_runtime_upgrade.rs +++ b/substrate/frame/support/test/tests/versioned_migration.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for VersionedRuntimeUpgrade +//! Tests for [`VersionedMigration`] #![cfg(all(feature = "experimental", feature = "try-runtime"))] use frame_support::{ construct_runtime, derive_impl, - migrations::VersionedRuntimeUpgrade, + migrations::VersionedMigration, parameter_types, traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion}, weights::constants::RocksDbWeight, @@ -90,7 +90,7 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { ext } -/// A dummy migration for testing the `VersionedRuntimeUpgrade` trait. +/// A dummy migration for testing the `VersionedMigration` trait. /// Sets SomeStorage to S. struct SomeUnversionedMigration(sp_std::marker::PhantomData); @@ -124,13 +124,13 @@ impl OnRuntimeUpgrade for SomeUnversioned } type VersionedMigrationV0ToV1 = - VersionedRuntimeUpgrade<0, 1, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; + VersionedMigration<0, 1, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; type VersionedMigrationV1ToV2 = - VersionedRuntimeUpgrade<1, 2, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; + VersionedMigration<1, 2, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; type VersionedMigrationV2ToV4 = - VersionedRuntimeUpgrade<2, 4, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; + VersionedMigration<2, 4, SomeUnversionedMigration, DummyPallet, RocksDbWeight>; #[test] fn successful_upgrade_path() { -- GitLab From d81c8cbaa7088d13d6a8a703a7347bd6b76b56a9 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 30 Aug 2023 09:37:13 +0200 Subject: [PATCH 019/633] [ci] Fix buildah and reorder test-doc dag (#1275) --- .gitlab-ci.yml | 2 +- .gitlab/pipeline/test.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c6fbc17a182..9e7346601ba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ workflow: variables: CI_IMAGE: "paritytech/ci-unified:bullseye-1.70.0-2023-05-23-v20230706" - BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" + # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" RUSTY_CACHIER_SINGLE_BRANCH: master diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index a83ab8c2bfa..dbe8193bc0f 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -147,7 +147,10 @@ test-doc: extends: - .docker-env - .common-refs - - .run-immediately + # DAG + needs: + - job: test-rustdoc + artifacts: false variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. @@ -160,10 +163,7 @@ test-rustdoc: extends: - .docker-env - .common-refs - # DAG - needs: - - job: test-doc - artifacts: false + - .run-immediately variables: SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings" -- GitLab From cbd745c846719acb73e60d91c5bd461b2572b4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 30 Aug 2023 09:48:29 +0200 Subject: [PATCH 020/633] Fix `node-metrics` test (#1287) --- .gitlab/pipeline/test.yml | 2 + polkadot/scripts/ci/changelog/.gitignore | 4 - polkadot/scripts/ci/changelog/Gemfile | 23 - polkadot/scripts/ci/changelog/Gemfile.lock | 84 ---- polkadot/scripts/ci/changelog/README.md | 80 ---- polkadot/scripts/ci/changelog/bin/changelog | 105 ----- .../scripts/ci/changelog/digests/.gitignore | 1 - .../scripts/ci/changelog/digests/.gitkeep | 0 .../scripts/ci/changelog/lib/changelog.rb | 38 -- .../changelog/templates/_free_notes.md.tera | 10 - .../ci/changelog/templates/change.md.tera | 43 -- .../ci/changelog/templates/changes.md.tera | 15 - .../changelog/templates/changes_api.md.tera | 17 - .../templates/changes_client.md.tera | 17 - .../changelog/templates/changes_misc.md.tera | 42 -- .../templates/changes_runtime.md.tera | 19 - .../ci/changelog/templates/compiler.md.tera | 7 - .../ci/changelog/templates/debug.md.tera | 8 - .../changelog/templates/docker_image.md.tera | 11 - .../changelog/templates/full_pr_list.md.tera | 16 - .../templates/global_priority.md.tera | 22 - .../changelog/templates/high_priority.md.tera | 38 -- .../templates/host_functions-list.md.tera | 12 - .../templates/host_functions.md.tera | 44 -- .../changelog/templates/migrations-db.md.tera | 30 -- .../templates/migrations-runtime.md.tera | 29 -- .../changelog/templates/pre_release.md.tera | 11 - .../ci/changelog/templates/runtime.md.tera | 28 -- .../ci/changelog/templates/runtimes.md.tera | 19 - .../ci/changelog/templates/template.md.tera | 37 -- .../scripts/ci/changelog/test/test_basic.rb | 23 - polkadot/scripts/ci/common/lib.sh | 265 ----------- .../adder-collator/build-injected.sh | 13 - .../dockerfiles/adder-collator/test-build.sh | 23 - .../ci/dockerfiles/binary_injected.Dockerfile | 48 -- .../scripts/ci/dockerfiles/build-injected.sh | 92 ---- polkadot/scripts/ci/dockerfiles/entrypoint.sh | 18 - .../ci/dockerfiles/malus/build-injected.sh | 14 - .../ci/dockerfiles/malus/test-build.sh | 19 - .../scripts/ci/dockerfiles/polkadot/README.md | 9 - .../ci/dockerfiles/polkadot/build-injected.sh | 13 - .../polkadot/docker-compose-local.yml | 50 -- .../dockerfiles/polkadot/docker-compose.yml | 22 - .../polkadot/polkadot_Dockerfile.README.md | 7 - .../polkadot/polkadot_builder.Dockerfile | 36 -- .../polkadot_injected_debian.Dockerfile | 53 --- .../ci/dockerfiles/polkadot/test-build.sh | 18 - .../ci/dockerfiles/staking-miner/README.md | 37 -- .../staking-miner/build-injected.sh | 13 - .../ci/dockerfiles/staking-miner/build.sh | 13 - .../staking-miner_Dockerfile.README.md | 3 - .../staking-miner_builder.Dockerfile | 43 -- .../dockerfiles/staking-miner/test-build.sh | 18 - polkadot/scripts/ci/github/check-rel-br | 127 ----- polkadot/scripts/ci/github/check_bootnodes.sh | 71 --- polkadot/scripts/ci/github/check_labels.sh | 75 --- .../scripts/ci/github/check_new_bootnodes.sh | 42 -- .../scripts/ci/github/check_weights_swc.sh | 20 - .../ci/github/extrinsic-ordering-filter.sh | 55 --- .../ci/github/generate_release_text.rb | 148 ------ polkadot/scripts/ci/github/lib.rb | 10 - .../scripts/ci/github/polkadot_release.erb | 42 -- polkadot/scripts/ci/github/run_fuzzer.sh | 13 - .../ci/github/verify_updated_weights.sh | 56 --- .../ci/gitlab/check_extrinsics_ordering.sh | 82 ---- polkadot/scripts/ci/gitlab/check_runtime.sh | 204 -------- polkadot/scripts/ci/gitlab/lingua.dic | 344 -------------- polkadot/scripts/ci/gitlab/pipeline/build.yml | 174 ------- polkadot/scripts/ci/gitlab/pipeline/check.yml | 136 ------ .../scripts/ci/gitlab/pipeline/publish.yml | 276 ----------- .../ci/gitlab/pipeline/short-benchmarks.yml | 27 -- polkadot/scripts/ci/gitlab/pipeline/test.yml | 119 ----- .../scripts/ci/gitlab/pipeline/weights.yml | 39 -- .../scripts/ci/gitlab/pipeline/zombienet.yml | 444 ------------------ polkadot/scripts/ci/gitlab/prettier.sh | 6 - polkadot/scripts/ci/gitlab/spellcheck.toml | 34 -- .../ci/gitlab/test_deterministic_wasm.sh | 15 - .../scripts/ci/run_benches_for_runtime.sh | 76 --- 78 files changed, 2 insertions(+), 4295 deletions(-) delete mode 100644 polkadot/scripts/ci/changelog/.gitignore delete mode 100644 polkadot/scripts/ci/changelog/Gemfile delete mode 100644 polkadot/scripts/ci/changelog/Gemfile.lock delete mode 100644 polkadot/scripts/ci/changelog/README.md delete mode 100755 polkadot/scripts/ci/changelog/bin/changelog delete mode 100644 polkadot/scripts/ci/changelog/digests/.gitignore delete mode 100644 polkadot/scripts/ci/changelog/digests/.gitkeep delete mode 100644 polkadot/scripts/ci/changelog/lib/changelog.rb delete mode 100644 polkadot/scripts/ci/changelog/templates/_free_notes.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/change.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/changes.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/changes_api.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/changes_client.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/changes_misc.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/changes_runtime.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/compiler.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/debug.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/docker_image.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/full_pr_list.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/global_priority.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/high_priority.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/host_functions-list.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/host_functions.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/migrations-db.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/migrations-runtime.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/pre_release.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/runtime.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/runtimes.md.tera delete mode 100644 polkadot/scripts/ci/changelog/templates/template.md.tera delete mode 100644 polkadot/scripts/ci/changelog/test/test_basic.rb delete mode 100755 polkadot/scripts/ci/common/lib.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/adder-collator/build-injected.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/adder-collator/test-build.sh delete mode 100644 polkadot/scripts/ci/dockerfiles/binary_injected.Dockerfile delete mode 100755 polkadot/scripts/ci/dockerfiles/build-injected.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/entrypoint.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/malus/build-injected.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/malus/test-build.sh delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/README.md delete mode 100755 polkadot/scripts/ci/dockerfiles/polkadot/build-injected.sh delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/docker-compose-local.yml delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/docker-compose.yml delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile delete mode 100644 polkadot/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile delete mode 100755 polkadot/scripts/ci/dockerfiles/polkadot/test-build.sh delete mode 100644 polkadot/scripts/ci/dockerfiles/staking-miner/README.md delete mode 100755 polkadot/scripts/ci/dockerfiles/staking-miner/build-injected.sh delete mode 100755 polkadot/scripts/ci/dockerfiles/staking-miner/build.sh delete mode 100644 polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md delete mode 100644 polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile delete mode 100755 polkadot/scripts/ci/dockerfiles/staking-miner/test-build.sh delete mode 100755 polkadot/scripts/ci/github/check-rel-br delete mode 100755 polkadot/scripts/ci/github/check_bootnodes.sh delete mode 100755 polkadot/scripts/ci/github/check_labels.sh delete mode 100755 polkadot/scripts/ci/github/check_new_bootnodes.sh delete mode 100755 polkadot/scripts/ci/github/check_weights_swc.sh delete mode 100755 polkadot/scripts/ci/github/extrinsic-ordering-filter.sh delete mode 100644 polkadot/scripts/ci/github/generate_release_text.rb delete mode 100644 polkadot/scripts/ci/github/lib.rb delete mode 100644 polkadot/scripts/ci/github/polkadot_release.erb delete mode 100755 polkadot/scripts/ci/github/run_fuzzer.sh delete mode 100755 polkadot/scripts/ci/github/verify_updated_weights.sh delete mode 100755 polkadot/scripts/ci/gitlab/check_extrinsics_ordering.sh delete mode 100755 polkadot/scripts/ci/gitlab/check_runtime.sh delete mode 100644 polkadot/scripts/ci/gitlab/lingua.dic delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/build.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/check.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/publish.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/short-benchmarks.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/test.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/weights.yml delete mode 100644 polkadot/scripts/ci/gitlab/pipeline/zombienet.yml delete mode 100755 polkadot/scripts/ci/gitlab/prettier.sh delete mode 100644 polkadot/scripts/ci/gitlab/spellcheck.toml delete mode 100755 polkadot/scripts/ci/gitlab/test_deterministic_wasm.sh delete mode 100755 polkadot/scripts/ci/run_benches_for_runtime.sh diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index dbe8193bc0f..9dc14d7f163 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -196,6 +196,8 @@ test-node-metrics: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: + # Build the required workers. + - cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker --profile testnet --verbose --locked - mkdir -p artifacts - time cargo test --profile testnet --locked diff --git a/polkadot/scripts/ci/changelog/.gitignore b/polkadot/scripts/ci/changelog/.gitignore deleted file mode 100644 index 4fbcc523b04..00000000000 --- a/polkadot/scripts/ci/changelog/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -changelog.md -*.json -release*.md -.env diff --git a/polkadot/scripts/ci/changelog/Gemfile b/polkadot/scripts/ci/changelog/Gemfile deleted file mode 100644 index 46b058e3c50..00000000000 --- a/polkadot/scripts/ci/changelog/Gemfile +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -source 'https://rubygems.org' - -git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } - -gem 'octokit', '~> 4' - -gem 'git_diff_parser', '~> 3' - -gem 'toml', '~> 0.3.0' - -gem 'rake', group: :dev - -gem 'optparse', '~> 0.1.1' - -gem 'logger', '~> 1.4' - -gem 'changelogerator', '0.10.1' - -gem 'test-unit', group: :dev - -gem 'rubocop', group: :dev, require: false diff --git a/polkadot/scripts/ci/changelog/Gemfile.lock b/polkadot/scripts/ci/changelog/Gemfile.lock deleted file mode 100644 index 422aa3a8844..00000000000 --- a/polkadot/scripts/ci/changelog/Gemfile.lock +++ /dev/null @@ -1,84 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - ast (2.4.2) - changelogerator (0.10.1) - git_diff_parser (~> 3) - octokit (~> 4) - faraday (1.8.0) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0.1) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - git_diff_parser (3.2.0) - logger (1.4.4) - multipart-post (2.1.1) - octokit (4.21.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) - optparse (0.1.1) - parallel (1.21.0) - parser (3.0.2.0) - ast (~> 2.4.1) - parslet (2.0.0) - power_assert (2.0.1) - public_suffix (4.0.6) - rainbow (3.0.0) - rake (13.0.6) - regexp_parser (2.1.1) - rexml (3.2.5) - rubocop (1.23.0) - parallel (~> 1.10) - parser (>= 3.0.0.0) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.12.0, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.13.0) - parser (>= 3.0.1.1) - ruby-progressbar (1.11.0) - ruby2_keywords (0.0.5) - sawyer (0.8.2) - addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - test-unit (3.5.1) - power_assert - toml (0.3.0) - parslet (>= 1.8.0, < 3.0.0) - unicode-display_width (2.1.0) - -PLATFORMS - x86_64-darwin-20 - x86_64-darwin-22 - -DEPENDENCIES - changelogerator (= 0.10.1) - git_diff_parser (~> 3) - logger (~> 1.4) - octokit (~> 4) - optparse (~> 0.1.1) - rake - rubocop - test-unit - toml (~> 0.3.0) - -BUNDLED WITH - 2.4.6 diff --git a/polkadot/scripts/ci/changelog/README.md b/polkadot/scripts/ci/changelog/README.md deleted file mode 100644 index ab3c1fd214e..00000000000 --- a/polkadot/scripts/ci/changelog/README.md +++ /dev/null @@ -1,80 +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. See below for an example - -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 [] -``` - -For instance: -``` -./bin/changelog v0.9.18 -``` - -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_SHELL=true -DEBUG=1 -NO_CACHE=1 -``` -## 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 -- E2 => database migration -- B0 => silent, not showing up -- B1 => noteworthy -- T0 => node -- T1 => runtime - -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 debuggin - -### Hot Reload - -The following command allows **Hot Reload**: -``` -fswatch templates -e ".*\.md$" | xargs -n1 -I{} ./bin/changelog v0.9.18 -``` -### 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 will want to refresh the data. -You can then either delete manually the `.json` file or `export NO_CACHE=1` to force refreshing the data. - -## Full PR list - -At times, it may be useful to get a raw full PR list. -In order to produce this list, you first need to fetch the the latest `context.json` from the `release-notes-context` artifacts you can find [here](https://github.com/paritytech/polkadot/actions/workflows/release-30_publish-draft-release.yml). You may store this `context.json` under `scripts/ci/changelog`. - -Using the `full_pr_list.md.tera` template, you can generate the `raw` list of changes: - -``` -cd scripts/ci/changelog -tera --env --env-key env --template templates/full_pr_list.md.tera context.json -``` diff --git a/polkadot/scripts/ci/changelog/bin/changelog b/polkadot/scripts/ci/changelog/bin/changelog deleted file mode 100755 index e642a448904..00000000000 --- a/polkadot/scripts/ci/changelog/bin/changelog +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env ruby - -# frozen_string_literal: true - -# call for instance as: -# ./bin/changelog [] [] -# for instance, for the release notes of v1.2.3: -# ./bin/changelog v1.2.3 -# or -# ./bin/changelog v1.2.3 v1.2.2 -# -# You may set the ENV NO_CACHE to force fetching from Github -# You should also ensure you set the ENV: GITHUB_TOKEN - -require_relative '../lib/changelog' -require 'logger' - -logger = Logger.new($stdout) -logger.level = Logger::DEBUG -logger.debug('Starting') - -changelogerator_version = `changelogerator --version` -logger.debug(changelogerator_version) - -owner = 'paritytech' -repo = 'polkadot' - -gh_polkadot = SubRef.new(format('%s/%s', { owner: owner, repo: repo })) -last_release_ref = gh_polkadot.get_last_ref() - -polkadot_ref2 = ARGV[0] || 'HEAD' -polkadot_ref1 = ARGV[1] || last_release_ref - -output = ARGV[2] || 'release-notes.md' - -ENV['REF1'] = polkadot_ref1 -ENV['REF2'] = polkadot_ref2 - -substrate_ref1 = gh_polkadot.get_dependency_reference(polkadot_ref1, 'sp-io') -substrate_ref2 = gh_polkadot.get_dependency_reference(polkadot_ref2, 'sp-io') - -logger.debug("Polkadot from: #{polkadot_ref1}") -logger.debug("Polkadot to: #{polkadot_ref2}") - -logger.debug("Substrate from: #{substrate_ref1}") -logger.debug("Substrate to: #{substrate_ref2}") - -substrate_data = 'substrate.json' -polkadot_data = 'polkadot.json' - -logger.debug("Using SUBSTRATE: #{substrate_data}") -logger.debug("Using POLKADOT: #{polkadot_data}") - -logger.warn('NO_CACHE set') if ENV['NO_CACHE'] - -if ENV['NO_CACHE'] || !File.file?(polkadot_data) - logger.debug(format('Fetching data for Polkadot into %s', polkadot_data)) - cmd = format('changelogerator %s/%s -f %s -t %s > %s', - { owner: owner, repo: 'polkadot', from: polkadot_ref1, to: polkadot_ref2, output: polkadot_data }) - system(cmd) -else - logger.debug("Re-using:#{polkadot_data}") -end - -if ENV['NO_CACHE'] || !File.file?(substrate_data) - logger.debug(format('Fetching data for Substrate into %s', substrate_data)) - cmd = format('changelogerator %s/%s -f %s -t %s > %s', - { owner: owner, repo: 'substrate', from: substrate_ref1, to: substrate_ref2, output: substrate_data }) - system(cmd) -else - logger.debug("Re-using:#{substrate_data}") -end - -KUSAMA_DIGEST = ENV['KUSAMA_DIGEST'] || 'digests/kusama_srtool_output.json' -WESTEND_DIGEST = ENV['WESTEND_DIGEST'] || 'digests/westend_srtool_output.json' -ROCOCO_DIGEST = ENV['ROCOCO_DIGEST'] || 'digests/rococo_srtool_output.json' -POLKADOT_DIGEST = ENV['POLKADOT_DIGEST'] || 'digests/polkadot_srtool_output.json' - -# Here we compose all the pieces together into one -# single big json file. -cmd = format('jq \ - --slurpfile substrate %s \ - --slurpfile polkadot %s \ - --slurpfile srtool_kusama %s \ - --slurpfile srtool_westend %s \ - --slurpfile srtool_rococo %s \ - --slurpfile srtool_polkadot %s \ - -n \'{ - substrate: $substrate[0], - polkadot: $polkadot[0], - srtool: [ - { name: "kusama", data: $srtool_kusama[0] }, - { name: "westend", data: $srtool_westend[0] }, - { name: "rococo", data: $srtool_rococo[0] }, - { name: "polkadot", data: $srtool_polkadot[0] } - ] }\' > context.json', substrate_data, polkadot_data, - KUSAMA_DIGEST, - WESTEND_DIGEST, - ROCOCO_DIGEST, - POLKADOT_DIGEST) -system(cmd) - -cmd = format('tera --env --env-key env --include-path templates \ - --template templates/template.md.tera context.json > %s', output) -system(cmd) diff --git a/polkadot/scripts/ci/changelog/digests/.gitignore b/polkadot/scripts/ci/changelog/digests/.gitignore deleted file mode 100644 index a6c57f5fb2f..00000000000 --- a/polkadot/scripts/ci/changelog/digests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.json diff --git a/polkadot/scripts/ci/changelog/digests/.gitkeep b/polkadot/scripts/ci/changelog/digests/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/polkadot/scripts/ci/changelog/lib/changelog.rb b/polkadot/scripts/ci/changelog/lib/changelog.rb deleted file mode 100644 index e98baf82f01..00000000000 --- a/polkadot/scripts/ci/changelog/lib/changelog.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -# A Class to find Substrate references -class SubRef - require 'octokit' - require 'toml' - - attr_reader :client, :repository - - def initialize(github_repo) - @client = Octokit::Client.new( - access_token: ENV['GITHUB_TOKEN'] - ) - @repository = @client.repository(github_repo) - end - - # This function checks the Cargo.lock of a given - # Rust project, for a given package, and fetches - # the dependency git ref. - def get_dependency_reference(ref, package) - cargo = TOML::Parser.new( - Base64.decode64( - @client.contents( - @repository.full_name, - path: 'Cargo.lock', - query: { ref: ref.to_s } - ).content - ) - ).parsed - cargo['package'].find { |p| p['name'] == package }['source'].split('#').last - end - - # Get the git ref of the last release for the repo. - # repo is given in the form paritytech/polkadot - def get_last_ref() - 'refs/tags/' + @client.latest_release(@repository.full_name).tag_name - end -end diff --git a/polkadot/scripts/ci/changelog/templates/_free_notes.md.tera b/polkadot/scripts/ci/changelog/templates/_free_notes.md.tera deleted file mode 100644 index c4a841a9925..00000000000 --- a/polkadot/scripts/ci/changelog/templates/_free_notes.md.tera +++ /dev/null @@ -1,10 +0,0 @@ - -{# This file uses the Markdown format with additional templating such as this comment. -#} -{# Such a comment will not show up in the rendered release notes. -#} -{# The content of this file (if any) will be inserted at the top of the release notes -#} -{# and generated for each new release candidate. -#} -{# Ensure you leave an empty line at both top and bottom of this file. -#} - - - - diff --git a/polkadot/scripts/ci/changelog/templates/change.md.tera b/polkadot/scripts/ci/changelog/templates/change.md.tera deleted file mode 100644 index cfde3be6e85..00000000000 --- a/polkadot/scripts/ci/changelog/templates/change.md.tera +++ /dev/null @@ -1,43 +0,0 @@ -{# This macro shows ONE change #} -{%- macro change(c, cml="[C]", dot="[P]", sub="[S]") -%} - -{%- if c.meta.C and c.meta.C.agg.max >= 7 -%} -{%- set prio = " ‼️ HIGH" -%} -{%- elif c.meta.C and c.meta.C.agg.max >= 3 -%} -{%- set prio = " ❗️ Medium" -%} -{%- elif c.meta.C and c.meta.C.agg.max < 3 -%} -{%- set prio = " Low" -%} -{%- else -%} -{%- set prio = "" -%} -{%- endif -%} - -{%- set audit = "" -%} - -{%- if c.meta.D and c.meta.D.D1 -%} -{%- set audit = "✅ audited " -%} -{%- elif c.meta.D and c.meta.D.D2 -%} -{%- set audit = "✅ trivial " -%} -{%- elif c.meta.D and c.meta.D.D3 -%} -{%- set audit = "✅ trivial " -%} -{%- elif c.meta.D and c.meta.D.D5 -%} -{%- set audit = "⏳ pending non-critical audit " -%} -{%- else -%} -{%- set audit = "" -%} -{%- endif -%} - -{%- if c.html_url is containing("polkadot") -%} -{%- set repo = dot -%} -{%- elif c.html_url is containing("substrate") -%} -{%- set repo = sub -%} -{%- else -%} -{%- set repo = " " -%} -{%- endif -%} - -{%- if c.meta.T and c.meta.T.T6 -%} -{%- set xcm = " [✉️ XCM]" -%} -{%- else -%} -{%- set xcm = "" -%} -{%- endif -%} - -{{- repo }} {{ audit }}[`#{{c.number}}`]({{c.html_url}}) {{- prio }} - {{ c.title | capitalize | truncate(length=120, end="…") }}{{xcm }} -{%- endmacro change -%} diff --git a/polkadot/scripts/ci/changelog/templates/changes.md.tera b/polkadot/scripts/ci/changelog/templates/changes.md.tera deleted file mode 100644 index f598b2fe83f..00000000000 --- a/polkadot/scripts/ci/changelog/templates/changes.md.tera +++ /dev/null @@ -1,15 +0,0 @@ -{# This include generates the section showing the changes #} -## Changes - -### Legend - -- {{ DOT }} Polkadot -- {{ SUB }} Substrate - -{% include "changes_client.md.tera" %} - -{% include "changes_runtime.md.tera" %} - -{% include "changes_api.md.tera" %} - -{% include "changes_misc.md.tera" %} diff --git a/polkadot/scripts/ci/changelog/templates/changes_api.md.tera b/polkadot/scripts/ci/changelog/templates/changes_api.md.tera deleted file mode 100644 index 29e08b8cd38..00000000000 --- a/polkadot/scripts/ci/changelog/templates/changes_api.md.tera +++ /dev/null @@ -1,17 +0,0 @@ -{% import "change.md.tera" as m_c -%} -### API - -{#- The changes are sorted by merge date #} -{%- for pr in changes | sort(attribute="merged_at") %} - -{%- if pr.meta.B %} - {%- if pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- else -%} - - {%- if pr.meta.T and pr.meta.T.T2 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} diff --git a/polkadot/scripts/ci/changelog/templates/changes_client.md.tera b/polkadot/scripts/ci/changelog/templates/changes_client.md.tera deleted file mode 100644 index 6d31961c365..00000000000 --- a/polkadot/scripts/ci/changelog/templates/changes_client.md.tera +++ /dev/null @@ -1,17 +0,0 @@ -{% import "change.md.tera" as m_c -%} -### Client - -{#- The changes are sorted by merge date #} -{%- for pr in changes | sort(attribute="merged_at") %} - -{%- if pr.meta.B %} - {%- if pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- else -%} - - {%- if pr.meta.T and pr.meta.T.T0 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} diff --git a/polkadot/scripts/ci/changelog/templates/changes_misc.md.tera b/polkadot/scripts/ci/changelog/templates/changes_misc.md.tera deleted file mode 100644 index 725b03081eb..00000000000 --- a/polkadot/scripts/ci/changelog/templates/changes_misc.md.tera +++ /dev/null @@ -1,42 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{%- set_global misc_count = 0 -%} -{#- First pass to count #} -{%- for pr in changes -%} - {%- if pr.meta.B %} - {%- if pr.meta.B.B0 -%} - {#- We skip silent ones -#} - {%- else -%} - {%- if pr.meta.T and pr.meta.T.agg.max > 2 %} -{%- set_global misc_count = misc_count + 1 -%} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor -%} - - -{%- if misc_count > 0 %} -### Misc - -{% if misc_count > 10 %} -There are other misc. changes. You can expand the list below to view them all. -
Other misc. changes -{% endif -%} - -{#- The changes are sorted by merge date #} -{%- for pr in changes | sort(attribute="merged_at") %} - {%- if pr.meta.B and not pr.title is containing("ompanion") %} - {%- if pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- else -%} - {%- if pr.meta.T and pr.meta.T.agg.max > 2 %} -- {{ m_c::change(c=pr) }} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} - -{% if misc_count > 10 %} -
-{% endif -%} -{% endif -%} diff --git a/polkadot/scripts/ci/changelog/templates/changes_runtime.md.tera b/polkadot/scripts/ci/changelog/templates/changes_runtime.md.tera deleted file mode 100644 index bd126c0628c..00000000000 --- a/polkadot/scripts/ci/changelog/templates/changes_runtime.md.tera +++ /dev/null @@ -1,19 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -### Runtime - -{#- The changes are sorted by merge date -#} -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B -%} -{%- if pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - -{%- if pr.meta.T and pr.meta.T.T1 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} -{%- endif -%} -{%- endif -%} - -{%- endif -%} -{%- endfor %} diff --git a/polkadot/scripts/ci/changelog/templates/compiler.md.tera b/polkadot/scripts/ci/changelog/templates/compiler.md.tera deleted file mode 100644 index 6fa1baa6506..00000000000 --- a/polkadot/scripts/ci/changelog/templates/compiler.md.tera +++ /dev/null @@ -1,7 +0,0 @@ -## Rust compiler versions - -This release was built and tested against the following versions of `rustc`. -Other versions may work. - -- Rust Stable: `{{ env.RUSTC_STABLE }}` -- Rust Nightly: `{{ env.RUSTC_NIGHTLY }}` diff --git a/polkadot/scripts/ci/changelog/templates/debug.md.tera b/polkadot/scripts/ci/changelog/templates/debug.md.tera deleted file mode 100644 index 8c829b09ffe..00000000000 --- a/polkadot/scripts/ci/changelog/templates/debug.md.tera +++ /dev/null @@ -1,8 +0,0 @@ -{%- set to_ignore = changes | filter(attribute="meta.B.B0") %} - - diff --git a/polkadot/scripts/ci/changelog/templates/docker_image.md.tera b/polkadot/scripts/ci/changelog/templates/docker_image.md.tera deleted file mode 100644 index 4a3793a86ad..00000000000 --- a/polkadot/scripts/ci/changelog/templates/docker_image.md.tera +++ /dev/null @@ -1,11 +0,0 @@ - -## Docker image - -The docker image for this release can be found at [Docker hub](https://hub.docker.com/r/parity/polkadot/tags?page=1&ordering=last_updated) -(It will be available a few minutes after the release has been published). - -You may pull it using: - -``` -docker pull parity/polkadot:latest -``` diff --git a/polkadot/scripts/ci/changelog/templates/full_pr_list.md.tera b/polkadot/scripts/ci/changelog/templates/full_pr_list.md.tera deleted file mode 100644 index 1cdab310652..00000000000 --- a/polkadot/scripts/ci/changelog/templates/full_pr_list.md.tera +++ /dev/null @@ -1,16 +0,0 @@ -{# This is a helper template to get the FULL PR list #} -{# It is not used in the release notes #} - -# PR list - -## substrate - -{%- for change in substrate.changes %} - - [S] [`{{ change.number }}`]({{ change.html_url }}) - {{ change.title }} -{%- endfor %} - -## polkadot - -{%- for change in polkadot.changes %} - - [P] [`{{ change.number }}`]({{ change.html_url }}) - {{ change.title }} -{%- endfor %} diff --git a/polkadot/scripts/ci/changelog/templates/global_priority.md.tera b/polkadot/scripts/ci/changelog/templates/global_priority.md.tera deleted file mode 100644 index fe3d634f19d..00000000000 --- a/polkadot/scripts/ci/changelog/templates/global_priority.md.tera +++ /dev/null @@ -1,22 +0,0 @@ -{% import "high_priority.md.tera" as m_p -%} -## Upgrade Priority - -{%- set polkadot_prio = 0 -%} -{%- set substrate_prio = 0 -%} - -{# We fetch the various priorities #} -{%- if polkadot.meta.C -%} - {%- set polkadot_prio = polkadot.meta.C.max -%} -{%- endif -%} -{%- if substrate.meta.C -%} - {%- set substrate_prio = substrate.meta.C.max -%} -{%- endif -%} - -{# We compute the global priority #} -{%- set global_prio = polkadot_prio -%} -{%- if substrate_prio > global_prio -%} - {%- set global_prio = substrate_prio -%} -{%- endif -%} - -{#- We show the result #} -{{ m_p::high_priority(p=global_prio, changes=changes) }} diff --git a/polkadot/scripts/ci/changelog/templates/high_priority.md.tera b/polkadot/scripts/ci/changelog/templates/high_priority.md.tera deleted file mode 100644 index 39938da44d1..00000000000 --- a/polkadot/scripts/ci/changelog/templates/high_priority.md.tera +++ /dev/null @@ -1,38 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{# This macro convert a priority level into readable output #} -{%- macro high_priority(p, changes) -%} - -{%- if p >= 7 -%} - {%- set prio = "‼️ HIGH" -%} - {%- set text = "This is a **high priority** release and you must upgrade as as soon as possible." -%} -{%- elif p >= 3 -%} - {%- set prio = "❗️ Medium" -%} - {%- set text = "This is a medium priority release and you should upgrade in a timely manner." -%} -{%- else -%} - {%- set prio = "Low" -%} - {%- set text = "This is a low priority release and you may upgrade at your convenience." -%} -{%- endif %} - - - -{%- if prio %} -{{prio}}: {{text}} - -{% if p >= 3 %} -The changes motivating this priority level are: -{% for pr in changes | sort(attribute="merged_at") -%} - {%- if pr.meta.C -%} - {%- if pr.meta.C.agg.max >= p %} -- {{ m_c::change(c=pr) }} -{%- if pr.meta.T and pr.meta.T.T1 %} (RUNTIME) -{% endif %} - {%- endif -%} - {%- endif -%} -{%- endfor -%} -{%- else -%} - -{%- endif -%} -{%- endif -%} - -{%- endmacro priority -%} diff --git a/polkadot/scripts/ci/changelog/templates/host_functions-list.md.tera b/polkadot/scripts/ci/changelog/templates/host_functions-list.md.tera deleted file mode 100644 index 954d41e40d3..00000000000 --- a/polkadot/scripts/ci/changelog/templates/host_functions-list.md.tera +++ /dev/null @@ -1,12 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - {%- if pr.meta.E and pr.meta.E.E3 -%} -- {{ m_c::change(c=pr) }} - {% endif -%} -{% endif -%} -{%- endfor -%} diff --git a/polkadot/scripts/ci/changelog/templates/host_functions.md.tera b/polkadot/scripts/ci/changelog/templates/host_functions.md.tera deleted file mode 100644 index e38bc5d7182..00000000000 --- a/polkadot/scripts/ci/changelog/templates/host_functions.md.tera +++ /dev/null @@ -1,44 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{%- set_global host_fn_count = 0 -%} -{%- set_global upgrade_first = 0 -%} - -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - {%- if pr.meta.E and pr.meta.E.E3 -%} - {%- set_global host_fn_count = host_fn_count + 1 -%} - - {{ m_c::change(c=pr) }} - {% endif -%} - {%- if pr.meta.E and pr.meta.E.E4 -%} - {%- set_global upgrade_first = upgrade_first + 1 -%} - - {{ m_c::change(c=pr) }} - {% endif -%} -{% endif -%} -{%- endfor -%} - - - -{%- if upgrade_first != 0 %} -## Node upgrade required -⚠️ There is a runtime change that will require nodes to be upgraded BEFORE the runtime upgrade. - -⚠️ It is critical that you update your client before the chain switches to the new runtime. -{%- endif %} - - - -## Host functions - -{% if host_fn_count == 0 %} -ℹ️ This release does not contain any change related to host functions. -{% elif host_fn_count == 1 -%} -{# ---- #} -ℹ️ The runtimes in this release contain one change related to **host function**s: -{% include "host_functions-list.md.tera" -%} -{%- else -%} -ℹ️ The runtimes in this release contain {{ host_fn_count }} changes related to **host function**s: -{% include "host_functions-list.md.tera" -%} -{%- endif %} diff --git a/polkadot/scripts/ci/changelog/templates/migrations-db.md.tera b/polkadot/scripts/ci/changelog/templates/migrations-db.md.tera deleted file mode 100644 index 130a61a12cb..00000000000 --- a/polkadot/scripts/ci/changelog/templates/migrations-db.md.tera +++ /dev/null @@ -1,30 +0,0 @@ -{% import "change.md.tera" as m_c %} -{%- set_global db_migration_count = 0 -%} -{%- for pr in changes -%} - {%- if pr.meta.B and pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- elif pr.meta.E and pr.meta.E.E1 -%} - {%- set_global db_migration_count = db_migration_count + 1 -%} - {%- endif -%} -{%- endfor %} - -## Database Migrations - -Database migrations are operations upgrading the database to the latest stand. -Some migrations may break compatibility, making a backup of your database is highly recommended. - -{% if db_migration_count == 0 -%} -ℹ️ There is no database migration in this release. -{%- elif db_migration_count == 1 -%} -⚠️ There is one database migration in this release: -{%- else -%} -⚠️ There are {{ db_migration_count }} database migrations in this release: -{%- endif %} -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 %} -{#- We skip silent ones -#} -{%- elif pr.meta.E and pr.meta.E.E1 -%} -- {{ m_c::change(c=pr) }} -{% endif -%} -{% endfor -%} diff --git a/polkadot/scripts/ci/changelog/templates/migrations-runtime.md.tera b/polkadot/scripts/ci/changelog/templates/migrations-runtime.md.tera deleted file mode 100644 index 25517a142eb..00000000000 --- a/polkadot/scripts/ci/changelog/templates/migrations-runtime.md.tera +++ /dev/null @@ -1,29 +0,0 @@ -{%- import "change.md.tera" as m_c %} -{%- set_global runtime_migration_count = 0 -%} -{%- for pr in changes -%} - {%- if pr.meta.B and pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- elif pr.meta.E and pr.meta.E.E0 -%} - {%- set_global runtime_migration_count = runtime_migration_count + 1 -%} - {%- endif -%} -{%- endfor %} - -## Runtime Migrations - -Runtime migrations are operations running once during a runtime upgrade. - -{% if runtime_migration_count == 0 -%} -ℹ️ There is no runtime migration in this release. -{%- elif runtime_migration_count == 1 -%} -⚠️ There is one runtime migration in this release: -{%- else -%} -⚠️ There are {{ runtime_migration_count }} runtime migrations in this release: -{%- endif %} -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 %} -{#- We skip silent ones -#} -{%- elif pr.meta.E and pr.meta.E.E0 -%} -- {{ m_c::change(c=pr) }} -{% endif -%} -{% endfor -%} diff --git a/polkadot/scripts/ci/changelog/templates/pre_release.md.tera b/polkadot/scripts/ci/changelog/templates/pre_release.md.tera deleted file mode 100644 index 7d4ad42dd8f..00000000000 --- a/polkadot/scripts/ci/changelog/templates/pre_release.md.tera +++ /dev/null @@ -1,11 +0,0 @@ -{%- if env.PRE_RELEASE == "true" -%} -
⚠️ This is a pre-release - -**Release candidates** are **pre-releases** and may not be final. -Although they are reasonably tested, there may be additional changes or issues -before an official release is tagged. Use at your own discretion, and consider -only using final releases on critical production infrastructure. -
-{% else -%} - -{%- endif %} diff --git a/polkadot/scripts/ci/changelog/templates/runtime.md.tera b/polkadot/scripts/ci/changelog/templates/runtime.md.tera deleted file mode 100644 index cd7edf28f7a..00000000000 --- a/polkadot/scripts/ci/changelog/templates/runtime.md.tera +++ /dev/null @@ -1,28 +0,0 @@ -{# This macro shows one runtime #} -{%- macro runtime(runtime) -%} - -### {{ runtime.name | capitalize }} - -{%- if runtime.data.runtimes.compressed.subwasm.compression.compressed %} -{%- set compressed = "Yes" %} -{%- else %} -{%- set compressed = "No" %} -{%- endif %} - -{%- set comp_ratio = 100 - (runtime.data.runtimes.compressed.subwasm.compression.size_compressed / runtime.data.runtimes.compressed.subwasm.compression.size_decompressed *100) %} - - - - - -``` -🏋️ Runtime Size: {{ runtime.data.runtimes.compressed.subwasm.size | filesizeformat }} ({{ runtime.data.runtimes.compressed.subwasm.size }} bytes) -🔥 Core Version: {{ runtime.data.runtimes.compressed.subwasm.core_version.specName }}-{{ runtime.data.runtimes.compressed.subwasm.core_version.specVersion }} ({{ runtime.data.runtimes.compressed.subwasm.core_version.implName }}-{{ runtime.data.runtimes.compressed.subwasm.core_version.implVersion }}.tx{{ runtime.data.runtimes.compressed.subwasm.core_version.transactionVersion }}.au{{ runtime.data.runtimes.compressed.subwasm.core_version.authoringVersion }}) -🗜 Compressed: {{ compressed }}: {{ comp_ratio | round(method="ceil", precision=2) }}% -🎁 Metadata version: V{{ runtime.data.runtimes.compressed.subwasm.metadata_version }} -🗳️ system.setCode hash: {{ runtime.data.runtimes.compressed.subwasm.proposal_hash }} -🗳️ authorizeUpgrade hash: {{ runtime.data.runtimes.compressed.subwasm.parachain_authorize_upgrade_hash }} -🗳️ Blake2-256 hash: {{ runtime.data.runtimes.compressed.subwasm.blake2_256 }} -📦 IPFS: {{ runtime.data.runtimes.compressed.subwasm.ipfs_hash }} -``` -{%- endmacro runtime %} diff --git a/polkadot/scripts/ci/changelog/templates/runtimes.md.tera b/polkadot/scripts/ci/changelog/templates/runtimes.md.tera deleted file mode 100644 index 0847382689f..00000000000 --- a/polkadot/scripts/ci/changelog/templates/runtimes.md.tera +++ /dev/null @@ -1,19 +0,0 @@ -{# This include shows the list and details of the runtimes #} -{%- import "runtime.md.tera" as m_r -%} - -{# --- #} - -## Runtimes - -{% set rtm = srtool[0] -%} - -The information about the runtimes included in this release can be found below. -The runtimes have been built using [{{ rtm.data.gen }}](https://github.com/paritytech/srtool) and `{{ rtm.data.rustc }}`. - -{%- for runtime in srtool | sort(attribute="name") %} -{%- set HIDE_VAR = "HIDE_SRTOOL_" ~ runtime.name | upper %} -{%- if not env is containing(HIDE_VAR) %} - -{{ m_r::runtime(runtime=runtime) }} -{%- endif %} -{%- endfor %} diff --git a/polkadot/scripts/ci/changelog/templates/template.md.tera b/polkadot/scripts/ci/changelog/templates/template.md.tera deleted file mode 100644 index e04636b4b22..00000000000 --- a/polkadot/scripts/ci/changelog/templates/template.md.tera +++ /dev/null @@ -1,37 +0,0 @@ -{# This is the entry point of the template -#} - -{% include "pre_release.md.tera" -%} - -{% if env.PRE_RELEASE == "true" -%} -This pre-release contains the changes from `{{ env.REF1 | replace(from="refs/tags/", to="") }}` to `{{ env.REF2 | replace(from="refs/tags/", to="") }}`. -{%- else -%} -This release contains the changes from `{{ env.REF1 | replace(from="refs/tags/", to="") }}` to `{{ env.REF2 | replace(from="refs/tags/", to="") }}`. -{% endif -%} - -{%- set changes = polkadot.changes | concat(with=substrate.changes) -%} -{%- include "debug.md.tera" -%} - -{%- set CML = "[C]" -%} -{%- set DOT = "[P]" -%} -{%- set SUB = "[S]" -%} - -{# -- Manual free notes section -- #} -{% include "_free_notes.md.tera" -%} - -{# -- Important automatic section -- #} -{% include "global_priority.md.tera" -%} - -{% include "host_functions.md.tera" -%} - -{% include "migrations-db.md.tera" -%} - -{% include "migrations-runtime.md.tera" -%} -{# --------------------------------- #} - -{% include "compiler.md.tera" -%} - -{% include "runtimes.md.tera" -%} - -{% include "changes.md.tera" -%} - -{% include "docker_image.md.tera" -%} diff --git a/polkadot/scripts/ci/changelog/test/test_basic.rb b/polkadot/scripts/ci/changelog/test/test_basic.rb deleted file mode 100644 index d099fadca43..00000000000 --- a/polkadot/scripts/ci/changelog/test/test_basic.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require_relative '../lib/changelog' -require 'test/unit' - -class TestChangelog < Test::Unit::TestCase - def test_get_dep_ref_polkadot - c = SubRef.new('paritytech/polkadot') - ref = '13c2695' - package = 'sc-cli' - result = c.get_dependency_reference(ref, package) - assert_equal('7db0768a85dc36a3f2a44d042b32f3715c00a90d', result) - end - - def test_get_dep_ref_invalid_ref - c = SubRef.new('paritytech/polkadot') - ref = '9999999' - package = 'sc-cli' - assert_raise do - c.get_dependency_reference(ref, package) - end - end -end diff --git a/polkadot/scripts/ci/common/lib.sh b/polkadot/scripts/ci/common/lib.sh deleted file mode 100755 index e490ec22d5b..00000000000 --- a/polkadot/scripts/ci/common/lib.sh +++ /dev/null @@ -1,265 +0,0 @@ -#!/bin/sh - -api_base="https://api.github.com/repos" - -# Function to take 2 git tags/commits and get any lines from commit messages -# that contain something that looks like a PR reference: e.g., (#1234) -sanitised_git_logs(){ - git --no-pager log --pretty=format:"%s" "$1...$2" | - # Only find messages referencing a PR - grep -E '\(#[0-9]+\)' | - # Strip any asterisks - sed 's/^* //g' -} - -# Checks whether a tag on github has been verified -# repo: 'organization/repo' -# tagver: 'v1.2.3' -# Usage: check_tag $repo $tagver -check_tag () { - repo=$1 - tagver=$2 - if [ -n "$GITHUB_RELEASE_TOKEN" ]; then - echo '[+] Fetching tag using privileged token' - tag_out=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") - else - echo '[+] Fetching tag using unprivileged token' - tag_out=$(curl -H "Authorization: token $GITHUB_PR_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") - fi - tag_sha=$(echo "$tag_out" | jq -r .object.sha) - object_url=$(echo "$tag_out" | jq -r .object.url) - if [ "$tag_sha" = "null" ]; then - return 2 - fi - echo "[+] Tag object SHA: $tag_sha" - verified_str=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$object_url" | jq -r .verification.verified) - if [ "$verified_str" = "true" ]; then - # Verified, everything is good - return 0 - else - # Not verified. Bad juju. - return 1 - fi -} - -# Checks whether a given PR has a given label. -# repo: 'organization/repo' -# pr_id: 12345 -# label: B1-silent -# Usage: has_label $repo $pr_id $label -has_label(){ - repo="$1" - pr_id="$2" - label="$3" - - # These will exist if the function is called in Gitlab. - # If the function's called in Github, we should have GITHUB_ACCESS_TOKEN set - # already. - if [ -n "$GITHUB_RELEASE_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_RELEASE_TOKEN" - elif [ -n "$GITHUB_PR_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_PR_TOKEN" - fi - - out=$(curl -H "Authorization: token $GITHUB_TOKEN" -s "$api_base/$repo/pulls/$pr_id") - [ -n "$(echo "$out" | tr -d '\r\n' | jq ".labels | .[] | select(.name==\"$label\")")" ] -} - -github_label () { - echo - echo "# run github-api job for labeling it ${1}" - curl -sS -X POST \ - -F "token=${CI_JOB_TOKEN}" \ - -F "ref=master" \ - -F "variables[LABEL]=${1}" \ - -F "variables[PRNO]=${CI_COMMIT_REF_NAME}" \ - -F "variables[PROJECT]=paritytech/polkadot" \ - "${GITLAB_API}/projects/${GITHUB_API_PROJECT}/trigger/pipeline" -} - -# Formats a message into a JSON string for posting to Matrix -# message: 'any plaintext message' -# formatted_message: 'optional message formatted in html' -# Usage: structure_message $content $formatted_content (optional) -structure_message() { - if [ -z "$2" ]; then - body=$(jq -Rs --arg body "$1" '{"msgtype": "m.text", $body}' < /dev/null) - else - body=$(jq -Rs --arg body "$1" --arg formatted_body "$2" '{"msgtype": "m.text", $body, "format": "org.matrix.custom.html", $formatted_body}' < /dev/null) - fi - echo "$body" -} - -# Post a message to a matrix room -# body: '{body: "JSON string produced by structure_message"}' -# room_id: !fsfSRjgjBWEWffws:matrix.parity.io -# access_token: see https://matrix.org/docs/guides/client-server-api/ -# Usage: send_message $body (json formatted) $room_id $access_token -send_message() { - curl -XPOST -d "$1" "https://m.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" -} - -# Pretty-printing functions -boldprint () { printf "|\n| \033[1m%s\033[0m\n|\n" "${@}"; } -boldcat () { printf "|\n"; while read -r l; do printf "| \033[1m%s\033[0m\n" "${l}"; done; printf "|\n" ; } - -skip_if_companion_pr() { - url="https://api.github.com/repos/paritytech/polkadot/pulls/${CI_COMMIT_REF_NAME}" - echo "[+] API URL: $url" - - pr_title=$(curl -sSL -H "Authorization: token ${GITHUB_PR_TOKEN}" "$url" | jq -r .title) - echo "[+] PR title: $pr_title" - - if echo "$pr_title" | grep -qi '^companion'; then - echo "[!] PR is a companion PR. Build is already done in substrate" - exit 0 - else - echo "[+] PR is not a companion PR. Proceeding test" - fi -} - -# Fetches the tag name of the latest release from a repository -# repo: 'organisation/repo' -# Usage: latest_release 'paritytech/polkadot' -latest_release() { - curl -s "$api_base/$1/releases/latest" | jq -r '.tag_name' -} - -# Check for runtime changes between two commits. This is defined as any changes -# to /primitives/src/* and any *production* chains under /runtime -has_runtime_changes() { - from=$1 - to=$2 - - if git diff --name-only "${from}...${to}" \ - | grep -q -e '^runtime/polkadot' -e '^runtime/kusama' -e '^primitives/src/' -e '^runtime/common' - then - return 0 - else - return 1 - fi -} - -# given a bootnode and the path to a chainspec file, this function will create a new chainspec file -# with only the bootnode specified and test whether that bootnode provides peers -# The optional third argument is the index of the bootnode in the list of bootnodes, this is just used to pick an ephemeral -# port for the node to run on. If you're only testing one, it'll just use the first ephemeral port -# BOOTNODE: /dns/polkadot-connect-0.parity.io/tcp/443/wss/p2p/12D3KooWEPmjoRpDSUuiTjvyNDd8fejZ9eNWH5bE965nyBMDrB4o -# CHAINSPEC_FILE: /path/to/polkadot.json -check_bootnode(){ - BOOTNODE=$1 - BASE_CHAINSPEC=$2 - RUNTIME=$(basename "$BASE_CHAINSPEC" | cut -d '.' -f 1) - MIN_PEERS=1 - - # Generate a temporary chainspec file containing only the bootnode we care about - TMP_CHAINSPEC_FILE="$RUNTIME.$(echo "$BOOTNODE" | tr '/' '_').tmp.json" - jq ".bootNodes = [\"$BOOTNODE\"] " < "$CHAINSPEC_FILE" > "$TMP_CHAINSPEC_FILE" - - # Grab an unused port by binding to port 0 and then immediately closing the socket - # This is a bit of a hack, but it's the only way to do it in the shell - RPC_PORT=$(python -c "import socket; s=socket.socket(); s.bind(('', 0)); print(s.getsockname()[1]); s.close()") - - echo "[+] Checking bootnode $BOOTNODE" - polkadot --chain "$TMP_CHAINSPEC_FILE" --no-mdns --rpc-port="$RPC_PORT" --tmp > /dev/null 2>&1 & - # Wait a few seconds for the node to start up - sleep 5 - POLKADOT_PID=$! - - MAX_POLLS=10 - TIME_BETWEEN_POLLS=3 - for _ in $(seq 1 "$MAX_POLLS"); do - # Check the health endpoint of the RPC node - PEERS="$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"system_health","params":[],"id":1}' http://localhost:"$RPC_PORT" | jq -r '.result.peers')" - # Sometimes due to machine load or other reasons, we don't get a response from the RPC node - # If $PEERS is an empty variable, make it 0 so we can still do the comparison - if [ -z "$PEERS" ]; then - PEERS=0 - fi - if [ "$PEERS" -ge $MIN_PEERS ]; then - echo "[+] $PEERS peers found for $BOOTNODE" - echo " Bootnode appears contactable" - kill $POLKADOT_PID - # Delete the temporary chainspec file now we're done running the node - rm "$TMP_CHAINSPEC_FILE" - return 0 - fi - sleep "$TIME_BETWEEN_POLLS" - done - kill $POLKADOT_PID - # Delete the temporary chainspec file now we're done running the node - rm "$TMP_CHAINSPEC_FILE" - echo "[!] No peers found for $BOOTNODE" - echo " Bootnode appears unreachable" - return 1 -} - -# Assumes the ENV are set: -# - RELEASE_ID -# - GITHUB_TOKEN -# - REPO in the form paritytech/polkadot -fetch_release_artifacts() { - echo "Release ID : $RELEASE_ID" - echo "Repo : $REPO" - - curl -L -s \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/${REPO}/releases/${RELEASE_ID} > release.json - - # Get Asset ids - ids=($(jq -r '.assets[].id' < release.json )) - count=$(jq '.assets|length' < release.json ) - - # Fetch artifacts - mkdir -p "./release-artifacts" - pushd "./release-artifacts" > /dev/null - - iter=1 - for id in "${ids[@]}" - do - echo " - $iter/$count: downloading asset id: $id..." - curl -s -OJ -L -H "Accept: application/octet-stream" \ - -H "Authorization: Token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/${REPO}/releases/assets/$id" - iter=$((iter + 1)) - done - - pwd - ls -al --color - popd > /dev/null -} - -# Check the checksum for a given binary -function check_sha256() { - echo "Checking SHA256 for $1" - shasum -qc $1.sha256 -} - -# Import GPG keys of the release team members -# This is done in parallel as it can take a while sometimes -function import_gpg_keys() { - GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} - SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" - WILL="2835EAF92072BC01D188AF2C4A092B93E97CE1E2" - EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" - MARA="533C920F40E73A21EEB7E9EBF27AEA7E7594C9CF" - MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" - - echo "Importing GPG keys from $GPG_KEYSERVER in parallel" - for key in $SEC $WILL $EGOR $MARA $MORGAN; do - ( - echo "Importing GPG key $key" - gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key - echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key $key trust; - ) & - done - wait -} - -# Check the GPG signature for a given binary -function check_gpg() { - echo "Checking GPG Signature for $1" - gpg --no-tty --verify -q $1.asc $1 -} diff --git a/polkadot/scripts/ci/dockerfiles/adder-collator/build-injected.sh b/polkadot/scripts/ci/dockerfiles/adder-collator/build-injected.sh deleted file mode 100755 index 9a1857bc7ab..00000000000 --- a/polkadot/scripts/ci/dockerfiles/adder-collator/build-injected.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_binary -# This script replace the former dedicated Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` - -export BINARY=adder-collator,undying-collator -export BIN_FOLDER=$1 - -$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/polkadot/scripts/ci/dockerfiles/adder-collator/test-build.sh b/polkadot/scripts/ci/dockerfiles/adder-collator/test-build.sh deleted file mode 100755 index 171e0309f80..00000000000 --- a/polkadot/scripts/ci/dockerfiles/adder-collator/test-build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -TMP=$(mktemp -d) -ENGINE=${ENGINE:-podman} - -# TODO: Switch to /bin/bash when the image is built from parity/base-bin - -# Fetch some binaries -$ENGINE run --user root --rm -i \ - --pull always \ - -v "$TMP:/export" \ - --entrypoint /usr/bin/bash \ - paritypr/colander:master -c \ - 'cp "$(which adder-collator)" /export' - -$ENGINE run --user root --rm -i \ - --pull always \ - -v "$TMP:/export" \ - --entrypoint /usr/bin/bash \ - paritypr/colander:master -c \ - 'cp "$(which undying-collator)" /export' - -./build-injected.sh $TMP diff --git a/polkadot/scripts/ci/dockerfiles/binary_injected.Dockerfile b/polkadot/scripts/ci/dockerfiles/binary_injected.Dockerfile deleted file mode 100644 index cee81a2eb8a..00000000000 --- a/polkadot/scripts/ci/dockerfiles/binary_injected.Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM docker.io/parity/base-bin - -# This file allows building a Generic container image -# based on one or multiple pre-built Linux binaries. -# Some defaults are set to polkadot but all can be overriden. - -SHELL ["/bin/bash", "-c"] - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -# That can be a single one or a comma separated list -ARG BINARY=polkadot - -ARG BIN_FOLDER=. -ARG DOC_URL=https://github.com/paritytech/polkadot -ARG DESCRIPTION="Polkadot: a platform for web3" -ARG AUTHORS="devops-team@parity.io" -ARG VENDOR="Parity Technologies" - -LABEL io.parity.image.authors=${AUTHORS} \ - io.parity.image.vendor="${VENDOR}" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.title="${IMAGE_NAME}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="${DOC_URL}" \ - io.parity.image.description="${DESCRIPTION}" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/binary_injected.Dockerfile" - -USER root -WORKDIR /app - -# add polkadot binary to docker image -# sample for polkadot: COPY ./polkadot ./polkadot-*-worker /usr/local/bin/ -COPY entrypoint.sh . -COPY "bin/*" "/usr/local/bin/" -RUN chmod -R a+rx "/usr/local/bin" - -USER parity -ENV BINARY=${BINARY} - -# ENTRYPOINT -ENTRYPOINT ["/app/entrypoint.sh"] - -# We call the help by default -CMD ["--help"] diff --git a/polkadot/scripts/ci/dockerfiles/build-injected.sh b/polkadot/scripts/ci/dockerfiles/build-injected.sh deleted file mode 100755 index d0e7fee3646..00000000000 --- a/polkadot/scripts/ci/dockerfiles/build-injected.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash -set -e - -# This script allows building a Container Image from a Linux -# binary that is injected into a base-image. - -ENGINE=${ENGINE:-podman} - -if [ "$ENGINE" == "podman" ]; then - PODMAN_FLAGS="--format docker" -else - PODMAN_FLAGS="" -fi - -CONTEXT=$(mktemp -d) -REGISTRY=${REGISTRY:-docker.io} - -# The following line ensure we know the project root -PROJECT_ROOT=${PROJECT_ROOT:-$(git rev-parse --show-toplevel)} -DOCKERFILE=${DOCKERFILE:-$PROJECT_ROOT/scripts/ci/dockerfiles/binary_injected.Dockerfile} -VERSION_TOML=$(grep "^version " $PROJECT_ROOT/Cargo.toml | grep -oE "([0-9\.]+-?[0-9]+)") - -#n The following VAR have default that can be overriden -DOCKER_OWNER=${DOCKER_OWNER:-parity} - -# We may get 1..n binaries, comma separated -BINARY=${BINARY:-polkadot} -IFS=',' read -r -a BINARIES <<< "$BINARY" - -VERSION=${VERSION:-$VERSION_TOML} -BIN_FOLDER=${BIN_FOLDER:-.} - -IMAGE=${IMAGE:-${REGISTRY}/${DOCKER_OWNER}/${BINARIES[0]}} -DESCRIPTION_DEFAULT="Injected Container image built for ${BINARY}" -DESCRIPTION=${DESCRIPTION:-$DESCRIPTION_DEFAULT} - -VCS_REF=${VCS_REF:-01234567} - -# Build the image -echo "Using engine: $ENGINE" -echo "Using Dockerfile: $DOCKERFILE" -echo "Using context: $CONTEXT" -echo "Building ${IMAGE}:latest container image for ${BINARY} v${VERSION} from ${BIN_FOLDER} hang on!" -echo "BIN_FOLDER=$BIN_FOLDER" -echo "CONTEXT=$CONTEXT" - -# We need all binaries and resources available in the Container build "CONTEXT" -mkdir -p $CONTEXT/bin -for bin in "${BINARIES[@]}" -do - echo "Copying $BIN_FOLDER/$bin to context: $CONTEXT/bin" - cp "$BIN_FOLDER/$bin" "$CONTEXT/bin" -done - -cp "$PROJECT_ROOT/scripts/ci/dockerfiles/entrypoint.sh" "$CONTEXT" - -echo "Building image: ${IMAGE}" - -TAGS=${TAGS[@]:-latest} -IFS=',' read -r -a TAG_ARRAY <<< "$TAGS" -TAG_ARGS=" " - -echo "The image ${IMAGE} will be tagged with ${TAG_ARRAY[*]}" -for tag in "${TAG_ARRAY[@]}"; do - TAG_ARGS+="--tag ${IMAGE}:${tag} " -done - -echo "$TAG_ARGS" - -# time \ -$ENGINE build \ - ${PODMAN_FLAGS} \ - --build-arg VCS_REF="${VCS_REF}" \ - --build-arg BUILD_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \ - --build-arg IMAGE_NAME="${IMAGE}" \ - --build-arg BINARY="${BINARY}" \ - --build-arg BIN_FOLDER="${BIN_FOLDER}" \ - --build-arg DESCRIPTION="${DESCRIPTION}" \ - ${TAG_ARGS} \ - -f "${DOCKERFILE}" \ - ${CONTEXT} - -echo "Your Container image for ${IMAGE} is ready" -$ENGINE images - -if [[ -z "${SKIP_IMAGE_VALIDATION}" ]]; then - echo "Check the image ${IMAGE}:${TAG_ARRAY[0]}" - $ENGINE run --rm -i "${IMAGE}:${TAG_ARRAY[0]}" --version - - echo "Query binaries" - $ENGINE run --rm -i --entrypoint /bin/bash "${IMAGE}:${TAG_ARRAY[0]}" -c 'echo BINARY: $BINARY' -fi diff --git a/polkadot/scripts/ci/dockerfiles/entrypoint.sh b/polkadot/scripts/ci/dockerfiles/entrypoint.sh deleted file mode 100755 index eaa815faf6a..00000000000 --- a/polkadot/scripts/ci/dockerfiles/entrypoint.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -# Sanity check -if [ -z "$BINARY" ] -then - echo "BINARY ENV not defined, this should never be the case. Aborting..." - exit 1 -fi - -# If the user built the image with multiple binaries, -# we consider the first one to be the canonical one -# To start with another binary, the user can either: -# - use the --entrypoint option -# - pass the ENV BINARY with a single binary -IFS=',' read -r -a BINARIES <<< "$BINARY" -BIN0=${BINARIES[0]} -echo "Starting binary $BIN0" -$BIN0 $@ diff --git a/polkadot/scripts/ci/dockerfiles/malus/build-injected.sh b/polkadot/scripts/ci/dockerfiles/malus/build-injected.sh deleted file mode 100755 index 99bd5fde1d5..00000000000 --- a/polkadot/scripts/ci/dockerfiles/malus/build-injected.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_binary -# This script replace the former dedicated Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` - -export BINARY=malus,polkadot-execute-worker,polkadot-prepare-worker -export BIN_FOLDER=$1 -# export TAGS=... - -$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/polkadot/scripts/ci/dockerfiles/malus/test-build.sh b/polkadot/scripts/ci/dockerfiles/malus/test-build.sh deleted file mode 100755 index 3114e9e2adf..00000000000 --- a/polkadot/scripts/ci/dockerfiles/malus/test-build.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -TMP=$(mktemp -d) -ENGINE=${ENGINE:-podman} - -export TAGS=latest,beta,7777,1.0.2-rc23 - -# Fetch some binaries -$ENGINE run --user root --rm -i \ - --pull always \ - -v "$TMP:/export" \ - --entrypoint /bin/bash \ - paritypr/malus:7217 -c \ - 'cp "$(which malus)" /export' - -echo "Checking binaries we got:" -ls -al $TMP - -./build-injected.sh $TMP diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/README.md b/polkadot/scripts/ci/dockerfiles/polkadot/README.md deleted file mode 100644 index e331d8984c2..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Self built Docker image - -The Polkadot repo contains several options to build Docker images for Polkadot. - -This folder contains a self-contained image that does not require a Linux pre-built binary. - -Instead, building the image is possible on any host having docker installed and will -build Polkadot inside Docker. That also means that no Rust toolchain is required on the host -machine for the build to succeed. diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/build-injected.sh b/polkadot/scripts/ci/dockerfiles/polkadot/build-injected.sh deleted file mode 100755 index 22774c7b712..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/build-injected.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_binary -# This script replace the former dedicated Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` - -export BINARY=polkadot,polkadot-execute-worker,polkadot-prepare-worker -export BIN_FOLDER=$1 - -$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose-local.yml b/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose-local.yml deleted file mode 100644 index 1ff3a1ccaac..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose-local.yml +++ /dev/null @@ -1,50 +0,0 @@ -version: '3' -services: - node_alice: - ports: - - "30333:30333" - - "9933:9933" - - "9944:9944" - - "9615:9615" - image: parity/polkadot:latest - volumes: - - "polkadot-data-alice:/data" - command: | - --chain=polkadot-local - --alice - -d /data - --node-key 0000000000000000000000000000000000000000000000000000000000000001 - networks: - testing_net: - ipv4_address: 172.28.1.1 - - node_bob: - ports: - - "30344:30333" - - "9935:9933" - - "9945:9944" - - "29615:9615" - image: parity/polkadot:latest - volumes: - - "polkadot-data-bob:/data" - links: - - "node_alice:alice" - command: | - --chain=polkadot-local - --bob - -d /data - --bootnodes '/ip4/172.28.1.1/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR' - networks: - testing_net: - ipv4_address: 172.28.1.2 - -volumes: - polkadot-data-alice: - polkadot-data-bob: - -networks: - testing_net: - ipam: - driver: default - config: - - subnet: 172.28.0.0/16 diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose.yml b/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose.yml deleted file mode 100644 index 524b1164796..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/docker-compose.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3' -services: - polkadot: - image: parity/polkadot:latest - - ports: - - "127.0.0.1:30333:30333/tcp" - - "127.0.0.1:9933:9933/tcp" - - "127.0.0.1:9944:9944/tcp" - - "127.0.0.1:9615:9615/tcp" - - volumes: - - "polkadot-data:/data" - - command: | - --unsafe-rpc-external - --unsafe-ws-external - --rpc-cors all - --prometheus-external - -volumes: - polkadot-data: diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md b/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md deleted file mode 100644 index 7e89cb55f3d..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Polkadot official Docker image - -## [Polkadot](https://polkadot.network/) - -## [GitHub](https://github.com/paritytech/polkadot) - -## [Polkadot Wiki](https://wiki.polkadot.network/) diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile b/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile deleted file mode 100644 index f263c836bbf..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# This is the build stage for Polkadot. Here we create the binary in a temporary image. -FROM docker.io/paritytech/ci-linux:production as builder - -WORKDIR /polkadot -COPY . /polkadot - -RUN cargo build --locked --release - -# This is the 2nd stage: a very small image where we copy the Polkadot binary." -FROM docker.io/parity/base-bin:latest - -LABEL description="Multistage Docker image for Polkadot: a platform for web3" \ - io.parity.image.type="builder" \ - 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}/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -COPY --from=builder /polkadot/target/release/polkadot /usr/local/bin - -RUN useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ - mkdir -p /data /polkadot/.local/share && \ - chown -R polkadot:polkadot /data && \ - ln -s /data /polkadot/.local/share/polkadot && \ -# unclutter and minimize the attack surface - rm -rf /usr/bin /usr/sbin && \ -# check if executable works in this container - /usr/local/bin/polkadot --version - -USER polkadot - -EXPOSE 30333 9933 9944 9615 -VOLUME ["/data"] - -ENTRYPOINT ["/usr/local/bin/polkadot"] diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile b/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile deleted file mode 100644 index e2c72dcfe2e..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG POLKADOT_VERSION -ARG POLKADOT_GPGKEY=9D4B2B6EB8F97156D19669A9FF0812D491B96798 -ARG GPG_KEYSERVER="keyserver.ubuntu.com" - -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.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - libssl1.1 \ - ca-certificates \ - gnupg && \ - useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ -# add repo's gpg keys and install the published polkadot binary - gpg --keyserver ${GPG_KEYSERVER} --recv-keys ${POLKADOT_GPGKEY} && \ - gpg --export ${POLKADOT_GPGKEY} > /usr/share/keyrings/parity.gpg && \ - echo 'deb [signed-by=/usr/share/keyrings/parity.gpg] https://releases.parity.io/deb release main' > /etc/apt/sources.list.d/parity.list && \ - apt-get update && \ - apt-get install -y --no-install-recommends polkadot=${POLKADOT_VERSION#?} && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* ; \ - mkdir -p /data /polkadot/.local/share && \ - chown -R polkadot:polkadot /data && \ - ln -s /data /polkadot/.local/share/polkadot - -USER polkadot - -# check if executable works in this container -RUN /usr/bin/polkadot --version -RUN /usr/bin/polkadot-execute-worker --version -RUN /usr/bin/polkadot-prepare-worker --version - -EXPOSE 30333 9933 9944 -VOLUME ["/polkadot"] - -ENTRYPOINT ["/usr/bin/polkadot"] diff --git a/polkadot/scripts/ci/dockerfiles/polkadot/test-build.sh b/polkadot/scripts/ci/dockerfiles/polkadot/test-build.sh deleted file mode 100755 index d2d904561cb..00000000000 --- a/polkadot/scripts/ci/dockerfiles/polkadot/test-build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -TMP=$(mktemp -d) -ENGINE=${ENGINE:-podman} - -# You need to build an injected image first - -# Fetch some binaries -$ENGINE run --user root --rm -i \ - -v "$TMP:/export" \ - --entrypoint /bin/bash \ - parity/polkadot -c \ - 'cp "$(which polkadot)" /export' - -echo "Checking binaries we got:" -tree $TMP - -./build-injected.sh $TMP diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/README.md b/polkadot/scripts/ci/dockerfiles/staking-miner/README.md deleted file mode 100644 index 3610e113031..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# staking-miner container image - -## Build using the Builder - -``` -./build.sh -``` - -## Build the injected Image - -You first need a valid Linux binary to inject. Let's assume this binary is located in `BIN_FOLDER`. - -``` -./build-injected.sh "$BIN_FOLDER" -``` - -## Test - -Here is how to test the image. We can generate a valid seed but the staking-miner will quickly notice that our -account is not funded and "does not exist". - -You may pass any ENV supported by the binary and must provide at least a few such as `SEED` and `URI`: -``` -ENV SEED="" -ENV URI="wss://rpc.polkadot.io:443" -ENV RUST_LOG="info" -``` - -``` -export SEED=$(subkey generate -n polkadot --output-type json | jq -r .secretSeed) -podman run --rm -it \ - -e URI="wss://rpc.polkadot.io:443" \ - -e RUST_LOG="info" \ - -e SEED \ - localhost/parity/staking-miner \ - dry-run seq-phragmen -``` diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/build-injected.sh b/polkadot/scripts/ci/dockerfiles/staking-miner/build-injected.sh deleted file mode 100755 index 536636df6a9..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/build-injected.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_staking-miner_binary -# This script replace the former dedicated staking-miner "injected" Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` - -export BINARY=staking-miner -export BIN_FOLDER=$1 - -$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/build.sh b/polkadot/scripts/ci/dockerfiles/staking-miner/build.sh deleted file mode 100755 index 67c82afcd2c..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_staking-miner_binary -# This script replace the former dedicated staking-miner "injected" Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` -ENGINE=podman - -echo "Building the staking-miner using the Builder image" -echo "PROJECT_ROOT=$PROJECT_ROOT" -$ENGINE build -t staking-miner -f staking-miner_builder.Dockerfile "$PROJECT_ROOT" diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md b/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md deleted file mode 100644 index ce424c42f47..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Staking-miner Docker image - -## [GitHub](https://github.com/paritytech/polkadot/tree/master/utils/staking-miner) diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile b/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile deleted file mode 100644 index 0ae77f36c79..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -FROM paritytech/ci-linux:production as builder - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME="staking-miner" -ARG PROFILE=production - -LABEL description="This is the build stage. Here we create the binary." - -WORKDIR /app -COPY . /app -RUN cargo build --locked --profile $PROFILE --package staking-miner - -# ===== SECOND STAGE ====== - -FROM docker.io/parity/base-bin:latest -LABEL description="This is the 2nd stage: a very small image where we copy the binary." -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="${IMAGE_NAME} for substrate based chains" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_builder.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -ARG PROFILE=release -COPY --from=builder /app/target/$PROFILE/staking-miner /usr/local/bin - -# show backtraces -ENV RUST_BACKTRACE 1 - -USER parity - -ENV SEED="" -ENV URI="wss://rpc.polkadot.io" -ENV RUST_LOG="info" - -# check if the binary works in this container -RUN /usr/local/bin/staking-miner --version - -ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/polkadot/scripts/ci/dockerfiles/staking-miner/test-build.sh b/polkadot/scripts/ci/dockerfiles/staking-miner/test-build.sh deleted file mode 100755 index 0ce74e2df29..00000000000 --- a/polkadot/scripts/ci/dockerfiles/staking-miner/test-build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -TMP=$(mktemp -d) -ENGINE=${ENGINE:-podman} - -# You need to build an injected image first - -# Fetch some binaries -$ENGINE run --user root --rm -i \ - -v "$TMP:/export" \ - --entrypoint /bin/bash \ - parity/staking-miner -c \ - 'cp "$(which staking-miner)" /export' - -echo "Checking binaries we got:" -tree $TMP - -./build-injected.sh $TMP diff --git a/polkadot/scripts/ci/github/check-rel-br b/polkadot/scripts/ci/github/check-rel-br deleted file mode 100755 index 1b49ae62172..00000000000 --- a/polkadot/scripts/ci/github/check-rel-br +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -# This script helps running sanity checks on a release branch -# It is intended to be ran from the repo and from the release branch - -# NOTE: The diener runs do take time and are not really required because -# if we missed the diener runs, the Cargo.lock that we check won't pass -# the tests. See https://github.com/bkchr/diener/issues/17 - -grv=$(git remote --verbose | grep push) -export RUST_LOG=none -REPO=$(echo "$grv" | cut -d ' ' -f1 | cut -d$'\t' -f2 | sed 's/.*github.com\/\(.*\)/\1/g' | cut -d '/' -f2 | cut -d '.' -f1 | sort | uniq) -echo "[+] Detected repo: $REPO" - -BRANCH=$(git branch --show-current) -if ! [[ "$BRANCH" =~ ^release.*$ || "$BRANCH" =~ ^polkadot.*$ ]]; then - echo "This script is meant to run only on a RELEASE branch." - echo "Try one of the following branch:" - git branch -r --format "%(refname:short)" --sort=-committerdate | grep -Ei '/?release' | head - exit 1 -fi -echo "[+] Working on $BRANCH" - -# Tried to get the version of the release from the branch -# input: release-foo-v0.9.22 or release-bar-v9220 or release-foo-v0.9.220 -# output: 0.9.22 -get_version() { - branch=$1 - [[ $branch =~ -v(.*) ]] - version=${BASH_REMATCH[1]} - if [[ $version =~ \. ]]; then - MAJOR=$(($(echo $version | cut -d '.' -f1))) - MINOR=$(($(echo $version | cut -d '.' -f2))) - PATCH=$(($(echo $version | cut -d '.' -f3))) - echo $MAJOR.$MINOR.${PATCH:0:2} - else - MAJOR=$(echo $(($version / 100000))) - remainer=$(($version - $MAJOR * 100000)) - MINOR=$(echo $(($remainer / 1000))) - remainer=$(($remainer - $MINOR * 1000)) - PATCH=$(echo $(($remainer / 10))) - echo $MAJOR.$MINOR.$PATCH - fi -} - -# return the name of the release branch for a given repo and version -get_release_branch() { - repo=$1 - version=$2 - case $repo in - polkadot) - echo "release-v$version" - ;; - - substrate) - echo "polkadot-v$version" - ;; - - *) - echo "Repo $repo is not supported, exiting" - exit 1 - ;; - esac -} - -# repo = substrate / polkadot -check_release_branch_repo() { - repo=$1 - branch=$2 - - echo "[+] Checking deps for $repo=$branch" - - POSTIVE=$(cat Cargo.lock | grep "$repo?branch=$branch" | sort | uniq | wc -l) - NEGATIVE=$(cat Cargo.lock | grep "$repo?branch=" | grep -v $branch | sort | uniq | wc -l) - - if [[ $POSTIVE -eq 1 && $NEGATIVE -eq 0 ]]; then - echo -e "[+] ✅ Looking good" - cat Cargo.lock | grep "$repo?branch=" | sort | uniq | sed 's/^/\t - /' - return 0 - else - echo -e "[+] ❌ Something seems to be wrong, we want 1 unique match and 0 non match (1, 0) and we got ($(($POSTIVE)), $(($NEGATIVE)))" - cat Cargo.lock | grep "$repo?branch=" | sort | uniq | sed 's/^/\t - /' - return 1 - fi -} - -# Check a release branch -check_release_branches() { - SUBSTRATE_BRANCH=$1 - POLKADOT_BRANCH=$2 - - check_release_branch_repo substrate $SUBSTRATE_BRANCH - ret_a1=$? - - ret_b1=0 - if [ $POLKADOT_BRANCH ]; then - check_release_branch_repo polkadot $POLKADOT_BRANCH - ret_b1=$? - fi - - STATUS=$(($ret_a1 + $ret_b1)) - - return $STATUS -} - -VERSION=$(get_version $BRANCH) -echo "[+] Target version: v$VERSION" - -case $REPO in - polkadot) - substrate=$(get_release_branch substrate $VERSION) - - check_release_branches $substrate - ;; - - cumulus) - polkadot=$(get_release_branch polkadot $VERSION) - substrate=$(get_release_branch substrate $VERSION) - - check_release_branches $substrate $polkadot - ;; - - *) - echo "REPO $REPO is not supported, exiting" - exit 1 - ;; -esac diff --git a/polkadot/scripts/ci/github/check_bootnodes.sh b/polkadot/scripts/ci/github/check_bootnodes.sh deleted file mode 100755 index f98a58cda2c..00000000000 --- a/polkadot/scripts/ci/github/check_bootnodes.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash - -# In this script, we check each bootnode for a given chainspec file and ensure they are contactable. -# We do this by removing every bootnode from the chainspec with the exception of the one -# we want to check. Then we spin up a node using this new chainspec, wait a little while -# and then check our local node's RPC endpoint for the number of peers. If the node hasn't -# been able to contact any other nodes, we can reason that the bootnode we used is not well-connected -# or is otherwise uncontactable. - -# shellcheck source=scripts/ci/common/lib.sh -source "$(dirname "${0}")/../common/lib.sh" -CHAINSPEC_FILE="$1" -RUNTIME=$(basename "$CHAINSPEC_FILE" | cut -d '.' -f 1) - -trap cleanup EXIT INT TERM - -cleanup(){ - echo "[+] Script interrupted or ended. Cleaning up..." - # Kill all the polkadot processes - killall polkadot > /dev/null 2>&1 - exit $1 -} - -# count the number of bootnodes -BOOTNODES=$( jq -r '.bootNodes | length' "$CHAINSPEC_FILE" ) -# Make a temporary dir for chainspec files -# Store an array of the bad bootnodes -BAD_BOOTNODES=() -GOOD_BOOTNODES=() -PIDS=() - -echo "[+] Checking $BOOTNODES bootnodes for $RUNTIME" -for i in $(seq 0 $((BOOTNODES-1))); do - BOOTNODE=$( jq -r .bootNodes["$i"] < "$CHAINSPEC_FILE" ) - # Check each bootnode in parallel - check_bootnode "$BOOTNODE" "$CHAINSPEC_FILE" & - PIDS+=($!) - # Hold off 5 seconds between attempting to spawn nodes to stop the machine from getting overloaded - sleep 5 -done -RESPS=() -# Wait for all the nodes to finish -for pid in "${PIDS[@]}"; do - wait "$pid" - RESPS+=($?) -done -echo -# For any bootnodes that failed, add them to the bad bootnodes array -for i in "${!RESPS[@]}"; do - if [ "${RESPS[$i]}" -ne 0 ]; then - BAD_BOOTNODES+=("$( jq -r .bootNodes["$i"] < "$CHAINSPEC_FILE" )") - fi -done -# For any bootnodes that succeeded, add them to the good bootnodes array -for i in "${!RESPS[@]}"; do - if [ "${RESPS[$i]}" -eq 0 ]; then - GOOD_BOOTNODES+=("$( jq -r .bootNodes["$i"] < "$CHAINSPEC_FILE" )") - fi -done - -# If we've got any uncontactable bootnodes for this runtime, print them -if [ ${#BAD_BOOTNODES[@]} -gt 0 ]; then - echo "[!] Bad bootnodes found for $RUNTIME:" - for i in "${BAD_BOOTNODES[@]}"; do - echo " $i" - done - cleanup 1 -else - echo "[+] All bootnodes for $RUNTIME are contactable" - cleanup 0 -fi diff --git a/polkadot/scripts/ci/github/check_labels.sh b/polkadot/scripts/ci/github/check_labels.sh deleted file mode 100755 index 12f07b3495e..00000000000 --- a/polkadot/scripts/ci/github/check_labels.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bash - -#shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -repo="$GITHUB_REPOSITORY" -pr="$GITHUB_PR" - -ensure_labels() { - for label in "$@"; do - if has_label "$repo" "$pr" "$label"; then - return 0 - fi - done - return 1 -} - -# Must have one of the following labels -releasenotes_labels=( - 'B0-silent' - 'B1-releasenotes' - 'B7-runtimenoteworthy' -) - -# Must be an ordered list of priorities, lowest first -priority_labels=( - 'C1-low 📌' - 'C3-medium 📣' - 'C7-high ❗️' - 'C9-critical ‼️' -) - -audit_labels=( - 'D1-audited 👍' - 'D2-notlive 💤' - 'D3-trivial 🧸' - 'D5-nicetohaveaudit ⚠️' - 'D9-needsaudit 👮' -) - -echo "[+] Checking release notes (B) labels for $CI_COMMIT_BRANCH" -if ensure_labels "${releasenotes_labels[@]}"; then - echo "[+] Release notes label detected. All is well." -else - echo "[!] Release notes label not detected. Please add one of: ${releasenotes_labels[*]}" - exit 1 -fi - -echo "[+] Checking release priority (C) labels for $CI_COMMIT_BRANCH" -if ensure_labels "${priority_labels[@]}"; then - echo "[+] Release priority label detected. All is well." -else - echo "[!] Release priority label not detected. Please add one of: ${priority_labels[*]}" - exit 1 -fi - -if has_runtime_changes "${BASE_SHA}" "${HEAD_SHA}"; then - echo "[+] Runtime changes detected. Checking audit (D) labels" - if ensure_labels "${audit_labels[@]}"; then - echo "[+] Release audit label detected. All is well." - else - echo "[!] Release audit label not detected. Please add one of: ${audit_labels[*]}" - exit 1 - fi -fi - -# If the priority is anything other than the lowest, we *must not* have a B0-silent -# label -if has_label "$repo" "$GITHUB_PR" 'B0-silent' && - ! has_label "$repo" "$GITHUB_PR" "${priority_labels[0]}"; then - echo "[!] Changes with a priority higher than C1-low *MUST* have a B- label that is not B0-Silent" - exit 1 -fi - -exit 0 diff --git a/polkadot/scripts/ci/github/check_new_bootnodes.sh b/polkadot/scripts/ci/github/check_new_bootnodes.sh deleted file mode 100755 index 604db6a4e36..00000000000 --- a/polkadot/scripts/ci/github/check_new_bootnodes.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -set -e -# shellcheck source=scripts/ci/common/lib.sh -source "$(dirname "${0}")/../common/lib.sh" - -# This script checks any new bootnodes added since the last git commit - -RUNTIMES=( kusama westend polkadot ) - -WAS_ERROR=0 - -for RUNTIME in "${RUNTIMES[@]}"; do - CHAINSPEC_FILE="node/service/chain-specs/$RUNTIME.json" - # Get the bootnodes from master's chainspec - git show origin/master:"$CHAINSPEC_FILE" | jq '{"oldNodes": .bootNodes}' > "$RUNTIME-old-bootnodes.json" - # Get the bootnodes from the current branch's chainspec - git show HEAD:"$CHAINSPEC_FILE" | jq '{"newNodes": .bootNodes}' > "$RUNTIME-new-bootnodes.json" - # Make a chainspec containing only the new bootnodes - jq ".bootNodes = $(jq -rs '.[0] * .[1] | .newNodes-.oldNodes' \ - "$RUNTIME-new-bootnodes.json" "$RUNTIME-old-bootnodes.json")" \ - < "node/service/chain-specs/$RUNTIME.json" \ - > "$RUNTIME-new-chainspec.json" - # exit early if the new chainspec has no bootnodes - if [ "$(jq -r '.bootNodes | length' "$RUNTIME-new-chainspec.json")" -eq 0 ]; then - echo "[+] No new bootnodes for $RUNTIME" - # Clean up the temporary files - rm "$RUNTIME-new-chainspec.json" "$RUNTIME-old-bootnodes.json" "$RUNTIME-new-bootnodes.json" - continue - fi - # Check the new bootnodes - if ! "scripts/ci/github/check_bootnodes.sh" "$RUNTIME-new-chainspec.json"; then - WAS_ERROR=1 - fi - # Clean up the temporary files - rm "$RUNTIME-new-chainspec.json" "$RUNTIME-old-bootnodes.json" "$RUNTIME-new-bootnodes.json" -done - - -if [ $WAS_ERROR -eq 1 ]; then - echo "[!] One of the new bootnodes failed to connect. Please check logs above." - exit 1 -fi diff --git a/polkadot/scripts/ci/github/check_weights_swc.sh b/polkadot/scripts/ci/github/check_weights_swc.sh deleted file mode 100755 index 35652f4fde8..00000000000 --- a/polkadot/scripts/ci/github/check_weights_swc.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Need to set globstar for ** magic -shopt -s globstar - -RUNTIME=$1 -VERSION=$2 -echo "
" -echo "Weight changes for $RUNTIME" -echo -swc compare commits \ - --method asymptotic \ - --offline \ - --path-pattern "./runtime/$RUNTIME/src/weights/**/*.rs" \ - --no-color \ - --format markdown \ - --strip-path-prefix "runtime/$RUNTIME/src/weights/" \ - "$VERSION" - #--ignore-errors -echo -echo "
" diff --git a/polkadot/scripts/ci/github/extrinsic-ordering-filter.sh b/polkadot/scripts/ci/github/extrinsic-ordering-filter.sh deleted file mode 100755 index 4fd3337f64a..00000000000 --- a/polkadot/scripts/ci/github/extrinsic-ordering-filter.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -# This script is used in a Github Workflow. It helps filtering out what is interesting -# when comparing metadata and spot what would require a tx version bump. - -# shellcheck disable=SC2002,SC2086 - -FILE=$1 - -# Higlight indexes that were deleted -function find_deletions() { - echo "\n## Deletions\n" - RES=$(cat "$FILE" | grep -n '\[\-\]' | tr -s " ") - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' - else - echo "n/a" - fi -} - -# Highlight indexes that have been deleted -function find_index_changes() { - echo "\n## Index changes\n" - RES=$(cat "$FILE" | grep -E -n -i 'idx:\s*([0-9]+)\s*(->)\s*([0-9]+)' | tr -s " ") - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' - else - echo "n/a" - fi -} - -# Highlight values that decreased -function find_decreases() { - echo "\n## Decreases\n" - OUT=$(cat "$FILE" | grep -E -i -o '([0-9]+)\s*(->)\s*([0-9]+)' | awk '$1 > $3 { printf "%s;", $0 }') - IFS=$';' LIST=("$OUT") - unset RES - for line in "${LIST[@]}"; do - RES="$RES\n$(cat "$FILE" | grep -E -i -n \"$line\" | tr -s " ")" - done - - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' | sort -u -g | uniq - else - echo "n/a" - fi -} - -echo "\n------------------------------ SUMMARY -------------------------------" -echo "\n⚠️ This filter is here to help spotting changes that should be reviewed carefully." -echo "\n⚠️ It catches only index changes, deletions and value decreases". - -find_deletions "$FILE" -find_index_changes "$FILE" -find_decreases "$FILE" -echo "\n----------------------------------------------------------------------\n" diff --git a/polkadot/scripts/ci/github/generate_release_text.rb b/polkadot/scripts/ci/github/generate_release_text.rb deleted file mode 100644 index 83b3853a342..00000000000 --- a/polkadot/scripts/ci/github/generate_release_text.rb +++ /dev/null @@ -1,148 +0,0 @@ -# frozen_string_literal: true - -require 'base64' -require 'changelogerator' -require 'erb' -require 'git' -require 'json' -require 'octokit' -require 'toml' -require_relative './lib.rb' - -# A logger only active when NOT running in CI -def logger(s) - puts "▶ DEBUG: %s" % [s] if ENV['CI'] != 'true' -end - -# Check if all the required ENV are set -# This is especially convenient when testing locally -def check_env() - if ENV['CI'] != 'true' then - logger("Running locally") - vars = ['GITHUB_REF', 'GITHUB_TOKEN', 'GITHUB_WORKSPACE', 'GITHUB_REPOSITORY', 'RUSTC_STABLE', 'RUSTC_NIGHTLY'] - vars.each { |x| - env = (ENV[x] || "") - if env.length > 0 then - logger("- %s:\tset: %s, len: %d" % [x, env.length > 0 || false, env.length]) - else - logger("- %s:\tset: %s, len: %d" % [x, env.length > 0 || false, env.length]) - end - } - end -end - -check_env() - -current_ref = ENV['GITHUB_REF'] -token = ENV['GITHUB_TOKEN'] - -logger("Connecting to Github") -github_client = Octokit::Client.new( - access_token: token -) - -polkadot_path = ENV['GITHUB_WORKSPACE'] + '/polkadot/' - -# Generate an ERB renderer based on the template .erb file -renderer = ERB.new( - File.read(File.join(polkadot_path, 'scripts/ci/github/polkadot_release.erb')), - trim_mode: '<>' -) - -# get ref of last polkadot release -last_ref = 'refs/tags/' + github_client.latest_release(ENV['GITHUB_REPOSITORY']).tag_name -logger("Last ref: " + last_ref) - -logger("Generate changelog for Polkadot") -polkadot_cl = Changelog.new( - 'paritytech/polkadot', last_ref, current_ref, token: token -) - -# Gets the substrate commit hash used for a given polkadot ref -def get_substrate_commit(client, ref) - cargo = TOML::Parser.new( - Base64.decode64( - client.contents( - ENV['GITHUB_REPOSITORY'], - path: 'Cargo.lock', - query: { ref: ref.to_s } - ).content - ) - ).parsed - cargo['package'].find { |p| p['name'] == 'sc-cli' }['source'].split('#').last -end - -substrate_prev_sha = get_substrate_commit(github_client, last_ref) -substrate_cur_sha = get_substrate_commit(github_client, current_ref) - -logger("Generate changelog for Substrate") -substrate_cl = Changelog.new( - 'paritytech/substrate', substrate_prev_sha, substrate_cur_sha, - token: token, - prefix: true -) - -# Combine all changes into a single array and filter out companions -all_changes = (polkadot_cl.changes + substrate_cl.changes).reject do |c| - c[:title] =~ /[Cc]ompanion/ -end - -# Set all the variables needed for a release - -misc_changes = Changelog.changes_with_label(all_changes, 'B1-releasenotes') -client_changes = Changelog.changes_with_label(all_changes, 'B5-clientnoteworthy') -runtime_changes = Changelog.changes_with_label(all_changes, 'B7-runtimenoteworthy') - -# Add the audit status for runtime changes -runtime_changes.each do |c| - if c[:labels].any? { |l| l[:name] == 'D1-audited 👍' } - c[:pretty_title] = "✅ `audited` #{c[:pretty_title]}" - next - end - if c[:labels].any? { |l| l[:name] == 'D2-notlive 💤' } - c[:pretty_title] = "✅ `not live` #{c[:pretty_title]}" - next - end - if c[:labels].any? { |l| l[:name] == 'D3-trivial 🧸' } - c[:pretty_title] = "✅ `trivial` #{c[:pretty_title]}" - next - end - if c[:labels].any? { |l| l[:name] == 'D5-nicetohaveaudit ⚠️' } - c[:pretty_title] = "⏳ `pending non-critical audit` #{c[:pretty_title]}" - next - end - if c[:labels].any? { |l| l[:name] == 'D9-needsaudit 👮' } - c[:pretty_title] = "❌ `AWAITING AUDIT` #{c[:pretty_title]}" - next - end - c[:pretty_title] = "⭕️ `unknown audit requirements` #{c[:pretty_title]}" -end - -# The priority of users upgraded is determined by the highest-priority -# *Client* change -release_priority = Changelog.highest_priority_for_changes(client_changes) - -# Pulled from the previous Github step -rustc_stable = ENV['RUSTC_STABLE'] -rustc_nightly = ENV['RUSTC_NIGHTLY'] -polkadot_runtime = get_runtime('polkadot', polkadot_path) -kusama_runtime = get_runtime('kusama', polkadot_path) -westend_runtime = get_runtime('westend', polkadot_path) -rococo_runtime = get_runtime('rococo', polkadot_path) - -# These json files should have been downloaded as part of the build-runtimes -# github action - -polkadot_json = JSON.parse( - File.read( - "#{ENV['GITHUB_WORKSPACE']}/polkadot-srtool-json/polkadot_srtool_output.json" - ) -) - -kusama_json = JSON.parse( - File.read( - "#{ENV['GITHUB_WORKSPACE']}/kusama-srtool-json/kusama_srtool_output.json" - ) -) - -puts renderer.result diff --git a/polkadot/scripts/ci/github/lib.rb b/polkadot/scripts/ci/github/lib.rb deleted file mode 100644 index 14663acaf31..00000000000 --- a/polkadot/scripts/ci/github/lib.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -# Gets the runtime version for a given runtime from the filesystem. -# Optionally accepts a path that is the root of the project which defaults to -# the current working directory -def get_runtime(runtime: nil, path: '.', runtime_dir: 'runtime') - File.open(path + "/#{runtime_dir}/#{runtime}/src/lib.rs") do |f| - f.find { |l| l =~ /spec_version/ }.match(/[0-9]+/)[0] - end -end diff --git a/polkadot/scripts/ci/github/polkadot_release.erb b/polkadot/scripts/ci/github/polkadot_release.erb deleted file mode 100644 index 3fcf07dddc5..00000000000 --- a/polkadot/scripts/ci/github/polkadot_release.erb +++ /dev/null @@ -1,42 +0,0 @@ -<%= print release_priority[:text] %> <%= puts " due to changes: *#{Changelog.changes_with_label(all_changes, release_priority[:label]).map(&:pretty_title).join(", ")}*" if release_priority[:priority] > 1 %> - -Native runtimes: - -- Polkadot: **<%= polkadot_runtime %>** -- Kusama: **<%= kusama_runtime %>** -- Westend: **<%= westend_runtime %>** - -This release was tested against the following versions of `rustc`. Other versions may work. - -- <%= rustc_stable %> -- <%= rustc_nightly %> - -WASM runtimes built with [<%= polkadot_json['info']['generator']['name'] %> v<%= polkadot_json['info']['generator']['version'] %>](https://github.com/paritytech/srtool) using `<%= polkadot_json['rustc'] %>`. - -Proposal hashes: -* `polkadot_runtime-v<%= polkadot_runtime %>.compact.compressed.wasm`: `<%= polkadot_json['runtimes']['compressed']['prop'] %>` -* `kusama_runtime-v<%= kusama_runtime %>.compact.compressed.wasm`: `<%= kusama_json['runtimes']['compressed']['prop'] %>` - -<% unless misc_changes.empty? %> -## Changes - -<% misc_changes.each do |c| %> -* <%= c[:pretty_title] %> -<% end %> -<% end %> - -<% unless client_changes.empty? %> -## Client - -<% client_changes.each do |c| %> -* <%= c[:pretty_title] %> -<% end %> -<% end %> - -<% unless runtime_changes.empty? %> -## Runtime - -<% runtime_changes.each do |c| %> -* <%= c[:pretty_title] %> -<% end %> -<% end %> diff --git a/polkadot/scripts/ci/github/run_fuzzer.sh b/polkadot/scripts/ci/github/run_fuzzer.sh deleted file mode 100755 index b73a83beab9..00000000000 --- a/polkadot/scripts/ci/github/run_fuzzer.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -timeout --signal INT 5h cargo hfuzz run $1 -status=$? - -if [ $status -ne 124 ]; then - echo "Found a panic!" - # TODO: provide Minimal Reproducible Input - # TODO: message on Matrix - exit 1 -else - echo "Didn't find any problem in 5 hours of fuzzing" -fi diff --git a/polkadot/scripts/ci/github/verify_updated_weights.sh b/polkadot/scripts/ci/github/verify_updated_weights.sh deleted file mode 100755 index 54db1de21ca..00000000000 --- a/polkadot/scripts/ci/github/verify_updated_weights.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -ROOT="$(dirname "$0")/../../.." -RUNTIME="$1" - -# If we're on a mac, use gdate for date command (requires coreutils installed via brew) -if [[ "$OSTYPE" == "darwin"* ]]; then - DATE="gdate" -else - DATE="date" -fi - -function check_date() { - # Get the dates as input arguments - LAST_RUN="$1" - TODAY="$($DATE +%Y-%m-%d)" - # Calculate the date two days before today - CUTOFF=$($DATE -d "$TODAY - 2 days" +%Y-%m-%d) - - if [[ "$LAST_RUN" > "$CUTOFF" ]]; then - return 0 - else - return 1 - fi -} - -check_weights(){ - FILE=$1 - CUR_DATE=$2 - DATE_REGEX='[0-9]{4}-[0-9]{2}-[0-9]{2}' - LAST_UPDATE="$(grep -E "//! DATE: $DATE_REGEX" "$FILE" | sed -r "s/.*DATE: ($DATE_REGEX).*/\1/")" - # If the file does not contain a date, flag it as an error. - if [ -z "$LAST_UPDATE" ]; then - echo "Skipping $FILE, no date found." - return 0 - fi - if ! check_date "$LAST_UPDATE" ; then - echo "ERROR: $FILE was not updated for the current date. Last update: $LAST_UPDATE" - return 1 - fi - # echo "OK: $FILE" -} - -echo "Checking weights for $RUNTIME" -CUR_DATE="$(date +%Y-%m-%d)" -HAS_ERROR=0 -for FILE in "$ROOT"/runtime/"$RUNTIME"/src/weights/*.rs; do - if ! check_weights "$FILE" "$CUR_DATE"; then - HAS_ERROR=1 - fi -done - -if [ $HAS_ERROR -eq 1 ]; then - echo "ERROR: One or more weights files were not updated during the last benchmark run. Check the logs above." - exit 1 -fi \ No newline at end of file diff --git a/polkadot/scripts/ci/gitlab/check_extrinsics_ordering.sh b/polkadot/scripts/ci/gitlab/check_extrinsics_ordering.sh deleted file mode 100755 index 8a7385f03f9..00000000000 --- a/polkadot/scripts/ci/gitlab/check_extrinsics_ordering.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -set -e - -# Include the common functions library -#shellcheck source=../common/lib.sh -. "$(dirname "${0}")/../common/lib.sh" - -HEAD_BIN=./artifacts/polkadot -HEAD_WS=ws://localhost:9944 -RELEASE_WS=ws://localhost:9945 - -runtimes=( - "westend" - "kusama" - "polkadot" -) - -# First we fetch the latest released binary -latest_release=$(latest_release 'paritytech/polkadot') -RELEASE_BIN="./polkadot-$latest_release" -echo "[+] Fetching binary for Polkadot version $latest_release" -curl -L "https://github.com/paritytech/polkadot/releases/download/$latest_release/polkadot" > "$RELEASE_BIN" || exit 1 -chmod +x "$RELEASE_BIN" - - -for RUNTIME in "${runtimes[@]}"; do - echo "[+] Checking runtime: ${RUNTIME}" - - release_transaction_version=$( - git show "origin/release:runtime/${RUNTIME}/src/lib.rs" | \ - grep 'transaction_version' - ) - - current_transaction_version=$( - grep 'transaction_version' "./runtime/${RUNTIME}/src/lib.rs" - ) - - echo "[+] Release: ${release_transaction_version}" - echo "[+] Ours: ${current_transaction_version}" - - if [ ! "$release_transaction_version" = "$current_transaction_version" ]; then - echo "[+] Transaction version for ${RUNTIME} has been bumped since last release." - exit 0 - fi - - # Start running the nodes in the background - $HEAD_BIN --chain="$RUNTIME-local" --tmp & - $RELEASE_BIN --chain="$RUNTIME-local" --ws-port 9945 --tmp & - jobs - - # Sleep a little to allow the nodes to spin up and start listening - TIMEOUT=5 - for i in $(seq $TIMEOUT); do - sleep 1 - if [ "$(lsof -nP -iTCP -sTCP:LISTEN | grep -c '994[45]')" == 2 ]; then - echo "[+] Both nodes listening" - break - fi - if [ "$i" == $TIMEOUT ]; then - echo "[!] Both nodes not listening after $i seconds. Exiting" - exit 1 - fi - done - sleep 5 - - changed_extrinsics=$( - polkadot-js-metadata-cmp "$RELEASE_WS" "$HEAD_WS" \ - | sed 's/^ \+//g' | grep -e 'idx: [0-9]\+ -> [0-9]\+' || true - ) - - if [ -n "$changed_extrinsics" ]; then - echo "[!] Extrinsics indexing/ordering has changed in the ${RUNTIME} runtime! If this change is intentional, please bump transaction_version in lib.rs. Changed extrinsics:" - echo "$changed_extrinsics" - exit 1 - fi - - echo "[+] No change in extrinsics ordering for the ${RUNTIME} runtime" - jobs -p | xargs kill; sleep 5 -done - -# Sleep a little to let the jobs die properly -sleep 5 diff --git a/polkadot/scripts/ci/gitlab/check_runtime.sh b/polkadot/scripts/ci/gitlab/check_runtime.sh deleted file mode 100755 index 9618bbfa1c7..00000000000 --- a/polkadot/scripts/ci/gitlab/check_runtime.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env bash - -# Check for any changes in any runtime directories (e.g., ^runtime/polkadot) as -# well as directories common to all runtimes (e.g., ^runtime/common). If there -# are no changes, check if the Substrate git SHA in Cargo.lock has been -# changed. If so, pull the repo and verify if {spec,impl}_versions have been -# altered since the previous Substrate version used. -# -# If there were changes to any runtimes or common dirs, we iterate over each -# runtime (defined in the $runtimes() array), and check if {spec,impl}_version -# have been changed since the last release. - -set -e # fail on any error - -#Include the common functions library -#shellcheck source=../common/lib.sh -. "$(dirname "${0}")/../common/lib.sh" - -SUBSTRATE_REPO="https://github.com/paritytech/substrate" -SUBSTRATE_REPO_CARGO="git\+${SUBSTRATE_REPO}" -SUBSTRATE_VERSIONS_FILE="bin/node/runtime/src/lib.rs" - -# figure out the latest release tag -boldprint "make sure we have all tags (including those from the release branch)" -git fetch --depth="${GIT_DEPTH:-100}" origin release -git fetch --depth="${GIT_DEPTH:-100}" origin 'refs/tags/*:refs/tags/*' -LATEST_TAG="$(git tag -l | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+-?[0-9]*$' | sort -V | tail -n 1)" -boldprint "latest release tag ${LATEST_TAG}" - -boldprint "latest 10 commits of ${CI_COMMIT_REF_NAME}" -git --no-pager log --graph --oneline --decorate=short -n 10 - -boldprint "make sure the master branch is available in shallow clones" -git fetch --depth="${GIT_DEPTH:-100}" origin master - - -runtimes=( - "kusama" - "polkadot" - "westend" - "rococo" -) - -common_dirs=( - "common" -) - -# Helper function to join elements in an array with a multi-char delimiter -# https://stackoverflow.com/questions/1527049/how-can-i-join-elements-of-an-array-in-bash -function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; } - -boldprint "check if the wasm sources changed since ${LATEST_TAG}" -if ! has_runtime_changes "${LATEST_TAG}" "${CI_COMMIT_SHA}"; then - boldprint "no changes to any runtime source code detected" - # continue checking if Cargo.lock was updated with a new substrate reference - # and if that change includes a {spec|impl}_version update. - - SUBSTRATE_REFS_CHANGED="$( - git diff "refs/tags/${LATEST_TAG}...${CI_COMMIT_SHA}" Cargo.lock \ - | sed -n -r "s~^[\+\-]source = \"${SUBSTRATE_REPO_CARGO}#([a-f0-9]+)\".*$~\1~p" | sort -u | wc -l - )" - - # check Cargo.lock for substrate ref change - case "${SUBSTRATE_REFS_CHANGED}" in - (0) - boldprint "substrate refs not changed in Cargo.lock" - exit 0 - ;; - (2) - boldprint "substrate refs updated since ${LATEST_TAG}" - ;; - (*) - boldprint "check unsupported: more than one commit targeted in repo ${SUBSTRATE_REPO_CARGO}" - exit 1 - esac - - - SUBSTRATE_PREV_REF="$( - git diff "refs/tags/${LATEST_TAG}...${CI_COMMIT_SHA}" Cargo.lock \ - | sed -n -r "s~^\-source = \"${SUBSTRATE_REPO_CARGO}#([a-f0-9]+)\".*$~\1~p" | sort -u | head -n 1 - )" - - SUBSTRATE_NEW_REF="$( - git diff "refs/tags/${LATEST_TAG}...${CI_COMMIT_SHA}" Cargo.lock \ - | sed -n -r "s~^\+source = \"${SUBSTRATE_REPO_CARGO}#([a-f0-9]+)\".*$~\1~p" | sort -u | head -n 1 - )" - - - boldcat < ${add_spec_version} - -EOT - continue - - else - # check for impl_version updates: if only the impl versions changed, we assume - # there is no consensus-critical logic that has changed. - - add_impl_version="$( - git diff refs/tags/"${LATEST_TAG}...${CI_COMMIT_SHA}" "runtime/${RUNTIME}/src/lib.rs" \ - | sed -n -r 's/^\+[[:space:]]+impl_version: +([0-9]+),$/\1/p' - )" - sub_impl_version="$( - git diff refs/tags/"${LATEST_TAG}...${CI_COMMIT_SHA}" "runtime/${RUNTIME}/src/lib.rs" \ - | sed -n -r 's/^\-[[:space:]]+impl_version: +([0-9]+),$/\1/p' - )" - - - # see if the impl version changed - if [ "${add_impl_version}" != "${sub_impl_version}" ] - then - boldcat < ${add_impl_version} - -EOT - continue - fi - - failed_runtime_checks+=("$RUNTIME") - fi -done - -if [ ${#failed_runtime_checks} -gt 0 ]; then - boldcat < ./artifacts/VERSION - - echo -n ${EXTRATAG} > ./artifacts/EXTRATAG - - echo -n ${CI_JOB_ID} > ./artifacts/BUILD_LINUX_JOB_ID - - RELEASE_VERSION=$(./artifacts/polkadot -V | awk '{print $2}'| awk -F "-" '{print $1}') - - echo -n "v${RELEASE_VERSION}" > ./artifacts/BUILD_RELEASE_VERSION - -build-test-collators: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .common-refs - - .compiler-info - - .collect-artifacts - script: - - time cargo build --locked --profile testnet --verbose -p test-parachain-adder-collator - - time cargo build --locked --profile testnet --verbose -p test-parachain-undying-collator - # pack artifacts - - mkdir -p ./artifacts - - mv ./target/testnet/adder-collator ./artifacts/. - - mv ./target/testnet/undying-collator ./artifacts/. - - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - - echo "adder-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - - echo "undying-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - -build-malus: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .common-refs - - .compiler-info - - .collect-artifacts - script: - - time cargo build --locked --profile testnet --verbose -p polkadot-test-malus - # pack artifacts - - mkdir -p ./artifacts - - mv ./target/testnet/malus ./artifacts/. - - mv ./target/testnet/polkadot-execute-worker ./artifacts/. - - mv ./target/testnet/polkadot-prepare-worker ./artifacts/. - - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - - echo "polkadot-test-malus = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - -build-staking-miner: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .common-refs - - .compiler-info - - .collect-artifacts - script: - - time cargo build --locked --release --package staking-miner - # pack artifacts - - mkdir -p ./artifacts - - mv ./target/release/staking-miner ./artifacts/. - - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - - echo "staking-miner = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - -build-rustdoc: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in test.yml - needs: - - job: test-deterministic-wasm - artifacts: false - extends: - - .docker-env - - .test-refs - variables: - SKIP_WASM_BUILD: 1 - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 1 days - paths: - - ./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 --workspace --verbose --no-deps - - rm -f ./target/doc/.lock - - mv ./target/doc ./crate-docs - # FIXME: remove me after CI image gets nonroot - - chown -R nonroot:nonroot ./crate-docs - - echo "" > ./crate-docs/index.html - -build-implementers-guide: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in test.yml - needs: - - job: test-deterministic-wasm - artifacts: false - extends: - - .kubernetes-env - - .test-refs - - .collect-artifacts-short - # git depth is set on purpose: https://github.com/paritytech/polkadot/issues/6284 - variables: - GIT_STRATEGY: clone - GIT_DEPTH: 0 - CI_IMAGE: paritytech/mdbook-utils:e14aae4a-20221123 - script: - - mdbook build ./roadmap/implementers-guide - - mkdir -p artifacts - - mv roadmap/implementers-guide/book artifacts/ - -build-short-benchmark: - stage: build - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .test-refs - - .collect-artifacts - script: - - cargo build --profile release --locked --features=runtime-benchmarks - - mkdir artifacts - - cp ./target/release/polkadot ./artifacts/ diff --git a/polkadot/scripts/ci/gitlab/pipeline/check.yml b/polkadot/scripts/ci/gitlab/pipeline/check.yml deleted file mode 100644 index 9b2ad5e7383..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/check.yml +++ /dev/null @@ -1,136 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "check" stage - -check-runtime: - stage: check - image: paritytech/tools:latest - extends: - - .kubernetes-env - rules: - - if: $CI_COMMIT_REF_NAME =~ /^release-v[0-9]+\.[0-9]+.*$/ # i.e. release-v0.9.27 - variables: - GITLAB_API: "https://gitlab.parity.io/api/v4" - GITHUB_API_PROJECT: "parity%2Finfrastructure%2Fgithub-api" - script: - - ./scripts/ci/gitlab/check_runtime.sh - allow_failure: true - -cargo-fmt: - stage: check - extends: - - .docker-env - - .test-refs - script: - - cargo +nightly --version - - cargo +nightly fmt --all -- --check - allow_failure: true - -# Disabled in https://github.com/paritytech/polkadot/pull/7512 -.spellcheck_disabled: - stage: check - extends: - - .docker-env - - .test-refs - script: - - cargo spellcheck --version - # compare with the commit parent to the PR, given it's from a default branch - - git fetch origin +${CI_DEFAULT_BRANCH}:${CI_DEFAULT_BRANCH} - - echo "___Spellcheck is going to check your diff___" - - cargo spellcheck list-files -vvv $(git diff --diff-filter=AM --name-only $(git merge-base ${CI_COMMIT_SHA} ${CI_DEFAULT_BRANCH} -- :^bridges)) - - time cargo spellcheck check -vvv --cfg=scripts/ci/gitlab/spellcheck.toml --checkers hunspell --code 1 - $(git diff --diff-filter=AM --name-only $(git merge-base ${CI_COMMIT_SHA} ${CI_DEFAULT_BRANCH} -- :^bridges)) - allow_failure: true - -check-try-runtime: - stage: check - extends: - - .docker-env - - .test-refs - - .compiler-info - script: - # Check that everything compiles with `try-runtime` feature flag. - - cargo check --locked --features try-runtime --all - -# More info can be found here: https://github.com/paritytech/polkadot/pull/5865 -.check-runtime-migration: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .compiler-info - 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 - 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 - -check-runtime-migration-polkadot: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .compiler-info - - .check-runtime-migration - variables: - NETWORK: "polkadot" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - -check-runtime-migration-kusama: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .compiler-info - - .check-runtime-migration - variables: - NETWORK: "kusama" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - -check-runtime-migration-westend: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .compiler-info - - .check-runtime-migration - variables: - NETWORK: "westend" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - -check-runtime-migration-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .compiler-info - - .check-runtime-migration - variables: - NETWORK: "rococo" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - -# is broken, need to fix -check-no-default-features: - stage: check - extends: - - .docker-env - - .test-refs - - .compiler-info - script: - # Check that polkadot-cli will compile no default features. - - pushd ./node/service && cargo check --locked --no-default-features && popd - - pushd ./cli && cargo check --locked --no-default-features --features "service" && popd - - exit 0 - -# this is artificial job to run some build and tests using DAG -job-starter: - stage: check - image: paritytech/tools:latest - extends: - - .kubernetes-env - - .common-refs - script: - - echo ok diff --git a/polkadot/scripts/ci/gitlab/pipeline/publish.yml b/polkadot/scripts/ci/gitlab/pipeline/publish.yml deleted file mode 100644 index c224094125e..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/publish.yml +++ /dev/null @@ -1,276 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "publish" stage - -# This image is used in testnets -# Release image is handled by the Github Action here: -# .github/workflows/publish-docker-release.yml -publish-polkadot-debug-image: - stage: publish - extends: - - .kubernetes-env - - .build-push-image - rules: - # Don't run when triggered from another pipeline - - 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 - variables: - IMAGE_NAME: "polkadot-debug" - BINARY: "polkadot,polkadot-execute-worker,polkadot-prepare-worker" - needs: - - job: build-linux-stable - artifacts: true - after_script: - - !reference [.build-push-image, after_script] - # pass artifacts to the zombienet-tests job - # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance - - echo "PARACHAINS_IMAGE_NAME=${IMAGE}" > ./artifacts/parachains.env - - echo "PARACHAINS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/parachains.env - artifacts: - reports: - # this artifact is used in zombienet-tests job - dotenv: ./artifacts/parachains.env - expire_in: 1 days - -publish-test-collators-image: - # service image for Simnet - stage: publish - extends: - - .kubernetes-env - - .build-push-image - - .zombienet-refs - variables: - IMAGE_NAME: "colander" - BINARY: "adder-collator,undying-collator" - needs: - - job: build-test-collators - artifacts: true - after_script: - - !reference [.build-push-image, after_script] - # pass artifacts to the zombienet-tests job - - echo "COLLATOR_IMAGE_NAME=${IMAGE}" > ./artifacts/collator.env - - echo "COLLATOR_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/collator.env - artifacts: - reports: - # this artifact is used in zombienet-tests job - dotenv: ./artifacts/collator.env - -publish-malus-image: - # service image for Simnet - stage: publish - extends: - - .kubernetes-env - - .build-push-image - - .zombienet-refs - variables: - IMAGE_NAME: "malus" - BINARY: "malus,polkadot-execute-worker,polkadot-prepare-worker" - needs: - - job: build-malus - artifacts: true - after_script: - - !reference [.build-push-image, after_script] - # pass artifacts to the zombienet-tests job - - echo "MALUS_IMAGE_NAME=${IMAGE}" > ./artifacts/malus.env - - echo "MALUS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/malus.env - artifacts: - reports: - # this artifact is used in zombienet-tests job - dotenv: ./artifacts/malus.env - -publish-staking-miner-image: - stage: publish - extends: - - .kubernetes-env - - .build-push-image - - .publish-refs - variables: - IMAGE_NAME: "staking-miner" - BINARY: "staking-miner" - DOCKER_OWNER: "paritytech" - DOCKER_USER: "${Docker_Hub_User_Parity}" - DOCKER_PASS: "${Docker_Hub_Pass_Parity}" - needs: - - job: build-staking-miner - artifacts: true - -publish-polkadot-image-description: - stage: publish - image: paritytech/dockerhub-description - variables: - DOCKER_USERNAME: ${Docker_Hub_User_Parity} - DOCKER_PASSWORD: ${Docker_Hub_Pass_Parity} - DOCKERHUB_REPOSITORY: parity/polkadot - SHORT_DESCRIPTION: "Polkadot Official Docker Image" - README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md - rules: - - if: $CI_COMMIT_REF_NAME == "master" - changes: - - scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md - - if: $CI_PIPELINE_SOURCE == "schedule" - when: never - script: - - cd / && sh entrypoint.sh - tags: - - kubernetes-parity-build - -publish-staking-miner-image-description: - stage: publish - image: paritytech/dockerhub-description - variables: - DOCKER_USERNAME: ${Docker_Hub_User_Parity} - DOCKER_PASSWORD: ${Docker_Hub_Pass_Parity} - DOCKERHUB_REPOSITORY: paritytech/staking-miner - SHORT_DESCRIPTION: "Staking-miner Docker Image" - README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md - rules: - - if: $CI_COMMIT_REF_NAME == "master" - changes: - - scripts/ci/dockerfiles/staking-miner/staking-miner_Dockerfile.README.md - - if: $CI_PIPELINE_SOURCE == "schedule" - when: never - script: - - cd / && sh entrypoint.sh - tags: - - kubernetes-parity-build - -publish-s3-release: - stage: publish - extends: - - .kubernetes-env - needs: - - job: build-linux-stable - artifacts: true - variables: - CI_IMAGE: paritytech/awscli:latest - GIT_STRATEGY: none - PREFIX: "builds/polkadot/${ARCH}-${DOCKER_OS}" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - # publishing binaries nightly - - if: $CI_PIPELINE_SOURCE == "schedule" - before_script: - - !reference [.build-push-image, before_script] - script: - - echo "uploading objects to https://releases.parity.io/${PREFIX}/${VERSION}" - - aws s3 sync --acl public-read ./artifacts/ s3://${AWS_BUCKET}/${PREFIX}/${VERSION}/ - - echo "update objects at https://releases.parity.io/${PREFIX}/${EXTRATAG}" - - find ./artifacts -type f | while read file; do - name="${file#./artifacts/}"; - aws s3api copy-object - --copy-source ${AWS_BUCKET}/${PREFIX}/${VERSION}/${name} - --bucket ${AWS_BUCKET} --key ${PREFIX}/${EXTRATAG}/${name}; - done - - | - cat <<-EOM - | - | polkadot binary paths: - | - | - https://releases.parity.io/${PREFIX}/${EXTRATAG}/polkadot - | - https://releases.parity.io/${PREFIX}/${VERSION}/polkadot - | - EOM - after_script: - - aws s3 ls s3://${AWS_BUCKET}/${PREFIX}/${EXTRATAG}/ - --recursive --human-readable --summarize - -publish-rustdoc: - stage: publish - extends: - - .kubernetes-env - variables: - CI_IMAGE: paritytech/tools:latest - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" - # `needs:` can be removed after CI image gets nonroot. In this case `needs:` stops other - # artifacts from being dowloaded by this job. - needs: - - job: build-rustdoc - artifacts: true - - job: build-implementers-guide - artifacts: true - script: - # Save README and docs - - cp -r ./crate-docs/ /tmp/doc/ - - cp -r ./artifacts/book/ /tmp/ - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - - git checkout gh-pages - # Remove everything and restore generated docs and README - - cp index.html /tmp - - cp README.md /tmp - - rm -rf ./* - # dir for rustdoc - - mkdir -p doc - # dir for implementors guide - - mkdir -p book - - mv /tmp/doc/* doc/ - - mv /tmp/book/html/* book/ - - mv /tmp/index.html . - - mv /tmp/README.md . - # Upload files - - git add --all --force - # `git commit` has an exit code of > 0 if there is nothing to commit. - # This causes GitLab to exit immediately and marks this job failed. - # We don't want to mark the entire job failed if there's nothing to - # publish though, hence the `|| true`. - - git commit -m "Updated docs for ${CI_COMMIT_REF_NAME}" || - echo "___Nothing to commit___" - - git push origin gh-pages --force - - echo "___Rustdoc was successfully published to https://paritytech.github.io/polkadot/___" - after_script: - - rm -rf .git/ ./* - -.update-substrate-template-repository: - stage: publish - extends: .kubernetes-env - variables: - GIT_STRATEGY: none - rules: - # The template is only updated for FINAL releases - # i.e. the rule should not cover RC or patch releases - - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+$/ # e.g. v1.0 - - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ # e.g. v1.0.0 - script: - - git clone --depth=1 --branch="$PIPELINE_SCRIPTS_TAG" https://github.com/paritytech/pipeline-scripts - - export POLKADOT_BRANCH="polkadot-$CI_COMMIT_TAG" - - git clone --depth=1 --branch="$POLKADOT_BRANCH" https://github.com/paritytech/"$TEMPLATE_SOURCE" - - cd "$TEMPLATE_SOURCE" - - ../pipeline-scripts/update_substrate_template.sh - --repo-name "$TARGET_REPOSITORY" - --template-path "$TEMPLATE_PATH" - --github-api-token "$GITHUB_TOKEN" - --polkadot-branch "$POLKADOT_BRANCH" - -# Ref: https://github.com/paritytech/opstooling/issues/111 -update-node-template: - extends: .update-substrate-template-repository - variables: - TARGET_REPOSITORY: substrate-node-template - TEMPLATE_SOURCE: substrate - TEMPLATE_PATH: bin/node-template - -# Ref: https://github.com/paritytech/opstooling/issues/111 -update-parachain-template: - extends: .update-substrate-template-repository - variables: - TARGET_REPOSITORY: substrate-parachain-template - TEMPLATE_SOURCE: cumulus - TEMPLATE_PATH: parachain-template diff --git a/polkadot/scripts/ci/gitlab/pipeline/short-benchmarks.yml b/polkadot/scripts/ci/gitlab/pipeline/short-benchmarks.yml deleted file mode 100644 index dd150e5916e..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/short-benchmarks.yml +++ /dev/null @@ -1,27 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "short-benchmarks" stage - -# Run all pallet benchmarks only once to check if there are any errors -short-benchmark-polkadot: &short-bench - stage: short-benchmarks - extends: - - .test-pr-refs - - .docker-env - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-short-benchmark - artifacts: true - variables: - RUNTIME: polkadot - script: - - ./artifacts/polkadot benchmark pallet --wasm-execution compiled --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 diff --git a/polkadot/scripts/ci/gitlab/pipeline/test.yml b/polkadot/scripts/ci/gitlab/pipeline/test.yml deleted file mode 100644 index 963df0aa030..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/test.yml +++ /dev/null @@ -1,119 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "test" stage - -# It's more like a check and it belongs to the previous stage, but we want to run this job with real tests in parallel -find-fail-ci-phrase: - stage: test - variables: - CI_IMAGE: "paritytech/tools:latest" - ASSERT_REGEX: "FAIL-CI" - GIT_DEPTH: 1 - extends: - - .kubernetes-env - script: - - set +e - - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - - if [ $exit_status -eq 0 ]; then - echo "$ASSERT_REGEX was found, exiting with 1"; - exit 1; - else - echo "No $ASSERT_REGEX was found, exiting with 0"; - exit 0; - fi - -test-linux-stable: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .common-refs - - .pipeline-stopper-artifacts - before_script: - - !reference [.compiler-info, before_script] - - !reference [.pipeline-stopper-vars, before_script] - variables: - RUST_TOOLCHAIN: stable - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo test --workspace --profile testnet --verbose --locked --features=runtime-benchmarks,runtime-metrics,try-runtime,ci-only-tests - # Run `polkadot-runtime-parachains` tests a second time because `paras_inherent::enter` tests are gated by not having - # the `runtime-benchmarks` feature enabled. - - time cargo test --profile testnet --verbose --locked --features=runtime-metrics,try-runtime -p polkadot-runtime-parachains - -test-linux-oldkernel-stable: - extends: test-linux-stable - tags: - - oldkernel-vm - -.check-dependent-project: &check-dependent-project - stage: test - extends: - - .docker-env - - .test-pr-refs - script: - - git clone - --depth=1 - "--branch=$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts - - ./pipeline-scripts/check_dependent_project.sh - --org paritytech - --dependent-repo "$DEPENDENT_REPO" - --github-api-token "$GITHUB_PR_TOKEN" - --extra-dependencies "$EXTRA_DEPENDENCIES" - --companion-overrides "$COMPANION_OVERRIDES" - -check-dependent-cumulus: - <<: *check-dependent-project - variables: - DEPENDENT_REPO: cumulus - EXTRA_DEPENDENCIES: substrate - COMPANION_OVERRIDES: | - polkadot: release-v* - cumulus: polkadot-v* - -test-node-metrics: - stage: test - extends: - - .docker-env - - .test-refs - - .compiler-info - variables: - RUST_TOOLCHAIN: stable - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - # Build the required workers. - - cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker --profile testnet --verbose --locked - # Run tests. - - time cargo test --profile testnet --verbose --locked --features=runtime-metrics -p polkadot-node-metrics - -test-deterministic-wasm: - stage: test - extends: - - .docker-env - - .test-refs - - .compiler-info - script: - - ./scripts/ci/gitlab/test_deterministic_wasm.sh - -cargo-clippy: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - # the job can be found in check.yml - needs: - - job: job-starter - artifacts: false - extends: - - .docker-env - - .test-refs - script: - - echo $RUSTFLAGS - - cargo version && cargo clippy --version - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy -q --locked --all-targets --workspace diff --git a/polkadot/scripts/ci/gitlab/pipeline/weights.yml b/polkadot/scripts/ci/gitlab/pipeline/weights.yml deleted file mode 100644 index edca9e769b4..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/weights.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "weights" stage - -update_polkadot_weights: &update-weights - # The update-weights pipeline defaults to `interruptible: false` so that we'll be able to - # reach and run the benchmarking jobs despite the "Auto-cancel redundant pipelines" CI setting. - # The setting is relevant because future pipelines (e.g. created for new commits or other schedules) - # might otherwise cancel the benchmark jobs early. - interruptible: false - stage: weights - timeout: 1d - when: manual - image: $CI_IMAGE - variables: - RUNTIME: polkadot - artifacts: - paths: - - ${RUNTIME}_weights_${CI_COMMIT_SHORT_SHA}.patch - script: - - ./scripts/ci/run_benches_for_runtime.sh $RUNTIME - - git diff -P > ${RUNTIME}_weights_${CI_COMMIT_SHORT_SHA}.patch - # uses the "shell" executors - tags: - - weights - -update_kusama_weights: - <<: *update-weights - variables: - RUNTIME: kusama - -update_westend_weights: - <<: *update-weights - variables: - RUNTIME: westend - -update_rococo_weights: - <<: *update-weights - variables: - RUNTIME: rococo diff --git a/polkadot/scripts/ci/gitlab/pipeline/zombienet.yml b/polkadot/scripts/ci/gitlab/pipeline/zombienet.yml deleted file mode 100644 index 62e081d1de0..00000000000 --- a/polkadot/scripts/ci/gitlab/pipeline/zombienet.yml +++ /dev/null @@ -1,444 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "zombienet" stage - -zombienet-tests-parachains-smoke-test: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-malus-image - - job: publish-test-collators-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE="docker.io/paritypr/colander:7292" # The collator image is fixed - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0001-parachains-smoke-test.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-parachains-pvf: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0001-parachains-pvf.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-parachains-disputes: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: publish-malus-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0002-parachains-disputes.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-parachains-disputes-garbage-candidate: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: publish-malus-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0003-parachains-garbage-candidate.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-parachains-disputes-past-session: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: publish-malus-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0004-parachains-disputes-past-session.zndsl" - allow_failure: true - retry: 2 - tags: - - zombienet-polkadot-integration-test - - -zombienet-test-parachains-upgrade-smoke-test: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-malus-image - - job: publish-test-collators-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" - before_script: - - echo "ZombieNet Tests Config" - - echo "${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG}" - - echo "docker.io/parity/polkadot-collator:latest" - - echo "${ZOMBIENET_IMAGE}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export COL_IMAGE="docker.io/parity/polkadot-collator:latest" # Use cumulus lastest image - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0002-parachains-upgrade-smoke-test.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-misc-paritydb: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/misc" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0001-paritydb.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-misc-upgrade-node: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: build-linux-stable - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/misc" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE="docker.io/parity/polkadot:latest" - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - - BUILD_LINUX_JOB_ID="$(cat ./artifacts/BUILD_LINUX_JOB_ID)" - - export POLKADOT_PR_ARTIFACTS_URL="https://gitlab.parity.io/parity/mirrors/polkadot/-/jobs/${BUILD_LINUX_JOB_ID}/artifacts/raw/artifacts" - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0002-upgrade-node.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-malus-dispute-valid: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - - job: publish-malus-image - - job: publish-test-collators-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/node/malus/integrationtests" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie* - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0001-dispute-valid-block.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-deregister-register-validator: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie* - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0003-deregister-register-validator-smoke.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-beefy-and-mmr: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - extends: - - .kubernetes-env - - .zombienet-refs - needs: - - job: publish-polkadot-debug-image - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie* - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="0003-beefy-and-mmr.zndsl" - allow_failure: true - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-async-backing-compatibility: - stage: zombienet - extends: - - .kubernetes-env - - .zombienet-refs - image: "${ZOMBIENET_IMAGE}" - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: build-linux-stable - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="001-async-backing-compatibility.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-async-backing-runtime-upgrade: - stage: zombienet - extends: - - .kubernetes-env - - .zombienet-refs - image: "${ZOMBIENET_IMAGE}" - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: build-linux-stable - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - - export POLKADOT_PR_BIN_URL="https://gitlab.parity.io/parity/mirrors/polkadot/-/jobs/${BUILD_LINUX_JOB_ID}/artifacts/raw/artifacts/polkadot" - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="002-async-backing-runtime-upgrade.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-tests-async-backing-collator-mix: - stage: zombienet - extends: - - .kubernetes-env - - .zombienet-refs - image: "${ZOMBIENET_IMAGE}" - needs: - - job: publish-polkadot-debug-image - - job: publish-test-collators-image - - job: build-linux-stable - artifacts: true - variables: - RUN_IN_CONTAINER: "1" - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" - - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --test="003-async-backing-collator-mix.zndsl" - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test diff --git a/polkadot/scripts/ci/gitlab/prettier.sh b/polkadot/scripts/ci/gitlab/prettier.sh deleted file mode 100755 index 299bbee179d..00000000000 --- a/polkadot/scripts/ci/gitlab/prettier.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# meant to be installed via -# git config filter.ci-prettier.clean "scripts/ci/gitlab/prettier.sh" - -prettier --parser yaml diff --git a/polkadot/scripts/ci/gitlab/spellcheck.toml b/polkadot/scripts/ci/gitlab/spellcheck.toml deleted file mode 100644 index 636cafa2cc4..00000000000 --- a/polkadot/scripts/ci/gitlab/spellcheck.toml +++ /dev/null @@ -1,34 +0,0 @@ -[hunspell] -lang = "en_US" -search_dirs = ["."] -extra_dictionaries = ["lingua.dic"] -skip_os_lookups = true -use_builtin = true - -[hunspell.quirks] -# He tagged it as 'TheGreatestOfAllTimes' -transform_regex = [ -# `Type`'s - "^'([^\\s])'$", -# 5x -# 10.7% - "^[0-9_]+(?:\\.[0-9]*)?(x|%)$", -# Transforms' - "^(.*)'$", -# backslashes - "^\\+$", - "^[0-9]*+k|MB|Mb|ms|Mbit|nd|th|rd$", -# single char `=` `>` `%` .. - "^=|>|<|%$", -# 22_100 - "^(?:[0-9]+_)+[0-9]+$", -# V5, v5, P1.2, etc - "[A-Za-z][0-9]", -# ~50 - "~[0-9]+", - "ABI", - "bool", - "sigil", -] -allow_concatenation = true -allow_dashes = true diff --git a/polkadot/scripts/ci/gitlab/test_deterministic_wasm.sh b/polkadot/scripts/ci/gitlab/test_deterministic_wasm.sh deleted file mode 100755 index b4292376942..00000000000 --- a/polkadot/scripts/ci/gitlab/test_deterministic_wasm.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -#shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -# build runtime -WASM_BUILD_NO_COLOR=1 cargo build --verbose --release -p kusama-runtime -p polkadot-runtime -p westend-runtime -# make checksum -sha256sum target/release/wbuild/*-runtime/target/wasm32-unknown-unknown/release/*.wasm > checksum.sha256 -# clean up - FIXME: can we reuse some of the artifacts? -cargo clean -# build again -WASM_BUILD_NO_COLOR=1 cargo build --verbose --release -p kusama-runtime -p polkadot-runtime -p westend-runtime -# confirm checksum -sha256sum -c checksum.sha256 diff --git a/polkadot/scripts/ci/run_benches_for_runtime.sh b/polkadot/scripts/ci/run_benches_for_runtime.sh deleted file mode 100755 index 296985a4276..00000000000 --- a/polkadot/scripts/ci/run_benches_for_runtime.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash - -# Runs all benchmarks for all pallets, for a given runtime, provided by $1 -# Should be run on a reference machine to gain accurate benchmarks -# current reference machine: https://github.com/paritytech/substrate/pull/5848 - -runtime="$1" - -echo "[+] Compiling benchmarks..." -cargo build --profile production --locked --features=runtime-benchmarks - -# Load all pallet names in an array. -PALLETS=($( - ./target/production/polkadot benchmark pallet --list --chain="${runtime}-dev" |\ - tail -n+2 |\ - cut -d',' -f1 |\ - sort |\ - uniq -)) - -echo "[+] Benchmarking ${#PALLETS[@]} pallets for runtime $runtime" - -# Define the error file. -ERR_FILE="benchmarking_errors.txt" -# Delete the error file before each run. -rm -f $ERR_FILE - -# Benchmark each pallet. -for PALLET in "${PALLETS[@]}"; do - echo "[+] Benchmarking $PALLET for $runtime"; - - output_file="" - if [[ $PALLET == *"::"* ]]; then - # translates e.g. "pallet_foo::bar" to "pallet_foo_bar" - output_file="${PALLET//::/_}.rs" - fi - - OUTPUT=$( - ./target/production/polkadot benchmark pallet \ - --chain="${runtime}-dev" \ - --steps=50 \ - --repeat=20 \ - --pallet="$PALLET" \ - --extrinsic="*" \ - --wasm-execution=compiled \ - --header=./file_header.txt \ - --output="./runtime/${runtime}/src/weights/${output_file}" 2>&1 - ) - if [ $? -ne 0 ]; then - echo "$OUTPUT" >> "$ERR_FILE" - echo "[-] Failed to benchmark $PALLET. Error written to $ERR_FILE; continuing..." - fi -done - -# Update the block and extrinsic overhead weights. -echo "[+] Benchmarking block and extrinsic overheads..." -OUTPUT=$( - ./target/production/polkadot benchmark overhead \ - --chain="${runtime}-dev" \ - --wasm-execution=compiled \ - --weight-path="runtime/${runtime}/constants/src/weights/" \ - --warmup=10 \ - --repeat=100 \ - --header=./file_header.txt -) -if [ $? -ne 0 ]; then - echo "$OUTPUT" >> "$ERR_FILE" - echo "[-] Failed to benchmark the block and extrinsic overheads. Error written to $ERR_FILE; continuing..." -fi - -# Check if the error file exists. -if [ -f "$ERR_FILE" ]; then - echo "[-] Some benchmarks failed. See: $ERR_FILE" -else - echo "[+] All benchmarks passed." -fi -- GitLab From c5060a5d5a018a9a6d82adc37036accf25f962ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:54:15 +0200 Subject: [PATCH 021/633] Bump the known_good_semver group with 2 updates (#1284) Bumps the known_good_semver group with 2 updates: [serde](https://github.com/serde-rs/serde) and [clap](https://github.com/clap-rs/clap). Updates `serde` from 1.0.186 to 1.0.188 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.186...v1.0.188) Updates `clap` from 4.4.0 to 4.4.1 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.4.0...v4.4.1) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 72 +++++++++---------- cumulus/client/cli/Cargo.toml | 2 +- .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 4 +- .../pallets/template/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 +- .../bridge-hub-polkadot/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 4 +- cumulus/test/service/Cargo.toml | 4 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/parachain/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/kusama/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/polkadot/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/utils/staking-miner/Cargo.toml | 4 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 4 +- substrate/bin/node/cli/Cargo.toml | 6 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 4 +- .../client/consensus/babe/rpc/Cargo.toml | 2 +- substrate/client/consensus/beefy/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/grandpa/Cargo.toml | 2 +- .../client/consensus/grandpa/rpc/Cargo.toml | 2 +- .../merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/tracing/Cargo.toml | 2 +- substrate/client/transaction-pool/Cargo.toml | 2 +- .../client/transaction-pool/api/Cargo.toml | 2 +- substrate/frame/beefy-mmr/Cargo.toml | 2 +- substrate/frame/beefy/Cargo.toml | 2 +- substrate/frame/benchmarking/Cargo.toml | 2 +- substrate/frame/conviction-voting/Cargo.toml | 2 +- substrate/frame/democracy/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- substrate/frame/message-queue/Cargo.toml | 2 +- substrate/frame/offences/Cargo.toml | 2 +- substrate/frame/referenda/Cargo.toml | 2 +- substrate/frame/remark/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- .../frame/state-trie-migration/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 2 +- .../frame/support/test/pallet/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/tips/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../frame/transaction-storage/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- .../primitives/application-crypto/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- .../primitives/consensus/babe/Cargo.toml | 2 +- .../primitives/consensus/beefy/Cargo.toml | 2 +- .../primitives/consensus/grandpa/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- .../merkle-mountain-range/Cargo.toml | 2 +- .../primitives/npos-elections/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- substrate/primitives/rpc/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/primitives/staking/Cargo.toml | 2 +- substrate/primitives/storage/Cargo.toml | 2 +- .../primitives/test-primitives/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/primitives/weights/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 4 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../frame/remote-externalities/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 4 +- 99 files changed, 144 insertions(+), 144 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 781e464d125..6f54299b7a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2355,7 +2355,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.0", + "clap 4.4.1", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2486,9 +2486,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" +checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" dependencies = [ "clap_builder", "clap_derive 4.4.0", @@ -2497,9 +2497,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" +checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" dependencies = [ "anstream", "anstyle", @@ -2513,7 +2513,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", ] [[package]] @@ -3113,7 +3113,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.0", + "clap 4.4.1", "criterion-plot", "futures", "is-terminal", @@ -3278,7 +3278,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3971,7 +3971,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.0", + "clap 4.4.1", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -5218,7 +5218,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.0", + "clap 4.4.1", "comfy-table", "frame-benchmarking", "frame-support", @@ -5310,7 +5310,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -8345,7 +8345,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.4.0", + "clap 4.4.1", "derive_more", "fs_extra", "futures", @@ -8382,7 +8382,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.4.0", + "clap 4.4.1", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8508,7 +8508,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8562,7 +8562,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "generate-bags", "kitchensink-runtime", ] @@ -8571,7 +8571,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8614,7 +8614,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "flate2", "fs_extra", "glob", @@ -11016,7 +11016,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11746,7 +11746,7 @@ dependencies = [ name = "polkadot-cli" version = "1.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "frame-benchmarking-cli", "futures", "log", @@ -12579,7 +12579,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.0", + "clap 4.4.1", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -13176,7 +13176,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.0", + "clap 4.4.1", "color-eyre", "futures", "futures-timer", @@ -13322,7 +13322,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "generate-bags", "kusama-runtime", "polkadot-runtime", @@ -14084,7 +14084,7 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "frame-system", "kusama-runtime", "kusama-runtime-constants", @@ -14792,7 +14792,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.4.0", + "clap 4.4.1", "fdlimit", "futures", "futures-timer", @@ -15896,7 +15896,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "fs4", "log", "sc-client-db", @@ -16335,18 +16335,18 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -17424,7 +17424,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17855,7 +17855,7 @@ name = "staking-miner" version = "1.0.0" dependencies = [ "assert_cmd", - "clap 4.4.0", + "clap 4.4.1", "exitcode", "frame-election-provider-support", "frame-remote-externalities", @@ -18009,7 +18009,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "sc-cli", ] @@ -18051,7 +18051,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "frame-support", "frame-system", "sc-cli", @@ -18530,7 +18530,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "futures", "futures-timer", "log", @@ -18579,7 +18579,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.0", + "clap 4.4.1", "futures", "futures-timer", "log", @@ -19255,7 +19255,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.0", + "clap 4.4.1", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 40c53ae919a..9f818ef846c 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.3.24", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 1056efd2dc8..9797c512505 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -33,7 +33,7 @@ tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" serde_json = "1.0.105" -serde = "1.0.183" +serde = "1.0.188" schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index f4fdfc64fac..09938ede01a 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -11,10 +11,10 @@ build = "build.rs" publish = false [dependencies] -clap = { version = "4.3.24", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } -serde = { version = "1.0.183", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.28" diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index e06f836c3be..af35ab651dc 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -21,7 +21,7 @@ frame-support = { path = "../../../../substrate/frame/support", default-features frame-system = { path = "../../../../substrate/frame/system", default-features = false} [dev-dependencies] -serde = { version = "1.0.183" } +serde = { version = "1.0.188" } # Substrate sp-core = { path = "../../../../substrate/primitives/core", default-features = false} 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 f29ee82b7cb..1370838fec1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -13,7 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = 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"] } -serde = { version = "1.0.183", optional = true, features = ["derive"] } +serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" # Substrate 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 87afb20eb90..a9c14af6dd3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -13,7 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = 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"] } -serde = { version = "1.0.183", optional = true, features = ["derive"] } +serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" # Substrate 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 95bf4c16967..af187bdb40e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -13,7 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = 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"] } -serde = { version = "1.0.183", optional = true, features = ["derive"] } +serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 8ae7a1f25f3..aff88e1fa6e 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -12,12 +12,12 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.3.24", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.20" -serde = { version = "1.0.183", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.105" # Local diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 2869af94a77..04247dd0248 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -11,12 +11,12 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.3.24", features = ["derive"] } +clap = { version = "4.4.1", 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"] } rand = "0.8.5" -serde = { version = "1.0.183", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } tokio = { version = "1.32.0", features = ["macros"] } tracing = "0.1.37" url = "2.4.0" diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 2da40193e96..8a5b2d04461 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.0.9", features = ["derive"], optional = true } +clap = { version = "4.4.1", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.31" futures = "0.3.21" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 6f39368168f..f94e19ad521 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.0.9", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index fcd7d4b3af9..33893ebeba6 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -20,7 +20,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime" } polkadot-parachain = { path = "../../parachain", default-features = false } schnorrkel = "0.9.1" thiserror = "1.0.31" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.11.2", default-features = false } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 3c89f1d2a54..0948a3c55d2 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -77,7 +77,7 @@ frame-benchmarking = { path = "../../../substrate/frame/benchmarking" } futures = "0.3.21" hex-literal = "0.4.1" gum = { package = "tracing-gum", path = "../gum" } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.96" thiserror = "1.0.31" kvdb = "0.13.0" diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index b51ed8e9ecf..86db6cb9bab 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -21,7 +21,7 @@ derive_more = "0.99.11" bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } # all optional crates. -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } [features] default = [ "std" ] diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index f706156d0cd..1a013fa0b1e 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -18,7 +18,7 @@ required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.0.9", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index c5eae3802c6..2cb44fd25a6 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -18,7 +18,7 @@ required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.0.9", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } futures = "0.3.19" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 520d10261be..c29159d18f9 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -10,7 +10,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive", "serde"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } application-crypto = { package = "sp-application-crypto", path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } inherents = { package = "sp-inherents", path = "../../substrate/primitives/inherents", default-features = false } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 484eb826f29..7574374b46a 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -12,7 +12,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["alloc"] } +serde = { version = "1.0.188", default-features = false, features = ["alloc"] } serde_derive = { version = "1.0.117" } static_assertions = "1.1.0" diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 3d7d1c9c5cb..e226b510739 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -12,7 +12,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ 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.163", 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" diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 73f95c09292..865ab44ac54 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -11,7 +11,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } derive_more = "0.99.17" bitflags = "1.3.2" diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 1cd5abfdd6d..7458df46351 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -12,7 +12,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ 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.163", 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" diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index e552920243d..cec95481633 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.163", 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" diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 8e212673a39..3413319410d 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false } +serde = { version = "1.0.188", default-features = false } serde_derive = { version = "1.0.117", optional = true } smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index a0410dc7d3c..b1f9cf6f0cc 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -12,7 +12,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ 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.163", default-features = false } +serde = { version = "1.0.188", default-features = false } serde_derive = { version = "1.0.117", optional = true } smallvec = "1.8.0" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index de5ec422ff4..1fdd6a107c6 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.0.9", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 3e5ccdb44d3..d1019317f6d 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -19,6 +19,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.0.9", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml index 5ca528235a5..b9cddcb656e 100644 --- a/polkadot/utils/staking-miner/Cargo.toml +++ b/polkadot/utils/staking-miner/Cargo.toml @@ -12,12 +12,12 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -clap = { version = "4.0.9", features = ["derive", "env"] } +clap = { version = "4.4.1", features = ["derive", "env"] } tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } jsonrpsee = { version = "0.16.2", features = ["ws-client", "macros"] } log = "0.4.17" paste = "1.0.7" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0" thiserror = "1.0.31" tokio = { version = "1.24.2", features = ["macros", "rt-multi-thread", "sync"] } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index ba1944ebe85..6f442b14769 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -14,7 +14,7 @@ log = { version = "0.4.17", default-features = false } 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", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } -serde = { version = "1.0.163", default-features = false, features = ["alloc", "derive"] } +serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } xcm-procedural = { path = "procedural" } [dev-dependencies] diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index f98741d01bd..1fd44d882e6 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -10,7 +10,7 @@ version = "1.0.0" bounded-collections = { version = "0.1.8", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true, features = ["derive"] } +serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 834668468f7..b89cd0c7088 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index c98547a33d6..8f55aab5a16 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } @@ -21,7 +21,7 @@ kitchensink-runtime = { path = "../runtime" } sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 01e8d871665..330256dd2e5 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -38,9 +38,9 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.2.5", features = ["derive"], optional = true } +clap = { version = "4.4.1", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.21" log = "0.4.17" @@ -135,7 +135,7 @@ pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] -clap = { version = "4.2.5", optional = true } +clap = { version = "4.4.1", 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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 59700bca36e..31e2a18c9c1 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 0c8bc3b32dc..b85f7d5e065 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } rand = "0.8" node-cli = { path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 5c1124d3984..c936e9fba40 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index e032e24e721..6acd57ef516 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] memmap2 = "0.5.0" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 6eebe095729..9404ba1b959 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.2.5", features = ["derive", "string"] } +clap = { version = "4.4.1", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} @@ -25,7 +25,7 @@ parity-scale-codec = "3.6.1" rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" thiserror = "1.0.30" tiny-bip39 = "1.0.0" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 0735cac21e7..bfae5ad3fd0 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } futures = "0.3.21" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0" sc-consensus-babe = { path = ".." } sc-consensus-epochs = { path = "../../epochs" } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index a5706724ebe..aae5a44d7fa 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -38,7 +38,7 @@ sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] -serde = "1.0.163" +serde = "1.0.188" tempfile = "3.1.0" tokio = "1.22.0" sc-block-builder = { path = "../../block-builder" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 1480d87064c..f9c3b4a99df 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4" parking_lot = "0.12.1" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0" sc-consensus-beefy = { path = ".." } sp-consensus-beefy = { path = "../../../../primitives/consensus/beefy" } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index bf6549c6244..dfd9916850e 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -52,7 +52,7 @@ sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } -serde = "1.0.163" +serde = "1.0.188" tokio = "1.22.0" sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index fe8f17405d9..e2f9e40afb2 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -15,7 +15,7 @@ futures = "0.3.16" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.6.1", features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0" sc-client-api = { path = "../../../api" } sc-consensus-grandpa = { path = ".." } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 38aea978597..6aa32333af9 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index e8d847e1419..72e38ce498d 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -33,7 +33,7 @@ parking_lot = "0.12.1" partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" smallvec = "1.11.0" thiserror = "1.0" diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index c13ca207cea..fb0d0a8a1f8 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 4a7539aa8a5..6f794d93fed 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -34,7 +34,7 @@ log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 48ee1b03561..e8e7fbcc469 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.2.5", features = ["derive", "string"] } +clap = { version = "4.4.1", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.6.3" sc-client-db = { path = "../db", default-features = false} diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 6babb1f5c9a..59cc6ba4048 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0.30" sc-chain-spec = { path = "../chain-spec" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 7301f28921c..5834d8dec07 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4.17" rand = "0.8.5" rand_pcg = "0.3.1" regex = "1" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 452715c449a..15362912909 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -22,7 +22,7 @@ parking_lot = "0.12.1" pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0.30" wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index f2e7cd11627..c9cd6ca313c 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.17" } parking_lot = "0.12.1" regex = "1.6.0" rustc-hash = "1.1.0" -serde = "1.0.163" +serde = "1.0.188" thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.3" diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 6f56378c699..0e502cb39fb 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -20,7 +20,7 @@ futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" parking_lot = "0.12.1" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0.30" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index 65d32dc60f4..edab1304e01 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -13,7 +13,7 @@ async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" log = "0.4.17" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0.30" sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core", default-features = false} diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 82970ca385c..020ca52a277 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -13,7 +13,7 @@ array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index ddee3c6fe8e..1445658bafb 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-authorship = { path = "../authorship", default-features = false} diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 8b47a1f948b..107f3b7d56f 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ linregress = { version = "0.5.1", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-support-procedural = { path = "../support/procedural", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index 6efa631cd97..666a02e9b23 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "max-encoded-len", ] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"], optional = true } +serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index d686684b638..038e8d2cef4 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"], optional = true } +serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 1bf4196e825..9b1e0264956 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 81f929c8f07..19ea25198f3 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -11,7 +11,7 @@ description = "FRAME pallet to queue and process messages" [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"] } -serde = { version = "1.0.163", optional = true, features = ["derive"] } +serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 7e9b093a038..2cfbfe6b5d0 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-balances = { path = "../balances", default-features = false} diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 6c0e86db346..ac4f46d12df 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"], optional = true } +serde = { version = "1.0.188", features = ["derive"], optional = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index cf98ae2794a..ae791011b16 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 491d19008da..5cd134471eb 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.163", default-features = false, features = ["alloc", "derive"]} +serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"]} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 8ba57fc8f71..2a9de6f2acc 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.3", default-features = false, optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index fa85181b31e..864e3bd9ad3 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.163", default-features = false, features = ["alloc", "derive"] } +serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 1519d3f5cc3..8b891279914 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" -serde = { version = "1.0.163", default-features = false, features = ["derive"] } +serde = { version = "1.0.188", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 8aae80362d3..8db2e9ba7c4 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive"] } +serde = { version = "1.0.188", default-features = false, features = ["derive"] } frame-support = { path = "../..", default-features = false} frame-system = { path = "../../../system", default-features = false} sp-runtime = { path = "../../../../primitives/runtime", default-features = false} diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 32bcc796f60..d1d5897ce35 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } frame-support = { path = "../support", default-features = false} sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 63b5c5cefff..0e9314a9f97 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"], optional = true } +serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 6fe9c7eb7e3..1db63bd134a 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index d89336fbf9f..edf05a05331 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -27,7 +27,7 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } [dev-dependencies] serde_json = "1.0.85" diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index 1f2773f6285..a1aec7ef65a 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", optional = true } +serde = { version = "1.0.188", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index f5bcb17b406..785564cd988 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive"], optional = true } +serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 0eea63fefcb..7c5e3173077 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { path = "../core", default-features = false} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } sp-std = { path = "../std", default-features = false} sp-io = { path = "../io", default-features = false} diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index ba7f6f8e176..4c2a78aec6f 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index ba011c84ea5..764e9550180 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-consensus-slots = { path = "../slots", default-features = false} diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 2c38917999f..6a12a5a7c7c 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-core = { path = "../../core", default-features = false} diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index bf2ae2921a4..bee9092b986 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", features = ["derive", "alloc"], default-features = false, optional = true } +serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-core = { path = "../../core", default-features = false} diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 4300c6a08fa..355cbab26fb 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -17,7 +17,7 @@ arrayvec = { version = "0.7.2", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.163", optional = true, default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.188", optional = true, default-features = false, features = ["derive", "alloc"] } bounded-collections = { version = "0.1.8", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 4d985e7a784..747b967dd9e 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } -serde = { version = "1.0.163", features = ["derive", "alloc"], default-features = false, optional = true } +serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } sp-api = { path = "../api", default-features = false} sp-core = { path = "../core", default-features = false} sp-debug-derive = { path = "../debug-derive", default-features = false} diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 00b4bd14b7d..68f1bef9166 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 8a36cea3b2e..aad90a36c73 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index d2bbaeff3d2..21447dafb05 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rustc-hash = "1.1.0" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } sp-core = { path = "../core" } [dev-dependencies] diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 7f31f0930b1..6ca435f2c2b 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 9f67446969d..825806078f6 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } 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"] } impl-trait-for-tuples = "0.2.2" diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 01a9b9b650a..11e574f1c4c 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-debug-derive = { path = "../debug-derive", default-features = false} sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index a5d7b518a69..91d532b6e16 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index bcd701c2f6e..3002566f74f 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } thiserror = { version = "1.0.30", optional = true } sp-core-hashing-proc-macro = { path = "../core/hashing/proc-macro" } sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 467cb145c94..03e06aad086 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 5cd90a25f6c..6d8636e4fe2 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 1ee3e74fdd1..91c30f5a8ec 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -17,7 +17,7 @@ array-bytes = "6.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 654479f5fdd..4f587d55e79 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { path = "../../primitives/externalities", default-features = # 3rd party array-bytes = { version = "6.1", optional = true } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.163", features = ["alloc", "derive"], default-features = false } +serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } [dev-dependencies] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 7238aa2ba32..5a74abb1c93 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.0.1", default-features = false } handlebars = "4.2.2" @@ -26,7 +26,7 @@ linked-hash-map = "0.5.4" log = "0.4.17" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" thiserror = "1.0.30" thousands = "0.2.0" diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 4e6392d5102..4653e585ebd 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index c72912aeafc..37b70564f3f 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.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 49f9fac11f6..ad6ab006da1 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] jsonrpsee = { version = "0.16.2", features = ["http-client"] } codec = { package = "parity-scale-codec", version = "3.6.1" } log = "0.4.17" -serde = "1.0.163" +serde = "1.0.188" sp-core = { path = "../../../primitives/core" } sp-state-machine = { path = "../../../primitives/state-machine" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 01b655cea8a..c17dfa823fb 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -35,11 +35,11 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true} substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.57" -clap = { version = "4.2.5", features = ["derive"] } +clap = { version = "4.4.1", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -serde = "1.0.163" +serde = "1.0.188" serde_json = "1.0.85" zstd = { version = "0.12.3", default-features = false } -- GitLab From 7768b77d53eb9a6585faace16fac27091895bc56 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 30 Aug 2023 11:32:34 +0200 Subject: [PATCH 022/633] Remove old UI test (#1289) Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Liam Aharon --- .gitlab/pipeline/test.yml | 9 +++---- .../test/tests/construct_runtime_ui.rs | 3 +++ .../genesis_default_not_satisfied.rs | 26 ------------------- .../genesis_default_not_satisfied.stderr | 16 ------------ 4 files changed, 7 insertions(+), 47 deletions(-) delete mode 100644 substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.rs delete mode 100644 substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 9dc14d7f163..c81750d49f9 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -212,7 +212,7 @@ test-deterministic-wasm: - .common-refs # DAG needs: - - job: test-frame-support + - job: test-frame-ui artifacts: false script: - .gitlab/test_deterministic_wasm.sh @@ -295,7 +295,7 @@ node-bench-regression-guard: # if this fails (especially after rust version upgrade) run # ./substrate/.maintain/update-rust-stable.sh -test-frame-support: +test-frame-ui: stage: test extends: - .docker-env @@ -314,9 +314,8 @@ test-frame-support: # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: - - time cargo test --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental --manifest-path ./substrate/frame/support/test/Cargo.toml - - time cargo test --locked -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental --manifest-path ./substrate/frame/support/test/Cargo.toml - - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --locked -- --ignored timeout + - time cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental + - time cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true # This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. diff --git a/substrate/frame/support/test/tests/construct_runtime_ui.rs b/substrate/frame/support/test/tests/construct_runtime_ui.rs index ec6758f4b29..c3197c99a72 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui.rs @@ -27,6 +27,9 @@ fn ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); + // Deny all warnings since we emit warnings as part of a Runtime's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + let t = trybuild::TestCases::new(); t.compile_fail("tests/construct_runtime_ui/*.rs"); } diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.rs b/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.rs deleted file mode 100644 index a4a0eb832c9..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.rs +++ /dev/null @@ -1,26 +0,0 @@ -#[frame_support::pallet] -mod pallet { - use frame_support::pallet_prelude::{BuildGenesisConfig, Hooks}; - use frame_system::pallet_prelude::BlockNumberFor; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - pub struct Pallet(core::marker::PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - - #[pallet::genesis_config] - pub struct GenesisConfig; - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig {} -} - -fn main() { -} diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr deleted file mode 100644 index 67cbe80be0d..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0277]: the trait bound `pallet::GenesisConfig: std::default::Default` is not satisfied - --> tests/pallet_ui/genesis_default_not_satisfied.rs:22:30 - | -22 | impl BuildGenesisConfig for GenesisConfig {} - | ^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `pallet::GenesisConfig` - | -note: required by a bound in `BuildGenesisConfig` - --> $WORKSPACE/substrate/frame/support/src/traits/hooks.rs - | - | pub trait BuildGenesisConfig: Default + sp_runtime::traits::MaybeSerializeDeserialize { - | ^^^^^^^ required by this bound in `BuildGenesisConfig` -help: consider annotating `pallet::GenesisConfig` with `#[derive(Default)]` - | -19 + #[derive(Default)] -20 | pub struct GenesisConfig; - | -- GitLab From bfb241d7f3e29152b9fe0ab3a0364ee0c89ec65c Mon Sep 17 00:00:00 2001 From: Przemek Rzad Date: Wed, 30 Aug 2023 14:45:49 +0200 Subject: [PATCH 023/633] Add missing licenses and tune the scanning workflow (#1288) * Add missing Cumulus licenses * Typo * Add missing Substrate licenses * Single job checking the sub-repos in steps * Remove dates * Remove dates * Add missing (C) * Update FRAME UI tests Signed-off-by: Oliver Tale-Yazdi * Update more UI tests Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- .github/workflows/check-licenses.yml | 37 +- .../bin/runtime-common/src/integrity.rs | 2 +- cumulus/bridges/bin/runtime-common/src/lib.rs | 2 +- .../bin/runtime-common/src/messages.rs | 2 +- .../bin/runtime-common/src/messages_api.rs | 2 +- .../src/messages_benchmarking.rs | 2 +- .../runtime-common/src/messages_call_ext.rs | 2 +- .../runtime-common/src/messages_generation.rs | 2 +- .../src/messages_xcm_extension.rs | 2 +- .../bridges/bin/runtime-common/src/mock.rs | 2 +- .../src/parachains_benchmarking.rs | 2 +- .../runtime-common/src/priority_calculator.rs | 2 +- .../src/refund_relayer_extension.rs | 2 +- .../modules/grandpa/src/benchmarking.rs | 2 +- .../bridges/modules/grandpa/src/call_ext.rs | 2 +- cumulus/bridges/modules/grandpa/src/lib.rs | 2 +- cumulus/bridges/modules/grandpa/src/mock.rs | 2 +- .../modules/grandpa/src/storage_types.rs | 2 +- .../bridges/modules/grandpa/src/weights.rs | 2 +- .../modules/messages/src/benchmarking.rs | 2 +- .../modules/messages/src/inbound_lane.rs | 2 +- cumulus/bridges/modules/messages/src/lib.rs | 2 +- cumulus/bridges/modules/messages/src/mock.rs | 2 +- .../modules/messages/src/outbound_lane.rs | 2 +- .../bridges/modules/messages/src/weights.rs | 2 +- .../modules/messages/src/weights_ext.rs | 2 +- .../modules/parachains/src/benchmarking.rs | 2 +- .../modules/parachains/src/call_ext.rs | 2 +- cumulus/bridges/modules/parachains/src/lib.rs | 2 +- .../bridges/modules/parachains/src/mock.rs | 2 +- .../bridges/modules/parachains/src/weights.rs | 2 +- .../modules/parachains/src/weights_ext.rs | 2 +- .../modules/relayers/src/benchmarking.rs | 2 +- cumulus/bridges/modules/relayers/src/lib.rs | 2 +- cumulus/bridges/modules/relayers/src/mock.rs | 2 +- .../modules/relayers/src/payment_adapter.rs | 2 +- .../modules/relayers/src/stake_adapter.rs | 2 +- .../bridges/modules/relayers/src/weights.rs | 2 +- .../modules/relayers/src/weights_ext.rs | 2 +- .../xcm-bridge-hub-router/src/benchmarking.rs | 2 +- .../modules/xcm-bridge-hub-router/src/lib.rs | 2 +- .../modules/xcm-bridge-hub-router/src/mock.rs | 2 +- .../xcm-bridge-hub-router/src/weights.rs | 2 +- .../chain-asset-hub-kusama/src/lib.rs | 2 +- .../chain-asset-hub-polkadot/src/lib.rs | 2 +- .../chain-bridge-hub-cumulus/src/lib.rs | 2 +- .../chain-bridge-hub-kusama/src/lib.rs | 2 +- .../chain-bridge-hub-polkadot/src/lib.rs | 2 +- .../chain-bridge-hub-rococo/src/lib.rs | 2 +- .../chain-bridge-hub-wococo/src/lib.rs | 2 +- .../primitives/chain-kusama/src/lib.rs | 2 +- .../primitives/chain-polkadot/src/lib.rs | 2 +- .../primitives/chain-rococo/src/lib.rs | 2 +- .../primitives/chain-wococo/src/lib.rs | 2 +- .../header-chain/src/justification/mod.rs | 2 +- .../verification/equivocation.rs | 2 +- .../src/justification/verification/mod.rs | 2 +- .../justification/verification/optimizer.rs | 2 +- .../src/justification/verification/strict.rs | 2 +- .../primitives/header-chain/src/lib.rs | 2 +- .../header-chain/src/storage_keys.rs | 2 +- .../tests/implementation_match.rs | 2 +- .../tests/justification/equivocation.rs | 2 +- .../tests/justification/optimizer.rs | 2 +- .../tests/justification/strict.rs | 2 +- .../primitives/header-chain/tests/tests.rs | 16 + .../bridges/primitives/messages/src/lib.rs | 2 +- .../primitives/messages/src/source_chain.rs | 2 +- .../primitives/messages/src/storage_keys.rs | 2 +- .../primitives/messages/src/target_chain.rs | 2 +- .../bridges/primitives/parachains/src/lib.rs | 2 +- .../primitives/polkadot-core/src/lib.rs | 2 +- .../polkadot-core/src/parachains.rs | 2 +- .../bridges/primitives/relayers/src/lib.rs | 2 +- .../primitives/relayers/src/registration.rs | 2 +- .../bridges/primitives/runtime/src/chain.rs | 2 +- .../primitives/runtime/src/extensions.rs | 2 +- cumulus/bridges/primitives/runtime/src/lib.rs | 2 +- .../primitives/runtime/src/messages.rs | 2 +- .../primitives/runtime/src/storage_proof.rs | 2 +- .../primitives/runtime/src/storage_types.rs | 2 +- .../primitives/test-utils/src/keyring.rs | 2 +- .../bridges/primitives/test-utils/src/lib.rs | 2 +- .../xcm-bridge-hub-router/src/lib.rs | 2 +- cumulus/client/cli/src/lib.rs | 2 +- cumulus/client/collator/src/lib.rs | 2 +- cumulus/client/collator/src/service.rs | 2 +- cumulus/client/consensus/aura/src/collator.rs | 2 +- .../consensus/aura/src/collators/basic.rs | 2 +- .../consensus/aura/src/collators/lookahead.rs | 2 +- .../consensus/aura/src/collators/mod.rs | 2 +- .../aura/src/equivocation_import_queue.rs | 2 +- .../client/consensus/aura/src/import_queue.rs | 2 +- cumulus/client/consensus/aura/src/lib.rs | 2 +- .../consensus/common/src/import_queue.rs | 2 +- .../consensus/common/src/level_monitor.rs | 2 +- cumulus/client/consensus/common/src/lib.rs | 2 +- .../common/src/parachain_consensus.rs | 2 +- cumulus/client/consensus/common/src/tests.rs | 2 +- cumulus/client/consensus/proposer/src/lib.rs | 2 +- .../consensus/relay-chain/src/import_queue.rs | 2 +- .../client/consensus/relay-chain/src/lib.rs | 2 +- cumulus/client/network/src/lib.rs | 2 +- cumulus/client/network/src/tests.rs | 2 +- .../src/active_candidate_recovery.rs | 2 +- cumulus/client/pov-recovery/src/lib.rs | 2 +- .../src/lib.rs | 2 +- .../client/relay-chain-interface/src/lib.rs | 2 +- .../src/blockchain_rpc_client.rs | 2 +- .../src/collator_overseer.rs | 2 +- .../relay-chain-minimal-node/src/lib.rs | 2 +- .../relay-chain-minimal-node/src/network.rs | 2 +- .../relay-chain-rpc-interface/src/lib.rs | 2 +- .../src/light_client_worker.rs | 2 +- .../src/reconnecting_ws_client.rs | 2 +- .../src/rpc_client.rs | 2 +- .../src/tokio_platform.rs | 2 +- cumulus/client/service/src/lib.rs | 2 +- cumulus/file_header.txt | 2 +- .../pallets/aura-ext/src/consensus_hook.rs | 2 +- cumulus/pallets/aura-ext/src/lib.rs | 2 +- .../collator-selection/src/benchmarking.rs | 2 +- cumulus/pallets/collator-selection/src/lib.rs | 2 +- .../collator-selection/src/migration.rs | 2 +- .../pallets/collator-selection/src/mock.rs | 2 +- .../pallets/collator-selection/src/tests.rs | 2 +- .../pallets/collator-selection/src/weights.rs | 2 +- cumulus/pallets/dmp-queue/src/lib.rs | 2 +- cumulus/pallets/dmp-queue/src/migration.rs | 2 +- .../parachain-system/proc-macro/src/lib.rs | 2 +- .../parachain-system/src/consensus_hook.rs | 2 +- cumulus/pallets/parachain-system/src/lib.rs | 2 +- .../pallets/parachain-system/src/migration.rs | 2 +- .../src/relay_state_snapshot.rs | 2 +- cumulus/pallets/parachain-system/src/tests.rs | 2 +- .../src/unincluded_segment.rs | 2 +- .../src/validate_block/implementation.rs | 2 +- .../src/validate_block/mod.rs | 2 +- .../src/validate_block/tests.rs | 2 +- .../pallets/session-benchmarking/src/lib.rs | 2 +- cumulus/pallets/solo-to-para/src/lib.rs | 2 +- cumulus/pallets/xcm/src/lib.rs | 2 +- .../pallets/xcmp-queue/src/benchmarking.rs | 2 +- cumulus/pallets/xcmp-queue/src/lib.rs | 2 +- cumulus/pallets/xcmp-queue/src/migration.rs | 2 +- cumulus/pallets/xcmp-queue/src/mock.rs | 2 +- cumulus/pallets/xcmp-queue/src/tests.rs | 2 +- cumulus/pallets/xcmp-queue/src/weights.rs | 15 + .../runtime/src/weights/block_weights.rs | 2 +- .../runtime/src/weights/extrinsic_weights.rs | 2 +- .../runtime/src/weights/mod.rs | 2 +- .../runtime/src/weights/paritydb_weights.rs | 2 +- .../runtime/src/weights/rocksdb_weights.rs | 2 +- cumulus/parachains/common/src/impls.rs | 2 +- cumulus/parachains/common/src/lib.rs | 2 +- cumulus/parachains/common/src/xcm_config.rs | 15 + .../assets/asset-hub-kusama/src/lib.rs | 2 +- .../src/tests/hrmp_channels.rs | 2 +- .../assets/asset-hub-kusama/src/tests/mod.rs | 2 +- .../src/tests/reserve_transfer.rs | 2 +- .../assets/asset-hub-kusama/src/tests/send.rs | 2 +- .../src/tests/set_xcm_versions.rs | 2 +- .../assets/asset-hub-kusama/src/tests/swap.rs | 16 + .../asset-hub-kusama/src/tests/teleport.rs | 2 +- .../assets/asset-hub-polkadot/src/lib.rs | 2 +- .../src/tests/hrmp_channels.rs | 2 +- .../asset-hub-polkadot/src/tests/mod.rs | 2 +- .../src/tests/reserve_transfer.rs | 2 +- .../asset-hub-polkadot/src/tests/send.rs | 2 +- .../src/tests/set_xcm_versions.rs | 2 +- .../asset-hub-polkadot/src/tests/teleport.rs | 2 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../assets/asset-hub-westend/src/tests/mod.rs | 2 +- .../src/tests/reserve_transfer.rs | 2 +- .../asset-hub-westend/src/tests/send.rs | 2 +- .../src/tests/set_xcm_versions.rs | 2 +- .../asset-hub-westend/src/tests/swap.rs | 16 + .../asset-hub-westend/src/tests/teleport.rs | 2 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../bridge-hub-rococo/src/tests/example.rs | 2 +- .../bridge-hub-rococo/src/tests/mod.rs | 2 +- .../collectives-polkadot/src/lib.rs | 2 +- .../src/tests/fellowship.rs | 2 +- .../collectives-polkadot/src/tests/mod.rs | 2 +- .../emulated/common/src/constants.rs | 16 + .../emulated/common/src/impls.rs | 16 + .../emulated/common/src/lib.rs | 16 + .../pallets/parachain-info/src/lib.rs | 2 +- cumulus/parachains/pallets/ping/src/lib.rs | 2 +- .../assets/asset-hub-kusama/src/constants.rs | 2 +- .../assets/asset-hub-kusama/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../asset-hub-kusama/src/weights/mod.rs | 16 + .../src/weights/pallet_asset_conversion.rs | 2 +- .../src/weights/pallet_assets_foreign.rs | 2 +- .../src/weights/pallet_assets_local.rs | 2 +- .../src/weights/pallet_assets_pool.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../weights/pallet_nft_fractionalization.rs | 2 +- .../src/weights/pallet_nfts.rs | 2 +- .../src/weights/pallet_proxy.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_uniques.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../asset-hub-kusama/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 2 +- .../asset-hub-polkadot/src/constants.rs | 2 +- .../assets/asset-hub-polkadot/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../asset-hub-polkadot/src/weights/mod.rs | 16 + .../src/weights/pallet_assets_foreign.rs | 2 +- .../src/weights/pallet_assets_local.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../src/weights/pallet_nfts.rs | 2 +- .../src/weights/pallet_proxy.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_uniques.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../asset-hub-polkadot/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../asset-hub-polkadot/src/xcm_config.rs | 2 +- .../assets/asset-hub-westend/src/constants.rs | 2 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../asset-hub-westend/src/weights/mod.rs | 16 + .../src/weights/pallet_asset_conversion.rs | 2 +- .../src/weights/pallet_assets_foreign.rs | 2 +- .../src/weights/pallet_assets_local.rs | 2 +- .../src/weights/pallet_assets_pool.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../weights/pallet_nft_fractionalization.rs | 2 +- .../src/weights/pallet_nfts.rs | 2 +- .../src/weights/pallet_proxy.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_uniques.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../asset-hub-westend/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../asset-hub-westend/src/xcm_config.rs | 2 +- .../assets/common/src/foreign_creators.rs | 2 +- .../assets/common/src/fungible_conversion.rs | 2 +- .../runtimes/assets/common/src/lib.rs | 2 +- .../common/src/local_and_foreign_assets.rs | 2 +- .../runtimes/assets/common/src/matching.rs | 2 +- .../runtimes/assets/common/src/runtime_api.rs | 2 +- .../runtimes/assets/test-utils/src/lib.rs | 2 +- .../assets/test-utils/src/test_cases.rs | 2 +- .../bridge-hub-kusama/src/constants.rs | 2 +- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../bridge-hub-kusama/src/weights/mod.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../bridge-hub-kusama/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../bridge-hub-kusama/src/xcm_config.rs | 2 +- .../bridge-hub-kusama/tests/tests.rs | 2 +- .../bridge-hub-polkadot/src/constants.rs | 2 +- .../bridge-hub-polkadot/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../bridge-hub-polkadot/src/weights/mod.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../bridge-hub-polkadot/src/xcm_config.rs | 2 +- .../bridge-hub-polkadot/tests/tests.rs | 2 +- .../src/bridge_hub_rococo_config.rs | 2 +- .../src/bridge_hub_wococo_config.rs | 2 +- .../bridge-hub-rococo/src/constants.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../bridge-hub-rococo/src/weights/mod.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_bridge_grandpa.rs | 2 +- ...et_bridge_grandpa_bridge_rococo_grandpa.rs | 2 +- ...et_bridge_grandpa_bridge_wococo_grandpa.rs | 2 +- .../src/weights/pallet_bridge_messages.rs | 2 +- ...ith_bridge_hub_rococo_messages_instance.rs | 2 +- ...ith_bridge_hub_wococo_messages_instance.rs | 2 +- .../src/weights/pallet_bridge_parachains.rs | 2 +- ...untime_bridge_parachain_rococo_instance.rs | 2 +- ...untime_bridge_parachain_wococo_instance.rs | 2 +- .../src/weights/pallet_bridge_relayers.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../bridge-hub-rococo/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 2 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 2 +- .../bridge-hub-rococo/src/xcm_config.rs | 2 +- .../bridge-hub-rococo/tests/tests.rs | 2 +- .../bridge-hubs/test-utils/src/lib.rs | 2 +- .../bridge-hubs/test-utils/src/test_cases.rs | 2 +- .../collectives-polkadot/src/constants.rs | 2 +- .../src/fellowship/migration.rs | 2 +- .../src/fellowship/mod.rs | 2 +- .../src/fellowship/origins.rs | 2 +- .../src/fellowship/tracks.rs | 2 +- .../collectives-polkadot/src/impls.rs | 2 +- .../collectives-polkadot/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../collectives-polkadot/src/weights/mod.rs | 16 + .../src/weights/pallet_alliance.rs | 2 +- .../src/weights/pallet_balances.rs | 2 +- .../src/weights/pallet_collator_selection.rs | 2 +- .../src/weights/pallet_collective.rs | 2 +- .../src/weights/pallet_core_fellowship.rs | 2 +- .../src/weights/pallet_multisig.rs | 2 +- .../src/weights/pallet_preimage.rs | 2 +- .../src/weights/pallet_proxy.rs | 2 +- .../src/weights/pallet_ranked_collective.rs | 2 +- .../src/weights/pallet_referenda.rs | 2 +- .../src/weights/pallet_salary.rs | 2 +- .../src/weights/pallet_scheduler.rs | 2 +- .../src/weights/pallet_session.rs | 2 +- .../src/weights/pallet_timestamp.rs | 2 +- .../src/weights/pallet_utility.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../collectives-polkadot/src/xcm_config.rs | 2 +- .../contracts-rococo/src/constants.rs | 2 +- .../contracts-rococo/src/contracts.rs | 15 + .../contracts/contracts-rococo/src/lib.rs | 2 +- .../src/weights/block_weights.rs | 2 +- .../src/weights/extrinsic_weights.rs | 2 +- .../contracts-rococo/src/weights/mod.rs | 2 +- .../src/weights/paritydb_weights.rs | 2 +- .../src/weights/rocksdb_weights.rs | 2 +- .../contracts-rococo/src/xcm_config.rs | 2 +- .../runtimes/glutton/glutton-kusama/build.rs | 15 + .../glutton/glutton-kusama/src/lib.rs | 2 +- .../src/weights/frame_system.rs | 2 +- .../glutton/glutton-kusama/src/weights/mod.rs | 16 + .../src/weights/pallet_glutton.rs | 2 +- .../glutton/glutton-kusama/src/xcm_config.rs | 2 +- .../runtimes/starters/seedling/src/lib.rs | 2 +- .../runtimes/starters/shell/build.rs | 2 +- .../runtimes/starters/shell/src/lib.rs | 2 +- .../runtimes/starters/shell/src/xcm_config.rs | 2 +- .../runtimes/testing/penpal/build.rs | 2 +- .../runtimes/testing/penpal/src/lib.rs | 2 +- .../penpal/src/weights/block_weights.rs | 2 +- .../penpal/src/weights/extrinsic_weights.rs | 2 +- .../testing/penpal/src/weights/mod.rs | 2 +- .../penpal/src/weights/paritydb_weights.rs | 2 +- .../penpal/src/weights/rocksdb_weights.rs | 2 +- .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- .../testing/rococo-parachain/src/lib.rs | 2 +- cumulus/polkadot-parachain/build.rs | 2 +- .../src/chain_spec/asset_hubs.rs | 2 +- .../src/chain_spec/bridge_hubs.rs | 2 +- .../src/chain_spec/collectives.rs | 2 +- .../src/chain_spec/contracts.rs | 2 +- .../src/chain_spec/glutton.rs | 2 +- .../polkadot-parachain/src/chain_spec/mod.rs | 2 +- .../src/chain_spec/penpal.rs | 2 +- .../src/chain_spec/rococo_parachain.rs | 2 +- .../src/chain_spec/seedling.rs | 2 +- .../src/chain_spec/shell.rs | 2 +- cumulus/polkadot-parachain/src/cli.rs | 2 +- cumulus/polkadot-parachain/src/command.rs | 2 +- cumulus/polkadot-parachain/src/main.rs | 2 +- cumulus/polkadot-parachain/src/rpc.rs | 2 +- cumulus/polkadot-parachain/src/service.rs | 2 +- .../tests/benchmark_storage_works.rs | 16 + cumulus/polkadot-parachain/tests/common.rs | 4 +- .../tests/polkadot_argument_parsing.rs | 4 +- .../tests/polkadot_mdns_issue.rs | 4 +- .../tests/purge_chain_works.rs | 4 +- .../tests/running_the_node_and_interrupt.rs | 4 +- cumulus/primitives/aura/src/lib.rs | 2 +- cumulus/primitives/core/src/lib.rs | 2 +- .../parachain-inherent/src/client_side.rs | 2 +- .../primitives/parachain-inherent/src/lib.rs | 2 +- .../primitives/parachain-inherent/src/mock.rs | 2 +- cumulus/primitives/timestamp/src/lib.rs | 2 +- cumulus/primitives/utility/src/lib.rs | 2 +- cumulus/test/client/src/block_builder.rs | 2 +- cumulus/test/client/src/lib.rs | 2 +- cumulus/test/relay-sproof-builder/src/lib.rs | 2 +- .../relay-validation-worker-provider/build.rs | 2 +- .../src/lib.rs | 2 +- cumulus/test/runtime/build.rs | 2 +- cumulus/test/runtime/src/lib.rs | 2 +- cumulus/test/runtime/src/test_pallet.rs | 2 +- .../service/benches/transaction_throughput.rs | 2 +- cumulus/test/service/src/chain_spec.rs | 2 +- cumulus/test/service/src/cli.rs | 2 +- cumulus/test/service/src/genesis.rs | 2 +- cumulus/test/service/src/lib.rs | 2 +- cumulus/test/service/src/main.rs | 2 +- cumulus/xcm/xcm-emulator/src/lib.rs | 2 +- .../src/tests/prospective_parachains.rs | 2 +- .../core/prospective-parachains/src/error.rs | 2 +- .../src/fragment_tree.rs | 2 +- .../core/prospective-parachains/src/lib.rs | 2 +- .../prospective-parachains/src/metrics.rs | 2 +- .../core/prospective-parachains/src/tests.rs | 2 +- .../src/collator_side/collation.rs | 2 +- .../tests/prospective_parachains.rs | 2 +- .../src/validator_side/collation.rs | 2 +- .../src/validator_side/metrics.rs | 2 +- .../tests/prospective_parachains.rs | 2 +- .../protocol/src/request_response/vstaging.rs | 2 +- .../src/legacy_v1/mod.rs | 2 +- .../src/vstaging/candidates.rs | 2 +- .../src/vstaging/cluster.rs | 2 +- .../src/vstaging/grid.rs | 2 +- .../src/vstaging/groups.rs | 2 +- .../src/vstaging/mod.rs | 2 +- .../src/vstaging/requests.rs | 2 +- .../src/vstaging/statement_store.rs | 2 +- .../src/vstaging/tests/cluster.rs | 2 +- .../src/vstaging/tests/grid.rs | 2 +- .../src/vstaging/tests/mod.rs | 2 +- .../src/vstaging/tests/requests.rs | 2 +- .../src/backing_implicit_view.rs | 2 +- .../src/inclusion_emulator/mod.rs | 2 +- .../src/inclusion_emulator/staging.rs | 2 +- polkadot/primitives/src/v5/slashing.rs | 2 +- .../parachains/src/inclusion/benchmarking.rs | 2 +- polkadot/runtime/parachains/src/ump_tests.rs | 2 +- polkadot/xcm/xcm-builder/src/pay.rs | 2 +- .../xcm-builder/src/process_xcm_message.rs | 2 +- substrate/bin/node/runtime/src/assets_api.rs | 2 +- substrate/client/authority-discovery/build.rs | 18 + .../incoming_requests_handler.rs | 2 +- .../consensus/grandpa/src/warp_proof.rs | 2 +- .../client/executor/runtime-test/src/lib.rs | 18 + substrate/client/network/bitswap/build.rs | 18 + substrate/client/network/bitswap/src/lib.rs | 2 +- .../client/network/common/src/sync/warp.rs | 2 +- substrate/client/network/light/build.rs | 18 + substrate/client/network/sync/build.rs | 18 + .../network/sync/src/block_request_handler.rs | 2 +- substrate/client/network/sync/src/engine.rs | 2 +- .../network/sync/src/state_request_handler.rs | 2 +- .../network/sync/src/warp_request_handler.rs | 2 +- .../rpc-spec-v2/src/chain_head/tests.rs | 18 + substrate/client/tracing/src/block/mod.rs | 2 +- .../client/tracing/src/logging/directives.rs | 2 +- substrate/frame/asset-conversion/src/lib.rs | 2 +- substrate/frame/asset-conversion/src/mock.rs | 2 +- substrate/frame/asset-conversion/src/tests.rs | 2 +- substrate/frame/asset-conversion/src/types.rs | 2 +- substrate/frame/atomic-swap/src/tests.rs | 17 + .../bags-list/remote-tests/src/migration.rs | 2 +- .../bags-list/remote-tests/src/snapshot.rs | 2 +- .../bags-list/remote-tests/src/try_state.rs | 2 +- substrate/frame/balances/src/impl_currency.rs | 2 +- substrate/frame/balances/src/impl_fungible.rs | 2 +- substrate/frame/balances/src/migration.rs | 2 +- .../balances/src/tests/currency_tests.rs | 2 +- .../balances/src/tests/dispatchable_tests.rs | 2 +- .../balances/src/tests/fungible_tests.rs | 2 +- substrate/frame/balances/src/tests/mod.rs | 2 +- .../balances/src/tests/reentrancy_tests.rs | 2 +- substrate/frame/balances/src/types.rs | 2 +- .../frame/benchmarking/pov/src/weights.rs | 16 + substrate/frame/contracts/src/debug.rs | 17 + .../frame/contracts/src/tests/pallet_dummy.rs | 17 + .../frame/contracts/src/tests/test_debug.rs | 17 + substrate/frame/core-fellowship/src/lib.rs | 2 +- substrate/frame/core-fellowship/src/tests.rs | 2 +- .../test-staking-e2e/src/mock.rs | 2 +- .../solution-type/fuzzer/src/compact.rs | 17 + .../tests/ui/fail/missing_accuracy.rs | 17 + .../tests/ui/fail/missing_accuracy.stderr | 8 +- .../tests/ui/fail/missing_size_bound.rs | 17 + .../tests/ui/fail/missing_size_bound.stderr | 8 +- .../tests/ui/fail/missing_target.rs | 17 + .../tests/ui/fail/missing_target.stderr | 8 +- .../tests/ui/fail/missing_voter.rs | 17 + .../tests/ui/fail/missing_voter.stderr | 8 +- .../tests/ui/fail/no_annotations.rs | 17 + .../tests/ui/fail/no_annotations.stderr | 8 +- .../tests/ui/fail/swap_voter_target.rs | 17 + .../tests/ui/fail/swap_voter_target.stderr | 8 +- .../tests/ui/fail/wrong_attribute.rs | 17 + .../tests/ui/fail/wrong_attribute.stderr | 8 +- .../elections-phragmen/src/migrations/v5.rs | 17 + .../frame/examples/kitchensink/src/weights.rs | 16 + substrate/frame/examples/split/src/weights.rs | 16 + substrate/frame/glutton/src/benchmarking.rs | 2 +- substrate/frame/glutton/src/lib.rs | 2 +- substrate/frame/glutton/src/mock.rs | 2 +- substrate/frame/glutton/src/tests.rs | 2 +- .../frame/nft-fractionalization/src/lib.rs | 2 +- .../frame/nft-fractionalization/src/mock.rs | 2 +- .../frame/nft-fractionalization/src/tests.rs | 2 +- .../frame/nft-fractionalization/src/types.rs | 2 +- substrate/frame/nfts/runtime-api/src/lib.rs | 2 +- substrate/frame/nomination-pools/src/mock.rs | 17 + substrate/frame/salary/src/lib.rs | 2 +- substrate/frame/salary/src/tests.rs | 2 +- substrate/frame/society/src/weights.rs | 2 +- .../frame/staking/reward-curve/src/log.rs | 17 + .../frame/staking/runtime-api/src/lib.rs | 2 +- .../procedural/src/dummy_part_checker.rs | 17 + .../procedural/src/pallet/expand/doc_only.rs | 2 +- .../support/src/storage/types/counted_nmap.rs | 2 +- .../tokens/fungible/conformance_tests/mod.rs | 17 + .../src/traits/tokens/fungible/freeze.rs | 2 +- .../src/traits/tokens/fungible/hold.rs | 2 +- .../src/traits/tokens/fungible/item_of.rs | 2 +- .../support/src/traits/tokens/fungible/mod.rs | 2 +- .../src/traits/tokens/fungible/regular.rs | 2 +- .../src/traits/tokens/fungibles/freeze.rs | 2 +- .../src/traits/tokens/fungibles/hold.rs | 2 +- .../src/traits/tokens/fungibles/lifetime.rs | 2 +- .../src/traits/tokens/fungibles/mod.rs | 2 +- .../src/traits/tokens/fungibles/regular.rs | 2 +- .../test/tests/benchmark_ui/bad_param_name.rs | 17 + .../tests/benchmark_ui/bad_param_name.stderr | 4 +- .../benchmark_ui/bad_param_name_too_long.rs | 17 + .../bad_param_name_too_long.stderr | 8 +- .../benchmark_ui/bad_param_name_upper_case.rs | 17 + .../bad_param_name_upper_case.stderr | 8 +- .../test/tests/benchmark_ui/bad_params.rs | 17 + .../test/tests/benchmark_ui/bad_params.stderr | 4 +- .../bad_return_non_benchmark_err.rs | 17 + .../bad_return_non_benchmark_err.stderr | 4 +- .../benchmark_ui/bad_return_non_type_path.rs | 17 + .../bad_return_non_type_path.stderr | 4 +- .../benchmark_ui/bad_return_non_unit_t.rs | 17 + .../benchmark_ui/bad_return_non_unit_t.stderr | 8 +- .../bad_return_type_blank_with_question.rs | 17 + ...bad_return_type_blank_with_question.stderr | 6 +- .../bad_return_type_no_last_stmt.rs | 17 + .../bad_return_type_no_last_stmt.stderr | 10 +- .../bad_return_type_non_result.rs | 17 + .../bad_return_type_non_result.stderr | 4 +- .../benchmark_ui/bad_return_type_option.rs | 17 + .../bad_return_type_option.stderr | 4 +- .../test/tests/benchmark_ui/dup_block.rs | 17 + .../test/tests/benchmark_ui/dup_block.stderr | 4 +- .../tests/benchmark_ui/dup_extrinsic_call.rs | 17 + .../benchmark_ui/dup_extrinsic_call.stderr | 4 +- .../test/tests/benchmark_ui/empty_function.rs | 17 + .../tests/benchmark_ui/empty_function.stderr | 4 +- .../test/tests/benchmark_ui/extra_extra.rs | 17 + .../tests/benchmark_ui/extra_extra.stderr | 8 +- .../tests/benchmark_ui/extra_skip_meta.rs | 17 + .../tests/benchmark_ui/extra_skip_meta.stderr | 8 +- .../benchmark_ui/extrinsic_call_out_of_fn.rs | 17 + .../extrinsic_call_out_of_fn.stderr | 12 +- .../test/tests/benchmark_ui/invalid_origin.rs | 17 + .../tests/benchmark_ui/invalid_origin.stderr | 14 +- .../test/tests/benchmark_ui/missing_call.rs | 17 + .../tests/benchmark_ui/missing_call.stderr | 8 +- .../test/tests/benchmark_ui/missing_origin.rs | 17 + .../tests/benchmark_ui/missing_origin.stderr | 4 +- .../tests/benchmark_ui/pass/valid_basic.rs | 17 + .../valid_complex_path_benchmark_result.rs | 17 + .../benchmark_ui/pass/valid_const_expr.rs | 17 + .../benchmark_ui/pass/valid_no_last_stmt.rs | 17 + .../pass/valid_path_result_benchmark_error.rs | 17 + .../tests/benchmark_ui/pass/valid_result.rs | 17 + .../tests/benchmark_ui/unrecognized_option.rs | 17 + .../benchmark_ui/unrecognized_option.stderr | 8 +- .../abundant_where_param.rs | 17 + .../abundant_where_param.stderr | 8 +- .../both_use_and_excluded_parts.rs | 17 + .../both_use_and_excluded_parts.stderr | 14 +- .../construct_runtime_ui/conflicting_index.rs | 17 + .../conflicting_index.stderr | 12 +- .../conflicting_index_2.rs | 17 + .../conflicting_index_2.stderr | 12 +- .../conflicting_module_name.rs | 17 + .../conflicting_module_name.stderr | 16 +- .../deprecated_where_block.rs | 17 + .../deprecated_where_block.stderr | 380 +++++++++--------- .../double_module_parts.rs | 17 + .../double_module_parts.stderr | 8 +- .../construct_runtime_ui/duplicate_exclude.rs | 17 + .../duplicate_exclude.stderr | 8 +- .../construct_runtime_ui/empty_pallet_path.rs | 17 + .../empty_pallet_path.stderr | 8 +- .../construct_runtime_ui/exclude_missspell.rs | 17 + .../exclude_missspell.stderr | 8 +- .../exclude_undefined_part.rs | 17 + .../exclude_undefined_part.stderr | 14 +- .../feature_gated_system_pallet.rs | 17 + .../feature_gated_system_pallet.stderr | 8 +- .../generics_in_invalid_module.rs | 17 + .../generics_in_invalid_module.stderr | 8 +- .../invalid_meta_literal.rs | 17 + .../invalid_meta_literal.stderr | 8 +- .../invalid_module_details.rs | 17 + .../invalid_module_details.stderr | 8 +- .../invalid_module_details_keyword.rs | 17 + .../invalid_module_details_keyword.stderr | 8 +- .../invalid_module_entry.rs | 17 + .../invalid_module_entry.stderr | 8 +- .../invalid_token_after_module.rs | 17 + .../invalid_token_after_module.stderr | 8 +- .../invalid_token_after_name.rs | 17 + .../invalid_token_after_name.stderr | 8 +- .../invalid_where_param.rs | 17 + .../invalid_where_param.stderr | 8 +- ...g_event_generic_on_module_with_instance.rs | 17 + ...ent_generic_on_module_with_instance.stderr | 8 +- .../missing_module_instance.rs | 17 + .../missing_module_instance.stderr | 8 +- ..._origin_generic_on_module_with_instance.rs | 17 + ...gin_generic_on_module_with_instance.stderr | 8 +- .../missing_system_module.rs | 17 + .../missing_system_module.stderr | 10 +- .../missing_where_param.rs | 17 + .../missing_where_param.stderr | 8 +- .../more_than_256_modules.rs | 17 + .../more_than_256_modules.stderr | 4 +- .../no_comma_after_where.rs | 17 + .../no_comma_after_where.stderr | 8 +- .../number_of_pallets_exceeds_tuple_size.rs | 17 + ...umber_of_pallets_exceeds_tuple_size.stderr | 40 +- .../pallet_error_too_large.rs | 17 + .../pallet_error_too_large.stderr | 18 +- .../undefined_call_part.rs | 17 + .../undefined_call_part.stderr | 18 +- .../undefined_event_part.rs | 17 + .../undefined_event_part.stderr | 38 +- .../undefined_genesis_config_part.rs | 17 + .../undefined_genesis_config_part.stderr | 38 +- .../undefined_inherent_part.rs | 17 + .../undefined_inherent_part.stderr | 108 ++--- .../undefined_origin_part.rs | 17 + .../undefined_origin_part.stderr | 38 +- .../undefined_validate_unsigned_part.rs | 17 + .../undefined_validate_unsigned_part.stderr | 66 +-- .../unsupported_meta_structure.rs | 17 + .../unsupported_meta_structure.stderr | 8 +- .../unsupported_pallet_attr.rs | 17 + .../unsupported_pallet_attr.stderr | 8 +- .../use_undefined_part.rs | 17 + .../use_undefined_part.stderr | 14 +- .../derive_impl_ui/attached_to_non_impl.rs | 17 + .../attached_to_non_impl.stderr | 4 +- .../derive_impl_ui/bad_default_impl_path.rs | 17 + .../bad_default_impl_path.stderr | 4 +- .../derive_impl_ui/bad_disambiguation_path.rs | 17 + .../bad_disambiguation_path.stderr | 4 +- ...ntime_type_fails_when_type_not_in_scope.rs | 17 + ...e_type_fails_when_type_not_in_scope.stderr | 6 +- .../inject_runtime_type_invalid.rs | 17 + .../inject_runtime_type_invalid.stderr | 10 +- .../missing_disambiguation_path.rs | 17 + .../missing_disambiguation_path.stderr | 4 +- .../derive_impl_ui/pass/basic_overriding.rs | 17 + .../pass/macro_magic_working.rs | 17 + .../pass/runtime_type_working.rs | 17 + .../test/tests/derive_no_bound_ui/clone.rs | 17 + .../tests/derive_no_bound_ui/clone.stderr | 8 +- .../test/tests/derive_no_bound_ui/debug.rs | 17 + .../tests/derive_no_bound_ui/debug.stderr | 14 +- .../test/tests/derive_no_bound_ui/default.rs | 17 + .../tests/derive_no_bound_ui/default.stderr | 8 +- .../derive_no_bound_ui/default_empty_enum.rs | 17 + .../default_empty_enum.stderr | 8 +- .../default_no_attribute.rs | 17 + .../default_no_attribute.stderr | 8 +- .../default_too_many_attributes.rs | 17 + .../default_too_many_attributes.stderr | 28 +- .../tests/derive_no_bound_ui/default_union.rs | 17 + .../derive_no_bound_ui/default_union.stderr | 8 +- .../test/tests/derive_no_bound_ui/eq.rs | 17 + .../test/tests/derive_no_bound_ui/eq.stderr | 20 +- .../tests/derive_no_bound_ui/partial_eq.rs | 17 + .../derive_no_bound_ui/partial_eq.stderr | 8 +- .../test/tests/pallet_ui/attr_non_empty.rs | 17 + .../tests/pallet_ui/attr_non_empty.stderr | 8 +- .../pallet_ui/call_argument_invalid_bound.rs | 17 + .../call_argument_invalid_bound.stderr | 16 +- .../call_argument_invalid_bound_2.rs | 17 + .../call_argument_invalid_bound_2.stderr | 26 +- .../call_argument_invalid_bound_3.rs | 17 + .../call_argument_invalid_bound_3.stderr | 12 +- .../pallet_ui/call_conflicting_indices.rs | 17 + .../pallet_ui/call_conflicting_indices.stderr | 8 +- .../tests/pallet_ui/call_index_has_suffix.rs | 17 + .../pallet_ui/call_index_has_suffix.stderr | 4 +- .../test/tests/pallet_ui/call_invalid_attr.rs | 17 + .../tests/pallet_ui/call_invalid_attr.stderr | 4 +- .../tests/pallet_ui/call_invalid_const.rs | 17 + .../tests/pallet_ui/call_invalid_const.stderr | 4 +- .../tests/pallet_ui/call_invalid_index.rs | 17 + .../tests/pallet_ui/call_invalid_index.stderr | 4 +- .../pallet_ui/call_invalid_origin_type.rs | 17 + .../pallet_ui/call_invalid_origin_type.stderr | 8 +- .../tests/pallet_ui/call_invalid_return.rs | 17 + .../pallet_ui/call_invalid_return.stderr | 4 +- .../test/tests/pallet_ui/call_invalid_vis.rs | 17 + .../tests/pallet_ui/call_invalid_vis.stderr | 4 +- .../tests/pallet_ui/call_invalid_vis_2.rs | 17 + .../tests/pallet_ui/call_invalid_vis_2.stderr | 4 +- .../tests/pallet_ui/call_missing_index.rs | 17 + .../tests/pallet_ui/call_missing_index.stderr | 16 +- .../tests/pallet_ui/call_missing_weight.rs | 17 + .../pallet_ui/call_missing_weight.stderr | 4 +- .../pallet_ui/call_multiple_call_index.rs | 17 + .../pallet_ui/call_multiple_call_index.stderr | 4 +- .../test/tests/pallet_ui/call_no_origin.rs | 17 + .../tests/pallet_ui/call_no_origin.stderr | 4 +- .../test/tests/pallet_ui/call_no_return.rs | 17 + .../tests/pallet_ui/call_no_return.stderr | 4 +- .../call_weight_argument_has_suffix.rs | 17 + .../call_weight_argument_has_suffix.stderr | 8 +- .../pallet_ui/call_weight_const_warning.rs | 17 + .../call_weight_const_warning.stderr | 4 +- .../call_weight_const_warning_twice.rs | 17 + .../call_weight_const_warning_twice.stderr | 12 +- .../call_weight_inherited_invalid.rs | 17 + .../call_weight_inherited_invalid.stderr | 8 +- .../call_weight_inherited_invalid2.rs | 17 + .../call_weight_inherited_invalid2.stderr | 8 +- .../call_weight_inherited_invalid3.rs | 17 + .../call_weight_inherited_invalid3.stderr | 20 +- .../call_weight_inherited_invalid4.rs | 17 + .../call_weight_inherited_invalid4.stderr | 8 +- .../call_weight_inherited_invalid5.rs | 17 + .../call_weight_inherited_invalid5.stderr | 8 +- .../compare_unset_storage_version.rs | 17 + .../compare_unset_storage_version.stderr | 4 +- .../composite_enum_unsupported_identifier.rs | 17 + ...mposite_enum_unsupported_identifier.stderr | 4 +- ...efault_config_with_no_default_in_system.rs | 17 + ...lt_config_with_no_default_in_system.stderr | 8 +- .../tests/pallet_ui/deprecated_store_attr.rs | 17 + .../pallet_ui/deprecated_store_attr.stderr | 12 +- .../tests/pallet_ui/dev_mode_without_arg.rs | 17 + .../pallet_ui/dev_mode_without_arg.stderr | 4 +- .../dev_mode_without_arg_call_index.rs | 17 + .../dev_mode_without_arg_call_index.stderr | 8 +- .../dev_mode_without_arg_default_hasher.rs | 17 + ...dev_mode_without_arg_default_hasher.stderr | 12 +- .../dev_mode_without_arg_max_encoded_len.rs | 17 + ...ev_mode_without_arg_max_encoded_len.stderr | 12 +- .../tests/pallet_ui/duplicate_call_attr.rs | 17 + .../pallet_ui/duplicate_call_attr.stderr | 4 +- .../pallet_ui/duplicate_storage_prefix.rs | 17 + .../pallet_ui/duplicate_storage_prefix.stderr | 32 +- .../tests/pallet_ui/duplicate_store_attr.rs | 17 + .../pallet_ui/duplicate_store_attr.stderr | 4 +- .../error_does_not_derive_pallet_error.rs | 17 + .../error_does_not_derive_pallet_error.stderr | 32 +- .../tests/pallet_ui/error_where_clause.rs | 17 + .../tests/pallet_ui/error_where_clause.stderr | 4 +- .../test/tests/pallet_ui/error_wrong_item.rs | 17 + .../tests/pallet_ui/error_wrong_item.stderr | 4 +- .../tests/pallet_ui/error_wrong_item_name.rs | 17 + .../pallet_ui/error_wrong_item_name.stderr | 4 +- .../tests/pallet_ui/event_field_not_member.rs | 17 + .../pallet_ui/event_field_not_member.stderr | 12 +- .../tests/pallet_ui/event_not_in_trait.rs | 17 + .../tests/pallet_ui/event_not_in_trait.stderr | 12 +- .../pallet_ui/event_type_invalid_bound.rs | 17 + .../pallet_ui/event_type_invalid_bound.stderr | 8 +- .../pallet_ui/event_type_invalid_bound_2.rs | 17 + .../event_type_invalid_bound_2.stderr | 8 +- .../test/tests/pallet_ui/event_wrong_item.rs | 17 + .../tests/pallet_ui/event_wrong_item.stderr | 4 +- .../tests/pallet_ui/event_wrong_item_name.rs | 17 + .../pallet_ui/event_wrong_item_name.stderr | 4 +- .../genesis_inconsistent_build_config.rs | 17 + .../genesis_inconsistent_build_config.stderr | 8 +- .../pallet_ui/genesis_invalid_generic.rs | 17 + .../pallet_ui/genesis_invalid_generic.stderr | 16 +- .../tests/pallet_ui/genesis_wrong_name.rs | 17 + .../tests/pallet_ui/genesis_wrong_name.stderr | 4 +- .../tests/pallet_ui/hold_reason_non_enum.rs | 17 + .../pallet_ui/hold_reason_non_enum.stderr | 4 +- .../tests/pallet_ui/hold_reason_not_pub.rs | 17 + .../pallet_ui/hold_reason_not_pub.stderr | 4 +- .../tests/pallet_ui/hooks_invalid_item.rs | 17 + .../tests/pallet_ui/hooks_invalid_item.stderr | 6 +- .../pallet_ui/inconsistent_instance_1.rs | 17 + .../pallet_ui/inconsistent_instance_1.stderr | 20 +- .../pallet_ui/inconsistent_instance_2.rs | 17 + .../pallet_ui/inconsistent_instance_2.stderr | 20 +- .../pallet_ui/inherent_check_inner_span.rs | 17 + .../inherent_check_inner_span.stderr | 4 +- .../tests/pallet_ui/inherent_invalid_item.rs | 17 + .../pallet_ui/inherent_invalid_item.stderr | 4 +- .../test/tests/pallet_ui/lock_id_duplicate.rs | 17 + .../tests/pallet_ui/lock_id_duplicate.stderr | 4 +- .../test/tests/pallet_ui/mod_not_inlined.rs | 17 + .../tests/pallet_ui/mod_not_inlined.stderr | 20 +- ...default_bounds_but_missing_with_default.rs | 17 + ...ult_bounds_but_missing_with_default.stderr | 8 +- .../no_default_but_missing_with_default.rs | 17 + ...no_default_but_missing_with_default.stderr | 8 +- ...storage_map_explicit_key_default_hasher.rs | 17 + ...age_map_explicit_key_default_hasher.stderr | 12 +- .../pallet_ui/pallet_doc_arg_non_path.rs | 17 + .../pallet_ui/pallet_doc_arg_non_path.stderr | 8 +- .../test/tests/pallet_ui/pallet_doc_empty.rs | 17 + .../tests/pallet_ui/pallet_doc_empty.stderr | 8 +- .../tests/pallet_ui/pallet_doc_invalid_arg.rs | 17 + .../pallet_ui/pallet_doc_invalid_arg.stderr | 8 +- .../pallet_ui/pallet_doc_multiple_args.rs | 17 + .../pallet_ui/pallet_doc_multiple_args.stderr | 8 +- .../tests/pallet_ui/pallet_invalid_arg.rs | 17 + .../tests/pallet_ui/pallet_invalid_arg.stderr | 8 +- .../pallet_ui/pallet_struct_invalid_attr.rs | 17 + .../pallet_struct_invalid_attr.stderr | 8 +- .../tests/pallet_ui/pass/default_config.rs | 17 + .../tests/pallet_ui/pass/dev_mode_valid.rs | 17 + .../pallet_ui/pass/error_nested_types.rs | 17 + .../pallet_ui/pass/inherited_call_weight.rs | 17 + .../pallet_ui/pass/inherited_call_weight2.rs | 17 + .../pallet_ui/pass/inherited_call_weight3.rs | 17 + .../pass/inherited_call_weight_dev_mode.rs | 17 + .../pallet_ui/pass/no_std_genesis_config.rs | 17 + .../pass/trait_constant_valid_bounds.rs | 17 + .../pass/where_clause_missing_hooks.rs | 17 + ...storage_ensure_span_are_ok_on_wrong_gen.rs | 17 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 28 +- ...ensure_span_are_ok_on_wrong_gen_unnamed.rs | 17 + ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 28 +- .../pallet_ui/storage_incomplete_item.rs | 17 + .../pallet_ui/storage_incomplete_item.stderr | 8 +- .../pallet_ui/storage_info_unsatisfied.rs | 17 + .../pallet_ui/storage_info_unsatisfied.stderr | 32 +- .../storage_info_unsatisfied_nmap.rs | 17 + .../storage_info_unsatisfied_nmap.stderr | 4 +- .../pallet_ui/storage_invalid_attribute.rs | 17 + .../storage_invalid_attribute.stderr | 4 +- .../storage_invalid_first_generic.rs | 17 + .../storage_invalid_first_generic.stderr | 8 +- .../pallet_ui/storage_invalid_rename_value.rs | 17 + .../storage_invalid_rename_value.stderr | 4 +- .../pallet_ui/storage_multiple_getters.rs | 17 + .../pallet_ui/storage_multiple_getters.stderr | 4 +- .../pallet_ui/storage_multiple_renames.rs | 17 + .../pallet_ui/storage_multiple_renames.stderr | 4 +- .../pallet_ui/storage_not_storage_type.rs | 17 + .../pallet_ui/storage_not_storage_type.stderr | 4 +- .../storage_result_query_missing_generics.rs | 17 + ...orage_result_query_missing_generics.stderr | 10 +- ...storage_result_query_multiple_type_args.rs | 17 + ...age_result_query_multiple_type_args.stderr | 4 +- ...ge_result_query_no_defined_pallet_error.rs | 17 + ...esult_query_no_defined_pallet_error.stderr | 4 +- ...age_result_query_parenthesized_generics.rs | 17 + ...result_query_parenthesized_generics.stderr | 4 +- ...storage_result_query_wrong_generic_kind.rs | 17 + ...age_result_query_wrong_generic_kind.stderr | 4 +- .../storage_value_duplicate_named_generic.rs | 17 + ...orage_value_duplicate_named_generic.stderr | 8 +- ...storage_value_generic_named_and_unnamed.rs | 17 + ...age_value_generic_named_and_unnamed.stderr | 4 +- .../pallet_ui/storage_value_no_generic.rs | 17 + .../pallet_ui/storage_value_no_generic.stderr | 4 +- .../storage_value_unexpected_named_generic.rs | 17 + ...rage_value_unexpected_named_generic.stderr | 8 +- .../tests/pallet_ui/storage_wrong_item.rs | 17 + .../tests/pallet_ui/storage_wrong_item.stderr | 4 +- .../pallet_ui/store_trait_leak_private.rs | 17 + .../pallet_ui/store_trait_leak_private.stderr | 10 +- .../pallet_ui/trait_constant_invalid_bound.rs | 17 + .../trait_constant_invalid_bound.stderr | 8 +- .../trait_constant_invalid_bound_lifetime.rs | 17 + ...ait_constant_invalid_bound_lifetime.stderr | 8 +- .../tests/pallet_ui/trait_invalid_item.rs | 17 + .../tests/pallet_ui/trait_invalid_item.stderr | 8 +- .../trait_item_duplicate_constant_attr.rs | 17 + .../trait_item_duplicate_constant_attr.stderr | 8 +- .../trait_item_duplicate_no_default.rs | 17 + .../trait_item_duplicate_no_default.stderr | 4 +- .../tests/pallet_ui/trait_no_supertrait.rs | 17 + .../pallet_ui/trait_no_supertrait.stderr | 8 +- .../pallet_ui/type_value_error_in_block.rs | 17 + .../type_value_error_in_block.stderr | 4 +- .../type_value_forgotten_where_clause.rs | 17 + .../type_value_forgotten_where_clause.stderr | 36 +- .../pallet_ui/type_value_invalid_item.rs | 17 + .../pallet_ui/type_value_invalid_item.stderr | 4 +- .../tests/pallet_ui/type_value_no_return.rs | 17 + .../pallet_ui/type_value_no_return.stderr | 4 +- .../tests/split_ui/import_without_pallet.rs | 17 + .../split_ui/import_without_pallet.stderr | 4 +- .../test/tests/split_ui/no_section_found.rs | 17 + .../tests/split_ui/no_section_found.stderr | 20 +- .../test/tests/split_ui/pass/split_valid.rs | 17 + .../pass/split_valid_disambiguation.rs | 17 + .../tests/split_ui/section_not_imported.rs | 17 + .../split_ui/section_not_imported.stderr | 4 +- .../checks_for_valid_storage_type.rs | 17 + .../checks_for_valid_storage_type.stderr | 8 +- .../forbid_underscore_as_prefix.rs | 17 + .../forbid_underscore_as_prefix.stderr | 8 +- .../prefix_must_be_an_ident.rs | 17 + .../prefix_must_be_an_ident.stderr | 8 +- .../frame/transaction-payment/src/payment.rs | 17 + substrate/frame/tx-pause/src/benchmarking.rs | 2 +- substrate/frame/tx-pause/src/lib.rs | 2 +- substrate/frame/tx-pause/src/mock.rs | 2 +- substrate/frame/tx-pause/src/tests.rs | 2 +- .../test/tests/ui/adding_self_parameter.rs | 17 + .../tests/ui/adding_self_parameter.stderr | 8 +- .../tests/ui/changed_in_no_default_method.rs | 17 + .../ui/changed_in_no_default_method.stderr | 8 +- .../tests/ui/changed_in_unknown_version.rs | 17 + .../ui/changed_in_unknown_version.stderr | 8 +- .../api/test/tests/ui/declaring_old_block.rs | 17 + .../test/tests/ui/declaring_old_block.stderr | 16 +- ...declaring_own_block_with_different_name.rs | 17 + ...aring_own_block_with_different_name.stderr | 8 +- .../tests/ui/empty_impl_runtime_apis_call.rs | 17 + .../ui/empty_impl_runtime_apis_call.stderr | 4 +- .../ui/impl_incorrect_method_signature.rs | 17 + .../ui/impl_incorrect_method_signature.stderr | 26 +- .../api/test/tests/ui/impl_missing_version.rs | 17 + .../test/tests/ui/impl_missing_version.stderr | 6 +- .../ui/impl_two_traits_with_same_name.rs | 17 + .../ui/impl_two_traits_with_same_name.stderr | 4 +- .../test/tests/ui/invalid_api_version_1.rs | 17 + .../tests/ui/invalid_api_version_1.stderr | 8 +- .../test/tests/ui/invalid_api_version_2.rs | 17 + .../tests/ui/invalid_api_version_2.stderr | 8 +- .../test/tests/ui/invalid_api_version_3.rs | 17 + .../tests/ui/invalid_api_version_3.stderr | 8 +- .../test/tests/ui/invalid_api_version_4.rs | 17 + .../tests/ui/invalid_api_version_4.stderr | 8 +- .../ui/method_ver_lower_than_trait_ver.rs | 17 + .../ui/method_ver_lower_than_trait_ver.stderr | 16 +- .../ui/missing_block_generic_parameter.rs | 17 + .../ui/missing_block_generic_parameter.stderr | 4 +- .../test/tests/ui/missing_path_for_trait.rs | 17 + .../tests/ui/missing_path_for_trait.stderr | 4 +- .../test/tests/ui/missing_versioned_method.rs | 17 + .../tests/ui/missing_versioned_method.stderr | 6 +- .../missing_versioned_method_multiple_vers.rs | 17 + ...sing_versioned_method_multiple_vers.stderr | 6 +- .../ui/mock_advanced_hash_by_reference.rs | 17 + .../ui/mock_advanced_hash_by_reference.stderr | 14 +- .../tests/ui/mock_advanced_missing_hash.rs | 17 + .../ui/mock_advanced_missing_hash.stderr | 4 +- .../test/tests/ui/mock_only_one_block_type.rs | 17 + .../tests/ui/mock_only_one_block_type.stderr | 8 +- .../test/tests/ui/mock_only_one_self_type.rs | 17 + .../tests/ui/mock_only_one_self_type.stderr | 8 +- .../test/tests/ui/mock_only_self_reference.rs | 17 + .../tests/ui/mock_only_self_reference.stderr | 54 +-- .../tests/ui/no_default_implementation.rs | 17 + .../tests/ui/no_default_implementation.stderr | 14 +- .../ui/positive_cases/custom_where_bound.rs | 17 + .../tests/ui/positive_cases/default_impls.rs | 17 + ...ype_reference_in_impl_runtime_apis_call.rs | 17 + ...reference_in_impl_runtime_apis_call.stderr | 28 +- substrate/primitives/core/benches/bench.rs | 2 +- .../crypto/ec-utils/src/bls12_377.rs | 2 +- .../crypto/ec-utils/src/bls12_381.rs | 2 +- .../primitives/crypto/ec-utils/src/bw6_761.rs | 2 +- .../crypto/ec-utils/src/ed_on_bls12_377.rs | 2 +- .../src/ed_on_bls12_381_bandersnatch.rs | 2 +- .../tests/ui/no_duplicate_versions.rs | 17 + .../tests/ui/no_duplicate_versions.stderr | 16 +- .../tests/ui/no_feature_gated_method.rs | 17 + .../tests/ui/no_feature_gated_method.stderr | 4 +- .../tests/ui/no_gaps_in_versions.rs | 17 + .../tests/ui/no_gaps_in_versions.stderr | 4 +- .../tests/ui/no_generic_parameters_method.rs | 17 + .../ui/no_generic_parameters_method.stderr | 8 +- .../tests/ui/no_generic_parameters_trait.rs | 17 + .../ui/no_generic_parameters_trait.stderr | 8 +- .../tests/ui/no_method_implementation.rs | 17 + .../tests/ui/no_method_implementation.stderr | 8 +- .../ui/no_versioned_conditional_build.rs | 17 + .../ui/no_versioned_conditional_build.stderr | 8 +- .../tests/ui/pass_by_enum_with_struct.rs | 17 + .../tests/ui/pass_by_enum_with_struct.stderr | 12 +- .../ui/pass_by_enum_with_value_variant.rs | 17 + .../ui/pass_by_enum_with_value_variant.stderr | 12 +- .../tests/ui/pass_by_inner_with_two_fields.rs | 17 + .../ui/pass_by_inner_with_two_fields.stderr | 12 +- .../tests/ui/take_self_by_value.rs | 17 + .../tests/ui/take_self_by_value.stderr | 8 +- .../staking/src/currency_to_vote.rs | 2 +- .../ci/node-template-release/src/main.rs | 18 + 1046 files changed, 6695 insertions(+), 1891 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index e213acd4988..3da699a354f 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -9,10 +9,9 @@ permissions: jobs: check-licenses: runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - repo: [polkadot] + env: + LICENSES: "'Apache-2.0' 'GPL-3.0-only' 'GPL-3.0-or-later WITH Classpath-exception-2.0'" + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout sources uses: actions/checkout@v3 @@ -21,16 +20,26 @@ jobs: node-version: "18.x" registry-url: "https://npm.pkg.github.com" scope: "@paritytech" - - name: Check the licenses for ${{ matrix.repo }} + + - name: Check the licenses in Polkadot run: | shopt -s globstar - echo "install" - npm install -g @paritytech/license-scanner@0.0.5 - echo "run for ${{ matrix.repo }}" - cd ${{ matrix.repo }} npx @paritytech/license-scanner scan \ - --ensure-licenses=Apache-2.0 \ - --ensure-licenses=GPL-3.0-only \ - ./**/*.rs - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + --ensure-licenses ${{ env.LICENSES }} \ + -- ./polkadot/**/*.rs + + - name: Check the licenses in Cumulus + run: | + shopt -s globstar + npx @paritytech/license-scanner scan \ + --ensure-licenses ${{ env.LICENSES }} \ + --exclude ./cumulus/parachain-template \ + -- ./cumulus/**/*.rs + + - name: Check the licenses in Substrate + run: | + shopt -s globstar + npx @paritytech/license-scanner scan \ + --ensure-licenses ${{ env.LICENSES }} \ + --exclude ./substrate/bin/node-template \ + -- ./substrate/**/*.rs diff --git a/cumulus/bridges/bin/runtime-common/src/integrity.rs b/cumulus/bridges/bin/runtime-common/src/integrity.rs index a0af3b981f3..290c22f835d 100644 --- a/cumulus/bridges/bin/runtime-common/src/integrity.rs +++ b/cumulus/bridges/bin/runtime-common/src/integrity.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/lib.rs b/cumulus/bridges/bin/runtime-common/src/lib.rs index 817922bc907..ae6f40b1421 100644 --- a/cumulus/bridges/bin/runtime-common/src/lib.rs +++ b/cumulus/bridges/bin/runtime-common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages.rs b/cumulus/bridges/bin/runtime-common/src/messages.rs index a650f082774..ac66adae661 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_api.rs b/cumulus/bridges/bin/runtime-common/src/messages_api.rs index 199e062fe98..ccf1c754041 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_api.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_api.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs b/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs index b067523c305..60f4bb17858 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs b/cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs index badb17efa08..07a99d2c0a1 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_generation.rs b/cumulus/bridges/bin/runtime-common/src/messages_generation.rs index 8dbf3abd683..3c550a9bd0f 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_generation.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_generation.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 44e554ecb24..b47e9994da7 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/mock.rs b/cumulus/bridges/bin/runtime-common/src/mock.rs index 9c41d17fa99..45ef790d744 100644 --- a/cumulus/bridges/bin/runtime-common/src/mock.rs +++ b/cumulus/bridges/bin/runtime-common/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs b/cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs index aad53673c3a..63dc78385e4 100644 --- a/cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs +++ b/cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs b/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs index 590de05fb1c..dad6c77b01f 100644 --- a/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs index 4e577e88a41..cea43b7c1de 100644 --- a/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/benchmarking.rs b/cumulus/bridges/modules/grandpa/src/benchmarking.rs index aa222d6e4de..182b2f56eb1 100644 --- a/cumulus/bridges/modules/grandpa/src/benchmarking.rs +++ b/cumulus/bridges/modules/grandpa/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/call_ext.rs b/cumulus/bridges/modules/grandpa/src/call_ext.rs index 7a6c61007de..e0648d5dd0f 100644 --- a/cumulus/bridges/modules/grandpa/src/call_ext.rs +++ b/cumulus/bridges/modules/grandpa/src/call_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/lib.rs b/cumulus/bridges/modules/grandpa/src/lib.rs index 425712ad9a2..22df604bf18 100644 --- a/cumulus/bridges/modules/grandpa/src/lib.rs +++ b/cumulus/bridges/modules/grandpa/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/mock.rs b/cumulus/bridges/modules/grandpa/src/mock.rs index bd305dfef9d..f88a0a3e6a6 100644 --- a/cumulus/bridges/modules/grandpa/src/mock.rs +++ b/cumulus/bridges/modules/grandpa/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/storage_types.rs b/cumulus/bridges/modules/grandpa/src/storage_types.rs index 59fcb5d3f07..6d1a7882dd4 100644 --- a/cumulus/bridges/modules/grandpa/src/storage_types.rs +++ b/cumulus/bridges/modules/grandpa/src/storage_types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/grandpa/src/weights.rs b/cumulus/bridges/modules/grandpa/src/weights.rs index 4b94f7adfe7..89ed70d13ac 100644 --- a/cumulus/bridges/modules/grandpa/src/weights.rs +++ b/cumulus/bridges/modules/grandpa/src/weights.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/benchmarking.rs b/cumulus/bridges/modules/messages/src/benchmarking.rs index 04f64b53b30..8c4e6fbf00c 100644 --- a/cumulus/bridges/modules/messages/src/benchmarking.rs +++ b/cumulus/bridges/modules/messages/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/inbound_lane.rs b/cumulus/bridges/modules/messages/src/inbound_lane.rs index 359e9022b0b..966ec939e70 100644 --- a/cumulus/bridges/modules/messages/src/inbound_lane.rs +++ b/cumulus/bridges/modules/messages/src/inbound_lane.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/lib.rs b/cumulus/bridges/modules/messages/src/lib.rs index 67c6fb23cf1..b87c64d1607 100644 --- a/cumulus/bridges/modules/messages/src/lib.rs +++ b/cumulus/bridges/modules/messages/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/mock.rs b/cumulus/bridges/modules/messages/src/mock.rs index 67f7b78a487..aebb7eafa78 100644 --- a/cumulus/bridges/modules/messages/src/mock.rs +++ b/cumulus/bridges/modules/messages/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/outbound_lane.rs b/cumulus/bridges/modules/messages/src/outbound_lane.rs index 45b0f4e6809..f92e9ccfd95 100644 --- a/cumulus/bridges/modules/messages/src/outbound_lane.rs +++ b/cumulus/bridges/modules/messages/src/outbound_lane.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/weights.rs b/cumulus/bridges/modules/messages/src/weights.rs index 9880f1dd1ea..5b6863984ec 100644 --- a/cumulus/bridges/modules/messages/src/weights.rs +++ b/cumulus/bridges/modules/messages/src/weights.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/messages/src/weights_ext.rs b/cumulus/bridges/modules/messages/src/weights_ext.rs index 3aefd6be7ca..1be24a738a4 100644 --- a/cumulus/bridges/modules/messages/src/weights_ext.rs +++ b/cumulus/bridges/modules/messages/src/weights_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/benchmarking.rs b/cumulus/bridges/modules/parachains/src/benchmarking.rs index 59c4642cde9..27e06a12a1d 100644 --- a/cumulus/bridges/modules/parachains/src/benchmarking.rs +++ b/cumulus/bridges/modules/parachains/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/call_ext.rs b/cumulus/bridges/modules/parachains/src/call_ext.rs index ea842a61b3e..99640dadc61 100644 --- a/cumulus/bridges/modules/parachains/src/call_ext.rs +++ b/cumulus/bridges/modules/parachains/src/call_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/lib.rs b/cumulus/bridges/modules/parachains/src/lib.rs index be46fae3c92..b2ef0bf52bd 100644 --- a/cumulus/bridges/modules/parachains/src/lib.rs +++ b/cumulus/bridges/modules/parachains/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/mock.rs b/cumulus/bridges/modules/parachains/src/mock.rs index a7030f0ae03..14afe384171 100644 --- a/cumulus/bridges/modules/parachains/src/mock.rs +++ b/cumulus/bridges/modules/parachains/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/weights.rs b/cumulus/bridges/modules/parachains/src/weights.rs index 1e81dba72fe..9182ec46611 100644 --- a/cumulus/bridges/modules/parachains/src/weights.rs +++ b/cumulus/bridges/modules/parachains/src/weights.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/parachains/src/weights_ext.rs b/cumulus/bridges/modules/parachains/src/weights_ext.rs index eecdfe90359..13bc9ad2bbc 100644 --- a/cumulus/bridges/modules/parachains/src/weights_ext.rs +++ b/cumulus/bridges/modules/parachains/src/weights_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/benchmarking.rs b/cumulus/bridges/modules/relayers/src/benchmarking.rs index d66a11ff06d..2d74ab38f9d 100644 --- a/cumulus/bridges/modules/relayers/src/benchmarking.rs +++ b/cumulus/bridges/modules/relayers/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/lib.rs b/cumulus/bridges/modules/relayers/src/lib.rs index a71c218443b..b9b98ca7e25 100644 --- a/cumulus/bridges/modules/relayers/src/lib.rs +++ b/cumulus/bridges/modules/relayers/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/mock.rs b/cumulus/bridges/modules/relayers/src/mock.rs index b3fcb24cdd2..4713ec91658 100644 --- a/cumulus/bridges/modules/relayers/src/mock.rs +++ b/cumulus/bridges/modules/relayers/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/payment_adapter.rs b/cumulus/bridges/modules/relayers/src/payment_adapter.rs index a9536cfc027..b2d9c676bdd 100644 --- a/cumulus/bridges/modules/relayers/src/payment_adapter.rs +++ b/cumulus/bridges/modules/relayers/src/payment_adapter.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/stake_adapter.rs b/cumulus/bridges/modules/relayers/src/stake_adapter.rs index 055b6a111ec..88af9b1877b 100644 --- a/cumulus/bridges/modules/relayers/src/stake_adapter.rs +++ b/cumulus/bridges/modules/relayers/src/stake_adapter.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/weights.rs b/cumulus/bridges/modules/relayers/src/weights.rs index 1bc195a5424..2e064a3936d 100644 --- a/cumulus/bridges/modules/relayers/src/weights.rs +++ b/cumulus/bridges/modules/relayers/src/weights.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/relayers/src/weights_ext.rs b/cumulus/bridges/modules/relayers/src/weights_ext.rs index d459b0686bd..9cd25c47c37 100644 --- a/cumulus/bridges/modules/relayers/src/weights_ext.rs +++ b/cumulus/bridges/modules/relayers/src/weights_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index b32b983daf7..dbbce84d3eb 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 87e050b45c7..5cf94fc83fd 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 5ad7be4890a..cd50b98a168 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs index 04909f3b2e8..62936e997f3 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs b/cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs index b3b25ba6edd..94016c1da0c 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs +++ b/cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs b/cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs index 7363e5af02a..486fba60e1f 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs +++ b/cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index 525b2e62cea..feef61c7f20 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs b/cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs index af50a97b28b..3a919648df4 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs +++ b/cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs b/cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs index a1f6ae1a1a9..bf8d8e07c3a 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs +++ b/cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index 37b1a9ebb92..b726c62ac42 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs index 635a4c96054..5e4758645d9 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-kusama/src/lib.rs b/cumulus/bridges/primitives/chain-kusama/src/lib.rs index b758484aefe..e234a87b6cf 100644 --- a/cumulus/bridges/primitives/chain-kusama/src/lib.rs +++ b/cumulus/bridges/primitives/chain-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-polkadot/src/lib.rs b/cumulus/bridges/primitives/chain-polkadot/src/lib.rs index eb62c1729ad..9585fd4d716 100644 --- a/cumulus/bridges/primitives/chain-polkadot/src/lib.rs +++ b/cumulus/bridges/primitives/chain-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-rococo/src/lib.rs b/cumulus/bridges/primitives/chain-rococo/src/lib.rs index 140069d7569..cf7cd16990f 100644 --- a/cumulus/bridges/primitives/chain-rococo/src/lib.rs +++ b/cumulus/bridges/primitives/chain-rococo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/chain-wococo/src/lib.rs b/cumulus/bridges/primitives/chain-wococo/src/lib.rs index 8247b63238c..c64451993ee 100644 --- a/cumulus/bridges/primitives/chain-wococo/src/lib.rs +++ b/cumulus/bridges/primitives/chain-wococo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/justification/mod.rs b/cumulus/bridges/primitives/header-chain/src/justification/mod.rs index 44548b8d3ff..24c453a0790 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/mod.rs +++ b/cumulus/bridges/primitives/header-chain/src/justification/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs b/cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs index 2484fc4d6b2..e2d7a8e804c 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs +++ b/cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs b/cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs index 353960734cc..bb8aaadf327 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs b/cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs index 99ccdd50616..6552b359170 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs +++ b/cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs b/cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs index a9d5f4c1f73..f899c6c8efc 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs +++ b/cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/lib.rs b/cumulus/bridges/primitives/header-chain/src/lib.rs index ea6c58f4c09..7008dfa6063 100644 --- a/cumulus/bridges/primitives/header-chain/src/lib.rs +++ b/cumulus/bridges/primitives/header-chain/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/src/storage_keys.rs b/cumulus/bridges/primitives/header-chain/src/storage_keys.rs index c4dbe53bd9a..55d095afbf2 100644 --- a/cumulus/bridges/primitives/header-chain/src/storage_keys.rs +++ b/cumulus/bridges/primitives/header-chain/src/storage_keys.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/tests/implementation_match.rs b/cumulus/bridges/primitives/header-chain/tests/implementation_match.rs index db96961832d..f664a419621 100644 --- a/cumulus/bridges/primitives/header-chain/tests/implementation_match.rs +++ b/cumulus/bridges/primitives/header-chain/tests/implementation_match.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs b/cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs index f3c133481fb..0bc084cc1a9 100644 --- a/cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs +++ b/cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs b/cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs index bdc90a3b07c..21bcd7e86b5 100644 --- a/cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs +++ b/cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/strict.rs b/cumulus/bridges/primitives/header-chain/tests/justification/strict.rs index 9568f7f7cf9..188c9f5baba 100644 --- a/cumulus/bridges/primitives/header-chain/tests/justification/strict.rs +++ b/cumulus/bridges/primitives/header-chain/tests/justification/strict.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/header-chain/tests/tests.rs b/cumulus/bridges/primitives/header-chain/tests/tests.rs index 7c525a9303a..269fde09bb7 100644 --- a/cumulus/bridges/primitives/header-chain/tests/tests.rs +++ b/cumulus/bridges/primitives/header-chain/tests/tests.rs @@ -1,3 +1,19 @@ +// 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 . + mod justification { mod equivocation; mod optimizer; diff --git a/cumulus/bridges/primitives/messages/src/lib.rs b/cumulus/bridges/primitives/messages/src/lib.rs index 8cafd58650f..e48914f7591 100644 --- a/cumulus/bridges/primitives/messages/src/lib.rs +++ b/cumulus/bridges/primitives/messages/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/messages/src/source_chain.rs b/cumulus/bridges/primitives/messages/src/source_chain.rs index 5e4be53c53a..73092c3cce0 100644 --- a/cumulus/bridges/primitives/messages/src/source_chain.rs +++ b/cumulus/bridges/primitives/messages/src/source_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/messages/src/storage_keys.rs b/cumulus/bridges/primitives/messages/src/storage_keys.rs index 4edf9828cfd..8eedf8fcc7a 100644 --- a/cumulus/bridges/primitives/messages/src/storage_keys.rs +++ b/cumulus/bridges/primitives/messages/src/storage_keys.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/messages/src/target_chain.rs b/cumulus/bridges/primitives/messages/src/target_chain.rs index 3d73ca50013..388ce16ccdc 100644 --- a/cumulus/bridges/primitives/messages/src/target_chain.rs +++ b/cumulus/bridges/primitives/messages/src/target_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/parachains/src/lib.rs b/cumulus/bridges/primitives/parachains/src/lib.rs index 21e78e0009f..262b9c6f977 100644 --- a/cumulus/bridges/primitives/parachains/src/lib.rs +++ b/cumulus/bridges/primitives/parachains/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/polkadot-core/src/lib.rs b/cumulus/bridges/primitives/polkadot-core/src/lib.rs index 36ef58eed4d..b35d97ec79a 100644 --- a/cumulus/bridges/primitives/polkadot-core/src/lib.rs +++ b/cumulus/bridges/primitives/polkadot-core/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/polkadot-core/src/parachains.rs b/cumulus/bridges/primitives/polkadot-core/src/parachains.rs index 7268d9c70af..3cf8eca0c6b 100644 --- a/cumulus/bridges/primitives/polkadot-core/src/parachains.rs +++ b/cumulus/bridges/primitives/polkadot-core/src/parachains.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/relayers/src/lib.rs b/cumulus/bridges/primitives/relayers/src/lib.rs index 21f66a2ffa1..c529eea536d 100644 --- a/cumulus/bridges/primitives/relayers/src/lib.rs +++ b/cumulus/bridges/primitives/relayers/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/relayers/src/registration.rs b/cumulus/bridges/primitives/relayers/src/registration.rs index 7ab20844bdf..bc2d0d127ae 100644 --- a/cumulus/bridges/primitives/relayers/src/registration.rs +++ b/cumulus/bridges/primitives/relayers/src/registration.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/chain.rs b/cumulus/bridges/primitives/runtime/src/chain.rs index 43fdaf8da1b..5caaebd42ba 100644 --- a/cumulus/bridges/primitives/runtime/src/chain.rs +++ b/cumulus/bridges/primitives/runtime/src/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/extensions.rs b/cumulus/bridges/primitives/runtime/src/extensions.rs index 96ee9d1e6ec..253350d17e7 100644 --- a/cumulus/bridges/primitives/runtime/src/extensions.rs +++ b/cumulus/bridges/primitives/runtime/src/extensions.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/lib.rs b/cumulus/bridges/primitives/runtime/src/lib.rs index f4f52866de9..ece782e352b 100644 --- a/cumulus/bridges/primitives/runtime/src/lib.rs +++ b/cumulus/bridges/primitives/runtime/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/messages.rs b/cumulus/bridges/primitives/runtime/src/messages.rs index e3ce37ed592..0f219e984f7 100644 --- a/cumulus/bridges/primitives/runtime/src/messages.rs +++ b/cumulus/bridges/primitives/runtime/src/messages.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/storage_proof.rs b/cumulus/bridges/primitives/runtime/src/storage_proof.rs index 09641376666..1b706aa66c1 100644 --- a/cumulus/bridges/primitives/runtime/src/storage_proof.rs +++ b/cumulus/bridges/primitives/runtime/src/storage_proof.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/runtime/src/storage_types.rs b/cumulus/bridges/primitives/runtime/src/storage_types.rs index e555f60e87f..91c5451805a 100644 --- a/cumulus/bridges/primitives/runtime/src/storage_types.rs +++ b/cumulus/bridges/primitives/runtime/src/storage_types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/test-utils/src/keyring.rs b/cumulus/bridges/primitives/test-utils/src/keyring.rs index a4e818a3b88..b99132de3ec 100644 --- a/cumulus/bridges/primitives/test-utils/src/keyring.rs +++ b/cumulus/bridges/primitives/test-utils/src/keyring.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/test-utils/src/lib.rs b/cumulus/bridges/primitives/test-utils/src/lib.rs index 5a7d0cca279..4d3b8475993 100644 --- a/cumulus/bridges/primitives/test-utils/src/lib.rs +++ b/cumulus/bridges/primitives/test-utils/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs index 0dd329f9e4a..dbedb7a52c7 100644 --- a/cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs +++ b/cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index 3ad68eb04ea..1b18ed06437 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/collator/src/lib.rs b/cumulus/client/collator/src/lib.rs index 647107a7c7c..f17ae488310 100644 --- a/cumulus/client/collator/src/lib.rs +++ b/cumulus/client/collator/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/client/collator/src/service.rs b/cumulus/client/collator/src/service.rs index c798cb84c23..c06be006fc1 100644 --- a/cumulus/client/collator/src/service.rs +++ b/cumulus/client/collator/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/collator.rs b/cumulus/client/consensus/aura/src/collator.rs index 37cf1ea57c3..b00c3952e2b 100644 --- a/cumulus/client/consensus/aura/src/collator.rs +++ b/cumulus/client/consensus/aura/src/collator.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index d6f30aa672b..3c904915cea 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 9663ef5ad3a..58d8e9d1a06 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs index 55128dfdc85..4c7b759daf7 100644 --- a/cumulus/client/consensus/aura/src/collators/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs index 919e0da39b1..5cd65ed5546 100644 --- a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs +++ b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/import_queue.rs b/cumulus/client/consensus/aura/src/import_queue.rs index 2f422b9edb1..2611eaf532f 100644 --- a/cumulus/client/consensus/aura/src/import_queue.rs +++ b/cumulus/client/consensus/aura/src/import_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/aura/src/lib.rs b/cumulus/client/consensus/aura/src/lib.rs index 792f7b230d6..6ededa7a92c 100644 --- a/cumulus/client/consensus/aura/src/lib.rs +++ b/cumulus/client/consensus/aura/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/common/src/import_queue.rs b/cumulus/client/consensus/common/src/import_queue.rs index e54598ac856..311a2b7ad8c 100644 --- a/cumulus/client/consensus/common/src/import_queue.rs +++ b/cumulus/client/consensus/common/src/import_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/common/src/level_monitor.rs b/cumulus/client/consensus/common/src/level_monitor.rs index 8a6bbef62f3..5f115ec2c4a 100644 --- a/cumulus/client/consensus/common/src/level_monitor.rs +++ b/cumulus/client/consensus/common/src/level_monitor.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index 49e157481e7..edd97cf02a2 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/common/src/parachain_consensus.rs b/cumulus/client/consensus/common/src/parachain_consensus.rs index 5bbaa2893cf..b4b315bb32b 100644 --- a/cumulus/client/consensus/common/src/parachain_consensus.rs +++ b/cumulus/client/consensus/common/src/parachain_consensus.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index b6fcc4a1764..15586d81d9b 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/proposer/src/lib.rs b/cumulus/client/consensus/proposer/src/lib.rs index c2e95eca3a3..7404651bcd9 100644 --- a/cumulus/client/consensus/proposer/src/lib.rs +++ b/cumulus/client/consensus/proposer/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/relay-chain/src/import_queue.rs b/cumulus/client/consensus/relay-chain/src/import_queue.rs index 72704673bf8..9ee03b95904 100644 --- a/cumulus/client/consensus/relay-chain/src/import_queue.rs +++ b/cumulus/client/consensus/relay-chain/src/import_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/consensus/relay-chain/src/lib.rs b/cumulus/client/consensus/relay-chain/src/lib.rs index ee912520d66..fc395a9d957 100644 --- a/cumulus/client/consensus/relay-chain/src/lib.rs +++ b/cumulus/client/consensus/relay-chain/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/network/src/lib.rs b/cumulus/client/network/src/lib.rs index b42342e5b77..1c70b823411 100644 --- a/cumulus/client/network/src/lib.rs +++ b/cumulus/client/network/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index e1bb961c75f..af7747622ef 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs index feb09d005ce..322b19c796a 100644 --- a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs +++ b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index a7509c54ab0..b050bc66799 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 5b3ab15ed6f..42a56b649f0 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index a0258e20632..a6970732447 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 fc4d803002c..0a3d61e83e5 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 0acd04e73cd..491758c1329 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 8d022821908..366d428eda7 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index 5097e6ce33a..f39d7a26dd8 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index c01f38433dc..96f8fc8b556 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b6773870512..84e66f95571 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index 5a35b2b5bfa..322bcc93dae 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b079294b784..8d070d62820 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/relay-chain-rpc-interface/src/tokio_platform.rs b/cumulus/client/relay-chain-rpc-interface/src/tokio_platform.rs index 7b8c69645b6..75a5604d741 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/tokio_platform.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/tokio_platform.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 11b6240eb73..211a5cc3b79 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/file_header.txt b/cumulus/file_header.txt index 04f0c5de271..712045bf2ca 100644 --- a/cumulus/file_header.txt +++ b/cumulus/file_header.txt @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/aura-ext/src/consensus_hook.rs b/cumulus/pallets/aura-ext/src/consensus_hook.rs index 745ee7a3352..089ab5c3198 100644 --- a/cumulus/pallets/aura-ext/src/consensus_hook.rs +++ b/cumulus/pallets/aura-ext/src/consensus_hook.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index d22202bdbaa..34a41557152 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index 5eb8a5ce65b..49999dc114d 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 924b24d7104..24493ce9d9c 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index 3b298353386..58b4cc5b06a 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index d8c6d783f3f..44d531c971e 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/collator-selection/src/tests.rs b/cumulus/pallets/collator-selection/src/tests.rs index cbfbde743f0..d4dae513df3 100644 --- a/cumulus/pallets/collator-selection/src/tests.rs +++ b/cumulus/pallets/collator-selection/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/collator-selection/src/weights.rs b/cumulus/pallets/collator-selection/src/weights.rs index a4a30d83361..f8f86fb7dec 100644 --- a/cumulus/pallets/collator-selection/src/weights.rs +++ b/cumulus/pallets/collator-selection/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/dmp-queue/src/lib.rs b/cumulus/pallets/dmp-queue/src/lib.rs index aca9025d9e3..eff4a625ef1 100644 --- a/cumulus/pallets/dmp-queue/src/lib.rs +++ b/cumulus/pallets/dmp-queue/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/dmp-queue/src/migration.rs b/cumulus/pallets/dmp-queue/src/migration.rs index b2323f6a60f..63457ee4936 100644 --- a/cumulus/pallets/dmp-queue/src/migration.rs +++ b/cumulus/pallets/dmp-queue/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs index 70c6857120c..ece9348f43e 100644 --- a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs +++ b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/consensus_hook.rs b/cumulus/pallets/parachain-system/src/consensus_hook.rs index 2566eea9bbc..91353fc7bbd 100644 --- a/cumulus/pallets/parachain-system/src/consensus_hook.rs +++ b/cumulus/pallets/parachain-system/src/consensus_hook.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index ded869bf6f7..7fd44454811 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/migration.rs b/cumulus/pallets/parachain-system/src/migration.rs index 17dce3a11a9..a92f85b9cd4 100644 --- a/cumulus/pallets/parachain-system/src/migration.rs +++ b/cumulus/pallets/parachain-system/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs index b8556485041..5519d1521ea 100644 --- a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs +++ b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 41e8dc63808..5586feb8879 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/unincluded_segment.rs b/cumulus/pallets/parachain-system/src/unincluded_segment.rs index 2598228dd60..1e83a945c4e 100644 --- a/cumulus/pallets/parachain-system/src/unincluded_segment.rs +++ b/cumulus/pallets/parachain-system/src/unincluded_segment.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index 0eb83639018..8001b4cc8ac 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/validate_block/mod.rs b/cumulus/pallets/parachain-system/src/validate_block/mod.rs index 4e387bf8496..ab8ea43ec7c 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/mod.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/parachain-system/src/validate_block/tests.rs b/cumulus/pallets/parachain-system/src/validate_block/tests.rs index 7772f637256..0cf68f25cc3 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/tests.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/session-benchmarking/src/lib.rs b/cumulus/pallets/session-benchmarking/src/lib.rs index 5217bbae71b..f474def6b13 100644 --- a/cumulus/pallets/session-benchmarking/src/lib.rs +++ b/cumulus/pallets/session-benchmarking/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/solo-to-para/src/lib.rs b/cumulus/pallets/solo-to-para/src/lib.rs index 5672ec4ece4..da948615d4e 100644 --- a/cumulus/pallets/solo-to-para/src/lib.rs +++ b/cumulus/pallets/solo-to-para/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/xcm/src/lib.rs b/cumulus/pallets/xcm/src/lib.rs index f230ced5dc5..da806917ad3 100644 --- a/cumulus/pallets/xcm/src/lib.rs +++ b/cumulus/pallets/xcm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/xcmp-queue/src/benchmarking.rs b/cumulus/pallets/xcmp-queue/src/benchmarking.rs index f4167e522fa..17ec60a2f3f 100644 --- a/cumulus/pallets/xcmp-queue/src/benchmarking.rs +++ b/cumulus/pallets/xcmp-queue/src/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 960af9b5b77..1cb92f59518 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index bda54620cd9..a54ddfb9cec 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 55734087814..a3f10fa5428 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 45c4519d3aa..2929e8452be 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/pallets/xcmp-queue/src/weights.rs b/cumulus/pallets/xcmp-queue/src/weights.rs index cbb29ac3ae3..2d20bba6f8f 100644 --- a/cumulus/pallets/xcmp-queue/src/weights.rs +++ b/cumulus/pallets/xcmp-queue/src/weights.rs @@ -1,3 +1,18 @@ +// 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(unused_parens)] #![allow(unused_imports)] diff --git a/cumulus/parachain-template/runtime/src/weights/block_weights.rs b/cumulus/parachain-template/runtime/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachain-template/runtime/src/weights/block_weights.rs +++ b/cumulus/parachain-template/runtime/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs b/cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs +++ b/cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachain-template/runtime/src/weights/mod.rs b/cumulus/parachain-template/runtime/src/weights/mod.rs index ed0b4dbcd47..30fa2c40606 100644 --- a/cumulus/parachain-template/runtime/src/weights/mod.rs +++ b/cumulus/parachain-template/runtime/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs b/cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs +++ b/cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs b/cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs +++ b/cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 4a1f4f90d05..107cd5c6873 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index 0a9686bf8a3..797010d49a0 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 99dd0ace0fc..14667144145 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -1,3 +1,18 @@ +// 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::impls::AccountIdOf; use core::marker::PhantomData; use frame_support::{ diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs index 2609ba4ca8d..d16d8548ba4 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 99dd042ccaf..aca67e0eeb8 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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-kusama/src/tests/mod.rs index 73dd76ec9c6..41d84065819 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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-kusama/src/tests/reserve_transfer.rs index 9e11830acce..26b3cdf68b1 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-kusama/src/tests/reserve_transfer.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 819517ee840..8a6328d0d6a 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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-kusama/src/tests/set_xcm_versions.rs index 0ab53b45122..155ada2ec2f 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-kusama/src/tests/set_xcm_versions.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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-kusama/src/tests/swap.rs index eb545155a54..aad93db9922 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs @@ -1,3 +1,19 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + use crate::*; use asset_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; use frame_support::{instances::Instance2, BoundedVec}; 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-kusama/src/tests/teleport.rs index cf9f5a23272..868d02fefa6 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 9d87458f876..44004813f18 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 9335d69b4d7..7756a0cc202 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs index 00e0a663e47..547b59deadc 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 7d773a5865e..e6722d585bc 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index eb4c2ae6add..0b4a9836acd 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 84abf630e50..287bfa35ae9 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index 843ef6d3cce..166f73137e7 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b7f064e7d6e..f09fed97b8f 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 e45b78da1c2..e2a60e0b300 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 8d3c5358a37..67fc53a826a 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 87dfab93a5b..bdc3ff90e41 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 76e38083659..57632527174 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index 03ac7514608..1c4dd9d7683 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -1,3 +1,19 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + use crate::*; #[test] 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 17f204f3807..b45cfbe16c0 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 2a4927d857c..4689c076b51 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index 1293f65929a..127292829fd 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 532e31aa1a6..6e11743aecb 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index b71ee65a222..9fbee683fed 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 index a6d16a273b7..de84ac64d26 100644 --- 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs index 1ede78b5979..a9445ac8ec7 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 3eb65fa26c1..569436f06a0 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -1,3 +1,19 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 92c68f4dd61..92282eb8c0a 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -1,3 +1,19 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + use super::{BridgeHubRococo, BridgeHubWococo}; // pub use paste; use bp_messages::{ diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index f6d58970036..77345291690 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -1,3 +1,19 @@ +// 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 use lazy_static; pub mod constants; pub mod impls; diff --git a/cumulus/parachains/pallets/parachain-info/src/lib.rs b/cumulus/parachains/pallets/parachain-info/src/lib.rs index 6a9707365c3..c17a6d5e146 100644 --- a/cumulus/parachains/pallets/parachain-info/src/lib.rs +++ b/cumulus/parachains/pallets/parachain-info/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs index 7425b5bd52f..feda3d0b6f9 100644 --- a/cumulus/parachains/pallets/ping/src/lib.rs +++ b/cumulus/parachains/pallets/ping/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs index 0ca93a8446f..8daf8fda4b4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 2130c6502f8..afccc5c068b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs index df8188debdd..9c7a56687b3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs index 20e421541b0..96477ddf4bd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs index 955d4690634..281c013b337 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs @@ -1,3 +1,19 @@ +// 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; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs index bb09a851332..702f3743a72 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs index 3a801b758cf..7c237b20389 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs index d88f5991e32..10bd4b1f8b0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs index eeac89bb453..444699e33ef 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs index b387e626209..be1ac3011f7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs index a528b0f6685..7fe56ac31f7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs index f949a0786bf..ee7b7073641 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs index ab3bcbea826..c55a18adc52 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs index 453d2d477bf..2de706bbdc7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs index 6c548ac1f27..9bc4ba448e5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs index c5064adf8b0..56982f565ac 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs index 8edae065f1b..94914eefba0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs index 4da387aa872..43bc74931cb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs index 22d20c26e25..680e65a2dcf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs index ee76b111e83..c2ed67d2f5d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 8608d04af06..9aff4902d15 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 17e4ea7c8b6..6e663039b0c 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 4988047014b..625549ecfcc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 25d47b55977..7a28840adcb 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs index d3ddab9a854..d430e38f1af 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 4a81c7fb6e3..7275209802f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index e3c64776ae1..65844ce194a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs index a2007347211..713c33d34f7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs index 2cf514a5598..3eb3b925e65 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs @@ -1,3 +1,19 @@ +// 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; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs index 817d567c863..51413bb471b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs index 829b3543ee3..c8420e72ba2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs index 0da4d38eda2..a7f02ba24fd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs index 6d8828e836c..53efb218440 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs index d51eb85f6dc..705aca9e1a4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs index 1a04d8b0991..6d6f7cbbafb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs index df0124b471d..99db2865692 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs index 50c77fd3bc8..8a6943d5304 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs index 93f7e31120c..8c6a2b5505e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs index 3917b594c3f..a88928be653 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs index bda0c6e1aa9..c6fc093cc4b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs index 8d14734888b..bd7615895e2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 79f8e83a4f2..55fed809e2b 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 7fea608319f..4f64ea3fa1b 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index aa7451594f5..061992691a6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 3e40afb83f9..05110b65622 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs index fe789569a8a..b2629ef10fc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 48f2bfa45d8..b5f33e4e014 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs index 55ddfea38d1..cda66f6ea7e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs index 9ec9befa97c..c70ea9d58b2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 955d4690634..281c013b337 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -1,3 +1,19 @@ +// 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; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs index 1744fcbe397..2f39df65403 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs index 5deffe235cc..5be1319b10d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs index 15f4fdecbd2..aa09be829c8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs index 6101141e3ae..bfe73e1cfaf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs index db6dd8fef51..f6bf09d63ba 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs index 80da7446bcd..2473c58e458 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs index 230539e94df..107d78c98f9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs index 38387a1df06..e155e1bada3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs index 5c0a53e9333..687dfa07f75 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs index 076d79ff627..657bd2764cf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs index 8b8e5500d10..92602191744 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs index 40c5f353609..13f18861d37 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs index 813d472709d..53bead08f5d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs index ca0ead95b15..7db443ebbf1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 0256b49be3f..1cc4c2d0e24 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 763cb6c10f1..bb850ac72c0 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 ee435559f46..d6763d2fc66 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index a1d06914aa6..e776529eb7f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 e0af76d6d00..121f9753193 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs b/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs index 00f336f9c68..1ed7bd0538c 100644 --- a/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs +++ b/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs b/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs index 5aa5a69caa9..80f8a971d21 100644 --- a/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs +++ b/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 25ab296ff1c..560a89b131c 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 72fd9e7a916..4fae973d981 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 964f25cda35..08d39117001 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs b/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs index 7eee95bb3b6..0a166a04819 100644 --- a/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs +++ b/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 9a24867592e..7177726e070 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 f11d590f4af..7a8d571403c 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs index f0908fcd439..760bf7fb6d1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 af00e06c781..044ff845fe6 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs index 83b242f0459..991cba573bf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs index 83b8ec960fb..5a0a60cc995 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs index d5722374def..e226021e77a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs index 1387ee30c7d..51ca2e660b3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs index 7854bf88e40..fa0ac199ca2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs index 14b11f9380a..96b2d859ed8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs index 69371604e79..cc1b4aeb0dd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs index 31830fbc722..32f6e4a6b43 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs index f871f81b756..15b06676cd3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs index e2effcd36df..71bc5830771 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 295e222f27a..0e740922f33 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 4ebc6eacb9f..6c8c7ab66bb 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index d38d177a605..b1e8107b30b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 1fcec7b6b9c..4e295be542e 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs index c9215b6157c..5418e36bd12 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs index a42c3e4f85d..3bab7bd1eb3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 0a6bddb2257..f735858a934 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs index 2bd7975bf98..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 740c3e9dd0a..98834cc44e8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs index 898d72ec5b1..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs index 62883b2d907..4aeb4660d87 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs index 457d00f36bd..e226021e77a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs index d58126b3fd6..5abe64bb411 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs index 0b153be2719..e0f4156fe4d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs index 9984823b1c1..4625c4f474e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs index 3b74d0afd18..29bc576ebc8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs index fdb3c2ac959..8252834cc11 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs index a7b31d3d385..5205e9fff85 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs index c9e13f2bdb2..ffc5fa2fc23 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs index 1c6d2ebe568..25679703831 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs index aa0cb2b4bc3..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 4d7b626cb72..4f8c2dec7a8 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b02cfcbf75f..7c525dca051 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 87bd0a6173b..7968649d143 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 0b5831f028b..d4b97ce2d29 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs index f9fbf35e9f1..03b23cdd7ac 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 d45238b0f42..bc8f97ad97c 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b676e2c5994..5178b75c303 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs index 860b4ad2ba9..80620feaedc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 a00dd30a870..db53867f094 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 23bdc6fa4d7..0106d6398f4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs index 7146e59f1d0..3dec4cc7f18 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 81ecd10512f..54c7c03fb60 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs index 9f16d8b8141..26a188a9861 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index 2465d52cbe6..5fbe2da8eaa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs index 746db2a421c..f646ddc3a38 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_wococo_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_wococo_grandpa.rs index 377569f1aeb..5c7c8246247 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_wococo_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_wococo_grandpa.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs index f5ab0edddde..ec40615dc13 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs index 3fe496036f1..7c25ae337ad 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance.rs index 112eb227148..c3dbc19518b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index d77c43e729f..c9f1d7e05d3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs index 3ba8fabf779..147e8447ee8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs index da5ec6c1418..432f9f9969d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index 426b098d54e..a934a1be582 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs index 956b7b7b43c..9cbfa6ce80e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs index f3a2e7f0268..91840ae0c6d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs index afa64ae7537..c9d04f9c6df 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs index 61742f36995..0a5bf9b9f9c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs index 4941bd66154..44cd0cf91e7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index f6d61f9e6c2..72bdb282585 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 a5c6bf858f6..40a2036fb49 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 25ec8777cd3..8f9fbc91245 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 @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 3cb066bc53d..da3404909f3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 170382fe583..ddba163df59 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 1d8439d23e0..77e7e0382d3 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index 289d3f5b4d3..26eb09b73fa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 bd0f070f9dc..aa7fa16a979 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 @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs index ac516447c74..46b562ea4de 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs index 6f5b8aff8d4..9350d03a2c9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 489b868eff3..9b867533129 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs index 04663aeecf3..5ed2c19f79e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs index fc53efdd7e8..f4ba4e05ec1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs index c28b4e2dc1e..4addc8cd565 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index a9af3b0f29f..5033a2d8beb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 28e1cd902b5..ccd9478bf10 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs index 75cc6580a39..31cd502d192 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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 b0e49549914..9ddf53792ea 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs @@ -1,3 +1,19 @@ +// 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; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs index c822a0c85cd..9e3acac46a4 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs index 80b90aadc0d..dd0c02ab873 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs index 8376006e30c..ea237d602a9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs index 013cfee7ba9..2d344ad0db7 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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.rs index 50a8bcea500..d053513b53a 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.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs index b2e36af383b..a8dd58320cc 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs index ef2406230b2..cf2f0ae39da 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs index 9732251e5aa..faf100d23bb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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.rs index 0ce5de87c8f..561edda953b 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.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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.rs index 1e8b3ecae2e..12d92a803ca 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify 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.rs index 351834c5e3a..3a6825cf641 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs index b647f7eba87..d30ac82bf05 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs index 909f9a64f5a..2af8ce29a19 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs index bb8f0e0b376..bc149ec63a1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs index f16ffc4c0c3..5d6b0cb8285 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs index 030d754ec4c..738742b6108 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 e9b5c1b165a..98a3710e42a 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs index db7922ea905..9b0fe5182a2 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index 1c2b24d88a8..6598fd3fae0 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -1,3 +1,18 @@ +// 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::{ constants::currency::deposit, Balance, Balances, RandomnessCollectiveFlip, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, Timestamp, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 9f381d4417a..b5815ab057e 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs index ed0b4dbcd47..30fa2c40606 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 3857c07fd03..8040ff74935 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs index 9b53d2457df..1580e6f07be 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs @@ -1,3 +1,18 @@ +// 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 substrate_wasm_builder::WasmBuilder; fn main() { diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index cd9d31a4d98..dde8f747d46 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs index 1aff76714bb..36c4abc4006 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs index 234ce34bf42..990558538ac 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs @@ -1 +1,17 @@ +// 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 pallet_glutton; diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs index f43a4878265..f278d246b33 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs index a09880f8cdc..fb7b78b79d2 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index edca2b09394..5f6733faf70 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/starters/shell/build.rs b/cumulus/parachains/runtimes/starters/shell/build.rs index 256e9fb765b..9c9cde9a25a 100644 --- a/cumulus/parachains/runtimes/starters/shell/build.rs +++ b/cumulus/parachains/runtimes/starters/shell/build.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 205462fac39..ef914a246ef 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs index b1fcfc5c8f6..ff773ca7816 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/build.rs b/cumulus/parachains/runtimes/testing/penpal/build.rs index 256e9fb765b..9c9cde9a25a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/build.rs +++ b/cumulus/parachains/runtimes/testing/penpal/build.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 4bc7dfacc05..9a758cdd978 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs index b2092d875c8..e7fdb2aae2a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs index 332c3b324bb..1a4adb968bb 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs index ed0b4dbcd47..30fa2c40606 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs index 4338d928d80..25679703831 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs index 1d115d963fa..3dd817aa6f1 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 1825bea425d..694f9c1ade3 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index d01c66e772d..084372589d9 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/build.rs b/cumulus/polkadot-parachain/build.rs index ae164d6cb0f..dd0d112bca7 100644 --- a/cumulus/polkadot-parachain/build.rs +++ b/cumulus/polkadot-parachain/build.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 0523c3b7e65..c1fb60374ae 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 911368073d5..b151b2fd615 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 82c925c5d49..6126fbb114f 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs index b8af83a0d70..bf318e448f0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 5ea51c3a918..acd5b5bfbe1 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index d7014a9f43c..9cd0a37ad63 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index 264898991eb..479d1701e37 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index 1ed1a3e35fb..fb66efbf9ae 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs index 4a43b4cf476..3ebfb80d468 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/chain_spec/shell.rs b/cumulus/polkadot-parachain/src/chain_spec/shell.rs index eca605b10df..7eb65591b12 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/shell.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/shell.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/cli.rs b/cumulus/polkadot-parachain/src/cli.rs index 11b2e105ecb..63e4baf27ae 100644 --- a/cumulus/polkadot-parachain/src/cli.rs +++ b/cumulus/polkadot-parachain/src/cli.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 008e5435f0b..1814d820058 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index d114d2f5f2c..e40af8128f7 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/rpc.rs b/cumulus/polkadot-parachain/src/rpc.rs index df6283388f9..d106c52a364 100644 --- a/cumulus/polkadot-parachain/src/rpc.rs +++ b/cumulus/polkadot-parachain/src/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 3899814cb0e..f7b053b4b6a 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs b/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs index df3078b4dab..c2850b64e45 100644 --- a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs +++ b/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs @@ -1,3 +1,19 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + #![cfg(feature = "runtime-benchmarks")] use assert_cmd::cargo::cargo_bin; diff --git a/cumulus/polkadot-parachain/tests/common.rs b/cumulus/polkadot-parachain/tests/common.rs index d8ecfe9bcbe..20926ddd91d 100644 --- a/cumulus/polkadot-parachain/tests/common.rs +++ b/cumulus/polkadot-parachain/tests/common.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . +// along with Cumulus. If not, see . #![cfg(unix)] diff --git a/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs b/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs index 0538a47aa93..9337da85d74 100644 --- a/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs +++ b/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . +// along with Cumulus. If not, see . use tempfile::tempdir; diff --git a/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs b/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs index c88c81230b0..e3ccb7fe0fb 100644 --- a/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs +++ b/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . +// along with Cumulus. If not, see . use tempfile::tempdir; diff --git a/cumulus/polkadot-parachain/tests/purge_chain_works.rs b/cumulus/polkadot-parachain/tests/purge_chain_works.rs index 8a41ee780c5..6415a914c7a 100644 --- a/cumulus/polkadot-parachain/tests/purge_chain_works.rs +++ b/cumulus/polkadot-parachain/tests/purge_chain_works.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . +// along with Cumulus. If not, see . use assert_cmd::cargo::cargo_bin; use nix::sys::signal::SIGINT; diff --git a/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs b/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs index 254602a2184..0f4ae699238 100644 --- a/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs +++ b/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . +// along with Cumulus. If not, see . use tempfile::tempdir; diff --git a/cumulus/primitives/aura/src/lib.rs b/cumulus/primitives/aura/src/lib.rs index a0d7a0206a6..826b65fddd2 100644 --- a/cumulus/primitives/aura/src/lib.rs +++ b/cumulus/primitives/aura/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index 19cc69ea301..d697713f39a 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/parachain-inherent/src/client_side.rs b/cumulus/primitives/parachain-inherent/src/client_side.rs index 1d936239104..52987d2da44 100644 --- a/cumulus/primitives/parachain-inherent/src/client_side.rs +++ b/cumulus/primitives/parachain-inherent/src/client_side.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/parachain-inherent/src/lib.rs b/cumulus/primitives/parachain-inherent/src/lib.rs index 34b9064090c..08407023bb4 100644 --- a/cumulus/primitives/parachain-inherent/src/lib.rs +++ b/cumulus/primitives/parachain-inherent/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/parachain-inherent/src/mock.rs b/cumulus/primitives/parachain-inherent/src/mock.rs index 18e23ba23af..5168b46a14d 100644 --- a/cumulus/primitives/parachain-inherent/src/mock.rs +++ b/cumulus/primitives/parachain-inherent/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/timestamp/src/lib.rs b/cumulus/primitives/timestamp/src/lib.rs index c8030fb09c4..535c4a2a726 100644 --- a/cumulus/primitives/timestamp/src/lib.rs +++ b/cumulus/primitives/timestamp/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 87be029163d..e908e9e22c0 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/test/client/src/block_builder.rs b/cumulus/test/client/src/block_builder.rs index 06c7416be67..2d930d1be59 100644 --- a/cumulus/test/client/src/block_builder.rs +++ b/cumulus/test/client/src/block_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index 9660a99c359..f59aa09e666 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/relay-sproof-builder/src/lib.rs b/cumulus/test/relay-sproof-builder/src/lib.rs index a17e5df13d0..69a82d05d81 100644 --- a/cumulus/test/relay-sproof-builder/src/lib.rs +++ b/cumulus/test/relay-sproof-builder/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/relay-validation-worker-provider/build.rs b/cumulus/test/relay-validation-worker-provider/build.rs index a0a476b0195..60bb950db1f 100644 --- a/cumulus/test/relay-validation-worker-provider/build.rs +++ b/cumulus/test/relay-validation-worker-provider/build.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/relay-validation-worker-provider/src/lib.rs b/cumulus/test/relay-validation-worker-provider/src/lib.rs index 840214eb3c0..6c3f4182b03 100644 --- a/cumulus/test/relay-validation-worker-provider/src/lib.rs +++ b/cumulus/test/relay-validation-worker-provider/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs index 77631afefe6..5e5f6a35a50 100644 --- a/cumulus/test/runtime/build.rs +++ b/cumulus/test/runtime/build.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Substrate is free software: you can redistribute it and/or modify diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 4c213ad4054..ccf624c0ffa 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index bc72ef19505..0af23797dad 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/service/benches/transaction_throughput.rs b/cumulus/test/service/benches/transaction_throughput.rs index 48bf49487e6..83981a91d46 100644 --- a/cumulus/test/service/benches/transaction_throughput.rs +++ b/cumulus/test/service/benches/transaction_throughput.rs @@ -1,6 +1,6 @@ // This file is part of Cumulus. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// 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 diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 3d72d0db3ab..7c8c984c2b2 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 4c86094f81d..f295192c3b1 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/service/src/genesis.rs b/cumulus/test/service/src/genesis.rs index fb1825cfbdd..9dba57ba9fb 100644 --- a/cumulus/test/service/src/genesis.rs +++ b/cumulus/test/service/src/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 7dcab7c5076..3275aabc4d8 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index a2b177db251..5946e9cc350 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 72f88ee7fa9..40cbaf4dea6 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 7c2773c8e3b..6c155390566 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/prospective-parachains/src/error.rs b/polkadot/node/core/prospective-parachains/src/error.rs index 0ad98d1ff90..2b0933ab1c7 100644 --- a/polkadot/node/core/prospective-parachains/src/error.rs +++ b/polkadot/node/core/prospective-parachains/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs index ec06f2d6070..ed2988fcb39 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index a7f37d873d6..6e5844a62a1 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/prospective-parachains/src/metrics.rs b/polkadot/node/core/prospective-parachains/src/metrics.rs index d7a1760bb45..57061497a1c 100644 --- a/polkadot/node/core/prospective-parachains/src/metrics.rs +++ b/polkadot/node/core/prospective-parachains/src/metrics.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index de7a84d9a60..9fc77624b97 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 28dd9e0a959..627c38b776f 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 02e8d0a7a81..bd55c35852f 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 ba59cce56b6..4c92780f2da 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/collator-protocol/src/validator_side/metrics.rs b/polkadot/node/network/collator-protocol/src/validator_side/metrics.rs index d898a5e7cef..195a135947d 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/metrics.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/metrics.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 a803827792d..e2a007b308e 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 @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/protocol/src/request_response/vstaging.rs b/polkadot/node/network/protocol/src/request_response/vstaging.rs index f84de950553..34a17b4baaa 100644 --- a/polkadot/node/network/protocol/src/request_response/vstaging.rs +++ b/polkadot/node/network/protocol/src/request_response/vstaging.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 b5895cb9f65..9ae76047383 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs b/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs index 42d24361450..d6b68510f1c 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs b/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs index 3214507407a..55d847f8315 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs b/polkadot/node/network/statement-distribution/src/vstaging/grid.rs index c6c73f8bae5..ec470a2eeb4 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/grid.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs b/polkadot/node/network/statement-distribution/src/vstaging/groups.rs index 86321b30f22..f93a8e13fc1 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/groups.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs b/polkadot/node/network/statement-distribution/src/vstaging/mod.rs index 03af4ce8159..830a488308a 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/requests.rs b/polkadot/node/network/statement-distribution/src/vstaging/requests.rs index 2593d81ba0b..79925f2115d 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/requests.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/requests.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs b/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs index 50ac99d0a81..9ea926f24aa 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs index 1ff53d3fd99..50d0477eb51 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs index 0c9fa60ed2e..0739f301943 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs index f5f4c844325..88c8a42599d 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs index a86ef97f780..5eef5809b4d 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index adf7fbd5425..83c15fdef95 100644 --- a/polkadot/node/subsystem-util/src/backing_implicit_view.rs +++ b/polkadot/node/subsystem-util/src/backing_implicit_view.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index 6ab19fa660b..1487077d9ed 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs index a4b85775981..eb063229752 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/primitives/src/v5/slashing.rs b/polkadot/primitives/src/v5/slashing.rs index 34424a00d23..efffb932cdc 100644 --- a/polkadot/primitives/src/v5/slashing.rs +++ b/polkadot/primitives/src/v5/slashing.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs index 0471c0c3b2b..169e858deda 100644 --- a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs +++ b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index 22aee31043a..e96b5e96892 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index ae0f9ee3403..39e09e05677 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index 808cf5521d3..e8bb68f0787 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/substrate/bin/node/runtime/src/assets_api.rs b/substrate/bin/node/runtime/src/assets_api.rs index cf1a663d703..792ed7c6576 100644 --- a/substrate/bin/node/runtime/src/assets_api.rs +++ b/substrate/bin/node/runtime/src/assets_api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// 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 diff --git a/substrate/client/authority-discovery/build.rs b/substrate/client/authority-discovery/build.rs index 00d45f07ae1..83076ac8c89 100644 --- a/substrate/client/authority-discovery/build.rs +++ b/substrate/client/authority-discovery/build.rs @@ -1,3 +1,21 @@ +// 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 . + fn main() { prost_build::compile_protos( &["src/worker/schema/dht-v1.proto", "src/worker/schema/dht-v2.proto"], diff --git a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index b8d8cd35434..71c5c49b369 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index 9acf1f21877..ea8114eafd7 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/executor/runtime-test/src/lib.rs b/substrate/client/executor/runtime-test/src/lib.rs index 2bd2aeeb606..ec9b2378d4d 100644 --- a/substrate/client/executor/runtime-test/src/lib.rs +++ b/substrate/client/executor/runtime-test/src/lib.rs @@ -1,3 +1,21 @@ +// 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 . + #![cfg_attr(not(feature = "std"), no_std)] // Make the WASM binary available. diff --git a/substrate/client/network/bitswap/build.rs b/substrate/client/network/bitswap/build.rs index 671277230a7..2495a9c2565 100644 --- a/substrate/client/network/bitswap/build.rs +++ b/substrate/client/network/bitswap/build.rs @@ -1,3 +1,21 @@ +// 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 . + const PROTOS: &[&str] = &["src/schema/bitswap.v1.2.0.proto"]; fn main() { diff --git a/substrate/client/network/bitswap/src/lib.rs b/substrate/client/network/bitswap/src/lib.rs index beaaa8fd0fd..7bb8b003065 100644 --- a/substrate/client/network/bitswap/src/lib.rs +++ b/substrate/client/network/bitswap/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/network/common/src/sync/warp.rs b/substrate/client/network/common/src/sync/warp.rs index 37a6e62c53b..91d6c4151a4 100644 --- a/substrate/client/network/common/src/sync/warp.rs +++ b/substrate/client/network/common/src/sync/warp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/network/light/build.rs b/substrate/client/network/light/build.rs index 9c44bcd2931..199738abc91 100644 --- a/substrate/client/network/light/build.rs +++ b/substrate/client/network/light/build.rs @@ -1,3 +1,21 @@ +// 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 . + const PROTOS: &[&str] = &["src/schema/light.v1.proto"]; fn main() { diff --git a/substrate/client/network/sync/build.rs b/substrate/client/network/sync/build.rs index 55794919cdb..b780136737e 100644 --- a/substrate/client/network/sync/build.rs +++ b/substrate/client/network/sync/build.rs @@ -1,3 +1,21 @@ +// 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 . + const PROTOS: &[&str] = &["src/schema/api.v1.proto"]; fn main() { diff --git a/substrate/client/network/sync/src/block_request_handler.rs b/substrate/client/network/sync/src/block_request_handler.rs index 291157eae4b..d90a00b3767 100644 --- a/substrate/client/network/sync/src/block_request_handler.rs +++ b/substrate/client/network/sync/src/block_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index d5c4957ab3d..65bd56a2895 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// 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 diff --git a/substrate/client/network/sync/src/state_request_handler.rs b/substrate/client/network/sync/src/state_request_handler.rs index ed14b889cbb..f78fadccc2d 100644 --- a/substrate/client/network/sync/src/state_request_handler.rs +++ b/substrate/client/network/sync/src/state_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/network/sync/src/warp_request_handler.rs b/substrate/client/network/sync/src/warp_request_handler.rs index a49a65af51d..0e502a6dba5 100644 --- a/substrate/client/network/sync/src/warp_request_handler.rs +++ b/substrate/client/network/sync/src/warp_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify 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 00ed9089058..1336cff84b6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1,3 +1,21 @@ +// 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::{ event::{MethodResponse, StorageQuery, StorageQueryType, StorageResultType}, test_utils::ChainHeadMockClient, diff --git a/substrate/client/tracing/src/block/mod.rs b/substrate/client/tracing/src/block/mod.rs index c0442abc125..9ebf8e55c94 100644 --- a/substrate/client/tracing/src/block/mod.rs +++ b/substrate/client/tracing/src/block/mod.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/client/tracing/src/logging/directives.rs b/substrate/client/tracing/src/logging/directives.rs index f1caf1a13a2..a99e9c4c890 100644 --- a/substrate/client/tracing/src/logging/directives.rs +++ b/substrate/client/tracing/src/logging/directives.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index d1d68f3e10f..8d811473e86 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 7fe81b81404..3a19f39e7ca 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 450a074ec36..190e4fb6214 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 9c28bd7666b..ffdc63ce0ce 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index 858417e8007..e20e1df564c 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg(test)] use super::*; diff --git a/substrate/frame/bags-list/remote-tests/src/migration.rs b/substrate/frame/bags-list/remote-tests/src/migration.rs index 7847fdc7591..dc133745afe 100644 --- a/substrate/frame/bags-list/remote-tests/src/migration.rs +++ b/substrate/frame/bags-list/remote-tests/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/substrate/frame/bags-list/remote-tests/src/snapshot.rs b/substrate/frame/bags-list/remote-tests/src/snapshot.rs index 78c5b4e1c7b..13922cd3ca6 100644 --- a/substrate/frame/bags-list/remote-tests/src/snapshot.rs +++ b/substrate/frame/bags-list/remote-tests/src/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify 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 5bbac00bc75..338be50a93f 100644 --- a/substrate/frame/bags-list/remote-tests/src/try_state.rs +++ b/substrate/frame/bags-list/remote-tests/src/try_state.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 2cbe776c512..c64a4929dd5 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/impl_fungible.rs b/substrate/frame/balances/src/impl_fungible.rs index 03c40bb3a84..fc8c2d71f25 100644 --- a/substrate/frame/balances/src/impl_fungible.rs +++ b/substrate/frame/balances/src/impl_fungible.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/migration.rs b/substrate/frame/balances/src/migration.rs index 6a272a611c3..ba6819ec6e8 100644 --- a/substrate/frame/balances/src/migration.rs +++ b/substrate/frame/balances/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index c9ad19f79e3..969731b49a2 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/tests/dispatchable_tests.rs b/substrate/frame/balances/src/tests/dispatchable_tests.rs index 76d0961e577..8f625a18944 100644 --- a/substrate/frame/balances/src/tests/dispatchable_tests.rs +++ b/substrate/frame/balances/src/tests/dispatchable_tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/tests/fungible_tests.rs b/substrate/frame/balances/src/tests/fungible_tests.rs index ab2606c53ff..8bf0509d8f7 100644 --- a/substrate/frame/balances/src/tests/fungible_tests.rs +++ b/substrate/frame/balances/src/tests/fungible_tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index cefc6e9e8f5..d15f8e89118 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/tests/reentrancy_tests.rs b/substrate/frame/balances/src/tests/reentrancy_tests.rs index e97bf2ed2b7..1afbe82c7e2 100644 --- a/substrate/frame/balances/src/tests/reentrancy_tests.rs +++ b/substrate/frame/balances/src/tests/reentrancy_tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/balances/src/types.rs b/substrate/frame/balances/src/types.rs index cd100d0df6c..af775b8eefe 100644 --- a/substrate/frame/balances/src/types.rs +++ b/substrate/frame/balances/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/benchmarking/pov/src/weights.rs b/substrate/frame/benchmarking/pov/src/weights.rs index f16ac7fbc27..d84ac88c98f 100644 --- a/substrate/frame/benchmarking/pov/src/weights.rs +++ b/substrate/frame/benchmarking/pov/src/weights.rs @@ -1,3 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Autogenerated weights for frame_benchmarking_pallet_pov //! diff --git a/substrate/frame/contracts/src/debug.rs b/substrate/frame/contracts/src/debug.rs index a92f428c8f8..d92379a806d 100644 --- a/substrate/frame/contracts/src/debug.rs +++ b/substrate/frame/contracts/src/debug.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub use crate::exec::ExportedFunction; use crate::{CodeHash, Config, LOG_TARGET}; use pallet_contracts_primitives::ExecReturnValue; diff --git a/substrate/frame/contracts/src/tests/pallet_dummy.rs b/substrate/frame/contracts/src/tests/pallet_dummy.rs index 7f8db53bf46..2af8475d17e 100644 --- a/substrate/frame/contracts/src/tests/pallet_dummy.rs +++ b/substrate/frame/contracts/src/tests/pallet_dummy.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub use pallet::*; #[frame_support::pallet(dev_mode)] diff --git a/substrate/frame/contracts/src/tests/test_debug.rs b/substrate/frame/contracts/src/tests/test_debug.rs index ba936a4588d..c7862c7f03d 100644 --- a/substrate/frame/contracts/src/tests/test_debug.rs +++ b/substrate/frame/contracts/src/tests/test_debug.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::*; use crate::debug::{CallSpan, ExportedFunction, Tracing}; use frame_support::traits::Currency; diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs index ace614d2bdd..1aa53cf08d1 100644 --- a/substrate/frame/core-fellowship/src/lib.rs +++ b/substrate/frame/core-fellowship/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/core-fellowship/src/tests.rs b/substrate/frame/core-fellowship/src/tests.rs index c95699e66e4..a02c010718c 100644 --- a/substrate/frame/core-fellowship/src/tests.rs +++ b/substrate/frame/core-fellowship/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 9c3511ae357..024dc6ae7d6 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 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/src/compact.rs b/substrate/frame/election-provider-support/solution-type/fuzzer/src/compact.rs index e7ef440ff21..90fd9509e6f 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/src/compact.rs +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/src/compact.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; use honggfuzz::fuzz; use sp_arithmetic::Percent; diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs index 52ae9623fd3..c72ad9853e2 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr index b6bb8f39ede..4ff7d479a98 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr @@ -1,5 +1,5 @@ error: Expected binding: `Accuracy = ...` - --> $DIR/missing_accuracy.rs:6:2 - | -6 | Perbill, - | ^^^^^^^ + --> tests/ui/fail/missing_accuracy.rs:23:2 + | +23 | Perbill, + | ^^^^^^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs index fe8ac04cc8d..c1dd5964972 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr index c685ab816d3..52fb081b3f4 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr @@ -1,5 +1,5 @@ error: Expected binding: `MaxVoters = ...` - --> tests/ui/fail/missing_size_bound.rs:7:2 - | -7 | ConstU32::<10>, - | ^^^^^^^^^^^^^^ + --> tests/ui/fail/missing_size_bound.rs:24:2 + | +24 | ConstU32::<10>, + | ^^^^^^^^^^^^^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs index b457c4abada..1747693b4e5 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr index d0c92c5bbd8..783af709fe2 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr @@ -1,5 +1,5 @@ error: Expected binding: `TargetIndex = ...` - --> $DIR/missing_target.rs:5:2 - | -5 | u8, - | ^^ + --> tests/ui/fail/missing_target.rs:22:2 + | +22 | u8, + | ^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs index 3d12e3e6b5e..10e7d7577a2 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr index a825d460c2f..c8a5b92b762 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr @@ -1,5 +1,5 @@ error: Expected binding: `VoterIndex = ...` - --> $DIR/missing_voter.rs:4:2 - | -4 | u16, - | ^^^ + --> tests/ui/fail/missing_voter.rs:21:2 + | +21 | u16, + | ^^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs index 9aab15e7ec9..6e0a0df14ce 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr index 28f1c209154..af548a524b2 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr @@ -1,5 +1,5 @@ error: Expected binding: `VoterIndex = ...` - --> $DIR/no_annotations.rs:4:2 - | -4 | u16, - | ^^^ + --> tests/ui/fail/no_annotations.rs:21:2 + | +21 | u16, + | ^^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs index 4275aae045a..2ae1aa2b9de 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr index 5759fee7472..0a4bc7515f4 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr @@ -1,5 +1,5 @@ error: Expected `VoterIndex` - --> $DIR/swap_voter_target.rs:4:2 - | -4 | TargetIndex = u16, - | ^^^^^^^^^^^ + --> tests/ui/fail/swap_voter_target.rs:21:2 + | +21 | TargetIndex = u16, + | ^^^^^^^^^^^ diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs index a51cc724ad1..4fcd8a815c9 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!( diff --git a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr index ab700a3f2af..a18b294516b 100644 --- a/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr +++ b/substrate/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr @@ -1,5 +1,5 @@ error: compact solution can accept only #[compact] - --> $DIR/wrong_attribute.rs:4:2 - | -4 | #[pages(1)] pub struct TestSolution::< - | ^^^^^^^^^^^ + --> tests/ui/fail/wrong_attribute.rs:21:2 + | +21 | #[pages(1)] pub struct TestSolution::< + | ^^^^^^^^^^^ diff --git a/substrate/frame/elections-phragmen/src/migrations/v5.rs b/substrate/frame/elections-phragmen/src/migrations/v5.rs index eb35c1fae0f..6fac923703f 100644 --- a/substrate/frame/elections-phragmen/src/migrations/v5.rs +++ b/substrate/frame/elections-phragmen/src/migrations/v5.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::super::*; /// Migrate the locks and vote stake on accounts (as specified with param `to_migrate`) that have diff --git a/substrate/frame/examples/kitchensink/src/weights.rs b/substrate/frame/examples/kitchensink/src/weights.rs index 1d083a9b80e..43f48332ae9 100644 --- a/substrate/frame/examples/kitchensink/src/weights.rs +++ b/substrate/frame/examples/kitchensink/src/weights.rs @@ -1,3 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Autogenerated weights for `pallet_example_kitchensink` //! diff --git a/substrate/frame/examples/split/src/weights.rs b/substrate/frame/examples/split/src/weights.rs index 4219ce1e269..58b9e2af43a 100644 --- a/substrate/frame/examples/split/src/weights.rs +++ b/substrate/frame/examples/split/src/weights.rs @@ -1,3 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Autogenerated weights for pallet_template //! diff --git a/substrate/frame/glutton/src/benchmarking.rs b/substrate/frame/glutton/src/benchmarking.rs index 58720758745..fa93c7ccc82 100644 --- a/substrate/frame/glutton/src/benchmarking.rs +++ b/substrate/frame/glutton/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/glutton/src/lib.rs b/substrate/frame/glutton/src/lib.rs index c76cc30017c..3d2af95e934 100644 --- a/substrate/frame/glutton/src/lib.rs +++ b/substrate/frame/glutton/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/glutton/src/mock.rs b/substrate/frame/glutton/src/mock.rs index c79ddd53718..4bc40b54788 100644 --- a/substrate/frame/glutton/src/mock.rs +++ b/substrate/frame/glutton/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/glutton/src/tests.rs b/substrate/frame/glutton/src/tests.rs index 1897ff63a70..c67543cf55a 100644 --- a/substrate/frame/glutton/src/tests.rs +++ b/substrate/frame/glutton/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nft-fractionalization/src/lib.rs b/substrate/frame/nft-fractionalization/src/lib.rs index b1663e95d85..e97d3802fd2 100644 --- a/substrate/frame/nft-fractionalization/src/lib.rs +++ b/substrate/frame/nft-fractionalization/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index 6565adaf6fc..c690f0e580e 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nft-fractionalization/src/tests.rs b/substrate/frame/nft-fractionalization/src/tests.rs index b82402bda1e..036cc668db2 100644 --- a/substrate/frame/nft-fractionalization/src/tests.rs +++ b/substrate/frame/nft-fractionalization/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nft-fractionalization/src/types.rs b/substrate/frame/nft-fractionalization/src/types.rs index cbaaf5f5160..8df65b15112 100644 --- a/substrate/frame/nft-fractionalization/src/types.rs +++ b/substrate/frame/nft-fractionalization/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nfts/runtime-api/src/lib.rs b/substrate/frame/nfts/runtime-api/src/lib.rs index 0c23d178107..867138b5bdd 100644 --- a/substrate/frame/nfts/runtime-api/src/lib.rs +++ b/substrate/frame/nfts/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 7d0d729a40d..28c24c42803 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::*; use crate::{self as pools}; use frame_support::{assert_ok, parameter_types, PalletId}; diff --git a/substrate/frame/salary/src/lib.rs b/substrate/frame/salary/src/lib.rs index 75d6fdd329a..f2903f527f2 100644 --- a/substrate/frame/salary/src/lib.rs +++ b/substrate/frame/salary/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/salary/src/tests.rs b/substrate/frame/salary/src/tests.rs index 034dce24b8b..1136ea746f6 100644 --- a/substrate/frame/salary/src/tests.rs +++ b/substrate/frame/salary/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/society/src/weights.rs b/substrate/frame/society/src/weights.rs index d113f617c88..7c59aed8449 100644 --- a/substrate/frame/society/src/weights.rs +++ b/substrate/frame/society/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/staking/reward-curve/src/log.rs b/substrate/frame/staking/reward-curve/src/log.rs index 248a1e3c36a..70191180da3 100644 --- a/substrate/frame/staking/reward-curve/src/log.rs +++ b/substrate/frame/staking/reward-curve/src/log.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// Simple u32 power of 2 function - simply uses a bit shift macro_rules! pow2 { ($n:expr) => { diff --git a/substrate/frame/staking/runtime-api/src/lib.rs b/substrate/frame/staking/runtime-api/src/lib.rs index 378599c6655..c669d222ec6 100644 --- a/substrate/frame/staking/runtime-api/src/lib.rs +++ b/substrate/frame/staking/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/procedural/src/dummy_part_checker.rs b/substrate/frame/support/procedural/src/dummy_part_checker.rs index 792b17a8f77..34d9a3e236b 100644 --- a/substrate/frame/support/procedural/src/dummy_part_checker.rs +++ b/substrate/frame/support/procedural/src/dummy_part_checker.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use crate::COUNTER; use proc_macro::TokenStream; diff --git a/substrate/frame/support/procedural/src/pallet/expand/doc_only.rs b/substrate/frame/support/procedural/src/pallet/expand/doc_only.rs index 50afeb3ca88..621a051acae 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/doc_only.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/doc_only.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 7dbcb74f000..54f8e57cf24 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs index 88ba56a6fed..56166436003 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs @@ -1 +1,18 @@ +// 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 inspect_mutate; diff --git a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs index 1ec3a5fadf5..bc8f22b959c 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungible/hold.rs b/substrate/frame/support/src/traits/tokens/fungible/hold.rs index aa15e9df63a..15c046fbe9a 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/hold.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 cf2d96ef287..88b9de7fdbf 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index 8ab63ad366f..2205fd5dc58 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 2838bed540a..70d751b4977 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs index 08549c2d4b7..88f083b0a21 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs index c751a836d1f..4f86704df16 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 9e2c306f6f3..0e195a52318 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 697eff39ff7..4fd6ef43a15 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index b6cea15284d..93816576247 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.rs index 657e481a943..17a3aa4a9ee 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.stderr index 4e2d63a6b50..c7deb671121 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name.stderr @@ -1,5 +1,5 @@ error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. - --> tests/benchmark_ui/bad_param_name.rs:10:11 + --> tests/benchmark_ui/bad_param_name.rs:27:11 | -10 | fn bench(winton: Linear<1, 2>) { +27 | fn bench(winton: Linear<1, 2>) { | ^^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs index f970126d12e..9c3aff9ff05 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr index 32f6bf8e47d..bed3bc9c4b1 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr @@ -1,5 +1,5 @@ error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. - --> tests/benchmark_ui/bad_param_name_too_long.rs:8:11 - | -8 | fn bench(xx: Linear<1, 2>) { - | ^^ + --> tests/benchmark_ui/bad_param_name_too_long.rs:25:11 + | +25 | fn bench(xx: Linear<1, 2>) { + | ^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs index 9970f323016..dad9ee9fd12 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr index 48dd41d3262..43fd9d9804e 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr @@ -1,5 +1,5 @@ error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. - --> tests/benchmark_ui/bad_param_name_upper_case.rs:8:11 - | -8 | fn bench(D: Linear<1, 2>) { - | ^ + --> tests/benchmark_ui/bad_param_name_upper_case.rs:25:11 + | +25 | fn bench(D: Linear<1, 2>) { + | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_params.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_params.rs index 5049f2eae2c..e92e3d2f253 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_params.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_params.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_params.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_params.stderr index 068eaedd531..16aabbff153 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_params.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_params.stderr @@ -1,5 +1,5 @@ error: Invalid benchmark function param. A valid example would be `x: Linear<5, 10>`. - --> tests/benchmark_ui/bad_params.rs:10:31 + --> tests/benchmark_ui/bad_params.rs:27:31 | -10 | fn bench(y: Linear<1, 2>, x: u32) { +27 | fn bench(y: Linear<1, 2>, x: u32) { | ^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs index 5e332801df8..4e70aef50ee 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr index ab0bff54a8a..f80fe997a00 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr @@ -1,5 +1,5 @@ error: expected `BenchmarkError` - --> tests/benchmark_ui/bad_return_non_benchmark_err.rs:10:27 + --> tests/benchmark_ui/bad_return_non_benchmark_err.rs:27:27 | -10 | fn bench() -> Result<(), BenchmarkException> { +27 | fn bench() -> Result<(), BenchmarkException> { | ^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs index a4b0d007eee..f424fb1f926 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr index 69d61b42291..405fb473090 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr @@ -1,5 +1,5 @@ error: Only `Result<(), BenchmarkError>` or a blank return type is allowed on benchmark function definitions - --> tests/benchmark_ui/bad_return_non_type_path.rs:10:16 + --> tests/benchmark_ui/bad_return_non_type_path.rs:27:16 | -10 | fn bench() -> (String, u32) { +27 | fn bench() -> (String, u32) { | ^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs index 15289c298ae..e204e66c129 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr index 4181ea099a1..cae0a7a0584 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr @@ -1,5 +1,5 @@ error: expected `()` - --> tests/benchmark_ui/bad_return_non_unit_t.rs:8:23 - | -8 | fn bench() -> Result { - | ^^^ + --> tests/benchmark_ui/bad_return_non_unit_t.rs:25:23 + | +25 | fn bench() -> Result { + | ^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs index a6a2c61127f..dd3ea73951e 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr index 601bbd20fb7..7e0a02be649 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr @@ -1,10 +1,10 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> tests/benchmark_ui/bad_return_type_blank_with_question.rs:15:14 + --> tests/benchmark_ui/bad_return_type_blank_with_question.rs:32:14 | -5 | #[benchmarks] +22 | #[benchmarks] | ------------- this function should return `Result` or `Option` to accept `?` ... -15 | something()?; +32 | something()?; | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual>` is not implemented for `()` diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs index 76f12990053..cf4605406fa 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr index ff501a620fe..9ec5a17118e 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr @@ -1,9 +1,9 @@ error: Benchmark `#[block]` or `#[extrinsic_call]` item cannot be the last statement of your benchmark function definition if you have defined a return type. You should return something compatible with Result<(), BenchmarkError> (i.e. `Ok(())`) as the last statement or change your signature to a blank return type. - --> tests/benchmark_ui/bad_return_type_no_last_stmt.rs:10:43 + --> tests/benchmark_ui/bad_return_type_no_last_stmt.rs:27:43 | -10 | fn bench() -> Result<(), BenchmarkError> { +27 | fn bench() -> Result<(), BenchmarkError> { | ______________________________________________^ -11 | | #[block] -12 | | {} -13 | | } +28 | | #[block] +29 | | {} +30 | | } | |_____^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs index c206ec36a15..5a434aac55c 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr index b830b8eb59c..ff813df375d 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr @@ -1,5 +1,5 @@ error: expected `Result` - --> tests/benchmark_ui/bad_return_type_non_result.rs:10:31 + --> tests/benchmark_ui/bad_return_type_non_result.rs:27:31 | -10 | fn bench(y: Linear<1, 2>) -> String { +27 | fn bench(y: Linear<1, 2>) -> String { | ^^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs index 4b558859397..1a831e6e679 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr index 050da167673..6b2f73bd666 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr @@ -1,5 +1,5 @@ error: expected `Result` - --> tests/benchmark_ui/bad_return_type_option.rs:10:16 + --> tests/benchmark_ui/bad_return_type_option.rs:27:16 | -10 | fn bench() -> Option { +27 | fn bench() -> Option { | ^^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_block.rs b/substrate/frame/support/test/tests/benchmark_ui/dup_block.rs index 2c2ef9db9a4..cba310adb26 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/dup_block.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_block.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_block.stderr b/substrate/frame/support/test/tests/benchmark_ui/dup_block.stderr index 3d73c3d6609..f17cec0fbdf 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/dup_block.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_block.stderr @@ -1,5 +1,5 @@ error: Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark. - --> tests/benchmark_ui/dup_block.rs:14:3 + --> tests/benchmark_ui/dup_block.rs:31:3 | -14 | #[block] +31 | #[block] | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs b/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs index 4d135d1a04f..e82f6ec3d90 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr b/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr index 593f7072bfa..6512c753590 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr @@ -1,5 +1,5 @@ error: Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark. - --> tests/benchmark_ui/dup_extrinsic_call.rs:14:3 + --> tests/benchmark_ui/dup_extrinsic_call.rs:31:3 | -14 | #[extrinsic_call] +31 | #[extrinsic_call] | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/empty_function.rs b/substrate/frame/support/test/tests/benchmark_ui/empty_function.rs index bc04101dd38..7fcd45d1bc4 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/empty_function.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/empty_function.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/empty_function.stderr b/substrate/frame/support/test/tests/benchmark_ui/empty_function.stderr index 69d75303613..4d73fa1835a 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/empty_function.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/empty_function.stderr @@ -1,5 +1,5 @@ error: No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body. - --> tests/benchmark_ui/empty_function.rs:10:13 + --> tests/benchmark_ui/empty_function.rs:27:13 | -10 | fn bench() {} +27 | fn bench() {} | ^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/extra_extra.rs b/substrate/frame/support/test/tests/benchmark_ui/extra_extra.rs index 1aa6c9ecb75..d94c427451c 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extra_extra.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/extra_extra.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/extra_extra.stderr b/substrate/frame/support/test/tests/benchmark_ui/extra_extra.stderr index bf36b4f0805..17c67d21be1 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extra_extra.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/extra_extra.stderr @@ -1,5 +1,5 @@ error: unexpected end of input, `extra` can only be specified once - --> tests/benchmark_ui/extra_extra.rs:9:26 - | -9 | #[benchmark(extra, extra)] - | ^ + --> tests/benchmark_ui/extra_extra.rs:26:26 + | +26 | #[benchmark(extra, extra)] + | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs b/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs index 3418c7af737..37693c4b718 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr b/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr index 4d48a8ad77a..e17eba963a1 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr @@ -1,5 +1,5 @@ error: unexpected end of input, `skip_meta` can only be specified once - --> tests/benchmark_ui/extra_skip_meta.rs:9:34 - | -9 | #[benchmark(skip_meta, skip_meta)] - | ^ + --> tests/benchmark_ui/extra_skip_meta.rs:26:34 + | +26 | #[benchmark(skip_meta, skip_meta)] + | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs b/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs index ce360ee7577..101ba73488f 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[extrinsic_call] diff --git a/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr b/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr index c5194d7a665..530754b723a 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr @@ -1,7 +1,7 @@ error: `#[extrinsic_call]` must be in a benchmark function definition labeled with `#[benchmark]`. - --> tests/benchmark_ui/extrinsic_call_out_of_fn.rs:3:1 - | -3 | #[extrinsic_call] - | ^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `extrinsic_call` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/benchmark_ui/extrinsic_call_out_of_fn.rs:20:1 + | +20 | #[extrinsic_call] + | ^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `extrinsic_call` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.rs b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.rs index cfb00e88c00..ce7693fc71b 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr index 115a8206f58..87d4f476a60 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `::RuntimeOrigin: From<{integer}>` is not satisfied - --> tests/benchmark_ui/invalid_origin.rs:6:1 - | -6 | #[benchmarks] - | ^^^^^^^^^^^^^ the trait `From<{integer}>` is not implemented for `::RuntimeOrigin` - | - = note: required for `{integer}` to implement `Into<::RuntimeOrigin>` - = note: this error originates in the attribute macro `benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/benchmark_ui/invalid_origin.rs:23:1 + | +23 | #[benchmarks] + | ^^^^^^^^^^^^^ the trait `From<{integer}>` is not implemented for `::RuntimeOrigin` + | + = note: required for `{integer}` to implement `Into<::RuntimeOrigin>` + = note: this error originates in the attribute macro `benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/benchmark_ui/missing_call.rs b/substrate/frame/support/test/tests/benchmark_ui/missing_call.rs index f39e74286b5..0e65f6867a4 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/missing_call.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/missing_call.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/missing_call.stderr b/substrate/frame/support/test/tests/benchmark_ui/missing_call.stderr index 908d9704392..fd4d43d0a3d 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/missing_call.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/missing_call.stderr @@ -1,8 +1,8 @@ error: No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body. - --> tests/benchmark_ui/missing_call.rs:10:13 + --> tests/benchmark_ui/missing_call.rs:27:13 | -10 | fn bench() { +27 | fn bench() { | ________________^ -11 | | assert_eq!(2 + 2, 4); -12 | | } +28 | | assert_eq!(2 + 2, 4); +29 | | } | |_____^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/missing_origin.rs b/substrate/frame/support/test/tests/benchmark_ui/missing_origin.rs index 2aaed756b9a..15fb850dfbc 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/missing_origin.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/missing_origin.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/missing_origin.stderr b/substrate/frame/support/test/tests/benchmark_ui/missing_origin.stderr index 0e72bff4747..c72f2734db5 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/missing_origin.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/missing_origin.stderr @@ -1,5 +1,5 @@ error: Single-item extrinsic calls must specify their origin as the first argument. - --> tests/benchmark_ui/missing_origin.rs:12:3 + --> tests/benchmark_ui/missing_origin.rs:29:3 | -12 | thing(); +29 | thing(); | ^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs index 450ce4f9c50..126cee8fa6c 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs index 4930aedd601..5cbc4aa23f1 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs index bead3bf277b..b1ef44be8b0 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; use frame_support_test::Config; use frame_support::parameter_types; diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs index ce09b437a83..0bbd412423a 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs index 4930aedd601..5cbc4aa23f1 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_result.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_result.rs index 33d71ece4a0..2948a2b7ebc 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_result.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_result.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.rs b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.rs index 18cae4d5d5c..0b007741f11 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr index 5cebe9eab05..bea770b634e 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr @@ -1,5 +1,5 @@ error: expected `extra` or `skip_meta` - --> tests/benchmark_ui/unrecognized_option.rs:9:32 - | -9 | #[benchmark(skip_meta, extra, bad)] - | ^^^ + --> tests/benchmark_ui/unrecognized_option.rs:26:32 + | +26 | #[benchmark(skip_meta, extra, bad)] + | ^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs b/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs index ab55c22e9fb..fddb6408ea7 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.stderr index b622adbfe65..8fd67547af9 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/abundant_where_param.stderr @@ -1,5 +1,5 @@ error: `Block` was declared above. Please use exactly one declaration for `Block`. - --> $DIR/abundant_where_param.rs:7:3 - | -7 | Block = Block1, - | ^^^^^ + --> tests/construct_runtime_ui/abundant_where_param.rs:24:3 + | +24 | Block = Block1, + | ^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs b/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs index 4cb24971465..d5d8553725a 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_runtime::{generic, traits::BlakeTwo256}; use sp_core::sr25519; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr index 1ea62b7d6fd..732b8edb821 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr @@ -1,22 +1,22 @@ error: Unexpected tokens, expected one of `=`, `,` - --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:26:43 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:43:43 | -26 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, +43 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, | ^^^^^^^^^ error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:18:64 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:35:64 | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | ^^^^^^^^^^^ not found in this scope | help: you might be missing a type parameter | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:20:25 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:37:25 | -20 | impl pallet::Config for Runtime {} +37 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs index 712452d1a3a..c94d092579d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr index 2e2028fd1b8..ef4fb8beba8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr @@ -1,11 +1,11 @@ error: Pallet indices are conflicting: Both pallets System and Pallet1 are at index 0 - --> $DIR/conflicting_index.rs:9:3 - | -9 | System: system::{}, - | ^^^^^^ + --> tests/construct_runtime_ui/conflicting_index.rs:26:3 + | +26 | System: system::{}, + | ^^^^^^ error: Pallet indices are conflicting: Both pallets System and Pallet1 are at index 0 - --> $DIR/conflicting_index.rs:10:3 + --> tests/construct_runtime_ui/conflicting_index.rs:27:3 | -10 | Pallet1: pallet1::{} = 0, +27 | Pallet1: pallet1::{} = 0, | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs index 6bc6bc5402e..3ba427f993c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr index bfa3706a456..d771119f221 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr @@ -1,11 +1,11 @@ error: Pallet indices are conflicting: Both pallets System and Pallet3 are at index 5 - --> $DIR/conflicting_index_2.rs:9:3 - | -9 | System: system::{} = 5, - | ^^^^^^ + --> tests/construct_runtime_ui/conflicting_index_2.rs:26:3 + | +26 | System: system::{} = 5, + | ^^^^^^ error: Pallet indices are conflicting: Both pallets System and Pallet3 are at index 5 - --> $DIR/conflicting_index_2.rs:12:3 + --> tests/construct_runtime_ui/conflicting_index_2.rs:29:3 | -12 | Pallet3: pallet3::{}, +29 | Pallet3: pallet3::{}, | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.rs b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.rs index 513fbcfb513..133e8b1ca48 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.stderr index 6fb983f03a9..20051949b2d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/conflicting_module_name.stderr @@ -1,11 +1,11 @@ error: Two pallets with the same name! - --> tests/construct_runtime_ui/conflicting_module_name.rs:7:3 - | -7 | Balance: balances::{Pallet}, - | ^^^^^^^ + --> tests/construct_runtime_ui/conflicting_module_name.rs:24:3 + | +24 | Balance: balances::{Pallet}, + | ^^^^^^^ error: Two pallets with the same name! - --> tests/construct_runtime_ui/conflicting_module_name.rs:8:3 - | -8 | Balance: balances::{Pallet}, - | ^^^^^^^ + --> tests/construct_runtime_ui/conflicting_module_name.rs:25:3 + | +25 | Balance: balances::{Pallet}, + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.rs b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.rs index c0e325085b5..5fd7822e8c3 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { 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 ec004fcf953..cc2c2e16009 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 @@ -5,30 +5,30 @@ error: use of deprecated constant `WhereSection::_w`: For more info see: - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | / construct_runtime! { -4 | | pub struct Runtime where -5 | | Block = Block, -6 | | NodeBlock = Block, +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | -10 | | } -11 | | } +27 | | } +28 | | } | |_^ | = note: `-D deprecated` implied by `-D warnings` = note: this error originates in the macro `frame_support::match_and_insert` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | @@ -40,28 +40,28 @@ note: required by a bound in `frame_system::Event` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | note: required because it appears within the type `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Clone` @@ -72,28 +72,28 @@ note: required by a bound in `Clone` = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | note: required because it appears within the type `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` @@ -104,28 +104,28 @@ note: required by a bound in `EncodeLike` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | note: required because it appears within the type `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Decode` @@ -136,15 +136,15 @@ note: required by a bound in `Decode` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | @@ -157,15 +157,15 @@ note: required by a bound in `From` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | @@ -178,38 +178,38 @@ note: required by a bound in `TryInto` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 - | -3 | construct_runtime! { - | ^ the trait `Config` is not implemented for `Runtime` - | - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | ^ the trait `Config` is not implemented for `Runtime` + | + = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | @@ -217,15 +217,15 @@ error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satis = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | @@ -234,29 +234,29 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Clone` @@ -267,29 +267,29 @@ note: required by a bound in `Clone` = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` @@ -300,29 +300,29 @@ note: required by a bound in `EncodeLike` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Decode` @@ -333,40 +333,40 @@ note: required by a bound in `Decode` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:9:3 - | -9 | System: frame_system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ the trait `Config` is not implemented for `Runtime` - | + --> tests/construct_runtime_ui/deprecated_where_block.rs:26:3 + | +26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^ the trait `Config` is not implemented for `Runtime` + | note: required by a bound in `frame_system::GenesisConfig` - --> $WORKSPACE/substrate/frame/system/src/lib.rs - | - | pub struct GenesisConfig { - | ^^^^^^ required by this bound in `GenesisConfig` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub struct GenesisConfig { + | ^^^^^^ required by this bound in `GenesisConfig` error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | note: required because it appears within the type `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Result` @@ -377,28 +377,28 @@ note: required by a bound in `Result` = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | note: required because it appears within the type `RuntimeEvent` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `TryInto` @@ -409,29 +409,29 @@ note: required by a bound in `TryInto` = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:3:1 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -3 | // construct_runtime! { -4 | || pub struct Runtime where -5 | || Block = Block, -6 | || NodeBlock = Block, +20 | // construct_runtime! { +21 | || pub struct Runtime where +22 | || Block = Block, +23 | || NodeBlock = Block, ... || -10 | || } -11 | || } +27 | || } +28 | || } | ||_- in this macro invocation ... | note: required by a bound in `Result` diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.rs b/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.rs index 68a2523d3bc..ac5cf22ce1d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.stderr index e3f69478144..51459614ebe 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/double_module_parts.stderr @@ -1,5 +1,5 @@ error: `Config` was already declared before. Please remove the duplicate declaration - --> tests/construct_runtime_ui/double_module_parts.rs:7:37 - | -7 | Balance: balances::{Config, Call, Config, Origin}, - | ^^^^^^ + --> tests/construct_runtime_ui/double_module_parts.rs:24:37 + | +24 | Balance: balances::{Config, Call, Config, Origin}, + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs b/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs index 83e708841aa..ea169c8ff24 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr index 75de5607652..e6d2fd4938d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr @@ -1,5 +1,5 @@ error: `Call` was already declared before. Please remove the duplicate declaration - --> $DIR/duplicate_exclude.rs:9:46 - | -9 | System: frame_system exclude_parts { Call, Call }, - | ^^^^ + --> tests/construct_runtime_ui/duplicate_exclude.rs:26:46 + | +26 | System: frame_system exclude_parts { Call, Call }, + | ^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs index 23badd76276..3b8497fcc24 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr index f0c0f17779d..b76fa8b2fc8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr @@ -1,5 +1,5 @@ error: expected one of: `crate`, `self`, `super`, identifier - --> tests/construct_runtime_ui/empty_pallet_path.rs:6:11 - | -6 | system: , - | ^ + --> tests/construct_runtime_ui/empty_pallet_path.rs:23:11 + | +23 | system: , + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs index 441e9c75040..2619b680fcf 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr index 82e6aa6c8e3..243e6618eaa 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr @@ -1,5 +1,5 @@ error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` - --> $DIR/exclude_missspell.rs:9:24 - | -9 | System: frame_system exclude_part { Call }, - | ^^^^^^^^^^^^ + --> tests/construct_runtime_ui/exclude_missspell.rs:26:24 + | +26 | System: frame_system exclude_part { Call }, + | ^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs index 10cda7b4e7e..b4cea16d1a5 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_runtime::{generic, traits::BlakeTwo256}; use sp_core::sr25519; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr index 4b85613838a..a6a630cf8cb 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr @@ -1,22 +1,22 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> tests/construct_runtime_ui/exclude_undefined_part.rs:31:34 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:48:34 | -31 | Pallet: pallet exclude_parts { Call }, +48 | Pallet: pallet exclude_parts { Call }, | ^^^^ error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/exclude_undefined_part.rs:23:64 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:40:64 | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +40 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | ^^^^^^^^^^^ not found in this scope | help: you might be missing a type parameter | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +40 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/exclude_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:42:25 | -25 | impl pallet::Config for Runtime {} +42 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs b/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs index 35d49a4d8a2..fbb6cad39d4 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr index 6a6c4b41588..9e7578fdac2 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr @@ -1,5 +1,5 @@ error: `System` pallet declaration is feature gated, please remove any `#[cfg]` attributes - --> tests/construct_runtime_ui/feature_gated_system_pallet.rs:7:3 - | -7 | System: frame_system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ + --> tests/construct_runtime_ui/feature_gated_system_pallet.rs:24:3 + | +24 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.rs b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.rs index 1ad1f8e0b1d..3f6cb19ba6b 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr index a6adb37d049..bf53f43b9ba 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr @@ -1,5 +1,5 @@ error: `Call` is not allowed to have generics. Only the following pallets are allowed to have generics: `Event`, `Error`, `Origin`, `Config`. - --> tests/construct_runtime_ui/generics_in_invalid_module.rs:7:36 - | -7 | Balance: balances::::{Call, Origin}, - | ^^^^ + --> tests/construct_runtime_ui/generics_in_invalid_module.rs:24:36 + | +24 | Balance: balances::::{Call, Origin}, + | ^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs index bce87c51336..526dd50fb7d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr index bfee2910cd2..dfb49b14946 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr @@ -1,6 +1,6 @@ error: feature = 1 ^ expected one of ``, `all`, `any`, `not` here - --> tests/construct_runtime_ui/invalid_meta_literal.rs:7:3 - | -7 | #[cfg(feature = 1)] - | ^ + --> tests/construct_runtime_ui/invalid_meta_literal.rs:24:3 + | +24 | #[cfg(feature = 1)] + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.rs index bf6919f5a58..c7fcb54cd41 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr index 1f9277c3f0a..5656e2ba4dc 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr @@ -1,5 +1,5 @@ error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` - --> tests/construct_runtime_ui/invalid_module_details.rs:6:17 - | -6 | system: System::(), - | ^ + --> tests/construct_runtime_ui/invalid_module_details.rs:23:17 + | +23 | system: System::(), + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.rs index 51f14e6883e..c5dc80acfcd 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr index dfcc9b8be42..ad631de204e 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr @@ -1,5 +1,5 @@ error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` - --> tests/construct_runtime_ui/invalid_module_details_keyword.rs:6:20 - | -6 | system: System::{enum}, - | ^^^^ + --> tests/construct_runtime_ui/invalid_module_details_keyword.rs:23:20 + | +23 | system: System::{enum}, + | ^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs index 607741d7823..9a8a6c17b7c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr index 9dd849ff041..b5b89a5a270 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr @@ -1,5 +1,5 @@ error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` - --> tests/construct_runtime_ui/invalid_module_entry.rs:7:23 - | -7 | Balance: balances::{Unexpected}, - | ^^^^^^^^^^ + --> tests/construct_runtime_ui/invalid_module_entry.rs:24:23 + | +24 | Balance: balances::{Unexpected}, + | ^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.rs index c132fa01b22..ddd1bada35c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr index 80be1b8dd42..5a28b42efe0 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr @@ -1,5 +1,5 @@ error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` - --> tests/construct_runtime_ui/invalid_token_after_module.rs:6:18 - | -6 | system: System ? - | ^ + --> tests/construct_runtime_ui/invalid_token_after_module.rs:23:18 + | +23 | system: System ? + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.rs index 42e7759f87f..07b86180ccf 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.stderr index 8988f8a35b0..bafde9b1f3e 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_token_after_name.stderr @@ -1,5 +1,5 @@ error: expected `:` - --> tests/construct_runtime_ui/invalid_token_after_name.rs:6:10 - | -6 | system ? - | ^ + --> tests/construct_runtime_ui/invalid_token_after_name.rs:23:10 + | +23 | system ? + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.rs b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.rs index 091f0644494..23e0b344067 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.stderr index 9e358b6a21f..02a0bb645bb 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_where_param.stderr @@ -1,5 +1,5 @@ error: expected one of: `Block`, `NodeBlock`, `UncheckedExtrinsic` - --> $DIR/invalid_where_param.rs:7:3 - | -7 | TypeX = Block, - | ^^^^^ + --> tests/construct_runtime_ui/invalid_where_param.rs:24:3 + | +24 | TypeX = Block, + | ^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs b/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs index bc2039c4e81..985bef03a2f 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr index 30fcba4c710..facd83a1086 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr @@ -1,5 +1,5 @@ error: Instantiable pallet with no generic `Event` cannot be constructed: pallet `Balance` must have generic `Event` - --> tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs:7:3 - | -7 | Balance: balances:: expanded::{}::{Event}, - | ^^^^^^^ + --> tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs:24:3 + | +24 | Balance: balances:: expanded::{}::{Event}, + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.rs b/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.rs index afd96a04854..42041419028 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.stderr index 5072f718db1..6138a2d4008 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_module_instance.stderr @@ -1,5 +1,5 @@ error: expected identifier - --> tests/construct_runtime_ui/missing_module_instance.rs:6:20 - | -6 | system: System::<>, - | ^ + --> tests/construct_runtime_ui/missing_module_instance.rs:23:20 + | +23 | system: System::<>, + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs b/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs index 42db63ae90a..32fc906fd05 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr index 6c076d7b49f..e688d80e028 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr @@ -1,5 +1,5 @@ error: Instantiable pallet with no generic `Origin` cannot be constructed: pallet `Balance` must have generic `Origin` - --> tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs:7:3 - | -7 | Balance: balances:: expanded::{}::{Origin}, - | ^^^^^^^ + --> tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs:24:3 + | +24 | Balance: balances:: expanded::{}::{Origin}, + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.rs b/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.rs index 685f9059b1b..fbf30cf4fe7 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.stderr index c8631f44051..11ec6f33d20 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_system_module.stderr @@ -1,6 +1,6 @@ error: `System` pallet declaration is missing. Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},` - --> tests/construct_runtime_ui/missing_system_module.rs:5:2 - | -5 | / { -6 | | } - | |_____^ + --> tests/construct_runtime_ui/missing_system_module.rs:22:2 + | +22 | / { +23 | | } + | |_____^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs b/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs index 4d2225a4afb..249c7ba7edc 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr index fb7e38b53dc..92075a650b0 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr @@ -1,5 +1,5 @@ error: Missing associated type for `UncheckedExtrinsic`. Add `UncheckedExtrinsic` = ... to where section. - --> tests/construct_runtime_ui/missing_where_param.rs:7:2 - | -7 | {} - | ^ + --> tests/construct_runtime_ui/missing_where_param.rs:24:2 + | +24 | {} + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs b/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs index 7dcbdb9aa4f..f04ac1c25f3 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr index 2e055f5d372..def06573d74 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr @@ -1,5 +1,5 @@ error: Pallet index doesn't fit into u8, index is 256 - --> $DIR/more_than_256_modules.rs:10:3 + --> tests/construct_runtime_ui/more_than_256_modules.rs:27:3 | -10 | Pallet256: pallet256::{}, +27 | Pallet256: pallet256::{}, | ^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs b/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs index 499f9a5cdcd..5442634a7ac 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.stderr index caf4a7401b0..5b53e455c9c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.stderr @@ -1,5 +1,5 @@ error: Expected `,` or `{` - --> $DIR/no_comma_after_where.rs:6:3 - | -6 | Block = Block, - | ^^^^^ + --> tests/construct_runtime_ui/no_comma_after_where.rs:23:3 + | +23 | Block = Block, + | ^^^^^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs index 0d6afbcdc2c..ea52293a673 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr index 75d0ce05465..af9069edc80 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -1,63 +1,63 @@ error: The number of pallets exceeds the maximum number of tuple elements. To increase this limit, enable the tuples-96 feature of [frame_support]. - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:49:2 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:66:2 | -49 | pub struct Runtime +66 | pub struct Runtime | ^^^ error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:18:64 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:35:64 | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | ^^^^^^^^^^^ not found in this scope | help: you might be missing a type parameter | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:20:25 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:37:25 | -20 | impl pallet::Config for Runtime {} +37 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:22:31 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:31 | -22 | impl frame_system::Config for Runtime { +39 | impl frame_system::Config for Runtime { | ^^^^^^^ not found in this scope error[E0412]: cannot find type `RuntimeOrigin` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:24:23 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:41:23 | -24 | type RuntimeOrigin = RuntimeOrigin; +41 | type RuntimeOrigin = RuntimeOrigin; | ^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeOrigin` error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:26:21 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:43:21 | -26 | type RuntimeCall = RuntimeCall; +43 | type RuntimeCall = RuntimeCall; | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` error[E0412]: cannot find type `RuntimeEvent` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:32:22 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:49:22 | -32 | type RuntimeEvent = RuntimeEvent; +49 | type RuntimeEvent = RuntimeEvent; | ^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeEvent` error[E0412]: cannot find type `PalletInfo` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:38:20 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:55:20 | -38 | type PalletInfo = PalletInfo; +55 | type PalletInfo = PalletInfo; | ^^^^^^^^^^ | help: you might have meant to use the associated type | -38 | type PalletInfo = Self::PalletInfo; +55 | type PalletInfo = Self::PalletInfo; | ~~~~~~~~~~~~~~~~ help: consider importing one of these items | -1 + use frame_benchmarking::__private::traits::PalletInfo; +18 + use frame_benchmarking::__private::traits::PalletInfo; | -1 + use frame_support::traits::PalletInfo; +18 + use frame_support::traits::PalletInfo; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs index 8b3e26bc5e2..2834b5b8f2a 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr index 47504573515..0ad408b8123 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr @@ -1,13 +1,13 @@ error[E0080]: evaluation of constant value failed - --> tests/construct_runtime_ui/pallet_error_too_large.rs:73:1 + --> tests/construct_runtime_ui/pallet_error_too_large.rs:90:1 | -73 | / construct_runtime! { -74 | | pub struct Runtime -75 | | { -76 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, -77 | | Pallet: pallet::{Pallet}, -78 | | } -79 | | } - | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:73:1 +90 | / construct_runtime! { +91 | | pub struct Runtime +92 | | { +93 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +94 | | Pallet: pallet::{Pallet}, +95 | | } +96 | | } + | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:90:1 | = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index 25cb5e93f65..62c4b1327e0 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index f3f29e4c695..c6dfeb792b8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -1,16 +1,16 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove `Call` from construct_runtime? - --> tests/construct_runtime_ui/undefined_call_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_call_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet::{Pallet, Call}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet::{Pallet, Call}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index c44cceef81a..893690501a8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 81e42cec3b9..6dd332630ad 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -1,36 +1,36 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remove `Event` from construct_runtime? - --> tests/construct_runtime_ui/undefined_event_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Event}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Event}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Event` in module `pallet` - --> tests/construct_runtime_ui/undefined_event_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:65:1 | -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Event}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Event}, +70 | | } +71 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | -1 + use frame_support_test::Event; +18 + use frame_support_test::Event; | -1 + use frame_system::Event; +18 + use frame_system::Event; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index 4436202f04f..a3501ca31a3 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 920785fc962..00b5a137003 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -1,36 +1,36 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you should remove `Config` from construct_runtime? - --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Config}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Config}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in module `pallet` - --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:65:1 | -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Config}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Config}, +70 | | } +71 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | -1 + use frame_system::GenesisConfig; +18 + use frame_system::GenesisConfig; | -1 + use test_pallet::GenesisConfig; +18 + use test_pallet::GenesisConfig; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index 8b48c4d0d6a..e22745930d6 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 659d43b1510..749d2d9c159 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -1,34 +1,34 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should remove `Inherent` from construct_runtime? - --> tests/construct_runtime_ui/undefined_inherent_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `create_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `create_inherent` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | _^ -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -37,19 +37,19 @@ error[E0599]: no function or associated item named `create_inherent` found for s = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `is_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `is_inherent` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | _^ -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -58,19 +58,19 @@ error[E0599]: no function or associated item named `is_inherent` found for struc = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `check_inherent` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | _^ -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -79,19 +79,19 @@ error[E0599]: no function or associated item named `check_inherent` found for st = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- associated item `INHERENT_IDENTIFIER` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | _^ -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_^ associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -100,19 +100,19 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `is_inherent_required` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `is_inherent_required` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | _^ -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -53 | | } -54 | | } +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +70 | | } +71 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 974928785f7..656365279b8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index c41dbe79421..13612233e86 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -1,36 +1,36 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remove `Origin` from construct_runtime? - --> tests/construct_runtime_ui/undefined_origin_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Origin}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Origin}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Origin` in module `pallet` - --> tests/construct_runtime_ui/undefined_origin_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:65:1 | -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet expanded::{}::{Pallet, Origin}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet expanded::{}::{Pallet, Origin}, +70 | | } +71 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | -1 + use frame_support_test::Origin; +18 + use frame_support_test::Origin; | -1 + use frame_system::Origin; +18 + use frame_system::Origin; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 505b249d92d..05545821ab0 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 007b7725073..64677728c8b 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -1,49 +1,49 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you should remove `ValidateUnsigned` from construct_runtime? - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:22:1 | -5 | #[frame_support::pallet] +22 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -48 | / construct_runtime! { -49 | | pub struct Runtime -50 | | { -51 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, -52 | | Pallet: pallet::{Pallet, ValidateUnsigned}, -53 | | } -54 | | } +65 | / construct_runtime! { +66 | | pub struct Runtime +67 | | { +68 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +69 | | Pallet: pallet::{Pallet, ValidateUnsigned}, +70 | | } +71 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:52:3 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:69:3 | -48 | // construct_runtime! { -49 | || pub struct Runtime -50 | || { -51 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -52 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +65 | // construct_runtime! { +66 | || pub struct Runtime +67 | || { +68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, | || -^^^^^^ variant or associated item not found in `RuntimeCall` | ||________| | | ... | error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `pre_dispatch` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | __^ | | _| | || -49 | || pub struct Runtime -50 | || { -51 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -52 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -53 | || } -54 | || } +66 | || pub struct Runtime +67 | || { +68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +70 | || } +71 | || } | ||_- in this macro invocation ... | | @@ -54,21 +54,21 @@ error[E0599]: no function or associated item named `pre_dispatch` found for stru = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:48:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:65:1 | -11 | pub struct Pallet(_); +28 | pub struct Pallet(_); | -------------------- function or associated item `validate_unsigned` not found for this struct ... -48 | construct_runtime! { +65 | construct_runtime! { | __^ | | _| | || -49 | || pub struct Runtime -50 | || { -51 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -52 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -53 | || } -54 | || } +66 | || pub struct Runtime +67 | || { +68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +70 | || } +71 | || } | ||_- in this macro invocation ... | | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs index e4e2d3dca02..30715bb0492 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr index 34637269db6..efaed3e97b9 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr @@ -1,6 +1,6 @@ error: feature(test) ^ expected one of `=`, `,`, `)` here - --> tests/construct_runtime_ui/unsupported_meta_structure.rs:7:3 - | -7 | #[cfg(feature(test))] - | ^ + --> tests/construct_runtime_ui/unsupported_meta_structure.rs:24:3 + | +24 | #[cfg(feature(test))] + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs index 491cc2c9053..d3af4a53ef0 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; construct_runtime! { diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr index da1b61b1c30..52fbe6d466e 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr @@ -1,5 +1,5 @@ error: Unsupported attribute, only #[cfg] is supported on pallet declarations in `construct_runtime` - --> tests/construct_runtime_ui/unsupported_pallet_attr.rs:7:3 - | -7 | #[attr] - | ^ + --> tests/construct_runtime_ui/unsupported_pallet_attr.rs:24:3 + | +24 | #[attr] + | ^ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs index 8563be1008c..36dde76d504 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_runtime::{generic, traits::BlakeTwo256}; use sp_core::sr25519; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr index 4058ccab2c5..802a966c02c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr @@ -1,22 +1,22 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> tests/construct_runtime_ui/use_undefined_part.rs:31:30 + --> tests/construct_runtime_ui/use_undefined_part.rs:48:30 | -31 | Pallet: pallet use_parts { Call }, +48 | Pallet: pallet use_parts { Call }, | ^^^^ error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/use_undefined_part.rs:23:64 + --> tests/construct_runtime_ui/use_undefined_part.rs:40:64 | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +40 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | ^^^^^^^^^^^ not found in this scope | help: you might be missing a type parameter | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +40 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/use_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/use_undefined_part.rs:42:25 | -25 | impl pallet::Config for Runtime {} +42 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs index 3b279169338..332e1e78730 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::*; pub trait Animal { diff --git a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr index 735fd7a628e..1dc575bbffa 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr @@ -1,5 +1,5 @@ error: expected `impl` - --> tests/derive_impl_ui/attached_to_non_impl.rs:39:1 + --> tests/derive_impl_ui/attached_to_non_impl.rs:56:1 | -39 | struct Something {} +56 | struct Something {} | ^^^^^^ diff --git a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs index 2badd183003..bc118acdf1e 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::*; pub trait Animal { 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 1cac1662462..5cfbd8c8862 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,7 @@ error: cannot find macro `__export_tokens_tt_tiger` in this scope - --> tests/derive_impl_ui/bad_default_impl_path.rs:42:1 + --> tests/derive_impl_ui/bad_default_impl_path.rs:59:1 | -42 | #[derive_impl(Tiger as Animal)] +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/bad_disambiguation_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs index adc5df23a75..9535ac3deda 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::*; pub trait Animal { diff --git a/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr index 6fd4e431beb..664146302d2 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr @@ -1,5 +1,5 @@ error[E0405]: cannot find trait `Insect` in this scope - --> tests/derive_impl_ui/bad_disambiguation_path.rs:38:35 + --> tests/derive_impl_ui/bad_disambiguation_path.rs:55:35 | -38 | #[derive_impl(FourLeggedAnimal as Insect)] +55 | #[derive_impl(FourLeggedAnimal as Insect)] | ^^^^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs index 0d8dc8eb1d4..7e5df20a963 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::{*, pallet_prelude::inject_runtime_type}; use static_assertions::assert_type_eq_all; 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 683131cceb8..79b50a940b8 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 @@ -1,10 +1,10 @@ error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs:13:10 + --> tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs:30:10 | -13 | type RuntimeCall = (); +30 | type RuntimeCall = (); | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` ... -18 | #[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall; +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) diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.rs b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.rs index 60ec710d015..cb541091a97 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::{*, pallet_prelude::inject_runtime_type}; use static_assertions::assert_type_eq_all; diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr index c3382510744..501aad0419f 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr @@ -1,14 +1,14 @@ error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo` - --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:15:5 + --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:32:5 | -15 | type RuntimeInfo = (); +32 | type RuntimeInfo = (); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0046]: not all trait items implemented, missing: `RuntimeInfo` - --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:13:1 + --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:30:1 | -5 | type RuntimeInfo; +22 | type RuntimeInfo; | ---------------- `RuntimeInfo` from trait ... -13 | impl Config for Pallet { +30 | impl Config for Pallet { | ^^^^^^^^^^^^^^^^^^^^^^ missing `RuntimeInfo` in implementation diff --git a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs index 21f1cc32009..f26c28313e5 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::*; pub trait Animal { diff --git a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr index 85cd94ae08a..365df0331ae 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr @@ -1,7 +1,7 @@ error: unexpected end of input, expected identifier - --> tests/derive_impl_ui/missing_disambiguation_path.rs:38:1 + --> tests/derive_impl_ui/missing_disambiguation_path.rs:55:1 | -38 | #[derive_impl(FourLeggedAnimal as)] +55 | #[derive_impl(FourLeggedAnimal as)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `derive_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs b/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs index 336ddc315f8..37c0742f195 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::*; use static_assertions::assert_type_eq_all; diff --git a/substrate/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs b/substrate/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs index ec09bd15e01..e4cb94e74bd 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::macro_magic::export_tokens] struct MyCoolStruct { field: u32, diff --git a/substrate/frame/support/test/tests/derive_impl_ui/pass/runtime_type_working.rs b/substrate/frame/support/test/tests/derive_impl_ui/pass/runtime_type_working.rs index 04ad0089446..93b7309cf97 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/pass/runtime_type_working.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/pass/runtime_type_working.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::{*, pallet_prelude::inject_runtime_type}; use static_assertions::assert_type_eq_all; diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/clone.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/clone.rs index 2bc1cc492d1..9da7d66fe1b 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/clone.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/clone.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 7744586e56b..e0294d3c2fd 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied - --> tests/derive_no_bound_ui/clone.rs:7:2 - | -7 | c: T::C, - | ^ the trait `Clone` is not implemented for `::C` + --> tests/derive_no_bound_ui/clone.rs:24:2 + | +24 | c: T::C, + | ^ the trait `Clone` is not implemented for `::C` diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/debug.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/debug.rs index 6016c3e6d98..02215cb8d57 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/debug.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/debug.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } 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 acc7f80b376..d86292d71b7 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 @@ -1,8 +1,8 @@ error[E0277]: `::C` doesn't implement `std::fmt::Debug` - --> tests/derive_no_bound_ui/debug.rs:7:2 - | -7 | c: T::C, - | ^ `::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` + --> tests/derive_no_bound_ui/debug.rs:24:2 + | +24 | c: T::C, + | ^ `::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` diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/default.rs index 0780a88e675..1a66c3b79fc 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/default.stderr index d56dd438f2a..90e976d9f6a 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `::C: std::default::Default` is not satisfied - --> tests/derive_no_bound_ui/default.rs:7:2 - | -7 | c: T::C, - | ^ the trait `std::default::Default` is not implemented for `::C` + --> tests/derive_no_bound_ui/default.rs:24:2 + | +24 | c: T::C, + | ^ the trait `std::default::Default` is not implemented for `::C` diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs index 51b6137c007..48f276df68b 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[derive(frame_support::DefaultNoBound)] enum Empty {} diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr index 9c93b515adc..246fe67586b 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr @@ -1,5 +1,5 @@ error: cannot derive Default for an empty enum - --> tests/derive_no_bound_ui/default_empty_enum.rs:2:6 - | -2 | enum Empty {} - | ^^^^^ + --> tests/derive_no_bound_ui/default_empty_enum.rs:19:6 + | +19 | enum Empty {} + | ^^^^^ diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs index 185df01fe2b..1d40eac4c71 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr index 12e00236715..d0c4401e8c5 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr @@ -1,5 +1,5 @@ error: no default declared, make a variant default by placing `#[default]` above it - --> tests/derive_no_bound_ui/default_no_attribute.rs:6:6 - | -6 | enum Foo { - | ^^^ + --> tests/derive_no_bound_ui/default_no_attribute.rs:23:6 + | +23 | enum Foo { + | ^^^ diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs index c3d175da6c0..808223f2ff0 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr index 5430ef142c5..775964ea42d 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr @@ -1,21 +1,21 @@ error: multiple declared defaults - --> tests/derive_no_bound_ui/default_too_many_attributes.rs:5:10 - | -5 | #[derive(frame_support::DefaultNoBound)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `frame_support::DefaultNoBound` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:22:10 + | +22 | #[derive(frame_support::DefaultNoBound)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `frame_support::DefaultNoBound` (in Nightly builds, run with -Z macro-backtrace for more info) error: first default - --> tests/derive_no_bound_ui/default_too_many_attributes.rs:7:2 - | -7 | / #[default] -8 | | Bar(T::C), - | |_____________^ + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:24:2 + | +24 | / #[default] +25 | | Bar(T::C), + | |_____________^ error: additional default - --> tests/derive_no_bound_ui/default_too_many_attributes.rs:9:2 + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:26:2 | -9 | / #[default] -10 | | Baz, +26 | / #[default] +27 | | Baz, | |_______^ diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.rs index 5822cda1aa6..74e4b61df72 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[derive(frame_support::DefaultNoBound)] union Foo { field1: u32, diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.stderr index 1e01e1baaf8..177fcce7fe1 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/default_union.stderr @@ -1,5 +1,5 @@ error: Union type not supported by `derive(DefaultNoBound)` - --> tests/derive_no_bound_ui/default_union.rs:2:1 - | -2 | union Foo { - | ^^^^^ + --> tests/derive_no_bound_ui/default_union.rs:19:1 + | +19 | union Foo { + | ^^^^^ diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/eq.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/eq.rs index a4845262636..12636c94e69 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/eq.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/eq.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/eq.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/eq.stderr index eb3345eede5..c8430210e82 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/eq.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/eq.stderr @@ -1,12 +1,12 @@ error[E0277]: can't compare `Foo` with `Foo` - --> tests/derive_no_bound_ui/eq.rs:6:8 - | -6 | struct Foo { - | ^^^^^^^^^^^^^^ no implementation for `Foo == Foo` - | - = help: the trait `PartialEq` is not implemented for `Foo` + --> tests/derive_no_bound_ui/eq.rs:23:8 + | +23 | struct Foo { + | ^^^^^^^^^^^^^^ no implementation for `Foo == Foo` + | + = help: the trait `PartialEq` is not implemented for `Foo` note: required by a bound in `std::cmp::Eq` - --> $RUST/core/src/cmp.rs - | - | pub trait Eq: PartialEq { - | ^^^^^^^^^^^^^^^ required by this bound in `Eq` + --> $RUST/core/src/cmp.rs + | + | pub trait Eq: PartialEq { + | ^^^^^^^^^^^^^^^ required by this bound in `Eq` diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.rs b/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.rs index 7bd6b7ef6a2..23a910a24ea 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.rs +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + trait Config { type C; } diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr index 1c230db376a..b46df2369b4 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr @@ -1,5 +1,5 @@ error[E0369]: binary operation `==` cannot be applied to type `::C` - --> tests/derive_no_bound_ui/partial_eq.rs:7:2 - | -7 | c: T::C, - | ^ + --> tests/derive_no_bound_ui/partial_eq.rs:24:2 + | +24 | c: T::C, + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.rs b/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.rs index 5173d983bbd..fb3d1a74247 100644 --- a/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.rs +++ b/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet [foo]] mod foo { } diff --git a/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.stderr b/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.stderr index 9eac5de35db..1a54d76c97d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/attr_non_empty.stderr @@ -1,5 +1,5 @@ error: Invalid pallet macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::pallet]` or `#[pallet]`, or must specify the `dev_mode` attribute, such as `#[frame_support::pallet(dev_mode)]` or #[pallet(dev_mode)]. - --> tests/pallet_ui/attr_non_empty.rs:1:26 - | -1 | #[frame_support::pallet [foo]] - | ^^^ + --> tests/pallet_ui/attr_non_empty.rs:18:26 + | +18 | #[frame_support::pallet [foo]] + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs index 4f18f728181..06a11115017 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; 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 d10bf135901..c86930f8a64 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 @@ -4,17 +4,17 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_argument_invalid_bound.rs:19:20 + --> tests/pallet_ui/call_argument_invalid_bound.rs:36:20 | -19 | #[pallet::weight(0)] +36 | #[pallet::weight(0)] | ^ | = note: `-D deprecated` implied by `-D warnings` error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` @@ -22,13 +22,13 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs index 20568908e72..3ce76180081 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; 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 7173cdcd473..1b04f44c78f 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 @@ -4,17 +4,17 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:19:20 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:36:20 | -19 | #[pallet::weight(0)] +36 | #[pallet::weight(0)] | ^ | = note: `-D deprecated` implied by `-D warnings` error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` @@ -22,32 +22,32 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 | -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 | -1 | #[frame_support::pallet] +18 | #[frame_support::pallet] | ------------------------ required by a bound introduced by this call ... -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | = note: required for `::Bar` to implement `Encode` error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:34:12 | -17 | #[pallet::call] +34 | #[pallet::call] | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | = note: required for `::Bar` to implement `Decode` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs index 64b6642b0a8..22507b196e4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use codec::{Decode, Encode}; 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 4cbed370962..7429bce050c 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 @@ -4,17 +4,17 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_argument_invalid_bound_3.rs:21:20 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:38:20 | -21 | #[pallet::weight(0)] +38 | #[pallet::weight(0)] | ^ | = note: `-D deprecated` implied by `-D warnings` error[E0277]: `Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound_3.rs:23:36 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:40:36 | -23 | pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { +40 | pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { | ^^^^ `Bar` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Bar` @@ -23,6 +23,6 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = note: required for the cast from `&Bar` to the object type `dyn std::fmt::Debug` help: consider annotating `Bar` with `#[derive(Debug)]` | -17 + #[derive(Debug)] -18 | struct Bar; +34 + #[derive(Debug)] +35 | struct Bar; | diff --git a/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs b/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs index 395766c7cd3..061f551e54c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResultWithPostInfo; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr b/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr index 5d0c90609c2..99970f3094e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr @@ -1,11 +1,11 @@ error: Call indices are conflicting: Both functions foo and bar are at index 10 - --> tests/pallet_ui/call_conflicting_indices.rs:15:10 + --> tests/pallet_ui/call_conflicting_indices.rs:32:10 | -15 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} +32 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} | ^^^ error: Call indices are conflicting: Both functions foo and bar are at index 10 - --> tests/pallet_ui/call_conflicting_indices.rs:19:10 + --> tests/pallet_ui/call_conflicting_indices.rs:36:10 | -19 | pub fn bar(origin: OriginFor) -> DispatchResultWithPostInfo {} +36 | pub fn bar(origin: OriginFor) -> DispatchResultWithPostInfo {} | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs b/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs index abe4dc199bf..6e45aba406a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResultWithPostInfo; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr b/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr index 2f4cead6cf7..9ee626f2fcc 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr @@ -1,5 +1,5 @@ error: Number literal must not have a suffix - --> tests/pallet_ui/call_index_has_suffix.rs:14:30 + --> tests/pallet_ui/call_index_has_suffix.rs:31:30 | -14 | #[pallet::call_index(0something)] +31 | #[pallet::call_index(0something)] | ^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.rs index 118d3c92f36..059bea886eb 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResultWithPostInfo; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr index 3f680203a26..eec5e33ccbd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr @@ -1,5 +1,5 @@ error: expected `weight` or `call_index` - --> tests/pallet_ui/call_invalid_attr.rs:14:13 + --> tests/pallet_ui/call_invalid_attr.rs:31:13 | -14 | #[pallet::weird_attr] +31 | #[pallet::weird_attr] | ^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.rs index 1a28bc32e65..78de6a433b9 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.stderr index 0acb3e864a5..152a1bdc83b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_const.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, only method accepted - --> $DIR/call_invalid_const.rs:17:3 + --> tests/pallet_ui/call_invalid_const.rs:34:3 | -17 | const Foo: u8 = 3u8; +34 | const Foo: u8 = 3u8; | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.rs index 0b40691ca43..64d1eac20d4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResultWithPostInfo; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.stderr index 1e07a4974bf..78656db0ebd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_index.stderr @@ -1,5 +1,5 @@ error: number too large to fit in target type - --> tests/pallet_ui/call_invalid_index.rs:15:24 + --> tests/pallet_ui/call_invalid_index.rs:32:24 | -15 | #[pallet::call_index(256)] +32 | #[pallet::call_index(256)] | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.rs index 2502506fa6a..ee574bbbe58 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr index f17cd9016a6..99146c0563a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr @@ -1,11 +1,11 @@ error: Invalid type: expected `OriginFor` - --> $DIR/call_invalid_origin_type.rs:17:22 + --> tests/pallet_ui/call_invalid_origin_type.rs:34:22 | -17 | pub fn foo(origin: u8) {} +34 | pub fn foo(origin: u8) {} | ^^ error: expected `OriginFor` - --> $DIR/call_invalid_origin_type.rs:17:22 + --> tests/pallet_ui/call_invalid_origin_type.rs:34:22 | -17 | pub fn foo(origin: u8) {} +34 | pub fn foo(origin: u8) {} | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.rs index 1ccdff5d073..5cce3f5a6da 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.stderr index 8803bbba013..4752a1be55e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_return.stderr @@ -1,5 +1,5 @@ error: expected `DispatchResultWithPostInfo` or `DispatchResult` - --> tests/pallet_ui/call_invalid_return.rs:17:39 + --> tests/pallet_ui/call_invalid_return.rs:34:39 | -17 | pub fn foo(origin: OriginFor) -> ::DispatchResult { todo!() } +34 | pub fn foo(origin: OriginFor) -> ::DispatchResult { todo!() } | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.rs index fe1c5aee453..0f153e47e08 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.stderr index 321828a1ae2..eaac9a44df8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, dispatchable function must be public: `pub fn` - --> $DIR/call_invalid_vis.rs:20:3 + --> tests/pallet_ui/call_invalid_vis.rs:37:3 | -20 | fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { +37 | fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.rs b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.rs index fb25e9876dc..9f36083ee63 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.stderr index 7d3113474af..24bb848a478 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_vis_2.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, dispatchable function must be public: `pub fn` - --> $DIR/call_invalid_vis_2.rs:20:3 + --> tests/pallet_ui/call_invalid_vis_2.rs:37:3 | -20 | pub(crate) fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { +37 | pub(crate) fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.rs b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.rs index 98c49f493e5..a0c5c6ce4d1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResult; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr index 82dbe1d24c2..4d55ef79856 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr @@ -5,9 +5,9 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: For more info see: - --> tests/pallet_ui/call_missing_index.rs:15:10 + --> tests/pallet_ui/call_missing_index.rs:32:10 | -15 | pub fn foo(_: OriginFor) -> DispatchResult { +32 | pub fn foo(_: OriginFor) -> DispatchResult { | ^^^ | = note: `-D deprecated` implied by `-D warnings` @@ -19,9 +19,9 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_1::_w`: For more info see: - --> tests/pallet_ui/call_missing_index.rs:20:10 + --> tests/pallet_ui/call_missing_index.rs:37:10 | -20 | pub fn bar(_: OriginFor) -> DispatchResult { +37 | pub fn bar(_: OriginFor) -> DispatchResult { | ^^^ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: @@ -30,9 +30,9 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_missing_index.rs:14:20 + --> tests/pallet_ui/call_missing_index.rs:31:20 | -14 | #[pallet::weight(0)] +31 | #[pallet::weight(0)] | ^ error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: @@ -41,7 +41,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: For more info see: - --> tests/pallet_ui/call_missing_index.rs:19:20 + --> tests/pallet_ui/call_missing_index.rs:36:20 | -19 | #[pallet::weight(0)] +36 | #[pallet::weight(0)] | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.rs b/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.rs index 4cdb85502b5..9845bc012dc 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.stderr b/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.stderr index 0a6cf16571f..555dd426fe2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_missing_weight.stderr @@ -1,7 +1,7 @@ error: A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an inherited weight from the `#[pallet:call(weight($type))]` attribute, but none were given. - --> tests/pallet_ui/call_missing_weight.rs:17:7 + --> tests/pallet_ui/call_missing_weight.rs:34:7 | -17 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} +34 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs b/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs index 5753ecd076c..f2b068e0765 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResultWithPostInfo; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr b/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr index ba22b012745..14af3c7995d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, too many call_index attributes given - --> tests/pallet_ui/call_multiple_call_index.rs:17:7 + --> tests/pallet_ui/call_multiple_call_index.rs:34:7 | -17 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} +34 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_no_origin.rs b/substrate/frame/support/test/tests/pallet_ui/call_no_origin.rs index 231c75f43f4..a0c18b87383 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_no_origin.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_no_origin.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_no_origin.stderr b/substrate/frame/support/test/tests/pallet_ui/call_no_origin.stderr index 97574ea1b64..d7aa4ea763f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_no_origin.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_no_origin.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, must have at least origin arg - --> $DIR/call_no_origin.rs:17:7 + --> tests/pallet_ui/call_no_origin.rs:34:7 | -17 | pub fn foo() {} +34 | pub fn foo() {} | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_no_return.rs b/substrate/frame/support/test/tests/pallet_ui/call_no_return.rs index 68a883c52c0..87b47c8b4d8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_no_return.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_no_return.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_no_return.stderr b/substrate/frame/support/test/tests/pallet_ui/call_no_return.stderr index 18ebbaff76d..e73b4c28e49 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_no_return.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_no_return.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::call, require return type DispatchResultWithPostInfo - --> $DIR/call_no_return.rs:17:7 + --> tests/pallet_ui/call_no_return.rs:34:7 | -17 | pub fn foo(origin: OriginFor) {} +34 | pub fn foo(origin: OriginFor) {} | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs index c122877e8a0..8584b5f0aac 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResult; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr index 0651f003b9e..cf23a76f8ea 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr @@ -1,7 +1,7 @@ error: invalid suffix `something` for number literal - --> tests/pallet_ui/call_weight_argument_has_suffix.rs:15:26 + --> tests/pallet_ui/call_weight_argument_has_suffix.rs:32:26 | -15 | #[pallet::weight(10_000something)] +32 | #[pallet::weight(10_000something)] | ^^^^^^^^^^^^^^^ invalid suffix `something` | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) @@ -12,9 +12,9 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_weight_argument_has_suffix.rs:15:26 + --> tests/pallet_ui/call_weight_argument_has_suffix.rs:32:26 | -15 | #[pallet::weight(10_000something)] +32 | #[pallet::weight(10_000something)] | ^^^^^^^^^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs index 2e5dc2a649e..e371c423ea4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResult; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr index b04c3ec395c..ccd5a935773 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr @@ -4,9 +4,9 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_weight_const_warning.rs:15:26 + --> tests/pallet_ui/call_weight_const_warning.rs:32:26 | -15 | #[pallet::weight(123_u64)] +32 | #[pallet::weight(123_u64)] | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs index 798911dba33..bb880eabcd3 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::DispatchResult; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr index c6567902075..aadb939b645 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr @@ -1,7 +1,7 @@ error: invalid suffix `custom_prefix` for number literal - --> tests/pallet_ui/call_weight_const_warning_twice.rs:19:26 + --> tests/pallet_ui/call_weight_const_warning_twice.rs:36:26 | -19 | #[pallet::weight(123_custom_prefix)] +36 | #[pallet::weight(123_custom_prefix)] | ^^^^^^^^^^^^^^^^^ invalid suffix `custom_prefix` | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) @@ -12,9 +12,9 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/call_weight_const_warning_twice.rs:15:26 + --> tests/pallet_ui/call_weight_const_warning_twice.rs:32:26 | -15 | #[pallet::weight(123)] +32 | #[pallet::weight(123)] | ^^^ | = note: `-D deprecated` implied by `-D warnings` @@ -25,7 +25,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: For more info see: - --> tests/pallet_ui/call_weight_const_warning_twice.rs:19:26 + --> tests/pallet_ui/call_weight_const_warning_twice.rs:36:26 | -19 | #[pallet::weight(123_custom_prefix)] +36 | #[pallet::weight(123_custom_prefix)] | ^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs index ff235e98609..f5be788ba36 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::pallet_prelude::*; pub trait WeightInfo { diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr index 7eed646e7b1..6b30716a938 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr @@ -1,11 +1,11 @@ error: expected `weight` - --> tests/pallet_ui/call_weight_inherited_invalid.rs:19:17 + --> tests/pallet_ui/call_weight_inherited_invalid.rs:36:17 | -19 | #[pallet::call(invalid)] +36 | #[pallet::call(invalid)] | ^^^^^^^ error: expected parentheses - --> tests/pallet_ui/call_weight_inherited_invalid.rs:40:17 + --> tests/pallet_ui/call_weight_inherited_invalid.rs:57:17 | -40 | #[pallet::call = invalid] +57 | #[pallet::call = invalid] | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs index 76ccf5db220..771cfb51572 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Weight is an ident instead of a type. use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr index 29f3b6bfd2b..e84b0b6f3fd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr @@ -1,11 +1,11 @@ error[E0412]: cannot find type `prefix` in this scope - --> tests/pallet_ui/call_weight_inherited_invalid2.rs:22:24 + --> tests/pallet_ui/call_weight_inherited_invalid2.rs:39:24 | -22 | #[pallet::call(weight(prefix))] +39 | #[pallet::call(weight(prefix))] | ^^^^^^ not found in this scope error[E0412]: cannot find type `prefix` in this scope - --> tests/pallet_ui/call_weight_inherited_invalid2.rs:43:26 + --> tests/pallet_ui/call_weight_inherited_invalid2.rs:60:26 | -43 | #[pallet::call(weight = prefix)] +60 | #[pallet::call(weight = prefix)] | ^^^^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs index b31bc0ae234..70e57a29184 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Call weight is an LitInt instead of a type. use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr index fab7acb90de..e8e6f2fe6df 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr @@ -1,19 +1,19 @@ error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime - --> tests/pallet_ui/call_weight_inherited_invalid3.rs:22:24 + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:39:24 | -22 | #[pallet::call(weight(123))] +39 | #[pallet::call(weight(123))] | ^^^ error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime - --> tests/pallet_ui/call_weight_inherited_invalid3.rs:43:26 + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:60:26 | -43 | #[pallet::call(weight = 123)] +60 | #[pallet::call(weight = 123)] | ^^^ error: unused import: `frame_system::pallet_prelude::*` - --> tests/pallet_ui/call_weight_inherited_invalid3.rs:4:5 - | -4 | use frame_system::pallet_prelude::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D unused-imports` implied by `-D warnings` + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:21:5 + | +21 | use frame_system::pallet_prelude::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs index 39c0929d603..c7b312b2f2e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Function does not exist in the trait. use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr index fbde5c691c5..b4c0885507c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr @@ -1,11 +1,11 @@ error[E0599]: no function or associated item named `foo` found for associated type `::WeightInfo` in the current scope - --> tests/pallet_ui/call_weight_inherited_invalid4.rs:24:10 + --> tests/pallet_ui/call_weight_inherited_invalid4.rs:41:10 | -24 | pub fn foo(_: OriginFor) -> DispatchResult { +41 | pub fn foo(_: OriginFor) -> DispatchResult { | ^^^ function or associated item not found in `::WeightInfo` error[E0599]: no function or associated item named `foo` found for associated type `::WeightInfo` in the current scope - --> tests/pallet_ui/call_weight_inherited_invalid4.rs:45:10 + --> tests/pallet_ui/call_weight_inherited_invalid4.rs:62:10 | -45 | pub fn foo(_: OriginFor) -> DispatchResult { +62 | pub fn foo(_: OriginFor) -> DispatchResult { | ^^^ function or associated item not found in `::WeightInfo` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs index a5b2f5c7f6a..dc6c43fb7a2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Stray tokens after good input. #[frame_support::pallet] diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr index c0e9ef2d9e9..e12fbfcf4b4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr @@ -1,11 +1,11 @@ error: unexpected token - --> tests/pallet_ui/call_weight_inherited_invalid5.rs:14:50 + --> tests/pallet_ui/call_weight_inherited_invalid5.rs:31:50 | -14 | #[pallet::call(weight(::WeightInfo straycat))] +31 | #[pallet::call(weight(::WeightInfo straycat))] | ^^^^^^^^ error: unexpected token - --> tests/pallet_ui/call_weight_inherited_invalid5.rs:34:52 + --> tests/pallet_ui/call_weight_inherited_invalid5.rs:51:52 | -34 | #[pallet::call(weight = ::WeightInfo straycat)] +51 | #[pallet::call(weight = ::WeightInfo straycat)] | ^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs index e417c619fc4..840a6dee20c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs +++ b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr index e75aa522615..1b48197cc9e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `!=` cannot be applied to type `NoStorageVersionSet` - --> tests/pallet_ui/compare_unset_storage_version.rs:15:39 + --> tests/pallet_ui/compare_unset_storage_version.rs:32:39 | -15 | if Self::current_storage_version() != Self::on_chain_storage_version() { +32 | if Self::current_storage_version() != Self::on_chain_storage_version() { | ------------------------------- ^^ -------------------------------- StorageVersion | | | NoStorageVersionSet diff --git a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs index 74692ee94ef..ca755ff9c2b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs +++ b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr index 902e8923759..cdc8f623142 100644 --- a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr @@ -1,5 +1,5 @@ error: expected one of: `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` - --> tests/pallet_ui/composite_enum_unsupported_identifier.rs:10:11 + --> tests/pallet_ui/composite_enum_unsupported_identifier.rs:27:11 | -10 | pub enum HoldReasons {} +27 | pub enum HoldReasons {} | ^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.rs b/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.rs index 026b74c914a..aeee038fb0d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.rs +++ b/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.stderr b/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.stderr index 17d81811356..a86fd96ea28 100644 --- a/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/default_config_with_no_default_in_system.stderr @@ -1,5 +1,5 @@ error[E0220]: associated type `Block` not found for `Self` - --> tests/pallet_ui/default_config_with_no_default_in_system.rs:8:31 - | -8 | type MyGetParam2: Get; - | ^^^^^ there is a similarly named associated type `Block` in the trait `frame_system::Config` + --> tests/pallet_ui/default_config_with_no_default_in_system.rs:25:31 + | +25 | type MyGetParam2: Get; + | ^^^^^ there is a similarly named associated type `Block` in the trait `frame_system::Config` diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs index 0799a3fce8d..72ad7896dfe 100644 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr index 5d2734b4db6..942db0ab469 100644 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr @@ -1,9 +1,9 @@ error: use of deprecated struct `pallet::_::Store`: Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/deprecated_store_attr.rs:7:3 - | -7 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D deprecated` implied by `-D warnings` + --> tests/pallet_ui/deprecated_store_attr.rs:24:3 + | +24 | #[pallet::generate_store(trait Store)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs index 2a413eea9b4..b75b9729d0e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] #[frame_support::pallet] diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr index 1e2011b2a30..5aea7d83a61 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr @@ -1,7 +1,7 @@ error: A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an inherited weight from the `#[pallet:call(weight($type))]` attribute, but none were given. - --> tests/pallet_ui/dev_mode_without_arg.rs:22:7 + --> tests/pallet_ui/dev_mode_without_arg.rs:39:7 | -22 | pub fn my_call(_origin: OriginFor) -> DispatchResult { +39 | pub fn my_call(_origin: OriginFor) -> DispatchResult { | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.rs b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.rs index 1920b6799de..06c657f2e35 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.rs +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr index b75edff1ab5..bcfe43d008f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr @@ -5,9 +5,9 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: For more info see: - --> tests/pallet_ui/dev_mode_without_arg_call_index.rs:22:10 + --> tests/pallet_ui/dev_mode_without_arg_call_index.rs:39:10 | -22 | pub fn my_call(_origin: OriginFor) -> DispatchResult { +39 | pub fn my_call(_origin: OriginFor) -> DispatchResult { | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` @@ -18,7 +18,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/dev_mode_without_arg_call_index.rs:21:20 + --> tests/pallet_ui/dev_mode_without_arg_call_index.rs:38:20 | -21 | #[pallet::weight(0)] +38 | #[pallet::weight(0)] | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs index fb113947956..60945cabc47 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr index e0dbc8c953b..81d0257ca6c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr @@ -1,11 +1,11 @@ error: `_` can only be used in dev_mode. Please specify an appropriate hasher. - --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:21:47 + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:38:47 | -21 | type MyStorageMap = StorageMap<_, _, u32, u64>; +38 | type MyStorageMap = StorageMap<_, _, u32, u64>; | ^ error[E0432]: unresolved import `pallet` - --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:3:9 - | -3 | pub use pallet::*; - | ^^^^^^ help: a similar path exists: `test_pallet::pallet` + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:20:9 + | +20 | pub use pallet::*; + | ^^^^^^ help: a similar path exists: `test_pallet::pallet` diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs index f6efcc3fc3d..092e06b08e3 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; 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 cf502ac5be4..74ee0e4aeba 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 @@ -5,9 +5,9 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: For more info see: - --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:25:10 + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:42:10 | -25 | pub fn my_call(_origin: OriginFor) -> DispatchResult { +42 | pub fn my_call(_origin: OriginFor) -> DispatchResult { | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` @@ -18,15 +18,15 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: For more info see: - --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:24:20 + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:41:20 | -24 | #[pallet::weight(0)] +41 | #[pallet::weight(0)] | ^ error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:11:12 + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:28:12 | -11 | #[pallet::pallet] +28 | #[pallet::pallet] | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Vec` | = help: the following other types implement trait `MaxEncodedLen`: diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs b/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs index 6d781a19e67..76a64842105 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr index 2b03f410243..fcaa576f8c5 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr @@ -1,5 +1,5 @@ error: Invalid duplicated attribute - --> $DIR/duplicate_call_attr.rs:22:12 + --> tests/pallet_ui/duplicate_call_attr.rs:39:12 | -22 | #[pallet::call] +39 | #[pallet::call] | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs b/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs index 543c15bd069..d649ae300b4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr b/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr index 75297dc5a7f..1e046d85f7b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr @@ -1,47 +1,47 @@ error: Duplicate storage prefixes found for `Foo` - --> $DIR/duplicate_storage_prefix.rs:15:29 + --> tests/pallet_ui/duplicate_storage_prefix.rs:32:29 | -15 | #[pallet::storage_prefix = "Foo"] +32 | #[pallet::storage_prefix = "Foo"] | ^^^^^ error: Duplicate storage prefixes found for `Foo` - --> $DIR/duplicate_storage_prefix.rs:12:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:29:7 | -12 | type Foo = StorageValue<_, u8>; +29 | type Foo = StorageValue<_, u8>; | ^^^ error: Duplicate storage prefixes found for `CounterForBar`, used for counter associated to counted storage map - --> $DIR/duplicate_storage_prefix.rs:22:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:39:7 | -22 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; +39 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; | ^^^ error: Duplicate storage prefixes found for `CounterForBar` - --> $DIR/duplicate_storage_prefix.rs:19:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:36:7 | -19 | type CounterForBar = StorageValue<_, u16>; +36 | type CounterForBar = StorageValue<_, u16>; | ^^^^^^^^^^^^^ error[E0412]: cannot find type `_GeneratedPrefixForStorageFoo` in this scope - --> $DIR/duplicate_storage_prefix.rs:12:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:29:7 | -12 | type Foo = StorageValue<_, u8>; +29 | type Foo = StorageValue<_, u8>; | ^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageNotFoo` in this scope - --> $DIR/duplicate_storage_prefix.rs:16:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:33:7 | -16 | type NotFoo = StorageValue<_, u16>; +33 | type NotFoo = StorageValue<_, u16>; | ^^^^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageCounterForBar` in this scope - --> $DIR/duplicate_storage_prefix.rs:19:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:36:7 | -19 | type CounterForBar = StorageValue<_, u16>; +36 | type CounterForBar = StorageValue<_, u16>; | ^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageBar` in this scope - --> $DIR/duplicate_storage_prefix.rs:22:7 + --> tests/pallet_ui/duplicate_storage_prefix.rs:39:7 | -22 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; +39 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; | ^^^ not found in this scope diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs index ab318034aca..334fd8a46af 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr index 1c13ee17eb7..864b399326e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr @@ -1,5 +1,5 @@ error: Unexpected duplicated attribute - --> tests/pallet_ui/duplicate_store_attr.rs:12:3 + --> tests/pallet_ui/duplicate_store_attr.rs:29:3 | -12 | #[pallet::generate_store(trait Store)] +29 | #[pallet::generate_store(trait Store)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs index 254d6586677..2e92f5358ea 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs +++ b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] 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 7edb55a62d4..cfa0d465990 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 @@ -1,17 +1,17 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied - --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:1:1 - | -1 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ 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) - and 36 others - = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ 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) + 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/error_where_clause.rs b/substrate/frame/support/test/tests/pallet_ui/error_where_clause.rs index 29d7435bc4b..32e74b940a2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_where_clause.rs +++ b/substrate/frame/support/test/tests/pallet_ui/error_where_clause.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/error_where_clause.stderr b/substrate/frame/support/test/tests/pallet_ui/error_where_clause.stderr index 8e9d0e60692..f9bcb61786b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_where_clause.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_where_clause.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::error, where clause is not allowed on pallet error item - --> $DIR/error_where_clause.rs:19:20 + --> tests/pallet_ui/error_where_clause.rs:36:20 | -19 | pub enum Error where u32: From {} +36 | pub enum Error where u32: From {} | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.rs b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.rs index 50e66dc8c0d..fce7267224d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.stderr b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.stderr index 8c0496782fb..cbaac7b5d4f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::error, expected item enum - --> $DIR/error_wrong_item.rs:19:2 + --> tests/pallet_ui/error_wrong_item.rs:36:2 | -19 | pub struct Foo; +36 | pub struct Foo; | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.rs b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.rs index 14107fafb06..ba4d43955af 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.rs +++ b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.stderr b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.stderr index d7e54ad8a75..784ae4631af 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_wrong_item_name.stderr @@ -1,5 +1,5 @@ error: expected `Error` - --> $DIR/error_wrong_item_name.rs:19:11 + --> tests/pallet_ui/error_wrong_item_name.rs:36:11 | -19 | pub enum Foo {} +36 | pub enum Foo {} | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.rs b/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.rs index 2b45a971788..a7e6d213318 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, IsType}; 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 1161f4a1902..4df6deafa0d 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 @@ -1,19 +1,19 @@ error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:40:7 | -23 | B { b: T::Bar }, +40 | B { b: T::Bar }, | ^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> tests/pallet_ui/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:40:7 | -23 | B { b: T::Bar }, +40 | B { b: T::Bar }, | ^ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:40:7 | -23 | B { b: T::Bar }, +40 | B { b: T::Bar }, | ^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` diff --git a/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.rs b/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.rs index 94151ba4c3d..405faeb6de0 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr b/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr index 2eda72eb5f7..eef17ffab4f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr @@ -1,7 +1,7 @@ error: Invalid usage of RuntimeEvent, `Config` contains no associated type `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). An RuntimeEvent associated type must be declare on trait `Config`. - --> $DIR/event_not_in_trait.rs:1:1 - | -1 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/pallet_ui/event_not_in_trait.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs index a02cc9b9de8..665d2a984cf 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 @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr index d54149d719a..e9e4c1269f2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr @@ -1,5 +1,5 @@ error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` - --> $DIR/event_type_invalid_bound.rs:9:3 - | -9 | type RuntimeEvent; - | ^^^^ + --> tests/pallet_ui/event_type_invalid_bound.rs:26:3 + | +26 | type RuntimeEvent; + | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs index 99df89d6727..23d5a3b449e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, IsType}; diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr index ea8b2ff000c..436a8651bb8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr @@ -1,5 +1,5 @@ error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `From` or `From>` or `From>` - --> $DIR/event_type_invalid_bound_2.rs:9:3 - | -9 | type RuntimeEvent: IsType<::RuntimeEvent>; - | ^^^^ + --> tests/pallet_ui/event_type_invalid_bound_2.rs:26:3 + | +26 | type RuntimeEvent: IsType<::RuntimeEvent>; + | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.rs b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.rs index d6690557c39..4b4654cf590 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.stderr b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.stderr index 0ef150dfd62..155391f11ed 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::event, expected enum item - --> $DIR/event_wrong_item.rs:19:2 + --> tests/pallet_ui/event_wrong_item.rs:36:2 | -19 | pub struct Foo; +36 | pub struct Foo; | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.rs b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.rs index d828965c517..3588760c3bf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.stderr b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.stderr index 14e8615c561..b70e560e69a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_wrong_item_name.stderr @@ -1,5 +1,5 @@ error: expected `Event` - --> $DIR/event_wrong_item_name.rs:19:11 + --> tests/pallet_ui/event_wrong_item_name.rs:36:11 | -19 | pub enum Foo {} +36 | pub enum Foo {} | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.rs b/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.rs index 9ae851005ac..b55620329a6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.rs +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.stderr b/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.stderr index 9afc1037a48..d515547ec3a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_inconsistent_build_config.stderr @@ -1,5 +1,5 @@ error: `#[pallet::genesis_config]` and `#[pallet::genesis_build]` attributes must be either both used or both not used, instead genesis_config is unused and genesis_build is used - --> $DIR/genesis_inconsistent_build_config.rs:2:1 - | -2 | mod pallet { - | ^^^ + --> tests/pallet_ui/genesis_inconsistent_build_config.rs:19:1 + | +19 | mod pallet { + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.rs b/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.rs index f1eae16f496..b65216f1e6b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.rs +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; 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 f57b4a61c80..e3dd0b7aa1d 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,13 +1,13 @@ error: Invalid genesis builder: expected `GenesisBuild` or `GenesisBuild` - --> $DIR/genesis_invalid_generic.rs:19:7 + --> tests/pallet_ui/genesis_invalid_generic.rs:36:7 | -19 | impl GenesisBuild for GenesisConfig {} +36 | impl GenesisBuild for GenesisConfig {} | ^^^^^^^^^^^^ error: expected `<` - --> $DIR/genesis_invalid_generic.rs:1:1 - | -1 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/pallet_ui/genesis_invalid_generic.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.rs b/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.rs index 5e8b297ba4c..d04465321f5 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.rs +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.stderr b/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.stderr index dd2e65588f5..4d1c09ec5ed 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_wrong_name.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::genesis_build, expected impl<..> GenesisBuild<..> for GenesisConfig<..> - --> $DIR/genesis_wrong_name.rs:19:2 + --> tests/pallet_ui/genesis_wrong_name.rs:36:2 | -19 | impl Foo {} +36 | impl Foo {} | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs b/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs index 8008c465e61..45ec8f334f2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs +++ b/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr b/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr index 7d86b8d4f1b..45351f36879 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::composite_enum, expected enum item - --> tests/pallet_ui/hold_reason_non_enum.rs:10:2 + --> tests/pallet_ui/hold_reason_non_enum.rs:27:2 | -10 | pub struct HoldReason; +27 | pub struct HoldReason; | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs b/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs index 626dad74113..5c6e7415436 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs +++ b/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr b/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr index e8b0c14e967..75834ad8b89 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::composite_enum, `HoldReason` must be public - --> tests/pallet_ui/hold_reason_not_pub.rs:10:5 + --> tests/pallet_ui/hold_reason_not_pub.rs:27:5 | -10 | enum HoldReason {} +27 | enum HoldReason {} | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.rs b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.rs index 7c66b3e6cec..2b317b4b325 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index d0af35197f1..b7327943ee2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -1,7 +1,7 @@ error[E0107]: missing generics for trait `Hooks` - --> tests/pallet_ui/hooks_invalid_item.rs:12:18 + --> tests/pallet_ui/hooks_invalid_item.rs:29:18 | -12 | impl Hooks for Pallet {} +29 | impl Hooks for Pallet {} | ^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `BlockNumber` @@ -11,5 +11,5 @@ note: trait defined here, with 1 generic parameter: `BlockNumber` | ^^^^^ ----------- help: add missing generic argument | -12 | impl Hooks for Pallet {} +29 | impl Hooks for Pallet {} | +++++++++++++ diff --git a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.rs b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.rs index 00b57a01235..4dc3e9bc745 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.rs +++ b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.stderr b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.stderr index 06c7941a0bc..89f0be401ab 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_1.stderr @@ -1,29 +1,29 @@ error: Invalid generic declaration, trait is defined with instance but generic use none - --> $DIR/inconsistent_instance_1.rs:10:20 + --> tests/pallet_ui/inconsistent_instance_1.rs:27:20 | -10 | pub struct Pallet(core::marker::PhantomData); +27 | pub struct Pallet(core::marker::PhantomData); | ^ error: Invalid generic declaration, trait is defined with instance but generic use none - --> $DIR/inconsistent_instance_1.rs:16:7 + --> tests/pallet_ui/inconsistent_instance_1.rs:33:7 | -16 | impl Pallet {} +33 | impl Pallet {} | ^ error: Invalid generic declaration, trait is defined with instance but generic use none - --> $DIR/inconsistent_instance_1.rs:16:18 + --> tests/pallet_ui/inconsistent_instance_1.rs:33:18 | -16 | impl Pallet {} +33 | impl Pallet {} | ^^^^^^ error: Invalid generic declaration, trait is defined with instance but generic use none - --> $DIR/inconsistent_instance_1.rs:13:47 + --> tests/pallet_ui/inconsistent_instance_1.rs:30:47 | -13 | impl Hooks> for Pallet {} +30 | impl Hooks> for Pallet {} | ^^^^^^ error: Invalid generic declaration, trait is defined with instance but generic use none - --> $DIR/inconsistent_instance_1.rs:13:7 + --> tests/pallet_ui/inconsistent_instance_1.rs:30:7 | -13 | impl Hooks> for Pallet {} +30 | impl Hooks> for Pallet {} | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.rs b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.rs index e7b51cb5ebe..e05ff6cd5ed 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.stderr b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.stderr index 9d61f2976b7..703f5396b8a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/inconsistent_instance_2.stderr @@ -1,29 +1,29 @@ error: Invalid generic declaration, trait is defined without instance but generic use some - --> $DIR/inconsistent_instance_2.rs:10:20 + --> tests/pallet_ui/inconsistent_instance_2.rs:27:20 | -10 | pub struct Pallet(core::marker::PhantomData<(T, I)>); +27 | pub struct Pallet(core::marker::PhantomData<(T, I)>); | ^ error: Invalid generic declaration, trait is defined without instance but generic use some - --> $DIR/inconsistent_instance_2.rs:16:7 + --> tests/pallet_ui/inconsistent_instance_2.rs:33:7 | -16 | impl, I: 'static> Pallet {} +33 | impl, I: 'static> Pallet {} | ^ error: Invalid generic declaration, trait is defined without instance but generic use some - --> $DIR/inconsistent_instance_2.rs:16:33 + --> tests/pallet_ui/inconsistent_instance_2.rs:33:33 | -16 | impl, I: 'static> Pallet {} +33 | impl, I: 'static> Pallet {} | ^^^^^^ error: Invalid generic declaration, trait is defined without instance but generic use some - --> $DIR/inconsistent_instance_2.rs:13:62 + --> tests/pallet_ui/inconsistent_instance_2.rs:30:62 | -13 | impl, I: 'static> Hooks> for Pallet {} +30 | impl, I: 'static> Hooks> for Pallet {} | ^^^^^^ error: Invalid generic declaration, trait is defined without instance but generic use some - --> $DIR/inconsistent_instance_2.rs:13:7 + --> tests/pallet_ui/inconsistent_instance_2.rs:30:7 | -13 | impl, I: 'static> Hooks> for Pallet {} +30 | impl, I: 'static> Hooks> for Pallet {} | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.rs b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.rs index 9704a7e1a44..1bb92eaf9e8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.rs +++ b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, ProvideInherent}; 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 bc34c55241a..3a26d1c0495 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 @@ -1,7 +1,7 @@ error[E0046]: not all trait items implemented, missing: `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`, `is_inherent` - --> $DIR/inherent_check_inner_span.rs:19:2 + --> tests/pallet_ui/inherent_check_inner_span.rs:36:2 | -19 | impl ProvideInherent for Pallet {} +36 | impl ProvideInherent for Pallet {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`, `is_inherent` in implementation | = help: implement the missing item: `type Call = Type;` diff --git a/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.rs b/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.rs index 97eda447213..f497ddeb6f0 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.stderr index b62b1234bde..efafdf8c4f1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/inherent_invalid_item.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::inherent, expected impl<..> ProvideInherent for Pallet<..> - --> $DIR/inherent_invalid_item.rs:19:2 + --> tests/pallet_ui/inherent_invalid_item.rs:36:2 | -19 | impl Foo {} +36 | impl Foo {} | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs b/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs index 70418efc414..f350b37a499 100644 --- a/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs +++ b/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr b/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr index 1b7097d0a10..d298afa341b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr @@ -1,5 +1,5 @@ error: Invalid duplicated `LockId` definition - --> tests/pallet_ui/lock_id_duplicate.rs:13:14 + --> tests/pallet_ui/lock_id_duplicate.rs:30:14 | -13 | pub enum LockId {} +30 | pub enum LockId {} | ^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.rs b/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.rs index c74c7f5ef2a..abe356edd5f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.rs +++ b/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod foo; diff --git a/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.stderr b/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.stderr index 9ad93939d8c..b9ce5789fd4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/mod_not_inlined.stderr @@ -1,13 +1,13 @@ error[E0658]: non-inline modules in proc macro input are unstable - --> $DIR/mod_not_inlined.rs:2:1 - | -2 | mod foo; - | ^^^^^^^^ - | - = note: see issue #54727 for more information + --> tests/pallet_ui/mod_not_inlined.rs:19:1 + | +19 | mod foo; + | ^^^^^^^^ + | + = note: see issue #54727 for more information error: Invalid pallet definition, expected mod to be inlined. - --> $DIR/mod_not_inlined.rs:2:1 - | -2 | mod foo; - | ^^^ + --> tests/pallet_ui/mod_not_inlined.rs:19:1 + | +19 | mod foo; + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.rs b/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.rs index 123d7914174..5892940a4cd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.rs +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.stderr b/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.stderr index cbed14bca2c..6e2bc2a7409 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_bounds_but_missing_with_default.stderr @@ -1,5 +1,5 @@ error: `#[pallet:no_default_bounds]` can only be used if `#[pallet::config(with_default)]` has been specified - --> tests/pallet_ui/no_default_bounds_but_missing_with_default.rs:9:4 - | -9 | #[pallet::no_default_bounds] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/no_default_bounds_but_missing_with_default.rs:26:4 + | +26 | #[pallet::no_default_bounds] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs index 5ffa13c2224..292cb367d09 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr index aebde115eb8..e8df28a3046 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr @@ -1,5 +1,5 @@ error: `#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` has been specified - --> tests/pallet_ui/no_default_but_missing_with_default.rs:9:4 - | -9 | #[pallet::no_default] - | ^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/no_default_but_missing_with_default.rs:26:4 + | +26 | #[pallet::no_default] + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs b/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs index 7d8be8ec001..37ad00e0fdd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs +++ b/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.stderr b/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.stderr index 68751470a3e..6cb3ac9e945 100644 --- a/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.stderr @@ -1,11 +1,11 @@ error: Invalid pallet::storage, cannot find `Hasher` generic, required for `StorageMap`. - --> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:21:43 + --> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:38:43 | -21 | type MyStorageMap = StorageMap; +38 | type MyStorageMap = StorageMap; | ^ error[E0432]: unresolved import `pallet` - --> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:3:9 - | -3 | pub use pallet::*; - | ^^^^^^ help: a similar path exists: `test_pallet::pallet` + --> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:20:9 + | +20 | pub use pallet::*; + | ^^^^^^ help: a similar path exists: `test_pallet::pallet` diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs index 32df5d61836..f2fe8de464b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] // Must receive a string literal pointing to a path #[pallet_doc(X)] diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr index 9a1249dd36f..a630380b594 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr @@ -1,5 +1,5 @@ error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` - --> tests/pallet_ui/pallet_doc_arg_non_path.rs:3:1 - | -3 | #[pallet_doc(X)] - | ^ + --> tests/pallet_ui/pallet_doc_arg_non_path.rs:20:1 + | +20 | #[pallet_doc(X)] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs index 6ff01e9fb44..e3a3679fb4e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] // Expected one argument for the doc path. #[pallet_doc] diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr index a220cbe9e99..0ef0ea9cc72 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr @@ -1,5 +1,5 @@ error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` - --> tests/pallet_ui/pallet_doc_empty.rs:3:1 - | -3 | #[pallet_doc] - | ^ + --> tests/pallet_ui/pallet_doc_empty.rs:20:1 + | +20 | #[pallet_doc] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs index c7d3b556a08..54c5336f789 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] // Argument expected as list, not named value. #[pallet_doc = "invalid"] diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr index bee7c708507..8a948b1b59d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr @@ -1,5 +1,5 @@ error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` - --> tests/pallet_ui/pallet_doc_invalid_arg.rs:3:1 - | -3 | #[pallet_doc = "invalid"] - | ^ + --> tests/pallet_ui/pallet_doc_invalid_arg.rs:20:1 + | +20 | #[pallet_doc = "invalid"] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs index a799879fe44..4342cdf39dd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] // Supports only one argument. #[pallet_doc("A", "B")] diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr index e769555438e..c3e05b38bbe 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr @@ -1,5 +1,5 @@ error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` - --> tests/pallet_ui/pallet_doc_multiple_args.rs:3:1 - | -3 | #[pallet_doc("A", "B")] - | ^ + --> tests/pallet_ui/pallet_doc_multiple_args.rs:20:1 + | +20 | #[pallet_doc("A", "B")] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs index 1fc42f6511c..003b2479f1c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet(foo)] pub mod pallet {} diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr index 234dc07f2ec..8736890f117 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr @@ -1,5 +1,5 @@ error: Invalid pallet macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::pallet]` or `#[pallet]`, or must specify the `dev_mode` attribute, such as `#[frame_support::pallet(dev_mode)]` or #[pallet(dev_mode)]. - --> tests/pallet_ui/pallet_invalid_arg.rs:1:25 - | -1 | #[frame_support::pallet(foo)] - | ^^^ + --> tests/pallet_ui/pallet_invalid_arg.rs:18:25 + | +18 | #[frame_support::pallet(foo)] + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.rs b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.rs index ac52e75a5f4..3d6a5c0b0a5 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr index 301a73c000f..33a2d1da786 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr @@ -1,5 +1,5 @@ error: expected one of: `generate_store`, `without_storage_info`, `storage_version` - --> tests/pallet_ui/pallet_struct_invalid_attr.rs:7:12 - | -7 | #[pallet::generate_storage_info] // invalid - | ^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/pallet_struct_invalid_attr.rs:24:12 + | +24 | #[pallet::generate_storage_info] // invalid + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/default_config.rs b/substrate/frame/support/test/tests/pallet_ui/pass/default_config.rs index 9f90ae67d57..f169ee34c9a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/default_config.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/default_config.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs index ed779da80a1..bf26cfd95b1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::traits::ConstU32; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs b/substrate/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs index 1b6f584af23..2e0df1ac398 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use codec::{Decode, Encode}; use frame_support::PalletError; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs index 355a1c978df..fdb9d8c401d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs index ae70c295d8d..208c719cdfc 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs index 567fd2e5fa0..f40d1040858 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs index 04ce49ee71e..a78c9d8f36e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs index 87659a0bab5..9ab486c718c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use frame_support::construct_runtime; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/trait_constant_valid_bounds.rs b/substrate/frame/support/test/tests/pallet_ui/pass/trait_constant_valid_bounds.rs index 71eb4f2992b..83b323e3aba 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/trait_constant_valid_bounds.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/trait_constant_valid_bounds.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs b/substrate/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs index 15fff372a1d..560ebbb8687 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { #[pallet::config] diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs index fe4682c401f..b767d6b60df 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue}; 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 bc6d98b8da8..e290b22a0ea 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 @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: @@ -14,9 +14,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -34,9 +34,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: @@ -55,9 +55,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: @@ -74,9 +74,9 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: @@ -89,9 +89,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -109,9 +109,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs index 82512a89fb1..6c53bc5dc6a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue}; 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 1c010d662d0..0e3a7c9f1cb 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 @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: @@ -14,9 +14,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -34,9 +34,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -10 | #[pallet::without_storage_info] +27 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: @@ -55,9 +55,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: @@ -74,9 +74,9 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: @@ -89,9 +89,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -109,9 +109,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -21 | #[pallet::storage] +38 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.rs b/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.rs index e451df8c78a..df7ecbcee7c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.stderr index 57f3ab78a53..9679c3fee8d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_incomplete_item.stderr @@ -1,13 +1,13 @@ error: free type alias without body - --> $DIR/storage_incomplete_item.rs:19:2 + --> tests/pallet_ui/storage_incomplete_item.rs:36:2 | -19 | type Foo; +36 | type Foo; | ^^^^^^^^- | | | help: provide a definition for the type: `= ;` error[E0433]: failed to resolve: use of undeclared crate or module `pallet` - --> $DIR/storage_incomplete_item.rs:18:4 + --> tests/pallet_ui/storage_incomplete_item.rs:35:4 | -18 | #[pallet::storage] +35 | #[pallet::storage] | ^^^^^^ use of undeclared crate or module `pallet` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs index 4d43e3a17a9..a17f85e66ac 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue}; 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 c17f9eaa032..9a31e4b6bdf 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 @@ -1,17 +1,17 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/storage_info_unsatisfied.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ 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) - and $N others - = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageInfoTrait` + --> tests/pallet_ui/storage_info_unsatisfied.rs:26:12 + | +26 | #[pallet::pallet] + | ^^^^^^ 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) + 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.rs b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs index dd10bc0723f..be0665db7b6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::{ 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 c34c796fe59..cdcd1b401f8 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 @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:12:12 + --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:29:12 | -12 | #[pallet::pallet] +29 | #[pallet::pallet] | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = help: the following other types implement trait `MaxEncodedLen`: diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.rs b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.rs index c6a88c08313..914a8d6cd4d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr index 80c6526bbf8..7f125526edf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr @@ -1,5 +1,5 @@ error: expected one of: `getter`, `storage_prefix`, `unbounded`, `whitelist_storage` - --> $DIR/storage_invalid_attribute.rs:16:12 + --> tests/pallet_ui/storage_invalid_attribute.rs:33:12 | -16 | #[pallet::generate_store(pub trait Store)] +33 | #[pallet::generate_store(pub trait Store)] | ^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.rs b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.rs index c8df93c9b32..62367d2da7e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.stderr index b37f7e57f35..0b1a7273fa8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_first_generic.stderr @@ -1,11 +1,11 @@ error: Invalid pallet::storage, for unnamed generic arguments the type first generic argument must be `_`, the argument is then replaced by macro. - --> $DIR/storage_invalid_first_generic.rs:19:29 + --> tests/pallet_ui/storage_invalid_first_generic.rs:36:29 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^ error: expected `_` - --> $DIR/storage_invalid_first_generic.rs:19:29 + --> tests/pallet_ui/storage_invalid_first_generic.rs:36:29 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.rs b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.rs index c3a08e05e2a..336d81c2541 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.stderr index 513970f98a4..e7cff8b4689 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_rename_value.stderr @@ -1,5 +1,5 @@ error: `pub` is not a valid identifier - --> $DIR/storage_invalid_rename_value.rs:13:29 + --> tests/pallet_ui/storage_invalid_rename_value.rs:30:29 | -13 | #[pallet::storage_prefix = "pub"] +30 | #[pallet::storage_prefix = "pub"] | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.rs b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.rs index 309b9b24136..54f0c1ef537 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr index 40f57f16e0d..494205c2690 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr @@ -1,5 +1,5 @@ error: Invalid attribute: Duplicate attribute - --> $DIR/storage_multiple_getters.rs:20:3 + --> tests/pallet_ui/storage_multiple_getters.rs:37:3 | -20 | #[pallet::getter(fn foo_error)] +37 | #[pallet::getter(fn foo_error)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.rs b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.rs index f3caef80a7e..e338faef5c2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr index 52cb7e85adf..60720a46a2b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr @@ -1,5 +1,5 @@ error: Invalid attribute: Duplicate attribute - --> $DIR/storage_multiple_renames.rs:20:3 + --> tests/pallet_ui/storage_multiple_renames.rs:37:3 | -20 | #[pallet::storage_prefix = "Baz"] +37 | #[pallet::storage_prefix = "Baz"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.rs b/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.rs index 03eee6fc8ec..f1eb2bed2a1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr index 3358f00151d..27dd3a1ef42 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` or `CountedStorageNMap` in order to expand metadata, found `u8`. - --> $DIR/storage_not_storage_type.rs:19:16 + --> tests/pallet_ui/storage_not_storage_type.rs:36:16 | -19 | type Foo = u8; +36 | type Foo = u8; | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs index a051cc087db..4171596ddde 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr index 9e63fd03db5..7ca7ec8bbb7 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr @@ -1,15 +1,15 @@ error[E0107]: missing generics for enum `pallet::Error` - --> tests/pallet_ui/storage_result_query_missing_generics.rs:17:56 + --> tests/pallet_ui/storage_result_query_missing_generics.rs:34:56 | -17 | type Foo = StorageValue<_, u8, ResultQuery>; +34 | type Foo = StorageValue<_, u8, ResultQuery>; | ^^^^^ expected 1 generic argument | note: enum defined here, with 1 generic parameter: `T` - --> tests/pallet_ui/storage_result_query_missing_generics.rs:12:11 + --> tests/pallet_ui/storage_result_query_missing_generics.rs:29:11 | -12 | pub enum Error { +29 | pub enum Error { | ^^^^^ - help: add missing generic argument | -17 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue>>; +34 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue>>; | +++ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs index 9e0da4b6212..a1ce60eb21c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr index 4be2a36eb89..1e27dac745d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, unexpected number of generic arguments for ResultQuery, expected 1 type argument, found 2 - --> tests/pallet_ui/storage_result_query_multiple_type_args.rs:19:56 + --> tests/pallet_ui/storage_result_query_multiple_type_args.rs:36:56 | -19 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue, SomeOtherError>>; +36 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue, SomeOtherError>>; | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs index 102a2261f83..c09d0949403 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr index 77a7972a5b5..1593c982069 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, unexpected number of path segments for the generics in ResultQuery, expected a path with at least 2 segments, found 1 - --> tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs:12:56 + --> tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs:29:56 | -12 | type Foo = StorageValue<_, u8, ResultQuery>; +29 | type Foo = StorageValue<_, u8, ResultQuery>; | ^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs index f30dc3b6a3c..1734a1b625c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr index 89ddd1599ac..926f9ad7575 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr @@ -1,5 +1,5 @@ error: expected `,` - --> tests/pallet_ui/storage_result_query_parenthesized_generics.rs:18:55 + --> tests/pallet_ui/storage_result_query_parenthesized_generics.rs:35:55 | -18 | type Foo = StorageValue<_, u8, ResultQuery(NonExistentValue)>; +35 | type Foo = StorageValue<_, u8, ResultQuery(NonExistentValue)>; | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs index a5065398b39..30d1b6b48ec 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr index 9f333ae28e6..b08af8da5a8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, unexpected generic argument kind, expected a type path to a `PalletError` enum variant, found `'static` - --> tests/pallet_ui/storage_result_query_wrong_generic_kind.rs:18:56 + --> tests/pallet_ui/storage_result_query_wrong_generic_kind.rs:35:56 | -18 | type Foo = StorageValue<_, u8, ResultQuery<'static>>; +35 | type Foo = StorageValue<_, u8, ResultQuery<'static>>; | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.rs b/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.rs index 1f076b1ecbf..01046371155 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue}; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.stderr index 3def9061fec..ab30a9e42bc 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_duplicate_named_generic.stderr @@ -1,11 +1,11 @@ error: Invalid pallet::storage, Duplicated named generic - --> $DIR/storage_value_duplicate_named_generic.rs:19:42 + --> tests/pallet_ui/storage_value_duplicate_named_generic.rs:36:42 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^^^^ error: Invalid pallet::storage, Duplicated named generic - --> $DIR/storage_value_duplicate_named_generic.rs:19:29 + --> tests/pallet_ui/storage_value_duplicate_named_generic.rs:36:29 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.rs b/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.rs index fd0ea4794bc..8e82daa6270 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue, OptionQuery}; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.stderr index 61c01943cc3..d58c0445188 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_generic_named_and_unnamed.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, invalid generic declaration for storage. Expect only type generics or binding generics, e.g. `` or ``. - --> $DIR/storage_value_generic_named_and_unnamed.rs:19:16 + --> tests/pallet_ui/storage_value_generic_named_and_unnamed.rs:36:16 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.rs b/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.rs index e62bdafaa26..60f83f3d803 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.stderr index f7449c5ffda..688d7cc5ea1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_no_generic.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, invalid number of generic generic arguments, expect more that 0 generic arguments. - --> $DIR/storage_value_no_generic.rs:19:16 + --> tests/pallet_ui/storage_value_no_generic.rs:36:16 | -19 | type Foo = StorageValue; +36 | type Foo = StorageValue; | ^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.rs b/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.rs index a3e54448e42..15383c570d1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, StorageValue}; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.stderr index f03b71ff5eb..32e12c89f1b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_value_unexpected_named_generic.stderr @@ -1,11 +1,11 @@ error: Invalid pallet::storage, Unexpected generic `P` for `StorageValue`. `StorageValue` expect generics `Value`, and optional generics `QueryKind`, `OnEmpty`. - --> $DIR/storage_value_unexpected_named_generic.rs:19:29 + --> tests/pallet_ui/storage_value_unexpected_named_generic.rs:36:29 | -19 | type Foo = StorageValue

; +36 | type Foo = StorageValue

; | ^ error: Invalid pallet::storage, cannot find `Value` generic, required for `StorageValue`. - --> $DIR/storage_value_unexpected_named_generic.rs:19:28 + --> tests/pallet_ui/storage_value_unexpected_named_generic.rs:36:28 | -19 | type Foo = StorageValue

; +36 | type Foo = StorageValue

; | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.rs b/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.rs index 56c4b86f2b3..90293497a9b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.stderr index d875d8acec6..3856d44d78e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_wrong_item.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::storage, expect item type. - --> $DIR/storage_wrong_item.rs:19:2 + --> tests/pallet_ui/storage_wrong_item.rs:36:2 | -19 | impl Foo {} +36 | impl Foo {} | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs index 3ebd1cb9fa6..55dd315fb29 100644 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs +++ b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr index a8836bc0482..20144d825e8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr @@ -1,18 +1,18 @@ error: use of deprecated struct `pallet::_::Store`: Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/store_trait_leak_private.rs:11:3 + --> tests/pallet_ui/store_trait_leak_private.rs:28:3 | -11 | #[pallet::generate_store(pub trait Store)] +28 | #[pallet::generate_store(pub trait Store)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` error[E0446]: private type `_GeneratedPrefixForStorageFoo` in public interface - --> tests/pallet_ui/store_trait_leak_private.rs:11:37 + --> tests/pallet_ui/store_trait_leak_private.rs:28:37 | -11 | #[pallet::generate_store(pub trait Store)] +28 | #[pallet::generate_store(pub trait Store)] | ^^^^^ can't leak private type ... -20 | #[pallet::storage] +37 | #[pallet::storage] | ------- `_GeneratedPrefixForStorageFoo` declared as private diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.rs b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.rs index ce599d5a31e..7702de1e39e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.stderr index 057ec6ffb2c..a9dbdd23cb4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound.stderr @@ -1,5 +1,5 @@ error: Invalid usage of `#[pallet::constant]`: `Get` trait bound not found - --> $DIR/trait_constant_invalid_bound.rs:9:3 - | -9 | type U; - | ^^^^ + --> tests/pallet_ui/trait_constant_invalid_bound.rs:26:3 + | +26 | type U; + | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.rs b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.rs index 47303f2b20a..c29259762b2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.stderr index 8d830fed8f3..7d14aad6256 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_constant_invalid_bound_lifetime.stderr @@ -1,5 +1,5 @@ error: Invalid usage of `#[pallet::constant]`: Expected a type argument - --> $DIR/trait_constant_invalid_bound_lifetime.rs:9:15 - | -9 | type U: Get<'static>; - | ^^^^^^^ + --> tests/pallet_ui/trait_constant_invalid_bound_lifetime.rs:26:15 + | +26 | type U: Get<'static>; + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.rs b/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.rs index 8537659dcd0..af8589ccf64 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr index e3409a81911..bf0000209cf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr @@ -1,5 +1,5 @@ error: Invalid #[pallet::constant] in #[pallet::config], expected type item - --> tests/pallet_ui/trait_invalid_item.rs:9:3 - | -9 | const U: u8 = 3; - | ^^^^^ + --> tests/pallet_ui/trait_invalid_item.rs:26:3 + | +26 | const U: u8 = 3; + | ^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs index 8f3d9f3f3e2..ad02fe85367 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr index 3679b67f07b..75ae829f977 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr @@ -1,5 +1,5 @@ error: Duplicate #[pallet::constant] attribute not allowed. - --> tests/pallet_ui/trait_item_duplicate_constant_attr.rs:9:4 - | -9 | #[pallet::constant] - | ^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/trait_item_duplicate_constant_attr.rs:26:4 + | +26 | #[pallet::constant] + | ^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs index d2040ec74dc..51498e663cd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::*; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr index 77a29c394d6..8162af2ea2b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr @@ -1,5 +1,5 @@ error: Duplicate #[pallet::no_default] attribute not allowed. - --> tests/pallet_ui/trait_item_duplicate_no_default.rs:10:4 + --> tests/pallet_ui/trait_item_duplicate_no_default.rs:27:4 | -10 | #[pallet::no_default] +27 | #[pallet::no_default] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.rs b/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.rs index 0fc987f7bbd..da3337a87df 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.rs +++ b/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.stderr b/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.stderr index c38f43d28eb..e18ed29daef 100644 --- a/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/trait_no_supertrait.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::trait, expected explicit `frame_system::Config` as supertrait, found none. (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]` - --> $DIR/trait_no_supertrait.rs:7:2 - | -7 | pub trait Config { - | ^^^ + --> tests/pallet_ui/trait_no_supertrait.rs:24:2 + | +24 | pub trait Config { + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.rs b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.rs index a13e1c7c5c2..90e6893bcbb 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.rs +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr index f46b89a067b..41dcd273d96 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr @@ -1,5 +1,5 @@ error[E0599]: no function or associated item named `new` found for type `u32` in the current scope - --> $DIR/type_value_error_in_block.rs:20:8 + --> tests/pallet_ui/type_value_error_in_block.rs:37:8 | -20 | u32::new() +37 | u32::new() | ^^^ function or associated item not found in `u32` diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.rs b/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.rs index b04d8b89467..20a444881d5 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.rs +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::Hooks; diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr b/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr index d955960c315..93b0caaf8d7 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr @@ -1,53 +1,53 @@ error[E0277]: the trait bound `::AccountId: From` is not satisfied - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:34 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:41:34 | -24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } +41 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^ the trait `From` is not implemented for `::AccountId` | note: required by a bound in `pallet::Config` - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:8:51 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:25:51 | -7 | pub trait Config: frame_system::Config +24 | pub trait Config: frame_system::Config | ------ required by a bound in this trait -8 | where ::AccountId: From +25 | where ::AccountId: From | ^^^^^^^^^ required by this bound in `Config` help: consider further restricting the associated type | -24 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } +41 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `::AccountId: From` is not satisfied - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:12 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:41:12 | -24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } +41 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^^^^^ the trait `From` is not implemented for `::AccountId` | note: required by a bound in `pallet::Config` - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:8:51 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:25:51 | -7 | pub trait Config: frame_system::Config +24 | pub trait Config: frame_system::Config | ------ required by a bound in this trait -8 | where ::AccountId: From +25 | where ::AccountId: From | ^^^^^^^^^ required by this bound in `Config` help: consider further restricting the associated type | -24 | #[pallet::type_value where ::AccountId: From] fn Foo() -> u32 { 3u32 } +41 | #[pallet::type_value where ::AccountId: From] fn Foo() -> u32 { 3u32 } | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `::AccountId: From` is not satisfied - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:12 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:41:12 | -24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } +41 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^^^^^ the trait `From` is not implemented for `::AccountId` | note: required by a bound in `pallet::Config` - --> tests/pallet_ui/type_value_forgotten_where_clause.rs:8:51 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:25:51 | -7 | pub trait Config: frame_system::Config +24 | pub trait Config: frame_system::Config | ------ required by a bound in this trait -8 | where ::AccountId: From +25 | where ::AccountId: From | ^^^^^^^^^ required by this bound in `Config` help: consider further restricting the associated type | -24 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } +41 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.rs b/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.rs index 1b6c975b09e..ea13c7f01d4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.rs +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, PhantomData}; diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.stderr index 5ae618df883..94fe88418e6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_invalid_item.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::type_value, expected item fn - --> $DIR/type_value_invalid_item.rs:18:24 + --> tests/pallet_ui/type_value_invalid_item.rs:35:24 | -18 | #[pallet::type_value] struct Foo; +35 | #[pallet::type_value] struct Foo; | ^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.rs b/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.rs index 82eb3b17d03..e9c24b4b8c9 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.rs +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::pallet] mod pallet { use frame_support::pallet_prelude::{Hooks, PhantomData}; diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.stderr b/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.stderr index 65ac0243f9f..58c45dfe879 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_no_return.stderr @@ -1,5 +1,5 @@ error: Invalid pallet::type_value, expected return type - --> $DIR/type_value_no_return.rs:18:24 + --> tests/pallet_ui/type_value_no_return.rs:35:24 | -18 | #[pallet::type_value] fn Foo() {} +35 | #[pallet::type_value] fn Foo() {} | ^^ diff --git a/substrate/frame/support/test/tests/split_ui/import_without_pallet.rs b/substrate/frame/support/test/tests/split_ui/import_without_pallet.rs index 874a92e4610..e62828ddf3e 100644 --- a/substrate/frame/support/test/tests/split_ui/import_without_pallet.rs +++ b/substrate/frame/support/test/tests/split_ui/import_without_pallet.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_macros::*; diff --git a/substrate/frame/support/test/tests/split_ui/import_without_pallet.stderr b/substrate/frame/support/test/tests/split_ui/import_without_pallet.stderr index 0d7b5414b10..4db71c59050 100644 --- a/substrate/frame/support/test/tests/split_ui/import_without_pallet.stderr +++ b/substrate/frame/support/test/tests/split_ui/import_without_pallet.stderr @@ -1,5 +1,5 @@ error: `#[import_section]` can only be applied to a valid pallet module - --> tests/split_ui/import_without_pallet.rs:12:9 + --> tests/split_ui/import_without_pallet.rs:29:9 | -12 | pub mod pallet { +29 | pub mod pallet { | ^^^^^^ diff --git a/substrate/frame/support/test/tests/split_ui/no_section_found.rs b/substrate/frame/support/test/tests/split_ui/no_section_found.rs index fe12c6dc51b..95b90a47916 100644 --- a/substrate/frame/support/test/tests/split_ui/no_section_found.rs +++ b/substrate/frame/support/test/tests/split_ui/no_section_found.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_macros::*; diff --git a/substrate/frame/support/test/tests/split_ui/no_section_found.stderr b/substrate/frame/support/test/tests/split_ui/no_section_found.stderr index e0a9322b188..486543c16ed 100644 --- a/substrate/frame/support/test/tests/split_ui/no_section_found.stderr +++ b/substrate/frame/support/test/tests/split_ui/no_section_found.stderr @@ -1,13 +1,13 @@ error[E0432]: unresolved import `pallet` - --> tests/split_ui/no_section_found.rs:5:9 - | -5 | pub use pallet::*; - | ^^^^^^ help: a similar path exists: `test_pallet::pallet` + --> tests/split_ui/no_section_found.rs:22:9 + | +22 | pub use pallet::*; + | ^^^^^^ help: a similar path exists: `test_pallet::pallet` error: cannot find macro `__export_tokens_tt_storages_dev` in this scope - --> tests/split_ui/no_section_found.rs:7:1 - | -7 | #[import_section(storages_dev)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/split_ui/no_section_found.rs:24:1 + | +24 | #[import_section(storages_dev)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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/split_ui/pass/split_valid.rs b/substrate/frame/support/test/tests/split_ui/pass/split_valid.rs index 8b5839ecd28..a3ad7c2bf6f 100644 --- a/substrate/frame/support/test/tests/split_ui/pass/split_valid.rs +++ b/substrate/frame/support/test/tests/split_ui/pass/split_valid.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_macros::*; diff --git a/substrate/frame/support/test/tests/split_ui/pass/split_valid_disambiguation.rs b/substrate/frame/support/test/tests/split_ui/pass/split_valid_disambiguation.rs index 8d8d50422e9..dba0eb7333a 100644 --- a/substrate/frame/support/test/tests/split_ui/pass/split_valid_disambiguation.rs +++ b/substrate/frame/support/test/tests/split_ui/pass/split_valid_disambiguation.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_macros::*; diff --git a/substrate/frame/support/test/tests/split_ui/section_not_imported.rs b/substrate/frame/support/test/tests/split_ui/section_not_imported.rs index bcabf662567..dc1e84ad28b 100644 --- a/substrate/frame/support/test/tests/split_ui/section_not_imported.rs +++ b/substrate/frame/support/test/tests/split_ui/section_not_imported.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_macros::*; diff --git a/substrate/frame/support/test/tests/split_ui/section_not_imported.stderr b/substrate/frame/support/test/tests/split_ui/section_not_imported.stderr index 41ac2a5f58d..f79ac938a61 100644 --- a/substrate/frame/support/test/tests/split_ui/section_not_imported.stderr +++ b/substrate/frame/support/test/tests/split_ui/section_not_imported.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type `MyStorageMap` - --> tests/split_ui/section_not_imported.rs:27:4 + --> tests/split_ui/section_not_imported.rs:44:4 | -27 | MyStorageMap::::insert(1, 2); +44 | MyStorageMap::::insert(1, 2); | ^^^^^^^^^^^^ | | | use of undeclared type `MyStorageMap` diff --git a/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs b/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs index 4ed9d5adfec..362e6ead61e 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs +++ b/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::storage_alias] type Ident = StorageValue; diff --git a/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr b/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr index 726efed4007..e793aeb85bc 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr +++ b/substrate/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr @@ -1,5 +1,5 @@ error: If there are no generics, the prefix is only allowed to be an identifier. - --> tests/storage_alias_ui/checks_for_valid_storage_type.rs:2:27 - | -2 | type Ident = StorageValue; - | ^^^^^^^^^^^^ + --> tests/storage_alias_ui/checks_for_valid_storage_type.rs:19:27 + | +19 | type Ident = StorageValue; + | ^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs b/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs index 59d8004bbe6..08bc8d6cc47 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs +++ b/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::storage_alias] type Ident = CustomStorage; diff --git a/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr b/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr index 3b5e3e9c23c..9f173472a8b 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr +++ b/substrate/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr @@ -1,5 +1,5 @@ error: expected one of: `StorageValue`, `StorageMap`, `CountedStorageMap`, `StorageDoubleMap`, `StorageNMap` - --> tests/storage_alias_ui/forbid_underscore_as_prefix.rs:2:14 - | -2 | type Ident = CustomStorage; - | ^^^^^^^^^^^^^ + --> tests/storage_alias_ui/forbid_underscore_as_prefix.rs:19:14 + | +19 | type Ident = CustomStorage; + | ^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs b/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs index 79328268dc9..4b0978f5f96 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs +++ b/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[frame_support::storage_alias] type NoUnderscore = StorageValue<_, u32>; diff --git a/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr b/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr index abb7bf2518f..18810f20d38 100644 --- a/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr +++ b/substrate/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr @@ -1,5 +1,5 @@ error: `_` is not allowed as prefix by `storage_alias`. - --> tests/storage_alias_ui/prefix_must_be_an_ident.rs:2:34 - | -2 | type NoUnderscore = StorageValue<_, u32>; - | ^ + --> tests/storage_alias_ui/prefix_must_be_an_ident.rs:19:34 + | +19 | type NoUnderscore = StorageValue<_, u32>; + | ^ diff --git a/substrate/frame/transaction-payment/src/payment.rs b/substrate/frame/transaction-payment/src/payment.rs index bc871deafdc..22b0ac7c742 100644 --- a/substrate/frame/transaction-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/src/payment.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// ! Traits and default implementation for paying transaction fees. use crate::Config; diff --git a/substrate/frame/tx-pause/src/benchmarking.rs b/substrate/frame/tx-pause/src/benchmarking.rs index 81595ef9f72..126c0837949 100644 --- a/substrate/frame/tx-pause/src/benchmarking.rs +++ b/substrate/frame/tx-pause/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/tx-pause/src/lib.rs b/substrate/frame/tx-pause/src/lib.rs index 36147d32a2f..f8abf678e5a 100644 --- a/substrate/frame/tx-pause/src/lib.rs +++ b/substrate/frame/tx-pause/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 70c888f3c38..706b0a558ba 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/frame/tx-pause/src/tests.rs b/substrate/frame/tx-pause/src/tests.rs index ca259315726..ed0b8d103c8 100644 --- a/substrate/frame/tx-pause/src/tests.rs +++ b/substrate/frame/tx-pause/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/primitives/api/test/tests/ui/adding_self_parameter.rs b/substrate/primitives/api/test/tests/ui/adding_self_parameter.rs index 117fa261886..dcd680a2079 100644 --- a/substrate/primitives/api/test/tests/ui/adding_self_parameter.rs +++ b/substrate/primitives/api/test/tests/ui/adding_self_parameter.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { fn test(&self); diff --git a/substrate/primitives/api/test/tests/ui/adding_self_parameter.stderr b/substrate/primitives/api/test/tests/ui/adding_self_parameter.stderr index 894713d35ee..0260ccda12c 100644 --- a/substrate/primitives/api/test/tests/ui/adding_self_parameter.stderr +++ b/substrate/primitives/api/test/tests/ui/adding_self_parameter.stderr @@ -1,5 +1,5 @@ error: `self` as argument not supported. - --> $DIR/adding_self_parameter.rs:3:11 - | -3 | fn test(&self); - | ^ + --> tests/ui/adding_self_parameter.rs:20:11 + | +20 | fn test(&self); + | ^ diff --git a/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.rs b/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.rs index a0bb4e2830c..08d92b1f372 100644 --- a/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.rs +++ b/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} diff --git a/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.stderr b/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.stderr index 2140703a5d2..67eb3d90d27 100644 --- a/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.stderr +++ b/substrate/primitives/api/test/tests/ui/changed_in_no_default_method.stderr @@ -1,6 +1,6 @@ error: There is no 'default' method with this name (without `changed_in` attribute). The 'default' method is used to call into the latest implementation. - --> tests/ui/changed_in_no_default_method.rs:9:6 - | -9 | fn test(data: u64); - | ^^^^ + --> tests/ui/changed_in_no_default_method.rs:26:6 + | +26 | fn test(data: u64); + | ^^^^ diff --git a/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.rs b/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.rs index 164b91d1942..9ad3b3914bb 100644 --- a/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.rs +++ b/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} diff --git a/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.stderr b/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.stderr index d4a03bab552..6d17b7a5a2d 100644 --- a/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.stderr +++ b/substrate/primitives/api/test/tests/ui/changed_in_unknown_version.stderr @@ -1,5 +1,5 @@ error: `changed_in` version can not be greater than the `api_version` - --> tests/ui/changed_in_unknown_version.rs:8:3 - | -8 | fn test(data: u64); - | ^^ + --> tests/ui/changed_in_unknown_version.rs:25:3 + | +25 | fn test(data: u64); + | ^^ diff --git a/substrate/primitives/api/test/tests/ui/declaring_old_block.rs b/substrate/primitives/api/test/tests/ui/declaring_old_block.rs index fb741590282..6aa0582db15 100644 --- a/substrate/primitives/api/test/tests/ui/declaring_old_block.rs +++ b/substrate/primitives/api/test/tests/ui/declaring_old_block.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { fn test(); diff --git a/substrate/primitives/api/test/tests/ui/declaring_old_block.stderr b/substrate/primitives/api/test/tests/ui/declaring_old_block.stderr index 50dd37582c6..233fe2f5f1b 100644 --- a/substrate/primitives/api/test/tests/ui/declaring_old_block.stderr +++ b/substrate/primitives/api/test/tests/ui/declaring_old_block.stderr @@ -1,11 +1,11 @@ error: `Block: BlockT` generic parameter will be added automatically by the `decl_runtime_apis!` macro! If you try to use a different trait than the substrate `Block` trait, please rename it locally. - --> $DIR/declaring_old_block.rs:2:23 - | -2 | pub trait Api { - | ^^^^^^ + --> tests/ui/declaring_old_block.rs:19:23 + | +19 | pub trait Api { + | ^^^^^^ error: `Block: BlockT` generic parameter will be added automatically by the `decl_runtime_apis!` macro! - --> $DIR/declaring_old_block.rs:2:16 - | -2 | pub trait Api { - | ^^^^^ + --> tests/ui/declaring_old_block.rs:19:16 + | +19 | pub trait Api { + | ^^^^^ diff --git a/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.rs b/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.rs index e3c7ae8a39a..b8eeef3c3e5 100644 --- a/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.rs +++ b/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { fn test(); diff --git a/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.stderr b/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.stderr index 778de3c9d15..59a73819089 100644 --- a/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.stderr +++ b/substrate/primitives/api/test/tests/ui/declaring_own_block_with_different_name.stderr @@ -1,5 +1,5 @@ error: `Block: BlockT` generic parameter will be added automatically by the `decl_runtime_apis!` macro! If you try to use a different trait than the substrate `Block` trait, please rename it locally. - --> $DIR/declaring_own_block_with_different_name.rs:2:19 - | -2 | pub trait Api { - | ^^^^^^ + --> tests/ui/declaring_own_block_with_different_name.rs:19:19 + | +19 | pub trait Api { + | ^^^^^^ diff --git a/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.rs b/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.rs index 68d84d97fa8..1dce4fed006 100644 --- a/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.rs +++ b/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} diff --git a/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr b/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr index 96ec09a1855..498a3f201c3 100644 --- a/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr +++ b/substrate/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr @@ -1,7 +1,7 @@ error: No api implementation given! - --> tests/ui/empty_impl_runtime_apis_call.rs:11:1 + --> tests/ui/empty_impl_runtime_apis_call.rs:28:1 | -11 | sp_api::impl_runtime_apis! {} +28 | sp_api::impl_runtime_apis! {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs index 32501be7855..43718e4cd04 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 2324be85be4..4bd64c974f2 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -1,35 +1,35 @@ error[E0053]: method `test` has an incompatible type for trait - --> tests/ui/impl_incorrect_method_signature.rs:16:17 + --> tests/ui/impl_incorrect_method_signature.rs:33:17 | -16 | fn test(data: String) {} +33 | fn test(data: String) {} | ^^^^^^ | | | expected `u64`, found `std::string::String` | help: change the parameter type to match the trait: `u64` | note: type in trait - --> tests/ui/impl_incorrect_method_signature.rs:10:17 + --> tests/ui/impl_incorrect_method_signature.rs:27:17 | -10 | fn test(data: u64); +27 | fn test(data: u64); | ^^^ = note: expected signature `fn(u64)` found signature `fn(std::string::String)` error[E0308]: mismatched types - --> tests/ui/impl_incorrect_method_signature.rs:16:11 + --> tests/ui/impl_incorrect_method_signature.rs:33:11 | -14 | / sp_api::impl_runtime_apis! { -15 | | impl self::Api for Runtime { -16 | | fn test(data: String) {} +31 | / sp_api::impl_runtime_apis! { +32 | | impl self::Api for Runtime { +33 | | fn test(data: String) {} | | ^^^^ expected `u64`, found `String` -17 | | } +34 | | } ... | -29 | | } -30 | | } +46 | | } +47 | | } | |_- arguments to this function are incorrect | note: associated function defined here - --> tests/ui/impl_incorrect_method_signature.rs:10:6 + --> tests/ui/impl_incorrect_method_signature.rs:27:6 | -10 | fn test(data: u64); +27 | fn test(data: u64); | ^^^^ diff --git a/substrate/primitives/api/test/tests/ui/impl_missing_version.rs b/substrate/primitives/api/test/tests/ui/impl_missing_version.rs index 8fd40a40092..560257b5168 100644 --- a/substrate/primitives/api/test/tests/ui/impl_missing_version.rs +++ b/substrate/primitives/api/test/tests/ui/impl_missing_version.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/impl_missing_version.stderr b/substrate/primitives/api/test/tests/ui/impl_missing_version.stderr index 770543aa887..c154bb10be0 100644 --- a/substrate/primitives/api/test/tests/ui/impl_missing_version.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_missing_version.stderr @@ -1,8 +1,8 @@ error[E0405]: cannot find trait `ApiV4` in module `self::runtime_decl_for_api` - --> tests/ui/impl_missing_version.rs:18:13 + --> tests/ui/impl_missing_version.rs:35:13 | -8 | pub trait Api { +25 | pub trait Api { | ------------- similarly named trait `ApiV2` defined here ... -18 | impl self::Api for Runtime { +35 | impl self::Api for Runtime { | ^^^ help: a trait with a similar name exists: `ApiV2` diff --git a/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.rs b/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.rs index cb8f2f493d7..4647a78809a 100644 --- a/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.rs +++ b/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} 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 a41f59f36b1..9e014e3ea82 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 @@ -1,5 +1,5 @@ error: Two traits with the same name detected! The trait name is used to generate its ID. Please rename one trait at the declaration! - --> tests/ui/impl_two_traits_with_same_name.rs:24:15 + --> tests/ui/impl_two_traits_with_same_name.rs:41:15 | -24 | impl second::Api for Runtime { +41 | impl second::Api for Runtime { | ^^^ diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_1.rs b/substrate/primitives/api/test/tests/ui/invalid_api_version_1.rs index e038dd0aa65..67af9a95521 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_1.rs +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_1.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { #[api_version] pub trait Api { diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_1.stderr b/substrate/primitives/api/test/tests/ui/invalid_api_version_1.stderr index 53ffce959bb..41ee4d5657c 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_1.stderr +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_1.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> tests/ui/invalid_api_version_1.rs:2:2 - | -2 | #[api_version] - | ^ + --> tests/ui/invalid_api_version_1.rs:19:2 + | +19 | #[api_version] + | ^ diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_2.rs b/substrate/primitives/api/test/tests/ui/invalid_api_version_2.rs index bb8ed8ed11f..fe563023f75 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_2.rs +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_2.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { #[api_version("1")] pub trait Api { diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_2.stderr b/substrate/primitives/api/test/tests/ui/invalid_api_version_2.stderr index 0c5274d4680..adfe4962ce4 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_2.stderr +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_2.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> tests/ui/invalid_api_version_2.rs:2:2 - | -2 | #[api_version("1")] - | ^ + --> tests/ui/invalid_api_version_2.rs:19:2 + | +19 | #[api_version("1")] + | ^ diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_3.rs b/substrate/primitives/api/test/tests/ui/invalid_api_version_3.rs index d010866e237..385837067e9 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_3.rs +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_3.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { #[api_version()] pub trait Api { diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_3.stderr b/substrate/primitives/api/test/tests/ui/invalid_api_version_3.stderr index 4a34a7aa9b4..cd73a384f60 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_3.stderr +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_3.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> tests/ui/invalid_api_version_3.rs:2:2 - | -2 | #[api_version()] - | ^ + --> tests/ui/invalid_api_version_3.rs:19:2 + | +19 | #[api_version()] + | ^ diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_4.rs b/substrate/primitives/api/test/tests/ui/invalid_api_version_4.rs index 37b5b6ffa25..adca5f72559 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_4.rs +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_4.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { #[api_version("1")] diff --git a/substrate/primitives/api/test/tests/ui/invalid_api_version_4.stderr b/substrate/primitives/api/test/tests/ui/invalid_api_version_4.stderr index 57541a97f6c..a241ee02870 100644 --- a/substrate/primitives/api/test/tests/ui/invalid_api_version_4.stderr +++ b/substrate/primitives/api/test/tests/ui/invalid_api_version_4.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> tests/ui/invalid_api_version_4.rs:3:3 - | -3 | #[api_version("1")] - | ^ + --> tests/ui/invalid_api_version_4.rs:20:3 + | +20 | #[api_version("1")] + | ^ diff --git a/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs b/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs index b4f43cd401b..ca61bff5e6a 100644 --- a/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs +++ b/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { #[api_version(2)] pub trait Api { diff --git a/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr b/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr index ec4b594023a..dec73775363 100644 --- a/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr +++ b/substrate/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr @@ -1,11 +1,11 @@ error: Method version `1` is older than (or equal to) trait version `2`.Methods can't define versions older than the trait version. - --> tests/ui/method_ver_lower_than_trait_ver.rs:4:3 - | -4 | #[api_version(1)] - | ^ + --> tests/ui/method_ver_lower_than_trait_ver.rs:21:3 + | +21 | #[api_version(1)] + | ^ error: Trait version is set here. - --> tests/ui/method_ver_lower_than_trait_ver.rs:2:2 - | -2 | #[api_version(2)] - | ^ + --> tests/ui/method_ver_lower_than_trait_ver.rs:19:2 + | +19 | #[api_version(2)] + | ^ diff --git a/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.rs b/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.rs index b69505bfeb0..81d4bfeda82 100644 --- a/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.rs +++ b/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} diff --git a/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.stderr b/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.stderr index 5dc2b993bb1..4d7ead55d61 100644 --- a/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.stderr +++ b/substrate/primitives/api/test/tests/ui/missing_block_generic_parameter.stderr @@ -1,5 +1,5 @@ error: Missing `Block` generic parameter. - --> tests/ui/missing_block_generic_parameter.rs:12:13 + --> tests/ui/missing_block_generic_parameter.rs:29:13 | -12 | impl self::Api for Runtime { +29 | impl self::Api for Runtime { | ^^^ diff --git a/substrate/primitives/api/test/tests/ui/missing_path_for_trait.rs b/substrate/primitives/api/test/tests/ui/missing_path_for_trait.rs index e47bca1c3f6..d1a0a27e20a 100644 --- a/substrate/primitives/api/test/tests/ui/missing_path_for_trait.rs +++ b/substrate/primitives/api/test/tests/ui/missing_path_for_trait.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. struct Runtime {} diff --git a/substrate/primitives/api/test/tests/ui/missing_path_for_trait.stderr b/substrate/primitives/api/test/tests/ui/missing_path_for_trait.stderr index cca99350197..9444b0041e6 100644 --- a/substrate/primitives/api/test/tests/ui/missing_path_for_trait.stderr +++ b/substrate/primitives/api/test/tests/ui/missing_path_for_trait.stderr @@ -1,5 +1,5 @@ error: The implemented trait has to be referenced with a path, e.g. `impl client::Core for Runtime`. - --> tests/ui/missing_path_for_trait.rs:12:7 + --> tests/ui/missing_path_for_trait.rs:29:7 | -12 | impl Api for Runtime { +29 | impl Api for Runtime { | ^^^ diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs b/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs index 919cef055fe..6ead545f85a 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method.stderr b/substrate/primitives/api/test/tests/ui/missing_versioned_method.stderr index b88d903212d..e313b7948e8 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method.stderr +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method.stderr @@ -1,8 +1,8 @@ error[E0046]: not all trait items implemented, missing: `test3` - --> tests/ui/missing_versioned_method.rs:18:2 + --> tests/ui/missing_versioned_method.rs:35:2 | -12 | fn test3(); +29 | fn test3(); | ----------- `test3` from trait ... -18 | impl self::Api for Runtime { +35 | impl self::Api for Runtime { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `test3` in implementation diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs index 036bba417f5..8eebc1d79ba 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr index 4afa6856a58..a45d2e6d354 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr @@ -1,8 +1,8 @@ error[E0046]: not all trait items implemented, missing: `test3` - --> tests/ui/missing_versioned_method_multiple_vers.rs:20:2 + --> tests/ui/missing_versioned_method_multiple_vers.rs:37:2 | -12 | fn test3(); +29 | fn test3(); | ----------- `test3` from trait ... -20 | impl self::Api for Runtime { +37 | impl self::Api for Runtime { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `test3` in implementation diff --git a/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs b/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs index 45e6adb2fcf..7fa3916bf20 100644 --- a/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs +++ b/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use substrate_test_runtime_client::runtime::Block; use sp_api::ApiError; diff --git a/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr b/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr index 234331c9749..a7ea3146e89 100644 --- a/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr @@ -1,13 +1,13 @@ error: `Hash` needs to be taken by value and not by reference! - --> tests/ui/mock_advanced_hash_by_reference.rs:12:1 + --> tests/ui/mock_advanced_hash_by_reference.rs:29:1 | -12 | / sp_api::mock_impl_runtime_apis! { -13 | | impl Api for MockApi { -14 | | #[advanced] -15 | | fn test(&self, _: &Hash) -> Result<(), ApiError> { +29 | / sp_api::mock_impl_runtime_apis! { +30 | | impl Api for MockApi { +31 | | #[advanced] +32 | | fn test(&self, _: &Hash) -> Result<(), ApiError> { ... | -18 | | } -19 | | } +35 | | } +36 | | } | |_^ | = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.rs b/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.rs index 76bf5f1aa74..2a2eeec6313 100644 --- a/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.rs +++ b/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use substrate_test_runtime_client::runtime::Block; use sp_api::ApiError; diff --git a/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr b/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr index 48a94a00bea..0e45f73f3ed 100644 --- a/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr @@ -1,5 +1,5 @@ error: If using the `advanced` attribute, it is required that the function takes at least one argument, the `Hash`. - --> tests/ui/mock_advanced_missing_hash.rs:15:3 + --> tests/ui/mock_advanced_missing_hash.rs:32:3 | -15 | fn test(&self) -> Result<(), ApiError> { +32 | fn test(&self) -> Result<(), ApiError> { | ^^ diff --git a/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.rs b/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.rs index f49cafd23a0..a4c98ca0cb0 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.rs +++ b/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + struct Block2; sp_api::decl_runtime_apis! { diff --git a/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.stderr b/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.stderr index 1831d0485b4..cd29108e156 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_only_one_block_type.stderr @@ -1,11 +1,11 @@ error: Block type should be the same between all runtime apis. - --> $DIR/mock_only_one_block_type.rs:20:12 + --> tests/ui/mock_only_one_block_type.rs:37:12 | -20 | impl Api2 for MockApi { +37 | impl Api2 for MockApi { | ^^^^^^ error: First block type found here - --> $DIR/mock_only_one_block_type.rs:16:11 + --> tests/ui/mock_only_one_block_type.rs:33:11 | -16 | impl Api for MockApi { +33 | impl Api for MockApi { | ^^^^^ diff --git a/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.rs b/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.rs index 617031b4d5f..155b3d23d91 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.rs +++ b/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { fn test(data: u64); diff --git a/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.stderr b/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.stderr index 5f1e29b281c..e9e7da2db8b 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_only_one_self_type.stderr @@ -1,11 +1,11 @@ error: Self type should not change between runtime apis - --> $DIR/mock_only_one_self_type.rs:19:23 + --> tests/ui/mock_only_one_self_type.rs:36:23 | -19 | impl Api2 for MockApi2 { +36 | impl Api2 for MockApi2 { | ^^^^^^^^ error: First self type found here - --> $DIR/mock_only_one_self_type.rs:15:22 + --> tests/ui/mock_only_one_self_type.rs:32:22 | -15 | impl Api for MockApi { +32 | impl Api for MockApi { | ^^^^^^^ diff --git a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.rs b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.rs index 8a733f5779c..061206fff73 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.rs +++ b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use substrate_test_runtime_client::runtime::Block; sp_api::decl_runtime_apis! { diff --git a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr index f088e8f2de5..84575577187 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr @@ -1,50 +1,50 @@ error: Only `&self` is supported! - --> tests/ui/mock_only_self_reference.rs:14:11 + --> tests/ui/mock_only_self_reference.rs:31:11 | -14 | fn test(self, data: u64) {} +31 | fn test(self, data: u64) {} | ^^^^ error: Only `&self` is supported! - --> tests/ui/mock_only_self_reference.rs:16:12 + --> tests/ui/mock_only_self_reference.rs:33:12 | -16 | fn test2(&mut self, data: u64) {} +33 | fn test2(&mut self, data: u64) {} | ^ error[E0050]: method `test` has 2 parameters but the declaration in trait `Api::test` has 3 - --> tests/ui/mock_only_self_reference.rs:12:1 + --> tests/ui/mock_only_self_reference.rs:29:1 | -3 | / sp_api::decl_runtime_apis! { -4 | | pub trait Api { -5 | | fn test(data: u64); +20 | / sp_api::decl_runtime_apis! { +21 | | pub trait Api { +22 | | fn test(data: u64); | |_________________________- trait requires 3 parameters ... -12 | / sp_api::mock_impl_runtime_apis! { -13 | | impl Api for MockApi { -14 | | fn test(self, data: u64) {} -15 | | -16 | | fn test2(&mut self, data: u64) {} -17 | | } -18 | | } +29 | / sp_api::mock_impl_runtime_apis! { +30 | | impl Api for MockApi { +31 | | fn test(self, data: u64) {} +32 | | +33 | | fn test2(&mut self, data: u64) {} +34 | | } +35 | | } | |_^ expected 3 parameters, found 2 | = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0050]: method `test2` has 2 parameters but the declaration in trait `Api::test2` has 3 - --> tests/ui/mock_only_self_reference.rs:12:1 + --> tests/ui/mock_only_self_reference.rs:29:1 | -3 | / sp_api::decl_runtime_apis! { -4 | | pub trait Api { -5 | | fn test(data: u64); -6 | | fn test2(data: u64); +20 | / sp_api::decl_runtime_apis! { +21 | | pub trait Api { +22 | | fn test(data: u64); +23 | | fn test2(data: u64); | |__________________________- trait requires 3 parameters ... -12 | / sp_api::mock_impl_runtime_apis! { -13 | | impl Api for MockApi { -14 | | fn test(self, data: u64) {} -15 | | -16 | | fn test2(&mut self, data: u64) {} -17 | | } -18 | | } +29 | / sp_api::mock_impl_runtime_apis! { +30 | | impl Api for MockApi { +31 | | fn test(self, data: u64) {} +32 | | +33 | | fn test2(&mut self, data: u64) {} +34 | | } +35 | | } | |_^ expected 3 parameters, found 2 | = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/api/test/tests/ui/no_default_implementation.rs b/substrate/primitives/api/test/tests/ui/no_default_implementation.rs index 6af93d6b865..4b96700ae36 100644 --- a/substrate/primitives/api/test/tests/ui/no_default_implementation.rs +++ b/substrate/primitives/api/test/tests/ui/no_default_implementation.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + sp_api::decl_runtime_apis! { pub trait Api { fn test() { diff --git a/substrate/primitives/api/test/tests/ui/no_default_implementation.stderr b/substrate/primitives/api/test/tests/ui/no_default_implementation.stderr index 0ccece14419..0d25fe2e59f 100644 --- a/substrate/primitives/api/test/tests/ui/no_default_implementation.stderr +++ b/substrate/primitives/api/test/tests/ui/no_default_implementation.stderr @@ -1,8 +1,8 @@ error: A runtime API function cannot have a default implementation! - --> $DIR/no_default_implementation.rs:3:13 - | -3 | fn test() { - | ___________________^ -4 | | println!("Hey, I'm a default implementation!"); -5 | | } - | |_________^ + --> tests/ui/no_default_implementation.rs:20:13 + | +20 | fn test() { + | ___________________^ +21 | | println!("Hey, I'm a default implementation!"); +22 | | } + | |_________^ diff --git a/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs b/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs index b572a3bc30d..594556d57be 100644 --- a/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs +++ b/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::traits::Block as BlockT; diff --git a/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs b/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs index 58192feb9ec..ae573238ffe 100644 --- a/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs +++ b/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs index 14a8fa4d4e0..921bf0d0435 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime::traits::Block as BlockT; use substrate_test_runtime_client::runtime::Block; diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index e9d550f3a3b..4c21a3afb9b 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -1,39 +1,39 @@ error[E0053]: method `test` has an incompatible type for trait - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:16:17 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:17 | -16 | fn test(data: &u64) { +33 | fn test(data: &u64) { | ^^^^ | | | expected `u64`, found `&u64` | help: change the parameter type to match the trait: `u64` | note: type in trait - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:10:17 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:27:17 | -10 | fn test(data: u64); +27 | fn test(data: u64); | ^^^ = note: expected signature `fn(u64)` found signature `fn(&u64)` error[E0308]: mismatched types - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:16:11 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:11 | -14 | / sp_api::impl_runtime_apis! { -15 | | impl self::Api for Runtime { -16 | | fn test(data: &u64) { +31 | / sp_api::impl_runtime_apis! { +32 | | impl self::Api for Runtime { +33 | | fn test(data: &u64) { | | ^^^^^^^ expected `u64`, found `&u64` -17 | | unimplemented!() +34 | | unimplemented!() ... | -31 | | } -32 | | } +48 | | } +49 | | } | |_- arguments to this function are incorrect | note: associated function defined here - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:10:6 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:27:6 | -10 | fn test(data: u64); +27 | fn test(data: u64); | ^^^^ help: consider removing the borrow | -16 | fn test(data: &u64) { +33 | fn test(data: &u64) { | diff --git a/substrate/primitives/core/benches/bench.rs b/substrate/primitives/core/benches/bench.rs index e91c1758c3c..ffca819b638 100644 --- a/substrate/primitives/core/benches/bench.rs +++ b/substrate/primitives/core/benches/bench.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs index 9230479b3be..78f20297299 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs index 6c707aa5814..b2ec48a42fc 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs index 2f3b4c3c9c9..4ad26fc54b1 100644 --- a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs +++ b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 index 84a86286180..e69dbd79846 100644 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); 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 index 72b68c3b471..7e9cd87e543 100644 --- 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 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.rs b/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.rs index 948c327aa1a..3dc49f7333b 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.stderr b/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.stderr index 592dd9928c9..f8dbdfbcb8f 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_duplicate_versions.stderr @@ -1,11 +1,11 @@ error: Duplicated version attribute - --> $DIR/no_duplicate_versions.rs:7:2 - | -7 | #[version(2)] - | ^ + --> tests/ui/no_duplicate_versions.rs:24:2 + | +24 | #[version(2)] + | ^ error: Previous version with the same number defined here - --> $DIR/no_duplicate_versions.rs:5:2 - | -5 | #[version(2)] - | ^ + --> tests/ui/no_duplicate_versions.rs:22:2 + | +22 | #[version(2)] + | ^ diff --git a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs index 51e45f178f0..836c5866459 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] 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 e8accd62fc6..23e671f6ce3 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 @@ -1,5 +1,5 @@ error[E0425]: cannot find function `bar` in module `test` - --> tests/ui/no_feature_gated_method.rs:16:8 + --> tests/ui/no_feature_gated_method.rs:33:8 | -16 | test::bar(); +33 | test::bar(); | ^^^ not found in `test` diff --git a/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.rs b/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.rs index c468f48e374..8706a287822 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.stderr b/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.stderr index cdefcf60c56..142ca186c7d 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_gaps_in_versions.stderr @@ -1,5 +1,5 @@ error: Unexpected version attribute: missing version '2' for this function - --> $DIR/no_gaps_in_versions.rs:13:2 + --> tests/ui/no_gaps_in_versions.rs:30:2 | -13 | #[version(3)] +30 | #[version(3)] | ^ diff --git a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.rs b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.rs index 407942eb5ed..7fd61802a1a 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.stderr b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.stderr index 8a549753ac9..f5257bdd992 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_method.stderr @@ -1,5 +1,5 @@ error: Generic parameters not supported. - --> $DIR/no_generic_parameters_method.rs:5:10 - | -5 | fn test() {} - | ^ + --> tests/ui/no_generic_parameters_method.rs:22:10 + | +22 | fn test() {} + | ^ diff --git a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.rs b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.rs index 35efac6761c..ebb5b6f03f8 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.stderr b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.stderr index 794e30bca76..88a623c63bb 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_generic_parameters_trait.stderr @@ -1,5 +1,5 @@ error: Generic parameters not supported. - --> $DIR/no_generic_parameters_trait.rs:4:12 - | -4 | trait Test { - | ^ + --> tests/ui/no_generic_parameters_trait.rs:21:12 + | +21 | trait Test { + | ^ diff --git a/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.rs b/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.rs index e3cd93e4a97..d243b0da609 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.stderr b/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.stderr index 31b2d397623..b2b570ca307 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_method_implementation.stderr @@ -1,5 +1,5 @@ error: Methods need to have an implementation. - --> $DIR/no_method_implementation.rs:5:2 - | -5 | fn test(); - | ^^ + --> tests/ui/no_method_implementation.rs:22:2 + | +22 | fn test(); + | ^^ diff --git a/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.rs b/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.rs index a4a8a5804be..73bb0fd3f17 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.stderr b/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.stderr index 6f50e14278d..6a99f4f76b5 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_versioned_conditional_build.stderr @@ -1,5 +1,5 @@ error: Conditional compilation is not supported for versioned functions - --> tests/ui/no_versioned_conditional_build.rs:7:2 - | -7 | #[version(2)] - | ^ + --> tests/ui/no_versioned_conditional_build.rs:24:2 + | +24 | #[version(2)] + | ^ diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs index 6f4ae37ea46..dcc8fb0930b 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::pass_by::PassByEnum; #[derive(PassByEnum)] diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr index 44fb5a244e0..c5b69d426ab 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr @@ -1,7 +1,7 @@ error: `PassByEnum` only supports enums as input type. - --> $DIR/pass_by_enum_with_struct.rs:3:10 - | -3 | #[derive(PassByEnum)] - | ^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/ui/pass_by_enum_with_struct.rs:20:10 + | +20 | #[derive(PassByEnum)] + | ^^^^^^^^^^ + | + = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs index a03bfdc1aed..b6faa46605b 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::pass_by::PassByEnum; #[derive(PassByEnum)] diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr index 633dc3bbe8b..ad94efed3c6 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr @@ -1,7 +1,7 @@ error: `PassByEnum` only supports unit variants. - --> $DIR/pass_by_enum_with_value_variant.rs:3:10 - | -3 | #[derive(PassByEnum)] - | ^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/ui/pass_by_enum_with_value_variant.rs:20:10 + | +20 | #[derive(PassByEnum)] + | ^^^^^^^^^^ + | + = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs index f496bc37001..2b7e98165ba 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::pass_by::PassByInner; #[derive(PassByInner)] diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr index 0ffee00210e..3ca1362fb42 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr @@ -1,7 +1,7 @@ error: Only newtype/one field structs are supported by `PassByInner`! - --> $DIR/pass_by_inner_with_two_fields.rs:3:10 - | -3 | #[derive(PassByInner)] - | ^^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByInner` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/ui/pass_by_inner_with_two_fields.rs:20:10 + | +20 | #[derive(PassByInner)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `PassByInner` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.rs b/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.rs index 9c12614d930..82227dc67ff 100644 --- a/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.rs +++ b/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.stderr b/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.stderr index 9b17a63a35c..3e9a4b74e8b 100644 --- a/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/take_self_by_value.stderr @@ -1,5 +1,5 @@ error: Taking `Self` by value is not allowed. - --> $DIR/take_self_by_value.rs:5:10 - | -5 | fn test(self) {} - | ^^^^ + --> tests/ui/take_self_by_value.rs:22:10 + | +22 | fn test(self) {} + | ^^^^ diff --git a/substrate/primitives/staking/src/currency_to_vote.rs b/substrate/primitives/staking/src/currency_to_vote.rs index 556e5bd2104..ff1253ade5f 100644 --- a/substrate/primitives/staking/src/currency_to_vote.rs +++ b/substrate/primitives/staking/src/currency_to_vote.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/substrate/scripts/ci/node-template-release/src/main.rs b/substrate/scripts/ci/node-template-release/src/main.rs index 9681d73fa6f..850535e4045 100644 --- a/substrate/scripts/ci/node-template-release/src/main.rs +++ b/substrate/scripts/ci/node-template-release/src/main.rs @@ -1,3 +1,21 @@ +// 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 std::{ collections::HashMap, fs::{self, File, OpenOptions}, -- GitLab From be7f1244c9d69f45f2bed08b3a8542188a4db613 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Wed, 30 Aug 2023 15:08:47 +0200 Subject: [PATCH 024/633] Fix links in contributing and PR template docs (#1300) * add link to labels doc * add absolute links in PR template * Update docs/CONTRIBUTING.md --- docs/CONTRIBUTING.md | 2 +- docs/PULL_REQUEST_TEMPLATE.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index fa850f6bdc2..a4632c1a1ea 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -34,7 +34,7 @@ No PR should be merged until all reviews' comments are addressed. ### Labels: -The set of labels and their description can be found [here](linktobeinserted) +The set of labels and their description can be found [here](https://paritytech.github.io/labels/doc_polkadot-sdk.html). ### Process: diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 15482d9e85a..1d0ef338c10 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -3,7 +3,7 @@ ✄ ----------------------------------------------------------------------------- Thank you for your Pull Request! 🙏 Please make sure it follows the contribution -guidelines outlined in [this document](CONTRIBUTING.md) and fill out the +guidelines outlined in [this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md) and fill out the sections below. Once you're ready to submit your PR for review, please delete this section and leave only the text under the "Description" heading. @@ -29,7 +29,7 @@ Cumulus companion: (*if applicable*) # Checklist - [ ] My PR includes a detailed description as outlined in the "Description" section above -- [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) +- [ ] My PR follows the [labeling requirements](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#process) of this project (at minimum one label for `T` 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) -- GitLab From 31c79470a3d59d72c1856488f2c8d33b10e8c7fb Mon Sep 17 00:00:00 2001 From: Lulu Date: Wed, 30 Aug 2023 16:57:49 +0200 Subject: [PATCH 025/633] Rename squatted crates (#1241) * Rename squatted crates This commit adds the staging- prefix to squatted crates so we can go forward and publish them to crates.io. Using the staging- prefix is a temp fix until we decide on replacement names. https://forum.parity.io/t/renaming-squated-crates-in-substrate-polkadot-cumulus/1964/6 * Fix test after crate renames * Update Lockfile --- Cargo.lock | 604 +++++++++--------- cumulus/bridges/bin/runtime-common/Cargo.toml | 4 +- .../modules/xcm-bridge-hub-router/Cargo.toml | 4 +- cumulus/pallets/dmp-queue/Cargo.toml | 2 +- cumulus/pallets/parachain-system/Cargo.toml | 2 +- cumulus/pallets/xcm/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/Cargo.toml | 6 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/parachain-template/runtime/Cargo.toml | 6 +- cumulus/parachains/common/Cargo.toml | 6 +- .../assets/asset-hub-kusama/Cargo.toml | 4 +- .../assets/asset-hub-polkadot/Cargo.toml | 4 +- .../assets/asset-hub-westend/Cargo.toml | 4 +- .../bridges/bridge-hub-rococo/Cargo.toml | 4 +- .../collectives-polkadot/Cargo.toml | 4 +- .../emulated/common/Cargo.toml | 6 +- cumulus/parachains/pallets/ping/Cargo.toml | 2 +- .../assets/asset-hub-kusama/Cargo.toml | 6 +- .../assets/asset-hub-polkadot/Cargo.toml | 6 +- .../assets/asset-hub-westend/Cargo.toml | 6 +- .../runtimes/assets/common/Cargo.toml | 6 +- .../runtimes/assets/test-utils/Cargo.toml | 4 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 6 +- .../bridge-hub-polkadot/Cargo.toml | 6 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 +- .../bridge-hubs/test-utils/Cargo.toml | 6 +- .../collectives-polkadot/Cargo.toml | 6 +- .../contracts/contracts-rococo/Cargo.toml | 6 +- .../glutton/glutton-kusama/Cargo.toml | 6 +- .../runtimes/starters/shell/Cargo.toml | 6 +- .../parachains/runtimes/test-utils/Cargo.toml | 4 +- .../runtimes/testing/penpal/Cargo.toml | 6 +- .../testing/rococo-parachain/Cargo.toml | 6 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/primitives/core/Cargo.toml | 2 +- cumulus/primitives/utility/Cargo.toml | 6 +- cumulus/xcm/xcm-emulator/Cargo.toml | 4 +- polkadot/node/service/Cargo.toml | 2 +- .../node/test/performance-test/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/kusama/Cargo.toml | 8 +- polkadot/runtime/parachains/Cargo.toml | 4 +- polkadot/runtime/polkadot/Cargo.toml | 6 +- polkadot/runtime/rococo/Cargo.toml | 6 +- polkadot/runtime/test-runtime/Cargo.toml | 6 +- polkadot/runtime/westend/Cargo.toml | 6 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/utils/staking-miner/Cargo.toml | 6 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 8 +- polkadot/xcm/pallet-xcm/Cargo.toml | 6 +- polkadot/xcm/xcm-builder/Cargo.toml | 6 +- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 2 + polkadot/xcm/xcm-executor/Cargo.toml | 4 +- .../xcm-executor/integration-tests/Cargo.toml | 4 +- polkadot/xcm/xcm-simulator/Cargo.toml | 6 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 6 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 6 +- 59 files changed, 438 insertions(+), 436 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f54299b7a2..74034bab663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -716,9 +716,9 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -788,10 +788,10 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -816,9 +816,9 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -884,10 +884,10 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -915,9 +915,9 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -985,11 +985,11 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", "westend-runtime-constants", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -1021,9 +1021,9 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "staging-xcm", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-executor", ] [[package]] @@ -1043,10 +1043,10 @@ dependencies = [ "sp-api", "sp-runtime", "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -1883,10 +1883,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -1946,10 +1946,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -1975,9 +1975,9 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -2053,11 +2053,11 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "static_assertions", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -2102,9 +2102,9 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -2138,9 +2138,9 @@ dependencies = [ "sp-runtime", "sp-std", "sp-trie", + "staging-xcm", + "staging-xcm-builder", "static_assertions", - "xcm", - "xcm-builder", ] [[package]] @@ -2603,9 +2603,9 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -2672,10 +2672,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -2880,10 +2880,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -3555,7 +3555,7 @@ dependencies = [ "sp-runtime", "sp-std", "sp-version", - "xcm", + "staging-xcm", ] [[package]] @@ -3591,8 +3591,8 @@ dependencies = [ "sp-tracing", "sp-trie", "sp-version", + "staging-xcm", "trie-db", - "xcm", ] [[package]] @@ -3645,7 +3645,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", + "staging-xcm", ] [[package]] @@ -3667,9 +3667,9 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -3684,7 +3684,7 @@ dependencies = [ "scale-info", "sp-runtime", "sp-std", - "xcm", + "staging-xcm", ] [[package]] @@ -3713,7 +3713,7 @@ dependencies = [ "sp-runtime", "sp-std", "sp-trie", - "xcm", + "staging-xcm", ] [[package]] @@ -3762,9 +3762,9 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -5892,10 +5892,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -6447,7 +6447,6 @@ dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", - "kusama-runtime", "kusama-runtime-constants", "lazy_static", "pallet-assets", @@ -6479,11 +6478,12 @@ dependencies = [ "sp-runtime", "sp-tracing", "sp-weights", + "staging-kusama-runtime", + "staging-xcm", + "staging-xcm-executor", "westend-runtime", "westend-runtime-constants", - "xcm", "xcm-emulator", - "xcm-executor", ] [[package]] @@ -6915,119 +6915,6 @@ dependencies = [ "substrate-wasm-builder", ] -[[package]] -name = "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 0.4.1", - "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", - "static_assertions", - "substrate-wasm-builder", - "tiny-keccak", - "tokio", - "xcm", - "xcm-builder", - "xcm-executor", -] - [[package]] name = "kusama-runtime-constants" version = "1.0.0" @@ -10950,9 +10837,9 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -10975,9 +10862,9 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -10995,8 +10882,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", + "staging-xcm", + "staging-xcm-builder", ] [[package]] @@ -11063,10 +10950,10 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-timestamp", + "staging-xcm", "substrate-build-script-utils", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", - "xcm", ] [[package]] @@ -11118,10 +11005,10 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -11147,10 +11034,10 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -11182,9 +11069,9 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", + "staging-xcm", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-executor", ] [[package]] @@ -11445,10 +11332,10 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -12640,6 +12527,7 @@ dependencies = [ "sp-session", "sp-timestamp", "sp-transaction-pool", + "staging-xcm", "substrate-build-script-utils", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", @@ -12647,7 +12535,6 @@ dependencies = [ "tempfile", "tokio", "wait-timeout", - "xcm", ] [[package]] @@ -12655,7 +12542,6 @@ name = "polkadot-performance-test" version = "1.0.0" dependencies = [ "env_logger 0.9.3", - "kusama-runtime", "log", "polkadot-erasure-coding", "polkadot-node-core-pvf-prepare-worker", @@ -12664,6 +12550,7 @@ dependencies = [ "quote", "sc-executor-common", "sp-maybe-compressed-blob", + "staging-kusama-runtime", "thiserror", ] @@ -12830,13 +12717,13 @@ dependencies = [ "sp-transaction-pool", "sp-trie", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "static_assertions", "substrate-wasm-builder", "tiny-keccak", "tokio", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -12886,8 +12773,8 @@ dependencies = [ "sp-session", "sp-staking", "sp-std", + "staging-xcm", "static_assertions", - "xcm", ] [[package]] @@ -12963,10 +12850,10 @@ dependencies = [ "sp-staking", "sp-std", "sp-tracing", + "staging-xcm", + "staging-xcm-executor", "static_assertions", "thousands", - "xcm", - "xcm-executor", ] [[package]] @@ -12984,7 +12871,6 @@ dependencies = [ "futures", "hex-literal 0.4.1", "is_executable", - "kusama-runtime", "kusama-runtime-constants", "kvdb", "kvdb-rocksdb", @@ -13089,6 +12975,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-kusama-runtime", "substrate-prometheus-endpoint", "tempfile", "thiserror", @@ -13258,12 +13145,12 @@ dependencies = [ "sp-transaction-pool", "sp-trie", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", "test-runtime-constants", "tiny-keccak", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -13324,9 +13211,9 @@ version = "1.0.0" dependencies = [ "clap 4.4.1", "generate-bags", - "kusama-runtime", "polkadot-runtime", "sp-io", + "staging-kusama-runtime", "westend-runtime", ] @@ -14086,7 +13973,6 @@ version = "1.0.0" dependencies = [ "clap 4.4.1", "frame-system", - "kusama-runtime", "kusama-runtime-constants", "log", "pallet-bags-list-remote-tests", @@ -14094,6 +13980,7 @@ dependencies = [ "polkadot-runtime-constants", "sp-core", "sp-tracing", + "staging-kusama-runtime", "tokio", "westend-runtime", "westend-runtime-constants", @@ -14266,10 +14153,10 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -14358,13 +14245,13 @@ dependencies = [ "sp-transaction-pool", "sp-trie", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "static_assertions", "substrate-wasm-builder", "tiny-keccak", "tokio", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -16534,10 +16421,10 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -17851,7 +17738,120 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "staking-miner" +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 0.4.1", + "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-staking-miner" version = "1.0.0" dependencies = [ "assert_cmd", @@ -17863,7 +17863,6 @@ dependencies = [ "frame-system", "futures-util", "jsonrpsee", - "kusama-runtime", "log", "pallet-balances", "pallet-election-provider-multi-phase", @@ -17884,6 +17883,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-version", + "staging-kusama-runtime", "sub-tokens", "thiserror", "tokio", @@ -17891,6 +17891,73 @@ dependencies = [ "westend-runtime", ] +[[package]] +name = "staging-xcm" +version = "1.0.0" +dependencies = [ + "bounded-collections", + "derivative", + "hex", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-weights", + "xcm-procedural", +] + +[[package]] +name = "staging-xcm-builder" +version = "1.0.0" +dependencies = [ + "assert_matches", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-assets", + "pallet-balances", + "pallet-salary", + "pallet-transaction-payment", + "pallet-xcm", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-parachains", + "polkadot-test-runtime", + "primitive-types", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "staging-xcm-executor" +version = "1.0.0" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -20433,13 +20500,13 @@ dependencies = [ "sp-tracing", "sp-transaction-pool", "sp-version", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "substrate-wasm-builder", "tiny-keccak", "tokio", "westend-runtime-constants", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -20794,54 +20861,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xcm" -version = "1.0.0" -dependencies = [ - "bounded-collections", - "derivative", - "hex", - "hex-literal 0.4.1", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-io", - "sp-weights", - "xcm-procedural", -] - -[[package]] -name = "xcm-builder" -version = "1.0.0" -dependencies = [ - "assert_matches", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-assets", - "pallet-balances", - "pallet-salary", - "pallet-transaction-payment", - "pallet-xcm", - "parity-scale-codec", - "polkadot-parachain", - "polkadot-primitives", - "polkadot-runtime-parachains", - "polkadot-test-runtime", - "primitive-types", - "scale-info", - "sp-arithmetic", - "sp-io", - "sp-runtime", - "sp-std", - "sp-weights", - "xcm", - "xcm-executor", -] - [[package]] name = "xcm-emulator" version = "0.1.0" @@ -20871,27 +20890,8 @@ dependencies = [ "sp-runtime", "sp-std", "sp-trie", - "xcm", - "xcm-executor", -] - -[[package]] -name = "xcm-executor" -version = "1.0.0" -dependencies = [ - "environmental", - "frame-benchmarking", - "frame-support", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-weights", - "xcm", + "staging-xcm", + "staging-xcm-executor", ] [[package]] @@ -20911,8 +20911,8 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-tracing", - "xcm", - "xcm-executor", + "staging-xcm", + "staging-xcm-executor", ] [[package]] @@ -20937,9 +20937,9 @@ dependencies = [ "polkadot-runtime-parachains", "sp-io", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -20963,9 +20963,9 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "xcm-simulator", ] @@ -20989,9 +20989,9 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "xcm-simulator", ] diff --git a/cumulus/bridges/bin/runtime-common/Cargo.toml b/cumulus/bridges/bin/runtime-common/Cargo.toml index 6c0f576a7dd..b139f835c1a 100644 --- a/cumulus/bridges/bin/runtime-common/Cargo.toml +++ b/cumulus/bridges/bin/runtime-common/Cargo.toml @@ -41,8 +41,8 @@ sp-std = { path = "../../../../substrate/primitives/std", default-features = fal sp-trie = { path = "../../../../substrate/primitives/trie", default-features = false } # Polkadot dependencies -xcm = { path = "../../../../polkadot/xcm", default-features = false } -xcm-builder = { path = "../../../../polkadot/xcm/xcm-builder", 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 } [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 4f244a9e6a7..6ad3c57ca73 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -26,8 +26,8 @@ sp-std = { path = "../../../../substrate/primitives/std", default-features = fal # Polkadot Dependencies -xcm = { path = "../../../../polkadot/xcm", default-features = false } -xcm-builder = { path = "../../../../polkadot/xcm/xcm-builder", 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 } [dev-dependencies] sp-io = { path = "../../../../substrate/primitives/io" } diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index db654b4c132..9d61a2c99fd 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -17,7 +17,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false} # Polkadot -xcm = { path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 6dab4f75d7d..b72a7924be5 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -29,7 +29,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features # Polkadot polkadot-parachain = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} -xcm = { path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} # Cumulus cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false } diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 42a9d52993c..229edaaab4c 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -14,7 +14,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} cumulus-primitives-core = { path = "../../primitives/core", default-features = false } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 919749c0f45..de4ad61de9e 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -19,8 +19,8 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false} # Polkadot polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -35,7 +35,7 @@ sp-core = { path = "../../../substrate/primitives/core" } pallet-balances = { path = "../../../substrate/frame/balances" } # Polkadot -xcm-builder = { path = "../../../polkadot/xcm/xcm-builder" } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder" } # Cumulus cumulus-pallet-parachain-system = { path = "../parachain-system" } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 09938ede01a..186ab634682 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -56,7 +56,7 @@ substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } # Polkadot polkadot-cli = { path = "../../../polkadot/cli", features = ["rococo-native"] } polkadot-primitives = { path = "../../../polkadot/primitives" } -xcm = { path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} # Cumulus cumulus-client-cli = { path = "../../client/cli" } diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index b321d6e3160..0a7801c99bc 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -56,9 +56,9 @@ sp-version = { path = "../../../substrate/primitives/version", default-features pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain = { path = "../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 1b790dd5b6f..0c863b7295b 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -29,9 +29,9 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false # Polkadot polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 7c870e0220c..78d6b0925bb 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -25,8 +25,8 @@ polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives" polkadot-parachain = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus 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 index 174091d881b..0d415f8d74f 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -23,8 +23,8 @@ polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives" polkadot-parachain = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus 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 798ba7d3f3a..847ab2fa9f8 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 @@ -25,8 +25,8 @@ polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives" polkadot-parachain = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus 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 e81e7a19489..4a4bdeb9b1f 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 @@ -23,8 +23,8 @@ polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives" polkadot-parachain = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index accb04db7f3..d23c511a706 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -25,8 +25,8 @@ polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives" polkadot-parachain = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index e14969deeab..97a5868adc6 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -36,14 +36,14 @@ polkadot-primitives = { path = "../../../../../polkadot/primitives", default-fea polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../polkadot/runtime/polkadot" } polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/constants" } -kusama-runtime = { path = "../../../../../polkadot/runtime/kusama" } +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" } westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants" } -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index e214081ab04..f0afa63d692 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -13,7 +13,7 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime", default-featur frame-support = { path = "../../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../../substrate/frame/system", default-features = false} -xcm = { path = "../../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } cumulus-pallet-xcm = { path = "../../../pallets/xcm", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index e085ee24c60..1eca60a81e5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -61,9 +61,9 @@ pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchma polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index b008b21b12d..813a0a33c2a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -56,9 +56,9 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d polkadot-parachain = { 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 = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 51df6591488..14f1e541091 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -59,9 +59,9 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index cdb7b87dacb..a8b5f3f8c6b 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -21,9 +21,9 @@ pallet-asset-tx-payment = { path = "../../../../../substrate/frame/transaction-p # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 parachains-common = { path = "../../../common", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index baf66a15872..332a3f8a7f1 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -35,8 +35,8 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } # Polkadot -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} 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 1370838fec1..b1695f4abcd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -54,9 +54,9 @@ pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchma polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } 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 a9c14af6dd3..1dfa84f338f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -54,9 +54,9 @@ pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchma polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } 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 af187bdb40e..93fc1d82430 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -54,9 +54,9 @@ pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchma polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 18a8d56a60e..73678e8f91a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -37,9 +37,9 @@ parachains-runtimes-test-utils = { path = "../../test-utils", default-features = # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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} # Bridges bp-bridge-hub-rococo = { path = "../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 59046ff1209..be9c0fc9952 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -58,9 +58,9 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d polkadot-parachain = { 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 = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 266437a4821..ea24392657f 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -57,9 +57,9 @@ pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 4973021d300..0caf00340d3 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -31,9 +31,9 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} # Polkadot -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index d7afc8be864..6f904605710 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -25,9 +25,9 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} # Polkadot -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 76ce2b9907e..76be24b6118 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -35,8 +35,8 @@ cumulus-test-relay-sproof-builder = { path = "../../../test/relay-sproof-builder parachain-info = { path = "../../pallets/parachain-info", default-features = false } # Polkadot -xcm = { path = "../../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain = { path = "../../../../polkadot/parachain", default-features = false} diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index cd36927afec..711d2542f12 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -58,9 +58,9 @@ polkadot-primitives = { path = "../../../../../polkadot/primitives", default-fea pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 361f7759199..43f25d72e33 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -38,9 +38,9 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} -xcm = { path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { path = "../../../../../polkadot/xcm/xcm-executor", 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 } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index aff88e1fa6e..766bd34a0dd 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -77,7 +77,7 @@ substrate-state-trie-migration-rpc = { path = "../../substrate/utils/frame/rpc/s polkadot-cli = { path = "../../polkadot/cli", features = ["rococo-native"] } polkadot-primitives = { path = "../../polkadot/primitives" } polkadot-service = { path = "../../polkadot/node/service" } -xcm = { path = "../../polkadot/xcm" } +xcm = { package = "staging-xcm", path = "../../polkadot/xcm" } # Cumulus cumulus-client-cli = { path = "../client/cli" } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index fdbef574773..761ca04d152 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -18,7 +18,7 @@ sp-trie = { path = "../../../substrate/primitives/trie", default-features = fals polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false} polkadot-parachain = { path = "../../../polkadot/parachain", default-features = false} polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} [features] default = [ "std" ] diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 27f3996b885..47c5442574f 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -16,9 +16,9 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false} # Polkadot polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} -xcm = { path = "../../../polkadot/xcm", default-features = false} -xcm-executor = { path = "../../../polkadot/xcm/xcm-executor", default-features = false} -xcm-builder = { path = "../../../polkadot/xcm/xcm-builder", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false} # Cumulus diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 58666ec39ec..c95c2f70313 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -36,7 +36,7 @@ cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } parachains-common = { path = "../../parachains/common" } # Polkadot -xcm = { path = "../../../polkadot/xcm" } -xcm-executor = { path = "../../../polkadot/xcm/xcm-executor" } +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm" } +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor" } polkadot-primitives = { path = "../../../polkadot/primitives" } polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 0948a3c55d2..6a8c09821be 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -113,7 +113,7 @@ westend-runtime-constants = { path = "../../runtime/westend/constants", optional # Polkadot Runtimes polkadot-runtime = { path = "../../runtime/polkadot", optional = true } -kusama-runtime = { path = "../../runtime/kusama", 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 } diff --git a/polkadot/node/test/performance-test/Cargo.toml b/polkadot/node/test/performance-test/Cargo.toml index 0c5192571b2..98b67615a6f 100644 --- a/polkadot/node/test/performance-test/Cargo.toml +++ b/polkadot/node/test/performance-test/Cargo.toml @@ -20,7 +20,7 @@ polkadot-primitives = { path = "../../../primitives" } sc-executor-common = { path = "../../../../substrate/client/executor/common" } sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob" } -kusama-runtime = { path = "../../../runtime/kusama" } +kusama-runtime = { package = "staging-kusama-runtime", path = "../../../runtime/kusama" } [[bin]] name = "gen-ref-constants" diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 7574374b46a..83aa70cd308 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -49,7 +49,7 @@ libsecp256k1 = { version = "0.7.0", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } slot-range-helper = { path = "slot_range_helper", default-features = false } -xcm = { path = "../../xcm", default-features = false } +xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } [dev-dependencies] hex-literal = "0.4.1" diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index e226b510739..96a00743545 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "kusama-runtime" +name = "staging-kusama-runtime" build = "build.rs" version = "1.0.0" authors.workspace = true @@ -107,9 +107,9 @@ runtime-common = { package = "polkadot-runtime-common", path = "../common", defa runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } -xcm = { package = "xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", 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"] } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 865ab44ac54..8531741395f 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -40,8 +40,8 @@ frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-f frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } -xcm = { package = "xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", 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 } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } rand = { version = "0.8.5", default-features = false } diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 7458df46351..48f720caa64 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -98,9 +98,9 @@ runtime-common = { package = "polkadot-runtime-common", path = "../common", defa runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } -xcm = { package = "xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", 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" diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index cec95481633..4c268c3e2b6 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -89,9 +89,9 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain = { path = "../../parachain", default-features = false } -xcm = { package = "xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", 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"] } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 3413319410d..2d24c0077bf 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -61,9 +61,9 @@ primitives = { package = "polkadot-primitives", path = "../../primitives", defau pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } polkadot-parachain = { path = "../../parachain", default-features = false } polkadot-runtime-parachains = { path = "../parachains", default-features = false } -xcm-builder = { path = "../../xcm/xcm-builder", default-features = false } -xcm-executor = { path = "../../xcm/xcm-executor", default-features = false } -xcm = { path = "../../xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } +xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } [dev-dependencies] hex-literal = "0.4.1" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index b1f9cf6f0cc..add80488a64 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -100,9 +100,9 @@ primitives = { package = "polkadot-primitives", path = "../../primitives", defau polkadot-parachain = { path = "../../parachain", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } -xcm = { package = "xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", 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" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 1fdd6a107c6..88911d3f6ac 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -12,5 +12,5 @@ generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } westend-runtime = { path = "../../runtime/westend" } -kusama-runtime = { path = "../../runtime/kusama" } +kusama-runtime = { package = "staging-kusama-runtime", path = "../../runtime/kusama" } polkadot-runtime = { path = "../../runtime/polkadot" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index d1019317f6d..871eb0a9329 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true [dependencies] polkadot-runtime = { path = "../../../runtime/polkadot" } -kusama-runtime = { path = "../../../runtime/kusama" } +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" } diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml index b9cddcb656e..b9ddca12660 100644 --- a/polkadot/utils/staking-miner/Cargo.toml +++ b/polkadot/utils/staking-miner/Cargo.toml @@ -1,9 +1,9 @@ [[bin]] -name = "staking-miner" +name = "staging-staking-miner" path = "src/main.rs" [package] -name = "staking-miner" +name = "staging-staking-miner" version = "1.0.0" authors.workspace = true edition.workspace = true @@ -42,7 +42,7 @@ core-primitives = { package = "polkadot-core-primitives", path = "../../core-pri runtime-common = { package = "polkadot-runtime-common", path = "../../runtime/common" } polkadot-runtime = { path = "../../runtime/polkadot" } -kusama-runtime = { path = "../../runtime/kusama" } +kusama-runtime = { package = "staging-kusama-runtime", path = "../../runtime/kusama" } westend-runtime = { path = "../../runtime/westend" } exitcode = "1.1" diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 6f442b14769..3c9fd026717 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "xcm" +name = "staging-xcm" description = "The basic XCM datastructures." version = "1.0.0" authors.workspace = true diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 416f5c4bd6e..35b0b7dc553 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -16,10 +16,10 @@ frame-system = { path = "../../../substrate/frame/system", default-features = fa sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} sp-std = { path = "../../../substrate/primitives/std", default-features = false} sp-io = { path = "../../../substrate/primitives/io", default-features = false} -xcm-executor = { path = "../xcm-executor", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false} -xcm = { path = "..", default-features = false } -xcm-builder = { path = "../xcm-builder", default-features = false } +xcm = { package = "staging-xcm", path = "..", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } log = "0.4.17" [dev-dependencies] @@ -27,7 +27,7 @@ pallet-balances = { path = "../../../substrate/frame/balances" } pallet-assets = { path = "../../../substrate/frame/assets" } sp-core = { path = "../../../substrate/primitives/core" } sp-tracing = { path = "../../../substrate/primitives/tracing" } -xcm = { path = ".." } +xcm = { package = "staging-xcm", path = ".." } # temp pallet-xcm = { path = "../pallet-xcm" } polkadot-runtime-common = { path = "../../runtime/common" } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 1fd44d882e6..6c010fd9343 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -21,14 +21,14 @@ sp-io = { path = "../../../substrate/primitives/io", default-features = false} sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} sp-std = { path = "../../../substrate/primitives/std", default-features = false} -xcm = { path = "..", default-features = false } -xcm-executor = { path = "../xcm-executor", default-features = false } +xcm = { package = "staging-xcm", path = "..", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } [dev-dependencies] pallet-balances = { path = "../../../substrate/frame/balances" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain = { path = "../../parachain" } -xcm-builder = { path = "../xcm-builder" } +xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } [features] default = [ "std" ] diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index ea44ce9aa73..11911d377cd 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "xcm-builder" +name = "staging-xcm-builder" description = "Tools & types for building with XCM and its executor." authors.workspace = true edition.workspace = true @@ -10,8 +10,8 @@ version = "1.0.0" impl-trait-for-tuples = "0.2.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -xcm = { path = "..", default-features = false } -xcm-executor = { path = "../xcm-executor", default-features = false } +xcm = { package = "staging-xcm", path = "..", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index f799be7e401..56502c445c2 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -30,6 +30,8 @@ use polkadot_runtime_parachains::{configuration, origin, shared}; use xcm::latest::{opaque, prelude::*}; use xcm_executor::XcmExecutor; +use staging_xcm_builder as xcm_builder; + use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 7a7eb75a80e..902f55901d6 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "xcm-executor" +name = "staging-xcm-executor" description = "An abstract and configurable XCM message executor." authors.workspace = true edition.workspace = true @@ -10,7 +10,7 @@ version = "1.0.0" impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -xcm = { path = "..", default-features = false } +xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index d1db6cccddc..d869fc6f2dc 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -20,8 +20,8 @@ sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } -xcm = { path = "../..", default-features = false } -xcm-executor = { path = ".." } +xcm = { package = "staging-xcm", path = "../..", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = ".." } sp-tracing = { path = "../../../../substrate/primitives/tracing" } [features] diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index cde85649778..fb9a8f68562 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -14,9 +14,9 @@ frame-support = { path = "../../../substrate/frame/support" } sp-io = { path = "../../../substrate/primitives/io" } sp-std = { path = "../../../substrate/primitives/std" } -xcm = { path = ".." } -xcm-executor = { path = "../xcm-executor" } -xcm-builder = { path = "../xcm-builder" } +xcm = { package = "staging-xcm", path = ".." } +xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor" } +xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } polkadot-core-primitives = { path = "../../core-primitives" } polkadot-parachain = { path = "../../parachain" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 06635938e1a..e29c1c0d1f2 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -22,10 +22,10 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime" } sp-io = { path = "../../../../substrate/primitives/io" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } -xcm = { path = "../.." } +xcm = { package = "staging-xcm", path = "../.." } xcm-simulator = { path = ".." } -xcm-executor = { path = "../../xcm-executor" } -xcm-builder = { path = "../../xcm-builder" } +xcm-executor = { package = "staging-xcm-executor", path = "../../xcm-executor" } +xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-runtime-parachains = { path = "../../../runtime/parachains" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index bfc96656bcf..a6258a83f9f 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -22,10 +22,10 @@ sp-core = { path = "../../../../substrate/primitives/core" } sp-runtime = { path = "../../../../substrate/primitives/runtime" } sp-io = { path = "../../../../substrate/primitives/io" } -xcm = { path = "../.." } +xcm = { package = "staging-xcm", path = "../.." } xcm-simulator = { path = ".." } -xcm-executor = { path = "../../xcm-executor" } -xcm-builder = { path = "../../xcm-builder" } +xcm-executor = { package = "staging-xcm-executor", path = "../../xcm-executor" } +xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-runtime-parachains = { path = "../../../runtime/parachains" } -- GitLab From b46f07ff7144b40051fd995d77a8fbd808ecc238 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:58:37 +0300 Subject: [PATCH 026/633] Fix polkadot zombienet tests (#1276) * fix tests Signed-off-by: Andrei Sandu * ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE Signed-off-by: Andrei Sandu * deleted by mistake Signed-off-by: Andrei Sandu * remove LOCAL_DIR override Signed-off-by: Andrei Sandu * Fix secondary image Signed-off-by: Andrei Sandu * fix get BUILD_RELEASE_VERSION in pipeline --------- Signed-off-by: Andrei Sandu Co-authored-by: Javier Viola --- .gitlab/pipeline/zombienet/polkadot.yml | 45 +++++++++++++++++-- ...=> 0004-parachains-garbage-candidate.toml} | 0 ...> 0004-parachains-garbage-candidate.zndsl} | 2 +- ...005-parachains-disputes-past-session.toml} | 0 ...05-parachains-disputes-past-session.zndsl} | 2 +- 5 files changed, 43 insertions(+), 6 deletions(-) rename polkadot/zombienet_tests/functional/{0003-parachains-garbage-candidate.toml => 0004-parachains-garbage-candidate.toml} (100%) rename polkadot/zombienet_tests/functional/{0003-parachains-garbage-candidate.zndsl => 0004-parachains-garbage-candidate.zndsl} (98%) rename polkadot/zombienet_tests/functional/{0004-parachains-disputes-past-session.toml => 0005-parachains-disputes-past-session.toml} (100%) rename polkadot/zombienet_tests/functional/{0004-parachains-disputes-past-session.zndsl => 0005-parachains-disputes-past-session.zndsl} (97%) diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index e4c56a7d620..87b821742c6 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -4,19 +4,24 @@ # common settings for all zombienet jobs .zombienet-polkadot-common: before_script: + - export BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" # from build-linux-stable job - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} + - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - export MALUS_IMAGE="${MALUS_IMAGE}":${PIPELINE_IMAGE_TAG} - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" - echo "local-dir ${LOCAL_DIR}" - echo "polkadot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" + - echo "polkadot secondary image ${ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}" - echo "colander image ${COL_IMAGE}" - echo "malus image ${MALUS_IMAGE}" stage: zombienet image: "${ZOMBIENET_IMAGE}" needs: + - job: build-linux-stable + artifacts: true - job: build-push-image-malus artifacts: true - job: build-push-image-polkadot-debug @@ -64,21 +69,29 @@ zombienet-polkadot-functional-0002-parachains-disputes: --local-dir="${LOCAL_DIR}/functional" --test="0002-parachains-disputes.zndsl" -zombienet-polkadot-functional-0003-parachains-disputes-garbage-candidate: +zombienet-polkadot-functional-0003-beefy-and-mmr: extends: - .zombienet-polkadot-common script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/functional" - --test="0003-parachains-garbage-candidate.zndsl" + --test="0003-beefy-and-mmr.zndsl" -zombienet-polkadot-functional-0004-beefy-and-mmr: +zombienet-polkadot-functional-0004-parachains-disputes-garbage-candidate: extends: - .zombienet-polkadot-common script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/functional" - --test="0003-beefy-and-mmr.zndsl" + --test="0004-parachains-garbage-candidate.zndsl" + +zombienet-polkadot-functional-0005-parachains-disputes-past-session: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0005-parachains-disputes-past-session.zndsl" zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: @@ -168,3 +181,27 @@ 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/polkadot/zombienet_tests/functional/0003-parachains-garbage-candidate.toml b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml similarity index 100% rename from polkadot/zombienet_tests/functional/0003-parachains-garbage-candidate.toml rename to polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml diff --git a/polkadot/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.zndsl similarity index 98% rename from polkadot/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl rename to polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.zndsl index c4fd3ee7c55..be2ae9504b8 100644 --- a/polkadot/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl +++ b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.zndsl @@ -1,5 +1,5 @@ Description: Test dispute finality lag when 1/3 of parachain validators always attempt to include an invalid block -Network: ./0003-parachains-garbage-candidate.toml +Network: ./0004-parachains-garbage-candidate.toml Creds: config # Check authority status. diff --git a/polkadot/zombienet_tests/functional/0004-parachains-disputes-past-session.toml b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml similarity index 100% rename from polkadot/zombienet_tests/functional/0004-parachains-disputes-past-session.toml rename to polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml diff --git a/polkadot/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl similarity index 97% rename from polkadot/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl rename to polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl index bf3fb0ac9de..bc3674f4f53 100644 --- a/polkadot/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl +++ b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl @@ -1,5 +1,5 @@ Description: Past-session dispute slashing -Network: ./0004-parachains-disputes-past-session.toml +Network: ./0005-parachains-disputes-past-session.toml Creds: config # Ensure nodes are up and running -- GitLab From 43c0c09bcb9a4db0856598dd07357c0b7292bb84 Mon Sep 17 00:00:00 2001 From: Lulu Date: Wed, 30 Aug 2023 17:04:21 +0200 Subject: [PATCH 027/633] Symlink chain-specs json files to crate where they are used (#1171) When publishing crates, each crate becomes it's own tarball that can't access files from other crates. So symlink the files to be crate local and cargo will replace the symlinks with real files at publish time. We can't just move all of them as it makes the package larger than the max crates.io package size. Co-authored-by: Javier Viola --- .../chain-specs/asset-hub-kusama.json | 1 + .../chain-specs/asset-hub-polkadot.json | 1 + .../chain-specs/asset-hub-westend.json | 1 + .../chain-specs/bridge-hub-kusama.json | 1 + .../chain-specs/bridge-hub-polkadot.json | 1 + .../chain-specs/bridge-hub-rococo.json | 1 + .../chain-specs/bridge-hub-westend.json | 1 + .../chain-specs/bridge-hub-wococo.json | 1 + .../chain-specs/collectives-polkadot.json | 1 + .../chain-specs/collectives-westend.json | 1 + .../chain-specs/contracts-rococo.json | 1 + .../polkadot-parachain/chain-specs/tick.json | 1 + .../polkadot-parachain/chain-specs/track.json | 1 + .../polkadot-parachain/chain-specs/trick.json | 1 + .../src/chain_spec/bridge_hubs.rs | 10 +++++----- cumulus/polkadot-parachain/src/command.rs | 18 +++++++++--------- 16 files changed, 28 insertions(+), 14 deletions(-) create mode 120000 cumulus/polkadot-parachain/chain-specs/asset-hub-kusama.json create mode 120000 cumulus/polkadot-parachain/chain-specs/asset-hub-polkadot.json create mode 120000 cumulus/polkadot-parachain/chain-specs/asset-hub-westend.json create mode 120000 cumulus/polkadot-parachain/chain-specs/bridge-hub-kusama.json create mode 120000 cumulus/polkadot-parachain/chain-specs/bridge-hub-polkadot.json create mode 120000 cumulus/polkadot-parachain/chain-specs/bridge-hub-rococo.json create mode 120000 cumulus/polkadot-parachain/chain-specs/bridge-hub-westend.json create mode 120000 cumulus/polkadot-parachain/chain-specs/bridge-hub-wococo.json create mode 120000 cumulus/polkadot-parachain/chain-specs/collectives-polkadot.json create mode 120000 cumulus/polkadot-parachain/chain-specs/collectives-westend.json create mode 120000 cumulus/polkadot-parachain/chain-specs/contracts-rococo.json create mode 120000 cumulus/polkadot-parachain/chain-specs/tick.json create mode 120000 cumulus/polkadot-parachain/chain-specs/track.json create mode 120000 cumulus/polkadot-parachain/chain-specs/trick.json diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-kusama.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-kusama.json new file mode 120000 index 00000000000..89a3015b50a --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-kusama.json @@ -0,0 +1 @@ +../../parachains/chain-specs/asset-hub-kusama.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-polkadot.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-polkadot.json new file mode 120000 index 00000000000..43a1cb41131 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-polkadot.json @@ -0,0 +1 @@ +../../parachains/chain-specs/asset-hub-polkadot.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-westend.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-westend.json new file mode 120000 index 00000000000..03742c40162 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-westend.json @@ -0,0 +1 @@ +../../parachains/chain-specs/asset-hub-westend.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/bridge-hub-kusama.json b/cumulus/polkadot-parachain/chain-specs/bridge-hub-kusama.json new file mode 120000 index 00000000000..fc91654c6ff --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/bridge-hub-kusama.json @@ -0,0 +1 @@ +../../parachains/chain-specs/bridge-hub-kusama.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/bridge-hub-polkadot.json b/cumulus/polkadot-parachain/chain-specs/bridge-hub-polkadot.json new file mode 120000 index 00000000000..df22d3e8800 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/bridge-hub-polkadot.json @@ -0,0 +1 @@ +../../parachains/chain-specs/bridge-hub-polkadot.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/bridge-hub-rococo.json b/cumulus/polkadot-parachain/chain-specs/bridge-hub-rococo.json new file mode 120000 index 00000000000..8970d92bcf5 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/bridge-hub-rococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/bridge-hub-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/bridge-hub-westend.json b/cumulus/polkadot-parachain/chain-specs/bridge-hub-westend.json new file mode 120000 index 00000000000..9f9e4dad5c1 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/bridge-hub-westend.json @@ -0,0 +1 @@ +../../parachains/chain-specs/bridge-hub-westend.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/bridge-hub-wococo.json b/cumulus/polkadot-parachain/chain-specs/bridge-hub-wococo.json new file mode 120000 index 00000000000..e13ab77265d --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/bridge-hub-wococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/bridge-hub-wococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/collectives-polkadot.json b/cumulus/polkadot-parachain/chain-specs/collectives-polkadot.json new file mode 120000 index 00000000000..afece75567b --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/collectives-polkadot.json @@ -0,0 +1 @@ +../../parachains/chain-specs/collectives-polkadot.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/collectives-westend.json b/cumulus/polkadot-parachain/chain-specs/collectives-westend.json new file mode 120000 index 00000000000..84e23b06fb4 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/collectives-westend.json @@ -0,0 +1 @@ +../../parachains/chain-specs/collectives-westend.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json b/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json new file mode 120000 index 00000000000..b9f8e8f31e8 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/contracts-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/tick.json b/cumulus/polkadot-parachain/chain-specs/tick.json new file mode 120000 index 00000000000..47c93a98405 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/tick.json @@ -0,0 +1 @@ +../../parachains/chain-specs/tick.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/track.json b/cumulus/polkadot-parachain/chain-specs/track.json new file mode 120000 index 00000000000..9474c223a94 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/track.json @@ -0,0 +1 @@ +../../parachains/chain-specs/track.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/trick.json b/cumulus/polkadot-parachain/chain-specs/trick.json new file mode 120000 index 00000000000..de1fb9edf30 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/trick.json @@ -0,0 +1 @@ +../../parachains/chain-specs/trick.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index b151b2fd615..4cb81f57081 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -97,7 +97,7 @@ impl BridgeHubRuntimeType { match self { BridgeHubRuntimeType::Polkadot => Ok(Box::new(polkadot::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/bridge-hub-polkadot.json")[..], + &include_bytes!("../../chain-specs/bridge-hub-polkadot.json")[..], )?)), BridgeHubRuntimeType::PolkadotLocal => Ok(Box::new(polkadot::local_config( polkadot::BRIDGE_HUB_POLKADOT_LOCAL, @@ -113,7 +113,7 @@ impl BridgeHubRuntimeType { ))), BridgeHubRuntimeType::Kusama => Ok(Box::new(kusama::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/bridge-hub-kusama.json")[..], + &include_bytes!("../../chain-specs/bridge-hub-kusama.json")[..], )?)), BridgeHubRuntimeType::KusamaLocal => Ok(Box::new(kusama::local_config( kusama::BRIDGE_HUB_KUSAMA_LOCAL, @@ -129,11 +129,11 @@ impl BridgeHubRuntimeType { ))), BridgeHubRuntimeType::Westend => Ok(Box::new(westend::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/bridge-hub-westend.json")[..], + &include_bytes!("../../chain-specs/bridge-hub-westend.json")[..], )?)), BridgeHubRuntimeType::Rococo => Ok(Box::new(rococo::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/bridge-hub-rococo.json")[..], + &include_bytes!("../../chain-specs/bridge-hub-rococo.json")[..], )?)), BridgeHubRuntimeType::RococoLocal => Ok(Box::new(rococo::local_config( rococo::BRIDGE_HUB_ROCOCO_LOCAL, @@ -153,7 +153,7 @@ impl BridgeHubRuntimeType { ))), BridgeHubRuntimeType::Wococo => Ok(Box::new(wococo::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/bridge-hub-wococo.json")[..], + &include_bytes!("../../chain-specs/bridge-hub-wococo.json")[..], )?)), BridgeHubRuntimeType::WococoLocal => Ok(Box::new(wococo::local_config( wococo::BRIDGE_HUB_WOCOCO_LOCAL, diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 1814d820058..596b7baf671 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -121,15 +121,15 @@ fn load_spec(id: &str) -> std::result::Result, String> { Box::new(chain_spec::rococo_parachain::staging_rococo_parachain_local_config()), "tick" => Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/tick.json")[..], + &include_bytes!("../chain-specs/tick.json")[..], )?), "trick" => Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/trick.json")[..], + &include_bytes!("../chain-specs/trick.json")[..], )?), "track" => Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/track.json")[..], + &include_bytes!("../chain-specs/track.json")[..], )?), // -- Starters @@ -147,7 +147,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { // the shell-based chain spec as used for syncing "asset-hub-polkadot" | "statemint" => Box::new(chain_spec::asset_hubs::AssetHubPolkadotChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/asset-hub-polkadot.json")[..], + &include_bytes!("../chain-specs/asset-hub-polkadot.json")[..], )?), // -- Asset Hub Kusama @@ -161,7 +161,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { // the shell-based chain spec as used for syncing "asset-hub-kusama" | "statemine" => Box::new(chain_spec::asset_hubs::AssetHubKusamaChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/asset-hub-kusama.json")[..], + &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], )?), // -- Asset Hub Westend @@ -175,7 +175,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { // the shell-based chain spec as used for syncing "asset-hub-westend" | "westmint" => Box::new(chain_spec::asset_hubs::AssetHubWestendChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/asset-hub-westend.json")[..], + &include_bytes!("../chain-specs/asset-hub-westend.json")[..], )?), // -- Polkadot Collectives @@ -185,11 +185,11 @@ fn load_spec(id: &str) -> std::result::Result, String> { Box::new(chain_spec::collectives::collectives_polkadot_local_config()), "collectives-polkadot" => Box::new(chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/collectives-polkadot.json")[..], + &include_bytes!("../chain-specs/collectives-polkadot.json")[..], )?), "collectives-westend" => Box::new(chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/collectives-westend.json")[..], + &include_bytes!("../chain-specs/collectives-westend.json")[..], )?), // -- Contracts on Rococo @@ -200,7 +200,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { "contracts-rococo-genesis" => Box::new(chain_spec::contracts::contracts_rococo_config()), "contracts-rococo" => Box::new(chain_spec::contracts::ContractsRococoChainSpec::from_json_bytes( - &include_bytes!("../../parachains/chain-specs/contracts-rococo.json")[..], + &include_bytes!("../chain-specs/contracts-rococo.json")[..], )?), // -- BridgeHub -- GitLab From af432f0fc3452aa86027f466a3f2ec2415a29519 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Wed, 30 Aug 2023 14:38:03 -0300 Subject: [PATCH 028/633] fix chain-spec path for substrate tests (#1307) * fix chain-spec path for substrate tests * update chain-spec path for cumulus test --- cumulus/zombienet/tests/0007-full_node_warp_sync.toml | 4 ++-- substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml | 2 +- .../0002-validators-warp-sync/test-validators-warp-sync.toml | 2 +- .../test-block-building-warp-sync.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cumulus/zombienet/tests/0007-full_node_warp_sync.toml b/cumulus/zombienet/tests/0007-full_node_warp_sync.toml index 937c0b83683..42d1de7148d 100644 --- a/cumulus/zombienet/tests/0007-full_node_warp_sync.toml +++ b/cumulus/zombienet/tests/0007-full_node_warp_sync.toml @@ -3,7 +3,7 @@ default_image = "{{RELAY_IMAGE}}" default_command = "polkadot" default_args = [ "-lparachain=debug" ] chain = "rococo-local" -chain_spec_path = "zombienet/tests/0007-warp-sync-relaychain-spec.json" +chain_spec_path = "cumulus/zombienet/tests/0007-warp-sync-relaychain-spec.json" [[relaychain.nodes]] name = "alice" @@ -28,7 +28,7 @@ chain_spec_path = "zombienet/tests/0007-warp-sync-relaychain-spec.json" [[parachains]] id = 2000 cumulus_based = true -chain_spec_path = "zombienet/tests/0007-warp-sync-parachain-spec.json" +chain_spec_path = "cumulus/zombienet/tests/0007-warp-sync-parachain-spec.json" add_to_genesis = false # Run 'dave' as parachain collator. diff --git a/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml b/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml index 272b5862e8e..d14d77cfe62 100644 --- a/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml +++ b/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "zombienet/0001-basic-warp-sync/chain-spec.json" +chain_spec_path = "substrate/zombienet/0001-basic-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "alice" diff --git a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml index df4414f5c8b..8336672ad49 100644 --- a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml +++ b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "zombienet/0002-validators-warp-sync/chain-spec.json" +chain_spec_path = "substrate/zombienet/0002-validators-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "alice" diff --git a/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml b/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml index 5119c919c70..6642ba8fea3 100644 --- a/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml +++ b/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "zombienet/0003-block-building-warp-sync/chain-spec.json" +chain_spec_path = "substrate/zombienet/0003-block-building-warp-sync/chain-spec.json" #we need at least 3 nodes for warp sync [[relaychain.nodes]] -- GitLab From 73915d3459a0723e2ca80a5ca5d0a11a3736b18d Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 30 Aug 2023 21:06:42 +0300 Subject: [PATCH 029/633] add missing feature (#1310) Signed-off-by: Andrei Sandu --- polkadot/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 48bc0877c0f..e3cfda9bd46 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -66,6 +66,7 @@ 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] -- GitLab From 5462409cc00a079a59f1ead28f6e479379249200 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Thu, 31 Aug 2023 04:43:16 +0900 Subject: [PATCH 030/633] Fix typo in statement-store/README.md (#1317) absense -> absence --- substrate/primitives/statement-store/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/statement-store/README.md b/substrate/primitives/statement-store/README.md index fb88aaa4ecd..2cde0d669ee 100644 --- a/substrate/primitives/statement-store/README.md +++ b/substrate/primitives/statement-store/README.md @@ -10,7 +10,7 @@ Each field is effectively a key/value pair. Fields must be sorted and the same f Formally, `Statement` is equivalent to the type `Vec` and `Field` is the SCALE-encoded enumeration: - 0: `AuthenticityProof(Proof)`: The signature of the message. For cryptography where the public key cannot be derived from the signature together with the message data, then this will also include the signer's public key. The message data is all fields of the messages fields except the signature concatenated together *without the length prefix that a `Vec` would usually imply*. This is so that the signature can be derived without needing to re-encode the statement. -- 1: `DecryptionKey([u8; 32])`: The decryption key identifier which should be used to decrypt the statement's data. In the absense of this field `Data` should be treated as not encrypted. +- 1: `DecryptionKey([u8; 32])`: The decryption key identifier which should be used to decrypt the statement's data. In the absence of this field `Data` should be treated as not encrypted. - 2: `Priority(u32)`: Priority specifier. Higher priority statements should be kept around at the cost of lower priority statements if multiple statements from the same sender are competing for persistence or transport. Nodes should disregard when considering unsigned statements. - 3: `Channel([u8; 32])`: The channel identifier. Only one message of a given channel should be retained at once (the one of highest priority). Nodes should disregard when considering unsigned statements. - 4: `Topic1([u8; 32]))`: First topic identifier. -- GitLab From 36b4f2583edd5c951a00cbd1694c96e83e6570e8 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 30 Aug 2023 21:55:41 +0200 Subject: [PATCH 031/633] Fix CI (#1316) * Fix deterministic WASM check Signed-off-by: Oliver Tale-Yazdi * Fix build-staking-miner Signed-off-by: Oliver Tale-Yazdi * Remove Kusama and Polkadot runtime-migration checks Will be removed in https://github.com/paritytech/polkadot-sdk/pull/1304 anyway. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- .gitlab/pipeline/build.yml | 3 +-- .gitlab/pipeline/check.yml | 26 -------------------------- .gitlab/test_deterministic_wasm.sh | 8 +++++--- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 0364c360760..6ea153ff6da 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -88,7 +88,7 @@ build-staking-miner: - job: build-malus artifacts: false script: - - time cargo build --locked --release --package staking-miner + - time cargo build -q --locked --release --package staging-staking-miner # # pack artifacts # - mkdir -p ./artifacts # - mv ./target/release/staking-miner ./artifacts/. @@ -353,4 +353,3 @@ build-subkey-linux: # after_script: [""] # tags: # - osx - diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index efd57ba1d86..f88f5808637 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -121,30 +121,6 @@ test-rust-feature-propagation: --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 -check-runtime-migration-polkadot: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "polkadot" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - -check-runtime-migration-kusama: - stage: check - # DAG - needs: - - job: check-runtime-migration-polkadot - artifacts: false - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "kusama" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 - check-runtime-migration-westend: stage: check extends: @@ -153,7 +129,6 @@ check-runtime-migration-westend: - .check-runtime-migration variables: NETWORK: "westend" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 check-runtime-migration-rococo: stage: check @@ -167,7 +142,6 @@ check-runtime-migration-rococo: - .check-runtime-migration variables: NETWORK: "rococo" - allow_failure: true # FIXME https://github.com/paritytech/substrate/issues/13107 find-fail-ci-phrase: stage: check diff --git a/.gitlab/test_deterministic_wasm.sh b/.gitlab/test_deterministic_wasm.sh index 5b04013e1df..4f1d2981ff2 100755 --- a/.gitlab/test_deterministic_wasm.sh +++ b/.gitlab/test_deterministic_wasm.sh @@ -1,15 +1,17 @@ #!/usr/bin/env bash +set -e #shellcheck source=../common/lib.sh source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/common/lib.sh" # build runtime -WASM_BUILD_NO_COLOR=1 cargo build --verbose --release -p kusama-runtime -p polkadot-runtime -p westend-runtime +WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-runtime # make checksum sha256sum target/release/wbuild/*-runtime/target/wasm32-unknown-unknown/release/*.wasm > checksum.sha256 -# clean up - FIXME: can we reuse some of the artifacts? + cargo clean + # build again -WASM_BUILD_NO_COLOR=1 cargo build --verbose --release -p kusama-runtime -p polkadot-runtime -p westend-runtime +WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-runtime # confirm checksum sha256sum -c checksum.sha256 -- GitLab From 109287f4cac8ac39df344b2b10a2c1d2f8c28d2d Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 31 Aug 2023 07:16:57 +0100 Subject: [PATCH 032/633] Put `GetWeight` where it belongs (#1212) * Put `GetWeight` where it belongs * add GetWeight to v2 * Re-export unchanged trait --------- Co-authored-by: Just van Stam Co-authored-by: Keith Yeung --- polkadot/xcm/src/lib.rs | 5 ----- polkadot/xcm/src/v2/mod.rs | 4 ++-- polkadot/xcm/src/v2/traits.rs | 5 +++++ polkadot/xcm/src/v3/mod.rs | 5 +++-- polkadot/xcm/xcm-builder/src/weight.rs | 5 ++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index a012c5f53fb..52f32f7310b 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -447,11 +447,6 @@ pub mod opaque { pub type VersionedXcm = super::VersionedXcm<()>; } -// A simple trait to get the weight of some object. -pub trait GetWeight { - fn weight(&self) -> latest::Weight; -} - #[test] fn conversion_works() { use latest::prelude::*; diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index 8a67b771c9e..a81468cd481 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -55,7 +55,7 @@ use super::{ NetworkId as NewNetworkId, Response as NewResponse, WeightLimit as NewWeightLimit, Xcm as NewXcm, }, - DoubleEncoded, GetWeight, + DoubleEncoded, }; use alloc::{vec, vec::Vec}; use bounded_collections::{ConstU32, WeakBoundedVec}; @@ -77,7 +77,7 @@ pub use multiasset::{ pub use multilocation::{ Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen, }; -pub use traits::{Error, ExecuteXcm, Outcome, Result, SendError, SendResult, SendXcm}; +pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendResult, SendXcm}; /// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs index ae03cf5547b..80603b4100d 100644 --- a/polkadot/xcm/src/v2/traits.rs +++ b/polkadot/xcm/src/v2/traits.rs @@ -23,6 +23,11 @@ use scale_info::TypeInfo; use super::*; +// A simple trait to get the weight of some object. +pub trait GetWeight { + fn weight(&self) -> sp_weights::Weight; +} + #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] pub enum Error { // Errors that happen due to instructions being executed. These alone are defined in the diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index ef3306d276f..78ea7a58aba 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -20,7 +20,7 @@ use super::v2::{ Instruction as OldInstruction, Response as OldResponse, WeightLimit as OldWeightLimit, Xcm as OldXcm, }; -use crate::{DoubleEncoded, GetWeight}; +use crate::DoubleEncoded; use alloc::{vec, vec::Vec}; use bounded_collections::{parameter_types, BoundedVec, ConstU32}; use core::{ @@ -54,7 +54,7 @@ pub use traits::{ SendResult, SendXcm, Weight, XcmHash, }; // These parts of XCM v2 are unchanged in XCM v3, and are re-imported here. -pub use super::v2::OriginKind; +pub use super::v2::{GetWeight, OriginKind}; /// This module's XCM version. pub const VERSION: super::Version = 3; @@ -186,6 +186,7 @@ pub mod prelude { AssetInstance::{self, *}, BodyId, BodyPart, Error as XcmError, ExecuteXcm, Fungibility::{self, *}, + GetWeight, Instruction::*, InteriorMultiLocation, Junction::{self, *}, diff --git a/polkadot/xcm/xcm-builder/src/weight.rs b/polkadot/xcm/xcm-builder/src/weight.rs index f1c14a4c651..c16c52939a3 100644 --- a/polkadot/xcm/xcm-builder/src/weight.rs +++ b/polkadot/xcm/xcm-builder/src/weight.rs @@ -73,7 +73,7 @@ where W: XcmWeightInfo, C: Decode + GetDispatchInfo, M: Get, - Instruction: xcm::GetWeight, + Instruction: xcm::latest::GetWeight, { fn weight(message: &mut Xcm) -> Result { log::trace!(target: "xcm::weight", "WeightInfoBounds message: {:?}", message); @@ -90,7 +90,7 @@ where W: XcmWeightInfo, C: Decode + GetDispatchInfo, M: Get, - Instruction: xcm::GetWeight, + Instruction: xcm::latest::GetWeight, { fn weight_with_limit(message: &Xcm, instrs_limit: &mut u32) -> Result { let mut r: Weight = Weight::zero(); @@ -104,7 +104,6 @@ where instruction: &Instruction, instrs_limit: &mut u32, ) -> Result { - use xcm::GetWeight; let instr_weight = match instruction { Transact { require_weight_at_most, .. } => *require_weight_at_most, SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?, -- GitLab From 5559b752b41dcd70c321d81c5e418ad15c31edda Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:40:40 +0300 Subject: [PATCH 033/633] substrate: peer_store: log warn on disconnecting because of reputation (#1299) * substrate: peer_store: log error on disconnecting because of reputation Disconnecting and banning a peer because of negative reputation is usually an indicative of one of two things: 1. We've got a bug that forces disconnects. 2. We've got malicious peers that try to attack us. We both cases I don't think we should hide this behind a trace log and we should log errors, so that things are easy to notice and debug/mitigated. Signed-off-by: Alexandru Gheorghe * Move from error to warn Signed-off-by: Alexandru Gheorghe --------- Signed-off-by: Alexandru Gheorghe --- substrate/client/network/src/peer_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/network/src/peer_store.rs b/substrate/client/network/src/peer_store.rs index 2f3d4a1fd1a..35d17e588cb 100644 --- a/substrate/client/network/src/peer_store.rs +++ b/substrate/client/network/src/peer_store.rs @@ -222,7 +222,7 @@ impl PeerStoreInner { if peer_info.reputation < BANNED_THRESHOLD { self.protocols.iter().for_each(|handle| handle.disconnect_peer(peer_id)); - log::trace!( + log::warn!( target: LOG_TARGET, "Report {}: {:+} to {}. Reason: {}. Banned, disconnecting.", peer_id, -- GitLab From 7cef7cdfb0a62c8c16c1f48ab0daaaaf09d04396 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Thu, 31 Aug 2023 10:48:16 +0200 Subject: [PATCH 034/633] PVF: Take back a stolen right (#1207) --- polkadot/node/core/pvf/Cargo.toml | 2 +- polkadot/node/core/pvf/common/src/lib.rs | 7 ++----- polkadot/node/core/pvf/common/src/worker/mod.rs | 4 +++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index eb61b4ccb0e..a10b748e882 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -47,7 +47,7 @@ assert_matches = "1.4.0" hex-literal = "0.3.4" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } # For the puppet worker, depend on ourselves with the test-utils feature. -polkadot-node-core-pvf = { path = "", features = ["test-utils"] } +polkadot-node-core-pvf = { path = ".", features = ["test-utils"] } adder = { package = "test-parachain-adder", path = "../../../parachain/test-parachains/adder" } halt = { package = "test-parachain-halt", path = "../../../parachain/test-parachains/halt" } diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index 2cc9c72e182..c358ad6e134 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -25,11 +25,8 @@ pub mod worker; pub use cpu_time::ProcessTime; -/// DO NOT USE - internal for macros only. -#[doc(hidden)] -pub mod __private { - pub use sp_tracing::try_init_simple; -} +// Used by `decl_worker_main!`. +pub use sp_tracing; const LOG_TARGET: &str = "parachain::pvf-common"; diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index 4ea0e5aa1a9..40e540bb3f7 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -41,7 +41,9 @@ macro_rules! decl_worker_main { } fn main() { - $crate::__private::try_init_simple(); + // TODO: Remove this dependency, and `pub use sp_tracing` in `lib.rs`. + // See . + $crate::sp_tracing::try_init_simple(); let args = std::env::args().collect::>(); if args.len() == 1 { -- GitLab From aabed6757e26e21ce06dd59946a17b72f349185e Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:36:38 +0200 Subject: [PATCH 035/633] [ci] add more jobs for pipeline cancel, cleanup (#1314) --- .gitlab-ci.yml | 55 ++ cumulus/scripts/ci/changelog/.gitignore | 4 - cumulus/scripts/ci/changelog/Gemfile | 23 - cumulus/scripts/ci/changelog/Gemfile.lock | 84 --- cumulus/scripts/ci/changelog/README.md | 78 --- cumulus/scripts/ci/changelog/bin/changelog | 164 ------ .../scripts/ci/changelog/digests/.gitignore | 1 - cumulus/scripts/ci/changelog/digests/.gitkeep | 0 cumulus/scripts/ci/changelog/lib/changelog.rb | 32 -- .../ci/changelog/templates/change.md.tera | 44 -- .../ci/changelog/templates/changes.md.tera | 21 - .../changelog/templates/changes_api.md.tera | 19 - .../templates/changes_client.md.tera | 17 - .../changelog/templates/changes_misc.md.tera | 39 -- .../templates/changes_runtime.md.tera | 19 - .../ci/changelog/templates/compiler.md.tera | 6 - .../ci/changelog/templates/debug.md.tera | 9 - .../changelog/templates/docker_image.md.tera | 11 - .../templates/global_priority.md.tera | 35 -- .../changelog/templates/high_priority.md.tera | 56 -- .../templates/host_functions.md.tera | 38 -- .../changelog/templates/migrations-db.md.tera | 26 - .../templates/migrations-runtime.md.tera | 14 - .../changelog/templates/pre_release.md.tera | 11 - .../ci/changelog/templates/runtime.md.tera | 28 - .../ci/changelog/templates/runtimes.md.tera | 17 - .../ci/changelog/templates/template.md.tera | 38 -- .../scripts/ci/changelog/test/test_basic.rb | 23 - cumulus/scripts/ci/common/lib.sh | 141 ----- cumulus/scripts/ci/create-benchmark-pr.sh | 53 -- cumulus/scripts/ci/github/check-rel-br | 127 ----- cumulus/scripts/ci/github/check_labels.sh | 91 ---- .../ci/github/extrinsic-ordering-filter.sh | 55 -- cumulus/scripts/ci/github/runtime-version.rb | 10 - .../scripts/ci/gitlab/pipeline/benchmarks.yml | 84 --- cumulus/scripts/ci/gitlab/pipeline/build.yml | 138 ----- .../ci/gitlab/pipeline/integration_tests.yml | 2 - .../scripts/ci/gitlab/pipeline/publish.yml | 105 ---- .../ci/gitlab/pipeline/short-benchmarks.yml | 56 -- cumulus/scripts/ci/gitlab/pipeline/test.yml | 111 ---- .../scripts/ci/gitlab/pipeline/zombienet.yml | 141 ----- cumulus/scripts/ci/gitlab/prettier.sh | 6 - substrate/scripts/ci/common/lib.sh | 117 ----- substrate/scripts/ci/github/check_labels.sh | 68 --- .../scripts/ci/github/generate_changelog.sh | 85 --- .../scripts/ci/gitlab/check-each-crate.py | 57 -- substrate/scripts/ci/gitlab/check_runtime.sh | 121 ----- substrate/scripts/ci/gitlab/check_signed.sh | 16 - substrate/scripts/ci/gitlab/ensure-deps.sh | 80 --- .../scripts/ci/gitlab/pipeline/build.yml | 215 -------- .../scripts/ci/gitlab/pipeline/check.yml | 78 --- .../scripts/ci/gitlab/pipeline/publish.yml | 270 ---------- substrate/scripts/ci/gitlab/pipeline/test.yml | 494 ------------------ .../scripts/ci/gitlab/pipeline/zombienet.yml | 67 --- substrate/scripts/ci/gitlab/prettier.sh | 6 - .../ci/gitlab/publish_draft_release.sh | 54 -- 56 files changed, 55 insertions(+), 3705 deletions(-) delete mode 100644 cumulus/scripts/ci/changelog/.gitignore delete mode 100644 cumulus/scripts/ci/changelog/Gemfile delete mode 100644 cumulus/scripts/ci/changelog/Gemfile.lock delete mode 100644 cumulus/scripts/ci/changelog/README.md delete mode 100755 cumulus/scripts/ci/changelog/bin/changelog delete mode 100644 cumulus/scripts/ci/changelog/digests/.gitignore delete mode 100644 cumulus/scripts/ci/changelog/digests/.gitkeep delete mode 100644 cumulus/scripts/ci/changelog/lib/changelog.rb delete mode 100644 cumulus/scripts/ci/changelog/templates/change.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/changes.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/changes_api.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/changes_client.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/changes_misc.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/changes_runtime.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/compiler.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/debug.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/docker_image.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/global_priority.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/high_priority.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/host_functions.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/migrations-db.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/migrations-runtime.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/pre_release.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/runtime.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/runtimes.md.tera delete mode 100644 cumulus/scripts/ci/changelog/templates/template.md.tera delete mode 100755 cumulus/scripts/ci/changelog/test/test_basic.rb delete mode 100644 cumulus/scripts/ci/common/lib.sh delete mode 100755 cumulus/scripts/ci/create-benchmark-pr.sh delete mode 100755 cumulus/scripts/ci/github/check-rel-br delete mode 100755 cumulus/scripts/ci/github/check_labels.sh delete mode 100755 cumulus/scripts/ci/github/extrinsic-ordering-filter.sh delete mode 100644 cumulus/scripts/ci/github/runtime-version.rb delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/benchmarks.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/build.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/integration_tests.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/publish.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/short-benchmarks.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/test.yml delete mode 100644 cumulus/scripts/ci/gitlab/pipeline/zombienet.yml delete mode 100755 cumulus/scripts/ci/gitlab/prettier.sh delete mode 100755 substrate/scripts/ci/common/lib.sh delete mode 100755 substrate/scripts/ci/github/check_labels.sh delete mode 100755 substrate/scripts/ci/github/generate_changelog.sh delete mode 100755 substrate/scripts/ci/gitlab/check-each-crate.py delete mode 100755 substrate/scripts/ci/gitlab/check_runtime.sh delete mode 100755 substrate/scripts/ci/gitlab/check_signed.sh delete mode 100755 substrate/scripts/ci/gitlab/ensure-deps.sh delete mode 100644 substrate/scripts/ci/gitlab/pipeline/build.yml delete mode 100644 substrate/scripts/ci/gitlab/pipeline/check.yml delete mode 100644 substrate/scripts/ci/gitlab/pipeline/publish.yml delete mode 100644 substrate/scripts/ci/gitlab/pipeline/test.yml delete mode 100644 substrate/scripts/ci/gitlab/pipeline/zombienet.yml delete mode 100755 substrate/scripts/ci/gitlab/prettier.sh delete mode 100755 substrate/scripts/ci/gitlab/publish_draft_release.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9e7346601ba..2e0465ba1eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -333,3 +333,58 @@ cancel-pipeline-cargo-clippy: extends: .cancel-pipeline-template needs: - job: cargo-clippy + +cancel-pipeline-build-linux-stable: + extends: .cancel-pipeline-template + needs: + - job: build-linux-stable + +cancel-pipeline-build-linux-stable-cumulus: + extends: .cancel-pipeline-template + needs: + - job: build-linux-stable-cumulus + +cancel-pipeline-build-linux-substrate: + extends: .cancel-pipeline-template + needs: + - job: build-linux-substrate + +cancel-pipeline-test-node-metrics: + extends: .cancel-pipeline-template + needs: + - job: test-node-metrics + +cancel-pipeline-test-frame-ui: + extends: .cancel-pipeline-template + needs: + - job: test-frame-ui + +cancel-pipeline-quick-benchmarks: + extends: .cancel-pipeline-template + needs: + - job: quick-benchmarks + +cancel-pipeline-check-try-runtime: + extends: .cancel-pipeline-template + needs: + - job: check-try-runtime + +cancel-pipeline-test-frame-examples-compile-to-wasm: + extends: .cancel-pipeline-template + needs: + - job: test-frame-examples-compile-to-wasm + +cancel-pipeline-build-short-benchmark: + extends: .cancel-pipeline-template + needs: + - job: build-short-benchmark + +cancel-pipeline-check-runtime-migration-rococo: + extends: .cancel-pipeline-template + needs: + - job: check-runtime-migration-rococo + +cancel-pipeline-check-runtime-migration-westend: + extends: .cancel-pipeline-template + needs: + - job: check-runtime-migration-westend diff --git a/cumulus/scripts/ci/changelog/.gitignore b/cumulus/scripts/ci/changelog/.gitignore deleted file mode 100644 index 4fbcc523b04..00000000000 --- a/cumulus/scripts/ci/changelog/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -changelog.md -*.json -release*.md -.env diff --git a/cumulus/scripts/ci/changelog/Gemfile b/cumulus/scripts/ci/changelog/Gemfile deleted file mode 100644 index 46b058e3c50..00000000000 --- a/cumulus/scripts/ci/changelog/Gemfile +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -source 'https://rubygems.org' - -git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } - -gem 'octokit', '~> 4' - -gem 'git_diff_parser', '~> 3' - -gem 'toml', '~> 0.3.0' - -gem 'rake', group: :dev - -gem 'optparse', '~> 0.1.1' - -gem 'logger', '~> 1.4' - -gem 'changelogerator', '0.10.1' - -gem 'test-unit', group: :dev - -gem 'rubocop', group: :dev, require: false diff --git a/cumulus/scripts/ci/changelog/Gemfile.lock b/cumulus/scripts/ci/changelog/Gemfile.lock deleted file mode 100644 index 893bec54919..00000000000 --- a/cumulus/scripts/ci/changelog/Gemfile.lock +++ /dev/null @@ -1,84 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - ast (2.4.2) - changelogerator (0.10.1) - git_diff_parser (~> 3) - octokit (~> 4) - faraday (1.8.0) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0.1) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - git_diff_parser (3.2.0) - logger (1.4.4) - multipart-post (2.1.1) - octokit (4.21.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) - optparse (0.1.1) - parallel (1.21.0) - parser (3.0.2.0) - ast (~> 2.4.1) - parslet (2.0.0) - power_assert (2.0.1) - public_suffix (4.0.6) - rainbow (3.0.0) - rake (13.0.6) - regexp_parser (2.1.1) - rexml (3.2.5) - rubocop (1.23.0) - parallel (~> 1.10) - parser (>= 3.0.0.0) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.12.0, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.13.0) - parser (>= 3.0.1.1) - ruby-progressbar (1.11.0) - ruby2_keywords (0.0.5) - sawyer (0.8.2) - addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - test-unit (3.5.1) - power_assert - toml (0.3.0) - parslet (>= 1.8.0, < 3.0.0) - unicode-display_width (2.1.0) - -PLATFORMS - x86_64-darwin-20 - x86_64-darwin-22 - -DEPENDENCIES - changelogerator (= 0.10.1) - git_diff_parser (~> 3) - logger (~> 1.4) - octokit (~> 4) - optparse (~> 0.1.1) - rake - rubocop - test-unit - toml (~> 0.3.0) - -BUNDLED WITH - 2.2.22 diff --git a/cumulus/scripts/ci/changelog/README.md b/cumulus/scripts/ci/changelog/README.md deleted file mode 100644 index 478e0b56d9c..00000000000 --- a/cumulus/scripts/ci/changelog/README.md +++ /dev/null @@ -1,78 +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 debuggin - -### 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/ci/changelog/bin/changelog b/cumulus/scripts/ci/changelog/bin/changelog deleted file mode 100755 index 6cd012a29ed..00000000000 --- a/cumulus/scripts/ci/changelog/bin/changelog +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env ruby - -# frozen_string_literal: true - -# call for instance as: -# ./bin/changelog statemine-v5.0.0 -# -# You may set the ENV NO_CACHE to force fetching from Github -# You should also ensure you set the ENV: GITHUB_TOKEN - -require_relative '../lib/changelog' -require 'logger' - -logger = Logger.new($stdout) -logger.level = Logger::DEBUG -logger.debug('Starting') - -changelogerator_version = `changelogerator --version` -logger.debug(changelogerator_version) - -owner = 'paritytech' -repo = 'cumulus' -ref1 = ARGV[0] -ref2 = ARGV[1] || 'HEAD' -output = ARGV[2] || 'release-notes.md' - -ENV['REF1'] = ref1 -ENV['REF2'] = ref2 - -gh_cumulus = SubRef.new(format('%s/%s', { owner: owner, repo: repo })) - -polkadot_ref1 = gh_cumulus.get_dependency_reference(ref1, 'polkadot-primitives') -polkadot_ref2 = gh_cumulus.get_dependency_reference(ref2, 'polkadot-primitives') - -substrate_ref1 = gh_cumulus.get_dependency_reference(ref1, 'sp-io') -substrate_ref2 = gh_cumulus.get_dependency_reference(ref2, 'sp-io') - -logger.debug("Cumulus from: #{ref1}") -logger.debug("Cumulus to: #{ref2}") - -logger.debug("Polkadot from: #{polkadot_ref1}") -logger.debug("Polkadot to: #{polkadot_ref2}") - -logger.debug("Substrate from: #{substrate_ref1}") -logger.debug("Substrate to: #{substrate_ref2}") - -cumulus_data = 'cumulus.json' -substrate_data = 'substrate.json' -polkadot_data = 'polkadot.json' - -logger.debug("Using CUMULUS: #{cumulus_data}") -logger.debug("Using SUBSTRATE: #{substrate_data}") -logger.debug("Using POLKADOT: #{polkadot_data}") - -logger.warn('NO_CACHE set') if ENV['NO_CACHE'] - -# This is acting as cache so we don't spend time querying while testing -if ENV['NO_CACHE'] || !File.file?(cumulus_data) - logger.debug(format('Fetching data for Cumulus into %s', cumulus_data)) - cmd = format('changelogerator %s/%s -f %s -t %s > %s', - { owner: owner, repo: repo, from: ref1, to: ref2, output: cumulus_data }) - system(cmd) -else - logger.debug("Re-using:#{cumulus_data}") -end - -if ENV['NO_CACHE'] || !File.file?(polkadot_data) - logger.debug(format('Fetching data for Polkadot into %s', polkadot_data)) - cmd = format('changelogerator %s/%s -f %s -t %s > %s', - { owner: owner, repo: 'polkadot', from: polkadot_ref1, to: polkadot_ref2, output: polkadot_data }) - system(cmd) -else - logger.debug("Re-using:#{polkadot_data}") -end - -if ENV['NO_CACHE'] || !File.file?(substrate_data) - logger.debug(format('Fetching data for Substrate into %s', substrate_data)) - cmd = format('changelogerator %s/%s -f %s -t %s > %s', - { owner: owner, repo: 'substrate', from: substrate_ref1, to: substrate_ref2, output: substrate_data }) - system(cmd) -else - logger.debug("Re-using:#{substrate_data}") -end - -POLKADOT_COLLECTIVES_DIGEST = ENV['COLLECTIVES_POLKADOT_DIGEST'] || 'digests/collectives-polkadot-srtool-digest.json' -SHELL_DIGEST = ENV['SHELL_DIGEST'] || 'digests/shell-srtool-digest.json' -ASSET_HUB_WESTEND_DIGEST = ENV['ASSET_HUB_WESTEND_DIGEST'] || 'digests/asset-hub-westend-srtool-digest.json' -ASSET_HUB_KUSAMA_DIGEST = ENV['ASSET_HUB_KUSAMA_DIGEST'] || 'digests/asset-hub-kusama-srtool-digest.json' -ASSET_HUB_POLKADOT_DIGEST = ENV['ASSET_HUB_POLKADOT_DIGEST'] || 'digests/asset-hub-westend-srtool-digest.json' -BRIDGE_HUB_ROCOCO_DIGEST = ENV['BRIDGE_HUB_ROCOCO_DIGEST'] || 'digests/bridge-hub-rococo-srtool-digest.json' -BRIDGE_HUB_KUSAMA_DIGEST = ENV['BRIDGE_HUB_KUSAMA_DIGEST'] || 'digests/bridge-hub-kusama-srtool-digest.json' -BRIDGE_HUB_POLKADOT_DIGEST = ENV['BRIDGE_HUB_POLKADOT_DIGEST'] || 'digests/bridge-hub-polkadot-srtool-digest.json' -ROCOCO_PARA_DIGEST = ENV['ROCOCO_PARA_DIGEST'] || 'digests/rococo-parachain-srtool-digest.json' -CANVAS_KUSAMA_DIGEST = ENV['CANVAS_KUSAMA_DIGEST'] || 'digests/contracts-rococo-srtool-digest.json' - -logger.debug("Release type: #{ENV['RELEASE_TYPE']}") - -if ENV['RELEASE_TYPE'] && ENV['RELEASE_TYPE'] == 'client' - logger.debug('Building changelog without runtimes') - cmd = format('jq \ - --slurpfile cumulus %s \ - --slurpfile substrate %s \ - --slurpfile polkadot %s \ - -n \'{ - cumulus: $cumulus[0], - substrate: $substrate[0], - polkadot: $polkadot[0], - }\' > context.json', cumulus_data, substrate_data, polkadot_data, - ) -else - logger.debug('Building changelog with runtimes') - - # Here we compose all the pieces together into one - # single big json file. - cmd = format('jq \ - --slurpfile cumulus %s \ - --slurpfile substrate %s \ - --slurpfile polkadot %s \ - --slurpfile srtool_shell %s \ - --slurpfile srtool_westmint %s \ - --slurpfile srtool_statemine %s \ - --slurpfile srtool_statemint %s \ - --slurpfile srtool_rococo_parachain %s \ - --slurpfile srtool_contracts_rococo %s \ - --slurpfile srtool_polkadot_collectives %s \ - --slurpfile srtool_bridge_hub_rococo %s \ - --slurpfile srtool_bridge_hub_kusama %s \ - --slurpfile srtool_bridge_hub_polkadot %s \ - -n \'{ - cumulus: $cumulus[0], - substrate: $substrate[0], - polkadot: $polkadot[0], - srtool: [ - { order: 10, name: "asset-hub-polkadot", note: " (Former Statemint)", data: $srtool_statemint[0] }, - { order: 11, name: "bridge-hub-polkadot", data: $srtool_bridge_hub_polkadot[0] }, - { order: 20, name: "asset-hub-kusama", note: " (Former Statemine)", data: $srtool_statemine[0] }, - { order: 21, name: "bridge-hub-kusama", data: $srtool_bridge_hub_kusama[0] }, - { order: 30, name: "asset-hub-westend", note: " (Former Westmint)", data: $srtool_westmint[0] }, - { order: 40, name: "rococo", data: $srtool_rococo_parachain[0] }, - { order: 41, name: "bridge-hub-rococo", data: $srtool_bridge_hub_rococo[0] }, - { order: 50, name: "polkadot-collectives", data: $srtool_polkadot_collectives[0] }, - { order: 60, name: "contracts", data: $srtool_contracts_rococo[0] }, - { order: 90, name: "shell", data: $srtool_shell[0] } - ] }\' > context.json', - cumulus_data, - substrate_data, - polkadot_data, - SHELL_DIGEST, - ASSET_HUB_WESTEND_DIGEST, - ASSET_HUB_KUSAMA_DIGEST, - ASSET_HUB_POLKADOT_DIGEST, - ROCOCO_PARA_DIGEST, - CANVAS_KUSAMA_DIGEST, - POLKADOT_COLLECTIVES_DIGEST, - BRIDGE_HUB_ROCOCO_DIGEST, - BRIDGE_HUB_KUSAMA_DIGEST, - BRIDGE_HUB_POLKADOT_DIGEST - ) -end -system(cmd) - -cmd = format('tera --env --env-key env --include-path templates \ - --template templates/template.md.tera context.json > %s', output) -system(cmd) diff --git a/cumulus/scripts/ci/changelog/digests/.gitignore b/cumulus/scripts/ci/changelog/digests/.gitignore deleted file mode 100644 index a6c57f5fb2f..00000000000 --- a/cumulus/scripts/ci/changelog/digests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.json diff --git a/cumulus/scripts/ci/changelog/digests/.gitkeep b/cumulus/scripts/ci/changelog/digests/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cumulus/scripts/ci/changelog/lib/changelog.rb b/cumulus/scripts/ci/changelog/lib/changelog.rb deleted file mode 100644 index 2d9ee29a8c8..00000000000 --- a/cumulus/scripts/ci/changelog/lib/changelog.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -# A Class to find Substrate references -class SubRef - require 'octokit' - require 'toml' - - attr_reader :client, :repository - - def initialize(github_repo) - @client = Octokit::Client.new( - access_token: ENV['GITHUB_TOKEN'] - ) - @repository = @client.repository(github_repo) - end - - # This function checks the Cargo.lock of a given - # Rust project, for a given package, and fetches - # the dependency git ref. - def get_dependency_reference(ref, package) - cargo = TOML::Parser.new( - Base64.decode64( - @client.contents( - @repository.full_name, - path: 'Cargo.lock', - query: { ref: ref.to_s } - ).content - ) - ).parsed - cargo['package'].find { |p| p['name'] == package }['source'].split('#').last - end -end diff --git a/cumulus/scripts/ci/changelog/templates/change.md.tera b/cumulus/scripts/ci/changelog/templates/change.md.tera deleted file mode 100644 index 609a038789a..00000000000 --- a/cumulus/scripts/ci/changelog/templates/change.md.tera +++ /dev/null @@ -1,44 +0,0 @@ -{# This macro shows ONE change #} -{%- macro change(c, cml="[C]", dot="[P]", sub="[S]") -%} - -{%- if c.meta.C and c.meta.C.agg.max >= 5 -%} -{%- set prio = " ‼️ HIGH" -%} -{%- elif c.meta.C and c.meta.C.agg.max >= 3 -%} -{%- set prio = " ❗️ Medium" -%} -{%- elif c.meta.C and c.meta.C.agg.max < 3 -%} -{%- set prio = " Low" -%} -{%- else -%} -{%- set prio = "" -%} -{%- endif -%} - -{%- set audit = "" -%} -{# -{%- if c.meta.D and c.meta.D.D1 -%} -{%- set audit = "✅ audited " -%} -{%- elif c.meta.D and c.meta.D.D2 -%} -{%- set audit = "✅ trivial " -%} -{%- elif c.meta.D and c.meta.D.D3 -%} -{%- set audit = "✅ trivial " -%} -{%- elif c.meta.D and c.meta.D.D5 -%} -{%- set audit = "⏳ pending non-critical audit " -%} -{%- else -%} -{%- set audit = "" -%} -{%- endif -%} -#} -{%- if c.html_url is containing("polkadot") -%} -{%- set repo = dot -%} -{%- elif c.html_url is containing("cumulus") -%} -{%- set repo = cml -%} -{%- elif c.html_url is containing("substrate") -%} -{%- set repo = sub -%} -{%- else -%} -{%- set repo = " " -%} -{%- endif -%} -{# #} -{%- if c.meta.T and c.meta.T.T6 -%} -{%- set xcm = " [✉️ XCM]" -%} -{%- else -%} -{%- set xcm = "" -%} -{%- endif -%} -{{- repo }} {{ audit }}[`#{{c.number}}`]({{c.html_url}}) {{- prio }} - {{ c.title | capitalize | truncate(length=60, end="…") }}{{xcm }} -{%- endmacro change %} diff --git a/cumulus/scripts/ci/changelog/templates/changes.md.tera b/cumulus/scripts/ci/changelog/templates/changes.md.tera deleted file mode 100644 index f1704546b0a..00000000000 --- a/cumulus/scripts/ci/changelog/templates/changes.md.tera +++ /dev/null @@ -1,21 +0,0 @@ -{# This include generates the section showing the changes #} -## Changes - -### Legend - -- {{ CML }} Cumulus -- {{ DOT }} Polkadot -- {{ SUB }} Substrate - -{% if env.RELEASE_TYPE and env.RELEASE_TYPE == "client" %} -{% include "changes_client.md.tera" %} -{% else %} -{% include "migrations-runtime.md.tera" -%} - -{% include "changes_runtime.md.tera" %} - -{% endif %} - -{% include "changes_api.md.tera" %} - -{% include "changes_misc.md.tera" %} diff --git a/cumulus/scripts/ci/changelog/templates/changes_api.md.tera b/cumulus/scripts/ci/changelog/templates/changes_api.md.tera deleted file mode 100644 index 2379c178c03..00000000000 --- a/cumulus/scripts/ci/changelog/templates/changes_api.md.tera +++ /dev/null @@ -1,19 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -### API - -{#- The changes are sorted by merge date -#} -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B -%} -{%- if pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - -{%- if pr.meta.B.B1 and pr.meta.T.T2 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} -{%- endif -%} -{%- endif -%} - -{%- endif -%} -{%- endfor %} diff --git a/cumulus/scripts/ci/changelog/templates/changes_client.md.tera b/cumulus/scripts/ci/changelog/templates/changes_client.md.tera deleted file mode 100644 index 05a521d6870..00000000000 --- a/cumulus/scripts/ci/changelog/templates/changes_client.md.tera +++ /dev/null @@ -1,17 +0,0 @@ -{% import "change.md.tera" as m_c -%} -### Client - -{#- The changes are sorted by merge date #} -{%- for pr in changes | sort(attribute="merged_at") %} - -{%- if pr.meta.B %} - {%- if pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- else -%} - - {%- if pr.meta.B.B1 and pr.meta.T and pr.meta.T.T0 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} diff --git a/cumulus/scripts/ci/changelog/templates/changes_misc.md.tera b/cumulus/scripts/ci/changelog/templates/changes_misc.md.tera deleted file mode 100644 index b36595bc5d6..00000000000 --- a/cumulus/scripts/ci/changelog/templates/changes_misc.md.tera +++ /dev/null @@ -1,39 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{%- set_global misc_count = 0 -%} -{#- First pass to count #} -{%- for pr in changes -%} - {%- if pr.meta.B %} - {%- if pr.meta.B.B0 -%} - {#- We skip silent ones -#} - {%- else -%} - {%- if pr.meta.T and pr.meta.T.agg.max > 2 %} -{%- set_global misc_count = misc_count + 1 -%} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} - -### Misc - -{% if misc_count > 10 %} -There are other misc. changes. You can expand the list below to view them all. -

Other misc. changes -{% endif -%} - -{#- The changes are sorted by merge date #} -{%- for pr in changes | sort(attribute="merged_at") %} - {%- if pr.meta.B and not pr.title is containing("ompanion") %} - {%- if pr.meta.B.B0 %} - {#- We skip silent ones -#} - {%- else -%} - {%- if pr.meta.T and pr.meta.T.agg.max > 2 %} -- {{ m_c::change(c=pr) }} - {%- endif -%} - {% endif -%} - {% endif -%} -{% endfor %} - -{% if misc_count > 10 %} -
-{% endif -%} diff --git a/cumulus/scripts/ci/changelog/templates/changes_runtime.md.tera b/cumulus/scripts/ci/changelog/templates/changes_runtime.md.tera deleted file mode 100644 index 39c27263765..00000000000 --- a/cumulus/scripts/ci/changelog/templates/changes_runtime.md.tera +++ /dev/null @@ -1,19 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -### Runtime - -{#- The changes are sorted by merge date -#} -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B -%} -{%- if pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - -{%- if pr.meta.B.B1 and pr.meta.T.T1 and not pr.title is containing("ompanion") %} -- {{ m_c::change(c=pr) }} -{%- endif -%} -{%- endif -%} - -{%- endif -%} -{%- endfor %} diff --git a/cumulus/scripts/ci/changelog/templates/compiler.md.tera b/cumulus/scripts/ci/changelog/templates/compiler.md.tera deleted file mode 100644 index 0420a88c396..00000000000 --- a/cumulus/scripts/ci/changelog/templates/compiler.md.tera +++ /dev/null @@ -1,6 +0,0 @@ -## Rust compiler versions - -This release was tested against the following versions of `rustc`. Other versions may work. - -- Rust Stable: `{{ env.RUSTC_STABLE }}` -- Rust Nightly: `{{ env.RUSTC_NIGHTLY }}` diff --git a/cumulus/scripts/ci/changelog/templates/debug.md.tera b/cumulus/scripts/ci/changelog/templates/debug.md.tera deleted file mode 100644 index 4f0b14c00f1..00000000000 --- a/cumulus/scripts/ci/changelog/templates/debug.md.tera +++ /dev/null @@ -1,9 +0,0 @@ -{%- set to_ignore = changes | filter(attribute="meta.B.B0") %} - diff --git a/cumulus/scripts/ci/changelog/templates/docker_image.md.tera b/cumulus/scripts/ci/changelog/templates/docker_image.md.tera deleted file mode 100644 index cb0c619f3a7..00000000000 --- a/cumulus/scripts/ci/changelog/templates/docker_image.md.tera +++ /dev/null @@ -1,11 +0,0 @@ - -## Docker images - -The docker image for this release can be found in [Docker hub](https://hub.docker.com/r/parity/polkadot-parachain/tags?page=1&ordering=last_updated). -(It will be available a few minutes after the release has been published). - -You may also pull it with: - -``` -docker pull parity/polkadot-parachain:latest -``` diff --git a/cumulus/scripts/ci/changelog/templates/global_priority.md.tera b/cumulus/scripts/ci/changelog/templates/global_priority.md.tera deleted file mode 100644 index 3d8a507ed1f..00000000000 --- a/cumulus/scripts/ci/changelog/templates/global_priority.md.tera +++ /dev/null @@ -1,35 +0,0 @@ -{%- import "high_priority.md.tera" as m_p -%} -## Global Priority - -{%- set cumulus_prio = 0 -%} -{%- set polkadot_prio = 0 -%} -{%- set substrate_prio = 0 -%} - -{# We fetch the various priorities #} -{%- if cumulus.meta.C -%} - {%- set cumulus_prio = cumulus.meta.C.max -%} -{%- endif -%} -{%- if polkadot.meta.C -%} - {%- set polkadot_prio = polkadot.meta.C.max -%} -{%- endif -%} -{%- if substrate.meta.C -%} - {%- set substrate_prio = substrate.meta.C.max -%} -{%- endif -%} - -{# We compute the global priority #} -{%- set global_prio = cumulus_prio -%} -{%- if polkadot_prio > global_prio -%} - {% set global_prio = polkadot_prio -%} -{%- endif -%} -{%- if substrate_prio > global_prio -%} - {%- set global_prio = substrate_prio -%} -{%- endif %} - - - -{# We show the result #} -{{ m_p::high_priority(p=global_prio, changes=changes) }} diff --git a/cumulus/scripts/ci/changelog/templates/high_priority.md.tera b/cumulus/scripts/ci/changelog/templates/high_priority.md.tera deleted file mode 100644 index 21e331892b8..00000000000 --- a/cumulus/scripts/ci/changelog/templates/high_priority.md.tera +++ /dev/null @@ -1,56 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{# This macro convert a priority level into readable output #} -{%- macro high_priority(p, changes) -%} - -{# real globals don't work so we count the number of host functions here as well #} -{# unfortunately, the next snippet is duplicated in the host_functions.md.tera template #} -{# as well #} -{%- set_global host_fn_count = 0 -%} - -{# We loop first to count the number of host functions but we do not display anything yet #} -{%- for pr in changes -%} -{%- if pr.meta.B and pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - {%- if pr.meta.E and pr.meta.E.E4 -%} - {%- set_global host_fn_count = host_fn_count + 1 -%} - {%- endif -%} -{%- endif -%} -{%- endfor -%} - -{%- if p >= 5 or host_fn_count > 0 -%} - {%- set prio = "‼️ HIGH" -%} - {%- set text = "This is a **high priority** release and you must upgrade as as soon as possible." -%} -{%- elif p >= 3 -%} - {%- set prio = "❗️ Medium" -%} - {%- set text = "This is a medium priority release and you should upgrade in a timely manner." -%} -{%- else -%} - {%- set prio = "Low" -%} - {%- set text = "This is a low priority release and you may upgrade at your convenience." -%} -{%- endif -%} - - -{% if prio -%} -{{prio}}: {{text}} -{%- else -%} - -{%- endif %} - -{# We only show details if Medium or High #} -{%- if p >= 5 -%} -The changes motivating this priority level are: -{% for pr in changes | sort(attribute="merged_at") -%} - {%- if pr.meta.C -%} - {%- if pr.meta.C.agg.max >= p %} -- {{ m_c::change(c=pr) }} -{%- if pr.meta.B and pr.meta.B.B1 and pr.meta.T and pr.meta.T.T1 %} -(RUNTIME) -{% endif %} - - {%- endif -%} - {%- endif -%} -{%- endfor %} -{%- endif %} - -{%- endmacro priority -%} diff --git a/cumulus/scripts/ci/changelog/templates/host_functions.md.tera b/cumulus/scripts/ci/changelog/templates/host_functions.md.tera deleted file mode 100644 index 2a9b26e8090..00000000000 --- a/cumulus/scripts/ci/changelog/templates/host_functions.md.tera +++ /dev/null @@ -1,38 +0,0 @@ -{%- import "change.md.tera" as m_c -%} - -{%- set_global host_fn_count = 0 -%} - -{# We loop first to count the number of host functions but we do not display anything yet #} -{%- for pr in changes -%} -{%- if pr.meta.B and pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - {%- if pr.meta.E and pr.meta.E.E4 -%} - {%- set_global host_fn_count = host_fn_count + 1 -%} - {% endif -%} -{%- endif -%} -{%- endfor -%} - - - -{% if host_fn_count == 0 -%} - -{%- else -%} -## Host functions - -⚠️ The runtimes in this release contain {{ host_fn_count }} new **host function{{ host_fn_count | pluralize }}**. - -⚠️ It is critical that you update your client before the chain switches to the new runtimes. - -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 -%} -{#- We skip silent ones -#} -{%- else -%} - {%- if pr.meta.E and pr.meta.E.E4 -%} - - {{ m_c::change(c=pr) }} - {% endif -%} - {% endif -%} -{%- endfor -%} - -{%- endif %} diff --git a/cumulus/scripts/ci/changelog/templates/migrations-db.md.tera b/cumulus/scripts/ci/changelog/templates/migrations-db.md.tera deleted file mode 100644 index e840d991d9a..00000000000 --- a/cumulus/scripts/ci/changelog/templates/migrations-db.md.tera +++ /dev/null @@ -1,26 +0,0 @@ -{%- import "change.md.tera" as m_c %} -{%- set_global db_migration_count = 0 -%} - -## Database Migrations - -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 %} -{#- We skip silent ones -#} -{%- else -%} -{%- if pr.meta.E and pr.meta.E.E2 -%} -{%- set_global db_migration_count = db_migration_count + 1 -%} -- {{ m_c::change(c=pr) }} -{% endif -%} -{% endif -%} -{% endfor -%} - -{%- if db_migration_count == 0 -%} -No Database migration detected in this release. -{% else %} - -There is {{ db_migration_count }} database migration(s) in this release. - -Database migrations are operations bringing your database to the latest stand. -Some migrations may break compatibility and making a backup of your database is highly recommended. -{%- endif %} diff --git a/cumulus/scripts/ci/changelog/templates/migrations-runtime.md.tera b/cumulus/scripts/ci/changelog/templates/migrations-runtime.md.tera deleted file mode 100644 index f02499a84d7..00000000000 --- a/cumulus/scripts/ci/changelog/templates/migrations-runtime.md.tera +++ /dev/null @@ -1,14 +0,0 @@ -{%- import "change.md.tera" as m_c %} - -## Runtime Migrations - -{% for pr in changes | sort(attribute="merged_at") -%} - -{%- if pr.meta.B and pr.meta.B.B0 %} -{#- We skip silent ones -#} -{%- else -%} -{%- if pr.meta.E and pr.meta.E.E1 -%} -- {{ m_c::change(c=pr) }} -{% endif -%} -{% endif -%} -{% endfor -%} diff --git a/cumulus/scripts/ci/changelog/templates/pre_release.md.tera b/cumulus/scripts/ci/changelog/templates/pre_release.md.tera deleted file mode 100644 index 53a0e906541..00000000000 --- a/cumulus/scripts/ci/changelog/templates/pre_release.md.tera +++ /dev/null @@ -1,11 +0,0 @@ -{%- if env.PRE_RELEASE == "true" -%} -
⚠️ This is a pre-release - -**Release candidates** are **pre-releases** may not be final. -Although they are reasonably tested, there may be additional changes or issues -before an official release is tagged. Use at your own discretion, and consider -only using published releases on critical production infrastructure. -
-{% else -%} - -{%- endif %} diff --git a/cumulus/scripts/ci/changelog/templates/runtime.md.tera b/cumulus/scripts/ci/changelog/templates/runtime.md.tera deleted file mode 100644 index d2070245838..00000000000 --- a/cumulus/scripts/ci/changelog/templates/runtime.md.tera +++ /dev/null @@ -1,28 +0,0 @@ -{# This macro shows one runtime #} -{%- macro runtime(runtime) -%} - -### {{ runtime.name | replace(from="-", to=" ") | title }} {%- if runtime.note -%} {{ runtime.note }} {%- endif -%} - -{%- if runtime.data.runtimes.compressed.subwasm.compression.compressed %} -{%- set compressed = "Yes" %} -{%- else %} -{%- set compressed = "No" %} -{%- endif %} - -{%- set comp_ratio = 100 - (runtime.data.runtimes.compressed.subwasm.compression.size_compressed / runtime.data.runtimes.compressed.subwasm.compression.size_decompressed *100) %} - - - - - - - -``` -🏋️ Runtime Size: {{ runtime.data.runtimes.compressed.subwasm.size | filesizeformat }} ({{ runtime.data.runtimes.compressed.subwasm.size }} bytes) -🔥 Core Version: {{ runtime.data.runtimes.compressed.subwasm.core_version.specName }}-{{ runtime.data.runtimes.compressed.subwasm.core_version.specVersion }} ({{ runtime.data.runtimes.compressed.subwasm.core_version.implName }}-{{ runtime.data.runtimes.compressed.subwasm.core_version.implVersion }}.tx{{ runtime.data.runtimes.compressed.subwasm.core_version.transactionVersion }}.au{{ runtime.data.runtimes.compressed.subwasm.core_version.authoringVersion }}) -🗜 Compressed: {{ compressed }}: {{ comp_ratio | round(method="ceil", precision=2) }}% -🎁 Metadata version: V{{ runtime.data.runtimes.compressed.subwasm.metadata_version }} -🗳️ Blake2-256 hash: {{ runtime.data.runtimes.compressed.subwasm.blake2_256 }} -📦 IPFS: {{ runtime.data.runtimes.compressed.subwasm.ipfs_hash }} -``` -{%- endmacro runtime %} diff --git a/cumulus/scripts/ci/changelog/templates/runtimes.md.tera b/cumulus/scripts/ci/changelog/templates/runtimes.md.tera deleted file mode 100644 index fe2e16aa9c2..00000000000 --- a/cumulus/scripts/ci/changelog/templates/runtimes.md.tera +++ /dev/null @@ -1,17 +0,0 @@ -{# This include shows the list and details of the runtimes #} -{%- import "runtime.md.tera" as m_r -%} - -## Runtimes - -{% set rtm = srtool[0] -%} - -The information about the runtimes included in this release can be found below. -The runtimes have been built using [{{ rtm.data.gen }}](https://github.com/paritytech/srtool) and `{{ rtm.data.rustc }}`. - -{%- for runtime in srtool | sort(attribute="order") %} -{%- set HIDE_VAR = "HIDE_SRTOOL_" ~ runtime.name | upper %} -{%- if not env is containing(HIDE_VAR) %} - -{{ m_r::runtime(runtime=runtime) }} -{%- endif %} -{%- endfor %} diff --git a/cumulus/scripts/ci/changelog/templates/template.md.tera b/cumulus/scripts/ci/changelog/templates/template.md.tera deleted file mode 100644 index 8b14db43fe2..00000000000 --- a/cumulus/scripts/ci/changelog/templates/template.md.tera +++ /dev/null @@ -1,38 +0,0 @@ -{# This is the entry point of the template for the parachains-* releases-#} - -{% include "pre_release.md.tera" -%} - -{% if env.PRE_RELEASE == "true" -%} -This pre-release contains the changes from `{{ env.REF1 }}` to `{{ env.REF2 }}`. -{% else -%} -This release contains the changes from `{{ env.REF1 }}` to `{{ env.REF2 }}`. -{% endif -%} - -{%- set changes = cumulus.changes | concat(with=substrate.changes) -%} -{%- set changes = changes | concat(with=polkadot.changes) -%} -{%- include "debug.md.tera" -%} - -{%- set CML = "[C]" -%} -{%- set DOT = "[P]" -%} -{%- set SUB = "[S]" -%} - -{# We check for host function first because no matter what the priority is, #} -{# we will force it to HIGH if at least one host function was detected. #} - -{% include "host_functions.md.tera" -%} - -{% if env.RELEASE_TYPE and env.RELEASE_TYPE == "client" -%} -{% include "global_priority.md.tera" -%} -{% include "compiler.md.tera" -%} -{% include "migrations-db.md.tera" %} - -{% else %} -{% include "migrations-runtime.md.tera" %} -{% include "runtimes.md.tera" -%} -{% endif %} - -{% include "changes.md.tera" -%} - -{% if env.RELEASE_TYPE and env.RELEASE_TYPE == "client" -%} -{% include "docker_image.md.tera" -%} -{% endif %} diff --git a/cumulus/scripts/ci/changelog/test/test_basic.rb b/cumulus/scripts/ci/changelog/test/test_basic.rb deleted file mode 100755 index d099fadca43..00000000000 --- a/cumulus/scripts/ci/changelog/test/test_basic.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require_relative '../lib/changelog' -require 'test/unit' - -class TestChangelog < Test::Unit::TestCase - def test_get_dep_ref_polkadot - c = SubRef.new('paritytech/polkadot') - ref = '13c2695' - package = 'sc-cli' - result = c.get_dependency_reference(ref, package) - assert_equal('7db0768a85dc36a3f2a44d042b32f3715c00a90d', result) - end - - def test_get_dep_ref_invalid_ref - c = SubRef.new('paritytech/polkadot') - ref = '9999999' - package = 'sc-cli' - assert_raise do - c.get_dependency_reference(ref, package) - end - end -end diff --git a/cumulus/scripts/ci/common/lib.sh b/cumulus/scripts/ci/common/lib.sh deleted file mode 100644 index 93e0392b3e2..00000000000 --- a/cumulus/scripts/ci/common/lib.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/sh - -api_base="https://api.github.com/repos" - -# Function to take 2 git tags/commits and get any lines from commit messages -# that contain something that looks like a PR reference: e.g., (#1234) -sanitised_git_logs(){ - git --no-pager log --pretty=format:"%s" "$1...$2" | - # Only find messages referencing a PR - grep -E '\(#[0-9]+\)' | - # Strip any asterisks - sed 's/^* //g' -} - -# Checks whether a tag on github has been verified -# repo: 'organization/repo' -# tagver: 'v1.2.3' -# Usage: check_tag $repo $tagver -check_tag () { - repo=$1 - tagver=$2 - if [ -n "$GITHUB_RELEASE_TOKEN" ]; then - echo '[+] Fetching tag using privileged token' - tag_out=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") - else - echo '[+] Fetching tag using unprivileged token' - tag_out=$(curl -H "Authorization: token $GITHUB_PR_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") - fi - tag_sha=$(echo "$tag_out" | jq -r .object.sha) - object_url=$(echo "$tag_out" | jq -r .object.url) - if [ "$tag_sha" = "null" ]; then - return 2 - fi - echo "[+] Tag object SHA: $tag_sha" - verified_str=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$object_url" | jq -r .verification.verified) - if [ "$verified_str" = "true" ]; then - # Verified, everything is good - return 0 - else - # Not verified. Bad juju. - return 1 - fi -} - -# Checks whether a given PR has a given label. -# repo: 'organization/repo' -# pr_id: 12345 -# label: B1-silent -# Usage: has_label $repo $pr_id $label -has_label(){ - repo="$1" - pr_id="$2" - label="$3" - - # These will exist if the function is called in Gitlab. - # If the function's called in Github, we should have GITHUB_ACCESS_TOKEN set - # already. - if [ -n "$GITHUB_RELEASE_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_RELEASE_TOKEN" - elif [ -n "$GITHUB_PR_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_PR_TOKEN" - fi - - out=$(curl -H "Authorization: token $GITHUB_TOKEN" -s "$api_base/$repo/pulls/$pr_id") - [ -n "$(echo "$out" | tr -d '\r\n' | jq ".labels | .[] | select(.name==\"$label\")")" ] -} - -github_label () { - echo - echo "# run github-api job for labeling it ${1}" - curl -sS -X POST \ - -F "token=${CI_JOB_TOKEN}" \ - -F "ref=master" \ - -F "variables[LABEL]=${1}" \ - -F "variables[PRNO]=${CI_COMMIT_REF_NAME}" \ - -F "variables[PROJECT]=paritytech/polkadot" \ - "${GITLAB_API}/projects/${GITHUB_API_PROJECT}/trigger/pipeline" -} - -# Formats a message into a JSON string for posting to Matrix -# message: 'any plaintext message' -# formatted_message: 'optional message formatted in html' -# Usage: structure_message $content $formatted_content (optional) -structure_message() { - if [ -z "$2" ]; then - body=$(jq -Rs --arg body "$1" '{"msgtype": "m.text", $body}' < /dev/null) - else - body=$(jq -Rs --arg body "$1" --arg formatted_body "$2" '{"msgtype": "m.text", $body, "format": "org.matrix.custom.html", $formatted_body}' < /dev/null) - fi - echo "$body" -} - -# Post a message to a matrix room -# body: '{body: "JSON string produced by structure_message"}' -# room_id: !fsfSRjgjBWEWffws:matrix.parity.io -# access_token: see https://matrix.org/docs/guides/client-server-api/ -# Usage: send_message $body (json formatted) $room_id $access_token -send_message() { -curl -XPOST -d "$1" "https://matrix.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" -} - -# Pretty-printing functions -boldprint () { printf "|\n| \033[1m%s\033[0m\n|\n" "${@}"; } -boldcat () { printf "|\n"; while read -r l; do printf "| \033[1m%s\033[0m\n" "${l}"; done; printf "|\n" ; } - -skip_if_companion_pr() { - url="https://api.github.com/repos/paritytech/polkadot/pulls/${CI_COMMIT_REF_NAME}" - echo "[+] API URL: $url" - - pr_title=$(curl -sSL -H "Authorization: token ${GITHUB_PR_TOKEN}" "$url" | jq -r .title) - echo "[+] PR title: $pr_title" - - if echo "$pr_title" | grep -qi '^companion'; then - echo "[!] PR is a companion PR. Build is already done in substrate" - exit 0 - else - echo "[+] PR is not a companion PR. Proceeding test" - fi -} - -# Fetches the tag name of the latest release from a repository -# repo: 'organisation/repo' -# Usage: latest_release 'paritytech/polkadot' -latest_release() { - curl -s "$api_base/$1/releases/latest" | jq -r '.tag_name' -} - -# Check for runtime changes between two commits. This is defined as any changes -# to /primitives/src/* and any *production* chains under /runtime -has_runtime_changes() { - from=$1 - to=$2 - - if git diff --name-only "${from}...${to}" \ - | grep -q -e '^runtime/polkadot' -e '^runtime/kusama' -e '^primitives/src/' -e '^runtime/common' - then - return 0 - else - return 1 - fi -} diff --git a/cumulus/scripts/ci/create-benchmark-pr.sh b/cumulus/scripts/ci/create-benchmark-pr.sh deleted file mode 100755 index 46927f24b80..00000000000 --- a/cumulus/scripts/ci/create-benchmark-pr.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -set -Eeu -o pipefail -shopt -s inherit_errexit - -PR_TITLE="$1" -HEAD_REF="$2" - -ORG="paritytech" -REPO="$CI_PROJECT_NAME" -BASE_REF="$CI_COMMIT_BRANCH" -# Change threshold in %. Bigger values excludes the small changes. -THRESHOLD=${THRESHOLD:-30} - -WEIGHTS_COMPARISON_URL_PARTS=( - "https://weights.tasty.limo/compare?" - "repo=$REPO&" - "threshold=$THRESHOLD&" - "path_pattern=**%2Fweights%2F*.rs&" - "method=guess-worst&" - "ignore_errors=true&" - "unit=time&" - "old=$BASE_REF&" - "new=$HEAD_REF" -) -printf -v WEIGHTS_COMPARISON_URL %s "${WEIGHTS_COMPARISON_URL_PARTS[@]}" - -PAYLOAD="$(jq -n \ - --arg title "$PR_TITLE" \ - --arg body " -This PR is generated automatically by CI. - -Compare the weights with \`$BASE_REF\`: $WEIGHTS_COMPARISON_URL - -- [ ] Backport to master and node release branch once merged -" \ - --arg base "$BASE_REF" \ - --arg head "$HEAD_REF" \ - '{ - title: $title, - body: $body, - head: $head, - base: $base - }' -)" - -echo "PAYLOAD: $PAYLOAD" - -curl \ - -H "Authorization: token $GITHUB_TOKEN" \ - -X POST \ - -d "$PAYLOAD" \ - "https://api.github.com/repos/$ORG/$REPO/pulls" diff --git a/cumulus/scripts/ci/github/check-rel-br b/cumulus/scripts/ci/github/check-rel-br deleted file mode 100755 index 1b49ae62172..00000000000 --- a/cumulus/scripts/ci/github/check-rel-br +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -# This script helps running sanity checks on a release branch -# It is intended to be ran from the repo and from the release branch - -# NOTE: The diener runs do take time and are not really required because -# if we missed the diener runs, the Cargo.lock that we check won't pass -# the tests. See https://github.com/bkchr/diener/issues/17 - -grv=$(git remote --verbose | grep push) -export RUST_LOG=none -REPO=$(echo "$grv" | cut -d ' ' -f1 | cut -d$'\t' -f2 | sed 's/.*github.com\/\(.*\)/\1/g' | cut -d '/' -f2 | cut -d '.' -f1 | sort | uniq) -echo "[+] Detected repo: $REPO" - -BRANCH=$(git branch --show-current) -if ! [[ "$BRANCH" =~ ^release.*$ || "$BRANCH" =~ ^polkadot.*$ ]]; then - echo "This script is meant to run only on a RELEASE branch." - echo "Try one of the following branch:" - git branch -r --format "%(refname:short)" --sort=-committerdate | grep -Ei '/?release' | head - exit 1 -fi -echo "[+] Working on $BRANCH" - -# Tried to get the version of the release from the branch -# input: release-foo-v0.9.22 or release-bar-v9220 or release-foo-v0.9.220 -# output: 0.9.22 -get_version() { - branch=$1 - [[ $branch =~ -v(.*) ]] - version=${BASH_REMATCH[1]} - if [[ $version =~ \. ]]; then - MAJOR=$(($(echo $version | cut -d '.' -f1))) - MINOR=$(($(echo $version | cut -d '.' -f2))) - PATCH=$(($(echo $version | cut -d '.' -f3))) - echo $MAJOR.$MINOR.${PATCH:0:2} - else - MAJOR=$(echo $(($version / 100000))) - remainer=$(($version - $MAJOR * 100000)) - MINOR=$(echo $(($remainer / 1000))) - remainer=$(($remainer - $MINOR * 1000)) - PATCH=$(echo $(($remainer / 10))) - echo $MAJOR.$MINOR.$PATCH - fi -} - -# return the name of the release branch for a given repo and version -get_release_branch() { - repo=$1 - version=$2 - case $repo in - polkadot) - echo "release-v$version" - ;; - - substrate) - echo "polkadot-v$version" - ;; - - *) - echo "Repo $repo is not supported, exiting" - exit 1 - ;; - esac -} - -# repo = substrate / polkadot -check_release_branch_repo() { - repo=$1 - branch=$2 - - echo "[+] Checking deps for $repo=$branch" - - POSTIVE=$(cat Cargo.lock | grep "$repo?branch=$branch" | sort | uniq | wc -l) - NEGATIVE=$(cat Cargo.lock | grep "$repo?branch=" | grep -v $branch | sort | uniq | wc -l) - - if [[ $POSTIVE -eq 1 && $NEGATIVE -eq 0 ]]; then - echo -e "[+] ✅ Looking good" - cat Cargo.lock | grep "$repo?branch=" | sort | uniq | sed 's/^/\t - /' - return 0 - else - echo -e "[+] ❌ Something seems to be wrong, we want 1 unique match and 0 non match (1, 0) and we got ($(($POSTIVE)), $(($NEGATIVE)))" - cat Cargo.lock | grep "$repo?branch=" | sort | uniq | sed 's/^/\t - /' - return 1 - fi -} - -# Check a release branch -check_release_branches() { - SUBSTRATE_BRANCH=$1 - POLKADOT_BRANCH=$2 - - check_release_branch_repo substrate $SUBSTRATE_BRANCH - ret_a1=$? - - ret_b1=0 - if [ $POLKADOT_BRANCH ]; then - check_release_branch_repo polkadot $POLKADOT_BRANCH - ret_b1=$? - fi - - STATUS=$(($ret_a1 + $ret_b1)) - - return $STATUS -} - -VERSION=$(get_version $BRANCH) -echo "[+] Target version: v$VERSION" - -case $REPO in - polkadot) - substrate=$(get_release_branch substrate $VERSION) - - check_release_branches $substrate - ;; - - cumulus) - polkadot=$(get_release_branch polkadot $VERSION) - substrate=$(get_release_branch substrate $VERSION) - - check_release_branches $substrate $polkadot - ;; - - *) - echo "REPO $REPO is not supported, exiting" - exit 1 - ;; -esac diff --git a/cumulus/scripts/ci/github/check_labels.sh b/cumulus/scripts/ci/github/check_labels.sh deleted file mode 100755 index 102b1a4b066..00000000000 --- a/cumulus/scripts/ci/github/check_labels.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash - -#shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -repo="$GITHUB_REPOSITORY" -pr="$GITHUB_PR" - -ensure_labels() { - for label in "$@"; do - if has_label "$repo" "$pr" "$label"; then - return 0 - fi - done - return 1 -} - -# Must have one of the following labels -releasenotes_labels=( - 'B0-silent' - 'B1-note_worthy' -) - -# Must be an ordered list of priorities, lowest first -priority_labels=( - 'C1-low' - 'C3-medium' - 'C5-high' - 'C7-critical' -) - -audit_labels=( - 'D1-audited 👍' - 'D2-notlive 💤' - 'D3-trivial 🧸' - 'D5-nicetohaveaudit ⚠️' - 'D9-needsaudit 👮' -) - -x_labels=( - 'X0-node' - 'X1-runtime' - 'X2-API' - 'X9-misc' -) - -echo "[+] Checking release notes (B) labels for $CI_COMMIT_BRANCH" -if ensure_labels "${releasenotes_labels[@]}"; then - echo "[+] Release notes label detected. All is well." -else - echo "[!] Release notes label not detected. Please add one of: ${releasenotes_labels[*]}" - exit 1 -fi - -if has_label "$repo" "$pr" 'B1-note_worthy'; then - echo "[+] B1-note_worthy is chosen. Checking that there X-labels for $CI_COMMIT_BRANCH" - if ensure_labels "${x_labels[@]}"; then - echo "[+] X-label detected. All is well." - else - echo "[!] X-label not detected. Please add one of: ${x_labels[*]}" - exit 1 - fi -fi - -echo "[+] Checking release priority (C) labels for $CI_COMMIT_BRANCH" -if ensure_labels "${priority_labels[@]}"; then - echo "[+] Release priority label detected. All is well." -else - echo "[!] Release priority label not detected. Please add one of: ${priority_labels[*]}" - exit 1 -fi - -if has_runtime_changes "${BASE_SHA}" "${HEAD_SHA}"; then - echo "[+] Runtime changes detected. Checking audit (D) labels" - if ensure_labels "${audit_labels[@]}"; then - echo "[+] Release audit label detected. All is well." - else - echo "[!] Release audit label not detected. Please add one of: ${audit_labels[*]}" - exit 1 - fi -fi - -# If the priority is anything other than the lowest, we *must not* have a B0-silent -# label -if has_label "$repo" "$GITHUB_PR" 'B0-silent' && - ! has_label "$repo" "$GITHUB_PR" "${priority_labels[0]}"; then - echo "[!] Changes with a priority higher than C1-low *MUST* have a B- label that is not B0-Silent" - exit 1 -fi - -exit 0 diff --git a/cumulus/scripts/ci/github/extrinsic-ordering-filter.sh b/cumulus/scripts/ci/github/extrinsic-ordering-filter.sh deleted file mode 100755 index 4fd3337f64a..00000000000 --- a/cumulus/scripts/ci/github/extrinsic-ordering-filter.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -# This script is used in a Github Workflow. It helps filtering out what is interesting -# when comparing metadata and spot what would require a tx version bump. - -# shellcheck disable=SC2002,SC2086 - -FILE=$1 - -# Higlight indexes that were deleted -function find_deletions() { - echo "\n## Deletions\n" - RES=$(cat "$FILE" | grep -n '\[\-\]' | tr -s " ") - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' - else - echo "n/a" - fi -} - -# Highlight indexes that have been deleted -function find_index_changes() { - echo "\n## Index changes\n" - RES=$(cat "$FILE" | grep -E -n -i 'idx:\s*([0-9]+)\s*(->)\s*([0-9]+)' | tr -s " ") - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' - else - echo "n/a" - fi -} - -# Highlight values that decreased -function find_decreases() { - echo "\n## Decreases\n" - OUT=$(cat "$FILE" | grep -E -i -o '([0-9]+)\s*(->)\s*([0-9]+)' | awk '$1 > $3 { printf "%s;", $0 }') - IFS=$';' LIST=("$OUT") - unset RES - for line in "${LIST[@]}"; do - RES="$RES\n$(cat "$FILE" | grep -E -i -n \"$line\" | tr -s " ")" - done - - if [ "$RES" ]; then - echo "$RES" | awk '{ printf "%s\\n", $0 }' | sort -u -g | uniq - else - echo "n/a" - fi -} - -echo "\n------------------------------ SUMMARY -------------------------------" -echo "\n⚠️ This filter is here to help spotting changes that should be reviewed carefully." -echo "\n⚠️ It catches only index changes, deletions and value decreases". - -find_deletions "$FILE" -find_index_changes "$FILE" -find_decreases "$FILE" -echo "\n----------------------------------------------------------------------\n" diff --git a/cumulus/scripts/ci/github/runtime-version.rb b/cumulus/scripts/ci/github/runtime-version.rb deleted file mode 100644 index 14663acaf31..00000000000 --- a/cumulus/scripts/ci/github/runtime-version.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -# Gets the runtime version for a given runtime from the filesystem. -# Optionally accepts a path that is the root of the project which defaults to -# the current working directory -def get_runtime(runtime: nil, path: '.', runtime_dir: 'runtime') - File.open(path + "/#{runtime_dir}/#{runtime}/src/lib.rs") do |f| - f.find { |l| l =~ /spec_version/ }.match(/[0-9]+/)[0] - end -end diff --git a/cumulus/scripts/ci/gitlab/pipeline/benchmarks.yml b/cumulus/scripts/ci/gitlab/pipeline/benchmarks.yml deleted file mode 100644 index 0cbc42aabae..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/benchmarks.yml +++ /dev/null @@ -1,84 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "benchmarks" stage -# Work only on release-parachains-v* branches - -benchmarks-build: - stage: benchmarks-build - extends: - - .docker-env - - .collect-artifacts - - .benchmarks-manual-refs - script: - - time cargo build --profile production --locked --features runtime-benchmarks - - mkdir -p artifacts - - cp target/production/polkadot-parachain ./artifacts/ - -benchmarks-assets: - stage: benchmarks-run - timeout: 1d - extends: - - .docker-env - - .collect-artifacts - - .benchmarks-refs - before_script: - - !reference [.docker-env, before_script] - script: - - ./scripts/benchmarks-ci.sh assets asset-hub-kusama ./artifacts - - ./scripts/benchmarks-ci.sh assets asset-hub-polkadot ./artifacts - - ./scripts/benchmarks-ci.sh assets asset-hub-westend ./artifacts - - export CURRENT_TIME=$(date '+%s') - - export BRANCHNAME="weights-asset-hub-polkadot-${CI_COMMIT_BRANCH}-${CURRENT_TIME}" - - !reference [.git-commit-push, script] - - ./scripts/ci/create-benchmark-pr.sh "[benchmarks] Update weights for asset-hub-kusama/-polkadot" "$BRANCHNAME" - - rm -f ./artifacts/polkadot-parachain - - rm -f ./artifacts/test-parachain - after_script: - - rm -rf .git/config - tags: - - weights-vm - -benchmarks-collectives: - stage: benchmarks-run - timeout: 1d - extends: - - .docker-env - - .collect-artifacts - - .benchmarks-refs - before_script: - - !reference [.docker-env, before_script] - script: - - ./scripts/benchmarks-ci.sh collectives collectives-polkadot ./artifacts - - export CURRENT_TIME=$(date '+%s') - - export BRANCHNAME="weights-collectives-${CI_COMMIT_BRANCH}-${CURRENT_TIME}" - - !reference [.git-commit-push, script] - - ./scripts/ci/create-benchmark-pr.sh "[benchmarks] Update weights for collectives" "$BRANCHNAME" - - rm -f ./artifacts/polkadot-parachain - - rm -f ./artifacts/test-parachain - after_script: - - rm -rf .git/config - tags: - - weights-vm - -benchmarks-bridge-hubs: - stage: benchmarks-run - timeout: 1d - extends: - - .docker-env - - .collect-artifacts - - .benchmarks-refs - before_script: - - !reference [.docker-env, before_script] - script: - - ./scripts/benchmarks-ci.sh bridge-hubs bridge-hub-polkadot ./artifacts - - ./scripts/benchmarks-ci.sh bridge-hubs bridge-hub-kusama ./artifacts - - ./scripts/benchmarks-ci.sh bridge-hubs bridge-hub-rococo ./artifacts - - export CURRENT_TIME=$(date '+%s') - - export BRANCHNAME="weights-bridge-hubs-${CI_COMMIT_BRANCH}-${CURRENT_TIME}" - - !reference [.git-commit-push, script] - - ./scripts/ci/create-benchmark-pr.sh "[benchmarks] Update weights for bridge-hubs" "$BRANCHNAME" - - rm -f ./artifacts/polkadot-parachain - - rm -f ./artifacts/test-parachain - after_script: - - rm -rf .git/config - tags: - - weights-vm diff --git a/cumulus/scripts/ci/gitlab/pipeline/build.yml b/cumulus/scripts/ci/gitlab/pipeline/build.yml deleted file mode 100644 index b47dd9fe30d..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/build.yml +++ /dev/null @@ -1,138 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "build" stage - -build-linux-stable: - stage: build - extends: - - .docker-env - - .common-refs - - .collect-artifacts - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-rustdoc - artifacts: false - script: - - echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" - - time cargo build --release --locked --bin polkadot-parachain - - echo "___Packing the artifacts___" - - mkdir -p ./artifacts - - mv ./target/release/polkadot-parachain ./artifacts/. - - echo "___The VERSION is either a tag name or the curent branch if triggered not by a tag___" - - echo ${CI_COMMIT_REF_NAME} | tee ./artifacts/VERSION - -build-test-parachain: - stage: build - extends: - - .docker-env - - .common-refs - - .collect-artifacts - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-rustdoc - artifacts: false - script: - - echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" - - time cargo build --release --locked --bin test-parachain - - echo "___Packing the artifacts___" - - mkdir -p ./artifacts - - mv ./target/release/test-parachain ./artifacts/. - - mkdir -p ./artifacts/zombienet - - mv ./target/release/wbuild/cumulus-test-runtime/wasm_binary_spec_version_incremented.rs.compact.compressed.wasm ./artifacts/zombienet/. - -# build runtime only if files in $RUNTIME_PATH/$RUNTIME_NAME were changed -.build-runtime-template: &build-runtime-template - stage: build - extends: - - .docker-env - - .pr-refs - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-rustdoc - artifacts: false - variables: - RUNTIME_PATH: "parachains/runtimes/assets" - script: - - cd ${RUNTIME_PATH} - - for directory in $(echo */); do - echo "_____Running cargo check for ${directory} ______"; - cd ${directory}; - pwd; - SKIP_WASM_BUILD=1 cargo check --locked; - cd ..; - done - -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-bridge-hubs -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-contracts -# DAG: build-runtime-assets -> build-runtime-starters -> build-runtime-testing -build-runtime-assets: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/assets" - -build-runtime-collectives: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/collectives" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-bridge-hubs: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/bridge-hubs" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-contracts: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/contracts" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-starters: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/starters" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-testing: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "parachains/runtimes/testing" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-starters - artifacts: false - -build-short-benchmark: - stage: build - extends: - - .docker-env - - .common-refs - - .collect-artifacts - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-rustdoc - artifacts: false - script: - - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot-parachain - - mkdir -p ./artifacts - - cp ./target/release/polkadot-parachain ./artifacts/ diff --git a/cumulus/scripts/ci/gitlab/pipeline/integration_tests.yml b/cumulus/scripts/ci/gitlab/pipeline/integration_tests.yml deleted file mode 100644 index a884361aa7c..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/integration_tests.yml +++ /dev/null @@ -1,2 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "integration_stage" stage diff --git a/cumulus/scripts/ci/gitlab/pipeline/publish.yml b/cumulus/scripts/ci/gitlab/pipeline/publish.yml deleted file mode 100644 index e59ff167698..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/publish.yml +++ /dev/null @@ -1,105 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "publish" stage - -.build-push-image: - image: $BUILDAH_IMAGE - variables: - DOCKERFILE: "" # docker/path-to.Dockerfile - IMAGE_NAME: "" # docker.io/paritypr/image_name - VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" - script: - - test "$PARITYPR_USER" -a "$PARITYPR_PASS" || - ( echo "no docker credentials provided"; exit 1 ) - - $BUILDAH_COMMAND build - --format=docker - --build-arg VCS_REF="${CI_COMMIT_SHA}" - --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" - --build-arg IMAGE_NAME="${IMAGE_NAME}" - --tag "$IMAGE_NAME:$VERSION" - --file ${DOCKERFILE} . - - echo "$PARITYPR_PASS" | - buildah login --username "$PARITYPR_USER" --password-stdin docker.io - - $BUILDAH_COMMAND info - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$VERSION" - after_script: - - buildah logout --all - -build-push-image-polkadot-parachain-debug: - stage: publish - extends: - - .kubernetes-env - - .common-refs - - .build-push-image - needs: - - job: build-linux-stable - artifacts: true - variables: - DOCKERFILE: "docker/polkadot-parachain-debug_unsigned_injected.Dockerfile" - IMAGE_NAME: "docker.io/paritypr/polkadot-parachain-debug" - VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" - -build-push-image-test-parachain: - stage: publish - extends: - - .kubernetes-env - - .common-refs - - .build-push-image - needs: - - job: build-test-parachain - artifacts: true - variables: - DOCKERFILE: "docker/test-parachain_injected.Dockerfile" - IMAGE_NAME: "docker.io/paritypr/test-parachain" - VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" - -publish-s3: - stage: publish - extends: - - .kubernetes-env - - .publish-refs - image: paritytech/awscli:latest - needs: - - job: build-linux-stable - artifacts: true - variables: - GIT_STRATEGY: none - BUCKET: "releases.parity.io" - PREFIX: "cumulus/${ARCH}-${DOCKER_OS}" - script: - - echo "___Publishing a binary with debug assertions!___" - - echo "___VERSION = $(cat ./artifacts/VERSION) ___" - - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/VERSION)/ - - echo "___Updating objects in latest path___" - - aws s3 sync s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/VERSION)/ s3://${BUCKET}/${PREFIX}/latest/ - after_script: - - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ - --recursive --human-readable --summarize - -publish-benchmarks-assets-s3: &publish-benchmarks - stage: publish - extends: - - .kubernetes-env - - .benchmarks-refs - image: paritytech/awscli:latest - needs: - - job: benchmarks-assets - artifacts: true - variables: - GIT_STRATEGY: none - BUCKET: "releases.parity.io" - PREFIX: "cumulus/$CI_COMMIT_REF_NAME/benchmarks-assets" - script: - - echo "___Publishing benchmark results___" - - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/ - after_script: - - aws s3 ls s3://${BUCKET}/${PREFIX}/ --recursive --human-readable --summarize - -publish-benchmarks-collectives-s3: - <<: *publish-benchmarks - variables: - GIT_STRATEGY: none - BUCKET: "releases.parity.io" - PREFIX: "cumulus/$CI_COMMIT_REF_NAME/benchmarks-collectives" - needs: - - job: benchmarks-collectives - artifacts: true diff --git a/cumulus/scripts/ci/gitlab/pipeline/short-benchmarks.yml b/cumulus/scripts/ci/gitlab/pipeline/short-benchmarks.yml deleted file mode 100644 index f63ad1e0d04..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/short-benchmarks.yml +++ /dev/null @@ -1,56 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "short-benchmarks" stage - -# Run all pallet benchmarks only once to check if there are any errors -.short-benchmark-template: &short-bench - stage: short-benchmarks - extends: - - .common-refs - - .docker-env - needs: - - job: build-short-benchmark - artifacts: true - variables: - RUNTIME_CHAIN: benchmarked-runtime-chain - script: - - ./artifacts/polkadot-parachain benchmark pallet --wasm-execution compiled --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -short-benchmark-asset-hub-polkadot: - <<: *short-bench - variables: - RUNTIME_CHAIN: asset-hub-polkadot-dev - -short-benchmark-asset-hub-kusama: - <<: *short-bench - variables: - RUNTIME_CHAIN: asset-hub-kusama-dev - -short-benchmark-asset-hub-westend: - <<: *short-bench - variables: - RUNTIME_CHAIN: asset-hub-westend-dev - -short-benchmark-bridge-hub-polkadot: - <<: *short-bench - variables: - RUNTIME_CHAIN: bridge-hub-polkadot-dev - -short-benchmark-bridge-hub-kusama: - <<: *short-bench - variables: - RUNTIME_CHAIN: bridge-hub-kusama-dev - -short-benchmark-bridge-hub-rococo: - <<: *short-bench - variables: - RUNTIME_CHAIN: bridge-hub-rococo-dev - -short-benchmark-collectives-polkadot : - <<: *short-bench - variables: - RUNTIME_CHAIN: collectives-polkadot-dev - -short-benchmark-glutton-kusama : - <<: *short-bench - variables: - RUNTIME_CHAIN: glutton-kusama-dev-1300 diff --git a/cumulus/scripts/ci/gitlab/pipeline/test.yml b/cumulus/scripts/ci/gitlab/pipeline/test.yml deleted file mode 100644 index 2d84010cb74..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/test.yml +++ /dev/null @@ -1,111 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "test" stage - -# It's more like a check, but we want to run this job with real tests in parallel -find-fail-ci-phrase: - stage: test - variables: - CI_IMAGE: "paritytech/tools:latest" - ASSERT_REGEX: "FAIL-CI" - GIT_DEPTH: 1 - extends: - - .kubernetes-env - script: - - set +e - - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - - if [ $exit_status -eq 0 ]; then - echo "$ASSERT_REGEX was found, exiting with 1"; - exit 1; - else - echo "No $ASSERT_REGEX was found, exiting with 0"; - exit 0; - fi - -test-linux-stable: - stage: test - extends: - - .docker-env - - .common-refs - - .pipeline-stopper-artifacts - before_script: - - !reference [.docker-env, before_script] - - !reference [.pipeline-stopper-vars, before_script] - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo nextest run --all --release --locked --run-ignored all - -test-doc: - stage: test - extends: - - .docker-env - - .common-refs - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo test --doc - -check-runtime-benchmarks: - stage: test - extends: - - .docker-env - - .common-refs - script: - # Check that the node will compile with `runtime-benchmarks` feature flag. - - time cargo check --locked --all --features runtime-benchmarks - # Check that parachain-template will compile with `runtime-benchmarks` feature flag. - - time cargo check --locked -p parachain-template-node --features runtime-benchmarks - -cargo-check-try-runtime: - stage: test - extends: - - .docker-env - - .common-refs - variables: - RUSTFLAGS: "-D warnings" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-runtime-benchmarks - artifacts: false - script: - # Check that the node will compile with `try-runtime` feature flag. - - time cargo check --locked --all --features try-runtime - # Check that parachain-template will compile with `try-runtime` feature flag. - - time cargo check --locked -p parachain-template-node --features try-runtime - -check-rustdoc: - stage: test - extends: - - .docker-env - - .common-refs - variables: - SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" - script: - - time cargo doc --workspace --all-features --verbose --no-deps - -cargo-check-benches: - stage: test - extends: - - .docker-env - - .common-refs - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-rustdoc - artifacts: false - script: - - time cargo check --all --benches - -cargo-clippy: - stage: test - extends: - - .docker-env - - .common-refs - script: - - echo $RUSTFLAGS - - cargo version && cargo clippy --version - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --locked --all-targets --workspace diff --git a/cumulus/scripts/ci/gitlab/pipeline/zombienet.yml b/cumulus/scripts/ci/gitlab/pipeline/zombienet.yml deleted file mode 100644 index d5ab3e13d42..00000000000 --- a/cumulus/scripts/ci/gitlab/pipeline/zombienet.yml +++ /dev/null @@ -1,141 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "zombienet" stage - -.zombienet-before-script: - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE}" - - echo "${RELAY_IMAGE}" - - echo "${COL_IMAGE}" - - echo "${GH_DIR}" - - export DEBUG=zombie - - export RELAY_IMAGE=${POLKADOT_IMAGE} - - export COL_IMAGE=${COL_IMAGE} - -.zombienet-after-script: - after_script: - - mkdir -p ./zombienet-logs - - cp /tmp/zombie*/logs/* ./zombienet-logs/ - -# common settings for all zombienet jobs -.zombienet-common: - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - needs: - - job: build-push-image-test-parachain - artifacts: true - variables: - POLKADOT_IMAGE: "docker.io/paritypr/polkadot-debug:master" - GH_DIR: "https://github.com/paritytech/cumulus/tree/${CI_COMMIT_SHORT_SHA}/zombienet/tests" - COL_IMAGE: "docker.io/paritypr/test-parachain:${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" - FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 2 days - paths: - - ./zombienet-logs - allow_failure: false - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-0001-sync_blocks_from_tip_without_connected_collator: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0001-sync_blocks_from_tip_without_connected_collator.zndsl" - -zombienet-0002-pov_recovery: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0002-pov_recovery.zndsl" - -zombienet-0003-full_node_catching_up: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0003-full_node_catching_up.zndsl" - -zombienet-0004-runtime_upgrade: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - needs: - - !reference [.zombienet-common, needs] - - job: build-test-parachain - artifacts: true - before_script: - - ls -ltr * - - cp ./artifacts/zombienet/wasm_binary_spec_version_incremented.rs.compact.compressed.wasm /tmp/ - - ls /tmp - - !reference [.zombienet-before-script, before_script] - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0004-runtime_upgrade.zndsl" - -zombienet-0005-migrate_solo_to_para: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - needs: - - !reference [.zombienet-common, needs] - - job: build-test-parachain - artifacts: true - before_script: - - ls -ltr * - - !reference [.zombienet-before-script, before_script] - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0005-migrate_solo_to_para.zndsl" - -zombienet-0006-rpc_collator_builds_blocks: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0006-rpc_collator_builds_blocks.zndsl" - -zombienet-0007-full_node_warp_sync: - extends: - - .zombienet-common - - .zombienet-refs - - .zombienet-before-script - - .zombienet-after-script - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}" - --concurrency=1 - --test="0007-full_node_warp_sync.zndsl" diff --git a/cumulus/scripts/ci/gitlab/prettier.sh b/cumulus/scripts/ci/gitlab/prettier.sh deleted file mode 100755 index 299bbee179d..00000000000 --- a/cumulus/scripts/ci/gitlab/prettier.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# meant to be installed via -# git config filter.ci-prettier.clean "scripts/ci/gitlab/prettier.sh" - -prettier --parser yaml diff --git a/substrate/scripts/ci/common/lib.sh b/substrate/scripts/ci/common/lib.sh deleted file mode 100755 index 08c2fe81ada..00000000000 --- a/substrate/scripts/ci/common/lib.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/sh - -api_base="https://api.github.com/repos" - -# Function to take 2 git tags/commits and get any lines from commit messages -# that contain something that looks like a PR reference: e.g., (#1234) -sanitised_git_logs(){ - git --no-pager log --pretty=format:"%s" "$1...$2" | - # Only find messages referencing a PR - grep -E '\(#[0-9]+\)' | - # Strip any asterisks - sed 's/^* //g' | - # And add them all back - sed 's/^/* /g' -} - -# Returns the last published release on github -# Note: we can't just use /latest because that ignores prereleases -# repo: 'organization/repo' -# Usage: last_github_release "$repo" -last_github_release(){ - i=0 - # Iterate over releases until we find the last release that's not just a draft - while [ $i -lt 29 ]; do - out=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$api_base/$1/releases" | jq ".[$i]") - echo "$out" - # Ugh when echoing to jq, we need to translate newlines into spaces :/ - if [ "$(echo "$out" | tr '\r\n' ' ' | jq '.draft')" = "false" ]; then - echo "$out" | tr '\r\n' ' ' | jq '.tag_name' - return - else - i=$((i + 1)) - fi - done -} - -# Checks whether a tag on github has been verified -# repo: 'organization/repo' -# tagver: 'v1.2.3' -# Usage: check_tag $repo $tagver -check_tag () { - repo=$1 - tagver=$2 - tag_out=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") - tag_sha=$(echo "$tag_out" | jq -r .object.sha) - object_url=$(echo "$tag_out" | jq -r .object.url) - if [ "$tag_sha" = "null" ]; then - return 2 - fi - verified_str=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$object_url" | jq -r .verification.verified) - if [ "$verified_str" = "true" ]; then - # Verified, everything is good - return 0 - else - # Not verified. Bad juju. - return 1 - fi -} - -# Checks whether a given PR has a given label. -# repo: 'organization/repo' -# pr_id: 12345 -# label: B1-silent -# Usage: has_label $repo $pr_id $label -has_label(){ - repo="$1" - pr_id="$2" - label="$3" - - # These will exist if the function is called in Gitlab. - # If the function's called in Github, we should have GITHUB_ACCESS_TOKEN set - # already. - if [ -n "$GITHUB_RELEASE_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_RELEASE_TOKEN" - elif [ -n "$GITHUB_PR_TOKEN" ]; then - GITHUB_TOKEN="$GITHUB_PR_TOKEN" - fi - - out=$(curl -H "Authorization: token $GITHUB_TOKEN" -s "$api_base/$repo/pulls/$pr_id") - [ -n "$(echo "$out" | tr -d '\r\n' | jq ".labels | .[] | select(.name==\"$label\")")" ] -} - -# Formats a message into a JSON string for posting to Matrix -# message: 'any plaintext message' -# formatted_message: 'optional message formatted in html' -# Usage: structure_message $content $formatted_content (optional) -structure_message() { - if [ -z "$2" ]; then - body=$(jq -Rs --arg body "$1" '{"msgtype": "m.text", $body}' < /dev/null) - else - body=$(jq -Rs --arg body "$1" --arg formatted_body "$2" '{"msgtype": "m.text", $body, "format": "org.matrix.custom.html", $formatted_body}' < /dev/null) - fi - echo "$body" -} - -# Post a message to a matrix room -# body: '{body: "JSON string produced by structure_message"}' -# room_id: !fsfSRjgjBWEWffws:matrix.parity.io -# access_token: see https://matrix.org/docs/guides/client-server-api/ -# Usage: send_message $body (json formatted) $room_id $access_token -send_message() { - curl -XPOST -d "$1" "https://m.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" -} - -# Check for runtime changes between two commits. This is defined as any changes -# to bin/node/src/runtime, frame/ and primitives/sr_* trees. -has_runtime_changes() { - from=$1 - to=$2 - if git diff --name-only "${from}...${to}" \ - | grep -q -e '^frame/' -e '^primitives/' - then - return 0 - else - return 1 - fi -} diff --git a/substrate/scripts/ci/github/check_labels.sh b/substrate/scripts/ci/github/check_labels.sh deleted file mode 100755 index 7b0aed9fe73..00000000000 --- a/substrate/scripts/ci/github/check_labels.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash -set -e - -#shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -repo="$GITHUB_REPOSITORY" -pr="$GITHUB_PR" - -ensure_labels() { - for label in "$@"; do - if has_label "$repo" "$pr" "$label"; then - return 0 - fi - done - return 1 -} - -# Must have one of the following labels -releasenotes_labels=( - 'B0-silent' - 'B3-apinoteworthy' - 'B5-clientnoteworthy' - 'B7-runtimenoteworthy' -) - -criticality_labels=( - 'C1-low 📌' - 'C3-medium 📣' - 'C7-high ❗️' - 'C9-critical ‼️' -) - -audit_labels=( - 'D1-audited 👍' - 'D2-notlive 💤' - 'D3-trivial 🧸' - 'D5-nicetohaveaudit ⚠️' - 'D9-needsaudit 👮' -) - -echo "[+] Checking release notes (B) labels" -if ensure_labels "${releasenotes_labels[@]}"; then - echo "[+] Release notes label detected. All is well." -else - echo "[!] Release notes label not detected. Please add one of: ${releasenotes_labels[*]}" - exit 1 -fi - -echo "[+] Checking release criticality (C) labels" -if ensure_labels "${criticality_labels[@]}"; then - echo "[+] Release criticality label detected. All is well." -else - echo "[!] Release criticality label not detected. Please add one of: ${criticality_labels[*]}" - exit 1 -fi - -if has_runtime_changes origin/master "${HEAD_SHA}"; then - echo "[+] Runtime changes detected. Checking audit (D) labels" - if ensure_labels "${audit_labels[@]}"; then - echo "[+] Release audit label detected. All is well." - else - echo "[!] Release audit label not detected. Please add one of: ${audit_labels[*]}" - exit 1 - fi -fi - -exit 0 diff --git a/substrate/scripts/ci/github/generate_changelog.sh b/substrate/scripts/ci/github/generate_changelog.sh deleted file mode 100755 index 32ac1760a61..00000000000 --- a/substrate/scripts/ci/github/generate_changelog.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env bash - -# shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -version="$2" -last_version="$1" - -all_changes="$(sanitised_git_logs "$last_version" "$version")" -runtime_changes="" -api_changes="" -client_changes="" -changes="" -migrations="" - -while IFS= read -r line; do - pr_id=$(echo "$line" | sed -E 's/.*#([0-9]+)\)$/\1/') - - # Skip if the PR has the silent label - this allows us to skip a few requests - if has_label 'paritytech/substrate' "$pr_id" 'B0-silent'; then - continue - fi - if has_label 'paritytech/substrate' "$pr_id" 'B3-apinoteworthy' ; then - api_changes="$api_changes -$line" - fi - if has_label 'paritytech/substrate' "$pr_id" 'B5-clientnoteworthy'; then - client_changes="$client_changes -$line" - fi - if has_label 'paritytech/substrate' "$pr_id" 'B7-runtimenoteworthy'; then - runtime_changes="$runtime_changes -$line" - fi - if has_label 'paritytech/substrate' "$pr_id" 'E1-runtime-migration'; then - migrations="$migrations -$line" - fi -done <<< "$all_changes" - -# Make the substrate section if there are any substrate changes -if [ -n "$runtime_changes" ] || - [ -n "$api_changes" ] || - [ -n "$client_changes" ] || - [ -n "$migrations" ]; then - changes=$(cat << EOF -Substrate changes ------------------ - -EOF -) - if [ -n "$runtime_changes" ]; then - changes="$changes - -Runtime -------- -$runtime_changes" - fi - if [ -n "$client_changes" ]; then - changes="$changes - -Client ------- -$client_changes" - fi - if [ -n "$api_changes" ]; then - changes="$changes - -API ---- -$api_changes" - fi - release_text="$release_text - -$changes" -fi -if [ -n "$migrations" ]; then - changes="$changes - -Runtime Migrations ------------------- -$migrations" -fi - -echo "$changes" diff --git a/substrate/scripts/ci/gitlab/check-each-crate.py b/substrate/scripts/ci/gitlab/check-each-crate.py deleted file mode 100755 index adad4f5bd58..00000000000 --- a/substrate/scripts/ci/gitlab/check-each-crate.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -# A script that checks each workspace crate individually. -# It's relevant to check workspace crates individually because otherwise their compilation problems -# due to feature misconfigurations won't be caught, as exemplified by -# https://github.com/paritytech/substrate/issues/12705 -# -# `check-each-crate.py target_group groups_total` -# -# - `target_group`: Integer starting from 1, the group this script should execute. -# - `groups_total`: Integer starting from 1, total number of groups. - -import subprocess, sys - -# Get all crates -output = subprocess.check_output(["cargo", "tree", "--locked", "--workspace", "--depth", "0", "--prefix", "none"]) - -# Convert the output into a proper list -crates = [] -for line in output.splitlines(): - if line != b"": - crates.append(line.decode('utf8').split(" ")[0]) - -# Make the list unique and sorted -crates = list(set(crates)) -crates.sort() - -target_group = int(sys.argv[1]) - 1 -groups_total = int(sys.argv[2]) - -if len(crates) == 0: - print("No crates detected!", file=sys.stderr) - sys.exit(1) - -print(f"Total crates: {len(crates)}", file=sys.stderr) - -crates_per_group = len(crates) // groups_total - -# If this is the last runner, we need to take care of crates -# after the group that we lost because of the integer division. -if target_group + 1 == groups_total: - overflow_crates = len(crates) % groups_total -else: - overflow_crates = 0 - -print(f"Crates per group: {crates_per_group}", file=sys.stderr) - -# Check each crate -for i in range(0, crates_per_group + overflow_crates): - crate = crates_per_group * target_group + i - - print(f"Checking {crates[crate]}", file=sys.stderr) - - res = subprocess.run(["cargo", "check", "--locked", "-p", crates[crate]]) - - if res.returncode != 0: - sys.exit(1) diff --git a/substrate/scripts/ci/gitlab/check_runtime.sh b/substrate/scripts/ci/gitlab/check_runtime.sh deleted file mode 100755 index 71d6965ecf4..00000000000 --- a/substrate/scripts/ci/gitlab/check_runtime.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -# -# -# check for any changes in the node/src/runtime, frame/ and primitives/sr_* trees. if -# there are any changes found, it should mark the PR breaksconsensus and -# "auto-fail" the PR if there isn't a change in the runtime/src/lib.rs file -# that alters the version. - -set -e # fail on any error - -#shellcheck source=../common/lib.sh -. "$(dirname "${0}")/../common/lib.sh" - -VERSIONS_FILE="bin/node/runtime/src/lib.rs" - -boldprint () { printf "|\n| \033[1m%s\033[0m\n|\n" "${@}"; } -boldcat () { printf "|\n"; while read -r l; do printf "| \033[1m%s\033[0m\n" "${l}"; done; printf "|\n" ; } - -github_label () { - echo - echo "# run github-api job for labeling it ${1}" - curl -sS -X POST \ - -F "token=${CI_JOB_TOKEN}" \ - -F "ref=master" \ - -F "variables[LABEL]=${1}" \ - -F "variables[PRNO]=${CI_COMMIT_REF_NAME}" \ - "${GITLAB_API}/projects/${GITHUB_API_PROJECT}/trigger/pipeline" -} - - -boldprint "latest 10 commits of ${CI_COMMIT_REF_NAME}" -git log --graph --oneline --decorate=short -n 10 - -boldprint "make sure the master branch and release tag are available in shallow clones" -git fetch --depth="${GIT_DEPTH:-100}" origin master -git fetch --depth="${GIT_DEPTH:-100}" origin release -git tag -f release FETCH_HEAD -git log -n1 release - - -boldprint "check if the wasm sources changed" -if ! has_runtime_changes origin/master "${CI_COMMIT_SHA}" -then - boldcat <<-EOT - - no changes to the runtime source code detected - - EOT - - exit 0 -fi - - - -# check for spec_version updates: if the spec versions changed, then there is -# consensus-critical logic that has changed. the runtime wasm blobs must be -# rebuilt. - -add_spec_version="$(git diff tags/release ${CI_COMMIT_SHA} -- "${VERSIONS_FILE}" \ - | sed -n -r "s/^\+[[:space:]]+spec_version: +([0-9]+),$/\1/p")" -sub_spec_version="$(git diff tags/release ${CI_COMMIT_SHA} -- "${VERSIONS_FILE}" \ - | sed -n -r "s/^\-[[:space:]]+spec_version: +([0-9]+),$/\1/p")" - - - -if [ "${add_spec_version}" != "${sub_spec_version}" ] -then - - boldcat <<-EOT - - changes to the runtime sources and changes in the spec version. - - spec_version: ${sub_spec_version} -> ${add_spec_version} - - EOT - exit 0 - -else - # check for impl_version updates: if only the impl versions changed, we assume - # there is no consensus-critical logic that has changed. - - add_impl_version="$(git diff tags/release ${CI_COMMIT_SHA} -- "${VERSIONS_FILE}" \ - | sed -n -r 's/^\+[[:space:]]+impl_version: +([0-9]+),$/\1/p')" - sub_impl_version="$(git diff tags/release ${CI_COMMIT_SHA} -- "${VERSIONS_FILE}" \ - | sed -n -r 's/^\-[[:space:]]+impl_version: +([0-9]+),$/\1/p')" - - - # see if the impl version changed - if [ "${add_impl_version}" != "${sub_impl_version}" ] - then - boldcat <<-EOT - - changes to the runtime sources and changes in the impl version. - - impl_version: ${sub_impl_version} -> ${add_impl_version} - - EOT - exit 0 - fi - - - boldcat <<-EOT - - wasm source files changed but not the spec/impl version. If changes made do not alter logic, - just bump 'impl_version'. If they do change logic, bump 'spec_version'. - - source file directories: - - bin/node/src/runtime - - frame - - primitives/sr-* - - versions file: ${VERSIONS_FILE} - - EOT -fi - -# dropped through. there's something wrong; exit 1. - -exit 1 - -# vim: noexpandtab diff --git a/substrate/scripts/ci/gitlab/check_signed.sh b/substrate/scripts/ci/gitlab/check_signed.sh deleted file mode 100755 index 20d47c23047..00000000000 --- a/substrate/scripts/ci/gitlab/check_signed.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -version="$CI_COMMIT_TAG" - -echo '[+] Checking tag has been signed' -check_tag "paritytech/substrate" "$version" -case $? in - 0) echo '[+] Tag found and has been signed'; exit 0 - ;; - 1) echo '[!] Tag found but has not been signed. Aborting release.'; exit 1 - ;; - 2) echo '[!] Tag not found. Aborting release.'; exit 1 -esac diff --git a/substrate/scripts/ci/gitlab/ensure-deps.sh b/substrate/scripts/ci/gitlab/ensure-deps.sh deleted file mode 100755 index 7087200cef5..00000000000 --- a/substrate/scripts/ci/gitlab/ensure-deps.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash - -# The script is meant to check if the rules regarding packages -# dependencies are satisfied. -# The general format is: -# [top-lvl-dir] MESSAGE/[other-top-dir] - -# For instance no crate within `./client` directory -# is allowed to import any crate with a directory path containing `frame`. -# Such rule is just: `client crates must not depend on anything in /frame`. - -# The script should be run from the main repo directory! - -set -u - -# HARD FAILING -MUST_NOT=( - "client crates must not depend on anything in /frame" - "client crates must not depend on anything in /node" - "frame crates must not depend on anything in /node" - "frame crates must not depend on anything in /client" - "primitives crates must not depend on anything in /frame" -) - -# ONLY DISPLAYED, script still succeeds -PLEASE_DONT=( - "primitives crates should not depend on anything in /client" -) - -VIOLATIONS=() -PACKAGES=() - -function check_rule() { - rule=$1 - from=$(echo $rule | cut -f1 -d\ ) - to=$(echo $rule | cut -f2 -d\/) - - cd $from - echo "Checking rule '$rule'" - packages=$(find -name Cargo.toml | xargs grep -wn "path.*\.\.\/$to") - has_references=$(echo -n $packages | wc -c) - if [ "$has_references" != "0" ]; then - VIOLATIONS+=("$rule") - # Find packages that violate: - PACKAGES+=("$packages") - fi - cd - > /dev/null -} - -for rule in "${MUST_NOT[@]}" -do - check_rule "$rule"; -done - -# Only the MUST NOT will be counted towards failure -HARD_VIOLATIONS=${#VIOLATIONS[@]} - - -for rule in "${PLEASE_DONT[@]}" -do - check_rule "$rule"; -done - -# Display violations and fail -I=0 -for v in "${VIOLATIONS[@]}" -do - cat << EOF - -=========================================== -======= Violation of rule: $v -=========================================== -${PACKAGES[$I]} - - -EOF - I=$I+1 -done - -exit $HARD_VIOLATIONS diff --git a/substrate/scripts/ci/gitlab/pipeline/build.yml b/substrate/scripts/ci/gitlab/pipeline/build.yml deleted file mode 100644 index 8f63f6ecc39..00000000000 --- a/substrate/scripts/ci/gitlab/pipeline/build.yml +++ /dev/null @@ -1,215 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "build" stage - -# PIPELINE_SCRIPTS_TAG can be found in the project variables - -.check-dependent-project: - stage: build - # DAG: this is artificial dependency - needs: - - job: cargo-clippy - artifacts: false - extends: - - .docker-env - - .test-refs-no-trigger-prs-only - variables: - RUSTFLAGS: "-D warnings" - script: - - cargo install --locked --git https://github.com/paritytech/try-runtime-cli --rev a93c9b5abe5d31a4cf1936204f7e5c489184b521 - - git clone - --depth=1 - --branch="$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts - - ./pipeline-scripts/check_dependent_project.sh - --org paritytech - --dependent-repo "$DEPENDENT_REPO" - --github-api-token "$GITHUB_PR_TOKEN" - --extra-dependencies "$EXTRA_DEPENDENCIES" - --companion-overrides "$COMPANION_OVERRIDES" - -.check-runtime-migration: - extends: - - .check-dependent-project - - .test-refs-no-trigger-prs-only - variables: - DEPENDENT_REPO: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - polkadot: release-v* - COMPANION_CHECK_COMMAND: > - time cargo build --release -p "$NETWORK"-runtime --features try-runtime && - 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 - -# Individual jobs are set up for each dependent project so that they can be ran in parallel. -# Arguably we could generate a job for each companion in the PR's description using Gitlab's -# parent-child pipelines but that's more complicated. - -check-runtime-migration-polkadot: - extends: - - .check-runtime-migration - variables: - NETWORK: polkadot - -check-runtime-migration-kusama: - extends: .check-runtime-migration - variables: - NETWORK: kusama - -check-runtime-migration-rococo: - extends: .check-runtime-migration - variables: - NETWORK: rococo - allow_failure: true - -check-runtime-migration-westend: - extends: .check-runtime-migration - variables: - NETWORK: westend - -check-dependent-polkadot: - extends: .check-dependent-project - variables: - DEPENDENT_REPO: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - polkadot: release-v* - # enable the same feature flags as polkadot's test-linux-stable - COMPANION_CHECK_COMMAND: > - cargo check --all-targets --workspace - --features=runtime-benchmarks,runtime-metrics,try-runtime - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs - -check-dependent-cumulus: - extends: .check-dependent-project - variables: - DEPENDENT_REPO: cumulus - EXTRA_DEPENDENCIES: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - polkadot: release-v* - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs - -build-linux-substrate: - stage: build - extends: - - .collect-artifacts - - .docker-env - - .build-refs - variables: - # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - needs: - - job: test-linux-stable - artifacts: false - before_script: - - !reference [.timestamp, before_script] - - !reference [.job-switcher, before_script] - - mkdir -p ./artifacts/substrate/ - - !reference [.rusty-cachier, before_script] - # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary - # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 - - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" - script: - - rusty-cachier snapshot create - - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release -p node-cli --verbose - - mv $CARGO_TARGET_DIR/release/substrate-node ./artifacts/substrate/substrate - - echo -n "Substrate version = " - - if [ "${CI_COMMIT_TAG}" ]; then - echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; - else - ./artifacts/substrate/substrate --version | - cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; - fi - - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 - - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - - printf '\n# building node-template\n\n' - - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz - - rusty-cachier cache upload - -.build-subkey: - stage: build - extends: - - .collect-artifacts - - .docker-env - - .publish-refs - variables: - # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - before_script: - - !reference [.timestamp, before_script] - - !reference [.job-switcher, before_script] - - mkdir -p ./artifacts/subkey - - !reference [.rusty-cachier, before_script] - script: - - rusty-cachier snapshot create - - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - - cd - - - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. - - echo -n "Subkey version = " - - ./artifacts/subkey/subkey --version | - sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | - tee ./artifacts/subkey/VERSION; - - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ - - rusty-cachier cache upload - -build-subkey-linux: - extends: .build-subkey - -build-subkey-macos: - extends: .build-subkey - # duplicating before_script & script sections from .build-subkey hidden job - # to overwrite rusty-cachier integration as it doesn't work on macos - before_script: - # skip timestamp script, the osx bash doesn't support printf %()T - - !reference [.job-switcher, before_script] - - mkdir -p ./artifacts/subkey - script: - - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - - cd - - - mv ./target/release/subkey ./artifacts/subkey/. - - echo -n "Subkey version = " - - ./artifacts/subkey/subkey --version | - sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | - tee ./artifacts/subkey/VERSION; - - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ - after_script: [""] - tags: - - osx - -build-rustdoc: - stage: build - extends: - - .docker-env - - .test-refs - variables: - SKIP_WASM_BUILD: 1 - DOC_INDEX_PAGE: "substrate/index.html" # default redirected page - # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 7 days - paths: - - ./crate-docs/ - # DAG: this is artificial dependency - needs: - - job: cargo-clippy - artifacts: false - script: - - rusty-cachier snapshot create - - time cargo doc --locked --workspace --all-features --verbose --no-deps - - rm -f $CARGO_TARGET_DIR/doc/.lock - - mv $CARGO_TARGET_DIR/doc ./crate-docs - # FIXME: remove me after CI image gets nonroot - - chown -R nonroot:nonroot ./crate-docs - - echo "" > ./crate-docs/index.html - - rusty-cachier cache upload diff --git a/substrate/scripts/ci/gitlab/pipeline/check.yml b/substrate/scripts/ci/gitlab/pipeline/check.yml deleted file mode 100644 index 576daec9b43..00000000000 --- a/substrate/scripts/ci/gitlab/pipeline/check.yml +++ /dev/null @@ -1,78 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "check" stage - -check-runtime: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - variables: - CI_IMAGE: "paritytech/tools:latest" - GITLAB_API: "https://gitlab.parity.io/api/v4" - GITHUB_API_PROJECT: "parity%2Finfrastructure%2Fgithub-api" - script: - - ./scripts/ci/gitlab/check_runtime.sh - allow_failure: true - -check-signed-tag: - stage: check - extends: .kubernetes-env - variables: - CI_IMAGE: "paritytech/tools:latest" - rules: - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - ./scripts/ci/gitlab/check_signed.sh - -test-dependency-rules: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - variables: - CI_IMAGE: "paritytech/tools:latest" - script: - - ./scripts/ci/gitlab/ensure-deps.sh - -test-rust-features: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - script: - - git clone - --depth=1 - --branch="$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts - - bash ./pipeline-scripts/rust-features.sh . - -test-rust-feature-propagation: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - script: - - cargo install --locked --version 0.7.4 -q -f zepter && zepter --version - - echo "👉 Hello developer! If you see this CI check failing then it means that one of the crates is missing a feature for one of its dependencies. The output below tells you which feature needs to be added for which dependency to which crate. You can do this by modifying the Cargo.toml file. For more context see the MR where this check was introduced https://github.com/paritytech/substrate/pull/14660" - - zepter lint propagate-feature --feature try-runtime --left-side-feature-missing=ignore --workspace --feature-enables-dep="try-runtime:frame-try-runtime" --locked - - zepter lint propagate-feature --feature runtime-benchmarks --left-side-feature-missing=ignore --workspace --feature-enables-dep="runtime-benchmarks:frame-benchmarking" --locked - - zepter lint propagate-feature --feature std --left-side-feature-missing=ignore --workspace --locked - allow_failure: true # Experimental - -test-prometheus-alerting-rules: - stage: check - extends: .kubernetes-env - variables: - CI_IMAGE: "paritytech/tools:latest" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_COMMIT_BRANCH - changes: - - .gitlab-ci.yml - - ./scripts/ci/monitoring/**/* - script: - - promtool check rules ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml - - cat ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml | - promtool test rules ./scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml diff --git a/substrate/scripts/ci/gitlab/pipeline/publish.yml b/substrate/scripts/ci/gitlab/pipeline/publish.yml deleted file mode 100644 index c90af7ba347..00000000000 --- a/substrate/scripts/ci/gitlab/pipeline/publish.yml +++ /dev/null @@ -1,270 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "publish" stage - -.build-push-docker-image-common: - extends: - - .kubernetes-env - stage: publish - variables: - CI_IMAGE: $BUILDAH_IMAGE - GIT_STRATEGY: none - DOCKERFILE: $PRODUCT.Dockerfile - IMAGE_NAME: docker.io/$IMAGE_PATH - before_script: - - !reference [.kubernetes-env, before_script] - - cd ./artifacts/$PRODUCT/ - - VERSION="$(cat ./VERSION)" - - echo "${PRODUCT} version = ${VERSION}" - - test -z "${VERSION}" && exit 1 - script: - - test "$DOCKER_USER" -a "$DOCKER_PASS" || - ( echo "no docker credentials provided"; exit 1 ) - - $BUILDAH_COMMAND build - --format=docker - --build-arg VCS_REF="${CI_COMMIT_SHA}" - --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" - --build-arg IMAGE_NAME="${IMAGE_PATH}" - --tag "$IMAGE_NAME:$VERSION" - --tag "$IMAGE_NAME:latest" - --file "$DOCKERFILE" . - - echo "$DOCKER_PASS" | - buildah login --username "$DOCKER_USER" --password-stdin docker.io - - $BUILDAH_COMMAND info - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$VERSION" - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:latest" - after_script: - - buildah logout --all - - echo "SUBSTRATE_IMAGE_NAME=${IMAGE_NAME}" | tee -a ./artifacts/$PRODUCT/build.env - - IMAGE_TAG="$(cat ./artifacts/$PRODUCT/VERSION)" - - echo "SUBSTRATE_IMAGE_TAG=${IMAGE_TAG}" | tee -a ./artifacts/$PRODUCT/build.env - - cat ./artifacts/$PRODUCT/build.env - -.build-push-docker-image: - extends: - - .publish-refs - - .build-push-docker-image-common - variables: - IMAGE_PATH: parity/$PRODUCT - DOCKER_USER: $Docker_Hub_User_Parity - DOCKER_PASS: $Docker_Hub_Pass_Parity - -.push-docker-image-description: - stage: publish - extends: - - .kubernetes-env - variables: - CI_IMAGE: paritytech/dockerhub-description - DOCKERHUB_REPOSITORY: parity/$PRODUCT - DOCKER_USERNAME: $Docker_Hub_User_Parity - DOCKER_PASSWORD: $Docker_Hub_Pass_Parity - README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md - rules: - - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" - changes: - - scripts/ci/docker/$PRODUCT.Dockerfile.README.md - before_script: - - echo - script: - - cd / && sh entrypoint.sh - -# publish image to docker.io/paritypr, (e.g. for later use in zombienet testing) -.build-push-image-temporary: - extends: - - .build-refs - - .build-push-docker-image-common - variables: - IMAGE_PATH: paritypr/$PRODUCT - DOCKER_USER: $PARITYPR_USER - DOCKER_PASS: $PARITYPR_PASS - -publish-docker-substrate: - extends: .build-push-docker-image - needs: - - job: build-linux-substrate - artifacts: true - variables: - PRODUCT: substrate - -publish-docker-description-substrate: - extends: .push-docker-image-description - variables: - PRODUCT: substrate - SHORT_DESCRIPTION: "Substrate Docker Image." - -publish-docker-substrate-temporary: - extends: .build-push-image-temporary - needs: - - job: build-linux-substrate - artifacts: true - variables: - PRODUCT: substrate - artifacts: - reports: - # this artifact is used in zombienet-tests job - # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance - dotenv: ./artifacts/$PRODUCT/build.env - expire_in: 24h - -publish-docker-subkey: - extends: .build-push-docker-image - needs: - - job: build-subkey-linux - artifacts: true - variables: - PRODUCT: subkey - -publish-docker-description-subkey: - extends: .push-docker-image-description - variables: - PRODUCT: subkey - SHORT_DESCRIPTION: "The subkey program is a key management utility for Substrate-based blockchains." - -publish-s3-release: - stage: publish - extends: - - .publish-refs - - .kubernetes-env - needs: - - job: build-linux-substrate - artifacts: true - - job: build-subkey-linux - artifacts: true - image: paritytech/awscli:latest - variables: - GIT_STRATEGY: none - BUCKET: "releases.parity.io" - PREFIX: "substrate/${ARCH}-${DOCKER_OS}" - script: - - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ - - echo "update objects in latest path" - - aws s3 sync s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ s3://${BUCKET}/${PREFIX}/latest/ - after_script: - - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ - --recursive --human-readable --summarize - -publish-rustdoc: - stage: publish - extends: .kubernetes-env - variables: - CI_IMAGE: node:16 - GIT_DEPTH: 100 - RUSTDOCS_DEPLOY_REFS: "master" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^monthly-20[0-9]{2}-[0-9]{2}.*$/ # to support: monthly-2021-09+1 - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - # `needs:` can be removed after CI image gets nonroot. In this case `needs:` stops other - # artifacts from being dowloaded by this job. - needs: - - job: build-rustdoc - artifacts: true - script: - # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we - # exit immediately. - # Putting spaces at the front and back to ensure we are not matching just any substring, but the - # whole space-separated value. - - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - # Save README and docs - - cp -r ./crate-docs/ /tmp/doc/ - - cp README.md /tmp/doc/ - # we don't need to commit changes because we copy docs to /tmp - - git checkout gh-pages --force - # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} - # Ensure the destination dir doesn't exist. - - rm -rf ${CI_COMMIT_REF_NAME} - - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} - # Upload files - - git add --all - # `git commit` has an exit code of > 0 if there is nothing to commit. - # This causes GitLab to exit immediately and marks this job failed. - # We don't want to mark the entire job failed if there's nothing to - # publish though, hence the `|| true`. - - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || - echo "___Nothing to commit___" - - git push origin gh-pages --force - after_script: - - rm -rf .git/ ./* - -publish-draft-release: - stage: publish - image: paritytech/tools:latest - rules: - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - ./scripts/ci/gitlab/publish_draft_release.sh - allow_failure: true - -.publish-crates-template: - stage: publish - extends: - - .crates-publishing-template - - .crates-publishing-pipeline - # We don't want multiple jobs racing to publish crates as it's redundant and they might overwrite - # the releases of one another. Use resource_group to ensure that at most one instance of this job - # is running at any given time. - resource_group: crates-publishing - # crates.io currently rate limits crate publishing at 1 per minute: - # https://github.com/paritytech/release-engineering/issues/123#issuecomment-1335509748 - # Taking into account the 202 (as of Dec 07, 2022) publishable Substrate crates, in the worst - # case, due to the rate limits alone, we'd have to wait through at least 202 minutes of delay. - # Taking into account also the verification steps and extra synchronization delays after - # publishing the crate, the job needs to have a much higher timeout than average. - timeout: 9h - # A custom publishing environment is used for us to be able to set up protected secrets - # specifically for it - environment: publish-crates - script: - - rusty-cachier snapshot create - - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git - - CRATESIO_TARGET_INSTANCE=default ./releng-scripts/publish-crates - - rusty-cachier cache upload - -publish-crates: - extends: .publish-crates-template - # publish-crates should only be run if publish-crates-locally passes - needs: - - job: check-crate-publishing - artifacts: false - -publish-crates-manual: - extends: .publish-crates-template - when: manual - interruptible: false - -check-crate-publishing: - stage: publish - extends: - - .crates-publishing-template - - .crates-publishing-pipeline - # When lots of crates are taken into account (for example on master where all crates are tested) - # the job might take a long time, as evidenced by: - # https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2269364 - timeout: 4h - script: - - rusty-cachier snapshot create - - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git - - CRATESIO_TARGET_INSTANCE=local ./releng-scripts/publish-crates - - rusty-cachier cache upload diff --git a/substrate/scripts/ci/gitlab/pipeline/test.yml b/substrate/scripts/ci/gitlab/pipeline/test.yml deleted file mode 100644 index 9c057e8d915..00000000000 --- a/substrate/scripts/ci/gitlab/pipeline/test.yml +++ /dev/null @@ -1,494 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "test" stage - -# It's more like a check and it belongs to the previous stage, but we want to run this job with real tests in parallel -find-fail-ci-phrase: - stage: test - variables: - CI_IMAGE: "paritytech/tools:latest" - ASSERT_REGEX: "FAIL-CI" - GIT_DEPTH: 1 - extends: - - .kubernetes-env - script: - - set +e - - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - - if [ $exit_status -eq 0 ]; then - echo "$ASSERT_REGEX was found, exiting with 1"; - exit 1; - else - echo "No $ASSERT_REGEX was found, exiting with 0"; - exit 0; - fi - -cargo-deny-licenses: - stage: test - extends: - - .docker-env - - .test-refs - variables: - CARGO_DENY_CMD: "cargo deny --all-features check licenses -c ./scripts/ci/deny.toml" - script: - - rusty-cachier snapshot create - - $CARGO_DENY_CMD --hide-inclusion-graph - - rusty-cachier cache upload - after_script: - - !reference [.rusty-cachier, after_script] - - echo "___The complete log is in the artifacts___" - - $CARGO_DENY_CMD 2> deny.log - - if [ $CI_JOB_STATUS != 'success' ]; then - echo 'Please check license of your crate or add an exception to scripts/ci/deny.toml'; - fi - artifacts: - name: $CI_COMMIT_SHORT_SHA - expire_in: 3 days - when: always - paths: - - deny.log - -cargo-fmt: - stage: test - variables: - RUSTY_CACHIER_TOOLCHAIN: nightly - extends: - - .docker-env - - .test-refs - script: - - rusty-cachier snapshot create - - cargo +nightly fmt --all -- --check - - rusty-cachier cache upload - -cargo-fmt-manifest: - stage: test - extends: - - .docker-env - - .test-refs - script: - - cargo install zepter --locked --version 0.11.1 -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 - -cargo-clippy: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: cargo-fmt - artifacts: false - extends: - - .docker-env - - .test-refs - script: - - echo $RUSTFLAGS - - cargo version && cargo clippy --version - - rusty-cachier snapshot create - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --locked --all-targets --workspace - - rusty-cachier cache upload - -cargo-check-benches: - stage: test - variables: - CI_JOB_NAME: "cargo-check-benches" - extends: - - .docker-env - - .test-refs-check-benches - - .collect-artifacts - - .pipeline-stopper-artifacts - before_script: - - !reference [.timestamp, before_script] - # perform rusty-cachier operations before any further modifications to the git repo to make cargo feel cheated not so much - - !reference [.rust-info-script, script] - - !reference [.job-switcher, before_script] - - !reference [.rusty-cachier, before_script] - - !reference [.pipeline-stopper-vars, script] - # merges in the master branch on PRs. skip if base is not master - - 'if [ $CI_COMMIT_REF_NAME != "master" ]; then - BASE=$(curl -s -H "Authorization: Bearer ${GITHUB_PR_TOKEN}" https://api.github.com/repos/paritytech/substrate/pulls/${CI_COMMIT_REF_NAME} | jq -r .base.ref); - printf "Merging base branch %s\n" "${BASE:=master}"; - if [ $BASE != "master" ]; then - echo "$BASE is not master, skipping merge"; - else - git config user.email "ci@gitlab.parity.io"; - git fetch origin "refs/heads/${BASE}"; - git merge --verbose --no-edit FETCH_HEAD; - fi - fi' - parallel: 2 - script: - - rusty-cachier snapshot create - - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - # this job is executed in parallel on two runners - - echo "___Running benchmarks___"; - - case ${CI_NODE_INDEX} in - 1) - SKIP_WASM_BUILD=1 time cargo check --locked --benches --all; - cargo run --locked --release -p node-bench -- ::trie::read::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; - echo "___Uploading cache for rusty-cachier___"; - rusty-cachier cache upload - ;; - 2) - cargo run --locked --release -p node-bench -- ::node::import::sr25519::transfer_keep_alive::paritydb::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::sr25519::transfer_keep_alive::paritydb::small.json - ;; - esac - -node-bench-regression-guard: - # it's not belong to `build` semantically, but dag jobs can't depend on each other - # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 - # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 - stage: build - extends: - - .docker-env - - .test-refs-no-trigger-prs-only - needs: - # this is a DAG - - job: cargo-check-benches - artifacts: true - # polls artifact from master to compare with current result - # need to specify both parallel jobs from master because of the bug - # https://gitlab.com/gitlab-org/gitlab/-/issues/39063 - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 1/2" - ref: master - artifacts: true - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 2/2" - ref: master - artifacts: true - variables: - CI_IMAGE: "paritytech/node-bench-regression-guard:latest" - before_script: - - !reference [.timestamp, before_script] - script: - - echo "------- IMPORTANT -------" - - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" - - echo "In case of this job failure, check your pipeline's cargo-check-benches" - - "node-bench-regression-guard --reference artifacts/benches/master-* - --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" - after_script: [""] - -cargo-check-try-runtime-and-experimental: - stage: test - extends: - - .docker-env - - .test-refs - script: - - rusty-cachier snapshot create - - time cargo check --workspace --locked --features try-runtime,experimental - - rusty-cachier cache upload - -test-deterministic-wasm: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: cargo-check-try-runtime-and-experimental - artifacts: false - extends: - - .docker-env - - .test-refs - variables: - WASM_BUILD_NO_COLOR: 1 - # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - script: - - rusty-cachier snapshot create - # build runtime - - cargo build --locked --verbose --release -p kitchensink-runtime - # make checksum - - sha256sum $CARGO_TARGET_DIR/release/wbuild/kitchensink-runtime/target/wasm32-unknown-unknown/release/kitchensink_runtime.wasm > checksum.sha256 - # clean up - - rm -rf $CARGO_TARGET_DIR/release/wbuild - # build again - - cargo build --locked --verbose --release -p kitchensink-runtime - # confirm checksum - - sha256sum -c ./checksum.sha256 - # clean up again, don't put release binaries into the cache - - rm -rf $CARGO_TARGET_DIR/release/wbuild - - rusty-cachier cache upload - -test-linux-stable: - stage: test - extends: - - .docker-env - - .test-refs - - .pipeline-stopper-artifacts - variables: - # 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: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - # needed for rusty-cachier to keep cache in test-linux-stable folder and not in test-linux-stable-1/3 - CI_JOB_NAME: "test-linux-stable" - parallel: 3 - script: - - rusty-cachier snapshot create - # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - # tests are partitioned by nextest and executed in parallel on $CI_NODE_TOTAL runners - - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - - time cargo nextest run --workspace - --locked - --release - --verbose - --features runtime-benchmarks,try-runtime,experimental - --manifest-path ./bin/node/cli/Cargo.toml - --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - # run runtime-api tests with `enable-staging-api` feature - - time cargo nextest run -p sp-api-test --features enable-staging-api - # we need to update cache only from one job - - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi - # Upload tests results to Elasticsearch - - echo "Upload test results to Elasticsearch" - - cat target/nextest/default/junit.xml | xq . > target/nextest/default/junit.json - - | - curl -v -XPOST --http1.1 \ - -u ${ELASTIC_USERNAME}:${ELASTIC_PASSWORD} \ - https://elasticsearch.parity-build.parity.io/unit-tests/_doc/${CI_JOB_ID} \ - -H 'Content-Type: application/json' \ - -d @target/nextest/default/junit.json || echo "failed to upload junit report" - artifacts: - when: always - paths: - - target/nextest/default/junit.xml - reports: - junit: target/nextest/default/junit.xml - -test-frame-support: - stage: test - extends: - - .docker-env - - .test-refs - variables: - # 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: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - script: - - rusty-cachier snapshot create - - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true - - time cargo test --verbose --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental --manifest-path ./frame/support/test/Cargo.toml - - time cargo test --verbose --locked -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental --manifest-path ./frame/support/test/Cargo.toml - - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true - - rusty-cachier cache upload - -# This job runs tests that don't work with cargo-nextest in test-linux-stable -test-linux-stable-extra: - stage: test - extends: - - .docker-env - - .test-refs - variables: - # 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: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - script: - - rusty-cachier snapshot create - # Run node-cli tests - # TODO: add to test-linux-stable-nextest after fix https://github.com/paritytech/substrate/issues/11321 - - time cargo test node-cli --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml - # Run doctests - # TODO: add to test-linux-stable-nextest after fix https://github.com/nextest-rs/nextest/issues/16 - - time cargo test --doc --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml - - rusty-cachier cache upload - -# This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. -quick-benchmarks: - stage: test - extends: - - .docker-env - - .test-refs - variables: - # 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" - script: - - rusty-cachier snapshot create - - time cargo run --locked --release -p node-cli --features runtime-benchmarks -- benchmark pallet --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - - rusty-cachier cache upload - -test-frame-examples-compile-to-wasm: - # into one job - stage: test - extends: - - .docker-env - - .test-refs - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: 1 - script: - - rusty-cachier snapshot create - - cd ./frame/examples/offchain-worker/ - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - - cd ../basic - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - - rusty-cachier cache upload - -test-linux-stable-int: - stage: test - extends: - - .docker-env - - .test-refs - - .pipeline-stopper-artifacts - variables: - # 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: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - script: - - rusty-cachier snapshot create - - WASM_BUILD_NO_COLOR=1 - RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace - time cargo test -p node-cli --release --verbose --locked -- --ignored - - rusty-cachier cache upload - -# more information about this job can be found here: -# https://github.com/paritytech/substrate/pull/6916 -check-tracing: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: test-linux-stable-int - artifacts: false - extends: - - .docker-env - - .test-refs - - .pipeline-stopper-artifacts - script: - - rusty-cachier snapshot create - # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features - - time cargo test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - - rusty-cachier cache upload - -# more information about this job can be found here: -# https://github.com/paritytech/substrate/pull/3778 -test-full-crypto-feature: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: check-tracing - artifacts: false - extends: - - .docker-env - - .test-refs - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: 1 - script: - - rusty-cachier snapshot create - - cd primitives/core/ - - time cargo build --locked --verbose --no-default-features --features full_crypto - - cd ../application-crypto - - time cargo build --locked --verbose --no-default-features --features full_crypto - - rusty-cachier cache upload - -check-rustdoc: - stage: test - extends: - - .docker-env - - .test-refs - variables: - SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" - script: - - rusty-cachier snapshot create - - time cargo doc --locked --workspace --all-features --verbose --no-deps - - rusty-cachier cache upload - -cargo-check-each-crate: - stage: test - extends: - - .docker-env - - .test-refs - - .collect-artifacts - - .pipeline-stopper-artifacts - variables: - # $CI_JOB_NAME is set manually so that rusty-cachier can share the cache for all - # "cargo-check-each-crate I/N" jobs - CI_JOB_NAME: cargo-check-each-crate - script: - - rusty-cachier snapshot create - - PYTHONUNBUFFERED=x time ./scripts/ci/gitlab/check-each-crate.py "$CI_NODE_INDEX" "$CI_NODE_TOTAL" - # need to update cache only from one job - - if [ "$CI_NODE_INDEX" == 1 ]; then rusty-cachier cache upload; fi - parallel: 2 - -cargo-check-each-crate-macos: - stage: test - extends: - - .test-refs - - .collect-artifacts - - .pipeline-stopper-artifacts - before_script: - # skip timestamp script, the osx bash doesn't support printf %()T - - !reference [.job-switcher, before_script] - - !reference [.rust-info-script, script] - - !reference [.pipeline-stopper-vars, script] - variables: - SKIP_WASM_BUILD: 1 - script: - # TODO: enable rusty-cachier once it supports Mac - # TODO: use parallel jobs, as per cargo-check-each-crate, once more Mac runners are available - # - time ./scripts/ci/gitlab/check-each-crate.py 1 1 - - time cargo check --workspace --locked - tags: - - osx - -cargo-hfuzz: - stage: test - extends: - - .docker-env - - .test-refs - - .pipeline-stopper-artifacts - variables: - # max 10s per iteration, 60s per file - HFUZZ_RUN_ARGS: > - --exit_upon_crash - --exit_code_upon_crash 1 - --timeout 10 - --run_time 60 - # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: - # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian - # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr - # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling rusty-cachier's absolute CARGO_TARGET_DIR - HFUZZ_BUILD_ARGS: > - --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" - --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" - artifacts: - name: "hfuzz-$CI_COMMIT_SHORT_SHA" - expire_in: 7 days - when: on_failure - paths: - - primitives/arithmetic/fuzzer/hfuzz_workspace/ - script: - - cd ./primitives/arithmetic/fuzzer - - rusty-cachier snapshot create - - cargo hfuzz build - - rusty-cachier cache upload - - 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 diff --git a/substrate/scripts/ci/gitlab/pipeline/zombienet.yml b/substrate/scripts/ci/gitlab/pipeline/zombienet.yml deleted file mode 100644 index 31ee5103432..00000000000 --- a/substrate/scripts/ci/gitlab/pipeline/zombienet.yml +++ /dev/null @@ -1,67 +0,0 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "zombienet" stage - -# common settings for all zombienet jobs -.zombienet-common: - before_script: - - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE}" - - echo "${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" - - echo "${GH_DIR}" - - export DEBUG=zombie,zombie::network-node - - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG} - - echo "${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - stage: zombienet - image: "${ZOMBIENET_IMAGE}" - needs: - - job: publish-docker-substrate-temporary - extends: - - .kubernetes-env - - .zombienet-refs - variables: - GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" - FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 2 days - paths: - - ./zombienet-logs - after_script: - - mkdir -p ./zombienet-logs - - cp /tmp/zombie*/logs/* ./zombienet-logs/ - retry: 2 - tags: - - zombienet-polkadot-integration-test - -zombienet-0000-block-building: - extends: - - .zombienet-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0000-block-building" - --test="block-building.zndsl" - -zombienet-0001-basic-warp-sync: - extends: - - .zombienet-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0001-basic-warp-sync" - --test="test-warp-sync.zndsl" - -zombienet-0002-validators-warp-sync: - extends: - - .zombienet-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0002-validators-warp-sync" - --test="test-validators-warp-sync.zndsl" - -zombienet-0003-block-building-warp-sync: - extends: - - .zombienet-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0003-block-building-warp-sync" - --test="test-block-building-warp-sync.zndsl" diff --git a/substrate/scripts/ci/gitlab/prettier.sh b/substrate/scripts/ci/gitlab/prettier.sh deleted file mode 100755 index 299bbee179d..00000000000 --- a/substrate/scripts/ci/gitlab/prettier.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# meant to be installed via -# git config filter.ci-prettier.clean "scripts/ci/gitlab/prettier.sh" - -prettier --parser yaml diff --git a/substrate/scripts/ci/gitlab/publish_draft_release.sh b/substrate/scripts/ci/gitlab/publish_draft_release.sh deleted file mode 100755 index 88d1de0e04f..00000000000 --- a/substrate/scripts/ci/gitlab/publish_draft_release.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -# shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" - -version="$CI_COMMIT_TAG" - -# Note that this is not the last *tagged* version, but the last *published* version -last_version=$(last_github_release 'paritytech/substrate') - -release_text="$(./generate_release_text.sh "$last_version" "$version")" - -echo "[+] Pushing release to github" -# Create release on github -release_name="Substrate $version" -data=$(jq -Rs --arg version "$version" \ - --arg release_name "$release_name" \ - --arg release_text "$release_text" \ -'{ - "tag_name": $version, - "target_commitish": "master", - "name": $release_name, - "body": $release_text, - "draft": true, - "prerelease": false -}' < /dev/null) - -out=$(curl -s -X POST --data "$data" -H "Authorization: token $GITHUB_RELEASE_TOKEN" "$api_base/paritytech/substrate/releases") - -html_url=$(echo "$out" | jq -r .html_url) - -if [ "$html_url" == "null" ] -then - echo "[!] Something went wrong posting:" - echo "$out" -else - echo "[+] Release draft created: $html_url" -fi - -echo '[+] Sending draft release URL to Matrix' - -msg_body=$(cat <Release pipeline for Substrate $version complete.
-Draft release created: $html_url -EOF -) -send_message "$(structure_message "$msg_body" "$formatted_msg_body")" "!aJymqQYtCjjqImFLSb:parity.io" "$RELEASENOTES_MATRIX_V2_ACCESS_TOKEN" - -echo "[+] Done! Maybe the release worked..." -- GitLab From 80a19bec6aa4287ceca7a771cc40908b921d3870 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Thu, 31 Aug 2023 12:48:01 +0200 Subject: [PATCH 036/633] remove disable-runtime-api (#1328) --- polkadot/runtime/kusama/Cargo.toml | 6 ------ polkadot/runtime/kusama/src/lib.rs | 4 ---- polkadot/runtime/polkadot/Cargo.toml | 6 ------ polkadot/runtime/polkadot/src/lib.rs | 4 ---- polkadot/runtime/rococo/Cargo.toml | 6 ------ polkadot/runtime/rococo/src/lib.rs | 4 ---- polkadot/runtime/westend/Cargo.toml | 6 ------ polkadot/runtime/westend/src/lib.rs | 4 ---- 8 files changed, 40 deletions(-) diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 96a00743545..8b0f59516c6 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -338,12 +338,6 @@ try-runtime = [ "runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -# When enabled, the runtime API will not be build. -# -# This is required by Cumulus to access certain types of the -# runtime without clashing with the runtime API exported functions -# in WASM. -disable-runtime-api = [] # 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 diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index e9e3fb2d202..ac80f88cfaa 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -139,10 +139,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { authoring_version: 2, spec_version: 9430, impl_version: 0, - #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, - #[cfg(feature = "disable-runtime-api")] - apis: sp_version::create_apis_vec![[]], transaction_version: 23, state_version: 1, }; @@ -1820,7 +1817,6 @@ mod benches { ); } -#[cfg(not(feature = "disable-runtime-api"))] sp_api::impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 48f720caa64..d185677ab8d 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -307,12 +307,6 @@ try-runtime = [ "runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -# When enabled, the runtime API will not be build. -# -# This is required by Cumulus to access certain types of the -# runtime without clashing with the runtime API exported functions -# in WASM. -disable-runtime-api = [] # 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 diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index c4458076cb3..f97c0981039 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -130,10 +130,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { authoring_version: 0, spec_version: 9430, impl_version: 0, - #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, - #[cfg(feature = "disable-runtime-api")] - apis: sp_version::create_apis_vec![[]], transaction_version: 24, state_version: 0, }; @@ -1599,7 +1596,6 @@ mod benches { ); } -#[cfg(not(feature = "disable-runtime-api"))] sp_api::impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 4c268c3e2b6..aa94d5914d6 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -282,12 +282,6 @@ try-runtime = [ "runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -# When enabled, the runtime API will not be build. -# -# This is required by Cumulus to access certain types of the -# runtime without clashing with the runtime API exported functions -# in WASM. -disable-runtime-api = [] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = [] diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 6894bd7bbf4..192f4117ba6 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -116,10 +116,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { authoring_version: 0, spec_version: 9430, impl_version: 0, - #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, - #[cfg(feature = "disable-runtime-api")] - apis: sp_version::create_apis_vec![[]], transaction_version: 22, state_version: 1, }; @@ -1647,7 +1644,6 @@ mod benches { ); } -#[cfg(not(feature = "disable-runtime-api"))] sp_api::impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index add80488a64..dc5bdaf6559 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -311,12 +311,6 @@ try-runtime = [ "runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -# When enabled, the runtime API will not be build. -# -# This is required by Cumulus to access certain types of the -# runtime without clashing with the runtime API exported functions -# in WASM. -disable-runtime-api = [] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = [] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9ae30c37601..12baa20a129 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -121,10 +121,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { authoring_version: 2, spec_version: 9430, impl_version: 0, - #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, - #[cfg(feature = "disable-runtime-api")] - apis: sp_version::create_apis_vec![[]], transaction_version: 22, state_version: 1, }; @@ -1494,7 +1491,6 @@ mod benches { ); } -#[cfg(not(feature = "disable-runtime-api"))] sp_api::impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { -- GitLab From dfc0d1bc8379ad63fe41b92b99157d2deca4df6c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 31 Aug 2023 12:48:39 +0200 Subject: [PATCH 037/633] Remove `substrate_test_utils::test` (#1321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Directly use tokio::test Signed-off-by: Oliver Tale-Yazdi * Remove old code Signed-off-by: Oliver Tale-Yazdi * Delete substrate-test-utils-test-crate Also not needed anymore. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- Cargo.lock | 20 ----- Cargo.toml | 2 - polkadot/node/metrics/src/tests.rs | 2 +- .../node/test/service/tests/build-blocks.rs | 2 +- .../node/test/service/tests/call-function.rs | 2 +- .../adder/collator/tests/integration.rs | 2 +- .../undying/collator/tests/integration.rs | 2 +- substrate/test-utils/Cargo.toml | 1 - substrate/test-utils/derive/Cargo.toml | 19 ----- substrate/test-utils/derive/src/lib.rs | 73 ------------------- substrate/test-utils/src/lib.rs | 20 ----- substrate/test-utils/test-crate/Cargo.toml | 17 ----- substrate/test-utils/test-crate/src/main.rs | 25 ------- substrate/test-utils/tests/basic.rs | 49 ------------- substrate/test-utils/tests/ui.rs | 23 ------ .../tests/ui/too-many-func-parameters.rs | 24 ------ .../tests/ui/too-many-func-parameters.stderr | 5 -- 17 files changed, 5 insertions(+), 283 deletions(-) delete mode 100644 substrate/test-utils/derive/Cargo.toml delete mode 100644 substrate/test-utils/derive/src/lib.rs delete mode 100644 substrate/test-utils/test-crate/Cargo.toml delete mode 100644 substrate/test-utils/test-crate/src/main.rs delete mode 100644 substrate/test-utils/tests/basic.rs delete mode 100644 substrate/test-utils/tests/ui.rs delete mode 100644 substrate/test-utils/tests/ui/too-many-func-parameters.rs delete mode 100644 substrate/test-utils/tests/ui/too-many-func-parameters.stderr diff --git a/Cargo.lock b/Cargo.lock index 74034bab663..a57f6d69826 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18321,30 +18321,10 @@ version = "4.0.0-dev" dependencies = [ "futures", "sc-service", - "substrate-test-utils-derive", "tokio", "trybuild", ] -[[package]] -name = "substrate-test-utils-derive" -version = "0.10.0-dev" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "substrate-test-utils-test-crate" -version = "0.1.0" -dependencies = [ - "sc-service", - "substrate-test-utils", - "tokio", -] - [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 48081ad14a3..82b196e7a47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -432,11 +432,9 @@ members = [ "substrate/test-utils", "substrate/test-utils/cli", "substrate/test-utils/client", - "substrate/test-utils/derive", "substrate/test-utils/runtime", "substrate/test-utils/runtime/client", "substrate/test-utils/runtime/transaction-pool", - "substrate/test-utils/test-crate", "substrate/utils/binary-merkle-tree", "substrate/utils/build-script-utils", "substrate/utils/fork-tree", diff --git a/polkadot/node/metrics/src/tests.rs b/polkadot/node/metrics/src/tests.rs index 68abfeebc12..861080228cd 100644 --- a/polkadot/node/metrics/src/tests.rs +++ b/polkadot/node/metrics/src/tests.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; const DEFAULT_PROMETHEUS_PORT: u16 = 9616; -#[substrate_test_utils::test(flavor = "multi_thread")] +#[tokio::test(flavor = "multi_thread")] async fn runtime_can_publish_metrics() { let mut alice_config = node_config(|| {}, tokio::runtime::Handle::current(), Alice, Vec::new(), true); diff --git a/polkadot/node/test/service/tests/build-blocks.rs b/polkadot/node/test/service/tests/build-blocks.rs index b75fed60297..d5c6ab0b5ba 100644 --- a/polkadot/node/test/service/tests/build-blocks.rs +++ b/polkadot/node/test/service/tests/build-blocks.rs @@ -18,7 +18,7 @@ use futures::{future, pin_mut, select, FutureExt}; use polkadot_test_service::*; use sp_keyring::Sr25519Keyring; -#[substrate_test_utils::test(flavor = "multi_thread")] +#[tokio::test(flavor = "multi_thread")] async fn ensure_test_service_build_blocks() { let mut builder = sc_cli::LoggerBuilder::new(""); builder.with_colors(false); diff --git a/polkadot/node/test/service/tests/call-function.rs b/polkadot/node/test/service/tests/call-function.rs index c3baefdb9c9..39d162eb376 100644 --- a/polkadot/node/test/service/tests/call-function.rs +++ b/polkadot/node/test/service/tests/call-function.rs @@ -17,7 +17,7 @@ use polkadot_test_service::*; use sp_keyring::Sr25519Keyring::{Alice, Bob, Charlie}; -#[substrate_test_utils::test(flavor = "multi_thread")] +#[tokio::test(flavor = "multi_thread")] async fn call_function_actually_work() { let alice_config = node_config(|| {}, tokio::runtime::Handle::current(), Alice, Vec::new(), true); diff --git a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs index b891b29db59..6b481f961a4 100644 --- a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs @@ -22,7 +22,7 @@ const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_adder_collator_puppet_worker"); // If this test is failing, make sure to run all tests with the `real-overseer` feature being // enabled. -#[substrate_test_utils::test(flavor = "multi_thread")] +#[tokio::test(flavor = "multi_thread")] async fn collating_using_adder_collator() { use polkadot_primitives::Id as ParaId; use sp_keyring::AccountKeyring::*; diff --git a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs index 21d174fb06c..a98a7ff6eef 100644 --- a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs @@ -21,7 +21,7 @@ const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_undying_collator_puppet_worker"); // If this test is failing, make sure to run all tests with the `real-overseer` feature being // enabled. -#[substrate_test_utils::test(flavor = "multi_thread")] +#[tokio::test(flavor = "multi_thread")] async fn collating_using_undying_collator() { use polkadot_primitives::Id as ParaId; use sp_keyring::AccountKeyring::*; diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index 977d1f69405..31bdc0f663a 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -15,7 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.16" tokio = { version = "1.22.0", features = ["macros", "time"] } -substrate-test-utils-derive = { path = "derive" } [dev-dependencies] trybuild = { version = "1.0.74", features = [ "diff" ] } diff --git a/substrate/test-utils/derive/Cargo.toml b/substrate/test-utils/derive/Cargo.toml deleted file mode 100644 index 8299f6db048..00000000000 --- a/substrate/test-utils/derive/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "substrate-test-utils-derive" -version = "0.10.0-dev" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "Substrate test utilities macros" -publish = false - -[dependencies] -proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.16", features = ["full"] } - -[lib] -proc-macro = true diff --git a/substrate/test-utils/derive/src/lib.rs b/substrate/test-utils/derive/src/lib.rs deleted file mode 100644 index 0291d825e76..00000000000 --- a/substrate/test-utils/derive/src/lib.rs +++ /dev/null @@ -1,73 +0,0 @@ -// 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 proc_macro::{Span, TokenStream}; -use proc_macro_crate::{crate_name, FoundCrate}; -use quote::quote; - -#[proc_macro_attribute] -pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(item as syn::ItemFn); - - parse_knobs(input, args.into()).unwrap_or_else(|e| e.to_compile_error().into()) -} - -fn parse_knobs( - mut input: syn::ItemFn, - args: proc_macro2::TokenStream, -) -> Result { - let sig = &mut input.sig; - let body = &input.block; - let attrs = &input.attrs; - let vis = input.vis; - - if !sig.inputs.is_empty() { - return Err(syn::Error::new_spanned(&sig, "No arguments expected for tests.")) - } - - let crate_name = match crate_name("substrate-test-utils") { - Ok(FoundCrate::Itself) => syn::Ident::new("substrate_test_utils", Span::call_site().into()), - Ok(FoundCrate::Name(crate_name)) => syn::Ident::new(&crate_name, Span::call_site().into()), - Err(e) => return Err(syn::Error::new_spanned(&sig, e)), - }; - - let header = { - quote! { - #[#crate_name::tokio::test( #args )] - } - }; - - let result = quote! { - #header - #(#attrs)* - #vis #sig { - if #crate_name::tokio::time::timeout( - std::time::Duration::from_secs( - std::env::var("SUBSTRATE_TEST_TIMEOUT") - .ok() - .and_then(|x| x.parse().ok()) - .unwrap_or(600)), - async move { #body }, - ).await.is_err() { - panic!("The test took too long!"); - } - } - }; - - Ok(result.into()) -} diff --git a/substrate/test-utils/src/lib.rs b/substrate/test-utils/src/lib.rs index 1ad70289368..30472e79b3f 100644 --- a/substrate/test-utils/src/lib.rs +++ b/substrate/test-utils/src/lib.rs @@ -17,26 +17,6 @@ //! Test utils -#[doc(hidden)] -pub use futures; -/// Marks async function to be executed by an async runtime suitable to test environment. -/// -/// # Requirements -/// -/// You must have tokio in the `[dev-dependencies]` of your crate to use this macro. -/// -/// # Example -/// -/// ``` -/// #[substrate_test_utils::test] -/// async fn basic_test() { -/// assert!(true); -/// } -/// ``` -pub use substrate_test_utils_derive::test; -#[doc(hidden)] -pub use tokio; - /// Panic when the vectors are different, without taking the order into account. /// /// # Examples diff --git a/substrate/test-utils/test-crate/Cargo.toml b/substrate/test-utils/test-crate/Cargo.toml deleted file mode 100644 index bb68c9f18ed..00000000000 --- a/substrate/test-utils/test-crate/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "substrate-test-utils-test-crate" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dev-dependencies] -tokio = { version = "1.22.0", features = ["macros"] } -sc-service = { path = "../../client/service" } -test-utils = { package = "substrate-test-utils", path = ".." } diff --git a/substrate/test-utils/test-crate/src/main.rs b/substrate/test-utils/test-crate/src/main.rs deleted file mode 100644 index cab4cc6e924..00000000000 --- a/substrate/test-utils/test-crate/src/main.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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 . - -#[cfg(test)] -#[test_utils::test] -async fn basic_test() { - assert!(true); -} - -fn main() {} diff --git a/substrate/test-utils/tests/basic.rs b/substrate/test-utils/tests/basic.rs deleted file mode 100644 index e8c46b1e837..00000000000 --- a/substrate/test-utils/tests/basic.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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_test_utils::test] -async fn basic_test() { - assert!(true); -} - -#[substrate_test_utils::test] -#[should_panic(expected = "boo!")] -async fn panicking_test() { - panic!("boo!"); -} - -#[substrate_test_utils::test(flavor = "multi_thread", worker_threads = 1)] -async fn basic_test_with_args() { - assert!(true); -} - -// NOTE: enable this test only after setting SUBSTRATE_TEST_TIMEOUT to a smaller value -// -// SUBSTRATE_TEST_TIMEOUT=1 cargo test -- --ignored timeout -#[substrate_test_utils::test] -#[should_panic(expected = "test took too long")] -#[ignore] -async fn timeout() { - tokio::time::sleep(std::time::Duration::from_secs( - std::env::var("SUBSTRATE_TEST_TIMEOUT") - .expect("env var SUBSTRATE_TEST_TIMEOUT has been provided by the user") - .parse::() - .unwrap() + 1, - )) - .await; -} diff --git a/substrate/test-utils/tests/ui.rs b/substrate/test-utils/tests/ui.rs deleted file mode 100644 index baf822bb87a..00000000000 --- a/substrate/test-utils/tests/ui.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 . - -#[test] -fn substrate_test_utils_derive_trybuild() { - let t = trybuild::TestCases::new(); - t.compile_fail("tests/ui/too-many-func-parameters.rs"); -} diff --git a/substrate/test-utils/tests/ui/too-many-func-parameters.rs b/substrate/test-utils/tests/ui/too-many-func-parameters.rs deleted file mode 100644 index 0eece5f9e61..00000000000 --- a/substrate/test-utils/tests/ui/too-many-func-parameters.rs +++ /dev/null @@ -1,24 +0,0 @@ -// 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_test_utils::test] -async fn too_many_func_parameters(_: u32) { - assert!(true); -} - -fn main() {} diff --git a/substrate/test-utils/tests/ui/too-many-func-parameters.stderr b/substrate/test-utils/tests/ui/too-many-func-parameters.stderr deleted file mode 100644 index 1b1630022e4..00000000000 --- a/substrate/test-utils/tests/ui/too-many-func-parameters.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: No arguments expected for tests. - --> $DIR/too-many-func-parameters.rs:20:1 - | -20 | async fn too_many_func_parameters(_: u32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- GitLab From f1845f725d27fd62eded566a23585d5e2972ce59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:48:59 +0200 Subject: [PATCH 038/633] Bump zstd from 0.11.2+zstd.1.5.2 to 0.12.4 (#1326) Bumps [zstd](https://github.com/gyscos/zstd-rs) from 0.11.2+zstd.1.5.2 to 0.12.4. - [Release notes](https://github.com/gyscos/zstd-rs/releases) - [Commits](https://github.com/gyscos/zstd-rs/commits) --- updated-dependencies: - dependency-name: zstd dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 2 +- polkadot/node/primitives/Cargo.toml | 2 +- substrate/frame/state-trie-migration/Cargo.toml | 2 +- substrate/primitives/maybe-compressed-blob/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/utils/frame/try-runtime/cli/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a57f6d69826..fe538e170fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12318,7 +12318,7 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-runtime", "thiserror", - "zstd 0.11.2+zstd.1.5.2", + "zstd 0.12.4", ] [[package]] diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 33893ebeba6..e7101c875e7 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0.31" serde = { version = "1.0.188", features = ["derive"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] -zstd = { version = "0.11.2", default-features = false } +zstd = { version = "0.12.4", default-features = false } [dev-dependencies] polkadot-erasure-coding = { path = "../../erasure-coding" } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 2a9de6f2acc..83218a13136 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -17,7 +17,7 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } thousands = { version = "0.2.0", optional = true } -zstd = { version = "0.12.3", default-features = false, optional = true } +zstd = { version = "0.12.4", default-features = false, optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/primitives/maybe-compressed-blob/Cargo.toml b/substrate/primitives/maybe-compressed-blob/Cargo.toml index da4c412c452..c6fa7103672 100644 --- a/substrate/primitives/maybe-compressed-blob/Cargo.toml +++ b/substrate/primitives/maybe-compressed-blob/Cargo.toml @@ -12,4 +12,4 @@ readme = "README.md" [dependencies] thiserror = "1.0" -zstd = { version = "0.12.3", default-features = false } +zstd = { version = "0.12.4", default-features = false } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 6ca435f2c2b..7050c27bc84 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -33,7 +33,7 @@ sp-weights = { path = "../weights", default-features = false} [dev-dependencies] rand = "0.8.5" serde_json = "1.0.85" -zstd = { version = "0.12.3", default-features = false } +zstd = { version = "0.12.4", default-features = false } sp-api = { path = "../api" } sp-state-machine = { path = "../state-machine" } sp-tracing = { path = "../tracing" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index c17dfa823fb..3ad069ddc47 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -41,7 +41,7 @@ log = "0.4.17" parity-scale-codec = "3.6.1" serde = "1.0.188" serde_json = "1.0.85" -zstd = { version = "0.12.3", default-features = false } +zstd = { version = "0.12.4", default-features = false } [dev-dependencies] assert_cmd = "2.0.10" -- GitLab From d6af073aa501e2c9621a4fcb595d584b529d6de1 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Thu, 31 Aug 2023 14:01:36 +0300 Subject: [PATCH 039/633] backing: move the min votes threshold to the runtime (#1200) * move min backing votes const to runtime also cache it per-session in the backing subsystem Signed-off-by: alindima * add runtime migration * introduce api versioning for min_backing votes also enable it for rococo/versi for testing * also add min_backing_votes runtime calls to statement-distribution this dependency has been recently introduced by async backing * remove explicit version runtime API call this is not needed, as the RuntimeAPISubsystem already takes care of versioning and will return NotSupported if the version is not right. * address review comments - parametrise backing votes runtime API with session index - remove RuntimeInfo usage in backing subsystem, as runtime API caches the min backing votes by session index anyway. - move the logic for adjusting the configured needed backing votes with the size of the backing group to a primitives helper. - move the legacy min backing votes value to a primitives helper. - mark JoinMultiple error as fatal, since the Canceled (non-multiple) counterpart is also fatal. - make backing subsystem handle fatal errors for new leaves update. - add HostConfiguration consistency check for zeroed backing votes threshold - add cumulus accompanying change * fix cumulus test compilation * fix tests * more small fixes * fix merge * bump runtime api version for westend and rollback version for rococo --------- Signed-off-by: alindima Co-authored-by: Javier Viola --- .../src/blockchain_rpc_client.rs | 8 + .../src/rpc_client.rs | 10 + .../emulated/common/src/lib.rs | 1 + polkadot/node/core/backing/src/error.rs | 1 + polkadot/node/core/backing/src/lib.rs | 55 +-- polkadot/node/core/backing/src/tests/mod.rs | 31 +- .../src/tests/prospective_parachains.rs | 30 +- polkadot/node/core/runtime-api/src/cache.rs | 15 + polkadot/node/core/runtime-api/src/lib.rs | 18 + polkadot/node/core/runtime-api/src/tests.rs | 4 + .../network/statement-distribution/Cargo.toml | 2 +- .../src/vstaging/grid.rs | 2 +- .../src/vstaging/groups.rs | 17 +- .../src/vstaging/mod.rs | 21 +- .../src/vstaging/tests/mod.rs | 18 +- polkadot/node/primitives/src/lib.rs | 7 - polkadot/node/subsystem-types/src/messages.rs | 5 + .../subsystem-types/src/runtime_client.rs | 16 + .../node/subsystem-util/src/runtime/error.rs | 4 +- .../node/subsystem-util/src/runtime/mod.rs | 45 ++- polkadot/primitives/src/lib.rs | 32 +- polkadot/primitives/src/runtime_api.rs | 7 + polkadot/primitives/src/v5/mod.rs | 12 + polkadot/runtime/kusama/src/lib.rs | 2 + .../runtime/parachains/src/configuration.rs | 29 +- .../parachains/src/configuration/migration.rs | 1 + .../src/configuration/migration/v8.rs | 104 +++++- .../src/configuration/migration/v9.rs | 321 ++++++++++++++++++ .../parachains/src/configuration/tests.rs | 6 + .../runtime/parachains/src/inclusion/mod.rs | 28 +- .../runtime/parachains/src/inclusion/tests.rs | 27 +- .../parachains/src/paras_inherent/tests.rs | 239 ++++++------- .../src/runtime_api_impl/vstaging.rs | 5 + polkadot/runtime/polkadot/src/lib.rs | 2 + polkadot/runtime/rococo/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 10 +- polkadot/statement-table/src/generic.rs | 33 +- 37 files changed, 917 insertions(+), 252 deletions(-) create mode 100644 polkadot/runtime/parachains/src/configuration/migration/v9.rs 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 0a3d61e83e5..57e16bc4283 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 @@ -338,6 +338,14 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { .await?) } + async fn minimum_backing_votes( + &self, + at: Hash, + session_index: polkadot_primitives::SessionIndex, + ) -> Result { + 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?) } 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 8d070d62820..c1e92b249d7 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -588,6 +588,16 @@ impl RelayChainRpcClient { .await } + /// Get the minimum number of backing votes for a candidate. + pub async fn parachain_host_minimum_backing_votes( + &self, + at: RelayHash, + _session_index: SessionIndex, + ) -> Result { + self.call_remote_runtime_function("ParachainHost_minimum_backing_votes", at, None::<()>) + .await + } + #[allow(missing_docs)] pub async fn parachain_host_staging_async_backing_params( &self, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 77345291690..6201b0ef719 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -35,6 +35,7 @@ pub use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; pub use parachains_common::{AccountId, Balance}; pub use paste; use polkadot_parachain::primitives::HrmpChannelId; +use polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::ParachainHostV6; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use sp_core::{sr25519, storage::Storage, Get}; use sp_tracing; diff --git a/polkadot/node/core/backing/src/error.rs b/polkadot/node/core/backing/src/error.rs index d8f9e82d8f4..1b00a62510b 100644 --- a/polkadot/node/core/backing/src/error.rs +++ b/polkadot/node/core/backing/src/error.rs @@ -79,6 +79,7 @@ pub enum Error { RuntimeApiUnavailable(#[source] oneshot::Canceled), #[error("a channel was closed before receipt in try_join!")] + #[fatal] JoinMultiple(#[source] oneshot::Canceled), #[error("Obtaining erasure chunks failed")] diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 58763e6d80c..a75571da76d 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -80,8 +80,8 @@ use futures::{ use error::{Error, FatalResult}; use polkadot_node_primitives::{ - minimum_votes, AvailableData, InvalidCandidate, PoV, SignedFullStatementWithPVD, - StatementWithPVD, ValidationResult, + AvailableData, InvalidCandidate, PoV, SignedFullStatementWithPVD, StatementWithPVD, + ValidationResult, }; use polkadot_node_subsystem::{ messages::{ @@ -98,7 +98,9 @@ use polkadot_node_subsystem_util::{ backing_implicit_view::{FetchError as ImplicitViewFetchError, View as ImplicitView}, request_from_runtime, request_session_index_for_child, request_validator_groups, request_validators, - runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, + runtime::{ + self, prospective_parachains_mode, request_min_backing_votes, ProspectiveParachainsMode, + }, Validator, }; use polkadot_primitives::{ @@ -219,6 +221,8 @@ struct PerRelayParentState { awaiting_validation: HashSet, /// Data needed for retrying in case of `ValidatedCandidateCommand::AttestNoPoV`. fallbacks: HashMap, + /// The minimum backing votes threshold. + minimum_backing_votes: u32, } struct PerCandidateState { @@ -400,8 +404,8 @@ impl TableContextTrait for TableContext { self.groups.get(group).map_or(false, |g| g.iter().any(|a| a == authority)) } - fn requisite_votes(&self, group: &ParaId) -> usize { - self.groups.get(group).map_or(usize::MAX, |g| minimum_votes(g.len())) + fn get_group_size(&self, group: &ParaId) -> Option { + self.groups.get(group).map(|g| g.len()) } } @@ -965,28 +969,25 @@ async fn construct_per_relay_parent_state( ($x: expr) => { match $x { Ok(x) => x, - Err(e) => { - gum::warn!( - target: LOG_TARGET, - err = ?e, - "Failed to fetch runtime API data for job", - ); + Err(err) => { + // Only bubble up fatal errors. + error::log_error(Err(Into::::into(err).into()))?; // We can't do candidate validation work if we don't have the // requisite runtime API data. But these errors should not take // down the node. - return Ok(None); - } + return Ok(None) + }, } - } + }; } let parent = relay_parent; - let (validators, groups, session_index, cores) = futures::try_join!( + let (session_index, validators, groups, cores) = futures::try_join!( + request_session_index_for_child(parent, ctx.sender()).await, request_validators(parent, ctx.sender()).await, request_validator_groups(parent, ctx.sender()).await, - request_session_index_for_child(parent, ctx.sender()).await, request_from_runtime(parent, ctx.sender(), |tx| { RuntimeApiRequest::AvailabilityCores(tx) },) @@ -994,10 +995,12 @@ async fn construct_per_relay_parent_state( ) .map_err(Error::JoinMultiple)?; + let session_index = try_runtime_api!(session_index); let validators: Vec<_> = try_runtime_api!(validators); let (validator_groups, group_rotation_info) = try_runtime_api!(groups); - let session_index = try_runtime_api!(session_index); let cores = try_runtime_api!(cores); + let minimum_backing_votes = + try_runtime_api!(request_min_backing_votes(parent, session_index, ctx.sender()).await); let signing_context = SigningContext { parent_hash: parent, session_index }; let validator = @@ -1061,6 +1064,7 @@ async fn construct_per_relay_parent_state( issued_statements: HashSet::new(), awaiting_validation: HashSet::new(), fallbacks: HashMap::new(), + minimum_backing_votes, })) } @@ -1563,10 +1567,13 @@ async fn post_import_statement_actions( rp_state: &mut PerRelayParentState, summary: Option<&TableSummary>, ) -> Result<(), Error> { - if let Some(attested) = summary - .as_ref() - .and_then(|s| rp_state.table.attested_candidate(&s.candidate, &rp_state.table_context)) - { + if let Some(attested) = summary.as_ref().and_then(|s| { + rp_state.table.attested_candidate( + &s.candidate, + &rp_state.table_context, + rp_state.minimum_backing_votes, + ) + }) { let candidate_hash = attested.candidate.hash(); // `HashSet::insert` returns true if the thing wasn't in there already. @@ -2009,7 +2016,11 @@ fn handle_get_backed_candidates_message( }; rp_state .table - .attested_candidate(&candidate_hash, &rp_state.table_context) + .attested_candidate( + &candidate_hash, + &rp_state.table_context, + rp_state.minimum_backing_votes, + ) .and_then(|attested| table_attested_to_backed(attested, &rp_state.table_context)) }) .collect(); diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 054337669c0..06baebc98e6 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -34,7 +34,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecTimeoutKind, - ScheduledCore, SessionIndex, + ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use sp_application_crypto::AppCrypto; use sp_keyring::Sr25519Keyring; @@ -80,6 +80,7 @@ struct TestState { head_data: HashMap, signing_context: SigningContext, relay_parent: Hash, + minimum_backing_votes: u32, } impl TestState { @@ -150,6 +151,7 @@ impl Default for TestState { validation_data, signing_context, relay_parent, + minimum_backing_votes: LEGACY_MIN_BACKING_VOTES, } } } @@ -250,6 +252,16 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS } ); + // Check that subsystem job issues a request for the session index for child. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == test_state.relay_parent => { + tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + } + ); + // Check that subsystem job issues a request for a validator set. assert_matches!( virtual_overseer.recv().await, @@ -270,23 +282,24 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS } ); - // Check that subsystem job issues a request for the session index for child. + // Check that subsystem job issues a request for the availability cores. assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); } ); - // Check that subsystem job issues a request for the availability cores. + // Check if subsystem job issues a request for the minimum backing votes. assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::MinimumBackingVotes(session_index, tx), + )) if parent == test_state.relay_parent && session_index == test_state.signing_context.session_index => { + tx.send(Ok(test_state.minimum_backing_votes)).unwrap(); } ); } diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 6c155390566..7a30886736d 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -138,13 +138,24 @@ async fn activate_leaf( } for (hash, number) in ancestry_iter.take(requested_len) { - // Check that subsystem job issues a request for a validator set. let msg = match next_overseer_message.take() { Some(msg) => msg, None => virtual_overseer.recv().await, }; + + // Check that subsystem job issues a request for the session index for child. assert_matches!( msg, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + } + ); + + // Check that subsystem job issues a request for a validator set. + assert_matches!( + virtual_overseer.recv().await, AllMessages::RuntimeApi( RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) ) if parent == hash => { @@ -164,23 +175,24 @@ async fn activate_leaf( } ); - // Check that subsystem job issues a request for the session index for child. + // Check that subsystem job issues a request for the availability cores. assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) ) if parent == hash => { - tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); } ); - // Check that subsystem job issues a request for the availability cores. + // Check if subsystem job issues a request for the minimum backing votes. assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) - ) if parent == hash => { - tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::MinimumBackingVotes(session_index, tx), + )) if parent == hash && session_index == test_state.signing_context.session_index => { + tx.send(Ok(test_state.minimum_backing_votes)).unwrap(); } ); } diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index cd22f37ddee..7f41d74e616 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -65,6 +65,7 @@ pub(crate) struct RequestResultCache { 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, @@ -97,6 +98,7 @@ impl Default for RequestResultCache { disputes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), 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)), @@ -434,6 +436,18 @@ impl RequestResultCache { None } + pub(crate) fn minimum_backing_votes(&mut self, session_index: SessionIndex) -> Option { + self.minimum_backing_votes.get(&session_index).copied() + } + + pub(crate) fn cache_minimum_backing_votes( + &mut self, + session_index: SessionIndex, + minimum_backing_votes: u32, + ) { + self.minimum_backing_votes.insert(session_index, minimum_backing_votes); + } + pub(crate) fn staging_para_backing_state( &mut self, key: (Hash, ParaId), @@ -469,6 +483,7 @@ pub(crate) enum RequestResult { // The structure of each variant is (relay_parent, [params,]*, result) Authorities(Hash, Vec), Validators(Hash, Vec), + MinimumBackingVotes(Hash, SessionIndex, u32), ValidatorGroups(Hash, (Vec>, GroupRotationInfo)), AvailabilityCores(Hash, Vec), PersistedValidationData(Hash, ParaId, OccupiedCoreAssumption, Option), diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 78531d41272..ec9bf10fa6e 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -101,6 +101,9 @@ where self.requests_cache.cache_authorities(relay_parent, authorities), Validators(relay_parent, validators) => self.requests_cache.cache_validators(relay_parent, validators), + MinimumBackingVotes(_, session_index, minimum_backing_votes) => self + .requests_cache + .cache_minimum_backing_votes(session_index, minimum_backing_votes), ValidatorGroups(relay_parent, groups) => self.requests_cache.cache_validator_groups(relay_parent, groups), AvailabilityCores(relay_parent, cores) => @@ -301,6 +304,15 @@ where Request::StagingAsyncBackingParams(sender) => query!(staging_async_backing_params(), sender) .map(|sender| Request::StagingAsyncBackingParams(sender)), + Request::MinimumBackingVotes(index, sender) => { + if let Some(value) = self.requests_cache.minimum_backing_votes(index) { + self.metrics.on_cached_request(); + let _ = sender.send(Ok(value)); + None + } else { + Some(Request::MinimumBackingVotes(index, sender)) + } + }, } } @@ -551,6 +563,12 @@ where ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT, sender ), + Request::MinimumBackingVotes(index, sender) => query!( + MinimumBackingVotes, + minimum_backing_votes(index), + ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT, + sender + ), Request::StagingParaBackingState(para, sender) => { query!( diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index c3f8108312b..bb7c2968961 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -264,6 +264,10 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { ) -> Result, ApiError> { todo!("Not required for tests") } + + async fn minimum_backing_votes(&self, _: Hash, _: SessionIndex) -> Result { + todo!("Not required for tests") + } } #[test] diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 4c835bc3a68..5ff1ba9de02 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -16,6 +16,7 @@ sp-keystore = { path = "../../../../substrate/primitives/keystore" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } +polkadot-node-subsystem-types = { path = "../../subsystem-types" } polkadot-node-network-protocol = { path = "../protocol" } arrayvec = "0.7.4" indexmap = "1.9.1" @@ -39,4 +40,3 @@ sc-network = { path = "../../../../substrate/client/network" } futures-timer = "3.0.2" polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } rand_chacha = "0.3" -polkadot-node-subsystem-types = { path = "../../subsystem-types" } diff --git a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs b/polkadot/node/network/statement-distribution/src/vstaging/grid.rs index ec470a2eeb4..4fd77d0ced1 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/grid.rs @@ -1074,7 +1074,7 @@ mod tests { fn dummy_groups(group_size: usize) -> Groups { let groups = vec![(0..(group_size as u32)).map(ValidatorIndex).collect()].into(); - Groups::new(groups) + Groups::new(groups, 2) } #[test] diff --git a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs b/polkadot/node/network/statement-distribution/src/vstaging/groups.rs index f93a8e13fc1..b2daa1c0ac7 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/groups.rs @@ -16,8 +16,10 @@ //! A utility for tracking groups and their members within a session. -use polkadot_node_primitives::minimum_votes; -use polkadot_primitives::vstaging::{GroupIndex, IndexedVec, ValidatorIndex}; +use polkadot_primitives::{ + effective_minimum_backing_votes, + vstaging::{GroupIndex, IndexedVec, ValidatorIndex}, +}; use std::collections::HashMap; @@ -27,12 +29,16 @@ use std::collections::HashMap; pub struct Groups { groups: IndexedVec>, by_validator_index: HashMap, + backing_threshold: u32, } impl Groups { /// Create a new [`Groups`] tracker with the groups and discovery keys /// from the session. - pub fn new(groups: IndexedVec>) -> Self { + pub fn new( + groups: IndexedVec>, + backing_threshold: u32, + ) -> Self { let mut by_validator_index = HashMap::new(); for (i, group) in groups.iter().enumerate() { @@ -42,7 +48,7 @@ impl Groups { } } - Groups { groups, by_validator_index } + Groups { groups, by_validator_index, backing_threshold } } /// Access all the underlying groups. @@ -60,7 +66,8 @@ impl Groups { &self, group_index: GroupIndex, ) -> Option<(usize, usize)> { - self.get(group_index).map(|g| (g.len(), minimum_votes(g.len()))) + self.get(group_index) + .map(|g| (g.len(), effective_minimum_backing_votes(g.len(), self.backing_threshold))) } /// Get the group index for a validator by index. diff --git a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs b/polkadot/node/network/statement-distribution/src/vstaging/mod.rs index 830a488308a..4639720b322 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/mod.rs @@ -41,8 +41,9 @@ use polkadot_node_subsystem::{ overseer, ActivatedLeaf, }; use polkadot_node_subsystem_util::{ - backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, - runtime::ProspectiveParachainsMode, + backing_implicit_view::View as ImplicitView, + reputation::ReputationAggregator, + runtime::{request_min_backing_votes, ProspectiveParachainsMode}, }; use polkadot_primitives::vstaging::{ AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, @@ -163,8 +164,8 @@ struct PerSessionState { } impl PerSessionState { - fn new(session_info: SessionInfo, keystore: &KeystorePtr) -> Self { - let groups = Groups::new(session_info.validator_groups.clone()); + fn new(session_info: SessionInfo, keystore: &KeystorePtr, backing_threshold: u32) -> Self { + let groups = Groups::new(session_info.validator_groups.clone(), backing_threshold); let mut authority_lookup = HashMap::new(); for (i, ad) in session_info.discovery_keys.iter().cloned().enumerate() { authority_lookup.insert(ad, ValidatorIndex(i as _)); @@ -504,9 +505,13 @@ pub(crate) async fn handle_active_leaves_update( Some(s) => s, }; - state - .per_session - .insert(session_index, PerSessionState::new(session_info, &state.keystore)); + let minimum_backing_votes = + request_min_backing_votes(new_relay_parent, session_index, ctx.sender()).await?; + + state.per_session.insert( + session_index, + PerSessionState::new(session_info, &state.keystore, minimum_backing_votes), + ); } let per_session = state @@ -2502,7 +2507,7 @@ pub(crate) async fn dispatch_requests(ctx: &mut Context, state: &mut St Some(RequestProperties { unwanted_mask, backing_threshold: if require_backing { - Some(polkadot_node_primitives::minimum_votes(group.len())) + Some(per_session.groups.get_size_and_backing_threshold(group_index)?.1) } else { None }, diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs index 88c8a42599d..c5a4d14d2c7 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs @@ -356,7 +356,7 @@ async fn activate_leaf( virtual_overseer: &mut VirtualOverseer, leaf: &TestLeaf, test_state: &TestState, - expect_session_info_request: bool, + is_new_session: bool, ) { let activated = ActivatedLeaf { hash: leaf.hash, @@ -371,14 +371,14 @@ async fn activate_leaf( )))) .await; - handle_leaf_activation(virtual_overseer, leaf, test_state, expect_session_info_request).await; + handle_leaf_activation(virtual_overseer, leaf, test_state, is_new_session).await; } async fn handle_leaf_activation( virtual_overseer: &mut VirtualOverseer, leaf: &TestLeaf, test_state: &TestState, - expect_session_info_request: bool, + is_new_session: bool, ) { let TestLeaf { number, hash, parent_hash, para_data, session, availability_cores } = leaf; @@ -447,7 +447,7 @@ async fn handle_leaf_activation( } ); - if expect_session_info_request { + if is_new_session { assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( @@ -455,6 +455,16 @@ async fn handle_leaf_activation( tx.send(Ok(Some(test_state.session_info.clone()))).unwrap(); } ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::MinimumBackingVotes(session_index, tx), + )) if parent == *hash && session_index == *session => { + tx.send(Ok(2)).unwrap(); + } + ); } } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index baab07a9ba2..b1e56394796 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -649,10 +649,3 @@ pub fn maybe_compress_pov(pov: PoV) -> PoV { let pov = PoV { block_data: BlockData(raw) }; pov } - -/// How many votes we need to consider a candidate backed. -/// -/// WARNING: This has to be kept in sync with the runtime check in the inclusion module. -pub fn minimum_votes(n_validators: usize) -> usize { - std::cmp::min(2, n_validators) -} diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 8adc39eed56..6b078e08377 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -691,6 +691,8 @@ pub enum RuntimeApiRequest { slashing::OpaqueKeyOwnershipProof, RuntimeApiSender>, ), + /// Get the minimum required backing votes. + MinimumBackingVotes(SessionIndex, RuntimeApiSender), /// Get the backing state of the given para. /// This is a staging API that will not be available on production runtimes. @@ -719,6 +721,9 @@ impl RuntimeApiRequest { /// `SubmitReportDisputeLost` pub const SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT: u32 = 5; + /// `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. diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 312cc4eec6c..06aa351efb4 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -232,6 +232,14 @@ pub trait RuntimeApiSubsystemClient { session_index: SessionIndex, ) -> Result, ApiError>; + // === STAGING v6 === + /// Get the minimum number of backing votes. + async fn minimum_backing_votes( + &self, + at: Hash, + session_index: SessionIndex, + ) -> Result; + // === Asynchronous backing API === /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. @@ -473,6 +481,14 @@ where runtime_api.submit_report_dispute_lost(at, dispute_proof, key_ownership_proof) } + async fn minimum_backing_votes( + &self, + at: Hash, + _session_index: SessionIndex, + ) -> Result { + self.client.runtime_api().minimum_backing_votes(at) + } + async fn staging_para_backing_state( &self, at: Hash, diff --git a/polkadot/node/subsystem-util/src/runtime/error.rs b/polkadot/node/subsystem-util/src/runtime/error.rs index db3eacd6851..9c3d57b8ea6 100644 --- a/polkadot/node/subsystem-util/src/runtime/error.rs +++ b/polkadot/node/subsystem-util/src/runtime/error.rs @@ -33,7 +33,7 @@ pub enum Error { /// Some request to the runtime failed. /// For example if we prune a block we're requesting info about. #[error("Runtime API error {0}")] - RuntimeRequest(RuntimeApiError), + RuntimeRequest(#[from] RuntimeApiError), /// We tried fetching a session info which was not available. #[error("There was no session with the given index {0}")] @@ -43,7 +43,7 @@ pub enum Error { pub type Result = std::result::Result; /// Receive a response from a runtime request and convert errors. -pub(crate) async fn recv_runtime( +pub async fn recv_runtime( r: oneshot::Receiver>, ) -> Result { let result = r diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index a044a64e93a..fcd778b0784 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -24,27 +24,29 @@ use sp_core::crypto::ByteArray; use sp_keystore::{Keystore, KeystorePtr}; use polkadot_node_subsystem::{ - errors::RuntimeApiError, messages::RuntimeApiMessage, overseer, SubsystemSender, + errors::RuntimeApiError, + messages::{RuntimeApiMessage, RuntimeApiRequest}, + overseer, SubsystemSender, }; use polkadot_primitives::{ vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, + ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use crate::{ - request_availability_cores, request_candidate_events, request_key_ownership_proof, - request_on_chain_votes, request_session_index_for_child, request_session_info, - request_staging_async_backing_params, request_submit_report_dispute_lost, + request_availability_cores, request_candidate_events, request_from_runtime, + request_key_ownership_proof, request_on_chain_votes, request_session_index_for_child, + request_session_info, request_staging_async_backing_params, request_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash, request_validator_groups, }; /// Errors that can happen on runtime fetches. mod error; -use error::{recv_runtime, Result}; -pub use error::{Error, FatalError, JfyiError}; +use error::Result; +pub use error::{recv_runtime, Error, FatalError, JfyiError}; const LOG_TARGET: &'static str = "parachain::runtime-info"; @@ -451,3 +453,32 @@ where }) } } + +/// Request the min backing votes value. +/// Prior to runtime API version 6, just return a hardcoded constant. +pub async fn request_min_backing_votes( + parent: Hash, + session_index: SessionIndex, + sender: &mut impl overseer::SubsystemSender, +) -> Result { + let min_backing_votes_res = recv_runtime( + request_from_runtime(parent, sender, |tx| { + RuntimeApiRequest::MinimumBackingVotes(session_index, tx) + }) + .await, + ) + .await; + + if let Err(Error::RuntimeRequest(RuntimeApiError::NotSupported { .. })) = min_backing_votes_res + { + gum::trace!( + target: LOG_TARGET, + ?parent, + "Querying the backing threshold from the runtime is not supported by the current Runtime API", + ); + + Ok(LEGACY_MIN_BACKING_VOTES) + } else { + min_backing_votes_res + } +} diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 3680cb857e6..729908cc12b 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -34,19 +34,19 @@ 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, 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, CoreOccupied, 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, OccupiedCore, - OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, + 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, CoreOccupied, 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, + OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, PvfPrepTimeoutKind, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, @@ -55,9 +55,9 @@ pub use v5::{ UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, - ValidityError, ASSIGNMENT_KEY_TYPE_ID, LOWEST_PUBLIC_ID, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, - MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, - PARACHAIN_KEY_TYPE_ID, + ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, + MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, }; #[cfg(feature = "std")] diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 483256fe20f..86aca6c9bc6 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -240,6 +240,13 @@ sp_api::decl_runtime_apis! { key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, ) -> Option<()>; + /***** Staging *****/ + + /// 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 *****/ /// Returns the state of parachain backing for a given para. diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v5/mod.rs index 825d733c5f5..a41bfcdef84 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v5/mod.rs @@ -390,6 +390,10 @@ pub const MAX_POV_SIZE: u32 = 5 * 1024 * 1024; /// Can be adjusted in configuration. pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000; +/// Backing votes threshold used from the host prior to runtime API version 6 and from the runtime +/// prior to v9 configuration migration. +pub const LEGACY_MIN_BACKING_VOTES: u32 = 2; + // The public key of a keypair used by a validator for determining assignments /// to approve included parachain candidates. mod assignment_app { @@ -1695,6 +1699,14 @@ pub const fn supermajority_threshold(n: usize) -> usize { n - byzantine_threshold(n) } +/// Adjust the configured needed backing votes with the size of the backing group. +pub fn effective_minimum_backing_votes( + group_len: usize, + configured_minimum_backing_votes: u32, +) -> usize { + sp_std::cmp::min(group_len, configured_minimum_backing_votes as usize) +} + /// Information about validator sets of a session. /// /// NOTE: `SessionInfo` is frozen. Do not include new fields, consider creating a separate runtime diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index ac80f88cfaa..4b5f03b38c6 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -1738,6 +1738,8 @@ pub mod migrations { // Upgrade SessionKeys to include BEEFY key UpgradeSessionKeys, + + parachains_configuration::migration::v9::MigrateToV9, ); } diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index fc24ac18ed5..77c15c5672f 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -24,8 +24,8 @@ use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use polkadot_parachain::primitives::{MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM}; use primitives::{ - vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, MAX_CODE_SIZE, - MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + 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, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; @@ -245,6 +245,9 @@ pub struct HostConfiguration { /// This value should be greater than /// [`paras_availability_period`](Self::paras_availability_period). pub minimum_validation_upgrade_delay: BlockNumber, + /// The minimum number of valid backing statements required to consider a parachain candidate + /// backable. + pub minimum_backing_votes: u32, } impl> Default for HostConfiguration { @@ -295,6 +298,7 @@ impl> Default for HostConfiguration { MaxHrmpOutboundChannelsExceeded, /// Maximum number of HRMP inbound channels exceeded. MaxHrmpInboundChannelsExceeded, + /// `minimum_backing_votes` is set to zero. + ZeroMinimumBackingVotes, } impl HostConfiguration @@ -411,6 +417,10 @@ where return Err(MaxHrmpInboundChannelsExceeded) } + if self.minimum_backing_votes.is_zero() { + return Err(ZeroMinimumBackingVotes) + } + Ok(()) } @@ -477,7 +487,8 @@ pub mod pallet { /// v5-v6: (remove UMP dispatch queue) /// v6-v7: /// v7-v8: - const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); + /// v8-v9: + const STORAGE_VERSION: StorageVersion = StorageVersion::new(9); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1153,6 +1164,18 @@ pub mod pallet { config.on_demand_ttl = new; }) } + /// Set the minimum backing votes threshold. + #[pallet::call_index(52)] + #[pallet::weight(( + T::WeightInfo::set_config_with_u32(), + DispatchClass::Operational + ))] + pub fn set_minimum_backing_votes(origin: OriginFor, new: u32) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.minimum_backing_votes = new; + }) + } } #[pallet::hooks] diff --git a/polkadot/runtime/parachains/src/configuration/migration.rs b/polkadot/runtime/parachains/src/configuration/migration.rs index 4499b116462..26f8a85b496 100644 --- a/polkadot/runtime/parachains/src/configuration/migration.rs +++ b/polkadot/runtime/parachains/src/configuration/migration.rs @@ -19,3 +19,4 @@ pub mod v6; pub mod v7; pub mod v8; +pub mod v9; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v8.rs b/polkadot/runtime/parachains/src/configuration/migration/v8.rs index 7f7cc1cdefc..5c5b3482183 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v8.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v8.rs @@ -23,14 +23,114 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::SessionIndex; +use primitives::{ + vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, +}; use sp_runtime::Perbill; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use super::v7::V7HostConfiguration; -type V8HostConfiguration = configuration::HostConfiguration; +/// All configuration of the runtime with respect to paras. +#[derive(Clone, Encode, Decode, Debug)] +pub struct V8HostConfiguration { + pub max_code_size: u32, + pub max_head_data_size: u32, + pub max_upward_queue_count: u32, + pub max_upward_queue_size: u32, + pub max_upward_message_size: u32, + pub max_upward_message_num_per_candidate: u32, + pub hrmp_max_message_num_per_candidate: u32, + pub validation_upgrade_cooldown: BlockNumber, + pub validation_upgrade_delay: BlockNumber, + pub async_backing_params: AsyncBackingParams, + pub max_pov_size: u32, + pub max_downward_message_size: u32, + pub hrmp_max_parachain_outbound_channels: u32, + pub hrmp_sender_deposit: Balance, + pub hrmp_recipient_deposit: Balance, + pub hrmp_channel_max_capacity: u32, + pub hrmp_channel_max_total_size: u32, + pub hrmp_max_parachain_inbound_channels: u32, + pub hrmp_channel_max_message_size: u32, + pub executor_params: ExecutorParams, + pub code_retention_period: BlockNumber, + pub on_demand_cores: u32, + pub on_demand_retries: u32, + pub on_demand_queue_max_size: u32, + pub on_demand_target_queue_utilization: Perbill, + pub on_demand_fee_variability: Perbill, + pub on_demand_base_fee: Balance, + pub on_demand_ttl: BlockNumber, + pub group_rotation_frequency: BlockNumber, + pub paras_availability_period: BlockNumber, + pub scheduling_lookahead: u32, + pub max_validators_per_core: Option, + pub max_validators: Option, + pub dispute_period: SessionIndex, + pub dispute_post_conclusion_acceptance_period: BlockNumber, + pub no_show_slots: u32, + pub n_delay_tranches: u32, + pub zeroth_delay_tranche_width: u32, + pub needed_approvals: u32, + pub relay_vrf_modulo_samples: u32, + pub pvf_voting_ttl: SessionIndex, + pub minimum_validation_upgrade_delay: BlockNumber, +} + +impl> Default for V8HostConfiguration { + fn default() -> Self { + Self { + async_backing_params: AsyncBackingParams { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + no_show_slots: 1u32.into(), + validation_upgrade_cooldown: Default::default(), + validation_upgrade_delay: 2u32.into(), + code_retention_period: Default::default(), + max_code_size: Default::default(), + max_pov_size: Default::default(), + max_head_data_size: Default::default(), + on_demand_cores: Default::default(), + on_demand_retries: Default::default(), + scheduling_lookahead: 1, + max_validators_per_core: Default::default(), + max_validators: None, + dispute_period: 6, + dispute_post_conclusion_acceptance_period: 100.into(), + n_delay_tranches: Default::default(), + zeroth_delay_tranche_width: Default::default(), + needed_approvals: Default::default(), + relay_vrf_modulo_samples: Default::default(), + max_upward_queue_count: Default::default(), + max_upward_queue_size: Default::default(), + max_downward_message_size: Default::default(), + max_upward_message_size: Default::default(), + max_upward_message_num_per_candidate: Default::default(), + hrmp_sender_deposit: Default::default(), + hrmp_recipient_deposit: Default::default(), + hrmp_channel_max_capacity: Default::default(), + hrmp_channel_max_total_size: Default::default(), + hrmp_max_parachain_inbound_channels: Default::default(), + hrmp_channel_max_message_size: Default::default(), + hrmp_max_parachain_outbound_channels: Default::default(), + hrmp_max_message_num_per_candidate: Default::default(), + pvf_voting_ttl: 2u32.into(), + minimum_validation_upgrade_delay: 2.into(), + executor_params: Default::default(), + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_ttl: 5u32.into(), + } + } +} mod v7 { use super::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v9.rs b/polkadot/runtime/parachains/src/configuration/migration/v9.rs new file mode 100644 index 00000000000..64d71e628f4 --- /dev/null +++ b/polkadot/runtime/parachains/src/configuration/migration/v9.rs @@ -0,0 +1,321 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::configuration::{self, Config, Pallet}; +use frame_support::{ + pallet_prelude::*, + traits::{Defensive, StorageVersion}, + weights::Weight, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::{SessionIndex, LEGACY_MIN_BACKING_VOTES}; +use sp_runtime::Perbill; +use sp_std::vec::Vec; + +use frame_support::traits::OnRuntimeUpgrade; + +use super::v8::V8HostConfiguration; +type V9HostConfiguration = configuration::HostConfiguration; + +mod v8 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V8HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V8HostConfiguration>)>, + OptionQuery, + >; +} + +mod v9 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V9HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V9HostConfiguration>)>, + OptionQuery, + >; +} + +pub struct MigrateToV9(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV9 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV9"); + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV9 started"); + if StorageVersion::get::>() == 8 { + let weight_consumed = migrate_to_v9::(); + + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV9 executed successfully"); + StorageVersion::new(9).put::>(); + + weight_consumed + } else { + log::warn!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV9 should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade() for HostConfiguration MigrateToV9"); + ensure!( + StorageVersion::get::>() >= 9, + "Storage version should be >= 9 after the migration" + ); + + Ok(()) + } +} + +fn migrate_to_v9() -> Weight { + // Unusual formatting is justified: + // - make it easier to verify that fields assign what they supposed to assign. + // - this code is transient and will be removed after all migrations are done. + // - this code is important enough to optimize for legibility sacrificing consistency. + #[rustfmt::skip] + let translate = + |pre: V8HostConfiguration>| -> + V9HostConfiguration> + { + V9HostConfiguration { +max_code_size : pre.max_code_size, +max_head_data_size : pre.max_head_data_size, +max_upward_queue_count : pre.max_upward_queue_count, +max_upward_queue_size : pre.max_upward_queue_size, +max_upward_message_size : pre.max_upward_message_size, +max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate, +hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate, +validation_upgrade_cooldown : pre.validation_upgrade_cooldown, +validation_upgrade_delay : pre.validation_upgrade_delay, +max_pov_size : pre.max_pov_size, +max_downward_message_size : pre.max_downward_message_size, +hrmp_sender_deposit : pre.hrmp_sender_deposit, +hrmp_recipient_deposit : pre.hrmp_recipient_deposit, +hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity, +hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size, +hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels, +hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels, +hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size, +code_retention_period : pre.code_retention_period, +on_demand_cores : pre.on_demand_cores, +on_demand_retries : pre.on_demand_retries, +group_rotation_frequency : pre.group_rotation_frequency, +paras_availability_period : pre.paras_availability_period, +scheduling_lookahead : pre.scheduling_lookahead, +max_validators_per_core : pre.max_validators_per_core, +max_validators : pre.max_validators, +dispute_period : pre.dispute_period, +dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period, +no_show_slots : pre.no_show_slots, +n_delay_tranches : pre.n_delay_tranches, +zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width, +needed_approvals : pre.needed_approvals, +relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, +pvf_voting_ttl : pre.pvf_voting_ttl, +minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, +async_backing_params : pre.async_backing_params, +executor_params : pre.executor_params, +on_demand_queue_max_size : 10_000u32, +on_demand_base_fee : 10_000_000u128, +on_demand_fee_variability : Perbill::from_percent(3), +on_demand_target_queue_utilization : Perbill::from_percent(25), +on_demand_ttl : 5u32.into(), +minimum_backing_votes : LEGACY_MIN_BACKING_VOTES + } + }; + + let v8 = v8::ActiveConfig::::get() + .defensive_proof("Could not decode old config") + .unwrap_or_default(); + let v9 = translate(v8); + v9::ActiveConfig::::set(Some(v9)); + + // Allowed to be empty. + let pending_v8 = v8::PendingConfigs::::get().unwrap_or_default(); + let mut pending_v9 = Vec::new(); + + for (session, v8) in pending_v8.into_iter() { + let v9 = translate(v8); + pending_v9.push((session, v9)); + } + v9::PendingConfigs::::set(Some(pending_v9.clone())); + + let num_configs = (pending_v9.len() + 1) as u64; + T::DbWeight::get().reads_writes(num_configs, num_configs) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{new_test_ext, Test}; + + #[test] + fn v9_deserialized_from_actual_data() { + // Example how to get new `raw_config`: + // We'll obtain the raw_config at a specified a block + // Steps: + // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate + // 2. Set these parameters: + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration + // 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of + // the block) + // 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the + // referenced block. + // 2.4. You'll also need the decoded values to update the test. + // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage + // 3.1 Enter the encoded storage key and you get the raw config. + + // This exceeds the maximal line width length, but that's fine, since this is not code and + // doesn't need to be read and also leaving it as one line allows to easily copy it. + let raw_config = + hex_literal::hex![" + 0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000000000000000001027000080b2e60e80c3c901809698000000000000000000000000000500000014000000040000000100000001010000000006000000640000000200000019000000000000000300000002000000020000000500000002000000" + ]; + + let v9 = + V9HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); + + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. + assert_eq!(v9.max_code_size, 3_145_728); + assert_eq!(v9.validation_upgrade_cooldown, 2); + assert_eq!(v9.max_pov_size, 5_242_880); + assert_eq!(v9.hrmp_channel_max_message_size, 1_048_576); + assert_eq!(v9.n_delay_tranches, 25); + assert_eq!(v9.minimum_validation_upgrade_delay, 5); + assert_eq!(v9.group_rotation_frequency, 20); + assert_eq!(v9.on_demand_cores, 0); + assert_eq!(v9.on_demand_base_fee, 10_000_000); + assert_eq!(v9.minimum_backing_votes, LEGACY_MIN_BACKING_VOTES); + } + + #[test] + fn test_migrate_to_v9() { + // Host configuration has lots of fields. However, in this migration we only add one + // field. The most important part to check are a couple of the last fields. We also pick + // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and + // also their type. + // + // We specify only the picked fields and the rest should be provided by the `Default` + // implementation. That implementation is copied over between the two types and should work + // fine. + let v8 = V8HostConfiguration:: { + needed_approvals: 69, + paras_availability_period: 55, + hrmp_recipient_deposit: 1337, + max_pov_size: 1111, + minimum_validation_upgrade_delay: 20, + ..Default::default() + }; + + let mut pending_configs = Vec::new(); + pending_configs.push((100, v8.clone())); + pending_configs.push((300, v8.clone())); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v8 version in the state. + v8::ActiveConfig::::set(Some(v8)); + v8::PendingConfigs::::set(Some(pending_configs)); + + migrate_to_v9::(); + + let v9 = v9::ActiveConfig::::get().unwrap(); + let mut configs_to_check = v9::PendingConfigs::::get().unwrap(); + configs_to_check.push((0, v9.clone())); + + for (_, v8) in configs_to_check { + #[rustfmt::skip] + { + assert_eq!(v8.max_code_size , v9.max_code_size); + assert_eq!(v8.max_head_data_size , v9.max_head_data_size); + assert_eq!(v8.max_upward_queue_count , v9.max_upward_queue_count); + assert_eq!(v8.max_upward_queue_size , v9.max_upward_queue_size); + assert_eq!(v8.max_upward_message_size , v9.max_upward_message_size); + assert_eq!(v8.max_upward_message_num_per_candidate , v9.max_upward_message_num_per_candidate); + assert_eq!(v8.hrmp_max_message_num_per_candidate , v9.hrmp_max_message_num_per_candidate); + assert_eq!(v8.validation_upgrade_cooldown , v9.validation_upgrade_cooldown); + assert_eq!(v8.validation_upgrade_delay , v9.validation_upgrade_delay); + assert_eq!(v8.max_pov_size , v9.max_pov_size); + assert_eq!(v8.max_downward_message_size , v9.max_downward_message_size); + assert_eq!(v8.hrmp_max_parachain_outbound_channels , v9.hrmp_max_parachain_outbound_channels); + assert_eq!(v8.hrmp_sender_deposit , v9.hrmp_sender_deposit); + assert_eq!(v8.hrmp_recipient_deposit , v9.hrmp_recipient_deposit); + assert_eq!(v8.hrmp_channel_max_capacity , v9.hrmp_channel_max_capacity); + assert_eq!(v8.hrmp_channel_max_total_size , v9.hrmp_channel_max_total_size); + assert_eq!(v8.hrmp_max_parachain_inbound_channels , v9.hrmp_max_parachain_inbound_channels); + assert_eq!(v8.hrmp_channel_max_message_size , v9.hrmp_channel_max_message_size); + assert_eq!(v8.code_retention_period , v9.code_retention_period); + assert_eq!(v8.on_demand_cores , v9.on_demand_cores); + assert_eq!(v8.on_demand_retries , v9.on_demand_retries); + assert_eq!(v8.group_rotation_frequency , v9.group_rotation_frequency); + assert_eq!(v8.paras_availability_period , v9.paras_availability_period); + assert_eq!(v8.scheduling_lookahead , v9.scheduling_lookahead); + assert_eq!(v8.max_validators_per_core , v9.max_validators_per_core); + assert_eq!(v8.max_validators , v9.max_validators); + assert_eq!(v8.dispute_period , v9.dispute_period); + assert_eq!(v8.no_show_slots , v9.no_show_slots); + assert_eq!(v8.n_delay_tranches , v9.n_delay_tranches); + assert_eq!(v8.zeroth_delay_tranche_width , v9.zeroth_delay_tranche_width); + assert_eq!(v8.needed_approvals , v9.needed_approvals); + assert_eq!(v8.relay_vrf_modulo_samples , v9.relay_vrf_modulo_samples); + assert_eq!(v8.pvf_voting_ttl , v9.pvf_voting_ttl); + assert_eq!(v8.minimum_validation_upgrade_delay , v9.minimum_validation_upgrade_delay); + assert_eq!(v8.async_backing_params.allowed_ancestry_len, v9.async_backing_params.allowed_ancestry_len); + assert_eq!(v8.async_backing_params.max_candidate_depth , v9.async_backing_params.max_candidate_depth); + assert_eq!(v8.executor_params , v9.executor_params); + assert_eq!(v8.minimum_backing_votes , v9.minimum_backing_votes); + }; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression. + } + }); + } + + // Test that migration doesn't panic in case there're no pending configurations upgrades in + // pallet's storage. + #[test] + fn test_migrate_to_v9_no_pending() { + let v8 = V8HostConfiguration::::default(); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v8 version in the state. + v8::ActiveConfig::::set(Some(v8)); + // Ensure there're no pending configs. + v8::PendingConfigs::::set(None); + + // Shouldn't fail. + migrate_to_v9::(); + }); + } +} diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index 43c03067a9a..ea39628c958 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -317,6 +317,7 @@ fn setting_pending_config_members() { on_demand_fee_variability: Perbill::from_percent(3), on_demand_target_queue_utilization: Perbill::from_percent(25), on_demand_ttl: 5u32, + minimum_backing_votes: 5, }; Configuration::set_validation_upgrade_cooldown( @@ -467,6 +468,11 @@ fn setting_pending_config_members() { .unwrap(); Configuration::set_pvf_voting_ttl(RuntimeOrigin::root(), new_config.pvf_voting_ttl) .unwrap(); + Configuration::set_minimum_backing_votes( + RuntimeOrigin::root(), + new_config.minimum_backing_votes, + ) + .unwrap(); assert_eq!(PendingConfigs::::get(), vec![(shared::SESSION_DELAY, new_config)],); }) diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index ceec7d718e8..a9ee2d1b961 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -36,11 +36,11 @@ use frame_system::pallet_prelude::*; use pallet_message_queue::OnQueueChanged; use parity_scale_codec::{Decode, Encode}; use primitives::{ - supermajority_threshold, well_known_keys, AvailabilityBitfield, BackedCandidate, - CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId, - SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex, - ValidityAttestation, + effective_minimum_backing_votes, supermajority_threshold, well_known_keys, + AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor, + CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, + HeadData, Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, + ValidatorId, ValidatorIndex, ValidityAttestation, }; use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; @@ -199,17 +199,6 @@ impl Default for ProcessedCandidates { } } -/// Number of backing votes we need for a valid backing. -/// -/// WARNING: This check has to be kept in sync with the node side checks. -pub fn minimum_backing_votes(n_validators: usize) -> usize { - // For considerations on this value see: - // https://github.com/paritytech/polkadot/pull/1656#issuecomment-999734650 - // and - // https://github.com/paritytech/polkadot/issues/4386 - sp_std::cmp::min(n_validators, 2) -} - /// Reads the footprint of queues for a specific origin type. pub trait QueueFootprinter { type Origin; @@ -622,6 +611,7 @@ impl Pallet { return Ok(ProcessedCandidates::default()) } + let minimum_backing_votes = configuration::Pallet::::config().minimum_backing_votes; let validators = shared::Pallet::::active_validator_keys(); // Collect candidate receipts with backers. @@ -738,7 +728,11 @@ impl Pallet { match maybe_amount_validated { Ok(amount_validated) => ensure!( - amount_validated >= minimum_backing_votes(group_vals.len()), + amount_validated >= + effective_minimum_backing_votes( + group_vals.len(), + minimum_backing_votes + ), Error::::InsufficientBacking, ), Err(()) => { diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 7c22ac36a80..70c5e959038 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -26,7 +26,10 @@ use crate::{ paras_inherent::DisputedBitfield, shared::AllowedRelayParentsTracker, }; -use primitives::{SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields}; +use primitives::{ + effective_minimum_backing_votes, SignedAvailabilityBitfields, + UncheckedSignedAvailabilityBitfields, +}; use assert_matches::assert_matches; use frame_support::assert_noop; @@ -120,11 +123,14 @@ pub(crate) fn back_candidate( kind: BackingKind, ) -> BackedCandidate { let mut validator_indices = bitvec::bitvec![u8, BitOrderLsb0; 0; group.len()]; - let threshold = minimum_backing_votes(group.len()); + let threshold = effective_minimum_backing_votes( + group.len(), + configuration::Pallet::::config().minimum_backing_votes, + ); let signing = match kind { BackingKind::Unanimous => group.len(), - BackingKind::Threshold => threshold, + BackingKind::Threshold => threshold as usize, BackingKind::Lacking => threshold.saturating_sub(1), }; @@ -1609,7 +1615,10 @@ fn backing_works() { ); let backers = { - let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len()); + let num_backers = effective_minimum_backing_votes( + group_validators(GroupIndex(0)).unwrap().len(), + configuration::Pallet::::config().minimum_backing_votes, + ); backing_bitfield(&(0..num_backers).collect::>()) }; assert_eq!( @@ -1631,7 +1640,10 @@ fn backing_works() { ); let backers = { - let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len()); + let num_backers = effective_minimum_backing_votes( + group_validators(GroupIndex(0)).unwrap().len(), + configuration::Pallet::::config().minimum_backing_votes, + ); backing_bitfield(&(0..num_backers).map(|v| v + 2).collect::>()) }; assert_eq!( @@ -1765,7 +1777,10 @@ fn can_include_candidate_with_ok_code_upgrade() { assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); let backers = { - let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len()); + let num_backers = effective_minimum_backing_votes( + group_validators(GroupIndex(0)).unwrap().len(), + configuration::Pallet::::config().minimum_backing_votes, + ); backing_bitfield(&(0..num_backers).collect::>()) }; assert_eq!( diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index 1e527190966..ab515cb3756 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -948,8 +948,11 @@ fn default_header() -> primitives::Header { mod sanitizers { use super::*; - use crate::inclusion::tests::{ - back_candidate, collator_sign_candidate, BackingKind, TestCandidateBuilder, + use crate::{ + inclusion::tests::{ + back_candidate, collator_sign_candidate, BackingKind, TestCandidateBuilder, + }, + mock::{new_test_ext, MockGenesisConfig}, }; use bitvec::order::Lsb0; use primitives::{ @@ -1207,131 +1210,133 @@ mod sanitizers { #[test] fn candidates() { - const RELAY_PARENT_NUM: u32 = 3; - - let header = default_header(); - let relay_parent = header.hash(); - let session_index = SessionIndex::from(0_u32); - - let keystore = LocalKeystore::in_memory(); - let keystore = Arc::new(keystore) as KeystorePtr; - let signing_context = SigningContext { parent_hash: relay_parent, session_index }; - - let validators = vec![ - keyring::Sr25519Keyring::Alice, - keyring::Sr25519Keyring::Bob, - keyring::Sr25519Keyring::Charlie, - keyring::Sr25519Keyring::Dave, - ]; - for validator in validators.iter() { - Keystore::sr25519_generate_new( - &*keystore, - PARACHAIN_KEY_TYPE_ID, - Some(&validator.to_seed()), - ) - .unwrap(); - } - - let has_concluded_invalid = - |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - - let entry_ttl = 10_000; - let scheduled = (0_usize..2) - .into_iter() - .map(|idx| { - let core_idx = CoreIndex::from(idx as u32); - let ca = CoreAssignment { - paras_entry: ParasEntry::new( - Assignment::new(ParaId::from(1_u32 + idx as u32)), - entry_ttl, - ), - core: core_idx, - }; - ca - }) - .collect::>(); - - let group_validators = |group_index: GroupIndex| { - match group_index { - group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), - group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), - _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + const RELAY_PARENT_NUM: u32 = 3; + + let header = default_header(); + let relay_parent = header.hash(); + let session_index = SessionIndex::from(0_u32); + + let keystore = LocalKeystore::in_memory(); + let keystore = Arc::new(keystore) as KeystorePtr; + let signing_context = SigningContext { parent_hash: relay_parent, session_index }; + + let validators = vec![ + keyring::Sr25519Keyring::Alice, + keyring::Sr25519Keyring::Bob, + keyring::Sr25519Keyring::Charlie, + keyring::Sr25519Keyring::Dave, + ]; + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); } - .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) - }; - - let backed_candidates = (0_usize..2) - .into_iter() - .map(|idx0| { - let idx1 = idx0 + 1; - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(idx1), - relay_parent, - pov_hash: Hash::repeat_byte(idx1 as u8), - persisted_validation_data_hash: [42u8; 32].into(), - hrmp_watermark: RELAY_PARENT_NUM, - ..Default::default() - } - .build(); - - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(idx0 as u32)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - ); - backed - }) - .collect::>(); - - // happy path - assert_eq!( - sanitize_backed_candidates::( - backed_candidates.clone(), - has_concluded_invalid, - &scheduled - ), - backed_candidates - ); - - // nothing is scheduled, so no paraids match, thus all backed candidates are skipped - { - let scheduled = &Vec::new(); - assert!(sanitize_backed_candidates::( - backed_candidates.clone(), - has_concluded_invalid, - &scheduled - ) - .is_empty()); - } + let has_concluded_invalid = + |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - // candidates that have concluded as invalid are filtered out - { - // mark every second one as concluded invalid - let set = { - let mut set = std::collections::HashSet::new(); - for (idx, backed_candidate) in backed_candidates.iter().enumerate() { - if idx & 0x01 == 0 { - set.insert(backed_candidate.hash()); - } + let entry_ttl = 10_000; + let scheduled = (0_usize..2) + .into_iter() + .map(|idx| { + let core_idx = CoreIndex::from(idx as u32); + let ca = CoreAssignment { + paras_entry: ParasEntry::new( + Assignment::new(ParaId::from(1_u32 + idx as u32)), + entry_ttl, + ), + core: core_idx, + }; + ca + }) + .collect::>(); + + let group_validators = |group_index: GroupIndex| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), + group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), + _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), } - set + .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; - let has_concluded_invalid = - |_idx: usize, candidate: &BackedCandidate| set.contains(&candidate.hash()); + + let backed_candidates = (0_usize..2) + .into_iter() + .map(|idx0| { + let idx1 = idx0 + 1; + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(idx1), + relay_parent, + pov_hash: Hash::repeat_byte(idx1 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(idx0 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + ); + backed + }) + .collect::>(); + + // happy path assert_eq!( sanitize_backed_candidates::( backed_candidates.clone(), has_concluded_invalid, &scheduled - ) - .len(), - backed_candidates.len() / 2 + ), + backed_candidates ); - } + + // nothing is scheduled, so no paraids match, thus all backed candidates are skipped + { + let scheduled = &Vec::new(); + assert!(sanitize_backed_candidates::( + backed_candidates.clone(), + has_concluded_invalid, + &scheduled + ) + .is_empty()); + } + + // candidates that have concluded as invalid are filtered out + { + // mark every second one as concluded invalid + let set = { + let mut set = std::collections::HashSet::new(); + for (idx, backed_candidate) in backed_candidates.iter().enumerate() { + if idx & 0x01 == 0 { + set.insert(backed_candidate.hash()); + } + } + set + }; + let has_concluded_invalid = + |_idx: usize, candidate: &BackedCandidate| set.contains(&candidate.hash()); + assert_eq!( + sanitize_backed_candidates::( + backed_candidates.clone(), + has_concluded_invalid, + &scheduled + ) + .len(), + backed_candidates.len() / 2 + ); + } + }); } } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 5406428377d..deef19d9071 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -118,3 +118,8 @@ pub fn backing_state( 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 +} diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index f97c0981039..2efd329eea0 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -1522,6 +1522,8 @@ pub mod migrations { frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, + + parachains_configuration::migration::v9::MigrateToV9, ); } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 192f4117ba6..a80f45c340d 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1549,6 +1549,7 @@ pub mod migrations { assigned_slots::migration::v1::VersionCheckedMigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, + parachains_configuration::migration::v9::MigrateToV9, ); } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 12baa20a129..73aa4980151 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -62,7 +62,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, reward_points as parachains_reward_points, - runtime_api_impl::v5 as parachains_runtime_api_impl, + runtime_api_impl::{ + v5 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, }; @@ -1422,6 +1424,7 @@ pub mod migrations { parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, UpgradeSessionKeys, + parachains_configuration::migration::v9::MigrateToV9, ); } @@ -1557,6 +1560,7 @@ sp_api::impl_runtime_apis! { } } + #[api_version(6)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1687,6 +1691,10 @@ sp_api::impl_runtime_apis! { key_ownership_proof, ) } + + fn minimum_backing_votes() -> u32 { + parachains_staging_runtime_api_impl::minimum_backing_votes::() + } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index a427aae42fb..22bffde5acc 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -30,7 +30,10 @@ use std::{ hash::Hash, }; -use primitives::{ValidatorSignature, ValidityAttestation as PrimitiveValidityAttestation}; +use primitives::{ + effective_minimum_backing_votes, ValidatorSignature, + ValidityAttestation as PrimitiveValidityAttestation, +}; use parity_scale_codec::{Decode, Encode}; @@ -57,8 +60,8 @@ pub trait Context { /// Members are meant to submit candidates and vote on validity. fn is_member_of(&self, authority: &Self::AuthorityId, group: &Self::GroupId) -> bool; - /// requisite number of votes for validity from a group. - fn requisite_votes(&self, group: &Self::GroupId) -> usize; + /// Get a validator group size. + fn get_group_size(&self, group: &Self::GroupId) -> Option; } /// Table configuration. @@ -319,9 +322,12 @@ impl Table { &self, digest: &Ctx::Digest, context: &Ctx, + minimum_backing_votes: u32, ) -> Option> { self.candidate_votes.get(digest).and_then(|data| { - let v_threshold = context.requisite_votes(&data.group_id); + let v_threshold = context.get_group_size(&data.group_id).map_or(usize::MAX, |len| { + effective_minimum_backing_votes(len, minimum_backing_votes) + }); data.attested(v_threshold) }) } @@ -636,16 +642,13 @@ mod tests { self.authorities.get(authority).map(|v| v == group).unwrap_or(false) } - fn requisite_votes(&self, id: &GroupId) -> usize { - let mut total_validity = 0; - - for validity in self.authorities.values() { - if validity == id { - total_validity += 1 - } + fn get_group_size(&self, group: &Self::GroupId) -> Option { + let count = self.authorities.values().filter(|g| *g == group).count(); + if count == 0 { + None + } else { + Some(count) } - - total_validity / 2 + 1 } } @@ -910,7 +913,7 @@ mod tests { table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); - assert!(table.attested_candidate(&candidate_digest, &context).is_none()); + assert!(table.attested_candidate(&candidate_digest, &context, 2).is_none()); let vote = SignedStatement { statement: Statement::Valid(candidate_digest), @@ -920,7 +923,7 @@ mod tests { table.import_statement(&context, vote); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); - assert!(table.attested_candidate(&candidate_digest, &context).is_some()); + assert!(table.attested_candidate(&candidate_digest, &context, 2).is_some()); } #[test] -- GitLab From bdbe98297032e21a553bf191c530690b1d591405 Mon Sep 17 00:00:00 2001 From: Juan Date: Thu, 31 Aug 2023 13:08:44 +0200 Subject: [PATCH 040/633] Restructure `dispatch` macro related exports (#1162) * restructure dispatch macro related exports * moved Dispatchable to lib.rs * fix .gitignore final newline * ".git/.scripts/commands/fmt/fmt.sh" * fix rustdocs * wip --------- Co-authored-by: Liam Aharon Co-authored-by: command-bot <> Co-authored-by: ordian --- Cargo.lock | 1 - .../src/messages_xcm_extension.rs | 2 +- .../runtime-common/src/priority_calculator.rs | 4 ++-- .../src/refund_relayer_extension.rs | 4 ++-- .../xcm-bridge-hub-router/src/benchmarking.rs | 5 +--- cumulus/pallets/parachain-system/src/lib.rs | 4 ++-- cumulus/pallets/parachain-system/src/tests.rs | 3 +-- cumulus/pallets/xcm/src/lib.rs | 2 +- .../common/src/local_and_foreign_assets.rs | 15 +++++------- .../collectives-polkadot/src/impls.rs | 3 ++- .../parachains/runtimes/test-utils/src/lib.rs | 4 ++-- cumulus/primitives/utility/src/lib.rs | 2 +- cumulus/xcm/xcm-emulator/src/lib.rs | 3 +-- .../common/src/assigned_slots/migration.rs | 5 +--- polkadot/runtime/common/src/auctions.rs | 5 ++-- polkadot/runtime/common/src/claims.rs | 8 ++++--- .../runtime/common/src/crowdloan/migration.rs | 3 +-- polkadot/runtime/common/src/mock.rs | 7 ++---- polkadot/runtime/common/src/purchase.rs | 8 +++---- .../pallet-xcm-benchmarks/src/generic/mod.rs | 6 ++--- polkadot/xcm/pallet-xcm/src/lib.rs | 11 ++++----- polkadot/xcm/xcm-builder/src/tests/mock.rs | 5 ++-- polkadot/xcm/xcm-executor/src/config.rs | 3 ++- .../xcm-executor/src/traits/on_response.rs | 6 ++--- substrate/frame/alliance/src/lib.rs | 9 +++---- substrate/frame/assets/src/benchmarking.rs | 5 +--- substrate/frame/assets/src/lib.rs | 4 ++-- substrate/frame/benchmarking/src/utils.rs | 8 ++----- substrate/frame/collective/src/lib.rs | 8 ++++--- substrate/frame/contracts/src/exec.rs | 11 +++++---- substrate/frame/contracts/src/gas.rs | 6 ++--- substrate/frame/contracts/src/lib.rs | 9 +++---- .../frame/contracts/src/migration/v15.rs | 4 +++- substrate/frame/contracts/src/storage.rs | 3 +-- .../frame/contracts/src/storage/meter.rs | 5 ++-- substrate/frame/contracts/src/tests.rs | 4 ++-- substrate/frame/contracts/src/wasm/mod.rs | 4 ++-- substrate/frame/contracts/src/wasm/runtime.rs | 4 ++-- substrate/frame/conviction-voting/src/lib.rs | 13 +++++++--- .../src/unsigned.rs | 4 ++-- .../test-staking-e2e/src/mock.rs | 3 ++- substrate/frame/lottery/src/lib.rs | 4 ++-- substrate/frame/multisig/src/migrations.rs | 3 +-- substrate/frame/nfts/runtime-api/Cargo.toml | 3 +-- substrate/frame/nfts/runtime-api/src/lib.rs | 2 +- substrate/frame/nfts/src/benchmarking.rs | 3 +-- substrate/frame/nfts/src/tests.rs | 6 +++-- substrate/frame/offences/src/migration.rs | 3 +-- substrate/frame/proxy/src/lib.rs | 4 ++-- substrate/frame/proxy/src/tests.rs | 3 +-- .../ranked-collective/src/benchmarking.rs | 2 +- substrate/frame/ranked-collective/src/lib.rs | 4 ++-- substrate/frame/referenda/src/benchmarking.rs | 3 +-- substrate/frame/referenda/src/tests.rs | 7 ++---- substrate/frame/safe-mode/src/tests.rs | 4 ++-- substrate/frame/scheduler/src/lib.rs | 8 +++---- substrate/frame/session/src/lib.rs | 4 ++-- substrate/frame/staking/src/benchmarking.rs | 3 +-- substrate/frame/staking/src/migrations.rs | 5 ++-- substrate/frame/staking/src/pallet/mod.rs | 2 +- .../frame/state-trie-migration/src/lib.rs | 1 - .../src/construct_runtime/expand/call.rs | 12 +++++----- .../procedural/src/pallet/expand/call.rs | 4 ++-- substrate/frame/support/src/dispatch.rs | 24 +++++-------------- .../frame/support/src/dispatch_context.rs | 8 +++---- substrate/frame/support/src/lib.rs | 14 +++++------ .../support/src/traits/tokens/currency.rs | 7 ++---- .../src/traits/tokens/currency/reservable.rs | 3 ++- .../src/traits/tokens/fungible/regular.rs | 3 +-- .../src/traits/tokens/fungibles/regular.rs | 3 +-- .../support/src/traits/tokens/nonfungibles.rs | 4 ++-- .../src/traits/tokens/nonfungibles_v2.rs | 4 ++-- substrate/frame/support/src/traits/voting.rs | 4 ++-- .../support/test/tests/construct_runtime.rs | 8 +++---- substrate/frame/support/test/tests/pallet.rs | 8 +++---- .../support/test/tests/pallet_instance.rs | 7 ++++-- .../frame/transaction-storage/src/lib.rs | 4 ++-- substrate/frame/treasury/src/benchmarking.rs | 3 +-- substrate/frame/tx-pause/src/tests.rs | 3 ++- substrate/frame/uniques/src/benchmarking.rs | 3 +-- substrate/frame/uniques/src/tests.rs | 3 ++- substrate/frame/utility/src/tests.rs | 6 ++--- substrate/frame/vesting/src/lib.rs | 4 ++-- substrate/frame/vesting/src/tests.rs | 3 ++- 84 files changed, 195 insertions(+), 244 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe538e170fa..becee4e11c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9970,7 +9970,6 @@ dependencies = [ name = "pallet-nfts-runtime-api" version = "4.0.0-dev" dependencies = [ - "frame-support", "pallet-nfts", "parity-scale-codec", "sp-api", diff --git a/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs index b47e9994da7..77c23db3b2b 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -29,7 +29,7 @@ use bp_messages::{ use bp_runtime::messages::MessageDispatchResult; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::{Decode, Encode}; -use frame_support::{dispatch::Weight, traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound}; +use frame_support::{traits::Get, weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; use pallet_bridge_messages::{ Config as MessagesConfig, OutboundLanesCongestedSignals, Pallet as MessagesPallet, WeightInfoExt as MessagesPalletWeights, diff --git a/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs b/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs index dad6c77b01f..3d53f9da8c2 100644 --- a/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs @@ -51,13 +51,13 @@ mod integrity_tests { use bp_messages::MessageNonce; use bp_runtime::PreComputedSize; use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, Dispatchable, Pays, PostDispatchInfo}, + dispatch::{DispatchClass, DispatchInfo, Pays, PostDispatchInfo}, traits::Get, }; use pallet_bridge_messages::WeightInfoExt; use pallet_transaction_payment::OnChargeTransaction; use sp_runtime::{ - traits::{UniqueSaturatedInto, Zero}, + traits::{Dispatchable, UniqueSaturatedInto, Zero}, transaction_validity::TransactionPriority, FixedPointOperand, SaturatedConversion, Saturating, }; diff --git a/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs index cea43b7c1de..f0c2cbf4450 100644 --- a/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -27,7 +27,7 @@ use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Parachain, ParachainIdOf, RangeInclusiveExt, StaticStrProvider}; use codec::{Decode, Encode}; use frame_support::{ - dispatch::{CallableCallFor, DispatchInfo, Dispatchable, PostDispatchInfo}, + dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, traits::IsSubType, weights::Weight, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -47,7 +47,7 @@ use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTra use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Get, PostDispatchInfoOf, SignedExtension, Zero}, + traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, transaction_validity::{ TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, }, diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index dbbce84d3eb..4bbe414f663 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -22,10 +22,7 @@ use crate::{Bridge, Call}; use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; use frame_benchmarking::benchmarks_instance_pallet; -use frame_support::{ - dispatch::UnfilteredDispatchable, - traits::{EnsureOrigin, Get, Hooks}, -}; +use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; use sp_runtime::traits::Zero; use xcm::prelude::*; diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 7fd44454811..0ab2abb1881 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -36,7 +36,7 @@ use cumulus_primitives_core::{ }; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ - dispatch::{DispatchError, DispatchResult, Pays, PostDispatchInfo}, + dispatch::{DispatchResult, Pays, PostDispatchInfo}, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, storage, @@ -52,7 +52,7 @@ use sp_runtime::{ InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity, ValidTransaction, }, - RuntimeDebug, + DispatchError, RuntimeDebug, }; use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; use xcm::latest::XcmHash; diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 5586feb8879..626196790bc 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -23,10 +23,9 @@ use cumulus_primitives_core::{ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use frame_support::{ assert_ok, - dispatch::UnfilteredDispatchable, inherent::{InherentData, ProvideInherent}, parameter_types, - traits::{OnFinalize, OnInitialize}, + traits::{OnFinalize, OnInitialize, UnfilteredDispatchable}, weights::Weight, }; use frame_system::{ diff --git a/cumulus/pallets/xcm/src/lib.rs b/cumulus/pallets/xcm/src/lib.rs index da806917ad3..69b4f437540 100644 --- a/cumulus/pallets/xcm/src/lib.rs +++ b/cumulus/pallets/xcm/src/lib.rs @@ -24,7 +24,7 @@ use codec::{Decode, DecodeLimit, Encode}; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, }; -use frame_support::dispatch::Weight; +use frame_support::weights::Weight; pub use pallet::*; use scale_info::TypeInfo; use sp_runtime::{traits::BadOrigin, RuntimeDebug}; 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 4fae973d981..5c66d1cabe5 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 @@ -13,19 +13,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::{ - pallet_prelude::DispatchError, - traits::{ - fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced}, - tokens::{ - DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, - }, - AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess, +use frame_support::traits::{ + fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced}, + tokens::{ + DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, }, + AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess, }; use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter}; use parachains_common::AccountId; -use sp_runtime::{traits::MaybeEquivalence, DispatchResult}; +use sp_runtime::{traits::MaybeEquivalence, DispatchError, DispatchResult}; use sp_std::{boxed::Box, marker::PhantomData}; use xcm::latest::MultiLocation; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs index 4addc8cd565..c970d82cfe5 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs @@ -15,13 +15,14 @@ use crate::OriginCaller; use frame_support::{ - dispatch::{DispatchError, DispatchResultWithPostInfo}, + dispatch::DispatchResultWithPostInfo, traits::{Currency, Get, Imbalance, OnUnbalanced, OriginTrait, PrivilegeCmp}, weights::Weight, }; use log; use pallet_alliance::{ProposalIndex, ProposalProvider}; use parachains_common::impls::NegativeImbalance; +use sp_runtime::DispatchError; use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; use xcm::latest::{Fungibility, Junction, Parent}; diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 93183a73c22..89bc7c4906e 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -22,9 +22,9 @@ use cumulus_primitives_core::{ use cumulus_primitives_parachain_inherent::ParachainInherentData; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use frame_support::{ - dispatch::{DispatchResult, RawOrigin, UnfilteredDispatchable}, + dispatch::{DispatchResult, RawOrigin}, inherent::{InherentData, ProvideInherent}, - traits::{OnFinalize, OnInitialize, OriginTrait}, + traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable}, weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor}; diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index e908e9e22c0..7d07bc329ed 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -315,11 +315,11 @@ mod tests { use cumulus_primitives_core::UpwardMessage; use frame_support::{ assert_ok, - dispatch::DispatchError, traits::tokens::{ DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence, }, }; + use sp_runtime::DispatchError; use xcm_executor::{traits::Error, Assets}; /// Validates [`validate`] for required Some(destination) and Some(message) diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 40cbaf4dea6..b882e7a9f0b 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -pub use codec::{Decode, Encode}; +pub use codec::{Decode, Encode, EncodeLike}; pub use lazy_static::lazy_static; pub use log; pub use paste; @@ -32,7 +32,6 @@ pub use std::{ // Substrate pub use frame_support::{ assert_ok, - dispatch::EncodeLike, sp_runtime::{AccountId32, DispatchResult}, traits::{ tokens::currency::Currency, EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index 6a84ea3ccc4..656e0836bba 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -15,10 +15,7 @@ // along with Polkadot. If not, see . use super::{Config, MaxPermanentSlots, MaxTemporarySlots, Pallet, LOG_TARGET}; -use frame_support::{ - dispatch::GetStorageVersion, - traits::{Get, OnRuntimeUpgrade}, -}; +use frame_support::traits::{Get, GetStorageVersion, OnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use frame_support::ensure; diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index 9c2bb04b9c8..e35303912fa 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -677,9 +677,7 @@ mod tests { use crate::{auctions, mock::TestRegistrar}; use ::test_helpers::{dummy_hash, dummy_head_data, dummy_validation_code}; use frame_support::{ - assert_noop, assert_ok, assert_storage_noop, - dispatch::DispatchError::BadOrigin, - ord_parameter_types, parameter_types, + assert_noop, assert_ok, assert_storage_noop, ord_parameter_types, parameter_types, traits::{ConstU32, EitherOfDiverse, OnFinalize, OnInitialize}, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -689,6 +687,7 @@ mod tests { use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, + DispatchError::BadOrigin, }; use std::{cell::RefCell, collections::BTreeMap}; diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 9cc06b2bede..0c736a63284 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -711,7 +711,7 @@ mod tests { use claims::Call as ClaimsCall; use frame_support::{ assert_err, assert_noop, assert_ok, - dispatch::{DispatchError::BadOrigin, GetDispatchInfo, Pays}, + dispatch::{GetDispatchInfo, Pays}, ord_parameter_types, parameter_types, traits::{ConstU32, ExistenceRequirement, WithdrawReasons}, }; @@ -719,7 +719,9 @@ mod tests { use sp_runtime::{ traits::{BlakeTwo256, Identity, IdentityLookup}, transaction_validity::TransactionLongevity, - BuildStorage, TokenError, + BuildStorage, + DispatchError::BadOrigin, + TokenError, }; type Block = frame_system::mocking::MockBlock; @@ -1470,7 +1472,7 @@ mod benchmarking { use super::*; use crate::claims::Call; use frame_benchmarking::{account, benchmarks}; - use frame_support::dispatch::UnfilteredDispatchable; + use frame_support::traits::UnfilteredDispatchable; use frame_system::RawOrigin; use secp_utils::*; use sp_runtime::{traits::ValidateUnsigned, DispatchResult}; diff --git a/polkadot/runtime/common/src/crowdloan/migration.rs b/polkadot/runtime/common/src/crowdloan/migration.rs index 03c4ab6c311..5133c14ada9 100644 --- a/polkadot/runtime/common/src/crowdloan/migration.rs +++ b/polkadot/runtime/common/src/crowdloan/migration.rs @@ -16,9 +16,8 @@ use super::*; use frame_support::{ - dispatch::GetStorageVersion, storage_alias, - traits::{OnRuntimeUpgrade, StorageVersion}, + traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion}, Twox64Concat, }; diff --git a/polkadot/runtime/common/src/mock.rs b/polkadot/runtime/common/src/mock.rs index ed25072e246..c9e3a8c39f1 100644 --- a/polkadot/runtime/common/src/mock.rs +++ b/polkadot/runtime/common/src/mock.rs @@ -17,16 +17,13 @@ //! Mocking utilities for testing. use crate::traits::Registrar; -use frame_support::{ - dispatch::{DispatchError, DispatchResult}, - weights::Weight, -}; +use frame_support::{dispatch::DispatchResult, weights::Weight}; use frame_system::pallet_prelude::BlockNumberFor; use parity_scale_codec::{Decode, Encode}; use primitives::{HeadData, Id as ParaId, PvfCheckStatement, SessionIndex, ValidationCode}; use runtime_parachains::paras; use sp_keyring::Sr25519Keyring; -use sp_runtime::{traits::SaturatedConversion, Permill}; +use sp_runtime::{traits::SaturatedConversion, DispatchError, Permill}; use std::{cell::RefCell, collections::HashMap}; thread_local! { diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 2520c459591..58ca19d0288 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -484,14 +484,14 @@ mod tests { // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use crate::purchase; use frame_support::{ - assert_noop, assert_ok, - dispatch::DispatchError::BadOrigin, - ord_parameter_types, parameter_types, + assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::{Currency, WithdrawReasons}, }; use sp_runtime::{ traits::{BlakeTwo256, Dispatchable, IdentifyAccount, Identity, IdentityLookup, Verify}, - ArithmeticError, BuildStorage, MultiSignature, + ArithmeticError, BuildStorage, + DispatchError::BadOrigin, + MultiSignature, }; type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs index 195066ee5b4..f207c238a39 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs @@ -24,10 +24,8 @@ mod mock; #[frame_support::pallet] pub mod pallet { use frame_benchmarking::BenchmarkError; - use frame_support::{ - dispatch::{Dispatchable, GetDispatchInfo}, - pallet_prelude::Encode, - }; + use frame_support::{dispatch::GetDispatchInfo, pallet_prelude::Encode}; + use sp_runtime::traits::Dispatchable; use xcm::latest::{ InteriorMultiLocation, Junction, MultiAsset, MultiAssets, MultiLocation, NetworkId, Response, diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index aefcf30910e..9dfb63c2c9c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -34,7 +34,8 @@ use frame_support::traits::{ use scale_info::TypeInfo; use sp_runtime::{ traits::{ - AccountIdConversion, BadOrigin, BlakeTwo256, BlockNumberProvider, Hash, Saturating, Zero, + AccountIdConversion, BadOrigin, BlakeTwo256, BlockNumberProvider, Dispatchable, Hash, + Saturating, Zero, }, RuntimeDebug, }; @@ -43,10 +44,7 @@ use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_executor::traits::{ConvertOrigin, Properties}; use frame_support::{ - dispatch::{Dispatchable, GetDispatchInfo}, - pallet_prelude::*, - traits::WithdrawReasons, - PalletId, + dispatch::GetDispatchInfo, pallet_prelude::*, traits::WithdrawReasons, PalletId, }; use frame_system::pallet_prelude::*; pub use pallet::*; @@ -149,11 +147,12 @@ impl WeightInfo for TestWeightInfo { pub mod pallet { use super::*; use frame_support::{ - dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, + dispatch::{GetDispatchInfo, PostDispatchInfo}, parameter_types, }; use frame_system::Config as SysConfig; use sp_core::H256; + use sp_runtime::traits::Dispatchable; use xcm_executor::traits::{MatchesFungible, WeightBounds}; parameter_types! { diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 0e7b748106e..e73b62f0073 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -28,11 +28,10 @@ pub use crate::{ use frame_support::traits::{ContainsPair, Everything}; pub use frame_support::{ dispatch::{ - DispatchError, DispatchInfo, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, - Parameter, PostDispatchInfo, + DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, Parameter, PostDispatchInfo, }, ensure, match_types, parameter_types, - sp_runtime::DispatchErrorWithPostInfo, + sp_runtime::{traits::Dispatchable, DispatchError, DispatchErrorWithPostInfo}, traits::{ConstU32, Contains, Get, IsInVec}, }; pub use parity_scale_codec::{Decode, Encode}; diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index 1fc5cef3921..2ff12cd7a53 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -20,9 +20,10 @@ use crate::traits::{ WeightTrader, }; use frame_support::{ - dispatch::{Dispatchable, GetDispatchInfo, Parameter, PostDispatchInfo}, + dispatch::{GetDispatchInfo, Parameter, PostDispatchInfo}, traits::{Contains, ContainsPair, Get, PalletsInfoAccess}, }; +use sp_runtime::traits::Dispatchable; use xcm::prelude::*; /// The trait to parameterize the `XcmExecutor`. diff --git a/polkadot/xcm/xcm-executor/src/traits/on_response.rs b/polkadot/xcm/xcm-executor/src/traits/on_response.rs index b0f8b35bb98..3558160dc87 100644 --- a/polkadot/xcm/xcm-executor/src/traits/on_response.rs +++ b/polkadot/xcm/xcm-executor/src/traits/on_response.rs @@ -16,12 +16,10 @@ use crate::Xcm; use core::result; -use frame_support::{ - dispatch::fmt::Debug, - pallet_prelude::{Get, TypeInfo}, -}; +use frame_support::pallet_prelude::{Get, TypeInfo}; use parity_scale_codec::{FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::Zero; +use sp_std::fmt::Debug; use xcm::latest::{ Error as XcmError, InteriorMultiLocation, MultiLocation, QueryId, Response, Result as XcmResult, Weight, XcmContext, diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index 1986354a094..627399f805b 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -98,16 +98,13 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_runtime::{ - traits::{Saturating, StaticLookup, Zero}, - RuntimeDebug, + traits::{Dispatchable, Saturating, StaticLookup, Zero}, + DispatchError, RuntimeDebug, }; use sp_std::{convert::TryInto, prelude::*}; use frame_support::{ - dispatch::{ - DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, - PostDispatchInfo, - }, + dispatch::{DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, ensure, traits::{ ChangeMembers, Currency, Get, InitializeMembers, IsSubType, OnUnbalanced, diff --git a/substrate/frame/assets/src/benchmarking.rs b/substrate/frame/assets/src/benchmarking.rs index 376f19139ab..c9b0825542d 100644 --- a/substrate/frame/assets/src/benchmarking.rs +++ b/substrate/frame/assets/src/benchmarking.rs @@ -23,10 +23,7 @@ use super::*; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; -use frame_support::{ - dispatch::UnfilteredDispatchable, - traits::{EnsureOrigin, Get}, -}; +use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; use sp_runtime::traits::Bounded; use sp_std::prelude::*; diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 363a99701b5..79e4fe30018 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -160,12 +160,12 @@ pub use types::*; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero}, - ArithmeticError, TokenError, + ArithmeticError, DispatchError, TokenError, }; use sp_std::prelude::*; use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, ensure, pallet_prelude::DispatchResultWithPostInfo, storage::KeyPrefixIterator, diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index 59e5192b427..b9b3f91e2dd 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -17,16 +17,12 @@ //! Interfaces, types and utils for benchmarking a FRAME runtime. use codec::{Decode, Encode}; -use frame_support::{ - dispatch::{DispatchError, DispatchErrorWithPostInfo}, - pallet_prelude::*, - traits::StorageInfo, -}; +use frame_support::{dispatch::DispatchErrorWithPostInfo, pallet_prelude::*, traits::StorageInfo}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; -use sp_runtime::traits::TrailingZeroInput; +use sp_runtime::{traits::TrailingZeroInput, DispatchError}; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; diff --git a/substrate/frame/collective/src/lib.rs b/substrate/frame/collective/src/lib.rs index ac6ad39eac5..10f989e5c4c 100644 --- a/substrate/frame/collective/src/lib.rs +++ b/substrate/frame/collective/src/lib.rs @@ -45,13 +45,15 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_io::storage; -use sp_runtime::{traits::Hash, RuntimeDebug}; +use sp_runtime::{ + traits::{Dispatchable, Hash}, + DispatchError, RuntimeDebug, +}; use sp_std::{marker::PhantomData, prelude::*, result}; use frame_support::{ dispatch::{ - DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, - Pays, PostDispatchInfo, + DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, Pays, PostDispatchInfo, }, ensure, impl_ensure_origin_with_arg_ignoring_arg, traits::{ diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 1ba44220ff8..38c15a807c5 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -25,9 +25,7 @@ use crate::{ }; use frame_support::{ crypto::ecdsa::ECDSAExt, - dispatch::{ - fmt::Debug, DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, - }, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, storage::{with_transaction, TransactionOutcome}, traits::{ @@ -47,8 +45,11 @@ use sp_core::{ Get, }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; -use sp_runtime::traits::{Convert, Hash, Zero}; -use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec}; +use sp_runtime::{ + traits::{Convert, Dispatchable, Hash, Zero}, + DispatchError, +}; +use sp_std::{fmt::Debug, marker::PhantomData, mem, prelude::*, vec::Vec}; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; diff --git a/substrate/frame/contracts/src/gas.rs b/substrate/frame/contracts/src/gas.rs index 7d17642d92e..363ddfad975 100644 --- a/substrate/frame/contracts/src/gas.rs +++ b/substrate/frame/contracts/src/gas.rs @@ -17,14 +17,12 @@ use crate::{exec::ExecError, Config, Error}; use frame_support::{ - dispatch::{ - DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo, PostDispatchInfo, - }, + dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, PostDispatchInfo}, weights::Weight, DefaultNoBound, }; use sp_core::Get; -use sp_runtime::traits::Zero; +use sp_runtime::{traits::Zero, DispatchError}; use sp_std::marker::PhantomData; #[cfg(test)] diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 2b9dd07b3f6..e22e4a3f9ff 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -111,10 +111,7 @@ use crate::{ use codec::{Codec, Decode, Encode, HasCompact, MaxEncodedLen}; use environmental::*; use frame_support::{ - dispatch::{ - DispatchError, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo, RawOrigin, - WithPostDispatchInfo, - }, + dispatch::{GetDispatchInfo, Pays, PostDispatchInfo, RawOrigin, WithPostDispatchInfo}, ensure, error::BadOrigin, traits::{ @@ -137,8 +134,8 @@ use pallet_contracts_primitives::{ use scale_info::TypeInfo; use smallvec::Array; use sp_runtime::{ - traits::{Convert, Hash, Saturating, StaticLookup, Zero}, - RuntimeDebug, + traits::{Convert, Dispatchable, Hash, Saturating, StaticLookup, Zero}, + DispatchError, RuntimeDebug, }; use sp_std::{fmt::Debug, prelude::*}; diff --git a/substrate/frame/contracts/src/migration/v15.rs b/substrate/frame/contracts/src/migration/v15.rs index efece62905f..180fe855ca6 100644 --- a/substrate/frame/contracts/src/migration/v15.rs +++ b/substrate/frame/contracts/src/migration/v15.rs @@ -28,7 +28,7 @@ use crate::{ AccountIdOf, BalanceOf, CodeHash, Config, HoldReason, Pallet, TrieId, Weight, LOG_TARGET, }; #[cfg(feature = "try-runtime")] -use frame_support::{dispatch::Vec, traits::fungible::InspectHold}; +use frame_support::traits::fungible::InspectHold; use frame_support::{ pallet_prelude::*, storage_alias, @@ -43,6 +43,8 @@ use sp_core::hexdisplay::HexDisplay; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; use sp_runtime::{traits::Zero, Saturating}; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; mod old { use super::*; diff --git a/substrate/frame/contracts/src/storage.rs b/substrate/frame/contracts/src/storage.rs index d58fd0fe9db..d4d261f4ec1 100644 --- a/substrate/frame/contracts/src/storage.rs +++ b/substrate/frame/contracts/src/storage.rs @@ -27,7 +27,6 @@ use crate::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::DispatchError, storage::child::{self, ChildInfo}, weights::Weight, CloneNoBound, DefaultNoBound, @@ -37,7 +36,7 @@ use sp_core::Get; use sp_io::KillStorageResult; use sp_runtime::{ traits::{Hash, Saturating, Zero}, - BoundedBTreeMap, DispatchResult, RuntimeDebug, + BoundedBTreeMap, DispatchError, DispatchResult, RuntimeDebug, }; use sp_std::{marker::PhantomData, prelude::*}; diff --git a/substrate/frame/contracts/src/storage/meter.rs b/substrate/frame/contracts/src/storage/meter.rs index 2a9a083412b..9f098090bc8 100644 --- a/substrate/frame/contracts/src/storage/meter.rs +++ b/substrate/frame/contracts/src/storage/meter.rs @@ -23,7 +23,6 @@ use crate::{ }; use frame_support::{ - dispatch::{fmt::Debug, DispatchError}, ensure, traits::{ fungible::{Mutate, MutateHold}, @@ -37,9 +36,9 @@ use frame_support::{ use sp_api::HashT; use sp_runtime::{ traits::{Saturating, Zero}, - FixedPointNumber, FixedU128, + DispatchError, FixedPointNumber, FixedU128, }; -use sp_std::{marker::PhantomData, vec, vec::Vec}; +use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec}; /// Deposit that uses the native fungible's balance type. pub type DepositOf = Deposit>; diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 8cc6d00b3d4..9d03a29b038 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -42,7 +42,7 @@ use assert_matches::assert_matches; use codec::Encode; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_err_with_weight, assert_noop, assert_ok, - dispatch::{DispatchError, DispatchErrorWithPostInfo, PostDispatchInfo}, + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, storage::child, traits::{ @@ -61,7 +61,7 @@ use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, - AccountId32, BuildStorage, Perbill, TokenError, + AccountId32, BuildStorage, DispatchError, Perbill, TokenError, }; type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 291f39f7fa7..5fc65e314ad 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -42,12 +42,12 @@ use crate::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, ensure, traits::{fungible::MutateHold, tokens::Precision::BestEffort}, }; use sp_core::Get; -use sp_runtime::RuntimeDebug; +use sp_runtime::{DispatchError, RuntimeDebug}; use sp_std::prelude::*; use wasmi::{Instance, Linker, Memory, MemoryType, StackLimits, Store}; diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index ca23ab9fe5d..4bc00388f72 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -26,13 +26,13 @@ use crate::{ use bitflags::bitflags; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; -use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; +use frame_support::{ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::{ traits::{Bounded, Zero}, - RuntimeDebug, + DispatchError, RuntimeDebug, }; use sp_std::{fmt, prelude::*}; use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store}; diff --git a/substrate/frame/conviction-voting/src/lib.rs b/substrate/frame/conviction-voting/src/lib.rs index 9c2993fc5ca..1d6fbaa3869 100644 --- a/substrate/frame/conviction-voting/src/lib.rs +++ b/substrate/frame/conviction-voting/src/lib.rs @@ -28,7 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, ensure, traits::{ fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling, @@ -38,7 +38,7 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero}, - ArithmeticError, Perbill, + ArithmeticError, DispatchError, Perbill, }; use sp_std::prelude::*; @@ -86,8 +86,15 @@ type ClassOf = <>::Polls as Polling>>::C #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::ClassCountOf}; + use frame_support::{ + pallet_prelude::{ + DispatchResultWithPostInfo, IsType, StorageDoubleMap, StorageMap, ValueQuery, + }, + traits::ClassCountOf, + Twox64Concat, + }; use frame_system::pallet_prelude::*; + use sp_runtime::BoundedVec; #[pallet::pallet] pub struct Pallet(_); diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index af8f632f8a9..f1c9e92a704 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -984,12 +984,12 @@ mod tests { }; use codec::Decode; use frame_election_provider_support::IndexAssignment; - use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::OffchainWorker}; + use frame_support::{assert_noop, assert_ok, traits::OffchainWorker}; use sp_npos_elections::ElectionScore; use sp_runtime::{ bounded_vec, offchain::storage_lock::{BlockAndTime, StorageLock}, - traits::{ValidateUnsigned, Zero}, + traits::{Dispatchable, ValidateUnsigned, Zero}, ModuleError, PerU16, Perbill, }; 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 024dc6ae7d6..501f9f89ab7 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 @@ -18,7 +18,8 @@ #![allow(dead_code)] use frame_support::{ - assert_ok, dispatch::UnfilteredDispatchable, parameter_types, traits, traits::Hooks, + assert_ok, parameter_types, traits, + traits::{Hooks, UnfilteredDispatchable}, weights::constants, }; use frame_system::EnsureRoot; diff --git a/substrate/frame/lottery/src/lib.rs b/substrate/frame/lottery/src/lib.rs index c9c02540424..c54f6d76803 100644 --- a/substrate/frame/lottery/src/lib.rs +++ b/substrate/frame/lottery/src/lib.rs @@ -56,7 +56,7 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::{ - dispatch::{DispatchResult, Dispatchable, GetDispatchInfo}, + dispatch::{DispatchResult, GetDispatchInfo}, ensure, pallet_prelude::MaxEncodedLen, storage::bounded_vec::BoundedVec, @@ -65,7 +65,7 @@ use frame_support::{ }; pub use pallet::*; use sp_runtime::{ - traits::{AccountIdConversion, Saturating, Zero}, + traits::{AccountIdConversion, Dispatchable, Saturating, Zero}, ArithmeticError, DispatchError, RuntimeDebug, }; use sp_std::prelude::*; diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index 298e73c5d75..3be55080b24 100644 --- a/substrate/frame/multisig/src/migrations.rs +++ b/substrate/frame/multisig/src/migrations.rs @@ -19,8 +19,7 @@ use super::*; use frame_support::{ - dispatch::GetStorageVersion, - traits::{OnRuntimeUpgrade, WrapperKeepOpaque}, + traits::{GetStorageVersion, OnRuntimeUpgrade, WrapperKeepOpaque}, Identity, }; diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index 9c0d817723d..483c4bd3234 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -14,10 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} pallet-nfts = { path = "..", default-features = false} sp-api = { path = "../../../primitives/api", default-features = false} [features] default = [ "std" ] -std = [ "codec/std", "frame-support/std", "pallet-nfts/std", "sp-api/std" ] +std = [ "codec/std", "pallet-nfts/std", "sp-api/std" ] diff --git a/substrate/frame/nfts/runtime-api/src/lib.rs b/substrate/frame/nfts/runtime-api/src/lib.rs index 867138b5bdd..cf2d444b42f 100644 --- a/substrate/frame/nfts/runtime-api/src/lib.rs +++ b/substrate/frame/nfts/runtime-api/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use frame_support::dispatch::Vec; +use sp_api::vec::Vec; sp_api::decl_runtime_apis! { pub trait NftsApi diff --git a/substrate/frame/nfts/src/benchmarking.rs b/substrate/frame/nfts/src/benchmarking.rs index 995c8420367..8792af675fc 100644 --- a/substrate/frame/nfts/src/benchmarking.rs +++ b/substrate/frame/nfts/src/benchmarking.rs @@ -26,8 +26,7 @@ use frame_benchmarking::v1::{ }; use frame_support::{ assert_ok, - dispatch::UnfilteredDispatchable, - traits::{EnsureOrigin, Get}, + traits::{EnsureOrigin, Get, UnfilteredDispatchable}, BoundedVec, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index f7879570a4c..6e264048f11 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -21,7 +21,6 @@ use crate::{mock::*, Event, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, - dispatch::Dispatchable, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Mutate}, Currency, Get, @@ -29,7 +28,10 @@ use frame_support::{ }; use pallet_balances::Error as BalancesError; use sp_core::{bounded::BoundedVec, Pair}; -use sp_runtime::{traits::IdentifyAccount, MultiSignature, MultiSigner}; +use sp_runtime::{ + traits::{Dispatchable, IdentifyAccount}, + MultiSignature, MultiSigner, +}; use sp_std::prelude::*; type AccountIdOf = ::AccountId; diff --git a/substrate/frame/offences/src/migration.rs b/substrate/frame/offences/src/migration.rs index 3c0d243a55d..3b5cf3ce926 100644 --- a/substrate/frame/offences/src/migration.rs +++ b/substrate/frame/offences/src/migration.rs @@ -17,10 +17,9 @@ use super::{Config, Kind, OffenceDetails, Pallet, Perbill, SessionIndex, LOG_TARGET}; use frame_support::{ - dispatch::GetStorageVersion, pallet_prelude::ValueQuery, storage_alias, - traits::{Get, OnRuntimeUpgrade}, + traits::{Get, GetStorageVersion, OnRuntimeUpgrade}, weights::Weight, Twox64Concat, }; diff --git a/substrate/frame/proxy/src/lib.rs b/substrate/frame/proxy/src/lib.rs index 586d52fb62b..4d4da0433af 100644 --- a/substrate/frame/proxy/src/lib.rs +++ b/substrate/frame/proxy/src/lib.rs @@ -35,7 +35,7 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, GetDispatchInfo}, + dispatch::GetDispatchInfo, ensure, traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, }; @@ -45,7 +45,7 @@ use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ traits::{Dispatchable, Hash, Saturating, StaticLookup, TrailingZeroInput, Zero}, - DispatchResult, RuntimeDebug, + DispatchError, DispatchResult, RuntimeDebug, }; use sp_std::prelude::*; pub use weights::WeightInfo; diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 48a2a4ed0cc..0667be6e1e5 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -25,11 +25,10 @@ use crate as proxy; use codec::{Decode, Encode}; use frame_support::{ assert_noop, assert_ok, derive_impl, - dispatch::DispatchError, traits::{ConstU32, ConstU64, Contains}, }; use sp_core::H256; -use sp_runtime::{traits::BlakeTwo256, BuildStorage, RuntimeDebug}; +use sp_runtime::{traits::BlakeTwo256, BuildStorage, DispatchError, RuntimeDebug}; type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/ranked-collective/src/benchmarking.rs b/substrate/frame/ranked-collective/src/benchmarking.rs index b610d10009a..518428880e4 100644 --- a/substrate/frame/ranked-collective/src/benchmarking.rs +++ b/substrate/frame/ranked-collective/src/benchmarking.rs @@ -24,7 +24,7 @@ use crate::Pallet as RankedCollective; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, }; -use frame_support::{assert_ok, dispatch::UnfilteredDispatchable}; +use frame_support::{assert_ok, traits::UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; const SEED: u32 = 0; diff --git a/substrate/frame/ranked-collective/src/lib.rs b/substrate/frame/ranked-collective/src/lib.rs index d94932a1dac..deb1ccf2357 100644 --- a/substrate/frame/ranked-collective/src/lib.rs +++ b/substrate/frame/ranked-collective/src/lib.rs @@ -47,12 +47,12 @@ use sp_arithmetic::traits::Saturating; use sp_runtime::{ traits::{Convert, StaticLookup}, ArithmeticError::Overflow, - Perbill, RuntimeDebug, + DispatchError, Perbill, RuntimeDebug, }; use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ - dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo}, + dispatch::{DispatchResultWithPostInfo, PostDispatchInfo}, ensure, impl_ensure_origin_with_arg_ignoring_arg, traits::{EnsureOrigin, EnsureOriginWithArg, PollStatus, Polling, RankedMembers, VoteTally}, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index 78d14bd99d2..e884a0bb6ec 100644 --- a/substrate/frame/referenda/src/benchmarking.rs +++ b/substrate/frame/referenda/src/benchmarking.rs @@ -25,8 +25,7 @@ use frame_benchmarking::v1::{ }; use frame_support::{ assert_ok, - dispatch::UnfilteredDispatchable, - traits::{Bounded, Currency, EnsureOrigin, EnsureOriginWithArg}, + traits::{Bounded, Currency, EnsureOrigin, EnsureOriginWithArg, UnfilteredDispatchable}, }; use frame_system::RawOrigin; use sp_runtime::traits::Bounded as ArithBounded; diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs index c7469946c2d..d748c524605 100644 --- a/substrate/frame/referenda/src/tests.rs +++ b/substrate/frame/referenda/src/tests.rs @@ -21,12 +21,9 @@ use super::*; use crate::mock::{RefState::*, *}; use assert_matches::assert_matches; use codec::Decode; -use frame_support::{ - assert_noop, assert_ok, - dispatch::{DispatchError::BadOrigin, RawOrigin}, - traits::Contains, -}; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::Contains}; use pallet_balances::Error as BalancesError; +use sp_runtime::DispatchError::BadOrigin; #[test] fn params_should_work() { diff --git a/substrate/frame/safe-mode/src/tests.rs b/substrate/frame/safe-mode/src/tests.rs index 4ce9922d3b6..1e2eb343aa2 100644 --- a/substrate/frame/safe-mode/src/tests.rs +++ b/substrate/frame/safe-mode/src/tests.rs @@ -22,8 +22,8 @@ use super::*; use crate::mock::{RuntimeCall, *}; -use frame_support::{assert_err, assert_noop, assert_ok, dispatch::Dispatchable, traits::Currency}; -use sp_runtime::TransactionOutcome; +use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; +use sp_runtime::{traits::Dispatchable, TransactionOutcome}; /// Do something hypothetically by rolling back any changes afterwards. /// diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index f4b5521755b..4363f98668e 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -87,9 +87,7 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{ - DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, RawOrigin, - }, + dispatch::{DispatchResult, GetDispatchInfo, Parameter, RawOrigin}, ensure, traits::{ schedule::{self, DispatchTime, MaybeHashed}, @@ -105,8 +103,8 @@ use frame_system::{ use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ - traits::{BadOrigin, One, Saturating, Zero}, - BoundedVec, RuntimeDebug, + traits::{BadOrigin, Dispatchable, One, Saturating, Zero}, + BoundedVec, DispatchError, RuntimeDebug, }; use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index 1c0093c1df6..bf4671a247f 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -117,7 +117,7 @@ pub mod weights; use codec::{Decode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, ensure, traits::{ EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, @@ -129,7 +129,7 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, - ConsensusEngineId, KeyTypeId, Permill, RuntimeAppPublic, + ConsensusEngineId, DispatchError, KeyTypeId, Permill, RuntimeAppPublic, }; use sp_staking::SessionIndex; use sp_std::{ diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index e72a9baf044..ce5c35524c7 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -24,9 +24,8 @@ use testing_utils::*; use codec::Decode; use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ - dispatch::UnfilteredDispatchable, pallet_prelude::*, - traits::{Currency, Get, Imbalance}, + traits::{Currency, Get, Imbalance, UnfilteredDispatchable}, }; use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 332da506f01..89520028b90 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -19,8 +19,9 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ - dispatch::GetStorageVersion, pallet_prelude::ValueQuery, storage_alias, - traits::OnRuntimeUpgrade, + pallet_prelude::ValueQuery, + storage_alias, + traits::{GetStorageVersion, OnRuntimeUpgrade}, }; #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 40a2f5cf73e..c6c75326b80 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -17,11 +17,11 @@ //! Staking FRAME Pallet. +use codec::Codec; use frame_election_provider_support::{ ElectionProvider, ElectionProviderBase, SortedListProvider, VoteWeight, }; use frame_support::{ - dispatch::Codec, pallet_prelude::*, traits::{ Currency, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index e22a47458b7..3e69b219bb5 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -1268,7 +1268,6 @@ mod mock { #[cfg(test)] mod test { use super::{mock::*, *}; - use frame_support::dispatch::*; use sp_runtime::{bounded_vec, traits::Bounded, StateVersion}; #[test] diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs index cbf2ea90785..859b9a327e4 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -124,16 +124,16 @@ pub fn expand_outer_dispatch( } } - impl #scrate::dispatch::GetCallMetadata for RuntimeCall { - fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { - use #scrate::dispatch::GetCallName; + impl #scrate::traits::GetCallMetadata for RuntimeCall { + fn get_call_metadata(&self) -> #scrate::traits::CallMetadata { + use #scrate::traits::GetCallName; match self { #( #pallet_attrs #variant_patterns => { let function_name = call.get_call_name(); let pallet_name = stringify!(#pallet_names); - #scrate::dispatch::CallMetadata { function_name, pallet_name } + #scrate::traits::CallMetadata { function_name, pallet_name } } )* } @@ -147,7 +147,7 @@ pub fn expand_outer_dispatch( } fn get_call_names(module: &str) -> &'static [&'static str] { - use #scrate::dispatch::{Callable, GetCallName}; + use #scrate::{dispatch::Callable, traits::GetCallName}; match module { #( #pallet_attrs @@ -159,7 +159,7 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::dispatch::Dispatchable for RuntimeCall { + impl #scrate::__private::Dispatchable for RuntimeCall { type RuntimeOrigin = RuntimeOrigin; type Config = RuntimeCall; type Info = #scrate::dispatch::DispatchInfo; diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index 6489949ed5c..3ed5509863e 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -351,7 +351,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } - impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen> + impl<#type_impl_gen> #frame_support::traits::GetCallName for #call_ident<#type_use_gen> #where_clause { fn get_call_name(&self) -> &'static str { @@ -366,7 +366,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } - impl<#type_impl_gen> #frame_support::dispatch::GetCallIndex for #call_ident<#type_use_gen> + impl<#type_impl_gen> #frame_support::traits::GetCallIndex for #call_ident<#type_use_gen> #where_clause { fn get_call_index(&self) -> u8 { diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 0388a9adb39..eb1fc524200 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -18,30 +18,18 @@ //! Dispatch system. Contains a macro for defining runtime modules and //! generating values representing lazy module function calls. -pub use crate::traits::{ - CallMetadata, GetCallIndex, GetCallMetadata, GetCallName, GetStorageVersion, - UnfilteredDispatchable, -}; -pub use codec::{ - Codec, Decode, Encode, EncodeAsRef, EncodeLike, HasCompact, Input, MaxEncodedLen, Output, -}; -pub use scale_info::TypeInfo; -pub use sp_runtime::{ - traits::Dispatchable, transaction_validity::TransactionPriority, DispatchError, RuntimeDebug, -}; -pub use sp_std::{ - fmt, marker, - prelude::{Clone, Eq, PartialEq, Vec}, - result, -}; -pub use sp_weights::Weight; - +use crate::traits::UnfilteredDispatchable; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; +use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_runtime::{ generic::{CheckedExtrinsic, UncheckedExtrinsic}, traits::SignedExtension, + DispatchError, RuntimeDebug, }; +use sp_std::fmt; +use sp_weights::Weight; /// The return type of a `Dispatchable` in frame. When returned explicitly from /// a dispatchable function it allows overriding the default `PostDispatchInfo` diff --git a/substrate/frame/support/src/dispatch_context.rs b/substrate/frame/support/src/dispatch_context.rs index 31278ea9f81..608187b7220 100644 --- a/substrate/frame/support/src/dispatch_context.rs +++ b/substrate/frame/support/src/dispatch_context.rs @@ -26,11 +26,11 @@ //! //! # FRAME integration //! -//! The FRAME macros implement [`UnfilteredDispatchable`](crate::traits::UnfilteredDispatchable) for -//! each pallet `Call` enum. Part of this implementation is the call to [`run_in_context`], so that -//! each call to +//! The FRAME macros implement +//! [`UnfilteredDispatchable`](frame_support::traits::UnfilteredDispatchable) for each pallet `Call` +//! enum. Part of this implementation is the call to [`run_in_context`], so that each call to //! [`UnfilteredDispatchable::dispatch_bypass_filter`](crate::traits::UnfilteredDispatchable::dispatch_bypass_filter) -//! or [`Dispatchable::dispatch`](crate::dispatch::Dispatchable::dispatch) will run in a dispatch +//! or [`Dispatchable::dispatch`](sp_runtime::traits::Dispatchable::dispatch) will run in a dispatch //! context. //! //! # Example diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index a2a7e5ebc48..a7106780e02 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -49,7 +49,7 @@ pub mod __private { pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; - pub use sp_runtime::{RuntimeDebug, StateVersion}; + pub use sp_runtime::{traits::Dispatchable, RuntimeDebug, StateVersion}; #[cfg(feature = "std")] pub use sp_state_machine::BasicExternalities; pub use sp_std; @@ -806,10 +806,7 @@ pub mod testing_prelude { /// Prelude to be used alongside pallet macro, for ease of use. pub mod pallet_prelude { pub use crate::{ - dispatch::{ - DispatchClass, DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter, - Pays, - }, + dispatch::{DispatchClass, DispatchResult, DispatchResultWithPostInfo, Parameter, Pays}, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, storage, @@ -855,7 +852,7 @@ pub mod pallet_prelude { TransactionTag, TransactionValidity, TransactionValidityError, UnknownTransaction, ValidTransaction, }, - RuntimeDebug, MAX_MODULE_ERROR_ENCODED_SIZE, + DispatchError, RuntimeDebug, MAX_MODULE_ERROR_ENCODED_SIZE, }; pub use sp_std::marker::PhantomData; pub use sp_weights::Weight; @@ -1266,8 +1263,9 @@ pub mod pallet_prelude { /// Field types in enum variants must also implement [`PalletError`](traits::PalletError), /// otherwise the pallet will fail to compile. Rust primitive types have already implemented /// the [`PalletError`](traits::PalletError) trait along with some commonly used stdlib types -/// such as [`Option`] and [`PhantomData`](`frame_support::dispatch::marker::PhantomData`), and -/// hence in most use cases, a manual implementation is not necessary and is discouraged. +/// such as [`Option`] and +/// [`PhantomData`](`frame_support::__private::sp_std::marker::PhantomData`), and hence in most +/// use cases, a manual implementation is not necessary and is discouraged. /// /// The generic `T` must not bound anything and a `where` clause is not allowed. That said, /// bounds and/or a where clause should not needed for any use-case. diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index e6a7284a74b..0030e1261da 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -21,11 +21,8 @@ use super::{ imbalance::{Imbalance, SignedImbalance}, misc::{Balance, ExistenceRequirement, WithdrawReasons}, }; -use crate::{ - dispatch::{DispatchError, DispatchResult}, - traits::Get, -}; -use sp_runtime::traits::MaybeSerializeDeserialize; +use crate::{dispatch::DispatchResult, traits::Get}; +use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; diff --git a/substrate/frame/support/src/traits/tokens/currency/reservable.rs b/substrate/frame/support/src/traits/tokens/currency/reservable.rs index 79129cecdd6..ff8b0c6eea8 100644 --- a/substrate/frame/support/src/traits/tokens/currency/reservable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/reservable.rs @@ -22,9 +22,10 @@ use sp_core::Get; use super::{super::misc::BalanceStatus, Currency}; use crate::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, traits::{ExistenceRequirement, SignedImbalance, WithdrawReasons}, }; +use sp_runtime::DispatchError; /// A currency where funds can be reserved from the user. pub trait ReservableCurrency: Currency { diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 70d751b4977..fe2a1f2a14a 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -18,7 +18,6 @@ //! `Inspect` and `Mutate` traits for working with regular balances. use crate::{ - dispatch::DispatchError, ensure, traits::{ tokens::{ @@ -36,7 +35,7 @@ use crate::{ }, }; use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One}; -use sp_runtime::{traits::Saturating, ArithmeticError, TokenError}; +use sp_runtime::{traits::Saturating, ArithmeticError, DispatchError, TokenError}; use sp_std::marker::PhantomData; use super::{Credit, Debt, HandleImbalanceDrop, Imbalance}; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index 93816576247..7c39acdf424 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -20,7 +20,6 @@ use sp_std::marker::PhantomData; use crate::{ - dispatch::DispatchError, ensure, traits::{ tokens::{ @@ -38,7 +37,7 @@ use crate::{ }, }; use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One}; -use sp_runtime::{traits::Saturating, ArithmeticError, TokenError}; +use sp_runtime::{traits::Saturating, ArithmeticError, DispatchError, TokenError}; use super::{Credit, Debt, HandleImbalanceDrop, Imbalance}; diff --git a/substrate/frame/support/src/traits/tokens/nonfungibles.rs b/substrate/frame/support/src/traits/tokens/nonfungibles.rs index e9538d14f54..615e79c29c8 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungibles.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungibles.rs @@ -27,9 +27,9 @@ //! Implementations of these traits may be converted to implementations of corresponding //! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter. -use crate::dispatch::{DispatchError, DispatchResult}; +use crate::dispatch::DispatchResult; use codec::{Decode, Encode}; -use sp_runtime::TokenError; +use sp_runtime::{DispatchError, TokenError}; use sp_std::prelude::*; /// Trait for providing an interface to many read-only NFT-like sets of items. diff --git a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs index 345cce237b6..ec064bdebf6 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -27,9 +27,9 @@ //! Implementations of these traits may be converted to implementations of corresponding //! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter. -use crate::dispatch::{DispatchError, DispatchResult, Parameter}; +use crate::dispatch::{DispatchResult, Parameter}; use codec::{Decode, Encode}; -use sp_runtime::TokenError; +use sp_runtime::{DispatchError, TokenError}; use sp_std::prelude::*; /// Trait for providing an interface to many read-only NFT-like sets of items. diff --git a/substrate/frame/support/src/traits/voting.rs b/substrate/frame/support/src/traits/voting.rs index 4201b8d48d1..f5c9e285ef3 100644 --- a/substrate/frame/support/src/traits/voting.rs +++ b/substrate/frame/support/src/traits/voting.rs @@ -18,10 +18,10 @@ //! Traits and associated data structures concerned with voting, and moving between tokens and //! votes. -use crate::dispatch::{DispatchError, Parameter}; +use crate::dispatch::Parameter; use codec::{HasCompact, MaxEncodedLen}; use sp_arithmetic::Perbill; -use sp_runtime::traits::Member; +use sp_runtime::{traits::Member, DispatchError}; use sp_std::prelude::*; pub trait VoteTally { diff --git a/substrate/frame/support/test/tests/construct_runtime.rs b/substrate/frame/support/test/tests/construct_runtime.rs index a14276fa4d2..9ad51ad530e 100644 --- a/substrate/frame/support/test/tests/construct_runtime.rs +++ b/substrate/frame/support/test/tests/construct_runtime.rs @@ -578,14 +578,14 @@ fn call_weight_should_attach_to_call_enum() { #[test] fn call_name() { - use frame_support::dispatch::GetCallName; + use frame_support::traits::GetCallName; let name = module3::Call::::aux_4 {}.get_call_name(); assert_eq!("aux_4", name); } #[test] fn call_metadata() { - use frame_support::dispatch::{CallMetadata, GetCallMetadata}; + use frame_support::traits::{CallMetadata, GetCallMetadata}; let call = RuntimeCall::Module3(module3::Call::::aux_4 {}); let metadata = call.get_call_metadata(); let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() }; @@ -594,14 +594,14 @@ fn call_metadata() { #[test] fn get_call_names() { - use frame_support::dispatch::GetCallName; + use frame_support::traits::GetCallName; let call_names = module3::Call::::get_call_names(); assert_eq!(["fail", "aux_1", "aux_2", "aux_3", "aux_4", "operational"], call_names); } #[test] fn get_module_names() { - use frame_support::dispatch::GetCallMetadata; + use frame_support::traits::GetCallMetadata; let module_names = RuntimeCall::get_module_names(); assert_eq!( [ diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 8c85cd56959..88aad32225a 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -17,10 +17,7 @@ use frame_support::{ assert_ok, - dispatch::{ - DispatchClass, DispatchInfo, Dispatchable, GetDispatchInfo, Parameter, Pays, - UnfilteredDispatchable, - }, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays}, dispatch_context::with_context, pallet_prelude::{StorageInfoTrait, ValueQuery}, parameter_types, @@ -28,6 +25,7 @@ use frame_support::{ traits::{ ConstU32, GetCallIndex, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, + UnfilteredDispatchable, }, weights::{RuntimeDbWeight, Weight}, }; @@ -37,7 +35,7 @@ use sp_io::{ TestExternalities, }; use sp_runtime::{ - traits::{Extrinsic as ExtrinsicT, SignaturePayload as SignaturePayloadT}, + traits::{Dispatchable, Extrinsic as ExtrinsicT, SignaturePayload as SignaturePayloadT}, DispatchError, ModuleError, }; diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index be675a562ce..8d2d52d1885 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -16,11 +16,14 @@ // limitations under the License. use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, UnfilteredDispatchable}, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, pallet_prelude::ValueQuery, parameter_types, storage::unhashed, - traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, + traits::{ + ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, + UnfilteredDispatchable, + }, weights::Weight, }; use sp_io::{ diff --git a/substrate/frame/transaction-storage/src/lib.rs b/substrate/frame/transaction-storage/src/lib.rs index e784d20a0cf..753f5ca0c7b 100644 --- a/substrate/frame/transaction-storage/src/lib.rs +++ b/substrate/frame/transaction-storage/src/lib.rs @@ -30,10 +30,10 @@ mod tests; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{Dispatchable, GetDispatchInfo}, + dispatch::GetDispatchInfo, traits::{Currency, OnUnbalanced, ReservableCurrency}, }; -use sp_runtime::traits::{BlakeTwo256, Hash, One, Saturating, Zero}; +use sp_runtime::traits::{BlakeTwo256, Dispatchable, Hash, One, Saturating, Zero}; use sp_std::{prelude::*, result}; use sp_transaction_storage_proof::{ encode_index, random_chunk, InherentError, TransactionStorageProof, CHUNK_SIZE, diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index b8a53e06f20..24c290ddb66 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -23,9 +23,8 @@ use super::{Pallet as Treasury, *}; use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::{ - dispatch::UnfilteredDispatchable, ensure, - traits::{EnsureOrigin, OnInitialize}, + traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable}, }; use frame_system::RawOrigin; diff --git a/substrate/frame/tx-pause/src/tests.rs b/substrate/frame/tx-pause/src/tests.rs index ed0b8d103c8..48b70f71ccb 100644 --- a/substrate/frame/tx-pause/src/tests.rs +++ b/substrate/frame/tx-pause/src/tests.rs @@ -20,7 +20,8 @@ use super::*; use crate::mock::{RuntimeCall, *}; -use frame_support::{assert_err, assert_noop, assert_ok, dispatch::Dispatchable}; +use frame_support::{assert_err, assert_noop, assert_ok}; +use sp_runtime::DispatchError; // GENERAL SUCCESS/POSITIVE TESTS --------------------- diff --git a/substrate/frame/uniques/src/benchmarking.rs b/substrate/frame/uniques/src/benchmarking.rs index 4e63f69281e..821ca1794b8 100644 --- a/substrate/frame/uniques/src/benchmarking.rs +++ b/substrate/frame/uniques/src/benchmarking.rs @@ -24,8 +24,7 @@ use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ - dispatch::UnfilteredDispatchable, - traits::{EnsureOrigin, Get}, + traits::{EnsureOrigin, Get, UnfilteredDispatchable}, BoundedVec, }; use frame_system::RawOrigin as SystemOrigin; diff --git a/substrate/frame/uniques/src/tests.rs b/substrate/frame/uniques/src/tests.rs index 993552c3a2a..52f7df3b5ef 100644 --- a/substrate/frame/uniques/src/tests.rs +++ b/substrate/frame/uniques/src/tests.rs @@ -18,8 +18,9 @@ //! Tests for Uniques pallet. use crate::{mock::*, Event, *}; -use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::Currency}; +use frame_support::{assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalancesError; +use sp_runtime::traits::Dispatchable; use sp_std::prelude::*; fn items() -> Vec<(u64, u32, u32)> { diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index c2fd3a851c3..183853c4e8a 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -24,7 +24,7 @@ use super::*; use crate as utility; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable, Pays}, + dispatch::{DispatchErrorWithPostInfo, Pays}, error::BadOrigin, parameter_types, storage, traits::{ConstU32, ConstU64, Contains}, @@ -33,8 +33,8 @@ use frame_support::{ use pallet_collective::{EnsureProportionAtLeast, Instance1}; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, Hash, IdentityLookup}, - BuildStorage, TokenError, + traits::{BlakeTwo256, Dispatchable, Hash, IdentityLookup}, + BuildStorage, DispatchError, TokenError, }; type BlockNumber = u64; diff --git a/substrate/frame/vesting/src/lib.rs b/substrate/frame/vesting/src/lib.rs index eb829121e97..ee67a038e4d 100644 --- a/substrate/frame/vesting/src/lib.rs +++ b/substrate/frame/vesting/src/lib.rs @@ -58,7 +58,7 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchResult, ensure, storage::bounded_vec::BoundedVec, traits::{ @@ -74,7 +74,7 @@ use sp_runtime::{ AtLeast32BitUnsigned, Bounded, Convert, MaybeSerializeDeserialize, One, Saturating, StaticLookup, Zero, }, - RuntimeDebug, + DispatchError, RuntimeDebug, }; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; diff --git a/substrate/frame/vesting/src/tests.rs b/substrate/frame/vesting/src/tests.rs index 46afe895f6f..c35686bd514 100644 --- a/substrate/frame/vesting/src/tests.rs +++ b/substrate/frame/vesting/src/tests.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::{assert_noop, assert_ok, assert_storage_noop, dispatch::EncodeLike}; +use codec::EncodeLike; +use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use frame_system::RawOrigin; use sp_runtime::{ traits::{BadOrigin, Identity}, -- GitLab From f1f793718a2410872c3d61a86594a4c2bb9bea69 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 31 Aug 2023 13:38:11 +0200 Subject: [PATCH 041/633] Sassafras primitives (#1249) * Introduce Sassafras primitives * Keystore workaround * Fix doc * Use in keystore * Improve bandersnatch vrf docs * Apply review suggestions * Update README * Docs improvement * Docs fix --- Cargo.lock | 15 ++ Cargo.toml | 1 + substrate/client/keystore/src/local.rs | 248 +++++++++--------- .../primitives/consensus/sassafras/Cargo.toml | 50 ++++ .../primitives/consensus/sassafras/README.md | 12 + .../consensus/sassafras/src/digests.rs | 98 +++++++ .../primitives/consensus/sassafras/src/lib.rs | 169 ++++++++++++ .../consensus/sassafras/src/ticket.rs | 91 +++++++ .../primitives/consensus/sassafras/src/vrf.rs | 104 ++++++++ substrate/primitives/core/src/bandersnatch.rs | 195 ++++++++------ substrate/primitives/core/src/crypto.rs | 2 + substrate/primitives/keystore/src/lib.rs | 13 + 12 files changed, 797 insertions(+), 201 deletions(-) create mode 100644 substrate/primitives/consensus/sassafras/Cargo.toml create mode 100644 substrate/primitives/consensus/sassafras/README.md create mode 100644 substrate/primitives/consensus/sassafras/src/digests.rs create mode 100644 substrate/primitives/consensus/sassafras/src/lib.rs create mode 100644 substrate/primitives/consensus/sassafras/src/ticket.rs create mode 100644 substrate/primitives/consensus/sassafras/src/vrf.rs diff --git a/Cargo.lock b/Cargo.lock index becee4e11c9..0e0e47f955a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17049,6 +17049,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-consensus-sassafras" +version = "0.3.4-dev" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-consensus-slots", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 82b196e7a47..4db27b98e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -385,6 +385,7 @@ members = [ "substrate/primitives/consensus/common", "substrate/primitives/consensus/grandpa", "substrate/primitives/consensus/pow", + "substrate/primitives/consensus/sassafras", "substrate/primitives/consensus/slots", "substrate/primitives/core", "substrate/primitives/core/hashing", diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 97bc7c71a4a..c77f023e0f0 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -19,10 +19,6 @@ use parking_lot::RwLock; use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy}; -#[cfg(feature = "bandersnatch-experimental")] -use sp_core::bandersnatch; -#[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; use sp_core::{ crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString, VrfSecret}, ecdsa, ed25519, sr25519, @@ -36,6 +32,14 @@ use std::{ sync::Arc, }; +sp_keystore::bandersnatch_experimental_enabled! { +use sp_core::bandersnatch; +} + +sp_keystore::bls_experimental_enabled! { +use sp_core::{bls377, bls381}; +} + use crate::{Error, Result}; /// A local based keystore that is either memory-based or filesystem-based. @@ -132,6 +136,25 @@ impl LocalKeystore { } impl Keystore for LocalKeystore { + fn insert( + &self, + key_type: KeyTypeId, + suri: &str, + public: &[u8], + ) -> std::result::Result<(), ()> { + self.0.write().insert(key_type, suri, public).map_err(|_| ()) + } + + fn keys(&self, key_type: KeyTypeId) -> std::result::Result>, TraitError> { + self.0.read().raw_public_keys(key_type).map_err(|e| e.into()) + } + + fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { + public_keys + .iter() + .all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some()) + } + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) } @@ -236,140 +259,113 @@ impl Keystore for LocalKeystore { Ok(sig) } - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } - - /// Generate a new pair compatible with the 'bandersnatch' signature scheme. - /// - /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - self.generate_new::(key_type, seed) - } - - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_sign( - &self, - key_type: KeyTypeId, - public: &bandersnatch::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - self.sign::(key_type, public, msg) - } - - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_vrf_sign( - &self, - key_type: KeyTypeId, - public: &bandersnatch::Public, - data: &bandersnatch::vrf::VrfSignData, - ) -> std::result::Result, TraitError> { - self.vrf_sign::(key_type, public, data) - } + sp_keystore::bandersnatch_experimental_enabled! { + fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_vrf_output( - &self, - key_type: KeyTypeId, - public: &bandersnatch::Public, - input: &bandersnatch::vrf::VrfInput, - ) -> std::result::Result, TraitError> { - self.vrf_output::(key_type, public, input) - } + /// Generate a new pair compatible with the 'bandersnatch' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn bandersnatch_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } - #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_ring_vrf_sign( - &self, - key_type: KeyTypeId, - public: &bandersnatch::Public, - data: &bandersnatch::vrf::VrfSignData, - prover: &bandersnatch::ring_vrf::RingProver, - ) -> std::result::Result, TraitError> { - let sig = self - .0 - .read() - .key_pair_by_type::(public, key_type)? - .map(|pair| pair.ring_vrf_sign(data, prover)); - Ok(sig) - } + fn bandersnatch_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } - #[cfg(feature = "bls-experimental")] - fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } + fn bandersnatch_vrf_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + data: &bandersnatch::vrf::VrfSignData, + ) -> std::result::Result, TraitError> { + self.vrf_sign::(key_type, public, data) + } - #[cfg(feature = "bls-experimental")] - /// Generate a new pair compatible with the 'bls381' signature scheme. - /// - /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. - fn bls381_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - self.generate_new::(key_type, seed) - } + fn bandersnatch_vrf_output( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + input: &bandersnatch::vrf::VrfInput, + ) -> std::result::Result, TraitError> { + self.vrf_output::(key_type, public, input) + } - #[cfg(feature = "bls-experimental")] - fn bls381_sign( - &self, - key_type: KeyTypeId, - public: &bls381::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - self.sign::(key_type, public, msg) + fn bandersnatch_ring_vrf_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + data: &bandersnatch::vrf::VrfSignData, + prover: &bandersnatch::ring_vrf::RingProver, + ) -> std::result::Result, TraitError> { + let sig = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.ring_vrf_sign(data, prover)); + Ok(sig) + } } - #[cfg(feature = "bls-experimental")] - fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } + sp_keystore::bls_experimental_enabled! { + fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } - #[cfg(feature = "bls-experimental")] - /// Generate a new pair compatible with the 'bls377' signature scheme. - /// - /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. - fn bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - self.generate_new::(key_type, seed) - } + /// Generate a new pair compatible with the 'bls381' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn bls381_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } - #[cfg(feature = "bls-experimental")] - fn bls377_sign( - &self, - key_type: KeyTypeId, - public: &bls377::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - self.sign::(key_type, public, msg) - } + fn bls381_sign( + &self, + key_type: KeyTypeId, + public: &bls381::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } - fn insert( - &self, - key_type: KeyTypeId, - suri: &str, - public: &[u8], - ) -> std::result::Result<(), ()> { - self.0.write().insert(key_type, suri, public).map_err(|_| ()) - } + fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } - fn keys(&self, key_type: KeyTypeId) -> std::result::Result>, TraitError> { - self.0.read().raw_public_keys(key_type).map_err(|e| e.into()) - } + /// Generate a new pair compatible with the 'bls377' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } - fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { - public_keys - .iter() - .all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some()) + fn bls377_sign( + &self, + key_type: KeyTypeId, + public: &bls377::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } } } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml new file mode 100644 index 00000000000..56ae0087099 --- /dev/null +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "sp-consensus-sassafras" +version = "0.3.4-dev" +authors = ["Parity Technologies "] +description = "Primitives for Sassafras consensus" +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sp-consensus-sassafras" +readme = "README.md" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +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" } + +[features] +default = [ "std" ] +std = [ + "scale-codec/std", + "scale-info/std", + "serde/std", + "sp-api/std", + "sp-application-crypto/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] + +# Serde support without relying on std features. +serde = [ + "dep:serde", + "scale-info/serde", + "sp-application-crypto/serde", + "sp-consensus-slots/serde", + "sp-core/serde", + "sp-runtime/serde", +] diff --git a/substrate/primitives/consensus/sassafras/README.md b/substrate/primitives/consensus/sassafras/README.md new file mode 100644 index 00000000000..5024d1bf700 --- /dev/null +++ b/substrate/primitives/consensus/sassafras/README.md @@ -0,0 +1,12 @@ +Primitives for SASSAFRAS. + +# ⚠️ WARNING ⚠️ + +The crate interfaces and structures are highly experimental and may be subject +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. + +Tracking issue: https://github.com/paritytech/polkadot-sdk/issues/41 diff --git a/substrate/primitives/consensus/sassafras/src/digests.rs b/substrate/primitives/consensus/sassafras/src/digests.rs new file mode 100644 index 00000000000..95a305099de --- /dev/null +++ b/substrate/primitives/consensus/sassafras/src/digests.rs @@ -0,0 +1,98 @@ +// 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. + +//! Sassafras digests structures and helpers. + +use crate::{ + ticket::TicketClaim, vrf::VrfSignature, AuthorityId, AuthorityIndex, AuthoritySignature, + EpochConfiguration, Randomness, Slot, SASSAFRAS_ENGINE_ID, +}; + +use scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +use sp_runtime::{DigestItem, RuntimeDebug}; +use sp_std::vec::Vec; + +/// Epoch slot claim digest entry. +/// +/// This is mandatory for each block. +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct SlotClaim { + /// Authority index that claimed the slot. + pub authority_idx: AuthorityIndex, + /// Corresponding slot number. + pub slot: Slot, + /// Slot claim VRF signature. + pub vrf_signature: VrfSignature, + /// Ticket auxiliary information for claim check. + pub ticket_claim: Option, +} + +/// Information about the next epoch. +/// +/// This is mandatory in the first block of each epoch. +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +pub struct NextEpochDescriptor { + /// Authorities list. + pub authorities: Vec, + /// Epoch randomness. + pub randomness: Randomness, + /// Epoch configurable parameters. + /// + /// If not present previous epoch parameters are used. + pub config: Option, +} + +/// Runtime digest entries. +/// +/// Entries which may be generated by on-chain code. +#[derive(Decode, Encode, Clone, PartialEq, Eq)] +pub enum ConsensusLog { + /// Provides information about the next epoch parameters. + #[codec(index = 1)] + NextEpochData(NextEpochDescriptor), + /// Disable the authority with given index. + #[codec(index = 2)] + OnDisabled(AuthorityIndex), +} + +impl TryFrom<&DigestItem> for SlotClaim { + type Error = (); + fn try_from(item: &DigestItem) -> Result { + item.pre_runtime_try_to(&SASSAFRAS_ENGINE_ID).ok_or(()) + } +} + +impl From<&SlotClaim> for DigestItem { + fn from(claim: &SlotClaim) -> Self { + DigestItem::PreRuntime(SASSAFRAS_ENGINE_ID, claim.encode()) + } +} + +impl TryFrom<&DigestItem> for AuthoritySignature { + type Error = (); + fn try_from(item: &DigestItem) -> Result { + item.seal_try_to(&SASSAFRAS_ENGINE_ID).ok_or(()) + } +} + +impl From<&AuthoritySignature> for DigestItem { + fn from(signature: &AuthoritySignature) -> Self { + DigestItem::Seal(SASSAFRAS_ENGINE_ID, signature.encode()) + } +} diff --git a/substrate/primitives/consensus/sassafras/src/lib.rs b/substrate/primitives/consensus/sassafras/src/lib.rs new file mode 100644 index 00000000000..e421e771d40 --- /dev/null +++ b/substrate/primitives/consensus/sassafras/src/lib.rs @@ -0,0 +1,169 @@ +// 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. + +//! Primitives for Sassafras consensus. + +#![deny(warnings)] +#![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::crypto::KeyTypeId; +use sp_runtime::{ConsensusEngineId, RuntimeDebug}; +use sp_std::vec::Vec; + +pub use sp_consensus_slots::{Slot, SlotDuration}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +pub mod digests; +pub mod ticket; +pub mod vrf; + +pub use ticket::{ + ticket_id_threshold, EphemeralPublic, EphemeralSignature, TicketBody, TicketClaim, + TicketEnvelope, TicketId, +}; + +mod app { + use sp_application_crypto::{app_crypto, bandersnatch, key_types::SASSAFRAS}; + app_crypto!(bandersnatch, SASSAFRAS); +} + +/// Key type identifier. +pub const KEY_TYPE: KeyTypeId = sp_application_crypto::key_types::SASSAFRAS; + +/// Consensus engine identifier. +pub const SASSAFRAS_ENGINE_ID: ConsensusEngineId = *b"SASS"; + +/// VRF output length for per-slot randomness. +pub const RANDOMNESS_LENGTH: usize = 32; + +/// Index of an authority. +pub type AuthorityIndex = u32; + +/// Sassafras authority keypair. Necessarily equivalent to the schnorrkel public key used in +/// the main Sassafras module. If that ever changes, then this must, too. +#[cfg(feature = "std")] +pub type AuthorityPair = app::Pair; + +/// Sassafras authority signature. +pub type AuthoritySignature = app::Signature; + +/// Sassafras authority identifier. Necessarily equivalent to the schnorrkel public key used in +/// the main Sassafras module. If that ever changes, then this must, too. +pub type AuthorityId = app::Public; + +/// Weight of a Sassafras block. +/// Primary blocks have a weight of 1 whereas secondary blocks have a weight of 0. +pub type SassafrasBlockWeight = u32; + +/// An equivocation proof for multiple block authorships on the same slot (i.e. double vote). +pub type EquivocationProof = sp_consensus_slots::EquivocationProof; + +/// Randomness required by some protocol's operations. +pub type Randomness = [u8; RANDOMNESS_LENGTH]; + +/// Configuration data that can be modified on epoch change. +#[derive( + Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo, Default, +)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct EpochConfiguration { + /// Tickets threshold redundancy factor. + pub redundancy_factor: u32, + /// Tickets attempts for each validator. + pub attempts_number: u32, +} + +/// Sassafras epoch information +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] +pub struct Epoch { + /// The epoch index. + pub epoch_idx: u64, + /// The starting slot of the epoch. + pub start_slot: Slot, + /// Slot duration in milliseconds. + pub slot_duration: SlotDuration, + /// Duration of epoch in slots. + pub epoch_duration: u64, + /// Authorities for the epoch. + pub authorities: Vec, + /// Randomness for the epoch. + pub randomness: Randomness, + /// Epoch configuration. + pub config: EpochConfiguration, +} + +/// An opaque type used to represent the key ownership proof at the runtime API boundary. +/// +/// The inner value is an encoded representation of the actual key ownership proof which will be +/// parameterized when defining the runtime. At the runtime API boundary this type is unknown and +/// as such we keep this opaque representation, implementors of the runtime API will have to make +/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. +#[derive(Decode, Encode, PartialEq, TypeInfo)] +#[repr(transparent)] +pub struct OpaqueKeyOwnershipProof(Vec); + +// Runtime API. +sp_api::decl_runtime_apis! { + /// API necessary for block authorship with Sassafras. + pub trait SassafrasApi { + /// Get ring context to be used for ticket construction and verification. + fn ring_context() -> Option; + + /// Submit next epoch validator tickets via an unsigned extrinsic. + /// This method returns `false` when creation of the extrinsics fails. + fn submit_tickets_unsigned_extrinsic(tickets: Vec) -> bool; + + /// Get ticket id associated to the given slot. + fn slot_ticket_id(slot: Slot) -> Option; + + /// Get ticket id and data associated to the given slot. + fn slot_ticket(slot: Slot) -> Option<(TicketId, TicketBody)>; + + /// Current epoch information. + fn current_epoch() -> Epoch; + + /// Next epoch information. + fn next_epoch() -> Epoch; + + /// Generates a proof of key ownership for the given authority in the current epoch. + /// + /// An example usage of this module is coupled with the session historical module to prove + /// that a given authority key is tied to a given staking identity during a specific + /// session. + /// + /// Proofs of key ownership are necessary for submitting equivocation reports. + fn generate_key_ownership_proof(authority_id: AuthorityId) -> Option; + + /// Submits an unsigned extrinsic to report an equivocation. + /// + /// The caller must provide the equivocation proof and a key ownership proof (should be + /// obtained using `generate_key_ownership_proof`). The extrinsic will be unsigned and + /// should only be accepted for local authorship (not to be broadcast to the network). This + /// method returns `false` when creation of the extrinsic fails. + /// + /// Only useful in an offchain context. + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: EquivocationProof, + key_owner_proof: OpaqueKeyOwnershipProof, + ) -> bool; + } +} diff --git a/substrate/primitives/consensus/sassafras/src/ticket.rs b/substrate/primitives/consensus/sassafras/src/ticket.rs new file mode 100644 index 00000000000..d81770c96d9 --- /dev/null +++ b/substrate/primitives/consensus/sassafras/src/ticket.rs @@ -0,0 +1,91 @@ +// 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. + +//! Primitives related to tickets. + +use crate::vrf::RingVrfSignature; +use scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +pub use sp_core::ed25519::{Public as EphemeralPublic, Signature as EphemeralSignature}; + +/// Ticket identifier. +/// +/// Its value is the output of a VRF whose inputs cannot be controlled by the +/// ticket's creator (refer to [`crate::vrf::ticket_id_input`] parameters). +/// Because of this, it is also used as the ticket score to compare against +/// the epoch ticket's threshold to decide if the ticket is worth being considered +/// for slot assignment (refer to [`ticket_id_threshold`]). +pub type TicketId = u128; + +/// Ticket data persisted on-chain. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct TicketBody { + /// Attempt index. + pub attempt_idx: u32, + /// Ephemeral public key which gets erased when the ticket is claimed. + pub erased_public: EphemeralPublic, + /// Ephemeral public key which gets exposed when the ticket is claimed. + pub revealed_public: EphemeralPublic, +} + +/// Ticket ring vrf signature. +pub type TicketSignature = RingVrfSignature; + +/// Ticket envelope used on during submission. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct TicketEnvelope { + /// Ticket body. + pub body: TicketBody, + /// Ring signature. + pub signature: TicketSignature, +} + +/// Ticket claim information filled by the block author. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct TicketClaim { + /// Signature verified via `TicketBody::erased_public`. + pub erased_signature: EphemeralSignature, +} + +/// Computes ticket-id maximum allowed value for a given epoch. +/// +/// Only ticket identifiers below this threshold should be considered for slot +/// assignment. +/// +/// The value is computed as `TicketId::MAX*(redundancy*slots)/(attempts*validators)` +/// +/// Where: +/// - `redundancy`: redundancy factor; +/// - `slots`: number of slots in epoch; +/// - `attempts`: max number of tickets attempts per validator; +/// - `validators`: number of validators in epoch. +/// +/// If `attempts * validators = 0` then we return 0. +pub fn ticket_id_threshold( + redundancy: u32, + slots: u32, + attempts: u32, + validators: u32, +) -> TicketId { + let den = attempts as u64 * validators as u64; + let num = redundancy as u64 * slots as u64; + TicketId::max_value() + .checked_div(den.into()) + .unwrap_or_default() + .saturating_mul(num.into()) +} diff --git a/substrate/primitives/consensus/sassafras/src/vrf.rs b/substrate/primitives/consensus/sassafras/src/vrf.rs new file mode 100644 index 00000000000..d25a656f950 --- /dev/null +++ b/substrate/primitives/consensus/sassafras/src/vrf.rs @@ -0,0 +1,104 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utilities related to VRF input, output and signatures. + +use crate::{Randomness, TicketBody, TicketId}; +use scale_codec::Encode; +use sp_consensus_slots::Slot; +use sp_std::vec::Vec; + +pub use sp_core::bandersnatch::{ + ring_vrf::{RingContext, RingProver, RingVerifier, RingVrfSignature}, + vrf::{VrfInput, VrfOutput, VrfSignData, VrfSignature}, +}; + +fn vrf_input_from_data( + domain: &[u8], + data: impl IntoIterator>, +) -> VrfInput { + let buf = data.into_iter().fold(Vec::new(), |mut buf, item| { + let bytes = item.as_ref(); + buf.extend_from_slice(bytes); + let len = u8::try_from(bytes.len()).expect("private function with well known inputs; qed"); + buf.push(len); + buf + }); + VrfInput::new(domain, buf) +} + +/// VRF input to claim slot ownership during block production. +pub fn slot_claim_input(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfInput { + vrf_input_from_data( + b"sassafras-claim-v1.0", + [randomness.as_slice(), &slot.to_le_bytes(), &epoch.to_le_bytes()], + ) +} + +/// Signing-data to claim slot ownership during block production. +pub fn slot_claim_sign_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfSignData { + let input = slot_claim_input(randomness, slot, epoch); + VrfSignData::new_unchecked( + b"sassafras-slot-claim-transcript-v1.0", + Option::<&[u8]>::None, + Some(input), + ) +} + +/// VRF input to generate the ticket id. +pub fn ticket_id_input(randomness: &Randomness, attempt: u32, epoch: u64) -> VrfInput { + vrf_input_from_data( + b"sassafras-ticket-v1.0", + [randomness.as_slice(), &attempt.to_le_bytes(), &epoch.to_le_bytes()], + ) +} + +/// VRF input to generate the revealed key. +pub fn revealed_key_input(randomness: &Randomness, attempt: u32, epoch: u64) -> VrfInput { + vrf_input_from_data( + b"sassafras-revealed-v1.0", + [randomness.as_slice(), &attempt.to_le_bytes(), &epoch.to_le_bytes()], + ) +} + +/// Data to be signed via ring-vrf. +pub fn ticket_body_sign_data(ticket_body: &TicketBody, ticket_id_input: VrfInput) -> VrfSignData { + VrfSignData::new_unchecked( + b"sassafras-ticket-body-transcript-v1.0", + Some(ticket_body.encode().as_slice()), + Some(ticket_id_input), + ) +} + +/// Make ticket-id from the given VRF input and output. +/// +/// Input should have been obtained via [`ticket_id_input`]. +/// Output should have been obtained from the input directly using the vrf secret key +/// or from the vrf signature outputs. +pub fn make_ticket_id(input: &VrfInput, output: &VrfOutput) -> TicketId { + let bytes = output.make_bytes::<16>(b"ticket-id", input); + u128::from_le_bytes(bytes) +} + +/// Make revealed key seed from a given VRF input and ouput. +/// +/// Input should have been obtained via [`revealed_key_input`]. +/// Output should have been obtained from the input directly using the vrf secret key +/// or from the vrf signature outputs. +pub fn make_revealed_key_seed(input: &VrfInput, output: &VrfOutput) -> [u8; 32] { + output.make_bytes::<32>(b"revealed-seed", input) +} diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index c3ba7f41058..01f3538188a 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -18,7 +18,7 @@ //! VRFs backed by [Bandersnatch](https://neuromancer.sk/std/bls/Bandersnatch), //! an elliptic curve built over BLS12-381 scalar field. //! -//! The primitive can operate both as a traditional VRF or as an anonymized ring VRF. +//! The primitive can operate both as a regular VRF or as an anonymized Ring VRF. #[cfg(feature = "std")] use crate::crypto::Ss58Codec; @@ -31,7 +31,7 @@ use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretString use bandersnatch_vrfs::CanonicalSerialize; #[cfg(feature = "full_crypto")] use bandersnatch_vrfs::SecretKey; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime_interface::pass_by::PassByInner; @@ -42,7 +42,7 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band"); /// Context used to produce a plain signature without any VRF input/output. #[cfg(feature = "full_crypto")] -pub const SIGNING_CTX: &[u8] = b"SigningContext"; +pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext"; // Max ring domain size. const RING_DOMAIN_SIZE: usize = 1024; @@ -153,7 +153,8 @@ impl sp_std::fmt::Debug for Public { /// Bandersnatch signature. /// -/// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as `label`. +/// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript +/// `label`. #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)] pub struct Signature([u8; SIGNATURE_SERIALIZED_LEN]); @@ -238,7 +239,7 @@ impl TraitPair for Pair { /// Make a new key pair from secret seed material. /// - /// The slice must be 64 bytes long or it will return an error. + /// The slice must be 32 bytes long or it will return an error. fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != SEED_SERIALIZED_LEN { return Err(SecretStringError::InvalidSeedLength) @@ -272,7 +273,6 @@ impl TraitPair for Pair { Ok((Self::from_seed(&seed), Some(seed))) } - /// Get the public key. fn public(&self) -> Public { let public = self.secret.to_public(); let mut raw = [0; PUBLIC_SERIALIZED_LEN]; @@ -282,23 +282,25 @@ impl TraitPair for Pair { Public::unchecked_from(raw) } - /// Sign raw data. + /// Sign a message. + /// + /// In practice this produce a Schnorr signature of a transcript composed by + /// the constant label [`SIGNING_CTX`] and `data` without any additional data. + /// + /// See [`vrf::VrfSignData`] for additional details. fn sign(&self, data: &[u8]) -> Signature { let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data], None); self.vrf_sign(&data).signature } - /// Verify a signature on a message. - /// - /// Returns `true` if the signature is good. fn verify>(signature: &Signature, data: M, public: &Public) -> bool { let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data.as_ref()], None); let signature = - vrf::VrfSignature { signature: *signature, vrf_outputs: vrf::VrfIosVec::default() }; + vrf::VrfSignature { signature: *signature, outputs: vrf::VrfIosVec::default() }; public.vrf_verify(&data, &signature) } - /// Return a vector filled with seed raw data. + /// Return a vector filled with the seed (32 bytes). fn to_raw_vec(&self) -> Vec { self.seed().to_vec() } @@ -319,7 +321,8 @@ pub mod vrf { }; /// Max number of inputs/outputs which can be handled by the VRF signing procedures. - /// The number is quite arbitrary and fullfils the current usage of the primitive. + /// + /// The number is quite arbitrary and chosen to fulfill the use cases found so far. /// If required it can be extended in the future. pub const MAX_VRF_IOS: u32 = 3; @@ -328,7 +331,7 @@ pub mod vrf { /// Can contain at most [`MAX_VRF_IOS`] elements. pub type VrfIosVec = BoundedVec>; - /// VRF input to construct a [`VrfOutput`] instance and embeddable within [`VrfSignData`]. + /// VRF input to construct a [`VrfOutput`] instance and embeddable in [`VrfSignData`]. #[derive(Clone, Debug)] pub struct VrfInput(pub(super) bandersnatch_vrfs::VrfInput); @@ -342,7 +345,9 @@ pub mod vrf { /// VRF (pre)output derived from [`VrfInput`] using a [`VrfSecret`]. /// - /// This is used to produce an arbitrary number of verifiable *random* bytes. + /// This object is used to produce an arbitrary number of verifiable pseudo random + /// bytes and is often called pre-output to emphasize that this is not the actual + /// output of the VRF but an object capable of generating the output. #[derive(Clone, Debug, PartialEq, Eq)] pub struct VrfOutput(pub(super) bandersnatch_vrfs::VrfPreOut); @@ -379,92 +384,102 @@ pub mod vrf { } } - /// A *Fiat-Shamir* transcript and a sequence of [`VrfInput`]s ready to be signed. + /// Data to be signed via one of the two provided vrf flavors. + /// + /// The object contains a transcript and a sequence of [`VrfInput`]s ready to be signed. /// - /// The `transcript` will be used as messages for the *Fiat-Shamir* - /// transform part of the scheme. This data keeps the signature secure - /// but doesn't contribute to the actual VRF output. If unsure just give - /// it a unique label depending on the actual usage of the signing data. + /// The `transcript` summarizes a set of messages which are defining a particular + /// protocol by automating the Fiat-Shamir transform for challenge generation. + /// A good explaination of the topic can be found in Merlin [docs](https://merlin.cool/) /// - /// The `vrf_inputs` is a sequence of [`VrfInput`]s to be signed and which - /// are used to construct the [`VrfOutput`]s in the signature. + /// The `inputs` is a sequence of [`VrfInput`]s which, during the signing procedure, are + /// first transformed to [`VrfOutput`]s. Both inputs and outputs are then appended to + /// the transcript before signing the Fiat-Shamir transform result (the challenge). + /// + /// In practice, as a user, all these technical details can be easily ignored. + /// What is important to remember is: + /// - *Transcript* is an object defining the protocol and used to produce the signature. This + /// object doesn't influence the `VrfOutput`s values. + /// - *Vrf inputs* is some additional data which is used to produce *vrf outputs*. This data + /// will contribute to the signature as well. #[derive(Clone)] pub struct VrfSignData { /// VRF inputs to be signed. - pub vrf_inputs: VrfIosVec, - /// Associated Fiat-Shamir transcript. + pub inputs: VrfIosVec, + /// Associated protocol transcript. pub transcript: Transcript, } impl VrfSignData { /// Construct a new data to be signed. /// - /// The `transcript_data` is used to construct the *Fiat-Shamir* `Transcript`. - /// Fails if the `vrf_inputs` yields more elements than [`MAX_VRF_IOS`] + /// Fails if the `inputs` iterator yields more elements than [`MAX_VRF_IOS`] /// - /// Refer to the [`VrfSignData`] for more details about the usage of - /// `transcript_data` and `vrf_inputs` + /// Refer to [`VrfSignData`] for details about transcript and inputs. pub fn new( - label: &'static [u8], + transcript_label: &'static [u8], transcript_data: impl IntoIterator>, - vrf_inputs: impl IntoIterator, + inputs: impl IntoIterator, ) -> Result { - let vrf_inputs: Vec = vrf_inputs.into_iter().collect(); - if vrf_inputs.len() > MAX_VRF_IOS as usize { + let inputs: Vec = inputs.into_iter().collect(); + if inputs.len() > MAX_VRF_IOS as usize { return Err(()) } - Ok(Self::new_unchecked(label, transcript_data, vrf_inputs)) + Ok(Self::new_unchecked(transcript_label, transcript_data, inputs)) } /// Construct a new data to be signed. /// - /// The `transcript_data` is used to construct the *Fiat-Shamir* `Transcript`. - /// At most the first [`MAX_VRF_IOS`] elements of `vrf_inputs` are used. + /// At most the first [`MAX_VRF_IOS`] elements of `inputs` are used. /// - /// Refer to the [`VrfSignData`] for more details about the usage of - /// `transcript_data` and `vrf_inputs` + /// Refer to [`VrfSignData`] for details about transcript and inputs. pub fn new_unchecked( - label: &'static [u8], + transcript_label: &'static [u8], transcript_data: impl IntoIterator>, - vrf_inputs: impl IntoIterator, + inputs: impl IntoIterator, ) -> Self { - let vrf_inputs: Vec = vrf_inputs.into_iter().collect(); - let vrf_inputs = VrfIosVec::truncate_from(vrf_inputs); - let mut transcript = Transcript::new_labeled(label); - transcript_data - .into_iter() - .for_each(|data| transcript.append_slice(data.as_ref())); - VrfSignData { transcript, vrf_inputs } + let inputs: Vec = inputs.into_iter().collect(); + let inputs = VrfIosVec::truncate_from(inputs); + let mut transcript = Transcript::new_labeled(transcript_label); + transcript_data.into_iter().for_each(|data| transcript.append(data.as_ref())); + VrfSignData { transcript, inputs } } - /// Append a raw message to the transcript. + /// Append a message to the transcript. pub fn push_transcript_data(&mut self, data: &[u8]) { - self.transcript.append_slice(data); + self.transcript.append(data); } - /// Append a [`VrfInput`] to the vrf inputs to be signed. + /// Tries to append a [`VrfInput`] to the vrf inputs list. /// - /// On failure, gives back the [`VrfInput`] parameter. - pub fn push_vrf_input(&mut self, vrf_input: VrfInput) -> Result<(), VrfInput> { - self.vrf_inputs.try_push(vrf_input) + /// On failure, returns back the [`VrfInput`] parameter. + pub fn push_vrf_input(&mut self, input: VrfInput) -> Result<(), VrfInput> { + self.inputs.try_push(input) } - /// Create challenge from the transcript contained within the signing data. + /// Get the challenge associated to the `transcript` contained within the signing data. + /// + /// Ignores the vrf inputs and outputs. pub fn challenge(&self) -> [u8; N] { let mut output = [0; N]; let mut transcript = self.transcript.clone(); - let mut reader = transcript.challenge(b"Prehashed for bandersnatch"); + let mut reader = transcript.challenge(b"bandersnatch challenge"); reader.read_bytes(&mut output); output } } /// VRF signature. + /// + /// Includes both the transcript `signature` and the `outputs` generated from the + /// [`VrfSignData::inputs`]. + /// + /// Refer to [`VrfSignData`] for more details. #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct VrfSignature { /// VRF (pre)outputs. - pub vrf_outputs: VrfIosVec, - /// VRF signature. + pub outputs: VrfIosVec, + /// Transcript signature. pub signature: Signature, } @@ -481,7 +496,7 @@ pub mod vrf { fn vrf_sign(&self, data: &Self::VrfSignData) -> Self::VrfSignature { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); // Workaround to overcome backend signature generic over the number of IOs. - match data.vrf_inputs.len() { + match data.inputs.len() { 0 => self.vrf_sign_gen::<0>(data), 1 => self.vrf_sign_gen::<1>(data), 2 => self.vrf_sign_gen::<2>(data), @@ -506,12 +521,12 @@ pub mod vrf { impl VrfPublic for Public { fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - let preouts_len = signature.vrf_outputs.len(); - if preouts_len != data.vrf_inputs.len() { + let outputs_len = signature.outputs.len(); + if outputs_len != data.inputs.len() { return false } // Workaround to overcome backend signature generic over the number of IOs. - match preouts_len { + match outputs_len { 0 => self.vrf_verify_gen::<0>(data, signature), 1 => self.vrf_verify_gen::<1>(data, signature), 2 => self.vrf_verify_gen::<2>(data, signature), @@ -525,7 +540,7 @@ pub mod vrf { impl Pair { fn vrf_sign_gen(&self, data: &VrfSignData) -> VrfSignature { let ios: Vec<_> = data - .vrf_inputs + .inputs .iter() .map(|i| self.secret.clone().0.vrf_inout(i.0.clone())) .collect(); @@ -541,7 +556,7 @@ pub mod vrf { let outputs: Vec<_> = signature.preoutputs.into_iter().map(VrfOutput).collect(); let outputs = VrfIosVec::truncate_from(outputs); - VrfSignature { signature: Signature(sign_bytes), vrf_outputs: outputs } + VrfSignature { signature: Signature(sign_bytes), outputs } } /// Generate an arbitrary number of bytes from the given `context` and VRF `input`. @@ -567,7 +582,7 @@ pub mod vrf { }; let Ok(preouts) = signature - .vrf_outputs + .outputs .iter() .map(|o| o.0.clone()) .collect::>() @@ -587,7 +602,7 @@ pub mod vrf { }; let signature = ThinVrfSignature { signature, preoutputs: preouts }; - let inputs = data.vrf_inputs.iter().map(|i| i.0.clone()); + let inputs = data.inputs.iter().map(|i| i.0.clone()); signature.verify_thin_vrf(data.transcript.clone(), inputs, &public).is_ok() } @@ -675,6 +690,8 @@ pub mod ring_vrf { } } + impl EncodeLike for RingContext {} + impl MaxEncodedLen for RingContext { fn max_encoded_len() -> usize { <[u8; RING_CONTEXT_SERIALIZED_LEN]>::max_encoded_len() @@ -695,9 +712,9 @@ pub mod ring_vrf { /// VRF (pre)outputs. pub outputs: VrfIosVec, /// Pedersen VRF signature. - signature: [u8; PEDERSEN_SIGNATURE_SERIALIZED_LEN], + pub signature: [u8; PEDERSEN_SIGNATURE_SERIALIZED_LEN], /// Ring proof. - ring_proof: [u8; RING_PROOF_SERIALIZED_LEN], + pub ring_proof: [u8; RING_PROOF_SERIALIZED_LEN], } #[cfg(feature = "full_crypto")] @@ -710,7 +727,7 @@ pub mod ring_vrf { pub fn ring_vrf_sign(&self, data: &VrfSignData, prover: &RingProver) -> RingVrfSignature { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); // Workaround to overcome backend signature generic over the number of IOs. - match data.vrf_inputs.len() { + match data.inputs.len() { 0 => self.ring_vrf_sign_gen::<0>(data, prover), 1 => self.ring_vrf_sign_gen::<1>(data, prover), 2 => self.ring_vrf_sign_gen::<2>(data, prover), @@ -725,7 +742,7 @@ pub mod ring_vrf { prover: &RingProver, ) -> RingVrfSignature { let ios: Vec<_> = data - .vrf_inputs + .inputs .iter() .map(|i| self.secret.clone().0.vrf_inout(i.0.clone())) .collect(); @@ -760,7 +777,7 @@ pub mod ring_vrf { pub fn verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); let preouts_len = self.outputs.len(); - if preouts_len != data.vrf_inputs.len() { + if preouts_len != data.inputs.len() { return false } // Workaround to overcome backend signature generic over the number of IOs. @@ -798,7 +815,7 @@ pub mod ring_vrf { let ring_signature = bandersnatch_vrfs::RingVrfSignature { signature, preoutputs, ring_proof }; - let inputs = data.vrf_inputs.iter().map(|i| i.0.clone()); + let inputs = data.inputs.iter().map(|i| i.0.clone()); ring_signature .verify_ring_vrf(data.transcript.clone(), inputs, verifier) @@ -910,11 +927,11 @@ mod tests { let signature = pair.vrf_sign(&data); let o10 = pair.make_bytes::<32>(b"ctx1", &i1); - let o11 = signature.vrf_outputs[0].make_bytes::<32>(b"ctx1", &i1); + let o11 = signature.outputs[0].make_bytes::<32>(b"ctx1", &i1); assert_eq!(o10, o11); let o20 = pair.make_bytes::<48>(b"ctx2", &i2); - let o21 = signature.vrf_outputs[1].make_bytes::<48>(b"ctx2", &i2); + let o21 = signature.outputs[1].make_bytes::<48>(b"ctx2", &i2); assert_eq!(o20, o21); } @@ -932,8 +949,7 @@ mod tests { let bytes = expected.encode(); - let expected_len = - data.vrf_inputs.len() * PREOUT_SERIALIZED_LEN + SIGNATURE_SERIALIZED_LEN + 1; + let expected_len = data.inputs.len() * PREOUT_SERIALIZED_LEN + SIGNATURE_SERIALIZED_LEN + 1; assert_eq!(bytes.len(), expected_len); let decoded = VrfSignature::decode(&mut bytes.as_slice()).unwrap(); @@ -993,6 +1009,35 @@ mod tests { assert!(!signature.verify(&data, &verifier)); } + #[test] + fn ring_vrf_make_bytes_matches() { + let ring_ctx = RingContext::new_testing(); + + let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + assert!(pks.len() <= ring_ctx.max_keyset_size()); + + let pair = Pair::from_seed(DEV_SEED); + + // Just pick one index to patch with the actual public key + let prover_idx = 3; + pks[prover_idx] = pair.public(); + + let i1 = VrfInput::new(b"dom1", b"foo"); + let i2 = VrfInput::new(b"dom2", b"bar"); + let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]); + + let prover = ring_ctx.prover(&pks, prover_idx).unwrap(); + let signature = pair.ring_vrf_sign(&data, &prover); + + let o10 = pair.make_bytes::<32>(b"ctx1", &i1); + let o11 = signature.outputs[0].make_bytes::<32>(b"ctx1", &i1); + assert_eq!(o10, o11); + + let o20 = pair.make_bytes::<48>(b"ctx2", &i2); + let o21 = signature.outputs[1].make_bytes::<48>(b"ctx2", &i2); + assert_eq!(o20, o21); + } + #[test] fn encode_decode_ring_vrf_signature() { let ring_ctx = RingContext::new_testing(); @@ -1017,7 +1062,7 @@ mod tests { let bytes = expected.encode(); - let expected_len = data.vrf_inputs.len() * PREOUT_SERIALIZED_LEN + + let expected_len = data.inputs.len() * PREOUT_SERIALIZED_LEN + PEDERSEN_SIGNATURE_SERIALIZED_LEN + RING_PROOF_SERIALIZED_LEN + 1; diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 6afe4b752a6..8c7d98f00cd 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1136,6 +1136,8 @@ pub mod key_types { /// Key type for Babe module, built-in. Identified as `babe`. pub const BABE: KeyTypeId = KeyTypeId(*b"babe"); + /// Key type for Sassafras module, built-in. Identified as `sass`. + pub const SASSAFRAS: KeyTypeId = KeyTypeId(*b"sass"); /// Key type for Grandpa module, built-in. Identified as `gran`. pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran"); /// Key type for controlling an account in a Substrate runtime, built-in. Identified as `acco`. diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 82062fe7b40..035af7099a6 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -17,6 +17,7 @@ //! Keystore traits +#[cfg(feature = "std")] pub mod testing; #[cfg(feature = "bandersnatch-experimental")] @@ -631,3 +632,15 @@ impl KeystoreExt { Self(Arc::new(keystore)) } } + +sp_core::generate_feature_enabled_macro!( + bandersnatch_experimental_enabled, + feature = "bandersnatch-experimental", + $ +); + +sp_core::generate_feature_enabled_macro!( + bls_experimental_enabled, + feature = "bls-experimental", + $ +); -- GitLab From aedd28087421e47e26cf6d4721efdbb0b28f25a2 Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 31 Aug 2023 17:13:09 +0200 Subject: [PATCH 042/633] Fix polkadot-node-core-pvf-prepare-worker build with jemalloc (#1315) * Fix polkadot-node-core-pvf-prepare-worker build with jemalloc The jemalloc feature on polkadot-node-core-pvf-prepare-worker depended on some feature gated code in polkadot-node-core-pvf-common but there way no way to enable this feature gate. This commit adds the feature and makes prepare-worker enable it. * More jemalloc-allocator fixes * Fix jemalloc-allocator feature dep * Run `zepter format features` --------- Co-authored-by: Marcin S --- Cargo.lock | 1 - polkadot/Cargo.toml | 7 ++++++- polkadot/node/core/pvf/Cargo.toml | 1 + polkadot/node/core/pvf/common/Cargo.toml | 1 + polkadot/node/core/pvf/execute-worker/Cargo.toml | 4 ---- polkadot/node/core/pvf/prepare-worker/Cargo.toml | 5 ++++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e0e47f955a..5ffb73c9c67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12183,7 +12183,6 @@ dependencies = [ "sp-core", "sp-maybe-compressed-blob", "sp-tracing", - "tikv-jemalloc-ctl", "tokio", "tracing-gum", ] diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index e3cfda9bd46..f173557a0ff 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -22,7 +22,7 @@ version = "1.0.0" [dependencies] color-eyre = { version = "0.6.1", default-features = false } -tikv-jemallocator = "0.5.0" +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 = [ @@ -38,6 +38,9 @@ polkadot-overseer = { path = "node/overseer" } polkadot-node-core-pvf-common = { path = "node/core/pvf/common" } polkadot-node-core-pvf-execute-worker = { path = "node/core/pvf/execute-worker" } +[target.'cfg(target_os = "linux")'.dependencies] +tikv-jemallocator = "0.5.0" + [dev-dependencies] assert_cmd = "2.0.4" nix = { version = "0.26.1", features = ["signal"] } @@ -59,7 +62,9 @@ fast-runtime = [ "polkadot-cli/fast-runtime" ] runtime-metrics = [ "polkadot-cli/runtime-metrics" ] pyroscope = [ "polkadot-cli/pyroscope" ] jemalloc-allocator = [ + "dep:tikv-jemallocator", "polkadot-node-core-pvf-prepare-worker/jemalloc-allocator", + "polkadot-node-core-pvf/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator", ] diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index a10b748e882..f28d00d2690 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -54,6 +54,7 @@ halt = { package = "test-parachain-halt", path = "../../../parachain/test-parach [features] ci-only-tests = [] +jemalloc-allocator = [ "polkadot-node-core-pvf-common/jemalloc-allocator" ] # This feature is used to export test code to other crates without putting it in the production build. # This is also used by the `puppet_worker` binary. test-utils = [ diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index ded8f0dc63b..620e2148623 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -38,3 +38,4 @@ tempfile = "3.3.0" # This feature is used to export test code to other crates without putting it in the production build. # Also used for building the puppet worker. test-utils = [] +jemalloc-allocator = [] diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 5ef7c8e8e87..a9619015594 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -11,7 +11,6 @@ cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } rayon = "1.5.1" -tikv-jemalloc-ctl = { version = "0.5.0", optional = true } tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -24,8 +23,5 @@ sp-core = { path = "../../../../../substrate/primitives/core" } sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } sp-tracing = { path = "../../../../../substrate/primitives/tracing" } -[target.'cfg(target_os = "linux")'.dependencies] -tikv-jemalloc-ctl = "0.5.0" - [features] builder = [] diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index dfa87e4d240..61d197af07a 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -32,4 +32,7 @@ tikv-jemalloc-ctl = "0.5.0" [features] builder = [] -jemalloc-allocator = [ "dep:tikv-jemalloc-ctl" ] +jemalloc-allocator = [ + "dep:tikv-jemalloc-ctl", + "polkadot-node-core-pvf-common/jemalloc-allocator", +] -- GitLab From 995d81fd8460186ac4e60566b65a026f8a7173aa Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Thu, 31 Aug 2023 13:42:32 -0300 Subject: [PATCH 043/633] Add environmental variable to track decoded instructions (#1320) * Add environmental variable to track decoded instructions * Fix doc tests * Fix manifest formatting * ".git/.scripts/commands/fmt/fmt.sh" * Add one more test * Add SetAppendix in test --------- Co-authored-by: command-bot <> --- Cargo.lock | 1 + polkadot/xcm/Cargo.toml | 2 + polkadot/xcm/src/lib.rs | 3 +- polkadot/xcm/src/v2/multilocation.rs | 12 ++-- polkadot/xcm/src/v2/traits.rs | 2 +- polkadot/xcm/src/v3/junctions.rs | 4 +- polkadot/xcm/src/v3/mod.rs | 61 ++++++++++++++----- polkadot/xcm/src/v3/multilocation.rs | 10 +-- polkadot/xcm/src/v3/traits.rs | 4 +- .../xcm/xcm-builder/src/currency_adapter.rs | 2 +- polkadot/xcm/xcm-builder/src/matcher.rs | 2 +- polkadot/xcm/xcm-builder/src/matches_token.rs | 4 +- polkadot/xcm/xcm-executor/src/assets.rs | 2 +- .../xcm/xcm-executor/src/traits/conversion.rs | 2 +- 14 files changed, 72 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ffb73c9c67..9ea938e9caa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17910,6 +17910,7 @@ version = "1.0.0" dependencies = [ "bounded-collections", "derivative", + "environmental", "hex", "hex-literal 0.4.1", "impl-trait-for-tuples", diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 3c9fd026717..f04f31c3ec1 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -16,6 +16,7 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } xcm-procedural = { path = "procedural" } +environmental = { version = "1.1.4", default-features = false } [dev-dependencies] sp-io = { path = "../../substrate/primitives/io" } @@ -27,6 +28,7 @@ default = [ "std" ] wasm-api = [] std = [ "bounded-collections/std", + "environmental/std", "parity-scale-codec/std", "scale-info/std", "serde/std", diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 52f32f7310b..d3e2baf4f8a 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -20,7 +20,8 @@ // necessarily related to FRAME or even Substrate. // // Hence, `no_std` rather than sp-runtime. -#![no_std] +#![cfg_attr(not(feature = "std"), no_std)] + extern crate alloc; use derivative::Derivative; diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs index 9fb74e8afb3..4a65a419045 100644 --- a/polkadot/xcm/src/v2/multilocation.rs +++ b/polkadot/xcm/src/v2/multilocation.rs @@ -238,7 +238,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); /// assert_eq!( @@ -260,7 +260,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; /// let m = MultiLocation::new(1, X3(PalletInstance(3), OnlyChild, OnlyChild)); /// assert!(m.starts_with(&MultiLocation::new(1, X1(PalletInstance(3))))); /// assert!(!m.starts_with(&MultiLocation::new(1, X1(GeneralIndex(99))))); @@ -279,7 +279,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { /// let mut m = MultiLocation::new(1, X1(Parachain(21))); /// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(())); @@ -302,7 +302,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { /// let mut m = MultiLocation::new(2, X1(PalletInstance(3))); /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild))), Ok(())); @@ -839,7 +839,7 @@ impl Junctions { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*}; /// # fn main() { /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); @@ -857,7 +857,7 @@ impl Junctions { /// /// # Example /// ```rust - /// # use xcm::v2::{Junctions::*, Junction::*}; + /// # use staging_xcm::v2::{Junctions::*, Junction::*}; /// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild); /// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3)))); /// assert!(j.starts_with(&j)); diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs index 80603b4100d..8173beb19d8 100644 --- a/polkadot/xcm/src/v2/traits.rs +++ b/polkadot/xcm/src/v2/traits.rs @@ -278,7 +278,7 @@ pub type SendResult = result::Result<(), SendError>; /// /// # Example /// ```rust -/// # use xcm::v2::prelude::*; +/// # use staging_xcm::v2::prelude::*; /// # use parity_scale_codec::Encode; /// /// /// A sender that only passes the message through and does nothing. diff --git a/polkadot/xcm/src/v3/junctions.rs b/polkadot/xcm/src/v3/junctions.rs index 201a80fb765..c2826c4969e 100644 --- a/polkadot/xcm/src/v3/junctions.rs +++ b/polkadot/xcm/src/v3/junctions.rs @@ -437,7 +437,7 @@ impl Junctions { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { /// let mut m = X1(Parachain(21)); /// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(())); @@ -568,7 +568,7 @@ impl Junctions { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*}; /// # fn main() { /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 78ea7a58aba..a428f1277a5 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -22,7 +22,7 @@ use super::v2::{ }; use crate::DoubleEncoded; use alloc::{vec, vec::Vec}; -use bounded_collections::{parameter_types, BoundedVec, ConstU32}; +use bounded_collections::{parameter_types, BoundedVec}; use core::{ convert::{TryFrom, TryInto}, fmt::Debug, @@ -30,7 +30,8 @@ use core::{ }; use derivative::Derivative; use parity_scale_codec::{ - self, Decode, Encode, Error as CodecError, Input as CodecInput, MaxEncodedLen, + self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, + MaxEncodedLen, }; use scale_info::TypeInfo; @@ -69,13 +70,25 @@ pub type QueryId = u64; #[scale_info(bounds(), skip_type_params(Call))] pub struct Xcm(pub Vec>); -const MAX_INSTRUCTIONS_TO_DECODE: u32 = 100; +const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; + +environmental::environmental!(instructions_count: u8); impl Decode for Xcm { fn decode(input: &mut I) -> core::result::Result { - let bounded_instructions = - BoundedVec::, ConstU32>::decode(input)?; - Ok(Self(bounded_instructions.into_inner())) + instructions_count::using_once(&mut 0, || { + let number_of_instructions: u32 = >::decode(input)?.into(); + instructions_count::with(|count| { + *count = count.saturating_add(number_of_instructions as u8); + if *count > MAX_INSTRUCTIONS_TO_DECODE { + return Err(CodecError::from("Max instructions exceeded")) + } + Ok(()) + }) + .unwrap_or(Ok(()))?; + let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?; + Ok(Self(decoded_instructions)) + }) } } @@ -1441,15 +1454,31 @@ mod tests { } #[test] - fn decoding_fails_when_too_many_instructions() { - let small_xcm = Xcm::<()>(vec![ClearOrigin; 20]); - let bytes = small_xcm.encode(); - let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); - assert!(matches!(decoded_xcm, Ok(_))); - - let big_xcm = Xcm::<()>(vec![ClearOrigin; 64_000]); - let bytes = big_xcm.encode(); - let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); - assert!(matches!(decoded_xcm, Err(CodecError { .. }))); + fn decoding_respects_limit() { + let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]); + let encoded = max_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); + + let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]); + let encoded = big_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let nested_xcm = Xcm::<()>(vec![ + DepositReserveAsset { + assets: All.into(), + dest: Here.into(), + xcm: max_xcm, + }; + (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize + ]); + let encoded = nested_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); + let encoded = even_more_nested_xcm.encode(); + assert_eq!(encoded.len(), 342530); + // This should not decode since the limit is 100 + assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition"); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); } } diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 07f829d014c..7ac377d5c06 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -265,7 +265,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); /// assert_eq!( @@ -292,7 +292,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; /// # fn main() { /// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into(); /// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(())); @@ -313,7 +313,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; /// # fn main() { /// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into(); /// let r = m.appended_with((Parent, PalletInstance(3))).unwrap(); @@ -333,7 +333,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; /// # fn main() { /// let mut m: MultiLocation = (Parent, Parent, PalletInstance(3)).into(); /// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(())); @@ -382,7 +382,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; + /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; /// # fn main() { /// let m: MultiLocation = (Parent, Parent, PalletInstance(3)).into(); /// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap(); diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index 128be42c2a2..a3cbeada91b 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -449,8 +449,8 @@ pub type SendResult = result::Result<(T, MultiAssets), SendError>; /// # Example /// ```rust /// # use parity_scale_codec::Encode; -/// # use xcm::v3::{prelude::*, Weight}; -/// # use xcm::VersionedXcm; +/// # use staging_xcm::v3::{prelude::*, Weight}; +/// # use staging_xcm::VersionedXcm; /// # use std::convert::Infallible; /// /// /// A sender that only passes the message through and does nothing. diff --git a/polkadot/xcm/xcm-builder/src/currency_adapter.rs b/polkadot/xcm/xcm-builder/src/currency_adapter.rs index 4dbd4fe8bcd..23dc7958fe1 100644 --- a/polkadot/xcm/xcm-builder/src/currency_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/currency_adapter.rs @@ -53,7 +53,7 @@ impl From for XcmError { /// use frame_support::{parameter_types, PalletId}; /// use sp_runtime::traits::{AccountIdConversion, TrailingZeroInput}; /// use xcm::latest::prelude::*; -/// use xcm_builder::{ParentIsPreset, CurrencyAdapter, IsConcrete}; +/// use staging_xcm_builder::{ParentIsPreset, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. /// type AccountId = sp_runtime::AccountId32; diff --git a/polkadot/xcm/xcm-builder/src/matcher.rs b/polkadot/xcm/xcm-builder/src/matcher.rs index 4a3c896a159..9da135dae31 100644 --- a/polkadot/xcm/xcm-builder/src/matcher.rs +++ b/polkadot/xcm/xcm-builder/src/matcher.rs @@ -50,7 +50,7 @@ impl<'a, Call> CreateMatcher for &'a mut [Instruction] { /// ```rust /// use frame_support::traits::ProcessMessageError; /// use xcm::latest::Instruction; -/// use xcm_builder::{CreateMatcher, MatchXcm}; +/// use staging_xcm_builder::{CreateMatcher, MatchXcm}; /// /// let mut msg = [Instruction::<()>::ClearOrigin]; /// let res = msg diff --git a/polkadot/xcm/xcm-builder/src/matches_token.rs b/polkadot/xcm/xcm-builder/src/matches_token.rs index ddb25799be6..b6a320d8931 100644 --- a/polkadot/xcm/xcm-builder/src/matches_token.rs +++ b/polkadot/xcm/xcm-builder/src/matches_token.rs @@ -33,7 +33,7 @@ use xcm_executor::traits::{MatchesFungible, MatchesNonFungible}; /// /// ``` /// use xcm::latest::{MultiLocation, Parent}; -/// use xcm_builder::IsConcrete; +/// use staging_xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { @@ -71,7 +71,7 @@ impl, I: TryFrom> MatchesNonFungible for /// /// ``` /// use xcm::latest::prelude::*; -/// use xcm_builder::IsAbstract; +/// use staging_xcm_builder::IsAbstract; /// use xcm_executor::traits::{MatchesFungible, MatchesNonFungible}; /// /// frame_support::parameter_types! { diff --git a/polkadot/xcm/xcm-executor/src/assets.rs b/polkadot/xcm/xcm-executor/src/assets.rs index d8d8936df33..33f2ff218c7 100644 --- a/polkadot/xcm/xcm-executor/src/assets.rs +++ b/polkadot/xcm/xcm-executor/src/assets.rs @@ -446,7 +446,7 @@ impl Assets { /// Example: /// /// ``` - /// use xcm_executor::Assets; + /// use staging_xcm_executor::Assets; /// use xcm::latest::prelude::*; /// let assets_i_have: Assets = vec![ (Here, 100).into(), ([0; 32], 100).into() ].into(); /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), ([0; 32], 50).into() ].into(); diff --git a/polkadot/xcm/xcm-executor/src/traits/conversion.rs b/polkadot/xcm/xcm-executor/src/traits/conversion.rs index dac099ffaf8..1fcdf214057 100644 --- a/polkadot/xcm/xcm-executor/src/traits/conversion.rs +++ b/polkadot/xcm/xcm-executor/src/traits/conversion.rs @@ -46,7 +46,7 @@ impl ConvertLocation for Tuple { /// /// ```rust /// # use xcm::latest::{MultiLocation, Junctions, Junction, OriginKind}; -/// # use xcm_executor::traits::ConvertOrigin; +/// # use staging_xcm_executor::traits::ConvertOrigin; /// // A convertor that will bump the para id and pass it to the next one. /// struct BumpParaId; /// impl ConvertOrigin for BumpParaId { -- GitLab From ea5792508e8482dc1d5d4d529daa328c3d7ec71d Mon Sep 17 00:00:00 2001 From: Kevin Krone Date: Thu, 31 Aug 2023 19:45:14 +0200 Subject: [PATCH 044/633] Add README to project root (#1253) * Added root README.md draft * Modified Contribution section to reflect unified guidelines * Update README.md Co-authored-by: Squirrel * Expand Substrate description * Added Badges and Upstream deps * Fixed badge links * Fixed CONTRIBUTING.md links, added security and resources section to root README.md * Moved runtimes link to Polkadot section --------- Co-authored-by: Squirrel Co-authored-by: Oliver Tale-Yazdi --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++ docs/CONTRIBUTING.md | 6 ++--- 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000000..a0ef1818279 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +> NOTE: We have recently made significant changes to our repository structure. In order to +streamline our development process and foster better contributions, we have merged three separate +repositories Cumulus, Substrate and Polkadot into this repository. Read more about the changes [ +here](https://polkadot-public.notion.site/Polkadot-SDK-FAQ-fbc4cecc2c46443fb37b9eeec2f0d85f). + +# Polkadot SDK + +![](https://cms.polkadot.network/content/images/2021/06/1-xPcVR_fkITd0ssKBvJ3GMw.png) + +[![StackExchange](https://img.shields.io/badge/StackExchange-Community%20&%20Support-222222?logo=stackexchange)](https://substrate.stackexchange.com/) + +The Polkadot SDK repository provides all the resources needed to start building on the Polkadot +network, a multi-chain blockchain platform that enables different blockchains to interoperate and +share information in a secure and scalable way. The Polkadot SDK comprises three main pieces of +software: + +## [Polkadot](./polkadot/) +[![PolkadotForum](https://img.shields.io/badge/Polkadot_Forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) [![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](./polkadot/LICENSE) + +Implementation of a node for the https://polkadot.network in Rust, using the Substrate framework. +This directory currently contains runtimes for the Polkadot, Kusama, Westend, and Rococo networks. +In the future, these will be relocated to the [`runtimes`](https://github.com/polkadot-fellows/runtimes/) repository. + +## [Substrate](./substrate/) + [![SubstrateRustDocs](https://img.shields.io/badge/Rust_Docs-Substrate-24CC85?logo=rust)](https://paritytech.github.io/substrate/master/substrate/index.html) [![Substrate-license](https://img.shields.io/badge/License-GPL3%2FApache2.0-blue)](./substrate/README.md#LICENSE) + +Substrate is the primary blockchain SDK used by developers to create the parachains that make up +the Polkadot network. Additionally, it allows for the development of self-sovereign blockchains +that operate completely independently of Polkadot. + +## [Cumulus](./cumulus/) +[![CumulusRustDocs](https://img.shields.io/badge/Rust_Docs-Cumulus-222222?logo=rust)](https://paritytech.github.io/cumulus/cumulus_client_collator/index.html) [![Cumulus-license](https://img.shields.io/badge/License-GPL3-blue)](./cumulus/LICENSE) + +Cumulus is a set of tools for writing Substrate-based Polkadot parachains. + +## Upstream Dependencies + +Below are the primary upstream dependencies utilized in this project: + +- [parity-scale-codec](https://crates.io/crates/parity-scale-codec) +- [parity-db](https://crates.io/crates/parity-db) +- [parity-common](https://github.com/paritytech/parity-common) +- [trie](https://github.com/paritytech/trie) + +## Security + +The security policy and procedures can be found in [docs/SECURITY.md](./docs/SECURITY.md). + +## Contributing & Code of Conduct + +Ensure you follow our [contribution guidelines](./docs/CONTRIBUTING.md). In every interaction and contribution, this project adheres to the [Contributor Covenant Code of Conduct](./docs/CODE_OF_CONDUCT.md). + +## Additional Resources + +- For monitoring upcoming changes and current proposals related to the technical implementation of the Polkadot network, visit the [`Requests for Comment (RFC)`](https://github.com/polkadot-fellows/RFCs) repository. While it's maintained by the Polkadot Fellowship, the RFC process welcomes contributions from everyone. + diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index a4632c1a1ea..5e892625fb7 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -96,9 +96,9 @@ d) that the docs team was included in the review process of a docs update We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate state of a PR. Please familiarise yourself with them. Best way to get started is to a pick a ticket tagged -`[easy](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD0-easy)` -or `[medium](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD1-medium)` -and get going or `[mentor](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AC1-mentor)` +[easy](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD0-easy) +or [medium](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD1-medium) +and get going. Alternatively, look out for issues tagged [mentor](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AC1-mentor) and get in contact with the mentor offering their support on that larger task. **** -- GitLab From a33d7922f8f0f6a4887b5638f2bc09f578b6e2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 31 Aug 2023 23:53:29 +0200 Subject: [PATCH 045/633] Rename `polkadot-parachain` to `polkadot-parachain-primitives` (#1334) * Rename `polkadot-parachain` to `polkadot-parachain-primitives` While doing this it also fixes some last `rustdoc` issues and fixes another Cargo warning related to `pallet-paged-list`. * Fix compilation * ".git/.scripts/commands/fmt/fmt.sh" * Fix XCM docs --------- Co-authored-by: command-bot <> --- Cargo.lock | 122 +++++++++--------- .../polkadot-core/src/parachains.rs | 5 +- cumulus/client/network/Cargo.toml | 2 +- cumulus/client/network/src/lib.rs | 2 +- cumulus/client/network/src/tests.rs | 8 +- cumulus/pallets/parachain-system/Cargo.toml | 6 +- .../parachain-system/proc-macro/src/lib.rs | 2 +- cumulus/pallets/parachain-system/src/lib.rs | 4 +- .../src/validate_block/implementation.rs | 4 +- .../src/validate_block/mod.rs | 11 +- cumulus/parachain-template/runtime/Cargo.toml | 6 +- .../runtime/src/xcm_config.rs | 2 +- .../assets/asset-hub-kusama/Cargo.toml | 2 +- .../assets/asset-hub-kusama/src/lib.rs | 2 +- .../assets/asset-hub-polkadot/Cargo.toml | 2 +- .../assets/asset-hub-polkadot/src/lib.rs | 2 +- .../assets/asset-hub-westend/Cargo.toml | 2 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 2 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../collectives-polkadot/Cargo.toml | 2 +- .../collectives-polkadot/src/lib.rs | 2 +- .../emulated/common/Cargo.toml | 4 +- .../emulated/common/src/constants.rs | 2 +- .../emulated/common/src/lib.rs | 2 +- .../assets/asset-hub-kusama/Cargo.toml | 6 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 2 +- .../assets/asset-hub-polkadot/Cargo.toml | 6 +- .../asset-hub-polkadot/src/xcm_config.rs | 2 +- .../assets/asset-hub-westend/Cargo.toml | 6 +- .../asset-hub-westend/src/xcm_config.rs | 2 +- .../runtimes/assets/test-utils/Cargo.toml | 4 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 6 +- .../bridge-hub-kusama/src/xcm_config.rs | 2 +- .../bridge-hub-polkadot/Cargo.toml | 6 +- .../bridge-hub-polkadot/src/xcm_config.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 +- .../bridge-hub-rococo/src/xcm_config.rs | 2 +- .../collectives-polkadot/Cargo.toml | 6 +- .../collectives-polkadot/src/xcm_config.rs | 2 +- .../contracts/contracts-rococo/Cargo.toml | 6 +- .../contracts-rococo/src/xcm_config.rs | 2 +- .../parachains/runtimes/test-utils/Cargo.toml | 4 +- .../parachains/runtimes/test-utils/src/lib.rs | 2 +- .../runtimes/testing/penpal/Cargo.toml | 6 +- .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- .../testing/rococo-parachain/Cargo.toml | 6 +- .../testing/rococo-parachain/src/lib.rs | 2 +- cumulus/primitives/core/Cargo.toml | 4 +- cumulus/primitives/core/src/lib.rs | 4 +- cumulus/test/client/Cargo.toml | 2 +- cumulus/test/client/src/lib.rs | 4 +- cumulus/xcm/xcm-emulator/src/lib.rs | 2 +- .../node/core/candidate-validation/Cargo.toml | 2 +- .../node/core/candidate-validation/src/lib.rs | 9 +- polkadot/node/core/pvf/Cargo.toml | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- polkadot/node/core/pvf/common/src/execute.rs | 2 +- polkadot/node/core/pvf/common/src/pvf.rs | 2 +- .../node/core/pvf/execute-worker/Cargo.toml | 2 +- .../node/core/pvf/execute-worker/src/lib.rs | 2 +- .../node/core/pvf/prepare-worker/Cargo.toml | 2 +- polkadot/node/core/pvf/src/artifacts.rs | 2 +- polkadot/node/core/pvf/src/error.rs | 2 +- .../node/core/pvf/src/execute/worker_intf.rs | 2 +- polkadot/node/core/pvf/src/host.rs | 2 +- polkadot/node/core/pvf/src/lib.rs | 6 +- polkadot/node/core/pvf/tests/it/adder.rs | 2 +- polkadot/node/core/pvf/tests/it/main.rs | 2 +- .../network/approval-distribution/src/lib.rs | 4 +- .../network/dispute-distribution/src/lib.rs | 4 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/primitives/src/lib.rs | 4 +- polkadot/node/service/Cargo.toml | 4 +- .../node/subsystem-test-helpers/src/lib.rs | 2 +- polkadot/node/test/service/Cargo.toml | 4 +- polkadot/parachain/Cargo.toml | 2 +- .../test-parachains/adder/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../test-parachains/adder/collator/src/lib.rs | 2 +- .../test-parachains/undying/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- .../undying/collator/src/lib.rs | 2 +- polkadot/primitives/Cargo.toml | 6 +- polkadot/primitives/src/runtime_api.rs | 2 +- polkadot/primitives/src/v5/mod.rs | 2 +- .../implementers-guide/src/types/README.md | 12 +- polkadot/runtime/parachains/Cargo.toml | 6 +- .../runtime/parachains/src/configuration.rs | 4 +- polkadot/runtime/parachains/src/hrmp.rs | 2 +- polkadot/runtime/rococo/Cargo.toml | 6 +- polkadot/runtime/test-runtime/Cargo.toml | 6 +- polkadot/runtime/westend/Cargo.toml | 6 +- polkadot/xcm/pallet-xcm/Cargo.toml | 4 +- polkadot/xcm/pallet-xcm/src/mock.rs | 2 +- polkadot/xcm/pallet-xcm/src/tests.rs | 2 +- polkadot/xcm/src/v2/multilocation.rs | 8 -- polkadot/xcm/src/v3/junctions.rs | 4 - polkadot/xcm/src/v3/multilocation.rs | 10 -- polkadot/xcm/xcm-builder/Cargo.toml | 6 +- polkadot/xcm/xcm-builder/src/barriers.rs | 2 +- .../xcm/xcm-builder/src/origin_conversion.rs | 2 +- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 2 +- polkadot/xcm/xcm-builder/tests/scenarios.rs | 2 +- polkadot/xcm/xcm-simulator/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 4 +- .../xcm-simulator/example/src/parachain.rs | 2 +- .../xcm-simulator/example/src/relay_chain.rs | 2 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 4 +- polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs | 2 +- .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 2 +- .../xcm-simulator/fuzzer/src/relay_chain.rs | 2 +- polkadot/xcm/xcm-simulator/src/lib.rs | 2 +- substrate/frame/paged-list/fuzzer/Cargo.toml | 2 +- 114 files changed, 249 insertions(+), 260 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ea938e9caa..c99790ba28b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,7 +710,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", "sp-core", @@ -770,7 +770,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "primitive-types", "scale-info", @@ -810,7 +810,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", "sp-core", @@ -866,7 +866,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", "scale-info", @@ -909,7 +909,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", "sp-core", @@ -967,7 +967,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "primitive-types", "scale-info", @@ -1015,7 +1015,7 @@ dependencies = [ "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "sp-consensus-aura", "sp-core", "sp-io", @@ -1865,7 +1865,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", "serde", @@ -1927,7 +1927,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", "scale-info", @@ -1969,7 +1969,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", "sp-core", @@ -2033,7 +2033,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "rococo-runtime-constants", "scale-info", @@ -2597,7 +2597,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", "sp-core", @@ -2653,7 +2653,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", "scale-info", @@ -2864,7 +2864,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", "smallvec", @@ -3442,7 +3442,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-test-client", "portpicker", @@ -3577,7 +3577,7 @@ dependencies = [ "lazy_static", "log", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "sc-client-api", "scale-info", "sp-core", @@ -3706,7 +3706,7 @@ version = "0.1.0" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "scale-info", "sp-api", @@ -3896,7 +3896,7 @@ dependencies = [ "pallet-balances", "pallet-transaction-payment", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "sc-block-builder", "sc-consensus", @@ -6462,7 +6462,7 @@ dependencies = [ "paste", "penpal-runtime", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime", "polkadot-runtime-constants", @@ -10828,7 +10828,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", "serde", @@ -10989,7 +10989,7 @@ dependencies = [ "pallet-xcm", "parachain-info", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", "smallvec", @@ -11061,7 +11061,7 @@ dependencies = [ "parachain-info", "parachains-common", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "sp-consensus-aura", "sp-core", "sp-io", @@ -11314,7 +11314,7 @@ dependencies = [ "parachain-info", "parachains-common", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "scale-info", @@ -11949,7 +11949,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", "sp-core", @@ -12106,7 +12106,7 @@ dependencies = [ "polkadot-node-core-pvf-prepare-worker", "polkadot-node-metrics", "polkadot-node-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "rand 0.8.5", "slotmap", @@ -12155,7 +12155,7 @@ dependencies = [ "landlock", "libc", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "sc-executor", "sc-executor-common", @@ -12177,7 +12177,7 @@ dependencies = [ "futures", "parity-scale-codec", "polkadot-node-core-pvf-common", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "rayon", "sp-core", @@ -12195,7 +12195,7 @@ dependencies = [ "libc", "parity-scale-codec", "polkadot-node-core-pvf-common", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "rayon", "sc-executor", @@ -12305,7 +12305,7 @@ dependencies = [ "futures", "parity-scale-codec", "polkadot-erasure-coding", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "schnorrkel 0.9.1", "serde", @@ -12436,22 +12436,6 @@ dependencies = [ "tracing-gum", ] -[[package]] -name = "polkadot-parachain" -version = "1.0.0" -dependencies = [ - "bounded-collections", - "derive_more", - "frame-support", - "parity-scale-codec", - "polkadot-core-primitives", - "scale-info", - "serde", - "sp-core", - "sp-runtime", - "sp-std", -] - [[package]] name = "polkadot-parachain-bin" version = "1.0.0" @@ -12535,6 +12519,22 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "polkadot-parachain-primitives" +version = "1.0.0" +dependencies = [ + "bounded-collections", + "derive_more", + "frame-support", + "parity-scale-codec", + "polkadot-core-primitives", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "polkadot-performance-test" version = "1.0.0" @@ -12560,7 +12560,7 @@ dependencies = [ "hex-literal 0.4.1", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "scale-info", "serde", "sp-api", @@ -12825,7 +12825,7 @@ dependencies = [ "pallet-timestamp", "pallet-vesting", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-metrics", @@ -12912,7 +12912,7 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-rpc", "polkadot-runtime", @@ -13115,7 +13115,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -13164,7 +13164,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-rpc", "polkadot-runtime-common", @@ -14138,7 +14138,7 @@ dependencies = [ "parachain-info", "parachains-common", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "scale-info", "sp-api", "sp-block-builder", @@ -14212,7 +14212,7 @@ dependencies = [ "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -17938,7 +17938,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-xcm", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-parachains", "polkadot-test-runtime", @@ -18580,7 +18580,7 @@ version = "1.0.0" dependencies = [ "dlmalloc", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "sp-io", "sp-std", "substrate-wasm-builder", @@ -18600,7 +18600,7 @@ dependencies = [ "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-service", "polkadot-test-service", @@ -18629,7 +18629,7 @@ dependencies = [ "dlmalloc", "log", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "sp-io", "sp-std", "substrate-wasm-builder", @@ -18649,7 +18649,7 @@ dependencies = [ "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-service", "polkadot-test-service", @@ -20463,7 +20463,7 @@ dependencies = [ "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -20927,7 +20927,7 @@ dependencies = [ "parity-scale-codec", "paste", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-parachains", "sp-io", "sp-std", @@ -20949,7 +20949,7 @@ dependencies = [ "pallet-xcm", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", "sp-core", @@ -20976,7 +20976,7 @@ dependencies = [ "pallet-xcm", "parity-scale-codec", "polkadot-core-primitives", - "polkadot-parachain", + "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", "sp-core", diff --git a/cumulus/bridges/primitives/polkadot-core/src/parachains.rs b/cumulus/bridges/primitives/polkadot-core/src/parachains.rs index 3cf8eca0c6b..223956171f8 100644 --- a/cumulus/bridges/primitives/polkadot-core/src/parachains.rs +++ b/cumulus/bridges/primitives/polkadot-core/src/parachains.rs @@ -37,7 +37,8 @@ use parity_util_mem::MallocSizeOf; /// Parachain id. /// -/// This is an equivalent of the `polkadot_parachain::Id`, which is a compact-encoded `u32`. +/// This is an equivalent of the `polkadot_parachain_primitives::Id`, which is a compact-encoded +/// `u32`. #[derive( Clone, CompactAs, @@ -64,7 +65,7 @@ impl From for ParaId { /// Parachain head. /// -/// This is an equivalent of the `polkadot_parachain::HeadData`. +/// This is an equivalent of the `polkadot_parachain_primitives::HeadData`. /// /// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header. #[derive( diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 99a567a950c..eaaf497ac3e 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -23,7 +23,7 @@ sp-state-machine = { path = "../../../substrate/primitives/state-machine" } # Polkadot polkadot-node-primitives = { path = "../../../polkadot/node/primitives" } -polkadot-parachain = { path = "../../../polkadot/parachain" } +polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } polkadot-primitives = { path = "../../../polkadot/primitives" } # Cumulus diff --git a/cumulus/client/network/src/lib.rs b/cumulus/client/network/src/lib.rs index 1c70b823411..ebd557b805c 100644 --- a/cumulus/client/network/src/lib.rs +++ b/cumulus/client/network/src/lib.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_node_primitives::{CollationSecondedSignal, Statement}; -use polkadot_parachain::primitives::HeadData; +use polkadot_parachain_primitives::primitives::HeadData; use polkadot_primitives::{ CandidateReceipt, CompactStatement, Hash as PHash, Id as ParaId, OccupiedCoreAssumption, SigningContext, UncheckedSigned, diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index af7747622ef..e03f470753b 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -125,8 +125,10 @@ impl RelayChainInterface for DummyRelayChainInterface { if self.data.lock().has_pending_availability { Ok(Some(CommittedCandidateReceipt { descriptor: CandidateDescriptor { - para_head: polkadot_parachain::primitives::HeadData(default_header().encode()) - .hash(), + para_head: polkadot_parachain_primitives::primitives::HeadData( + default_header().encode(), + ) + .hash(), para_id: 0u32.into(), relay_parent: PHash::random(), collator: CollatorPair::generate().0.public(), @@ -315,7 +317,7 @@ async fn make_gossip_message_and_header( pov_hash: PHash::random(), erasure_root: PHash::random(), signature: sp_core::sr25519::Signature([0u8; 64]).into(), - para_head: polkadot_parachain::primitives::HeadData(header.encode()).hash(), + para_head: polkadot_parachain_primitives::primitives::HeadData(header.encode()).hash(), validation_code_hash: ValidationCodeHash::from(PHash::random()), }, }; diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index b72a7924be5..3063083c0ee 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -28,7 +28,7 @@ sp-trie = { path = "../../../substrate/primitives/trie", default-features = fals sp-version = { path = "../../../substrate/primitives/version", default-features = false} # Polkadot -polkadot-parachain = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} +polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} # Cumulus @@ -62,7 +62,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "scale-info/std", "sp-core/std", "sp-externalities/std", @@ -79,7 +79,7 @@ std = [ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs index ece9348f43e..8ab5d81efdc 100644 --- a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs +++ b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs @@ -142,7 +142,7 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To #check_inherents, >(params); - #crate_::validate_block::polkadot_parachain::write_result(&res) + #crate_::validate_block::polkadot_parachain_primitives::write_result(&res) } } } diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 0ab2abb1881..a8e9a0bf9ae 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -44,7 +44,7 @@ use frame_support::{ weights::Weight, }; use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor}; -use polkadot_parachain::primitives::RelayChainBlockNumber; +use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; use scale_info::TypeInfo; use sp_runtime::{ traits::{Block as BlockT, BlockNumberProvider, Hash}, @@ -1429,7 +1429,7 @@ impl Pallet { pub fn initialize_for_set_code_benchmark(max_code_size: u32) { // insert dummy ValidationData let vfp = PersistedValidationData { - parent_head: polkadot_parachain::primitives::HeadData(Default::default()), + parent_head: polkadot_parachain_primitives::primitives::HeadData(Default::default()), relay_parent_number: 1, relay_parent_storage_root: Default::default(), max_pov_size: 1_000, diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index 8001b4cc8ac..ce3b724420f 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -22,7 +22,9 @@ use cumulus_primitives_core::{ }; use cumulus_primitives_parachain_inherent::ParachainInherentData; -use polkadot_parachain::primitives::{HeadData, RelayChainBlockNumber, ValidationResult}; +use polkadot_parachain_primitives::primitives::{ + HeadData, RelayChainBlockNumber, ValidationResult, +}; use codec::Encode; diff --git a/cumulus/pallets/parachain-system/src/validate_block/mod.rs b/cumulus/pallets/parachain-system/src/validate_block/mod.rs index ab8ea43ec7c..db149401638 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/mod.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/mod.rs @@ -34,7 +34,7 @@ pub use bytes; pub use codec::decode_from_bytes; #[cfg(not(feature = "std"))] #[doc(hidden)] -pub use polkadot_parachain; +pub use polkadot_parachain_primitives; #[cfg(not(feature = "std"))] #[doc(hidden)] pub use sp_runtime::traits::GetRuntimeBlockType; @@ -42,15 +42,16 @@ pub use sp_runtime::traits::GetRuntimeBlockType; #[doc(hidden)] pub use sp_std; -/// Basically the same as [`ValidationParams`](polkadot_parachain::primitives::ValidationParams), -/// but a little bit optimized for our use case here. +/// Basically the same as +/// [`ValidationParams`](polkadot_parachain_primitives::primitives::ValidationParams), but a little +/// bit optimized for our use case here. /// /// `block_data` and `head_data` are represented as [`bytes::Bytes`] to make them reuse /// the memory of the input parameter of the exported `validate_blocks` function. /// /// The layout of this type must match exactly the layout of -/// [`ValidationParams`](polkadot_parachain::primitives::ValidationParams) to have the same -/// SCALE encoding. +/// [`ValidationParams`](polkadot_parachain_primitives::primitives::ValidationParams) to have the +/// same SCALE encoding. #[derive(codec::Decode)] #[cfg_attr(feature = "std", derive(codec::Encode))] #[doc(hidden)] diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 0a7801c99bc..f26b7be2353 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -54,7 +54,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features # Polkadot pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain = { path = "../../../polkadot/parachain", 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} @@ -104,7 +104,7 @@ std = [ "pallet-transaction-payment/std", "pallet-xcm/std", "parachain-info/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", "sp-api/std", @@ -139,7 +139,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index ff996d4dde3..353f68d22e3 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -9,7 +9,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; use xcm::latest::prelude::*; use xcm_builder::{ diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 78d6b0925bb..b179c646784 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -22,7 +22,7 @@ pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conv # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../../polkadot/parachain", 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} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs index d16d8548ba4..696e0a5cf76 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -42,7 +42,7 @@ pub use integration_tests_common::{ }; pub use parachains_common::Balance; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, 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 index 0d415f8d74f..4a0ca2e243a 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -20,7 +20,7 @@ pallet-assets = { path = "../../../../../../substrate/frame/assets", default-fea # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../../polkadot/parachain", 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} 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 index 44004813f18..176e3def1f2 100644 --- 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 @@ -40,7 +40,7 @@ pub use integration_tests_common::{ }; pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, 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 847ab2fa9f8..64522e309a2 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 @@ -22,7 +22,7 @@ pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conv # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../../polkadot/parachain", 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} 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 f09fed97b8f..b7eba63df10 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 @@ -39,7 +39,7 @@ pub use integration_tests_common::{ }; pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, 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 4a4bdeb9b1f..7b909562f15 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 @@ -20,7 +20,7 @@ pallet-assets = { path = "../../../../../../substrate/frame/assets", default-fea # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../../polkadot/parachain", 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} 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 4689c076b51..52c17122c57 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 @@ -43,7 +43,7 @@ pub use integration_tests_common::{ }; pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index d23c511a706..0882dd9d408 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -22,7 +22,7 @@ pallet-salary = { path = "../../../../../../substrate/frame/salary", default-fea # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../../polkadot/parachain", 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} 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 index 9fbee683fed..aae8ab2111e 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -40,7 +40,7 @@ pub use integration_tests_common::{ }; pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 97a5868adc6..382826873eb 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -30,7 +30,7 @@ beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../subs # Polkadot polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} 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" } @@ -90,7 +90,7 @@ runtime-benchmarks = [ "pallet-staking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "polkadot-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 569436f06a0..b32d86d3b07 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -18,7 +18,7 @@ use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; -use polkadot_parachain::primitives::{HeadData, ValidationCode}; +use polkadot_parachain_primitives::primitives::{HeadData, ValidationCode}; use polkadot_primitives::{AssignmentId, ValidatorId}; use polkadot_runtime_parachains::{ configuration::HostConfiguration, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 6201b0ef719..a5d80cafd7f 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ pub use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; pub use parachains_common::{AccountId, Balance}; pub use paste; -use polkadot_parachain::primitives::HrmpChannelId; +use polkadot_parachain_primitives::primitives::HrmpChannelId; use polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::ParachainHostV6; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use sp_core::{sr25519, storage::Storage, Get}; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 1eca60a81e5..53555499842 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -59,7 +59,7 @@ kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/cons 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 = { path = "../../../../../polkadot/parachain", 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} @@ -118,7 +118,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", @@ -200,7 +200,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", "sp-api/std", 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 7a28840adcb..0c197598f88 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 @@ -32,7 +32,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index 813a0a33c2a..dfc3d5416cc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -53,7 +53,7 @@ sp-weights = { path = "../../../../../substrate/primitives/weights", default-fea 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 = { path = "../../../../../polkadot/parachain", 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} @@ -105,7 +105,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", @@ -180,7 +180,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "polkadot-runtime-constants/std", "scale-info/std", 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 05110b65622..d59507e4bd0 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 @@ -28,7 +28,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 14f1e541091..8c25842cbf3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -56,7 +56,7 @@ primitive-types = { version = "0.12.1", default-features = false, features = ["c 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 = { path = "../../../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} @@ -110,7 +110,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", @@ -189,7 +189,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", "sp-api/std", 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 121f9753193..6981c290c98 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 @@ -32,7 +32,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 332a3f8a7f1..7fee710f000 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -38,7 +38,7 @@ parachains-runtimes-test-utils = { path = "../../test-utils", default-features = xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} [dev-dependencies] hex-literal = "0.4.1" @@ -66,7 +66,7 @@ std = [ "parachain-info/std", "parachains-common/std", "parachains-runtimes-test-utils/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "sp-consensus-aura/std", "sp-core/std", "sp-io/std", 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 b1695f4abcd..91eb7adc61f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -52,7 +52,7 @@ kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/cons 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 = { path = "../../../../../polkadot/parachain", 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} @@ -110,7 +110,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", "serde", @@ -148,7 +148,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", 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 4e295be542e..696462be9c4 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 @@ -25,7 +25,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, 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 1dfa84f338f..52a866b7097 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -52,7 +52,7 @@ polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/ pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", 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} @@ -109,7 +109,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "polkadot-runtime-constants/std", "scale-info/std", @@ -148,7 +148,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", 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 d4b97ce2d29..0965600c246 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 @@ -25,7 +25,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, 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 93fc1d82430..d65fb9b72cd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -52,7 +52,7 @@ rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/cons 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 = { path = "../../../../../polkadot/parachain", 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} @@ -144,7 +144,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "rococo-runtime-constants/std", "scale-info/std", @@ -188,7 +188,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", 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 ddba163df59..e3d8645d49e 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 @@ -31,7 +31,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use sp_core::Get; use xcm::latest::prelude::*; use xcm_builder::{ diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index be9c0fc9952..1f17a0ef0e6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -55,7 +55,7 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", 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} @@ -106,7 +106,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", @@ -186,7 +186,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "polkadot-runtime-constants/std", "scale-info/std", 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 98a3710e42a..b4db73e3ab4 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -25,7 +25,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index ea24392657f..2e298e05ec7 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -55,7 +55,7 @@ pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts 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 = { path = "../../../../../polkadot/parachain", 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} @@ -113,7 +113,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", "sp-api/std", @@ -151,7 +151,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", 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 8040ff74935..7433b8e94d6 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -24,7 +24,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 76be24b6118..681e5e64d41 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -38,7 +38,7 @@ parachain-info = { path = "../../pallets/parachain-info", default-features = fal xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain = { path = "../../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../../polkadot/parachain", default-features = false} [dev-dependencies] hex-literal = "0.4.1" @@ -65,7 +65,7 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "sp-consensus-aura/std", "sp-core/std", "sp-io/std", diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 89bc7c4906e..8289a80baa1 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -29,7 +29,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor}; use parachains_common::{AccountId, SLOT_DURATION}; -use polkadot_parachain::primitives::{ +use polkadot_parachain_primitives::primitives::{ HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat, }; use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID}; diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 711d2542f12..99caf2f27d0 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -56,7 +56,7 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", 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} @@ -109,7 +109,7 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-primitives/std", "polkadot-runtime-common/std", "scale-info/std", @@ -147,7 +147,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 694f9c1ade3..97d2e63370e 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -39,7 +39,7 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_asset_tx_payment::HandleCredit; use pallet_xcm::XcmPassthrough; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; use sp_runtime::traits::Zero; use xcm::latest::prelude::*; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 43f25d72e33..863b9edd725 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -37,7 +37,7 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain = { path = "../../../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", 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} @@ -84,7 +84,7 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", @@ -113,7 +113,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 084372589d9..362ad0383a2 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -76,7 +76,7 @@ use xcm_executor::traits::JustTry; // XCM imports use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; -use polkadot_parachain::primitives::Sibling; +use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 761ca04d152..fc7573be138 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -16,7 +16,7 @@ sp-trie = { path = "../../../substrate/primitives/trie", default-features = fals # Polkadot polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false} -polkadot-parachain = { path = "../../../polkadot/parachain", default-features = false} +polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false} polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} @@ -25,7 +25,7 @@ default = [ "std" ] std = [ "codec/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-primitives/std", "scale-info/std", "sp-api/std", diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index d697713f39a..faaef09b26e 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -19,13 +19,13 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use polkadot_parachain::primitives::HeadData; +use polkadot_parachain_primitives::primitives::HeadData; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain::primitives::{ +pub use polkadot_parachain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat, XcmpMessageHandler, }; diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 4e07be3368e..290cfd7e4d8 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -29,7 +29,7 @@ pallet-balances = { path = "../../../substrate/frame/balances" } # Polkadot polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-parachain = { path = "../../../polkadot/parachain" } +polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } # Cumulus cumulus-test-runtime = { path = "../runtime" } diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index f59aa09e666..61249bdb066 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -31,7 +31,9 @@ use sp_runtime::{generic::Era, BuildStorage, SaturatedConversion}; pub use block_builder::*; pub use cumulus_test_runtime as runtime; -pub use polkadot_parachain::primitives::{BlockData, HeadData, ValidationParams, ValidationResult}; +pub use polkadot_parachain_primitives::primitives::{ + BlockData, HeadData, ValidationParams, ValidationResult, +}; pub use sc_executor::error::Result as ExecutorResult; pub use substrate_test_client::*; diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index b882e7a9f0b..79fe496f26b 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -973,7 +973,7 @@ macro_rules! decl_test_networks { fn process_downward_messages() { use $crate::{DmpMessageHandler, Bounded}; - use polkadot_parachain::primitives::RelayChainBlockNumber; + use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; while let Some((to_para_id, messages)) = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 3935c91d897..a2e88778532 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -16,7 +16,7 @@ sp-maybe-compressed-blob = { package = "sp-maybe-compressed-blob", path = "../.. parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } polkadot-primitives = { path = "../../../primitives" } -polkadot-parachain = { path = "../../../parachain" } +polkadot-parachain-primitives = { path = "../../../parachain" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index f53f2a6aee0..0da2853340d 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -40,7 +40,9 @@ use polkadot_node_subsystem::{ SubsystemSender, }; use polkadot_node_subsystem_util::executor_params_at_relay_parent; -use polkadot_parachain::primitives::{ValidationParams, ValidationResult as WasmValidationResult}; +use polkadot_parachain_primitives::primitives::{ + ValidationParams, ValidationResult as WasmValidationResult, +}; use polkadot_primitives::{ CandidateCommitments, CandidateDescriptor, CandidateReceipt, ExecutorParams, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfExecTimeoutKind, PvfPrepTimeoutKind, @@ -111,10 +113,7 @@ pub struct CandidateValidationSubsystem { } impl CandidateValidationSubsystem { - /// Create a new `CandidateValidationSubsystem` with the given task spawner and isolation - /// strategy. - /// - /// Check out [`IsolationStrategy`] to get more details. + /// Create a new `CandidateValidationSubsystem`. pub fn with_config( config: Option, metrics: Metrics, diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index f28d00d2690..a265139d95c 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -25,7 +25,7 @@ tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -polkadot-parachain = { path = "../../../parachain" } +polkadot-parachain-primitives = { path = "../../../parachain" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-node-core-pvf-common = { path = "common" } polkadot-node-metrics = { path = "../../metrics" } diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 620e2148623..621f7e24f72 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -15,7 +15,7 @@ tokio = { version = "1.24.2", features = ["fs", "process", "io-util"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -polkadot-parachain = { path = "../../../../parachain" } +polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } sc-executor = { path = "../../../../../substrate/client/executor" } diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index de5ce39f783..399b847791a 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -16,7 +16,7 @@ use crate::error::InternalValidationError; use parity_scale_codec::{Decode, Encode}; -use polkadot_parachain::primitives::ValidationResult; +use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::ExecutorParams; use std::time::Duration; diff --git a/polkadot/node/core/pvf/common/src/pvf.rs b/polkadot/node/core/pvf/common/src/pvf.rs index e31264713a5..0cc86434c19 100644 --- a/polkadot/node/core/pvf/common/src/pvf.rs +++ b/polkadot/node/core/pvf/common/src/pvf.rs @@ -16,7 +16,7 @@ use crate::prepare::PrepareJobKind; use parity_scale_codec::{Decode, Encode}; -use polkadot_parachain::primitives::ValidationCodeHash; +use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParams; use sp_core::blake2_256; use std::{ diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index a9619015594..23678d95696 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -16,7 +16,7 @@ tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } polkadot-node-core-pvf-common = { path = "../common" } -polkadot-parachain = { path = "../../../../parachain" } +polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } sp-core = { path = "../../../../../substrate/primitives/core" } diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 7a14de18a82..36793a5c71e 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -37,7 +37,7 @@ use polkadot_node_core_pvf_common::{ worker_event_loop, }, }; -use polkadot_parachain::primitives::ValidationResult; +use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ path::PathBuf, sync::{mpsc::channel, Arc}, diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 61d197af07a..e7a12cd9a80 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } polkadot-node-core-pvf-common = { path = "../common" } -polkadot-parachain = { path = "../../../../parachain" } +polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } sc-executor = { path = "../../../../../substrate/client/executor" } diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index a180af15db2..dc5921df968 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -58,7 +58,7 @@ use crate::host::PrepareResultSender; use always_assert::always; use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; -use polkadot_parachain::primitives::ValidationCodeHash; +use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParamsHash; use std::{ collections::HashMap, diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index cb35ec9e9d9..87ef0b54a04 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -28,7 +28,7 @@ pub enum ValidationError { } /// A description of an error raised during executing a PVF and can be attributed to the combination -/// of the candidate [`polkadot_parachain::primitives::ValidationParams`] and the PVF. +/// of the candidate [`polkadot_parachain_primitives::primitives::ValidationParams`] and the PVF. #[derive(Debug, Clone)] pub enum InvalidCandidate { /// PVF preparation ended up with a deterministic error. diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index 948abd2261d..d66444a8102 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -32,7 +32,7 @@ use polkadot_node_core_pvf_common::{ execute::{Handshake, Response}, framed_recv, framed_send, }; -use polkadot_parachain::primitives::ValidationResult; +use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::ExecutorParams; use std::{path::Path, time::Duration}; use tokio::{io, net::UnixStream}; diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 9f3b7e23fd8..5290b2760f4 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -35,7 +35,7 @@ use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, pvf::PvfPrepData, }; -use polkadot_parachain::primitives::ValidationResult; +use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ collections::HashMap, path::{Path, PathBuf}, diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 1da0593835f..c3a7a461313 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -33,8 +33,8 @@ //! compile) in order to pre-check its validity. //! //! (b) PVF execution. This accepts the PVF -//! [`params`][`polkadot_parachain::primitives::ValidationParams`] and the `Pvf` code, prepares -//! (verifies and compiles) the code, and then executes PVF with the `params`. +//! [`params`][`polkadot_parachain_primitives::primitives::ValidationParams`] and the `Pvf` +//! code, prepares (verifies and compiles) the code, and then executes PVF with the `params`. //! //! (c) Heads up. This request allows to signal that the given PVF may be needed soon and that it //! should be prepared for execution. @@ -86,7 +86,7 @@ //! //! The execute workers will be fed by the requests from the execution queue, which is basically a //! combination of a path to the compiled artifact and the -//! [`params`][`polkadot_parachain::primitives::ValidationParams`]. +//! [`params`][`polkadot_parachain_primitives::primitives::ValidationParams`]. mod artifacts; mod error; diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index a4c2e21bdea..bad7a66054c 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -17,7 +17,7 @@ use super::TestHost; use adder::{hash_state, BlockData, HeadData}; use parity_scale_codec::{Decode, Encode}; -use polkadot_parachain::primitives::{ +use polkadot_parachain_primitives::primitives::{ BlockData as GenericBlockData, HeadData as GenericHeadData, RelayChainBlockNumber, ValidationParams, }; diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 72c459c2f63..8574bc16c5d 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -21,7 +21,7 @@ use polkadot_node_core_pvf::{ start, Config, InvalidCandidate, Metrics, PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; -use polkadot_parachain::primitives::{BlockData, ValidationParams, ValidationResult}; +use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::ExecutorParams; #[cfg(feature = "ci-only-tests")] diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index ac525ea6faf..70c20437d12 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! [`ApprovalDistributionSubsystem`] implementation. +//! [`ApprovalDistribution`] implementation. //! -//! https://w3f.github.io/parachain-implementers-guide/node/approval/approval-distribution.html +//! #![warn(missing_docs)] diff --git a/polkadot/node/network/dispute-distribution/src/lib.rs b/polkadot/node/network/dispute-distribution/src/lib.rs index 071dc3c3343..2b4466fc2fc 100644 --- a/polkadot/node/network/dispute-distribution/src/lib.rs +++ b/polkadot/node/network/dispute-distribution/src/lib.rs @@ -21,8 +21,8 @@ //! - a sender //! - and a receiver //! -//! The sender is responsible for getting our vote out, see [`sender`]. The receiver handles -//! incoming [`DisputeRequest`]s and offers spam protection, see [`receiver`]. +//! The sender is responsible for getting our vote out, see `sender`. The receiver handles +//! incoming [`DisputeRequest`](v1::DisputeRequest)s and offers spam protection, see `receiver`. use std::time::Duration; diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index e7101c875e7..ef03c02f7bc 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -17,7 +17,7 @@ sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } sp-runtime = { path = "../../../substrate/primitives/runtime" } -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", default-features = false } schnorrkel = "0.9.1" thiserror = "1.0.31" serde = { version = "1.0.188", features = ["derive"] } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index b1e56394796..463c7f960ba 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -39,7 +39,9 @@ pub use sp_consensus_babe::{ AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch, }; -pub use polkadot_parachain::primitives::{BlockData, HorizontalMessages, UpwardMessages}; +pub use polkadot_parachain_primitives::primitives::{ + BlockData, HorizontalMessages, UpwardMessages, +}; pub mod approval; diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 6a8c09821be..90881aa051a 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -94,7 +94,7 @@ is_executable = "1.0.1" polkadot-core-primitives = { path = "../../core-primitives" } polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" } polkadot-overseer = { path = "../overseer" } -polkadot-parachain = { path = "../../parachain" } +polkadot-parachain-primitives = { path = "../../parachain" } polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } polkadot-rpc = { path = "../../rpc" } @@ -200,7 +200,7 @@ runtime-benchmarks = [ "pallet-babe/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs index 339b99a4b5a..6f0c3016c7a 100644 --- a/polkadot/node/subsystem-test-helpers/src/lib.rs +++ b/polkadot/node/subsystem-test-helpers/src/lib.rs @@ -338,7 +338,7 @@ pub fn subsystem_test_harness( }); } -/// A forward subsystem that implements [`Subsystem`]. +/// A forward subsystem that implements [`Subsystem`](overseer::Subsystem). /// /// It forwards all communication from the overseer to the internal message /// channel. diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 2c8f0649669..d730a601d5a 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -17,7 +17,7 @@ tokio = "1.24.2" # Polkadot dependencies polkadot-overseer = { path = "../../overseer" } polkadot-primitives = { path = "../../../primitives" } -polkadot-parachain = { path = "../../../parachain" } +polkadot-parachain-primitives = { path = "../../../parachain" } polkadot-rpc = { path = "../../../rpc" } polkadot-runtime-common = { path = "../../../runtime/common" } polkadot-service = { path = "../../service" } @@ -68,7 +68,7 @@ runtime-benchmarks= [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 86db6cb9bab..c44ba02e3ae 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "polkadot-parachain" +name = "polkadot-parachain-primitives" description = "Types and utilities for creating and working with parachains" authors.workspace = true edition.workspace = true diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index 49e10dbd492..f22b5ccfdcc 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -9,7 +9,7 @@ authors.workspace = true publish = false [dependencies] -parachain = { package = "polkadot-parachain", path = "../..", default-features = false, features = [ "wasm-api" ] } +parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = [ "wasm-api" ] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 1a013fa0b1e..a570788e9e8 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -39,7 +39,7 @@ sc-service = { path = "../../../../../substrate/client/service" } polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] -polkadot-parachain = { path = "../../.." } +polkadot-parachain-primitives = { path = "../../.." } polkadot-test-service = { path = "../../../../node/test/service" } substrate-test-utils = { path = "../../../../../substrate/test-utils" } diff --git a/polkadot/parachain/test-parachains/adder/collator/src/lib.rs b/polkadot/parachain/test-parachains/adder/collator/src/lib.rs index 1ac561dda2b..5f62ae34cae 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/lib.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/lib.rs @@ -249,7 +249,7 @@ mod tests { use super::*; use futures::executor::block_on; - use polkadot_parachain::primitives::{ValidationParams, ValidationResult}; + use polkadot_parachain_primitives::primitives::{ValidationParams, ValidationResult}; use polkadot_primitives::PersistedValidationData; #[test] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 2766fb4e8a6..8690da5a4bd 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -9,7 +9,7 @@ edition.workspace = true license.workspace = true [dependencies] -parachain = { package = "polkadot-parachain", path = "../..", default-features = false, features = [ "wasm-api" ] } +parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = [ "wasm-api" ] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 2cb44fd25a6..781e4e3134f 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -39,7 +39,7 @@ sc-service = { path = "../../../../../substrate/client/service" } polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] -polkadot-parachain = { path = "../../.." } +polkadot-parachain-primitives = { path = "../../.." } polkadot-test-service = { path = "../../../../node/test/service" } # For the puppet worker, depend on ourselves with the test-utils feature. test-parachain-undying-collator = { path = "", features = ["test-utils"] } diff --git a/polkadot/parachain/test-parachains/undying/collator/src/lib.rs b/polkadot/parachain/test-parachains/undying/collator/src/lib.rs index e0ecc6b0997..3c869233182 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/lib.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/lib.rs @@ -338,7 +338,7 @@ use sp_core::traits::SpawnNamed; mod tests { use super::*; use futures::executor::block_on; - use polkadot_parachain::primitives::{ValidationParams, ValidationResult}; + use polkadot_parachain_primitives::primitives::{ValidationParams, ValidationResult}; use polkadot_primitives::{Hash, PersistedValidationData}; #[test] diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index c29159d18f9..9d17b70b817 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -26,7 +26,7 @@ sp-staking = { path = "../../substrate/primitives/staking", default-features = f sp-std = { package = "sp-std", path = "../../substrate/primitives/std", default-features = false } polkadot-core-primitives = { path = "../core-primitives", default-features = false } -polkadot-parachain = { path = "../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../parachain", default-features = false } [features] default = [ "std" ] @@ -36,7 +36,7 @@ std = [ "inherents/std", "parity-scale-codec/std", "polkadot-core-primitives/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "primitives/std", "runtime_primitives/std", "scale-info/std", @@ -51,7 +51,7 @@ std = [ "sp-std/std", ] runtime-benchmarks = [ - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "runtime_primitives/runtime-benchmarks", "sp-staking/runtime-benchmarks", ] diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 86aca6c9bc6..e5f1aa4276e 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -121,7 +121,7 @@ use crate::{ }; use parity_scale_codec::{Decode, Encode}; use polkadot_core_primitives as pcp; -use polkadot_parachain::primitives as ppp; +use polkadot_parachain_primitives::primitives as ppp; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; sp_api::decl_runtime_apis! { diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v5/mod.rs index a41bfcdef84..eed4cc2b36b 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v5/mod.rs @@ -42,7 +42,7 @@ pub use polkadot_core_primitives::v2::{ }; // Export some polkadot-parachain primitives -pub use polkadot_parachain::primitives::{ +pub use polkadot_parachain_primitives::primitives::{ HeadData, HorizontalMessages, HrmpChannelId, Id, UpwardMessage, UpwardMessages, ValidationCode, ValidationCodeHash, LOWEST_PUBLIC_ID, LOWEST_USER_ID, }; diff --git a/polkadot/roadmap/implementers-guide/src/types/README.md b/polkadot/roadmap/implementers-guide/src/types/README.md index 807130a5e66..87092bf3a00 100644 --- a/polkadot/roadmap/implementers-guide/src/types/README.md +++ b/polkadot/roadmap/implementers-guide/src/types/README.md @@ -31,7 +31,7 @@ digraph { CandidateDescriptor:collator -> CollatorId:w CandidateDescriptor:persisted_validation_data_hash -> PersistedValidationDataHash - Id [label="polkadot_parachain::primitives::Id"] + Id [label="polkadot_parachain_primitives::primitives::Id"] CollatorId [label="polkadot_primitives::v2::CollatorId"] PoVHash [label = "Hash", shape="doublecircle", fill="gray90"] @@ -128,11 +128,11 @@ digraph { >] - CandidateCommitments:upward_messages -> "polkadot_parachain::primitives::UpwardMessage":w + CandidateCommitments:upward_messages -> "polkadot_parachain_primitives::primitives::UpwardMessage":w CandidateCommitments:horizontal_messages -> "polkadot_core_primitives::v2::OutboundHrmpMessage":w CandidateCommitments:head_data -> HeadData:w - CandidateCommitments:horizontal_messages -> "polkadot_parachain::primitives::Id":w - CandidateCommitments:new_validation_code -> "polkadot_parachain::primitives::ValidationCode":w + CandidateCommitments:horizontal_messages -> "polkadot_parachain_primitives::primitives::Id":w + CandidateCommitments:new_validation_code -> "polkadot_parachain_primitives::primitives::ValidationCode":w PoV [label = < @@ -141,7 +141,7 @@ digraph {
>] - PoV:block_data -> "polkadot_parachain::primitives::BlockData":w + PoV:block_data -> "polkadot_parachain_primitives::primitives::BlockData":w BackedCandidate [label = < @@ -155,7 +155,7 @@ digraph { BackedCandidate:candidate -> CommittedCandidateReceipt:name BackedCandidate:validity_votes -> "polkadot_primitives:v0:ValidityAttestation":w - HeadData [label = "polkadot_parachain::primitives::HeadData"] + HeadData [label = "polkadot_parachain_primitives::primitives::HeadData"] CoreIndex [label = <
diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 8531741395f..9a8bd5017e0 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -47,7 +47,7 @@ primitives = { package = "polkadot-primitives", path = "../../primitives", defau rand = { version = "0.8.5", default-features = false } rand_chacha = { version = "0.3.1", default-features = false } static_assertions = { version = "1.1.0", optional = true } -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", default-features = false } polkadot-runtime-metrics = { path = "../metrics", default-features = false} [dev-dependencies] @@ -82,7 +82,7 @@ std = [ "pallet-timestamp/std", "pallet-vesting/std", "parity-scale-codec/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-metrics/std", "primitives/std", "rustc-hex/std", @@ -110,7 +110,7 @@ runtime-benchmarks = [ "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "primitives/runtime-benchmarks", "sp-application-crypto", "sp-runtime/runtime-benchmarks", diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 77c15c5672f..0c66bb5bdf9 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -22,7 +22,9 @@ use crate::{inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND, shared}; use frame_support::{pallet_prelude::*, DefaultNoBound}; use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; -use polkadot_parachain::primitives::{MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM}; +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, diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index 3a4d2df4b68..cdb38ba6a8e 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -21,7 +21,7 @@ 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::HorizontalMessages; +use polkadot_parachain_primitives::primitives::HorizontalMessages; use primitives::{ Balance, Hash, HrmpChannelId, Id as ParaId, InboundHrmpMessage, OutboundHrmpMessage, SessionIndex, diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index aa94d5914d6..6af9407a587 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -87,7 +87,7 @@ hex-literal = { version = "0.4.1" } runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features=["experimental"] } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", 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 } @@ -165,7 +165,7 @@ std = [ "pallet-xcm-benchmarks?/std", "pallet-xcm/std", "parity-scale-codec/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "primitives/std", "rococo-runtime-constants/std", "runtime-common/std", @@ -226,7 +226,7 @@ runtime-benchmarks = [ "pallet-vesting/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-common/runtime-benchmarks", "runtime-parachains/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 2d24c0077bf..1e411bc901c 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -59,7 +59,7 @@ pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", default-features = false } polkadot-runtime-parachains = { path = "../parachains", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } @@ -114,7 +114,7 @@ std = [ "pallet-vesting/std", "pallet-xcm/std", "parity-scale-codec/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "polkadot-runtime-parachains/std", "primitives/std", "runtime-common/std", @@ -152,7 +152,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-common/runtime-benchmarks", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index dc5bdaf6559..5a47288297b 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -97,7 +97,7 @@ hex-literal = { version = "0.4.1", optional = true } runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features=["experimental"] } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } @@ -184,7 +184,7 @@ std = [ "pallet-xcm-benchmarks?/std", "pallet-xcm/std", "parity-scale-codec/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "primitives/std", "runtime-common/std", "runtime-parachains/std", @@ -254,7 +254,7 @@ runtime-benchmarks = [ "pallet-vesting/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-common/runtime-benchmarks", "runtime-parachains/runtime-benchmarks", diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 6c010fd9343..17ee9840e8f 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -27,7 +27,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", def [dev-dependencies] pallet-balances = { path = "../../../substrate/frame/balances" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } -polkadot-parachain = { path = "../../parachain" } +polkadot-parachain-primitives = { path = "../../parachain" } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } [features] @@ -54,7 +54,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b56b1af82de..b09bcb80ed6 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -21,7 +21,7 @@ use frame_support::{ weights::Weight, }; use frame_system::EnsureRoot; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::origin; use sp_core::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 6ff9f1d893c..486887598c7 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::{ traits::{Currency, Hooks}, weights::Weight, }; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::AllowKnownQueryResponses; diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs index 4a65a419045..7d6bdece335 100644 --- a/polkadot/xcm/src/v2/multilocation.rs +++ b/polkadot/xcm/src/v2/multilocation.rs @@ -239,14 +239,12 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// # fn main() { /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); /// assert_eq!( /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3)))), /// Some(&OnlyChild), /// ); /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None); - /// # } /// ``` pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { if self.parents != prefix.parents { @@ -280,11 +278,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// # fn main() { /// let mut m = MultiLocation::new(1, X1(Parachain(21))); /// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(())); /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3)))); - /// # } /// ``` pub fn append_with(&mut self, suffix: Junctions) -> Result<(), Junctions> { if self.interior.len().saturating_add(suffix.len()) > MAX_JUNCTIONS { @@ -303,11 +299,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// # fn main() { /// let mut m = MultiLocation::new(2, X1(PalletInstance(3))); /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild))), Ok(())); /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3)))); - /// # } /// ``` pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { // prefix self (suffix) @@ -840,11 +834,9 @@ impl Junctions { /// # Example /// ```rust /// # use staging_xcm::v2::{Junctions::*, Junction::*}; - /// # fn main() { /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); /// assert_eq!(m.match_and_split(&X1(Parachain(2))), None); - /// # } /// ``` pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { if prefix.len() + 1 != self.len() || !self.starts_with(prefix) { diff --git a/polkadot/xcm/src/v3/junctions.rs b/polkadot/xcm/src/v3/junctions.rs index c2826c4969e..f7624c91c86 100644 --- a/polkadot/xcm/src/v3/junctions.rs +++ b/polkadot/xcm/src/v3/junctions.rs @@ -438,11 +438,9 @@ impl Junctions { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation}; - /// # fn main() { /// let mut m = X1(Parachain(21)); /// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(())); /// assert_eq!(m, X2(Parachain(21), PalletInstance(3))); - /// # } /// ``` pub fn append_with(&mut self, suffix: impl Into) -> Result<(), Junctions> { let suffix = suffix.into(); @@ -569,11 +567,9 @@ impl Junctions { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*}; - /// # fn main() { /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); /// assert_eq!(m.match_and_split(&X1(Parachain(2))), None); - /// # } /// ``` pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { if prefix.len() + 1 != self.len() { diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 7ac377d5c06..8a1575d9bc9 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -266,14 +266,12 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation}; - /// # fn main() { /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); /// assert_eq!( /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3)))), /// Some(&OnlyChild), /// ); /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None); - /// # } /// ``` pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { if self.parents != prefix.parents { @@ -293,11 +291,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; - /// # fn main() { /// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into(); /// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(())); /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3)))); - /// # } /// ``` pub fn append_with(&mut self, suffix: impl Into) -> Result<(), Self> { let prefix = core::mem::replace(self, suffix.into()); @@ -314,11 +310,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; - /// # fn main() { /// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into(); /// let r = m.appended_with((Parent, PalletInstance(3))).unwrap(); /// assert_eq!(r, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3)))); - /// # } /// ``` pub fn appended_with(mut self, suffix: impl Into) -> Result { match self.append_with(suffix) { @@ -334,11 +328,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; - /// # fn main() { /// let mut m: MultiLocation = (Parent, Parent, PalletInstance(3)).into(); /// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(())); /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3)))); - /// # } /// ``` pub fn prepend_with(&mut self, prefix: impl Into) -> Result<(), Self> { // prefix self (suffix) @@ -383,11 +375,9 @@ impl MultiLocation { /// # Example /// ```rust /// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent}; - /// # fn main() { /// let m: MultiLocation = (Parent, Parent, PalletInstance(3)).into(); /// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap(); /// assert_eq!(r, MultiLocation::new(1, X1(PalletInstance(3)))); - /// # } /// ``` pub fn prepended_with(mut self, prefix: impl Into) -> Result { match self.prepend_with(prefix) { diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 11911d377cd..1f0e1cf3477 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -23,7 +23,7 @@ pallet-transaction-payment = { path = "../../../substrate/frame/transaction-paym log = { version = "0.4.17", default-features = false } # Polkadot dependencies -polkadot-parachain = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { path = "../../parachain", default-features = false } [dev-dependencies] primitive-types = "0.12.1" @@ -45,7 +45,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-salary/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "polkadot-test-runtime/runtime-benchmarks", "primitives/runtime-benchmarks", @@ -58,7 +58,7 @@ std = [ "log/std", "pallet-transaction-payment/std", "parity-scale-codec/std", - "polkadot-parachain/std", + "polkadot-parachain-primitives/std", "scale-info/std", "sp-arithmetic/std", "sp-io/std", diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 353e111b813..0d04e0971bf 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -21,7 +21,7 @@ use frame_support::{ ensure, traits::{Contains, Get, ProcessMessageError}, }; -use polkadot_parachain::primitives::IsSystem; +use polkadot_parachain_primitives::primitives::IsSystem; use sp_std::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result}; use xcm::prelude::*; use xcm_executor::traits::{CheckSuspension, OnResponse, Properties, ShouldExecute}; diff --git a/polkadot/xcm/xcm-builder/src/origin_conversion.rs b/polkadot/xcm/xcm-builder/src/origin_conversion.rs index 112b26869a9..cced7dedf62 100644 --- a/polkadot/xcm/xcm-builder/src/origin_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/origin_conversion.rs @@ -18,7 +18,7 @@ use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait}; use frame_system::RawOrigin as SystemRawOrigin; -use polkadot_parachain::primitives::IsSystem; +use polkadot_parachain_primitives::primitives::IsSystem; use sp_runtime::traits::TryConvert; use sp_std::marker::PhantomData; use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, MultiLocation, NetworkId, OriginKind}; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 56502c445c2..363748940ca 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -25,7 +25,7 @@ use primitive_types::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; use sp_std::cell::RefCell; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared}; use xcm::latest::{opaque, prelude::*}; use xcm_executor::XcmExecutor; diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index 3e735720aa7..426efcaccdb 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -20,7 +20,7 @@ use mock::{ fake_message_hash, kusama_like_with_balances, AccountId, Balance, Balances, BaseXcmWeight, System, XcmConfig, CENTS, }; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index fb9a8f68562..eedcfa0032a 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -18,5 +18,5 @@ xcm = { package = "staging-xcm", path = ".." } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor" } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } polkadot-core-primitives = { path = "../../core-primitives" } -polkadot-parachain = { path = "../../parachain" } +polkadot-parachain-primitives = { path = "../../parachain" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index e29c1c0d1f2..9c48b11f622 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -29,7 +29,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-runtime-parachains = { path = "../../../runtime/parachains" } -polkadot-parachain = { path = "../../../parachain" } +polkadot-parachain-primitives = { path = "../../../parachain" } [features] default = [] @@ -40,7 +40,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index 9c4cbe8fcb2..bc7cba31382 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -34,7 +34,7 @@ use sp_std::prelude::*; use pallet_xcm::XcmPassthrough; use polkadot_core_primitives::BlockNumber as RelayBlockNumber; -use polkadot_parachain::primitives::{ +use polkadot_parachain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; use xcm::{latest::prelude::*, VersionedXcm}; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 6f0e92dc91b..4e9195a8454 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -26,7 +26,7 @@ use frame_system::EnsureRoot; use sp_core::{ConstU32, H256}; use sp_runtime::{traits::IdentityLookup, AccountId32}; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{ configuration, inclusion::{AggregateMessageOrigin, UmpQueueId}, diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index a6258a83f9f..0ca57e680d1 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -29,7 +29,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-runtime-parachains = { path = "../../../runtime/parachains" } -polkadot-parachain = { path = "../../../parachain" } +polkadot-parachain-primitives = { path = "../../../parachain" } [features] runtime-benchmarks = [ @@ -38,7 +38,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs index 441b9f4d286..0893c7c086f 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs @@ -19,7 +19,7 @@ mod relay_chain; use codec::DecodeLimit; use polkadot_core_primitives::AccountId; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::{traits::AccountIdConversion, BuildStorage}; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 3d0b1c82f69..95f875eca06 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -33,7 +33,7 @@ use sp_std::prelude::*; use pallet_xcm::XcmPassthrough; use polkadot_core_primitives::BlockNumber as RelayBlockNumber; -use polkadot_parachain::primitives::{ +use polkadot_parachain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; use xcm::{latest::prelude::*, VersionedXcm}; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 32f3b8aa83f..a29ead9e6c3 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -26,7 +26,7 @@ use frame_system::EnsureRoot; use sp_core::{ConstU32, H256}; use sp_runtime::{traits::IdentityLookup, AccountId32}; -use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{ configuration, inclusion::{AggregateMessageOrigin, UmpQueueId}, diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs index cf56784f7d4..add1b90f415 100644 --- a/polkadot/xcm/xcm-simulator/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/src/lib.rs @@ -27,7 +27,7 @@ pub use sp_io::{hashing::blake2_256, TestExternalities}; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData}; pub use polkadot_core_primitives::BlockNumber as RelayBlockNumber; -pub use polkadot_parachain::primitives::{ +pub use polkadot_parachain_primitives::primitives::{ DmpMessageHandler as DmpMessageHandlerT, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler as XcmpMessageHandlerT, }; diff --git a/substrate/frame/paged-list/fuzzer/Cargo.toml b/substrate/frame/paged-list/fuzzer/Cargo.toml index a6f499d0da1..d96c0348cf4 100644 --- a/substrate/frame/paged-list/fuzzer/Cargo.toml +++ b/substrate/frame/paged-list/fuzzer/Cargo.toml @@ -10,7 +10,7 @@ description = "Fuzz storage types of pallet-paged-list" publish = false [[bin]] -name = "pallet-paged-list" +name = "pallet-paged-list-fuzzer" path = "src/paged_list.rs" [dependencies] -- GitLab From 16fe5be02f06b538e2c4bbb93adbcf82a60da4e3 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:16:07 +0530 Subject: [PATCH 046/633] Renames API (#1186) Co-authored-by: Javier Viola --- cumulus/xcm/xcm-emulator/src/lib.rs | 2 +- .../xcm-builder/src/process_xcm_message.rs | 6 ++-- polkadot/xcm/xcm-simulator/src/lib.rs | 2 +- substrate/frame/broker/src/tick_impls.rs | 2 +- substrate/frame/glutton/src/lib.rs | 4 +-- substrate/frame/glutton/src/tests.rs | 4 +-- .../frame/message-queue/src/benchmarking.rs | 10 +++--- substrate/frame/message-queue/src/lib.rs | 8 ++--- substrate/frame/message-queue/src/tests.rs | 32 +++++++++---------- substrate/frame/scheduler/src/benchmarking.rs | 16 +++++----- substrate/frame/scheduler/src/lib.rs | 2 +- .../primitives/weights/src/weight_meter.rs | 28 ++++++++-------- 12 files changed, 58 insertions(+), 58 deletions(-) diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 79fe496f26b..261d4ad7924 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1027,7 +1027,7 @@ macro_rules! decl_test_networks { use $crate::{Bounded, ProcessMessage, WeightMeter}; use sp_core::Encode; while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { - let mut weight_meter = WeightMeter::max_limit(); + let mut weight_meter = WeightMeter::new(); <$relay_chain>::ext_wrapper(|| { let _ = <$relay_chain as RelayChain>::MessageProcessor::process_message( &msg[..], diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index e8bb68f0787..dba45a8310a 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -110,7 +110,7 @@ mod tests { // Errors if we stay below a weight limit of 1000. for i in 0..10 { - let meter = &mut WeightMeter::from_limit((i * 10).into()); + let meter = &mut WeightMeter::with_limit((i * 10).into()); let mut id = [0; 32]; assert_err!( Processor::process_message(msg, ORIGIN, meter, &mut id), @@ -120,7 +120,7 @@ mod tests { } // Works with a limit of 1000. - let meter = &mut WeightMeter::from_limit(1000.into()); + let meter = &mut WeightMeter::with_limit(1000.into()); let mut id = [0; 32]; assert_ok!(Processor::process_message(msg, ORIGIN, meter, &mut id)); assert_eq!(meter.consumed(), 1000.into()); @@ -150,6 +150,6 @@ mod tests { } fn process_raw(raw: &[u8]) -> Result { - Processor::process_message(raw, ORIGIN, &mut WeightMeter::max_limit(), &mut [0; 32]) + Processor::process_message(raw, ORIGIN, &mut WeightMeter::new(), &mut [0; 32]) } } diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs index add1b90f415..b38465b3d4a 100644 --- a/polkadot/xcm/xcm-simulator/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/src/lib.rs @@ -324,7 +324,7 @@ macro_rules! decl_test_network { let mut _id = [0; 32]; let r = <$relay_chain>::process_message( encoded.as_slice(), para_id, - &mut $crate::WeightMeter::max_limit(), + &mut $crate::WeightMeter::new(), &mut _id, ); match r { diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index 0677d2793e2..d65b8968f3c 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -41,7 +41,7 @@ impl Pallet { _ => return Weight::zero(), }; - let mut meter = WeightMeter::max_limit(); + let mut meter = WeightMeter::new(); if Self::process_core_count(&mut status) { meter.consume(T::WeightInfo::process_core_count(status.core_count.into())); diff --git a/substrate/frame/glutton/src/lib.rs b/substrate/frame/glutton/src/lib.rs index 3d2af95e934..f5e90a17c73 100644 --- a/substrate/frame/glutton/src/lib.rs +++ b/substrate/frame/glutton/src/lib.rs @@ -188,7 +188,7 @@ pub mod pallet { } fn on_idle(_: BlockNumberFor, remaining_weight: Weight) -> Weight { - let mut meter = WeightMeter::from_limit(remaining_weight); + let mut meter = WeightMeter::with_limit(remaining_weight); if meter.try_consume(T::WeightInfo::empty_on_idle()).is_err() { return T::WeightInfo::empty_on_idle() } @@ -197,7 +197,7 @@ pub mod pallet { Storage::::get().saturating_mul_int(meter.remaining().proof_size()); let computation_weight_limit = Compute::::get().saturating_mul_int(meter.remaining().ref_time()); - let mut meter = WeightMeter::from_limit(Weight::from_parts( + let mut meter = WeightMeter::with_limit(Weight::from_parts( computation_weight_limit, proof_size_limit, )); diff --git a/substrate/frame/glutton/src/tests.rs b/substrate/frame/glutton/src/tests.rs index c67543cf55a..b72d5272772 100644 --- a/substrate/frame/glutton/src/tests.rs +++ b/substrate/frame/glutton/src/tests.rs @@ -252,7 +252,7 @@ fn on_idle_weight_over_unity_is_close_enough_works() { fn waste_at_most_ref_time_weight_close_enough() { new_test_ext().execute_with(|| { let mut meter = - WeightMeter::from_limit(Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX)); + WeightMeter::with_limit(Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX)); // Over-spending fails defensively. Glutton::waste_at_most_ref_time(&mut meter); @@ -269,7 +269,7 @@ fn waste_at_most_ref_time_weight_close_enough() { fn waste_at_most_proof_size_weight_close_enough() { new_test_ext().execute_with(|| { let mut meter = - WeightMeter::from_limit(Weight::from_parts(u64::MAX, WEIGHT_PROOF_SIZE_PER_MB * 5)); + WeightMeter::with_limit(Weight::from_parts(u64::MAX, WEIGHT_PROOF_SIZE_PER_MB * 5)); // Over-spending fails defensively. Glutton::waste_at_most_proof_size(&mut meter); diff --git a/substrate/frame/message-queue/src/benchmarking.rs b/substrate/frame/message-queue/src/benchmarking.rs index bbd321ceadd..eedaaebeca9 100644 --- a/substrate/frame/message-queue/src/benchmarking.rs +++ b/substrate/frame/message-queue/src/benchmarking.rs @@ -78,7 +78,7 @@ mod benchmarks { fn service_queue_base() { #[block] { - MessageQueue::::service_queue(0.into(), &mut WeightMeter::max_limit(), Weight::MAX); + MessageQueue::::service_queue(0.into(), &mut WeightMeter::new(), Weight::MAX); } } @@ -89,7 +89,7 @@ mod benchmarks { let page = PageOf::::default(); Pages::::insert(&origin, 0, &page); let mut book_state = single_page_book::(); - let mut meter = WeightMeter::max_limit(); + let mut meter = WeightMeter::new(); let limit = Weight::MAX; #[block] @@ -108,7 +108,7 @@ mod benchmarks { page.remaining = 1.into(); Pages::::insert(&origin, 0, &page); let mut book_state = single_page_book::(); - let mut meter = WeightMeter::max_limit(); + let mut meter = WeightMeter::new(); let limit = Weight::MAX; #[block] @@ -124,7 +124,7 @@ mod benchmarks { let mut page = page::(&msg.clone()); let mut book = book_for::(&page); assert!(page.peek_first().is_some(), "There is one message"); - let mut weight = WeightMeter::max_limit(); + let mut weight = WeightMeter::new(); #[block] { @@ -158,7 +158,7 @@ mod benchmarks { #[benchmark] fn bump_service_head() { setup_bump_service_head::(0.into(), 10.into()); - let mut weight = WeightMeter::max_limit(); + let mut weight = WeightMeter::new(); #[block] { diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 5acc3e9d5a1..9ded84bb035 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -832,7 +832,7 @@ impl Pallet { ); ensure!(!is_processed, Error::::AlreadyProcessed); use MessageExecutionStatus::*; - let mut weight_counter = WeightMeter::from_limit(weight_limit); + let mut weight_counter = WeightMeter::with_limit(weight_limit); match Self::process_message_payload( origin.clone(), page_index, @@ -1150,7 +1150,7 @@ impl Pallet { //loop around this origin let starting_origin = ServiceHead::::get().unwrap(); - while let Some(head) = Self::bump_service_head(&mut WeightMeter::max_limit()) { + while let Some(head) = Self::bump_service_head(&mut WeightMeter::new()) { ensure!( BookStateFor::::contains_key(&head), "Service head must point to an existing book" @@ -1362,7 +1362,7 @@ impl ServiceQueues for Pallet { fn service_queues(weight_limit: Weight) -> Weight { // The maximum weight that processing a single message may take. let overweight_limit = weight_limit; - let mut weight = WeightMeter::from_limit(weight_limit); + let mut weight = WeightMeter::with_limit(weight_limit); let mut next = match Self::bump_service_head(&mut weight) { Some(h) => h, @@ -1402,7 +1402,7 @@ impl ServiceQueues for Pallet { weight_limit: Weight, (message_origin, page, index): Self::OverweightMessageAddress, ) -> Result { - let mut weight = WeightMeter::from_limit(weight_limit); + let mut weight = WeightMeter::with_limit(weight_limit); if weight .try_consume( T::WeightInfo::execute_overweight_page_removed() diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index bcb099a6acc..092bd1d8334 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -381,7 +381,7 @@ fn service_queue_bails() { // Not enough weight for `service_queue_base`. build_and_execute::(|| { set_weight("service_queue_base", 2.into_weight()); - let mut meter = WeightMeter::from_limit(1.into_weight()); + let mut meter = WeightMeter::with_limit(1.into_weight()); assert_storage_noop!(MessageQueue::service_queue(0u32.into(), &mut meter, Weight::MAX)); assert!(meter.consumed().is_zero()); @@ -389,7 +389,7 @@ fn service_queue_bails() { // Not enough weight for `ready_ring_unknit`. build_and_execute::(|| { set_weight("ready_ring_unknit", 2.into_weight()); - let mut meter = WeightMeter::from_limit(1.into_weight()); + let mut meter = WeightMeter::with_limit(1.into_weight()); assert_storage_noop!(MessageQueue::service_queue(0u32.into(), &mut meter, Weight::MAX)); assert!(meter.consumed().is_zero()); @@ -399,7 +399,7 @@ fn service_queue_bails() { set_weight("service_queue_base", 2.into_weight()); set_weight("ready_ring_unknit", 2.into_weight()); - let mut meter = WeightMeter::from_limit(3.into_weight()); + let mut meter = WeightMeter::with_limit(3.into_weight()); assert_storage_noop!(MessageQueue::service_queue(0.into(), &mut meter, Weight::MAX)); assert!(meter.consumed().is_zero()); }); @@ -426,7 +426,7 @@ fn service_page_works() { msgs -= process; // Enough weight to process `process` messages. - let mut meter = WeightMeter::from_limit(((2 + (3 + 1) * process) as u64).into_weight()); + let mut meter = WeightMeter::with_limit(((2 + (3 + 1) * process) as u64).into_weight()); System::reset_events(); let (processed, status) = crate::Pallet::::service_page(&Here, &mut book, &mut meter, Weight::MAX); @@ -449,7 +449,7 @@ fn service_page_bails() { // Not enough weight for `service_page_base_completion`. build_and_execute::(|| { set_weight("service_page_base_completion", 2.into_weight()); - let mut meter = WeightMeter::from_limit(1.into_weight()); + let mut meter = WeightMeter::with_limit(1.into_weight()); let (page, _) = full_page::(); let mut book = book_for::(&page); @@ -466,7 +466,7 @@ fn service_page_bails() { // Not enough weight for `service_page_base_no_completion`. build_and_execute::(|| { set_weight("service_page_base_no_completion", 2.into_weight()); - let mut meter = WeightMeter::from_limit(1.into_weight()); + let mut meter = WeightMeter::with_limit(1.into_weight()); let (page, _) = full_page::(); let mut book = book_for::(&page); @@ -487,7 +487,7 @@ fn service_page_item_bails() { build_and_execute::(|| { let _guard = StorageNoopGuard::default(); let (mut page, _) = full_page::(); - let mut weight = WeightMeter::from_limit(10.into_weight()); + let mut weight = WeightMeter::with_limit(10.into_weight()); let overweight_limit = 10.into_weight(); set_weight("service_page_item", 11.into_weight()); @@ -518,7 +518,7 @@ fn service_page_suspension_works() { Pages::::insert(Here, 0, page); // First we process 5 messages from this page. - let mut meter = WeightMeter::from_limit(5.into_weight()); + let mut meter = WeightMeter::with_limit(5.into_weight()); let (_, status) = crate::Pallet::::service_page(&Here, &mut book, &mut meter, Weight::MAX); @@ -534,7 +534,7 @@ fn service_page_suspension_works() { let (_, status) = crate::Pallet::::service_page( &Here, &mut book, - &mut WeightMeter::max_limit(), + &mut WeightMeter::new(), Weight::MAX, ); assert_eq!(status, NoProgress); @@ -546,7 +546,7 @@ fn service_page_suspension_works() { let (_, status) = crate::Pallet::::service_page( &Here, &mut book, - &mut WeightMeter::max_limit(), + &mut WeightMeter::new(), Weight::MAX, ); assert_eq!(status, NoMore); @@ -564,7 +564,7 @@ fn bump_service_head_works() { // Bump 99 times. for i in 0..99 { - let current = MessageQueue::bump_service_head(&mut WeightMeter::max_limit()).unwrap(); + let current = MessageQueue::bump_service_head(&mut WeightMeter::new()).unwrap(); assert_eq!(current, [Here, There, Everywhere(0)][i % 3]); } @@ -581,7 +581,7 @@ fn bump_service_head_bails() { setup_bump_service_head::(0.into(), 1.into()); let _guard = StorageNoopGuard::default(); - let mut meter = WeightMeter::from_limit(1.into_weight()); + let mut meter = WeightMeter::with_limit(1.into_weight()); assert!(MessageQueue::bump_service_head(&mut meter).is_none()); assert_eq!(meter.consumed(), 0.into_weight()); }); @@ -591,7 +591,7 @@ fn bump_service_head_bails() { fn bump_service_head_trivial_works() { build_and_execute::(|| { set_weight("bump_service_head", 2.into_weight()); - let mut meter = WeightMeter::max_limit(); + let mut meter = WeightMeter::new(); assert_eq!(MessageQueue::bump_service_head(&mut meter), None, "Cannot bump"); assert_eq!(meter.consumed(), 2.into_weight()); @@ -616,7 +616,7 @@ fn bump_service_head_no_head_noops() { ServiceHead::::kill(); // Nothing happens. - assert_storage_noop!(MessageQueue::bump_service_head(&mut WeightMeter::max_limit())); + assert_storage_noop!(MessageQueue::bump_service_head(&mut WeightMeter::new())); }); } @@ -624,7 +624,7 @@ fn bump_service_head_no_head_noops() { fn service_page_item_consumes_correct_weight() { build_and_execute::(|| { let mut page = page::(b"weight=3"); - let mut weight = WeightMeter::from_limit(10.into_weight()); + let mut weight = WeightMeter::with_limit(10.into_weight()); let overweight_limit = 0.into_weight(); set_weight("service_page_item", 2.into_weight()); @@ -648,7 +648,7 @@ fn service_page_item_consumes_correct_weight() { fn service_page_item_skips_perm_overweight_message() { build_and_execute::(|| { let mut page = page::(b"TooMuch"); - let mut weight = WeightMeter::from_limit(2.into_weight()); + let mut weight = WeightMeter::with_limit(2.into_weight()); let overweight_limit = 0.into_weight(); set_weight("service_page_item", 2.into_weight()); diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index b41cea44965..341a19cdb23 100644 --- a/substrate/frame/scheduler/src/benchmarking.rs +++ b/substrate/frame/scheduler/src/benchmarking.rs @@ -131,7 +131,7 @@ benchmarks! { let now = BlockNumberFor::::from(BLOCK_NUMBER); IncompleteSince::::put(now - One::one()); }: { - Scheduler::::service_agendas(&mut WeightMeter::max_limit(), now, 0); + Scheduler::::service_agendas(&mut WeightMeter::new(), now, 0); } verify { assert_eq!(IncompleteSince::::get(), Some(now - One::one())); } @@ -143,7 +143,7 @@ benchmarks! { fill_schedule::(now, s)?; let mut executed = 0; }: { - Scheduler::::service_agenda(&mut WeightMeter::max_limit(), &mut executed, now, now, 0); + Scheduler::::service_agenda(&mut WeightMeter::new(), &mut executed, now, now, 0); } verify { assert_eq!(executed, 0); } @@ -154,7 +154,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::from_limit(Weight::zero()); + let mut counter = WeightMeter::with_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -172,7 +172,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, Some(s), 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::from_limit(Weight::zero()); + let mut counter = WeightMeter::with_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -184,7 +184,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, true, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::from_limit(Weight::zero()); + let mut counter = WeightMeter::with_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -196,7 +196,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(true, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::from_limit(Weight::zero()); + let mut counter = WeightMeter::with_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -204,7 +204,7 @@ benchmarks! { // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. execute_dispatch_signed { - let mut counter = WeightMeter::max_limit(); + let mut counter = WeightMeter::new(); let origin = make_origin::(true); let call = T::Preimages::realize(&make_call::(None)).unwrap().0; }: { @@ -215,7 +215,7 @@ benchmarks! { // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. execute_dispatch_unsigned { - let mut counter = WeightMeter::max_limit(); + let mut counter = WeightMeter::new(); let origin = make_origin::(false); let call = T::Preimages::realize(&make_call::(None)).unwrap().0; }: { diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 4363f98668e..3da4aa03cae 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -318,7 +318,7 @@ pub mod pallet { impl Hooks> for Pallet { /// Execute the scheduled calls fn on_initialize(now: BlockNumberFor) -> Weight { - let mut weight_counter = WeightMeter::from_limit(T::MaximumWeight::get()); + let mut weight_counter = WeightMeter::with_limit(T::MaximumWeight::get()); Self::service_agendas(&mut weight_counter, now, u32::max_value()); weight_counter.consumed() } diff --git a/substrate/primitives/weights/src/weight_meter.rs b/substrate/primitives/weights/src/weight_meter.rs index 3b0b21ea879..584d22304c3 100644 --- a/substrate/primitives/weights/src/weight_meter.rs +++ b/substrate/primitives/weights/src/weight_meter.rs @@ -31,7 +31,7 @@ use sp_arithmetic::Perbill; /// use sp_weights::{Weight, WeightMeter}; /// /// // The weight is limited to (10, 0). -/// let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); +/// let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 0)); /// // There is enough weight remaining for an operation with (6, 0) weight. /// assert!(meter.try_consume(Weight::from_parts(6, 0)).is_ok()); /// assert_eq!(meter.remaining(), Weight::from_parts(4, 0)); @@ -51,13 +51,13 @@ pub struct WeightMeter { impl WeightMeter { /// Creates [`Self`] from a limit for the maximal consumable weight. - pub fn from_limit(limit: Weight) -> Self { + pub fn with_limit(limit: Weight) -> Self { Self { consumed: Weight::zero(), limit } } /// Creates [`Self`] with the maximal possible limit for the consumable weight. - pub fn max_limit() -> Self { - Self::from_limit(Weight::MAX) + pub fn new() -> Self { + Self::with_limit(Weight::MAX) } /// The already consumed weight. @@ -84,7 +84,7 @@ impl WeightMeter { /// use sp_weights::{Weight, WeightMeter}; /// use sp_arithmetic::Perbill; /// - /// let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); + /// let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 20)); /// // Nothing consumed so far: /// assert_eq!(meter.consumed_ratio(), Perbill::from_percent(0)); /// meter.consume(Weight::from_parts(5, 5)); @@ -158,7 +158,7 @@ mod tests { #[test] fn weight_meter_remaining_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 20)); assert!(meter.check_accrue(Weight::from_parts(5, 0))); assert_eq!(meter.consumed, Weight::from_parts(5, 0)); @@ -175,7 +175,7 @@ mod tests { #[test] fn weight_meter_can_accrue_works() { - let meter = WeightMeter::from_limit(Weight::from_parts(1, 1)); + let meter = WeightMeter::with_limit(Weight::from_parts(1, 1)); assert!(meter.can_accrue(Weight::from_parts(0, 0))); assert!(meter.can_accrue(Weight::from_parts(1, 1))); @@ -186,7 +186,7 @@ mod tests { #[test] fn weight_meter_check_accrue_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(2, 2)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(2, 2)); assert!(meter.check_accrue(Weight::from_parts(0, 0))); assert!(meter.check_accrue(Weight::from_parts(1, 1))); @@ -199,7 +199,7 @@ mod tests { #[test] fn weight_meter_check_and_can_accrue_works() { - let mut meter = WeightMeter::max_limit(); + let mut meter = WeightMeter::new(); assert!(meter.can_accrue(Weight::from_parts(u64::MAX, 0))); assert!(meter.check_accrue(Weight::from_parts(u64::MAX, 0))); @@ -219,7 +219,7 @@ mod tests { #[test] fn consumed_ratio_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 20)); assert!(meter.check_accrue(Weight::from_parts(5, 0))); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(50)); @@ -239,7 +239,7 @@ mod tests { #[test] fn try_consume_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 0)); assert!(meter.try_consume(Weight::from_parts(11, 0)).is_err()); assert!(meter.consumed().is_zero(), "No modification"); @@ -253,7 +253,7 @@ mod tests { #[test] fn can_consume_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 0)); assert!(!meter.can_consume(Weight::from_parts(11, 0))); assert!(meter.consumed().is_zero(), "No modification"); @@ -267,7 +267,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn consume_works() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(5, 10)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(5, 10)); meter.consume(Weight::from_parts(4, 0)); assert_eq!(meter.remaining(), Weight::from_parts(1, 10)); @@ -281,7 +281,7 @@ mod tests { #[cfg(debug_assertions)] #[should_panic(expected = "Weight counter overflow")] fn consume_defensive_fail() { - let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); + let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 0)); let _ = meter.consume(Weight::from_parts(11, 0)); } } -- GitLab From 12443589e3321f3097544330b802b63551ddebd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 03:22:35 -0700 Subject: [PATCH 047/633] Bump the known_good_semver group with 1 update (#1347) Bumps the known_good_semver group with 1 update: [clap](https://github.com/clap-rs/clap). - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.4.1...v4.4.2) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 71 +++++++++---------- cumulus/client/cli/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/utils/staking-miner/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 27 files changed, 62 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c99790ba28b..e886e044249 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2355,7 +2355,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.1", + "clap 4.4.2", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2486,20 +2486,19 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", - "clap_derive 4.4.0", - "once_cell", + "clap_derive 4.4.2", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", @@ -2513,7 +2512,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", ] [[package]] @@ -2531,9 +2530,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", @@ -3113,7 +3112,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.1", + "clap 4.4.2", "criterion-plot", "futures", "is-terminal", @@ -3278,7 +3277,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3971,7 +3970,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.1", + "clap 4.4.2", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -5218,7 +5217,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.1", + "clap 4.4.2", "comfy-table", "frame-benchmarking", "frame-support", @@ -5310,7 +5309,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -8232,7 +8231,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.4.1", + "clap 4.4.2", "derive_more", "fs_extra", "futures", @@ -8269,7 +8268,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.4.1", + "clap 4.4.2", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8395,7 +8394,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8449,7 +8448,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "generate-bags", "kitchensink-runtime", ] @@ -8458,7 +8457,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8501,7 +8500,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "flate2", "fs_extra", "glob", @@ -10902,7 +10901,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11632,7 +11631,7 @@ dependencies = [ name = "polkadot-cli" version = "1.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "frame-benchmarking-cli", "futures", "log", @@ -12448,7 +12447,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.1", + "clap 4.4.2", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -13061,7 +13060,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.1", + "clap 4.4.2", "color-eyre", "futures", "futures-timer", @@ -13207,7 +13206,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "generate-bags", "polkadot-runtime", "sp-io", @@ -13969,7 +13968,7 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "frame-system", "kusama-runtime-constants", "log", @@ -14677,7 +14676,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.4.1", + "clap 4.4.2", "fdlimit", "futures", "futures-timer", @@ -15781,7 +15780,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "fs4", "log", "sc-client-db", @@ -17324,7 +17323,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17868,7 +17867,7 @@ name = "staging-staking-miner" version = "1.0.0" dependencies = [ "assert_cmd", - "clap 4.4.1", + "clap 4.4.2", "exitcode", "frame-election-provider-support", "frame-remote-externalities", @@ -18090,7 +18089,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "sc-cli", ] @@ -18132,7 +18131,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "frame-support", "frame-system", "sc-cli", @@ -18591,7 +18590,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "futures", "futures-timer", "log", @@ -18640,7 +18639,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.1", + "clap 4.4.2", "futures", "futures-timer", "log", @@ -19316,7 +19315,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.1", + "clap 4.4.2", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 9f818ef846c..6c44d5f5fd3 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 186ab634682..b1f1946e3ed 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 766bd34a0dd..dc59b820752 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 04247dd0248..04d53545ead 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.1", features = ["derive"] } +clap = { version = "4.4.2", 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/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 8a5b2d04461..bcb4f2ac130 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.1", features = ["derive"], optional = true } +clap = { version = "4.4.2", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.31" futures = "0.3.21" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index f94e19ad521..56053b8814a 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index a570788e9e8..7079ab73270 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -18,7 +18,7 @@ required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 781e4e3134f..0f1fd60a900 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -18,7 +18,7 @@ required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } futures = "0.3.19" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 88911d3f6ac..98a0a9b6a88 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.4.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 871eb0a9329..bbdddf75064 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -19,6 +19,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.4.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml index b9ddca12660..09e73bc10f2 100644 --- a/polkadot/utils/staking-miner/Cargo.toml +++ b/polkadot/utils/staking-miner/Cargo.toml @@ -12,7 +12,7 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -clap = { version = "4.4.1", features = ["derive", "env"] } +clap = { version = "4.4.2", features = ["derive", "env"] } tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } jsonrpsee = { version = "0.16.2", features = ["ws-client", "macros"] } log = "0.4.17" diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index b89cd0c7088..38eba5ee0e1 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 8f55aab5a16..a02d7393740 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 330256dd2e5..28701db482d 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.1", features = ["derive"], optional = true } +clap = { version = "4.4.2", 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"] } @@ -135,7 +135,7 @@ pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] -clap = { version = "4.4.1", optional = true } +clap = { version = "4.4.2", 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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 31e2a18c9c1..2b6a5e1aea1 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index b85f7d5e065..fcc97e7809b 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } rand = "0.8" node-cli = { path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index c936e9fba40..98276863f8d 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 9404ba1b959..917cdc04d1d 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.1", features = ["derive", "string"] } +clap = { version = "4.4.2", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index e8e7fbcc469..c5b71260f97 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.1", features = ["derive", "string"] } +clap = { version = "4.4.2", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.6.3" sc-client-db = { path = "../db", default-features = false} 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 9b1e0264956..69ce42559a6 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index aad90a36c73..86927786c58 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 6d8636e4fe2..6c4cee8ece3 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 5a74abb1c93..096e4be82d4 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.1", features = ["derive"] } +clap = { version = "4.4.2", 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/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 4653e585ebd..d191506a2ac 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.1", features = ["derive"] } +clap = { version = "4.4.2", 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 37b70564f3f..43005ca5c4a 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 3ad069ddc47..7d1c204422a 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.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -- GitLab From 241601b1c11902c1a051c9c204122fdecfe2e980 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Fri, 1 Sep 2023 12:44:06 +0200 Subject: [PATCH 048/633] [xcm-emulator] Improve hygiene and clean up (#1301) * improve hygiene & clean up * improve hygiene & clean up - xcm-emulator * improve hygiene & clean up - common * improve hygiene & clean up - tests * improve hygiene & clean up - tests 2 * last hygiene bits * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- Cargo.lock | 48 +-- .../assets/asset-hub-kusama/Cargo.toml | 6 - .../assets/asset-hub-kusama/src/lib.rs | 38 +-- .../assets/asset-hub-polkadot/Cargo.toml | 8 +- .../assets/asset-hub-polkadot/src/lib.rs | 32 +- .../assets/asset-hub-westend/Cargo.toml | 6 - .../assets/asset-hub-westend/src/lib.rs | 29 +- .../bridges/bridge-hub-rococo/Cargo.toml | 9 +- .../bridges/bridge-hub-rococo/src/lib.rs | 39 +-- .../collectives-polkadot/Cargo.toml | 5 - .../collectives-polkadot/src/lib.rs | 36 +-- .../emulated/common/Cargo.toml | 11 - .../emulated/common/src/constants.rs | 17 +- .../emulated/common/src/impls.rs | 274 ++++++++++-------- .../emulated/common/src/lib.rs | 85 +----- .../emulated/common/src/xcm_helpers.rs | 66 +++++ cumulus/xcm/xcm-emulator/Cargo.toml | 6 +- cumulus/xcm/xcm-emulator/src/lib.rs | 186 ++++++------ 18 files changed, 388 insertions(+), 513 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs diff --git a/Cargo.lock b/Cargo.lock index e886e044249..040f5659e49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -697,9 +697,6 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-kusama-runtime", - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -713,11 +710,8 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", - "sp-core", "sp-runtime", - "sp-weights", "staging-xcm", - "staging-xcm-executor", "xcm-emulator", ] @@ -798,12 +792,11 @@ dependencies = [ name = "asset-hub-polkadot-integration-tests" version = "1.0.0" dependencies = [ - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", + "asset-hub-kusama-runtime", "frame-support", "frame-system", "integration-tests-common", + "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-xcm", @@ -813,11 +806,8 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", - "sp-core", "sp-runtime", - "sp-weights", "staging-xcm", - "staging-xcm-executor", "xcm-emulator", ] @@ -896,9 +886,6 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-westend-runtime", - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -912,11 +899,8 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", - "sp-core", "sp-runtime", - "sp-weights", "staging-xcm", - "staging-xcm-executor", "xcm-emulator", ] @@ -1957,13 +1941,10 @@ name = "bridge-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ "bp-messages", - "cumulus-pallet-parachain-system", + "cumulus-pallet-dmp-queue", "cumulus-pallet-xcmp-queue", "frame-support", - "frame-system", "integration-tests-common", - "pallet-assets", - "pallet-balances", "pallet-bridge-messages", "pallet-xcm", "parachains-common", @@ -1972,11 +1953,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime", "polkadot-runtime-parachains", - "sp-core", - "sp-runtime", - "sp-weights", "staging-xcm", - "staging-xcm-executor", "xcm-emulator", ] @@ -2581,15 +2558,12 @@ dependencies = [ name = "collectives-polkadot-integration-tests" version = "0.1.0" dependencies = [ - "asset-hub-polkadot-runtime", "collectives-polkadot-runtime", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "frame-support", - "frame-system", "integration-tests-common", "pallet-assets", - "pallet-balances", "pallet-core-fellowship", "pallet-salary", "pallet-xcm", @@ -2601,9 +2575,7 @@ dependencies = [ "polkadot-runtime-parachains", "sp-core", "sp-runtime", - "sp-weights", "staging-xcm", - "staging-xcm-executor", "xcm-emulator", ] @@ -6434,7 +6406,6 @@ dependencies = [ "asset-hub-polkadot-runtime", "asset-hub-westend-runtime", "bp-messages", - "bp-runtime", "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", @@ -6445,17 +6416,13 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "frame-support", - "frame-system", "kusama-runtime-constants", - "lazy_static", "pallet-assets", - "pallet-balances", "pallet-bridge-messages", "pallet-im-online", "pallet-message-queue", "pallet-staking", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "paste", @@ -6475,11 +6442,8 @@ dependencies = [ "sp-consensus-beefy", "sp-core", "sp-runtime", - "sp-tracing", - "sp-weights", "staging-kusama-runtime", "staging-xcm", - "staging-xcm-executor", "westend-runtime", "westend-runtime-constants", "xcm-emulator", @@ -20858,9 +20822,7 @@ dependencies = [ name = "xcm-emulator" version = "0.1.0" dependencies = [ - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-test-relay-sproof-builder", @@ -20871,10 +20833,10 @@ dependencies = [ "log", "pallet-balances", "pallet-message-queue", - "parachain-info", "parachains-common", "parity-scale-codec", "paste", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-parachains", "sp-arithmetic", @@ -20882,7 +20844,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "sp-trie", + "sp-tracing", "staging-xcm", "staging-xcm-executor", ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index b179c646784..66885797860 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -14,8 +14,6 @@ assert_matches = "1.5.0" 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} -sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../../substrate/primitives/weights", 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} @@ -26,15 +24,11 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusama" } -cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs index 696e0a5cf76..a81badf1149 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -17,42 +17,28 @@ pub use codec::Encode; pub use frame_support::{ assert_err, assert_ok, - instances::Instance1, pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, - traits::{fungibles::Inspect, OriginTrait}, + sp_runtime::{AccountId32, DispatchError, DispatchResult}, + traits::fungibles::Inspect, }; pub use integration_tests_common::{ constants::{ - accounts::{ALICE, BOB}, - asset_hub_kusama::ED as ASSET_HUB_KUSAMA_ED, - kusama::ED as KUSAMA_ED, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, + asset_hub_kusama::ED as ASSET_HUB_KUSAMA_ED, kusama::ED as KUSAMA_ED, PROOF_SIZE_THRESHOLD, + REF_TIME_THRESHOLD, XCM_V3, }, - lazy_static::lazy_static, - xcm_transact_paid_execution, xcm_transact_unpaid_execution, AccountId, AssetHubKusama, - AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, BridgeHubKusama, - BridgeHubKusamaPallet, BridgeHubKusamaReceiver, BridgeHubKusamaSender, BridgeHubPolkadot, - BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, Kusama, KusamaMockNet, KusamaPallet, - KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, PenpalKusamaAReceiver, - PenpalKusamaASender, PenpalKusamaB, PenpalKusamaBPallet, PenpalKusamaBReceiver, - PenpalKusamaBSender, PenpalPolkadotA, PenpalPolkadotAReceiver, PenpalPolkadotASender, Polkadot, - PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, Kusama, + KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, + PenpalKusamaAReceiver, PenpalKusamaASender, }; -pub use parachains_common::Balance; -pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; +pub use parachains_common::{AccountId, Balance}; pub use xcm::{ - prelude::*, + prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Kusama as KusamaId}, - DoubleEncoded, }; pub use xcm_emulator::{ - assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, - TestContext, TestExt, TestExternalities, + 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; 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 index 4a0ca2e243a..ef62f4b88d5 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -13,10 +13,9 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = 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} -sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../../substrate/primitives/weights", 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} @@ -24,14 +23,11 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } -cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } +asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusama" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} 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 index 176e3def1f2..6ca6c55f4e9 100644 --- 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 @@ -17,40 +17,28 @@ pub use codec::Encode; pub use frame_support::{ assert_err, assert_ok, - instances::Instance1, pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, - traits::{fungibles::Inspect, OriginTrait}, + sp_runtime::{AccountId32, DispatchError, DispatchResult}, + traits::fungibles::Inspect, }; pub use integration_tests_common::{ constants::{ - accounts::{ALICE, BOB}, - asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, - polkadot::ED as POLKADOT_ED, + asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, polkadot::ED as POLKADOT_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - lazy_static::lazy_static, - xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubPolkadot, - AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, BridgeHubPolkadot, - BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalPolkadotA, - PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotASender, PenpalPolkadotB, - PenpalPolkadotBPallet, PenpalPolkadotBReceiver, PenpalPolkadotBSender, Polkadot, - PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, + PenpalPolkadotA, PenpalPolkadotAReceiver, Polkadot, PolkadotPallet, PolkadotReceiver, + PolkadotSender, }; pub use parachains_common::{AccountId, Balance}; -pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ - prelude::*, + prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Polkadot as PolkadotId}, - DoubleEncoded, }; pub use xcm_emulator::{ - assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, - TestContext, TestExt, TestExternalities, + 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; 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 64522e309a2..c76d4b1501b 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 @@ -14,8 +14,6 @@ assert_matches = "1.5.0" 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} -sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../../substrate/primitives/weights", 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} @@ -26,15 +24,11 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } -cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} 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 b7eba63df10..c00f557f177 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 @@ -17,39 +17,30 @@ pub use codec::Encode; pub use frame_support::{ assert_err, assert_ok, - instances::{Instance1, Instance2}, + instances::Instance2, pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError, MultiAddress}, - traits::{fungibles::Inspect, OriginTrait}, + sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError}, + traits::fungibles::Inspect, BoundedVec, }; pub use integration_tests_common::{ constants::{ - accounts::{ALICE, BOB}, - asset_hub_westend::ED as ASSET_HUB_WESTEND_ED, - westend::ED as WESTEND_ED, + asset_hub_westend::ED as ASSET_HUB_WESTEND_ED, westend::ED as WESTEND_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - lazy_static::lazy_static, - xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubWestend, - AssetHubWestendPallet, AssetHubWestendReceiver, AssetHubWestendSender, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalWestendA, - PenpalWestendAPallet, PenpalWestendAReceiver, PenpalWestendASender, Westend, WestendMockNet, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + AssetHubWestend, AssetHubWestendPallet, AssetHubWestendReceiver, AssetHubWestendSender, + PenpalWestendA, PenpalWestendAPallet, PenpalWestendAReceiver, PenpalWestendASender, Westend, WestendPallet, WestendReceiver, WestendSender, }; pub use parachains_common::{AccountId, Balance}; -pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ - prelude::*, + prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Westend as WestendId}, - DoubleEncoded, }; pub use xcm_emulator::{ - assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, - TestContext, TestExt, TestExternalities, + 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; 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 7b909562f15..12a2ed51591 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 @@ -10,13 +10,7 @@ publish = false 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} -sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} -pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} -pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} @@ -24,13 +18,12 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false} bp-messages = { path = "../../../../../bridges/primitives/messages", 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 52c17122c57..468527ec582 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 @@ -15,48 +15,27 @@ // along with Cumulus. If not, see . pub use bp_messages::LaneId; -pub use codec::Encode; -pub use frame_support::{ - assert_err, assert_ok, - instances::Instance1, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, - traits::{fungibles::Inspect, OriginTrait}, -}; +pub use frame_support::assert_ok; pub use integration_tests_common::{ constants::{ - accounts::{ALICE, BOB}, - asset_hub_kusama::ED as ASSET_HUB_ROCOCO_ED, - kusama::ED as ROCOCO_ED, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, + asset_hub_kusama::ED as ASSET_HUB_ROCOCO_ED, kusama::ED as ROCOCO_ED, PROOF_SIZE_THRESHOLD, + REF_TIME_THRESHOLD, XCM_V3, }, - lazy_static::lazy_static, - xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubRococo, - AssetHubRococoPallet, AssetHubRococoReceiver, AssetHubRococoSender, AssetHubWococo, - AssetHubWococoPallet, AssetHubWococoReceiver, AssetHubWococoSender, BridgeHubRococo, - BridgeHubRococoPallet, BridgeHubRococoReceiver, BridgeHubRococoSender, BridgeHubWococo, - BridgeHubWococoPallet, BridgeHubWococoReceiver, BridgeHubWococoSender, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalRococoA, PenpalRococoAPallet, - PenpalRococoAReceiver, PenpalRococoASender, Rococo, RococoMockNet, RococoPallet, - RococoReceiver, RococoSender, Wococo, WococoMockNet, WococoPallet, WococoReceiver, - WococoSender, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + AssetHubRococo, AssetHubRococoReceiver, AssetHubWococo, BridgeHubRococo, BridgeHubWococo, + PenpalRococoA, Rococo, RococoPallet, }; pub use parachains_common::{AccountId, Balance}; -pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ - prelude::*, + prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, NetworkId::{Rococo as RococoId, Wococo as WococoId}, }, - DoubleEncoded, }; pub use xcm_emulator::{ - assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, - TestContext, TestExt, TestExternalities, + 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; diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index 0882dd9d408..ee0e254befc 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -12,10 +12,7 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = # 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} sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} -pallet-balances = { path = "../../../../../../substrate/frame/balances", 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} @@ -26,7 +23,6 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus @@ -34,7 +30,6 @@ 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" } -asset-hub-polkadot-runtime = { path = "../../../../runtimes/assets/asset-hub-polkadot" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", 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 index aae8ab2111e..6bbd112f687 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -15,42 +15,24 @@ // along with Cumulus. If not, see . pub use codec::Encode; -pub use frame_support::{ - assert_err, assert_ok, - instances::Instance1, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, - traits::{fungibles::Inspect, OriginTrait}, -}; +pub use frame_support::{assert_ok, sp_runtime::AccountId32}; pub use integration_tests_common::{ constants::{ - accounts::{ALICE, BOB}, - asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, - polkadot::ED as POLKADOT_ED, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, + accounts::ALICE, asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, + polkadot::ED as POLKADOT_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - lazy_static::lazy_static, - xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubPolkadot, - AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, BridgeHubPolkadot, - BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalPolkadotA, - PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotASender, PenpalPolkadotB, - PenpalPolkadotBPallet, PenpalPolkadotBReceiver, PenpalPolkadotBSender, Polkadot, - PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, Collectives, + PenpalPolkadotA, Polkadot, }; pub use parachains_common::{AccountId, Balance}; -pub use polkadot_core_primitives::InboundDownwardMessage; -pub use polkadot_parachain_primitives::primitives::{HrmpChannelId, Id}; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ - prelude::*, + prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Polkadot as PolkadotId}, - DoubleEncoded, }; pub use xcm_emulator::{ - assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, - TestContext, TestExt, TestExternalities, + 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; diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 382826873eb..a8002158dbc 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -8,7 +8,6 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -lazy_static = "1.4.0" paste = "1.0.14" # Substrate @@ -16,12 +15,8 @@ grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/c sp-authority-discovery = { path = "../../../../../substrate/primitives/authority-discovery", default-features = false} 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} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} -sp-weights = { path = "../../../../../substrate/primitives/weights", default-features = false} sp-consensus-babe = { path = "../../../../../substrate/primitives/consensus/babe", default-features = false} -sp-tracing = { path = "../../../../../substrate/primitives/tracing" } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false} pallet-staking = { path = "../../../../../substrate/frame/staking", default-features = false} pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} @@ -43,12 +38,10 @@ rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/cons westend-runtime = { path = "../../../../../polkadot/runtime/westend" } westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants" } xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../common" } -parachain-info = { path = "../../../pallets/parachain-info" } cumulus-primitives-core = { path = "../../../../primitives/core" } penpal-runtime = { path = "../../../runtimes/testing/penpal" } asset-hub-polkadot-runtime = { path = "../../../runtimes/assets/asset-hub-polkadot" } @@ -63,7 +56,6 @@ cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue" } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } bp-messages = { path = "../../../../bridges/primitives/messages" } -bp-runtime = { path = "../../../../bridges/primitives/runtime" } pallet-bridge-messages = { path = "../../../../bridges/modules/messages" } bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common" } @@ -80,10 +72,8 @@ runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", "frame-support/runtime-benchmarks", - "frame-system/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", @@ -98,5 +88,4 @@ runtime-benchmarks = [ "rococo-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "westend-runtime/runtime-benchmarks", - "xcm-executor/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 b32d86d3b07..fedc46fabff 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -14,9 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +// Substrate use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_core::{sr25519, storage::Storage, Pair, Public}; +use sp_runtime::{ + traits::{IdentifyAccount, Verify}, + BuildStorage, MultiSignature, Perbill, +}; + +// Cumulus use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; use polkadot_parachain_primitives::primitives::{HeadData, ValidationCode}; use polkadot_primitives::{AssignmentId, ValidatorId}; @@ -25,13 +35,6 @@ use polkadot_runtime_parachains::{ paras::{ParaGenesisArgs, ParaKind}, }; use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; -use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; -use sp_consensus_babe::AuthorityId as BabeId; -use sp_core::{sr25519, storage::Storage, Pair, Public}; -use sp_runtime::{ - traits::{IdentifyAccount, Verify}, - BuildStorage, MultiSignature, Perbill, -}; use xcm; pub const XCM_V2: u32 = 3; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 92282eb8c0a..f13da001620 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -14,18 +14,51 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use super::{BridgeHubRococo, BridgeHubWococo}; -// pub use paste; +pub use codec::{Decode, Encode}; +pub use paste; + +pub use crate::{ + constants::{PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD}, + xcm_helpers::xcm_transact_unpaid_execution, + BridgeHubRococo, BridgeHubWococo, +}; + +// Substrate +pub use frame_support::{assert_ok, traits::fungibles::Inspect}; +pub use pallet_assets; +pub use pallet_message_queue; +use sp_core::Get; + +// Cumulus use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, LaneId, MessageKey, OutboundLaneData, }; use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; -use codec::Decode; -pub use cumulus_primitives_core::{DmpMessageHandler, XcmpMessageHandler}; +pub use cumulus_pallet_dmp_queue; +pub use cumulus_pallet_parachain_system; +pub use cumulus_pallet_xcmp_queue; +pub use cumulus_primitives_core::{ + relay_chain::HrmpChannelId, DmpMessageHandler, ParaId, XcmpMessageHandler, +}; use pallet_bridge_messages::{Config, Instance1, Instance2, OutboundLanes, Pallet}; -use sp_core::Get; -use xcm_emulator::{BridgeMessage, BridgeMessageDispatchError, BridgeMessageHandler, Chain}; +pub use parachains_common::{AccountId, Balance}; +pub use xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, BridgeMessage, + BridgeMessageDispatchError, BridgeMessageHandler, Chain, Parachain, RelayChain, TestExt, +}; + +// Polkadot +pub use pallet_xcm; +pub use polkadot_runtime_parachains::{ + dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, +}; +pub use xcm::{ + prelude::{OriginKind, Outcome, VersionedXcm, Weight}, + v3::Error, + DoubleEncoded, +}; pub struct BridgeHubMessageHandler { _marker: std::marker::PhantomData<(S, T, I)>, @@ -145,14 +178,14 @@ where #[macro_export] macro_rules! impl_accounts_helpers_for_relay_chain { ( $chain:ident ) => { - $crate::paste::paste! { + $crate::impls::paste::paste! { impl $chain { /// Fund a set of accounts with a balance - pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { - Self::execute_with(|| { + pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { + ::execute_with(|| { for account in accounts { - assert_ok!(]>::Balances::force_set_balance( - ::RuntimeOrigin::root(), + $crate::impls::assert_ok!(]>::Balances::force_set_balance( + ::RuntimeOrigin::root(), account.0.into(), account.1, )); @@ -160,8 +193,8 @@ macro_rules! impl_accounts_helpers_for_relay_chain { }); } /// Fund a sovereign account based on its Parachain Id - pub fn fund_para_sovereign(amount: Balance, para_id: ParaId) -> sp_runtime::AccountId32 { - let sovereign_account = Self::sovereign_account_id_of_child_para(para_id); + pub fn fund_para_sovereign(amount: $crate::impls::Balance, para_id: $crate::impls::ParaId) -> sp_runtime::AccountId32 { + let sovereign_account = ::sovereign_account_id_of_child_para(para_id); Self::fund_accounts(vec![(sovereign_account.clone(), amount)]); sovereign_account } @@ -173,20 +206,20 @@ macro_rules! impl_accounts_helpers_for_relay_chain { #[macro_export] macro_rules! impl_assert_events_helpers_for_relay_chain { ( $chain:ident ) => { - $crate::paste::paste! { - type [<$chain RuntimeEvent>] = <$chain as Chain>::RuntimeEvent; + $crate::impls::paste::paste! { + type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; impl $chain { /// Asserts a dispatchable is completely executed and XCM sent - pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option) { - assert_expected_events!( + pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) { + $crate::impls::assert_expected_events!( Self, vec![ [<$chain RuntimeEvent>]::XcmPallet( - pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) } + $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -197,18 +230,18 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { /// Asserts a dispatchable is incompletely executed and XCM sent pub fn assert_xcm_pallet_attempted_incomplete( - expected_weight: Option, - expected_error: Option, + expected_weight: Option<$crate::impls::Weight>, + expected_error: Option<$crate::impls::Error>, ) { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ // Dispatchable is properly executed and XCM message sent [<$chain RuntimeEvent>]::XcmPallet( - pallet_xcm::Event::Attempted { outcome: Outcome::Incomplete(weight, error) } + $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -220,10 +253,10 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { /// Asserts a XCM message is sent pub fn assert_xcm_pallet_sent() { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + [<$chain RuntimeEvent>]::XcmPallet($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, ] ); } @@ -231,22 +264,22 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { /// Asserts a XCM from System Parachain is succesfully received and proccessed pub fn assert_ump_queue_processed( expected_success: bool, - expected_id: Option, - expected_weight: Option, + expected_id: Option<$crate::impls::ParaId>, + expected_weight: Option<$crate::impls::Weight>, ) { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ // XCM is succesfully received and proccessed - [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { - origin: AggregateMessageOrigin::Ump(UmpQueueId::Para(id)), + [<$chain RuntimeEvent>]::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { + origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)), weight_used, success, .. }) => { id: *id == expected_id.unwrap_or(*id), - weight_used: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight_used: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight_used), *weight_used ), @@ -263,16 +296,18 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { #[macro_export] macro_rules! impl_hrmp_channels_helpers_for_relay_chain { ( $chain:ident ) => { - $crate::paste::paste! { + $crate::impls::paste::paste! { impl $chain { /// Init open channel request with another Parachain pub fn init_open_channel_call( - recipient_para_id: ParaId, + recipient_para_id: $crate::impls::ParaId, max_capacity: u32, max_message_size: u32, - ) -> DoubleEncoded<()> { - ::RuntimeCall::Hrmp(polkadot_runtime_parachains::hrmp::Call::< - ::Runtime, + ) -> $crate::impls::DoubleEncoded<()> { + use $crate::impls::Encode; + + ::RuntimeCall::Hrmp($crate::impls::hrmp::Call::< + ::Runtime, >::hrmp_init_open_channel { recipient: recipient_para_id, proposed_max_capacity: max_capacity, @@ -282,9 +317,11 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { .into() } /// Recipient Parachain accept the open request from another Parachain - pub fn accept_open_channel_call(sender_para_id: ParaId) -> DoubleEncoded<()> { - ::RuntimeCall::Hrmp(polkadot_runtime_parachains::hrmp::Call::< - ::Runtime, + pub fn accept_open_channel_call(sender_para_id: $crate::impls::ParaId) -> $crate::impls::DoubleEncoded<()> { + use $crate::impls::Encode; + + ::RuntimeCall::Hrmp($crate::impls::hrmp::Call::< + ::Runtime, >::hrmp_accept_open_channel { sender: sender_para_id, }) @@ -293,19 +330,21 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { } /// A root origin force to open a channel between two Parachains - pub fn force_process_hrmp_open(sender: ParaId, recipient: ParaId) { - Self::execute_with(|| { + pub fn force_process_hrmp_open(sender: $crate::impls::ParaId, recipient: $crate::impls::ParaId) { + use $crate::impls::Chain; + + ::execute_with(|| { let relay_root_origin = ::RuntimeOrigin::root(); // Force process HRMP open channel requests without waiting for the next session - assert_ok!(]>::Hrmp::force_process_hrmp_open( + $crate::impls::assert_ok!(]>::Hrmp::force_process_hrmp_open( relay_root_origin, 0 )); - let channel_id = HrmpChannelId { sender, recipient }; + let channel_id = $crate::impls::HrmpChannelId { sender, recipient }; - let hrmp_channel_exist = polkadot_runtime_parachains::hrmp::HrmpChannels::< + let hrmp_channel_exist = $crate::impls::hrmp::HrmpChannels::< ::Runtime, >::contains_key(&channel_id); @@ -321,14 +360,14 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { #[macro_export] macro_rules! impl_accounts_helpers_for_parachain { ( $chain:ident ) => { - $crate::paste::paste! { + $crate::impls::paste::paste! { impl $chain { /// Fund a set of accounts with a balance - pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { - Self::execute_with(|| { + pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { + ::execute_with(|| { for account in accounts { - assert_ok!(]>::Balances::force_set_balance( - ::RuntimeOrigin::root(), + $crate::impls::assert_ok!(]>::Balances::force_set_balance( + ::RuntimeOrigin::root(), account.0.into(), account.1, )); @@ -343,20 +382,20 @@ macro_rules! impl_accounts_helpers_for_parachain { #[macro_export] macro_rules! impl_assert_events_helpers_for_parachain { ( $chain:ident ) => { - $crate::paste::paste! { - type [<$chain RuntimeEvent>] = <$chain as Chain>::RuntimeEvent; + $crate::impls::paste::paste! { + type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; impl $chain { /// Asserts a dispatchable is completely executed and XCM sent - pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option) { - assert_expected_events!( + pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) { + $crate::impls::assert_expected_events!( Self, vec![ [<$chain RuntimeEvent>]::PolkadotXcm( - pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) } + $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -367,18 +406,18 @@ macro_rules! impl_assert_events_helpers_for_parachain { /// Asserts a dispatchable is incompletely executed and XCM sent pub fn assert_xcm_pallet_attempted_incomplete( - expected_weight: Option, - expected_error: Option, + expected_weight: Option<$crate::impls::Weight>, + expected_error: Option<$crate::impls::Error>, ) { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ // Dispatchable is properly executed and XCM message sent [<$chain RuntimeEvent>]::PolkadotXcm( - pallet_xcm::Event::Attempted { outcome: Outcome::Incomplete(weight, error) } + $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -389,13 +428,13 @@ macro_rules! impl_assert_events_helpers_for_parachain { } /// Asserts a dispatchable throws and error when trying to be sent - pub fn assert_xcm_pallet_attempted_error(expected_error: Option) { - assert_expected_events!( + pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::Error>) { + $crate::impls::assert_expected_events!( Self, vec![ // Execution fails in the origin with `Barrier` [<$chain RuntimeEvent>]::PolkadotXcm( - pallet_xcm::Event::Attempted { outcome: Outcome::Error(error) } + $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error(error) } ) => { error: *error == expected_error.unwrap_or(*error), }, @@ -405,36 +444,36 @@ macro_rules! impl_assert_events_helpers_for_parachain { /// Asserts a XCM message is sent pub fn assert_xcm_pallet_sent() { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, + [<$chain RuntimeEvent>]::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, ] ); } /// Asserts a XCM message is sent to Relay Chain pub fn assert_parachain_system_ump_sent() { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ [<$chain RuntimeEvent>]::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + $crate::impls::cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } ) => {}, ] ); } /// Asserts a XCM from Relay Chain is completely executed - pub fn assert_dmp_queue_complete(expected_weight: Option) { - assert_expected_events!( + pub fn assert_dmp_queue_complete(expected_weight: Option<$crate::impls::Weight>) { + $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Complete(weight), .. + [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: $crate::impls::Outcome::Complete(weight), .. }) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -445,17 +484,17 @@ macro_rules! impl_assert_events_helpers_for_parachain { /// Asserts a XCM from Relay Chain is incompletely executed pub fn assert_dmp_queue_incomplete( - expected_weight: Option, - expected_error: Option, + expected_weight: Option<$crate::impls::Weight>, + expected_error: Option<$crate::impls::Error>, ) { - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Incomplete(weight, error), .. + [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: $crate::impls::Outcome::Incomplete(weight, error), .. }) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -466,15 +505,15 @@ macro_rules! impl_assert_events_helpers_for_parachain { } /// Asserts a XCM from another Parachain is completely executed - pub fn assert_xcmp_queue_success(expected_weight: Option) { - assert_expected_events!( + pub fn assert_xcmp_queue_success(expected_weight: Option<$crate::impls::Weight>) { + $crate::impls::assert_expected_events!( Self, vec![ [<$chain RuntimeEvent>]::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::Success { weight, .. } + $crate::impls::cumulus_pallet_xcmp_queue::Event::Success { weight, .. } ) => { - weight: weight_within_threshold( - (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + weight: $crate::impls::weight_within_threshold( + ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), @@ -490,18 +529,20 @@ macro_rules! impl_assert_events_helpers_for_parachain { #[macro_export] macro_rules! impl_assets_helpers_for_parachain { ( $chain:ident, $relay_chain:ident ) => { - $crate::paste::paste! { + $crate::impls::paste::paste! { impl $chain { /// Returns the encoded call for `force_create` from the assets pallet pub fn force_create_asset_call( asset_id: u32, - owner: AccountId, + owner: $crate::impls::AccountId, is_sufficient: bool, - min_balance: Balance, - ) -> DoubleEncoded<()> { - ::RuntimeCall::Assets(pallet_assets::Call::< + min_balance: $crate::impls::Balance, + ) -> $crate::impls::DoubleEncoded<()> { + use $crate::impls::{Chain, Encode}; + + ::RuntimeCall::Assets($crate::impls::pallet_assets::Call::< ::Runtime, - Instance1, + $crate::impls::pallet_assets::Instance1, >::force_create { id: asset_id.into(), owner: owner.into(), @@ -514,37 +555,37 @@ macro_rules! impl_assets_helpers_for_parachain { /// Returns a `VersionedXcm` for `force_create` from the assets pallet pub fn force_create_asset_xcm( - origin_kind: OriginKind, + origin_kind: $crate::impls::OriginKind, asset_id: u32, - owner: AccountId, + owner: $crate::impls::AccountId, is_sufficient: bool, - min_balance: Balance, - ) -> VersionedXcm<()> { + min_balance: $crate::impls::Balance, + ) -> $crate::impls::VersionedXcm<()> { let call = Self::force_create_asset_call(asset_id, owner, is_sufficient, min_balance); - xcm_transact_unpaid_execution(call, origin_kind) + $crate::impls::xcm_transact_unpaid_execution(call, origin_kind) } /// Mint assets making use of the assets pallet pub fn mint_asset( - signed_origin: ::RuntimeOrigin, + signed_origin: ::RuntimeOrigin, id: u32, - beneficiary: AccountId, + beneficiary: $crate::impls::AccountId, amount_to_mint: u128, ) { - Self::execute_with(|| { - assert_ok!(]>::Assets::mint( + ::execute_with(|| { + $crate::impls::assert_ok!(]>::Assets::mint( signed_origin, id.into(), beneficiary.clone().into(), amount_to_mint )); - type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + RuntimeEvent::Assets($crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }) => { asset_id: *asset_id == id, owner: *owner == beneficiary.clone().into(), amount: *amount == amount_to_mint, @@ -559,14 +600,15 @@ macro_rules! impl_assets_helpers_for_parachain { id: u32, min_balance: u128, is_sufficient: bool, - asset_owner: AccountId, + asset_owner: $crate::impls::AccountId, 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( - OriginKind::Superuser, + $crate::impls::OriginKind::Superuser, id, asset_owner.clone(), is_sufficient, @@ -574,7 +616,7 @@ macro_rules! impl_assets_helpers_for_parachain { ); <$relay_chain>::execute_with(|| { - assert_ok!(<$relay_chain as [<$relay_chain Pallet>]>::XcmPallet::send( + $crate::impls::assert_ok!(<$relay_chain as [<$relay_chain Pallet>]>::XcmPallet::send( root_origin, bx!(destination.into()), bx!(xcm), @@ -584,15 +626,15 @@ macro_rules! impl_assets_helpers_for_parachain { }); Self::execute_with(|| { - Self::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_445_000, 200_000))); + Self::assert_dmp_queue_complete(Some($crate::impls::Weight::from_parts(1_019_445_000, 200_000))); - type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; - assert_expected_events!( + $crate::impls::assert_expected_events!( Self, vec![ // Asset has been created - RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { + RuntimeEvent::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => { asset_id: *asset_id == id, owner: *owner == asset_owner.clone(), }, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index a5d80cafd7f..49751136f7b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -14,46 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -pub use lazy_static; pub mod constants; pub mod impls; +pub mod xcm_helpers; -pub use codec::Encode; -pub use constants::{ +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, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, -}; -use frame_support::{ - assert_ok, - instances::Instance1, - parameter_types, - traits::{fungibles::Inspect, Hooks}, -}; -pub use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; -pub use parachains_common::{AccountId, Balance}; -pub use paste; -use polkadot_parachain_primitives::primitives::HrmpChannelId; -use polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::ParachainHostV6; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; -pub use sp_core::{sr25519, storage::Storage, Get}; -use sp_tracing; -use xcm_emulator::{ - assert_expected_events, bx, decl_test_bridges, decl_test_networks, decl_test_parachains, - decl_test_relay_chains, decl_test_sender_receiver_accounts_parameter_types, - helpers::weight_within_threshold, BridgeMessageHandler, Chain, DefaultMessageProcessor, ParaId, - Parachain, RelayChain, TestExt, }; +use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; -pub use xcm::{ - prelude::{ - AccountId32, All, BuyExecution, DepositAsset, MultiAsset, MultiAssets, MultiLocation, - OriginKind, Outcome, RefundSurplus, Transact, UnpaidExecution, VersionedXcm, Weight, - WeightLimit, WithdrawAsset, Xcm, X1, - }, - v3::Error, - DoubleEncoded, +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use xcm_emulator::{ + decl_test_bridges, decl_test_networks, decl_test_parachains, decl_test_relay_chains, + decl_test_sender_receiver_accounts_parameter_types, DefaultMessageProcessor, }; decl_test_relay_chains! { @@ -87,7 +65,7 @@ decl_test_relay_chains! { Hrmp: kusama_runtime::Hrmp, } }, - #[api_version(5)] + #[api_version(6)] pub struct Westend { genesis = westend::genesis(), on_init = (), @@ -582,44 +560,3 @@ decl_test_sender_receiver_accounts_parameter_types! { PenpalWestendA { sender: ALICE, receiver: BOB }, PenpalRococoA { sender: ALICE, receiver: BOB } } - -/// Helper method to build a XCM with a `Transact` instruction and paying for its execution -pub fn xcm_transact_paid_execution( - call: DoubleEncoded<()>, - origin_kind: OriginKind, - native_asset: MultiAsset, - beneficiary: AccountId, -) -> VersionedXcm<()> { - let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let native_assets: MultiAssets = native_asset.clone().into(); - - VersionedXcm::from(Xcm(vec![ - WithdrawAsset(native_assets), - BuyExecution { fees: native_asset, weight_limit }, - Transact { require_weight_at_most, origin_kind, call }, - RefundSurplus, - DepositAsset { - assets: All.into(), - beneficiary: MultiLocation { - parents: 0, - interior: X1(AccountId32 { network: None, id: beneficiary.into() }), - }, - }, - ])) -} - -/// Helper method to build a XCM with a `Transact` instruction without paying for its execution -pub fn xcm_transact_unpaid_execution( - call: DoubleEncoded<()>, - origin_kind: OriginKind, -) -> VersionedXcm<()> { - let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let check_origin = None; - - VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - Transact { require_weight_at_most, origin_kind, call }, - ])) -} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs new file mode 100644 index 00000000000..4096cdbba0b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -0,0 +1,66 @@ +// 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 . + +use parachains_common::AccountId; +use xcm::{ + prelude::{ + AccountId32, All, BuyExecution, DepositAsset, MultiAsset, MultiAssets, MultiLocation, + OriginKind, RefundSurplus, Transact, UnpaidExecution, VersionedXcm, Weight, WeightLimit, + WithdrawAsset, Xcm, X1, + }, + DoubleEncoded, +}; + +/// Helper method to build a XCM with a `Transact` instruction and paying for its execution +pub fn xcm_transact_paid_execution( + call: DoubleEncoded<()>, + origin_kind: OriginKind, + native_asset: MultiAsset, + beneficiary: AccountId, +) -> VersionedXcm<()> { + let weight_limit = WeightLimit::Unlimited; + let require_weight_at_most = Weight::from_parts(1000000000, 200000); + let native_assets: MultiAssets = native_asset.clone().into(); + + VersionedXcm::from(Xcm(vec![ + WithdrawAsset(native_assets), + BuyExecution { fees: native_asset, weight_limit }, + Transact { require_weight_at_most, origin_kind, call }, + RefundSurplus, + DepositAsset { + assets: All.into(), + beneficiary: MultiLocation { + parents: 0, + interior: X1(AccountId32 { network: None, id: beneficiary.into() }), + }, + }, + ])) +} + +/// Helper method to build a XCM with a `Transact` instruction without paying for its execution +pub fn xcm_transact_unpaid_execution( + call: DoubleEncoded<()>, + origin_kind: OriginKind, +) -> VersionedXcm<()> { + let weight_limit = WeightLimit::Unlimited; + let require_weight_at_most = Weight::from_parts(1000000000, 200000); + let check_origin = None; + + VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit, check_origin }, + Transact { require_weight_at_most, origin_kind, call }, + ])) +} diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index c95c2f70313..72007ba98f7 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -21,16 +21,13 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-std = { path = "../../../substrate/primitives/std" } sp-runtime = { path = "../../../substrate/primitives/runtime" } sp-arithmetic = { path = "../../../substrate/primitives/arithmetic" } -sp-trie = { path = "../../../substrate/primitives/trie" } +sp-tracing = { path = "../../../substrate/primitives/tracing" } pallet-balances = { path = "../../../substrate/frame/balances" } pallet-message-queue = { path = "../../../substrate/frame/message-queue" } # Cumulus cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue" } -cumulus-pallet-dmp-queue = { path = "../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system" } -parachain-info = { path = "../../parachains/pallets/parachain-info" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } parachains-common = { path = "../../parachains/common" } @@ -39,4 +36,5 @@ parachains-common = { path = "../../parachains/common" } xcm = { package = "staging-xcm", path = "../../../polkadot/xcm" } xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor" } polkadot-primitives = { path = "../../../polkadot/primitives" } +polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 261d4ad7924..59f238528fc 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -19,61 +19,45 @@ pub use lazy_static::lazy_static; pub use log; pub use paste; pub use std::{ - any::type_name, - collections::HashMap, - error::Error, - fmt, - marker::PhantomData, - ops::Deref, - sync::{Condvar, Mutex}, - thread::LocalKey, + any::type_name, collections::HashMap, error::Error, fmt, marker::PhantomData, ops::Deref, + sync::Mutex, }; // Substrate pub use frame_support::{ assert_ok, - sp_runtime::{AccountId32, DispatchResult}, + sp_runtime::{traits::Header as HeaderT, AccountId32, DispatchResult}, traits::{ - tokens::currency::Currency, EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, - ProcessMessageError, ServiceQueues, + EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues, }, weights::{Weight, WeightMeter}, - StorageHasher, }; -pub use frame_system::{AccountInfo, Config as SystemConfig, Pallet as SystemPallet}; +pub use frame_system::{Config as SystemConfig, Pallet as SystemPallet}; pub use pallet_balances::AccountData; pub use sp_arithmetic::traits::Bounded; -pub use sp_core::{sr25519, storage::Storage, Pair, H256}; +pub use sp_core::{blake2_256, parameter_types, sr25519, storage::Storage, Pair}; pub use sp_io::TestExternalities; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, fmt::Debug}; -pub use sp_trie::StorageProof; +pub use sp_tracing; -//Cumulus -pub use cumulus_pallet_dmp_queue; -pub use cumulus_pallet_parachain_system::{self, Pallet as ParachainSystemPallet}; -pub use cumulus_pallet_xcmp_queue::{Config as XcmpQueueConfig, Pallet as XcmpQueuePallet}; +// Cumulus +pub use cumulus_pallet_parachain_system::Pallet as ParachainSystemPallet; pub use cumulus_primitives_core::{ - self, - relay_chain::{BlockNumber as RelayBlockNumber, HeadData}, - DmpMessageHandler, ParaId, PersistedValidationData, XcmpMessageHandler, + relay_chain::{BlockNumber as RelayBlockNumber, HeadData, HrmpChannelId}, + AbridgedHrmpChannel, DmpMessageHandler, ParaId, PersistedValidationData, XcmpMessageHandler, }; pub use cumulus_primitives_parachain_inherent::ParachainInherentData; pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; -pub use pallet_message_queue::{ - Config as MessageQueueConfig, Event as MessageQueueEvent, Pallet as MessageQueuePallet, -}; -pub use parachain_info; +pub use pallet_message_queue::{Config as MessageQueueConfig, Pallet as MessageQueuePallet}; pub use parachains_common::{AccountId, Balance, BlockNumber}; pub use polkadot_primitives; -pub use polkadot_runtime_parachains::{ - dmp, - inclusion::{AggregateMessageOrigin, UmpQueueId}, -}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; // Polkadot -pub use xcm::{ - v3::prelude::{AccountId32 as AccountId32Junction, Parachain as ParachainJunction, *}, - VersionedMultiAssets, VersionedMultiLocation, +pub use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; +pub use xcm::v3::prelude::{ + Ancestor, MultiAssets, MultiLocation, Parachain as ParachainJunction, Parent, WeightLimit, + XcmHash, X1, }; pub use xcm_executor::traits::ConvertLocation; @@ -362,23 +346,24 @@ macro_rules! decl_test_relay_chains { } ), + + $(,)? ) => { $( #[derive(Clone)] pub struct $name; - impl Chain for $name { + impl $crate::Chain for $name { type Runtime = $runtime::Runtime; type RuntimeCall = $runtime::RuntimeCall; type RuntimeOrigin = $runtime::RuntimeOrigin; type RuntimeEvent = $runtime::RuntimeEvent; type System = $crate::SystemPallet::; - fn account_data_of(account: AccountId) -> $crate::AccountData { - Self::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) + fn account_data_of(account: $crate::AccountId) -> $crate::AccountData<$crate::Balance> { + ::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) } - fn events() -> Vec<::RuntimeEvent> { + fn events() -> Vec<::RuntimeEvent> { Self::System::events() .iter() .map(|record| record.event.clone()) @@ -386,7 +371,7 @@ macro_rules! decl_test_relay_chains { } } - impl RelayChain for $name { + impl $crate::RelayChain for $name { type SovereignAccountOf = $sovereign_acc_of; type MessageProcessor = $mp; } @@ -430,7 +415,7 @@ macro_rules! __impl_test_ext_for_relay_chain { (@impl $name:ident, $genesis:expr, $on_init:expr, $api_version:ident, $local_ext:ident, $global_ext:ident) => { thread_local! { pub static $local_ext: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new(<$name>::build_new_ext($genesis)); + = $crate::RefCell::new(<$name as $crate::TestExt>::build_new_ext($genesis)); } $crate::lazy_static! { @@ -438,11 +423,11 @@ macro_rules! __impl_test_ext_for_relay_chain { = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); } - impl TestExt for $name { + impl $crate::TestExt for $name { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { - use $crate::{NetworkComponent, Network, Chain}; + use $crate::{sp_tracing, NetworkComponent, Network, Chain, TestExternalities}; - let mut ext = $crate::TestExternalities::new(storage); + let mut ext = TestExternalities::new(storage); ext.execute_with(|| { #[allow(clippy::no_effect)] @@ -512,7 +497,7 @@ macro_rules! __impl_test_ext_for_relay_chain { } fn execute_with(execute: impl FnOnce() -> R) -> R { - use $crate::{NetworkComponent, Network}; + use $crate::{Chain, NetworkComponent, Network}; // Make sure the Network is initialized <$name as NetworkComponent>::Network::init(); @@ -527,7 +512,7 @@ macro_rules! __impl_test_ext_for_relay_chain { //TODO: mark sent count & filter out sent msg for para_id in<$name as NetworkComponent>::Network::para_ids() { // downward messages - let downward_messages = ::Runtime::dmq_contents(para_id.into()) + let downward_messages = ::Runtime::dmq_contents(para_id.into()) .into_iter() .map(|inbound| (inbound.sent_at, inbound.msg)); if downward_messages.len() == 0 { @@ -586,23 +571,24 @@ macro_rules! decl_test_parachains { } ), + + $(,)? ) => { $( #[derive(Clone)] pub struct $name; - impl Chain for $name { + impl $crate::Chain for $name { type Runtime = $runtime::Runtime; type RuntimeCall = $runtime::RuntimeCall; type RuntimeOrigin = $runtime::RuntimeOrigin; type RuntimeEvent = $runtime::RuntimeEvent; type System = $crate::SystemPallet::; - fn account_data_of(account: AccountId) -> $crate::AccountData { - Self::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) + fn account_data_of(account: $crate::AccountId) -> $crate::AccountData<$crate::Balance> { + ::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) } - fn events() -> Vec<::RuntimeEvent> { + fn events() -> Vec<::RuntimeEvent> { Self::System::events() .iter() .map(|record| record.event.clone()) @@ -610,25 +596,25 @@ macro_rules! decl_test_parachains { } } - impl Parachain for $name { + impl $crate::Parachain for $name { type XcmpMessageHandler = $xcmp_message_handler; type DmpMessageHandler = $dmp_message_handler; type LocationToAccountId = $location_to_account; - type ParachainSystem = $crate::ParachainSystemPallet<::Runtime>; + type ParachainSystem = $crate::ParachainSystemPallet<::Runtime>; type ParachainInfo = $parachain_info; fn init() { - use $crate::{Network, NetworkComponent, Hooks}; + use $crate::{Chain, HeadData, Network, NetworkComponent, Hooks, Encode, Parachain, TestExt}; let para_id = Self::para_id(); - ::ext_wrapper(|| { + Self::ext_wrapper(|| { let block_number = ::System::block_number(); let mut relay_block_number = ::Network::relay_block_number(); // Get parent head data let header = ::System::finalize(); - let parent_head_data = $crate::HeadData(header.encode()); + let parent_head_data = HeadData(header.encode()); $crate::LAST_HEAD.with(|b| b.borrow_mut() .get_mut(::Network::name()) @@ -638,7 +624,7 @@ macro_rules! decl_test_parachains { let next_block_number = block_number + 1; ::System::initialize(&next_block_number, &header.hash(), &Default::default()); - ::ParachainSystem::on_initialize(next_block_number); + <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(next_block_number); }); } } @@ -675,7 +661,7 @@ macro_rules! __impl_test_ext_for_parachain { (@impl $name:ident, $genesis:expr, $on_init:expr, $local_ext:ident, $global_ext:ident) => { thread_local! { pub static $local_ext: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new(<$name>::build_new_ext($genesis)); + = $crate::RefCell::new(<$name as $crate::TestExt>::build_new_ext($genesis)); } $crate::lazy_static! { @@ -683,20 +669,18 @@ macro_rules! __impl_test_ext_for_parachain { = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); } - impl TestExt for $name { + impl $crate::TestExt for $name { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { - use $crate::{NetworkComponent, Network, Chain}; - let mut ext = $crate::TestExternalities::new(storage); ext.execute_with(|| { #[allow(clippy::no_effect)] $on_init; - sp_tracing::try_init_simple(); + $crate::sp_tracing::try_init_simple(); - let mut block_number = ::System::block_number(); + let mut block_number = ::System::block_number(); block_number = std::cmp::max(1, block_number); - ::System::set_block_number(block_number); + ::System::set_block_number(block_number); }); ext } @@ -757,10 +741,7 @@ macro_rules! __impl_test_ext_for_parachain { } fn execute_with(execute: impl FnOnce() -> R) -> R { - use $crate::{Get, Hooks, NetworkComponent, Network, Bridge}; - use sp_core::Encode; - use sp_runtime::traits::BlakeTwo256; - use polkadot_primitives::HashT; + use $crate::{Chain, Get, Hooks, NetworkComponent, Network, Parachain, Encode}; // Make sure the Network is initialized <$name as NetworkComponent>::Network::init(); @@ -801,10 +782,8 @@ macro_rules! __impl_test_ext_for_parachain { // Finalize block and send messages if needed $local_ext.with(|v| { v.borrow_mut().execute_with(|| { - use sp_runtime::traits::Header as HeaderT; - let block_number = ::System::block_number(); - let mock_header = HeaderT::new( + let mock_header = $crate::HeaderT::new( 0, Default::default(), Default::default(), @@ -839,9 +818,9 @@ macro_rules! __impl_test_ext_for_parachain { } // get bridge messages - type NetworkBridge = <<$name as NetworkComponent>::Network as Network>::Bridge; + type NetworkBridge = <<$name as NetworkComponent>::Network as $crate::Network>::Bridge; - let bridge_messages = ::Handler::get_source_outbound_messages(); + let bridge_messages = <::Handler as $crate::BridgeMessageHandler>::get_source_outbound_messages(); // send bridged messages for msg in bridge_messages { @@ -849,17 +828,17 @@ macro_rules! __impl_test_ext_for_parachain { } // log events - Self::events().iter().for_each(|event| { + ::events().iter().for_each(|event| { $crate::log::debug!(target: concat!("events::", stringify!($name)), "{:?}", event); }); // clean events - ::System::reset_events(); + ::System::reset_events(); // reinitialize before next call. let next_block_number = block_number + 1; - ::System::initialize(&next_block_number, &created_header.hash(), &Default::default()); - ::ParachainSystem::on_initialize(next_block_number); + ::System::initialize(&next_block_number, &created_header.hash(), &Default::default()); + <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(next_block_number); }) }); @@ -894,6 +873,7 @@ macro_rules! decl_test_networks { } ), + + $(,)? ) => { $( pub struct $name; @@ -907,7 +887,7 @@ macro_rules! decl_test_networks { } fn reset() { - use $crate::{TestExt, VecDeque}; + use $crate::{TestExt}; $crate::INITIALIZED.with(|b| b.borrow_mut().remove(Self::name())); $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); @@ -933,25 +913,25 @@ macro_rules! decl_test_networks { $crate::PARA_IDS.with(|b| b.borrow_mut().insert(Self::name().to_string(), Self::para_ids())); $crate::LAST_HEAD.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::HashMap::new())); - $( <$parachain>::init(); )* + $( <$parachain as $crate::Parachain>::init(); )* } } fn para_ids() -> Vec { vec![$( - <$parachain>::para_id().into(), + <$parachain as $crate::Parachain>::para_id().into(), )*] } fn relay_block_number() -> u32 { - Self::Relay::ext_wrapper(|| { - ::System::block_number() + ::ext_wrapper(|| { + ::System::block_number() }) } fn set_relay_block_number(number: u32) { - Self::Relay::ext_wrapper(|| { - ::System::set_block_number(number); + ::ext_wrapper(|| { + ::System::set_block_number(number); }) } @@ -972,8 +952,7 @@ macro_rules! decl_test_networks { } fn process_downward_messages() { - use $crate::{DmpMessageHandler, Bounded}; - use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; + use $crate::{DmpMessageHandler, Bounded, Parachain, RelayChainBlockNumber, TestExt}; while let Some((to_para_id, messages)) = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { @@ -1005,7 +984,7 @@ macro_rules! decl_test_networks { } fn process_horizontal_messages() { - use $crate::{XcmpMessageHandler, Bounded}; + use $crate::{XcmpMessageHandler, Bounded, Parachain, TestExt}; while let Some((to_para_id, messages)) = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { @@ -1024,16 +1003,16 @@ macro_rules! decl_test_networks { } fn process_upward_messages() { - use $crate::{Bounded, ProcessMessage, WeightMeter}; - use sp_core::Encode; + use $crate::{Encode, ProcessMessage, TestExt}; + while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { - let mut weight_meter = WeightMeter::new(); + let mut weight_meter = $crate::WeightMeter::new(); <$relay_chain>::ext_wrapper(|| { - let _ = <$relay_chain as RelayChain>::MessageProcessor::process_message( + let _ = <$relay_chain as $crate::RelayChain>::MessageProcessor::process_message( &msg[..], from_para_id.into(), &mut weight_meter, - &mut msg.using_encoded(sp_core::blake2_256), + &mut msg.using_encoded($crate::blake2_256), ); }); $crate::log::debug!(target: concat!("ump::", stringify!($name)) , "Upward message processed {:?} from para_id {:?}", &msg, &from_para_id); @@ -1041,19 +1020,19 @@ macro_rules! decl_test_networks { } fn process_bridged_messages() { - use $crate::Bridge; + use $crate::{Bridge, BridgeMessageHandler, TestExt}; // Make sure both, including the target `Network` are initialized ::init(); while let Some(msg) = $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { - let dispatch_result = <::Target as TestExt>::ext_wrapper(|| { + let dispatch_result = <::Target as TestExt>::ext_wrapper(|| { <::Handler as BridgeMessageHandler>::dispatch_target_inbound_message(msg.clone()) }); match dispatch_result { Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg.clone()), Ok(()) => { - <::Source as TestExt>::ext_wrapper(|| { + <::Source as TestExt>::ext_wrapper(|| { <::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.id); }); $crate::log::debug!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg.clone()); @@ -1067,8 +1046,6 @@ macro_rules! decl_test_networks { relay_parent_number: u32, parent_head_data: $crate::HeadData, ) -> $crate::ParachainInherentData { - use $crate::cumulus_primitives_core::{relay_chain::{HeadData, HrmpChannelId}, AbridgedHrmpChannel}; - let mut sproof = $crate::RelayStateSproofBuilder::default(); sproof.para_id = para_id.into(); @@ -1084,11 +1061,11 @@ macro_rules! decl_test_networks { sproof .hrmp_channels - .entry(HrmpChannelId { + .entry($crate::HrmpChannelId { sender: sproof.para_id, recipient: recipient_para_id, }) - .or_insert_with(|| AbridgedHrmpChannel { + .or_insert_with(|| $crate::AbridgedHrmpChannel { max_capacity: 1024, max_total_size: 1024 * 1024, max_message_size: 1024 * 1024, @@ -1138,6 +1115,7 @@ macro_rules! decl_test_bridges { } ), + + $(,)? ) => { $( #[derive(Debug)] @@ -1165,8 +1143,8 @@ macro_rules! __impl_check_assertion { impl $crate::CheckAssertion for $chain where - Origin: Chain + Clone, - Destination: Chain + Clone, + Origin: $crate::Chain + Clone, + Destination: $crate::Chain + Clone, Origin::RuntimeOrigin: $crate::OriginTrait + Clone, Destination::RuntimeOrigin: $crate::OriginTrait + Clone, @@ -1174,6 +1152,8 @@ macro_rules! __impl_check_assertion { Args: Clone, { fn check_assertion(test: $crate::Test) { + use $crate::TestExt; + let chain_name = std::any::type_name::<$chain>(); <$chain>::execute_with(|| { @@ -1193,7 +1173,7 @@ macro_rules! __impl_check_assertion { macro_rules! assert_expected_events { ( $chain:ident, vec![$( $event_pat:pat => { $($attr:ident : $condition:expr, )* }, )*] ) => { let mut message: Vec = Vec::new(); - let mut events = <$chain>::events(); + let mut events = <$chain as $crate::Chain>::events(); $( let mut event_received = false; @@ -1256,7 +1236,7 @@ macro_rules! assert_expected_events { if !message.is_empty() { // Log events as they will not be logged after the panic - <$chain>::events().iter().for_each(|event| { + <$chain as $crate::Chain>::events().iter().for_each(|event| { $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); }); panic!("{}", message.concat()) @@ -1275,10 +1255,10 @@ macro_rules! bx { macro_rules! decl_test_sender_receiver_accounts_parameter_types { ( $( $chain:ident { sender: $sender:expr, receiver: $receiver:expr }),+ ) => { $crate::paste::paste! { - parameter_types! { + $crate::parameter_types! { $( - pub [<$chain Sender>]: $crate::AccountId = <$chain>::account_id_of($sender); - pub [<$chain Receiver>]: $crate::AccountId = <$chain>::account_id_of($receiver); + pub [<$chain Sender>]: $crate::AccountId = <$chain as $crate::Chain>::account_id_of($sender); + pub [<$chain Receiver>]: $crate::AccountId = <$chain as $crate::Chain>::account_id_of($receiver); )+ } } -- GitLab From 15cb0af58c1178736dd13db9f1602b2a31158cb9 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 1 Sep 2023 13:27:18 +0200 Subject: [PATCH 049/633] Added short-benchmarks for cumulus (#1183) * Added short-benchmarks for cumulus * Added `--bin` flag for short-benchmarks * fix dependency for short-benchmark-cumulus * Fixed benchmark with new XCM::V3 `MAX_INSTRUCTIONS_TO_DECODE` * Fixed benchmark for bridge messages pallets --------- Co-authored-by: alvicsam Co-authored-by: Javier Viola Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .gitlab/pipeline/build.yml | 15 +++- .gitlab/pipeline/short-benchmarks.yml | 62 +++++++++++++ .../src/messages_benchmarking.rs | 87 ++++++++++++++----- .../modules/messages/src/weights_ext.rs | 4 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 10 ++- 5 files changed, 151 insertions(+), 27 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 6ea153ff6da..636f7e47afa 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -146,7 +146,7 @@ build-short-benchmark: - .run-immediately - .collect-artifacts script: - - cargo build --profile release --locked --features=runtime-benchmarks + - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot - mkdir -p artifacts - target/release/polkadot --version - cp ./target/release/polkadot ./artifacts/ @@ -265,6 +265,19 @@ build-runtime-testing: - job: build-runtime-starters artifacts: false +build-short-benchmark-cumulus: + stage: build + extends: + - .docker-env + - .common-refs + - .run-immediately + - .collect-artifacts + script: + - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot-parachain + - mkdir -p artifacts + - target/release/polkadot-parachain --version + - cp ./target/release/polkadot-parachain ./artifacts/ + # substrate build-linux-substrate: diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 2993338cabb..81601fba32a 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -2,6 +2,9 @@ # Here are all jobs that are executed during "short-benchmarks" stage # Run all pallet benchmarks only once to check if there are any errors + +# run short-benchmarks for relay chain runtimes from polkadot + short-benchmark-polkadot: &short-bench stage: short-benchmarks extends: @@ -12,6 +15,8 @@ short-benchmark-polkadot: &short-bench artifacts: true variables: RUNTIME: polkadot + tags: + - benchmark script: - ./artifacts/polkadot benchmark pallet --execution wasm --wasm-execution compiled --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 @@ -24,3 +29,60 @@ short-benchmark-westend: <<: *short-bench variables: RUNTIME: westend + +# run short-benchmarks for system parachain runtimes from cumulus + +.short-benchmark-cumulus: &short-bench-cumulus + stage: short-benchmarks + extends: + - .common-refs + - .docker-env + needs: + - job: build-short-benchmark-cumulus + artifacts: true + variables: + RUNTIME_CHAIN: benchmarked-runtime-chain + tags: + - benchmark + script: + - ./artifacts/polkadot-parachain benchmark pallet --wasm-execution compiled --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + +short-benchmark-asset-hub-polkadot: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: asset-hub-polkadot-dev + +short-benchmark-asset-hub-kusama: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: asset-hub-kusama-dev + +short-benchmark-asset-hub-westend: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: asset-hub-westend-dev + +short-benchmark-bridge-hub-polkadot: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: bridge-hub-polkadot-dev + +short-benchmark-bridge-hub-kusama: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: bridge-hub-kusama-dev + +short-benchmark-bridge-hub-rococo: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: bridge-hub-rococo-dev + +short-benchmark-collectives-polkadot: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: collectives-polkadot-dev + +short-benchmark-glutton-kusama: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: glutton-kusama-dev-1300 diff --git a/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs b/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs index 60f4bb17858..d80a88f1068 100644 --- a/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -29,7 +29,7 @@ use crate::{ }, }; -use bp_messages::storage_keys; +use bp_messages::{storage_keys, MessagePayload}; use bp_polkadot_core::parachains::ParaHash; use bp_runtime::{ record_all_trie_keys, Chain, Parachain, RawStorageProof, StorageProofSize, UnderlyingChainOf, @@ -45,8 +45,8 @@ use xcm::v3::prelude::*; /// Prepare inbound bridge message according to given message proof parameters. fn prepare_inbound_message( params: &MessageProofParams, - destination: InteriorMultiLocation, -) -> Vec { + successful_dispatch_message_generator: impl Fn(usize) -> MessagePayload, +) -> MessagePayload { // we only care about **this** message size when message proof needs to be `Minimal` let expected_size = match params.size { StorageProofSize::Minimal(size) => size as usize, @@ -58,20 +58,15 @@ fn prepare_inbound_message( return vec![0u8; expected_size] } - // else let's prepare successful message. For XCM bridge hubs, it is the message that - // will be pushed further to some XCM queue (XCMP/UMP) - let location = xcm::VersionedInteriorMultiLocation::V3(destination); - let location_encoded_size = location.encoded_size(); - - // we don't need to be super-precise with `expected_size` here - let xcm_size = expected_size.saturating_sub(location_encoded_size); - let xcm = xcm::VersionedXcm::<()>::V3(vec![Instruction::ClearOrigin; xcm_size].into()); - - // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor - // or public fields, so just tuple - // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed - // to the storage) - (location, xcm).encode().encode() + // else let's prepare successful message. + let msg = successful_dispatch_message_generator(expected_size); + assert!( + msg.len() >= expected_size, + "msg.len(): {} does not match expected_size: {}", + expected_size, + msg.len() + ); + msg } /// Prepare proof of messages for the `receive_messages_proof` call. @@ -84,7 +79,7 @@ fn prepare_inbound_message( /// function. pub fn prepare_message_proof_from_grandpa_chain( params: MessageProofParams, - message_destination: InteriorMultiLocation, + message_generator: impl Fn(usize) -> MessagePayload, ) -> (FromBridgedChainMessagesProof>>, Weight) where R: pallet_bridge_grandpa::Config>>, @@ -97,7 +92,7 @@ where params.message_nonces.clone(), params.outbound_lane_data.clone(), params.size, - prepare_inbound_message(¶ms, message_destination), + prepare_inbound_message(¶ms, message_generator), encode_all_messages, encode_lane_data, ); @@ -127,7 +122,7 @@ where /// `prepare_message_proof_from_grandpa_chain` function. pub fn prepare_message_proof_from_parachain( params: MessageProofParams, - message_destination: InteriorMultiLocation, + message_generator: impl Fn(usize) -> MessagePayload, ) -> (FromBridgedChainMessagesProof>>, Weight) where R: pallet_bridge_parachains::Config, @@ -141,7 +136,7 @@ where params.message_nonces.clone(), params.outbound_lane_data.clone(), params.size, - prepare_inbound_message(¶ms, message_destination), + prepare_inbound_message(¶ms, message_generator), encode_all_messages, encode_lane_data, ); @@ -291,3 +286,53 @@ where pallet_bridge_parachains::initialize_for_benchmarks::(bridged_header); (bridged_block_number, bridged_header_hash) } + +/// Returns callback which generates `BridgeMessage` from Polkadot XCM builder based on +/// `expected_message_size` for benchmark. +pub fn generate_xcm_builder_bridge_message_sample( + destination: InteriorMultiLocation, +) -> impl Fn(usize) -> MessagePayload { + move |expected_message_size| -> MessagePayload { + // For XCM bridge hubs, it is the message that + // will be pushed further to some XCM queue (XCMP/UMP) + let location = xcm::VersionedInteriorMultiLocation::V3(destination); + let location_encoded_size = location.encoded_size(); + + // we don't need to be super-precise with `expected_size` here + let xcm_size = expected_message_size.saturating_sub(location_encoded_size); + let xcm_data_size = xcm_size.saturating_sub( + // minus empty instruction size + xcm::v3::Instruction::<()>::ExpectPallet { + index: 0, + name: vec![], + module_name: vec![], + crate_major: 0, + min_crate_minor: 0, + } + .encoded_size(), + ); + + log::trace!( + target: "runtime::bridge-benchmarks", + "generate_xcm_builder_bridge_message_sample with expected_message_size: {}, location_encoded_size: {}, xcm_size: {}, xcm_data_size: {}", + expected_message_size, location_encoded_size, xcm_size, xcm_data_size, + ); + + let xcm = xcm::VersionedXcm::<()>::V3( + vec![xcm::v3::Instruction::<()>::ExpectPallet { + index: 0, + name: vec![42; xcm_data_size], + module_name: vec![], + crate_major: 0, + min_crate_minor: 0, + }] + .into(), + ); + + // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor + // or public fields, so just tuple + // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed + // to the storage) + (location, xcm).encode().encode() + } +} diff --git a/cumulus/bridges/modules/messages/src/weights_ext.rs b/cumulus/bridges/modules/messages/src/weights_ext.rs index 1be24a738a4..aeb3a581a69 100644 --- a/cumulus/bridges/modules/messages/src/weights_ext.rs +++ b/cumulus/bridges/modules/messages/src/weights_ext.rs @@ -29,8 +29,8 @@ pub const EXPECTED_DEFAULT_MESSAGE_LENGTH: u32 = 128; /// calls we're checking here would fit 1KB. const SIGNED_EXTENSIONS_SIZE: u32 = 1024; -/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at -/// Rialto chain. This mostly depends on number of entries (and their density) in the storage trie. +/// Number of extra bytes (excluding size of storage value itself) of storage proof. +/// This mostly depends on number of entries (and their density) in the storage trie. /// Some reserve is reserved to account future chain growth. pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; 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 db53867f094..a872e232730 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 @@ -1040,7 +1040,11 @@ impl_runtime_apis! { type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; - use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof_from_parachain, prepare_message_proof_from_parachain}; + use bridge_runtime_common::messages_benchmarking::{ + prepare_message_delivery_proof_from_parachain, + prepare_message_proof_from_parachain, + generate_xcm_builder_bridge_message_sample, + }; use pallet_bridge_messages::benchmarking::{ Config as BridgeMessagesConfig, Pallet as BridgeMessagesBench, @@ -1072,7 +1076,7 @@ impl_runtime_apis! { Runtime, BridgeGrandpaWococoInstance, bridge_hub_rococo_config::WithBridgeHubWococoMessageBridge, - >(params, X2(GlobalConsensus(Rococo), Parachain(42))) + >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Rococo), Parachain(42)))) } fn prepare_message_delivery_proof( @@ -1115,7 +1119,7 @@ impl_runtime_apis! { Runtime, BridgeGrandpaRococoInstance, bridge_hub_wococo_config::WithBridgeHubRococoMessageBridge, - >(params, X2(GlobalConsensus(Wococo), Parachain(42))) + >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Wococo), Parachain(42)))) } fn prepare_message_delivery_proof( -- GitLab From e165eacd58a7bdf27533db3f21cec412c325b8b7 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Fri, 1 Sep 2023 14:55:23 +0300 Subject: [PATCH 050/633] Logs: add extra debug log for negative rep changes (#1205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor and more debug Signed-off-by: Andrei Sandu * review Signed-off-by: Andrei Sandu * fix Signed-off-by: Andrei Sandu * 🤦 Signed-off-by: Andrei Sandu --------- Signed-off-by: Andrei Sandu --- polkadot/node/subsystem-util/src/reputation.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/polkadot/node/subsystem-util/src/reputation.rs b/polkadot/node/subsystem-util/src/reputation.rs index 89e3eb64df9..349a6425433 100644 --- a/polkadot/node/subsystem-util/src/reputation.rs +++ b/polkadot/node/subsystem-util/src/reputation.rs @@ -25,6 +25,7 @@ use std::{collections::HashMap, time::Duration}; /// Default delay for sending reputation changes pub const REPUTATION_CHANGE_INTERVAL: Duration = Duration::from_secs(30); +const LOG_TARGET: &'static str = "parachain::reputation-aggregator"; type BatchReputationChange = HashMap; @@ -75,6 +76,10 @@ impl ReputationAggregator { peer_id: PeerId, rep: UnifiedReputationChange, ) { + if rep.cost_or_benefit() < 0 { + gum::debug!(target: LOG_TARGET, peer = ?peer_id, ?rep, "Reduce reputation"); + } + if (self.send_immediately_if)(rep) { self.single_send(sender, peer_id, rep).await; } else { @@ -97,12 +102,8 @@ impl ReputationAggregator { } fn add(&mut self, peer_id: PeerId, rep: UnifiedReputationChange) { - if self.by_peer.is_none() { - self.by_peer = Some(HashMap::new()); - } - if let Some(ref mut by_peer) = self.by_peer { - add_reputation(by_peer, peer_id, rep) - } + let by_peer = self.by_peer.get_or_insert(HashMap::new()); + add_reputation(by_peer, peer_id, rep) } } -- GitLab From 24c41f10bb29857cc7fcb316d47ac055c15537f7 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 1 Sep 2023 14:33:15 +0200 Subject: [PATCH 051/633] Contracts: `seal0::balance` should return the free balance (#1254) --- .../frame/contracts/fixtures/balance.wat | 42 ++++++++++++++++ substrate/frame/contracts/fixtures/drain.wat | 35 +++++++++++-- substrate/frame/contracts/src/exec.rs | 8 ++- substrate/frame/contracts/src/tests.rs | 50 +++++++++++++++++++ 4 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 substrate/frame/contracts/fixtures/balance.wat diff --git a/substrate/frame/contracts/fixtures/balance.wat b/substrate/frame/contracts/fixtures/balance.wat new file mode 100644 index 00000000000..d86d5c4b1c6 --- /dev/null +++ b/substrate/frame/contracts/fixtures/balance.wat @@ -0,0 +1,42 @@ +(module + (import "seal0" "seal_balance" (func $seal_balance (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 8) reserved for $seal_balance output + + ;; [8, 16) length of the buffer for $seal_balance + (data (i32.const 8) "\08") + + ;; [16, inf) zero initialized + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "deploy")) + + (func (export "call") + (call $seal_balance (i32.const 0) (i32.const 8)) + + ;; Balance should be encoded as a u64. + (call $assert + (i32.eq + (i32.load (i32.const 8)) + (i32.const 8) + ) + ) + + ;; Assert the free balance to be zero. + (call $assert + (i64.eq + (i64.load (i32.const 0)) + (i64.const 0) + ) + ) + ) +) diff --git a/substrate/frame/contracts/fixtures/drain.wat b/substrate/frame/contracts/fixtures/drain.wat index 9f126898fac..cb8ff0aed61 100644 --- a/substrate/frame/contracts/fixtures/drain.wat +++ b/substrate/frame/contracts/fixtures/drain.wat @@ -1,14 +1,20 @@ (module (import "seal0" "seal_balance" (func $seal_balance (param i32 i32))) + (import "seal0" "seal_minimum_balance" (func $seal_minimum_balance (param i32 i32))) (import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 8) reserved for $seal_balance output - ;; [8, 16) length of the buffer + ;; [8, 16) length of the buffer for $seal_balance (data (i32.const 8) "\08") - ;; [16, inf) zero initialized + ;; [16, 24) reserved for $seal_minimum_balance + + ;; [24, 32) length of the buffer for $seal_minimum_balance + (data (i32.const 24) "\08") + + ;; [32, inf) zero initialized (func $assert (param i32) (block $ok @@ -33,13 +39,32 @@ ) ) - ;; Try to self-destruct by sending full balance to the 0 address. + ;; Get the minimum balance. + (call $seal_minimum_balance (i32.const 16) (i32.const 24)) + + ;; Minimum balance should be encoded as a u64. + (call $assert + (i32.eq + (i32.load (i32.const 24)) + (i32.const 8) + ) + ) + + ;; Make the transferred value exceed the balance by adding the minimum balance. + (i64.store (i32.const 0) + (i64.add + (i64.load (i32.const 0)) + (i64.load (i32.const 16)) + ) + ) + + ;; Try to self-destruct by sending more balance to the 0 address. ;; The call will fail because a contract transfer has a keep alive requirement (call $assert (i32.eq (call $seal_transfer - (i32.const 16) ;; Pointer to destination address - (i32.const 32) ;; Length of destination address + (i32.const 32) ;; Pointer to destination address + (i32.const 48) ;; Length of destination address (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 8) ;; Length of the buffer with value to transfer ) diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 38c15a807c5..894667280b7 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -30,7 +30,7 @@ use frame_support::{ storage::{with_transaction, TransactionOutcome}, traits::{ fungible::{Inspect, Mutate}, - tokens::Preservation, + tokens::{Fortitude, Preservation}, Contains, OriginTrait, Randomness, Time, }, weights::Weight, @@ -1368,7 +1368,11 @@ where } fn balance(&self) -> BalanceOf { - T::Currency::balance(&self.top_frame().account_id) + T::Currency::reducible_balance( + &self.top_frame().account_id, + Preservation::Preserve, + Fortitude::Polite, + ) } fn value_transferred(&self) -> BalanceOf { diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 9d03a29b038..0c0a2f7f932 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -5891,3 +5891,53 @@ fn root_cannot_instantiate() { ); }); } + +#[test] +fn balance_api_returns_free_balance() { + let (wasm, _code_hash) = compile_module::("balance").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract without any extra balance. + let addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm.to_vec()), + vec![], + vec![], + DebugInfo::Skip, + CollectEvents::Skip, + ) + .result + .unwrap() + .account_id; + + let value = 0; + // Call BOB which makes it call the balance runtime API. + // The contract code asserts that the returned balance is 0. + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + value, + GAS_LIMIT, + None, + vec![] + )); + + let value = 1; + // Calling with value will trap the contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + value, + GAS_LIMIT, + None, + vec![] + ), + >::ContractTrapped + ); + }); +} -- GitLab From a8468134932358abed247963a640877c550a2c64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:44:14 +0300 Subject: [PATCH 052/633] Bump bs58 from 0.4.0 to 0.5.0 (#1293) Bumps [bs58](https://github.com/Nullus157/bs58-rs) from 0.4.0 to 0.5.0. - [Changelog](https://github.com/Nullus157/bs58-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/Nullus157/bs58-rs/compare/0.4.0...0.5.0) --- updated-dependencies: - dependency-name: bs58 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- polkadot/node/metrics/Cargo.toml | 2 +- polkadot/runtime/metrics/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 040f5659e49..2c1fe1484a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12215,7 +12215,7 @@ name = "polkadot-node-metrics" version = "1.0.0" dependencies = [ "assert_cmd", - "bs58 0.4.0", + "bs58 0.5.0", "futures", "futures-timer", "hyper", @@ -12755,7 +12755,7 @@ dependencies = [ name = "polkadot-runtime-metrics" version = "1.0.0" dependencies = [ - "bs58 0.4.0", + "bs58 0.5.0", "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", @@ -17047,7 +17047,7 @@ dependencies = [ "bitflags 1.3.2", "blake2", "bounded-collections", - "bs58 0.4.0", + "bs58 0.5.0", "criterion 0.4.0", "dyn-clonable", "ed25519-zebra 3.1.0", diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index 3b6a67abc13..d497fa7607a 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -21,7 +21,7 @@ substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } sc-tracing = { path = "../../../substrate/client/tracing" } codec = { package = "parity-scale-codec", version = "3.6.1" } primitives = { package = "polkadot-primitives", path = "../../primitives" } -bs58 = { version = "0.4.0", features = ["alloc"] } +bs58 = { version = "0.5.0", features = ["alloc"] } log = "0.4.17" [dev-dependencies] diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index 567a0655661..cfa6bf3dafb 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -12,7 +12,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -bs58 = { version = "0.4.0", default-features = false, features = ["alloc"] } +bs58 = { version = "0.5.0", default-features = false, features = ["alloc"] } [features] default = [ "std" ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 355cbab26fb..991e07f2061 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -23,7 +23,7 @@ primitive-types = { version = "0.12.0", default-features = false, features = ["c impl-serde = { version = "0.4.0", default-features = false, optional = true } hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } -bs58 = { version = "0.4.0", default-features = false, optional = true } +bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "1.0.0", optional = true } -- GitLab From 0d6ef3e6c2c2dd46b12b6d88cda36532181b1811 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 1 Sep 2023 15:58:46 +0200 Subject: [PATCH 053/633] Use bandersnatch-vrfs with locked dependencies ref (#1342) * Use bandersnatch-vrfs with locked dependencies ref * Update ark-scale to 0.0.10 * Bump ark-substrate crates version --- Cargo.lock | 45 ++++++++++--------- substrate/primitives/core/Cargo.toml | 2 +- .../primitives/crypto/ec-utils/Cargo.toml | 14 +++--- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c1fe1484a6..13bc2327dae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,11 +499,12 @@ dependencies = [ [[package]] name = "ark-scale" -version = "0.0.3" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d028cd1025d002fa88c10cd644d29028a7b40806579b608c6ba843b937bbb23" +checksum = "49b08346a3e38e2be792ef53ee168623c9244d968ff00cd70fb9932f6fe36393" dependencies = [ "ark-ec", + "ark-ff", "ark-serialize", "ark-std", "parity-scale-codec", @@ -512,7 +513,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" dependencies = [ "ark-ec", "ark-ff", @@ -560,7 +561,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" dependencies = [ "ark-ff", "ark-serialize", @@ -1239,12 +1240,13 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" version = "0.0.1" -source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" dependencies = [ "ark-bls12-381", "ark-ec", "ark-ed-on-bls12-381-bandersnatch", "ark-ff", + "ark-scale", "ark-serialize", "ark-std", "dleq_vrf", @@ -2703,7 +2705,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#0e948f3c28cbacecdd3020403c4841c0eb339213" +source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213" dependencies = [ "ark-ec", "ark-ff", @@ -4432,10 +4434,11 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" dependencies = [ "ark-ec", "ark-ff", + "ark-scale", "ark-secret-scalar", "ark-serialize", "ark-std", @@ -14020,7 +14023,7 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#0e948f3c28cbacecdd3020403c4841c0eb339213" +source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213" dependencies = [ "ark-ec", "ark-ff", @@ -16783,9 +16786,9 @@ dependencies = [ [[package]] name = "sp-ark-bls12-377" -version = "0.4.0-beta" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e61a06f286f4e8565a67865ef52e83edabf447881898c94527ffc7b839177" +checksum = "f9b60ba7d8fbb82e21f5be499b02438c9a79365acb441a4dc3993179f09c4cc9" dependencies = [ "ark-bls12-377", "ark-ff", @@ -16798,9 +16801,9 @@ dependencies = [ [[package]] name = "sp-ark-bls12-381" -version = "0.4.0-beta" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3352feef6c9c34022fa766a0c9a86a88a83d280a3e5b34781a1a9af98377a130" +checksum = "c2cd101171d2e988a4e1b2320ad3f26f8746a263110c7153213fe86293e0552b" dependencies = [ "ark-bls12-381", "ark-ff", @@ -16813,9 +16816,9 @@ dependencies = [ [[package]] name = "sp-ark-bw6-761" -version = "0.4.0-beta" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf069165e230aef3c4680edea2d8ab3caa89c039e0b61fad2b8e061fb393668" +checksum = "d94d66ba98893cc42dfe81d5b5dee9142577176bdbdba80ec25a37d8cdffdbd5" dependencies = [ "ark-bw6-761", "ark-ff", @@ -16827,9 +16830,9 @@ dependencies = [ [[package]] name = "sp-ark-ed-on-bls12-377" -version = "0.4.0-beta" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63f1fe8e7e87cb0258d61212b019d4d0fd230293ec42a564eb671c83d437497" +checksum = "37f6ea96c9b1cd4cbd05d741225ff7f6328ab035bda16cf3fac105c87ad98959" dependencies = [ "ark-ed-on-bls12-377", "ark-ff", @@ -16843,9 +16846,9 @@ dependencies = [ [[package]] name = "sp-ark-ed-on-bls12-381-bandersnatch" -version = "0.4.0-beta" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "838ddc5508aff3e89f930e7e7f3565d0786ac27868cfd61587afe681011e1140" +checksum = "4db7a801260397cd58077befcee87acfdde8c189f48718bba1bc3783c799b67b" dependencies = [ "ark-ec", "ark-ed-on-bls12-381-bandersnatch", @@ -16860,9 +16863,9 @@ dependencies = [ [[package]] name = "sp-ark-models" -version = "0.4.0" +version = "0.4.1-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28fa906b809d7a346b2aa32a4bd0c884a75f9f588f9a4a07272f63eaf8a10765" +checksum = "cd77599e09f12893739e1ef822ae065f2f46c3be040ba1979bb786ae21059f44" dependencies = [ "ark-ec", "ark-ff", @@ -19382,7 +19385,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 991e07f2061..efcaad1a6f6 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -58,7 +58,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 = "c86ebd4", default-features = false, optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "3119f51", default-features = false, optional = true } [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 3ee9fea6a36..15a6e85abb9 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -23,18 +23,18 @@ 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.3", features = ["hazmat"], default-features = false } +ark-scale = { version = "0.0.10", 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.0-beta", default-features = false } -sp-ark-bls12-377 = { version = "0.4.0-beta", default-features = false } -sp-ark-bls12-381 = { version = "0.4.0-beta", default-features = false } -sp-ark-bw6-761 = { version = "0.4.0-beta", default-features = false } -sp-ark-ed-on-bls12-377 = { version = "0.4.0-beta", default-features = false } -sp-ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0-beta", 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 } [features] default = [ "std" ] -- GitLab From ccdf636c49ca63c440a218b390124db8742ef702 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Fri, 1 Sep 2023 17:54:03 +0200 Subject: [PATCH 054/633] fix typos (#1339) --- substrate/bin/node-template/docs/rust-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node-template/docs/rust-setup.md b/substrate/bin/node-template/docs/rust-setup.md index 2755966e3ae..133db0277bb 100644 --- a/substrate/bin/node-template/docs/rust-setup.md +++ b/substrate/bin/node-template/docs/rust-setup.md @@ -2,7 +2,7 @@ title: Installation --- -This guide is for reference only, please check the latest information on getting starting with Substrate +This guide is for reference only, please check the latest information on getting started with Substrate [here](https://docs.substrate.io/main-docs/install/). This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. @@ -74,7 +74,7 @@ brew install openssl ### Windows **_PLEASE NOTE:_** Native Windows development of Substrate is _not_ very well supported! It is _highly_ -recommend to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) +recommended to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) (WSL) and follow the instructions for [Ubuntu/Debian](#ubuntudebian). Please refer to the separate [guide for native Windows development](https://docs.substrate.io/main-docs/install/windows/). -- GitLab From a2b64706071cd566ac00456fd0b3761dca62a6f8 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:07:32 +0200 Subject: [PATCH 055/633] Use cached session index to obtain executor params (#1190) * Import changes from archieved repo * Revert erroneous changes * Fix more tests * Resolve discussions * Fix MORE tests * approval-voting: launch_approval better interface (#1355) --------- Co-authored-by: Javier Viola Co-authored-by: ordian Co-authored-by: ordian --- .../node/core/approval-voting/src/import.rs | 60 +++- polkadot/node/core/approval-voting/src/lib.rs | 58 ++- .../node/core/approval-voting/src/tests.rs | 15 +- polkadot/node/core/backing/src/lib.rs | 18 +- polkadot/node/core/backing/src/tests/mod.rs | 258 +++++++++++++- .../src/tests/prospective_parachains.rs | 35 +- .../node/core/candidate-validation/src/lib.rs | 39 +- .../core/candidate-validation/src/tests.rs | 336 +++++++----------- .../core/dispute-coordinator/src/import.rs | 22 +- .../dispute-coordinator/src/initialized.rs | 1 + .../node/core/dispute-coordinator/src/lib.rs | 1 + .../src/participation/mod.rs | 1 + .../src/participation/queues/mod.rs | 29 +- .../src/participation/queues/tests.rs | 3 +- .../src/participation/tests.rs | 11 +- .../core/dispute-coordinator/src/tests.rs | 47 ++- polkadot/node/core/pvf/tests/it/main.rs | 2 +- polkadot/node/malus/src/variants/common.rs | 10 + .../src/pov_requester/mod.rs | 8 +- .../src/requester/tests.rs | 8 +- .../src/tests/state.rs | 8 +- .../src/collator_side/tests/mod.rs | 14 +- .../dispute-distribution/src/tests/mod.rs | 43 ++- .../src/legacy_v1/tests.rs | 69 +++- .../node/overseer/examples/minimal-example.rs | 1 + polkadot/node/overseer/src/tests.rs | 2 + polkadot/node/subsystem-types/src/messages.rs | 2 + .../node/subsystem-util/src/runtime/error.rs | 4 + .../node/subsystem-util/src/runtime/mod.rs | 25 +- 29 files changed, 809 insertions(+), 321 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index 6f376fc6fcc..df712fc45a5 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -598,7 +598,9 @@ pub(crate) mod tests { use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage}; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; - use polkadot_primitives::{Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex}; + use polkadot_primitives::{ + ExecutorParams, Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex, + }; pub(crate) use sp_consensus_babe::{ digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest}, AllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch, @@ -835,6 +837,20 @@ pub(crate) mod tests { si_tx.send(Ok(Some(session_info.clone()))).unwrap(); } ); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); }); futures::executor::block_on(futures::future::join(test_fut, aux_fut)); @@ -952,6 +968,20 @@ pub(crate) mod tests { si_tx.send(Ok(Some(session_info.clone()))).unwrap(); } ); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); }); futures::executor::block_on(futures::future::join(test_fut, aux_fut)); @@ -1172,6 +1202,20 @@ pub(crate) mod tests { si_tx.send(Ok(Some(session_info.clone()))).unwrap(); } ); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); }); futures::executor::block_on(futures::future::join(test_fut, aux_fut)); @@ -1374,6 +1418,20 @@ pub(crate) mod tests { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( handle.recv().await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks( diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index e99572b31c4..0087f8e1435 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -45,13 +45,13 @@ use polkadot_node_subsystem_util::{ self, database::Database, metrics::{self, prometheus}, - runtime::{Config as RuntimeInfoConfig, RuntimeInfo}, + runtime::{Config as RuntimeInfoConfig, ExtendedSessionInfo, RuntimeInfo}, TimeoutExt, }; use polkadot_primitives::{ ApprovalVote, BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement, - GroupIndex, Hash, PvfExecTimeoutKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, - ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + ExecutorParams, GroupIndex, Hash, PvfExecTimeoutKind, SessionIndex, SessionInfo, + ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; @@ -643,12 +643,12 @@ impl CurrentlyCheckingSet { } } -async fn get_session_info<'a, Sender>( +async fn get_extended_session_info<'a, Sender>( runtime_info: &'a mut RuntimeInfo, sender: &mut Sender, relay_parent: Hash, session_index: SessionIndex, -) -> Option<&'a SessionInfo> +) -> Option<&'a ExtendedSessionInfo> where Sender: SubsystemSender, { @@ -656,19 +656,33 @@ where .get_session_info_by_index(sender, relay_parent, session_index) .await { - Ok(extended_info) => Some(&extended_info.session_info), + Ok(extended_info) => Some(&extended_info), Err(_) => { gum::debug!( target: LOG_TARGET, session = session_index, ?relay_parent, - "Can't obtain SessionInfo" + "Can't obtain SessionInfo or ExecutorParams" ); None }, } } +async fn get_session_info<'a, Sender>( + runtime_info: &'a mut RuntimeInfo, + sender: &mut Sender, + relay_parent: Hash, + session_index: SessionIndex, +) -> Option<&'a SessionInfo> +where + Sender: SubsystemSender, +{ + get_extended_session_info(runtime_info, sender, relay_parent, session_index) + .await + .map(|extended_info| &extended_info.session_info) +} + struct State { keystore: Arc, slot_duration_millis: u64, @@ -746,6 +760,7 @@ enum Action { relay_block_hash: Hash, candidate_index: CandidateIndex, session: SessionIndex, + executor_params: ExecutorParams, candidate: CandidateReceipt, backing_group: GroupIndex, }, @@ -968,6 +983,7 @@ async fn handle_actions( relay_block_hash, candidate_index, session, + executor_params, candidate, backing_group, } => { @@ -1008,6 +1024,7 @@ async fn handle_actions( }, None => { let ctx = &mut *ctx; + currently_checking_set .insert_relay_block_hash( candidate_hash, @@ -1022,6 +1039,7 @@ async fn handle_actions( validator_index, block_hash, backing_group, + executor_params, &launch_approval_span, ) .await @@ -2328,17 +2346,18 @@ async fn process_wakeup( _ => return Ok(Vec::new()), }; - let session_info = match get_session_info( - session_info_provider, - ctx.sender(), - block_entry.parent_hash(), - block_entry.session(), - ) - .await - { - Some(i) => i, - None => return Ok(Vec::new()), - }; + let ExtendedSessionInfo { ref session_info, ref executor_params, .. } = + match get_extended_session_info( + session_info_provider, + ctx.sender(), + block_entry.parent_hash(), + block_entry.session(), + ) + .await + { + Some(i) => i, + None => return Ok(Vec::new()), + }; let block_tick = slot_number_to_tick(state.slot_duration_millis, block_entry.slot()); let no_show_duration = slot_number_to_tick( @@ -2425,6 +2444,7 @@ async fn process_wakeup( relay_block_hash: relay_block, candidate_index: i as _, session: block_entry.session(), + executor_params: executor_params.clone(), candidate: candidate_receipt, backing_group, }); @@ -2466,6 +2486,7 @@ async fn launch_approval( validator_index: ValidatorIndex, block_hash: Hash, backing_group: GroupIndex, + executor_params: ExecutorParams, span: &jaeger::Span, ) -> SubsystemResult> { let (a_tx, a_rx) = oneshot::channel(); @@ -2611,6 +2632,7 @@ async fn launch_approval( validation_code, candidate.clone(), available_data.pov, + executor_params, PvfExecTimeoutKind::Approval, val_tx, )) diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index f58e60c6a48..3c7b74b26fb 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -910,6 +910,19 @@ async fn import_block( si_tx.send(Ok(Some(session_info.clone()))).unwrap(); } ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(_, si_tx), + ) + ) => { + // Make sure all SessionExecutorParams calls are not made for the leaf (but for its relay parent) + assert_ne!(req_block_hash, hashes[(number-1) as usize].0); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); } assert_matches!( @@ -2376,7 +2389,7 @@ async fn handle_double_assignment_import( assert_matches!( overseer_recv(virtual_overseer).await, - AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx)) if timeout == PvfExecTimeoutKind::Approval => { + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)) if timeout == PvfExecTimeoutKind::Approval => { tx.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) .unwrap(); } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index a75571da76d..97efb3ba808 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -96,8 +96,8 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ self as util, backing_implicit_view::{FetchError as ImplicitViewFetchError, View as ImplicitView}, - request_from_runtime, request_session_index_for_child, request_validator_groups, - request_validators, + executor_params_at_relay_parent, request_from_runtime, request_session_index_for_child, + request_validator_groups, request_validators, runtime::{ self, prospective_parachains_mode, request_min_backing_votes, ProspectiveParachainsMode, }, @@ -105,9 +105,9 @@ use polkadot_node_subsystem_util::{ }; use polkadot_primitives::{ BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, PersistedValidationData, - PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, - ValidatorSignature, ValidityAttestation, + CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, Hash, Id as ParaId, + PersistedValidationData, PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId, + ValidatorIndex, ValidatorSignature, ValidityAttestation, }; use sp_keystore::KeystorePtr; use statement_table::{ @@ -555,6 +555,7 @@ async fn request_candidate_validation( code: ValidationCode, candidate_receipt: CandidateReceipt, pov: Arc, + executor_params: ExecutorParams, ) -> Result { let (tx, rx) = oneshot::channel(); @@ -564,6 +565,7 @@ async fn request_candidate_validation( code, candidate_receipt, pov, + executor_params, PvfExecTimeoutKind::Backing, tx, )) @@ -630,6 +632,11 @@ async fn validate_and_make_available( } }; + let executor_params = match executor_params_at_relay_parent(relay_parent, &mut sender).await { + Ok(ep) => ep, + Err(e) => return Err(Error::UtilError(e)), + }; + let pov = match pov { PoVData::Ready(pov) => pov, PoVData::FetchFromValidator { from_validator, candidate_hash, pov_hash } => @@ -665,6 +672,7 @@ async fn validate_and_make_available( validation_code, candidate.clone(), pov.clone(), + executor_params, ) .await? }; diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 06baebc98e6..f5ea827d254 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -348,6 +348,24 @@ fn backing_second_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -356,6 +374,7 @@ fn backing_second_works() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -494,6 +513,24 @@ fn backing_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is the PoV. assert_matches!( @@ -519,6 +556,7 @@ fn backing_works() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -678,6 +716,24 @@ fn backing_works_while_validation_ongoing() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is PoV from the // `PoVDistribution`. @@ -704,6 +760,7 @@ fn backing_works_while_validation_ongoing() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -850,6 +907,24 @@ fn backing_misbehavior_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::AvailabilityDistribution( @@ -871,6 +946,7 @@ fn backing_misbehavior_works() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1036,6 +1112,24 @@ fn backing_dont_second_invalid() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -1044,6 +1138,7 @@ fn backing_dont_second_invalid() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1082,6 +1177,24 @@ fn backing_dont_second_invalid() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -1090,6 +1203,7 @@ fn backing_dont_second_invalid() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1200,6 +1314,24 @@ fn backing_second_after_first_fails_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. assert_matches!( virtual_overseer.recv().await, @@ -1223,6 +1355,7 @@ fn backing_second_after_first_fails_works() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1289,6 +1422,24 @@ fn backing_second_after_first_fails_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -1357,6 +1508,24 @@ fn backing_works_after_failed_validation() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. assert_matches!( virtual_overseer.recv().await, @@ -1380,6 +1549,7 @@ fn backing_works_after_failed_validation() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1566,6 +1736,24 @@ fn retry_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. // We cancel - should mean retry on next backing statement. assert_matches!( @@ -1586,7 +1774,7 @@ fn retry_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; // Not deterministic which message comes first: - for _ in 0u32..3 { + for _ in 0u32..5 { match virtual_overseer.recv().await { AllMessages::Provisioner(ProvisionerMessage::ProvisionableData( _, @@ -1605,6 +1793,18 @@ fn retry_works() { )) if hash == validation_code.hash() => { tx.send(Ok(Some(validation_code.clone()))).unwrap(); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + tx.send(Ok(1u32.into())).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(sess_idx, tx), + )) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + }, msg => { assert!(false, "Unexpected message: {:?}", msg); }, @@ -1624,6 +1824,24 @@ fn retry_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::AvailabilityDistribution( @@ -1647,6 +1865,7 @@ fn retry_works() { _validation_code, candidate_receipt, _pov, + _, timeout, .. ), @@ -1821,6 +2040,24 @@ fn cannot_second_multiple_candidates_per_parent() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -1829,6 +2066,7 @@ fn cannot_second_multiple_candidates_per_parent() { _validation_code, candidate_receipt, _pov, + _, timeout, tx, ), @@ -1907,6 +2145,24 @@ fn cannot_second_multiple_candidates_per_parent() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 7a30886736d..07e2a3a89bb 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -217,6 +217,24 @@ async fn assert_validate_seconded_candidate( } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + if fetch_pov { assert_matches!( virtual_overseer.recv().await, @@ -239,6 +257,7 @@ async fn assert_validate_seconded_candidate( _validation_code, candidate_receipt, _pov, + _, timeout, tx, )) if &_pvd == pvd && @@ -1339,7 +1358,7 @@ fn concurrent_dependent_candidates() { tx.send(pov.clone()).unwrap(); }, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, tx), + CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, _, tx), ) => { let candidate_hash = candidate.hash(); let (head_data, pvd) = if candidate_hash == candidate_a_hash { @@ -1396,6 +1415,20 @@ fn concurrent_dependent_candidates() { break } }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + tx.send(Ok(1u32.into())).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(sess_idx, tx), + )) => { + assert_eq!(sess_idx, 1); + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + }, + _ => panic!("unexpected message received from overseer: {:?}", msg), } } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 0da2853340d..3281fcc59a1 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -164,6 +164,7 @@ async fn run( CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ) => { @@ -179,6 +180,7 @@ async fn run( validation_host, candidate_receipt, pov, + executor_params, timeout, &metrics, ) @@ -196,23 +198,23 @@ async fn run( validation_code, candidate_receipt, pov, + executor_params, timeout, response_sender, ) => { let bg = { - let mut sender = ctx.sender().clone(); let metrics = metrics.clone(); let validation_host = validation_host.clone(); async move { let _timer = metrics.time_validate_from_exhaustive(); let res = validate_candidate_exhaustive( - &mut sender, validation_host, persisted_validation_data, validation_code, candidate_receipt, pov, + executor_params, timeout, &metrics, ) @@ -497,6 +499,7 @@ async fn validate_from_chain_state( validation_host: ValidationHost, candidate_receipt: CandidateReceipt, pov: Arc, + executor_params: ExecutorParams, exec_timeout_kind: PvfExecTimeoutKind, metrics: &Metrics, ) -> Result @@ -511,12 +514,12 @@ where }; let validation_result = validate_candidate_exhaustive( - sender, validation_host, validation_data, validation_code, candidate_receipt.clone(), pov, + executor_params, exec_timeout_kind, metrics, ) @@ -546,19 +549,16 @@ where validation_result } -async fn validate_candidate_exhaustive( - sender: &mut Sender, +async fn validate_candidate_exhaustive( mut validation_backend: impl ValidationBackend + Send, persisted_validation_data: PersistedValidationData, validation_code: ValidationCode, candidate_receipt: CandidateReceipt, pov: Arc, + executor_params: ExecutorParams, exec_timeout_kind: PvfExecTimeoutKind, metrics: &Metrics, -) -> Result -where - Sender: SubsystemSender, -{ +) -> Result { let _timer = metrics.time_validate_candidate_exhaustive(); let validation_code_hash = validation_code.hash(); @@ -615,27 +615,6 @@ where relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root, }; - let executor_params = if let Ok(executor_params) = - executor_params_at_relay_parent(candidate_receipt.descriptor.relay_parent, sender).await - { - gum::debug!( - target: LOG_TARGET, - ?validation_code_hash, - ?para_id, - "Acquired executor params for the session: {:?}", - executor_params, - ); - executor_params - } else { - gum::warn!( - target: LOG_TARGET, - ?validation_code_hash, - ?para_id, - "Failed to acquire executor params for the session", - ); - return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)) - }; - let result = validation_backend .validate_candidate_with_retry( raw_validation_code.to_vec(), diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 2dcead4db46..af530a20c4e 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -26,37 +26,6 @@ use polkadot_primitives::{HeadData, Id as ParaId, UpwardMessage}; use sp_core::testing::TaskExecutor; use sp_keyring::Sr25519Keyring; -fn test_with_executor_params, R, M>( - mut ctx_handle: test_helpers::TestSubsystemContextHandle, - test: impl FnOnce() -> T, -) -> R { - let test_fut = test(); - - let overseer = async move { - assert_matches!( - ctx_handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - assert_matches!( - ctx_handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx)) - ) => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); - }; - - futures::pin_mut!(test_fut); - futures::pin_mut!(overseer); - let v = executor::block_on(future::join(test_fut, overseer)); - v.0 -} - #[test] fn correctly_checks_included_assumption() { let validation_data: PersistedValidationData = Default::default(); @@ -460,23 +429,16 @@ fn candidate_validation_ok_is_ok() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), - validation_data.clone(), - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }) + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), + validation_data.clone(), + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )) .unwrap(); assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { @@ -517,27 +479,21 @@ fn candidate_validation_bad_return_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result(Err( - ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), - )), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }); + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Err( + ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), + )), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )) + .unwrap(); - assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); + assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::Timeout)); } // Test that we vote valid if we get `AmbiguousWorkerDeath`, retry, and then succeed. @@ -588,26 +544,19 @@ fn candidate_validation_one_ambiguous_error_is_valid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - Ok(validation_result), - ]), - validation_data.clone(), - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }) + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result_list(vec![ + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Ok(validation_result), + ]), + validation_data.clone(), + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )) .unwrap(); assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { @@ -648,26 +597,19 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - ]), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }) + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result_list(vec![ + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + ]), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )) .unwrap(); assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::ExecutionError(_))); @@ -702,29 +644,22 @@ fn candidate_validation_retry_internal_errors() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(InternalValidationError::HostCommunication("foo".into()).into()), - // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - // Throw another internal error. - Err(InternalValidationError::HostCommunication("bar".into()).into()), - ]), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }); + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result_list(vec![ + Err(InternalValidationError::HostCommunication("foo".into()).into()), + // Throw an AWD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + // Throw another internal error. + Err(InternalValidationError::HostCommunication("bar".into()).into()), + ]), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )); assert_matches!(v, Err(ValidationFailed(s)) if s.contains("bar")); } @@ -758,29 +693,22 @@ fn candidate_validation_retry_panic_errors() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("foo".into()))), - // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - // Throw another panic error. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("bar".into()))), - ]), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }); + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result_list(vec![ + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("foo".into()))), + // Throw an AWD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + // Throw another panic error. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("bar".into()))), + ]), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(s))) if s == "bar".to_string()); } @@ -813,25 +741,18 @@ fn candidate_validation_timeout_is_internal_error() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result(Err( - ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), - )), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }); + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Err( + ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), + )), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); } @@ -867,23 +788,16 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() { hrmp_watermark: 12345, }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let result = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }) + let result = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )) .unwrap(); // Ensure `post validation` check on the commitments hash works as expected. @@ -919,11 +833,9 @@ fn candidate_validation_code_mismatch_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let pool = TaskExecutor::new(); - let (mut ctx, _ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); + let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::(pool.clone()); let v = executor::block_on(validate_candidate_exhaustive( - ctx.sender(), MockValidateCandidateBackend::with_hardcoded_result(Err( ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), )), @@ -931,6 +843,7 @@ fn candidate_validation_code_mismatch_is_invalid() { validation_code, candidate_receipt, Arc::new(pov), + ExecutorParams::default(), PvfExecTimeoutKind::Backing, &Default::default(), )) @@ -981,23 +894,16 @@ fn compressed_code_works() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; - let pool = TaskExecutor::new(); - let (mut ctx, ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); - let metrics = Metrics::default(); - - let v = test_with_executor_params(ctx_handle, || { - validate_candidate_exhaustive( - ctx.sender(), - MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - PvfExecTimeoutKind::Backing, - &metrics, - ) - }); + let v = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecTimeoutKind::Backing, + &Default::default(), + )); assert_matches!(v, Ok(ValidationResult::Valid(_, _))); } @@ -1037,16 +943,15 @@ fn code_decompression_failure_is_error() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let pool = TaskExecutor::new(); - let (mut ctx, _ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); + let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::(pool.clone()); let v = executor::block_on(validate_candidate_exhaustive( - ctx.sender(), MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, candidate_receipt, Arc::new(pov), + ExecutorParams::default(), PvfExecTimeoutKind::Backing, &Default::default(), )); @@ -1090,16 +995,15 @@ fn pov_decompression_failure_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let pool = TaskExecutor::new(); - let (mut ctx, _ctx_handle) = - test_helpers::make_subsystem_context::(pool.clone()); + let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::(pool.clone()); let v = executor::block_on(validate_candidate_exhaustive( - ctx.sender(), MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, candidate_receipt, Arc::new(pov), + ExecutorParams::default(), PvfExecTimeoutKind::Backing, &Default::default(), )); diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs index 0da3723ebf2..cf51ae4d365 100644 --- a/polkadot/node/core/dispute-coordinator/src/import.rs +++ b/polkadot/node/core/dispute-coordinator/src/import.rs @@ -34,8 +34,9 @@ use polkadot_node_primitives::{ use polkadot_node_subsystem::overseer; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - CandidateReceipt, DisputeStatement, Hash, IndexedVec, SessionIndex, SessionInfo, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + CandidateReceipt, DisputeStatement, ExecutorParams, Hash, IndexedVec, SessionIndex, + SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, + ValidatorSignature, }; use sc_keystore::LocalKeystore; @@ -47,6 +48,8 @@ pub struct CandidateEnvironment<'a> { session_index: SessionIndex, /// Session for above index. session: &'a SessionInfo, + /// Executor parameters for the session. + executor_params: &'a ExecutorParams, /// Validator indices controlled by this node. controlled_indices: HashSet, } @@ -63,17 +66,17 @@ impl<'a> CandidateEnvironment<'a> { session_index: SessionIndex, relay_parent: Hash, ) -> Option> { - let session_info = match runtime_info + let (session, executor_params) = match runtime_info .get_session_info_by_index(ctx.sender(), relay_parent, session_index) .await { - Ok(extended_session_info) => &extended_session_info.session_info, + Ok(extended_session_info) => + (&extended_session_info.session_info, &extended_session_info.executor_params), Err(_) => return None, }; - let controlled_indices = - find_controlled_validator_indices(keystore, &session_info.validators); - Some(Self { session_index, session: session_info, controlled_indices }) + let controlled_indices = find_controlled_validator_indices(keystore, &session.validators); + Some(Self { session_index, session, executor_params, controlled_indices }) } /// Validators in the candidate's session. @@ -86,6 +89,11 @@ impl<'a> CandidateEnvironment<'a> { &self.session } + /// Executor parameters for the candidate's session + pub fn executor_params(&self) -> &ExecutorParams { + &self.executor_params + } + /// Retrieve `SessionIndex` for this environment. pub fn session_index(&self) -> SessionIndex { self.session_index diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index c1d02ef976c..dd7aef19f6e 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -1160,6 +1160,7 @@ impl Initialized { ParticipationRequest::new( new_state.candidate_receipt().clone(), session, + env.executor_params().clone(), request_timer, ), ) diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index f7e3d0657f2..3f0fd401314 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -398,6 +398,7 @@ impl DisputeCoordinatorSubsystem { ParticipationRequest::new( vote_state.votes().candidate_receipt.clone(), session, + env.executor_params().clone(), request_timer, ), )); diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index 25b7352807f..5a3c4be90aa 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -366,6 +366,7 @@ async fn participate( validation_code, req.candidate_receipt().clone(), available_data.pov, + req.executor_params(), PvfExecTimeoutKind::Approval, validation_tx, )) diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs index 8a4374999f8..1105135a747 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs @@ -21,7 +21,9 @@ use std::{ use futures::channel::oneshot; use polkadot_node_subsystem::{messages::ChainApiMessage, overseer}; -use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex}; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex, +}; use crate::{ error::{FatalError, FatalResult, Result}, @@ -73,6 +75,7 @@ pub struct ParticipationRequest { candidate_hash: CandidateHash, candidate_receipt: CandidateReceipt, session: SessionIndex, + executor_params: ExecutorParams, request_timer: Option, // Sends metric data when request is dropped } @@ -120,9 +123,16 @@ impl ParticipationRequest { pub fn new( candidate_receipt: CandidateReceipt, session: SessionIndex, + executor_params: ExecutorParams, request_timer: Option, ) -> Self { - Self { candidate_hash: candidate_receipt.hash(), candidate_receipt, session, request_timer } + Self { + candidate_hash: candidate_receipt.hash(), + candidate_receipt, + session, + executor_params, + request_timer, + } } pub fn candidate_receipt(&'_ self) -> &'_ CandidateReceipt { @@ -134,6 +144,9 @@ impl ParticipationRequest { pub fn session(&self) -> SessionIndex { self.session } + pub fn executor_params(&self) -> ExecutorParams { + self.executor_params.clone() + } pub fn discard_timer(&mut self) { if let Some(timer) = self.request_timer.take() { timer.stop_and_discard(); @@ -150,11 +163,17 @@ impl ParticipationRequest { #[cfg(test)] impl PartialEq for ParticipationRequest { fn eq(&self, other: &Self) -> bool { - let ParticipationRequest { candidate_receipt, candidate_hash, session, request_timer: _ } = - self; + let ParticipationRequest { + candidate_receipt, + candidate_hash, + session, + executor_params, + request_timer: _, + } = self; candidate_receipt == other.candidate_receipt() && candidate_hash == other.candidate_hash() && - *session == other.session() + *session == other.session() && + executor_params.hash() == other.executor_params.hash() } } #[cfg(test)] diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs index d4f43639ce8..63bfc1d7d02 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs @@ -27,7 +27,7 @@ fn make_participation_request(hash: Hash) -> ParticipationRequest { // make it differ: receipt.commitments_hash = hash; let request_timer = Metrics::default().time_participation_pipeline(); - ParticipationRequest::new(receipt, 1, request_timer) + ParticipationRequest::new(receipt, 1, Default::default(), request_timer) } /// Make dummy comparator for request, based on the given block number. @@ -46,6 +46,7 @@ fn clone_request(request: &ParticipationRequest) -> ParticipationRequest { candidate_receipt: request.candidate_receipt.clone(), candidate_hash: request.candidate_hash, session: request.session, + executor_params: request.executor_params.clone(), request_timer: None, } } diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index 32725a3ac65..a2e8e88cb67 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -73,7 +73,8 @@ async fn participate_with_commitments_hash( let session = 1; let request_timer = participation.metrics.time_participation_pipeline(); - let req = ParticipationRequest::new(candidate_receipt, session, request_timer); + let req = + ParticipationRequest::new(candidate_receipt, session, Default::default(), request_timer); participation .queue_participation(ctx, ParticipationPriority::BestEffort, req) @@ -120,7 +121,7 @@ pub async fn participation_full_happy_path( assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, _, timeout, tx) ) if timeout == PvfExecTimeoutKind::Approval => { if expected_commitments_hash != candidate_receipt.commitments_hash { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); @@ -455,7 +456,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) ) if timeout == PvfExecTimeoutKind::Approval => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, @@ -492,7 +493,7 @@ fn cast_invalid_vote_if_commitments_dont_match() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) ) if timeout == PvfExecTimeoutKind::Approval => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, @@ -529,7 +530,7 @@ fn cast_valid_vote_if_validation_passes() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) ) if timeout == PvfExecTimeoutKind::Approval => { tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 75eae8200dc..8d6a2e10396 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -63,9 +63,9 @@ use polkadot_node_subsystem_test_helpers::{ }; use polkadot_primitives::{ ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CandidateReceipt, CoreIndex, DisputeStatement, GroupIndex, Hash, HeadData, Header, IndexedVec, - MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData, + Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SessionInfo, + SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; use crate::{ @@ -347,6 +347,17 @@ impl TestState { let _ = tx.send(Ok(Some(self.session_info()))); } ); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::SessionExecutorParams(session_index, tx), + )) => { + assert_eq!(h, block_hash); + assert_eq!(session_index, i); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); } } @@ -3482,6 +3493,16 @@ fn session_info_is_requested_only_once() { let _ = tx.send(Ok(Some(test_state.session_info()))); } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(session_index, tx), + )) => { + assert_eq!(session_index, 2); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); test_state }) }); @@ -3532,6 +3553,16 @@ fn session_info_big_jump_works() { let _ = tx.send(Ok(Some(test_state.session_info()))); } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(session_index, tx), + )) => { + assert_eq!(session_index, expected_idx); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); } test_state }) @@ -3582,6 +3613,16 @@ fn session_info_small_jump_works() { let _ = tx.send(Ok(Some(test_state.session_info()))); } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(session_index, tx), + )) => { + assert_eq!(session_index, expected_idx); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); } test_state }) diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 8574bc16c5d..12d87ee4426 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -258,7 +258,7 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { #[tokio::test] async fn deleting_prepared_artifact_does_not_dispute() { let host = TestHost::new(); - let cache_dir = host.cache_dir.path().clone(); + let cache_dir = host.cache_dir.path(); let result = host .validate_candidate( diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 475ca8f3145..bc5f6f92aed 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -278,6 +278,7 @@ where validation_code, candidate_receipt, pov, + executor_params, timeout, sender, ), @@ -292,6 +293,7 @@ where validation_code, candidate_receipt, pov, + executor_params, timeout, sender, ), @@ -329,6 +331,7 @@ where validation_code, candidate_receipt, pov, + executor_params, timeout, sender, ), @@ -368,6 +371,7 @@ where validation_code, candidate_receipt, pov, + executor_params, timeout, sender, ), @@ -382,6 +386,7 @@ where validation_code, candidate_receipt, pov, + executor_params, timeout, sender, ), @@ -394,6 +399,7 @@ where CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ), @@ -406,6 +412,7 @@ where msg: CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ), @@ -435,6 +442,7 @@ where msg: CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ), @@ -468,6 +476,7 @@ where msg: CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ), @@ -479,6 +488,7 @@ where msg: CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + executor_params, timeout, response_sender, ), diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs index 8fc9fa82153..12a97a1fb5a 100644 --- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs @@ -146,7 +146,7 @@ mod tests { AllMessages, AvailabilityDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; - use polkadot_primitives::{CandidateHash, Hash, ValidatorIndex}; + use polkadot_primitives::{CandidateHash, ExecutorParams, Hash, ValidatorIndex}; use test_helpers::mock::make_ferdie_keystore; use super::*; @@ -208,6 +208,12 @@ mod tests { )) => { tx.send(Ok(Some(make_session_info()))).unwrap(); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(_, tx), + )) => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + }, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests( mut reqs, _, diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index b74a69ea076..5f7e4c36f06 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -24,8 +24,8 @@ use polkadot_node_network_protocol::jaeger; use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - BlockNumber, CoreState, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionIndex, - SessionInfo, + BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, + SessionIndex, SessionInfo, }; use sp_core::traits::SpawnNamed; @@ -120,6 +120,10 @@ fn spawn_virtual_overseer( tx.send(Ok(Some(test_state.session_info.clone()))) .expect("Receiver should be alive."); }, + RuntimeApiRequest::SessionExecutorParams(_, tx) => { + tx.send(Ok(Some(ExecutorParams::default()))) + .expect("Receiver should be alive."); + }, RuntimeApiRequest::AvailabilityCores(tx) => { let para_id = ParaId::from(1_u32); let maybe_block_position = diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 706ec13a3e9..ecde44788c2 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -48,8 +48,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateHash, CoreState, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionInfo, - ValidatorIndex, + CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, + SessionInfo, ValidatorIndex, }; use test_helpers::mock::make_ferdie_keystore; @@ -267,6 +267,10 @@ impl TestState { tx.send(Ok(Some(self.session_info.clone()))) .expect("Receiver should be alive."); }, + RuntimeApiRequest::SessionExecutorParams(_, tx) => { + tx.send(Ok(Some(ExecutorParams::default()))) + .expect("Receiver should be alive."); + }, RuntimeApiRequest::AvailabilityCores(tx) => { gum::trace!(target: LOG_TARGET, cores= ?self.cores[&hash], hash = ?hash, "Sending out cores for hash"); tx.send(Ok(self.cores[&hash].clone())) 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 fae719b2b4a..8b28730c901 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 @@ -45,8 +45,8 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - AuthorityDiscoveryId, CollatorPair, GroupIndex, GroupRotationInfo, IndexedVec, ScheduledCore, - SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, GroupRotationInfo, IndexedVec, + ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; @@ -398,6 +398,16 @@ async fn distribute_collation_with_receipt( tx.send(Ok(Some(test_state.session_info.clone()))).unwrap(); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionExecutorParams(session_index, tx), + )) => { + assert_eq!(relay_parent, relay_parent); + assert_eq!(session_index, test_state.current_session_index()); + + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( _relay_parent, RuntimeApiRequest::ValidatorGroups(tx), diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index bc8e8e8be16..f53b9c0dd4b 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -57,7 +57,8 @@ use polkadot_node_subsystem_test_helpers::{ mock::make_ferdie_keystore, subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CandidateReceipt, Hash, SessionIndex, SessionInfo, + AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex, + SessionInfo, }; use self::mock::{ @@ -635,6 +636,16 @@ async fn nested_network_dispute_request<'a, F, O>( }, unexpected => panic!("Unexpected message {:?}", unexpected), } + match handle.recv().await { + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(_, tx), + )) => { + tx.send(Ok(Some(ExecutorParams::default()))) + .expect("Receiver should stay alive."); + }, + unexpected => panic!("Unexpected message {:?}", unexpected), + } } // Import should get initiated: @@ -746,15 +757,27 @@ async fn activate_leaf( if let Some(session_info) = new_session { assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - h, - RuntimeApiRequest::SessionInfo(session_idx, tx) - )) => { - assert_eq!(h, activate); - assert_eq!(session_index, session_idx); - tx.send(Ok(Some(session_info))).expect("Receiver should stay alive."); - }); + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::SessionInfo(session_idx, tx) + )) => { + assert_eq!(h, activate); + assert_eq!(session_index, session_idx); + tx.send(Ok(Some(session_info))).expect("Receiver should stay alive."); + } + ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::SessionExecutorParams(session_idx, tx) + )) => { + assert_eq!(h, activate); + assert_eq!(session_index, session_idx); + tx.send(Ok(Some(ExecutorParams::default()))).expect("Receiver should stay alive."); + } + ); } assert_matches!( 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 a8ce65f2986..63ac1febde5 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -44,7 +44,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore; use polkadot_primitives::{ - GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, ValidationCode, + ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, + ValidationCode, }; use polkadot_primitives_test_helpers::{ dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng, @@ -828,6 +829,17 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == hash_a && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -1062,6 +1074,17 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == hash_a && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -1586,6 +1609,17 @@ fn delay_reputation_changes() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == hash_a && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -2060,6 +2094,17 @@ fn share_prioritizes_backing_group() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == hash_a && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of dummy peers and view for (peer, pair) in dummy_peers.clone().into_iter().zip(dummy_pairs) { handle @@ -2376,6 +2421,17 @@ fn peer_cant_flood_with_large_statements() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == hash_a && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -2595,6 +2651,17 @@ fn handle_multiple_seconded_statements() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx)) + ) + if r == relay_parent_hash && sess_index == session_index + => { + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + // notify of peers and view for peer in all_peers.iter() { handle diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index a823b1d3961..e78941776d5 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -76,6 +76,7 @@ impl Subsystem1 { let msg = CandidateValidationMessage::ValidateFromChainState( candidate_receipt, PoV { block_data: BlockData(Vec::new()) }.into(), + Default::default(), PvfExecTimeoutKind::Backing, tx, ); diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 4ac538a7fd3..22d9bf0a708 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -106,6 +106,7 @@ where ctx.send_message(CandidateValidationMessage::ValidateFromChainState( candidate_receipt, PoV { block_data: BlockData(Vec::new()) }.into(), + Default::default(), PvfExecTimeoutKind::Backing, tx, )) @@ -779,6 +780,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { CandidateValidationMessage::ValidateFromChainState( candidate_receipt, pov, + Default::default(), PvfExecTimeoutKind::Backing, sender, ) diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 6b078e08377..a53908d3c2c 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -143,6 +143,7 @@ pub enum CandidateValidationMessage { ValidateFromChainState( CandidateReceipt, Arc, + ExecutorParams, /// Execution timeout PvfExecTimeoutKind, oneshot::Sender>, @@ -161,6 +162,7 @@ pub enum CandidateValidationMessage { ValidationCode, CandidateReceipt, Arc, + ExecutorParams, /// Execution timeout PvfExecTimeoutKind, oneshot::Sender>, diff --git a/polkadot/node/subsystem-util/src/runtime/error.rs b/polkadot/node/subsystem-util/src/runtime/error.rs index 9c3d57b8ea6..8751693b078 100644 --- a/polkadot/node/subsystem-util/src/runtime/error.rs +++ b/polkadot/node/subsystem-util/src/runtime/error.rs @@ -38,6 +38,10 @@ pub enum Error { /// We tried fetching a session info which was not available. #[error("There was no session with the given index {0}")] NoSuchSession(SessionIndex), + + /// We tried fetching executor params for a session which were not available. + #[error("There was no executor parameters for session with the given index {0}")] + NoExecutorParams(SessionIndex), } pub type Result = std::result::Result; diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index fcd778b0784..fc767faa763 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -29,17 +29,18 @@ use polkadot_node_subsystem::{ overseer, SubsystemSender, }; use polkadot_primitives::{ - vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, - Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, - SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + 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, }; use crate::{ request_availability_cores, request_candidate_events, request_from_runtime, - request_key_ownership_proof, request_on_chain_votes, request_session_index_for_child, - request_session_info, request_staging_async_backing_params, request_submit_report_dispute_lost, - request_unapplied_slashes, request_validation_code_by_hash, request_validator_groups, + 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_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash, + request_validator_groups, }; /// Errors that can happen on runtime fetches. @@ -84,6 +85,8 @@ pub struct ExtendedSessionInfo { pub session_info: SessionInfo, /// Contains useful information about ourselves, in case this node is a validator. pub validator_info: ValidatorInfo, + /// Session executor parameters + pub executor_params: ExecutorParams, } /// Information about ourselves, in case we are an `Authority`. @@ -174,9 +177,15 @@ impl RuntimeInfo { recv_runtime(request_session_info(parent, session_index, sender).await) .await? .ok_or(JfyiError::NoSuchSession(session_index))?; + + let executor_params = + recv_runtime(request_session_executor_params(parent, session_index, sender).await) + .await? + .ok_or(JfyiError::NoExecutorParams(session_index))?; + let validator_info = self.get_validator_info(&session_info)?; - let full_info = ExtendedSessionInfo { session_info, validator_info }; + let full_info = ExtendedSessionInfo { session_info, validator_info, executor_params }; self.session_info_cache.insert(session_index, full_info); } -- GitLab From 23a2b7b5b33067fa2d7cadc4e98379b2d660d9d2 Mon Sep 17 00:00:00 2001 From: eskimor Date: Fri, 1 Sep 2023 20:56:09 +0200 Subject: [PATCH 056/633] Fix wrong ref counting (#1358) * Fix wrong ref counting in case of multiple inserts at same height. * More warn --------- Co-authored-by: eskimor --- .../node/core/dispute-coordinator/src/initialized.rs | 4 ++-- .../dispute-coordinator/src/scraping/candidates.rs | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index dd7aef19f6e..2d8e15064e4 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -1271,7 +1271,7 @@ impl Initialized { if import_result.has_fresh_byzantine_threshold_against() { let blocks_including = self.scraper.get_blocks_including_candidate(&candidate_hash); for (parent_block_number, parent_block_hash) in &blocks_including { - gum::trace!( + gum::warn!( target: LOG_TARGET, ?candidate_hash, ?parent_block_number, @@ -1282,7 +1282,7 @@ impl Initialized { if blocks_including.len() > 0 { ctx.send_message(ChainSelectionMessage::RevertBlocks(blocks_including)).await; } else { - gum::debug!( + gum::warn!( target: LOG_TARGET, ?candidate_hash, ?session, diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs b/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs index 38956700545..b1870164cb8 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs @@ -135,11 +135,14 @@ impl ScrapedCandidates { } pub fn insert(&mut self, block_number: BlockNumber, candidate_hash: CandidateHash) { - self.candidates.insert(candidate_hash); - self.candidates_by_block_number + if self + .candidates_by_block_number .entry(block_number) .or_default() - .insert(candidate_hash); + .insert(candidate_hash) + { + self.candidates.insert(candidate_hash); + } } // Used only for tests to verify the pruning doesn't leak data. @@ -159,6 +162,8 @@ mod scraped_candidates_tests { let mut candidates = ScrapedCandidates::new(); let target = CandidateHash(BlakeTwo256::hash(&vec![1, 2, 3])); candidates.insert(1, target); + // Repeated inserts at same height should be fine: + candidates.insert(1, target); assert!(candidates.contains(&target)); -- GitLab From dbbfe041fd5bb88fe63d1196e49a73a595761c7d Mon Sep 17 00:00:00 2001 From: Squirrel Date: Fri, 1 Sep 2023 21:15:20 +0100 Subject: [PATCH 057/633] [xcm-emulator] Unignore cumulus integration tests (#1247) * tests should not be run with runtime-benchmarks feature --- .../assets/asset-hub-kusama/Cargo.toml | 16 ++ .../assets/asset-hub-kusama/src/lib.rs | 3 +- .../src/tests/hrmp_channels.rs | 3 +- .../assets/asset-hub-kusama/src/tests/send.rs | 135 ++++++++--------- .../asset-hub-kusama/src/tests/teleport.rs | 2 - .../assets/asset-hub-polkadot/Cargo.toml | 16 ++ .../assets/asset-hub-polkadot/src/lib.rs | 5 +- .../src/tests/hrmp_channels.rs | 3 +- .../asset-hub-polkadot/src/tests/send.rs | 141 +++++++++--------- .../assets/asset-hub-westend/Cargo.toml | 16 ++ .../assets/asset-hub-westend/src/lib.rs | 1 + .../asset-hub-westend/src/tests/send.rs | 141 +++++++++--------- .../asset-hub-westend/src/tests/teleport.rs | 2 - .../bridges/bridge-hub-rococo/src/lib.rs | 1 + .../collectives-polkadot/src/lib.rs | 1 + .../src/tests/fellowship.rs | 94 ++++++------ 16 files changed, 322 insertions(+), 258 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 66885797860..d45a201a4d0 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -33,3 +33,19 @@ asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusam # 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", + "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-kusama/src/lib.rs index a81badf1149..9325ca54b06 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -29,7 +29,7 @@ pub use integration_tests_common::{ xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, Kusama, KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, - PenpalKusamaAReceiver, PenpalKusamaASender, + PenpalKusamaAReceiver, PenpalKusamaASender, PenpalKusamaB, PenpalKusamaBPallet, }; pub use parachains_common::{AccountId, Balance}; pub use xcm::{ @@ -87,4 +87,5 @@ 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/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs index aca67e0eeb8..8647c1aa008 100644 --- 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 @@ -21,7 +21,6 @@ const MAX_MESSAGE_SIZE: u32 = 8192; /// Opening HRMP channels between Parachains should work #[test] -#[cfg(feature = "FIXME-IGNORED")] // fn open_hrmp_channel_between_paras_works() { // Parchain A init values let para_a_id = PenpalKusamaA::para_id(); @@ -110,6 +109,8 @@ fn open_hrmp_channel_between_paras_works() { PenpalKusamaB::assert_xcm_pallet_sent(); }); + PenpalKusamaB::execute_with(|| {}); + Kusama::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; 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 index 8a6328d0d6a..598256db83a 100644 --- 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 @@ -126,72 +126,73 @@ fn send_transact_native_from_system_para_to_relay_fails() { /// Parachain should be able to send XCM paying its fee with sufficient asset /// in the System Parachain #[test] -#[ignore] 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, - // }, - // ] - // ); - // }); + 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(); + }); + + PenpalKusamaA::execute_with(|| {}); + + 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-kusama/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs index 868d02fefa6..b671fd5b444 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs @@ -187,7 +187,6 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { /// Limited Teleport of native asset from System Parachain to Relay Chain /// should work when there is enough balance in Relay Chain's `CheckAccount` #[test] -#[cfg(feature = "FIXME-IGNORED")] // 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(); @@ -226,7 +225,6 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { /// 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] -#[cfg(feature = "FIXME-IGNORED")] // 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; 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 index ef62f4b88d5..3d5d23e9963 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -32,3 +32,19 @@ asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusam # 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", + "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 index 6ca6c55f4e9..6cbf6ab1ccb 100644 --- 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 @@ -28,8 +28,8 @@ pub use integration_tests_common::{ }, xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, - PenpalPolkadotA, PenpalPolkadotAReceiver, Polkadot, PolkadotPallet, PolkadotReceiver, - PolkadotSender, + PenpalPolkadotA, PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotB, + PenpalPolkadotBPallet, Polkadot, PolkadotPallet, PolkadotReceiver, PolkadotSender, }; pub use parachains_common::{AccountId, Balance}; pub use xcm::{ @@ -87,4 +87,5 @@ 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-polkadot/src/tests/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs index 7756a0cc202..337e4ba6113 100644 --- 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 @@ -21,7 +21,6 @@ const MAX_MESSAGE_SIZE: u32 = 8192; /// Opening HRMP channels between Parachains should work #[test] -#[cfg(feature = "FIXME-IGNORED")] // fn open_hrmp_channel_between_paras_works() { // Parchain A init values let para_a_id = PenpalPolkadotA::para_id(); @@ -110,6 +109,8 @@ fn open_hrmp_channel_between_paras_works() { PenpalPolkadotB::assert_xcm_pallet_sent(); }); + PenpalPolkadotB::execute_with(|| {}); + Polkadot::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; 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 index 0b4a9836acd..978377b0fda 100644 --- 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 @@ -129,75 +129,76 @@ fn send_transact_native_from_system_para_to_relay_fails() { /// Parachain should be able to send XCM paying its fee with sufficient asset /// in the System Parachain #[test] -#[ignore] 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, - // }, - // ] - // ); - // }); + 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(); + }); + + PenpalPolkadotA::execute_with(|| {}); + + 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-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index c76d4b1501b..34d34009ebd 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 @@ -33,3 +33,19 @@ asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-west # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} integration-tests-common = { path = "../../common", default-features = false} + +[features] +runtime-benchmarks = [ + "asset-hub-westend-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", + "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-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index c00f557f177..2c89c0f9dd4 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 @@ -89,4 +89,5 @@ 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/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs index bdc3ff90e41..f2040351e5d 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 @@ -68,75 +68,76 @@ fn send_transact_sudo_from_relay_to_system_para_works() { /// Parachain should be able to send XCM paying its fee with sufficient asset /// in the System Parachain #[test] -#[ignore] fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { - // let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( - // AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()), - // ); - - // // Force create and mint assets for Parachain's sovereign account - // AssetHubWestend::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 = AssetHubWestend::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 = - // PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into(); - // let xcm = xcm_transact_paid_execution( - // call, - // origin_kind, - // native_asset, - // para_sovereign_account.clone(), - // ); - - // PenpalWestendA::execute_with(|| { - // assert_ok!(::PolkadotXcm::send( - // root_origin, - // bx!(system_para_destination), - // bx!(xcm), - // )); - - // PenpalWestendA::assert_xcm_pallet_sent(); - // }); - - // AssetHubWestend::execute_with(|| { - // type RuntimeEvent = ::RuntimeEvent; - - // AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( - // 2_176_414_000, - // 203_593, - // ))); - - // assert_expected_events!( - // AssetHubWestend, - // 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, - // }, - // ] - // ); - // }); + let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()), + ); + + // Force create and mint assets for Parachain's sovereign account + AssetHubWestend::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 = AssetHubWestend::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 = + PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + native_asset, + para_sovereign_account.clone(), + ); + + PenpalWestendA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + PenpalWestendA::assert_xcm_pallet_sent(); + }); + + PenpalWestendA::execute_with(|| {}); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( + 2_176_414_000, + 203_593, + ))); + + assert_expected_events!( + AssetHubWestend, + 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-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index b45cfbe16c0..233dc32b13b 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 @@ -187,7 +187,6 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { /// Limited Teleport of native asset from System Parachain to Relay Chain /// should work when there is enough balance in Relay Chain's `CheckAccount` #[test] -#[cfg(feature = "FIXME-IGNORED")] // 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(); @@ -226,7 +225,6 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { /// 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] -#[cfg(feature = "FIXME-IGNORED")] // fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; 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 468527ec582..0a923ec04de 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 @@ -64,4 +64,5 @@ 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/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs index 6bbd112f687..ad2b5a50111 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -80,4 +80,5 @@ pub fn system_para_test_args( } #[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 index de84ac64d26..26fa55acb0d 100644 --- 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 @@ -16,54 +16,64 @@ //! 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] -#[ignore] 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; + 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; - // 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)); + }); - // 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; - // 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 { .. }) => {}, + ] + ); + }); - // assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount)); - // assert_expected_events!( - // Collectives, - // vec![ - // RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - // ] - // ); - // }); + Collectives::execute_with(|| {}); - // AssetHubPolkadot::execute_with(|| { - // type RuntimeEvent = ::RuntimeEvent; + 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 { .. }) => {}, - // ] - // ); - // }); + 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 { .. }) => {}, + ] + ); + }); } -- GitLab From 8cfaad46007f1e68d0e1c285e5057922ff9cb352 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Sat, 2 Sep 2023 02:34:46 +0200 Subject: [PATCH 058/633] [improve docs]: Template pallet (#1280) * add and refactor docs * commit mistake * improvements * fixes * Apply suggestions from code review Co-authored-by: Squirrel * fix: use markdown syntax * from review: explain what generate_deposit does * from review: add note about errors * updates * fix: bring back getter --------- Co-authored-by: Squirrel --- .../node-template/pallets/template/src/lib.rs | 156 ++++++++++++++---- 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/substrate/bin/node-template/pallets/template/src/lib.rs b/substrate/bin/node-template/pallets/template/src/lib.rs index edf7769bab7..4a2e53baa77 100644 --- a/substrate/bin/node-template/pallets/template/src/lib.rs +++ b/substrate/bin/node-template/pallets/template/src/lib.rs @@ -1,105 +1,201 @@ +//! # Template Pallet +//! +//! A pallet with minimal functionality to help developers understand the essential components of +//! writing a FRAME pallet. It is typically used in beginner tutorials or in Substrate template +//! nodes as a starting point for creating a new pallet and **not meant to be used in production**. +//! +//! ## Overview +//! +//! This template pallet contains basic examples of: +//! - declaring a storage item that stores a single `u32` value +//! - declaring and using events +//! - declaring and using errors +//! - a dispatchable function that allows a user to set a new value to storage and emits an event +//! upon success +//! - another dispatchable function that causes a custom error to be thrown +//! +//! Each pallet section is annotated with an attribute using the `#[pallet::...]` procedural macro. +//! This macro generates the necessary code for a pallet to be aggregated into a FRAME runtime. +//! +//! Learn more about FRAME macros [here](https://docs.substrate.io/reference/frame-macros/). +//! +//! ### Pallet Sections +//! +//! The pallet sections in this template are: +//! +//! - A **configuration trait** that defines the types and parameters which the pallet depends on +//! (denoted by the `#[pallet::config]` attribute). See: [`Config`]. +//! - A **means to store pallet-specific data** (denoted by the `#[pallet::storage]` attribute). +//! See: [`storage_types`]. +//! - A **declaration of the events** this pallet emits (denoted by the `#[pallet::event]` +//! attribute). See: [`Event`]. +//! - A **declaration of the errors** that this pallet can throw (denoted by the `#[pallet::error]` +//! attribute). See: [`Error`]. +//! - A **set of dispatchable functions** that define the pallet's functionality (denoted by the +//! `#[pallet::call]` attribute). See: [`dispatchables`]. +//! +//! Run `cargo doc --package pallet-template --open` to view this pallet's documentation. + +// We make sure this pallet uses `no_std` for compiling to Wasm. #![cfg_attr(not(feature = "std"), no_std)] -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// +// Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; +// FRAME pallets require their own "mock runtimes" to be able to run unit tests. This module +// contains a mock runtime specific for testing this pallet's functionality. #[cfg(test)] mod mock; +// This module contains the unit tests for this pallet. +// Learn about pallet unit testing here: https://docs.substrate.io/test/unit-testing/ #[cfg(test)] mod tests; +// Every callable function or "dispatchable" a pallet exposes must have weight values that correctly +// estimate a dispatchable's execution time. The benchmarking module is used to calculate weights +// for each dispatchable and generates this pallet's weight.rs file. Learn more about benchmarking here: https://docs.substrate.io/test/benchmark/ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod weights; pub use weights::*; +// All pallet logic is defined in its own module and must be annotated by the `pallet` attribute. #[frame_support::pallet] pub mod pallet { + // Import various useful types required by all FRAME pallets. use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + // The `Pallet` struct serves as a placeholder to implement traits, methods and dispatchables + // (`Call`s) in this pallet. #[pallet::pallet] pub struct Pallet(_); - /// Configure the pallet by specifying the parameters and types on which it depends. + /// The pallet's configuration trait. + /// + /// All our types and constants a pallet depends on must be declared here. + /// These types are defined generically and made concrete when the pallet is declared in the + /// `runtime/src/lib.rs` file of your chain. #[pallet::config] pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. + /// The overarching runtime event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Type representing the weight of this pallet + /// A type representing the weights required by the dispatchables of this pallet. type WeightInfo: WeightInfo; } - // The pallet's runtime storage items. - // https://docs.substrate.io/main-docs/build/runtime-storage/ + /// A storage item for this pallet. + /// + /// In this template, we are declaring a storage item called `Something` that stores a single + /// `u32` value. Learn more about runtime storage here: + /// The [`getter`] macro generates a function to conveniently retrieve the value from storage. #[pallet::storage] #[pallet::getter(fn something)] - // Learn more about declaring storage items: - // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items pub type Something = StorageValue<_, u32>; - // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/main-docs/build/events-errors/ + /// Events that functions in this pallet can emit. + /// + /// Events are a simple means of indicating to the outside world (such as dApps, chain explorers + /// or other users) that some notable update in the runtime has occurred. In a FRAME pallet, the + /// documentation for each event field and its parameters is added to a node's metadata so it + /// can be used by external interfaces or tools. + /// + /// The `generate_deposit` macro generates a function on `Pallet` called `deposit_event` which + /// will convert the event type of your pallet into `RuntimeEvent` (declared in the pallet's + /// [`Config`] trait) and deposit it using [`frame_system::Pallet::deposit_event`]. #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event documentation should end with an array that provides descriptive names for event - /// parameters. [something, who] - SomethingStored { something: u32, who: T::AccountId }, + /// A user has successfully set a new value. + SomethingStored { + /// The new value set. + something: u32, + /// The account who set the new value. + who: T::AccountId, + }, } - // Errors inform users that something went wrong. + /// Errors that can be returned by this pallet. + /// + /// Errors tell users that something went wrong so it's important that their naming is + /// informative. Similar to events, error documentation is added to a node's metadata so it's + /// equally important that they have helpful documentation associated with them. + /// + /// This type of runtime error can be up to 4 bytes in size should you want to return additional + /// information. #[pallet::error] pub enum Error { - /// Error names should be descriptive. + /// The value retrieved was `None` as no value was previously set. NoneValue, - /// Errors should have helpful documentation associated with them. + /// There was an attempt to increment the value in storage over `u32::MAX`. StorageOverflow, } - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + /// The pallet's dispatchable functions ([`Call`]s). + /// + /// Dispatchable functions allows users to interact with the pallet and invoke state changes. + /// These functions materialize as "extrinsics", which are often compared to transactions. + /// They must always return a `DispatchResult` and be annotated with a weight and call index. + /// + /// The [`call_index`] macro is used to explicitly + /// define an index for calls in the [`Call`] enum. This is useful for pallets that may + /// introduce new dispatchables over time. If the order of a dispatchable changes, its index + /// will also change which will break backwards compatibility. + /// + /// The [`weight`] macro is used to assign a weight to each call. #[pallet::call] impl Pallet { - /// An example dispatchable that takes a singles value as a parameter, writes the value to - /// storage and emits an event. This function must be dispatched by a signed extrinsic. + /// An example dispatchable that takes a single u32 value as a parameter, writes the value + /// to storage and emits an event. + /// + /// It checks that the _origin_ for this call is _Signed_ and returns a dispatch + /// error if it isn't. Learn more about origins here: #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::do_something())] pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ let who = ensure_signed(origin)?; // Update storage. - >::put(something); + Something::::put(something); // Emit an event. Self::deposit_event(Event::SomethingStored { something, who }); - // Return a successful DispatchResultWithPostInfo + + // Return a successful `DispatchResult` Ok(()) } /// An example dispatchable that may throw a custom error. + /// + /// It checks that the caller is a signed origin and reads the current value from the + /// `Something` storage item. If a current value exists, it is incremented by 1 and then + /// written back to storage. + /// + /// ## Errors + /// + /// The function will return an error under the following conditions: + /// + /// - If no value has been set ([`Error::NoneValue`]) + /// - If incrementing the value in storage causes an arithmetic overflow + /// ([`Error::StorageOverflow`]) #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::cause_error())] pub fn cause_error(origin: OriginFor) -> DispatchResult { let _who = ensure_signed(origin)?; // Read a value from storage. - match >::get() { + match Pallet::::something() { // Return an error if the value has not been set. None => Err(Error::::NoneValue.into()), Some(old) => { - // Increment the value read from storage; will error in the event of overflow. + // Increment the value read from storage. This will cause an error in the event + // of overflow. let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; // Update the value in storage with the incremented result. - >::put(new); + Something::::put(new); Ok(()) }, } -- GitLab From 3f92be2cc2a2fc6d24413200abb7bf6eea71df67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sat, 2 Sep 2023 14:41:33 +0200 Subject: [PATCH 059/633] contracts: Update to wasmi 0.31 (#1350) * contracts: Update to wasmi 0.31 * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_contracts --------- Co-authored-by: command-bot <> --- Cargo.lock | 38 +- substrate/frame/contracts/Cargo.toml | 2 +- substrate/frame/contracts/src/weights.rs | 1734 +++++++++++----------- 3 files changed, 869 insertions(+), 905 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13bc2327dae..f3bbc2faf29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,12 +6471,6 @@ dependencies = [ "webrtc-util", ] -[[package]] -name = "intx" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -9387,7 +9381,7 @@ dependencies = [ "sp-runtime", "sp-std", "wasm-instrument 0.4.0", - "wasmi 0.30.0", + "wasmi", "wat", ] @@ -16574,7 +16568,7 @@ dependencies = [ "smallvec", "soketto", "twox-hash", - "wasmi 0.31.0", + "wasmi", "x25519-dalek 2.0.0", "zeroize", ] @@ -19811,20 +19805,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmi" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" -dependencies = [ - "intx", - "smallvec", - "spin 0.9.8", - "wasmi_arena", - "wasmi_core 0.12.0", - "wasmparser-nostd", -] - [[package]] name = "wasmi" version = "0.31.0" @@ -19834,7 +19814,7 @@ dependencies = [ "smallvec", "spin 0.9.8", "wasmi_arena", - "wasmi_core 0.13.0", + "wasmi_core", "wasmparser-nostd", ] @@ -19844,18 +19824,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" -[[package]] -name = "wasmi_core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" -dependencies = [ - "downcast-rs", - "libm", - "num-traits", - "paste", -] - [[package]] name = "wasmi_core" version = "0.13.0" diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 8d6a9fd9cdb..237ab9303e2 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -26,7 +26,7 @@ serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } -wasmi = { version = "0.30", default-features = false } +wasmi = { version = "0.31", default-features = false } impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate contract code diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index 34bea8ff0a3..22e4f749313 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -18,10 +18,10 @@ //! Autogenerated weights for `pallet_contracts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-pzhd7p6z-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: // target/production/substrate-node @@ -32,12 +32,12 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_contracts // --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/contracts/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/contracts/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -141,8 +141,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_410_000 picoseconds. - Weight::from_parts(2_581_000, 1627) + // Minimum execution time: 2_548_000 picoseconds. + Weight::from_parts(2_670_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -152,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `451 + k * (69 ±0)` // Estimated: `441 + k * (70 ±0)` - // Minimum execution time: 13_278_000 picoseconds. - Weight::from_parts(13_944_000, 441) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(1_194_404, 0).saturating_mul(k.into())) + // Minimum execution time: 13_526_000 picoseconds. + Weight::from_parts(13_902_000, 441) + // Standard Error: 1_058 + .saturating_add(Weight::from_parts(1_274_724, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -169,10 +169,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_533_000 picoseconds. - Weight::from_parts(9_141_899, 6149) + // Minimum execution time: 8_426_000 picoseconds. + Weight::from_parts(8_591_621, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_327, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -185,8 +185,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_998_000 picoseconds. - Weight::from_parts(17_776_000, 6450) + // Minimum execution time: 17_008_000 picoseconds. + Weight::from_parts(17_742_000, 6450) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,10 +199,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_919_000 picoseconds. - Weight::from_parts(4_057_153, 3635) - // Standard Error: 1_252 - .saturating_add(Weight::from_parts(1_151_419, 0).saturating_mul(k.into())) + // Minimum execution time: 3_949_000 picoseconds. + Weight::from_parts(4_062_000, 3635) + // Standard Error: 1_983 + .saturating_add(Weight::from_parts(1_173_197, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -221,10 +221,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `325 + c * (1 ±0)` // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 17_730_000 picoseconds. - Weight::from_parts(17_540_884, 6263) + // Minimum execution time: 17_094_000 picoseconds. + Weight::from_parts(17_338_591, 6263) // Standard Error: 1 - .saturating_add(Weight::from_parts(417, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(436, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -235,8 +235,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 13_089_000 picoseconds. - Weight::from_parts(13_727_000, 6380) + // Minimum execution time: 12_704_000 picoseconds. + Weight::from_parts(13_147_000, 6380) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -250,8 +250,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `360` // Estimated: `6300` - // Minimum execution time: 49_083_000 picoseconds. - Weight::from_parts(50_462_000, 6300) + // Minimum execution time: 48_387_000 picoseconds. + Weight::from_parts(50_024_000, 6300) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -263,8 +263,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 49_299_000 picoseconds. - Weight::from_parts(50_805_000, 6534) + // Minimum execution time: 59_300_000 picoseconds. + Weight::from_parts(61_805_000, 6534) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -274,8 +274,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 3_305_000 picoseconds. - Weight::from_parts(3_489_000, 1627) + // Minimum execution time: 3_327_000 picoseconds. + Weight::from_parts(3_502_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -287,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 12_657_000 picoseconds. - Weight::from_parts(13_100_000, 3631) + // Minimum execution time: 12_759_000 picoseconds. + Weight::from_parts(13_134_000, 3631) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -298,8 +298,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_784_000 picoseconds. - Weight::from_parts(4_994_000, 3607) + // Minimum execution time: 4_775_000 picoseconds. + Weight::from_parts(5_084_000, 3607) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -310,8 +310,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_762_000 picoseconds. - Weight::from_parts(6_945_000, 3632) + // Minimum execution time: 6_663_000 picoseconds. + Weight::from_parts(6_855_000, 3632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -322,8 +322,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_999_000 picoseconds. - Weight::from_parts(7_372_000, 3607) + // Minimum execution time: 7_212_000 picoseconds. + Weight::from_parts(7_426_000, 3607) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -344,12 +344,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `759` - // Estimated: `6710 + c * (1 ±0)` - // Minimum execution time: 304_121_000 picoseconds. - Weight::from_parts(288_627_840, 6710) - // Standard Error: 83 - .saturating_add(Weight::from_parts(37_343, 0).saturating_mul(c.into())) + // Measured: `792` + // Estimated: `6743 + c * (1 ±0)` + // Minimum execution time: 289_557_000 picoseconds. + Weight::from_parts(272_895_652, 6743) + // Standard Error: 80 + .saturating_add(Weight::from_parts(39_917, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -377,16 +377,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `290` - // Estimated: `8714` - // Minimum execution time: 4_101_589_000 picoseconds. - Weight::from_parts(694_193_047, 8714) - // Standard Error: 334 - .saturating_add(Weight::from_parts(108_847, 0).saturating_mul(c.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_677, 0).saturating_mul(i.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_783, 0).saturating_mul(s.into())) + // Measured: `323` + // Estimated: `8747` + // Minimum execution time: 4_671_359_000 picoseconds. + Weight::from_parts(586_523_882, 8747) + // Standard Error: 206 + .saturating_add(Weight::from_parts(115_402, 0).saturating_mul(c.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(1_797, 0).saturating_mul(i.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(2_046, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -404,22 +404,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `6471` - // Minimum execution time: 2_011_580_000 picoseconds. - Weight::from_parts(397_415_227, 6471) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_689, 0).saturating_mul(i.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_679, 0).saturating_mul(s.into())) + // Measured: `560` + // Estimated: `6504` + // Minimum execution time: 2_170_657_000 picoseconds. + Weight::from_parts(369_331_405, 6504) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_940, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_858, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -439,10 +439,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `793` - // Estimated: `6733` - // Minimum execution time: 204_975_000 picoseconds. - Weight::from_parts(214_770_000, 6733) + // Measured: `826` + // Estimated: `6766` + // Minimum execution time: 204_287_000 picoseconds. + Weight::from_parts(213_239_000, 6766) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -461,10 +461,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 269_545_000 picoseconds. - Weight::from_parts(256_054_650, 3607) - // Standard Error: 91 - .saturating_add(Weight::from_parts(72_743, 0).saturating_mul(c.into())) + // Minimum execution time: 285_434_000 picoseconds. + Weight::from_parts(242_697_648, 3607) + // Standard Error: 128 + .saturating_add(Weight::from_parts(76_087, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -482,8 +482,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 47_880_000 picoseconds. - Weight::from_parts(49_427_000, 3780) + // Minimum execution time: 46_486_000 picoseconds. + Weight::from_parts(48_422_000, 3780) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -499,8 +499,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 37_898_000 picoseconds. - Weight::from_parts(39_826_000, 8967) + // Minimum execution time: 37_568_000 picoseconds. + Weight::from_parts(38_589_000, 8967) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -521,12 +521,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `833 + r * (6 ±0)` - // Estimated: `6773 + r * (6 ±0)` - // Minimum execution time: 260_916_000 picoseconds. - Weight::from_parts(295_521_846, 6773) - // Standard Error: 1_126 - .saturating_add(Weight::from_parts(348_317, 0).saturating_mul(r.into())) + // Measured: `866 + r * (6 ±0)` + // Estimated: `6806 + r * (6 ±0)` + // Minimum execution time: 274_513_000 picoseconds. + Weight::from_parts(288_793_403, 6806) + // Standard Error: 650 + .saturating_add(Weight::from_parts(339_309, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -548,12 +548,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (209 ±0)` - // Estimated: `6793 + r * (2684 ±0)` - // Minimum execution time: 274_335_000 picoseconds. - Weight::from_parts(132_998_512, 6793) - // Standard Error: 7_396 - .saturating_add(Weight::from_parts(3_602_287, 0).saturating_mul(r.into())) + // Measured: `922 + r * (209 ±0)` + // Estimated: `6826 + r * (2684 ±0)` + // Minimum execution time: 260_096_000 picoseconds. + Weight::from_parts(149_954_322, 6826) + // Standard Error: 5_713 + .saturating_add(Weight::from_parts(3_788_924, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -576,12 +576,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (213 ±0)` - // Estimated: `6797 + r * (2688 ±0)` - // Minimum execution time: 272_514_000 picoseconds. - Weight::from_parts(104_825_618, 6797) - // Standard Error: 10_038 - .saturating_add(Weight::from_parts(4_520_258, 0).saturating_mul(r.into())) + // Measured: `921 + r * (213 ±0)` + // Estimated: `6830 + r * (2688 ±0)` + // Minimum execution time: 277_496_000 picoseconds. + Weight::from_parts(285_839_000, 6830) + // Standard Error: 10_076 + .saturating_add(Weight::from_parts(4_720_110, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -604,12 +604,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `840 + r * (6 ±0)` - // Estimated: `6782 + r * (6 ±0)` - // Minimum execution time: 264_593_000 picoseconds. - Weight::from_parts(294_139_363, 6782) - // Standard Error: 907 - .saturating_add(Weight::from_parts(432_964, 0).saturating_mul(r.into())) + // Measured: `873 + r * (6 ±0)` + // Estimated: `6815 + r * (6 ±0)` + // Minimum execution time: 275_655_000 picoseconds. + Weight::from_parts(291_386_528, 6815) + // Standard Error: 898 + .saturating_add(Weight::from_parts(428_765, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -631,12 +631,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (3 ±0)` - // Estimated: `6771 + r * (3 ±0)` - // Minimum execution time: 260_412_000 picoseconds. - Weight::from_parts(284_371_703, 6771) - // Standard Error: 433 - .saturating_add(Weight::from_parts(182_952, 0).saturating_mul(r.into())) + // Measured: `863 + r * (3 ±0)` + // Estimated: `6804 + r * (3 ±0)` + // Minimum execution time: 260_323_000 picoseconds. + Weight::from_parts(286_371_403, 6804) + // Standard Error: 451 + .saturating_add(Weight::from_parts(183_053, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -656,12 +656,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `720 + r * (3 ±0)` - // Estimated: `6660 + r * (3 ±0)` - // Minimum execution time: 255_112_000 picoseconds. - Weight::from_parts(273_052_488, 6660) - // Standard Error: 376 - .saturating_add(Weight::from_parts(166_644, 0).saturating_mul(r.into())) + // Measured: `753 + r * (3 ±0)` + // Estimated: `6693 + r * (3 ±0)` + // Minimum execution time: 262_974_000 picoseconds. + Weight::from_parts(276_571_502, 6693) + // Standard Error: 527 + .saturating_add(Weight::from_parts(165_364, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -683,12 +683,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `834 + r * (6 ±0)` - // Estimated: `6774 + r * (6 ±0)` - // Minimum execution time: 270_426_000 picoseconds. - Weight::from_parts(289_240_775, 6774) - // Standard Error: 748 - .saturating_add(Weight::from_parts(344_791, 0).saturating_mul(r.into())) + // Measured: `867 + r * (6 ±0)` + // Estimated: `6807 + r * (6 ±0)` + // Minimum execution time: 272_826_000 picoseconds. + Weight::from_parts(290_963_001, 6807) + // Standard Error: 810 + .saturating_add(Weight::from_parts(343_762, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -710,12 +710,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (6 ±0)` - // Estimated: `6773 + r * (6 ±0)` - // Minimum execution time: 260_217_000 picoseconds. - Weight::from_parts(288_660_978, 6773) - // Standard Error: 1_199 - .saturating_add(Weight::from_parts(550_304, 0).saturating_mul(r.into())) + // Measured: `863 + r * (6 ±0)` + // Estimated: `6806 + r * (6 ±0)` + // Minimum execution time: 277_324_000 picoseconds. + Weight::from_parts(290_872_814, 6806) + // Standard Error: 766 + .saturating_add(Weight::from_parts(371_542, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -737,12 +737,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `974 + r * (6 ±0)` - // Estimated: `6898 + r * (6 ±0)` - // Minimum execution time: 273_473_000 picoseconds. - Weight::from_parts(298_889_279, 6898) - // Standard Error: 4_604 - .saturating_add(Weight::from_parts(1_630_175, 0).saturating_mul(r.into())) + // Measured: `1007 + r * (6 ±0)` + // Estimated: `6931 + r * (6 ±0)` + // Minimum execution time: 274_460_000 picoseconds. + Weight::from_parts(285_748_025, 6931) + // Standard Error: 1_570 + .saturating_add(Weight::from_parts(1_656_237, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -764,12 +764,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (6 ±0)` - // Estimated: `6790 + r * (6 ±0)` - // Minimum execution time: 262_033_000 picoseconds. - Weight::from_parts(284_293_851, 6790) - // Standard Error: 591 - .saturating_add(Weight::from_parts(369_240, 0).saturating_mul(r.into())) + // Measured: `877 + r * (6 ±0)` + // Estimated: `6823 + r * (6 ±0)` + // Minimum execution time: 278_254_000 picoseconds. + Weight::from_parts(283_893_525, 6823) + // Standard Error: 726 + .saturating_add(Weight::from_parts(347_368, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -791,12 +791,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (6 ±0)` - // Estimated: `6783 + r * (6 ±0)` - // Minimum execution time: 274_568_000 picoseconds. - Weight::from_parts(294_688_466, 6783) - // Standard Error: 768 - .saturating_add(Weight::from_parts(349_584, 0).saturating_mul(r.into())) + // Measured: `875 + r * (6 ±0)` + // Estimated: `6816 + r * (6 ±0)` + // Minimum execution time: 279_646_000 picoseconds. + Weight::from_parts(292_505_446, 6816) + // Standard Error: 867 + .saturating_add(Weight::from_parts(337_202, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -818,12 +818,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839 + r * (6 ±0)` - // Estimated: `6786 + r * (6 ±0)` - // Minimum execution time: 264_061_000 picoseconds. - Weight::from_parts(287_964_188, 6786) - // Standard Error: 490 - .saturating_add(Weight::from_parts(356_273, 0).saturating_mul(r.into())) + // Measured: `872 + r * (6 ±0)` + // Estimated: `6819 + r * (6 ±0)` + // Minimum execution time: 274_522_000 picoseconds. + Weight::from_parts(295_135_659, 6819) + // Standard Error: 1_052 + .saturating_add(Weight::from_parts(330_788, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -845,12 +845,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (6 ±0)` - // Estimated: `6771 + r * (6 ±0)` - // Minimum execution time: 275_707_000 picoseconds. - Weight::from_parts(290_797_828, 6771) - // Standard Error: 967 - .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) + // Measured: `863 + r * (6 ±0)` + // Estimated: `6804 + r * (6 ±0)` + // Minimum execution time: 274_228_000 picoseconds. + Weight::from_parts(289_201_593, 6804) + // Standard Error: 752 + .saturating_add(Weight::from_parts(337_860, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -874,12 +874,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `904 + r * (14 ±0)` - // Estimated: `6839 + r * (14 ±0)` - // Minimum execution time: 272_492_000 picoseconds. - Weight::from_parts(295_010_878, 6839) - // Standard Error: 2_549 - .saturating_add(Weight::from_parts(1_426_715, 0).saturating_mul(r.into())) + // Measured: `937 + r * (14 ±0)` + // Estimated: `6872 + r * (14 ±0)` + // Minimum execution time: 277_142_000 picoseconds. + Weight::from_parts(296_736_114, 6872) + // Standard Error: 1_502 + .saturating_add(Weight::from_parts(1_446_663, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) @@ -901,12 +901,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `832 + r * (6 ±0)` - // Estimated: `6774 + r * (6 ±0)` - // Minimum execution time: 257_981_000 picoseconds. - Weight::from_parts(285_824_773, 6774) - // Standard Error: 704 - .saturating_add(Weight::from_parts(301_327, 0).saturating_mul(r.into())) + // Measured: `865 + r * (6 ±0)` + // Estimated: `6807 + r * (6 ±0)` + // Minimum execution time: 276_087_000 picoseconds. + Weight::from_parts(287_863_377, 6807) + // Standard Error: 495 + .saturating_add(Weight::from_parts(282_718, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -928,12 +928,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `836` - // Estimated: `6776` - // Minimum execution time: 259_470_000 picoseconds. - Weight::from_parts(232_759_442, 6776) - // Standard Error: 24 - .saturating_add(Weight::from_parts(981, 0).saturating_mul(n.into())) + // Measured: `869` + // Estimated: `6809` + // Minimum execution time: 277_128_000 picoseconds. + Weight::from_parts(234_478_674, 6809) + // Standard Error: 23 + .saturating_add(Weight::from_parts(1_052, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -954,12 +954,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `820 + r * (45 ±0)` - // Estimated: `6760 + r * (45 ±0)` - // Minimum execution time: 252_740_000 picoseconds. - Weight::from_parts(278_155_436, 6760) - // Standard Error: 882_420 - .saturating_add(Weight::from_parts(755_063, 0).saturating_mul(r.into())) + // Measured: `853 + r * (45 ±0)` + // Estimated: `6793 + r * (45 ±0)` + // Minimum execution time: 251_983_000 picoseconds. + Weight::from_parts(277_986_885, 6793) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) @@ -981,12 +979,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830` - // Estimated: `6777` - // Minimum execution time: 257_318_000 picoseconds. - Weight::from_parts(285_765_697, 6777) - // Standard Error: 1 - .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) + // Measured: `863` + // Estimated: `6810` + // Minimum execution time: 275_108_000 picoseconds. + Weight::from_parts(284_552_708, 6810) + // Standard Error: 0 + .saturating_add(Weight::from_parts(391, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1013,12 +1011,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2939 + r * (316 ±0)` - // Estimated: `8879 + r * (5266 ±0)` - // Minimum execution time: 280_392_000 picoseconds. - Weight::from_parts(310_023_381, 8879) - // Standard Error: 1_008_026 - .saturating_add(Weight::from_parts(130_208_818, 0).saturating_mul(r.into())) + // Measured: `2972 + r * (316 ±0)` + // Estimated: `8912 + r * (5266 ±0)` + // Minimum execution time: 281_278_000 picoseconds. + Weight::from_parts(306_800_667, 8912) + // Standard Error: 855_257 + .saturating_add(Weight::from_parts(126_508_132, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1044,12 +1042,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (10 ±0)` - // Estimated: `6852 + r * (10 ±0)` - // Minimum execution time: 270_547_000 picoseconds. - Weight::from_parts(295_931_189, 6852) - // Standard Error: 3_280 - .saturating_add(Weight::from_parts(1_941_248, 0).saturating_mul(r.into())) + // Measured: `944 + r * (10 ±0)` + // Estimated: `6885 + r * (10 ±0)` + // Minimum execution time: 260_609_000 picoseconds. + Weight::from_parts(287_385_076, 6885) + // Standard Error: 2_754 + .saturating_add(Weight::from_parts(2_057_388, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -1071,12 +1069,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (10 ±0)` - // Estimated: `6772 + r * (10 ±0)` - // Minimum execution time: 255_730_000 picoseconds. - Weight::from_parts(301_859_471, 6772) - // Standard Error: 5_401 - .saturating_add(Weight::from_parts(3_887_632, 0).saturating_mul(r.into())) + // Measured: `863 + r * (10 ±0)` + // Estimated: `6805 + r * (10 ±0)` + // Minimum execution time: 254_770_000 picoseconds. + Weight::from_parts(255_105_647, 6805) + // Standard Error: 5_707 + .saturating_add(Weight::from_parts(3_808_788, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -1099,14 +1097,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `847 + t * (32 ±0)` - // Estimated: `6792 + t * (2508 ±0)` - // Minimum execution time: 276_643_000 picoseconds. - Weight::from_parts(294_275_838, 6792) - // Standard Error: 106_745 - .saturating_add(Weight::from_parts(2_831_489, 0).saturating_mul(t.into())) - // Standard Error: 29 - .saturating_add(Weight::from_parts(624, 0).saturating_mul(n.into())) + // Measured: `880 + t * (32 ±0)` + // Estimated: `6825 + t * (2508 ±0)` + // Minimum execution time: 278_200_000 picoseconds. + Weight::from_parts(288_081_493, 6825) + // Standard Error: 97_535 + .saturating_add(Weight::from_parts(3_683_455, 0).saturating_mul(t.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1130,12 +1128,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `829 + r * (7 ±0)` - // Estimated: `6774 + r * (7 ±0)` - // Minimum execution time: 169_012_000 picoseconds. - Weight::from_parts(179_567_029, 6774) - // Standard Error: 534 - .saturating_add(Weight::from_parts(249_500, 0).saturating_mul(r.into())) + // Measured: `862 + r * (7 ±0)` + // Estimated: `6807 + r * (7 ±0)` + // Minimum execution time: 167_181_000 picoseconds. + Weight::from_parts(178_433_475, 6807) + // Standard Error: 374 + .saturating_add(Weight::from_parts(241_240, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) @@ -1157,12 +1155,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125780` - // Estimated: `131722` - // Minimum execution time: 408_647_000 picoseconds. - Weight::from_parts(387_678_006, 131722) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_045, 0).saturating_mul(i.into())) + // Measured: `125813` + // Estimated: `131755` + // Minimum execution time: 434_456_000 picoseconds. + Weight::from_parts(400_940_450, 131755) + // Standard Error: 13 + .saturating_add(Weight::from_parts(1_102, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1171,12 +1169,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `891 + r * (292 ±0)` - // Estimated: `892 + r * (293 ±0)` - // Minimum execution time: 279_315_000 picoseconds. - Weight::from_parts(171_270_899, 892) - // Standard Error: 15_492 - .saturating_add(Weight::from_parts(6_776_878, 0).saturating_mul(r.into())) + // Measured: `924 + r * (292 ±0)` + // Estimated: `925 + r * (293 ±0)` + // Minimum execution time: 277_825_000 picoseconds. + Weight::from_parts(159_688_263, 925) + // Standard Error: 13_610 + .saturating_add(Weight::from_parts(7_145_641, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1188,12 +1186,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1413` - // Estimated: `1396` - // Minimum execution time: 289_666_000 picoseconds. - Weight::from_parts(348_062_625, 1396) - // Standard Error: 79 - .saturating_add(Weight::from_parts(532, 0).saturating_mul(n.into())) + // Measured: `1446` + // Estimated: `1429` + // Minimum execution time: 284_745_000 picoseconds. + Weight::from_parts(345_928_316, 1429) + // Standard Error: 70 + .saturating_add(Weight::from_parts(547, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -1202,12 +1200,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1219 + n * (1 ±0)` - // Estimated: `1219 + n * (1 ±0)` - // Minimum execution time: 273_840_000 picoseconds. - Weight::from_parts(297_024_621, 1219) - // Standard Error: 55 - .saturating_add(Weight::from_parts(945, 0).saturating_mul(n.into())) + // Measured: `1252 + n * (1 ±0)` + // Estimated: `1252 + n * (1 ±0)` + // Minimum execution time: 275_328_000 picoseconds. + Weight::from_parts(300_037_010, 1252) + // Standard Error: 32 + .saturating_add(Weight::from_parts(558, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1217,12 +1215,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `887 + r * (288 ±0)` - // Estimated: `893 + r * (289 ±0)` - // Minimum execution time: 279_110_000 picoseconds. - Weight::from_parts(177_898_012, 893) - // Standard Error: 16_287 - .saturating_add(Weight::from_parts(6_640_103, 0).saturating_mul(r.into())) + // Measured: `920 + r * (288 ±0)` + // Estimated: `926 + r * (289 ±0)` + // Minimum execution time: 273_742_000 picoseconds. + Weight::from_parts(169_430_806, 926) + // Standard Error: 11_821 + .saturating_add(Weight::from_parts(6_927_074, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1234,10 +1232,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1215 + n * (1 ±0)` - // Estimated: `1215 + n * (1 ±0)` - // Minimum execution time: 276_566_000 picoseconds. - Weight::from_parts(304_992_376, 1215) + // Measured: `1248 + n * (1 ±0)` + // Estimated: `1248 + n * (1 ±0)` + // Minimum execution time: 275_167_000 picoseconds. + Weight::from_parts(301_883_655, 1248) + // Standard Error: 35 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1247,12 +1247,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `887 + r * (296 ±0)` - // Estimated: `889 + r * (297 ±0)` - // Minimum execution time: 266_285_000 picoseconds. - Weight::from_parts(200_488_939, 889) - // Standard Error: 11_193 - .saturating_add(Weight::from_parts(5_467_725, 0).saturating_mul(r.into())) + // Measured: `920 + r * (296 ±0)` + // Estimated: `922 + r * (297 ±0)` + // Minimum execution time: 274_628_000 picoseconds. + Weight::from_parts(195_255_092, 922) + // Standard Error: 9_109 + .saturating_add(Weight::from_parts(5_707_060, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1263,12 +1263,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1231 + n * (1 ±0)` - // Estimated: `1231 + n * (1 ±0)` - // Minimum execution time: 278_625_000 picoseconds. - Weight::from_parts(304_319_493, 1231) - // Standard Error: 39 - .saturating_add(Weight::from_parts(415, 0).saturating_mul(n.into())) + // Measured: `1264 + n * (1 ±0)` + // Estimated: `1264 + n * (1 ±0)` + // Minimum execution time: 274_202_000 picoseconds. + Weight::from_parts(296_440_752, 1264) + // Standard Error: 38 + .saturating_add(Weight::from_parts(1_010, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1278,12 +1278,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `898 + r * (288 ±0)` - // Estimated: `895 + r * (289 ±0)` - // Minimum execution time: 271_851_000 picoseconds. - Weight::from_parts(202_164_395, 895) - // Standard Error: 11_115 - .saturating_add(Weight::from_parts(5_273_320, 0).saturating_mul(r.into())) + // Measured: `931 + r * (288 ±0)` + // Estimated: `928 + r * (289 ±0)` + // Minimum execution time: 274_123_000 picoseconds. + Weight::from_parts(193_280_535, 928) + // Standard Error: 9_264 + .saturating_add(Weight::from_parts(5_548_039, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1294,12 +1294,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1218 + n * (1 ±0)` - // Estimated: `1218 + n * (1 ±0)` - // Minimum execution time: 274_200_000 picoseconds. - Weight::from_parts(299_524_586, 1218) - // Standard Error: 33 - .saturating_add(Weight::from_parts(272, 0).saturating_mul(n.into())) + // Measured: `1251 + n * (1 ±0)` + // Estimated: `1251 + n * (1 ±0)` + // Minimum execution time: 276_425_000 picoseconds. + Weight::from_parts(300_521_806, 1251) + // Standard Error: 36 + .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1309,12 +1309,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880 + r * (296 ±0)` - // Estimated: `885 + r * (297 ±0)` - // Minimum execution time: 258_535_000 picoseconds. - Weight::from_parts(190_468_808, 885) - // Standard Error: 11_940 - .saturating_add(Weight::from_parts(6_737_079, 0).saturating_mul(r.into())) + // Measured: `913 + r * (296 ±0)` + // Estimated: `918 + r * (297 ±0)` + // Minimum execution time: 264_860_000 picoseconds. + Weight::from_parts(191_561_777, 918) + // Standard Error: 10_678 + .saturating_add(Weight::from_parts(6_895_457, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1326,12 +1326,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1232 + n * (1 ±0)` - // Estimated: `1232 + n * (1 ±0)` - // Minimum execution time: 280_536_000 picoseconds. - Weight::from_parts(304_479_477, 1232) + // Measured: `1265 + n * (1 ±0)` + // Estimated: `1265 + n * (1 ±0)` + // Minimum execution time: 282_501_000 picoseconds. + Weight::from_parts(303_351_919, 1265) // Standard Error: 37 - .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(643, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1353,12 +1353,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1382 + r * (45 ±0)` - // Estimated: `7274 + r * (2520 ±0)` - // Minimum execution time: 260_373_000 picoseconds. - Weight::from_parts(278_290_000, 7274) - // Standard Error: 25_683 - .saturating_add(Weight::from_parts(39_264_864, 0).saturating_mul(r.into())) + // Measured: `1415 + r * (45 ±0)` + // Estimated: `7307 + r * (2520 ±0)` + // Minimum execution time: 273_198_000 picoseconds. + Weight::from_parts(179_673_238, 7307) + // Standard Error: 34_990 + .saturating_add(Weight::from_parts(38_468_091, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1382,12 +1382,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1227 + r * (245 ±0)` - // Estimated: `9407 + r * (2721 ±0)` - // Minimum execution time: 277_621_000 picoseconds. - Weight::from_parts(281_775_000, 9407) - // Standard Error: 110_802 - .saturating_add(Weight::from_parts(245_363_533, 0).saturating_mul(r.into())) + // Measured: `1260 + r * (245 ±0)` + // Estimated: `9440 + r * (2721 ±0)` + // Minimum execution time: 283_869_000 picoseconds. + Weight::from_parts(288_374_000, 9440) + // Standard Error: 137_512 + .saturating_add(Weight::from_parts(248_206_665, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1412,11 +1412,11 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` - // Estimated: `6779 + r * (2637 ±3)` - // Minimum execution time: 267_314_000 picoseconds. - Weight::from_parts(279_888_000, 6779) - // Standard Error: 144_378 - .saturating_add(Weight::from_parts(244_606_414, 0).saturating_mul(r.into())) + // Estimated: `6812 + r * (2637 ±3)` + // Minimum execution time: 257_577_000 picoseconds. + Weight::from_parts(277_310_000, 6812) + // Standard Error: 150_204 + .saturating_add(Weight::from_parts(249_943_483, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1441,14 +1441,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1274 + t * (277 ±0)` - // Estimated: `12164 + t * (5227 ±0)` - // Minimum execution time: 477_589_000 picoseconds. - Weight::from_parts(70_712_793, 12164) - // Standard Error: 11_713_135 - .saturating_add(Weight::from_parts(375_371_698, 0).saturating_mul(t.into())) + // Measured: `1307 + t * (277 ±0)` + // Estimated: `12197 + t * (5227 ±0)` + // Minimum execution time: 471_081_000 picoseconds. + Weight::from_parts(79_081_122, 12197) + // Standard Error: 11_777_790 + .saturating_add(Weight::from_parts(357_425_411, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(991, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_111, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -1469,19 +1469,19 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) - /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:800 w:800) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1245 + r * (255 ±0)` - // Estimated: `9587 + r * (2731 ±0)` - // Minimum execution time: 662_502_000 picoseconds. - Weight::from_parts(671_726_000, 9587) - // Standard Error: 351_643 - .saturating_add(Weight::from_parts(390_457_971, 0).saturating_mul(r.into())) + // Measured: `1278 + r * (255 ±0)` + // Estimated: `9620 + r * (2731 ±0)` + // Minimum execution time: 672_742_000 picoseconds. + Weight::from_parts(680_025_000, 9620) + // Standard Error: 313_642 + .saturating_add(Weight::from_parts(388_311_259, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -1502,25 +1502,23 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1270 + t * (104 ±0)` - // Estimated: `12178 + t * (2549 ±1)` - // Minimum execution time: 2_675_525_000 picoseconds. - Weight::from_parts(851_421_242, 12178) - // Standard Error: 7_094_722 - .saturating_add(Weight::from_parts(112_457_697, 0).saturating_mul(t.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(1_867, 0).saturating_mul(i.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(1_931, 0).saturating_mul(s.into())) + // Measured: `1303 + t * (104 ±0)` + // Estimated: `12211 + t * (2549 ±1)` + // Minimum execution time: 2_733_870_000 picoseconds. + Weight::from_parts(1_001_793_458, 12211) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(i.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(2_060, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(11_u64)) @@ -1544,12 +1542,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `829 + r * (8 ±0)` - // Estimated: `6768 + r * (8 ±0)` - // Minimum execution time: 270_818_000 picoseconds. - Weight::from_parts(286_520_166, 6768) - // Standard Error: 575 - .saturating_add(Weight::from_parts(402_286, 0).saturating_mul(r.into())) + // Measured: `862 + r * (8 ±0)` + // Estimated: `6801 + r * (8 ±0)` + // Minimum execution time: 272_658_000 picoseconds. + Weight::from_parts(282_717_645, 6801) + // Standard Error: 517 + .saturating_add(Weight::from_parts(400_604, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1571,12 +1569,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `6775` - // Minimum execution time: 257_134_000 picoseconds. - Weight::from_parts(268_214_648, 6775) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_098, 0).saturating_mul(n.into())) + // Measured: `870` + // Estimated: `6808` + // Minimum execution time: 260_969_000 picoseconds. + Weight::from_parts(265_206_847, 6808) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1597,12 +1595,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6773 + r * (8 ±0)` - // Minimum execution time: 259_222_000 picoseconds. - Weight::from_parts(283_273_283, 6773) - // Standard Error: 967 - .saturating_add(Weight::from_parts(817_596, 0).saturating_mul(r.into())) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6806 + r * (8 ±0)` + // Minimum execution time: 262_351_000 picoseconds. + Weight::from_parts(286_974_296, 6806) + // Standard Error: 514 + .saturating_add(Weight::from_parts(802_363, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1624,12 +1622,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6781` - // Minimum execution time: 260_040_000 picoseconds. - Weight::from_parts(283_869_860, 6781) + // Measured: `872` + // Estimated: `6814` + // Minimum execution time: 276_907_000 picoseconds. + Weight::from_parts(277_928_418, 6814) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_349, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_410, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1650,12 +1648,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6775 + r * (8 ±0)` - // Minimum execution time: 260_698_000 picoseconds. - Weight::from_parts(282_900_345, 6775) - // Standard Error: 805 - .saturating_add(Weight::from_parts(469_457, 0).saturating_mul(r.into())) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6808 + r * (8 ±0)` + // Minimum execution time: 263_660_000 picoseconds. + Weight::from_parts(285_665_916, 6808) + // Standard Error: 527 + .saturating_add(Weight::from_parts(480_457, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1677,12 +1675,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6780` - // Minimum execution time: 256_967_000 picoseconds. - Weight::from_parts(273_024_512, 6780) + // Measured: `872` + // Estimated: `6813` + // Minimum execution time: 262_071_000 picoseconds. + Weight::from_parts(270_115_341, 6813) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_254, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1703,12 +1701,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6772 + r * (8 ±0)` - // Minimum execution time: 272_039_000 picoseconds. - Weight::from_parts(289_853_116, 6772) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6805 + r * (8 ±0)` + // Minimum execution time: 265_568_000 picoseconds. + Weight::from_parts(285_791_811, 6805) // Standard Error: 559 - .saturating_add(Weight::from_parts(459_383, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(505_330, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1730,12 +1728,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6778` - // Minimum execution time: 253_913_000 picoseconds. - Weight::from_parts(274_682_010, 6778) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) + // Measured: `872` + // Estimated: `6811` + // Minimum execution time: 271_336_000 picoseconds. + Weight::from_parts(272_829_313, 6811) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1756,12 +1754,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `964 + n * (1 ±0)` - // Estimated: `6901 + n * (1 ±0)` - // Minimum execution time: 343_955_000 picoseconds. - Weight::from_parts(350_777_388, 6901) + // Measured: `997 + n * (1 ±0)` + // Estimated: `6934 + n * (1 ±0)` + // Minimum execution time: 351_146_000 picoseconds. + Weight::from_parts(355_368_323, 6934) // Standard Error: 14 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(6_155, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1783,12 +1781,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `774 + r * (112 ±0)` - // Estimated: `6715 + r * (112 ±0)` - // Minimum execution time: 268_698_000 picoseconds. - Weight::from_parts(336_398_814, 6715) - // Standard Error: 16_627 - .saturating_add(Weight::from_parts(56_155_384, 0).saturating_mul(r.into())) + // Measured: `807 + r * (112 ±0)` + // Estimated: `6748 + r * (112 ±0)` + // Minimum execution time: 277_250_000 picoseconds. + Weight::from_parts(346_490_114, 6748) + // Standard Error: 14_654 + .saturating_add(Weight::from_parts(56_127_492, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) @@ -1810,12 +1808,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (76 ±0)` - // Estimated: `6768 + r * (77 ±0)` - // Minimum execution time: 258_906_000 picoseconds. - Weight::from_parts(340_672_829, 6768) - // Standard Error: 18_295 - .saturating_add(Weight::from_parts(46_106_884, 0).saturating_mul(r.into())) + // Measured: `907 + r * (76 ±0)` + // Estimated: `6801 + r * (77 ±0)` + // Minimum execution time: 272_697_000 picoseconds. + Weight::from_parts(345_385_667, 6801) + // Standard Error: 14_226 + .saturating_add(Weight::from_parts(46_037_637, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) @@ -1837,12 +1835,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (42 ±0)` - // Estimated: `6783 + r * (42 ±0)` - // Minimum execution time: 275_105_000 picoseconds. - Weight::from_parts(313_700_348, 6783) - // Standard Error: 11_960 - .saturating_add(Weight::from_parts(12_050_300, 0).saturating_mul(r.into())) + // Measured: `877 + r * (42 ±0)` + // Estimated: `6816 + r * (42 ±0)` + // Minimum execution time: 271_800_000 picoseconds. + Weight::from_parts(314_891_136, 6816) + // Standard Error: 9_762 + .saturating_add(Weight::from_parts(11_949_979, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) @@ -1865,11 +1863,11 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` - // Estimated: `6774 + r * (3090 ±7)` - // Minimum execution time: 259_178_000 picoseconds. - Weight::from_parts(275_643_000, 6774) - // Standard Error: 54_044 - .saturating_add(Weight::from_parts(26_026_930, 0).saturating_mul(r.into())) + // Estimated: `6807 + r * (3090 ±10)` + // Minimum execution time: 274_238_000 picoseconds. + Weight::from_parts(278_034_000, 6807) + // Standard Error: 77_011 + .saturating_add(Weight::from_parts(27_627_005, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1893,12 +1891,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 32]`. fn add_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `895 + r * (131 ±0)` - // Estimated: `6845 + r * (2606 ±0)` - // Minimum execution time: 263_386_000 picoseconds. - Weight::from_parts(295_443_439, 6845) - // Standard Error: 24_422 - .saturating_add(Weight::from_parts(6_429_537, 0).saturating_mul(r.into())) + // Measured: `928 + r * (131 ±0)` + // Estimated: `6878 + r * (2606 ±0)` + // Minimum execution time: 271_519_000 picoseconds. + Weight::from_parts(292_726_476, 6878) + // Standard Error: 23_870 + .saturating_add(Weight::from_parts(6_695_172, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1922,12 +1920,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 32]`. fn remove_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `936 + r * (183 ±0)` + // Measured: `969 + r * (183 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 261_371_000 picoseconds. - Weight::from_parts(297_493_194, 129453) - // Standard Error: 23_734 - .saturating_add(Weight::from_parts(5_673_169, 0).saturating_mul(r.into())) + // Minimum execution time: 274_675_000 picoseconds. + Weight::from_parts(293_727_489, 129453) + // Standard Error: 23_160 + .saturating_add(Weight::from_parts(5_895_043, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1951,12 +1949,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (3 ±0)` - // Estimated: `6771 + r * (3 ±0)` - // Minimum execution time: 275_558_000 picoseconds. - Weight::from_parts(287_220_765, 6771) - // Standard Error: 437 - .saturating_add(Weight::from_parts(184_125, 0).saturating_mul(r.into())) + // Measured: `858 + r * (3 ±0)` + // Estimated: `6804 + r * (3 ±0)` + // Minimum execution time: 253_330_000 picoseconds. + Weight::from_parts(281_079_564, 6804) + // Standard Error: 378 + .saturating_add(Weight::from_parts(180_655, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -1978,12 +1976,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2076 + r * (39 ±0)` - // Estimated: `7866 + r * (40 ±0)` - // Minimum execution time: 265_752_000 picoseconds. - Weight::from_parts(331_187_665, 7866) - // Standard Error: 1_950 - .saturating_add(Weight::from_parts(312_262, 0).saturating_mul(r.into())) + // Measured: `2109 + r * (39 ±0)` + // Estimated: `7899 + r * (40 ±0)` + // Minimum execution time: 276_552_000 picoseconds. + Weight::from_parts(368_521_088, 7899) + // Standard Error: 2_310 + .saturating_add(Weight::from_parts(318_129, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -2007,12 +2005,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `828 + r * (3 ±0)` - // Estimated: `6768 + r * (3 ±0)` - // Minimum execution time: 257_114_000 picoseconds. - Weight::from_parts(286_686_654, 6768) - // Standard Error: 426 - .saturating_add(Weight::from_parts(162_295, 0).saturating_mul(r.into())) + // Measured: `861 + r * (3 ±0)` + // Estimated: `6801 + r * (3 ±0)` + // Minimum execution time: 258_953_000 picoseconds. + Weight::from_parts(288_222_836, 6801) + // Standard Error: 367 + .saturating_add(Weight::from_parts(152_842, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -2022,10 +2020,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_388_000 picoseconds. - Weight::from_parts(1_680_408, 0) - // Standard Error: 21 - .saturating_add(Weight::from_parts(10_564, 0).saturating_mul(r.into())) + // Minimum execution time: 1_476_000 picoseconds. + Weight::from_parts(2_119_717, 0) + // Standard Error: 28 + .saturating_add(Weight::from_parts(9_805, 0).saturating_mul(r.into())) } } @@ -2037,8 +2035,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_410_000 picoseconds. - Weight::from_parts(2_581_000, 1627) + // Minimum execution time: 2_548_000 picoseconds. + Weight::from_parts(2_670_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -2048,10 +2046,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `451 + k * (69 ±0)` // Estimated: `441 + k * (70 ±0)` - // Minimum execution time: 13_278_000 picoseconds. - Weight::from_parts(13_944_000, 441) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(1_194_404, 0).saturating_mul(k.into())) + // Minimum execution time: 13_526_000 picoseconds. + Weight::from_parts(13_902_000, 441) + // Standard Error: 1_058 + .saturating_add(Weight::from_parts(1_274_724, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -2065,10 +2063,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_533_000 picoseconds. - Weight::from_parts(9_141_899, 6149) + // Minimum execution time: 8_426_000 picoseconds. + Weight::from_parts(8_591_621, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_327, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -2081,8 +2079,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_998_000 picoseconds. - Weight::from_parts(17_776_000, 6450) + // Minimum execution time: 17_008_000 picoseconds. + Weight::from_parts(17_742_000, 6450) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2095,10 +2093,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_919_000 picoseconds. - Weight::from_parts(4_057_153, 3635) - // Standard Error: 1_252 - .saturating_add(Weight::from_parts(1_151_419, 0).saturating_mul(k.into())) + // Minimum execution time: 3_949_000 picoseconds. + Weight::from_parts(4_062_000, 3635) + // Standard Error: 1_983 + .saturating_add(Weight::from_parts(1_173_197, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -2117,10 +2115,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `325 + c * (1 ±0)` // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 17_730_000 picoseconds. - Weight::from_parts(17_540_884, 6263) + // Minimum execution time: 17_094_000 picoseconds. + Weight::from_parts(17_338_591, 6263) // Standard Error: 1 - .saturating_add(Weight::from_parts(417, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(436, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -2131,8 +2129,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 13_089_000 picoseconds. - Weight::from_parts(13_727_000, 6380) + // Minimum execution time: 12_704_000 picoseconds. + Weight::from_parts(13_147_000, 6380) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2146,8 +2144,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `360` // Estimated: `6300` - // Minimum execution time: 49_083_000 picoseconds. - Weight::from_parts(50_462_000, 6300) + // Minimum execution time: 48_387_000 picoseconds. + Weight::from_parts(50_024_000, 6300) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2159,8 +2157,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 49_299_000 picoseconds. - Weight::from_parts(50_805_000, 6534) + // Minimum execution time: 59_300_000 picoseconds. + Weight::from_parts(61_805_000, 6534) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2170,8 +2168,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 3_305_000 picoseconds. - Weight::from_parts(3_489_000, 1627) + // Minimum execution time: 3_327_000 picoseconds. + Weight::from_parts(3_502_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2183,8 +2181,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 12_657_000 picoseconds. - Weight::from_parts(13_100_000, 3631) + // Minimum execution time: 12_759_000 picoseconds. + Weight::from_parts(13_134_000, 3631) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2194,8 +2192,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_784_000 picoseconds. - Weight::from_parts(4_994_000, 3607) + // Minimum execution time: 4_775_000 picoseconds. + Weight::from_parts(5_084_000, 3607) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2206,8 +2204,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_762_000 picoseconds. - Weight::from_parts(6_945_000, 3632) + // Minimum execution time: 6_663_000 picoseconds. + Weight::from_parts(6_855_000, 3632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2218,8 +2216,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_999_000 picoseconds. - Weight::from_parts(7_372_000, 3607) + // Minimum execution time: 7_212_000 picoseconds. + Weight::from_parts(7_426_000, 3607) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2240,12 +2238,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `759` - // Estimated: `6710 + c * (1 ±0)` - // Minimum execution time: 304_121_000 picoseconds. - Weight::from_parts(288_627_840, 6710) - // Standard Error: 83 - .saturating_add(Weight::from_parts(37_343, 0).saturating_mul(c.into())) + // Measured: `792` + // Estimated: `6743 + c * (1 ±0)` + // Minimum execution time: 289_557_000 picoseconds. + Weight::from_parts(272_895_652, 6743) + // Standard Error: 80 + .saturating_add(Weight::from_parts(39_917, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -2273,16 +2271,16 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `290` - // Estimated: `8714` - // Minimum execution time: 4_101_589_000 picoseconds. - Weight::from_parts(694_193_047, 8714) - // Standard Error: 334 - .saturating_add(Weight::from_parts(108_847, 0).saturating_mul(c.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_677, 0).saturating_mul(i.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_783, 0).saturating_mul(s.into())) + // Measured: `323` + // Estimated: `8747` + // Minimum execution time: 4_671_359_000 picoseconds. + Weight::from_parts(586_523_882, 8747) + // Standard Error: 206 + .saturating_add(Weight::from_parts(115_402, 0).saturating_mul(c.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(1_797, 0).saturating_mul(i.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(2_046, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2300,22 +2298,22 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `6471` - // Minimum execution time: 2_011_580_000 picoseconds. - Weight::from_parts(397_415_227, 6471) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_689, 0).saturating_mul(i.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_679, 0).saturating_mul(s.into())) + // Measured: `560` + // Estimated: `6504` + // Minimum execution time: 2_170_657_000 picoseconds. + Weight::from_parts(369_331_405, 6504) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_940, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_858, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2335,10 +2333,10 @@ impl WeightInfo for () { /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `793` - // Estimated: `6733` - // Minimum execution time: 204_975_000 picoseconds. - Weight::from_parts(214_770_000, 6733) + // Measured: `826` + // Estimated: `6766` + // Minimum execution time: 204_287_000 picoseconds. + Weight::from_parts(213_239_000, 6766) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2357,10 +2355,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 269_545_000 picoseconds. - Weight::from_parts(256_054_650, 3607) - // Standard Error: 91 - .saturating_add(Weight::from_parts(72_743, 0).saturating_mul(c.into())) + // Minimum execution time: 285_434_000 picoseconds. + Weight::from_parts(242_697_648, 3607) + // Standard Error: 128 + .saturating_add(Weight::from_parts(76_087, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2378,8 +2376,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 47_880_000 picoseconds. - Weight::from_parts(49_427_000, 3780) + // Minimum execution time: 46_486_000 picoseconds. + Weight::from_parts(48_422_000, 3780) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2395,8 +2393,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 37_898_000 picoseconds. - Weight::from_parts(39_826_000, 8967) + // Minimum execution time: 37_568_000 picoseconds. + Weight::from_parts(38_589_000, 8967) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2417,12 +2415,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `833 + r * (6 ±0)` - // Estimated: `6773 + r * (6 ±0)` - // Minimum execution time: 260_916_000 picoseconds. - Weight::from_parts(295_521_846, 6773) - // Standard Error: 1_126 - .saturating_add(Weight::from_parts(348_317, 0).saturating_mul(r.into())) + // Measured: `866 + r * (6 ±0)` + // Estimated: `6806 + r * (6 ±0)` + // Minimum execution time: 274_513_000 picoseconds. + Weight::from_parts(288_793_403, 6806) + // Standard Error: 650 + .saturating_add(Weight::from_parts(339_309, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2444,12 +2442,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (209 ±0)` - // Estimated: `6793 + r * (2684 ±0)` - // Minimum execution time: 274_335_000 picoseconds. - Weight::from_parts(132_998_512, 6793) - // Standard Error: 7_396 - .saturating_add(Weight::from_parts(3_602_287, 0).saturating_mul(r.into())) + // Measured: `922 + r * (209 ±0)` + // Estimated: `6826 + r * (2684 ±0)` + // Minimum execution time: 260_096_000 picoseconds. + Weight::from_parts(149_954_322, 6826) + // Standard Error: 5_713 + .saturating_add(Weight::from_parts(3_788_924, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2472,12 +2470,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (213 ±0)` - // Estimated: `6797 + r * (2688 ±0)` - // Minimum execution time: 272_514_000 picoseconds. - Weight::from_parts(104_825_618, 6797) - // Standard Error: 10_038 - .saturating_add(Weight::from_parts(4_520_258, 0).saturating_mul(r.into())) + // Measured: `921 + r * (213 ±0)` + // Estimated: `6830 + r * (2688 ±0)` + // Minimum execution time: 277_496_000 picoseconds. + Weight::from_parts(285_839_000, 6830) + // Standard Error: 10_076 + .saturating_add(Weight::from_parts(4_720_110, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2500,12 +2498,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `840 + r * (6 ±0)` - // Estimated: `6782 + r * (6 ±0)` - // Minimum execution time: 264_593_000 picoseconds. - Weight::from_parts(294_139_363, 6782) - // Standard Error: 907 - .saturating_add(Weight::from_parts(432_964, 0).saturating_mul(r.into())) + // Measured: `873 + r * (6 ±0)` + // Estimated: `6815 + r * (6 ±0)` + // Minimum execution time: 275_655_000 picoseconds. + Weight::from_parts(291_386_528, 6815) + // Standard Error: 898 + .saturating_add(Weight::from_parts(428_765, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2527,12 +2525,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (3 ±0)` - // Estimated: `6771 + r * (3 ±0)` - // Minimum execution time: 260_412_000 picoseconds. - Weight::from_parts(284_371_703, 6771) - // Standard Error: 433 - .saturating_add(Weight::from_parts(182_952, 0).saturating_mul(r.into())) + // Measured: `863 + r * (3 ±0)` + // Estimated: `6804 + r * (3 ±0)` + // Minimum execution time: 260_323_000 picoseconds. + Weight::from_parts(286_371_403, 6804) + // Standard Error: 451 + .saturating_add(Weight::from_parts(183_053, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -2552,12 +2550,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `720 + r * (3 ±0)` - // Estimated: `6660 + r * (3 ±0)` - // Minimum execution time: 255_112_000 picoseconds. - Weight::from_parts(273_052_488, 6660) - // Standard Error: 376 - .saturating_add(Weight::from_parts(166_644, 0).saturating_mul(r.into())) + // Measured: `753 + r * (3 ±0)` + // Estimated: `6693 + r * (3 ±0)` + // Minimum execution time: 262_974_000 picoseconds. + Weight::from_parts(276_571_502, 6693) + // Standard Error: 527 + .saturating_add(Weight::from_parts(165_364, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -2579,12 +2577,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `834 + r * (6 ±0)` - // Estimated: `6774 + r * (6 ±0)` - // Minimum execution time: 270_426_000 picoseconds. - Weight::from_parts(289_240_775, 6774) - // Standard Error: 748 - .saturating_add(Weight::from_parts(344_791, 0).saturating_mul(r.into())) + // Measured: `867 + r * (6 ±0)` + // Estimated: `6807 + r * (6 ±0)` + // Minimum execution time: 272_826_000 picoseconds. + Weight::from_parts(290_963_001, 6807) + // Standard Error: 810 + .saturating_add(Weight::from_parts(343_762, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2606,12 +2604,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (6 ±0)` - // Estimated: `6773 + r * (6 ±0)` - // Minimum execution time: 260_217_000 picoseconds. - Weight::from_parts(288_660_978, 6773) - // Standard Error: 1_199 - .saturating_add(Weight::from_parts(550_304, 0).saturating_mul(r.into())) + // Measured: `863 + r * (6 ±0)` + // Estimated: `6806 + r * (6 ±0)` + // Minimum execution time: 277_324_000 picoseconds. + Weight::from_parts(290_872_814, 6806) + // Standard Error: 766 + .saturating_add(Weight::from_parts(371_542, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2633,12 +2631,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `974 + r * (6 ±0)` - // Estimated: `6898 + r * (6 ±0)` - // Minimum execution time: 273_473_000 picoseconds. - Weight::from_parts(298_889_279, 6898) - // Standard Error: 4_604 - .saturating_add(Weight::from_parts(1_630_175, 0).saturating_mul(r.into())) + // Measured: `1007 + r * (6 ±0)` + // Estimated: `6931 + r * (6 ±0)` + // Minimum execution time: 274_460_000 picoseconds. + Weight::from_parts(285_748_025, 6931) + // Standard Error: 1_570 + .saturating_add(Weight::from_parts(1_656_237, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2660,12 +2658,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (6 ±0)` - // Estimated: `6790 + r * (6 ±0)` - // Minimum execution time: 262_033_000 picoseconds. - Weight::from_parts(284_293_851, 6790) - // Standard Error: 591 - .saturating_add(Weight::from_parts(369_240, 0).saturating_mul(r.into())) + // Measured: `877 + r * (6 ±0)` + // Estimated: `6823 + r * (6 ±0)` + // Minimum execution time: 278_254_000 picoseconds. + Weight::from_parts(283_893_525, 6823) + // Standard Error: 726 + .saturating_add(Weight::from_parts(347_368, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2687,12 +2685,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (6 ±0)` - // Estimated: `6783 + r * (6 ±0)` - // Minimum execution time: 274_568_000 picoseconds. - Weight::from_parts(294_688_466, 6783) - // Standard Error: 768 - .saturating_add(Weight::from_parts(349_584, 0).saturating_mul(r.into())) + // Measured: `875 + r * (6 ±0)` + // Estimated: `6816 + r * (6 ±0)` + // Minimum execution time: 279_646_000 picoseconds. + Weight::from_parts(292_505_446, 6816) + // Standard Error: 867 + .saturating_add(Weight::from_parts(337_202, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2714,12 +2712,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839 + r * (6 ±0)` - // Estimated: `6786 + r * (6 ±0)` - // Minimum execution time: 264_061_000 picoseconds. - Weight::from_parts(287_964_188, 6786) - // Standard Error: 490 - .saturating_add(Weight::from_parts(356_273, 0).saturating_mul(r.into())) + // Measured: `872 + r * (6 ±0)` + // Estimated: `6819 + r * (6 ±0)` + // Minimum execution time: 274_522_000 picoseconds. + Weight::from_parts(295_135_659, 6819) + // Standard Error: 1_052 + .saturating_add(Weight::from_parts(330_788, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2741,12 +2739,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (6 ±0)` - // Estimated: `6771 + r * (6 ±0)` - // Minimum execution time: 275_707_000 picoseconds. - Weight::from_parts(290_797_828, 6771) - // Standard Error: 967 - .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) + // Measured: `863 + r * (6 ±0)` + // Estimated: `6804 + r * (6 ±0)` + // Minimum execution time: 274_228_000 picoseconds. + Weight::from_parts(289_201_593, 6804) + // Standard Error: 752 + .saturating_add(Weight::from_parts(337_860, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2770,12 +2768,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `904 + r * (14 ±0)` - // Estimated: `6839 + r * (14 ±0)` - // Minimum execution time: 272_492_000 picoseconds. - Weight::from_parts(295_010_878, 6839) - // Standard Error: 2_549 - .saturating_add(Weight::from_parts(1_426_715, 0).saturating_mul(r.into())) + // Measured: `937 + r * (14 ±0)` + // Estimated: `6872 + r * (14 ±0)` + // Minimum execution time: 277_142_000 picoseconds. + Weight::from_parts(296_736_114, 6872) + // Standard Error: 1_502 + .saturating_add(Weight::from_parts(1_446_663, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) @@ -2797,12 +2795,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `832 + r * (6 ±0)` - // Estimated: `6774 + r * (6 ±0)` - // Minimum execution time: 257_981_000 picoseconds. - Weight::from_parts(285_824_773, 6774) - // Standard Error: 704 - .saturating_add(Weight::from_parts(301_327, 0).saturating_mul(r.into())) + // Measured: `865 + r * (6 ±0)` + // Estimated: `6807 + r * (6 ±0)` + // Minimum execution time: 276_087_000 picoseconds. + Weight::from_parts(287_863_377, 6807) + // Standard Error: 495 + .saturating_add(Weight::from_parts(282_718, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2824,12 +2822,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `836` - // Estimated: `6776` - // Minimum execution time: 259_470_000 picoseconds. - Weight::from_parts(232_759_442, 6776) - // Standard Error: 24 - .saturating_add(Weight::from_parts(981, 0).saturating_mul(n.into())) + // Measured: `869` + // Estimated: `6809` + // Minimum execution time: 277_128_000 picoseconds. + Weight::from_parts(234_478_674, 6809) + // Standard Error: 23 + .saturating_add(Weight::from_parts(1_052, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2850,12 +2848,10 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `820 + r * (45 ±0)` - // Estimated: `6760 + r * (45 ±0)` - // Minimum execution time: 252_740_000 picoseconds. - Weight::from_parts(278_155_436, 6760) - // Standard Error: 882_420 - .saturating_add(Weight::from_parts(755_063, 0).saturating_mul(r.into())) + // Measured: `853 + r * (45 ±0)` + // Estimated: `6793 + r * (45 ±0)` + // Minimum execution time: 251_983_000 picoseconds. + Weight::from_parts(277_986_885, 6793) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) @@ -2877,12 +2873,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830` - // Estimated: `6777` - // Minimum execution time: 257_318_000 picoseconds. - Weight::from_parts(285_765_697, 6777) - // Standard Error: 1 - .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) + // Measured: `863` + // Estimated: `6810` + // Minimum execution time: 275_108_000 picoseconds. + Weight::from_parts(284_552_708, 6810) + // Standard Error: 0 + .saturating_add(Weight::from_parts(391, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2909,12 +2905,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2939 + r * (316 ±0)` - // Estimated: `8879 + r * (5266 ±0)` - // Minimum execution time: 280_392_000 picoseconds. - Weight::from_parts(310_023_381, 8879) - // Standard Error: 1_008_026 - .saturating_add(Weight::from_parts(130_208_818, 0).saturating_mul(r.into())) + // Measured: `2972 + r * (316 ±0)` + // Estimated: `8912 + r * (5266 ±0)` + // Minimum execution time: 281_278_000 picoseconds. + Weight::from_parts(306_800_667, 8912) + // Standard Error: 855_257 + .saturating_add(Weight::from_parts(126_508_132, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2940,12 +2936,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (10 ±0)` - // Estimated: `6852 + r * (10 ±0)` - // Minimum execution time: 270_547_000 picoseconds. - Weight::from_parts(295_931_189, 6852) - // Standard Error: 3_280 - .saturating_add(Weight::from_parts(1_941_248, 0).saturating_mul(r.into())) + // Measured: `944 + r * (10 ±0)` + // Estimated: `6885 + r * (10 ±0)` + // Minimum execution time: 260_609_000 picoseconds. + Weight::from_parts(287_385_076, 6885) + // Standard Error: 2_754 + .saturating_add(Weight::from_parts(2_057_388, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -2967,12 +2963,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (10 ±0)` - // Estimated: `6772 + r * (10 ±0)` - // Minimum execution time: 255_730_000 picoseconds. - Weight::from_parts(301_859_471, 6772) - // Standard Error: 5_401 - .saturating_add(Weight::from_parts(3_887_632, 0).saturating_mul(r.into())) + // Measured: `863 + r * (10 ±0)` + // Estimated: `6805 + r * (10 ±0)` + // Minimum execution time: 254_770_000 picoseconds. + Weight::from_parts(255_105_647, 6805) + // Standard Error: 5_707 + .saturating_add(Weight::from_parts(3_808_788, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -2995,14 +2991,14 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `847 + t * (32 ±0)` - // Estimated: `6792 + t * (2508 ±0)` - // Minimum execution time: 276_643_000 picoseconds. - Weight::from_parts(294_275_838, 6792) - // Standard Error: 106_745 - .saturating_add(Weight::from_parts(2_831_489, 0).saturating_mul(t.into())) - // Standard Error: 29 - .saturating_add(Weight::from_parts(624, 0).saturating_mul(n.into())) + // Measured: `880 + t * (32 ±0)` + // Estimated: `6825 + t * (2508 ±0)` + // Minimum execution time: 278_200_000 picoseconds. + Weight::from_parts(288_081_493, 6825) + // Standard Error: 97_535 + .saturating_add(Weight::from_parts(3_683_455, 0).saturating_mul(t.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3026,12 +3022,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `829 + r * (7 ±0)` - // Estimated: `6774 + r * (7 ±0)` - // Minimum execution time: 169_012_000 picoseconds. - Weight::from_parts(179_567_029, 6774) - // Standard Error: 534 - .saturating_add(Weight::from_parts(249_500, 0).saturating_mul(r.into())) + // Measured: `862 + r * (7 ±0)` + // Estimated: `6807 + r * (7 ±0)` + // Minimum execution time: 167_181_000 picoseconds. + Weight::from_parts(178_433_475, 6807) + // Standard Error: 374 + .saturating_add(Weight::from_parts(241_240, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) @@ -3053,12 +3049,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125780` - // Estimated: `131722` - // Minimum execution time: 408_647_000 picoseconds. - Weight::from_parts(387_678_006, 131722) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_045, 0).saturating_mul(i.into())) + // Measured: `125813` + // Estimated: `131755` + // Minimum execution time: 434_456_000 picoseconds. + Weight::from_parts(400_940_450, 131755) + // Standard Error: 13 + .saturating_add(Weight::from_parts(1_102, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3067,12 +3063,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `891 + r * (292 ±0)` - // Estimated: `892 + r * (293 ±0)` - // Minimum execution time: 279_315_000 picoseconds. - Weight::from_parts(171_270_899, 892) - // Standard Error: 15_492 - .saturating_add(Weight::from_parts(6_776_878, 0).saturating_mul(r.into())) + // Measured: `924 + r * (292 ±0)` + // Estimated: `925 + r * (293 ±0)` + // Minimum execution time: 277_825_000 picoseconds. + Weight::from_parts(159_688_263, 925) + // Standard Error: 13_610 + .saturating_add(Weight::from_parts(7_145_641, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3084,12 +3080,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1413` - // Estimated: `1396` - // Minimum execution time: 289_666_000 picoseconds. - Weight::from_parts(348_062_625, 1396) - // Standard Error: 79 - .saturating_add(Weight::from_parts(532, 0).saturating_mul(n.into())) + // Measured: `1446` + // Estimated: `1429` + // Minimum execution time: 284_745_000 picoseconds. + Weight::from_parts(345_928_316, 1429) + // Standard Error: 70 + .saturating_add(Weight::from_parts(547, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -3098,12 +3094,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1219 + n * (1 ±0)` - // Estimated: `1219 + n * (1 ±0)` - // Minimum execution time: 273_840_000 picoseconds. - Weight::from_parts(297_024_621, 1219) - // Standard Error: 55 - .saturating_add(Weight::from_parts(945, 0).saturating_mul(n.into())) + // Measured: `1252 + n * (1 ±0)` + // Estimated: `1252 + n * (1 ±0)` + // Minimum execution time: 275_328_000 picoseconds. + Weight::from_parts(300_037_010, 1252) + // Standard Error: 32 + .saturating_add(Weight::from_parts(558, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3113,12 +3109,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `887 + r * (288 ±0)` - // Estimated: `893 + r * (289 ±0)` - // Minimum execution time: 279_110_000 picoseconds. - Weight::from_parts(177_898_012, 893) - // Standard Error: 16_287 - .saturating_add(Weight::from_parts(6_640_103, 0).saturating_mul(r.into())) + // Measured: `920 + r * (288 ±0)` + // Estimated: `926 + r * (289 ±0)` + // Minimum execution time: 273_742_000 picoseconds. + Weight::from_parts(169_430_806, 926) + // Standard Error: 11_821 + .saturating_add(Weight::from_parts(6_927_074, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3130,10 +3126,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1215 + n * (1 ±0)` - // Estimated: `1215 + n * (1 ±0)` - // Minimum execution time: 276_566_000 picoseconds. - Weight::from_parts(304_992_376, 1215) + // Measured: `1248 + n * (1 ±0)` + // Estimated: `1248 + n * (1 ±0)` + // Minimum execution time: 275_167_000 picoseconds. + Weight::from_parts(301_883_655, 1248) + // Standard Error: 35 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3143,12 +3141,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `887 + r * (296 ±0)` - // Estimated: `889 + r * (297 ±0)` - // Minimum execution time: 266_285_000 picoseconds. - Weight::from_parts(200_488_939, 889) - // Standard Error: 11_193 - .saturating_add(Weight::from_parts(5_467_725, 0).saturating_mul(r.into())) + // Measured: `920 + r * (296 ±0)` + // Estimated: `922 + r * (297 ±0)` + // Minimum execution time: 274_628_000 picoseconds. + Weight::from_parts(195_255_092, 922) + // Standard Error: 9_109 + .saturating_add(Weight::from_parts(5_707_060, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3159,12 +3157,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1231 + n * (1 ±0)` - // Estimated: `1231 + n * (1 ±0)` - // Minimum execution time: 278_625_000 picoseconds. - Weight::from_parts(304_319_493, 1231) - // Standard Error: 39 - .saturating_add(Weight::from_parts(415, 0).saturating_mul(n.into())) + // Measured: `1264 + n * (1 ±0)` + // Estimated: `1264 + n * (1 ±0)` + // Minimum execution time: 274_202_000 picoseconds. + Weight::from_parts(296_440_752, 1264) + // Standard Error: 38 + .saturating_add(Weight::from_parts(1_010, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3174,12 +3172,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `898 + r * (288 ±0)` - // Estimated: `895 + r * (289 ±0)` - // Minimum execution time: 271_851_000 picoseconds. - Weight::from_parts(202_164_395, 895) - // Standard Error: 11_115 - .saturating_add(Weight::from_parts(5_273_320, 0).saturating_mul(r.into())) + // Measured: `931 + r * (288 ±0)` + // Estimated: `928 + r * (289 ±0)` + // Minimum execution time: 274_123_000 picoseconds. + Weight::from_parts(193_280_535, 928) + // Standard Error: 9_264 + .saturating_add(Weight::from_parts(5_548_039, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3190,12 +3188,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1218 + n * (1 ±0)` - // Estimated: `1218 + n * (1 ±0)` - // Minimum execution time: 274_200_000 picoseconds. - Weight::from_parts(299_524_586, 1218) - // Standard Error: 33 - .saturating_add(Weight::from_parts(272, 0).saturating_mul(n.into())) + // Measured: `1251 + n * (1 ±0)` + // Estimated: `1251 + n * (1 ±0)` + // Minimum execution time: 276_425_000 picoseconds. + Weight::from_parts(300_521_806, 1251) + // Standard Error: 36 + .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3205,12 +3203,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880 + r * (296 ±0)` - // Estimated: `885 + r * (297 ±0)` - // Minimum execution time: 258_535_000 picoseconds. - Weight::from_parts(190_468_808, 885) - // Standard Error: 11_940 - .saturating_add(Weight::from_parts(6_737_079, 0).saturating_mul(r.into())) + // Measured: `913 + r * (296 ±0)` + // Estimated: `918 + r * (297 ±0)` + // Minimum execution time: 264_860_000 picoseconds. + Weight::from_parts(191_561_777, 918) + // Standard Error: 10_678 + .saturating_add(Weight::from_parts(6_895_457, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3222,12 +3220,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1232 + n * (1 ±0)` - // Estimated: `1232 + n * (1 ±0)` - // Minimum execution time: 280_536_000 picoseconds. - Weight::from_parts(304_479_477, 1232) + // Measured: `1265 + n * (1 ±0)` + // Estimated: `1265 + n * (1 ±0)` + // Minimum execution time: 282_501_000 picoseconds. + Weight::from_parts(303_351_919, 1265) // Standard Error: 37 - .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(643, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3249,12 +3247,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1382 + r * (45 ±0)` - // Estimated: `7274 + r * (2520 ±0)` - // Minimum execution time: 260_373_000 picoseconds. - Weight::from_parts(278_290_000, 7274) - // Standard Error: 25_683 - .saturating_add(Weight::from_parts(39_264_864, 0).saturating_mul(r.into())) + // Measured: `1415 + r * (45 ±0)` + // Estimated: `7307 + r * (2520 ±0)` + // Minimum execution time: 273_198_000 picoseconds. + Weight::from_parts(179_673_238, 7307) + // Standard Error: 34_990 + .saturating_add(Weight::from_parts(38_468_091, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3278,12 +3276,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1227 + r * (245 ±0)` - // Estimated: `9407 + r * (2721 ±0)` - // Minimum execution time: 277_621_000 picoseconds. - Weight::from_parts(281_775_000, 9407) - // Standard Error: 110_802 - .saturating_add(Weight::from_parts(245_363_533, 0).saturating_mul(r.into())) + // Measured: `1260 + r * (245 ±0)` + // Estimated: `9440 + r * (2721 ±0)` + // Minimum execution time: 283_869_000 picoseconds. + Weight::from_parts(288_374_000, 9440) + // Standard Error: 137_512 + .saturating_add(Weight::from_parts(248_206_665, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3308,11 +3306,11 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` - // Estimated: `6779 + r * (2637 ±3)` - // Minimum execution time: 267_314_000 picoseconds. - Weight::from_parts(279_888_000, 6779) - // Standard Error: 144_378 - .saturating_add(Weight::from_parts(244_606_414, 0).saturating_mul(r.into())) + // Estimated: `6812 + r * (2637 ±3)` + // Minimum execution time: 257_577_000 picoseconds. + Weight::from_parts(277_310_000, 6812) + // Standard Error: 150_204 + .saturating_add(Weight::from_parts(249_943_483, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3337,14 +3335,14 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1274 + t * (277 ±0)` - // Estimated: `12164 + t * (5227 ±0)` - // Minimum execution time: 477_589_000 picoseconds. - Weight::from_parts(70_712_793, 12164) - // Standard Error: 11_713_135 - .saturating_add(Weight::from_parts(375_371_698, 0).saturating_mul(t.into())) + // Measured: `1307 + t * (277 ±0)` + // Estimated: `12197 + t * (5227 ±0)` + // Minimum execution time: 471_081_000 picoseconds. + Weight::from_parts(79_081_122, 12197) + // Standard Error: 11_777_790 + .saturating_add(Weight::from_parts(357_425_411, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(991, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_111, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -3365,19 +3363,19 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) - /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:800 w:800) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1245 + r * (255 ±0)` - // Estimated: `9587 + r * (2731 ±0)` - // Minimum execution time: 662_502_000 picoseconds. - Weight::from_parts(671_726_000, 9587) - // Standard Error: 351_643 - .saturating_add(Weight::from_parts(390_457_971, 0).saturating_mul(r.into())) + // Measured: `1278 + r * (255 ±0)` + // Estimated: `9620 + r * (2731 ±0)` + // Minimum execution time: 672_742_000 picoseconds. + Weight::from_parts(680_025_000, 9620) + // Standard Error: 313_642 + .saturating_add(Weight::from_parts(388_311_259, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -3398,25 +3396,23 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1270 + t * (104 ±0)` - // Estimated: `12178 + t * (2549 ±1)` - // Minimum execution time: 2_675_525_000 picoseconds. - Weight::from_parts(851_421_242, 12178) - // Standard Error: 7_094_722 - .saturating_add(Weight::from_parts(112_457_697, 0).saturating_mul(t.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(1_867, 0).saturating_mul(i.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(1_931, 0).saturating_mul(s.into())) + // Measured: `1303 + t * (104 ±0)` + // Estimated: `12211 + t * (2549 ±1)` + // Minimum execution time: 2_733_870_000 picoseconds. + Weight::from_parts(1_001_793_458, 12211) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(i.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(2_060, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(11_u64)) @@ -3440,12 +3436,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `829 + r * (8 ±0)` - // Estimated: `6768 + r * (8 ±0)` - // Minimum execution time: 270_818_000 picoseconds. - Weight::from_parts(286_520_166, 6768) - // Standard Error: 575 - .saturating_add(Weight::from_parts(402_286, 0).saturating_mul(r.into())) + // Measured: `862 + r * (8 ±0)` + // Estimated: `6801 + r * (8 ±0)` + // Minimum execution time: 272_658_000 picoseconds. + Weight::from_parts(282_717_645, 6801) + // Standard Error: 517 + .saturating_add(Weight::from_parts(400_604, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3467,12 +3463,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `6775` - // Minimum execution time: 257_134_000 picoseconds. - Weight::from_parts(268_214_648, 6775) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_098, 0).saturating_mul(n.into())) + // Measured: `870` + // Estimated: `6808` + // Minimum execution time: 260_969_000 picoseconds. + Weight::from_parts(265_206_847, 6808) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3493,12 +3489,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6773 + r * (8 ±0)` - // Minimum execution time: 259_222_000 picoseconds. - Weight::from_parts(283_273_283, 6773) - // Standard Error: 967 - .saturating_add(Weight::from_parts(817_596, 0).saturating_mul(r.into())) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6806 + r * (8 ±0)` + // Minimum execution time: 262_351_000 picoseconds. + Weight::from_parts(286_974_296, 6806) + // Standard Error: 514 + .saturating_add(Weight::from_parts(802_363, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3520,12 +3516,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6781` - // Minimum execution time: 260_040_000 picoseconds. - Weight::from_parts(283_869_860, 6781) + // Measured: `872` + // Estimated: `6814` + // Minimum execution time: 276_907_000 picoseconds. + Weight::from_parts(277_928_418, 6814) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_349, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_410, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3546,12 +3542,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6775 + r * (8 ±0)` - // Minimum execution time: 260_698_000 picoseconds. - Weight::from_parts(282_900_345, 6775) - // Standard Error: 805 - .saturating_add(Weight::from_parts(469_457, 0).saturating_mul(r.into())) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6808 + r * (8 ±0)` + // Minimum execution time: 263_660_000 picoseconds. + Weight::from_parts(285_665_916, 6808) + // Standard Error: 527 + .saturating_add(Weight::from_parts(480_457, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3573,12 +3569,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6780` - // Minimum execution time: 256_967_000 picoseconds. - Weight::from_parts(273_024_512, 6780) + // Measured: `872` + // Estimated: `6813` + // Minimum execution time: 262_071_000 picoseconds. + Weight::from_parts(270_115_341, 6813) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_254, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3599,12 +3595,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + r * (8 ±0)` - // Estimated: `6772 + r * (8 ±0)` - // Minimum execution time: 272_039_000 picoseconds. - Weight::from_parts(289_853_116, 6772) + // Measured: `864 + r * (8 ±0)` + // Estimated: `6805 + r * (8 ±0)` + // Minimum execution time: 265_568_000 picoseconds. + Weight::from_parts(285_791_811, 6805) // Standard Error: 559 - .saturating_add(Weight::from_parts(459_383, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(505_330, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3626,12 +3622,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `6778` - // Minimum execution time: 253_913_000 picoseconds. - Weight::from_parts(274_682_010, 6778) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) + // Measured: `872` + // Estimated: `6811` + // Minimum execution time: 271_336_000 picoseconds. + Weight::from_parts(272_829_313, 6811) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3652,12 +3648,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `964 + n * (1 ±0)` - // Estimated: `6901 + n * (1 ±0)` - // Minimum execution time: 343_955_000 picoseconds. - Weight::from_parts(350_777_388, 6901) + // Measured: `997 + n * (1 ±0)` + // Estimated: `6934 + n * (1 ±0)` + // Minimum execution time: 351_146_000 picoseconds. + Weight::from_parts(355_368_323, 6934) // Standard Error: 14 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(6_155, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3679,12 +3675,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `774 + r * (112 ±0)` - // Estimated: `6715 + r * (112 ±0)` - // Minimum execution time: 268_698_000 picoseconds. - Weight::from_parts(336_398_814, 6715) - // Standard Error: 16_627 - .saturating_add(Weight::from_parts(56_155_384, 0).saturating_mul(r.into())) + // Measured: `807 + r * (112 ±0)` + // Estimated: `6748 + r * (112 ±0)` + // Minimum execution time: 277_250_000 picoseconds. + Weight::from_parts(346_490_114, 6748) + // Standard Error: 14_654 + .saturating_add(Weight::from_parts(56_127_492, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) @@ -3706,12 +3702,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (76 ±0)` - // Estimated: `6768 + r * (77 ±0)` - // Minimum execution time: 258_906_000 picoseconds. - Weight::from_parts(340_672_829, 6768) - // Standard Error: 18_295 - .saturating_add(Weight::from_parts(46_106_884, 0).saturating_mul(r.into())) + // Measured: `907 + r * (76 ±0)` + // Estimated: `6801 + r * (77 ±0)` + // Minimum execution time: 272_697_000 picoseconds. + Weight::from_parts(345_385_667, 6801) + // Standard Error: 14_226 + .saturating_add(Weight::from_parts(46_037_637, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) @@ -3733,12 +3729,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (42 ±0)` - // Estimated: `6783 + r * (42 ±0)` - // Minimum execution time: 275_105_000 picoseconds. - Weight::from_parts(313_700_348, 6783) - // Standard Error: 11_960 - .saturating_add(Weight::from_parts(12_050_300, 0).saturating_mul(r.into())) + // Measured: `877 + r * (42 ±0)` + // Estimated: `6816 + r * (42 ±0)` + // Minimum execution time: 271_800_000 picoseconds. + Weight::from_parts(314_891_136, 6816) + // Standard Error: 9_762 + .saturating_add(Weight::from_parts(11_949_979, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) @@ -3761,11 +3757,11 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` - // Estimated: `6774 + r * (3090 ±7)` - // Minimum execution time: 259_178_000 picoseconds. - Weight::from_parts(275_643_000, 6774) - // Standard Error: 54_044 - .saturating_add(Weight::from_parts(26_026_930, 0).saturating_mul(r.into())) + // Estimated: `6807 + r * (3090 ±10)` + // Minimum execution time: 274_238_000 picoseconds. + Weight::from_parts(278_034_000, 6807) + // Standard Error: 77_011 + .saturating_add(Weight::from_parts(27_627_005, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3789,12 +3785,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 32]`. fn add_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `895 + r * (131 ±0)` - // Estimated: `6845 + r * (2606 ±0)` - // Minimum execution time: 263_386_000 picoseconds. - Weight::from_parts(295_443_439, 6845) - // Standard Error: 24_422 - .saturating_add(Weight::from_parts(6_429_537, 0).saturating_mul(r.into())) + // Measured: `928 + r * (131 ±0)` + // Estimated: `6878 + r * (2606 ±0)` + // Minimum execution time: 271_519_000 picoseconds. + Weight::from_parts(292_726_476, 6878) + // Standard Error: 23_870 + .saturating_add(Weight::from_parts(6_695_172, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3818,12 +3814,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 32]`. fn remove_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `936 + r * (183 ±0)` + // Measured: `969 + r * (183 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 261_371_000 picoseconds. - Weight::from_parts(297_493_194, 129453) - // Standard Error: 23_734 - .saturating_add(Weight::from_parts(5_673_169, 0).saturating_mul(r.into())) + // Minimum execution time: 274_675_000 picoseconds. + Weight::from_parts(293_727_489, 129453) + // Standard Error: 23_160 + .saturating_add(Weight::from_parts(5_895_043, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3847,12 +3843,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (3 ±0)` - // Estimated: `6771 + r * (3 ±0)` - // Minimum execution time: 275_558_000 picoseconds. - Weight::from_parts(287_220_765, 6771) - // Standard Error: 437 - .saturating_add(Weight::from_parts(184_125, 0).saturating_mul(r.into())) + // Measured: `858 + r * (3 ±0)` + // Estimated: `6804 + r * (3 ±0)` + // Minimum execution time: 253_330_000 picoseconds. + Weight::from_parts(281_079_564, 6804) + // Standard Error: 378 + .saturating_add(Weight::from_parts(180_655, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -3874,12 +3870,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2076 + r * (39 ±0)` - // Estimated: `7866 + r * (40 ±0)` - // Minimum execution time: 265_752_000 picoseconds. - Weight::from_parts(331_187_665, 7866) - // Standard Error: 1_950 - .saturating_add(Weight::from_parts(312_262, 0).saturating_mul(r.into())) + // Measured: `2109 + r * (39 ±0)` + // Estimated: `7899 + r * (40 ±0)` + // Minimum execution time: 276_552_000 picoseconds. + Weight::from_parts(368_521_088, 7899) + // Standard Error: 2_310 + .saturating_add(Weight::from_parts(318_129, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3903,12 +3899,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `828 + r * (3 ±0)` - // Estimated: `6768 + r * (3 ±0)` - // Minimum execution time: 257_114_000 picoseconds. - Weight::from_parts(286_686_654, 6768) - // Standard Error: 426 - .saturating_add(Weight::from_parts(162_295, 0).saturating_mul(r.into())) + // Measured: `861 + r * (3 ±0)` + // Estimated: `6801 + r * (3 ±0)` + // Minimum execution time: 258_953_000 picoseconds. + Weight::from_parts(288_222_836, 6801) + // Standard Error: 367 + .saturating_add(Weight::from_parts(152_842, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -3918,9 +3914,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_388_000 picoseconds. - Weight::from_parts(1_680_408, 0) - // Standard Error: 21 - .saturating_add(Weight::from_parts(10_564, 0).saturating_mul(r.into())) + // Minimum execution time: 1_476_000 picoseconds. + Weight::from_parts(2_119_717, 0) + // Standard Error: 28 + .saturating_add(Weight::from_parts(9_805, 0).saturating_mul(r.into())) } } -- GitLab From 2c3e869c3866e74953e95eda5b8a08b04f6e3787 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sat, 2 Sep 2023 21:25:43 +0200 Subject: [PATCH 060/633] substrate: chain-spec paths corrected in zombienet tests (#1362) * substrate: chain-spec paths corrected in zombienet tests * fix chain-spec path in cumulus test * disable beefy on validator --------- Co-authored-by: Javier Viola --- cumulus/zombienet/tests/0007-full_node_warp_sync.toml | 6 +++--- .../zombienet/0001-basic-warp-sync/test-warp-sync.toml | 2 +- .../test-validators-warp-sync.toml | 2 +- .../test-block-building-warp-sync.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cumulus/zombienet/tests/0007-full_node_warp_sync.toml b/cumulus/zombienet/tests/0007-full_node_warp_sync.toml index 42d1de7148d..524ce6643ce 100644 --- a/cumulus/zombienet/tests/0007-full_node_warp_sync.toml +++ b/cumulus/zombienet/tests/0007-full_node_warp_sync.toml @@ -3,7 +3,7 @@ default_image = "{{RELAY_IMAGE}}" default_command = "polkadot" default_args = [ "-lparachain=debug" ] chain = "rococo-local" -chain_spec_path = "cumulus/zombienet/tests/0007-warp-sync-relaychain-spec.json" +chain_spec_path = "0007-warp-sync-relaychain-spec.json" [[relaychain.nodes]] name = "alice" @@ -23,12 +23,12 @@ chain_spec_path = "cumulus/zombienet/tests/0007-warp-sync-relaychain-spec.json" [[relaychain.nodes]] name = "dave" validator = true - args = ["--sync warp", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}} {{'bob'|zombie('multiAddress')}} {{'charlie'|zombie('multiAddress')}}"] + args = ["--no-beefy", "--sync warp", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}} {{'bob'|zombie('multiAddress')}} {{'charlie'|zombie('multiAddress')}}"] [[parachains]] id = 2000 cumulus_based = true -chain_spec_path = "cumulus/zombienet/tests/0007-warp-sync-parachain-spec.json" +chain_spec_path = "0007-warp-sync-parachain-spec.json" add_to_genesis = false # Run 'dave' as parachain collator. diff --git a/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml b/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml index d14d77cfe62..773f5020bc3 100644 --- a/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml +++ b/substrate/zombienet/0001-basic-warp-sync/test-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "substrate/zombienet/0001-basic-warp-sync/chain-spec.json" +chain_spec_path = "chain-spec.json" [[relaychain.nodes]] name = "alice" diff --git a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml index 8336672ad49..12951575f4a 100644 --- a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml +++ b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "substrate/zombienet/0002-validators-warp-sync/chain-spec.json" +chain_spec_path = "chain-spec.json" [[relaychain.nodes]] name = "alice" diff --git a/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml b/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml index 6642ba8fea3..7fe9b0f065d 100644 --- a/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml +++ b/substrate/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml @@ -6,7 +6,7 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" default_command = "substrate" chain = "gen-db" -chain_spec_path = "substrate/zombienet/0003-block-building-warp-sync/chain-spec.json" +chain_spec_path = "chain-spec.json" #we need at least 3 nodes for warp sync [[relaychain.nodes]] -- GitLab From bc6fca3c44b4c2a512b34aca900754ecb3d51e6d Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 3 Sep 2023 15:11:26 +0200 Subject: [PATCH 061/633] Ensure cumulus/bridges is ignored by formatter and run it (#1369) --- .rustfmt.toml | 4 ++-- substrate/client/network/src/service.rs | 14 ++++++++------ .../rpc-spec-v2/src/chain_head/chain_head.rs | 6 ++++-- .../src/chain_head/chain_head_storage.rs | 4 +--- substrate/frame/broker/src/dispatchable_impls.rs | 4 ++-- substrate/frame/broker/src/tick_impls.rs | 4 ++-- substrate/frame/safe-mode/src/lib.rs | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 10568e49680..0dc11bdb8a3 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -19,9 +19,9 @@ trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true ignore = [ - "bridges", + "cumulus/bridges", ] edition = "2021" # Format comments comment_width = 100 -wrap_comments = true \ No newline at end of file +wrap_comments = true diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index aca0072a31d..c1df48ad785 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -943,9 +943,10 @@ where peers: HashSet, ) -> Result<(), String> { let Some(set_id) = self.notification_protocol_ids.get(&protocol) else { - return Err( - format!("Cannot add peers to reserved set of unknown protocol: {}", protocol) - ) + return Err(format!( + "Cannot add peers to reserved set of unknown protocol: {}", + protocol + )) }; let peers = self.split_multiaddr_and_peer_id(peers)?; @@ -974,9 +975,10 @@ where peers: Vec, ) -> Result<(), String> { let Some(set_id) = self.notification_protocol_ids.get(&protocol) else { - return Err( - format!("Cannot remove peers from reserved set of unknown protocol: {}", protocol) - ) + return Err(format!( + "Cannot remove peers from reserved set of unknown protocol: {}", + protocol + )) }; for peer_id in peers.into_iter() { diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index bae7c84df0e..14364c331e6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -462,7 +462,8 @@ where follow_subscription: String, operation_id: String, ) -> RpcResult<()> { - let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) + else { return Ok(()) }; @@ -479,7 +480,8 @@ where follow_subscription: String, operation_id: String, ) -> RpcResult<()> { - let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) + else { return Ok(()) }; 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 5e1f38f9a99..48a673f47e3 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 @@ -166,9 +166,7 @@ where let mut ret = Vec::with_capacity(self.operation_max_storage_items); for _ in 0..self.operation_max_storage_items { - let Some(key) = keys_iter.next() else { - break - }; + let Some(key) = keys_iter.next() else { break }; let result = match ty { IterQueryType::Value => self.query_storage_value(hash, &key, child_key), diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index 7c1d5a786b7..8dc0c9de393 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -334,10 +334,10 @@ impl Pallet { contribution.length.saturating_dec(); let Some(mut pool_record) = InstaPoolHistory::::get(r) else { - continue; + continue }; let Some(total_payout) = pool_record.maybe_payout else { - break; + break }; let p = total_payout .saturating_mul(contributed_parts.into()) diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index d65b8968f3c..909af6caf73 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -96,7 +96,7 @@ impl Pallet { pub(crate) fn process_revenue() -> bool { let Some((until, amount)) = T::Coretime::check_notify_revenue_info() else { - return false; + return false }; let when: Timeslice = (until / T::TimeslicePeriod::get()).saturating_sub(One::one()).saturated_into(); @@ -290,7 +290,7 @@ impl Pallet { core: CoreIndex, ) { let Some(workplan) = Workplan::::take((timeslice, core)) else { - return; + return }; let workload = Workload::::get(core); let parts_used = workplan.iter().map(|i| i.mask).fold(CoreMask::void(), |a, i| a | i); diff --git a/substrate/frame/safe-mode/src/lib.rs b/substrate/frame/safe-mode/src/lib.rs index ff045b964af..b8e8378fa9e 100644 --- a/substrate/frame/safe-mode/src/lib.rs +++ b/substrate/frame/safe-mode/src/lib.rs @@ -398,7 +398,7 @@ pub mod pallet { /// [`EnteredUntil`]. fn on_initialize(current: BlockNumberFor) -> Weight { let Some(limit) = EnteredUntil::::get() else { - return T::WeightInfo::on_initialize_noop(); + return T::WeightInfo::on_initialize_noop() }; if current > limit { -- GitLab From 4053bdac03d5a31732f07861c37eed30021a7783 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 4 Sep 2023 03:52:20 +0800 Subject: [PATCH 062/633] feat: add futures api to `TransactionPool` (#1348) * feat: add futures api to `TransactionPool` * fix clippy --- substrate/bin/node/bench/src/construct.rs | 4 ++++ substrate/client/transaction-pool/api/src/lib.rs | 3 +++ substrate/client/transaction-pool/src/graph/base_pool.rs | 3 +-- .../client/transaction-pool/src/graph/validated_pool.rs | 2 +- substrate/client/transaction-pool/src/lib.rs | 6 ++++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index 4f3ca07f86b..f14f89fcd3a 100644 --- a/substrate/bin/node/bench/src/construct.rs +++ b/substrate/bin/node/bench/src/construct.rs @@ -282,6 +282,10 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { Default::default() } + fn futures(&self) -> Vec { + unimplemented!() + } + fn status(&self) -> PoolStatus { unimplemented!() } diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index 32fe30f4584..a132cbc46e9 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -247,6 +247,9 @@ pub trait TransactionPool: Send + Sync { fn remove_invalid(&self, hashes: &[TxHash]) -> Vec>; // *** logging + /// Get futures transaction list. + fn futures(&self) -> Vec; + /// Returns pool status. fn status(&self) -> PoolStatus; diff --git a/substrate/client/transaction-pool/src/graph/base_pool.rs b/substrate/client/transaction-pool/src/graph/base_pool.rs index a9d2d6c825f..32885622da4 100644 --- a/substrate/client/transaction-pool/src/graph/base_pool.rs +++ b/substrate/client/transaction-pool/src/graph/base_pool.rs @@ -84,8 +84,7 @@ pub struct PruneStatus { } /// Immutable transaction -#[cfg_attr(test, derive(Clone))] -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone)] pub struct Transaction { /// Raw extrinsic representing that transaction. pub data: Extrinsic, diff --git a/substrate/client/transaction-pool/src/graph/validated_pool.rs b/substrate/client/transaction-pool/src/graph/validated_pool.rs index ed76d439ae7..3d7cfeb46b0 100644 --- a/substrate/client/transaction-pool/src/graph/validated_pool.rs +++ b/substrate/client/transaction-pool/src/graph/validated_pool.rs @@ -106,7 +106,7 @@ pub struct ValidatedPool { is_validator: IsValidator, options: Options, listener: RwLock, B>>, - pool: RwLock, ExtrinsicFor>>, + pub(crate) pool: RwLock, ExtrinsicFor>>, import_notification_sinks: Mutex>>>, rotator: PoolRotator>, } diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index 80e5925194c..ffaab89d982 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -358,6 +358,12 @@ where fn ready(&self) -> ReadyIteratorFor { Box::new(self.pool.validated_pool().ready()) } + + fn futures(&self) -> Vec { + let pool = self.pool.validated_pool().pool.read(); + + pool.futures().cloned().collect::>() + } } impl FullPool -- GitLab From 6322a76e36ec1ab1fdbe85f304b5154827088fae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 08:48:15 +0300 Subject: [PATCH 063/633] Bump proc-macro-warning from 0.4.1 to 0.4.2 (#1376) Bumps [proc-macro-warning](https://github.com/ggwpez/proc-macro-warning) from 0.4.1 to 0.4.2. - [Release notes](https://github.com/ggwpez/proc-macro-warning/releases) - [Commits](https://github.com/ggwpez/proc-macro-warning/compare/v0.4.1...v0.4.2) --- updated-dependencies: - dependency-name: proc-macro-warning dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- substrate/frame/support/procedural/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3bbc2faf29..62652542fe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13423,9 +13423,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro-warning" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70550716265d1ec349c41f70dd4f964b4fd88394efe4405f0c1da679c4799a07" +checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", @@ -19379,7 +19379,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index a25216ea9aa..ad28eed959e 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.16", features = ["full"] } frame-support-procedural-tools = { path = "tools" } -proc-macro-warning = { version = "0.4.1", default-features = false } +proc-macro-warning = { version = "0.4.2", default-features = false } macro_magic = { version = "0.4.2", features = ["proc_support"] } expander = "2.0.0" -- GitLab From a7ed6d2086a1cd57421400de4f8e2f2f72eeeb7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 08:48:36 +0300 Subject: [PATCH 064/633] Bump the known_good_semver group with 1 update (#1375) Bumps the known_good_semver group with 1 update: [syn](https://github.com/dtolnay/syn). - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.29...2.0.31) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 100 +++++++++--------- .../parachain-system/proc-macro/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- 17 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62652542fe0..8af7f4f8721 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,7 +1138,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1160,7 +1160,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1177,7 +1177,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1352,7 +1352,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -2516,7 +2516,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3575,7 +3575,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4067,7 +4067,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4107,7 +4107,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4124,7 +4124,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4422,7 +4422,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4484,7 +4484,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.29", + "syn 2.0.31", "termcolor", "toml 0.7.6", "walkdir", @@ -4728,7 +4728,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4739,7 +4739,7 @@ checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4902,7 +4902,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -5258,7 +5258,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.29", + "syn 2.0.31", "trybuild", ] @@ -5410,7 +5410,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -5421,7 +5421,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -5430,7 +5430,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -5653,7 +5653,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -7660,7 +7660,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -7674,7 +7674,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -7685,7 +7685,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -7696,7 +7696,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -9403,7 +9403,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -10474,7 +10474,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -11333,7 +11333,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -11374,7 +11374,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -13347,7 +13347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -13429,7 +13429,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -13475,7 +13475,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -13866,7 +13866,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -14628,7 +14628,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -15841,7 +15841,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -16195,7 +16195,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -16261,7 +16261,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -16701,7 +16701,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -17102,7 +17102,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -17146,7 +17146,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -17377,7 +17377,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -17617,7 +17617,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -18441,9 +18441,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -18690,7 +18690,7 @@ checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -18881,7 +18881,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -19062,7 +19062,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -19105,7 +19105,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -19678,7 +19678,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -19712,7 +19712,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20848,7 +20848,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -20967,7 +20967,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 58a4a97e049..e5e7da81d2a 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.29" +syn = "2.0.31" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index fc057c76975..ec6b817476a 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.15", features = ["full", "extra-traits"] } +syn = { version = "2.0.31", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index a5c50a48007..6545fb68764 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.15" +syn = "2.0.31" Inflector = "0.11.4" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 8b8210fe04f..b5ecc6107b9 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.16" +syn = "2.0.31" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 23dc9557a4b..8c444ffb606 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.16", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.31", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index afc6ce281bb..ecc5bc627b7 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.16", features = ["full"] } +syn = { version = "2.0.31", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index bc0127e91ba..7693da0372d 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.16", features = ["full", "visit"] } +syn = { version = "2.0.31", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index dc845848161..e1b97d278da 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.16", features = ["full", "visit"] } +syn = { version = "2.0.31", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index ad28eed959e..9ca86b9fccb 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.4" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.16", features = ["full"] } +syn = { version = "2.0.31", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 3a56f29eb19..46c26425651 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.16", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.31", 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 68e85a2060d..da01e6f4f6a 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.16", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.31", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index c415813b978..6819d139f45 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.16", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.31", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index d3a74d4bb81..ef17473a6f3 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.16", features = ["full", "parsing"] } +syn = { version = "2.0.31", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index bd35939a8b9..292c07e092f 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.16" +syn = "2.0.31" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 3488e4f50bf..e01343d6dc0 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.16", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.31", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index e7cec134ed5..25b5e7906f6 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.16", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.31", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } -- GitLab From 830fde2a60d60e214d95b3c9da6b6a11bbccf707 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 4 Sep 2023 09:19:41 +0200 Subject: [PATCH 065/633] Update `fmt` file and some authors (#1379) * Include bridges into fmt Signed-off-by: Oliver Tale-Yazdi * Fix some authors Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- .rustfmt.toml | 5 +---- polkadot/roadmap/implementers-guide/book.toml | 2 +- substrate/frame/asset-rate/Cargo.toml | 2 +- substrate/primitives/consensus/sassafras/Cargo.toml | 2 +- substrate/utils/frame/rpc/support/Cargo.toml | 5 +---- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 0dc11bdb8a3..c3421539123 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,4 +1,5 @@ # Basic +edition = "2021" hard_tabs = true max_width = 100 use_small_heuristics = "Max" @@ -18,10 +19,6 @@ match_block_trailing_comma = true trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true -ignore = [ - "cumulus/bridges", -] -edition = "2021" # Format comments comment_width = 100 wrap_comments = true diff --git a/polkadot/roadmap/implementers-guide/book.toml b/polkadot/roadmap/implementers-guide/book.toml index 0ced0e26f9a..1e6680f6f4b 100644 --- a/polkadot/roadmap/implementers-guide/book.toml +++ b/polkadot/roadmap/implementers-guide/book.toml @@ -1,5 +1,5 @@ [book] -authors = ["Rob Habermeier", "Peter Goodspeed-Niklaus"] +authors = ["Parity Technologies "] language = "en" multilingual = false src = "src" diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 479631e7dd1..2338e8711ed 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-asset-rate" version = "4.0.0-dev" description = "Whitelist non-native assets for treasury spending and provide conversion to native balance" -authors = ["William Freudenberger "] +authors.workspace = true homepage = "https://substrate.io" edition.workspace = true license = "Apache-2.0" diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 56ae0087099..e848f280f5d 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp-consensus-sassafras" version = "0.3.4-dev" -authors = ["Parity Technologies "] +authors.workspace = true description = "Primitives for Sassafras consensus" edition = "2021" license = "Apache-2.0" diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 5cc4f6cbc09..b0a00e1207a 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -1,10 +1,7 @@ [package] name = "substrate-frame-rpc-support" version = "3.0.0" -authors = [ - "Parity Technologies ", - "Andrew Dirksen ", -] +authors.workspace = true edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" -- GitLab From a30092ab42c74c8a4d4c6ce8ac2b0e860749bb46 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 4 Sep 2023 11:02:32 +0200 Subject: [PATCH 066/633] Markdown linter (#1309) * Add markdown linting - add linter default rules - adapt rules to current code - fix the code for linting to pass - add CI check fix #1243 * Fix markdown for Substrate * Fix tooling install * Fix workflow * Add documentation * Remove trailing spaces * Update .github/.markdownlint.yaml Co-authored-by: Oliver Tale-Yazdi * Fix mangled markdown/lists * Fix captalization issues on known words --- .github/.markdownlint.yaml | 210 ++++ .github/workflows/check-markdown.yml | 33 + README.md | 50 +- cumulus/BRIDGES.md | 34 +- cumulus/README.md | 162 ++- cumulus/bridges/CODE_OF_CONDUCT.md | 4 +- cumulus/bridges/README.md | 118 ++- cumulus/bridges/SECURITY.md | 12 +- cumulus/bridges/docs/high-level-overview.md | 209 ++-- .../docs/polkadot-kusama-bridge-overview.md | 111 +- cumulus/bridges/modules/messages/README.md | 339 +++---- cumulus/bridges/modules/parachains/README.md | 2 +- cumulus/docs/container.md | 30 +- cumulus/docs/release.md | 55 +- cumulus/pallets/collator-selection/README.md | 2 +- cumulus/parachain-template/README.md | 2 +- .../e2e/collectives/README.md | 16 +- .../parachains/runtimes/bridge-hubs/README.md | 67 +- .../contracts/contracts-rococo/README.md | 4 +- cumulus/scripts/ci/changelog/README.md | 77 ++ cumulus/xcm/xcm-emulator/README.md | 4 +- .../0007-prepare-warp-sync-db-snapshot.md | 15 +- docs/CONTRIBUTING.md | 18 +- docs/DOCUMENTATION_GUIDELINE.md | 245 +++-- docs/PULL_REQUEST_TEMPLATE.md | 26 +- docs/STYLE_GUIDE.md | 40 +- docs/markdown_linting.md | 20 + polkadot/README.md | 8 +- polkadot/RELEASE.md | 93 +- polkadot/doc/docker.md | 50 +- polkadot/doc/release-checklist.md | 111 +- polkadot/doc/shell-completion.md | 6 +- polkadot/doc/testing.md | 108 +- polkadot/erasure-coding/benches/README.md | 8 +- polkadot/grafana/README.md | 52 +- polkadot/node/gum/README.md | 2 +- polkadot/node/malus/README.md | 4 +- polkadot/node/metrics/README.md | 2 +- polkadot/node/test/service/README.md | 2 +- polkadot/parachain/test-parachains/README.md | 3 +- .../test-parachains/adder/collator/README.md | 2 +- .../roadmap/implementers-guide/src/README.md | 10 +- .../roadmap/implementers-guide/src/SUMMARY.md | 20 +- .../implementers-guide/src/architecture.md | 58 +- .../implementers-guide/src/disputes-flow.md | 40 +- .../implementers-guide/src/glossary.md | 74 +- .../implementers-guide/src/messaging.md | 90 +- .../implementers-guide/src/node/README.md | 43 +- .../src/node/approval/README.md | 7 +- .../node/approval/approval-distribution.md | 200 ++-- .../src/node/approval/approval-voting.md | 294 ++++-- .../src/node/availability/README.md | 6 +- .../availability/availability-distribution.md | 96 +- .../availability/availability-recovery.md | 56 +- .../availability/bitfield-distribution.md | 34 +- .../src/node/availability/bitfield-signing.md | 24 +- .../src/node/backing/README.md | 13 +- .../src/node/backing/candidate-backing.md | 100 +- .../backing/statement-distribution-legacy.md | 152 ++- .../node/backing/statement-distribution.md | 460 ++++----- .../src/node/collators/README.md | 8 +- .../node/collators/collation-generation.md | 40 +- .../src/node/collators/collator-protocol.md | 118 ++- .../src/node/disputes/README.md | 12 +- .../src/node/disputes/dispute-coordinator.md | 960 ++++++++---------- .../src/node/disputes/dispute-distribution.md | 12 +- .../src/node/grandpa-voting-rule.md | 25 +- .../implementers-guide/src/node/overseer.md | 99 +- .../src/node/subsystems-and-jobs.md | 172 ++-- .../src/node/utility/availability-store.md | 72 +- .../src/node/utility/candidate-validation.md | 43 +- .../src/node/utility/chain-api.md | 6 +- .../src/node/utility/chain-selection.md | 53 +- .../src/node/utility/network-bridge.md | 98 +- .../src/node/utility/provisioner.md | 198 ++-- .../src/node/utility/pvf-prechecker.md | 55 +- .../src/node/utility/runtime-api.md | 10 +- .../src/protocol-approval.md | 336 ++++-- .../src/protocol-chain-selection.md | 45 +- .../src/protocol-disputes.md | 126 ++- .../src/protocol-overview.md | 127 ++- .../implementers-guide/src/pvf-prechecking.md | 69 +- .../src/runtime-api/README.md | 39 +- .../src/runtime-api/availability-cores.md | 18 +- .../candidate-pending-availability.md | 3 +- .../src/runtime-api/disputes-info.md | 5 +- .../runtime-api/persisted-validation-data.md | 6 +- .../src/runtime-api/pvf-prechecking.md | 14 +- .../src/runtime-api/session-index.md | 3 +- .../src/runtime-api/validator-groups.md | 3 +- .../src/runtime-api/validators.md | 3 +- .../implementers-guide/src/runtime/README.md | 89 +- .../src/runtime/configuration.md | 26 +- .../src/runtime/disputes.md | 103 +- .../implementers-guide/src/runtime/dmp.md | 13 +- .../implementers-guide/src/runtime/hrmp.md | 95 +- .../src/runtime/inclusion.md | 122 ++- .../src/runtime/initializer.md | 21 +- .../src/runtime/parainherent.md | 61 +- .../implementers-guide/src/runtime/paras.md | 97 +- .../src/runtime/scheduler.md | 147 ++- .../src/runtime/session_info.md | 14 +- .../implementers-guide/src/runtime/shared.md | 32 +- .../implementers-guide/src/types/approval.md | 19 +- .../src/types/availability.md | 24 +- .../implementers-guide/src/types/backing.md | 29 +- .../implementers-guide/src/types/candidate.md | 60 +- .../implementers-guide/src/types/disputes.md | 3 +- .../implementers-guide/src/types/network.md | 3 +- .../src/types/overseer-protocol.md | 51 +- .../src/whence-parachains.md | 39 +- polkadot/roadmap/parachains.md | 182 ++-- polkadot/runtime/rococo/README.md | 6 +- polkadot/utils/staking-miner/README.md | 37 +- polkadot/xcm/xcm-simulator/fuzzer/README.md | 6 +- polkadot/zombienet_tests/README.md | 44 +- substrate/README.md | 46 +- substrate/bin/node-template/README.md | 179 ++-- .../bin/node-template/docs/rust-setup.md | 103 +- .../node-template/pallets/template/README.md | 2 +- substrate/bin/utils/subkey/README.md | 67 +- substrate/bin/utils/subkey/SECURITY.md | 23 +- substrate/client/allocator/README.md | 2 +- substrate/client/api/README.md | 2 +- substrate/client/block-builder/README.md | 2 +- substrate/client/chain-spec/README.md | 2 +- substrate/client/cli/README.md | 2 +- substrate/client/consensus/aura/README.md | 4 +- substrate/client/consensus/babe/README.md | 2 +- substrate/client/consensus/babe/rpc/README.md | 2 +- substrate/client/consensus/common/README.md | 2 +- substrate/client/consensus/epochs/README.md | 2 +- substrate/client/consensus/grandpa/README.md | 4 +- .../client/consensus/grandpa/rpc/README.md | 2 +- .../client/consensus/manual-seal/README.md | 2 +- substrate/client/consensus/slots/README.md | 2 +- substrate/client/db/README.md | 2 +- substrate/client/executor/README.md | 2 +- substrate/client/executor/common/README.md | 2 +- substrate/client/executor/wasmtime/README.md | 2 +- substrate/client/informant/README.md | 2 +- substrate/client/keystore/README.md | 2 +- substrate/client/network-gossip/README.md | 2 +- substrate/client/network/README.md | 10 +- substrate/client/offchain/README.md | 2 +- substrate/client/proposer-metrics/README.md | 2 +- substrate/client/rpc-api/README.md | 4 +- substrate/client/rpc-servers/README.md | 2 +- substrate/client/rpc-spec-v2/README.md | 4 +- substrate/client/rpc/README.md | 2 +- substrate/client/service/README.md | 2 +- substrate/client/state-db/README.md | 6 +- substrate/client/telemetry/README.md | 6 +- substrate/client/tracing/README.md | 4 +- substrate/client/transaction-pool/README.md | 8 +- substrate/docker/README.md | 30 +- substrate/docs/CHANGELOG.md | 144 ++- substrate/docs/SECURITY.md | 40 +- substrate/docs/STYLE_GUIDE.md | 70 +- substrate/docs/Upgrade.md | 8 +- substrate/docs/Upgrading-2.0-to-3.0.md | 140 ++- substrate/docs/node-template-release.md | 96 +- substrate/frame/README.md | 7 +- substrate/frame/assets/README.md | 35 +- substrate/frame/atomic-swap/README.md | 6 +- substrate/frame/aura/README.md | 3 +- substrate/frame/authority-discovery/README.md | 4 +- substrate/frame/authorship/README.md | 2 +- substrate/frame/babe/README.md | 2 +- substrate/frame/balances/README.md | 62 +- substrate/frame/benchmarking/README.md | 181 ++-- substrate/frame/child-bounties/README.md | 2 +- substrate/frame/contracts/CHANGELOG.md | 2 +- substrate/frame/contracts/README.md | 130 +-- .../frame/contracts/benchmarks/README.md | 11 +- .../frame/contracts/primitives/README.md | 2 +- substrate/frame/core-fellowship/README.md | 2 +- substrate/frame/elections-phragmen/README.md | 110 +- substrate/frame/examples/basic/README.md | 2 +- substrate/frame/examples/split/README.md | 2 +- substrate/frame/executive/README.md | 18 +- substrate/frame/glutton/README.md | 7 +- substrate/frame/grandpa/README.md | 2 +- substrate/frame/identity/README.md | 28 +- substrate/frame/indices/README.md | 2 +- .../README.md | 20 +- substrate/frame/multisig/README.md | 6 +- .../frame/nft-fractionalization/README.md | 8 +- substrate/frame/nfts/README.md | 24 +- substrate/frame/nicks/README.md | 6 +- substrate/frame/nis/README.md | 2 +- .../nomination-pools/runtime-api/README.md | 2 +- substrate/frame/offences/README.md | 2 +- .../frame/offences/benchmarking/README.md | 2 +- substrate/frame/ranked-collective/README.md | 2 +- substrate/frame/recovery/README.md | 28 +- substrate/frame/remark/README.md | 2 +- substrate/frame/root-offences/README.md | 2 +- substrate/frame/root-testing/README.md | 2 +- substrate/frame/salary/README.md | 2 +- substrate/frame/scheduler/README.md | 8 +- substrate/frame/session/README.md | 64 +- .../frame/session/benchmarking/README.md | 2 +- substrate/frame/society/README.md | 38 +- substrate/frame/staking/README.md | 193 ++-- substrate/frame/sudo/README.md | 6 +- substrate/frame/support/README.md | 2 +- substrate/frame/support/test/tests/pallet.rs | 6 +- substrate/frame/system/README.md | 36 +- substrate/frame/system/benchmarking/README.md | 2 +- .../frame/system/benchmarking/res/README.md | 3 +- .../frame/system/rpc/runtime-api/README.md | 2 +- substrate/frame/timestamp/README.md | 8 +- substrate/frame/tips/README.md | 4 +- substrate/frame/transaction-storage/README.md | 24 +- substrate/frame/uniques/README.md | 16 +- substrate/frame/utility/README.md | 4 +- substrate/primitives/api/README.md | 2 +- .../primitives/application-crypto/README.md | 2 +- substrate/primitives/arithmetic/README.md | 2 +- .../primitives/authority-discovery/README.md | 2 +- substrate/primitives/block-builder/README.md | 2 +- substrate/primitives/blockchain/README.md | 2 +- substrate/primitives/consensus/aura/README.md | 2 +- substrate/primitives/consensus/babe/README.md | 2 +- .../primitives/consensus/common/README.md | 4 +- .../primitives/consensus/grandpa/README.md | 2 +- substrate/primitives/consensus/pow/README.md | 2 +- .../primitives/consensus/slots/README.md | 2 +- substrate/primitives/database/README.md | 2 +- substrate/primitives/externalities/README.md | 2 +- substrate/primitives/inherents/README.md | 2 +- substrate/primitives/io/README.md | 4 +- substrate/primitives/keyring/README.md | 2 +- substrate/primitives/npos-elections/README.md | 55 +- substrate/primitives/offchain/README.md | 2 +- substrate/primitives/panic-handler/README.md | 2 +- substrate/primitives/rpc/README.md | 2 +- .../primitives/runtime-interface/README.md | 50 +- substrate/primitives/runtime/README.md | 2 +- substrate/primitives/session/README.md | 2 +- substrate/primitives/staking/README.md | 2 +- substrate/primitives/state-machine/README.md | 2 +- .../primitives/statement-store/README.md | 35 +- substrate/primitives/std/README.md | 2 +- substrate/primitives/storage/README.md | 2 +- substrate/primitives/timestamp/README.md | 2 +- substrate/primitives/tracing/README.md | 2 +- .../primitives/transaction-pool/README.md | 2 +- substrate/primitives/trie/README.md | 2 +- substrate/primitives/version/README.md | 2 +- substrate/primitives/wasm-interface/README.md | 2 +- .../ci/docker/subkey.Dockerfile.README.md | 7 +- .../ci/docker/substrate.Dockerfile.README.md | 2 +- .../grafana-dashboards/README_dashboard.md | 2 +- substrate/utils/build-script-utils/README.md | 2 +- substrate/utils/fork-tree/README.md | 2 +- .../utils/frame/benchmarking-cli/README.md | 17 +- .../benchmarking-cli/src/block/README.md | 81 +- .../benchmarking-cli/src/machine/README.md | 48 +- .../benchmarking-cli/src/overhead/README.md | 62 +- .../benchmarking-cli/src/shared/README.md | 7 +- .../benchmarking-cli/src/storage/README.md | 43 +- .../utils/frame/frame-utilities-cli/README.md | 2 +- substrate/utils/frame/rpc/support/README.md | 2 +- substrate/utils/frame/rpc/system/README.md | 2 +- substrate/utils/prometheus/README.md | 12 +- substrate/utils/wasm-builder/README.md | 61 +- .../zombienet/0001-basic-warp-sync/README.md | 9 +- .../0002-validators-warp-sync/README.md | 7 +- .../0003-block-building-warp-sync/README.md | 5 +- 271 files changed, 6425 insertions(+), 4586 deletions(-) create mode 100644 .github/.markdownlint.yaml create mode 100644 .github/workflows/check-markdown.yml create mode 100644 cumulus/scripts/ci/changelog/README.md create mode 100644 docs/markdown_linting.md diff --git a/.github/.markdownlint.yaml b/.github/.markdownlint.yaml new file mode 100644 index 00000000000..6a93d89c46a --- /dev/null +++ b/.github/.markdownlint.yaml @@ -0,0 +1,210 @@ +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time +MD001: true + +# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading +MD002: + # Heading level + level: 1 + +# MD003/heading-style/header-style - Heading style +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style - Unordered list style +MD004: + # List style + style: "consistent" + +# MD005/list-indent - Inconsistent indentation for list items at the same level +MD005: false + +# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line +MD006: false + +# MD007/ul-indent - Unordered list indentation +MD007: false + +# MD009/no-trailing-spaces - Trailing spaces +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs - Hard tabs +MD010: false + +# MD011/no-reversed-links - Reversed link syntax +MD011: true + +# MD012/no-multiple-blanks - Multiple consecutive blank lines +MD012: + # Consecutive blank lines + maximum: 2 + +# MD013/line-length - Line length +MD013: + # Number of characters + line_length: 120 + # Number of characters for headings + heading_line_length: 120 + # Number of characters for code blocks + code_block_line_length: 150 + # Include code blocks + code_blocks: true + # Include tables + tables: true + # Include headings + headings: true + # Include headings + headers: true + # Strict length checking + strict: false + # Stern length checking + stern: false + +# MD014/commands-show-output - Dollar signs used before commands without showing output +MD014: true + +# MD018/no-missing-space-atx - No space after hash on atx style heading +MD018: true + +# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading +MD019: true + +# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading +MD020: true + +# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading +MD021: true + +# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines +MD022: false + +# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line +MD023: true + +# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content +MD024: false + +# MD025/single-title/single-h1 - Multiple top-level headings in the same document +MD025: false + +# MD026/no-trailing-punctuation - Trailing punctuation in heading +MD026: + # Punctuation characters + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol +MD027: true + +# MD028/no-blanks-blockquote - Blank line inside blockquote +MD028: true + +# MD029/ol-prefix - Ordered list item prefix +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space - Spaces after list markers +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines +MD031: false + +# MD032/blanks-around-lists - Lists should be surrounded by blank lines +MD032: false + +# MD033/no-inline-html - Inline HTML +MD033: false + +# MD034/no-bare-urls - Bare URL used +MD034: false + +# MD035/hr-style - Horizontal rule style +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading +MD036: false + +# MD037/no-space-in-emphasis - Spaces inside emphasis markers +MD037: true + +# MD038/no-space-in-code - Spaces inside code span elements +MD038: true + +# MD039/no-space-in-links - Spaces inside link text +MD039: true + +# MD040/fenced-code-language - Fenced code blocks should have a language specified +MD040: false + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: false + +# MD042/no-empty-links - No empty links +MD042: true + +# MD043/required-headings/required-headers - Required heading structure +MD043: false + +# MD044/proper-names - Proper names should have the correct capitalization +MD044: + # List of proper names + names: ["Polkadot", "Substrate", "Cumulus", "Parity"] + # Include code blocks + code_blocks: false + # Include HTML elements + html_elements: false + +# MD045/no-alt-text - Images should have alternate text (alt text) +MD045: false + +# MD046/code-block-style - Code block style +MD046: + # Block style + style: "consistent" + +# MD047/single-trailing-newline - Files should end with a single newline character +MD047: true + +# MD048/code-fence-style - Code fence style +MD048: + # Code fence style + style: "consistent" + +# MD049/emphasis-style - Emphasis style should be consistent +MD049: false + +# MD050/strong-style - Strong style should be consistent +MD050: + # Strong style + style: "consistent" + +# MD051/link-fragments - Link fragments should be valid +MD051: false + +# MD052/reference-links-images - Reference links and images should use a label that is defined +MD052: false + +# MD053/link-image-reference-definitions - Link and image reference definitions should be needed +MD053: false diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml new file mode 100644 index 00000000000..b386fd6d1b1 --- /dev/null +++ b/.github/workflows/check-markdown.yml @@ -0,0 +1,33 @@ +name: Check Markdown + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + packages: read + +jobs: + lint-markdown: + runs-on: ubuntu-latest + + 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: Install tooling + run: | + npm install -g markdownlint-cli + markdownlint --version + + - name: Check Markdown + env: + CONFIG: .github/.markdownlint.yaml + run: | + markdownlint --config "$CONFIG" --ignore target . diff --git a/README.md b/README.md index a0ef1818279..56b3481bafc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -> NOTE: We have recently made significant changes to our repository structure. In order to -streamline our development process and foster better contributions, we have merged three separate -repositories Cumulus, Substrate and Polkadot into this repository. Read more about the changes [ +> NOTE: We have recently made significant changes to our repository structure. In order to streamline our development +process and foster better contributions, we have merged three separate repositories Cumulus, Substrate and Polkadot into +this repository. Read more about the changes [ here](https://polkadot-public.notion.site/Polkadot-SDK-FAQ-fbc4cecc2c46443fb37b9eeec2f0d85f). # Polkadot SDK @@ -9,27 +9,29 @@ here](https://polkadot-public.notion.site/Polkadot-SDK-FAQ-fbc4cecc2c46443fb37b9 [![StackExchange](https://img.shields.io/badge/StackExchange-Community%20&%20Support-222222?logo=stackexchange)](https://substrate.stackexchange.com/) -The Polkadot SDK repository provides all the resources needed to start building on the Polkadot -network, a multi-chain blockchain platform that enables different blockchains to interoperate and -share information in a secure and scalable way. The Polkadot SDK comprises three main pieces of -software: +The Polkadot SDK repository provides all the resources needed to start building on the Polkadot network, a multi-chain +blockchain platform that enables different blockchains to interoperate and share information in a secure and scalable +way. The Polkadot SDK comprises three main pieces of software: ## [Polkadot](./polkadot/) -[![PolkadotForum](https://img.shields.io/badge/Polkadot_Forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) [![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](./polkadot/LICENSE) +[![PolkadotForum](https://img.shields.io/badge/Polkadot_Forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) +[![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](./polkadot/LICENSE) -Implementation of a node for the https://polkadot.network in Rust, using the Substrate framework. -This directory currently contains runtimes for the Polkadot, Kusama, Westend, and Rococo networks. -In the future, these will be relocated to the [`runtimes`](https://github.com/polkadot-fellows/runtimes/) repository. +Implementation of a node for the https://polkadot.network in Rust, using the Substrate framework. This directory +currently contains runtimes for the Polkadot, Kusama, Westend, and Rococo networks. In the future, these will be +relocated to the [`runtimes`](https://github.com/polkadot-fellows/runtimes/) repository. ## [Substrate](./substrate/) - [![SubstrateRustDocs](https://img.shields.io/badge/Rust_Docs-Substrate-24CC85?logo=rust)](https://paritytech.github.io/substrate/master/substrate/index.html) [![Substrate-license](https://img.shields.io/badge/License-GPL3%2FApache2.0-blue)](./substrate/README.md#LICENSE) + [![SubstrateRustDocs](https://img.shields.io/badge/Rust_Docs-Substrate-24CC85?logo=rust)](https://paritytech.github.io/substrate/master/substrate/index.html) + [![Substrate-license](https://img.shields.io/badge/License-GPL3%2FApache2.0-blue)](./substrate/README.md#LICENSE) -Substrate is the primary blockchain SDK used by developers to create the parachains that make up -the Polkadot network. Additionally, it allows for the development of self-sovereign blockchains -that operate completely independently of Polkadot. +Substrate is the primary blockchain SDK used by developers to create the parachains that make up the Polkadot network. +Additionally, it allows for the development of self-sovereign blockchains that operate completely independently of +Polkadot. ## [Cumulus](./cumulus/) -[![CumulusRustDocs](https://img.shields.io/badge/Rust_Docs-Cumulus-222222?logo=rust)](https://paritytech.github.io/cumulus/cumulus_client_collator/index.html) [![Cumulus-license](https://img.shields.io/badge/License-GPL3-blue)](./cumulus/LICENSE) +[![CumulusRustDocs](https://img.shields.io/badge/Rust_Docs-Cumulus-222222?logo=rust)](https://paritytech.github.io/cumulus/cumulus_client_collator/index.html) +[![Cumulus-license](https://img.shields.io/badge/License-GPL3-blue)](./cumulus/LICENSE) Cumulus is a set of tools for writing Substrate-based Polkadot parachains. @@ -37,10 +39,10 @@ Cumulus is a set of tools for writing Substrate-based Polkadot parachains. Below are the primary upstream dependencies utilized in this project: -- [parity-scale-codec](https://crates.io/crates/parity-scale-codec) -- [parity-db](https://crates.io/crates/parity-db) -- [parity-common](https://github.com/paritytech/parity-common) -- [trie](https://github.com/paritytech/trie) +- [`parity-scale-codec`](https://crates.io/crates/parity-scale-codec) +- [`parity-db`](https://crates.io/crates/parity-db) +- [`parity-common`](https://github.com/paritytech/parity-common) +- [`trie`](https://github.com/paritytech/trie) ## Security @@ -48,9 +50,11 @@ The security policy and procedures can be found in [docs/SECURITY.md](./docs/SEC ## Contributing & Code of Conduct -Ensure you follow our [contribution guidelines](./docs/CONTRIBUTING.md). In every interaction and contribution, this project adheres to the [Contributor Covenant Code of Conduct](./docs/CODE_OF_CONDUCT.md). +Ensure you follow our [contribution guidelines](./docs/CONTRIBUTING.md). In every interaction and contribution, this +project adheres to the [Contributor Covenant Code of Conduct](./docs/CODE_OF_CONDUCT.md). ## Additional Resources -- For monitoring upcoming changes and current proposals related to the technical implementation of the Polkadot network, visit the [`Requests for Comment (RFC)`](https://github.com/polkadot-fellows/RFCs) repository. While it's maintained by the Polkadot Fellowship, the RFC process welcomes contributions from everyone. - +- For monitoring upcoming changes and current proposals related to the technical implementation of the Polkadot network, + visit the [`Requests for Comment (RFC)`](https://github.com/polkadot-fellows/RFCs) repository. While it's maintained + by the Polkadot Fellowship, the RFC process welcomes contributions from everyone. diff --git a/cumulus/BRIDGES.md b/cumulus/BRIDGES.md index 8766de92c17..a6f00aec092 100644 --- a/cumulus/BRIDGES.md +++ b/cumulus/BRIDGES.md @@ -1,13 +1,13 @@ -# Using Parity Bridges Common dependency (`git subtree`). +# Using Parity Bridges Common dependency (`git subtree`) In `./bridges` sub-directory you can find a `git subtree` imported version of: -[parity-bridges-common](https://github.com/paritytech/parity-bridges-common/) repository. +[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common/) repository. (For regular Cumulus contributor 1. is relevant) \ (For Cumulus maintainer 1. and 2. are relevant) \ (For Bridges team 1. and 2. and 3. are relevant) -# 1. How to fix broken Bridges code? +## How to fix broken Bridges code? To fix Bridges code simply create a commit in current (`Cumulus`) repo. Best if the commit is isolated to changes in `./bridges` sub-directory, because it makes @@ -16,7 +16,7 @@ it easier to import that change back to upstream repo. (Any changes to `bridges` subtree require Bridges team approve and they should manage backport to Bridges repo) -# 2. How to pull latest Bridges code to the `bridges` subtree +## How to pull latest Bridges code to the `bridges` subtree (in practice) The `bridges` repo has a stabilized branch `polkadot-staging` dedicated for releasing. @@ -25,7 +25,7 @@ The `bridges` repo has a stabilized branch `polkadot-staging` dedicated for rele cd # this will update new git branches from bridges repo -# there could be unresolved conflicts, but dont worry, +# there could be unresolved conflicts, but don't worry, # lots of them are caused because of removed unneeded files with patch step, BRANCH=polkadot-staging ./scripts/bridges_update_subtree.sh fetch @@ -45,9 +45,9 @@ BRANCH=polkadot-staging ./scripts/bridges_update_subtree.sh fetch # so after all conflicts are solved and patch passes and compiles, # then we need to finish merge with: git merge --continue -```` +``` -# 3. How to pull latest Bridges code or contribute back? +## How to pull latest Bridges code or contribute back? (in theory) Note that it's totally fine to ping the **Bridges Team** to do that for you. The point @@ -58,34 +58,34 @@ If you still would like to either update the code to match latest code from the or create an upstream PR read below. The following commands should be run in the current (`polkadot`) repo. -1. Add Bridges repo as a local remote: +### Add Bridges repo as a local remote ``` -$ git remote add -f bridges git@github.com:paritytech/parity-bridges-common.git +git remote add -f bridges git@github.com:paritytech/parity-bridges-common.git ``` If you plan to contribute back, consider forking the repository on Github and adding your personal fork as a remote as well. ``` -$ git remote add -f my-bridges git@github.com:tomusdrw/parity-bridges-common.git +git remote add -f my-bridges git@github.com:tomusdrw/parity-bridges-common.git ``` -2. To update Bridges: +### To update Bridges +``` +git fetch bridges polkadot-staging +git subtree pull --prefix=bridges bridges polkadot-staging --squash ``` -$ git fetch bridges polkadot-staging -$ git subtree pull --prefix=bridges bridges polkadot-staging --squash -```` We use `--squash` to avoid adding individual commits and rather squashing them all into one. -3. Clean unneeded files here: +### Clean unneeded files here ``` ./bridges/scripts/verify-pallets-build.sh --ignore-git-state --no-revert ``` -4. Contributing back to Bridges (creating upstream PR) +### Contributing back to Bridges (creating upstream PR) ``` -$ git subtree push --prefix=bridges my-bridges polkadot-staging +git subtree push --prefix=bridges my-bridges polkadot-staging ``` This command will push changes to your personal fork of Bridges repo, from where you can simply create a PR to the main repo. diff --git a/cumulus/README.md b/cumulus/README.md index 419e293a0ab..19f9f3f113d 100644 --- a/cumulus/README.md +++ b/cumulus/README.md @@ -2,59 +2,53 @@ [![Doc](https://img.shields.io/badge/cumulus%20docs-master-brightgreen)](https://paritytech.github.io/cumulus/) -This repository contains both the Cumulus SDK and also specific chains implemented on top of this -SDK. +This repository contains both the Cumulus SDK and also specific chains implemented on top of this SDK. -If you only want to run a **Polkadot Parachain Node**, check out our [container -section](./docs/container.md). +If you only want to run a **Polkadot Parachain Node**, check out our [container section](./docs/container.md). ## Cumulus SDK -A set of tools for writing [Substrate](https://substrate.io/)-based -[Polkadot](https://wiki.polkadot.network/en/) -[parachains](https://wiki.polkadot.network/docs/en/learn-parachains). Refer to the included -[overview](docs/overview.md) for architectural details, and the [Connect to a relay chain how-to -guide](https://docs.substrate.io/reference/how-to-guides/parachains/connect-to-a-relay-chain/) for a -guided walk-through of using these tools. +A set of tools for writing [Substrate](https://substrate.io/)-based [Polkadot](https://wiki.polkadot.network/en/) +[parachains](https://wiki.polkadot.network/docs/en/learn-parachains). Refer to the included [overview](docs/overview.md) +for architectural details, and the [Connect to a relay chain how-to +guide](https://docs.substrate.io/reference/how-to-guides/parachains/connect-to-a-relay-chain/) for a guided walk-through +of using these tools. -It's easy to write blockchains using Substrate, and the overhead of writing parachains' -distribution, p2p, database, and synchronization layers should be just as low. This project aims to -make it easy to write parachains for Polkadot by leveraging the power of Substrate. +It's easy to write blockchains using Substrate, and the overhead of writing parachains' distribution, p2p, database, and +synchronization layers should be just as low. This project aims to make it easy to write parachains for Polkadot by +leveraging the power of Substrate. -Cumulus clouds are shaped sort of like dots; together they form a system that is intricate, -beautiful and functional. +Cumulus clouds are shaped sort of like dots; together they form a system that is intricate, beautiful and functional. ### Consensus [`parachain-consensus`](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/client/consensus/common/src/parachain_consensus.rs) -is a [consensus engine](https://docs.substrate.io/v3/advanced/consensus) for Substrate that follows -a Polkadot [relay chain](https://wiki.polkadot.network/docs/en/learn-architecture#relay-chain). This -will run a Polkadot node internally, and dictate to the client and synchronization algorithms which -chain to follow, -[finalize](https://wiki.polkadot.network/docs/en/learn-consensus#probabilistic-vs-provable-finality), -and treat as best. +is a [consensus engine](https://docs.substrate.io/v3/advanced/consensus) for Substrate that follows a Polkadot [relay +chain](https://wiki.polkadot.network/docs/en/learn-architecture#relay-chain). This will run a Polkadot node internally, +and dictate to the client and synchronization algorithms which chain to follow, +[finalize](https://wiki.polkadot.network/docs/en/learn-consensus#probabilistic-vs-provable-finality), and treat as best. ### Collator -A Polkadot [collator](https://wiki.polkadot.network/docs/en/learn-collator) for the parachain is -implemented by the `polkadot-parachain` binary (previously called `polkadot-collator`). +A Polkadot [collator](https://wiki.polkadot.network/docs/en/learn-collator) for the parachain is implemented by the +`polkadot-parachain` binary (previously called `polkadot-collator`). -You may run `polkadot-parachain` locally after building it or using one of the container option -described [here](./docs/container.md). +You may run `polkadot-parachain` locally after building it or using one of the container option described +[here](./docs/container.md). -### Relay Chain Interaction -To operate a parachain node, a connection to the corresponding relay -chain is necessary. This can be achieved in one of three ways: -1. Run a full relay chain node within the parachain node (default) -2. Connect to an external relay chain node via WebSocket RPC +### Relay Chain Interaction +To operate a parachain node, a connection to the corresponding relay chain is necessary. This can be achieved in one of +three ways: +1. Run a full relay chain node within the parachain node (default) +2. Connect to an external relay chain node via WebSocket RPC 3. Run a light client for the relay chain #### In-process Relay Chain Node -If an external relay chain node is not specified (default behavior), then a full relay chain node is -spawned within the same process. +If an external relay chain node is not specified (default behavior), then a full relay chain node is spawned within the +same process. -This node has all of the typical components of a regular Polkadot node and will have to fully sync -with the relay chain to work. +This node has all of the typical components of a regular Polkadot node and will have to fully sync with the relay chain +to work. ##### Example command ```bash @@ -66,19 +60,16 @@ polkadot-parachain \ ``` #### External Relay Chain Node -An external relay chain node is connected via WebsSocket RPC by using the -`--relay-chain-rpc-urls` command line argument. This option accepts one or more -space-separated WebSocket URLs to a full relay chain node. By default, only the -first URL will be used, with the rest as a backup in case the connection to the -first node is lost. +An external relay chain node is connected via WebsSocket RPC by using the `--relay-chain-rpc-urls` command line +argument. This option accepts one or more space-separated WebSocket URLs to a full relay chain node. By default, only +the first URL will be used, with the rest as a backup in case the connection to the first node is lost. -Parachain nodes using this feature won't have to fully sync with the relay chain -to work, so in general they will use fewer system resources. +Parachain nodes using this feature won't have to fully sync with the relay chain to work, so in general they will use +fewer system resources. -**Note:** At this time, any parachain nodes using this feature will still spawn a -significantly cut-down relay chain node in-process. Even though they lack the -majority of normal Polkadot subsystems, they will still need to connect directly -to the relay chain network. +**Note:** At this time, any parachain nodes using this feature will still spawn a significantly cut-down relay chain +node in-process. Even though they lack the majority of normal Polkadot subsystems, they will still need to connect +directly to the relay chain network. ##### Example command @@ -94,17 +85,15 @@ polkadot-parachain \ ``` #### Relay Chain Light Client -An internal relay chain light client provides a fast and lightweight approach -for connecting to the relay chain network. It provides relay chain notifications -and facilitates runtime calls. +An internal relay chain light client provides a fast and lightweight approach for connecting to the relay chain network. +It provides relay chain notifications and facilitates runtime calls. -To specify which chain the light client should connect to, users need to supply -a relay chain chain-spec as part of the relay chain arguments. +To specify which chain the light client should connect to, users need to supply a relay chain chain-spec as part of the +relay chain arguments. -**Note:** At this time, any parachain nodes using this feature will still spawn -a significantly cut-down relay chain node in-process. Even though they lack the -majority of normal Polkadot subsystems, they will still need to connect directly -to the relay chain network. +**Note:** At this time, any parachain nodes using this feature will still spawn a significantly cut-down relay chain +node in-process. Even though they lack the majority of normal Polkadot subsystems, they will still need to connect +directly to the relay chain network. ##### Example command @@ -118,23 +107,22 @@ polkadot-parachain \ ``` ## Installation and Setup -Before building Cumulus SDK based nodes / runtimes prepare your environment by -following Substrate [installation instructions](https://docs.substrate.io/main-docs/install/). +Before building Cumulus SDK based nodes / runtimes prepare your environment by following Substrate [installation +instructions](https://docs.substrate.io/main-docs/install/). -To launch a local network, you can use [zombienet](https://github.com/paritytech/zombienet) -for quick setup and experimentation or follow the [manual setup](#manual-setup). +To launch a local network, you can use [zombienet](https://github.com/paritytech/zombienet) for quick setup and +experimentation or follow the [manual setup](#manual-setup). ### Zombienet -We use Zombienet to spin up networks for integration tests and local networks. -Follow [these installation steps](https://github.com/paritytech/zombienet#requirements-by-provider) -to set it up on your machine. A simple network specification with two relay chain -nodes and one collator is located at [zombienet/examples/small_network.toml](zombienet/examples/small_network.toml). +We use Zombienet to spin up networks for integration tests and local networks. Follow [these installation +steps](https://github.com/paritytech/zombienet#requirements-by-provider) to set it up on your machine. A simple network +specification with two relay chain nodes and one collator is located at +[zombienet/examples/small_network.toml](zombienet/examples/small_network.toml). #### Which provider should I use? Zombienet offers multiple providers to run networks. Choose the one that best fits your needs: - **Podman:** Choose this if you want to spin up a network quick and easy. -- **Native:** Choose this if you want to develop and deploy your changes. Requires compilation -of the binaries. +- **Native:** Choose this if you want to develop and deploy your changes. Requires compilation of the binaries. - **Kubernetes:** Choose this for advanced use-cases or running on cloud-infrastructure. #### How to run @@ -183,13 +171,16 @@ cargo build --release --bin polkadot-parachain ./target/release/polkadot-parachain export-genesis-wasm > genesis-wasm # Collator1 -./target/release/polkadot-parachain --collator --alice --force-authoring --tmp --port 40335 --rpc-port 9946 -- --chain ../polkadot/rococo-local-cfde.json --port 30335 +./target/release/polkadot-parachain --collator --alice --force-authoring \ + --tmp --port 40335 --rpc-port 9946 -- --chain ../polkadot/rococo-local-cfde.json --port 30335 # Collator2 -./target/release/polkadot-parachain --collator --bob --force-authoring --tmp --port 40336 --rpc-port 9947 -- --chain ../polkadot/rococo-local-cfde.json --port 30336 +./target/release/polkadot-parachain --collator --bob --force-authoring \ + --tmp --port 40336 --rpc-port 9947 -- --chain ../polkadot/rococo-local-cfde.json --port 30336 # Parachain Full Node 1 -./target/release/polkadot-parachain --tmp --port 40337 --rpc-port 9948 -- --chain ../polkadot/rococo-local-cfde.json --port 30337 +./target/release/polkadot-parachain --tmp --port 40337 --rpc-port 9948 -- \ + --chain ../polkadot/rococo-local-cfde.json --port 30337 ``` #### Register the parachain @@ -199,8 +190,8 @@ cargo build --release --bin polkadot-parachain ## Asset Hub 🪙 -This repository also contains the Asset Hub runtimes. Asset Hub is a system parachain -providing an asset store for the Polkadot ecosystem. +This repository also contains the Asset Hub runtimes. Asset Hub is a system parachain providing an asset store for the +Polkadot ecosystem. ### Build & Launch a Node @@ -228,20 +219,18 @@ See [the `contracts-rococo` readme](parachains/runtimes/contracts/contracts-roco See [the `bridge-hubs` readme](parachains/runtimes/bridge-hubs/README.md) for details. ## Rococo 👑 -[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is becoming a -[Community Parachain Testbed](https://polkadot.network/blog/rococo-revamp-becoming-a-community-parachain-testbed/) -for parachain teams in the Polkadot ecosystem. It supports multiple parachains with the -differentiation of long-term connections and recurring short-term connections, to see -which parachains are currently connected and how long they will be connected for -[see here](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/parachains). +[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is becoming a [Community Parachain +Testbed](https://polkadot.network/blog/rococo-revamp-becoming-a-community-parachain-testbed/) for parachain teams in the +Polkadot ecosystem. It supports multiple parachains with the differentiation of long-term connections and recurring +short-term connections, to see which parachains are currently connected and how long they will be connected for [see +here](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/parachains). -Rococo is an elaborate style of design and the name describes the painstaking effort that -has gone into this project. +Rococo is an elaborate style of design and the name describes the painstaking effort that has gone into this project. ### Build & Launch Rococo Collators -Collators are similar to validators in the relay chain. These nodes build the blocks that -will eventually be included by the relay chain for a parachain. +Collators are similar to validators in the relay chain. These nodes build the blocks that will eventually be included by +the relay chain for a parachain. To run a Rococo collator you will need to compile the following binary: @@ -250,8 +239,7 @@ To run a Rococo collator you will need to compile the following binary: cargo build --release --locked --bin polkadot-parachain ``` -Once the executable is built, launch collators for each parachain (repeat once each for chain -`tick`, `trick`, `track`): +Once the executable is built, launch collators for each parachain (repeat once each for chain `tick`, `trick`, `track`): ```bash ./target/release/polkadot-parachain --chain $CHAIN --validator @@ -261,10 +249,10 @@ You can also build [using a container](./docs/container.md). ### Parachains -* [Asset Hub](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-statemint-rpc.polkadot.io#/explorer) -* [Contracts on Rococo](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-contracts-rpc.polkadot.io#/explorer) -* [RILT](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo.kilt.io#/explorer) +- [Asset Hub](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-statemint-rpc.polkadot.io#/explorer) +- [Contracts on Rococo](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-contracts-rpc.polkadot.io#/explorer) +- [RILT](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo.kilt.io#/explorer) -The network uses horizontal message passing (HRMP) to enable communication between -parachains and the relay chain and, in turn, between parachains. This means that every -message is sent to the relay chain, and from the relay chain to its destination parachain. +The network uses horizontal message passing (HRMP) to enable communication between parachains and the relay chain and, +in turn, between parachains. This means that every message is sent to the relay chain, and from the relay chain to its +destination parachain. diff --git a/cumulus/bridges/CODE_OF_CONDUCT.md b/cumulus/bridges/CODE_OF_CONDUCT.md index 70541fb72fa..23411da2e04 100644 --- a/cumulus/bridges/CODE_OF_CONDUCT.md +++ b/cumulus/bridges/CODE_OF_CONDUCT.md @@ -34,9 +34,9 @@ of preference. We see that blockchains are naturally community platforms with u ultimate decision makers. We assert that good software will maximise user agency by facilitate user-expression on the network. As such: -- This project will strive to give users as much choice as is both reasonable and possible over what +* This project will strive to give users as much choice as is both reasonable and possible over what protocol they adhere to; but -- use of the project's technical forums, commenting systems, pull requests and issue trackers as a +* use of the project's technical forums, commenting systems, pull requests and issue trackers as a means to express individual protocol preferences is forbidden. ## Our Responsibilities diff --git a/cumulus/bridges/README.md b/cumulus/bridges/README.md index 2f8c5ca9abb..da46fe67d92 100644 --- a/cumulus/bridges/README.md +++ b/cumulus/bridges/README.md @@ -2,11 +2,10 @@ This is a collection of components for building bridges. -These components include Substrate pallets for syncing headers, passing arbitrary messages, as well -as libraries for building relayers to provide cross-chain communication capabilities. +These components include Substrate pallets for syncing headers, passing arbitrary messages, as well as libraries for +building relayers to provide cross-chain communication capabilities. -Three bridge nodes are also available. The nodes can be used to run test networks which bridge other -Substrate chains. +Three bridge nodes are also available. The nodes can be used to run test networks which bridge other Substrate chains. 🚧 The bridges are currently under construction - a hardhat is recommended beyond this point 🚧 @@ -21,8 +20,8 @@ Substrate chains. ## Installation -To get up and running you need both stable and nightly Rust. Rust nightly is used to build the Web -Assembly (WASM) runtime for the node. You can configure the WASM support as so: +To get up and running you need both stable and nightly Rust. Rust nightly is used to build the Web Assembly (WASM) +runtime for the node. You can configure the WASM support as so: ```bash rustup install nightly @@ -38,8 +37,8 @@ cargo build --all cargo test --all ``` -Also you can build the repo with -[Parity CI Docker image](https://github.com/paritytech/scripts/tree/master/dockerfiles/bridges-ci): +Also you can build the repo with [Parity CI Docker +image](https://github.com/paritytech/scripts/tree/master/dockerfiles/bridges-ci): ```bash docker pull paritytech/bridges-ci:production @@ -57,16 +56,14 @@ docker run --rm -it -w /shellhere/parity-bridges-common \ If you want to reproduce other steps of CI process you can use the following [guide](https://github.com/paritytech/scripts#reproduce-ci-locally). -If you need more information about setting up your development environment [Substrate's -Installation page](https://docs.substrate.io/main-docs/install/) is a good -resource. +If you need more information about setting up your development environment [Substrate's Installation +page](https://docs.substrate.io/main-docs/install/) is a good resource. ## High-Level Architecture -This repo has support for bridging foreign chains together using a combination of Substrate pallets -and external processes called relayers. A bridge chain is one that is able to follow the consensus -of a foreign chain independently. For example, consider the case below where we want to bridge two -Substrate based chains. +This repo has support for bridging foreign chains together using a combination of Substrate pallets and external +processes called relayers. A bridge chain is one that is able to follow the consensus of a foreign chain independently. +For example, consider the case below where we want to bridge two Substrate based chains. ``` +---------------+ +---------------+ @@ -82,19 +79,19 @@ Substrate based chains. +---------------+ ``` -The Millau chain must be able to accept Rialto headers and verify their integrity. It does this by -using a runtime module designed to track GRANDPA finality. Since two blockchains can't interact -directly they need an external service, called a relayer, to communicate. The relayer will subscribe -to new Rialto headers via RPC and submit them to the Millau chain for verification. +The Millau chain must be able to accept Rialto headers and verify their integrity. It does this by using a runtime +module designed to track GRANDPA finality. Since two blockchains can't interact directly they need an external service, +called a relayer, to communicate. The relayer will subscribe to new Rialto headers via RPC and submit them to the Millau +chain for verification. -Take a look at [Bridge High Level Documentation](./docs/high-level-overview.md) for more in-depth -description of the bridge interaction. +Take a look at [Bridge High Level Documentation](./docs/high-level-overview.md) for more in-depth description of the +bridge interaction. ## Project Layout -Here's an overview of how the project is laid out. The main bits are the `bin`, which is the actual -"blockchain", the `modules` which are used to build the blockchain's logic (a.k.a the runtime) and -the `relays` which are used to pass messages between chains. +Here's an overview of how the project is laid out. The main bits are the `bin`, which is the actual "blockchain", the +`modules` which are used to build the blockchain's logic (a.k.a the runtime) and the `relays` which are used to pass +messages between chains. ``` ├── bin // Node and Runtime for the various Substrate chains @@ -117,16 +114,16 @@ the `relays` which are used to pass messages between chains. ## Running the Bridge -To run the Bridge you need to be able to connect the bridge relay node to the RPC interface of nodes -on each side of the bridge (source and target chain). +To run the Bridge you need to be able to connect the bridge relay node to the RPC interface of nodes on each side of the +bridge (source and target chain). There are 2 ways to run the bridge, described below: -- building & running from source: with this option, you'll be able to run the bridge between two standalone -chains that are running GRANDPA finality gadget to achieve finality; +- building & running from source: with this option, you'll be able to run the bridge between two standalone chains that +are running GRANDPA finality gadget to achieve finality; -- running a Docker Compose setup: this is a recommended option, where you'll see bridges with parachains, -complex relays and more. +- running a Docker Compose setup: this is a recommended option, where you'll see bridges with parachains, complex relays +and more. ### Using the Source @@ -141,16 +138,15 @@ cargo build -p substrate-relay ### Running a Dev network -We will launch a dev network to demonstrate how to relay a message between two Substrate based -chains (named Rialto and Millau). +We will launch a dev network to demonstrate how to relay a message between two Substrate based chains (named Rialto and +Millau). -To do this we will need two nodes, two relayers which will relay headers, and two relayers which -will relay messages. +To do this we will need two nodes, two relayers which will relay headers, and two relayers which will relay messages. #### Running from local scripts -To run a simple dev network you can use the scripts located in the -[`deployments/local-scripts` folder](./deployments/local-scripts). +To run a simple dev network you can use the scripts located in the [`deployments/local-scripts` +folder](./deployments/local-scripts). First, we must run the two Substrate nodes. @@ -167,8 +163,8 @@ After the nodes are up we can run the header relayers. ./deployments/local-scripts/relay-rialto-to-millau.sh ``` -At this point you should see the relayer submitting headers from the Millau Substrate chain to the -Rialto Substrate chain. +At this point you should see the relayer submitting headers from the Millau Substrate chain to the Rialto Substrate +chain. ``` # Header Relayer Logs @@ -192,20 +188,23 @@ You will also see the message lane relayers listening for new messages. [Millau_to_Rialto_MessageLane_00000000] [date] DEBUG bridge Asking Millau::ReceivingConfirmationsDelivery about best message nonces [...] [date] INFO bridge Synced Some(2) of Some(3) nonces in Millau::MessagesDelivery -> Rialto::MessagesDelivery race [...] [date] DEBUG bridge Asking Millau::MessagesDelivery about message nonces -[...] [date] DEBUG bridge Received best nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { latest_nonce: 0, nonces_data: () } +[...] [date] DEBUG bridge Received best nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { + latest_nonce: 0, nonces_data: () } [...] [date] DEBUG bridge Asking Millau::ReceivingConfirmationsDelivery about finalized message nonces -[...] [date] DEBUG bridge Received finalized nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { latest_nonce: 0, nonces_data: () } +[...] [date] DEBUG bridge Received finalized nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { + latest_nonce: 0, nonces_data: () } [...] [date] DEBUG bridge Received nonces from Millau::MessagesDelivery: SourceClientNonces { new_nonces: {}, confirmed_nonce: Some(0) } [...] [date] DEBUG bridge Asking Millau node about its state -[...] [date] DEBUG bridge Received state from Millau node: ClientState { best_self: HeaderId(1593, 0xacac***), best_finalized_self: HeaderId(1590, 0x0be81d...), best_finalized_peer_at_best_self: HeaderId(0, 0xdcdd89...) } +[...] [date] DEBUG bridge Received state from Millau node: ClientState { best_self: HeaderId(1593, 0xacac***), best_finalized_self: + HeaderId(1590, 0x0be81d...), best_finalized_peer_at_best_self: HeaderId(0, 0xdcdd89...) } ``` To send a message see the ["How to send a message" section](#how-to-send-a-message). ### How to send a message -In this section we'll show you how to quickly send a bridge message. The message is just an encoded XCM -`Trap(43)` message. +In this section we'll show you how to quickly send a bridge message. The message is just an encoded XCM `Trap(43)` +message. ```bash # In `parity-bridges-common` folder @@ -222,20 +221,20 @@ TRACE bridge Sent transaction to Millau node: 0x5e68... And at the Rialto node logs you'll something like this: ``` -... runtime::bridge-messages: Received messages: total=1, valid=1. Weight used: Weight(ref_time: 1215065371, proof_size: 48559)/Weight(ref_time: 1215065371, proof_size: 54703). -``` +... runtime::bridge-messages: Received messages: total=1, valid=1. Weight used: Weight(ref_time: 1215065371, proof_size: + 48559)/Weight(ref_time: 1215065371, proof_size: 54703). +``` -It means that the message has been delivered and dispatched. Message may be dispatched with an -error, though - the goal of our test bridge is to ensure that messages are successfully delivered -and all involved components are working. +It means that the message has been delivered and dispatched. Message may be dispatched with an error, though - the goal +of our test bridge is to ensure that messages are successfully delivered and all involved components are working. ## Full Network Docker Compose Setup -For a more sophisticated deployment which includes bidirectional header sync, message passing, -monitoring dashboards, etc. see the [Deployments README](./deployments/README.md). +For a more sophisticated deployment which includes bidirectional header sync, message passing, monitoring dashboards, +etc. see the [Deployments README](./deployments/README.md). -You should note that you can find images for all the bridge components published on -[Docker Hub](https://hub.docker.com/u/paritytech). +You should note that you can find images for all the bridge components published on [Docker +Hub](https://hub.docker.com/u/paritytech). To run a Rialto node for example, you can use the following command: @@ -247,13 +246,12 @@ docker run -p 30333:30333 -p 9933:9933 -p 9944:9944 \ ## Community -Main hangout for the community is [Element](https://element.io/) (formerly Riot). Element is a chat -server like, for example, Discord. Most discussions around Polkadot and Substrate happen -in various Element "rooms" (channels). So, joining Element might be a good idea, anyway. +Main hangout for the community is [Element](https://element.io/) (formerly Riot). Element is a chat server like, for +example, Discord. Most discussions around Polkadot and Substrate happen in various Element "rooms" (channels). So, +joining Element might be a good idea, anyway. -If you are interested in information exchange and development of Polkadot related bridges please -feel free to join the [Polkadot Bridges](https://app.element.io/#/room/#bridges:web3.foundation) -Element channel. +If you are interested in information exchange and development of Polkadot related bridges please feel free to join the +[Polkadot Bridges](https://app.element.io/#/room/#bridges:web3.foundation) Element channel. -The [Substrate Technical](https://app.element.io/#/room/#substrate-technical:matrix.org) Element -channel is most suited for discussions regarding Substrate itself. +The [Substrate Technical](https://app.element.io/#/room/#substrate-technical:matrix.org) Element channel is most suited +for discussions regarding Substrate itself. diff --git a/cumulus/bridges/SECURITY.md b/cumulus/bridges/SECURITY.md index 65f2f3bff05..9f215c88765 100644 --- a/cumulus/bridges/SECURITY.md +++ b/cumulus/bridges/SECURITY.md @@ -4,11 +4,15 @@ Thanks for helping make the Parity ecosystem more secure. Security is one of our ## Reporting a vulnerability -If you find something that can be treated as a security vulnerability, please do not use the issue tracker or discuss it in the public forum as it can cause more damage, rather than giving real help to the ecosystem. +If you find something that can be treated as a security vulnerability, please do not use the issue tracker or discuss it +in the public forum as it can cause more damage, rather than giving real help to the ecosystem. Security vulnerabilities should be reported by the [contact form](https://security-submission.parity.io/). -If you think that your report might be eligible for the Bug Bounty Program, please mark this during the submission. Please check up-to-date [Parity Bug Bounty Program rules](https://www.parity.io/bug-bounty) to find out the information about our Bug Bounty Program. - -**Warning**: This is an unified SECURITY.md file for Paritytech GitHub Organization. The presence of this file does not mean that this repository is covered by the Bug Bounty program. Please always check the Bug Bounty Program scope for information. +If you think that your report might be eligible for the Bug Bounty Program, please mark this during the submission. +Please check up-to-date [Parity Bug Bounty Program rules](https://www.parity.io/bug-bounty) to find out the information +about our Bug Bounty Program. +**Warning**: This is an unified SECURITY.md file for Paritytech GitHub Organization. The presence of this file does not +mean that this repository is covered by the Bug Bounty program. Please always check the Bug Bounty Program scope for +information. diff --git a/cumulus/bridges/docs/high-level-overview.md b/cumulus/bridges/docs/high-level-overview.md index 449224124af..42efc8100bd 100644 --- a/cumulus/bridges/docs/high-level-overview.md +++ b/cumulus/bridges/docs/high-level-overview.md @@ -1,83 +1,85 @@ # High-Level Bridge Documentation -This document gives a brief, abstract description of main components that may be found in this repository. -If you want to see how we're using them to build Rococo <> Wococo (Kusama <> Polkadot) bridge, please -refer to the [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md). +This document gives a brief, abstract description of main components that may be found in this repository. If you want +to see how we're using them to build Rococo <> Wococo (Kusama <> Polkadot) bridge, please refer to the [Polkadot <> +Kusama Bridge](./polkadot-kusama-bridge-overview.md). ## Purpose -This repo contains all components required to build a trustless connection between standalone Substrate chains, -that are using GRANDPA finality, their parachains or any combination of those. On top of this connection, we -offer a messaging pallet that provides means to organize messages exchange. +This repo contains all components required to build a trustless connection between standalone Substrate chains, that are +using GRANDPA finality, their parachains or any combination of those. On top of this connection, we offer a messaging +pallet that provides means to organize messages exchange. -On top of that layered infrastructure, anyone may build their own bridge applications - e.g. [XCM messaging](./polkadot-kusama-bridge-overview.md), -[encoded calls messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging) and so on. +On top of that layered infrastructure, anyone may build their own bridge applications - e.g. [XCM +messaging](./polkadot-kusama-bridge-overview.md), [encoded calls +messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging) and so on. ## Terminology -Even though we support (and require) two-way bridging, the documentation will generally talk about -a one-sided interaction. That's to say, we will only talk about syncing finality proofs and messages -from a _source_ chain to a _target_ chain. This is because the two-sided interaction is really just the -one-sided interaction with the source and target chains switched. +Even though we support (and require) two-way bridging, the documentation will generally talk about a one-sided +interaction. That's to say, we will only talk about syncing finality proofs and messages from a _source_ chain to a +_target_ chain. This is because the two-sided interaction is really just the one-sided interaction with the source and +target chains switched. The bridge has both on-chain (pallets) and offchain (relayers) components. ## On-chain components -On-chain bridge components are pallets that are deployed at the chain runtime. Finality pallets require -deployment at the target chain, while messages pallet needs to be deployed at both, source -and target chains. +On-chain bridge components are pallets that are deployed at the chain runtime. Finality pallets require deployment at +the target chain, while messages pallet needs to be deployed at both, source and target chains. ### Bridge GRANDPA Finality Pallet -A GRANDPA light client of the source chain built into the target chain's runtime. It provides a "source of truth" -about the source chain headers which have been finalized. This is useful for higher level applications. +A GRANDPA light client of the source chain built into the target chain's runtime. It provides a "source of truth" about +the source chain headers which have been finalized. This is useful for higher level applications. -The pallet tracks current GRANDPA authorities set and only accepts finality proofs (GRANDPA justifications), -generated by the current authorities set. The GRANDPA protocol itself requires current authorities set to -generate explicit justification for the header that enacts next authorities set. Such headers and their finality -proofs are called mandatory in the pallet and relayer pays no fee for such headers submission. +The pallet tracks current GRANDPA authorities set and only accepts finality proofs (GRANDPA justifications), generated +by the current authorities set. The GRANDPA protocol itself requires current authorities set to generate explicit +justification for the header that enacts next authorities set. Such headers and their finality proofs are called +mandatory in the pallet and relayer pays no fee for such headers submission. -The pallet does not require all headers to be imported or provided. The relayer itself chooses which headers -he wants to submit (with the exception of mandatory headers). +The pallet does not require all headers to be imported or provided. The relayer itself chooses which headers he wants to +submit (with the exception of mandatory headers). More: [pallet level documentation and code](../modules/grandpa/). ### Bridge Parachains Finality Pallet -Parachains are not supposed to have their own finality, so we can't use bridge GRANDPA pallet to verify their -finality proofs. Instead, they rely on their relay chain finality. The parachain header is considered final, -when it is accepted by the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras) -at its relay chain. Obviously, the relay chain block, where it is accepted, must also be finalized by the relay -chain GRANDPA gadget. +Parachains are not supposed to have their own finality, so we can't use bridge GRANDPA pallet to verify their finality +proofs. Instead, they rely on their relay chain finality. The parachain header is considered final, when it is accepted +by the [`paras` +pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras) +at its relay chain. Obviously, the relay chain block, where it is accepted, must also be finalized by the relay chain +GRANDPA gadget. That said, the bridge parachains pallet accepts storage proof of one or several parachain heads, inserted to the [`Heads`](https://github.com/paritytech/polkadot/blob/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras/mod.rs#L642) -map of the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras). +map of the [`paras` +pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras). To verify this storage proof, the pallet uses relay chain header, imported earlier by the bridge GRANDPA pallet. -The pallet may track multiple parachains at once and those parachains may use different primitives. So the -parachain header decoding never happens at the pallet level. For maintaining the headers order, the pallet -uses relay chain header number. +The pallet may track multiple parachains at once and those parachains may use different primitives. So the parachain +header decoding never happens at the pallet level. For maintaining the headers order, the pallet uses relay chain header +number. More: [pallet level documentation and code](../modules/parachains/). ### Bridge Messages Pallet -The pallet is responsible for queuing messages at the source chain and receiving the messages proofs at the -target chain. The messages are sent to the particular _lane_, where they are guaranteed to be received in the -same order they are sent. The pallet supports many lanes. +The pallet is responsible for queuing messages at the source chain and receiving the messages proofs at the target +chain. The messages are sent to the particular _lane_, where they are guaranteed to be received in the same order they +are sent. The pallet supports many lanes. -The lane has two ends. Outbound lane end is storing number of messages that have been sent and the number of -messages that have been received. Inbound lane end stores the number of messages that have been received and -also a map that maps messages to relayers that have delivered those messages to the target chain. +The lane has two ends. Outbound lane end is storing number of messages that have been sent and the number of messages +that have been received. Inbound lane end stores the number of messages that have been received and also a map that maps +messages to relayers that have delivered those messages to the target chain. The pallet has three main entrypoints: - the `send_message` may be used by the other runtime pallets to send the messages; -- the `receive_messages_proof` is responsible for parsing the messages proof and handing messages over to the -dispatch code; -- the `receive_messages_delivery_proof` is responsible for parsing the messages delivery proof and rewarding -relayers that have delivered the message. +- the `receive_messages_proof` is responsible for parsing the messages proof and handing messages over to the dispatch +code; +- the `receive_messages_delivery_proof` is responsible for parsing the messages delivery proof and rewarding relayers +that have delivered the message. Many things are abstracted by the pallet: - the message itself may mean anything, the pallet doesn't care about its content; @@ -85,97 +87,98 @@ Many things are abstracted by the pallet: - the messages proof and messages delivery proof are verified outside of the pallet; - the relayers incentivization scheme is defined outside of the pallet. -Outside of the messaging pallet, we have a set of adapters, where messages and delivery proofs are regular -storage proofs. The proofs are generated at the bridged chain and require bridged chain finality. So messages -pallet, in this case, depends on one of the finality pallets. The messages are XCM messages and we are using -XCM executor to dispatch them on receival. You may find more info in [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md) -document. +Outside of the messaging pallet, we have a set of adapters, where messages and delivery proofs are regular storage +proofs. The proofs are generated at the bridged chain and require bridged chain finality. So messages pallet, in this +case, depends on one of the finality pallets. The messages are XCM messages and we are using XCM executor to dispatch +them on receival. You may find more info in [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md) document. More: [pallet level documentation and code](../modules/messages/). ### Bridge Relayers Pallet -The pallet is quite simple. It just registers relayer rewards and has an entrypoint to collect them. When -the rewards are registered and the reward amount is configured outside of the pallet. +The pallet is quite simple. It just registers relayer rewards and has an entrypoint to collect them. When the rewards +are registered and the reward amount is configured outside of the pallet. More: [pallet level documentation and code](../modules/relayers/). ## Offchain Components -Offchain bridge components are separate processes, called relayers. Relayers are connected both to the -source chain and target chain nodes. Relayers are reading state of the source chain, compare it to the -state of the target chain and, if state at target chain needs to be updated, submits target chain -transaction. +Offchain bridge components are separate processes, called relayers. Relayers are connected both to the source chain and +target chain nodes. Relayers are reading state of the source chain, compare it to the state of the target chain and, if +state at target chain needs to be updated, submits target chain transaction. ### GRANDPA Finality Relay -The task of relay is to submit source chain GRANDPA justifications and their corresponding headers to -the Bridge GRANDPA Finality Pallet, deployed at the target chain. For that, the relay subscribes to -the source chain GRANDPA justifications stream and submits every new justification it sees to the -target chain GRANDPA light client. In addition, relay is searching for mandatory headers and -submits their justifications - without that the pallet will be unable to move forward. +The task of relay is to submit source chain GRANDPA justifications and their corresponding headers to the Bridge GRANDPA +Finality Pallet, deployed at the target chain. For that, the relay subscribes to the source chain GRANDPA justifications +stream and submits every new justification it sees to the target chain GRANDPA light client. In addition, relay is +searching for mandatory headers and submits their justifications - without that the pallet will be unable to move +forward. -More: [GRANDPA Finality Relay Sequence Diagram](./grandpa-finality-relay.html), [pallet level documentation and code](../relays/finality/). +More: [GRANDPA Finality Relay Sequence Diagram](./grandpa-finality-relay.html), [pallet level documentation and +code](../relays/finality/). ### Parachains Finality Relay -The relay connects to the source _relay_ chain and the target chain nodes. It doesn't need to connect to the -tracked parachain nodes. The relay looks at the [`Heads`](https://github.com/paritytech/polkadot/blob/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras/mod.rs#L642) -map of the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras) -in source chain, and compares the value with the best parachain head, stored in the bridge parachains pallet at -the target chain. If new parachain head appears at the relay chain block `B`, the relay process **waits** -until header `B` or one of its ancestors appears at the target chain. Once it is available, the storage -proof of the map entry is generated and is submitted to the target chain. +The relay connects to the source _relay_ chain and the target chain nodes. It doesn't need to connect to the tracked +parachain nodes. The relay looks at the +[`Heads`](https://github.com/paritytech/polkadot/blob/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras/mod.rs#L642) +map of the [`paras` +pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras) +in source chain, and compares the value with the best parachain head, stored in the bridge parachains pallet at the +target chain. If new parachain head appears at the relay chain block `B`, the relay process **waits** until header `B` +or one of its ancestors appears at the target chain. Once it is available, the storage proof of the map entry is +generated and is submitted to the target chain. -As its on-chain component (which requires bridge GRANDPA pallet to be deployed nearby), the parachains -finality relay requires GRANDPA finality relay to be running in parallel. Without it, the header `B` or -any of its children's finality at source won't be relayed at target, and target chain -won't be able to verify generated storage proof. +As its on-chain component (which requires bridge GRANDPA pallet to be deployed nearby), the parachains finality relay +requires GRANDPA finality relay to be running in parallel. Without it, the header `B` or any of its children's finality +at source won't be relayed at target, and target chain won't be able to verify generated storage proof. More: [Parachains Finality Relay Sequence Diagram](./parachains-finality-relay.html), [code](../relays/parachains/). ### Messages Relay -Messages relay is actually two relays that are running in a single process: messages delivery relay and -delivery confirmation relay. Even though they are more complex and have many caveats, the overall algorithm -is the same as in other relays. +Messages relay is actually two relays that are running in a single process: messages delivery relay and delivery +confirmation relay. Even though they are more complex and have many caveats, the overall algorithm is the same as in +other relays. -Message delivery relay connects to the source chain and looks at the outbound lane end, waiting until new -messages are queued there. Once they appear at the source block `B`, the relay start waiting for the block -`B` or its descendant appear at the target chain. Then the messages storage proof is generated and submitted -to the bridge messages pallet at the target chain. In addition, the transaction may include the storage proof -of the outbound lane state - that proves that relayer rewards have been paid and this data (map of relay -accounts to the delivered messages) may be pruned from the inbound lane state at the target chain. +Message delivery relay connects to the source chain and looks at the outbound lane end, waiting until new messages are +queued there. Once they appear at the source block `B`, the relay start waiting for the block `B` or its descendant +appear at the target chain. Then the messages storage proof is generated and submitted to the bridge messages pallet at +the target chain. In addition, the transaction may include the storage proof of the outbound lane state - that proves +that relayer rewards have been paid and this data (map of relay accounts to the delivered messages) may be pruned from +the inbound lane state at the target chain. -Delivery confirmation relay connects to the target chain and starts watching the inbound lane end. When new -messages are delivered to the target chain, the corresponding _source chain account_ is inserted to the -map in the inbound lane data. Relay detects that, say, at the target chain block `B` and waits until that -block or its descendant appears at the source chain. Once that happens, the relay crafts a storage proof of -that data and sends it to the messages pallet, deployed at the source chain. +Delivery confirmation relay connects to the target chain and starts watching the inbound lane end. When new messages are +delivered to the target chain, the corresponding _source chain account_ is inserted to the map in the inbound lane data. +Relay detects that, say, at the target chain block `B` and waits until that block or its descendant appears at the +source chain. Once that happens, the relay crafts a storage proof of that data and sends it to the messages pallet, +deployed at the source chain. -As you can see, the messages relay also requires finality relay to be operating in parallel. Since messages -relay submits transactions to both source and target chains, it requires both _source-to-target_ and -_target-to-source_ finality relays. They can be GRANDPA finality relays or GRANDPA+parachains finality relays, -depending on the type of connected chain. +As you can see, the messages relay also requires finality relay to be operating in parallel. Since messages relay +submits transactions to both source and target chains, it requires both _source-to-target_ and _target-to-source_ +finality relays. They can be GRANDPA finality relays or GRANDPA+parachains finality relays, depending on the type of +connected chain. -More: [Messages Relay Sequence Diagram](./messages-relay.html), [pallet level documentation and code](../relays/messages/). +More: [Messages Relay Sequence Diagram](./messages-relay.html), [pallet level documentation and +code](../relays/messages/). ### Complex Relay -Every relay transaction has its cost. The only transaction, that is "free" to relayer is when the mandatory -GRANDPA header is submitted. The relay that feeds the bridge with every relay chain and/or parachain head it -sees, will have to pay a (quite large) cost. And if no messages are sent through the bridge, that is just -waste of money. +Every relay transaction has its cost. The only transaction, that is "free" to relayer is when the mandatory GRANDPA +header is submitted. The relay that feeds the bridge with every relay chain and/or parachain head it sees, will have to +pay a (quite large) cost. And if no messages are sent through the bridge, that is just waste of money. -We have a special relay mode, called _complex relay_, where relay mostly sleeps and only submits transactions -that are required for the messages/confirmations delivery. This mode starts two message relays (in both -directions). All required finality relays are also started in a special _on-demand_ mode. In this mode they -do not submit any headers without special request. As always, the only exception is when GRANDPA finality -relay sees the mandatory header - it is submitted without such request. +We have a special relay mode, called _complex relay_, where relay mostly sleeps and only submits transactions that are +required for the messages/confirmations delivery. This mode starts two message relays (in both directions). All required +finality relays are also started in a special _on-demand_ mode. In this mode they do not submit any headers without +special request. As always, the only exception is when GRANDPA finality relay sees the mandatory header - it is +submitted without such request. -The message relays are watching their lanes and when, at some block `B`, they see new messages/confirmations -to be delivered, they are asking on-demand relays to relay this block `B`. On-demand relays does that and -then message relay may perform its job. If on-demand relay is a parachain finality relay, it also runs its -own on-demand GRANDPA relay, which is used to relay required relay chain headers. +The message relays are watching their lanes and when, at some block `B`, they see new messages/confirmations to be +delivered, they are asking on-demand relays to relay this block `B`. On-demand relays does that and then message relay +may perform its job. If on-demand relay is a parachain finality relay, it also runs its own on-demand GRANDPA relay, +which is used to relay required relay chain headers. -More: [Complex Relay Sequence Diagram](./complex-relay.html), [code](../relays/bin-substrate/src/cli/relay_headers_and_messages/). +More: [Complex Relay Sequence Diagram](./complex-relay.html), +[code](../relays/bin-substrate/src/cli/relay_headers_and_messages/). diff --git a/cumulus/bridges/docs/polkadot-kusama-bridge-overview.md b/cumulus/bridges/docs/polkadot-kusama-bridge-overview.md index b469720f65b..08036f0b072 100644 --- a/cumulus/bridges/docs/polkadot-kusama-bridge-overview.md +++ b/cumulus/bridges/docs/polkadot-kusama-bridge-overview.md @@ -1,35 +1,35 @@ # Polkadot <> Kusama Bridge Overview -This document describes how we use all components, described in the [High-Level Bridge Documentation](./high-level-overview.md), -to build the XCM bridge between Kusama and Polkadot. In this case, our components merely work as a XCM transport -(like XCMP/UMP/HRMP), between chains that are not a part of the same consensus system. +This document describes how we use all components, described in the [High-Level Bridge +Documentation](./high-level-overview.md), to build the XCM bridge between Kusama and Polkadot. In this case, our +components merely work as a XCM transport (like XCMP/UMP/HRMP), between chains that are not a part of the same consensus +system. The overall architecture may be seen in [this diagram](./polkadot-kusama-bridge.html). ## Bridge Hubs -All operations at relay chain are expensive. Ideally all non-mandatory transactions must happen on parachains. -That's why we are planning to have two parachains - Polkadot Bridge Hub under Polkadot consensus and Kusama -Bridge Hub under Kusama consensus. +All operations at relay chain are expensive. Ideally all non-mandatory transactions must happen on parachains. That's +why we are planning to have two parachains - Polkadot Bridge Hub under Polkadot consensus and Kusama Bridge Hub under +Kusama consensus. -The Bridge Hub will have all required bridge pallets in its runtime. We hope that later, other teams will be able to -use our bridge hubs too and have their pallets there. +The Bridge Hub will have all required bridge pallets in its runtime. We hope that later, other teams will be able to use +our bridge hubs too and have their pallets there. -The Bridge Hub will use the base token of the ecosystem - KSM at Kusama Bridge Hub and DOT at Polkadot Bridge Hub. -The runtime will have minimal set of non-bridge pallets, so there's not much you can do directly on bridge hubs. +The Bridge Hub will use the base token of the ecosystem - KSM at Kusama Bridge Hub and DOT at Polkadot Bridge Hub. The +runtime will have minimal set of non-bridge pallets, so there's not much you can do directly on bridge hubs. ## Connecting Parachains -You won't be able to directly use bridge hub transactions to send XCM messages over the bridge. Instead, you'll need -to use other parachains transactions, which will use HRMP to deliver messages to the Bridge Hub. The Bridge Hub will -just queue these messages in its outbound lane, which is dedicated to deliver messages between two parachains. +You won't be able to directly use bridge hub transactions to send XCM messages over the bridge. Instead, you'll need to +use other parachains transactions, which will use HRMP to deliver messages to the Bridge Hub. The Bridge Hub will just +queue these messages in its outbound lane, which is dedicated to deliver messages between two parachains. -Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two -parachains would allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama -accounts to hold wrapped DOT tokens. +Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two parachains would +allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama accounts to hold wrapped DOT tokens. -For that bridge (pair of parachains under different consensus systems) we'll be using the lane 00000000. Later, -when other parachains will join the bridge, they will be using other lanes for their messages. +For that bridge (pair of parachains under different consensus systems) we'll be using the lane 00000000. Later, when +other parachains will join the bridge, they will be using other lanes for their messages. ## Running Relayers @@ -38,9 +38,9 @@ justifications to the bridge hubs at the other side. It'll also relay finalized Hub heads. This will only happen when messages will be queued at hubs. So most of time relayer will be idle. There's no any active relayer sets, or something like that. Anyone may start its own relayer and relay queued messages. -We are not against that and, as always, appreciate any community efforts. Of course, running relayer has the cost. -Apart from paying for the CPU and network, the relayer pays for transactions at both sides of the bridge. We have -a mechanism for rewarding relayers. +We are not against that and, as always, appreciate any community efforts. Of course, running relayer has the cost. Apart +from paying for the CPU and network, the relayer pays for transactions at both sides of the bridge. We have a mechanism +for rewarding relayers. ### Compensating the Cost of Message Delivery Transactions @@ -56,51 +56,49 @@ is the relayer, which is following our rules: - we compensate the cost of message delivery transactions that have actually delivered the messages. So if your transaction has claimed to deliver messages `[42, 43, 44]`, but, because of some reasons, has actually delivered - messages `[42, 43]`, the transaction will be free for relayer. If it has not delivered any messages, then - the relayer pays the full cost of the transaction; + messages `[42, 43]`, the transaction will be free for relayer. If it has not delivered any messages, then the relayer + pays the full cost of the transaction; - we compensate the cost of message delivery and all required finality calls, if they are part of the same [`frame_utility::batch_all`](https://github.com/paritytech/substrate/blob/891d6a5c870ab88521183facafc811a203bb6541/frame/utility/src/lib.rs#L326) - transaction. Of course, the calls inside the batch must be linked - e.g. the submitted parachain head must be used - to prove messages. Relay header must be used to prove parachain head finality. If one of calls fails, or if they - are not linked together, the relayer pays the full transaction cost. + transaction. Of course, the calls inside the batch must be linked - e.g. the submitted parachain head must be used to + prove messages. Relay header must be used to prove parachain head finality. If one of calls fails, or if they are not + linked together, the relayer pays the full transaction cost. Please keep in mind that the fee of "zero-cost" transactions is still withdrawn from the relayer account. But the -compensation is registered in the `pallet_bridge_relayers::RelayerRewards` map at the target bridge hub. The relayer -may later claim all its rewards later, using the `pallet_bridge_relayers::claim_rewards` call. +compensation is registered in the `pallet_bridge_relayers::RelayerRewards` map at the target bridge hub. The relayer may +later claim all its rewards later, using the `pallet_bridge_relayers::claim_rewards` call. *A side note*: why we don't simply set the cost of useful transactions to zero? That's because the bridge has its cost. If we won't take any fees, it would mean that the sender is not obliged to pay for its messages. And Bridge Hub -collators (and, maybe, "treasury") are not receiving any payment for including transactions. More about this later, -in the [Who is Rewarding Relayers](#who-is-rewarding-relayers) section. +collators (and, maybe, "treasury") are not receiving any payment for including transactions. More about this later, in +the [Who is Rewarding Relayers](#who-is-rewarding-relayers) section. ### Message Delivery Confirmation Rewards In addition to the "zero-cost" message delivery transactions, the relayer is also rewarded for: -- delivering every message. The reward is registered during delivery confirmation transaction at the Source Bridge - Hub.; +- delivering every message. The reward is registered during delivery confirmation transaction at the Source Bridge Hub.; -- submitting delivery confirmation transaction. The relayer may submit delivery confirmation that e.g. confirms - delivery of four messages, of which the only one (or zero) messages is actually delivered by this relayer. It - receives some fee for confirming messages, delivered by other relayers. +- submitting delivery confirmation transaction. The relayer may submit delivery confirmation that e.g. confirms delivery + of four messages, of which the only one (or zero) messages is actually delivered by this relayer. It receives some fee + for confirming messages, delivered by other relayers. Both rewards may be claimed using the `pallet_bridge_relayers::claim_rewards` call at the Source Bridge Hub. ### Who is Rewarding Relayers Obviously, there should be someone who is paying relayer rewards. We want bridge transactions to have a cost, so we -can't use fees for rewards. Instead, the parachains using the bridge, use sovereign accounts on both sides -of the bridge to cover relayer rewards. +can't use fees for rewards. Instead, the parachains using the bridge, use sovereign accounts on both sides of the bridge +to cover relayer rewards. -Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will -have an account at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama -Bridge Hub. The sovereign accounts are used as a source of funds when the relayer is calling the -`pallet_bridge_relayers::claim_rewards`. +Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will have an account +at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama Bridge Hub. The sovereign accounts +are used as a source of funds when the relayer is calling the `pallet_bridge_relayers::claim_rewards`. -Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. -Kusama Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign account -is not used to cover rewards of bridging with some other Polkadot Parachain. +Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. Kusama +Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign +account is not used to cover rewards of bridging with some other Polkadot Parachain. ### Multiple Relayers and Rewards @@ -108,25 +106,24 @@ Our goal is to incentivize running honest relayers. But we have no relayers sets message delivery transaction, hoping that the cost of this transaction will be compensated. So what if some message is currently queued and two relayers are submitting two identical message delivery transactions at once? Without any special means, the cost of first included transaction will be compensated and the cost of the other one won't. A honest, -but unlucky relayer will lose some money. In addition, we'll waste some portion of block size and weight, which -may be used by other useful transactions. +but unlucky relayer will lose some money. In addition, we'll waste some portion of block size and weight, which may be +used by other useful transactions. -To solve the problem, we have two signed extensions ([generate_bridge_reject_obsolete_headers_and_messages! {}](../bin/runtime-common/src/lib.rs) -and [RefundRelayerForMessagesFromParachain](../bin/runtime-common/src/refund_relayer_extension.rs)), that are -preventing bridge transactions with obsolete data from including into the block. We are rejecting following -transactions: +To solve the problem, we have two signed extensions ([generate_bridge_reject_obsolete_headers_and_messages! +{}](../bin/runtime-common/src/lib.rs) and +[RefundRelayerForMessagesFromParachain](../bin/runtime-common/src/refund_relayer_extension.rs)), that are preventing +bridge transactions with obsolete data from including into the block. We are rejecting following transactions: - transactions, that are submitting the GRANDPA justification for the best finalized header, or one of its ancestors; - transactions, that are submitting the proof of the current best parachain head, or one of its ancestors; -- transactions, that are delivering already delivered messages. If at least one of messages is not yet delivered, - the transaction is not rejected; +- transactions, that are delivering already delivered messages. If at least one of messages is not yet delivered, the + transaction is not rejected; -- transactions, that are confirming delivery of already confirmed messages. If at least one of confirmations is new, - the transaction is not rejected; +- transactions, that are confirming delivery of already confirmed messages. If at least one of confirmations is new, the + transaction is not rejected; - [`frame_utility::batch_all`](https://github.com/paritytech/substrate/blob/891d6a5c870ab88521183facafc811a203bb6541/frame/utility/src/lib.rs#L326) - transactions, that have both finality and message delivery calls. All restrictions from the - [Compensating the Cost of Message Delivery Transactions](#compensating-the-cost-of-message-delivery-transactions) - are applied. + transactions, that have both finality and message delivery calls. All restrictions from the [Compensating the Cost of + Message Delivery Transactions](#compensating-the-cost-of-message-delivery-transactions) are applied. diff --git a/cumulus/bridges/modules/messages/README.md b/cumulus/bridges/modules/messages/README.md index b5250d0dca0..457d5f5facf 100644 --- a/cumulus/bridges/modules/messages/README.md +++ b/cumulus/bridges/modules/messages/README.md @@ -1,8 +1,7 @@ # Bridge Messages Pallet -The messages pallet is used to deliver messages from source chain to target chain. Message is -(almost) opaque to the module and the final goal is to hand message to the message dispatch -mechanism. +The messages pallet is used to deliver messages from source chain to target chain. Message is (almost) opaque to the +module and the final goal is to hand message to the message dispatch mechanism. ## Contents @@ -14,229 +13,203 @@ mechanism. ## Overview -Message lane is an unidirectional channel, where messages are sent from source chain to the target -chain. At the same time, a single instance of messages module supports both outbound lanes and -inbound lanes. So the chain where the module is deployed (this chain), may act as a source chain for -outbound messages (heading to a bridged chain) and as a target chain for inbound messages (coming -from a bridged chain). +Message lane is an unidirectional channel, where messages are sent from source chain to the target chain. At the same +time, a single instance of messages module supports both outbound lanes and inbound lanes. So the chain where the module +is deployed (this chain), may act as a source chain for outbound messages (heading to a bridged chain) and as a target +chain for inbound messages (coming from a bridged chain). -Messages module supports multiple message lanes. Every message lane is identified with a 4-byte -identifier. Messages sent through the lane are assigned unique (for this lane) increasing integer -value that is known as nonce ("number that can only be used once"). Messages that are sent over the -same lane are guaranteed to be delivered to the target chain in the same order they're sent from -the source chain. In other words, message with nonce `N` will be delivered right before delivering a -message with nonce `N+1`. +Messages module supports multiple message lanes. Every message lane is identified with a 4-byte identifier. Messages +sent through the lane are assigned unique (for this lane) increasing integer value that is known as nonce ("number that +can only be used once"). Messages that are sent over the same lane are guaranteed to be delivered to the target chain in +the same order they're sent from the source chain. In other words, message with nonce `N` will be delivered right before +delivering a message with nonce `N+1`. -Single message lane may be seen as a transport channel for single application (onchain, offchain or -mixed). At the same time the module itself never dictates any lane or message rules. In the end, it -is the runtime developer who defines what message lane and message mean for this runtime. +Single message lane may be seen as a transport channel for single application (onchain, offchain or mixed). At the same +time the module itself never dictates any lane or message rules. In the end, it is the runtime developer who defines +what message lane and message mean for this runtime. -In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane -as a channel of communication between two parachains of different relay chains. For example, lane -`[0, 0, 0, 0]` is used for Polkadot <> Kusama Asset Hub communications. Other lanes may be used to -bridge other parachains. +In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane as a channel of +communication between two parachains of different relay chains. For example, lane `[0, 0, 0, 0]` is used for Polkadot <> +Kusama Asset Hub communications. Other lanes may be used to bridge other parachains. ## Message Workflow -The pallet is not intended to be used by end users and provides no public calls to send the message. -Instead, it provides runtime-internal method that allows other pallets (or other runtime code) to queue -outbound messages. - -The message "appears" when some runtime code calls the `send_message()` method of the pallet. -The submitter specifies the lane that they're willing to use and the message itself. If some fee must -be paid for sending the message, it must be paid outside of the pallet. If a message passes all checks -(that include, for example, message size check, disabled lane check, ...), the nonce is assigned and -the message is stored in the module storage. The message is in an "undelivered" state now. - -We assume that there are external, offchain actors, called relayers, that are submitting module -related transactions to both target and source chains. The pallet itself has no assumptions about -relayers incentivization scheme, but it has some callbacks for paying rewards. See -[Integrating Messages Module into runtime](#Integrating-Messages-Module-into-runtime) -for details. - -Eventually, some relayer would notice this message in the "undelivered" state and it would decide to -deliver this message. Relayer then crafts `receive_messages_proof()` transaction (aka delivery -transaction) for the messages module instance, deployed at the target chain. Relayer provides -its account id at the source chain, the proof of message (or several messages), the number of -messages in the transaction and their cumulative dispatch weight. Once a transaction is mined, the -message is considered "delivered". - -Once a message is delivered, the relayer may want to confirm delivery back to the source chain. -There are two reasons why it would want to do that. The first is that we intentionally limit number -of "delivered", but not yet "confirmed" messages at inbound lanes -(see [What about other Constants in the Messages Module Configuration Trait](#What-about-other-Constants-in-the-Messages-Module-Configuration-Trait) for explanation). -So at some point, the target chain may stop accepting new messages until relayers confirm some of -these. The second is that if the relayer wants to be rewarded for delivery, it must prove the fact -that it has actually delivered the message. And this proof may only be generated after the delivery -transaction is mined. So relayer crafts the `receive_messages_delivery_proof()` transaction (aka -confirmation transaction) for the messages module instance, deployed at the source chain. Once -this transaction is mined, the message is considered "confirmed". - -The "confirmed" state is the final state of the message. But there's one last thing related to the -message - the fact that it is now "confirmed" and reward has been paid to the relayer (or at least -callback for this has been called), must be confirmed to the target chain. Otherwise, we may reach -the limit of "unconfirmed" messages at the target chain and it will stop accepting new messages. So -relayer sometimes includes a nonce of the latest "confirmed" message in the next +The pallet is not intended to be used by end users and provides no public calls to send the message. Instead, it +provides runtime-internal method that allows other pallets (or other runtime code) to queue outbound messages. + +The message "appears" when some runtime code calls the `send_message()` method of the pallet. The submitter specifies +the lane that they're willing to use and the message itself. If some fee must be paid for sending the message, it must +be paid outside of the pallet. If a message passes all checks (that include, for example, message size check, disabled +lane check, ...), the nonce is assigned and the message is stored in the module storage. The message is in an +"undelivered" state now. + +We assume that there are external, offchain actors, called relayers, that are submitting module related transactions to +both target and source chains. The pallet itself has no assumptions about relayers incentivization scheme, but it has +some callbacks for paying rewards. See [Integrating Messages Module into +runtime](#Integrating-Messages-Module-into-runtime) for details. + +Eventually, some relayer would notice this message in the "undelivered" state and it would decide to deliver this +message. Relayer then crafts `receive_messages_proof()` transaction (aka delivery transaction) for the messages module +instance, deployed at the target chain. Relayer provides its account id at the source chain, the proof of message (or +several messages), the number of messages in the transaction and their cumulative dispatch weight. Once a transaction is +mined, the message is considered "delivered". + +Once a message is delivered, the relayer may want to confirm delivery back to the source chain. There are two reasons +why it would want to do that. The first is that we intentionally limit number of "delivered", but not yet "confirmed" +messages at inbound lanes (see [What about other Constants in the Messages Module Configuration +Trait](#What-about-other-Constants-in-the-Messages-Module-Configuration-Trait) for explanation). So at some point, the +target chain may stop accepting new messages until relayers confirm some of these. The second is that if the relayer +wants to be rewarded for delivery, it must prove the fact that it has actually delivered the message. And this proof may +only be generated after the delivery transaction is mined. So relayer crafts the `receive_messages_delivery_proof()` +transaction (aka confirmation transaction) for the messages module instance, deployed at the source chain. Once this +transaction is mined, the message is considered "confirmed". + +The "confirmed" state is the final state of the message. But there's one last thing related to the message - the fact +that it is now "confirmed" and reward has been paid to the relayer (or at least callback for this has been called), must +be confirmed to the target chain. Otherwise, we may reach the limit of "unconfirmed" messages at the target chain and it +will stop accepting new messages. So relayer sometimes includes a nonce of the latest "confirmed" message in the next `receive_messages_proof()` transaction, proving that some messages have been confirmed. ## Integrating Messages Module into Runtime -As it has been said above, the messages module supports both outbound and inbound message lanes. -So if we will integrate a module in some runtime, it may act as the source chain runtime for -outbound messages and as the target chain runtime for inbound messages. In this section, we'll -sometimes refer to the chain we're currently integrating with, as "this chain" and the other -chain as "bridged chain". - -Messages module doesn't simply accept transactions that are claiming that the bridged chain has -some updated data for us. Instead of this, the module assumes that the bridged chain is able to -prove that updated data in some way. The proof is abstracted from the module and may be of any kind. -In our Substrate-to-Substrate bridge we're using runtime storage proofs. Other bridges may use -transaction proofs, Substrate header digests or anything else that may be proved. - -**IMPORTANT NOTE**: everything below in this chapter describes details of the messages module -configuration. But if you're interested in well-probed and relatively easy integration of two -Substrate-based chains, you may want to look at the -[bridge-runtime-common](../../bin/runtime-common/) crate. This crate is providing a lot of -helpers for integration, which may be directly used from within your runtime. Then if you'll decide -to change something in this scheme, get back here for detailed information. +As it has been said above, the messages module supports both outbound and inbound message lanes. So if we will integrate +a module in some runtime, it may act as the source chain runtime for outbound messages and as the target chain runtime +for inbound messages. In this section, we'll sometimes refer to the chain we're currently integrating with, as "this +chain" and the other chain as "bridged chain". + +Messages module doesn't simply accept transactions that are claiming that the bridged chain has some updated data for +us. Instead of this, the module assumes that the bridged chain is able to prove that updated data in some way. The proof +is abstracted from the module and may be of any kind. In our Substrate-to-Substrate bridge we're using runtime storage +proofs. Other bridges may use transaction proofs, Substrate header digests or anything else that may be proved. + +**IMPORTANT NOTE**: everything below in this chapter describes details of the messages module configuration. But if +you're interested in well-probed and relatively easy integration of two Substrate-based chains, you may want to look at +the [bridge-runtime-common](../../bin/runtime-common/) crate. This crate is providing a lot of helpers for integration, +which may be directly used from within your runtime. Then if you'll decide to change something in this scheme, get back +here for detailed information. ### General Information -The messages module supports instances. Every module instance is supposed to bridge this chain -and some bridged chain. To bridge with another chain, using another instance is suggested (this -isn't forced anywhere in the code, though). Keep in mind, that the pallet may be used to build -virtual channels between multiple chains, as we do in our [Polkadot <> Kusama bridge](../../docs/polkadot-kusama-bridge-overview.md). -There, the pallet actually bridges only two parachains - Kusama Bridge Hub and Polkadot -Bridge Hub. However, other Kusama and Polkadot parachains are able to send (XCM) messages to their -Bridge Hubs. The messages will be delivered to the other side of the bridge and routed to the proper +The messages module supports instances. Every module instance is supposed to bridge this chain and some bridged chain. +To bridge with another chain, using another instance is suggested (this isn't forced anywhere in the code, though). Keep +in mind, that the pallet may be used to build virtual channels between multiple chains, as we do in our [Polkadot <> +Kusama bridge](../../docs/polkadot-kusama-bridge-overview.md). There, the pallet actually bridges only two parachains - +Kusama Bridge Hub and Polkadot Bridge Hub. However, other Kusama and Polkadot parachains are able to send (XCM) messages +to their Bridge Hubs. The messages will be delivered to the other side of the bridge and routed to the proper destination parachain within the bridged chain consensus. -Message submitters may track message progress by inspecting module events. When Message is accepted, -the `MessageAccepted` event is emitted. The event contains both message lane identifier and nonce that -has been assigned to the message. When a message is delivered to the target chain, the `MessagesDelivered` -event is emitted from the `receive_messages_delivery_proof()` transaction. The `MessagesDelivered` contains -the message lane identifier and inclusive range of delivered message nonces. +Message submitters may track message progress by inspecting module events. When Message is accepted, the +`MessageAccepted` event is emitted. The event contains both message lane identifier and nonce that has been assigned to +the message. When a message is delivered to the target chain, the `MessagesDelivered` event is emitted from the +`receive_messages_delivery_proof()` transaction. The `MessagesDelivered` contains the message lane identifier and +inclusive range of delivered message nonces. -The pallet provides no means to get the result of message dispatch at the target chain. If that is -required, it must be done outside of the pallet. For example, XCM messages, when dispatched, have -special instructions to send some data back to the sender. Other dispatchers may use similar -mechanism for that. +The pallet provides no means to get the result of message dispatch at the target chain. If that is required, it must be +done outside of the pallet. For example, XCM messages, when dispatched, have special instructions to send some data back +to the sender. Other dispatchers may use similar mechanism for that. ### How to plug-in Messages Module to Send Messages to the Bridged Chain? -The `pallet_bridge_messages::Config` trait has 3 main associated types that are used to work with -outbound messages. The `pallet_bridge_messages::Config::TargetHeaderChain` defines how we see the -bridged chain as the target for our outbound messages. It must be able to check that the bridged -chain may accept our message - like that the message has size below maximal possible transaction -size of the chain and so on. And when the relayer sends us a confirmation transaction, this -implementation must be able to parse and verify the proof of messages delivery. Normally, you would -reuse the same (configurable) type on all chains that are sending messages to the same bridged -chain. - -The `pallet_bridge_messages::Config::LaneMessageVerifier` defines a single callback to verify outbound -messages. The simplest callback may just accept all messages. But in this case you'll need to answer -many questions first. Who will pay for the delivery and confirmation transaction? Are we sure that -someone will ever deliver this message to the bridged chain? Are we sure that we don't bloat our -runtime storage by accepting this message? What if the message is improperly encoded or has some -fields set to invalid values? Answering all those (and similar) questions would lead to correct -implementation. +The `pallet_bridge_messages::Config` trait has 3 main associated types that are used to work with outbound messages. The +`pallet_bridge_messages::Config::TargetHeaderChain` defines how we see the bridged chain as the target for our outbound +messages. It must be able to check that the bridged chain may accept our message - like that the message has size below +maximal possible transaction size of the chain and so on. And when the relayer sends us a confirmation transaction, this +implementation must be able to parse and verify the proof of messages delivery. Normally, you would reuse the same +(configurable) type on all chains that are sending messages to the same bridged chain. + +The `pallet_bridge_messages::Config::LaneMessageVerifier` defines a single callback to verify outbound messages. The +simplest callback may just accept all messages. But in this case you'll need to answer many questions first. Who will +pay for the delivery and confirmation transaction? Are we sure that someone will ever deliver this message to the +bridged chain? Are we sure that we don't bloat our runtime storage by accepting this message? What if the message is +improperly encoded or has some fields set to invalid values? Answering all those (and similar) questions would lead to +correct implementation. There's another thing to consider when implementing type for use in -`pallet_bridge_messages::Config::LaneMessageVerifier`. It is whether we treat all message lanes -identically, or they'll have different sets of verification rules? For example, you may reserve -lane#1 for messages coming from some 'wrapped-token' pallet - then you may verify in your -implementation that the origin is associated with this pallet. Lane#2 may be reserved for 'system' -messages and you may charge zero fee for such messages. You may have some rate limiting for messages -sent over the lane#3. Or you may just verify the same rules set for all outbound messages - it is +`pallet_bridge_messages::Config::LaneMessageVerifier`. It is whether we treat all message lanes identically, or they'll +have different sets of verification rules? For example, you may reserve lane#1 for messages coming from some +'wrapped-token' pallet - then you may verify in your implementation that the origin is associated with this pallet. +Lane#2 may be reserved for 'system' messages and you may charge zero fee for such messages. You may have some rate +limiting for messages sent over the lane#3. Or you may just verify the same rules set for all outbound messages - it is all up to the `pallet_bridge_messages::Config::LaneMessageVerifier` implementation. -The last type is the `pallet_bridge_messages::Config::DeliveryConfirmationPayments`. When confirmation -transaction is received, we call the `pay_reward()` method, passing the range of delivered messages. -You may use the [`pallet-bridge-relayers`](../relayers/) pallet and its -[`DeliveryConfirmationPaymentsAdapter`](../relayers/src/payment_adapter.rs) adapter as a possible -implementation. It allows you to pay fixed reward for relaying the message and some of its portion -for confirming delivery. +The last type is the `pallet_bridge_messages::Config::DeliveryConfirmationPayments`. When confirmation transaction is +received, we call the `pay_reward()` method, passing the range of delivered messages. You may use the +[`pallet-bridge-relayers`](../relayers/) pallet and its +[`DeliveryConfirmationPaymentsAdapter`](../relayers/src/payment_adapter.rs) adapter as a possible implementation. It +allows you to pay fixed reward for relaying the message and some of its portion for confirming delivery. ### I have a Messages Module in my Runtime, but I Want to Reject all Outbound Messages. What shall I do? You should be looking at the `bp_messages::source_chain::ForbidOutboundMessages` structure -[`bp_messages::source_chain`](../../primitives/messages/src/source_chain.rs). It implements -all required traits and will simply reject all transactions, related to outbound messages. +[`bp_messages::source_chain`](../../primitives/messages/src/source_chain.rs). It implements all required traits and will +simply reject all transactions, related to outbound messages. ### How to plug-in Messages Module to Receive Messages from the Bridged Chain? -The `pallet_bridge_messages::Config` trait has 2 main associated types that are used to work with -inbound messages. The `pallet_bridge_messages::Config::SourceHeaderChain` defines how we see the -bridged chain as the source of our inbound messages. When relayer sends us a delivery transaction, -this implementation must be able to parse and verify the proof of messages wrapped in this -transaction. Normally, you would reuse the same (configurable) type on all chains that are sending -messages to the same bridged chain. +The `pallet_bridge_messages::Config` trait has 2 main associated types that are used to work with inbound messages. The +`pallet_bridge_messages::Config::SourceHeaderChain` defines how we see the bridged chain as the source of our inbound +messages. When relayer sends us a delivery transaction, this implementation must be able to parse and verify the proof +of messages wrapped in this transaction. Normally, you would reuse the same (configurable) type on all chains that are +sending messages to the same bridged chain. -The `pallet_bridge_messages::Config::MessageDispatch` defines a way on how to dispatch delivered -messages. Apart from actually dispatching the message, the implementation must return the correct -dispatch weight of the message before dispatch is called. +The `pallet_bridge_messages::Config::MessageDispatch` defines a way on how to dispatch delivered messages. Apart from +actually dispatching the message, the implementation must return the correct dispatch weight of the message before +dispatch is called. ### I have a Messages Module in my Runtime, but I Want to Reject all Inbound Messages. What shall I do? -You should be looking at the `bp_messages::target_chain::ForbidInboundMessages` structure from -the [`bp_messages::target_chain`](../../primitives/messages/src/target_chain.rs) module. It -implements all required traits and will simply reject all transactions, related to inbound messages. +You should be looking at the `bp_messages::target_chain::ForbidInboundMessages` structure from the +[`bp_messages::target_chain`](../../primitives/messages/src/target_chain.rs) module. It implements all required traits +and will simply reject all transactions, related to inbound messages. ### What about other Constants in the Messages Module Configuration Trait? Two settings that are used to check messages in the `send_message()` function. The -`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that -may be used to send messages. All messages sent using other lanes are rejected. All messages that have -size above `pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. - -To be able to reward the relayer for delivering messages, we store a map of message nonces range => -identifier of the relayer that has delivered this range at the target chain runtime storage. If a -relayer delivers multiple consequent ranges, they're merged into single entry. So there may be more -than one entry for the same relayer. Eventually, this whole map must be delivered back to the source -chain to confirm delivery and pay rewards. So to make sure we are able to craft this confirmation -transaction, we need to: (1) keep the size of this map below a certain limit and (2) make sure that -the weight of processing this map is below a certain limit. Both size and processing weight mostly -depend on the number of entries. The number of entries is limited with the -`pallet_bridge_messages::ConfigMaxUnrewardedRelayerEntriesAtInboundLane` parameter. Processing weight -also depends on the total number of messages that are being confirmed, because every confirmed -message needs to be read. So there's another -`pallet_bridge_messages::Config::MaxUnconfirmedMessagesAtInboundLane` parameter for that. - -When choosing values for these parameters, you must also keep in mind that if proof in your scheme -is based on finality of headers (and it is the most obvious option for Substrate-based chains with -finality notion), then choosing too small values for these parameters may cause significant delays -in message delivery. That's because there are too many actors involved in this scheme: 1) authorities -that are finalizing headers of the target chain need to finalize header with non-empty map; 2) the -headers relayer then needs to submit this header and its finality proof to the source chain; 3) the -messages relayer must then send confirmation transaction (storage proof of this map) to the source -chain; 4) when the confirmation transaction will be mined at some header, source chain authorities -must finalize this header; 5) the headers relay then needs to submit this header and its finality -proof to the target chain; 6) only now the messages relayer may submit new messages from the source -to target chain and prune the entry from the map. - -Delivery transaction requires the relayer to provide both number of entries and total number of -messages in the map. This means that the module never charges an extra cost for delivering a map - -the relayer would need to pay exactly for the number of entries+messages it has delivered. So the -best guess for values of these parameters would be the pair that would occupy `N` percent of the -maximal transaction size and weight of the source chain. The `N` should be large enough to process -large maps, at the same time keeping reserve for future source chain upgrades. +`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that may be used to send +messages. All messages sent using other lanes are rejected. All messages that have size above +`pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. + +To be able to reward the relayer for delivering messages, we store a map of message nonces range => identifier of the +relayer that has delivered this range at the target chain runtime storage. If a relayer delivers multiple consequent +ranges, they're merged into single entry. So there may be more than one entry for the same relayer. Eventually, this +whole map must be delivered back to the source chain to confirm delivery and pay rewards. So to make sure we are able to +craft this confirmation transaction, we need to: (1) keep the size of this map below a certain limit and (2) make sure +that the weight of processing this map is below a certain limit. Both size and processing weight mostly depend on the +number of entries. The number of entries is limited with the +`pallet_bridge_messages::ConfigMaxUnrewardedRelayerEntriesAtInboundLane` parameter. Processing weight also depends on +the total number of messages that are being confirmed, because every confirmed message needs to be read. So there's +another `pallet_bridge_messages::Config::MaxUnconfirmedMessagesAtInboundLane` parameter for that. + +When choosing values for these parameters, you must also keep in mind that if proof in your scheme is based on finality +of headers (and it is the most obvious option for Substrate-based chains with finality notion), then choosing too small +values for these parameters may cause significant delays in message delivery. That's because there are too many actors +involved in this scheme: 1) authorities that are finalizing headers of the target chain need to finalize header with +non-empty map; 2) the headers relayer then needs to submit this header and its finality proof to the source chain; 3) +the messages relayer must then send confirmation transaction (storage proof of this map) to the source chain; 4) when +the confirmation transaction will be mined at some header, source chain authorities must finalize this header; 5) the +headers relay then needs to submit this header and its finality proof to the target chain; 6) only now the messages +relayer may submit new messages from the source to target chain and prune the entry from the map. + +Delivery transaction requires the relayer to provide both number of entries and total number of messages in the map. +This means that the module never charges an extra cost for delivering a map - the relayer would need to pay exactly for +the number of entries+messages it has delivered. So the best guess for values of these parameters would be the pair that +would occupy `N` percent of the maximal transaction size and weight of the source chain. The `N` should be large enough +to process large maps, at the same time keeping reserve for future source chain upgrades. ## Non-Essential Functionality -There may be a special account in every runtime where the messages module is deployed. This -account, named 'module owner', is like a module-level sudo account - he's able to halt and -resume all module operations without requiring runtime upgrade. Calls that are related to this -account are: +There may be a special account in every runtime where the messages module is deployed. This account, named 'module +owner', is like a module-level sudo account - he's able to halt and resume all module operations without requiring +runtime upgrade. Calls that are related to this account are: - `fn set_owner()`: current module owner may call it to transfer "ownership" to another account; -- `fn halt_operations()`: the module owner (or sudo account) may call this function to stop all - module operations. After this call, all message-related transactions will be rejected until - further `resume_operations` call'. This call may be used when something extraordinary happens with - the bridge; -- `fn resume_operations()`: module owner may call this function to resume bridge operations. The - module will resume its regular operations after this call. +- `fn halt_operations()`: the module owner (or sudo account) may call this function to stop all module operations. After + this call, all message-related transactions will be rejected until further `resume_operations` call'. This call may be + used when something extraordinary happens with the bridge; +- `fn resume_operations()`: module owner may call this function to resume bridge operations. The module will resume its + regular operations after this call. If pallet owner is not defined, the governance may be used to make those calls. ## Messages Relay -We have an offchain actor, who is watching for new messages and submits them to the bridged chain. -It is the messages relay - you may look at the [crate level documentation and the code](../../relays/messages/). +We have an offchain actor, who is watching for new messages and submits them to the bridged chain. It is the messages +relay - you may look at the [crate level documentation and the code](../../relays/messages/). diff --git a/cumulus/bridges/modules/parachains/README.md b/cumulus/bridges/modules/parachains/README.md index 5982c65ad31..d3f52c791ab 100644 --- a/cumulus/bridges/modules/parachains/README.md +++ b/cumulus/bridges/modules/parachains/README.md @@ -19,7 +19,7 @@ validators. Validators validate the block and register the new parachain head in [`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, 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. +even though the names are similar. And what the bridge parachains pallet does, is simply verifying storage proofs of parachain heads within that `Heads` map. It does that using relay chain header, that has been previously imported by the diff --git a/cumulus/docs/container.md b/cumulus/docs/container.md index 63575f37a59..ef7c52a44fa 100644 --- a/cumulus/docs/container.md +++ b/cumulus/docs/container.md @@ -1,19 +1,22 @@ -## Using Containers +# Using Containers -Using containers via **Podman** or **Docker** brings benefit, whether it is to build a container image or -run a node while keeping a minimum footprint on your local system. +Using containers via **Podman** or **Docker** brings benefit, whether it is to build a container image or run a node +while keeping a minimum footprint on your local system. -This document mentions using `podman` or `docker`. Those are usually interchangeable and it is encouraged using preferably **Podman**. If you have podman installed and want to use all the commands mentioned below, you can simply create an alias with `alias docker=podman`. +This document mentions using `podman` or `docker`. Those are usually interchangeable and it is encouraged using +preferably **Podman**. If you have podman installed and want to use all the commands mentioned below, you can simply +create an alias with `alias docker=podman`. There are a few options to build a node within a container and inject a binary inside an image. -### Parity built container image +## Parity built container image Parity builds and publishes a container image that can be found as `docker.io/parity/polkadot-parachain`. -### Parity CI image +## Parity CI image -Parity maintains and uses internally a generic "CI" image that can be used as a base to build binaries: [Parity CI container image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux): +Parity maintains and uses internally a generic "CI" image that can be used as a base to build binaries: [Parity CI +container image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux): The command below allows building a Linux binary without having to even install Rust or any dependency locally: @@ -29,19 +32,22 @@ sudo chown -R $(id -u):$(id -g) target/ If you want to reproduce other steps of CI process you can use the following [guide](https://github.com/paritytech/scripts#gitlab-ci-for-building-docker-images). -### Injected image +## Injected image -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. +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 following command allows producing a new container image where the compiled binary is injected: +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 ``` -### Container build +## Container build -Alternatively, you can build an image with a builder pattern. This options takes a while but offers a simple method for anyone to get a working container image without requiring any of the Rust toolchain installed locally. +Alternatively, you can build an image with a builder pattern. This options takes a while but offers a simple method for +anyone to get a working container image without requiring any of the Rust toolchain installed locally. ```bash docker build \ diff --git a/cumulus/docs/release.md b/cumulus/docs/release.md index b04c4e844c4..38d1915013b 100644 --- a/cumulus/docs/release.md +++ b/cumulus/docs/release.md @@ -37,8 +37,8 @@ performed during the release process. ### Burn In -Ensure that Parity DevOps has run the new release on Westend and Kusama Asset Hub collators for 12h -prior to publishing the release. +Ensure that Parity DevOps has run the new release on Westend and Kusama Asset Hub collators for 12h prior to publishing +the release. ### Build Artifacts @@ -75,56 +75,61 @@ function of the appropriate pallets. ### Extrinsic Ordering & Storage -Offline signing libraries depend on a consistent ordering of call indices and -functions. Compare the metadata of the 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`. +Offline signing libraries depend on a consistent ordering of call indices and functions. Compare the metadata of the +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/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 run it, in the _Run Workflow_ dropdown: 1. **Use workflow from**: to ignore, leave `master` as default -2. **The WebSocket url of the reference node**: - - Asset Hub Polkadot: `wss://statemint-rpc.polkadot.io` +2. **The WebSocket url of the reference node**: - Asset Hub Polkadot: `wss://statemint-rpc.polkadot.io` - Asset Hub Kusama: `wss://statemine-rpc.polkadot.io` - Asset Hub Westend: `wss://westmint-rpc.polkadot.io` -3. **A url to a Linux binary for the node containing the runtime to test**: Paste the URL of the latest release-candidate binary from the draft-release on Github. The binary has to previously be uploaded to S3 (Github url link to the binary is constantly changing) +3. **A url to a Linux binary for the node containing the runtime to test**: Paste the URL of the latest + release-candidate binary from the draft-release on Github. The binary has to previously be uploaded to S3 (Github url + link to the binary is constantly changing) - E.g: https://releases.parity.io/cumulus/v0.9.270-rc3/polkadot-parachain -4. **The name of the chain under test. Usually, you would pass a local chain**: - - Asset Hub Polkadot: `asset-hub-polkadot-local` +4. **The name of the chain under test. Usually, you would pass a local chain**: - Asset Hub Polkadot: + `asset-hub-polkadot-local` - Asset Hub Kusama: `asset-hub-kusama-local` - Asset Hub Westend: `asset-hub-westend-local` 5. Click **Run workflow** -When the workflow is done, click on it and download the zip artifact, inside you'll find an `output.txt` file. The things to look for in the output are lines like: +When the workflow is done, click on it and download the zip artifact, inside you'll find an `output.txt` file. The +things to look for in the output are lines like: - `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for Identity has changed - `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. - If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` -**Note**: Adding new functions to the runtime does not constitute a breaking change -as long as the indexes did not change. +**Note**: Adding new functions to the runtime does not constitute a breaking change as long as the indexes did not +change. -**Note**: Extrinsic function signatures changes (adding/removing & ordering arguments) are not caught by the job, so those changes should be reviewed "manually" +**Note**: Extrinsic function signatures changes (adding/removing & ordering arguments) are not caught by the job, so +those changes should be reviewed "manually" ### Benchmarks -The Benchmarks can now be started from the CI. First find the CI pipeline from [here](https://gitlab.parity.io/parity/mirrors/cumulus/-/pipelines?page=1&scope=all&ref=release-parachains-v9220) and pick the latest. -[Guide](https://github.com/paritytech/ci_cd/wiki/Benchmarks:-cumulus) +The Benchmarks can now be started from the CI. First find the CI pipeline from +[here](https://gitlab.parity.io/parity/mirrors/cumulus/-/pipelines?page=1&scope=all&ref=release-parachains-v9220) and +pick the latest. [Guide](https://github.com/paritytech/ci_cd/wiki/Benchmarks:-cumulus) ### Integration Tests Until https://github.com/paritytech/ci_cd/issues/499 is done, tests will have to be run manually. -1. Go to https://github.com/paritytech/parachains-integration-tests and check out the release branch. -E.g. https://github.com/paritytech/parachains-integration-tests/tree/release-v9270-v0.9.27 -for `release-parachains-v0.9.270` +1. Go to https://github.com/paritytech/parachains-integration-tests and check out the release branch. E.g. +https://github.com/paritytech/parachains-integration-tests/tree/release-v9270-v0.9.27 for `release-parachains-v0.9.270` 2. Clone `release-parachains-` branch from Cumulus 3. `cargo build --release` 4. Copy `./target/polkadot-parachain` to `./bin` -5. Clone `it/release--fast-sudo` from Polkadot -In case the branch does not exists (it is a manual process): cherry pick paritytech/polkadot@791c8b8 and run -`find . -type f -name "*.toml" -print0 | xargs -0 sed -i '' -e 's/polkadot-vX.X.X/polkadot-v/g'` +5. Clone `it/release--fast-sudo` from Polkadot In case the branch does not exists (it is a manual process): + cherry pick `paritytech/polkadot@791c8b8` and run: + `find . -type f -name "*.toml" -print0 | xargs -0 sed -i '' -e 's/polkadot-vX.X.X/polkadot-v/g'` 6. `cargo build --release --features fast-runtime` 7. Copy `./target/polkadot` into `./bin` (in Cumulus) 8. Run the tests: - - Asset Hub Polkadot: `yarn zombienet-test -c ./examples/statemint/config.toml -t ./examples/statemint` - - Asset Hub Kusama: `yarn zombienet-test -c ./examples/statemine/config.toml -t ./examples/statemine` + - Asset Hub Polkadot: `yarn zombienet-test -c ./examples/statemint/config.toml -t ./examples/statemint` + - Asset Hub Kusama: `yarn zombienet-test -c ./examples/statemine/config.toml -t ./examples/statemine` diff --git a/cumulus/pallets/collator-selection/README.md b/cumulus/pallets/collator-selection/README.md index 9718db58b37..811207fd8c0 100644 --- a/cumulus/pallets/collator-selection/README.md +++ b/cumulus/pallets/collator-selection/README.md @@ -1 +1 @@ -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/cumulus/parachain-template/README.md b/cumulus/parachain-template/README.md index 6dcc70c5382..2d71bbd71f3 100644 --- a/cumulus/parachain-template/README.md +++ b/cumulus/parachain-template/README.md @@ -19,4 +19,4 @@ parathreads [here](https://wiki.polkadot.network/docs/learn-parathreads). 🧙 Learn about how to use this template and run your own parachain testnet for it in the -[Devhub Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/). \ No newline at end of file +[Devhub Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/). diff --git a/cumulus/parachains/integration-tests/e2e/collectives/README.md b/cumulus/parachains/integration-tests/e2e/collectives/README.md index 98ea77aac60..9c4efe7c950 100644 --- a/cumulus/parachains/integration-tests/e2e/collectives/README.md +++ b/cumulus/parachains/integration-tests/e2e/collectives/README.md @@ -1,19 +1,23 @@ -E2E tests concerning Polkadot Governance and the Collectives Parachain. The tests run by the Parachain Integration Tests [tool](https://github.com/paritytech/parachains-integration-tests/). +E2E tests concerning Polkadot Governance and the Collectives Parachain. The tests run by the Parachain Integration Tests +[tool](https://github.com/paritytech/parachains-integration-tests/). -## Requirements +# Requirements The tests require some changes to the regular production runtime builds: -RelayChain runtime: +## RelayChain runtime 1. Alice has SUDO -2. Public Referenda `StakingAdmin`, `FellowshipAdmin` tracks settings (see the corresponding keys of the `TRACKS_DATA` constant in the `governance::tracks` module of the Relay Chain runtime crate): +2. Public Referenda `StakingAdmin`, `FellowshipAdmin` tracks settings (see the corresponding keys of the `TRACKS_DATA` + constant in the `governance::tracks` module of the Relay Chain runtime crate): ``` yaml prepare_period: 5 Block, decision_period: 1 Block, confirm_period: 1 Block, min_enactment_period: 1 Block, ``` -Collectives runtime: -1. Fellowship Referenda `Fellows` track settings (see the corresponding key of the `TRACKS_DATA` constant in the `fellowship::tracks` module of the Collectives runtime crate): + +## Collectives runtime +1. Fellowship Referenda `Fellows` track settings (see the corresponding key of the `TRACKS_DATA` constant in the + `fellowship::tracks` module of the Collectives runtime crate): ``` yaml prepare_period: 5 Block, decision_period: 1 Block, diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index 1520065b7e3..487c601ef84 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -1,26 +1,26 @@ - [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) + - [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) - * [How to test local BridgeHubKusama/BridgeHubPolkadot](#how-to-test-local-bridgehubkusamabridgehubpolkadot) + - [Send messages - transfer asset over bridge](#send-messages---transfer-asset-over-bridge) + - [How to test live BridgeHubRococo/BridgeHubWococo](#how-to-test-live-bridgehubrococobridgehubwococo) + - [How to test local BridgeHubKusama/BridgeHubPolkadot](#how-to-test-local-bridgehubkusamabridgehubpolkadot) # Bridge-hub Parachains -_BridgeHub(s)_ are **_system parachains_** that will house trustless bridges from the local -ecosystem to others. -The current trustless bridges planned for the BridgeHub(s) are: +_BridgeHub(s)_ are **_system parachains_** that will house trustless bridges from the local ecosystem to others. The +current trustless bridges planned for the BridgeHub(s) are: - `BridgeHubPolkadot` system parachain: 1. Polkadot <-> Kusama bridge 2. Polkadot <-> Ethereum bridge (Snowbridge) - `BridgeHubKusama` system parachain: 1. Kusama <-> Polkadot bridge - 2. Kusama <-> Ethereum bridge - The high-level responsibilities of each bridge living on BridgeHub: + 2. Kusama <-> Ethereum bridge The high-level + responsibilities of each bridge living on BridgeHub: - sync finality proofs between relay chains (or equivalent) - sync finality proofs between BridgeHub parachains - pass (XCM) messages between different BridgeHub parachains @@ -192,43 +192,40 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ``` **Check relay-chain headers relaying:** -- Rococo parachain: - - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - - Pallet: **bridgeWococoGrandpa** - - Keys: **bestFinalized()** -- Wococo parachain: - - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - - Pallet: **bridgeRococoGrandpa** - - Keys: **bestFinalized()** +- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: + **bridgeWococoGrandpa** - Keys: **bestFinalized()** +- Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: + **bridgeRococoGrandpa** - Keys: **bestFinalized()** **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()** -- Wococo parachain: - - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - - Pallet: **bridgeRococoParachain** - - Keys: **bestParaHeads()** +- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: + **bridgeWococoParachain** - Keys: **bestParaHeads()** +- Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: + **bridgeRococoParachain** - Keys: **bestParaHeads()** ### Send messages - transfer asset over bridge TODO: see `# !!! READ HERE` above ## 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) +(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`) +- 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`) ## How to test local BridgeHubKusama/BridgeHubPolkadot diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md b/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md index e4f15ccf92d..387bb24bb0e 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md @@ -33,8 +33,8 @@ There are also different user interfaces and command-line tools you can use to d or interact with contracts: * [Contracts UI](https://paritytech.github.io/contracts-ui/) ‒ a beginner-friendly UI for smart contract developers. -* [polkadot-js](https://polkadot.js.org/apps/) ‒ the go-to expert UI for smart contract developers. -* [cargo-contract](https://github.com/paritytech/cargo-contract) ‒ a CLI tool, ideal for scripting or your terminal workflow. +* [`polkadot-js`](https://polkadot.js.org/apps/) ‒ the go-to expert UI for smart contract developers. +* [`cargo-contract`](https://github.com/paritytech/cargo-contract) ‒ a CLI tool, ideal for scripting or your terminal workflow. If you are looking for a quickstart, we can recommend [ink!'s Guided Tutorial for Beginners](https://docs.substrate.io/tutorials/v3/ink-workshop/pt1/). diff --git a/cumulus/scripts/ci/changelog/README.md b/cumulus/scripts/ci/changelog/README.md new file mode 100644 index 00000000000..e274b491947 --- /dev/null +++ b/cumulus/scripts/ci/changelog/README.md @@ -0,0 +1,77 @@ +# 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 debuggin + +### 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/xcm/xcm-emulator/README.md b/cumulus/xcm/xcm-emulator/README.md index d188c99eecf..2a861a9d269 100644 --- a/cumulus/xcm/xcm-emulator/README.md +++ b/cumulus/xcm/xcm-emulator/README.md @@ -13,11 +13,11 @@ As the messages do not physically go through the same messaging infrastructure there is some code that is not being tested compared to using slower E2E tests. In future it may be possible to run these XCM emulated tests as E2E tests (without changes). -As well as the XCM message transport being mocked out, so too are areas around consensus, +As well as the XCM message transport being mocked out, so too are areas around consensus, in particular things like disputes, staking and iamonline events can't be tested. ## Alternatives If you just wish to test execution of various XCM instructions -against the XCM VM then the `xcm-simulator` (in the polkadot +against the XCM VM then the `xcm-simulator` (in the Polkadot repo) is the perfect tool for this. diff --git a/cumulus/zombienet/tests/0007-prepare-warp-sync-db-snapshot.md b/cumulus/zombienet/tests/0007-prepare-warp-sync-db-snapshot.md index 7885dd0c026..373e4807238 100644 --- a/cumulus/zombienet/tests/0007-prepare-warp-sync-db-snapshot.md +++ b/cumulus/zombienet/tests/0007-prepare-warp-sync-db-snapshot.md @@ -1,22 +1,24 @@ # Database snapshot guide -For this guide we will be taking a snapshot of a parachain and relay chain. Please note we are using a local chain here `rococo_local_testnet` and `local_testnet`. Live chains will have different values +For this guide we will be taking a snapshot of a parachain and relay chain. Please note we are using a local chain here +`rococo_local_testnet` and `local_testnet`. Live chains will have different values *Please ensure that the database is not in current use, i.e no nodes are writing to it* # How to prepare database for a relaychain -To prepare snapshot for a relay chain we need to copy the database. +To prepare snapshot for a relay chain we need to copy the database. ``` mkdir -p relaychain-snapshot/alice/data/chains/rococo_local_testnet/db/ -cp -r chain-data/alice/data/chains/rococo_local_testnet/db/. relaychain-snapshot/alice/data/chains/rococo_local_testnet/db/ +cp -r chain-data/alice/data/chains/rococo_local_testnet/db/. relaychain-snapshot/alice/data/chains/rococo_local_testnet/db/ tar -C relaychain-snapshot/alice/ -czf relaychain.tgz data ``` # How to prepare database for a parachain -To prepare snapshot for a parachain we need to copy the database for both the collator node (parachain data) and validator (relay data) +To prepare snapshot for a parachain we need to copy the database for both the collator node (parachain data) and +validator (relay data) ``` #Parachain data @@ -33,5 +35,6 @@ tar -C parachain-snapshot/charlie/ -czf parachain.tgz data relay-data ``` # Restoring a snapshot -Zombienet will automatically download the `*.tgz` file to the respective folder for a run. However you can also download it manually, just ensure you extract the tar file in the correct directory, i.e. the root directory -`chain-data/charlie/` \ No newline at end of file +Zombienet will automatically download the `*.tgz` file to the respective folder for a run. However you can also download +it manually, just ensure you extract the tar file in the correct directory, i.e. the root directory +`chain-data/charlie/` diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5e892625fb7..20fa1d3a768 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -32,11 +32,11 @@ If it is an urgent fix with no large change to logic, then it may be merged afte contributor has reviewed it well and approved the review once CI is complete. No PR should be merged until all reviews' comments are addressed. -### Labels: +### Labels The set of labels and their description can be found [here](https://paritytech.github.io/labels/doc_polkadot-sdk.html). -### Process: +### Process 1. Please use our [Pull Request Template](./PULL_REQUEST_TEMPLATE.md) and make sure all relevant information is reflected in your PR. @@ -50,12 +50,12 @@ The set of labels and their description can be found [here](https://paritytech.g `T13-documentation`. The docs team will get in touch. 5. If your PR changes files in these paths: - `polkadot` : '^runtime/polkadot' - `polkadot` : '^runtime/kusama' - `polkadot` : '^primitives/src/' - `polkadot` : '^runtime/common' - `substrate` : '^frame/' - `substrate` : '^primitives/' + `polkadot` : `^runtime/polkadot` + `polkadot` : `^runtime/kusama` + `polkadot` : `^primitives/src/` + `polkadot` : `^runtime/common` + `substrate` : `^frame/` + `substrate` : `^primitives/` It should be added to the [security audit board](https://github.com/orgs/paritytech/projects/103) and will need to undergo an audit before merge. @@ -67,7 +67,7 @@ to change the code to make it work/compile. It should also mention potential storage migrations and if they require some special setup aside adding it to the list of migrations in the runtime. -## Reviewing pull requests: +## Reviewing pull requests When reviewing a pull request, the end-goal is to suggest useful changes to the author. Reviews should finish with approval unless there are issues that would result in: diff --git a/docs/DOCUMENTATION_GUIDELINE.md b/docs/DOCUMENTATION_GUIDELINE.md index 82361732959..f6c8cac7cd2 100644 --- a/docs/DOCUMENTATION_GUIDELINE.md +++ b/docs/DOCUMENTATION_GUIDELINE.md @@ -1,11 +1,10 @@ # Substrate Documentation Guidelines -This document is focused on documenting parts of substrate that relate to its -external API. The list of such crates can be found in [CODEOWNERS](./CODEOWNERS). -Search for the crates auto-assigned to the `docs-audit` team. +This document is focused on documenting parts of Substrate that relate to its external API. The list of such crates can +be found in [CODEOWNERS](./CODEOWNERS). Search for the crates auto-assigned to the `docs-audit` team. -These crates are used by external developers and need thorough documentation. -They are the most concerned with FRAME development. +These crates are used by external developers and need thorough documentation. They are the most concerned with FRAME +development. - [Substrate Documentation Guidelines](#substrate-documentation-guidelines) - [General/Non-Pallet Crates](#generalnon-pallet-crates) @@ -35,22 +34,19 @@ First, consider the case for all such crates, except for those that are pallets. The first question is, what should you document? Use this filter: 1. In the crates assigned to `docs-audit` in [CODEOWNERS](./CODEOWNERS), -2. All `pub` items need to be documented. If not `pub`, it doesn't appear in the -rust-docs, and is not public facing. +2. All `pub` items need to be documented. If not `pub`, it doesn't appear in the rust-docs, and is not public facing. - * Within `pub` items, sometimes they are only `pub` to be used by another - internal crate, and you can foresee that this won't be used by anyone else. - These need **not** be documented thoroughly. + - Within `pub` items, sometimes they are only `pub` to be used by another internal crate, and you can foresee that + this won't be used by anyone else. These need **not** be documented thoroughly. - * Reminder: `trait` items are public by definition if the trait is public. + - Reminder: `trait` items are public by definition if the trait is public. 3. All public modules (`mod`) should have reasonable module-level documentation (`//!`). #### Rust Docs vs. Code Comments -Note that anything starting with `///` is an external rust-doc, and everything -starting with `//` does not appear in the rust-docs. -It's important to not confuse the two in your documentation. +Note that anything starting with `///` is an external rust-doc, and everything starting with `//` does not appear in the +rust-docs. It's important to not confuse the two in your documentation. ```rust /// Computes the square root of the input, returning `Ok(_)` if successful. @@ -73,100 +69,88 @@ pub fn sqrt(x: u32) -> Result { There are good sources to look into: - [Rust Documentation Guide](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html) -- [Documentation in Rust Book](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments) -- [Guide on Writing Documentation for a Rust Crate](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate) - -As mentioned [here](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#writing-documentation-comments) and [here](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate), -always start with a **single sentence** demonstrating what is documented. All additional -documentation should be added *after a newline*. Strive to make the first sentence succinct -and short.The reason for this is the first paragraph of docs about an item (everything -before the first newline) is used as the excerpt that rust doc displays about -this item when it appears in tables, such as the table listing all functions in -a module. If this excerpt is too long, the module docs will be very difficult -to read. - -About [special sections](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#special-sections), we will most likely not need to think about panic and safety in any runtime related code. Our code is never `unsafe`, and will (almost) never panic. - -Use `# Examples as much as possible. These are great ways to further -demonstrate what your APIs are doing, and add free test coverage. As an -additional benefit, any code in rust-docs is treated as an "integration tests", -not unit tests, which tests your crate in a different way than unit tests. So, -it is both a win for "more documentation" and a win for "more test coverage". - -You can also consider having an `# Error` section optionally. Of course, this -only applies if there is a `Result` being returned, and if the `Error` variants -are overly complicated. - -Strive to include correct links to other items in your written docs as much as -possible. In other words, avoid \`some_func\` and instead use \[\`some_fund\`\]. -Read more about how to correctly use links in your rust-docs -[here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) -and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). -Strive to include correct links to other items in your written docs as much as -possible. In other words, avoid `` `some_func` `` and instead use -``[`some_func`]``. - -> While you are linking, you might become conscious of the fact that you are -in need of linking to (too many) foreign items in order to explain your API. -This is leaning more towards API-Design rather than documentation, but it is a -warning that the subject API might be slightly wrong. For example, most "glue" -traits[^1] in `frame/support` should be designed and documented without making -hard assumptions about particular pallets that implement them. +- [Documentation in Rust + Book](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments) +- [Guide on Writing Documentation for a Rust + Crate](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate) + +As mentioned +[here](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#writing-documentation-comments) +and [here](https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate), +always start with a **single sentence** demonstrating what is documented. All additional documentation should be added +*after a newline*. Strive to make the first sentence succinct and short.The reason for this is the first paragraph of +docs about an item (everything before the first newline) is used as the excerpt that rust doc displays about this item +when it appears in tables, such as the table listing all functions in a module. If this excerpt is too long, the module +docs will be very difficult to read. + +About [special +sections](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/documentation.html#special-sections), +we will most likely not need to think about panic and safety in any runtime related code. Our code is never `unsafe`, +and will (almost) never panic. + +Use `# Examples as much as possible. These are great ways to further demonstrate what your APIs are doing, and add free +test coverage. As an additional benefit, any code in rust-docs is treated as an "integration tests", not unit tests, +which tests your crate in a different way than unit tests. So, it is both a win for "more documentation" and a win for +"more test coverage". + +You can also consider having an `# Error` section optionally. Of course, this only applies if there is a `Result` being +returned, and if the `Error` variants are overly complicated. + +Strive to include correct links to other items in your written docs as much as possible. In other words, avoid +\`some_func\` and instead use \[\`some_fund\`\]. Read more about how to correctly use links in your rust-docs +[here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and +[here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). Strive to +include correct links to other items in your written docs as much as possible. In other words, avoid `` `some_func` `` +and instead use ``[`some_func`]``. + +> While you are linking, you might become conscious of the fact that you are in need of linking to (too many) foreign +items in order to explain your API. This is leaning more towards API-Design rather than documentation, but it is a +warning that the subject API might be slightly wrong. For example, most "glue" traits[^1] in `frame/support` should be +designed and documented without making hard assumptions about particular pallets that implement them. --- #### TLDR -0. Have the goal of enforcing `#![deny(missing_docs)]` mentally, even if it is -not enforced by the compiler 🙈. -1. Start with a single, clear and concise sentence. Follow up with more context, -after a newline, if needed. +0. Have the goal of enforcing `#![deny(missing_docs)]` mentally, even if it is not enforced by the compiler 🙈. +1. Start with a single, clear and concise sentence. Follow up with more context, after a newline, if needed. 2. Use examples as much as reasonably possible. 3. Use links as much as possible. -4. Think about context. If you are explaining a lot of foreign topics while -documenting a trait that should not explicitly depend on them, you have likely -not designed it properly. +4. Think about context. If you are explaining a lot of foreign topics while documenting a trait that should not +explicitly depend on them, you have likely not designed it properly. --- #### Proc-Macros -Note that there are special considerations when documenting proc macros. Doc -links will appear to function _within_ your proc macro crate, but often will no -longer function when these proc macros are re-exported elsewhere in your -project. The exception is doc links to _other proc macros_ which will function -just fine if they are also being re-exported. It is also often necessary to -disambiguate between a proc macro and a function of the same name, which can be -done using the `macro@my_macro_name` syntax in your link. Read more about how to -correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) -and [here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). +Note that there are special considerations when documenting proc macros. Doc links will appear to function _within_ your +proc macro crate, but often will no longer function when these proc macros are re-exported elsewhere in your project. +The exception is doc links to _other proc macros_ which will function just fine if they are also being re-exported. It +is also often necessary to disambiguate between a proc macro and a function of the same name, which can be done using +the `macro@my_macro_name` syntax in your link. Read more about how to correctly use links in your rust-docs +[here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and +[here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). --- ### Other Guidelines -The above five guidelines must always be reasonably respected in the -documentation. +The above five guidelines must always be reasonably respected in the documentation. -The following are a set of notes that may not necessarily hold in all -circumstances: +The following are a set of notes that may not necessarily hold in all circumstances: --- #### Document Through Code -You should make sure that your code is properly-named and well-organized so that -your code functions as a form of documentation. However, within the complexity -of our projects in Polkadot/Substrate that is not enough. Particularly, things -like examples, errors and panics cannot be documented only through properly- -named and well-organized code. +You should make sure that your code is properly-named and well-organized so that your code functions as a form of +documentation. However, within the complexity of our projects in Polkadot/Substrate that is not enough. Particularly, +things like examples, errors and panics cannot be documented only through properly- named and well-organized code. -> Our north star is self-documenting code that also happens to be well-documented -and littered with examples. +> Our north star is self-documenting code that also happens to be well-documented and littered with examples. -* Your written documents should *complement* the code, not *repeat* it. As an -example, a documentation on top of a code example should never look like the -following: +- Your written documents should *complement* the code, not *repeat* it. As an example, a documentation on top of a code +example should never look like the following: ```rust /// Sends request and handles the response. @@ -175,15 +159,14 @@ following: } ``` -In the above example, the documentation has added no useful information not -already contained within the properly-named trait and is redundant. +In the above example, the documentation has added no useful information not already contained within the properly-named +trait and is redundant. --- #### Formatting Matters -The way you format your documents (newlines, heading and so on) makes a -difference. Consider the below examples: +The way you format your documents (newlines, heading and so on) makes a difference. Consider the below examples: ```rust /// This function works with input u32 x and multiplies it by two. If @@ -206,16 +189,15 @@ fn multiply_by_2(x: u32) -> u32 { .. } // More efficiency can be achieved if we improve this via such and such. fn multiply_by_2(x: u32) -> u32 { .. } ``` -They are both roughly conveying the same set of facts, but one is easier to -follow because it was formatted cleanly. Especially for traits and types that -you can foresee will be seen and used a lot, try and write a well formatted +They are both roughly conveying the same set of facts, but one is easier to follow because it was formatted cleanly. +Especially for traits and types that you can foresee will be seen and used a lot, try and write a well formatted version. -Similarly, make sure your comments are wrapped at 100 characters line-width (as -defined by our [`rustfmt.toml`](../rustfmt.toml)), no **more and no less**! The -more is fixed by `rustfmt` and our CI, but if you (for some unknown reason) -wrap your lines at 59 characters, it will pass the CI, and it will not look good -🫣. Consider using a plugin like [rewrap](https://marketplace.visualstudio.com/items?itemName=stkb.rewrap) (for Visual Studio Code) to properly do this. +Similarly, make sure your comments are wrapped at 100 characters line-width (as defined by our +[`rustfmt.toml`](../rustfmt.toml)), no **more and no less**! The more is fixed by `rustfmt` and our CI, but if you (for +some unknown reason) wrap your lines at 59 characters, it will pass the CI, and it will not look good 🫣. Consider using +a plugin like [rewrap](https://marketplace.visualstudio.com/items?itemName=stkb.rewrap) (for Visual Studio Code) to +properly do this. [^1]: Those that help two pallets talk to each other. @@ -224,12 +206,11 @@ wrap your lines at 59 characters, it will pass the CI, and it will not look good ## Pallet Crates -The guidelines so far have been general in nature, and are applicable to crates -that are pallets and crates that're not pallets. +The guidelines so far have been general in nature, and are applicable to crates that are pallets and crates that're not +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. +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. --- @@ -252,15 +233,20 @@ For the top-level pallet docs, consider the following template: //! //! ### Example //! -//! . +//! . //! //! ## Pallet API //! -//! +//! //! -//! See the [`pallet`] module for more information about the interfaces this pallet exposes, including its configuration trait, dispatchables, storage items, events and errors. +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, including its configuration +//! trait, dispatchables, storage items, events and errors. //! -//! +//! //! //! This section can most often be left as-is. //! @@ -268,7 +254,8 @@ For the top-level pallet docs, consider the following template: //! //! //! -//! +//! //! //! ### Design Goals (optional) //! @@ -276,31 +263,31 @@ For the top-level pallet docs, consider the following template: //! //! ### Design (optional) //! -//! +//! //! //! ### Terminology (optional) //! -//! +//! ``` -This template's details (heading 3s and beyond) are left flexible, and at the -discretion of the developer to make the best final choice about. For example, -you might want to include `### Terminology` or not. Moreover, you might find it +This template's details (heading 3s and beyond) are left flexible, and at the discretion of the developer to make the +best final choice about. For example, you might want to include `### Terminology` or not. Moreover, you might find it more useful to include it in `## Overview`. -Nonetheless, the high level flow of going from the most high level explanation -to the most low level explanation is important to follow. +Nonetheless, the high level flow of going from the most high level explanation to the most low level explanation is +important to follow. -As a rule of thumb, the Heading 2s (`##`) in this template can be considered a -strict rule, while the Heading 3s (`###`) and beyond are flexible. +As a rule of thumb, the Heading 2s (`##`) in this template can be considered a strict rule, while the Heading 3s (`###`) +and beyond are flexible. --- #### Polkadot and Substrate -Optionally, in order to demonstrate the relation between the two, you can start -the pallet documentation with: +Optionally, in order to demonstrate the relation between the two, you can start the pallet documentation with: ``` //! > Made with *Substrate*, for *Polkadot*. @@ -331,7 +318,8 @@ For each dispatchable (`fn` item inside `#[pallet::call]`), consider the followi /// /// ## Errors (optional) /// -/// +/// /// /// ## Events (optional) /// @@ -339,29 +327,26 @@ For each dispatchable (`fn` item inside `#[pallet::call]`), consider the followi pub fn name_of_dispatchable(origin: OriginFor, ...) -> DispatchResult {} ``` -Consider the fact that these docs will be part of the metadata of the associated dispatchable, and might be used by wallets and explorers. +Consider the fact that these docs will be part of the metadata of the associated dispatchable, and might be used by +wallets and explorers. --- ### Storage Items -1. If a map-like type is being used, always note the choice of your hashers as -private code docs (`// Hasher X chosen because ...`). Recall that this is not -relevant information to external people, so it must be documented as `//`. +1. If a map-like type is being used, always note the choice of your hashers as private code docs (`// Hasher X chosen +because ...`). Recall that this is not relevant information to external people, so it must be documented as `//`. -2. Consider explaining the crypto-economics of how a deposit is being taken in -return of the storage being used. +2. Consider explaining the crypto-economics of how a deposit is being taken in return of the storage being used. -3. Consider explaining why it is safe for the storage item to be unbounded, if -`#[pallet::unbounded]` or `#[pallet::without_storage_info]` is being used. +3. Consider explaining why it is safe for the storage item to be unbounded, if `#[pallet::unbounded]` or +`#[pallet::without_storage_info]` is being used. --- ### Errors and Events -Consider the fact that, similar to dispatchables, these docs will be part of -the metadata of the associated event/error, and might be used by wallets and -explorers. +Consider the fact that, similar to dispatchables, these docs will be part of the metadata of the associated event/error, +and might be used by wallets and explorers. -Specifically for `error`, explain why the error has happened, and what can be -done in order to avoid it. +Specifically for `error`, explain why the error has happened, and what can be done in order to avoid it. diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 1d0ef338c10..284ad15afc9 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -2,25 +2,27 @@ ✄ ----------------------------------------------------------------------------- -Thank you for your Pull Request! 🙏 Please make sure it follows the contribution -guidelines outlined in [this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md) and fill out the -sections below. Once you're ready to submit your PR for review, please delete -this section and leave only the text under the "Description" heading. - +Thank you for your Pull Request! 🙏 Please make sure it follows the contribution guidelines outlined in +[this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md) and fill +out the sections below. Once you're ready to submit your PR for review, please +delete this section and leave only the text under the "Description" heading. # Description -*Please include a summary of the changes and the related issue. Please also include relevant motivation and context, including:* +*Please include a summary of the changes and the related issue. Please also include relevant motivation and context, +including:* - What does this PR do? - Why are these changes needed? - How were these changes implemented and what do they affect? -*Use [Github semantic linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) to address any open issues this PR relates to or closes.* +*Use [Github semantic +linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) +to address any open issues this PR relates to or closes.* -Fixes # (issue number, *if applicable*) +Fixes # (issue number, *if applicable*) -Closes # (issue number, *if applicable*) +Closes # (issue number, *if applicable*) Polkadot companion: (*if applicable*) @@ -29,10 +31,12 @@ Cumulus companion: (*if applicable*) # Checklist - [ ] My PR includes a detailed description as outlined in the "Description" section above -- [ ] My PR follows the [labeling requirements](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#process) of this project (at minimum one label for `T` required) +- [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` + 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) +- [ ] 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/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md index eb3399880f5..a9ac4a5910b 100644 --- a/docs/STYLE_GUIDE.md +++ b/docs/STYLE_GUIDE.md @@ -2,19 +2,19 @@ title: Style Guide for Rust in the Polkadot-SDK --- -Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` +Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` then you will adhere to most of these style guidelines automatically. # Formatting -- Indent using tabs. -- Lines should be longer than 100 characters long only in exceptional circumstances and certainly +- Indent using tabs. +- Lines should be longer than 100 characters long only in exceptional circumstances and certainly no longer than 120. For this purpose, tabs are considered 4 characters wide. -- Indent levels should be greater than 5 only in exceptional circumstances and certainly no +- Indent levels should be greater than 5 only in exceptional circumstances and certainly no greater than 8. If they are greater than 5, then consider using `let` or auxiliary functions in order to strip out complex inline expressions. -- Never have spaces on a line prior to a non-whitespace character -- Follow-on lines are only ever a single indent from the original line. +- Never have spaces on a line prior to a non-whitespace character +- Follow-on lines are only ever a single indent from the original line. ```rust fn calculation(some_long_variable_a: i8, some_long_variable_b: i8) -> bool { @@ -25,7 +25,7 @@ fn calculation(some_long_variable_a: i8, some_long_variable_b: i8) -> bool { } ``` -- Indent level should follow open parens/brackets, but should be collapsed to the smallest number +- Indent level should follow open parens/brackets, but should be collapsed to the smallest number of levels actually used: ```rust @@ -45,8 +45,8 @@ fn calculate( } ``` -- `where` is indented, and its items are indented one further. -- Argument lists or function invocations that are too long to fit on one line are indented +- `where` is indented, and its items are indented one further. +- Argument lists or function invocations that are too long to fit on one line are indented similarly to code blocks, and once one param is indented in such a way, all others should be, too. Run-on parameter lists are also acceptable for single-line run-ons of basic function calls. @@ -92,7 +92,7 @@ fn foo(really_long_parameter_name_1: SomeLongTypeName, really_long_parameter_nam } ``` -- Always end last item of a multi-line comma-delimited set with `,` when legal: +- Always end last item of a multi-line comma-delimited set with `,` when legal: ```rust struct Point { @@ -104,7 +104,7 @@ struct Point { enum Meal { Breakfast, Lunch, Dinner }; ``` -- Avoid trailing `;`s where unneeded. +- Avoid trailing `;`s where unneeded. ```rust if condition { @@ -112,8 +112,8 @@ if condition { } ``` -- `match` arms may be either blocks or have a trailing `,` but not both. -- Blocks should not be used unnecessarily. +- `match` arms may be either blocks or have a trailing `,` but not both. +- Blocks should not be used unnecessarily. ```rust match meal { @@ -126,7 +126,7 @@ match meal { # Style -- Panickers require explicit proofs they don't trigger. Calling `unwrap` is discouraged. The +- Panickers require explicit proofs they don't trigger. Calling `unwrap` is discouraged. The exception to this rule is test code. Avoiding panickers by restructuring code is preferred if feasible. @@ -139,14 +139,14 @@ let mut target_path = ); ``` -- Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, +- Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, consider trade-offs between efficiency on one hand and reliability, maintenance costs, and security on the other. Here is a list of questions that may help evaluating the trade-off while preparing or reviewing a PR: - - how much more performant or compact the resulting code will be using unsafe code, - - how likely is it that invariants could be violated, - - are issues stemming from the use of unsafe code caught by existing tests/tooling, - - what are the consequences if the problems slip into production. + - how much more performant or compact the resulting code will be using unsafe code, + - how likely is it that invariants could be violated, + - are issues stemming from the use of unsafe code caught by existing tests/tooling, + - what are the consequences if the problems slip into production. # Manifest Formatting @@ -177,4 +177,4 @@ default = [ # Comments go here as well ;) "std", ] -``` \ No newline at end of file +``` diff --git a/docs/markdown_linting.md b/docs/markdown_linting.md new file mode 100644 index 00000000000..d916b86ba54 --- /dev/null +++ b/docs/markdown_linting.md @@ -0,0 +1,20 @@ +# Markdown linting + +Since the introduction of [PR #1309](https://github.com/paritytech/polkadot-sdk/pull/1309), the markdown +files in this repository are checked by a linter for formatting and consistency. + +The linter used is [`markdownlint`](https://github.com/DavidAnson/markdownlint) and can be installed locally on your +machine. It can also be setup as [pre-commit hook](https://github.com/igorshubovych/markdownlint-cli#use-with-pre-commit) +to ensure that your markdown is passing all the tests. + +The rules in place are defined +[here](https://github.com/paritytech/polkadot-sdk/blob/master/.github/.markdownlint.yaml). + +You may run `markdownlint` locally using: +``` +markdownlint --config .github/.markdownlint.yaml --ignore target . +``` + +There are also plugins for your favorite editor, that can ensure that most +of the rules will pass and fix typical issues (such as trailing spaces, +missing eof new line, long lines, etc...) diff --git a/polkadot/README.md b/polkadot/README.md index 8f0809c9fc7..93e93cfba0e 100644 --- a/polkadot/README.md +++ b/polkadot/README.md @@ -22,7 +22,7 @@ Installation from the Debian repository will create a `systemd` service that can 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 +`/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) @@ -128,7 +128,7 @@ Connect to the global Polkadot Mainnet network by running: You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). -[telemetry]: https://telemetry.polkadot.io/#list/Polkadot +[telemetry](https://telemetry.polkadot.io/#list/Polkadot): https://telemetry.polkadot.io/#list/Polkadot ### Connect to the "Kusama" Canary Network @@ -140,7 +140,7 @@ Connect to the global Kusama canary network by running: You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). -[telemetry]: https://telemetry.polkadot.io/#list/Kusama +[telemetry](https://telemetry.polkadot.io/#list/Kusama): https://telemetry.polkadot.io/#list/Kusama ### Connect to the Westend Testnet @@ -152,7 +152,7 @@ Connect to the global Westend testnet by running: You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). -[telemetry]: https://telemetry.polkadot.io/#list/Westend +[telemetry](https://telemetry.polkadot.io/#list/Westend): https://telemetry.polkadot.io/#list/Westend ### Obtaining DOTs diff --git a/polkadot/RELEASE.md b/polkadot/RELEASE.md index 937c1e6e515..196f27e595d 100644 --- a/polkadot/RELEASE.md +++ b/polkadot/RELEASE.md @@ -1,57 +1,52 @@ -Polkadot Release Process ------------------------- +# Polkadot Release Process -### Branches -* release-candidate branch: The branch used for staging of the next release. - Named like `release-v0.8.26` - -### Notes -* The release-candidate branch *must* be made in the paritytech/polkadot repo in -order for release automation to work correctly -* Any new pushes/merges to the release-candidate branch (for example, -refs/heads/release-v0.8.26) will result in the rc index being bumped (e.g., v0.8.26-rc1 -to v0.8.26-rc2) and new wasms built. +## Branches +* release-candidate branch: The branch used for staging of the next release. Named like `release-v0.8.26` -### Release workflow +## Notes +* The release-candidate branch *must* be made in the `paritytech/polkadot` repo in order for release automation to work +correctly +* Any new pushes/merges to the release-candidate branch (for example, refs/heads/release-v0.8.26) will result in the rc +index being bumped (e.g., v0.8.26-rc1 to v0.8.26-rc2) and new wasm built. -Below are the steps of the release workflow. Steps prefixed with NOACTION are -automated and require no human action. +## Release workflow + +Below are the steps of the release workflow. Steps prefixed with NOACTION are automated and require no human action. 1. To initiate the release process: - 1. branch master off to a release candidate branch: - - `git checkout master; git pull; git checkout -b release-v0.8.26` - 2. In the [substrate](https://github.com/paritytech/substrate) repo, check out the commit used by polkadot (this can be found using the following command in the *polkadot* repo: `grep 'paritytech/substrate' Cargo.lock | grep -E '[0-9a-f]{40}' | sort | uniq ` - 3. Branch off this **substrate** commit into its own branch: `git branch -b polkadot-v0.8.26; git push origin refs/heads/polkadot-v0.8.26` - 4. In the **polkadot** repository, use [diener](https://github.com/bkchr/diener/) to switch to this branch: `diener update --branch "polkadot-v0.8.26" --substrate`. Update Cargo.lock (to do this, you can run `cargo build` and then ctrl+c once it finishes fetching and begins compiling) - 5. Push the **polkadot** `release-v0.8.26` branch to Github: `git push origin refs/heads/release-v0.8.26` -2. NOACTION: The current HEAD of the release-candidate branch is tagged `v0.8.26-rc1` -3. NOACTION: A draft release and runtime WASMs are created for this - release-candidate automatically. A link to the draft release will be linked in - the internal polkadot matrix channel. -4. NOACTION: A new Github issue is created containing a checklist of manual - steps to be completed before we are confident with the release. This will be - linked in Matrix. -5. Complete the steps in the issue created in step 4, signing them off as - completed -6. (optional) If a fix is required to the release-candidate: + 1. branch master off to a release candidate branch: - `git checkout master; git pull; git checkout -b release-v0.8.26` + 1. In the [Substrate](https://github.com/paritytech/substrate) repo, check out the commit used by Polkadot (this can + be found using the following command in the *Polkadot* repo: `grep 'paritytech/substrate' Cargo.lock | grep -E + '[0-9a-f]{40}' | sort | uniq` + 1. Branch off this **Substrate** commit into its own branch: `git branch -b polkadot-v0.8.26; git push origin + refs/heads/polkadot-v0.8.26` + 1. In the **Polkadot** repository, use [diener](https://github.com/bkchr/diener/) to switch to this branch: `diener + update --branch "polkadot-v0.8.26" --substrate`. Update Cargo.lock (to do this, you can run `cargo build` and then + ctrl+c once it finishes fetching and begins compiling) + 1. Push the **Polkadot** `release-v0.8.26` branch to Github: `git push origin refs/heads/release-v0.8.26` +1. NOACTION: The current HEAD of the release-candidate branch is tagged `v0.8.26-rc1` +1. NOACTION: A draft release and runtime WASMs are created for this release-candidate automatically. A link to the draft + release will be linked in the internal Polkadot matrix channel. +1. NOACTION: A new Github issue is created containing a checklist of manual steps to be completed before we are + confident with the release. This will be linked in Matrix. +1. Complete the steps in the issue created in step 4, signing them off as completed +1. (optional) If a fix is required to the release-candidate: 1. Merge the fix with `master` first - 2. Cherry-pick the commit from `master` to `release-v0.8.26`, fixing any - merge conflicts. Try to avoid unnecessarily bumping crates. - 3. Push the release-candidate branch to Github - this is now the new release- - candidate - 4. Depending on the cherry-picked changes, it may be necessary to perform some - or all of the manual tests again. - 5. If there are **substrate** changes required, these should be cherry-picked to the substrate `polkadot-v0.8.26` branch and pushed, and the version of substrate used in **polkadot** updated using `cargo update -p sp-io` -7. Once happy with the release-candidate, tag the current top commit in the release candidate branch and push to Github: `git tag -s -m 'v0.8.26' v0.8.26; git push --tags` -9. NOACTION: The HEAD of the `release` branch will be tagged with `v0.8.26`, - and a final draft release will be created on Github. + 1. Cherry-pick the commit from `master` to `release-v0.8.26`, fixing any merge conflicts. Try to avoid unnecessarily + bumping crates. + 1. Push the release-candidate branch to Github - this is now the new release- candidate + 1. Depending on the cherry-picked changes, it may be necessary to perform some or all of the manual tests again. + 1. If there are **Substrate** changes required, these should be cherry-picked to the Substrate `polkadot-v0.8.26` + branch and pushed, and the version of Substrate used in **Polkadot** updated using `cargo update -p sp-io` +1. Once happy with the release-candidate, tag the current top commit in the release candidate branch and push to Github: + `git tag -s -m 'v0.8.26' v0.8.26; git push --tags` +1. NOACTION: The HEAD of the `release` branch will be tagged with `v0.8.26`, and a final draft release will be created + on Github. -### Security releases +## Security releases -Occasionally there may be changes that need to be made to the most recently -released version of Polkadot, without taking *every* change to `master` since -the last release. For example, in the event of a security vulnerability being -found, where releasing a fixed version is a matter of some expediency. In cases -like this, the fix should first be merged with master, cherry-picked to a branch -forked from `release`, tested, and then finally merged with `release`. A -sensible versioning scheme for changes like this is `vX.Y.Z-1`. +Occasionally there may be changes that need to be made to the most recently released version of Polkadot, without taking +*every* change to `master` since the last release. For example, in the event of a security vulnerability being found, +where releasing a fixed version is a matter of some expediency. In cases like this, the fix should first be merged with +master, cherry-picked to a branch forked from `release`, tested, and then finally merged with `release`. A sensible +versioning scheme for changes like this is `vX.Y.Z-1`. diff --git a/polkadot/doc/docker.md b/polkadot/doc/docker.md index f20c2d001ed..dc679908ec6 100644 --- a/polkadot/doc/docker.md +++ b/polkadot/doc/docker.md @@ -1,6 +1,8 @@ # Using Containers -The following commands should work no matter if you use Docker or Podman. In general, Podman is recommended. All commands are "engine neutral" so you can use the container engine of your choice while still being able to copy/paste the commands below. +The following commands should work no matter if you use Docker or Podman. In general, Podman is recommended. All +commands are "engine neutral" so you can use the container engine of your choice while still being able to copy/paste +the commands below. Let's start defining Podman as our engine: ``` @@ -14,11 +16,15 @@ ENGINE=docker ## The easiest way -The easiest/faster option to run Polkadot in Docker is to use the latest release images. These are small images that use the latest official release of the Polkadot binary, pulled from our Debian package. +The easiest/faster option to run Polkadot in Docker is to use the latest release images. These are small images that use +the latest official release of the Polkadot binary, pulled from our Debian package. -**_The following examples are running on westend chain and without SSL. They can be used to quick start and learn how Polkadot needs to be configured. Please find out how to secure your node, if you want to operate it on the internet. Do not expose RPC and WS ports, if they are not correctly configured._** +**_The following examples are running on westend chain and without SSL. They can be used to quick start and learn how +Polkadot needs to be configured. Please find out how to secure your node, if you want to operate it on the internet. Do +not expose RPC and WS ports, if they are not correctly configured._** -Let's first check the version we have. The first time you run this command, the Polkadot docker image will be downloaded. This takes a bit of time and bandwidth, be patient: +Let's first check the version we have. The first time you run this command, the Polkadot docker image will be +downloaded. This takes a bit of time and bandwidth, be patient: ```bash $ENGINE run --rm -it parity/polkadot:latest --version @@ -32,11 +38,14 @@ $ENGINE run --rm -it parity/polkadot:latest --chain westend --name "PolkaDocker" ## Examples -Once you are done experimenting and picking the best node name :) you can start Polkadot as daemon, exposes the Polkadot ports and mount a volume that will keep your blockchain data locally. Make sure that you set the ownership of your local directory to the Polkadot user that is used by the container. +Once you are done experimenting and picking the best node name :) you can start Polkadot as daemon, exposes the Polkadot +ports and mount a volume that will keep your blockchain data locally. Make sure that you set the ownership of your local +directory to the Polkadot user that is used by the container. Set user id 1000 and group id 1000, by running `chown 1000.1000 /my/local/folder -R` if you use a bind mount. -To start a Polkadot node on default rpc port 9933 and default p2p port 30333 use the following command. If you want to connect to rpc port 9933, then must add Polkadot startup parameter: `--rpc-external`. +To start a Polkadot node on default rpc port 9933 and default p2p port 30333 use the following command. If you want to +connect to rpc port 9933, then must add Polkadot startup parameter: `--rpc-external`. ```bash $ENGINE run -d -p 30333:30333 -p 9933:9933 \ @@ -82,7 +91,8 @@ services: ] ``` -With following `docker-compose.yml` you can set up a node and use polkadot-js-apps as the front end on port 80. After starting the node use a browser and enter your Docker host IP in the URL field: __ +With following `docker-compose.yml` you can set up a node and use `polkadot-js-apps` as the front end on port 80. After +starting the node use a browser and enter your Docker host IP in the URL field: __ ```bash version: '2' @@ -117,12 +127,14 @@ services: Chain syncing will utilize all available memory and CPU power your server has to offer, which can lead to crashing. -If running on a low resource VPS, use `--memory` and `--cpus` to limit the resources used. E.g. To allow a maximum of 512MB memory and 50% of 1 CPU, use `--cpus=".5" --memory="512m"`. Read more about limiting a container's resources [here](https://docs.docker.com/config/containers/resource_constraints). +If running on a low resource VPS, use `--memory` and `--cpus` to limit the resources used. E.g. To allow a maximum of +512MB memory and 50% of 1 CPU, use `--cpus=".5" --memory="512m"`. Read more about limiting a container's resources +[here](https://docs.docker.com/config/containers/resource_constraints). ## Build your own image -There are 3 options to build a polkadot container image: +There are 3 options to build a Polkadot container image: - using the builder image - using the injected "Debian" image - using the generic injected image @@ -131,27 +143,31 @@ There are 3 options to build a polkadot container image: To get up and running with the smallest footprint on your system, you may use an existing Polkadot Container image. -You may also build a polkadot container image yourself (it takes a while...) using the container specs `scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile`. +You may also build a Polkadot container image yourself (it takes a while...) using the container specs +`scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile`. ### Debian injected -The Debian injected image is how the official polkadot container image is produced. It relies on the Debian package that is published upon each release. The Debian injected image is usually available a few minutes after a new release is published. -It has the benefit of relying on the GPG signatures embedded in the Debian package. +The Debian injected image is how the official Polkadot container image is produced. It relies on the Debian package that +is published upon each release. The Debian injected image is usually available a few minutes after a new release is +published. It has the benefit of relying on the GPG signatures embedded in the Debian package. ### Generic injected -For simple testing purposes, the easiest option for polkadot and also random binaries, is to use the `binary_injected.Dockerfile` container spec. This option is less secure since the injected binary is not checked at all but it has the benefit to be simple. This option requires to already have a valid `polkadot` binary, compiled for Linux. +For simple testing purposes, the easiest option for Polkadot and also random binaries, is to use the +`binary_injected.Dockerfile` container spec. This option is less secure since the injected binary is not checked at all +but it has the benefit to be simple. This option requires to already have a valid `polkadot` binary, compiled for Linux. This binary is then simply copied inside the `parity/base-bin` image. ## Reporting issues -If you run into issues with Polkadot when using docker, please run the following command -(replace the tag with the appropriate one if you do not use latest): +If you run into issues with Polkadot when using docker, please run the following command (replace the tag with the +appropriate one if you do not use latest): ```bash $ENGINE run --rm -it parity/polkadot:latest --version ``` -This will show you the Polkadot version as well as the git commit ref that was used to build your container. -You can now paste the version information in a [new issue](https://github.com/paritytech/polkadot/issues/new/choose). +This will show you the Polkadot version as well as the git commit ref that was used to build your container. You can now +paste the version information in a [new issue](https://github.com/paritytech/polkadot/issues/new/choose). diff --git a/polkadot/doc/release-checklist.md b/polkadot/doc/release-checklist.md index 4be7c9bcd5d..8c57791fed1 100644 --- a/polkadot/doc/release-checklist.md +++ b/polkadot/doc/release-checklist.md @@ -1,98 +1,91 @@ -## Notes +# Notes -### Burn In +## Burn In -Ensure that Parity DevOps has run the new release on Westend, Kusama, and -Polkadot validators for at least 12 hours prior to publishing the release. +Ensure that Parity DevOps has run the new release on Westend, Kusama, and Polkadot validators for at least 12 hours +prior to publishing the release. -### Build Artifacts +## Build Artifacts Add any necessary assets to the release. They should include: -- Linux binary -- GPG signature of the Linux binary -- SHA256 of binary -- Source code -- Wasm binaries of any runtimes +* Linux binary +* GPG signature of the Linux binary +* SHA256 of binary +* Source code +* Wasm binaries of any runtimes -### Release notes +## Release notes The release notes should list: -- The priority of the release (i.e., how quickly users should upgrade) - this is - based on the max priority of any *client* changes. -- Which native runtimes and their versions are included -- The proposal hashes of the runtimes as built with - [srtool](https://gitlab.com/chevdor/srtool) -- Any changes in this release that are still awaiting audit +* The priority of the release (i.e., how quickly users should upgrade) - this is based on the max priority of any + *client* changes. +* Which native runtimes and their versions are included +* The proposal hashes of the runtimes as built with [srtool](https://gitlab.com/chevdor/srtool) +* Any changes in this release that are still awaiting audit The release notes may also list: -- Free text at the beginning of the notes mentioning anything important - regarding this release -- Notable changes (those labelled with B[1-9]-* labels) separated into sections +* Free text at the beginning of the notes mentioning anything important regarding this release +* Notable changes (those labelled with B[1-9]-* labels) separated into sections -### Spec Version +## Spec Version -A runtime upgrade must bump the spec number. This may follow a pattern with the -client release (e.g. runtime v12 corresponds to v0.8.12, even if the current -runtime is not v11). +A runtime upgrade must bump the spec number. This may follow a pattern with the client release (e.g. runtime v12 +corresponds to v0.8.12, even if the current runtime is not v11). -### Old Migrations Removed +## Old Migrations Removed -Any previous `on_runtime_upgrade` functions from old upgrades must be removed -to prevent them from executing a second time. The `on_runtime_upgrade` function -can be found in `runtime//src/lib.rs`. +Any previous `on_runtime_upgrade` functions from old upgrades must be removed to prevent them from executing a second +time. The `on_runtime_upgrade` function can be found in `runtime//src/lib.rs`. -### New Migrations +## New Migrations -Ensure that any migrations that are required due to storage or logic changes -are included in the `on_runtime_upgrade` function of the appropriate pallets. +Ensure that any migrations that are required due to storage or logic changes are included in the `on_runtime_upgrade` +function of the appropriate pallets. -### Extrinsic Ordering +## Extrinsic Ordering -Offline signing libraries depend on a consistent ordering of call indices and -functions. Compare the metadata of the current and new runtimes and ensure that -the `module index, call index` tuples map to the same set of functions. In case +Offline signing libraries depend on a consistent ordering of call indices and functions. Compare the metadata of the +current and new runtimes and ensure that the `module index, call index` tuples map to the same set of functions. In case of a breaking change, increase `transaction_version`. -To verify the order has not changed, you may manually start the following [Github Action](https://github.com/paritytech/polkadot/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, you may manually start the following [Github +Action](https://github.com/paritytech/polkadot/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. The things to look for in the output are lines like: - - `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for `Identity` has changed - - `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. - - If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` + * `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for `Identity` has changed + * `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. + * If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` -Note: Adding new functions to the runtime does not constitute a breaking change -as long as the indexes did not change. +Note: Adding new functions to the runtime does not constitute a breaking change as long as the indexes did not change. -### Proxy Filtering +## Proxy Filtering -The runtime contains proxy filters that map proxy types to allowable calls. If -the new runtime contains any new calls, verify that the proxy filters are up to -date to include them. +The runtime contains proxy filters that map proxy types to allowable calls. If the new runtime contains any new calls, +verify that the proxy filters are up to date to include them. -### Benchmarks +## Benchmarks -There are three benchmarking machines reserved for updating the weights at -release-time. To initialise a benchmark run for each production runtime -(westend, kusama, polkadot): +There are three benchmarking machines reserved for updating the weights at release-time. To initialise a benchmark run +for each production runtime (`westend`, `kusama`, `polkadot`): * Go to https://gitlab.parity.io/parity/polkadot/-/pipelines?page=1&scope=branches&ref=master * Click the link to the last pipeline run for master * Start each of the manual jobs: - * 'update_westend_weights' - * 'update_polkadot_weights' - * 'update_kusama_weights' -* When these jobs have completed (it takes a few hours), a git PATCH file will - be available to download as an artifact. + * `update_westend_weights` + * `update_polkadot_weights` + * `update_kusama_weights` +* When these jobs have completed (it takes a few hours), a git PATCH file will be available to download as an artifact. * On your local machine, branch off master * Download the patch file and apply it to your branch with `git patch patchfile.patch` * Commit the changes to your branch and submit a PR against master -* The weights should be (Currently manually) checked to make sure there are no - big outliers (i.e., twice or half the weight). +* The weights should be (Currently manually) checked to make sure there are no big outliers (i.e., twice or half the + weight). -### Polkadot JS +## Polkadot JS -Ensure that a release of [Polkadot JS API]() contains any new types or -interfaces necessary to interact with the new runtime. +Ensure that a release of [Polkadot JS API](https://github.com/polkadot-js/api) contains any new types or interfaces +necessary to interact with the new runtime. diff --git a/polkadot/doc/shell-completion.md b/polkadot/doc/shell-completion.md index 9c53cf43a10..9761c153d5b 100644 --- a/polkadot/doc/shell-completion.md +++ b/polkadot/doc/shell-completion.md @@ -1,6 +1,7 @@ # Shell completion -The Polkadot CLI command supports shell auto-completion. For this to work, you will need to run the completion script matching you build and system. +The Polkadot CLI command supports shell auto-completion. For this to work, you will need to run the completion script +matching you build and system. Assuming you built a release version using `cargo build --release` and use `bash` run the following: @@ -30,7 +31,8 @@ source $HOME/.bash_profile ## Update -When you build a new version of Polkadot, the following will ensure you auto-completion script matches the current binary: +When you build a new version of Polkadot, the following will ensure you auto-completion script matches the current +binary: ```bash COMPL_DIR=$HOME/.completion diff --git a/polkadot/doc/testing.md b/polkadot/doc/testing.md index 78ad77e0e0f..1045303baf0 100644 --- a/polkadot/doc/testing.md +++ b/polkadot/doc/testing.md @@ -4,7 +4,7 @@ Automated testing is an essential tool to assure correctness. ## Scopes -The testing strategy for polkadot is 4-fold: +The testing strategy for Polkadot is 4-fold: ### Unit testing (1) @@ -16,18 +16,15 @@ There are two variants of integration tests: #### Subsystem tests (2) -One particular subsystem (subsystem under test) interacts with a -mocked overseer that is made to assert incoming and outgoing messages -of the subsystem under test. -This is largely present today, but has some fragmentation in the evolved -integration test implementation. A `proc-macro`/`macro_rules` would allow -for more consistent implementation and structure. +One particular subsystem (subsystem under test) interacts with a mocked overseer that is made to assert incoming and +outgoing messages of the subsystem under test. This is largely present today, but has some fragmentation in the evolved +integration test implementation. A `proc-macro`/`macro_rules` would allow for more consistent implementation and +structure. #### Behavior tests (3) -Launching small scale networks, with multiple adversarial nodes without any further tooling required. -This should include tests around the thresholds in order to evaluate the error handling once certain -assumed invariants fail. +Launching small scale networks, with multiple adversarial nodes without any further tooling required. This should +include tests around the thresholds in order to evaluate the error handling once certain assumed invariants fail. For this purpose based on `AllSubsystems` and `proc-macro` `AllSubsystemsGen`. @@ -35,18 +32,14 @@ This assumes a simplistic test runtime. #### Testing at scale (4) -Launching many nodes with configurable network speed and node features in a cluster of nodes. -At this scale the [Simnet][simnet] comes into play which launches a full cluster of nodes. -The scale is handled by spawning a kubernetes cluster and the meta description -is covered by [Gurke][Gurke]. -Asserts are made using Grafana rules, based on the existing prometheus metrics. This can -be extended by adding an additional service translating `jaeger` spans into addition -prometheus avoiding additional polkadot source changes. +Launching many nodes with configurable network speed and node features in a cluster of nodes. At this scale the +[Simnet][simnet] comes into play which launches a full cluster of nodes. The scale is handled by spawning a kubernetes +cluster and the meta description is covered by [Gurke][Gurke]. Asserts are made using Grafana rules, based on the +existing prometheus metrics. This can be extended by adding an additional service translating `jaeger` spans into +addition prometheus avoiding additional Polkadot source changes. -_Behavior tests_ and _testing at scale_ have naturally soft boundary. -The most significant difference is the presence of a real network and -the number of nodes, since a single host often not capable to run -multiple nodes at once. +_Behavior tests_ and _testing at scale_ have naturally soft boundary. The most significant difference is the presence of +a real network and the number of nodes, since a single host often not capable to run multiple nodes at once. --- @@ -54,8 +47,8 @@ multiple nodes at once. Coverage gives a _hint_ of the actually covered source lines by tests and test applications. -The state of the art is currently [tarpaulin][tarpaulin] which unfortunately yields a -lot of false negatives. Lines that are in fact covered, marked as uncovered due to a mere linebreak in a statement can cause these artifacts. This leads to +The state of the art is currently [tarpaulin][tarpaulin] which unfortunately yields a lot of false negatives. Lines that +are in fact covered, marked as uncovered due to a mere linebreak in a statement can cause these artifacts. This leads to lower coverage percentages than there actually is. Since late 2020 rust has gained [MIR based coverage tooling]( @@ -97,9 +90,11 @@ The test coverage in `lcov` can the be published to . bash <(curl -s https://codecov.io/bash) -f lcov.info ``` -or just printed as part of the PR using a github action i.e. [`jest-lcov-reporter`](https://github.com/marketplace/actions/jest-lcov-reporter). +or just printed as part of the PR using a github action i.e. +[`jest-lcov-reporter`](https://github.com/marketplace/actions/jest-lcov-reporter). -For full examples on how to use [`grcov` /w polkadot specifics see the github repo](https://github.com/mozilla/grcov#coverallscodecov-output). +For full examples on how to use [`grcov` /w Polkadot specifics see the github +repo](https://github.com/mozilla/grcov#coverallscodecov-output). ## Fuzzing @@ -109,11 +104,12 @@ Currently implemented fuzzing targets: * `erasure-coding` -The tooling of choice here is `honggfuzz-rs` as it allows _fastest_ coverage according to "some paper" which is a positive feature when run as part of PRs. +The tooling of choice here is `honggfuzz-rs` as it allows _fastest_ coverage according to "some paper" which is a +positive feature when run as part of PRs. -Fuzzing is generally not applicable for data secured by cryptographic hashes or signatures. Either the input has to be specifically crafted, such that the discarded input -percentage stays in an acceptable range. -System level fuzzing is hence simply not feasible due to the amount of state that is required. +Fuzzing is generally not applicable for data secured by cryptographic hashes or signatures. Either the input has to be +specifically crafted, such that the discarded input percentage stays in an acceptable range. System level fuzzing is +hence simply not feasible due to the amount of state that is required. Other candidates to implement fuzzing are: @@ -128,14 +124,17 @@ There are various ways of performance metrics. * cache hits/misses w/ `iai` harness or `criterion-perf` * `coz` a performance based compiler -Most of them are standard tools to aid in the creation of statistical tests regarding change in time of certain unit tests. +Most of them are standard tools to aid in the creation of statistical tests regarding change in time of certain unit +tests. -`coz` is meant for runtime. In our case, the system is far too large to yield a sufficient number of measurements in finite time. -An alternative approach could be to record incoming package streams per subsystem and store dumps of them, which in return could be replayed repeatedly at an -accelerated speed, with which enough metrics could be obtained to yield -information on which areas would improve the metrics. -This unfortunately will not yield much information, since most if not all of the subsystem code is linear based on the input to generate one or multiple output messages, it is unlikely to get any useful metrics without mocking a sufficiently large part of the other subsystem which overlaps with [#Integration tests] which is unfortunately not repeatable as of now. -As such the effort gain seems low and this is not pursued at the current time. +`coz` is meant for runtime. In our case, the system is far too large to yield a sufficient number of measurements in +finite time. An alternative approach could be to record incoming package streams per subsystem and store dumps of them, +which in return could be replayed repeatedly at an accelerated speed, with which enough metrics could be obtained to +yield information on which areas would improve the metrics. This unfortunately will not yield much information, since +most if not all of the subsystem code is linear based on the input to generate one or multiple output messages, it is +unlikely to get any useful metrics without mocking a sufficiently large part of the other subsystem which overlaps with +[#Integration tests] which is unfortunately not repeatable as of now. As such the effort gain seems low and this is not +pursued at the current time. ## Writing small scope integration tests with preconfigured workers @@ -152,29 +151,25 @@ Requirements: ### Goals -The main goals are is to allow creating a test node which -exhibits a certain behavior by utilizing a subset of _wrapped_ or _replaced_ subsystems easily. -The runtime must not matter at all for these tests and should be simplistic. -The execution must be fast, this mostly means to assure a close to zero network latency as -well as shorting the block time and epoch times down to a few `100ms` and a few dozend blocks per epoch. +The main goals are is to allow creating a test node which exhibits a certain behavior by utilizing a subset of _wrapped_ +or _replaced_ subsystems easily. The runtime must not matter at all for these tests and should be simplistic. The +execution must be fast, this mostly means to assure a close to zero network latency as well as shorting the block time +and epoch times down to a few `100ms` and a few dozend blocks per epoch. ### Approach #### MVP -A simple small scale builder pattern would suffice for stage one implementation of allowing to -replace individual subsystems. -An alternative would be to harness the existing `AllSubsystems` type -and replace the subsystems as needed. +A simple small scale builder pattern would suffice for stage one implementation of allowing to replace individual +subsystems. An alternative would be to harness the existing `AllSubsystems` type and replace the subsystems as needed. #### Full `proc-macro` implementation -`Overseer` is a common pattern. -It could be extracted as `proc` macro and generative `proc-macro`. -This would replace the `AllSubsystems` type as well as implicitly create -the `AllMessages` enum as `AllSubsystemsGen` does today. +`Overseer` is a common pattern. It could be extracted as `proc` macro and generative `proc-macro`. This would replace +the `AllSubsystems` type as well as implicitly create the `AllMessages` enum as `AllSubsystemsGen` does today. -The implementation is yet to be completed, see the [implementation PR](https://github.com/paritytech/polkadot/pull/2962) for details. +The implementation is yet to be completed, see the [implementation PR](https://github.com/paritytech/polkadot/pull/2962) +for details. ##### Declare an overseer implementation @@ -233,19 +228,16 @@ fn main() -> eyre::Result<()> { #### Simnet -Spawn a kubernetes cluster based on a meta description using [Gurke] with the -[Simnet] scripts. +Spawn a kubernetes cluster based on a meta description using [Gurke] with the [Simnet] scripts. -Coordinated attacks of multiple nodes or subsystems must be made possible via -a side-channel, that is out of scope for this document. +Coordinated attacks of multiple nodes or subsystems must be made possible via a side-channel, that is out of scope for +this document. -The individual node configurations are done as targets with a particular -builder configuration. +The individual node configurations are done as targets with a particular builder configuration. #### Behavior tests w/o Simnet -Commonly this will require multiple nodes, and most machines are limited to -running two or three nodes concurrently. +Commonly this will require multiple nodes, and most machines are limited to running two or three nodes concurrently. Hence, this is not the common case and is just an implementation _idea_. ```rust diff --git a/polkadot/erasure-coding/benches/README.md b/polkadot/erasure-coding/benches/README.md index e643643229e..94fca5400c6 100644 --- a/polkadot/erasure-coding/benches/README.md +++ b/polkadot/erasure-coding/benches/README.md @@ -1,10 +1,10 @@ -### Run benches +# Run benches ``` -$ cd erasure-coding # ensure you are in the right directory -$ cargo bench +cd erasure-coding # ensure you are in the right directory +cargo bench ``` -### `scaling_with_validators` +## `scaling_with_validators` This benchmark evaluates the performance of constructing the chunks and the erasure root from PoV and reconstructing the PoV from chunks. You can see the results of running this bench on 5950x below. diff --git a/polkadot/grafana/README.md b/polkadot/grafana/README.md index 73c5b6feacf..7350001bfa1 100644 --- a/polkadot/grafana/README.md +++ b/polkadot/grafana/README.md @@ -1,35 +1,35 @@ # Do I need this ? -Polkadot nodes collect and produce Prometheus metrics and logs. These include health, performance and debug -information such as last finalized block, height of the chain, and many other deeper implementation details -of the Polkadot/Substrate node subsystems. These are crucial pieces of information that one needs to successfully +Polkadot nodes collect and produce Prometheus metrics and logs. These include health, performance and debug +information such as last finalized block, height of the chain, and many other deeper implementation details +of the Polkadot/Substrate node subsystems. These are crucial pieces of information that one needs to successfully monitor the liveliness and performance of a network and its validators. # How does it work ? -Just import the dashboard JSON files from this folder in your Grafana installation. All dashboards are grouped in +Just import the dashboard JSON files from this folder in your Grafana installation. All dashboards are grouped in folder percategory (like for example `parachains`). The files have been created by Grafana export functionality and follow the data model specified [here](https://grafana.com/docs/grafana/latest/dashboards/json-model/). -We aim to keep the dashboards here in sync with the implementation, except dashboards for development and +We aim to keep the dashboards here in sync with the implementation, except dashboards for development and testing. # Contributing -**Your contributions are most welcome!** +**Your contributions are most welcome!** Please make sure to follow the following design guidelines: - Add a new entry in this file and describe the usecase and key metrics -- Ensure proper names and descriptions for dashboard panels and add relevant documentation when needed. -This is very important as not all users have similar depth of understanding of the implementation +- Ensure proper names and descriptions for dashboard panels and add relevant documentation when needed. +This is very important as not all users have similar depth of understanding of the implementation - Have labels for axis - All values have proper units of measurement - A crisp and clear color scheme is used # Prerequisites -Before you continue make sure you have Grafana set up, or otherwise follow this -[guide](https://wiki.polkadot.network/docs/maintain-guides-how-to-monitor-your-node). +Before you continue make sure you have Grafana set up, or otherwise follow this +[guide](https://wiki.polkadot.network/docs/maintain-guides-how-to-monitor-your-node). You might also need to [setup Loki](https://grafana.com/go/webinar/loki-getting-started/). @@ -44,7 +44,7 @@ This section is a list of dashboards, their use case as well as the key metrics ## Node Versions -Useful for monitoring versions and logs of validator nodes. Includes time series panels that +Useful for monitoring versions and logs of validator nodes. Includes time series panels that track node warning and error log rates. These can be further investigated in Grafana Loki. Requires Loki for log aggregation and querying. @@ -64,30 +64,30 @@ It includes panels covering key subsystems of the parachain node side implementa - Disputes coordinator - Chain selection -It is important to note that this dashboard applies only for validator nodes. The prometheus -queries assume the `instance` label value contains the string `validator` only for validator nodes. +It is important to note that this dashboard applies only for validator nodes. The prometheus +queries assume the `instance` label value contains the string `validator` only for validator nodes. [Dashboard JSON](parachains/status.json) ### Key liveliness indicators - **Relay chain finality lag**. How far behind finality is compared to the current best block. By design, GRANDPA never finalizes past last 2 blocks, so this value is always >=2 blocks. -- **Approval checking finality lag**. The distance (in blocks) between the chain head and the last block -on which Approval voting is happening. The block is generally the highest approved ancestor of the head +- **Approval checking finality lag**. The distance (in blocks) between the chain head and the last block +on which Approval voting is happening. The block is generally the highest approved ancestor of the head block and the metric is computed during relay chain selection. -- **Disputes finality lag**. How far behind the chain head is the last approved and non disputed block. -This value is always higher than approval checking lag as it further restricts finality to only undisputed +- **Disputes finality lag**. How far behind the chain head is the last approved and non disputed block. +This value is always higher than approval checking lag as it further restricts finality to only undisputed chains. -- **PVF preparation and execution time**. Each parachain has it's own PVF (parachain validation function): -a wasm blob that is executed by validators during backing, approval checking and disputing. The PVF -preparation time refers to the time it takes for the PVF wasm to be compiled. This step is done once and -then result cached. PVF execution will use the resulting artifact to execute the PVF for a given candidate. -PVFs are expected to have a limited execution time to ensure there is enough time left for the parachain +- **PVF preparation and execution time**. Each parachain has it's own PVF (parachain validation function): +a wasm blob that is executed by validators during backing, approval checking and disputing. The PVF +preparation time refers to the time it takes for the PVF wasm to be compiled. This step is done once and +then result cached. PVF execution will use the resulting artifact to execute the PVF for a given candidate. +PVFs are expected to have a limited execution time to ensure there is enough time left for the parachain block to be included in the relay block. -- **Time to recover and check candidate**. This is part of approval voting and covers the time it takes +- **Time to recover and check candidate**. This is part of approval voting and covers the time it takes to recover the candidate block available data from other validators, check it (includes PVF execution time) and issue statement or initiate dispute. -- **Assignment delay tranches**. Approval voting is designed such that validators assigned to check a specific -candidate are split up into equal delay tranches (0.5 seconds each). All validators checks are ordered by the delay -tranche index. Early tranches of validators have the opportunity to check the candidate first before later tranches +- **Assignment delay tranches**. Approval voting is designed such that validators assigned to check a specific +candidate are split up into equal delay tranches (0.5 seconds each). All validators checks are ordered by the delay +tranche index. Early tranches of validators have the opportunity to check the candidate first before later tranches that act as as backups in case of no shows. diff --git a/polkadot/node/gum/README.md b/polkadot/node/gum/README.md index 739ce3066ec..aed57635132 100644 --- a/polkadot/node/gum/README.md +++ b/polkadot/node/gum/README.md @@ -52,6 +52,6 @@ when providing to any of the log macros (`warn!`, `info!`, etc.). The crate has to be used throughout the entire codebase to work consistently, to disambiguate, the prefix `gum::` is used. -Feature parity with `tracing::{warn!,..}` is not desired. We want consistency +Feature Parity with `tracing::{warn!,..}` is not desired. We want consistency more than anything. All currently used features _are_ supported with _gum_ as well. diff --git a/polkadot/node/malus/README.md b/polkadot/node/malus/README.md index fb4bb0cd272..e0c7893a753 100644 --- a/polkadot/node/malus/README.md +++ b/polkadot/node/malus/README.md @@ -18,7 +18,7 @@ defined in the [(DSL[(**D**omain **S**pecific **L**anguage)]) doc](https://parit ## Usage -> Assumes you already gained permissiones, ping in element @javier:matrix.parity.io to get access. +> Assumes you already gained permissiones, ping in element `@javier:matrix.parity.io` to get access. > and you have cloned the [zombienet][zombienet] repo. To launch a test case in the development cluster use (e.g. for the ./node/malus/integrationtests/0001-dispute-valid-block.toml): @@ -48,7 +48,7 @@ This will also teardown the namespace after completion. ## Container Image Building Note In order to build the container image you need to have the latest changes from -polkadot and substrate master branches. +Polkadot and Substrate master branches. ```sh pwd # run this from the current dir diff --git a/polkadot/node/metrics/README.md b/polkadot/node/metrics/README.md index cc88884f214..0cf57006f67 100644 --- a/polkadot/node/metrics/README.md +++ b/polkadot/node/metrics/README.md @@ -1,4 +1,4 @@ -# polkadot-node-metrics +# `polkadot-node-metrics` ## Testing diff --git a/polkadot/node/test/service/README.md b/polkadot/node/test/service/README.md index 2fdee46a7f9..b0240588c44 100644 --- a/polkadot/node/test/service/README.md +++ b/polkadot/node/test/service/README.md @@ -1,4 +1,4 @@ -# polkadot-test-service +# `polkadot-test-service` ## Testing diff --git a/polkadot/parachain/test-parachains/README.md b/polkadot/parachain/test-parachains/README.md index 2c708bd5431..e679d40591b 100644 --- a/polkadot/parachain/test-parachains/README.md +++ b/polkadot/parachain/test-parachains/README.md @@ -1,3 +1,4 @@ # Test Parachains -Each parachain consists of three parts: a `#![no_std]` library with the main execution logic, a WASM crate which wraps this logic, and a collator node. +Each parachain consists of three parts: a `#![no_std]` library with the main execution logic, a WASM crate which wraps +this logic, and a collator node. diff --git a/polkadot/parachain/test-parachains/adder/collator/README.md b/polkadot/parachain/test-parachains/adder/collator/README.md index a1378544c38..dd737627c9a 100644 --- a/polkadot/parachain/test-parachains/adder/collator/README.md +++ b/polkadot/parachain/test-parachains/adder/collator/README.md @@ -19,7 +19,7 @@ Next start the collator that will collate for the adder parachain: cargo run --release -p test-parachain-adder-collator -- --tmp --chain rococo-local --port 50553 ``` -The last step is to register the parachain using polkadot-js. The parachain id is +The last step is to register the parachain using `polkadot-js`. The parachain id is 100. The genesis state and the validation code are printed at startup by the collator. To do this automatically, run `scripts/adder-collator.sh`. diff --git a/polkadot/roadmap/implementers-guide/src/README.md b/polkadot/roadmap/implementers-guide/src/README.md index 9b618999277..6673c533ece 100644 --- a/polkadot/roadmap/implementers-guide/src/README.md +++ b/polkadot/roadmap/implementers-guide/src/README.md @@ -1,5 +1,11 @@ # Preamble -This document aims to describe the purpose, functionality, and implementation of the host for Polkadot's _parachains_ functionality - that is, the software which provides security and advancement for constituent parachains. It is not for the implementer of a specific parachain but rather for the implementer of the Parachain Host. In practice, this is for the implementers of Polkadot in general. +This document aims to describe the purpose, functionality, and implementation of the host for Polkadot's _parachains_ +functionality - that is, the software which provides security and advancement for constituent parachains. It is not for +the implementer of a specific parachain but rather for the implementer of the Parachain Host. In practice, this is for +the implementers of Polkadot in general. -There are a number of other documents describing the research in more detail. All referenced documents will be linked here and should be read alongside this document for the best understanding of the full picture. However, this is the only document which aims to describe key aspects of Polkadot's particular instantiation of much of that research down to low-level technical details and software architecture. +There are a number of other documents describing the research in more detail. All referenced documents will be linked +here and should be read alongside this document for the best understanding of the full picture. However, this is the +only document which aims to describe key aspects of Polkadot's particular instantiation of much of that research down to +low-level technical details and software architecture. diff --git a/polkadot/roadmap/implementers-guide/src/SUMMARY.md b/polkadot/roadmap/implementers-guide/src/SUMMARY.md index e997d4d77ad..bb19390c7af 100644 --- a/polkadot/roadmap/implementers-guide/src/SUMMARY.md +++ b/polkadot/roadmap/implementers-guide/src/SUMMARY.md @@ -71,16 +71,16 @@ - [Chain Selection Request](node/utility/chain-selection.md) - [PVF Pre-Checking](node/utility/pvf-prechecker.md) - [Data Structures and Types](types/README.md) - - [Candidate](types/candidate.md) - - [Backing](types/backing.md) - - [Availability](types/availability.md) - - [Overseer and Subsystem Protocol](types/overseer-protocol.md) - - [Runtime](types/runtime.md) - - [Messages](types/messages.md) - - [Network](types/network.md) - - [Approvals](types/approval.md) - - [Disputes](types/disputes.md) - - [PVF Pre-checking](types/pvf-prechecking.md) + - [Candidate](types/candidate.md) + - [Backing](types/backing.md) + - [Availability](types/availability.md) + - [Overseer and Subsystem Protocol](types/overseer-protocol.md) + - [Runtime](types/runtime.md) + - [Messages](types/messages.md) + - [Network](types/network.md) + - [Approvals](types/approval.md) + - [Disputes](types/disputes.md) + - [PVF Pre-checking](types/pvf-prechecking.md) [Glossary](glossary.md) [Further Reading](further-reading.md) diff --git a/polkadot/roadmap/implementers-guide/src/architecture.md b/polkadot/roadmap/implementers-guide/src/architecture.md index 0c192a5b980..b7527066200 100644 --- a/polkadot/roadmap/implementers-guide/src/architecture.md +++ b/polkadot/roadmap/implementers-guide/src/architecture.md @@ -1,8 +1,13 @@ # Architecture Overview -This section aims to describe, at a high level, the code architecture and subsystems involved in the implementation of an individual Parachain Host. It also illuminates certain subtleties and challenges faced in the design and implementation of those subsystems. +This section aims to describe, at a high level, the code architecture and subsystems involved in the implementation of +an individual Parachain Host. It also illuminates certain subtleties and challenges faced in the design and +implementation of those subsystems. -To recap, Polkadot includes a blockchain known as the relay-chain. A blockchain is a Directed Acyclic Graph (DAG) of state transitions, where every block can be considered to be the head of a linked-list (known as a "chain" or "fork") with a cumulative state which is determined by applying the state transition of each block in turn. All paths through the DAG terminate at the Genesis Block. In fact, the blockchain is a tree, since each block can have only one parent. +To recap, Polkadot includes a blockchain known as the relay-chain. A blockchain is a Directed Acyclic Graph (DAG) of +state transitions, where every block can be considered to be the head of a linked-list (known as a "chain" or "fork") +with a cumulative state which is determined by applying the state transition of each block in turn. All paths through +the DAG terminate at the Genesis Block. In fact, the blockchain is a tree, since each block can have only one parent. ```dot process digraph { @@ -22,16 +27,25 @@ digraph { } ``` -A blockchain network is comprised of nodes. These nodes each have a view of many different forks of a blockchain and must decide which forks to follow and what actions to take based on the forks of the chain that they are aware of. +A blockchain network is comprised of nodes. These nodes each have a view of many different forks of a blockchain and +must decide which forks to follow and what actions to take based on the forks of the chain that they are aware of. -So in specifying an architecture to carry out the functionality of a Parachain Host, we have to answer two categories of questions: +So in specifying an architecture to carry out the functionality of a Parachain Host, we have to answer two categories of +questions: -1. What is the state-transition function of the blockchain? What is necessary for a transition to be considered valid, and what information is carried within the implicit state of a block? -1. Being aware of various forks of the blockchain as well as global private state such as a view of the current time, what behaviors should a node undertake? What information should a node extract from the state of which forks, and how should that information be used? +1. What is the state-transition function of the blockchain? What is necessary for a transition to be considered valid, + and what information is carried within the implicit state of a block? +1. Being aware of various forks of the blockchain as well as global private state such as a view of the current time, + what behaviors should a node undertake? What information should a node extract from the state of which forks, and how + should that information be used? -The first category of questions will be addressed by the Runtime, which defines the state-transition logic of the chain. Runtime logic only has to focus on the perspective of one chain, as each state has only a single parent state. +The first category of questions will be addressed by the Runtime, which defines the state-transition logic of the chain. +Runtime logic only has to focus on the perspective of one chain, as each state has only a single parent state. -The second category of questions addressed by Node-side behavior. Node-side behavior defines all activities that a node undertakes, given its view of the blockchain/block-DAG. Node-side behavior can take into account all or many of the forks of the blockchain, and only conditionally undertake certain activities based on which forks it is aware of, as well as the state of the head of those forks. +The second category of questions addressed by Node-side behavior. Node-side behavior defines all activities that a node +undertakes, given its view of the blockchain/block-DAG. Node-side behavior can take into account all or many of the +forks of the blockchain, and only conditionally undertake certain activities based on which forks it is aware of, as +well as the state of the head of those forks. ```dot process digraph G { @@ -46,7 +60,13 @@ digraph G { ``` -It is also helpful to divide Node-side behavior into two further categories: Networking and Core. Networking behaviors relate to how information is distributed between nodes. Core behaviors relate to internal work that a specific node does. These two categories of behavior often interact, but can be heavily abstracted from each other. Core behaviors care that information is distributed and received, but not the internal details of how distribution and receipt function. Networking behaviors act on requests for distribution or fetching of information, but are not concerned with how the information is used afterwards. This allows us to create clean boundaries between Core and Networking activities, improving the modularity of the code. +It is also helpful to divide Node-side behavior into two further categories: Networking and Core. Networking behaviors +relate to how information is distributed between nodes. Core behaviors relate to internal work that a specific node +does. These two categories of behavior often interact, but can be heavily abstracted from each other. Core behaviors +care that information is distributed and received, but not the internal details of how distribution and receipt +function. Networking behaviors act on requests for distribution or fetching of information, but are not concerned with +how the information is used afterwards. This allows us to create clean boundaries between Core and Networking +activities, improving the modularity of the code. ```text ___________________ ____________________ @@ -65,8 +85,18 @@ It is also helpful to divide Node-side behavior into two further categories: Net ``` -Node-side behavior is split up into various subsystems. Subsystems are long-lived workers that perform a particular category of work. Subsystems can communicate with each other, and do so via an [Overseer](node/overseer.md) that prevents race conditions. - -Runtime logic is divided up into Modules and APIs. Modules encapsulate particular behavior of the system. Modules consist of storage, routines, and entry-points. Routines are invoked by entry points, by other modules, upon block initialization or closing. Routines can read and alter the storage of the module. Entry-points are the means by which new information is introduced to a module and can limit the origins (user, root, parachain) that they accept being called by. Each block in the blockchain contains a set of Extrinsics. Each extrinsic targets a a specific entry point to trigger and which data should be passed to it. Runtime APIs provide a means for Node-side behavior to extract meaningful information from the state of a single fork. - -These two aspects of the implementation are heavily dependent on each other. The Runtime depends on Node-side behavior to author blocks, and to include Extrinsics which trigger the correct entry points. The Node-side behavior relies on Runtime APIs to extract information necessary to determine which actions to take. +Node-side behavior is split up into various subsystems. Subsystems are long-lived workers that perform a particular +category of work. Subsystems can communicate with each other, and do so via an [Overseer](node/overseer.md) that +prevents race conditions. + +Runtime logic is divided up into Modules and APIs. Modules encapsulate particular behavior of the system. Modules +consist of storage, routines, and entry-points. Routines are invoked by entry points, by other modules, upon block +initialization or closing. Routines can read and alter the storage of the module. Entry-points are the means by which +new information is introduced to a module and can limit the origins (user, root, parachain) that they accept being +called by. Each block in the blockchain contains a set of Extrinsics. Each extrinsic targets a a specific entry point to +trigger and which data should be passed to it. Runtime APIs provide a means for Node-side behavior to extract meaningful +information from the state of a single fork. + +These two aspects of the implementation are heavily dependent on each other. The Runtime depends on Node-side behavior +to author blocks, and to include Extrinsics which trigger the correct entry points. The Node-side behavior relies on +Runtime APIs to extract information necessary to determine which actions to take. diff --git a/polkadot/roadmap/implementers-guide/src/disputes-flow.md b/polkadot/roadmap/implementers-guide/src/disputes-flow.md index a325b2ce727..f9fd8dcce35 100644 --- a/polkadot/roadmap/implementers-guide/src/disputes-flow.md +++ b/polkadot/roadmap/implementers-guide/src/disputes-flow.md @@ -70,10 +70,12 @@ stateDiagram-v2 ## Conditional formulation -The set of validators eligible to vote consists of -the validators that had duty at the time of backing, plus backing votes by the backing validators. +The set of validators eligible to vote consists of the validators that had duty at the time of backing, plus backing +votes by the backing validators. -If a validator receives an initial dispute message (a set of votes where there are at least two opposing votes contained), and the PoV or Code are hence not reconstructable from local storage, that validator must request the required data from its peers. +If a validator receives an initial dispute message (a set of votes where there are at least two opposing votes +contained), and the PoV or Code are hence not reconstructable from local storage, that validator must request the +required data from its peers. The dispute availability message must contain code, persisted validation data, and the proof of validity. @@ -81,9 +83,11 @@ Only peers that already voted shall be queried for the dispute availability data The peer to be queried for disputes data, must be picked at random. -A validator must retain code, persisted validation data and PoV until a block, that contains the dispute resolution, is finalized - plus an additional 24 hours. +A validator must retain code, persisted validation data and PoV until a block, that contains the dispute resolution, is +finalized - plus an additional 24 hours. -Dispute availability gossip must continue beyond the dispute resolution, until the post resolution timeout expired (equiv to the timeout until which additional late votes are accepted). +Dispute availability gossip must continue beyond the dispute resolution, until the post resolution timeout expired +(equiv to the timeout until which additional late votes are accepted). Remote disputes are disputes that are in relation to a chain that is not part of the local validators active heads. @@ -93,32 +97,42 @@ Persisted votes stay persisted for `N` sessions, and are cleaned up on a per ses Votes must be queryable by a particular validator, identified by its signing key. -Votes must be queryable by a particular validator, identified by a session index and the validator index valid in that session. +Votes must be queryable by a particular validator, identified by a session index and the validator index valid in that +session. If there exists a negative and a positive vote for a particular block, a dispute is detected. If a dispute is detected, all currently available votes for that block must be gossiped. -If an incoming dispute vote is detected, a validator must cast their own vote. The vote is determined by validating the PoV with the Code at the time of backing the block in question. +If an incoming dispute vote is detected, a validator must cast their own vote. The vote is determined by validating the +PoV with the Code at the time of backing the block in question. If the validator was also a backer of the block, validation and casting an additional vote should be skipped. -If the count of votes pro or cons regarding the disputed block, reaches the required ⅔ supermajority (including the backing votes), the conclusion must be recorded on chain and the voters on the loosing and no-shows being slashed appropriately. +If the count of votes pro or cons regarding the disputed block, reaches the required ⅔ supermajority (including the +backing votes), the conclusion must be recorded on chain and the voters on the loosing and no-shows being slashed +appropriately. -If a block is found invalid by a dispute resolution, it must be blacklisted to avoid resync or further build on that chain if other chains are available (to be detailed in the grandpa fork choice rule). +If a block is found invalid by a dispute resolution, it must be blacklisted to avoid resync or further build on that +chain if other chains are available (to be detailed in the grandpa fork choice rule). A dispute accepts Votes after the dispute is resolved, for 1 day. -If a vote is received, after the dispute is resolved, the vote shall still be recorded in the state root, albeit yielding less reward. +If a vote is received, after the dispute is resolved, the vote shall still be recorded in the state root, albeit +yielding less reward. Recording in the state root might happen batched, at timeout expiry. -If a new active head/chain appears, and the dispute resolution was not recorded on that chain yet, the dispute resolution or open dispute must be recorded / transplanted to that chain as well, since the disputes must be present on all chains to make sure the offender is punished. +If a new active head/chain appears, and the dispute resolution was not recorded on that chain yet, the dispute +resolution or open dispute must be recorded / transplanted to that chain as well, since the disputes must be present on +all chains to make sure the offender is punished. -If a validator votes in two opposing ways, this composes of a double vote like in other cases (backing, approval voting). +If a validator votes in two opposing ways, this composes of a double vote like in other cases (backing, approval +voting). If a dispute is not resolved within due time, all validators are to be slashed for a small amount. If a dispute is not resolved within due time, governance mode shall be entered for manual resolution. -If a validator unexpectedly restarts, the dispute shall be continued with the state based on votes being cast and being present in persistent storage. +If a validator unexpectedly restarts, the dispute shall be continued with the state based on votes being cast and being +present in persistent storage. diff --git a/polkadot/roadmap/implementers-guide/src/glossary.md b/polkadot/roadmap/implementers-guide/src/glossary.md index a036ccdd668..b2365ba51c5 100644 --- a/polkadot/roadmap/implementers-guide/src/glossary.md +++ b/polkadot/roadmap/implementers-guide/src/glossary.md @@ -2,46 +2,72 @@ Here you can find definitions of a bunch of jargon, usually specific to the Polkadot project. -- **Approval Checker:** A validator who randomly self-selects so to perform validity checks on a parablock which is pending approval. -- **BABE:** (Blind Assignment for Blockchain Extension). The algorithm validators use to safely extend the Relay Chain. See [the Polkadot wiki][0] for more information. -- **Backable Candidate:** A Parachain Candidate which is backed by a majority of validators assigned to a given parachain. +- **Approval Checker:** A validator who randomly self-selects so to perform validity checks on a parablock which is + pending approval. +- **BABE:** (Blind Assignment for Blockchain Extension). The algorithm validators use to safely extend the Relay Chain. + See [the Polkadot wiki][0] for more information. +- **Backable Candidate:** A Parachain Candidate which is backed by a majority of validators assigned to a given + parachain. - **Backed Candidate:** A Backable Candidate noted in a relay-chain block - **Backing:** A set of statements proving that a Parachain Candidate is backable. - **Collator:** A node who generates Proofs-of-Validity (PoV) for blocks of a specific parachain. -- **DMP:** (Downward Message Passing). Message passing from the relay-chain to a parachain. Also there is a runtime parachains module with the same name. -- **DMQ:** (Downward Message Queue). A message queue for messages from the relay-chain down to a parachain. A parachain has -exactly one downward message queue. -- **Extrinsic:** An element of a relay-chain block which triggers a specific entry-point of a runtime module with given arguments. -- **GRANDPA:** (Ghost-based Recursive ANcestor Deriving Prefix Agreement). The algorithm validators use to guarantee finality of the Relay Chain. -- **HRMP:** (Horizontally Relay-routed Message Passing). A mechanism for message passing between parachains (hence horizontal) that leverages the relay-chain storage. Predates XCMP. Also there is a runtime parachains module with the same name. -- **Inclusion Pipeline:** The set of steps taken to carry a Parachain Candidate from authoring, to backing, to availability and full inclusion in an active fork of its parachain. +- **DMP:** (Downward Message Passing). Message passing from the relay-chain to a parachain. Also there is a runtime + parachains module with the same name. +- **DMQ:** (Downward Message Queue). A message queue for messages from the relay-chain down to a parachain. A parachain +has exactly one downward message queue. +- **Extrinsic:** An element of a relay-chain block which triggers a specific entry-point of a runtime module with given + arguments. +- **GRANDPA:** (Ghost-based Recursive ANcestor Deriving Prefix Agreement). The algorithm validators use to guarantee + finality of the Relay Chain. +- **HRMP:** (Horizontally Relay-routed Message Passing). A mechanism for message passing between parachains (hence + horizontal) that leverages the relay-chain storage. Predates XCMP. Also there is a runtime parachains module with the + same name. +- **Inclusion Pipeline:** The set of steps taken to carry a Parachain Candidate from authoring, to backing, to + availability and full inclusion in an active fork of its parachain. - **Module:** A component of the Runtime logic, encapsulating storage, routines, and entry-points. - **Module Entry Point:** A recipient of new information presented to the Runtime. This may trigger routines. -- **Module Routine:** A piece of code executed within a module by block initialization, closing, or upon an entry point being triggered. This may execute computation, and read or write storage. -- **MQC:** (Message Queue Chain). A cryptographic data structure that resembles an append-only linked list which doesn't store original values but only their hashes. The whole structure is described by a single hash, referred as a "head". When a value is appended, it's contents hashed with the previous head creating a hash that becomes a new head. -- **Node:** A participant in the Polkadot network, who follows the protocols of communication and connection to other nodes. Nodes form a peer-to-peer network topology without a central authority. +- **Module Routine:** A piece of code executed within a module by block initialization, closing, or upon an entry point + being triggered. This may execute computation, and read or write storage. +- **MQC:** (Message Queue Chain). A cryptographic data structure that resembles an append-only linked list which doesn't + store original values but only their hashes. The whole structure is described by a single hash, referred as a "head". + When a value is appended, it's contents hashed with the previous head creating a hash that becomes a new head. +- **Node:** A participant in the Polkadot network, who follows the protocols of communication and connection to other + nodes. Nodes form a peer-to-peer network topology without a central authority. - **Parachain Candidate, or Candidate:** A proposed block for inclusion into a parachain. - **Parablock:** A block in a parachain. - **Parachain:** A constituent chain secured by the Relay Chain's validators. -- **Parachain Validators:** A subset of validators assigned during a period of time to back candidates for a specific parachain +- **Parachain Validators:** A subset of validators assigned during a period of time to back candidates for a specific + parachain - **On-demand parachain:** A parachain which is scheduled on a pay-as-you-go basis. -- **Lease holding parachain:** A parachain possessing an active slot lease. The lease holder is assigned a single availability core for the duration of the lease, granting consistent blockspace scheduling at the rate 1 parablock per relay block. +- **Lease holding parachain:** A parachain possessing an active slot lease. The lease holder is assigned a single + availability core for the duration of the lease, granting consistent blockspace scheduling at the rate 1 parablock per + relay block. - **PDK (Parachain Development Kit):** A toolset that allows one to develop a parachain. Cumulus is a PDK. -- **Preimage:** In our context, if `H(X) = Y` where `H` is a hash function and `Y` is the hash, then `X` is the hash preimage. -- **Proof-of-Validity (PoV):** A stateless-client proof that a parachain candidate is valid, with respect to some validation function. +- **Preimage:** In our context, if `H(X) = Y` where `H` is a hash function and `Y` is the hash, then `X` is the hash + preimage. +- **Proof-of-Validity (PoV):** A stateless-client proof that a parachain candidate is valid, with respect to some + validation function. - **PVF:** Parachain Validation Function. The validation code that is run by validators on parachains. -- **PVF Prechecking:** This is the process of initially checking the PVF when it is first added. We attempt preparation of the PVF and make sure it succeeds within a given timeout, plus some additional checks. -- **PVF Preparation:** This is the process of preparing the WASM blob and includes both prevalidation and compilation. As there is no prevalidation right now, preparation just consists of compilation. -- **Relay Parent:** A block in the relay chain, referred to in a context where work is being done in the context of the state at this block. +- **PVF Prechecking:** This is the process of initially checking the PVF when it is first added. We attempt preparation + of the PVF and make sure it succeeds within a given timeout, plus some additional checks. +- **PVF Preparation:** This is the process of preparing the WASM blob and includes both prevalidation and compilation. + As there is no prevalidation right now, preparation just consists of compilation. +- **Relay Parent:** A block in the relay chain, referred to in a context where work is being done in the context of the + state at this block. - **Runtime:** The relay-chain state machine. - **Runtime Module:** See Module. -- **Runtime API:** A means for the node-side behavior to access structured information based on the state of a fork of the blockchain. +- **Runtime API:** A means for the node-side behavior to access structured information based on the state of a fork of + the blockchain. - **Subsystem:** A long-running task which is responsible for carrying out a particular category of work. - **UMP:** (Upward Message Passing) A vertical message passing mechanism from a parachain to the relay chain. -- **Validator:** Specially-selected node in the network who is responsible for validating parachain blocks and issuing attestations about their validity. +- **Validator:** Specially-selected node in the network who is responsible for validating parachain blocks and issuing + attestations about their validity. - **Validation Function:** A piece of Wasm code that describes the state-transition function of a parachain. -- **VMP:** (Vertical Message Passing) A family of mechanisms that are responsible for message exchange between the relay chain and parachains. -- **XCMP:** (Cross-Chain Message Passing) A type of horizontal message passing (i.e. between parachains) that allows secure message passing directly between parachains and has minimal resource requirements from the relay chain, thus highly scalable. +- **VMP:** (Vertical Message Passing) A family of mechanisms that are responsible for message exchange between the relay + chain and parachains. +- **XCMP:** (Cross-Chain Message Passing) A type of horizontal message passing (i.e. between parachains) that allows + secure message passing directly between parachains and has minimal resource requirements from the relay chain, thus + highly scalable. ## See Also diff --git a/polkadot/roadmap/implementers-guide/src/messaging.md b/polkadot/roadmap/implementers-guide/src/messaging.md index edc810e0341..11cd3565e8e 100644 --- a/polkadot/roadmap/implementers-guide/src/messaging.md +++ b/polkadot/roadmap/implementers-guide/src/messaging.md @@ -1,9 +1,9 @@ # Messaging Overview -The Polkadot Host has a few mechanisms that are responsible for message passing. They can be generally divided -on two categories: Horizontal and Vertical. Horizontal Message Passing (HMP) refers to mechanisms -that are responsible for exchanging messages between parachains. Vertical Message Passing (VMP) is -used for communication between the relay chain and parachains. +The Polkadot Host has a few mechanisms that are responsible for message passing. They can be generally divided on two +categories: Horizontal and Vertical. Horizontal Message Passing (HMP) refers to mechanisms that are responsible for +exchanging messages between parachains. Vertical Message Passing (VMP) is used for communication between the relay chain +and parachains. ## Vertical Message Passing @@ -19,35 +19,34 @@ digraph { Downward Message Passing (DMP) is a mechanism for delivering messages to parachains from the relay chain. -Each parachain has its own queue that stores all pending inbound downward messages. A parachain -doesn't have to process all messages at once, however, there are rules as to how the downward message queue -should be processed. Currently, at least one message must be consumed per candidate if the queue is not empty. -The downward message queue doesn't have a cap on its size and it is up to the relay-chain to put mechanisms -that prevent spamming in place. +Each parachain has its own queue that stores all pending inbound downward messages. A parachain doesn't have to process +all messages at once, however, there are rules as to how the downward message queue should be processed. Currently, at +least one message must be consumed per candidate if the queue is not empty. The downward message queue doesn't have a +cap on its size and it is up to the relay-chain to put mechanisms that prevent spamming in place. -Upward Message Passing (UMP) is a mechanism responsible for delivering messages in the opposite direction: -from a parachain up to the relay chain. Upward messages are essentially byte blobs. However, they are interpreted -by the relay-chain according to the XCM standard. +Upward Message Passing (UMP) is a mechanism responsible for delivering messages in the opposite direction: from a +parachain up to the relay chain. Upward messages are essentially byte blobs. However, they are interpreted by the +relay-chain according to the XCM standard. -The XCM standard is a common vocabulary of messages. The XCM standard doesn't require a particular interpretation of -a message. However, the parachains host (e.g. Polkadot) guarantees certain semantics for those. +The XCM standard is a common vocabulary of messages. The XCM standard doesn't require a particular interpretation of a +message. However, the parachains host (e.g. Polkadot) guarantees certain semantics for those. -Moreover, while most XCM messages are handled by the on-chain XCM interpreter, some of the messages are special -cased. Specifically, those messages can be checked during the acceptance criteria and thus invalid -messages would lead to rejecting the candidate itself. +Moreover, while most XCM messages are handled by the on-chain XCM interpreter, some of the messages are special cased. +Specifically, those messages can be checked during the acceptance criteria and thus invalid messages would lead to +rejecting the candidate itself. -One kind of such a message is `Xcm::Transact`. This upward message can be seen as a way for a parachain -to execute arbitrary entrypoints on the relay-chain. `Xcm::Transact` messages resemble regular extrinsics with the exception that they -originate from a parachain. +One kind of such a message is `Xcm::Transact`. This upward message can be seen as a way for a parachain to execute +arbitrary entrypoints on the relay-chain. `Xcm::Transact` messages resemble regular extrinsics with the exception that +they originate from a parachain. -The payload of `Xcm::Transact` messages is referred as to `Dispatchable`. When a candidate with such a message is enacted -the dispatchables are put into a queue corresponding to the parachain. There can be only so many dispatchables in that queue at once. -The weight that processing of the dispatchables can consume is limited by a preconfigured value. Therefore, it is possible -that some dispatchables will be left for later blocks. To make the dispatching more fair, the queues are processed turn-by-turn -in a round robin fashion. +The payload of `Xcm::Transact` messages is referred as to `Dispatchable`. When a candidate with such a message is +enacted the dispatchables are put into a queue corresponding to the parachain. There can be only so many dispatchables +in that queue at once. The weight that processing of the dispatchables can consume is limited by a preconfigured value. +Therefore, it is possible that some dispatchables will be left for later blocks. To make the dispatching more fair, the +queues are processed turn-by-turn in a round robin fashion. -The second category of special cased XCM messages are for horizontal messaging channel management, -namely messages meant to request opening and closing HRMP channels (HRMP will be described below). +The second category of special cased XCM messages are for horizontal messaging channel management, namely messages meant +to request opening and closing HRMP channels (HRMP will be described below). ## Horizontal Message Passing @@ -77,29 +76,28 @@ The most important member of this family is XCMP. > ℹ️ XCMP is currently under construction and details are subject for change. -XCMP is a message passing mechanism between parachains that require minimal involvement of the relay chain. -The relay chain provides means for sending parachains to authenticate messages sent to recipient parachains. +XCMP is a message passing mechanism between parachains that require minimal involvement of the relay chain. The relay +chain provides means for sending parachains to authenticate messages sent to recipient parachains. -Semantically communication occurs through so called channels. A channel is unidirectional and it has -two endpoints, for sender and for recipient. A channel can be opened only if the both parties agree -and closed unilaterally. +Semantically communication occurs through so called channels. A channel is unidirectional and it has two endpoints, for +sender and for recipient. A channel can be opened only if the both parties agree and closed unilaterally. -Only the channel metadata is stored on the relay-chain in a very compact form: all messages and their -contents sent by the sender parachain are encoded using only one root hash. This root is referred as -MQC head. +Only the channel metadata is stored on the relay-chain in a very compact form: all messages and their contents sent by +the sender parachain are encoded using only one root hash. This root is referred as MQC head. -The authenticity of the messages must be proven using that root hash to the receiving party at the -candidate authoring time. The proof stems from the relay parent storage that contains the root hash of the channel. -Since not all messages are required to be processed by the receiver's candidate, only the processed -messages are supplied (i.e. preimages), rest are provided as hashes. +The authenticity of the messages must be proven using that root hash to the receiving party at the candidate authoring +time. The proof stems from the relay parent storage that contains the root hash of the channel. Since not all messages +are required to be processed by the receiver's candidate, only the processed messages are supplied (i.e. preimages), +rest are provided as hashes. -Further details can be found at the official repository for the -[Cross-Consensus Message Format (XCM)](https://github.com/paritytech/xcm-format/blob/master/README.md), as well as -at the [W3F research website](https://research.web3.foundation/en/latest/polkadot/XCMP.html) and -[this blogpost](https://medium.com/web3foundation/polkadots-messaging-scheme-b1ec560908b7). +Further details can be found at the official repository for the [Cross-Consensus Message Format +(XCM)](https://github.com/paritytech/xcm-format/blob/master/README.md), as well as at the [W3F research +website](https://research.web3.foundation/en/latest/polkadot/XCMP.html) and [this +blogpost](https://medium.com/web3foundation/polkadots-messaging-scheme-b1ec560908b7). -HRMP (Horizontally Relay-routed Message Passing) is a stop gap that predates XCMP. Semantically, it mimics XCMP's interface. -The crucial difference from XCMP though is that all the messages are stored in the relay-chain storage. That makes -things simple but at the same time that makes HRMP more demanding in terms of resources thus making it more expensive. +HRMP (Horizontally Relay-routed Message Passing) is a stop gap that predates XCMP. Semantically, it mimics XCMP's +interface. The crucial difference from XCMP though is that all the messages are stored in the relay-chain storage. That +makes things simple but at the same time that makes HRMP more demanding in terms of resources thus making it more +expensive. Once XCMP is available we expect to retire HRMP. diff --git a/polkadot/roadmap/implementers-guide/src/node/README.md b/polkadot/roadmap/implementers-guide/src/node/README.md index edd72d2335b..c67f2b0b82e 100644 --- a/polkadot/roadmap/implementers-guide/src/node/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/README.md @@ -2,30 +2,49 @@ ## Design Goals -* Modularity: Components of the system should be as self-contained as possible. Communication boundaries between components should be well-defined and mockable. This is key to creating testable, easily reviewable code. -* Minimizing side effects: Components of the system should aim to minimize side effects and to communicate with other components via message-passing. -* Operational Safety: The software will be managing signing keys where conflicting messages can lead to large amounts of value to be slashed. Care should be taken to ensure that no messages are signed incorrectly or in conflict with each other. +* Modularity: Components of the system should be as self-contained as possible. Communication boundaries between + components should be well-defined and mockable. This is key to creating testable, easily reviewable code. +* Minimizing side effects: Components of the system should aim to minimize side effects and to communicate with other + components via message-passing. +* Operational Safety: The software will be managing signing keys where conflicting messages can lead to large amounts of + value to be slashed. Care should be taken to ensure that no messages are signed incorrectly or in conflict with each + other. -The architecture of the node-side behavior aims to embody the Rust principles of ownership and message-passing to create clean, isolatable code. Each resource should have a single owner, with minimal sharing where unavoidable. +The architecture of the node-side behavior aims to embody the Rust principles of ownership and message-passing to create +clean, isolatable code. Each resource should have a single owner, with minimal sharing where unavoidable. -Many operations that need to be carried out involve the network, which is asynchronous. This asynchrony affects all core subsystems that rely on the network as well. The approach of hierarchical state machines is well-suited to this kind of environment. +Many operations that need to be carried out involve the network, which is asynchronous. This asynchrony affects all core +subsystems that rely on the network as well. The approach of hierarchical state machines is well-suited to this kind of +environment. We introduce ## Components The node architecture consists of the following components: - * The Overseer (and subsystems): A hierarchy of state machines where an overseer supervises subsystems. Subsystems can contain their own internal hierarchy of jobs. This is elaborated on in the next section on Subsystems. + * The Overseer (and subsystems): A hierarchy of state machines where an overseer supervises subsystems. Subsystems can + contain their own internal hierarchy of jobs. This is elaborated on in the next section on Subsystems. * A block proposer: Logic triggered by the consensus algorithm of the chain when the node should author a block. - * A GRANDPA voting rule: A strategy for selecting chains to vote on in the GRANDPA algorithm to ensure that only valid parachain candidates appear in finalized relay-chain blocks. + * A GRANDPA voting rule: A strategy for selecting chains to vote on in the GRANDPA algorithm to ensure that only valid + parachain candidates appear in finalized relay-chain blocks. ## Assumptions -The Node-side code comes with a set of assumptions that we build upon. These assumptions encompass most of the fundamental blockchain functionality. +The Node-side code comes with a set of assumptions that we build upon. These assumptions encompass most of the +fundamental blockchain functionality. We assume the following constraints regarding provided basic functionality: * The underlying **consensus** algorithm, whether it is BABE or SASSAFRAS is implemented. - * There is a **chain synchronization** protocol which will search for and download the longest available chains at all times. - * The **state** of all blocks at the head of the chain is available. There may be **state pruning** such that state of the last `k` blocks behind the last finalized block are available, as well as the state of all their descendants. This assumption implies that the state of all active leaves and their last `k` ancestors are all available. The underlying implementation is expected to support `k` of a few hundred blocks, but we reduce this to a very conservative `k=5` for our purposes. - * There is an underlying **networking** framework which provides **peer discovery** services which will provide us with peers and will not create "loopback" connections to our own node. The number of peers we will have is assumed to be bounded at 1000. - * There is a **transaction pool** and a **transaction propagation** mechanism which maintains a set of current transactions and distributes to connected peers. Current transactions are those which are not outdated relative to some "best" fork of the chain, which is part of the active heads, and have not been included in the best fork. + * There is a **chain synchronization** protocol which will search for and download the longest available chains at all + times. + * The **state** of all blocks at the head of the chain is available. There may be **state pruning** such that state of + the last `k` blocks behind the last finalized block are available, as well as the state of all their descendants. + This assumption implies that the state of all active leaves and their last `k` ancestors are all available. The + underlying implementation is expected to support `k` of a few hundred blocks, but we reduce this to a very + conservative `k=5` for our purposes. + * There is an underlying **networking** framework which provides **peer discovery** services which will provide us + with peers and will not create "loopback" connections to our own node. The number of peers we will have is assumed + to be bounded at 1000. + * There is a **transaction pool** and a **transaction propagation** mechanism which maintains a set of current + transactions and distributes to connected peers. Current transactions are those which are not outdated relative to + some "best" fork of the chain, which is part of the active heads, and have not been included in the best fork. diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/README.md b/polkadot/roadmap/implementers-guide/src/node/approval/README.md index 1f65173e16b..ae9f46674e5 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/README.md @@ -2,6 +2,9 @@ The approval subsystems implement the node-side of the [Approval Protocol](../../protocol-approval.md). -We make a divide between the [assignment/voting logic](approval-voting.md) and the [distribution logic](approval-distribution.md) that distributes assignment certifications and approval votes. The logic in the assignment and voting also informs the GRANDPA voting rule on how to vote. +We make a divide between the [assignment/voting logic](approval-voting.md) and the [distribution +logic](approval-distribution.md) that distributes assignment certifications and approval votes. The logic in the +assignment and voting also informs the GRANDPA voting rule on how to vote. -These subsystems are intended to flag issues and begin participating in live disputes. Dispute subsystems also track all observed votes (backing, approval, and dispute-specific) by all validators on all candidates. +These subsystems are intended to flag issues and begin participating in live disputes. Dispute subsystems also track all +observed votes (backing, approval, and dispute-specific) by all validators on all candidates. diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md index 81c98afa16b..ce71de6f76b 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md @@ -2,50 +2,73 @@ A subsystem for the distribution of assignments and approvals for approval checks on candidates over the network. -The [Approval Voting](approval-voting.md) subsystem is responsible for active participation in a protocol designed to select a sufficient number of validators to check each and every candidate which appears in the relay chain. Statements of participation in this checking process are divided into two kinds: - - **Assignments** indicate that validators have been selected to do checking - - **Approvals** indicate that validators have checked and found the candidate satisfactory. - -The [Approval Voting](approval-voting.md) subsystem handles all the issuing and tallying of this protocol, but this subsystem is responsible for the disbursal of statements among the validator-set. - -The inclusion pipeline of candidates concludes after availability, and only after inclusion do candidates actually get pushed into the approval checking pipeline. As such, this protocol deals with the candidates _made available by_ particular blocks, as opposed to the candidates which actually appear within those blocks, which are the candidates _backed by_ those blocks. Unless stated otherwise, whenever we reference a candidate partially by block hash, we are referring to the set of candidates _made available by_ those blocks. - -We implement this protocol as a gossip protocol, and like other parachain-related gossip protocols our primary concerns are about ensuring fast message propagation while maintaining an upper bound on the number of messages any given node must store at any time. - -Approval messages should always follow assignments, so we need to be able to discern two pieces of information based on our [View](../../types/network.md#universal-types): +The [Approval Voting](approval-voting.md) subsystem is responsible for active participation in a protocol designed to +select a sufficient number of validators to check each and every candidate which appears in the relay chain. Statements +of participation in this checking process are divided into two kinds: + * **Assignments** indicate that validators have been selected to do checking + * **Approvals** indicate that validators have checked and found the candidate satisfactory. + +The [Approval Voting](approval-voting.md) subsystem handles all the issuing and tallying of this protocol, but this +subsystem is responsible for the disbursal of statements among the validator-set. + +The inclusion pipeline of candidates concludes after availability, and only after inclusion do candidates actually get +pushed into the approval checking pipeline. As such, this protocol deals with the candidates _made available by_ +particular blocks, as opposed to the candidates which actually appear within those blocks, which are the candidates +_backed by_ those blocks. Unless stated otherwise, whenever we reference a candidate partially by block hash, we are +referring to the set of candidates _made available by_ those blocks. + +We implement this protocol as a gossip protocol, and like other parachain-related gossip protocols our primary concerns +are about ensuring fast message propagation while maintaining an upper bound on the number of messages any given node +must store at any time. + +Approval messages should always follow assignments, so we need to be able to discern two pieces of information based on +our [View](../../types/network.md#universal-types): 1. Is a particular assignment relevant under a given `View`? 2. Is a particular approval relevant to any assignment in a set? -For our own local view, these two queries must not yield false negatives. When applied to our peers' views, it is acceptable for them to yield false negatives. The reason for that is that our peers' views may be beyond ours, and we are not capable of fully evaluating them. Once we have caught up, we can check again for false negatives to continue distributing. +For our own local view, these two queries must not yield false negatives. When applied to our peers' views, it is +acceptable for them to yield false negatives. The reason for that is that our peers' views may be beyond ours, and we +are not capable of fully evaluating them. Once we have caught up, we can check again for false negatives to continue +distributing. -For assignments, what we need to be checking is whether we are aware of the (block, candidate) pair that the assignment references. For approvals, we need to be aware of an assignment by the same validator which references the candidate being approved. +For assignments, what we need to be checking is whether we are aware of the (block, candidate) pair that the assignment +references. For approvals, we need to be aware of an assignment by the same validator which references the candidate +being approved. -However, awareness on its own of a (block, candidate) pair would imply that even ancient candidates all the way back to the genesis are relevant. We are actually not interested in anything before finality. +However, awareness on its own of a (block, candidate) pair would imply that even ancient candidates all the way back to +the genesis are relevant. We are actually not interested in anything before finality. -We gossip assignments along a grid topology produced by the [Gossip Support Subsystem](../utility/gossip-support.md) and also to a few random peers. The first time we accept an assignment or approval, regardless of the source, which originates from a validator peer in a shared dimension of the grid, we propagate the message to validator peers in the unshared dimension as well as a few random peers. +We gossip assignments along a grid topology produced by the [Gossip Support Subsystem](../utility/gossip-support.md) and +also to a few random peers. The first time we accept an assignment or approval, regardless of the source, which +originates from a validator peer in a shared dimension of the grid, we propagate the message to validator peers in the +unshared dimension as well as a few random peers. -But, in case these mechanisms don't work on their own, we need to trade bandwidth for protocol liveness by introducing aggression. +But, in case these mechanisms don't work on their own, we need to trade bandwidth for protocol liveness by introducing +aggression. Aggression has 3 levels: - Aggression Level 0: The basic behaviors described above. - Aggression Level 1: The originator of a message sends to all peers. Other peers follow the rules above. - Aggression Level 2: All peers send all messages to all their row and column neighbors. This means that each validator will, on average, receive each message approximately 2*sqrt(n) times. +* Aggression Level 0: The basic behaviors described above. +* Aggression Level 1: The originator of a message sends to all peers. Other peers follow the rules above. +* Aggression Level 2: All peers send all messages to all their row and column neighbors. This means that each validator + will, on average, receive each message approximately 2*sqrt(n) times. -These aggression levels are chosen based on how long a block has taken to finalize: assignments and approvals related to the unfinalized block will be propagated with more aggression. In particular, it's only the earliest unfinalized blocks that aggression should be applied to, because descendants may be unfinalized only by virtue of being descendants. +These aggression levels are chosen based on how long a block has taken to finalize: assignments and approvals related to +the unfinalized block will be propagated with more aggression. In particular, it's only the earliest unfinalized blocks +that aggression should be applied to, because descendants may be unfinalized only by virtue of being descendants. ## Protocol Input: - - `ApprovalDistributionMessage::NewBlocks` - - `ApprovalDistributionMessage::DistributeAssignment` - - `ApprovalDistributionMessage::DistributeApproval` - - `ApprovalDistributionMessage::NetworkBridgeUpdate` - - `OverseerSignal::BlockFinalized` + * `ApprovalDistributionMessage::NewBlocks` + * `ApprovalDistributionMessage::DistributeAssignment` + * `ApprovalDistributionMessage::DistributeApproval` + * `ApprovalDistributionMessage::NetworkBridgeUpdate` + * `OverseerSignal::BlockFinalized` Output: - - `ApprovalVotingMessage::CheckAndImportAssignment` - - `ApprovalVotingMessage::CheckAndImportApproval` - - `NetworkBridgeMessage::SendValidationMessage::ApprovalDistribution` + * `ApprovalVotingMessage::CheckAndImportAssignment` + * `ApprovalVotingMessage::CheckAndImportApproval` + * `NetworkBridgeMessage::SendValidationMessage::ApprovalDistribution` ## Functionality @@ -134,28 +157,37 @@ Iterate over every `BlockEntry` and remove `PeerId` from it. #### `NetworkBridgeEvent::OurViewChange` -Remove entries in `pending_known` for all hashes not present in the view. -Ensure a vector is present in `pending_known` for each hash in the view that does not have an entry in `blocks`. +Remove entries in `pending_known` for all hashes not present in the view. Ensure a vector is present in `pending_known` +for each hash in the view that does not have an entry in `blocks`. #### `NetworkBridgeEvent::PeerViewChange` Invoke `unify_with_peer(peer, view)` to catch them up to messages we have. -We also need to use the `view.finalized_number` to remove the `PeerId` from any blocks that it won't be wanting information about anymore. Note that we have to be on guard for peers doing crazy stuff like jumping their `finalized_number` forward 10 trillion blocks to try and get us stuck in a loop for ages. +We also need to use the `view.finalized_number` to remove the `PeerId` from any blocks that it won't be wanting +information about anymore. Note that we have to be on guard for peers doing crazy stuff like jumping their +`finalized_number` forward 10 trillion blocks to try and get us stuck in a loop for ages. -One of the safeguards we can implement is to reject view updates from peers where the new `finalized_number` is less than the previous. +One of the safeguards we can implement is to reject view updates from peers where the new `finalized_number` is less +than the previous. -We augment that by defining `constrain(x)` to output the x bounded by the first and last numbers in `state.blocks_by_number`. +We augment that by defining `constrain(x)` to output the x bounded by the first and last numbers in +`state.blocks_by_number`. -From there, we can loop backwards from `constrain(view.finalized_number)` until `constrain(last_view.finalized_number)` is reached, removing the `PeerId` from all `BlockEntry`s referenced at that height. We can break the loop early if we ever exit the bound supplied by the first block in `state.blocks_by_number`. +From there, we can loop backwards from `constrain(view.finalized_number)` until `constrain(last_view.finalized_number)` +is reached, removing the `PeerId` from all `BlockEntry`s referenced at that height. We can break the loop early if we +ever exit the bound supplied by the first block in `state.blocks_by_number`. #### `NetworkBridgeEvent::PeerMessage` -If the block hash referenced by the message exists in `pending_known`, add it to the vector of pending messages and return. +If the block hash referenced by the message exists in `pending_known`, add it to the vector of pending messages and +return. -If the message is of type `ApprovalDistributionV1Message::Assignment(assignment_cert, claimed_index)`, then call `import_and_circulate_assignment(MessageSource::Peer(sender), assignment_cert, claimed_index)` +If the message is of type `ApprovalDistributionV1Message::Assignment(assignment_cert, claimed_index)`, then call +`import_and_circulate_assignment(MessageSource::Peer(sender), assignment_cert, claimed_index)` -If the message is of type `ApprovalDistributionV1Message::Approval(approval_vote)`, then call `import_and_circulate_approval(MessageSource::Peer(sender), approval_vote)` +If the message is of type `ApprovalDistributionV1Message::Approval(approval_vote)`, then call +`import_and_circulate_approval(MessageSource::Peer(sender), approval_vote)` ### Subsystem Updates @@ -164,7 +196,8 @@ If the message is of type `ApprovalDistributionV1Message::Approval(approval_vote Create `BlockEntry` and `CandidateEntries` for all blocks. For all entries in `pending_known`: - * If there is now an entry under `blocks` for the block hash, drain all messages and import with `import_and_circulate_assignment` and `import_and_circulate_approval`. + * If there is now an entry under `blocks` for the block hash, drain all messages and import with + `import_and_circulate_assignment` and `import_and_circulate_approval`. For all peers: * Compute `view_intersection` as the intersection of the peer's view blocks with the hashes of the new blocks. @@ -180,7 +213,8 @@ Call `import_and_circulate_approval` with `MessageSource::Local`. #### `OverseerSignal::BlockFinalized` -Prune all lists from `blocks_by_number` with number less than or equal to `finalized_number`. Prune all the `BlockEntry`s referenced by those lists. +Prune all lists from `blocks_by_number` with number less than or equal to `finalized_number`. Prune all the +`BlockEntry`s referenced by those lists. ### Utility @@ -192,9 +226,14 @@ enum MessageSource { } ``` -#### `import_and_circulate_assignment(source: MessageSource, assignment: IndirectAssignmentCert, claimed_candidate_index: CandidateIndex)` +#### `import_and_circulate_assignment(...)` -Imports an assignment cert referenced by block hash and candidate index. As a postcondition, if the cert is valid, it will have distributed the cert to all peers who have the block in their view, with the exclusion of the peer referenced by the `MessageSource`. +`import_and_circulate_assignment(source: MessageSource, assignment: IndirectAssignmentCert, claimed_candidate_index: +CandidateIndex)` + +Imports an assignment cert referenced by block hash and candidate index. As a postcondition, if the cert is valid, it +will have distributed the cert to all peers who have the block in their view, with the exclusion of the peer referenced +by the `MessageSource`. We maintain a few invariants: * we only send an assignment to a peer after we add its fingerprint to our knowledge @@ -202,61 +241,84 @@ We maintain a few invariants: The algorithm is the following: - * Load the `BlockEntry` using `assignment.block_hash`. If it does not exist, report the source if it is `MessageSource::Peer` and return. + * Load the `BlockEntry` using `assignment.block_hash`. If it does not exist, report the source if it is + `MessageSource::Peer` and return. * Compute a fingerprint for the `assignment` using `claimed_candidate_index`. * If the source is `MessageSource::Peer(sender)`: - * check if `peer` appears under `known_by` and whether the fingerprint is in the knowledge of the peer. If the peer does not know the block, report for providing data out-of-view and proceed. If the peer does know the block and the `sent` knowledge contains the fingerprint, report for providing replicate data and return, otherwise, insert into the `received` knowledge and return. - * If the message fingerprint appears under the `BlockEntry`'s `Knowledge`, give the peer a small positive reputation boost, - add the fingerprint to the peer's knowledge only if it knows about the block and return. - Note that we must do this after checking for out-of-view and if the peers knows about the block to avoid being spammed. - If we did this check earlier, a peer could provide data out-of-view repeatedly and be rewarded for it. + * check if `peer` appears under `known_by` and whether the fingerprint is in the knowledge of the peer. If the peer + does not know the block, report for providing data out-of-view and proceed. If the peer does know the block and + the `sent` knowledge contains the fingerprint, report for providing replicate data and return, otherwise, insert + into the `received` knowledge and return. + * If the message fingerprint appears under the `BlockEntry`'s `Knowledge`, give the peer a small positive reputation + boost, add the fingerprint to the peer's knowledge only if it knows about the block and return. Note that we must do + this after checking for out-of-view and if the peers knows about the block to avoid being spammed. If we did this + check earlier, a peer could provide data out-of-view repeatedly and be rewarded for it. * Dispatch `ApprovalVotingMessage::CheckAndImportAssignment(assignment)` and wait for the response. * If the result is `AssignmentCheckResult::Accepted` * If the vote was accepted but not duplicate, give the peer a positive reputation boost - * add the fingerprint to both our and the peer's knowledge in the `BlockEntry`. Note that we only doing this after making sure we have the right fingerprint. - * If the result is `AssignmentCheckResult::AcceptedDuplicate`, add the fingerprint to the peer's knowledge if it knows about the block and return. + * add the fingerprint to both our and the peer's knowledge in the `BlockEntry`. Note that we only doing this after + making sure we have the right fingerprint. + * If the result is `AssignmentCheckResult::AcceptedDuplicate`, add the fingerprint to the peer's knowledge if it + knows about the block and return. * If the result is `AssignmentCheckResult::TooFarInFuture`, mildly punish the peer and return. * If the result is `AssignmentCheckResult::Bad`, punish the peer and return. * If the source is `MessageSource::Local(CandidateIndex)` * check if the fingerprint appears under the `BlockEntry's` knowledge. If not, add it. - * Load the candidate entry for the given candidate index. It should exist unless there is a logic error in the approval voting subsystem. - * Set the approval state for the validator index to `ApprovalState::Assigned` unless the approval state is set already. This should not happen as long as the approval voting subsystem instructs us to ignore duplicate assignments. - * Dispatch a `ApprovalDistributionV1Message::Assignment(assignment, candidate_index)` to all peers in the `BlockEntry`'s `known_by` set, excluding the peer in the `source`, if `source` has kind `MessageSource::Peer`. Add the fingerprint of the assignment to the knowledge of each peer. + * Load the candidate entry for the given candidate index. It should exist unless there is a logic error in the + approval voting subsystem. + * Set the approval state for the validator index to `ApprovalState::Assigned` unless the approval state is set + already. This should not happen as long as the approval voting subsystem instructs us to ignore duplicate + assignments. + * Dispatch a `ApprovalDistributionV1Message::Assignment(assignment, candidate_index)` to all peers in the + `BlockEntry`'s `known_by` set, excluding the peer in the `source`, if `source` has kind `MessageSource::Peer`. Add + the fingerprint of the assignment to the knowledge of each peer. #### `import_and_circulate_approval(source: MessageSource, approval: IndirectSignedApprovalVote)` Imports an approval signature referenced by block hash and candidate index: - * Load the `BlockEntry` using `approval.block_hash` and the candidate entry using `approval.candidate_entry`. If either does not exist, report the source if it is `MessageSource::Peer` and return. + * Load the `BlockEntry` using `approval.block_hash` and the candidate entry using `approval.candidate_entry`. If + either does not exist, report the source if it is `MessageSource::Peer` and return. * Compute a fingerprint for the approval. - * Compute a fingerprint for the corresponding assignment. If the `BlockEntry`'s knowledge does not contain that fingerprint, then report the source if it is `MessageSource::Peer` and return. All references to a fingerprint after this refer to the approval's, not the assignment's. + * Compute a fingerprint for the corresponding assignment. If the `BlockEntry`'s knowledge does not contain that + fingerprint, then report the source if it is `MessageSource::Peer` and return. All references to a fingerprint after + this refer to the approval's, not the assignment's. * If the source is `MessageSource::Peer(sender)`: - * check if `peer` appears under `known_by` and whether the fingerprint is in the knowledge of the peer. If the peer does not know the block, report for providing data out-of-view and proceed. If the peer does know the block and the `sent` knowledge contains the fingerprint, report for providing replicate data and return, otherwise, insert into the `received` knowledge and return. - * If the message fingerprint appears under the `BlockEntry`'s `Knowledge`, give the peer a small positive reputation boost, - add the fingerprint to the peer's knowledge only if it knows about the block and return. - Note that we must do this after checking for out-of-view to avoid being spammed. If we did this check earlier, a peer could provide data out-of-view repeatedly and be rewarded for it. + * check if `peer` appears under `known_by` and whether the fingerprint is in the knowledge of the peer. If the peer + does not know the block, report for providing data out-of-view and proceed. If the peer does know the block and + the `sent` knowledge contains the fingerprint, report for providing replicate data and return, otherwise, insert + into the `received` knowledge and return. + * If the message fingerprint appears under the `BlockEntry`'s `Knowledge`, give the peer a small positive reputation + boost, add the fingerprint to the peer's knowledge only if it knows about the block and return. Note that we must do + this after checking for out-of-view to avoid being spammed. If we did this check earlier, a peer could provide data + out-of-view repeatedly and be rewarded for it. * Dispatch `ApprovalVotingMessage::CheckAndImportApproval(approval)` and wait for the response. * If the result is `VoteCheckResult::Accepted(())`: * Give the peer a positive reputation boost and add the fingerprint to both our and the peer's knowledge. * If the result is `VoteCheckResult::Bad`: * Report the peer and return. - * Load the candidate entry for the given candidate index. It should exist unless there is a logic error in the approval voting subsystem. - * Set the approval state for the validator index to `ApprovalState::Approved`. It should already be in the `Assigned` state as our `BlockEntry` knowledge contains a fingerprint for the assignment. - * Dispatch a `ApprovalDistributionV1Message::Approval(approval)` to all peers in the `BlockEntry`'s `known_by` set, excluding the peer in the `source`, if `source` has kind `MessageSource::Peer`. Add the fingerprint of the assignment to the knowledge of each peer. Note that this obeys the politeness conditions: + * Load the candidate entry for the given candidate index. It should exist unless there is a logic error in the + approval voting subsystem. + * Set the approval state for the validator index to `ApprovalState::Approved`. It should already be in the `Assigned` + state as our `BlockEntry` knowledge contains a fingerprint for the assignment. + * Dispatch a `ApprovalDistributionV1Message::Approval(approval)` to all peers in the `BlockEntry`'s `known_by` set, + excluding the peer in the `source`, if `source` has kind `MessageSource::Peer`. Add the fingerprint of the + assignment to the knowledge of each peer. Note that this obeys the politeness conditions: * We guarantee elsewhere that all peers within `known_by` are aware of all assignments relative to the block. * We've checked that this specific approval has a corresponding assignment within the `BlockEntry`. * Thus, all peers are aware of the assignment or have a message to them in-flight which will make them so. - -#### `unify_with_peer(peer: PeerId, view)`: +#### `unify_with_peer(peer: PeerId, view)` 1. Initialize a set `missing_knowledge = {}` For each block in the view: - 2. Load the `BlockEntry` for the block. If the block is unknown, or the number is less than or equal to the view's finalized number go to step 6. - 3. Inspect the `known_by` set of the `BlockEntry`. If the peer already knows all assignments/approvals, go to step 6. - 4. Add the peer to `known_by` and add the hash and missing knowledge of the block to `missing_knowledge`. - 5. Return to step 2 with the ancestor of the block. - -6. For each block in `missing_knowledge`, send all assignments and approvals for all candidates in those blocks to the peer. + 1. Load the `BlockEntry` for the block. If the block is unknown, or the number is less than or equal to the view's + finalized number go to step 6. + 1. Inspect the `known_by` set of the `BlockEntry`. If the peer already knows all assignments/approvals, go to step 6. + 1. Add the peer to `known_by` and add the hash and missing knowledge of the block to `missing_knowledge`. + 1. Return to step 2 with the ancestor of the block. + +1. For each block in `missing_knowledge`, send all assignments and approvals for all candidates in those blocks to the + peer. diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md index 88744e50cf7..6da2f5d9b88 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md @@ -1,35 +1,61 @@ # Approval Voting -Reading the [section on the approval protocol](../../protocol-approval.md) will likely be necessary to understand the aims of this subsystem. - -Approval votes are split into two parts: Assignments and Approvals. Validators first broadcast their assignment to indicate intent to check a candidate. Upon successfully checking, they broadcast an approval vote. If a validator doesn't broadcast their approval vote shortly after issuing an assignment, this is an indication that they are being prevented from recovering or validating the block data and that more validators should self-select to check the candidate. This is known as a "no-show". - -The core of this subsystem is a Tick-based timer loop, where Ticks are 500ms. We also reason about time in terms of `DelayTranche`s, which measure the number of ticks elapsed since a block was produced. We track metadata for all un-finalized but included candidates. We compute our local assignments to check each candidate, as well as which `DelayTranche` those assignments may be minimally triggered at. As the same candidate may appear in more than one block, we must produce our potential assignments for each (Block, Candidate) pair. The timing loop is based on waiting for assignments to become no-shows or waiting to broadcast and begin our own assignment to check. - -Another main component of this subsystem is the logic for determining when a (Block, Candidate) pair has been approved and when to broadcast and trigger our own assignment. Once a (Block, Candidate) pair has been approved, we mark a corresponding bit in the `BlockEntry` that indicates the candidate has been approved under the block. When we trigger our own assignment, we broadcast it via Approval Distribution, begin fetching the data from Availability Recovery, and then pass it through to the Candidate Validation. Once these steps are successful, we issue our approval vote. If any of these steps fail, we don't issue any vote and will "no-show" from the perspective of other validators in addition a dispute is raised via the dispute-coordinator, by sending `IssueLocalStatement`. - -Where this all fits into Polkadot is via block finality. Our goal is to not finalize any block containing a candidate that is not approved. We provide a hook for a custom GRANDPA voting rule - GRANDPA makes requests of the form (target, minimum) consisting of a target block (i.e. longest chain) that it would like to finalize, and a minimum block which, due to the rules of GRANDPA, must be voted on. The minimum is typically the last finalized block, but may be beyond it, in the case of having a last-round-estimate beyond the last finalized. Thus, our goal is to inform GRANDPA of some block between target and minimum which we believe can be finalized safely. We do this by iterating backwards from the target to the minimum and finding the longest continuous chain from minimum where all candidates included by those blocks have been approved. +Reading the [section on the approval protocol](../../protocol-approval.md) will likely be necessary to understand the +aims of this subsystem. + +Approval votes are split into two parts: Assignments and Approvals. Validators first broadcast their assignment to +indicate intent to check a candidate. Upon successfully checking, they broadcast an approval vote. If a validator +doesn't broadcast their approval vote shortly after issuing an assignment, this is an indication that they are being +prevented from recovering or validating the block data and that more validators should self-select to check the +candidate. This is known as a "no-show". + +The core of this subsystem is a Tick-based timer loop, where Ticks are 500ms. We also reason about time in terms of +`DelayTranche`s, which measure the number of ticks elapsed since a block was produced. We track metadata for all +un-finalized but included candidates. We compute our local assignments to check each candidate, as well as which +`DelayTranche` those assignments may be minimally triggered at. As the same candidate may appear in more than one block, +we must produce our potential assignments for each (Block, Candidate) pair. The timing loop is based on waiting for +assignments to become no-shows or waiting to broadcast and begin our own assignment to check. + +Another main component of this subsystem is the logic for determining when a (Block, Candidate) pair has been approved +and when to broadcast and trigger our own assignment. Once a (Block, Candidate) pair has been approved, we mark a +corresponding bit in the `BlockEntry` that indicates the candidate has been approved under the block. When we trigger +our own assignment, we broadcast it via Approval Distribution, begin fetching the data from Availability Recovery, and +then pass it through to the Candidate Validation. Once these steps are successful, we issue our approval vote. If any of +these steps fail, we don't issue any vote and will "no-show" from the perspective of other validators in addition a +dispute is raised via the dispute-coordinator, by sending `IssueLocalStatement`. + +Where this all fits into Polkadot is via block finality. Our goal is to not finalize any block containing a candidate +that is not approved. We provide a hook for a custom GRANDPA voting rule - GRANDPA makes requests of the form (target, +minimum) consisting of a target block (i.e. longest chain) that it would like to finalize, and a minimum block which, +due to the rules of GRANDPA, must be voted on. The minimum is typically the last finalized block, but may be beyond it, +in the case of having a last-round-estimate beyond the last finalized. Thus, our goal is to inform GRANDPA of some block +between target and minimum which we believe can be finalized safely. We do this by iterating backwards from the target +to the minimum and finding the longest continuous chain from minimum where all candidates included by those blocks have +been approved. ## Protocol Input: - - `ApprovalVotingMessage::CheckAndImportAssignment` - - `ApprovalVotingMessage::CheckAndImportApproval` - - `ApprovalVotingMessage::ApprovedAncestor` + * `ApprovalVotingMessage::CheckAndImportAssignment` + * `ApprovalVotingMessage::CheckAndImportApproval` + * `ApprovalVotingMessage::ApprovedAncestor` Output: - - `ApprovalDistributionMessage::DistributeAssignment` - - `ApprovalDistributionMessage::DistributeApproval` - - `RuntimeApiMessage::Request` - - `ChainApiMessage` - - `AvailabilityRecoveryMessage::Recover` - - `CandidateExecutionMessage::ValidateFromExhaustive` + * `ApprovalDistributionMessage::DistributeAssignment` + * `ApprovalDistributionMessage::DistributeApproval` + * `RuntimeApiMessage::Request` + * `ChainApiMessage` + * `AvailabilityRecoveryMessage::Recover` + * `CandidateExecutionMessage::ValidateFromExhaustive` ## Functionality -The approval voting subsystem is responsible for casting votes and determining approval of candidates and as a result, blocks. +The approval voting subsystem is responsible for casting votes and determining approval of candidates and as a result, +blocks. -This subsystem wraps a database which is used to store metadata about unfinalized blocks and the candidates within them. Candidates may appear in multiple blocks, and assignment criteria are chosen differently based on the hash of the block they appear in. +This subsystem wraps a database which is used to store metadata about unfinalized blocks and the candidates within them. +Candidates may appear in multiple blocks, and assignment criteria are chosen differently based on the hash of the block +they appear in. ## Database Schema @@ -150,16 +176,22 @@ struct State { } ``` -This guide section makes no explicit references to writes to or reads from disk. Instead, it handles them implicitly, with the understanding that updates to block, candidate, and approval entries are persisted to disk. +This guide section makes no explicit references to writes to or reads from disk. Instead, it handles them implicitly, +with the understanding that updates to block, candidate, and approval entries are persisted to disk. [`SessionInfo`](../../runtime/session_info.md) -On start-up, we clear everything currently stored by the database. This is done by loading the `StoredBlockRange`, iterating through each block number, iterating through each block hash, and iterating through each candidate referenced by each block. Although this is `O(o*n*p)`, we don't expect to have more than a few unfinalized blocks at any time and in extreme cases, a few thousand. The clearing operation should be relatively fast as a result. +On start-up, we clear everything currently stored by the database. This is done by loading the `StoredBlockRange`, +iterating through each block number, iterating through each block hash, and iterating through each candidate referenced +by each block. Although this is `O(o*n*p)`, we don't expect to have more than a few unfinalized blocks at any time and +in extreme cases, a few thousand. The clearing operation should be relatively fast as a result. Main loop: * Each iteration, select over all of - * The next `Tick` in `wakeups`: trigger `wakeup_process` for each `(Hash, Hash)` pair scheduled under the `Tick` and then remove all entries under the `Tick`. - * The next message from the overseer: handle the message as described in the [Incoming Messages section](#incoming-messages) + * The next `Tick` in `wakeups`: trigger `wakeup_process` for each `(Hash, Hash)` pair scheduled under the `Tick` and + then remove all entries under the `Tick`. + * The next message from the overseer: handle the message as described in the [Incoming Messages + section](#incoming-messages) * The next approval vote request from `background_rx` * If this is an `ApprovalVoteRequest`, [Issue an approval vote](#issue-approval-vote). @@ -167,41 +199,84 @@ Main loop: #### `OverseerSignal::BlockFinalized` -On receiving an `OverseerSignal::BlockFinalized(h)`, we fetch the block number `b` of that block from the `ChainApi` subsystem. We update our `StoredBlockRange` to begin at `b+1`. Additionally, we remove all block entries and candidates referenced by them up to and including `b`. Lastly, we prune out all descendants of `h` transitively: when we remove a `BlockEntry` with number `b` that is not equal to `h`, we recursively delete all the `BlockEntry`s referenced as children. We remove the `block_assignments` entry for the block hash and if `block_assignments` is now empty, remove the `CandidateEntry`. We also update each of the `BlockNumber -> Vec` keys in the database to reflect the blocks at that height, clearing if empty. +On receiving an `OverseerSignal::BlockFinalized(h)`, we fetch the block number `b` of that block from the `ChainApi` +subsystem. We update our `StoredBlockRange` to begin at `b+1`. Additionally, we remove all block entries and candidates +referenced by them up to and including `b`. Lastly, we prune out all descendants of `h` transitively: when we remove a +`BlockEntry` with number `b` that is not equal to `h`, we recursively delete all the `BlockEntry`s referenced as +children. We remove the `block_assignments` entry for the block hash and if `block_assignments` is now empty, remove the +`CandidateEntry`. We also update each of the `BlockNumber -> Vec` keys in the database to reflect the blocks at +that height, clearing if empty. #### `OverseerSignal::ActiveLeavesUpdate` On receiving an `OverseerSignal::ActiveLeavesUpdate(update)`: - * We determine the set of new blocks that were not in our previous view. This is done by querying the ancestry of all new items in the view and contrasting against the stored `BlockNumber`s. Typically, there will be only one new block. We fetch the headers and information on these blocks from the `ChainApi` subsystem. Stale leaves in the update can be ignored. + * We determine the set of new blocks that were not in our previous view. This is done by querying the ancestry of all + new items in the view and contrasting against the stored `BlockNumber`s. Typically, there will be only one new + block. We fetch the headers and information on these blocks from the `ChainApi` subsystem. Stale leaves in the + update can be ignored. * We update the `StoredBlockRange` and the `BlockNumber` maps. - * We use the `RuntimeApiSubsystem` to determine information about these blocks. It is generally safe to assume that runtime state is available for recent, unfinalized blocks. In the case that it isn't, it means that we are catching up to the head of the chain and needn't worry about assignments to those blocks anyway, as the security assumption of the protocol tolerates nodes being temporarily offline or out-of-date. - * We fetch the set of candidates included by each block by dispatching a `RuntimeApiRequest::CandidateEvents` and checking the `CandidateIncluded` events. - * We fetch the session of the block by dispatching a `session_index_for_child` request with the parent-hash of the block. - * If the `session index - APPROVAL_SESSIONS > state.earliest_session`, then bump `state.earliest_sessions` to that amount and prune earlier sessions. - * If the session isn't in our `state.session_info`, load the session info for it and for all sessions since the earliest-session, including the earliest-session, if that is missing. And it can be, just after pruning, if we've done a big jump forward, as is the case when we've just finished chain synchronization. + * We use the `RuntimeApiSubsystem` to determine information about these blocks. It is generally safe to assume that + runtime state is available for recent, unfinalized blocks. In the case that it isn't, it means that we are catching + up to the head of the chain and needn't worry about assignments to those blocks anyway, as the security assumption + of the protocol tolerates nodes being temporarily offline or out-of-date. + * We fetch the set of candidates included by each block by dispatching a `RuntimeApiRequest::CandidateEvents` and + checking the `CandidateIncluded` events. + * We fetch the session of the block by dispatching a `session_index_for_child` request with the parent-hash of the + block. + * If the `session index - APPROVAL_SESSIONS > state.earliest_session`, then bump `state.earliest_sessions` to that + amount and prune earlier sessions. + * If the session isn't in our `state.session_info`, load the session info for it and for all sessions since the + earliest-session, including the earliest-session, if that is missing. And it can be, just after pruning, if we've + done a big jump forward, as is the case when we've just finished chain synchronization. * If any of the runtime API calls fail, we just warn and skip the block. - * We use the `RuntimeApiSubsystem` to determine the set of candidates included in these blocks and use BABE logic to determine the slot number and VRF of the blocks. - * We also note how late we appear to have received the block. We create a `BlockEntry` for each block and a `CandidateEntry` for each candidate obtained from `CandidateIncluded` events after making a `RuntimeApiRequest::CandidateEvents` request. - * For each candidate, if the amount of needed approvals is more than the validators remaining after the backing group of the candidate is subtracted, then the candidate is insta-approved as approval would be impossible otherwise. If all candidates in the block are insta-approved, or there are no candidates in the block, then the block is insta-approved. If the block is insta-approved, a [`ChainSelectionMessage::Approved`][CSM] should be sent for the block. - * Ensure that the `CandidateEntry` contains a `block_assignments` entry for the block, with the correct backing group set. + * We use the `RuntimeApiSubsystem` to determine the set of candidates included in these blocks and use BABE logic to + determine the slot number and VRF of the blocks. + * We also note how late we appear to have received the block. We create a `BlockEntry` for each block and a + `CandidateEntry` for each candidate obtained from `CandidateIncluded` events after making a + `RuntimeApiRequest::CandidateEvents` request. + * For each candidate, if the amount of needed approvals is more than the validators remaining after the backing group + of the candidate is subtracted, then the candidate is insta-approved as approval would be impossible otherwise. If + all candidates in the block are insta-approved, or there are no candidates in the block, then the block is + insta-approved. If the block is insta-approved, a [`ChainSelectionMessage::Approved`][CSM] should be sent for the + block. + * Ensure that the `CandidateEntry` contains a `block_assignments` entry for the block, with the correct backing group + set. * If a validator in this session, compute and assign `our_assignment` for the `block_assignments` * Only if not a member of the backing group. - * Run `RelayVRFModulo` and `RelayVRFDelay` according to the [the approvals protocol section](../../protocol-approval.md#assignment-criteria). Ensure that the assigned core derived from the output is covered by the auxiliary signature aggregated in the `VRFPRoof`. - * [Handle Wakeup](#handle-wakeup) for each new candidate in each new block - this will automatically broadcast a 0-tranche assignment, kick off approval work, and schedule the next delay. + * Run `RelayVRFModulo` and `RelayVRFDelay` according to the [the approvals protocol + section](../../protocol-approval.md#assignment-criteria). Ensure that the assigned core derived from the output is + covered by the auxiliary signature aggregated in the `VRFPRoof`. + * [Handle Wakeup](#handle-wakeup) for each new candidate in each new block - this will automatically broadcast a + 0-tranche assignment, kick off approval work, and schedule the next delay. * Dispatch an `ApprovalDistributionMessage::NewBlocks` with the meta information filled out for each new block. #### `ApprovalVotingMessage::CheckAndImportAssignment` -On receiving a `ApprovalVotingMessage::CheckAndImportAssignment` message, we check the assignment cert against the block entry. The cert itself contains information necessary to determine the candidate that is being assigned-to. In detail: - * Load the `BlockEntry` for the relay-parent referenced by the message. If there is none, return `AssignmentCheckResult::Bad`. +On receiving a `ApprovalVotingMessage::CheckAndImportAssignment` message, we check the assignment cert against the block +entry. The cert itself contains information necessary to determine the candidate that is being assigned-to. In detail: + * Load the `BlockEntry` for the relay-parent referenced by the message. If there is none, return + `AssignmentCheckResult::Bad`. * Fetch the `SessionInfo` for the session of the block * Determine the assignment key of the validator based on that. - * Determine the claimed core index by looking up the candidate with given index in `block_entry.candidates`. Return `AssignmentCheckResult::Bad` if missing. + * Determine the claimed core index by looking up the candidate with given index in `block_entry.candidates`. Return + `AssignmentCheckResult::Bad` if missing. * Check the assignment cert - * If the cert kind is `RelayVRFModulo`, then the certificate is valid as long as `sample < session_info.relay_vrf_samples` and the VRF is valid for the validator's key with the input `block_entry.relay_vrf_story ++ sample.encode()` as described with [the approvals protocol section](../../protocol-approval.md#assignment-criteria). We set `core_index = vrf.make_bytes().to_u32() % session_info.n_cores`. If the `BlockEntry` causes inclusion of a candidate at `core_index`, then this is a valid assignment for the candidate at `core_index` and has delay tranche 0. Otherwise, it can be ignored. - * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the input `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not cause inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included candidate. The delay tranche for the assignment is determined by reducing `(vrf.make_bytes().to_u64() % (session_info.n_delay_tranches + session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. - * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary signature. + * If the cert kind is `RelayVRFModulo`, then the certificate is valid as long as `sample < + session_info.relay_vrf_samples` and the VRF is valid for the validator's key with the input + `block_entry.relay_vrf_story ++ sample.encode()` as described with [the approvals protocol + section](../../protocol-approval.md#assignment-criteria). We set `core_index = vrf.make_bytes().to_u32() % + session_info.n_cores`. If the `BlockEntry` causes inclusion of a candidate at `core_index`, then this is a valid + assignment for the candidate at `core_index` and has delay tranche 0. Otherwise, it can be ignored. + * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the input + `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol + section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not cause + inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included candidate. The + delay tranche for the assignment is determined by reducing `(vrf.make_bytes().to_u64() % + (session_info.n_delay_tranches + + session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. + * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary + signature. * If the delay tranche is too far in the future, return `AssignmentCheckResult::TooFarInFuture`. * Import the assignment. * Load the candidate in question and access the `approval_entry` for the block hash the cert references. @@ -217,32 +292,41 @@ On receiving a `ApprovalVotingMessage::CheckAndImportAssignment` message, we che On receiving a `CheckAndImportApproval(indirect_approval_vote, response_channel)` message: * Fetch the `BlockEntry` from the indirect approval vote's `block_hash`. If none, return `ApprovalCheckResult::Bad`. - * Fetch the `CandidateEntry` from the indirect approval vote's `candidate_index`. If the block did not trigger inclusion of enough candidates, return `ApprovalCheckResult::Bad`. - * Construct a `SignedApprovalVote` using the candidate hash and check against the validator's approval key, based on the session info of the block. If invalid or no such validator, return `ApprovalCheckResult::Bad`. + * Fetch the `CandidateEntry` from the indirect approval vote's `candidate_index`. If the block did not trigger + inclusion of enough candidates, return `ApprovalCheckResult::Bad`. + * Construct a `SignedApprovalVote` using the candidate hash and check against the validator's approval key, based on + the session info of the block. If invalid or no such validator, return `ApprovalCheckResult::Bad`. * Send `ApprovalCheckResult::Accepted` * [Import the checked approval vote](#import-checked-approval) #### `ApprovalVotingMessage::ApprovedAncestor` On receiving an `ApprovedAncestor(Hash, BlockNumber, response_channel)`: - * Iterate over the ancestry of the hash all the way back to block number given, starting from the provided block hash. Load the `CandidateHash`es from each block entry. + * Iterate over the ancestry of the hash all the way back to block number given, starting from the provided block hash. + Load the `CandidateHash`es from each block entry. * Keep track of an `all_approved_max: Option<(Hash, BlockNumber, Vec<(Hash, Vec))>`. - * For each block hash encountered, load the `BlockEntry` associated. If any are not found, return `None` on the response channel and conclude. - * If the block entry's `approval_bitfield` has all bits set to 1 and `all_approved_max == None`, set `all_approved_max = Some((current_hash, current_number))`. + * For each block hash encountered, load the `BlockEntry` associated. If any are not found, return `None` on the + response channel and conclude. + * If the block entry's `approval_bitfield` has all bits set to 1 and `all_approved_max == None`, set `all_approved_max + = Some((current_hash, current_number))`. * If the block entry's `approval_bitfield` has any 0 bits, set `all_approved_max = None`. - * If `all_approved_max` is `Some`, push the current block hash and candidate hashes onto the list of blocks and candidates `all_approved_max`. + * If `all_approved_max` is `Some`, push the current block hash and candidate hashes onto the list of blocks and + candidates `all_approved_max`. * After iterating all ancestry, return `all_approved_max`. ### Updates and Auxiliary Logic #### Import Checked Approval - * Import an approval vote which we can assume to have passed signature checks and correspond to an imported assignment. + * Import an approval vote which we can assume to have passed signature checks and correspond to an imported + assignment. * Requires `(BlockEntry, CandidateEntry, ValidatorIndex)` * Set the corresponding bit of the `approvals` bitfield in the `CandidateEntry` to `1`. If already `1`, return. - * Checks the approval state of a candidate under a specific block, and updates the block and candidate entries accordingly. + * Checks the approval state of a candidate under a specific block, and updates the block and candidate entries + accordingly. * Checks the `ApprovalEntry` for the block. * [determine the tranches to inspect](#determine-required-tranches) of the candidate, - * [the candidate is approved under the block](#check-approval), set the corresponding bit in the `block_entry.approved_bitfield`. + * [the candidate is approved under the block](#check-approval), set the corresponding bit in the + `block_entry.approved_bitfield`. * If the block is now fully approved and was not before, send a [`ChainSelectionMessage::Approved`][CSM]. * Otherwise, [schedule a wakeup of the candidate](#schedule-wakeup) * If the approval vote originates locally, set the `our_approval_sig` in the candidate entry. @@ -250,13 +334,19 @@ On receiving an `ApprovedAncestor(Hash, BlockNumber, response_channel)`: #### Handling Wakeup * Handle a previously-scheduled wakeup of a candidate under a specific block. * Requires `(relay_block, candidate_hash)` - * Load the `BlockEntry` and `CandidateEntry` from disk. If either is not present, this may have lost a race with finality and can be ignored. Also load the `ApprovalEntry` for the block and candidate. + * Load the `BlockEntry` and `CandidateEntry` from disk. If either is not present, this may have lost a race with + finality and can be ignored. Also load the `ApprovalEntry` for the block and candidate. * [determine the `RequiredTranches` of the candidate](#determine-required-tranches). * Determine if we should trigger our assignment. * If we've already triggered or `OurAssignment` is `None`, we do not trigger. - * If we have `RequiredTranches::All`, then we trigger if the candidate is [not approved](#check-approval). We have no next wakeup as we assume that other validators are doing the same and we will be implicitly woken up by handling new votes. - * If we have `RequiredTranches::Pending { considered, next_no_show, uncovered, maximum_broadcast, clock_drift }`, then we trigger if our assignment's tranche is less than or equal to `maximum_broadcast` and the current tick, with `clock_drift` applied, is at least the tick of our tranche. - * If we have `RequiredTranches::Exact { .. }` then we do not trigger, because this value indicates that no new assignments are needed at the moment. + * If we have `RequiredTranches::All`, then we trigger if the candidate is [not approved](#check-approval). We have + no next wakeup as we assume that other validators are doing the same and we will be implicitly woken up by + handling new votes. + * If we have `RequiredTranches::Pending { considered, next_no_show, uncovered, maximum_broadcast, clock_drift }`, + then we trigger if our assignment's tranche is less than or equal to `maximum_broadcast` and the current tick, + with `clock_drift` applied, is at least the tick of our tranche. + * If we have `RequiredTranches::Exact { .. }` then we do not trigger, because this value indicates that no new + assignments are needed at the moment. * If we should trigger our assignment * Import the assignment to the `ApprovalEntry` * Broadcast on network with an `ApprovalDistributionMessage::DistributeAssignment`. @@ -265,26 +355,39 @@ On receiving an `ApprovedAncestor(Hash, BlockNumber, response_channel)`: #### Schedule Wakeup - * Requires `(approval_entry, candidate_entry)` which effectively denotes a `(Block Hash, Candidate Hash)` pair - the candidate, along with the block it appears in. + * Requires `(approval_entry, candidate_entry)` which effectively denotes a `(Block Hash, Candidate Hash)` pair - the + candidate, along with the block it appears in. * Also requires `RequiredTranches` * If the `approval_entry` is approved, this doesn't need to be woken up again. - * If `RequiredTranches::All` - no wakeup. We assume other incoming votes will trigger wakeup and potentially re-schedule. - * If `RequiredTranches::Pending { considered, next_no_show, uncovered, maximum_broadcast, clock_drift }` - schedule at the lesser of the next no-show tick, or the tick, offset positively by `clock_drift` of the next non-empty tranche we are aware of after `considered`, including any tranche containing our own unbroadcast assignment. This can lead to no wakeup in the case that we have already broadcast our assignment and there are no pending no-shows; that is, we have approval votes for every assignment we've received that is not already a no-show. In this case, we will be re-triggered by other validators broadcasting their assignments. - * If `RequiredTranches::Exact { next_no_show, latest_assignment_tick, .. }` - set a wakeup for the earlier of the next no-show tick or the latest assignment tick + `APPROVAL_DELAY`. + * If `RequiredTranches::All` - no wakeup. We assume other incoming votes will trigger wakeup and potentially + re-schedule. + * If `RequiredTranches::Pending { considered, next_no_show, uncovered, maximum_broadcast, clock_drift }` - schedule at + the lesser of the next no-show tick, or the tick, offset positively by `clock_drift` of the next non-empty tranche + we are aware of after `considered`, including any tranche containing our own unbroadcast assignment. This can lead + to no wakeup in the case that we have already broadcast our assignment and there are no pending no-shows; that is, + we have approval votes for every assignment we've received that is not already a no-show. In this case, we will be + re-triggered by other validators broadcasting their assignments. + * If `RequiredTranches::Exact { next_no_show, latest_assignment_tick, .. }` - set a wakeup for the earlier of the next + no-show tick or the latest assignment tick + `APPROVAL_DELAY`. #### Launch Approval Work * Requires `(SessionIndex, SessionInfo, CandidateReceipt, ValidatorIndex, backing_group, block_hash, candidate_index)` * Extract the public key of the `ValidatorIndex` from the `SessionInfo` for the session. -* Issue an `AvailabilityRecoveryMessage::RecoverAvailableData(candidate, session_index, Some(backing_group), response_sender)` -* Load the historical validation code of the parachain by dispatching a `RuntimeApiRequest::ValidationCodeByHash(descriptor.validation_code_hash)` against the state of `block_hash`. +* Issue an `AvailabilityRecoveryMessage::RecoverAvailableData(candidate, session_index, Some(backing_group), + response_sender)` +* Load the historical validation code of the parachain by dispatching a + `RuntimeApiRequest::ValidationCodeByHash(descriptor.validation_code_hash)` against the state of `block_hash`. * Spawn a background task with a clone of `background_tx` * Wait for the available data - * Issue a `CandidateValidationMessage::ValidateFromExhaustive` message with `APPROVAL_EXECUTION_TIMEOUT` as the timeout parameter. + * Issue a `CandidateValidationMessage::ValidateFromExhaustive` message with `APPROVAL_EXECUTION_TIMEOUT` as the + timeout parameter. * Wait for the result of validation * Check that the result of validation, if valid, matches the commitments in the receipt. * If valid, issue a message on `background_tx` detailing the request. - * If any of the data, the candidate, or the commitments are invalid, issue on `background_tx` a [`DisputeCoordinatorMessage::IssueLocalStatement`](../../types/overseer-protocol.md#dispute-coordinator-message) with `valid = false` to initiate a dispute. + * If any of the data, the candidate, or the commitments are invalid, issue on `background_tx` a + [`DisputeCoordinatorMessage::IssueLocalStatement`](../../types/overseer-protocol.md#dispute-coordinator-message) + with `valid = false` to initiate a dispute. #### Issue Approval Vote * Fetch the block entry and candidate entry. Ignore if `None` - we've probably just lost a race with finality. @@ -297,14 +400,22 @@ On receiving an `ApprovedAncestor(Hash, BlockNumber, response_channel)`: #### Determine Required Tranches -This logic is for inspecting an approval entry that tracks the assignments received, along with information on which assignments have corresponding approval votes. Inspection also involves the current time and expected requirements and is used to help the higher-level code determine the following: +This logic is for inspecting an approval entry that tracks the assignments received, along with information on which +assignments have corresponding approval votes. Inspection also involves the current time and expected requirements and +is used to help the higher-level code determine the following: * Whether to broadcast the local assignment * Whether to check that the candidate entry has been completely approved. - * If the candidate is waiting on approval, when to schedule the next wakeup of the `(candidate, block)` pair at a point where the state machine could be advanced. + * If the candidate is waiting on approval, when to schedule the next wakeup of the `(candidate, block)` pair at a + point where the state machine could be advanced. -These routines are pure functions which only depend on the environmental state. The expectation is that this determination is re-run every time we attempt to update an approval entry: either when we trigger a wakeup to advance the state machine based on a no-show or our own broadcast, or when we receive further assignments or approvals from the network. +These routines are pure functions which only depend on the environmental state. The expectation is that this +determination is re-run every time we attempt to update an approval entry: either when we trigger a wakeup to advance +the state machine based on a no-show or our own broadcast, or when we receive further assignments or approvals from the +network. -Thus it may be that at some point in time, we consider that tranches 0..X is required to be considered, but as we receive more information, we might require fewer tranches. Or votes that we perceived to be missing and require replacement are filled in and change our view. +Thus it may be that at some point in time, we consider that tranches 0..X is required to be considered, but as we +receive more information, we might require fewer tranches. Or votes that we perceived to be missing and require +replacement are filled in and change our view. Requires `(approval_entry, approvals_received, tranche_now, block_tick, no_show_duration, needed_approvals)` @@ -327,7 +438,8 @@ enum RequiredTranches { /// as though it is `clock_drift` ticks earlier. clock_drift: Tick, }, - // An exact number of required tranches and a number of no-shows. This indicates that the amount of `needed_approvals` are assigned and additionally all no-shows are covered. + // An exact number of required tranches and a number of no-shows. This indicates that the amount of `needed_approvals` + // are assigned and additionally all no-shows are covered. Exact { /// The tranche to inspect up to. needed: DelayTranche, @@ -345,13 +457,21 @@ enum RequiredTranches { **Clock-drift and Tranche-taking** -Our vote-counting procedure depends heavily on how we interpret time based on the presence of no-shows - assignments which have no corresponding approval after some time. +Our vote-counting procedure depends heavily on how we interpret time based on the presence of no-shows - assignments +which have no corresponding approval after some time. We have this is because of how we handle no-shows: we keep track of the depth of no-shows we are covering. -As an example: there may be initial no-shows in tranche 0. It'll take `no_show_duration` ticks before those are considered no-shows. Then, we don't want to immediately take `no_show_duration` more tranches. Instead, we want to take one tranche for each uncovered no-show. However, as we take those tranches, there may be further no-shows. Since these depth-1 no-shows should have only been triggered after the depth-0 no-shows were already known to be no-shows, we need to discount the local clock by `no_show_duration` to see whether these should be considered no-shows or not. There may be malicious parties who broadcast their assignment earlier than they were meant to, who shouldn't be counted as instant no-shows. We continue onwards to cover all depth-1 no-shows which may lead to depth-2 no-shows and so on. +As an example: there may be initial no-shows in tranche 0. It'll take `no_show_duration` ticks before those are +considered no-shows. Then, we don't want to immediately take `no_show_duration` more tranches. Instead, we want to take +one tranche for each uncovered no-show. However, as we take those tranches, there may be further no-shows. Since these +depth-1 no-shows should have only been triggered after the depth-0 no-shows were already known to be no-shows, we need +to discount the local clock by `no_show_duration` to see whether these should be considered no-shows or not. There may +be malicious parties who broadcast their assignment earlier than they were meant to, who shouldn't be counted as instant +no-shows. We continue onwards to cover all depth-1 no-shows which may lead to depth-2 no-shows and so on. -Likewise, when considering how many tranches to take, the no-show depth should be used to apply a depth-discount or clock drift to the `tranche_now`. +Likewise, when considering how many tranches to take, the no-show depth should be used to apply a depth-discount or +clock drift to the `tranche_now`. **Procedure** @@ -360,21 +480,35 @@ Likewise, when considering how many tranches to take, the no-show depth should b * Take tranches up to `tranche_now - clock_drift` until all needed assignments are met. * Keep track of the `next_no_show` according to the clock drift, as we go. * Keep track of the `last_assignment_tick` as we go. - * If running out of tranches before then, return `Pending { considered, next_no_show, maximum_broadcast, clock_drift }` + * If running out of tranches before then, return `Pending { considered, next_no_show, maximum_broadcast, clock_drift + }` * If there are no no-shows, return `Exact { needed, tolerated_missing, next_no_show, last_assignment_tick }` - * `maximum_broadcast` is either `DelayTranche::max_value()` at tranche 0 or otherwise by the last considered tranche + the number of uncovered no-shows at this point. - * If there are no-shows, return to the beginning, incrementing `depth` and attempting to cover the number of no-shows. Each no-show must be covered by a non-empty tranche, which are tranches that have at least one assignment. Each non-empty tranche covers exactly one no-show. - * If at any point, it seems that all validators are required, do an early return with `RequiredTranches::All` which indicates that everyone should broadcast. + * `maximum_broadcast` is either `DelayTranche::max_value()` at tranche 0 or otherwise by the last considered tranche + + the number of uncovered no-shows at this point. + * If there are no-shows, return to the beginning, incrementing `depth` and attempting to cover the number of no-shows. + Each no-show must be covered by a non-empty tranche, which are tranches that have at least one assignment. Each + non-empty tranche covers exactly one no-show. + * If at any point, it seems that all validators are required, do an early return with `RequiredTranches::All` which + indicates that everyone should broadcast. #### Check Approval * Check whether a candidate is approved under a particular block. * Requires `(block_entry, candidate_entry, approval_entry, n_tranches)` - * If we have `3 * n_approvals > n_validators`, return true. This is because any set with f+1 validators must have at least one honest validator, who has approved the candidate. + * If we have `3 * n_approvals > n_validators`, return true. This is because any set with f+1 validators must have at + least one honest validator, who has approved the candidate. * If `n_tranches` is `RequiredTranches::Pending`, return false * If `n_tranches` is `RequiredTranches::All`, return false. - * If `n_tranches` is `RequiredTranches::Exact { tranche, tolerated_missing, latest_assignment_tick, .. }`, then we return whether all assigned validators up to `tranche` less `tolerated_missing` have approved and `latest_assignment_tick + APPROVAL_DELAY >= tick_now`. - * e.g. if we had 5 tranches and 1 tolerated missing, we would accept only if all but 1 of assigned validators in tranches 0..=5 have approved. In that example, we also accept all validators in tranches 0..=5 having approved, but that would indicate that the `RequiredTranches` value was incorrectly constructed, so it is not realistic. `tolerated_missing` actually represents covered no-shows. If there are more missing approvals than there are tolerated missing, that indicates that there are some assignments which are not yet no-shows, but may become no-shows, and we should wait for the validators to either approve or become no-shows. - * e.g. If the above passes and the `latest_assignment_tick` was 5 and the current tick was 6, then we'd return false. + * If `n_tranches` is `RequiredTranches::Exact { tranche, tolerated_missing, latest_assignment_tick, .. }`, then we + return whether all assigned validators up to `tranche` less `tolerated_missing` have approved and + `latest_assignment_tick + APPROVAL_DELAY >= tick_now`. + * e.g. if we had 5 tranches and 1 tolerated missing, we would accept only if all but 1 of assigned validators in + tranches 0..=5 have approved. In that example, we also accept all validators in tranches 0..=5 having approved, + but that would indicate that the `RequiredTranches` value was incorrectly constructed, so it is not realistic. + `tolerated_missing` actually represents covered no-shows. If there are more missing approvals than there are + tolerated missing, that indicates that there are some assignments which are not yet no-shows, but may become + no-shows, and we should wait for the validators to either approve or become no-shows. + * e.g. If the above passes and the `latest_assignment_tick` was 5 and the current tick was 6, then we'd return + false. ### Time diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/README.md b/polkadot/roadmap/implementers-guide/src/node/availability/README.md index 76bd6467e17..2fcfd58de9e 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/README.md @@ -1,3 +1,7 @@ # Availability Subsystems -The availability subsystems are responsible for ensuring that Proofs of Validity of backed candidates are widely available within the validator set, without requiring every node to retain a full copy. They accomplish this by broadly distributing erasure-coded chunks of the PoV, keeping track of which validator has which chunk by means of signed bitfields. They are also responsible for reassembling a complete PoV when required, e.g. when an approval checker needs to validate a parachain block. +The availability subsystems are responsible for ensuring that Proofs of Validity of backed candidates are widely +available within the validator set, without requiring every node to retain a full copy. They accomplish this by broadly +distributing erasure-coded chunks of the PoV, keeping track of which validator has which chunk by means of signed +bitfields. They are also responsible for reassembling a complete PoV when required, e.g. when an approval checker needs +to validate a parachain block. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/availability-distribution.md b/polkadot/roadmap/implementers-guide/src/node/availability/availability-distribution.md index 1760a2ee7df..931d82d529b 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/availability-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/availability-distribution.md @@ -1,31 +1,26 @@ # Availability Distribution -This subsystem is responsible for distribution availability data to peers. -Availability data are chunks, `PoV`s and `AvailableData` (which is `PoV` + -`PersistedValidationData`). It does so via request response protocols. +This subsystem is responsible for distribution availability data to peers. Availability data are chunks, `PoV`s and +`AvailableData` (which is `PoV` + `PersistedValidationData`). It does so via request response protocols. In particular this subsystem is responsible for: -- Respond to network requests requesting availability data by querying the - [Availability Store](../utility/availability-store.md). -- Request chunks from backing validators to put them in the local `Availability - Store` whenever we find an occupied core on any fresh leaf, - this is to ensure availability by at least 2/3+ of all validators, this - happens after a candidate is backed. -- Fetch `PoV` from validators, when requested via `FetchPoV` message from - backing (`pov_requester` module). +- Respond to network requests requesting availability data by querying the [Availability + Store](../utility/availability-store.md). +- Request chunks from backing validators to put them in the local `Availability Store` whenever we find an occupied core + on any fresh leaf, this is to ensure availability by at least 2/3+ of all validators, this happens after a candidate + is backed. +- Fetch `PoV` from validators, when requested via `FetchPoV` message from backing (`pov_requester` module). -The backing subsystem is responsible of making available data available in the -local `Availability Store` upon validation. This subsystem will serve any -network requests by querying that store. +The backing subsystem is responsible of making available data available in the local `Availability Store` upon +validation. This subsystem will serve any network requests by querying that store. ## Protocol -This subsystem does not handle any peer set messages, but the `pov_requester` -does connect to validators of the same backing group on the validation peer -set, to ensure fast propagation of statements between those validators and for -ensuring already established connections for requesting `PoV`s. Other than that -this subsystem drives request/response protocols. +This subsystem does not handle any peer set messages, but the `pov_requester` does connect to validators of the same +backing group on the validation peer set, to ensure fast propagation of statements between those validators and for +ensuring already established connections for requesting `PoV`s. Other than that this subsystem drives request/response +protocols. Input: @@ -48,51 +43,42 @@ Output: ### PoV Requester -The PoV requester in the `pov_requester` module takes care of staying connected -to validators of the current backing group of this very validator on the `Validation` -peer set and it will handle `FetchPoV` requests by issuing network requests to -those validators. It will check the hash of the received `PoV`, but will not do any -further validation. That needs to be done by the original `FetchPoV` sender -(backing subsystem). +The PoV requester in the `pov_requester` module takes care of staying connected to validators of the current backing +group of this very validator on the `Validation` peer set and it will handle `FetchPoV` requests by issuing network +requests to those validators. It will check the hash of the received `PoV`, but will not do any further validation. That +needs to be done by the original `FetchPoV` sender (backing subsystem). ### Chunk Requester -After a candidate is backed, the availability of the PoV block must be confirmed -by 2/3+ of all validators. The chunk requester is responsible of making that -availability a reality. +After a candidate is backed, the availability of the PoV block must be confirmed by 2/3+ of all validators. The chunk +requester is responsible of making that availability a reality. -It does that by querying checking occupied cores for all active leaves. For each -occupied core it will spawn a task fetching the erasure chunk which has the -`ValidatorIndex` of the node. For this an `ChunkFetchingRequest` is issued, via -substrate's generic request/response protocol. +It does that by querying checking occupied cores for all active leaves. For each occupied core it will spawn a task +fetching the erasure chunk which has the `ValidatorIndex` of the node. For this an `ChunkFetchingRequest` is issued, via +Substrate's generic request/response protocol. -The spawned task will start trying to fetch the chunk from validators in -responsible group of the occupied core, in a random order. For ensuring that we -use already open TCP connections wherever possible, the requester maintains a -cache and preserves that random order for the entire session. +The spawned task will start trying to fetch the chunk from validators in responsible group of the occupied core, in a +random order. For ensuring that we use already open TCP connections wherever possible, the requester maintains a cache +and preserves that random order for the entire session. -Note however that, because not all validators in a group have to be actual -backers, not all of them are required to have the needed chunk. This in turn -could lead to low throughput, as we have to wait for fetches to fail, -before reaching a validator finally having our chunk. We do rank back validators -not delivering our chunk, but as backers could vary from block to block on a -perfectly legitimate basis, this is still not ideal. See issues [2509](https://github.com/paritytech/polkadot/issues/2509) and [2512](https://github.com/paritytech/polkadot/issues/2512) -for more information. +Note however that, because not all validators in a group have to be actual backers, not all of them are required to have +the needed chunk. This in turn could lead to low throughput, as we have to wait for fetches to fail, before reaching a +validator finally having our chunk. We do rank back validators not delivering our chunk, but as backers could vary from +block to block on a perfectly legitimate basis, this is still not ideal. See issues +[2509](https://github.com/paritytech/polkadot/issues/2509) and +[2512](https://github.com/paritytech/polkadot/issues/2512) for more information. -The current implementation also only fetches chunks for occupied cores in blocks -in active leaves. This means though, if active leaves skips a block or we are -particularly slow in fetching our chunk, we might not fetch our chunk if -availability reached 2/3 fast enough (slot becomes free). This is not desirable -as we would like as many validators as possible to have their chunk. See this -[issue](https://github.com/paritytech/polkadot/issues/2513) for more details. +The current implementation also only fetches chunks for occupied cores in blocks in active leaves. This means though, if +active leaves skips a block or we are particularly slow in fetching our chunk, we might not fetch our chunk if +availability reached 2/3 fast enough (slot becomes free). This is not desirable as we would like as many validators as +possible to have their chunk. See this [issue](https://github.com/paritytech/polkadot/issues/2513) for more details. ### Serving -On the other side the subsystem will listen for incoming `ChunkFetchingRequest`s -and `PoVFetchingRequest`s from the network bridge and will respond to queries, -by looking the requested chunks and `PoV`s up in the availability store, this -happens in the `responder` module. +On the other side the subsystem will listen for incoming `ChunkFetchingRequest`s and `PoVFetchingRequest`s from the +network bridge and will respond to queries, by looking the requested chunks and `PoV`s up in the availability store, +this happens in the `responder` module. -We rely on the backing subsystem to make available data available locally in the -`Availability Store` after it has validated it. +We rely on the backing subsystem to make available data available locally in the `Availability Store` after it has +validated it. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md index ac733c1ce91..e3bb14db3a5 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md @@ -1,8 +1,13 @@ # Availability Recovery -This subsystem is the inverse of the [Availability Distribution](availability-distribution.md) subsystem: validators will serve the availability chunks kept in the availability store to nodes who connect to them. And the subsystem will also implement the other side: the logic for nodes to connect to validators, request availability pieces, and reconstruct the `AvailableData`. +This subsystem is the inverse of the [Availability Distribution](availability-distribution.md) subsystem: validators +will serve the availability chunks kept in the availability store to nodes who connect to them. And the subsystem will +also implement the other side: the logic for nodes to connect to validators, request availability pieces, and +reconstruct the `AvailableData`. -This version of the availability recovery subsystem is based off of direct connections to validators. In order to recover any given `AvailableData`, we must recover at least `f + 1` pieces from validators of the session. Thus, we will connect to and query randomly chosen validators until we have received `f + 1` pieces. +This version of the availability recovery subsystem is based off of direct connections to validators. In order to +recover any given `AvailableData`, we must recover at least `f + 1` pieces from validators of the session. Thus, we will +connect to and query randomly chosen validators until we have received `f + 1` pieces. ## Protocol @@ -10,18 +15,20 @@ This version of the availability recovery subsystem is based off of direct conne Input: -- `NetworkBridgeUpdate(update)` -- `AvailabilityRecoveryMessage::RecoverAvailableData(candidate, session, backing_group, response)` +* `NetworkBridgeUpdate(update)` +* `AvailabilityRecoveryMessage::RecoverAvailableData(candidate, session, backing_group, response)` Output: -- `NetworkBridge::SendValidationMessage` -- `NetworkBridge::ReportPeer` -- `AvailabilityStore::QueryChunk` +* `NetworkBridge::SendValidationMessage` +* `NetworkBridge::ReportPeer` +* `AvailabilityStore::QueryChunk` ## Functionality -We hold a state which tracks the currently ongoing recovery tasks, as well as which request IDs correspond to which task. A recovery task is a structure encapsulating all recovery tasks with the network necessary to recover the available data in respect to one candidate. +We hold a state which tracks the currently ongoing recovery tasks, as well as which request IDs correspond to which +task. A recovery task is a structure encapsulating all recovery tasks with the network necessary to recover the +available data in respect to one candidate. ```rust struct State { @@ -87,17 +94,22 @@ On `Conclude`, shut down the subsystem. 1. Check the `availability_lru` for the candidate and return the data if so. 1. Check if there is already an recovery handle for the request. If so, add the response handle to it. -1. Otherwise, load the session info for the given session under the state of `live_block_hash`, and initiate a recovery task with *`launch_recovery_task`*. Add a recovery handle to the state and add the response channel to it. +1. Otherwise, load the session info for the given session under the state of `live_block_hash`, and initiate a recovery + task with *`launch_recovery_task`*. Add a recovery handle to the state and add the response channel to it. 1. If the session info is not available, return `RecoveryError::Unavailable` on the response channel. ### Recovery logic #### `launch_recovery_task(session_index, session_info, candidate_receipt, candidate_hash, Option)` -1. Compute the threshold from the session info. It should be `f + 1`, where `n = 3f + k`, where `k in {1, 2, 3}`, and `n` is the number of validators. -1. Set the various fields of `RecoveryParams` based on the validator lists in `session_info` and information about the candidate. -1. If the `backing_group_index` is `Some`, start in the `RequestFromBackers` phase with a shuffling of the backing group validator indices and a `None` requesting value. -1. Otherwise, start in the `RequestChunksFromValidators` source with `received_chunks`,`requesting_chunks`, and `next_shuffling` all empty. +1. Compute the threshold from the session info. It should be `f + 1`, where `n = 3f + k`, where `k in {1, 2, 3}`, and + `n` is the number of validators. +1. Set the various fields of `RecoveryParams` based on the validator lists in `session_info` and information about the + candidate. +1. If the `backing_group_index` is `Some`, start in the `RequestFromBackers` phase with a shuffling of the backing group + validator indices and a `None` requesting value. +1. Otherwise, start in the `RequestChunksFromValidators` source with `received_chunks`,`requesting_chunks`, and + `next_shuffling` all empty. 1. Set the `to_subsystems` sender to be equal to a clone of the `SubsystemContext`'s sender. 1. Initialize `received_chunks` to an empty set, as well as `requesting_chunks`. @@ -115,19 +127,24 @@ const N_PARALLEL: usize = 50; * Loop: * If the `requesting_pov` is `Some`, poll for updates on it. If it concludes, set `requesting_pov` to `None`. * If the `requesting_pov` is `None`, take the next backer off the `shuffled_backers`. - * If the backer is `Some`, issue a `NetworkBridgeMessage::Requests` with a network request for the `AvailableData` and wait for the response. + * If the backer is `Some`, issue a `NetworkBridgeMessage::Requests` with a network request for the + `AvailableData` and wait for the response. * If it concludes with a `None` result, return to beginning. * If it concludes with available data, attempt a re-encoding. * If it has the correct erasure-root, break and issue a `Ok(available_data)`. * If it has an incorrect erasure-root, return to beginning. * Send the result to each member of `awaiting`. - * If the backer is `None`, set the source to `RequestChunksFromValidators` with a random shuffling of validators and empty `received_chunks`, and `requesting_chunks` and break the loop. + * If the backer is `None`, set the source to `RequestChunksFromValidators` with a random shuffling of validators + and empty `received_chunks`, and `requesting_chunks` and break the loop. * If the task contains `RequestChunksFromValidators`: - * Request `AvailabilityStoreMessage::QueryAllChunks`. For each chunk that exists, add it to `received_chunks` and remote the validator from `shuffling`. + * Request `AvailabilityStoreMessage::QueryAllChunks`. For each chunk that exists, add it to `received_chunks` and + remote the validator from `shuffling`. * Loop: - * If `received_chunks + requesting_chunks + shuffling` lengths are less than the threshold, break and return `Err(Unavailable)`. - * Poll for new updates from `requesting_chunks`. Check merkle proofs of any received chunks. If the request simply fails due to network issues, insert into the front of `shuffling` to be retried. + * If `received_chunks + requesting_chunks + shuffling` lengths are less than the threshold, break and return + `Err(Unavailable)`. + * Poll for new updates from `requesting_chunks`. Check merkle proofs of any received chunks. If the request simply + fails due to network issues, insert into the front of `shuffling` to be retried. * If `received_chunks` has more than `threshold` entries, attempt to recover the data. * If that fails, return `Err(RecoveryError::Invalid)` * If correct: @@ -135,5 +152,6 @@ const N_PARALLEL: usize = 50; * break and issue `Ok(available_data)` * Send the result to each member of `awaiting`. * While there are fewer than `N_PARALLEL` entries in `requesting_chunks`, - * Pop the next item from `shuffling`. If it's empty and `requesting_chunks` is empty, return `Err(RecoveryError::Unavailable)`. + * Pop the next item from `shuffling`. If it's empty and `requesting_chunks` is empty, return + `Err(RecoveryError::Unavailable)`. * Issue a `NetworkBridgeMessage::Requests` and wait for the response in `requesting_chunks`. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-distribution.md b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-distribution.md index 53bd8a1bced..097f2e63538 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-distribution.md @@ -1,34 +1,40 @@ # Bitfield Distribution -Validators vote on the availability of a backed candidate by issuing signed bitfields, where each bit corresponds to a single candidate. These bitfields can be used to compactly determine which backed candidates are available or not based on a 2/3+ quorum. +Validators vote on the availability of a backed candidate by issuing signed bitfields, where each bit corresponds to a +single candidate. These bitfields can be used to compactly determine which backed candidates are available or not based +on a 2/3+ quorum. ## Protocol `PeerSet`: `Validation` -Input: -[`BitfieldDistributionMessage`](../../types/overseer-protocol.md#bitfield-distribution-message) which are gossiped to all peers, no matter if validator or not. +Input: [`BitfieldDistributionMessage`](../../types/overseer-protocol.md#bitfield-distribution-message) which are +gossiped to all peers, no matter if validator or not. Output: -- `NetworkBridge::SendValidationMessage([PeerId], message)` gossip a verified incoming bitfield on to interested subsystems within this validator node. -- `NetworkBridge::ReportPeer(PeerId, cost_or_benefit)` improve or penalize the reputation of peers based on the messages that are received relative to the current view. -- `ProvisionerMessage::ProvisionableData(ProvisionableData::Bitfield(relay_parent, SignedAvailabilityBitfield))` pass - on the bitfield to the other submodules via the overseer. +- `NetworkBridge::SendValidationMessage([PeerId], message)` gossip a verified incoming bitfield on to interested + subsystems within this validator node. +- `NetworkBridge::ReportPeer(PeerId, cost_or_benefit)` improve or penalize the reputation of peers based on the messages + that are received relative to the current view. +- `ProvisionerMessage::ProvisionableData(ProvisionableData::Bitfield(relay_parent, SignedAvailabilityBitfield))` pass on + the bitfield to the other submodules via the overseer. ## Functionality This is implemented as a gossip system. -It is necessary to track peer connection, view change, and disconnection events, in order to maintain an index of which peers are interested in which relay parent bitfields. +It is necessary to track peer connection, view change, and disconnection events, in order to maintain an index of which +peers are interested in which relay parent bitfields. -Before gossiping incoming bitfields, they must be checked to be signed by one of the validators -of the validator set relevant to the current relay parent. -Only accept bitfields relevant to our current view and only distribute bitfields to other peers when relevant to their most recent view. -Accept and distribute only one bitfield per validator. +Before gossiping incoming bitfields, they must be checked to be signed by one of the validators of the validator set +relevant to the current relay parent. Only accept bitfields relevant to our current view and only distribute bitfields +to other peers when relevant to their most recent view. Accept and distribute only one bitfield per validator. -When receiving a bitfield either from the network or from a `DistributeBitfield` message, forward it along to the block authorship (provisioning) subsystem for potential inclusion in a block. +When receiving a bitfield either from the network or from a `DistributeBitfield` message, forward it along to the block +authorship (provisioning) subsystem for potential inclusion in a block. -Peers connecting after a set of valid bitfield gossip messages was received, those messages must be cached and sent upon connection of new peers or re-connecting peers. +Peers connecting after a set of valid bitfield gossip messages was received, those messages must be cached and sent upon +connection of new peers or re-connecting peers. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md index 08cbe528473..a5875e0a805 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md @@ -1,12 +1,15 @@ # Bitfield Signing -Validators vote on the availability of a backed candidate by issuing signed bitfields, where each bit corresponds to a single candidate. These bitfields can be used to compactly determine which backed candidates are available or not based on a 2/3+ quorum. +Validators vote on the availability of a backed candidate by issuing signed bitfields, where each bit corresponds to a +single candidate. These bitfields can be used to compactly determine which backed candidates are available or not based +on a 2/3+ quorum. ## Protocol Input: -There is no dedicated input mechanism for bitfield signing. Instead, Bitfield Signing produces a bitfield representing the current state of availability on `StartWork`. +There is no dedicated input mechanism for bitfield signing. Instead, Bitfield Signing produces a bitfield representing +the current state of availability on `StartWork`. Output: @@ -15,15 +18,20 @@ Output: ## Functionality -Upon receipt of an `ActiveLeavesUpdate`, launch bitfield signing job for each `activated` head referring to a fresh leaf. Stop the job for each `deactivated` head. +Upon receipt of an `ActiveLeavesUpdate`, launch bitfield signing job for each `activated` head referring to a fresh +leaf. Stop the job for each `deactivated` head. ## Bitfield Signing Job -Localized to a specific relay-parent `r` -If not running as a validator, do nothing. +Localized to a specific relay-parent `r` If not running as a validator, do nothing. -- For each fresh leaf, begin by waiting a fixed period of time so availability distribution has the chance to make candidates available. -- Determine our validator index `i`, the set of backed candidates pending availability in `r`, and which bit of the bitfield each corresponds to. -- Start with an empty bitfield. For each bit in the bitfield, if there is a candidate pending availability, query the [Availability Store](../utility/availability-store.md) for whether we have the availability chunk for our validator index. The `OccupiedCore` struct contains the candidate hash so the full candidate does not need to be fetched from runtime. +- For each fresh leaf, begin by waiting a fixed period of time so availability distribution has the chance to make + candidates available. +- Determine our validator index `i`, the set of backed candidates pending availability in `r`, and which bit of the + bitfield each corresponds to. +- Start with an empty bitfield. For each bit in the bitfield, if there is a candidate pending availability, query the + [Availability Store](../utility/availability-store.md) for whether we have the availability chunk for our validator + index. The `OccupiedCore` struct contains the candidate hash so the full candidate does not need to be fetched from + runtime. - For all chunks we have, set the corresponding bit in the bitfield. - Sign the bitfield and dispatch a `BitfieldDistribution::DistributeBitfield` message. diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/README.md b/polkadot/roadmap/implementers-guide/src/node/backing/README.md index ac47abefb0d..d2a77ded6b7 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/README.md @@ -1,10 +1,15 @@ # Backing Subsystems -The backing subsystems, when conceived as a black box, receive an arbitrary quantity of parablock candidates and associated proofs of validity from arbitrary untrusted collators. From these, they produce a bounded quantity of backable candidates which relay chain block authors may choose to include in a subsequent block. +The backing subsystems, when conceived as a black box, receive an arbitrary quantity of parablock candidates and +associated proofs of validity from arbitrary untrusted collators. From these, they produce a bounded quantity of +backable candidates which relay chain block authors may choose to include in a subsequent block. In broad strokes, the flow operates like this: - **Candidate Selection** winnows the field of parablock candidates, selecting up to one of them to second. -- **Candidate Backing** ensures that a seconding candidate is valid, then generates the appropriate `Statement`. It also keeps track of which candidates have received the backing of a quorum of other validators. -- **Statement Distribution** is the networking component which ensures that all validators receive each others' statements. -- **PoV Distribution** is the networking component which ensures that validators considering a candidate can get the appropriate PoV. +- **Candidate Backing** ensures that a seconding candidate is valid, then generates the appropriate `Statement`. It also + keeps track of which candidates have received the backing of a quorum of other validators. +- **Statement Distribution** is the networking component which ensures that all validators receive each others' + statements. +- **PoV Distribution** is the networking component which ensures that validators considering a candidate can get the + appropriate PoV. diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/candidate-backing.md b/polkadot/roadmap/implementers-guide/src/node/backing/candidate-backing.md index 0eee0cc532e..31f8423fe27 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/candidate-backing.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/candidate-backing.md @@ -1,12 +1,20 @@ # Candidate Backing -The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at least one validator, and approved by a quorum. Parablocks for which not enough validators will assert correctness are discarded. If the block later proves invalid, the initial backers are slashable; this gives polkadot a rational threat model during subsequent stages. +The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at +least one validator, and approved by a quorum. Parablocks for which not enough validators will assert correctness are +discarded. If the block later proves invalid, the initial backers are slashable; this gives Polkadot a rational threat +model during subsequent stages. -Its role is to produce backable candidates for inclusion in new relay-chain blocks. It does so by issuing signed [`Statement`s][Statement] and tracking received statements signed by other validators. Once enough statements are received, they can be combined into backing for specific candidates. +Its role is to produce backable candidates for inclusion in new relay-chain blocks. It does so by issuing signed +[`Statement`s][Statement] and tracking received statements signed by other validators. Once enough statements are +received, they can be combined into backing for specific candidates. -Note that though the candidate backing subsystem attempts to produce as many backable candidates as possible, it does _not_ attempt to choose a single authoritative one. The choice of which actually gets included is ultimately up to the block author, by whatever metrics it may use; those are opaque to this subsystem. +Note that though the candidate backing subsystem attempts to produce as many backable candidates as possible, it does +_not_ attempt to choose a single authoritative one. The choice of which actually gets included is ultimately up to the +block author, by whatever metrics it may use; those are opaque to this subsystem. -Once a sufficient quorum has agreed that a candidate is valid, this subsystem notifies the [Provisioner][PV], which in turn engages block production mechanisms to include the parablock. +Once a sufficient quorum has agreed that a candidate is valid, this subsystem notifies the [Provisioner][PV], which in +turn engages block production mechanisms to include the parablock. ## Protocol @@ -14,33 +22,49 @@ Input: [`CandidateBackingMessage`][CBM] Output: -- [`CandidateValidationMessage`][CVM] -- [`RuntimeApiMessage`][RAM] -- [`CollatorProtocolMessage`][CPM] -- [`ProvisionerMessage`][PM] -- [`AvailabilityDistributionMessage`][ADM] -- [`StatementDistributionMessage`][SDM] +* [`CandidateValidationMessage`][CVM] +* [`RuntimeApiMessage`][RAM] +* [`CollatorProtocolMessage`][CPM] +* [`ProvisionerMessage`][PM] +* [`AvailabilityDistributionMessage`][ADM] +* [`StatementDistributionMessage`][SDM] ## Functionality -The [Collator Protocol][CP] subsystem is the primary source of non-overseer messages into this subsystem. That subsystem generates appropriate [`CandidateBackingMessage`s][CBM] and passes them to this subsystem. +The [Collator Protocol][CP] subsystem is the primary source of non-overseer messages into this subsystem. That subsystem +generates appropriate [`CandidateBackingMessage`s][CBM] and passes them to this subsystem. -This subsystem requests validation from the [Candidate Validation][CV] and generates an appropriate [`Statement`][Statement]. All `Statement`s are then passed on to the [Statement Distribution][SD] subsystem to be gossiped to peers. When [Candidate Validation][CV] decides that a candidate is invalid, and it was recommended to us to second by our own [Collator Protocol][CP] subsystem, a message is sent to the [Collator Protocol][CP] subsystem with the candidate's hash so that the collator which recommended it can be penalized. +This subsystem requests validation from the [Candidate Validation][CV] and generates an appropriate +[`Statement`][Statement]. All `Statement`s are then passed on to the [Statement Distribution][SD] subsystem to be +gossiped to peers. When [Candidate Validation][CV] decides that a candidate is invalid, and it was recommended to us to +second by our own [Collator Protocol][CP] subsystem, a message is sent to the [Collator Protocol][CP] subsystem with the +candidate's hash so that the collator which recommended it can be penalized. -The subsystem should maintain a set of handles to Candidate Backing Jobs that are currently live, as well as the relay-parent to which they correspond. +The subsystem should maintain a set of handles to Candidate Backing Jobs that are currently live, as well as the +relay-parent to which they correspond. ### On Overseer Signal * If the signal is an [`OverseerSignal`][OverseerSignal]`::ActiveLeavesUpdate`: - * spawn a Candidate Backing Job for each `activated` head referring to a fresh leaf, storing a bidirectional channel with the Candidate Backing Job in the set of handles. + * spawn a Candidate Backing Job for each `activated` head referring to a fresh leaf, storing a bidirectional channel + with the Candidate Backing Job in the set of handles. * cease the Candidate Backing Job for each `deactivated` head, if any. -* If the signal is an [`OverseerSignal`][OverseerSignal]`::Conclude`: Forward conclude messages to all jobs, wait a small amount of time for them to join, and then exit. +* If the signal is an [`OverseerSignal`][OverseerSignal]`::Conclude`: Forward conclude messages to all jobs, wait a + small amount of time for them to join, and then exit. ### On Receiving `CandidateBackingMessage` -* If the message is a [`CandidateBackingMessage`][CBM]`::GetBackedCandidates`, get all backable candidates from the statement table and send them back. -* If the message is a [`CandidateBackingMessage`][CBM]`::Second`, sign and dispatch a `Seconded` statement only if we have not seconded any other candidate and have not signed a `Valid` statement for the requested candidate. Signing both a `Seconded` and `Valid` message is a double-voting misbehavior with a heavy penalty, and this could occur if another validator has seconded the same candidate and we've received their message before the internal seconding request. -* If the message is a [`CandidateBackingMessage`][CBM]`::Statement`, count the statement to the quorum. If the statement in the message is `Seconded` and it contains a candidate that belongs to our assignment, request the corresponding `PoV` from the backing node via `AvailabilityDistribution` and launch validation. Issue our own `Valid` or `Invalid` statement as a result. +* If the message is a [`CandidateBackingMessage`][CBM]`::GetBackedCandidates`, get all backable candidates from the + statement table and send them back. +* If the message is a [`CandidateBackingMessage`][CBM]`::Second`, sign and dispatch a `Seconded` statement only if we + have not seconded any other candidate and have not signed a `Valid` statement for the requested candidate. Signing + both a `Seconded` and `Valid` message is a double-voting misbehavior with a heavy penalty, and this could occur if + another validator has seconded the same candidate and we've received their message before the internal seconding + request. +* If the message is a [`CandidateBackingMessage`][CBM]`::Statement`, count the statement to the quorum. If the statement + in the message is `Seconded` and it contains a candidate that belongs to our assignment, request the corresponding + `PoV` from the backing node via `AvailabilityDistribution` and launch validation. Issue our own `Valid` or `Invalid` + statement as a result. If the seconding node did not provide us with the `PoV` we will retry fetching from other backing validators. @@ -51,19 +75,25 @@ If the seconding node did not provide us with the `PoV` we will retry fetching f > * Allow inclusion of _old_ parachain candidates validated by _current_ validators. > * Allow inclusion of _old_ parachain candidates validated by _old_ validators. > -> This will probably blur the lines between jobs, will probably require inter-job communication and a short-term memory of recently backable, but not backed candidates. +> This will probably blur the lines between jobs, will probably require inter-job communication and a short-term memory +> of recently backable, but not backed candidates. ## Candidate Backing Job -The Candidate Backing Job represents the work a node does for backing candidates with respect to a particular relay-parent. +The Candidate Backing Job represents the work a node does for backing candidates with respect to a particular +relay-parent. -The goal of a Candidate Backing Job is to produce as many backable candidates as possible. This is done via signed [`Statement`s][STMT] by validators. If a candidate receives a majority of supporting Statements from the Parachain Validators currently assigned, then that candidate is considered backable. +The goal of a Candidate Backing Job is to produce as many backable candidates as possible. This is done via signed +[`Statement`s][STMT] by validators. If a candidate receives a majority of supporting Statements from the Parachain +Validators currently assigned, then that candidate is considered backable. ### On Startup -* Fetch current validator set, validator -> parachain assignments from [`Runtime API`][RA] subsystem using [`RuntimeApiRequest::Validators`][RAM] and [`RuntimeApiRequest::ValidatorGroups`][RAM] +* Fetch current validator set, validator -> parachain assignments from [`Runtime API`][RA] subsystem using + [`RuntimeApiRequest::Validators`][RAM] and [`RuntimeApiRequest::ValidatorGroups`][RAM] * Determine if the node controls a key in the current validator set. Call this the local key if so. -* If the local key exists, extract the parachain head and validation function from the [`Runtime API`][RA] for the parachain the local key is assigned to by issuing a [`RuntimeApiRequest::Validators`][RAM] +* If the local key exists, extract the parachain head and validation function from the [`Runtime API`][RA] for the + parachain the local key is assigned to by issuing a [`RuntimeApiRequest::Validators`][RAM] * Issue a [`RuntimeApiRequest::SigningContext`][RAM] message to get a context that will later be used upon signing. ### On Receiving New Candidate Backing Message @@ -91,15 +121,17 @@ match msg { } ``` -Add `Seconded` statements and `Valid` statements to a quorum. If the quorum reaches a pre-defined threshold, send a [`ProvisionerMessage`][PM]`::ProvisionableData(ProvisionableData::BackedCandidate(CandidateReceipt))` message. -`Invalid` statements that conflict with already witnessed `Seconded` and `Valid` statements for the given candidate, statements that are double-votes, self-contradictions and so on, should result in issuing a [`ProvisionerMessage`][PM]`::MisbehaviorReport` message for each newly detected case of this kind. +Add `Seconded` statements and `Valid` statements to a quorum. If the quorum reaches a pre-defined threshold, send a +[`ProvisionerMessage`][PM]`::ProvisionableData(ProvisionableData::BackedCandidate(CandidateReceipt))` message. `Invalid` +statements that conflict with already witnessed `Seconded` and `Valid` statements for the given candidate, statements +that are double-votes, self-contradictions and so on, should result in issuing a +[`ProvisionerMessage`][PM]`::MisbehaviorReport` message for each newly detected case of this kind. -Backing does not need to concern itself with providing statements to the dispute -coordinator as the dispute coordinator scrapes them from chain. This way the -import is batched and contains only statements that actually made it on some +Backing does not need to concern itself with providing statements to the dispute coordinator as the dispute coordinator +scrapes them from chain. This way the import is batched and contains only statements that actually made it on some chain. -### Validating Candidates. +### Validating Candidates ```rust fn spawn_validation_work(candidate, parachain head, validation function) { @@ -119,14 +151,16 @@ fn spawn_validation_work(candidate, parachain head, validation function) { ### Fetch PoV Block -Create a `(sender, receiver)` pair. -Dispatch a [`AvailabilityDistributionMessage`][ADM]`::FetchPoV{ validator_index, pov_hash, candidate_hash, tx, } and listen on the passed receiver for a response. Availability distribution will send the request to the validator specified by `validator_index`, which might not be serving it for whatever reasons, therefore we need to retry with other backing validators in that case. +Create a `(sender, receiver)` pair. Dispatch a [`AvailabilityDistributionMessage`][ADM]`::FetchPoV{ validator_index, +pov_hash, candidate_hash, tx, }` and listen on the passed receiver for a response. Availability distribution will send +the request to the validator specified by `validator_index`, which might not be serving it for whatever reasons, +therefore we need to retry with other backing validators in that case. ### Validate PoV Block -Create a `(sender, receiver)` pair. -Dispatch a `CandidateValidationMessage::Validate(validation function, candidate, pov, BACKING_EXECUTION_TIMEOUT, sender)` and listen on the receiver for a response. +Create a `(sender, receiver)` pair. Dispatch a `CandidateValidationMessage::Validate(validation function, candidate, +pov, BACKING_EXECUTION_TIMEOUT, sender)` and listen on the receiver for a response. ### Distribute Signed Statement diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md index 5cbc875d8a7..e10a55010b9 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md @@ -1,18 +1,16 @@ # Statement Distribution (Legacy) -This describes the legacy, backwards-compatible version of the Statement -Distribution subsystem. +This describes the legacy, backwards-compatible version of the Statement Distribution subsystem. -**Note:** All the V1 (legacy) code was extracted out to a `legacy_v1` module of -the `statement-distribution` crate, which doesn't alter any logic. V2 (new -protocol) peers also run `legacy_v1` and communicate with V1 peers using V1 -messages and with V2 peers using V2 messages. Once the runtime upgrade goes -through on all networks, this `legacy_v1` code will no longer be triggered and -will be vestigial and can be removed. +**Note:** All the V1 (legacy) code was extracted out to a `legacy_v1` module of the `statement-distribution` crate, +which doesn't alter any logic. V2 (new protocol) peers also run `legacy_v1` and communicate with V1 peers using V1 +messages and with V2 peers using V2 messages. Once the runtime upgrade goes through on all networks, this `legacy_v1` +code will no longer be triggered and will be vestigial and can be removed. ## Overview -The Statement Distribution Subsystem is responsible for distributing statements about seconded candidates between validators. +The Statement Distribution Subsystem is responsible for distributing statements about seconded candidates between +validators. ## Protocol @@ -31,89 +29,133 @@ Output: ## Functionality -Implemented as a gossip protocol. Handles updates to our view and peers' views. Neighbor packets are used to inform peers which chain heads we are interested in data for. +Implemented as a gossip protocol. Handles updates to our view and peers' views. Neighbor packets are used to inform +peers which chain heads we are interested in data for. -The Statement Distribution Subsystem is responsible for distributing signed statements that we have generated and for forwarding statements generated by other validators. It also detects a variety of Validator misbehaviors for reporting to the [Provisioner Subsystem](../utility/provisioner.md). During the Backing stage of the inclusion pipeline, Statement Distribution is the main point of contact with peer nodes. On receiving a signed statement from a peer in the same backing group, assuming the peer receipt state machine is in an appropriate state, it sends the Candidate Receipt to the [Candidate Backing subsystem](candidate-backing.md) to handle the validator's statement. On receiving `StatementDistributionMessage::Share` we make sure to send messages to our backing group in addition to random other peers, to ensure a fast backing process and getting all statements quickly for distribution. +The Statement Distribution Subsystem is responsible for distributing signed statements that we have generated and for +forwarding statements generated by other validators. It also detects a variety of Validator misbehaviors for reporting +to the [Provisioner Subsystem](../utility/provisioner.md). During the Backing stage of the inclusion pipeline, Statement +Distribution is the main point of contact with peer nodes. On receiving a signed statement from a peer in the same +backing group, assuming the peer receipt state machine is in an appropriate state, it sends the Candidate Receipt to the +[Candidate Backing subsystem](candidate-backing.md) to handle the validator's statement. On receiving +`StatementDistributionMessage::Share` we make sure to send messages to our backing group in addition to random other +peers, to ensure a fast backing process and getting all statements quickly for distribution. -This subsystem tracks equivocating validators and stops accepting information from them. It establishes a data-dependency order: +This subsystem tracks equivocating validators and stops accepting information from them. It establishes a +data-dependency order: - In order to receive a `Seconded` message we have the corresponding chain head in our view - In order to receive a `Valid` message we must have received the corresponding `Seconded` message. -And respect this data-dependency order from our peers by respecting their views. This subsystem is responsible for checking message signatures. +And respect this data-dependency order from our peers by respecting their views. This subsystem is responsible for +checking message signatures. The Statement Distribution subsystem sends statements to peer nodes. ## Peer Receipt State Machine -There is a very simple state machine which governs which messages we are willing to receive from peers. Not depicted in the state machine: on initial receipt of any [`SignedFullStatement`](../../types/backing.md#signed-statement-type), validate that the provided signature does in fact sign the included data. Note that each individual parablock candidate gets its own instance of this state machine; it is perfectly legal to receive a `Valid(X)` before a `Seconded(Y)`, as long as a `Seconded(X)` has been received. +There is a very simple state machine which governs which messages we are willing to receive from peers. Not depicted in +the state machine: on initial receipt of any [`SignedFullStatement`](../../types/backing.md#signed-statement-type), +validate that the provided signature does in fact sign the included data. Note that each individual parablock candidate +gets its own instance of this state machine; it is perfectly legal to receive a `Valid(X)` before a `Seconded(Y)`, as +long as a `Seconded(X)` has been received. -A: Initial State. Receive `SignedFullStatement(Statement::Second)`: extract `Statement`, forward to Candidate Backing, proceed to B. Receive any other `SignedFullStatement` variant: drop it. +A: Initial State. Receive `SignedFullStatement(Statement::Second)`: extract `Statement`, forward to Candidate Backing, +proceed to B. Receive any other `SignedFullStatement` variant: drop it. -B: Receive any `SignedFullStatement`: check signature and determine whether the statement is new to us. if new, forward to Candidate Backing and circulate to other peers. Receive `OverseerMessage::StopWork`: proceed to C. +B: Receive any `SignedFullStatement`: check signature and determine whether the statement is new to us. if new, forward +to Candidate Backing and circulate to other peers. Receive `OverseerMessage::StopWork`: proceed to C. C: Receive any message for this block: drop it. -For large statements (see below), we also keep track of the total received large -statements per peer and have a hard limit on that number for flood protection. -This is necessary as in the current code we only forward statements once we have -all the data, therefore flood protection for large statement is a bit more -subtle. This will become an obsolete problem once [off chain code -upgrades](https://github.com/paritytech/polkadot/issues/2979) are implemented. +For large statements (see below), we also keep track of the total received large statements per peer and have a hard +limit on that number for flood protection. This is necessary as in the current code we only forward statements once we +have all the data, therefore flood protection for large statement is a bit more subtle. This will become an obsolete +problem once [off chain code upgrades](https://github.com/paritytech/polkadot/issues/2979) are implemented. ## Peer Knowledge Tracking -The peer receipt state machine implies that for parsimony of network resources, we should model the knowledge of our peers, and help them out. For example, let's consider a case with peers A, B, and C, validators X and Y, and candidate M. A sends us a `Statement::Second(M)` signed by X. We've double-checked it, and it's valid. While we're checking it, we receive a copy of X's `Statement::Second(M)` from `B`, along with a `Statement::Valid(M)` signed by Y. +The peer receipt state machine implies that for parsimony of network resources, we should model the knowledge of our +peers, and help them out. For example, let's consider a case with peers A, B, and C, validators X and Y, and candidate +M. A sends us a `Statement::Second(M)` signed by X. We've double-checked it, and it's valid. While we're checking it, we +receive a copy of X's `Statement::Second(M)` from `B`, along with a `Statement::Valid(M)` signed by Y. -Our response to A is just the `Statement::Valid(M)` signed by Y. However, we haven't heard anything about this from C. Therefore, we send it everything we have: first a copy of X's `Statement::Second`, then Y's `Statement::Valid`. +Our response to A is just the `Statement::Valid(M)` signed by Y. However, we haven't heard anything about this from C. +Therefore, we send it everything we have: first a copy of X's `Statement::Second`, then Y's `Statement::Valid`. -This system implies a certain level of duplication of messages--we received X's `Statement::Second` from both our peers, and C may experience the same--but it minimizes the degree to which messages are simply dropped. +This system implies a certain level of duplication of messages--we received X's `Statement::Second` from both our peers, +and C may experience the same--but it minimizes the degree to which messages are simply dropped. And respect this data-dependency order from our peers. This subsystem is responsible for checking message signatures. -No jobs. We follow view changes from the [`NetworkBridge`](../utility/network-bridge.md), which in turn is updated by the overseer. +No jobs. We follow view changes from the [`NetworkBridge`](../utility/network-bridge.md), which in turn is updated by +the overseer. ## Equivocations and Flood Protection -An equivocation is a double-vote by a validator. The [Candidate Backing](candidate-backing.md) Subsystem is better-suited than this one to detect equivocations as it adds votes to quorum trackers. +An equivocation is a double-vote by a validator. The [Candidate Backing](candidate-backing.md) Subsystem is +better-suited than this one to detect equivocations as it adds votes to quorum trackers. -At this level, we are primarily concerned about flood-protection, and to some extent, detecting equivocations is a part of that. In particular, we are interested in detecting equivocations of `Seconded` statements. Since every other statement is dependent on `Seconded` statements, ensuring that we only ever hold a bounded number of `Seconded` statements is sufficient for flood-protection. +At this level, we are primarily concerned about flood-protection, and to some extent, detecting equivocations is a part +of that. In particular, we are interested in detecting equivocations of `Seconded` statements. Since every other +statement is dependent on `Seconded` statements, ensuring that we only ever hold a bounded number of `Seconded` +statements is sufficient for flood-protection. -The simple approach is to say that we only receive up to two `Seconded` statements per validator per chain head. However, the marginal cost of equivocation, conditional on having already equivocated, is close to 0, since a single double-vote offence is counted as all double-vote offences for a particular chain-head. Even if it were not, there is some amount of equivocations that can be done such that the marginal cost of issuing further equivocations is close to 0, as there would be an amount of equivocations necessary to be completely and totally obliterated by the slashing algorithm. We fear the validator with nothing left to lose. +The simple approach is to say that we only receive up to two `Seconded` statements per validator per chain head. +However, the marginal cost of equivocation, conditional on having already equivocated, is close to 0, since a single +double-vote offence is counted as all double-vote offences for a particular chain-head. Even if it were not, there is +some amount of equivocations that can be done such that the marginal cost of issuing further equivocations is close to +0, as there would be an amount of equivocations necessary to be completely and totally obliterated by the slashing +algorithm. We fear the validator with nothing left to lose. With that in mind, this simple approach has a caveat worth digging deeper into. -First: We may be aware of two equivocated `Seconded` statements issued by a validator. A totally honest peer of ours can also be aware of one or two different `Seconded` statements issued by the same validator. And yet another peer may be aware of one or two _more_ `Seconded` statements. And so on. This interacts badly with pre-emptive sending logic. Upon sending a `Seconded` statement to a peer, we will want to pre-emptively follow up with all statements relative to that candidate. Waiting for acknowledgment introduces latency at every hop, so that is best avoided. What can happen is that upon receipt of the `Seconded` statement, the peer will discard it as it falls beyond the bound of 2 that it is allowed to store. It cannot store anything in memory about discarded candidates as that would introduce a DoS vector. Then, the peer would receive from us all of the statements pertaining to that candidate, which, from its perspective, would be undesired - they are data-dependent on the `Seconded` statement we sent them, but they have erased all record of that from their memory. Upon receiving a potential flood of undesired statements, this 100% honest peer may choose to disconnect from us. In this way, an adversary may be able to partition the network with careful distribution of equivocated `Seconded` statements. - -The fix is to track, per-peer, the hashes of up to 4 candidates per validator (per relay-parent) that the peer is aware of. It is 4 because we may send them 2 and they may send us 2 different ones. We track the data that they are aware of as the union of things we have sent them and things they have sent us. If we receive a 1st or 2nd `Seconded` statement from a peer, we note it in the peer's known candidates even if we do disregard the data locally. And then, upon receipt of any data dependent on that statement, we do not reduce that peer's standing in our eyes, as the data was not undesired. - -There is another caveat to the fix: we don't want to allow the peer to flood us because it has set things up in a way that it knows we will drop all of its traffic. -We also track how many statements we have received per peer, per candidate, and per chain-head. This is any statement concerning a particular candidate: `Seconded`, `Valid`, or `Invalid`. If we ever receive a statement from a peer which would push any of these counters beyond twice the amount of validators at the chain-head, we begin to lower the peer's standing and eventually disconnect. This bound is a massive overestimate and could be reduced to twice the number of validators in the corresponding validator group. It is worth noting that the goal at the time of writing is to ensure any finite bound on the amount of stored data, as any equivocation results in a large slash. +First: We may be aware of two equivocated `Seconded` statements issued by a validator. A totally honest peer of ours can +also be aware of one or two different `Seconded` statements issued by the same validator. And yet another peer may be +aware of one or two _more_ `Seconded` statements. And so on. This interacts badly with pre-emptive sending logic. Upon +sending a `Seconded` statement to a peer, we will want to pre-emptively follow up with all statements relative to that +candidate. Waiting for acknowledgment introduces latency at every hop, so that is best avoided. What can happen is that +upon receipt of the `Seconded` statement, the peer will discard it as it falls beyond the bound of 2 that it is allowed +to store. It cannot store anything in memory about discarded candidates as that would introduce a DoS vector. Then, the +peer would receive from us all of the statements pertaining to that candidate, which, from its perspective, would be +undesired - they are data-dependent on the `Seconded` statement we sent them, but they have erased all record of that +from their memory. Upon receiving a potential flood of undesired statements, this 100% honest peer may choose to +disconnect from us. In this way, an adversary may be able to partition the network with careful distribution of +equivocated `Seconded` statements. + +The fix is to track, per-peer, the hashes of up to 4 candidates per validator (per relay-parent) that the peer is aware +of. It is 4 because we may send them 2 and they may send us 2 different ones. We track the data that they are aware of +as the union of things we have sent them and things they have sent us. If we receive a 1st or 2nd `Seconded` statement +from a peer, we note it in the peer's known candidates even if we do disregard the data locally. And then, upon receipt +of any data dependent on that statement, we do not reduce that peer's standing in our eyes, as the data was not +undesired. + +There is another caveat to the fix: we don't want to allow the peer to flood us because it has set things up in a way +that it knows we will drop all of its traffic. We also track how many statements we have received per peer, per +candidate, and per chain-head. This is any statement concerning a particular candidate: `Seconded`, `Valid`, or +`Invalid`. If we ever receive a statement from a peer which would push any of these counters beyond twice the amount of +validators at the chain-head, we begin to lower the peer's standing and eventually disconnect. This bound is a massive +overestimate and could be reduced to twice the number of validators in the corresponding validator group. It is worth +noting that the goal at the time of writing is to ensure any finite bound on the amount of stored data, as any +equivocation results in a large slash. ## Large statements -Seconded statements can become quite large on parachain runtime upgrades for -example. For this reason, there exists a `LargeStatement` constructor for the -`StatementDistributionMessage` wire message, which only contains light metadata -of a statement. The actual candidate data is not included. This message type is -used whenever a message is deemed large. The receiver of such a message needs to -request the actual payload via request/response by means of a +Seconded statements can become quite large on parachain runtime upgrades for example. For this reason, there exists a +`LargeStatement` constructor for the `StatementDistributionMessage` wire message, which only contains light metadata of +a statement. The actual candidate data is not included. This message type is used whenever a message is deemed large. +The receiver of such a message needs to request the actual payload via request/response by means of a `StatementFetchingV1` request. -This is necessary as distribution of a large payload (mega bytes) via gossip -would make the network collapse and timely distribution of statements would no -longer be possible. By using request/response it is ensured that each peer only -transferes large data once. We only take good care to detect an overloaded -peer early and immediately move on to a different peer for fetching the data. -This mechanism should result in a good load distribution and therefore a rather +This is necessary as distribution of a large payload (mega bytes) via gossip would make the network collapse and timely +distribution of statements would no longer be possible. By using request/response it is ensured that each peer only +transferes large data once. We only take good care to detect an overloaded peer early and immediately move on to a +different peer for fetching the data. This mechanism should result in a good load distribution and therefore a rather optimal distribution path. -With these optimizations, distribution of payloads in the size of up to 3 to 4 -MB should work with Kusama validator specifications. For scaling up even more, -runtime upgrades and message passing should be done off chain at some point. +With these optimizations, distribution of payloads in the size of up to 3 to 4 MB should work with Kusama validator +specifications. For scaling up even more, runtime upgrades and message passing should be done off chain at some point. -Flood protection considerations: For making DoS attacks slightly harder on this -subsystem, nodes will only respond to large statement requests, when they -previously notified that peer via gossip about that statement. So, it is not -possible to DoS nodes at scale, by requesting candidate data over and over -again. +Flood protection considerations: For making DoS attacks slightly harder on this subsystem, nodes will only respond to +large statement requests, when they previously notified that peer via gossip about that statement. So, it is not +possible to DoS nodes at scale, by requesting candidate data over and over again. diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md index 2e014284821..24f2785f829 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md @@ -1,158 +1,127 @@ # Statement Distribution -This subsystem is responsible for distributing signed statements that we have generated and forwarding statements generated by our peers. Received candidate receipts and statements are passed to the [Candidate Backing subsystem](candidate-backing.md) to handle producing local statements. On receiving `StatementDistributionMessage::Share`, this subsystem distributes the message across the network with redundency to ensure a fast backing process. +This subsystem is responsible for distributing signed statements that we have generated and forwarding statements +generated by our peers. Received candidate receipts and statements are passed to the [Candidate Backing +subsystem](candidate-backing.md) to handle producing local statements. On receiving +`StatementDistributionMessage::Share`, this subsystem distributes the message across the network with redundency to +ensure a fast backing process. ## Overview -**Goal:** every well-connected node is aware of every next potential parachain -block. +**Goal:** every well-connected node is aware of every next potential parachain block. Validators can either: - receive parachain block from collator, check block, and gossip statement. -- receive statements from other validators, check the parachain block if it - originated within their own group, gossip forward statement if valid. - -Validators must have statements, candidates, and persisted validation from all -other validators. This is because we need to store statements from validators -who've checked the candidate on the relay chain, so we know who to hold -accountable in case of disputes. Any validator can be selected as the next -relay-chain block author, and this is not revealed in advance for security -reasons. As a result, all validators must have a up to date view of all possible -parachain candidates + backing statements that could be placed on-chain in the -next block. - -[This blog post](https://polkadot.network/blog/polkadot-v1-0-sharding-and-economic-security) -puts it another way: "Validators who aren't assigned to the parachain still -listen for the attestations [statements] because whichever validator ends up -being the author of the relay-chain block needs to bundle up attested parachain -blocks for several parachains and place them into the relay-chain block." - -Backing-group quorum (that is, enough backing group votes) must be reached -before the block author will consider the candidate. Therefore, validators need -to consider _all_ seconded candidates within their own group, because that's -what they're assigned to work on. Validators only need to consider _backable_ -candidates from other groups. This informs the design of the statement -distribution protocol to have separate phases for in-group and out-group -distribution, respectively called "cluster" and "grid" mode (see below). +- receive statements from other validators, check the parachain block if it originated within their own group, gossip + forward statement if valid. + +Validators must have statements, candidates, and persisted validation from all other validators. This is because we need +to store statements from validators who've checked the candidate on the relay chain, so we know who to hold accountable +in case of disputes. Any validator can be selected as the next relay-chain block author, and this is not revealed in +advance for security reasons. As a result, all validators must have a up to date view of all possible parachain +candidates + backing statements that could be placed on-chain in the next block. + +[This blog post](https://polkadot.network/blog/polkadot-v1-0-sharding-and-economic-security) puts it another way: +"Validators who aren't assigned to the parachain still listen for the attestations [statements] because whichever +validator ends up being the author of the relay-chain block needs to bundle up attested parachain blocks for several +parachains and place them into the relay-chain block." + +Backing-group quorum (that is, enough backing group votes) must be reached before the block author will consider the +candidate. Therefore, validators need to consider _all_ seconded candidates within their own group, because that's what +they're assigned to work on. Validators only need to consider _backable_ candidates from other groups. This informs the +design of the statement distribution protocol to have separate phases for in-group and out-group distribution, +respectively called "cluster" and "grid" mode (see below). ### With Async Backing -Asynchronous backing changes the runtime to accept parachain candidates from a -certain allowed range of historic relay-parents. These candidates must be backed -by the group assigned to the parachain as-of their corresponding relay parents. +Asynchronous backing changes the runtime to accept parachain candidates from a certain allowed range of historic +relay-parents. These candidates must be backed by the group assigned to the parachain as-of their corresponding relay +parents. ## Protocol -To address the concern of dealing with large numbers of spam candidates or -statements, the overall design approach is to combine a focused "clustering" -protocol for legitimate fresh candidates with a broad-distribution "grid" -protocol to quickly get backed candidates into the hands of many validators. -Validators do not eagerly send each other heavy `CommittedCandidateReceipt`, -but instead request these lazily through request/response protocols. +To address the concern of dealing with large numbers of spam candidates or statements, the overall design approach is to +combine a focused "clustering" protocol for legitimate fresh candidates with a broad-distribution "grid" protocol to +quickly get backed candidates into the hands of many validators. Validators do not eagerly send each other heavy +`CommittedCandidateReceipt`, but instead request these lazily through request/response protocols. A high-level description of the protocol follows: ### Messages -Nodes can send each other a few kinds of messages: `Statement`, -`BackedCandidateManifest`, `BackedCandidateAcknowledgement`. +Nodes can send each other a few kinds of messages: `Statement`, `BackedCandidateManifest`, +`BackedCandidateAcknowledgement`. -- `Statement` messages contain only a signed compact statement, without full - candidate info. -- `BackedCandidateManifest` messages advertise a description of a backed - candidate and stored statements. -- `BackedCandidateAcknowledgement` messages acknowledge that a backed candidate - is fully known. +- `Statement` messages contain only a signed compact statement, without full candidate info. +- `BackedCandidateManifest` messages advertise a description of a backed candidate and stored statements. +- `BackedCandidateAcknowledgement` messages acknowledge that a backed candidate is fully known. ### Request/response protocol -Nodes can request the full `CommittedCandidateReceipt` and -`PersistedValidationData`, along with statements, over a request/response -protocol. This is the `AttestedCandidateRequest`; the response is -`AttestedCandidateResponse`. +Nodes can request the full `CommittedCandidateReceipt` and `PersistedValidationData`, along with statements, over a +request/response protocol. This is the `AttestedCandidateRequest`; the response is `AttestedCandidateResponse`. ### Importability and the Hypothetical Frontier -The **prospective parachains** subsystem maintains prospective "fragment trees" -which can be used to determine whether a particular parachain candidate could -possibly be included in the future. Candidates which either are within a -fragment tree or _would be_ part of a fragment tree if accepted are said to be -in the "hypothetical frontier". +The **prospective parachains** subsystem maintains prospective "fragment trees" which can be used to determine whether a +particular parachain candidate could possibly be included in the future. Candidates which either are within a fragment +tree or _would be_ part of a fragment tree if accepted are said to be in the "hypothetical frontier". -The **statement-distribution** subsystem keeps track of all candidates, and -updates its knowledge of the hypothetical frontier based on events such as new -relay parents, new confirmed candidates, and newly backed candidates. +The **statement-distribution** subsystem keeps track of all candidates, and updates its knowledge of the hypothetical +frontier based on events such as new relay parents, new confirmed candidates, and newly backed candidates. -We only consider statements as "importable" when the corresponding candidate is -part of the hypothetical frontier, and only send "importable" statements to the -backing subsystem itself. +We only consider statements as "importable" when the corresponding candidate is part of the hypothetical frontier, and +only send "importable" statements to the backing subsystem itself. ### Cluster Mode -- Validator nodes are partitioned into groups (with some exceptions), and - validators within a group at a relay-parent can send each other `Statement` - messages for any candidates within that group and based on that relay-parent. +- Validator nodes are partitioned into groups (with some exceptions), and validators within a group at a relay-parent + can send each other `Statement` messages for any candidates within that group and based on that relay-parent. - This is referred to as the "cluster" mode. - - Right now these are the same as backing groups, though "cluster" - specifically refers to the set of nodes communicating with each other in the - first phase of distribution. + - Right now these are the same as backing groups, though "cluster" specifically refers to the set of nodes + communicating with each other in the first phase of distribution. - `Seconded` statements must be sent before `Valid` statements. -- `Seconded` statements may only be sent to other members of the group when the - candidate is fully known by the local validator. - - "Fully known" means the validator has the full `CommittedCandidateReceipt` - and `PersistedValidationData`, which it receives on request from other - validators or from a collator. - - The reason for this is that sending a statement (which is always a - `CompactStatement` carrying nothing but a hash and signature) to the - cluster, is also a signal that the sending node is available to request the - candidate from. - - This makes the protocol easier to reason about, while also reducing network - messages about candidates that don't really exist. -- Validators in a cluster receiving messages about unknown candidates request - the candidate (and statements) from other cluster members which have it. +- `Seconded` statements may only be sent to other members of the group when the candidate is fully known by the local + validator. + - "Fully known" means the validator has the full `CommittedCandidateReceipt` and `PersistedValidationData`, which it + receives on request from other validators or from a collator. + - The reason for this is that sending a statement (which is always a `CompactStatement` carrying nothing but a hash + and signature) to the cluster, is also a signal that the sending node is available to request the candidate from. + - This makes the protocol easier to reason about, while also reducing network messages about candidates that don't + really exist. +- Validators in a cluster receiving messages about unknown candidates request the candidate (and statements) from other + cluster members which have it. - Spam considerations - - The maximum depth of candidates allowed in asynchronous backing determines - the maximum amount of `Seconded` statements originating from a validator V - which each validator in a cluster may send to others. This bounds the number - of candidates. - - There is a small number of validators in each group, which further limits - the amount of candidates. -- We accept candidates which don't fit in the fragment trees of any relay - parents. - - "Accept" means "attempt to request and store in memory until useful or - expired". - - We listen to prospective parachains subsystem to learn of new additions to - the fragment trees. + - The maximum depth of candidates allowed in asynchronous backing determines the maximum amount of `Seconded` + statements originating from a validator V which each validator in a cluster may send to others. This bounds the + number of candidates. + - There is a small number of validators in each group, which further limits the amount of candidates. +- We accept candidates which don't fit in the fragment trees of any relay parents. + - "Accept" means "attempt to request and store in memory until useful or expired". + - We listen to prospective parachains subsystem to learn of new additions to the fragment trees. - Use this to attempt to import the candidate later. ### Grid Mode -- Every consensus session provides randomness and a fixed validator set, which - is used to build a redundant grid topology. - - It's redundant in the sense that there are 2 paths from every node to every - other node. See "Grid Topology" section for more details. -- This grid topology is used to create a sending path from each validator group - to every validator. -- When a node observes a candidate as backed, it sends a - `BackedCandidateManifest` to their "receiving" nodes. +- Every consensus session provides randomness and a fixed validator set, which is used to build a redundant grid + topology. + - It's redundant in the sense that there are 2 paths from every node to every other node. See "Grid Topology" section + for more details. +- This grid topology is used to create a sending path from each validator group to every validator. +- When a node observes a candidate as backed, it sends a `BackedCandidateManifest` to their "receiving" nodes. - If receiving nodes don't yet know the candidate, they request it. -- Once they know the candidate, they respond with a - `BackedCandidateAcknowledgement`. -- Once two nodes perform a manifest/acknowledgement exchange, they can send - `Statement` messages directly to each other for any new statements they might - need. - - This limits the amount of statements we'd have to deal with w.r.t. - candidates that don't really exist. See "Manifest Exchange" section. -- There are limitations on the number of candidates that can be advertised by - each peer, similar to those in the cluster. Validators do not request - candidates which exceed these limitations. -- Validators request candidates as soon as they are advertised, but do not - import the statements until the candidate is part of the hypothetical - frontier, and do not re-advertise or acknowledge until the candidate is - considered both backable and part of the hypothetical frontier. -- Note that requesting is not an implicit acknowledgement, and an explicit - acknowledgement must be sent upon receipt. +- Once they know the candidate, they respond with a `BackedCandidateAcknowledgement`. +- Once two nodes perform a manifest/acknowledgement exchange, they can send `Statement` messages directly to each other + for any new statements they might need. + - This limits the amount of statements we'd have to deal with w.r.t. candidates that don't really exist. See "Manifest + Exchange" section. +- There are limitations on the number of candidates that can be advertised by each peer, similar to those in the + cluster. Validators do not request candidates which exceed these limitations. +- Validators request candidates as soon as they are advertised, but do not import the statements until the candidate is + part of the hypothetical frontier, and do not re-advertise or acknowledge until the candidate is considered both + backable and part of the hypothetical frontier. +- Note that requesting is not an implicit acknowledgement, and an explicit acknowledgement must be sent upon receipt. ## Messages @@ -161,27 +130,23 @@ backing subsystem itself. - `ActiveLeaves` - Notification of a change in the set of active leaves. - `StatementDistributionMessage::Share` - - Notification of a locally-originating statement. That is, this statement - comes from our node and should be distributed to other nodes. - - Sent by the Backing Subsystem after it successfully imports a - locally-originating statement. + - Notification of a locally-originating statement. That is, this statement comes from our node and should be + distributed to other nodes. + - Sent by the Backing Subsystem after it successfully imports a locally-originating statement. - `StatementDistributionMessage::Backed` - - Notification of a candidate being backed (received enough validity votes - from the backing group). - - Sent by the Backing Subsystem after it successfully imports a statement for - the first time and after sending ~Share~. + - Notification of a candidate being backed (received enough validity votes from the backing group). + - Sent by the Backing Subsystem after it successfully imports a statement for the first time and after sending + ~Share~. - `StatementDistributionMessage::NetworkBridgeUpdate` - See next section. #### Network bridge events - v1 compatibility - - Messages for the v1 protocol are routed to the legacy statement - distribution. + - Messages for the v1 protocol are routed to the legacy statement distribution. - `Statement` - Notification of a signed statement. - - Sent by a peer's Statement Distribution subsystem when circulating - statements. + - Sent by a peer's Statement Distribution subsystem when circulating statements. - `BackedCandidateManifest` - Notification of a backed candidate being known by the sending node. - For the candidate being requested by the receiving node if needed. @@ -196,26 +161,23 @@ backing subsystem itself. ### Outgoing - `NetworkBridgeTxMessage::SendValidationMessages` - - Sends a peer all pending messages / acknowledgements / statements for a - relay parent, either through the cluster or the grid. + - Sends a peer all pending messages / acknowledgements / statements for a relay parent, either through the cluster or + the grid. - `NetworkBridgeTxMessage::SendValidationMessage` - - Circulates a compact statement to all peers who need it, either through the - cluster or the grid. + - Circulates a compact statement to all peers who need it, either through the cluster or the grid. - `NetworkBridgeTxMessage::ReportPeer` - Reports a peer (either good or bad). - `CandidateBackingMessage::Statement` - Note a validator's statement about a particular candidate. - `ProspectiveParachainsMessage::GetHypotheticalFrontier` - - Gets the hypothetical frontier membership of candidates under active leaves' - fragment trees. + - Gets the hypothetical frontier membership of candidates under active leaves' fragment trees. - `NetworkBridgeTxMessage::SendRequests` - Sends requests, initiating the request/response protocol. ## Request/Response -We also have a request/response protocol because validators do not eagerly send -each other heavy `CommittedCandidateReceipt`, but instead need to request these -lazily. +We also have a request/response protocol because validators do not eagerly send each other heavy +`CommittedCandidateReceipt`, but instead need to request these lazily. ### Protocol @@ -225,16 +187,13 @@ lazily. - Done as needed, when handling incoming manifests/statements. - `RequestManager::dispatch_requests` sends any queued-up requests. - Calls `RequestManager::next_request` to completion. - - Creates the `OutgoingRequest`, saves the receiver in - `RequestManager::pending_responses`. - - Does nothing if we have more responses pending than the limit of parallel - requests. + - Creates the `OutgoingRequest`, saves the receiver in `RequestManager::pending_responses`. + - Does nothing if we have more responses pending than the limit of parallel requests. 2. Peer - Requests come in on a peer on the `IncomingRequestReceiver`. - - Runs in a background responder task which feeds requests to `answer_request` - through `MuxedMessage`. + - Runs in a background responder task which feeds requests to `answer_request` through `MuxedMessage`. - This responder task has a limit on the number of parallel requests. - `answer_request` on the peer takes the request and sends a response. - Does this using the response sender on the request. @@ -243,8 +202,7 @@ lazily. - `receive_response` on the original validator yields a response. - Response was sent on the request's response sender. - - Uses `RequestManager::await_incoming` to await on pending responses in an - unordered fashion. + - Uses `RequestManager::await_incoming` to await on pending responses in an unordered fashion. - Runs on the `MuxedMessage` receiver. - `handle_response` handles the response. @@ -265,25 +223,23 @@ lazily. ## Manifests -A manifest is a message about a known backed candidate, along with a description -of the statements backing it. It can be one of two kinds: +A manifest is a message about a known backed candidate, along with a description of the statements backing it. It can be +one of two kinds: -- `Full`: Contains information about the candidate and should be sent to peers - who may not have the candidate yet. This is also called an `Announcement`. -- `Acknowledgement`: Omits information implicit in the candidate, and should be - sent to peers which are guaranteed to have the candidate already. +- `Full`: Contains information about the candidate and should be sent to peers who may not have the candidate yet. This + is also called an `Announcement`. +- `Acknowledgement`: Omits information implicit in the candidate, and should be sent to peers which are guaranteed to + have the candidate already. ### Manifest Exchange -Manifest exchange is when a receiving node received a `Full` manifest and -replied with an `Acknowledgement`. It indicates that both nodes know the -candidate as valid and backed. This allows the nodes to send `Statement` -messages directly to each other for any new statements. +Manifest exchange is when a receiving node received a `Full` manifest and replied with an `Acknowledgement`. It +indicates that both nodes know the candidate as valid and backed. This allows the nodes to send `Statement` messages +directly to each other for any new statements. -Why? This limits the amount of statements we'd have to deal with w.r.t. -candidates that don't really exist. Limiting out-of-group statement distribution -between peers to only candidates that both peers agree are backed and exist -ensures we only have to store statements about real candidates. +Why? This limits the amount of statements we'd have to deal with w.r.t. candidates that don't really exist. Limiting +out-of-group statement distribution between peers to only candidates that both peers agree are backed and exist ensures +we only have to store statements about real candidates. In practice, manifest exchange means that one of three things have happened: @@ -291,36 +247,31 @@ In practice, manifest exchange means that one of three things have happened: - We announced, they acknowledged. - We announced, they announced. -Concerning the last case, note that it is possible for two nodes to have each -other in their sending set. Consider: +Concerning the last case, note that it is possible for two nodes to have each other in their sending set. Consider: ``` 1 2 3 4 ``` -If validators 2 and 4 are in group B, then there is a path `2->1->3` and -`4->3->1`. Therefore, 1 and 3 might send each other manifests for the same -candidate at the same time, without having seen the other's yet. This also -counts as a manifest exchange, but is only allowed to occur in this way. +If validators 2 and 4 are in group B, then there is a path `2->1->3` and `4->3->1`. Therefore, 1 and 3 might send each +other manifests for the same candidate at the same time, without having seen the other's yet. This also counts as a +manifest exchange, but is only allowed to occur in this way. -After the exchange is complete, we update pending statements. Pending statements -are those we know locally that the remote node does not. +After the exchange is complete, we update pending statements. Pending statements are those we know locally that the +remote node does not. #### Alternative Paths Through The Topology -Nodes should send a `BackedCandidateAcknowledgement(CandidateHash, -StatementFilter)` notification to any peer which has sent a manifest, and the -candidate has been acquired by other means. This keeps alternative paths through -the topology open, which allows nodes to receive additional statements that come -later, but not after the candidate has been posted on-chain. +Nodes should send a `BackedCandidateAcknowledgement(CandidateHash, StatementFilter)` notification to any peer which has +sent a manifest, and the candidate has been acquired by other means. This keeps alternative paths through the topology +open, which allows nodes to receive additional statements that come later, but not after the candidate has been posted +on-chain. -This is mostly about the limitation that the runtime has no way for block -authors to post statements that come after the parablock is posted on-chain and -ensure those validators still get rewarded. Technically, we only need enough -statements to back the candidate and the manifest + request will provide that. -But more statements might come shortly afterwards, and we want those to end up -on-chain as well to ensure all validators in the group are rewarded. +This is mostly about the limitation that the runtime has no way for block authors to post statements that come after the +parablock is posted on-chain and ensure those validators still get rewarded. Technically, we only need enough statements +to back the candidate and the manifest + request will provide that. But more statements might come shortly afterwards, +and we want those to end up on-chain as well to ensure all validators in the group are rewarded. For clarity, here is the full timeline: @@ -333,52 +284,42 @@ For clarity, here is the full timeline: ## Cluster Module -The cluster module provides direct distribution of unbacked candidates within a -group. By utilizing this initial phase of propagating only within -clusters/groups, we bound the number of `Seconded` messages per validator per -relay-parent, helping us prevent spam. Validators can try to circumvent this, -but they would only consume a few KB of memory and it is trivially slashable on -chain. +The cluster module provides direct distribution of unbacked candidates within a group. By utilizing this initial phase +of propagating only within clusters/groups, we bound the number of `Seconded` messages per validator per relay-parent, +helping us prevent spam. Validators can try to circumvent this, but they would only consume a few KB of memory and it is +trivially slashable on chain. -The cluster module determines whether to accept/reject messages from other -validators in the same group. It keeps track of what we have sent to other -validators in the group, and pending statements. For the full protocol, see -"Protocol". +The cluster module determines whether to accept/reject messages from other validators in the same group. It keeps track +of what we have sent to other validators in the group, and pending statements. For the full protocol, see "Protocol". ## Grid Module -The grid module provides distribution of backed candidates and late statements -outside the backing group. For the full protocol, see the "Protocol" section. +The grid module provides distribution of backed candidates and late statements outside the backing group. For the full +protocol, see the "Protocol" section. ### Grid Topology -For distributing outside our cluster (aka backing group) we use a 2D grid -topology. This limits the amount of peers we send messages to, and handles -view updates. +For distributing outside our cluster (aka backing group) we use a 2D grid topology. This limits the amount of peers we +send messages to, and handles view updates. The basic operation of the grid topology is that: -- A validator producing a message sends it to its row-neighbors and its - column-neighbors. -- A validator receiving a message originating from one of its row-neighbors - sends it to its column-neighbors. -- A validator receiving a message originating from one of its column-neighbors - sends it to its row-neighbors. +- A validator producing a message sends it to its row-neighbors and its column-neighbors. +- A validator receiving a message originating from one of its row-neighbors sends it to its column-neighbors. +- A validator receiving a message originating from one of its column-neighbors sends it to its row-neighbors. -This grid approach defines 2 unique paths for every validator to reach every -other validator in at most 2 hops, providing redundancy. +This grid approach defines 2 unique paths for every validator to reach every other validator in at most 2 hops, +providing redundancy. Propagation follows these rules: -- Each node has a receiving set and a sending set. These are different for each - group. That is, if a node receives a candidate from group A, it checks if it - is allowed to receive from that node for candidates from group A. +- Each node has a receiving set and a sending set. These are different for each group. That is, if a node receives a + candidate from group A, it checks if it is allowed to receive from that node for candidates from group A. - For groups that we are in, receive from nobody and send to our X/Y peers. - For groups that we are not part of: - - We receive from any validator in the group we share a slice with and send to - the corresponding X/Y slice in the other dimension. - - For any validators we don't share a slice with, we receive from the nodes - which share a slice with them. + - We receive from any validator in the group we share a slice with and send to the corresponding X/Y slice in the + other dimension. + - For any validators we don't share a slice with, we receive from the nodes which share a slice with them. ### Example @@ -391,81 +332,63 @@ For size 11, the matrix would be: 9 10 ``` -e.g. for index 10, the neighbors would be 1, 4, 7, 9 -- these are the nodes we -could directly communicate with (e.g. either send to or receive from). - -Now, which of these neighbors can 10 receive from? Recall that the -sending/receiving sets for 10 would be different for different groups. Here are -some hypothetical scenarios: - -- **Scenario 1:** 9 belongs to group A but not 10. Here, 10 can directly receive - candidates from group A from 9. 10 would propagate them to the nodes in {1, 4, - 7} that are not in A. -- **Scenario 2:** 6 is in group A instead of 9, and 7 is not in group A. 10 can - receive group A messages from 7 or 9. 10 will try to relay these messages, but - 7 and 9 together should have already propagated the message to all x/y - peers of 10. If so, then 10 will just receive acknowledgements in reply rather - than requests. -- **Scenario 3:** 10 itself is in group A. 10 would not receive candidates from - this group from any other nodes through the grid. It would itself send such - candidates to all its neighbors that are not in A. +e.g. for index 10, the neighbors would be 1, 4, 7, 9 -- these are the nodes we could directly communicate with (e.g. +either send to or receive from). + +Now, which of these neighbors can 10 receive from? Recall that the sending/receiving sets for 10 would be different for +different groups. Here are some hypothetical scenarios: + +- **Scenario 1:** 9 belongs to group A but not 10. Here, 10 can directly receive candidates from group A from 9. 10 + would propagate them to the nodes in {1, 4, 7} that are not in A. +- **Scenario 2:** 6 is in group A instead of 9, and 7 is not in group A. 10 can receive group A messages from 7 or 9. 10 + will try to relay these messages, but 7 and 9 together should have already propagated the message to all x/y peers of + 10. If so, then 10 will just receive acknowledgements in reply rather than requests. +- **Scenario 3:** 10 itself is in group A. 10 would not receive candidates from this group from any other nodes through + the grid. It would itself send such candidates to all its neighbors that are not in A. ### Seconding Limit -The seconding limit is a per-validator limit. Before asynchronous backing, we -had a rule that every validator was only allowed to second one candidate per -relay parent. With asynchronous backing, we have a 'maximum depth' which makes -it possible to second multiple candidates per relay parent. The seconding limit -is set to `max depth + 1` to set an upper bound on candidates entering the -system. +The seconding limit is a per-validator limit. Before asynchronous backing, we had a rule that every validator was only +allowed to second one candidate per relay parent. With asynchronous backing, we have a 'maximum depth' which makes it +possible to second multiple candidates per relay parent. The seconding limit is set to `max depth + 1` to set an upper +bound on candidates entering the system. ## Candidates Module -The candidates module provides a tracker for all known candidates in the view, -whether they are confirmed or not, and how peers have advertised the candidates. -What is a confirmed candidate? It is a candidate for which we have the full -receipt and the persisted validation data. This module gets confirmed candidates -from two sources: +The candidates module provides a tracker for all known candidates in the view, whether they are confirmed or not, and +how peers have advertised the candidates. What is a confirmed candidate? It is a candidate for which we have the full +receipt and the persisted validation data. This module gets confirmed candidates from two sources: -- It can be that a validator fetched a collation directly from the collator and - validated it. -- The first time a validator gets an announcement for an unknown candidate, it - will send a request for the candidate. Upon receiving a response and - validating it (see `UnhandledResponse::validate_response`), it will mark the - candidate as confirmed. +- It can be that a validator fetched a collation directly from the collator and validated it. +- The first time a validator gets an announcement for an unknown candidate, it will send a request for the candidate. + Upon receiving a response and validating it (see `UnhandledResponse::validate_response`), it will mark the candidate + as confirmed. ## Requests Module -The requests module provides a manager for pending requests for candidate data, -as well as pending responses. See "Request/Response Protocol" for a high-level -description of the flow. See module-docs for full details. +The requests module provides a manager for pending requests for candidate data, as well as pending responses. See +"Request/Response Protocol" for a high-level description of the flow. See module-docs for full details. ## Glossary -- **Acknowledgement:** A partial manifest sent to a validator that already has the - candidate to inform them that the sending node also knows the candidate. - Concludes a manifest exchange. -- **Announcement:** A full manifest indicating that a backed candidate is known by - the sending node. Initiates a manifest exchange. +- **Acknowledgement:** A partial manifest sent to a validator that already has the candidate to inform them that the + sending node also knows the candidate. Concludes a manifest exchange. +- **Announcement:** A full manifest indicating that a backed candidate is known by the sending node. Initiates a + manifest exchange. - **Attestation:** See "Statement". - **Backable vs. Backed:** - - Note that we sometimes use "backed" to refer to candidates that are - "backable", but not yet backed on chain. - - **Backed** should technically mean that the parablock candidate and its - backing statements have been added to a relay chain block. - - **Backable** is when the necessary backing statements have been acquired but - those statements and the parablock candidate haven't been backed in a relay - chain block yet. -- **Fragment tree:** A parachain fragment not referenced by the relay-chain. - It is a tree of prospective parachain blocks. -- **Manifest:** A message about a known backed candidate, along with a - description of the statements backing it. There are two kinds of manifest, - `Acknowledgement` and `Announcement`. See "Manifests" section. + - Note that we sometimes use "backed" to refer to candidates that are "backable", but not yet backed on chain. + - **Backed** should technically mean that the parablock candidate and its backing statements have been added to a + relay chain block. + - **Backable** is when the necessary backing statements have been acquired but those statements and the parablock + candidate haven't been backed in a relay chain block yet. +- **Fragment tree:** A parachain fragment not referenced by the relay-chain. It is a tree of prospective parachain + blocks. +- **Manifest:** A message about a known backed candidate, along with a description of the statements backing it. There + are two kinds of manifest, `Acknowledgement` and `Announcement`. See "Manifests" section. - **Peer:** Another validator that a validator is connected to. -- **Request/response:** A protocol used to lazily request and receive heavy - candidate data when needed. -- **Reputation:** Tracks reputation of peers. Applies annoyance cost and good - behavior benefits. +- **Request/response:** A protocol used to lazily request and receive heavy candidate data when needed. +- **Reputation:** Tracks reputation of peers. Applies annoyance cost and good behavior benefits. - **Statement:** Signed statements that can be made about parachain candidates. - **Seconded:** Proposal of a parachain candidate. Implicit validity vote. - **Valid:** States that a parachain candidate is valid. @@ -474,6 +397,5 @@ description of the flow. See module-docs for full details. - **Explicit view** / **immediate view** - The view a peer has of the relay chain heads and highest finalized block. - **Implicit view** - - Derived from the immediate view. Composed of active leaves and minimum - relay-parents allowed for candidates of various parachains at those - leaves. + - Derived from the immediate view. Composed of active leaves and minimum relay-parents allowed for candidates of + various parachains at those leaves. diff --git a/polkadot/roadmap/implementers-guide/src/node/collators/README.md b/polkadot/roadmap/implementers-guide/src/node/collators/README.md index 3642e415efa..09edd0c119f 100644 --- a/polkadot/roadmap/implementers-guide/src/node/collators/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/collators/README.md @@ -1,6 +1,8 @@ # Collators -Collators are special nodes which bridge a parachain to the relay chain. They are simultaneously full nodes of the parachain, and at least light clients of the relay chain. Their overall contribution to the system is the generation of Proofs of Validity for parachain candidates. +Collators are special nodes which bridge a parachain to the relay chain. They are simultaneously full nodes of the +parachain, and at least light clients of the relay chain. Their overall contribution to the system is the generation of +Proofs of Validity for parachain candidates. -The **Collation Generation** subsystem triggers collators to produce collations -and then forwards them to **Collator Protocol** to circulate to validators. +The **Collation Generation** subsystem triggers collators to produce collations and then forwards them to **Collator +Protocol** to circulate to validators. diff --git a/polkadot/roadmap/implementers-guide/src/node/collators/collation-generation.md b/polkadot/roadmap/implementers-guide/src/node/collators/collation-generation.md index 9053ea40f89..05148357f75 100644 --- a/polkadot/roadmap/implementers-guide/src/node/collators/collation-generation.md +++ b/polkadot/roadmap/implementers-guide/src/node/collators/collation-generation.md @@ -1,17 +1,18 @@ # Collation Generation -The collation generation subsystem is executed on collator nodes and produces candidates to be distributed to validators. If configured to produce collations for a para, it produces collations and then feeds them to the [Collator Protocol][CP] subsystem, which handles the networking. +The collation generation subsystem is executed on collator nodes and produces candidates to be distributed to +validators. If configured to produce collations for a para, it produces collations and then feeds them to the [Collator +Protocol][CP] subsystem, which handles the networking. ## Protocol Collation generation for Parachains currently works in the following way: -1. A new relay chain block is imported. -2. The collation generation subsystem checks if the core associated to - the parachain is free and if yes, continues. -3. Collation generation calls our collator callback, if present, to generate a PoV. If none exists, do nothing. -4. Authoring logic determines if the current node should build a PoV. -5. Build new PoV and give it back to collation generation. +1. A new relay chain block is imported. +2. The collation generation subsystem checks if the core associated to the parachain is free and if yes, continues. +3. Collation generation calls our collator callback, if present, to generate a PoV. If none exists, do nothing. +4. Authoring logic determines if the current node should build a PoV. +5. Build new PoV and give it back to collation generation. ## Messages @@ -22,8 +23,7 @@ Collation generation for Parachains currently works in the following way: - Triggers collation generation procedure outlined in "Protocol" section. - `CollationGenerationMessage::Initialize` - Initializes the subsystem. Carries a config. - - No more than one initialization message should ever be sent to the collation - generation subsystem. + - No more than one initialization message should ever be sent to the collation generation subsystem. - Sent by a collator to initialize this subsystem. - `CollationGenerationMessage::SubmitCollation` - If the subsystem isn't initialized or the relay-parent is too old to be relevant, ignore the message. @@ -37,7 +37,9 @@ Collation generation for Parachains currently works in the following way: ## Functionality -The process of generating a collation for a parachain is very parachain-specific. As such, the details of how to do so are left beyond the scope of this description. The subsystem should be implemented as an abstract wrapper, which is aware of this configuration: +The process of generating a collation for a parachain is very parachain-specific. As such, the details of how to do so +are left beyond the scope of this description. The subsystem should be implemented as an abstract wrapper, which is +aware of this configuration: ```rust /// The output of a collator. @@ -117,30 +119,24 @@ The configuration should be optional, to allow for the case where the node is no - **Collation (output of a collator)** - - Contains the PoV (proof to verify the state transition of the - parachain) and other data. + - Contains the PoV (proof to verify the state transition of the parachain) and other data. - **Collation result** - - Contains the collation, and an optional result sender for a - collation-seconded signal. + - Contains the collation, and an optional result sender for a collation-seconded signal. - **Collation seconded signal** - - The signal that is returned when a collation was seconded by a - validator. + - The signal that is returned when a collation was seconded by a validator. - **Collation function** - - Called with the relay chain block the parablock will be built on top - of. + - Called with the relay chain block the parablock will be built on top of. - Called with the validation data. - - Provides information about the state of the parachain on the relay - chain. + - Provides information about the state of the parachain on the relay chain. - **Collation generation config** - - Contains collator's authentication key, optional collator function, and - parachain ID. + - Contains collator's authentication key, optional collator function, and parachain ID. [CP]: collator-protocol.md diff --git a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md index 09265a53484..1fed671170c 100644 --- a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md @@ -1,16 +1,25 @@ # Collator Protocol -The Collator Protocol implements the network protocol by which collators and validators communicate. It is used by collators to distribute collations to validators and used by validators to accept collations by collators. +The Collator Protocol implements the network protocol by which collators and validators communicate. It is used by +collators to distribute collations to validators and used by validators to accept collations by collators. -Collator-to-Validator networking is more difficult than Validator-to-Validator networking because the set of possible collators for any given para is unbounded, unlike the validator set. Validator-to-Validator networking protocols can easily be implemented as gossip because the data can be bounded, and validators can authenticate each other by their `PeerId`s for the purposes of instantiating and accepting connections. +Collator-to-Validator networking is more difficult than Validator-to-Validator networking because the set of possible +collators for any given para is unbounded, unlike the validator set. Validator-to-Validator networking protocols can +easily be implemented as gossip because the data can be bounded, and validators can authenticate each other by their +`PeerId`s for the purposes of instantiating and accepting connections. -Since, at least at the level of the para abstraction, the collator-set for any given para is unbounded, validators need to make sure that they are receiving connections from capable and honest collators and that their bandwidth and time are not being wasted by attackers. Communicating across this trust-boundary is the most difficult part of this subsystem. +Since, at least at the level of the para abstraction, the collator-set for any given para is unbounded, validators need +to make sure that they are receiving connections from capable and honest collators and that their bandwidth and time are +not being wasted by attackers. Communicating across this trust-boundary is the most difficult part of this subsystem. -Validation of candidates is a heavy task, and furthermore, the [`PoV`][PoV] itself is a large piece of data. Empirically, `PoV`s are on the order of 10MB. +Validation of candidates is a heavy task, and furthermore, the [`PoV`][PoV] itself is a large piece of data. +Empirically, `PoV`s are on the order of 10MB. > TODO: note the incremental validation function Ximin proposes at https://github.com/paritytech/polkadot/issues/1348 -As this network protocol serves as a bridge between collators and validators, it communicates primarily with one subsystem on behalf of each. As a collator, this will receive messages from the [`CollationGeneration`][CG] subsystem. As a validator, this will communicate only with the [`CandidateBacking`][CB]. +As this network protocol serves as a bridge between collators and validators, it communicates primarily with one +subsystem on behalf of each. As a collator, this will receive messages from the [`CollationGeneration`][CG] subsystem. +As a validator, this will communicate only with the [`CandidateBacking`][CB]. ## Protocol @@ -18,9 +27,9 @@ Input: [`CollatorProtocolMessage`][CPM] Output: -- [`RuntimeApiMessage`][RAM] -- [`NetworkBridgeMessage`][NBM] -- [`CandidateBackingMessage`][CBM] +* [`RuntimeApiMessage`][RAM] +* [`NetworkBridgeMessage`][NBM] +* [`CandidateBackingMessage`][CBM] ## Functionality @@ -28,7 +37,8 @@ This network protocol uses the `Collation` peer-set of the [`NetworkBridge`][NB] It uses the [`CollatorProtocolV1Message`](../../types/network.md#collator-protocol) as its `WireMessage` -Since this protocol functions both for validators and collators, it is easiest to go through the protocol actions for each of them separately. +Since this protocol functions both for validators and collators, it is easiest to go through the protocol actions for +each of them separately. Validators and collators. ```dot process @@ -47,24 +57,44 @@ digraph { ### Collators -It is assumed that collators are only collating on a single parachain. Collations are generated by the [Collation Generation][CG] subsystem. We will keep up to one local collation per relay-parent, based on `DistributeCollation` messages. If the para is not scheduled on any core, at the relay-parent, or the relay-parent isn't in the active-leaves set, we ignore the message as it must be invalid in that case - although this indicates a logic error elsewhere in the node. +It is assumed that collators are only collating on a single parachain. Collations are generated by the [Collation +Generation][CG] subsystem. We will keep up to one local collation per relay-parent, based on `DistributeCollation` +messages. If the para is not scheduled on any core, at the relay-parent, or the relay-parent isn't in the active-leaves +set, we ignore the message as it must be invalid in that case - although this indicates a logic error elsewhere in the +node. -We keep track of the Para ID we are collating on as a collator. This starts as `None`, and is updated with each `CollateOn` message received. If the `ParaId` of a collation requested to be distributed does not match the one we expect, we ignore the message. +We keep track of the Para ID we are collating on as a collator. This starts as `None`, and is updated with each +`CollateOn` message received. If the `ParaId` of a collation requested to be distributed does not match the one we +expect, we ignore the message. As with most other subsystems, we track the active leaves set by following `ActiveLeavesUpdate` signals. -For the purposes of actually distributing a collation, we need to be connected to the validators who are interested in collations on that `ParaId` at this point in time. We assume that there is a discovery API for connecting to a set of validators. +For the purposes of actually distributing a collation, we need to be connected to the validators who are interested in +collations on that `ParaId` at this point in time. We assume that there is a discovery API for connecting to a set of +validators. -As seen in the [Scheduler Module][SCH] of the runtime, validator groups are fixed for an entire session and their rotations across cores are predictable. Collators will want to do these things when attempting to distribute collations at a given relay-parent: +As seen in the [Scheduler Module][SCH] of the runtime, validator groups are fixed for an entire session and their +rotations across cores are predictable. Collators will want to do these things when attempting to distribute collations +at a given relay-parent: * Determine which core the para collated-on is assigned to. * Determine the group on that core. - * Issue a discovery request for the validators of the current group with[`NetworkBridgeMessage`][NBM]`::ConnectToValidators`. - -Once connected to the relevant peers for the current group assigned to the core (transitively, the para), advertise the collation to any of them which advertise the relay-parent in their view (as provided by the [Network Bridge][NB]). If any respond with a request for the full collation, provide it. However, we only send one collation at a time per relay parent, other requests need to wait. This is done to reduce the bandwidth requirements of a collator and also increases the chance to fully send the collation to at least one validator. From the point where one validator has received the collation and seconded it, it will also start to share this collation with other validators in its backing group. Upon receiving a view update from any of these peers which includes a relay-parent for which we have a collation that they will find relevant, advertise the collation to them if we haven't already. + * Issue a discovery request for the validators of the current group + with[`NetworkBridgeMessage`][NBM]`::ConnectToValidators`. + +Once connected to the relevant peers for the current group assigned to the core (transitively, the para), advertise the +collation to any of them which advertise the relay-parent in their view (as provided by the [Network Bridge][NB]). If +any respond with a request for the full collation, provide it. However, we only send one collation at a time per relay +parent, other requests need to wait. This is done to reduce the bandwidth requirements of a collator and also increases +the chance to fully send the collation to at least one validator. From the point where one validator has received the +collation and seconded it, it will also start to share this collation with other validators in its backing group. Upon +receiving a view update from any of these peers which includes a relay-parent for which we have a collation that they +will find relevant, advertise the collation to them if we haven't already. ### Validators -On the validator side of the protocol, validators need to accept incoming connections from collators. They should keep some peer slots open for accepting new speculative connections from collators and should disconnect from collators who are not relevant. +On the validator side of the protocol, validators need to accept incoming connections from collators. They should keep +some peer slots open for accepting new speculative connections from collators and should disconnect from collators who +are not relevant. ```dot process digraph G { @@ -98,32 +128,62 @@ digraph G { } ``` -When peers connect to us, they can `Declare` that they represent a collator with given public key and intend to collate on a specific para ID. Once they've declared that, and we checked their signature, they can begin to send advertisements of collations. The peers should not send us any advertisements for collations that are on a relay-parent outside of our view or for a para outside of the one they've declared. +When peers connect to us, they can `Declare` that they represent a collator with given public key and intend to collate +on a specific para ID. Once they've declared that, and we checked their signature, they can begin to send advertisements +of collations. The peers should not send us any advertisements for collations that are on a relay-parent outside of our +view or for a para outside of the one they've declared. -The protocol tracks advertisements received and the source of the advertisement. The advertisement source is the `PeerId` of the peer who sent the message. We accept one advertisement per collator per source per relay-parent. +The protocol tracks advertisements received and the source of the advertisement. The advertisement source is the +`PeerId` of the peer who sent the message. We accept one advertisement per collator per source per relay-parent. -As a validator, we will handle requests from other subsystems to fetch a collation on a specific `ParaId` and relay-parent. These requests are made with the request response protocol `CollationFetchingRequest` request. To do so, we need to first check if we have already gathered a collation on that `ParaId` and relay-parent. If not, we need to select one of the advertisements and issue a request for it. If we've already issued a request, we shouldn't issue another one until the first has returned. +As a validator, we will handle requests from other subsystems to fetch a collation on a specific `ParaId` and +relay-parent. These requests are made with the request response protocol `CollationFetchingRequest` request. To do so, +we need to first check if we have already gathered a collation on that `ParaId` and relay-parent. If not, we need to +select one of the advertisements and issue a request for it. If we've already issued a request, we shouldn't issue +another one until the first has returned. -When acting on an advertisement, we issue a `Requests::CollationFetchingV1`. However, we only request one collation at a time per relay parent. This reduces the bandwidth requirements and as we can second only one candidate per relay parent, the others are probably not required anyway. If the request times out, we need to note the collator as being unreliable and reduce its priority relative to other collators. +When acting on an advertisement, we issue a `Requests::CollationFetchingV1`. However, we only request one collation at a +time per relay parent. This reduces the bandwidth requirements and as we can second only one candidate per relay parent, +the others are probably not required anyway. If the request times out, we need to note the collator as being unreliable +and reduce its priority relative to other collators. -As a validator, once the collation has been fetched some other subsystem will inspect and do deeper validation of the collation. The subsystem will report to this subsystem with a [`CollatorProtocolMessage`][CPM]`::ReportCollator`. In that case, if we are connected directly to the collator, we apply a cost to the `PeerId` associated with the collator and potentially disconnect or blacklist it. If the collation is seconded, we notify the collator and apply a benefit to the `PeerId` associated with the collator. +As a validator, once the collation has been fetched some other subsystem will inspect and do deeper validation of the +collation. The subsystem will report to this subsystem with a [`CollatorProtocolMessage`][CPM]`::ReportCollator`. In +that case, if we are connected directly to the collator, we apply a cost to the `PeerId` associated with the collator +and potentially disconnect or blacklist it. If the collation is seconded, we notify the collator and apply a benefit to +the `PeerId` associated with the collator. ### Interaction with [Candidate Backing][CB] -As collators advertise the availability, a validator will simply second the first valid parablock candidate per relay head by sending a [`CandidateBackingMessage`][CBM]`::Second`. Note that this message contains the relay parent of the advertised collation, the candidate receipt and the [PoV][PoV]. +As collators advertise the availability, a validator will simply second the first valid parablock candidate per relay +head by sending a [`CandidateBackingMessage`][CBM]`::Second`. Note that this message contains the relay parent of the +advertised collation, the candidate receipt and the [PoV][PoV]. -Subsequently, once a valid parablock candidate has been seconded, the [`CandidateBacking`][CB] subsystem will send a [`CollatorProtocolMessage`][CPM]`::Seconded`, which will trigger this subsystem to notify the collator at the `PeerId` that first advertised the parablock on the seconded relay head of their successful seconding. +Subsequently, once a valid parablock candidate has been seconded, the [`CandidateBacking`][CB] subsystem will send a +[`CollatorProtocolMessage`][CPM]`::Seconded`, which will trigger this subsystem to notify the collator at the `PeerId` +that first advertised the parablock on the seconded relay head of their successful seconding. ## Future Work Several approaches have been discussed, but all have some issues: -- The current approach is very straightforward. However, that protocol is vulnerable to a single collator which, as an attack or simply through chance, gets its block candidate to the node more often than its fair share of the time. -- If collators produce blocks via Aura, BABE or in future Sassafras, it may be possible to choose an "Official" collator for the round, but it may be tricky to ensure that the PVF logic is enforced at collator leader election. -- We could use relay-chain BABE randomness to generate some delay `D` on the order of 1 second, +- 1 second. The collator would then second the first valid parablock which arrives after `D`, or in case none has arrived by `2*D`, the last valid parablock which has arrived. This makes it very hard for a collator to game the system to always get its block nominated, but it reduces the maximum throughput of the system by introducing delay into an already tight schedule. -- A variation of that scheme would be to have a fixed acceptance window `D` for parablock candidates and keep track of count `C`: the number of parablock candidates received. At the end of the period `D`, we choose a random number I in the range `[0, C)` and second the block at Index I. Its drawback is the same: it must wait the full `D` period before seconding any of its received candidates, reducing throughput. -- In order to protect against DoS attacks, it may be prudent to run throw out collations from collators that have behaved poorly (whether recently or historically) and subsequently only verify the PoV for the most suitable of collations. +* The current approach is very straightforward. However, that protocol is vulnerable to a single collator which, as an + attack or simply through chance, gets its block candidate to the node more often than its fair share of the time. +* If collators produce blocks via Aura, BABE or in future Sassafras, it may be possible to choose an "Official" collator + for the round, but it may be tricky to ensure that the PVF logic is enforced at collator leader election. +* We could use relay-chain BABE randomness to generate some delay `D` on the order of 1 second, +* 1 second. The + collator would then second the first valid parablock which arrives after `D`, or in case none has arrived by `2*D`, + the last valid parablock which has arrived. This makes it very hard for a collator to game the system to always get + its block nominated, but it reduces the maximum throughput of the system by introducing delay into an already tight + schedule. +* A variation of that scheme would be to have a fixed acceptance window `D` for parablock candidates and keep track of + count `C`: the number of parablock candidates received. At the end of the period `D`, we choose a random number I in + the range `[0, C)` and second the block at Index I. Its drawback is the same: it must wait the full `D` period before + seconding any of its received candidates, reducing throughput. +* In order to protect against DoS attacks, it may be prudent to run throw out collations from collators that have + behaved poorly (whether recently or historically) and subsequently only verify the PoV for the most suitable of + collations. [CB]: ../backing/candidate-backing.md [CBM]: ../../types/overseer-protocol.md#candidate-backing-mesage diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/README.md b/polkadot/roadmap/implementers-guide/src/node/disputes/README.md index a6e126b1534..36f497114a7 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/README.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/README.md @@ -4,12 +4,12 @@ If approval voting finds an invalid candidate, a dispute is raised. The disputes subsystems are concerned with the following: 1. Disputes can be raised -2. Disputes (votes) get propagated to all other validators -3. Votes get recorded as necessary -3. Nodes will participate in disputes in a sensible fashion -4. Finality is stopped while a candidate is being disputed on chain -5. Chains can be reverted in case a dispute concludes invalid -6. Votes are provided to the provisioner for importing on chain, in order for +1. Disputes (votes) get propagated to all other validators +1. Votes get recorded as necessary +1. Nodes will participate in disputes in a sensible fashion +1. Finality is stopped while a candidate is being disputed on chain +1. Chains can be reverted in case a dispute concludes invalid +1. Votes are provided to the provisioner for importing on chain, in order for slashing to work. The dispute-coordinator subsystem interfaces with the provisioner and chain 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 f8bfe6506aa..daba416e263 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md @@ -1,86 +1,64 @@ # Dispute Coordinator -The coordinator is the central subsystem of the node-side components which -participate in disputes. It wraps a database, which is used to track statements -observed by _all_ validators over some window of sessions. Votes older than this +The coordinator is the central subsystem of the node-side components which participate in disputes. It wraps a database, +which is used to track statements observed by _all_ validators over some window of sessions. Votes older than this session window are pruned. In particular the dispute-coordinator is responsible for: -- Ensuring that the node is able to raise a dispute in case an invalid candidate - is found during approval checking. -- Ensuring that backing and approval votes will be recorded on chain. With these - votes on chain we can be certain that appropriate targets for slashing will be - available for concluded disputes. Also, scraping these votes during a dispute +- Ensuring that the node is able to raise a dispute in case an invalid candidate is found during approval checking. +- Ensuring that backing and approval votes will be recorded on chain. With these votes on chain we can be certain that + appropriate targets for slashing will be available for concluded disputes. Also, scraping these votes during a dispute is necessary for critical spam prevention measures. - Ensuring backing votes will never get overridden by explicit votes. -- Coordinating actual participation in a dispute, ensuring that the node - participates in any justified dispute in a way that ensures resolution of - disputes on the network even in the case of many disputes raised (flood/DoS - scenario). -- Ensuring disputes resolve, even for candidates on abandoned forks as much as - reasonably possible, to rule out "free tries" and thus guarantee our gambler's - ruin property. -- Providing an API for chain selection, so we can prevent finalization of any - chain which has included candidates for which a dispute is either ongoing or - concluded invalid and avoid building on chains with an included invalid +- Coordinating actual participation in a dispute, ensuring that the node participates in any justified dispute in a way + that ensures resolution of disputes on the network even in the case of many disputes raised (flood/DoS scenario). +- Ensuring disputes resolve, even for candidates on abandoned forks as much as reasonably possible, to rule out "free + tries" and thus guarantee our gambler's ruin property. +- Providing an API for chain selection, so we can prevent finalization of any chain which has included candidates for + which a dispute is either ongoing or concluded invalid and avoid building on chains with an included invalid candidate. -- Providing an API for retrieving (resolved) disputes, including all votes, both - implicit (approval, backing) and explicit dispute votes. So validators can get - rewarded/slashed accordingly. +- Providing an API for retrieving (resolved) disputes, including all votes, both implicit (approval, backing) and + explicit dispute votes. So validators can get rewarded/slashed accordingly. ## Ensuring That Disputes Can Be Raised -If a candidate turns out invalid in approval checking, the `approval-voting` -subsystem will try to issue a dispute. For this, it will send a message -`DisputeCoordinatorMessage::IssueLocalStatement` to the dispute coordinator, -indicating to cast an explicit invalid vote. It is the responsibility of the -dispute coordinator on reception of such a message to create and sign that -explicit invalid vote and trigger a dispute if none for that candidate is -already ongoing. - -In order to raise a dispute, a node has to be able to provide two opposing votes. -Given that the reason of the backing phase is to have validators with skin in -the game, the opposing valid vote will very likely be a backing vote. It could -also be some already cast approval vote, but the significant point here is: As -long as we have backing votes available, any node will be able to raise a -dispute. - -Therefore a vital responsibility of the dispute coordinator is to make sure -backing votes are available for all candidates that might still get disputed. To -accomplish this task in an efficient way the dispute-coordinator relies on chain -scraping. Whenever a candidate gets backed on chain, we record in chain storage -the backing votes imported in that block. This way, given the chain state for a -given relay chain block, we can retrieve via a provided runtime API the backing -votes imported by that block. The dispute coordinator makes sure to query those -votes for any non finalized blocks: In case of missed blocks, it will do chain -traversal as necessary. +If a candidate turns out invalid in approval checking, the `approval-voting` subsystem will try to issue a dispute. For +this, it will send a message `DisputeCoordinatorMessage::IssueLocalStatement` to the dispute coordinator, indicating to +cast an explicit invalid vote. It is the responsibility of the dispute coordinator on reception of such a message to +create and sign that explicit invalid vote and trigger a dispute if none for that candidate is already ongoing. + +In order to raise a dispute, a node has to be able to provide two opposing votes. Given that the reason of the backing +phase is to have validators with skin in the game, the opposing valid vote will very likely be a backing vote. It could +also be some already cast approval vote, but the significant point here is: As long as we have backing votes available, +any node will be able to raise a dispute. + +Therefore a vital responsibility of the dispute coordinator is to make sure backing votes are available for all +candidates that might still get disputed. To accomplish this task in an efficient way the dispute-coordinator relies on +chain scraping. Whenever a candidate gets backed on chain, we record in chain storage the backing votes imported in that +block. This way, given the chain state for a given relay chain block, we can retrieve via a provided runtime API the +backing votes imported by that block. The dispute coordinator makes sure to query those votes for any non finalized +blocks: In case of missed blocks, it will do chain traversal as necessary. Relying on chain scraping is very efficient for two reasons: -1. Votes are already batched. We import all available backing votes for a - candidate all at once. If instead we imported votes from candidate-backing as - they came along, we would import each vote individually which is - inefficient in the current dispute coordinator implementation (quadratic - complexity). -2. We also import less votes in total, as we avoid importing statements for - candidates that never got successfully backed on any chain. - -It also is secure, because disputes are only ever raised in the approval voting -phase. A node only starts the approval process after it has seen a candidate -included on some chain, for that to happen it must have been backed previously. -Therefore backing votes are available at that point in time. Signals are -processed first, so even if a block is skipped and we only start importing -backing votes on the including block, we will have seen the backing votes by the -time we process messages from approval voting. - -In summary, for making it possible for a dispute to be raised, recording of -backing votes from chain is sufficient and efficient. In particular there is no -need to preemptively import approval votes, which has shown to be a very +1. Votes are already batched. We import all available backing votes for a candidate all at once. If instead we imported + votes from candidate-backing as they came along, we would import each vote individually which is inefficient in the + current dispute coordinator implementation (quadratic complexity). +2. We also import less votes in total, as we avoid importing statements for candidates that never got successfully + backed on any chain. + +It also is secure, because disputes are only ever raised in the approval voting phase. A node only starts the approval +process after it has seen a candidate included on some chain, for that to happen it must have been backed previously. +Therefore backing votes are available at that point in time. Signals are processed first, so even if a block is skipped +and we only start importing backing votes on the including block, we will have seen the backing votes by the time we +process messages from approval voting. + +In summary, for making it possible for a dispute to be raised, recording of backing votes from chain is sufficient and +efficient. In particular there is no need to preemptively import approval votes, which has shown to be a very inefficient process. (Quadratic complexity adds up, with 35 votes in total per candidate) -Approval votes are very relevant nonetheless as we are going to see in the next -section. +Approval votes are very relevant nonetheless as we are going to see in the next section. ## Ensuring approval votes will be recorded @@ -88,521 +66,402 @@ section. Only votes recorded by the dispute coordinator will be considered for slashing. -While there is no need to record approval votes in the dispute coordinator -preemptively, we make some effort to have any in approval-voting received -approval votes recorded when a dispute actually happens: - -This is not required for concluding the dispute, as nodes send their own vote -anyway (either explicit valid or their existing approval-vote). What nodes can -do though, is participating in approval-voting, casting a vote, but later when a -dispute is raised reconsider their vote and send an explicit invalid vote. If -they managed to only have that one recorded, then they could avoid a slash. - -This is not a problem for our basic security assumptions: The backers are the -ones to be supposed to have skin in the game, so we are not too woried about -colluding approval voters getting away slash free as the gambler's ruin property -is 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.) - - -So we do want to fetch approval votes from approval-voting. Importing votes is -most efficient when batched. At the same time approval voting and disputes are -running concurrently so approval votes are expected to trickle in still, when a +While there is no need to record approval votes in the dispute coordinator preemptively, we make some effort to have any +in approval-voting received approval votes recorded when a dispute actually happens: + +This is not required for concluding the dispute, as nodes send their own vote anyway (either explicit valid or their +existing approval-vote). What nodes can do though, is participating in approval-voting, casting a vote, but later when a +dispute is raised reconsider their vote and send an explicit invalid vote. If they managed to only have that one +recorded, then they could avoid a slash. + +This is not a problem for our basic security assumptions: The backers are the ones to be supposed to have skin in the +game, so we are not too woried about colluding approval voters getting away slash free as the gambler's ruin property is +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.) + + +So we do want to fetch approval votes from approval-voting. Importing votes is most efficient when batched. At the same +time approval voting and disputes are running concurrently so approval votes are expected to trickle in still, when a dispute is already ongoing. Hence, we have the following requirements for importing approval votes: -1. Only import them when there is a dispute, because otherwise we are - wasting lots of resources _always_ for the exceptional case of a dispute. +1. Only import them when there is a dispute, because otherwise we are wasting lots of resources _always_ for the + exceptional case of a dispute. 2. Import votes batched when possible, to avoid quadratic import complexity. -3. Take into account that approval voting is still ongoing, while a dispute is - already running. - -With a design where approval voting sends votes to the dispute-coordinator by -itself, we would need to make approval voting aware of ongoing disputes and once -it is aware it could start sending all already existing votes batched and -trickling in votes as they come. The problem with this is, that it adds some -unnecessary complexity to approval-voting and also we might still import most of -the votes unbatched one-by-one, depending on what point in time the dispute was +3. Take into account that approval voting is still ongoing, while a dispute is already running. + +With a design where approval voting sends votes to the dispute-coordinator by itself, we would need to make approval +voting aware of ongoing disputes and once it is aware it could start sending all already existing votes batched and +trickling in votes as they come. The problem with this is, that it adds some unnecessary complexity to approval-voting +and also we might still import most of the votes unbatched one-by-one, depending on what point in time the dispute was raised. -Instead of the dispute coordinator informing approval-voting of an ongoing -dispute for it to begin forwarding votes to the dispute coordinator, it makes -more sense for the dispute-coordinator to just ask approval-voting for votes of -candidates in dispute. This way, the dispute coordinator can also pick the best -time for maximizing the number of votes in the batch. - -Now the question remains, when should the dispute coordinator ask -approval-voting for votes? - -In fact for slashing it is only relevant to have them once the dispute -concluded, so we can query approval voting the moment the dispute concludes! -Two concerns that come to mind, are easily addressed: - -1. Timing: We would like to rely as little as possible on implementation details - of approval voting. In particular, if the dispute is ongoing for a long time, - do we have any guarantees that approval votes are kept around long enough by - approval voting? Will approval votes still be present by the time the - dispute concludes in all cases? The answer is nuanced, but in general we - cannot rely on it. The problem is first, that finalization and - approval-voting is an off-chain process so there is no global consensus: As - soon as at least f+1 honest (f=n/3, where n is the number of - validators/nodes) nodes have seen the dispute conclude, finalization will - take place and approval votes will be cleared. This would still be fine, if - we had some guarantees that those honest nodes will be able to include those - votes in a block. This guarantee does not exist unfortunately, we will - discuss the problem and solutions in more detail [below][#Ensuring Chain Import]. - - The second problem is that approval-voting will abandon votes as soon as a - chain can no longer be finalized (some other/better fork already has been). - This second problem can somehow be mitigated by also importing votes as soon - as a dispute is detected, but not fully resolved. It is still inherently - racy. The good thing is, this should be good 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. - -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 deleting votes we will import approval votes twice during a -dispute: Once when it is raised, to make as sure as possible to see approval -votes also for abandoned forks and second when the dispute concludes, to -maximize the amount of potentially malicious approval votes to be recorded. The -raciness obviously is not fully resolved by this, but this is fine as argued -above. +Instead of the dispute coordinator informing approval-voting of an ongoing dispute for it to begin forwarding votes to +the dispute coordinator, it makes more sense for the dispute-coordinator to just ask approval-voting for votes of +candidates in dispute. This way, the dispute coordinator can also pick the best time for maximizing the number of votes +in the batch. + +Now the question remains, when should the dispute coordinator ask approval-voting for votes? + +In fact for slashing it is only relevant to have them once the dispute concluded, so we can query approval voting the +moment the dispute concludes! Two concerns that come to mind, are easily addressed: + +1. Timing: We would like to rely as little as possible on implementation details of approval voting. In particular, if + the dispute is ongoing for a long time, do we have any guarantees that approval votes are kept around long enough by + approval voting? Will approval votes still be present by the time the dispute concludes in all cases? The answer is + nuanced, but in general we cannot rely on it. The problem is first, that finalization and approval-voting is an + off-chain process so there is no global consensus: As soon as at least f+1 honest (f=n/3, where n is the number of + validators/nodes) nodes have seen the dispute conclude, finalization will take place and approval votes will be + cleared. This would still be fine, if we had some guarantees that those honest nodes will be able to include those + votes in a block. This guarantee does not exist unfortunately, we will discuss the problem and solutions in more + detail [below][#Ensuring Chain Import]. + + The second problem is that approval-voting will abandon votes as soon as a chain can no longer be finalized (some + other/better fork already has been). This second problem can somehow be mitigated by also importing votes as soon as + a dispute is detected, but not fully resolved. It is still inherently racy. The good thing is, this should be good + 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. + +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 +deleting votes we will import approval votes twice during a dispute: Once when it is raised, to make as sure as possible +to see approval votes also for abandoned forks and second when the dispute concludes, to maximize the amount of +potentially malicious approval votes to be recorded. The raciness obviously is not fully resolved by this, but this is +fine as argued above. Ensuring vote import on chain is covered in the next section. -What we don't care about is that honest approval-voters will likely validate -twice, once in approval voting and once via dispute-participation. Avoiding that -does not really seem worthwhile though, as disputes are for one exceptional, so -a little wasted effort won't affect everyday performance - second, even with -eager importing of approval votes, those doubled work is still present as -disputes and approvals are racing. Every time participation is faster than -approval, a node would do double work. +What we don't care about is that honest approval-voters will likely validate twice, once in approval voting and once via +dispute-participation. Avoiding that does not really seem worthwhile though, as disputes are for one exceptional, so a +little wasted effort won't affect everyday performance - second, even with eager importing of approval votes, those +doubled work is still present as disputes and approvals are racing. Every time participation is faster than approval, a +node would do double work. ### Ensuring Chain Import -While in the previous section we discussed means for nodes to ensure relevant -votes are recorded so lazy approval checkers get slashed properly, it is crucial -to also discuss the actual chain import. Only if we guarantee that recorded votes -will get imported on chain (on all potential chains really) we will succeed -in executing slashes. Particularly we need to make sure backing votes end up on -chain consistently. - -Dispute distribution will make sure all explicit dispute votes get distributed -among nodes which includes current block producers (current authority set) which -is an important property: If the dispute carries on across an era change, we -need to ensure that the new validator set will learn about any disputes and -their votes, so they can put that information on chain. Dispute-distribution -luckily has this property and always sends votes to the current authority set. -The issue is, for dispute-distribution, nodes send only their own explicit (or -in some cases their approval vote) in addition to some opposing vote. This -guarantees that at least some backing or approval vote will be present at the -block producer, but we don't have a 100% guarantee to have votes for all -backers, even less for approval checkers. - -Reason for backing votes: While backing votes will be present on at least some -chain, that does not mean that any such chain is still considered for block -production in the current set - they might only exist on an already abandoned -fork. This means a block producer that just joined the set, might not have seen -any of them. - -For approvals it is even more tricky and less necessary: Approval voting together -with finalization is a completely off-chain process therefore those protocols -don't care about block production at all. Approval votes only have a guarantee of -being propagated between the nodes that are responsible for finalizing the -concerned blocks. This implies that on an era change the current authority set, -will not necessarily get informed about any approval votes for the previous era. -Hence even if all validators of the previous era successfully recorded all approval -votes in the dispute coordinator, they won't get a chance to put them on chain, -hence they won't be considered for slashing. - -It is important to note, that the essential properties of the system still hold: -Dispute-distribution will distribute at _least one_ "valid" vote to the current -authority set, hence at least one node will get slashed in case of outcome -"invalid". Also in reality the validator set is rarely exchanged 100%, therefore -in practice some validators in the current authority set will overlap with the -ones in the previous set and will be able to record votes on chain. - -Still, for maximum accountability we need to make sure a previous authority set -can communicate votes to the next one, regardless of any chain: This is yet to -be implemented see section "Resiliency" in dispute-distribution and +While in the previous section we discussed means for nodes to ensure relevant votes are recorded so lazy approval +checkers get slashed properly, it is crucial to also discuss the actual chain import. Only if we guarantee that recorded +votes will get imported on chain (on all potential chains really) we will succeed in executing slashes. Particularly we +need to make sure backing votes end up on chain consistently. + +Dispute distribution will make sure all explicit dispute votes get distributed among nodes which includes current block +producers (current authority set) which is an important property: If the dispute carries on across an era change, we +need to ensure that the new validator set will learn about any disputes and their votes, so they can put that +information on chain. Dispute-distribution luckily has this property and always sends votes to the current authority +set. The issue is, for dispute-distribution, nodes send only their own explicit (or in some cases their approval vote) +in addition to some opposing vote. This guarantees that at least some backing or approval vote will be present at the +block producer, but we don't have a 100% guarantee to have votes for all backers, even less for approval checkers. + +Reason for backing votes: While backing votes will be present on at least some chain, that does not mean that any such +chain is still considered for block production in the current set - they might only exist on an already abandoned fork. +This means a block producer that just joined the set, might not have seen any of them. + +For approvals it is even more tricky and less necessary: Approval voting together with finalization is a completely +off-chain process therefore those protocols don't care about block production at all. Approval votes only have a +guarantee of being propagated between the nodes that are responsible for finalizing the concerned blocks. This implies +that on an era change the current authority set, will not necessarily get informed about any approval votes for the +previous era. Hence even if all validators of the previous era successfully recorded all approval votes in the dispute +coordinator, they won't get a chance to put them on chain, hence they won't be considered for slashing. + +It is important to note, that the essential properties of the system still hold: Dispute-distribution will distribute at +_least one_ "valid" vote to the current authority set, hence at least one node will get slashed in case of outcome +"invalid". Also in reality the validator set is rarely exchanged 100%, therefore in practice some validators in the +current authority set will overlap with the ones in the previous set and will be able to record votes on chain. + +Still, for maximum accountability we need to make sure a previous authority set can communicate votes to the next one, +regardless of any chain: This is yet to be implemented see section "Resiliency" in dispute-distribution and [this](https://github.com/paritytech/polkadot/issues/3398) ticket. ## Coordinating Actual Dispute Participation -Once the dispute coordinator learns about a dispute, it is its responsibility to -make sure the local node participates in that dispute. +Once the dispute coordinator learns about a dispute, it is its responsibility to make sure the local node participates +in that dispute. -The dispute coordinator learns about a dispute by importing votes from either -chain scraping or from dispute-distribution. If it finds opposing votes (always -the case when coming from dispute-distribution), it records the presence of a -dispute. Then, in case it does not find any local vote for that dispute already, -it needs to trigger participation in the dispute (see previous section for -considerations when the found local vote is an approval vote). +The dispute coordinator learns about a dispute by importing votes from either chain scraping or from +dispute-distribution. If it finds opposing votes (always the case when coming from dispute-distribution), it records the +presence of a dispute. Then, in case it does not find any local vote for that dispute already, it needs to trigger +participation in the dispute (see previous section for considerations when the found local vote is an approval vote). -Participation means, recovering availability and re-evaluating the POV. The -result of that validation (either valid or invalid) will be the node's vote on -that dispute: Either explicit "invalid" or "valid". The dispute coordinator will -inform `dispute-distribution` about our vote and `dispute-distribution` will make -sure that our vote gets distributed to all other validators. +Participation means, recovering availability and re-evaluating the POV. The result of that validation (either valid or +invalid) will be the node's vote on that dispute: Either explicit "invalid" or "valid". The dispute coordinator will +inform `dispute-distribution` about our vote and `dispute-distribution` will make sure that our vote gets distributed to +all other validators. -Nothing ever is that easy though. We can not blindly import anything that comes -along and trigger participation no matter what. +Nothing ever is that easy though. We can not blindly import anything that comes along and trigger participation no +matter what. ### Spam Considerations -In Polkadot's security model, it is important that attempts to attack the system -result in a slash of the offenders. Therefore we need to make sure that this -slash is actually happening. Attackers could try to prevent the slashing from -taking place, by overwhelming validators with disputes in such a way that no -single dispute ever concludes, because nodes are busy processing newly incoming -ones. Other attacks are imaginable as well, like raising disputes for candidates -that don't exist, just filling up everyone's disk slowly or worse making nodes -try to participate, which will result in lots of network requests for recovering -availability. - -The last point brings up a significant consideration in general: Disputes are -about escalation: Every node will suddenly want to check, instead of only a few. -A single message will trigger the whole network to start significant amount of -work and will cause lots of network traffic and messages. Hence the -dispute system is very susceptible to being a brutal amplifier for DoS attacks, -resulting in DoS attacks to become very easy and cheap, if we are not careful. - -One counter measure we are taking is making raising of disputes a costly thing: -If you raise a dispute, because you claim a candidate is invalid, although it is -in fact valid - you will get slashed, hence you pay for consuming those -resources. The issue is: This only works if the dispute concerns a candidate -that actually exists! - -If a node raises a dispute for a candidate that never got included (became -available) on any chain, then the dispute can never conclude, hence nobody gets -slashed. It makes sense to point out that this is less bad than it might sound -at first, as trying to participate in a dispute for a non existing candidate is -"relatively" cheap. Each node will send out a few hundred tiny request messages -for availability chunks, which all will end up in a tiny response "NoSuchChunk" -and then no participation will actually happen as there is nothing to -participate. Malicious nodes could provide chunks, which would make things more -costly, but at the full expense of the attackers bandwidth - no amplification -here. I am bringing that up for completeness only: Triggering a thousand nodes -to send out a thousand tiny network messages by just sending out a single -garbage message, is still a significant amplification and is nothing to ignore - -this could absolutely be used to cause harm! +In Polkadot's security model, it is important that attempts to attack the system result in a slash of the offenders. +Therefore we need to make sure that this slash is actually happening. Attackers could try to prevent the slashing from +taking place, by overwhelming validators with disputes in such a way that no single dispute ever concludes, because +nodes are busy processing newly incoming ones. Other attacks are imaginable as well, like raising disputes for +candidates that don't exist, just filling up everyone's disk slowly or worse making nodes try to participate, which will +result in lots of network requests for recovering availability. + +The last point brings up a significant consideration in general: Disputes are about escalation: Every node will suddenly +want to check, instead of only a few. A single message will trigger the whole network to start significant amount of +work and will cause lots of network traffic and messages. Hence the dispute system is very susceptible to being a brutal +amplifier for DoS attacks, resulting in DoS attacks to become very easy and cheap, if we are not careful. + +One counter measure we are taking is making raising of disputes a costly thing: If you raise a dispute, because you +claim a candidate is invalid, although it is in fact valid - you will get slashed, hence you pay for consuming those +resources. The issue is: This only works if the dispute concerns a candidate that actually exists! + +If a node raises a dispute for a candidate that never got included (became available) on any chain, then the dispute can +never conclude, hence nobody gets slashed. It makes sense to point out that this is less bad than it might sound at +first, as trying to participate in a dispute for a non existing candidate is "relatively" cheap. Each node will send out +a few hundred tiny request messages for availability chunks, which all will end up in a tiny response "NoSuchChunk" and +then no participation will actually happen as there is nothing to participate. Malicious nodes could provide chunks, +which would make things more costly, but at the full expense of the attackers bandwidth - no amplification here. I am +bringing that up for completeness only: Triggering a thousand nodes to send out a thousand tiny network messages by just +sending out a single garbage message, is still a significant amplification and is nothing to ignore - this could +absolutely be used to cause harm! ### Participation -As explained, just blindly participating in any "dispute" that comes along is -not a good idea. First we would like to make sure the dispute is actually -genuine, to prevent cheap DoS attacks. Secondly, in case of genuine disputes, we -would like to conclude one after the other, in contrast to -processing all at the same time, slowing down progress on all of them, bringing -individual processing to a complete halt in the worst case (nodes get overwhelmed -at some stage in the pipeline). - -To ensure to only spend significant work on genuine disputes, we only trigger -participation at all on any _vote import_ if any of the following holds true: - -- We saw the disputed candidate included in some not yet finalized block on at - least one fork of the chain. -- We have seen the disputed candidate backed in some not yet finalized block on - at least one fork of the chain. This ensures the candidate is at least not - completely made up and there has been some effort already flown into that - candidate. Generally speaking a dispute shouldn't be raised for a candidate - which is backed but is not yet included. Disputes are raised during approval - checking. We participate on such disputes as a precaution - maybe we haven't - seen the `CandidateIncluded` event yet? -- The dispute is already confirmed: Meaning that 1/3+1 nodes already - participated, as this suggests in our threat model that there was at least one - honest node that already voted, so the dispute must be genuine. - -Note: A node might be out of sync with the chain and we might only learn about a -block, including a candidate, after we learned about the dispute. This means, we -have to re-evaluate participation decisions on block import! - -With this, nodes won't waste significant resources on completely made up -candidates. The next step is to process dispute participation in a (globally) -ordered fashion. Meaning a majority of validators should arrive at at least -roughly at the same ordering of participation, for disputes to get resolved one -after another. This order is only relevant if there are lots of disputes, so we -obviously only need to worry about order if participations start queuing up. - -We treat participation for candidates that we have seen included with priority -and put them on a priority queue which sorts participation based on the block -number of the relay parent of the candidate and for candidates with the same -relay parent height further by the `CandidateHash`. This ordering is globally -unique and also prioritizes older candidates. - -The latter property makes sense, because if an older candidate turns out invalid, -we can roll back the full chain at once. If we resolved earlier disputes first -and they turned out invalid as well, we might need to roll back a couple of -times instead of just once to the oldest offender. This is obviously a good -idea, in particular it makes it impossible for an attacker to prevent rolling -back a very old candidate, by keeping raising disputes for newer candidates. - -For candidates we have not seen included, but we know are backed (thanks to -chain scraping) or we have seen a dispute with 1/3+1 participation (confirmed -dispute) on them - we put participation on a best-effort queue. It has got the -same ordering as the priority one - by block heights of the relay parent, older -blocks are with priority. There is a possibility not to be able to obtain the -block number of the parent when we are inserting the dispute in the queue. To -account for races, we will promote any existing participation request to the -priority queue once we learn about an including block. NOTE: this is still work -in progress and is tracked by [this +As explained, just blindly participating in any "dispute" that comes along is not a good idea. First we would like to +make sure the dispute is actually genuine, to prevent cheap DoS attacks. Secondly, in case of genuine disputes, we would +like to conclude one after the other, in contrast to processing all at the same time, slowing down progress on all of +them, bringing individual processing to a complete halt in the worst case (nodes get overwhelmed at some stage in the +pipeline). + +To ensure to only spend significant work on genuine disputes, we only trigger participation at all on any _vote import_ +if any of the following holds true: + +- We saw the disputed candidate included in some not yet finalized block on at least one fork of the chain. +- We have seen the disputed candidate backed in some not yet finalized block on at least one fork of the chain. This + ensures the candidate is at least not completely made up and there has been some effort already flown into that + candidate. Generally speaking a dispute shouldn't be raised for a candidate which is backed but is not yet included. + Disputes are raised during approval checking. We participate on such disputes as a precaution - maybe we haven't seen + the `CandidateIncluded` event yet? +- The dispute is already confirmed: Meaning that 1/3+1 nodes already participated, as this suggests in our threat model + that there was at least one honest node that already voted, so the dispute must be genuine. + +Note: A node might be out of sync with the chain and we might only learn about a block, including a candidate, after we +learned about the dispute. This means, we have to re-evaluate participation decisions on block import! + +With this, nodes won't waste significant resources on completely made up candidates. The next step is to process dispute +participation in a (globally) ordered fashion. Meaning a majority of validators should arrive at at least roughly at the +same ordering of participation, for disputes to get resolved one after another. This order is only relevant if there are +lots of disputes, so we obviously only need to worry about order if participations start queuing up. + +We treat participation for candidates that we have seen included with priority and put them on a priority queue which +sorts participation based on the block number of the relay parent of the candidate and for candidates with the same +relay parent height further by the `CandidateHash`. This ordering is globally unique and also prioritizes older +candidates. + +The latter property makes sense, because if an older candidate turns out invalid, we can roll back the full chain at +once. If we resolved earlier disputes first and they turned out invalid as well, we might need to roll back a couple of +times instead of just once to the oldest offender. This is obviously a good idea, in particular it makes it impossible +for an attacker to prevent rolling back a very old candidate, by keeping raising disputes for newer candidates. + +For candidates we have not seen included, but we know are backed (thanks to chain scraping) or we have seen a dispute +with 1/3+1 participation (confirmed dispute) on them - we put participation on a best-effort queue. It has got the same +ordering as the priority one - by block heights of the relay parent, older blocks are with priority. There is a +possibility not to be able to obtain the block number of the parent when we are inserting the dispute in the queue. To +account for races, we will promote any existing participation request to the priority queue once we learn about an +including block. NOTE: this is still work in progress and is tracked by [this issue](https://github.com/paritytech/polkadot/issues/5875). ### Abandoned Forks -Finalization: As mentioned we care about included and backed candidates on any -non-finalized chain, given that any disputed chain will not get finalized, we -don't need to care about finalized blocks, but what about forks that fall behind -the finalized chain in terms of block number? For those we would still like to -be able to participate in any raised disputes, otherwise attackers might be able -to avoid a slash if they manage to create a better fork after they learned about -the approval checkers. Therefore we do care about those forks even after they -have fallen behind the finalized chain. - -For simplicity we also care about the actual finalized chain (not just forks) up -to a certain depth. We do have to limit the depth, because otherwise we open a -DoS vector again. The depth (into the finalized chain) should be oriented on the -approval-voting execution timeout, in particular it should be significantly -larger. Otherwise by the time the execution is allowed to finish, we already -dropped information about those candidates and the dispute could not conclude. +Finalization: As mentioned we care about included and backed candidates on any non-finalized chain, given that any +disputed chain will not get finalized, we don't need to care about finalized blocks, but what about forks that fall +behind the finalized chain in terms of block number? For those we would still like to be able to participate in any +raised disputes, otherwise attackers might be able to avoid a slash if they manage to create a better fork after they +learned about the approval checkers. Therefore we do care about those forks even after they have fallen behind the +finalized chain. + +For simplicity we also care about the actual finalized chain (not just forks) up to a certain depth. We do have to limit +the depth, because otherwise we open a DoS vector again. The depth (into the finalized chain) should be oriented on the +approval-voting execution timeout, in particular it should be significantly larger. Otherwise by the time the execution +is allowed to finish, we already dropped information about those candidates and the dispute could not conclude. ## Import ### Spam Considerations -In the last section we looked at how to treat queuing participations to -handle heavy dispute load well. This already ensures, that honest nodes won't -amplify cheap DoS attacks. There is one minor issue remaining: Even if we delay -participation until we have some confirmation of the authenticity of the -dispute, we should also not blindly import all votes arriving into the database -as this might be used to just slowly fill up disk space, until the node is no -longer functional. This leads to our last protection mechanism at the dispute -coordinator level (dispute-distribution also has its own), which is spam slots. -For each import containing an invalid vote, where we don't know whether it might -be spam or not we increment a counter for each signing participant of explicit -`invalid` votes. - -What votes do we treat as a potential spam? A vote will increase a spam slot if -and only if all of the following conditions are satisfied: - -* the candidate under dispute was not seen included nor backed on any chain -* the dispute is not confirmed -* we haven't cast a vote for the dispute - -Whenever any vote on a dispute is imported these conditions are checked. If the -dispute is found not to be potential spam, then spam slots for the disputed candidate hash are cleared. This decrements the spam count for every validator +In the last section we looked at how to treat queuing participations to handle heavy dispute load well. This already +ensures, that honest nodes won't amplify cheap DoS attacks. There is one minor issue remaining: Even if we delay +participation until we have some confirmation of the authenticity of the dispute, we should also not blindly import all +votes arriving into the database as this might be used to just slowly fill up disk space, until the node is no longer +functional. This leads to our last protection mechanism at the dispute coordinator level (dispute-distribution also has +its own), which is spam slots. For each import containing an invalid vote, where we don't know whether it might be spam +or not we increment a counter for each signing participant of explicit `invalid` votes. + +What votes do we treat as a potential spam? A vote will increase a spam slot if and only if all of the following +conditions are satisfied: + +- the candidate under dispute was not seen included nor backed on any chain +- the dispute is not confirmed +- we haven't cast a vote for the dispute + +Whenever any vote on a dispute is imported these conditions are checked. If the dispute is found not to be potential +spam, then spam slots for the disputed candidate hash are cleared. This decrements the spam count for every validator 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 -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. - -The reason this works is because we only need to worry about actual dispute -votes. Import of backing votes are already rate limited and concern only real -candidates. For approval votes a similar argument holds (if they come from -approval-voting), but we also don't import them until a dispute already -concluded. For actual dispute votes we need two opposing votes, so there must be -an explicit `invalid` vote in the import. Only a third of the validators can be -malicious, so spam disk usage is limited to `2*vote_size*n/3*NUM_SPAM_SLOTS`, with -`n` being the number of validators. +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 +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. + +The reason this works is because we only need to worry about actual dispute votes. Import of backing votes are already +rate limited and concern only real candidates. For approval votes a similar argument holds (if they come from +approval-voting), but we also don't import them until a dispute already concluded. For actual dispute votes we need two +opposing votes, so there must be an explicit `invalid` vote in the import. Only a third of the validators can be +malicious, so spam disk usage is limited to `2*vote_size*n/3*NUM_SPAM_SLOTS`, with `n` being the number of validators. ### Backing Votes -Backing votes are in some way special. For starters they are the only valid -votes that are guaranteed to exist for any valid dispute to be raised. Second -they are the only votes that commit to a shorter execution timeout -`BACKING_EXECUTION_TIMEOUT`, compared to a more lenient timeout used in approval -voting. To account properly for execution time variance across machines, -slashing might treat backing votes differently (more aggressively) than other -voting `valid` votes. Hence in import we shall never override a backing vote -with another valid vote. They can not be assumed to be interchangeable. +Backing votes are in some way special. For starters they are the only valid votes that are guaranteed to exist for any +valid dispute to be raised. Second they are the only votes that commit to a shorter execution timeout +`BACKING_EXECUTION_TIMEOUT`, compared to a more lenient timeout used in approval voting. To account properly for +execution time variance across machines, slashing might treat backing votes differently (more aggressively) than other +voting `valid` votes. Hence in import we shall never override a backing vote with another valid vote. They can not be +assumed to be interchangeable. ## Attacks & Considerations -The following attacks on the priority queue and best-effort queues are -considered in above design. +The following attacks on the priority queue and best-effort queues are considered in above design. ### Priority Queue -On the priority queue, we will only queue participations for candidates we have -seen included on any chain. Any attack attempt would start with a candidate -included on some chain, but an attacker could try to only reveal the including -relay chain blocks to just some honest validators and stop as soon as it learns -that some honest validator would have a relevant approval assignment. +On the priority queue, we will only queue participations for candidates we have seen included on any chain. Any attack +attempt would start with a candidate included on some chain, but an attacker could try to only reveal the including +relay chain blocks to just some honest validators and stop as soon as it learns that some honest validator would have a +relevant approval assignment. -Without revealing the including block to any honest validator, we don't really -have an attack yet. Once the block is revealed though, the above is actually -very hard. Each honest validator will re-distribute the block it just learned -about. This means an attacker would need to pull of a targeted DoS attack, which -allows the validator to send its assignment, but prevents it from forwarding and -sharing the relay chain block. +Without revealing the including block to any honest validator, we don't really have an attack yet. Once the block is +revealed though, the above is actually very hard. Each honest validator will re-distribute the block it just learned +about. This means an attacker would need to pull of a targeted DoS attack, which allows the validator to send its +assignment, but prevents it from forwarding and sharing the relay chain block. -This sounds already hard enough, provided that we also start participation if -we learned about an including block after the dispute has been raised already -(we need to update participation queues on new leaves), but to be even safer -we choose to have an additional best-effort queue. +This sounds already hard enough, provided that we also start participation if we learned about an including block after +the dispute has been raised already (we need to update participation queues on new leaves), but to be even safer we +choose to have an additional best-effort queue. ### Best-Effort Queue -While attacking the priority queue is already pretty hard, attacking the -best-effort queue is even harder. For a candidate to be a threat, it has to be -included on some chain. For it to be included, it has to have been backed before -and at least n/3 honest nodes must have seen that block, so availability -(inclusion) can be reached. Making a full third of the nodes not further -propagate a block, while at the same time allowing them to fetch chunks, sign -and distribute bitfields seems almost infeasible and even if accomplished, those -nodes would be enough to confirm a dispute and we have not even touched the -above fact that in addition, for an attack, the following including block must -be shared with honest validators as well. - -It is worth mentioning that a successful attack on the priority queue as -outlined above is already outside of our threat model, as it assumes n/3 -malicious nodes + additionally malfunctioning/DoSed nodes. Even more so for -attacks on the best-effort queue, as our threat model only allows for n/3 -malicious _or_ malfunctioning nodes in total. It would therefore be a valid -decision to ditch the best-effort queue, if it proves to become a burden or -creates other issues. - -One issue we should not be worried about though is spam. For abusing best-effort -for spam, the following scenario would be necessary: - -An attacker controls a backing group: The attacker can then have candidates -backed and choose to not provide chunks. This should come at a cost to miss out -on rewards for backing, so is not free. At the same time it is rate limited, as -a backing group can only back so many candidates legitimately. (~ 1 per slot): - -1. They have to wait until a malicious actor becomes block producer (for causing - additional forks via equivocation for example). +While attacking the priority queue is already pretty hard, attacking the best-effort queue is even harder. For a +candidate to be a threat, it has to be included on some chain. For it to be included, it has to have been backed before +and at least n/3 honest nodes must have seen that block, so availability (inclusion) can be reached. Making a full third +of the nodes not further propagate a block, while at the same time allowing them to fetch chunks, sign and distribute +bitfields seems almost infeasible and even if accomplished, those nodes would be enough to confirm a dispute and we have +not even touched the above fact that in addition, for an attack, the following including block must be shared with +honest validators as well. + +It is worth mentioning that a successful attack on the priority queue as outlined above is already outside of our threat +model, as it assumes n/3 malicious nodes + additionally malfunctioning/DoSed nodes. Even more so for attacks on the +best-effort queue, as our threat model only allows for n/3 malicious _or_ malfunctioning nodes in total. It would +therefore be a valid decision to ditch the best-effort queue, if it proves to become a burden or creates other issues. + +One issue we should not be worried about though is spam. For abusing best-effort for spam, the following scenario would +be necessary: + +An attacker controls a backing group: The attacker can then have candidates backed and choose to not provide chunks. +This should come at a cost to miss out on rewards for backing, so is not free. At the same time it is rate limited, as a +backing group can only back so many candidates legitimately. (~ 1 per slot): + +1. They have to wait until a malicious actor becomes block producer (for causing additional forks via equivocation for + example). 2. Forks are possible, but if caused by equivocation also not free. -3. For each fork the attacker has to wait until the candidate times out, for - backing another one. +3. For each fork the attacker has to wait until the candidate times out, for backing another one. -Assuming there can only be a handful of forks, 2) together with 3) the candidate -timeout restriction, frequency should indeed be in the ballpark of once per -slot. Scaling linearly in the number of controlled backing groups, so two groups +Assuming there can only be a handful of forks, 2) together with 3) the candidate timeout restriction, frequency should +indeed be in the ballpark of once per slot. Scaling linearly in the number of controlled backing groups, so two groups would mean 2 backings per slot, ... -So by this reasoning an attacker could only do very limited harm and at the same -time will have to pay some price for it (it will miss out on rewards). Overall -the work done by the network might even be in the same ballpark as if actors -just behaved honestly: +So by this reasoning an attacker could only do very limited harm and at the same time will have to pay some price for it +(it will miss out on rewards). Overall the work done by the network might even be in the same ballpark as if actors just +behaved honestly: 1. Validators would have fetched chunks 2. Approval checkers would have done approval checks -While because of the attack (backing, not providing chunks and afterwards -disputing the candidate), the work for 1000 validators would be: +While because of the attack (backing, not providing chunks and afterwards disputing the candidate), the work for 1000 +validators would be: -All validators sending out ~ 1000 tiny requests over already established -connections, with also tiny (byte) responses. +All validators sending out ~ 1000 tiny requests over already established connections, with also tiny (byte) responses. -This means around a million requests, while in the honest case it would be ~ -10000 (30 approval checkers x330) - where each request triggers a response in -the range of kilobytes. Hence network load alone will likely be higher in the -honest case than in the DoS attempt case, which would mean the DoS attempt -actually reduces load, while also costing rewards. +This means around a million requests, while in the honest case it would be ~ 10000 (30 approval checkers x330) - where +each request triggers a response in the range of kilobytes. Hence network load alone will likely be higher in the honest +case than in the DoS attempt case, which would mean the DoS attempt actually reduces load, while also costing rewards. -In the worst case this can happen multiple times, as we would retry that on -every vote import. The effect would still be in the same ballpark as honest -behavior though and can also be mitigated by chilling repeated availability -recovery requests for example. +In the worst case this can happen multiple times, as we would retry that on every vote import. The effect would still be +in the same ballpark as honest behavior though and can also be mitigated by chilling repeated availability recovery +requests for example. ## Out of Scope ### No Disputes for Non Included Candidates -We only ever care about disputes for candidates that have been included on at -least some chain (became available). This is because the availability system was -designed for precisely that: Only with inclusion (availability) we have -guarantees about the candidate to actually be available. Because only then we -have guarantees that malicious backers can be reliably checked and slashed. Also, by design non included candidates do not pose any threat to the system. - -One could think of an (additional) dispute system to make it possible to dispute -any candidate that has been proposed by a validator, no matter whether it got -successfully included or even backed. Unfortunately, it would be very brittle -(no availability) and also spam protection would be way harder than for the -disputes handled by the dispute-coordinator. In fact, all the spam handling -strategies described above would simply be unavailable. - -It is worth thinking about who could actually raise such disputes anyway: -Approval checkers certainly not, as they will only ever check once availability -succeeded. The only other nodes that meaningfully could/would are honest backing -nodes or collators. For collators spam considerations would be even worse as -there can be an unlimited number of them and we can not charge them for spam, so -trying to handle disputes raised by collators would be even more complex. For -honest backers: It actually makes more sense for them to wait until availability -is reached as well, as only then they have guarantees that other nodes will be -able to check. If they disputed before, all nodes would need to recover the data +We only ever care about disputes for candidates that have been included on at least some chain (became available). This +is because the availability system was designed for precisely that: Only with inclusion (availability) we have +guarantees about the candidate to actually be available. Because only then we have guarantees that malicious backers can +be reliably checked and slashed. Also, by design non included candidates do not pose any threat to the system. + +One could think of an (additional) dispute system to make it possible to dispute any candidate that has been proposed by +a validator, no matter whether it got successfully included or even backed. Unfortunately, it would be very brittle (no +availability) and also spam protection would be way harder than for the disputes handled by the dispute-coordinator. In +fact, all the spam handling strategies described above would simply be unavailable. + +It is worth thinking about who could actually raise such disputes anyway: Approval checkers certainly not, as they will +only ever check once availability succeeded. The only other nodes that meaningfully could/would are honest backing nodes +or collators. For collators spam considerations would be even worse as there can be an unlimited number of them and we +can not charge them for spam, so trying to handle disputes raised by collators would be even more complex. For honest +backers: It actually makes more sense for them to wait until availability is reached as well, as only then they have +guarantees that other nodes will be able to check. If they disputed before, all nodes would need to recover the data 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 complexity. We therefore punt on such -disputes and concentrate on disputes the system was designed to handle. +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 +complexity. We therefore punt on such disputes and concentrate on disputes the system was designed to handle. ### No Disputes for Already Finalized Blocks -Note that by above rules in the `Participation` section, we will not participate -in disputes concerning a candidate in an already finalized block. This is -because, disputing an already finalized block is simply too late and therefore -of little value. Once finalized, bridges have already processed the block for -example, so we have to assume the damage is already done. Governance has to step -in and fix what can be fixed. +Note that by above rules in the `Participation` section, we will not participate in disputes concerning a candidate in +an already finalized block. This is because, disputing an already finalized block is simply too late and therefore of +little value. Once finalized, bridges have already processed the block for example, so we have to assume the damage is +already done. Governance has to step in and fix what can be fixed. -Making disputes for already finalized blocks possible would only provide two -features: +Making disputes for already finalized blocks possible would only provide two features: 1. We can at least still slash attackers. -2. We can freeze the chain to some governance only mode, in an attempt to - minimize potential harm done. +2. We can freeze the chain to some governance only mode, in an attempt to minimize potential harm done. -Both seem kind of worthwhile, although as argued above, it is likely that there -is not too much that can be done in 2 and we would likely only ending up DoSing -the whole system without much we can do. 1 can also be achieved via governance +Both seem kind of worthwhile, although as argued above, it is likely that there is not too much that can be done in 2 +and we would likely only ending up DoSing the whole system without much we can do. 1 can also be achieved via governance mechanisms. -In any case, our focus should be making as sure as reasonably possible that any -potentially invalid block does not get finalized in the first place. Not -allowing disputing already finalized blocks actually helps a great deal with -this goal as it massively reduces the amount of candidates that can be disputed. - -This makes attempts to overwhelm the system with disputes significantly harder -and counter measures way easier. We can limit inclusion for example (as -suggested [here](https://github.com/paritytech/polkadot/issues/5898) in case of -high dispute load. Another measure we have at our disposal is that on finality -lag block production will slow down, implicitly reducing the rate of new -candidates that can be disputed. Hence, the cutting-off of the unlimited -candidate supply of already finalized blocks, guarantees the necessary DoS -protection and ensures we can have measures in place to keep up with processing -of disputes. - -If we allowed participation for disputes for already finalized candidates, the -above spam protection mechanisms would be insufficient/relying 100% on full and -quick disabling of spamming validators. +In any case, our focus should be making as sure as reasonably possible that any potentially invalid block does not get +finalized in the first place. Not allowing disputing already finalized blocks actually helps a great deal with this goal +as it massively reduces the amount of candidates that can be disputed. + +This makes attempts to overwhelm the system with disputes significantly harder and counter measures way easier. We can +limit inclusion for example (as suggested [here](https://github.com/paritytech/polkadot/issues/5898) in case of high +dispute load. Another measure we have at our disposal is that on finality lag block production will slow down, +implicitly reducing the rate of new candidates that can be disputed. Hence, the cutting-off of the unlimited candidate +supply of already finalized blocks, guarantees the necessary DoS protection and ensures we can have measures in place to +keep up with processing of disputes. + +If we allowed participation for disputes for already finalized candidates, the above spam protection mechanisms would be +insufficient/relying 100% on full and quick disabling of spamming validators. ## Database Schema We use an underlying Key-Value database where we assume we have the following operations available: - * `write(key, value)` - * `read(key) -> Option` - * `iter_with_prefix(prefix) -> Iterator<(key, value)>` - gives all keys and values in - lexicographical order where the key starts with `prefix`. + - `write(key, value)` + - `read(key) -> Option` + - `iter_with_prefix(prefix) -> Iterator<(key, value)>` - gives all keys and values in lexicographical order where the + key starts with `prefix`. We use this database to encode the following schema: @@ -612,8 +471,8 @@ We use this database to encode the following schema: "earliest-session" -> Option ``` -The meta information that we track per-candidate is defined as the `CandidateVotes` struct. -This draws on the [dispute statement types][DisputeTypes] +The meta information that we track per-candidate is defined as the `CandidateVotes` struct. This draws on the [dispute +statement types][DisputeTypes] ```rust /// Tracked votes on candidates, for the purposes of dispute resolution. @@ -659,8 +518,7 @@ Output: ## Functionality -This assumes a constant `DISPUTE_WINDOW: SessionWindowSize`. This should correspond to at least 1 -day. +This assumes a constant `DISPUTE_WINDOW: SessionWindowSize`. This should correspond to at least 1 day. Ephemeral in-memory state: @@ -684,42 +542,36 @@ struct State { ### On startup -When the subsystem is initialised it waits for a new leaf (message -`OverseerSignal::ActiveLeaves`). The leaf is used to initialise a -`RollingSessionWindow` instance (contains leaf hash and `DISPUTE_WINDOW` which -is a constant). +When the subsystem is initialised it waits for a new leaf (message `OverseerSignal::ActiveLeaves`). The leaf is used to +initialise a `RollingSessionWindow` instance (contains leaf hash and `DISPUTE_WINDOW` which is a constant). -Next the active disputes are loaded from the DB and initialize spam slots -accordingly, then for each loaded dispute, we either send a -`DisputeDistribution::SendDispute` if there is a local vote from us available or -if there is none and participation is in order, we push the dispute to -participation. +Next the active disputes are loaded from the DB and initialize spam slots accordingly, then for each loaded dispute, we +either send a `DisputeDistribution::SendDispute` if there is a local vote from us available or if there is none and +participation is in order, we push the dispute to participation. ### The main loop -Just after the subsystem initialisation the main loop (`fn run_until_error()`) runs until -`OverseerSignal::Conclude` signal is received. Before executing the actual main loop the leaf and -the participations, obtained during startup are enqueued for processing. If there is capacity (the -number of running participations is less than `MAX_PARALLEL_PARTICIPATIONS`) participation jobs are -started (`func participate`). Finally the component waits for messages from Overseer. The behaviour -on each message is described in the following subsections. +Just after the subsystem initialisation the main loop (`fn run_until_error()`) runs until `OverseerSignal::Conclude` +signal is received. Before executing the actual main loop the leaf and the participations, obtained during startup are +enqueued for processing. If there is capacity (the number of running participations is less than +`MAX_PARALLEL_PARTICIPATIONS`) participation jobs are started (`func participate`). Finally the component waits for +messages from Overseer. The behaviour on each message is described in the following subsections. ### On `OverseerSignal::ActiveLeaves` -Initiates processing via the `Participation` module and updates the internal state of the subsystem. -More concretely: +Initiates processing via the `Participation` module and updates the internal state of the subsystem. More concretely: -* Passes the `ActiveLeavesUpdate` message to the ordering provider. -* Updates the session info cache. -* Updates `self.highest_session`. -* Prunes old spam slots in case the session window has advanced. -* Scrapes on chain votes. +- Passes the `ActiveLeavesUpdate` message to the ordering provider. +- Updates the session info cache. +- Updates `self.highest_session`. +- Prunes old spam slots in case the session window has advanced. +- Scrapes on chain votes. ### On `MuxedMessage::Participation` -This message is sent from `Participatuion` module and indicates a processed dispute participation. -It's the result of the processing job initiated with `OverseerSignal::ActiveLeaves`. The subsystem -issues a `DisputeMessage` with the result. +This message is sent from `Participatuion` module and indicates a processed dispute participation. It's the result of +the processing job initiated with `OverseerSignal::ActiveLeaves`. The subsystem issues a `DisputeMessage` with the +result. ### On `OverseerSignal::Conclude` @@ -731,14 +583,13 @@ Performs cleanup of the finalized candidate. ### On `DisputeCoordinatorMessage::ImportStatements` -Import statements by validators are processed in `fn handle_import_statements()`. The function has -got three main responsibilities: -* Initiate participation in disputes and sending out of any existing own - approval vote in case of a raised dispute. -* Persist all fresh votes in the database. Fresh votes in this context means votes that are not - already processed by the node. -* Spam protection on all invalid (`DisputeStatement::Invalid`) votes. Please check the SpamSlots - section for details on how spam protection works. +Import statements by validators are processed in `fn handle_import_statements()`. The function has got three main +responsibilities: +- Initiate participation in disputes and sending out of any existing own approval vote in case of a raised dispute. +- Persist all fresh votes in the database. Fresh votes in this context means votes that are not already processed by the + node. +- Spam protection on all invalid (`DisputeStatement::Invalid`) votes. Please check the SpamSlots section for details on + how spam protection works. ### On `DisputeCoordinatorMessage::RecentDisputes` @@ -750,38 +601,35 @@ Returns all recent disputes concluded within the last `ACTIVE_DURATION_SECS` . ### On `DisputeCoordinatorMessage::QueryCandidateVotes` -Loads `candidate-votes` for every `(SessionIndex, CandidateHash)` in the input query and returns -data within each `CandidateVote`. If a particular `candidate-vote` is missing, that particular -request is omitted from the response. +Loads `candidate-votes` for every `(SessionIndex, CandidateHash)` in the input query and returns data within each +`CandidateVote`. If a particular `candidate-vote` is missing, that particular request is omitted from the response. ### On `DisputeCoordinatorMessage::IssueLocalStatement` Executes `fn issue_local_statement()` which performs the following operations: -* Deconstruct into parts `{ session_index, candidate_hash, candidate_receipt, is_valid }`. -* Construct a [`DisputeStatement`][DisputeStatement] based on `Valid` or `Invalid`, depending on the - parameterization of this routine. -* Sign the statement with each key in the `SessionInfo`'s list of parachain validation keys which is - present in the keystore, except those whose indices appear in `voted_indices`. This will typically - just be one key, but this does provide some future-proofing for situations where the same node may - run on behalf multiple validators. At the time of writing, this is not a use-case we support as - other subsystems do not invariably provide this guarantee. -* Write statement to DB. -* Send a `DisputeDistributionMessage::SendDispute` message to get the vote distributed to other - validators. +- Deconstruct into parts `{ session_index, candidate_hash, candidate_receipt, is_valid }`. +- Construct a [`DisputeStatement`][DisputeStatement] based on `Valid` or `Invalid`, depending on the parameterization of + this routine. +- Sign the statement with each key in the `SessionInfo`'s list of parachain validation keys which is present in the + keystore, except those whose indices appear in `voted_indices`. This will typically just be one key, but this does + provide some future-proofing for situations where the same node may run on behalf multiple validators. At the time of + writing, this is not a use-case we support as other subsystems do not invariably provide this guarantee. +- Write statement to DB. +- Send a `DisputeDistributionMessage::SendDispute` message to get the vote distributed to other validators. ### On `DisputeCoordinatorMessage::DetermineUndisputedChain` Executes `fn determine_undisputed_chain()` which performs the following: -* Load `"recent-disputes"`. -* Deconstruct into parts `{ base_number, block_descriptions, rx }` -* Starting from the beginning of `block_descriptions`: +- Load `"recent-disputes"`. +- Deconstruct into parts `{ base_number, block_descriptions, rx }` +- Starting from the beginning of `block_descriptions`: 1. Check the `RecentDisputes` for a dispute of each candidate in the block description. 1. If there is a dispute which is active or concluded negative, exit the loop. -* For the highest index `i` reached in the `block_descriptions`, send `(base_number + i + 1, - block_hash)` on the channel, unless `i` is 0, in which case `None` should be sent. The - `block_hash` is determined by inspecting `block_descriptions[i]`. +- For the highest index `i` reached in the `block_descriptions`, send `(base_number + i + 1, block_hash)` on the + channel, unless `i` is 0, in which case `None` should be sent. The `block_hash` is determined by inspecting + `block_descriptions[i]`. [DisputeTypes]: ../../types/disputes.md [DisputeStatement]: ../../types/disputes.md#disputestatement diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md index 3a45f53c45d..4547e02352e 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md @@ -202,8 +202,8 @@ the dispute-coordinator already knows about the dispute. Goal 3 and 4 are obviously very related and both can easily be solved via rate limiting as we shall see below. Rate limits should already be implemented at the -substrate level, but [are not](https://github.com/paritytech/substrate/issues/7750) -at the time of writing. But even if they were, the enforced substrate limits would +Substrate level, but [are not](https://github.com/paritytech/substrate/issues/7750) +at the time of writing. But even if they were, the enforced Substrate limits would likely not be configurable and thus would still be to high for our needs as we can rely on the following observations: @@ -282,10 +282,10 @@ well, we will do the following: to assume this is concerning a new dispute. 2. We open a batch and start collecting incoming messages for that candidate, instead of immediately forwarding. -4. We keep collecting votes in the batch until we receive less than +3. We keep collecting votes in the batch until we receive less than `MIN_KEEP_BATCH_ALIVE_VOTES` unique votes in the last `BATCH_COLLECTING_INTERVAL`. This is important to accommodate for goal 5 and also 3. -5. We send the whole batch to the dispute-coordinator. +4. We send the whole batch to the dispute-coordinator. This together with rate limiting explained above ensures we will be able to process valid disputes: We can limit the number of simultaneous existing batches @@ -312,8 +312,8 @@ of attackers, each has 10 messages per second, all are needed to maintain the batches in memory. Therefore we have a hard cap of around 330 (number of malicious nodes) open batches. Each can be filled with number of malicious actor's votes. So 330 batches with each 330 votes: Let's assume approximately 100 -bytes per signature/vote. This results in a worst case memory usage of 330 * 330 -* 100 ~= 10 MiB. +bytes per signature/vote. This results in a worst case memory usage of +`330 * 330 * 100 ~= 10 MiB`. For 10_000 validators, we are already in the Gigabyte range, which means that with a validator set that large we might want to be more strict with the rate limit or diff --git a/polkadot/roadmap/implementers-guide/src/node/grandpa-voting-rule.md b/polkadot/roadmap/implementers-guide/src/node/grandpa-voting-rule.md index 5e608ccfd62..6997dc99f80 100644 --- a/polkadot/roadmap/implementers-guide/src/node/grandpa-voting-rule.md +++ b/polkadot/roadmap/implementers-guide/src/node/grandpa-voting-rule.md @@ -1,10 +1,25 @@ # GRANDPA Voting Rule -Specifics on the motivation and types of constraints we apply to the GRANDPA voting logic as well as the definitions of **viable** and **finalizable** blocks can be found in the [Chain Selection Protocol](../protocol-chain-selection.md) section. -The subsystem which provides us with viable leaves is the [Chain Selection Subsystem](utility/chain-selection.md). +Specifics on the motivation and types of constraints we apply to the GRANDPA voting logic as well as the definitions of +**viable** and **finalizable** blocks can be found in the [Chain Selection Protocol](../protocol-chain-selection.md) +section. The subsystem which provides us with viable leaves is the [Chain Selection +Subsystem](utility/chain-selection.md). -GRANDPA's regular voting rule is for each validator to select the longest chain they are aware of. GRANDPA proceeds in rounds, collecting information from all online validators and determines the blocks that a supermajority of validators all have in common with each other. +GRANDPA's regular voting rule is for each validator to select the longest chain they are aware of. GRANDPA proceeds in +rounds, collecting information from all online validators and determines the blocks that a supermajority of validators +all have in common with each other. -The low-level GRANDPA logic will provide us with a **required block**. We can find the best leaf containing that block in its chain with the [`ChainSelectionMessage::BestLeafContaining`](../types/overseer-protocol.md#chain-selection-message). If the result is `None`, then we will simply cast a vote on the required block. +The low-level GRANDPA logic will provide us with a **required block**. We can find the best leaf containing that block +in its chain with the +[`ChainSelectionMessage::BestLeafContaining`](../types/overseer-protocol.md#chain-selection-message). If the result is +`None`, then we will simply cast a vote on the required block. -The **viable** leaves provided from the chain selection subsystem are not necessarily **finalizable**, so we need to perform further work to discover the finalizable ancestor of the block. The first constraint is to avoid voting on any unapproved block. The highest approved ancestor of a given block can be determined by querying the Approval Voting subsystem via the [`ApprovalVotingMessage::ApprovedAncestor`](../types/overseer-protocol.md#approval-voting) message. If the response is `Some`, we continue and apply the second constraint. The second constraint is to avoid voting on any block containing a candidate undergoing an active dispute. The list of block hashes and candidates returned from `ApprovedAncestor` should be reversed, and passed to the [`DisputeCoordinatorMessage::DetermineUndisputedChain`](../types/overseer-protocol.md#dispute-coordinator-message) to determine the **finalizable** block which will be our eventual vote. +The **viable** leaves provided from the chain selection subsystem are not necessarily **finalizable**, so we need to +perform further work to discover the finalizable ancestor of the block. The first constraint is to avoid voting on any +unapproved block. The highest approved ancestor of a given block can be determined by querying the Approval Voting +subsystem via the [`ApprovalVotingMessage::ApprovedAncestor`](../types/overseer-protocol.md#approval-voting) message. If +the response is `Some`, we continue and apply the second constraint. The second constraint is to avoid voting on any +block containing a candidate undergoing an active dispute. The list of block hashes and candidates returned from +`ApprovedAncestor` should be reversed, and passed to the +[`DisputeCoordinatorMessage::DetermineUndisputedChain`](../types/overseer-protocol.md#dispute-coordinator-message) to +determine the **finalizable** block which will be our eventual vote. diff --git a/polkadot/roadmap/implementers-guide/src/node/overseer.md b/polkadot/roadmap/implementers-guide/src/node/overseer.md index 21300d9098a..53a11530810 100644 --- a/polkadot/roadmap/implementers-guide/src/node/overseer.md +++ b/polkadot/roadmap/implementers-guide/src/node/overseer.md @@ -24,27 +24,44 @@ The hierarchy of subsystems: ``` -The overseer determines work to do based on block import events and block finalization events. It does this by keeping track of the set of relay-parents for which work is currently being done. This is known as the "active leaves" set. It determines an initial set of active leaves on startup based on the data on-disk, and uses events about blockchain import to update the active leaves. Updates lead to [`OverseerSignal`](../types/overseer-protocol.md#overseer-signal)`::ActiveLeavesUpdate` being sent according to new relay-parents, as well as relay-parents to stop considering. Block import events inform the overseer of leaves that no longer need to be built on, now that they have children, and inform us to begin building on those children. Block finalization events inform us when we can stop focusing on blocks that appear to have been orphaned. - -The overseer is also responsible for tracking the freshness of active leaves. Leaves are fresh when they're encountered for the first time, and stale when they're encountered for subsequent times. This can occur after chain reversions or when the fork-choice rule abandons some chain. This distinction is used to manage **Reversion Safety**. Consensus messages are often localized to a specific relay-parent, and it is often a misbehavior to equivocate or sign two conflicting messages. When reverting the chain, we may begin work on a leaf that subsystems have already signed messages for. Subsystems which need to account for reversion safety should avoid performing work on stale leaves. +The overseer determines work to do based on block import events and block finalization events. It does this by keeping +track of the set of relay-parents for which work is currently being done. This is known as the "active leaves" set. It +determines an initial set of active leaves on startup based on the data on-disk, and uses events about blockchain import +to update the active leaves. Updates lead to +[`OverseerSignal`](../types/overseer-protocol.md#overseer-signal)`::ActiveLeavesUpdate` being sent according to new +relay-parents, as well as relay-parents to stop considering. Block import events inform the overseer of leaves that no +longer need to be built on, now that they have children, and inform us to begin building on those children. Block +finalization events inform us when we can stop focusing on blocks that appear to have been orphaned. + +The overseer is also responsible for tracking the freshness of active leaves. Leaves are fresh when they're encountered +for the first time, and stale when they're encountered for subsequent times. This can occur after chain reversions or +when the fork-choice rule abandons some chain. This distinction is used to manage **Reversion Safety**. Consensus +messages are often localized to a specific relay-parent, and it is often a misbehavior to equivocate or sign two +conflicting messages. When reverting the chain, we may begin work on a leaf that subsystems have already signed messages +for. Subsystems which need to account for reversion safety should avoid performing work on stale leaves. The overseer's logic can be described with these functions: ## On Startup * Start all subsystems -* Determine all blocks of the blockchain that should be built on. This should typically be the head of the best fork of the chain we are aware of. Sometimes add recent forks as well. +* Determine all blocks of the blockchain that should be built on. This should typically be the head of the best fork of + the chain we are aware of. Sometimes add recent forks as well. * Send an `OverseerSignal::ActiveLeavesUpdate` to all subsystems with `activated` containing each of these blocks. * Begin listening for block import and finality events ## On Block Import Event -* Apply the block import event to the active leaves. A new block should lead to its addition to the active leaves set and its parent being deactivated. -* Mark any stale leaves as stale. The overseer should track all leaves it activates to determine whether leaves are fresh or stale. -* Send an `OverseerSignal::ActiveLeavesUpdate` message to all subsystems containing all activated and deactivated leaves. +* Apply the block import event to the active leaves. A new block should lead to its addition to the active leaves set + and its parent being deactivated. +* Mark any stale leaves as stale. The overseer should track all leaves it activates to determine whether leaves are + fresh or stale. +* Send an `OverseerSignal::ActiveLeavesUpdate` message to all subsystems containing all activated and deactivated + leaves. * Ensure all `ActiveLeavesUpdate` messages are flushed before resuming activity as a message router. -> TODO: in the future, we may want to avoid building on too many sibling blocks at once. the notion of a "preferred head" among many competing sibling blocks would imply changes in our "active leaves" update rules here +> TODO: in the future, we may want to avoid building on too many sibling blocks at once. the notion of a "preferred +> head" among many competing sibling blocks would imply changes in our "active leaves" update rules here ## On Finalization Event @@ -54,11 +71,16 @@ The overseer's logic can be described with these functions: ## On Subsystem Failure -Subsystems are essential tasks meant to run as long as the node does. Subsystems can spawn ephemeral work in the form of jobs, but the subsystems themselves should not go down. If a subsystem goes down, it will be because of a critical error that should take the entire node down as well. +Subsystems are essential tasks meant to run as long as the node does. Subsystems can spawn ephemeral work in the form of +jobs, but the subsystems themselves should not go down. If a subsystem goes down, it will be because of a critical error +that should take the entire node down as well. ## Communication Between Subsystems -When a subsystem wants to communicate with another subsystem, or, more typically, a job within a subsystem wants to communicate with its counterpart under another subsystem, that communication must happen via the overseer. Consider this example where a job on subsystem A wants to send a message to its counterpart under subsystem B. This is a realistic scenario, where you can imagine that both jobs correspond to work under the same relay-parent. +When a subsystem wants to communicate with another subsystem, or, more typically, a job within a subsystem wants to +communicate with its counterpart under another subsystem, that communication must happen via the overseer. Consider this +example where a job on subsystem A wants to send a message to its counterpart under subsystem B. This is a realistic +scenario, where you can imagine that both jobs correspond to work under the same relay-parent. ```text +--------+ +--------+ @@ -78,21 +100,48 @@ When a subsystem wants to communicate with another subsystem, or, more typically +------------------------------+ ``` -First, the subsystem that spawned a job is responsible for handling the first step of the communication. The overseer is not aware of the hierarchy of tasks within any given subsystem and is only responsible for subsystem-to-subsystem communication. So the sending subsystem must pass on the message via the overseer to the receiving subsystem, in such a way that the receiving subsystem can further address the communication to one of its internal tasks, if necessary. - -This communication prevents a certain class of race conditions. When the Overseer determines that it is time for subsystems to begin working on top of a particular relay-parent, it will dispatch a `ActiveLeavesUpdate` message to all subsystems to do so, and those messages will be handled asynchronously by those subsystems. Some subsystems will receive those messsages before others, and it is important that a message sent by subsystem A after receiving `ActiveLeavesUpdate` message will arrive at subsystem B after its `ActiveLeavesUpdate` message. If subsystem A maintained an independent channel with subsystem B to communicate, it would be possible for subsystem B to handle the side message before the `ActiveLeavesUpdate` message, but it wouldn't have any logical course of action to take with the side message - leading to it being discarded or improperly handled. Well-architectured state machines should have a single source of inputs, so that is what we do here. - -One exception is reasonable to make for responses to requests. A request should be made via the overseer in order to ensure that it arrives after any relevant `ActiveLeavesUpdate` message. A subsystem issuing a request as a result of a `ActiveLeavesUpdate` message can safely receive the response via a side-channel for two reasons: - -1. It's impossible for a request to be answered before it arrives, it is provable that any response to a request obeys the same ordering constraint. -1. The request was sent as a result of handling a `ActiveLeavesUpdate` message. Then there is no possible future in which the `ActiveLeavesUpdate` message has not been handled upon the receipt of the response. - -So as a single exception to the rule that all communication must happen via the overseer we allow the receipt of responses to requests via a side-channel, which may be established for that purpose. This simplifies any cases where the outside world desires to make a request to a subsystem, as the outside world can then establish a side-channel to receive the response on. - -It's important to note that the overseer is not aware of the internals of subsystems, and this extends to the jobs that they spawn. The overseer isn't aware of the existence or definition of those jobs, and is only aware of the outer subsystems with which it interacts. This gives subsystem implementations leeway to define internal jobs as they see fit, and to wrap a more complex hierarchy of state machines than having a single layer of jobs for relay-parent-based work. Likewise, subsystems aren't required to spawn jobs. Certain types of subsystems, such as those for shared storage or networking resources, won't perform block-based work but would still benefit from being on the Overseer's message bus. These subsystems can just ignore the overseer's signals for block-based work. - -Furthermore, the protocols by which subsystems communicate with each other should be well-defined irrespective of the implementation of the subsystem. In other words, their interface should be distinct from their implementation. This will prevent subsystems from accessing aspects of each other that are beyond the scope of the communication boundary. +First, the subsystem that spawned a job is responsible for handling the first step of the communication. The overseer is +not aware of the hierarchy of tasks within any given subsystem and is only responsible for subsystem-to-subsystem +communication. So the sending subsystem must pass on the message via the overseer to the receiving subsystem, in such a +way that the receiving subsystem can further address the communication to one of its internal tasks, if necessary. + +This communication prevents a certain class of race conditions. When the Overseer determines that it is time for +subsystems to begin working on top of a particular relay-parent, it will dispatch a `ActiveLeavesUpdate` message to all +subsystems to do so, and those messages will be handled asynchronously by those subsystems. Some subsystems will receive +those messsages before others, and it is important that a message sent by subsystem A after receiving +`ActiveLeavesUpdate` message will arrive at subsystem B after its `ActiveLeavesUpdate` message. If subsystem A +maintained an independent channel with subsystem B to communicate, it would be possible for subsystem B to handle the +side message before the `ActiveLeavesUpdate` message, but it wouldn't have any logical course of action to take with the +side message - leading to it being discarded or improperly handled. Well-architectured state machines should have a +single source of inputs, so that is what we do here. + +One exception is reasonable to make for responses to requests. A request should be made via the overseer in order to +ensure that it arrives after any relevant `ActiveLeavesUpdate` message. A subsystem issuing a request as a result of a +`ActiveLeavesUpdate` message can safely receive the response via a side-channel for two reasons: + +1. It's impossible for a request to be answered before it arrives, it is provable that any response to a request obeys + the same ordering constraint. +1. The request was sent as a result of handling a `ActiveLeavesUpdate` message. Then there is no possible future in + which the `ActiveLeavesUpdate` message has not been handled upon the receipt of the response. + +So as a single exception to the rule that all communication must happen via the overseer we allow the receipt of +responses to requests via a side-channel, which may be established for that purpose. This simplifies any cases where the +outside world desires to make a request to a subsystem, as the outside world can then establish a side-channel to +receive the response on. + +It's important to note that the overseer is not aware of the internals of subsystems, and this extends to the jobs that +they spawn. The overseer isn't aware of the existence or definition of those jobs, and is only aware of the outer +subsystems with which it interacts. This gives subsystem implementations leeway to define internal jobs as they see fit, +and to wrap a more complex hierarchy of state machines than having a single layer of jobs for relay-parent-based work. +Likewise, subsystems aren't required to spawn jobs. Certain types of subsystems, such as those for shared storage or +networking resources, won't perform block-based work but would still benefit from being on the Overseer's message bus. +These subsystems can just ignore the overseer's signals for block-based work. + +Furthermore, the protocols by which subsystems communicate with each other should be well-defined irrespective of the +implementation of the subsystem. In other words, their interface should be distinct from their implementation. This will +prevent subsystems from accessing aspects of each other that are beyond the scope of the communication boundary. ## On shutdown -Send an `OverseerSignal::Conclude` message to each subsystem and wait some time for them to conclude before hard-exiting. +Send an `OverseerSignal::Conclude` message to each subsystem and wait some time for them to conclude before +hard-exiting. diff --git a/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md b/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md index 6e3b4cd2d16..a3ca7347eb6 100644 --- a/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md +++ b/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md @@ -1,25 +1,66 @@ # Subsystems and Jobs -In this section we define the notions of Subsystems and Jobs. These are guidelines for how we will employ an architecture of hierarchical state machines. We'll have a top-level state machine which oversees the next level of state machines which oversee another layer of state machines and so on. The next sections will lay out these guidelines for what we've called subsystems and jobs, since this model applies to many of the tasks that the Node-side behavior needs to encompass, but these are only guidelines and some Subsystems may have deeper hierarchies internally. - -Subsystems are long-lived worker tasks that are in charge of performing some particular kind of work. All subsystems can communicate with each other via a well-defined protocol. Subsystems can't generally communicate directly, but must coordinate communication through an [Overseer](overseer.md), which is responsible for relaying messages, handling subsystem failures, and dispatching work signals. - -Most work that happens on the Node-side is related to building on top of a specific relay-chain block, which is contextually known as the "relay parent". We call it the relay parent to explicitly denote that it is a block in the relay chain and not on a parachain. We refer to the parent because when we are in the process of building a new block, we don't know what that new block is going to be. The parent block is our only stable point of reference, even though it is usually only useful when it is not yet a parent but in fact a leaf of the block-DAG expected to soon become a parent (because validators are authoring on top of it). Furthermore, we are assuming a forkful blockchain-extension protocol, which means that there may be multiple possible children of the relay-parent. Even if the relay parent has multiple children blocks, the parent of those children is the same, and the context in which those children is authored should be the same. The parent block is the best and most stable reference to use for defining the scope of work items and messages, and is typically referred to by its cryptographic hash. - -Since this goal of determining when to start and conclude work relative to a specific relay-parent is common to most, if not all subsystems, it is logically the job of the Overseer to distribute those signals as opposed to each subsystem duplicating that effort, potentially being out of synchronization with each other. Subsystem A should be able to expect that subsystem B is working on the same relay-parents as it is. One of the Overseer's tasks is to provide this heartbeat, or synchronized rhythm, to the system. - -The work that subsystems spawn to be done on a specific relay-parent is known as a job. Subsystems should set up and tear down jobs according to the signals received from the overseer. Subsystems may share or cache state between jobs. - -Subsystems must be robust to spurious exits. The outputs of the set of subsystems as a whole comprises of signed messages and data committed to disk. Care must be taken to avoid issuing messages that are not substantiated. Since subsystems need to be safe under spurious exits, it is the expected behavior that an `OverseerSignal::Conclude` can just lead to breaking the loop and exiting directly as opposed to waiting for everything to shut down gracefully. +In this section we define the notions of Subsystems and Jobs. These are +guidelines for how we will employ an architecture of hierarchical state +machines. We'll have a top-level state machine which oversees the next level of +state machines which oversee another layer of state machines and so on. The next +sections will lay out these guidelines for what we've called subsystems and +jobs, since this model applies to many of the tasks that the Node-side behavior +needs to encompass, but these are only guidelines and some Subsystems may have +deeper hierarchies internally. + +Subsystems are long-lived worker tasks that are in charge of performing some +particular kind of work. All subsystems can communicate with each other via a +well-defined protocol. Subsystems can't generally communicate directly, but must +coordinate communication through an [Overseer](overseer.md), which is +responsible for relaying messages, handling subsystem failures, and dispatching +work signals. + +Most work that happens on the Node-side is related to building on top of a +specific relay-chain block, which is contextually known as the "relay parent". +We call it the relay parent to explicitly denote that it is a block in the relay +chain and not on a parachain. We refer to the parent because when we are in the +process of building a new block, we don't know what that new block is going to +be. The parent block is our only stable point of reference, even though it is +usually only useful when it is not yet a parent but in fact a leaf of the +block-DAG expected to soon become a parent (because validators are authoring on +top of it). Furthermore, we are assuming a forkful blockchain-extension +protocol, which means that there may be multiple possible children of the +relay-parent. Even if the relay parent has multiple children blocks, the parent +of those children is the same, and the context in which those children is +authored should be the same. The parent block is the best and most stable +reference to use for defining the scope of work items and messages, and is +typically referred to by its cryptographic hash. + +Since this goal of determining when to start and conclude work relative to a +specific relay-parent is common to most, if not all subsystems, it is logically +the job of the Overseer to distribute those signals as opposed to each subsystem +duplicating that effort, potentially being out of synchronization with each +other. Subsystem A should be able to expect that subsystem B is working on the +same relay-parents as it is. One of the Overseer's tasks is to provide this +heartbeat, or synchronized rhythm, to the system. + +The work that subsystems spawn to be done on a specific relay-parent is known as +a job. Subsystems should set up and tear down jobs according to the signals +received from the overseer. Subsystems may share or cache state between jobs. + +Subsystems must be robust to spurious exits. The outputs of the set of +subsystems as a whole comprises of signed messages and data committed to disk. +Care must be taken to avoid issuing messages that are not substantiated. Since +subsystems need to be safe under spurious exits, it is the expected behavior +that an `OverseerSignal::Conclude` can just lead to breaking the loop and +exiting directly as opposed to waiting for everything to shut down gracefully. ## Subsystem Message Traffic Which subsystems send messages to which other subsystems. -**Note**: This diagram omits the overseer for simplicity. In fact, all messages are relayed via the overseer. +**Note**: This diagram omits the overseer for simplicity. In fact, all messages +are relayed via the overseer. -**Note**: Messages with a filled diamond arrowhead ("♦") include a `oneshot::Sender` which communicates a response from the recipient. -Messages with an open triangle arrowhead ("Δ") do not include a return sender. +**Note**: Messages with a filled diamond arrowhead ("♦") include a +`oneshot::Sender` which communicates a response from the recipient. Messages +with an open triangle arrowhead ("Δ") do not include a return sender. ```dot process digraph { @@ -125,14 +166,17 @@ digraph { ## The Path to Inclusion (Node Side) -Let's contextualize that diagram a bit by following a parachain block from its creation through finalization. -Parachains can use completely arbitrary processes to generate blocks. The relay chain doesn't know or care about -the details; each parachain just needs to provide a [collator](collators/collation-generation.md). +Let's contextualize that diagram a bit by following a parachain block from its +creation through finalization. Parachains can use completely arbitrary processes +to generate blocks. The relay chain doesn't know or care about the details; each +parachain just needs to provide a [collator](collators/collation-generation.md). -**Note**: Inter-subsystem communications are relayed via the overseer, but that step is omitted here for brevity. +**Note**: Inter-subsystem communications are relayed via the overseer, but that +step is omitted here for brevity. -**Note**: Dashed lines indicate a request/response cycle, where the response is communicated asynchronously via -a oneshot channel. Adjacent dashed lines may be processed in parallel. +**Note**: Dashed lines indicate a request/response cycle, where the response is +communicated asynchronously via a oneshot channel. Adjacent dashed lines may be +processed in parallel. ```mermaid sequenceDiagram @@ -156,11 +200,13 @@ sequenceDiagram end ``` -The `DistributeCollation` messages that `CollationGeneration` sends to the `CollatorProtocol` contains -two items: a `CandidateReceipt` and `PoV`. The `CollatorProtocol` is then responsible for distributing -that collation to interested validators. However, not all potential collations are of interest. The -`CandidateSelection` subsystem is responsible for determining which collations are interesting, before -`CollatorProtocol` actually fetches the collation. +The `DistributeCollation` messages that `CollationGeneration` sends to the +`CollatorProtocol` contains two items: a `CandidateReceipt` and `PoV`. The +`CollatorProtocol` is then responsible for distributing that collation to +interested validators. However, not all potential collations are of interest. +The `CandidateSelection` subsystem is responsible for determining which +collations are interesting, before `CollatorProtocol` actually fetches the +collation. ```mermaid sequenceDiagram @@ -205,10 +251,11 @@ sequenceDiagram end ``` -Assuming we hit the happy path, flow continues with `CandidateSelection` receiving a `(candidate_receipt, pov)` as -the return value from its -`FetchCollation` request. The only time `CandidateSelection` actively requests a collation is when -it hasn't yet seconded one for some `relay_parent`, and is ready to second. +Assuming we hit the happy path, flow continues with `CandidateSelection` +receiving a `(candidate_receipt, pov)` as the return value from its +`FetchCollation` request. The only time `CandidateSelection` actively requests a +collation is when it hasn't yet seconded one for some `relay_parent`, and is +ready to second. ```mermaid sequenceDiagram @@ -243,15 +290,17 @@ sequenceDiagram end ``` -At this point, you'll see that control flows in two directions: to `StatementDistribution` to distribute -the `SignedStatement`, and to `PoVDistribution` to distribute the `PoV`. However, that's largely a mirage: -while the initial implementation distributes `PoV`s by gossip, that's inefficient, and will be replaced -with a system which fetches `PoV`s only when actually necessary. +At this point, you'll see that control flows in two directions: to +`StatementDistribution` to distribute the `SignedStatement`, and to +`PoVDistribution` to distribute the `PoV`. However, that's largely a mirage: +while the initial implementation distributes `PoV`s by gossip, that's +inefficient, and will be replaced with a system which fetches `PoV`s only when +actually necessary. > TODO: figure out more precisely the current status and plans; write them up -Therefore, we'll follow the `SignedStatement`. The `StatementDistribution` subsystem is largely concerned -with implementing a gossip protocol: +Therefore, we'll follow the `SignedStatement`. The `StatementDistribution` +subsystem is largely concerned with implementing a gossip protocol: ```mermaid sequenceDiagram @@ -278,8 +327,8 @@ sequenceDiagram end ``` -But who are these `Listener`s who've asked to be notified about incoming `SignedStatement`s? -Nobody, as yet. +But who are these `Listener`s who've asked to be notified about incoming +`SignedStatement`s? Nobody, as yet. Let's pick back up with the PoV Distribution subsystem. @@ -305,11 +354,13 @@ sequenceDiagram Note over PD,NB: On receipt of a network PoV, PovDistribution forwards it to each Listener.
It also penalizes bad gossipers. ``` -Unlike in the case of `StatementDistribution`, there is another subsystem which in various circumstances -already registers a listener to be notified when a new `PoV` arrives: `CandidateBacking`. Note that this -is the second time that `CandidateBacking` has gotten involved. The first instance was from the perspective -of the validator choosing to second a candidate via its `CandidateSelection` subsystem. This time, it's -from the perspective of some other validator, being informed that this foreign `PoV` has been received. +Unlike in the case of `StatementDistribution`, there is another subsystem which +in various circumstances already registers a listener to be notified when a new +`PoV` arrives: `CandidateBacking`. Note that this is the second time that +`CandidateBacking` has gotten involved. The first instance was from the +perspective of the validator choosing to second a candidate via its +`CandidateSelection` subsystem. This time, it's from the perspective of some +other validator, being informed that this foreign `PoV` has been received. ```mermaid sequenceDiagram @@ -326,10 +377,11 @@ sequenceDiagram CB ->> AS: StoreAvailableData ``` -At this point, things have gone a bit nonlinear. Let's pick up the thread again with `BitfieldSigning`. As -the `Overseer` activates each relay parent, it starts a `BitfieldSigningJob` which operates on an extremely -simple metric: after creation, it immediately goes to sleep for 1.5 seconds. On waking, it records the state -of the world pertaining to availability at that moment. +At this point, things have gone a bit nonlinear. Let's pick up the thread again +with `BitfieldSigning`. As the `Overseer` activates each relay parent, it starts +a `BitfieldSigningJob` which operates on an extremely simple metric: after +creation, it immediately goes to sleep for 1.5 seconds. On waking, it records +the state of the world pertaining to availability at that moment. ```mermaid sequenceDiagram @@ -350,9 +402,10 @@ sequenceDiagram end ``` -`BitfieldDistribution` is, like the other `*Distribution` subsystems, primarily interested in implementing -a peer-to-peer gossip network propagating its particular messages. However, it also serves as an essential -relay passing the message along. +`BitfieldDistribution` is, like the other `*Distribution` subsystems, primarily +interested in implementing a peer-to-peer gossip network propagating its +particular messages. However, it also serves as an essential relay passing the +message along. ```mermaid sequenceDiagram @@ -366,12 +419,14 @@ sequenceDiagram BD ->> NB: SendValidationMessage::BitfieldDistribution::Bitfield ``` -We've now seen the message flow to the `Provisioner`: both `CandidateBacking` and `BitfieldDistribution` -contribute provisionable data. Now, let's look at that subsystem. +We've now seen the message flow to the `Provisioner`: both `CandidateBacking` +and `BitfieldDistribution` contribute provisionable data. Now, let's look at +that subsystem. -Much like the `BitfieldSigning` subsystem, the `Provisioner` creates a new job for each newly-activated -leaf, and starts a timer. Unlike `BitfieldSigning`, we won't depict that part of the process, because -the `Provisioner` also has other things going on. +Much like the `BitfieldSigning` subsystem, the `Provisioner` creates a new job +for each newly-activated leaf, and starts a timer. Unlike `BitfieldSigning`, we +won't depict that part of the process, because the `Provisioner` also has other +things going on. ```mermaid sequenceDiagram @@ -411,8 +466,9 @@ sequenceDiagram end ``` -In principle, any arbitrary subsystem could send a `RequestInherentData` to the `Provisioner`. In practice, -only the `ParachainsInherentDataProvider` does so. +In principle, any arbitrary subsystem could send a `RequestInherentData` to the +`Provisioner`. In practice, only the `ParachainsInherentDataProvider` does so. -The tuple `(SignedAvailabilityBitfields, BackedCandidates, ParentHeader)` is injected by the `ParachainsInherentDataProvider` -into the inherent data. From that point on, control passes from the node to the runtime. +The tuple `(SignedAvailabilityBitfields, BackedCandidates, ParentHeader)` is +injected by the `ParachainsInherentDataProvider` into the inherent data. From +that point on, control passes from the node to the runtime. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/availability-store.md b/polkadot/roadmap/implementers-guide/src/node/utility/availability-store.md index bd61455934e..71d3f324523 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/availability-store.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/availability-store.md @@ -9,13 +9,20 @@ The two data types: For each of these data we have pruning rules that determine how long we need to keep that data available. -PoV hypothetically only need to be kept around until the block where the data was made fully available is finalized. However, disputes can revert finality, so we need to be a bit more conservative and we add a delay. We should keep the PoV until a block that finalized availability of it has been finalized for 1 day + 1 hour. +PoV hypothetically only need to be kept around until the block where the data was made fully available is finalized. +However, disputes can revert finality, so we need to be a bit more conservative and we add a delay. We should keep the +PoV until a block that finalized availability of it has been finalized for 1 day + 1 hour. -Availability chunks need to be kept available until the dispute period for the corresponding candidate has ended. We can accomplish this by using the same criterion as the above. This gives us a pruning condition of the block finalizing availability of the chunk being final for 1 day + 1 hour. +Availability chunks need to be kept available until the dispute period for the corresponding candidate has ended. We can +accomplish this by using the same criterion as the above. This gives us a pruning condition of the block finalizing +availability of the chunk being final for 1 day + 1 hour. -There is also the case where a validator commits to make a PoV available, but the corresponding candidate is never backed. In this case, we keep the PoV available for 1 hour. +There is also the case where a validator commits to make a PoV available, but the corresponding candidate is never +backed. In this case, we keep the PoV available for 1 hour. -There may be multiple competing blocks all ending the availability phase for a particular candidate. Until finality, it will be unclear which of those is actually the canonical chain, so the pruning records for PoVs and Availability chunks should keep track of all such blocks. +There may be multiple competing blocks all ending the availability phase for a particular candidate. Until finality, it +will be unclear which of those is actually the canonical chain, so the pruning records for PoVs and Availability chunks +should keep track of all such blocks. ## Lifetime of the block data and chunks in storage @@ -44,7 +51,8 @@ We use an underlying Key-Value database where we assume we have the following op - `write(key, value)` - `read(key) -> Option` -- `iter_with_prefix(prefix) -> Iterator<(key, value)>` - gives all keys and values in lexicographical order where the key starts with `prefix`. +- `iter_with_prefix(prefix) -> Iterator<(key, value)>` - gives all keys and values in lexicographical order where the + key starts with `prefix`. We use this database to encode the following schema: @@ -57,7 +65,8 @@ We use this database to encode the following schema: ("prune_by_time", Timestamp, CandidateHash) -> Option<()> ``` -Timestamps are the wall-clock seconds since Unix epoch. Timestamps and block numbers are both encoded as big-endian so lexicographic order is ascending. +Timestamps are the wall-clock seconds since Unix epoch. Timestamps and block numbers are both encoded as big-endian so +lexicographic order is ascending. The meta information that we track per-candidate is defined as the `CandidateMeta` struct @@ -80,9 +89,12 @@ enum State { } ``` -We maintain the invariant that if a candidate has a meta entry, its available data exists on disk if `data_available` is true. All chunks mentioned in the meta entry are available. +We maintain the invariant that if a candidate has a meta entry, its available data exists on disk if `data_available` is +true. All chunks mentioned in the meta entry are available. -Additionally, there is exactly one `prune_by_time` entry which holds the candidate hash unless the state is `Unfinalized`. There may be zero, one, or many "unfinalized" keys with the given candidate, and this will correspond to the `state` of the meta entry. +Additionally, there is exactly one `prune_by_time` entry which holds the candidate hash unless the state is +`Unfinalized`. There may be zero, one, or many "unfinalized" keys with the given candidate, and this will correspond to +the `state` of the meta entry. ## Protocol @@ -96,9 +108,15 @@ Output: For each head in the `activated` list: -- Load all ancestors of the head back to the finalized block so we don't miss anything if import notifications are missed. If a `StoreChunk` message is received for a candidate which has no entry, then we will prematurely lose the data. -- Note any new candidates backed in the head. Update the `CandidateMeta` for each. If the `CandidateMeta` does not exist, create it as `Unavailable` with the current timestamp. Register a `"prune_by_time"` entry based on the current timestamp + 1 hour. -- Note any new candidate included in the head. Update the `CandidateMeta` for each, performing a transition from `Unavailable` to `Unfinalized` if necessary. That includes removing the `"prune_by_time"` entry. Add the head hash and number to the state, if unfinalized. Add an `"unfinalized"` entry for the block and candidate. +- Load all ancestors of the head back to the finalized block so we don't miss anything if import notifications are + missed. If a `StoreChunk` message is received for a candidate which has no entry, then we will prematurely lose the + data. +- Note any new candidates backed in the head. Update the `CandidateMeta` for each. If the `CandidateMeta` does not + exist, create it as `Unavailable` with the current timestamp. Register a `"prune_by_time"` entry based on the current + timestamp + 1 hour. +- Note any new candidate included in the head. Update the `CandidateMeta` for each, performing a transition from + `Unavailable` to `Unfinalized` if necessary. That includes removing the `"prune_by_time"` entry. Add the head hash and + number to the state, if unfinalized. Add an `"unfinalized"` entry for the block and candidate. - The `CandidateEvent` runtime API can be used for this purpose. On `OverseerSignal::BlockFinalized(finalized)` events: @@ -106,17 +124,22 @@ On `OverseerSignal::BlockFinalized(finalized)` events: - for each key in `iter_with_prefix("unfinalized")` - Stop if the key is beyond `("unfinalized, finalized)` - For each block number f that we encounter, load the finalized hash for that block. - - The state of each `CandidateMeta` we encounter here must be `Unfinalized`, since we loaded the candidate from an `"unfinalized"` key. + - The state of each `CandidateMeta` we encounter here must be `Unfinalized`, since we loaded the candidate from an + `"unfinalized"` key. - For each candidate that we encounter under `f` and the finalized block hash, - - Update the `CandidateMeta` to have `State::Finalized`. Remove all `"unfinalized"` entries from the old `Unfinalized` state. + - Update the `CandidateMeta` to have `State::Finalized`. Remove all `"unfinalized"` entries from the old + `Unfinalized` state. - Register a `"prune_by_time"` entry for the candidate based on the current time + 1 day + 1 hour. - For each candidate that we encounter under `f` which is not under the finalized block hash, - Remove all entries under `f` in the `Unfinalized` state. - - If the `CandidateMeta` has state `Unfinalized` with an empty list of blocks, downgrade to `Unavailable` and re-schedule pruning under the timestamp + 1 hour. We do not prune here as the candidate still may be included in a descendant of the finalized chain. + - If the `CandidateMeta` has state `Unfinalized` with an empty list of blocks, downgrade to `Unavailable` and + re-schedule pruning under the timestamp + 1 hour. We do not prune here as the candidate still may be included in + a descendant of the finalized chain. - Remove all `"unfinalized"` keys under `f`. - Update `last_finalized` = finalized. - This is roughly `O(n * m)` where n is the number of blocks finalized since the last update, and `m` is the number of parachains. + This is roughly `O(n * m)` where n is the number of blocks finalized since the last update, and `m` is the number of + parachains. On `QueryAvailableData` message: @@ -139,7 +162,8 @@ On `QueryChunk` message: On `QueryAllChunks` message: - Query `("meta", candidate_hash)`. If `None`, send an empty response and return. -- For all `1` bits in the `chunks_stored`, query `("chunk", candidate_hash, index)`. Ignore but warn on errors, and return a vector of all loaded chunks. +- For all `1` bits in the `chunks_stored`, query `("chunk", candidate_hash, index)`. Ignore but warn on errors, and + return a vector of all loaded chunks. On `QueryChunkAvailability` message: @@ -149,14 +173,17 @@ On `QueryChunkAvailability` message: On `StoreChunk` message: -- If there is a `CandidateMeta` under the candidate hash, set the bit of the erasure-chunk in the `chunks_stored` bitfield to `1`. If it was not `1` already, write the chunk under `("chunk", candidate_hash, chunk_index)`. +- If there is a `CandidateMeta` under the candidate hash, set the bit of the erasure-chunk in the `chunks_stored` + bitfield to `1`. If it was not `1` already, write the chunk under `("chunk", candidate_hash, chunk_index)`. This is `O(n)` in the size of the chunk. On `StoreAvailableData` message: -- Compute the erasure root of the available data and compare it with `expected_erasure_root`. Return `StoreAvailableDataError::InvalidErasureRoot` on mismatch. -- If there is no `CandidateMeta` under the candidate hash, create it with `State::Unavailable(now)`. Load the `CandidateMeta` otherwise. +- Compute the erasure root of the available data and compare it with `expected_erasure_root`. Return + `StoreAvailableDataError::InvalidErasureRoot` on mismatch. +- If there is no `CandidateMeta` under the candidate hash, create it with `State::Unavailable(now)`. Load the + `CandidateMeta` otherwise. - Store `data` under `("available", candidate_hash)` and set `data_available` to true. - Store each chunk under `("chunk", candidate_hash, index)` and set every bit in `chunks_stored` to `1`. @@ -172,12 +199,13 @@ Every 5 minutes, run a pruning routine: - For each erasure chunk bit set, remove `("chunk", candidate_hash, bit_index)`. - If `data_available`, remove `("available", candidate_hash)` - This is O(n * m) in the amount of candidates and average size of the data stored. This is probably the most expensive operation but does not need - to be run very often. + This is O(n * m) in the amount of candidates and average size of the data stored. This is probably the most expensive + operation but does not need to be run very often. ## Basic scenarios to test -Basically we need to test the correctness of data flow through state FSMs described earlier. These tests obviously assume that some mocking of time is happening. +Basically we need to test the correctness of data flow through state FSMs described earlier. These tests obviously +assume that some mocking of time is happening. - Stored data that is never included pruned in necessary timeout - A block (and/or a chunk) is added to the store. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md index 4a1d02be556..376fa187de1 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md @@ -2,7 +2,8 @@ This subsystem is responsible for handling candidate validation requests. It is a simple request/response server. -A variety of subsystems want to know if a parachain block candidate is valid. None of them care about the detailed mechanics of how a candidate gets validated, just the results. This subsystem handles those details. +A variety of subsystems want to know if a parachain block candidate is valid. None of them care about the detailed +mechanics of how a candidate gets validated, just the results. This subsystem handles those details. ## Protocol @@ -12,35 +13,53 @@ Output: Validation result via the provided response side-channel. ## Functionality -This subsystem groups the requests it handles in two categories: *candidate validation* and *PVF pre-checking*. +This subsystem groups the requests it handles in two categories: *candidate validation* and *PVF pre-checking*. -The first category can be further subdivided in two request types: one which draws out validation data from the state, and another which accepts all validation data exhaustively. Validation returns three possible outcomes on the response channel: the candidate is valid, the candidate is invalid, or an internal error occurred. +The first category can be further subdivided in two request types: one which draws out validation data from the state, +and another which accepts all validation data exhaustively. Validation returns three possible outcomes on the response +channel: the candidate is valid, the candidate is invalid, or an internal error occurred. -Parachain candidates are validated against their validation function: A piece of Wasm code that describes the state-transition of the parachain. Validation function execution is not metered. This means that an execution which is an infinite loop or simply takes too long must be forcibly exited by some other means. For this reason, we recommend dispatching candidate validation to be done on subprocesses which can be killed if they time-out. +Parachain candidates are validated against their validation function: A piece of Wasm code that describes the +state-transition of the parachain. Validation function execution is not metered. This means that an execution which is +an infinite loop or simply takes too long must be forcibly exited by some other means. For this reason, we recommend +dispatching candidate validation to be done on subprocesses which can be killed if they time-out. -Upon receiving a validation request, the first thing the candidate validation subsystem should do is make sure it has all the necessary parameters to the validation function. These are: +Upon receiving a validation request, the first thing the candidate validation subsystem should do is make sure it has +all the necessary parameters to the validation function. These are: * The Validation Function itself. * The [`CandidateDescriptor`](../../types/candidate.md#candidatedescriptor). * The [`ValidationData`](../../types/candidate.md#validationdata). * The [`PoV`](../../types/availability.md#proofofvalidity). -The second category is for PVF pre-checking. This is primarly used by the [PVF pre-checker](pvf-prechecker.md) subsystem. +The second category is for PVF pre-checking. This is primarly used by the [PVF pre-checker](pvf-prechecker.md) +subsystem. ### Determining Parameters For a [`CandidateValidationMessage`][CVM]`::ValidateFromExhaustive`, these parameters are exhaustively provided. -For a [`CandidateValidationMessage`][CVM]`::ValidateFromChainState`, some more work needs to be done. Due to the uncertainty of Availability Cores (implemented in the [`Scheduler`](../../runtime/scheduler.md) module of the runtime), a candidate at a particular relay-parent and for a particular para may have two different valid validation-data to be executed under depending on what is assumed to happen if the para is occupying a core at the onset of the new block. This is encoded as an `OccupiedCoreAssumption` in the runtime API. +For a [`CandidateValidationMessage`][CVM]`::ValidateFromChainState`, some more work needs to be done. Due to the +uncertainty of Availability Cores (implemented in the [`Scheduler`](../../runtime/scheduler.md) module of the runtime), +a candidate at a particular relay-parent and for a particular para may have two different valid validation-data to be +executed under depending on what is assumed to happen if the para is occupying a core at the onset of the new block. +This is encoded as an `OccupiedCoreAssumption` in the runtime API. -The way that we can determine which assumption the candidate is meant to be executed under is simply to do an exhaustive check of both possibilities based on the state of the relay-parent. First we fetch the validation data under the assumption that the block occupying becomes available. If the `validation_data_hash` of the `CandidateDescriptor` matches this validation data, we use that. Otherwise, if the `validation_data_hash` matches the validation data fetched under the `TimedOut` assumption, we use that. Otherwise, we return a `ValidationResult::Invalid` response and conclude. +The way that we can determine which assumption the candidate is meant to be executed under is simply to do an exhaustive +check of both possibilities based on the state of the relay-parent. First we fetch the validation data under the +assumption that the block occupying becomes available. If the `validation_data_hash` of the `CandidateDescriptor` +matches this validation data, we use that. Otherwise, if the `validation_data_hash` matches the validation data fetched +under the `TimedOut` assumption, we use that. Otherwise, we return a `ValidationResult::Invalid` response and conclude. -Then, we can fetch the validation code from the runtime based on which type of candidate this is. This gives us all the parameters. The descriptor and PoV come from the request itself, and the other parameters have been derived from the state. +Then, we can fetch the validation code from the runtime based on which type of candidate this is. This gives us all the +parameters. The descriptor and PoV come from the request itself, and the other parameters have been derived from the +state. > TODO: This would be a great place for caching to avoid making lots of runtime requests. That would need a job, though. ### Execution of the Parachain Wasm -Once we have all parameters, we can spin up a background task to perform the validation in a way that doesn't hold up the entire event loop. Before invoking the validation function itself, this should first do some basic checks: +Once we have all parameters, we can spin up a background task to perform the validation in a way that doesn't hold up +the entire event loop. Before invoking the validation function itself, this should first do some basic checks: * The collator signature is valid * The PoV provided matches the `pov_hash` field of the descriptor @@ -48,6 +67,8 @@ For more details please see [PVF Host and Workers](pvf-host-and-workers.md). ### Checking Validation Outputs -If we can assume the presence of the relay-chain state (that is, during processing [`CandidateValidationMessage`][CVM]`::ValidateFromChainState`) we can run all the checks that the relay-chain would run at the inclusion time thus confirming that the candidate will be accepted. +If we can assume the presence of the relay-chain state (that is, during processing +[`CandidateValidationMessage`][CVM]`::ValidateFromChainState`) we can run all the checks that the relay-chain would run +at the inclusion time thus confirming that the candidate will be accepted. [CVM]: ../../types/overseer-protocol.md#validationrequesttype diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md b/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md index e9ef9b5695b..aab4f2d5cb5 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md @@ -1,6 +1,7 @@ # Chain API -The Chain API subsystem is responsible for providing a single point of access to chain state data via a set of pre-determined queries. +The Chain API subsystem is responsible for providing a single point of access to chain state data via a set of +pre-determined queries. ## Protocol @@ -10,7 +11,8 @@ Output: None ## Functionality -On receipt of `ChainApiMessage`, answer the request and provide the response to the side-channel embedded within the request. +On receipt of `ChainApiMessage`, answer the request and provide the response to the side-channel embedded within the +request. Currently, the following requests are supported: * Block hash to number diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/chain-selection.md b/polkadot/roadmap/implementers-guide/src/node/utility/chain-selection.md index 640691e5596..1d1358b228b 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/chain-selection.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/chain-selection.md @@ -1,8 +1,12 @@ # Chain Selection Subsystem -This subsystem implements the necessary metadata for the implementation of the [chain selection](../../protocol-chain-selection.md) portion of the protocol. +This subsystem implements the necessary metadata for the implementation of the [chain +selection](../../protocol-chain-selection.md) portion of the protocol. -The subsystem wraps a database component which maintains a view of the unfinalized chain and records the properties of each block: whether the block is **viable**, whether it is **stagnant**, and whether it is **reverted**. It should also maintain an updated set of active leaves in accordance with this view, which should be cheap to query. Leaves are ordered descending first by weight and then by block number. +The subsystem wraps a database component which maintains a view of the unfinalized chain and records the properties of +each block: whether the block is **viable**, whether it is **stagnant**, and whether it is **reverted**. It should also +maintain an updated set of active leaves in accordance with this view, which should be cheap to query. Leaves are +ordered descending first by weight and then by block number. This subsystem needs to update its information on the unfinalized chain: * On every leaf-activated signal @@ -11,32 +15,47 @@ This subsystem needs to update its information on the unfinalized chain: * On every `ChainSelectionMessage::RevertBlocks` * Periodically, to detect stagnation. -Simple implementations of these updates do `O(n_unfinalized_blocks)` disk operations. If the amount of unfinalized blocks is relatively small, the updates should not take very much time. However, in cases where there are hundreds or thousands of unfinalized blocks the naive implementations of these update algorithms would have to be replaced with more sophisticated versions. +Simple implementations of these updates do `O(n_unfinalized_blocks)` disk operations. If the amount of unfinalized +blocks is relatively small, the updates should not take very much time. However, in cases where there are hundreds or +thousands of unfinalized blocks the naive implementations of these update algorithms would have to be replaced with more +sophisticated versions. -### `OverseerSignal::ActiveLeavesUpdate` +## `OverseerSignal::ActiveLeavesUpdate` -Determine all new blocks implicitly referenced by any new active leaves and add them to the view. Update the set of viable leaves accordingly. The weights of imported blocks can be determined by the [`ChainApiMessage::BlockWeight`](../../types/overseer-protocol.md#chain-api-message). +Determine all new blocks implicitly referenced by any new active leaves and add them to the view. Update the set of +viable leaves accordingly. The weights of imported blocks can be determined by the +[`ChainApiMessage::BlockWeight`](../../types/overseer-protocol.md#chain-api-message). -### `OverseerSignal::BlockFinalized` +## `OverseerSignal::BlockFinalized` -Delete data for all orphaned chains and update all metadata descending from the new finalized block accordingly, along with the set of viable leaves. Note that finalizing a **reverted** or **stagnant** block means that the descendants of those blocks may lose that status because the definitions of those properties don't include the finalized chain. Update the set of viable leaves accordingly. +Delete data for all orphaned chains and update all metadata descending from the new finalized block accordingly, along +with the set of viable leaves. Note that finalizing a **reverted** or **stagnant** block means that the descendants of +those blocks may lose that status because the definitions of those properties don't include the finalized chain. Update +the set of viable leaves accordingly. -### `ChainSelectionMessage::Approved` +## `ChainSelectionMessage::Approved` -Update the approval status of the referenced block. If the block was stagnant and thus non-viable and is now viable, then the metadata of all of its descendants needs to be updated as well, as they may no longer be stagnant either. Update the set of viable leaves accordingly. +Update the approval status of the referenced block. If the block was stagnant and thus non-viable and is now viable, +then the metadata of all of its descendants needs to be updated as well, as they may no longer be stagnant either. +Update the set of viable leaves accordingly. -### `ChainSelectionMessage::Leaves` +## `ChainSelectionMessage::Leaves` -Gets all leaves of the chain, i.e. block hashes that are suitable to build upon and have no suitable children. Supplies the leaves in descending order by score. +Gets all leaves of the chain, i.e. block hashes that are suitable to build upon and have no suitable children. Supplies +the leaves in descending order by score. -### `ChainSelectionMessage::BestLeafContaining` +## `ChainSelectionMessage::BestLeafContaining` -If the required block is unknown or not viable, then return `None`. Iterate over all leaves in order of descending weight, returning the first leaf containing the required block in its chain, and `None` otherwise. +If the required block is unknown or not viable, then return `None`. Iterate over all leaves in order of descending +weight, returning the first leaf containing the required block in its chain, and `None` otherwise. -### `ChainSelectionMessage::RevertBlocks` -This message indicates that a dispute has concluded against a parachain block candidate. The message passes along a vector containing the block number and block hash of each block where the disputed candidate was included. The passed blocks will be marked as reverted, and their descendants will be marked as non-viable. +## `ChainSelectionMessage::RevertBlocks` +This message indicates that a dispute has concluded against a parachain block candidate. The message passes along a +vector containing the block number and block hash of each block where the disputed candidate was included. The passed +blocks will be marked as reverted, and their descendants will be marked as non-viable. -### Periodically +## Periodically -Detect stagnant blocks and apply the stagnant definition to all descendants. Update the set of viable leaves accordingly. +Detect stagnant blocks and apply the stagnant definition to all descendants. Update the set of viable leaves +accordingly. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/network-bridge.md b/polkadot/roadmap/implementers-guide/src/node/utility/network-bridge.md index 3245772d9d8..d2506fbe83e 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/network-bridge.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/network-bridge.md @@ -1,30 +1,43 @@ # Network Bridge -One of the main features of the overseer/subsystem duality is to avoid shared ownership of resources and to communicate via message-passing. However, implementing each networking subsystem as its own network protocol brings a fair share of challenges. - -The most notable challenge is coordinating and eliminating race conditions of peer connection and disconnection events. If we have many network protocols that peers are supposed to be connected on, it is difficult to enforce that a peer is indeed connected on all of them or the order in which those protocols receive notifications that peers have connected. This becomes especially difficult when attempting to share peer state across protocols. All of the Parachain-Host's gossip protocols eliminate DoS with a data-dependency on current chain heads. However, it is inefficient and confusing to implement the logic for tracking our current chain heads as well as our peers' on each of those subsystems. Having one subsystem for tracking this shared state and distributing it to the others is an improvement in architecture and efficiency. - -One other piece of shared state to track is peer reputation. When peers are found to have provided value or cost, we adjust their reputation accordingly. - -So in short, this Subsystem acts as a bridge between an actual network component and a subsystem's protocol. The implementation of the underlying network component is beyond the scope of this module. We make certain assumptions about the network component: - * The network allows registering of protocols and multiple versions of each protocol. - * The network handles version negotiation of protocols with peers and only connects the peer on the highest version of the protocol. - * Each protocol has its own peer-set, although there may be some overlap. - * The network provides peer-set management utilities for discovering the peer-IDs of validators and a means of dialing peers with given IDs. - - -The network bridge makes use of the peer-set feature, but is not generic over peer-set. Instead, it exposes two peer-sets that event producers can attach to: `Validation` and `Collation`. More information can be found on the documentation of the [`NetworkBridgeMessage`][NBM]. +One of the main features of the overseer/subsystem duality is to avoid shared ownership of resources and to communicate +via message-passing. However, implementing each networking subsystem as its own network protocol brings a fair share of +challenges. + +The most notable challenge is coordinating and eliminating race conditions of peer connection and disconnection events. +If we have many network protocols that peers are supposed to be connected on, it is difficult to enforce that a peer is +indeed connected on all of them or the order in which those protocols receive notifications that peers have connected. +This becomes especially difficult when attempting to share peer state across protocols. All of the Parachain-Host's +gossip protocols eliminate DoS with a data-dependency on current chain heads. However, it is inefficient and confusing +to implement the logic for tracking our current chain heads as well as our peers' on each of those subsystems. Having +one subsystem for tracking this shared state and distributing it to the others is an improvement in architecture and +efficiency. + +One other piece of shared state to track is peer reputation. When peers are found to have provided value or cost, we +adjust their reputation accordingly. + +So in short, this Subsystem acts as a bridge between an actual network component and a subsystem's protocol. The +implementation of the underlying network component is beyond the scope of this module. We make certain assumptions about +the network component: + - The network allows registering of protocols and multiple versions of each protocol. + - The network handles version negotiation of protocols with peers and only connects the peer on the highest version of + the protocol. + - Each protocol has its own peer-set, although there may be some overlap. + - The network provides peer-set management utilities for discovering the peer-IDs of validators and a means of dialing + peers with given IDs. + +The network bridge makes use of the peer-set feature, but is not generic over peer-set. Instead, it exposes two +peer-sets that event producers can attach to: `Validation` and `Collation`. More information can be found on the +documentation of the [`NetworkBridgeMessage`][NBM]. ## Protocol Input: [`NetworkBridgeMessage`][NBM] - -Output: - - [`ApprovalDistributionMessage`][AppD]`::NetworkBridgeUpdate` - - [`BitfieldDistributionMessage`][BitD]`::NetworkBridgeUpdate` - - [`CollatorProtocolMessage`][CollP]`::NetworkBridgeUpdate` - - [`StatementDistributionMessage`][StmtD]`::NetworkBridgeUpdate` +Output: - [`ApprovalDistributionMessage`][AppD]`::NetworkBridgeUpdate` - + [`BitfieldDistributionMessage`][BitD]`::NetworkBridgeUpdate` - + [`CollatorProtocolMessage`][CollP]`::NetworkBridgeUpdate` - + [`StatementDistributionMessage`][StmtD]`::NetworkBridgeUpdate` ## Functionality @@ -37,7 +50,8 @@ enum WireMessage { } ``` -and instantiates this type twice, once using the [`ValidationProtocolV1`][VP1] message type, and once with the [`CollationProtocolV1`][CP1] message type. +and instantiates this type twice, once using the [`ValidationProtocolV1`][VP1] message type, and once with the +[`CollationProtocolV1`][CP1] message type. ```rust type ValidationV1Message = WireMessage; @@ -46,17 +60,21 @@ type CollationV1Message = WireMessage; ### Startup -On startup, we register two protocols with the underlying network utility. One for validation and one for collation. We register only version 1 of each of these protocols. +On startup, we register two protocols with the underlying network utility. One for validation and one for collation. We +register only version 1 of each of these protocols. ### Main Loop -The bulk of the work done by this subsystem is in responding to network events, signals from the overseer, and messages from other subsystems. +The bulk of the work done by this subsystem is in responding to network events, signals from the overseer, and messages +from other subsystems. Each network event is associated with a particular peer-set. ### Overseer Signal: `ActiveLeavesUpdate` -The `activated` and `deactivated` lists determine the evolution of our local view over time. A `ProtocolMessage::ViewUpdate` is issued to each connected peer on each peer-set, and a `NetworkBridgeEvent::OurViewChange` is issued to each event handler for each protocol. +The `activated` and `deactivated` lists determine the evolution of our local view over time. A +`ProtocolMessage::ViewUpdate` is issued to each connected peer on each peer-set, and a +`NetworkBridgeEvent::OurViewChange` is issued to each event handler for each protocol. We only send view updates if the node has indicated that it has finished major blockchain synchronization. @@ -64,24 +82,31 @@ If we are connected to the same peer on both peer-sets, we will send the peer tw ### Overseer Signal: `BlockFinalized` -We update our view's `finalized_number` to the provided one and delay `ProtocolMessage::ViewUpdate` and `NetworkBridgeEvent::OurViewChange` till the next `ActiveLeavesUpdate`. +We update our view's `finalized_number` to the provided one and delay `ProtocolMessage::ViewUpdate` and +`NetworkBridgeEvent::OurViewChange` till the next `ActiveLeavesUpdate`. ### Network Event: `PeerConnected` -Issue a `NetworkBridgeEvent::PeerConnected` for each [Event Handler](#event-handlers) of the peer-set and negotiated protocol version of the peer. Also issue a `NetworkBridgeEvent::PeerViewChange` and send the peer our current view, but only if the node has indicated that it has finished major blockchain synchronization. Otherwise, we only send the peer an empty view. +Issue a `NetworkBridgeEvent::PeerConnected` for each [Event Handler](#event-handlers) of the peer-set and negotiated +protocol version of the peer. Also issue a `NetworkBridgeEvent::PeerViewChange` and send the peer our current view, but +only if the node has indicated that it has finished major blockchain synchronization. Otherwise, we only send the peer +an empty view. ### Network Event: `PeerDisconnected` -Issue a `NetworkBridgeEvent::PeerDisconnected` for each [Event Handler](#event-handlers) of the peer-set and negotiated protocol version of the peer. +Issue a `NetworkBridgeEvent::PeerDisconnected` for each [Event Handler](#event-handlers) of the peer-set and negotiated +protocol version of the peer. ### Network Event: `ProtocolMessage` -Map the message onto the corresponding [Event Handler](#event-handlers) based on the peer-set this message was received on and dispatch via overseer. +Map the message onto the corresponding [Event Handler](#event-handlers) based on the peer-set this message was received +on and dispatch via overseer. ### Network Event: `ViewUpdate` - Check that the new view is valid and note it as the most recent view update of the peer on this peer-set. -- Map a `NetworkBridgeEvent::PeerViewChange` onto the corresponding [Event Handler](#event-handlers) based on the peer-set this message was received on and dispatch via overseer. +- Map a `NetworkBridgeEvent::PeerViewChange` onto the corresponding [Event Handler](#event-handlers) based on the + peer-set this message was received on and dispatch via overseer. ### `ReportPeer` @@ -108,22 +133,23 @@ Map the message onto the corresponding [Event Handler](#event-handlers) based on ### `NewGossipTopology` -- Map all `AuthorityDiscoveryId`s to `PeerId`s and issue a corresponding `NetworkBridgeUpdate` - to all validation subsystems. +- Map all `AuthorityDiscoveryId`s to `PeerId`s and issue a corresponding `NetworkBridgeUpdate` to all validation + subsystems. ## Event Handlers -Network bridge event handlers are the intended recipients of particular network protocol messages. These are each a variant of a message to be sent via the overseer. +Network bridge event handlers are the intended recipients of particular network protocol messages. These are each a +variant of a message to be sent via the overseer. ### Validation V1 -* `ApprovalDistributionV1Message -> ApprovalDistributionMessage::NetworkBridgeUpdate` -* `BitfieldDistributionV1Message -> BitfieldDistributionMessage::NetworkBridgeUpdate` -* `StatementDistributionV1Message -> StatementDistributionMessage::NetworkBridgeUpdate` +- `ApprovalDistributionV1Message -> ApprovalDistributionMessage::NetworkBridgeUpdate` +- `BitfieldDistributionV1Message -> BitfieldDistributionMessage::NetworkBridgeUpdate` +- `StatementDistributionV1Message -> StatementDistributionMessage::NetworkBridgeUpdate` ### Collation V1 -* `CollatorProtocolV1Message -> CollatorProtocolMessage::NetworkBridgeUpdate` +- `CollatorProtocolV1Message -> CollatorProtocolMessage::NetworkBridgeUpdate` [NBM]: ../../types/overseer-protocol.md#network-bridge-message [AppD]: ../../types/overseer-protocol.md#approval-distribution-message diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md index a3998cabba6..0b4fe6a4587 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md @@ -1,28 +1,43 @@ # Provisioner -Relay chain block authorship authority is governed by BABE and is beyond the scope of the Overseer and the rest of the subsystems. That said, ultimately the block author needs to select a set of backable parachain candidates and other consensus data, and assemble a block from them. This subsystem is responsible for providing the necessary data to all potential block authors. +Relay chain block authorship authority is governed by BABE and is beyond the scope of the Overseer and the rest of the +subsystems. That said, ultimately the block author needs to select a set of backable parachain candidates and other +consensus data, and assemble a block from them. This subsystem is responsible for providing the necessary data to all +potential block authors. ## Provisionable Data -There are several distinct types of provisionable data, but they share this property in common: all should eventually be included in a relay chain block. +There are several distinct types of provisionable data, but they share this property in common: all should eventually be +included in a relay chain block. ### Backed Candidates -The block author can choose 0 or 1 backed parachain candidates per parachain; the only constraint is that each backable candidate has the appropriate relay parent. However, the choice of a backed candidate must be the block author's. The provisioner subsystem is how those block authors make this choice in practice. +The block author can choose 0 or 1 backed parachain candidates per parachain; the only constraint is that each backable +candidate has the appropriate relay parent. However, the choice of a backed candidate must be the block author's. The +provisioner subsystem is how those block authors make this choice in practice. ### Signed Bitfields -[Signed bitfields](../../types/availability.md#signed-availability-bitfield) are attestations from a particular validator about which candidates it believes are available. Those will only be provided on fresh leaves. +[Signed bitfields](../../types/availability.md#signed-availability-bitfield) are attestations from a particular +validator about which candidates it believes are available. Those will only be provided on fresh leaves. ### Misbehavior Reports -Misbehavior reports are self-contained proofs of misbehavior by a validator or group of validators. For example, it is very easy to verify a double-voting misbehavior report: the report contains two votes signed by the same key, advocating different outcomes. Concretely, misbehavior reports become inherents which cause dots to be slashed. +Misbehavior reports are self-contained proofs of misbehavior by a validator or group of validators. For example, it is +very easy to verify a double-voting misbehavior report: the report contains two votes signed by the same key, advocating +different outcomes. Concretely, misbehavior reports become inherents which cause dots to be slashed. -Note that there is no mechanism in place which forces a block author to include a misbehavior report which it doesn't like, for example if it would be slashed by such a report. The chain's defense against this is to have a relatively long slash period, such that it's likely to encounter an honest author before the slash period expires. +Note that there is no mechanism in place which forces a block author to include a misbehavior report which it doesn't +like, for example if it would be slashed by such a report. The chain's defense against this is to have a relatively long +slash period, such that it's likely to encounter an honest author before the slash period expires. ### Dispute Inherent -The dispute inherent is similar to a misbehavior report in that it is an attestation of misbehavior on the part of a validator or group of validators. Unlike a misbehavior report, it is not self-contained: resolution requires coordinated action by several validators. The canonical example of a dispute inherent involves an approval checker discovering that a set of validators has improperly approved an invalid parachain block: resolving this requires the entire validator set to re-validate the block, so that the minority can be slashed. +The dispute inherent is similar to a misbehavior report in that it is an attestation of misbehavior on the part of a +validator or group of validators. Unlike a misbehavior report, it is not self-contained: resolution requires coordinated +action by several validators. The canonical example of a dispute inherent involves an approval checker discovering that +a set of validators has improperly approved an invalid parachain block: resolving this requires the entire validator set +to re-validate the block, so that the minority can be slashed. Dispute resolution is complex and is explained in substantially more detail [here](../../runtime/disputes.md). @@ -34,58 +49,85 @@ The subsystem should maintain a set of handles to Block Authorship Provisioning - `ActiveLeavesUpdate`: - For each `activated` head: - - spawn a Block Authorship Provisioning iteration with the given relay parent, storing a bidirectional channel with that iteration. + - spawn a Block Authorship Provisioning iteration with the given relay parent, storing a bidirectional channel with + that iteration. - For each `deactivated` head: - terminate the Block Authorship Provisioning iteration for the given relay parent, if any. -- `Conclude`: Forward `Conclude` to all iterations, waiting a small amount of time for them to join, and then hard-exiting. +- `Conclude`: Forward `Conclude` to all iterations, waiting a small amount of time for them to join, and then + hard-exiting. ### On `ProvisionerMessage` -Forward the message to the appropriate Block Authorship Provisioning iteration, or discard if no appropriate iteration is currently active. +Forward the message to the appropriate Block Authorship Provisioning iteration, or discard if no appropriate iteration +is currently active. ### Per Provisioning Iteration -Input: [`ProvisionerMessage`](../../types/overseer-protocol.md#provisioner-message). Backed candidates come from the [Candidate Backing subsystem](../backing/candidate-backing.md), signed bitfields come from the [Bitfield Distribution subsystem](../availability/bitfield-distribution.md), and disputes come from the [Disputes Subsystem](../disputes/dispute-coordinator.md). Misbehavior reports are currently sent from the [Candidate Backing subsystem](../backing/candidate-backing.md) and contain the following misbehaviors: +Input: [`ProvisionerMessage`](../../types/overseer-protocol.md#provisioner-message). Backed candidates come from the +[Candidate Backing subsystem](../backing/candidate-backing.md), signed bitfields come from the [Bitfield Distribution +subsystem](../availability/bitfield-distribution.md), and disputes come from the [Disputes +Subsystem](../disputes/dispute-coordinator.md). Misbehavior reports are currently sent from the [Candidate Backing +subsystem](../backing/candidate-backing.md) and contain the following misbehaviors: 1. `Misbehavior::ValidityDoubleVote` 2. `Misbehavior::MultipleCandidates` 3. `Misbehavior::UnauthorizedStatement` 4. `Misbehavior::DoubleSign` -But we choose not to punish these forms of misbehavior for the time being. Risks from misbehavior are sufficiently mitigated at the protocol level via reputation changes. Punitive actions here may become desirable enough to dedicate time to in the future. +But we choose not to punish these forms of misbehavior for the time being. Risks from misbehavior are sufficiently +mitigated at the protocol level via reputation changes. Punitive actions here may become desirable enough to dedicate +time to in the future. At initialization, this subsystem has no outputs. -Block authors request the inherent data they should use for constructing the inherent in the block which contains parachain execution information. +Block authors request the inherent data they should use for constructing the inherent in the block which contains +parachain execution information. ## Block Production -When a validator is selected by BABE to author a block, it becomes a block producer. The provisioner is the subsystem best suited to choosing which specific backed candidates and availability bitfields should be assembled into the block. To engage this functionality, a `ProvisionerMessage::RequestInherentData` is sent; the response is a [`ParaInherentData`](../../types/runtime.md#parainherentdata). Each relay chain block backs at most one backable parachain block candidate per parachain. Additionally no further block candidate can be backed until the previous one either gets declared available or expired. If bitfields indicate that candidate A, predecessor of B, should be declared available, then B can be backed in the same relay block. Appropriate bitfields, as outlined in the section on [bitfield selection](#bitfield-selection), and any dispute statements should be attached as well. +When a validator is selected by BABE to author a block, it becomes a block producer. The provisioner is the subsystem +best suited to choosing which specific backed candidates and availability bitfields should be assembled into the block. +To engage this functionality, a `ProvisionerMessage::RequestInherentData` is sent; the response is a +[`ParaInherentData`](../../types/runtime.md#parainherentdata). Each relay chain block backs at most one backable +parachain block candidate per parachain. Additionally no further block candidate can be backed until the previous one +either gets declared available or expired. If bitfields indicate that candidate A, predecessor of B, should be declared +available, then B can be backed in the same relay block. Appropriate bitfields, as outlined in the section on [bitfield +selection](#bitfield-selection), and any dispute statements should be attached as well. ### Bitfield Selection -Our goal with respect to bitfields is simple: maximize availability. However, it's not quite as simple as always including all bitfields; there are constraints which still need to be met: +Our goal with respect to bitfields is simple: maximize availability. However, it's not quite as simple as always +including all bitfields; there are constraints which still need to be met: - not more than one bitfield per validator - each 1 bit must correspond to an occupied core -Beyond that, a semi-arbitrary selection policy is fine. In order to meet the goal of maximizing availability, a heuristic of picking the bitfield with the greatest number of 1 bits set in the event of conflict is useful. +Beyond that, a semi-arbitrary selection policy is fine. In order to meet the goal of maximizing availability, a +heuristic of picking the bitfield with the greatest number of 1 bits set in the event of conflict is useful. ### Dispute Statement Selection -This is the point at which the block author provides further votes to active disputes or initiates new disputes in the runtime state. +This is the point at which the block author provides further votes to active disputes or initiates new disputes in the +runtime state. -The block-authoring logic of the runtime has an extra step between handling the inherent-data and producing the actual inherent call, which we assume performs the work of filtering out disputes which are not relevant to the on-chain state. Backing votes are always kept in the dispute statement set. This ensures we punish the maximum number of misbehaving backers. +The block-authoring logic of the runtime has an extra step between handling the inherent-data and producing the actual +inherent call, which we assume performs the work of filtering out disputes which are not relevant to the on-chain state. +Backing votes are always kept in the dispute statement set. This ensures we punish the maximum number of misbehaving +backers. To select disputes: -- Issue a `DisputeCoordinatorMessage::RecentDisputes` message and wait for the response. This is a set of all disputes in recent sessions which we are aware of. +- Issue a `DisputeCoordinatorMessage::RecentDisputes` message and wait for the response. This is a set of all disputes + in recent sessions which we are aware of. ### Determining Bitfield Availability -An occupied core has a `CoreAvailability` bitfield. We also have a list of `SignedAvailabilityBitfield`s. We need to determine from these whether or not a core at a particular index has become available. +An occupied core has a `CoreAvailability` bitfield. We also have a list of `SignedAvailabilityBitfield`s. We need to +determine from these whether or not a core at a particular index has become available. -The key insight required is that `CoreAvailability` is transverse to the `SignedAvailabilityBitfield`s: if we conceptualize the list of bitfields as many rows, each bit of which is its own column, then `CoreAvailability` for a given core index is the vertical slice of bits in the set at that index. +The key insight required is that `CoreAvailability` is transverse to the `SignedAvailabilityBitfield`s: if we +conceptualize the list of bitfields as many rows, each bit of which is its own column, then `CoreAvailability` for a +given core index is the vertical slice of bits in the set at that index. To compute bitfield availability, then: @@ -97,16 +139,22 @@ To compute bitfield availability, then: ### Candidate Selection: Prospective Parachains Mode -The state of the provisioner `PerRelayParent` tracks an important setting, `ProspectiveParachainsMode`. This setting determines which backable candidate selection method the provisioner uses. +The state of the provisioner `PerRelayParent` tracks an important setting, `ProspectiveParachainsMode`. This setting +determines which backable candidate selection method the provisioner uses. -`ProspectiveParachainsMode::Disabled` - The provisioner uses its own internal legacy candidate selection. -`ProspectiveParachainsMode::Enabled` - The provisioner requests that [prospective parachains](../backing/prospective-parachains.md) provide selected candidates. +`ProspectiveParachainsMode::Disabled` - The provisioner uses its own internal legacy candidate selection. +`ProspectiveParachainsMode::Enabled` - The provisioner requests that [prospective +parachains](../backing/prospective-parachains.md) provide selected candidates. -Candidates selected with `ProspectiveParachainsMode::Enabled` are able to benefit from the increased block production time asynchronous backing allows. For this reason all Polkadot protocol networks will eventually use prospective parachains candidate selection. Then legacy candidate selection will be removed as obsolete. +Candidates selected with `ProspectiveParachainsMode::Enabled` are able to benefit from the increased block production +time asynchronous backing allows. For this reason all Polkadot protocol networks will eventually use prospective +parachains candidate selection. Then legacy candidate selection will be removed as obsolete. ### Prospective Parachains Candidate Selection -The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. In prospective parachains candidate selection the provisioner handles the former process while [prospective parachains](../backing/prospective-parachains.md) handles the latter. +The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate +appropriate to each free core. In prospective parachains candidate selection the provisioner handles the former process +while [prospective parachains](../backing/prospective-parachains.md) handles the latter. To select backable candidates: @@ -116,32 +164,50 @@ To select backable candidates: - The core is unscheduled and doesn’t need to be provisioned with a candidate - On `CoreState::Scheduled` - The core is unoccupied and scheduled to accept a backed block for a particular `para_id`. - - The provisioner requests a backable candidate from [prospective parachains](../backing/prospective-parachains.md) with the desired relay parent, the core’s scheduled `para_id`, and an empty required path. + - The provisioner requests a backable candidate from [prospective parachains](../backing/prospective-parachains.md) + with the desired relay parent, the core’s scheduled `para_id`, and an empty required path. - On `CoreState::Occupied` - - The availability core is occupied by a parachain block candidate pending availability. A further candidate need not be provided by the provisioner unless the core will be vacated this block. This is the case when either bitfields indicate the current core occupant has been made available or a timeout is reached. + - The availability core is occupied by a parachain block candidate pending availability. A further candidate need + not be provided by the provisioner unless the core will be vacated this block. This is the case when either + bitfields indicate the current core occupant has been made available or a timeout is reached. - If `bitfields_indicate_availability` - - If `Some(scheduled_core) = occupied_core.next_up_on_available`, the core will be vacated and in need of a provisioned candidate. The provisioner requests a backable candidate from [prospective parachains](../backing/prospective-parachains.md) with the core’s scheduled `para_id` and a required path with one entry. This entry corresponds to the parablock candidate previously occupying this core, which was made available and can be built upon even though it hasn’t been seen as included in a relay chain block yet. See the Required Path section below for more detail. - - If `occupied_core.next_up_on_available` is `None`, then the core being vacated is unscheduled and doesn’t need to be provisioned with a candidate. + - If `Some(scheduled_core) = occupied_core.next_up_on_available`, the core will be vacated and in need of a + provisioned candidate. The provisioner requests a backable candidate from [prospective + parachains](../backing/prospective-parachains.md) with the core’s scheduled `para_id` and a required path with + one entry. This entry corresponds to the parablock candidate previously occupying this core, which was made + available and can be built upon even though it hasn’t been seen as included in a relay chain block yet. See the + Required Path section below for more detail. + - If `occupied_core.next_up_on_available` is `None`, then the core being vacated is unscheduled and doesn’t need + to be provisioned with a candidate. - Else-if `occupied_core.time_out_at == block_number` - - If `Some(scheduled_core) = occupied_core.next_up_on_timeout`, the core will be vacated and in need of a provisioned candidate. A candidate is requested in exactly the same way as with `CoreState::Scheduled`. - - Else the core being vacated is unscheduled and doesn’t need to be provisioned with a candidate -The end result of this process is a vector of `CandidateHash`s, sorted in order of their core index. + - If `Some(scheduled_core) = occupied_core.next_up_on_timeout`, the core will be vacated and in need of a + provisioned candidate. A candidate is requested in exactly the same way as with `CoreState::Scheduled`. + - Else the core being vacated is unscheduled and doesn’t need to be provisioned with a candidate The end result of +this process is a vector of `CandidateHash`s, sorted in order of their core index. #### Required Path -Required path is a parameter for `ProspectiveParachainsMessage::GetBackableCandidate`, which the provisioner sends in candidate selection. +Required path is a parameter for `ProspectiveParachainsMessage::GetBackableCandidate`, which the provisioner sends in +candidate selection. -An empty required path indicates that the requested candidate should be a direct child of the most recently included parablock for the given `para_id` as of the given relay parent. +An empty required path indicates that the requested candidate should be a direct child of the most recently included +parablock for the given `para_id` as of the given relay parent. -In contrast, a required path with one or more entries prompts [prospective parachains](../backing/prospective-parachains.md) to step forward through its fragment tree for the given `para_id` and relay parent until the desired parablock is reached. We then select a direct child of that parablock to pass to the provisioner. +In contrast, a required path with one or more entries prompts [prospective +parachains](../backing/prospective-parachains.md) to step forward through its fragment tree for the given `para_id` and +relay parent until the desired parablock is reached. We then select a direct child of that parablock to pass to the +provisioner. -The parablocks making up a required path do not need to have been previously seen as included in relay chain blocks. Thus the ability to provision backable candidates based on a required path effectively decouples backing from inclusion. +The parablocks making up a required path do not need to have been previously seen as included in relay chain blocks. +Thus the ability to provision backable candidates based on a required path effectively decouples backing from inclusion. -### Legacy Candidate Selection +### Legacy Candidate Selection -Legacy candidate selection takes place in the provisioner. Thus the provisioner needs to keep an up to date record of all [backed_candidates](../../types/backing.md#backed-candidate) `PerRelayParent` to pick from. +Legacy candidate selection takes place in the provisioner. Thus the provisioner needs to keep an up to date record of +all [backed_candidates](../../types/backing.md#backed-candidate) `PerRelayParent` to pick from. -The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. +The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate +appropriate to each free core. To determine availability: @@ -149,38 +215,54 @@ To determine availability: - For each core state: - On `CoreState::Scheduled`, then we can make an `OccupiedCoreAssumption::Free`. - On `CoreState::Occupied`, then we may be able to make an assumption: - - If the bitfields indicate availability and there is a scheduled `next_up_on_available`, then we can make an `OccupiedCoreAssumption::Included`. - - If the bitfields do not indicate availability, and there is a scheduled `next_up_on_time_out`, and `occupied_core.time_out_at == block_number_under_production`, then we can make an `OccupiedCoreAssumption::TimedOut`. + - If the bitfields indicate availability and there is a scheduled `next_up_on_available`, then we can make an + `OccupiedCoreAssumption::Included`. + - If the bitfields do not indicate availability, and there is a scheduled `next_up_on_time_out`, and + `occupied_core.time_out_at == block_number_under_production`, then we can make an + `OccupiedCoreAssumption::TimedOut`. - If we did not make an `OccupiedCoreAssumption`, then continue on to the next core. - - Now compute the core's `validation_data_hash`: get the `PersistedValidationData` from the runtime, given the known `ParaId` and `OccupiedCoreAssumption`; + - Now compute the core's `validation_data_hash`: get the `PersistedValidationData` from the runtime, given the known + `ParaId` and `OccupiedCoreAssumption`; - Find an appropriate candidate for the core. - - There are two constraints: `backed_candidate.candidate.descriptor.para_id == scheduled_core.para_id && candidate.candidate.descriptor.validation_data_hash == computed_validation_data_hash`. - - In the event that more than one candidate meets the constraints, selection between the candidates is arbitrary. However, not more than one candidate can be selected per core. + - There are two constraints: `backed_candidate.candidate.descriptor.para_id == scheduled_core.para_id && + candidate.candidate.descriptor.validation_data_hash == computed_validation_data_hash`. + - In the event that more than one candidate meets the constraints, selection between the candidates is arbitrary. + However, not more than one candidate can be selected per core. The end result of this process is a vector of `CandidateHash`s, sorted in order of their core index. ### Retrieving Full `BackedCandidate`s for Selected Hashes -Legacy candidate selection and prospective parachains candidate selection both leave us with a vector of `CandidateHash`s. These are passed to the backing subsystem with `CandidateBackingMessage::GetBackedCandidates`. +Legacy candidate selection and prospective parachains candidate selection both leave us with a vector of +`CandidateHash`s. These are passed to the backing subsystem with `CandidateBackingMessage::GetBackedCandidates`. -The response is a vector of `BackedCandidate`s, sorted in order of their core index and ready to be provisioned to block authoring. The candidate selection and retrieval process should select at maximum one candidate which upgrades the runtime validation code. +The response is a vector of `BackedCandidate`s, sorted in order of their core index and ready to be provisioned to block +authoring. The candidate selection and retrieval process should select at maximum one candidate which upgrades the +runtime validation code. ## Glossary -- **Relay-parent:** - - A particular relay-chain block which serves as an anchor and reference point for processes and data which depend on relay-chain state. -- **Active Leaf:** - - A relay chain block which is the head of an active fork of the relay chain. +- **Relay-parent:** + - A particular relay-chain block which serves as an anchor and reference point for processes and data which depend on + relay-chain state. +- **Active Leaf:** + - A relay chain block which is the head of an active fork of the relay chain. - Block authorship provisioning jobs are spawned per active leaf and concluded for any leaves which become inactive. -- **Candidate Selection:** +- **Candidate Selection:** - The process by which the provisioner selects backable parachain block candidates to pass to block authoring. - - Two versions, prospective parachains candidate selection and legacy candidate selection. See their respective protocol sections for details. -- **Availability Core:** - - Often referred to simply as "cores", availability cores are an abstraction used for resource management. For the provisioner, availability cores are most relevant in that core states determine which `para_id`s to provision backable candidates for. - - For more on availability cores see [Scheduler Module: Availability Cores](../../runtime/scheduler.md#availability-cores) + - Two versions, prospective parachains candidate selection and legacy candidate selection. See their respective + protocol sections for details. +- **Availability Core:** + - Often referred to simply as "cores", availability cores are an abstraction used for resource management. For the + provisioner, availability cores are most relevant in that core states determine which `para_id`s to provision + backable candidates for. + - For more on availability cores see [Scheduler Module: Availability + Cores](../../runtime/scheduler.md#availability-cores) - **Availability Bitfield:** - - Often referred to simply as a "bitfield", an availability bitfield represents the view of parablock candidate availability from a particular validator's perspective. Each bit in the bitfield corresponds to a single [availability core](../../runtime-api/availability-cores.md). + - Often referred to simply as a "bitfield", an availability bitfield represents the view of parablock candidate + availability from a particular validator's perspective. Each bit in the bitfield corresponds to a single + [availability core](../../runtime-api/availability-cores.md). - For more on availability bitfields see [availability](../../types/availability.md) - **Backable vs. Backed:** - Note that we sometimes use "backed" to refer to candidates that are "backable", but not yet backed on chain. - - Backable means that a quorum of the candidate's assigned backing group have provided signed affirming statements. \ No newline at end of file + - Backable means that a quorum of the candidate's assigned backing group have provided signed affirming statements. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md index 3cae12e65f3..b722bdc6539 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md @@ -1,45 +1,70 @@ # PVF Pre-checker -The PVF pre-checker is a subsystem that is responsible for watching the relay chain for new PVFs that require pre-checking. Head over to [overview] for the PVF pre-checking process overview. +The PVF pre-checker is a subsystem that is responsible for watching the relay chain for new PVFs that require +pre-checking. Head over to [overview] for the PVF pre-checking process overview. ## Protocol -There is no dedicated input mechanism for PVF pre-checker. Instead, PVF pre-checker looks on the `ActiveLeavesUpdate` event stream for work. +There is no dedicated input mechanism for PVF pre-checker. Instead, PVF pre-checker looks on the `ActiveLeavesUpdate` +event stream for work. -This subsytem does not produce any output messages either. The subsystem will, however, send messages to the [Runtime API] subsystem to query for the pending PVFs and to submit votes. In addition to that, it will also communicate with [Candidate Validation] Subsystem to request PVF pre-check. +This subsytem does not produce any output messages either. The subsystem will, however, send messages to the [Runtime +API] subsystem to query for the pending PVFs and to submit votes. In addition to that, it will also communicate with +[Candidate Validation] Subsystem to request PVF pre-check. ## Functionality -If the node is running in a collator mode, this subsystem will be disabled. The PVF pre-checker subsystem keeps track of the PVFs that are relevant for the subsystem. +If the node is running in a collator mode, this subsystem will be disabled. The PVF pre-checker subsystem keeps track of +the PVFs that are relevant for the subsystem. -To be relevant for the subsystem, a PVF must be returned by the [`pvfs_require_precheck` runtime API][PVF pre-checking runtime API] in any of the active leaves. If the PVF is not present in any of the active leaves, it ceases to be relevant. +To be relevant for the subsystem, a PVF must be returned by the [`pvfs_require_precheck` runtime API][PVF pre-checking +runtime API] in any of the active leaves. If the PVF is not present in any of the active leaves, it ceases to be +relevant. -When a PVF just becomes relevant, the subsystem will send a message to the [Candidate Validation] subsystem asking for the pre-check. +When a PVF just becomes relevant, the subsystem will send a message to the [Candidate Validation] subsystem asking for +the pre-check. -Upon receving a message from the candidate-validation subsystem, the pre-checker will note down that the PVF has its judgement and will also sign and submit a [`PvfCheckStatement`][PvfCheckStatement] via the [`submit_pvf_check_statement` runtime API][PVF pre-checking runtime API]. In case, a judgement was received for a PVF that is no longer in view it is ignored. +Upon receving a message from the candidate-validation subsystem, the pre-checker will note down that the PVF has its +judgement and will also sign and submit a [`PvfCheckStatement`][PvfCheckStatement] via the [`submit_pvf_check_statement` +runtime API][PVF pre-checking runtime API]. In case, a judgement was received for a PVF that is no longer in view it is +ignored. -Since a vote only is valid during [one session][overview], the subsystem will have to resign and submit the statements for the new session. The new session is assumed to be started if at least one of the leaves has a greater session index that was previously observed in any of the leaves. +Since a vote only is valid during [one session][overview], the subsystem will have to resign and submit the statements +for the new session. The new session is assumed to be started if at least one of the leaves has a greater session index +that was previously observed in any of the leaves. -The subsystem tracks all the statements that it submitted within a session. If for some reason a PVF became irrelevant and then becomes relevant again, the subsystem will not submit a new statement for that PVF within the same session. +The subsystem tracks all the statements that it submitted within a session. If for some reason a PVF became irrelevant +and then becomes relevant again, the subsystem will not submit a new statement for that PVF within the same session. -If the node is not in the active validator set, it will still perform all the checks. However, it will only submit the check statements when the node is in the active validator set. +If the node is not in the active validator set, it will still perform all the checks. However, it will only submit the +check statements when the node is in the active validator set. ### Rejecting failed PVFs -It is possible that the candidate validation was not able to check the PVF, e.g. if it timed out. In that case, the PVF pre-checker will vote against it. This is considered safe, as there is no slashing for being on the wrong side of a pre-check vote. +It is possible that the candidate validation was not able to check the PVF, e.g. if it timed out. In that case, the PVF +pre-checker will vote against it. This is considered safe, as there is no slashing for being on the wrong side of a +pre-check vote. Rejecting instead of abstaining is better in several ways: 1. Conclusion is reached faster - we have actual votes, instead of relying on a timeout. -1. Being strict in pre-checking makes it safer to be more lenient in preparation errors afterwards. Hence we have more leeway in avoiding raising dubious disputes, without making things less secure. +1. Being strict in pre-checking makes it safer to be more lenient in preparation errors afterwards. Hence we have more + leeway in avoiding raising dubious disputes, without making things less secure. -Also, if we only abstain, an attacker can specially craft a PVF wasm blob so that it will fail on e.g. 50% of the validators. In that case a supermajority will never be reached and the vote will repeat multiple times, most likely with the same result (since all votes are cleared on a session change). This is avoided by rejecting failed PVFs, and by only requiring 1/3 of validators to reject a PVF to reach a decision. +Also, if we only abstain, an attacker can specially craft a PVF wasm blob so that it will fail on e.g. 50% of the +validators. In that case a supermajority will never be reached and the vote will repeat multiple times, most likely with +the same result (since all votes are cleared on a session change). This is avoided by rejecting failed PVFs, and by only +requiring 1/3 of validators to reject a PVF to reach a decision. ### Note on Disputes -Having a pre-checking phase allows us to make certain assumptions later when preparing the PVF for execution. If a runtime passed pre-checking, then we know that the runtime should be valid, and therefore any issue during preparation for execution can be assumed to be a local problem on the current node. +Having a pre-checking phase allows us to make certain assumptions later when preparing the PVF for execution. If a +runtime passed pre-checking, then we know that the runtime should be valid, and therefore any issue during preparation +for execution can be assumed to be a local problem on the current node. -For this reason, even deterministic preparation errors should not trigger disputes. And since we do not dispute as a result of the pre-checking phase, as stated above, it should be impossible for preparation in general to result in disputes. +For this reason, even deterministic preparation errors should not trigger disputes. And since we do not dispute as a +result of the pre-checking phase, as stated above, it should be impossible for preparation in general to result in +disputes. [overview]: ../../pvf-prechecking.md [Runtime API]: runtime-api.md diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/runtime-api.md b/polkadot/roadmap/implementers-guide/src/node/utility/runtime-api.md index 6271429c266..b687bd5684c 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/runtime-api.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/runtime-api.md @@ -1,6 +1,7 @@ # Runtime API -The Runtime API subsystem is responsible for providing a single point of access to runtime state data via a set of pre-determined queries. This prevents shared ownership of a blockchain client resource by providing +The Runtime API subsystem is responsible for providing a single point of access to runtime state data via a set of +pre-determined queries. This prevents shared ownership of a blockchain client resource by providing ## Protocol @@ -10,8 +11,11 @@ Output: None ## Functionality -On receipt of `RuntimeApiMessage::Request(relay_parent, request)`, answer the request using the post-state of the `relay_parent` provided and provide the response to the side-channel embedded within the request. +On receipt of `RuntimeApiMessage::Request(relay_parent, request)`, answer the request using the post-state of the +`relay_parent` provided and provide the response to the side-channel embedded within the request. ## Jobs -> TODO Don't limit requests based on parent hash, but limit caching. No caching should be done for any requests on `relay_parent`s that are not active based on `ActiveLeavesUpdate` messages. Maybe with some leeway for things that have just been stopped. +> TODO Don't limit requests based on parent hash, but limit caching. No caching should be done for any requests on +> `relay_parent`s that are not active based on `ActiveLeavesUpdate` messages. Maybe with some leeway for things that +> have just been stopped. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-approval.md b/polkadot/roadmap/implementers-guide/src/protocol-approval.md index 693822ce079..9ba7f6da173 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-approval.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-approval.md @@ -1,19 +1,39 @@ # Approval Process -The Approval Process is the mechanism by which the relay-chain ensures that only valid parablocks are finalized and that backing validators are held accountable for managing to get bad blocks included into the relay chain. +The Approval Process is the mechanism by which the relay-chain ensures that only valid parablocks are finalized and that +backing validators are held accountable for managing to get bad blocks included into the relay chain. -Having a parachain include a bad block into a fork of the relay-chain is not catastrophic as long as the block isn't finalized by the relay-chain's finality gadget, GRANDPA. If the block isn't finalized, that means that the fork of the relay-chain can be reverted in favor of another by means of a dynamic fork-choice rule which leads honest validators to ignore any forks containing that parablock. +Having a parachain include a bad block into a fork of the relay-chain is not catastrophic as long as the block isn't +finalized by the relay-chain's finality gadget, GRANDPA. If the block isn't finalized, that means that the fork of the +relay-chain can be reverted in favor of another by means of a dynamic fork-choice rule which leads honest validators to +ignore any forks containing that parablock. Dealing with a bad parablock proceeds in these stages: 1. Detection 2. Escalation 3. Consequences -First, the bad block must be detected by an honest party. Second, the honest party must escalate the bad block to be checked by all validators. And last, the correct consequences of a bad block must occur. The first consequence, as mentioned above, is to revert the chain so what full nodes perceive to be best no longer contains the bad parablock. The second consequence is to slash all malicious validators. Note that, if the chain containing the bad block is reverted, that the result of the dispute needs to be transplanted or at least transplantable to all other forks of the chain so that malicious validators are slashed in all possible histories. Phrased alternatively, there needs to be no possible relay-chain in which malicious validators get away cost-free. - -Accepting a parablock is the end result of having passed through the detection stage without dispute, or having passed through the escalation/dispute stage with a positive outcome. For this to work, we need the detection procedure to have the properties that enough honest validators are always selected to check the parablock and that they cannot be interfered with by an adversary. This needs to be balanced with the scaling concern of parachains in general: the easiest way to get the first property is to have everyone check everything, but that is clearly too heavy. So we also have a desired constraint on the other property that we have as few validators as possible check any particular parablock. Our assignment function is the method by which we select validators to do approval checks on parablocks. - -It often makes more sense to think of relay-chain blocks as having been approved or not as opposed to thinking about whether parablocks have been approved. A relay-chain block containing a single bad parablock needs to be reverted, and a relay-chain block that contains only approved parablocks can be called approved, as long as its parent relay-chain block is also approved. It is important that the validity of any particular relay-chain block depend on the validity of its ancestry, so we do not finalize a block which has a bad block in its ancestry. +First, the bad block must be detected by an honest party. Second, the honest party must escalate the bad block to be +checked by all validators. And last, the correct consequences of a bad block must occur. The first consequence, as +mentioned above, is to revert the chain so what full nodes perceive to be best no longer contains the bad parablock. The +second consequence is to slash all malicious validators. Note that, if the chain containing the bad block is reverted, +that the result of the dispute needs to be transplanted or at least transplantable to all other forks of the chain so +that malicious validators are slashed in all possible histories. Phrased alternatively, there needs to be no possible +relay-chain in which malicious validators get away cost-free. + +Accepting a parablock is the end result of having passed through the detection stage without dispute, or having passed +through the escalation/dispute stage with a positive outcome. For this to work, we need the detection procedure to have +the properties that enough honest validators are always selected to check the parablock and that they cannot be +interfered with by an adversary. This needs to be balanced with the scaling concern of parachains in general: the +easiest way to get the first property is to have everyone check everything, but that is clearly too heavy. So we also +have a desired constraint on the other property that we have as few validators as possible check any particular +parablock. Our assignment function is the method by which we select validators to do approval checks on parablocks. + +It often makes more sense to think of relay-chain blocks as having been approved or not as opposed to thinking about +whether parablocks have been approved. A relay-chain block containing a single bad parablock needs to be reverted, and a +relay-chain block that contains only approved parablocks can be called approved, as long as its parent relay-chain block +is also approved. It is important that the validity of any particular relay-chain block depend on the validity of its +ancestry, so we do not finalize a block which has a bad block in its ancestry. ```dot process Approval Process digraph { @@ -24,29 +44,56 @@ digraph { Approval has roughly two parts: -- **Assignments** determines which validators performs approval checks on which candidates. It ensures that each candidate receives enough random checkers, while reducing adversaries' odds for obtaining enough checkers, and limiting adversaries' foreknowledge. It tracks approval votes to identify when "no show" approval check takes suspiciously long, perhaps indicating the node being under attack, and assigns more checks in this case. It tracks relay chain equivocations to determine when adversaries possibly gained foreknowledge about assignments, and adds additional checks in this case. +- **Assignments** determines which validators performs approval checks on which candidates. It ensures that each + candidate receives enough random checkers, while reducing adversaries' odds for obtaining enough checkers, and + limiting adversaries' foreknowledge. It tracks approval votes to identify when "no show" approval check takes + suspiciously long, perhaps indicating the node being under attack, and assigns more checks in this case. It tracks + relay chain equivocations to determine when adversaries possibly gained foreknowledge about assignments, and adds + additional checks in this case. -- **Approval checks** listens to the assignments subsystem for outgoing assignment notices that we shall check specific candidates. It then performs these checks by first invoking the reconstruction subsystem to obtain the candidate, second invoking the candidate validity utility subsystem upon the candidate, and finally sending out an approval vote, or perhaps initiating a dispute. +- **Approval checks** listens to the assignments subsystem for outgoing assignment notices that we shall check specific + candidates. It then performs these checks by first invoking the reconstruction subsystem to obtain the candidate, + second invoking the candidate validity utility subsystem upon the candidate, and finally sending out an approval vote, + or perhaps initiating a dispute. -These both run first as off-chain consensus protocols using messages gossiped among all validators, and second as an on-chain record of this off-chain protocols' progress after the fact. We need the on-chain protocol to provide rewards for the off-chain protocol. +These both run first as off-chain consensus protocols using messages gossiped among all validators, and second as an +on-chain record of this off-chain protocols' progress after the fact. We need the on-chain protocol to provide rewards +for the off-chain protocol. -Approval requires two gossiped message types, assignment notices created by its assignments subsystem, and approval votes sent by our approval checks subsystem when authorized by the candidate validity utility subsystem. +Approval requires two gossiped message types, assignment notices created by its assignments subsystem, and approval +votes sent by our approval checks subsystem when authorized by the candidate validity utility subsystem. -### Approval keys +## Approval keys We need two separate keys for the approval subsystem: -- **Approval assignment keys** are sr25519/schnorrkel keys used only for the assignment criteria VRFs. We implicitly sign assignment notices with approval assignment keys by including their relay chain context and additional data in the VRF's extra message, but exclude these from its VRF input. +- **Approval assignment keys** are sr25519/schnorrkel keys used only for the assignment criteria VRFs. We implicitly + sign assignment notices with approval assignment keys by including their relay chain context and additional data in + the VRF's extra message, but exclude these from its VRF input. -- **Approval vote keys** would only sign off on candidate parablock validity and has no natural key type restrictions. There's no need for this to actually embody a new session key type. We just want to make a distinction between assignments and approvals, although distant future node configurations might favor separate roles. We re-use the same keys as are used for parachain backing in practice. +- **Approval vote keys** would only sign off on candidate parablock validity and has no natural key type restrictions. + There's no need for this to actually embody a new session key type. We just want to make a distinction between + assignments and approvals, although distant future node configurations might favor separate roles. We re-use the same + keys as are used for parachain backing in practice. -Approval vote keys could relatively easily be handled by some hardened signer tooling, perhaps even HSMs assuming we select ed25519 for approval vote keys. Approval assignment keys might or might not support hardened signer tooling, but doing so sounds far more complex. In fact, assignment keys determine only VRF outputs that determine approval checker assignments, for which they can only act or not act, so they cannot equivocate, lie, etc. and represent little if any slashing risk for validator operators. +Approval vote keys could relatively easily be handled by some hardened signer tooling, perhaps even HSMs assuming we +select ed25519 for approval vote keys. Approval assignment keys might or might not support hardened signer tooling, but +doing so sounds far more complex. In fact, assignment keys determine only VRF outputs that determine approval checker +assignments, for which they can only act or not act, so they cannot equivocate, lie, etc. and represent little if any +slashing risk for validator operators. -In future, we shall determine which among the several hardening techniques best benefits the network as a whole. We could provide a multi-process multi-machine architecture for validators, perhaps even reminiscent of GNUNet, or perhaps more resembling smart HSM tooling. We might instead design a system that more resembled full systems, like like Cosmos' sentry nodes. In either case, approval assignments might be handled by a slightly hardened machine, but not necessarily nearly as hardened as approval votes, but approval votes machines must similarly run foreign WASM code, which increases their risk, so assignments being separate sounds helpful. +In future, we shall determine which among the several hardening techniques best benefits the network as a whole. We +could provide a multi-process multi-machine architecture for validators, perhaps even reminiscent of GNUNet, or perhaps +more resembling smart HSM tooling. We might instead design a system that more resembled full systems, like like Cosmos' +sentry nodes. In either case, approval assignments might be handled by a slightly hardened machine, but not necessarily +nearly as hardened as approval votes, but approval votes machines must similarly run foreign WASM code, which increases +their risk, so assignments being separate sounds helpful. ## Assignments -Approval assignment determines on which candidate parachain blocks each validator performs approval checks. An approval session considers only one relay chain block and assigns only those candidates that relay chain block declares available. +Approval assignment determines on which candidate parachain blocks each validator performs approval checks. An approval +session considers only one relay chain block and assigns only those candidates that relay chain block declares +available. Assignment balances several concerns: @@ -54,149 +101,286 @@ Assignment balances several concerns: - ensures enough checkers, and - distributes assignments relatively equitably. -Assignees determine their own assignments to check specific candidates using two or three assignment criteria. Assignees never reveal their assignments until relevant, and gossip delays assignments sent early, which limits others' foreknowledge. Assignees learn their assignment only with the relay chain block. +Assignees determine their own assignments to check specific candidates using two or three assignment criteria. +Assignees never reveal their assignments until relevant, and gossip delays assignments sent early, which limits others' +foreknowledge. Assignees learn their assignment only with the relay chain block. -All criteria require the validator evaluate a verifiable random function (VRF) using their VRF secret key. All criteria input specific data called "stories" about the session's relay chain block, and output candidates to check and a precedence called a `DelayTranche`. +All criteria require the validator evaluate a verifiable random function (VRF) using their VRF secret key. All criteria +input specific data called "stories" about the session's relay chain block, and output candidates to check and a +precedence called a `DelayTranche`. -We liberate availability cores when their candidate becomes available of course, but one approval assignment criteria continues associating each candidate with the core number it occupied when it became available. +We liberate availability cores when their candidate becomes available of course, but one approval assignment criteria +continues associating each candidate with the core number it occupied when it became available. -Assignment operates in loosely timed rounds determined by this `DelayTranche`s, which proceed roughly 12 times faster than six second block production assuming half second gossip times. If a candidate `C` needs more approval checkers by the time we reach round `t` then any validators with an assignment to `C` in delay tranche `t` gossip their send assignment notice for `C`. We continue until all candidates have enough approval checkers assigned. We take entire tranches together if we do not yet have enough, so we expect strictly more than enough checkers. We also take later tranches if some checkers return their approval votes too slow (see no shows below). +Assignment operates in loosely timed rounds determined by this `DelayTranche`s, which proceed roughly 12 times faster +than six second block production assuming half second gossip times. If a candidate `C` needs more approval checkers by +the time we reach round `t` then any validators with an assignment to `C` in delay tranche `t` gossip their send +assignment notice for `C`. We continue until all candidates have enough approval checkers assigned. We take entire +tranches together if we do not yet have enough, so we expect strictly more than enough checkers. We also take later +tranches if some checkers return their approval votes too slow (see no shows below). -Assignment ensures validators check those relay chain blocks for which they have delay tranche zero aka the highest precedence, so that adversaries always face honest checkers equal to the expected number of assignments with delay tranche zero. +Assignment ensures validators check those relay chain blocks for which they have delay tranche zero aka the highest +precedence, so that adversaries always face honest checkers equal to the expected number of assignments with delay +tranche zero. -Among these criteria, the BABE VRF output provides the story for two, which reduces how frequently adversaries could position their own checkers. We have one criterion whose story consists of the candidate's block hash plus external knowledge that a relay chain equivocation exists with a conflicting candidate. It provides unforeseeable assignments when adversaries gain foreknowledge about the other two by committing an equivocation in relay chain block production. +Among these criteria, the BABE VRF output provides the story for two, which reduces how frequently adversaries could +position their own checkers. We have one criterion whose story consists of the candidate's block hash plus external +knowledge that a relay chain equivocation exists with a conflicting candidate. It provides unforeseeable assignments +when adversaries gain foreknowledge about the other two by committing an equivocation in relay chain block production. ## Announcements / Notices -We gossip assignment notices among nodes so that all validators know which validators should check each candidate, and if any candidate requires more checkers. +We gossip assignment notices among nodes so that all validators know which validators should check each candidate, and +if any candidate requires more checkers. -Assignment notices consist of a relay chain context given by a block hash, an assignment criteria, consisting of the criteria identifier and optionally a criteria specific field, an assignee identifier, and a VRF signature by the assignee, which itself consists of a VRF pre-output and a DLEQ proof. Its VRF input consists of the criteria, usually including a criteria specific field, and a "story" about its relay chain context block. +Assignment notices consist of a relay chain context given by a block hash, an assignment criteria, consisting of the +criteria identifier and optionally a criteria specific field, an assignee identifier, and a VRF signature by the +assignee, which itself consists of a VRF pre-output and a DLEQ proof. Its VRF input consists of the criteria, usually +including a criteria specific field, and a "story" about its relay chain context block. -We never include stories inside the gossip messages containing assignment notices, but require each validator reconstruct them. We never care about assignments in the disputes process, so this does not complicate remote disputes. +We never include stories inside the gossip messages containing assignment notices, but require each validator +reconstruct them. We never care about assignments in the disputes process, so this does not complicate remote disputes. -In a Schnorr VRF, there is an extra signed message distinct from this input, which we set to the relay chain block hash. As a result, assignment notices are self signing and can be "politely" gossiped without additional signatures, meaning between nodes who can compute the story from the relay chain context. In other words, if we cannot compute the story required by an assignment notice's VRF part then our self signing property fails and we cannot verify its origin. We could fix this with either another signature layer (64 bytes) or by including the VRF input point computed from the story (32 bytes), but doing so appears unhelpful. +In a Schnorr VRF, there is an extra signed message distinct from this input, which we set to the relay chain block hash. +As a result, assignment notices are self signing and can be "politely" gossiped without additional signatures, meaning +between nodes who can compute the story from the relay chain context. In other words, if we cannot compute the story +required by an assignment notice's VRF part then our self signing property fails and we cannot verify its origin. We +could fix this with either another signature layer (64 bytes) or by including the VRF input point computed from the +story (32 bytes), but doing so appears unhelpful. -Any validator could send their assignment notices and/or approval votes too early. We gossip the approval votes early because they represent a major commitment by the validator. We delay gossiping the assignment notices until they agree with our local clock however. We also impose a politeness condition that the recipient knows the relay chain context used by the assignment notice. +Any validator could send their assignment notices and/or approval votes too early. We gossip the approval votes early +because they represent a major commitment by the validator. We delay gossiping the assignment notices until they agree +with our local clock however. We also impose a politeness condition that the recipient knows the relay chain context +used by the assignment notice. ## Stories -We based assignment criteria upon two possible "stories" about the relay chain block `R` that included the candidate aka declared the candidate available. All stories have an output that attempts to minimize adversarial influence, which then acts as the VRF input for an assignment criteria. +We based assignment criteria upon two possible "stories" about the relay chain block `R` that included the candidate aka +declared the candidate available. All stories have an output that attempts to minimize adversarial influence, which +then acts as the VRF input for an assignment criteria. -We first have a `RelayVRFStory` that outputs the randomness from another VRF output produced by the relay chain block producer when creating `R`. Among honest nodes, only this one relay chain block producer who creates `R` knew the story in advance, and even they knew nothing two epochs previously. +We first have a `RelayVRFStory` that outputs the randomness from another VRF output produced by the relay chain block +producer when creating `R`. Among honest nodes, only this one relay chain block producer who creates `R` knew the story +in advance, and even they knew nothing two epochs previously. -In BABE, we create this value calling `schnorrkel::vrf::VRFInOut::make_bytes` with a context "A&V RC-VRF", with the `VRFInOut` coming from either the VRF that authorized block production for primary blocks, or else from the secondary block VRF for the secondary block type. +In BABE, we create this value calling `schnorrkel::vrf::VRFInOut::make_bytes` with a context "A&V RC-VRF", with the +`VRFInOut` coming from either the VRF that authorized block production for primary blocks, or else from the secondary +block VRF for the secondary block type. -In Sassafras, we shall always use the non-anonymized recycling VRF output, never the anonymized ring VRF that authorizes block production. We do not currently know if Sassafras shall have a separate schnorrkel key, but if it reuses its ring VRF key there is an equivalent `ring_vrf::VRFInOut::make_bytes`. +In Sassafras, we shall always use the non-anonymized recycling VRF output, never the anonymized ring VRF that authorizes +block production. We do not currently know if Sassafras shall have a separate schnorrkel key, but if it reuses its ring +VRF key there is an equivalent `ring_vrf::VRFInOut::make_bytes`. -We like that `RelayVRFStory` admits relatively few choices, but an adversary who equivocates in relay chain block production could learn assignments that depend upon the `RelayVRFStory` too early because the same relay chain VRF appears in multiple blocks. +We like that `RelayVRFStory` admits relatively few choices, but an adversary who equivocates in relay chain block +production could learn assignments that depend upon the `RelayVRFStory` too early because the same relay chain VRF +appears in multiple blocks. -We therefore provide a secondary `RelayEquivocationStory` that outputs the candidate's block hash, but only for candidate equivocations. We say a candidate `C` in `R` is an equivocation when there exists another relay chain block `R1` that equivocates for `R` in the sense that `R` and `R1` have the same `RelayVRFStory`, but `R` contains `C` and `R1` does not contain `C`. +We therefore provide a secondary `RelayEquivocationStory` that outputs the candidate's block hash, but only for +candidate equivocations. We say a candidate `C` in `R` is an equivocation when there exists another relay chain block +`R1` that equivocates for `R` in the sense that `R` and `R1` have the same `RelayVRFStory`, but `R` contains `C` and +`R1` does not contain `C`. -We want checkers for candidate equivocations that lie outside our preferred relay chain as well, which represents a slightly different usage for the assignments module, and might require more information in the gossip messages. +We want checkers for candidate equivocations that lie outside our preferred relay chain as well, which represents a +slightly different usage for the assignments module, and might require more information in the gossip messages. ## Assignment criteria -Assignment criteria compute actual assignments using stories and the validators' secret approval assignment key. Assignment criteria output a `Position` consisting of both a `ParaId` to be checked, as well as a precedence `DelayTranche` for when the assignment becomes valid. +Assignment criteria compute actual assignments using stories and the validators' secret approval assignment key. +Assignment criteria output a `Position` consisting of both a `ParaId` to be checked, as well as a precedence +`DelayTranche` for when the assignment becomes valid. -Assignment criteria come in three flavors, `RelayVRFModulo`, `RelayVRFDelay` and `RelayEquivocation`. Among these, both `RelayVRFModulo` and `RelayVRFDelay` run a VRF whose input is the output of a `RelayVRFStory`, while `RelayEquivocation` runs a VRF whose input is the output of a `RelayEquivocationStory`. +Assignment criteria come in three flavors, `RelayVRFModulo`, `RelayVRFDelay` and `RelayEquivocation`. Among these, both +`RelayVRFModulo` and `RelayVRFDelay` run a VRF whose input is the output of a `RelayVRFStory`, while `RelayEquivocation` +runs a VRF whose input is the output of a `RelayEquivocationStory`. Among these, we have two distinct VRF output computations: -`RelayVRFModulo` runs several distinct samples whose VRF input is the `RelayVRFStory` and the sample number. It computes the VRF output with `schnorrkel::vrf::VRFInOut::make_bytes` using the context "A&V Core", reduces this number modulo the number of availability cores, and outputs the candidate just declared available by, and included by aka leaving, that availability core. We drop any samples that return no candidate because no candidate was leaving the sampled availability core in this relay chain block. We choose three samples initially, but we could make polkadot more secure and efficient by increasing this to four or five, and reducing the backing checks accordingly. All successful `RelayVRFModulo` samples are assigned delay tranche zero. +`RelayVRFModulo` runs several distinct samples whose VRF input is the `RelayVRFStory` and the sample number. It +computes the VRF output with `schnorrkel::vrf::VRFInOut::make_bytes` using the context "A&V Core", reduces this number +modulo the number of availability cores, and outputs the candidate just declared available by, and included by aka +leaving, that availability core. We drop any samples that return no candidate because no candidate was leaving the +sampled availability core in this relay chain block. We choose three samples initially, but we could make Polkadot more +secure and efficient by increasing this to four or five, and reducing the backing checks accordingly. All successful +`RelayVRFModulo` samples are assigned delay tranche zero. -There is no sampling process for `RelayVRFDelay` and `RelayEquivocation`. We instead run them on specific candidates and they compute a delay from their VRF output. `RelayVRFDelay` runs for all candidates included under, aka declared available by, a relay chain block, and inputs the associated VRF output via `RelayVRFStory`. `RelayEquivocation` runs only on candidate block equivocations, and inputs their block hashes via the `RelayEquivocation` story. +There is no sampling process for `RelayVRFDelay` and `RelayEquivocation`. We instead run them on specific candidates +and they compute a delay from their VRF output. `RelayVRFDelay` runs for all candidates included under, aka declared +available by, a relay chain block, and inputs the associated VRF output via `RelayVRFStory`. `RelayEquivocation` runs +only on candidate block equivocations, and inputs their block hashes via the `RelayEquivocation` story. -`RelayVRFDelay` and `RelayEquivocation` both compute their output with `schnorrkel::vrf::VRFInOut::make_bytes` using the context "A&V Tranche" and reduce the result modulo `num_delay_tranches + zeroth_delay_tranche_width`, and consolidate results 0 through `zeroth_delay_tranche_width` to be 0. In this way, they ensure the zeroth delay tranche has `zeroth_delay_tranche_width+1` times as many assignments as any other tranche. +`RelayVRFDelay` and `RelayEquivocation` both compute their output with `schnorrkel::vrf::VRFInOut::make_bytes` using the +context "A&V Tranche" and reduce the result modulo `num_delay_tranches + zeroth_delay_tranche_width`, and consolidate +results 0 through `zeroth_delay_tranche_width` to be 0. In this way, they ensure the zeroth delay tranche has +`zeroth_delay_tranche_width+1` times as many assignments as any other tranche. -As future work (or TODO?), we should merge assignment notices with the same delay and story using `vrf_merge`. We cannot merge those with the same delay and different stories because `RelayEquivocationStory`s could change but `RelayVRFStory` never changes. +As future work (or TODO?), we should merge assignment notices with the same delay and story using `vrf_merge`. We +cannot merge those with the same delay and different stories because `RelayEquivocationStory`s could change but +`RelayVRFStory` never changes. ## Announcer and Watcher/Tracker -We track all validators' announced approval assignments for each candidate associated to each relay chain block, which tells us which validators were assigned to which candidates. +We track all validators' announced approval assignments for each candidate associated to each relay chain block, which +tells us which validators were assigned to which candidates. -We permit at most one assignment per candidate per story per validator, so one validator could be assigned under both the `RelayVRFDelay` and `RelayEquivocation` criteria, but not under both `RelayVRFModulo` and `RelayVRFDelay` criteria, since those both use the same story. We permit only one approval vote per candidate per validator, which counts for any applicable criteria. +We permit at most one assignment per candidate per story per validator, so one validator could be assigned under both +the `RelayVRFDelay` and `RelayEquivocation` criteria, but not under both `RelayVRFModulo` and `RelayVRFDelay` criteria, +since those both use the same story. We permit only one approval vote per candidate per validator, which counts for any +applicable criteria. -We announce, and start checking for, our own assignments when the delay of their tranche is reached, but only if the tracker says the assignee candidate requires more approval checkers. We never announce an assignment we believe unnecessary because early announcements gives an adversary information. All delay tranche zero assignments always get announced, which includes all `RelayVRFModulo` assignments. +We announce, and start checking for, our own assignments when the delay of their tranche is reached, but only if the +tracker says the assignee candidate requires more approval checkers. We never announce an assignment we believe +unnecessary because early announcements gives an adversary information. All delay tranche zero assignments always get +announced, which includes all `RelayVRFModulo` assignments. -In other words, if some candidate `C` needs more approval checkers by the time we reach round `t` then any validators with an assignment to `C` in delay tranche `t` gossip their send assignment notice for `C`, and begin reconstruction and validation for 'C. If however `C` reached enough assignments, then validators with later assignments skip announcing their assignments. +In other words, if some candidate `C` needs more approval checkers by the time we reach round `t` then any validators +with an assignment to `C` in delay tranche `t` gossip their send assignment notice for `C`, and begin reconstruction and +validation for 'C. If however `C` reached enough assignments, then validators with later assignments skip announcing +their assignments. -We continue until all candidates have enough approval checkers assigned. We never prioritize assignments within tranches and count all or no assignments for a given tranche together, so we often overshoot the target number of assigned approval checkers. +We continue until all candidates have enough approval checkers assigned. We never prioritize assignments within +tranches and count all or no assignments for a given tranche together, so we often overshoot the target number of +assigned approval checkers. ### No shows -We have a "no show" timeout longer than one relay chain slot, so at least 6 seconds, during which we expect approval checks should succeed in reconstructing the candidate block, in redoing its erasure coding to check the candidate receipt, and finally in rechecking the candidate block itself. +We have a "no show" timeout longer than one relay chain slot, so at least 6 seconds, during which we expect approval +checks should succeed in reconstructing the candidate block, in redoing its erasure coding to check the candidate +receipt, and finally in rechecking the candidate block itself. -We consider a validator a "no show" if they do not approve or dispute within this "no show" timeout from our receiving their assignment notice. We time this from our receipt of their assignment notice instead of our imagined real time for their tranche because otherwise receiving late assignment notices creates immediate "no shows" and unnecessary work. +We consider a validator a "no show" if they do not approve or dispute within this "no show" timeout from our receiving +their assignment notice. We time this from our receipt of their assignment notice instead of our imagined real time for +their tranche because otherwise receiving late assignment notices creates immediate "no shows" and unnecessary work. -We worry "no shows" represent a validator under denial of service attack, presumably to prevent it from reconstructing the candidate, but perhaps delaying it form gossiping a dispute too. We therefore always replace "no shows" by adding one entire extra delay tranche worth of validators, so such attacks always result in additional checkers. +We worry "no shows" represent a validator under denial of service attack, presumably to prevent it from reconstructing +the candidate, but perhaps delaying it form gossiping a dispute too. We therefore always replace "no shows" by adding +one entire extra delay tranche worth of validators, so such attacks always result in additional checkers. -As an example, imagine we need 20 checkers, but tranche zero produces only 14, and tranche one only 4, then we take all 5 from tranche two, and thus require 23 checkers for that candidate. If one checker Charlie from tranche one or two does not respond within say 8 seconds, then we add all 7 checkers from tranche three. If again one checker Cindy from tranche three does not respond within 8 seconds then we take all 3 checkers from tranche four. We now have 33 checkers working on the candidate, so this escalated quickly. +As an example, imagine we need 20 checkers, but tranche zero produces only 14, and tranche one only 4, then we take all +5 from tranche two, and thus require 23 checkers for that candidate. If one checker Charlie from tranche one or two +does not respond within say 8 seconds, then we add all 7 checkers from tranche three. If again one checker Cindy from +tranche three does not respond within 8 seconds then we take all 3 checkers from tranche four. We now have 33 checkers +working on the candidate, so this escalated quickly. -We escalated so quickly because we worried that Charlie and Cindy might be the only honest checkers assigned to that candidate. If therefore either Charlie or Cindy finally return an approval, then we can conclude approval, and abandon the checkers from tranche four. +We escalated so quickly because we worried that Charlie and Cindy might be the only honest checkers assigned to that +candidate. If therefore either Charlie or Cindy finally return an approval, then we can conclude approval, and abandon +the checkers from tranche four. -We therefore require the "no show" timeout to be longer than a relay chain slot so that we can witness "no shows" on-chain. We discuss below how this helps reward validators who replace "no shows". +We therefore require the "no show" timeout to be longer than a relay chain slot so that we can witness "no shows" +on-chain. We discuss below how this helps reward validators who replace "no shows". -We avoid slashing for "no shows" by itself, although being "no show" could enter into some computation that punishes repeated poor performance, presumably replaces `ImOnline`, and we could reduce their rewards and further rewards those who filled in. +We avoid slashing for "no shows" by itself, although being "no show" could enter into some computation that punishes +repeated poor performance, presumably replaces `ImOnline`, and we could reduce their rewards and further rewards those +who filled in. -As future work, we foresee expanding the "no show" scheme to anonymize the additional checkers, like by using assignment noticed with a new criteria that employs a ring VRF and then all validators providing cover by requesting a couple erasure coded pieces, but such anonymity scheme sound extremely complex and lie far beyond our initial functionality. +As future work, we foresee expanding the "no show" scheme to anonymize the additional checkers, like by using assignment +noticed with a new criteria that employs a ring VRF and then all validators providing cover by requesting a couple +erasure coded pieces, but such anonymity scheme sound extremely complex and lie far beyond our initial functionality. ## Assignment postponement -We expect validators could occasionally overloaded when they randomly acquire too many assignments. All these fluctuations amortize over multiple blocks fairly well, but this slows down finality. +We expect validators could occasionally overloaded when they randomly acquire too many assignments. All these +fluctuations amortize over multiple blocks fairly well, but this slows down finality. -We therefore permit validators to delay sending their assignment noticed intentionally. If nobody knows about their assignment then they avoid creating "no shows" and the workload progresses normally. +We therefore permit validators to delay sending their assignment noticed intentionally. If nobody knows about their +assignment then they avoid creating "no shows" and the workload progresses normally. -We strongly prefer if postponements come from tranches higher aka less important than zero because tranche zero checks provide somewhat more security. +We strongly prefer if postponements come from tranches higher aka less important than zero because tranche zero checks +provide somewhat more security. TODO: When? Is this optimal for the network? etc. ## On-chain verification -We should verify approval on-chain to reward approval checkers. We therefore require the "no show" timeout to be longer than a relay chain slot so that we can witness "no shows" on-chain, which helps with this goal. The major challenge with an on-chain record of the off-chain process is adversarial block producers who may either censor votes or publish votes to the chain which cause other votes to be ignored and unrewarded (reward stealing). +We should verify approval on-chain to reward approval checkers. We therefore require the "no show" timeout to be longer +than a relay chain slot so that we can witness "no shows" on-chain, which helps with this goal. The major challenge with +an on-chain record of the off-chain process is adversarial block producers who may either censor votes or publish votes +to the chain which cause other votes to be ignored and unrewarded (reward stealing). -In principle, all validators have some "tranche" at which they're assigned to the parachain candidate, which ensures we reach enough validators eventually. As noted above, we often retract "no shows" when the slow validator eventually shows up, so witnessing their initially being a "no show" helps manage rewards. +In principle, all validators have some "tranche" at which they're assigned to the parachain candidate, which ensures we +reach enough validators eventually. As noted above, we often retract "no shows" when the slow validator eventually +shows up, so witnessing their initially being a "no show" helps manage rewards. -We expect on-chain verification should work in two phases: We first record assignments notices and approval votes on-chain in relay chain block, doing the VRF or regular signature verification again in block verification, and inserting chain authenticated unsigned notes into the relay chain state that contain the checker, tranche, paraid, and relay block height for each assignment notice. We then later have another relay chain block that runs some "approved" intrinsic, which extract all these notes from the state and feeds them into our approval code. +We expect on-chain verification should work in two phases: We first record assignments notices and approval votes +on-chain in relay chain block, doing the VRF or regular signature verification again in block verification, and +inserting chain authenticated unsigned notes into the relay chain state that contain the checker, tranche, paraid, and +relay block height for each assignment notice. We then later have another relay chain block that runs some "approved" +intrinsic, which extract all these notes from the state and feeds them into our approval code. -We now encounter one niche concern in the interaction between postponement and on-chain verification: Any validator with a tranche zero (or other low) assignment could delay sending an assignment notice, like because they postponed their assigned tranche (which is allowed). If they later send this assignment notices right around finality time, then they race with this approved. intrinsic: If their announcement gets on-chain (also allowed), then yes it delays finality. If it does not get on-chain, then yes we've one announcement that the off-chain consensus system says is valid, but the chain ignores for being too slow. +We now encounter one niche concern in the interaction between postponement and on-chain verification: Any validator +with a tranche zero (or other low) assignment could delay sending an assignment notice, like because they postponed +their assigned tranche (which is allowed). If they later send this assignment notices right around finality time, then +they race with this approved. intrinsic: If their announcement gets on-chain (also allowed), then yes it delays +finality. If it does not get on-chain, then yes we've one announcement that the off-chain consensus system says is +valid, but the chain ignores for being too slow. -We need the chain to win in this case, but doing this requires imposing an annoyingly long overarching delay upon finality. We might explore limits on postponement too, but this sounds much harder. +We need the chain to win in this case, but doing this requires imposing an annoyingly long overarching delay upon +finality. We might explore limits on postponement too, but this sounds much harder. ## Parameters -We prefer doing approval checkers assignments under `RelayVRFModulo` as opposed to `RelayVRFDelay` because `RelayVRFModulo` avoids giving individual checkers too many assignments and tranche zero assignments benefit security the most. We suggest assigning at least 16 checkers under `RelayVRFModulo` although assignment levels have never been properly analyzed. +We prefer doing approval checkers assignments under `RelayVRFModulo` as opposed to `RelayVRFDelay` because +`RelayVRFModulo` avoids giving individual checkers too many assignments and tranche zero assignments benefit security +the most. We suggest assigning at least 16 checkers under `RelayVRFModulo` although assignment levels have never been +properly analyzed. -Our delay criteria `RelayVRFDelay` and `RelayEquivocation` both have two primary paramaters, expected checkers per tranche and the zeroth delay tranche width. +Our delay criteria `RelayVRFDelay` and `RelayEquivocation` both have two primary paramaters, expected checkers per +tranche and the zeroth delay tranche width. -We require expected checkers per tranche to be less than three because otherwise an adversary with 1/3 stake could force all nodes into checking all blocks. We strongly recommend expected checkers per tranche to be less than two, which helps avoid both accidental and intentional explosions. We also suggest expected checkers per tranche be larger than one, which helps prevent adversaries from predicting than advancing one tranche adds only their own validators. +We require expected checkers per tranche to be less than three because otherwise an adversary with 1/3 stake could force +all nodes into checking all blocks. We strongly recommend expected checkers per tranche to be less than two, which +helps avoid both accidental and intentional explosions. We also suggest expected checkers per tranche be larger than +one, which helps prevent adversaries from predicting than advancing one tranche adds only their own validators. -We improve security more with tranche zero assignments, so `RelayEquivocation` should consolidates its first several tranches into tranche zero. We describe this as the zeroth delay tranche width, which initially we set to 12 for `RelayEquivocation` and `1` for `RelayVRFDelay`. +We improve security more with tranche zero assignments, so `RelayEquivocation` should consolidates its first several +tranches into tranche zero. We describe this as the zeroth delay tranche width, which initially we set to 12 for +`RelayEquivocation` and `1` for `RelayVRFDelay`. ## Why VRFs? We do assignments with VRFs to give "enough" checkers some meaning beyond merely "expected" checkers: -We could specify a protocol that used only system randomness, which works because our strongest defense is the expected number of honest checkers who assign themselves. In this, adversaries could trivially flood their own blocks with their own checkers, so this strong defense becomes our only defense, and delay tranches become useless, so some blocks actually have zero approval checkers and possibly only one checker overall. +We could specify a protocol that used only system randomness, which works because our strongest defense is the expected +number of honest checkers who assign themselves. In this, adversaries could trivially flood their own blocks with their +own checkers, so this strong defense becomes our only defense, and delay tranches become useless, so some blocks +actually have zero approval checkers and possibly only one checker overall. -VRFs though require adversaries wait far longer between such attacks, which also helps against adversaries with little at stake because they compromised validators. VRFs raise user confidence that no such "drive by" attacks occurred because the delay tranche system ensure at least some minimum number of approval checkers. In this vein, VRFs permit reducing backing checks and increasing approval checks, which makes polkadot more efficient. +VRFs though require adversaries wait far longer between such attacks, which also helps against adversaries with little +at stake because they compromised validators. VRFs raise user confidence that no such "drive by" attacks occurred +because the delay tranche system ensure at least some minimum number of approval checkers. In this vein, VRFs permit +reducing backing checks and increasing approval checks, which makes Polkadot more efficient. ## Gossip -Any validator could send their assignment notices and/or approval votes too early. We gossip the approval votes because they represent a major commitment by the validator. We retain but delay gossiping the assignment notices until they agree with our local clock. +Any validator could send their assignment notices and/or approval votes too early. We gossip the approval votes because +they represent a major commitment by the validator. We retain but delay gossiping the assignment notices until they +agree with our local clock. -Assignment notices being gossiped too early might create a denial of service vector. If so, we might exploit the relative time scheme that synchronizes our clocks, which conceivably permits just dropping excessively early assignments. +Assignment notices being gossiped too early might create a denial of service vector. If so, we might exploit the +relative time scheme that synchronizes our clocks, which conceivably permits just dropping excessively early +assignments. ## Finality GRANDPA Voting Rule -The relay-chain requires validators to participate in GRANDPA. In GRANDPA, validators submit off-chain votes on what they believe to be the best block of the chain, and GRANDPA determines the common block contained by a supermajority of sub-chains. There are also additional constraints on what can be submitted based on results of previous rounds of voting. +The relay-chain requires validators to participate in GRANDPA. In GRANDPA, validators submit off-chain votes on what +they believe to be the best block of the chain, and GRANDPA determines the common block contained by a supermajority of +sub-chains. There are also additional constraints on what can be submitted based on results of previous rounds of +voting. -In order to avoid finalizing anything which has not received enough approval votes or is disputed, we will pair the approval protocol with an alteration to the GRANDPA voting strategy for honest nodes which causes them to vote only on chains where every parachain candidate within has been approved. Furthermore, the voting rule prevents voting for chains where there is any live dispute or any dispute has resolved to a candidate being invalid. +In order to avoid finalizing anything which has not received enough approval votes or is disputed, we will pair the +approval protocol with an alteration to the GRANDPA voting strategy for honest nodes which causes them to vote only on +chains where every parachain candidate within has been approved. Furthermore, the voting rule prevents voting for +chains where there is any live dispute or any dispute has resolved to a candidate being invalid. -Thus, the finalized relay-chain should contain only relay-chain blocks where a majority believe that every block within has been sufficiently approved. +Thus, the finalized relay-chain should contain only relay-chain blocks where a majority believe that every block within +has been sufficiently approved. ### Future work -We could consider additional gossip messages with which nodes claims "slow availability" and/or "slow candidate" to fine tune the assignments "no show" system, but long enough "no show" delays suffice probably. +We could consider additional gossip messages with which nodes claims "slow availability" and/or "slow candidate" to fine +tune the assignments "no show" system, but long enough "no show" delays suffice probably. -We shall develop more practical experience with UDP once the availability system works using direct UDP connections. In this, we should discover if reconstruction performs adequately with a complete graphs or -benefits from topology restrictions. At this point, an assignment notices could implicitly request pieces from a random 1/3rd, perhaps topology restricted, which saves one gossip round. If this preliminary fast reconstruction fails, then nodes' request alternative pieces directly. There is an interesting design space in how this overlaps with "slow availability" claims. +We shall develop more practical experience with UDP once the availability system works using direct UDP connections. In +this, we should discover if reconstruction performs adequately with a complete graphs or benefits from topology +restrictions. At this point, an assignment notices could implicitly request pieces from a random 1/3rd, perhaps +topology restricted, which saves one gossip round. If this preliminary fast reconstruction fails, then nodes' request +alternative pieces directly. There is an interesting design space in how this overlaps with "slow availability" claims. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-chain-selection.md b/polkadot/roadmap/implementers-guide/src/protocol-chain-selection.md index dd066df43cd..9f0262243bd 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-chain-selection.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-chain-selection.md @@ -1,12 +1,21 @@ # Chain Selection -Chain selection processes in blockchains are used for the purpose of selecting blocks to build on and finalize. It is important for these processes to be consistent among nodes and resilient to a maximum proportion of malicious nodes which do not obey the chain selection process. +Chain selection processes in blockchains are used for the purpose of selecting blocks to build on and finalize. It is +important for these processes to be consistent among nodes and resilient to a maximum proportion of malicious nodes +which do not obey the chain selection process. -The parachain host uses both a block authoring system and a finality gadget. The chain selection strategy of the parachain host involves two key components: a _leaf-selection_ rule and a set of _finality constraints_. When it's a validator's turn to author on a block, they are expected to select the best block via the leaf-selection rule to build on top of. When a validator is participating in finality, there is a minimum block which can be voted on, which is usually the finalized block. The validator should select the best chain according to the leaf-selection rule and subsequently apply the finality constraints to arrive at the actual vote cast by that validator. +The parachain host uses both a block authoring system and a finality gadget. The chain selection strategy of the +parachain host involves two key components: a _leaf-selection_ rule and a set of _finality constraints_. When it's a +validator's turn to author on a block, they are expected to select the best block via the leaf-selection rule to build +on top of. When a validator is participating in finality, there is a minimum block which can be voted on, which is +usually the finalized block. The validator should select the best chain according to the leaf-selection rule and +subsequently apply the finality constraints to arrive at the actual vote cast by that validator. -Before diving into the particularities of the leaf-selection rule and the finality constraints, it's important to discuss the goals that these components are meant to achieve. For this it is useful to create the definitions of _viable_ and _finalizable_ blocks. +Before diving into the particularities of the leaf-selection rule and the finality constraints, it's important to +discuss the goals that these components are meant to achieve. For this it is useful to create the definitions of +_viable_ and _finalizable_ blocks. -### Property Definitions +## Property Definitions A block is considered **viable** when all of the following hold: 1. It is or descends from the finalized block @@ -32,17 +41,27 @@ A block is considered **finalizable** when all of the following hold: 4. It is either finalized or includes no candidates which have unresolved disputes or have lost a dispute. -### The leaf-selection rule +## The leaf-selection rule -We assume that every block has an implicit weight or score which can be used to compare blocks. In BABE, this is determined by the number of primary slots included in the chain. In PoW, this is the chain with either the most work or GHOST weight. +We assume that every block has an implicit weight or score which can be used to compare blocks. In BABE, this is +determined by the number of primary slots included in the chain. In PoW, this is the chain with either the most work or +GHOST weight. -The leaf-selection rule based on our definitions above is simple: we take the maximum-scoring viable leaf we are aware of. In the case of a tie we select the one with a lower lexicographical block hash. +The leaf-selection rule based on our definitions above is simple: we take the maximum-scoring viable leaf we are aware +of. In the case of a tie we select the one with a lower lexicographical block hash. -### The best-chain-containing rule +## The best-chain-containing rule -Finality gadgets, as mentioned above, will often impose an additional requirement to vote on a chain containing a specific block, known as the **required** block. Although this is typically the most recently finalized block, it is possible that it may be a block that is unfinalized. When receiving such a request: +Finality gadgets, as mentioned above, will often impose an additional requirement to vote on a chain containing a +specific block, known as the **required** block. Although this is typically the most recently finalized block, it is +possible that it may be a block that is unfinalized. When receiving such a request: 1. If the required block is the best finalized block, then select the best viable leaf. -2. If the required block is unfinalized and non-viable, then select the required block and go no further. This is likely an indication that something bad will be finalized in the network, which will never happen when approvals & disputes are functioning correctly. Nevertheless we account for the case here. -3. If the required block is unfinalized and viable, then iterate over the viable leaves in descending order by score and select the first one which contains the required block in its chain. Backwards iteration is a simple way to check this, but if unfinalized chains grow long then Merkle Mountain-Ranges will most likely be more efficient. - -Once selecting a leaf, the chain should be constrained to the maximum of the required block or the highest **finalizable** ancestor. +2. If the required block is unfinalized and non-viable, then select the required block and go no further. This is likely + an indication that something bad will be finalized in the network, which will never happen when approvals & disputes + are functioning correctly. Nevertheless we account for the case here. +3. If the required block is unfinalized and viable, then iterate over the viable leaves in descending order by score and + select the first one which contains the required block in its chain. Backwards iteration is a simple way to check + this, but if unfinalized chains grow long then Merkle Mountain-Ranges will most likely be more efficient. + +Once selecting a leaf, the chain should be constrained to the maximum of the required block or the highest +**finalizable** ancestor. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-disputes.md b/polkadot/roadmap/implementers-guide/src/protocol-disputes.md index ebbc534f199..2a4082cc07f 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-disputes.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-disputes.md @@ -4,14 +4,27 @@ Fast forward to [more detailed disputes requirements](./disputes-flow.md). ## Motivation and Background -All parachain blocks that end up in the finalized relay chain should be valid. This does not apply to blocks that are only backed, but not included. +All parachain blocks that end up in the finalized relay chain should be valid. This does not apply to blocks that are +only backed, but not included. We have two primary components for ensuring that nothing invalid ends up in the finalized relay chain: - * Approval Checking, as described [here](./protocol-approval.md) and implemented according to the [Approval Voting](node/approval/approval-voting.md) subsystem. This protocol can be shown to prevent invalid parachain blocks from making their way into the finalized relay chain as long as the amount of attempts are limited. - * Disputes, this protocol, which ensures that each attempt to include something bad is caught, and the offending validators are punished. -Disputes differ from backing and approval process (and can not be part of those) in that a dispute is independent of a particular fork, while both backing and approval operate on particular forks. This distinction is important! Approval voting stops, if an alternative fork which might not contain the currently approved candidate gets finalized. This is totally fine from the perspective of approval voting as its sole purpose is to make sure invalid blocks won't get finalized. For disputes on the other hand we have different requirements: Even though the "danger" is past and the adversaries were not able to get their invalid block approved, we still want them to get slashed for the attempt. Otherwise they just have been able to get a free try, but this is something we need to avoid in our security model, as it is based on the assumption that the probability of getting an invalid block finalized is very low and an attacker would get bankrupt before it could have tried often enough. - -Every dispute stems from a disagreement among two or more validators. If a bad actor creates a bad block, but the bad actor never distributes it to honest validators, then nobody will dispute it. Of course, such a situation is not even an attack on the network, so we don't need to worry about defending against it. + * Approval Checking, as described [here](./protocol-approval.md) and implemented according to the [Approval + Voting](node/approval/approval-voting.md) subsystem. This protocol can be shown to prevent invalid parachain blocks + from making their way into the finalized relay chain as long as the amount of attempts are limited. + * Disputes, this protocol, which ensures that each attempt to include something bad is caught, and the offending +validators are punished. Disputes differ from backing and approval process (and can not be part of those) in that a +dispute is independent of a particular fork, while both backing and approval operate on particular forks. This +distinction is important! Approval voting stops, if an alternative fork which might not contain the currently approved +candidate gets finalized. This is totally fine from the perspective of approval voting as its sole purpose is to make +sure invalid blocks won't get finalized. For disputes on the other hand we have different requirements: Even though the +"danger" is past and the adversaries were not able to get their invalid block approved, we still want them to get +slashed for the attempt. Otherwise they just have been able to get a free try, but this is something we need to avoid in +our security model, as it is based on the assumption that the probability of getting an invalid block finalized is very +low and an attacker would get bankrupt before it could have tried often enough. + +Every dispute stems from a disagreement among two or more validators. If a bad actor creates a bad block, but the bad +actor never distributes it to honest validators, then nobody will dispute it. Of course, such a situation is not even an +attack on the network, so we don't need to worry about defending against it. We are interested in identifying and deterring the following attack scenario: * A parablock included on a branch of the relay chain is bad @@ -20,48 +33,101 @@ We are also interested in identifying these additional scenarios: * A parablock backed on a branch of the relay chain is bad * A parablock seconded, but not backed on any branch of the relay chain, is bad. -Punishing misbehavior in the latter two scenarios doesn't effect our security guarantees and introduces substantial technical challenges as described in the `No Disputes for Non Included Candidates` section of [Dispute Coordinator](./node/disputes/dispute-coordinator.md). We therefore choose to punt on disputes in these cases, instead favoring the protocol simplicity resulting from only punishing in the first scenario. - -As covered in the [protocol overview](./protocol-overview.md), checking a parachain block requires 3 pieces of data: the parachain validation code, the [`AvailableData`](types/availability.md), and the [`CandidateReceipt`](types/candidate.md). The validation code is available on-chain, and published ahead of time, so that no two branches of the relay chain have diverging views of the validation code for a given parachain. Note that only for the first scenario, where the parablock has been included on a branch of the relay chain, is the data necessarily available. Thus, dispute processes should begin with an availability process to ensure availability of the `AvailableData`. This availability process will conclude quickly if the data is already available. If the data is not already available, then the initiator of the dispute must make it available. - -Disputes have both an on-chain and an off-chain component. Slashing and punishment is handled on-chain, so votes by validators on either side of the dispute must be placed on-chain. Furthermore, a dispute on one branch of the relay chain should be transposed to all other active branches of the relay chain. The fact that slashing occurs _in all histories_ is crucial for deterring attempts to attack the network. The attacker should not be able to escape with their funds because the network has moved on to another branch of the relay chain where no attack was attempted. - -In fact, this is why we introduce a distinction between _local_ and _remote_ disputes. We categorize disputes as either local or remote relative to any particular branch of the relay chain. Local disputes are about dealing with our first scenario, where a parablock has been included on the specific branch we are looking at. In these cases, the chain is corrupted all the way back to the point where the parablock was backed and must be discarded. However, as mentioned before, the dispute must propagate to all other branches of the relay chain. All other disputes are considered _remote_. For the on-chain component, when handling a dispute for a block which was not included in the current fork of the relay chain, it is impossible to discern between our attack scenarios. It is possible that the parablock was included somewhere, or backed somewhere, or wasn't backed anywhere. The on-chain component for handling these cases will be the same. +Punishing misbehavior in the latter two scenarios doesn't effect our security guarantees and introduces substantial +technical challenges as described in the `No Disputes for Non Included Candidates` section of [Dispute +Coordinator](./node/disputes/dispute-coordinator.md). We therefore choose to punt on disputes in these cases, instead +favoring the protocol simplicity resulting from only punishing in the first scenario. + +As covered in the [protocol overview](./protocol-overview.md), checking a parachain block requires 3 pieces of data: the +parachain validation code, the [`AvailableData`](types/availability.md), and the +[`CandidateReceipt`](types/candidate.md). The validation code is available on-chain, and published ahead of time, so +that no two branches of the relay chain have diverging views of the validation code for a given parachain. Note that +only for the first scenario, where the parablock has been included on a branch of the relay chain, is the data +necessarily available. Thus, dispute processes should begin with an availability process to ensure availability of the +`AvailableData`. This availability process will conclude quickly if the data is already available. If the data is not +already available, then the initiator of the dispute must make it available. + +Disputes have both an on-chain and an off-chain component. Slashing and punishment is handled on-chain, so votes by +validators on either side of the dispute must be placed on-chain. Furthermore, a dispute on one branch of the relay +chain should be transposed to all other active branches of the relay chain. The fact that slashing occurs _in all +histories_ is crucial for deterring attempts to attack the network. The attacker should not be able to escape with their +funds because the network has moved on to another branch of the relay chain where no attack was attempted. + +In fact, this is why we introduce a distinction between _local_ and _remote_ disputes. We categorize disputes as either +local or remote relative to any particular branch of the relay chain. Local disputes are about dealing with our first +scenario, where a parablock has been included on the specific branch we are looking at. In these cases, the chain is +corrupted all the way back to the point where the parablock was backed and must be discarded. However, as mentioned +before, the dispute must propagate to all other branches of the relay chain. All other disputes are considered _remote_. +For the on-chain component, when handling a dispute for a block which was not included in the current fork of the relay +chain, it is impossible to discern between our attack scenarios. It is possible that the parablock was included +somewhere, or backed somewhere, or wasn't backed anywhere. The on-chain component for handling these cases will be the +same. ## Initiation -Disputes are initiated by any validator who finds their opinion on the validity of a parablock in opposition to another issued statement. As all statements currently gathered by the relay chain imply validity, disputes will be initiated only by nodes which perceive that the parablock is bad. - -The initiation of a dispute begins off-chain. A validator signs a message indicating that it disputes the validity of the parablock and notifies all other validators, off-chain, of all of the statements it is aware of for the disputed parablock. These may be backing statements or approval-checking statements. It is worth noting that there is no special message type for initiating a dispute. It is the same message as is used to participate in a dispute and vote negatively. As such, there is no consensus required on who initiated a dispute, only on the fact that there is a dispute in-progress. - -In practice, the initiator of a dispute will be either one of the backers or one of the approval checkers for the parablock. If the result of execution is found to be invalid, the validator will initiate the dispute as described above. Furthermore, if the dispute occurs during the backing phase, the initiator must make the data available to other validators. If the dispute occurs during approval checking, the data is already available. - -Lastly, it is possible that for backing disputes, i.e. where the data is not already available among all validators, that an adversary may DoS the few parties who are checking the block to prevent them from distributing the data to other validators participating in the dispute process. Note that this can only occur pre-inclusion for any given parablock, so the downside of this attack is small and it is not security-critical to address these cases. However, we assume that the adversary can only prevent the validator from issuing messages for a limited amount of time. We also assume that there is a side-channel where the relay chain's governance mechanisms can trigger disputes by providing the full PoV and candidate receipt on-chain manually. +Disputes are initiated by any validator who finds their opinion on the validity of a parablock in opposition to another +issued statement. As all statements currently gathered by the relay chain imply validity, disputes will be initiated +only by nodes which perceive that the parablock is bad. + +The initiation of a dispute begins off-chain. A validator signs a message indicating that it disputes the validity of +the parablock and notifies all other validators, off-chain, of all of the statements it is aware of for the disputed +parablock. These may be backing statements or approval-checking statements. It is worth noting that there is no special +message type for initiating a dispute. It is the same message as is used to participate in a dispute and vote +negatively. As such, there is no consensus required on who initiated a dispute, only on the fact that there is a dispute +in-progress. + +In practice, the initiator of a dispute will be either one of the backers or one of the approval checkers for the +parablock. If the result of execution is found to be invalid, the validator will initiate the dispute as described +above. Furthermore, if the dispute occurs during the backing phase, the initiator must make the data available to other +validators. If the dispute occurs during approval checking, the data is already available. + +Lastly, it is possible that for backing disputes, i.e. where the data is not already available among all validators, +that an adversary may DoS the few parties who are checking the block to prevent them from distributing the data to other +validators participating in the dispute process. Note that this can only occur pre-inclusion for any given parablock, so +the downside of this attack is small and it is not security-critical to address these cases. However, we assume that the +adversary can only prevent the validator from issuing messages for a limited amount of time. We also assume that there +is a side-channel where the relay chain's governance mechanisms can trigger disputes by providing the full PoV and +candidate receipt on-chain manually. ## Dispute Participation -Once becoming aware of a dispute, it is the responsibility of all validators to participate in the dispute. Concretely, this means: - * Circulate all statements about the candidate that we are aware of - backing statements, approval checking statements, and dispute statements. +Once becoming aware of a dispute, it is the responsibility of all validators to participate in the dispute. Concretely, +this means: + * Circulate all statements about the candidate that we are aware of - backing statements, approval checking + statements, and dispute statements. * If we have already issued any type of statement about the candidate, go no further. - * Download the [`AvailableData`](types/availability.md). If possible, this should first be attempted from other dispute participants or backing validators, and then [(via erasure-coding)](node/availability/availability-recovery.md) from all validators. - * Extract the Validation Code from any recent relay chain block. Code is guaranteed to be kept available on-chain, so we don't need to download any particular fork of the chain. - * Execute the block under the validation code, using the `AvailableData`, and check that all outputs are correct, including the `erasure-root` of the [`CandidateReceipt`](types/candidate.md). + * Download the [`AvailableData`](types/availability.md). If possible, this should first be attempted from other + dispute participants or backing validators, and then [(via + erasure-coding)](node/availability/availability-recovery.md) from all validators. + * Extract the Validation Code from any recent relay chain block. Code is guaranteed to be kept available on-chain, so + we don't need to download any particular fork of the chain. + * Execute the block under the validation code, using the `AvailableData`, and check that all outputs are correct, + including the `erasure-root` of the [`CandidateReceipt`](types/candidate.md). * Issue a dispute participation statement to the effect of the validity of the candidate block. Disputes _conclude_ after ⅔ supermajority is reached in either direction. -The on-chain component of disputes can be initiated by providing any two conflicting votes and it also waits for a ⅔ supermajority on either side. The on-chain component also tracks which parablocks have already been disputed so the same parablock may only be disputed once on any particular branch of the relay chain. Lastly, it also tracks which blocks have been included on the current branch of the relay chain. When a dispute is initiated for a para, inclusion is halted for the para until the dispute concludes. +The on-chain component of disputes can be initiated by providing any two conflicting votes and it also waits for a ⅔ +supermajority on either side. The on-chain component also tracks which parablocks have already been disputed so the same +parablock may only be disputed once on any particular branch of the relay chain. Lastly, it also tracks which blocks +have been included on the current branch of the relay chain. When a dispute is initiated for a para, inclusion is halted +for the para until the dispute concludes. -The author of a relay chain block should initiate the on-chain component of disputes for all disputes which the chain is not aware of, and provide all statements to the on-chain component as well. This should all be done via _inherents_. +The author of a relay chain block should initiate the on-chain component of disputes for all disputes which the chain is +not aware of, and provide all statements to the on-chain component as well. This should all be done via _inherents_. Validators can learn about dispute statements in two ways: * Receiving them from other validators over gossip - * Scraping them from imported blocks of the relay chain. This is also used for validators to track other types of statements, such as backing statements. + * Scraping them from imported blocks of the relay chain. This is also used for validators to track other types of + statements, such as backing statements. -Validators are rewarded for providing statements to the chain as well as for participating in the dispute, on either side. However, the losing side of the dispute is slashed. +Validators are rewarded for providing statements to the chain as well as for participating in the dispute, on either +side. However, the losing side of the dispute is slashed. ## Dispute Conclusion -Disputes, roughly, are over when one side reaches a ⅔ supermajority. They may also never conclude without either side witnessing supermajority, which will only happen if the majority of validators are unable to vote for some reason. Furthermore, disputes on-chain will stay open for some fixed amount of time even after concluding, to accept new votes. +Disputes, roughly, are over when one side reaches a ⅔ supermajority. They may also never conclude without either side +witnessing supermajority, which will only happen if the majority of validators are unable to vote for some reason. +Furthermore, disputes on-chain will stay open for some fixed amount of time even after concluding, to accept new votes. Late votes, after the dispute already reached a ⅔ supermajority, must be rewarded (albeit a smaller amount) as well. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-overview.md b/polkadot/roadmap/implementers-guide/src/protocol-overview.md index fa5a866e612..96827e8c06b 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-overview.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-overview.md @@ -1,28 +1,61 @@ # Protocol Overview -This section aims to describe, at a high level, the actors and protocols involved in running parachains in Polkadot. Specifically, we describe how different actors communicate with each other, what data structures they keep both individually and collectively, and the high-level purpose on why they do these things. +This section aims to describe, at a high level, the actors and protocols involved in running parachains in Polkadot. +Specifically, we describe how different actors communicate with each other, what data structures they keep both +individually and collectively, and the high-level purpose on why they do these things. -Our top-level goal is to carry a parachain block from authoring to secure inclusion, and define a process which can be carried out repeatedly and in parallel for many different parachains to extend them over time. Understanding of the high-level approach taken here is important to provide context for the proposed architecture further on. The key parts of Polkadot relevant to this are the main Polkadot blockchain, known as the relay-chain, and the actors which provide security and inputs to this blockchain. +Our top-level goal is to carry a parachain block from authoring to secure inclusion, and define a process which can be +carried out repeatedly and in parallel for many different parachains to extend them over time. Understanding of the +high-level approach taken here is important to provide context for the proposed architecture further on. The key parts +of Polkadot relevant to this are the main Polkadot blockchain, known as the relay-chain, and the actors which provide +security and inputs to this blockchain. First, it's important to go over the main actors we have involved in this protocol. -1. Validators. These nodes are responsible for validating proposed parachain blocks. They do so by checking a Proof-of-Validity (PoV) of the block and ensuring that the PoV remains available. They put financial capital down as "skin in the game" which can be slashed (destroyed) if they are proven to have misvalidated. -1. Collators. These nodes are responsible for creating the Proofs-of-Validity that validators know how to check. Creating a PoV typically requires familiarity with the transaction format and block authoring rules of the parachain, as well as having access to the full state of the parachain. - -This implies a simple pipeline where collators send validators parachain blocks and their requisite PoV to check. Then, validators validate the block using the PoV, signing statements which describe either the positive or negative outcome, and with enough positive statements, the block can be noted on the relay-chain. Negative statements are not a veto but will lead to a dispute, with those on the wrong side being slashed. If another validator later detects that a validator or group of validators incorrectly signed a statement claiming a block was valid, then those validators will be _slashed_, with the checker receiving a bounty. - -However, there is a problem with this formulation. In order for another validator to check the previous group of validators' work after the fact, the PoV must remain _available_ so the other validator can fetch it in order to check the work. The PoVs are expected to be too large to include in the blockchain directly, so we require an alternate _data availability_ scheme which requires validators to prove that the inputs to their work will remain available, and so their work can be checked. Empirical tests tell us that many PoVs may be between 1 and 10MB during periods of heavy load. - -Here is a description of the Inclusion Pipeline: the path a parachain block (or parablock, for short) takes from creation to inclusion: +1. Validators. These nodes are responsible for validating proposed parachain blocks. They do so by checking a + Proof-of-Validity (PoV) of the block and ensuring that the PoV remains available. They put financial capital down as + "skin in the game" which can be slashed (destroyed) if they are proven to have misvalidated. +1. Collators. These nodes are responsible for creating the Proofs-of-Validity that validators know how to check. + Creating a PoV typically requires familiarity with the transaction format and block authoring rules of the parachain, + as well as having access to the full state of the parachain. + +This implies a simple pipeline where collators send validators parachain blocks and their requisite PoV to check. Then, +validators validate the block using the PoV, signing statements which describe either the positive or negative outcome, +and with enough positive statements, the block can be noted on the relay-chain. Negative statements are not a veto but +will lead to a dispute, with those on the wrong side being slashed. If another validator later detects that a validator +or group of validators incorrectly signed a statement claiming a block was valid, then those validators will be +_slashed_, with the checker receiving a bounty. + +However, there is a problem with this formulation. In order for another validator to check the previous group of +validators' work after the fact, the PoV must remain _available_ so the other validator can fetch it in order to check +the work. The PoVs are expected to be too large to include in the blockchain directly, so we require an alternate _data +availability_ scheme which requires validators to prove that the inputs to their work will remain available, and so +their work can be checked. Empirical tests tell us that many PoVs may be between 1 and 10MB during periods of heavy +load. + +Here is a description of the Inclusion Pipeline: the path a parachain block (or parablock, for short) takes from +creation to inclusion: 1. Validators are selected and assigned to parachains by the Validator Assignment routine. -1. A collator produces the parachain block, which is known as a parachain candidate or candidate, along with a PoV for the candidate. -1. The collator forwards the candidate and PoV to validators assigned to the same parachain via the [Collator Protocol](node/collators/collator-protocol.md). -1. The validators assigned to a parachain at a given point in time participate in the [Candidate Backing subsystem](node/backing/candidate-backing.md) to validate candidates that were put forward for validation. Candidates which gather enough signed validity statements from validators are considered "backable". Their backing is the set of signed validity statements. -1. A relay-chain block author, selected by BABE, can note up to one (1) backable candidate for each parachain to include in the relay-chain block alongside its backing. A backable candidate once included in the relay-chain is considered backed in that fork of the relay-chain. -1. Once backed in the relay-chain, the parachain candidate is considered to be "pending availability". It is not considered to be included as part of the parachain until it is proven available. -1. In the following relay-chain blocks, validators will participate in the [Availability Distribution subsystem](node/availability/availability-distribution.md) to ensure availability of the candidate. Information regarding the availability of the candidate will be noted in the subsequent relay-chain blocks. -1. Once the relay-chain state machine has enough information to consider the candidate's PoV as being available, the candidate is considered to be part of the parachain and is graduated to being a full parachain block, or parablock for short. +1. A collator produces the parachain block, which is known as a parachain candidate or candidate, along with a PoV for + the candidate. +1. The collator forwards the candidate and PoV to validators assigned to the same parachain via the [Collator + Protocol](node/collators/collator-protocol.md). +1. The validators assigned to a parachain at a given point in time participate in the [Candidate Backing + subsystem](node/backing/candidate-backing.md) to validate candidates that were put forward for validation. Candidates + which gather enough signed validity statements from validators are considered "backable". Their backing is the set of + signed validity statements. +1. A relay-chain block author, selected by BABE, can note up to one (1) backable candidate for each parachain to include + in the relay-chain block alongside its backing. A backable candidate once included in the relay-chain is considered + backed in that fork of the relay-chain. +1. Once backed in the relay-chain, the parachain candidate is considered to be "pending availability". It is not + considered to be included as part of the parachain until it is proven available. +1. In the following relay-chain blocks, validators will participate in the [Availability Distribution + subsystem](node/availability/availability-distribution.md) to ensure availability of the candidate. Information + regarding the availability of the candidate will be noted in the subsequent relay-chain blocks. +1. Once the relay-chain state machine has enough information to consider the candidate's PoV as being available, the + candidate is considered to be part of the parachain and is graduated to being a full parachain block, or parablock + for short. Note that the candidate can fail to be included in any of the following ways: @@ -31,21 +64,47 @@ Note that the candidate can fail to be included in any of the following ways: - The candidate is not selected by a relay-chain block author to be included in the relay chain - The candidate's PoV is not considered as available within a timeout and is discarded from the relay chain. -This process can be divided further down. Steps 2 & 3 relate to the work of the collator in collating and distributing the candidate to validators via the Collation Distribution Subsystem. Steps 3 & 4 relate to the work of the validators in the Candidate Backing Subsystem and the block author (itself a validator) to include the block into the relay chain. Steps 6, 7, and 8 correspond to the logic of the relay-chain state-machine (otherwise known as the Runtime) used to fully incorporate the block into the chain. Step 7 requires further work on the validators' parts to participate in the Availability Distribution Subsystem and include that information into the relay chain for step 8 to be fully realized. - -This brings us to the second part of the process. Once a parablock is considered available and part of the parachain, it is still "pending approval". At this stage in the pipeline, the parablock has been backed by a majority of validators in the group assigned to that parachain, and its data has been guaranteed available by the set of validators as a whole. Once it's considered available, the host will even begin to accept children of that block. At this point, we can consider the parablock as having been tentatively included in the parachain, although more confirmations are desired. However, the validators in the parachain-group (known as the "Parachain Validators" for that parachain) are sampled from a validator set which contains some proportion of byzantine, or arbitrarily malicious members. This implies that the Parachain Validators for some parachain may be majority-dishonest, which means that (secondary) approval checks must be done on the block before it can be considered approved. This is necessary only because the Parachain Validators for a given parachain are sampled from an overall validator set which is assumed to be up to <1/3 dishonest - meaning that there is a chance to randomly sample Parachain Validators for a parachain that are majority or fully dishonest and can back a candidate wrongly. The Approval Process allows us to detect such misbehavior after-the-fact without allocating more Parachain Validators and reducing the throughput of the system. A parablock's failure to pass the approval process will invalidate the block as well as all of its descendants. However, only the validators who backed the block in question will be slashed, not the validators who backed the descendants. +This process can be divided further down. Steps 2 & 3 relate to the work of the collator in collating and distributing +the candidate to validators via the Collation Distribution Subsystem. Steps 3 & 4 relate to the work of the validators +in the Candidate Backing Subsystem and the block author (itself a validator) to include the block into the relay chain. +Steps 6, 7, and 8 correspond to the logic of the relay-chain state-machine (otherwise known as the Runtime) used to +fully incorporate the block into the chain. Step 7 requires further work on the validators' parts to participate in the +Availability Distribution Subsystem and include that information into the relay chain for step 8 to be fully realized. + +This brings us to the second part of the process. Once a parablock is considered available and part of the parachain, it +is still "pending approval". At this stage in the pipeline, the parablock has been backed by a majority of validators in +the group assigned to that parachain, and its data has been guaranteed available by the set of validators as a whole. +Once it's considered available, the host will even begin to accept children of that block. At this point, we can +consider the parablock as having been tentatively included in the parachain, although more confirmations are desired. +However, the validators in the parachain-group (known as the "Parachain Validators" for that parachain) are sampled from +a validator set which contains some proportion of byzantine, or arbitrarily malicious members. This implies that the +Parachain Validators for some parachain may be majority-dishonest, which means that (secondary) approval checks must be +done on the block before it can be considered approved. This is necessary only because the Parachain Validators for a +given parachain are sampled from an overall validator set which is assumed to be up to <1/3 dishonest - meaning that +there is a chance to randomly sample Parachain Validators for a parachain that are majority or fully dishonest and can +back a candidate wrongly. The Approval Process allows us to detect such misbehavior after-the-fact without allocating +more Parachain Validators and reducing the throughput of the system. A parablock's failure to pass the approval process +will invalidate the block as well as all of its descendants. However, only the validators who backed the block in +question will be slashed, not the validators who backed the descendants. The Approval Process, at a glance, looks like this: -1. Parablocks that have been included by the Inclusion Pipeline are pending approval for a time-window known as the secondary checking window. +1. Parablocks that have been included by the Inclusion Pipeline are pending approval for a time-window known as the + secondary checking window. 1. During the secondary-checking window, validators randomly self-select to perform secondary checks on the parablock. -1. These validators, known in this context as secondary checkers, acquire the parablock and its PoV, and re-run the validation function. -1. The secondary checkers gossip the result of their checks. Contradictory results lead to escalation, where all validators are required to check the block. The validators on the losing side of the dispute are slashed. -1. At the end of the Approval Process, the parablock is either Approved or it is rejected. More on the rejection process later. +1. These validators, known in this context as secondary checkers, acquire the parablock and its PoV, and re-run the + validation function. +1. The secondary checkers gossip the result of their checks. Contradictory results lead to escalation, where all + validators are required to check the block. The validators on the losing side of the dispute are slashed. +1. At the end of the Approval Process, the parablock is either Approved or it is rejected. More on the rejection process + later. -More information on the Approval Process can be found in the dedicated section on [Approval](protocol-approval.md). More information on Disputes can be found in the dedicated section on [Disputes](protocol-disputes.md). +More information on the Approval Process can be found in the dedicated section on [Approval](protocol-approval.md). More +information on Disputes can be found in the dedicated section on [Disputes](protocol-disputes.md). -These two pipelines sum up the sequence of events necessary to extend and acquire full security on a Parablock. Note that the Inclusion Pipeline must conclude for a specific parachain before a new block can be accepted on that parachain. After inclusion, the Approval Process kicks off, and can be running for many parachain blocks at once. +These two pipelines sum up the sequence of events necessary to extend and acquire full security on a Parablock. Note +that the Inclusion Pipeline must conclude for a specific parachain before a new block can be accepted on that parachain. +After inclusion, the Approval Process kicks off, and can be running for many parachain blocks at once. Reiterating the lifecycle of a candidate: @@ -129,8 +188,11 @@ digraph { The diagram above shows the happy path of a block from (1) Candidate to the (7) Approved state. -It is also important to take note of the fact that the relay-chain is extended by BABE, which is a forkful algorithm. That means that different block authors can be chosen at the same time, and may not be building on the same block parent. Furthermore, the set of validators is not fixed, nor is the set of parachains. And even with the same set of validators and parachains, the validators' assignments to parachains is flexible. This means that the architecture proposed in the next chapters must deal with the variability and multiplicity of the network state. - +It is also important to take note of the fact that the relay-chain is extended by BABE, which is a forkful algorithm. +That means that different block authors can be chosen at the same time, and may not be building on the same block +parent. Furthermore, the set of validators is not fixed, nor is the set of parachains. And even with the same set of +validators and parachains, the validators' assignments to parachains is flexible. This means that the architecture +proposed in the next chapters must deal with the variability and multiplicity of the network state. ```dot process digraph { @@ -169,7 +231,9 @@ digraph { } ``` -In this example, group 1 has received block C while the others have not due to network asynchrony. Now, a validator from group 2 may be able to build another block on top of B, called `C'`. Assume that afterwards, some validators become aware of both C and `C'`, while others remain only aware of one. +In this example, group 1 has received block C while the others have not due to network asynchrony. Now, a validator from +group 2 may be able to build another block on top of B, called `C'`. Assume that afterwards, some validators become +aware of both C and `C'`, while others remain only aware of one. ```dot process digraph { @@ -216,4 +280,7 @@ digraph { } ``` -Those validators that are aware of many competing heads must be aware of the work happening on each one. They may contribute to some or a full extent on both. It is possible that due to network asynchrony two forks may grow in parallel for some time, although in the absence of an adversarial network this is unlikely in the case where there are validators who are aware of both chain heads. +Those validators that are aware of many competing heads must be aware of the work happening on each one. They may +contribute to some or a full extent on both. It is possible that due to network asynchrony two forks may grow in +parallel for some time, although in the absence of an adversarial network this is unlikely in the case where there are +validators who are aware of both chain heads. diff --git a/polkadot/roadmap/implementers-guide/src/pvf-prechecking.md b/polkadot/roadmap/implementers-guide/src/pvf-prechecking.md index 91cc8f9b6a2..44ddb0abbe0 100644 --- a/polkadot/roadmap/implementers-guide/src/pvf-prechecking.md +++ b/polkadot/roadmap/implementers-guide/src/pvf-prechecking.md @@ -2,20 +2,28 @@ ## Motivation -Parachains' validation function is described by a wasm module that we refer to as a PVF. Since a PVF is a wasm module the typical way of executing it is to compile it to machine code. +Parachains' validation function is described by a wasm module that we refer to as a PVF. Since a PVF is a wasm module +the typical way of executing it is to compile it to machine code. -Typically an optimizing compiler consists of algorithms that are able to optimize the resulting machine code heavily. However, while those algorithms perform quite well for a typical wasm code produced by standard toolchains (e.g. rustc/LLVM), those algorithms can be abused to consume a lot of resources. Moreover, since those algorithms are rather complex there is a lot of room for a bug that can crash the compiler. +Typically an optimizing compiler consists of algorithms that are able to optimize the resulting machine code heavily. +However, while those algorithms perform quite well for a typical wasm code produced by standard toolchains (e.g. +rustc/LLVM), those algorithms can be abused to consume a lot of resources. Moreover, since those algorithms are rather +complex there is a lot of room for a bug that can crash the compiler. -If compilation of a Parachain Validation Function (PVF) takes too long or uses too much memory, this can leave a node in limbo as to whether a candidate of that parachain is valid or not. +If compilation of a Parachain Validation Function (PVF) takes too long or uses too much memory, this can leave a node in +limbo as to whether a candidate of that parachain is valid or not. -The amount of time that a PVF takes to compile is a subjective resource limit and as such PVFs may be maliciously crafted so that there is e.g. a 50/50 split of validators which can and cannot compile and execute the PVF. +The amount of time that a PVF takes to compile is a subjective resource limit and as such PVFs may be maliciously +crafted so that there is e.g. a 50/50 split of validators which can and cannot compile and execute the PVF. This has the following implications: - In backing, inclusion may be slow due to backing groups being unable to execute the block - In approval checking, there may be many no-shows, leading to slow finality -- In disputes, neither side may reach supermajority. Nobody will get slashed and the chain will not be reverted or finalized. +- In disputes, neither side may reach supermajority. Nobody will get slashed and the chain will not be reverted or + finalized. -As a result of this issue we need a fairly hard guarantee that the PVFs of registered parachains/threads can be compiled within a reasonable amount of time. +As a result of this issue we need a fairly hard guarantee that the PVFs of registered parachains/threads can be compiled +within a reasonable amount of time. ## Solution @@ -23,9 +31,12 @@ The problem is solved by having a pre-checking process. ### Pre-checking -Pre-checking mostly consists of attempting to prepare (compile) the PVF WASM blob. We use more strict limits (e.g. timeouts) here compared to regular preparation for execution. This way errors during preparation later are likely unrelated to the PVF itself, as it already passed pre-checking. We can treat such errors as local node issues. +Pre-checking mostly consists of attempting to prepare (compile) the PVF WASM blob. We use more strict limits (e.g. +timeouts) here compared to regular preparation for execution. This way errors during preparation later are likely +unrelated to the PVF itself, as it already passed pre-checking. We can treat such errors as local node issues. -We also have an additional step where we attempt to instantiate the WASM runtime without running it. This is unrelated to preparation so we don't time it, but it does help us catch more issues. +We also have an additional step where we attempt to instantiate the WASM runtime without running it. This is unrelated +to preparation so we don't time it, but it does help us catch more issues. ### Protocol @@ -34,27 +45,41 @@ Pre-checking is run when a new validation code is included in the chain. A new P - A new parachain is registered. - An existing parachain signalled an upgrade of its validation code. -Before any of those operations finish, the PVF pre-checking vote is initiated. The PVF pre-checking vote is identified by the PVF code hash that is being voted on. If there is already PVF pre-checking process running, then no -new PVF pre-checking vote will be started. Instead, the operation just subscribes to the existing vote. +Before any of those operations finish, the PVF pre-checking vote is initiated. The PVF pre-checking vote is identified +by the PVF code hash that is being voted on. If there is already PVF pre-checking process running, then no new PVF +pre-checking vote will be started. Instead, the operation just subscribes to the existing vote. -The pre-checking vote can be concluded either by obtaining a threshold of votes for a decision, or if it expires. The threshold to accept is a supermajority of 2/3 of validators. We reject once a supermajority is no longer possible. +The pre-checking vote can be concluded either by obtaining a threshold of votes for a decision, or if it expires. The +threshold to accept is a supermajority of 2/3 of validators. We reject once a supermajority is no longer possible. -Each validator checks the list of PVFs available for voting. The vote is binary, i.e. accept or reject a given PVF. As soon as the threshold of votes are collected for one of the sides of the vote, the voting is concluded in that direction and the effects of the voting are enacted. +Each validator checks the list of PVFs available for voting. The vote is binary, i.e. accept or reject a given PVF. As +soon as the threshold of votes are collected for one of the sides of the vote, the voting is concluded in that direction +and the effects of the voting are enacted. -Only validators from the active set can participate in the vote. The set of active validators can change each session. That's why we reset the votes each session. A voting that observed a certain number of sessions will be rejected. +Only validators from the active set can participate in the vote. The set of active validators can change each session. +That's why we reset the votes each session. A voting that observed a certain number of sessions will be rejected. The effects of the PVF accepting depend on the operations requested it: -1. All onboardings subscribed to the approved PVF pre-checking process will get scheduled and after passing 2 session boundaries they will be onboarded. -1. All upgrades subscribed to the approved PVF pre-checking process will get scheduled very similarly to the existing process. Upgrades with pre-checking are really the same process that is just delayed by the time required for pre-checking voting. In case of instant approval the mechanism is exactly the same. +1. All onboardings subscribed to the approved PVF pre-checking process will get scheduled and after passing 2 session + boundaries they will be onboarded. +1. All upgrades subscribed to the approved PVF pre-checking process will get scheduled very similarly to the existing + process. Upgrades with pre-checking are really the same process that is just delayed by the time required for + pre-checking voting. In case of instant approval the mechanism is exactly the same. -In case PVF pre-checking process was concluded with rejection, then all the operations that are subscribed to the rejected PVF pre-checking process will be processed as follows. That is, onboarding or upgrading will be cancelled. +In case PVF pre-checking process was concluded with rejection, then all the operations that are subscribed to the +rejected PVF pre-checking process will be processed as follows. That is, onboarding or upgrading will be cancelled. The logic described above is implemented by the [paras] module. ### Subsystem -On the node-side, there is a PVF pre-checking [subsystem][pvf-prechecker-subsystem] that scans the chain for new PVFs via using [runtime APIs][pvf-runtime-api]. Upon finding a new PVF, the subsystem will initiate a PVF pre-checking request and wait for the result. Whenever the result is obtained, the subsystem will use the [runtime API][pvf-runtime-api] to submit a vote for the PVF. The vote is an unsigned transaction. The vote will be distributed via the gossip similarly to a normal transaction. Eventually a block producer will include the vote into the block where it will be handled by the [runtime][paras]. +On the node-side, there is a PVF pre-checking [subsystem][pvf-prechecker-subsystem] that scans the chain for new PVFs +via using [runtime APIs][pvf-runtime-api]. Upon finding a new PVF, the subsystem will initiate a PVF pre-checking +request and wait for the result. Whenever the result is obtained, the subsystem will use the [runtime +API][pvf-runtime-api] to submit a vote for the PVF. The vote is an unsigned transaction. The vote will be distributed +via the gossip similarly to a normal transaction. Eventually a block producer will include the vote into the block where +it will be handled by the [runtime][paras]. ## Summary @@ -62,11 +87,15 @@ Parachains' validation function is described by a wasm module that we refer to a In order to make the PVF usable for candidate validation it has to be registered on-chain. -As part of the registration process, it has to go through pre-checking. Pre-checking is a game of attempting preparation and additional checks, and reporting the results back on-chain. +As part of the registration process, it has to go through pre-checking. Pre-checking is a game of attempting preparation +and additional checks, and reporting the results back on-chain. -We define preparation as a process that: validates the consistency of the wasm binary (aka prevalidation) and the compilation of the wasm module into machine code (referred to as an artifact). +We define preparation as a process that: validates the consistency of the wasm binary (aka prevalidation) and the +compilation of the wasm module into machine code (referred to as an artifact). -Besides pre-checking, preparation can also be triggered by execution, since a compiled artifact is needed for the execution. If an artifact already exists, execution will skip preparation. If it does do preparation, execution uses a more lenient timeout than preparation, to avoid the situation where honest validators fail on valid, pre-checked PVFs. +Besides pre-checking, preparation can also be triggered by execution, since a compiled artifact is needed for the +execution. If an artifact already exists, execution will skip preparation. If it does do preparation, execution uses a +more lenient timeout than preparation, to avoid the situation where honest validators fail on valid, pre-checked PVFs. [paras]: runtime/paras.md [pvf-runtime-api]: runtime-api/pvf-prechecking.md diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/README.md b/polkadot/roadmap/implementers-guide/src/runtime-api/README.md index 740ffd38cce..d74100f2e26 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/README.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/README.md @@ -2,9 +2,16 @@ Runtime APIs are the means by which the node-side code extracts information from the state of the runtime. -Every block in the relay-chain contains a *state root* which is the root hash of a state trie encapsulating all storage of runtime modules after execution of the block. This is a cryptographic commitment to a unique state. We use the terminology of accessing the *state at* a block to refer accessing the state referred to by the state root of that block. +Every block in the relay-chain contains a *state root* which is the root hash of a state trie encapsulating all storage +of runtime modules after execution of the block. This is a cryptographic commitment to a unique state. We use the +terminology of accessing the *state at* a block to refer accessing the state referred to by the state root of that +block. -Although Runtime APIs are often used for simple storage access, they are actually empowered to do arbitrary computation. The implementation of the Runtime APIs lives within the Runtime as Wasm code and exposes `extern` functions that can be invoked with arguments and have a return value. Runtime APIs have access to a variety of host functions, which are contextual functions provided by the Wasm execution context, that allow it to carry out many different types of behaviors. +Although Runtime APIs are often used for simple storage access, they are actually empowered to do arbitrary computation. +The implementation of the Runtime APIs lives within the Runtime as Wasm code and exposes `extern` functions that can be +invoked with arguments and have a return value. Runtime APIs have access to a variety of host functions, which are +contextual functions provided by the Wasm execution context, that allow it to carry out many different types of +behaviors. Abilities provided by host functions includes: @@ -14,16 +21,25 @@ Abilities provided by host functions includes: * Optimized versions of cryptographic functions * More -So it is clear that Runtime APIs are a versatile and powerful tool to leverage the state of the chain. In general, we will use Runtime APIs for these purposes: +So it is clear that Runtime APIs are a versatile and powerful tool to leverage the state of the chain. In general, we +will use Runtime APIs for these purposes: * Access of a storage item * Access of a bundle of related storage items * Deriving a value from storage based on arguments * Submitting misbehavior reports -More broadly, we have the goal of using Runtime APIs to write Node-side code that fulfills the requirements set by the Runtime. In particular, the constraints set forth by the [Scheduler](../runtime/scheduler.md) and [Inclusion](../runtime/inclusion.md) modules. These modules are responsible for advancing paras with a two-phase protocol where validators are first chosen to validate and back a candidate and then required to ensure availability of referenced data. In the second phase, validators are meant to attest to those para-candidates that they have their availability chunk for. As the Node-side code needs to generate the inputs into these two phases, the runtime API needs to transmit information from the runtime that is aware of the Availability Cores model instantiated by the Scheduler and Inclusion modules. +More broadly, we have the goal of using Runtime APIs to write Node-side code that fulfills the requirements set by the +Runtime. In particular, the constraints set forth by the [Scheduler](../runtime/scheduler.md) and +[Inclusion](../runtime/inclusion.md) modules. These modules are responsible for advancing paras with a two-phase +protocol where validators are first chosen to validate and back a candidate and then required to ensure availability of +referenced data. In the second phase, validators are meant to attest to those para-candidates that they have their +availability chunk for. As the Node-side code needs to generate the inputs into these two phases, the runtime API needs +to transmit information from the runtime that is aware of the Availability Cores model instantiated by the Scheduler and +Inclusion modules. -Node-side code is also responsible for detecting and reporting misbehavior performed by other validators, and the set of Runtime APIs needs to provide methods for observing live disputes and submitting reports as transactions. +Node-side code is also responsible for detecting and reporting misbehavior performed by other validators, and the set of +Runtime APIs needs to provide methods for observing live disputes and submitting reports as transactions. The next sections will contain information on specific runtime APIs. The format is this: @@ -38,9 +54,16 @@ The next sections will contain information on specific runtime APIs. The format fn some_runtime_api(at: Block, arg1: Type1, arg2: Type2, ...) -> ReturnValue; ``` -Certain runtime APIs concerning the state of a para require the caller to provide an `OccupiedCoreAssumption`. This indicates how the result of the runtime API should be computed if there is a candidate from the para occupying an availability core in the [Inclusion Module](../runtime/inclusion.md). +Certain runtime APIs concerning the state of a para require the caller to provide an `OccupiedCoreAssumption`. This +indicates how the result of the runtime API should be computed if there is a candidate from the para occupying an +availability core in the [Inclusion Module](../runtime/inclusion.md). -The choices of assumption are whether the candidate occupying that core should be assumed to have been made available and included or timed out and discarded, along with a third option to assert that the core was not occupied. This choice affects everything from the parent head-data, the validation code, and the state of message-queues. Typically, users will take the assumption that either the core was free or that the occupying candidate was included, as timeouts are expected only in adversarial circumstances and even so, only in a small minority of blocks directly following validator set rotations. +The choices of assumption are whether the candidate occupying that core should be assumed to have been made available +and included or timed out and discarded, along with a third option to assert that the core was not occupied. This choice +affects everything from the parent head-data, the validation code, and the state of message-queues. Typically, users +will take the assumption that either the core was free or that the occupying candidate was included, as timeouts are +expected only in adversarial circumstances and even so, only in a small minority of blocks directly following validator +set rotations. ```rust /// An assumption being made about the state of an occupied core. @@ -52,4 +75,4 @@ enum OccupiedCoreAssumption { /// The core was not occupied to begin with. Free, } -``` \ No newline at end of file +``` diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md b/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md index 9402924f001..43288116089 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md @@ -1,14 +1,26 @@ # Availability Cores -Yields information on all availability cores. Cores are either free or occupied. Free cores can have paras assigned to them. Occupied cores don't, but they can become available part-way through a block due to bitfields and then have something scheduled on them. To allow optimistic validation of candidates, the occupied cores are accompanied by information on what is upcoming. This information can be leveraged when validators perceive that there is a high likelihood of a core becoming available based on bitfields seen, and then optimistically validate something that would become scheduled based on that, although there is no guarantee on what the block producer will actually include in the block. +Yields information on all availability cores. Cores are either free or occupied. Free cores can have paras assigned to +them. Occupied cores don't, but they can become available part-way through a block due to bitfields and then have +something scheduled on them. To allow optimistic validation of candidates, the occupied cores are accompanied by +information on what is upcoming. This information can be leveraged when validators perceive that there is a high +likelihood of a core becoming available based on bitfields seen, and then optimistically validate something that would +become scheduled based on that, although there is no guarantee on what the block producer will actually include in the +block. -See also the [Scheduler Module](../runtime/scheduler.md) for a high-level description of what an availability core is and why it exists. +See also the [Scheduler Module](../runtime/scheduler.md) for a high-level description of what an availability core is +and why it exists. ```rust fn availability_cores(at: Block) -> Vec; ``` -This is all the information that a validator needs about scheduling for the current block. It includes all information on [Scheduler](../runtime/scheduler.md) core-assignments and [Inclusion](../runtime/inclusion.md) state of blocks occupying availability cores. It includes data necessary to determine not only which paras are assigned now, but which cores are likely to become freed after processing bitfields, and exactly which bitfields would be necessary to make them so. The implementation of this runtime API should invoke `Scheduler::clear` and `Scheduler::schedule(Vec::new(), current_block_number + 1)` to ensure that scheduling is accurate. +This is all the information that a validator needs about scheduling for the current block. It includes all information +on [Scheduler](../runtime/scheduler.md) core-assignments and [Inclusion](../runtime/inclusion.md) state of blocks +occupying availability cores. It includes data necessary to determine not only which paras are assigned now, but which +cores are likely to become freed after processing bitfields, and exactly which bitfields would be necessary to make them +so. The implementation of this runtime API should invoke `Scheduler::clear` and `Scheduler::schedule(Vec::new(), +current_block_number + 1)` to ensure that scheduling is accurate. ```rust struct OccupiedCore { diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/candidate-pending-availability.md b/polkadot/roadmap/implementers-guide/src/runtime-api/candidate-pending-availability.md index 9c8969f6a95..e118757d83c 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/candidate-pending-availability.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/candidate-pending-availability.md @@ -1,6 +1,7 @@ # Candidate Pending Availability -Get the receipt of a candidate pending availability. This returns `Some` for any paras assigned to occupied cores in `availability_cores` and `None` otherwise. +Get the receipt of a candidate pending availability. This returns `Some` for any paras assigned to occupied cores in +`availability_cores` and `None` otherwise. ```rust fn candidate_pending_availability(at: Block, ParaId) -> Option; diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/disputes-info.md b/polkadot/roadmap/implementers-guide/src/runtime-api/disputes-info.md index 3548d5fb579..24f64a81538 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/disputes-info.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/disputes-info.md @@ -1,6 +1,9 @@ # Disputes Info -Get information about all disputes known by the chain as well as information about which validators the disputes subsystem will accept disputes from. These disputes may be either live or concluded. The [`DisputeState`](../types/disputes.md#disputestate) can be used to determine whether the dispute still accepts votes, as well as which validators' votes may be included. +Get information about all disputes known by the chain as well as information about which validators the disputes +subsystem will accept disputes from. These disputes may be either live or concluded. The +[`DisputeState`](../types/disputes.md#disputestate) can be used to determine whether the dispute still accepts votes, as +well as which validators' votes may be included. ```rust struct Dispute { diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/persisted-validation-data.md b/polkadot/roadmap/implementers-guide/src/runtime-api/persisted-validation-data.md index 2fd3e55c871..e741008a737 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/persisted-validation-data.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/persisted-validation-data.md @@ -1,6 +1,8 @@ # Persisted Validation Data -Yields the [`PersistedValidationData`](../types/candidate.md#persistedvalidationdata) for the given [`ParaId`](../types/candidate.md#paraid) along with an assumption that should be used if the para currently occupies a core: +Yields the [`PersistedValidationData`](../types/candidate.md#persistedvalidationdata) for the given +[`ParaId`](../types/candidate.md#paraid) along with an assumption that should be used if the para currently occupies a +core: ```rust /// Returns the persisted validation data for the given para and occupied core assumption. @@ -8,4 +10,4 @@ Yields the [`PersistedValidationData`](../types/candidate.md#persistedvalidation /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. fn persisted_validation_data(at: Block, ParaId, OccupiedCoreAssumption) -> Option; -``` \ No newline at end of file +``` diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/pvf-prechecking.md b/polkadot/roadmap/implementers-guide/src/runtime-api/pvf-prechecking.md index c74232367bf..ef9b801a81c 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/pvf-prechecking.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/pvf-prechecking.md @@ -4,18 +4,18 @@ There are two main runtime APIs to work with PVF pre-checking. -The first runtime API is designed to fetch all PVFs that require pre-checking voting. The PVFs are -identified by their code hashes. As soon as the PVF gains required support, the runtime API will -not return the PVF anymore. +The first runtime API is designed to fetch all PVFs that require pre-checking voting. The PVFs are identified by their +code hashes. As soon as the PVF gains required support, the runtime API will not return the PVF anymore. ```rust fn pvfs_require_precheck() -> Vec; ``` -The second runtime API is needed to submit the judgement for a PVF, whether it is approved or not. -The voting process uses unsigned transactions. The [`PvfCheckStatement`](../types/pvf-prechecking.md) is circulated through the network via gossip similar to a normal transaction. At some point the validator -will include the statement in the block, where it will be processed by the runtime. If that was the -last vote before gaining the super-majority, this PVF will not be returned by `pvfs_require_precheck` anymore. +The second runtime API is needed to submit the judgement for a PVF, whether it is approved or not. The voting process +uses unsigned transactions. The [`PvfCheckStatement`](../types/pvf-prechecking.md) is circulated through the network via +gossip similar to a normal transaction. At some point the validator will include the statement in the block, where it +will be processed by the runtime. If that was the last vote before gaining the super-majority, this PVF will not be +returned by `pvfs_require_precheck` anymore. ```rust fn submit_pvf_check_statement(stmt: PvfCheckStatement, signature: ValidatorSignature); diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/session-index.md b/polkadot/roadmap/implementers-guide/src/runtime-api/session-index.md index 1baf6a167db..d1441a3a739 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/session-index.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/session-index.md @@ -2,7 +2,8 @@ Get the session index that is expected at the child of a block. -In the [`Initializer`](../runtime/initializer.md) module, session changes are buffered by one block. The session index of the child of any relay block is always predictable by that block's state. +In the [`Initializer`](../runtime/initializer.md) module, session changes are buffered by one block. The session index +of the child of any relay block is always predictable by that block's state. This session index can be used to derive a [`SigningContext`](../types/candidate.md#signing-context). diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/validator-groups.md b/polkadot/roadmap/implementers-guide/src/runtime-api/validator-groups.md index 8815a021741..e5ed7b43aa9 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/validator-groups.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/validator-groups.md @@ -1,6 +1,7 @@ # Validator Groups -Yields the validator groups used during the current session. The validators in the groups are referred to by their index into the validator-set and this is assumed to be as-of the child of the block whose state is being queried. +Yields the validator groups used during the current session. The validators in the groups are referred to by their index +into the validator-set and this is assumed to be as-of the child of the block whose state is being queried. ```rust /// A helper data-type for tracking validator-group rotations. diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/validators.md b/polkadot/roadmap/implementers-guide/src/runtime-api/validators.md index b7f1d964754..e9d94d736b2 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/validators.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/validators.md @@ -1,6 +1,7 @@ # Validators -Yields the validator-set at the state of a given block. This validator set is always the one responsible for backing parachains in the child of the provided block. +Yields the validator-set at the state of a given block. This validator set is always the one responsible for backing +parachains in the child of the provided block. ```rust fn validators(at: Block) -> Vec; diff --git a/polkadot/roadmap/implementers-guide/src/runtime/README.md b/polkadot/roadmap/implementers-guide/src/runtime/README.md index 995b684b1f0..459f0e6b69d 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/README.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/README.md @@ -1,42 +1,83 @@ # Runtime Architecture -It's clear that we want to separate different aspects of the runtime logic into different modules. Modules define their own storage, routines, and entry-points. They also define initialization and finalization logic. +It's clear that we want to separate different aspects of the runtime logic into different modules. Modules define their +own storage, routines, and entry-points. They also define initialization and finalization logic. -Due to the (lack of) guarantees provided by a particular blockchain-runtime framework, there is no defined or dependable order in which modules' initialization or finalization logic will run. Supporting this blockchain-runtime framework is important enough to include that same uncertainty in our model of runtime modules in this guide. Furthermore, initialization logic of modules can trigger the entry-points or routines of other modules. This is one architectural pressure against dividing the runtime logic into multiple modules. However, in this case the benefits of splitting things up outweigh the costs, provided that we take certain precautions against initialization and entry-point races. +Due to the (lack of) guarantees provided by a particular blockchain-runtime framework, there is no defined or dependable +order in which modules' initialization or finalization logic will run. Supporting this blockchain-runtime framework is +important enough to include that same uncertainty in our model of runtime modules in this guide. Furthermore, +initialization logic of modules can trigger the entry-points or routines of other modules. This is one architectural +pressure against dividing the runtime logic into multiple modules. However, in this case the benefits of splitting +things up outweigh the costs, provided that we take certain precautions against initialization and entry-point races. -We also expect, although it's beyond the scope of this guide, that these runtime modules will exist alongside various other modules. This has two facets to consider. First, even if the modules that we describe here don't invoke each others' entry points or routines during initialization, we still have to protect against those other modules doing that. Second, some of those modules are expected to provide governance capabilities for the chain. Configuration exposed by parachain-host modules is mostly for the benefit of these governance modules, to allow the operators or community of the chain to tweak parameters. +We also expect, although it's beyond the scope of this guide, that these runtime modules will exist alongside various +other modules. This has two facets to consider. First, even if the modules that we describe here don't invoke each +others' entry points or routines during initialization, we still have to protect against those other modules doing that. +Second, some of those modules are expected to provide governance capabilities for the chain. Configuration exposed by +parachain-host modules is mostly for the benefit of these governance modules, to allow the operators or community of the +chain to tweak parameters. -The runtime's primary role is to manage scheduling and updating of parachains, as well as handling misbehavior reports and slashing. This guide doesn't focus on how parachains are registered, only that they are. Also, this runtime description assumes that validator sets are selected somehow, but doesn't assume any other details than a periodic _session change_ event. Session changes give information about the incoming validator set and the validator set of the following session. +The runtime's primary role is to manage scheduling and updating of parachains, as well as handling misbehavior reports +and slashing. This guide doesn't focus on how parachains are registered, only that they are. Also, this runtime +description assumes that validator sets are selected somehow, but doesn't assume any other details than a periodic +_session change_ event. Session changes give information about the incoming validator set and the validator set of the +following session. -The runtime also serves another role, which is to make data available to the Node-side logic via Runtime APIs. These Runtime APIs should be sufficient for the Node-side code to author blocks correctly. +The runtime also serves another role, which is to make data available to the Node-side logic via Runtime APIs. These +Runtime APIs should be sufficient for the Node-side code to author blocks correctly. -There is some functionality of the relay chain relating to parachains that we also consider beyond the scope of this document. In particular, all modules related to how parachains are registered aren't part of this guide, although we do provide routines that should be called by the registration process. +There is some functionality of the relay chain relating to parachains that we also consider beyond the scope of this +document. In particular, all modules related to how parachains are registered aren't part of this guide, although we do +provide routines that should be called by the registration process. We will split the logic of the runtime up into these modules: -* Initializer: manages initialization order of the other modules. -* Shared: manages shared storage and configurations for other modules. -* Configuration: manages configuration and configuration updates in a non-racy manner. -* Paras: manages chain-head and validation code for parachains. -* Scheduler: manages parachain scheduling as well as validator assignments. -* Inclusion: handles the inclusion and availability of scheduled parachains. -* SessionInfo: manages various session keys of validators and other params stored per session. -* Disputes: handles dispute resolution for included, available parablocks. -* Slashing: handles slashing logic for concluded disputes. -* HRMP: handles horizontal messages between paras. -* UMP: handles upward messages from a para to the relay chain. -* DMP: handles downward messages from the relay chain to the para. +- Initializer: manages initialization order of the other modules. +- Shared: manages shared storage and configurations for other modules. +- Configuration: manages configuration and configuration updates in a non-racy manner. +- Paras: manages chain-head and validation code for parachains. +- Scheduler: manages parachain scheduling as well as validator assignments. +- Inclusion: handles the inclusion and availability of scheduled parachains. +- SessionInfo: manages various session keys of validators and other params stored per session. +- Disputes: handles dispute resolution for included, available parablocks. +- Slashing: handles slashing logic for concluded disputes. +- HRMP: handles horizontal messages between paras. +- UMP: handles upward messages from a para to the relay chain. +- DMP: handles downward messages from the relay chain to the para. -The [Initializer module](initializer.md) is special - it's responsible for handling the initialization logic of the other modules to ensure that the correct initialization order and related invariants are maintained. The other modules won't specify a on-initialize logic, but will instead expose a special semi-private routine that the initialization module will call. The other modules are relatively straightforward and perform the roles described above. +The [Initializer module](initializer.md) is special - it's responsible for handling the initialization logic of the +other modules to ensure that the correct initialization order and related invariants are maintained. The other modules +won't specify a on-initialize logic, but will instead expose a special semi-private routine that the initialization +module will call. The other modules are relatively straightforward and perform the roles described above. -The Parachain Host operates under a changing set of validators. Time is split up into periodic sessions, where each session brings a potentially new set of validators. Sessions are buffered by one, meaning that the validators of the upcoming session `n+1` are determined at the end of session `n-1`, right before session `n` starts. Parachain Host runtime modules need to react to changes in the validator set, as it will affect the runtime logic for processing candidate backing, availability bitfields, and misbehavior reports. The Parachain Host modules can't determine ahead-of-time exactly when session change notifications are going to happen within the block (note: this depends on module initialization order again - better to put session before parachains modules). +The Parachain Host operates under a changing set of validators. Time is split up into periodic sessions, where each +session brings a potentially new set of validators. Sessions are buffered by one, meaning that the validators of the +upcoming session `n+1` are determined at the end of session `n-1`, right before session `n` starts. Parachain Host +runtime modules need to react to changes in the validator set, as it will affect the runtime logic for processing +candidate backing, availability bitfields, and misbehavior reports. The Parachain Host modules can't determine +ahead-of-time exactly when session change notifications are going to happen within the block (note: this depends on +module initialization order again - better to put session before parachains modules). -The relay chain is intended to use BABE or SASSAFRAS, which both have the property that a session changing at a block is determined not by the number of the block but instead by the time the block is authored. In some sense, sessions change in-between blocks, not at blocks. This has the side effect that the session of a child block cannot be determined solely by the parent block's identifier. Being able to unilaterally determine the validator-set at a specific block based on its parent hash would make a lot of Node-side logic much simpler. +The relay chain is intended to use BABE or SASSAFRAS, which both have the property that a session changing at a block is +determined not by the number of the block but instead by the time the block is authored. In some sense, sessions change +in-between blocks, not at blocks. This has the side effect that the session of a child block cannot be determined solely +by the parent block's identifier. Being able to unilaterally determine the validator-set at a specific block based on +its parent hash would make a lot of Node-side logic much simpler. -In order to regain the property that the validator set of a block is predictable by its parent block, we delay session changes' application to Parachains by 1 block. This means that if there is a session change at block X, that session change will be stored and applied during initialization of direct descendants of X. This principal side effect of this change is that the Parachains runtime can disagree with session or consensus modules about which session it currently is. Misbehavior reporting routines in particular will be affected by this, although not severely. The parachains runtime might believe it is the last block of the session while the system is really in the first block of the next session. In such cases, a historical validator-set membership proof will need to accompany any misbehavior report, although they typically do not need to during current-session misbehavior reports. +In order to regain the property that the validator set of a block is predictable by its parent block, we delay session +changes' application to Parachains by 1 block. This means that if there is a session change at block X, that session +change will be stored and applied during initialization of direct descendants of X. This principal side effect of this +change is that the Parachains runtime can disagree with session or consensus modules about which session it currently +is. Misbehavior reporting routines in particular will be affected by this, although not severely. The parachains runtime +might believe it is the last block of the session while the system is really in the first block of the next session. In +such cases, a historical validator-set membership proof will need to accompany any misbehavior report, although they +typically do not need to during current-session misbehavior reports. -So the other role of the initializer module is to forward session change notifications to modules in the initialization order. Session change is also the point at which the [Configuration Module](configuration.md) updates the configuration. Most of the other modules will handle changes in the configuration during their session change operation, so the initializer should provide both the old and new configuration to all the other -modules alongside the session change notification. This means that a session change notification should consist of the following data: +So the other role of the initializer module is to forward session change notifications to modules in the initialization +order. Session change is also the point at which the [Configuration Module](configuration.md) updates the configuration. +Most of the other modules will handle changes in the configuration during their session change operation, so the +initializer should provide both the old and new configuration to all the other modules alongside the session change +notification. This means that a session change notification should consist of the following data: ```rust struct SessionChangeNotification { diff --git a/polkadot/roadmap/implementers-guide/src/runtime/configuration.md b/polkadot/roadmap/implementers-guide/src/runtime/configuration.md index be62ab2d4d5..37885bd4815 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/configuration.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/configuration.md @@ -1,6 +1,11 @@ # Configuration Pallet -This module is responsible for managing all configuration of the parachain host in-flight. It provides a central point for configuration updates to prevent races between configuration changes and parachain-processing logic. Configuration can only change during the session change routine, and as this module handles the session change notification first it provides an invariant that the configuration does not change throughout the entire session. Both the [scheduler](scheduler.md) and [inclusion](inclusion.md) modules rely on this invariant to ensure proper behavior of the scheduler. +This module is responsible for managing all configuration of the parachain host in-flight. It provides a central point +for configuration updates to prevent races between configuration changes and parachain-processing logic. Configuration +can only change during the session change routine, and as this module handles the session change notification first it +provides an invariant that the configuration does not change throughout the entire session. Both the +[scheduler](scheduler.md) and [inclusion](inclusion.md) modules rely on this invariant to ensure proper behavior of the +scheduler. The configuration that we will be tracking is the [`HostConfiguration`](../types/runtime.md#host-configuration) struct. @@ -23,7 +28,8 @@ The session change routine works as follows: - If there is no pending configurations, then return early. - Take all pending configurations that are less than or equal to the current session index. - - Get the pending configuration with the highest session index and apply it to the current configuration. Discard the earlier ones if any. + - Get the pending configuration with the highest session index and apply it to the current configuration. Discard the + earlier ones if any. ## Routines @@ -41,17 +47,17 @@ pub fn configuration() -> HostConfiguration { Configuration::get() } -/// Schedules updating the host configuration. The update is given by the `updater` closure. The -/// closure takes the current version of the configuration and returns the new version. -/// Returns an `Err` if the closure returns a broken configuration. However, there are a couple of -/// exceptions: +/// Schedules updating the host configuration. The update is given by the `updater` closure. The +/// closure takes the current version of the configuration and returns the new version. +/// Returns an `Err` if the closure returns a broken configuration. However, there are a couple of +/// exceptions: /// -/// - if the configuration that was passed in the closure is already broken, then it will pass the +/// - if the configuration that was passed in the closure is already broken, then it will pass the /// update: you cannot break something that is already broken. /// - If the `BypassConsistencyCheck` flag is set, then the checks will be skipped. /// /// The changes made by this function will always be scheduled at session X, where X is the current session index + 2. -/// If there is already a pending update for X, then the closure will receive the already pending configuration for +/// If there is already a pending update for X, then the closure will receive the already pending configuration for /// session X. /// /// If there is already a pending update for the current session index + 1, then it won't be touched. Otherwise, @@ -61,4 +67,6 @@ fn schedule_config_update(updater: impl FnOnce(&mut HostConfiguration Option, Frozen: Option, ``` -> `byzantine_threshold` refers to the maximum number `f` of validators which may be byzantine. The total number of validators is `n = 3f + e` where `e in { 1, 2, 3 }`. +> `byzantine_threshold` refers to the maximum number `f` of validators which may be byzantine. The total number of +> validators is `n = 3f + e` where `e in { 1, 2, 3 }`. ## Session Change 1. If the current session is not greater than `config.dispute_period + 1`, nothing to do here. -1. Set `pruning_target = current_session - config.dispute_period - 1`. We add the extra `1` because we want to keep things for `config.dispute_period` _full_ sessions. - The stuff at the end of the most recent session has been around for a little over 0 sessions, not a little over 1. +1. Set `pruning_target = current_session - config.dispute_period - 1`. We add the extra `1` because we want to keep + things for `config.dispute_period` _full_ sessions. The stuff at the end of the most recent session has been around + for a little over 0 sessions, not a little over 1. 1. If `LastPrunedSession` is `None`, then set `LastPrunedSession` to `Some(pruning_target)` and return. -2. Otherwise, clear out all disputes and included candidates entries in the range `last_pruned..=pruning_target` and set `LastPrunedSession` to `Some(pruning_target)`. +1. Otherwise, clear out all disputes and included candidates entries in the range `last_pruned..=pruning_target` and set + `LastPrunedSession` to `Some(pruning_target)`. ## Block Initialization @@ -61,11 +82,10 @@ This is currently a `no op`. ## Routines * `filter_multi_dispute_data(MultiDisputeStatementSet) -> MultiDisputeStatementSet`: - 1. Takes a `MultiDisputeStatementSet` and filters it down to a `MultiDisputeStatementSet` - that satisfies all the criteria of `provide_multi_dispute_data`. That is, eliminating - ancient votes, duplicates and unconfirmed disputes. - This can be used by block authors to create the final submission in a block which is - guaranteed to pass the `provide_multi_dispute_data` checks. + 1. Takes a `MultiDisputeStatementSet` and filters it down to a `MultiDisputeStatementSet` that satisfies all the + criteria of `provide_multi_dispute_data`. That is, eliminating ancient votes, duplicates and unconfirmed disputes. + This can be used by block authors to create the final submission in a block which is guaranteed to pass the + `provide_multi_dispute_data` checks. * `provide_multi_dispute_data(MultiDisputeStatementSet) -> Vec<(SessionIndex, Hash)>`: 1. Pass on each dispute statement set to `provide_dispute_data`, propagating failure. @@ -76,46 +96,55 @@ This is currently a `no op`. 1. `SessionInfo` is used to check statement signatures and this function should fail if any signatures are invalid. 1. If there is no dispute under `Disputes`, create a new `DisputeState` with blank bitfields. 1. If `concluded_at` is `Some`, and is `concluded_at + config.post_conclusion_acceptance_period < now`, return false. - 2. Import all statements into the dispute. This should fail if any statements are duplicate or if the corresponding bit for the corresponding validator is set in the dispute already. - 3. If `concluded_at` is `None`, reward all statements. - 4. If `concluded_at` is `Some`, reward all statements slightly less. - 5. If either side now has supermajority and did not previously, slash the other side. This may be both sides, and we support this possibility in code, but note that this requires validators to participate on both sides which has negative expected value. Set `concluded_at` to `Some(now)` if it was `None`. - 6. If just concluded against the candidate and the `Included` map contains `(session, candidate)`: invoke `revert_and_freeze` with the stored block number. - 7. Return true if just initiated, false otherwise. - -* `disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState)>`: Get a list of all disputes and info about dispute state. + 1. Import all statements into the dispute. This should fail if any statements are duplicate or if the corresponding + bit for the corresponding validator is set in the dispute already. + 1. If `concluded_at` is `None`, reward all statements. + 1. If `concluded_at` is `Some`, reward all statements slightly less. + 1. If either side now has supermajority and did not previously, slash the other side. This may be both sides, and we + support this possibility in code, but note that this requires validators to participate on both sides which has + negative expected value. Set `concluded_at` to `Some(now)` if it was `None`. + 1. If just concluded against the candidate and the `Included` map contains `(session, candidate)`: invoke + `revert_and_freeze` with the stored block number. + 1. Return true if just initiated, false otherwise. + +* `disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState)>`: Get a list of all disputes and info about dispute + state. 1. Iterate over all disputes in `Disputes` and collect into a vector. * `note_included(SessionIndex, CandidateHash, included_in: BlockNumber)`: 1. Add `(SessionIndex, CandidateHash)` to the `Included` map with `included_in - 1` as the value. - 1. If there is a dispute under `(SessionIndex, CandidateHash)` that has concluded against the candidate, invoke `revert_and_freeze` with the stored block number. + 1. If there is a dispute under `(SessionIndex, CandidateHash)` that has concluded against the candidate, invoke + `revert_and_freeze` with the stored block number. -* `concluded_invalid(SessionIndex, CandidateHash) -> bool`: Returns whether a candidate has already concluded a dispute in the negative. +* `concluded_invalid(SessionIndex, CandidateHash) -> bool`: Returns whether a candidate has already concluded a dispute + in the negative. * `is_frozen()`: Load the value of `Frozen` from storage. Return true if `Some` and false if `None`. -* `last_valid_block()`: Load the value of `Frozen` from storage and return. None indicates that all blocks in the chain are potentially valid. +* `last_valid_block()`: Load the value of `Frozen` from storage and return. None indicates that all blocks in the chain + are potentially valid. * `revert_and_freeze(BlockNumber)`: 1. If `is_frozen()` return. 1. Set `Frozen` to `Some(BlockNumber)` to indicate a rollback to the block number. - 1. Issue a `Revert(BlockNumber + 1)` log to indicate a rollback of the block's child in the header chain, which is the same as a rollback to the block number. + 1. Issue a `Revert(BlockNumber + 1)` log to indicate a rollback of the block's child in the header chain, which is the + same as a rollback to the block number. # Disputes filtering All disputes delivered to the runtime by the client are filtered before the actual import. In this context actual import means persisted in the runtime storage. The filtering has got two purposes: -- Limit the amount of data saved onchain. -- Prevent persisting malicious dispute data onchain. +* Limit the amount of data saved onchain. +* Prevent persisting malicious dispute data onchain. *Implementation note*: Filtering is performed in function `filter_dispute_data` from `Disputes` pallet. The filtering is performed on the whole statement set which is about to be imported onchain. The following filters are applied: 1. Remove ancient disputes - if a dispute is concluded before the block number indicated in `OLDEST_ACCEPTED` parameter - it is removed from the set. `OLDEST_ACCEPTED` is a runtime configuration option. - *Implementation note*: `dispute_post_conclusion_acceptance_period` from - `HostConfiguration` is used in the current Polkadot/Kusama implementation. + it is removed from the set. `OLDEST_ACCEPTED` is a runtime configuration option. *Implementation note*: + `dispute_post_conclusion_acceptance_period` from `HostConfiguration` is used in the current Polkadot/Kusama + implementation. 2. Remove votes from unknown validators. If there is a vote from a validator which wasn't an authority in the session where the dispute was raised - they are removed. Please note that this step removes only single votes instead of removing the whole dispute. @@ -138,4 +167,4 @@ inconclusive disputes are not slashed. Thanks to the applied filtering (describe confident that there are no spam disputes in the runtime. So if a validator is not voting it is due to another reason (e.g. being under DoS attack). There is no reason to punish such validators with a slash. -*Implementation note*: Slashing is performed in `process_checked_dispute_data` from `Disputes` pallet. \ No newline at end of file +*Implementation note*: Slashing is performed in `process_checked_dispute_data` from `Disputes` pallet. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/dmp.md b/polkadot/roadmap/implementers-guide/src/runtime/dmp.md index f56df31934e..5aeb3bd68ef 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/dmp.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/dmp.md @@ -28,7 +28,8 @@ No initialization routine runs for this module. Candidate Acceptance Function: * `check_processed_downward_messages(P: ParaId, relay_parent_number: BlockNumber, processed_downward_messages: u32)`: - 1. Checks that `processed_downward_messages` is at least 1 if `DownwardMessageQueues` for `P` is not empty at the given `relay_parent_number`. + 1. Checks that `processed_downward_messages` is at least 1 if `DownwardMessageQueues` for `P` is not empty at the + given `relay_parent_number`. 1. Checks that `DownwardMessageQueues` for `P` is at least `processed_downward_messages` long. Candidate Enactment: @@ -38,11 +39,11 @@ Candidate Enactment: Utility routines. -`queue_downward_message(P: ParaId, M: DownwardMessage)`: - 1. Check if the size of `M` exceeds the `config.max_downward_message_size`. If so, return an error. - 1. Wrap `M` into `InboundDownwardMessage` using the current block number for `sent_at`. - 1. Obtain a new MQC link for the resulting `InboundDownwardMessage` and replace `DownwardMessageQueueHeads` for `P` with the resulting hash. - 1. Add the resulting `InboundDownwardMessage` into `DownwardMessageQueues` for `P`. +`queue_downward_message(P: ParaId, M: DownwardMessage)`: 1. Check if the size of `M` exceeds the + `config.max_downward_message_size`. If so, return an error. 1. Wrap `M` into `InboundDownwardMessage` using the + current block number for `sent_at`. 1. Obtain a new MQC link for the resulting `InboundDownwardMessage` and replace + `DownwardMessageQueueHeads` for `P` with the resulting hash. 1. Add the resulting `InboundDownwardMessage` into + `DownwardMessageQueues` for `P`. ## Session Change diff --git a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md index 927c14cd596..aa31491d72f 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md @@ -1,6 +1,7 @@ # HRMP Pallet -A module responsible for Horizontally Relay-routed Message Passing (HRMP). See [Messaging Overview](../messaging.md) for more details. +A module responsible for Horizontally Relay-routed Message Passing (HRMP). See [Messaging Overview](../messaging.md) for +more details. ## Storage @@ -132,7 +133,8 @@ Candidate Acceptance Function: 1. or in `HrmpChannelDigests` for `P` an entry with the block number should exist * `check_outbound_hrmp(sender: ParaId, Vec)`: 1. Checks that there are at most `config.hrmp_max_message_num_per_candidate` messages. - 1. Checks that horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages have the same recipient. + 1. Checks that horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages + have the same recipient. 1. For each horizontal message `M` with the channel `C` identified by `(sender, M.recipient)` check: 1. exists 1. `M`'s payload size doesn't exceed a preconfigured limit `C.max_message_size` @@ -143,42 +145,48 @@ Candidate Enactment: * `queue_outbound_hrmp(sender: ParaId, Vec)`: 1. For each horizontal message `HM` with the channel `C` identified by `(sender, HM.recipient)`: - 1. Append `HM` into `HrmpChannelContents` that corresponds to `C` with `sent_at` equals to the current block number. - 1. Locate or create an entry in `HrmpChannelDigests` for `HM.recipient` and append `sender` into the entry's list. + 1. Append `HM` into `HrmpChannelContents` that corresponds to `C` with `sent_at` equals to the current block + number. + 1. Locate or create an entry in `HrmpChannelDigests` for `HM.recipient` and append `sender` into the entry's + list. 1. Increment `C.msg_count` 1. Increment `C.total_size` by `HM`'s payload size - 1. Append a new link to the MQC and save the new head in `C.mqc_head`. Note that the current block number as of enactment is used for the link. + 1. Append a new link to the MQC and save the new head in `C.mqc_head`. Note that the current block number as of + enactment is used for the link. * `prune_hrmp(recipient, new_hrmp_watermark)`: - 1. From `HrmpChannelDigests` for `recipient` remove all entries up to an entry with block number equal to `new_hrmp_watermark`. - 1. From the removed digests construct a set of paras that sent new messages within the interval between the old and new watermarks. - 1. For each channel `C` identified by `(sender, recipient)` for each `sender` coming from the set, prune messages up to the `new_hrmp_watermark`. + 1. From `HrmpChannelDigests` for `recipient` remove all entries up to an entry with block number equal to + `new_hrmp_watermark`. + 1. From the removed digests construct a set of paras that sent new messages within the interval between the old and + new watermarks. + 1. For each channel `C` identified by `(sender, recipient)` for each `sender` coming from the set, prune messages up + to the `new_hrmp_watermark`. 1. For each pruned message `M` from channel `C`: 1. Decrement `C.msg_count` 1. Decrement `C.total_size` by `M`'s payload size. 1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark` > NOTE: That collecting digests can be inefficient and the time it takes grows very fast. Thanks to the aggressive - > parameterization this shouldn't be a big of a deal. - > If that becomes a problem consider introducing an extra dictionary which says at what block the given sender - > sent a message to the recipient. + > parameterization this shouldn't be a big of a deal. If that becomes a problem consider introducing an extra + > dictionary which says at what block the given sender sent a message to the recipient. ## Entry-points The following entry-points are meant to be used for HRMP channel management. -Those entry-points are meant to be called from a parachain. `origin` is defined as the `ParaId` of -the parachain executed the message. +Those entry-points are meant to be called from a parachain. `origin` is defined as the `ParaId` of the parachain +executed the message. * `hrmp_init_open_channel(recipient, proposed_max_capacity, proposed_max_message_size)`: 1. Check that the `origin` is not `recipient`. 1. Check that `proposed_max_capacity` is less or equal to `config.hrmp_channel_max_capacity` and greater than zero. - 1. Check that `proposed_max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater than zero. + 1. Check that `proposed_max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater + than zero. 1. Check that `recipient` is a valid para. 1. Check that there is no existing channel for `(origin, recipient)` in `HrmpChannels`. 1. Check that there is no existing open channel request (`origin`, `recipient`) in `HrmpOpenChannelRequests`. - 1. Check that the sum of the number of already opened HRMP channels by the `origin` (the size - of the set found `HrmpEgressChannelsIndex` for `origin`) and the number of open requests by the - `origin` (the value from `HrmpOpenChannelRequestCount` for `origin`) doesn't exceed the limit of - channels (`config.hrmp_max_parachain_outbound_channels` or `config.hrmp_max_parathread_outbound_channels`) minus 1. + 1. Check that the sum of the number of already opened HRMP channels by the `origin` (the size of the set found + `HrmpEgressChannelsIndex` for `origin`) and the number of open requests by the `origin` (the value from + `HrmpOpenChannelRequestCount` for `origin`) doesn't exceed the limit of channels + (`config.hrmp_max_parachain_outbound_channels` or `config.hrmp_max_parathread_outbound_channels`) minus 1. 1. Check that `origin`'s balance is more or equal to `config.hrmp_sender_deposit` 1. Reserve the deposit for the `origin` according to `config.hrmp_sender_deposit` 1. Increase `HrmpOpenChannelRequestCount` by 1 for `origin`. @@ -189,27 +197,26 @@ the parachain executed the message. 1. Set `max_message_size` to `proposed_max_message_size` 1. Set `max_total_size` to `config.hrmp_channel_max_total_size` 1. Send a downward message to `recipient` notifying about an inbound HRMP channel request. - - The DM is sent using `queue_downward_message`. - - The DM is represented by the `HrmpNewChannelOpenRequest` XCM message. - - `sender` is set to `origin`, - - `max_message_size` is set to `proposed_max_message_size`, - - `max_capacity` is set to `proposed_max_capacity`. + * The DM is sent using `queue_downward_message`. + * The DM is represented by the `HrmpNewChannelOpenRequest` XCM message. + * `sender` is set to `origin`, + * `max_message_size` is set to `proposed_max_message_size`, + * `max_capacity` is set to `proposed_max_capacity`. * `hrmp_accept_open_channel(sender)`: 1. Check that there is an existing request between (`sender`, `origin`) in `HrmpOpenChannelRequests` 1. Check that it is not confirmed. - 1. Check that the sum of the number of inbound HRMP channels opened to `origin` (the size of the set - found in `HrmpIngressChannelsIndex` for `origin`) and the number of accepted open requests by the `origin` - (the value from `HrmpAcceptedChannelRequestCount` for `origin`) doesn't exceed the limit of channels - (`config.hrmp_max_parachain_inbound_channels` or `config.hrmp_max_parathread_inbound_channels`) - minus 1. + 1. Check that the sum of the number of inbound HRMP channels opened to `origin` (the size of the set found in + `HrmpIngressChannelsIndex` for `origin`) and the number of accepted open requests by the `origin` (the value from + `HrmpAcceptedChannelRequestCount` for `origin`) doesn't exceed the limit of channels + (`config.hrmp_max_parachain_inbound_channels` or `config.hrmp_max_parathread_inbound_channels`) minus 1. 1. Check that `origin`'s balance is more or equal to `config.hrmp_recipient_deposit`. 1. Reserve the deposit for the `origin` according to `config.hrmp_recipient_deposit` 1. For the request in `HrmpOpenChannelRequests` identified by `(sender, P)`, set `confirmed` flag to `true`. 1. Increase `HrmpAcceptedChannelRequestCount` by 1 for `origin`. 1. Send a downward message to `sender` notifying that the channel request was accepted. - - The DM is sent using `queue_downward_message`. - - The DM is represented by the `HrmpChannelAccepted` XCM message. - - `recipient` is set to `origin`. + * The DM is sent using `queue_downward_message`. + * The DM is represented by the `HrmpChannelAccepted` XCM message. + * `recipient` is set to `origin`. * `hrmp_cancel_open_request(ch)`: 1. Check that `origin` is either `ch.sender` or `ch.recipient` 1. Check that the open channel request `ch` exists. @@ -221,15 +228,15 @@ the parachain executed the message. 1. Check that `origin` is either `ch.sender` or `ch.recipient` 1. Check that `HrmpChannels` for `ch` exists. 1. Check that `ch` is not in the `HrmpCloseChannelRequests` set. - 1. If not already there, insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch` - and append `ch` to `HrmpCloseChannelRequestsList`. + 1. If not already there, insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch` and append `ch` to + `HrmpCloseChannelRequestsList`. 1. Send a downward message to the opposite party notifying about the channel closing. - - The DM is sent using `queue_downward_message`. - - The DM is represented by the `HrmpChannelClosing` XCM message with: - - `initator` is set to `origin`, - - `sender` is set to `ch.sender`, - - `recipient` is set to `ch.recipient`. - - The opposite party is `ch.sender` if `origin` is `ch.recipient` and `ch.recipient` if `origin` is `ch.sender`. + * The DM is sent using `queue_downward_message`. + * The DM is represented by the `HrmpChannelClosing` XCM message with: + * `initator` is set to `origin`, + * `sender` is set to `ch.sender`, + * `recipient` is set to `ch.recipient`. + * The opposite party is `ch.sender` if `origin` is `ch.recipient` and `ch.recipient` if `origin` is `ch.sender`. ## Session Change @@ -241,13 +248,15 @@ the parachain executed the message. 1. Remove `HrmpOpenChannelRequests` and `HrmpOpenChannelRequestsList` for `(P, _)` and `(_, P)`. 1. For each removed channel request `C`: 1. Unreserve the sender's deposit if the sender is not present in `outgoing_paras` - 1. Unreserve the recipient's deposit if `C` is confirmed and the recipient is not present in `outgoing_paras` -1. For each channel designator `D` in `HrmpOpenChannelRequestsList` we query the request `R` from `HrmpOpenChannelRequests`: + 1. Unreserve the recipient's deposit if `C` is confirmed and the recipient is not present in + `outgoing_paras` +1. For each channel designator `D` in `HrmpOpenChannelRequestsList` we query the request `R` from + `HrmpOpenChannelRequests`: 1. if `R.confirmed = true`, 1. if both `D.sender` and `D.recipient` are not offboarded. 1. create a new channel `C` between `(D.sender, D.recipient)`. - 1. Initialize the `C.sender_deposit` with `R.sender_deposit` and `C.recipient_deposit` - with the value found in the configuration `config.hrmp_recipient_deposit`. + 1. Initialize the `C.sender_deposit` with `R.sender_deposit` and `C.recipient_deposit` with the value + found in the configuration `config.hrmp_recipient_deposit`. 1. Insert `sender` into the set `HrmpIngressChannelsIndex` for the `recipient`. 1. Insert `recipient` into the set `HrmpEgressChannelsIndex` for the `sender`. 1. decrement `HrmpOpenChannelRequestCount` for `D.sender` by 1. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index 3fe7711ae2d..f73df209981 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -1,6 +1,7 @@ # Inclusion Pallet -The inclusion module is responsible for inclusion and availability of scheduled parachains. It also manages the UMP dispatch queue of each parachain. +The inclusion module is responsible for inclusion and availability of scheduled parachains. It also manages the UMP +dispatch queue of each parachain. ## Storage @@ -37,11 +38,9 @@ PendingAvailabilityCommitments: map ParaId => CandidateCommitments; ## Config Dependencies -* `MessageQueue`: - The message queue provides general queueing and processing functionality. Currently it - replaces the old `UMP` dispatch queue. Other use-cases can be implemented as well by - adding new variants to `AggregateMessageOrigin`. Normally it should be set to an instance - of the `MessageQueue` pallet. +* `MessageQueue`: The message queue provides general queueing and processing functionality. Currently it replaces the + old `UMP` dispatch queue. Other use-cases can be implemented as well by adding new variants to + `AggregateMessageOrigin`. Normally it should be set to an instance of the `MessageQueue` pallet. ## Session Change @@ -49,11 +48,13 @@ PendingAvailabilityCommitments: map ParaId => CandidateCommitments; 1. Clear out all validator bitfields. Optional: -1. The UMP queue of all outgoing paras can be "swept". This would prevent the dispatch queue from automatically being serviced. It is a consideration for the chain and specific behaviour is not defined. +1. The UMP queue of all outgoing paras can be "swept". This would prevent the dispatch queue from automatically being + serviced. It is a consideration for the chain and specific behaviour is not defined. ## Initialization -No initialization routine runs for this module. However, the initialization of the `MessageQueue` pallet will attempt to process any pending UMP messages. +No initialization routine runs for this module. However, the initialization of the `MessageQueue` pallet will attempt to +process any pending UMP messages. ## Routines @@ -63,20 +64,19 @@ All failed checks should lead to an unrecoverable error making the block invalid * `process_bitfields(expected_bits, Bitfields, core_lookup: Fn(CoreIndex) -> Option)`: 1. Call `sanitize_bitfields` and use the sanitized `signed_bitfields` from now on. 1. Call `sanitize_backed_candidates` and use the sanitized `backed_candidates` from now on. - 1. Apply each bit of bitfield to the corresponding pending candidate, looking up on-demand parachain cores using the `core_lookup`. Disregard bitfields that have a `1` bit for any free cores. - 1. For each applied bit of each availability-bitfield, set the bit for the validator in the `CandidatePendingAvailability`'s `availability_votes` bitfield. Track all candidates that now have >2/3 of bits set in their `availability_votes`. These candidates are now available and can be enacted. + 1. Apply each bit of bitfield to the corresponding pending candidate, looking up on-demand parachain cores using the + `core_lookup`. Disregard bitfields that have a `1` bit for any free cores. + 1. For each applied bit of each availability-bitfield, set the bit for the validator in the + `CandidatePendingAvailability`'s `availability_votes` bitfield. Track all candidates that now have >2/3 of bits set + in their `availability_votes`. These candidates are now available and can be enacted. 1. For all now-available candidates, invoke the `enact_candidate` routine with the candidate and relay-parent number. - 1. Return a list of `(CoreIndex, CandidateHash)` from freed cores consisting of the cores where candidates have become available. -* `sanitize_bitfields( - unchecked_bitfields: UncheckedSignedAvailabilityBitfields, - disputed_bitfield: DisputedBitfield, - expected_bits: usize, - parent_hash: T::Hash, - session_index: SessionIndex, - validators: &[ValidatorId], - full_check: FullCheck, - )`: - 1. check that `disputed_bitfield` has the same number of bits as the `expected_bits`, iff not return early with an empty vec. + 1. Return a list of `(CoreIndex, CandidateHash)` from freed cores consisting of the cores where candidates have become + available. +* `sanitize_bitfields( unchecked_bitfields: UncheckedSignedAvailabilityBitfields, + disputed_bitfield: DisputedBitfield, expected_bits: usize, parent_hash: T::Hash, session_index: SessionIndex, + validators: &[ValidatorId], full_check: FullCheck, )`: + 1. check that `disputed_bitfield` has the same number of bits as the `expected_bits`, iff not return early with an + empty vec. 1. each of the below checks is for each bitfield. If a check does not pass the bitfield will be skipped. 1. check that there are no bits set that reference a disputed candidate. 1. check that the number of bits is equal to `expected_bits`. @@ -84,41 +84,58 @@ All failed checks should lead to an unrecoverable error making the block invalid 1. check that the validator bit index is not out of bounds. 1. check the validators signature, iff `full_check=FullCheck::Yes`. -* `sanitize_backed_candidates) -> bool>( - mut backed_candidates: Vec>, - candidate_has_concluded_invalid_dispute: F, - scheduled: &[CoreAssignment], - ) ` +* `sanitize_backed_candidates) -> bool>( mut + backed_candidates: Vec>, candidate_has_concluded_invalid_dispute: F, scheduled: + &[CoreAssignment], )` 1. filter out any backed candidates that have concluded invalid. 1. filters backed candidates whom's paraid was scheduled by means of the provided `scheduled` parameter. 1. sorts remaining candidates with respect to the core index assigned to them. -* `process_candidates(allowed_relay_parents, BackedCandidates, scheduled: Vec, group_validators: Fn(GroupIndex) -> Option>)`: +* `process_candidates(allowed_relay_parents, BackedCandidates, scheduled: Vec, group_validators: + Fn(GroupIndex) -> Option>)`: > For details on `AllowedRelayParentsTracker` see documentation for [Shared](./shared.md) module. - 1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`. + 1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores + appear in assignments in `scheduled`. 1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates. 1. check that the relay-parent from each candidate receipt is one of the allowed relay-parents. 1. check that there is no candidate pending availability for any scheduled `ParaId`. - 1. check that each candidate's `validation_data_hash` corresponds to a `PersistedValidationData` computed from the state of the context block. + 1. check that each candidate's `validation_data_hash` corresponds to a `PersistedValidationData` computed from the + state of the context block. 1. If the core assignment includes a specific collator, ensure the backed candidate is issued by that collator. - 1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID. + 1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` + of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` + for the given para ID. 1. Check the collator's signature on the candidate data. - 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup, while group indices are computed by `Scheduler` according to group rotation info. - 1. call `check_upward_messages(config, para, commitments.upward_messages)` to check that the upward messages are valid. - 1. call `Dmp::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained. - 1. call `Hrmp::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark. - 1. using `Hrmp::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a valid set of horizontal messages - 1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` bitfield. + 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators + assigned to the groups, fetched with the `group_validators` lookup, while group indices are computed by `Scheduler` + according to group rotation info. + 1. call `check_upward_messages(config, para, commitments.upward_messages)` to check that the upward messages are + valid. + 1. call `Dmp::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ + is properly drained. + 1. call `Hrmp::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing + the HRMP watermark. + 1. using `Hrmp::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a + valid set of horizontal messages + 1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` + bitfield. 1. create a corresponding entry in the `PendingAvailabilityCommitments` with the commitments. - 1. Return a `Vec` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex. + 1. Return a `Vec` of all scheduled cores of the list of passed assignments that a candidate was + successfully backed for, sorted ascending by CoreIndex. * `enact_candidate(relay_parent_number: BlockNumber, CommittedCandidateReceipt)`: - 1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number, config)`. - > TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it. + 1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number, + config)`. + > TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session + > boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might + > have changed and the para may de-sync from the host's understanding of it. 1. Reward all backing validators of each candidate, contained within the `backers` field. - 1. call `receive_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments). + 1. call `receive_upward_messages` for each backed candidate, using the + [`UpwardMessage`s](../types/messages.md#upward-message) from the + [`CandidateCommitments`](../types/candidate.md#candidate-commitments). 1. call `Dmp::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`. 1. call `Hrmp::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`. - 1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment, + 1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from + the commitment, 1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`. * `collect_pending`: @@ -130,21 +147,28 @@ All failed checks should lead to an unrecoverable error making the block invalid // return a vector of cleaned-up core IDs. } ``` -* `force_enact(ParaId)`: Forcibly enact the candidate with the given ID as though it had been deemed available by bitfields. Is a no-op if there is no candidate pending availability for this para-id. This should generally not be used but it is useful during execution of Runtime APIs, where the changes to the state are expected to be discarded directly after. -* `candidate_pending_availability(ParaId) -> Option`: returns the `CommittedCandidateReceipt` pending availability for the para provided, if any. -* `pending_availability(ParaId) -> Option`: returns the metadata around the candidate pending availability for the para, if any. -* `collect_disputed(disputed: Vec) -> Vec`: Sweeps through all paras pending availability. If the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and the commitments. Return a vector of cleaned-up core IDs. +* `force_enact(ParaId)`: Forcibly enact the candidate with the given ID as though it had been deemed available by + bitfields. Is a no-op if there is no candidate pending availability for this para-id. This should generally not be + used but it is useful during execution of Runtime APIs, where the changes to the state are expected to be discarded + directly after. +* `candidate_pending_availability(ParaId) -> Option`: returns the `CommittedCandidateReceipt` + pending availability for the para provided, if any. +* `pending_availability(ParaId) -> Option`: returns the metadata around the candidate + pending availability for the para, if any. +* `collect_disputed(disputed: Vec) -> Vec`: Sweeps through all paras pending availability. If + the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and + the commitments. Return a vector of cleaned-up core IDs. These functions were formerly part of the UMP pallet: * `check_upward_messages(P: ParaId, Vec)`: - 1. Checks that the parachain is not currently offboarding and error otherwise. + 1. Checks that the parachain is not currently offboarding and error otherwise. 1. Checks that there are at most `config.max_upward_message_num_per_candidate` messages to be enqueued. 1. Checks that no message exceeds `config.max_upward_message_size`. 1. Checks that the total resulting queue size would not exceed `co`. - 1. Verify that queuing up the messages could not result in exceeding the queue's footprint - according to the config items `config.max_upward_queue_count` and `config.max_upward_queue_size`. The queue's current footprint is provided in `well_known_keys` - in order to facilitate oraclisation on to the para. + 1. Verify that queuing up the messages could not result in exceeding the queue's footprint according to the config + items `config.max_upward_queue_count` and `config.max_upward_queue_size`. The queue's current footprint is provided + in `well_known_keys` in order to facilitate oraclisation on to the para. Candidate Enactment: diff --git a/polkadot/roadmap/implementers-guide/src/runtime/initializer.md b/polkadot/roadmap/implementers-guide/src/runtime/initializer.md index 19dfcbde50a..a8522b36969 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/initializer.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/initializer.md @@ -1,6 +1,7 @@ # Initializer Pallet -This module is responsible for initializing the other modules in a deterministic order. It also has one other purpose as described in the overview of the runtime: accepting and forwarding session change notifications. +This module is responsible for initializing the other modules in a deterministic order. It also has one other purpose as +described in the overview of the runtime: accepting and forwarding session change notifications. ## Storage @@ -15,7 +16,9 @@ BufferedSessionChanges: Vec<(BlockNumber, ValidatorSet, ValidatorSet)>; ## Initialization -Before initializing modules, remove all changes from the `BufferedSessionChanges` with number less than or equal to the current block number, and apply the last one. The session change is applied to all modules in the same order as initialization. +Before initializing modules, remove all changes from the `BufferedSessionChanges` with number less than or equal to the +current block number, and apply the last one. The session change is applied to all modules in the same order as +initialization. The other parachains modules are initialized in this order: @@ -30,16 +33,24 @@ The other parachains modules are initialized in this order: 1. UMP 1. HRMP -The [Configuration Module](configuration.md) is first, since all other modules need to operate under the same configuration as each other. Then the [Shared](shared.md) module is invoked, which determines the set of active validators. It would lead to inconsistency if, for example, the scheduler ran first and then the configuration was updated before the Inclusion module. +The [Configuration Module](configuration.md) is first, since all other modules need to operate under the same +configuration as each other. Then the [Shared](shared.md) module is invoked, which determines the set of active +validators. It would lead to inconsistency if, for example, the scheduler ran first and then the configuration was +updated before the Inclusion module. Set `HasInitialized` to true. ## Session Change -Store the session change information in `BufferedSessionChange` along with the block number at which it was submitted, plus one. Although the expected operational parameters of the block authorship system should prevent more than one change from being buffered at any time, it may occur. Regardless, we always need to track the block number at which the session change can be applied so as to remain flexible over session change notifications being issued before or after initialization of the current block. +Store the session change information in `BufferedSessionChange` along with the block number at which it was submitted, +plus one. Although the expected operational parameters of the block authorship system should prevent more than one +change from being buffered at any time, it may occur. Regardless, we always need to track the block number at which the +session change can be applied so as to remain flexible over session change notifications being issued before or after +initialization of the current block. ## Finalization -Finalization order is less important in this case than initialization order, so we finalize the modules in the reverse order from initialization. +Finalization order is less important in this case than initialization order, so we finalize the modules in the reverse +order from initialization. Set `HasInitialized` to false. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md index 405468c609a..4a771f1df64 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md @@ -1,15 +1,27 @@ # `ParaInherent` -This module is responsible for providing all data given to the runtime by the block author to the various parachains modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also "inherent", in that it is provided with no origin by the block author. The data within it carries its own authentication; i.e. the data takes the form of signed statements by validators. Invalid data will be filtered and not applied. +This module is responsible for providing all data given to the runtime by the block author to the various parachains +modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also +"inherent", in that it is provided with no origin by the block author. The data within it carries its own +authentication; i.e. the data takes the form of signed statements by validators. Invalid data will be filtered and not +applied. -This module does not have the same initialization/finalization concerns as the others, as it only requires that entry points be triggered after all modules have initialized and that finalization happens after entry points are triggered. Both of these are assumptions we have already made about the runtime's order of operations, so this module doesn't need to be initialized or finalized by the `Initializer`. +This module does not have the same initialization/finalization concerns as the others, as it only requires that entry +points be triggered after all modules have initialized and that finalization happens after entry points are triggered. +Both of these are assumptions we have already made about the runtime's order of operations, so this module doesn't need +to be initialized or finalized by the `Initializer`. There are a couple of important notes to the operations in this inherent as they relate to disputes. -1. We don't accept bitfields or backed candidates if in "governance-only" mode from having a local dispute conclude on this fork. -1. When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the block before blocks are included as opposed to backing. It's important to do this before processing bitfields. -1. `Inclusion::collect_disputed` is kind of expensive so it's important to gate this on whether there are actually any new disputes. Which should be never. -1. And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's important to import dispute statements before backing, but this is already the case as disputes are imported before processing bitfields. +1. We don't accept bitfields or backed candidates if in "governance-only" mode from having a local dispute conclude on + this fork. +1. When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the + block before blocks are included as opposed to backing. It's important to do this before processing bitfields. +1. `Inclusion::collect_disputed` is kind of expensive so it's important to gate this on whether there are actually any + new disputes. Which should be never. +1. And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's + important to import dispute statements before backing, but this is already the case as disputes are imported before + processing bitfields. ## Storage @@ -32,26 +44,19 @@ OnChainVotes: Option, * `enter`: This entry-point accepts one parameter: [`ParaInherentData`](../types/runtime.md#ParaInherentData). * `create_inherent`: This entry-point accepts one parameter: `InherentData`. -Both entry points share mostly the same code. `create_inherent` will -meaningfully limit inherent data to adhere to the weight limit, in addition to -sanitizing any inputs and filtering out invalid data. Conceptually it is part of -the block production. The `enter` call on the other hand is part of block import -and consumes/imports the data previously produced by `create_inherent`. - -In practice both calls process inherent data and apply it to the state. Block -production and block import should arrive at the same new state. Hence we re-use -the same logic to ensure this is the case. - -The only real difference between the two is, that on `create_inherent` we -actually need the processed and filtered inherent data to build the block, while -on `enter` the processed data should for one be identical to the incoming -inherent data (assuming honest block producers) and second it is irrelevant, as -we are not building a block but just processing it, so the processed inherent -data is simply dropped. - -This also means that the `enter` function keeps data around for no good reason. -This seems acceptable though as the size of a block is rather limited. -Nevertheless if we ever wanted to optimize this we can easily implement an -inherent collector that has two implementations, where one clones and stores the -data and the other just passes it on. +Both entry points share mostly the same code. `create_inherent` will meaningfully limit inherent data to adhere to the +weight limit, in addition to sanitizing any inputs and filtering out invalid data. Conceptually it is part of the block +production. The `enter` call on the other hand is part of block import and consumes/imports the data previously produced +by `create_inherent`. +In practice both calls process inherent data and apply it to the state. Block production and block import should arrive +at the same new state. Hence we re-use the same logic to ensure this is the case. + +The only real difference between the two is, that on `create_inherent` we actually need the processed and filtered +inherent data to build the block, while on `enter` the processed data should for one be identical to the incoming +inherent data (assuming honest block producers) and second it is irrelevant, as we are not building a block but just +processing it, so the processed inherent data is simply dropped. + +This also means that the `enter` function keeps data around for no good reason. This seems acceptable though as the size +of a block is rather limited. Nevertheless if we ever wanted to optimize this we can easily implement an inherent +collector that has two implementations, where one clones and stores the data and the other just passes it on. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/paras.md b/polkadot/roadmap/implementers-guide/src/runtime/paras.md index b3015bd5729..ac9b1520c3d 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/paras.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/paras.md @@ -1,14 +1,12 @@ # Paras Pallet -The Paras module is responsible for storing information on parachains. Registered -parachains cannot change except at session boundaries and after at least a full -session has passed. This is primarily to ensure that the number and meaning of bits required for the -availability bitfields does not change except at session boundaries. +The Paras module is responsible for storing information on parachains. Registered parachains cannot change except at +session boundaries and after at least a full session has passed. This is primarily to ensure that the number and meaning +of bits required for the availability bitfields does not change except at session boundaries. It's also responsible for: -- managing parachain validation code upgrades as well as maintaining availability of old parachain -code and its pruning. +- managing parachain validation code upgrades as well as maintaining availability of old parachain code and its pruning. - vetting PVFs by means of the PVF pre-checking mechanism. ## Storage @@ -102,8 +100,8 @@ struct PvfCheckActiveVoteState { #### Para Lifecycle -Because the state changes of parachains are delayed, we track the specific state of -the para using the `ParaLifecycle` enum. +Because the state changes of parachains are delayed, we track the specific state of the para using the `ParaLifecycle` +enum. ``` None Parathread (on-demand parachain) Parachain @@ -132,8 +130,8 @@ None Parathread (on-demand parachain) Parachain + + + ``` -Note that if PVF pre-checking is enabled, onboarding of a para may potentially be delayed. This can -happen due to PVF pre-checking voting concluding late. +Note that if PVF pre-checking is enabled, onboarding of a para may potentially be delayed. This can happen due to PVF +pre-checking voting concluding late. During the transition period, the para object is still considered in its existing state. @@ -210,7 +208,7 @@ UpcomingUpgrades: Vec<(ParaId, BlockNumberFor)>; ActionsQueue: map SessionIndex => Vec; /// Upcoming paras instantiation arguments. /// -/// NOTE that after PVF pre-checking is enabled the para genesis arg will have it's code set +/// NOTE that after PVF pre-checking is enabled the para genesis arg will have it's code set /// to empty. Instead, the code will be saved into the storage right away via `CodeByHash`. UpcomingParasGenesis: map ParaId => Option; /// The number of references on the validation code in `CodeByHash` storage. @@ -223,12 +221,13 @@ CodeByHash: map ValidationCodeHash => Option 1. Execute all queued actions for paralifecycle changes: 1. Clean up outgoing paras. - 1. This means removing the entries under `Heads`, `CurrentCode`, `FutureCodeUpgrades`, - `FutureCode` and `MostRecentContext`. An according entry should be added to `PastCode`, `PastCodeMeta`, and `PastCodePruning` using the outgoing `ParaId` and removed `CurrentCode` value. This is because any outdated validation code must remain available on-chain for a determined amount - of blocks, and validation code outdated by de-registering the para is still subject to that - invariant. - 1. Apply all incoming paras by initializing the `Heads` and `CurrentCode` using the genesis - parameters as well as `MostRecentContext` to `0`. + 1. This means removing the entries under `Heads`, `CurrentCode`, `FutureCodeUpgrades`, `FutureCode` and + `MostRecentContext`. An according entry should be added to `PastCode`, `PastCodeMeta`, and `PastCodePruning` + using the outgoing `ParaId` and removed `CurrentCode` value. This is because any outdated validation code must + remain available on-chain for a determined amount of blocks, and validation code outdated by de-registering the + para is still subject to that invariant. + 1. Apply all incoming paras by initializing the `Heads` and `CurrentCode` using the genesis parameters as well as + `MostRecentContext` to `0`. 1. Amend the `Parachains` list and `ParaLifecycle` to reflect changes in registered parachains. 1. Amend the `ParaLifecycle` set to reflect changes in registered on-demand parachains. 1. Upgrade all on-demand parachains that should become lease holding parachains, updating the `Parachains` list and @@ -239,40 +238,50 @@ CodeByHash: map ValidationCodeHash => Option 1. Go over all active PVF pre-checking votes: 1. Increment `age` of the vote. 1. If `age` reached `cfg.pvf_voting_ttl`, then enact PVF rejection and remove the vote from the active list. - 1. Otherwise, reinitialize the ballots. - 1. Resize the `votes_accept`/`votes_reject` to have the same length as the incoming validator set. - 1. Zero all the votes. + 1. Otherwise, reinitialize the ballots. 1. Resize the `votes_accept`/`votes_reject` to have the same length as the + incoming validator set. 1. Zero all the votes. ## Initialization -1. Do pruning based on all entries in `PastCodePruning` with `BlockNumber <= now`. Update the - corresponding `PastCodeMeta` and `PastCode` accordingly. +1. Do pruning based on all entries in `PastCodePruning` with `BlockNumber <= now`. Update the corresponding + `PastCodeMeta` and `PastCode` accordingly. 1. Toggle the upgrade related signals - 1. Collect all `(para_id, expected_at)` from `UpcomingUpgrades` where `expected_at <= now` and prune them. For each para pruned set `UpgradeGoAheadSignal` to `GoAhead`. Reserve weight for the state modification to upgrade each para pruned. - 1. Collect all `(para_id, next_possible_upgrade_at)` from `UpgradeCooldowns` where `next_possible_upgrade_at <= now`. For each para obtained this way reserve weight to remove its `UpgradeRestrictionSignal` on finalization. + 1. Collect all `(para_id, expected_at)` from `UpcomingUpgrades` where `expected_at <= now` and prune them. For each + para pruned set `UpgradeGoAheadSignal` to `GoAhead`. Reserve weight for the state modification to upgrade each para + pruned. + 1. Collect all `(para_id, next_possible_upgrade_at)` from `UpgradeCooldowns` where `next_possible_upgrade_at <= now`. + For each para obtained this way reserve weight to remove its `UpgradeRestrictionSignal` on finalization. ## Routines -* `schedule_para_initialize(ParaId, ParaGenesisArgs)`: Schedule a para to be initialized at the next - session. Noop if para is already registered in the system with some `ParaLifecycle`. -* `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up after the next full session. -* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread (on-demand parachain) to be upgraded to a parachain. -* `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded from lease holding to on-demand. -* `schedule_code_upgrade(ParaId, new_code, relay_parent: BlockNumber, HostConfiguration)`: Schedule a future code - upgrade of the given parachain. In case the PVF pre-checking is disabled, or the new code is already present in the storage, the upgrade will be applied after inclusion of a block of the same parachain - executed in the context of a relay-chain block with number >= `relay_parent + config.validation_upgrade_delay`. If the upgrade is scheduled `UpgradeRestrictionSignal` is set and it will remain set until `relay_parent + config.validation_upgrade_cooldown`. -In case the PVF pre-checking is enabled, or the new code is not already present in the storage, then the PVF pre-checking run will be scheduled for that validation code. If the pre-checking concludes with rejection, then the upgrade is canceled. Otherwise, after pre-checking is concluded the upgrade will be scheduled and be enacted as described above. -* `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, - where the new head was executed in the context of a relay-chain block with given number, the latter value is inserted into the `MostRecentContext` mapping. This will apply pending code upgrades based on the block number provided. If an upgrade took place it will clear the `UpgradeGoAheadSignal`. -* `lifecycle(ParaId) -> Option`: Return the `ParaLifecycle` of a para. -* `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live lease holding parachain, - including those which may be transitioning to an on-demand parachain in the future. -* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread (on-demand parachain), +- `schedule_para_initialize(ParaId, ParaGenesisArgs)`: Schedule a para to be initialized at the next session. Noop if + para is already registered in the system with some `ParaLifecycle`. +- `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up after the next full session. +- `schedule_parathread_upgrade(ParaId)`: Schedule a parathread (on-demand parachain) to be upgraded to a parachain. +- `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded from lease holding to on-demand. +- `schedule_code_upgrade(ParaId, new_code, relay_parent: BlockNumber, HostConfiguration)`: Schedule a future code + upgrade of the given parachain. In case the PVF pre-checking is disabled, or the new code is already present in the + storage, the upgrade will be applied after inclusion of a block of the same parachain executed in the context of a +relay-chain block with number >= `relay_parent + config.validation_upgrade_delay`. If the upgrade is scheduled +`UpgradeRestrictionSignal` is set and it will remain set until `relay_parent + config.validation_upgrade_cooldown`. In +case the PVF pre-checking is enabled, or the new code is not already present in the storage, then the PVF pre-checking +run will be scheduled for that validation code. If the pre-checking concludes with rejection, then the upgrade is +canceled. Otherwise, after pre-checking is concluded the upgrade will be scheduled and be enacted as described above. +- `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, where the new head was + executed in the context of a relay-chain block with given number, the latter value is inserted into the + `MostRecentContext` mapping. This will apply pending code upgrades based on the block number provided. If an upgrade + took place it will clear the `UpgradeGoAheadSignal`. +- `lifecycle(ParaId) -> Option`: Return the `ParaLifecycle` of a para. +- `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live lease holding parachain, including + those which may be transitioning to an on-demand parachain in the future. +- `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread (on-demand parachain), including those which may be transitioning to a lease holding parachain in the future. -* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live on-demand parachain - or live lease holding parachain. -* `can_upgrade_validation_code(ParaId) -> bool`: Returns true if the given para can signal code upgrade right now. -* `pvfs_require_prechecking() -> Vec`: Returns the list of PVF validation code hashes that require PVF pre-checking votes. +- `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live on-demand parachain or live + lease holding parachain. +- `can_upgrade_validation_code(ParaId) -> bool`: Returns true if the given para can signal code upgrade right now. +- `pvfs_require_prechecking() -> Vec`: Returns the list of PVF validation code hashes that require + PVF pre-checking votes. ## Finalization -Collect all `(para_id, next_possible_upgrade_at)` from `UpgradeCooldowns` where `next_possible_upgrade_at <= now` and prune them. For each para pruned remove its `UpgradeRestrictionSignal`. +Collect all `(para_id, next_possible_upgrade_at)` from `UpgradeCooldowns` where `next_possible_upgrade_at <= now` and +prune them. For each para pruned remove its `UpgradeRestrictionSignal`. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md index 312ecedcb50..2b8832946fc 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md @@ -1,6 +1,7 @@ # Scheduler Pallet -> TODO: this section is still heavily under construction. key questions about availability cores and validator assignment are still open and the flow of the the section may be contradictory or inconsistent +> TODO: this section is still heavily under construction. key questions about availability cores and validator +> assignment are still open and the flow of the the section may be contradictory or inconsistent The Scheduler module is responsible for two main tasks: @@ -9,16 +10,29 @@ The Scheduler module is responsible for two main tasks: It aims to achieve these tasks with these goals in mind: -- It should be possible to know at least a block ahead-of-time, ideally more, which validators are going to be assigned to which parachains. +- It should be possible to know at least a block ahead-of-time, ideally more, which validators are going to be assigned + to which parachains. - Parachains that have a candidate pending availability in this fork of the chain should not be assigned. -- Validator assignments should not be gameable. Malicious cartels should not be able to manipulate the scheduler to assign themselves as desired. +- Validator assignments should not be gameable. Malicious cartels should not be able to manipulate the scheduler to + assign themselves as desired. - High or close to optimal throughput of parachains. Work among validator groups should be balanced. ## Availability Cores -The Scheduler manages resource allocation using the concept of "Availability Cores". There will be one availability core for each lease holding parachain, and a fixed number of cores used for multiplexing on-demand parachains. Validators will be partitioned into groups, with the same number of groups as availability cores. Validator groups will be assigned to different availability cores over time. - -An availability core can exist in either one of two states at the beginning or end of a block: free or occupied. A free availability core can have a lease holding or on-demand parachain assigned to it for the potential to have a backed candidate included. After backing, the core enters the occupied state as the backed candidate is pending availability. There is an important distinction: a core is not considered occupied until it is in charge of a block pending availability, although the implementation may treat scheduled cores the same as occupied ones for brevity. A core exits the occupied state when the candidate is no longer pending availability - either on timeout or on availability. A core starting in the occupied state can move to the free state and back to occupied all within a single block, as availability bitfields are processed before backed candidates. At the end of the block, there is a possible timeout on availability which can move the core back to the free state if occupied. +The Scheduler manages resource allocation using the concept of "Availability Cores". There will be one availability core +for each lease holding parachain, and a fixed number of cores used for multiplexing on-demand parachains. Validators +will be partitioned into groups, with the same number of groups as availability cores. Validator groups will be assigned +to different availability cores over time. + +An availability core can exist in either one of two states at the beginning or end of a block: free or occupied. A free +availability core can have a lease holding or on-demand parachain assigned to it for the potential to have a backed +candidate included. After backing, the core enters the occupied state as the backed candidate is pending availability. +There is an important distinction: a core is not considered occupied until it is in charge of a block pending +availability, although the implementation may treat scheduled cores the same as occupied ones for brevity. A core exits +the occupied state when the candidate is no longer pending availability - either on timeout or on availability. A core +starting in the occupied state can move to the free state and back to occupied all within a single block, as +availability bitfields are processed before backed candidates. At the end of the block, there is a possible timeout on +availability which can move the core back to the free state if occupied. Cores are treated as an ordered list and are typically referred to by their index in that list. @@ -82,19 +96,47 @@ digraph { ## Validator Groups -Validator group assignments do not need to change very quickly. The security benefits of fast rotation are redundant with the challenge mechanism in the [Approval process](../protocol-approval.md). Because of this, we only divide validators into groups at the beginning of the session and do not shuffle membership during the session. However, we do take steps to ensure that no particular validator group has dominance over a single lease holding parachain or on-demand parachain-multiplexer for an entire session to provide better guarantees of live-ness. - -Validator groups rotate across availability cores in a round-robin fashion, with rotation occurring at fixed intervals. The i'th group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of rotations that have occurred in the session, and `n` is the number of cores. This makes upcoming rotations within the same session predictable. - -When a rotation occurs, validator groups are still responsible for distributing availability chunks for any previous cores that are still occupied and pending availability. In practice, rotation and availability-timeout frequencies should be set so this will only be the core they have just been rotated from. It is possible that a validator group is rotated onto a core which is currently occupied. In this case, the validator group will have nothing to do until the previously-assigned group finishes their availability work and frees the core or the availability process times out. Depending on if the core is for a lease holding parachain or on-demand parachain, a different timeout `t` from the [`HostConfiguration`](../types/runtime.md#host-configuration) will apply. Availability timeouts should only be triggered in the first `t-1` blocks after the beginning of a rotation. +Validator group assignments do not need to change very quickly. The security benefits of fast rotation are redundant +with the challenge mechanism in the [Approval process](../protocol-approval.md). Because of this, we only divide +validators into groups at the beginning of the session and do not shuffle membership during the session. However, we do +take steps to ensure that no particular validator group has dominance over a single lease holding parachain or on-demand +parachain-multiplexer for an entire session to provide better guarantees of live-ness. + +Validator groups rotate across availability cores in a round-robin fashion, with rotation occurring at fixed intervals. +The i'th group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of rotations that +have occurred in the session, and `n` is the number of cores. This makes upcoming rotations within the same session +predictable. + +When a rotation occurs, validator groups are still responsible for distributing availability chunks for any previous +cores that are still occupied and pending availability. In practice, rotation and availability-timeout frequencies +should be set so this will only be the core they have just been rotated from. It is possible that a validator group is +rotated onto a core which is currently occupied. In this case, the validator group will have nothing to do until the +previously-assigned group finishes their availability work and frees the core or the availability process times out. +Depending on if the core is for a lease holding parachain or on-demand parachain, a different timeout `t` from the +[`HostConfiguration`](../types/runtime.md#host-configuration) will apply. Availability timeouts should only be triggered +in the first `t-1` blocks after the beginning of a rotation. ## Claims -On-demand parachains operate on a system of claims. Collators purchase claims on authoring the next block of an on-demand parachain, although the purchase mechanism is beyond the scope of the scheduler. The scheduler guarantees that they'll be given at least a certain number of attempts to author a candidate that is backed. Attempts that fail during the availability phase are not counted, since ensuring availability at that stage is the responsibility of the backing validators, not of the collator. When a claim is accepted, it is placed into a queue of claims, and each claim is assigned to a particular on-demand parachain-multiplexing core in advance. Given that the current assignments of validator groups to cores are known, and the upcoming assignments are predictable, it is possible for on-demand parachain collators to know who they should be talking to now and how they should begin establishing connections with as a fallback. - -With this information, the Node-side can be aware of which on-demand parachains have a good chance of being includable within the relay-chain block and can focus any additional resources on backing candidates from those on-demand parachains. Furthermore, Node-side code is aware of which validator group will be responsible for that thread. If the necessary conditions are reached for core reassignment, those candidates can be backed within the same block as the core being freed. - -On-demand claims, when scheduled onto a free core, may not result in a block pending availability. This may be due to collator error, networking timeout, or censorship by the validator group. In this case, the claims should be retried a certain number of times to give the collator a fair shot. +On-demand parachains operate on a system of claims. Collators purchase claims on authoring the next block of an +on-demand parachain, although the purchase mechanism is beyond the scope of the scheduler. The scheduler guarantees that +they'll be given at least a certain number of attempts to author a candidate that is backed. Attempts that fail during +the availability phase are not counted, since ensuring availability at that stage is the responsibility of the backing +validators, not of the collator. When a claim is accepted, it is placed into a queue of claims, and each claim is +assigned to a particular on-demand parachain-multiplexing core in advance. Given that the current assignments of +validator groups to cores are known, and the upcoming assignments are predictable, it is possible for on-demand +parachain collators to know who they should be talking to now and how they should begin establishing connections with as +a fallback. + +With this information, the Node-side can be aware of which on-demand parachains have a good chance of being includable +within the relay-chain block and can focus any additional resources on backing candidates from those on-demand +parachains. Furthermore, Node-side code is aware of which validator group will be responsible for that thread. If the +necessary conditions are reached for core reassignment, those candidates can be backed within the same block as the core +being freed. + +On-demand claims, when scheduled onto a free core, may not result in a block pending availability. This may be due to +collator error, networking timeout, or censorship by the validator group. In this case, the claims should be retried a +certain number of times to give the collator a fair shot. ## Storage @@ -104,7 +146,7 @@ Utility structs: // A claim on authoring the next block for a given parathread (on-demand parachain). struct ParathreadClaim(ParaId, CollatorId); -// An entry tracking a parathread (on-demand parachain) claim to ensure it does not +// An entry tracking a parathread (on-demand parachain) claim to ensure it does not // pass the maximum number of retries. struct ParathreadEntry { claim: ParathreadClaim, @@ -165,7 +207,7 @@ ParathreadClaimIndex: Vec; /// The block number where the session start occurred. Used to track how many group rotations have occurred. SessionStartBlock: BlockNumber; /// Currently scheduled cores - free but up to be occupied. -/// The value contained here will not be valid after the end of a block. +/// The value contained here will not be valid after the end of a block. /// Runtime APIs should be used to determine scheduled cores /// for the upcoming block. Scheduled: Vec, // sorted ascending by CoreIndex. @@ -173,13 +215,17 @@ Scheduled: Vec, // sorted ascending by CoreIndex. ## Session Change -Session changes are the only time that configuration can change, and the [Configuration module](configuration.md)'s session-change logic is handled before this module's. We also lean on the behavior of the [Inclusion module](inclusion.md) which clears all its occupied cores on session change. Thus we don't have to worry about cores being occupied across session boundaries and it is safe to re-size the `AvailabilityCores` bitfield. +Session changes are the only time that configuration can change, and the [Configuration module](configuration.md)'s +session-change logic is handled before this module's. We also lean on the behavior of the [Inclusion +module](inclusion.md) which clears all its occupied cores on session change. Thus we don't have to worry about cores +being occupied across session boundaries and it is safe to re-size the `AvailabilityCores` bitfield. Actions: 1. Set `SessionStartBlock` to current block number + 1, as session changes are applied at the end of the block. 1. Clear all `Some` members of `AvailabilityCores`. Return all parathread claims to queue with retries un-incremented. -1. Set `configuration = Configuration::configuration()` (see [`HostConfiguration`](../types/runtime.md#host-configuration)) +1. Set `configuration = Configuration::configuration()` (see + [`HostConfiguration`](../types/runtime.md#host-configuration)) 1. Fetch `Shared::ActiveValidators` as AV. 1. Determine the number of cores & validator groups as `n_cores`. This is the maximum of 1. `Paras::parachains().len() + configuration.parathread_cores` @@ -187,13 +233,18 @@ Actions: 1. Resize `AvailabilityCores` to have length `n_cores` with all `None` entries. 1. Compute new validator groups by shuffling using a secure randomness beacon - Note that the total number of validators `V` in AV may not be evenly divided by `n_cores`. - - The groups are selected by partitioning AV. The first `V % N` groups will have `(V / n_cores) + 1` members, while the remaining groups will have `(V / N)` members each. - - Instead of using the indices within AV, which point to the broader set, indices _into_ AV should be used. This implies that groups should have simply ascending validator indices. + - The groups are selected by partitioning AV. The first `V % N` groups will have `(V / n_cores) + 1` members, while + the remaining groups will have `(V / N)` members each. + - Instead of using the indices within AV, which point to the broader set, indices _into_ AV should be used. This + implies that groups should have simply ascending validator indices. 1. Prune the parathread (on-demand parachain) queue to remove all retries beyond `configuration.parathread_retries`. - Also prune all on-demand claims corresponding to de-registered parachains. - all pruned claims should have their entry removed from the parathread (on-demand parachain) index. - - assign all non-pruned claims to new cores if the number of on-demand parachain cores has changed between the `new_config` and `old_config` of the `SessionChangeNotification`. - - Assign claims in equal balance across all cores if rebalancing, and set the `next_core` of the `ParathreadQueue` (on-demand queue) by incrementing the relative index of the last assigned core and taking it modulo the number of on-demand cores. + - assign all non-pruned claims to new cores if the number of on-demand parachain cores has changed between the + `new_config` and `old_config` of the `SessionChangeNotification`. + - Assign claims in equal balance across all cores if rebalancing, and set the `next_core` of the `ParathreadQueue` + (on-demand queue) by incrementing the relative index of the last assigned core and taking it modulo the number of + on-demand cores. ## Initialization @@ -208,28 +259,52 @@ No finalization routine runs for this module. - `add_parathread_claim(ParathreadClaim)`: Add a parathread (on-demand parachain) claim to the queue. - Fails if any on-demand claim on the same parachain is currently indexed. - Fails if the queue length is >= `config.scheduling_lookahead * config.parathread_cores`. - - The core used for the on-demand claim is the `next_core` field of the `ParathreadQueue` (on-demand queue) and adding `Paras::parachains().len()` to it. + - The core used for the on-demand claim is the `next_core` field of the `ParathreadQueue` (on-demand queue) and adding + `Paras::parachains().len()` to it. - `next_core` is then updated by adding 1 and taking it modulo `config.parathread_cores`. - The claim is then added to the claim index. -- `free_cores(Vec<(CoreIndex, FreedReason)>)`: indicate previosuly-occupied cores which are to be considered returned and why they are being returned. +- `free_cores(Vec<(CoreIndex, FreedReason)>)`: indicate previosuly-occupied cores which are to be considered returned + and why they are being returned. - All freed lease holding parachain cores should be assigned to their respective parachain - - All freed on-demand parachain cores whose reason for freeing was `FreedReason::Concluded` should have the claim removed from the claim index. - - All freed on-demand cores whose reason for freeing was `FreedReason::TimedOut` should have the claim added to the parathread queue (on-demand queue) again without retries incremented + - All freed on-demand parachain cores whose reason for freeing was `FreedReason::Concluded` should have the claim + removed from the claim index. + - All freed on-demand cores whose reason for freeing was `FreedReason::TimedOut` should have the claim added to the + parathread queue (on-demand queue) again without retries incremented - All freed on-demand cores should take the next on-demand parachain entry from the queue. -- `schedule(Vec<(CoreIndex, FreedReason)>, now: BlockNumber)`: schedule new core assignments, with a parameter indicating previously-occupied cores which are to be considered returned and why they are being returned. +- `schedule(Vec<(CoreIndex, FreedReason)>, now: BlockNumber)`: schedule new core assignments, with a parameter + indicating previously-occupied cores which are to be considered returned and why they are being returned. - Invoke `free_cores(freed_cores)` - - The i'th validator group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of rotations that have occurred in the session, and `n` is the total number of cores. This makes upcoming rotations within the same session predictable. Rotations are based off of `now`. + - The i'th validator group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of + rotations that have occurred in the session, and `n` is the total number of cores. This makes upcoming rotations + within the same session predictable. Rotations are based off of `now`. - `scheduled() -> Vec`: Get currently scheduled core assignments. - `occupied(Vec)`. Note that the given cores have become occupied. - Behavior undefined if any given cores were not scheduled. - Behavior undefined if the given cores are not sorted ascending by core index - This clears them from `Scheduled` and marks each corresponding `core` in the `AvailabilityCores` as occupied. - - Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be implemented efficiently. + - Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be + implemented efficiently. - `core_para(CoreIndex) -> ParaId`: return the currently-scheduled or occupied ParaId for the given core. -- `group_validators(GroupIndex) -> Option>`: return all validators in a given group, if the group index is valid for this session. -- `availability_timeout_predicate() -> Option bool>`: returns an optional predicate that should be used for timing out occupied cores. if `None`, no timing-out should be done. The predicate accepts the index of the core, and the block number since which it has been occupied. The predicate should be implemented based on the time since the last validator group rotation, and the respective parachain timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)` of the last rotation would this return `Some`. +- `group_validators(GroupIndex) -> Option>`: return all validators in a given group, if the group + index is valid for this session. +- `availability_timeout_predicate() -> Option bool>`: returns an optional predicate + that should be used for timing out occupied cores. if `None`, no timing-out should be done. The predicate accepts the + index of the core, and the block number since which it has been occupied. The predicate should be implemented based on + the time since the last validator group rotation, and the respective parachain timeouts, i.e. only within + `max(config.chain_availability_period, config.thread_availability_period)` of the last rotation would this return + `Some`. - `group_rotation_info(now: BlockNumber) -> GroupRotationInfo`: Returns a helper for determining group rotation. -- `next_up_on_available(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it became available. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For lease holding parachains, this is always the ID of the parachain and no specified collator. For on-demand parachains, this is based on the next item in the `ParathreadQueue` (on-demand queue) assigned to that core, and is `None` if there isn't one. -- `next_up_on_time_out(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it timed out. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For on-demand parachains, this is based on the next item in the `ParathreadQueue` (on-demand queue) assigned to that core, or if there isn't one, the claim that is currently occupying the core. Otherwise `None`. +- `next_up_on_available(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core + assuming it is currently occupied and the candidate occupying it became available. Returns in `ScheduledCore` format + (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For lease holding parachains, this is + always the ID of the parachain and no specified collator. For on-demand parachains, this is based on the next item in + the `ParathreadQueue` (on-demand queue) assigned to that core, and is `None` if there isn't one. +- `next_up_on_time_out(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core + assuming it is currently occupied and the candidate occupying it timed out. Returns in `ScheduledCore` format (todo: + link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the + parachain and no specified collator. For on-demand parachains, this is based on the next item in the `ParathreadQueue` + (on-demand queue) assigned to that core, or if there isn't one, the claim that is currently occupying the core. + Otherwise `None`. - `clear()`: - - Free all scheduled cores and return on-demand claims to queue, with retries incremented. Skip on-demand parachains which no longer exist under paras. + - Free all scheduled cores and return on-demand claims to queue, with retries incremented. Skip on-demand parachains + which no longer exist under paras. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/session_info.md b/polkadot/roadmap/implementers-guide/src/runtime/session_info.md index 5ee63ab5a90..0442ee57505 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/session_info.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/session_info.md @@ -1,6 +1,8 @@ # Session Info -For disputes and approvals, we need access to information about validator sets from prior sessions. We also often want easy access to the same information about the current session's validator set. This module aggregates and stores this information in a rolling window while providing easy APIs for access. +For disputes and approvals, we need access to information about validator sets from prior sessions. We also often want +easy access to the same information about the current session's validator set. This module aggregates and stores this +information in a rolling window while providing easy APIs for access. ## Storage @@ -66,10 +68,14 @@ Sessions: map SessionIndex => Option, ## Session Change -1. Update `EarliestStoredSession` based on `config.dispute_period` and remove all entries from `Sessions` from the previous value up to the new value. -1. Create a new entry in `Sessions` with information about the current session. Use `shared::ActiveValidators` to determine the indices into the broader validator sets (validation, assignment, discovery) which are actually used for parachain validation. Only these validators should appear in the `SessionInfo`. +1. Update `EarliestStoredSession` based on `config.dispute_period` and remove all entries from `Sessions` from the + previous value up to the new value. +1. Create a new entry in `Sessions` with information about the current session. Use `shared::ActiveValidators` to + determine the indices into the broader validator sets (validation, assignment, discovery) which are actually used for + parachain validation. Only these validators should appear in the `SessionInfo`. ## Routines * `earliest_stored_session() -> SessionIndex`: Yields the earliest session for which we have information stored. -* `session_info(session: SessionIndex) -> Option`: Yields the session info for the given session, if stored. +* `session_info(session: SessionIndex) -> Option`: Yields the session info for the given session, if + stored. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/shared.md b/polkadot/roadmap/implementers-guide/src/runtime/shared.md index 0f173134e2a..ebed240838a 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/shared.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/shared.md @@ -2,11 +2,11 @@ This module is responsible for managing shared storage and configuration for other modules. -It is important that other pallets are able to use the Shared Module, so it should not have a -dependency on any other modules in the Parachains Runtime. +It is important that other pallets are able to use the Shared Module, so it should not have a dependency on any other +modules in the Parachains Runtime. -For the moment, it is used exclusively to track the current session index across the Parachains -Runtime system, and when it should be allowed to schedule future changes to Paras or Configurations. +For the moment, it is used exclusively to track the current session index across the Parachains Runtime system, and when +it should be allowed to schedule future changes to Paras or Configurations. ## Constants @@ -57,24 +57,26 @@ AllowedRelayParents: AllowedRelayParentsTracker, The Shared Module currently has no initialization routines. -The Shared Module is initialized directly after the Configuration module, but before all other -modules. It is important to update the Shared Module before any other module since its state may be -used within the logic of other modules, and it is important that the state is consistent across -them. +The Shared Module is initialized directly after the Configuration module, but before all other modules. It is important +to update the Shared Module before any other module since its state may be used within the logic of other modules, and +it is important that the state is consistent across them. ## Session Change -During a session change, the Shared Module receives and stores the current Session Index directly from the initializer module, along with the broader validator set, and it returns the new list of validators. +During a session change, the Shared Module receives and stores the current Session Index directly from the initializer +module, along with the broader validator set, and it returns the new list of validators. -The list of validators should be first shuffled according to the chain's random seed and then truncated. The indices of these validators should be set to `ActiveValidatorIndices` and then returned back to the initializer. `ActiveValidatorKeys` should be set accordingly. +The list of validators should be first shuffled according to the chain's random seed and then truncated. The indices of +these validators should be set to `ActiveValidatorIndices` and then returned back to the initializer. +`ActiveValidatorKeys` should be set accordingly. This information is used in the: -* Configuration Module: For delaying updates to configurations until at lease one full session has - passed. +* Configuration Module: For delaying updates to configurations until at lease one full session has passed. * Paras Module: For delaying updates to paras until at least one full session has passed. -Allowed relay parents buffer, which is maintained by [ParaInherent](./parainherent.md) module, is cleared on every session change. +Allowed relay parents buffer, which is maintained by [ParaInherent](./parainherent.md) module, is cleared on every +session change. ## Finalization @@ -82,6 +84,6 @@ The Shared Module currently has no finalization routines. ## Functions -* `scheduled_sessions() -> SessionIndex`: Return the next session index where updates to the - Parachains Runtime system would be safe to apply. +* `scheduled_sessions() -> SessionIndex`: Return the next session index where updates to the Parachains Runtime system + would be safe to apply. * `set_session_index(SessionIndex)`: For tests. Set the current session index in the Shared Module. diff --git a/polkadot/roadmap/implementers-guide/src/types/approval.md b/polkadot/roadmap/implementers-guide/src/types/approval.md index b58e0a8187e..bc33f024426 100644 --- a/polkadot/roadmap/implementers-guide/src/types/approval.md +++ b/polkadot/roadmap/implementers-guide/src/types/approval.md @@ -6,9 +6,11 @@ The public key of a keypair used by a validator for determining assignments to a ## `AssignmentCert` -An `AssignmentCert`, short for Assignment Certificate, is a piece of data provided by a validator to prove that they have been selected to perform approval checks on an included candidate. +An `AssignmentCert`, short for Assignment Certificate, is a piece of data provided by a validator to prove that they +have been selected to perform approval checks on an included candidate. -These certificates can be checked in the context of a specific block, candidate, and validator assignment VRF key. The block state will also provide further context about the availability core states at that block. +These certificates can be checked in the context of a specific block, candidate, and validator assignment VRF key. The +block state will also provide further context about the availability core states at that block. ```rust enum AssignmentCertKind { @@ -53,7 +55,8 @@ struct ApprovalVote(Hash); ## `SignedApprovalVote` -An approval vote signed with a validator's key. This should be verifiable under the `ValidatorId` corresponding to the `ValidatorIndex` of the session, which should be implicit from context. +An approval vote signed with a validator's key. This should be verifiable under the `ValidatorId` corresponding to the +`ValidatorIndex` of the session, which should be implicit from context. ```rust struct SignedApprovalVote { @@ -65,9 +68,11 @@ struct SignedApprovalVote { ## `IndirectSignedApprovalVote` -A signed approval vote which references the candidate indirectly via the block. If there exists a look-up to the candidate hash from the block hash and candidate index, then this can be transformed into a `SignedApprovalVote`. +A signed approval vote which references the candidate indirectly via the block. If there exists a look-up to the +candidate hash from the block hash and candidate index, then this can be transformed into a `SignedApprovalVote`. -Although this vote references the candidate by a specific block hash and candidate index, the signature is computed on the actual `SignedApprovalVote` payload. +Although this vote references the candidate by a specific block hash and candidate index, the signature is computed on +the actual `SignedApprovalVote` payload. ```rust struct IndirectSignedApprovalVote { @@ -82,7 +87,9 @@ struct IndirectSignedApprovalVote { ## `CheckedAssignmentCert` -An assignment cert which has checked both the VRF and the validity of the implied assignment according to the selection criteria rules of the protocol. This type should be declared in such a way as to be instantiatable only when the checks have actually been done. Fields should be accessible via getters, not direct struct access. +An assignment cert which has checked both the VRF and the validity of the implied assignment according to the selection +criteria rules of the protocol. This type should be declared in such a way as to be instantiatable only when the checks +have actually been done. Fields should be accessible via getters, not direct struct access. ```rust struct CheckedAssignmentCert { diff --git a/polkadot/roadmap/implementers-guide/src/types/availability.md b/polkadot/roadmap/implementers-guide/src/types/availability.md index e2b90e86f43..a04b896c128 100644 --- a/polkadot/roadmap/implementers-guide/src/types/availability.md +++ b/polkadot/roadmap/implementers-guide/src/types/availability.md @@ -1,13 +1,12 @@ # Availability -One of the key roles of validators is to ensure availability of all data necessary to validate -candidates for the duration of a challenge period. This is done via an erasure-coding of the data to keep available. +One of the key roles of validators is to ensure availability of all data necessary to validate candidates for the +duration of a challenge period. This is done via an erasure-coding of the data to keep available. ## Signed Availability Bitfield A bitfield [signed](backing.md#signed-wrapper) by a particular validator about the availability of pending candidates. - ```rust type SignedAvailabilityBitfield = Signed; @@ -16,26 +15,30 @@ struct Bitfields(Vec<(SignedAvailabilityBitfield)>), // bitfields sorted by vali ### Semantics -A `SignedAvailabilityBitfield` represents the view from a particular validator's perspective. Each bit in the bitfield corresponds to a single [availability core](../runtime-api/availability-cores.md). A `1` bit indicates that the validator believes the following statements to be true for a core: +A `SignedAvailabilityBitfield` represents the view from a particular validator's perspective. Each bit in the bitfield +corresponds to a single [availability core](../runtime-api/availability-cores.md). A `1` bit indicates that the +validator believes the following statements to be true for a core: - the availability core is occupied -- there exists a [`CommittedCandidateReceipt`](candidate.html#committed-candidate-receipt) corresponding to that core. In other words, that para has a block in progress. +- there exists a [`CommittedCandidateReceipt`](candidate.html#committed-candidate-receipt) corresponding to that core. + In other words, that para has a block in progress. - the validator's [Availability Store](../node/utility/availability-store.md) contains a chunk of that parablock's PoV. In other words, it is the transpose of [`OccupiedCore::availability`](../runtime-api/availability-cores.md). ## Proof-of-Validity -Often referred to as PoV, this is a type-safe wrapper around bytes (`Vec`) when referring to data that acts as a stateless-client proof of validity of a candidate, when used as input to the validation function of the para. +Often referred to as PoV, this is a type-safe wrapper around bytes (`Vec`) when referring to data that acts as a +stateless-client proof of validity of a candidate, when used as input to the validation function of the para. ```rust struct PoV(Vec); ``` - ## Available Data -This is the data we want to keep available for each [candidate](candidate.md) included in the relay chain. This is the PoV of the block, as well as the [`PersistedValidationData`](candidate.md#persistedvalidationdata) +This is the data we want to keep available for each [candidate](candidate.md) included in the relay chain. This is the +PoV of the block, as well as the [`PersistedValidationData`](candidate.md#persistedvalidationdata) ```rust struct AvailableData { @@ -50,7 +53,10 @@ struct AvailableData { ## Erasure Chunk -The [`AvailableData`](#availabledata) is split up into an erasure-coding as part of the availability process. Each validator gets a chunk. This describes one of those chunks, along with its proof against a merkle root hash, which should be apparent from context, and is the `erasure_root` field of a [`CandidateDescriptor`](candidate.md#candidatedescriptor). +The [`AvailableData`](#availabledata) is split up into an erasure-coding as part of the availability process. Each +validator gets a chunk. This describes one of those chunks, along with its proof against a merkle root hash, which +should be apparent from context, and is the `erasure_root` field of a +[`CandidateDescriptor`](candidate.md#candidatedescriptor). ```rust diff --git a/polkadot/roadmap/implementers-guide/src/types/backing.md b/polkadot/roadmap/implementers-guide/src/types/backing.md index 5fcb3ae161b..7e43325ec5c 100644 --- a/polkadot/roadmap/implementers-guide/src/types/backing.md +++ b/polkadot/roadmap/implementers-guide/src/types/backing.md @@ -1,12 +1,15 @@ # Backing Types -[Candidates](candidate.md) go through many phases before being considered included in a fork of the relay chain and eventually accepted. +[Candidates](candidate.md) go through many phases before being considered included in a fork of the relay chain and +eventually accepted. -These types describe the data used in the backing phase. Some are sent over the wire within subsystems, and some are simply included in the relay-chain block. +These types describe the data used in the backing phase. Some are sent over the wire within subsystems, and some are +simply included in the relay-chain block. ## Validity Attestation -An attestation of validity for a candidate, used as part of a backing. Both the `Seconded` and `Valid` statements are considered attestations of validity. This structure is only useful where the candidate referenced is apparent. +An attestation of validity for a candidate, used as part of a backing. Both the `Seconded` and `Valid` statements are +considered attestations of validity. This structure is only useful where the candidate referenced is apparent. ```rust enum ValidityAttestation { @@ -21,7 +24,8 @@ enum ValidityAttestation { ## Signed Wrapper -There are a few distinct types which we desire to sign, and validate the signatures of. Instead of duplicating this work, we extract a signed wrapper. +There are a few distinct types which we desire to sign, and validate the signatures of. Instead of duplicating this +work, we extract a signed wrapper. ```rust,ignore /// A signed type which encapsulates the common desire to sign some data and validate a signature. @@ -44,13 +48,18 @@ impl, RealPayload: Encode> Signed`. Therefore, for the generic case where `RealPayload = Payload`, it changes nothing. However, we `impl EncodeAs for Statement`, which helps efficiency. +`EncodeAs` is a helper trait with a blanket impl which ensures that any `T` can `EncodeAs`. Therefore, for the +generic case where `RealPayload = Payload`, it changes nothing. However, we `impl EncodeAs for +Statement`, which helps efficiency. ## Statement Type -The [Candidate Backing subsystem](../node/backing/candidate-backing.md) issues and signs these after candidate validation. +The [Candidate Backing subsystem](../node/backing/candidate-backing.md) issues and signs these after candidate +validation. ```rust /// A statement about the validity of a parachain candidate. @@ -94,11 +103,13 @@ pub type SignedFullStatement = Signed; pub type SignedStatement = Signed; ``` -Munging the signed `Statement` into a `CompactStatement` before signing allows the candidate receipt itself to be omitted when checking a signature on a `Seconded` statement. +Munging the signed `Statement` into a `CompactStatement` before signing allows the candidate receipt itself to be +omitted when checking a signature on a `Seconded` statement. ## Backed Candidate -An [`CommittedCandidateReceipt`](candidate.md#committed-candidate-receipt) along with all data necessary to prove its backing. This is submitted to the relay-chain to process and move along the candidate to the pending-availability stage. +An [`CommittedCandidateReceipt`](candidate.md#committed-candidate-receipt) along with all data necessary to prove its +backing. This is submitted to the relay-chain to process and move along the candidate to the pending-availability stage. ```rust struct BackedCandidate { diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index a37f98054c5..00176229e5a 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -1,15 +1,18 @@ # Candidate Types -Para candidates are some of the most common types, both within the runtime and on the Node-side. -Candidates are the fundamental datatype for advancing parachains, encapsulating the collator's signature, the context of the parablock, the commitments to the output, and a commitment to the data which proves it valid. +Para candidates are some of the most common types, both within the runtime and on the Node-side. Candidates are the +fundamental datatype for advancing parachains, encapsulating the collator's signature, the context of the parablock, the +commitments to the output, and a commitment to the data which proves it valid. -In a way, this entire guide is about these candidates: how they are scheduled, constructed, backed, included, and challenged. +In a way, this entire guide is about these candidates: how they are scheduled, constructed, backed, included, and +challenged. This section will describe the base candidate type, its components, and variants that contain extra data. ## Para Id -A unique 32-bit identifier referring to a specific para (chain or thread). The relay-chain runtime guarantees that `ParaId`s are unique for the duration of any session, but recycling and reuse over a longer period of time is permitted. +A unique 32-bit identifier referring to a specific para (chain or thread). The relay-chain runtime guarantees that +`ParaId`s are unique for the duration of any session, but recycling and reuse over a longer period of time is permitted. ```rust struct ParaId(u32); @@ -17,9 +20,12 @@ struct ParaId(u32); ## Candidate Receipt -Much info in a [`FullCandidateReceipt`](#full-candidate-receipt) is duplicated from the relay-chain state. When the corresponding relay-chain state is considered widely available, the Candidate Receipt should be favored over the `FullCandidateReceipt`. +Much info in a [`FullCandidateReceipt`](#full-candidate-receipt) is duplicated from the relay-chain state. When the +corresponding relay-chain state is considered widely available, the Candidate Receipt should be favored over the +`FullCandidateReceipt`. -Examples of situations where the state is readily available includes within the scope of work done by subsystems working on a given relay-parent, or within the logic of the runtime importing a backed candidate. +Examples of situations where the state is readily available includes within the scope of work done by subsystems working +on a given relay-parent, or within the logic of the runtime importing a backed candidate. ```rust /// A candidate-receipt. @@ -33,9 +39,13 @@ struct CandidateReceipt { ## Full Candidate Receipt -This is the full receipt type. The `PersistedValidationData` are technically redundant with the `inner.relay_parent`, which uniquely describes the block in the blockchain from whose state these values are derived. The [`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason. +This is the full receipt type. The `PersistedValidationData` are technically redundant with the `inner.relay_parent`, +which uniquely describes the block in the blockchain from whose state these values are derived. The +[`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason. -However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old blockchain state. In situations such as availability and approval, having the full description of the candidate within a self-contained struct is convenient. +However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old +blockchain state. In situations such as availability and approval, having the full description of the candidate within a +self-contained struct is convenient. ```rust /// All data pertaining to the execution of a para candidate. @@ -47,9 +57,13 @@ struct FullCandidateReceipt { ## Committed Candidate Receipt -This is a variant of the candidate receipt which includes the commitments of the candidate receipt alongside the descriptor. This should be favored over the [`Candidate Receipt`](#candidate-receipt) in situations where the candidate is not going to be executed but the actual data committed to is important. This is often the case in the backing phase. +This is a variant of the candidate receipt which includes the commitments of the candidate receipt alongside the +descriptor. This should be favored over the [`Candidate Receipt`](#candidate-receipt) in situations where the candidate +is not going to be executed but the actual data committed to is important. This is often the case in the backing phase. -The hash of the committed candidate receipt will be the same as the corresponding [`Candidate Receipt`](#candidate-receipt), because it is computed by first hashing the encoding of the commitments to form a plain [`Candidate Receipt`](#candidate-receipt). +The hash of the committed candidate receipt will be the same as the corresponding [`Candidate +Receipt`](#candidate-receipt), because it is computed by first hashing the encoding of the commitments to form a plain +[`Candidate Receipt`](#candidate-receipt). ```rust /// A candidate-receipt with commitments directly included. @@ -110,15 +124,24 @@ pub struct ValidationParams { ## `PersistedValidationData` -The validation data provides information about how to create the inputs for validation of a candidate. This information is derived from the chain state and will vary from para to para, although some of the fields may be the same for every para. +The validation data provides information about how to create the inputs for validation of a candidate. This information +is derived from the chain state and will vary from para to para, although some of the fields may be the same for every +para. -Since this data is used to form inputs to the validation function, it needs to be persisted by the availability system to avoid dependence on availability of the relay-chain state. +Since this data is used to form inputs to the validation function, it needs to be persisted by the availability system +to avoid dependence on availability of the relay-chain state. -Furthermore, the validation data acts as a way to authorize the additional data the collator needs to pass to the validation function. For example, the validation function can check whether the incoming messages (e.g. downward messages) were actually sent by using the data provided in the validation data using so called MQC heads. +Furthermore, the validation data acts as a way to authorize the additional data the collator needs to pass to the +validation function. For example, the validation function can check whether the incoming messages (e.g. downward +messages) were actually sent by using the data provided in the validation data using so called MQC heads. -Since the commitments of the validation function are checked by the relay-chain, approval checkers can rely on the invariant that the relay-chain only includes para-blocks for which these checks have already been done. As such, there is no need for the validation data used to inform validators and collators about the checks the relay-chain will perform to be persisted by the availability system. +Since the commitments of the validation function are checked by the relay-chain, approval checkers can rely on the +invariant that the relay-chain only includes para-blocks for which these checks have already been done. As such, there +is no need for the validation data used to inform validators and collators about the checks the relay-chain will perform +to be persisted by the availability system. -The `PersistedValidationData` should be relatively lightweight primarily because it is constructed during inclusion for each candidate and therefore lies on the critical path of inclusion. +The `PersistedValidationData` should be relatively lightweight primarily because it is constructed during inclusion for +each candidate and therefore lies on the critical path of inclusion. ```rust struct PersistedValidationData { @@ -150,7 +173,8 @@ struct HeadData(Vec); ## Candidate Commitments -The execution and validation of parachain candidates produces a number of values which either must be committed to blocks on the relay chain or committed to the state of the relay chain. +The execution and validation of parachain candidates produces a number of values which either must be committed to +blocks on the relay chain or committed to the state of the relay chain. ```rust /// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation. @@ -174,7 +198,9 @@ struct CandidateCommitments { ## Signing Context -This struct provides context to signatures by combining with various payloads to localize the signature to a particular session index and relay-chain hash. Having these fields included in the signature makes misbehavior attribution much simpler. +This struct provides context to signatures by combining with various payloads to localize the signature to a particular +session index and relay-chain hash. Having these fields included in the signature makes misbehavior attribution much +simpler. ```rust struct SigningContext { diff --git a/polkadot/roadmap/implementers-guide/src/types/disputes.md b/polkadot/roadmap/implementers-guide/src/types/disputes.md index 24f152b1308..c49e0fea262 100644 --- a/polkadot/roadmap/implementers-guide/src/types/disputes.md +++ b/polkadot/roadmap/implementers-guide/src/types/disputes.md @@ -28,7 +28,8 @@ enum DisputeStatement { ## Dispute Statement Kinds -Kinds of dispute statements. Each of these can be combined with a candidate hash, session index, validator public key, and validator signature to reproduce and check the original statement. +Kinds of dispute statements. Each of these can be combined with a candidate hash, session index, validator public key, +and validator signature to reproduce and check the original statement. ```rust enum ValidDisputeStatementKind { diff --git a/polkadot/roadmap/implementers-guide/src/types/network.md b/polkadot/roadmap/implementers-guide/src/types/network.md index b698ca2075b..60f5bda28fa 100644 --- a/polkadot/roadmap/implementers-guide/src/types/network.md +++ b/polkadot/roadmap/implementers-guide/src/types/network.md @@ -139,7 +139,8 @@ enum CollationProtocolV1 { ## Network Bridge Event -These updates are posted from the [Network Bridge Subsystem](../node/utility/network-bridge.md) to other subsystems based on registered listeners. +These updates are posted from the [Network Bridge Subsystem](../node/utility/network-bridge.md) to other subsystems +based on registered listeners. ```rust struct NewGossipTopology { diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index 3d9037699da..fababbff354 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -1,6 +1,7 @@ # Overseer Protocol -This chapter contains message types sent to and from the overseer, and the underlying subsystem message types that are transmitted using these. +This chapter contains message types sent to and from the overseer, and the underlying subsystem message types that are +transmitted using these. ## Overseer Signal @@ -17,7 +18,8 @@ enum OverseerSignal { } ``` -All subsystems have their own message types; all of them need to be able to listen for overseer signals as well. There are currently two proposals for how to handle that with unified communication channels: +All subsystems have their own message types; all of them need to be able to listen for overseer signals as well. There +are currently two proposals for how to handle that with unified communication channels: 1. Retaining the `OverseerSignal` definition above, add `enum FromOrchestra {Signal(OverseerSignal), Message(T)}`. 1. Add a generic varint to `OverseerSignal`: `Message(T)`. @@ -26,7 +28,8 @@ Either way, there will be some top-level type encapsulating messages from the ov ## Active Leaves Update -Indicates a change in active leaves. Activated leaves should have jobs, whereas deactivated leaves should lead to winding-down of work based on those leaves. +Indicates a change in active leaves. Activated leaves should have jobs, whereas deactivated leaves should lead to +winding-down of work based on those leaves. ```rust enum LeafStatus { @@ -201,7 +204,8 @@ enum ApprovalDistributionMessage { Messages received by the availability distribution subsystem. -This is a network protocol that receives messages of type [`AvailabilityDistributionV1Message`][AvailabilityDistributionV1NetworkMessage]. +This is a network protocol that receives messages of type +[`AvailabilityDistributionV1Message`][AvailabilityDistributionV1NetworkMessage]. ```rust enum AvailabilityDistributionMessage { @@ -293,7 +297,7 @@ pub enum AvailabilityStoreMessage { tx: oneshot::Sender>, }, - /// Computes and checks the erasure root of `AvailableData` before storing all of its chunks in + /// Computes and checks the erasure root of `AvailableData` before storing all of its chunks in /// the AV store. /// /// Return `Ok(())` if the store operation succeeded, `Err(StoreAvailableData)` if it failed. @@ -319,8 +323,8 @@ pub enum StoreAvailableDataError { ## Bitfield Distribution Message -Messages received by the bitfield distribution subsystem. -This is a network protocol that receives messages of type [`BitfieldDistributionV1Message`][BitfieldDistributionV1NetworkMessage]. +Messages received by the bitfield distribution subsystem. This is a network protocol that receives messages of type +[`BitfieldDistributionV1Message`][BitfieldDistributionV1NetworkMessage]. ```rust enum BitfieldDistributionMessage { @@ -354,7 +358,7 @@ enum CandidateBackingMessage { /// The PoV is expected to match the `pov_hash` in the descriptor. Second(Hash, CandidateReceipt, PoV), /// Note a peer validator's statement about a particular candidate. Disagreements about validity must be escalated - /// to a broader check by the Disputes Subsystem, though that escalation is deferred until the approval voting + /// to a broader check by the Disputes Subsystem, though that escalation is deferred until the approval voting /// stage to guarantee availability. Agreements are simply tallied until a quorum is reached. Statement(Statement), } @@ -420,7 +424,8 @@ enum ChainSelectionMessage { Messages received by the [Collator Protocol subsystem](../node/collators/collator-protocol.md) -This is a network protocol that receives messages of type [`CollatorProtocolV1Message`][CollatorProtocolV1NetworkMessage]. +This is a network protocol that receives messages of type +[`CollatorProtocolV1Message`][CollatorProtocolV1NetworkMessage]. ```rust enum CollatorProtocolMessage { @@ -452,7 +457,8 @@ enum CollatorProtocolMessage { Messages received by the [Collation Generation subsystem](../node/collators/collation-generation.md) -This is the core interface by which collators built on top of a Polkadot node submit collations to validators. As such, these messages are not sent by any subsystem but are instead sent from outside of the overseer. +This is the core interface by which collators built on top of a Polkadot node submit collations to validators. As such, +these messages are not sent by any subsystem but are instead sent from outside of the overseer. ```rust /// A function provided to the subsystem which it uses to pull new collations. @@ -503,7 +509,8 @@ enum CollationGenerationMessage { Messages received by the [Dispute Coordinator subsystem](../node/disputes/dispute-coordinator.md) -This subsystem coordinates participation in disputes, tracks live disputes, and observed statements of validators from subsystems. +This subsystem coordinates participation in disputes, tracks live disputes, and observed statements of validators from +subsystems. ```rust enum DisputeCoordinatorMessage { @@ -572,11 +579,9 @@ pub enum ImportStatementsResult { } ``` - ## Dispute Distribution Message -Messages received by the [Dispute Distribution -subsystem](../node/disputes/dispute-distribution.md). This subsystem is +Messages received by the [Dispute Distribution subsystem](../node/disputes/dispute-distribution.md). This subsystem is responsible of distributing explicit dispute statements. ```rust @@ -602,8 +607,8 @@ enum DisputeDistributionMessage { ## Network Bridge Message -Messages received by the network bridge. This subsystem is invoked by others to manipulate access -to the low-level networking code. +Messages received by the network bridge. This subsystem is invoked by others to manipulate access to the low-level +networking code. ```rust /// Peer-sets handled by the network bridge. @@ -778,7 +783,8 @@ enum ProvisionerMessage { The Runtime API subsystem is responsible for providing an interface to the state of the chain's runtime. -This is fueled by an auxiliary type encapsulating all request types defined in the [Runtime API section](../runtime-api) of the guide. +This is fueled by an auxiliary type encapsulating all request types defined in the [Runtime API section](../runtime-api) +of the guide. ```rust enum RuntimeApiRequest { @@ -835,10 +841,12 @@ enum RuntimeApiMessage { ## Statement Distribution Message -The Statement Distribution subsystem distributes signed statements and candidates from validators to other validators. It does this by distributing full statements, which embed the candidate receipt, as opposed to compact statements which don't. -It receives updates from the network bridge and signed statements to share with other validators. +The Statement Distribution subsystem distributes signed statements and candidates from validators to other validators. +It does this by distributing full statements, which embed the candidate receipt, as opposed to compact statements which +don't. It receives updates from the network bridge and signed statements to share with other validators. -This is a network protocol that receives messages of type [`StatementDistributionV1Message`][StatementDistributionV1NetworkMessage]. +This is a network protocol that receives messages of type +[`StatementDistributionV1Message`][StatementDistributionV1NetworkMessage]. ```rust enum StatementDistributionMessage { @@ -855,7 +863,8 @@ enum StatementDistributionMessage { ## Validation Request Type -Various modules request that the [Candidate Validation subsystem](../node/utility/candidate-validation.md) validate a block with this message. It returns [`ValidationOutputs`](candidate.md#validationoutputs) for successful validation. +Various modules request that the [Candidate Validation subsystem](../node/utility/candidate-validation.md) validate a +block with this message. It returns [`ValidationOutputs`](candidate.md#validationoutputs) for successful validation. ```rust diff --git a/polkadot/roadmap/implementers-guide/src/whence-parachains.md b/polkadot/roadmap/implementers-guide/src/whence-parachains.md index 41842e93943..faec46be2c6 100644 --- a/polkadot/roadmap/implementers-guide/src/whence-parachains.md +++ b/polkadot/roadmap/implementers-guide/src/whence-parachains.md @@ -1,29 +1,50 @@ # Whence Parachains -Parachains are the solution to a problem. As with any solution, it cannot be understood without first understanding the problem. So let's start by going over the issues faced by blockchain technology that led to us beginning to explore the design space for something like parachains. +Parachains are the solution to a problem. As with any solution, it cannot be understood without first understanding the +problem. So let's start by going over the issues faced by blockchain technology that led to us beginning to explore the +design space for something like parachains. ## Issue 1: Scalability -It became clear a few years ago that the transaction throughput of simple Proof-of-Work (PoW) blockchains such as Bitcoin, Ethereum, and myriad others was simply too low. +It became clear a few years ago that the transaction throughput of simple Proof-of-Work (PoW) blockchains such as +Bitcoin, Ethereum, and myriad others was simply too low. > TODO: what if there were more blockchains, etc. -Proof-of-Stake (PoS) systems can accomplish higher throughput than PoW blockchains. PoS systems are secured by bonded capital as opposed to spent effort - liquidity opportunity cost vs. burning electricity. The way they work is by selecting a set of validators with known economic identity who lock up tokens in exchange for earning the right to "validate" or participate in the consensus process. If they are found to carry out that process wrongly, they will be slashed, meaning some or all of the locked tokens will be burned. This provides a strong disincentive in the direction of misbehavior. +Proof-of-Stake (PoS) systems can accomplish higher throughput than PoW blockchains. PoS systems are secured by bonded +capital as opposed to spent effort - liquidity opportunity cost vs. burning electricity. The way they work is by +selecting a set of validators with known economic identity who lock up tokens in exchange for earning the right to +"validate" or participate in the consensus process. If they are found to carry out that process wrongly, they will be +slashed, meaning some or all of the locked tokens will be burned. This provides a strong disincentive in the direction +of misbehavior. -Since the consensus protocol doesn't revolve around wasting effort, block times and agreement can occur much faster. Solutions to PoW challenges don't have to be found before a block can be authored, so the overhead of authoring a block is reduced to only the costs of creating and distributing the block. +Since the consensus protocol doesn't revolve around wasting effort, block times and agreement can occur much faster. +Solutions to PoW challenges don't have to be found before a block can be authored, so the overhead of authoring a block +is reduced to only the costs of creating and distributing the block. -However, consensus on a PoS chain requires full agreement of 2/3+ of the validator set for everything that occurs at Layer 1: all logic which is carried out as part of the blockchain's state machine. This means that everybody still needs to check everything. Furthermore, validators may have different views of the system based on the information that they receive over an asynchronous network, making agreement on the latest state more difficult. +However, consensus on a PoS chain requires full agreement of 2/3+ of the validator set for everything that occurs at +Layer 1: all logic which is carried out as part of the blockchain's state machine. This means that everybody still needs +to check everything. Furthermore, validators may have different views of the system based on the information that they +receive over an asynchronous network, making agreement on the latest state more difficult. -Parachains are an example of a **sharded** protocol. Sharding is a concept borrowed from traditional database architecture. Rather than requiring every participant to check every transaction, we require each participant to check some subset of transactions, with enough redundancy baked in that byzantine (arbitrarily malicious) participants can't sneak in invalid transactions - at least not without being detected and getting slashed, with those transactions reverted. +Parachains are an example of a **sharded** protocol. Sharding is a concept borrowed from traditional database +architecture. Rather than requiring every participant to check every transaction, we require each participant to check +some subset of transactions, with enough redundancy baked in that byzantine (arbitrarily malicious) participants can't +sneak in invalid transactions - at least not without being detected and getting slashed, with those transactions +reverted. -Sharding and Proof-of-Stake in coordination with each other allow a parachain host to provide full security on many parachains, even without all participants checking all state transitions. +Sharding and Proof-of-Stake in coordination with each other allow a parachain host to provide full security on many +parachains, even without all participants checking all state transitions. > TODO: note about network effects & bridging ## Issue 2: Flexibility / Specialization -"dumb" VMs don't give you the flexibility. Any engineer knows that being able to specialize on a problem gives them and their users more _leverage_. +"dumb" VMs don't give you the flexibility. Any engineer knows that being able to specialize on a problem gives them and +their users more _leverage_. > TODO: expand on leverage -Having recognized these issues, we set out to find a solution to these problems, which could allow developers to create and deploy purpose-built blockchains unified under a common source of security, with the capability of message-passing between them; a _heterogeneous sharding solution_, which we have come to know as **Parachains**. +Having recognized these issues, we set out to find a solution to these problems, which could allow developers to create +and deploy purpose-built blockchains unified under a common source of security, with the capability of message-passing +between them; a _heterogeneous sharding solution_, which we have come to know as **Parachains**. diff --git a/polkadot/roadmap/parachains.md b/polkadot/roadmap/parachains.md index 9d6c014a1c7..77e97433676 100644 --- a/polkadot/roadmap/parachains.md +++ b/polkadot/roadmap/parachains.md @@ -1,17 +1,23 @@ # Parachains Roadmap -This is a roadmap for the core technology underlying Parachains - what protocols, APIs, and code paths need to be in place to fully instantiate a self-sufficient and secure parachain. We don't attempt to cover anything on what APIs a parachain toolkit might expose in order to make use of parachain features - only how those features are implemented and the low-level APIs that they expose to the validation function, if any. + +This is a roadmap for the core technology underlying Parachains - what protocols, APIs, and code paths need to be in +place to fully instantiate a self-sufficient and secure parachain. We don't attempt to cover anything on what APIs a +parachain toolkit might expose in order to make use of parachain features - only how those features are implemented and +the low-level APIs that they expose to the validation function, if any. ## Categories We will use these categories to delineate features: -*Runtime*: Runtime code for the Relay chain specifying consensus-critical state and updates that all full nodes must maintain or perform. +*Runtime*: Runtime code for the Relay chain specifying consensus-critical state and updates that all full nodes must +maintain or perform. *Networking*: Protocols for nodes to speak to each other and transmit information across the network. -*Node*: State or updates that must be maintained or performed by some or all nodes off-chain. Often interfaces with networking components, and references runtime state. +*Node*: State or updates that must be maintained or performed by some or all nodes off-chain. Often interfaces with +networking components, and references runtime state. --- -## Sub-projects and features: +## Sub-projects and features This section contains various sub-projects and the features that make them up. ### Infrastructure/API @@ -20,7 +26,8 @@ This section contains various sub-projects and the features that make them up. Category: Networking -Validators assigned to a parachain need a way to discover and connect to collators in order to get fresh parachain blocks to validate. +Validators assigned to a parachain need a way to discover and connect to collators in order to get fresh parachain +blocks to validate. Collators need to discover and connect to validators in order to submit parachain blocks. @@ -30,7 +37,9 @@ Some connections are long-lived, some are just for a single request. #### Custom libp2p sub-protocols -Polkadot parachains involve many distinct networking protocols. Ideally, we'd be able to spawn each of these as a separate futures task which communicates via channel with other protocols or node code as necessary. This requires changes in Substrate and libp2p. +Polkadot parachains involve many distinct networking protocols. Ideally, we'd be able to spawn each of these as a +separate futures task which communicates via channel with other protocols or node code as necessary. This requires +changes in Substrate and libp2p. --- ### Assignment @@ -39,21 +48,26 @@ Polkadot parachains involve many distinct networking protocols. Ideally, we'd be Category: Runtime -Auctioning and registration of parachains. This is already implemented and follows the [Parachain Allocation — Research at W3F](https://research.web3.foundation/en/latest/polkadot/Parachain-Allocation.html) document. +Auctioning and registration of parachains. This is already implemented and follows the [Parachain Allocation — Research +at W3F](https://research.web3.foundation/en/latest/polkadot/Parachain-Allocation.html) document. #### *On-demand Blockspace Purchase* Category: Runtime -The blockspace purchasing system for on-demand parachains consists of an on-chain mechanism for resolving block space purchases by collators and ensuring that they author a block. +The blockspace purchasing system for on-demand parachains consists of an on-chain mechanism for resolving block space +purchases by collators and ensuring that they author a block. -The node-side portion of on-demand parachains is for collators to actually purchase blockspace and to configure the conditions in which purchases are made. +The node-side portion of on-demand parachains is for collators to actually purchase blockspace and to configure the +conditions in which purchases are made. #### *Validator Assignment* Category: Runtime -Assignment of validators to parachains. Validators are only assigned to parachains for a short period of time. Tweakable parameters include length of time assigned to each parachain and length of time in advance that the network is aware of validators' assignments. +Assignment of validators to parachains. Validators are only assigned to parachains for a short period of time. Tweakable +parameters include length of time assigned to each parachain and length of time in advance that the network is aware of +validators' assignments. --- ### Agreement @@ -62,19 +76,26 @@ Assignment of validators to parachains. Validators are only assigned to parachai Category: Networking -A black-box networking component for circulating attestation messages (`Candidate`, `Valid`, `Invalid`) between validators of any given parachain to create a quorum on which blocks can be included. +A black-box networking component for circulating attestation messages (`Candidate`, `Valid`, `Invalid`) between +validators of any given parachain to create a quorum on which blocks can be included. #### *Availability Erasure-coding* Category: Node, Networking -For each potential, considered parachain block, perform an erasure-coding of the PoV and outgoing messages of the block. Call the number of validators on the relay chain for the Relay-chain block this parachain block is being considered for inclusion in `n`. Erasure-code into `n` pieces, where any `f + 1` can recover (`f` being the maximum number of tolerated faulty nodes = ~ `n / 3`). The `i'th` validator stores the `i'th` piece of the coding and provides it to any who ask. +For each potential, considered parachain block, perform an erasure-coding of the PoV and outgoing messages of the block. +Call the number of validators on the relay chain for the Relay-chain block this parachain block is being considered for +inclusion in `n`. Erasure-code into `n` pieces, where any `f + 1` can recover (`f` being the maximum number of tolerated +faulty nodes = ~ `n / 3`). The `i'th` validator stores the `i'th` piece of the coding and provides it to any who ask. #### *PoV block fetching* Category: Networking -A black-box networking component for validators or fishermen on a parachain to obtain the PoV block referenced by hash in an attestation, for the purpose of validating. When fetching "current" PoV blocks (close to the head of the chain, or relating to the block currently being built), this should be fast. When fetching "old" PoV blocks, it should be possible and fall back on recovering from the availability erasure-coding. +A black-box networking component for validators or fishermen on a parachain to obtain the PoV block referenced by hash +in an attestation, for the purpose of validating. When fetching "current" PoV blocks (close to the head of the chain, or +relating to the block currently being built), this should be fast. When fetching "old" PoV blocks, it should be possible +and fall back on recovering from the availability erasure-coding. #### *On-demand Blockspace Purchase* @@ -95,58 +116,80 @@ The main event loop of a collator node: --- ### Cross-chain Messaging -https://hackmd.io/ILoQltEISP697oMYe4HbrA?view -https://github.com/paritytech/polkadot/issues/597 +https://hackmd.io/ILoQltEISP697oMYe4HbrA?view https://github.com/paritytech/polkadot/issues/597 -The biggest sub-project of the parachains roadmap - how messages are sent between parachains. This involves the state-machine ordering of incoming messages, protocols for fetching those messages, and node logic for persisting the messages. +The biggest sub-project of the parachains roadmap - how messages are sent between parachains. This involves the +state-machine ordering of incoming messages, protocols for fetching those messages, and node logic for persisting the +messages. -This is designed around a concept of unidirectional _channels_ between paras, which consist of a sender and receiver. At each relay chain block, each para has an opportunity to send a message on each channel for which it controls the sending half. It will also attempt to process messages on each receiving half of the channel which it controls _in order_: messages sent at block height `b` must be processed before those sent at block height `b+1`. For messages on different channels sent at the same block height, there will be some well-defined order in which they should be processed. +This is designed around a concept of unidirectional _channels_ between paras, which consist of a sender and receiver. At +each relay chain block, each para has an opportunity to send a message on each channel for which it controls the sending +half. It will also attempt to process messages on each receiving half of the channel which it controls _in order_: +messages sent at block height `b` must be processed before those sent at block height `b+1`. For messages on different +channels sent at the same block height, there will be some well-defined order in which they should be processed. -This means that a receiving para will have a maximum height differential of `1` in terms of the most recently processed message's send-height across all of the channels it is receiving on. The minimum processed send-height of a receiving para is known as its _watermark_. All messages on all channels sending to this para before or at the watermark have been processed. +This means that a receiving para will have a maximum height differential of `1` in terms of the most recently processed +message's send-height across all of the channels it is receiving on. The minimum processed send-height of a receiving +para is known as its _watermark_. All messages on all channels sending to this para before or at the watermark have been +processed. #### *Finalize CandidateReceipt format* Category: Runtime / Node -The `CandidateReceipt` is the wrapper around a parablock header which is submitted to the runtime. It contains cryptographic commitments to data which is important for validation or interpretation of the parablock, including the hash of the witness data and outgoing message data. +The `CandidateReceipt` is the wrapper around a parablock header which is submitted to the runtime. It contains +cryptographic commitments to data which is important for validation or interpretation of the parablock, including the +hash of the witness data and outgoing message data. -The `CandidateReceipt` format should be finalized in accordance to the XCMP writeups linked above - most importantly, to be altered to hold `bitfield` and `message_root` fields which cryptographically commit to the state of each open channel. +The `CandidateReceipt` format should be finalized in accordance to the XCMP writeups linked above - most importantly, to +be altered to hold `bitfield` and `message_root` fields which cryptographically commit to the state of each open +channel. #### *Finalize PovBlock format* Category: Runtime / Node -The `PovBlock` or `Proof-of-Validity` block contains all the data you need to validate a parablock. It will need to contain incoming message queues and potentially outgoing ones as well. +The `PovBlock` or `Proof-of-Validity` block contains all the data you need to validate a parablock. It will need to +contain incoming message queues and potentially outgoing ones as well. #### *CST Update Procedure* Category: Runtime -Storage definitions and update logic of the Channel State Table (CST) based on the supplied `CandidateReceipt`s in a relay chain block. +Storage definitions and update logic of the Channel State Table (CST) based on the supplied `CandidateReceipt`s in a +relay chain block. #### *CST Entry Proof Generation and Checking* Category: Node -Means for full nodes of the relay chain to generate proofs of items in the CST and for light clients or pruned nodes to check those proofs. +Means for full nodes of the relay chain to generate proofs of items in the CST and for light clients or pruned nodes to +check those proofs. #### *MQC Storage and Distribution Protocol* Category: Node -Every channel's state is described by a Message Queue Chain (MQC) which is a hash-chain, where the links are defined by `(M, b, H)`: the message most recently sent, the block height at which the prior message was sent, and the hash of the prior link. +Every channel's state is described by a Message Queue Chain (MQC) which is a hash-chain, where the links are defined by +`(M, b, H)`: the message most recently sent, the block height at which the prior message was sent, and the hash of the +prior link. -It is the responsibility of the full nodes of the _sending_ para to maintain all links of the MQC up to and including the link where `b` is less than the watermark of the _receiving_ para. +It is the responsibility of the full nodes of the _sending_ para to maintain all links of the MQC up to and including +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. +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. -We will need a network where collators of paras can discover and fetch the relevant portion of the MQC incoming from all channels. +We will need a network where collators of paras can discover and fetch the relevant portion of the MQC incoming from all +channels. #### *Channel Registrar and Economics* Category: Runtime -Runtime logic for paras to open and close channels by putting down a deposit. The amount of channels an on-demand parachain can open will be limited. Channels that are pending close should remain open until the watermark of the recipient has reached the block height of the close request. +Runtime logic for paras to open and close channels by putting down a deposit. The amount of channels an on-demand +parachain can open will be limited. Channels that are pending close should remain open until the watermark of the +recipient has reached the block height of the close request. --- ### Fishing/Slashing @@ -155,17 +198,29 @@ Runtime logic for paras to open and close channels by putting down a deposit. Th Category: Runtime -In Polkadot, a bad parachain group can force inclusion of an invalid or unavailable parachain block. It is the job of fishermen to detect those blocks and report them to the runtime. This item is about the report handler +In Polkadot, a bad parachain group can force inclusion of an invalid or unavailable parachain block. It is the job of +fishermen to detect those blocks and report them to the runtime. This item is about the report handler -The W3F-research writeup on availability/validity provides a high-level view of the dispute resolution process: [Availability and Validity — Research at W3F](https://research.web3.foundation/en/latest/polkadot/Availability_and_Validity.html) +The W3F-research writeup on availability/validity provides a high-level view of the dispute resolution process: +[Availability and Validity — Research at +W3F](https://research.web3.foundation/en/latest/polkadot/Availability_and_Validity.html) -One of the main behaviors that is unimplemented and needs to be is the _rollback_ that occurs when the dispute resolution process concludes that an error has been made. When we mark a parachain block as having been invalid or unavailable, we need to roll back all parachains to a point from just before this state. We would also need to roll back relay chain state, because there may have been messages from a parachain to a relay chain that now need to be rolled back. The easiest thing to do would be to side-step that by putting a delay on upwards messages, but this would impact the UX of parachain participation in slot auctions, council votes, etc. considerably. Assuming we can't side-step this, we will have to find a way to roll back selected state of the relay chain. +One of the main behaviors that is unimplemented and needs to be is the _rollback_ that occurs when the dispute +resolution process concludes that an error has been made. When we mark a parachain block as having been invalid or +unavailable, we need to roll back all parachains to a point from just before this state. We would also need to roll +back relay chain state, because there may have been messages from a parachain to a relay chain that now need to be +rolled back. The easiest thing to do would be to side-step that by putting a delay on upwards messages, but this would +impact the UX of parachain participation in slot auctions, council votes, etc. considerably. Assuming we can't side-step +this, we will have to find a way to roll back selected state of the relay chain. #### *Double-vote Slash Handler* Category: Runtime -In the attestation process, validators may submit only one `Candidate` message for a given relay chain block. If issuing a `Candidate` message on a parachain block, neither a `Valid` or `Invalid` vote cannot be issued on that parachain block, as the `Candidate` message is an implicit validity vote. Otherwise, it is illegal to cast both a `Valid` and `Invalid` vote on a given parachain block. +In the attestation process, validators may submit only one `Candidate` message for a given relay chain block. If issuing +a `Candidate` message on a parachain block, neither a `Valid` or `Invalid` vote cannot be issued on that parachain +block, as the `Candidate` message is an implicit validity vote. Otherwise, it is illegal to cast both a `Valid` and +`Invalid` vote on a given parachain block. Runtime handlers that take two conflicting votes as arguments and slash the offender are needed. @@ -173,9 +228,11 @@ Runtime handlers that take two conflicting votes as arguments and slash the offe Category: Node -This code-path is also taken by validators who self-select based on VRF [Availability and Validity — Research at W3F](https://research.web3.foundation/en/latest/polkadot/Availability_and_Validity.html). Validators and fishermen will select parachain blocks to re-validate. In these steps: -* Attempt to recover the PoV block, falling back on the erasure-coding. If not available, issue report. -* Attempt to validate the PoV block. If invalid, issue report. +This code-path is also taken by validators who self-select based on VRF [Availability and Validity — Research at +W3F](https://research.web3.foundation/en/latest/polkadot/Availability_and_Validity.html). Validators and fishermen will +select parachain blocks to re-validate. In these steps: +- Attempt to recover the PoV block, falling back on the erasure-coding. If not available, issue report. +- Attempt to validate the PoV block. If invalid, issue report. #### *Double-vote Fishing* @@ -186,45 +243,50 @@ Nodes that observe a double-vote in the attestation process should submit a repo --- # Phases -This roadmap is divided up into phases, where each represents another set of deliverables or iteration on a black-box component with respect to the prior phase. +This roadmap is divided up into phases, where each represents another set of deliverables or iteration on a black-box +component with respect to the prior phase. ## Phase 0: MVP -The very first phase - this is parachains without slashing (full security) or cross-chain messaging. It is primarily a PoC that registration and validation are working correctly. +The very first phase - this is parachains without slashing (full security) or cross-chain messaging. It is primarily a +PoC that registration and validation are working correctly. -### Infrastructure/API: - - Custom libp2p sub-protocols - - Peer Set Management +### Infrastructure/API +- Custom libp2p sub-protocols +- Peer Set Management -### Assignment: - - Auctions - - On-demand Blockspace purchase - - Validator Assignment +### Assignment +- Auctions +- On-demand Blockspace purchase +- Validator Assignment -### Agreement: - - Attestation Circulation (black box: gossip) - - Availability Erasure-coding (black box: gossip) - - PoV block fetching (black box: gossip) - - Collation Loop +### Agreement +- Attestation Circulation (black box: gossip) +- Availability Erasure-coding (black box: gossip) +- PoV block fetching (black box: gossip) +- Collation Loop -### Cross-chain Messaging: - - Finalize `CandidateReceipt` format +### Cross-chain Messaging +- Finalize `CandidateReceipt` format ## Phase 1: Fishing and Slashing -This phase marks advancement in the security of parachains. Once completed, parachains are a full-fledged cryptoeconomically secure rollup primitive. This phase also includes implementation work on XCMP, but does not enable it fully. +This phase marks advancement in the security of parachains. Once completed, parachains are a full-fledged +cryptoeconomically secure rollup primitive. This phase also includes implementation work on XCMP, but does not enable it +fully. ### Agreement - - Availability Erasure-coding (black box: targeted distribution) - - PoV block fetching (black box: targeted distribution and fetching) +- Availability Erasure-coding (black box: targeted distribution) +- PoV block fetching (black box: targeted distribution and fetching) ### Fishing/Slashing - - Validity/Availability Report Handler - - Double-vote Slash Handler - - Validity/Availability Fishing - - Double-vote Fishing -### Cross-chain Messaging: - - Finalize `PoVBlock` format. +- Validity/Availability Report Handler +- Double-vote Slash Handler +- Validity/Availability Fishing +- Double-vote Fishing + +### Cross-chain Messaging +- Finalize `PoVBlock` format. ## Phase 2: Messaging diff --git a/polkadot/runtime/rococo/README.md b/polkadot/runtime/rococo/README.md index 0f35665ca17..465afd25549 100644 --- a/polkadot/runtime/rococo/README.md +++ b/polkadot/runtime/rococo/README.md @@ -4,8 +4,10 @@ Rococo is a testnet runtime with no stability guarantees. ## How to run `rococo-local` -The [Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/) details building, starting, and testing `rococo-local` and parachains connecting to it. +The [Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/) details building, starting, and +testing `rococo-local` and parachains connecting to it. ## How to register a parachain on the Rococo testnet -The [parachain registration process](https://docs.substrate.io/tutorials/v3/cumulus/rococo/) on the public Rococo testnet is also outlined. +The [parachain registration process](https://docs.substrate.io/tutorials/v3/cumulus/rococo/) on the public Rococo +testnet is also outlined. diff --git a/polkadot/utils/staking-miner/README.md b/polkadot/utils/staking-miner/README.md index 7e7254dc775..8fec746e6ee 100644 --- a/polkadot/utils/staking-miner/README.md +++ b/polkadot/utils/staking-miner/README.md @@ -1,11 +1,19 @@ # Staking Miner -Substrate chains validators compute a basic solution for the NPoS election. The optimization of the solution is computing-intensive and can be delegated to the `staking-miner`. The `staking-miner` does not act as validator and focuses solely on the optimization of the solution. +Substrate chains validators compute a basic solution for the NPoS election. The optimization of the solution is +computing-intensive and can be delegated to the `staking-miner`. The `staking-miner` does not act as validator and +focuses solely on the optimization of the solution. -The staking miner connects to a specified chain and keeps listening to new Signed phase of the [pallet-election-provider-multi-phase](https://crates.parity.io/pallet_election_provider_multi_phase/index.html) in order to submit solutions to the NPoS election. When the correct time comes, it computes its solution and submit it to the chain. -The default miner algorithm is [sequential-phragmen](https://crates.parity.io/sp_npos_elections/phragmen/fn.seq_phragmen_core.html)] with a configurable number of balancing iterations that improve the score. +The staking miner connects to a specified chain and keeps listening to new Signed phase of the +[pallet-election-provider-multi-phase](https://crates.parity.io/pallet_election_provider_multi_phase/index.html) in +order to submit solutions to the NPoS election. When the correct time comes, it computes its solution and submit it to +the chain. The default miner algorithm is +[sequential-phragmen](https://crates.parity.io/sp_npos_elections/phragmen/fn.seq_phragmen_core.html)] with a +configurable number of balancing iterations that improve the score. -Running the staking-miner requires passing the seed of a funded account in order to pay the fees for the transactions that will be sent. The same account's balance is used to reserve deposits as well. The best solution in each round is rewarded. All correct solutions will get their bond back. Any invalid solution will lose their bond. +Running the staking-miner requires passing the seed of a funded account in order to pay the fees for the transactions +that will be sent. The same account's balance is used to reserve deposits as well. The best solution in each round is +rewarded. All correct solutions will get their bond back. Any invalid solution will lose their bond. You can check the help with: ``` @@ -22,13 +30,15 @@ cargo build --profile production --locked --package staking-miner --bin staking- ## Docker There are 2 options to build a staking-miner Docker image: -- injected binary: the binary is first built on a Linux host and then injected into a Docker base image. This method only works if you have a Linux host or access to a pre-built binary from a Linux host. -- multi-stage: the binary is entirely built within the multi-stage Docker image. There is no requirement on the host in terms of OS and the host does not even need to have any Rust toolchain installed. +- injected binary: the binary is first built on a Linux host and then injected into a Docker base image. This method + only works if you have a Linux host or access to a pre-built binary from a Linux host. +- multi-stage: the binary is entirely built within the multi-stage Docker image. There is no requirement on the host in + terms of OS and the host does not even need to have any Rust toolchain installed. ### Building the injected image -First build the binary as documented [above](#building). -You may then inject the binary into a Docker base image: `parity/base-bin` (running the command from the root of the Polkadot repository): +First build the binary as documented [above](#building). You may then inject the binary into a Docker base image: +`parity/base-bin` (running the command from the root of the Polkadot repository): ``` TODO: UPDATE THAT docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile target/release @@ -36,9 +46,9 @@ docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-mi ### Building the multi-stage image -Unlike the injected image that requires a Linux pre-built binary, this option does not requires a Linux host, nor Rust to be installed. -The trade-off however is that it takes a little longer to build and this option is less ideal for CI tasks. -You may build the multi-stage image the root of the Polkadot repository with: +Unlike the injected image that requires a Linux pre-built binary, this option does not requires a Linux host, nor Rust +to be installed. The trade-off however is that it takes a little longer to build and this option is less ideal for CI +tasks. You may build the multi-stage image the root of the Polkadot repository with: ``` TODO: UPDATE THAT docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile . @@ -46,8 +56,9 @@ docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-mi ### Running -A Docker container, especially one holding one of your `SEED` should be kept as secure as possible. -While it won't prevent a malicious actor to read your `SEED` if they gain access to your container, it is nonetheless recommended running this container in `read-only` mode: +A Docker container, especially one holding one of your `SEED` should be kept as secure as possible. While it won't +prevent a malicious actor to read your `SEED` if they gain access to your container, it is nonetheless recommended +running this container in `read-only` mode: ``` # The following line starts with an extra space on purpose: diff --git a/polkadot/xcm/xcm-simulator/fuzzer/README.md b/polkadot/xcm/xcm-simulator/fuzzer/README.md index 69e8cd377b9..0b3fdd8ec77 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/README.md +++ b/polkadot/xcm/xcm-simulator/fuzzer/README.md @@ -1,6 +1,7 @@ # XCM Simulator Fuzzer -This project will fuzz-test the XCM simulator. It can catch reachable panics, timeouts as well as integer overflows and underflows. +This project will fuzz-test the XCM simulator. It can catch reachable panics, timeouts as well as integer overflows and +underflows. ## Install dependencies @@ -29,7 +30,8 @@ cargo hfuzz run-debug xcm-fuzzer hfuzz_workspace/xcm-fuzzer/fuzzer_input_file In this directory, run these four commands: ``` -RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build +RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" \ +CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build ../../../target/debug/xcm-fuzzer hfuzz_workspace/xcm-fuzzer/input/ zip -0 ccov.zip `find ../../../target/ \( -name "*.gc*" -o -name "test-*.gc*" \) -print` grcov ccov.zip -s ../../../ -t html --llvm --branch --ignore-not-existing -o ./coverage diff --git a/polkadot/zombienet_tests/README.md b/polkadot/zombienet_tests/README.md index 84334c3e1cf..516ff880b2e 100644 --- a/polkadot/zombienet_tests/README.md +++ b/polkadot/zombienet_tests/README.md @@ -1,34 +1,38 @@ # Zombienet tests -_The content of this directory is meant to be used by Parity's private CI/CD infrastructure with private tools. At the moment those tools are still early stage of development and we don't know if / when they will available for public use._ +_The content of this directory is meant to be used by Parity's private CI/CD infrastructure with private tools. At the +moment those tools are still early stage of development and we don't know if / when they will available for public use._ ## Contents of this directory -`parachains` - At the moment this directory only have one test related to parachains: `/parachains-smoke-test`, that check the parachain registration and the block height. +`parachains` At the moment this directory only have one test related to parachains: `/parachains-smoke-test`, that check + the parachain registration and the block height. ## Resources -* [zombienet repo](https://github.com/paritytech/zombienet) -* [zombienet book](https://paritytech.github.io/zombienet/) +- [zombienet repo](https://github.com/paritytech/zombienet) +- [zombienet book](https://paritytech.github.io/zombienet/) ## Running tests locally -To run any test locally use the native provider (`zombienet test -p native ...`) you need first build the binaries. They are: +To run any test locally use the native provider (`zombienet test -p native ...`) you need first build the binaries. They +are: -* adder-collator -> polkadot/target/testnet/adder-collator -* malus -> polkadot/target/testnet/malus -* polkadot -> polkadot/target/testnet/polkadot, polkadot/target/testnet/polkadot-prepare-worker, polkadot/target/testnet/polkadot-execute-worker -* polkadot-collator -> cumulus/target/release/polkadot-parachain -* undying-collator -> polkadot/target/testnet/undying-collator +- `adder-collator` -> `polkadot/target/testnet/adder-collator` +- `malus` -> `polkadot/target/testnet/malus` +- `polkadot` -> `polkadot/target/testnet/polkadot`, `polkadot/target/testnet/polkadot-prepare-worker`, + `polkadot/target/testnet/polkadot-execute-worker` +- `polkadot-collator` -> `cumulus/target/release/polkadot-parachain` +- `undying-collator` -> `polkadot/target/testnet/undying-collator` To build them use: -* adder-collator -> `cargo build --profile testnet -p test-parachain-adder-collator` -* undying-collator -> `cargo build --profile testnet -p test-parachain-undying-collator` -* malus -> `cargo build --profile testnet -p polkadot-test-malus` -* polkadot (in polkadot repo) and polkadot-collator (in cumulus repo) -> `cargo build --profile testnet` +- `adder-collator` -> `cargo build --profile testnet -p test-parachain-adder-collator` +- `undying-collator` -> `cargo build --profile testnet -p test-parachain-undying-collator` +- `malus` -> `cargo build --profile testnet -p polkadot-test-malus` +- `polkadot` (in the Polkadot repo) and `polkadot-collator` (in Cumulus repo) -> `cargo build --profile testnet` -One solution is to use the `.set_env` file (from this directory) and fill the `CUSTOM_PATHS` before *source* it to patch the PATH of your system to find the binaries you just built. +One solution is to use the `.set_env` file (from this directory) and fill the `CUSTOM_PATHS` before _source_ it to patch +the PATH of your system to find the binaries you just built. E.g.: ``` @@ -45,8 +49,9 @@ CUSTOM_PATHS=( source .set_env ``` -Then you have your `PATH` customized and ready to run `zombienet`. - **NOTE**: You should need to do this ones per terminal session, since we are patching the `PATH` and re-exporting. **Or** you can also `source` this file in your `.bashrc` file to get executed automatically in each new session. +Then you have your `PATH` customized and ready to run `zombienet`. **NOTE**: You should need to do this ones per + terminal session, since we are patching the `PATH` and re-exporting. **Or** you can also `source` this file in your + `.bashrc` file to get executed automatically in each new session. Example: @@ -57,4 +62,5 @@ zombienet test -p native 0001-parachains-pvf.zndsl ## Questions / permissions -Ping in element Javier (@javier:matrix.parity.io) to ask questions or grant permission to run the test from your local setup. +Ping in element Javier (`@javier:matrix.parity.io`) to ask questions or grant permission to run the test from your local +setup. diff --git a/substrate/README.md b/substrate/README.md index 6ed64ac82ee..f7afa7a894d 100644 --- a/substrate/README.md +++ b/substrate/README.md @@ -1,27 +1,35 @@ -# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.md) [![Stack Exchange](https://img.shields.io/badge/Substrate-Community%20&%20Support-24CC85?logo=stackexchange)](https://substrate.stackexchange.com/) +# Substrate + +[![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) +[![GitLab +Status](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.md) +[![Stack +Exchange](https://img.shields.io/badge/Substrate-Community%20&%20Support-24CC85?logo=stackexchange)](https://substrate.stackexchange.com/)

- +

Substrate is a next-generation framework for blockchain innovation 🚀. ## Getting Started -Head to [docs.substrate.io](https://docs.substrate.io) and follow the -[installation](https://docs.substrate.io/install/) instructions. Then try out one of the -[tutorials](https://docs.substrate.io/tutorials/). Refer to the [Docker instructions](./docker/README.md) to quickly run Substrate, Substrate Node Template, Subkey, or to build a chain spec. +Head to [`docs.substrate.io`](https://docs.substrate.io) and follow the [installation](https://docs.substrate.io/install/) +instructions. Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). Refer to the [Docker +instructions](./docker/README.md) to quickly run Substrate, Substrate Node Template, Subkey, or to build a chain spec. ## Community & Support -Join the highly active and supportive community on the -[Substrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. -Please do report bugs and [issues here](https://github.com/paritytech/polkadot-sdk/issues) for anything you suspect requires action in the source. +Join the highly active and supportive community on the [Substrate Stack Exchange](https://substrate.stackexchange.com/) +to ask questions about use and problems you run into using this software. Please do report bugs and [issues +here](https://github.com/paritytech/polkadot-sdk/issues) for anything you suspect requires action in the source. ## Contributions & Code of Conduct Please follow the contributions guidelines as outlined in -[`docs/CONTRIBUTING.md`](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md). -In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CODE_OF_CONDUCT.md). +[`docs/CONTRIBUTING.md`](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md). In all +communications and contributions, this project follows the [Contributor Covenant Code of +Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CODE_OF_CONDUCT.md). ## Security @@ -30,15 +38,13 @@ The security policy and procedures can be found in ## License -- Substrate Primitives (`sp-*`), Frame (`frame-*`) and the pallets (`pallets-*`), binaries (`/bin`) -and all other utilities are licensed under [Apache 2.0](LICENSE-APACHE2). - Substrate Client -(`/client/*` / `sc-*`) is licensed under [GPL v3.0 with a classpath linking -exception](LICENSE-GPL3). +- Substrate Primitives (`sp-*`), Frame (`frame-*`) and the pallets (`pallets-*`), binaries (`/bin`) and all other +utilities are licensed under [Apache 2.0](LICENSE-APACHE2). - Substrate Client (`/client/*` / `sc-*`) is licensed under +[GPL v3.0 with a classpath linking exception](LICENSE-GPL3). -The reason for the split-licensing is to ensure that for the vast majority of teams using Substrate -to create feature-chains, then all changes can be made entirely in Apache2-licensed code, allowing -teams full freedom over what and how they release and giving licensing clarity to commercial teams. +The reason for the split-licensing is to ensure that for the vast majority of teams using Substrate to create +feature-chains, then all changes can be made entirely in Apache2-licensed code, allowing teams full freedom over what +and how they release and giving licensing clarity to commercial teams. -In the interests of the community, we require any deeper improvements made to Substrate's core logic -(e.g. Substrate's internal consensus, crypto or database code) to be contributed back so everyone -can benefit. +In the interests of the community, we require any deeper improvements made to Substrate's core logic (e.g. Substrate's +internal consensus, crypto or database code) to be contributed back so everyone can benefit. diff --git a/substrate/bin/node-template/README.md b/substrate/bin/node-template/README.md index 337facaaf08..a07328df88c 100644 --- a/substrate/bin/node-template/README.md +++ b/substrate/bin/node-template/README.md @@ -2,17 +2,26 @@ A fresh [Substrate](https://substrate.io/) node, ready for hacking :rocket: -A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) 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) 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) repository. +A standalone version of this template is available for each release of Polkadot +in the [Substrate Developer Hub Parachain +Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) +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) +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) +repository. ## Getting Started -Depending on your operating system and Rust version, there might be additional packages required to compile this template. -Check the [Install](https://docs.substrate.io/install/) instructions for your platform for the most common dependencies. -Alternatively, you can use one of the [alternative installation](#alternatives-installations) options. +Depending on your operating system and Rust version, there might be additional +packages required to compile this template. Check the +[Install](https://docs.substrate.io/install/) instructions for your platform for +the most common dependencies. Alternatively, you can use one of the [alternative +installation](#alternatives-installations) options. ### Build @@ -24,13 +33,16 @@ cargo build --release ### Embedded Docs -After you build the project, you can use the following command to explore its parameters and subcommands: +After you build the project, you can use the following command to explore its +parameters and subcommands: ```sh ./target/release/node-template -h ``` -You can generate and view the [Rust Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template with this command: +You can generate and view the [Rust +Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template +with this command: ```sh cargo +nightly doc --open @@ -38,7 +50,8 @@ cargo +nightly doc --open ### Single-Node Development Chain -The following command starts a single-node development chain that doesn't persist state: +The following command starts a single-node development chain that doesn't +persist state: ```sh ./target/release/node-template --dev @@ -61,10 +74,12 @@ Development chains: - Maintain state in a `tmp` folder while the node is running. - Use the **Alice** and **Bob** accounts as default validator authorities. - Use the **Alice** account as the default `sudo` account. -- Are preconfigured with a genesis state (`/node/src/chain_spec.rs`) that includes several prefunded development accounts. +- Are preconfigured with a genesis state (`/node/src/chain_spec.rs`) that + includes several prefunded development accounts. -To persist chain state between runs, specify a base path by running a command similar to the following: +To persist chain state between runs, specify a base path by running a command +similar to the following: ```sh // Create a folder to use as the db base path @@ -84,81 +99,127 @@ db keystore network ### Connect with Polkadot-JS Apps Front-End -After you start the node template locally, you can interact with it using the hosted version of the [Polkadot/Substrate Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) front-end by connecting to the local node endpoint. -A hosted version is also available on [IPFS (redirect) here](https://dotapps.io/) or [IPNS (direct) here](ipns://dotapps.io/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/explorer). -You can also find the source code and instructions for hosting your own instance on the [polkadot-js/apps](https://github.com/polkadot-js/apps) repository. +After you start the node template locally, you can interact with it using the +hosted version of the [Polkadot/Substrate +Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) +front-end by connecting to the local node endpoint. A hosted version is also +available on [IPFS (redirect) here](https://dotapps.io/) or [IPNS (direct) +here](ipns://dotapps.io/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/explorer). You can +also find the source code and instructions for hosting your own instance on the +[`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository. ### Multi-Node Local Testnet -If you want to see the multi-node consensus algorithm in action, see [Simulate a network](https://docs.substrate.io/tutorials/build-a-blockchain/simulate-network/). +If you want to see the multi-node consensus algorithm in action, see [Simulate a +network](https://docs.substrate.io/tutorials/build-a-blockchain/simulate-network/). ## Template Structure -A Substrate project such as this consists of a number of components that are spread across a few directories. +A Substrate project such as this consists of a number of components that are +spread across a few directories. ### Node -A blockchain node is an application that allows users to participate in a blockchain network. -Substrate-based blockchain nodes expose a number of capabilities: - -- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the - nodes in the network to communicate with one another. -- Consensus: Blockchains must have a way to come to [consensus](https://docs.substrate.io/fundamentals/consensus/) on the state of the network. - Substrate makes it possible to supply custom consensus engines and also ships with several consensus mechanisms that have been built on top of [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). -- RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. - -There are several files in the `node` directory. -Take special note of the following: - -- [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain specification](https://docs.substrate.io/build/chain-spec/) is a source code file that defines a Substrate chain's initial (genesis) state. - Chain specifications are useful for development and testing, and critical when architecting the launch of a production chain. - Take note of the `development_config` and `testnet_genesis` functions,. - These functions are used to define the genesis state for the local development chain configuration. - These functions identify some [well-known accounts](https://docs.substrate.io/reference/command-line-tools/subkey/) and use them to configure the blockchain's initial state. -- [`service.rs`](./node/src/service.rs): This file defines the node implementation. - Take note of the libraries that this file imports and the names of the functions it invokes. - In particular, there are references to consensus-related topics, such as the [block finalization and forks](https://docs.substrate.io/fundamentals/consensus/#finalization-and-forks) and other [consensus mechanisms](https://docs.substrate.io/fundamentals/consensus/#default-consensus-models) such as Aura for block authoring and GRANDPA for finality. - +A blockchain node is an application that allows users to participate in a +blockchain network. Substrate-based blockchain nodes expose a number of +capabilities: + +- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking + stack to allow the nodes in the network to communicate with one another. +- Consensus: Blockchains must have a way to come to + [consensus](https://docs.substrate.io/fundamentals/consensus/) on the state of + the network. Substrate makes it possible to supply custom consensus engines + and also ships with several consensus mechanisms that have been built on top + of [Web3 Foundation + research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). +- RPC Server: A remote procedure call (RPC) server is used to interact with + Substrate nodes. + +There are several files in the `node` directory. Take special note of the +following: + +- [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain + specification](https://docs.substrate.io/build/chain-spec/) is a source code + file that defines a Substrate chain's initial (genesis) state. Chain + specifications are useful for development and testing, and critical when + architecting the launch of a production chain. Take note of the + `development_config` and `testnet_genesis` functions,. These functions are + used to define the genesis state for the local development chain + configuration. These functions identify some [well-known + accounts](https://docs.substrate.io/reference/command-line-tools/subkey/) and + use them to configure the blockchain's initial state. +- [`service.rs`](./node/src/service.rs): This file defines the node + implementation. Take note of the libraries that this file imports and the + names of the functions it invokes. In particular, there are references to + consensus-related topics, such as the [block finalization and + forks](https://docs.substrate.io/fundamentals/consensus/#finalization-and-forks) + and other [consensus + mechanisms](https://docs.substrate.io/fundamentals/consensus/#default-consensus-models) + such as Aura for block authoring and GRANDPA for finality. ### Runtime In Substrate, the terms "runtime" and "state transition function" are analogous. -Both terms refer to the core logic of the blockchain that is responsible for validating blocks and executing the state changes they define. -The Substrate project in this repository uses [FRAME](https://docs.substrate.io/learn/runtime-development/#frame) to construct a blockchain runtime. -FRAME allows runtime developers to declare domain-specific logic in modules called "pallets". -At the heart of FRAME is a helpful [macro language](https://docs.substrate.io/reference/frame-macros/) that makes it easy to create pallets and flexibly compose them to create blockchains that can address [a variety of needs](https://substrate.io/ecosystem/projects/). - -Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note the following: - -- This file configures several pallets to include in the runtime. - Each pallet configuration is defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. -- The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://paritytech.github.io/substrate/master/frame_support/macro.construct_runtime.html) macro, which is part of the [core FRAME pallet library](https://docs.substrate.io/reference/frame-pallets/#system-pallets). +Both terms refer to the core logic of the blockchain that is responsible for +validating blocks and executing the state changes they define. The Substrate +project in this repository uses +[FRAME](https://docs.substrate.io/learn/runtime-development/#frame) to construct +a blockchain runtime. FRAME allows runtime developers to declare domain-specific +logic in modules called "pallets". At the heart of FRAME is a helpful [macro +language](https://docs.substrate.io/reference/frame-macros/) that makes it easy +to create pallets and flexibly compose them to create blockchains that can +address [a variety of needs](https://substrate.io/ecosystem/projects/). + +Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this +template and note the following: + +- This file configures several pallets to include in the runtime. Each pallet + configuration is defined by a code block that begins with `impl + $PALLET_NAME::Config for Runtime`. +- The pallets are composed into a single runtime by way of the + [`construct_runtime!`](https://paritytech.github.io/substrate/master/frame_support/macro.construct_runtime.html) + macro, which is part of the [core FRAME pallet + library](https://docs.substrate.io/reference/frame-pallets/#system-pallets). ### Pallets -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 template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. +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 +template pallet that is [defined in the +`pallets`](./pallets/template/src/lib.rs) directory. A FRAME pallet is comprised of a number of blockchain primitives, including: -- Storage: FRAME defines a rich set of powerful [storage abstractions](https://docs.substrate.io/build/runtime-storage/) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. -- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. -- Events: Substrate uses [events](https://docs.substrate.io/build/events-and-errors/) to notify users of significant state changes. +- Storage: FRAME defines a rich set of powerful [storage + abstractions](https://docs.substrate.io/build/runtime-storage/) that makes it + easy to use Substrate's efficient key-value database to manage the evolving + state of a blockchain. +- Dispatchables: FRAME pallets define special types of functions that can be + invoked (dispatched) from outside of the runtime in order to update its state. +- Events: Substrate uses + [events](https://docs.substrate.io/build/events-and-errors/) to notify users + of significant state changes. - Errors: When a dispatchable fails, it returns an error. -Each pallet has its own `Config` trait which serves as a configuration interface to generically define the types and parameters it depends on. +Each pallet has its own `Config` trait which serves as a configuration interface +to generically define the types and parameters it depends on. ## Alternatives Installations -Instead of installing dependencies and building this source directly, consider the following alternatives. +Instead of installing dependencies and building this source directly, consider +the following alternatives. ### Nix Install [nix](https://nixos.org/) and -[nix-direnv](https://github.com/nix-community/nix-direnv) for a fully plug-and-play -experience for setting up the development environment. -To get all the correct dependencies, activate direnv `direnv allow`. +[nix-direnv](https://github.com/nix-community/nix-direnv) for a fully +plug-and-play experience for setting up the development environment. To get all +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 build the Docker container with the Substrate Node Template binary. +Please follow the [Substrate Docker instructions +here](https://github.com/paritytech/substrate/blob/master/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 133db0277bb..38fddd5026b 100644 --- a/substrate/bin/node-template/docs/rust-setup.md +++ b/substrate/bin/node-template/docs/rust-setup.md @@ -1,22 +1,18 @@ ---- -title: Installation ---- +# Installation -This guide is for reference only, please check the latest information on getting started with Substrate -[here](https://docs.substrate.io/main-docs/install/). +This guide is for reference only, please check the latest information on getting started with Substrate [here](https://docs.substrate.io/main-docs/install/). -This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. -Since Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first -thing you will need to do is prepare the computer for Rust development - these steps will vary based -on the computer's operating system. Once Rust is configured, you will use its toolchains to interact -with Rust projects; the commands for Rust's toolchains will be the same for all supported, -Unix-based operating systems. +This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. Since +Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do +is prepare the computer for Rust development - these steps will vary based on the computer's operating system. Once Rust +is configured, you will use its toolchains to interact with Rust projects; the commands for Rust's toolchains will be +the same for all supported, Unix-based operating systems. ## Build dependencies -Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples -in the [Substrate Docs](https://docs.substrate.io) use Unix-style terminals to demonstrate how to -interact with Substrate from the command line. +Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples in the [Substrate +Docs](https://docs.substrate.io) use Unix-style terminals to demonstrate how to interact with Substrate from the command +line. ### Ubuntu/Debian @@ -55,10 +51,9 @@ sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel ### macOS -> **Apple M1 ARM** -> If you have an Apple M1 ARM system on a chip, make sure that you have Apple Rosetta 2 -> installed through `softwareupdate --install-rosetta`. This is only needed to run the -> `protoc` tool during the build. The build itself and the target binaries would remain native. +> **Apple M1 ARM** If you have an Apple M1 ARM system on a chip, make sure that you have Apple Rosetta 2 installed +> through `softwareupdate --install-rosetta`. This is only needed to run the `protoc` tool during the build. The build +> itself and the target binaries would remain native. Open the Terminal application and execute the following commands: @@ -81,8 +76,8 @@ Please refer to the separate ## Rust developer environment -This guide uses installer and the `rustup` tool to manage the Rust toolchain. -First install and configure `rustup`: +This guide uses installer and the `rustup` tool to manage the Rust toolchain. First install and +configure `rustup`: ```bash # Install @@ -102,13 +97,13 @@ rustup target add wasm32-unknown-unknown --toolchain nightly ## Test your set-up -Now the best way to ensure that you have successfully prepared a computer for Substrate -development is to follow the steps in [our first Substrate tutorial](https://docs.substrate.io/tutorials/v3/create-your-first-substrate-chain/). +Now the best way to ensure that you have successfully prepared a computer for Substrate development is to follow the +steps in [our first Substrate tutorial](https://docs.substrate.io/tutorials/v3/create-your-first-substrate-chain/). ## Troubleshooting Substrate builds -Sometimes you can't get the Substrate node template -to compile out of the box. Here are some tips to help you work through that. +Sometimes you can't get the Substrate node template to compile out of the box. Here are some tips to help you work +through that. ### Rust configuration check @@ -144,27 +139,27 @@ stable-x86_64-unknown-linux-gnu (default) rustc 1.50.0 (cb75ad5db 2021-02-10) ``` -As you can see above, the default toolchain is stable, and the -`nightly-x86_64-unknown-linux-gnu` toolchain as well as its `wasm32-unknown-unknown` target is installed. -You also see that `nightly-2020-10-06-x86_64-unknown-linux-gnu` is installed, but is not used unless explicitly defined as illustrated in the [specify your nightly version](#specifying-nightly-version) -section. +As you can see above, the default toolchain is stable, and the `nightly-x86_64-unknown-linux-gnu` toolchain as well as +its `wasm32-unknown-unknown` target is installed. You also see that `nightly-2020-10-06-x86_64-unknown-linux-gnu` is +installed, but is not used unless explicitly defined as illustrated in the [specify your nightly +version](#specifying-nightly-version) section. ### WebAssembly compilation -Substrate uses [WebAssembly](https://webassembly.org) (Wasm) to produce portable blockchain -runtimes. You will need to configure your Rust compiler to use -[`nightly` builds](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) to allow you to -compile Substrate runtime code to the Wasm target. +Substrate uses [WebAssembly](https://webassembly.org) (Wasm) to produce portable blockchain runtimes. You will need to +configure your Rust compiler to use [`nightly` builds](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) to +allow you to compile Substrate runtime code to the Wasm target. > There are upstream issues in Rust that need to be resolved before all of Substrate can use the stable Rust toolchain. -> [This is our tracking issue](https://github.com/paritytech/substrate/issues/1252) if you're curious as to why and how this will be resolved. +> [This is our tracking issue](https://github.com/paritytech/substrate/issues/1252) if you're curious as to why and how +> this will be resolved. #### Latest nightly for Substrate `master` -Developers who are building Substrate _itself_ should always use the latest bug-free versions of -Rust stable and nightly. This is because the Substrate codebase follows the tip of Rust nightly, -which means that changes in Substrate often depend on upstream changes in the Rust nightly compiler. -To ensure your Rust compiler is always up to date, you should run: +Developers who are building Substrate _itself_ should always use the latest bug-free versions of Rust stable and +nightly. This is because the Substrate codebase follows the tip of Rust nightly, which means that changes in Substrate +often depend on upstream changes in the Rust nightly compiler. To ensure your Rust compiler is always up to date, you +should run: ```bash rustup update @@ -172,21 +167,19 @@ rustup update nightly rustup target add wasm32-unknown-unknown --toolchain nightly ``` -> NOTE: It may be necessary to occasionally rerun `rustup update` if a change in the upstream Substrate -> codebase depends on a new feature of the Rust compiler. When you do this, both your nightly -> and stable toolchains will be pulled to the most recent release, and for nightly, it is -> generally _not_ expected to compile WASM without error (although it very often does). -> Be sure to [specify your nightly version](#specifying-nightly-version) if you get WASM build errors -> from `rustup` and [downgrade nightly as needed](#downgrading-rust-nightly). +> NOTE: It may be necessary to occasionally rerun `rustup update` if a change in the upstream Substrate codebase depends +> on a new feature of the Rust compiler. When you do this, both your nightly and stable toolchains will be pulled to the +> most recent release, and for nightly, it is generally _not_ expected to compile WASM without error (although it very +> often does). Be sure to [specify your nightly version](#specifying-nightly-version) if you get WASM build errors from +> `rustup` and [downgrade nightly as needed](#downgrading-rust-nightly). #### Rust nightly toolchain -If you want to guarantee that your build works on your computer as you update Rust and other -dependencies, you should 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). +If you want to guarantee that your build works on your computer as you update Rust and other dependencies, you should +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). ```bash # Specify the specific nightly toolchain in the date below: @@ -203,20 +196,20 @@ rustup target add wasm32-unknown-unknown --toolchain nightly- ### Specifying nightly version -Use the `WASM_BUILD_TOOLCHAIN` environment variable to specify the Rust nightly version a Substrate -project should use for Wasm compilation: +Use the `WASM_BUILD_TOOLCHAIN` environment variable to specify the Rust nightly version a Substrate project should use +for Wasm compilation: ```bash WASM_BUILD_TOOLCHAIN=nightly- cargo build --release ``` -> Note that this only builds _the runtime_ with the specified nightly. The rest of project will be -> compiled with **your default toolchain**, i.e. the latest installed stable toolchain. +> Note that this only builds _the runtime_ with the specified nightly. The rest of project will be compiled with **your +> default toolchain**, i.e. the latest installed stable toolchain. ### Downgrading Rust nightly -If your computer is configured to use the latest Rust nightly and you would like to downgrade to a -specific nightly version, follow these steps: +If your computer is configured to use the latest Rust nightly and you would like to downgrade to a specific nightly +version, follow these steps: ```bash rustup uninstall nightly diff --git a/substrate/bin/node-template/pallets/template/README.md b/substrate/bin/node-template/pallets/template/README.md index d0d59537c12..9e4dc55267d 100644 --- a/substrate/bin/node-template/pallets/template/README.md +++ b/substrate/bin/node-template/pallets/template/README.md @@ -1 +1 @@ -License: MIT-0 \ No newline at end of file +License: MIT-0 diff --git a/substrate/bin/utils/subkey/README.md b/substrate/bin/utils/subkey/README.md index d19ccefb59a..60e5a9ca935 100644 --- a/substrate/bin/utils/subkey/README.md +++ b/substrate/bin/utils/subkey/README.md @@ -1,26 +1,33 @@ # Subkey -Subkey is a commandline utility included with Substrate. It allows generating and restoring keys for Substrate based chains such as Polkadot, Kusama and a growing number of parachains and Substrate based projects. +Subkey is a commandline utility included with Substrate. It allows generating and restoring keys for Substrate based +chains such as Polkadot, Kusama and a growing number of parachains and Substrate based projects. `subkey` provides a few sub-commands to generate keys, check keys, sign messages, verify messages, etc... -You can see the full list of commands with `subkey --help`. Most commands have additional help available with for instance `subkey generate --help` for the `generate` command. +You can see the full list of commands with `subkey --help`. Most commands have additional help available with for +instance `subkey generate --help` for the `generate` command. ## Safety first -`subkey` does not need an internet connection to work. Indeed, for the best security, you should be using `subkey` on a machine that is **not connected** to the internet. +`subkey` does not need an internet connection to work. Indeed, for the best security, you should be using `subkey` on a +machine that is **not connected** to the internet. -`subkey` deals with **seeds** and **private keys**. Make sure to use `subkey` in a safe environment (ie. no one looking over your shoulder) and on a safe computer (ie. no one able to check your command history). +`subkey` deals with **seeds** and **private keys**. Make sure to use `subkey` in a safe environment (ie. no one looking +over your shoulder) and on a safe computer (ie. no one able to check your command history). -If you save any output of `subkey` into a file, make sure to apply proper permissions and/or delete the file as soon as possible. +If you save any output of `subkey` into a file, make sure to apply proper permissions and/or delete the file as soon as +possible. ## Usage -The following guide explains *some* of the `subkey` commands. For the full list and the most up to date documentation, make sure to check the integrated help with `subkey --help`. +The following guide explains *some* of the `subkey` commands. For the full list and the most up to date documentation, +make sure to check the integrated help with `subkey --help`. ### Install with Cargo -You will need to have the Substrate build dependencies to install Subkey. Use the following two commands to install the dependencies and Subkey, respectively: +You will need to have the Substrate build dependencies to install Subkey. Use the following two commands to install the +dependencies and Subkey, respectively: Command: @@ -58,19 +65,26 @@ Secret phrase `hotel forest jar hover kite book view eight stuff angle legend de --- ☠️ DO NT RE-USE ANY OF THE SEEDS AND SECRETS FROM THIS PAGE ☠️. -You can read more about security and risks in [SECURITY.md](./SECURITY.md) and in the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-account-generation). +You can read more about security and risks in [SECURITY.md](./SECURITY.md) and in the [Polkadot +Wiki](https://wiki.polkadot.network/docs/learn-account-generation). --- -The output above shows a **secret phrase** (also called **mnemonic phrase**) and the **secret seed** (also called **Private Key**). Those 2 secrets are the pieces of information you MUST keep safe and secret. All the other information below can be derived from those secrets. +The output above shows a **secret phrase** (also called **mnemonic phrase**) and the **secret seed** (also called +**Private Key**). Those 2 secrets are the pieces of information you MUST keep safe and secret. All the other information +below can be derived from those secrets. -The output above also show the **public key** and the **Account ID**. Those are the independant from the network where you will use the key. +The output above also show the **public key** and the **Account ID**. Those are the independant from the network where +you will use the key. -The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for a given network (for instance Kusama or Polkadot). +The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for +a given network (for instance Kusama or Polkadot). -You can read more about the [SS58 format in the Substrate Docs](https://docs.substrate.io/reference/address-formats/) and see the list of reserved prefixes in the [SS58 Registry](https://github.com/paritytech/ss58-registry). +You can read more about the [SS58 format in the Substrate Docs](https://docs.substrate.io/reference/address-formats/) +and see the list of reserved prefixes in the [SS58 Registry](https://github.com/paritytech/ss58-registry). -For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` the SS58 addresses are: +For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` the +SS58 addresses are: - Polkadot: `16m4J167Mptt8UXL8aGSAi7U2FnPpPxZHPrCgMG9KJzVoFqM` - Kusama: `JLNozAv8QeLSbLFwe2UvWeKKE4yvmDbfGxTuiYkF2BUMx4M` @@ -129,13 +143,17 @@ Secret phrase `soup lyrics media market way crouch elevator put moon useful ques SS58 Address: 5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC ``` -Using the `inspect` command (see more details below), we see that knowning only the **secret seed** is no longer sufficient to recover the account: +Using the `inspect` command (see more details below), we see that knowning only the **secret seed** is no longer +sufficient to recover the account: ```bash subkey inspect "soup lyrics media market way crouch elevator put moon useful question wide" ``` -which recovers the account `5Fe4sqj2K4fRuzEGvToi4KATqZfiDU7TqynjXG6PZE2dxwyh` and not `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC` as we expected. The additional user-defined **password** (`extra_secret` in our example) is now required to fully recover the account. Let's inspect the the previous mnemonic, this time passing also the required `password` as shown below: +which recovers the account `5Fe4sqj2K4fRuzEGvToi4KATqZfiDU7TqynjXG6PZE2dxwyh` and not +`5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC` as we expected. The additional user-defined **password** +(`extra_secret` in our example) is now required to fully recover the account. Let's inspect the the previous mnemonic, +this time passing also the required `password` as shown below: ```bash subkey inspect --password extra_secret "soup lyrics media market way crouch elevator put moon useful question wide" @@ -161,7 +179,8 @@ subkey inspect --public < pubkey | address > **NOTE**: While you will be able to recover the secret seed from the mnemonic, the opposite is not possible. -**NOTE**: For obvious reasons, the **secrets** cannot be recovered from passing **public data** such as `pubkey` or `address` as input. +**NOTE**: For obvious reasons, the **secrets** cannot be recovered from passing **public data** such as `pubkey` or +`address` as input. command: @@ -181,7 +200,8 @@ Secret Key URI `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c9 ### Signing -`subkey` allows using a **secret key** to sign a random message. The signature can then be verified by anyone using your **public key**: +`subkey` allows using a **secret key** to sign a random message. The signature can then be verified by anyone using your +**public key**: ```bash echo -n | subkey sign --suri @@ -201,11 +221,13 @@ output: 9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c ``` -**NOTE**: Each run of the `sign` command will yield a different output. While each signature is different, they are all valid. +**NOTE**: Each run of the `sign` command will yield a different output. While each signature is different, they are all +valid. ### Verifying a signature -Given a message, a signature and an address, `subkey` can verify whether the **message** has been digitally signed by the holder (or one of the holders) of the **private key** for the given **address**: +Given a message, a signature and an address, `subkey` can verify whether the **message** has been digitally signed by +the holder (or one of the holders) of the **private key** for the given **address**: ```bash echo -n | subkey verify
@@ -234,7 +256,8 @@ Error: SignatureInvalid ### Using the vanity generator -You can use the included vanity generator to find a seed that provides an address which includes the desired pattern. Be warned, depending on your hardware this may take a while. +You can use the included vanity generator to find a seed that provides an address which includes the desired pattern. Be +warned, depending on your hardware this may take a while. command: @@ -256,7 +279,9 @@ Secret Key URI `0x8c9a73097f235b84021a446bc2826a00c690ea0be3e0d81a84931cb4146d66 `Bob` now got a nice address starting with their name: 1**bob**YxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE. -**Note**: While `Bob`, having a short name (3 chars), got a result rather quickly, it will take much longer for `Alice` who has a much longer name, thus the chances to generate a random address that contains the chain `alice` will be much smaller. +**Note**: While `Bob`, having a short name (3 chars), got a result rather quickly, it will take much longer for `Alice` +who has a much longer name, thus the chances to generate a random address that contains the chain `alice` will be much +smaller. ## License diff --git a/substrate/bin/utils/subkey/SECURITY.md b/substrate/bin/utils/subkey/SECURITY.md index 672d2965c7e..698f119c292 100644 --- a/substrate/bin/utils/subkey/SECURITY.md +++ b/substrate/bin/utils/subkey/SECURITY.md @@ -1,8 +1,9 @@ # Keys and Security -The following information is not exhaustive but meant to prevent the most common mistakes. -You can read more about security and risks in the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-account-generation). -The Polkadot network has a few **test networks**, e.g. **Westend**. Test networks are a great way to experiment and learn safely as you can lose tokens on those networks without any financial consequences. +The following information is not exhaustive but meant to prevent the most common mistakes. You can read more about +security and risks in the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-account-generation). The Polkadot +network has a few **test networks**, e.g. **Westend**. Test networks are a great way to experiment and learn safely as +you can lose tokens on those networks without any financial consequences. `subkey` generates and provides 2 pieces of **secret** information: - **secret phrase**: a bunch of words, exactly 12 by default (can be 12, 15, 18, 21 or 24) @@ -10,16 +11,22 @@ The Polkadot network has a few **test networks**, e.g. **Westend**. Test network There are 2 risks related to private keys: - loss of keys: this can happen if you don't have a proper backup -- leak of the keys: this can unfortunately happen in many ways, including malware, phishing, key logger, backups on system that are online and not properly secured +- leak of the keys: this can unfortunately happen in many ways, including malware, phishing, key logger, backups on + system that are online and not properly secured You want to ensure that: - you **do not lose** those secrets - **no one but you can access** those secrets -☠️ **DO NOT SHARE** your mnemonic phrase or secret seed with ANYONE under **ANY** circumstances. Doing so would give them access to your funds and to send transactions on your behalf. +☠️ **DO NOT SHARE** your mnemonic phrase or secret seed with ANYONE under **ANY** circumstances. Doing so would give +them access to your funds and to send transactions on your behalf. -☠️ If someone is asking for your **secret** phrase or **secret** seed, you can be **SURE** they are attempting to steal your funds. +☠️ If someone is asking for your **secret** phrase or **secret** seed, you can be **SURE** they are attempting to steal +your funds. -✅ It is however fine to share your **SS58 Address** as this is meant to be public information and is needed by anyone you want to be able to make transfer to or otherwise interact with your account. They will only ever need your **Public Address**. +✅ It is however fine to share your **SS58 Address** as this is meant to be public information and is needed by anyone +you want to be able to make transfer to or otherwise interact with your account. They will only ever need your **Public +Address**. -⚠️ While using the same key on multiple networks is possible, it is usually **not** recommended unless you have good motivations for doing so and understand the associated risks and drawbacks. +⚠️ While using the same key on multiple networks is possible, it is usually **not** recommended unless you have good +motivations for doing so and understand the associated risks and drawbacks. diff --git a/substrate/client/allocator/README.md b/substrate/client/allocator/README.md index b89348b4c69..e5a94e50f36 100644 --- a/substrate/client/allocator/README.md +++ b/substrate/client/allocator/README.md @@ -3,4 +3,4 @@ Collection of allocator implementations. This crate provides the following allocator implementations: - A freeing-bump allocator: [`FreeingBumpHeapAllocator`](https://docs.rs/sc-allocator/latest/sc_allocator/struct.FreeingBumpHeapAllocator.html) -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/client/api/README.md b/substrate/client/api/README.md index 142f5b32dd9..7f94b1ca5e6 100644 --- a/substrate/client/api/README.md +++ b/substrate/client/api/README.md @@ -1,3 +1,3 @@ Substrate client interfaces. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/block-builder/README.md b/substrate/client/block-builder/README.md index b105d420336..f255b9a5480 100644 --- a/substrate/client/block-builder/README.md +++ b/substrate/client/block-builder/README.md @@ -6,4 +6,4 @@ This crate provides the [`BlockBuilder`] utility and the corresponding runtime a The block builder utility is used in the node as an abstraction over the runtime api to initialize a block, to push extrinsics and to finalize a block. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/chain-spec/README.md b/substrate/client/chain-spec/README.md index 5525affbed8..dad1662d323 100644 --- a/substrate/client/chain-spec/README.md +++ b/substrate/client/chain-spec/README.md @@ -89,4 +89,4 @@ pub struct Extension { pub type MyChainSpec = GenericChainSpec; ``` -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/cli/README.md b/substrate/client/cli/README.md index 2504dbb0c03..aeaee1e1219 100644 --- a/substrate/client/cli/README.md +++ b/substrate/client/cli/README.md @@ -1,3 +1,3 @@ Substrate CLI library. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/aura/README.md b/substrate/client/consensus/aura/README.md index 85d82cd7dfd..cefa5f6c7d9 100644 --- a/substrate/client/consensus/aura/README.md +++ b/substrate/client/consensus/aura/README.md @@ -1,4 +1,4 @@ -Aura (Authority-round) consensus in substrate. +Aura (Authority-round) consensus in Substrate. Aura works by having a list of authorities A who are expected to roughly agree on the current time. Time is divided up into discrete slots of t @@ -12,4 +12,4 @@ far in the future they are. NOTE: Aura itself is designed to be generic over the crypto used. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/babe/README.md b/substrate/client/consensus/babe/README.md index a404d2ea447..a3cf944b513 100644 --- a/substrate/client/consensus/babe/README.md +++ b/substrate/client/consensus/babe/README.md @@ -45,4 +45,4 @@ blocks) and will go with the longest one in case of a tie. An in-depth description and analysis of the protocol can be found here: -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/babe/rpc/README.md b/substrate/client/consensus/babe/rpc/README.md index e76dd3dc67f..e1a366204cd 100644 --- a/substrate/client/consensus/babe/rpc/README.md +++ b/substrate/client/consensus/babe/rpc/README.md @@ -1,3 +1,3 @@ RPC api for babe. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/common/README.md b/substrate/client/consensus/common/README.md index a6717a1d7a6..9b953fbf327 100644 --- a/substrate/client/consensus/common/README.md +++ b/substrate/client/consensus/common/README.md @@ -1,3 +1,3 @@ Collection of common consensus specific implementations -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/epochs/README.md b/substrate/client/consensus/epochs/README.md index 1e74e04172c..e4abc58c6c0 100644 --- a/substrate/client/consensus/epochs/README.md +++ b/substrate/client/consensus/epochs/README.md @@ -1,3 +1,3 @@ Generic utilities for epoch-based consensus engines. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/grandpa/README.md b/substrate/client/consensus/grandpa/README.md index 64a7e70bc6a..f4045896599 100644 --- a/substrate/client/consensus/grandpa/README.md +++ b/substrate/client/consensus/grandpa/README.md @@ -1,4 +1,4 @@ -Integration of the GRANDPA finality gadget into substrate. +Integration of the GRANDPA finality gadget into Substrate. This crate is unstable and the API and usage may change. @@ -36,4 +36,4 @@ number (this is num(signal) + N). When finalizing a block, we either apply or prune any signaled changes based on whether the signaling block is included in the newly-finalized chain. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/grandpa/rpc/README.md b/substrate/client/consensus/grandpa/rpc/README.md index 0007f55dbd4..ad73878a61b 100644 --- a/substrate/client/consensus/grandpa/rpc/README.md +++ b/substrate/client/consensus/grandpa/rpc/README.md @@ -1,3 +1,3 @@ RPC API for GRANDPA. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/manual-seal/README.md b/substrate/client/consensus/manual-seal/README.md index b355f8b7318..131b620cb2f 100644 --- a/substrate/client/consensus/manual-seal/README.md +++ b/substrate/client/consensus/manual-seal/README.md @@ -1,4 +1,4 @@ A manual sealing engine: the engine listens for rpc calls to seal blocks and create forks. This is suitable for a testing environment. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/slots/README.md b/substrate/client/consensus/slots/README.md index 9ab3c3742f3..aa896430f7d 100644 --- a/substrate/client/consensus/slots/README.md +++ b/substrate/client/consensus/slots/README.md @@ -4,4 +4,4 @@ Some consensus algorithms have a concept of *slots*, which are intervals in time during which certain events can and/or must occur. This crate provides generic functionality for slots. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/db/README.md b/substrate/client/db/README.md index e5fb3fce1d9..a11ae0d6f57 100644 --- a/substrate/client/db/README.md +++ b/substrate/client/db/README.md @@ -8,4 +8,4 @@ having discarded heavy state that will allow a chain reorganization. Finality implies canonicality but not vice-versa. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/executor/README.md b/substrate/client/executor/README.md index ab7b3d45206..6a35697962f 100644 --- a/substrate/client/executor/README.md +++ b/substrate/client/executor/README.md @@ -10,4 +10,4 @@ provided into the wasm runtime module. by the current value of `:code` in the provided externalities), i.e. interfacing with wasm engine used, instance cache. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/executor/common/README.md b/substrate/client/executor/common/README.md index 0c0d3bf08bc..253d7340313 100644 --- a/substrate/client/executor/common/README.md +++ b/substrate/client/executor/common/README.md @@ -1,3 +1,3 @@ A set of common definitions that are needed for defining execution engines. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/executor/wasmtime/README.md b/substrate/client/executor/wasmtime/README.md index 3e9ac0bddbd..64fc2fa0c28 100644 --- a/substrate/client/executor/wasmtime/README.md +++ b/substrate/client/executor/wasmtime/README.md @@ -1 +1 @@ -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/informant/README.md b/substrate/client/informant/README.md index b494042590a..a5ad89a932d 100644 --- a/substrate/client/informant/README.md +++ b/substrate/client/informant/README.md @@ -1,3 +1,3 @@ Console informant. Prints sync progress and block events. Runs on the calling thread. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/keystore/README.md b/substrate/client/keystore/README.md index 9946a61d6fd..5d50f7ad2cf 100644 --- a/substrate/client/keystore/README.md +++ b/substrate/client/keystore/README.md @@ -1,3 +1,3 @@ Keystore (and session key management) for ed25519 based chains like Polkadot. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/network-gossip/README.md b/substrate/client/network-gossip/README.md index 9030fac0564..900f223251d 100644 --- a/substrate/client/network-gossip/README.md +++ b/substrate/client/network-gossip/README.md @@ -38,4 +38,4 @@ opens the door for neighbor status packets to be baked into the gossip protocol. These status packets will typically contain light pieces of information used to inform peers of a current view of protocol state. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/network/README.md b/substrate/client/network/README.md index cad46d05909..f4031fbd308 100644 --- a/substrate/client/network/README.md +++ b/substrate/client/network/README.md @@ -80,8 +80,8 @@ is "dot". In the protocol names below, `` must be replaced with the protocol ID. > **Note**: It is possible for the same connection to be used for multiple chains. For example, -> one can use both the `/dot/sync/2` and `/sub/sync/2` protocols on the same -> connection, provided that the remote supports them. +> one can use both the `/dot/sync/2` and `/sub/sync/2` protocols on the same +> connection, provided that the remote supports them. Substrate uses the following standard libp2p protocols: @@ -138,7 +138,7 @@ substream is closed, the entire connection is closed as well. This is a bug that resolved by deprecating the protocol entirely. Within the unique Substrate substream, messages encoded using -[*parity-scale-codec*](https://github.com/paritytech/parity-scale-codec) are exchanged. +[`parity-scale-codec``](https://github.com/paritytech/parity-scale-codec) are exchanged. The detail of theses messages is not totally in place, but they can be found in the `message.rs` file. @@ -240,7 +240,7 @@ The state is then imported into the database and the keep-up sync starts in norm This is similar to fast sync, but instead of downloading and verifying full header chain, the algorithm only downloads finalized authority set changes. -### GRANDPA warp sync. +### GRANDPA warp sync GRANDPA keeps justifications for each finalized authority set change. Each change is signed by the authorities from the previous set. By downloading and verifying these signed hand-offs starting from genesis, @@ -254,7 +254,7 @@ the fast sync. The state is verified to match the header storage root. After the database it is queried for the information that allows GRANDPA and BABE to continue operating from that state. This includes BABE epoch information and GRANDPA authority set id. -### Background block download. +### Background block download After the latest state has been imported the node is fully operational, but is still missing historic block data. I.e. it is unable to serve bock bodies and headers other than the most recent one. To make sure all diff --git a/substrate/client/offchain/README.md b/substrate/client/offchain/README.md index f7c097e8e0b..74d54c0c234 100644 --- a/substrate/client/offchain/README.md +++ b/substrate/client/offchain/README.md @@ -15,4 +15,4 @@ for instance via: 2. Majority voting for results 3. etc -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/proposer-metrics/README.md b/substrate/client/proposer-metrics/README.md index 9669c7d3519..27a6b726814 100644 --- a/substrate/client/proposer-metrics/README.md +++ b/substrate/client/proposer-metrics/README.md @@ -1,3 +1,3 @@ Prometheus basic proposer metrics. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/rpc-api/README.md b/substrate/client/rpc-api/README.md index e860e0c2334..8ea6e686c1a 100644 --- a/substrate/client/rpc-api/README.md +++ b/substrate/client/rpc-api/README.md @@ -1,5 +1,5 @@ Substrate RPC interfaces. -A collection of RPC methods and subscriptions supported by all substrate clients. +A collection of RPC methods and subscriptions supported by all Substrate clients. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/rpc-servers/README.md b/substrate/client/rpc-servers/README.md index cf00b3169a6..16f1bb9f2a3 100644 --- a/substrate/client/rpc-servers/README.md +++ b/substrate/client/rpc-servers/README.md @@ -1,3 +1,3 @@ Substrate RPC servers. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/rpc-spec-v2/README.md b/substrate/client/rpc-spec-v2/README.md index e860e0c2334..8ea6e686c1a 100644 --- a/substrate/client/rpc-spec-v2/README.md +++ b/substrate/client/rpc-spec-v2/README.md @@ -1,5 +1,5 @@ Substrate RPC interfaces. -A collection of RPC methods and subscriptions supported by all substrate clients. +A collection of RPC methods and subscriptions supported by all Substrate clients. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/rpc/README.md b/substrate/client/rpc/README.md index 6066af4da71..7490d0dc2b0 100644 --- a/substrate/client/rpc/README.md +++ b/substrate/client/rpc/README.md @@ -2,4 +2,4 @@ Substrate RPC implementation. A core implementation of Substrate RPC interfaces. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/service/README.md b/substrate/client/service/README.md index 26f940f16df..0a36138a366 100644 --- a/substrate/client/service/README.md +++ b/substrate/client/service/README.md @@ -1,4 +1,4 @@ Substrate service. Starts a thread that spins up the network, client, and extrinsic pool. Manages communication between them. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/state-db/README.md b/substrate/client/state-db/README.md index a02b3929088..c97cc23400f 100644 --- a/substrate/client/state-db/README.md +++ b/substrate/client/state-db/README.md @@ -2,15 +2,15 @@ State database maintenance. Handles canonicalization and pruning in the database this module is a `ChangeSet` which is basically a list of key-value pairs (trie nodes) that were added or deleted during block execution. -# Canonicalization. +# Canonicalization Canonicalization window tracks a tree of blocks identified by header hash. The in-memory overlay allows to get any node that was inserted in any of the blocks within the window. The tree is journaled to the backing database and rebuilt on startup. Canonicalization function selects one root from the top of the tree and discards all other roots and their subtrees. -# Pruning. +# Pruning See `RefWindow` for pruning algorithm details. `StateDb` prunes on each canonicalization until pruning constraints are satisfied. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/telemetry/README.md b/substrate/client/telemetry/README.md index 2e3e19bd2f6..849fad8bec7 100644 --- a/substrate/client/telemetry/README.md +++ b/substrate/client/telemetry/README.md @@ -1,6 +1,6 @@ # sc-telemetry -Substrate's client telemetry is a part of substrate that allows ingesting telemetry data +Substrate's client telemetry is a part of Substrate that allows ingesting telemetry data with for example [Polkadot telemetry](https://github.com/paritytech/substrate-telemetry). It works using Tokio's [tracing](https://github.com/tokio-rs/tracing/) library. The telemetry @@ -9,8 +9,8 @@ tracing `Layer`. This layer will then send the data through an asynchronous chan background task called [`TelemetryWorker`] which will send the information to the configured remote telemetry servers. -If multiple substrate nodes are running in the same process, it uses a `tracing::Span` to -identify which substrate node is reporting the telemetry. Every task spawned using sc-service's +If multiple Substrate nodes are running in the same process, it uses a `tracing::Span` to +identify which Substrate node is reporting the telemetry. Every task spawned using sc-service's `TaskManager` automatically inherit this span. Substrate's nodes initialize/register with the [`TelemetryWorker`] using a [`TelemetryHandle`]. diff --git a/substrate/client/tracing/README.md b/substrate/client/tracing/README.md index b008436df9b..f52e9d4dbc6 100644 --- a/substrate/client/tracing/README.md +++ b/substrate/client/tracing/README.md @@ -1,4 +1,4 @@ -Instrumentation implementation for substrate. +Instrumentation implementation for Substrate. This crate is unstable and the API and usage may change. @@ -8,4 +8,4 @@ See `sp-tracing` for examples on how to use tracing. Currently we provide `Log` (default), `Telemetry` variants for `Receiver` -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/transaction-pool/README.md b/substrate/client/transaction-pool/README.md index 4a2bbb8838f..b34b623b26e 100644 --- a/substrate/client/transaction-pool/README.md +++ b/substrate/client/transaction-pool/README.md @@ -232,7 +232,7 @@ are interested in. Since the pool is expected to store more transactions than what can fit in a single block, validating the entire pool on every block might not be -feasible. This means that the actual implementation might need to take some +feasible. This means that the actual implementation might need to take some shortcuts. ## Suggestions & caveats @@ -255,7 +255,7 @@ shortcuts. lot of re-orgs. Make sure that transactions are never lost. 1. The UTXO model is quite challenging. A transaction becomes valid right after - it's included in a block, however it is waiting for exactly the same inputs + it's included in a block, however it is waiting for exactly the same inputs to be spent, so it will never really be included again. 1. Note that in a non-ideal implementation the state of the pool will most @@ -278,7 +278,7 @@ shortcuts. 1. We periodically validate all transactions in the pool in batches. -1. To minimize runtime calls, we introduce the batch-verify call. Note it should +1. To minimize runtime calls, we introduce the batch-verify call. Note it should reset the state (overlay) after every verification. 1. Consider leveraging finality. Maybe we could verify against latest finalised @@ -355,7 +355,7 @@ figure out what tags were satisfied by a transaction in that block. For each blo transaction we either call into the runtime to get it's `ValidTransaction` object, or we check the pool if that transaction is already known to spare the runtime call. From this we gather the full set of `provides` tags and perform pruning of -the `ready` pool based on that. Also, we promote all transactions from `future` +the `ready` pool based on that. Also, we promote all transactions from `future` that have their tags satisfied. In case we remove transactions that we are unsure if they were already included diff --git a/substrate/docker/README.md b/substrate/docker/README.md index 71ddb2dffd1..f9cc7ed1465 100644 --- a/substrate/docker/README.md +++ b/substrate/docker/README.md @@ -1,27 +1,32 @@ # Substrate Builder Docker Image -The Docker image in this folder is a `builder` image. It is self contained and allows users to build the binaries themselves. -There is no requirement on having Rust or any other toolchain installed but a working Docker environment. +The Docker image in this folder is a `builder` image. It is self contained and allows users to build the binaries +themselves. There is no requirement on having Rust or any other toolchain installed but a working Docker environment. -Unlike the `parity/polkadot` image which contains a single binary (`polkadot`!) used by default, the image in this folder builds and contains several binaries and you need to provide the name of the binary to be called. +Unlike the `parity/polkadot` image which contains a single binary (`polkadot`!) used by default, the image in this +folder builds and contains several binaries and you need to provide the name of the binary to be called. -You should refer to the [.Dockerfile](./substrate_builder.Dockerfile) for the actual list. At the time of editing, the list of included binaries is: +You should refer to the [.Dockerfile](./substrate_builder.Dockerfile) for the actual list. At the time of editing, the +list of included binaries is: -- substrate -- subkey -- node-template -- chain-spec-builder +- `substrate` +- `subkey` +- `node-template` +- `chain-spec-builder` First, install [Docker](https://docs.docker.com/get-docker/). -Then to generate the latest parity/substrate image. Please run: +Then to generate the latest `parity/substrate` image. Please run: ```sh ./build.sh ``` -> If you wish to create a debug build rather than a production build, then you may modify the [.Dockerfile](./substrate_builder.Dockerfile) replacing `cargo build --locked --release` with just `cargo build --locked` and replacing `target/release` with `target/debug`. +If you wish to create a debug build rather than a production build, then you may modify the +[.Dockerfile](./substrate_builder.Dockerfile) replacing `cargo build --locked --release` with just +`cargo build --locked` and replacing `target/release` with `target/debug`. -> If you get an error that a tcp port address is already in use then find an available port to use for the host port in the [.Dockerfile](./substrate_builder.Dockerfile). +If you get an error that a tcp port address is already in use then find an available port to use for the host port in +the [.Dockerfile](./substrate_builder.Dockerfile). The image can be used by passing the selected binary followed by the appropriate tags for this binary. @@ -32,7 +37,8 @@ Your best guess to get started is to pass the `--help flag`. Here are a few exam - `./run.sh node-template --version` - `./run.sh chain-spec-builder --help` -Then try running the following command to start a single node development chain using the Substrate Node Template binary `node-template`: +Then try running the following command to start a single node development chain using the Substrate Node Template binary +`node-template`: ```sh ./run.sh node-template --dev --ws-external diff --git a/substrate/docs/CHANGELOG.md b/substrate/docs/CHANGELOG.md index 25f8e582c78..8a1b245a5b0 100644 --- a/substrate/docs/CHANGELOG.md +++ b/substrate/docs/CHANGELOG.md @@ -8,24 +8,36 @@ The format is based on [Keep a Changelog]. ## 2.0.1-> 3.0.0 - Apollo 14 -Most notably, this is the first release of the new FRAME (2.0) with its new macro-syntax and some changes in types, and pallet versioning. This release also incorporates the faster and improve version 2.0 of the parity-scale-codec and upgraded dependencies all-around. While the `FinalityTracker` pallet has been dropped, this release marks the first public appearance of a few new pallets, too;Bounties, Lottery, Tips (extracted from the `Treasury`-pallet, see #7536) and Merkle-Mountain-Ranges (MMR). - -On the client side, the most notable changes are around the keystore, making it async and switching to a different signing model allowing for remote-signing to be implemented; and various changes to improve networking and light-client support, like adding the Grandpa warp sync request-response protocol (#7711). - -_Contracts_: Please note that the contracts pallet _is not part_ of this release. The pallet is not yet ready and will be released separately in the coming weeks. The currently released contracts pallet _is not compatible_ with the new FRAME, thus if you need the contracts pallet, we recommend you wait with the upgrade until it has been released, too. +Most notably, this is the first release of the new FRAME (2.0) with its new macro-syntax and some changes in types, and +pallet versioning. This release also incorporates the faster and improve version 2.0 of the `parity-scale-codec` and +upgraded dependencies all-around. While the `FinalityTracker` pallet has been dropped, this release marks the first +public appearance of a few new pallets, too;Bounties, Lottery, Tips (extracted from the `Treasury`-pallet, see #7536) +and Merkle-Mountain-Ranges (MMR). + +On the client side, the most notable changes are around the keystore, making it async and switching to a different +signing model allowing for remote-signing to be implemented; and various changes to improve networking and light-client +support, like adding the Grandpa warp sync request-response protocol (#7711). + +_Contracts_: Please note that the contracts pallet _is not part_ of this release. The pallet is not yet ready and will +be released separately in the coming weeks. The currently released contracts pallet _is not compatible_ with the new +FRAME, thus if you need the contracts pallet, we recommend you wait with the upgrade until it has been released, too. ### Upgrade instructions -Not too much has changed on the top and API level for developing Substrate between 2.0 and 3.0. The easiest and quickest path for upgrading is just to take the latest node-template and try applying your changes to it: +Not too much has changed on the top and API level for developing Substrate between 2.0 and 3.0. The easiest and quickest +path for upgrading is just to take the latest node-template and try applying your changes to it: 1. take a diff between 2.0 and your changes 2. store that diff 3. remove everything, copy over the 3.0 node-template 4. try re-applying your diff, manually, a hunk at a time. -If that doesn't work for you, we are working on an in-depth-guide for all major changes that took place and how you need to adapt your code for it. [You can find the upgrade guide under `docs/` in the repo](https://github.com/paritytech/substrate/blob/master/docs/Upgrading-2.0-to-3.0.md), if you have further questions or problem, please [feel free to ask in the github discussion board](https://github.com/paritytech/substrate/discussions). +If that doesn't work for you, we are working on an in-depth-guide for all major changes that took place and how you need +to adapt your code for it. [You can find the upgrade guide under `docs/` in the +repo](https://github.com/paritytech/substrate/blob/master/docs/Upgrading-2.0-to-3.0.md), if you have further questions +or problem, please [feel free to ask in the github discussion +board](https://github.com/paritytech/substrate/discussions). -Runtime -------- +#### Runtime * contracts: Charge rent for code storage (#7935) * contracts: Emit event on contract termination (#8014) @@ -63,8 +75,7 @@ Runtime * Move proxies migration (#7205) * Introduce `cancel_proposal` to rid us of those pesky proposals (#7111) -Client ------- +#### Client * Remove backwards-compatibility networking hack (#8068) * Extend SS58 network identifiers (#8039) @@ -97,8 +108,7 @@ Client * Refactor CurrencyToVote (#6896) * client/network: Stop sending noise legacy handshake (#7211) -API ---- +#### API * pallet macro: easier syntax for `#[pallet::pallet]` with `struct Pallet(_)` (#8091) * WasmExecutor takes a cache directory (#8057) @@ -106,7 +116,7 @@ API * Migrate assets pallet to new macros (#7984) * contracts: Make ChainExtension trait generic over the runtime (#8003) * Decouple the session validators from im-online (#7127) -* Update parity-scale-codec to 2.0 (#7994) +* Update `parity-scale-codec` to 2.0 (#7994) * Merkle Mountain Range pallet improvements (#7891) * Cleaner GRANDPA RPC API for proving finality (#7339) * Migrate frame-system to pallet attribute macro (#7898) @@ -136,8 +146,7 @@ API * SystemOrigin trait (#7226) * permit setting treasury pallet initial funding through genesis (#7214) -Runtime Migrations ------------------- +#### Runtime Migrations * Migrate assets pallet to new macros (#7984) * Fix elections-phragmen and proxy issue (#7040) @@ -149,8 +158,7 @@ Runtime Migrations ## 2.0.0-> 2.0.1 -Patch release with backports to fix broken nightly builds. -Namely contains backports of +Patch release with backports to fix broken nightly builds. Namely contains backports of * [#7381: Make Substrate compile with latest nightly](https://github.com/paritytech/substrate/pull/7381) * [#7238: Fix compilation with environmental on latest nightly](https://github.com/paritytech/substrate/pull/7238) @@ -161,8 +169,7 @@ Namely contains backports of ## 2.0.0-rc6 -> 2.0.0 – two dot 😮 -Runtime -------- +### Runtime * Rename `ModuleToIndex` to `PalletRuntimeSetup` (#7148) * Bounties (#5715) @@ -174,8 +181,7 @@ Runtime * Time-delay proxies (#6770) * Refcounts are now u32 (#7164) -Client ------- +### Client * Rename `inspect-key` to `inspect` (#7160) * Send import notification always for re-orgs (#7118) @@ -190,8 +196,7 @@ Client * Fix benchmark read/write key tracker for keys in child storages. (#6905) * *: Update to next libp2p version 0.24.0 (#6891) -API ---- +### API * grandpa-rpc: use FinalityProofProvider to check finality for rpc (#6215) * pow: replace the thread-base mining loop with a future-based mining worker (#7060) @@ -204,16 +209,14 @@ API * Add a `LightSyncState` field to the chain spec (#6894) * *: Update to next libp2p version 0.24.0 (#6891) -Runtime Migrations ------------------- +### Runtime Migrations * Time-delay proxies (#6770) ## 2.0.0-rc5 -> 2.0.0-rc6 – Rock Hyrax -Runtime -------- +### Runtime * Custom Codec Implementation for NPoS Election (#6720) * Successful `note_imminent_preimage` is free (#6793) @@ -224,8 +227,7 @@ Runtime * pallet-evm: add support for tuple-based precompile declarations (#6681) * grandpa: allow noting that the set has stalled (#6725) -Client ------- +#### Client * Merge Subkey into sc-cli (#4954) * RpcHandlers Refactorings (#6846) @@ -239,8 +241,7 @@ Client * Name all the tasks! (#6726) * Child nodes can be handled by adding a child `TaskManager` to the parent's `TaskManager` (#6771) -API ---- +### API * pow: add access to pre-digest for algorithm verifiers (#6900) * babe, aura, pow: only call check_inherents if authoring version is compatible (#6862) @@ -254,8 +255,7 @@ API ## 2.0.0-rc4 -> 2.0.0-rc5 – River Dolphin -Runtime -------- +### Runtime * Support using system storage directly for EVM balance and nonce (#6659) * Properly filter out duplicate voters in elections. (#6693) @@ -273,14 +273,13 @@ Runtime * pallet-evm: customizable chain id (#6537) * Refactor as_sub to make things clearer. (#6503) -Client ------- +### Client * Update wasmtime to (almost) latest master (#6662) * Update to latest sysinfo prevents leaking fd-handlers (#6708) * Tracing values (#6679) * Graceful shutdown for the task manager (#6654) -* Update substrate-networking Grafana dashboard (#6649) +* Update `substrate-networking` Grafana dashboard (#6649) * *: Update to libp2p v0.21.1 (#6559) * Send Status message on all newly-opened legacy substreams (#6593) * babe: report equivocations (#6362) @@ -288,8 +287,7 @@ Client * Remove the service, replacing it with a struct of individual chain components (#6352) * Fix tx-pool returning the same transaction multiple times (#6535) -API ---- +### API * Better handling of stable-only build (#6569) * Remove the service builder (#6557) @@ -302,8 +300,7 @@ API ## 2.0.0-rc3 -> 2.0.0-rc4 (Rhinoceros) -Runtime -------- +### Runtime * Staking Payout Creates Controller (#6496) * `pallet-scheduler`: Check that `when` is not in the past (#6480) @@ -321,8 +318,7 @@ Runtime * Add events for balance reserve and unreserve functions (#6330) * Introduce frozen indices. (#6307) -Client ------- +### Client * client/network/service: Add primary dimension to connection metrics (#6472) * Fix Babe secondary plain slots claiming (#6451) @@ -340,8 +336,7 @@ Client * new crate sc-light (#6235) * Allow adding a prefix to the informant (#6174) -API ---- +### API * seal: Remove ext_dispatch_call and ext_get_runtime_storage (#6464) * seal: Refactor ext_gas_price (#6478) @@ -356,16 +351,14 @@ API ## 2.0.0-rc2 -> 2.0.0-rc3 -Runtime -------- +### Runtime * Introduce stacked filtering (#6273) * Allow "pure" proxied accounts (#6236) * Allow over-weight collective proposals to be closed (#6163) * Fix Election when ForceNone V1 (#6166) -Client ------- +### Client * Make transaction pool prune transactions only of canonical blocks (#6123) * Rename all the election operations (#6245) @@ -381,14 +374,12 @@ Client ## 2.0.0-alpha.8 -> 2.0.0-rc1 -Runtime -------- +### Runtime * Allow operational recovery path if on_initialize use fullblock. (#6089) * Maximum extrinsic weight limit (#6067) -Client ------- +### Client * Add JSON format to import blocks and set it as default (#5816) * Upgrade to libp2p v0.19 - Changes the default PeerId representation (#6064) @@ -396,17 +387,17 @@ Client ## 2.0.0-alpha.7 -> 2.0.0-alpha.8 -**License Changed** -From this release forward, the code is released under a new – more relaxed – license scheme: Client (`sc-*`) is released under "GPL 3.0 or newer with the Classpath Exception", while primitives, FRAME, the pallets, utils and test-utils are released under "Apache 2.0". More details in the [Relax licensing scheme PR](https://github.com/paritytech/substrate/pull/5947). +**License Changed** From this release forward, the code is released under a new – more relaxed – license scheme: Client +(`sc-*`) is released under "GPL 3.0 or newer with the Classpath Exception", while primitives, FRAME, the pallets, utils +and test-utils are released under "Apache 2.0". More details in the [Relax licensing scheme +PR](https://github.com/paritytech/substrate/pull/5947). -Runtime -------- +### Runtime * Democracy weight (#5828) * Make `Digest` support `StorageAppend` (#5922) -Client ------- +### Client * Meter block import results via prometheus (#6025) * Added RuntimePublic for ecdsa public key. (#6029) @@ -418,8 +409,7 @@ Client ## 2.0.0-alpha.6 -> 2.0.0-alpha.7 -Runtime -------- +### Runtime * Use `storage::append` in the implementation of the storage types (#5889) * pallet-sudo: Store `DispatchResult` in `Sudid` event (#5804) @@ -431,8 +421,7 @@ Runtime * Transaction versioning in the RuntimeVersion (#5582) * emit TipClosed event on success tip payout (#5656) -Client ------- +### Client * Adds `export-state` subcommand (#5842) * Drop ClientProvider (#5823) @@ -454,8 +443,7 @@ Client * Use a Kademlia instance per `ProtocolId`. (#5045) * Report tasks metrics to Prometheus (#5619) -API ---- +### API * Child trie api changes BREAKING (#4857) * Pass max-total to RewardRemainder on end_era (#5697) @@ -463,8 +451,7 @@ API ## 2.0.0-alpha.5 -> 2.0.0-alpha.6 -Runtime -------- +### Runtime * Unsigned Validation best practices (#5563) * Generate Unit Tests for Benchmarks (#5527) @@ -473,8 +460,7 @@ Runtime * Pass transaction source to validate_transaction (#5366) * on_initialize return weight consumed and default cost to default DispatchInfo instead of zero (#5382) -Client ------- +### Client * Add new RPC method to get the chain type (#5576) * Reuse wasmtime instances, the PR (#5567) @@ -488,10 +474,10 @@ Client * Make transactions and block announces use notifications substre… (#5360) * Adds state_queryStorageAt (#5362) * Offchain Phragmén BREAKING. (#4517) -* `sc_rpc::system::SystemInfo.impl_version` now returns the full version (2.0.0-alpha.2-b950f731c-x86_64-linux-gnu) instead of the short version (1.0.0) (#5271) +* `sc_rpc::system::SystemInfo.impl_version` now returns the full version (2.0.0-alpha.2-b950f731c-x86_64-linux-gnu) + instead of the short version (1.0.0) (#5271) -API ---- +### API * Unsigned Validation best practices (#5563) * Split the Roles in three types (#5520) @@ -501,16 +487,14 @@ API ## 2.0.0-alpha.4 -> 2.0.0-alpha.5 -Runtime -------- +### Runtime * pallet-evm: configurable gasometer config (#5320) * Adds new event phase `Initialization` (#5302) ## 2.0.0-alpha.3 -> 2.0.0-alpha.4 -Runtime -------- +### Runtime * Move runtime upgrade to `frame-executive` (#5197) * Split fees and tips between author and treasury independently (#5207) @@ -520,22 +504,20 @@ Runtime * Adds `vested_transfer` to Vesting pallet (#5029) * Change extrinsic_count to extrinsic_index in pallet-utility (#5044) -Client ------- +### Client * client/finality-grandpa: Add Prometheus metrics to GossipValidator (#5237) * removes use of sc_client::Client from node-transaction-factory (#5158) * removes use of sc_client::Client from sc_network (#5147) * Use CLI to configure max instances cache (#5177) * client/service/src/builder.rs: Add build_info metric (#5192) -* Remove substrate-ui.parity.io from CORS whitelist (#5142) +* Remove `substrate-ui.parity.io` from CORS whitelist (#5142) * removes use of sc_client::Client from sc-rpc (#5063) * Use 128mb for db cache default (#5134) * Drop db-cache default from 1gig to 32mb (#5128) * Add more metrics to prometheus (#5034) -API ---- +### API * Produce block always on updated transaction pool state (#5227) * Add `ext_terminate` (#5234) diff --git a/substrate/docs/SECURITY.md b/substrate/docs/SECURITY.md index 19f5b145feb..0d2064863d8 100644 --- a/substrate/docs/SECURITY.md +++ b/substrate/docs/SECURITY.md @@ -1,11 +1,14 @@ # Security Policy -Parity Technologies is committed to resolving security vulnerabilities in our software quickly and carefully. We take the necessary steps to minimize risk, provide timely information, and deliver vulnerability fixes and mitigations required to address security issues. +Parity Technologies is committed to resolving security vulnerabilities in our software quickly and carefully. We take +the necessary steps to minimize risk, provide timely information, and deliver vulnerability fixes and mitigations +required to address security issues. ## Reporting a Vulnerability -Security vulnerabilities in Parity software should be reported by email to security@parity.io. If you think your report might be eligible for the Parity Bug Bounty Program, your email should be send to bugbounty@parity.io. +Security vulnerabilities in Parity software should be reported by email to security@parity.io. If you think your report +might be eligible for the Parity Bug Bounty Program, your email should be send to bugbounty@parity.io. Your report should include the following: @@ -16,11 +19,16 @@ Your report should include the following: - reproduction - other details -Try to include as much information in your report as you can, including a description of the vulnerability, its potential impact, and steps for reproducing it. Be sure to use a descriptive subject line. +Try to include as much information in your report as you can, including a description of the vulnerability, its +potential impact, and steps for reproducing it. Be sure to use a descriptive subject line. -You'll receive a response to your email within two business days indicating the next steps in handling your report. We encourage finders to use encrypted communication channels to protect the confidentiality of vulnerability reports. You can encrypt your report using our public key. This key is [on MIT's key server](https://pgp.mit.edu/pks/lookup?op=get&search=0x5D0F03018D07DE73) server and reproduced below. +You'll receive a response to your email within two business days indicating the next steps in handling your report. We +encourage finders to use encrypted communication channels to protect the confidentiality of vulnerability reports. You +can encrypt your report using our public key. This key is [on MIT's key +server](https://pgp.mit.edu/pks/lookup?op=get&search=0x5D0F03018D07DE73) server and reproduced below. -After the initial reply to your report, our team will endeavor to keep you informed of the progress being made towards a fix. These updates will be sent at least every five business days. +After the initial reply to your report, our team will endeavor to keep you informed of the progress being made towards a +fix. These updates will be sent at least every five business days. Thank you for taking the time to responsibly disclose any vulnerabilities you find. @@ -29,19 +37,23 @@ Thank you for taking the time to responsibly disclose any vulnerabilities you fi Responsible investigation and reporting includes, but isn't limited to, the following: - Don't violate the privacy of other users, destroy data, etc. -- Don’t defraud or harm Parity Technologies Ltd or its users during your research; you should make a good faith effort to not interrupt or degrade our services. -- Don't target our physical security measures, or attempt to use social engineering, spam, distributed denial of service (DDOS) attacks, etc. +- Don’t defraud or harm Parity Technologies Ltd or its users during your research; you should make a good faith effort + to not interrupt or degrade our services. +- Don't target our physical security measures, or attempt to use social engineering, spam, distributed denial of service + (DDOS) attacks, etc. - Initially report the bug only to us and not to anyone else. -- Give us a reasonable amount of time to fix the bug before disclosing it to anyone else, and give us adequate written warning before disclosing it to anyone else. -- In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to us or our users. Otherwise your actions might be interpreted as an attack rather than an effort to be helpful. +- Give us a reasonable amount of time to fix the bug before disclosing it to anyone else, and give us adequate written + warning before disclosing it to anyone else. +- In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be + disruptive or harmful to us or our users. Otherwise your actions might be interpreted as an attack rather than an + effort to be helpful. ## Bug Bounty Program -Our Bug Bounty Program allows us to recognize and reward members of the Parity community for helping us find and address significant bugs, in accordance with the terms of the Parity Bug Bounty Program. A detailed description on eligibility, rewards, legal information and terms & conditions for contributors can be found on [our website](https://paritytech.io/bug-bounty.html). - - - - +Our Bug Bounty Program allows us to recognize and reward members of the Parity community for helping us find and address +significant bugs, in accordance with the terms of the Parity Bug Bounty Program. A detailed description on eligibility, +rewards, legal information and terms & conditions for contributors can be found on [our +website](https://paritytech.io/bug-bounty.html). ## Plaintext PGP Key diff --git a/substrate/docs/STYLE_GUIDE.md b/substrate/docs/STYLE_GUIDE.md index a89dcf52ffc..6ea0755d080 100644 --- a/substrate/docs/STYLE_GUIDE.md +++ b/substrate/docs/STYLE_GUIDE.md @@ -2,19 +2,18 @@ title: Style Guide for Rust in Substrate --- -Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` -then you will adhere to most of these style guidelines automatically. +Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` then you will adhere to +most of these style guidelines automatically. # Code Formatting -- Indent using tabs. -- Lines should be longer than 100 characters long only in exceptional circumstances and certainly - no longer than 120. For this purpose, tabs are considered 4 characters wide. -- Indent levels should be greater than 5 only in exceptional circumstances and certainly no - greater than 8. If they are greater than 5, then consider using `let` or auxiliary functions in - order to strip out complex inline expressions. -- Never have spaces on a line prior to a non-whitespace character -- Follow-on lines are only ever a single indent from the original line. +- Indent using tabs. +- Lines should be longer than 100 characters long only in exceptional circumstances and certainly no longer than 120. + For this purpose, tabs are considered 4 characters wide. +- Indent levels should be greater than 5 only in exceptional circumstances and certainly no greater than 8. If they are + greater than 5, then consider using `let` or auxiliary functions in order to strip out complex inline expressions. +- Never have spaces on a line prior to a non-whitespace character +- Follow-on lines are only ever a single indent from the original line. ```rust fn calculation(some_long_variable_a: i8, some_long_variable_b: i8) -> bool { @@ -25,8 +24,8 @@ fn calculation(some_long_variable_a: i8, some_long_variable_b: i8) -> bool { } ``` -- Indent level should follow open parens/brackets, but should be collapsed to the smallest number - of levels actually used: +- Indent level should follow open parens/brackets, but should be collapsed to the smallest number of levels actually + used: ```rust fn calculate( @@ -45,10 +44,10 @@ fn calculate( } ``` -- `where` is indented, and its items are indented one further. -- Argument lists or function invocations that are too long to fit on one line are indented - similarly to code blocks, and once one param is indented in such a way, all others should be, - too. Run-on parameter lists are also acceptable for single-line run-ons of basic function calls. +- `where` is indented, and its items are indented one further. +- Argument lists or function invocations that are too long to fit on one line are indented similarly to code blocks, and + once one param is indented in such a way, all others should be, too. Run-on parameter lists are also acceptable for + single-line run-ons of basic function calls. ```rust // OK @@ -92,7 +91,7 @@ fn foo(really_long_parameter_name_1: SomeLongTypeName, really_long_parameter_nam } ``` -- Always end last item of a multi-line comma-delimited set with `,` when legal: +- Always end last item of a multi-line comma-delimited set with `,` when legal: ```rust struct Point { @@ -104,7 +103,7 @@ struct Point { enum Meal { Breakfast, Lunch, Dinner }; ``` -- Avoid trailing `;`s where unneeded. +- Avoid trailing `;`s where unneeded. ```rust if condition { @@ -112,8 +111,8 @@ if condition { } ``` -- `match` arms may be either blocks or have a trailing `,` but not both. -- Blocks should not be used unnecessarily. +- `match` arms may be either blocks or have a trailing `,` but not both. +- Blocks should not be used unnecessarily. ```rust match meal { @@ -126,9 +125,8 @@ match meal { # Style -- Panickers require explicit proofs they don't trigger. Calling `unwrap` is discouraged. The - exception to this rule is test code. Avoiding panickers by restructuring code is preferred if - feasible. +- Panickers require explicit proofs they don't trigger. Calling `unwrap` is discouraged. The exception to this rule is + test code. Avoiding panickers by restructuring code is preferred if feasible. ```rust let mut target_path = @@ -139,21 +137,22 @@ let mut target_path = ); ``` -- Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, - consider trade-offs between efficiency on one hand and reliability, maintenance costs, and - security on the other. Here is a list of questions that may help evaluating the trade-off while - preparing or reviewing a PR: - - how much more performant or compact the resulting code will be using unsafe code, - - how likely is it that invariants could be violated, - - are issues stemming from the use of unsafe code caught by existing tests/tooling, - - what are the consequences if the problems slip into production. +- Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, consider trade-offs between + efficiency on one hand and reliability, maintenance costs, and security on the other. Here is a list of questions + that may help evaluating the trade-off while preparing or reviewing a PR: + - how much more performant or compact the resulting code will be using unsafe code, + - how likely is it that invariants could be violated, + - are issues stemming from the use of unsafe code caught by existing tests/tooling, + - what are the consequences if the problems slip into production. # Manifest Formatting -> **TLDR** -> You can use the CLI tool [Zepter](https://crates.io/crates/zepter) to format the files: `zepter format features` +> **TLDR** You can use the CLI tool [Zepter](https://crates.io/crates/zepter) to format the files: `zepter format +> features` -Rust `Cargo.toml` files need to respect certain formatting rules. All entries need to be alphabetically sorted. This makes it easier to read them and insert new entries. The exhaustive list of rules is enforced by the CI. The general format looks like this: +Rust `Cargo.toml` files need to respect certain formatting rules. All entries need to be alphabetically sorted. This +makes it easier to read them and insert new entries. The exhaustive list of rules is enforced by the CI. The general +format looks like this: - The feature is written as a single line if it fits within 80 chars: ```toml @@ -161,7 +160,8 @@ Rust `Cargo.toml` files need to respect certain formatting rules. All entries ne default = [ "std" ] ``` -- Otherwise the feature is broken down into multiple lines with one entry per line. Each line is padded with one tab and no trailing spaces but a trailing comma. +- Otherwise the feature is broken down into multiple lines with one entry per line. Each line is padded with one tab and + no trailing spaces but a trailing comma. ```toml [features] default = [ diff --git a/substrate/docs/Upgrade.md b/substrate/docs/Upgrade.md index 4908d53f579..08b5a7d37b6 100644 --- a/substrate/docs/Upgrade.md +++ b/substrate/docs/Upgrade.md @@ -1,5 +1,7 @@ -# Upgrade path for you building on substrate +# Upgrade path for you building on Substrate ## master - - crate rename has been fixed `sp-application-crypto` (was `sc-application-crypto`); `.maintain/rename-crates-for-2.0.sh` has been updated accordingly, you can use it to upgrade to latest naming convention - - crates have been renamed, run `bash .maintain/rename-crates-for-2.0.sh` \ No newline at end of file + - crate rename has been fixed `sp-application-crypto` (was `sc-application-crypto`); + `.maintain/rename-crates-for-2.0.sh` has been updated accordingly, you can use it to upgrade to latest naming + convention + - crates have been renamed, run `bash .maintain/rename-crates-for-2.0.sh` diff --git a/substrate/docs/Upgrading-2.0-to-3.0.md b/substrate/docs/Upgrading-2.0-to-3.0.md index 906018db9a7..58066ce074d 100644 --- a/substrate/docs/Upgrading-2.0-to-3.0.md +++ b/substrate/docs/Upgrading-2.0-to-3.0.md @@ -4,7 +4,8 @@ An incomplete guide. ## Refreshing the node-template -Not much has changed on the top and API level for developing Substrate between 2.0 and 3.0. If you've made only small changes to the node-template, we recommend to do the following - it is easiest and quickest path forward: +Not much has changed on the top and API level for developing Substrate between 2.0 and 3.0. If you've made only small +changes to the node-template, we recommend to do the following - it is easiest and quickest path forward: 1. take a diff between 2.0 and your changes 2. store that diff 3. remove everything, copy over the 3.0 node-template @@ -12,19 +13,30 @@ Not much has changed on the top and API level for developing Substrate between 2 ## In-Depth guide on the changes -If you've made significant changes or diverted from the node-template a lot, starting out with that is probably not helping. For that case, we'll take a look at all changes between 2.0 and 3.0 to the fully-implemented node and explain them one by one, so you can follow up, what needs to be changing for your node. +If you've made significant changes or diverted from the node-template a lot, starting out with that is probably not +helping. For that case, we'll take a look at all changes between 2.0 and 3.0 to the fully-implemented node and explain +them one by one, so you can follow up, what needs to be changing for your node. _Note_: Of course, step 1 is to upgrade your `Cargo.toml`'s to use the latest version of Substrate and all dependencies. -We'll be taking the diff from 2.0.1 to 3.0.0 on `bin/node` as the baseline of what has changed between these two versions in terms of adapting ones code base. We will not be covering the changes made on the tests and bench-marking as they are mostly reactions to the other changes. +We'll be taking the diff from 2.0.1 to 3.0.0 on `bin/node` as the baseline of what has changed between these two +versions in terms of adapting ones code base. We will not be covering the changes made on the tests and bench-marking as +they are mostly reactions to the other changes. ### Versions upgrade -First and foremost you have to upgrade the version pf the dependencies of course, that's `0.8.x -> 0.9.0` and `2.0.x -> 3.0.0` for all `sc-`, `sp-`, `frame-`, and `pallet-` coming from Parity. Further more this release also upgraded its own dependencies, most notably, we are now using `parity-scale-codec 2.0`, `parking_lot 0.11` and `substrate-wasm-builder 3.0.0` (as build dependency). All other dependency upgrades should resolve automatically or are just internal. However you might see some error that another dependency/type you have as a dependency and one of our upgraded crates don't match up, if so please check the version of said dependency - we've probably upgraded it. +First and foremost you have to upgrade the version pf the dependencies of course, that's `0.8.x -> 0.9.0` and `2.0.x -> +3.0.0` for all `sc-`, `sp-`, `frame-`, and `pallet-` coming from Parity. Further more this release also upgraded its own +dependencies, most notably, we are now using `parity-scale-codec 2.0`, `parking_lot 0.11` and `substrate-wasm-builder +3.0.0` (as build dependency). All other dependency upgrades should resolve automatically or are just internal. However +you might see some error that another dependency/type you have as a dependency and one of our upgraded crates don't +match up, if so please check the version of said dependency - we've probably upgraded it. ### WASM-Builder -The new version of wasm-builder has gotten a bit smarter and a lot faster (you should definitely switch). Once you've upgraded the dependency, in most cases you just have to remove the now obsolete `with_wasm_builder_from_crates_or_path`-function and you are good to go: +The new version of wasm-builder has gotten a bit smarter and a lot faster (you should definitely switch). Once you've +upgraded the dependency, in most cases you just have to remove the now obsolete +`with_wasm_builder_from_crates_or_path`-function and you are good to go: ```diff: rust --- a/bin/node/runtime/build.rs @@ -49,11 +61,15 @@ The new version of wasm-builder has gotten a bit smarter and a lot faster (you s #### FRAME 2.0 -The new FRAME 2.0 macros are a lot nicer to use and easier to read. While we were on that change though, we also cleaned up some mainly internal names and traits. The old `macro`'s still work and also produce the new structure, however, when plugging all that together as a Runtime, there's some things we have to adapt now: +The new FRAME 2.0 macros are a lot nicer to use and easier to read. While we were on that change though, we also cleaned +up some mainly internal names and traits. The old `macro`'s still work and also produce the new structure, however, when +plugging all that together as a Runtime, there's some things we have to adapt now: ##### `::Trait for Runtime` becomes `::Config for Runtime` -The most visible and significant change is that the macros no longer generate the `$pallet::Trait` but now a much more aptly named `$pallet::Config`. Thus, we need to rename all `::Trait for Runtime` into`::Config for Runtime`, e.g. for the `sudo` pallet we must do: +The most visible and significant change is that the macros no longer generate the `$pallet::Trait` but now a much more +aptly named `$pallet::Config`. Thus, we need to rename all `::Trait for Runtime` into`::Config for Runtime`, e.g. for +the `sudo` pallet we must do: ```diff -impl pallet_sudo::Trait for Runtime { @@ -65,11 +81,15 @@ The same goes for all `` and alike, which simply be #### SS58 Prefix is now a runtime param -Since [#7810](https://github.com/paritytech/substrate/pull/7810) we don't define the ss58 prefix in the chainspec anymore but moved it into the runtime. Namely, `frame_system` now needs a new `SS58Prefix`, which in substrate node we have defined for ourselves as: `pub const SS58Prefix: u8 = 42;`. Use your own chain-specific value there. +Since [#7810](https://github.com/paritytech/substrate/pull/7810) we don't define the ss58 prefix in the chainspec +anymore but moved it into the runtime. Namely, `frame_system` now needs a new `SS58Prefix`, which in Substrate node we +have defined for ourselves as: `pub const SS58Prefix: u8 = 42;`. Use your own chain-specific value there. #### Weight Definition -`type WeightInfo` has changed and instead on `weights::pallet_$name::WeightInfo` is now bound to the Runtime as `pallet_$name::weights::SubstrateWeight`. As a result we have to the change the type definitions everywhere in our Runtime accordingly: +`type WeightInfo` has changed and instead on `weights::pallet_$name::WeightInfo` is now bound to the Runtime as +`pallet_$name::weights::SubstrateWeight`. As a result we have to the change the type definitions everywhere in +our Runtime accordingly: ```diff - type WeightInfo = weights::pallet_$name::WeightInfo; @@ -170,24 +190,29 @@ And update the overall definition for weights on frame and a few related types a + type SystemWeightInfo = frame_system::weights::SubstrateWeight; ``` -#### Pallets: +#### Pallets ##### Assets The assets pallet has seen a variety of changes: -- [Features needed for reserve-backed stablecoins #7152 ](https://github.com/paritytech/substrate/pull/7152) -- [Freeze Assets and Asset Metadata #7346 ](https://github.com/paritytech/substrate/pull/7346) -- [Introduces account existence providers reference counting #7363 ]((https://github.com/paritytech/substrate/pull/7363)) +- [Features needed for reserve-backed stablecoins #7152](https://github.com/paritytech/substrate/pull/7152) +- [Freeze Assets and Asset Metadata #7346](https://github.com/paritytech/substrate/pull/7346) +- [Introduces account existence providers reference counting #7363]((https://github.com/paritytech/substrate/pull/7363)) -have all altered the feature set and changed the concepts. However, it has some of the best documentation and explains the current state very well. If you are using the assets pallet and need to upgrade from an earlier version, we recommend you use the current docs to guide your way! +have all altered the feature set and changed the concepts. However, it has some of the best documentation and explains +the current state very well. If you are using the assets pallet and need to upgrade from an earlier version, we +recommend you use the current docs to guide your way! ##### Contracts -As noted in the changelog, the `contracts`-pallet is still undergoing massive changes and is not yet part of this release. We are expecting for it to be released a few weeks after. If your chain is dependent on this pallet, we recommend to wait until it has been released as the currently released version is not compatible with FRAME 2.0. +As noted in the changelog, the `contracts`-pallet is still undergoing massive changes and is not yet part of this +release. We are expecting for it to be released a few weeks after. If your chain is dependent on this pallet, we +recommend to wait until it has been released as the currently released version is not compatible with FRAME 2.0. #### (changes) Treasury -As mentioned above, Bounties, Tips and Lottery have been extracted out of treasury into their own pallets - removing these options here. Secondly we must now specify the `BurnDestination` and `SpendFunds`, which now go the `Bounties`. +As mentioned above, Bounties, Tips and Lottery have been extracted out of treasury into their own pallets - removing +these options here. Secondly we must now specify the `BurnDestination` and `SpendFunds`, which now go the `Bounties`. ```diff - type Tippers = Elections; @@ -206,9 +231,10 @@ As mentioned above, Bounties, Tips and Lottery have been extracted out of treasu + type SpendFunds = Bounties; ``` -Factoring out Bounties and Tips means most of these definitions have now moved there, while the parameter types can be left as they were: +Factoring out Bounties and Tips means most of these definitions have now moved there, while the parameter types can be +left as they were: -###### 🆕 Bounties +##### 🆕 Bounties ```rust= impl pallet_bounties::Config for Runtime { @@ -241,11 +267,15 @@ impl pallet_tips::Config for Runtime { #### `FinalityTracker` removed -Finality Tracker has been removed in favor of a different approach to handle the issue in GRANDPA, [see #7228 for details](https://github.com/paritytech/substrate/pull/7228). With latest GRANDPA this is not needed anymore and can be removed without worry. +Finality Tracker has been removed in favor of a different approach to handle the issue in GRANDPA, [see #7228 for +details](https://github.com/paritytech/substrate/pull/7228). With latest GRANDPA this is not needed anymore and can be +removed without worry. #### (changes) Elections Phragmen -The pallet has been moved to a new system in which the exact amount of deposit for each voter, candidate, member, or runner-up is now deposited on-chain. Moreover, the concept of a `defunct_voter` is removed, since votes now have adequate deposit associated with them. A number of configuration parameters has changed to reflect this, as shown below: +The pallet has been moved to a new system in which the exact amount of deposit for each voter, candidate, member, or +runner-up is now deposited on-chain. Moreover, the concept of a `defunct_voter` is removed, since votes now have +adequate deposit associated with them. A number of configuration parameters has changed to reflect this, as shown below: ```diff= parameter_types! { @@ -277,11 +307,16 @@ The pallet has been moved to a new system in which the exact amount of deposit f type TermDuration = TermDuration; ``` - **This upgrade requires storage [migration](https://github.com/paritytech/substrate/blob/master/frame/elections-phragmen/src/migrations_3_0_0.rs)**. Further details can be found in the [pallet-specific changelog](https://github.com/paritytech/substrate/blob/master/frame/elections-phragmen/CHANGELOG.md#security). + **This upgrade requires storage + [migration](https://github.com/paritytech/substrate/blob/master/frame/elections-phragmen/src/migrations_3_0_0.rs)**. + Further details can be found in the [pallet-specific + changelog](https://github.com/paritytech/substrate/blob/master/frame/elections-phragmen/CHANGELOG.md#security). #### (changes) Democracy -Democracy brings three new settings with this release, all to allow for better influx- and spam-control. Namely these allow to specify the maximum number of proposals at a time, who can blacklist and who can cancel proposals. This diff acts as a good starting point: +Democracy brings three new settings with this release, all to allow for better influx- and spam-control. Namely these +allow to specify the maximum number of proposals at a time, who can blacklist and who can cancel proposals. This diff +acts as a good starting point: ```diff= @@ -508,6 +537,14 @@ impl pallet_democracy::Trait for Runtime { @@ -311,7 +346,9 @@ Democracy brings three new settings with this release, all to allow for better i ### Primitives -The shared primitives define the API between Client and Runtime. Usually, you don't have to touch nor directly interact with them, unless you created your own client or frame-less runtime. Therefore we'd expect you to understand whether you are effected by changes and how to update your code yourself. +The shared primitives define the API between Client and Runtime. Usually, you don't have to touch nor directly interact +with them, unless you created your own client or frame-less runtime. Therefore we'd expect you to understand whether you +are effected by changes and how to update your code yourself. ---- @@ -321,10 +358,17 @@ The shared primitives define the API between Client and Runtime. Usually, you do A few minor things have changed in the `cli` (compared to 2.0.1): -1. we've [replaced the newly added `BuildSyncSpec` subcommand with an RPC API](https://github.com/paritytech/substrate/commit/65cc9af9b8df8d36928f6144ee7474cefbd70454#diff-c57da6fbeff8c46ce15f55ea42fedaa5a4684d79578006ce4af01ae04fd6b8f8) in an on-going effort to make light-client-support smoother, see below -2. we've [removed double accounts from our chainspec-builder](https://github.com/paritytech/substrate/commit/31499cd29ed30df932fb71b7459796f7160d0272) -3. we [don't fallback to `--chain flaming-fir` anymore](https://github.com/paritytech/substrate/commit/13cdf1c8cd2ee62d411f82b64dc7eba860c9c6c6), if no chain is given our substrate-node will error. -4. [the `subkey`-integration has seen a fix to the `insert`-command](https://github.com/paritytech/substrate/commit/54bde60cfd2c544c54e9e8623b6b8725b99557f8) that requires you to now add the `&cli` as a param. +1. we've [replaced the newly added `BuildSyncSpec` subcommand with an RPC + API](https://github.com/paritytech/substrate/commit/65cc9af9b8df8d36928f6144ee7474cefbd70454#diff-c57da6fbeff8c46ce15f55ea42fedaa5a4684d79578006ce4af01ae04fd6b8f8) + in an on-going effort to make light-client-support smoother, see below +2. we've [removed double accounts from our + chainspec-builder](https://github.com/paritytech/substrate/commit/31499cd29ed30df932fb71b7459796f7160d0272) +3. we [don't fallback to `--chain flaming-fir` + anymore](https://github.com/paritytech/substrate/commit/13cdf1c8cd2ee62d411f82b64dc7eba860c9c6c6), if no chain is + given our `substrate-node` will error. +4. [the `subkey`-integration has seen a fix to the + `insert`-command](https://github.com/paritytech/substrate/commit/54bde60cfd2c544c54e9e8623b6b8725b99557f8) that + requires you to now add the `&cli` as a param. ```diff= --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -344,7 +388,8 @@ A few minor things have changed in the `cli` (compared to 2.0.1): ##### Light client support -As said, we've added a new optional RPC service for improved light client support. For that to work, we need to pass the `chain_spec` and give access to the `AuxStore` to our `rpc`: +As said, we've added a new optional RPC service for improved light client support. For that to work, we need to pass the +`chain_spec` and give access to the `AuxStore` to our `rpc`: ```diff= @@ -438,17 +483,30 @@ and add the new service: ##### Telemetry -The telemetry subsystem has seen a few fixes and refactorings to allow for a more flexible handling, in particular in regards to parachains. Most notably `sc_service::spawn_tasks` now returns the `telemetry_connection_notifier` as the second member of the tuple, (`let (_rpc_handlers, telemetry_connection_notifier) = sc_service::spawn_tasks(`), which should be passed to `telemetry_on_connect` of `new_full_base` now: `telemetry_on_connect: telemetry_connection_notifier.map(|x| x.on_connect_stream()),` (see the service-section below for a full diff). +The telemetry subsystem has seen a few fixes and refactorings to allow for a more flexible handling, in particular in +regards to parachains. Most notably `sc_service::spawn_tasks` now returns the `telemetry_connection_notifier` as the +second member of the tuple, (`let (_rpc_handlers, telemetry_connection_notifier) = sc_service::spawn_tasks(`), which +should be passed to `telemetry_on_connect` of `new_full_base` now: `telemetry_on_connect: +telemetry_connection_notifier.map(|x| x.on_connect_stream()),` (see the service-section below for a full diff). ##### Async & Remote Keystore support -In order to allow for remote-keystores, the keystore-subsystem has been reworked to support async operations and generally refactored to not provide the keys itself but only sign on request. This allows for remote-keystore to never hand out keys and thus to operate any substrate-based node in a manner without ever having the private keys in the local system memory. +In order to allow for remote-keystores, the keystore-subsystem has been reworked to support async operations and +generally refactored to not provide the keys itself but only sign on request. This allows for remote-keystore to never +hand out keys and thus to operate any Substrate-based node in a manner without ever having the private keys in the local +system memory. -There are some operations, however, that the keystore must be local for performance reasons and for which a remote keystore won't work (in particular around parachains). As such, the keystore has both a slot for remote but also always a local instance, where some operations hard bind to the local variant, while most subsystems just ask the generic keystore which prefers a remote signer if given. To reflect this change, `sc_service::new_full_parts` now returns a `KeystoreContainer` rather than the keystore, and the other subsystems (e.g. `sc_service::PartialComponents`) expect to be given that. +There are some operations, however, that the keystore must be local for performance reasons and for which a remote +keystore won't work (in particular around parachains). As such, the keystore has both a slot for remote but also always +a local instance, where some operations hard bind to the local variant, while most subsystems just ask the generic +keystore which prefers a remote signer if given. To reflect this change, `sc_service::new_full_parts` now returns a +`KeystoreContainer` rather than the keystore, and the other subsystems (e.g. `sc_service::PartialComponents`) expect to +be given that. -###### on RPC: +###### on RPC -This has most visible changes for the rpc, where we are switching from the previous `KeyStorePtr` to the new `SyncCryptoStorePtr`: +This has most visible changes for the rpc, where we are switching from the previous `KeyStorePtr` to the new +`SyncCryptoStorePtr`: ```diff @@ -483,9 +541,15 @@ This has most visible changes for the rpc, where we are switching from the previ ##### GRANDPA -As already in the changelog, a few things significant things have changed in regards to GRANDPA: the finality tracker has been replaced, an RPC command has been added and WARP-sync-support for faster light client startup has been implemented. All this means we have to do a few changes to our GRANDPA setup procedures in the client. +As already in the changelog, a few things significant things have changed in regards to GRANDPA: the finality tracker +has been replaced, an RPC command has been added and WARP-sync-support for faster light client startup has been +implemented. All this means we have to do a few changes to our GRANDPA setup procedures in the client. -First and foremost, grandpa internalised a few aspects, and thus `new_partial` doesn't expect a tuple but only the `grandpa::SharedVoterState` as input now, and unpacking that again later is not needed anymore either. On the opposite side `grandpa::FinalityProofProvider::new_for_service` now requires the `Some(shared_authority_set)` to be passed as a new third parameter. This set also becomes relevant when adding warp-sync-support, which is added as an extra-protocol-layer to the networking as: +First and foremost, grandpa internalised a few aspects, and thus `new_partial` doesn't expect a tuple but only the +`grandpa::SharedVoterState` as input now, and unpacking that again later is not needed anymore either. On the opposite +side `grandpa::FinalityProofProvider::new_for_service` now requires the `Some(shared_authority_set)` to be passed as a +new third parameter. This set also becomes relevant when adding warp-sync-support, which is added as an +extra-protocol-layer to the networking as: ```diff= + config.network.extra_sets.push(grandpa::grandpa_peers_set_config()); @@ -496,11 +560,13 @@ First and foremost, grandpa internalised a few aspects, and thus `new_partial` d + )); ``` -As these changes pull through the entirety of `cli/src/service.rs`, we recommend looking at the final diff below for guidance. +As these changes pull through the entirety of `cli/src/service.rs`, we recommend looking at the final diff below for +guidance. ##### In a nutshell -Altogether this accumulates to the following diff for `node/cli/src/service.rs`. If you want these features and have modified your chain you should probably try to apply these patches: +Altogether this accumulates to the following diff for `node/cli/src/service.rs`. If you want these features and have +modified your chain you should probably try to apply these patches: ```diff= diff --git a/substrate/docs/node-template-release.md b/substrate/docs/node-template-release.md index 911e6a2bbe7..0acaf3bdc61 100644 --- a/substrate/docs/node-template-release.md +++ b/substrate/docs/node-template-release.md @@ -1,71 +1,65 @@ # Substrate Node Template Release Process -1. 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 ID in the remote repository. +## 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 +ID in the remote repository. - Assume you are in root directory of Substrate. Run: +Assume you are in root directory of Substrate. Run: - ```bash - cd scripts/ci/ - ./node-template-release.sh - ``` +```bash +cd scripts/ci/ ./node-template-release.sh +``` -2. Expand the output tar gzipped file and replace files in current Substrate Node Template -by running the following command. +## Expand the output tar gzipped file and replace files in current Substrate Node Template by running the following +command. - ```bash - # This is where the tar.gz file uncompressed - cd substrate-node-template - # rsync with force copying. Note the slash at the destination directory is important - rsync -avh * / - # For dry-running add `-n` argument - # rsync -avhn * / - ``` +```bash +# This is where the tar.gz file uncompressed cd substrate-node-template # rsync with force copying. Note the +slash at the destination directory is important rsync -avh * / # For dry-running +add `-n` argument # rsync -avhn * / +``` - The above command only copies existing files from the source to the destination, but does not - delete files/directories that are removed from the source. So you need to manually check and - remove them in the destination. +The above command only copies existing files from the source to the destination, but does not delete files/directories +that are removed from the source. So you need to manually check and remove them in the destination. -3. There is a `Cargo.toml` file in the root directory. Inside, dependencies are listed form and -linked to a certain git commit in Substrate remote repository, such as: +## There is a `Cargo.toml` file in the root directory. Inside, dependencies are listed form and linked to a certain git +commit in Substrate remote repository, such as: - ```toml - sp-core = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", rev = "de80d0107336a9c7a2efdc0199015e4d67fcbdb5", default-features = false } - ``` +```toml +toml sp-core = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", rev = +"de80d0107336a9c7a2efdc0199015e4d67fcbdb5", default-features = false } +``` - We will update each of them to link to the Rust [crate registry](https://crates.io/). -After confirming the versioned package is published in the crate, the above will become: +e will update each of them to link to the Rust [crate registry](https://crates.io/). After confirming the versioned +package is published in the crate, the above will become: - ```toml - [workspace.dependencies] - sp-core = { version = "7.0.0", default-features = false } - ``` +```toml +[workspace.dependencies] sp-core = { version = "7.0.0", default-features = false } +``` - P.S: This step can be automated if we update `node-template-release` package in - `scripts/ci/node-template-release`. +P.S: This step can be automated if we update `node-template-release` package in `scripts/ci/node-template-release`. -4. Once the `Cargo.toml` is updated, compile and confirm that the Node Template builds. Then commit -the changes to a new branch in [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template), and make a PR. +## Once the `Cargo.toml` is updated, compile and confirm that the Node Template builds. Then commit the changes to a new +branch in [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template), and make a PR. - > Note that there is a chance the code in Substrate Node Template works with the linked Substrate git - commit but not with published packages due to the latest (as yet) unpublished features. In this case, - rollback that section of the Node Template to its previous version to ensure the Node Template builds. +> Note that there is a chance the code in Substrate Node Template works with the linked Substrate git commit but not +with published packages due to the latest (as yet) unpublished features. In this case, rollback that section of the +Node Template to its previous version to ensure the Node Template builds. -5. Once the PR is merged, tag the merged commit in master branch with the version number -`vX.Y.Z+A` (e.g. `v3.0.0+1`). The `X`(major), `Y`(minor), and `Z`(patch) version number should -follow Substrate release version. The last digit is any significant fixes made in the Substrate -Node Template apart from Substrate. When the Substrate version is updated, this digit is reset to 0. +## Once the PR is merged, tag the merged commit in master branch with the version number `vX.Y.Z+A` (e.g. `v3.0.0+1`) +The `X`(major), `Y`(minor), and `Z`(patch) version number should follow Substrate release version. The last digit is any +significant fixes made in the Substrate Node Template apart from Substrate. When the Substrate version is updated, this +digit is reset to 0. ## Troubleshooting -- Running the script `./node-template-release.sh `, after all tests passed - successfully, seeing the following error message: +- Running the script `./node-template-release.sh `, after all tests passed successfully, seeing the + following error message: - ``` - thread 'main' panicked at 'Creates output file: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:250:10 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - ``` +``` +thread 'main' panicked at 'Creates output file: Os { code: 2, kind: NotFound, message: "No such file or directory" +}', src/main.rs:250:10 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +``` - This is likely due to that your output path is not a valid `tar.gz` filename or you don't have write - permission to the destination. Try with a simple output path such as `~/node-tpl.tar.gz`. +This is likely due to that your output path is not a valid `tar.gz` filename or you don't have write permission to the +destination. Try with a simple output path such as `~/node-tpl.tar.gz`. diff --git a/substrate/frame/README.md b/substrate/frame/README.md index 47a7892c2c8..0a6c01fd035 100644 --- a/substrate/frame/README.md +++ b/substrate/frame/README.md @@ -1,11 +1,12 @@ # FRAME -The FRAME development environment provides modules (called "pallets") and support libraries that you can use, modify, and extend to build the runtime logic to suit the needs of your blockchain. +The FRAME development environment provides modules (called "pallets") and support libraries that you can use, modify, +and extend to build the runtime logic to suit the needs of your blockchain. -### Documentation +## Documentation https://docs.substrate.io/reference/frame-pallets/ -### Issues +## Issues https://github.com/orgs/paritytech/projects/40 diff --git a/substrate/frame/assets/README.md b/substrate/frame/assets/README.md index aae5244953e..863bcccbbaf 100644 --- a/substrate/frame/assets/README.md +++ b/substrate/frame/assets/README.md @@ -4,21 +4,21 @@ A simple, secure module for dealing with fungible assets. ## Overview -The Assets module provides functionality for asset management of fungible asset classes -with a fixed supply, including: +The Assets module provides functionality for asset management of fungible asset classes with a fixed supply, including: * Asset Issuance * Asset Transfer * Asset Destruction -To use it in your runtime, you need to implement the assets [`assets::Config`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/trait.Config.html). +To use it in your runtime, you need to implement the assets +[`assets::Config`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/trait.Config.html). -The supported dispatchable functions are documented in the [`assets::Call`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/enum.Call.html) enum. +The supported dispatchable functions are documented in the +[`assets::Call`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/enum.Call.html) enum. ### Terminology -* **Asset issuance:** The creation of a new asset, whose total supply will belong to the - account that issues the asset. +* **Asset issuance:** The creation of a new asset, whose total supply will belong to the account that issues the asset. * **Asset transfer:** The action of transferring assets from one account to another. * **Asset destruction:** The process of an account removing its entire holding of an asset. * **Fungible asset:** An asset whose units are interchangeable. @@ -30,20 +30,19 @@ The assets system in Substrate is designed to make the following possible: * Issue a unique asset to its creator's account. * Move assets between accounts. -* Remove an account's balance of an asset when requested by that account's owner and update - the asset's total supply. +* Remove an account's balance of an asset when requested by that account's owner and update the asset's total supply. ## Interface ### Dispatchable Functions * `issue` - Issues the total supply of a new fungible asset to the account of the caller of the function. -* `transfer` - Transfers an `amount` of units of fungible asset `id` from the balance of -the function caller's account (`origin`) to a `target` account. -* `destroy` - Destroys the entire holding of a fungible asset `id` associated with the account -that called the function. +* `transfer` - Transfers an `amount` of units of fungible asset `id` from the balance of the function caller's account +(`origin`) to a `target` account. +* `destroy` - Destroys the entire holding of a fungible asset `id` associated with the account that called the function. -Please refer to the [`Call`](https://docs.rs/pallet-assets/latest/pallet_assets/enum.Call.html) enum and its associated variants for documentation on each function. +Please refer to the [`Call`](https://docs.rs/pallet-assets/latest/pallet_assets/enum.Call.html) enum and its associated +variants for documentation on each function. ### Public Functions @@ -51,7 +50,8 @@ Please refer to the [`Call`](https://docs.rs/pallet-assets/latest/pallet_assets/ * `balance` - Get the asset `id` balance of `who`. * `total_supply` - Get the total supply of an asset `id`. -Please refer to the [`Pallet`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/struct.Pallet.html) struct for details on publicly available functions. +Please refer to the [`Pallet`](https://docs.rs/pallet-assets/latest/pallet_assets/pallet/struct.Pallet.html) struct for +details on publicly available functions. ## Usage @@ -111,11 +111,10 @@ pub mod pallet { ## Assumptions -Below are assumptions that must be held when using this module. If any of -them are violated, the behavior of this module is undefined. +Below are assumptions that must be held when using this module. If any of them are violated, the behavior of this +module is undefined. -* The total count of assets should be less than - `Config::AssetId::max_value()`. +* The total count of assets should be less than `Config::AssetId::max_value()`. ## Related Modules diff --git a/substrate/frame/atomic-swap/README.md b/substrate/frame/atomic-swap/README.md index 888a64ec7e0..d5f924c64fc 100644 --- a/substrate/frame/atomic-swap/README.md +++ b/substrate/frame/atomic-swap/README.md @@ -16,8 +16,8 @@ claimed within a specified duration of time, the sender may cancel it. ### Dispatchable Functions -* `create_swap` - called by a sender to register a new atomic swap -* `claim_swap` - called by the target to approve a swap -* `cancel_swap` - may be called by a sender after a specified duration +- `create_swap` - called by a sender to register a new atomic swap +- `claim_swap` - called by the target to approve a swap +- `cancel_swap` - may be called by a sender after a specified duration License: Apache-2.0 diff --git a/substrate/frame/aura/README.md b/substrate/frame/aura/README.md index 263f158d790..3ce9652a538 100644 --- a/substrate/frame/aura/README.md +++ b/substrate/frame/aura/README.md @@ -23,6 +23,7 @@ consensus rounds (via `slots`). If you're interested in hacking on this module, it is useful to understand the interaction with `substrate/primitives/inherents/src/lib.rs` and, specifically, the required implementation of [`ProvideInherent`](https://docs.rs/sp-inherents/latest/sp_inherents/trait.ProvideInherent.html) and -[`ProvideInherentData`](https://docs.rs/sp-inherents/latest/sp_inherents/trait.ProvideInherentData.html) to create and check inherents. +[`ProvideInherentData`](https://docs.rs/sp-inherents/latest/sp_inherents/trait.ProvideInherentData.html) to create and +check inherents. License: Apache-2.0 diff --git a/substrate/frame/authority-discovery/README.md b/substrate/frame/authority-discovery/README.md index 9a534dcbeb6..f4435a9f316 100644 --- a/substrate/frame/authority-discovery/README.md +++ b/substrate/frame/authority-discovery/README.md @@ -1,6 +1,6 @@ -# Authority discovery module. +# Authority discovery module This module is used by the `client/authority-discovery` to retrieve the current set of authorities. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/authorship/README.md b/substrate/frame/authorship/README.md index d61747da3e1..db4b979319a 100644 --- a/substrate/frame/authorship/README.md +++ b/substrate/frame/authorship/README.md @@ -2,4 +2,4 @@ Authorship tracking for FRAME runtimes. This tracks the current author of the block and recent uncles. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/babe/README.md b/substrate/frame/babe/README.md index 6f20be89efc..3d1af534eeb 100644 --- a/substrate/frame/babe/README.md +++ b/substrate/frame/babe/README.md @@ -1,4 +1,4 @@ Consensus extension module for BABE consensus. Collects on-chain randomness from VRF outputs and manages epoch transitions. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/balances/README.md b/substrate/frame/balances/README.md index fa1ee622d48..1dc93a6bd8f 100644 --- a/substrate/frame/balances/README.md +++ b/substrate/frame/balances/README.md @@ -21,49 +21,48 @@ The Balances module provides functions for: ### Terminology -- **Existential Deposit:** The minimum balance required to create or keep an account open. This prevents -"dust accounts" from filling storage. When the free plus the reserved balance (i.e. the total balance) - fall below this, then the account is said to be dead; and it loses its functionality as well as any - prior history and all information on it is removed from the chain's state. - No account should ever have a total balance that is strictly between 0 and the existential - deposit (exclusive). If this ever happens, it indicates either a bug in this module or an - erroneous raw mutation of storage. +- **Existential Deposit:** The minimum balance required to create or keep an account open. This prevents "dust accounts" +from filling storage. When the free plus the reserved balance (i.e. the total balance) fall below this, then the account + is said to be dead; and it loses its functionality as well as any prior history and all information on it is removed + from the chain's state. No account should ever have a total balance that is strictly between 0 and the existential + deposit (exclusive). If this ever happens, it indicates either a bug in this module or an erroneous raw mutation of + storage. - **Total Issuance:** The total number of units in existence in a system. -- **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its -total balance has become zero (or, strictly speaking, less than the Existential Deposit). +- **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its total balance has +become zero (or, strictly speaking, less than the Existential Deposit). -- **Free Balance:** The portion of a balance that is not reserved. The free balance is the only - balance that matters for most operations. +- **Free Balance:** The portion of a balance that is not reserved. The free balance is the only balance that matters for + most operations. -- **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. - Reserved balance can still be slashed, but only after all the free balance has been slashed. +- **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. Reserved balance can + still be slashed, but only after all the free balance has been slashed. -- **Imbalance:** A condition when some funds were credited or debited without equal and opposite accounting -(i.e. a difference between total issuance and account balances). Functions that result in an imbalance will -return an object of the `Imbalance` trait that can be managed within your runtime logic. (If an imbalance is -simply dropped, it should automatically maintain any book-keeping such as total issuance.) +- **Imbalance:** A condition when some funds were credited or debited without equal and opposite accounting (i.e. a +difference between total issuance and account balances). Functions that result in an imbalance will return an object of +the `Imbalance` trait that can be managed within your runtime logic. (If an imbalance is simply dropped, it should +automatically maintain any book-keeping such as total issuance.) -- **Lock:** A freeze on a specified amount of an account's free balance until a specified block number. Multiple -locks always operate over the same funds, so they "overlay" rather than "stack". +- **Lock:** A freeze on a specified amount of an account's free balance until a specified block number. Multiple locks +always operate over the same funds, so they "overlay" rather than "stack". ### Implementations -The Balances module provides implementations for the following traits. If these traits provide the functionality -that you need, then you can avoid coupling with the Balances module. +The Balances module provides implementations for the following traits. If these traits provide the functionality that +you need, then you can avoid coupling with the Balances module. -- [`Currency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.Currency.html): Functions for dealing with a -fungible assets system. +- [`Currency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.Currency.html): Functions for dealing +with a fungible assets system. - [`ReservableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.ReservableCurrency.html): Functions for dealing with assets that can be reserved from an account. -- [`LockableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.LockableCurrency.html): Functions for -dealing with accounts that allow liquidity restrictions. +- [`LockableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.LockableCurrency.html): Functions +for dealing with accounts that allow liquidity restrictions. - [`Imbalance`](https://docs.rs/frame-support/latest/frame_support/traits/trait.Imbalance.html): Functions for handling -imbalances between total issuance in the system and account balances. Must be used when a function -creates new funds (e.g. a reward) or destroys some funds (e.g. a system fee). -- [`IsDeadAccount`](https://docs.rs/frame-support/latest/frame_support/traits/trait.IsDeadAccount.html): Determiner to say whether a -given account is unused. +imbalances between total issuance in the system and account balances. Must be used when a function creates new funds +(e.g. a reward) or destroys some funds (e.g. a system fee). +- [`IsDeadAccount`](https://docs.rs/frame-support/latest/frame_support/traits/trait.IsDeadAccount.html): Determiner to +say whether a given account is unused. ## Interface @@ -113,10 +112,11 @@ fn update_ledger( ## Genesis config -The Balances module depends on the [`GenesisConfig`](https://docs.rs/pallet-balances/latest/pallet_balances/pallet/struct.GenesisConfig.html). +The Balances module depends on the +[`GenesisConfig`](https://docs.rs/pallet-balances/latest/pallet_balances/pallet/struct.GenesisConfig.html). ## Assumptions -* Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. +- Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. License: Apache-2.0 diff --git a/substrate/frame/benchmarking/README.md b/substrate/frame/benchmarking/README.md index dc6a184435d..bf0bde2c3df 100644 --- a/substrate/frame/benchmarking/README.md +++ b/substrate/frame/benchmarking/README.md @@ -1,99 +1,86 @@ # Substrate Runtime Benchmarking Framework -This crate contains a set of utilities that can be used to benchmark and weigh FRAME pallets that -you develop for your Substrate Runtime. +This crate contains a set of utilities that can be used to benchmark and weigh FRAME pallets that you develop for your +Substrate Runtime. ## Overview -Substrate's FRAME framework allows you to develop custom logic for your blockchain that can be -included in your runtime. This flexibility is key to help you design complex and interactive -pallets, but without accurate weights assigned to dispatchables, your blockchain may become -vulnerable to denial of service (DoS) attacks by malicious actors. +Substrate's FRAME framework allows you to develop custom logic for your blockchain that can be included in your runtime. +This flexibility is key to help you design complex and interactive pallets, but without accurate weights assigned to +dispatchables, your blockchain may become vulnerable to denial of service (DoS) attacks by malicious actors. -The Substrate Runtime Benchmarking Framework is a tool you can use to mitigate DoS attacks against -your blockchain network by benchmarking the computational resources required to execute different -functions in the runtime, for example extrinsics, `on_initialize`, `verify_unsigned`, etc... +The Substrate Runtime Benchmarking Framework is a tool you can use to mitigate DoS attacks against your blockchain +network by benchmarking the computational resources required to execute different functions in the runtime, for example +extrinsics, `on_initialize`, `verify_unsigned`, etc... -The general philosophy behind the benchmarking system is: If your node can know ahead of time how -long it will take to execute an extrinsic, it can safely make decisions to include or exclude that -extrinsic based on its available resources. By doing this, it can keep the block production and -import process running smoothly. +The general philosophy behind the benchmarking system is: If your node can know ahead of time how long it will take to +execute an extrinsic, it can safely make decisions to include or exclude that extrinsic based on its available +resources. By doing this, it can keep the block production and import process running smoothly. To achieve this, we need to model how long it takes to run each function in the runtime by: * Creating custom benchmarking logic that executes a specific code path of a function. -* Executing the benchmark in the Wasm execution environment, on a specific set of hardware, with a - custom runtime configuration, etc... -* Executing the benchmark across controlled ranges of possible values that may affect the result of - the benchmark (called "components"). +* Executing the benchmark in the Wasm execution environment, on a specific set of hardware, with a custom runtime + configuration, etc... +* Executing the benchmark across controlled ranges of possible values that may affect the result of the benchmark + (called "components"). * Executing the benchmark multiple times at each point in order to isolate and remove outliers. * Using the results of the benchmark to create a linear model of the function across its components. -With this linear model, we are able to estimate ahead of time how long it takes to execute some -logic, and thus make informed decisions without actually spending any significant resources at -runtime. +With this linear model, we are able to estimate ahead of time how long it takes to execute some logic, and thus make +informed decisions without actually spending any significant resources at runtime. -Note that we assume that all extrinsics are assumed to be of linear complexity, which is why we are -able to always fit them to a linear model. Quadratic or higher complexity functions are, in general, -considered to be dangerous to the runtime as the weight of these functions may explode as the -runtime state or input becomes too complex. +Note that we assume that all extrinsics are assumed to be of linear complexity, which is why we are able to always fit +them to a linear model. Quadratic or higher complexity functions are, in general, considered to be dangerous to the +runtime as the weight of these functions may explode as the runtime state or input becomes too complex. The benchmarking framework comes with the following tools: -* [A set of macros](./src/lib.rs) (`benchmarks!`, `add_benchmark!`, etc...) to make it easy to - write, test, and add runtime benchmarks. +* [A set of macros](./src/lib.rs) (`benchmarks!`, `add_benchmark!`, etc...) to make it easy to write, test, and add + runtime benchmarks. * [A set of linear regression analysis functions](./src/analysis.rs) for processing benchmark data. -* [A CLI extension](../../utils/frame/benchmarking-cli/README.md) to make it easy to execute benchmarks on your - node. +* [A CLI extension](../../utils/frame/benchmarking-cli/README.md) to make it easy to execute benchmarks on your node. -The end-to-end benchmarking pipeline is disabled by default when compiling a node. If you want to -run benchmarks, you need to enable it by compiling with a Rust feature flag `runtime-benchmarks`. -More details about this below. +The end-to-end benchmarking pipeline is disabled by default when compiling a node. If you want to run benchmarks, you +need to enable it by compiling with a Rust feature flag `runtime-benchmarks`. More details about this below. ### Weight -Substrate represents computational resources using a generic unit of measurement called "Weight". It -defines 10^12 Weight as 1 second of computation on the physical machine used for benchmarking. This -means that the weight of a function may change based on the specific hardware used to benchmark the -runtime functions. +Substrate represents computational resources using a generic unit of measurement called "Weight". It defines 10^12 +Weight as 1 second of computation on the physical machine used for benchmarking. This means that the weight of a +function may change based on the specific hardware used to benchmark the runtime functions. -By modeling the expected weight of each runtime function, the blockchain is able to calculate how -many transactions or system level functions it will be able to execute within a certain period of -time. Often, the limiting factor for a blockchain is the fixed block production time for the -network. +By modeling the expected weight of each runtime function, the blockchain is able to calculate how many transactions or +system level functions it will be able to execute within a certain period of time. Often, the limiting factor for a +blockchain is the fixed block production time for the network. -Within FRAME, each dispatchable function must have a `#[weight]` annotation with a function that can -return the expected weight for the worst case scenario execution of that function given its inputs. -This benchmarking framework will result in a file that automatically generates those formulas for -you, which you can then use in your pallet. +Within FRAME, each dispatchable function must have a `#[weight]` annotation with a function that can return the expected +weight for the worst case scenario execution of that function given its inputs. This benchmarking framework will result +in a file that automatically generates those formulas for you, which you can then use in your pallet. ## Writing Benchmarks -Writing a runtime benchmark is much like writing a unit test for your pallet. It needs to be -carefully crafted to execute a certain logical path in your code. In tests you want to check for -various success and failure conditions, but with benchmarks you specifically look for the **most -computationally heavy** path, a.k.a the "worst case scenario". +Writing a runtime benchmark is much like writing a unit test for your pallet. It needs to be carefully crafted to +execute a certain logical path in your code. In tests you want to check for various success and failure conditions, but +with benchmarks you specifically look for the **most computationally heavy** path, a.k.a the "worst case scenario". -This means that if there are certain storage items or runtime state that may affect the complexity -of the function, for example triggering more iterations in a `for` loop, to get an accurate result, -you must set up your benchmark to trigger this. +This means that if there are certain storage items or runtime state that may affect the complexity of the function, for +example triggering more iterations in a `for` loop, to get an accurate result, you must set up your benchmark to trigger +this. -It may be that there are multiple paths your function can go down, and it is not clear which one is -the heaviest. In this case, you should just create a benchmark for each scenario! You may find that -there are paths in your code where complexity may become unbounded depending on user input. This may -be a hint that you should enforce sane boundaries for how a user can use your pallet. For example: -limiting the number of elements in a vector, limiting the number of iterations in a `for` loop, -etc... +It may be that there are multiple paths your function can go down, and it is not clear which one is the heaviest. In +this case, you should just create a benchmark for each scenario! You may find that there are paths in your code where +complexity may become unbounded depending on user input. This may be a hint that you should enforce sane boundaries for +how a user can use your pallet. For example: limiting the number of elements in a vector, limiting the number of +iterations in a `for` loop, etc... -Examples of end-to-end benchmarks can be found in the [pallets provided by Substrate](../), and the -specific details on how to use the `benchmarks!` macro can be found in [its -documentation](./src/lib.rs). +Examples of end-to-end benchmarks can be found in the [pallets provided by Substrate](../), and the specific details on +how to use the `benchmarks!` macro can be found in [its documentation](./src/lib.rs). ## Testing Benchmarks -You can test your benchmarks using the same test runtime that you created for your pallet's unit -tests. By creating your benchmarks in the `benchmarks!` macro, it automatically generates test -functions for you: +You can test your benchmarks using the same test runtime that you created for your pallet's unit tests. By creating your +benchmarks in the `benchmarks!` macro, it automatically generates test functions for you: ```rust fn test_benchmark_[benchmark_name]::() -> Result<(), &'static str> @@ -101,19 +88,18 @@ fn test_benchmark_[benchmark_name]::() -> Result<(), &'static str> Simply add these functions to a unit test and ensure that the result of the function is `Ok(())`. -> **Note:** If your test runtime and production runtime have different configurations, you may get -different results when testing your benchmark and actually running it. +> **Note:** If your test runtime and production runtime have different configurations, you may get different results +when testing your benchmark and actually running it. -In general, benchmarks returning `Ok(())` is all you need to check for since it signals the executed -extrinsic has completed successfully. However, you can optionally include a `verify` block with your -benchmark, which can additionally verify any final conditions, such as the final state of your -runtime. +In general, benchmarks returning `Ok(())` is all you need to check for since it signals the executed extrinsic has +completed successfully. However, you can optionally include a `verify` block with your benchmark, which can additionally +verify any final conditions, such as the final state of your runtime. These additional `verify` blocks will not affect the results of your final benchmarking process. -To run the tests, you need to enable the `runtime-benchmarks` feature flag. This may also mean you -need to move into your node's binary folder. For example, with the Substrate repository, this is how -you would test the Balances pallet's benchmarks: +To run the tests, you need to enable the `runtime-benchmarks` feature flag. This may also mean you need to move into +your node's binary folder. For example, with the Substrate repository, this is how you would test the Balances pallet's +benchmarks: ```bash cargo test -p pallet-balances --features runtime-benchmarks @@ -123,19 +109,20 @@ cargo test -p pallet-balances --features runtime-benchmarks > ``` > error: --features is not allowed in the root of a virtual workspace` > ``` -> To solve this, navigate to the folder of the node (`cd bin/node/cli`) or pallet (`cd frame/pallet`) and run the command there. +> To solve this, navigate to the folder of the node (`cd bin/node/cli`) or pallet (`cd frame/pallet`) and run the +> command there. -This will instance each linear component with different values. The number of values per component is set to six and can be changed with the `VALUES_PER_COMPONENT` environment variable. +This will instance each linear component with different values. The number of values per component is set to six and can +be changed with the `VALUES_PER_COMPONENT` environment variable. ## Adding Benchmarks -The benchmarks included with each pallet are not automatically added to your node. To actually -execute these benchmarks, you need to implement the `frame_benchmarking::Benchmark` trait. You can -see an example of how to do this in the [included Substrate -node](../../bin/node/runtime/src/lib.rs). +The benchmarks included with each pallet are not automatically added to your node. To actually execute these benchmarks, +you need to implement the `frame_benchmarking::Benchmark` trait. You can see an example of how to do this in the +[included Substrate node](../../bin/node/runtime/src/lib.rs). -Assuming there are already some benchmarks set up on your node, you just need to add another -instance of the `add_benchmark!` macro: +Assuming there are already some benchmarks set up on your node, you just need to add another instance of the +`add_benchmark!` macro: ```rust /// configuration for running benchmarks @@ -147,22 +134,20 @@ add_benchmark!(params, batches, pallet_balances, Balances); /// the `struct` created for your pallet by `construct_runtime!` ``` -Once you have done this, you will need to compile your node binary with the `runtime-benchmarks` -feature flag: +Once you have done this, you will need to compile your node binary with the `runtime-benchmarks` feature flag: ```bash cd bin/node/cli cargo build --profile=production --features runtime-benchmarks ``` -The production profile applies various compiler optimizations. -These optimizations slow down the compilation process *a lot*. +The production profile applies various compiler optimizations. +These optimizations slow down the compilation process *a lot*. If you are just testing things out and don't need final numbers, don't include `--profile=production`. ## Running Benchmarks -Finally, once you have a node binary with benchmarks enabled, you need to execute your various -benchmarks. +Finally, once you have a node binary with benchmarks enabled, you need to execute your various benchmarks. You can get a list of the available benchmarks by running: @@ -183,24 +168,24 @@ Then you can run a benchmark like so: --output \ # Output benchmark results into a folder or file ``` -This will output a file `pallet_name.rs` which implements the `WeightInfo` trait you should include -in your pallet. Double colons `::` will be replaced with a `_` in the output name if you specify a directory. Each blockchain should generate their own benchmark file with their custom -implementation of the `WeightInfo` trait. This means that you will be able to use these modular -Substrate pallets while still keeping your network safe for your specific configuration and +This will output a file `pallet_name.rs` which implements the `WeightInfo` trait you should include in your pallet. +Double colons `::` will be replaced with a `_` in the output name if you specify a directory. Each blockchain should +generate their own benchmark file with their custom implementation of the `WeightInfo` trait. This means that you will +be able to use these modular Substrate pallets while still keeping your network safe for your specific configuration and requirements. -The benchmarking CLI uses a Handlebars template to format the final output file. You can optionally -pass the flag `--template` pointing to a custom template that can be used instead. Within the -template, you have access to all the data provided by the `TemplateData` struct in the -[benchmarking CLI writer](../../utils/frame/benchmarking-cli/src/writer.rs). You can find the -default template used [here](../../utils/frame/benchmarking-cli/src/template.hbs). +The benchmarking CLI uses a Handlebars template to format the final output file. You can optionally pass the flag +`--template` pointing to a custom template that can be used instead. Within the template, you have access to all the +data provided by the `TemplateData` struct in the [benchmarking CLI +writer](../../utils/frame/benchmarking-cli/src/writer.rs). You can find the default template used +[here](../../utils/frame/benchmarking-cli/src/template.hbs). There are some custom Handlebars helpers included with our output generation: -* `underscore`: Add an underscore to every 3rd character from the right of a string. Primarily to be -used for delimiting large numbers. -* `join`: Join an array of strings into a space-separated string for the template. Primarily to be -used for joining all the arguments passed to the CLI. +* `underscore`: Add an underscore to every 3rd character from the right of a string. Primarily to be used for delimiting +large numbers. +* `join`: Join an array of strings into a space-separated string for the template. Primarily to be used for joining all +the arguments passed to the CLI. To get a full list of available options when running benchmarks, run: diff --git a/substrate/frame/child-bounties/README.md b/substrate/frame/child-bounties/README.md index 695b6616b17..cf62698dcaf 100644 --- a/substrate/frame/child-bounties/README.md +++ b/substrate/frame/child-bounties/README.md @@ -8,7 +8,7 @@ With child bounties, a large bounty proposal can be divided into smaller chunks, for parallel execution, and for efficient governance and tracking of spent funds. A child bounty is a smaller piece of work, extracted from a parent bounty. A curator is assigned after the child bounty is created by the parent bounty curator, -to be delegated with the responsibility of assigning a payout address once +to be delegated with the responsibility of assigning a payout address once the specified set of tasks is completed. ## Interface diff --git a/substrate/frame/contracts/CHANGELOG.md b/substrate/frame/contracts/CHANGELOG.md index dcb9d6d4d2b..aca94e5b149 100644 --- a/substrate/frame/contracts/CHANGELOG.md +++ b/substrate/frame/contracts/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -The semantic versioning guarantees cover the interface to the substrate runtime which +The semantic versioning guarantees cover the interface to the Substrate runtime which includes this pallet as a dependency. This module will also add storage migrations whenever changes require it. Stability with regard to offchain tooling is explicitly excluded from this guarantee: For example adding a new field to an in-storage data structure will require diff --git a/substrate/frame/contracts/README.md b/substrate/frame/contracts/README.md index aeb30cef32f..0b6548cf641 100644 --- a/substrate/frame/contracts/README.md +++ b/substrate/frame/contracts/README.md @@ -9,66 +9,68 @@ The Contracts module provides functionality for the runtime to deploy and execut ## Overview -This module extends accounts based on the [`frame_support::traits::fungible`] traits to have smart-contract functionality. It can -be used with other modules that implement accounts based on [`frame_support::traits::fungible`]. These "smart-contract accounts" -have the ability to instantiate smart-contracts and make calls to other contract and non-contract accounts. +This module extends accounts based on the [`frame_support::traits::fungible`] traits to have smart-contract +functionality. It can be used with other modules that implement accounts based on [`frame_support::traits::fungible`]. +These "smart-contract accounts" have the ability to instantiate smart-contracts and make calls to other contract and +non-contract accounts. -The smart-contract code is stored once, and later retrievable via its `code_hash`. -This means that multiple smart-contracts can be instantiated from the same `code`, without replicating -the code each time. +The smart-contract code is stored once, and later retrievable via its `code_hash`. This means that multiple +smart-contracts can be instantiated from the same `code`, without replicating the code each time. -When a smart-contract is called, its associated code is retrieved via the code hash and gets executed. -This call can alter the storage entries of the smart-contract account, instantiate new smart-contracts, -or call other smart-contracts. +When a smart-contract is called, its associated code is retrieved via the code hash and gets executed. This call can +alter the storage entries of the smart-contract account, instantiate new smart-contracts, or call other smart-contracts. -Finally, when an account is reaped, its associated code and storage of the smart-contract account -will also be deleted. +Finally, when an account is reaped, its associated code and storage of the smart-contract account will also be deleted. ### Weight -Senders must specify a [`Weight`](https://paritytech.github.io/substrate/master/sp_weights/struct.Weight.html) limit with every call, as all instructions invoked by the smart-contract require weight. -Unused weight is refunded after the call, regardless of the execution outcome. +Senders must specify a [`Weight`](https://paritytech.github.io/substrate/master/sp_weights/struct.Weight.html) limit +with every call, as all instructions invoked by the smart-contract require weight. Unused weight is refunded after the +call, regardless of the execution outcome. -If the weight limit is reached, then all calls and state changes (including balance transfers) are only -reverted at the current call's contract level. For example, if contract A calls B and B runs out of weight mid-call, -then all of B's calls are reverted. Assuming correct error handling by contract A, A's other calls and state -changes still persist. +If the weight limit is reached, then all calls and state changes (including balance transfers) are only reverted at the +current call's contract level. For example, if contract A calls B and B runs out of weight mid-call, then all of B's +calls are reverted. Assuming correct error handling by contract A, A's other calls and state changes still persist. One `ref_time` `Weight` is defined as one picosecond of execution time on the runtime's reference machine. ### Revert Behaviour -Contract call failures are not cascading. When failures occur in a sub-call, they do not "bubble up", -and the call will only revert at the specific contract level. For example, if contract A calls contract B, and B -fails, A can decide how to handle that failure, either proceeding or reverting A's changes. +Contract call failures are not cascading. When failures occur in a sub-call, they do not "bubble up", and the call will +only revert at the specific contract level. For example, if contract A calls contract B, and B fails, A can decide how +to handle that failure, either proceeding or reverting A's changes. ### Off-chain Execution -In general, a contract execution needs to be deterministic so that all nodes come to the same -conclusion when executing it. To that end we disallow any instructions that could cause -indeterminism. Most notable are any floating point arithmetic. That said, sometimes contracts -are executed off-chain and hence are not subject to consensus. If code is only executed by a -single node and implicitly trusted by other actors is such a case. Trusted execution environments -come to mind. To that end we allow the execution of indeterminstic code for off-chain usages -with the following constraints: - -1. No contract can ever be instantiated from an indeterministic code. The only way to execute -the code is to use a delegate call from a deterministic contract. -2. The code that wants to use this feature needs to depend on `pallet-contracts` and use [`bare_call()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.bare_call) +In general, a contract execution needs to be deterministic so that all nodes come to the same conclusion when executing +it. To that end we disallow any instructions that could cause indeterminism. Most notable are any floating point +arithmetic. That said, sometimes contracts are executed off-chain and hence are not subject to consensus. If code is +only executed by a single node and implicitly trusted by other actors is such a case. Trusted execution environments +come to mind. To that end we allow the execution of indeterminstic code for off-chain usages with the following +constraints: + +1. No contract can ever be instantiated from an indeterministic code. The only way to execute the code is to use a +delegate call from a deterministic contract. +2. The code that wants to use this feature needs to depend on `pallet-contracts` and use +[`bare_call()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.bare_call) directly. This makes sure that by default `pallet-contracts` does not expose any indeterminism. #### How to use -An indeterministic code can be deployed on-chain by passing `Determinism::Relaxed` -to [`upload_code()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.upload_code). A deterministic contract can then delegate call into it if and only if it -is ran by using [`bare_call()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.bare_call) and passing [`Determinism::Relaxed`](https://paritytech.github.io/substrate/master/pallet_contracts/enum.Determinism.html#variant.Relaxed) to it. **Never use -this argument when the contract is called from an on-chain transaction.** +An indeterministic code can be deployed on-chain by passing `Determinism::Relaxed` to +[`upload_code()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.upload_code). +A deterministic contract can then delegate call into it if and only if it is ran by using +[`bare_call()`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/struct.Pallet.html#method.bare_call) +and passing +[`Determinism::Relaxed`](https://paritytech.github.io/substrate/master/pallet_contracts/enum.Determinism.html#variant.Relaxed) +to it. **Never use this argument when the contract is called from an on-chain transaction.** ## Interface ### Dispatchable functions -Those are documented in the [reference documentation](https://paritytech.github.io/substrate/master/pallet_contracts/index.html#dispatchable-functions). +Those are documented in the [reference +documentation](https://paritytech.github.io/substrate/master/pallet_contracts/index.html#dispatchable-functions). ### Interface exposed to contracts @@ -99,43 +101,43 @@ The documentation of all importable functions can be found ## Usage -This module executes WebAssembly smart contracts. These can potentially be written in any language -that compiles to Wasm. However, using a language that specifically targets this module -will make things a lot easier. One such language is [`ink!`](https://use.ink). It enables -writing WebAssembly-based smart-contracts in the Rust programming language. +This module executes WebAssembly smart contracts. These can potentially be written in any language that compiles to +Wasm. However, using a language that specifically targets this module will make things a lot easier. One such language +is [`ink!`](https://use.ink). It enables writing WebAssembly-based smart-contracts in the Rust programming language. ## Debugging -Contracts can emit messages to the client when called as RPC through the [`debug_message`](https://paritytech.github.io/substrate/master/pallet_contracts/api_doc/trait.Current.html#tymethod.debug_message) +Contracts can emit messages to the client when called as RPC through the +[`debug_message`](https://paritytech.github.io/substrate/master/pallet_contracts/api_doc/trait.Current.html#tymethod.debug_message) API. This is exposed in [ink!](https://use.ink) via [`ink_env::debug_message()`](https://paritytech.github.io/ink/ink_env/fn.debug_message.html). -Those messages are gathered into an internal buffer and sent to the RPC client. -It is up the the individual client if and how those messages are presented to the user. +Those messages are gathered into an internal buffer and sent to the RPC client. It is up the the individual client if +and how those messages are presented to the user. -This buffer is also printed as a debug message. In order to see these messages on the node -console the log level for the `runtime::contracts` target needs to be raised to at least -the `debug` level. However, those messages are easy to overlook because of the noise generated -by block production. A good starting point for observing them on the console is using this -command line in the root directory of the substrate repository: +This buffer is also printed as a debug message. In order to see these messages on the node console the log level for the +`runtime::contracts` target needs to be raised to at least the `debug` level. However, those messages are easy to +overlook because of the noise generated by block production. A good starting point for observing them on the console is +using this command line in the root directory of the Substrate repository: ```bash cargo run --release -- --dev -lerror,runtime::contracts=debug ``` -This raises the log level of `runtime::contracts` to `debug` and all other targets -to `error` in order to prevent them from spamming the console. +This raises the log level of `runtime::contracts` to `debug` and all other targets to `error` in order to prevent them +from spamming the console. -`--dev`: Use a dev chain spec -`--tmp`: Use temporary storage for chain data (the chain state is deleted on exit) +`--dev`: Use a dev chain spec `--tmp`: Use temporary storage for chain data (the chain state is deleted on exit) ## Host function tracing -For contract authors, it can be a helpful debugging tool to see which host functions are called, with which arguments, and what the result was. +For contract authors, it can be a helpful debugging tool to see which host functions are called, with which arguments, +and what the result was. -In order to see these messages on the node console, the log level for the `runtime::contracts::strace` target needs to be raised to the `trace` level. +In order to see these messages on the node console, the log level for the `runtime::contracts::strace` target needs to +be raised to the `trace` level. -Example: +Example: ```bash cargo run --release -- --dev -lerror,runtime::contracts::strace=trace,runtime::contracts=debug @@ -143,18 +145,16 @@ cargo run --release -- --dev -lerror,runtime::contracts::strace=trace,runtime::c ## Unstable Interfaces -Driven by the desire to have an iterative approach in developing new contract interfaces -this pallet contains the concept of an unstable interface. Akin to the rust nightly compiler -it allows us to add new interfaces but mark them as unstable so that contract languages can -experiment with them and give feedback before we stabilize those. +Driven by the desire to have an iterative approach in developing new contract interfaces this pallet contains the +concept of an unstable interface. Akin to the rust nightly compiler it allows us to add new interfaces but mark them as +unstable so that contract languages can experiment with them and give feedback before we stabilize those. In order to access interfaces marked as `#[unstable]` in [`runtime.rs`](src/wasm/runtime.rs) one need to set -`pallet_contracts::Config::UnsafeUnstableInterface` to `ConstU32`. **It should be obvious -that any production runtime should never be compiled with this feature: In addition to be -subject to change or removal those interfaces might not have proper weights associated with -them and are therefore considered unsafe**. +`pallet_contracts::Config::UnsafeUnstableInterface` to `ConstU32`. **It should be obvious that any production +runtime should never be compiled with this feature: In addition to be subject to change or removal those interfaces +might not have proper weights associated with them and are therefore considered unsafe**. -New interfaces are generally added as unstable and might go through several iterations -before they are promoted to a stable interface. +New interfaces are generally added as unstable and might go through several iterations before they are promoted to a +stable interface. License: Apache-2.0 diff --git a/substrate/frame/contracts/benchmarks/README.md b/substrate/frame/contracts/benchmarks/README.md index a621dd65d59..e4441d6bab2 100644 --- a/substrate/frame/contracts/benchmarks/README.md +++ b/substrate/frame/contracts/benchmarks/README.md @@ -1,9 +1,8 @@ # Benchmarks -This directory contains real world ([ink!](https://use.ink), [solang](https://github.com/hyperledger/solang)) contracts which are used in macro benchmarks. -Those benchmarks are not used to determine weights but rather to compare different contract -languages and execution engines with larger wasm modules. - -Files in this directory are used by `#[extra]` benchmarks in `src/benchmarking`. The json -files are for informational purposes only and are not consumed by the benchmarks. +This directory contains real world ([ink!](https://use.ink), [solang](https://github.com/hyperledger/solang)) contracts +which are used in macro benchmarks. Those benchmarks are not used to determine weights but rather to compare different +contract languages and execution engines with larger wasm modules. +Files in this directory are used by `#[extra]` benchmarks in `src/benchmarking`. The json files are for informational +purposes only and are not consumed by the benchmarks. diff --git a/substrate/frame/contracts/primitives/README.md b/substrate/frame/contracts/primitives/README.md index 12718cd8642..c84cfbfe1a8 100644 --- a/substrate/frame/contracts/primitives/README.md +++ b/substrate/frame/contracts/primitives/README.md @@ -1,3 +1,3 @@ A crate that hosts a common definitions that are relevant for the pallet-contracts. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/core-fellowship/README.md b/substrate/frame/core-fellowship/README.md index 3c9b1f63e08..97718eef7a3 100644 --- a/substrate/frame/core-fellowship/README.md +++ b/substrate/frame/core-fellowship/README.md @@ -1,3 +1,3 @@ # Core Fellowship -Logic specific to the core Polkadot Fellowship. \ No newline at end of file +Logic specific to the core Polkadot Fellowship. diff --git a/substrate/frame/elections-phragmen/README.md b/substrate/frame/elections-phragmen/README.md index 26b3f260da5..f5ed609f212 100644 --- a/substrate/frame/elections-phragmen/README.md +++ b/substrate/frame/elections-phragmen/README.md @@ -1,64 +1,58 @@ -# Phragmén Election Module. +# Phragmén Election Module An election module based on sequential phragmen. -### Term and Round - -The election happens in _rounds_: every `N` blocks, all previous members are retired and a new -set is elected (which may or may not have an intersection with the previous set). Each round -lasts for some number of blocks defined by `TermDuration` storage item. The words _term_ and -_round_ can be used interchangeably in this context. - -`TermDuration` might change during a round. This can shorten or extend the length of the round. -The next election round's block number is never stored but rather always checked on the fly. -Based on the current block number and `TermDuration`, the condition `BlockNumber % TermDuration -== 0` being satisfied will always trigger a new election round. - -### Voting - -Voters can vote for any set of the candidates by providing a list of account ids. Invalid votes -(voting for non-candidates) are ignored during election. Yet, a voter _might_ vote for a future -candidate. Voters reserve a bond as they vote. Each vote defines a `value`. This amount is -locked from the account of the voter and indicates the weight of the vote. Voters can update -their votes at any time by calling `vote()` again. This keeps the bond untouched but can -optionally change the locked `value`. After a round, votes are kept and might still be valid for -further rounds. A voter is responsible for calling `remove_voter` once they are done to have -their bond back and remove the lock. - -Voters also report other voters as being defunct to earn their bond. A voter is defunct once all -of the candidates that they have voted for are neither a valid candidate anymore nor a member. -Upon reporting, if the target voter is actually defunct, the reporter will be rewarded by the -voting bond of the target. The target will lose their bond and get removed. If the target is not -defunct, the reporter is slashed and removed. To prevent being reported, voters should manually -submit a `remove_voter()` as soon as they are in the defunct state. - -### Candidacy and Members - -Candidates also reserve a bond as they submit candidacy. A candidate cannot take their candidacy -back. A candidate can end up in one of the below situations: - - **Winner**: A winner is kept as a _member_. They must still have a bond in reserve and they - are automatically counted as a candidate for the next election. - - **Runner-up**: Runners-up are the best candidates immediately after the winners. The number - of runners_up to keep is configurable. Runners-up are used, in order that they are elected, - as replacements when a candidate is kicked by `[remove_member]`, or when an active member - renounces their candidacy. Runners are automatically counted as a candidate for the next - election. - - **Loser**: Any of the candidate who are not a winner are left as losers. A loser might be an - _outgoing member or runner_, meaning that they are an active member who failed to keep their - spot. An outgoing will always lose their bond. - -##### Renouncing candidacy. - -All candidates, elected or not, can renounce their candidacy. A call to [`Module::renounce_candidacy`] -will always cause the candidacy bond to be refunded. - -Note that with the members being the default candidates for the next round and votes persisting -in storage, the election system is entirely stable given no further input. This means that if -the system has a particular set of candidates `C` and voters `V` that lead to a set of members -`M` being elected, as long as `V` and `C` don't remove their candidacy and votes, `M` will keep -being re-elected at the end of each round. - -### Module Information +## Term and Round + +The election happens in _rounds_: every `N` blocks, all previous members are retired and a new set is elected (which may +or may not have an intersection with the previous set). Each round lasts for some number of blocks defined by +`TermDuration` storage item. The words _term_ and _round_ can be used interchangeably in this context. + +`TermDuration` might change during a round. This can shorten or extend the length of the round. The next election +round's block number is never stored but rather always checked on the fly. Based on the current block number and +`TermDuration`, the condition `BlockNumber % TermDuration == 0` being satisfied will always trigger a new election +round. + +## Voting + +Voters can vote for any set of the candidates by providing a list of account ids. Invalid votes (voting for +non-candidates) are ignored during election. Yet, a voter _might_ vote for a future candidate. Voters reserve a bond as +they vote. Each vote defines a `value`. This amount is locked from the account of the voter and indicates the weight of +the vote. Voters can update their votes at any time by calling `vote()` again. This keeps the bond untouched but can +optionally change the locked `value`. After a round, votes are kept and might still be valid for further rounds. A voter +is responsible for calling `remove_voter` once they are done to have their bond back and remove the lock. + +Voters also report other voters as being defunct to earn their bond. A voter is defunct once all of the candidates that +they have voted for are neither a valid candidate anymore nor a member. Upon reporting, if the target voter is actually +defunct, the reporter will be rewarded by the voting bond of the target. The target will lose their bond and get +removed. If the target is not defunct, the reporter is slashed and removed. To prevent being reported, voters should +manually submit a `remove_voter()` as soon as they are in the defunct state. + +## Candidacy and Members + +Candidates also reserve a bond as they submit candidacy. A candidate cannot take their candidacy back. A candidate can +end up in one of the below situations: + - **Winner**: A winner is kept as a _member_. They must still have a bond in reserve and they are automatically + counted as a candidate for the next election. + - **Runner-up**: Runners-up are the best candidates immediately after the winners. The number of runners_up to keep is + configurable. Runners-up are used, in order that they are elected, as replacements when a candidate is kicked by + `[remove_member]`, or when an active member renounces their candidacy. Runners are automatically counted as a + candidate for the next election. + - **Loser**: Any of the candidate who are not a winner are left as losers. A loser might be an _outgoing member or + runner_, meaning that they are an active member who failed to keep their spot. An outgoing will always lose their + bond. + +### Renouncing candidacy + +All candidates, elected or not, can renounce their candidacy. A call to [`Module::renounce_candidacy`] will always cause +the candidacy bond to be refunded. + +Note that with the members being the default candidates for the next round and votes persisting in storage, the election +system is entirely stable given no further input. This means that if the system has a particular set of candidates `C` +and voters `V` that lead to a set of members `M` being elected, as long as `V` and `C` don't remove their candidacy and +votes, `M` will keep being re-elected at the end of each round. + +## Module Information - [`election_sp_phragmen::Config`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/trait.Config.html) - [`Call`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/enum.Call.html) diff --git a/substrate/frame/examples/basic/README.md b/substrate/frame/examples/basic/README.md index 2af50573f80..be787d1b6ec 100644 --- a/substrate/frame/examples/basic/README.md +++ b/substrate/frame/examples/basic/README.md @@ -9,7 +9,7 @@ Run `cargo doc --package pallet-example-basic --open` to view this pallet's docu **This pallet serves as an example and is not meant to be used in production.** -### Documentation Guidelines: +## Documentation Guidelines diff --git a/substrate/frame/examples/split/README.md b/substrate/frame/examples/split/README.md index 413ce9b913c..9c4d5443ca0 100644 --- a/substrate/frame/examples/split/README.md +++ b/substrate/frame/examples/split/README.md @@ -3,7 +3,7 @@ A simple example of a FRAME pallet demonstrating the ability to split sections across multiple files. -Note that this is purely experimental at this point. +Note that this is purely experimental at this point. Run `cargo doc --package pallet-example-split --open` to view this pallet's documentation. diff --git a/substrate/frame/executive/README.md b/substrate/frame/executive/README.md index c14c3912b08..96a412a4537 100644 --- a/substrate/frame/executive/README.md +++ b/substrate/frame/executive/README.md @@ -1,13 +1,13 @@ # Executive Module -The Executive module acts as the orchestration layer for the runtime. It dispatches incoming -extrinsic calls to the respective modules in the runtime. +The Executive module acts as the orchestration layer for the runtime. It dispatches incoming extrinsic calls to the +respective modules in the runtime. ## Overview -The executive module is not a typical pallet providing functionality around a specific feature. -It is a cross-cutting framework component for the FRAME. It works in conjunction with the -[FRAME System module](https://docs.rs/frame-system/latest/frame_system/) to perform these cross-cutting functions. +The executive module is not a typical pallet providing functionality around a specific feature. It is a cross-cutting +framework component for the FRAME. It works in conjunction with the [FRAME System +module](https://docs.rs/frame-system/latest/frame_system/) to perform these cross-cutting functions. The Executive module provides functions to: @@ -26,7 +26,8 @@ The Executive module provides the following implementations: ## Usage -The default Substrate node template declares the [`Executive`](https://docs.rs/frame-executive/latest/frame_executive/struct.Executive.html) type in its library. +The default Substrate node template declares the +[`Executive`](https://docs.rs/frame-executive/latest/frame_executive/struct.Executive.html) type in its library. ### Example @@ -46,9 +47,8 @@ pub type Executive = executive::Executive< ### Custom `OnRuntimeUpgrade` logic -You can add custom logic that should be called in your runtime on a runtime upgrade. This is -done by setting an optional generic parameter. The custom logic will be called before -the on runtime upgrade logic of all modules is called. +You can add custom logic that should be called in your runtime on a runtime upgrade. This is done by setting an optional +generic parameter. The custom logic will be called before the on runtime upgrade logic of all modules is called. ```rust # diff --git a/substrate/frame/glutton/README.md b/substrate/frame/glutton/README.md index 8ad4f791718..89dbe26ec7a 100644 --- a/substrate/frame/glutton/README.md +++ b/substrate/frame/glutton/README.md @@ -4,6 +4,9 @@ # Glutton Pallet -The `Glutton` pallet gets the name from its property to consume vast amounts of resources. It can be used to push para-chains and their relay-chains to the limits. This is good for testing out theoretical limits in a practical way. +The `Glutton` pallet gets the name from its property to consume vast amounts of resources. It can be used to push +para-chains and their relay-chains to the limits. This is good for testing out theoretical limits in a practical way. -The `Glutton` can be set to consume a fraction of the available unused weight of a chain. It accomplishes this by utilizing the `on_idle` hook and consuming a specific ration of the remaining weight. The rations can be set via `set_compute` and `set_storage`. Initially the `Glutton` needs to be initialized once with `initialize_pallet`. +The `Glutton` can be set to consume a fraction of the available unused weight of a chain. It accomplishes this by +utilizing the `on_idle` hook and consuming a specific ration of the remaining weight. The rations can be set via +`set_compute` and `set_storage`. Initially the `Glutton` needs to be initialized once with `initialize_pallet`. diff --git a/substrate/frame/grandpa/README.md b/substrate/frame/grandpa/README.md index 84b181a8b31..5978931c5a8 100644 --- a/substrate/frame/grandpa/README.md +++ b/substrate/frame/grandpa/README.md @@ -9,4 +9,4 @@ finality notifications. For full integration with GRANDPA, the `GrandpaApi` should be implemented. The necessary items are re-exported via the `fg_primitives` crate. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index a67c259e253..0203656eff4 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -28,27 +28,27 @@ no state-bloat attack is viable. ### Dispatchable Functions #### For general users -* `set_identity` - Set the associated identity of an account; a small deposit is reserved if not +- `set_identity` - Set the associated identity of an account; a small deposit is reserved if not already taken. -* `clear_identity` - Remove an account's associated identity; the deposit is returned. -* `request_judgement` - Request a judgement from a registrar, paying a fee. -* `cancel_request` - Cancel the previous request for a judgement. +- `clear_identity` - Remove an account's associated identity; the deposit is returned. +- `request_judgement` - Request a judgement from a registrar, paying a fee. +- `cancel_request` - Cancel the previous request for a judgement. #### For general users with sub-identities -* `set_subs` - Set the sub-accounts of an identity. -* `add_sub` - Add a sub-identity to an identity. -* `remove_sub` - Remove a sub-identity of an identity. -* `rename_sub` - Rename a sub-identity of an identity. -* `quit_sub` - Remove a sub-identity of an identity (called by the sub-identity). +- `set_subs` - Set the sub-accounts of an identity. +- `add_sub` - Add a sub-identity to an identity. +- `remove_sub` - Remove a sub-identity of an identity. +- `rename_sub` - Rename a sub-identity of an identity. +- `quit_sub` - Remove a sub-identity of an identity (called by the sub-identity). #### For registrars -* `set_fee` - Set the fee required to be paid for a judgement to be given by the registrar. -* `set_fields` - Set the fields that a registrar cares about in their judgements. -* `provide_judgement` - Provide a judgement to an identity. +- `set_fee` - Set the fee required to be paid for a judgement to be given by the registrar. +- `set_fields` - Set the fields that a registrar cares about in their judgements. +- `provide_judgement` - Provide a judgement to an identity. #### For super-users -* `add_registrar` - Add a new registrar to the system. -* `kill_identity` - Forcibly remove the associated identity; the deposit is lost. +- `add_registrar` - Add a new registrar to the system. +- `kill_identity` - Forcibly remove the associated identity; the deposit is lost. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/indices/README.md b/substrate/frame/indices/README.md index 243392780db..ba4b9679a29 100644 --- a/substrate/frame/indices/README.md +++ b/substrate/frame/indices/README.md @@ -1,4 +1,4 @@ An index is a short form of an address. This module handles allocation of indices for a newly created accounts. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/insecure-randomness-collective-flip/README.md b/substrate/frame/insecure-randomness-collective-flip/README.md index ef02e4b5c84..4f02782fa65 100644 --- a/substrate/frame/insecure-randomness-collective-flip/README.md +++ b/substrate/frame/insecure-randomness-collective-flip/README.md @@ -1,25 +1,27 @@ # DO NOT USE IN PRODUCTION -The produced values do not fulfill the cryptographic requirements for random numbers. Should not be used for high-stake production use-cases. +The produced values do not fulfill the cryptographic requirements for random numbers. Should not be used for high-stake +production use-cases. # Randomness Module -The Randomness Collective Flip module provides a [`random`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html#method.random) -function that generates low-influence random values based on the block hashes from the previous -`81` blocks. Low-influence randomness can be useful when defending against relatively weak -adversaries. Using this pallet as a randomness source is advisable primarily in low-security -situations like testing. +The Randomness Collective Flip module provides a +[`random`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html#method.random) +function that generates low-influence random values based on the block hashes from the previous `81` blocks. +Low-influence randomness can be useful when defending against relatively weak adversaries. Using this pallet as a +randomness source is advisable primarily in low-security situations like testing. ## Public Functions -See the [`Module`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html) struct for details of publicly available functions. +See the +[`Module`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html) +struct for details of publicly available functions. ## Usage ### Prerequisites -Import the Randomness Collective Flip module and derive your module's configuration trait from -the system trait. +Import the Randomness Collective Flip module and derive your module's configuration trait from the system trait. ### Example - Get random seed for the current block diff --git a/substrate/frame/multisig/README.md b/substrate/frame/multisig/README.md index 5f320377d34..e9095198585 100644 --- a/substrate/frame/multisig/README.md +++ b/substrate/frame/multisig/README.md @@ -18,10 +18,10 @@ not available or desired. ### Dispatchable Functions -* `as_multi` - Approve and if possible dispatch a call from a composite origin formed from a +- `as_multi` - Approve and if possible dispatch a call from a composite origin formed from a number of signed origins. -* `approve_as_multi` - Approve a call from a composite origin. -* `cancel_as_multi` - Cancel a call from a composite origin. +- `approve_as_multi` - Approve a call from a composite origin. +- `cancel_as_multi` - Cancel a call from a composite origin. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/nft-fractionalization/README.md b/substrate/frame/nft-fractionalization/README.md index 180eef22cc4..3f83ae9d150 100644 --- a/substrate/frame/nft-fractionalization/README.md +++ b/substrate/frame/nft-fractionalization/README.md @@ -1,6 +1,8 @@ -### Lock NFT +# Lock NFT Lock an NFT from `pallet-nfts` and mint fungible assets from `pallet-assets`. -The NFT gets locked by putting a system-level attribute named `Locked`. This prevents the NFT from being transferred further. -The NFT becomes unlocked when the `Locked` attribute is removed. In order to unify the fungible asset and unlock the NFT, an account must hold the full issuance of the asset the NFT was fractionalised into. Holding less of the fungible asset will not allow the unlocking of the NFT. +The NFT gets locked by putting a system-level attribute named `Locked`. This prevents the NFT from being transferred +further. The NFT becomes unlocked when the `Locked` attribute is removed. In order to unify the fungible asset and +unlock the NFT, an account must hold the full issuance of the asset the NFT was fractionalised into. Holding less of the +fungible asset will not allow the unlocking of the NFT. diff --git a/substrate/frame/nfts/README.md b/substrate/frame/nfts/README.md index 7de4b9440e7..93ccf294985 100644 --- a/substrate/frame/nfts/README.md +++ b/substrate/frame/nfts/README.md @@ -13,9 +13,11 @@ The NFTs pallet provides functionality for non-fungible tokens' management, incl * Attributes Management * NFT Burning -To use it in your runtime, you need to implement [`nfts::Config`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/trait.Config.html). +To use it in your runtime, you need to implement +[`nfts::Config`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/trait.Config.html). -The supported dispatchable functions are documented in the [`nfts::Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum. +The supported dispatchable functions are documented in the +[`nfts::Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum. ### Terminology @@ -24,8 +26,9 @@ The supported dispatchable functions are documented in the [`nfts::Call`](https: * **NFT transfer:** The action of sending an item from one account to another. * **Atomic swap:** The action of exchanging items between accounts without needing a 3rd party service. * **NFT burning:** The destruction of an item. -* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly - one instance of such an item in existence and there is exactly one owning account (though that owning account could be a proxy account or multi-sig account). +* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly one instance of + such an item in existence and there is exactly one owning account (though that owning account could be a proxy account + or multi-sig account). * **Soul Bound NFT:** An item that is non-transferable from the account which it is minted into. ### Goals @@ -35,10 +38,8 @@ The NFTs pallet in Substrate is designed to make the following possible: * Allow accounts to permissionlessly create nft collections. * Allow a named (permissioned) account to mint and burn unique items within a collection. * Move items between accounts permissionlessly. -* Allow a named (permissioned) account to freeze and unfreeze items within a - collection or the entire collection. -* Allow the owner of an item to delegate the ability to transfer the item to some - named third-party. +* Allow a named (permissioned) account to freeze and unfreeze items within a collection or the entire collection. +* Allow the owner of an item to delegate the ability to transfer the item to some named third-party. * Allow third-parties to store information in an NFT _without_ owning it (Eg. save game state). ## Interface @@ -71,7 +72,8 @@ The NFTs pallet in Substrate is designed to make the following possible: * `clear_all_transfer_approvals`: Clears all transfer approvals set by calling the `approve_transfer`. * `lock_collection`: Prevent all items within a collection from being transferred (making them all `soul bound`). * `lock_item_properties`: Lock item's metadata or attributes. -* `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items will not be affected.) +* `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items + will not be affected.) * `set_team`: Alter the permissioned accounts of a collection. * `set_collection_max_supply`: Change the max supply of a collection. * `update_mint_settings`: Update the minting settings for collection. @@ -94,8 +96,8 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_collection_config`: Change collection's config. * `force_set_attribute`: Set an attribute. -Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum -and its associated variants for documentation on each function. +Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and +its associated variants for documentation on each function. ## Related Modules diff --git a/substrate/frame/nicks/README.md b/substrate/frame/nicks/README.md index 768043ffb9b..2b05f32d334 100644 --- a/substrate/frame/nicks/README.md +++ b/substrate/frame/nicks/README.md @@ -14,10 +14,10 @@ have not been designed to be economically secure. Do not use this pallet as-is i ### Dispatchable Functions -* `set_name` - Set the associated name of an account; a small deposit is reserved if not already +- `set_name` - Set the associated name of an account; a small deposit is reserved if not already taken. -* `clear_name` - Remove an account's associated name; the deposit is returned. -* `kill_name` - Forcibly remove the associated name; the deposit is lost. +- `clear_name` - Remove an account's associated name; the deposit is returned. +- `kill_name` - Forcibly remove the associated name; the deposit is lost. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/nis/README.md b/substrate/frame/nis/README.md index 0c3f0c383a1..032df7d0186 100644 --- a/substrate/frame/nis/README.md +++ b/substrate/frame/nis/README.md @@ -2,4 +2,4 @@ Provides a non-interactiove variant of staking. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/nomination-pools/runtime-api/README.md b/substrate/frame/nomination-pools/runtime-api/README.md index af90b31733b..499af052a73 100644 --- a/substrate/frame/nomination-pools/runtime-api/README.md +++ b/substrate/frame/nomination-pools/runtime-api/README.md @@ -1,3 +1,3 @@ Runtime API definition for nomination-pools pallet. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/offences/README.md b/substrate/frame/offences/README.md index 454c7effaf3..e7cf302fb8a 100644 --- a/substrate/frame/offences/README.md +++ b/substrate/frame/offences/README.md @@ -2,4 +2,4 @@ Tracks reported offences -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/offences/benchmarking/README.md b/substrate/frame/offences/benchmarking/README.md index cbfe91d73a6..95892a8f344 100644 --- a/substrate/frame/offences/benchmarking/README.md +++ b/substrate/frame/offences/benchmarking/README.md @@ -1,3 +1,3 @@ Offences pallet benchmarking. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/ranked-collective/README.md b/substrate/frame/ranked-collective/README.md index b5fe65ef349..e9624159d2f 100644 --- a/substrate/frame/ranked-collective/README.md +++ b/substrate/frame/ranked-collective/README.md @@ -1,4 +1,4 @@ -# Ranked collective system. +# Ranked collective system This is a membership pallet providing a `Tally` implementation ready for use with polling systems such as the Referenda pallet. Members each have a rank, with zero being the lowest. diff --git a/substrate/frame/recovery/README.md b/substrate/frame/recovery/README.md index 31416c65c46..7e2dd7a2361 100644 --- a/substrate/frame/recovery/README.md +++ b/substrate/frame/recovery/README.md @@ -16,11 +16,11 @@ friends are needed to give another account access to the recoverable account. The recovery process for each recoverable account can be configured by the account owner. They are able to choose: -* `friends` - The list of friends that the account owner trusts to protect the +- `friends` - The list of friends that the account owner trusts to protect the recovery process for their account. -* `threshold` - The number of friends that need to approve a recovery process for +- `threshold` - The number of friends that need to approve a recovery process for the account to be successfully recovered. -* `delay_period` - The minimum number of blocks after the beginning of the recovery +- `delay_period` - The minimum number of blocks after the beginning of the recovery process that need to pass before the account can be successfully recovered. There is a configurable deposit that all users need to pay to create a recovery @@ -84,20 +84,20 @@ It is important to note that this is a powerful pallet that can compromise the security of an account if used incorrectly. Some recommended practices for users of this pallet are: -* Configure a significant `delay_period` for your recovery process: As long as you +- Configure a significant `delay_period` for your recovery process: As long as you have access to your recoverable account, you need only check the blockchain once every `delay_period` blocks to ensure that no recovery attempt is successful against your account. Using off-chain notification systems can help with this, but ultimately, setting a large `delay_period` means that even the most skilled attacker will need to wait this long before they can access your account. -* Use a high threshold of approvals: Setting a value of 1 for the threshold means +- Use a high threshold of approvals: Setting a value of 1 for the threshold means that any of your friends would be able to recover your account. They would simply need to start a recovery process and approve their own process. Similarly, a threshold of 2 would mean that any 2 friends could work together to gain access to your account. The only way to prevent against these kinds of attacks is to choose a high threshold of approvals and select from a diverse friend group that would not be able to reasonably coordinate with one another. -* Reset your configuration over time: Since the entire deposit of creating a +- Reset your configuration over time: Since the entire deposit of creating a recovery configuration is returned to the user, the only cost of updating your recovery configuration is the transaction fees for the calls. Thus, it is strongly encouraged to regularly update your recovery configuration @@ -110,25 +110,25 @@ of this pallet are: #### For General Users -* `create_recovery` - Create a recovery configuration for your account and make it recoverable. -* `initiate_recovery` - Start the recovery process for a recoverable account. +- `create_recovery` - Create a recovery configuration for your account and make it recoverable. +- `initiate_recovery` - Start the recovery process for a recoverable account. #### For Friends of a Recoverable Account -* `vouch_recovery` - As a `friend` of a recoverable account, vouch for a recovery attempt on the account. +- `vouch_recovery` - As a `friend` of a recoverable account, vouch for a recovery attempt on the account. #### For a User Who Successfully Recovered an Account -* `claim_recovery` - Claim access to the account that you have successfully completed the recovery process for. -* `as_recovered` - Send a transaction as an account that you have recovered. See other functions below. +- `claim_recovery` - Claim access to the account that you have successfully completed the recovery process for. +- `as_recovered` - Send a transaction as an account that you have recovered. See other functions below. #### For the Recoverable Account -* `close_recovery` - Close an active recovery process for your account and reclaim the recovery deposit. -* `remove_recovery` - Remove the recovery configuration from the account, making it un-recoverable. +- `close_recovery` - Close an active recovery process for your account and reclaim the recovery deposit. +- `remove_recovery` - Remove the recovery configuration from the account, making it un-recoverable. #### For Super Users -* `set_recovered` - The ROOT origin is able to skip the recovery process and directly allow +- `set_recovered` - The ROOT origin is able to skip the recovery process and directly allow one account to access another. License: Apache-2.0 diff --git a/substrate/frame/remark/README.md b/substrate/frame/remark/README.md index f2341d6a0ea..5224f1b2882 100644 --- a/substrate/frame/remark/README.md +++ b/substrate/frame/remark/README.md @@ -1,6 +1,6 @@ # Remark Storage Pallet -Allows storing arbitrary data off chain. +Allows storing arbitrary data off chain. License: Apache-2.0 diff --git a/substrate/frame/root-offences/README.md b/substrate/frame/root-offences/README.md index c5821587218..b4e8381df2e 100644 --- a/substrate/frame/root-offences/README.md +++ b/substrate/frame/root-offences/README.md @@ -2,4 +2,4 @@ Pallet that allows the root to create an offence. -NOTE: This pallet should only be used for testing purposes. \ No newline at end of file +NOTE: This pallet should only be used for testing purposes. diff --git a/substrate/frame/root-testing/README.md b/substrate/frame/root-testing/README.md index 637430445a2..aa231e3ef20 100644 --- a/substrate/frame/root-testing/README.md +++ b/substrate/frame/root-testing/README.md @@ -2,4 +2,4 @@ Pallet that contains extrinsics that can be usefull in testing. -NOTE: This pallet should only be used for testing purposes and should not be used in production runtimes! \ No newline at end of file +NOTE: This pallet should only be used for testing purposes and should not be used in production runtimes! diff --git a/substrate/frame/salary/README.md b/substrate/frame/salary/README.md index 25c1be0e805..ec3882dd097 100644 --- a/substrate/frame/salary/README.md +++ b/substrate/frame/salary/README.md @@ -1,3 +1,3 @@ # Salary -Make periodic payment to members of a ranked collective according to rank. \ No newline at end of file +Make periodic payment to members of a ranked collective according to rank. diff --git a/substrate/frame/scheduler/README.md b/substrate/frame/scheduler/README.md index bdd2c2226c8..6aec2ddb0e4 100644 --- a/substrate/frame/scheduler/README.md +++ b/substrate/frame/scheduler/README.md @@ -23,12 +23,12 @@ then those filter will not be used when dispatching the schedule call. ### Dispatchable Functions -* `schedule` - schedule a dispatch, which may be periodic, to occur at a +- `schedule` - schedule a dispatch, which may be periodic, to occur at a specified block and with a specified priority. -* `cancel` - cancel a scheduled dispatch, specified by block number and +- `cancel` - cancel a scheduled dispatch, specified by block number and index. -* `schedule_named` - augments the `schedule` interface with an additional +- `schedule_named` - augments the `schedule` interface with an additional `Vec` parameter that can be used for identification. -* `cancel_named` - the named complement to the cancel function. +- `cancel_named` - the named complement to the cancel function. License: Apache 2.0 diff --git a/substrate/frame/session/README.md b/substrate/frame/session/README.md index 09132470d44..fa7c9b3f983 100644 --- a/substrate/frame/session/README.md +++ b/substrate/frame/session/README.md @@ -1,7 +1,7 @@ # Session Pallet -The Session module allows validators to manage their session keys, provides a function for changing -the session length, and handles session rotation. +The Session module allows validators to manage their session keys, provides a function for changing the session length, +and handles session rotation. - [`session::Trait`](https://docs.rs/pallet-session/latest/pallet_session/trait.Config.html) - [`Call`](https://docs.rs/pallet-session/latest/pallet_session/enum.Call.html) @@ -12,34 +12,31 @@ the session length, and handles session rotation. ### Terminology -- **Session:** A session is a period of time that has a constant set of validators. Validators can only join -or exit the validator set at a session change. It is measured in block numbers. The block where a session is -ended is determined by the `ShouldEndSession` trait. When the session is ending, a new validator set -can be chosen by `OnSessionEnding` implementations. -- **Session key:** A session key is actually several keys kept together that provide the various signing -functions required by network authorities/validators in pursuit of their duties. -- **Validator ID:** Every account has an associated validator ID. For some simple staking systems, this -may just be the same as the account ID. For staking systems using a stash/controller model, -the validator ID would be the stash account ID of the controller. -- **Session key configuration process:** Session keys are set using `set_keys` for use not in -the next session, but the session after next. They are stored in `NextKeys`, a mapping between -the caller's `ValidatorId` and the session keys provided. `set_keys` allows users to set their -session key prior to being selected as validator. -It is a public call since it uses `ensure_signed`, which checks that the origin is a signed account. -As such, the account ID of the origin stored in `NextKeys` may not necessarily be associated with -a block author or a validator. The session keys of accounts are removed once their account balance is zero. -- **Session length:** This pallet does not assume anything about the length of each session. -Rather, it relies on an implementation of `ShouldEndSession` to dictate a new session's start. -This pallet provides the `PeriodicSessions` struct for simple periodic sessions. -- **Session rotation configuration:** Configure as either a 'normal' (rewardable session where rewards are -applied) or 'exceptional' (slashable) session rotation. -- **Session rotation process:** At the beginning of each block, the `on_initialize` function -queries the provided implementation of `ShouldEndSession`. If the session is to end the newly -activated validator IDs and session keys are taken from storage and passed to the -`SessionHandler`. The validator set supplied by `SessionManager::new_session` and the corresponding session -keys, which may have been registered via `set_keys` during the previous session, are written -to storage where they will wait one session before being passed to the `SessionHandler` -themselves. +- **Session:** A session is a period of time that has a constant set of validators. Validators can only join or exit the +validator set at a session change. It is measured in block numbers. The block where a session is ended is determined by +the `ShouldEndSession` trait. When the session is ending, a new validator set can be chosen by `OnSessionEnding` +implementations. +- **Session key:** A session key is actually several keys kept together that provide the various signing functions +required by network authorities/validators in pursuit of their duties. +- **Validator ID:** Every account has an associated validator ID. For some simple staking systems, this may just be the +same as the account ID. For staking systems using a stash/controller model, the validator ID would be the stash account +ID of the controller. +- **Session key configuration process:** Session keys are set using `set_keys` for use not in the next session, but the +session after next. They are stored in `NextKeys`, a mapping between the caller's `ValidatorId` and the session keys +provided. `set_keys` allows users to set their session key prior to being selected as validator. It is a public call +since it uses `ensure_signed`, which checks that the origin is a signed account. As such, the account ID of the origin +stored in `NextKeys` may not necessarily be associated with a block author or a validator. The session keys of accounts +are removed once their account balance is zero. +- **Session length:** This pallet does not assume anything about the length of each session. Rather, it relies on an +implementation of `ShouldEndSession` to dictate a new session's start. This pallet provides the `PeriodicSessions` +struct for simple periodic sessions. +- **Session rotation configuration:** Configure as either a 'normal' (rewardable session where rewards are applied) or +'exceptional' (slashable) session rotation. +- **Session rotation process:** At the beginning of each block, the `on_initialize` function queries the provided +implementation of `ShouldEndSession`. If the session is to end the newly activated validator IDs and session keys are +taken from storage and passed to the `SessionHandler`. The validator set supplied by `SessionManager::new_session` and +the corresponding session keys, which may have been registered via `set_keys` during the previous session, are written +to storage where they will wait one session before being passed to the `SessionHandler` themselves. ### Goals @@ -57,8 +54,8 @@ The Session pallet is designed to make the following possible: ### Public Functions -- `rotate_session` - Change to the next session. Register the new authority set. Queue changes -for next session rotation. +- `rotate_session` - Change to the next session. Register the new authority set. Queue changes for next session +rotation. - `disable_index` - Disable a validator by index. - `disable` - Disable a validator by Validator ID @@ -66,7 +63,8 @@ for next session rotation. ### Example from the FRAME -The [Staking pallet](https://docs.rs/pallet-staking/latest/pallet_staking/) uses the Session pallet to get the validator set. +The [Staking pallet](https://docs.rs/pallet-staking/latest/pallet_staking/) uses the Session pallet to get the validator +set. ```rust use pallet_session as session; diff --git a/substrate/frame/session/benchmarking/README.md b/substrate/frame/session/benchmarking/README.md index d034a9ec732..e097f03f34a 100644 --- a/substrate/frame/session/benchmarking/README.md +++ b/substrate/frame/session/benchmarking/README.md @@ -1,3 +1,3 @@ Benchmarks for the Session Pallet. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/society/README.md b/substrate/frame/society/README.md index 80998618664..c091d6c97d4 100644 --- a/substrate/frame/society/README.md +++ b/substrate/frame/society/README.md @@ -11,16 +11,16 @@ and maintain a membership society. ### User Types At any point, a user in the society can be one of a: -* Bidder - A user who has submitted intention of joining the society. -* Candidate - A user who will be voted on to join the society. -* Suspended Candidate - A user who failed to win a vote. -* Member - A user who is a member of the society. -* Suspended Member - A member of the society who has accumulated too many strikes +- Bidder - A user who has submitted intention of joining the society. +- Candidate - A user who will be voted on to join the society. +- Suspended Candidate - A user who failed to win a vote. +- Member - A user who is a member of the society. +- Suspended Member - A member of the society who has accumulated too many strikes or failed their membership challenge. Of the non-suspended members, there is always a: -* Head - A member who is exempt from suspension. -* Defender - A member whose membership is under question and voted on again. +- Head - A member who is exempt from suspension. +- Defender - A member whose membership is under question and voted on again. Of the non-suspended members of the society, a random set of them are chosen as "skeptics". The mechanics of skeptics is explained in the @@ -201,28 +201,28 @@ future payouts slashed. #### For General Users -* `bid` - A user can make a bid to join the membership society by reserving a deposit. -* `unbid` - A user can withdraw their bid for entry, the deposit is returned. +- `bid` - A user can make a bid to join the membership society by reserving a deposit. +- `unbid` - A user can withdraw their bid for entry, the deposit is returned. #### For Members -* `vouch` - A member can place a bid on behalf of a user to join the membership society. -* `unvouch` - A member can revoke their vouch for a user. -* `vote` - A member can vote to approve or reject a candidate's request to join the society. -* `defender_vote` - A member can vote to approve or reject a defender's continued membership +- `vouch` - A member can place a bid on behalf of a user to join the membership society. +- `unvouch` - A member can revoke their vouch for a user. +- `vote` - A member can vote to approve or reject a candidate's request to join the society. +- `defender_vote` - A member can vote to approve or reject a defender's continued membership to the society. -* `payout` - A member can claim their first matured payment. -* `unfound` - Allow the founder to unfound the society when they are the only member. +- `payout` - A member can claim their first matured payment. +- `unfound` - Allow the founder to unfound the society when they are the only member. #### For Super Users -* `found` - The founder origin can initiate this society. Useful for bootstrapping the Society +- `found` - The founder origin can initiate this society. Useful for bootstrapping the Society pallet on an already running chain. -* `judge_suspended_member` - The suspension judgement origin is able to make +- `judge_suspended_member` - The suspension judgement origin is able to make judgement on a suspended member. -* `judge_suspended_candidate` - The suspension judgement origin is able to +- `judge_suspended_candidate` - The suspension judgement origin is able to make judgement on a suspended candidate. -* `set_max_membership` - The ROOT origin can update the maximum member count for the society. +- `set_max_membership` - The ROOT origin can update the maximum member count for the society. The max membership count must be greater than 1. License: Apache-2.0 diff --git a/substrate/frame/staking/README.md b/substrate/frame/staking/README.md index ccb9901a679..387b94b6a68 100644 --- a/substrate/frame/staking/README.md +++ b/substrate/frame/staking/README.md @@ -8,25 +8,24 @@ The Staking module is used to manage funds at stake by network maintainers. ## Overview -The Staking module is the means by which a set of network maintainers (known as _authorities_ in -some contexts and _validators_ in others) are chosen based upon those who voluntarily place -funds under deposit. Under deposit, those funds are rewarded under normal operation but are held -at pain of _slash_ (expropriation) should the staked maintainer be found not to be discharging -its duties properly. +The Staking module is the means by which a set of network maintainers (known as _authorities_ in some contexts and +_validators_ in others) are chosen based upon those who voluntarily place funds under deposit. Under deposit, those +funds are rewarded under normal operation but are held at pain of _slash_ (expropriation) should the staked maintainer +be found not to be discharging its duties properly. ### Terminology -- Staking: The process of locking up funds for some time, placing them at risk of slashing - (loss) in order to become a rewarded maintainer of the network. -- Validating: The process of running a node to actively maintain the network, either by - producing blocks or guaranteeing finality of the chain. -- Nominating: The process of placing staked funds behind one or more validators in order to - share in any reward, and punishment, they take. +- Staking: The process of locking up funds for some time, placing them at risk of slashing (loss) in order to become a + rewarded maintainer of the network. +- Validating: The process of running a node to actively maintain the network, either by producing blocks or guaranteeing + finality of the chain. +- Nominating: The process of placing staked funds behind one or more validators in order to share in any reward, and + punishment, they take. - Stash account: The account holding an owner's funds used for staking. - Controller account: The account that controls an owner's funds for staking. -- Era: A (whole) number of sessions, which is the period that the validator set (and each - validator's active nominator set) is recalculated and where rewards are paid out. +- Era: A (whole) number of sessions, which is the period that the validator set (and each validator's active nominator + set) is recalculated and where rewards are paid out. - Slash: The punishment of a staker by reducing its funds. ### Goals @@ -42,91 +41,90 @@ The staking system in Substrate NPoS is designed to make the following possible: #### Staking -Almost any interaction with the Staking module requires a process of _**bonding**_ (also known -as being a _staker_). To become *bonded*, a fund-holding account known as the _stash account_, -which holds some or all of the funds that become frozen in place as part of the staking process, -is paired with an active **controller** account, which issues instructions on how they shall be -used. +Almost any interaction with the Staking module requires a process of _**bonding**_ (also known as being a _staker_). To +become *bonded*, a fund-holding account known as the _stash account_, which holds some or all of the funds that become +frozen in place as part of the staking process, is paired with an active **controller** account, which issues +instructions on how they shall be used. -An account pair can become bonded using the [`bond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.bond) call. +An account pair can become bonded using the +[`bond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.bond) call. Stash accounts can update their associated controller back to their stash account using the -[`set_controller`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.set_controller) -call. +[`set_controller`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.set_controller) call. -Note: Controller accounts are being deprecated in favor of proxy accounts, so it is no longer -possible to set a unique address for a stash's controller. +Note: Controller accounts are being deprecated in favor of proxy accounts, so it is no longer possible to set a unique +address for a stash's controller. -There are three possible roles that any staked account pair can be in: `Validator`, `Nominator` -and `Idle` (defined in [`StakerStatus`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.StakerStatus.html)). There are three +There are three possible roles that any staked account pair can be in: `Validator`, `Nominator` and `Idle` (defined in +[`StakerStatus`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.StakerStatus.html)). There are three corresponding instructions to change between roles, namely: [`validate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.validate), -[`nominate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.nominate), and [`chill`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.chill). +[`nominate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.nominate), and +[`chill`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.chill). #### Validating -A **validator** takes the role of either validating blocks or ensuring their finality, -maintaining the veracity of the network. A validator should avoid both any sort of malicious -misbehavior and going offline. Bonded accounts that state interest in being a validator do NOT -get immediately chosen as a validator. Instead, they are declared as a _candidate_ and they -_might_ get elected at the _next era_ as a validator. The result of the election is determined -by nominators and their votes. +A **validator** takes the role of either validating blocks or ensuring their finality, maintaining the veracity of the +network. A validator should avoid both any sort of malicious misbehavior and going offline. Bonded accounts that state +interest in being a validator do NOT get immediately chosen as a validator. Instead, they are declared as a _candidate_ +and they _might_ get elected at the _next era_ as a validator. The result of the election is determined by nominators +and their votes. An account can become a validator candidate via the [`validate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.validate) call. #### 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 -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 -the misbehaving/offline validators as much as possible, simply because the nominators will also -lose funds if they vote poorly. +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 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 the +misbehaving/offline validators as much as possible, simply because the nominators will also lose funds if they vote +poorly. -An account can become a nominator via the [`nominate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.nominate) call. +An account can become a nominator via the +[`nominate`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.nominate) call. #### Rewards and Slash -The **reward and slashing** procedure is the core of the Staking module, attempting to _embrace -valid behavior_ while _punishing any misbehavior or lack of availability_. +The **reward and slashing** procedure is the core of the Staking module, attempting to _embrace valid behavior_ while +_punishing any misbehavior or lack of availability_. -Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the -`payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the -validator as well as its nominators. Only the [`Config::MaxNominatorRewardedPerValidator`] -biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each -nominator's account. +Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the `payout_stakers` call. Any +account can call `payout_stakers`, which pays the reward to the validator as well as its nominators. Only the +[`Config::MaxNominatorRewardedPerValidator`] biggest stakers can claim their reward. This is to limit the i/o cost to +mutate storage for each nominator's account. -Slashing can occur at any point in time, once misbehavior is reported. Once slashing is -determined, a value is deducted from the balance of the validator and all the nominators who -voted for this validator (values are deducted from the _stash_ account of the slashed entity). +Slashing can occur at any point in time, once misbehavior is reported. Once slashing is determined, a value is deducted +from the balance of the validator and all the nominators who voted for this validator (values are deducted from the +_stash_ account of the slashed entity). Slashing logic is further described in the documentation of the `slashing` module. -Similar to slashing, rewards are also shared among a validator and its associated nominators. -Yet, the reward funds are not always transferred to the stash account and can be configured. See -[Reward Calculation](https://docs.rs/pallet-staking/latest/pallet_staking/#reward-calculation) for more details. +Similar to slashing, rewards are also shared among a validator and its associated nominators. Yet, the reward funds are +not always transferred to the stash account and can be configured. See [Reward +Calculation](https://docs.rs/pallet-staking/latest/pallet_staking/#reward-calculation) for more details. #### Chilling -Finally, any of the roles above can choose to step back temporarily and just chill for a while. -This means that if they are a nominator, they will not be considered as voters anymore and if -they are validators, they will no longer be a candidate for the next election. +Finally, any of the roles above can choose to step back temporarily and just chill for a while. This means that if they +are a nominator, they will not be considered as voters anymore and if they are validators, they will no longer be a +candidate for the next election. -An account can step back via the [`chill`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.chill) call. +An account can step back via the +[`chill`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.chill) call. ### Session managing -The module implement the trait `SessionManager`. Which is the only API to query new validator -set and allowing these validator set to be rewarded once their era is ended. +The module implement the trait `SessionManager`. Which is the only API to query new validator set and allowing these +validator set to be rewarded once their era is ended. ## Interface ### Dispatchable Functions -The dispatchable functions of the Staking module enable the steps needed for entities to accept -and change their role, alongside some helper functions to get/set the metadata of the module. +The dispatchable functions of the Staking module enable the steps needed for entities to accept and change their role, +alongside some helper functions to get/set the metadata of the module. ### Public Functions @@ -134,7 +132,7 @@ The Staking module contains many public storage items and (im)mutable functions. ## Usage -### Example: Rewarding a validator by id. +### Example: Rewarding a validator by id ```rust use pallet_staking::{self as staking}; @@ -169,7 +167,8 @@ pub mod pallet { ### Era payout The era payout is computed using yearly inflation curve defined at -[`T::RewardCurve`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.RewardCurve) as such: +[`T::RewardCurve`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.RewardCurve) as +such: ```nocompile staker_payout = yearly_inflation(npos_token_staked / total_tokens) * total_tokens / era_per_year @@ -184,37 +183,38 @@ The remaining reward is send to the configurable end-point ### Reward Calculation -Validators and nominators are rewarded at the end of each era. The total reward of an era is -calculated using the era duration and the staking rate (the total amount of tokens staked by -nominators and validators, divided by the total token supply). It aims to incentivize toward a -defined staking rate. The full specification can be found +Validators and nominators are rewarded at the end of each era. The total reward of an era is calculated using the era +duration and the staking rate (the total amount of tokens staked by nominators and validators, divided by the total +token supply). It aims to incentivize toward a defined staking rate. The full specification can be found [here](https://research.web3.foundation/en/latest/polkadot/economics/1-token-economics.html#inflation-model). -Total reward is split among validators and their nominators depending on the number of points -they received during the era. Points are added to a validator using +Total reward is split among validators and their nominators depending on the number of points they received during the +era. Points are added to a validator using [`reward_by_ids`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.reward_by_ids) or [`reward_by_indices`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.reward_by_indices). [`Module`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Module.html) implements -[`pallet_authorship::EventHandler`](https://docs.rs/pallet-authorship/latest/pallet_authorship/trait.EventHandler.html) to add reward -points to block producer and block producer of referenced uncles. +[`pallet_authorship::EventHandler`](https://docs.rs/pallet-authorship/latest/pallet_authorship/trait.EventHandler.html) +to add reward points to block producer and block producer of referenced uncles. The validator and its nominator split their reward as following: The validator can declare an amount, named -[`commission`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.ValidatorPrefs.html#structfield.commission), that does not get shared -with the nominators at each reward payout through its -[`ValidatorPrefs`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.ValidatorPrefs.html). This value gets deducted from the total reward -that is paid to the validator and its nominators. The remaining portion is split among the -validator and all of the nominators that nominated the validator, proportional to the value -staked behind this validator (_i.e._ dividing the +[`commission`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.ValidatorPrefs.html#structfield.commission), +that does not get shared with the nominators at each reward payout through its +[`ValidatorPrefs`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.ValidatorPrefs.html). This value gets +deducted from the total reward that is paid to the validator and its nominators. The remaining portion is split among +the validator and all of the nominators that nominated the validator, proportional to the value staked behind this +validator (_i.e._ dividing the [`own`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html#structfield.own) or [`others`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html#structfield.others) by -[`total`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html#structfield.total) in [`Exposure`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html)). +[`total`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html#structfield.total) in +[`Exposure`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Exposure.html)). All entities who receive a reward have the option to choose their reward destination through the [`Payee`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.Payee.html) storage item (see -[`set_payee`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.set_payee)), to be one of the following: +[`set_payee`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.set_payee)), to be one of the +following: - Controller account, (obviously) not increasing the staked value. - Stash account, not increasing the staked value. @@ -225,32 +225,33 @@ All entities who receive a reward have the option to choose their reward destina Any funds already placed into stash can be the target of the following operations: The controller account can free a portion (or all) of the funds using the -[`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond) call. Note that the funds are not immediately -accessible. Instead, a duration denoted by [`BondingDuration`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.BondingDuration) -(in number of eras) must pass until the funds can actually be removed. Once the -`BondingDuration` is over, the [`withdraw_unbonded`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.withdraw_unbonded) +[`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond) call. Note that the funds +are not immediately accessible. Instead, a duration denoted by +[`BondingDuration`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.BondingDuration) +(in number of eras) must pass until the funds can actually be removed. Once the `BondingDuration` is over, the +[`withdraw_unbonded`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.withdraw_unbonded) call can be used to actually withdraw the funds. -Note that there is a limitation to the number of fund-chunks that can be scheduled to be -unlocked in the future via [`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond). In case this maximum -(`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful -call to `withdraw_unbonded` to remove some of the chunks. +Note that there is a limitation to the number of fund-chunks that can be scheduled to be unlocked in the future via +[`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond). In case this maximum +(`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful call to `withdraw_unbonded` +to remove some of the chunks. ### Election Algorithm -The current election algorithm is implemented based on Phragmén. The reference implementation -can be found [here](https://github.com/w3f/consensus/tree/master/NPoS). +The current election algorithm is implemented based on Phragmén. The reference implementation can be found +[here](https://github.com/w3f/consensus/tree/master/NPoS). -The election algorithm, aside from electing the validators with the most stake value and votes, -tries to divide the nominator votes among candidates in an equal manner. To further assure this, -an optional post-processing can be applied that iteratively normalizes the nominator staked -values until the total difference among votes of a particular nominator are less than a -threshold. +The election algorithm, aside from electing the validators with the most stake value and votes, tries to divide the +nominator votes among candidates in an equal manner. To further assure this, an optional post-processing can be applied +that iteratively normalizes the nominator staked values until the total difference among votes of a particular nominator +are less than a threshold. ## GenesisConfig -The Staking module depends on the [`GenesisConfig`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.GenesisConfig.html). The -`GenesisConfig` is optional and allow to set some initial stakers. +The Staking module depends on the +[`GenesisConfig`](https://docs.rs/pallet-staking/latest/pallet_staking/struct.GenesisConfig.html). The `GenesisConfig` +is optional and allow to set some initial stakers. ## Related Modules diff --git a/substrate/frame/sudo/README.md b/substrate/frame/sudo/README.md index 886dc598177..371f89e5348 100644 --- a/substrate/frame/sudo/README.md +++ b/substrate/frame/sudo/README.md @@ -16,8 +16,8 @@ Only one account can be the sudo key at a time. Only the sudo key can call the dispatchable functions from the Sudo module. -* `sudo` - Make a `Root` call to a dispatchable function. -* `set_key` - Assign a new account to be the sudo key. +- `sudo` - Make a `Root` call to a dispatchable function. +- `set_key` - Assign a new account to be the sudo key. ## Usage @@ -68,7 +68,7 @@ You need to set an initial superuser account as the sudo `key`. ## Related Modules -* [Democracy](https://docs.rs/pallet-democracy/latest/pallet_democracy/) +- [Democracy](https://docs.rs/pallet-democracy/latest/pallet_democracy/) [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/support/README.md b/substrate/frame/support/README.md index 2282870aca0..dd2a07346dd 100644 --- a/substrate/frame/support/README.md +++ b/substrate/frame/support/README.md @@ -1,3 +1,3 @@ Support code for the runtime. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 88aad32225a..1898246470c 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -1386,7 +1386,7 @@ fn metadata() { } } - let readme = "Support code for the runtime.\n\nLicense: Apache-2.0"; + let readme = "Support code for the runtime.\n\nLicense: Apache-2.0\n"; let expected_pallet_doc = vec![" Pallet documentation", readme, readme]; let pallets = vec![ @@ -1889,7 +1889,7 @@ fn metadata_ir_pallet_runtime_docs() { .find(|pallet| pallet.name == "Example") .expect("Pallet should be present"); - let readme = "Support code for the runtime.\n\nLicense: Apache-2.0"; + let readme = "Support code for the runtime.\n\nLicense: Apache-2.0\n"; let expected = vec![" Pallet documentation", readme, readme]; assert_eq!(pallet.docs, expected); } @@ -1919,7 +1919,7 @@ fn extrinsic_metadata_ir_types() { #[test] fn test_pallet_runtime_docs() { let docs = crate::pallet::Pallet::::pallet_documentation_metadata(); - let readme = "Support code for the runtime.\n\nLicense: Apache-2.0"; + let readme = "Support code for the runtime.\n\nLicense: Apache-2.0\n"; let expected = vec![" Pallet documentation", readme, readme]; assert_eq!(docs, expected); } diff --git a/substrate/frame/system/README.md b/substrate/frame/system/README.md index 30b2ea73720..c15281d365b 100644 --- a/substrate/frame/system/README.md +++ b/substrate/frame/system/README.md @@ -1,20 +1,20 @@ # System Module -The System module provides low-level access to core types and cross-cutting utilities. -It acts as the base layer for other pallets to interact with the Substrate framework components. +The System module provides low-level access to core types and cross-cutting utilities. It acts as the base layer for +other pallets to interact with the Substrate framework components. - [`system::Config`](https://docs.rs/frame-system/latest/frame_system/pallet/trait.Config.html) ## Overview -The System module defines the core data types used in a Substrate runtime. -It also provides several utility functions (see [`Pallet`](https://docs.rs/frame-system/latest/frame_system/pallet/struct.Pallet.html)) for other FRAME pallets. +The System module defines the core data types used in a Substrate runtime. It also provides several utility functions +(see [`Pallet`](https://docs.rs/frame-system/latest/frame_system/pallet/struct.Pallet.html)) for other FRAME pallets. -In addition, it manages the storage items for extrinsics data, indexes, event records, and digest items, -among other things that support the execution of the current block. +In addition, it manages the storage items for extrinsics data, indexes, event records, and digest items, among other +things that support the execution of the current block. -It also handles low-level tasks like depositing logs, basic set up and take down of -temporary storage entries, and access to previous block hashes. +It also handles low-level tasks like depositing logs, basic set up and take down of temporary storage entries, and +access to previous block hashes. ## Interface @@ -24,26 +24,22 @@ The System module does not implement any dispatchable functions. ### Public Functions -See the [`Pallet`](https://docs.rs/frame-system/latest/frame_system/pallet/struct.Pallet.html) struct for details of publicly available functions. +See the [`Pallet`](https://docs.rs/frame-system/latest/frame_system/pallet/struct.Pallet.html) struct for details of +publicly available functions. ### Signed Extensions The System module defines the following extensions: - - [`CheckWeight`]: Checks the weight and length of the block and ensure that it does not - exceed the limits. - - [`CheckNonce`]: Checks the nonce of the transaction. Contains a single payload of type - `T::Nonce`. + - [`CheckWeight`]: Checks the weight and length of the block and ensure that it does not exceed the limits. + - [`CheckNonce`]: Checks the nonce of the transaction. Contains a single payload of type `T::Nonce`. - [`CheckEra`]: Checks the era of the transaction. Contains a single payload of type `Era`. - - [`CheckGenesis`]: Checks the provided genesis hash of the transaction. Must be a part of the - signed payload of the transaction. - - [`CheckSpecVersion`]: Checks that the runtime version is the same as the one used to sign the - transaction. - - [`CheckTxVersion`]: Checks that the transaction version is the same as the one used to sign the + - [`CheckGenesis`]: Checks the provided genesis hash of the transaction. Must be a part of the signed payload of the transaction. + - [`CheckSpecVersion`]: Checks that the runtime version is the same as the one used to sign the transaction. + - [`CheckTxVersion`]: Checks that the transaction version is the same as the one used to sign the transaction. -Lookup the runtime aggregator file (e.g. `node/runtime`) to see the full list of signed -extensions included in a chain. +Lookup the runtime aggregator file (e.g. `node/runtime`) to see the full list of signed extensions included in a chain. ## Usage diff --git a/substrate/frame/system/benchmarking/README.md b/substrate/frame/system/benchmarking/README.md index 9718db58b37..811207fd8c0 100644 --- a/substrate/frame/system/benchmarking/README.md +++ b/substrate/frame/system/benchmarking/README.md @@ -1 +1 @@ -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/system/benchmarking/res/README.md b/substrate/frame/system/benchmarking/res/README.md index 43bb2b5c283..6eca9229531 100644 --- a/substrate/frame/system/benchmarking/res/README.md +++ b/substrate/frame/system/benchmarking/res/README.md @@ -2,4 +2,5 @@ These runtimes are used for benchmarking the `set_code` intrinsic. **Don't use them in production environments!** -To update the just copy the new runtime from `target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm` to here. +To update the just copy the new runtime from +`target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm` to here. diff --git a/substrate/frame/system/rpc/runtime-api/README.md b/substrate/frame/system/rpc/runtime-api/README.md index ab46c22a8be..d418cad5a34 100644 --- a/substrate/frame/system/rpc/runtime-api/README.md +++ b/substrate/frame/system/rpc/runtime-api/README.md @@ -4,4 +4,4 @@ This API should be imported and implemented by the runtime, of a node that wants to use the custom RPC extension adding System access methods. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/frame/timestamp/README.md b/substrate/frame/timestamp/README.md index 1546377ee67..69dba60550e 100644 --- a/substrate/frame/timestamp/README.md +++ b/substrate/frame/timestamp/README.md @@ -22,16 +22,16 @@ because of cumulative calculation errors and hence should be avoided. ### Dispatchable Functions -* `set` - Sets the current time. +- `set` - Sets the current time. ### Public functions -* `get` - Gets the current time for the current block. If this function is called prior to +- `get` - Gets the current time for the current block. If this function is called prior to setting the timestamp, it will return the timestamp of the previous block. ### Config Getters -* `MinimumPeriod` - Gets the minimum (and advised) period between blocks for the chain. +- `MinimumPeriod` - Gets the minimum (and advised) period between blocks for the chain. ## Usage @@ -78,6 +78,6 @@ the Timestamp module for session management. ## Related Modules -* [Session](https://docs.rs/pallet-session/latest/pallet_session/) +- [Session](https://docs.rs/pallet-session/latest/pallet_session/) License: Apache-2.0 diff --git a/substrate/frame/tips/README.md b/substrate/frame/tips/README.md index d885ce770f7..1960172c497 100644 --- a/substrate/frame/tips/README.md +++ b/substrate/frame/tips/README.md @@ -11,7 +11,7 @@ entered where any remaining members can declare their tip amounts also. After th countdown period, the median of all declared tips is paid to the reported beneficiary, along with any finders fee, in case of a public (and bonded) original report. -### Terminology +## Terminology - **Tipping:** The process of gathering declarations of amounts to tip and taking the median amount to be transferred from the treasury to a beneficiary account. @@ -30,4 +30,4 @@ any finders fee, in case of a public (and bonded) original report. - `tip_new` - Report an item worthy of a tip and declare a specific amount to tip. - `tip` - Declare or redeclare an amount to tip for a particular reason. - `close_tip` - Close and pay out a tip. -- `slash_tip` - Remove and slash an already-open tip. \ No newline at end of file +- `slash_tip` - Remove and slash an already-open tip. diff --git a/substrate/frame/transaction-storage/README.md b/substrate/frame/transaction-storage/README.md index 0ed3ba279c2..1066968469d 100644 --- a/substrate/frame/transaction-storage/README.md +++ b/substrate/frame/transaction-storage/README.md @@ -2,8 +2,9 @@ Indexes transactions and manages storage proofs. -Allows storing arbitrary data on the chain. Data is automatically removed after `StoragePeriod` blocks, unless the storage is renewed. -Validators must submit proof of storing a random chunk of data for block `N - StoragePeriod` when producing block `N`. +Allows storing arbitrary data on the chain. Data is automatically removed after `StoragePeriod` blocks, unless the +storage is renewed. Validators must submit proof of storing a random chunk of data for block `N - StoragePeriod` when +producing block `N`. # Running a chain @@ -15,8 +16,9 @@ Start with generating a chain spec. cargo run --release -- build-spec --chain=local > sc_init.json ``` -Edit the json chain spec file to customise the chain. The storage chain genesis params are configured in the `transactionStorage` section. -Note that `storagePeriod` is specified in blocks and changing it also requires code changes at the moment. +Edit the json chain spec file to customise the chain. The storage chain genesis params are configured in the +`transactionStorage` section. Note that `storagePeriod` is specified in blocks and changing it also requires code +changes at the moment. Build a raw spec from the init spec. @@ -31,11 +33,11 @@ cargo run --release -- --chain=sc.json -d /tmp/alice --storage-chain --keep-bloc cargo run --release -- --chain=sc.json -d /tmp/bob --storage-chain --keep-blocks=100800 --ipfs-server --validator --bob ``` -`--storage-chain` enables transaction indexing. -`--keep-blocks=100800` enables block pruning. The value here should be greater or equal than the storage period. -`--ipfs-server` enables serving stored content over IPFS. +`--storage-chain` enables transaction indexing. `--keep-blocks=100800` enables block pruning. The value here should be +greater or equal than the storage period. `--ipfs-server` enables serving stored content over IPFS. -Once the network is started, any other joining nodes need to sync with `--sync=fast`. Regular sync will fail because block pruning removes old blocks. The chain does not keep full block history. +Once the network is started, any other joining nodes need to sync with `--sync=fast`. Regular sync will fail because +block pruning removes old blocks. The chain does not keep full block history. ```bash cargo run --release -- --chain=sc.json -d /tmp/charlie --storage-chain --keep-blocks=100800 --ipfs-server --validator --charlie --sync=fast @@ -43,7 +45,8 @@ cargo run --release -- --chain=sc.json -d /tmp/charlie --storage-chain --keep-bl # Making transactions -To store data use the `transactionStorage.store` extrinsic. And IPFS CID can be generated from the Blake2-256 hash of the data. +To store data use the `transactionStorage.store` extrinsic. And IPFS CID can be generated from the Blake2-256 hash of +the data. ```js const util_crypto = require('@polkadot/util-crypto'); @@ -76,7 +79,8 @@ ipfs block get /ipfs/ > kitten.jpeg ``` To renew data and prevent it from being disposed after the storage period, use `transactionStorage.renew(block, index)` -where `block` is the block number of the previous store or renew transction, and index is the index of that transaction in the block. +where `block` is the block number of the previous store or renew transction, and index is the index of that transaction +in the block. License: Apache-2.0 diff --git a/substrate/frame/uniques/README.md b/substrate/frame/uniques/README.md index 6cdbcf79f1c..538fd9e70a2 100644 --- a/substrate/frame/uniques/README.md +++ b/substrate/frame/uniques/README.md @@ -13,9 +13,11 @@ The Uniques module provides functionality for non-fungible tokens' management, i * Attributes Management * Item Burning -To use it in your runtime, you need to implement [`uniques::Config`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/trait.Config.html). +To use it in your runtime, you need to implement +[`uniques::Config`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/trait.Config.html). -The supported dispatchable functions are documented in the [`uniques::Call`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/enum.Call.html) enum. +The supported dispatchable functions are documented in the +[`uniques::Call`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/enum.Call.html) enum. ### Terminology @@ -23,8 +25,8 @@ The supported dispatchable functions are documented in the [`uniques::Call`](htt * **Item minting:** The action of creating a new item within a collection. * **Item transfer:** The action of sending an item from one account to another. * **Item burning:** The destruction of an item. -* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly - one instance of such an item in existence and there is exactly one owning account. +* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly one instance of + such an item in existence and there is exactly one owning account. ### Goals @@ -33,10 +35,8 @@ The Uniques pallet in Substrate is designed to make the following possible: * Allow accounts to permissionlessly create NFT collections. * Allow a named (permissioned) account to mint and burn unique items within a collection. * Move items between accounts permissionlessly. -* Allow a named (permissioned) account to freeze and unfreeze unique items within a - collection or the entire collection. -* Allow the owner of an item to delegate the ability to transfer the item to some - named third-party. +* Allow a named (permissioned) account to freeze and unfreeze unique items within a collection or the entire collection. +* Allow the owner of an item to delegate the ability to transfer the item to some named third-party. ## Interface diff --git a/substrate/frame/utility/README.md b/substrate/frame/utility/README.md index db19b0cf8cf..00fff76cd62 100644 --- a/substrate/frame/utility/README.md +++ b/substrate/frame/utility/README.md @@ -27,10 +27,10 @@ filtered by any proxy. ### Dispatchable Functions #### For batch dispatch -* `batch` - Dispatch multiple calls from the sender's origin. +- `batch` - Dispatch multiple calls from the sender's origin. #### For pseudonymal dispatch -* `as_derivative` - Dispatch a call from a derivative signed origin. +- `as_derivative` - Dispatch a call from a derivative signed origin. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/primitives/api/README.md b/substrate/primitives/api/README.md index 1cf9437373c..ee0e402f9d7 100644 --- a/substrate/primitives/api/README.md +++ b/substrate/primitives/api/README.md @@ -14,4 +14,4 @@ api, the [`ApiExt`] trait, the [`CallApiAt`] trait and the [`ConstructRuntimeApi On a meta level this implies, the client calls the generated API from the client perspective. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/application-crypto/README.md b/substrate/primitives/application-crypto/README.md index c86e33552f6..a686b746581 100644 --- a/substrate/primitives/application-crypto/README.md +++ b/substrate/primitives/application-crypto/README.md @@ -1,3 +1,3 @@ Traits and macros for constructing application specific strongly typed crypto wrappers. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/arithmetic/README.md b/substrate/primitives/arithmetic/README.md index e6e52c2a826..b5dcfdb2944 100644 --- a/substrate/primitives/arithmetic/README.md +++ b/substrate/primitives/arithmetic/README.md @@ -1,3 +1,3 @@ Minimal fixed point arithmetic primitives and types for runtime. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/authority-discovery/README.md b/substrate/primitives/authority-discovery/README.md index 65c2e22dde0..3b48ddc61c5 100644 --- a/substrate/primitives/authority-discovery/README.md +++ b/substrate/primitives/authority-discovery/README.md @@ -1,3 +1,3 @@ Runtime Api to help discover authorities. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/block-builder/README.md b/substrate/primitives/block-builder/README.md index 433197d3be9..952c94798d3 100644 --- a/substrate/primitives/block-builder/README.md +++ b/substrate/primitives/block-builder/README.md @@ -1,3 +1,3 @@ The block builder runtime api. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/blockchain/README.md b/substrate/primitives/blockchain/README.md index 8298bfd7ae6..a0a5b2edce5 100644 --- a/substrate/primitives/blockchain/README.md +++ b/substrate/primitives/blockchain/README.md @@ -1,3 +1,3 @@ Substrate blockchain traits and primitives. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/aura/README.md b/substrate/primitives/consensus/aura/README.md index 0f360ae67eb..725c6fc6db4 100644 --- a/substrate/primitives/consensus/aura/README.md +++ b/substrate/primitives/consensus/aura/README.md @@ -1,3 +1,3 @@ Primitives for Aura. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/babe/README.md b/substrate/primitives/consensus/babe/README.md index 54bae05fd6d..59f8d925af7 100644 --- a/substrate/primitives/consensus/babe/README.md +++ b/substrate/primitives/consensus/babe/README.md @@ -1,3 +1,3 @@ Primitives for BABE. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/common/README.md b/substrate/primitives/consensus/common/README.md index 963bb0fbdba..f61a00c42c8 100644 --- a/substrate/primitives/consensus/common/README.md +++ b/substrate/primitives/consensus/common/README.md @@ -1,7 +1,7 @@ -Common utilities for building and using consensus engines in substrate. +Common utilities for building and using consensus engines in Substrate. Much of this crate is _unstable_ and thus the API is likely to undergo change. Implementors of traits should not rely on the interfaces to remain the same. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/grandpa/README.md b/substrate/primitives/consensus/grandpa/README.md index 77a7abca2ee..d357904cd1f 100644 --- a/substrate/primitives/consensus/grandpa/README.md +++ b/substrate/primitives/consensus/grandpa/README.md @@ -1,3 +1,3 @@ Primitives for GRANDPA integration, suitable for WASM compilation. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/pow/README.md b/substrate/primitives/consensus/pow/README.md index 88186437764..390190c5d18 100644 --- a/substrate/primitives/consensus/pow/README.md +++ b/substrate/primitives/consensus/pow/README.md @@ -1,3 +1,3 @@ Primitives for Substrate Proof-of-Work (PoW) consensus. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/consensus/slots/README.md b/substrate/primitives/consensus/slots/README.md index f451c32888a..3052131721a 100644 --- a/substrate/primitives/consensus/slots/README.md +++ b/substrate/primitives/consensus/slots/README.md @@ -1,3 +1,3 @@ Primitives for slots-based consensus engines. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/database/README.md b/substrate/primitives/database/README.md index cd0677eb9eb..26f58ea8d45 100644 --- a/substrate/primitives/database/README.md +++ b/substrate/primitives/database/README.md @@ -1,3 +1,3 @@ The main database trait, allowing Substrate to store data persistently. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/externalities/README.md b/substrate/primitives/externalities/README.md index 3141b2609e6..543b63ecbdb 100644 --- a/substrate/primitives/externalities/README.md +++ b/substrate/primitives/externalities/README.md @@ -6,4 +6,4 @@ access the node from the runtime via the runtime interfaces. This crate exposes the main [`Externalities`] trait. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/inherents/README.md b/substrate/primitives/inherents/README.md index 78aa625fe85..20ceb529469 100644 --- a/substrate/primitives/inherents/README.md +++ b/substrate/primitives/inherents/README.md @@ -14,4 +14,4 @@ A module can also just check given inherents. For using a module as inherent pro to be registered by the `construct_runtime!` macro. The macro documentation gives more information on how that is done. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/io/README.md b/substrate/primitives/io/README.md index a24370cc566..5e252eeacb0 100644 --- a/substrate/primitives/io/README.md +++ b/substrate/primitives/io/README.md @@ -1,3 +1,3 @@ -I/O host interface for substrate runtime. +I/O host interface for Substrate runtime. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/keyring/README.md b/substrate/primitives/keyring/README.md index 1610f237df9..555a35f09bc 100644 --- a/substrate/primitives/keyring/README.md +++ b/substrate/primitives/keyring/README.md @@ -1,3 +1,3 @@ Support code for the runtime. A set of test accounts. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/npos-elections/README.md b/substrate/primitives/npos-elections/README.md index 6881fc6418f..e65f22ca271 100644 --- a/substrate/primitives/npos-elections/README.md +++ b/substrate/primitives/npos-elections/README.md @@ -1,30 +1,29 @@ -A set of election algorithms to be used with a substrate runtime, typically within the staking -sub-system. Notable implementation include: +# sp-npos-elections -- [`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`]: 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_solution`]: Implements the star balancing algorithm. This iterative process can push - a solution toward being more `balanced`, which in turn can increase its score. +A set of election algorithms to be used with a Substrate runtime, typically within the staking sub-system. Notable +implementation include: -### Terminology +- [`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`]: 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_solution`]: Implements the star balancing algorithm. This iterative process can push a solution toward being + more `balanced`, which in turn can increase its score. -This crate uses context-independent words, not to be confused with staking. This is because the -election algorithms of this crate, while designed for staking, can be used in other contexts as -well. +## Terminology -`Voter`: The entity casting some votes to a number of `Targets`. This is the same as `Nominator` -in the context of staking. `Target`: The entities eligible to be voted upon. This is the same as -`Validator` in the context of staking. `Edge`: A mapping from a `Voter` to a `Target`. +This crate uses context-independent words, not to be confused with staking. This is because the election algorithms of +this crate, while designed for staking, can be used in other contexts as well. + +`Voter`: The entity casting some votes to a number of `Targets`. This is the same as `Nominator` in the context of +staking. `Target`: The entities eligible to be voted upon. This is the same as `Validator` in the context of staking. +`Edge`: A mapping from a `Voter` to a `Target`. The goal of an election algorithm is to provide an `ElectionResult`. A data composed of: -- `winners`: A flat list of identifiers belonging to those who have won the election, usually - ordered in some meaningful way. They are zipped with their total backing stake. -- `assignment`: A mapping from each voter to their winner-only targets, zipped with a ration - denoting the amount of support given to that particular target. +- `winners`: A flat list of identifiers belonging to those who have won the election, usually ordered in some meaningful + way. They are zipped with their total backing stake. +- `assignment`: A mapping from each voter to their winner-only targets, zipped with a ration denoting the amount of + support given to that particular target. ```rust // the winners. @@ -44,16 +43,14 @@ let election_result = ElectionResult { winners, assignments }; ``` -The `Assignment` field of the election result is voter-major, i.e. it is from the perspective of -the voter. The struct that represents the opposite is called a `Support`. This struct is usually -accessed in a map-like manner, i.e. keyed by voters, therefore it is stored as a mapping called -`SupportMap`. +The `Assignment` field of the election result is voter-major, i.e. it is from the perspective of the voter. The struct +that represents the opposite is called a `Support`. This struct is usually accessed in a map-like manner, i.e. keyed by +voters, therefore it is stored as a mapping called `SupportMap`. -Moreover, the support is built from absolute backing values, not ratios like the example above. -A struct similar to `Assignment` that has stake value instead of ratios is called an -`StakedAssignment`. +Moreover, the support is built from absolute backing values, not ratios like the example above. A struct similar to +`Assignment` that has stake value instead of ratios is called an `StakedAssignment`. More information can be found at: https://arxiv.org/abs/2004.12990 -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/offchain/README.md b/substrate/primitives/offchain/README.md index a8620d3bb9d..5c239d2e0e7 100644 --- a/substrate/primitives/offchain/README.md +++ b/substrate/primitives/offchain/README.md @@ -1,3 +1,3 @@ The Offchain Worker runtime api primitives. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/panic-handler/README.md b/substrate/primitives/panic-handler/README.md index c08396960f4..f4f974ea6e1 100644 --- a/substrate/primitives/panic-handler/README.md +++ b/substrate/primitives/panic-handler/README.md @@ -7,4 +7,4 @@ given URL. By default, the panic handler aborts the process by calling [`std::process::exit`]. This can temporarily be disabled by using an [`AbortGuard`]. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/rpc/README.md b/substrate/primitives/rpc/README.md index 8a9c17edd47..4d48fc56aed 100644 --- a/substrate/primitives/rpc/README.md +++ b/substrate/primitives/rpc/README.md @@ -1,3 +1,3 @@ Substrate RPC primitives and utilities. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/runtime-interface/README.md b/substrate/primitives/runtime-interface/README.md index 49e13f1b2e7..f6dfea945dd 100644 --- a/substrate/primitives/runtime-interface/README.md +++ b/substrate/primitives/runtime-interface/README.md @@ -1,43 +1,42 @@ Substrate runtime interface -This crate provides types, traits and macros around runtime interfaces. A runtime interface is -a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the -interface maps to a direct function call of the implementation. For a wasm runtime the interface -maps to an external function call. These external functions are exported by the wasm executor -and they map to the same implementation as the native calls. +This crate provides types, traits and macros around runtime interfaces. A runtime interface is a fixed interface between +a Substrate runtime and a Substrate node. For a native runtime the interface maps to a direct function call of the +implementation. For a wasm runtime the interface maps to an external function call. These external functions are +exported by the wasm executor and they map to the same implementation as the native calls. # Using a type in a runtime interface -Any type that should be used in a runtime interface as argument or return value needs to -implement [`RIType`]. The associated type [`FFIType`](https:/docs.rs/sp-runtime-interface/latest/sp_runtime_interface/trait.RIType.html#associatedtype.FFIType) -is the type that is used in the FFI function to represent the actual type. For example `[T]` is -represented by an `u64`. The slice pointer and the length will be mapped to an `u64` value. -For more information see this [table](https:/docs.rs/sp-runtime-interface/latest/sp_runtime_interface/#ffi-type-and-conversion). -The FFI function definition is used when calling from the wasm runtime into the node. +Any type that should be used in a runtime interface as argument or return value needs to implement [`RIType`]. The +associated type +[`FFIType`](https:/docs.rs/sp-runtime-interface/latest/sp_runtime_interface/trait.RIType.html#associatedtype.FFIType) is +the type that is used in the FFI function to represent the actual type. For example `[T]` is represented by an `u64`. +The slice pointer and the length will be mapped to an `u64` value. For more information see this +[table](https:/docs.rs/sp-runtime-interface/latest/sp_runtime_interface/#ffi-type-and-conversion). The FFI function +definition is used when calling from the wasm runtime into the node. Traits are used to convert from a type to the corresponding [`RIType::FFIType`](https:/docs.rs/sp-runtime-interface/latest/sp_runtime_interface/trait.RIType.html#associatedtype.FFIType). -Depending on where and how a type should be used in a function signature, a combination of the -following traits need to be implemented: +Depending on where and how a type should be used in a function signature, a combination of the following traits need to +be implemented: 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`] 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`] 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`] -The traits are implemented for most of the common types like `[T]`, `Vec`, arrays and -primitive types. +The traits are implemented for most of the common types like `[T]`, `Vec`, arrays and primitive types. -For custom types, we provide the [`PassBy`](https://docs.rs/sp-runtime-interface/latest/sp_runtime_interface/pass_by#PassBy) trait and strategies that define -how a type is passed between the wasm runtime and the node. Each strategy also provides a derive -macro to simplify the implementation. +For custom types, we provide the +[`PassBy`](https://docs.rs/sp-runtime-interface/latest/sp_runtime_interface/pass_by#PassBy) trait and strategies that +define how a type is passed between the wasm runtime and the node. Each strategy also provides a derive macro to +simplify the implementation. # Performance -To not waste any more performance when calling into the node, not all types are SCALE encoded -when being passed as arguments between the wasm runtime and the node. For most types that -are raw bytes like `Vec`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding -them in front of. The implementation of [`RIType`] each type provides more information on how -the data is passed. +To not waste any more performance when calling into the node, not all types are SCALE encoded when being passed as +arguments between the wasm runtime and the node. For most types that are raw bytes like `Vec`, `[u8]` or `[u8; N]` +we pass them directly, without SCALE encoding them in front of. The implementation of [`RIType`] each type provides more +information on how the data is passed. # Declaring a runtime interface @@ -57,9 +56,10 @@ For more information on declaring a runtime interface, see # FFI type and conversion -The following table documents how values of types are passed between the wasm and -the host side and how they are converted into the corresponding type. +The following table documents how values of types are passed between the wasm and the host side and how they are +converted into the corresponding type. + | Type | FFI type | Conversion | |----|----|----| | `u8` | `u8` | `Identity` | diff --git a/substrate/primitives/runtime/README.md b/substrate/primitives/runtime/README.md index 1515cd8e296..2755690e4b3 100644 --- a/substrate/primitives/runtime/README.md +++ b/substrate/primitives/runtime/README.md @@ -1,3 +1,3 @@ Runtime Modules shared primitive types. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/session/README.md b/substrate/primitives/session/README.md index 2d1f9d9bc1d..9ad3e274703 100644 --- a/substrate/primitives/session/README.md +++ b/substrate/primitives/session/README.md @@ -1,3 +1,3 @@ Substrate core types around sessions. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/staking/README.md b/substrate/primitives/staking/README.md index 892e1379d9a..3e0ea0ba1fa 100644 --- a/substrate/primitives/staking/README.md +++ b/substrate/primitives/staking/README.md @@ -1,4 +1,4 @@ A crate which contains primitives that are useful for implementation that uses staking approaches in general. Definitions related to sessions, slashing, etc go here. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/state-machine/README.md b/substrate/primitives/state-machine/README.md index aa244da62d5..91d706f860e 100644 --- a/substrate/primitives/state-machine/README.md +++ b/substrate/primitives/state-machine/README.md @@ -1,3 +1,3 @@ Substrate state machine implementation. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/statement-store/README.md b/substrate/primitives/statement-store/README.md index 2cde0d669ee..f224f6ce431 100644 --- a/substrate/primitives/statement-store/README.md +++ b/substrate/primitives/statement-store/README.md @@ -1,18 +1,35 @@ +# Statement store + Statement store is an off-chain data-store for signed statements accessible via RPC and OCW. -Nodes hold a number of statements with a proof of authenticity owing to an account ID. OCWs can place items in the data-store (with valid signatures) for any accounts whose keys they control. Users can also submit pre-signed statements via RPC. Statements can also be submitted from on-chain logic through an on-chain event. +Nodes hold a number of statements with a proof of authenticity owing to an account ID. OCWs can place items in the +data-store (with valid signatures) for any accounts whose keys they control. Users can also submit pre-signed statements +via RPC. Statements can also be submitted from on-chain logic through an on-chain event. -A new system event `NewStatement` is added to the runtime. This event allows any account on-chain to declare that they want to make a statement for the store. Within the node store and for broadcasting, the statement would be accompanied with the hash of the block and index of the event within it, essentially taking the place of a real signature. +A new system event `NewStatement` is added to the runtime. This event allows any account on-chain to declare that they +want to make a statement for the store. Within the node store and for broadcasting, the statement would be accompanied +with the hash of the block and index of the event within it, essentially taking the place of a real signature. -Statements comprise an optional proof of authenticity (e.g. a signature) and a number of fields. For statements without a proof, nodes would gossip statements randomly with a rate-limiter to minimise the chance of being overrun by a misbehaving node. These will generally be disregarded by nodes unless they are gossiped by several different peers or if a peer pays for it somehow (e.g. gossiping something valuable). +Statements comprise an optional proof of authenticity (e.g. a signature) and a number of fields. For statements without +a proof, nodes would gossip statements randomly with a rate-limiter to minimise the chance of being overrun by a +misbehaving node. These will generally be disregarded by nodes unless they are gossiped by several different peers or if +a peer pays for it somehow (e.g. gossiping something valuable). -Each field is effectively a key/value pair. Fields must be sorted and the same field type may not be repeated. Depending on which keys are present, clients may index the message for ease of retrieval. +Each field is effectively a key/value pair. Fields must be sorted and the same field type may not be repeated. Depending +on which keys are present, clients may index the message for ease of retrieval. Formally, `Statement` is equivalent to the type `Vec` and `Field` is the SCALE-encoded enumeration: -- 0: `AuthenticityProof(Proof)`: The signature of the message. For cryptography where the public key cannot be derived from the signature together with the message data, then this will also include the signer's public key. The message data is all fields of the messages fields except the signature concatenated together *without the length prefix that a `Vec` would usually imply*. This is so that the signature can be derived without needing to re-encode the statement. -- 1: `DecryptionKey([u8; 32])`: The decryption key identifier which should be used to decrypt the statement's data. In the absence of this field `Data` should be treated as not encrypted. -- 2: `Priority(u32)`: Priority specifier. Higher priority statements should be kept around at the cost of lower priority statements if multiple statements from the same sender are competing for persistence or transport. Nodes should disregard when considering unsigned statements. -- 3: `Channel([u8; 32])`: The channel identifier. Only one message of a given channel should be retained at once (the one of highest priority). Nodes should disregard when considering unsigned statements. +- 0: `AuthenticityProof(Proof)`: The signature of the message. For cryptography where the public key cannot be derived + from the signature together with the message data, then this will also include the signer's public key. The message + data is all fields of the messages fields except the signature concatenated together *without the length prefix that a + `Vec` would usually imply*. This is so that the signature can be derived without needing to re-encode the statement. +- 1: `DecryptionKey([u8; 32])`: The decryption key identifier which should be used to decrypt the statement's data. In + the absence of this field `Data` should be treated as not encrypted. +- 2: `Priority(u32)`: Priority specifier. Higher priority statements should be kept around at the cost of lower priority + statements if multiple statements from the same sender are competing for persistence or transport. Nodes should + disregard when considering unsigned statements. +- 3: `Channel([u8; 32])`: The channel identifier. Only one message of a given channel should be retained at once (the + one of highest priority). Nodes should disregard when considering unsigned statements. - 4: `Topic1([u8; 32]))`: First topic identifier. - 5: `Topic2([u8; 32]))`: Second topic identifier. - 6: `Topic3([u8; 32]))`: Third topic identifier. @@ -25,7 +42,7 @@ Formally, `Statement` is equivalent to the type `Vec` and `Field` is the - 2: `Secp256k1Ecdsa { signature: [u8; 65], signer: [u8; 33] )` - 3: `OnChain { who: [u8; 32], block_hash: [u8; 32], event_index: u64 }` -### Potential uses +## Potential uses Potential use-cases are various and include: - ring-signature aggregation; diff --git a/substrate/primitives/std/README.md b/substrate/primitives/std/README.md index 6dddd8fbbdd..e186ccecf7b 100644 --- a/substrate/primitives/std/README.md +++ b/substrate/primitives/std/README.md @@ -1,4 +1,4 @@ Lowest-abstraction level for the Substrate runtime: just exports useful primitives from std or client/alloc to be used with any code that depends on the runtime. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/storage/README.md b/substrate/primitives/storage/README.md index c33144fc4f6..ac922f139ff 100644 --- a/substrate/primitives/storage/README.md +++ b/substrate/primitives/storage/README.md @@ -1,3 +1,3 @@ Primitive types for storage related stuff. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/timestamp/README.md b/substrate/primitives/timestamp/README.md index a61a776912c..41649cdfc8e 100644 --- a/substrate/primitives/timestamp/README.md +++ b/substrate/primitives/timestamp/README.md @@ -1,3 +1,3 @@ Substrate core types and inherents for timestamps. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/tracing/README.md b/substrate/primitives/tracing/README.md index d66bb90016c..4582a34d918 100644 --- a/substrate/primitives/tracing/README.md +++ b/substrate/primitives/tracing/README.md @@ -12,4 +12,4 @@ Additionally, we have a const: `WASM_TRACE_IDENTIFIER`, which holds a span name to signal that the 'actual' span name and target should be retrieved instead from the associated Fields mentioned above. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/transaction-pool/README.md b/substrate/primitives/transaction-pool/README.md index 417565ebfce..209d23e9980 100644 --- a/substrate/primitives/transaction-pool/README.md +++ b/substrate/primitives/transaction-pool/README.md @@ -1,3 +1,3 @@ Transaction pool primitives types & Runtime API. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/trie/README.md b/substrate/primitives/trie/README.md index 634ba4bdead..e82080da5ff 100644 --- a/substrate/primitives/trie/README.md +++ b/substrate/primitives/trie/README.md @@ -1,3 +1,3 @@ Utility functions to interact with Substrate's Base-16 Modified Merkle Patricia tree ("trie"). -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/version/README.md b/substrate/primitives/version/README.md index 84f0ae57d9d..8decaaa85f8 100644 --- a/substrate/primitives/version/README.md +++ b/substrate/primitives/version/README.md @@ -1,3 +1,3 @@ Version module for the Substrate runtime; Provides a function that returns the runtime version. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/primitives/wasm-interface/README.md b/substrate/primitives/wasm-interface/README.md index 7e6c46581ae..2e584adeb83 100644 --- a/substrate/primitives/wasm-interface/README.md +++ b/substrate/primitives/wasm-interface/README.md @@ -1,3 +1,3 @@ Types and traits for interfacing between the host and the wasm runtime. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/scripts/ci/docker/subkey.Dockerfile.README.md b/substrate/scripts/ci/docker/subkey.Dockerfile.README.md index 30a5e821215..fe3359d01e8 100644 --- a/substrate/scripts/ci/docker/subkey.Dockerfile.README.md +++ b/substrate/scripts/ci/docker/subkey.Dockerfile.README.md @@ -1,8 +1,11 @@ -# The `subkey` program is a key management utility for Substrate-based blockchains. You can use the `subkey` program to perform the following tasks: +# Subkey + +The `subkey` program is a key management utility for Substrate-based blockchains. You can use the `subkey` program to +perform the following tasks * Generate and inspect cryptographically-secure public and private key pairs. * Restore keys from secret phrases and raw seeds. * Sign and verify signatures on messages. * Sign and verify signatures for encoded transactions. * Derive hierarchical deterministic child key pairs. -* [Documentation](https://docs.substrate.io/reference/command-line-tools/subkey/) \ No newline at end of file +* [Documentation](https://docs.substrate.io/reference/command-line-tools/subkey/) diff --git a/substrate/scripts/ci/docker/substrate.Dockerfile.README.md b/substrate/scripts/ci/docker/substrate.Dockerfile.README.md index 557fd8f835d..9e97701e92f 100644 --- a/substrate/scripts/ci/docker/substrate.Dockerfile.README.md +++ b/substrate/scripts/ci/docker/substrate.Dockerfile.README.md @@ -1 +1 @@ -# Substrate Docker Image \ No newline at end of file +# Substrate Docker Image diff --git a/substrate/scripts/ci/monitoring/grafana-dashboards/README_dashboard.md b/substrate/scripts/ci/monitoring/grafana-dashboards/README_dashboard.md index 50f54a107e9..2267cfbefb7 100644 --- a/substrate/scripts/ci/monitoring/grafana-dashboards/README_dashboard.md +++ b/substrate/scripts/ci/monitoring/grafana-dashboards/README_dashboard.md @@ -1,4 +1,4 @@ -## Substrate Dashboard +# Substrate Dashboard Shared templated Grafana dashboards. diff --git a/substrate/utils/build-script-utils/README.md b/substrate/utils/build-script-utils/README.md index 1c184f67326..f857d04710b 100644 --- a/substrate/utils/build-script-utils/README.md +++ b/substrate/utils/build-script-utils/README.md @@ -1,3 +1,3 @@ Crate with utility functions for `build.rs` scripts. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/utils/fork-tree/README.md b/substrate/utils/fork-tree/README.md index fef7db57f68..ba573dfff41 100644 --- a/substrate/utils/fork-tree/README.md +++ b/substrate/utils/fork-tree/README.md @@ -1,4 +1,4 @@ Utility library for managing tree-like ordered data with logic for pruning the tree while finalizing nodes. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/utils/frame/benchmarking-cli/README.md b/substrate/utils/frame/benchmarking-cli/README.md index e6a48b61fd2..27673ea9580 100644 --- a/substrate/utils/frame/benchmarking-cli/README.md +++ b/substrate/utils/frame/benchmarking-cli/README.md @@ -1,10 +1,11 @@ # The Benchmarking CLI -This crate contains commands to benchmark various aspects of Substrate and the hardware. -All commands are exposed by the Substrate node but can be exposed by any Substrate client. -The goal is to have a comprehensive suite of benchmarks that cover all aspects of Substrate and the hardware that its running on. +This crate contains commands to benchmark various aspects of Substrate and the hardware. +All commands are exposed by the Substrate node but can be exposed by any Substrate client. +The goal is to have a comprehensive suite of benchmarks that cover all aspects of Substrate and the hardware that its +running on. -Invoking the root benchmark command prints a help menu: +Invoking the root benchmark command prints a help menu: ```sh $ cargo run --profile=production -- benchmark @@ -25,10 +26,12 @@ SUBCOMMANDS: storage Benchmark the storage speed of a chain snapshot ``` -All examples use the `production` profile for correctness which makes the compilation *very* slow; for testing you can use `--release`. -For the final results the `production` profile and reference hardware should be used, otherwise the results are not comparable. +All examples use the `production` profile for correctness which makes the compilation *very* slow; for testing you can +use `--release`. +For the final results the `production` profile and reference hardware should be used, otherwise the results are not +comparable. -The sub-commands are explained in depth here: +The sub-commands are explained in depth here: - [block] Compare the weight of a historic block to its actual resource usage - [machine] Gauges the speed of the hardware - [overhead] Creates weight files for the *Block*- and *Extrinsic*-base weights diff --git a/substrate/utils/frame/benchmarking-cli/src/block/README.md b/substrate/utils/frame/benchmarking-cli/src/block/README.md index 7e99f0df9d4..e03f60e7627 100644 --- a/substrate/utils/frame/benchmarking-cli/src/block/README.md +++ b/substrate/utils/frame/benchmarking-cli/src/block/README.md @@ -1,65 +1,62 @@ # The `benchmark block` command -The whole benchmarking process in Substrate aims to predict the resource usage of an unexecuted block. -This command measures how accurate this prediction was by executing a block and comparing the predicted weight to its actual resource usage. -It can be used to measure the accuracy of the pallet benchmarking. +The whole benchmarking process in Substrate aims to predict the resource usage of an unexecuted block. This command +measures how accurate this prediction was by executing a block and comparing the predicted weight to its actual resource +usage. It can be used to measure the accuracy of the pallet benchmarking. -In the following it will be explained once for Polkadot and once for Substrate. +In the following it will be explained once for Polkadot and once for Substrate. ## Polkadot # 1 (Also works for Kusama, Westend and Rococo) -Suppose you either have a synced Polkadot node or downloaded a snapshot from [Polkachu]. -This example uses a pruned ParityDB snapshot from the 2022-4-19 with the last block being 9939462. -For pruned snapshots you need to know the number of the last block (to be improved [here]). -Pruned snapshots normally store the last 256 blocks, archive nodes can use any block range. +Suppose you either have a synced Polkadot node or downloaded a snapshot from [Polkachu]. This example uses a pruned +ParityDB snapshot from the 2022-4-19 with the last block being 9939462. For pruned snapshots you need to know the number +of the last block (to be improved [here]). Pruned snapshots normally store the last 256 blocks, archive nodes can use +any block range. -In this example we will benchmark just the last 10 blocks: +In this example we will benchmark just the last 10 blocks: ```sh cargo run --profile=production -- benchmark block --from 9939453 --to 9939462 --db paritydb ``` Output: ```pre -Block 9939453 with 2 tx used 4.57% of its weight ( 26,458,801 of 579,047,053 ns) -Block 9939454 with 3 tx used 4.80% of its weight ( 28,335,826 of 590,414,831 ns) -Block 9939455 with 2 tx used 4.76% of its weight ( 27,889,567 of 586,484,595 ns) -Block 9939456 with 2 tx used 4.65% of its weight ( 27,101,306 of 582,789,723 ns) -Block 9939457 with 2 tx used 4.62% of its weight ( 26,908,882 of 582,789,723 ns) -Block 9939458 with 2 tx used 4.78% of its weight ( 28,211,440 of 590,179,467 ns) -Block 9939459 with 4 tx used 4.78% of its weight ( 27,866,077 of 583,260,451 ns) -Block 9939460 with 3 tx used 4.72% of its weight ( 27,845,836 of 590,462,629 ns) -Block 9939461 with 2 tx used 4.58% of its weight ( 26,685,119 of 582,789,723 ns) -Block 9939462 with 2 tx used 4.60% of its weight ( 26,840,938 of 583,697,101 ns) +Block 9939453 with 2 tx used 4.57% of its weight ( 26,458,801 of 579,047,053 ns) +Block 9939454 with 3 tx used 4.80% of its weight ( 28,335,826 of 590,414,831 ns) +Block 9939455 with 2 tx used 4.76% of its weight ( 27,889,567 of 586,484,595 ns) +Block 9939456 with 2 tx used 4.65% of its weight ( 27,101,306 of 582,789,723 ns) +Block 9939457 with 2 tx used 4.62% of its weight ( 26,908,882 of 582,789,723 ns) +Block 9939458 with 2 tx used 4.78% of its weight ( 28,211,440 of 590,179,467 ns) +Block 9939459 with 4 tx used 4.78% of its weight ( 27,866,077 of 583,260,451 ns) +Block 9939460 with 3 tx used 4.72% of its weight ( 27,845,836 of 590,462,629 ns) +Block 9939461 with 2 tx used 4.58% of its weight ( 26,685,119 of 582,789,723 ns) +Block 9939462 with 2 tx used 4.60% of its weight ( 26,840,938 of 583,697,101 ns) ``` ### Output Interpretation (Only results from reference hardware are relevant) -Each block is executed multiple times and the results are averaged. -The percent number is the interesting part and indicates how much weight was used as compared to how much was predicted. -The closer to 100% this is without exceeding 100%, the better. -If it exceeds 100%, the block is marked with "**OVER WEIGHT!**" to easier spot them. This is not good since then the benchmarking under-estimated the weight. -This would mean that an honest validator would possibly not be able to keep up with importing blocks since users did not pay for enough weight. -If that happens the validator could lag behind the chain and get slashed for missing deadlines. -It is therefore important to investigate any overweight blocks. +Each block is executed multiple times and the results are averaged. The percent number is the interesting part and +indicates how much weight was used as compared to how much was predicted. The closer to 100% this is without exceeding +100%, the better. If it exceeds 100%, the block is marked with "**OVER WEIGHT!**" to easier spot them. This is not good +since then the benchmarking under-estimated the weight. This would mean that an honest validator would possibly not be +able to keep up with importing blocks since users did not pay for enough weight. If that happens the validator could lag +behind the chain and get slashed for missing deadlines. It is therefore important to investigate any overweight blocks. -In this example you can see an unexpected result; only < 5% of the weight was used! -The measured blocks can be executed much faster than predicted. -This means that the benchmarking process massively over-estimated the execution time. -Since they are off by so much, it is an issue [polkadot#5192]. +In this example you can see an unexpected result; only < 5% of the weight was used! The measured blocks can be executed +much faster than predicted. This means that the benchmarking process massively over-estimated the execution time. Since +they are off by so much, it is an issue [`polkadot#5192`]. The ideal range for these results would be 85-100%. ## Polkadot # 2 -Let's take a more interesting example where the blocks use more of their predicted weight. -Every day when validators pay out rewards, the blocks are nearly full. -Using an archive node here is the easiest. +Let's take a more interesting example where the blocks use more of their predicted weight. Every day when validators pay +out rewards, the blocks are nearly full. Using an archive node here is the easiest. -The Polkadot blocks TODO-TODO for example contain large batch transactions for staking payout. +The Polkadot blocks TODO-TODO for example contain large batch transactions for staking payout. ```sh cargo run --profile=production -- benchmark block --from TODO --to TODO --db paritydb @@ -71,21 +68,20 @@ TODO ## Substrate -It is also possible to try the procedure in Substrate, although it's a bit boring. +It is also possible to try the procedure in Substrate, although it's a bit boring. -First you need to create some blocks with either a local or dev chain. -This example will use the standard development spec. -Pick a non existing directory where the chain data will be stored, eg `/tmp/dev`. +First you need to create some blocks with either a local or dev chain. This example will use the standard development +spec. Pick a non existing directory where the chain data will be stored, eg `/tmp/dev`. ```sh cargo run --profile=production -- --dev -d /tmp/dev ``` -You should see after some seconds that it started to produce blocks: +You should see after some seconds that it started to produce blocks: ```pre … ✨ Imported #1 (0x801d…9189) … ``` -You can now kill the node with `Ctrl+C`. Then measure how long it takes to execute these blocks: +You can now kill the node with `Ctrl+C`. Then measure how long it takes to execute these blocks: ```sh cargo run --profile=production -- benchmark block --from 1 --to 1 --dev -d /tmp/dev --pruning archive ``` @@ -94,9 +90,8 @@ This will benchmark the first block. If you killed the node at a later point, yo Block 1 with 1 tx used 72.04% of its weight ( 4,945,664 of 6,864,702 ns) ``` -In this example the block used ~72% of its weight. -The benchmarking therefore over-estimated the effort to execute the block. -Since this block is empty, its not very interesting. +In this example the block used ~72% of its weight. The benchmarking therefore over-estimated the effort to execute the +block. Since this block is empty, its not very interesting. ## Arguments diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/README.md b/substrate/utils/frame/benchmarking-cli/src/machine/README.md index f22a8ea54b8..d3c9a0ec840 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/README.md +++ b/substrate/utils/frame/benchmarking-cli/src/machine/README.md @@ -1,17 +1,17 @@ # The `benchmark machine` command -Different Substrate chains can have different hardware requirements. -It is therefore important to be able to quickly gauge if a piece of hardware fits a chains' requirements. -The `benchmark machine` command archives this by measuring key metrics and making them comparable. +Different Substrate chains can have different hardware requirements. +It is therefore important to be able to quickly gauge if a piece of hardware fits a chains' requirements. +The `benchmark machine` command archives this by measuring key metrics and making them comparable. -Invoking the command looks like this: +Invoking the command looks like this: ```sh cargo run --profile=production -- benchmark machine --dev ``` ## Output -The output on reference hardware: +The output on reference hardware: ```pre +----------+----------------+---------------+--------------+-------------------+ @@ -29,37 +29,49 @@ The output on reference hardware: +----------+----------------+---------------+--------------+-------------------+ ``` -The *score* is the average result of each benchmark. It always adheres to "higher is better". +The *score* is the average result of each benchmark. It always adheres to "higher is better". -The *category* indicate which part of the hardware was benchmarked: +The *category* indicate which part of the hardware was benchmarked: - **CPU** Processor intensive task - **Memory** RAM intensive task - **Disk** Hard drive intensive task -The *function* is the concrete benchmark that was run: -- **BLAKE2-256** The throughput of the [Blake2-256] cryptographic hashing function with 32 KiB input. The [blake2_256 function] is used in many places in Substrate. The throughput of a hash function strongly depends on the input size, therefore we settled to use a fixed input size for comparable results. -- **SR25519 Verify** Sr25519 is an optimized version of the [Curve25519] signature scheme. Signature verification is used by Substrate when verifying extrinsics and blocks. +The *function* is the concrete benchmark that was run: +- **BLAKE2-256** The throughput of the [Blake2-256] cryptographic hashing function with 32 KiB input. The [blake2_256 + function] is used in many places in Substrate. The throughput of a hash function strongly depends on the input size, + therefore we settled to use a fixed input size for comparable results. +- **SR25519 Verify** Sr25519 is an optimized version of the [Curve25519] signature scheme. Signature verification is + used by Substrate when verifying extrinsics and blocks. - **Copy** The throughput of copying memory from one place in the RAM to another. -- **Seq Write** The throughput of writing data to the storage location sequentially. It is important that the same disk is used that will later-on be used to store the chain data. -- **Rnd Write** The throughput of writing data to the storage location in a random order. This is normally much slower than the sequential write. +- **Seq Write** The throughput of writing data to the storage location sequentially. It is important that the same disk + is used that will later-on be used to store the chain data. +- **Rnd Write** The throughput of writing data to the storage location in a random order. This is normally much slower + than the sequential write. -The *score* needs to reach the *minimum* in order to pass the benchmark. This can be reduced with the `--tolerance` flag. +The *score* needs to reach the *minimum* in order to pass the benchmark. This can be reduced with the `--tolerance` +flag. -The *result* indicated if a specific benchmark was passed by the machine or not. The percent number is the relative score reached to the *minimum* that is needed. The `--tolerance` flag is taken into account for this decision. For example a benchmark that passes even with 95% since the *tolerance* was set to 10% would look like this: `✅ Pass ( 95.0 %)`. +The *result* indicated if a specific benchmark was passed by the machine or not. The percent number is the relative +score reached to the *minimum* that is needed. The `--tolerance` flag is taken into account for this decision. For +example a benchmark that passes even with 95% since the *tolerance* was set to 10% would look like this: `✅ Pass ( 95.0 +%)`. ## Interpretation -Ideally all results show a `Pass` and the program exits with code 0. Currently some of the benchmarks can fail even on reference hardware; they are still being improved to make them more deterministic. -Make sure to run nothing else on the machine when benchmarking it. +Ideally all results show a `Pass` and the program exits with code 0. Currently some of the benchmarks can fail even on +reference hardware; they are still being improved to make them more deterministic. +Make sure to run nothing else on the machine when benchmarking it. You can re-run them multiple times to get more reliable results. ## Arguments -- `--tolerance` A percent number to reduce the *minimum* requirement. This should be used to ignore outliers of the benchmarks. The default value is 10%. +- `--tolerance` A percent number to reduce the *minimum* requirement. This should be used to ignore outliers of the + benchmarks. The default value is 10%. - `--verify-duration` How long the verification benchmark should run. - `--disk-duration` How long the *read* and *write* benchmarks should run each. - `--allow-fail` Always exit the program with code 0. -- `--chain` / `--dev` Specify the chain config to use. This will be used to compare the results with the requirements of the chain (WIP). +- `--chain` / `--dev` Specify the chain config to use. This will be used to compare the results with the requirements of + the chain (WIP). - [`--base-path`] License: Apache-2.0 diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/README.md b/substrate/utils/frame/benchmarking-cli/src/overhead/README.md index 390bc09e417..648908010ba 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/README.md @@ -1,21 +1,21 @@ # The `benchmark overhead` command -Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead". -This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead. -The exact overhead to can vary per Substrate chain and needs to be calculated per chain. -This command calculates the exact values of these overhead weights for any Substrate chain that supports it. +Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead". This is necessary +since the weight that is calculated by the pallet benchmarks does not include this overhead. The exact overhead to can +vary per Substrate chain and needs to be calculated per chain. This command calculates the exact values of these +overhead weights for any Substrate chain that supports it. ## How does it work? -The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`]. -Both are executed sequentially when invoking the command. +The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`]. Both are executed +sequentially when invoking the command. ## BlockExecutionWeight -The block execution weight is defined as the weight that it takes to execute an *empty block*. -It is measured by constructing an empty block and measuring its executing time. -The result are written to a `block_weights.rs` file which is created from a template. -The file will contain the concrete weight value and various statistics about the measurements. For example: +The block execution weight is defined as the weight that it takes to execute an *empty block*. It is measured by +constructing an empty block and measuring its executing time. The result are written to a `block_weights.rs` file which +is created from a template. The file will contain the concrete weight value and various statistics about the +measurements. For example: ```rust /// Time to execute an empty block. /// Calculated by multiplying the *Average* with `1` and adding `0`. @@ -34,16 +34,17 @@ pub const BlockExecutionWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(3_532_484), 0); ``` -In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. -This constant weight is therefore added to each block to ensure that Substrate budgets enough time to execute it. +In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute +*any* block. This constant weight is therefore added to each block to ensure that Substrate budgets enough time to +execute it. ## ExtrinsicBaseWeight -The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic. -An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above. -The benchmark now constructs a block which is filled with only NO-OP extrinsics. -This block is then executed many times and the weights are measured. -The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`. +The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic. An *empty* extrinsic +is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above. The benchmark now +constructs a block which is filled with only NO-OP extrinsics. This block is then executed many times and the weights +are measured. The result is divided by the number of extrinsics in that block and the results are written to +`extrinsic_weights.rs`. The relevant section in the output file looks like this: ```rust @@ -64,8 +65,9 @@ pub const ExtrinsicBaseWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(67_745), 0); ``` -In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. -This constant weight is therefore added to each extrinsic to ensure that Substrate budgets enough time to execute it. +In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to +execute *any* extrinsic. This constant weight is therefore added to each extrinsic to ensure that Substrate budgets +enough time to execute it. ## Invocation @@ -106,15 +108,18 @@ The complete command for Polkadot looks like this: cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/ ``` -This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory. -You can try the same for *Rococo* and to see that the results slightly differ. +This will overwrite the the +[block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) +and +[extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) +files in the Polkadot runtime directory. You can try the same for *Rococo* and to see that the results slightly differ. 👉 It is paramount to use `--profile=production` and `--wasm-execution=compiled` as the results are otherwise useless. ## Output Interpretation -Lower is better. The less weight the execution overhead needs, the better. -Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block. -Minimizing this is important to have a large transaction throughput. +Lower is better. The less weight the execution overhead needs, the better. Since the weights of the overhead is charged +per extrinsic and per block, a larger weight results in less extrinsics per block. Minimizing this is important to have +a large transaction throughput. ## Arguments @@ -132,7 +137,10 @@ Minimizing this is important to have a large transaction throughput. License: Apache-2.0 -[`ExtrinsicBaseWeight`]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/extrinsic_weights.rs#L26 -[`BlockExecutionWeight`]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/block_weights.rs#L26 +[`ExtrinsicBaseWeight`]: + https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/extrinsic_weights.rs#L26 +[`BlockExecutionWeight`]: + https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/block_weights.rs#L26 -[System::Remark]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/system/src/lib.rs#L382 +[System::Remark]: + https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/system/src/lib.rs#L382 diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/README.md b/substrate/utils/frame/benchmarking-cli/src/shared/README.md index 08e25b0e08f..0b1128bca3a 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/README.md +++ b/substrate/utils/frame/benchmarking-cli/src/shared/README.md @@ -10,7 +10,10 @@ Contains code that is shared among multiple sub-commands. - `--weight-path` Set the file or directory to write the weight files to. - `--db` The database backend to use. This depends on your snapshot. - `--pruning` Set the pruning mode of the node. Some benchmarks require you to set this to `archive`. -- `--base-path` The location on the disk that should be used for the benchmarks. You can try this on different disks or even on a mounted RAM-disk. It is important to use the same location that will later-on be used to store the chain data to get the correct results. -- `--header` Optional file header which will be prepended to the weight output file. Can be used for adding LICENSE headers. +- `--base-path` The location on the disk that should be used for the benchmarks. You can try this on different disks or + even on a mounted RAM-disk. It is important to use the same location that will later-on be used to store the chain + data to get the correct results. +- `--header` Optional file header which will be prepended to the weight output file. Can be used for adding LICENSE + headers. License: Apache-2.0 diff --git a/substrate/utils/frame/benchmarking-cli/src/storage/README.md b/substrate/utils/frame/benchmarking-cli/src/storage/README.md index f61b7ba1bdd..95c83d2edbc 100644 --- a/substrate/utils/frame/benchmarking-cli/src/storage/README.md +++ b/substrate/utils/frame/benchmarking-cli/src/storage/README.md @@ -1,17 +1,19 @@ # The `benchmark storage` command -The cost of storage operations in a Substrate chain depends on the current chain state. -It is therefore important to regularly update these weights as the chain grows. -This sub-command measures the cost of storage operations for a concrete snapshot. +The cost of storage operations in a Substrate chain depends on the current chain state. +It is therefore important to regularly update these weights as the chain grows. +This sub-command measures the cost of storage operations for a concrete snapshot. -For the Substrate node it looks like this (for debugging you can use `--release`): +For the Substrate node it looks like this (for debugging you can use `--release`): ```sh cargo run --profile=production -- benchmark storage --dev --state-version=1 ``` -Running the command on Substrate itself is not verify meaningful, since the genesis state of the `--dev` chain spec is used. +Running the command on Substrate itself is not verify meaningful, since the genesis state of the `--dev` chain spec is +used. -The output for the Polkadot client with a recent chain snapshot will give you a better impression. A recent snapshot can be downloaded from [Polkachu]. +The output for the Polkadot client with a recent chain snapshot will give you a better impression. A recent snapshot can +be downloaded from [Polkachu]. Then run (remove the `--db=paritydb` if you have a RocksDB snapshot): ```sh cargo run --profile=production -- benchmark storage --dev --state-version=0 --db=paritydb --weight-path runtime/polkadot/constants/src/weights @@ -20,8 +22,8 @@ cargo run --profile=production -- benchmark storage --dev --state-version=0 --db This takes a while since reads and writes all keys from the snapshot: ```pre # The 'read' benchmark -Preparing keys from block BlockId::Number(9939462) -Reading 1379083 keys +Preparing keys from block BlockId::Number(9939462) +Reading 1379083 keys Time summary [ns]: Total: 19668919930 Min: 6450, Max: 1217259 @@ -31,11 +33,11 @@ Value size summary: Total: 265702275 Min: 1, Max: 1381859 Average: 192, Median: 80, Stddev: 3427.53 -Percentiles 99th, 95th, 75th: 3368, 383, 80 +Percentiles 99th, 95th, 75th: 3368, 383, 80 # The 'write' benchmark -Preparing keys from block BlockId::Number(9939462) -Writing 1379083 keys +Preparing keys from block BlockId::Number(9939462) +Writing 1379083 keys Time summary [ns]: Total: 98393809781 Min: 12969, Max: 13282577 @@ -49,12 +51,13 @@ Percentiles 99th, 95th, 75th: 3368, 383, 80 Writing weights to "paritydb_weights.rs" ``` -You will see that the [paritydb_weights.rs] files was modified and now contains new weights. -The exact command for Polkadot can be seen at the top of the file. -This uses the most recent block from your snapshot which is printed at the top. -The value size summary tells us that the pruned Polkadot chain state is ~253 MiB in size. -Reading a value on average takes (in this examples) 14.3 µs and writing 71.3 µs. -The interesting part in the generated weight file tells us the weight constants and some statistics about the measurements: +You will see that the [paritydb_weights.rs] files was modified and now contains new weights. The exact command for +Polkadot can be seen at the top of the file. +This uses the most recent block from your snapshot which is printed at the top. +The value size summary tells us that the pruned Polkadot chain state is ~253 MiB in size. +Reading a value on average takes (in this examples) 14.3 µs and writing 71.3 µs. +The interesting part in the generated weight file tells us the weight constants and some statistics about the +measurements: ```rust /// Time to read one storage item. /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. @@ -90,7 +93,8 @@ write: 71_347 * constants::WEIGHT_REF_TIME_PER_NANOS, ## Arguments - `--db` Specify which database backend to use. This greatly influences the results. -- `--state-version` Set the version of the state encoding that this snapshot uses. Should be set to `1` for Substrate `--dev` and `0` for Polkadot et al. Using the wrong version can corrupt the snapshot. +- `--state-version` Set the version of the state encoding that this snapshot uses. Should be set to `1` for Substrate + `--dev` and `0` for Polkadot et al. Using the wrong version can corrupt the snapshot. - [`--mul`](../shared/README.md#arguments) - [`--add`](../shared/README.md#arguments) - [`--metric`](../shared/README.md#arguments) @@ -103,4 +107,5 @@ License: Apache-2.0 [Polkachu]: https://polkachu.com/snapshots -[paritydb_weights.rs]: https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/paritydb_weights.rs#L60 +[paritydb_weights.rs]: + https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/paritydb_weights.rs#L60 diff --git a/substrate/utils/frame/frame-utilities-cli/README.md b/substrate/utils/frame/frame-utilities-cli/README.md index b1e4f869af7..54467a3ad77 100644 --- a/substrate/utils/frame/frame-utilities-cli/README.md +++ b/substrate/utils/frame/frame-utilities-cli/README.md @@ -1,3 +1,3 @@ frame-system CLI utilities -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/utils/frame/rpc/support/README.md b/substrate/utils/frame/rpc/support/README.md index ca575061293..72e39b76118 100644 --- a/substrate/utils/frame/rpc/support/README.md +++ b/substrate/utils/frame/rpc/support/README.md @@ -1,4 +1,4 @@ Combines [sc_rpc_api::state::StateClient] with [frame_support::storage::generator] traits to provide strongly typed chain state queries over rpc. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/utils/frame/rpc/system/README.md b/substrate/utils/frame/rpc/system/README.md index 38986983d93..4eb4a74cece 100644 --- a/substrate/utils/frame/rpc/system/README.md +++ b/substrate/utils/frame/rpc/system/README.md @@ -1,3 +1,3 @@ System FRAME specific RPC methods. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/substrate/utils/prometheus/README.md b/substrate/utils/prometheus/README.md index 9dd0882105c..507b9b24fb7 100644 --- a/substrate/utils/prometheus/README.md +++ b/substrate/utils/prometheus/README.md @@ -2,15 +2,19 @@ ## Introduction -[Prometheus](https://prometheus.io/) is one of the most widely used monitoring tools for managing highly available services supported by [Cloud Native Computing Foundation](https://www.cncf.io/). By providing Prometheus metrics in Substrate, node operators can easily adopt widely used display/alert tools such -as [Grafana](https://grafana.com/) and [Alertmanager](https://prometheus.io/docs/alerting/alertmanager/). Easy access to such monitoring tools will benefit parachain developers/operators and validators to have much higher availability of their services. +[Prometheus](https://prometheus.io/) is one of the most widely used monitoring tools for managing highly available +services supported by [Cloud Native Computing Foundation](https://www.cncf.io/). By providing Prometheus metrics in +Substrate, node operators can easily adopt widely used display/alert tools such as [Grafana](https://grafana.com/) and +[Alertmanager](https://prometheus.io/docs/alerting/alertmanager/). Easy access to such monitoring tools will benefit +parachain developers/operators and validators to have much higher availability of their services. Metrics will be served under `/metrics` on TCP port 9615 by default. ## Quick Start - + 1. From the root of the repository start Substrate `cargo run --release`. 2. In another terminal run `curl localhost:9615/metrics` to retrieve the metrics. -To learn how to configure Prometheus see the Prometheus [Getting Started](https://prometheus.io/docs/prometheus/latest/getting_started/) guide. \ No newline at end of file +To learn how to configure Prometheus see the Prometheus [Getting +Started](https://prometheus.io/docs/prometheus/latest/getting_started/) guide. diff --git a/substrate/utils/wasm-builder/README.md b/substrate/utils/wasm-builder/README.md index b1ccb1b35b1..db32f5cbc95 100644 --- a/substrate/utils/wasm-builder/README.md +++ b/substrate/utils/wasm-builder/README.md @@ -1,14 +1,15 @@ # Wasm builder is a utility for building a project as a Wasm binary -The Wasm builder is a tool that integrates the process of building the WASM binary of your project into the main -`cargo` build process. +The Wasm builder is a tool that integrates the process of building the WASM binary of your project into the main `cargo` +build process. ## Project setup A project that should be compiled as a Wasm binary needs to: 1. Add a `build.rs` file. -2. Add `wasm-builder` as dependency into `build-dependencies` (can be made optional and only enabled when `std` feature is used). +2. Add `wasm-builder` as dependency into `build-dependencies` (can be made optional and only enabled when `std` feature + is used). The `build.rs` file needs to contain the following code: @@ -35,43 +36,40 @@ As the final step, you need to add the following to your project: include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); ``` -This will include the generated Wasm binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`. -The former is a compact Wasm binary and the latter is the Wasm binary as being generated by the compiler. -Both variables have `Option<&'static [u8]>` as type. +This will include the generated Wasm binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`. The former is a +compact Wasm binary and the latter is the Wasm binary as being generated by the compiler. Both variables have +`Option<&'static [u8]>` as type. ### Features -Wasm builder supports to enable cargo features while building the Wasm binary. By default it will -enable all features in the wasm build that are enabled for the native build except the -`default` and `std` features. Besides that, wasm builder supports the special `runtime-wasm` -feature. This `runtime-wasm` feature will be enabled by the wasm builder when it compiles the -Wasm binary. If this feature is not present, it will not be enabled. +Wasm builder supports to enable cargo features while building the Wasm binary. By default it will enable all features in +the wasm build that are enabled for the native build except the `default` and `std` features. Besides that, wasm builder +supports the special `runtime-wasm` feature. This `runtime-wasm` feature will be enabled by the wasm builder when it +compiles the Wasm binary. If this feature is not present, it will not be enabled. ## Environment variables By using environment variables, you can configure which Wasm binaries are built and how: -- `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be recompiled. - If this is the first run and there doesn't exist a Wasm binary, this will set both - variables to `None`. -- `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are `release` or `debug`. - By default the build type is equal to the build type used by the main build. -- `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the variable - needs to change. As wasm-builder instructs `cargo` to watch for file changes - this environment variable should only be required in certain circumstances. +- `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be recompiled. If this is + the first run and there doesn't exist a Wasm binary, this will set both variables to `None`. +- `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are `release` or `debug`. By + default the build type is equal to the build type used by the main build. +- `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the variable needs to change. + As wasm-builder instructs `cargo` to watch for file changes this environment variable should only + be required in certain circumstances. - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm binary. - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. -- `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path needs - to be absolute. -- `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The - format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. -- `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to prevent network access. Useful in offline environments. +- `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path needs to be absolute. +- `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The format needs to be the same + as used by cargo, e.g. `nightly-2020-02-20`. +- `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to prevent network access. + Useful in offline environments. -Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. -Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will -be `NODE_RUNTIME`. +Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. Where +`PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will be `NODE_RUNTIME`. -## Prerequisites: +## Prerequisites Wasm builder requires the following prerequisites for building the Wasm binary: @@ -81,9 +79,8 @@ or - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain -If a specific rust is installed with `rustup`, it is important that the wasm target is -installed as well. For example if installing the rust from 20.02.2020 using `rustup -install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add -wasm32-unknown-unknown --toolchain nightly-2020-02-20`. +If a specific rust is installed with `rustup`, it is important that the wasm target is installed as well. For example if +installing the rust from 20.02.2020 using `rustup install nightly-2020-02-20`, the wasm target needs to be installed as +well `rustup target add wasm32-unknown-unknown --toolchain nightly-2020-02-20`. License: Apache-2.0 diff --git a/substrate/zombienet/0001-basic-warp-sync/README.md b/substrate/zombienet/0001-basic-warp-sync/README.md index 7550ca89236..1f8bddee640 100644 --- a/substrate/zombienet/0001-basic-warp-sync/README.md +++ b/substrate/zombienet/0001-basic-warp-sync/README.md @@ -35,8 +35,8 @@ Once the zombienet is stopped, the database snapshot (`{alice,bob}/data/chains/local_testnet/db/` dirs) was created using the following commands: ```bash -mkdir -p db-snapshot/{alice,bob}/data/chains/local_testnet/db/ -cp -r db-test-gen/alice/data/chains/local_testnet/db/full db-snapshot/alice/data/chains/local_testnet/db/ +mkdir -p db-snapshot/{alice,bob}/data/chains/local_testnet/db/ +cp -r db-test-gen/alice/data/chains/local_testnet/db/full db-snapshot/alice/data/chains/local_testnet/db/ cp -r db-test-gen/bob/data/chains/local_testnet/db/full db-snapshot/bob/data/chains/local_testnet/db/ ``` @@ -72,7 +72,8 @@ Chain spec was simply built with: substrate build-spec --chain=local > chain-spec.json ``` -Please note that `chain-spec.json` committed into repository is `raw` version produced by `zombienet` during database snapshot generation. Zombienet applies some modifications to plain versions of chain-spec. +Please note that `chain-spec.json` committed into repository is `raw` version produced by `zombienet` during database +snapshot generation. Zombienet applies some modifications to plain versions of chain-spec. # Run the test Test can be run with the following command: @@ -91,7 +92,7 @@ index 23fb13cfb0..89f8646291 100644 --- a/bin/node/runtime/src/constants.rs +++ b/bin/node/runtime/src/constants.rs @@ -63,7 +63,7 @@ pub mod time { - + // NOTE: Currently it is not possible to change the epoch duration after the chain has started. // Attempting to do so will brick block production. - pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; diff --git a/substrate/zombienet/0002-validators-warp-sync/README.md b/substrate/zombienet/0002-validators-warp-sync/README.md index 662360fbf3c..99fcb731380 100644 --- a/substrate/zombienet/0002-validators-warp-sync/README.md +++ b/substrate/zombienet/0002-validators-warp-sync/README.md @@ -1,4 +1,3 @@ -Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync validators and make sure they can build blocks. -0001-basic-warp-sync chainspec (copied) and database are reused in this test. - - +Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync +validators and make sure they can build blocks. 0001-basic-warp-sync chainspec (copied) and database are reused in this +test. diff --git a/substrate/zombienet/0003-block-building-warp-sync/README.md b/substrate/zombienet/0003-block-building-warp-sync/README.md index 311d3550f76..08dc730a58b 100644 --- a/substrate/zombienet/0003-block-building-warp-sync/README.md +++ b/substrate/zombienet/0003-block-building-warp-sync/README.md @@ -1,4 +1,3 @@ -Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync full nodes in the presence of validators. +Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync full nodes +in the presence of validators. 0001-basic-warp-sync chainspec (copied) and database are reused in this test. - - -- GitLab From 2c35bc3d273f47d45c17078134c048016ef7a57a Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Mon, 4 Sep 2023 12:30:25 +0200 Subject: [PATCH 067/633] [xcm-emulator] Redo Parachain init (#1356) * bring back proper init * refactor block cycle * ".git/.scripts/commands/fmt/fmt.sh" * Update cumulus/xcm/xcm-emulator/src/lib.rs Co-authored-by: Squirrel --------- Co-authored-by: command-bot <> Co-authored-by: Giles Cope --- .../assets/asset-hub-kusama/src/tests/send.rs | 2 - .../asset-hub-polkadot/src/tests/send.rs | 2 - .../asset-hub-polkadot/src/tests/teleport.rs | 2 - .../asset-hub-westend/src/tests/send.rs | 2 - .../bridge-hub-rococo/src/tests/example.rs | 141 +++++++++--------- .../src/tests/fellowship.rs | 3 - cumulus/xcm/xcm-emulator/src/lib.rs | 128 +++++++++------- 7 files changed, 142 insertions(+), 138 deletions(-) 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 index 598256db83a..d633c25b732 100644 --- 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 @@ -174,8 +174,6 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { PenpalKusamaA::assert_xcm_pallet_sent(); }); - PenpalKusamaA::execute_with(|| {}); - AssetHubKusama::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; 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 index 978377b0fda..143ab06b4e9 100644 --- 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 @@ -177,8 +177,6 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { PenpalPolkadotA::assert_xcm_pallet_sent(); }); - PenpalPolkadotA::execute_with(|| {}); - AssetHubPolkadot::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; 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 index 166f73137e7..f0fbcf37fcc 100644 --- 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 @@ -187,7 +187,6 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { /// Limited Teleport of native asset from System Parachain to Relay Chain /// should work when there is enough balance in Relay Chain's `CheckAccount` #[test] -#[cfg(feature = "FIXME-IGNORED")] // 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(); @@ -226,7 +225,6 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { /// 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] -#[cfg(feature = "FIXME-IGNORED")] // 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; 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 f2040351e5d..fcaffdabc4c 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 @@ -116,8 +116,6 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { PenpalWestendA::assert_xcm_pallet_sent(); }); - PenpalWestendA::execute_with(|| {}); - AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index 127292829fd..777acd2aa97 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -14,85 +14,86 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use crate::*; + #[test] -#[ignore] fn example() { - // // Init tests variables - // // XcmPallet send arguments - // let sudo_origin = ::RuntimeOrigin::root(); - // let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into(); - // let weight_limit = WeightLimit::Unlimited; - // let check_origin = None; + // Init tests variables + // XcmPallet send arguments + let sudo_origin = ::RuntimeOrigin::root(); + let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into(); + let weight_limit = WeightLimit::Unlimited; + let check_origin = None; - // let remote_xcm = Xcm(vec![ClearOrigin]); + let remote_xcm = Xcm(vec![ClearOrigin]); - // let xcm = VersionedXcm::from(Xcm(vec![ - // UnpaidExecution { weight_limit, check_origin }, - // ExportMessage { - // network: WococoId, - // destination: X1(Parachain(AssetHubWococo::para_id().into())), - // xcm: remote_xcm, - // }, - // ])); + let xcm = VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit, check_origin }, + ExportMessage { + network: WococoId, + destination: X1(Parachain(AssetHubWococo::para_id().into())), + xcm: remote_xcm, + }, + ])); - // //Rococo Global Consensus - // // Send XCM message from Relay Chain to Bridge Hub source Parachain - // Rococo::execute_with(|| { - // assert_ok!(::XcmPallet::send( - // sudo_origin, - // bx!(destination), - // bx!(xcm), - // )); + //Rococo Global Consensus + // Send XCM message from Relay Chain to Bridge Hub source Parachain + Rococo::execute_with(|| { + assert_ok!(::XcmPallet::send( + sudo_origin, + bx!(destination), + bx!(xcm), + )); - // type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - // assert_expected_events!( - // Rococo, - // vec![ - // RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - // ] - // ); - // }); - // // Receive XCM message in Bridge Hub source Parachain - // BridgeHubRococo::execute_with(|| { - // type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + // Receive XCM message in Bridge Hub source Parachain + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; - // assert_expected_events!( - // BridgeHubRococo, - // vec![ - // RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - // outcome: Outcome::Complete(_), - // .. - // }) => {}, - // RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { - // lane_id: LaneId([0, 0, 0, 1]), - // nonce: 1, - // }) => {}, - // ] - // ); - // }); + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: Outcome::Complete(_), + .. + }) => {}, + RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { + lane_id: LaneId([0, 0, 0, 1]), + nonce: 1, + }) => {}, + ] + ); + }); - // // Wococo GLobal Consensus - // // Receive XCM message in Bridge Hub target Parachain - // BridgeHubWococo::execute_with(|| { - // type RuntimeEvent = ::RuntimeEvent; + // Wococo GLobal Consensus + // Receive XCM message in Bridge Hub target Parachain + BridgeHubWococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; - // assert_expected_events!( - // BridgeHubWococo, - // vec![ - // RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - // ] - // ); - // }); - // // Receive embeded XCM message within `ExportMessage` in Parachain destination - // AssetHubWococo::execute_with(|| { - // type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + // Receive embeded XCM message within `ExportMessage` in Parachain destination + AssetHubWococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; - // assert_expected_events!( - // AssetHubWococo, - // vec![ - // RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { .. }) => {}, - // ] - // ); - // }); + assert_expected_events!( + AssetHubWococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { .. }) => {}, + ] + ); + }); } 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 index 26fa55acb0d..82e998f5a76 100644 --- 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 @@ -58,11 +58,8 @@ fn pay_salary() { ); }); - Collectives::execute_with(|| {}); - AssetHubPolkadot::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( AssetHubPolkadot, vec![ diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 59f238528fc..9fda0632bae 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -248,6 +248,14 @@ pub trait Parachain: Chain { type ParachainInfo: Get; type ParachainSystem; + fn init(); + + fn new_block(); + + fn finalize_block(); + + fn set_last_head(); + fn para_id() -> ParaId { Self::ext_wrapper(|| Self::ParachainInfo::get()) } @@ -263,8 +271,6 @@ pub trait Parachain: Chain { fn sovereign_account_id_of(location: MultiLocation) -> AccountId { Self::LocationToAccountId::convert_location(&location).unwrap() } - - fn init(); } pub trait Bridge { @@ -603,28 +609,74 @@ macro_rules! decl_test_parachains { type ParachainSystem = $crate::ParachainSystemPallet<::Runtime>; type ParachainInfo = $parachain_info; + // We run an empty block during initialisation to open HRMP channels + // and have them ready for the next block fn init() { use $crate::{Chain, HeadData, Network, NetworkComponent, Hooks, Encode, Parachain, TestExt}; + // Set the last block head for later use in the next block + Self::set_last_head(); + // Initialize a new block + Self::new_block(); + // Finalize the new block + Self::finalize_block(); + } + + fn new_block() { + use $crate::{Chain, HeadData, Network, NetworkComponent, Hooks, Encode, Parachain, TestExt}; + + let para_id = Self::para_id().into(); + + Self::ext_wrapper(|| { + // Increase Relay Chain block number + let mut relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); + relay_block_number += 1; + <$name as NetworkComponent>::Network::set_relay_block_number(relay_block_number); + + // Initialize a new Parachain block + let mut block_number = ::System::block_number(); + block_number += 1; + let parent_head_data = $crate::LAST_HEAD.with(|b| b.borrow_mut() + .get_mut(::Network::name()) + .expect("network not initialized?") + .get(¶_id) + .expect("network not initialized?") + .clone() + ); + ::System::initialize(&block_number, &parent_head_data.hash(), &Default::default()); + <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(block_number); + + let _ = ::ParachainSystem::set_validation_data( + ::RuntimeOrigin::none(), + <$name as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), + ); + }); + } - let para_id = Self::para_id(); + fn finalize_block() { + use $crate::{Chain, Encode, Hooks, Network, NetworkComponent, Parachain, TestExt}; Self::ext_wrapper(|| { let block_number = ::System::block_number(); - let mut relay_block_number = ::Network::relay_block_number(); + ::ParachainSystem::on_finalize(block_number); + }); + + Self::set_last_head(); + } - // Get parent head data - let header = ::System::finalize(); - let parent_head_data = HeadData(header.encode()); + fn set_last_head() { + use $crate::{Chain, Encode, HeadData, Network, NetworkComponent, Parachain, TestExt}; + + let para_id = Self::para_id().into(); + + Self::ext_wrapper(|| { + // Store parent head data for use later. + let created_header = ::System::finalize(); $crate::LAST_HEAD.with(|b| b.borrow_mut() .get_mut(::Network::name()) .expect("network not initialized?") - .insert(para_id.into(), parent_head_data.clone()) + .insert(para_id, HeadData(created_header.encode())) ); - - let next_block_number = block_number + 1; - ::System::initialize(&next_block_number, &header.hash(), &Default::default()); - <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(next_block_number); }); } } @@ -746,43 +798,20 @@ macro_rules! __impl_test_ext_for_parachain { // Make sure the Network is initialized <$name as NetworkComponent>::Network::init(); - let para_id = <$name>::para_id().into(); - - // Initialize block - $local_ext.with(|v| { - v.borrow_mut().execute_with(|| { - let parent_head_data = $crate::LAST_HEAD.with(|b| b.borrow_mut() - .get_mut(::Network::name()) - .expect("network not initialized?") - .get(¶_id) - .expect("network not initialized?") - .clone() - ); - - // Increase block number - let mut relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); - relay_block_number += 1; - <$name as NetworkComponent>::Network::set_relay_block_number(relay_block_number); - - let _ = ::ParachainSystem::set_validation_data( - ::RuntimeOrigin::none(), - <$name as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), - ); - }) - }); + // Initialize a new block + Self::new_block(); // Execute let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); - // provide inbound DMP/HRMP messages through a side-channel. - // normally this would come through the `set_validation_data`, - // but we go around that. - <$name as NetworkComponent>::Network::process_messages(); + // Finalize the block + Self::finalize_block(); - // Finalize block and send messages if needed + let para_id = <$name>::para_id().into(); + + // Send messages if needed $local_ext.with(|v| { v.borrow_mut().execute_with(|| { - let block_number = ::System::block_number(); let mock_header = $crate::HeaderT::new( 0, Default::default(), @@ -791,16 +820,6 @@ macro_rules! __impl_test_ext_for_parachain { Default::default(), ); - // Finalize to get xcmp messages. - ::ParachainSystem::on_finalize(block_number); - // Store parent head data for use later. - let created_header = ::System::finalize(); - $crate::LAST_HEAD.with(|b| b.borrow_mut() - .get_mut(::Network::name()) - .expect("network not initialized?") - .insert(para_id.into(), $crate::HeadData(created_header.encode())) - ); - let collation_info = ::ParachainSystem::collect_collation_info(&mock_header); // send upward messages @@ -834,11 +853,6 @@ macro_rules! __impl_test_ext_for_parachain { // clean events ::System::reset_events(); - - // reinitialize before next call. - let next_block_number = block_number + 1; - ::System::initialize(&next_block_number, &created_header.hash(), &Default::default()); - <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(next_block_number); }) }); -- GitLab From be761b743ba4c8ac0c5ad39fc71b98547ac9ba37 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Mon, 4 Sep 2023 23:42:19 +1200 Subject: [PATCH 068/633] add Treasurer to SchedulerOrigin (#1325) --- polkadot/runtime/kusama/src/lib.rs | 3 ++- polkadot/runtime/polkadot/src/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 4b5f03b38c6..94af807fb5d 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -228,7 +228,8 @@ impl pallet_scheduler::Config for Runtime { type MaximumWeight = MaximumSchedulerWeight; // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of // OpenGov to schedule periodic auctions. - type ScheduleOrigin = EitherOf, AuctionAdmin>; + // Also allow Treasurer to schedule recurring payments. + type ScheduleOrigin = EitherOf, AuctionAdmin>, Treasurer>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = weights::pallet_scheduler::WeightInfo; type OriginPrivilegeCmp = OriginPrivilegeCmp; diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index 2efd329eea0..b71e0f726c5 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -212,7 +212,8 @@ impl pallet_scheduler::Config for Runtime { type MaximumWeight = MaximumSchedulerWeight; // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of // OpenGov to schedule periodic auctions. - type ScheduleOrigin = EitherOf, AuctionAdmin>; + // Also allow Treasurer to schedule recurring payments. + type ScheduleOrigin = EitherOf, AuctionAdmin>, Treasurer>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = weights::pallet_scheduler::WeightInfo; type OriginPrivilegeCmp = OriginPrivilegeCmp; -- GitLab From 2f242e0792dc941c7d3225a1d7c266fde02fc938 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 4 Sep 2023 14:45:33 +0200 Subject: [PATCH 069/633] Cleanup repo (a tiny bit) (#1382) * Delete stale adoc files Signed-off-by: Oliver Tale-Yazdi * Convert adoc to md Signed-off-by: Oliver Tale-Yazdi * Add adoc to gitignore Signed-off-by: Oliver Tale-Yazdi * Delete more random unmaintained files Signed-off-by: Oliver Tale-Yazdi * Markdown lint Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- .gitignore | 1 + cumulus/bridges/rustfmt.toml | 24 - polkadot/RELEASE.md | 52 -- polkadot/doc/release-checklist.md | 91 --- polkadot/node/service/README.adoc | 5 - polkadot/parachain/README.adoc | 5 - polkadot/primitives/README.adoc | 5 - polkadot/runtime/polkadot/README.adoc | 5 - polkadot/src/README.adoc | 5 - polkadot/statement-table/README.adoc | 5 - substrate/.maintain/getgoing.sh | 6 - substrate/.maintain/runtime-dep.py | 34 -- substrate/.maintain/update-deps.sh | 9 - ...ll-completion.adoc => shell-completion.md} | 23 +- substrate/client/cli/README.adoc | 6 - substrate/docs/README.adoc | 522 ------------------ substrate/docs/Structure.adoc | 121 ---- 17 files changed, 9 insertions(+), 910 deletions(-) delete mode 100644 cumulus/bridges/rustfmt.toml delete mode 100644 polkadot/RELEASE.md delete mode 100644 polkadot/doc/release-checklist.md delete mode 100644 polkadot/node/service/README.adoc delete mode 100644 polkadot/parachain/README.adoc delete mode 100644 polkadot/primitives/README.adoc delete mode 100644 polkadot/runtime/polkadot/README.adoc delete mode 100644 polkadot/src/README.adoc delete mode 100644 polkadot/statement-table/README.adoc delete mode 100644 substrate/.maintain/getgoing.sh delete mode 100755 substrate/.maintain/runtime-dep.py delete mode 100755 substrate/.maintain/update-deps.sh rename substrate/bin/node/cli/doc/{shell-completion.adoc => shell-completion.md} (75%) delete mode 100644 substrate/client/cli/README.adoc delete mode 100644 substrate/docs/README.adoc delete mode 100644 substrate/docs/Structure.adoc diff --git a/.gitignore b/.gitignore index bd7f34b4810..35e02e706b4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .local .vscode .wasm-binaries +*.adoc *.bin *.iml *.orig diff --git a/cumulus/bridges/rustfmt.toml b/cumulus/bridges/rustfmt.toml deleted file mode 100644 index 082150daf04..00000000000 --- a/cumulus/bridges/rustfmt.toml +++ /dev/null @@ -1,24 +0,0 @@ -# Basic -hard_tabs = true -max_width = 100 -use_small_heuristics = "Max" -# Imports -imports_granularity = "Crate" -reorder_imports = true -# Consistency -newline_style = "Unix" -# Format comments -comment_width = 100 -wrap_comments = true -# Misc -chain_width = 80 -spaces_around_ranges = false -binop_separator = "Back" -reorder_impl_items = false -match_arm_leading_pipes = "Preserve" -match_arm_blocks = false -match_block_trailing_comma = true -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true - diff --git a/polkadot/RELEASE.md b/polkadot/RELEASE.md deleted file mode 100644 index 196f27e595d..00000000000 --- a/polkadot/RELEASE.md +++ /dev/null @@ -1,52 +0,0 @@ -# Polkadot Release Process - -## Branches -* release-candidate branch: The branch used for staging of the next release. Named like `release-v0.8.26` - -## Notes -* The release-candidate branch *must* be made in the `paritytech/polkadot` repo in order for release automation to work -correctly -* Any new pushes/merges to the release-candidate branch (for example, refs/heads/release-v0.8.26) will result in the rc -index being bumped (e.g., v0.8.26-rc1 to v0.8.26-rc2) and new wasm built. - -## Release workflow - -Below are the steps of the release workflow. Steps prefixed with NOACTION are automated and require no human action. - -1. To initiate the release process: - 1. branch master off to a release candidate branch: - `git checkout master; git pull; git checkout -b release-v0.8.26` - 1. In the [Substrate](https://github.com/paritytech/substrate) repo, check out the commit used by Polkadot (this can - be found using the following command in the *Polkadot* repo: `grep 'paritytech/substrate' Cargo.lock | grep -E - '[0-9a-f]{40}' | sort | uniq` - 1. Branch off this **Substrate** commit into its own branch: `git branch -b polkadot-v0.8.26; git push origin - refs/heads/polkadot-v0.8.26` - 1. In the **Polkadot** repository, use [diener](https://github.com/bkchr/diener/) to switch to this branch: `diener - update --branch "polkadot-v0.8.26" --substrate`. Update Cargo.lock (to do this, you can run `cargo build` and then - ctrl+c once it finishes fetching and begins compiling) - 1. Push the **Polkadot** `release-v0.8.26` branch to Github: `git push origin refs/heads/release-v0.8.26` -1. NOACTION: The current HEAD of the release-candidate branch is tagged `v0.8.26-rc1` -1. NOACTION: A draft release and runtime WASMs are created for this release-candidate automatically. A link to the draft - release will be linked in the internal Polkadot matrix channel. -1. NOACTION: A new Github issue is created containing a checklist of manual steps to be completed before we are - confident with the release. This will be linked in Matrix. -1. Complete the steps in the issue created in step 4, signing them off as completed -1. (optional) If a fix is required to the release-candidate: - 1. Merge the fix with `master` first - 1. Cherry-pick the commit from `master` to `release-v0.8.26`, fixing any merge conflicts. Try to avoid unnecessarily - bumping crates. - 1. Push the release-candidate branch to Github - this is now the new release- candidate - 1. Depending on the cherry-picked changes, it may be necessary to perform some or all of the manual tests again. - 1. If there are **Substrate** changes required, these should be cherry-picked to the Substrate `polkadot-v0.8.26` - branch and pushed, and the version of Substrate used in **Polkadot** updated using `cargo update -p sp-io` -1. Once happy with the release-candidate, tag the current top commit in the release candidate branch and push to Github: - `git tag -s -m 'v0.8.26' v0.8.26; git push --tags` -1. NOACTION: The HEAD of the `release` branch will be tagged with `v0.8.26`, and a final draft release will be created - on Github. - -## Security releases - -Occasionally there may be changes that need to be made to the most recently released version of Polkadot, without taking -*every* change to `master` since the last release. For example, in the event of a security vulnerability being found, -where releasing a fixed version is a matter of some expediency. In cases like this, the fix should first be merged with -master, cherry-picked to a branch forked from `release`, tested, and then finally merged with `release`. A sensible -versioning scheme for changes like this is `vX.Y.Z-1`. diff --git a/polkadot/doc/release-checklist.md b/polkadot/doc/release-checklist.md deleted file mode 100644 index 8c57791fed1..00000000000 --- a/polkadot/doc/release-checklist.md +++ /dev/null @@ -1,91 +0,0 @@ - -# Notes - -## Burn In - -Ensure that Parity DevOps has run the new release on Westend, Kusama, and Polkadot validators for at least 12 hours -prior to publishing the release. - -## Build Artifacts - -Add any necessary assets to the release. They should include: - -* Linux binary -* GPG signature of the Linux binary -* SHA256 of binary -* Source code -* Wasm binaries of any runtimes - -## Release notes - -The release notes should list: - -* The priority of the release (i.e., how quickly users should upgrade) - this is based on the max priority of any - *client* changes. -* Which native runtimes and their versions are included -* The proposal hashes of the runtimes as built with [srtool](https://gitlab.com/chevdor/srtool) -* Any changes in this release that are still awaiting audit - -The release notes may also list: - -* Free text at the beginning of the notes mentioning anything important regarding this release -* Notable changes (those labelled with B[1-9]-* labels) separated into sections - -## Spec Version - -A runtime upgrade must bump the spec number. This may follow a pattern with the client release (e.g. runtime v12 -corresponds to v0.8.12, even if the current runtime is not v11). - -## Old Migrations Removed - -Any previous `on_runtime_upgrade` functions from old upgrades must be removed to prevent them from executing a second -time. The `on_runtime_upgrade` function can be found in `runtime//src/lib.rs`. - -## New Migrations - -Ensure that any migrations that are required due to storage or logic changes are included in the `on_runtime_upgrade` -function of the appropriate pallets. - -## Extrinsic Ordering - -Offline signing libraries depend on a consistent ordering of call indices and functions. Compare the metadata of the -current and new runtimes and ensure that the `module index, call index` tuples map to the same set of functions. In case -of a breaking change, increase `transaction_version`. - -To verify the order has not changed, you may manually start the following [Github -Action](https://github.com/paritytech/polkadot/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. - -The things to look for in the output are lines like: - * `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for `Identity` has changed - * `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. - * If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` - -Note: Adding new functions to the runtime does not constitute a breaking change as long as the indexes did not change. - -## Proxy Filtering - -The runtime contains proxy filters that map proxy types to allowable calls. If the new runtime contains any new calls, -verify that the proxy filters are up to date to include them. - -## Benchmarks - -There are three benchmarking machines reserved for updating the weights at release-time. To initialise a benchmark run -for each production runtime (`westend`, `kusama`, `polkadot`): -* Go to https://gitlab.parity.io/parity/polkadot/-/pipelines?page=1&scope=branches&ref=master -* Click the link to the last pipeline run for master -* Start each of the manual jobs: - * `update_westend_weights` - * `update_polkadot_weights` - * `update_kusama_weights` -* When these jobs have completed (it takes a few hours), a git PATCH file will be available to download as an artifact. -* On your local machine, branch off master -* Download the patch file and apply it to your branch with `git patch patchfile.patch` -* Commit the changes to your branch and submit a PR against master -* The weights should be (Currently manually) checked to make sure there are no big outliers (i.e., twice or half the - weight). - -## Polkadot JS - -Ensure that a release of [Polkadot JS API](https://github.com/polkadot-js/api) contains any new types or interfaces -necessary to interact with the new runtime. diff --git a/polkadot/node/service/README.adoc b/polkadot/node/service/README.adoc deleted file mode 100644 index 2196d546780..00000000000 --- a/polkadot/node/service/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot Service - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/polkadot/parachain/README.adoc b/polkadot/parachain/README.adoc deleted file mode 100644 index 8650919e64e..00000000000 --- a/polkadot/parachain/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot Parachain - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/polkadot/primitives/README.adoc b/polkadot/primitives/README.adoc deleted file mode 100644 index 0e5c9412f00..00000000000 --- a/polkadot/primitives/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot primitives - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/polkadot/runtime/polkadot/README.adoc b/polkadot/runtime/polkadot/README.adoc deleted file mode 100644 index 33373310819..00000000000 --- a/polkadot/runtime/polkadot/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot Runtime - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/polkadot/src/README.adoc b/polkadot/src/README.adoc deleted file mode 100644 index 4ec8e18d8af..00000000000 --- a/polkadot/src/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot Src - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/polkadot/statement-table/README.adoc b/polkadot/statement-table/README.adoc deleted file mode 100644 index a4da4dee80f..00000000000 --- a/polkadot/statement-table/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Polkadot Statement table - -placeholder -//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159) diff --git a/substrate/.maintain/getgoing.sh b/substrate/.maintain/getgoing.sh deleted file mode 100644 index 98f360837d0..00000000000 --- a/substrate/.maintain/getgoing.sh +++ /dev/null @@ -1,6 +0,0 @@ -/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -brew install openssl cmake -curl https://sh.rustup.rs -sSf | sh -source ~/.cargo/env -cargo install --git https://github.com/paritytech/substrate subkey -cargo install --git https://github.com/paritytech/substrate substrate diff --git a/substrate/.maintain/runtime-dep.py b/substrate/.maintain/runtime-dep.py deleted file mode 100755 index 3198bb3e266..00000000000 --- a/substrate/.maintain/runtime-dep.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 - -# To run this script, you need to install the 'toml' python package and install the 'graphviz' package: -# pip install toml -# sudo apt-get install graphviz -# the first parameter is the runtime folder -# python ./.maintain/runtime-dep.py ./substrate/runtime | dot -Tpng -o output.png -import sys -import os -import toml - -if len(sys.argv) != 2: - print("needs the runtime folder.") - sys.exit(-1) - -runtime_dir = sys.argv[1] - -files = [os.path.join(runtime_dir, f, 'Cargo.toml') for f in os.listdir(runtime_dir) if os.path.isfile(os.path.join(runtime_dir, f, 'Cargo.toml')) and f != 'example'] - -print("digraph G {") - - -PREFIX = "substrate-runtime-" - -for f in files: - manifest = toml.load(f) - - package_name = manifest['package']['name'] - deps = [d for d in manifest['dependencies'].keys() if d.startswith(PREFIX)] - - for d in deps: - print(" \"{}\" -> \"{}\";".format(package_name, d)) - -print("}") diff --git a/substrate/.maintain/update-deps.sh b/substrate/.maintain/update-deps.sh deleted file mode 100755 index cd6b7c85382..00000000000 --- a/substrate/.maintain/update-deps.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -- -set -eu -case $0 in - (/*) dir=${0%/*}/;; - (*/*) dir=./${0%/*};; - (*) dir=.;; -esac - -find "$dir/.." -name Cargo.lock -execdir cargo update \; diff --git a/substrate/bin/node/cli/doc/shell-completion.adoc b/substrate/bin/node/cli/doc/shell-completion.md similarity index 75% rename from substrate/bin/node/cli/doc/shell-completion.adoc rename to substrate/bin/node/cli/doc/shell-completion.md index 168f00994fb..3f009a04373 100644 --- a/substrate/bin/node/cli/doc/shell-completion.adoc +++ b/substrate/bin/node/cli/doc/shell-completion.md @@ -1,12 +1,11 @@ +# Shell completion -== Shell completion - -The Substrate cli command supports shell auto-completion. For this to work, you will need to run the completion script matching your build and system. +The Substrate cli command supports shell auto-completion. For this to work, you will need to run the +completion script matching your build and system. Assuming you built a release version using `cargo build --release` and use `bash` run the following: -[source, shell] -source target/release/completion-scripts/substrate.bash +`source target/release/completion-scripts/substrate.bash` You can find completion scripts for: - bash @@ -17,25 +16,19 @@ You can find completion scripts for: To make this change persistent, you can proceed as follows: -.First install - -[source, shell] ----- +```shell COMPL_DIR=$HOME/.completion mkdir -p $COMPL_DIR cp -f target/release/completion-scripts/substrate.bash $COMPL_DIR/ echo "source $COMPL_DIR/substrate.bash" >> $HOME/.bash_profile source $HOME/.bash_profile ----- - -.Update +``` When you build a new version of Substrate, the following will ensure your auto-completion script matches the current binary: -[source, shell] ----- +```shell COMPL_DIR=$HOME/.completion mkdir -p $COMPL_DIR cp -f target/release/completion-scripts/substrate.bash $COMPL_DIR/ source $HOME/.bash_profile ----- +``` diff --git a/substrate/client/cli/README.adoc b/substrate/client/cli/README.adoc deleted file mode 100644 index fc58908fdf2..00000000000 --- a/substrate/client/cli/README.adoc +++ /dev/null @@ -1,6 +0,0 @@ - -= Substrate CLI - -Substrate CLI library - -include::doc/shell-completion.adoc[] diff --git a/substrate/docs/README.adoc b/substrate/docs/README.adoc deleted file mode 100644 index 3537e346a66..00000000000 --- a/substrate/docs/README.adoc +++ /dev/null @@ -1,522 +0,0 @@ -= Substrate -:Author: Substrate developers -:Revision: 0.2.0 -:toc: -:sectnums: - -== Intro in one sentence - -Substrate is a next-generation framework for blockchain innovation. - -== Description - -At its heart, Substrate is a combination of three technologies: https://webassembly.org/[WebAssembly], https://libp2p.io/[Libp2p] and GRANDPA Consensus. About GRANDPA, see this https://hackmd.io/Jd0byWX0RiqFiXUVC78Bdw?view#GRANDPA[definition], https://medium.com/polkadot-network/grandpa-block-finality-in-polkadot-an-introduction-part-1-d08a24a021b5[introduction] and https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf[formal specification]. It is both a library for building new blockchains and a "skeleton key" of a blockchain client, able to synchronize to any Substrate-based chain. - -Substrate chains have three distinct features that make them "next-generation": a dynamic, self-defining state-transition function; light-client functionality from day one; and a progressive consensus algorithm with fast block production and adaptive, definite finality. The STF, encoded in WebAssembly, is known as the "runtime". This defines the `execute_block` function, and can specify everything from the staking algorithm, transaction semantics, logging mechanisms and procedures for replacing any aspect of itself or of the blockchain's state ("governance"). Because the runtime is entirely dynamic all of these can be switched out or upgraded at any time. A Substrate chain is very much a "living organism". - -See also https://www.parity.io/what-is-substrate/. - -== Usage - -Substrate is still an early stage project, and while it has already been used as the basis of major projects like Polkadot, using it is still a significant undertaking. In particular, you should have a good knowledge of blockchain concepts and basic cryptography. Terminology like header, block, client, hash, transaction and signature should be familiar. At present you will need a working knowledge of Rust to be able to do anything interesting (though eventually, we aim for this not to be the case). - -Substrate is designed for use in one of three ways: - -**1. Trivial**: By running the Substrate binary `substrate` and configuring it with a genesis block that includes the current demonstration runtime. In this case, you just build Substrate, configure a JSON file, and launch your own blockchain. This affords you the least amount of customizability, primarily allowing you to change the genesis parameters of the various included runtime modules such as balances, staking, block-period, fees, and governance. - -**2. Modular**: By hacking together pallets built with Substrate FRAME into a new runtime and possibly altering or reconfiguring the Substrate client's block authoring logic. This affords you a very large amount of freedom over your blockchain's logic, letting you change data types, add or remove modules, and crucially, add your own modules. Much can be changed without touching the block authoring logic (since it is generic). If this is the case, then the existing Substrate binary can be used for block authoring and syncing. If the block authoring logic needs to be tweaked, then a new, altered block authoring binary must be built as a separate project and used by validators. This is how the Polkadot relay chain is built and should suffice for almost all circumstances in the near to mid-term. - -**3. Generic**: The entire FRAME can be ignored and the entire runtime designed and implemented from scratch. If desired, this can be done in a language other than Rust, provided it can target WebAssembly. If the runtime can be made compatible with the existing client's block authoring logic, then you can simply construct a new genesis block from your Wasm blob and launch your chain with the existing Rust-based Substrate client. If not, then you'll need to alter the client's block authoring logic accordingly. This is probably a useless option for most projects right now, but provides complete flexibility allowing for a long-term, far-reaching upgrade path for the Substrate paradigm. - -=== The Basics of Substrate - -Substrate is a blockchain platform with a completely generic state transition function. That said, it does come with both standards and conventions (particularly regarding the Runtime Module Library) regarding underlying data structures. Roughly speaking, these core data types correspond to +trait+s in terms of the actual non-negotiable standard and generic +struct+s in terms of the convention. - -``` -Header := Parent + ExtrinsicsRoot + StorageRoot + Digest -Block := Header + Extrinsics + Justifications -``` - -=== Extrinsics - -Extrinsics in Substrate are pieces of information from "the outside world" that are contained in the blocks of the chain. You might think "ahh, that means *transactions*": in fact, no. Extrinsics fall into two broad categories of which only one is *transactions*. The other is known as *inherents*. The difference between these two is that transactions are signed and gossiped on the network and can be deemed useful *per se*. This fits the mold of what you would call transactions in Bitcoin or Ethereum. - -Inherents, meanwhile, are not passed on the network and are not signed. They represent data which describes the environment but which cannot call upon anything to prove it such as a signature. Rather they are assumed to be "true" simply because a sufficiently large number of validators have agreed on them being reasonable. - -To give an example, there is the timestamp inherent, which sets the current timestamp of the block. This is not a fixed part of Substrate, but does come as part of FRAME to be used as desired. No signature could fundamentally prove that a block were authored at a given time in quite the same way that a signature can "prove" the desire to spend some particular funds. Rather, it is the business of each validator to ensure that they believe the timestamp is set to something reasonable before they agree that the block candidate is valid. - -Other examples include the parachain-heads extrinsic in Polkadot and the "note-missed-proposal" extrinsic used in FRAME to determine and punish or deactivate offline validators. - - -=== Runtime and API - -Substrate chains all have a runtime. The runtime is a WebAssembly "blob" that includes a number of entry-points. Some entry-points are required as part of the underlying Substrate specification. Others are merely convention and required for the default implementation of the Substrate client to be able to author blocks. - -If you want to develop a chain with Substrate, you will need to implement the `Core` trait. This `Core` trait generates an API with the minimum necessary functionality to interact with your runtime. A special macro is provided called `impl_runtime_apis!` that help you implement runtime API traits. All runtime API trait implementations need to be done in one call of the `impl_runtime_apis!` macro. All parameters and return values need to implement https://crates.io/crates/parity-codec[`parity-codec`] to be encodable and decodable. - -Here's a snippet of the Polkadot API implementation as of PoC-3: - -```rust -impl_runtime_apis! { - impl client_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) - } - } - // ---snip--- -} -``` - - -=== Inherent Extrinsics - -Substrate FRAME includes functionality for timestamps and slashing. If used, these rely on "trusted" external information being passed in via inherent extrinsics. The Substrate reference block authoring client software will expect to be able to call into the runtime API with collated data (in the case of the reference Substrate authoring client, this is merely the current timestamp and which nodes were offline) in order to return the appropriate extrinsics ready for inclusion. If new inherent extrinsic types and data are to be used in a modified runtime, then it is this function (and its argument type) that would change. - -=== Block-authoring Logic - -In Substrate, there is a major distinction between blockchain *syncing* and block *authoring* ("authoring" is a more general term for what is called "mining" in Bitcoin). The first case might be referred to as a "full node" (or "light node" - Substrate supports both): authoring necessarily requires a synced node and, therefore, all authoring clients must necessarily be able to synchronize. However, the reverse is not true. The primary functionality that authoring nodes have which is not in "sync nodes" is threefold: transaction queue logic, inherent transaction knowledge and BFT consensus logic. BFT consensus logic is provided as a core element of Substrate and can be ignored since it is only exposed in the SDK under the `authorities()` API entry. - -Transaction queue logic in Substrate is designed to be as generic as possible, allowing a runtime to express which transactions are fit for inclusion in a block through the `initialize_block` and `apply_extrinsic` calls. However, more subtle aspects like prioritization and replacement policy must currently be expressed "hard coded" as part of the blockchain's authoring code. That said, Substrate's reference implementation for a transaction queue should be sufficient for an initial chain implementation. - -Inherent extrinsic knowledge is again somewhat generic, and the actual construction of the extrinsics is, by convention, delegated to the "soft code" in the runtime. If ever there needs to be additional extrinsic information in the chain, then both the block authoring logic will need to be altered to provide it into the runtime and the runtime's `inherent_extrinsics` call will need to use this extra information in order to construct any additional extrinsic transactions for inclusion in the block. - -== Roadmap - -=== So far - -- 0.1 "PoC-1": PBFT consensus, Wasm runtime engine, basic runtime modules. -- 0.2 "PoC-2": Libp2p - -=== In progress - -- AfG consensus -- Improved PoS -- Smart contract runtime module - -=== The future - -- Splitting out runtime modules into separate repo -- Introduce substrate executable (the skeleton-key runtime) -- Introduce basic but extensible transaction queue and block-builder and place them in the executable. -- DAO runtime module -- Audit - -== Trying out Substrate Node - -Substrate Node is Substrate's pre-baked blockchain client. You can run a development node locally or configure a new chain and launch your own global testnet. - -=== On Mac and Ubuntu - -To get going as fast as possible, there is a simple script that installs all required dependencies and installs Substrate into your path. Just open a terminal and run: - -[source, shell] ----- -curl https://getsubstrate.io -sSf | bash ----- - -You can start a local Substrate development chain with running `substrate --dev`. - -To create your own global network/cryptocurrency, you'll need to make a new Substrate Node chain specification file ("chainspec"). - -First let's get a template chainspec that you can edit. We'll use the "staging" chain, a sort of default chain that the node comes pre-configured with: - -[source, shell] ----- -substrate build-spec --chain=staging > ~/chainspec.json ----- - -Now, edit `~/chainspec.json` in your editor. There are a lot of individual fields for each module, and one very large one which contains the WebAssembly code blob for this chain. The easiest field to edit is the block `period`. Change it to 10 (seconds): - -[source, json] ----- - "timestamp": { - "minimumPeriod": 10 - }, ----- - -Now with this new chainspec file, you can build a "raw" chain definition for your new chain: - -[source, shell] ----- -substrate build-spec --chain ~/chainspec.json --raw > ~/mychain.json ----- - -This can be fed into Substrate: - -[source, shell] ----- -substrate --chain ~/mychain.json ----- - -It won't do much until you start producing blocks though, so to do that you'll need to use the `--validator` option together with passing the seed for the account(s) that is configured to be the initial authorities: - -[source, shell] ----- -substrate --chain ~/mychain.json --validator ----- - -You can distribute `mychain.json` so that everyone can synchronize and (depending on your authorities list) validate on your chain. - - -== Building - -=== Hacking on Substrate - -If you'd actually like to hack on Substrate, you can just grab the source code and -build it. Ensure you have Rust and the support software installed: - -==== Linux and Mac - -For Unix-based operating systems, you should run the following commands: - -[source, shell] ----- -curl https://sh.rustup.rs -sSf | sh - -rustup update nightly -rustup target add wasm32-unknown-unknown --toolchain nightly -rustup update stable ----- - -You will also need to install the following packages: - - - Linux: -[source, shell] -sudo apt install cmake pkg-config libssl-dev git clang libclang-dev llvm - -- Linux on ARM: -`rust-lld` is required for linking wasm, but is missing on non Tier 1 platforms. -So, use this https://github.com/Plume-org/Plume/blob/master/script/wasm-deps.sh[script] -to build `lld` and create the symlink `/usr/bin/rust-lld` to the build binary. - - - Mac: -[source, shell] -brew install cmake pkg-config openssl git llvm - -To finish installation of Substrate, jump down to <>. - -==== Windows - -If you are trying to set up Substrate on Windows, you should do the following: - -1. First, you will need to download and install "Build Tools for Visual Studio:" - - * You can get it at this link: https://aka.ms/buildtools - * Run the installation file: `vs_buildtools.exe` - * Please ensure the Windows 10 SDK component is included when installing the Visual C++ Build Tools. - * image:https://i.imgur.com/zayVLmu.png[image] - * Restart your computer. - -2. Next, you need to install Rust: - - * Detailed instructions are provided by the https://doc.rust-lang.org/book/ch01-01-installation.html#installing-rustup-on-windows[Rust Book]. - * Download from: https://www.rust-lang.org/tools/install - * Run the installation file: `rustup-init.exe` - > Note that it should not prompt you to install vs_buildtools since you did it in step 1. - * Choose "Default Installation." - * To get started, you need Cargo's bin directory (%USERPROFILE%\.cargo\bin) in your PATH environment variable. Future applications will automatically have the correct environment, but you may need to restart your current shell. - -3. Then, you will need to run some commands in CMD to set up your Wasm Build Environment: - - rustup update nightly - rustup update stable - rustup target add wasm32-unknown-unknown --toolchain nightly - -4. Then, you need to install LLVM: https://releases.llvm.org/download.html - -5. Next, you need to install OpenSSL, which we will do with `vcpkg`: - - mkdir \Tools - cd \Tools - git clone https://github.com/Microsoft/vcpkg.git - cd vcpkg - .\bootstrap-vcpkg.bat - .\vcpkg.exe install openssl:x64-windows-static - -6. After, you need to add OpenSSL to your System Variables. Note that in order for the following commands to work, you need to use Windows Powershell: - - $env:OPENSSL_DIR = 'C:\Tools\vcpkg\installed\x64-windows-static' - $env:OPENSSL_STATIC = 'Yes' - [System.Environment]::SetEnvironmentVariable('OPENSSL_DIR', $env:OPENSSL_DIR, [System.EnvironmentVariableTarget]::User) - [System.Environment]::SetEnvironmentVariable('OPENSSL_STATIC', $env:OPENSSL_STATIC, [System.EnvironmentVariableTarget]::User) - -7. Finally, you need to install `cmake`: https://cmake.org/download/ - -==== Docker - -You can use https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux[Parity CI docker image] with all necessary dependencies to build Substrate: - -[source, shell] ----- -#run it in the folder with the Substrate source code -docker run --rm -it -w /shellhere/substrate \ - -v $(pwd):/shellhere/substrate \ - paritytech/ci-linux:production ----- - -You can find necessary cargo commands in <> - -==== Shared Steps - -Then, grab the Substrate source code: - -[source, shell] ----- -git clone https://github.com/paritytech/substrate.git -cd substrate ----- - -Then build the code: - -[source, shell] ----- -cargo build # Builds all native code ----- - -You can run all the tests if you like: - -[source, shell] -cargo test --all - -Or just run the tests of a specific package (i.e. `cargo test -p pallet-assets`) - -You can start a development chain with: - -[source, shell] -cargo run --release -- --dev - -Detailed logs may be shown by running the node with the following environment variables set: `RUST_LOG=debug RUST_BACKTRACE=1 cargo run --release \-- --dev`. - -If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain specification that have been endowed with a testnet DOTs. We'll give each node a name and expose them so they are listed on link:https://telemetry.polkadot.io/#/Local%20Testnet[Telemetry]. You'll need two terminal windows open. - -We'll start Alice's Substrate node first on default TCP port 30333 with their chain database stored locally at `/tmp/alice`. The Bootnode ID of Alice's node is `QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR`, which is generated from the `--node-key` value that we specify below: - -[source, shell] -cargo run --release \-- \ - --base-path /tmp/alice \ - --chain=local \ - --alice \ - --node-key 0000000000000000000000000000000000000000000000000000000000000001 \ - --telemetry-url 'ws://telemetry.polkadot.io:1024 0' \ - --validator - -In the second terminal, we'll run the following to start Bob's Substrate node on a different TCP port of 30334, and with their chain database stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect Bob's node to Alice's Bootnode ID on TCP port 30333: - -[source, shell] -cargo run --release \-- \ - --base-path /tmp/bob \ - --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR \ - --chain=local \ - --bob \ - --port 30334 \ - --telemetry-url 'ws://telemetry.polkadot.io:1024 0' \ - --validator - -Additional Substrate CLI usage options are available and may be shown by running `cargo run \-- --help`. - -[[flaming-fir]] -=== Joining the Flaming Fir Testnet - -Flaming Fir is the new testnet for Substrate master (2.0) to test the latest development features. Please note that master is not compatible with the BBQ Birch, Charred Cherry, Dried Danta or Emberic Elm testnets. Ensure you have the dependencies listed above before compiling. - -Since Flaming Fir is targeting the master branch we make absolutely no guarantees of stability and/or persistence of the network. We might reset the chain at any time if it is necessary to deploy new changes. Currently, the validators are running with a client built from `d013bd900`, if you build from this commit you should be able to successfully sync, later commits may not work as new breaking changes may be introduced in master. - -Latest known working version: `a2a0eb5398d6223e531455b4c155ef053a4a3a2b` - -[source, shell] ----- -git clone https://github.com/paritytech/substrate.git -cd substrate -git checkout -b flaming-fir a2a0eb5398d6223e531455b4c155ef053a4a3a2b ----- - -You can run the tests if you like: - -[source, shell] -cargo test --all - -Start your node: - -[source, shell] -cargo run --release \-- - -To see a list of command line options, enter: - -[source, shell] -cargo run --release \-- --help - -For example, you can choose a custom node name: - -[source, shell] -cargo run --release \-- --name my_custom_name - -If you are successful, you will see your node syncing at https://telemetry.polkadot.io/#/Flaming%20Fir - -=== Joining the Emberic Elm Testnet - -Emberic Elm is the testnet for Substrate 1.0. Please note that 1.0 is not compatible with the BBQ Birch, Charred Cherry, Dried Danta or Flaming Fir testnets. -In order to join the Emberic Elm testnet you should build from the `v1.0` branch. Ensure you have the dependencies listed above before compiling. - -[source, shell] ----- -git clone https://github.com/paritytech/substrate.git -cd substrate -git checkout -b v1.0 origin/v1.0 ----- - -You can then follow the same steps for building and running as described above in <>. - -== Key management - -Keys in Substrate are stored in the keystore in the file system. To store keys into this keystore, -you need to use one of the two provided RPC calls. If your keys are encrypted or should be encrypted -by the keystore, you need to provide the key using one of the cli arguments `--password`, -`--password-interactive` or `--password-filename`. - -=== Recommended RPC call - -For most users who want to run a validator node, the `author_rotateKeys` RPC call is sufficient. -The RPC call will generate `N` Session keys for you and return their public keys. `N` is the number -of session keys configured in the runtime. The output of the RPC call can be used as input for the -`session::set_keys` transaction. - -``` -curl -H 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"author_rotateKeys", "id":1 }' localhost:9933 -``` - -=== Advanced RPC call - -If the Session keys need to match a fixed seed, they can be set individually key by key. The RPC call -expects the key seed and the key type. The key types supported by default in Substrate are listed -https://github.com/paritytech/substrate/blob/master/core/primitives/src/crypto.rs#L767[here], but the -user can declare any key type. - -``` -curl -H 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"author_insertKey", "params":["KEY_TYPE", "SEED", "PUBLIC"],"id":1 }' localhost:9933 -``` - -`KEY_TYPE` - needs to be replaced with the 4-character key type identifier. -`SEED` - is the seed of the key. -`PUBLIC` - public key for the given key. - -== Documentation - -=== Viewing documentation for Substrate packages - -You can generate documentation for a Substrate Rust package and have it automatically open in your web browser using https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html#using-rustdoc-with-cargo[rustdoc with Cargo], -(of the The Rustdoc Book), by running the following command: - -``` -cargo doc --package --open -``` - -Replacing `` with one of the following (i.e. `cargo doc --package substrate --open`): - -* All Substrate Packages -[source, shell] -substrate -* Substrate Core -[source, shell] -substrate, substrate-cli, substrate-client, substrate-client-db, -substrate-consensus-common, substrate-consensus-rhd, -substrate-executor, substrate-finality-grandpa, substrate-keyring, substrate-keystore, substrate-network, -substrate-network-libp2p, substrate-primitives, substrate-rpc, substrate-rpc-servers, -substrate-serializer, substrate-service, substrate-service-test, substrate-state-db, -substrate-state-machine, substrate-telemetry, substrate-test-client, -substrate-test-runtime, substrate-transaction-graph, sp-transaction-pool, -substrate-trie -* Substrate Runtime -[source, shell] -sr-api, sr-io, sr-primitives, sr-sandbox, sr-std, sr-version -* FRAME Core -[source, shell] -frame-metadata, frame-support, frame-system -* FRAME Pallets -[source, shell] -pallet-assets, pallet-balances, pallet-consensus, pallet-contracts, pallet-council, pallet-democracy, pallet-example, -frame-executive, pallet-session, pallet-staking, pallet-timestamp, pallet-treasury -* Node -[source, shell] -node-cli, node-consensus, node-executor, node-network, node-primitives, kitchensink-runtime -* Subkey -[source, shell] -subkey - -=== Contributing to documentation for Substrate packages - -https://doc.rust-lang.org/1.9.0/book/documentation.html[Document source code] for Substrate packages by annotating the source code with documentation comments. - -Example (generic): -```markdown -/// Summary -/// -/// Description -/// -/// # Panics -/// -/// # Errors -/// -/// # Safety -/// -/// # Examples -/// -/// Summary of Example 1 -/// -/// ```rust -/// // insert example 1 code here -/// ``` -/// -``` - -* Important notes: -** Documentation comments must use annotations with a triple slash `///` -** Modules are documented using `//!` -``` -//! Summary (of module) -//! -//! Description (of module) -``` -* Special section header is indicated with a hash `#`. -** `Panics` section requires an explanation if the function triggers a panic -** `Errors` section is for describing conditions under which a function of method returns `Err(E)` if it returns a `Result` -** `Safety` section requires an explanation if the function is `unsafe` -** `Examples` section includes examples of using the function or method -* Code block annotations for examples are included between triple graves, as shown above. -Instead of including the programming language to use for syntax highlighting as the annotation -after the triple graves, alternative annotations include the `ignore`, `text`, `should_panic`, or `no_run`. -* Summary sentence is a short high level single sentence of its functionality -* Description paragraph is for details additional to the summary sentence -* Missing documentation annotations may be used to identify where to generate warnings with `#![warn(missing_docs)]` -or errors `#![deny(missing_docs)]` -* Hide documentation for items with `#[doc(hidden)]` - -=== Contributing to documentation (tests, extended examples, macros) for Substrate packages - -The code block annotations in the `# Example` section may be used as https://doc.rust-lang.org/1.9.0/book/documentation.html#documentation-as-tests[documentation as tests and for extended examples]. - -* Important notes: -** Rustdoc will automatically add a `main()` wrapper around the code block to test it -** https://doc.rust-lang.org/1.9.0/book/documentation.html#documenting-macros[Documenting macros]. -** Documentation as tests examples are included when running `cargo test` - -== Contributing - -=== Contributing Guidelines - -include::CONTRIBUTING.md[] - -=== Contributor Code of Conduct - -include::CODE_OF_CONDUCT.md[] - -== License - -https://github.com/paritytech/substrate/blob/master/LICENSE[LICENSE] diff --git a/substrate/docs/Structure.adoc b/substrate/docs/Structure.adoc deleted file mode 100644 index 6c810a83c51..00000000000 --- a/substrate/docs/Structure.adoc +++ /dev/null @@ -1,121 +0,0 @@ -= Structure -:Author: Substrate developers -:Revision: 0.3.0 -:toc: -:sectnums: - - -== Overview - -Substrate is split into multiple levels with increasing opinion and decreasing flexibility: - -* primitives -* client -* FRAME (formerly `srml`) - -Putting all these components together we have: - -* Integration Tests -* Node -* Node template -* Subkey - -=== Runtime - -* _found in_: `/primitives` -* _crates prefix_: `sp-` -* _constraints_: -** must be `[no_std]` -** crates may not (dev-)depend on crates in other subfolders of this repo - -In the lowest level, Substrate defines primitives, interfaces and traits to implement any on-chain Substrate transition system and its interactions with the outside world. This is the lowest level of abstraction and opinion that everything else builds upon. - -=== Client - -* _found in_: `/client` -* _crates prefix_: `sc-` -* _constraints_: -** crates may not (dev-)depend on any `frame-`-crates - -In the client you can find a set of crates to construct the outer substrate-node, implementing outer runtime interfaces, thus it depends on `runtime`. It provides the outer building blocks like transaction queue, networking layer, database backend, full* and light-client support. - -=== FRAME (formerly `srml`) - -* _found in_: `/frame` -* _crates prefix_: `frame-` and `pallet-` -* _constraints_: -** all crates that go on chain must be `[no_std]` -** must not (dev-)depend on anything in `/client` - -FRAME is a set of modules that implement specific transition functions and features one might want to have in their runtime. - -_Pallets_ are individual modules within _FRAME._ These are containers that host domain-specific logic. They have the `pallet-` prefix. For example, `pallet-staking` contains logic for staking tokens. - -There are a few crates with the `frame-` prefix. These do not contain domain-specific logic. Rather, they are the main FRAME support infrastructure. These are: - -- Executive -- Metadata -- Support -- System -- Utility - -=== Integration Tests - -* _found in_: `/test` -* _crates prefix_: `substrate-test` -* _constraints_: -** only helpers may be published -** purely testing crates must be `publish = false` - -All tests that have to pull (dev)-dependencies out of their subtree and would thus break the dependency rules are considered integration tests and should be stored in here. Only helper-crates in here shall be published, everything else is expected to be non-publish. - -=== Binaries and template - -* _found in_: `/bin` - -We also provide some binaries pulling from the components creating full applications. - -==== Node - -* _found in_: `/bin/node` - -The default (testing) application pulling together our recommended setup of substrate-client with a wasm-contracts-supporting frame-runtime. The node pulls it all together, constructs the (upgradable) runtime, and wires up the client around it. You can find an example client, which includes a full wasm-contracts chain in `node`. This is also what is being built and run if you do `cargo run`. - -==== Node Template - -* _found in_: `/bin/node-template` - -We also provide a template to get you started building your own node. - -==== Utils - -* _found in_: `/bin/utils` - -- **subkey** - Subkey is a client library to generate keys and sign transactions to send to a substrate node. -- **chain-spec-builder** - The chain spec builder builds a chain specification that includes a Substrate runtime compiled as WASM. To ensure proper functioning of the included runtime compile (or run) the chain spec builder binary in `--release` mode. - -== Internal Dependency Tree - -[ditaa] -.... -+---------------+ +----------------+ -| | | | -| runtime +<------+ frame | -| | | | -+------+-----+--+ +-------------+--+ - ^ ^ ^ - | +----------------+ | - | | | -+------+--------+ | | -| | | | -| client | +--+-------+--------+ -| +<---------+ | -+---------------+ | | - | test /bin/* | - | | - | | - +-------------------+ - -.... -- GitLab From 89bfdb15dab74359b91011578efa204ea9884b07 Mon Sep 17 00:00:00 2001 From: ordian Date: Mon, 4 Sep 2023 16:48:12 +0200 Subject: [PATCH 070/633] approval-voting: use proper hash when querying session info (#1387) --- polkadot/node/core/approval-voting/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 0087f8e1435..ddef736feab 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -2350,7 +2350,7 @@ async fn process_wakeup( match get_extended_session_info( session_info_provider, ctx.sender(), - block_entry.parent_hash(), + block_entry.block_hash(), block_entry.session(), ) .await -- GitLab From ddab7156b4d579516d81a8ae3b6233250bd2ba45 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 4 Sep 2023 16:58:32 +0200 Subject: [PATCH 071/633] [ci] Remove runtime-benchmarks from tests (#1335) * [ci] Remove runtime-benchmarks from tests * Update .gitlab/pipeline/test.yml Co-authored-by: Oliver Tale-Yazdi * remove ing * move benchmark tests to additional tests * rm -q option * try release profile * use testnet profile * move to a separate job * rm dup --------- Co-authored-by: Oliver Tale-Yazdi --- .gitlab/pipeline/test.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index c81750d49f9..d128cb09902 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -34,7 +34,7 @@ test-linux-stable: --locked \ --release \ --no-fail-fast \ - --features runtime-benchmarks,try-runtime,experimental \ + --features try-runtime,experimental \ --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} # run runtime-api tests with `enable-staging-api` feature on the 1st node - if [ ${CI_NODE_INDEX} == 1 ]; then time cargo nextest run -p sp-api-test --features enable-staging-api; fi @@ -92,7 +92,22 @@ test-linux-stable-additional-tests: --locked \ --release \ --features runtime-benchmarks,try-runtime - allow_failure: true + +# https://github.com/paritytech/ci_cd/issues/864 +test-linux-stable-runtime-benchmarks: + stage: test + extends: + - .docker-env + - .common-refs + - .run-immediately + - .pipeline-stopper-artifacts + variables: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + script: + - time cargo nextest run --features runtime-benchmarks benchmark --locked --cargo-profile testnet # these ones can be really slow so it's better to run them separately test-linux-stable-slow: -- GitLab From 01cdae878d2d6f71395abd6e4014136a9147bea4 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 4 Sep 2023 18:27:53 +0300 Subject: [PATCH 072/633] Extract block announce validation from `ChainSync` (#1170) --- substrate/client/network/common/src/sync.rs | 68 +-- .../sync/src/block_announce_validator.rs | 405 +++++++++++++++ substrate/client/network/sync/src/engine.rs | 153 +++--- .../client/network/sync/src/futures_stream.rs | 134 +++++ substrate/client/network/sync/src/lib.rs | 488 ++++-------------- substrate/client/network/sync/src/mock.rs | 15 +- substrate/client/utils/src/mpsc.rs | 10 + 7 files changed, 727 insertions(+), 546 deletions(-) create mode 100644 substrate/client/network/sync/src/block_announce_validator.rs create mode 100644 substrate/client/network/sync/src/futures_stream.rs diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index b142925aeb1..461c4ae411d 100644 --- a/substrate/client/network/common/src/sync.rs +++ b/substrate/client/network/common/src/sync.rs @@ -22,12 +22,12 @@ pub mod message; pub mod metrics; pub mod warp; -use crate::{role::Roles, types::ReputationChange}; +use crate::{role::Roles, sync::message::BlockAnnounce, types::ReputationChange}; use futures::Stream; use libp2p_identity::PeerId; -use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}; +use message::{BlockData, BlockRequest, BlockResponse}; use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock}; use sp_consensus::BlockOrigin; use sp_runtime::{ @@ -157,38 +157,6 @@ pub enum ImportResult { JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), } -/// Value polled from `ChainSync` -#[derive(Debug)] -pub enum PollResult { - Import(ImportResult), - Announce(PollBlockAnnounceValidation), -} - -/// Result of [`ChainSync::poll_block_announce_validation`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PollBlockAnnounceValidation { - /// The announcement failed at validation. - /// - /// The peer reputation should be decreased. - Failure { - /// Who sent the processed block announcement? - who: PeerId, - /// Should the peer be disconnected? - disconnect: bool, - }, - /// The announcement does not require further handling. - Nothing { - /// Who sent the processed block announcement? - who: PeerId, - /// Was this their new best block? - is_best: bool, - /// The announcement. - announce: BlockAnnounce, - }, - /// The block announcement should be skipped. - Skip, -} - /// Sync operation mode. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SyncMode { @@ -408,29 +376,14 @@ pub trait ChainSync: Send { /// Notify about finalization of the given block. fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); - /// Push a block announce validation. - /// - /// It is required that [`ChainSync::poll_block_announce_validation`] is called - /// to check for finished block announce validations. - fn push_block_announce_validation( + /// Notify about pre-validated block announcement. + fn on_validated_block_announce( &mut self, - who: PeerId, - hash: Block::Hash, - announce: BlockAnnounce, is_best: bool, + who: PeerId, + announce: &BlockAnnounce, ); - /// Poll block announce validation. - /// - /// Block announce validations can be pushed by using - /// [`ChainSync::push_block_announce_validation`]. - /// - /// This should be polled until it returns [`Poll::Pending`]. - fn poll_block_announce_validation( - &mut self, - cx: &mut std::task::Context<'_>, - ) -> Poll>; - /// 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. @@ -447,14 +400,7 @@ pub trait ChainSync: Send { ) -> Result>, String>; /// Advance the state of `ChainSync` - /// - /// Internally calls [`ChainSync::poll_block_announce_validation()`] and - /// this function should be polled until it returns [`Poll::Pending`] to - /// consume all pending events. - fn poll( - &mut self, - cx: &mut std::task::Context, - ) -> Poll>; + 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/sync/src/block_announce_validator.rs b/substrate/client/network/sync/src/block_announce_validator.rs new file mode 100644 index 00000000000..f083f9e29e4 --- /dev/null +++ b/substrate/client/network/sync/src/block_announce_validator.rs @@ -0,0 +1,405 @@ +// 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 . + +//! `BlockAnnounceValidator` is responsible for async validation of block announcements. + +use crate::futures_stream::FuturesStream; +use futures::{Future, FutureExt, Stream, StreamExt}; +use libp2p::PeerId; +use log::{debug, error, trace, warn}; +use sc_network_common::sync::message::BlockAnnounce; +use sp_consensus::block_validation::Validation; +use sp_runtime::traits::{Block as BlockT, Header, Zero}; +use std::{ + collections::{hash_map::Entry, HashMap}, + default::Default, + pin::Pin, + task::{Context, Poll}, +}; + +/// Log target for this file. +const LOG_TARGET: &str = "sync"; + +/// Maximum number of concurrent block announce validations. +/// +/// If the queue reaches the maximum, we drop any new block +/// announcements. +const MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS: usize = 256; + +/// Maximum number of concurrent block announce validations per peer. +/// +/// See [`MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS`] for more information. +const MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER: usize = 4; + +/// Item that yields [`Stream`] implementation of [`BlockAnnounceValidator`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum BlockAnnounceValidationResult { + /// The announcement failed at validation. + /// + /// The peer reputation should be decreased. + Failure { + /// The id of the peer that send us the announcement. + peer_id: PeerId, + /// Should the peer be disconnected? + disconnect: bool, + }, + /// The announcement was validated successfully and should be passed to [`crate::ChainSync`]. + Process { + /// The id of the peer that send us the announcement. + peer_id: PeerId, + /// Was this their new best block? + is_new_best: bool, + /// The announcement. + announce: BlockAnnounce, + }, + /// The block announcement should be skipped. + Skip { + /// The id of the peer that send us the announcement. + peer_id: PeerId, + }, +} + +impl BlockAnnounceValidationResult { + fn peer_id(&self) -> &PeerId { + match self { + BlockAnnounceValidationResult::Failure { peer_id, .. } | + BlockAnnounceValidationResult::Process { peer_id, .. } | + BlockAnnounceValidationResult::Skip { peer_id } => peer_id, + } + } +} + +/// Result of [`BlockAnnounceValidator::allocate_slot_for_block_announce_validation`]. +enum AllocateSlotForBlockAnnounceValidation { + /// Success, there is a slot for the block announce validation. + Allocated, + /// We reached the total maximum number of validation slots. + TotalMaximumSlotsReached, + /// We reached the maximum number of validation slots for the given peer. + MaximumPeerSlotsReached, +} + +pub(crate) struct BlockAnnounceValidator { + /// A type to check incoming block announcements. + validator: Box + Send>, + /// All block announcements that are currently being validated. + validations: FuturesStream< + Pin> + Send>>, + >, + /// Number of concurrent block announce validations per peer. + validations_per_peer: HashMap, +} + +impl BlockAnnounceValidator { + pub(crate) fn new( + validator: Box + Send>, + ) -> Self { + Self { + validator, + validations: Default::default(), + validations_per_peer: Default::default(), + } + } + + /// Push a block announce validation. + pub(crate) fn push_block_announce_validation( + &mut self, + peer_id: PeerId, + hash: B::Hash, + announce: BlockAnnounce, + is_best: bool, + ) { + let header = &announce.header; + let number = *header.number(); + debug!( + target: LOG_TARGET, + "Pre-validating received block announcement {:?} with number {:?} from {}", + hash, + number, + peer_id, + ); + + if number.is_zero() { + warn!( + target: LOG_TARGET, + "💔 Ignored genesis block (#0) announcement from {}: {}", + peer_id, + hash, + ); + return + } + + // Try to allocate a slot for this block announce validation. + match self.allocate_slot_for_block_announce_validation(&peer_id) { + AllocateSlotForBlockAnnounceValidation::Allocated => {}, + AllocateSlotForBlockAnnounceValidation::TotalMaximumSlotsReached => { + warn!( + target: LOG_TARGET, + "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots are occupied.", + number, + hash, + peer_id, + ); + return + }, + AllocateSlotForBlockAnnounceValidation::MaximumPeerSlotsReached => { + warn!( + target: LOG_TARGET, + "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots for this peer are occupied.", + number, + hash, + peer_id, + ); + return + }, + } + + // Let external validator check the block announcement. + let assoc_data = announce.data.as_ref().map_or(&[][..], |v| v.as_slice()); + let future = self.validator.validate(header, assoc_data); + + self.validations.push( + async move { + match future.await { + Ok(Validation::Success { is_new_best }) => { + let is_new_best = is_new_best || is_best; + + trace!( + target: LOG_TARGET, + "Block announcement validated successfully: from {}: {:?}. Local best: {}.", + peer_id, + announce.summary(), + is_new_best, + ); + + BlockAnnounceValidationResult::Process { is_new_best, announce, peer_id } + }, + Ok(Validation::Failure { disconnect }) => { + debug!( + target: LOG_TARGET, + "Block announcement validation failed: from {}, block {:?}. Disconnect: {}.", + peer_id, + hash, + disconnect, + ); + + BlockAnnounceValidationResult::Failure { peer_id, disconnect } + }, + Err(e) => { + debug!( + target: LOG_TARGET, + "💔 Ignoring block announcement validation from {} of block {:?} due to internal error: {}.", + peer_id, + hash, + e, + ); + + BlockAnnounceValidationResult::Skip { peer_id } + }, + } + } + .boxed(), + ); + } + + /// Checks if there is a slot for a block announce validation. + /// + /// The total number and the number per peer of concurrent block announce validations + /// is capped. + /// + /// Returns [`AllocateSlotForBlockAnnounceValidation`] to inform about the result. + /// + /// # Note + /// + /// It is *required* to call [`Self::deallocate_slot_for_block_announce_validation`] when the + /// validation is finished to clear the slot. + fn allocate_slot_for_block_announce_validation( + &mut self, + peer_id: &PeerId, + ) -> AllocateSlotForBlockAnnounceValidation { + if self.validations.len() >= MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS { + return AllocateSlotForBlockAnnounceValidation::TotalMaximumSlotsReached + } + + match self.validations_per_peer.entry(*peer_id) { + Entry::Vacant(entry) => { + entry.insert(1); + AllocateSlotForBlockAnnounceValidation::Allocated + }, + Entry::Occupied(mut entry) => { + if *entry.get() < MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER { + *entry.get_mut() += 1; + AllocateSlotForBlockAnnounceValidation::Allocated + } else { + AllocateSlotForBlockAnnounceValidation::MaximumPeerSlotsReached + } + }, + } + } + + /// Should be called when a block announce validation is finished, to update the slots + /// of the peer that send the block announce. + fn deallocate_slot_for_block_announce_validation(&mut self, peer_id: &PeerId) { + match self.validations_per_peer.entry(*peer_id) { + Entry::Vacant(_) => { + error!( + target: LOG_TARGET, + "💔 Block announcement validation from peer {} finished for a slot that was not allocated!", + peer_id, + ); + }, + Entry::Occupied(mut entry) => match entry.get().checked_sub(1) { + Some(value) => + if value == 0 { + entry.remove(); + } else { + *entry.get_mut() = value; + }, + None => { + entry.remove(); + + error!( + target: LOG_TARGET, + "Invalid (zero) block announce validation slot counter for peer {peer_id}.", + ); + debug_assert!( + false, + "Invalid (zero) block announce validation slot counter for peer {peer_id}.", + ); + }, + }, + } + } +} + +impl Stream for BlockAnnounceValidator { + type Item = BlockAnnounceValidationResult; + + /// Poll for finished block announce validations. The stream never terminates. + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let validation = futures::ready!(self.validations.poll_next_unpin(cx)) + .expect("`FuturesStream` never terminates; qed"); + self.deallocate_slot_for_block_announce_validation(validation.peer_id()); + + Poll::Ready(Some(validation)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::block_announce_validator::AllocateSlotForBlockAnnounceValidation; + use libp2p::PeerId; + use sp_consensus::block_validation::DefaultBlockAnnounceValidator; + use substrate_test_runtime_client::runtime::Block; + + #[test] + fn allocate_one_validation_slot() { + let mut validator = + BlockAnnounceValidator::::new(Box::new(DefaultBlockAnnounceValidator {})); + let peer_id = PeerId::random(); + + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + } + + #[test] + fn allocate_validation_slots_for_two_peers() { + let mut validator = + BlockAnnounceValidator::::new(Box::new(DefaultBlockAnnounceValidator {})); + let peer_id_1 = PeerId::random(); + let peer_id_2 = PeerId::random(); + + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id_1), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id_2), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + } + + #[test] + fn maximum_validation_slots_per_peer() { + let mut validator = + BlockAnnounceValidator::::new(Box::new(DefaultBlockAnnounceValidator {})); + let peer_id = PeerId::random(); + + for _ in 0..MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER { + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + } + + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::MaximumPeerSlotsReached, + )); + } + + #[test] + fn validation_slots_per_peer_deallocated() { + let mut validator = + BlockAnnounceValidator::::new(Box::new(DefaultBlockAnnounceValidator {})); + let peer_id = PeerId::random(); + + for _ in 0..MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER { + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + } + + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::MaximumPeerSlotsReached, + )); + + validator.deallocate_slot_for_block_announce_validation(&peer_id); + + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::Allocated, + )); + } + + #[test] + fn maximum_validation_slots_for_all_peers() { + let mut validator = + BlockAnnounceValidator::::new(Box::new(DefaultBlockAnnounceValidator {})); + + for _ in 0..MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS { + validator.validations.push( + futures::future::ready(BlockAnnounceValidationResult::Skip { + peer_id: PeerId::random(), + }) + .boxed(), + ); + } + + let peer_id = PeerId::random(); + assert!(matches!( + validator.allocate_slot_for_block_announce_validation(&peer_id), + AllocateSlotForBlockAnnounceValidation::TotalMaximumSlotsReached, + )); + } +} diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 65bd56a2895..9b97bf2b7c3 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -20,6 +20,9 @@ //! to tip and keep the blockchain up to date with network updates. use crate::{ + block_announce_validator::{ + BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, + }, service::{self, chain_sync::ToServiceCommand}, ChainSync, ClientError, SyncingService, }; @@ -45,7 +48,7 @@ use sc_network_common::{ sync::{ message::{BlockAnnounce, BlockAnnouncesHandshake, BlockState}, warp::WarpSyncParams, - BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, PollBlockAnnounceValidation, SyncEvent, + BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, SyncEvent, }, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -239,6 +242,9 @@ pub struct SyncingEngine { /// Number of inbound peers accepted so far. num_in_peers: usize, + /// Async processor of block announce validations. + block_announce_validator: BlockAnnounceValidatorStream, + /// A cache for the data that was associated to a block announcement. block_announce_data_cache: LruMap>, @@ -352,7 +358,6 @@ where protocol_id, fork_id, roles, - block_announce_validator, max_parallel_downloads, max_blocks_per_request, warp_sync_params, @@ -389,6 +394,9 @@ where peers: HashMap::new(), block_announce_data_cache: LruMap::new(ByLength::new(cache_capacity)), block_announce_protocol_name, + block_announce_validator: BlockAnnounceValidatorStream::new( + block_announce_validator, + ), num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), service_rx, @@ -453,9 +461,9 @@ where } } - fn update_peer_info(&mut self, who: &PeerId) { - if let Some(info) = self.chain_sync.peer_info(who) { - if let Some(ref mut peer) = self.peers.get_mut(who) { + fn update_peer_info(&mut self, peer_id: &PeerId) { + if let Some(info) = self.chain_sync.peer_info(peer_id) { + if let Some(ref mut peer) = self.peers.get_mut(peer_id) { peer.info.best_hash = info.best_hash; peer.info.best_number = info.best_number; } @@ -463,14 +471,16 @@ where } /// Process the result of the block announce validation. - pub fn process_block_announce_validation_result( + fn process_block_announce_validation_result( &mut self, - validation_result: PollBlockAnnounceValidation, + validation_result: BlockAnnounceValidationResult, ) { match validation_result { - PollBlockAnnounceValidation::Skip => {}, - PollBlockAnnounceValidation::Nothing { is_best: _, who, announce } => { - self.update_peer_info(&who); + BlockAnnounceValidationResult::Skip { peer_id: _ } => {}, + BlockAnnounceValidationResult::Process { is_new_best, peer_id, announce } => { + self.chain_sync.on_validated_block_announce(is_new_best, peer_id, &announce); + + self.update_peer_info(&peer_id); if let Some(data) = announce.data { if !data.is_empty() { @@ -478,41 +488,29 @@ where } } }, - PollBlockAnnounceValidation::Failure { who, disconnect } => { + BlockAnnounceValidationResult::Failure { peer_id, disconnect } => { if disconnect { self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); } - self.network_service.report_peer(who, rep::BAD_BLOCK_ANNOUNCEMENT); + self.network_service.report_peer(peer_id, rep::BAD_BLOCK_ANNOUNCEMENT); }, } } /// Push a block announce validation. - /// - /// It is required that [`ChainSync::poll_block_announce_validation`] is - /// called later to check for finished validations. The result of the validation - /// needs to be passed to [`SyncingEngine::process_block_announce_validation_result`] - /// to finish the processing. - /// - /// # Note - /// - /// This will internally create a future, but this future will not be registered - /// in the task before being polled once. So, it is required to call - /// [`ChainSync::poll_block_announce_validation`] to ensure that the future is - /// registered properly and will wake up the task when being ready. pub fn push_block_announce_validation( &mut self, - who: PeerId, + peer_id: PeerId, announce: BlockAnnounce, ) { let hash = announce.header.hash(); - let peer = match self.peers.get_mut(&who) { + let peer = match self.peers.get_mut(&peer_id) { Some(p) => p, None => { - log::error!(target: "sync", "Received block announce from disconnected peer {}", who); + log::error!(target: "sync", "Received block announce from disconnected peer {}", peer_id); debug_assert!(false); return }, @@ -525,7 +523,8 @@ where BlockState::Normal => false, }; - self.chain_sync.push_block_announce_validation(who, hash, announce, is_best); + self.block_announce_validator + .push_block_announce_validation(peer_id, hash, announce, is_best); } } @@ -558,10 +557,10 @@ where .or_else(|| self.block_announce_data_cache.get(&hash).cloned()) .unwrap_or_default(); - for (who, ref mut peer) in self.peers.iter_mut() { + for (peer_id, ref mut peer) in self.peers.iter_mut() { let inserted = peer.known_blocks.insert(hash); if inserted { - log::trace!(target: "sync", "Announcing block {:?} to {}", hash, who); + log::trace!(target: "sync", "Announcing block {:?} to {}", hash, peer_id); let message = BlockAnnounce { header: header.clone(), state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, @@ -656,14 +655,14 @@ where } } }, - ToServiceCommand::JustificationImported(peer, hash, number, success) => { + ToServiceCommand::JustificationImported(peer_id, hash, number, success) => { self.chain_sync.on_justification_import(hash, number, success); if !success { - log::info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer, hash); + log::info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer_id, hash); self.network_service - .disconnect_peer(peer, self.block_announce_protocol_name.clone()); + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); self.network_service.report_peer( - peer, + peer_id, ReputationChange::new_fatal("Invalid justification"), ); } @@ -698,8 +697,11 @@ where let _ = tx.send(self.chain_sync.num_sync_requests()); }, ToServiceCommand::PeersInfo(tx) => { - let peers_info = - self.peers.iter().map(|(id, peer)| (*id, peer.info.clone())).collect(); + let peers_info = self + .peers + .iter() + .map(|(peer_id, peer)| (*peer_id, peer.info.clone())) + .collect(); let _ = tx.send(peers_info); }, ToServiceCommand::OnBlockFinalized(hash, header) => @@ -742,14 +744,6 @@ where if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { self.last_notification_io = Instant::now(); self.push_block_announce_validation(remote, announce); - - // Make sure that the newly added block announce validation future - // was polled once to be registered in the task. - if let Poll::Ready(res) = - self.chain_sync.poll_block_announce_validation(cx) - { - self.process_block_announce_validation_result(res) - } } else { log::warn!(target: "sub-libp2p", "Failed to decode block announce"); } @@ -770,10 +764,14 @@ where } } - // poll `ChainSync` last because of a block announcement was received through the - // event stream between `SyncingEngine` and `Protocol` and the validation finished - // right after it as queued, the resulting block request (if any) can be sent right away. - while let Poll::Ready(result) = self.chain_sync.poll(cx) { + // Drive `ChainSync`. + while let Poll::Ready(()) = self.chain_sync.poll(cx) {} + + // Poll block announce validations last, because if a block announcement was received + // through the event stream between `SyncingEngine` and `Protocol` and the validation + // finished right after it is queued, the resulting block request (if any) can be sent + // right away. + while let Poll::Ready(Some(result)) = self.block_announce_validator.poll_next_unpin(cx) { self.process_block_announce_validation_result(result); } @@ -783,15 +781,15 @@ where /// Called by peer when it is disconnecting. /// /// Returns a result if the handshake of this peer was indeed accepted. - pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) -> Result<(), ()> { - if let Some(info) = self.peers.remove(&peer) { - if self.important_peers.contains(&peer) { - log::warn!(target: "sync", "Reserved peer {} disconnected", peer); + pub fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) -> Result<(), ()> { + if let Some(info) = self.peers.remove(&peer_id) { + if self.important_peers.contains(&peer_id) { + log::warn!(target: "sync", "Reserved peer {} disconnected", peer_id); } else { - log::debug!(target: "sync", "{} disconnected", peer); + log::debug!(target: "sync", "{} disconnected", peer_id); } - if !self.default_peers_set_no_slot_connected_peers.remove(&peer) && + if !self.default_peers_set_no_slot_connected_peers.remove(&peer_id) && info.inbound && info.info.roles.is_full() { match self.num_in_peers.checked_sub(1) { @@ -808,9 +806,10 @@ where } } - self.chain_sync.peer_disconnected(&peer); - self.event_streams - .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer)).is_ok()); + self.chain_sync.peer_disconnected(&peer_id); + self.event_streams.retain(|stream| { + stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok() + }); Ok(()) } else { Err(()) @@ -824,35 +823,35 @@ where /// from. pub fn on_sync_peer_connected( &mut self, - who: PeerId, + peer_id: PeerId, status: &BlockAnnouncesHandshake, sink: NotificationsSink, inbound: bool, ) -> Result<(), ()> { - log::trace!(target: "sync", "New peer {} {:?}", who, status); + log::trace!(target: "sync", "New peer {} {:?}", peer_id, status); - if self.peers.contains_key(&who) { - log::error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", who); + if self.peers.contains_key(&peer_id) { + log::error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", peer_id); debug_assert!(false); return Err(()) } if status.genesis_hash != self.genesis_hash { - self.network_service.report_peer(who, rep::GENESIS_MISMATCH); + self.network_service.report_peer(peer_id, rep::GENESIS_MISMATCH); - if self.important_peers.contains(&who) { + if self.important_peers.contains(&peer_id) { log::error!( target: "sync", "Reserved peer id `{}` is on a different chain (our genesis: {} theirs: {})", - who, + peer_id, self.genesis_hash, status.genesis_hash, ); - } else if self.boot_node_ids.contains(&who) { + } else if self.boot_node_ids.contains(&peer_id) { log::error!( target: "sync", "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", - who, + peer_id, self.genesis_hash, status.genesis_hash, ); @@ -867,7 +866,7 @@ where return Err(()) } - let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&who); + let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&peer_id); let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; // make sure to accept no more than `--in-peers` many full nodes @@ -875,7 +874,7 @@ where status.roles.is_full() && inbound && self.num_in_peers == self.max_in_peers { - log::debug!(target: "sync", "All inbound slots have been consumed, rejecting {who}"); + log::debug!(target: "sync", "All inbound slots have been consumed, rejecting {peer_id}"); return Err(()) } @@ -885,7 +884,7 @@ where self.default_peers_set_no_slot_connected_peers.len() + this_peer_reserved_slot { - log::debug!(target: "sync", "Too many full nodes, rejecting {}", who); + log::debug!(target: "sync", "Too many full nodes, rejecting {}", peer_id); return Err(()) } @@ -893,7 +892,7 @@ where (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light { // Make sure that not all slots are occupied by light clients. - log::debug!(target: "sync", "Too many light nodes, rejecting {}", who); + log::debug!(target: "sync", "Too many light nodes, rejecting {}", peer_id); return Err(()) } @@ -911,7 +910,7 @@ where }; let req = if peer.info.roles.is_full() { - match self.chain_sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { + match self.chain_sync.new_peer(peer_id, peer.info.best_hash, peer.info.best_number) { Ok(req) => req, Err(BadPeer(id, repu)) => { self.network_service.report_peer(id, repu); @@ -922,22 +921,22 @@ where None }; - log::debug!(target: "sync", "Connected {}", who); + log::debug!(target: "sync", "Connected {}", peer_id); - self.peers.insert(who, peer); + self.peers.insert(peer_id, peer); if no_slot_peer { - self.default_peers_set_no_slot_connected_peers.insert(who); + self.default_peers_set_no_slot_connected_peers.insert(peer_id); } else if inbound && status.roles.is_full() { self.num_in_peers += 1; } if let Some(req) = req { - self.chain_sync.send_block_request(who, req); + self.chain_sync.send_block_request(peer_id, req); } self.event_streams - .retain(|stream| stream.unbounded_send(SyncEvent::PeerConnected(who)).is_ok()); + .retain(|stream| stream.unbounded_send(SyncEvent::PeerConnected(peer_id)).is_ok()); Ok(()) } diff --git a/substrate/client/network/sync/src/futures_stream.rs b/substrate/client/network/sync/src/futures_stream.rs new file mode 100644 index 00000000000..c33d582345b --- /dev/null +++ b/substrate/client/network/sync/src/futures_stream.rs @@ -0,0 +1,134 @@ +// 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 . + +//! A wrapper for [`FuturesUnordered`] that wakes the task up once a new future is pushed +//! for it to be polled automatically. It's [`Stream`] never terminates. + +use futures::{stream::FuturesUnordered, Future, Stream, StreamExt}; +use std::{ + pin::Pin, + task::{Context, Poll, Waker}, +}; + +/// Wrapper around [`FuturesUnordered`] that wakes a task up automatically. +pub struct FuturesStream { + futures: FuturesUnordered, + waker: Option, +} + +/// Surprizingly, `#[derive(Default)]` doesn't work on [`FuturesStream`]. +impl Default for FuturesStream { + fn default() -> FuturesStream { + FuturesStream { futures: Default::default(), waker: None } + } +} + +impl FuturesStream { + /// Push a future for processing. + pub fn push(&mut self, future: F) { + self.futures.push(future); + + if let Some(waker) = self.waker.take() { + waker.wake(); + } + } + + /// The number of futures in the stream. + pub fn len(&self) -> usize { + self.futures.len() + } +} + +impl Stream for FuturesStream { + type Item = ::Output; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let Poll::Ready(Some(result)) = self.futures.poll_next_unpin(cx) else { + self.waker = Some(cx.waker().clone()); + + return Poll::Pending + }; + + Poll::Ready(Some(result)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::future::{BoxFuture, FutureExt}; + + /// [`Stream`] implementation for [`FuturesStream`] relies on the undocumented + /// feature that [`FuturesUnordered`] can be polled and repeatedly yield + /// `Poll::Ready(None)` before any futures are added into it. + #[tokio::test] + async fn empty_futures_unordered_can_be_polled() { + let mut unordered = FuturesUnordered::>::default(); + + futures::future::poll_fn(|cx| { + assert_eq!(unordered.poll_next_unpin(cx), Poll::Ready(None)); + assert_eq!(unordered.poll_next_unpin(cx), Poll::Ready(None)); + + Poll::Ready(()) + }) + .await; + } + + /// [`Stream`] implementation for [`FuturesStream`] relies on the undocumented + /// feature that [`FuturesUnordered`] can be polled and repeatedly yield + /// `Poll::Ready(None)` after all the futures in it have resolved. + #[tokio::test] + async fn deplenished_futures_unordered_can_be_polled() { + let mut unordered = FuturesUnordered::>::default(); + + unordered.push(futures::future::ready(()).boxed()); + assert_eq!(unordered.next().await, Some(())); + + futures::future::poll_fn(|cx| { + assert_eq!(unordered.poll_next_unpin(cx), Poll::Ready(None)); + assert_eq!(unordered.poll_next_unpin(cx), Poll::Ready(None)); + + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn empty_futures_stream_yields_pending() { + let mut stream = FuturesStream::>::default(); + + futures::future::poll_fn(|cx| { + assert_eq!(stream.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn futures_stream_resolves_futures_and_yields_pending() { + let mut stream = FuturesStream::default(); + stream.push(futures::future::ready(17)); + + futures::future::poll_fn(|cx| { + assert_eq!(stream.poll_next_unpin(cx), Poll::Ready(Some(17))); + assert_eq!(stream.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + }) + .await; + } +} diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 175c1c43f46..0c2013b1497 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -37,9 +37,7 @@ use crate::{ use codec::{Decode, DecodeAll, Encode}; use extra_requests::ExtraRequests; -use futures::{ - channel::oneshot, stream::FuturesUnordered, task::Poll, Future, FutureExt, StreamExt, -}; +use futures::{channel::oneshot, task::Poll, Future, FutureExt}; use libp2p::{request_response::OutboundFailure, PeerId}; use log::{debug, error, info, trace, warn}; use prost::Message; @@ -66,16 +64,12 @@ use sc_network_common::{ warp::{EncodedProof, WarpProofRequest, WarpSyncParams, WarpSyncPhase, WarpSyncProgress}, BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, - OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, SyncMode, - SyncState, SyncStatus, + OpaqueStateResponse, PeerInfo, PeerRequest, SyncMode, SyncState, SyncStatus, }, }; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; -use sp_consensus::{ - block_validation::{BlockAnnounceValidator, Validation}, - BlockOrigin, BlockStatus, -}; +use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ traits::{ Block as BlockT, CheckedSub, Hash, HashingFor, Header as HeaderT, NumberFor, One, @@ -85,7 +79,7 @@ use sp_runtime::{ }; use std::{ - collections::{hash_map::Entry, HashMap, HashSet}, + collections::{HashMap, HashSet}, iter, ops::Range, pin::Pin, @@ -94,7 +88,9 @@ use std::{ pub use service::chain_sync::SyncingService; +mod block_announce_validator; mod extra_requests; +mod futures_stream; mod schema; pub mod block_request_handler; @@ -117,17 +113,6 @@ const MAX_DOWNLOAD_AHEAD: u32 = 2048; /// common block of a node. const MAX_BLOCKS_TO_LOOK_BACKWARDS: u32 = MAX_DOWNLOAD_AHEAD / 2; -/// Maximum number of concurrent block announce validations. -/// -/// If the queue reaches the maximum, we drop any new block -/// announcements. -const MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS: usize = 256; - -/// Maximum number of concurrent block announce validations per peer. -/// -/// See [`MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS`] for more information. -const MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER: usize = 4; - /// Pick the state to sync as the latest finalized number minus this. const STATE_SYNC_FINALITY_THRESHOLD: u32 = 8; @@ -307,19 +292,12 @@ pub struct ChainSync { fork_targets: HashMap>, /// A set of peers for which there might be potential block requests allowed_requests: AllowedRequests, - /// A type to check incoming block announcements. - block_announce_validator: Box + Send>, /// Maximum number of peers to ask the same blocks in parallel. max_parallel_downloads: u32, /// Maximum blocks per request. max_blocks_per_request: u32, /// Total number of downloaded blocks. downloaded_blocks: usize, - /// All block announcement that are currently being validated. - block_announce_validation: - FuturesUnordered> + Send>>>, - /// Stats per peer about the number of concurrent block announce validations. - block_announce_validation_per_peer_stats: HashMap, /// State sync in progress, if any. state_sync: Option>, /// Warp sync in progress, if any. @@ -424,51 +402,6 @@ impl PeerSyncState { } } -/// Result of [`ChainSync::block_announce_validation`]. -#[derive(Debug, Clone, PartialEq, Eq)] -enum PreValidateBlockAnnounce { - /// The announcement failed at validation. - /// - /// The peer reputation should be decreased. - Failure { - /// Who sent the processed block announcement? - who: PeerId, - /// Should the peer be disconnected? - disconnect: bool, - }, - /// The pre-validation was sucessful and the announcement should be - /// further processed. - Process { - /// Is this the new best block of the peer? - is_new_best: bool, - /// The id of the peer that send us the announcement. - who: PeerId, - /// The announcement. - announce: BlockAnnounce, - }, - /// The announcement validation returned an error. - /// - /// An error means that *this* node failed to validate it because some internal error happened. - /// If the block announcement was invalid, [`Self::Failure`] is the correct variant to express - /// this. - Error { who: PeerId }, - /// The block announcement should be skipped. - /// - /// This should *only* be returned when there wasn't a slot registered - /// for this block announcement validation. - Skip, -} - -/// Result of [`ChainSync::has_slot_for_block_announce_validation`]. -enum HasSlotForBlockAnnounceValidation { - /// Yes, there is a slot for the block announce validation. - Yes, - /// We reached the total maximum number of validation slots. - TotalMaximumSlotsReached, - /// We reached the maximum number of validation slots for the given peer. - MaximumPeerSlotsReached, -} - impl ChainSyncT for ChainSync where B: BlockT, @@ -692,7 +625,7 @@ where self.extra_justifications.reset(); } - // The implementation is similar to on_block_announce with unknown parent hash. + // The implementation is similar to `on_validated_block_announce` with unknown parent hash. fn set_sync_fork_request( &mut self, mut peers: Vec, @@ -1107,119 +1040,88 @@ where } } - fn push_block_announce_validation( + fn on_validated_block_announce( &mut self, - who: PeerId, - hash: B::Hash, - announce: BlockAnnounce, is_best: bool, + who: PeerId, + announce: &BlockAnnounce, ) { - let header = &announce.header; - let number = *header.number(); - debug!( - target: "sync", - "Pre-validating received block announcement {:?} with number {:?} from {}", - hash, - number, - who, - ); + let number = *announce.header.number(); + let hash = announce.header.hash(); + let parent_status = + self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown); + let known_parent = parent_status != BlockStatus::Unknown; + let ancient_parent = parent_status == BlockStatus::InChainPruned; - if number.is_zero() { - self.block_announce_validation.push( - async move { - warn!( - target: "sync", - "💔 Ignored genesis block (#0) announcement from {}: {}", - who, - hash, - ); - PreValidateBlockAnnounce::Skip - } - .boxed(), - ); + let known = self.is_known(&hash); + let peer = if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!(target: "sync", "💔 Called `on_validated_block_announce` with a bad peer ID"); + return + }; + + if let PeerSyncState::AncestorSearch { .. } = peer.state { + trace!(target: "sync", "Peer {} is in the ancestor search state.", who); return } - // Check if there is a slot for this block announce validation. - match self.has_slot_for_block_announce_validation(&who) { - HasSlotForBlockAnnounceValidation::Yes => {}, - HasSlotForBlockAnnounceValidation::TotalMaximumSlotsReached => { - self.block_announce_validation.push( - async move { - warn!( - target: "sync", - "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots are occupied.", - number, - hash, - who, - ); - PreValidateBlockAnnounce::Skip - } - .boxed(), - ); - return - }, - HasSlotForBlockAnnounceValidation::MaximumPeerSlotsReached => { - self.block_announce_validation.push(async move { - warn!( - target: "sync", - "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots for this peer are occupied.", - number, - hash, - who, - ); - PreValidateBlockAnnounce::Skip - }.boxed()); - return - }, + if is_best { + // update their best block + peer.best_number = number; + peer.best_hash = hash; } - // Let external validator check the block announcement. - let assoc_data = announce.data.as_ref().map_or(&[][..], |v| v.as_slice()); - let future = self.block_announce_validator.validate(header, assoc_data); + // If the announced block is the best they have and is not ahead of us, our common number + // is either one further ahead or it's the one they just announced, if we know about it. + if is_best { + if known && self.best_queued_number >= number { + self.update_peer_common_number(&who, number); + } else if announce.header.parent_hash() == &self.best_queued_hash || + known_parent && self.best_queued_number >= number + { + self.update_peer_common_number(&who, number.saturating_sub(One::one())); + } + } + self.allowed_requests.add(&who); - self.block_announce_validation.push( - async move { - match future.await { - Ok(Validation::Success { is_new_best }) => PreValidateBlockAnnounce::Process { - is_new_best: is_new_best || is_best, - announce, - who, - }, - Ok(Validation::Failure { disconnect }) => { - debug!( - target: "sync", - "Block announcement validation of block {:?} from {} failed", - hash, - who, - ); - PreValidateBlockAnnounce::Failure { who, disconnect } - }, - Err(e) => { - debug!( - target: "sync", - "💔 Block announcement validation of block {:?} errored: {}", - hash, - e, - ); - PreValidateBlockAnnounce::Error { who } - }, - } + // known block case + if known || self.is_already_downloading(&hash) { + trace!(target: "sync", "Known block announce from {}: {}", who, hash); + if let Some(target) = self.fork_targets.get_mut(&hash) { + target.peers.insert(who); } - .boxed(), - ); - } + return + } - fn poll_block_announce_validation( - &mut self, - cx: &mut std::task::Context, - ) -> Poll> { - match self.block_announce_validation.poll_next_unpin(cx) { - Poll::Ready(Some(res)) => { - self.peer_block_announce_validation_finished(&res); - Poll::Ready(self.finish_block_announce_validation(res)) - }, - _ => Poll::Pending, + if ancient_parent { + trace!( + target: "sync", + "Ignored ancient block announced from {}: {} {:?}", + who, + hash, + announce.header, + ); + return + } + + if self.status().state == SyncState::Idle { + trace!( + target: "sync", + "Added sync target for block announced from {}: {} {:?}", + who, + hash, + announce.summary(), + ); + self.fork_targets + .entry(hash) + .or_insert_with(|| ForkTarget { + number, + parent_hash: Some(*announce.header.parent_hash()), + peers: Default::default(), + }) + .peers + .insert(who); } } @@ -1319,10 +1221,7 @@ where .map_err(|error: codec::Error| error.to_string()) } - fn poll( - &mut self, - cx: &mut std::task::Context, - ) -> Poll> { + fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { // Should be called before `process_outbound_requests` to ensure // that a potential target block is directly leading to requests. if let Some(warp_sync) = &mut self.warp_sync { @@ -1339,10 +1238,6 @@ where } } - if let Poll::Ready(announce) = self.poll_block_announce_validation(cx) { - return Poll::Ready(announce) - } - Poll::Pending } @@ -1395,7 +1290,6 @@ where protocol_id: ProtocolId, fork_id: &Option, roles: Roles, - block_announce_validator: Box + Send>, max_parallel_downloads: u32, max_blocks_per_request: u32, warp_sync_params: Option>, @@ -1430,12 +1324,9 @@ where queue_blocks: Default::default(), fork_targets: Default::default(), allowed_requests: Default::default(), - block_announce_validator, max_parallel_downloads, max_blocks_per_request, downloaded_blocks: 0, - block_announce_validation: Default::default(), - block_announce_validation_per_peer_stats: Default::default(), state_sync: None, warp_sync: None, import_existing: false, @@ -1586,186 +1477,6 @@ where self.allowed_requests.set_all(); } - /// Checks if there is a slot for a block announce validation. - /// - /// The total number and the number per peer of concurrent block announce validations - /// is capped. - /// - /// Returns [`HasSlotForBlockAnnounceValidation`] to inform about the result. - /// - /// # Note - /// - /// It is *required* to call [`Self::peer_block_announce_validation_finished`] when the - /// validation is finished to clear the slot. - fn has_slot_for_block_announce_validation( - &mut self, - peer: &PeerId, - ) -> HasSlotForBlockAnnounceValidation { - if self.block_announce_validation.len() >= MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS { - return HasSlotForBlockAnnounceValidation::TotalMaximumSlotsReached - } - - match self.block_announce_validation_per_peer_stats.entry(*peer) { - Entry::Vacant(entry) => { - entry.insert(1); - HasSlotForBlockAnnounceValidation::Yes - }, - Entry::Occupied(mut entry) => { - if *entry.get() < MAX_CONCURRENT_BLOCK_ANNOUNCE_VALIDATIONS_PER_PEER { - *entry.get_mut() += 1; - HasSlotForBlockAnnounceValidation::Yes - } else { - HasSlotForBlockAnnounceValidation::MaximumPeerSlotsReached - } - }, - } - } - - /// Should be called when a block announce validation is finished, to update the slots - /// of the peer that send the block announce. - fn peer_block_announce_validation_finished( - &mut self, - res: &PreValidateBlockAnnounce, - ) { - let peer = match res { - PreValidateBlockAnnounce::Failure { who, .. } | - PreValidateBlockAnnounce::Process { who, .. } | - PreValidateBlockAnnounce::Error { who } => who, - PreValidateBlockAnnounce::Skip => return, - }; - - match self.block_announce_validation_per_peer_stats.entry(*peer) { - Entry::Vacant(_) => { - error!( - target: "sync", - "💔 Block announcement validation from peer {} finished for that no slot was allocated!", - peer, - ); - }, - Entry::Occupied(mut entry) => { - *entry.get_mut() = entry.get().saturating_sub(1); - if *entry.get() == 0 { - entry.remove(); - } - }, - } - } - - /// This will finish processing of the block announcement. - fn finish_block_announce_validation( - &mut self, - pre_validation_result: PreValidateBlockAnnounce, - ) -> PollBlockAnnounceValidation { - let (announce, is_best, who) = match pre_validation_result { - PreValidateBlockAnnounce::Failure { who, disconnect } => { - debug!( - target: "sync", - "Failed announce validation: {:?}, disconnect: {}", - who, - disconnect, - ); - return PollBlockAnnounceValidation::Failure { who, disconnect } - }, - PreValidateBlockAnnounce::Process { announce, is_new_best, who } => - (announce, is_new_best, who), - PreValidateBlockAnnounce::Error { .. } | PreValidateBlockAnnounce::Skip => { - debug!( - target: "sync", - "Ignored announce validation", - ); - return PollBlockAnnounceValidation::Skip - }, - }; - - trace!( - target: "sync", - "Finished block announce validation: from {:?}: {:?}. local_best={}", - who, - announce.summary(), - is_best, - ); - - let number = *announce.header.number(); - let hash = announce.header.hash(); - let parent_status = - self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown); - let known_parent = parent_status != BlockStatus::Unknown; - let ancient_parent = parent_status == BlockStatus::InChainPruned; - - let known = self.is_known(&hash); - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!(target: "sync", "💔 Called on_block_announce with a bad peer ID"); - return PollBlockAnnounceValidation::Nothing { is_best, who, announce } - }; - - if let PeerSyncState::AncestorSearch { .. } = peer.state { - trace!(target: "sync", "Peer state is ancestor search."); - return PollBlockAnnounceValidation::Nothing { is_best, who, announce } - } - - if is_best { - // update their best block - peer.best_number = number; - peer.best_hash = hash; - } - - // If the announced block is the best they have and is not ahead of us, our common number - // is either one further ahead or it's the one they just announced, if we know about it. - if is_best { - if known && self.best_queued_number >= number { - self.update_peer_common_number(&who, number); - } else if announce.header.parent_hash() == &self.best_queued_hash || - known_parent && self.best_queued_number >= number - { - self.update_peer_common_number(&who, number - One::one()); - } - } - self.allowed_requests.add(&who); - - // known block case - if known || self.is_already_downloading(&hash) { - trace!(target: "sync", "Known block announce from {}: {}", who, hash); - if let Some(target) = self.fork_targets.get_mut(&hash) { - target.peers.insert(who); - } - return PollBlockAnnounceValidation::Nothing { is_best, who, announce } - } - - if ancient_parent { - trace!( - target: "sync", - "Ignored ancient block announced from {}: {} {:?}", - who, - hash, - announce.header, - ); - return PollBlockAnnounceValidation::Nothing { is_best, who, announce } - } - - if self.status().state == SyncState::Idle { - trace!( - target: "sync", - "Added sync target for block announced from {}: {} {:?}", - who, - hash, - announce.summary(), - ); - self.fork_targets - .entry(hash) - .or_insert_with(|| ForkTarget { - number, - parent_hash: Some(*announce.header.parent_hash()), - peers: Default::default(), - }) - .peers - .insert(who); - } - - PollBlockAnnounceValidation::Nothing { is_best, who, announce } - } - /// 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. @@ -3162,14 +2873,13 @@ fn validate_blocks( mod test { use super::*; use crate::service::network::NetworkServiceProvider; - use futures::{executor::block_on, future::poll_fn}; + use futures::executor::block_on; use sc_block_builder::BlockBuilderProvider; use sc_network_common::{ role::Role, - sync::message::{BlockData, BlockState, FromBlock}, + sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}, }; use sp_blockchain::HeaderBackend; - use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, @@ -3183,7 +2893,6 @@ mod test { // internally we should process the response as the justification not being available. let client = Arc::new(TestClientBuilder::new().build()); - let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let peer_id = PeerId::random(); let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); @@ -3195,7 +2904,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - block_announce_validator, 1, 64, None, @@ -3262,7 +2970,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 1, 64, None, @@ -3344,23 +3051,16 @@ mod test { /// Send a block annoucnement for the given `header`. fn send_block_announce( header: Header, - peer_id: &PeerId, + peer_id: PeerId, sync: &mut ChainSync, ) { - let block_annnounce = BlockAnnounce { + let announce = BlockAnnounce { header: header.clone(), state: Some(BlockState::Best), data: Some(Vec::new()), }; - sync.push_block_announce_validation(*peer_id, header.hash(), block_annnounce, true); - - // Poll until we have procssed the block announcement - block_on(poll_fn(|cx| loop { - if sync.poll_block_announce_validation(cx).is_pending() { - break Poll::Ready(()) - } - })) + sync.on_validated_block_announce(true, peer_id, &announce); } /// Create a block response from the given `blocks`. @@ -3444,7 +3144,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 5, 64, None, @@ -3491,7 +3190,7 @@ mod test { assert!(sync.block_requests().is_empty()); // Let peer2 announce a fork of block 3 - send_block_announce(block3_fork.header().clone(), &peer_id2, &mut sync); + send_block_announce(block3_fork.header().clone(), peer_id2, &mut sync); // Import and tell sync that we now have the fork. block_on(client.import(BlockOrigin::Own, block3_fork.clone())).unwrap(); @@ -3500,13 +3199,13 @@ mod test { let block4 = build_block_at(block3_fork.hash(), false); // Let peer2 announce block 4 and check that sync wants to get the block. - send_block_announce(block4.header().clone(), &peer_id2, &mut sync); + send_block_announce(block4.header().clone(), peer_id2, &mut sync); let request = get_block_request(&mut sync, FromBlock::Hash(block4.hash()), 2, &peer_id2); // Peer1 announces the same block, but as the common block is still `1`, sync will request // block 2 again. - send_block_announce(block4.header().clone(), &peer_id1, &mut sync); + send_block_announce(block4.header().clone(), peer_id1, &mut sync); let request2 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id1); @@ -3571,7 +3270,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 5, 64, None, @@ -3647,7 +3345,7 @@ mod test { sync.queue_blocks.clear(); // Let peer2 announce that it finished syncing - send_block_announce(best_block.header().clone(), &peer_id2, &mut sync); + send_block_announce(best_block.header().clone(), peer_id2, &mut sync); let (peer1_req, peer2_req) = sync.block_requests().into_iter().fold((None, None), |res, req| { @@ -3729,7 +3427,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 5, 64, None, @@ -3754,7 +3451,7 @@ mod test { sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) .unwrap(); - send_block_announce(fork_blocks.last().unwrap().header().clone(), &peer_id1, &mut sync); + send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); let mut request = get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); @@ -3872,7 +3569,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 5, 64, None, @@ -3897,7 +3593,7 @@ mod test { sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) .unwrap(); - send_block_announce(fork_blocks.last().unwrap().header().clone(), &peer_id1, &mut sync); + send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); let mut request = get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); @@ -4017,7 +3713,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 1, 64, None, @@ -4039,7 +3734,7 @@ mod test { // Create a "new" header and announce it let mut header = blocks[0].header().clone(); header.number = 4; - send_block_announce(header, &peer_id1, &mut sync); + send_block_announce(header, peer_id1, &mut sync); assert!(sync.fork_targets.len() == 1); sync.peer_disconnected(&peer_id1); @@ -4063,7 +3758,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - Box::new(DefaultBlockAnnounceValidator), 1, 64, None, @@ -4107,7 +3801,6 @@ mod test { #[test] fn sync_restart_removes_block_but_not_justification_requests() { let mut client = Arc::new(TestClientBuilder::new().build()); - let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); @@ -4117,7 +3810,6 @@ mod test { ProtocolId::from("test-protocol-name"), &Some(String::from("test-fork-id")), Roles::from(&Role::Full), - block_announce_validator, 1, 64, None, diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index 838c6cf7667..d37095c17d2 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -24,7 +24,7 @@ use libp2p::PeerId; use sc_network_common::sync::{ message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, - OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, SyncStatus, + OpaqueBlockResponse, PeerInfo, SyncStatus, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -71,17 +71,12 @@ mockall::mock! { success: bool, ); fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); - fn push_block_announce_validation( + fn on_validated_block_announce( &mut self, - who: PeerId, - hash: Block::Hash, - announce: BlockAnnounce, is_best: bool, + who: PeerId, + announce: &BlockAnnounce, ); - fn poll_block_announce_validation<'a>( - &mut self, - cx: &mut std::task::Context<'a>, - ) -> Poll>; fn peer_disconnected(&mut self, who: &PeerId); fn metrics(&self) -> Metrics; fn block_response_into_blocks( @@ -92,7 +87,7 @@ mockall::mock! { fn poll<'a>( &mut self, cx: &mut std::task::Context<'a>, - ) -> Poll>; + ) -> Poll<()>; fn send_block_request( &mut self, who: PeerId, diff --git a/substrate/client/utils/src/mpsc.rs b/substrate/client/utils/src/mpsc.rs index 36e44be5e29..039e03f9e61 100644 --- a/substrate/client/utils/src/mpsc.rs +++ b/substrate/client/utils/src/mpsc.rs @@ -123,6 +123,11 @@ impl TracingUnboundedSender { s }) } + + /// The number of elements in the channel (proxy function to [`async_channel::Sender`]). + pub fn len(&self) -> usize { + self.inner.len() + } } impl TracingUnboundedReceiver { @@ -139,6 +144,11 @@ impl TracingUnboundedReceiver { s }) } + + /// The number of elements in the channel (proxy function to [`async_channel::Receiver`]). + pub fn len(&self) -> usize { + self.inner.len() + } } impl Drop for TracingUnboundedReceiver { -- GitLab From 076529ea550dc7362b695dbc20d04f3c718da9d4 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 4 Sep 2023 21:33:20 +0200 Subject: [PATCH 073/633] Contracts: Update read_sandbox (#1390) * Update runtime.rs * Fix * Revert "Update runtime.rs" This reverts commit 808f026a835b1f2707f640799454a50fd3a8be7b. * nit mono-repo fixes --- substrate/frame/contracts/build.rs | 2 +- substrate/frame/contracts/src/tests.rs | 4 +++- substrate/frame/contracts/src/wasm/runtime.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substrate/frame/contracts/build.rs b/substrate/frame/contracts/build.rs index 7817ace9c98..42bc45d563d 100644 --- a/substrate/frame/contracts/build.rs +++ b/substrate/frame/contracts/build.rs @@ -53,7 +53,7 @@ fn get_latest_version() -> u16 { fn main() -> Result<(), Box> { let out_dir = std::env::var("OUT_DIR")?; let path = std::path::Path::new(&out_dir).join("migration_codegen.rs"); - let mut f = std::fs::File::create(&path)?; + let mut f = std::fs::File::create(path)?; let version = get_latest_version(); write!( f, diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 0c0a2f7f932..8d6c5c5ac72 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -564,7 +564,9 @@ where { let fixture_path = [ // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder - std::env::var("CARGO_MANIFEST_DIR").as_deref().unwrap_or("frame/contracts"), + std::env::var("CARGO_MANIFEST_DIR") + .as_deref() + .unwrap_or("substrate/frame/contracts"), "/fixtures/", fixture_name, ".wat", diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 4bc00388f72..4fd52b471a0 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -608,7 +608,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { let mut bound_checked = memory .get(ptr..ptr + D::max_encoded_len() as usize) .ok_or_else(|| Error::::OutOfBounds)?; - let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked) + let decoded = D::decode_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } -- GitLab From 7217a5da65142d104903eacffcdfa54b093cc645 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 5 Sep 2023 12:31:57 +1000 Subject: [PATCH 074/633] rust docs: add simple analytics (#1377) * inject simple analytics * comments * fix chown * comments * doc features --- .gitlab/pipeline/build.yml | 21 ++++++++++++++++++++- substrate/.maintain/rustdocs-release.sh | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 636f7e47afa..20fed5df3df 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -114,11 +114,30 @@ build-rustdoc: 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 --workspace --no-deps + - time cargo doc --features try-runtime,experimental --workspace --no-deps - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs # FIXME: remove me after CI image gets nonroot - chown -R nonroot:nonroot ./crate-docs + # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into + # all .html files + - | + inject_simple_analytics() { + local path="$1" + local script_content="" + + # Function that inject script into the head of an html file using sed. + process_file() { + local file="$1" + echo "Adding Simple Analytics script to $file" + sed -i "s||$script_content|" "$file" + } + export -f process_file + + # Modify .html files in parallel using xargs, otherwise it can take a long time. + find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {} + } + inject_simple_analytics "./crate-docs" - echo "" > ./crate-docs/index.html build-implementers-guide: diff --git a/substrate/.maintain/rustdocs-release.sh b/substrate/.maintain/rustdocs-release.sh index 2a1e141e63a..091f9289e4e 100755 --- a/substrate/.maintain/rustdocs-release.sh +++ b/substrate/.maintain/rustdocs-release.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash # set -x -# This script manages the deployment of Substrate rustdocs to https://paritytech.github.io/substrate/. +# This script used to manage the deployment of Substrate rustdocs to https://paritytech.github.io/substrate/. +# It is no longer used anywhere, and only here for historical/demonstration purposes. # - With `deploy` sub-command, it will checkout the passed-in branch/tag ref, build the rustdocs # locally (this takes some time), update the `index.html` index page, and push it to remote # `gh-pages` branch. So users running this command need to have write access to the remote -- GitLab From a14691804dce0815defa955450fecf1d9f2ca1c4 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:13:19 +0200 Subject: [PATCH 075/633] Move Relay-Specific Shared Code to One Place (#1193) * add common libs * asset hubs * add westend * bridge hubs * collectives * contracts * emulated tests * parachain bin * delete collectives constants and update docs * integration tests should have apache license (some missing, some needed changing) * propagate features * fmt --- Cargo.lock | 6 + cumulus/parachains/common/Cargo.toml | 11 ++ .../src/constants.rs => common/src/kusama.rs} | 31 ++--- cumulus/parachains/common/src/lib.rs | 4 + .../constants.rs => common/src/polkadot.rs} | 34 ++--- .../src/constants.rs => common/src/rococo.rs} | 4 +- .../constants.rs => common/src/westend.rs} | 4 +- .../assets/asset-hub-kusama/Cargo.toml | 1 + .../assets/asset-hub-kusama/src/lib.rs | 25 ++-- .../src/tests/hrmp_channels.rs | 27 ++-- .../assets/asset-hub-kusama/src/tests/mod.rs | 25 ++-- .../src/tests/reserve_transfer.rs | 27 ++-- .../assets/asset-hub-kusama/src/tests/send.rs | 27 ++-- .../src/tests/set_xcm_versions.rs | 25 ++-- .../assets/asset-hub-kusama/src/tests/swap.rs | 37 +++--- .../asset-hub-kusama/src/tests/teleport.rs | 25 ++-- .../assets/asset-hub-polkadot/Cargo.toml | 1 + .../assets/asset-hub-polkadot/src/lib.rs | 25 ++-- .../src/tests/hrmp_channels.rs | 27 ++-- .../asset-hub-polkadot/src/tests/mod.rs | 25 ++-- .../src/tests/reserve_transfer.rs | 27 ++-- .../asset-hub-polkadot/src/tests/send.rs | 27 ++-- .../src/tests/set_xcm_versions.rs | 25 ++-- .../asset-hub-polkadot/src/tests/teleport.rs | 25 ++-- .../assets/asset-hub-westend/Cargo.toml | 1 + .../assets/asset-hub-westend/src/lib.rs | 25 ++-- .../assets/asset-hub-westend/src/tests/mod.rs | 25 ++-- .../src/tests/reserve_transfer.rs | 27 ++-- .../asset-hub-westend/src/tests/send.rs | 27 ++-- .../src/tests/set_xcm_versions.rs | 25 ++-- .../asset-hub-westend/src/tests/swap.rs | 35 +++--- .../asset-hub-westend/src/tests/teleport.rs | 25 ++-- .../bridges/bridge-hub-rococo/Cargo.toml | 1 + .../bridges/bridge-hub-rococo/src/lib.rs | 25 ++-- .../bridge-hub-rococo/src/tests/example.rs | 25 ++-- .../bridge-hub-rococo/src/tests/mod.rs | 25 ++-- .../collectives-polkadot/Cargo.toml | 1 + .../collectives-polkadot/src/lib.rs | 25 ++-- .../src/tests/fellowship.rs | 25 ++-- .../collectives-polkadot/src/tests/mod.rs | 25 ++-- .../emulated/common/Cargo.toml | 1 + .../emulated/common/src/constants.rs | 39 +++--- .../emulated/common/src/impls.rs | 27 ++-- .../emulated/common/src/lib.rs | 25 ++-- .../assets/asset-hub-kusama/src/constants.rs | 118 ----------------- .../assets/asset-hub-kusama/src/lib.rs | 11 +- .../assets/asset-hub-kusama/tests/tests.rs | 5 +- .../asset-hub-polkadot/src/constants.rs | 119 ------------------ .../assets/asset-hub-polkadot/src/lib.rs | 6 +- .../assets/asset-hub-polkadot/tests/tests.rs | 10 +- .../assets/asset-hub-westend/src/lib.rs | 8 +- .../assets/asset-hub-westend/tests/tests.rs | 17 +-- .../bridge-hub-kusama/src/constants.rs | 117 ----------------- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 8 +- .../bridge-hub-kusama/tests/tests.rs | 6 +- .../bridge-hub-polkadot/src/constants.rs | 117 ----------------- .../bridge-hub-polkadot/src/lib.rs | 8 +- .../bridge-hub-polkadot/tests/tests.rs | 6 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 9 +- .../bridge-hub-rococo/tests/tests.rs | 3 +- .../src/fellowship/mod.rs | 5 +- .../collectives-polkadot/src/lib.rs | 10 +- .../contracts-rococo/src/contracts.rs | 6 +- .../contracts/contracts-rococo/src/lib.rs | 9 +- .../src/chain_spec/asset_hubs.rs | 6 +- .../src/chain_spec/bridge_hubs.rs | 6 +- .../src/chain_spec/collectives.rs | 2 +- .../src/chain_spec/contracts.rs | 2 +- 68 files changed, 534 insertions(+), 1009 deletions(-) rename cumulus/parachains/{runtimes/contracts/contracts-rococo/src/constants.rs => common/src/kusama.rs} (95%) rename cumulus/parachains/{runtimes/collectives/collectives-polkadot/src/constants.rs => common/src/polkadot.rs} (94%) rename cumulus/parachains/{runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs => common/src/rococo.rs} (96%) rename cumulus/parachains/{runtimes/assets/asset-hub-westend/src/constants.rs => common/src/westend.rs} (96%) delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs diff --git a/Cargo.lock b/Cargo.lock index 8af7f4f8721..38d0a3388d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10978,6 +10978,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-support", "frame-system", + "kusama-runtime-constants", "log", "num-traits", "pallet-asset-tx-payment", @@ -10986,8 +10987,12 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "parity-scale-codec", + "polkadot-core-primitives", "polkadot-primitives", + "polkadot-runtime-constants", + "rococo-runtime-constants", "scale-info", + "smallvec", "sp-consensus-aura", "sp-core", "sp-io", @@ -10997,6 +11002,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "westend-runtime-constants", ] [[package]] diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 0c863b7295b..18cafde0d30 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -13,6 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive log = { version = "0.4.19", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } num-traits = { version = "0.2", default-features = false} +smallvec = "1.11.0" # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } @@ -28,6 +29,11 @@ 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} @@ -52,18 +58,23 @@ 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", "pallet-authorship/std", "pallet-balances/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", "sp-io/std", "sp-runtime/std", "sp-std/std", + "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs b/cumulus/parachains/common/src/kusama.rs similarity index 95% rename from cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs rename to cumulus/parachains/common/src/kusama.rs index 9b0fe5182a2..308f7d081ce 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/constants.rs +++ b/cumulus/parachains/common/src/kusama.rs @@ -13,6 +13,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Consensus-related. +pub mod consensus { + /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included + /// into the relay chain. + pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; + /// How many parachain blocks are processed by the relay chain per parent. Limits the + /// number of blocks authored per slot. + pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; + /// Relay chain slot duration, in milliseconds. + pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +} + +/// Constants relating to KSM. pub mod currency { use kusama_runtime_constants as constants; use polkadot_core_primitives::Balance; @@ -31,7 +44,7 @@ pub mod currency { } } -/// Fee-related. +/// Constants related to Kusama fee payment. pub mod fee { use frame_support::{ pallet_prelude::Weight, @@ -75,8 +88,8 @@ pub mod fee { impl WeightToFeePolynomial for RefTimeToFee { type Balance = Balance; fn polynomial() -> WeightToFeeCoefficients { - // in Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Rococo Contracts, we map to 1/10 of that, or 1/100 CENT + // In Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. let p = super::currency::CENTS; let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); @@ -107,15 +120,3 @@ pub mod fee { } } } - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index 797010d49a0..cb2ac1a1e3e 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -16,6 +16,10 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod impls; +pub mod kusama; +pub mod polkadot; +pub mod rococo; +pub mod westend; pub mod xcm_config; pub use constants::*; pub use opaque::*; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs b/cumulus/parachains/common/src/polkadot.rs similarity index 94% rename from cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs rename to cumulus/parachains/common/src/polkadot.rs index 46b562ea4de..52cee939224 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/constants.rs +++ b/cumulus/parachains/common/src/polkadot.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Universally recognized accounts. pub mod account { use frame_support::PalletId; @@ -28,6 +29,19 @@ pub mod account { pub const REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/refer"); } +/// Consensus-related. +pub mod consensus { + /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included + /// into the relay chain. + pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; + /// How many parachain blocks are processed by the relay chain per parent. Limits the + /// number of blocks authored per slot. + pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; + /// Relay chain slot duration, in milliseconds. + pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +} + +/// Constants relating to DOT. pub mod currency { use polkadot_core_primitives::Balance; use polkadot_runtime_constants as constants; @@ -41,12 +55,12 @@ pub mod currency { pub const MILLICENTS: Balance = constants::currency::MILLICENTS; pub const fn deposit(items: u32, bytes: u32) -> Balance { - // 1/100 of Polkadot. + // 1/100 of Polkadot constants::currency::deposit(items, bytes) / 100 } } -/// Fee-related. +/// Constants related to Polkadot fee payment. pub mod fee { use frame_support::{ pallet_prelude::Weight, @@ -90,8 +104,8 @@ pub mod fee { impl WeightToFeePolynomial for RefTimeToFee { type Balance = Balance; fn polynomial() -> WeightToFeeCoefficients { - // in Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in a parachain, we map to 1/10 of that, or 1/100 CENT + // In Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. let p = super::currency::CENTS; let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); @@ -122,15 +136,3 @@ pub mod fee { } } } - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs b/cumulus/parachains/common/src/rococo.rs similarity index 96% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs rename to cumulus/parachains/common/src/rococo.rs index 80620feaedc..6e31def4b55 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/constants.rs +++ b/cumulus/parachains/common/src/rococo.rs @@ -73,8 +73,8 @@ pub mod fee { impl WeightToFeePolynomial for RefTimeToFee { type Balance = Balance; fn polynomial() -> WeightToFeeCoefficients { - // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Bridge Hub, we map to 1/10 of that, or 1/100 CENT + // In Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. let p = super::currency::CENTS; let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs b/cumulus/parachains/common/src/westend.rs similarity index 96% rename from cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs rename to cumulus/parachains/common/src/westend.rs index b2629ef10fc..9d3e0bd1a0e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/constants.rs +++ b/cumulus/parachains/common/src/westend.rs @@ -75,8 +75,8 @@ pub mod fee { impl WeightToFeePolynomial for RefTimeToFee { type Balance = Balance; fn polynomial() -> WeightToFeeCoefficients { - // in Westend, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Asset Hub, we map to 1/10 of that, or 1/100 CENT + // In Westend, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. let p = super::currency::CENTS; let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index d45a201a4d0..4f17b1ac55b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -3,6 +3,7 @@ name = "asset-hub-kusama-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" publish = false diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs index 9325ca54b06..ad74aa2301f 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub use codec::Encode; pub use frame_support::{ 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 index 8647c1aa008..623b3ff599c 100644 --- 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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-kusama/src/tests/mod.rs index 41d84065819..b3089a3b382 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod hrmp_channels; mod reserve_transfer; 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-kusama/src/tests/reserve_transfer.rs index 26b3cdf68b1..645dca5035b 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-kusama/src/tests/reserve_transfer.rs @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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 index d633c25b732..5891b694c8e 100644 --- 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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-kusama/src/tests/set_xcm_versions.rs index 155ada2ec2f..a7af96096cd 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-kusama/src/tests/set_xcm_versions.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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 crate::*; 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-kusama/src/tests/swap.rs index aad93db9922..3a67b543582 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs @@ -1,22 +1,21 @@ // 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 . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::*; -use asset_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; use frame_support::{instances::Instance2, BoundedVec}; +use parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; use sp_runtime::{DispatchError, ModuleError}; #[test] @@ -183,11 +182,9 @@ fn swap_locally_on_chain_using_foreign_assets() { .encode() .into(); - let buy_execution_fee_amount = - asset_hub_kusama_runtime::constants::fee::WeightToFee::weight_to_fee(&Weight::from_parts( - 10_100_000_000_000, - 300_000, - )); + let buy_execution_fee_amount = parachains_common::kusama::fee::WeightToFee::weight_to_fee( + &Weight::from_parts(10_100_000_000_000, 300_000), + ); let buy_execution_fee = MultiAsset { id: Concrete(MultiLocation { parents: 1, interior: Here }), fun: Fungible(buy_execution_fee_amount), 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-kusama/src/tests/teleport.rs index b671fd5b444..f69878f3543 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. #![allow(dead_code)] // 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 index 3d5d23e9963..ed383207228 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -3,6 +3,7 @@ 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 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 index 6cbf6ab1ccb..e8ba8e44f25 100644 --- 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub use codec::Encode; pub use frame_support::{ 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 index 337e4ba6113..a1423f2ea90 100644 --- 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs index 547b59deadc..c22de4f1c3e 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod hrmp_channels; mod reserve_transfer; 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 index e6722d585bc..e53693d85d2 100644 --- 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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 index 143ab06b4e9..244b428a752 100644 --- 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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 index 287bfa35ae9..e121c416799 100644 --- 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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 crate::*; 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 index f0fbcf37fcc..644c51d75b6 100644 --- 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. #![allow(dead_code)] // 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 34d34009ebd..0c60a30a0b9 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 @@ -3,6 +3,7 @@ name = "asset-hub-westend-integration-tests" version = "1.0.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" description = "Asset Hub Westend runtime integration tests with xcm-emulator" publish = false 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 2c89c0f9dd4..6e0f3434aed 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub use codec::Encode; pub use frame_support::{ 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 e2a60e0b300..b3841af0e6c 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod reserve_transfer; mod send; 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 67fc53a826a..51fac43be12 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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 fcaffdabc4c..424d222bef3 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 @@ -1,18 +1,17 @@ // 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 . +// 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::*; 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 57632527174..2720095aac0 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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 crate::*; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index 1c4dd9d7683..7d1615c9e29 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -1,18 +1,17 @@ // 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 . +// 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::*; @@ -171,11 +170,9 @@ fn swap_locally_on_chain_using_foreign_assets() { .encode() .into(); - let buy_execution_fee_amount = - asset_hub_westend_runtime::constants::fee::WeightToFee::weight_to_fee(&Weight::from_parts( - 10_100_000_000_000, - 300_000, - )); + let buy_execution_fee_amount = parachains_common::westend::fee::WeightToFee::weight_to_fee( + &Weight::from_parts(10_100_000_000_000, 300_000), + ); let buy_execution_fee = MultiAsset { id: Concrete(MultiLocation { parents: 1, interior: Here }), fun: Fungible(buy_execution_fee_amount), 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 233dc32b13b..8de73a7420c 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. #![allow(dead_code)] // 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 12a2ed51591..ee689685554 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 @@ -3,6 +3,7 @@ name = "bridge-hub-rococo-integration-tests" version = "1.0.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" publish = 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 0a923ec04de..122d6546115 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub use bp_messages::LaneId; pub use frame_support::assert_ok; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index 777acd2aa97..f24e13bb71b 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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 crate::*; 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 6e11743aecb..48347557ae7 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 @@ -1,17 +1,16 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod example; diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index ee0e254befc..5a28b127415 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -3,6 +3,7 @@ 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 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 index ad2b5a50111..aa716c7c948 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub use codec::Encode; pub use frame_support::{assert_ok, sp_runtime::AccountId32}; 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 index 82e998f5a76..c08a660205f 100644 --- 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Integration tests concerning the Fellowship. diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs index a9445ac8ec7..fb3e235a25c 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs @@ -1,17 +1,16 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod fellowship; diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index a8002158dbc..ac1e650d5de 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -3,6 +3,7 @@ name = "integration-tests-common" version = "1.0.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" description = "Common resources for integration testing with xcm-emulator" publish = false diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index fedc46fabff..8725ebd140b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. // Substrate use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; @@ -632,7 +631,7 @@ pub mod rococo { pub mod asset_hub_polkadot { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = asset_hub_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = asset_hub_polkadot_runtime::RuntimeGenesisConfig { @@ -689,7 +688,7 @@ pub mod asset_hub_polkadot { pub mod asset_hub_westend { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = asset_hub_westend_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { @@ -746,7 +745,7 @@ pub mod asset_hub_westend { pub mod asset_hub_kusama { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = asset_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = asset_hub_kusama_runtime::RuntimeGenesisConfig { @@ -864,7 +863,7 @@ pub mod penpal { pub mod collectives { use super::*; pub const PARA_ID: u32 = 1001; - pub const ED: Balance = collectives_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = collectives_polkadot_runtime::RuntimeGenesisConfig { @@ -921,7 +920,7 @@ pub mod collectives { pub mod bridge_hub_kusama { use super::*; pub const PARA_ID: u32 = 1002; - pub const ED: Balance = bridge_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = bridge_hub_kusama_runtime::RuntimeGenesisConfig { @@ -978,7 +977,7 @@ pub mod bridge_hub_kusama { pub mod bridge_hub_polkadot { use super::*; pub const PARA_ID: u32 = 1002; - pub const ED: Balance = bridge_hub_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = bridge_hub_polkadot_runtime::RuntimeGenesisConfig { @@ -1035,7 +1034,7 @@ pub mod bridge_hub_polkadot { pub mod bridge_hub_rococo { use super::*; pub const PARA_ID: u32 = 1013; - pub const ED: Balance = bridge_hub_rococo_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index f13da001620..eed61d94171 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -1,18 +1,17 @@ // 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 . +// 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::{Decode, Encode}; pub use paste; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 49751136f7b..7461165f2a1 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub mod constants; pub mod impls; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs deleted file mode 100644 index 8daf8fda4b4..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/constants.rs +++ /dev/null @@ -1,118 +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 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 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 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 - } -} - -/// Fee-related. -pub mod fee { - use frame_support::weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, Weight, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }; - use polkadot_core_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 frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Asset Hub, we map to 1/10 of that, or 1/100 CENT - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} 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 afccc5c068b..828d1b4750a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -24,7 +24,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod weights; pub mod xcm_config; @@ -50,7 +49,6 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -70,8 +68,10 @@ use pallet_asset_conversion_tx_payment::AssetConversionAdapter; use pallet_nfts::PalletFeatures; pub use parachains_common as common; use parachains_common::{ - impls::DealWithFees, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, - Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, + impls::DealWithFees, + kusama::{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; @@ -1395,8 +1395,9 @@ fn ensure_key_ss58() { #[cfg(test)] mod tests { - use super::{constants::fee, *}; + use super::*; use crate::{CENTS, MILLICENTS}; + use parachains_common::kusama::fee; use sp_runtime::traits::Zero; use sp_weights::WeightToFee; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs index 6d9eccdf374..7d49b56e461 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs @@ -21,7 +21,6 @@ use asset_hub_kusama_runtime::xcm_config::{ AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation, }; pub use asset_hub_kusama_runtime::{ - constants::fee::WeightToFee, xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig}, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, @@ -35,7 +34,9 @@ use frame_support::{ traits::fungibles::InspectEnumerable, weights::{Weight, WeightToFee as WeightToFeeT}, }; -use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; +use parachains_common::{ + kusama::fee::WeightToFee, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, +}; use sp_runtime::traits::MaybeEquivalence; use xcm::latest::prelude::*; use xcm_executor::traits::{Identity, JustTry, WeightTrader}; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs deleted file mode 100644 index d430e38f1af..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/constants.rs +++ /dev/null @@ -1,119 +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 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 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 fn deposit(items: u32, bytes: u32) -> Balance { - // 1/100 of Polkadot - constants::currency::deposit(items, bytes) / 100 - } -} - -/// Fee-related. -pub mod fee { - use frame_support::weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }; - use polkadot_core_primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - use sp_weights::Weight; - - /// 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 frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Asset Hub, we map to 1/10 of that, or 1/100 CENT - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} 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 7275209802f..0051af21f9a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -59,7 +59,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod weights; pub mod xcm_config; @@ -82,7 +81,6 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -102,6 +100,7 @@ use pallet_nfts::PalletFeatures; pub use parachains_common as common; use parachains_common::{ impls::{AssetsToBlockAuthor, DealWithFees}, + polkadot::{consensus::*, currency::*, fee::WeightToFee}, AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, @@ -1228,8 +1227,9 @@ cumulus_pallet_parachain_system::register_validate_block! { #[cfg(test)] mod tests { - use super::{constants::fee, *}; + use super::*; use crate::{CENTS, MILLICENTS}; + use parachains_common::polkadot::fee; use sp_runtime::traits::Zero; use sp_weights::WeightToFee; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index 3eab6723ec2..7200ebc16a2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -22,10 +22,9 @@ use asset_hub_polkadot_runtime::xcm_config::{ ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation, XcmConfig, }; pub use asset_hub_polkadot_runtime::{ - constants::fee::WeightToFee, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, - ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, - MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, - System, TrustBackedAssetsInstance, + AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, + ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, + RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use codec::{Decode, Encode}; @@ -36,7 +35,8 @@ use frame_support::{ weights::{Weight, WeightToFee as WeightToFeeT}, }; use parachains_common::{ - AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, Balance, + polkadot::fee::WeightToFee, AccountId, AssetHubPolkadotAuraId as AuraId, + AssetIdForTrustBackedAssets, Balance, }; use sp_runtime::traits::MaybeEquivalence; use xcm::latest::prelude::*; 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 b5f33e4e014..4887fce1b0a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -24,7 +24,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod weights; pub mod xcm_config; @@ -36,7 +35,6 @@ use assets_common::{ AssetIdForTrustBackedAssetsConvert, }; use codec::{Decode, Encode, MaxEncodedLen}; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use frame_support::{ construct_runtime, @@ -57,8 +55,10 @@ use pallet_asset_conversion_tx_payment::AssetConversionAdapter; use pallet_nfts::PalletFeatures; pub use parachains_common as common; use parachains_common::{ - impls::DealWithFees, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, - Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, + impls::DealWithFees, + westend::{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_api::impl_runtime_apis; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index b2bb511182e..599ff90e254 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -17,13 +17,6 @@ //! Tests for the Westmint (Westend Assets Hub) chain. -pub use asset_hub_westend_runtime::{ - constants::fee::WeightToFee, - xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig}, - AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System, - TrustBackedAssetsInstance, -}; use asset_hub_westend_runtime::{ xcm_config::{ AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, @@ -32,6 +25,12 @@ use asset_hub_westend_runtime::{ AllPalletsWithoutSystem, MetadataDepositBase, MetadataDepositPerByte, RuntimeCall, RuntimeEvent, }; +pub use asset_hub_westend_runtime::{ + xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig}, + AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, + ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System, + TrustBackedAssetsInstance, +}; use asset_test_utils::{CollatorSessionKeys, ExtBuilder, XcmReceivedFrom}; use codec::{Decode, DecodeLimit, Encode}; use cumulus_primitives_utility::ChargeWeightInFungibles; @@ -40,7 +39,9 @@ use frame_support::{ traits::fungibles::InspectEnumerable, weights::{Weight, WeightToFee as WeightToFeeT}, }; -use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; +use parachains_common::{ + westend::fee::WeightToFee, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, +}; use sp_io; use sp_runtime::traits::MaybeEquivalence; use std::convert::Into; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs deleted file mode 100644 index 760bf7fb6d1..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/constants.rs +++ /dev/null @@ -1,117 +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 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 UNITS: Balance = constants::currency::UNITS; - pub const CENTS: Balance = constants::currency::CENTS; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; - - 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 - } -} - -/// Fee-related. -pub mod fee { - use frame_support::{ - pallet_prelude::Weight, - weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, - }; - use polkadot_core_primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// 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 frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Bridge Hub, we map to 1/10 of that, or 1/100 CENT - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} 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 044ff845fe6..54b15e6b327 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 @@ -22,7 +22,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod weights; pub mod xcm_config; @@ -41,7 +40,6 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -69,8 +67,10 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use parachains_common::{ - impls::DealWithFees, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, + impls::DealWithFees, + kusama::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, + HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; // XCM Imports diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs index 5418e36bd12..893524e12f6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs @@ -15,12 +15,12 @@ // along with Cumulus. If not, see . pub use bridge_hub_kusama_runtime::{ - constants::fee::WeightToFee, xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, - ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, + xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, ExistentialDeposit, ParachainSystem, + PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, }; use codec::Decode; use frame_support::parameter_types; -use parachains_common::{AccountId, AuraId}; +use parachains_common::{kusama::fee::WeightToFee, AccountId, AuraId}; const ALICE: [u8; 32] = [1u8; 32]; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs deleted file mode 100644 index 3bab7bd1eb3..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/constants.rs +++ /dev/null @@ -1,117 +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 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 UNITS: Balance = constants::currency::UNITS; - pub const CENTS: Balance = constants::currency::CENTS; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; - - pub const fn deposit(items: u32, bytes: u32) -> Balance { - // 1/100 of Polkadot - constants::currency::deposit(items, bytes) / 100 - } -} - -/// Fee-related. -pub mod fee { - use frame_support::{ - pallet_prelude::Weight, - weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, - }; - use polkadot_core_primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// 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 frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // in Bridge Hub, we map to 1/10 of that, or 1/100 CENT - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} 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 f735858a934..dbfdc249a3c 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 @@ -22,7 +22,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod weights; pub mod xcm_config; @@ -41,7 +40,6 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -70,8 +68,10 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use parachains_common::{ - impls::DealWithFees, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, + impls::DealWithFees, + polkadot::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, + HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; // XCM Imports use xcm::latest::prelude::BodyId; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs index 03b23cdd7ac..0be87bd46fa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs @@ -15,12 +15,12 @@ // along with Cumulus. If not, see . pub use bridge_hub_polkadot_runtime::{ - constants::fee::WeightToFee, xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, - ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, + xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, ExistentialDeposit, ParachainSystem, + PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, }; use codec::Decode; use frame_support::parameter_types; -use parachains_common::{AccountId, AuraId}; +use parachains_common::{polkadot::fee::WeightToFee, AccountId, AuraId}; const ALICE: [u8; 32] = [1u8; 32]; 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 a872e232730..4311a6a629f 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 @@ -24,11 +24,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod bridge_hub_rococo_config; pub mod bridge_hub_wococo_config; -pub mod constants; mod weights; pub mod xcm_config; -use constants::{consensus::*, currency::*}; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -79,7 +77,6 @@ use crate::{ BridgeRefundBridgeHubRococoMessages, OnBridgeHubWococoBlobDispatcher, WithBridgeHubRococoMessageBridge, }, - constants::fee::WeightToFee, xcm_config::XcmRouter, }; use bridge_runtime_common::{ @@ -87,8 +84,10 @@ use bridge_runtime_common::{ messages_xcm_extension::{XcmAsPlainPayload, XcmBlobMessageDispatch}, }; use parachains_common::{ - impls::DealWithFees, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, + impls::DealWithFees, + rococo::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, + HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; use xcm_executor::XcmExecutor; 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 77e7e0382d3..e5fe67f2a8e 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,6 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_hub_rococo_config, bridge_hub_wococo_config, - constants::fee::WeightToFee, xcm_config::{RelayNetwork, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, DeliveryRewardInBalance, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, @@ -28,7 +27,7 @@ use bridge_hub_rococo_runtime::{ use codec::{Decode, Encode}; use frame_support::parameter_types; use frame_system::pallet_prelude::HeaderFor; -use parachains_common::{AccountId, AuraId, Balance}; +use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, 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 9b867533129..b97e44dda1b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -20,7 +20,7 @@ pub(crate) mod migration; mod origins; mod tracks; use crate::{ - constants, impls::ToParentTreasury, weights, AccountId, Balance, Balances, FellowshipReferenda, + impls::ToParentTreasury, weights, AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, DAYS, }; @@ -36,6 +36,7 @@ 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 sp_core::{ConstU128, ConstU32}; use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; @@ -62,7 +63,7 @@ pub mod ranks { parameter_types! { // Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting. - pub ReferendaPalletAccount: AccountId = constants::account::REFERENDA_PALLET_ID.into_account_truncating(); + pub ReferendaPalletAccount: AccountId = account::REFERENDA_PALLET_ID.into_account_truncating(); pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 5033a2d8beb..238db08a0c9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -36,7 +36,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; pub mod impls; mod weights; pub mod xcm_config; @@ -64,7 +63,6 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -79,7 +77,9 @@ use frame_system::{ }; pub use parachains_common as common; use parachains_common::{ - impls::DealWithFees, AccountId, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, + impls::DealWithFees, + polkadot::{account::*, consensus::*, currency::*, fee::WeightToFee}, + AccountId, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; @@ -484,8 +484,8 @@ parameter_types! { pub const AllyDeposit: Balance = 1_000 * UNITS; // 1,000 DOT bond to join as an Ally // The Alliance pallet account, used as a temporary place to deposit a slashed imbalance // before the teleport to the Treasury. - pub AlliancePalletAccount: AccountId = constants::account::ALLIANCE_PALLET_ID.into_account_truncating(); - pub PolkadotTreasuryAccount: AccountId = constants::account::POLKADOT_TREASURY_PALLET_ID.into_account_truncating(); + pub AlliancePalletAccount: AccountId = ALLIANCE_PALLET_ID.into_account_truncating(); + pub PolkadotTreasuryAccount: AccountId = POLKADOT_TREASURY_PALLET_ID.into_account_truncating(); // The number of blocks a member must wait between giving a retirement notice and retiring. // Supposed to be greater than time required to `kick_member` with alliance motion. pub const AllianceRetirementPeriod: BlockNumber = (90 * DAYS) + ALLIANCE_MOTION_DURATION; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index 6598fd3fae0..1c99393d5e5 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -14,8 +14,8 @@ // limitations under the License. use crate::{ - constants::currency::deposit, Balance, Balances, RandomnessCollectiveFlip, Runtime, - RuntimeCall, RuntimeEvent, RuntimeHoldReason, Timestamp, + Balance, Balances, RandomnessCollectiveFlip, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, Timestamp, }; use frame_support::{ parameter_types, @@ -28,7 +28,7 @@ use pallet_contracts::{ }; use sp_runtime::Perbill; -pub use parachains_common::AVERAGE_ON_INITIALIZE_RATIO; +pub use parachains_common::{rococo::currency::deposit, AVERAGE_ON_INITIALIZE_RATIO}; // Prints debug output of the `contracts` pallet to stdout if the node is // started with `-lruntime::contracts=debug`. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index b5815ab057e..399ada1be2c 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -25,7 +25,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -pub mod constants; mod contracts; mod weights; mod xcm_config; @@ -45,7 +44,6 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use constants::{consensus::*, currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -57,9 +55,10 @@ use frame_support::{ use frame_system::limits::{BlockLength, BlockWeights}; pub use parachains_common as common; use parachains_common::{ - impls::DealWithFees, AccountId, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, - SLOT_DURATION, + impls::DealWithFees, + rococo::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, + MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; pub use parachains_common::{AuraId, Balance}; use xcm_config::CollatorSelectionUpdateOrigin; diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index c1fb60374ae..c1edeb98cd0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -32,11 +32,11 @@ pub type AssetHubWestendChainSpec = sc_service::GenericChainSpec; const ASSET_HUB_POLKADOT_ED: AssetHubBalance = - asset_hub_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; const ASSET_HUB_KUSAMA_ED: AssetHubBalance = - asset_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; const ASSET_HUB_WESTEND_ED: AssetHubBalance = - asset_hub_westend_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; /// Generate the session keys from individual elements. /// diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 4cb81f57081..5de4a49f827 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -192,7 +192,7 @@ pub mod rococo { pub(crate) const BRIDGE_HUB_ROCOCO_LOCAL: &str = "bridge-hub-rococo-local"; pub(crate) const BRIDGE_HUB_ROCOCO_DEVELOPMENT: &str = "bridge-hub-rococo-dev"; const BRIDGE_HUB_ROCOCO_ED: BridgeHubBalance = - bridge_hub_rococo_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = @@ -372,7 +372,7 @@ pub mod kusama { pub(crate) const BRIDGE_HUB_KUSAMA_LOCAL: &str = "bridge-hub-kusama-local"; pub(crate) const BRIDGE_HUB_KUSAMA_DEVELOPMENT: &str = "bridge-hub-kusama-dev"; const BRIDGE_HUB_KUSAMA_ED: BridgeHubBalance = - bridge_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = @@ -509,7 +509,7 @@ pub mod polkadot { pub(crate) const BRIDGE_HUB_POLKADOT_LOCAL: &str = "bridge-hub-polkadot-local"; pub(crate) const BRIDGE_HUB_POLKADOT_DEVELOPMENT: &str = "bridge-hub-polkadot-dev"; const BRIDGE_HUB_POLKADOT_ED: BridgeHubBalance = - bridge_hub_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 6126fbb114f..fbf49b9535a 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -26,7 +26,7 @@ pub type CollectivesPolkadotChainSpec = sc_service::GenericChainSpec; const COLLECTIVES_POLKADOT_ED: CollectivesBalance = - collectives_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; /// Generate the session keys from individual elements. /// diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs index bf318e448f0..0d5012858ed 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs @@ -31,7 +31,7 @@ const CONTRACTS_PARACHAIN_ID: u32 = 1002; /// The existential deposit is determined by the runtime "contracts-rococo". const CONTRACTS_ROCOCO_ED: contracts_rococo_runtime::Balance = - contracts_rococo_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn contracts_rococo_development_config() -> ContractsRococoChainSpec { let mut properties = sc_chain_spec::Properties::new(); -- GitLab From 711132c961b1f62b4f1bf23aa015728bab41a5d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:27:19 +0200 Subject: [PATCH 076/633] Bump thiserror from 1.0.47 to 1.0.48 (#1396) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.47 to 1.0.48. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.47...1.0.48) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Liam Aharon --- Cargo.lock | 8 ++++---- cumulus/client/consensus/proposer/Cargo.toml | 2 +- cumulus/client/relay-chain-interface/Cargo.toml | 2 +- cumulus/client/relay-chain-rpc-interface/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/erasure-coding/Cargo.toml | 2 +- polkadot/node/collation-generation/Cargo.toml | 2 +- polkadot/node/core/approval-voting/Cargo.toml | 2 +- polkadot/node/core/av-store/Cargo.toml | 2 +- polkadot/node/core/backing/Cargo.toml | 2 +- polkadot/node/core/bitfield-signing/Cargo.toml | 2 +- polkadot/node/core/chain-selection/Cargo.toml | 2 +- polkadot/node/core/dispute-coordinator/Cargo.toml | 2 +- polkadot/node/core/parachains-inherent/Cargo.toml | 2 +- polkadot/node/core/prospective-parachains/Cargo.toml | 2 +- polkadot/node/core/provisioner/Cargo.toml | 2 +- polkadot/node/core/pvf-checker/Cargo.toml | 2 +- polkadot/node/jaeger/Cargo.toml | 2 +- .../node/network/availability-distribution/Cargo.toml | 2 +- polkadot/node/network/availability-recovery/Cargo.toml | 2 +- polkadot/node/network/collator-protocol/Cargo.toml | 2 +- polkadot/node/network/dispute-distribution/Cargo.toml | 2 +- polkadot/node/network/protocol/Cargo.toml | 2 +- polkadot/node/network/statement-distribution/Cargo.toml | 2 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/node/subsystem-types/Cargo.toml | 2 +- polkadot/node/subsystem-util/Cargo.toml | 2 +- polkadot/node/test/performance-test/Cargo.toml | 2 +- polkadot/node/zombienet-backchannel/Cargo.toml | 2 +- polkadot/utils/staking-miner/Cargo.toml | 2 +- substrate/client/allocator/Cargo.toml | 2 +- substrate/client/api/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/consensus/common/Cargo.toml | 2 +- substrate/client/executor/common/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/tracing/Cargo.toml | 2 +- substrate/client/transaction-pool/Cargo.toml | 2 +- substrate/client/transaction-pool/api/Cargo.toml | 2 +- substrate/primitives/api/Cargo.toml | 2 +- substrate/primitives/blockchain/Cargo.toml | 2 +- substrate/primitives/consensus/common/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/inherents/Cargo.toml | 2 +- substrate/primitives/state-machine/Cargo.toml | 2 +- substrate/primitives/timestamp/Cargo.toml | 2 +- substrate/primitives/trie/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/utils/frame/benchmarking-cli/Cargo.toml | 2 +- 53 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38d0a3388d3..c254302517f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18661,9 +18661,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] @@ -18690,9 +18690,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index f7edbc695e3..29720a8f479 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -8,7 +8,7 @@ edition.workspace = true [dependencies] anyhow = "1.0" async-trait = "0.1.73" -thiserror = "1.0.47" +thiserror = "1.0.48" # Substrate sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index b81cc1b4780..3da7ab0b0e8 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -16,6 +16,6 @@ sc-client-api = { path = "../../../substrate/client/api" } futures = "0.3.28" async-trait = "0.1.73" -thiserror = "1.0.47" +thiserror = "1.0.48" jsonrpsee-core = "0.16.2" parity-scale-codec = "3.6.4" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 9797c512505..305ab82b064 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -38,6 +38,6 @@ schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } either = "1.8.1" -thiserror = "1.0.38" +thiserror = "1.0.48" rand = "0.8.5" pin-project = "1.1.3" diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index bcb4f2ac130..c8c3f91f983 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -17,7 +17,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] clap = { version = "4.4.2", features = ["derive"], optional = true } log = "0.4.17" -thiserror = "1.0.31" +thiserror = "1.0.48" futures = "0.3.21" pyro = { package = "pyroscope", version = "0.5.3", optional = true } pyroscope_pprofrs = { version = "0.2", optional = true } diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index f74a8803882..d07b77ec4dd 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -12,7 +12,7 @@ novelpoly = { package = "reed-solomon-novelpoly", version = "1.0.0" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["std", "derive"] } sp-core = { path = "../../substrate/primitives/core" } sp-trie = { path = "../../substrate/primitives/trie" } -thiserror = "1.0.31" +thiserror = "1.0.48" [dev-dependencies] criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index e2870dc2cc8..b110540140f 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -15,7 +15,7 @@ polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-primitives = { path = "../../primitives" } sp-core = { path = "../../../substrate/primitives/core" } sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } -thiserror = "1.0.31" +thiserror = "1.0.48" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } [dev-dependencies] diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 307d9947a96..acad0d1fa4e 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -16,7 +16,7 @@ merlin = "2.0" schnorrkel = "0.9.1" kvdb = "0.13.0" derive_more = "0.99.17" -thiserror = "1.0.31" +thiserror = "1.0.48" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index efbbb27754e..955fe37d7c3 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true futures = "0.3.21" futures-timer = "3.0.2" kvdb = "0.13.0" -thiserror = "1.0.31" +thiserror = "1.0.48" gum = { package = "tracing-gum", path = "../../gum" } bitvec = "1.0.0" diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 0005f6f6a30..e7e6358e8a4 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -16,7 +16,7 @@ erasure-coding = { package = "polkadot-erasure-coding", path = "../../../erasure statement-table = { package = "polkadot-statement-table", path = "../../../statement-table" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.31" +thiserror = "1.0.48" fatality = "0.0.6" [dev-dependencies] diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index c2df6cc709e..de38d18d970 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -13,7 +13,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } wasm-timer = "0.2.5" -thiserror = "1.0.31" +thiserror = "1.0.48" [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 57ba7908315..7678379870e 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -15,7 +15,7 @@ polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } kvdb = "0.13.0" -thiserror = "1.0.31" +thiserror = "1.0.48" parity-scale-codec = "3.6.1" [dev-dependencies] diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index c49bd507127..6061c52b7e8 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -10,7 +10,7 @@ futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.1" kvdb = "0.13.0" -thiserror = "1.0.31" +thiserror = "1.0.48" schnellru = "0.2.1" fatality = "0.0.6" diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 515d70dad82..18d91dcfb56 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.31" +thiserror = "1.0.48" async-trait = "0.1.57" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-overseer = { path = "../../overseer" } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 9fa17ec0c15..77a59d87f3f 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true futures = "0.3.19" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.4" -thiserror = "1.0.30" +thiserror = "1.0.48" fatality = "0.0.6" bitvec = "1" diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index dc791417166..05ea92caa97 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.31" +thiserror = "1.0.48" polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 783ac19009a..0326a20e5a5 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true [dependencies] futures = "0.3.21" -thiserror = "1.0.31" +thiserror = "1.0.48" gum = { package = "tracing-gum", path = "../../gum" } polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 7b4b5e1c8bc..fcfbbaec611 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -14,7 +14,7 @@ polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } sc-network = { path = "../../../substrate/client/network" } sp-core = { path = "../../../substrate/primitives/core" } -thiserror = "1.0.31" +thiserror = "1.0.48" tokio = "1.24.2" log = "0.4.17" parity-scale-codec = { version = "3.6.1", default-features = false } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index 581192e9560..c3c7aa4e0ea 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -17,7 +17,7 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-primitives = { path = "../../primitives" } sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } sp-keystore = { path = "../../../../substrate/primitives/keystore" } -thiserror = "1.0.31" +thiserror = "1.0.48" rand = "0.8.5" derive_more = "0.99.17" schnellru = "0.2.1" diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index bf95fb1e9f4..07ff09c7e70 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -10,7 +10,7 @@ futures = "0.3.21" schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" -thiserror = "1.0.31" +thiserror = "1.0.48" gum = { package = "tracing-gum", path = "../../gum" } polkadot-erasure-coding = { path = "../../../erasure-coding" } diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index ac6284b305b..e5328cf1662 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -21,7 +21,7 @@ polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-subsystem = { path = "../../subsystem" } fatality = "0.0.6" -thiserror = "1.0.31" +thiserror = "1.0.48" tokio-util = "0.7.1" [dev-dependencies] diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index ece89f34c88..5d8e245d289 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -20,7 +20,7 @@ polkadot-node-primitives = { path = "../../primitives" } sc-network = { path = "../../../../substrate/client/network" } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } -thiserror = "1.0.31" +thiserror = "1.0.48" fatality = "0.0.6" schnellru = "0.2.1" indexmap = "1.9.1" diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 2a56f197b85..c33b9eae325 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -18,7 +18,7 @@ sc-network = { path = "../../../../substrate/client/network" } sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } strum = { version = "0.24", features = ["derive"] } futures = "0.3.21" -thiserror = "1.0.31" +thiserror = "1.0.48" fatality = "0.0.6" rand = "0.8" derive_more = "0.99" diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 5ff1ba9de02..bf516e7b7ba 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -21,7 +21,7 @@ polkadot-node-network-protocol = { path = "../protocol" } arrayvec = "0.7.4" indexmap = "1.9.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -thiserror = "1.0.31" +thiserror = "1.0.48" fatality = "0.0.6" bitvec = "1" diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index ef03c02f7bc..55dfa673870 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -19,7 +19,7 @@ sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compres sp-runtime = { path = "../../../substrate/primitives/runtime" } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } schnorrkel = "0.9.1" -thiserror = "1.0.31" +thiserror = "1.0.48" serde = { version = "1.0.188", features = ["derive"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 90881aa051a..03814af19cd 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -79,7 +79,7 @@ hex-literal = "0.4.1" gum = { package = "tracing-gum", path = "../gum" } serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.96" -thiserror = "1.0.31" +thiserror = "1.0.48" kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } parity-db = { version = "0.4.8", optional = true } diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 7ca3a0faf31..317b079a316 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -22,5 +22,5 @@ sp-authority-discovery = { path = "../../../substrate/primitives/authority-disco sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } -thiserror = "1.0.31" +thiserror = "1.0.48" async-trait = "0.1.57" diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index d243a90a2bd..204df0dad11 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -15,7 +15,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ parking_lot = "0.11.2" pin-project = "1.0.9" rand = "0.8.5" -thiserror = "1.0.31" +thiserror = "1.0.48" fatality = "0.0.6" gum = { package = "tracing-gum", path = "../gum" } derive_more = "0.99.17" diff --git a/polkadot/node/test/performance-test/Cargo.toml b/polkadot/node/test/performance-test/Cargo.toml index 98b67615a6f..5747ac88b1e 100644 --- a/polkadot/node/test/performance-test/Cargo.toml +++ b/polkadot/node/test/performance-test/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] -thiserror = "1.0.31" +thiserror = "1.0.48" quote = "1.0.28" env_logger = "0.9" log = "0.4" diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 3d59a4a3cdd..9bf56b550bb 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -16,7 +16,7 @@ futures-util = "0.3.23" lazy_static = "1.4.0" parity-scale-codec = { version = "3.6.1", features = ["derive"] } reqwest = { version = "0.11", features = ["rustls-tls"], default-features = false } -thiserror = "1.0.31" +thiserror = "1.0.48" gum = { package = "tracing-gum", path = "../gum" } serde = { version = "1.0", features = ["derive"] } serde_json = "1" diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml index 09e73bc10f2..4b012e3ac73 100644 --- a/polkadot/utils/staking-miner/Cargo.toml +++ b/polkadot/utils/staking-miner/Cargo.toml @@ -19,7 +19,7 @@ log = "0.4.17" paste = "1.0.7" serde = "1.0.188" serde_json = "1.0" -thiserror = "1.0.31" +thiserror = "1.0.48" tokio = { version = "1.24.2", features = ["macros", "rt-multi-thread", "sync"] } remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index ffbfe14e86c..31c714180ce 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.17" -thiserror = "1.0.30" +thiserror = "1.0.48" sp-core = { path = "../../primitives/core" } sp-wasm-interface = { path = "../../primitives/wasm-interface" } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 43545095c0e..b59149424ed 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -37,6 +37,6 @@ sp-statement-store = { path = "../../primitives/statement-store" } sp-storage = { path = "../../primitives/storage" } [dev-dependencies] -thiserror = "1.0.30" +thiserror = "1.0.48" sp-test-primitives = { path = "../../primitives/test-primitives" } substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 917cdc04d1d..06967a89093 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -27,7 +27,7 @@ regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.188" serde_json = "1.0.85" -thiserror = "1.0.30" +thiserror = "1.0.48" tiny-bip39 = "1.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } sc-client-api = { path = "../api" } diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index c9b3f221ecc..f269e3752d4 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -21,7 +21,7 @@ log = "0.4.17" mockall = "0.11.3" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } -thiserror = "1.0.30" +thiserror = "1.0.48" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } sc-utils = { path = "../../utils" } diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index e84b9f9c85b..5118279b43b 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0.30" +thiserror = "1.0.48" wasm-instrument = "0.3" sc-allocator = { path = "../../allocator" } sp-maybe-compressed-blob = { path = "../../../primitives/maybe-compressed-blob" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 6f794d93fed..87b341fe312 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -26,7 +26,7 @@ runtime-benchmarks = [ [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } -thiserror = "1.0.30" +thiserror = "1.0.48" futures = "0.3.21" rand = "0.8.5" parking_lot = "0.12.1" diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index c5b71260f97..5354819e3a3 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -15,4 +15,4 @@ fs4 = "0.6.3" sc-client-db = { path = "../db", default-features = false} sp-core = { path = "../../primitives/core" } tokio = "1.22.0" -thiserror = "1.0.30" +thiserror = "1.0.48" diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 59cc6ba4048..88d268cc93d 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" -thiserror = "1.0.30" +thiserror = "1.0.48" sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } sc-consensus-babe = { path = "../consensus/babe" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 15362912909..2be5ad5c143 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -24,5 +24,5 @@ sc-utils = { path = "../utils" } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" -thiserror = "1.0.30" +thiserror = "1.0.48" wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index c9cd6ca313c..ffcbf074908 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -23,7 +23,7 @@ parking_lot = "0.12.1" regex = "1.6.0" rustc-hash = "1.1.0" serde = "1.0.188" -thiserror = "1.0.30" +thiserror = "1.0.48" tracing = "0.1.29" tracing-log = "0.1.3" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 0e502cb39fb..b893dc839ed 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -21,7 +21,7 @@ linked-hash-map = "0.5.4" log = "0.4.17" parking_lot = "0.12.1" serde = { version = "1.0.188", features = ["derive"] } -thiserror = "1.0.30" +thiserror = "1.0.48" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } sc-transaction-pool-api = { path = "api" } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index edab1304e01..5ff5a4149ca 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -14,7 +14,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" log = "0.4.17" serde = { version = "1.0.188", features = ["derive"] } -thiserror = "1.0.30" +thiserror = "1.0.48" sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core", default-features = false} sp-runtime = { path = "../../../primitives/runtime", default-features = false} diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index c5611b22017..95b5dde3713 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -23,7 +23,7 @@ sp-version = { path = "../version", default-features = false} sp-state-machine = { path = "../state-machine", default-features = false, optional = true} sp-trie = { path = "../trie", default-features = false, optional = true} hash-db = { version = "0.16.0", optional = true } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true} log = { version = "0.4.17", default-features = false } diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 418f9458985..33db09ce0ac 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" log = "0.4.17" parking_lot = "0.12.1" schnellru = "0.2.1" -thiserror = "1.0.30" +thiserror = "1.0.48" sp-api = { path = "../api" } sp-consensus = { path = "../consensus/common" } sp-database = { path = "../database" } diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 284e00b272e..e8f6b806f8c 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.57" futures = { version = "0.3.21", features = ["thread-pool"] } log = "0.4.17" -thiserror = "1.0.30" +thiserror = "1.0.48" sp-core = { path = "../../core" } sp-inherents = { path = "../../inherents" } sp-runtime = { path = "../../runtime" } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index efcaad1a6f6..4e5186f1687 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -39,7 +39,7 @@ sp-storage = { path = "../storage", default-features = false} sp-externalities = { path = "../externalities", optional = true} futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } bitflags = "1.3" paste = "1.0.7" diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index d3ac94aa5fb..aa0aa95b3f8 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -18,7 +18,7 @@ async-trait = { version = "0.1.57", optional = true } 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"] } impl-trait-for-tuples = "0.2.2" -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } sp-runtime = { path = "../runtime", default-features = false, optional = true} sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index 3ab21308c3c..8546345e5ca 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -20,7 +20,7 @@ log = { version = "0.4.17", default-features = false } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8.5", optional = true } smallvec = "1.11.0" -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } sp-core = { path = "../core", default-features = false} sp-externalities = { path = "../externalities", default-features = false} diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 7de2a7d904d..44b0fdd831c 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } sp-inherents = { path = "../inherents", default-features = false} sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 31eb009328c..0bce597414b 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -27,7 +27,7 @@ memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.27.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 3002566f74f..1ab51a08bbe 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -19,7 +19,7 @@ impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.48", optional = true } sp-core-hashing-proc-macro = { path = "../core/hashing/proc-macro" } sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 096e4be82d4..85be451fa60 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -28,7 +28,7 @@ rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.188" serde_json = "1.0.85" -thiserror = "1.0.30" +thiserror = "1.0.48" thousands = "0.2.0" frame-benchmarking = { path = "../../../frame/benchmarking" } frame-support = { path = "../../../frame/support" } -- GitLab From adf847a582feac6bb654993e75331d63c109357d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:47:08 +0300 Subject: [PATCH 077/633] Bump actions/checkout from 3 to 4 (#1398) * Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update fmt-check.yml * Update .github/workflows/check-licenses.yml Co-authored-by: Chevdor * Update .github/workflows/check-markdown.yml Co-authored-by: Chevdor * Update .github/workflows/fmt-check.yml Co-authored-by: Chevdor --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Co-authored-by: Chevdor --- .github/workflows/check-licenses.yml | 2 +- .github/workflows/check-markdown.yml | 2 +- .github/workflows/fmt-check.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 3da699a354f..4d0afefc47a 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@v3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - uses: actions/setup-node@v3.8.1 with: node-version: "18.x" diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index b386fd6d1b1..f1e46ca2735 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@v3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - uses: actions/setup-node@v3.8.1 with: diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index fd4b72061b9..df785404036 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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Cargo fmt run: cargo +nightly fmt --all -- --check -- GitLab From 12194445b222ec4a31ef247d1bced9ba127d7d52 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Tue, 5 Sep 2023 12:34:50 +0300 Subject: [PATCH 078/633] Get rid of polling in `WarpSync` (#1265) --- polkadot/node/service/src/lib.rs | 2 +- substrate/bin/node/cli/src/service.rs | 3 +- .../client/network/common/src/sync/warp.rs | 13 +- substrate/client/network/sync/src/engine.rs | 118 ++++-- substrate/client/network/sync/src/lib.rs | 335 ++++++++++-------- substrate/client/network/sync/src/warp.rs | 95 +++-- substrate/client/network/test/src/lib.rs | 5 +- substrate/client/service/src/builder.rs | 5 +- substrate/client/service/src/lib.rs | 2 +- 9 files changed, 344 insertions(+), 234 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 95c887947c9..7f4eadaba7f 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -732,7 +732,7 @@ pub fn new_full( }: NewFullParams, ) -> Result { use polkadot_node_network_protocol::request_response::IncomingRequest; - use sc_network_common::sync::warp::WarpSyncParams; + use sc_network_sync::warp::WarpSyncParams; let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled; let role = config.role.clone(); diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index ecca5c60db5..e49c60fe2fb 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -32,8 +32,7 @@ use sc_client_api::{Backend, BlockBackend}; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::{event::Event, NetworkEventStream, NetworkService}; -use sc_network_common::sync::warp::WarpSyncParams; -use sc_network_sync::SyncingService; +use sc_network_sync::{warp::WarpSyncParams, SyncingService}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_statement_store::Store as StatementStore; use sc_telemetry::{Telemetry, TelemetryWorker}; diff --git a/substrate/client/network/common/src/sync/warp.rs b/substrate/client/network/common/src/sync/warp.rs index 91d6c4151a4..f4e39f43851 100644 --- a/substrate/client/network/common/src/sync/warp.rs +++ b/substrate/client/network/common/src/sync/warp.rs @@ -15,10 +15,9 @@ // along with Substrate. If not, see . use codec::{Decode, Encode}; -use futures::channel::oneshot; pub use sp_consensus_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::{fmt, sync::Arc}; +use std::fmt; /// Scale-encoded warp sync proof response. pub struct EncodedProof(pub Vec); @@ -30,16 +29,6 @@ pub struct WarpProofRequest { pub begin: B::Hash, } -/// The different types of warp syncing. -pub enum WarpSyncParams { - /// Standard warp sync for the chain. - WithProvider(Arc>), - /// Skip downloading proofs and wait for a header of the state that should be downloaded. - /// - /// It is expected that the header provider ensures that the header is trusted. - WaitForTarget(oneshot::Receiver<::Header>), -} - /// Proof verification result. pub enum VerificationResult { /// Proof is valid, but the target was not reached. diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 9b97bf2b7c3..23847d16c97 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -24,11 +24,16 @@ use crate::{ BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, }, service::{self, chain_sync::ToServiceCommand}, + warp::WarpSyncParams, ChainSync, ClientError, SyncingService, }; use codec::{Decode, Encode}; -use futures::{FutureExt, StreamExt}; +use futures::{ + channel::oneshot, + future::{BoxFuture, Fuse}, + FutureExt, StreamExt, +}; use futures_timer::Delay; use libp2p::PeerId; use prometheus_endpoint::{ @@ -47,7 +52,6 @@ use sc_network_common::{ role::Roles, sync::{ message::{BlockAnnounce, BlockAnnouncesHandshake, BlockState}, - warp::WarpSyncParams, BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, SyncEvent, }, }; @@ -67,6 +71,9 @@ use std::{ time::{Duration, Instant}, }; +/// Log target for this file. +const LOG_TARGET: &'static str = "sync"; + /// Interval at which we perform time based maintenance const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100); @@ -251,6 +258,10 @@ pub struct SyncingEngine { /// The `PeerId`'s of all boot nodes. boot_node_ids: HashSet, + /// A channel to get target block header if we skip over proofs downloading during warp sync. + warp_sync_target_block_header_rx: + Fuse>>, + /// Protocol name used for block announcements block_announce_protocol_name: ProtocolName, @@ -299,7 +310,11 @@ where let max_blocks_per_request = if net_config.network_config.max_blocks_per_request > crate::MAX_BLOCKS_IN_RESPONSE as u32 { - log::info!(target: "sync", "clamping maximum blocks per request to {}", crate::MAX_BLOCKS_IN_RESPONSE); + log::info!( + target: LOG_TARGET, + "clamping maximum blocks per request to {}", + crate::MAX_BLOCKS_IN_RESPONSE, + ); crate::MAX_BLOCKS_IN_RESPONSE as u32 } else { net_config.network_config.max_blocks_per_request @@ -352,6 +367,19 @@ where total.saturating_sub(net_config.network_config.default_peers_set_num_full) as usize }; + // Split warp sync params into warp sync config and a channel to retreive target block + // header. + let (warp_sync_config, warp_sync_target_block_header_rx) = + warp_sync_params.map_or((None, None), |params| { + let (config, target_block_rx) = params.split(); + (Some(config), target_block_rx) + }); + + // Make sure polling of the target block channel is a no-op if there is no block to + // retrieve. + 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(), @@ -360,7 +388,7 @@ where roles, max_parallel_downloads, max_blocks_per_request, - warp_sync_params, + warp_sync_config, metrics_registry, network_service.clone(), import_queue, @@ -404,6 +432,7 @@ where genesis_hash, important_peers, default_peers_set_no_slot_connected_peers: HashSet::new(), + warp_sync_target_block_header_rx, boot_node_ids, default_peers_set_no_slot_peers, default_peers_set_num_full, @@ -418,7 +447,7 @@ where match Metrics::register(r, is_major_syncing.clone()) { Ok(metrics) => Some(metrics), Err(err) => { - log::error!(target: "sync", "Failed to register metrics {err:?}"); + log::error!(target: LOG_TARGET, "Failed to register metrics {err:?}"); None }, } @@ -510,7 +539,10 @@ where let peer = match self.peers.get_mut(&peer_id) { Some(p) => p, None => { - log::error!(target: "sync", "Received block announce from disconnected peer {}", peer_id); + log::error!( + target: LOG_TARGET, + "Received block announce from disconnected peer {peer_id}", + ); debug_assert!(false); return }, @@ -536,11 +568,11 @@ where let header = match self.client.header(hash) { Ok(Some(header)) => header, Ok(None) => { - log::warn!(target: "sync", "Trying to announce unknown block: {}", hash); + log::warn!(target: LOG_TARGET, "Trying to announce unknown block: {hash}"); return }, Err(e) => { - log::warn!(target: "sync", "Error reading block header {}: {}", hash, e); + log::warn!(target: LOG_TARGET, "Error reading block header {hash}: {e}"); return }, }; @@ -551,7 +583,7 @@ where } let is_best = self.client.info().best_hash == hash; - log::debug!(target: "sync", "Reannouncing block {:?} is_best: {}", hash, is_best); + log::debug!(target: LOG_TARGET, "Reannouncing block {hash:?} is_best: {is_best}"); let data = data .or_else(|| self.block_announce_data_cache.get(&hash).cloned()) @@ -560,7 +592,7 @@ where for (peer_id, ref mut peer) in self.peers.iter_mut() { let inserted = peer.known_blocks.insert(hash); if inserted { - log::trace!(target: "sync", "Announcing block {:?} to {}", hash, peer_id); + log::trace!(target: LOG_TARGET, "Announcing block {hash:?} to {peer_id}"); let message = BlockAnnounce { header: header.clone(), state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, @@ -575,7 +607,7 @@ where /// Inform sync about new best imported block. pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { - log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); + log::debug!(target: LOG_TARGET, "New best block imported {hash:?}/#{number}"); self.chain_sync.update_chain_info(&hash, number); self.network_service.set_notification_handshake( @@ -619,7 +651,10 @@ where // consider it connected or are also all stalled. In order to unstall the node, // disconnect all peers and allow `ProtocolController` to establish new connections. if self.last_notification_io.elapsed() > INACTIVITY_EVICT_THRESHOLD { - log::debug!(target: "sync", "syncing has halted due to inactivity, evicting all peers"); + log::debug!( + target: LOG_TARGET, + "syncing has halted due to inactivity, evicting all peers", + ); for peer in self.peers.keys() { self.network_service.report_peer(*peer, rep::INACTIVE_SUBSTREAM); @@ -658,7 +693,10 @@ where ToServiceCommand::JustificationImported(peer_id, hash, number, success) => { self.chain_sync.on_justification_import(hash, number, success); if !success { - log::info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer_id, hash); + log::info!( + target: LOG_TARGET, + "💔 Invalid justification provided by {peer_id} for #{hash}", + ); self.network_service .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); self.network_service.report_peer( @@ -723,7 +761,7 @@ where }, Err(()) => { log::debug!( - target: "sync", + target: LOG_TARGET, "Failed to register peer {remote:?}: {received_handshake:?}", ); let _ = tx.send(false); @@ -732,7 +770,7 @@ where sc_network::SyncEvent::NotificationStreamClosed { remote } => { if self.on_sync_peer_disconnected(remote).is_err() { log::trace!( - target: "sync", + target: LOG_TARGET, "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", remote ); @@ -749,9 +787,8 @@ where } } else { log::trace!( - target: "sync", - "Received sync for peer earlier refused by sync layer: {}", - remote + target: LOG_TARGET, + "Received sync for peer earlier refused by sync layer: {remote}", ); } } @@ -764,6 +801,21 @@ where } } + // Retreive warp sync target block header just before polling `ChainSync` + // to make progress as soon as we receive it. + match self.warp_sync_target_block_header_rx.poll_unpin(cx) { + Poll::Ready(Ok(target)) => { + self.chain_sync.set_warp_sync_target_block(target); + }, + Poll::Ready(Err(err)) => { + log::error!( + target: LOG_TARGET, + "Failed to get target block for warp sync. Error: {err:?}", + ); + }, + Poll::Pending => {}, + } + // Drive `ChainSync`. while let Poll::Ready(()) = self.chain_sync.poll(cx) {} @@ -784,9 +836,9 @@ where pub fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) -> Result<(), ()> { if let Some(info) = self.peers.remove(&peer_id) { if self.important_peers.contains(&peer_id) { - log::warn!(target: "sync", "Reserved peer {} disconnected", peer_id); + log::warn!(target: LOG_TARGET, "Reserved peer {peer_id} disconnected"); } else { - log::debug!(target: "sync", "{} disconnected", peer_id); + log::debug!(target: LOG_TARGET, "{peer_id} disconnected"); } if !self.default_peers_set_no_slot_connected_peers.remove(&peer_id) && @@ -798,7 +850,7 @@ where }, None => { log::error!( - target: "sync", + target: LOG_TARGET, "trying to disconnect an inbound node which is not counted as inbound" ); debug_assert!(false); @@ -828,10 +880,13 @@ where sink: NotificationsSink, inbound: bool, ) -> Result<(), ()> { - log::trace!(target: "sync", "New peer {} {:?}", peer_id, status); + log::trace!(target: LOG_TARGET, "New peer {peer_id} {status:?}"); if self.peers.contains_key(&peer_id) { - log::error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", peer_id); + log::error!( + target: LOG_TARGET, + "Called on_sync_peer_connected with already connected peer {peer_id}", + ); debug_assert!(false); return Err(()) } @@ -841,7 +896,7 @@ where if self.important_peers.contains(&peer_id) { log::error!( - target: "sync", + target: LOG_TARGET, "Reserved peer id `{}` is on a different chain (our genesis: {} theirs: {})", peer_id, self.genesis_hash, @@ -849,7 +904,7 @@ where ); } else if self.boot_node_ids.contains(&peer_id) { log::error!( - target: "sync", + target: LOG_TARGET, "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", peer_id, self.genesis_hash, @@ -857,7 +912,7 @@ where ); } else { log::debug!( - target: "sync", + target: LOG_TARGET, "Peer is on different chain (our genesis: {} theirs: {})", self.genesis_hash, status.genesis_hash ); @@ -874,7 +929,10 @@ where status.roles.is_full() && inbound && self.num_in_peers == self.max_in_peers { - log::debug!(target: "sync", "All inbound slots have been consumed, rejecting {peer_id}"); + log::debug!( + target: LOG_TARGET, + "All inbound slots have been consumed, rejecting {peer_id}", + ); return Err(()) } @@ -884,7 +942,7 @@ where self.default_peers_set_no_slot_connected_peers.len() + this_peer_reserved_slot { - log::debug!(target: "sync", "Too many full nodes, rejecting {}", peer_id); + log::debug!(target: LOG_TARGET, "Too many full nodes, rejecting {peer_id}"); return Err(()) } @@ -892,7 +950,7 @@ where (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light { // Make sure that not all slots are occupied by light clients. - log::debug!(target: "sync", "Too many light nodes, rejecting {}", peer_id); + log::debug!(target: LOG_TARGET, "Too many light nodes, rejecting {peer_id}"); return Err(()) } @@ -921,7 +979,7 @@ where None }; - log::debug!(target: "sync", "Connected {}", peer_id); + log::debug!(target: LOG_TARGET, "Connected {peer_id}"); self.peers.insert(peer_id, peer); diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 0c2013b1497..df0ed2c4541 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -32,7 +32,7 @@ use crate::{ blocks::BlockCollection, schema::v1::{StateRequest, StateResponse}, state::StateSync, - warp::{WarpProofImportResult, WarpSync}, + warp::{WarpProofImportResult, WarpSync, WarpSyncConfig}, }; use codec::{Decode, DecodeAll, Encode}; @@ -61,7 +61,7 @@ use sc_network_common::{ BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, }, - warp::{EncodedProof, WarpProofRequest, WarpSyncParams, WarpSyncPhase, WarpSyncProgress}, + warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress}, BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, PeerRequest, SyncMode, SyncState, SyncStatus, @@ -103,6 +103,9 @@ pub mod state_request_handler; pub mod warp; pub mod warp_request_handler; +/// Log target for this file. +const LOG_TARGET: &'static str = "sync"; + /// Maximum blocks to store in the import queue. const MAX_IMPORTING_BLOCKS: usize = 2048; @@ -302,10 +305,12 @@ pub struct ChainSync { state_sync: Option>, /// Warp sync in progress, if any. warp_sync: Option>, - /// Warp sync params. + /// Warp sync configuration. /// /// Will be `None` after `self.warp_sync` is `Some(_)`. - warp_sync_params: Option>, + warp_sync_config: Option>, + /// A temporary storage for warp sync target block until warp sync is initialized. + warp_sync_target_block_header: Option, /// Enable importing existing blocks. This is used used after the state download to /// catch up to the latest state while re-importing blocks. import_existing: bool, @@ -351,7 +356,7 @@ impl PeerSync { fn update_common_number(&mut self, new_common: NumberFor) { if self.common_number < new_common { trace!( - target: "sync", + target: LOG_TARGET, "Updating peer {} common number from={} => to={}.", self.peer_id, self.common_number, @@ -497,7 +502,7 @@ where // There is nothing sync can get from the node that has no blockchain data. match self.block_status(&best_hash) { Err(e) => { - debug!(target:"sync", "Error reading blockchain: {}", e); + debug!(target:LOG_TARGET, "Error reading blockchain: {e}"); Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) }, Ok(BlockStatus::KnownBad) => { @@ -515,7 +520,7 @@ where // an ancestor search, which is what we do in the next match case below. if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS.into() { debug!( - target:"sync", + target:LOG_TARGET, "New peer with unknown best hash {} ({}), assuming common block.", self.best_queued_hash, self.best_queued_number @@ -536,10 +541,8 @@ where // If we are at genesis, just start downloading. let (state, req) = if self.best_queued_number.is_zero() { debug!( - target:"sync", - "New peer with best hash {} ({}).", - best_hash, - best_number, + target:LOG_TARGET, + "New peer with best hash {best_hash} ({best_number}).", ); (PeerSyncState::Available, None) @@ -547,7 +550,7 @@ where let common_best = std::cmp::min(self.best_queued_number, best_number); debug!( - target:"sync", + target:LOG_TARGET, "New peer with unknown best hash {} ({}), searching for common ancestor.", best_hash, best_number @@ -578,9 +581,14 @@ where if let SyncMode::Warp = self.mode { if self.peers.len() >= MIN_PEERS_TO_START_WARP_SYNC && self.warp_sync.is_none() { - log::debug!(target: "sync", "Starting warp state sync."); - if let Some(params) = self.warp_sync_params.take() { - self.warp_sync = Some(WarpSync::new(self.client.clone(), params)); + log::debug!(target: LOG_TARGET, "Starting warp state sync."); + + if let Some(config) = self.warp_sync_config.take() { + let mut warp_sync = WarpSync::new(self.client.clone(), config); + if let Some(header) = self.warp_sync_target_block_header.take() { + warp_sync.set_target_block(header); + } + self.warp_sync = Some(warp_sync); } } } @@ -590,10 +598,8 @@ where Ok(BlockStatus::InChainWithState) | Ok(BlockStatus::InChainPruned) => { debug!( - target: "sync", - "New peer with known best hash {} ({}).", - best_hash, - best_number, + target: LOG_TARGET, + "New peer with known best hash {best_hash} ({best_number}).", ); self.peers.insert( who, @@ -642,21 +648,23 @@ where .collect(); debug!( - target: "sync", - "Explicit sync request for block {:?} with no peers specified. \ - Syncing from these peers {:?} instead.", - hash, peers, + target: LOG_TARGET, + "Explicit sync request for block {hash:?} with no peers specified. \ + Syncing from these peers {peers:?} instead.", ); } else { - debug!(target: "sync", "Explicit sync request for block {:?} with {:?}", hash, peers); + debug!( + target: LOG_TARGET, + "Explicit sync request for block {hash:?} with {peers:?}", + ); } if self.is_known(hash) { - debug!(target: "sync", "Refusing to sync known hash {:?}", hash); + debug!(target: LOG_TARGET, "Refusing to sync known hash {hash:?}"); return } - trace!(target: "sync", "Downloading requested old fork {:?}", hash); + trace!(target: LOG_TARGET, "Downloading requested old fork {hash:?}"); for peer_id in &peers { if let Some(peer) = self.peers.get_mut(peer_id) { if let PeerSyncState::AncestorSearch { .. } = peer.state { @@ -689,7 +697,7 @@ where let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { let mut blocks = response.blocks; if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) { - trace!(target: "sync", "Reversing incoming block list"); + trace!(target: LOG_TARGET, "Reversing incoming block list"); blocks.reverse() } self.allowed_requests.add(who); @@ -740,17 +748,22 @@ where } }) .collect(); - debug!(target: "sync", "Drained {} gap blocks from {}", blocks.len(), gap_sync.best_queued_number); + debug!( + target: LOG_TARGET, + "Drained {} gap blocks from {}", + blocks.len(), + gap_sync.best_queued_number, + ); blocks } else { - debug!(target: "sync", "Unexpected gap block response from {}", who); + debug!(target: LOG_TARGET, "Unexpected gap block response from {who}"); return Err(BadPeer(*who, rep::NO_BLOCK)) } }, PeerSyncState::DownloadingStale(_) => { peer.state = PeerSyncState::Available; if blocks.is_empty() { - debug!(target: "sync", "Empty block response from {}", who); + debug!(target: LOG_TARGET, "Empty block response from {who}"); return Err(BadPeer(*who, rep::NO_BLOCK)) } validate_blocks::(&blocks, who, Some(request))?; @@ -779,7 +792,7 @@ where let matching_hash = match (blocks.get(0), self.client.hash(*current)) { (Some(block), Ok(maybe_our_block_hash)) => { trace!( - target: "sync", + target: LOG_TARGET, "Got ancestry block #{} ({}) from peer {}", current, block.hash, @@ -789,17 +802,15 @@ where }, (None, _) => { debug!( - target: "sync", - "Invalid response when searching for ancestor from {}", - who, + target: LOG_TARGET, + "Invalid response when searching for ancestor from {who}", ); return Err(BadPeer(*who, rep::UNKNOWN_ANCESTOR)) }, (_, Err(e)) => { info!( - target: "sync", - "❌ Error answering legitimate blockchain query: {}", - e, + target: LOG_TARGET, + "❌ Error answering legitimate blockchain query: {e}", ); return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR)) }, @@ -817,7 +828,10 @@ where } } if matching_hash.is_none() && current.is_zero() { - trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); + trace!( + target:LOG_TARGET, + "Ancestry search: genesis mismatch for peer {who}", + ); return Err(BadPeer(*who, rep::GENESIS_MISMATCH)) } if let Some((next_state, next_num)) = @@ -833,7 +847,7 @@ where // Ancestry search is complete. Check if peer is on a stale fork unknown // to us and add it to sync targets if necessary. trace!( - target: "sync", + target: LOG_TARGET, "Ancestry search complete. Ours={} ({}), Theirs={} ({}), Common={:?} ({})", self.best_queued_hash, self.best_queued_number, @@ -846,7 +860,7 @@ where peer.best_number < self.best_queued_number { trace!( - target: "sync", + target: LOG_TARGET, "Added fork target {} for {}", peer.best_hash, who, @@ -879,11 +893,11 @@ where return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), } } else if blocks.is_empty() { - debug!(target: "sync", "Empty block response from {}", who); + debug!(target: LOG_TARGET, "Empty block response from {who}"); return Err(BadPeer(*who, rep::NO_BLOCK)) } else { debug!( - target: "sync", + target: LOG_TARGET, "Too many blocks ({}) in warp target block response from {}", blocks.len(), who, @@ -892,7 +906,7 @@ where } } else { debug!( - target: "sync", + target: LOG_TARGET, "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", who, ); @@ -944,7 +958,10 @@ where let peer = if let Some(peer) = self.peers.get_mut(&who) { peer } else { - error!(target: "sync", "💔 Called on_block_justification with a peer ID of an unknown peer"); + error!( + target: LOG_TARGET, + "💔 Called on_block_justification with a peer ID of an unknown peer", + ); return Ok(OnBlockJustification::Nothing) }; @@ -956,7 +973,7 @@ where let justification = if let Some(block) = response.blocks.into_iter().next() { if hash != block.hash { warn!( - target: "sync", + target: LOG_TARGET, "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", who, hash, @@ -972,10 +989,8 @@ where // we might have asked the peer for a justification on a block that we assumed it // had but didn't (regardless of whether it had a justification for it or not). trace!( - target: "sync", - "Peer {:?} provided empty response for justification request {:?}", - who, - hash, + target: LOG_TARGET, + "Peer {who:?} provided empty response for justification request {hash:?}", ); None @@ -1013,10 +1028,8 @@ where if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { if let Ok(Some(header)) = self.client.header(*hash) { log::debug!( - target: "sync", - "Starting state sync for #{} ({})", - number, - hash, + target: LOG_TARGET, + "Starting state sync for #{number} ({hash})", ); self.state_sync = Some(StateSync::new( self.client.clone(), @@ -1033,9 +1046,8 @@ where if let Err(err) = r { warn!( - target: "sync", - "💔 Error cleaning up pending extra justification data requests: {}", - err, + target: LOG_TARGET, + "💔 Error cleaning up pending extra justification data requests: {err}", ); } } @@ -1057,12 +1069,12 @@ where let peer = if let Some(peer) = self.peers.get_mut(&who) { peer } else { - error!(target: "sync", "💔 Called `on_validated_block_announce` with a bad peer ID"); + error!(target: LOG_TARGET, "💔 Called `on_validated_block_announce` with a bad peer ID"); return }; if let PeerSyncState::AncestorSearch { .. } = peer.state { - trace!(target: "sync", "Peer {} is in the ancestor search state.", who); + trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", who); return } @@ -1222,12 +1234,6 @@ where } fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { - // Should be called before `process_outbound_requests` to ensure - // that a potential target block is directly leading to requests. - if let Some(warp_sync) = &mut self.warp_sync { - let _ = warp_sync.poll(cx); - } - self.process_outbound_requests(); while let Poll::Ready(result) = self.poll_pending_responses(cx) { @@ -1262,9 +1268,8 @@ where }, Err(err) => { log::warn!( - target: "sync", - "Failed to encode block request {:?}: {:?}", - opaque_req, err + target: LOG_TARGET, + "Failed to encode block request {opaque_req:?}: {err:?}", ); }, } @@ -1292,7 +1297,7 @@ where roles: Roles, max_parallel_downloads: u32, max_blocks_per_request: u32, - warp_sync_params: Option>, + warp_sync_config: Option>, metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, import_queue: Box>, @@ -1334,7 +1339,8 @@ where network_service, block_request_protocol_name, state_request_protocol_name, - warp_sync_params, + warp_sync_config, + warp_sync_target_block_header: None, warp_sync_protocol_name, block_announce_protocol_name: block_announce_config .notifications_protocol @@ -1346,7 +1352,10 @@ where match SyncingMetrics::register(r) { Ok(metrics) => Some(metrics), Err(err) => { - error!(target: "sync", "Failed to register metrics for ChainSync: {err:?}"); + error!( + target: LOG_TARGET, + "Failed to register metrics for ChainSync: {err:?}", + ); None }, } @@ -1403,7 +1412,7 @@ where new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); if new_blocks.len() != orig_len { debug!( - target: "sync", + target: LOG_TARGET, "Ignoring {} blocks that are already queued", orig_len - new_blocks.len(), ); @@ -1420,7 +1429,7 @@ where .and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) { trace!( - target:"sync", + target:LOG_TARGET, "Accepted {} blocks ({:?}) with origin {:?}", new_blocks.len(), h, @@ -1444,7 +1453,7 @@ where /// through all peers to update our view of their state as well. fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor) { if self.fork_targets.remove(hash).is_some() { - trace!(target: "sync", "Completed fork sync {:?}", hash); + trace!(target: LOG_TARGET, "Completed fork sync {hash:?}"); } if let Some(gap_sync) = &mut self.gap_sync { if number > gap_sync.best_queued_number && number <= gap_sync.target { @@ -1463,7 +1472,7 @@ where let new_common_number = if peer.best_number >= number { number } else { peer.best_number }; trace!( - target: "sync", + target: LOG_TARGET, "Updating peer {} info, ours={}, common={}->{}, their best={}", n, number, @@ -1483,10 +1492,15 @@ where fn restart(&mut self) -> impl Iterator), BadPeer>> + '_ { self.blocks.clear(); if let Err(e) = self.reset_sync_start_point() { - warn!(target: "sync", "💔 Unable to restart sync: {}", e); + warn!(target: LOG_TARGET, "💔 Unable to restart sync: {e}"); } self.allowed_requests.set_all(); - debug!(target:"sync", "Restarted with {} ({})", self.best_queued_number, self.best_queued_hash); + debug!( + target: LOG_TARGET, + "Restarted with {} ({})", + self.best_queued_number, + self.best_queued_hash, + ); let old_peers = std::mem::take(&mut self.peers); old_peers.into_iter().filter_map(move |(id, mut p)| { @@ -1517,14 +1531,14 @@ where let info = self.client.info(); if matches!(self.mode, SyncMode::LightState { .. }) && info.finalized_state.is_some() { warn!( - target: "sync", + target: LOG_TARGET, "Can't use fast sync mode with a partially synced database. Reverting to full sync mode." ); self.mode = SyncMode::Full; } if matches!(self.mode, SyncMode::Warp) && info.finalized_state.is_some() { warn!( - target: "sync", + target: LOG_TARGET, "Can't use warp sync mode with a partially synced database. Reverting to full sync mode." ); self.mode = SyncMode::Full; @@ -1539,25 +1553,30 @@ where self.import_existing = true; // Latest state is missing, start with the last finalized state or genesis instead. if let Some((hash, number)) = info.finalized_state { - debug!(target: "sync", "Starting from finalized state #{}", number); + debug!(target: LOG_TARGET, "Starting from finalized state #{number}"); self.best_queued_hash = hash; self.best_queued_number = number; } else { - debug!(target: "sync", "Restarting from genesis"); + debug!(target: LOG_TARGET, "Restarting from genesis"); self.best_queued_hash = Default::default(); self.best_queued_number = Zero::zero(); } } if let Some((start, end)) = info.block_gap { - debug!(target: "sync", "Starting gap sync #{} - #{}", start, end); + debug!(target: LOG_TARGET, "Starting gap sync #{start} - #{end}"); self.gap_sync = Some(GapSync { best_queued_number: start - One::one(), target: end, blocks: BlockCollection::new(), }); } - trace!(target: "sync", "Restarted sync at #{} ({:?})", self.best_queued_number, self.best_queued_hash); + trace!( + target: LOG_TARGET, + "Restarted sync at #{} ({:?})", + self.best_queued_number, + self.best_queued_hash, + ); Ok(()) } @@ -1607,6 +1626,15 @@ where .collect() } + /// Set warp sync target block externally in case we skip warp proof downloading. + pub fn set_warp_sync_target_block(&mut self, header: B::Header) { + if let Some(ref mut warp_sync) = self.warp_sync { + warp_sync.set_target_block(header); + } else { + self.warp_sync_target_block_header = Some(header); + } + } + /// Generate block request for downloading of the target block body during warp sync. fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { let sync = &self.warp_sync.as_ref()?; @@ -1625,7 +1653,7 @@ where // Find a random peer that has a block with the target number. for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.best_number >= target_number { - trace!(target: "sync", "New warp target block request for {}", id); + trace!(target: LOG_TARGET, "New warp target block request for {id}"); peer.state = PeerSyncState::DownloadingWarpTargetBlock; self.allowed_requests.clear(); return Some((*id, request)) @@ -1716,9 +1744,8 @@ where }, Err(err) => { log::warn!( - target: "sync", - "Failed to encode state request {:?}: {:?}", - request, err + target: LOG_TARGET, + "Failed to encode state request {request:?}: {err:?}", ); }, } @@ -1742,9 +1769,8 @@ where ), None => { log::warn!( - target: "sync", - "Trying to send warp sync request when no protocol is configured {:?}", - request, + target: LOG_TARGET, + "Trying to send warp sync request when no protocol is configured {request:?}", ); }, } @@ -1759,7 +1785,12 @@ where let blocks = match self.block_response_into_blocks(&request, response) { Ok(blocks) => blocks, Err(err) => { - debug!(target: "sync", "Failed to decode block response from {}: {}", peer_id, err); + debug!( + target: LOG_TARGET, + "Failed to decode block response from {}: {}", + peer_id, + err, + ); self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); return None }, @@ -1779,7 +1810,7 @@ where _ => Default::default(), }; trace!( - target: "sync", + target: LOG_TARGET, "BlockResponse {} from {} with {} blocks {}", block_response.id, peer_id, @@ -1888,10 +1919,8 @@ where Ok(proto) => proto, Err(e) => { debug!( - target: "sync", - "Failed to decode block response from peer {:?}: {:?}.", - id, - e + target: LOG_TARGET, + "Failed to decode block response from peer {id:?}: {e:?}.", ); self.network_service.report_peer(id, rep::BAD_MESSAGE); self.network_service @@ -1909,10 +1938,8 @@ where Ok(proto) => proto, Err(e) => { debug!( - target: "sync", - "Failed to decode state response from peer {:?}: {:?}.", - id, - e + target: LOG_TARGET, + "Failed to decode state response from peer {id:?}: {e:?}.", ); self.network_service.report_peer(id, rep::BAD_MESSAGE); self.network_service @@ -1930,7 +1957,7 @@ where }, }, Ok(Err(e)) => { - debug!(target: "sync", "Request to peer {:?} failed: {:?}.", id, e); + debug!(target: LOG_TARGET, "Request to peer {id:?} failed: {e:?}."); match e { RequestFailure::Network(OutboundFailure::Timeout) => { @@ -1971,9 +1998,8 @@ where }, Err(oneshot::Canceled) => { trace!( - target: "sync", - "Request to peer {:?} failed due to oneshot being canceled.", - id, + 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()); @@ -2058,7 +2084,7 @@ where } if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { - trace!(target: "sync", "Too many blocks in the queue."); + trace!(target: LOG_TARGET, "Too many blocks in the queue."); return Vec::new() } let is_major_syncing = self.status().state.is_major_syncing(); @@ -2093,7 +2119,7 @@ where queue.len() <= MAJOR_SYNC_BLOCKS.into() { trace!( - target: "sync", + target: LOG_TARGET, "Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.", id, peer.common_number, @@ -2118,7 +2144,7 @@ where ) { peer.state = PeerSyncState::DownloadingNew(range.start); trace!( - target: "sync", + target: LOG_TARGET, "New block request for {}, (best:{}, common:{}) {:?}", id, peer.best_number, @@ -2141,7 +2167,7 @@ where }, max_blocks_per_request, ) { - trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); + trace!(target: LOG_TARGET, "Downloading fork {hash:?} from {id}"); peer.state = PeerSyncState::DownloadingStale(hash); Some((id, req)) } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { @@ -2157,7 +2183,7 @@ where }) { peer.state = PeerSyncState::DownloadingGap(range.start); trace!( - target: "sync", + target: LOG_TARGET, "New gap block request for {}, (best:{}, common:{}) {:?}", id, peer.best_number, @@ -2192,7 +2218,7 @@ where if peer.state.is_available() && peer.common_number >= sync.target_block_num() { peer.state = PeerSyncState::DownloadingState; let request = sync.next_request(); - trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); + trace!(target: LOG_TARGET, "New StateRequest for {}: {:?}", id, request); self.allowed_requests.clear(); return Some((*id, OpaqueStateRequest(Box::new(request)))) } @@ -2207,7 +2233,7 @@ where { for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.best_number >= target { - trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); + trace!(target: LOG_TARGET, "New StateRequest for {id}: {request:?}"); peer.state = PeerSyncState::DownloadingState; self.allowed_requests.clear(); return Some((*id, OpaqueStateRequest(Box::new(request)))) @@ -2237,7 +2263,7 @@ where // Find a random peer that is synced as much as peer majority. for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.best_number >= median { - trace!(target: "sync", "New WarpProofRequest for {}", id); + trace!(target: LOG_TARGET, "New WarpProofRequest for {id}"); peer.state = PeerSyncState::DownloadingWarpProof; self.allowed_requests.clear(); return Some((*id, request)) @@ -2256,7 +2282,7 @@ where ) -> Result, BadPeer> { let response: Box = response.0.downcast().map_err(|_error| { error!( - target: "sync", + target: LOG_TARGET, "Failed to downcast opaque state response, this is an implementation bug." ); @@ -2271,7 +2297,7 @@ where } let import_result = if let Some(sync) = &mut self.state_sync { debug!( - target: "sync", + target: LOG_TARGET, "Importing state data from {} with {} keys, {} proof nodes.", who, response.entries.len(), @@ -2280,7 +2306,7 @@ where sync.import(*response) } else if let Some(sync) = &mut self.warp_sync { debug!( - target: "sync", + target: LOG_TARGET, "Importing state data from {} with {} keys, {} proof nodes.", who, response.entries.len(), @@ -2288,7 +2314,7 @@ where ); sync.import_state(*response) } else { - debug!(target: "sync", "Ignored obsolete state response from {}", who); + debug!(target: LOG_TARGET, "Ignored obsolete state response from {who}"); return Err(BadPeer(*who, rep::NOT_REQUESTED)) }; @@ -2307,12 +2333,12 @@ where skip_execution: self.skip_execution(), state: Some(state), }; - debug!(target: "sync", "State download is complete. Import is queued"); + debug!(target: LOG_TARGET, "State download is complete. Import is queued"); Ok(OnStateData::Import(origin, block)) }, state::ImportResult::Continue => Ok(OnStateData::Continue), state::ImportResult::BadResponse => { - debug!(target: "sync", "Bad state data received from {}", who); + debug!(target: LOG_TARGET, "Bad state data received from {who}"); Err(BadPeer(*who, rep::BAD_BLOCK)) }, } @@ -2327,21 +2353,21 @@ where } let import_result = if let Some(sync) = &mut self.warp_sync { debug!( - target: "sync", + target: LOG_TARGET, "Importing warp proof data from {}, {} bytes.", who, response.0.len(), ); sync.import_warp_proof(response) } else { - debug!(target: "sync", "Ignored obsolete warp sync response from {}", who); + debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {who}"); return Err(BadPeer(*who, rep::NOT_REQUESTED)) }; match import_result { WarpProofImportResult::Success => Ok(()), WarpProofImportResult::BadResponse => { - debug!(target: "sync", "Bad proof data received from {}", who); + debug!(target: LOG_TARGET, "Bad proof data received from {who}"); Err(BadPeer(*who, rep::BAD_BLOCK)) }, } @@ -2379,7 +2405,7 @@ where count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, ) -> Box), BadPeer>>> { - trace!(target: "sync", "Imported {} of {}", imported, count); + trace!(target: LOG_TARGET, "Imported {imported} of {count}"); let mut output = Vec::new(); @@ -2406,7 +2432,7 @@ where Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { if aux.clear_justification_requests { trace!( - target: "sync", + target: LOG_TARGET, "Block imported clears all pending justification requests {number}: {hash:?}", ); self.clear_justification_requests(); @@ -2414,7 +2440,7 @@ where if aux.needs_justification { trace!( - target: "sync", + target: LOG_TARGET, "Block imported but requires justification {number}: {hash:?}", ); self.request_justification(&hash, number); @@ -2434,7 +2460,7 @@ where self.state_sync.as_ref().map_or(false, |s| s.target() == hash); if state_sync_complete { info!( - target: "sync", + target: LOG_TARGET, "State sync is complete ({} MiB), restarting block sync.", self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)), ); @@ -2448,7 +2474,7 @@ where .map_or(false, |s| s.target_block_hash() == Some(hash)); if warp_sync_complete { info!( - target: "sync", + target: LOG_TARGET, "Warp sync is complete ({} MiB), restarting block sync.", self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)), ); @@ -2460,7 +2486,7 @@ where self.gap_sync.as_ref().map_or(false, |s| s.target == number); if gap_sync_complete { info!( - target: "sync", + target: LOG_TARGET, "Block history download is complete." ); self.gap_sync = None; @@ -2469,7 +2495,7 @@ where Err(BlockImportError::IncompleteHeader(who)) => if let Some(peer) = who { warn!( - target: "sync", + target: LOG_TARGET, "💔 Peer sent block with incomplete header to import", ); output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); @@ -2480,7 +2506,7 @@ where who.map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); warn!( - target: "sync", + target: LOG_TARGET, "💔 Verification failed for block {hash:?}{extra_message}: {e:?}", ); @@ -2493,7 +2519,7 @@ where Err(BlockImportError::BadBlock(who)) => if let Some(peer) = who { warn!( - target: "sync", + target: LOG_TARGET, "💔 Block {hash:?} received from peer {peer} has been blacklisted", ); output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); @@ -2502,10 +2528,10 @@ where // This may happen if the chain we were requesting upon has been discarded // in the meantime because other chain has been finalized. // Don't mark it as bad as it still may be synced if explicitly requested. - trace!(target: "sync", "Obsolete block {hash:?}"); + trace!(target: LOG_TARGET, "Obsolete block {hash:?}"); }, e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { - warn!(target: "sync", "💔 Error importing block {hash:?}: {}", e.unwrap_err()); + warn!(target: LOG_TARGET, "💔 Error importing block {hash:?}: {}", e.unwrap_err()); self.state_sync = None; self.warp_sync = None; output.extend(self.restart()); @@ -2625,7 +2651,7 @@ fn peer_block_request( return None } else if peer.common_number < finalized { trace!( - target: "sync", + target: LOG_TARGET, "Requesting pre-finalized chain from {:?}, common={}, finalized={}, peer best={}, our best={}", id, peer.common_number, finalized, peer.best_number, best_num, ); @@ -2704,11 +2730,21 @@ fn fork_sync_request( ) -> Option<(B::Hash, BlockRequest)> { targets.retain(|hash, r| { if r.number <= finalized { - trace!(target: "sync", "Removed expired fork sync request {:?} (#{})", hash, r.number); + trace!( + target: LOG_TARGET, + "Removed expired fork sync request {:?} (#{})", + hash, + r.number, + ); return false } if check_block(hash) != BlockStatus::Unknown { - trace!(target: "sync", "Removed obsolete fork sync request {:?} (#{})", hash, r.number); + trace!( + target: LOG_TARGET, + "Removed obsolete fork sync request {:?} (#{})", + hash, + r.number, + ); return false } true @@ -2729,7 +2765,10 @@ fn fork_sync_request( // request only single block 1 }; - trace!(target: "sync", "Downloading requested fork {:?} from {}, {} blocks", hash, id, count); + trace!( + target: LOG_TARGET, + "Downloading requested fork {hash:?} from {id}, {count} blocks", + ); return Some(( *hash, BlockRequest:: { @@ -2741,7 +2780,7 @@ fn fork_sync_request( }, )) } else { - trace!(target: "sync", "Fork too far in the future: {:?} (#{})", hash, r.number); + trace!(target: LOG_TARGET, "Fork too far in the future: {:?} (#{})", hash, r.number); } } None @@ -2778,7 +2817,7 @@ fn validate_blocks( if let Some(request) = request { if Some(blocks.len() as _) > request.max { debug!( - target: "sync", + target: LOG_TARGET, "Received more blocks than requested from {}. Expected in maximum {:?}, got {}.", who, request.max, @@ -2799,7 +2838,7 @@ fn validate_blocks( if !expected_block { debug!( - target: "sync", + target: LOG_TARGET, "Received block that was not requested. Requested {:?}, got {:?}.", request.from, block_header, @@ -2812,9 +2851,8 @@ fn validate_blocks( blocks.iter().any(|b| b.header.is_none()) { trace!( - target: "sync", - "Missing requested header for a block in response from {}.", - who, + target: LOG_TARGET, + "Missing requested header for a block in response from {who}.", ); return Err(BadPeer(*who, rep::BAD_RESPONSE)) @@ -2823,9 +2861,8 @@ fn validate_blocks( if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none()) { trace!( - target: "sync", - "Missing requested body for a block in response from {}.", - who, + target: LOG_TARGET, + "Missing requested body for a block in response from {who}.", ); return Err(BadPeer(*who, rep::BAD_RESPONSE)) @@ -2837,7 +2874,7 @@ fn validate_blocks( let hash = header.hash(); if hash != b.hash { debug!( - target:"sync", + target:LOG_TARGET, "Bad header received from {}. Expected hash {:?}, got {:?}", who, b.hash, @@ -2854,7 +2891,7 @@ fn validate_blocks( ); if expected != got { debug!( - target:"sync", + target:LOG_TARGET, "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", b.hash, who, @@ -3092,7 +3129,7 @@ mod test { ) -> BlockRequest { let requests = sync.block_requests(); - log::trace!(target: "sync", "Requests: {:?}", requests); + log::trace!(target: LOG_TARGET, "Requests: {requests:?}"); assert_eq!(1, requests.len()); assert_eq!(*peer, requests[0].0); @@ -3469,7 +3506,7 @@ mod test { break }; - log::trace!(target: "sync", "Request: {:?}", request); + log::trace!(target: LOG_TARGET, "Request: {request:?}"); } // Now request and import the fork. @@ -3611,7 +3648,7 @@ mod test { break }; - log::trace!(target: "sync", "Request: {:?}", request); + log::trace!(target: LOG_TARGET, "Request: {request:?}"); } // Now request and import the fork. diff --git a/substrate/client/network/sync/src/warp.rs b/substrate/client/network/sync/src/warp.rs index 912ad78dfdd..74835a6e015 100644 --- a/substrate/client/network/sync/src/warp.rs +++ b/substrate/client/network/sync/src/warp.rs @@ -19,36 +19,75 @@ //! Warp sync support. use crate::{ - oneshot, schema::v1::{StateRequest, StateResponse}, state::{ImportResult, StateSync}, }; -use futures::FutureExt; +use futures::channel::oneshot; use log::error; use sc_client_api::ProofProvider; use sc_network_common::sync::{ message::{BlockAttributes, BlockData, BlockRequest, Direction, FromBlock}, warp::{ - EncodedProof, VerificationResult, WarpProofRequest, WarpSyncParams, WarpSyncPhase, - WarpSyncProgress, WarpSyncProvider, + EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, + WarpSyncProvider, }, }; use sp_blockchain::HeaderBackend; use sp_consensus_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; -use std::{sync::Arc, task::Poll}; +use std::sync::Arc; +/// Log target for this file. +const LOG_TARGET: &'static str = "sync"; + +/// The different types of warp syncing, passed to `build_network`. +pub enum WarpSyncParams { + /// Standard warp sync for the chain. + WithProvider(Arc>), + /// Skip downloading proofs and wait for a header of the state that should be downloaded. + /// + /// It is expected that the header provider ensures that the header is trusted. + WaitForTarget(oneshot::Receiver<::Header>), +} + +/// Warp sync configuration as accepted by [`WarpSync`]. +pub enum WarpSyncConfig { + /// Standard warp sync for the chain. + WithProvider(Arc>), + /// Skip downloading proofs and wait for a header of the state that should be downloaded. + /// + /// It is expected that the header provider ensures that the header is trusted. + WaitForTarget, +} + +impl WarpSyncParams { + /// Split `WarpSyncParams` into `WarpSyncConfig` and warp sync target block header receiver. + pub fn split( + self, + ) -> (WarpSyncConfig, Option::Header>>) { + match self { + WarpSyncParams::WithProvider(provider) => + (WarpSyncConfig::WithProvider(provider), None), + WarpSyncParams::WaitForTarget(rx) => (WarpSyncConfig::WaitForTarget, Some(rx)), + } + } +} + +/// Warp sync phase. enum Phase { + /// Downloading warp proofs. WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash, warp_sync_provider: Arc>, }, - PendingTargetBlock { - target_block: Option>, - }, + /// Waiting for target block to be set externally if we skip warp proofs downloading, + /// and start straight from the target block (used by parachains warp sync). + PendingTargetBlock, + /// Downloading target block. TargetBlock(B::Header), + /// Downloading state. State(StateSync), } @@ -83,10 +122,10 @@ where /// Create a new instance. When passing a warp sync provider we will be checking for proof and /// authorities. Alternatively we can pass a target block when we want to skip downloading /// proofs, in this case we will continue polling until the target block is known. - pub fn new(client: Arc, warp_sync_params: WarpSyncParams) -> Self { + pub fn new(client: Arc, warp_sync_config: WarpSyncConfig) -> Self { let last_hash = client.hash(Zero::zero()).unwrap().expect("Genesis header always exists"); - match warp_sync_params { - WarpSyncParams::WithProvider(warp_sync_provider) => { + match warp_sync_config { + WarpSyncConfig::WithProvider(warp_sync_provider) => { let phase = Phase::WarpProof { set_id: 0, authorities: warp_sync_provider.current_authorities(), @@ -95,35 +134,23 @@ where }; Self { client, phase, total_proof_bytes: 0 } }, - WarpSyncParams::WaitForTarget(block) => Self { - client, - phase: Phase::PendingTargetBlock { target_block: Some(block) }, - total_proof_bytes: 0, - }, + WarpSyncConfig::WaitForTarget => + Self { client, phase: Phase::PendingTargetBlock, total_proof_bytes: 0 }, } } - /// Poll to make progress. - /// - /// This only makes progress when `phase = Phase::PendingTargetBlock` and the pending block was - /// sent. - pub fn poll(&mut self, cx: &mut std::task::Context) { - let new_phase = if let Phase::PendingTargetBlock { target_block: Some(target_block) } = - &mut self.phase - { - match target_block.poll_unpin(cx) { - Poll::Ready(Ok(target)) => Phase::TargetBlock(target), - Poll::Ready(Err(e)) => { - error!(target: "sync", "Failed to get target block. Error: {:?}",e); - Phase::PendingTargetBlock { target_block: None } - }, - _ => return, - } - } else { + /// Set target block externally in case we skip warp proof downloading. + pub fn set_target_block(&mut self, header: B::Header) { + let Phase::PendingTargetBlock = self.phase else { + error!( + target: LOG_TARGET, + "Attempt to set warp sync target block in invalid phase.", + ); + debug_assert!(false); return }; - self.phase = new_phase; + self.phase = Phase::TargetBlock(header); } /// Validate and import a state response. diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 2a20da5a556..d350b0e54ae 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -62,15 +62,14 @@ use sc_network::{ }; use sc_network_common::{ role::Roles, - sync::warp::{ - AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, - }, + sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, service::{chain_sync::SyncingService, network::NetworkServiceProvider}, state_request_handler::StateRequestHandler, + warp::WarpSyncParams, warp_request_handler, }; use sc_service::client::Client; diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index fe18d1d002d..917b3be8dc7 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -47,12 +47,13 @@ use sc_network::{ NetworkService, NetworkStateInfo, NetworkStatusProvider, }; use sc_network_bitswap::BitswapRequestHandler; -use sc_network_common::{role::Roles, sync::warp::WarpSyncParams}; +use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, engine::SyncingEngine, service::network::NetworkServiceProvider, state_request_handler::StateRequestHandler, - warp_request_handler::RequestHandler as WarpSyncRequestHandler, SyncingService, + warp::WarpSyncParams, warp_request_handler::RequestHandler as WarpSyncRequestHandler, + SyncingService, }; use sc_rpc::{ author::AuthorApiServer, diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 0961967f9ca..cd720e1c1e0 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -79,7 +79,7 @@ pub use sc_chain_spec::{ pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; -pub use sc_network_common::sync::warp::WarpSyncParams; +pub use sc_network_sync::warp::WarpSyncParams; #[doc(hidden)] pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::{ -- GitLab From ec8949f624305b32432e70cdcc8fd8db7535490b Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 5 Sep 2023 12:11:30 +0200 Subject: [PATCH 079/633] Remove redundant calls to `borrow()` (#1393) Co-authored-by: Keith Yeung Co-authored-by: Francisco Aguirre --- substrate/client/api/src/lib.rs | 5 +---- substrate/frame/message-queue/src/lib.rs | 4 ++-- substrate/frame/support/src/storage/generator/map.rs | 5 ++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/substrate/client/api/src/lib.rs b/substrate/client/api/src/lib.rs index faadf3663a5..f614a1e30b4 100644 --- a/substrate/client/api/src/lib.rs +++ b/substrate/client/api/src/lib.rs @@ -49,7 +49,6 @@ pub trait UsageProvider { pub mod utils { use sp_blockchain::{Error, HeaderBackend, HeaderMetadata}; use sp_runtime::traits::Block as BlockT; - use std::borrow::Borrow; /// Returns a function for checking block ancestry, the returned function will /// return `true` if the given hash (second parameter) is a descendent of the @@ -69,10 +68,8 @@ pub mod utils { return Ok(false) } - let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow())); - let mut hash = hash; - if let Some((current_hash, current_parent_hash)) = current { + if let Some((current_hash, current_parent_hash)) = ¤t { if base == current_hash { return Ok(false) } diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 9ded84bb035..7c38dec4b08 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -1092,7 +1092,7 @@ impl Pallet { origin.clone(), page_index, page.first_index, - payload.deref(), + payload, weight, overweight_limit, ) { @@ -1242,7 +1242,7 @@ impl Pallet { if let Some((_, processed, message)) = page.peek_index(i.try_into().expect("std-only code")) { - let msg = String::from_utf8_lossy(message.deref()); + let msg = String::from_utf8_lossy(message); if processed { page_info.push('*'); } diff --git a/substrate/frame/support/src/storage/generator/map.rs b/substrate/frame/support/src/storage/generator/map.rs index 90fac4b41c7..1d2511e324d 100644 --- a/substrate/frame/support/src/storage/generator/map.rs +++ b/substrate/frame/support/src/storage/generator/map.rs @@ -21,7 +21,6 @@ use crate::{ Never, }; use codec::{Decode, Encode, EncodeLike, FullCodec, FullEncode}; -use sp_std::borrow::Borrow; #[cfg(not(feature = "std"))] use sp_std::prelude::*; @@ -297,7 +296,7 @@ impl> storage::StorageMap let ret = f(&mut val); if ret.is_ok() { match G::from_query_to_optional_value(val) { - Some(ref val) => unhashed::put(final_key.as_ref(), &val.borrow()), + Some(ref val) => unhashed::put(final_key.as_ref(), &val), None => unhashed::kill(final_key.as_ref()), } } @@ -314,7 +313,7 @@ impl> storage::StorageMap let ret = f(&mut val); if ret.is_ok() { match val { - Some(ref val) => unhashed::put(final_key.as_ref(), &val.borrow()), + Some(ref val) => unhashed::put(final_key.as_ref(), &val), None => unhashed::kill(final_key.as_ref()), } } -- GitLab From 336916827f78a320fddbf1925984ec0a1f884376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 5 Sep 2023 13:24:19 +0200 Subject: [PATCH 080/633] Remove dynamic dispatch using `Ext` (#1399) --- substrate/frame/contracts/src/exec.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 894667280b7..fdb30310ef7 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -1625,13 +1625,13 @@ mod tests { } struct MockCtx<'a> { - ext: &'a mut dyn Ext, + ext: &'a mut MockStack<'a>, input_data: Vec, } #[derive(Clone)] struct MockExecutable { - func: Rc ExecResult + 'static>, + func: Rc Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>, func_type: ExportedFunction, code_hash: CodeHash, code_info: CodeInfo, @@ -1724,6 +1724,16 @@ mod tests { if let &Constructor = function { Self::increment_refcount(self.code_hash).unwrap(); } + // # Safety + // + // We know that we **always** call execute with a `MockStack` in this test. + // + // # Note + // + // The transmute is necessary because `execute` has to be generic over all + // `E: Ext`. However, `MockExecutable` can't be generic over `E` as it would + // constitute a cycle. + let ext = unsafe { std::mem::transmute(ext) }; if function == &self.func_type { (self.func)(MockCtx { ext, input_data }, &self) } else { -- GitLab From 51dcc9fbc873de6616dd67e7b919c6de249b222b Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 5 Sep 2023 18:56:32 -0300 Subject: [PATCH 081/633] Enforce a decoding limit in MultiAssets (#1395) * Enforce a decoding limit in MultiAssets * ".git/.scripts/commands/fmt/fmt.sh" * Update polkadot/xcm/src/v3/multiasset.rs Co-authored-by: Keith Yeung * Just use a BoundedVec * Conflicts --------- Co-authored-by: command-bot <> Co-authored-by: Keith Yeung --- polkadot/xcm/src/v3/multiasset.rs | 38 +++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 1668d1b870d..a5a74368289 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -40,6 +40,7 @@ use core::{ }; use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use bounded_collections::{BoundedVec, ConstU32}; /// A general identifier for an instance of a non-fungible asset class. #[derive( @@ -506,9 +507,8 @@ impl TryFrom for MultiAsset { #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct MultiAssets(Vec); -/// Maximum number of items we expect in a single `MultiAssets` value. Note this is not (yet) -/// enforced, and just serves to provide a sensible `max_encoded_len` for `MultiAssets`. -const MAX_ITEMS_IN_MULTIASSETS: usize = 20; +/// Maximum number of items in a single `MultiAssets` value that can be decoded. +pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20; impl MaxEncodedLen for MultiAssets { fn max_encoded_len() -> usize { @@ -517,8 +517,9 @@ impl MaxEncodedLen for MultiAssets { } impl Decode for MultiAssets { - fn decode(input: &mut I) -> Result { - Self::from_sorted_and_deduplicated(Vec::::decode(input)?) + fn decode(input: &mut I) -> Result { + let bounded_instructions = BoundedVec::>::decode(input)?; + Self::from_sorted_and_deduplicated(bounded_instructions.into_inner()) .map_err(|()| "Out of order".into()) } } @@ -974,4 +975,31 @@ mod tests { let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad); assert!(r.is_err()); } + + #[test] + fn decoding_respects_limit() { + use super::*; + + // Having lots of one asset will work since they are deduplicated + let lots_of_one_asset: MultiAssets = + vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_MULTIASSETS + 1].into(); + let encoded = lots_of_one_asset.encode(); + assert!(MultiAssets::decode(&mut &encoded[..]).is_ok()); + + // Fewer assets than the limit works + let mut few_assets: MultiAssets = Vec::new().into(); + for i in 0..MAX_ITEMS_IN_MULTIASSETS { + few_assets.push((GeneralIndex(i as u128), 1u128).into()); + } + let encoded = few_assets.encode(); + assert!(MultiAssets::decode(&mut &encoded[..]).is_ok()); + + // Having lots of different assets will not work + let mut too_many_different_assets: MultiAssets = Vec::new().into(); + for i in 0..MAX_ITEMS_IN_MULTIASSETS + 1 { + too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into()); + } + let encoded = too_many_different_assets.encode(); + assert!(MultiAssets::decode(&mut &encoded[..]).is_err()); + } } -- GitLab From 7986b12624f7fd6ecc55a151afca5df31608ed9f Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 6 Sep 2023 10:12:55 +0200 Subject: [PATCH 082/633] fmt fixes (#1413) --- polkadot/xcm/src/v3/multiasset.rs | 5 +++-- substrate/frame/broker/src/dispatchable_impls.rs | 8 ++------ substrate/frame/broker/src/tick_impls.rs | 8 ++------ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index a5a74368289..188555318c8 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -34,13 +34,13 @@ use crate::v2::{ WildMultiAsset as OldWildMultiAsset, }; use alloc::{vec, vec::Vec}; +use bounded_collections::{BoundedVec, ConstU32}; use core::{ cmp::Ordering, convert::{TryFrom, TryInto}, }; use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use bounded_collections::{BoundedVec, ConstU32}; /// A general identifier for an instance of a non-fungible asset class. #[derive( @@ -518,7 +518,8 @@ impl MaxEncodedLen for MultiAssets { impl Decode for MultiAssets { fn decode(input: &mut I) -> Result { - let bounded_instructions = BoundedVec::>::decode(input)?; + let bounded_instructions = + BoundedVec::>::decode(input)?; Self::from_sorted_and_deduplicated(bounded_instructions.into_inner()) .map_err(|()| "Out of order".into()) } diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index 8dc0c9de393..54cf5d71dca 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -333,12 +333,8 @@ impl Pallet { region.begin = r + 1; contribution.length.saturating_dec(); - let Some(mut pool_record) = InstaPoolHistory::::get(r) else { - continue - }; - let Some(total_payout) = pool_record.maybe_payout else { - break - }; + let Some(mut pool_record) = InstaPoolHistory::::get(r) else { continue }; + let Some(total_payout) = pool_record.maybe_payout else { break }; let p = total_payout .saturating_mul(contributed_parts.into()) .checked_div(&pool_record.private_contributions.into()) diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index 909af6caf73..a1a50a61908 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -95,9 +95,7 @@ impl Pallet { } pub(crate) fn process_revenue() -> bool { - let Some((until, amount)) = T::Coretime::check_notify_revenue_info() else { - return false - }; + let Some((until, amount)) = T::Coretime::check_notify_revenue_info() else { return false }; let when: Timeslice = (until / T::TimeslicePeriod::get()).saturating_sub(One::one()).saturated_into(); let mut revenue = T::ConvertBalance::convert_back(amount); @@ -289,9 +287,7 @@ impl Pallet { rc_begin: RelayBlockNumberOf, core: CoreIndex, ) { - let Some(workplan) = Workplan::::take((timeslice, core)) else { - return - }; + let Some(workplan) = Workplan::::take((timeslice, core)) else { return }; let workload = Workload::::get(core); let parts_used = workplan.iter().map(|i| i.mask).fold(CoreMask::void(), |a, i| a | i); let mut workplan = workplan.into_inner(); -- GitLab From eaf380aaf5d366d9ad9068126785f3a44cf88c43 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 6 Sep 2023 10:25:47 +0200 Subject: [PATCH 083/633] Add PRdoc check (#1408) * Add test prdoc * Prepare for the check * Escape PR number * Fix conditional step * Add checkout and actual check * Cleanup * Minor fixes * Add doumentation * Add more doc --- .github/workflows/check-prdoc.yml | 51 ++++++++++++++++++++++++++ cumulus/scripts/ci/changelog/README.md | 2 +- docs/CONTRIBUTING.md | 32 ++++++++++++---- prdoc/.gitkeep | 0 prdoc/pr_1408_prodc-introduction.prdoc | 19 ++++++++++ 5 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/check-prdoc.yml create mode 100644 prdoc/.gitkeep create mode 100644 prdoc/pr_1408_prodc-introduction.prdoc diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml new file mode 100644 index 00000000000..e677ded8d6c --- /dev/null +++ b/.github/workflows/check-prdoc.yml @@ -0,0 +1,51 @@ +name: Check PRdoc + +on: + pull_request: + types: [labeled, opened, synchronize, unlabeled] + +env: + # todo: switch to paritytech/prdoc once the container is built & published + # see https://github.com/paritytech/scripts/pull/595 + IMAGE: chevdor/prdoc:v0.0.4 + API_BASE: https://api.github.com/repos + REPO: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR: ${{ github.event.pull_request.number }} + MOUNT: /prdoc + ENGINE: docker + +jobs: + check-prdoc: + runs-on: ubuntu-latest + steps: + - name: Pull image + run: | + echo "Pulling $IMAGE" + docker pull $IMAGE + docker run --rm $IMAGE --version + + - name: Check if PRdoc is required + id: get-labels + run: | + # Fetch the labels for the PR under test + echo "Fetch the labels for $API_BASE/${REPO}/pulls/${GITHUB_PR}" + labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") + echo "Labels: ${labels}" + echo "labels=${labels}" >> "$GITHUB_OUTPUT" + + - name: No PRdoc required + if: ${{ contains(steps.get-labels.outputs.labels, 'R0') }} + run: | + echo "PR detected as silent, no PRdoc is required, exiting..." + exit 0 + + - name: Checkout repo + if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0 + + - name: PRdoc check for PR#${{ github.event.pull_request.number }} + if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} + run: | + echo "Checking for PR#$GITHUB_PR in $MOUNT" + $ENGINE run --rm -v $PWD/prdoc:/doc $IMAGE check -n 1408 diff --git a/cumulus/scripts/ci/changelog/README.md b/cumulus/scripts/ci/changelog/README.md index e274b491947..5c8ee9c9b91 100644 --- a/cumulus/scripts/ci/changelog/README.md +++ b/cumulus/scripts/ci/changelog/README.md @@ -61,7 +61,7 @@ all the labels that are used, search for `meta` in the templates. Currently, the 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 debuggin +## Dev and debugging ### Hot Reload diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 20fa1d3a768..d134188e25d 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -80,18 +80,36 @@ Reviews should finish with approval unless there are issues that would result in The reviewers are also responsible to check: -a) if a changelog is necessary and attached - -b) the quality of information in the changelog file - -c) the PR has an impact on docs - -d) that the docs team was included in the review process of a docs update +1. if a changelog is necessary and attached +1. the quality of information in the changelog file +1. the PR has an impact on docs +1. that the docs team was included in the review process of a docs update **Reviews may not be used as an effective veto for a PR because**: 1. There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. 2. It does not fit well with some other contributors' longer-term vision for the project. +## Documentation + +All Pull Requests must contain proper title & description. + +Some Pull Requests can be exempt of `prdoc` documentation, those +must be labelled with +[`R0-silent`](https://github.com/paritytech/labels/blob/main/ruled_labels/specs_polkadot-sdk.yaml#L89-L91). + +Non "silent" PRs must come with documentation in the form of a `.prdoc` file. +A `.prdoc` documentation is made of a text file (YAML) named `/prdoc/pr_NNNN.prdoc` where `NNNN` is the PR number. +For convenience, those file can also contain a short description/title: `/prdoc/pr_NNNN_pr-foobar.prdoc`. + +The CI automation checks for the presence and validity of a `prdoc` in the `/prdoc` folder. +Those files need to comply with a specific [schema](https://github.com/paritytech/prdoc/blob/master/schema_user.json). It +is highly recommended to [make your editor aware](https://github.com/paritytech/prdoc#schemas) of the schema as it is +self-described and will assist you in writing correct content. + +This schema is also embedded in the +[prdoc](https://github.com/paritytech/prdoc) utility that can also be used to generate and check the validity of a +`prdoc` locally. + ## Helping out We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate diff --git a/prdoc/.gitkeep b/prdoc/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/prdoc/pr_1408_prodc-introduction.prdoc b/prdoc/pr_1408_prodc-introduction.prdoc new file mode 100644 index 00000000000..4b10e0fe2e8 --- /dev/null +++ b/prdoc/pr_1408_prodc-introduction.prdoc @@ -0,0 +1,19 @@ +# This PR does not need a prdoc but it is provided in order to test +title: PRdoc check + +doc: + - audience: Core Dev + description: | + This PRdoc is an **example**. + + This PR brings support and automated checks for documentation in the form of a + [`prdoc`](https://github.com/paritytech/prdoc/) file. + +migrations: + db: [] + + runtime: [] + +crates: [] + +host_functions: [] -- GitLab From cd71f7e9b1ddfc30b674cf3316e49bff247a4b5b Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 6 Sep 2023 21:09:07 +1200 Subject: [PATCH 084/633] RFC 14: Improve locking mechanism for parachains (#1290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rfc14 * Update polkadot/runtime/common/src/paras_registrar/mod.rs Co-authored-by: Bastian Köcher * Update polkadot/runtime/common/src/paras_registrar/mod.rs Co-authored-by: Bastian Köcher * Update polkadot/runtime/common/src/paras_registrar/mod.rs Co-authored-by: Bastian Köcher * fmt * fix * Update polkadot/runtime/common/src/paras_registrar/migration.rs Co-authored-by: Oliver Tale-Yazdi * fmt * 2224 is unlocked * update migration list * update comment * use VersionedMigration --------- Co-authored-by: Bastian Köcher Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + .../runtime/common/src/assigned_slots/mod.rs | 1 + polkadot/runtime/common/src/crowdloan/mod.rs | 2 - .../runtime/common/src/integration_tests.rs | 1 + .../common/src/paras_registrar/migration.rs | 71 +++++++++++++++++++ .../mod.rs} | 61 ++++++++++++---- polkadot/runtime/kusama/Cargo.toml | 2 +- polkadot/runtime/kusama/src/lib.rs | 16 +++++ polkadot/runtime/parachains/Cargo.toml | 1 + polkadot/runtime/parachains/src/mock.rs | 1 + polkadot/runtime/parachains/src/paras/mod.rs | 27 ++++++- polkadot/runtime/polkadot/Cargo.toml | 2 +- polkadot/runtime/polkadot/src/lib.rs | 20 +++++- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 + polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/runtime/westend/src/lib.rs | 2 + 18 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 polkadot/runtime/common/src/paras_registrar/migration.rs rename polkadot/runtime/common/src/{paras_registrar.rs => paras_registrar/mod.rs} (97%) diff --git a/Cargo.lock b/Cargo.lock index c254302517f..918426ce5c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12780,6 +12780,7 @@ dependencies = [ "frame-system", "futures", "hex-literal 0.4.1", + "impl-trait-for-tuples", "log", "pallet-authority-discovery", "pallet-authorship", diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index 3683cfc210f..cc8ec339c11 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -739,6 +739,7 @@ mod tests { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = (); type NextSessionRotation = crate::mock::TestNextSessionRotation; + type OnNewHead = (); } impl parachains_shared::Config for Test {} diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 0303808e074..5a293914592 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -441,8 +441,6 @@ pub mod pallet { ); NextFundIndex::::put(new_fund_index); - // Add a lock to the para so that the configuration cannot be changed. - T::Registrar::apply_lock(index); Self::deposit_event(Event::::Created { para_id: index }); Ok(()) diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index f78347dedd8..f14db68267d 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -204,6 +204,7 @@ impl paras::Config for Test { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = (); type NextSessionRotation = crate::mock::TestNextSessionRotation; + type OnNewHead = (); } parameter_types! { diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs new file mode 100644 index 00000000000..7d3dda54e0e --- /dev/null +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -0,0 +1,71 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::traits::{Contains, OnRuntimeUpgrade}; + +#[derive(Encode, Decode)] +pub struct ParaInfoV1 { + manager: Account, + deposit: Balance, + locked: bool, +} + +pub struct VersionUncheckedMigrateToV1( + sp_std::marker::PhantomData<(T, UnlockParaIds)>, +); +impl> OnRuntimeUpgrade + for VersionUncheckedMigrateToV1 +{ + fn on_runtime_upgrade() -> Weight { + let mut count = 0u64; + Paras::::translate::>, _>(|key, v1| { + count.saturating_inc(); + Some(ParaInfo { + manager: v1.manager, + deposit: v1.deposit, + locked: if UnlockParaIds::contains(&key) { None } else { Some(v1.locked) }, + }) + }); + + log::info!(target: "runtime::registrar", "Upgraded {} storages to version 1", count); + T::DbWeight::get().reads_writes(count, count) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + Ok((Paras::::iter_keys().count() as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let old_count = u32::decode(&mut &state[..]).expect("Known good"); + let new_count = Paras::::iter_values().count() as u32; + + ensure!(old_count == new_count, "Paras count should not change"); + Ok(()) + } +} + +#[cfg(feature = "experimental")] +pub type VersionCheckedMigrateToV1 = + frame_support::migrations::VersionedMigration< + 0, + 1, + VersionUncheckedMigrateToV1, + super::Pallet, + ::DbWeight, + >; diff --git a/polkadot/runtime/common/src/paras_registrar.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs similarity index 97% rename from polkadot/runtime/common/src/paras_registrar.rs rename to polkadot/runtime/common/src/paras_registrar/mod.rs index 3f5a8e1a5f9..f2751803a41 100644 --- a/polkadot/runtime/common/src/paras_registrar.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -17,6 +17,8 @@ //! Pallet to handle parachain registration and related fund management. //! In essence this is a simple wrapper around `paras`. +pub mod migration; + use frame_support::{ dispatch::DispatchResult, ensure, @@ -35,7 +37,7 @@ use sp_std::{prelude::*, result}; use crate::traits::{OnSwap, Registrar}; pub use pallet::*; use parity_scale_codec::{Decode, Encode}; -use runtime_parachains::paras::ParaKind; +use runtime_parachains::paras::{OnNewHead, ParaKind}; use scale_info::TypeInfo; use sp_runtime::{ traits::{CheckedSub, Saturating}, @@ -49,7 +51,15 @@ pub struct ParaInfo { /// The amount reserved by the `manager` account for the registration. deposit: Balance, /// Whether the para registration should be locked from being controlled by the manager. - locked: bool, + /// None means the lock had not been explicitly set, and should be treated as false. + locked: Option, +} + +impl ParaInfo { + /// Returns if the para is locked. + pub fn is_locked(&self) -> bool { + self.locked.unwrap_or(false) + } } type BalanceOf = @@ -96,8 +106,12 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -446,12 +460,12 @@ impl Registrar for Pallet { // Apply a lock to the parachain. fn apply_lock(id: ParaId) { - Paras::::mutate(id, |x| x.as_mut().map(|info| info.locked = true)); + Paras::::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(true))); } // Remove a lock from the parachain. fn remove_lock(id: ParaId) { - Paras::::mutate(id, |x| x.as_mut().map(|info| info.locked = false)); + Paras::::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(false))); } // Register a Para ID under control of `manager`. @@ -481,9 +495,7 @@ impl Registrar for Pallet { ); runtime_parachains::schedule_parathread_upgrade::(id) .map_err(|_| Error::::CannotUpgrade)?; - // Once a para has upgraded to a parachain, it can no longer be managed by the owner. - // Intentionally, the flag stays with the para even after downgrade. - Self::apply_lock(id); + Ok(()) } @@ -533,7 +545,7 @@ impl Pallet { .map_err(|e| e.into()) .and_then(|who| -> DispatchResult { let para_info = Paras::::get(id).ok_or(Error::::NotRegistered)?; - ensure!(!para_info.locked, Error::::ParaLocked); + ensure!(!para_info.is_locked(), Error::::ParaLocked); ensure!(para_info.manager == who, Error::::NotOwner); Ok(()) }) @@ -566,7 +578,7 @@ impl Pallet { let deposit = deposit_override.unwrap_or_else(T::ParaDeposit::get); ::Currency::reserve(&who, deposit)?; - let info = ParaInfo { manager: who.clone(), deposit, locked: false }; + let info = ParaInfo { manager: who.clone(), deposit, locked: None }; Paras::::insert(id, info); Self::deposit_event(Event::::Reserved { para_id: id, who }); @@ -585,7 +597,7 @@ impl Pallet { ) -> DispatchResult { let deposited = if let Some(para_data) = Paras::::get(id) { ensure!(para_data.manager == who, Error::::NotOwner); - ensure!(!para_data.locked, Error::::ParaLocked); + ensure!(!para_data.is_locked(), Error::::ParaLocked); para_data.deposit } else { ensure!(!ensure_reserved, Error::::NotReserved); @@ -601,7 +613,7 @@ impl Pallet { } else if let Some(rebate) = deposited.checked_sub(&deposit) { ::Currency::unreserve(&who, rebate); }; - let info = ParaInfo { manager: who.clone(), deposit, locked: false }; + let info = ParaInfo { manager: who.clone(), deposit, locked: None }; Paras::::insert(id, info); // We check above that para has no lifecycle, so this should not fail. @@ -665,6 +677,21 @@ impl Pallet { } } +impl OnNewHead for Pallet { + fn on_new_head(id: ParaId, _head: &HeadData) -> Weight { + // mark the parachain locked if the locked value is not already set + let mut writes = 0; + if let Some(mut info) = Paras::::get(id) { + if info.locked.is_none() { + info.locked = Some(true); + Paras::::insert(id, info); + writes += 1; + } + } + T::DbWeight::get().reads_writes(1, writes) + } +} + #[cfg(test)] mod tests { use super::*; @@ -784,6 +811,7 @@ mod tests { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = (); type NextSessionRotation = crate::mock::TestNextSessionRotation; + type OnNewHead = (); } impl configuration::Config for Test { @@ -1270,8 +1298,10 @@ mod tests { )); assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin); - // Once they begin onboarding, we lock them in. - assert_ok!(Registrar::add_lock(RuntimeOrigin::signed(1), para_id)); + + // Once they produces new block, we lock them in. + Registrar::on_new_head(para_id, &Default::default()); + // Owner cannot pass origin check when checking lock assert_noop!( Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id), @@ -1283,6 +1313,11 @@ mod tests { assert_ok!(Registrar::remove_lock(para_origin(para_id), para_id)); // Owner can pass origin check again assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); + + // Won't lock again after it is unlocked + Registrar::on_new_head(para_id, &Default::default()); + + assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); }); } diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 8b0f59516c6..6b0370633f0 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -103,7 +103,7 @@ frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarki 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-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features = ["experimental"] } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 94af807fb5d..659a7052d2b 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -1215,6 +1215,7 @@ impl parachains_paras::Config for Runtime { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; + type OnNewHead = Registrar; } parameter_types! { @@ -1710,6 +1711,19 @@ pub mod migrations { } } + 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, @@ -1741,6 +1755,8 @@ pub mod migrations { UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, + // Migrate parachain info format + paras_registrar::migration::VersionCheckedMigrateToV1, ); } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 9a8bd5017e0..0e2f6aa1aa2 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] +impl-trait-for-tuples = "0.2.2" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index f978b6c3360..ded7de08e4f 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -214,6 +214,7 @@ impl crate::paras::Config for Test { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = TestNextSessionRotation; + type OnNewHead = (); } impl crate::dmp::Config for Test {} diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 95b89a1ca2c..2f370b5bfe4 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -481,6 +481,22 @@ impl PvfCheckActiveVoteState { } } +/// Runtime hook for when a parachain head is updated. +pub trait OnNewHead { + /// Called when a parachain head is updated. + /// Returns the weight consumed by this function. + fn on_new_head(id: ParaId, head: &HeadData) -> Weight; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl OnNewHead for Tuple { + fn on_new_head(id: ParaId, head: &HeadData) -> Weight { + let mut weight: Weight = Default::default(); + for_tuples!( #( weight.saturating_accrue(Tuple::on_new_head(id, head)); )* ); + weight + } +} + pub trait WeightInfo { fn force_set_current_code(c: u32) -> Weight; fn force_set_current_head(s: u32) -> Weight; @@ -575,6 +591,9 @@ pub mod pallet { /// be set to the `ParaInclusion` pallet. type QueueFootprinter: QueueFootprinter; + /// Runtime hook for when a parachain head is updated. + type OnNewHead: OnNewHead; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -1962,10 +1981,10 @@ impl Pallet { new_head: HeadData, execution_context: BlockNumberFor, ) -> Weight { - Heads::::insert(&id, new_head); + Heads::::insert(&id, &new_head); MostRecentContext::::insert(&id, execution_context); - if let Some(expected_at) = FutureCodeUpgrades::::get(&id) { + let weight = if let Some(expected_at) = FutureCodeUpgrades::::get(&id) { if expected_at <= execution_context { FutureCodeUpgrades::::remove(&id); UpgradeGoAheadSignal::::remove(&id); @@ -2005,7 +2024,9 @@ impl Pallet { // the `Abort` signal. UpgradeGoAheadSignal::::remove(&id); T::DbWeight::get().reads_writes(1, 2) - } + }; + + weight.saturating_add(T::OnNewHead::on_new_head(id, &new_head)) } /// Returns the list of PVFs (aka validation code) that require casting a vote by a validator in diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index d185677ab8d..0b9498347ca 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -94,7 +94,7 @@ pallet-session-benchmarking = { path = "../../../substrate/frame/session/benchma 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-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features = ["experimental"] } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index b71e0f726c5..45ea561b33f 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -47,8 +47,8 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, PrivilegeCmp, - ProcessMessage, ProcessMessageError, WithdrawReasons, + ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, + PrivilegeCmp, ProcessMessage, ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -1091,6 +1091,7 @@ impl parachains_paras::Config for Runtime { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; + type OnNewHead = Registrar; } parameter_types! { @@ -1503,6 +1504,19 @@ pub mod migrations { 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, @@ -1525,6 +1539,8 @@ pub mod migrations { frame_support::migrations::RemovePallet::DbWeight>, parachains_configuration::migration::v9::MigrateToV9, + // Migrate parachain info format + paras_registrar::migration::VersionCheckedMigrateToV1, ); } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6af9407a587..a181250cfa3 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -84,7 +84,7 @@ frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-fea frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } hex-literal = { version = "0.4.1" } -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features=["experimental"] } +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features = ["experimental"] } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index a80f45c340d..e043852901f 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1031,6 +1031,7 @@ impl parachains_paras::Config for Runtime { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; + type OnNewHead = Registrar; } parameter_types! { @@ -1550,6 +1551,7 @@ pub mod migrations { parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, parachains_configuration::migration::v9::MigrateToV9, + paras_registrar::migration::VersionCheckedMigrateToV1, ); } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index b2397299430..94852ad39f5 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -540,6 +540,7 @@ impl parachains_paras::Config for Runtime { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; + type OnNewHead = (); } impl parachains_dmp::Config for Runtime {} diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 5a47288297b..de561c8ac68 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -95,7 +95,7 @@ pallet-offences-benchmarking = { path = "../../../substrate/frame/offences/bench pallet-session-benchmarking = { path = "../../../substrate/frame/session/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, features=["experimental"] } +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features = ["experimental"] } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 73aa4980151..7dfc781d246 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1044,6 +1044,7 @@ impl parachains_paras::Config for Runtime { type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; + type OnNewHead = (); } parameter_types! { @@ -1425,6 +1426,7 @@ pub mod migrations { parachains_configuration::migration::v8::MigrateToV8, UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, + paras_registrar::migration::VersionCheckedMigrateToV1, ); } -- GitLab From cd901764a52edc04a6d22bea3a526def593ab2a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 12:30:54 +0300 Subject: [PATCH 085/633] Bump enumn from 0.1.11 to 0.1.12 (#1412) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [enumn](https://github.com/dtolnay/enumn) from 0.1.11 to 0.1.12. - [Release notes](https://github.com/dtolnay/enumn/releases) - [Commits](https://github.com/dtolnay/enumn/compare/0.1.11...0.1.12) --- updated-dependencies: - dependency-name: enumn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 4 ++-- polkadot/runtime/common/slot_range_helper/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 918426ce5c0..0d08c175bde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4733,9 +4733,9 @@ dependencies = [ [[package]] name = "enumn" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5" +checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index 30d5dc84e9d..f65717519d5 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true [dependencies] paste = "1.0" -enumn = "0.1.8" +enumn = "0.1.12" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { package = "sp-std", path = "../../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -- GitLab From dc28df0b278f2ca0f69d14363e08668a9ecc2fac Mon Sep 17 00:00:00 2001 From: Cem Eliguzel Date: Wed, 6 Sep 2023 13:02:33 +0300 Subject: [PATCH 086/633] Fix the wasm runtime substitute caching bug (#1416) --- substrate/client/service/src/client/wasm_substitutes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/service/src/client/wasm_substitutes.rs b/substrate/client/service/src/client/wasm_substitutes.rs index a792ab87e77..70db0ef20f5 100644 --- a/substrate/client/service/src/client/wasm_substitutes.rs +++ b/substrate/client/service/src/client/wasm_substitutes.rs @@ -126,7 +126,7 @@ where let runtime_code = RuntimeCode { code_fetcher: &WrappedRuntimeCode((&code).into()), heap_pages: None, - hash: Vec::new(), + hash: make_hash(&code), }; let version = Self::runtime_version(&executor, &runtime_code)?; let spec_version = version.spec_version; -- GitLab From 50de035f6d33b7233fd263892dd263d52b997f5c Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 6 Sep 2023 13:58:53 +0200 Subject: [PATCH 087/633] Fix PRdoc check (#1419) --- .github/workflows/check-prdoc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index e677ded8d6c..219952fdbfb 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -47,5 +47,5 @@ jobs: - name: PRdoc check for PR#${{ github.event.pull_request.number }} if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} run: | - echo "Checking for PR#$GITHUB_PR in $MOUNT" - $ENGINE run --rm -v $PWD/prdoc:/doc $IMAGE check -n 1408 + echo "Checking for PR#${GITHUB_PR} in $MOUNT" + $ENGINE run --rm -v $PWD/prdoc:/doc $IMAGE check -n ${GITHUB_PR} -- GitLab From 68ab943c65a7d214d62c3b7e0fd94561dd9e64b2 Mon Sep 17 00:00:00 2001 From: Juan Date: Wed, 6 Sep 2023 15:06:47 +0200 Subject: [PATCH 088/633] Remove deprecated `pallet_balances`'s `set_balance_deprecated` and `transfer` dispatchables (#1226) * remove deprecated dispatchables * update test * update tests * update tests * add prdocs * add prdoc * Update docs/prdoc/pr_1226.prdoc Co-authored-by: Chevdor * move prdoc file --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung Co-authored-by: Chevdor --- prdoc/pr_1226.prdoc | 17 +++++ substrate/frame/asset-conversion/src/tests.rs | 6 +- substrate/frame/balances/src/lib.rs | 63 ------------------- substrate/frame/safe-mode/src/mock.rs | 5 +- substrate/frame/safe-mode/src/tests.rs | 2 +- substrate/frame/tx-pause/src/mock.rs | 5 +- substrate/frame/tx-pause/src/tests.rs | 18 +++--- 7 files changed, 40 insertions(+), 76 deletions(-) create mode 100644 prdoc/pr_1226.prdoc diff --git a/prdoc/pr_1226.prdoc b/prdoc/pr_1226.prdoc new file mode 100644 index 00000000000..df7a425b538 --- /dev/null +++ b/prdoc/pr_1226.prdoc @@ -0,0 +1,17 @@ +title: Removed deprecated `Balances::transfer` and `Balances::set_balance_deprecated` functions. + +doc: + - audience: Builder + description: The Balances pallet's dispatchables `set_balance_deprecated` and `transfer` were deprecated in [paritytech/substrate#12951](https://github.com/paritytech/substrate/pull/12951) and have now been removed. + notes: + - Use `set_balance_deprecated` instead `force_set_balance` and `transfer_allow_death` instead of `transfer`. + +migrations: + db: [] + + runtime: [] + +crates: + - name: pallet-balances + +host_functions: [] diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 190e4fb6214..3af7500a6f3 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -1389,7 +1389,11 @@ fn cannot_block_pool_creation() { let pool_account = AssetConversion::get_pool_account(&AssetConversion::get_pool_id(token_2, token_1)); // And transfers the ED to that pool account - assert_ok!(Balances::transfer(RuntimeOrigin::signed(attacker), pool_account, ed)); + assert_ok!(Balances::transfer_allow_death( + RuntimeOrigin::signed(attacker), + pool_account, + ed + )); // Then, the attacker creates 14 tokens and sends one of each to the pool account for i in 10..25 { create_tokens(attacker, vec![NativeOrAssetId::Asset(i)]); diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index f94b3230b91..5da6600d879 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -563,53 +563,6 @@ pub mod pallet { Ok(()) } - /// Set the regular balance of a given account; it also takes a reserved balance but this - /// must be the same as the account's current reserved balance. - /// - /// The dispatch origin for this call is `root`. - /// - /// WARNING: This call is DEPRECATED! Use `force_set_balance` instead. - #[pallet::call_index(1)] - #[pallet::weight( - T::WeightInfo::force_set_balance_creating() // Creates a new account. - .max(T::WeightInfo::force_set_balance_killing()) // Kills an existing account. - )] - pub fn set_balance_deprecated( - origin: OriginFor, - who: AccountIdLookupOf, - #[pallet::compact] new_free: T::Balance, - #[pallet::compact] old_reserved: T::Balance, - ) -> DispatchResult { - ensure_root(origin)?; - let who = T::Lookup::lookup(who)?; - let existential_deposit = Self::ed(); - - let wipeout = new_free < existential_deposit; - let new_free = if wipeout { Zero::zero() } else { new_free }; - - // First we try to modify the account's balance to the forced balance. - let old_free = Self::try_mutate_account_handling_dust( - &who, - |account, _is_new| -> Result { - let old_free = account.free; - ensure!(account.reserved == old_reserved, TokenError::Unsupported); - account.free = new_free; - Ok(old_free) - }, - )?; - - // This will adjust the total issuance, which was not done by the `mutate_account` - // above. - if new_free > old_free { - mem::drop(PositiveImbalance::::new(new_free - old_free)); - } else if new_free < old_free { - mem::drop(NegativeImbalance::::new(old_free - new_free)); - } - - Self::deposit_event(Event::BalanceSet { who, free: new_free }); - Ok(()) - } - /// Exactly as `transfer_allow_death`, except the origin must be root and the source account /// may be specified. #[pallet::call_index(2)] @@ -730,22 +683,6 @@ pub mod pallet { } } - /// Alias for `transfer_allow_death`, provided only for name-wise compatibility. - /// - /// WARNING: DEPRECATED! Will be released in approximately 3 months. - #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::transfer_allow_death())] - pub fn transfer( - origin: OriginFor, - dest: AccountIdLookupOf, - #[pallet::compact] value: T::Balance, - ) -> DispatchResult { - let source = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; - >::transfer(&source, &dest, value, Expendable)?; - Ok(()) - } - /// Set the regular balance of a given account. /// /// The dispatch origin for this call is `root`. diff --git a/substrate/frame/safe-mode/src/mock.rs b/substrate/frame/safe-mode/src/mock.rs index 337b6076f84..635ee0cfedc 100644 --- a/substrate/frame/safe-mode/src/mock.rs +++ b/substrate/frame/safe-mode/src/mock.rs @@ -122,7 +122,10 @@ impl InstanceFilter for ProxyType { match self { ProxyType::Any => true, ProxyType::JustTransfer => { - matches!(c, RuntimeCall::Balances(pallet_balances::Call::transfer { .. })) + matches!( + c, + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) + ) }, ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), } diff --git a/substrate/frame/safe-mode/src/tests.rs b/substrate/frame/safe-mode/src/tests.rs index 1e2eb343aa2..ca1d7eb1d93 100644 --- a/substrate/frame/safe-mode/src/tests.rs +++ b/substrate/frame/safe-mode/src/tests.rs @@ -605,7 +605,7 @@ fn fails_when_explicit_origin_required() { } fn call_transfer() -> RuntimeCall { - RuntimeCall::Balances(pallet_balances::Call::transfer { dest: 1, value: 1 }) + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: 1, value: 1 }) } fn signed(who: u64) -> RuntimeOrigin { diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 706b0a558ba..60c5fc1eced 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -120,7 +120,10 @@ impl InstanceFilter for ProxyType { match self { ProxyType::Any => true, ProxyType::JustTransfer => { - matches!(c, RuntimeCall::Balances(pallet_balances::Call::transfer { .. })) + matches!( + c, + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) + ) }, ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), } diff --git a/substrate/frame/tx-pause/src/tests.rs b/substrate/frame/tx-pause/src/tests.rs index 48b70f71ccb..a71ff3439d9 100644 --- a/substrate/frame/tx-pause/src/tests.rs +++ b/substrate/frame/tx-pause/src/tests.rs @@ -32,7 +32,7 @@ fn can_pause_specific_call() { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer") + full_name::(b"Balances", b"transfer_allow_death") )); assert_err!( @@ -69,7 +69,7 @@ fn can_unpause_specific_call() { new_test_ext().execute_with(|| { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_err!( call_transfer(2, 1).dispatch(RuntimeOrigin::signed(2)), @@ -78,7 +78,7 @@ fn can_unpause_specific_call() { assert_ok!(TxPause::unpause( RuntimeOrigin::signed(mock::UnpauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_ok!(call_transfer(4, 1).dispatch(RuntimeOrigin::signed(0))); }); @@ -92,7 +92,7 @@ fn can_filter_balance_in_batch_when_paused() { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_ok!(batch_call.clone().dispatch(RuntimeOrigin::signed(0))); @@ -111,7 +111,7 @@ fn can_filter_balance_in_proxy_when_paused() { new_test_ext().execute_with(|| { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); @@ -152,7 +152,7 @@ fn fails_to_pause_unpausable_call_when_other_call_is_paused() { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_ok!(call_transfer_keep_alive(3, 1).dispatch(RuntimeOrigin::signed(3))); @@ -181,13 +181,13 @@ fn fails_to_pause_already_paused_pallet() { new_test_ext().execute_with(|| { assert_ok!(TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), )); assert_noop!( TxPause::pause( RuntimeOrigin::signed(mock::PauseOrigin::get()), - full_name::(b"Balances", b"transfer"), + full_name::(b"Balances", b"transfer_allow_death"), ), Error::::IsPaused ); @@ -208,7 +208,7 @@ fn fails_to_unpause_not_paused_pallet() { } pub fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(pallet_balances::Call::transfer { dest, value }) + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest, value }) } pub fn call_transfer_keep_alive(dest: u64, value: u64) -> RuntimeCall { -- GitLab From 4c077b209b17fbc0d8fa1468feb2015f7505f060 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 6 Sep 2023 15:00:53 +0100 Subject: [PATCH 089/633] pallet asset-conversion additional quote tests (#1371) * added identity quote test (only possible if fees are not included in quote) * add tests that compare quoted price to actual execution --- substrate/frame/asset-conversion/src/tests.rs | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 3af7500a6f3..1c1267ab87b 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -569,6 +569,16 @@ fn can_quote_price() { ), Some(60) ); + // including fee so should get less out... + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 3000, + true, + ), + Some(46) + ); // Check it still gives same price: // (if the above accidentally exchanged then it would not give same quote as before) assert_eq!( @@ -580,6 +590,16 @@ fn can_quote_price() { ), Some(60) ); + // including fee so should get less out... + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 3000, + true, + ), + Some(46) + ); // Check inverse: assert_eq!( @@ -591,6 +611,247 @@ fn can_quote_price() { ), Some(3000) ); + // including fee so should get less out... + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + 60, + true, + ), + Some(2302) + ); + + // + // same tests as above but for quote_price_tokens_for_exact_tokens: + // + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 60, + false, + ), + Some(3000) + ); + // including fee so should need to put more in... + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 60, + true, + ), + Some(4299) + ); + // Check it still gives same price: + // (if the above accidentally exchanged then it would not give same quote as before) + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 60, + false, + ), + Some(3000) + ); + // including fee so should need to put more in... + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + 60, + true, + ), + Some(4299) + ); + + // Check inverse: + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + 3000, + false, + ), + Some(60) + ); + // including fee so should need to put more in... + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + 3000, + true, + ), + Some(86) + ); + + // + // roundtrip: Without fees one should get the original number + // + let amount_in = 100; + + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + amount_in, + false, + ) + .and_then(|amount| AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + amount, + false, + )), + Some(amount_in) + ); + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + amount_in, + false, + ) + .and_then(|amount| AssetConversion::quote_price_exact_tokens_for_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + amount, + false, + )), + Some(amount_in) + ); + + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + amount_in, + false, + ) + .and_then(|amount| AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + amount, + false, + )), + Some(amount_in) + ); + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Native, + NativeOrAssetId::Asset(2), + amount_in, + false, + ) + .and_then(|amount| AssetConversion::quote_price_tokens_for_exact_tokens( + NativeOrAssetId::Asset(2), + NativeOrAssetId::Native, + amount, + false, + )), + Some(amount_in) + ); + }); +} + +#[test] +fn quote_price_exact_tokens_for_tokens_matches_execution() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + 10000, + 200, + 1, + 1, + user, + )); + + let amount = 1; + let quoted_price = 49; + assert_eq!( + AssetConversion::quote_price_exact_tokens_for_tokens(token_2, token_1, amount, true,), + Some(quoted_price) + ); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, amount)); + let prior_dot_balance = 20000; + assert_eq!(prior_dot_balance, balance(user2, token_1)); + assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user2), + bvec![token_2, token_1], + amount, + 1, + user2, + false, + )); + + assert_eq!(prior_dot_balance + quoted_price, balance(user2, token_1)); + }); +} + +#[test] +fn quote_price_tokens_for_exact_tokens_matches_execution() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + 10000, + 200, + 1, + 1, + user, + )); + + let amount = 49; + let quoted_price = 1; + assert_eq!( + AssetConversion::quote_price_tokens_for_exact_tokens(token_2, token_1, amount, true,), + Some(quoted_price) + ); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, amount)); + let prior_dot_balance = 20000; + assert_eq!(prior_dot_balance, balance(user2, token_1)); + let prior_asset_balance = 49; + assert_eq!(prior_asset_balance, balance(user2, token_2)); + assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( + RuntimeOrigin::signed(user2), + bvec![token_2, token_1], + amount, + 1, + user2, + false, + )); + + assert_eq!(prior_dot_balance + amount, balance(user2, token_1)); + assert_eq!(prior_asset_balance - quoted_price, balance(user2, token_2)); }); } -- GitLab From eeb368ed9ca3bc2af0ccf9dfddb985ddef8f4233 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Wed, 6 Sep 2023 16:11:10 +0200 Subject: [PATCH 090/633] GHW for building and publishing docker images (#1391) * add ghw and scripts for docker image deployment * debug * add permissions for content * fix path to the bin folder * add tags * rename env * fix path to docker file * make polkadot-parachain executable * fix typo * fix more typos * test * revert back use of working directory * mke bin executable in the artifacts folder * use cd instead of working directory * change path to cash * fix path to cash * change cache key * delete old flows * addressed PR comments * fix path * reorg docker files --- {.gitlab => .github/scripts}/common/lib.sh | 73 ++++++++- .../workflows/release-50_publish-docker.yml | 148 +++++++++--------- .gitlab/pipeline/build.yml | 2 +- .gitlab/pipeline/publish.yml | 18 +-- .gitlab/test_deterministic_wasm.sh | 2 +- cumulus/docker/parachain-registrar.dockerfile | 27 ---- ...rachain-debug_unsigned_injected.Dockerfile | 49 ------ .../polkadot-parachain_builder.Containerfile | 36 ----- .../docker/test-parachain-collator.dockerfile | 46 ------ .../docker/test-parachain_injected.Dockerfile | 49 ------ docker/docker-compose.yml | 129 --------------- docker/dockerfiles/binary_injected.Dockerfile | 48 ++++++ .../collator_injected.Dockerfile | 2 +- .../dockerfiles}/docker-compose.yml | 8 +- .../malus_injected.Dockerfile | 0 .../parachain-registrar.dockerfile | 2 +- ...rachain-debug_unsigned_injected.Dockerfile | 2 +- .../polkadot-parachain_builder.Containerfile | 4 +- .../polkadot-parachain_injected.Dockerfile | 10 +- docker/dockerfiles/polkadot/README.md | 9 ++ .../polkadot/docker-compose-local.yml | 50 ++++++ .../dockerfiles/polkadot/docker-compose.yml | 22 +++ .../polkadot/polkadot_Dockerfile.README.md | 7 + .../polkadot/polkadot_builder.Dockerfile | 36 +++++ .../polkadot_injected_debian.Dockerfile | 53 +++++++ .../polkadot_injected_debug.Dockerfile | 2 +- .../polkadot_injected_release.Dockerfile | 2 +- .../staking-miner_builder.Dockerfile | 0 .../staking-miner_injected.Dockerfile | 0 .../substrate_injected.Dockerfile | 0 .../test-parachain-collator.dockerfile | 2 +- .../test-parachain_injected.Dockerfile | 2 +- docker/injected.Dockerfile | 51 ------ .../scripts/adder-collator/build-injected.sh | 13 ++ docker/scripts/adder-collator/test-build.sh | 23 +++ docker/scripts/build-injected.sh | 100 ++++++++++++ docker/scripts/entrypoint.sh | 18 +++ docker/scripts/malus/build-injected.sh | 14 ++ docker/scripts/malus/test-build.sh | 19 +++ .../polkadot-parachain/build-injected.sh | 15 ++ .../scripts/polkadot-parachain/test-build.sh | 19 +++ ...polkadot-parachain_build-injected-image.sh | 2 +- docker/scripts/polkadot/build-injected.sh | 13 ++ docker/scripts/polkadot/test-build.sh | 18 +++ docker/scripts/staking-miner/README.md | 37 +++++ .../scripts/staking-miner/build-injected.sh | 13 ++ docker/scripts/staking-miner/build.sh | 13 ++ .../staking-miner_Dockerfile.README.md | 3 + .../staking-miner_builder.Dockerfile | 43 +++++ docker/scripts/staking-miner/test-build.sh | 18 +++ {cumulus/docs => docs}/container.md | 2 +- {polkadot/doc => docs}/docker.md | 2 +- .../workflows/release-40_publish-rc-image.yml | 132 ---------------- .../release-51_publish-docker-manual.yml | 51 ------ polkadot/utils/staking-miner/README.md | 2 +- 55 files changed, 784 insertions(+), 677 deletions(-) rename {.gitlab => .github/scripts}/common/lib.sh (76%) rename {cumulus/.github => .github}/workflows/release-50_publish-docker.yml (59%) delete mode 100644 cumulus/docker/parachain-registrar.dockerfile delete mode 100644 cumulus/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile delete mode 100644 cumulus/docker/polkadot-parachain_builder.Containerfile delete mode 100644 cumulus/docker/test-parachain-collator.dockerfile delete mode 100644 cumulus/docker/test-parachain_injected.Dockerfile delete mode 100644 docker/docker-compose.yml create mode 100644 docker/dockerfiles/binary_injected.Dockerfile rename docker/{ => dockerfiles}/collator_injected.Dockerfile (95%) rename {cumulus/docker => docker/dockerfiles}/docker-compose.yml (89%) rename docker/{ => dockerfiles}/malus_injected.Dockerfile (100%) rename docker/{ => dockerfiles}/parachain-registrar.dockerfile (89%) rename docker/{ => dockerfiles/polkadot-parachain}/polkadot-parachain-debug_unsigned_injected.Dockerfile (93%) rename docker/{ => dockerfiles/polkadot-parachain}/polkadot-parachain_builder.Containerfile (89%) rename cumulus/docker/injected.Dockerfile => docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile (68%) create mode 100644 docker/dockerfiles/polkadot/README.md create mode 100644 docker/dockerfiles/polkadot/docker-compose-local.yml create mode 100644 docker/dockerfiles/polkadot/docker-compose.yml create mode 100644 docker/dockerfiles/polkadot/polkadot_Dockerfile.README.md create mode 100644 docker/dockerfiles/polkadot/polkadot_builder.Dockerfile create mode 100644 docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile rename docker/{ => dockerfiles/polkadot}/polkadot_injected_debug.Dockerfile (94%) rename docker/{ => dockerfiles/polkadot}/polkadot_injected_release.Dockerfile (95%) rename docker/{ => dockerfiles}/staking-miner/staking-miner_builder.Dockerfile (100%) rename docker/{ => dockerfiles}/staking-miner/staking-miner_injected.Dockerfile (100%) rename docker/{ => dockerfiles}/substrate_injected.Dockerfile (100%) rename docker/{ => dockerfiles}/test-parachain-collator.dockerfile (96%) rename docker/{ => dockerfiles}/test-parachain_injected.Dockerfile (95%) delete mode 100644 docker/injected.Dockerfile create mode 100755 docker/scripts/adder-collator/build-injected.sh create mode 100755 docker/scripts/adder-collator/test-build.sh create mode 100755 docker/scripts/build-injected.sh create mode 100755 docker/scripts/entrypoint.sh create mode 100755 docker/scripts/malus/build-injected.sh create mode 100755 docker/scripts/malus/test-build.sh create mode 100755 docker/scripts/polkadot-parachain/build-injected.sh create mode 100755 docker/scripts/polkadot-parachain/test-build.sh rename cumulus/docker/scripts/build-injected-image.sh => docker/scripts/polkadot-parachain_build-injected-image.sh (70%) create mode 100755 docker/scripts/polkadot/build-injected.sh create mode 100755 docker/scripts/polkadot/test-build.sh create mode 100644 docker/scripts/staking-miner/README.md create mode 100755 docker/scripts/staking-miner/build-injected.sh create mode 100755 docker/scripts/staking-miner/build.sh create mode 100644 docker/scripts/staking-miner/staking-miner_Dockerfile.README.md create mode 100644 docker/scripts/staking-miner/staking-miner_builder.Dockerfile create mode 100755 docker/scripts/staking-miner/test-build.sh rename {cumulus/docs => docs}/container.md (96%) rename {polkadot/doc => docs}/docker.md (98%) delete mode 100644 polkadot/.github/workflows/release-40_publish-rc-image.yml delete mode 100644 polkadot/.github/workflows/release-51_publish-docker-manual.yml diff --git a/.gitlab/common/lib.sh b/.github/scripts/common/lib.sh similarity index 76% rename from .gitlab/common/lib.sh rename to .github/scripts/common/lib.sh index ba5b1714872..b0f9cb32063 100755 --- a/.gitlab/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -96,7 +96,7 @@ structure_message() { # access_token: see https://matrix.org/docs/guides/client-server-api/ # Usage: send_message $body (json formatted) $room_id $access_token send_message() { -curl -XPOST -d "$1" "https://matrix.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" + curl -XPOST -d "$1" "https://m.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" } # Pretty-printing functions @@ -193,3 +193,74 @@ check_bootnode(){ echo " Bootnode appears unreachable" return 1 } + +# Assumes the ENV are set: +# - RELEASE_ID +# - GITHUB_TOKEN +# - REPO in the form paritytech/polkadot +fetch_release_artifacts() { + echo "Release ID : $RELEASE_ID" + echo "Repo : $REPO" + echo "Binary : $BINARY" + + curl -L -s \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${REPO}/releases/${RELEASE_ID} > release.json + + # Get Asset ids + ids=($(jq -r '.assets[].id' < release.json )) + count=$(jq '.assets|length' < release.json ) + + # Fetch artifacts + mkdir -p "./release-artifacts/${BINARY}" + pushd "./release-artifacts/${BINARY}" > /dev/null + + iter=1 + for id in "${ids[@]}" + do + echo " - $iter/$count: downloading asset id: $id..." + curl -s -OJ -L -H "Accept: application/octet-stream" \ + -H "Authorization: Token ${GITHUB_TOKEN}" \ + "https://api.github.com/repos/${REPO}/releases/assets/$id" + iter=$((iter + 1)) + done + + pwd + ls -al --color + popd > /dev/null +} + +# Check the checksum for a given binary +function check_sha256() { + echo "Checking SHA256 for $1" + shasum -qc $1.sha256 +} + +# Import GPG keys of the release team members +# This is done in parallel as it can take a while sometimes +function import_gpg_keys() { + GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} + SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" + WILL="2835EAF92072BC01D188AF2C4A092B93E97CE1E2" + EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" + MARA="533C920F40E73A21EEB7E9EBF27AEA7E7594C9CF" + MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" + + echo "Importing GPG keys from $GPG_KEYSERVER in parallel" + for key in $SEC $WILL $EGOR $MARA $MORGAN; do + ( + echo "Importing GPG key $key" + gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key + echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key $key trust; + ) & + done + wait +} + +# Check the GPG signature for a given binary +function check_gpg() { + echo "Checking GPG Signature for $1" + gpg --no-tty --verify -q $1.asc $1 +} diff --git a/cumulus/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml similarity index 59% rename from cumulus/.github/workflows/release-50_publish-docker.yml rename to .github/workflows/release-50_publish-docker.yml index 6ad943c3903..0e466f26891 100644 --- a/cumulus/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -7,9 +7,10 @@ name: Release - Publish Docker Image # image and publishes it. on: - release: - types: - - published + #TODO: activate automated run later + # release: + # types: + # - published workflow_dispatch: inputs: release_id: @@ -39,6 +40,18 @@ on: required: true type: string default: parity + binary: + description: Binary to be published + required: true + default: polkadot + type: choice + options: + - polkadot + - staking-miner + - polkadot-parachain + +permissions: + contents: write env: RELEASE_ID: ${{ inputs.release_id }} @@ -47,8 +60,8 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCKER_OWNER: ${{ inputs.owner || github.repository_owner }} REPO: ${{ github.repository }} - BINARY: polkadot-parachain - EVENT_ACTION: ${{ github.event.action }} + BINARY: ${{ inputs.binary }} + # EVENT_ACTION: ${{ github.event.action }} EVENT_NAME: ${{ github.event_name }} IMAGE_TYPE: ${{ inputs.image_type }} @@ -58,59 +71,36 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - - name: Prepare temp folder - run: | - TMP=$(mktemp -d) - echo "TMP=$TMP" >> "$GITHUB_ENV" - pwd - ls -al "$TMP" + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - - name: Fetch lib.sh from polkadot repo - working-directory: ${{ env.TMP }} - run: | - curl -O -L \ - -H "Accept: application/vnd.github.v3.raw" \ - https://raw.githubusercontent.com/paritytech/polkadot/master/scripts/ci/common/lib.sh - - chmod a+x lib.sh - ls -al - - - name: Fetch release artifacts based on final release tag + #TODO: this step will be needed when automated triggering will work #this step runs only if the workflow is triggered automatically when new release is published - if: ${{ env.EVENT_NAME == 'release' && env.EVENT_ACTION != '' && env.EVENT_ACTION == 'published' }} - run: | - mkdir -p release-artifacts && cd release-artifacts - - for f in $BINARY $BINARY.asc $BINARY.sha256; do - URL="https://github.com/${{ github.event.repository.full_name }}/releases/download/${{ github.event.release.tag_name }}/$f" - echo " - Fetching $f from $URL" - wget "$URL" -O "$f" - done - chmod a+x $BINARY - cp -f ${TMP}/lib.sh . - ls -al + # if: ${{ env.EVENT_NAME == 'release' && env.EVENT_ACTION != '' && env.EVENT_ACTION == 'published' }} + # run: | + # mkdir -p release-artifacts && cd release-artifacts + + # for f in $BINARY $BINARY.asc $BINARY.sha256; do + # URL="https://github.com/${{ github.event.repository.full_name }}/releases/download/${{ github.event.release.tag_name }}/$f" + # echo " - Fetching $f from $URL" + # wget "$URL" -O "$f" + # done + # chmod a+x $BINARY + # ls -al - name: Fetch rc artifacts or release artifacts based on release id #this step runs only if the workflow is triggered manually if: ${{ env.EVENT_NAME == 'workflow_dispatch' }} run: | - . ${TMP}/lib.sh + . ./.github/scripts/common/lib.sh fetch_release_artifacts - chmod a+x release-artifacts/$BINARY - ls -al - - cp -f ${TMP}/lib.sh release-artifacts/ - - name: Cache the artifacts uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: - key: artifacts-${{ github.sha }} + key: artifacts-${{ env.BINARY }}-${{ github.sha }} path: | - ./release-artifacts/**/* + ./release-artifacts/${{ env.BINARY }}/**/* build-container: runs-on: ubuntu-latest @@ -118,40 +108,31 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Get artifacts from cache uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: - key: artifacts-${{ github.sha }} + key: artifacts-${{ env.BINARY }}-${{ github.sha }} fail-on-cache-miss: true path: | - ./release-artifacts/**/* + ./release-artifacts/${{ env.BINARY }}/**/* - name: Check sha256 ${{ env.BINARY }} - working-directory: ./release-artifacts + working-directory: ./release-artifacts/${{ env.BINARY }} run: | - . ./lib.sh + . ../../.github/scripts/common/lib.sh echo "Checking binary $BINARY" check_sha256 $BINARY && echo "OK" || echo "ERR" - name: Check GPG ${{ env.BINARY }} - working-directory: ./release-artifacts + working-directory: ./release-artifacts/${{ env.BINARY }} run: | - . ./lib.sh + . ../../.github/scripts/common/lib.sh import_gpg_keys check_gpg $BINARY - - name: Build Injected Container image for ${{ env.BINARY }} - env: - IMAGE_NAME: ${{ env.BINARY }} - OWNER: ${{ env.DOCKER_OWNER }} - run: | - ls -al - echo "Building container for $BINARY" - ./docker/scripts/build-injected-image.sh - - name: Fetch rc commit and tag if: ${{ env.IMAGE_TYPE == 'rc' }} id: fetch_rc_refs @@ -167,14 +148,43 @@ jobs: echo "No tag, doing without" - name: Fetch release tags - if: ${{ env.IMAGE_TYPE == 'release' || env.EVENT_NAME == 'release' && env.EVENT_ACTION != '' && env.EVENT_ACTION == 'published' }} + working-directory: ./release-artifacts/${{ env.BINARY }} + if: ${{ env.IMAGE_TYPE == 'release'}} id: fetch_release_refs run: | - VERSION=$(docker run --pull never --rm $DOCKER_OWNER/$BINARY --version | awk '{ print $2 }' ) + chmod a+rx $BINARY + VERSION=$(./$BINARY --version | awk '{ print $2 }' ) release=$( echo $VERSION | cut -f1 -d- ) echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT + - name: Build Injected Container image for polkadot/staking-miner + if: ${{ env.BINARY == 'polkadot' || env.BINARY == 'staking-miner' }} + env: + ARTIFACTS_FOLDER: ./release-artifacts + IMAGE_NAME: ${{ env.BINARY }} + OWNER: ${{ env.DOCKER_OWNER }} + TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} + run: | + ls -al + echo "Building container for $BINARY" + ./docker/scripts/build-injected.sh + + - name: Build Injected Container image for polkadot-parachain + if: ${{ env.BINARY == 'polkadot-parachain' }} + env: + ARTIFACTS_FOLDER: ./release-artifacts + IMAGE_NAME: ${{ env.BINARY }} + OWNER: ${{ env.DOCKER_OWNER }} + DOCKERFILE: docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile + TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} + run: | + ls -al + mkdir -p $ARTIFACTS_FOLDER/specs + cp cumulus/parachains/chain-specs/*.json $ARTIFACTS_FOLDER/specs + + echo "Building container for $BINARY" + ./docker/scripts/build-injected.sh - name: Login to Dockerhub uses: docker/login-action@v2 @@ -182,21 +192,11 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Tag and Push Container image for ${{ env.BINARY }} + - name: Push Container image for ${{ env.BINARY }} id: docker_push - env: - TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} run: | - TAGS=${TAGS[@]:-latest} - IFS=',' read -r -a TAG_ARRAY <<< "$TAGS" - - echo "The image ${BINARY} will be tagged with ${TAG_ARRAY[*]}" - for TAG in "${TAG_ARRAY[@]}"; do - $ENGINE tag ${DOCKER_OWNER}/${BINARY} ${DOCKER_OWNER}/${BINARY}:${TAG} - $ENGINE push ${DOCKER_OWNER}/${BINARY}:${TAG} - done - $ENGINE images | grep ${BINARY} + $ENGINE push --all-tags ${REGISTRY}/${DOCKER_OWNER}/${BINARY} - name: Check version for the published image for ${{ env.BINARY }} env: diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 20fed5df3df..2d74187cadf 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -328,7 +328,7 @@ build-linux-substrate: cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; fi - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 - - cp -r ./docker/substrate_injected.Dockerfile ./artifacts/substrate/ + - cp -r ./docker/dockerfiles/substrate_injected.Dockerfile ./artifacts/substrate/ # - printf '\n# building node-template\n\n' # - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index ed18082344f..341d3ac2a86 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -35,7 +35,7 @@ build-push-image-polkadot-parachain-debug: - job: build-linux-stable-cumulus artifacts: true variables: - DOCKERFILE: "docker/polkadot-parachain-debug_unsigned_injected.Dockerfile" + DOCKERFILE: "docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/polkadot-parachain-debug" build-push-image-test-parachain: @@ -48,7 +48,7 @@ build-push-image-test-parachain: - job: build-test-parachain artifacts: true variables: - DOCKERFILE: "docker/test-parachain_injected.Dockerfile" + DOCKERFILE: "docker/dockerfiles/test-parachain_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/test-parachain" # publish-s3: # stage: publish @@ -114,7 +114,7 @@ build-push-image-polkadot-debug: - job: build-linux-stable artifacts: true variables: - DOCKERFILE: "docker/polkadot_injected_debug.Dockerfile" + DOCKERFILE: "docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile" IMAGE_NAME: "docker.io/paritypr/polkadot-debug" build-push-image-colander: @@ -127,7 +127,7 @@ build-push-image-colander: - job: build-test-collators artifacts: true variables: - DOCKERFILE: "docker/collator_injected.Dockerfile" + DOCKERFILE: "docker/dockerfiles/collator_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/colander" build-push-image-malus: @@ -140,7 +140,7 @@ build-push-image-malus: - job: build-malus artifacts: true variables: - DOCKERFILE: "docker/malus_injected.Dockerfile" + DOCKERFILE: "docker/dockerfiles/malus_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/malus" build-push-image-substrate-pr: @@ -153,7 +153,7 @@ build-push-image-substrate-pr: - job: build-linux-substrate artifacts: true variables: - DOCKERFILE: "docker/substrate_injected.Dockerfile" + DOCKERFILE: "docker/dockerfiles/substrate_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/substrate" # old way @@ -201,7 +201,7 @@ build-push-image-substrate-pr: # GIT_STRATEGY: none # DOCKER_USER: ${PARITYPR_USER} # DOCKER_PASS: ${PARITYPR_PASS} -# # scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile +# # docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile # DOCKERFILE: polkadot_injected_debug.Dockerfile # IMAGE_NAME: docker.io/paritypr/polkadot-debug # needs: @@ -230,7 +230,7 @@ build-push-image-substrate-pr: # GIT_STRATEGY: none # DOCKER_USER: ${PARITYPR_USER} # DOCKER_PASS: ${PARITYPR_PASS} -# # scripts/ci/dockerfiles/collator_injected.Dockerfile +# # docker/dockerfiles/collator_injected.Dockerfile # DOCKERFILE: collator_injected.Dockerfile # IMAGE_NAME: docker.io/paritypr/colander # needs: @@ -258,7 +258,7 @@ build-push-image-substrate-pr: # GIT_STRATEGY: none # DOCKER_USER: ${PARITYPR_USER} # DOCKER_PASS: ${PARITYPR_PASS} -# # scripts/ci/dockerfiles/malus_injected.Dockerfile +# # docker/dockerfiles/malus_injected.Dockerfile # DOCKERFILE: malus_injected.Dockerfile # IMAGE_NAME: docker.io/paritypr/malus # needs: diff --git a/.gitlab/test_deterministic_wasm.sh b/.gitlab/test_deterministic_wasm.sh index 4f1d2981ff2..fac28fce1f6 100755 --- a/.gitlab/test_deterministic_wasm.sh +++ b/.gitlab/test_deterministic_wasm.sh @@ -2,7 +2,7 @@ set -e #shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/common/lib.sh" +source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../.github/scripts/common/lib.sh" # build runtime WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-runtime diff --git a/cumulus/docker/parachain-registrar.dockerfile b/cumulus/docker/parachain-registrar.dockerfile deleted file mode 100644 index f7d77454a2b..00000000000 --- a/cumulus/docker/parachain-registrar.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM node:latest AS pjs - -# It would be great to depend on a more stable tag, but we need some -# as-yet-unreleased features. -RUN yarn global add @polkadot/api-cli@0.10.0-beta.14 - -ENTRYPOINT [ "polkadot-js-api" ] -CMD [ "--version" ] - -# To use the pjs build stage to access the blockchain from the host machine: -# -# docker build -f docker/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: -# -# pjs query.sudo.key - -FROM pjs -RUN apt-get update && apt-get install curl netcat -y && \ - curl -sSo /wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \ - chmod +x /wait-for-it.sh -# the only thing left to do is to actually run the transaction. -COPY ./docker/scripts/register_para.sh /usr/bin -# unset the previous stage's entrypoint -ENTRYPOINT [] -CMD [ "/usr/bin/register_para.sh" ] diff --git a/cumulus/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile b/cumulus/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile deleted file mode 100644 index a2e32049f5b..00000000000 --- a/cumulus/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -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}/scripts/docker/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/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates \ - curl && \ - # apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ - # add user and link ~/.local/share/polkadot-parachain to /data - useradd -m -u 10000 -U -s /bin/sh -d /polkadot-parachain polkadot-parachain && \ - mkdir -p /data /polkadot-parachain/.local/share && \ - chown -R polkadot-parachain:polkadot-parachain /data && \ - ln -s /data /polkadot-parachain/.local/share/polkadot-parachain && \ - mkdir -p /specs - -# add polkadot-parachain binary to the docker image -COPY ./artifacts/polkadot-parachain /usr/local/bin -COPY ./parachains/chain-specs/*.json /specs/ - -USER polkadot-parachain - -# check if executable works in this container -RUN /usr/local/bin/polkadot-parachain --version - -EXPOSE 30333 9933 9944 -VOLUME ["/polkadot-parachain"] - -ENTRYPOINT ["/usr/local/bin/polkadot-parachain"] diff --git a/cumulus/docker/polkadot-parachain_builder.Containerfile b/cumulus/docker/polkadot-parachain_builder.Containerfile deleted file mode 100644 index 159bcb32369..00000000000 --- a/cumulus/docker/polkadot-parachain_builder.Containerfile +++ /dev/null @@ -1,36 +0,0 @@ -# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/ci/dockerfiles/polkadot/polkadot_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 - -WORKDIR /cumulus -COPY . /cumulus - -RUN cargo build --release --locked -p polkadot-parachain - -# This is the 2nd stage: a very small image where we copy the Polkadot binary." -FROM docker.io/library/ubuntu:20.04 - -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}/scripts/ci/dockerfiles/polkadot/polkadot-parachain_builder.Dockerfile" \ - io.parity.image.documentation="https://github.com/paritytech/cumulus" - -COPY --from=builder /cumulus/target/release/polkadot-parachain /usr/local/bin - -RUN useradd -m -u 1000 -U -s /bin/sh -d /cumulus polkadot-parachain && \ - mkdir -p /data /cumulus/.local/share && \ - chown -R polkadot-parachain:polkadot-parachain /data && \ - ln -s /data /cumulus/.local/share/polkadot-parachain && \ -# unclutter and minimize the attack surface - rm -rf /usr/bin /usr/sbin && \ -# check if executable works in this container - /usr/local/bin/polkadot-parachain --version - -USER polkadot-parachain - -EXPOSE 30333 9933 9944 9615 -VOLUME ["/data"] - -ENTRYPOINT ["/usr/local/bin/polkadot-parachain"] diff --git a/cumulus/docker/test-parachain-collator.dockerfile b/cumulus/docker/test-parachain-collator.dockerfile deleted file mode 100644 index 9c2d8fbe581..00000000000 --- a/cumulus/docker/test-parachain-collator.dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile -FROM docker.io/paritytech/ci-linux:production as builder - -WORKDIR /cumulus -COPY . /cumulus - -RUN cargo build --release --locked -p polkadot-parachain - -# the collator stage is normally built once, cached, and then ignored, but can -# be specified with the --target build flag. This adds some extra tooling to the -# image, which is required for a launcher script. The script simply adds two -# arguments to the list passed in: -# -# --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/PEER_ID -# -# with the appropriate ip and ID for both Alice and Bob -FROM debian:buster-slim as collator -RUN apt-get update && apt-get install jq curl bash -y && \ - curl -sSo /wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \ - chmod +x /wait-for-it.sh && \ - curl -sL https://deb.nodesource.com/setup_12.x | bash - && \ - apt-get install -y nodejs && \ - npm install --global yarn && \ - yarn global add @polkadot/api-cli@0.10.0-beta.14 -COPY --from=builder \ - /paritytech/cumulus/target/release/polkadot-parachain /usr/bin -COPY ./docker/scripts/inject_bootnodes.sh /usr/bin -CMD ["/usr/bin/inject_bootnodes.sh"] -COPY ./docker/scripts/healthcheck.sh /usr/bin/ -HEALTHCHECK --interval=300s --timeout=75s --start-period=30s --retries=3 \ - CMD ["/usr/bin/healthcheck.sh"] - -# the runtime stage is normally built once, cached, and ignored, but can be -# specified with the --target build flag. This just preserves one of the builder's -# outputs, which can then be moved into a volume at runtime -FROM debian:buster-slim as runtime -COPY --from=builder \ - /paritytech/cumulus/target/release/wbuild/cumulus-test-parachain-runtime/cumulus_test_parachain_runtime.compact.wasm \ - /var/opt/ -CMD ["cp", "-v", "/var/opt/cumulus_test_parachain_runtime.compact.wasm", "/runtime/"] - -FROM debian:buster-slim -COPY --from=builder \ - /paritytech/cumulus/target/release/polkadot-parachain /usr/bin - -CMD ["/usr/bin/polkadot-parachain"] diff --git a/cumulus/docker/test-parachain_injected.Dockerfile b/cumulus/docker/test-parachain_injected.Dockerfile deleted file mode 100644 index 6056c504604..00000000000 --- a/cumulus/docker/test-parachain_injected.Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -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/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/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates \ - curl && \ - # apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ - # add user and link ~/.local/share/test-parachain to /data - useradd -m -u 10000 -U -s /bin/sh -d /test-parachain test-parachain && \ - mkdir -p /data /test-parachain/.local/share && \ - chown -R test-parachain:test-parachain /data && \ - ln -s /data /test-parachain/.local/share/test-parachain && \ - mkdir -p /specs - -# add test-parachain binary to the docker image -COPY ./artifacts/test-parachain /usr/local/bin -COPY ./parachains/chain-specs/*.json /specs/ - -USER test-parachain - -# check if executable works in this container -RUN /usr/local/bin/test-parachain --version - -EXPOSE 30333 9933 9944 -VOLUME ["/test-parachain"] - -ENTRYPOINT ["/usr/local/bin/test-parachain"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index 8344ad43bb4..00000000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,129 +0,0 @@ -version: '3.7' -services: - node_alice: - image: "polkadot:${BRANCH:-cumulus-branch}" - ports: - - "30333:30333" - - "9933:9933" - - "9944:9944" - volumes: - - "polkadot-data-alice:/data" - - type: bind - source: ./test/parachain/chain-specs/polkadot_chainspec.json - target: /chainspec.json - read_only: true - command: > - polkadot - --chain=/chainspec.json - --base-path=/data - --port 30333 - --rpc-port 9933 - --ws-port 9944 - --rpc-external - --rpc-cors all - --ws-external - --alice - networks: - testing_net: - ipv4_address: 172.28.1.1 - aliases: - - alice - - node_bob: - image: "polkadot:${BRANCH:-cumulus-branch}" - ports: - - "30344:30333" - - "9935:9933" - - "9945:9944" - volumes: - - "polkadot-data-bob:/data" - - type: bind - source: ./test/parachain/chain-specs/polkadot_chainspec.json - target: /chainspec.json - read_only: true - command: > - polkadot - --chain=/chainspec.json - --base-path=/data - --port 30333 - --rpc-port 9933 - --ws-port 9944 - --rpc-external - --ws-external - --rpc-cors all - --bob - networks: - testing_net: - ipv4_address: 172.28.1.2 - aliases: - - bob - - genesis_state: - build: - context: . - dockerfile: ./docker/test-parachain-collator.dockerfile - image: "ctpc:latest" - volumes: - - "genesis-state:/data" - command: > - polkadot-parachain - export-genesis-state - /data/genesis-state - - collator: - build: - context: . - dockerfile: ./docker/test-parachain-collator.dockerfile - target: collator - image: "ctpc:collator" - volumes: - - "collator-data:/data" - depends_on: - - node_alice - - node_bob - command: > - inject_bootnodes.sh - --base-path=/data - networks: - testing_net: - - runtime: - build: - context: . - dockerfile: ./docker/test-parachain-collator.dockerfile - target: runtime - image: "ctpc:runtime" - volumes: - - "parachain-runtime:/runtime" - - - registrar: - build: - context: . - dockerfile: ./docker/parachain-registrar.dockerfile - image: para-reg:latest - volumes: - - "genesis-state:/genesis" - - "parachain-runtime:/runtime" - depends_on: - - node_alice - - runtime - - genesis_state - networks: - testing_net: - - -volumes: - polkadot-data-alice: - polkadot-data-bob: - collator-data: - genesis-state: - parachain-runtime: - - -networks: - testing_net: - ipam: - driver: default - config: - - subnet: 172.28.0.0/16 diff --git a/docker/dockerfiles/binary_injected.Dockerfile b/docker/dockerfiles/binary_injected.Dockerfile new file mode 100644 index 00000000000..ac1fd5317c6 --- /dev/null +++ b/docker/dockerfiles/binary_injected.Dockerfile @@ -0,0 +1,48 @@ +FROM docker.io/parity/base-bin + +# This file allows building a Generic container image +# based on one or multiple pre-built Linux binaries. +# Some defaults are set to polkadot but all can be overriden. + +SHELL ["/bin/bash", "-c"] + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG IMAGE_NAME + +# That can be a single one or a comma separated list +ARG BINARY=polkadot + +ARG BIN_FOLDER=. +ARG DOC_URL=https://github.com/paritytech/polkadot-sdk +ARG DESCRIPTION="Polkadot: a platform for web3" +ARG AUTHORS="devops-team@parity.io" +ARG VENDOR="Parity Technologies" + +LABEL io.parity.image.authors=${AUTHORS} \ + io.parity.image.vendor="${VENDOR}" \ + io.parity.image.revision="${VCS_REF}" \ + io.parity.image.title="${IMAGE_NAME}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="${DOC_URL}" \ + io.parity.image.description="${DESCRIPTION}" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/binary_injected.Dockerfile" + +USER root +WORKDIR /app + +# add polkadot binary to docker image +# sample for polkadot: COPY ./polkadot ./polkadot-*-worker /usr/local/bin/ +COPY entrypoint.sh . +COPY "bin/*" "/usr/local/bin/" +RUN chmod -R a+rx "/usr/local/bin" + +USER parity +ENV BINARY=${BINARY} + +# ENTRYPOINT +ENTRYPOINT ["/app/entrypoint.sh"] + +# We call the help by default +CMD ["--help"] diff --git a/docker/collator_injected.Dockerfile b/docker/dockerfiles/collator_injected.Dockerfile similarity index 95% rename from docker/collator_injected.Dockerfile rename to docker/dockerfiles/collator_injected.Dockerfile index 6472c240f33..0c9ea1e0ca8 100644 --- a/docker/collator_injected.Dockerfile +++ b/docker/dockerfiles/collator_injected.Dockerfile @@ -10,7 +10,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="Injected adder-collator Docker image" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/collator_injected.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot/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/" diff --git a/cumulus/docker/docker-compose.yml b/docker/dockerfiles/docker-compose.yml similarity index 89% rename from cumulus/docker/docker-compose.yml rename to docker/dockerfiles/docker-compose.yml index 8344ad43bb4..8dc8540353f 100644 --- a/cumulus/docker/docker-compose.yml +++ b/docker/dockerfiles/docker-compose.yml @@ -61,7 +61,7 @@ services: genesis_state: build: context: . - dockerfile: ./docker/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/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/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/parachain-registrar.dockerfile + dockerfile: ./docker/dockerfiles/parachain-registrar.dockerfile image: para-reg:latest volumes: - "genesis-state:/genesis" diff --git a/docker/malus_injected.Dockerfile b/docker/dockerfiles/malus_injected.Dockerfile similarity index 100% rename from docker/malus_injected.Dockerfile rename to docker/dockerfiles/malus_injected.Dockerfile diff --git a/docker/parachain-registrar.dockerfile b/docker/dockerfiles/parachain-registrar.dockerfile similarity index 89% rename from docker/parachain-registrar.dockerfile rename to docker/dockerfiles/parachain-registrar.dockerfile index f7d77454a2b..00908395101 100644 --- a/docker/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/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/polkadot-parachain-debug_unsigned_injected.Dockerfile b/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile similarity index 93% rename from docker/polkadot-parachain-debug_unsigned_injected.Dockerfile rename to docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile index e77563b8ebf..7a2202d9c52 100644 --- a/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_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="Cumulus, the Polkadot collator." \ - io.parity.image.source="https://github.com/paritytech/cumulus/blob/${VCS_REF}/scripts/docker/polkadot-parachain-debug_unsigned_injected.Dockerfile" \ + 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.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://github.com/paritytech/cumulus/" diff --git a/docker/polkadot-parachain_builder.Containerfile b/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile similarity index 89% rename from docker/polkadot-parachain_builder.Containerfile rename to docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile index 159bcb32369..4d110d6af47 100644 --- a/docker/polkadot-parachain_builder.Containerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile @@ -1,4 +1,4 @@ -# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile +# This file is sourced from https://github.com/paritytech/polkadot/blob/master/docker/dockerfiles/polkadot/polkadot_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,7 +14,7 @@ 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}/scripts/ci/dockerfiles/polkadot/polkadot-parachain_builder.Dockerfile" \ + 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" COPY --from=builder /cumulus/target/release/polkadot-parachain /usr/local/bin diff --git a/cumulus/docker/injected.Dockerfile b/docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile similarity index 68% rename from cumulus/docker/injected.Dockerfile rename to docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile index f9b11f022e7..16bd0f4cf3c 100644 --- a/cumulus/docker/injected.Dockerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-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="Cumulus, the Polkadot collator." \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/docker/Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot-parachain/polkadot-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/" # show backtraces ENV RUST_BACKTRACE 1 @@ -22,8 +22,10 @@ USER root RUN mkdir -p /specs # add polkadot-parachain binary to the docker image -COPY ./release-artifacts/* /usr/local/bin -COPY ./parachains/chain-specs/*.json /specs/ +COPY bin/* /usr/local/bin/ +COPY specs/* /specs/ + +RUN chmod -R a+rx "/usr/local/bin" USER parity diff --git a/docker/dockerfiles/polkadot/README.md b/docker/dockerfiles/polkadot/README.md new file mode 100644 index 00000000000..e331d8984c2 --- /dev/null +++ b/docker/dockerfiles/polkadot/README.md @@ -0,0 +1,9 @@ +# Self built Docker image + +The Polkadot repo contains several options to build Docker images for Polkadot. + +This folder contains a self-contained image that does not require a Linux pre-built binary. + +Instead, building the image is possible on any host having docker installed and will +build Polkadot inside Docker. That also means that no Rust toolchain is required on the host +machine for the build to succeed. diff --git a/docker/dockerfiles/polkadot/docker-compose-local.yml b/docker/dockerfiles/polkadot/docker-compose-local.yml new file mode 100644 index 00000000000..1ff3a1ccaac --- /dev/null +++ b/docker/dockerfiles/polkadot/docker-compose-local.yml @@ -0,0 +1,50 @@ +version: '3' +services: + node_alice: + ports: + - "30333:30333" + - "9933:9933" + - "9944:9944" + - "9615:9615" + image: parity/polkadot:latest + volumes: + - "polkadot-data-alice:/data" + command: | + --chain=polkadot-local + --alice + -d /data + --node-key 0000000000000000000000000000000000000000000000000000000000000001 + networks: + testing_net: + ipv4_address: 172.28.1.1 + + node_bob: + ports: + - "30344:30333" + - "9935:9933" + - "9945:9944" + - "29615:9615" + image: parity/polkadot:latest + volumes: + - "polkadot-data-bob:/data" + links: + - "node_alice:alice" + command: | + --chain=polkadot-local + --bob + -d /data + --bootnodes '/ip4/172.28.1.1/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR' + networks: + testing_net: + ipv4_address: 172.28.1.2 + +volumes: + polkadot-data-alice: + polkadot-data-bob: + +networks: + testing_net: + ipam: + driver: default + config: + - subnet: 172.28.0.0/16 diff --git a/docker/dockerfiles/polkadot/docker-compose.yml b/docker/dockerfiles/polkadot/docker-compose.yml new file mode 100644 index 00000000000..524b1164796 --- /dev/null +++ b/docker/dockerfiles/polkadot/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' +services: + polkadot: + image: parity/polkadot:latest + + ports: + - "127.0.0.1:30333:30333/tcp" + - "127.0.0.1:9933:9933/tcp" + - "127.0.0.1:9944:9944/tcp" + - "127.0.0.1:9615:9615/tcp" + + volumes: + - "polkadot-data:/data" + + command: | + --unsafe-rpc-external + --unsafe-ws-external + --rpc-cors all + --prometheus-external + +volumes: + polkadot-data: diff --git a/docker/dockerfiles/polkadot/polkadot_Dockerfile.README.md b/docker/dockerfiles/polkadot/polkadot_Dockerfile.README.md new file mode 100644 index 00000000000..7e89cb55f3d --- /dev/null +++ b/docker/dockerfiles/polkadot/polkadot_Dockerfile.README.md @@ -0,0 +1,7 @@ +# Polkadot official Docker image + +## [Polkadot](https://polkadot.network/) + +## [GitHub](https://github.com/paritytech/polkadot) + +## [Polkadot Wiki](https://wiki.polkadot.network/) diff --git a/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile b/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile new file mode 100644 index 00000000000..f8dc374a14a --- /dev/null +++ b/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile @@ -0,0 +1,36 @@ +# This is the build stage for Polkadot. Here we create the binary in a temporary image. +FROM docker.io/paritytech/ci-linux:production as builder + +WORKDIR /polkadot +COPY . /polkadot + +RUN cargo build --locked --release + +# This is the 2nd stage: a very small image where we copy the Polkadot binary." +FROM docker.io/parity/base-bin:latest + +LABEL description="Multistage Docker image for Polkadot: a platform for web3" \ + io.parity.image.type="builder" \ + 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/" + +COPY --from=builder /polkadot/target/release/polkadot /usr/local/bin + +RUN useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ + mkdir -p /data /polkadot/.local/share && \ + chown -R polkadot:polkadot /data && \ + ln -s /data /polkadot/.local/share/polkadot && \ +# unclutter and minimize the attack surface + rm -rf /usr/bin /usr/sbin && \ +# check if executable works in this container + /usr/local/bin/polkadot --version + +USER polkadot + +EXPOSE 30333 9933 9944 9615 +VOLUME ["/data"] + +ENTRYPOINT ["/usr/local/bin/polkadot"] diff --git a/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile new file mode 100644 index 00000000000..e2c72dcfe2e --- /dev/null +++ b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile @@ -0,0 +1,53 @@ +FROM docker.io/library/ubuntu:20.04 + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG POLKADOT_VERSION +ARG POLKADOT_GPGKEY=9D4B2B6EB8F97156D19669A9FF0812D491B96798 +ARG GPG_KEYSERVER="keyserver.ubuntu.com" + +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.revision="${VCS_REF}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot/" + +# show backtraces +ENV RUST_BACKTRACE 1 + +# install tools and dependencies +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + libssl1.1 \ + ca-certificates \ + gnupg && \ + useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ +# add repo's gpg keys and install the published polkadot binary + gpg --keyserver ${GPG_KEYSERVER} --recv-keys ${POLKADOT_GPGKEY} && \ + gpg --export ${POLKADOT_GPGKEY} > /usr/share/keyrings/parity.gpg && \ + echo 'deb [signed-by=/usr/share/keyrings/parity.gpg] https://releases.parity.io/deb release main' > /etc/apt/sources.list.d/parity.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends polkadot=${POLKADOT_VERSION#?} && \ +# apt cleanup + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* ; \ + mkdir -p /data /polkadot/.local/share && \ + chown -R polkadot:polkadot /data && \ + ln -s /data /polkadot/.local/share/polkadot + +USER polkadot + +# check if executable works in this container +RUN /usr/bin/polkadot --version +RUN /usr/bin/polkadot-execute-worker --version +RUN /usr/bin/polkadot-prepare-worker --version + +EXPOSE 30333 9933 9944 +VOLUME ["/polkadot"] + +ENTRYPOINT ["/usr/bin/polkadot"] diff --git a/docker/polkadot_injected_debug.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile similarity index 94% rename from docker/polkadot_injected_debug.Dockerfile rename to docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile index f7f764d335a..80ce8258987 100644 --- a/docker/polkadot_injected_debug.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_debug.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="Polkadot: a platform for web3" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot/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/" diff --git a/docker/polkadot_injected_release.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile similarity index 95% rename from docker/polkadot_injected_release.Dockerfile rename to docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile index 87ae7ac27dc..c13f2db982a 100644 --- a/docker/polkadot_injected_release.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile @@ -11,7 +11,7 @@ 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_injected_release.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot/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/" diff --git a/docker/staking-miner/staking-miner_builder.Dockerfile b/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile similarity index 100% rename from docker/staking-miner/staking-miner_builder.Dockerfile rename to docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile diff --git a/docker/staking-miner/staking-miner_injected.Dockerfile b/docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile similarity index 100% rename from docker/staking-miner/staking-miner_injected.Dockerfile rename to docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile diff --git a/docker/substrate_injected.Dockerfile b/docker/dockerfiles/substrate_injected.Dockerfile similarity index 100% rename from docker/substrate_injected.Dockerfile rename to docker/dockerfiles/substrate_injected.Dockerfile diff --git a/docker/test-parachain-collator.dockerfile b/docker/dockerfiles/test-parachain-collator.dockerfile similarity index 96% rename from docker/test-parachain-collator.dockerfile rename to docker/dockerfiles/test-parachain-collator.dockerfile index 9c2d8fbe581..0d56949152e 100644 --- a/docker/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/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile +# This file is sourced from https://github.com/paritytech/polkadot/blob/master/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile FROM docker.io/paritytech/ci-linux:production as builder WORKDIR /cumulus diff --git a/docker/test-parachain_injected.Dockerfile b/docker/dockerfiles/test-parachain_injected.Dockerfile similarity index 95% rename from docker/test-parachain_injected.Dockerfile rename to docker/dockerfiles/test-parachain_injected.Dockerfile index 0b345e16e4a..e5d0df7aad6 100644 --- a/docker/test-parachain_injected.Dockerfile +++ b/docker/dockerfiles/test-parachain_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="Test parachain for Zombienet" \ - io.parity.image.source="https://github.com/paritytech/cumulus/blob/${VCS_REF}/docker/test-parachain_injected.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/cumulus/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/" diff --git a/docker/injected.Dockerfile b/docker/injected.Dockerfile deleted file mode 100644 index 93d0561ca87..00000000000 --- a/docker/injected.Dockerfile +++ /dev/null @@ -1,51 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -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/polkadot/blob/${VCS_REF}/scripts/docker/Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/cumulus/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates \ - curl && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - 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 && \ - chown -R polkadot:polkadot /data && \ - ln -s /data /polkadot/.local/share/polkadot && \ - mkdir -p /specs - -# add polkadot-parachain binary to the docker image -COPY ./target/release/polkadot-parachain /usr/local/bin -COPY ./target/release/polkadot-parachain.asc /usr/local/bin -COPY ./target/release/polkadot-parachain.sha256 /usr/local/bin -COPY ./parachains/chain-specs/*.json /specs/ - -USER polkadot - -# check if executable works in this container -RUN /usr/local/bin/polkadot-parachain --version - -EXPOSE 30333 9933 9944 -VOLUME ["/polkadot"] - -ENTRYPOINT ["/usr/local/bin/polkadot-parachain"] diff --git a/docker/scripts/adder-collator/build-injected.sh b/docker/scripts/adder-collator/build-injected.sh new file mode 100755 index 00000000000..3a2d4974137 --- /dev/null +++ b/docker/scripts/adder-collator/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=adder-collator,undying-collator +export ARTIFACTS_FOLDER=$1 + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/adder-collator/test-build.sh b/docker/scripts/adder-collator/test-build.sh new file mode 100755 index 00000000000..171e0309f80 --- /dev/null +++ b/docker/scripts/adder-collator/test-build.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# TODO: Switch to /bin/bash when the image is built from parity/base-bin + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /usr/bin/bash \ + paritypr/colander:master -c \ + 'cp "$(which adder-collator)" /export' + +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /usr/bin/bash \ + paritypr/colander:master -c \ + 'cp "$(which undying-collator)" /export' + +./build-injected.sh $TMP diff --git a/docker/scripts/build-injected.sh b/docker/scripts/build-injected.sh new file mode 100755 index 00000000000..f415cf43c0e --- /dev/null +++ b/docker/scripts/build-injected.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +#set -e + +# This script allows building a Container Image from a Linux +# binary that is injected into a base-image. + +ENGINE=${ENGINE:-podman} + +if [ "$ENGINE" == "podman" ]; then + PODMAN_FLAGS="--format docker" +else + PODMAN_FLAGS="" +fi + +CONTEXT=$(mktemp -d) +REGISTRY=${REGISTRY:-docker.io} + +# The following line ensure we know the project root +PROJECT_ROOT=${PROJECT_ROOT:-$(git rev-parse --show-toplevel)} +DOCKERFILE=${DOCKERFILE:-docker/dockerfiles/binary_injected.Dockerfile} +VERSION_TOML=$(grep "^version " $PROJECT_ROOT/Cargo.toml | grep -oE "([0-9\.]+-?[0-9]+)") + +#n The following VAR have default that can be overriden +DOCKER_OWNER=${DOCKER_OWNER:-parity} + +# We may get 1..n binaries, comma separated +BINARY=${BINARY:-polkadot} +IFS=',' read -r -a BINARIES <<< "$BINARY" + +VERSION=${VERSION:-$VERSION_TOML} +ARTIFACTS_FOLDER=${ARTIFACTS_FOLDER:-.} + +IMAGE=${IMAGE:-${REGISTRY}/${DOCKER_OWNER}/${BINARIES[0]}} +DESCRIPTION_DEFAULT="Injected Container image built for ${BINARY}" +DESCRIPTION=${DESCRIPTION:-$DESCRIPTION_DEFAULT} + +VCS_REF=${VCS_REF:-01234567} + +# Build the image +echo "Using engine: $ENGINE" +echo "Using Dockerfile: $DOCKERFILE" +echo "Using context: $CONTEXT" +echo "Building ${IMAGE}:latest container image for ${BINARY} v${VERSION} from ${ARTIFACTS_FOLDER} hang on!" +echo "ARTIFACTS_FOLDER=$ARTIFACTS_FOLDER" +echo "CONTEXT=$CONTEXT" + +# We need all binaries and resources available in the Container build "CONTEXT" +mkdir -p $CONTEXT/bin +for bin in "${BINARIES[@]}" +do + echo "Copying $ARTIFACTS_FOLDER/$bin to context: $CONTEXT/bin" + ls -al "$ARTIFACTS_FOLDER/$bin" + cp -r "$ARTIFACTS_FOLDER/$bin" "$CONTEXT/bin" +done + +cp "$PROJECT_ROOT/docker/scripts/entrypoint.sh" "$CONTEXT" + +if [[ "$BINARY" == "polkadot-parachain" ]]; then + mkdir -p "$CONTEXT/specs" + echo "Copying parachains chain-specs from $ARTIFACTS_FOLDER/specs to context: $CONTEXT/specs" + ls -al "$ARTIFACTS_FOLDER/specs" + cp -r "$ARTIFACTS_FOLDER/specs" "$CONTEXT/specs" +fi + +echo "Building image: ${IMAGE}" + +TAGS=${TAGS[@]:-latest} +IFS=',' read -r -a TAG_ARRAY <<< "$TAGS" +TAG_ARGS=" " + +echo "The image ${IMAGE} will be tagged with ${TAG_ARRAY[*]}" +for tag in "${TAG_ARRAY[@]}"; do + TAG_ARGS+="--tag ${IMAGE}:${tag} " +done + +echo "$TAG_ARGS" + +# time \ +$ENGINE build \ + ${PODMAN_FLAGS} \ + --build-arg VCS_REF="${VCS_REF}" \ + --build-arg BUILD_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \ + --build-arg IMAGE_NAME="${IMAGE}" \ + --build-arg BINARY="${BINARY}" \ + --build-arg ARTIFACTS_FOLDER="${ARTIFACTS_FOLDER}" \ + --build-arg DESCRIPTION="${DESCRIPTION}" \ + ${TAG_ARGS} \ + -f "${PROJECT_ROOT}/${DOCKERFILE}" \ + ${CONTEXT} + +echo "Your Container image for ${IMAGE} is ready" +$ENGINE images + +if [[ -z "${SKIP_IMAGE_VALIDATION}" ]]; then + echo "Check the image ${IMAGE}:${TAG_ARRAY[0]}" + $ENGINE run --rm -i "${IMAGE}:${TAG_ARRAY[0]}" --version + + echo "Query binaries" + $ENGINE run --rm -i --entrypoint /bin/bash "${IMAGE}:${TAG_ARRAY[0]}" -c "echo BINARY: ${BINARY}" +fi diff --git a/docker/scripts/entrypoint.sh b/docker/scripts/entrypoint.sh new file mode 100755 index 00000000000..eaa815faf6a --- /dev/null +++ b/docker/scripts/entrypoint.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Sanity check +if [ -z "$BINARY" ] +then + echo "BINARY ENV not defined, this should never be the case. Aborting..." + exit 1 +fi + +# If the user built the image with multiple binaries, +# we consider the first one to be the canonical one +# To start with another binary, the user can either: +# - use the --entrypoint option +# - pass the ENV BINARY with a single binary +IFS=',' read -r -a BINARIES <<< "$BINARY" +BIN0=${BINARIES[0]} +echo "Starting binary $BIN0" +$BIN0 $@ diff --git a/docker/scripts/malus/build-injected.sh b/docker/scripts/malus/build-injected.sh new file mode 100755 index 00000000000..83e30e17850 --- /dev/null +++ b/docker/scripts/malus/build-injected.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=malus,polkadot-execute-worker,polkadot-prepare-worker +export ARTIFACTS_FOLDER=$1 +# export TAGS=... + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/malus/test-build.sh b/docker/scripts/malus/test-build.sh new file mode 100755 index 00000000000..3114e9e2adf --- /dev/null +++ b/docker/scripts/malus/test-build.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +export TAGS=latest,beta,7777,1.0.2-rc23 + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + paritypr/malus:7217 -c \ + 'cp "$(which malus)" /export' + +echo "Checking binaries we got:" +ls -al $TMP + +./build-injected.sh $TMP diff --git a/docker/scripts/polkadot-parachain/build-injected.sh b/docker/scripts/polkadot-parachain/build-injected.sh new file mode 100755 index 00000000000..f5c86a03517 --- /dev/null +++ b/docker/scripts/polkadot-parachain/build-injected.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=polkadot-parachain +export ARTIFACTS_FOLDER=$1 +export DOCKERFILE="docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile" +# export TAGS=... + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/polkadot-parachain/test-build.sh b/docker/scripts/polkadot-parachain/test-build.sh new file mode 100755 index 00000000000..1dc53bd0d0b --- /dev/null +++ b/docker/scripts/polkadot-parachain/test-build.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +export TAGS=latest,beta,7777,1.0.2-rc23 + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + parity/polkadot-parachain:7217 -c \ + 'cp "$(which malus)" /export' + +echo "Checking binaries we got:" +ls -al $TMP + +./build-injected.sh $TMP diff --git a/cumulus/docker/scripts/build-injected-image.sh b/docker/scripts/polkadot-parachain_build-injected-image.sh similarity index 70% rename from cumulus/docker/scripts/build-injected-image.sh rename to docker/scripts/polkadot-parachain_build-injected-image.sh index b8bb0dd7dd2..bb6909dd3b7 100755 --- a/cumulus/docker/scripts/build-injected-image.sh +++ b/docker/scripts/polkadot-parachain_build-injected-image.sh @@ -6,5 +6,5 @@ IMAGE_NAME=${IMAGE_NAME:-polkadot-parachain} docker build --no-cache \ --build-arg IMAGE_NAME=$IMAGE_NAME \ -t $OWNER/$IMAGE_NAME \ - -f ./docker/injected.Dockerfile \ + -f ./docker/dockerfiles/polkadot-parachain/polkadot-parachain_injected.Dockerfile \ . && docker images diff --git a/docker/scripts/polkadot/build-injected.sh b/docker/scripts/polkadot/build-injected.sh new file mode 100755 index 00000000000..7cc6db43a54 --- /dev/null +++ b/docker/scripts/polkadot/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=polkadot,polkadot-execute-worker,polkadot-prepare-worker +export ARTIFACTS_FOLDER=$1 + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/polkadot/test-build.sh b/docker/scripts/polkadot/test-build.sh new file mode 100755 index 00000000000..d2d904561cb --- /dev/null +++ b/docker/scripts/polkadot/test-build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# You need to build an injected image first + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + parity/polkadot -c \ + 'cp "$(which polkadot)" /export' + +echo "Checking binaries we got:" +tree $TMP + +./build-injected.sh $TMP diff --git a/docker/scripts/staking-miner/README.md b/docker/scripts/staking-miner/README.md new file mode 100644 index 00000000000..3610e113031 --- /dev/null +++ b/docker/scripts/staking-miner/README.md @@ -0,0 +1,37 @@ +# staking-miner container image + +## Build using the Builder + +``` +./build.sh +``` + +## Build the injected Image + +You first need a valid Linux binary to inject. Let's assume this binary is located in `BIN_FOLDER`. + +``` +./build-injected.sh "$BIN_FOLDER" +``` + +## Test + +Here is how to test the image. We can generate a valid seed but the staking-miner will quickly notice that our +account is not funded and "does not exist". + +You may pass any ENV supported by the binary and must provide at least a few such as `SEED` and `URI`: +``` +ENV SEED="" +ENV URI="wss://rpc.polkadot.io:443" +ENV RUST_LOG="info" +``` + +``` +export SEED=$(subkey generate -n polkadot --output-type json | jq -r .secretSeed) +podman run --rm -it \ + -e URI="wss://rpc.polkadot.io:443" \ + -e RUST_LOG="info" \ + -e SEED \ + localhost/parity/staking-miner \ + dry-run seq-phragmen +``` diff --git a/docker/scripts/staking-miner/build-injected.sh b/docker/scripts/staking-miner/build-injected.sh new file mode 100755 index 00000000000..efe323b5fed --- /dev/null +++ b/docker/scripts/staking-miner/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_staking-miner_binary +# This script replace the former dedicated staking-miner "injected" Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=staking-miner +export ARTIFACTS_FOLDER=$1 + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/staking-miner/build.sh b/docker/scripts/staking-miner/build.sh new file mode 100755 index 00000000000..c2b6ab77e53 --- /dev/null +++ b/docker/scripts/staking-miner/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_staking-miner_binary +# This script replace the former dedicated staking-miner "injected" Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` +ENGINE=podman + +echo "Building the staking-miner using the Builder image" +echo "PROJECT_ROOT=$PROJECT_ROOT" +$ENGINE build -t staking-miner -f "${PROJECT_ROOT}/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile" "$PROJECT_ROOT" diff --git a/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md b/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md new file mode 100644 index 00000000000..ce424c42f47 --- /dev/null +++ b/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md @@ -0,0 +1,3 @@ +# Staking-miner Docker image + +## [GitHub](https://github.com/paritytech/polkadot/tree/master/utils/staking-miner) diff --git a/docker/scripts/staking-miner/staking-miner_builder.Dockerfile b/docker/scripts/staking-miner/staking-miner_builder.Dockerfile new file mode 100644 index 00000000000..0ae77f36c79 --- /dev/null +++ b/docker/scripts/staking-miner/staking-miner_builder.Dockerfile @@ -0,0 +1,43 @@ +FROM paritytech/ci-linux:production as builder + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG IMAGE_NAME="staking-miner" +ARG PROFILE=production + +LABEL description="This is the build stage. Here we create the binary." + +WORKDIR /app +COPY . /app +RUN cargo build --locked --profile $PROFILE --package staking-miner + +# ===== SECOND STAGE ====== + +FROM docker.io/parity/base-bin:latest +LABEL description="This is the 2nd stage: a very small image where we copy the binary." +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="${IMAGE_NAME} for substrate based chains" \ + io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_builder.Dockerfile" \ + io.parity.image.revision="${VCS_REF}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot/" + +ARG PROFILE=release +COPY --from=builder /app/target/$PROFILE/staking-miner /usr/local/bin + +# show backtraces +ENV RUST_BACKTRACE 1 + +USER parity + +ENV SEED="" +ENV URI="wss://rpc.polkadot.io" +ENV RUST_LOG="info" + +# check if the binary works in this container +RUN /usr/local/bin/staking-miner --version + +ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/docker/scripts/staking-miner/test-build.sh b/docker/scripts/staking-miner/test-build.sh new file mode 100755 index 00000000000..0ce74e2df29 --- /dev/null +++ b/docker/scripts/staking-miner/test-build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# You need to build an injected image first + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + parity/staking-miner -c \ + 'cp "$(which staking-miner)" /export' + +echo "Checking binaries we got:" +tree $TMP + +./build-injected.sh $TMP diff --git a/cumulus/docs/container.md b/docs/container.md similarity index 96% rename from cumulus/docs/container.md rename to docs/container.md index ef7c52a44fa..afd3b27957c 100644 --- a/cumulus/docs/container.md +++ b/docs/container.md @@ -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/polkadot-parachain_builder.Containerfile . + --file ./docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile . ``` You may then run your new container: diff --git a/polkadot/doc/docker.md b/docs/docker.md similarity index 98% rename from polkadot/doc/docker.md rename to docs/docker.md index dc679908ec6..53619ca1a97 100644 --- a/polkadot/doc/docker.md +++ b/docs/docker.md @@ -144,7 +144,7 @@ There are 3 options to build a Polkadot container image: To get up and running with the smallest footprint on your system, you may use an existing Polkadot Container image. You may also build a Polkadot container image yourself (it takes a while...) using the container specs -`scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile`. +`docker/dockerfiles/polkadot/polkadot_builder.Dockerfile`. ### Debian injected diff --git a/polkadot/.github/workflows/release-40_publish-rc-image.yml b/polkadot/.github/workflows/release-40_publish-rc-image.yml deleted file mode 100644 index 3d91c5b8c68..00000000000 --- a/polkadot/.github/workflows/release-40_publish-rc-image.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Release - Publish RC Container image -# see https://github.com/paritytech/release-engineering/issues/97#issuecomment-1651372277 - -on: - workflow_dispatch: - inputs: - release_id: - description: | - Release ID. - You can find it using the command: - curl -s \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/$OWNER/$REPO/releases | \ - jq '.[] | { name: .name, id: .id }' - required: true - type: string - registry: - description: "Container registry" - required: true - type: string - default: docker.io - owner: - description: Owner of the container image repo - required: true - type: string - default: parity - -env: - RELEASE_ID: ${{ inputs.release_id }} - ENGINE: docker - REGISTRY: ${{ inputs.registry }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCKER_OWNER: ${{ inputs.owner || github.repository_owner }} - REPO: ${{ github.repository }} - -jobs: - fetch-artifacts: - runs-on: ubuntu-latest - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Fetch all artifacts - run: | - . ./scripts/ci/common/lib.sh - fetch_release_artifacts - - - name: Cache the artifacts - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 - with: - key: artifacts-${{ github.sha }} - path: | - ./release-artifacts/**/* - - build-container: - runs-on: ubuntu-latest - needs: fetch-artifacts - - strategy: - matrix: - binary: ["polkadot", "staking-miner"] - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Get artifacts from cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 - with: - key: artifacts-${{ github.sha }} - fail-on-cache-miss: true - path: | - ./release-artifacts/**/* - - - name: Check sha256 ${{ matrix.binary }} - working-directory: ./release-artifacts - run: | - . ../scripts/ci/common/lib.sh - - echo "Checking binary ${{ matrix.binary }}" - check_sha256 ${{ matrix.binary }} && echo "OK" || echo "ERR" - - - name: Check GPG ${{ matrix.binary }} - working-directory: ./release-artifacts - run: | - . ../scripts/ci/common/lib.sh - import_gpg_keys - check_gpg ${{ matrix.binary }} - - - name: Fetch commit and tag - id: fetch_refs - run: | - release=release-${{ inputs.release_id }} && \ - echo "release=${release}" >> $GITHUB_OUTPUT - - commit=$(git rev-parse --short HEAD) && \ - echo "commit=${commit}" >> $GITHUB_OUTPUT - - tag=$(git name-rev --tags --name-only $(git rev-parse HEAD)) && \ - [ "${tag}" != "undefined" ] && echo "tag=${tag}" >> $GITHUB_OUTPUT || \ - echo "No tag, doing without" - - - name: Build Injected Container image for ${{ matrix.binary }} - env: - BIN_FOLDER: ./release-artifacts - BINARY: ${{ matrix.binary }} - TAGS: ${{join(steps.fetch_refs.outputs.*, ',')}} - run: | - echo "Building container for ${{ matrix.binary }}" - ./scripts/ci/dockerfiles/build-injected.sh - - - name: Login to Dockerhub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Push Container image for ${{ matrix.binary }} - id: docker_push - env: - BINARY: ${{ matrix.binary }} - run: | - $ENGINE images | grep ${BINARY} - $ENGINE push --all-tags ${REGISTRY}/${DOCKER_OWNER}/${BINARY} - - - name: Check version for the published image for ${{ matrix.binary }} - env: - BINARY: ${{ matrix.binary }} - RELEASE_TAG: ${{ steps.fetch_refs.outputs.release }} - run: | - echo "Checking tag ${RELEASE_TAG} for image ${REGISTRY}/${DOCKER_OWNER}/${BINARY}" - $ENGINE run -i ${REGISTRY}/${DOCKER_OWNER}/${BINARY}:${RELEASE_TAG} --version diff --git a/polkadot/.github/workflows/release-51_publish-docker-manual.yml b/polkadot/.github/workflows/release-51_publish-docker-manual.yml deleted file mode 100644 index 919769f8700..00000000000 --- a/polkadot/.github/workflows/release-51_publish-docker-manual.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Release - Publish Docker image (manual dispatch) - -on: - workflow_dispatch: - inputs: - version: - description: version to build/release - default: v0.9.18 - required: true - date: - description: release date of version - default: "2022-02-23T19:11:58Z" - required: true - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # v2.1.0 - - name: Cache Docker layers - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - name: Login to Dockerhub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push - id: docker_build - uses: docker/build-push-action@v4 - with: - push: true - file: scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile - tags: | - parity/polkadot:latest - parity/polkadot:${{ github.event.inputs.version }} - build-args: | - POLKADOT_VERSION=${{ github.event.inputs.version }} - VCS_REF=${{ github.ref }} - BUILD_DATE=${{ github.event.inputs.date }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/polkadot/utils/staking-miner/README.md b/polkadot/utils/staking-miner/README.md index 8fec746e6ee..90a00eeac08 100644 --- a/polkadot/utils/staking-miner/README.md +++ b/polkadot/utils/staking-miner/README.md @@ -51,7 +51,7 @@ to be installed. The trade-off however is that it takes a little longer to build tasks. You may build the multi-stage image the root of the Polkadot repository with: ``` TODO: UPDATE THAT -docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile . +docker build -t staking-miner -f docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile . ``` ### Running -- GitLab From 1e2a2f0c69f3d8179a45363ddad18d26b5531183 Mon Sep 17 00:00:00 2001 From: eskimor Date: Wed, 6 Sep 2023 18:19:21 +0200 Subject: [PATCH 091/633] Fix nothing scheduled on session boundary (#1403) * Fix scheduled state at session boundaries. * Cleanup + better docs. * More cleanup and fixes. * Remove 12s hack. * Add dep. * Make clippy happy --------- Co-authored-by: eskimor --- Cargo.lock | 1 + polkadot/primitives/src/lib.rs | 4 +- polkadot/primitives/src/v5/mod.rs | 54 ---- polkadot/runtime/parachains/Cargo.toml | 1 + polkadot/runtime/parachains/src/assigner.rs | 4 +- .../parachains/src/assigner_on_demand/mod.rs | 5 +- .../src/assigner_on_demand/tests.rs | 6 +- .../parachains/src/assigner_parachains.rs | 6 +- polkadot/runtime/parachains/src/builder.rs | 14 +- .../runtime/parachains/src/configuration.rs | 17 +- .../runtime/parachains/src/inclusion/mod.rs | 208 ++++++------- .../runtime/parachains/src/inclusion/tests.rs | 129 +++----- .../parachains/src/paras_inherent/mod.rs | 32 +- .../parachains/src/paras_inherent/tests.rs | 22 +- .../parachains/src/runtime_api_impl/v5.rs | 66 ++-- polkadot/runtime/parachains/src/scheduler.rs | 281 +++++++++++------- .../parachains/src/scheduler/common.rs | 50 +--- .../parachains/src/scheduler/migration.rs | 1 - .../runtime/parachains/src/scheduler/tests.rs | 237 ++++++--------- 19 files changed, 492 insertions(+), 646 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d08c175bde..2fff5787989 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12792,6 +12792,7 @@ dependencies = [ "pallet-timestamp", "pallet-vesting", "parity-scale-codec", + "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 729908cc12b..9121b379085 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -41,8 +41,8 @@ pub use v5::{ BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, CollatorSignature, - CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, CoreOccupied, CoreState, - DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, ExecutorParam, + 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, diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v5/mod.rs index eed4cc2b36b..30782f95611 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v5/mod.rs @@ -830,60 +830,6 @@ pub struct ParathreadEntry { pub retries: u32, } -/// An assignment for a parachain scheduled to be backed and included in a relay chain block. -#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebug)] -pub struct Assignment { - /// Assignment's ParaId - pub para_id: Id, -} - -impl Assignment { - /// Create a new `Assignment`. - pub fn new(para_id: Id) -> Self { - Self { para_id } - } -} - -/// An entry tracking a paras -#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] -pub struct ParasEntry { - /// The `Assignment` - pub assignment: Assignment, - /// The number of times the entry has timed out in availability. - pub availability_timeouts: u32, - /// The block height where this entry becomes invalid. - pub ttl: N, -} - -impl ParasEntry { - /// Return `Id` from the underlying `Assignment`. - pub fn para_id(&self) -> Id { - self.assignment.para_id - } - - /// Create a new `ParasEntry`. - pub fn new(assignment: Assignment, now: N) -> Self { - ParasEntry { assignment, availability_timeouts: 0, ttl: now } - } -} - -/// What is occupying a specific availability core. -#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(PartialEq))] -pub enum CoreOccupied { - /// The core is not occupied. - Free, - /// A paras. - Paras(ParasEntry), -} - -impl CoreOccupied { - /// Is core free? - pub fn is_free(&self) -> bool { - matches!(self, Self::Free) - } -} - /// A helper data-type for tracking validator-group rotations. #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 0e2f6aa1aa2..77eba0bc10b 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -50,6 +50,7 @@ rand_chacha = { version = "0.3.1", default-features = false } static_assertions = { version = "1.1.0", optional = true } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } polkadot-runtime-metrics = { path = "../metrics", default-features = false} +polkadot-core-primitives = { path = "../../core-primitives", default-features = false } [dev-dependencies] futures = "0.3.21" diff --git a/polkadot/runtime/parachains/src/assigner.rs b/polkadot/runtime/parachains/src/assigner.rs index 55434da11f3..b21e857a471 100644 --- a/polkadot/runtime/parachains/src/assigner.rs +++ b/polkadot/runtime/parachains/src/assigner.rs @@ -17,11 +17,11 @@ //! The Polkadot multiplexing assignment provider. //! Provides blockspace assignments for both bulk and on demand parachains. use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; +use primitives::{CoreIndex, Id as ParaId}; use crate::{ configuration, paras, - scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig}, }; pub use pallet::*; diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index 0c9813d144f..75c29bd6fbe 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -34,7 +34,7 @@ mod tests; use crate::{ configuration, paras, - scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig}, }; use frame_support::{ @@ -46,7 +46,7 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::*; -use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; +use primitives::{CoreIndex, Id as ParaId}; use sp_runtime::{ traits::{One, SaturatedConversion}, FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating, @@ -606,7 +606,6 @@ impl AssignmentProvider> for Pallet { fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { let config = >::config(); AssignmentProviderConfig { - availability_period: config.paras_availability_period, max_availability_timeouts: config.on_demand_retries, ttl: config.on_demand_ttl, } diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs index 8041179cd90..fe9a4e52bd0 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs @@ -24,13 +24,11 @@ use crate::{ System, Test, }, paras::{ParaGenesisArgs, ParaKind}, + scheduler::common::Assignment, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use pallet_balances::Error as BalancesError; -use primitives::{ - v5::{Assignment, ValidationCode}, - BlockNumber, SessionIndex, -}; +use primitives::{v5::ValidationCode, BlockNumber, SessionIndex}; use sp_std::collections::btree_map::BTreeMap; fn schedule_blank_para(id: ParaId, parakind: ParaKind) { diff --git a/polkadot/runtime/parachains/src/assigner_parachains.rs b/polkadot/runtime/parachains/src/assigner_parachains.rs index 9a6b970597d..d605d866051 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains.rs @@ -19,11 +19,11 @@ use crate::{ configuration, paras, - scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig}, }; use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; -use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; +use primitives::{CoreIndex, Id as ParaId}; #[frame_support::pallet] pub mod pallet { @@ -57,9 +57,7 @@ impl AssignmentProvider> for Pallet { fn push_assignment_for_core(_: CoreIndex, _: Assignment) {} fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { - let config = >::config(); AssignmentProviderConfig { - availability_period: config.paras_availability_period, // The next assignment already goes to the same [`ParaId`], no timeout tracking needed. max_availability_timeouts: 0, // The next assignment already goes to the same [`ParaId`], this can be any number diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 4921af5bedd..dced24df0ae 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -18,18 +18,20 @@ use crate::{ configuration, inclusion, initializer, paras, paras::ParaKind, paras_inherent, - scheduler::{self, common::AssignmentProviderConfig}, + scheduler::{ + self, + common::{Assignment, AssignmentProviderConfig}, + CoreOccupied, ParasEntry, + }, session_info, shared, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use primitives::{ - collator_signature_payload, - v5::{Assignment, ParasEntry}, - AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor, - CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, - CoreIndex, CoreOccupied, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, + collator_signature_payload, AvailabilityBitfield, BackedCandidate, CandidateCommitments, + CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, + CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned, ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation, diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 0c66bb5bdf9..33039cd08ca 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -190,11 +190,20 @@ pub struct HostConfiguration { /// /// Must be non-zero. pub group_rotation_frequency: BlockNumber, - /// The availability period, in blocks. This is the amount of blocks - /// after inclusion that validators have to make the block available and signal its - /// availability to the chain. + /// The minimum availability period, in blocks. /// - /// Must be at least 1. + /// This is the minimum amount of blocks after a core became occupied that validators have time + /// to make the block available. + /// + /// This value only has effect on group rotations. If backers backed something at the end of + /// their rotation, the occupied core affects the backing group that comes afterwards. We limit + /// the effect one backing group can have on the next to `paras_availability_period` blocks. + /// + /// Within a group rotation there is no timeout as backers are only affecting themselves. + /// + /// Must be at least 1. With a value of 1, the previous group will not be able to negatively + /// affect the following group at the expense of a tight availability timeline at group + /// rotation boundaries. pub paras_availability_period: BlockNumber, /// The amount of blocks ahead to schedule paras. pub scheduling_lookahead: u32, diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index a9ee2d1b961..bb16c804150 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -22,7 +22,7 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, paras, - scheduler::{self, common::CoreAssignment}, + scheduler::{self, AvailabilityTimeoutStatus}, shared::{self, AllowedRelayParentsTracker}, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; @@ -46,7 +46,10 @@ use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; #[cfg(feature = "std")] use sp_std::fmt; -use sp_std::{collections::btree_set::BTreeSet, prelude::*}; +use sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + prelude::*, +}; pub use pallet::*; @@ -597,7 +600,7 @@ impl Pallet { pub(crate) fn process_candidates( allowed_relay_parents: &AllowedRelayParentsTracker>, candidates: Vec>, - scheduled: Vec>>, + scheduled: &BTreeMap, group_validators: GV, ) -> Result, DispatchError> where @@ -620,20 +623,18 @@ impl Pallet { // Do all checks before writing storage. let core_indices_and_backers = { - let mut skip = 0; let mut core_indices_and_backers = Vec::with_capacity(candidates.len()); let mut last_core = None; - let mut check_assignment_in_order = - |assignment: &CoreAssignment>| -> DispatchResult { - ensure!( - last_core.map_or(true, |core| assignment.core > core), - Error::::ScheduledOutOfOrder, - ); + let mut check_assignment_in_order = |core_idx| -> DispatchResult { + ensure!( + last_core.map_or(true, |core| core_idx > core), + Error::::ScheduledOutOfOrder, + ); - last_core = Some(assignment.core); - Ok(()) - }; + last_core = Some(core_idx); + Ok(()) + }; // We combine an outer loop over candidates with an inner loop over the scheduled, // where each iteration of the outer loop picks up at the position @@ -645,9 +646,7 @@ impl Pallet { // // In the meantime, we do certain sanity checks on the candidates and on the scheduled // list. - 'next_backed_candidate: for (candidate_idx, backed_candidate) in - candidates.iter().enumerate() - { + for (candidate_idx, backed_candidate) in candidates.iter().enumerate() { let relay_parent_hash = backed_candidate.descriptor().relay_parent; let para_id = backed_candidate.descriptor().para_id; @@ -681,108 +680,89 @@ impl Pallet { let para_id = backed_candidate.descriptor().para_id; let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; - for (i, core_assignment) in scheduled[skip..].iter().enumerate() { - check_assignment_in_order(core_assignment)?; + let core_idx = *scheduled.get(¶_id).ok_or(Error::::UnscheduledCandidate)?; + check_assignment_in_order(core_idx)?; + ensure!( + >::get(¶_id).is_none() && + >::get(¶_id).is_none(), + Error::::CandidateScheduledBeforeParaFree, + ); - if para_id == core_assignment.paras_entry.para_id() { - ensure!( - >::get(¶_id).is_none() && - >::get(¶_id).is_none(), - Error::::CandidateScheduledBeforeParaFree, - ); + // The candidate based upon relay parent `N` should be backed by a group + // assigned to core at block `N + 1`. Thus, `relay_parent_number + 1` + // will always land in the current session. + let group_idx = >::group_assigned_to_core( + core_idx, + relay_parent_number + One::one(), + ) + .ok_or_else(|| { + log::warn!( + target: LOG_TARGET, + "Failed to compute group index for candidate {}", + candidate_idx + ); + Error::::InvalidAssignment + })?; + let group_vals = + group_validators(group_idx).ok_or_else(|| Error::::InvalidGroupIndex)?; - // account for already skipped, and then skip this one. - skip = i + skip + 1; - - // The candidate based upon relay parent `N` should be backed by a group - // assigned to core at block `N + 1`. Thus, `relay_parent_number + 1` - // will always land in the current session. - let group_idx = >::group_assigned_to_core( - core_assignment.core, - relay_parent_number + One::one(), - ) - .ok_or_else(|| { - log::warn!( - target: LOG_TARGET, - "Failed to compute group index for candidate {}", - candidate_idx - ); - Error::::InvalidAssignment - })?; - let group_vals = group_validators(group_idx) - .ok_or_else(|| Error::::InvalidGroupIndex)?; - - // check the signatures in the backing and that it is a majority. - { - let maybe_amount_validated = primitives::check_candidate_backing( - &backed_candidate, - &signing_context, - group_vals.len(), - |intra_group_vi| { - group_vals - .get(intra_group_vi) - .and_then(|vi| validators.get(vi.0 as usize)) - .map(|v| v.clone()) - }, - ); - - match maybe_amount_validated { - Ok(amount_validated) => ensure!( - amount_validated >= - effective_minimum_backing_votes( - group_vals.len(), - minimum_backing_votes - ), - Error::::InsufficientBacking, + // check the signatures in the backing and that it is a majority. + { + let maybe_amount_validated = primitives::check_candidate_backing( + &backed_candidate, + &signing_context, + group_vals.len(), + |intra_group_vi| { + group_vals + .get(intra_group_vi) + .and_then(|vi| validators.get(vi.0 as usize)) + .map(|v| v.clone()) + }, + ); + + match maybe_amount_validated { + Ok(amount_validated) => ensure!( + amount_validated >= + effective_minimum_backing_votes( + group_vals.len(), + minimum_backing_votes ), - Err(()) => { - Err(Error::::InvalidBacking)?; - }, - } - - let mut backer_idx_and_attestation = - Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( - backed_candidate.validator_indices.count_ones(), - ); - let candidate_receipt = backed_candidate.receipt(); - - for ((bit_idx, _), attestation) in backed_candidate - .validator_indices - .iter() - .enumerate() - .filter(|(_, signed)| **signed) - .zip(backed_candidate.validity_votes.iter().cloned()) - { - let val_idx = group_vals - .get(bit_idx) - .expect("this query succeeded above; qed"); - backer_idx_and_attestation.push((*val_idx, attestation)); - - backers.set(val_idx.0 as _, true); - } - candidate_receipt_with_backing_validator_indices - .push((candidate_receipt, backer_idx_and_attestation)); - } - - core_indices_and_backers.push(( - (core_assignment.core, core_assignment.paras_entry.para_id()), - backers, - group_idx, - relay_parent_number, - )); - continue 'next_backed_candidate + Error::::InsufficientBacking, + ), + Err(()) => { + Err(Error::::InvalidBacking)?; + }, } - } - // end of loop reached means that the candidate didn't appear in the non-traversed - // section of the `scheduled` slice. either it was not scheduled or didn't appear in - // `candidates` in the correct order. - ensure!(false, Error::::UnscheduledCandidate); - } + let mut backer_idx_and_attestation = + Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( + backed_candidate.validator_indices.count_ones(), + ); + let candidate_receipt = backed_candidate.receipt(); + + for ((bit_idx, _), attestation) in backed_candidate + .validator_indices + .iter() + .enumerate() + .filter(|(_, signed)| **signed) + .zip(backed_candidate.validity_votes.iter().cloned()) + { + let val_idx = + group_vals.get(bit_idx).expect("this query succeeded above; qed"); + backer_idx_and_attestation.push((*val_idx, attestation)); + + backers.set(val_idx.0 as _, true); + } + candidate_receipt_with_backing_validator_indices + .push((candidate_receipt, backer_idx_and_attestation)); + } - // check remainder of scheduled cores, if any. - for assignment in scheduled[skip..].iter() { - check_assignment_in_order(assignment)?; + core_indices_and_backers.push(( + (core_idx, para_id), + backers, + group_idx, + relay_parent_number, + )); } core_indices_and_backers @@ -1043,13 +1023,13 @@ impl Pallet { /// /// Returns a vector of cleaned-up core IDs. pub(crate) fn collect_pending( - pred: impl Fn(CoreIndex, BlockNumberFor) -> bool, + pred: impl Fn(BlockNumberFor) -> AvailabilityTimeoutStatus>, ) -> Vec { let mut cleaned_up_ids = Vec::new(); let mut cleaned_up_cores = Vec::new(); for (para_id, pending_record) in >::iter() { - if pred(pending_record.core, pending_record.backed_in_number) { + if pred(pending_record.backed_in_number).timed_out { cleaned_up_ids.push(para_id); cleaned_up_cores.push(pending_record.core); } diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 70c5e959038..7677108d73d 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -36,7 +36,6 @@ use frame_support::assert_noop; use keyring::Sr25519Keyring; use parity_scale_codec::DecodeAll; use primitives::{ - v5::{Assignment, ParasEntry}, BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId, CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement, ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID, @@ -380,7 +379,9 @@ fn collect_pending_cleans_up_pending() { (chain_b, ParaKind::Parachain), (thread_a, ParaKind::Parathread), ]; - new_test_ext(genesis_config(paras)).execute_with(|| { + let mut config = genesis_config(paras); + config.configuration.config.group_rotation_frequency = 3; + new_test_ext(config).execute_with(|| { let default_candidate = TestCandidateBuilder::default().build(); >::insert( chain_a, @@ -408,7 +409,7 @@ fn collect_pending_cleans_up_pending() { descriptor: default_candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, - backed_in_number: 0, + backed_in_number: 5, backers: default_backing_bitfield(), backing_group: GroupIndex::from(1), }, @@ -422,7 +423,7 @@ fn collect_pending_cleans_up_pending() { assert!(>::get(&chain_a).is_some()); assert!(>::get(&chain_b).is_some()); - ParaInclusion::collect_pending(|core, _since| core == CoreIndex::from(0)); + ParaInclusion::collect_pending(Scheduler::availability_timeout_predicate()); assert!(>::get(&chain_a).is_none()); assert!(>::get(&chain_b).is_some()); @@ -910,23 +911,12 @@ fn candidate_checks() { ]; Scheduler::set_validator_groups(validator_groups); - let entry_ttl = 10_000; let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); - let chain_a_assignment = CoreAssignment { - core: CoreIndex::from(0), - paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - }; - - let chain_b_assignment = CoreAssignment { - core: CoreIndex::from(1), - paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), - }; + let chain_a_assignment = (chain_a, CoreIndex::from(0)); - let thread_a_assignment = CoreAssignment { - core: CoreIndex::from(2), - paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), - }; + let chain_b_assignment = (chain_b, CoreIndex::from(1)); + let thread_a_assignment = (thread_a, CoreIndex::from(2)); let allowed_relay_parents = default_allowed_relay_parent_tracker(); // unscheduled candidate. @@ -955,7 +945,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_b_assignment.clone()], + &[chain_b_assignment].into_iter().collect(), &group_validators, ), Error::::UnscheduledCandidate @@ -1010,10 +1000,10 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed_b, backed_a], - vec![chain_a_assignment.clone(), chain_b_assignment.clone()], + &[chain_a_assignment, chain_b_assignment].into_iter().collect(), &group_validators, ), - Error::::UnscheduledCandidate + Error::::ScheduledOutOfOrder ); } @@ -1043,7 +1033,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::InsufficientBacking @@ -1100,7 +1090,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed_b, backed_a], - vec![chain_a_assignment.clone(), chain_b_assignment.clone()], + &[chain_a_assignment, chain_b_assignment].into_iter().collect(), &group_validators, ), Error::::DisallowedRelayParent @@ -1138,7 +1128,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![thread_a_assignment.clone()], + &[thread_a_assignment].into_iter().collect(), &group_validators, ), Error::::NotCollatorSigned @@ -1188,7 +1178,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::CandidateScheduledBeforeParaFree @@ -1228,7 +1218,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::CandidateScheduledBeforeParaFree @@ -1272,7 +1262,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::PrematureCodeUpgrade @@ -1306,7 +1296,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Err(Error::::ValidationDataHashMismatch.into()), @@ -1341,7 +1331,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::InvalidValidationCodeHash @@ -1376,7 +1366,7 @@ fn candidate_checks() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ), Error::::ParaHeadMismatch @@ -1446,21 +1436,9 @@ fn backing_works() { let allowed_relay_parents = default_allowed_relay_parent_tracker(); - let entry_ttl = 10_000; - let chain_a_assignment = CoreAssignment { - core: CoreIndex::from(0), - paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - }; - - let chain_b_assignment = CoreAssignment { - core: CoreIndex::from(1), - paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), - }; - - let thread_a_assignment = CoreAssignment { - core: CoreIndex::from(2), - paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), - }; + let chain_a_assignment = (chain_a, CoreIndex::from(0)); + let chain_b_assignment = (chain_b, CoreIndex::from(1)); + let thread_a_assignment = (thread_a, CoreIndex::from(2)); let mut candidate_a = TestCandidateBuilder { para_id: chain_a, @@ -1548,11 +1526,9 @@ fn backing_works() { } = ParaInclusion::process_candidates( &allowed_relay_parents, backed_candidates.clone(), - vec![ - chain_a_assignment.clone(), - chain_b_assignment.clone(), - thread_a_assignment.clone(), - ], + &[chain_a_assignment, chain_b_assignment, thread_a_assignment] + .into_iter() + .collect(), &group_validators, ) .expect("candidates scheduled, in order, and backed"); @@ -1738,12 +1714,7 @@ fn can_include_candidate_with_ok_code_upgrade() { Scheduler::set_validator_groups(validator_groups); let allowed_relay_parents = default_allowed_relay_parent_tracker(); - let entry_ttl = 10_000; - let chain_a_assignment = CoreAssignment { - core: CoreIndex::from(0), - paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - }; - + let chain_a_assignment = (chain_a, CoreIndex::from(0)); let mut candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), @@ -1769,7 +1740,7 @@ fn can_include_candidate_with_ok_code_upgrade() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed_a], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ) .expect("candidates scheduled, in order, and backed"); @@ -1895,28 +1866,10 @@ fn check_allowed_relay_parents() { max_ancestry_len, ); - let chain_a_assignment = CoreAssignment { - core: CoreIndex::from(0), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_a }, - availability_timeouts: 0, - ttl: 5, - }, - }; + let chain_a_assignment = (chain_a, CoreIndex::from(0)); - let chain_b_assignment = CoreAssignment { - core: CoreIndex::from(1), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_b }, - availability_timeouts: 0, - ttl: 5, - }, - }; - - let thread_a_assignment = CoreAssignment { - core: CoreIndex::from(2), - paras_entry: ParasEntry::new(Assignment::new(thread_a), 5), - }; + let chain_b_assignment = (chain_b, CoreIndex::from(1)); + let thread_a_assignment = (thread_a, CoreIndex::from(2)); let mut candidate_a = TestCandidateBuilder { para_id: chain_a, @@ -1998,11 +1951,9 @@ fn check_allowed_relay_parents() { ParaInclusion::process_candidates( &allowed_relay_parents, backed_candidates.clone(), - vec![ - chain_a_assignment.clone(), - chain_b_assignment.clone(), - thread_a_assignment.clone(), - ], + &[chain_a_assignment, chain_b_assignment, thread_a_assignment] + .into_iter() + .collect(), &group_validators, ) .expect("candidates scheduled, in order, and backed"); @@ -2212,15 +2163,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let allowed_relay_parents = default_allowed_relay_parent_tracker(); - let chain_a_assignment = CoreAssignment { - core: CoreIndex::from(0), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_a }, - availability_timeouts: 0, - ttl: 5, - }, - }; - + let chain_a_assignment = (chain_a, CoreIndex::from(0)); let mut candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), @@ -2246,7 +2189,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ParaInclusion::process_candidates( &allowed_relay_parents, vec![backed_a], - vec![chain_a_assignment.clone()], + &[chain_a_assignment].into_iter().collect(), &group_validators, ) .expect("candidates scheduled, in order, and backed"); diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 6244f44e434..8e918d35d5f 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -29,10 +29,7 @@ use crate::{ initializer, metrics::METRICS, paras, - scheduler::{ - self, - common::{CoreAssignment, FreedReason}, - }, + scheduler::{self, FreedReason}, shared, ParaId, }; use bitvec::prelude::BitVec; @@ -245,8 +242,8 @@ pub mod pallet { T: Config, { // Handle timeouts for any availability core work. - let availability_pred = >::availability_timeout_predicate(); - let freed_timeout = if let Some(pred) = availability_pred { + let freed_timeout = if >::availability_timeout_check_required() { + let pred = >::availability_timeout_predicate(); >::collect_pending(pred) } else { Vec::new() @@ -320,7 +317,7 @@ impl Pallet { /// /// When called from `create_inherent` the `context` must be set to /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent - /// is not overweight. + /// is not overweight. /// It is **mandatory** that calls from `enter` set `context` to /// `ProcessInherentDataContext::Enter` to ensure the weight invariant is checked. /// @@ -583,7 +580,10 @@ impl Pallet { let freed = collect_all_freed_cores::(freed_concluded.iter().cloned()); - let scheduled = >::update_claimqueue(freed, now); + >::update_claimqueue(freed, now); + let scheduled = >::scheduled_paras() + .map(|(core_idx, para_id)| (para_id, core_idx)) + .collect(); METRICS.on_candidates_processed_total(backed_candidates.len() as u64); @@ -608,7 +608,7 @@ impl Pallet { .verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate) .is_err() }, - &scheduled[..], + &scheduled, ); METRICS.on_candidates_sanitized(backed_candidates.len() as u64); @@ -620,7 +620,7 @@ impl Pallet { } = >::process_candidates( &allowed_relay_parents, backed_candidates.clone(), - scheduled, + &scheduled, >::group_validators, )?; // Note which of the scheduled cores were actually occupied by a backed candidate. @@ -917,7 +917,7 @@ fn sanitize_backed_candidates< >( mut backed_candidates: Vec>, mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, - scheduled: &[CoreAssignment>], + scheduled: &BTreeMap, ) -> Vec> { // Remove any candidates that were concluded invalid. // This does not assume sorting. @@ -925,11 +925,6 @@ fn sanitize_backed_candidates< !candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate) }); - let scheduled_paras_to_core_idx = scheduled - .into_iter() - .map(|core_assignment| (core_assignment.paras_entry.para_id(), core_assignment.core)) - .collect::>(); - // Assure the backed candidate's `ParaId`'s core is free. // This holds under the assumption that `Scheduler::schedule` is called _before_. // We don't check the relay-parent because this is done in the closure when @@ -938,7 +933,7 @@ fn sanitize_backed_candidates< backed_candidates.retain(|backed_candidate| { let desc = backed_candidate.descriptor(); - scheduled_paras_to_core_idx.get(&desc.para_id).is_some() + scheduled.get(&desc.para_id).is_some() }); // Sort the `Vec` last, once there is a guarantee that these @@ -948,8 +943,7 @@ fn sanitize_backed_candidates< // but also allows this to be done in place. backed_candidates.sort_by(|x, y| { // Never panics, since we filtered all panic arguments out in the previous `fn retain`. - scheduled_paras_to_core_idx[&x.descriptor().para_id] - .cmp(&scheduled_paras_to_core_idx[&y.descriptor().para_id]) + scheduled[&x.descriptor().para_id].cmp(&scheduled[&y.descriptor().para_id]) }); backed_candidates diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index ab515cb3756..7c70fcea194 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -963,10 +963,7 @@ mod sanitizers { use crate::mock::Test; use keyring::Sr25519Keyring; - use primitives::{ - v5::{Assignment, ParasEntry}, - PARACHAIN_KEY_TYPE_ID, - }; + use primitives::PARACHAIN_KEY_TYPE_ID; use sc_keystore::LocalKeystore; use sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; @@ -1239,21 +1236,10 @@ mod sanitizers { let has_concluded_invalid = |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - let entry_ttl = 10_000; let scheduled = (0_usize..2) .into_iter() - .map(|idx| { - let core_idx = CoreIndex::from(idx as u32); - let ca = CoreAssignment { - paras_entry: ParasEntry::new( - Assignment::new(ParaId::from(1_u32 + idx as u32)), - entry_ttl, - ), - core: core_idx, - }; - ca - }) - .collect::>(); + .map(|idx| (ParaId::from(1_u32 + idx as u32), CoreIndex::from(idx as u32))) + .collect::>(); let group_validators = |group_index: GroupIndex| { match group_index { @@ -1304,7 +1290,7 @@ mod sanitizers { // nothing is scheduled, so no paraids match, thus all backed candidates are skipped { - let scheduled = &Vec::new(); + let scheduled = &BTreeMap::new(); assert!(sanitize_backed_candidates::( backed_candidates.clone(), has_concluded_invalid, diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs index bac1268f53b..46a609e0368 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs @@ -18,17 +18,17 @@ //! functions. use crate::{ - configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler, + disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, + scheduler::{self, CoreOccupied}, session_info, shared, }; use frame_system::pallet_prelude::*; use primitives::{ slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, - CoreIndex, CoreOccupied, CoreState, DisputeState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -52,29 +52,15 @@ pub fn validator_groups( /// Implementation for the `availability_cores` function of the runtime API. pub fn availability_cores() -> Vec>> { let cores = >::availability_cores(); - let config = >::config(); let now = >::block_number() + One::one(); - let rotation_info = >::group_rotation_info(now); - let time_out_at = |backed_in_number, availability_period| { - let time_out_at = backed_in_number + availability_period; - - let current_window = rotation_info.last_rotation_at() + availability_period; - let next_rotation = rotation_info.next_rotation_at(); - - // If we are within `period` blocks of rotation, timeouts are being checked - // actively. We could even time out this block. - if time_out_at < current_window { - time_out_at - } else if time_out_at <= next_rotation { - // Otherwise, it will time out at the sooner of the next rotation - next_rotation - } else { - // or the scheduled time-out. This is by definition within `period` blocks - // of `next_rotation` and is thus a valid timeout block. - time_out_at - } - }; + // This explicit update is only strictly required for session boundaries: + // + // At the end of a session we clear the claim queues: Without this update call, nothing would be + // scheduled to the client. + >::update_claimqueue(Vec::new(), now); + + let time_out_for = >::availability_timeout_predicate(); let group_responsible_for = |backed_in_number, core_index| match >::group_assigned_to_core( @@ -93,7 +79,9 @@ pub fn availability_cores() -> Vec = cores + let scheduled: BTreeMap<_, _> = >::scheduled_paras().collect(); + + cores .into_iter() .enumerate() .map(|(i, core)| match core { @@ -108,7 +96,7 @@ pub fn availability_cores() -> Vec>::next_up_on_time_out(CoreIndex( i as u32, )), @@ -121,19 +109,15 @@ pub fn availability_cores() -> Vec CoreState::Free, + CoreOccupied::Free => { + if let Some(para_id) = scheduled.get(&CoreIndex(i as _)).cloned() { + CoreState::Scheduled(primitives::ScheduledCore { para_id, collator: None }) + } else { + CoreState::Free + } + }, }) - .collect(); - - // This will overwrite only `Free` cores if the scheduler module is working as intended. - for scheduled in >::scheduled_claimqueue() { - core_states[scheduled.core.0 as usize] = CoreState::Scheduled(primitives::ScheduledCore { - para_id: scheduled.paras_entry.para_id(), - collator: None, - }); - } - - core_states + .collect() } /// Returns current block number being processed and the corresponding root hash. diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 577bcd153b5..60b2a925460 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -39,11 +39,11 @@ use crate::{configuration, initializer::SessionChangeNotification, paras}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; +pub use polkadot_core_primitives::v2::BlockNumber; use primitives::{ - v5::ParasEntry, CoreIndex, CoreOccupied, GroupIndex, GroupRotationInfo, Id as ParaId, - ScheduledCore, ValidatorIndex, + CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, ValidatorIndex, }; -use sp_runtime::traits::{One, Saturating}; +use sp_runtime::traits::One; use sp_std::{ collections::{btree_map::BTreeMap, vec_deque::VecDeque}, prelude::*, @@ -51,7 +51,7 @@ use sp_std::{ pub mod common; -use common::{AssignmentProvider, AssignmentProviderConfig, CoreAssignment, FreedReason}; +use common::{Assignment, AssignmentProvider, AssignmentProviderConfig}; pub use pallet::*; @@ -101,6 +101,36 @@ pub mod pallet { pub(crate) type AvailabilityCores = StorageValue<_, Vec>>, ValueQuery>; + /// Representation of a core in `AvailabilityCores`. + /// + /// This is not to be confused with `CoreState` which is an enriched variant of this and exposed + /// to the node side. It also provides information about scheduled/upcoming assignments for + /// example and is computed on the fly in the `availability_cores` runtime call. + #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub enum CoreOccupied { + /// No candidate is waiting availability on this core right now (the core is not occupied). + Free, + /// A para is currently waiting for availability/inclusion on this core. + Paras(ParasEntry), + } + + impl CoreOccupied { + /// Is core free? + pub fn is_free(&self) -> bool { + matches!(self, Self::Free) + } + } + + /// Reasons a core might be freed. + #[derive(Clone, Copy)] + pub enum FreedReason { + /// The core's work concluded and the parablock assigned to it is considered available. + Concluded, + /// The core's work timed out. + TimedOut, + } + /// The block number where the session start occurred. Used to track how many group rotations /// have occurred. /// @@ -124,6 +154,68 @@ pub mod pallet { BTreeMap>>>>, ValueQuery, >; + + /// Assignments as tracked in the claim queue. + #[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] + pub struct ParasEntry { + /// The underlying `Assignment` + pub assignment: Assignment, + /// The number of times the entry has timed out in availability already. + pub availability_timeouts: u32, + /// The block height until this entry needs to be backed. + /// + /// If missed the entry will be removed from the claim queue without ever having occupied + /// the core. + pub ttl: N, + } + + impl ParasEntry { + /// Return `Id` from the underlying `Assignment`. + pub fn para_id(&self) -> ParaId { + self.assignment.para_id + } + + /// Create a new `ParasEntry`. + pub fn new(assignment: Assignment, now: N) -> Self { + ParasEntry { assignment, availability_timeouts: 0, ttl: now } + } + } + + /// How a core is mapped to a backing group and a `ParaId` + #[derive(Clone, Encode, Decode, PartialEq, TypeInfo)] + #[cfg_attr(feature = "std", derive(Debug))] + pub struct CoreAssignment { + /// The core that is assigned. + pub core: CoreIndex, + /// The para id and accompanying information needed to collate and back a parablock. + pub paras_entry: ParasEntry, + } + + impl CoreAssignment { + /// Returns the [`ParaId`] of the assignment. + pub fn para_id(&self) -> ParaId { + self.paras_entry.para_id() + } + + /// Returns the inner [`ParasEntry`] of the assignment. + pub fn to_paras_entry(self) -> ParasEntry { + self.paras_entry + } + } + + /// Availability timeout status of a core. + pub(crate) struct AvailabilityTimeoutStatus { + /// Is the core already timed out? + /// + /// If this is true the core will be freed at this block. + pub timed_out: bool, + + /// When does this core timeout. + /// + /// The block number the core times out. If `timed_out` is true, this will correspond to + /// now (current block number). + pub live_until: BlockNumber, + } } type PositionInClaimqueue = u32; @@ -368,50 +460,47 @@ impl Pallet { Some(GroupIndex(group_idx as u32)) } - /// Returns an optional predicate that should be used for timing out occupied cores. - /// - /// If `None`, no timing-out should be done. The predicate accepts the index of the core, and - /// the block number since which it has been occupied, and the respective parachain timeouts, - /// i.e. only within `config.paras_availability_period` of the last rotation would this return - /// `Some`, unless there are no rotations. + /// Returns a predicate that should be used for timing out occupied cores. /// - /// The timeout used to depend, but does not depend any more on group rotations. First of all - /// it only matters if a para got another chance (a retry). If there is a retry and it happens - /// still within the same group rotation a censoring backing group would need to censor again - /// and lose out again on backing rewards. This is bad for the censoring backing group, it does - /// not matter for the parachain as long as it is retried often enough (so it eventually gets a - /// try on another backing group) - the effect is similar to having a prolonged timeout. It - /// should also be noted that for both malicious and offline backing groups it is actually more - /// realistic that the candidate will not be backed to begin with, instead of getting backed - /// and then not made available. + /// This only ever times out cores that have been occupied across a group rotation boundary. pub(crate) fn availability_timeout_predicate( - ) -> Option) -> bool> { - let now = >::block_number(); + ) -> impl Fn(BlockNumberFor) -> AvailabilityTimeoutStatus> { let config = >::config(); - let session_start = >::get(); + let now = >::block_number(); + let rotation_info = Self::group_rotation_info(now); - let blocks_since_session_start = now.saturating_sub(session_start); - let blocks_since_last_rotation = - blocks_since_session_start % config.group_rotation_frequency.max(1u8.into()); + let next_rotation = rotation_info.next_rotation_at(); - if blocks_since_last_rotation >= config.paras_availability_period { - None - } else { - Some(|core_index: CoreIndex, pending_since| { - let availability_cores = AvailabilityCores::::get(); - let AssignmentProviderConfig { availability_period, .. } = - T::AssignmentProvider::get_provider_config(core_index); - let now = >::block_number(); - match availability_cores.get(core_index.0 as usize) { - None => true, // out-of-bounds, doesn't really matter what is returned. - Some(CoreOccupied::Free) => true, // core free, still doesn't matter. - Some(CoreOccupied::Paras(_)) => - now.saturating_sub(pending_since) >= availability_period, - } - }) + let times_out = Self::availability_timeout_check_required(); + + move |pending_since| { + let time_out_at = if times_out { + // We are at the beginning of the rotation, here availability period is relevant. + // Note: blocks backed in this rotation will never time out here as backed_in + + // config.paras_availability_period will always be > now for these blocks, as + // otherwise above condition would not be true. + pending_since + config.paras_availability_period + } else { + next_rotation + config.paras_availability_period + }; + + AvailabilityTimeoutStatus { timed_out: time_out_at <= now, live_until: time_out_at } } } + /// Is evaluation of `availability_timeout_predicate` necessary at the current block? + /// + /// This can be used to avoid calling `availability_timeout_predicate` for each core in case + /// this function returns false. + pub(crate) fn availability_timeout_check_required() -> bool { + let config = >::config(); + let now = >::block_number() + One::one(); + let rotation_info = Self::group_rotation_info(now); + + let current_window = rotation_info.last_rotation_at() + config.paras_availability_period; + now < current_window + } + /// Returns a helper for determining group rotation. pub(crate) fn group_rotation_info( now: BlockNumberFor, @@ -508,7 +597,7 @@ impl Pallet { pub(crate) fn update_claimqueue( just_freed_cores: impl IntoIterator, now: BlockNumberFor, - ) -> Vec>> { + ) { Self::move_claimqueue_forward(); Self::free_cores_and_fill_claimqueue(just_freed_cores, now) } @@ -534,61 +623,58 @@ impl Pallet { fn free_cores_and_fill_claimqueue( just_freed_cores: impl IntoIterator, now: BlockNumberFor, - ) -> Vec>> { + ) { let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores); // This can only happen on new sessions at which we move all assignments back to the // provider. Hence, there's nothing we need to do here. if ValidatorGroups::::get().is_empty() { - vec![] - } else { - let n_lookahead = Self::claimqueue_lookahead(); - let n_session_cores = T::AssignmentProvider::session_core_count(); - let cq = ClaimQueue::::get(); - let ttl = >::config().on_demand_ttl; - - for core_idx in 0..n_session_cores { - let core_idx = CoreIndex::from(core_idx); - - // add previously timedout paras back into the queue - if let Some(mut entry) = timedout_paras.remove(&core_idx) { - let AssignmentProviderConfig { max_availability_timeouts, .. } = - T::AssignmentProvider::get_provider_config(core_idx); - if entry.availability_timeouts < max_availability_timeouts { - // Increment the timeout counter. - entry.availability_timeouts += 1; - // Reset the ttl so that a timed out assignment. - entry.ttl = now + ttl; - Self::add_to_claimqueue(core_idx, entry); - // The claim has been added back into the claimqueue. - // Do not pop another assignment for the core. - continue - } else { - // Consider timed out assignments for on demand parachains as concluded for - // the assignment provider - let ret = concluded_paras.insert(core_idx, entry.para_id()); - debug_assert!(ret.is_none()); - } + return + } + let n_lookahead = Self::claimqueue_lookahead(); + let n_session_cores = T::AssignmentProvider::session_core_count(); + let cq = ClaimQueue::::get(); + let ttl = >::config().on_demand_ttl; + + for core_idx in 0..n_session_cores { + let core_idx = CoreIndex::from(core_idx); + + // add previously timedout paras back into the queue + if let Some(mut entry) = timedout_paras.remove(&core_idx) { + let AssignmentProviderConfig { max_availability_timeouts, .. } = + T::AssignmentProvider::get_provider_config(core_idx); + if entry.availability_timeouts < max_availability_timeouts { + // Increment the timeout counter. + entry.availability_timeouts += 1; + // Reset the ttl so that a timed out assignment. + entry.ttl = now + ttl; + Self::add_to_claimqueue(core_idx, entry); + // The claim has been added back into the claimqueue. + // Do not pop another assignment for the core. + continue + } else { + // Consider timed out assignments for on demand parachains as concluded for + // the assignment provider + let ret = concluded_paras.insert(core_idx, entry.para_id()); + debug_assert!(ret.is_none()); } + } - // We consider occupied cores to be part of the claimqueue - let n_lookahead_used = cq.get(&core_idx).map_or(0, |v| v.len() as u32) + - if Self::is_core_occupied(core_idx) { 1 } else { 0 }; - for _ in n_lookahead_used..n_lookahead { - let concluded_para = concluded_paras.remove(&core_idx); - if let Some(assignment) = - T::AssignmentProvider::pop_assignment_for_core(core_idx, concluded_para) - { - Self::add_to_claimqueue(core_idx, ParasEntry::new(assignment, now + ttl)); - } + // We consider occupied cores to be part of the claimqueue + let n_lookahead_used = cq.get(&core_idx).map_or(0, |v| v.len() as u32) + + if Self::is_core_occupied(core_idx) { 1 } else { 0 }; + for _ in n_lookahead_used..n_lookahead { + let concluded_para = concluded_paras.remove(&core_idx); + if let Some(assignment) = + T::AssignmentProvider::pop_assignment_for_core(core_idx, concluded_para) + { + Self::add_to_claimqueue(core_idx, ParasEntry::new(assignment, now + ttl)); } } - - debug_assert!(timedout_paras.is_empty()); - debug_assert!(concluded_paras.is_empty()); - - Self::scheduled_claimqueue() } + + debug_assert!(timedout_paras.is_empty()); + debug_assert!(concluded_paras.is_empty()); } fn is_core_occupied(core_idx: CoreIndex) -> bool { @@ -623,29 +709,22 @@ impl Pallet { .ok_or("remove returned None")? .ok_or("Element in Claimqueue was None.")?; - // Since the core is now occupied, the next entry in the claimqueue in order to achieve - // 12 second block times needs to be None - if core_claims.front() != Some(&None) { - core_claims.push_front(None); - } Ok((pos as u32, pe)) }) } - // TODO: Temporary to imitate the old schedule() call. Will be adjusted when we make the - // scheduler AB ready - pub(crate) fn scheduled_claimqueue() -> Vec>> { + /// Paras scheduled next in the claim queue. + pub(crate) fn scheduled_paras() -> impl Iterator { + Self::scheduled_entries().map(|(core_idx, e)| (core_idx, e.assignment.para_id)) + } + + /// Internal access to entries at the top of the claim queue. + fn scheduled_entries() -> impl Iterator>)> { let claimqueue = ClaimQueue::::get(); claimqueue .into_iter() - .flat_map(|(core_idx, v)| { - v.front() - .cloned() - .flatten() - .map(|pe| CoreAssignment { core: core_idx, paras_entry: pe }) - }) - .collect() + .filter_map(|(core_idx, v)| v.front().cloned().flatten().map(|e| (core_idx, e))) } #[cfg(any(feature = "runtime-benchmarks", test))] diff --git a/polkadot/runtime/parachains/src/scheduler/common.rs b/polkadot/runtime/parachains/src/scheduler/common.rs index 0e8e8338b17..316e8e3b760 100644 --- a/polkadot/runtime/parachains/src/scheduler/common.rs +++ b/polkadot/runtime/parachains/src/scheduler/common.rs @@ -17,10 +17,7 @@ //! Common traits and types used by the scheduler and assignment providers. use frame_support::pallet_prelude::*; -use primitives::{ - v5::{Assignment, ParasEntry}, - CoreIndex, Id as ParaId, -}; +use primitives::{CoreIndex, Id as ParaId}; use scale_info::TypeInfo; use sp_std::prelude::*; @@ -28,21 +25,22 @@ use sp_std::prelude::*; #[allow(unused)] use crate::configuration::HostConfiguration; -/// Reasons a core might be freed -#[derive(Clone, Copy)] -pub enum FreedReason { - /// The core's work concluded and the parablock assigned to it is considered available. - Concluded, - /// The core's work timed out. - TimedOut, +/// An assignment for a parachain scheduled to be backed and included in a relay chain block. +#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebug)] +pub struct Assignment { + /// Assignment's ParaId + pub para_id: ParaId, +} + +impl Assignment { + /// Create a new `Assignment`. + pub fn new(para_id: ParaId) -> Self { + Self { para_id } + } } /// A set of variables required by the scheduler in order to operate. pub struct AssignmentProviderConfig { - /// The availability period specified by the implementation. - /// See [`HostConfiguration::paras_availability_period`] for more information. - pub availability_period: BlockNumber, - /// How many times a collation can time out on availability. /// Zero timeouts still means that a collation can be provided as per the slot auction /// assignment provider. @@ -72,25 +70,3 @@ pub trait AssignmentProvider { /// Returns a set of variables needed by the scheduler fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig; } - -/// How a core is mapped to a backing group and a `ParaId` -#[derive(Clone, Encode, Decode, PartialEq, TypeInfo)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct CoreAssignment { - /// The core that is assigned. - pub core: CoreIndex, - /// The para id and accompanying information needed to collate and back a parablock. - pub paras_entry: ParasEntry, -} - -impl CoreAssignment { - /// Returns the [`ParaId`] of the assignment. - pub fn para_id(&self) -> ParaId { - self.paras_entry.para_id() - } - - /// Returns the inner [`ParasEntry`] of the assignment. - pub fn to_paras_entry(self) -> ParasEntry { - self.paras_entry - } -} diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index 32ac9deaf68..accff7016ed 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -20,7 +20,6 @@ use super::*; use frame_support::{ pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, }; -use primitives::vstaging::Assignment; mod v0 { use super::*; diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index e203531ca49..108f365d6b5 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -18,7 +18,7 @@ use super::*; use frame_support::assert_ok; use keyring::Sr25519Keyring; -use primitives::{v5::Assignment, BlockNumber, SessionIndex, ValidationCode, ValidatorId}; +use primitives::{BlockNumber, SessionIndex, ValidationCode, ValidatorId}; use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::{ @@ -427,33 +427,27 @@ fn fill_claimqueue_fills() { { assert_eq!(Scheduler::claimqueue_len(), 2 * lookahead); - let scheduled = Scheduler::scheduled_claimqueue(); + let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect(); // Cannot assert on indices anymore as they depend on the assignment providers assert!(claimqueue_contains_para_ids::(vec![chain_a, chain_b])); assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_a }, - availability_timeouts: 0, - ttl: 6 - }, - } + scheduled.get(&CoreIndex(0)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 6 + }, ); assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(1), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_b }, - availability_timeouts: 0, - ttl: 6 - }, - } + scheduled.get(&CoreIndex(1)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: chain_b }, + availability_timeouts: 0, + ttl: 6 + }, ); } @@ -481,42 +475,33 @@ fn fill_claimqueue_fills() { { assert_eq!(Scheduler::claimqueue_len(), 5); - let scheduled = Scheduler::scheduled_claimqueue(); + let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect(); assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_a }, - availability_timeouts: 0, - ttl: 6 - }, - } + scheduled.get(&CoreIndex(0)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 6 + }, ); assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(1), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_b }, - availability_timeouts: 0, - ttl: 6 - }, - } + scheduled.get(&CoreIndex(1)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: chain_b }, + availability_timeouts: 0, + ttl: 6 + }, ); // Was added a block later, note the TTL. assert_eq!( - scheduled[2], - CoreAssignment { - core: CoreIndex(2), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_a }, - availability_timeouts: 0, - ttl: 7 - }, - } + scheduled.get(&CoreIndex(2)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_a }, + availability_timeouts: 0, + ttl: 7 + }, ); // Sits on the same core as `thread_a` assert_eq!( @@ -528,15 +513,12 @@ fn fill_claimqueue_fills() { }) ); assert_eq!( - scheduled[3], - CoreAssignment { - core: CoreIndex(3), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_c }, - availability_timeouts: 0, - ttl: 7 - }, - } + scheduled.get(&CoreIndex(3)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_c }, + availability_timeouts: 0, + ttl: 7 + }, ); } }); @@ -608,7 +590,7 @@ fn schedule_schedules_including_just_freed() { let mut now = 2; run_to_block(now, |_| None); - assert_eq!(Scheduler::scheduled_claimqueue().len(), 4); + assert_eq!(Scheduler::scheduled_paras().collect::>().len(), 4); // cores 0, 1, 2, and 3 should be occupied. mark them as such. let mut occupied_map: BTreeMap = BTreeMap::new(); @@ -630,7 +612,7 @@ fn schedule_schedules_including_just_freed() { // core 4 is free assert!(cores[4] == CoreOccupied::Free); - assert!(Scheduler::scheduled_claimqueue().is_empty()); + assert!(Scheduler::scheduled_paras().collect::>().is_empty()); // All core index entries in the claimqueue should have `None` in them. Scheduler::claimqueue().iter().for_each(|(_core_idx, core_queue)| { @@ -657,21 +639,18 @@ fn schedule_schedules_including_just_freed() { run_to_block(now, |_| None); { - let scheduled = Scheduler::scheduled_claimqueue(); + let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect(); // cores 0 and 1 are occupied by lease holding parachains. cores 2 and 3 are occupied by // on-demand parachain claims. core 4 was free. assert_eq!(scheduled.len(), 1); assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(4), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_b }, - availability_timeouts: 0, - ttl: 8 - }, - } + scheduled.get(&CoreIndex(4)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 8 + }, ); } @@ -686,54 +665,42 @@ fn schedule_schedules_including_just_freed() { Scheduler::update_claimqueue(just_updated, now); { - let scheduled = Scheduler::scheduled_claimqueue(); + let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect(); // 1 thing scheduled before, + 3 cores freed. assert_eq!(scheduled.len(), 4); assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - paras_entry: ParasEntry { - assignment: Assignment { para_id: chain_a }, - availability_timeouts: 0, - ttl: 8 - }, - } + scheduled.get(&CoreIndex(0)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 8 + }, ); assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(2), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_d }, - availability_timeouts: 0, - ttl: 8 - }, - } + scheduled.get(&CoreIndex(2)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_d }, + availability_timeouts: 0, + ttl: 8 + }, ); // Although C was descheduled, the core `4` was occupied so C goes back to the queue. assert_eq!( - scheduled[2], - CoreAssignment { - core: CoreIndex(3), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_c }, - availability_timeouts: 1, - ttl: 8 - }, - } + scheduled.get(&CoreIndex(3)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_c }, + availability_timeouts: 1, + ttl: 8 + }, ); assert_eq!( - scheduled[3], - CoreAssignment { - core: CoreIndex(4), - paras_entry: ParasEntry { - assignment: Assignment { para_id: thread_b }, - availability_timeouts: 0, - ttl: 8 - }, - } + scheduled.get(&CoreIndex(4)).unwrap(), + &ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 8 + }, ); // The only assignment yet to be popped on to the claim queue is `thread_e`. @@ -900,14 +867,14 @@ fn schedule_rotates_groups() { run_to_block(now, |_| None); let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor| { - let scheduled = Scheduler::scheduled_claimqueue(); + let scheduled: BTreeMap<_, _> = Scheduler::scheduled_paras().collect(); assert_eq!(scheduled.len(), 2); assert_eq!( - Scheduler::group_assigned_to_core(scheduled[0].core, *now).unwrap(), + Scheduler::group_assigned_to_core(CoreIndex(0), *now).unwrap(), GroupIndex((0u32 + rotations) % on_demand_cores) ); assert_eq!( - Scheduler::group_assigned_to_core(scheduled[1].core, *now).unwrap(), + Scheduler::group_assigned_to_core(CoreIndex(1), *now).unwrap(), GroupIndex((1u32 + rotations) % on_demand_cores) ); }; @@ -999,7 +966,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { ] .into_iter() .collect(); - let core_assignments = Scheduler::update_claimqueue(just_updated, now); + Scheduler::update_claimqueue(just_updated, now); // ParaId a exists in the claim queue until max_retries is reached. if n < max_retries + now { @@ -1008,13 +975,9 @@ fn on_demand_claims_are_pruned_after_timing_out() { assert!(!claimqueue_contains_para_ids::(vec![thread_a])); } - // Occupy the cores based on the output of update_claimqueue. - Scheduler::occupied( - core_assignments - .iter() - .map(|core_assignment| (core_assignment.core, core_assignment.para_id())) - .collect(), - ); + let core_assignments = Scheduler::scheduled_paras().collect(); + // Occupy the cores based on the result of update_claimqueue. + Scheduler::occupied(core_assignments); } // ParaId a does not exist in the claimqueue/availability_cores after @@ -1054,7 +1017,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { } } - let core_assignments = Scheduler::update_claimqueue(just_updated, now); + Scheduler::update_claimqueue(just_updated, now); // ParaId a exists in the claim queue until groups are rotated. if n < 31 { @@ -1063,13 +1026,9 @@ fn on_demand_claims_are_pruned_after_timing_out() { assert!(!claimqueue_contains_para_ids::(vec![thread_a])); } - // Occupy the cores based on the output of update_claimqueue. - Scheduler::occupied( - core_assignments - .iter() - .map(|core_assignment| (core_assignment.core, core_assignment.para_id())) - .collect(), - ); + let core_assignments = Scheduler::scheduled_paras().collect(); + // Occupy the cores based on the result of update_claimqueue. + Scheduler::occupied(core_assignments); } // ParaId a does not exist in the claimqueue/availability_cores after @@ -1124,33 +1083,25 @@ fn availability_predicate_works() { run_to_block(1 + paras_availability_period, |_| None); - assert!(Scheduler::availability_timeout_predicate().is_none()); + assert!(!Scheduler::availability_timeout_check_required()); run_to_block(1 + group_rotation_frequency, |_| None); { - let pred = Scheduler::availability_timeout_predicate() - .expect("predicate exists recently after rotation"); - let now = System::block_number(); - let would_be_timed_out = now - paras_availability_period; - for i in 0..AvailabilityCores::::get().len() { - // returns true for unoccupied cores. - // And can time out paras at this stage. - assert!(pred(CoreIndex(i as u32), would_be_timed_out)); - } + assert!(Scheduler::availability_timeout_check_required()); + let pred = Scheduler::availability_timeout_predicate(); + let last_rotation = Scheduler::group_rotation_info(now).last_rotation_at(); - assert!(!pred(CoreIndex(0), now)); - assert!(!pred(CoreIndex(1), now)); - assert!(pred(CoreIndex(2), now)); + let would_be_timed_out = now - paras_availability_period; + let should_not_be_timed_out = last_rotation; - // check the tight bound. - assert!(pred(CoreIndex(0), now - paras_availability_period)); - assert!(pred(CoreIndex(1), now - paras_availability_period)); + assert!(pred(would_be_timed_out).timed_out); + assert!(!pred(should_not_be_timed_out).timed_out); + assert!(!pred(now).timed_out); // check the threshold is exact. - assert!(!pred(CoreIndex(0), now - paras_availability_period + 1)); - assert!(!pred(CoreIndex(1), now - paras_availability_period + 1)); + assert!(!pred(would_be_timed_out + 1).timed_out); } run_to_block(1 + group_rotation_frequency + paras_availability_period, |_| None); -- GitLab From 0090152386c32740b223e7c1aea76cb3df013332 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 6 Sep 2023 19:34:41 +0200 Subject: [PATCH 092/633] Prevent a fail prdoc check to block (#1433) --- .github/workflows/check-prdoc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index 219952fdbfb..323be1d4e06 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -48,4 +48,4 @@ jobs: if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} run: | echo "Checking for PR#${GITHUB_PR} in $MOUNT" - $ENGINE run --rm -v $PWD/prdoc:/doc $IMAGE check -n ${GITHUB_PR} + $ENGINE run --rm -v $PWD/prdoc:/doc $IMAGE check -n ${GITHUB_PR} || true -- GitLab From a47943983f18ce00ceab3052bf2f9a2c62f80327 Mon Sep 17 00:00:00 2001 From: ordian Date: Wed, 6 Sep 2023 20:39:42 +0200 Subject: [PATCH 093/633] zombienet: use another collator image for the slashing test (#1386) * zombienet: use test-parachain image for the slashing test * use the right image * try polkadot-parachain image * try naming collator alice :see_no_evil: * add needed job for the pipeline * fix user id in polkadot-parachain-debug image * small tweaks to the test * another small tweak * yet another small tweak * bump zombienet version --------- Co-authored-by: Javier Viola --- .gitlab-ci.yml | 2 +- .gitlab/pipeline/zombienet/polkadot.yml | 4 ++++ .../polkadot-parachain-debug_unsigned_injected.Dockerfile | 2 +- .../functional/0005-parachains-disputes-past-session.toml | 7 +++---- .../functional/0005-parachains-disputes-past-session.zndsl | 6 +++--- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e0465ba1eb..748db808de6 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.65" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.67" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 87b821742c6..349807a610d 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -9,6 +9,7 @@ - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} + - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" - export MALUS_IMAGE="${MALUS_IMAGE}":${PIPELINE_IMAGE_TAG} - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" @@ -16,6 +17,7 @@ - echo "polkadot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - echo "polkadot secondary image ${ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}" - echo "colander image ${COL_IMAGE}" + - echo "cumulus image ${CUMULUS_IMAGE}" - echo "malus image ${MALUS_IMAGE}" stage: zombienet image: "${ZOMBIENET_IMAGE}" @@ -28,6 +30,8 @@ artifacts: true - job: build-push-image-colander artifacts: true + - job: build-push-image-polkadot-parachain-debug + artifacts: true extends: - .kubernetes-env - .zombienet-refs 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 7a2202d9c52..75cc2b9e629 100644 --- a/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && \ apt-get clean && \ find /var/lib/apt/lists/ -type f -not -name lock -delete; \ # add user and link ~/.local/share/polkadot-parachain to /data - useradd -m -u 10000 -U -s /bin/sh -d /polkadot-parachain polkadot-parachain && \ + useradd -m -u 1000 -U -s /bin/sh -d /polkadot-parachain polkadot-parachain && \ mkdir -p /data /polkadot-parachain/.local/share && \ chown -R polkadot-parachain:polkadot-parachain /data && \ ln -s /data /polkadot-parachain/.local/share/polkadot-parachain && \ diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml index 50c465950f7..25d922bb682 100644 --- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml +++ b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml @@ -5,7 +5,7 @@ bootnode = true [relaychain.genesis.runtime.configuration.config] max_validators_per_core = 1 needed_approvals = 2 - group_rotation_frequency = 3 + group_rotation_frequency = 2 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" @@ -39,8 +39,7 @@ id = 1000 cumulus_based = true [parachains.collator] - name = "collator" + name = "alice" command = "polkadot-parachain" - image = "docker.io/parity/polkadot-parachain:latest" - # image = "{{COL_IMAGE}}" + image = "{{CUMULUS_IMAGE}}" args = ["-lparachain=debug"] diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl index bc3674f4f53..a3f1f0669ac 100644 --- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl +++ b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl @@ -21,18 +21,18 @@ malus-validator: resume malus-validator: log line matches "Suggesting malicious candidate" within 200 seconds # Pause first flaky node -# Availability and finality will continue with 3/4 nodes online (incl. malus) +# Availability will continue with 3/4 nodes online (incl. malus) honest-flaky-validator-0: pause # Wait for the dispute -honest-flaky-validator-1: reports parachain_candidate_disputes_total is at least 1 within 40 seconds +honest-flaky-validator-1: reports parachain_candidate_disputes_total is at least 1 within 60 seconds # Pause second flaky node so that we do not revert blocks due to f+1 invalid votes # Availability and finality will stop honest-flaky-validator-1: pause # Wait for 1 full session to pass after the last unconcluded dispute. -sleep 120 seconds +sleep 110 seconds # Now resume flaky validators honest-flaky-validator: resume -- GitLab From 91deee7a1dba52e5e73d1a97d9fd5b8ad1e916a4 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Thu, 7 Sep 2023 08:05:31 +0530 Subject: [PATCH 094/633] Adds base benchmark for do_tick in broker pallet (#1235) * Adds base benchmark for do_tick * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_broker * Update substrate/frame/broker/src/benchmarking.rs Co-authored-by: Oliver Tale-Yazdi * Update substrate/frame/broker/src/benchmarking.rs * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_broker * Addresses review comment --------- Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi --- substrate/frame/broker/src/benchmarking.rs | 21 ++ substrate/frame/broker/src/tick_impls.rs | 7 +- substrate/frame/broker/src/weights.rs | 367 ++++++++++++--------- 3 files changed, 239 insertions(+), 156 deletions(-) diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 663bf2f466c..d22f3936c3e 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -852,6 +852,27 @@ mod benches { } } + #[benchmark] + fn do_tick_base() -> Result<(), BenchmarkError> { + setup_and_start_sale::()?; + + advance_to::(5); + + let mut status = Status::::get().unwrap(); + status.last_committed_timeslice = 3; + Status::::put(&status); + + #[block] + { + Broker::::do_tick(); + } + + let updated_status = Status::::get().unwrap(); + assert_eq!(status, updated_status); + + Ok(()) + } + // Implements a test for each benchmark. Execute with: // `cargo test -p pallet-broker --features runtime-benchmarks`. impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index a1a50a61908..7df8bd39d42 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -36,13 +36,14 @@ impl Pallet { /// - Request revenue information for a previous timeslice /// - Initialize an instantaneous core pool historical revenue record pub(crate) fn do_tick() -> Weight { + let mut meter = WeightMeter::new(); + meter.consume(T::WeightInfo::do_tick_base()); + let (mut status, config) = match (Status::::get(), Configuration::::get()) { (Some(s), Some(c)) => (s, c), - _ => return Weight::zero(), + _ => return meter.consumed(), }; - let mut meter = WeightMeter::new(); - if Self::process_core_count(&mut status) { meter.consume(T::WeightInfo::process_core_count(status.core_count.into())); } diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs index 93b568bf2a0..b3a151c6062 100644 --- a/substrate/frame/broker/src/weights.rs +++ b/substrate/frame/broker/src/weights.rs @@ -18,10 +18,10 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-pzhd7p6z-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: // target/production/substrate-node @@ -32,12 +32,12 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_broker // --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/broker/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/broker/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,6 +74,7 @@ pub trait WeightInfo { fn process_pool() -> Weight; fn process_core_schedule() -> Weight; fn request_revenue_info_at() -> Weight; + fn do_tick_base() -> Weight; } /// Weights for `pallet_broker` using the Substrate node and recommended hardware. @@ -85,8 +86,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_448_000 picoseconds. - Weight::from_parts(3_729_000, 0) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_344_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -95,8 +96,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 22_537_000 picoseconds. - Weight::from_parts(23_335_000, 7496) + // Minimum execution time: 21_259_000 picoseconds. + Weight::from_parts(22_110_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -106,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 21_668_000 picoseconds. - Weight::from_parts(22_442_000, 7496) + // Minimum execution time: 20_330_000 picoseconds. + Weight::from_parts(20_826_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -117,8 +118,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_606_000 picoseconds. - Weight::from_parts(14_104_000, 1526) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(13_960_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -137,12 +138,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(_n: u32, ) -> Weight { + fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 64_012_000 picoseconds. - Weight::from_parts(67_819_922, 8499) + // Minimum execution time: 57_770_000 picoseconds. + Weight::from_parts(61_047_512, 8499) + // Standard Error: 165 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) } @@ -160,8 +163,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `568` // Estimated: `2053` - // Minimum execution time: 48_110_000 picoseconds. - Weight::from_parts(49_234_000, 2053) + // Minimum execution time: 51_196_000 picoseconds. + Weight::from_parts(52_382_000, 2053) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -183,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `686` // Estimated: `4698` - // Minimum execution time: 69_580_000 picoseconds. - Weight::from_parts(70_914_000, 4698) + // Minimum execution time: 71_636_000 picoseconds. + Weight::from_parts(73_679_000, 4698) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -194,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 17_687_000 picoseconds. - Weight::from_parts(18_573_000, 3550) + // Minimum execution time: 19_182_000 picoseconds. + Weight::from_parts(19_775_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -205,8 +208,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_675_000 picoseconds. - Weight::from_parts(20_234_000, 3550) + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(21_557_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -216,8 +219,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_426_000 picoseconds. - Weight::from_parts(20_414_000, 3550) + // Minimum execution time: 21_190_000 picoseconds. + Weight::from_parts(22_215_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -233,8 +236,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 31_751_000 picoseconds. - Weight::from_parts(32_966_000, 4681) + // Minimum execution time: 34_591_000 picoseconds. + Weight::from_parts(36_227_000, 4681) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -252,8 +255,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 36_709_000 picoseconds. - Weight::from_parts(38_930_000, 5996) + // Minimum execution time: 40_346_000 picoseconds. + Weight::from_parts(41_951_000, 5996) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -261,20 +264,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:3 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:0) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `m` is `[1, 3]`. fn claim_revenue(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 55_510_000 picoseconds. - Weight::from_parts(56_665_061, 6196) - // Standard Error: 61_729 - .saturating_add(Weight::from_parts(1_724_824, 0).saturating_mul(m.into())) + // Minimum execution time: 75_734_000 picoseconds. + Weight::from_parts(78_168_395, 6196) + // Standard Error: 63_180 + .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(m.into())) } /// Storage: `System::Account` (r:1 w:1) @@ -283,8 +286,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 44_992_000 picoseconds. - Weight::from_parts(46_225_000, 3593) + // Minimum execution time: 46_383_000 picoseconds. + Weight::from_parts(47_405_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -296,8 +299,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 28_207_000 picoseconds. - Weight::from_parts(28_707_000, 3550) + // Minimum execution time: 30_994_000 picoseconds. + Weight::from_parts(31_979_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -311,8 +314,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 31_813_000 picoseconds. - Weight::from_parts(32_612_000, 3533) + // Minimum execution time: 37_584_000 picoseconds. + Weight::from_parts(44_010_000, 3533) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -326,10 +329,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `829` + // Measured: `830` // Estimated: `3593` - // Minimum execution time: 38_571_000 picoseconds. - Weight::from_parts(39_493_000, 3593) + // Minimum execution time: 45_266_000 picoseconds. + Weight::from_parts(48_000_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -341,42 +344,53 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `525` // Estimated: `4698` - // Minimum execution time: 24_714_000 picoseconds. - Weight::from_parts(25_288_000, 4698) + // Minimum execution time: 25_365_000 picoseconds. + Weight::from_parts(26_920_000, 4698) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:0 w:1) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_258_000 picoseconds. - Weight::from_parts(7_925_570, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 6_519_000 picoseconds. + Weight::from_parts(7_098_698, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// The range of component `n` is `[0, 1000]`. - fn process_core_count(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `97` - // Estimated: `3562` - // Minimum execution time: 7_136_000 picoseconds. - Weight::from_parts(7_788_194, 3562) + fn process_core_count(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `98` + // Estimated: `3563` + // Minimum execution time: 7_608_000 picoseconds. + Weight::from_parts(8_157_815, 3563) + // Standard Error: 26 + .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Broker::InstaPoolHistory` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_049_000 picoseconds. - Weight::from_parts(6_311_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `905` + // Estimated: `4370` + // Minimum execution time: 59_993_000 picoseconds. + Weight::from_parts(61_752_000, 4370) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -393,10 +407,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 47_504_000 picoseconds. - Weight::from_parts(49_778_098, 8499) - // Standard Error: 109 - .saturating_add(Weight::from_parts(427, 0).saturating_mul(n.into())) + // Minimum execution time: 41_863_000 picoseconds. + Weight::from_parts(44_033_031, 8499) + // Standard Error: 116 + .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -408,8 +422,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_573_000 picoseconds. - Weight::from_parts(10_034_000, 3493) + // Minimum execution time: 9_588_000 picoseconds. + Weight::from_parts(9_925_000, 3493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -421,8 +435,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 21_331_000 picoseconds. - Weight::from_parts(22_235_000, 4681) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_482_000, 4681) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -430,8 +444,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 191_000 picoseconds. - Weight::from_parts(234_000, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(184_000, 0) + } + /// Storage: `Broker::Status` (r:1 w:1) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + fn do_tick_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `699` + // Estimated: `4164` + // Minimum execution time: 19_824_000 picoseconds. + Weight::from_parts(20_983_000, 4164) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } } @@ -443,8 +474,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_448_000 picoseconds. - Weight::from_parts(3_729_000, 0) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_344_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -453,8 +484,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 22_537_000 picoseconds. - Weight::from_parts(23_335_000, 7496) + // Minimum execution time: 21_259_000 picoseconds. + Weight::from_parts(22_110_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -464,8 +495,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 21_668_000 picoseconds. - Weight::from_parts(22_442_000, 7496) + // Minimum execution time: 20_330_000 picoseconds. + Weight::from_parts(20_826_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -475,8 +506,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_606_000 picoseconds. - Weight::from_parts(14_104_000, 1526) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(13_960_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -495,12 +526,14 @@ impl WeightInfo for () { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(_n: u32, ) -> Weight { + fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 64_012_000 picoseconds. - Weight::from_parts(67_819_922, 8499) + // Minimum execution time: 57_770_000 picoseconds. + Weight::from_parts(61_047_512, 8499) + // Standard Error: 165 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) } @@ -518,8 +551,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `568` // Estimated: `2053` - // Minimum execution time: 48_110_000 picoseconds. - Weight::from_parts(49_234_000, 2053) + // Minimum execution time: 51_196_000 picoseconds. + Weight::from_parts(52_382_000, 2053) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -541,8 +574,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `686` // Estimated: `4698` - // Minimum execution time: 69_580_000 picoseconds. - Weight::from_parts(70_914_000, 4698) + // Minimum execution time: 71_636_000 picoseconds. + Weight::from_parts(73_679_000, 4698) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -552,8 +585,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 17_687_000 picoseconds. - Weight::from_parts(18_573_000, 3550) + // Minimum execution time: 19_182_000 picoseconds. + Weight::from_parts(19_775_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -563,8 +596,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_675_000 picoseconds. - Weight::from_parts(20_234_000, 3550) + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(21_557_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -574,8 +607,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_426_000 picoseconds. - Weight::from_parts(20_414_000, 3550) + // Minimum execution time: 21_190_000 picoseconds. + Weight::from_parts(22_215_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -591,8 +624,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 31_751_000 picoseconds. - Weight::from_parts(32_966_000, 4681) + // Minimum execution time: 34_591_000 picoseconds. + Weight::from_parts(36_227_000, 4681) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -610,8 +643,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 36_709_000 picoseconds. - Weight::from_parts(38_930_000, 5996) + // Minimum execution time: 40_346_000 picoseconds. + Weight::from_parts(41_951_000, 5996) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -619,20 +652,20 @@ impl WeightInfo for () { /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:3 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:0) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `m` is `[1, 3]`. fn claim_revenue(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 55_510_000 picoseconds. - Weight::from_parts(56_665_061, 6196) - // Standard Error: 61_729 - .saturating_add(Weight::from_parts(1_724_824, 0).saturating_mul(m.into())) + // Minimum execution time: 75_734_000 picoseconds. + Weight::from_parts(78_168_395, 6196) + // Standard Error: 63_180 + .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(m.into())) } /// Storage: `System::Account` (r:1 w:1) @@ -641,8 +674,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 44_992_000 picoseconds. - Weight::from_parts(46_225_000, 3593) + // Minimum execution time: 46_383_000 picoseconds. + Weight::from_parts(47_405_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -654,8 +687,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 28_207_000 picoseconds. - Weight::from_parts(28_707_000, 3550) + // Minimum execution time: 30_994_000 picoseconds. + Weight::from_parts(31_979_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -669,8 +702,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 31_813_000 picoseconds. - Weight::from_parts(32_612_000, 3533) + // Minimum execution time: 37_584_000 picoseconds. + Weight::from_parts(44_010_000, 3533) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -684,10 +717,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `829` + // Measured: `830` // Estimated: `3593` - // Minimum execution time: 38_571_000 picoseconds. - Weight::from_parts(39_493_000, 3593) + // Minimum execution time: 45_266_000 picoseconds. + Weight::from_parts(48_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -699,42 +732,53 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `525` // Estimated: `4698` - // Minimum execution time: 24_714_000 picoseconds. - Weight::from_parts(25_288_000, 4698) + // Minimum execution time: 25_365_000 picoseconds. + Weight::from_parts(26_920_000, 4698) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:0 w:1) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_258_000 picoseconds. - Weight::from_parts(7_925_570, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 6_519_000 picoseconds. + Weight::from_parts(7_098_698, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// The range of component `n` is `[0, 1000]`. - fn process_core_count(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `97` - // Estimated: `3562` - // Minimum execution time: 7_136_000 picoseconds. - Weight::from_parts(7_788_194, 3562) + fn process_core_count(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `98` + // Estimated: `3563` + // Minimum execution time: 7_608_000 picoseconds. + Weight::from_parts(8_157_815, 3563) + // Standard Error: 26 + .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Broker::InstaPoolHistory` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_049_000 picoseconds. - Weight::from_parts(6_311_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `905` + // Estimated: `4370` + // Minimum execution time: 59_993_000 picoseconds. + Weight::from_parts(61_752_000, 4370) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -751,10 +795,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 47_504_000 picoseconds. - Weight::from_parts(49_778_098, 8499) - // Standard Error: 109 - .saturating_add(Weight::from_parts(427, 0).saturating_mul(n.into())) + // Minimum execution time: 41_863_000 picoseconds. + Weight::from_parts(44_033_031, 8499) + // Standard Error: 116 + .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -766,8 +810,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_573_000 picoseconds. - Weight::from_parts(10_034_000, 3493) + // Minimum execution time: 9_588_000 picoseconds. + Weight::from_parts(9_925_000, 3493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -779,8 +823,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 21_331_000 picoseconds. - Weight::from_parts(22_235_000, 4681) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_482_000, 4681) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -788,7 +832,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 191_000 picoseconds. - Weight::from_parts(234_000, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(184_000, 0) + } + /// Storage: `Broker::Status` (r:1 w:1) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + fn do_tick_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `699` + // Estimated: `4164` + // Minimum execution time: 19_824_000 picoseconds. + Weight::from_parts(20_983_000, 4164) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } } -- GitLab From bf5d0e2847d81d8785a6547bfcc4b6efac4c4757 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 7 Sep 2023 10:34:53 +0200 Subject: [PATCH 095/633] Forgotten `polkadot-core-primitives/std` (#1440) * Forgotten `polkadot-core-primitives/std` * Reorder --- polkadot/runtime/parachains/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 77eba0bc10b..550c0ef7534 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -84,6 +84,7 @@ std = [ "pallet-timestamp/std", "pallet-vesting/std", "parity-scale-codec/std", + "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-metrics/std", "primitives/std", -- GitLab From bd23c8d9d7a6f4ac6eda77328642f678dadd5f92 Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 7 Sep 2023 17:01:55 +0800 Subject: [PATCH 096/633] remove unused `keystore_uri` (#1421) --- substrate/client/cli/src/params/keystore_params.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/substrate/client/cli/src/params/keystore_params.rs b/substrate/client/cli/src/params/keystore_params.rs index a2fdd6b2218..87210c3390c 100644 --- a/substrate/client/cli/src/params/keystore_params.rs +++ b/substrate/client/cli/src/params/keystore_params.rs @@ -31,10 +31,6 @@ const DEFAULT_KEYSTORE_CONFIG_PATH: &str = "keystore"; /// Parameters of the keystore #[derive(Debug, Clone, Args)] pub struct KeystoreParams { - /// Specify custom URIs to connect to for keystore-services - #[arg(long)] - pub keystore_uri: Option, - /// Specify custom keystore path. #[arg(long, value_name = "PATH")] pub keystore_path: Option, -- GitLab From 1346143194a48032ded51b5e3022c2dc3a8001ae Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 7 Sep 2023 11:31:18 +0200 Subject: [PATCH 097/633] [ci] Enable flacky collector for tests (#1439) --- .github/pr-custom-review.yml | 2 +- .gitlab/pipeline/test.yml | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index d37ea4cf095..0d691e7aa2f 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -19,7 +19,7 @@ rules: 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|^(?!.*\.dic$|.*spellcheck\.toml$)scripts/ci/.*|^\.github/.* + 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$|^\.github/.* min_approvals: 2 teams: - core-devs diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index d128cb09902..cbb5a023272 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -36,9 +36,23 @@ test-linux-stable: --no-fail-fast \ --features try-runtime,experimental \ --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + # Upload tests results to Elasticsearch + - echo "Upload test results to Elasticsearch" + - cat target/nextest/default/junit.xml | xq . > target/nextest/default/junit.json + - | + curl -v -XPOST --http1.1 \ + -u ${ELASTIC_USERNAME}:${ELASTIC_PASSWORD} \ + https://elasticsearch.parity-build.parity.io/unit-tests/_doc/${CI_JOB_ID} \ + -H 'Content-Type: application/json' \ + -d @target/nextest/default/junit.json || echo "failed to upload junit report" # run runtime-api tests with `enable-staging-api` feature on the 1st node - if [ ${CI_NODE_INDEX} == 1 ]; then time cargo nextest run -p sp-api-test --features enable-staging-api; fi - # todo: add flacky-test collector + artifacts: + when: always + paths: + - target/nextest/default/junit.xml + reports: + junit: target/nextest/default/junit.xml test-linux-oldkernel-stable: extends: test-linux-stable -- GitLab From 15503883e2d340a8c4355a4fa4cf75db5dacc4b5 Mon Sep 17 00:00:00 2001 From: ordian Date: Thu, 7 Sep 2023 12:24:40 +0200 Subject: [PATCH 098/633] polkadot: pin one block per session (#1220) * polkadot: propagate UnpinHandle to ActiveLeafUpdate Also extract the leaf creation for tests into a common function. * dispute-coordinator: try pinned blocks for slashin * apparently 1.72 is smarter than 1.70 * address nits * rename fresh_leaf to new_leaf --- Cargo.lock | 7 +- .../src/collator_overseer.rs | 18 +- .../node/core/approval-voting/src/tests.rs | 10 +- polkadot/node/core/av-store/src/tests.rs | 49 ++--- polkadot/node/core/backing/src/tests/mod.rs | 11 +- .../src/tests/prospective_parachains.rs | 72 ++------ .../node/core/chain-selection/src/tests.rs | 23 +-- .../dispute-coordinator/src/initialized.rs | 20 ++- .../src/participation/tests.rs | 12 +- .../dispute-coordinator/src/scraping/tests.rs | 15 +- .../core/dispute-coordinator/src/tests.rs | 19 +- .../core/prospective-parachains/src/tests.rs | 37 +--- .../disputes/prioritized_selection/tests.rs | 10 +- polkadot/node/core/pvf-checker/src/tests.rs | 14 +- .../src/requester/tests.rs | 47 +---- .../src/tests/state.rs | 17 +- .../availability-recovery/src/tests.rs | 168 +++++++----------- polkadot/node/network/bridge/src/rx/tests.rs | 71 ++------ .../src/collator_side/tests/mod.rs | 13 +- .../dispute-distribution/src/tests/mod.rs | 13 +- .../node/network/gossip-support/src/tests.rs | 17 +- .../src/legacy_v1/tests.rs | 47 +---- .../src/vstaging/tests/mod.rs | 9 +- polkadot/node/overseer/Cargo.toml | 2 +- polkadot/node/overseer/src/lib.rs | 25 ++- polkadot/node/overseer/src/tests.rs | 163 ++++++++++------- .../node/subsystem-test-helpers/Cargo.toml | 5 +- .../node/subsystem-test-helpers/src/lib.rs | 36 ---- .../node/subsystem-test-helpers/src/mock.rs | 22 ++- polkadot/node/subsystem-types/Cargo.toml | 1 + polkadot/node/subsystem-types/src/lib.rs | 15 +- polkadot/node/subsystem-util/Cargo.toml | 2 + .../node/subsystem-util/src/runtime/mod.rs | 17 ++ 33 files changed, 387 insertions(+), 620 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fff5787989..a95a7e2561d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12303,9 +12303,10 @@ dependencies = [ "parking_lot 0.12.1", "polkadot-node-subsystem", "polkadot-node-subsystem-util", - "polkadot-overseer", "polkadot-primitives", + "sc-client-api", "sc-keystore", + "sc-utils", "sp-application-crypto", "sp-core", "sp-keyring", @@ -12325,6 +12326,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-primitives", "polkadot-statement-table", + "sc-client-api", "sc-network", "sc-transaction-pool-api", "smallvec", @@ -12362,11 +12364,13 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-types", "polkadot-overseer", "polkadot-primitives", "polkadot-primitives-test-helpers", "prioritized-metered-channel", "rand 0.8.5", + "sc-client-api", "schnellru", "sp-application-crypto", "sp-core", @@ -12390,6 +12394,7 @@ dependencies = [ "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", + "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", "polkadot-primitives", "polkadot-primitives-test-helpers", 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 491758c1329..bea2fc330a2 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -36,13 +36,14 @@ use polkadot_node_network_protocol::{ use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics}; use polkadot_overseer::{ BlockInfo, DummySubsystem, Handle, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, - KNOWN_LEAVES_CACHE_SIZE, + UnpinHandle, KNOWN_LEAVES_CACHE_SIZE, }; use polkadot_primitives::CollatorPair; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_network::NetworkStateInfo; use sc_service::TaskManager; +use sc_utils::mpsc::tracing_unbounded; use sp_runtime::traits::Block as BlockT; use cumulus_primitives_core::relay_chain::{Block, Hash as PHash}; @@ -221,20 +222,25 @@ async fn forward_collator_events( ) -> Result<(), RelayChainError> { let mut finality = client.finality_notification_stream().await?.fuse(); let mut imports = client.import_notification_stream().await?.fuse(); + // Collators do no need to pin any specific blocks + let (dummy_sink, _) = tracing_unbounded("does-not-matter", 42); + let dummy_unpin_handle = UnpinHandle::new(Default::default(), dummy_sink); loop { select! { f = finality.next() => { match f { Some(header) => { + let hash = header.hash(); tracing::info!( target: "minimal-polkadot-node", "Received finalized block via RPC: #{} ({} -> {})", header.number, header.parent_hash, - header.hash() + hash, ); - let block_info = BlockInfo { hash: header.hash(), parent_hash: header.parent_hash, number: header.number }; + let unpin_handle = dummy_unpin_handle.clone(); + let block_info = BlockInfo { hash, parent_hash: header.parent_hash, number: header.number, unpin_handle }; handle.block_finalized(block_info).await; } None => return Err(RelayChainError::GenericError("Relay chain finality stream ended.".to_string())), @@ -243,14 +249,16 @@ async fn forward_collator_events( i = imports.next() => { match i { Some(header) => { + let hash = header.hash(); tracing::info!( target: "minimal-polkadot-node", "Received imported block via RPC: #{} ({} -> {})", header.number, header.parent_hash, - header.hash() + hash, ); - let block_info = BlockInfo { hash: header.hash(), parent_hash: header.parent_hash, number: header.number }; + let unpin_handle = dummy_unpin_handle.clone(); + let block_info = BlockInfo { hash, parent_hash: header.parent_hash, number: header.number, unpin_handle }; handle.block_imported(block_info).await; } None => return Err(RelayChainError::GenericError("Relay chain import stream ended.".to_string())), diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 3c7b74b26fb..0b98f28fbbf 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use self::test_helpers::mock::new_leaf; use super::*; use polkadot_node_primitives::{ approval::{ @@ -26,7 +27,7 @@ use polkadot_node_subsystem::{ messages::{ AllMessages, ApprovalVotingMessage, AssignmentCheckResult, AvailabilityRecoveryMessage, }, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, + ActiveLeavesUpdate, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; @@ -777,12 +778,7 @@ async fn import_block( overseer_send( overseer, FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( - ActivatedLeaf { - hash: *new_head, - number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }, + new_leaf(*new_head, number), ))), ) .await; diff --git a/polkadot/node/core/av-store/src/tests.rs b/polkadot/node/core/av-store/src/tests.rs index dbccf140158..652bf2a3fda 100644 --- a/polkadot/node/core/av-store/src/tests.rs +++ b/polkadot/node/core/av-store/src/tests.rs @@ -19,14 +19,14 @@ use super::*; use assert_matches::assert_matches; use futures::{channel::oneshot, executor, future, Future}; +use self::test_helpers::mock::new_leaf; use ::test_helpers::TestCandidateBuilder; use parking_lot::Mutex; use polkadot_node_primitives::{AvailableData, BlockData, PoV, Proof}; use polkadot_node_subsystem::{ errors::RuntimeApiError, - jaeger, messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, + ActiveLeavesUpdate, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{database::Database, TimeoutExt}; @@ -219,16 +219,11 @@ fn runtime_api_error_does_not_stop_the_subsystem() { let store = test_store(); test_harness(TestState::default(), store, |mut virtual_overseer| async move { - let new_leaf = Hash::repeat_byte(0x01); + let a_leaf = Hash::repeat_byte(0x01); overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: new_leaf, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(a_leaf, 1))), ) .await; @@ -246,7 +241,7 @@ fn runtime_api_error_does_not_stop_the_subsystem() { relay_parent, tx, )) => { - assert_eq!(relay_parent, new_leaf); + assert_eq!(relay_parent, a_leaf); tx.send(Ok(Some(header))).unwrap(); } ); @@ -258,7 +253,7 @@ fn runtime_api_error_does_not_stop_the_subsystem() { relay_parent, RuntimeApiRequest::CandidateEvents(tx), )) => { - assert_eq!(relay_parent, new_leaf); + assert_eq!(relay_parent, a_leaf); #[derive(Debug)] struct FauxError; impl std::error::Error for FauxError {} @@ -741,7 +736,7 @@ fn stored_data_kept_until_finalized() { available_data, ); - let new_leaf = import_leaf( + let a_leaf = import_leaf( &mut virtual_overseer, parent, block_number, @@ -764,7 +759,7 @@ fn stored_data_kept_until_finalized() { overseer_signal( &mut virtual_overseer, - OverseerSignal::BlockFinalized(new_leaf, block_number), + OverseerSignal::BlockFinalized(a_leaf, block_number), ) .await; @@ -849,16 +844,11 @@ fn we_dont_miss_anything_if_import_notifications_are_missed() { extrinsics_root: Hash::zero(), digest: Default::default(), }; - let new_leaf = Hash::repeat_byte(4); + let a_leaf = Hash::repeat_byte(4); overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: new_leaf, - number: 4, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(a_leaf, 4))), ) .await; @@ -868,7 +858,7 @@ fn we_dont_miss_anything_if_import_notifications_are_missed() { relay_parent, tx, )) => { - assert_eq!(relay_parent, new_leaf); + assert_eq!(relay_parent, a_leaf); tx.send(Ok(Some(header))).unwrap(); } ); @@ -886,7 +876,7 @@ fn we_dont_miss_anything_if_import_notifications_are_missed() { k, response_channel: tx, }) => { - assert_eq!(hash, new_leaf); + assert_eq!(hash, a_leaf); assert_eq!(k, 2); let _ = tx.send(Ok(vec![ Hash::repeat_byte(3), @@ -1166,16 +1156,11 @@ async fn import_leaf( extrinsics_root: Hash::zero(), digest: Default::default(), }; - let new_leaf = header.hash(); + let a_leaf = header.hash(); overseer_signal( virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: new_leaf, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(a_leaf, 1))), ) .await; @@ -1185,7 +1170,7 @@ async fn import_leaf( relay_parent, tx, )) => { - assert_eq!(relay_parent, new_leaf); + assert_eq!(relay_parent, a_leaf); tx.send(Ok(Some(header))).unwrap(); } ); @@ -1196,7 +1181,7 @@ async fn import_leaf( relay_parent, RuntimeApiRequest::CandidateEvents(tx), )) => { - assert_eq!(relay_parent, new_leaf); + assert_eq!(relay_parent, a_leaf); tx.send(Ok(events)).unwrap(); } ); @@ -1212,7 +1197,7 @@ async fn import_leaf( } ); - new_leaf + a_leaf } #[test] diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index f5ea827d254..a981487db44 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use self::test_helpers::mock::new_leaf; use super::*; use ::test_helpers::{ dummy_candidate_receipt_bad_sig, dummy_collator, dummy_collator_signature, @@ -24,12 +25,11 @@ use futures::{future, Future}; use polkadot_node_primitives::{BlockData, InvalidCandidate, SignedFullStatement, Statement}; use polkadot_node_subsystem::{ errors::RuntimeApiError, - jaeger, messages::{ AllMessages, CollatorProtocolMessage, RuntimeApiMessage, RuntimeApiRequest, ValidationFailed, }, - ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, TimeoutExt, + ActiveLeavesUpdate, FromOrchestra, OverseerSignal, TimeoutExt, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ @@ -234,12 +234,7 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS // Start work on some new parent. virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( - ActivatedLeaf { - hash: test_state.relay_parent, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }, + new_leaf(test_state.relay_parent, 1), )))) .await; diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 07e2a3a89bb..d6e93fb04d3 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -18,7 +18,7 @@ use polkadot_node_subsystem::{ messages::{ChainApiMessage, FragmentTreeMembership}, - TimeoutExt, + ActivatedLeaf, TimeoutExt, }; use polkadot_primitives::{vstaging as vstaging_primitives, BlockNumber, Header, OccupiedCore}; @@ -346,12 +346,7 @@ fn seconding_sanity_check_allowed() { // `a` is grandparent of `b`. let leaf_a_hash = Hash::from_low_u64_be(130); let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = ActivatedLeaf { - hash: leaf_a_hash, - number: LEAF_A_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; @@ -359,12 +354,7 @@ fn seconding_sanity_check_allowed() { const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; let leaf_b_hash = Hash::from_low_u64_be(128); - let activated = ActivatedLeaf { - hash: leaf_b_hash, - number: LEAF_B_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; let test_leaf_b = TestLeaf { activated, min_relay_parents }; @@ -503,24 +493,14 @@ fn seconding_sanity_check_disallowed() { // `a` is grandparent of `b`. let leaf_a_hash = Hash::from_low_u64_be(130); let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = ActivatedLeaf { - hash: leaf_a_hash, - number: LEAF_A_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; - let activated = ActivatedLeaf { - hash: leaf_b_hash, - number: LEAF_B_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; let test_leaf_b = TestLeaf { activated, min_relay_parents }; @@ -722,12 +702,7 @@ fn prospective_parachains_reject_candidate() { let leaf_a_hash = Hash::from_low_u64_be(130); let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = ActivatedLeaf { - hash: leaf_a_hash, - number: LEAF_A_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; @@ -905,12 +880,7 @@ fn second_multiple_candidates_per_relay_parent() { let leaf_hash = Hash::from_low_u64_be(130); let leaf_parent = get_parent_hash(leaf_hash); let leaf_grandparent = get_parent_hash(leaf_parent); - let activated = ActivatedLeaf { - hash: leaf_hash, - number: LEAF_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; @@ -1046,12 +1016,7 @@ fn backing_works() { let leaf_hash = Hash::from_low_u64_be(130); let leaf_parent = get_parent_hash(leaf_hash); - let activated = ActivatedLeaf { - hash: leaf_hash, - number: LEAF_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; @@ -1212,12 +1177,7 @@ fn concurrent_dependent_candidates() { let leaf_hash = Hash::from_low_u64_be(130); let leaf_parent = get_parent_hash(leaf_hash); let leaf_grandparent = get_parent_hash(leaf_parent); - let activated = ActivatedLeaf { - hash: leaf_hash, - number: LEAF_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; @@ -1458,12 +1418,7 @@ fn seconding_sanity_check_occupy_same_depth() { let leaf_hash = Hash::from_low_u64_be(130); let leaf_parent = get_parent_hash(leaf_hash); - let activated = ActivatedLeaf { - hash: leaf_hash, - number: LEAF_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); let min_block_number = LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN; let min_relay_parents = vec![(para_id_a, min_block_number), (para_id_b, min_block_number)]; @@ -1617,12 +1572,7 @@ fn occupied_core_assignment() { let leaf_a_hash = Hash::from_low_u64_be(130); let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = ActivatedLeaf { - hash: leaf_a_hash, - number: LEAF_A_BLOCK_NUMBER, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; diff --git a/polkadot/node/core/chain-selection/src/tests.rs b/polkadot/node/core/chain-selection/src/tests.rs index c04f9aaf660..cf021c0efeb 100644 --- a/polkadot/node/core/chain-selection/src/tests.rs +++ b/polkadot/node/core/chain-selection/src/tests.rs @@ -35,11 +35,10 @@ use parity_scale_codec::Encode; use parking_lot::Mutex; use sp_core::testing::TaskExecutor; -use polkadot_node_subsystem::{ - jaeger, messages::AllMessages, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, -}; +use polkadot_node_subsystem::{messages::AllMessages, ActiveLeavesUpdate}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{BlakeTwo256, ConsensusLog, HashT}; +use test_helpers::mock::new_leaf; #[derive(Default)] struct TestBackendInner { @@ -367,12 +366,10 @@ async fn import_blocks_into( let hash = header.hash(); virtual_overseer .send( - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( hash, - number: header.number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })) + header.number, + ))) .into(), ) .await; @@ -425,12 +422,10 @@ async fn import_all_blocks_into( let (_, write_rx) = backend.await_next_write(); virtual_overseer .send( - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: head_hash, - number: head.number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })) + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + head_hash, + head.number, + ))) .into(), ) .await; diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 2d8e15064e4..9bfca2d81a0 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -308,6 +308,8 @@ impl Initialized { Ok(session_idx) if self.gaps_in_cache || session_idx > self.highest_session_seen => { + // Pin the block from the new session. + self.runtime_info.pin_block(session_idx, new_leaf.unpin_handle); // Fetch the last `DISPUTE_WINDOW` number of sessions unless there are no gaps // in cache and we are not missing too many `SessionInfo`s let mut lower_bound = session_idx.saturating_sub(DISPUTE_WINDOW.get() - 1); @@ -387,26 +389,28 @@ impl Initialized { "Processing unapplied validator slashes", ); + let pinned_hash = self.runtime_info.get_block_in_session(session_index); let inclusions = self.scraper.get_blocks_including_candidate(&candidate_hash); - if inclusions.is_empty() { + if pinned_hash.is_none() && inclusions.is_empty() { gum::info!( target: LOG_TARGET, - "Couldn't find inclusion parent for an unapplied slash", + ?session_index, + "Couldn't find blocks in the session for an unapplied slash", ); return } - // Find the first inclusion parent that we can use + // Find a relay block that we can use // to generate key ownership proof on. - // We use inclusion parents because of the proper session index. + // We use inclusion parents as a fallback. let mut key_ownership_proofs = Vec::new(); let mut dispute_proofs = Vec::new(); - for (_height, inclusion_parent) in inclusions { + let blocks_in_the_session = + pinned_hash.into_iter().chain(inclusions.into_iter().map(|(_n, h)| h)); + for hash in blocks_in_the_session { for (validator_index, validator_id) in pending.keys.iter() { - let res = - key_ownership_proof(ctx.sender(), inclusion_parent, validator_id.clone()) - .await; + let res = key_ownership_proof(ctx.sender(), hash, validator_id.clone()).await; match res { Ok(Some(key_ownership_proof)) => { diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index a2e8e88cb67..ee6b950720e 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -28,15 +28,14 @@ use ::test_helpers::{ use parity_scale_codec::Encode; use polkadot_node_primitives::{AvailableData, BlockData, InvalidCandidate, PoV}; use polkadot_node_subsystem::{ - jaeger, messages::{ AllMessages, ChainApiMessage, DisputeCoordinatorMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, SpawnGlue, + ActiveLeavesUpdate, SpawnGlue, }; use polkadot_node_subsystem_test_helpers::{ - make_subsystem_context, TestSubsystemContext, TestSubsystemContextHandle, + make_subsystem_context, mock::new_leaf, TestSubsystemContext, TestSubsystemContextHandle, }; use polkadot_primitives::{ BlakeTwo256, CandidateCommitments, HashT, Header, PersistedValidationData, ValidationCode, @@ -100,12 +99,7 @@ async fn activate_leaf( participation .process_active_leaves_update( ctx, - &ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: block_hash, - span: Arc::new(jaeger::Span::Disabled), - number: block_number, - status: LeafStatus::Fresh, - }), + &ActiveLeavesUpdate::start_work(new_leaf(block_hash, block_number)), ) .await } diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs index 3dd58a060d7..ae722fcb1b4 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{sync::Arc, time::Duration}; +use std::time::Duration; use assert_matches::assert_matches; @@ -25,15 +25,15 @@ use sp_core::testing::TaskExecutor; use ::test_helpers::{dummy_collator, dummy_collator_signature, dummy_hash}; use polkadot_node_primitives::DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION; use polkadot_node_subsystem::{ - jaeger, messages::{ AllMessages, ChainApiMessage, DisputeCoordinatorMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, SpawnGlue, + ActivatedLeaf, ActiveLeavesUpdate, SpawnGlue, }; use polkadot_node_subsystem_test_helpers::{ - make_subsystem_context, TestSubsystemContext, TestSubsystemContextHandle, TestSubsystemSender, + make_subsystem_context, mock::new_leaf, TestSubsystemContext, TestSubsystemContextHandle, + TestSubsystemSender, }; use polkadot_node_subsystem_util::{reexports::SubsystemContext, TimeoutExt}; use polkadot_primitives::{ @@ -141,12 +141,7 @@ fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { /// Get a dummy `ActivatedLeaf` for a given block number. fn get_activated_leaf(n: BlockNumber) -> ActivatedLeaf { - ActivatedLeaf { - hash: get_block_number_hash(n), - number: n, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - } + new_leaf(get_block_number_hash(n), n) } /// Get a dummy relay parent hash for dummy block number. diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 8d6a2e10396..9254c2a851c 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -54,12 +54,11 @@ use sp_keystore::{Keystore, KeystorePtr}; use ::test_helpers::{dummy_candidate_receipt_bad_sig, dummy_digest, dummy_hash}; use polkadot_node_primitives::{Timestamp, ACTIVE_DURATION_SECS}; use polkadot_node_subsystem::{ - jaeger, messages::{AllMessages, BlockDescription, RuntimeApiMessage, RuntimeApiRequest}, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, + ActiveLeavesUpdate, }; use polkadot_node_subsystem_test_helpers::{ - make_buffered_subsystem_context, TestSubsystemContextHandle, + make_buffered_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; use polkadot_primitives::{ ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, @@ -276,12 +275,7 @@ impl TestState { gum::debug!(?block_number, "Activating block in activate_leaf_at_session."); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: block_hash, - span: Arc::new(jaeger::Span::Disabled), - number: block_number, - status: LeafStatus::Fresh, - }), + ActiveLeavesUpdate::start_work(new_leaf(block_hash, block_number)), ))) .await; @@ -449,12 +443,7 @@ impl TestState { ); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: *leaf, - number: n as u32, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }), + ActiveLeavesUpdate::start_work(new_leaf(*leaf, n as u32)), ))) .await; diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 9fc77624b97..eb12ea4537f 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -24,7 +24,6 @@ use polkadot_node_subsystem::{ }, }; use polkadot_node_subsystem_test_helpers as test_helpers; -use polkadot_node_subsystem_types::{jaeger, ActivatedLeaf, LeafStatus}; use polkadot_primitives::{ vstaging::{AsyncBackingParams, BackingState, Constraints, InboundHrmpLimitations}, CommittedCandidateReceipt, HeadData, Header, PersistedValidationData, ScheduledCore, @@ -32,6 +31,7 @@ use polkadot_primitives::{ }; use polkadot_primitives_test_helpers::make_candidate; use std::sync::Arc; +use test_helpers::mock::new_leaf; const ALLOWED_ANCESTRY_LEN: u32 = 3; const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = @@ -197,12 +197,7 @@ async fn activate_leaf_with_params( ) { let TestLeaf { number, hash, .. } = leaf; - let activated = ActivatedLeaf { - hash: *hash, - number: *number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(*hash, *number); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( @@ -497,12 +492,7 @@ fn should_do_no_work_if_async_backing_disabled_for_leaf() { // Start work on some new parent. virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash, 1)), ))) .await; @@ -1318,12 +1308,7 @@ fn correctly_updates_leaves() { .await; // Activate a leaf and remove one at the same time. - let activated = ActivatedLeaf { - hash: leaf_c.hash, - number: leaf_c.number, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }; + let activated = new_leaf(leaf_c.hash, leaf_c.number); let update = ActiveLeavesUpdate { activated: Some(activated), deactivated: [leaf_b.hash][..].into(), @@ -1349,12 +1334,7 @@ fn correctly_updates_leaves() { .await; // Activate and deactivate the same leaf. - let activated = ActivatedLeaf { - hash: leaf_a.hash, - number: leaf_a.number, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }; + let activated = new_leaf(leaf_a.hash, leaf_a.number); let update = ActiveLeavesUpdate { activated: Some(activated), deactivated: [leaf_a.hash][..].into(), @@ -1578,12 +1558,7 @@ fn uses_ancestry_only_within_session() { vec![Hash::repeat_byte(4), Hash::repeat_byte(3), Hash::repeat_byte(2)]; let session_change_hash = Hash::repeat_byte(3); - let activated = ActivatedLeaf { - hash, - number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(hash, number); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( diff --git a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs index 2fdeadb2f4f..f6c49e52eeb 100644 --- a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs +++ b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs @@ -24,12 +24,11 @@ use polkadot_node_primitives::{CandidateVotes, DisputeStatus, ACTIVE_DURATION_SE use polkadot_node_subsystem::messages::{ AllMessages, DisputeCoordinatorMessage, RuntimeApiMessage, RuntimeApiRequest, }; -use polkadot_node_subsystem_test_helpers::TestSubsystemSender; +use polkadot_node_subsystem_test_helpers::{mock::new_leaf, TestSubsystemSender}; use polkadot_primitives::{ CandidateHash, DisputeState, InvalidDisputeStatementKind, SessionIndex, ValidDisputeStatementKind, ValidatorSignature, }; -use std::sync::Arc; use test_helpers; // @@ -353,12 +352,7 @@ async fn mock_overseer( } fn leaf() -> ActivatedLeaf { - ActivatedLeaf { - hash: Hash::repeat_byte(0xAA), - number: 0xAA, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - } + new_leaf(Hash::repeat_byte(0xAA), 0xAA) } struct TestDisputes { diff --git a/polkadot/node/core/pvf-checker/src/tests.rs b/polkadot/node/core/pvf-checker/src/tests.rs index d1daa7a5813..bd8817000ae 100644 --- a/polkadot/node/core/pvf-checker/src/tests.rs +++ b/polkadot/node/core/pvf-checker/src/tests.rs @@ -17,14 +17,15 @@ use ::test_helpers::{dummy_digest, dummy_hash}; use futures::{channel::oneshot, future::BoxFuture, prelude::*}; use polkadot_node_subsystem::{ - jaeger, messages::{ AllMessages, CandidateValidationMessage, PreCheckOutcome, PvfCheckerMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, RuntimeApiError, + ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, +}; +use polkadot_node_subsystem_test_helpers::{ + make_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; -use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle}; use polkadot_primitives::{ BlockNumber, Hash, Header, PvfCheckStatement, SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, @@ -195,12 +196,7 @@ impl TestState { }, ); - Some(ActivatedLeaf { - hash: activated_leaf.block_hash, - span: Arc::new(jaeger::Span::Disabled), - number: activated_leaf.block_number, - status: LeafStatus::Fresh, - }) + Some(new_leaf(activated_leaf.block_hash, activated_leaf.block_number)) } else { None }; diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 5f7e4c36f06..c4252b4e439 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -16,12 +16,13 @@ use std::collections::HashMap; -use std::{future::Future, sync::Arc}; +use std::future::Future; use futures::FutureExt; use polkadot_node_network_protocol::jaeger; use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; +use polkadot_node_subsystem_test_helpers::mock::new_leaf; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, @@ -34,7 +35,7 @@ use polkadot_node_subsystem::{ AllMessages, AvailabilityDistributionMessage, AvailabilityStoreMessage, ChainApiMessage, NetworkBridgeTxMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, SpawnGlue, + ActiveLeavesUpdate, SpawnGlue, }; use polkadot_node_subsystem_test_helpers::{ make_subsystem_context, mock::make_ferdie_keystore, TestSubsystemContext, @@ -205,12 +206,7 @@ fn check_ancestry_lookup_in_same_session() { let spans: HashMap = HashMap::new(); let block_number = 1; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: Vec::new().into(), }; @@ -225,12 +221,7 @@ fn check_ancestry_lookup_in_same_session() { let block_number = 2; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: Vec::new().into(), }; @@ -252,12 +243,7 @@ fn check_ancestry_lookup_in_same_session() { // part of ancestry. let block_number = 2 + Requester::LEAF_ANCESTRY_LEN_WITHIN_SESSION; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: test_state.relay_chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: vec![chain[1], chain[2]].into(), }; requester @@ -292,12 +278,7 @@ fn check_ancestry_lookup_in_different_sessions() { let spans: HashMap = HashMap::new(); let block_number = 3; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: Vec::new().into(), }; @@ -310,12 +291,7 @@ fn check_ancestry_lookup_in_different_sessions() { let block_number = 4; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: vec![chain[1], chain[2], chain[3]].into(), }; @@ -328,12 +304,7 @@ fn check_ancestry_lookup_in_different_sessions() { let block_number = 5; let update = ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: chain[block_number], - number: block_number as u32, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(chain[block_number], block_number as u32)), deactivated: vec![chain[4]].into(), }; diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index ecde44788c2..101d917c0db 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -16,7 +16,6 @@ use std::{ collections::{HashMap, HashSet}, - sync::Arc, time::Duration, }; @@ -34,9 +33,8 @@ use sc_network::{config as netconfig, config::RequestResponseConfig, IfDisconnec use sp_core::{testing::TaskExecutor, traits::SpawnNamed}; use sp_keystore::KeystorePtr; -use polkadot_node_network_protocol::{ - jaeger, - request_response::{v1, IncomingRequest, OutgoingRequest, Requests}, +use polkadot_node_network_protocol::request_response::{ + v1, IncomingRequest, OutgoingRequest, Requests, }; use polkadot_node_primitives::ErasureChunk; use polkadot_node_subsystem::{ @@ -44,14 +42,14 @@ use polkadot_node_subsystem::{ AllMessages, AvailabilityDistributionMessage, AvailabilityStoreMessage, ChainApiMessage, NetworkBridgeTxMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, + ActiveLeavesUpdate, FromOrchestra, OverseerSignal, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionInfo, ValidatorIndex, }; -use test_helpers::mock::make_ferdie_keystore; +use test_helpers::mock::{make_ferdie_keystore, new_leaf}; use super::mock::{make_session_info, OccupiedCoreBuilder}; use crate::LOG_TARGET; @@ -175,12 +173,7 @@ impl TestState { .iter() .zip(advanced) .map(|(old, new)| ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: *new, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + activated: Some(new_leaf(*new, 1)), deactivated: vec![*old].into(), }) .collect::>() diff --git a/polkadot/node/network/availability-recovery/src/tests.rs b/polkadot/node/network/availability-recovery/src/tests.rs index de923f5967e..60c2d38ab31 100644 --- a/polkadot/node/network/availability-recovery/src/tests.rs +++ b/polkadot/node/network/availability-recovery/src/tests.rs @@ -29,12 +29,10 @@ use sc_network::config::RequestResponseConfig; use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks}; use polkadot_node_primitives::{BlockData, PoV, Proof}; -use polkadot_node_subsystem::{ - jaeger, - messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, - ActivatedLeaf, LeafStatus, +use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; +use polkadot_node_subsystem_test_helpers::{ + make_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; -use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ AuthorityDiscoveryId, Hash, HeadData, IndexedVec, PersistedValidationData, ValidatorId, @@ -561,12 +559,10 @@ fn availability_is_recovered_from_chunks_if_no_group_provided() { test_harness_fast_path(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -647,12 +643,10 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -733,12 +727,10 @@ fn bad_merkle_path_leads_to_recovery_error() { test_harness_fast_path(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -791,12 +783,10 @@ fn wrong_chunk_index_leads_to_recovery_error() { test_harness_fast_path(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -865,12 +855,10 @@ fn invalid_erasure_coding_leads_to_invalid_error() { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -914,12 +902,10 @@ fn fast_path_backing_group_recovers() { test_harness_fast_path(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -964,12 +950,10 @@ fn recovers_from_only_chunks_if_pov_large() { test_harness_chunks_if_pov_large(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1068,12 +1052,10 @@ fn fast_path_backing_group_recovers_if_pov_small() { test_harness_chunks_if_pov_large(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1127,12 +1109,10 @@ fn no_answers_in_fast_path_causes_chunk_requests() { test_harness_fast_path(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1189,12 +1169,10 @@ fn task_canceled_when_receivers_dropped() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1231,12 +1209,10 @@ fn chunks_retry_until_all_nodes_respond() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1292,12 +1268,10 @@ fn not_returning_requests_wont_stall_retrieval() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1364,12 +1338,10 @@ fn all_not_returning_requests_still_recovers_on_return() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1441,12 +1413,10 @@ fn returns_early_if_we_have_the_data() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1478,12 +1448,10 @@ fn does_not_query_local_validator() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; @@ -1537,12 +1505,10 @@ fn invalid_local_chunk_is_ignored() { test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move { overseer_signal( &mut virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.current, + 1, + ))), ) .await; diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 88a4b247fdc..127f46e0fa3 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -16,8 +16,9 @@ use super::*; use futures::{channel::oneshot, executor, stream::BoxStream}; +use overseer::jaeger; use polkadot_node_network_protocol::{self as net_protocol, OurView}; -use polkadot_node_subsystem::{messages::NetworkBridgeEvent, ActivatedLeaf}; +use polkadot_node_subsystem::messages::NetworkBridgeEvent; use assert_matches::assert_matches; use async_trait::async_trait; @@ -36,15 +37,14 @@ use polkadot_node_network_protocol::{ view, ObservedRole, Versioned, }; use polkadot_node_subsystem::{ - jaeger, messages::{ AllMessages, ApprovalDistributionMessage, BitfieldDistributionMessage, GossipSupportMessage, StatementDistributionMessage, }, - ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, + ActiveLeavesUpdate, FromOrchestra, OverseerSignal, }; use polkadot_node_subsystem_test_helpers::{ - SingleItemSink, SingleItemStream, TestSubsystemContextHandle, + mock::new_leaf, SingleItemSink, SingleItemStream, TestSubsystemContextHandle, }; use polkadot_node_subsystem_util::metered; use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash}; @@ -427,12 +427,7 @@ fn send_our_view_upon_connection() { let head = Hash::repeat_byte(1); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: head, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(head, 1)), ))) .await; @@ -514,12 +509,7 @@ fn sends_view_updates_to_peers() { virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -585,12 +575,7 @@ fn do_not_send_view_update_until_synced() { virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -601,12 +586,7 @@ fn do_not_send_view_update_until_synced() { virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_b, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_b, 1)), ))) .await; @@ -672,12 +652,7 @@ fn do_not_send_view_update_when_only_finalized_block_changed() { // This should trigger the view update to our peers. virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -895,12 +870,7 @@ fn peer_disconnect_from_just_one_peerset() { virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -1132,12 +1102,7 @@ fn sent_views_include_finalized_number_update() { .await; virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_b, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_b, 1)), ))) .await; @@ -1211,12 +1176,7 @@ fn our_view_updates_decreasing_order_and_limited_to_max() { // get the correct view. virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash, - number: i as _, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash, i as _)), ))) .await; } @@ -1265,12 +1225,7 @@ fn network_protocol_versioning_view_update() { let head = Hash::repeat_byte(1); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: head, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(head, 1)), ))) .await; 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 8b28730c901..b452c84c2cd 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 @@ -40,7 +40,7 @@ use polkadot_node_subsystem::{ errors::RuntimeApiError, jaeger, messages::{AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest}, - ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, + ActiveLeavesUpdate, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; @@ -49,6 +49,7 @@ use polkadot_primitives::{ ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; +use test_helpers::mock::new_leaf; mod prospective_parachains; @@ -310,12 +311,10 @@ async fn setup_system(virtual_overseer: &mut VirtualOverseer, test_state: &TestS overseer_signal( virtual_overseer, - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.relay_parent, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + test_state.relay_parent, + 1, + ))), ) .await; diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index f53b9c0dd4b..96f045cbf76 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -19,7 +19,6 @@ use std::{ collections::HashSet, - sync::Arc, task::Poll, time::{Duration, Instant}, }; @@ -51,10 +50,11 @@ use polkadot_node_subsystem::{ AllMessages, DisputeCoordinatorMessage, DisputeDistributionMessage, ImportStatementsResult, NetworkBridgeTxMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, Span, + ActiveLeavesUpdate, FromOrchestra, OverseerSignal, }; use polkadot_node_subsystem_test_helpers::{ - mock::make_ferdie_keystore, subsystem_test_harness, TestSubsystemContextHandle, + mock::{make_ferdie_keystore, new_leaf}, + subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex, @@ -735,12 +735,7 @@ async fn activate_leaf( ) { handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: activate, - number: 10, - status: LeafStatus::Fresh, - span: Arc::new(Span::Disabled), - }), + activated: Some(new_leaf(activate, 10)), deactivated: deactivate.into_iter().collect(), }))) .await; diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 20f55051415..2e909bb0a67 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -16,7 +16,7 @@ //! Unit tests for Gossip Support Subsystem. -use std::{collections::HashSet, sync::Arc, time::Duration}; +use std::{collections::HashSet, time::Duration}; use assert_matches::assert_matches; use async_trait::async_trait; @@ -30,15 +30,11 @@ use sp_core::crypto::Pair as PairT; use sp_keyring::Sr25519Keyring; use polkadot_node_network_protocol::grid_topology::{SessionGridTopology, TopologyPeerInfo}; -use polkadot_node_subsystem::{ - jaeger, - messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, - ActivatedLeaf, LeafStatus, -}; +use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt as _; use polkadot_primitives::{GroupIndex, IndexedVec}; -use test_helpers::mock::make_ferdie_keystore; +use test_helpers::mock::{make_ferdie_keystore, new_leaf}; use super::*; @@ -196,12 +192,7 @@ fn test_harness, AD: AuthorityDiscovery>( const TIMEOUT: Duration = Duration::from_millis(100); async fn overseer_signal_active_leaves(overseer: &mut VirtualOverseer, leaf: Hash) { - let leaf = ActivatedLeaf { - hash: leaf, - number: 0xdeadcafe, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let leaf = new_leaf(leaf, 0xdeadcafe); overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( leaf, 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 63ac1febde5..17a66a9ff79 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -36,13 +36,12 @@ use polkadot_node_primitives::{ SignedFullStatementWithPVD, Statement, UncheckedSignedFullStatement, }; use polkadot_node_subsystem::{ - jaeger, messages::{ network_bridge_event, AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, LeafStatus, RuntimeApiError, + RuntimeApiError, }; -use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore; +use polkadot_node_subsystem_test_helpers::mock::{make_ferdie_keystore, new_leaf}; use polkadot_primitives::{ ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, ValidationCode, @@ -787,12 +786,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -1032,12 +1026,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -1567,12 +1556,7 @@ fn delay_reputation_changes() { // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -2052,12 +2036,7 @@ fn share_prioritizes_backing_group() { // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -2379,12 +2358,7 @@ fn peer_cant_flood_with_large_statements() { // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: hash_a, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(hash_a, 1)), ))) .await; @@ -2609,12 +2583,7 @@ fn handle_multiple_seconded_statements() { // register our active heads. handle .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: relay_parent_hash, - number: 1, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }), + ActiveLeavesUpdate::start_work(new_leaf(relay_parent_hash, 1)), ))) .await; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs index c5a4d14d2c7..48ceebb1949 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs @@ -30,7 +30,6 @@ use polkadot_node_subsystem::messages::{ RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; -use polkadot_node_subsystem_types::{jaeger, ActivatedLeaf, LeafStatus}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::vstaging::{ AssignmentPair, AsyncBackingParams, BlockNumber, CommittedCandidateReceipt, CoreState, @@ -46,6 +45,7 @@ use assert_matches::assert_matches; use futures::Future; use parity_scale_codec::Encode; use rand::{Rng, SeedableRng}; +use test_helpers::mock::new_leaf; use std::sync::Arc; @@ -358,12 +358,7 @@ async fn activate_leaf( test_state: &TestState, is_new_session: bool, ) { - let activated = ActivatedLeaf { - hash: leaf.hash, - number: leaf.number, - status: LeafStatus::Fresh, - span: Arc::new(jaeger::Span::Disabled), - }; + let activated = new_leaf(leaf.hash, leaf.number); virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 2ebe2e9e074..0efd4d4c6ca 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -25,12 +25,12 @@ tikv-jemalloc-ctl = { version = "0.5.0", optional = true } [dev-dependencies] metered = { package = "prioritized-metered-channel", version = "0.2.0" } - sp-core = { path = "../../../substrate/primitives/core" } futures = { version = "0.3.21", features = ["thread-pool"] } femme = "2.2.1" assert_matches = "1.4.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } +node-test-helpers = { package = "polkadot-node-subsystem-test-helpers", path = "../subsystem-test-helpers" } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemalloc-ctl = "0.5.0" diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index b8643982323..7337f1e6be7 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -87,7 +87,7 @@ use polkadot_node_subsystem_types::messages::{ pub use polkadot_node_subsystem_types::{ errors::{SubsystemError, SubsystemResult}, jaeger, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, OverseerSignal, - RuntimeApiSubsystemClient, + RuntimeApiSubsystemClient, UnpinHandle, }; pub mod metrics; @@ -245,23 +245,35 @@ impl Handle { /// `HeaderBackend::block_number_from_id()`. #[derive(Debug, Clone)] pub struct BlockInfo { - /// hash of the block. + /// Hash of the block. pub hash: Hash, - /// hash of the parent block. + /// Hash of the parent block. pub parent_hash: Hash, - /// block's number. + /// Block's number. pub number: BlockNumber, + /// A handle to unpin the block on drop. + pub unpin_handle: UnpinHandle, } impl From> for BlockInfo { fn from(n: BlockImportNotification) -> Self { - BlockInfo { hash: n.hash, parent_hash: n.header.parent_hash, number: n.header.number } + let hash = n.hash; + let parent_hash = n.header.parent_hash; + let number = n.header.number; + let unpin_handle = n.into_unpin_handle(); + + BlockInfo { hash, parent_hash, number, unpin_handle } } } impl From> for BlockInfo { fn from(n: FinalityNotification) -> Self { - BlockInfo { hash: n.hash, parent_hash: n.header.parent_hash, number: n.header.number } + let hash = n.hash; + let parent_hash = n.header.parent_hash; + let number = n.header.number; + let unpin_handle = n.into_unpin_handle(); + + BlockInfo { hash, parent_hash, number, unpin_handle } } } @@ -792,6 +804,7 @@ where hash: block.hash, number: block.number, status, + unpin_handle: block.unpin_handle, span, }), None => ActiveLeavesUpdate::default(), diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 22d9bf0a708..298783f4180 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -19,15 +19,14 @@ use futures::{executor, pending, pin_mut, poll, select, stream, FutureExt}; use std::{collections::HashMap, sync::atomic, task::Poll}; use ::test_helpers::{dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash}; +use node_test_helpers::mock::{dummy_unpin_handle, new_leaf}; use polkadot_node_network_protocol::{PeerId, UnifiedReputationChange}; use polkadot_node_primitives::{ BlockData, CollationGenerationConfig, CollationResult, DisputeMessage, InvalidDisputeVote, PoV, UncheckedDisputeMessage, ValidDisputeVote, }; -use polkadot_node_subsystem_types::{ - jaeger, - messages::{NetworkBridgeEvent, ReportPeerMessage, RuntimeApiRequest}, - ActivatedLeaf, LeafStatus, +use polkadot_node_subsystem_types::messages::{ + NetworkBridgeEvent, ReportPeerMessage, RuntimeApiRequest, }; use polkadot_primitives::{ CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, @@ -99,7 +98,7 @@ where if c < 10 { let candidate_receipt = CandidateReceipt { descriptor: dummy_candidate_descriptor(dummy_hash()), - commitments_hash: Hash::zero(), + commitments_hash: dummy_hash(), }; let (tx, _) = oneshot::channel(); @@ -216,11 +215,20 @@ fn overseer_metrics_work() { executor::block_on(async move { let first_block_hash = [1; 32].into(); let second_block_hash = [2; 32].into(); + let unpin_handle = dummy_unpin_handle(dummy_hash()); - let first_block = - BlockInfo { hash: first_block_hash, parent_hash: [0; 32].into(), number: 1 }; - let second_block = - BlockInfo { hash: second_block_hash, parent_hash: first_block_hash, number: 2 }; + let first_block = BlockInfo { + hash: first_block_hash, + parent_hash: [0; 32].into(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; + let second_block = BlockInfo { + hash: second_block_hash, + parent_hash: first_block_hash, + number: 2, + unpin_handle: unpin_handle.clone(), + }; let registry = prometheus::Registry::new(); let (overseer, handle) = @@ -368,11 +376,20 @@ fn overseer_start_stop_works() { executor::block_on(async move { let first_block_hash = [1; 32].into(); let second_block_hash = [2; 32].into(); + let unpin_handle = dummy_unpin_handle(dummy_hash()); - let first_block = - BlockInfo { hash: first_block_hash, parent_hash: [0; 32].into(), number: 1 }; - let second_block = - BlockInfo { hash: second_block_hash, parent_hash: first_block_hash, number: 2 }; + let first_block = BlockInfo { + hash: first_block_hash, + parent_hash: [0; 32].into(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; + let second_block = BlockInfo { + hash: second_block_hash, + parent_hash: first_block_hash, + number: 2, + unpin_handle: unpin_handle.clone(), + }; let (tx_5, mut rx_5) = metered::channel(64); let (tx_6, mut rx_6) = metered::channel(64); @@ -396,21 +413,11 @@ fn overseer_start_stop_works() { let expected_heartbeats = vec![ OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: first_block_hash, - number: 1, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }), + activated: Some(new_leaf(first_block_hash, 1)), deactivated: Default::default(), }), OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: second_block_hash, - number: 2, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }), + activated: Some(new_leaf(second_block_hash, 2)), deactivated: [first_block_hash].as_ref().into(), }), ]; @@ -456,13 +463,26 @@ fn overseer_finalize_works() { let first_block_hash = [1; 32].into(); let second_block_hash = [2; 32].into(); let third_block_hash = [3; 32].into(); + let unpin_handle = dummy_unpin_handle(dummy_hash()); - let first_block = - BlockInfo { hash: first_block_hash, parent_hash: [0; 32].into(), number: 1 }; - let second_block = - BlockInfo { hash: second_block_hash, parent_hash: [42; 32].into(), number: 2 }; - let third_block = - BlockInfo { hash: third_block_hash, parent_hash: second_block_hash, number: 3 }; + let first_block = BlockInfo { + hash: first_block_hash, + parent_hash: [0; 32].into(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; + let second_block = BlockInfo { + hash: second_block_hash, + parent_hash: [42; 32].into(), + number: 2, + unpin_handle: unpin_handle.clone(), + }; + let third_block = BlockInfo { + hash: third_block_hash, + parent_hash: second_block_hash, + number: 3, + unpin_handle: unpin_handle.clone(), + }; let (tx_5, mut rx_5) = metered::channel(64); let (tx_6, mut rx_6) = metered::channel(64); @@ -492,21 +512,11 @@ fn overseer_finalize_works() { let expected_heartbeats = vec![ OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: first_block_hash, - number: 1, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }), + activated: Some(new_leaf(first_block_hash, 1)), deactivated: Default::default(), }), OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { - activated: Some(ActivatedLeaf { - hash: second_block_hash, - number: 2, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - }), + activated: Some(new_leaf(second_block_hash, 2)), deactivated: Default::default(), }), OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { @@ -563,11 +573,20 @@ fn overseer_finalize_leaf_preserves_it() { executor::block_on(async move { let first_block_hash = [1; 32].into(); let second_block_hash = [2; 32].into(); + let unpin_handle = dummy_unpin_handle(dummy_hash()); - let first_block = - BlockInfo { hash: first_block_hash, parent_hash: [0; 32].into(), number: 1 }; - let second_block = - BlockInfo { hash: second_block_hash, parent_hash: [42; 32].into(), number: 1 }; + let first_block = BlockInfo { + hash: first_block_hash, + parent_hash: [0; 32].into(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; + let second_block = BlockInfo { + hash: second_block_hash, + parent_hash: [42; 32].into(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; let (tx_5, mut rx_5) = metered::channel(64); let (tx_6, mut rx_6) = metered::channel(64); @@ -595,18 +614,14 @@ fn overseer_finalize_leaf_preserves_it() { handle.block_finalized(first_block).await; let expected_heartbeats = vec![ - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: first_block_hash, - number: 1, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - })), - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: second_block_hash, - number: 1, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + first_block_hash, + 1, + ))), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + second_block_hash, + 2, + ))), OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { deactivated: [second_block_hash].as_ref().into(), ..Default::default() @@ -657,11 +672,21 @@ fn do_not_send_empty_leaves_update_on_block_finalization() { let spawner = sp_core::testing::TaskExecutor::new(); executor::block_on(async move { - let imported_block = - BlockInfo { hash: Hash::random(), parent_hash: Hash::random(), number: 1 }; + let unpin_handle = dummy_unpin_handle(dummy_hash()); - let finalized_block = - BlockInfo { hash: Hash::random(), parent_hash: Hash::random(), number: 1 }; + let imported_block = BlockInfo { + hash: Hash::random(), + parent_hash: Hash::random(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; + + let finalized_block = BlockInfo { + hash: Hash::random(), + parent_hash: Hash::random(), + number: 1, + unpin_handle: unpin_handle.clone(), + }; let (tx_5, mut rx_5) = metered::channel(64); @@ -682,12 +707,10 @@ fn do_not_send_empty_leaves_update_on_block_finalization() { handle.block_imported(imported_block.clone()).await; let expected_heartbeats = vec![ - OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: imported_block.hash, - number: imported_block.number, - span: Arc::new(jaeger::Span::Disabled), - status: LeafStatus::Fresh, - })), + OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + imported_block.hash, + imported_block.number, + ))), OverseerSignal::BlockFinalized(finalized_block.hash, 1), ]; @@ -952,11 +975,13 @@ fn overseer_all_subsystems_receive_signals_and_messages() { pin_mut!(overseer_fut); // send a signal to each subsystem + let unpin_handle = dummy_unpin_handle(dummy_hash()); handle .block_imported(BlockInfo { hash: Default::default(), parent_hash: Default::default(), number: Default::default(), + unpin_handle: unpin_handle.clone(), }) .await; diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index 98b0d182a61..9087ca11f5d 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -14,11 +14,10 @@ parking_lot = "0.12.0" polkadot-node-subsystem = { path = "../subsystem" } polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-primitives = { path = "../../primitives" } +sc-client-api = { path = "../../../substrate/client/api" } +sc-utils = { path = "../../../substrate/client/utils" } sp-core = { path = "../../../substrate/primitives/core" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-keystore = { path = "../../../substrate/client/keystore" } sp-keyring = { path = "../../../substrate/primitives/keyring" } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } - -[dev-dependencies] -polkadot-overseer = { path = "../overseer" } diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs index 6f0c3016c7a..fe6b106bf46 100644 --- a/polkadot/node/subsystem-test-helpers/src/lib.rs +++ b/polkadot/node/subsystem-test-helpers/src/lib.rs @@ -435,42 +435,6 @@ impl Future for Yield { #[cfg(test)] mod tests { use super::*; - use futures::executor::block_on; - use polkadot_node_subsystem::messages::CollatorProtocolMessage; - use polkadot_overseer::{dummy::dummy_overseer_builder, Handle, HeadSupportsParachains}; - use polkadot_primitives::Hash; - use sp_core::traits::SpawnNamed; - - struct AlwaysSupportsParachains; - - #[async_trait::async_trait] - impl HeadSupportsParachains for AlwaysSupportsParachains { - async fn head_supports_parachains(&self, _head: &Hash) -> bool { - true - } - } - - #[test] - fn forward_subsystem_works() { - let spawner = sp_core::testing::TaskExecutor::new(); - let (tx, rx) = mpsc::channel(2); - let (overseer, handle) = - dummy_overseer_builder(spawner.clone(), AlwaysSupportsParachains, None) - .unwrap() - .replace_collator_protocol(|_| ForwardSubsystem(tx)) - .build() - .unwrap(); - - let mut handle = Handle::new(handle); - - spawner.spawn("overseer", None, overseer.run().then(|_| async { () }).boxed()); - - block_on(handle.send_msg_anon(CollatorProtocolMessage::CollateOn(Default::default()))); - assert!(matches!( - block_on(rx.into_future()).0.unwrap(), - CollatorProtocolMessage::CollateOn(_) - )); - } #[test] fn macro_arbitrary_order() { diff --git a/polkadot/node/subsystem-test-helpers/src/mock.rs b/polkadot/node/subsystem-test-helpers/src/mock.rs index 04695983d1d..35d74e27c9c 100644 --- a/polkadot/node/subsystem-test-helpers/src/mock.rs +++ b/polkadot/node/subsystem-test-helpers/src/mock.rs @@ -16,12 +16,15 @@ use std::sync::Arc; +use polkadot_node_subsystem::{jaeger, ActivatedLeaf, LeafStatus}; +use sc_client_api::UnpinHandle; use sc_keystore::LocalKeystore; +use sc_utils::mpsc::tracing_unbounded; use sp_application_crypto::AppCrypto; use sp_keyring::Sr25519Keyring; use sp_keystore::{Keystore, KeystorePtr}; -use polkadot_primitives::{AuthorityDiscoveryId, ValidatorId}; +use polkadot_primitives::{AuthorityDiscoveryId, Block, BlockNumber, Hash, ValidatorId}; /// Get mock keystore with `Ferdie` key. pub fn make_ferdie_keystore() -> KeystorePtr { @@ -40,3 +43,20 @@ pub fn make_ferdie_keystore() -> KeystorePtr { .expect("Insert key into keystore"); keystore } + +/// Create a meaningless unpin handle for a block. +pub fn dummy_unpin_handle(block: Hash) -> UnpinHandle { + let (dummy_sink, _) = tracing_unbounded("Expect Chaos", 69); + UnpinHandle::new(block, dummy_sink) +} + +/// Create a new leaf with the given hash and number. +pub fn new_leaf(hash: Hash, number: BlockNumber) -> ActivatedLeaf { + ActivatedLeaf { + hash, + number, + status: LeafStatus::Fresh, + unpin_handle: dummy_unpin_handle(hash), + span: Arc::new(jaeger::Span::Disabled), + } +} diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 317b079a316..f6965cf647c 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -19,6 +19,7 @@ sc-network = { path = "../../../substrate/client/network" } sp-api = { path = "../../../substrate/primitives/api" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } +sc-client-api = { path = "../../../substrate/client/api" } sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } diff --git a/polkadot/node/subsystem-types/src/lib.rs b/polkadot/node/subsystem-types/src/lib.rs index f438a09592c..02651ace1e5 100644 --- a/polkadot/node/subsystem-types/src/lib.rs +++ b/polkadot/node/subsystem-types/src/lib.rs @@ -22,10 +22,19 @@ #![warn(missing_docs)] +use smallvec::SmallVec; use std::{fmt, sync::Arc}; -pub use polkadot_primitives::{BlockNumber, Hash}; -use smallvec::SmallVec; +pub use polkadot_primitives::{Block, BlockNumber, Hash}; + +/// Keeps the state of a specific block pinned in memory while the handle is alive. +/// +/// The handle is reference counted and once the last is dropped, the +/// block is unpinned. +/// +/// This is useful for runtime API calls to blocks that are +/// racing against finality, e.g. for slashing purposes. +pub type UnpinHandle = sc_client_api::UnpinHandle; pub mod errors; pub mod messages; @@ -80,6 +89,8 @@ pub struct ActivatedLeaf { pub number: BlockNumber, /// The status of the leaf. pub status: LeafStatus, + /// A handle to unpin the block on drop. + pub unpin_handle: UnpinHandle, /// An associated [`jaeger::Span`]. /// /// NOTE: Each span should only be kept active as long as the leaf is considered active and diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 204df0dad11..0d5ae7a0e8e 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -22,6 +22,7 @@ derive_more = "0.99.17" schnellru = "0.2.1" polkadot-node-subsystem = { path = "../subsystem" } +polkadot-node-subsystem-types = { path = "../subsystem-types" } polkadot-node-jaeger = { path = "../jaeger" } polkadot-node-metrics = { path = "../metrics" } polkadot-node-network-protocol = { path = "../network/protocol" } @@ -33,6 +34,7 @@ metered = { package = "prioritized-metered-channel", version = "0.2.0" } sp-core = { path = "../../../substrate/primitives/core" } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../substrate/primitives/keystore" } +sc-client-api = { path = "../../../substrate/client/api" } kvdb = "0.13.0" parity-db = { version = "0.4.8"} diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index fc767faa763..c078b17d217 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -28,6 +28,7 @@ use polkadot_node_subsystem::{ messages::{RuntimeApiMessage, RuntimeApiRequest}, overseer, SubsystemSender, }; +use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, @@ -75,6 +76,10 @@ pub struct RuntimeInfo { /// Look up cached sessions by `SessionIndex`. session_info_cache: LruMap, + /// Unpin handle of *some* block in the session. + /// Only blocks pinned explicitly by `pin_block` are stored here. + pinned_blocks: LruMap, + /// Key store for determining whether we are a validator and what `ValidatorIndex` we have. keystore: Option, } @@ -120,6 +125,7 @@ impl RuntimeInfo { Self { session_index_cache: LruMap::new(ByLength::new(cfg.session_cache_lru_size.max(10))), session_info_cache: LruMap::new(ByLength::new(cfg.session_cache_lru_size)), + pinned_blocks: LruMap::new(ByLength::new(cfg.session_cache_lru_size)), keystore: cfg.keystore, } } @@ -145,6 +151,17 @@ impl RuntimeInfo { } } + /// Pin a given block in the given session if none are pinned in that session. + /// Unpinning will happen automatically when LRU cache grows over the limit. + pub fn pin_block(&mut self, session_index: SessionIndex, unpin_handle: UnpinHandle) { + self.pinned_blocks.get_or_insert(session_index, || unpin_handle); + } + + /// Get the hash of a pinned block for the given session index, if any. + pub fn get_block_in_session(&self, session_index: SessionIndex) -> Option { + self.pinned_blocks.peek(&session_index).map(|h| h.hash()) + } + /// Get `ExtendedSessionInfo` by relay parent hash. pub async fn get_session_info<'a, Sender>( &'a mut self, -- GitLab From 09503b1d2d844d0d4f89ea936689a303feaf40da Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:39:53 +0200 Subject: [PATCH 099/633] [ci] Return publish-rustdoc (#1402) * [WIP][ci] Return publish-rustdoc * rm files * fix ref * add build doc * add comment * move test-deterministic-wasm to test stage * rm test-deterministic-wasm from root * test publish * enable pipeline * add test_deterministic_wasm.sh for resolving conflicts * rm unused bash script --- .github/pr-custom-review.yml | 2 +- .gitlab-ci.yml | 5 +-- .gitlab/pipeline/build.yml | 14 ++++---- .gitlab/pipeline/check.yml | 1 - .gitlab/pipeline/publish.yml | 54 ++++++++++++++++++++++++++++++ .gitlab/pipeline/test.yml | 12 +++++-- .gitlab/test_deterministic_wasm.sh | 17 ---------- 7 files changed, 71 insertions(+), 34 deletions(-) delete mode 100755 .gitlab/test_deterministic_wasm.sh diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 0d691e7aa2f..bc9a3cfb8d2 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -19,7 +19,7 @@ rules: 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$|^\.github/.* + 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/.* min_approvals: 2 teams: - core-devs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 748db808de6..99381fae9ec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -197,8 +197,6 @@ default: extends: .build-refs include: - # weights jobs - # - gitlab/pipeline/weights.yml # check jobs - .gitlab/pipeline/check.yml # test jobs @@ -211,11 +209,10 @@ include: - .gitlab/pipeline/publish.yml # zombienet jobs - .gitlab/pipeline/zombienet.yml - # # timestamp handler + # timestamp handler - project: parity/infrastructure/ci_cd/shared ref: v0.2 file: /common/timestamp.yml - # 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. diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 2d74187cadf..e34dd40e081 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -105,20 +105,18 @@ build-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - # artifacts: - # name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - # when: on_success - # expire_in: 1 days - # paths: - # - ./crate-docs/ + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" + when: on_success + expire_in: 1 days + paths: + - ./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 - # FIXME: remove me after CI image gets nonroot - - chown -R nonroot:nonroot ./crate-docs # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into # all .html files - | diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index f88f5808637..446f5dde12e 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -103,7 +103,6 @@ test-rust-feature-propagation: - zepter lint propagate-feature --feature try-runtime --left-side-feature-missing=ignore --workspace --feature-enables-dep="try-runtime:frame-try-runtime" --locked - zepter lint propagate-feature --feature runtime-benchmarks --left-side-feature-missing=ignore --workspace --feature-enables-dep="runtime-benchmarks:frame-benchmarking" --locked - zepter lint propagate-feature --feature std --left-side-feature-missing=ignore --workspace --locked - allow_failure: true # Experimental # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 .check-runtime-migration: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 341d3ac2a86..1a513e5970d 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -1,6 +1,60 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "publish" stage +publish-rustdoc: + stage: publish + extends: .kubernetes-env + variables: + CI_IMAGE: node:18 + GIT_DEPTH: 100 + RUSTDOCS_DEPLOY_REFS: "master" + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME == "master" + needs: + - job: build-rustdoc + artifacts: true + script: + # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we + # exit immediately. + # Putting spaces at the front and back to ensure we are not matching just any substring, but the + # whole space-separated value. + # setup ssh + - eval $(ssh-agent) + - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} + - mkdir ~/.ssh && touch ~/.ssh/known_hosts + - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts + # Set git config + - git config user.email "devops-team@parity.io" + - git config user.name "${GITHUB_USER}" + - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" + - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" + - git fetch origin gh-pages + # Save README and docs + - cp -r ./crate-docs/ /tmp/doc/ + - cp README.md /tmp/doc/ + # we don't need to commit changes because we copy docs to /tmp + - git checkout gh-pages --force + # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS + - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud + - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} + # Ensure the destination dir doesn't exist. + - rm -rf ${CI_COMMIT_REF_NAME} + - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} + # Upload files + - git add --all + # `git commit` has an exit code of > 0 if there is nothing to commit. + # This causes GitLab to exit immediately and marks this job failed. + # We don't want to mark the entire job failed if there's nothing to + # publish though, hence the `|| true`. + - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || + echo "___Nothing to commit___" + - git push origin gh-pages --force + after_script: + - rm -rf .git/ ./* + # cumulus .build-push-image: diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index cbb5a023272..406c87923cc 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -231,8 +231,6 @@ test-node-metrics: - time cargo test --profile testnet --locked --features=runtime-metrics -p polkadot-node-metrics > artifacts/log.txt - # FIXME! - allow_failure: true test-deterministic-wasm: stage: test @@ -244,7 +242,15 @@ test-deterministic-wasm: - job: test-frame-ui artifacts: false script: - - .gitlab/test_deterministic_wasm.sh + # build runtime + - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-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 + # confirm checksum + - sha256sum -c checksum.sha256 cargo-check-benches: stage: test diff --git a/.gitlab/test_deterministic_wasm.sh b/.gitlab/test_deterministic_wasm.sh deleted file mode 100755 index fac28fce1f6..00000000000 --- a/.gitlab/test_deterministic_wasm.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -set -e - -#shellcheck source=../common/lib.sh -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../.github/scripts/common/lib.sh" - -# build runtime -WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-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 -# confirm checksum -sha256sum -c checksum.sha256 -- GitLab From a36d409e67a409a4b532deaf849a97a038aed974 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 7 Sep 2023 18:53:31 +0200 Subject: [PATCH 100/633] [ci] change image for prdoc gha (#1452) --- .github/workflows/check-prdoc.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index 323be1d4e06..a9b53768227 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -5,9 +5,7 @@ on: types: [labeled, opened, synchronize, unlabeled] env: - # todo: switch to paritytech/prdoc once the container is built & published - # see https://github.com/paritytech/scripts/pull/595 - IMAGE: chevdor/prdoc:v0.0.4 + IMAGE: paritytech/prdoc:v0.0.5 API_BASE: https://api.github.com/repos REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -28,11 +26,11 @@ jobs: - name: Check if PRdoc is required id: get-labels run: | - # Fetch the labels for the PR under test - echo "Fetch the labels for $API_BASE/${REPO}/pulls/${GITHUB_PR}" - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - echo "Labels: ${labels}" - echo "labels=${labels}" >> "$GITHUB_OUTPUT" + # Fetch the labels for the PR under test + echo "Fetch the labels for $API_BASE/${REPO}/pulls/${GITHUB_PR}" + labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") + echo "Labels: ${labels}" + echo "labels=${labels}" >> "$GITHUB_OUTPUT" - name: No PRdoc required if: ${{ contains(steps.get-labels.outputs.labels, 'R0') }} -- GitLab From 594a8177585d87d7658b58dc4a729955c6fdd527 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Fri, 8 Sep 2023 11:43:04 +0200 Subject: [PATCH 101/633] Update Chrono to 0.4.30 (#1451) --- Cargo.lock | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a95a7e2561d..16403dccf36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,7 +617,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.27", + "time", ] [[package]] @@ -633,7 +633,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.27", + "time", ] [[package]] @@ -2345,15 +2345,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.27" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", - "time 0.1.45", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -13803,7 +13802,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring 0.16.20", - "time 0.3.27", + "time", "x509-parser 0.13.2", "yasna", ] @@ -13816,7 +13815,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring 0.16.20", - "time 0.3.27", + "time", "yasna", ] @@ -18775,17 +18774,6 @@ dependencies = [ "tikv-jemalloc-sys", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.27" @@ -19656,12 +19644,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -20164,7 +20146,7 @@ dependencies = [ "sha2 0.10.7", "stun", "thiserror", - "time 0.3.27", + "time", "tokio", "turn", "url", @@ -20772,7 +20754,7 @@ dependencies = [ "ring 0.16.20", "rusticata-macros", "thiserror", - "time 0.3.27", + "time", ] [[package]] @@ -20790,7 +20772,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.27", + "time", ] [[package]] @@ -20960,7 +20942,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.27", + "time", ] [[package]] -- GitLab From 3293ba71798209ccab640f2d00e8353e42b2285b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 11:49:18 +0200 Subject: [PATCH 102/633] Bump actions/cache from 3.3.1 to 3.3.2 (#1456) Bumps [actions/cache](https://github.com/actions/cache) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8...704facf57e6136b1bc63b828d79edcd491f0ee84) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-50_publish-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 0e466f26891..512b91aa6e5 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -96,7 +96,7 @@ jobs: fetch_release_artifacts - name: Cache the artifacts - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: key: artifacts-${{ env.BINARY }}-${{ github.sha }} path: | @@ -111,7 +111,7 @@ jobs: uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Get artifacts from cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: key: artifacts-${{ env.BINARY }}-${{ github.sha }} fail-on-cache-miss: true -- GitLab From bce7c2465cfa11cdf51f0160fafecc7ef02e5a75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 12:50:56 +0300 Subject: [PATCH 103/633] Bump hex-literal from 0.3.4 to 0.4.1 (#1438) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.3.4 to 0.4.1. - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.3.4...hex-literal-v0.4.1) --- updated-dependencies: - dependency-name: hex-literal dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 64 ++++++++++++++----------------- polkadot/node/core/pvf/Cargo.toml | 2 +- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16403dccf36..cd55371e601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,7 +737,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "kusama-runtime-constants", "log", "pallet-asset-conversion", @@ -833,7 +833,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -926,7 +926,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-asset-conversion", "pallet-asset-conversion-tx-payment", @@ -990,7 +990,7 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "frame-support", "frame-system", - "hex-literal 0.4.1", + "hex-literal", "pallet-assets", "pallet-balances", "pallet-collator-selection", @@ -1636,7 +1636,7 @@ dependencies = [ "finality-grandpa", "frame-support", "hex", - "hex-literal 0.4.1", + "hex-literal", "parity-scale-codec", "scale-info", "serde", @@ -1666,7 +1666,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal 0.4.1", + "hex-literal", "parity-scale-codec", "scale-info", "serde", @@ -1728,7 +1728,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal 0.4.1", + "hex-literal", "parity-scale-codec", "scale-info", "sp-runtime", @@ -1754,7 +1754,7 @@ dependencies = [ "frame-support", "frame-system", "hash-db", - "hex-literal 0.4.1", + "hex-literal", "impl-trait-for-tuples", "log", "num-traits", @@ -1832,7 +1832,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "kusama-runtime-constants", "log", "pallet-aura", @@ -1895,7 +1895,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-aura", "pallet-authorship", @@ -1990,7 +1990,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-aura", "pallet-authorship", @@ -2599,7 +2599,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-alliance", "pallet-aura", @@ -2814,7 +2814,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "kusama-runtime-constants", "log", "pallet-aura", @@ -3544,7 +3544,7 @@ dependencies = [ "environmental", "frame-support", "frame-system", - "hex-literal 0.4.1", + "hex-literal", "impl-trait-for-tuples", "lazy_static", "log", @@ -6003,12 +6003,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" - [[package]] name = "hex-literal" version = "0.4.1" @@ -10933,7 +10927,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-aura", "pallet-authorship", @@ -11017,7 +11011,7 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "frame-support", "frame-system", - "hex-literal 0.4.1", + "hex-literal", "pallet-assets", "pallet-balances", "pallet-collator-selection", @@ -11262,7 +11256,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -12060,7 +12054,7 @@ dependencies = [ "assert_matches", "futures", "futures-timer", - "hex-literal 0.3.4", + "hex-literal", "libc", "parity-scale-codec", "pin-project", @@ -12436,7 +12430,7 @@ dependencies = [ "frame-benchmarking-cli", "futures", "glutton-runtime", - "hex-literal 0.4.1", + "hex-literal", "jsonrpsee", "log", "nix 0.26.2", @@ -12527,7 +12521,7 @@ name = "polkadot-primitives" version = "1.0.0" dependencies = [ "bitvec", - "hex-literal 0.4.1", + "hex-literal", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", @@ -12604,7 +12598,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", @@ -12704,7 +12698,7 @@ dependencies = [ "frame-support", "frame-support-test", "frame-system", - "hex-literal 0.4.1", + "hex-literal", "impl-trait-for-tuples", "libsecp256k1", "log", @@ -12783,7 +12777,7 @@ dependencies = [ "frame-support-test", "frame-system", "futures", - "hex-literal 0.4.1", + "hex-literal", "impl-trait-for-tuples", "log", "pallet-authority-discovery", @@ -12839,7 +12833,7 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", - "hex-literal 0.4.1", + "hex-literal", "is_executable", "kusama-runtime-constants", "kvdb", @@ -13068,7 +13062,7 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", @@ -14142,7 +14136,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", @@ -17737,7 +17731,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "kusama-runtime-constants", "log", "pallet-authority-discovery", @@ -17884,7 +17878,7 @@ dependencies = [ "derivative", "environmental", "hex", - "hex-literal 0.4.1", + "hex-literal", "impl-trait-for-tuples", "log", "parity-scale-codec", @@ -20343,7 +20337,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.1", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index a265139d95c..ad9120295d2 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -44,7 +44,7 @@ substrate-build-script-utils = { path = "../../../../substrate/utils/build-scrip [dev-dependencies] assert_matches = "1.4.0" -hex-literal = "0.3.4" +hex-literal = "0.4.1" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } # For the puppet worker, depend on ourselves with the test-utils feature. polkadot-node-core-pvf = { path = ".", features = ["test-utils"] } -- GitLab From 92d7751b4ded03403be3589c507c81f2cc728d11 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Fri, 8 Sep 2023 12:14:57 +0200 Subject: [PATCH 104/633] Update ed25519-dalek to v2 (#1446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update to ed25519-dalek v2 * Update Cargo.lock * Remove default features * Update cumulus/bridges/primitives/test-utils/src/keyring.rs Co-authored-by: Bastian Köcher --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 35 ++++--------------- .../bridges/primitives/test-utils/Cargo.toml | 2 +- .../primitives/test-utils/src/keyring.rs | 24 +++---------- substrate/primitives/io/Cargo.toml | 2 +- 4 files changed, 13 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd55371e601..3ba7edafbda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1778,7 +1778,7 @@ dependencies = [ "bp-parachains", "bp-polkadot-core", "bp-runtime", - "ed25519-dalek 1.0.1", + "ed25519-dalek", "finality-grandpa", "parity-scale-codec", "sp-application-crypto", @@ -4560,15 +4560,6 @@ dependencies = [ "spki 0.7.2", ] -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature 1.6.4", -] - [[package]] name = "ed25519" version = "2.2.2" @@ -4579,20 +4570,6 @@ dependencies = [ "signature 2.1.0", ] -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek 3.2.0", - "ed25519 1.5.3", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "ed25519-dalek" version = "2.0.0" @@ -4600,7 +4577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek 4.0.0", - "ed25519 2.2.2", + "ed25519", "rand_core 0.6.4", "serde", "sha2 0.10.7", @@ -4628,7 +4605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e83e509bcd060ca4b54b72bde5bb306cb2088cb01e14797ebae90a24f70f5f7" dependencies = [ "curve25519-dalek 4.0.0", - "ed25519 2.2.2", + "ed25519", "hashbrown 0.14.0", "hex", "rand_core 0.6.4", @@ -7123,7 +7100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce" dependencies = [ "bs58 0.4.0", - "ed25519-dalek 2.0.0", + "ed25519-dalek", "log", "multiaddr", "multihash", @@ -17194,7 +17171,7 @@ name = "sp-io" version = "23.0.0" dependencies = [ "bytes", - "ed25519-dalek 2.0.0", + "ed25519-dalek", "libsecp256k1", "log", "parity-scale-codec", @@ -17481,7 +17458,7 @@ version = "4.0.0-dev" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 4.0.0", - "ed25519-dalek 2.0.0", + "ed25519-dalek", "hkdf", "parity-scale-codec", "rand 0.8.5", diff --git a/cumulus/bridges/primitives/test-utils/Cargo.toml b/cumulus/bridges/primitives/test-utils/Cargo.toml index fc6e5859141..f6e8533705e 100644 --- a/cumulus/bridges/primitives/test-utils/Cargo.toml +++ b/cumulus/bridges/primitives/test-utils/Cargo.toml @@ -12,7 +12,7 @@ bp-parachains = { path = "../parachains", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -ed25519-dalek = { version = "1.0", default-features = false, features = ["u64_backend"] } +ed25519-dalek = { version = "2.0", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false } sp-consensus-grandpa = { path = "../../../../substrate/primitives/consensus/grandpa", default-features = false } diff --git a/cumulus/bridges/primitives/test-utils/src/keyring.rs b/cumulus/bridges/primitives/test-utils/src/keyring.rs index b99132de3ec..eabf9c784eb 100644 --- a/cumulus/bridges/primitives/test-utils/src/keyring.rs +++ b/cumulus/bridges/primitives/test-utils/src/keyring.rs @@ -18,7 +18,7 @@ use bp_header_chain::{justification::JustificationVerificationContext, AuthoritySet}; use codec::Encode; -use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature}; +use ed25519_dalek::{Signature, SigningKey, VerifyingKey}; use finality_grandpa::voter_set::VoterSet; use sp_consensus_grandpa::{AuthorityId, AuthorityList, AuthorityWeight, SetId}; use sp_runtime::RuntimeDebug; @@ -37,29 +37,15 @@ pub const FERDIE: Account = Account(5); pub struct Account(pub u16); impl Account { - pub fn public(&self) -> PublicKey { - (&self.secret()).into() + pub fn public(&self) -> VerifyingKey { + self.pair().verifying_key() } - pub fn secret(&self) -> SecretKey { + pub fn pair(&self) -> SigningKey { let data = self.0.encode(); let mut bytes = [0_u8; 32]; bytes[0..data.len()].copy_from_slice(&data); - SecretKey::from_bytes(&bytes) - .expect("A static array of the correct length is a known good.") - } - - pub fn pair(&self) -> Keypair { - let mut pair: [u8; 64] = [0; 64]; - - let secret = self.secret(); - pair[..32].copy_from_slice(&secret.to_bytes()); - - let public = self.public(); - pair[32..].copy_from_slice(&public.to_bytes()); - - Keypair::from_bytes(&pair) - .expect("We expect the SecretKey to be good, so this must also be good.") + SigningKey::from_bytes(&bytes) } pub fn sign(&self, msg: &[u8]) -> Signature { diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 4793938617e..ab9d26ec26f 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -33,7 +33,7 @@ tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.28", default-features = false} # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. -ed25519-dalek = { version = "2.0.0", default-features = false, optional = true } +ed25519-dalek = { version = "2.0", default-features = false, optional = true } [build-dependencies] rustversion = "1.0.6" -- GitLab From c5f7abe27f24e67e33c516b9ddd5d91812451c37 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Fri, 8 Sep 2023 13:45:54 +0200 Subject: [PATCH 105/633] Switch prdoc to the latest image (#1460) --- .github/workflows/check-prdoc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index a9b53768227..d153184941a 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -5,7 +5,7 @@ on: types: [labeled, opened, synchronize, unlabeled] env: - IMAGE: paritytech/prdoc:v0.0.5 + IMAGE: paritytech/prdoc:latest API_BASE: https://api.github.com/repos REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -- GitLab From af3e56cd867dc14378b9c423d0db339ad9c73b15 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:56:19 +0200 Subject: [PATCH 106/633] RuntimeCode: doc fixed (#1461) --- substrate/primitives/core/src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/core/src/traits.rs b/substrate/primitives/core/src/traits.rs index 40137053ab7..9815c84f339 100644 --- a/substrate/primitives/core/src/traits.rs +++ b/substrate/primitives/core/src/traits.rs @@ -91,7 +91,7 @@ pub struct RuntimeCode<'a> { /// /// If `None` are given, the default value of the executor will be used. pub heap_pages: Option, - /// The SCALE encoded hash of `code`. + /// The hash of `code`. /// /// The hashing algorithm isn't that important, as long as all runtime /// code instances use the same. -- GitLab From bd0678a7e7470c91bdbc22c6e02119b7bd0c8edc Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 8 Sep 2023 16:57:16 +0100 Subject: [PATCH 107/633] FRAME: Consideration (abstraction over storage deposits) (#1361) * Consideration trait * Avoid associated type in Consideration * Update substrate/frame/support/src/traits/tokens/fungible/freeze.rs Co-authored-by: Francisco Aguirre * Update substrate/frame/support/src/traits/tokens/fungible/freeze.rs Co-authored-by: Francisco Aguirre * Update substrate/frame/support/src/traits/storage.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update substrate/frame/support/src/traits/tokens/fungible/mod.rs Co-authored-by: Oliver Tale-Yazdi * ".git/.scripts/commands/fmt/fmt.sh" * Add --------- Co-authored-by: Francisco Aguirre Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- substrate/frame/support/src/traits.rs | 9 +- .../frame/support/src/traits/messages.rs | 8 +- .../frame/support/src/traits/preimages.rs | 5 +- substrate/frame/support/src/traits/storage.rs | 76 ++++++- .../src/traits/tokens/fungible/freeze.rs | 57 +++++- .../src/traits/tokens/fungible/hold.rs | 56 +++++- .../support/src/traits/tokens/fungible/mod.rs | 188 ++++++++++++++++++ .../src/traits/tokens/fungibles/freeze.rs | 74 ++++++- .../src/traits/tokens/fungibles/hold.rs | 24 ++- .../frame/support/src/traits/tokens/misc.rs | 16 +- 10 files changed, 491 insertions(+), 22 deletions(-) diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index f669046f858..40e348b5e37 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -90,8 +90,8 @@ pub use hooks::{ pub mod schedule; mod storage; pub use storage::{ - Incrementable, Instance, PartialStorageInfoTrait, StorageInfo, StorageInfoTrait, - StorageInstance, TrackedStorageKey, WhitelistedStorageKeys, + Consideration, Footprint, Incrementable, Instance, PartialStorageInfoTrait, StorageInfo, + StorageInfoTrait, StorageInstance, TrackedStorageKey, WhitelistedStorageKeys, }; mod dispatch; @@ -111,9 +111,8 @@ pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, St mod messages; pub use messages::{ - EnqueueMessage, EnqueueWithOrigin, ExecuteOverweightError, Footprint, HandleMessage, - NoopServiceQueues, ProcessMessage, ProcessMessageError, QueuePausedQuery, ServiceQueues, - TransformOrigin, + EnqueueMessage, EnqueueWithOrigin, ExecuteOverweightError, HandleMessage, NoopServiceQueues, + ProcessMessage, ProcessMessageError, QueuePausedQuery, ServiceQueues, TransformOrigin, }; mod safe_mode; diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index 36fa7957dff..0db163e072b 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -17,6 +17,7 @@ //! Traits for managing message queuing and handling. +use super::storage::Footprint; use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::{ConstU32, Get, TypedGet}; @@ -115,13 +116,6 @@ impl ServiceQueues for NoopServiceQueues { } } -/// The resource footprint of a queue. -#[derive(Default, Copy, Clone, Eq, PartialEq, RuntimeDebug)] -pub struct Footprint { - pub count: u64, - pub size: u64, -} - /// Can enqueue messages for multiple origins. pub trait EnqueueMessage { /// The maximal length any enqueued message may have. diff --git a/substrate/frame/support/src/traits/preimages.rs b/substrate/frame/support/src/traits/preimages.rs index 3e78116202b..bf08a286dd7 100644 --- a/substrate/frame/support/src/traits/preimages.rs +++ b/substrate/frame/support/src/traits/preimages.rs @@ -18,6 +18,7 @@ //! Stuff for dealing with 32-byte 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}; @@ -29,9 +30,7 @@ pub type BoundedInline = crate::BoundedVec>; /// The maximum we expect a single legacy hash lookup to be. const MAX_LEGACY_LEN: u32 = 1_000_000; -#[derive( - Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug, -)] +#[derive(Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, RuntimeDebug)] #[codec(mel_bound())] pub enum Bounded { /// A Blake2 256 hash with no preimage length. We diff --git a/substrate/frame/support/src/traits/storage.rs b/substrate/frame/support/src/traits/storage.rs index 64eddf51b7f..cfa24d73f94 100644 --- a/substrate/frame/support/src/traits/storage.rs +++ b/substrate/frame/support/src/traits/storage.rs @@ -17,9 +17,14 @@ //! Traits for encoding data related to pallet's storage items. +use codec::{Encode, FullCodec, MaxEncodedLen}; use impl_trait_for_tuples::impl_for_tuples; +use scale_info::TypeInfo; pub use sp_core::storage::TrackedStorageKey; -use sp_runtime::{traits::Saturating, RuntimeDebug}; +use sp_runtime::{ + traits::{Member, Saturating}, + DispatchError, RuntimeDebug, +}; use sp_std::{collections::btree_set::BTreeSet, prelude::*}; /// An instance of a pallet in the storage. @@ -127,6 +132,75 @@ impl WhitelistedStorageKeys for Tuple { } } +/// The resource footprint of a bunch of blobs. We assume only the number of blobs and their total +/// size in bytes matter. +#[derive(Default, Copy, Clone, Eq, PartialEq, RuntimeDebug)] +pub struct Footprint { + /// The number of blobs. + pub count: u64, + /// The total size of the blobs in bytes. + pub size: u64, +} + +impl Footprint { + pub fn from_parts(items: usize, len: usize) -> Self { + Self { count: items as u64, size: len as u64 } + } + + pub fn from_encodable(e: impl Encode) -> Self { + Self::from_parts(1, e.encoded_size()) + } +} + +/// Some sort of cost taken from account temporarily in order to offset the cost to the chain of +/// holding some data [`Footprint`] in state. +/// +/// The cost may be increased, reduced or dropped entirely as the footprint changes. +/// +/// A single ticket corresponding to some particular datum held in storage. This is an opaque +/// type, but must itself be stored and generally it should be placed alongside whatever data +/// the ticket was created for. +/// +/// While not technically a linear type owing to the need for `FullCodec`, *this should be +/// treated as one*. Don't type to duplicate it, and remember to drop it when you're done with +/// it. +#[must_use] +pub trait Consideration: Member + FullCodec + TypeInfo + MaxEncodedLen { + /// Create a ticket for the `new` footprint attributable to `who`. This ticket *must* ultimately + /// be consumed through `update` or `drop` once the footprint changes or is removed. + fn new(who: &AccountId, new: Footprint) -> Result; + + /// Optionally consume an old ticket and alter the footprint, enforcing the new cost to `who` + /// and returning the new ticket (or an error if there was an issue). + /// + /// For creating tickets and dropping them, you can use the simpler `new` and `drop` instead. + fn update(self, who: &AccountId, new: Footprint) -> Result; + + /// Consume a ticket for some `old` footprint attributable to `who` which should now been freed. + fn drop(self, who: &AccountId) -> Result<(), DispatchError>; + + /// Consume a ticket for some `old` footprint attributable to `who` which should be sacrificed. + /// + /// This is infallible. In the general case (and it is left unimplemented), then it is + /// equivalent to the consideration never being dropped. Cases which can handle this properly + /// should implement, but it *MUST* rely on the loss of the consideration to the owner. + fn burn(self, _: &AccountId) { + let _ = self; + } +} + +impl Consideration for () { + fn new(_: &A, _: Footprint) -> Result { + Ok(()) + } + fn update(self, _: &A, _: Footprint) -> Result<(), DispatchError> { + Ok(()) + } + fn drop(self, _: &A) -> Result<(), DispatchError> { + Ok(()) + } +} + macro_rules! impl_incrementable { ($($type:ty),+) => { $( diff --git a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs index bc8f22b959c..8b542ee4c60 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs @@ -18,7 +18,13 @@ //! The traits for putting freezes within a single fungible token class. use scale_info::TypeInfo; -use sp_runtime::DispatchResult; +use sp_arithmetic::{ + traits::{CheckedAdd, CheckedSub}, + ArithmeticError, +}; +use sp_runtime::{DispatchResult, TokenError}; + +use crate::{ensure, traits::tokens::Fortitude}; /// Trait for inspecting a fungible asset which can be frozen. Freezing is essentially setting a /// minimum balance bellow which the total balance (inclusive of any funds placed on hold) may not @@ -65,4 +71,53 @@ pub trait Mutate: Inspect { /// Remove an existing lock. fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult; + + /// Attempt to alter the amount frozen under the given `id` to `amount`. + /// + /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is + /// `Fortitude::Force`. + fn set_frozen( + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult { + let force = fortitude == Fortitude::Force; + ensure!(force || Self::balance_freezable(who) >= amount, TokenError::FundsUnavailable); + Self::set_freeze(id, who, amount) + } + + /// Attempt to set the amount frozen under the given `id` to `amount`, iff this would increase + /// the amount frozen under `id`. Do nothing otherwise. + /// + /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is + /// `Fortitude::Force`. + fn ensure_frozen( + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult { + let force = fortitude == Fortitude::Force; + ensure!(force || Self::balance_freezable(who) >= amount, TokenError::FundsUnavailable); + Self::extend_freeze(id, who, amount) + } + + /// Decrease the amount which is being frozen for a particular freeze, failing in the case of + /// underflow. + fn decrease_frozen(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult { + let a = Self::balance_frozen(id, who) + .checked_sub(&amount) + .ok_or(ArithmeticError::Underflow)?; + Self::set_freeze(id, who, a) + } + + /// Increase the amount which is being frozen for a particular freeze, failing in the case that + /// too little balance is available for being frozen. + fn increase_frozen(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult { + let a = Self::balance_frozen(id, who) + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + Self::set_frozen(id, who, a, Fortitude::Polite) + } } diff --git a/substrate/frame/support/src/traits/tokens/fungible/hold.rs b/substrate/frame/support/src/traits/tokens/fungible/hold.rs index 15c046fbe9a..6da652d2998 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/hold.rs @@ -92,11 +92,11 @@ pub trait Inspect: super::Inspect { who: &AccountId, amount: Self::Balance, ) -> DispatchResult { - ensure!(Self::hold_available(reason, who), TokenError::CannotCreateHold); ensure!( amount <= Self::reducible_balance(who, Protect, Force), TokenError::FundsUnavailable ); + ensure!(Self::hold_available(reason, who), TokenError::CannotCreateHold); Ok(()) } @@ -242,6 +242,41 @@ pub trait Mutate: Ok(actual) } + /// Hold or release funds in the account of `who` to bring the balance on hold for `reason` to + /// exactly `amount`. + fn set_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + let current_amount = Self::balance_on_hold(reason, who); + if current_amount < amount { + Self::hold(reason, who, amount - current_amount) + } else if current_amount > amount { + Self::release(reason, who, current_amount - amount, Precision::Exact).map(|_| ()) + } else { + Ok(()) + } + } + + /// Release all funds in the account of `who` on hold for `reason`. + /// + /// The actual amount released is returned with `Ok`. + /// + /// If `precision` is `BestEffort`, then the amount actually unreserved and returned as the + /// inner value of `Ok` may be smaller than the `amount` passed. + /// + /// NOTE! The inner of the `Ok` result variant returns the *actual* amount released. This is the + /// opposite of the `ReservableCurrency::unreserve()` result, which gives the amount not able + /// to be released! + fn release_all( + reason: &Self::Reason, + who: &AccountId, + precision: Precision, + ) -> Result { + Self::release(reason, who, Self::balance_on_hold(reason, who), precision) + } + /// Attempt to decrease the balance of `who` which is held for the given `reason` by `amount`. /// /// If `precision` is `BestEffort`, then as much as possible is reduced, up to `amount`, and the @@ -271,6 +306,25 @@ pub trait Mutate: Ok(amount) } + /// Attempt to decrease the balance of `who` which is held for the given `reason` to zero. + /// + /// If `precision` is `BestEffort`, then as much as possible is reduced, up to `amount`, and the + /// amount of tokens reduced is returned. Otherwise, if the total amount can be reduced, then it + /// is and the amount returned, and if not, then nothing changes and `Err` is returned. + /// + /// If `force` is `Force`, then locks/freezes will be ignored. This should only be used when + /// conducting slashing or other activity which materially disadvantages the account holder + /// since it could provide a means of circumventing freezes. + fn burn_all_held( + reason: &Self::Reason, + who: &AccountId, + precision: Precision, + force: Fortitude, + ) -> Result { + let amount = Self::balance_on_hold(reason, who); + Self::burn_held(reason, who, amount, precision, force) + } + /// Transfer held funds into a destination account. /// /// If `mode` is `OnHold`, then the destination account must already exist and the assets diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index 2205fd5dc58..61b75fd6563 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -45,6 +45,15 @@ mod imbalance; mod item_of; mod regular; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support_procedural::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use scale_info::TypeInfo; +use sp_std::marker::PhantomData; + +use super::{ + Fortitude::{Force, Polite}, + Precision::BestEffort, +}; pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze}; pub use hold::{ Balanced as BalancedHold, Inspect as InspectHold, Mutate as MutateHold, @@ -55,3 +64,182 @@ pub use item_of::ItemOf; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; +use sp_arithmetic::traits::Zero; +use sp_core::Get; +use sp_runtime::{traits::Convert, DispatchError}; + +use crate::{ + ensure, + traits::{Consideration, Footprint}, +}; + +/// Consideration method using a `fungible` balance frozen as the cost exacted for the footprint. +/// +/// The aggregate amount frozen under `R::get()` for any account which has multiple tickets, +/// is the *cumulative* amounts of each ticket's footprint (each individually determined by `D`). +#[derive( + CloneNoBound, + EqNoBound, + PartialEqNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(A, F, R, D))] +#[codec(mel_bound())] +pub struct FreezeConsideration(F::Balance, PhantomData (A, R, D)>) +where + F: MutateFreeze; +impl< + A: 'static, + F: 'static + MutateFreeze, + R: 'static + Get, + D: 'static + Convert, + > Consideration for FreezeConsideration +{ + fn new(who: &A, footprint: Footprint) -> Result { + let new = D::convert(footprint); + F::increase_frozen(&R::get(), who, new)?; + Ok(Self(new, PhantomData)) + } + fn update(self, who: &A, footprint: Footprint) -> Result { + let new = D::convert(footprint); + if self.0 > new { + F::decrease_frozen(&R::get(), who, self.0 - new)?; + } else if new > self.0 { + F::increase_frozen(&R::get(), who, new - self.0)?; + } + Ok(Self(new, PhantomData)) + } + fn drop(self, who: &A) -> Result<(), DispatchError> { + F::decrease_frozen(&R::get(), who, self.0).map(|_| ()) + } +} + +/// Consideration method using a `fungible` balance frozen as the cost exacted for the footprint. +#[derive( + CloneNoBound, + EqNoBound, + PartialEqNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(A, F, R, D))] +#[codec(mel_bound())] +pub struct HoldConsideration(F::Balance, PhantomData (A, R, D)>) +where + F: MutateHold; +impl< + A: 'static, + F: 'static + MutateHold, + R: 'static + Get, + D: 'static + Convert, + > Consideration for HoldConsideration +{ + fn new(who: &A, footprint: Footprint) -> Result { + let new = D::convert(footprint); + F::hold(&R::get(), who, new)?; + Ok(Self(new, PhantomData)) + } + fn update(self, who: &A, footprint: Footprint) -> Result { + let new = D::convert(footprint); + if self.0 > new { + F::release(&R::get(), who, self.0 - new, BestEffort)?; + } else if new > self.0 { + F::hold(&R::get(), who, new - self.0)?; + } + Ok(Self(new, PhantomData)) + } + fn drop(self, who: &A) -> Result<(), DispatchError> { + F::release(&R::get(), who, self.0, BestEffort).map(|_| ()) + } + fn burn(self, who: &A) { + let _ = F::burn_held(&R::get(), who, self.0, BestEffort, Force); + } +} + +/// Basic consideration method using a `fungible` balance frozen as the cost exacted for the +/// footprint. +/// +/// NOTE: This is an optimized implementation, which can only be used for systems where each +/// account has only a single active ticket associated with it since individual tickets do not +/// track the specific balance which is frozen. If you are uncertain then use `FreezeConsideration` +/// instead, since this works in all circumstances. +#[derive( + CloneNoBound, + EqNoBound, + PartialEqNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(A, Fx, Rx, D))] +#[codec(mel_bound())] +pub struct LoneFreezeConsideration(PhantomData (A, Fx, Rx, D)>); +impl< + A: 'static, + Fx: 'static + MutateFreeze, + Rx: 'static + Get, + D: 'static + Convert, + > Consideration for LoneFreezeConsideration +{ + fn new(who: &A, footprint: Footprint) -> Result { + ensure!(Fx::balance_frozen(&Rx::get(), who).is_zero(), DispatchError::Unavailable); + Fx::set_frozen(&Rx::get(), who, D::convert(footprint), Polite).map(|_| Self(PhantomData)) + } + fn update(self, who: &A, footprint: Footprint) -> Result { + Fx::set_frozen(&Rx::get(), who, D::convert(footprint), Polite).map(|_| Self(PhantomData)) + } + fn drop(self, who: &A) -> Result<(), DispatchError> { + Fx::thaw(&Rx::get(), who).map(|_| ()) + } +} + +/// Basic consideration method using a `fungible` balance placed on hold as the cost exacted for the +/// footprint. +/// +/// NOTE: This is an optimized implementation, which can only be used for systems where each +/// account has only a single active ticket associated with it since individual tickets do not +/// track the specific balance which is frozen. If you are uncertain then use `FreezeConsideration` +/// instead, since this works in all circumstances. +#[derive( + CloneNoBound, + EqNoBound, + PartialEqNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(A, Fx, Rx, D))] +#[codec(mel_bound())] +pub struct LoneHoldConsideration(PhantomData (A, Fx, Rx, D)>); +impl< + A: 'static, + F: 'static + MutateHold, + R: 'static + Get, + D: 'static + Convert, + > Consideration for LoneHoldConsideration +{ + fn new(who: &A, footprint: Footprint) -> Result { + ensure!(F::balance_on_hold(&R::get(), who).is_zero(), DispatchError::Unavailable); + F::set_on_hold(&R::get(), who, D::convert(footprint)).map(|_| Self(PhantomData)) + } + fn update(self, who: &A, footprint: Footprint) -> Result { + F::set_on_hold(&R::get(), who, D::convert(footprint)).map(|_| Self(PhantomData)) + } + fn drop(self, who: &A) -> Result<(), DispatchError> { + F::release_all(&R::get(), who, BestEffort).map(|_| ()) + } + fn burn(self, who: &A) { + let _ = F::burn_all_held(&R::get(), who, BestEffort, Force); + } +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs index 88f083b0a21..b07d20d6c41 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs @@ -17,8 +17,13 @@ //! The traits for putting freezes within a single fungible token class. +use crate::{ensure, traits::tokens::Fortitude}; use scale_info::TypeInfo; -use sp_runtime::DispatchResult; +use sp_arithmetic::{ + traits::{CheckedAdd, CheckedSub}, + ArithmeticError, +}; +use sp_runtime::{DispatchResult, TokenError}; /// Trait for inspecting a fungible asset which can be frozen. Freezing is essentially setting a /// minimum balance below which the total balance (inclusive of any funds placed on hold) may not @@ -75,4 +80,71 @@ pub trait Mutate: Inspect { /// Remove an existing lock. fn thaw(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> DispatchResult; + + /// Attempt to alter the amount frozen under the given `id` to `amount`. + /// + /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is + /// `Fortitude::Force`. + fn set_frozen( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult { + let force = fortitude == Fortitude::Force; + ensure!( + force || Self::balance_freezable(asset.clone(), who) >= amount, + TokenError::FundsUnavailable + ); + Self::set_freeze(asset, id, who, amount) + } + + /// Attempt to set the amount frozen under the given `id` to `amount`, iff this would increase + /// the amount frozen under `id`. Do nothing otherwise. + /// + /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is + /// `Fortitude::Force`. + fn ensure_frozen( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult { + let force = fortitude == Fortitude::Force; + ensure!( + force || Self::balance_freezable(asset.clone(), who) >= amount, + TokenError::FundsUnavailable + ); + Self::extend_freeze(asset, id, who, amount) + } + + /// Decrease the amount which is being frozen for a particular lock, failing in the case of + /// underflow. + fn decrease_frozen( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + let a = Self::balance_frozen(asset.clone(), id, who) + .checked_sub(&amount) + .ok_or(ArithmeticError::Underflow)?; + Self::set_frozen(asset, id, who, a, Fortitude::Polite) + } + + /// Increase the amount which is being frozen for a particular lock, failing in the case that + /// too little balance is available for being frozen. + fn increase_frozen( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + let a = Self::balance_frozen(asset.clone(), id, who) + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + Self::set_frozen(asset, id, who, a, Fortitude::Polite) + } } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs index 4f86704df16..1efd1594213 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs @@ -301,7 +301,8 @@ pub trait Mutate: Ok(actual) } - /// Attempt to decrease the balance of `who` which is held for the given `reason` by `amount`. + /// Attempt to decrease the `asset` balance of `who` which is held for the given `reason` by + /// `amount`. /// /// If `precision` is true, then as much as possible is reduced, up to `amount`, and the /// amount of tokens reduced is returned. Otherwise, if the total amount can be reduced, then it @@ -334,6 +335,27 @@ pub trait Mutate: Ok(amount) } + /// Attempt to decrease the `asset` balance of `who` which is held for the given `reason` to + /// zero. + /// + /// If `precision` is `BestEffort`, then as much as possible is reduced, up to `amount`, and the + /// amount of tokens reduced is returned. Otherwise, if the total amount can be reduced, then it + /// is and the amount returned, and if not, then nothing changes and `Err` is returned. + /// + /// If `force` is `Force`, then locks/freezes will be ignored. This should only be used when + /// conducting slashing or other activity which materially disadvantages the account holder + /// since it could provide a means of circumventing freezes. + fn burn_all_held( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + precision: Precision, + force: Fortitude, + ) -> Result { + let amount = Self::balance_on_hold(asset.clone(), reason, who); + Self::burn_held(asset, reason, who, amount, precision, force) + } + /// Transfer held funds into a destination account. /// /// If `mode` is `OnHold`, then the destination account must already exist and the assets diff --git a/substrate/frame/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index baf3fd5f354..84bbe3e8d9c 100644 --- a/substrate/frame/support/src/traits/tokens/misc.rs +++ b/substrate/frame/support/src/traits/tokens/misc.rs @@ -231,7 +231,16 @@ impl Balance for T { } -- GitLab From 60d1a0bdc3abd3e319666d37c3c0599fc4486792 Mon Sep 17 00:00:00 2001 From: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Fri, 8 Sep 2023 19:05:01 +0300 Subject: [PATCH 108/633] lookahead collator: read allowed ancestry len from relay client (#1180) * Read allowed ancestry len from active config * extract load_abridged_host_configuration --------- Co-authored-by: Javier Viola --- .../consensus/aura/src/collators/lookahead.rs | 37 +++++++++++++------ cumulus/client/consensus/common/src/lib.rs | 19 +++++++++- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 58d8e9d1a06..b1a7cde55c2 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -34,7 +34,8 @@ use codec::{Codec, Encode}; use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; use cumulus_client_consensus_common::{ - self as consensus_common, ParachainBlockImportMarker, ParentSearchParams, + self as consensus_common, load_abridged_host_configuration, ParachainBlockImportMarker, + ParentSearchParams, }; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; @@ -416,16 +417,30 @@ where Some(SlotClaim::unchecked::

(author_pub, slot, timestamp)) } +/// Reads allowed ancestry length parameter from the relay chain storage at the given relay parent. +/// +/// Falls back to 0 in case of an error. async fn max_ancestry_lookback( - _relay_parent: PHash, - _relay_client: &impl RelayChainInterface, + relay_parent: PHash, + relay_client: &impl RelayChainInterface, ) -> usize { - // TODO [https://github.com/paritytech/cumulus/issues/2706] - // We need to read the relay-chain state to know what the maximum - // age truly is, but that depends on those pallets existing. - // - // For now, just provide the conservative value of '2'. - // Overestimating can cause problems, as we'd be building on forks of the - // chain that can never get included. Underestimating is less of an issue. - 2 + match load_abridged_host_configuration(relay_parent, relay_client).await { + Ok(Some(config)) => config.async_backing_params.allowed_ancestry_len as usize, + Ok(None) => { + tracing::error!( + target: crate::LOG_TARGET, + "Active config is missing in relay chain storage", + ); + 0 + }, + Err(err) => { + tracing::error!( + target: crate::LOG_TARGET, + ?err, + ?relay_parent, + "Failed to read active config from relay chain client", + ); + 0 + }, + } } diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index edd97cf02a2..29ee7356ee2 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -20,8 +20,8 @@ use polkadot_primitives::{ }; use cumulus_primitives_core::{ - relay_chain::{BlockId as RBlockId, OccupiedCoreAssumption}, - ParaId, + relay_chain::{self, BlockId as RBlockId, OccupiedCoreAssumption}, + AbridgedHostConfiguration, ParaId, }; use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; @@ -412,3 +412,18 @@ pub fn relay_slot_and_timestamp( }) .ok() } + +/// Reads abridged host configuration from the relay chain storage at the given relay parent. +pub async fn load_abridged_host_configuration( + relay_parent: PHash, + relay_client: &impl RelayChainInterface, +) -> Result, RelayChainError> { + relay_client + .get_storage_by_key(relay_parent, relay_chain::well_known_keys::ACTIVE_CONFIG) + .await? + .map(|bytes| { + AbridgedHostConfiguration::decode(&mut &bytes[..]) + .map_err(RelayChainError::DeserializationError) + }) + .transpose() +} -- GitLab From 8dce0ad2a35907e92ab663e737c55b33a857c234 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 8 Sep 2023 19:48:17 +0200 Subject: [PATCH 109/633] Use sp_std Vec in no-std crate (#1471) --- substrate/primitives/crypto/ec-utils/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/crypto/ec-utils/src/lib.rs b/substrate/primitives/crypto/ec-utils/src/lib.rs index c1877dd5b5d..22e24e61f7b 100644 --- a/substrate/primitives/crypto/ec-utils/src/lib.rs +++ b/substrate/primitives/crypto/ec-utils/src/lib.rs @@ -21,6 +21,9 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + pub mod bls12_377; pub mod bls12_381; pub mod bw6_761; @@ -28,8 +31,6 @@ pub mod ed_on_bls12_377; pub mod ed_on_bls12_381_bandersnatch; mod utils; -use sp_runtime_interface::runtime_interface; - /// 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}; -- GitLab From 6b3aa7d23e75ef110790d013f58caf2b01a18b77 Mon Sep 17 00:00:00 2001 From: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:28:07 -0700 Subject: [PATCH 110/633] Handle `CollationSeconded` Logs Conditionally (#1475) * Removing unnecessary log * Drop unneeded log * Handling logs conditionally * Changing unexpected message to warn * Back to debug * fmt --- .../src/collator_side/mod.rs | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) 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 96978f39a53..ad2ab99568c 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -926,16 +926,42 @@ async fn handle_incoming_peer_message( target: LOG_TARGET, ?statement, ?origin, - "received a valid `CollationSeconded`", + "received a valid `CollationSeconded`, forwarding result to collator", ); let _ = sender.send(CollationSecondedSignal { statement, relay_parent }); } else { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?&statement.payload().candidate_hash(), - ?origin, - "received an unexpected `CollationSeconded`: unknown statement", - ); + // Checking whether the `CollationSeconded` statement is unexpected + let relay_parent = match state.per_relay_parent.get(&relay_parent) { + Some(per_relay_parent) => per_relay_parent, + None => { + gum::debug!( + target: LOG_TARGET, + candidate_relay_parent = %relay_parent, + candidate_hash = ?&statement.payload().candidate_hash(), + "Seconded statement relay parent is out of our view", + ); + return Ok(()) + }, + }; + match relay_parent.collations.get(&statement.payload().candidate_hash()) { + Some(_) => { + // We've seen this collation before, so a seconded statement is expected + gum::trace!( + target: LOG_TARGET, + ?statement, + ?origin, + "received a valid `CollationSeconded`", + ); + }, + None => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?&statement.payload().candidate_hash(), + ?origin, + "received an unexpected `CollationSeconded`: unknown statement", + ); + }, + } } } }, -- GitLab From 9bfb6529d1c01d46617a8ac2ab1a6699107004a5 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Sat, 9 Sep 2023 11:35:26 +0200 Subject: [PATCH 111/633] Introduce `default-members` to the workspace root (#1420) --- .gitlab/pipeline/build.yml | 10 +++++----- .gitlab/pipeline/check.yml | 2 +- .gitlab/pipeline/test.yml | 6 +++--- Cargo.toml | 1 + polkadot/Cargo.toml | 1 + 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index e34dd40e081..c4dfc0dd093 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -163,7 +163,7 @@ build-short-benchmark: - .run-immediately - .collect-artifacts script: - - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot + - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot --workspace - mkdir -p artifacts - target/release/polkadot --version - cp ./target/release/polkadot ./artifacts/ @@ -183,7 +183,7 @@ build-linux-stable-cumulus: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" - - time cargo build --release --locked --bin polkadot-parachain + - time cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain - echo "___Packing the artifacts___" - mkdir -p ./artifacts - mv ./target/release/polkadot-parachain ./artifacts/. @@ -203,7 +203,7 @@ build-test-parachain: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" - - time cargo build --release --locked --bin test-parachain + - time cargo build --release --locked -p cumulus-test-service --bin test-parachain - echo "___Packing the artifacts___" - mkdir -p ./artifacts - mv ./target/release/test-parachain ./artifacts/. @@ -290,7 +290,7 @@ build-short-benchmark-cumulus: - .run-immediately - .collect-artifacts script: - - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot-parachain + - cargo build --profile release --locked --features=runtime-benchmarks -p polkadot-parachain-bin --bin polkadot-parachain - mkdir -p artifacts - target/release/polkadot-parachain --version - cp ./target/release/polkadot-parachain ./artifacts/ @@ -316,7 +316,7 @@ build-linux-substrate: # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" script: - - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release + - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release -p node-cli - mv $CARGO_TARGET_DIR/release/substrate-node ./artifacts/substrate/substrate - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 446f5dde12e..5cc2337bf40 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -19,7 +19,7 @@ check-try-runtime: - time cargo check --locked -p parachain-template-node --features try-runtime # add after https://github.com/paritytech/substrate/pull/14502 is merged # experimental code may rely on try-runtime and vice-versa - - time cargo check --locked --features try-runtime,experimental + - time cargo check --locked --all --features try-runtime,experimental cargo-fmt-manifest: stage: check diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 406c87923cc..b29574ad14d 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -121,7 +121,7 @@ test-linux-stable-runtime-benchmarks: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - time cargo nextest run --features runtime-benchmarks benchmark --locked --cargo-profile testnet + - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet # these ones can be really slow so it's better to run them separately test-linux-stable-slow: @@ -185,7 +185,7 @@ test-doc: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - time cargo test --doc + - time cargo test --doc --workspace test-rustdoc: stage: test @@ -368,7 +368,7 @@ quick-benchmarks: WASM_BUILD_NO_COLOR: 1 WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" script: - - time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - time cargo run --locked --release -p node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 test-frame-examples-compile-to-wasm: # into one job diff --git a/Cargo.toml b/Cargo.toml index 4db27b98e90..8a9c2afe1d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -452,6 +452,7 @@ members = [ "substrate/utils/prometheus", "substrate/utils/wasm-builder", ] +default-members = [ "polkadot" ] [profile.release] # Polkadot runtime requires unwinding. diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index f173557a0ff..b9c132bbff9 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -19,6 +19,7 @@ readme = "README.md" authors.workspace = true edition.workspace = true version = "1.0.0" +default-run = "polkadot" [dependencies] color-eyre = { version = "0.6.1", default-features = false } -- GitLab From fbf5a814f07b10ad47ddf699a8b6a97fe53d8c66 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 9 Sep 2023 16:29:45 +0200 Subject: [PATCH 112/633] Remove `SafeCallFilter` from Relay Runtimes (#1303) * Remove SafeCallFilter from relay runtimes The relays do not suffer from PoV bloat, so we dont need a SafeCallFilter here. Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- polkadot/runtime/kusama/src/xcm_config.rs | 160 +------------------- polkadot/runtime/polkadot/src/xcm_config.rs | 149 +----------------- polkadot/runtime/rococo/src/xcm_config.rs | 141 +---------------- polkadot/runtime/westend/src/xcm_config.rs | 123 +-------------- 4 files changed, 14 insertions(+), 559 deletions(-) diff --git a/polkadot/runtime/kusama/src/xcm_config.rs b/polkadot/runtime/kusama/src/xcm_config.rs index c90e6c55a94..6a9cea22bbc 100644 --- a/polkadot/runtime/kusama/src/xcm_config.rs +++ b/polkadot/runtime/kusama/src/xcm_config.rs @@ -23,13 +23,12 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; use kusama_runtime_constants::currency::CENTS; use runtime_common::{ - crowdloan, paras_registrar, xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, }; @@ -44,7 +43,6 @@ use xcm_builder::{ SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::traits::WithOriginFilter; parameter_types! { /// The location of the KSM token, from the context of this chain. Since this token is native to this @@ -161,158 +159,6 @@ pub type Barrier = TrailingSetTopicAsId<( >, )>; -/// 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 - } - } - - match call { - RuntimeCall::System( - frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. }, - ) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(..) | - RuntimeCall::Balances(..) | - RuntimeCall::Crowdloan( - crowdloan::Call::create { .. } | - crowdloan::Call::contribute { .. } | - crowdloan::Call::withdraw { .. } | - crowdloan::Call::refund { .. } | - crowdloan::Call::dissolve { .. } | - crowdloan::Call::edit { .. } | - crowdloan::Call::poke { .. } | - crowdloan::Call::contribute_all { .. }, - ) | - RuntimeCall::Staking( - pallet_staking::Call::bond { .. } | - pallet_staking::Call::bond_extra { .. } | - pallet_staking::Call::unbond { .. } | - pallet_staking::Call::withdraw_unbonded { .. } | - pallet_staking::Call::validate { .. } | - pallet_staking::Call::nominate { .. } | - pallet_staking::Call::chill { .. } | - pallet_staking::Call::set_payee { .. } | - pallet_staking::Call::set_controller { .. } | - pallet_staking::Call::set_validator_count { .. } | - pallet_staking::Call::increase_validator_count { .. } | - pallet_staking::Call::scale_validator_count { .. } | - pallet_staking::Call::force_no_eras { .. } | - pallet_staking::Call::force_new_era { .. } | - pallet_staking::Call::set_invulnerables { .. } | - pallet_staking::Call::force_unstake { .. } | - pallet_staking::Call::force_new_era_always { .. } | - pallet_staking::Call::payout_stakers { .. } | - pallet_staking::Call::rebond { .. } | - pallet_staking::Call::reap_stash { .. } | - pallet_staking::Call::set_staking_configs { .. } | - pallet_staking::Call::chill_other { .. } | - pallet_staking::Call::force_apply_min_commission { .. }, - ) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda( - pallet_referenda::Call::place_decision_deposit { .. } | - pallet_referenda::Call::refund_decision_deposit { .. } | - pallet_referenda::Call::cancel { .. } | - pallet_referenda::Call::kill { .. } | - pallet_referenda::Call::nudge_referendum { .. } | - pallet_referenda::Call::one_fewer_deciding { .. }, - ) | - RuntimeCall::FellowshipCollective(..) | - RuntimeCall::FellowshipReferenda( - pallet_referenda::Call::place_decision_deposit { .. } | - pallet_referenda::Call::refund_decision_deposit { .. } | - pallet_referenda::Call::cancel { .. } | - pallet_referenda::Call::kill { .. } | - pallet_referenda::Call::nudge_referendum { .. } | - pallet_referenda::Call::one_fewer_deciding { .. }, - ) | - RuntimeCall::Claims( - super::claims::Call::claim { .. } | - super::claims::Call::mint_claim { .. } | - super::claims::Call::move_claim { .. }, - ) | - RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | - RuntimeCall::Identity( - pallet_identity::Call::add_registrar { .. } | - pallet_identity::Call::set_identity { .. } | - pallet_identity::Call::clear_identity { .. } | - pallet_identity::Call::request_judgement { .. } | - pallet_identity::Call::cancel_request { .. } | - pallet_identity::Call::set_fee { .. } | - pallet_identity::Call::set_account_id { .. } | - pallet_identity::Call::set_fields { .. } | - pallet_identity::Call::provide_judgement { .. } | - pallet_identity::Call::kill_identity { .. } | - pallet_identity::Call::add_sub { .. } | - pallet_identity::Call::rename_sub { .. } | - pallet_identity::Call::remove_sub { .. } | - pallet_identity::Call::quit_sub { .. }, - ) | - RuntimeCall::Society(..) | - RuntimeCall::Recovery(..) | - RuntimeCall::Vesting(..) | - RuntimeCall::Bounties( - pallet_bounties::Call::propose_bounty { .. } | - pallet_bounties::Call::approve_bounty { .. } | - pallet_bounties::Call::propose_curator { .. } | - pallet_bounties::Call::unassign_curator { .. } | - pallet_bounties::Call::accept_curator { .. } | - pallet_bounties::Call::award_bounty { .. } | - pallet_bounties::Call::claim_bounty { .. } | - pallet_bounties::Call::close_bounty { .. }, - ) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ElectionProviderMultiPhase(..) | - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools( - pallet_nomination_pools::Call::join { .. } | - pallet_nomination_pools::Call::bond_extra { .. } | - pallet_nomination_pools::Call::claim_payout { .. } | - pallet_nomination_pools::Call::unbond { .. } | - pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | - pallet_nomination_pools::Call::withdraw_unbonded { .. } | - pallet_nomination_pools::Call::create { .. } | - pallet_nomination_pools::Call::create_with_pool_id { .. } | - pallet_nomination_pools::Call::set_state { .. } | - pallet_nomination_pools::Call::set_configs { .. } | - pallet_nomination_pools::Call::update_roles { .. } | - pallet_nomination_pools::Call::chill { .. }, - ) | - RuntimeCall::Hrmp(..) | - RuntimeCall::Registrar( - paras_registrar::Call::deregister { .. } | - paras_registrar::Call::swap { .. } | - paras_registrar::Call::remove_lock { .. } | - paras_registrar::Call::reserve { .. } | - paras_registrar::Call::add_lock { .. }, - ) | - RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets { - .. - }) | - RuntimeCall::Whitelist(pallet_whitelist::Call::whitelist_call { .. }) | - RuntimeCall::Proxy(..) => true, - _ => false, - } - } -} - pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -343,8 +189,8 @@ impl xcm_executor::Config for XcmConfig { // No bridges yet... type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; } diff --git a/polkadot/runtime/polkadot/src/xcm_config.rs b/polkadot/runtime/polkadot/src/xcm_config.rs index 6c45f1cec40..c7b15f7256b 100644 --- a/polkadot/runtime/polkadot/src/xcm_config.rs +++ b/polkadot/runtime/polkadot/src/xcm_config.rs @@ -23,7 +23,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -32,7 +32,6 @@ use polkadot_runtime_constants::{ currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, }; use runtime_common::{ - crowdloan, paras_registrar, xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, }; @@ -46,7 +45,6 @@ use xcm_builder::{ SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::traits::WithOriginFilter; parameter_types! { /// The location of the DOT token, from the context of this chain. Since this token is native to this @@ -172,147 +170,6 @@ pub type Barrier = TrailingSetTopicAsId<( >, )>; -/// 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 - } - } - - match call { - RuntimeCall::System( - frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. }, - ) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(..) | - RuntimeCall::Balances(..) | - RuntimeCall::Crowdloan( - crowdloan::Call::create { .. } | - crowdloan::Call::contribute { .. } | - crowdloan::Call::withdraw { .. } | - crowdloan::Call::refund { .. } | - crowdloan::Call::dissolve { .. } | - crowdloan::Call::edit { .. } | - crowdloan::Call::poke { .. } | - crowdloan::Call::contribute_all { .. }, - ) | - RuntimeCall::Staking( - pallet_staking::Call::bond { .. } | - pallet_staking::Call::bond_extra { .. } | - pallet_staking::Call::unbond { .. } | - pallet_staking::Call::withdraw_unbonded { .. } | - pallet_staking::Call::validate { .. } | - pallet_staking::Call::nominate { .. } | - pallet_staking::Call::chill { .. } | - pallet_staking::Call::set_payee { .. } | - pallet_staking::Call::set_controller { .. } | - pallet_staking::Call::set_validator_count { .. } | - pallet_staking::Call::increase_validator_count { .. } | - pallet_staking::Call::scale_validator_count { .. } | - pallet_staking::Call::force_no_eras { .. } | - pallet_staking::Call::force_new_era { .. } | - pallet_staking::Call::set_invulnerables { .. } | - pallet_staking::Call::force_unstake { .. } | - pallet_staking::Call::force_new_era_always { .. } | - pallet_staking::Call::payout_stakers { .. } | - pallet_staking::Call::rebond { .. } | - pallet_staking::Call::reap_stash { .. } | - pallet_staking::Call::set_staking_configs { .. } | - pallet_staking::Call::chill_other { .. } | - pallet_staking::Call::force_apply_min_commission { .. }, - ) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda( - pallet_referenda::Call::place_decision_deposit { .. } | - pallet_referenda::Call::refund_decision_deposit { .. } | - pallet_referenda::Call::cancel { .. } | - pallet_referenda::Call::kill { .. } | - pallet_referenda::Call::nudge_referendum { .. } | - pallet_referenda::Call::one_fewer_deciding { .. }, - ) | - RuntimeCall::Claims( - super::claims::Call::claim { .. } | - super::claims::Call::mint_claim { .. } | - super::claims::Call::move_claim { .. }, - ) | - RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | - RuntimeCall::Identity( - pallet_identity::Call::add_registrar { .. } | - pallet_identity::Call::set_identity { .. } | - pallet_identity::Call::clear_identity { .. } | - pallet_identity::Call::request_judgement { .. } | - pallet_identity::Call::cancel_request { .. } | - pallet_identity::Call::set_fee { .. } | - pallet_identity::Call::set_account_id { .. } | - pallet_identity::Call::set_fields { .. } | - pallet_identity::Call::provide_judgement { .. } | - pallet_identity::Call::kill_identity { .. } | - pallet_identity::Call::add_sub { .. } | - pallet_identity::Call::rename_sub { .. } | - pallet_identity::Call::remove_sub { .. } | - pallet_identity::Call::quit_sub { .. }, - ) | - RuntimeCall::Vesting(..) | - RuntimeCall::Bounties( - pallet_bounties::Call::propose_bounty { .. } | - pallet_bounties::Call::approve_bounty { .. } | - pallet_bounties::Call::propose_curator { .. } | - pallet_bounties::Call::unassign_curator { .. } | - pallet_bounties::Call::accept_curator { .. } | - pallet_bounties::Call::award_bounty { .. } | - pallet_bounties::Call::claim_bounty { .. } | - pallet_bounties::Call::close_bounty { .. }, - ) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ElectionProviderMultiPhase(..) | - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools( - pallet_nomination_pools::Call::join { .. } | - pallet_nomination_pools::Call::bond_extra { .. } | - pallet_nomination_pools::Call::claim_payout { .. } | - pallet_nomination_pools::Call::unbond { .. } | - pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | - pallet_nomination_pools::Call::withdraw_unbonded { .. } | - pallet_nomination_pools::Call::create { .. } | - pallet_nomination_pools::Call::create_with_pool_id { .. } | - pallet_nomination_pools::Call::set_state { .. } | - pallet_nomination_pools::Call::set_configs { .. } | - pallet_nomination_pools::Call::update_roles { .. } | - pallet_nomination_pools::Call::chill { .. }, - ) | - RuntimeCall::Hrmp(..) | - RuntimeCall::Registrar( - paras_registrar::Call::deregister { .. } | - paras_registrar::Call::swap { .. } | - paras_registrar::Call::remove_lock { .. } | - paras_registrar::Call::reserve { .. } | - paras_registrar::Call::add_lock { .. }, - ) | - RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets { - .. - }) | - RuntimeCall::Whitelist(pallet_whitelist::Call::whitelist_call { .. }) | - RuntimeCall::Proxy(..) => true, - _ => false, - } - } -} - pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -344,8 +201,8 @@ impl xcm_executor::Config for XcmConfig { // No bridges yet... type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 356cffaa0ba..d561df14a02 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -22,13 +22,12 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; use rococo_runtime_constants::currency::CENTS; use runtime_common::{ - crowdloan, paras_registrar, xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, }; @@ -43,7 +42,7 @@ use xcm_builder::{ TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::XcmExecutor; parameter_types! { pub const TokenLocation: MultiLocation = Here.into_location(); @@ -157,138 +156,6 @@ pub type Barrier = TrailingSetTopicAsId<( >, )>; -/// 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 - } - } - - match call { - RuntimeCall::System( - frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. }, - ) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(..) | - RuntimeCall::Balances(..) | - RuntimeCall::Crowdloan( - crowdloan::Call::create { .. } | - crowdloan::Call::contribute { .. } | - crowdloan::Call::withdraw { .. } | - crowdloan::Call::refund { .. } | - crowdloan::Call::dissolve { .. } | - crowdloan::Call::edit { .. } | - crowdloan::Call::poke { .. } | - crowdloan::Call::contribute_all { .. }, - ) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Democracy( - pallet_democracy::Call::second { .. } | - pallet_democracy::Call::vote { .. } | - pallet_democracy::Call::emergency_cancel { .. } | - pallet_democracy::Call::fast_track { .. } | - pallet_democracy::Call::veto_external { .. } | - pallet_democracy::Call::cancel_referendum { .. } | - pallet_democracy::Call::delegate { .. } | - pallet_democracy::Call::undelegate { .. } | - pallet_democracy::Call::clear_public_proposals { .. } | - pallet_democracy::Call::unlock { .. } | - pallet_democracy::Call::remove_vote { .. } | - pallet_democracy::Call::remove_other_vote { .. } | - pallet_democracy::Call::blacklist { .. } | - pallet_democracy::Call::cancel_proposal { .. }, - ) | - RuntimeCall::Council( - pallet_collective::Call::vote { .. } | - pallet_collective::Call::disapprove_proposal { .. } | - pallet_collective::Call::close { .. }, - ) | - RuntimeCall::TechnicalCommittee( - pallet_collective::Call::vote { .. } | - pallet_collective::Call::disapprove_proposal { .. } | - pallet_collective::Call::close { .. }, - ) | - RuntimeCall::PhragmenElection( - pallet_elections_phragmen::Call::remove_voter { .. } | - pallet_elections_phragmen::Call::submit_candidacy { .. } | - pallet_elections_phragmen::Call::renounce_candidacy { .. } | - pallet_elections_phragmen::Call::remove_member { .. } | - pallet_elections_phragmen::Call::clean_defunct_voters { .. }, - ) | - RuntimeCall::TechnicalMembership( - pallet_membership::Call::add_member { .. } | - pallet_membership::Call::remove_member { .. } | - pallet_membership::Call::swap_member { .. } | - pallet_membership::Call::change_key { .. } | - pallet_membership::Call::set_prime { .. } | - pallet_membership::Call::clear_prime { .. }, - ) | - RuntimeCall::Treasury(..) | - RuntimeCall::Claims( - super::claims::Call::claim { .. } | - super::claims::Call::mint_claim { .. } | - super::claims::Call::move_claim { .. }, - ) | - RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | - RuntimeCall::Identity( - pallet_identity::Call::add_registrar { .. } | - pallet_identity::Call::set_identity { .. } | - pallet_identity::Call::clear_identity { .. } | - pallet_identity::Call::request_judgement { .. } | - pallet_identity::Call::cancel_request { .. } | - pallet_identity::Call::set_fee { .. } | - pallet_identity::Call::set_account_id { .. } | - pallet_identity::Call::set_fields { .. } | - pallet_identity::Call::provide_judgement { .. } | - pallet_identity::Call::kill_identity { .. } | - pallet_identity::Call::add_sub { .. } | - pallet_identity::Call::rename_sub { .. } | - pallet_identity::Call::remove_sub { .. } | - pallet_identity::Call::quit_sub { .. }, - ) | - RuntimeCall::Society(..) | - RuntimeCall::Recovery(..) | - RuntimeCall::Vesting(..) | - RuntimeCall::Bounties( - pallet_bounties::Call::propose_bounty { .. } | - pallet_bounties::Call::approve_bounty { .. } | - pallet_bounties::Call::propose_curator { .. } | - pallet_bounties::Call::unassign_curator { .. } | - pallet_bounties::Call::accept_curator { .. } | - pallet_bounties::Call::award_bounty { .. } | - pallet_bounties::Call::claim_bounty { .. } | - pallet_bounties::Call::close_bounty { .. }, - ) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::Hrmp(..) | - RuntimeCall::Registrar( - paras_registrar::Call::deregister { .. } | - paras_registrar::Call::swap { .. } | - paras_registrar::Call::remove_lock { .. } | - paras_registrar::Call::reserve { .. } | - paras_registrar::Call::add_lock { .. }, - ) | - RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets { - .. - }) => true, - _ => false, - } - } -} - pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -317,8 +184,8 @@ impl xcm_executor::Config for XcmConfig { type FeeManager = (); type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index a83c38c9f66..264830c693e 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -22,11 +22,10 @@ use super::{ }; use frame_support::{ parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Everything, Nothing}, }; use frame_system::EnsureRoot; use runtime_common::{ - crowdloan, paras_registrar, xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, }; @@ -41,7 +40,7 @@ use xcm_builder::{ SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::XcmExecutor; parameter_types! { pub const TokenLocation: MultiLocation = Here.into_location(); @@ -127,120 +126,6 @@ pub type Barrier = TrailingSetTopicAsId<( >, )>; -/// 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 - } - } - - match call { - RuntimeCall::System( - frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. }, - ) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(..) | - RuntimeCall::Balances(..) | - RuntimeCall::Crowdloan( - crowdloan::Call::create { .. } | - crowdloan::Call::contribute { .. } | - crowdloan::Call::withdraw { .. } | - crowdloan::Call::refund { .. } | - crowdloan::Call::dissolve { .. } | - crowdloan::Call::edit { .. } | - crowdloan::Call::poke { .. } | - crowdloan::Call::contribute_all { .. }, - ) | - RuntimeCall::Staking( - pallet_staking::Call::bond { .. } | - pallet_staking::Call::bond_extra { .. } | - pallet_staking::Call::unbond { .. } | - pallet_staking::Call::withdraw_unbonded { .. } | - pallet_staking::Call::validate { .. } | - pallet_staking::Call::nominate { .. } | - pallet_staking::Call::chill { .. } | - pallet_staking::Call::set_payee { .. } | - pallet_staking::Call::set_controller { .. } | - pallet_staking::Call::set_validator_count { .. } | - pallet_staking::Call::increase_validator_count { .. } | - pallet_staking::Call::scale_validator_count { .. } | - pallet_staking::Call::force_no_eras { .. } | - pallet_staking::Call::force_new_era { .. } | - pallet_staking::Call::set_invulnerables { .. } | - pallet_staking::Call::force_unstake { .. } | - pallet_staking::Call::force_new_era_always { .. } | - pallet_staking::Call::payout_stakers { .. } | - pallet_staking::Call::rebond { .. } | - pallet_staking::Call::reap_stash { .. } | - pallet_staking::Call::set_staking_configs { .. } | - pallet_staking::Call::chill_other { .. } | - pallet_staking::Call::force_apply_min_commission { .. }, - ) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | - RuntimeCall::Identity( - pallet_identity::Call::add_registrar { .. } | - pallet_identity::Call::set_identity { .. } | - pallet_identity::Call::clear_identity { .. } | - pallet_identity::Call::request_judgement { .. } | - pallet_identity::Call::cancel_request { .. } | - pallet_identity::Call::set_fee { .. } | - pallet_identity::Call::set_account_id { .. } | - pallet_identity::Call::set_fields { .. } | - pallet_identity::Call::provide_judgement { .. } | - pallet_identity::Call::kill_identity { .. } | - pallet_identity::Call::add_sub { .. } | - pallet_identity::Call::rename_sub { .. } | - pallet_identity::Call::remove_sub { .. } | - pallet_identity::Call::quit_sub { .. }, - ) | - RuntimeCall::Recovery(..) | - RuntimeCall::Vesting(..) | - RuntimeCall::ElectionProviderMultiPhase(..) | - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools( - pallet_nomination_pools::Call::join { .. } | - pallet_nomination_pools::Call::bond_extra { .. } | - pallet_nomination_pools::Call::claim_payout { .. } | - pallet_nomination_pools::Call::unbond { .. } | - pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | - pallet_nomination_pools::Call::withdraw_unbonded { .. } | - pallet_nomination_pools::Call::create { .. } | - pallet_nomination_pools::Call::create_with_pool_id { .. } | - pallet_nomination_pools::Call::set_state { .. } | - pallet_nomination_pools::Call::set_configs { .. } | - pallet_nomination_pools::Call::update_roles { .. } | - pallet_nomination_pools::Call::chill { .. }, - ) | - RuntimeCall::Hrmp(..) | - RuntimeCall::Registrar( - paras_registrar::Call::deregister { .. } | - paras_registrar::Call::swap { .. } | - paras_registrar::Call::remove_lock { .. } | - paras_registrar::Call::reserve { .. } | - paras_registrar::Call::add_lock { .. }, - ) | - RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets { - .. - }) => true, - _ => false, - } - } -} - pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -266,8 +151,8 @@ impl xcm_executor::Config for XcmConfig { type FeeManager = (); type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; } -- GitLab From 142a11ad9532754231a2b44fdbd080f656eb509d Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 11 Sep 2023 11:47:45 +0300 Subject: [PATCH 113/633] Update bridges subtree (#1392) * Move the bridges subtree under root * Squashed 'bridges/' changes from 277f0d5496..e50398d1c5 e50398d1c5 bridges subtree fixes (#2528) 99af07522d Markdown linter (#1309) (#2526) 733ff0fe7a `polkadot-staging` branch: Use polkadot-sdk dependencies (#2524) e8a59f141e Fix benchmark with new XCM::V3 `MAX_INSTRUCTIONS_TO_DECODE` (#2514) 62b185de15 Backport `polkadot-sdk` changes to `polkadot-staging` (#2518) d9658f4d5b Fix equivocation detection containers startup (#2516) (#2517) d65db28a8f Backport: building images from locally built binaries (#2513) 5fdbaf45f6 Start the equivocation detection loop from the complex relayer (#2507) (#2512) 7fbb67de46 Backport: Implement basic equivocations detection loop (#2375) cb7efe245c Manually update deps in polkadot staging (#2371) d17981fc33 #2351 to polkadot-staging (#2359) git-subtree-dir: bridges git-subtree-split: e50398d1c594e4e96df70b0bd376e565d17e8558 * Reapply diener workspacify * Fix Cargo.toml * Fix test * Adjustments --- .github/pr-custom-review.yml | 2 +- cumulus/BRIDGES.md => BRIDGES.md | 0 Cargo.toml | 50 ++++----- {cumulus/bridges => bridges}/.gitignore | 0 .../bridges => bridges}/CODE_OF_CONDUCT.md | 0 {cumulus/bridges => bridges}/LICENSE | 0 {cumulus/bridges => bridges}/README.md | 0 {cumulus/bridges => bridges}/SECURITY.md | 0 .../bin/runtime-common/Cargo.toml | 26 ++--- .../bin/runtime-common/src/integrity.rs | 13 --- .../bin/runtime-common/src/lib.rs | 0 .../bin/runtime-common/src/messages.rs | 0 .../bin/runtime-common/src/messages_api.rs | 0 .../src/messages_benchmarking.rs | 0 .../runtime-common/src/messages_call_ext.rs | 0 .../runtime-common/src/messages_generation.rs | 0 .../src/messages_xcm_extension.rs | 0 .../bin/runtime-common/src/mock.rs | 0 .../src/parachains_benchmarking.rs | 0 .../runtime-common/src/priority_calculator.rs | 0 .../src/refund_relayer_extension.rs | 0 .../docs/complex-relay.html | 0 .../docs/grandpa-finality-relay.html | 0 .../docs/high-level-overview.md | 0 .../docs/messages-relay.html | 0 .../docs/parachains-finality-relay.html | 0 .../docs/polkadot-kusama-bridge-overview.md | 0 .../docs/polkadot-kusama-bridge.html | 0 .../modules/grandpa/Cargo.toml | 18 +-- .../modules/grandpa/README.md | 0 .../modules/grandpa/src/benchmarking.rs | 0 .../modules/grandpa/src/call_ext.rs | 0 .../modules/grandpa/src/lib.rs | 0 .../modules/grandpa/src/mock.rs | 0 .../modules/grandpa/src/storage_types.rs | 0 .../modules/grandpa/src/weights.rs | 0 .../modules/messages/Cargo.toml | 16 +-- .../modules/messages/README.md | 0 .../modules/messages/src/benchmarking.rs | 0 .../modules/messages/src/inbound_lane.rs | 0 .../modules/messages/src/lib.rs | 0 .../modules/messages/src/mock.rs | 0 .../modules/messages/src/outbound_lane.rs | 0 .../modules/messages/src/weights.rs | 0 .../modules/messages/src/weights_ext.rs | 0 .../modules/parachains/Cargo.toml | 16 +-- .../modules/parachains/README.md | 0 .../modules/parachains/src/benchmarking.rs | 0 .../modules/parachains/src/call_ext.rs | 0 .../modules/parachains/src/lib.rs | 0 .../modules/parachains/src/mock.rs | 0 .../modules/parachains/src/weights.rs | 0 .../modules/parachains/src/weights_ext.rs | 0 .../modules/relayers/Cargo.toml | 20 ++-- .../modules/relayers/README.md | 0 .../modules/relayers/src/benchmarking.rs | 0 .../modules/relayers/src/lib.rs | 0 .../modules/relayers/src/mock.rs | 0 .../modules/relayers/src/payment_adapter.rs | 0 .../modules/relayers/src/stake_adapter.rs | 0 .../modules/relayers/src/weights.rs | 0 .../modules/relayers/src/weights_ext.rs | 0 .../modules/xcm-bridge-hub-router/Cargo.toml | 22 ++-- .../xcm-bridge-hub-router/src/benchmarking.rs | 0 .../modules/xcm-bridge-hub-router/src/lib.rs | 0 .../modules/xcm-bridge-hub-router/src/mock.rs | 2 +- .../xcm-bridge-hub-router/src/weights.rs | 0 .../chain-asset-hub-kusama/Cargo.toml | 2 +- .../chain-asset-hub-kusama/src/lib.rs | 0 .../chain-asset-hub-polkadot/Cargo.toml | 4 +- .../chain-asset-hub-polkadot/src/lib.rs | 0 .../chain-bridge-hub-cumulus/Cargo.toml | 10 +- .../chain-bridge-hub-cumulus/src/lib.rs | 91 +--------------- .../chain-bridge-hub-kusama/Cargo.toml | 8 +- .../chain-bridge-hub-kusama/src/lib.rs | 0 .../chain-bridge-hub-polkadot/Cargo.toml | 8 +- .../chain-bridge-hub-polkadot/src/lib.rs | 0 .../chain-bridge-hub-rococo/Cargo.toml | 8 +- .../chain-bridge-hub-rococo/src/lib.rs | 0 .../chain-bridge-hub-wococo/Cargo.toml | 8 +- .../chain-bridge-hub-wococo/src/lib.rs | 0 .../primitives/chain-kusama/Cargo.toml | 6 +- .../primitives/chain-kusama/src/lib.rs | 3 + .../primitives/chain-polkadot/Cargo.toml | 6 +- .../primitives/chain-polkadot/src/lib.rs | 5 +- .../primitives/chain-rococo/Cargo.toml | 6 +- .../primitives/chain-rococo/src/lib.rs | 3 + .../primitives/chain-wococo/Cargo.toml | 6 +- .../primitives/chain-wococo/src/lib.rs | 3 + .../primitives/header-chain/Cargo.toml | 10 +- .../header-chain/src/justification/mod.rs | 6 +- .../verification/equivocation.rs | 0 .../src/justification/verification/mod.rs | 0 .../justification/verification/optimizer.rs | 0 .../src/justification/verification/strict.rs | 0 .../primitives/header-chain/src/lib.rs | 7 +- .../header-chain/src/storage_keys.rs | 0 .../tests/implementation_match.rs | 0 .../tests/justification/equivocation.rs | 0 .../tests/justification/optimizer.rs | 0 .../tests/justification/strict.rs | 0 .../primitives/header-chain/tests/tests.rs | 0 .../primitives/messages/Cargo.toml | 6 +- .../primitives/messages/src/lib.rs | 0 .../primitives/messages/src/source_chain.rs | 0 .../primitives/messages/src/storage_keys.rs | 0 .../primitives/messages/src/target_chain.rs | 0 .../primitives/parachains/Cargo.toml | 8 +- .../primitives/parachains/src/lib.rs | 0 .../primitives/polkadot-core/Cargo.toml | 10 +- .../primitives/polkadot-core/src/lib.rs | 103 +++++++++++++++++- .../polkadot-core/src/parachains.rs | 0 .../primitives/relayers/Cargo.toml | 6 +- .../primitives/relayers/src/lib.rs | 0 .../primitives/relayers/src/registration.rs | 0 .../primitives/runtime/Cargo.toml | 16 +-- .../primitives/runtime/src/chain.rs | 0 .../primitives/runtime/src/extensions.rs | 12 +- .../primitives/runtime/src/lib.rs | 0 .../primitives/runtime/src/messages.rs | 0 .../primitives/runtime/src/storage_proof.rs | 0 .../primitives/runtime/src/storage_types.rs | 0 .../primitives/test-utils/Cargo.toml | 12 +- .../primitives/test-utils/src/keyring.rs | 0 .../primitives/test-utils/src/lib.rs | 0 .../xcm-bridge-hub-router/Cargo.toml | 4 +- .../xcm-bridge-hub-router/src/lib.rs | 0 .../scripts/verify-pallets-build.sh | 9 ++ .../bridges/bridge-hub-rococo/Cargo.toml | 4 +- .../emulated/common/Cargo.toml | 6 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 32 +++--- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 100 +++++++++-------- .../bridge-hubs/test-utils/Cargo.toml | 28 ++--- .../bridges_update_subtree.sh | 0 134 files changed, 398 insertions(+), 343 deletions(-) rename cumulus/BRIDGES.md => BRIDGES.md (100%) rename {cumulus/bridges => bridges}/.gitignore (100%) rename {cumulus/bridges => bridges}/CODE_OF_CONDUCT.md (100%) rename {cumulus/bridges => bridges}/LICENSE (100%) rename {cumulus/bridges => bridges}/README.md (100%) rename {cumulus/bridges => bridges}/SECURITY.md (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/Cargo.toml (72%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/integrity.rs (96%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/lib.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages_api.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages_benchmarking.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages_call_ext.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages_generation.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/messages_xcm_extension.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/mock.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/parachains_benchmarking.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/priority_calculator.rs (100%) rename {cumulus/bridges => bridges}/bin/runtime-common/src/refund_relayer_extension.rs (100%) rename {cumulus/bridges => bridges}/docs/complex-relay.html (100%) rename {cumulus/bridges => bridges}/docs/grandpa-finality-relay.html (100%) rename {cumulus/bridges => bridges}/docs/high-level-overview.md (100%) rename {cumulus/bridges => bridges}/docs/messages-relay.html (100%) rename {cumulus/bridges => bridges}/docs/parachains-finality-relay.html (100%) rename {cumulus/bridges => bridges}/docs/polkadot-kusama-bridge-overview.md (100%) rename {cumulus/bridges => bridges}/docs/polkadot-kusama-bridge.html (100%) rename {cumulus/bridges => bridges}/modules/grandpa/Cargo.toml (65%) rename {cumulus/bridges => bridges}/modules/grandpa/README.md (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/benchmarking.rs (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/call_ext.rs (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/lib.rs (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/mock.rs (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/storage_types.rs (100%) rename {cumulus/bridges => bridges}/modules/grandpa/src/weights.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/Cargo.toml (67%) rename {cumulus/bridges => bridges}/modules/messages/README.md (100%) rename {cumulus/bridges => bridges}/modules/messages/src/benchmarking.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/inbound_lane.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/lib.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/mock.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/outbound_lane.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/weights.rs (100%) rename {cumulus/bridges => bridges}/modules/messages/src/weights_ext.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/Cargo.toml (71%) rename {cumulus/bridges => bridges}/modules/parachains/README.md (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/benchmarking.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/call_ext.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/lib.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/mock.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/weights.rs (100%) rename {cumulus/bridges => bridges}/modules/parachains/src/weights_ext.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/Cargo.toml (66%) rename {cumulus/bridges => bridges}/modules/relayers/README.md (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/benchmarking.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/lib.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/mock.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/payment_adapter.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/stake_adapter.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/weights.rs (100%) rename {cumulus/bridges => bridges}/modules/relayers/src/weights_ext.rs (100%) rename {cumulus/bridges => bridges}/modules/xcm-bridge-hub-router/Cargo.toml (59%) rename {cumulus/bridges => bridges}/modules/xcm-bridge-hub-router/src/benchmarking.rs (100%) rename {cumulus/bridges => bridges}/modules/xcm-bridge-hub-router/src/lib.rs (100%) rename {cumulus/bridges => bridges}/modules/xcm-bridge-hub-router/src/mock.rs (99%) rename {cumulus/bridges => bridges}/modules/xcm-bridge-hub-router/src/weights.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-asset-hub-kusama/Cargo.toml (88%) rename {cumulus/bridges => bridges}/primitives/chain-asset-hub-kusama/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-asset-hub-polkadot/Cargo.toml (79%) rename {cumulus/bridges => bridges}/primitives/chain-asset-hub-polkadot/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-cumulus/Cargo.toml (62%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-cumulus/src/lib.rs (72%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-kusama/Cargo.toml (66%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-kusama/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-polkadot/Cargo.toml (66%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-polkadot/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-rococo/Cargo.toml (66%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-rococo/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-wococo/Cargo.toml (66%) rename {cumulus/bridges => bridges}/primitives/chain-bridge-hub-wococo/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/chain-kusama/Cargo.toml (71%) rename {cumulus/bridges => bridges}/primitives/chain-kusama/src/lib.rs (96%) rename {cumulus/bridges => bridges}/primitives/chain-polkadot/Cargo.toml (71%) rename {cumulus/bridges => bridges}/primitives/chain-polkadot/src/lib.rs (92%) rename {cumulus/bridges => bridges}/primitives/chain-rococo/Cargo.toml (71%) rename {cumulus/bridges => bridges}/primitives/chain-rococo/src/lib.rs (96%) rename {cumulus/bridges => bridges}/primitives/chain-wococo/Cargo.toml (73%) rename {cumulus/bridges => bridges}/primitives/chain-wococo/src/lib.rs (96%) rename {cumulus/bridges => bridges}/primitives/header-chain/Cargo.toml (66%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/justification/mod.rs (97%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/justification/verification/equivocation.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/justification/verification/mod.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/justification/verification/optimizer.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/justification/verification/strict.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/lib.rs (98%) rename {cumulus/bridges => bridges}/primitives/header-chain/src/storage_keys.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/tests/implementation_match.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/tests/justification/equivocation.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/tests/justification/optimizer.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/tests/justification/strict.rs (100%) rename {cumulus/bridges => bridges}/primitives/header-chain/tests/tests.rs (100%) rename {cumulus/bridges => bridges}/primitives/messages/Cargo.toml (78%) rename {cumulus/bridges => bridges}/primitives/messages/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/messages/src/source_chain.rs (100%) rename {cumulus/bridges => bridges}/primitives/messages/src/storage_keys.rs (100%) rename {cumulus/bridges => bridges}/primitives/messages/src/target_chain.rs (100%) rename {cumulus/bridges => bridges}/primitives/parachains/Cargo.toml (72%) rename {cumulus/bridges => bridges}/primitives/parachains/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/polkadot-core/Cargo.toml (69%) rename {cumulus/bridges => bridges}/primitives/polkadot-core/src/lib.rs (81%) rename {cumulus/bridges => bridges}/primitives/polkadot-core/src/parachains.rs (100%) rename {cumulus/bridges => bridges}/primitives/relayers/Cargo.toml (74%) rename {cumulus/bridges => bridges}/primitives/relayers/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/relayers/src/registration.rs (100%) rename {cumulus/bridges => bridges}/primitives/runtime/Cargo.toml (60%) rename {cumulus/bridges => bridges}/primitives/runtime/src/chain.rs (100%) rename {cumulus/bridges => bridges}/primitives/runtime/src/extensions.rs (94%) rename {cumulus/bridges => bridges}/primitives/runtime/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/runtime/src/messages.rs (100%) rename {cumulus/bridges => bridges}/primitives/runtime/src/storage_proof.rs (100%) rename {cumulus/bridges => bridges}/primitives/runtime/src/storage_types.rs (100%) rename {cumulus/bridges => bridges}/primitives/test-utils/Cargo.toml (63%) rename {cumulus/bridges => bridges}/primitives/test-utils/src/keyring.rs (100%) rename {cumulus/bridges => bridges}/primitives/test-utils/src/lib.rs (100%) rename {cumulus/bridges => bridges}/primitives/xcm-bridge-hub-router/Cargo.toml (76%) rename {cumulus/bridges => bridges}/primitives/xcm-bridge-hub-router/src/lib.rs (100%) rename {cumulus/bridges => bridges}/scripts/verify-pallets-build.sh (93%) rename {cumulus/scripts => scripts}/bridges_update_subtree.sh (100%) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index bc9a3cfb8d2..40fc53cbd02 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -39,7 +39,7 @@ rules: # 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: ^cumulus/bridges/.* + condition: ^bridges/.* min_approvals: 1 teams: - bridges-core diff --git a/cumulus/BRIDGES.md b/BRIDGES.md similarity index 100% rename from cumulus/BRIDGES.md rename to BRIDGES.md diff --git a/Cargo.toml b/Cargo.toml index 8a9c2afe1d1..5c43990d472 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,31 +8,31 @@ license = "GPL-3.0-only" resolver = "2" members = [ - "cumulus/bridges/bin/runtime-common", - "cumulus/bridges/modules/grandpa", - "cumulus/bridges/modules/messages", - "cumulus/bridges/modules/parachains", - "cumulus/bridges/modules/relayers", - "cumulus/bridges/modules/xcm-bridge-hub-router", - "cumulus/bridges/primitives/chain-asset-hub-kusama", - "cumulus/bridges/primitives/chain-asset-hub-polkadot", - "cumulus/bridges/primitives/chain-bridge-hub-cumulus", - "cumulus/bridges/primitives/chain-bridge-hub-kusama", - "cumulus/bridges/primitives/chain-bridge-hub-polkadot", - "cumulus/bridges/primitives/chain-bridge-hub-rococo", - "cumulus/bridges/primitives/chain-bridge-hub-wococo", - "cumulus/bridges/primitives/chain-kusama", - "cumulus/bridges/primitives/chain-polkadot", - "cumulus/bridges/primitives/chain-rococo", - "cumulus/bridges/primitives/chain-wococo", - "cumulus/bridges/primitives/header-chain", - "cumulus/bridges/primitives/messages", - "cumulus/bridges/primitives/parachains", - "cumulus/bridges/primitives/polkadot-core", - "cumulus/bridges/primitives/relayers", - "cumulus/bridges/primitives/runtime", - "cumulus/bridges/primitives/test-utils", - "cumulus/bridges/primitives/xcm-bridge-hub-router", + "bridges/bin/runtime-common", + "bridges/modules/grandpa", + "bridges/modules/messages", + "bridges/modules/parachains", + "bridges/modules/relayers", + "bridges/modules/xcm-bridge-hub-router", + "bridges/primitives/chain-asset-hub-kusama", + "bridges/primitives/chain-asset-hub-polkadot", + "bridges/primitives/chain-bridge-hub-cumulus", + "bridges/primitives/chain-bridge-hub-kusama", + "bridges/primitives/chain-bridge-hub-polkadot", + "bridges/primitives/chain-bridge-hub-rococo", + "bridges/primitives/chain-bridge-hub-wococo", + "bridges/primitives/chain-kusama", + "bridges/primitives/chain-polkadot", + "bridges/primitives/chain-rococo", + "bridges/primitives/chain-wococo", + "bridges/primitives/header-chain", + "bridges/primitives/messages", + "bridges/primitives/parachains", + "bridges/primitives/polkadot-core", + "bridges/primitives/relayers", + "bridges/primitives/runtime", + "bridges/primitives/test-utils", + "bridges/primitives/xcm-bridge-hub-router", "cumulus/client/cli", "cumulus/client/collator", "cumulus/client/consensus/aura", diff --git a/cumulus/bridges/.gitignore b/bridges/.gitignore similarity index 100% rename from cumulus/bridges/.gitignore rename to bridges/.gitignore diff --git a/cumulus/bridges/CODE_OF_CONDUCT.md b/bridges/CODE_OF_CONDUCT.md similarity index 100% rename from cumulus/bridges/CODE_OF_CONDUCT.md rename to bridges/CODE_OF_CONDUCT.md diff --git a/cumulus/bridges/LICENSE b/bridges/LICENSE similarity index 100% rename from cumulus/bridges/LICENSE rename to bridges/LICENSE diff --git a/cumulus/bridges/README.md b/bridges/README.md similarity index 100% rename from cumulus/bridges/README.md rename to bridges/README.md diff --git a/cumulus/bridges/SECURITY.md b/bridges/SECURITY.md similarity index 100% rename from cumulus/bridges/SECURITY.md rename to bridges/SECURITY.md diff --git a/cumulus/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml similarity index 72% rename from cumulus/bridges/bin/runtime-common/Cargo.toml rename to bridges/bin/runtime-common/Cargo.toml index b139f835c1a..5c3fefc69ce 100644 --- a/cumulus/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -29,24 +29,24 @@ pallet-bridge-relayers = { path = "../../modules/relayers", default-features = f # Substrate dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment", default-features = false } -pallet-utility = { path = "../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../../substrate/primitives/trie", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } # Polkadot dependencies -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 = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } -pallet-balances = { path = "../../../../substrate/frame/balances" } +pallet-balances = { path = "../../../substrate/frame/balances" } [features] default = [ "std" ] diff --git a/cumulus/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs similarity index 96% rename from cumulus/bridges/bin/runtime-common/src/integrity.rs rename to bridges/bin/runtime-common/src/integrity.rs index 290c22f835d..d3827a14dd6 100644 --- a/cumulus/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -27,7 +27,6 @@ use codec::Encode; use frame_support::{storage::generator::StorageValue, traits::Get, weights::Weight}; use frame_system::limits; use pallet_bridge_messages::WeightInfoExt as _; -use sp_runtime::traits::SignedExtension; /// Macro that ensures that the runtime configuration and chain primitives crate are sharing /// the same types (nonce, block number, hash, hasher, account id and header). @@ -347,15 +346,3 @@ pub fn check_message_lane_weights< ); } } - -/// Check that the `AdditionalSigned` type of a wrapped runtime is the same as the one of the -/// corresponding actual runtime. -/// -/// This method doesn't perform any `assert`. If the condition is not true it will generate a -/// compile-time error. -pub fn check_additional_signed() -where - SignedExt: SignedExtension, - IndirectSignedExt: SignedExtension, -{ -} diff --git a/cumulus/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/lib.rs rename to bridges/bin/runtime-common/src/lib.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages.rs rename to bridges/bin/runtime-common/src/messages.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages_api.rs rename to bridges/bin/runtime-common/src/messages_api.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages_benchmarking.rs rename to bridges/bin/runtime-common/src/messages_benchmarking.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages_call_ext.rs rename to bridges/bin/runtime-common/src/messages_call_ext.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/bin/runtime-common/src/messages_generation.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages_generation.rs rename to bridges/bin/runtime-common/src/messages_generation.rs diff --git a/cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/messages_xcm_extension.rs rename to bridges/bin/runtime-common/src/messages_xcm_extension.rs diff --git a/cumulus/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/mock.rs rename to bridges/bin/runtime-common/src/mock.rs diff --git a/cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs b/bridges/bin/runtime-common/src/parachains_benchmarking.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/parachains_benchmarking.rs rename to bridges/bin/runtime-common/src/parachains_benchmarking.rs diff --git a/cumulus/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/priority_calculator.rs rename to bridges/bin/runtime-common/src/priority_calculator.rs diff --git a/cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs similarity index 100% rename from cumulus/bridges/bin/runtime-common/src/refund_relayer_extension.rs rename to bridges/bin/runtime-common/src/refund_relayer_extension.rs diff --git a/cumulus/bridges/docs/complex-relay.html b/bridges/docs/complex-relay.html similarity index 100% rename from cumulus/bridges/docs/complex-relay.html rename to bridges/docs/complex-relay.html diff --git a/cumulus/bridges/docs/grandpa-finality-relay.html b/bridges/docs/grandpa-finality-relay.html similarity index 100% rename from cumulus/bridges/docs/grandpa-finality-relay.html rename to bridges/docs/grandpa-finality-relay.html diff --git a/cumulus/bridges/docs/high-level-overview.md b/bridges/docs/high-level-overview.md similarity index 100% rename from cumulus/bridges/docs/high-level-overview.md rename to bridges/docs/high-level-overview.md diff --git a/cumulus/bridges/docs/messages-relay.html b/bridges/docs/messages-relay.html similarity index 100% rename from cumulus/bridges/docs/messages-relay.html rename to bridges/docs/messages-relay.html diff --git a/cumulus/bridges/docs/parachains-finality-relay.html b/bridges/docs/parachains-finality-relay.html similarity index 100% rename from cumulus/bridges/docs/parachains-finality-relay.html rename to bridges/docs/parachains-finality-relay.html diff --git a/cumulus/bridges/docs/polkadot-kusama-bridge-overview.md b/bridges/docs/polkadot-kusama-bridge-overview.md similarity index 100% rename from cumulus/bridges/docs/polkadot-kusama-bridge-overview.md rename to bridges/docs/polkadot-kusama-bridge-overview.md diff --git a/cumulus/bridges/docs/polkadot-kusama-bridge.html b/bridges/docs/polkadot-kusama-bridge.html similarity index 100% rename from cumulus/bridges/docs/polkadot-kusama-bridge.html rename to bridges/docs/polkadot-kusama-bridge.html diff --git a/cumulus/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml similarity index 65% rename from cumulus/bridges/modules/grandpa/Cargo.toml rename to bridges/modules/grandpa/Cargo.toml index 87eda6b29a7..05d6a8e5c26 100644 --- a/cumulus/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -20,20 +20,20 @@ bp-header-chain = { path = "../../primitives/header-chain", default-features = f # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-consensus-grandpa = { path = "../../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../../substrate/primitives/trie", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } # Optional Benchmarking Dependencies bp-test-utils = { path = "../../primitives/test-utils", default-features = false, optional = true } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } [dev-dependencies] -sp-core = { path = "../../../../substrate/primitives/core" } -sp-io = { path = "../../../../substrate/primitives/io" } +sp-core = { path = "../../../substrate/primitives/core" } +sp-io = { path = "../../../substrate/primitives/io" } [features] default = [ "std" ] diff --git a/cumulus/bridges/modules/grandpa/README.md b/bridges/modules/grandpa/README.md similarity index 100% rename from cumulus/bridges/modules/grandpa/README.md rename to bridges/modules/grandpa/README.md diff --git a/cumulus/bridges/modules/grandpa/src/benchmarking.rs b/bridges/modules/grandpa/src/benchmarking.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/benchmarking.rs rename to bridges/modules/grandpa/src/benchmarking.rs diff --git a/cumulus/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/call_ext.rs rename to bridges/modules/grandpa/src/call_ext.rs diff --git a/cumulus/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/lib.rs rename to bridges/modules/grandpa/src/lib.rs diff --git a/cumulus/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/mock.rs rename to bridges/modules/grandpa/src/mock.rs diff --git a/cumulus/bridges/modules/grandpa/src/storage_types.rs b/bridges/modules/grandpa/src/storage_types.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/storage_types.rs rename to bridges/modules/grandpa/src/storage_types.rs diff --git a/cumulus/bridges/modules/grandpa/src/weights.rs b/bridges/modules/grandpa/src/weights.rs similarity index 100% rename from cumulus/bridges/modules/grandpa/src/weights.rs rename to bridges/modules/grandpa/src/weights.rs diff --git a/cumulus/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml similarity index 67% rename from cumulus/bridges/modules/messages/Cargo.toml rename to bridges/modules/messages/Cargo.toml index 5eecdb147fa..7b7ea061981 100644 --- a/cumulus/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -19,17 +19,17 @@ bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Dependencies -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -sp-io = { path = "../../../../substrate/primitives/io" } +pallet-balances = { path = "../../../substrate/frame/balances" } +sp-io = { path = "../../../substrate/primitives/io" } [features] default = [ "std" ] diff --git a/cumulus/bridges/modules/messages/README.md b/bridges/modules/messages/README.md similarity index 100% rename from cumulus/bridges/modules/messages/README.md rename to bridges/modules/messages/README.md diff --git a/cumulus/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/benchmarking.rs rename to bridges/modules/messages/src/benchmarking.rs diff --git a/cumulus/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/inbound_lane.rs rename to bridges/modules/messages/src/inbound_lane.rs diff --git a/cumulus/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/lib.rs rename to bridges/modules/messages/src/lib.rs diff --git a/cumulus/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/mock.rs rename to bridges/modules/messages/src/mock.rs diff --git a/cumulus/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/outbound_lane.rs rename to bridges/modules/messages/src/outbound_lane.rs diff --git a/cumulus/bridges/modules/messages/src/weights.rs b/bridges/modules/messages/src/weights.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/weights.rs rename to bridges/modules/messages/src/weights.rs diff --git a/cumulus/bridges/modules/messages/src/weights_ext.rs b/bridges/modules/messages/src/weights_ext.rs similarity index 100% rename from cumulus/bridges/modules/messages/src/weights_ext.rs rename to bridges/modules/messages/src/weights_ext.rs diff --git a/cumulus/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml similarity index 71% rename from cumulus/bridges/modules/parachains/Cargo.toml rename to bridges/modules/parachains/Cargo.toml index 50a838edf56..4eb09ed78d1 100644 --- a/cumulus/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -20,18 +20,18 @@ pallet-bridge-grandpa = { path = "../grandpa", default-features = false } # Substrate Dependencies -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../../substrate/primitives/trie", default-features = false } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } [dev-dependencies] bp-header-chain = { path = "../../primitives/header-chain" } bp-test-utils = { path = "../../primitives/test-utils" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-io = { path = "../../../../substrate/primitives/io" } +sp-core = { path = "../../../substrate/primitives/core" } +sp-io = { path = "../../../substrate/primitives/io" } [features] default = [ "std" ] diff --git a/cumulus/bridges/modules/parachains/README.md b/bridges/modules/parachains/README.md similarity index 100% rename from cumulus/bridges/modules/parachains/README.md rename to bridges/modules/parachains/README.md diff --git a/cumulus/bridges/modules/parachains/src/benchmarking.rs b/bridges/modules/parachains/src/benchmarking.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/benchmarking.rs rename to bridges/modules/parachains/src/benchmarking.rs diff --git a/cumulus/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/call_ext.rs rename to bridges/modules/parachains/src/call_ext.rs diff --git a/cumulus/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/lib.rs rename to bridges/modules/parachains/src/lib.rs diff --git a/cumulus/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/mock.rs rename to bridges/modules/parachains/src/mock.rs diff --git a/cumulus/bridges/modules/parachains/src/weights.rs b/bridges/modules/parachains/src/weights.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/weights.rs rename to bridges/modules/parachains/src/weights.rs diff --git a/cumulus/bridges/modules/parachains/src/weights_ext.rs b/bridges/modules/parachains/src/weights_ext.rs similarity index 100% rename from cumulus/bridges/modules/parachains/src/weights_ext.rs rename to bridges/modules/parachains/src/weights_ext.rs diff --git a/cumulus/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml similarity index 66% rename from cumulus/bridges/modules/relayers/Cargo.toml rename to bridges/modules/relayers/Cargo.toml index 3a7a57e1801..46fc3bb43b1 100644 --- a/cumulus/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -20,19 +20,19 @@ pallet-bridge-messages = { path = "../messages", default-features = false } # Substrate Dependencies -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [dev-dependencies] bp-runtime = { path = "../../primitives/runtime" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-io = { path = "../../../../substrate/primitives/io" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } +pallet-balances = { path = "../../../substrate/frame/balances" } +sp-core = { path = "../../../substrate/primitives/core" } +sp-io = { path = "../../../substrate/primitives/io" } +sp-runtime = { path = "../../../substrate/primitives/runtime" } [features] default = [ "std" ] diff --git a/cumulus/bridges/modules/relayers/README.md b/bridges/modules/relayers/README.md similarity index 100% rename from cumulus/bridges/modules/relayers/README.md rename to bridges/modules/relayers/README.md diff --git a/cumulus/bridges/modules/relayers/src/benchmarking.rs b/bridges/modules/relayers/src/benchmarking.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/benchmarking.rs rename to bridges/modules/relayers/src/benchmarking.rs diff --git a/cumulus/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/lib.rs rename to bridges/modules/relayers/src/lib.rs diff --git a/cumulus/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/mock.rs rename to bridges/modules/relayers/src/mock.rs diff --git a/cumulus/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/payment_adapter.rs rename to bridges/modules/relayers/src/payment_adapter.rs diff --git a/cumulus/bridges/modules/relayers/src/stake_adapter.rs b/bridges/modules/relayers/src/stake_adapter.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/stake_adapter.rs rename to bridges/modules/relayers/src/stake_adapter.rs diff --git a/cumulus/bridges/modules/relayers/src/weights.rs b/bridges/modules/relayers/src/weights.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/weights.rs rename to bridges/modules/relayers/src/weights.rs diff --git a/cumulus/bridges/modules/relayers/src/weights_ext.rs b/bridges/modules/relayers/src/weights_ext.rs similarity index 100% rename from cumulus/bridges/modules/relayers/src/weights_ext.rs rename to bridges/modules/relayers/src/weights_ext.rs diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml similarity index 59% rename from cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml rename to bridges/modules/xcm-bridge-hub-router/Cargo.toml index 6ad3c57ca73..c61cab291e1 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.19", default-features = false } +log = { version = "0.4.20", default-features = false } scale-info = { version = "2.8.0", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies @@ -17,21 +17,21 @@ bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", de # Substrate Dependencies -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot Dependencies -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 = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } [dev-dependencies] -sp-io = { path = "../../../../substrate/primitives/io" } -sp-std = { path = "../../../../substrate/primitives/std" } +sp-io = { path = "../../../substrate/primitives/io" } +sp-std = { path = "../../../substrate/primitives/std" } [features] default = [ "std" ] diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs similarity index 100% rename from cumulus/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs rename to bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs similarity index 100% rename from cumulus/bridges/modules/xcm-bridge-hub-router/src/lib.rs rename to bridges/modules/xcm-bridge-hub-router/src/lib.rs diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs similarity index 99% rename from cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs rename to bridges/modules/xcm-bridge-hub-router/src/mock.rs index cd50b98a168..58df21a6d90 100644 --- a/cumulus/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -144,5 +144,5 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - new_test_ext().execute_with(|| test()) + new_test_ext().execute_with(test) } diff --git a/cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs similarity index 100% rename from cumulus/bridges/modules/xcm-bridge-hub-router/src/weights.rs rename to bridges/modules/xcm-bridge-hub-router/src/weights.rs diff --git a/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml similarity index 88% rename from cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml rename to bridges/primitives/chain-asset-hub-kusama/Cargo.toml index 557f56bfb62..adb9a57bc13 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml @@ -11,7 +11,7 @@ codec = { package = "parity-scale-codec", version = "3.1.5", default-features = scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } # Bridge Dependencies bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } diff --git a/cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs b/bridges/primitives/chain-asset-hub-kusama/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-asset-hub-kusama/src/lib.rs rename to bridges/primitives/chain-asset-hub-kusama/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml similarity index 79% rename from cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml rename to bridges/primitives/chain-asset-hub-polkadot/Cargo.toml index 6fe9ffab44b..857ead15b0d 100644 --- a/cumulus/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml @@ -11,8 +11,8 @@ codec = { package = "parity-scale-codec", version = "3.1.5", default-features = scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } # Bridge Dependencies bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } diff --git a/cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs b/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs rename to bridges/primitives/chain-asset-hub-polkadot/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml similarity index 62% rename from cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml rename to bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index 865cead3c87..24cf7236d45 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -15,13 +15,13 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot Dependencies -polkadot-primitives = { path = "../../../../polkadot/primitives", default-features = false } +polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs similarity index 72% rename from cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs rename to bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index feef61c7f20..c1dbc6db36f 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -23,10 +23,9 @@ pub use bp_polkadot_core::{ }; use bp_messages::*; +use bp_polkadot_core::SuffixedCommonSignedExtension; use bp_runtime::extensions::{ - BridgeRejectObsoleteHeadersAndMessages, ChargeTransactionPayment, CheckEra, CheckGenesis, - CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, CheckWeight, - GenericSignedExtension, RefundBridgedParachainMessagesSchema, + BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, }; use frame_support::{ dispatch::DispatchClass, @@ -133,88 +132,8 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; /// analysis (like the one above). pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; -/// Extra signed extension data that is used by all bridge hubs. -pub type SignedExtra = ( - CheckNonZeroSender, - CheckSpecVersion, - CheckTxVersion, - CheckGenesis, - CheckEra, - CheckNonce, - CheckWeight, - ChargeTransactionPayment, +/// Signed extension that is used by all bridge hubs. +pub type SignedExtension = SuffixedCommonSignedExtension<( BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, -); - -/// Signed extension that is used by all bridge hubs. -pub type SignedExtension = GenericSignedExtension; - -/// Helper trait to define some extra methods on bridge hubs signed extension (and -/// overcome Rust limitations). -pub trait BridgeHubSignedExtension { - /// Create signed extension from its components. - fn from_params( - spec_version: u32, - transaction_version: u32, - era: bp_runtime::TransactionEra, - genesis_hash: Hash, - nonce: Nonce, - tip: Balance, - ) -> Self; - - /// Return transaction nonce. - fn nonce(&self) -> Nonce; - - /// Return transaction tip. - fn tip(&self) -> Balance; -} - -impl BridgeHubSignedExtension for SignedExtension { - /// Create signed extension from its components. - fn from_params( - spec_version: u32, - transaction_version: u32, - era: bp_runtime::TransactionEra, - genesis_hash: Hash, - nonce: Nonce, - tip: Balance, - ) -> Self { - GenericSignedExtension::new( - ( - (), // non-zero sender - (), // spec version - (), // tx version - (), // genesis - era.frame_era(), // era - nonce.into(), // nonce (compact encoding) - (), // Check weight - tip.into(), // transaction payment / tip (compact encoding) - (), // bridge reject obsolete headers and msgs - (), // bridge reward to relayer for message passing - ), - Some(( - (), - spec_version, - transaction_version, - genesis_hash, - era.signed_payload(genesis_hash), - (), - (), - (), - (), - (), - )), - ) - } - - /// Return transaction nonce. - fn nonce(&self) -> Nonce { - self.payload.5 .0 - } - - /// Return transaction tip. - fn tip(&self) -> Balance { - self.payload.7 .0 - } -} +)>; diff --git a/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml similarity index 66% rename from cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml rename to bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index 92b0c9bf447..387f5e8ade6 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -15,10 +15,10 @@ bp-messages = { path = "../messages", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", 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 } +frame-support = { path = "../../../substrate/frame/support", 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" ] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs b/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs rename to bridges/primitives/chain-bridge-hub-kusama/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml similarity index 66% rename from cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml rename to bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 7468d5be60d..40b386e22d2 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -16,10 +16,10 @@ bp-messages = { path = "../messages", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", 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 } +frame-support = { path = "../../../substrate/frame/support", 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" ] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs b/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs rename to bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml similarity index 66% rename from cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml rename to bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index 8dde903701c..05b8163e9fc 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -15,10 +15,10 @@ bp-messages = { path = "../messages", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", 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 } +frame-support = { path = "../../../substrate/frame/support", 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" ] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs rename to bridges/primitives/chain-bridge-hub-rococo/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml similarity index 66% rename from cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml rename to bridges/primitives/chain-bridge-hub-wococo/Cargo.toml index c93cdad5110..17c134f4412 100644 --- a/cumulus/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml @@ -16,10 +16,10 @@ bp-messages = { path = "../messages", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", 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 } +frame-support = { path = "../../../substrate/frame/support", 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" ] diff --git a/cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs rename to bridges/primitives/chain-bridge-hub-wococo/src/lib.rs diff --git a/cumulus/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml similarity index 71% rename from cumulus/bridges/primitives/chain-kusama/Cargo.toml rename to bridges/primitives/chain-kusama/Cargo.toml index e404bdb3d94..2d63c3f374f 100644 --- a/cumulus/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -16,9 +16,9 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs similarity index 96% rename from cumulus/bridges/primitives/chain-kusama/src/lib.rs rename to bridges/primitives/chain-kusama/src/lib.rs index e234a87b6cf..8c3fbd9c203 100644 --- a/cumulus/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -57,6 +57,9 @@ impl ChainWithGrandpa for Kusama { const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; } +// The SignedExtension used by Kusama. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; + /// Name of the parachains pallet in the Kusama runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/cumulus/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml similarity index 71% rename from cumulus/bridges/primitives/chain-polkadot/Cargo.toml rename to bridges/primitives/chain-polkadot/Cargo.toml index 4d9bf8c182f..539b10ef9c6 100644 --- a/cumulus/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -16,9 +16,9 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs similarity index 92% rename from cumulus/bridges/primitives/chain-polkadot/src/lib.rs rename to bridges/primitives/chain-polkadot/src/lib.rs index 9585fd4d716..d1d6f745431 100644 --- a/cumulus/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -21,7 +21,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; -use bp_runtime::{decl_bridge_finality_runtime_apis, Chain}; +use bp_runtime::{decl_bridge_finality_runtime_apis, extensions::PrevalidateAttests, Chain}; use frame_support::weights::Weight; use sp_std::prelude::Vec; @@ -57,6 +57,9 @@ impl ChainWithGrandpa for Polkadot { const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; } +/// The SignedExtension used by Polkadot. +pub type SignedExtension = SuffixedCommonSignedExtension; + /// Name of the parachains pallet in the Polkadot runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/cumulus/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml similarity index 71% rename from cumulus/bridges/primitives/chain-rococo/Cargo.toml rename to bridges/primitives/chain-rococo/Cargo.toml index 72c6d4c03b6..3c4d3917bc2 100644 --- a/cumulus/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -16,9 +16,9 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs similarity index 96% rename from cumulus/bridges/primitives/chain-rococo/src/lib.rs rename to bridges/primitives/chain-rococo/src/lib.rs index cf7cd16990f..1589d14ea51 100644 --- a/cumulus/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -61,6 +61,9 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +// The SignedExtension used by Rococo. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; + /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/cumulus/bridges/primitives/chain-wococo/Cargo.toml b/bridges/primitives/chain-wococo/Cargo.toml similarity index 73% rename from cumulus/bridges/primitives/chain-wococo/Cargo.toml rename to bridges/primitives/chain-wococo/Cargo.toml index f7feb7f96eb..05901821b36 100644 --- a/cumulus/bridges/primitives/chain-wococo/Cargo.toml +++ b/bridges/primitives/chain-wococo/Cargo.toml @@ -17,9 +17,9 @@ bp-rococo = { path = "../chain-rococo", default-features = false } # Substrate Based Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs similarity index 96% rename from cumulus/bridges/primitives/chain-wococo/src/lib.rs rename to bridges/primitives/chain-wococo/src/lib.rs index c64451993ee..5b5bde82690 100644 --- a/cumulus/bridges/primitives/chain-wococo/src/lib.rs +++ b/bridges/primitives/chain-wococo/src/lib.rs @@ -60,6 +60,9 @@ impl ChainWithGrandpa for Wococo { const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; } +// The SignedExtension used by Wococo. +pub use bp_rococo::CommonSignedExtension as SignedExtension; + /// Name of the With-Wococo GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_WOCOCO_GRANDPA_PALLET_NAME: &str = "BridgeWococoGrandpa"; diff --git a/cumulus/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml similarity index 66% rename from cumulus/bridges/primitives/header-chain/Cargo.toml rename to bridges/primitives/header-chain/Cargo.toml index a7b53b0336d..e3e83235960 100644 --- a/cumulus/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -18,11 +18,11 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-consensus-grandpa = { path = "../../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } +sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [dev-dependencies] bp-test-utils = { path = "../test-utils" } diff --git a/cumulus/bridges/primitives/header-chain/src/justification/mod.rs b/bridges/primitives/header-chain/src/justification/mod.rs similarity index 97% rename from cumulus/bridges/primitives/header-chain/src/justification/mod.rs rename to bridges/primitives/header-chain/src/justification/mod.rs index 24c453a0790..72a5f68918d 100644 --- a/cumulus/bridges/primitives/header-chain/src/justification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/mod.rs @@ -97,7 +97,11 @@ impl GrandpaJustification { } } -impl crate::FinalityProof for GrandpaJustification { +impl crate::FinalityProof for GrandpaJustification { + fn target_header_hash(&self) -> H::Hash { + self.commit.target_hash + } + fn target_header_number(&self) -> H::Number { self.commit.target_number } diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/src/justification/verification/equivocation.rs rename to bridges/primitives/header-chain/src/justification/verification/equivocation.rs diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/src/justification/verification/mod.rs rename to bridges/primitives/header-chain/src/justification/verification/mod.rs diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/src/justification/verification/optimizer.rs rename to bridges/primitives/header-chain/src/justification/verification/optimizer.rs diff --git a/cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs b/bridges/primitives/header-chain/src/justification/verification/strict.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/src/justification/verification/strict.rs rename to bridges/primitives/header-chain/src/justification/verification/strict.rs diff --git a/cumulus/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs similarity index 98% rename from cumulus/bridges/primitives/header-chain/src/lib.rs rename to bridges/primitives/header-chain/src/lib.rs index 7008dfa6063..d2c7ec0759e 100644 --- a/cumulus/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -127,7 +127,10 @@ pub struct InitializationData { } /// Abstract finality proof that is justifying block finality. -pub trait FinalityProof: Clone + Send + Sync + Debug { +pub trait FinalityProof: Clone + Send + Sync + Debug { + /// Return hash of header that this proof is generated for. + fn target_header_hash(&self) -> Hash; + /// Return number of header that this proof is generated for. fn target_header_number(&self) -> Number; } @@ -209,7 +212,7 @@ impl TryFrom> for HeaderGrandpa /// Helper trait for finding equivocations in finality proofs. pub trait FindEquivocations { /// The type returned when encountering an error while looking for equivocations. - type Error; + type Error: Debug; /// Find equivocations. fn find_equivocations( diff --git a/cumulus/bridges/primitives/header-chain/src/storage_keys.rs b/bridges/primitives/header-chain/src/storage_keys.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/src/storage_keys.rs rename to bridges/primitives/header-chain/src/storage_keys.rs diff --git a/cumulus/bridges/primitives/header-chain/tests/implementation_match.rs b/bridges/primitives/header-chain/tests/implementation_match.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/tests/implementation_match.rs rename to bridges/primitives/header-chain/tests/implementation_match.rs diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs b/bridges/primitives/header-chain/tests/justification/equivocation.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/tests/justification/equivocation.rs rename to bridges/primitives/header-chain/tests/justification/equivocation.rs diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs b/bridges/primitives/header-chain/tests/justification/optimizer.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/tests/justification/optimizer.rs rename to bridges/primitives/header-chain/tests/justification/optimizer.rs diff --git a/cumulus/bridges/primitives/header-chain/tests/justification/strict.rs b/bridges/primitives/header-chain/tests/justification/strict.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/tests/justification/strict.rs rename to bridges/primitives/header-chain/tests/justification/strict.rs diff --git a/cumulus/bridges/primitives/header-chain/tests/tests.rs b/bridges/primitives/header-chain/tests/tests.rs similarity index 100% rename from cumulus/bridges/primitives/header-chain/tests/tests.rs rename to bridges/primitives/header-chain/tests/tests.rs diff --git a/cumulus/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml similarity index 78% rename from cumulus/bridges/primitives/messages/Cargo.toml rename to bridges/primitives/messages/Cargo.toml index b1fa6d575ae..b30d6d2559f 100644 --- a/cumulus/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -18,9 +18,9 @@ bp-header-chain = { path = "../header-chain", default-features = false } # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [dev-dependencies] hex = "0.4" diff --git a/cumulus/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/messages/src/lib.rs rename to bridges/primitives/messages/src/lib.rs diff --git a/cumulus/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs similarity index 100% rename from cumulus/bridges/primitives/messages/src/source_chain.rs rename to bridges/primitives/messages/src/source_chain.rs diff --git a/cumulus/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs similarity index 100% rename from cumulus/bridges/primitives/messages/src/storage_keys.rs rename to bridges/primitives/messages/src/storage_keys.rs diff --git a/cumulus/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs similarity index 100% rename from cumulus/bridges/primitives/messages/src/target_chain.rs rename to bridges/primitives/messages/src/target_chain.rs diff --git a/cumulus/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml similarity index 72% rename from cumulus/bridges/primitives/parachains/Cargo.toml rename to bridges/primitives/parachains/Cargo.toml index 978296954bb..ca69523dde3 100644 --- a/cumulus/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -19,10 +19,10 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate dependencies -frame-support = { path = "../../../../substrate/frame/support", 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 } +frame-support = { path = "../../../substrate/frame/support", 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 } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/parachains/src/lib.rs rename to bridges/primitives/parachains/src/lib.rs diff --git a/cumulus/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml similarity index 69% rename from cumulus/bridges/primitives/polkadot-core/Cargo.toml rename to bridges/primitives/polkadot-core/Cargo.toml index 2563adaf219..aa7eb8024fb 100644 --- a/cumulus/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -19,11 +19,11 @@ 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-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 } +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] hex = "0.4" diff --git a/cumulus/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs similarity index 81% rename from cumulus/bridges/primitives/polkadot-core/src/lib.rs rename to bridges/primitives/polkadot-core/src/lib.rs index b35d97ec79a..af39b5ab9ba 100644 --- a/cumulus/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -17,7 +17,15 @@ #![cfg_attr(not(feature = "std"), no_std)] use bp_messages::MessageNonce; -use bp_runtime::{Chain, EncodedOrDecodedCall, StorageMapKeyProvider}; +use bp_runtime::{ + self, + extensions::{ + ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, + CheckSpecVersion, CheckTxVersion, CheckWeight, GenericSignedExtension, + SignedExtensionSchema, + }, + Chain, EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra, +}; use frame_support::{ dispatch::DispatchClass, parameter_types, @@ -272,6 +280,99 @@ impl AccountInfoStorageMapKeyProvider { } } +/// Extra signed extension data that is used by most chains. +pub type CommonSignedExtra = ( + CheckNonZeroSender, + CheckSpecVersion, + CheckTxVersion, + CheckGenesis, + CheckEra, + CheckNonce, + CheckWeight, + ChargeTransactionPayment, +); + +/// Extra signed extension data that starts with `CommonSignedExtra`. +pub type SuffixedCommonSignedExtension = + GenericSignedExtension<(CommonSignedExtra, Suffix)>; + +/// Helper trait to define some extra methods on `SuffixedCommonSignedExtension`. +pub trait SuffixedCommonSignedExtensionExt { + /// Create signed extension from its components. + fn from_params( + spec_version: u32, + transaction_version: u32, + era: TransactionEra, + genesis_hash: Hash, + nonce: Nonce, + tip: Balance, + extra: (Suffix::Payload, Suffix::AdditionalSigned), + ) -> Self; + + /// Return transaction nonce. + fn nonce(&self) -> Nonce; + + /// Return transaction tip. + fn tip(&self) -> Balance; +} + +impl SuffixedCommonSignedExtensionExt for SuffixedCommonSignedExtension +where + Suffix: SignedExtensionSchema, +{ + fn from_params( + spec_version: u32, + transaction_version: u32, + era: TransactionEra, + genesis_hash: Hash, + nonce: Nonce, + tip: Balance, + extra: (Suffix::Payload, Suffix::AdditionalSigned), + ) -> Self { + GenericSignedExtension::new( + ( + ( + (), // non-zero sender + (), // spec version + (), // tx version + (), // genesis + era.frame_era(), // era + nonce.into(), // nonce (compact encoding) + (), // Check weight + tip.into(), // transaction payment / tip (compact encoding) + ), + extra.0, + ), + Some(( + ( + (), + spec_version, + transaction_version, + genesis_hash, + era.signed_payload(genesis_hash), + (), + (), + (), + ), + extra.1, + )), + ) + } + + fn nonce(&self) -> Nonce { + let common_payload = self.payload.0; + common_payload.5 .0 + } + + fn tip(&self) -> Balance { + let common_payload = self.payload.0; + common_payload.7 .0 + } +} + +/// Signed extension that is used by most chains. +pub type CommonSignedExtension = SuffixedCommonSignedExtension<()>; + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/bridges/primitives/polkadot-core/src/parachains.rs b/bridges/primitives/polkadot-core/src/parachains.rs similarity index 100% rename from cumulus/bridges/primitives/polkadot-core/src/parachains.rs rename to bridges/primitives/polkadot-core/src/parachains.rs diff --git a/cumulus/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml similarity index 74% rename from cumulus/bridges/primitives/relayers/Cargo.toml rename to bridges/primitives/relayers/Cargo.toml index bc674d4cb77..99cd79c6841 100644 --- a/cumulus/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -17,9 +17,9 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } [dev-dependencies] hex = "0.4" diff --git a/cumulus/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/relayers/src/lib.rs rename to bridges/primitives/relayers/src/lib.rs diff --git a/cumulus/bridges/primitives/relayers/src/registration.rs b/bridges/primitives/relayers/src/registration.rs similarity index 100% rename from cumulus/bridges/primitives/relayers/src/registration.rs rename to bridges/primitives/relayers/src/registration.rs diff --git a/cumulus/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml similarity index 60% rename from cumulus/bridges/primitives/runtime/Cargo.toml rename to bridges/primitives/runtime/Cargo.toml index f6134d6e332..98269a1ffbb 100644 --- a/cumulus/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -17,14 +17,14 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv # Substrate Dependencies -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../../substrate/primitives/trie", 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-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } +sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } trie-db = { version = "0.27.1", default-features = false } [dev-dependencies] diff --git a/cumulus/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs similarity index 100% rename from cumulus/bridges/primitives/runtime/src/chain.rs rename to bridges/primitives/runtime/src/chain.rs diff --git a/cumulus/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs similarity index 94% rename from cumulus/bridges/primitives/runtime/src/extensions.rs rename to bridges/primitives/runtime/src/extensions.rs index 253350d17e7..44eeaad93c9 100644 --- a/cumulus/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -35,7 +35,12 @@ pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTy type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; } -// An implementation of `SignedExtensionSchema` using generic params. +impl SignedExtensionSchema for () { + type Payload = (); + type AdditionalSigned = (); +} + +/// An implementation of `SignedExtensionSchema` using generic params. #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); @@ -72,6 +77,9 @@ pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; /// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; +/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. +pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>; + /// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; @@ -99,7 +107,7 @@ pub struct GenericSignedExtension { // It may be set to `None` if extensions are decoded. We are never reconstructing transactions // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to // read fields of the `payload`. And when resigning transaction, we're reconstructing - // `SignedExtensions` from the scratch. + // `SignedExtensions` from scratch. additional_signed: Option, } diff --git a/cumulus/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/runtime/src/lib.rs rename to bridges/primitives/runtime/src/lib.rs diff --git a/cumulus/bridges/primitives/runtime/src/messages.rs b/bridges/primitives/runtime/src/messages.rs similarity index 100% rename from cumulus/bridges/primitives/runtime/src/messages.rs rename to bridges/primitives/runtime/src/messages.rs diff --git a/cumulus/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs similarity index 100% rename from cumulus/bridges/primitives/runtime/src/storage_proof.rs rename to bridges/primitives/runtime/src/storage_proof.rs diff --git a/cumulus/bridges/primitives/runtime/src/storage_types.rs b/bridges/primitives/runtime/src/storage_types.rs similarity index 100% rename from cumulus/bridges/primitives/runtime/src/storage_types.rs rename to bridges/primitives/runtime/src/storage_types.rs diff --git a/cumulus/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml similarity index 63% rename from cumulus/bridges/primitives/test-utils/Cargo.toml rename to bridges/primitives/test-utils/Cargo.toml index f6e8533705e..652ffe985c6 100644 --- a/cumulus/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -14,12 +14,12 @@ bp-runtime = { path = "../runtime", default-features = false } codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } ed25519-dalek = { version = "2.0", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false } -sp-consensus-grandpa = { path = "../../../../substrate/primitives/consensus/grandpa", 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 } -sp-trie = { path = "../../../../substrate/primitives/trie", default-features = false } +sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } +sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", 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 } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/test-utils/src/keyring.rs b/bridges/primitives/test-utils/src/keyring.rs similarity index 100% rename from cumulus/bridges/primitives/test-utils/src/keyring.rs rename to bridges/primitives/test-utils/src/keyring.rs diff --git a/cumulus/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/test-utils/src/lib.rs rename to bridges/primitives/test-utils/src/lib.rs diff --git a/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml similarity index 76% rename from cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml rename to bridges/primitives/xcm-bridge-hub-router/Cargo.toml index df2b00563de..725a7d94564 100644 --- a/cumulus/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -11,8 +11,8 @@ codec = { package = "parity-scale-codec", version = "3.1.5", default-features = scale-info = { version = "2.9.0", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs similarity index 100% rename from cumulus/bridges/primitives/xcm-bridge-hub-router/src/lib.rs rename to bridges/primitives/xcm-bridge-hub-router/src/lib.rs diff --git a/cumulus/bridges/scripts/verify-pallets-build.sh b/bridges/scripts/verify-pallets-build.sh similarity index 93% rename from cumulus/bridges/scripts/verify-pallets-build.sh rename to bridges/scripts/verify-pallets-build.sh index 1ea3dbe8626..b8ac09e26b8 100755 --- a/cumulus/bridges/scripts/verify-pallets-build.sh +++ b/bridges/scripts/verify-pallets-build.sh @@ -89,17 +89,26 @@ rm -rf $BRIDGES_FOLDER/scripts/update-weights-setup.sh rm -rf $BRIDGES_FOLDER/scripts/update_substrate.sh rm -rf $BRIDGES_FOLDER/tools rm -f $BRIDGES_FOLDER/.dockerignore +rm -f $BRIDGES_FOLDER/local.Dockerfile.dockerignore rm -f $BRIDGES_FOLDER/deny.toml rm -f $BRIDGES_FOLDER/.gitlab-ci.yml rm -f $BRIDGES_FOLDER/.editorconfig rm -f $BRIDGES_FOLDER/Cargo.toml rm -f $BRIDGES_FOLDER/ci.Dockerfile +rm -f $BRIDGES_FOLDER/local.Dockerfile rm -f $BRIDGES_FOLDER/CODEOWNERS rm -f $BRIDGES_FOLDER/Dockerfile +rm -f $BRIDGES_FOLDER/rustfmt.toml # let's fix Cargo.toml a bit (it'll be helpful if we are in the bridges repo) if [[ ! -f "Cargo.toml" ]]; then cat > Cargo.toml <<-CARGO_TOML + [workspace.package] + authors = ["Parity Technologies "] + edition = "2021" + repository = "https://github.com/paritytech/parity-bridges-common.git" + license = "GPL-3.0-only" + [workspace] resolver = "2" 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 ee689685554..c02c96255e1 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 @@ -25,8 +25,8 @@ pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-featu parachains-common = { path = "../../../../common" } cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} -pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false} -bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false} +pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} +bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index ac1e650d5de..925d2fc1939 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -56,9 +56,9 @@ xcm-emulator = { path = "../../../../xcm/xcm-emulator", default-features = false cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue" } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } -bp-messages = { path = "../../../../bridges/primitives/messages" } -pallet-bridge-messages = { path = "../../../../bridges/modules/messages" } -bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common" } +bp-messages = { path = "../../../../../bridges/primitives/messages" } +pallet-bridge-messages = { path = "../../../../../bridges/modules/messages" } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common" } [features] runtime-benchmarks = [ 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 d65fb9b72cd..395edafa651 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -72,26 +72,26 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-common = { path = "../../../common", default-features = false } # Bridges -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 } -bp-messages = { path = "../../../../bridges/primitives/messages", default-features = false } -bp-parachains = { path = "../../../../bridges/primitives/parachains", default-features = false } -bp-polkadot-core = { path = "../../../../bridges/primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../../../bridges/primitives/relayers", default-features = false } -bp-runtime = { path = "../../../../bridges/primitives/runtime", default-features = false } -bp-rococo = { path = "../../../../bridges/primitives/chain-rococo", default-features = false } -bp-wococo = { path = "../../../../bridges/primitives/chain-wococo", default-features = false } -pallet-bridge-grandpa = { path = "../../../../bridges/modules/grandpa", default-features = false } -pallet-bridge-messages = { path = "../../../../bridges/modules/messages", default-features = false } -pallet-bridge-parachains = { path = "../../../../bridges/modules/parachains", default-features = false } -pallet-bridge-relayers = { path = "../../../../bridges/modules/relayers", default-features = false } -bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common", 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 } +bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } +bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } +bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } +bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } +bp-wococo = { path = "../../../../../bridges/primitives/chain-wococo", default-features = false } +pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } +pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } [dev-dependencies] static_assertions = "1.1" bridge-hub-test-utils = { path = "../test-utils" } -bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common", features = ["integrity-test"] } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = ["integrity-test"] } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] 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 4311a6a629f..309a5cfb0b1 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 @@ -1243,55 +1243,67 @@ cumulus_pallet_parachain_system::register_validate_block! { #[cfg(test)] mod tests { use super::*; - use bp_runtime::TransactionEra; - use bridge_hub_test_utils::test_header; use codec::Encode; - - pub type TestBlockHeader = - sp_runtime::generic::Header; + use sp_runtime::{ + generic::Era, + traits::{SignedExtension, Zero}, + }; #[test] fn ensure_signed_extension_definition_is_compatible_with_relay() { - let payload: SignedExtra = ( - frame_system::CheckNonZeroSender::new(), - frame_system::CheckSpecVersion::new(), - frame_system::CheckTxVersion::new(), - frame_system::CheckGenesis::new(), - frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal), - frame_system::CheckNonce::from(10), - frame_system::CheckWeight::new(), - pallet_transaction_payment::ChargeTransactionPayment::from(10), - BridgeRejectObsoleteHeadersAndMessages {}, - ( - BridgeRefundBridgeHubRococoMessages::default(), - BridgeRefundBridgeHubWococoMessages::default(), - ), - ); - - { - use bp_bridge_hub_rococo::BridgeHubSignedExtension; - let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( - 10, - 10, - TransactionEra::Immortal, - test_header::(1).hash(), - 10, - 10, + use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + + sp_io::TestExternalities::default().execute_with(|| { + frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); + let payload: SignedExtra = ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(10), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(10), + BridgeRejectObsoleteHeadersAndMessages, + ( + BridgeRefundBridgeHubRococoMessages::default(), + BridgeRefundBridgeHubWococoMessages::default(), + ), ); - assert_eq!(payload.encode(), bhr_indirect_payload.encode()); - } - { - use bp_bridge_hub_wococo::BridgeHubSignedExtension; - let bhw_indirect_payload = bp_bridge_hub_wococo::SignedExtension::from_params( - 10, - 10, - TransactionEra::Immortal, - test_header::(1).hash(), - 10, - 10, - ); - assert_eq!(payload.encode(), bhw_indirect_payload.encode()); - } + { + let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( + VERSION.spec_version, + VERSION.transaction_version, + bp_runtime::TransactionEra::Immortal, + System::block_hash(BlockNumber::zero()), + 10, + 10, + (((), ()), ((), ())), + ); + assert_eq!(payload.encode(), bhr_indirect_payload.encode()); + assert_eq!( + payload.additional_signed().unwrap().encode(), + bhr_indirect_payload.additional_signed().unwrap().encode() + ) + } + + { + let bhw_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( + VERSION.spec_version, + VERSION.transaction_version, + bp_runtime::TransactionEra::Immortal, + System::block_hash(BlockNumber::zero()), + 10, + 10, + (((), ()), ((), ())), + ); + assert_eq!(payload.encode(), bhw_indirect_payload.encode()); + assert_eq!( + payload.additional_signed().unwrap().encode(), + bhw_indirect_payload.additional_signed().unwrap().encode() + ) + } + }); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 73678e8f91a..4a15640952d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -42,20 +42,20 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} # Bridges -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 } -bp-messages = { path = "../../../../bridges/primitives/messages", default-features = false } -bp-parachains = { path = "../../../../bridges/primitives/parachains", default-features = false } -bp-polkadot-core = { path = "../../../../bridges/primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../../../bridges/primitives/relayers", default-features = false } -bp-runtime = { path = "../../../../bridges/primitives/runtime", default-features = false } -bp-test-utils = { path = "../../../../bridges/primitives/test-utils", default-features = false } -pallet-bridge-grandpa = { path = "../../../../bridges/modules/grandpa", default-features = false } -pallet-bridge-parachains = { path = "../../../../bridges/modules/parachains", default-features = false } -pallet-bridge-messages = { path = "../../../../bridges/modules/messages", default-features = false } -pallet-bridge-relayers = { path = "../../../../bridges/modules/relayers", default-features = false } -bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common", 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 } +bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } +bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } +bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } +bp-test-utils = { path = "../../../../../bridges/primitives/test-utils", default-features = false } +pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } +pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } +pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } +pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/scripts/bridges_update_subtree.sh b/scripts/bridges_update_subtree.sh similarity index 100% rename from cumulus/scripts/bridges_update_subtree.sh rename to scripts/bridges_update_subtree.sh -- GitLab From 5b3f659ce38fea2eff142f4724bcf71ef5862c74 Mon Sep 17 00:00:00 2001 From: eskimor Date: Mon, 11 Sep 2023 11:25:40 +0200 Subject: [PATCH 114/633] Remove redundant book keeping in dispute coordinator. (#1432) * Remove redundant book keeping in dispute coordinator. * Fix docs. --------- Co-authored-by: eskimor --- .../src/scraping/candidates.rs | 11 +- .../dispute-coordinator/src/scraping/mod.rs | 103 ++++++++++-------- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs b/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs index b1870164cb8..c7c9c519916 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/candidates.rs @@ -120,18 +120,13 @@ impl ScrapedCandidates { // Removes all candidates up to a given height. The candidates at the block height are NOT // removed. - pub fn remove_up_to_height(&mut self, height: &BlockNumber) -> HashSet { - let mut candidates_modified: HashSet = HashSet::new(); + pub fn remove_up_to_height(&mut self, height: &BlockNumber) { let not_stale = self.candidates_by_block_number.split_off(&height); let stale = std::mem::take(&mut self.candidates_by_block_number); self.candidates_by_block_number = not_stale; - for candidates in stale.values() { - for c in candidates { - self.candidates.remove(c); - candidates_modified.insert(*c); - } + for candidate in stale.values().flatten() { + self.candidates.remove(candidate); } - candidates_modified } pub fn insert(&mut self, block_number: BlockNumber, candidate_hash: CandidateHash) { diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs index 67434bca85d..58f409b9311 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::collections::{BTreeMap, HashSet}; +use std::collections::{btree_map::Entry, BTreeMap, HashSet}; use futures::channel::oneshot; use schnellru::{ByLength, LruMap}; @@ -78,49 +78,66 @@ impl ScrapedUpdates { /// concluding against a candidate. Each candidate hash maps to a number of /// block heights, which in turn map to vectors of blocks at those heights. pub struct Inclusions { - inclusions_inner: BTreeMap>>, + inclusions_inner: BTreeMap>>, + /// Keeps track at which block number a candidate was inserted. Used in `remove_up_to_height`. + /// Without this tracking we won't be able to remove all candidates before block X. + candidates_by_block_number: BTreeMap>, } impl Inclusions { pub fn new() -> Self { - Self { inclusions_inner: BTreeMap::new() } + Self { inclusions_inner: BTreeMap::new(), candidates_by_block_number: BTreeMap::new() } } - // Add parent block to the vector which has CandidateHash as an outer key and - // BlockNumber as an inner key pub fn insert( &mut self, candidate_hash: CandidateHash, block_number: BlockNumber, block_hash: Hash, ) { - if let Some(blocks_including) = self.inclusions_inner.get_mut(&candidate_hash) { - if let Some(blocks_at_height) = blocks_including.get_mut(&block_number) { - blocks_at_height.push(block_hash); - } else { - blocks_including.insert(block_number, Vec::from([block_hash])); - } - } else { - let mut blocks_including: BTreeMap> = BTreeMap::new(); - blocks_including.insert(block_number, Vec::from([block_hash])); - self.inclusions_inner.insert(candidate_hash, blocks_including); - } + self.inclusions_inner + .entry(candidate_hash) + .or_default() + .entry(block_number) + .or_default() + .insert(block_hash); + + self.candidates_by_block_number + .entry(block_number) + .or_default() + .insert(candidate_hash); } - pub fn remove_up_to_height( - &mut self, - height: &BlockNumber, - candidates_modified: HashSet, - ) { - for candidate in candidates_modified { - if let Some(blocks_including) = self.inclusions_inner.get_mut(&candidate) { - // Returns everything after the given key, including the key. This works because the - // blocks are sorted in ascending order. - *blocks_including = blocks_including.split_off(height); + /// Removes all candidates up to a given height. + /// + /// The candidates at the block height are NOT removed. + pub fn remove_up_to_height(&mut self, height: &BlockNumber) { + let not_stale = self.candidates_by_block_number.split_off(&height); + let stale = std::mem::take(&mut self.candidates_by_block_number); + self.candidates_by_block_number = not_stale; + + for candidate in stale.into_values().flatten() { + debug_assert!(self.inclusions_inner.get(&candidate).is_some()); + match self.inclusions_inner.entry(candidate) { + Entry::Vacant(_) => { + gum::debug!( + target: LOG_TARGET, + "Inconsistency in `Inclusions` detected on pruning!" + ); + }, + Entry::Occupied(mut e) => { + let mut blocks_including = std::mem::take(e.get_mut()); + // Returns everything after the given key, including the key. This works because + // the blocks are sorted in ascending order. + blocks_including = blocks_including.split_off(&height); + if blocks_including.is_empty() { + e.remove_entry(); + } else { + *e.get_mut() = blocks_including; + } + }, } } - self.inclusions_inner - .retain(|_, blocks_including| blocks_including.keys().len() > 0); } pub fn get(&self, candidate: &CandidateHash) -> Vec<(BlockNumber, Hash)> { @@ -134,6 +151,10 @@ impl Inclusions { } inclusions_as_vec } + + pub fn contains(&self, candidate: &CandidateHash) -> bool { + self.inclusions_inner.get(candidate).is_some() + } } /// Chain scraper @@ -159,20 +180,20 @@ impl Inclusions { /// another precaution to have their `CandidateReceipts` available in case a dispute is raised on /// them, pub struct ChainScraper { - /// All candidates we have seen included, which not yet have been finalized. - included_candidates: candidates::ScrapedCandidates, - /// All candidates we have seen backed + /// All candidates we have seen backed. backed_candidates: candidates::ScrapedCandidates, - /// Latest relay blocks observed by the provider. - /// - /// We assume that ancestors of cached blocks are already processed, i.e. we have saved - /// corresponding included candidates. - last_observed_blocks: LruMap, + /// Maps included candidate hashes to one or more relay block heights and hashes. /// These correspond to all the relay blocks which marked a candidate as included, /// and are needed to apply reversions in case a dispute is concluded against the /// candidate. inclusions: Inclusions, + + /// Latest relay blocks observed by the provider. + /// + /// This is used to avoid redundant scraping of ancestry. We assume that ancestors of cached + /// blocks are already processed, i.e. we have saved corresponding included candidates. + last_observed_blocks: LruMap, } impl ChainScraper { @@ -194,10 +215,9 @@ impl ChainScraper { Sender: overseer::DisputeCoordinatorSenderTrait, { let mut s = Self { - included_candidates: candidates::ScrapedCandidates::new(), backed_candidates: candidates::ScrapedCandidates::new(), - last_observed_blocks: LruMap::new(ByLength::new(LRU_OBSERVED_BLOCKS_CAPACITY)), inclusions: Inclusions::new(), + last_observed_blocks: LruMap::new(ByLength::new(LRU_OBSERVED_BLOCKS_CAPACITY)), }; let update = ActiveLeavesUpdate { activated: Some(initial_head), deactivated: Default::default() }; @@ -207,7 +227,7 @@ impl ChainScraper { /// Check whether we have seen a candidate included on any chain. pub fn is_candidate_included(&self, candidate_hash: &CandidateHash) -> bool { - self.included_candidates.contains(candidate_hash) + self.inclusions.contains(candidate_hash) } /// Check whether the candidate is backed @@ -298,9 +318,7 @@ impl ChainScraper { { Some(key_to_prune) => { self.backed_candidates.remove_up_to_height(&key_to_prune); - let candidates_modified = - self.included_candidates.remove_up_to_height(&key_to_prune); - self.inclusions.remove_up_to_height(&key_to_prune, candidates_modified); + self.inclusions.remove_up_to_height(&key_to_prune); }, None => { // Nothing to prune. We are still in the beginning of the chain and there are not @@ -337,7 +355,6 @@ impl ChainScraper { ?block_number, "Processing included event" ); - self.included_candidates.insert(block_number, candidate_hash); self.inclusions.insert(candidate_hash, block_number, block_hash); included_receipts.push(receipt); }, -- GitLab From cdf0de6714caa3eb01f364c76b170ce10e75865c Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 11 Sep 2023 11:33:32 +0200 Subject: [PATCH 115/633] Merge `CODEOWNERS` Part 1 (#1472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge CODEOWNERS * Add the XCM team as owner of /polkadot/xcm * Update .github/CODEOWNERS Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --------- Co-authored-by: Francisco Aguirre Co-authored-by: Bastian Köcher Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .github/CODEOWNERS | 75 +++++++++++++++++++++++++++++++++++++ cumulus/CODEOWNERS | 23 ------------ polkadot/.github/CODEOWNERS | 6 --- substrate/docs/CODEOWNERS | 74 ------------------------------------ 4 files changed, 75 insertions(+), 103 deletions(-) create mode 100644 .github/CODEOWNERS delete mode 100644 cumulus/CODEOWNERS delete mode 100644 polkadot/.github/CODEOWNERS delete mode 100644 substrate/docs/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..fdaa0c8628f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,75 @@ +# Lists some code owners. +# +# A codeowner just oversees some part of the codebase. If an owned file is changed then the +# corresponding codeowner receives a review request. An approval of the codeowner might be +# required for merging a PR (depends on repository settings). +# +# For details about syntax, see: +# https://help.github.com/en/articles/about-code-owners +# But here are some important notes: +# +# - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` +# which can be everywhere. +# - Multiple owners are supported. +# - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind, +# that handles might work better because they are more recognizable on GitHub, +# eyou can use them for mentioning unlike an email. +# - The latest matching rule, if multiple, takes precedence. + +# CI +/.github/ @paritytech/ci @paritytech/release-engineering +/.gitlab-ci.yml @paritytech/ci +/.gitlab/ @paritytech/ci + +# XCM +/polkadot/xcm/ @paritytech/xcm + +# WASM executor, low-level client <-> WASM interface and other WASM-related code +/substrate/client/allocator/ @koute +/substrate/client/executor/ @koute +/substrate/primitives/panic-handler/ @koute +/substrate/primitives/runtime-interface/ @koute +/substrate/primitives/wasm-interface/ @koute +/substrate/utils/wasm-builder/ @koute + +# Systems-related bits and bobs on the client side +/substrate/client/sysinfo/ @koute +/substrate/client/tracing/ @koute + +# Documentation audit +/substrate/primitives/runtime @paritytech/docs-audit +/substrate/primitives/arithmetic @paritytech/docs-audit +# /primitives/core (to be added later) +# /primitives/io (to be added later) + +# FRAME +/substrate/frame/ @paritytech/frame-coders @paritytech/docs-audit +/substrate/frame/nfts/ @jsidorenko @paritytech/docs-audit +/substrate/frame/state-trie-migration/ @paritytech/frame-coders @cheme +/substrate/frame/uniques/ @jsidorenko @paritytech/docs-audit + +# GRANDPA, BABE, consensus stuff +/substrate/client/consensus/babe/ @andresilva +/substrate/client/consensus/grandpa/ @andresilva +/substrate/client/consensus/pow/ @sorpaas +/substrate/client/consensus/slots/ @andresilva +/substrate/frame/babe/ @andresilva +/substrate/frame/grandpa/ @andresilva +/substrate/primitives/consensus/pow/ @sorpaas + +# BEEFY, MMR +/substrate/frame/beefy/ @acatangiu +/substrate/frame/beefy-mmr/ @acatangiu +/substrate/frame/merkle-mountain-range/ @acatangiu +/substrate/primitives/merkle-mountain-range/ @acatangiu + +# Contracts +/substrate/frame/contracts/ @athei @paritytech/docs-audit + +# NPoS and election +/substrate/frame/election-provider-multi-phase/ @paritytech/staking-core @paritytech/docs-audit +/substrate/frame/election-provider-support/ @paritytech/staking-core @paritytech/docs-audit +/substrate/frame/elections-phragmen/ @paritytech/staking-core @paritytech/docs-audit +/substrate/frame/nomination-pools/ @paritytech/staking-core @paritytech/docs-audit +/substrate/frame/staking/ @paritytech/staking-core @paritytech/docs-audit +/substrate/primitives/npos-elections/ @paritytech/staking-core @paritytech/docs-audit diff --git a/cumulus/CODEOWNERS b/cumulus/CODEOWNERS deleted file mode 100644 index 3e5e8bd062d..00000000000 --- a/cumulus/CODEOWNERS +++ /dev/null @@ -1,23 +0,0 @@ -# Lists some code owners. -# -# A codeowner just oversees some part of the codebase. If an owned file is changed then the -# corresponding codeowner receives a review request. An approval of the codeowner might be -# required for merging a PR (depends on repository settings). -# -# For details about syntax, see: -# https://help.github.com/en/articles/about-code-owners -# But here are some important notes: -# -# - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` -# which can be everywhere. -# - Multiple owners are supported. -# - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind, -# that handles might work better because they are more recognizable on GitHub, -# eyou can use them for mentioning unlike an email. -# - The latest matching rule, if multiple, takes precedence. - -# CI -/.github/ @paritytech/ci @paritytech/release-engineering -/.gitlab-ci.yml @paritytech/ci -/scripts/ci/ @paritytech/ci @paritytech/release-engineering - diff --git a/polkadot/.github/CODEOWNERS b/polkadot/.github/CODEOWNERS deleted file mode 100644 index a92dc0bb006..00000000000 --- a/polkadot/.github/CODEOWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# CI -/.github/ @paritytech/ci @chevdor -/scripts/ci/ @paritytech/ci @chevdor -/.gitlab-ci.yml @paritytech/ci -# lingua.dic is not managed by CI team -/scripts/ci/gitlab/lingua.dic diff --git a/substrate/docs/CODEOWNERS b/substrate/docs/CODEOWNERS deleted file mode 100644 index 63294d90e9d..00000000000 --- a/substrate/docs/CODEOWNERS +++ /dev/null @@ -1,74 +0,0 @@ -# Lists some code owners. -# -# A codeowner just oversees some part of the codebase. If an owned file is changed then the -# corresponding codeowner receives a review request. An approval of the codeowner is -# not required for merging a PR though. -# -# **This is pretty much an experiment at the moment**. Feel free to remove yourself at any time if -# you do not want to receive review requests any longer. -# -# For details about syntax, see: -# https://help.github.com/en/articles/about-code-owners -# But here are some important notes: -# -# - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` which -# can be everywhere. -# - Multiple owners are supported. -# - Either handle (e.g, @pepyakin) or email can be used. Keep in mind, that handles might work better because they -# are more recognizable on GitHub, you can use them for mentioning unlike an email. -# - The latest matching rule, if multiple, takes precedence. - -# CI -/.github/ @paritytech/ci -/.gitlab-ci.yml @paritytech/ci -/scripts/ci/ @paritytech/ci - -# WASM executor, low-level client <-> WASM interface and other WASM-related code -/client/allocator/ @koute -/client/executor/ @koute -/primitives/panic-handler/ @koute -/primitives/runtime-interface/ @koute -/primitives/wasm-interface/ @koute -/utils/wasm-builder/ @koute - -# Systems-related bits and bobs on the client side -/client/sysinfo/ @koute -/client/tracing/ @koute - -# Documentation audit -/primitives/runtime @paritytech/docs-audit -/primitives/arithmetic @paritytech/docs-audit -# /primitives/core (to be added later) -# /primitives/io (to be added later) - -# FRAME -/frame/ @paritytech/frame-coders @paritytech/docs-audit -/frame/nfts/ @jsidorenko @paritytech/docs-audit -/frame/state-trie-migration/ @paritytech/frame-coders @cheme -/frame/uniques/ @jsidorenko @paritytech/docs-audit - -# GRANDPA, BABE, consensus stuff -/client/consensus/babe/ @andresilva -/client/consensus/grandpa/ @andresilva -/client/consensus/pow/ @sorpaas -/client/consensus/slots/ @andresilva -/frame/babe/ @andresilva -/frame/grandpa/ @andresilva -/primitives/consensus/pow/ @sorpaas - -# BEEFY, MMR -/frame/beefy/ @acatangiu -/frame/beefy-mmr/ @acatangiu -/frame/merkle-mountain-range/ @acatangiu -/primitives/merkle-mountain-range/ @acatangiu - -# Contracts -/frame/contracts/ @athei @paritytech/docs-audit - -# NPoS and election -/frame/election-provider-multi-phase/ @paritytech/staking-core @paritytech/docs-audit -/frame/election-provider-support/ @paritytech/staking-core @paritytech/docs-audit -/frame/elections-phragmen/ @paritytech/staking-core @paritytech/docs-audit -/frame/nomination-pools/ @paritytech/staking-core @paritytech/docs-audit -/frame/staking/ @paritytech/staking-core @paritytech/docs-audit -/primitives/npos-elections/ @paritytech/staking-core @paritytech/docs-audit -- GitLab From 00259b1c943bc9a774e34c1cef78656439bb2359 Mon Sep 17 00:00:00 2001 From: Lulu Date: Mon, 11 Sep 2023 11:13:55 +0100 Subject: [PATCH 116/633] Set bridge crates to no-publish (#1488) --- bridges/bin/runtime-common/Cargo.toml | 1 + bridges/modules/grandpa/Cargo.toml | 1 + bridges/modules/messages/Cargo.toml | 1 + bridges/modules/parachains/Cargo.toml | 1 + bridges/modules/relayers/Cargo.toml | 1 + bridges/modules/xcm-bridge-hub-router/Cargo.toml | 1 + bridges/primitives/chain-asset-hub-kusama/Cargo.toml | 1 + bridges/primitives/chain-asset-hub-polkadot/Cargo.toml | 1 + bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml | 1 + bridges/primitives/chain-bridge-hub-kusama/Cargo.toml | 1 + bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml | 1 + bridges/primitives/chain-bridge-hub-rococo/Cargo.toml | 1 + bridges/primitives/chain-bridge-hub-wococo/Cargo.toml | 1 + bridges/primitives/chain-kusama/Cargo.toml | 1 + bridges/primitives/chain-polkadot/Cargo.toml | 1 + bridges/primitives/chain-rococo/Cargo.toml | 1 + bridges/primitives/chain-wococo/Cargo.toml | 1 + bridges/primitives/header-chain/Cargo.toml | 1 + bridges/primitives/messages/Cargo.toml | 1 + bridges/primitives/parachains/Cargo.toml | 1 + bridges/primitives/polkadot-core/Cargo.toml | 1 + bridges/primitives/relayers/Cargo.toml | 1 + bridges/primitives/runtime/Cargo.toml | 1 + bridges/primitives/xcm-bridge-hub-router/Cargo.toml | 1 + 24 files changed, 24 insertions(+) diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 5c3fefc69ce..fed82cc781a 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -5,6 +5,7 @@ authors.workspace = true edition.workspace = true repository.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 05d6a8e5c26..daef4f5061f 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 7b7ea061981..c6ae68d88c4 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 4eb09ed78d1..1c433394cb3 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 46fc3bb43b1..1dc7e9f8152 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index c61cab291e1..b180985cd64 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml index adb9a57bc13..772130b6e51 100644 --- a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml index 857ead15b0d..db73bc6e14a 100644 --- a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index 24cf7236d45..a4afec8fdc4 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index 387f5e8ade6..bb3798d11e2 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 40b386e22d2..4321138dc50 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index 05b8163e9fc..aa15656fc3a 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml index 17c134f4412..7ae16cfb754 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml index 2d63c3f374f..7670dc9acc3 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml index 539b10ef9c6..efcf516f5db 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml index 3c4d3917bc2..2906bf1e267 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/chain-wococo/Cargo.toml b/bridges/primitives/chain-wococo/Cargo.toml index 05901821b36..bb7ada6c04d 100644 --- a/bridges/primitives/chain-wococo/Cargo.toml +++ b/bridges/primitives/chain-wococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index e3e83235960..ecde073c35e 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index b30d6d2559f..411f10f44c2 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index ca69523dde3..9d6f865cc1d 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index aa7eb8024fb..f2e38030143 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 99cd79c6841..93625a05855 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 98269a1ffbb..ef8d2b8b40d 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 725a7d94564..fe68183f904 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } -- GitLab From 056c4221af5106dd0a3a7cb4b8c229ba5fed09ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 13:09:34 +0200 Subject: [PATCH 117/633] Bump the known_good_semver group with 2 updates (#1485) Bumps the known_good_semver group with 2 updates: [serde_json](https://github.com/serde-rs/json) and [syn](https://github.com/dtolnay/syn). Updates `serde_json` from 1.0.105 to 1.0.106 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.105...v1.0.106) Updates `syn` from 2.0.31 to 2.0.32 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.31...2.0.32) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: known_good_semver ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 104 +++++++++--------- .../relay-chain-rpc-interface/Cargo.toml | 2 +- .../parachain-system/proc-macro/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/kusama/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/polkadot/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- .../client/consensus/babe/rpc/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/grandpa/Cargo.toml | 2 +- substrate/client/keystore/Cargo.toml | 2 +- .../merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-servers/Cargo.toml | 2 +- substrate/client/rpc/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../primitives/genesis-builder/Cargo.toml | 2 +- substrate/primitives/rpc/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 55 files changed, 106 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ba7edafbda..e675e0f3a28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,7 +1138,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1160,7 +1160,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1177,7 +1177,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1352,7 +1352,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2515,7 +2515,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -3574,7 +3574,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4066,7 +4066,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4106,7 +4106,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4123,7 +4123,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4421,7 +4421,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4483,7 +4483,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.31", + "syn 2.0.32", "termcolor", "toml 0.7.6", "walkdir", @@ -4704,7 +4704,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4715,7 +4715,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -4878,7 +4878,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -5234,7 +5234,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.31", + "syn 2.0.32", "trybuild", ] @@ -5386,7 +5386,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -5397,7 +5397,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -5406,7 +5406,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -5629,7 +5629,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -7630,7 +7630,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -7644,7 +7644,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -7655,7 +7655,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -7666,7 +7666,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -9373,7 +9373,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -10444,7 +10444,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -11309,7 +11309,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -11350,7 +11350,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -13330,7 +13330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -13412,7 +13412,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -13458,7 +13458,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -13849,7 +13849,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -14611,7 +14611,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -15824,7 +15824,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -16178,7 +16178,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -16192,9 +16192,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "itoa", "ryu", @@ -16244,7 +16244,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -16684,7 +16684,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -17085,7 +17085,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -17129,7 +17129,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -17360,7 +17360,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -17600,7 +17600,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -18424,9 +18424,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -18673,7 +18673,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -18853,7 +18853,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -19034,7 +19034,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -19077,7 +19077,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -19644,7 +19644,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-shared", ] @@ -19678,7 +19678,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20814,7 +20814,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -20933,7 +20933,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 305ab82b064..fb409dc4a6c 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -32,7 +32,7 @@ jsonrpsee = { version = "0.16.2", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" -serde_json = "1.0.105" +serde_json = "1.0.106" serde = "1.0.188" schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index e5e7da81d2a..22eb6014b3c 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.31" +syn = "2.0.32" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index dc59b820752..c0be39461ad 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.20" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.105" +serde_json = "1.0.106" # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index ec6b817476a..e7645201224 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.31", features = ["full", "extra-traits"] } +syn = { version = "2.0.32", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 03814af19cd..a50f33b98e1 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -78,7 +78,7 @@ futures = "0.3.21" hex-literal = "0.4.1" gum = { package = "tracing-gum", path = "../gum" } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.96" +serde_json = "1.0.106" thiserror = "1.0.48" kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index d730a601d5a..cf0921ccdfb 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -58,7 +58,7 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" } [dev-dependencies] pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -serde_json = "1.0.96" +serde_json = "1.0.106" substrate-test-utils = { path = "../../../../substrate/test-utils" } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 83aa70cd308..ce7db99b9ea 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -58,7 +58,7 @@ pallet-babe = { path = "../../../substrate/frame/babe" } pallet-treasury = { path = "../../../substrate/frame/treasury" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.96" +serde_json = "1.0.106" libsecp256k1 = "0.7.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 6b0370633f0..9d26217a20d 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -116,7 +116,7 @@ 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.96" +serde_json = "1.0.106" 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 } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 550c0ef7534..f39ce3ffd0d 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -62,7 +62,7 @@ test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../pri sp-tracing = { path = "../../../substrate/primitives/tracing" } thousands = "0.2.0" assert_matches = "1" -serde_json = "1.0.96" +serde_json = "1.0.106" [features] default = [ "std" ] diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 0b9498347ca..e5c25c1843f 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -107,7 +107,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.96" +serde_json = "1.0.106" separator = "0.4.1" remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index a181250cfa3..cc5b242ccd5 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -99,7 +99,7 @@ keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyrin remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } sp-trie = { path = "../../../substrate/primitives/trie" } separator = "0.4.1" -serde_json = "1.0.96" +serde_json = "1.0.106" sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 1e411bc901c..2d3451705df 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -70,7 +70,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.96" +serde_json = "1.0.106" [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index de561c8ac68..c8e182f3469 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -108,7 +108,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.96" +serde_json = "1.0.106" 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 } diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 6545fb68764..99637772131 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.31" +syn = "2.0.32" Inflector = "0.11.4" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index a02d7393740..2540e213f10 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -22,7 +22,7 @@ sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" kvdb-rocksdb = "0.19.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 28701db482d..2e94098a63c 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -106,7 +106,7 @@ sc-cli = { path = "../../../client/cli", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} node-inspect = { path = "../inspect", optional = true} try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} -serde_json = "1.0.85" +serde_json = "1.0.106" [dev-dependencies] sc-keystore = { path = "../../../client/keystore" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 6acd57ef516..8208383043d 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] memmap2 = "0.5.0" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } sc-executor = { path = "../executor" } diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index b5ecc6107b9..e92e66e9046 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.31" +syn = "2.0.32" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 06967a89093..5456ad27f23 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -26,7 +26,7 @@ rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0.48" tiny-bip39 = "1.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index bfae5ad3fd0..52440970e77 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -30,7 +30,7 @@ sp-keystore = { path = "../../../../primitives/keystore" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" tokio = "1.22.0" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index f9c3b4a99df..6ccf42cfa58 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -23,7 +23,7 @@ sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" sc-rpc = { path = "../../../rpc", features = ["test-helpers"]} substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index dfd9916850e..13b14b7e287 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -25,7 +25,7 @@ log = "0.4.17" parity-scale-codec = { version = "3.6.1", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0" fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index 9ead4265a84..e89a6148e16 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" parking_lot = "0.12.1" -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0" sp-application-crypto = { path = "../../primitives/application-crypto" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 6aa32333af9..65a9e5e8aff 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -23,4 +23,4 @@ sp-runtime = { path = "../../../primitives/runtime" } anyhow = "1" [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 72e38ce498d..df0b557e6d8 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -34,7 +34,7 @@ partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" smallvec = "1.11.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index fb0d0a8a1f8..08c480214f6 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } sc-transaction-pool-api = { path = "../transaction-pool/api" } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 94a0d815f2e..61280ad224e 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" -serde_json = "1.0.85" +serde_json = "1.0.106" tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } tower-http = { version = "0.4.0", features = ["cors"] } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index c7e9977cb25..4998a89b60a 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" parking_lot = "0.12.1" -serde_json = "1.0.85" +serde_json = "1.0.106" sc-block-builder = { path = "../block-builder" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 87b341fe312..5ca3c726971 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -35,7 +35,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-trie = { path = "../../primitives/trie" } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 88d268cc93d..60089074160 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0.48" sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 5834d8dec07..b2fd2bc7e43 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -21,7 +21,7 @@ rand = "0.8.5" rand_pcg = "0.3.1" regex = "1" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 2be5ad5c143..3f2a3002873 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0.48" wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 8c444ffb606..52ecd1a89e7 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.31", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.32", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index ecc5bc627b7..d840c097370 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.31", features = ["full"] } +syn = { version = "2.0.32", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 7693da0372d..d2c42fd68f3 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.31", features = ["full", "visit"] } +syn = { version = "2.0.32", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index e1b97d278da..ab25fdd35c8 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.31", features = ["full", "visit"] } +syn = { version = "2.0.32", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 864e3bd9ad3..f81bdd3b20a 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -42,7 +42,7 @@ sp-core-hashing-proc-macro = { path = "../../primitives/core/hashing/proc-macro" k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features=false} -serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } docify = "0.2.1" static_assertions = "1.1.0" diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 9ca86b9fccb..07a7ed079a9 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.4" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.31", features = ["full"] } +syn = { version = "2.0.32", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 46c26425651..48c8d9eb509 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.31", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.32", 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 da01e6f4f6a..e5a05627a6e 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.31", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.32", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 1db63bd134a..72ba8234839 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" pallet-balances = { path = "../balances" } [features] diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index edf05a05331..a262e15956a 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" serde = { version = "1.0.188", optional = true } [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" sp-storage = { path = "../../../primitives/storage", default-features = false} diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 6819d139f45..131f7dcf5b9 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.31", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.32", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index ef17473a6f3..de9168eaf78 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.31", features = ["full", "parsing"] } +syn = { version = "2.0.32", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 292c07e092f..4eb24634e65 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.31" +syn = "2.0.32" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index fb92f0223d0..4016a34e9dc 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { path = "../api", default-features = false} sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} -serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } [features] default = [ "std" ] diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index 21447dafb05..f65259df135 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ serde = { version = "1.0.188", features = ["derive"] } sp-core = { path = "../core" } [dev-dependencies] -serde_json = "1.0.85" +serde_json = "1.0.106" diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index e01343d6dc0..4d090937f2d 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.31", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.32", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 7050c27bc84..34e60febb6f 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-weights = { path = "../weights", default-features = false} [dev-dependencies] rand = "0.8.5" -serde_json = "1.0.85" +serde_json = "1.0.106" zstd = { version = "0.12.4", default-features = false } sp-api = { path = "../api" } sp-state-machine = { path = "../state-machine" } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 25b5e7906f6..1824c97b189 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.31", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.32", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 91c30f5a8ec..04681789560 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ "test-helpers", diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 4f587d55e79..4f6c47307ea 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -49,7 +49,7 @@ sp-externalities = { path = "../../primitives/externalities", default-features = array-bytes = { version = "6.1", optional = true } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } -serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } [dev-dependencies] futures = "0.3.21" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 85be451fa60..69c8fdf932e 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ log = "0.4.17" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" thiserror = "1.0.48" thousands = "0.2.0" frame-benchmarking = { path = "../../../frame/benchmarking" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 7d1c204422a..7bde09b8cf3 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -40,7 +40,7 @@ hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" serde = "1.0.188" -serde_json = "1.0.85" +serde_json = "1.0.106" zstd = { version = "0.12.4", default-features = false } [dev-dependencies] -- GitLab From a414ea7515c9cdc81f1d12410e646afc148250e8 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 11 Sep 2023 13:44:42 +0200 Subject: [PATCH 118/633] [ci] Move additional tests back to test-linux-stable (#1466) * [ci] Move additional tests back to test-linux-stable * run slow tests with all tests * check if test upgrade_version_checks_should_work works * rm comment --- .gitlab-ci.yml | 6 +++- .gitlab/pipeline/test.yml | 62 +++++++++++++++------------------------ 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 99381fae9ec..71518428b94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: "paritytech/ci-unified:bullseye-1.70.0-2023-05-23-v20230706" + CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" @@ -213,6 +213,10 @@ include: - project: parity/infrastructure/ci_cd/shared ref: v0.2 file: /common/timestamp.yml + # ci image + - project: parity/infrastructure/ci_cd/shared + ref: main + file: /common/ci-unified.yml # 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. diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index b29574ad14d..3a4f5e71247 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -23,13 +23,8 @@ test-linux-stable: - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" # add experimental to features after https://github.com/paritytech/substrate/pull/14502 is merged # "upgrade_version_checks_should_work" is currently failing - # "receive_rate_limit_is_enforced"and "benchmark_block_works" can be found in test-linux-stable-additional-tests - # they fail if run with other tests - # "rx::tests::sent_views_include_finalized_number_update", "follow_chain_works", "create_snapshot_works" and "block_execution_works" - # can be found in test-linux-stable-slow - | time cargo nextest run \ - -E 'all() & !test(upgrade_version_checks_should_work) & !test(receive_rate_limit_is_enforced) & !test(benchmark_block_works) & !test(rx::tests::sent_views_include_finalized_number_update) & !test(follow_chain_works) & !test(create_snapshot_works) & !test(block_execution_works)' \ --workspace \ --locked \ --release \ @@ -59,6 +54,22 @@ test-linux-oldkernel-stable: tags: - oldkernel-vm +# https://github.com/paritytech/ci_cd/issues/864 +test-linux-stable-runtime-benchmarks: + stage: test + extends: + - .docker-env + - .common-refs + - .run-immediately + - .pipeline-stopper-artifacts + variables: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + script: + - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + # can be used to run all tests # test-linux-stable-all: # stage: test @@ -85,7 +96,7 @@ test-linux-oldkernel-stable: # --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} # # todo: add flacky-test collector -# for some reasons these tests fail if run with all tests +# TODO: remove me test-linux-stable-additional-tests: stage: test extends: @@ -99,31 +110,11 @@ test-linux-stable-additional-tests: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - | - time cargo nextest run \ - -E 'test(receive_rate_limit_is_enforced) + test(benchmark_block_works)' \ - --workspace \ - --locked \ - --release \ - --features runtime-benchmarks,try-runtime + # tests were moved to test-linux-stable + # the jobs should be removed + - exit 0 -# https://github.com/paritytech/ci_cd/issues/864 -test-linux-stable-runtime-benchmarks: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - variables: - RUST_TOOLCHAIN: stable - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet - -# these ones can be really slow so it's better to run them separately +# TODO: remove me test-linux-stable-slow: stage: test # remove after cache is setup @@ -139,14 +130,9 @@ test-linux-stable-slow: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - | - time cargo nextest run \ - -E 'test(rx::tests::sent_views_include_finalized_number_update) + test(follow_chain_works) + test(create_snapshot_works) + test(block_execution_works)' \ - --workspace \ - --locked \ - --release \ - --features runtime-benchmarks,try-runtime - allow_failure: true + # tests were moved to test-linux-stable + # the jobs should be removed + - exit 0 # takes about 1,5h without cache # can be used to check that nextest works correctly -- GitLab From 6df8909d94482bf4aa586086a28f5befc34676e7 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Mon, 11 Sep 2023 16:39:51 +0100 Subject: [PATCH 119/633] [improve docs]: Sudo Pallet (#1209) * refactor docs * add docify * nit * add #![deny(missing_docs)] * Apply suggestions from code review Co-authored-by: Juan Co-authored-by: Francisco Aguirre --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Juan Co-authored-by: Francisco Aguirre --- Cargo.lock | 1 + substrate/frame/sudo/Cargo.toml | 2 + substrate/frame/sudo/src/lib.rs | 119 ++++++++++++++++++---------- substrate/frame/sudo/src/tests.rs | 3 + substrate/frame/sudo/src/weights.rs | 2 +- 5 files changed, 82 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e675e0f3a28..5d21b24804a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10510,6 +10510,7 @@ dependencies = [ name = "pallet-sudo" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index a75a0c504f9..9b148c0b471 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -22,6 +22,8 @@ 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.1" + [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index f735469558c..0c869bec7f0 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/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,41 +15,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Sudo Pallet -//! -//! - [`Config`] -//! - [`Call`] -//! -//! ## Overview -//! -//! The Sudo pallet allows for a single account (called the "sudo key") -//! to execute dispatchable functions that require a `Root` call -//! or designate a new account to replace them as the sudo key. -//! Only one account can be the sudo key at a time. -//! -//! ## Interface +//! > Made with *Substrate*, for *Polkadot*. //! -//! ### Dispatchable Functions +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/sudo) +//! [![polkadot]](https://polkadot.network) //! -//! Only the sudo key can call the dispatchable functions from the Sudo pallet. +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white //! -//! * `sudo` - Make a `Root` call to a dispatchable function. -//! * `set_key` - Assign a new account to be the sudo key. +//! # Sudo Pallet //! -//! ## Usage +//! A pallet to provide a way to execute privileged runtime calls using a specified sudo ("superuser +//! do") account. //! -//! ### Executing Privileged Functions +//! ## Pallet API //! -//! The Sudo pallet itself is not intended to be used within other pallets. -//! Instead, you can build "privileged functions" (i.e. functions that require `Root` origin) in -//! other pallets. You can execute these privileged functions by calling `sudo` with the sudo key -//! account. Privileged functions cannot be directly executed via an extrinsic. +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. //! -//! Learn more about privileged functions and `Root` origin in the [`Origin`] type documentation. +//! ## Overview //! -//! ### Simple Code Snippet +//! In Substrate blockchains, pallets may contain dispatchable calls that can only be called at +//! the system level of the chain (i.e. dispatchables that require a `Root` origin). +//! Setting a privileged account, called the _sudo key_, allows you to make such calls as an +//! extrinisic. //! -//! This is an example of a pallet that exposes a privileged function: +//! Here's an example of a privileged function in another pallet: //! //! ``` //! #[frame_support::pallet] @@ -76,27 +67,58 @@ //! } //! } //! } -//! # fn main() {} //! ``` //! -//! ### Signed Extension +//! With the Sudo pallet configured in your chain's runtime you can execute this privileged +//! function by constructing a call using the [`sudo`](Pallet::sudo) dispatchable. +//! +//! To use this pallet in your runtime, a sudo key must be specified in the [`GenesisConfig`] of +//! the pallet. You can change this key at anytime once your chain is live using the +//! [`set_key`](Pallet::set_key) dispatchable, however only one sudo key can be set at a +//! time. The pallet also allows you to make a call using +//! [`sudo_unchecked_weight`](Pallet::sudo_unchecked_weight), which allows the sudo account to +//! execute a call with a custom weight. +//! +//!

+//! Note: this pallet is not meant to be used inside other pallets. It is only
+//! meant to be used by constructing runtime calls from outside the runtime.
+//! 
+//! +//! This pallet also defines a [`SignedExtension`](sp_runtime::traits::SignedExtension) called +//! [`CheckOnlySudoAccount`] to ensure that only signed transactions by the sudo account are +//! accepted by the transaction pool. The intended use of this signed extension is to prevent other +//! accounts from spamming the transaction pool for the initial phase of a chain, during which +//! developers may only want a sudo account to be able to make transactions. +//! +//! Learn more about the `Root` origin in the [`RawOrigin`](frame_system::RawOrigin) type +//! documentation. //! -//! The Sudo pallet defines the following extension: +//! ### Examples //! -//! - [`CheckOnlySudoAccount`]: Ensures that the signed transactions are only valid if they are -//! signed by sudo account. +//! 1. You can make a privileged runtime call using `sudo` with an account that matches the sudo +//! key. +#![doc = docify::embed!("src/tests.rs", sudo_basics)] //! -//! ## Genesis Config +//! 2. Only an existing sudo key can set a new one. +#![doc = docify::embed!("src/tests.rs", set_key_basics)] //! -//! The Sudo pallet depends on the [`GenesisConfig`]. -//! You need to set an initial superuser account as the sudo `key`. +//! 3. You can also make non-privileged calls using `sudo_as`. +#![doc = docify::embed!("src/tests.rs", sudo_as_emits_events_correctly)] //! -//! ## Related Pallets +//! ## Low Level / Implementation Details //! -//! * [Democracy](../pallet_democracy/index.html) +//! This pallet checks that the caller of its dispatchables is a signed account and ensures that the +//! caller matches the sudo key in storage. +//! A caller of this pallet's dispatchables does not pay any fees to dispatch a call. If the account +//! making one of these calls is not the sudo key, the pallet returns a [`Error::RequireSudo`] +//! error. //! -//! [`Origin`]: https://docs.substrate.io/main-docs/build/origins/ +//! Once an origin is verified, sudo calls use `dispatch_bypass_filter` from the +//! [`UnfilteredDispatchable`](frame_support::traits::UnfilteredDispatchable) trait to allow call +//! execution without enforcing any further origin checks. +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] use sp_runtime::{traits::StaticLookup, DispatchResult}; @@ -261,12 +283,21 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A sudo just took place. \[result\] - Sudid { sudo_result: DispatchResult }, - /// The \[sudoer\] just switched identity; the old key is supplied if one existed. - KeyChanged { old_sudoer: Option }, - /// A sudo just took place. \[result\] - SudoAsDone { sudo_result: DispatchResult }, + /// A sudo call just took place. + Sudid { + /// The result of the call made by the sudo user. + sudo_result: DispatchResult, + }, + /// The sudo key has been updated. + KeyChanged { + /// The old sudo key if one was previously set. + old_sudoer: Option, + }, + /// A [sudo_as](Pallet::sudo_as) call just took place. + SudoAsDone { + /// The result of the call made by the sudo user. + sudo_result: DispatchResult, + }, } #[pallet::error] diff --git a/substrate/frame/sudo/src/tests.rs b/substrate/frame/sudo/src/tests.rs index c854fed8f07..6963ba2e6a0 100644 --- a/substrate/frame/sudo/src/tests.rs +++ b/substrate/frame/sudo/src/tests.rs @@ -34,6 +34,7 @@ fn test_setup_works() { }); } +#[docify::export] #[test] fn sudo_basics() { // Configure a default test environment and set the root `key` to 1. @@ -134,6 +135,7 @@ fn sudo_unchecked_weight_emits_events_correctly() { }) } +#[docify::export] #[test] fn set_key_basics() { new_test_ext(1).execute_with(|| { @@ -195,6 +197,7 @@ fn sudo_as_basics() { }); } +#[docify::export] #[test] fn sudo_as_emits_events_correctly() { new_test_ext(1).execute_with(|| { diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index 6a0197d1469..0cdd0c8a81f 100644 --- a/substrate/frame/sudo/src/weights.rs +++ b/substrate/frame/sudo/src/weights.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_sudo +//! Autogenerated weights for pallet_sudo. //! //! 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: `[]` -- GitLab From 4b8bd9060e66932f5e038e16478c089191b19723 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 11 Sep 2023 17:54:27 +0200 Subject: [PATCH 120/633] Delete staking miner (#1480) * Delete staking miner New repo should be used instead https://github.com/paritytech/staking-miner-v2 Signed-off-by: Oliver Tale-Yazdi * Remove staking-miner CI jobs Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- .../workflows/release-50_publish-docker.yml | 13 - .gitlab/pipeline/build.yml | 22 +- .gitlab/pipeline/publish.yml | 18 - Cargo.lock | 120 +--- Cargo.toml | 1 - .../staking-miner_builder.Dockerfile | 46 -- .../staking-miner_injected.Dockerfile | 43 -- docker/scripts/staking-miner/README.md | 37 - .../scripts/staking-miner/build-injected.sh | 13 - docker/scripts/staking-miner/build.sh | 13 - .../staking-miner_Dockerfile.README.md | 3 - .../staking-miner_builder.Dockerfile | 43 -- docker/scripts/staking-miner/test-build.sh | 18 - polkadot/utils/staking-miner/.gitignore | 2 - polkadot/utils/staking-miner/Cargo.toml | 54 -- polkadot/utils/staking-miner/README.md | 81 --- polkadot/utils/staking-miner/src/dry_run.rs | 166 ----- .../staking-miner/src/emergency_solution.rs | 65 -- polkadot/utils/staking-miner/src/main.rs | 665 ------------------ polkadot/utils/staking-miner/src/monitor.rs | 478 ------------- polkadot/utils/staking-miner/src/opts.rs | 366 ---------- polkadot/utils/staking-miner/src/prelude.rs | 55 -- polkadot/utils/staking-miner/src/rpc.rs | 182 ----- .../staking-miner/src/runtime_versions.rs | 90 --- polkadot/utils/staking-miner/src/signer.rs | 84 --- polkadot/utils/staking-miner/tests/cli.rs | 49 -- .../election-provider-multi-phase/src/lib.rs | 3 +- 27 files changed, 8 insertions(+), 2722 deletions(-) delete mode 100644 docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile delete mode 100644 docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile delete mode 100644 docker/scripts/staking-miner/README.md delete mode 100755 docker/scripts/staking-miner/build-injected.sh delete mode 100755 docker/scripts/staking-miner/build.sh delete mode 100644 docker/scripts/staking-miner/staking-miner_Dockerfile.README.md delete mode 100644 docker/scripts/staking-miner/staking-miner_builder.Dockerfile delete mode 100755 docker/scripts/staking-miner/test-build.sh delete mode 100644 polkadot/utils/staking-miner/.gitignore delete mode 100644 polkadot/utils/staking-miner/Cargo.toml delete mode 100644 polkadot/utils/staking-miner/README.md delete mode 100644 polkadot/utils/staking-miner/src/dry_run.rs delete mode 100644 polkadot/utils/staking-miner/src/emergency_solution.rs delete mode 100644 polkadot/utils/staking-miner/src/main.rs delete mode 100644 polkadot/utils/staking-miner/src/monitor.rs delete mode 100644 polkadot/utils/staking-miner/src/opts.rs delete mode 100644 polkadot/utils/staking-miner/src/prelude.rs delete mode 100644 polkadot/utils/staking-miner/src/rpc.rs delete mode 100644 polkadot/utils/staking-miner/src/runtime_versions.rs delete mode 100644 polkadot/utils/staking-miner/src/signer.rs delete mode 100644 polkadot/utils/staking-miner/tests/cli.rs diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 512b91aa6e5..7fdfc230354 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -47,7 +47,6 @@ on: type: choice options: - polkadot - - staking-miner - polkadot-parachain permissions: @@ -158,18 +157,6 @@ jobs: echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT - - name: Build Injected Container image for polkadot/staking-miner - if: ${{ env.BINARY == 'polkadot' || env.BINARY == 'staking-miner' }} - env: - ARTIFACTS_FOLDER: ./release-artifacts - IMAGE_NAME: ${{ env.BINARY }} - OWNER: ${{ env.DOCKER_OWNER }} - TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} - run: | - ls -al - echo "Building container for $BINARY" - ./docker/scripts/build-injected.sh - - name: Build Injected Container image for polkadot-parachain if: ${{ env.BINARY == 'polkadot-parachain' }} env: diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index c4dfc0dd093..328b37af1d4 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -77,26 +77,6 @@ build-malus: - echo "polkadot-test-malus = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - cp -r ./docker/* ./artifacts -build-staking-miner: - stage: build - extends: - - .docker-env - - .common-refs - # - .collect-artifacts - # DAG - needs: - - job: build-malus - artifacts: false - script: - - time cargo build -q --locked --release --package staging-staking-miner - # # pack artifacts - # - mkdir -p ./artifacts - # - mv ./target/release/staking-miner ./artifacts/. - # - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - # - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - # - echo "staking-miner = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - # - cp -r ./scripts/* ./artifacts - build-rustdoc: stage: build extends: @@ -358,7 +338,7 @@ build-subkey-linux: extends: .build-subkey # DAG needs: - - job: build-staking-miner + - job: build-malus artifacts: false # tbd # build-subkey-macos: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 1a513e5970d..9e24b8606a4 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -328,24 +328,6 @@ build-push-image-substrate-pr: # # this artifact is used in zombienet-tests job # dotenv: ./artifacts/malus.env -# publish-staking-miner-image: -# stage: publish -# extends: -# - .kubernetes-env -# - .build-push-image -# - .publish-refs -# variables: -# CI_IMAGE: ${BUILDAH_IMAGE} -# # scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile -# DOCKERFILE: ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile -# IMAGE_NAME: docker.io/paritytech/staking-miner -# GIT_STRATEGY: none -# DOCKER_USER: ${Docker_Hub_User_Parity} -# DOCKER_PASS: ${Docker_Hub_Pass_Parity} -# needs: -# - job: build-staking-miner -# artifacts: true - # substrate # publish-substrate-image-pr: diff --git a/Cargo.lock b/Cargo.lock index 5d21b24804a..3d4bc17563b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,7 +494,7 @@ dependencies = [ "ark-ff", "ark-std", "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber", ] [[package]] @@ -4838,12 +4838,6 @@ dependencies = [ "futures", ] -[[package]] -name = "exitcode" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" - [[package]] name = "expander" version = "0.0.4" @@ -7690,15 +7684,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matches" version = "0.1.10" @@ -8542,16 +8527,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num" version = "0.4.1" @@ -8771,12 +8746,6 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "owo-colors" version = "3.5.0" @@ -15117,7 +15086,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber", "wat", ] @@ -15815,7 +15784,7 @@ dependencies = [ "thiserror", "tracing", "tracing-log", - "tracing-subscriber 0.2.25", + "tracing-subscriber", ] [[package]] @@ -16394,18 +16363,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signal-hook-tokio" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e" -dependencies = [ - "futures-core", - "libc", - "signal-hook", - "tokio", -] - [[package]] name = "signature" version = "1.6.4" @@ -17525,7 +17482,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber", ] [[package]] @@ -17807,47 +17764,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "staging-staking-miner" -version = "1.0.0" -dependencies = [ - "assert_cmd", - "clap 4.4.2", - "exitcode", - "frame-election-provider-support", - "frame-remote-externalities", - "frame-support", - "frame-system", - "futures-util", - "jsonrpsee", - "log", - "pallet-balances", - "pallet-election-provider-multi-phase", - "pallet-staking", - "pallet-transaction-payment", - "parity-scale-codec", - "paste", - "polkadot-core-primitives", - "polkadot-runtime", - "polkadot-runtime-common", - "sc-transaction-pool-api", - "serde", - "serde_json", - "signal-hook", - "signal-hook-tokio", - "sp-core", - "sp-npos-elections", - "sp-runtime", - "sp-state-machine", - "sp-version", - "staging-kusama-runtime", - "sub-tokens", - "thiserror", - "tokio", - "tracing-subscriber 0.3.17", - "westend-runtime", -] - [[package]] name = "staging-xcm" version = "1.0.0" @@ -18022,14 +17938,6 @@ dependencies = [ "webrtc-util", ] -[[package]] -name = "sub-tokens" -version = "0.1.0" -source = "git+https://github.com/paritytech/substrate-debug-kit?branch=master#e12503ab781e913735dc389865a3b8b4a6c6399d" -dependencies = [ - "separator", -] - [[package]] name = "subkey" version = "3.0.0" @@ -19111,7 +19019,7 @@ dependencies = [ "ansi_term", "chrono", "lazy_static", - "matchers 0.0.1", + "matchers", "parking_lot 0.11.2", "regex", "serde", @@ -19125,24 +19033,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "matchers 0.1.0", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - [[package]] name = "trie-bench" version = "0.37.0" diff --git a/Cargo.toml b/Cargo.toml index 5c43990d472..89fb007058a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -172,7 +172,6 @@ members = [ "polkadot/statement-table", "polkadot/utils/generate-bags", "polkadot/utils/remote-ext-tests/bags-list", - "polkadot/utils/staking-miner", "polkadot/xcm", "polkadot/xcm/pallet-xcm", "polkadot/xcm/pallet-xcm-benchmarks", diff --git a/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile b/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile deleted file mode 100644 index a1932095fd4..00000000000 --- a/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -FROM paritytech/ci-linux:production as builder - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME="staking-miner" -ARG PROFILE=release - -LABEL description="This is the build stage. Here we create the binary." - -WORKDIR /app -COPY . /app -RUN cargo build --locked --$PROFILE --package staking-miner - -# ===== SECOND STAGE ====== - -FROM docker.io/library/ubuntu:20.04 -LABEL description="This is the 2nd stage: a very small image where we copy the binary." -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="${IMAGE_NAME} for substrate based chains" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_builder.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -ARG PROFILE=release -COPY --from=builder /app/target/$PROFILE/staking-miner /usr/local/bin - -RUN useradd -u 1000 -U -s /bin/sh miner && \ - rm -rf /usr/bin /usr/sbin - -# show backtraces -ENV RUST_BACKTRACE 1 - -USER miner - -ENV SEED="" -ENV URI="wss://rpc.polkadot.io" -ENV RUST_LOG="info" - -# check if the binary works in this container -RUN /usr/local/bin/staking-miner --version - -ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile b/docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile deleted file mode 100644 index 4901ab4a373..00000000000 --- a/docker/dockerfiles/staking-miner/staking-miner_injected.Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME="staking-miner" - -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="${IMAGE_NAME} for substrate based chains" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_injected.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ - useradd -u 1000 -U -s /bin/sh miner - -# add binary to docker image -COPY ./staking-miner /usr/local/bin - -USER miner - -ENV SEED="" -ENV URI="wss://rpc.polkadot.io" -ENV RUST_LOG="info" - -# check if the binary works in this container -RUN /usr/local/bin/staking-miner --version - -ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/docker/scripts/staking-miner/README.md b/docker/scripts/staking-miner/README.md deleted file mode 100644 index 3610e113031..00000000000 --- a/docker/scripts/staking-miner/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# staking-miner container image - -## Build using the Builder - -``` -./build.sh -``` - -## Build the injected Image - -You first need a valid Linux binary to inject. Let's assume this binary is located in `BIN_FOLDER`. - -``` -./build-injected.sh "$BIN_FOLDER" -``` - -## Test - -Here is how to test the image. We can generate a valid seed but the staking-miner will quickly notice that our -account is not funded and "does not exist". - -You may pass any ENV supported by the binary and must provide at least a few such as `SEED` and `URI`: -``` -ENV SEED="" -ENV URI="wss://rpc.polkadot.io:443" -ENV RUST_LOG="info" -``` - -``` -export SEED=$(subkey generate -n polkadot --output-type json | jq -r .secretSeed) -podman run --rm -it \ - -e URI="wss://rpc.polkadot.io:443" \ - -e RUST_LOG="info" \ - -e SEED \ - localhost/parity/staking-miner \ - dry-run seq-phragmen -``` diff --git a/docker/scripts/staking-miner/build-injected.sh b/docker/scripts/staking-miner/build-injected.sh deleted file mode 100755 index efe323b5fed..00000000000 --- a/docker/scripts/staking-miner/build-injected.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_staking-miner_binary -# This script replace the former dedicated staking-miner "injected" Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` - -export BINARY=staking-miner -export ARTIFACTS_FOLDER=$1 - -$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docker/scripts/staking-miner/build.sh b/docker/scripts/staking-miner/build.sh deleted file mode 100755 index c2b6ab77e53..00000000000 --- a/docker/scripts/staking-miner/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Sample call: -# $0 /path/to/folder_with_staking-miner_binary -# This script replace the former dedicated staking-miner "injected" Dockerfile -# and shows how to use the generic binary_injected.dockerfile - -PROJECT_ROOT=`git rev-parse --show-toplevel` -ENGINE=podman - -echo "Building the staking-miner using the Builder image" -echo "PROJECT_ROOT=$PROJECT_ROOT" -$ENGINE build -t staking-miner -f "${PROJECT_ROOT}/docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile" "$PROJECT_ROOT" diff --git a/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md b/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md deleted file mode 100644 index ce424c42f47..00000000000 --- a/docker/scripts/staking-miner/staking-miner_Dockerfile.README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Staking-miner Docker image - -## [GitHub](https://github.com/paritytech/polkadot/tree/master/utils/staking-miner) diff --git a/docker/scripts/staking-miner/staking-miner_builder.Dockerfile b/docker/scripts/staking-miner/staking-miner_builder.Dockerfile deleted file mode 100644 index 0ae77f36c79..00000000000 --- a/docker/scripts/staking-miner/staking-miner_builder.Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -FROM paritytech/ci-linux:production as builder - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME="staking-miner" -ARG PROFILE=production - -LABEL description="This is the build stage. Here we create the binary." - -WORKDIR /app -COPY . /app -RUN cargo build --locked --profile $PROFILE --package staking-miner - -# ===== SECOND STAGE ====== - -FROM docker.io/parity/base-bin:latest -LABEL description="This is the 2nd stage: a very small image where we copy the binary." -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="${IMAGE_NAME} for substrate based chains" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_builder.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -ARG PROFILE=release -COPY --from=builder /app/target/$PROFILE/staking-miner /usr/local/bin - -# show backtraces -ENV RUST_BACKTRACE 1 - -USER parity - -ENV SEED="" -ENV URI="wss://rpc.polkadot.io" -ENV RUST_LOG="info" - -# check if the binary works in this container -RUN /usr/local/bin/staking-miner --version - -ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/docker/scripts/staking-miner/test-build.sh b/docker/scripts/staking-miner/test-build.sh deleted file mode 100755 index 0ce74e2df29..00000000000 --- a/docker/scripts/staking-miner/test-build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -TMP=$(mktemp -d) -ENGINE=${ENGINE:-podman} - -# You need to build an injected image first - -# Fetch some binaries -$ENGINE run --user root --rm -i \ - -v "$TMP:/export" \ - --entrypoint /bin/bash \ - parity/staking-miner -c \ - 'cp "$(which staking-miner)" /export' - -echo "Checking binaries we got:" -tree $TMP - -./build-injected.sh $TMP diff --git a/polkadot/utils/staking-miner/.gitignore b/polkadot/utils/staking-miner/.gitignore deleted file mode 100644 index db7cff84833..00000000000 --- a/polkadot/utils/staking-miner/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.key -*.bin diff --git a/polkadot/utils/staking-miner/Cargo.toml b/polkadot/utils/staking-miner/Cargo.toml deleted file mode 100644 index 4b012e3ac73..00000000000 --- a/polkadot/utils/staking-miner/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[[bin]] -name = "staging-staking-miner" -path = "src/main.rs" - -[package] -name = "staging-staking-miner" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.workspace = true -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -clap = { version = "4.4.2", features = ["derive", "env"] } -tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } -jsonrpsee = { version = "0.16.2", features = ["ws-client", "macros"] } -log = "0.4.17" -paste = "1.0.7" -serde = "1.0.188" -serde_json = "1.0" -thiserror = "1.0.48" -tokio = { version = "1.24.2", features = ["macros", "rt-multi-thread", "sync"] } -remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } -signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } -sp-core = { path = "../../../substrate/primitives/core" } -sp-version = { path = "../../../substrate/primitives/version" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections" } -sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } - -frame-system = { path = "../../../substrate/frame/system" } -frame-support = { path = "../../../substrate/frame/support" } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support" } -pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase" } -pallet-staking = { path = "../../../substrate/frame/staking" } -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } - -core-primitives = { package = "polkadot-core-primitives", path = "../../core-primitives" } - -runtime-common = { package = "polkadot-runtime-common", path = "../../runtime/common" } -polkadot-runtime = { path = "../../runtime/polkadot" } -kusama-runtime = { package = "staging-kusama-runtime", path = "../../runtime/kusama" } -westend-runtime = { path = "../../runtime/westend" } -exitcode = "1.1" - -sub-tokens = { git = "https://github.com/paritytech/substrate-debug-kit", branch = "master" } -signal-hook = "0.3" -futures-util = "0.3" - -[dev-dependencies] -assert_cmd = "2.0.4" diff --git a/polkadot/utils/staking-miner/README.md b/polkadot/utils/staking-miner/README.md deleted file mode 100644 index 90a00eeac08..00000000000 --- a/polkadot/utils/staking-miner/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Staking Miner - -Substrate chains validators compute a basic solution for the NPoS election. The optimization of the solution is -computing-intensive and can be delegated to the `staking-miner`. The `staking-miner` does not act as validator and -focuses solely on the optimization of the solution. - -The staking miner connects to a specified chain and keeps listening to new Signed phase of the -[pallet-election-provider-multi-phase](https://crates.parity.io/pallet_election_provider_multi_phase/index.html) in -order to submit solutions to the NPoS election. When the correct time comes, it computes its solution and submit it to -the chain. The default miner algorithm is -[sequential-phragmen](https://crates.parity.io/sp_npos_elections/phragmen/fn.seq_phragmen_core.html)] with a -configurable number of balancing iterations that improve the score. - -Running the staking-miner requires passing the seed of a funded account in order to pay the fees for the transactions -that will be sent. The same account's balance is used to reserve deposits as well. The best solution in each round is -rewarded. All correct solutions will get their bond back. Any invalid solution will lose their bond. - -You can check the help with: -``` -staking-miner --help -``` - -## Building - -You can build from the root of the Polkadot repository using: -``` -cargo build --profile production --locked --package staking-miner --bin staking-miner -``` - -## Docker - -There are 2 options to build a staking-miner Docker image: -- injected binary: the binary is first built on a Linux host and then injected into a Docker base image. This method - only works if you have a Linux host or access to a pre-built binary from a Linux host. -- multi-stage: the binary is entirely built within the multi-stage Docker image. There is no requirement on the host in - terms of OS and the host does not even need to have any Rust toolchain installed. - -### Building the injected image - -First build the binary as documented [above](#building). You may then inject the binary into a Docker base image: -`parity/base-bin` (running the command from the root of the Polkadot repository): -``` -TODO: UPDATE THAT -docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile target/release -``` - -### Building the multi-stage image - -Unlike the injected image that requires a Linux pre-built binary, this option does not requires a Linux host, nor Rust -to be installed. The trade-off however is that it takes a little longer to build and this option is less ideal for CI -tasks. You may build the multi-stage image the root of the Polkadot repository with: -``` -TODO: UPDATE THAT -docker build -t staking-miner -f docker/dockerfiles/staking-miner/staking-miner_builder.Dockerfile . -``` - -### Running - -A Docker container, especially one holding one of your `SEED` should be kept as secure as possible. While it won't -prevent a malicious actor to read your `SEED` if they gain access to your container, it is nonetheless recommended -running this container in `read-only` mode: - -``` -# The following line starts with an extra space on purpose: - SEED=0x1234... - -docker run --rm -i \ - --name staking-miner \ - --read-only \ - -e RUST_LOG=info \ - -e SEED=$SEED \ - -e URI=wss://your-node:9944 \ - staking-miner dry-run -``` - -### Test locally - -Make sure you've built Polkadot, then: - -1. `cargo run -p polkadot --features fast-runtime -- --chain polkadot-dev --tmp --alice -lruntime=debug` -2. `cargo run -p staking-miner -- --uri ws://localhost:9944 monitor --seed-or-path //Alice phrag-mms` diff --git a/polkadot/utils/staking-miner/src/dry_run.rs b/polkadot/utils/staking-miner/src/dry_run.rs deleted file mode 100644 index 7e46f630a1f..00000000000 --- a/polkadot/utils/staking-miner/src/dry_run.rs +++ /dev/null @@ -1,166 +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 dry-run command. - -use crate::{opts::DryRunConfig, prelude::*, rpc::*, signer::Signer, Error, SharedRpcClient}; -use codec::Encode; -use frame_support::traits::Currency; -use sp_core::Bytes; -use sp_npos_elections::ElectionScore; - -/// Forcefully create the snapshot. This can be used to compute the election at anytime. -fn force_create_snapshot(ext: &mut Ext) -> Result<(), Error> { - ext.execute_with(|| { - if >::exists() { - log::info!(target: LOG_TARGET, "snapshot already exists."); - Ok(()) - } else { - log::info!(target: LOG_TARGET, "creating a fake snapshot now."); - >::create_snapshot().map(|_| ()).map_err(Into::into) - } - }) -} - -/// Helper method to print the encoded size of the snapshot. -async fn print_info( - rpc: &SharedRpcClient, - ext: &mut Ext, - raw_solution: &EPM::RawSolution>, - extrinsic: &Bytes, -) where - ::Currency: Currency, -{ - ext.execute_with(|| { - log::info!( - target: LOG_TARGET, - "Snapshot Metadata: {:?}", - >::snapshot_metadata() - ); - log::info!( - target: LOG_TARGET, - "Snapshot Encoded Length: {:?}", - >::snapshot() - .expect("snapshot must exist before calling `measure_snapshot_size`") - .encode() - .len() - ); - - let snapshot_size = - >::snapshot_metadata().expect("snapshot must exist by now; qed."); - let deposit = EPM::Pallet::::deposit_for(raw_solution, snapshot_size); - - let score = { - let ElectionScore { minimal_stake, sum_stake, sum_stake_squared } = raw_solution.score; - [Token::from(minimal_stake), Token::from(sum_stake), Token::from(sum_stake_squared)] - }; - - log::info!( - target: LOG_TARGET, - "solution score {:?} / deposit {:?} / length {:?}", - score, - Token::from(deposit), - raw_solution.encode().len(), - ); - }); - - let info = rpc.payment_query_info(&extrinsic, None).await; - - log::info!( - target: LOG_TARGET, - "payment_queryInfo: (fee = {}) {:?}", - info.as_ref() - .map(|d| Token::from(d.partial_fee)) - .unwrap_or_else(|_| Token::from(0)), - info, - ); -} - -/// Find the stake threshold in order to have at most `count` voters. -#[allow(unused)] -fn find_threshold(ext: &mut Ext, count: usize) { - ext.execute_with(|| { - let mut voters = >::snapshot() - .expect("snapshot must exist before calling `measure_snapshot_size`") - .voters; - voters.sort_by_key(|(_voter, weight, _targets)| std::cmp::Reverse(*weight)); - match voters.get(count) { - Some(threshold_voter) => println!("smallest allowed voter is {:?}", threshold_voter), - None => { - println!("requested truncation to {} voters but had only {}", count, voters.len()); - println!("smallest current voter: {:?}", voters.last()); - }, - } - }) -} - -macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! { - /// Execute the dry-run command. - pub(crate) async fn []( - rpc: SharedRpcClient, - config: DryRunConfig, - signer: Signer, - ) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> { - use $crate::[<$runtime _runtime_exports>]::*; - let pallets = if config.force_snapshot { - vec!["Staking".to_string(), "BagsList".to_string()] - } else { - Default::default() - }; - let mut ext = crate::create_election_ext::(rpc.clone(), config.at, pallets).await?; - if config.force_snapshot { - force_create_snapshot::(&mut ext)?; - }; - - log::debug!(target: LOG_TARGET, "solving with {:?}", config.solver); - let raw_solution = crate::mine_with::(&config.solver, &mut ext, false)?; - - let nonce = crate::get_account_info::(&rpc, &signer.account, config.at) - .await? - .map(|i| i.nonce) - .expect("signer account is checked to exist upon startup; it can only die if it \ - transfers funds out of it, or get slashed. If it does not exist at this point, \ - it is likely due to a bug, or the signer got slashed. Terminating." - ); - let tip = 0 as Balance; - let era = sp_runtime::generic::Era::Immortal; - let extrinsic = ext.execute_with(|| create_uxt(raw_solution.clone(), signer.clone(), nonce, tip, era)); - - let bytes = sp_core::Bytes(extrinsic.encode().to_vec()); - print_info::(&rpc, &mut ext, &raw_solution, &bytes).await; - - let feasibility_result = ext.execute_with(|| { - EPM::Pallet::::feasibility_check(raw_solution.clone(), EPM::ElectionCompute::Signed) - }); - log::info!(target: LOG_TARGET, "feasibility result is {:?}", feasibility_result.map(|_| ())); - - let dispatch_result = ext.execute_with(|| { - // manually tweak the phase. - EPM::CurrentPhase::::put(EPM::Phase::Signed); - EPM::Pallet::::submit(frame_system::RawOrigin::Signed(signer.account).into(), Box::new(raw_solution)) - }); - log::info!(target: LOG_TARGET, "dispatch result is {:?}", dispatch_result); - - let dry_run_fut = rpc.dry_run(&bytes, None); - let outcome: sp_runtime::ApplyExtrinsicResult = await_request_and_decode(dry_run_fut).await.map_err::, _>(Into::into)?; - log::info!(target: LOG_TARGET, "dry-run outcome is {:?}", outcome); - Ok(()) - } -}}} - -dry_run_cmd_for!(polkadot); -dry_run_cmd_for!(kusama); -dry_run_cmd_for!(westend); diff --git a/polkadot/utils/staking-miner/src/emergency_solution.rs b/polkadot/utils/staking-miner/src/emergency_solution.rs deleted file mode 100644 index 9ea9f90756e..00000000000 --- a/polkadot/utils/staking-miner/src/emergency_solution.rs +++ /dev/null @@ -1,65 +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 emergency-solution command. - -use crate::{prelude::*, EmergencySolutionConfig, Error, SharedRpcClient}; -use codec::Encode; -use std::io::Write; - -macro_rules! emergency_solution_cmd_for { ($runtime:ident) => { paste::paste! { - /// Execute the emergency-solution command. - pub(crate) async fn []( - client: SharedRpcClient, - config: EmergencySolutionConfig, - ) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> { - use $crate::[<$runtime _runtime_exports>]::*; - - let mut ext = crate::create_election_ext::(client, config.at, vec![]).await?; - let raw_solution = crate::mine_with::(&config.solver, &mut ext, false)?; - - ext.execute_with(|| { - assert!(EPM::Pallet::::current_phase().is_emergency()); - - log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score); - - let ready_solution = EPM::Pallet::::feasibility_check(raw_solution, EPM::ElectionCompute::Signed)?; - let encoded_size = ready_solution.encoded_size(); - let score = ready_solution.score; - let mut supports = ready_solution.supports.into_inner(); - // maybe truncate. - if let Some(take) = config.take { - log::info!(target: LOG_TARGET, "truncating {} winners to {}", supports.len(), take); - supports.sort_unstable_by_key(|(_, s)| s.total); - supports.truncate(take); - } - - // write to file and stdout. - let encoded_support = supports.encode(); - let mut supports_file = std::fs::File::create("solution.supports.bin")?; - supports_file.write_all(&encoded_support)?; - - log::info!(target: LOG_TARGET, "ReadySolution: size {:?} / score = {:?}", encoded_size, score); - log::trace!(target: LOG_TARGET, "Supports: {}", sp_core::hexdisplay::HexDisplay::from(&encoded_support)); - - Ok(()) - }) - } -}}} - -emergency_solution_cmd_for!(polkadot); -emergency_solution_cmd_for!(kusama); -emergency_solution_cmd_for!(westend); diff --git a/polkadot/utils/staking-miner/src/main.rs b/polkadot/utils/staking-miner/src/main.rs deleted file mode 100644 index 90b2c7366a1..00000000000 --- a/polkadot/utils/staking-miner/src/main.rs +++ /dev/null @@ -1,665 +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 . - -//! # Polkadot Staking Miner. -//! -//! Simple bot capable of monitoring a polkadot (and cousins) chain and submitting solutions to the -//! `pallet-election-provider-multi-phase`. See `--help` for more details. -//! -//! # Implementation Notes: -//! -//! - First draft: Be aware that this is the first draft and there might be bugs, or undefined -//! behaviors. Don't attach this bot to an account with lots of funds. -//! - Quick to crash: The bot is written so that it only continues to work if everything goes well. -//! In case of any failure (RPC, logic, IO), it will crash. This was a decision to simplify the -//! development. It is intended to run this bot with a `restart = true` way, so that it reports it -//! crash, but resumes work thereafter. - -// Silence erroneous warning about unsafe not being required whereas it is -// see https://github.com/rust-lang/rust/issues/49112 -#![allow(unused_unsafe)] - -mod dry_run; -mod emergency_solution; -mod monitor; -mod opts; -mod prelude; -mod rpc; -mod runtime_versions; -mod signer; - -pub(crate) use prelude::*; -pub(crate) use signer::get_account_info; - -use crate::opts::*; -use clap::Parser; -use frame_election_provider_support::NposSolver; -use frame_support::traits::Get; -use futures_util::StreamExt; -use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; -use remote_externalities::{Builder, Mode, OnlineConfig, Transport}; -use rpc::{RpcApiClient, SharedRpcClient}; -use runtime_versions::RuntimeVersions; -use signal_hook::consts::signal::*; -use signal_hook_tokio::Signals; -use sp_npos_elections::BalancingConfig; -use std::{ops::Deref, sync::Arc, time::Duration}; -use tracing_subscriber::{fmt, EnvFilter}; - -pub(crate) enum AnyRuntime { - Polkadot, - Kusama, - Westend, -} - -pub(crate) static mut RUNTIME: AnyRuntime = AnyRuntime::Polkadot; - -macro_rules! construct_runtime_prelude { - ($runtime:ident) => { paste::paste! { - pub(crate) mod [<$runtime _runtime_exports>] { - pub(crate) use crate::prelude::EPM; - pub(crate) use [<$runtime _runtime>]::*; - pub(crate) use crate::monitor::[] as monitor_cmd; - pub(crate) use crate::dry_run::[] as dry_run_cmd; - pub(crate) use crate::emergency_solution::[] as emergency_solution_cmd; - pub(crate) use private::{[] as create_uxt}; - - mod private { - use super::*; - pub(crate) fn []( - raw_solution: EPM::RawSolution>, - signer: crate::signer::Signer, - nonce: crate::prelude::Nonce, - tip: crate::prelude::Balance, - era: sp_runtime::generic::Era, - ) -> UncheckedExtrinsic { - use codec::Encode as _; - use sp_core::Pair as _; - use sp_runtime::traits::StaticLookup as _; - - let crate::signer::Signer { account, pair, .. } = signer; - - let local_call = EPMCall::::submit { raw_solution: Box::new(raw_solution) }; - let call: RuntimeCall = as std::convert::TryInto>::try_into(local_call) - .expect("election provider pallet must exist in the runtime, thus \ - inner call can be converted, qed." - ); - - let extra: SignedExtra = crate::[](nonce, tip, era); - let raw_payload = SignedPayload::new(call, extra).expect("creating signed payload infallible; qed."); - let signature = raw_payload.using_encoded(|payload| { - pair.sign(payload) - }); - let (call, extra, _) = raw_payload.deconstruct(); - let address = ::Lookup::unlookup(account); - let extrinsic = UncheckedExtrinsic::new_signed(call, address, signature.into(), extra); - log::debug!( - target: crate::LOG_TARGET, "constructed extrinsic {} with length {}", - sp_core::hexdisplay::HexDisplay::from(&extrinsic.encode()), - extrinsic.encode().len(), - ); - extrinsic - } - } - }} - }; -} - -// NOTE: we might be able to use some code from the bridges repo here. -fn signed_ext_builder_polkadot( - nonce: Nonce, - tip: Balance, - era: sp_runtime::generic::Era, -) -> polkadot_runtime_exports::SignedExtra { - use polkadot_runtime_exports::Runtime; - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(era), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - runtime_common::claims::PrevalidateAttests::::new(), - ) -} - -fn signed_ext_builder_kusama( - nonce: Nonce, - tip: Balance, - era: sp_runtime::generic::Era, -) -> kusama_runtime_exports::SignedExtra { - use kusama_runtime_exports::Runtime; - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(era), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) -} - -fn signed_ext_builder_westend( - nonce: Nonce, - tip: Balance, - era: sp_runtime::generic::Era, -) -> westend_runtime_exports::SignedExtra { - use westend_runtime_exports::Runtime; - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(era), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) -} - -construct_runtime_prelude!(polkadot); -construct_runtime_prelude!(kusama); -construct_runtime_prelude!(westend); - -// NOTE: this is no longer used extensively, most of the per-runtime stuff us delegated to -// `construct_runtime_prelude` and macro's the import directly from it. A part of the code is also -// still generic over `T`. My hope is to still make everything generic over a `Runtime`, but sadly -// that is not currently possible as each runtime has its unique `Call`, and all Calls are not -// sharing any generic trait. In other words, to create the `UncheckedExtrinsic` of each chain, you -// need the concrete `Call` of that chain as well. -#[macro_export] -macro_rules! any_runtime { - ($($code:tt)*) => { - unsafe { - match $crate::RUNTIME { - $crate::AnyRuntime::Polkadot => { - #[allow(unused)] - use $crate::polkadot_runtime_exports::*; - $($code)* - }, - $crate::AnyRuntime::Kusama => { - #[allow(unused)] - use $crate::kusama_runtime_exports::*; - $($code)* - }, - $crate::AnyRuntime::Westend => { - #[allow(unused)] - use $crate::westend_runtime_exports::*; - $($code)* - } - } - } - } -} - -/// Same as [`any_runtime`], but instead of returning a `Result`, this simply returns `()`. Useful -/// for situations where the result is not useful and un-ergonomic to handle. -#[macro_export] -macro_rules! any_runtime_unit { - ($($code:tt)*) => { - unsafe { - match $crate::RUNTIME { - $crate::AnyRuntime::Polkadot => { - #[allow(unused)] - use $crate::polkadot_runtime_exports::*; - let _ = $($code)*; - }, - $crate::AnyRuntime::Kusama => { - #[allow(unused)] - use $crate::kusama_runtime_exports::*; - let _ = $($code)*; - }, - $crate::AnyRuntime::Westend => { - #[allow(unused)] - use $crate::westend_runtime_exports::*; - let _ = $($code)*; - } - } - } - } -} - -#[derive(frame_support::DebugNoBound, thiserror::Error)] -enum Error { - Io(#[from] std::io::Error), - JsonRpsee(#[from] jsonrpsee::core::Error), - RpcHelperError(#[from] rpc::RpcHelperError), - Codec(#[from] codec::Error), - Crypto(sp_core::crypto::SecretStringError), - RemoteExternalities(&'static str), - PalletMiner(EPM::unsigned::MinerError), - PalletElection(EPM::ElectionError), - PalletFeasibility(EPM::FeasibilityError), - AccountDoesNotExists, - IncorrectPhase, - AlreadySubmitted, - VersionMismatch, - StrategyNotSatisfied, - Other(String), -} - -impl From for Error { - fn from(e: sp_core::crypto::SecretStringError) -> Error { - Error::Crypto(e) - } -} - -impl From for Error { - fn from(e: EPM::unsigned::MinerError) -> Error { - Error::PalletMiner(e) - } -} - -impl From> for Error { - fn from(e: EPM::ElectionError) -> Error { - Error::PalletElection(e) - } -} - -impl From for Error { - fn from(e: EPM::FeasibilityError) -> Error { - Error::PalletFeasibility(e) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - as std::fmt::Debug>::fmt(self, f) - } -} - -frame_support::parameter_types! { - /// Number of balancing iterations for a solution algorithm. Set based on the [`Solvers`] CLI - /// config. - pub static BalanceIterations: usize = 10; - pub static Balancing: Option = Some( BalancingConfig { iterations: BalanceIterations::get(), tolerance: 0 } ); -} - -/// Build the Ext at hash with all the data of `ElectionProviderMultiPhase` and any additional -/// pallets. -async fn create_election_ext( - client: SharedRpcClient, - at: Option, - additional: Vec, -) -> Result> -where - T: EPM::Config, -{ - use frame_support::{storage::generator::StorageMap, traits::PalletInfo}; - use sp_core::hashing::twox_128; - - let mut pallets = vec![::PalletInfo::name::>() - .expect("Pallet always has name; qed.") - .to_string()]; - pallets.extend(additional); - Builder::::new() - .mode(Mode::Online(OnlineConfig { - transport: Transport::Uri(client.uri().to_owned()), - at, - pallets, - hashed_prefixes: vec![>::prefix_hash()], - hashed_keys: vec![[twox_128(b"System"), twox_128(b"Number")].concat()], - ..Default::default() - })) - .build() - .await - .map_err(|why| Error::::RemoteExternalities(why)) - .map(|rx| rx.inner_ext) -} - -/// Compute the election. It expects to NOT be `Phase::Off`. In other words, the snapshot must -/// exists on the given externalities. -fn mine_solution( - ext: &mut Ext, - do_feasibility: bool, -) -> Result>, Error> -where - T: EPM::Config, - S: NposSolver< - Error = <::Solver as NposSolver>::Error, - AccountId = <::Solver as NposSolver>::AccountId, - >, -{ - ext.execute_with(|| { - let (solution, _) = >::mine_solution().map_err::, _>(Into::into)?; - if do_feasibility { - let _ = >::feasibility_check( - solution.clone(), - EPM::ElectionCompute::Signed, - )?; - } - Ok(solution) - }) -} - -/// Mine a solution with the given `solver`. -fn mine_with( - solver: &Solver, - ext: &mut Ext, - do_feasibility: bool, -) -> Result>, Error> -where - T: EPM::Config, - T::Solver: NposSolver, -{ - use frame_election_provider_support::{PhragMMS, SequentialPhragmen}; - - match solver { - Solver::SeqPhragmen { iterations } => { - BalanceIterations::set(*iterations); - mine_solution::< - T, - SequentialPhragmen< - ::AccountId, - sp_runtime::Perbill, - Balancing, - >, - >(ext, do_feasibility) - }, - Solver::PhragMMS { iterations } => { - BalanceIterations::set(*iterations); - mine_solution::< - T, - PhragMMS<::AccountId, sp_runtime::Perbill, Balancing>, - >(ext, do_feasibility) - }, - } -} - -#[allow(unused)] -fn mine_dpos(ext: &mut Ext) -> Result<(), Error> { - ext.execute_with(|| { - use std::collections::BTreeMap; - use EPM::RoundSnapshot; - let RoundSnapshot { voters, .. } = EPM::Snapshot::::get().unwrap(); - let desired_targets = EPM::DesiredTargets::::get().unwrap(); - let mut candidates_and_backing = BTreeMap::::new(); - voters.into_iter().for_each(|(who, stake, targets)| { - if targets.is_empty() { - println!("target = {:?}", (who, stake, targets)); - return - } - let share: u128 = (stake as u128) / (targets.len() as u128); - for target in targets { - *candidates_and_backing.entry(target.clone()).or_default() += share - } - }); - - let mut candidates_and_backing = - candidates_and_backing.into_iter().collect::>(); - candidates_and_backing.sort_by_key(|(_, total_stake)| *total_stake); - let winners = candidates_and_backing - .into_iter() - .rev() - .take(desired_targets as usize) - .collect::>(); - let score = { - let min_staker = *winners.last().map(|(_, stake)| stake).unwrap(); - let sum_stake = winners.iter().fold(0u128, |acc, (_, stake)| acc + stake); - let sum_squared = winners.iter().fold(0u128, |acc, (_, stake)| acc + stake); - [min_staker, sum_stake, sum_squared] - }; - println!("mined a dpos-like solution with score = {:?}", score); - Ok(()) - }) -} - -pub(crate) async fn check_versions( - rpc: &SharedRpcClient, - print: bool, -) -> Result<(), Error> { - let linked_version = T::Version::get(); - let on_chain_version = rpc - .runtime_version(None) - .await - .expect("runtime version RPC should always work; qed"); - - let do_print = || { - log::info!( - target: LOG_TARGET, - "linked version {:?}", - (&linked_version.spec_name, &linked_version.spec_version) - ); - log::info!( - target: LOG_TARGET, - "on-chain version {:?}", - (&on_chain_version.spec_name, &on_chain_version.spec_version) - ); - }; - - if print { - do_print(); - } - - // we relax the checking here a bit, which should not cause any issues in production (a chain - // that messes up its spec name is highly unlikely), but it allows us to do easier testing. - if linked_version.spec_name != on_chain_version.spec_name || - linked_version.spec_version != on_chain_version.spec_version - { - if !print { - do_print(); - } - log::error!( - target: LOG_TARGET, - "VERSION MISMATCH: any transaction will fail with bad-proof" - ); - Err(Error::VersionMismatch) - } else { - Ok(()) - } -} - -/// Control how we exit the application -fn controlled_exit(code: i32) { - log::info!(target: LOG_TARGET, "Exiting application"); - std::process::exit(code); -} - -/// Handles the various signal and exit the application -/// when appropriate. -async fn handle_signals(mut signals: Signals) { - let mut keyboard_sig_count: u8 = 0; - while let Some(signal) = signals.next().await { - match signal { - // Interrupts come from the keyboard - SIGQUIT | SIGINT => { - if keyboard_sig_count >= 1 { - log::info!( - target: LOG_TARGET, - "Received keyboard termination signal #{}/{}, quitting...", - keyboard_sig_count + 1, - 2 - ); - controlled_exit(exitcode::OK); - } - keyboard_sig_count += 1; - log::warn!( - target: LOG_TARGET, - "Received keyboard termination signal #{}, if you keep doing that I will really quit", - keyboard_sig_count - ); - }, - - SIGKILL | SIGTERM => { - log::info!(target: LOG_TARGET, "Received SIGKILL | SIGTERM, quitting..."); - controlled_exit(exitcode::OK); - }, - _ => unreachable!(), - } - } -} - -#[tokio::main] -async fn main() { - fmt().with_env_filter(EnvFilter::from_default_env()).init(); - - let Opt { uri, command, connection_timeout, request_timeout } = Opt::parse(); - log::debug!(target: LOG_TARGET, "attempting to connect to {:?}", uri); - - let signals = Signals::new(&[SIGTERM, SIGINT, SIGQUIT]).expect("Failed initializing Signals"); - let handle = signals.handle(); - let signals_task = tokio::spawn(handle_signals(signals)); - - let rpc = loop { - match SharedRpcClient::new( - &uri, - Duration::from_secs(connection_timeout as u64), - Duration::from_secs(request_timeout as u64), - ) - .await - { - Ok(client) => break client, - Err(why) => { - log::warn!( - target: LOG_TARGET, - "failed to connect to client due to {:?}, retrying soon..", - why - ); - tokio::time::sleep(std::time::Duration::from_millis(2500)).await; - }, - } - }; - - let chain: String = rpc.system_chain().await.expect("system_chain infallible; qed."); - match chain.to_lowercase().as_str() { - "polkadot" | "development" => { - sp_core::crypto::set_default_ss58_version( - sp_core::crypto::Ss58AddressFormatRegistry::PolkadotAccount.into(), - ); - sub_tokens::dynamic::set_name("DOT"); - sub_tokens::dynamic::set_decimal_points(10_000_000_000); - // safety: this program will always be single threaded, thus accessing global static is - // safe. - unsafe { - RUNTIME = AnyRuntime::Polkadot; - } - }, - "kusama" | "kusama-dev" => { - sp_core::crypto::set_default_ss58_version( - sp_core::crypto::Ss58AddressFormatRegistry::KusamaAccount.into(), - ); - sub_tokens::dynamic::set_name("KSM"); - sub_tokens::dynamic::set_decimal_points(1_000_000_000_000); - // safety: this program will always be single threaded, thus accessing global static is - // safe. - unsafe { - RUNTIME = AnyRuntime::Kusama; - } - }, - "westend" => { - sp_core::crypto::set_default_ss58_version( - sp_core::crypto::Ss58AddressFormatRegistry::PolkadotAccount.into(), - ); - sub_tokens::dynamic::set_name("WND"); - sub_tokens::dynamic::set_decimal_points(1_000_000_000_000); - // safety: this program will always be single threaded, thus accessing global static is - // safe. - unsafe { - RUNTIME = AnyRuntime::Westend; - } - }, - _ => { - eprintln!("unexpected chain: {:?}", chain); - return - }, - } - log::info!(target: LOG_TARGET, "connected to chain {:?}", chain); - - any_runtime_unit! { - check_versions::(&rpc, true).await - }; - - let outcome = any_runtime! { - match command { - Command::Monitor(monitor_config) => - { - let signer_account = any_runtime! { - signer::signer_uri_from_string::(&monitor_config.seed_or_path , &rpc) - .await - .expect("Provided account is invalid, terminating.") - }; - monitor_cmd(rpc, monitor_config, signer_account).await - .map_err(|e| { - log::error!(target: LOG_TARGET, "Monitor error: {:?}", e); - })}, - Command::DryRun(dryrun_config) => { - let signer_account = any_runtime! { - signer::signer_uri_from_string::(&dryrun_config.seed_or_path , &rpc) - .await - .expect("Provided account is invalid, terminating.") - }; - dry_run_cmd(rpc, dryrun_config, signer_account).await - .map_err(|e| { - log::error!(target: LOG_TARGET, "DryRun error: {:?}", e); - })}, - Command::EmergencySolution(emergency_solution_config) => - emergency_solution_cmd(rpc, emergency_solution_config).await - .map_err(|e| { - log::error!(target: LOG_TARGET, "EmergencySolution error: {:?}", e); - }), - Command::Info(info_opts) => { - let remote_runtime_version = rpc.runtime_version(None).await.expect("runtime_version infallible; qed."); - - let builtin_version = any_runtime! { - Version::get() - }; - - let versions = RuntimeVersions::new(&remote_runtime_version, &builtin_version); - - if !info_opts.json { - println!("{}", versions); - } else { - let versions = serde_json::to_string_pretty(&versions).expect("Failed serializing version info"); - println!("{}", versions); - } - Ok(()) - } - } - }; - log::info!(target: LOG_TARGET, "round of execution finished. outcome = {:?}", outcome); - - handle.close(); - let _ = signals_task.await; -} - -#[cfg(test)] -mod tests { - use super::*; - - fn get_version() -> sp_version::RuntimeVersion { - T::Version::get() - } - - #[test] - fn any_runtime_works() { - unsafe { - RUNTIME = AnyRuntime::Polkadot; - } - let polkadot_version = any_runtime! { get_version::() }; - - unsafe { - RUNTIME = AnyRuntime::Kusama; - } - let kusama_version = any_runtime! { get_version::() }; - - assert_eq!(polkadot_version.spec_name, "polkadot".into()); - assert_eq!(kusama_version.spec_name, "kusama".into()); - } -} diff --git a/polkadot/utils/staking-miner/src/monitor.rs b/polkadot/utils/staking-miner/src/monitor.rs deleted file mode 100644 index 607ecb6baa4..00000000000 --- a/polkadot/utils/staking-miner/src/monitor.rs +++ /dev/null @@ -1,478 +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 monitor command. - -use crate::{ - prelude::*, rpc::*, signer::Signer, Error, MonitorConfig, SharedRpcClient, SubmissionStrategy, -}; -use codec::Encode; -use jsonrpsee::core::Error as RpcError; -use sc_transaction_pool_api::TransactionStatus; -use sp_core::storage::StorageKey; -use sp_runtime::Perbill; -use std::sync::Arc; -use tokio::sync::{mpsc, Mutex}; -use EPM::{signed::SubmissionIndicesOf, SignedSubmissionOf}; - -/// Ensure that now is the signed phase. -async fn ensure_signed_phase>( - rpc: &SharedRpcClient, - at: B::Hash, -) -> Result<(), Error> { - let key = StorageKey(EPM::CurrentPhase::::hashed_key().to_vec()); - let phase = rpc - .get_storage_and_decode::>(&key, Some(at)) - .await - .map_err::, _>(Into::into)? - .unwrap_or_default(); - - if phase.is_signed() { - Ok(()) - } else { - Err(Error::IncorrectPhase) - } -} - -/// Ensure that our current `us` have not submitted anything previously. -async fn ensure_no_previous_solution( - rpc: &SharedRpcClient, - at: Hash, - us: &AccountId, -) -> Result<(), Error> -where - T: EPM::Config + frame_system::Config, - B: BlockT, -{ - let indices_key = StorageKey(EPM::SignedSubmissionIndices::::hashed_key().to_vec()); - - let indices: SubmissionIndicesOf = rpc - .get_storage_and_decode(&indices_key, Some(at)) - .await - .map_err::, _>(Into::into)? - .unwrap_or_default(); - - for (_score, _bn, idx) in indices { - let key = StorageKey(EPM::SignedSubmissionsMap::::hashed_key_for(idx)); - - if let Some(submission) = rpc - .get_storage_and_decode::>(&key, Some(at)) - .await - .map_err::, _>(Into::into)? - { - if &submission.who == us { - return Err(Error::AlreadySubmitted) - } - } - } - - Ok(()) -} - -/// `true` if `our_score` should pass the onchain `best_score` with the given strategy. -pub(crate) fn score_passes_strategy( - our_score: sp_npos_elections::ElectionScore, - best_score: sp_npos_elections::ElectionScore, - strategy: SubmissionStrategy, -) -> bool { - match strategy { - SubmissionStrategy::Always => true, - SubmissionStrategy::IfLeading => - our_score == best_score || - our_score.strict_threshold_better(best_score, Perbill::zero()), - SubmissionStrategy::ClaimBetterThan(epsilon) => - our_score.strict_threshold_better(best_score, epsilon), - SubmissionStrategy::ClaimNoWorseThan(epsilon) => - !best_score.strict_threshold_better(our_score, epsilon), - } -} - -/// Reads all current solutions and checks the scores according to the `SubmissionStrategy`. -async fn ensure_strategy_met( - rpc: &SharedRpcClient, - at: Hash, - score: sp_npos_elections::ElectionScore, - strategy: SubmissionStrategy, - max_submissions: u32, -) -> Result<(), Error> { - // don't care about current scores. - if matches!(strategy, SubmissionStrategy::Always) { - return Ok(()) - } - - let indices_key = StorageKey(EPM::SignedSubmissionIndices::::hashed_key().to_vec()); - - let indices: SubmissionIndicesOf = rpc - .get_storage_and_decode(&indices_key, Some(at)) - .await - .map_err::, _>(Into::into)? - .unwrap_or_default(); - - if indices.len() >= max_submissions as usize { - log::debug!(target: LOG_TARGET, "The submissions queue is full"); - } - - // default score is all zeros, any score is better than it. - let best_score = indices.last().map(|(score, _, _)| *score).unwrap_or_default(); - log::debug!(target: LOG_TARGET, "best onchain score is {:?}", best_score); - - if score_passes_strategy(score, best_score, strategy) { - Ok(()) - } else { - Err(Error::StrategyNotSatisfied) - } -} - -async fn get_latest_head( - rpc: &SharedRpcClient, - mode: &str, -) -> Result> { - if mode == "head" { - match rpc.block_hash(None).await { - Ok(Some(hash)) => Ok(hash), - Ok(None) => Err(Error::Other("Best head not found".into())), - Err(e) => Err(e.into()), - } - } else { - rpc.finalized_head().await.map_err(Into::into) - } -} - -macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! { - - /// The monitor command. - pub(crate) async fn []( - rpc: SharedRpcClient, - config: MonitorConfig, - signer: Signer, - ) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> { - use $crate::[<$runtime _runtime_exports>]::*; - type StakingMinerError = Error<$crate::[<$runtime _runtime_exports>]::Runtime>; - - let heads_subscription = || - if config.listen == "head" { - rpc.subscribe_new_heads() - } else { - rpc.subscribe_finalized_heads() - }; - - let mut subscription = heads_subscription().await?; - let (tx, mut rx) = mpsc::unbounded_channel::(); - let submit_lock = Arc::new(Mutex::new(())); - - loop { - let at = tokio::select! { - maybe_rp = subscription.next() => { - match maybe_rp { - Some(Ok(r)) => r, - Some(Err(e)) => { - log::error!(target: LOG_TARGET, "subscription failed to decode Header {:?}, this is bug please file an issue", e); - return Err(e.into()); - } - // The subscription was dropped, should only happen if: - // - the connection was closed. - // - the subscription could not keep up with the server. - None => { - log::warn!(target: LOG_TARGET, "subscription to `subscribeNewHeads/subscribeFinalizedHeads` terminated. Retrying.."); - subscription = heads_subscription().await?; - continue - } - } - }, - maybe_err = rx.recv() => { - match maybe_err { - Some(err) => return Err(err), - None => unreachable!("at least one sender kept in the main loop should always return Some; qed"), - } - } - }; - - // Spawn task and non-recoverable errors are sent back to the main task - // such as if the connection has been closed. - tokio::spawn( - send_and_watch_extrinsic(rpc.clone(), tx.clone(), at, signer.clone(), config.clone(), submit_lock.clone()) - ); - } - - /// Construct extrinsic at given block and watch it. - async fn send_and_watch_extrinsic( - rpc: SharedRpcClient, - tx: mpsc::UnboundedSender, - at: Header, - signer: Signer, - config: MonitorConfig, - submit_lock: Arc>, - ) { - - async fn flatten( - handle: tokio::task::JoinHandle> - ) -> Result { - match handle.await { - Ok(Ok(result)) => Ok(result), - Ok(Err(err)) => Err(err), - Err(err) => panic!("tokio spawn task failed; kill task: {:?}", err), - } - } - - let hash = at.hash(); - log::trace!(target: LOG_TARGET, "new event at #{:?} ({:?})", at.number, hash); - - // block on this because if this fails there is no way to recover from - // that error i.e, upgrade/downgrade required. - if let Err(err) = crate::check_versions::(&rpc, false).await { - let _ = tx.send(err.into()); - return; - } - - let rpc1 = rpc.clone(); - let rpc2 = rpc.clone(); - let account = signer.account.clone(); - - let signed_phase_fut = tokio::spawn(async move { - ensure_signed_phase::(&rpc1, hash).await - }); - - tokio::time::sleep(std::time::Duration::from_secs(config.delay as u64)).await; - - let no_prev_sol_fut = tokio::spawn(async move { - ensure_no_previous_solution::(&rpc2, hash, &account).await - }); - - // Run the calls in parallel and return once all has completed or any failed. - if let Err(err) = tokio::try_join!(flatten(signed_phase_fut), flatten(no_prev_sol_fut)) { - log::debug!(target: LOG_TARGET, "Skipping block {}; {}", at.number, err); - return; - } - - let _lock = submit_lock.lock().await; - - let mut ext = match crate::create_election_ext::(rpc.clone(), Some(hash), vec![]).await { - Ok(ext) => ext, - Err(err) => { - log::debug!(target: LOG_TARGET, "Skipping block {}; {}", at.number, err); - return; - } - }; - - // mine a solution, and run feasibility check on it as well. - let raw_solution = match crate::mine_with::(&config.solver, &mut ext, true) { - Ok(r) => r, - Err(err) => { - let _ = tx.send(err.into()); - return; - } - }; - - let score = raw_solution.score; - log::info!(target: LOG_TARGET, "mined solution with {:?}", score); - - let nonce = match crate::get_account_info::(&rpc, &signer.account, Some(hash)).await { - Ok(maybe_account) => { - let acc = maybe_account.expect(crate::signer::SIGNER_ACCOUNT_WILL_EXIST); - acc.nonce - } - Err(err) => { - let _ = tx.send(err); - return; - } - }; - - let tip = 0 as Balance; - let period = ::BlockHashCount::get() / 2; - let current_block = at.number.saturating_sub(1); - let era = sp_runtime::generic::Era::mortal(period.into(), current_block.into()); - - log::trace!( - target: LOG_TARGET, "transaction mortality: {:?} -> {:?}", - era.birth(current_block.into()), - era.death(current_block.into()), - ); - - let extrinsic = ext.execute_with(|| create_uxt(raw_solution, signer.clone(), nonce, tip, era)); - let bytes = sp_core::Bytes(extrinsic.encode()); - - let rpc1 = rpc.clone(); - let rpc2 = rpc.clone(); - let rpc3 = rpc.clone(); - - let latest_head = match get_latest_head::(&rpc, &config.listen).await { - Ok(hash) => hash, - Err(e) => { - log::debug!(target: LOG_TARGET, "Skipping to submit at block {}; {}", at.number, e); - return; - } - }; - - let ensure_strategy_met_fut = tokio::spawn(async move { - ensure_strategy_met::( - &rpc1, - latest_head, - score, - config.submission_strategy, - SignedMaxSubmissions::get() - ).await - }); - - let ensure_signed_phase_fut = tokio::spawn(async move { - ensure_signed_phase::(&rpc2, latest_head).await - }); - - let account = signer.account.clone(); - let no_prev_sol_fut = tokio::spawn(async move { - ensure_no_previous_solution::(&rpc3, latest_head, &account).await - }); - - // Run the calls in parallel and return once all has completed or any failed. - if let Err(err) = tokio::try_join!( - flatten(ensure_strategy_met_fut), - flatten(ensure_signed_phase_fut), - flatten(no_prev_sol_fut), - ) { - log::debug!(target: LOG_TARGET, "Skipping to submit at block {}; {}", at.number, err); - return; - } - - let mut tx_subscription = match rpc.watch_extrinsic(&bytes).await { - Ok(sub) => sub, - Err(RpcError::RestartNeeded(e)) => { - let _ = tx.send(RpcError::RestartNeeded(e).into()); - return - }, - Err(why) => { - // This usually happens when we've been busy with mining for a few blocks, and - // now we're receiving the subscriptions of blocks in which we were busy. In - // these blocks, we still don't have a solution, so we re-compute a new solution - // and submit it with an outdated `Nonce`, which yields most often `Stale` - // error. NOTE: to improve this overall, and to be able to introduce an array of - // other fancy features, we should make this multi-threaded and do the - // computation outside of this callback. - log::warn!( - target: LOG_TARGET, - "failing to submit a transaction {:?}. ignore block: {}", - why, at.number - ); - return; - }, - }; - - while let Some(rp) = tx_subscription.next().await { - let status_update = match rp { - Ok(r) => r, - Err(e) => { - log::error!(target: LOG_TARGET, "subscription failed to decode TransactionStatus {:?}, this is a bug please file an issue", e); - let _ = tx.send(e.into()); - return; - }, - }; - - log::trace!(target: LOG_TARGET, "status update {:?}", status_update); - match status_update { - TransactionStatus::Ready | - TransactionStatus::Broadcast(_) | - TransactionStatus::Future => continue, - TransactionStatus::InBlock((hash, _)) => { - log::info!(target: LOG_TARGET, "included at {:?}", hash); - let key = StorageKey( - frame_support::storage::storage_prefix(b"System", b"Events").to_vec(), - ); - - let events = match rpc.get_storage_and_decode::< - Vec::Hash>>, - >(&key, Some(hash)) - .await { - Ok(rp) => rp.unwrap_or_default(), - Err(RpcHelperError::JsonRpsee(RpcError::RestartNeeded(e))) => { - let _ = tx.send(RpcError::RestartNeeded(e).into()); - return; - } - // Decoding or other RPC error => just terminate the task. - Err(e) => { - log::warn!(target: LOG_TARGET, "get_storage [key: {:?}, hash: {:?}] failed: {:?}; skip block: {}", - key, hash, e, at.number - ); - return; - } - }; - - log::info!(target: LOG_TARGET, "events at inclusion {:?}", events); - }, - TransactionStatus::Retracted(hash) => { - log::info!(target: LOG_TARGET, "Retracted at {:?}", hash); - }, - TransactionStatus::Finalized((hash, _)) => { - log::info!(target: LOG_TARGET, "Finalized at {:?}", hash); - break - }, - _ => { - log::warn!( - target: LOG_TARGET, - "Stopping listen due to other status {:?}", - status_update - ); - break - }, - }; - } - } - } -}}} - -monitor_cmd_for!(polkadot); -monitor_cmd_for!(kusama); -monitor_cmd_for!(westend); - -#[cfg(test)] -pub mod tests { - use super::*; - - #[test] - fn score_passes_strategy_works() { - let s = |x| sp_npos_elections::ElectionScore { minimal_stake: x, ..Default::default() }; - let two = Perbill::from_percent(2); - - // anything passes Always - assert!(score_passes_strategy(s(0), s(0), SubmissionStrategy::Always)); - assert!(score_passes_strategy(s(5), s(0), SubmissionStrategy::Always)); - assert!(score_passes_strategy(s(5), s(10), SubmissionStrategy::Always)); - - // if leading - assert!(score_passes_strategy(s(0), s(0), SubmissionStrategy::IfLeading)); - assert!(score_passes_strategy(s(1), s(0), SubmissionStrategy::IfLeading)); - assert!(score_passes_strategy(s(2), s(0), SubmissionStrategy::IfLeading)); - assert!(!score_passes_strategy(s(5), s(10), SubmissionStrategy::IfLeading)); - assert!(!score_passes_strategy(s(9), s(10), SubmissionStrategy::IfLeading)); - assert!(score_passes_strategy(s(10), s(10), SubmissionStrategy::IfLeading)); - - // if better by 2% - assert!(!score_passes_strategy(s(50), s(100), SubmissionStrategy::ClaimBetterThan(two))); - assert!(!score_passes_strategy(s(100), s(100), SubmissionStrategy::ClaimBetterThan(two))); - assert!(!score_passes_strategy(s(101), s(100), SubmissionStrategy::ClaimBetterThan(two))); - assert!(!score_passes_strategy(s(102), s(100), SubmissionStrategy::ClaimBetterThan(two))); - assert!(score_passes_strategy(s(103), s(100), SubmissionStrategy::ClaimBetterThan(two))); - assert!(score_passes_strategy(s(150), s(100), SubmissionStrategy::ClaimBetterThan(two))); - - // if no less than 2% worse - assert!(!score_passes_strategy(s(50), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(!score_passes_strategy(s(97), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(98), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(99), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(100), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(101), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(102), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(103), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - assert!(score_passes_strategy(s(150), s(100), SubmissionStrategy::ClaimNoWorseThan(two))); - } -} diff --git a/polkadot/utils/staking-miner/src/opts.rs b/polkadot/utils/staking-miner/src/opts.rs deleted file mode 100644 index 4cf4d0a7651..00000000000 --- a/polkadot/utils/staking-miner/src/opts.rs +++ /dev/null @@ -1,366 +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 crate::prelude::*; -use clap::Parser; -use sp_runtime::Perbill; -use std::str::FromStr; - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -#[command(author, version, about)] -pub(crate) struct Opt { - /// The `ws` node to connect to. - #[arg(long, short, default_value = DEFAULT_URI, env = "URI", global = true)] - pub uri: String, - - /// WS connection timeout in number of seconds. - #[arg(long, default_value_t = 60)] - pub connection_timeout: usize, - - /// WS request timeout in number of seconds. - #[arg(long, default_value_t = 60 * 10)] - pub request_timeout: usize, - - #[command(subcommand)] - pub command: Command, -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) enum Command { - /// Monitor for the phase being signed, then compute. - Monitor(MonitorConfig), - - /// Just compute a solution now, and don't submit it. - DryRun(DryRunConfig), - - /// Provide a solution that can be submitted to the chain as an emergency response. - EmergencySolution(EmergencySolutionConfig), - - /// Return information about the current version - Info(InfoOpts), -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct MonitorConfig { - /// The path to a file containing the seed of the account. If the file is not found, the seed - /// is used as-is. - /// - /// Can also be provided via the `SEED` environment variable. - /// - /// WARNING: Don't use an account with a large stash for this. Based on how the bot is - /// configured, it might re-try and lose funds through transaction fees/deposits. - #[arg(long, short, env = "SEED")] - pub seed_or_path: String, - - /// They type of event to listen to. - /// - /// Typically, finalized is safer and there is no chance of anything going wrong, but it can be - /// slower. It is recommended to use finalized, if the duration of the signed phase is longer - /// than the the finality delay. - #[arg(long, default_value = "head", value_parser = ["head", "finalized"])] - pub listen: String, - - /// The solver algorithm to use. - #[command(subcommand)] - pub solver: Solver, - - /// Submission strategy to use. - /// - /// Possible options: - /// - /// `--submission-strategy if-leading`: only submit if leading. - /// - /// `--submission-strategy always`: always submit. - /// - /// `--submission-strategy "percent-better percent"`: submit if the submission is `n` percent - /// better. - /// - /// `--submission-strategy "no-worse-than percent"`: submit if submission is no more than - /// `n` percent worse. - #[clap(long, default_value = "if-leading")] - pub submission_strategy: SubmissionStrategy, - - /// Delay in number seconds to wait until starting mining a solution. - /// - /// At every block when a solution is attempted - /// a delay can be enforced to avoid submitting at - /// "same time" and risk potential races with other miners. - /// - /// When this is enabled and there are competing solutions, your solution might not be - /// submitted if the scores are equal. - #[arg(long, default_value_t = 0)] - pub delay: usize, -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct DryRunConfig { - /// The path to a file containing the seed of the account. If the file is not found, the seed - /// is used as-is. - /// - /// Can also be provided via the `SEED` environment variable. - /// - /// WARNING: Don't use an account with a large stash for this. Based on how the bot is - /// configured, it might re-try and lose funds through transaction fees/deposits. - #[arg(long, short, env = "SEED")] - pub seed_or_path: String, - - /// The block hash at which scraping happens. If none is provided, the latest head is used. - #[arg(long)] - pub at: Option, - - /// The solver algorithm to use. - #[command(subcommand)] - pub solver: Solver, - - /// Force create a new snapshot, else expect one to exist onchain. - #[arg(long)] - pub force_snapshot: bool, -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct EmergencySolutionConfig { - /// The block hash at which scraping happens. If none is provided, the latest head is used. - #[arg(long)] - pub at: Option, - - /// The solver algorithm to use. - #[command(subcommand)] - pub solver: Solver, - - /// The number of top backed winners to take. All are taken, if not provided. - pub take: Option, -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct InfoOpts { - /// Serialize the output as json - #[arg(long, short)] - pub json: bool, -} - -/// Submission strategy to use. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(test, derive(PartialEq))] -pub enum SubmissionStrategy { - /// Always submit. - Always, - /// Only submit if at the time, we are the best (or equal to it). - IfLeading, - /// Submit if we are no worse than `Perbill` worse than the best. - ClaimNoWorseThan(Perbill), - /// Submit if we are leading, or if the solution that's leading is more that the given - /// `Perbill` better than us. This helps detect obviously fake solutions and still combat them. - ClaimBetterThan(Perbill), -} - -#[derive(Debug, Clone, Parser)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) enum Solver { - SeqPhragmen { - #[arg(long, default_value_t = 10)] - iterations: usize, - }, - PhragMMS { - #[arg(long, default_value_t = 10)] - iterations: usize, - }, -} - -/// Custom `impl` to parse `SubmissionStrategy` from CLI. -/// -/// Possible options: -/// * --submission-strategy if-leading: only submit if leading -/// * --submission-strategy always: always submit -/// * --submission-strategy "percent-better percent": submit if submission is `n` percent better. -/// * --submission-strategy "no-worse-than percent": submit if submission is no more than `n` -/// percent worse. -impl FromStr for SubmissionStrategy { - type Err = String; - - fn from_str(s: &str) -> Result { - let s = s.trim(); - - let res = if s == "if-leading" { - Self::IfLeading - } else if s == "always" { - Self::Always - } else if let Some(percent) = s.strip_prefix("no-worse-than ") { - let percent: u32 = percent.parse().map_err(|e| format!("{:?}", e))?; - Self::ClaimNoWorseThan(Perbill::from_percent(percent)) - } else if let Some(percent) = s.strip_prefix("percent-better ") { - let percent: u32 = percent.parse().map_err(|e| format!("{:?}", e))?; - Self::ClaimBetterThan(Perbill::from_percent(percent)) - } else { - return Err(s.into()) - }; - Ok(res) - } -} - -#[cfg(test)] -mod test_super { - use super::*; - - #[test] - fn cli_monitor_works() { - let opt = Opt::try_parse_from([ - env!("CARGO_PKG_NAME"), - "--uri", - "hi", - "monitor", - "--seed-or-path", - "//Alice", - "--listen", - "head", - "--delay", - "12", - "seq-phragmen", - ]) - .unwrap(); - - assert_eq!( - opt, - Opt { - uri: "hi".to_string(), - connection_timeout: 60, - request_timeout: 10 * 60, - command: Command::Monitor(MonitorConfig { - seed_or_path: "//Alice".to_string(), - listen: "head".to_string(), - solver: Solver::SeqPhragmen { iterations: 10 }, - submission_strategy: SubmissionStrategy::IfLeading, - delay: 12, - }), - } - ); - } - - #[test] - fn cli_dry_run_works() { - let opt = Opt::try_parse_from([ - env!("CARGO_PKG_NAME"), - "--uri", - "hi", - "dry-run", - "--seed-or-path", - "//Alice", - "phrag-mms", - ]) - .unwrap(); - - assert_eq!( - opt, - Opt { - uri: "hi".to_string(), - connection_timeout: 60, - request_timeout: 10 * 60, - command: Command::DryRun(DryRunConfig { - seed_or_path: "//Alice".to_string(), - at: None, - solver: Solver::PhragMMS { iterations: 10 }, - force_snapshot: false, - }), - } - ); - } - - #[test] - fn cli_emergency_works() { - let opt = Opt::try_parse_from([ - env!("CARGO_PKG_NAME"), - "--uri", - "hi", - "emergency-solution", - "99", - "phrag-mms", - "--iterations", - "1337", - ]) - .unwrap(); - - assert_eq!( - opt, - Opt { - uri: "hi".to_string(), - connection_timeout: 60, - request_timeout: 10 * 60, - command: Command::EmergencySolution(EmergencySolutionConfig { - take: Some(99), - at: None, - solver: Solver::PhragMMS { iterations: 1337 } - }), - } - ); - } - - #[test] - fn cli_info_works() { - let opt = Opt::try_parse_from([env!("CARGO_PKG_NAME"), "--uri", "hi", "info"]).unwrap(); - - assert_eq!( - opt, - Opt { - uri: "hi".to_string(), - connection_timeout: 60, - request_timeout: 10 * 60, - command: Command::Info(InfoOpts { json: false }) - } - ); - } - - #[test] - fn cli_request_conn_timeout_works() { - let opt = Opt::try_parse_from([ - env!("CARGO_PKG_NAME"), - "--uri", - "hi", - "--request-timeout", - "10", - "--connection-timeout", - "9", - "info", - ]) - .unwrap(); - - assert_eq!( - opt, - Opt { - uri: "hi".to_string(), - connection_timeout: 9, - request_timeout: 10, - command: Command::Info(InfoOpts { json: false }) - } - ); - } - - #[test] - fn submission_strategy_from_str_works() { - use std::str::FromStr; - - assert_eq!(SubmissionStrategy::from_str("if-leading"), Ok(SubmissionStrategy::IfLeading)); - assert_eq!(SubmissionStrategy::from_str("always"), Ok(SubmissionStrategy::Always)); - assert_eq!( - SubmissionStrategy::from_str(" percent-better 99 "), - Ok(SubmissionStrategy::ClaimBetterThan(Perbill::from_percent(99))) - ); - } -} diff --git a/polkadot/utils/staking-miner/src/prelude.rs b/polkadot/utils/staking-miner/src/prelude.rs deleted file mode 100644 index fb701ece238..00000000000 --- a/polkadot/utils/staking-miner/src/prelude.rs +++ /dev/null @@ -1,55 +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 . - -//! Types that we don't fetch from a particular runtime and just assume that they are constant all -//! of the place. -//! -//! It is actually easy to convert the rest as well, but it'll be a lot of noise in our codebase, -//! needing to sprinkle `any_runtime` in a few extra places. - -/// The account id type. -pub type AccountId = core_primitives::AccountId; -/// The block number type. -pub type BlockNumber = core_primitives::BlockNumber; -/// The balance type. -pub type Balance = core_primitives::Balance; -/// Index of a transaction in the chain. -pub type Nonce = core_primitives::Nonce; -/// The hash type. We re-export it here, but we can easily get it from block as well. -pub type Hash = core_primitives::Hash; -/// The header type. We re-export it here, but we can easily get it from block as well. -pub type Header = core_primitives::Header; -/// The block type. -pub type Block = core_primitives::Block; - -pub use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; - -/// Default URI to connect to. -pub const DEFAULT_URI: &str = "wss://rpc.polkadot.io:443"; -/// The logging target. -pub const LOG_TARGET: &str = "staking-miner"; - -/// The election provider pallet. -pub use pallet_election_provider_multi_phase as EPM; - -/// The externalities type. -pub type Ext = sp_state_machine::TestExternalities>; - -/// The key pair type being used. We "strongly" assume sr25519 for simplicity. -pub type Pair = sp_core::sr25519::Pair; - -/// A dynamic token type used to represent account balances. -pub type Token = sub_tokens::dynamic::DynamicToken; diff --git a/polkadot/utils/staking-miner/src/rpc.rs b/polkadot/utils/staking-miner/src/rpc.rs deleted file mode 100644 index 2d25616e2a1..00000000000 --- a/polkadot/utils/staking-miner/src/rpc.rs +++ /dev/null @@ -1,182 +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 . - -//! JSON-RPC related types and helpers. - -use super::*; -use jsonrpsee::{ - core::{Error as RpcError, RpcResult}, - proc_macros::rpc, -}; -use pallet_transaction_payment::RuntimeDispatchInfo; -use sc_transaction_pool_api::TransactionStatus; -use sp_core::{storage::StorageKey, Bytes}; -use sp_version::RuntimeVersion; -use std::{future::Future, time::Duration}; - -#[derive(frame_support::DebugNoBound, thiserror::Error)] -pub(crate) enum RpcHelperError { - JsonRpsee(#[from] jsonrpsee::core::Error), - Codec(#[from] codec::Error), -} - -impl std::fmt::Display for RpcHelperError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - ::fmt(self, f) - } -} - -#[rpc(client)] -pub trait RpcApi { - /// Fetch system name. - #[method(name = "system_chain")] - async fn system_chain(&self) -> RpcResult; - - /// Fetch a storage key. - #[method(name = "state_getStorage")] - async fn storage(&self, key: &StorageKey, hash: Option) -> RpcResult>; - - /// Fetch the runtime version. - #[method(name = "state_getRuntimeVersion")] - async fn runtime_version(&self, at: Option) -> RpcResult; - - /// Fetch the payment query info. - #[method(name = "payment_queryInfo")] - async fn payment_query_info( - &self, - encoded_xt: &Bytes, - at: Option<&Hash>, - ) -> RpcResult>; - - /// Dry run an extrinsic at a given block. Return SCALE encoded - /// [`sp_runtime::ApplyExtrinsicResult`]. - #[method(name = "system_dryRun")] - async fn dry_run(&self, extrinsic: &Bytes, at: Option) -> RpcResult; - - /// Get hash of the n-th block in the canon chain. - /// - /// By default returns latest block hash. - #[method(name = "chain_getBlockHash", aliases = ["chain_getHead"], blocking)] - fn block_hash(&self, hash: Option) -> RpcResult>; - - /// Get hash of the last finalized block in the canon chain. - #[method(name = "chain_getFinalizedHead", aliases = ["chain_getFinalisedHead"], blocking)] - fn finalized_head(&self) -> RpcResult; - - /// Submit an extrinsic to watch. - /// - /// See [`TransactionStatus`](sc_transaction_pool_api::TransactionStatus) for details on - /// transaction life cycle. - #[subscription( - name = "author_submitAndWatchExtrinsic" => "author_extrinsicUpdate", - unsubscribe = "author_unwatchExtrinsic", - item = TransactionStatus - )] - fn watch_extrinsic(&self, bytes: &Bytes); - - /// New head subscription. - #[subscription( - name = "chain_subscribeNewHeads" => "newHead", - unsubscribe = "chain_unsubscribeNewHeads", - item = Header - )] - fn subscribe_new_heads(&self); - - /// Finalized head subscription. - #[subscription( - name = "chain_subscribeFinalizedHeads" => "chain_finalizedHead", - unsubscribe = "chain_unsubscribeFinalizedHeads", - item = Header - )] - fn subscribe_finalized_heads(&self); -} - -type Uri = String; - -/// Wraps a shared web-socket JSON-RPC client that can be cloned. -#[derive(Clone, Debug)] -pub(crate) struct SharedRpcClient(Arc, Uri); - -impl Deref for SharedRpcClient { - type Target = WsClient; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl SharedRpcClient { - /// Get the URI of the client. - pub fn uri(&self) -> &str { - &self.1 - } - - /// Create a new shared JSON-RPC web-socket client. - pub(crate) async fn new( - uri: &str, - connection_timeout: Duration, - request_timeout: Duration, - ) -> Result { - let client = WsClientBuilder::default() - .connection_timeout(connection_timeout) - .max_request_body_size(u32::MAX) - .request_timeout(request_timeout) - .max_concurrent_requests(u32::MAX as usize) - .build(uri) - .await?; - Ok(Self(Arc::new(client), uri.to_owned())) - } - - /// Get a storage item and decode it as `T`. - /// - /// # Return value: - /// - /// The function returns: - /// - /// * `Ok(Some(val))` if successful. - /// * `Ok(None)` if the storage item was not found. - /// * `Err(e)` if the JSON-RPC call failed. - pub(crate) async fn get_storage_and_decode<'a, T: codec::Decode>( - &self, - key: &StorageKey, - hash: Option, - ) -> Result, RpcHelperError> { - if let Some(bytes) = self.storage(key, hash).await? { - let decoded = ::decode(&mut &*bytes.0) - .map_err::(Into::into)?; - Ok(Some(decoded)) - } else { - Ok(None) - } - } -} - -/// Takes a future that returns `Bytes` and tries to decode those bytes into the type `Dec`. -/// Warning: don't use for storage, it will fail for non-existent storage items. -/// -/// # Return value: -/// -/// The function returns: -/// -/// * `Ok(val)` if successful. -/// * `Err(RpcHelperError::JsonRpsee)` if the JSON-RPC call failed. -/// * `Err(RpcHelperError::Codec)` if `Bytes` could not be decoded. -pub(crate) async fn await_request_and_decode<'a, Dec: codec::Decode>( - req: impl Future>, -) -> Result { - let bytes = req.await?; - Dec::decode(&mut &*bytes.0).map_err::(Into::into) -} diff --git a/polkadot/utils/staking-miner/src/runtime_versions.rs b/polkadot/utils/staking-miner/src/runtime_versions.rs deleted file mode 100644 index 38af05ead24..00000000000 --- a/polkadot/utils/staking-miner/src/runtime_versions.rs +++ /dev/null @@ -1,90 +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 sp_version::RuntimeVersion; -use std::fmt; - -#[derive(Debug, serde::Serialize)] -pub(crate) struct RuntimeWrapper<'a>(pub &'a RuntimeVersion); - -impl<'a> fmt::Display for RuntimeWrapper<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let width = 16; - - writeln!( - f, - r#" impl_name : {impl_name:>width$} - spec_name : {spec_name:>width$} - spec_version : {spec_version:>width$} - transaction_version : {transaction_version:>width$} - impl_version : {impl_version:>width$} - authoringVersion : {authoring_version:>width$} - state_version : {state_version:>width$}"#, - spec_name = self.0.spec_name.to_string(), - impl_name = self.0.impl_name.to_string(), - spec_version = self.0.spec_version, - impl_version = self.0.impl_version, - authoring_version = self.0.authoring_version, - transaction_version = self.0.transaction_version, - state_version = self.0.state_version, - ) - } -} - -impl<'a> From<&'a RuntimeVersion> for RuntimeWrapper<'a> { - fn from(r: &'a RuntimeVersion) -> Self { - RuntimeWrapper(r) - } -} - -#[derive(Debug, serde::Serialize)] -pub(crate) struct RuntimeVersions<'a> { - /// The `RuntimeVersion` linked in the staking-miner - pub linked: RuntimeWrapper<'a>, - - /// The `RuntimeVersion` reported by the node we connect to via RPC - pub remote: RuntimeWrapper<'a>, - - /// This `bool` reports whether both remote and linked `RuntimeVersion` are compatible - /// and if the staking-miner is expected to work properly against the remote runtime - compatible: bool, -} - -impl<'a> RuntimeVersions<'a> { - pub fn new( - remote_runtime_version: &'a RuntimeVersion, - linked_runtime_version: &'a RuntimeVersion, - ) -> Self { - Self { - remote: remote_runtime_version.into(), - linked: linked_runtime_version.into(), - compatible: are_runtimes_compatible(remote_runtime_version, linked_runtime_version), - } - } -} - -/// Check whether runtimes are compatible. Currently we only support equality. -fn are_runtimes_compatible(r1: &RuntimeVersion, r2: &RuntimeVersion) -> bool { - r1 == r2 -} - -impl<'a> fmt::Display for RuntimeVersions<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let _ = write!(f, "- linked:\n{}", self.linked); - let _ = write!(f, "- remote :\n{}", self.remote); - write!(f, "Compatible: {}", if self.compatible { "YES" } else { "NO" }) - } -} diff --git a/polkadot/utils/staking-miner/src/signer.rs b/polkadot/utils/staking-miner/src/signer.rs deleted file mode 100644 index e6677ccd3a6..00000000000 --- a/polkadot/utils/staking-miner/src/signer.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Wrappers around creating a signer account. - -use crate::{prelude::*, rpc::SharedRpcClient, AccountId, Error, Nonce, Pair, LOG_TARGET}; -use frame_system::AccountInfo; -use sp_core::{crypto::Pair as _, storage::StorageKey}; - -pub(crate) const SIGNER_ACCOUNT_WILL_EXIST: &str = - "signer account is checked to exist upon startup; it can only die if it transfers funds out \ - of it, or get slashed. If it does not exist at this point, it is likely due to a bug, or the \ - signer got slashed. Terminating."; - -/// Some information about the signer. Redundant at this point, but makes life easier. -#[derive(Clone)] -pub(crate) struct Signer { - /// The account id. - pub(crate) account: AccountId, - - /// The full crypto key-pair. - pub(crate) pair: Pair, -} - -pub(crate) async fn get_account_info + EPM::Config>( - rpc: &SharedRpcClient, - who: &T::AccountId, - maybe_at: Option, -) -> Result>, Error> { - rpc.get_storage_and_decode::>( - &StorageKey(>::hashed_key_for(&who)), - maybe_at, - ) - .await - .map_err(Into::into) -} - -/// Read the signer account's URI -pub(crate) async fn signer_uri_from_string< - T: frame_system::Config< - AccountId = AccountId, - Nonce = Nonce, - AccountData = pallet_balances::AccountData, - Hash = Hash, - > + EPM::Config, ->( - mut seed_or_path: &str, - client: &SharedRpcClient, -) -> Result> { - seed_or_path = seed_or_path.trim(); - - let seed = match std::fs::read(seed_or_path) { - Ok(s) => String::from_utf8(s).map_err(|_| Error::::AccountDoesNotExists)?, - Err(_) => seed_or_path.to_string(), - }; - let seed = seed.trim(); - - let pair = Pair::from_string(seed, None)?; - let account = T::AccountId::from(pair.public()); - let _info = get_account_info::(client, &account, None) - .await? - .ok_or(Error::::AccountDoesNotExists)?; - log::info!( - target: LOG_TARGET, - "loaded account {:?}, free: {:?}, info: {:?}", - &account, - Token::from(_info.data.free), - _info - ); - Ok(Signer { account, pair }) -} diff --git a/polkadot/utils/staking-miner/tests/cli.rs b/polkadot/utils/staking-miner/tests/cli.rs deleted file mode 100644 index 1ced1239e55..00000000000 --- a/polkadot/utils/staking-miner/tests/cli.rs +++ /dev/null @@ -1,49 +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 assert_cmd::{cargo::cargo_bin, Command}; -use serde_json::{Result, Value}; - -#[test] -fn cli_version_works() { - let crate_name = env!("CARGO_PKG_NAME"); - let output = Command::new(cargo_bin(crate_name)).arg("--version").output().unwrap(); - - assert!(output.status.success(), "command returned with non-success exit code"); - let version = String::from_utf8_lossy(&output.stdout).trim().to_owned(); - - assert_eq!(version, format!("{} {}", crate_name, env!("CARGO_PKG_VERSION"))); -} - -#[test] -fn cli_info_works() { - let crate_name = env!("CARGO_PKG_NAME"); - let output = Command::new(cargo_bin(crate_name)) - .arg("info") - .arg("--json") - .env("RUST_LOG", "none") - .output() - .unwrap(); - - assert!(output.status.success(), "command returned with non-success exit code"); - let info = String::from_utf8_lossy(&output.stdout).trim().to_owned(); - let v: Result = serde_json::from_str(&info); - let v = v.unwrap(); - assert!(!v["builtin"].to_string().is_empty()); - assert!(!v["builtin"]["spec_name"].to_string().is_empty()); - assert!(!v["builtin"]["spec_version"].to_string().is_empty()); - assert!(!v["remote"].to_string().is_empty()); -} diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index f26a6f40d42..0d751e3f9cb 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -149,7 +149,8 @@ //! while this binary lives in the Polkadot repository, this particular subcommand of it can work //! against any substrate-based chain. //! -//! See the `staking-miner` documentation in the Polkadot repository for more information. +//! See the [`staking-miner`](https://github.com/paritytech/staking-miner-v2) docs for more +//! information. //! //! ## Feasible Solution (correct solution) //! -- GitLab From 2c8021f998a4b3f3e9c0416c7886ef05803aba9d Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Mon, 11 Sep 2023 19:14:07 +0200 Subject: [PATCH 121/633] Retire puppet workers (#1449) Closes #583 After the separation of PVF worker binaries, dedicated puppet workers are not needed for tests anymore. The production workers can be used instead, avoiding some code duplication and decreasing complexity. The changes also make it possible to further refactor the code to isolate workers completely. --- Cargo.lock | 12 -- Cargo.toml | 1 - .../Cargo.toml | 15 -- .../relay-validation-worker-provider/build.rs | 169 ------------------ .../src/lib.rs | 27 --- cumulus/test/service/Cargo.toml | 1 - cumulus/test/service/src/lib.rs | 9 +- polkadot/node/core/pvf/Cargo.toml | 8 - .../node/core/pvf/common/src/worker/mod.rs | 4 + polkadot/node/core/pvf/src/lib.rs | 10 -- polkadot/node/core/pvf/src/testing.rs | 42 ----- polkadot/node/core/pvf/tests/README.md | 9 + polkadot/node/core/pvf/tests/it/main.rs | 17 +- .../node/core/pvf/tests/it/worker_common.rs | 35 ++-- .../test-parachains/adder/collator/Cargo.toml | 15 +- .../adder/collator/bin/puppet_worker.rs | 17 -- .../adder/collator/tests/integration.rs | 10 +- .../undying/collator/Cargo.toml | 19 +- .../undying/collator/bin/puppet_worker.rs | 17 -- .../undying/collator/tests/integration.rs | 10 +- 20 files changed, 71 insertions(+), 376 deletions(-) delete mode 100644 cumulus/test/relay-validation-worker-provider/Cargo.toml delete mode 100644 cumulus/test/relay-validation-worker-provider/build.rs delete mode 100644 cumulus/test/relay-validation-worker-provider/src/lib.rs create mode 100644 polkadot/node/core/pvf/tests/README.md delete mode 100644 polkadot/parachain/test-parachains/adder/collator/bin/puppet_worker.rs delete mode 100644 polkadot/parachain/test-parachains/undying/collator/bin/puppet_worker.rs diff --git a/Cargo.lock b/Cargo.lock index 3d4bc17563b..0623d96ef1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3899,14 +3899,6 @@ dependencies = [ "sp-trie", ] -[[package]] -name = "cumulus-test-relay-validation-worker-provider" -version = "0.1.0" -dependencies = [ - "polkadot-node-core-pvf", - "toml 0.7.6", -] - [[package]] name = "cumulus-test-runtime" version = "0.1.0" @@ -3958,7 +3950,6 @@ dependencies = [ "cumulus-relay-chain-minimal-node", "cumulus-test-client", "cumulus-test-relay-sproof-builder", - "cumulus-test-relay-validation-worker-provider", "cumulus-test-runtime", "frame-system", "frame-system-rpc-runtime-api", @@ -12018,7 +12009,6 @@ dependencies = [ "slotmap", "sp-core", "sp-maybe-compressed-blob", - "sp-tracing", "sp-wasm-interface", "substrate-build-script-utils", "tempfile", @@ -18462,7 +18452,6 @@ dependencies = [ "sp-keyring", "substrate-test-utils", "test-parachain-adder", - "test-parachain-adder-collator", "tokio", ] @@ -18511,7 +18500,6 @@ dependencies = [ "sp-keyring", "substrate-test-utils", "test-parachain-undying", - "test-parachain-undying-collator", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 89fb007058a..d1078e3c86a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,6 @@ members = [ "cumulus/primitives/utility", "cumulus/test/client", "cumulus/test/relay-sproof-builder", - "cumulus/test/relay-validation-worker-provider", "cumulus/test/runtime", "cumulus/test/service", "cumulus/xcm/xcm-emulator", diff --git a/cumulus/test/relay-validation-worker-provider/Cargo.toml b/cumulus/test/relay-validation-worker-provider/Cargo.toml deleted file mode 100644 index b7c59e83299..00000000000 --- a/cumulus/test/relay-validation-worker-provider/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "cumulus-test-relay-validation-worker-provider" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -build = "build.rs" -publish = false - -[dependencies] - -# Polkadot -polkadot-node-core-pvf = { path = "../../../polkadot/node/core/pvf", features = ["test-utils"] } - -[build-dependencies] -toml = "0.7.6" diff --git a/cumulus/test/relay-validation-worker-provider/build.rs b/cumulus/test/relay-validation-worker-provider/build.rs deleted file mode 100644 index 60bb950db1f..00000000000 --- a/cumulus/test/relay-validation-worker-provider/build.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use std::{ - env, fs, - path::{Path, PathBuf}, - process::{self, Command}, -}; -use toml::value::Table; - -/// The name of the project we will building. -const PROJECT_NAME: &str = "validation-worker"; -/// The env variable that instructs us to skip the build. -const SKIP_ENV: &str = "SKIP_BUILD"; - -fn main() { - if env::var(SKIP_ENV).is_ok() { - return - } - - let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo")); - - let project = create_project(&out_dir); - build_project(&project.join("Cargo.toml")); - - fs::copy(project.join("target/release").join(PROJECT_NAME), out_dir.join(PROJECT_NAME)) - .expect("Copies validation worker"); -} - -fn find_cargo_lock() -> PathBuf { - let mut path = PathBuf::from( - env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is set by cargo"), - ); - - loop { - if path.join("Cargo.lock").exists() { - return path.join("Cargo.lock") - } - - if !path.pop() { - panic!("Could not find `Cargo.lock`") - } - } -} - -fn create_project(out_dir: &Path) -> PathBuf { - let project_dir = out_dir.join(format!("{}-project", PROJECT_NAME)); - fs::create_dir_all(project_dir.join("src")).expect("Creates project dir and project src dir"); - - let mut project_toml = Table::new(); - - let mut package = Table::new(); - package.insert("name".into(), PROJECT_NAME.into()); - package.insert("version".into(), "1.0.0".into()); - package.insert("edition".into(), "2021".into()); - - project_toml.insert("package".into(), package.into()); - - project_toml.insert("workspace".into(), Table::new().into()); - - let mut dependencies = Table::new(); - - let mut dependency_project = Table::new(); - dependency_project.insert( - "path".into(), - env::var("CARGO_MANIFEST_DIR") - .expect("`CARGO_MANIFEST_DIR` is set by cargo") - .into(), - ); - - dependencies - .insert("cumulus-test-relay-validation-worker-provider".into(), dependency_project.into()); - - project_toml.insert("dependencies".into(), dependencies.into()); - - add_patches(&mut project_toml); - - fs::write( - project_dir.join("Cargo.toml"), - toml::to_string_pretty(&project_toml).expect("Wasm workspace toml is valid; qed"), - ) - .expect("Writes project `Cargo.toml`"); - - fs::write( - project_dir.join("src").join("main.rs"), - r#" - cumulus_test_relay_validation_worker_provider::polkadot_node_core_pvf::decl_puppet_worker_main!(); - "#, - ) - .expect("Writes `main.rs`"); - - let cargo_lock = find_cargo_lock(); - fs::copy(&cargo_lock, project_dir.join("Cargo.lock")).expect("Copies `Cargo.lock`"); - println!("cargo:rerun-if-changed={}", cargo_lock.display()); - - project_dir -} - -fn add_patches(project_toml: &mut Table) { - let workspace_toml_path = PathBuf::from( - env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is set by cargo"), - ) - .join("../../../Cargo.toml"); - - let mut workspace_toml: Table = toml::from_str( - &fs::read_to_string(&workspace_toml_path).expect("Workspace root `Cargo.toml` exists; qed"), - ) - .expect("Workspace root `Cargo.toml` is a valid toml file; qed"); - - let mut workspace_path = workspace_toml_path; - workspace_path.pop(); - - while let Some(mut patch) = - workspace_toml.remove("patch").and_then(|p| p.try_into::
().ok()) - { - // Iterate over all patches and make the patch path absolute from the workspace root path. - patch - .iter_mut() - .filter_map(|p| { - p.1.as_table_mut().map(|t| t.iter_mut().filter_map(|t| t.1.as_table_mut())) - }) - .flatten() - .for_each(|p| { - p.iter_mut().filter(|(k, _)| k == &"path").for_each(|(_, v)| { - if let Some(path) = v.as_str().map(PathBuf::from) { - if path.is_relative() { - *v = workspace_path.join(path).display().to_string().into(); - } - } - }) - }); - - project_toml.insert("patch".into(), patch.into()); - } -} - -fn build_project(cargo_toml: &Path) { - let cargo = env::var("CARGO").expect("`CARGO` env variable is always set by cargo"); - - let status = Command::new(cargo) - .arg("build") - .arg("--release") - .arg(format!("--manifest-path={}", cargo_toml.display())) - // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir - // exclusive). - .env_remove("CARGO_TARGET_DIR") - // Do not call us recursively. - .env(SKIP_ENV, "1") - .status(); - - match status.map(|s| s.success()) { - Ok(true) => {}, - // Use `process.exit(1)` to have a clean error output. - _ => process::exit(1), - } -} diff --git a/cumulus/test/relay-validation-worker-provider/src/lib.rs b/cumulus/test/relay-validation-worker-provider/src/lib.rs deleted file mode 100644 index 6c3f4182b03..00000000000 --- a/cumulus/test/relay-validation-worker-provider/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Provides the [`VALIDATION_WORKER`] for integration tests in Cumulus. -//! -//! The validation worker is used by the relay chain to validate parachains. This worker is placed -//! in an extra process to provide better security and to ensure that a worker can be killed etc. -//! -//! !!This should only be used for tests!! - -pub use polkadot_node_core_pvf; - -/// The path to the validation worker. -pub const VALIDATION_WORKER: &str = concat!(env!("OUT_DIR"), "/validation-worker"); diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 04d53545ead..c65eb0dd024 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -72,7 +72,6 @@ cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-relay-chain-inprocess-interface = { path = "../../client/relay-chain-inprocess-interface" } cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" } -cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } cumulus-test-runtime = { path = "../runtime" } cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-node" } cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 3275aabc4d8..a721645546a 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -903,8 +903,9 @@ pub fn run_relay_chain_validator_node( config.rpc_addr = Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port)); } - polkadot_test_service::run_validator_node( - config, - Some(cumulus_test_relay_validation_worker_provider::VALIDATION_WORKER.into()), - ) + let mut workers_path = std::env::current_exe().unwrap(); + workers_path.pop(); + workers_path.pop(); + + polkadot_test_service::run_validator_node(config, Some(workers_path)) } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index ad9120295d2..478d1952d9d 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -6,11 +6,6 @@ authors.workspace = true edition.workspace = true license.workspace = true -[[bin]] -name = "puppet_worker" -path = "bin/puppet_worker.rs" -required-features = ["test-utils"] - [dependencies] always-assert = "0.1" futures = "0.3.21" @@ -35,7 +30,6 @@ polkadot-primitives = { path = "../../../primitives" } sp-core = { path = "../../../../substrate/primitives/core" } sp-wasm-interface = { path = "../../../../substrate/primitives/wasm-interface" } sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob" } -sp-tracing = { path = "../../../../substrate/primitives/tracing", optional = true } polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker", optional = true } polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = true } @@ -56,9 +50,7 @@ halt = { package = "test-parachain-halt", path = "../../../parachain/test-parach ci-only-tests = [] jemalloc-allocator = [ "polkadot-node-core-pvf-common/jemalloc-allocator" ] # This feature is used to export test code to other crates without putting it in the production build. -# This is also used by the `puppet_worker` binary. test-utils = [ "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", - "sp-tracing", ] diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index 40e540bb3f7..a3f8e777c48 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -60,6 +60,10 @@ macro_rules! decl_worker_main { println!("{}", $worker_version); return }, + "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 { diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index c3a7a461313..0e4f2444adf 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -100,10 +100,6 @@ mod worker_intf; #[cfg(feature = "test-utils")] pub mod testing; -// Used by `decl_puppet_worker_main!`. -#[cfg(feature = "test-utils")] -pub use sp_tracing; - pub use error::{InvalidCandidate, ValidationError}; pub use host::{start, Config, ValidationHost, EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}; pub use metrics::Metrics; @@ -117,11 +113,5 @@ pub use polkadot_node_core_pvf_common::{ pvf::PvfPrepData, }; -// Re-export worker entrypoints. -#[cfg(feature = "test-utils")] -pub use polkadot_node_core_pvf_execute_worker::worker_entrypoint as execute_worker_entrypoint; -#[cfg(feature = "test-utils")] -pub use polkadot_node_core_pvf_prepare_worker::worker_entrypoint as prepare_worker_entrypoint; - /// The log target for this crate. pub const LOG_TARGET: &str = "parachain::pvf"; diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 980a28c0156..4301afc3cc7 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -47,45 +47,3 @@ pub fn validate_candidate( Ok(result) } - -/// Use this macro to declare a `fn main() {}` that will check the arguments and dispatch them to -/// the appropriate worker, making the executable that can be used for spawning workers. -#[macro_export] -macro_rules! decl_puppet_worker_main { - () => { - fn main() { - $crate::sp_tracing::try_init_simple(); - - let args = std::env::args().collect::>(); - if args.len() == 1 { - panic!("wrong number of arguments"); - } - - let entrypoint = match args[1].as_ref() { - "exit" => { - std::process::exit(1); - }, - "sleep" => { - std::thread::sleep(std::time::Duration::from_secs(5)); - return - }, - "prepare-worker" => $crate::prepare_worker_entrypoint, - "execute-worker" => $crate::execute_worker_entrypoint, - other => panic!("unknown subcommand: {}", other), - }; - - let mut node_version = None; - let mut socket_path: &str = ""; - - for i in (2..args.len()).step_by(2) { - 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()), - arg => panic!("Unexpected argument found: {}", arg), - } - } - - entrypoint(&socket_path, node_version, None); - } - }; -} diff --git a/polkadot/node/core/pvf/tests/README.md b/polkadot/node/core/pvf/tests/README.md new file mode 100644 index 00000000000..27385e19025 --- /dev/null +++ b/polkadot/node/core/pvf/tests/README.md @@ -0,0 +1,9 @@ +# PVF host integration tests + +## Testing + +Before running these tests, make sure the worker binaries are built first. This can be done with: + +```sh +cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker +``` diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 12d87ee4426..dc8f00098ec 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -33,7 +33,6 @@ use tokio::sync::Mutex; mod adder; mod worker_common; -const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_puppet_worker"); const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(3); @@ -51,10 +50,20 @@ impl TestHost { where F: FnOnce(&mut Config), { + let mut workers_path = std::env::current_exe().unwrap(); + workers_path.pop(); + workers_path.pop(); + let mut prepare_worker_path = workers_path.clone(); + prepare_worker_path.push("polkadot-prepare-worker"); + let mut execute_worker_path = workers_path.clone(); + execute_worker_path.push("polkadot-execute-worker"); let cache_dir = tempfile::tempdir().unwrap(); - let program_path = std::path::PathBuf::from(PUPPET_EXE); - let mut config = - Config::new(cache_dir.path().to_owned(), None, program_path.clone(), program_path); + let mut config = Config::new( + cache_dir.path().to_owned(), + None, + prepare_worker_path, + execute_worker_path, + ); f(&mut config); let (host, task) = start(config, Metrics::default()); let _ = tokio::task::spawn(task); diff --git a/polkadot/node/core/pvf/tests/it/worker_common.rs b/polkadot/node/core/pvf/tests/it/worker_common.rs index a3bf552e894..875ae79af09 100644 --- a/polkadot/node/core/pvf/tests/it/worker_common.rs +++ b/polkadot/node/core/pvf/tests/it/worker_common.rs @@ -14,26 +14,41 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::time::Duration; - use polkadot_node_core_pvf::testing::{spawn_with_program_path, SpawnErr}; +use std::time::Duration; -use crate::PUPPET_EXE; +fn worker_path(name: &str) -> std::path::PathBuf { + let mut worker_path = std::env::current_exe().unwrap(); + worker_path.pop(); + worker_path.pop(); + worker_path.push(name); + worker_path +} // Test spawning a program that immediately exits with a failure code. #[tokio::test] async fn spawn_immediate_exit() { - let result = - spawn_with_program_path("integration-test", PUPPET_EXE, &["exit"], Duration::from_secs(2)) - .await; + // There's no explicit `exit` subcommand in the worker; it will panic on an unknown + // subcommand anyway + let result = spawn_with_program_path( + "integration-test", + worker_path("polkadot-prepare-worker"), + &["exit"], + Duration::from_secs(2), + ) + .await; assert!(matches!(result, Err(SpawnErr::AcceptTimeout))); } #[tokio::test] async fn spawn_timeout() { - let result = - spawn_with_program_path("integration-test", PUPPET_EXE, &["sleep"], Duration::from_secs(2)) - .await; + let result = spawn_with_program_path( + "integration-test", + worker_path("polkadot-execute-worker"), + &["test-sleep"], + Duration::from_secs(2), + ) + .await; assert!(matches!(result, Err(SpawnErr::AcceptTimeout))); } @@ -41,7 +56,7 @@ async fn spawn_timeout() { async fn should_connect() { let _ = spawn_with_program_path( "integration-test", - PUPPET_EXE, + worker_path("polkadot-prepare-worker"), &["prepare-worker"], Duration::from_secs(2), ) diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 7079ab73270..5c93d716528 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -11,11 +11,6 @@ license.workspace = true name = "adder-collator" path = "src/main.rs" -[[bin]] -name = "adder_collator_puppet_worker" -path = "bin/puppet_worker.rs" -required-features = ["test-utils"] - [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.4.2", features = ["derive"] } @@ -33,25 +28,17 @@ polkadot-node-subsystem = { path = "../../../../node/subsystem" } sc-cli = { path = "../../../../../substrate/client/cli" } sp-core = { path = "../../../../../substrate/primitives/core" } sc-service = { path = "../../../../../substrate/client/service" } -# This one is tricky. Even though it is not used directly by the collator, we still need it for the -# `puppet_worker` binary, which is required for the integration test. However, this shouldn't be -# a big problem since it is used transitively anyway. -polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] polkadot-parachain-primitives = { path = "../../.." } polkadot-test-service = { path = "../../../../node/test/service" } +polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"] } substrate-test-utils = { path = "../../../../../substrate/test-utils" } sc-service = { path = "../../../../../substrate/client/service" } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } -# For the puppet worker, depend on ourselves with the test-utils feature. -test-parachain-adder-collator = { path = "", features = ["test-utils"] } tokio = { version = "1.24.2", features = ["macros"] } [features] network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] -# This feature is used to export test code to other crates without putting it in the production build. -# This is also used by the `puppet_worker` binary. -test-utils = [ "polkadot-node-core-pvf/test-utils" ] diff --git a/polkadot/parachain/test-parachains/adder/collator/bin/puppet_worker.rs b/polkadot/parachain/test-parachains/adder/collator/bin/puppet_worker.rs deleted file mode 100644 index 7f93519d845..00000000000 --- a/polkadot/parachain/test-parachains/adder/collator/bin/puppet_worker.rs +++ /dev/null @@ -1,17 +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 . - -polkadot_node_core_pvf::decl_puppet_worker_main!(); diff --git a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs index 6b481f961a4..85abf8bf36b 100644 --- a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs @@ -17,8 +17,6 @@ //! Integration test that ensures that we can build and include parachain //! blocks of the adder parachain. -const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_adder_collator_puppet_worker"); - // If this test is failing, make sure to run all tests with the `real-overseer` feature being // enabled. @@ -41,8 +39,12 @@ async fn collating_using_adder_collator() { true, ); + let mut workers_path = std::env::current_exe().unwrap(); + workers_path.pop(); + workers_path.pop(); + // start alice - let alice = polkadot_test_service::run_validator_node(alice_config, Some(PUPPET_EXE.into())); + let alice = polkadot_test_service::run_validator_node(alice_config, Some(workers_path.clone())); let bob_config = polkadot_test_service::node_config( || {}, @@ -53,7 +55,7 @@ async fn collating_using_adder_collator() { ); // start bob - let bob = polkadot_test_service::run_validator_node(bob_config, Some(PUPPET_EXE.into())); + let bob = polkadot_test_service::run_validator_node(bob_config, Some(workers_path)); let collator = test_parachain_adder_collator::Collator::new(); diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 0f1fd60a900..9cdacbc5657 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -11,15 +11,10 @@ publish = false name = "undying-collator" path = "src/main.rs" -[[bin]] -name = "undying_collator_puppet_worker" -path = "bin/puppet_worker.rs" -required-features = ["test-utils"] - [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.4.2", features = ["derive"] } -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" @@ -33,24 +28,14 @@ polkadot-node-subsystem = { path = "../../../../node/subsystem" } sc-cli = { path = "../../../../../substrate/client/cli" } sp-core = { path = "../../../../../substrate/primitives/core" } sc-service = { path = "../../../../../substrate/client/service" } -# This one is tricky. Even though it is not used directly by the collator, we still need it for the -# `puppet_worker` binary, which is required for the integration test. However, this shouldn't be -# a big problem since it is used transitively anyway. -polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] polkadot-parachain-primitives = { path = "../../.." } polkadot-test-service = { path = "../../../../node/test/service" } -# For the puppet worker, depend on ourselves with the test-utils feature. -test-parachain-undying-collator = { path = "", features = ["test-utils"] } +polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"] } substrate-test-utils = { path = "../../../../../substrate/test-utils" } sc-service = { path = "../../../../../substrate/client/service" } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } tokio = { version = "1.24.2", features = ["macros"] } - -[features] -# This feature is used to export test code to other crates without putting it in the production build. -# This is also used by the `puppet_worker` binary. -test-utils = [ "polkadot-node-core-pvf/test-utils" ] diff --git a/polkadot/parachain/test-parachains/undying/collator/bin/puppet_worker.rs b/polkadot/parachain/test-parachains/undying/collator/bin/puppet_worker.rs deleted file mode 100644 index 7f93519d845..00000000000 --- a/polkadot/parachain/test-parachains/undying/collator/bin/puppet_worker.rs +++ /dev/null @@ -1,17 +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 . - -polkadot_node_core_pvf::decl_puppet_worker_main!(); diff --git a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs index a98a7ff6eef..8be535b9bb4 100644 --- a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs @@ -17,8 +17,6 @@ //! Integration test that ensures that we can build and include parachain //! blocks of the `Undying` parachain. -const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_undying_collator_puppet_worker"); - // If this test is failing, make sure to run all tests with the `real-overseer` feature being // enabled. #[tokio::test(flavor = "multi_thread")] @@ -40,8 +38,12 @@ async fn collating_using_undying_collator() { true, ); + let mut workers_path = std::env::current_exe().unwrap(); + workers_path.pop(); + workers_path.pop(); + // start alice - let alice = polkadot_test_service::run_validator_node(alice_config, Some(PUPPET_EXE.into())); + let alice = polkadot_test_service::run_validator_node(alice_config, Some(workers_path.clone())); let bob_config = polkadot_test_service::node_config( || {}, @@ -52,7 +54,7 @@ async fn collating_using_undying_collator() { ); // start bob - let bob = polkadot_test_service::run_validator_node(bob_config, Some(PUPPET_EXE.into())); + let bob = polkadot_test_service::run_validator_node(bob_config, Some(workers_path)); let collator = test_parachain_undying_collator::Collator::new(1_000, 1); -- GitLab From 44dbb73945a20fa16ed004d50827c63c0921cbd0 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 11 Sep 2023 19:33:51 +0100 Subject: [PATCH 122/633] Allow to broadcast network messages in parallel (#1409) This PR addresses multiple issues pending: * [x] Update orchestra to the recent version and test how the node performs * [x] Add some useful metrics for outbound network bridge * [x] Try to send incoming network requests to all subsystems without blocking on some particular subsystem in that loop * [x] Fix all incompatibilities between orchestra and polkadot code (e.g. malus node) --- Cargo.lock | 41 +++++------ .../Cargo.toml | 2 +- polkadot/node/malus/src/interceptor.rs | 62 ++++++++++++++--- polkadot/node/malus/src/variants/common.rs | 7 -- polkadot/node/metrics/Cargo.toml | 3 +- polkadot/node/network/bridge/src/metrics.rs | 53 ++++++++++++++ polkadot/node/network/bridge/src/network.rs | 1 + polkadot/node/network/bridge/src/rx/mod.rs | 69 ++++++++++++++++--- polkadot/node/network/bridge/src/tx/mod.rs | 15 ++++ polkadot/node/overseer/Cargo.toml | 9 +-- polkadot/node/overseer/src/lib.rs | 2 +- polkadot/node/overseer/src/tests.rs | 1 + .../node/subsystem-test-helpers/src/lib.rs | 10 ++- polkadot/node/subsystem-types/Cargo.toml | 2 +- polkadot/node/subsystem-util/Cargo.toml | 2 +- 15 files changed, 223 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0623d96ef1c..686ee62add3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4841,18 +4841,6 @@ dependencies = [ "quote", ] -[[package]] -name = "expander" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" -dependencies = [ - "blake2", - "fs-err", - "proc-macro2", - "quote", -] - [[package]] name = "expander" version = "2.0.0" @@ -6896,6 +6884,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "layout-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1164ef87cb9607c2d887216eca79f0fc92895affe1789bba805dd38d829584e0" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -8692,9 +8689,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "orchestra" -version = "0.0.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" +checksum = "46d78e1deb2a8d54fc1f063a544130db4da31dfe4d5d3b493186424910222a76" dependencies = [ "async-trait", "dyn-clonable", @@ -8709,12 +8706,16 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.0.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" +checksum = "d035b1f968d91a826f2e34a9d6d02cb2af5aa7ca39ebd27922d850ab4b2dd2c6" dependencies = [ - "expander 0.0.6", - "itertools 0.10.5", + "anyhow", + "expander 2.0.0", + "fs-err", + "indexmap 2.0.0", + "itertools 0.11.0", + "layout-rs", "petgraph", "proc-macro-crate", "proc-macro2", @@ -13310,9 +13311,9 @@ dependencies = [ [[package]] name = "prioritized-metered-channel" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4" +checksum = "e99f0c89bd88f393aab44a4ab949351f7bc7e7e1179d11ecbfe50cbe4c47e342" dependencies = [ "coarsetime", "crossbeam-queue", diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index c198b22cad4..39eda5075e2 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -37,7 +37,7 @@ sp-keyring = { path = "../../../substrate/primitives/keyring" } # Polkadot polkadot-primitives = { path = "../../../polkadot/primitives" } polkadot-test-client = { path = "../../../polkadot/node/test/client" } -metered = { package = "prioritized-metered-channel", version = "0.2.0" } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } # Cumulus cumulus-test-service = { path = "../../test/service" } diff --git a/polkadot/node/malus/src/interceptor.rs b/polkadot/node/malus/src/interceptor.rs index cbf39bccd16..04ee0905dee 100644 --- a/polkadot/node/malus/src/interceptor.rs +++ b/polkadot/node/malus/src/interceptor.rs @@ -47,12 +47,20 @@ where Some(msg) } - /// Modify outgoing messages. + /// Specifies if we need to replace some outgoing message with another (potentially empty) + /// message + fn need_intercept_outgoing( + &self, + _msg: &::OutgoingMessages, + ) -> bool { + false + } + /// Send modified message instead of the original one fn intercept_outgoing( &self, - msg: ::OutgoingMessages, + _msg: &::OutgoingMessages, ) -> Option<::OutgoingMessages> { - Some(msg) + None } } @@ -66,7 +74,7 @@ pub struct InterceptedSender { #[async_trait::async_trait] impl overseer::SubsystemSender for InterceptedSender where - OutgoingMessage: overseer::AssociateOutgoing + Send + 'static, + OutgoingMessage: overseer::AssociateOutgoing + Send + 'static + TryFrom, Sender: overseer::SubsystemSender + overseer::SubsystemSender< < @@ -78,17 +86,48 @@ where < >::Message as overseer::AssociateOutgoing >::OutgoingMessages: - From, + From + Send + Sync, + >::Error: std::fmt::Debug, { async fn send_message(&mut self, msg: OutgoingMessage) { let msg = < <>::Message as overseer::AssociateOutgoing >::OutgoingMessages as From>::from(msg); - if let Some(msg) = self.message_filter.intercept_outgoing(msg) { + if self.message_filter.need_intercept_outgoing(&msg) { + if let Some(msg) = self.message_filter.intercept_outgoing(&msg) { + self.inner.send_message(msg).await; + } + } + else { self.inner.send_message(msg).await; } } + fn try_send_message(&mut self, msg: OutgoingMessage) -> Result<(), TrySendError> { + let msg = < + <>::Message as overseer::AssociateOutgoing + >::OutgoingMessages as From>::from(msg); + if self.message_filter.need_intercept_outgoing(&msg) { + if let Some(real_msg) = self.message_filter.intercept_outgoing(&msg) { + let orig_msg : OutgoingMessage = msg.into().try_into().expect("must be able to recover the original message"); + self.inner.try_send_message(real_msg).map_err(|e| { + match e { + TrySendError::Full(_) => TrySendError::Full(orig_msg), + TrySendError::Closed(_) => TrySendError::Closed(orig_msg), + } + }) + } + else { + // No message to send after intercepting + Ok(()) + } + } + else { + let orig_msg : OutgoingMessage = msg.into().try_into().expect("must be able to recover the original message"); + self.inner.try_send_message(orig_msg) + } + } + async fn send_messages(&mut self, msgs: T) where T: IntoIterator + Send, @@ -101,9 +140,14 @@ where fn send_unbounded_message(&mut self, msg: OutgoingMessage) { let msg = < - <>::Message as overseer::AssociateOutgoing - >::OutgoingMessages as From>::from(msg); - if let Some(msg) = self.message_filter.intercept_outgoing(msg) { + <>::Message as overseer::AssociateOutgoing + >::OutgoingMessages as From>::from(msg); + if self.message_filter.need_intercept_outgoing(&msg) { + if let Some(msg) = self.message_filter.intercept_outgoing(&msg) { + self.inner.send_unbounded_message(msg); + } + } + else { self.inner.send_unbounded_message(msg); } } diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index bc5f6f92aed..365b2f16ac2 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -498,11 +498,4 @@ where msg => Some(msg), } } - - fn intercept_outgoing( - &self, - msg: overseer::CandidateValidationOutgoingMessages, - ) -> Option { - Some(msg) - } } diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index d497fa7607a..e13ae63199f 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -11,8 +11,7 @@ futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } -metered = { package = "prioritized-metered-channel", version = "0.2.0" } - +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } # Both `sc-service` and `sc-cli` are required by runtime metrics `logger_hook()`. sc-service = { path = "../../../substrate/client/service" } sc-cli = { path = "../../../substrate/client/cli" } diff --git a/polkadot/node/network/bridge/src/metrics.rs b/polkadot/node/network/bridge/src/metrics.rs index bb90daad567..083a2a71aa0 100644 --- a/polkadot/node/network/bridge/src/metrics.rs +++ b/polkadot/node/network/bridge/src/metrics.rs @@ -105,9 +105,27 @@ impl Metrics { pub fn on_report_event(&self) { if let Some(metrics) = self.0.as_ref() { + self.on_message("report_peer"); metrics.report_events.inc() } } + + pub fn on_message(&self, message_type: &'static str) { + if let Some(metrics) = self.0.as_ref() { + metrics.messages_sent.with_label_values(&[message_type]).inc() + } + } + + pub fn on_delayed_rx_queue(&self, queue_size: usize) { + if let Some(metrics) = self.0.as_ref() { + metrics.rx_delayed_processing.observe(queue_size as f64); + } + } + pub fn time_delayed_rx_events( + &self, + ) -> Option { + self.0.as_ref().map(|metrics| metrics.rx_delayed_processing_time.start_timer()) + } } #[derive(Clone)] @@ -123,6 +141,13 @@ pub(crate) struct MetricsInner { bytes_received: prometheus::CounterVec, bytes_sent: prometheus::CounterVec, + + messages_sent: prometheus::CounterVec, + // The reason why a `Histogram` is used to track a queue size is that + // we need not only an average size of the queue (that will be 0 normally), but + // we also need a dynamics for this queue size in case of messages delays. + rx_delayed_processing: prometheus::Histogram, + rx_delayed_processing_time: prometheus::Histogram, } impl metrics::Metrics for Metrics { @@ -217,6 +242,34 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + messages_sent: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_parachain_messages_sent_total", + "The number of messages sent via network bridge", + ), + &["type"] + )?, + registry, + )?, + rx_delayed_processing: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_network_bridge_rx_delayed", + "Number of events being delayed while broadcasting from the network bridge", + ).buckets(vec![0.0, 1.0, 2.0, 8.0, 16.0]), + )?, + registry, + )?, + rx_delayed_processing_time: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_network_bridge_rx_delayed_time", + "Time spent for waiting of the delayed events", + ), + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index 4f21212dcb6..823e1254612 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -61,6 +61,7 @@ pub(crate) fn send_message( let message = { let encoded = message.encode(); metrics.on_notification_sent(peer_set, version, encoded.len(), peers.len()); + metrics.on_message(std::any::type_name::()); encoded }; diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 51d248ca2d4..e1125ebc904 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -20,7 +20,10 @@ use super::*; use always_assert::never; use bytes::Bytes; -use futures::stream::BoxStream; +use futures::{ + future::BoxFuture, + stream::{BoxStream, FuturesUnordered, StreamExt}, +}; use parity_scale_codec::{Decode, DecodeAll}; use sc_network::Event as NetworkEvent; @@ -244,6 +247,7 @@ where NetworkBridgeEvent::PeerViewChange(peer, View::default()), ], &mut sender, + &metrics, ) .await; @@ -352,6 +356,7 @@ where dispatch_validation_event_to_all( NetworkBridgeEvent::PeerDisconnected(peer), &mut sender, + &metrics, ) .await, PeerSet::Collation => @@ -490,7 +495,7 @@ where network_service.report_peer(remote, report.into()); } - dispatch_validation_events_to_all(events, &mut sender).await; + dispatch_validation_events_to_all(events, &mut sender, &metrics).await; } if !c_messages.is_empty() { @@ -992,8 +997,9 @@ fn send_collation_message_vstaging( async fn dispatch_validation_event_to_all( event: NetworkBridgeEvent, ctx: &mut impl overseer::NetworkBridgeRxSenderTrait, + metrics: &Metrics, ) { - dispatch_validation_events_to_all(std::iter::once(event), ctx).await + dispatch_validation_events_to_all(std::iter::once(event), ctx, metrics).await } async fn dispatch_collation_event_to_all( @@ -1038,20 +1044,65 @@ fn dispatch_collation_event_to_all_unbounded( } } +fn send_or_queue_validation_event( + event: E, + sender: &mut Sender, + delayed_queue: &FuturesUnordered>, +) where + E: Send + 'static, + Sender: overseer::NetworkBridgeRxSenderTrait + overseer::SubsystemSender, +{ + match sender.try_send_message(event) { + Ok(()) => {}, + Err(overseer::TrySendError::Full(event)) => { + let mut sender = sender.clone(); + delayed_queue.push(Box::pin(async move { + sender.send_message(event).await; + })); + }, + Err(overseer::TrySendError::Closed(_)) => { + panic!( + "NetworkBridgeRxSender is closed when trying to send event of type: {}", + std::any::type_name::() + ); + }, + } +} + async fn dispatch_validation_events_to_all( events: I, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + metrics: &Metrics, ) where I: IntoIterator>, I::IntoIter: Send, { + let delayed_messages: FuturesUnordered> = FuturesUnordered::new(); + + // Fast path for sending events to subsystems, if any subsystem's queue is full, we hold + // the slow path future in the `delayed_messages` queue. for event in events { - sender - .send_messages(event.focus().map(StatementDistributionMessage::from)) - .await; - sender.send_messages(event.focus().map(BitfieldDistributionMessage::from)).await; - sender.send_messages(event.focus().map(ApprovalDistributionMessage::from)).await; - sender.send_messages(event.focus().map(GossipSupportMessage::from)).await; + if let Ok(msg) = event.focus().map(StatementDistributionMessage::from) { + send_or_queue_validation_event(msg, sender, &delayed_messages); + } + if let Ok(msg) = event.focus().map(BitfieldDistributionMessage::from) { + send_or_queue_validation_event(msg, sender, &delayed_messages); + } + if let Ok(msg) = event.focus().map(ApprovalDistributionMessage::from) { + send_or_queue_validation_event(msg, sender, &delayed_messages); + } + if let Ok(msg) = event.focus().map(GossipSupportMessage::from) { + send_or_queue_validation_event(msg, sender, &delayed_messages); + } + } + + let delayed_messages_count = delayed_messages.len(); + metrics.on_delayed_rx_queue(delayed_messages_count); + + if delayed_messages_count > 0 { + // Here we wait for all the delayed messages to be sent. + let _timer = metrics.time_delayed_rx_events(); // Dropped after `await` is completed + let _: Vec<()> = delayed_messages.collect().await; } } diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 1b386ce1239..7fa1149593c 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -33,6 +33,7 @@ use polkadot_node_subsystem::{ /// /// To be passed to [`FullNetworkConfiguration::add_notification_protocol`](). pub use polkadot_node_network_protocol::peer_set::{peer_sets_info, IsAuthority}; +use polkadot_node_network_protocol::request_response::Requests; use sc_network::ReputationChange; use crate::validator_discovery; @@ -290,6 +291,20 @@ where ); for req in reqs { + match req { + Requests::ChunkFetchingV1(_) => metrics.on_message("chunk_fetching_v1"), + 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::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"), + } + network_service .start_request( &mut authority_discovery_service, diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 0efd4d4c6ca..5d41407ef83 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -16,7 +16,7 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-node-subsystem-types = { path = "../subsystem-types" } polkadot-node-metrics = { path = "../metrics" } polkadot-primitives = { path = "../../primitives" } -orchestra = "0.0.5" +orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } gum = { package = "tracing-gum", path = "../gum" } schnellru = "0.2.1" sp-core = { path = "../../../substrate/primitives/core" } @@ -24,7 +24,7 @@ async-trait = "0.1.57" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } [dev-dependencies] -metered = { package = "prioritized-metered-channel", version = "0.2.0" } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } futures = { version = "0.3.21", features = ["thread-pool"] } femme = "2.2.1" @@ -36,7 +36,8 @@ node-test-helpers = { package = "polkadot-node-subsystem-test-helpers", path = " tikv-jemalloc-ctl = "0.5.0" [features] -default = [] -expand = [ "orchestra/expand" ] +default = [ "futures_channel" ] dotgraph = [ "orchestra/dotgraph" ] +expand = [ "orchestra/expand" ] +futures_channel = [ "metered/futures_channel", "orchestra/futures_channel" ] jemalloc-allocator = [ "dep:tikv-jemalloc-ctl" ] diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 7337f1e6be7..84d5d19c3b9 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -107,7 +107,7 @@ pub use orchestra::{ contextbounds, orchestra, subsystem, FromOrchestra, MapSubsystem, MessagePacket, OrchestraError as OverseerError, SignalsReceived, Spawner, Subsystem, SubsystemContext, SubsystemIncomingMessages, SubsystemInstance, SubsystemMeterReadouts, SubsystemMeters, - SubsystemSender, TimeoutExt, ToOrchestra, + SubsystemSender, TimeoutExt, ToOrchestra, TrySendError, }; /// Store 2 days worth of blocks, not accounting for forks, diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 298783f4180..c17613fb7ea 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -1074,6 +1074,7 @@ fn overseer_all_subsystems_receive_signals_and_messages() { #[test] fn context_holds_onto_message_until_enough_signals_received() { + const CHANNEL_CAPACITY: usize = 64; let (candidate_validation_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (candidate_backing_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (statement_distribution_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs index fe6b106bf46..3f92513498c 100644 --- a/polkadot/node/subsystem-test-helpers/src/lib.rs +++ b/polkadot/node/subsystem-test-helpers/src/lib.rs @@ -20,7 +20,7 @@ use polkadot_node_subsystem::{ messages::AllMessages, overseer, FromOrchestra, OverseerSignal, SpawnGlue, SpawnedSubsystem, - SubsystemError, SubsystemResult, + SubsystemError, SubsystemResult, TrySendError, }; use polkadot_node_subsystem_util::TimeoutExt; @@ -160,6 +160,14 @@ where self.tx.send(msg.into()).await.expect("test overseer no longer live"); } + fn try_send_message( + &mut self, + msg: OutgoingMessage, + ) -> Result<(), TrySendError> { + self.tx.unbounded_send(msg.into()).expect("test overseer no longer live"); + Ok(()) + } + async fn send_messages(&mut self, msgs: I) where I: IntoIterator + Send, diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index f6965cf647c..a1c00cb0652 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -14,7 +14,7 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-statement-table = { path = "../../statement-table" } polkadot-node-jaeger = { path = "../jaeger" } -orchestra = "0.0.5" +orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } sc-network = { path = "../../../substrate/client/network" } sp-api = { path = "../../../substrate/primitives/api" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 0d5ae7a0e8e..d9364e2c2c0 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -29,7 +29,7 @@ polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } polkadot-overseer = { path = "../overseer" } -metered = { package = "prioritized-metered-channel", version = "0.2.0" } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } -- GitLab From c879d1d5827f1fa4f72621ce185fa08ac3ea8d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 11 Sep 2023 22:45:18 +0200 Subject: [PATCH 123/633] contracts: Run start function (#1367) Fixes #116 Start function wasn't allowed in a contract. Now it is allowed and is being run. It was disallowed because it is not used by Rust and supporting it made the code more complex. However, not running the start function violates the wasm standard. This makes life harder for some languages (see linked ticket). --- .../fixtures/run_out_of_gas_start_fn.wat | 10 + .../contracts/src/benchmarking/sandbox.rs | 8 +- substrate/frame/contracts/src/exec.rs | 111 ++++----- substrate/frame/contracts/src/lib.rs | 8 +- substrate/frame/contracts/src/tests.rs | 21 ++ substrate/frame/contracts/src/wasm/mod.rs | 212 +++++++++--------- 6 files changed, 198 insertions(+), 172 deletions(-) create mode 100644 substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat diff --git a/substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat b/substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat new file mode 100644 index 00000000000..6591d7ede78 --- /dev/null +++ b/substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat @@ -0,0 +1,10 @@ +(module + (import "env" "memory" (memory 1 1)) + (start $start) + (func $start + (loop $inf (br $inf)) ;; just run out of gas + (unreachable) + ) + (func (export "call")) + (func (export "deploy")) +) diff --git a/substrate/frame/contracts/src/benchmarking/sandbox.rs b/substrate/frame/contracts/src/benchmarking/sandbox.rs index 34974b02ea0..c3abbcad5f2 100644 --- a/substrate/frame/contracts/src/benchmarking/sandbox.rs +++ b/substrate/frame/contracts/src/benchmarking/sandbox.rs @@ -58,7 +58,13 @@ impl From<&WasmModule> for Sandbox { .add_fuel(u64::MAX) .expect("We've set up engine to fuel consuming mode; qed"); - let entry_point = instance.get_export(&store, "call").unwrap().into_func().unwrap(); + let entry_point = instance + .start(&mut store) + .unwrap() + .get_export(&store, "call") + .unwrap() + .into_func() + .unwrap(); Self { entry_point, store } } } diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index fdb30310ef7..f93e7a2b21a 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -21,7 +21,7 @@ use crate::{ storage::{self, meter::Diff, WriteOutcome}, BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error, Event, Nonce, Origin, Pallet as Contracts, Schedule, - WasmBlob, LOG_TARGET, + LOG_TARGET, }; use frame_support::{ crypto::ecdsa::ECDSAExt, @@ -318,6 +318,22 @@ pub trait Ext: sealing::Sealed { /// Returns a nonce that is incremented for every instantiated contract. fn nonce(&mut self) -> u64; + /// Increment the reference count of a of a stored code by one. + /// + /// # Errors + /// + /// [`Error::CodeNotFound`] is returned if no stored code found having the specified + /// `code_hash`. + fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError>; + + /// Decrement the reference count of a stored code by one. + /// + /// # Note + /// + /// A contract whose reference count dropped to zero isn't automatically removed. A + /// `remove_code` transaction must be submitted by the original uploader to do so. + fn decrement_refcount(code_hash: CodeHash); + /// Adds a delegate dependency to [`ContractInfo`]'s `delegate_dependencies` field. /// /// This ensures that the delegated contract is not removed while it is still in use. It @@ -381,22 +397,6 @@ pub trait Executable: Sized { gas_meter: &mut GasMeter, ) -> Result; - /// Increment the reference count of a of a stored code by one. - /// - /// # Errors - /// - /// [`Error::CodeNotFound`] is returned if no stored code found having the specified - /// `code_hash`. - fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError>; - - /// Decrement the reference count of a stored code by one. - /// - /// # Note - /// - /// A contract whose reference count dropped to zero isn't automatically removed. A - /// `remove_code` transaction must be submitted by the original uploader to do so. - fn decrement_refcount(code_hash: CodeHash); - /// Execute the specified exported function and return the result. /// /// When the specified function is `Constructor` the executable is stored and its @@ -1285,10 +1285,10 @@ where info.queue_trie_for_deletion(); ContractInfoOf::::remove(&frame.account_id); - E::decrement_refcount(info.code_hash); + Self::decrement_refcount(info.code_hash); for (code_hash, deposit) in info.delegate_dependencies() { - E::decrement_refcount(*code_hash); + Self::decrement_refcount(*code_hash); frame .nested_storage .charge_deposit(frame.account_id.clone(), StorageDeposit::Refund(*deposit)); @@ -1491,8 +1491,8 @@ where frame.nested_storage.charge_deposit(frame.account_id.clone(), deposit); - E::increment_refcount(hash)?; - E::decrement_refcount(prev_hash); + Self::increment_refcount(hash)?; + Self::decrement_refcount(prev_hash); Contracts::::deposit_event( vec![T::Hashing::hash_of(&frame.account_id), hash, prev_hash], Event::ContractCodeUpdated { @@ -1525,6 +1525,25 @@ where } } + fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { + >::mutate(code_hash, |existing| -> Result<(), DispatchError> { + if let Some(info) = existing { + *info.refcount_mut() = info.refcount().saturating_add(1); + Ok(()) + } else { + Err(Error::::CodeNotFound.into()) + } + }) + } + + fn decrement_refcount(code_hash: CodeHash) { + >::mutate(code_hash, |existing| { + if let Some(info) = existing { + *info.refcount_mut() = info.refcount().saturating_sub(1); + } + }); + } + fn add_delegate_dependency( &mut self, code_hash: CodeHash, @@ -1537,7 +1556,7 @@ where let deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit()); info.add_delegate_dependency(code_hash, deposit)?; - >::increment_refcount(code_hash)?; + Self::increment_refcount(code_hash)?; frame .nested_storage .charge_deposit(frame.account_id.clone(), StorageDeposit::Charge(deposit)); @@ -1552,8 +1571,7 @@ where let info = frame.contract_info.get(&frame.account_id); let deposit = info.remove_delegate_dependency(code_hash)?; - >::decrement_refcount(*code_hash); - + Self::decrement_refcount(*code_hash); frame .nested_storage .charge_deposit(frame.account_id.clone(), StorageDeposit::Refund(deposit)); @@ -1600,11 +1618,7 @@ mod tests { use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; use sp_runtime::{traits::Hash, DispatchError}; - use std::{ - cell::RefCell, - collections::hash_map::{Entry, HashMap}, - rc::Rc, - }; + use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc}; type System = frame_system::Pallet; @@ -1635,7 +1649,6 @@ mod tests { func_type: ExportedFunction, code_hash: CodeHash, code_info: CodeInfo, - refcount: u64, } #[derive(Default, Clone)] @@ -1664,37 +1677,11 @@ mod tests { func_type, code_hash: hash, code_info: CodeInfo::::new(ALICE), - refcount: 1, }, ); hash }) } - - fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { - Loader::mutate(|loader| { - match loader.map.entry(code_hash) { - Entry::Vacant(_) => Err(>::CodeNotFound)?, - Entry::Occupied(mut entry) => entry.get_mut().refcount += 1, - } - Ok(()) - }) - } - - fn decrement_refcount(code_hash: CodeHash) { - use std::collections::hash_map::Entry::Occupied; - Loader::mutate(|loader| { - let mut entry = match loader.map.entry(code_hash) { - Occupied(e) => e, - _ => panic!("code_hash does not exist"), - }; - let refcount = &mut entry.get_mut().refcount; - *refcount -= 1; - if *refcount == 0 { - entry.remove(); - } - }); - } } impl Executable for MockExecutable { @@ -1707,14 +1694,6 @@ mod tests { }) } - fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { - MockLoader::increment_refcount(code_hash) - } - - fn decrement_refcount(code_hash: CodeHash) { - MockLoader::decrement_refcount(code_hash); - } - fn execute>( self, ext: &mut E, @@ -1722,7 +1701,7 @@ mod tests { input_data: Vec, ) -> ExecResult { if let &Constructor = function { - Self::increment_refcount(self.code_hash).unwrap(); + E::increment_refcount(self.code_hash).unwrap(); } // # Safety // @@ -1733,7 +1712,7 @@ mod tests { // The transmute is necessary because `execute` has to be generic over all // `E: Ext`. However, `MockExecutable` can't be generic over `E` as it would // constitute a cycle. - let ext = unsafe { std::mem::transmute(ext) }; + let ext = unsafe { mem::transmute(ext) }; if function == &self.func_type { (self.func)(MockCtx { ext, input_data }, &self) } else { diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index e22e4a3f9ff..7d516fbe249 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -103,7 +103,9 @@ pub mod weights; #[cfg(test)] mod tests; use crate::{ - exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Key, MomentOf, Stack as ExecStack}, + exec::{ + AccountIdOf, ErrorOrigin, ExecError, Executable, Ext, Key, MomentOf, Stack as ExecStack, + }, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager}, wasm::{CodeInfo, WasmBlob}, @@ -658,8 +660,8 @@ pub mod pallet { } else { return Err(>::ContractNotFound.into()) }; - >::increment_refcount(code_hash)?; - >::decrement_refcount(contract.code_hash); + >>::increment_refcount(code_hash)?; + >>::decrement_refcount(contract.code_hash); Self::deposit_event( vec![T::Hashing::hash_of(&dest), code_hash, contract.code_hash], Event::ContractCodeUpdated { diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 8d6c5c5ac72..0fea2b15595 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -862,6 +862,27 @@ fn deposit_event_max_value_limit() { }); } +// Fail out of fuel (ref_time weight) inside the start function. +#[test] +fn run_out_of_fuel_start_fun() { + let (wasm, _code_hash) = compile_module::("run_out_of_gas_start_fn").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + assert_err_ignore_postinfo!( + Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + Weight::from_parts(1_000_000_000_000, u64::MAX), + None, + wasm, + vec![], + vec![], + ), + Error::::OutOfGas, + ); + }); +} + // Fail out of fuel (ref_time weight) in the engine. #[test] fn run_out_of_fuel_engine() { diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 5fc65e314ad..77e94b16777 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -49,7 +49,7 @@ use frame_support::{ use sp_core::Get; use sp_runtime::{DispatchError, RuntimeDebug}; use sp_std::prelude::*; -use wasmi::{Instance, Linker, Memory, MemoryType, StackLimits, Store}; +use wasmi::{InstancePre, Linker, Memory, MemoryType, StackLimits, Store}; const BYTES_PER_PAGE: usize = 64 * 1024; @@ -164,7 +164,30 @@ impl WasmBlob { /// /// Applies all necessary checks before removing the code. pub fn remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { - Self::try_remove_code(origin, code_hash) + >::try_mutate_exists(&code_hash, |existing| { + if let Some(code_info) = existing { + ensure!(code_info.refcount == 0, >::CodeInUse); + ensure!(&code_info.owner == origin, BadOrigin); + let _ = T::Currency::release( + &HoldReason::CodeUploadDepositReserve.into(), + &code_info.owner, + code_info.deposit, + BestEffort, + ); + let deposit_released = code_info.deposit; + let remover = code_info.owner.clone(); + + *existing = None; + >::remove(&code_hash); + >::deposit_event( + vec![code_hash], + Event::CodeRemoved { code_hash, deposit_released, remover }, + ); + Ok(()) + } else { + Err(>::CodeNotFound.into()) + } + }) } /// Creates and returns an instance of the supplied code. @@ -179,7 +202,7 @@ impl WasmBlob { determinism: Determinism, stack_limits: StackLimits, allow_deprecated: AllowDeprecatedInterface, - ) -> Result<(Store, Memory, Instance), &'static str> + ) -> Result<(Store, Memory, InstancePre), &'static str> where E: Environment, { @@ -217,9 +240,7 @@ impl WasmBlob { let instance = linker .instantiate(&mut store, &contract.module) - .map_err(|_| "can't instantiate module with provided definitions")? - .ensure_no_start(&mut store) - .map_err(|_| "start function is forbidden but found in the module")?; + .map_err(|_| "can't instantiate module with provided definitions")?; Ok((store, memory, instance)) } @@ -261,45 +282,6 @@ impl WasmBlob { }) } - /// Try to remove code together with all associated information. - fn try_remove_code(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { - >::try_mutate_exists(&code_hash, |existing| { - if let Some(code_info) = existing { - ensure!(code_info.refcount == 0, >::CodeInUse); - ensure!(&code_info.owner == origin, BadOrigin); - let _ = T::Currency::release( - &HoldReason::CodeUploadDepositReserve.into(), - &code_info.owner, - code_info.deposit, - BestEffort, - ); - let deposit_released = code_info.deposit; - let remover = code_info.owner.clone(); - - *existing = None; - >::remove(&code_hash); - >::deposit_event( - vec![code_hash], - Event::CodeRemoved { code_hash, deposit_released, remover }, - ); - Ok(()) - } else { - Err(>::CodeNotFound.into()) - } - }) - } - - /// Load code with the given code hash. - fn load_code( - code_hash: CodeHash, - gas_meter: &mut GasMeter, - ) -> Result<(CodeVec, CodeInfo), DispatchError> { - let code_info = >::get(code_hash).ok_or(Error::::CodeNotFound)?; - gas_meter.charge(CodeLoadToken(code_info.code_len))?; - let code = >::get(code_hash).ok_or(Error::::CodeNotFound)?; - Ok((code, code_info)) - } - /// Create the module without checking the passed code. /// /// # Note @@ -318,12 +300,6 @@ impl WasmBlob { } impl CodeInfo { - /// Return the refcount of the module. - #[cfg(test)] - pub fn refcount(&self) -> u64 { - self.refcount - } - #[cfg(test)] pub fn new(owner: T::AccountId) -> Self { CodeInfo { @@ -335,6 +311,16 @@ impl CodeInfo { } } + /// Returns reference count of the module. + pub fn refcount(&self) -> u64 { + self.refcount + } + + /// Return mutable reference to the refcount of the module. + pub fn refcount_mut(&mut self) -> &mut u64 { + &mut self.refcount + } + /// Returns the deposit of the module. pub fn deposit(&self) -> BalanceOf { self.deposit @@ -346,29 +332,12 @@ impl Executable for WasmBlob { code_hash: CodeHash, gas_meter: &mut GasMeter, ) -> Result { - let (code, code_info) = Self::load_code(code_hash, gas_meter)?; + let code_info = >::get(code_hash).ok_or(Error::::CodeNotFound)?; + gas_meter.charge(CodeLoadToken(code_info.code_len))?; + let code = >::get(code_hash).ok_or(Error::::CodeNotFound)?; Ok(Self { code, code_info, code_hash }) } - fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { - >::mutate(code_hash, |existing| -> Result<(), DispatchError> { - if let Some(info) = existing { - info.refcount = info.refcount.saturating_add(1); - Ok(()) - } else { - Err(Error::::CodeNotFound.into()) - } - }) - } - - fn decrement_refcount(code_hash: CodeHash) { - >::mutate(code_hash, |existing| { - if let Some(info) = existing { - info.refcount = info.refcount.saturating_sub(1); - } - }); - } - fn execute>( self, ext: &mut E, @@ -410,25 +379,38 @@ impl Executable for WasmBlob { .add_fuel(fuel_limit) .expect("We've set up engine to fuel consuming mode; qed"); - let exported_func = instance - .get_export(&store, function.identifier()) - .and_then(|export| export.into_func()) - .ok_or_else(|| { - log::error!(target: LOG_TARGET, "failed to find entry point"); - Error::::CodeRejected - })?; + // Sync this frame's gas meter with the engine's one. + let process_result = |mut store: Store>, result| { + let engine_consumed_total = + store.fuel_consumed().expect("Fuel metering is enabled; qed"); + let gas_meter = store.data_mut().ext().gas_meter_mut(); + gas_meter.charge_fuel(engine_consumed_total)?; + store.into_data().to_execution_result(result) + }; + // Start function should already see the correct refcount in case it will be ever inspected. if let &ExportedFunction::Constructor = function { - WasmBlob::::increment_refcount(self.code_hash)?; + E::increment_refcount(self.code_hash)?; } - let result = exported_func.call(&mut store, &[], &mut []); - let engine_consumed_total = store.fuel_consumed().expect("Fuel metering is enabled; qed"); - // Sync this frame's gas meter with the engine's one. - let gas_meter = store.data_mut().ext().gas_meter_mut(); - gas_meter.charge_fuel(engine_consumed_total)?; - - store.into_data().to_execution_result(result) + // Any abort in start function (includes `return` + `terminate`) will make us skip the + // call into the subsequent exported function. This means that calling `return` returns data + // from the whole contract execution. + match instance.start(&mut store) { + Ok(instance) => { + let exported_func = instance + .get_export(&store, function.identifier()) + .and_then(|export| export.into_func()) + .ok_or_else(|| { + log::error!(target: LOG_TARGET, "failed to find entry point"); + Error::::CodeRejected + })?; + + let result = exported_func.call(&mut store, &[], &mut []); + process_result(store, result) + }, + Err(err) => process_result(store, Err(err)), + } } fn code_hash(&self) -> &CodeHash { @@ -740,7 +722,10 @@ mod tests { fn nonce(&mut self) -> u64 { 995 } - + fn increment_refcount(_code_hash: CodeHash) -> Result<(), DispatchError> { + Ok(()) + } + fn decrement_refcount(_code_hash: CodeHash) {} fn add_delegate_dependency( &mut self, code: CodeHash, @@ -748,7 +733,6 @@ mod tests { self.delegate_dependencies.borrow_mut().insert(code); Ok(()) } - fn remove_delegate_dependency( &mut self, code: &CodeHash, @@ -790,11 +774,20 @@ mod tests { executable.execute(ext.borrow_mut(), entry_point, input_data) } - /// Execute the supplied code. + /// Execute the `call` function within the supplied code. fn execute>(wat: &str, input_data: Vec, ext: E) -> ExecResult { execute_internal(wat, input_data, ext, &ExportedFunction::Call, true, false) } + /// Execute the `deploy` function within the supplied code. + fn execute_instantiate>( + wat: &str, + input_data: Vec, + ext: E, + ) -> ExecResult { + execute_internal(wat, input_data, ext, &ExportedFunction::Constructor, true, false) + } + /// Execute the supplied code with disabled unstable functions. /// /// In our test config unstable functions are disabled so that we can test them. @@ -1878,32 +1871,47 @@ mod tests { assert_ok!(execute(CODE_VALUE_TRANSFERRED, vec![], MockExt::default())); } - const START_FN_ILLEGAL: &str = r#" + const START_FN_DOES_RUN: &str = r#" (module - (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32))) (import "env" "memory" (memory 1 1)) (start $start) (func $start - (unreachable) + (call $seal_deposit_event + (i32.const 0) ;; Pointer to the start of topics buffer + (i32.const 0) ;; The length of the topics buffer. + (i32.const 0) ;; Pointer to the start of the data buffer + (i32.const 13) ;; Length of the buffer + ) ) - (func (export "call") - (unreachable) - ) + (func (export "call")) - (func (export "deploy") - (unreachable) - ) + (func (export "deploy")) - (data (i32.const 8) "\01\02\03\04") + (data (i32.const 0) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00") ) "#; #[test] - fn start_fn_illegal() { - let output = execute(START_FN_ILLEGAL, vec![], MockExt::default()); - assert_err!(output, >::CodeRejected,); + fn start_fn_does_run_on_call() { + let mut ext = MockExt::default(); + execute(START_FN_DOES_RUN, vec![], &mut ext).unwrap(); + assert_eq!( + ext.events[0].1, + [0x00_u8, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00] + ); + } + + #[test] + fn start_fn_does_run_on_deploy() { + let mut ext = MockExt::default(); + execute_instantiate(START_FN_DOES_RUN, vec![], &mut ext).unwrap(); + assert_eq!( + ext.events[0].1, + [0x00_u8, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00] + ); } const CODE_TIMESTAMP_NOW: &str = r#" -- GitLab From 77c867bafff800488af43fa7e3602b914c062876 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 12 Sep 2023 16:13:27 +1000 Subject: [PATCH 124/633] fix simple analytics injection script (#1501) When `process_file` is run by `xargs`, it is executed inside a new shell without access to variables defined outside of its scope. This resulted in `script_content` being an empty string. By exporting `script_content` prior to running `xargs` it is available inside the new shells. --- .gitlab/pipeline/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 328b37af1d4..924d648e3f9 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -111,6 +111,9 @@ build-rustdoc: sed -i "s||$script_content|" "$file" } export -f process_file + # xargs runs process_file in seperate shells without access to outer variables. + # to make script_content available inside process_file, export it as an env var here. + export script_content # Modify .html files in parallel using xargs, otherwise it can take a long time. find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {} -- GitLab From d08170278bc795a322fbe21368bff84145b8e467 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Tue, 12 Sep 2023 09:49:48 +0300 Subject: [PATCH 125/633] Additional logging for `dispute-coordinator` (#1494) --- .../dispute-coordinator/src/initialized.rs | 7 +++++++ .../src/participation/mod.rs | 19 +++++++++++++++++++ .../src/participation/queues/mod.rs | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 9bfca2d81a0..9cd544a8c53 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -301,6 +301,13 @@ impl Initialized { self.participation.process_active_leaves_update(ctx, &update).await?; if let Some(new_leaf) = update.activated { + gum::trace!( + target: LOG_TARGET, + leaf_hash = ?new_leaf.hash, + block_number = new_leaf.number, + "Processing ActivatedLeaf" + ); + let session_idx = self.runtime_info.get_session_index_for_child(ctx.sender(), new_leaf.hash).await; diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index 5a3c4be90aa..35d07b411e8 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -260,6 +260,13 @@ impl Participation { req: ParticipationRequest, recent_head: Hash, ) -> FatalResult<()> { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?req.candidate_hash(), + session = req.session(), + "Forking participation" + ); + let participation_timer = self.metrics.time_participation(); if self.running_participations.insert(*req.candidate_hash()) { let sender = ctx.sender().clone(); @@ -314,12 +321,24 @@ async fn participate( }, Ok(Ok(data)) => data, Ok(Err(RecoveryError::Invalid)) => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?req.candidate_hash(), + session = req.session(), + "Invalid availability data during participation" + ); // the available data was recovered but it is invalid, therefore we'll // vote negatively for the candidate dispute send_result(&mut result_sender, req, ParticipationOutcome::Invalid).await; return }, Ok(Err(RecoveryError::Unavailable)) | Ok(Err(RecoveryError::ChannelClosed)) => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?req.candidate_hash(), + session = req.session(), + "Can't fetch availability data in participation" + ); send_result(&mut result_sender, req, ParticipationOutcome::Unavailable).await; return }, diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs index 1105135a747..d9e86def168 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs @@ -277,6 +277,11 @@ impl Queues { match self.priority.entry(comparator) { Entry::Occupied(_) => req.discard_timer(), Entry::Vacant(vac) => { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?req.candidate_hash(), + "Added to priority participation queue" + ); vac.insert(req); }, } @@ -295,6 +300,11 @@ impl Queues { match self.best_effort.entry(comparator) { Entry::Occupied(_) => req.discard_timer(), Entry::Vacant(vac) => { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?req.candidate_hash(), + "Added to best effort participation queue" + ); vac.insert(req); }, } -- GitLab From f551f52e3554a18e910b5a98f16ee851b25e9911 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:02:39 +1000 Subject: [PATCH 126/633] Bump cfg-expr from 0.15.4 to 0.15.5 (#1502) Bumps [cfg-expr](https://github.com/EmbarkStudios/cfg-expr) from 0.15.4 to 0.15.5.
Changelog

Sourced from cfg-expr's changelog.

[0.15.5] - 2023-09-08

Changed

  • PR#64 updated the builtin target list to 1.72.0. It also changed the MSRV to 1.70.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cfg-expr&package-manager=cargo&previous-version=0.15.4&new-version=0.15.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- substrate/frame/support/procedural/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 686ee62add3..eb13ab4b76a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2274,9 +2274,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" dependencies = [ "smallvec", ] diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 07a7ed079a9..308384f0363 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] derive-syn-parse = "0.1.5" Inflector = "0.11.4" -cfg-expr = "0.15.4" +cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -- GitLab From 391591b6a4e45d49bfafca77a41d1b684c9d5efe Mon Sep 17 00:00:00 2001 From: Lulu Date: Tue, 12 Sep 2023 11:41:34 +0100 Subject: [PATCH 127/633] Fix mistakes in Cargo.toml (#1504) --- substrate/frame/contracts/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 237ab9303e2..d5c809e1bf7 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for WASM contracts" readme = "README.md" -include = ["src/**/*", "README.md", "CHANGELOG.md"] +include = ["src/**/*", "build.rs", "README.md", "CHANGELOG.md"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 356693d90f0..6d96cb8abe7 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true description = "FRAME transaction pause pallet" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -- GitLab From f5ca403af9cea41230b27d74c98b205d9ba023c9 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Tue, 12 Sep 2023 14:38:31 +0300 Subject: [PATCH 128/633] Report `tracing_unbounded` channel size to prometheus (#1489) --- substrate/client/utils/src/metrics.rs | 27 ++++++++++++++++++++++----- substrate/client/utils/src/mpsc.rs | 27 ++++++++++++++++++++------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/substrate/client/utils/src/metrics.rs b/substrate/client/utils/src/metrics.rs index 6bbdbe2e2e5..308e90cb253 100644 --- a/substrate/client/utils/src/metrics.rs +++ b/substrate/client/utils/src/metrics.rs @@ -24,7 +24,10 @@ use prometheus::{ Error as PrometheusError, Registry, }; -use prometheus::{core::GenericCounterVec, Opts}; +use prometheus::{ + core::{GenericCounterVec, GenericGaugeVec}, + Opts, +}; lazy_static! { pub static ref TOKIO_THREADS_TOTAL: GenericCounter = @@ -36,18 +39,32 @@ lazy_static! { } lazy_static! { - pub static ref UNBOUNDED_CHANNELS_COUNTER : GenericCounterVec = GenericCounterVec::new( - Opts::new("substrate_unbounded_channel_len", "Items in each mpsc::unbounded instance"), - &["entity", "action"] // 'name of channel, send|received|dropped + pub static ref UNBOUNDED_CHANNELS_COUNTER: GenericCounterVec = GenericCounterVec::new( + Opts::new( + "substrate_unbounded_channel_len", + "Items sent/received/dropped on each mpsc::unbounded instance" + ), + &["entity", "action"], // name of channel, send|received|dropped + ).expect("Creating of statics doesn't fail. qed"); + pub static ref UNBOUNDED_CHANNELS_SIZE: GenericGaugeVec = GenericGaugeVec::new( + Opts::new( + "substrate_unbounded_channel_size", + "Size (number of messages to be processed) of each mpsc::unbounded instance", + ), + &["entity"], // name of channel ).expect("Creating of statics doesn't fail. qed"); - } +pub static SENT_LABEL: &'static str = "send"; +pub static RECEIVED_LABEL: &'static str = "received"; +pub static DROPPED_LABEL: &'static str = "dropped"; + /// Register the statics to report to registry pub fn register_globals(registry: &Registry) -> Result<(), PrometheusError> { registry.register(Box::new(TOKIO_THREADS_ALIVE.clone()))?; registry.register(Box::new(TOKIO_THREADS_TOTAL.clone()))?; registry.register(Box::new(UNBOUNDED_CHANNELS_COUNTER.clone()))?; + registry.register(Box::new(UNBOUNDED_CHANNELS_SIZE.clone()))?; Ok(()) } diff --git a/substrate/client/utils/src/mpsc.rs b/substrate/client/utils/src/mpsc.rs index 039e03f9e61..c24a5bd8904 100644 --- a/substrate/client/utils/src/mpsc.rs +++ b/substrate/client/utils/src/mpsc.rs @@ -20,7 +20,9 @@ pub use async_channel::{TryRecvError, TrySendError}; -use crate::metrics::UNBOUNDED_CHANNELS_COUNTER; +use crate::metrics::{ + DROPPED_LABEL, RECEIVED_LABEL, SENT_LABEL, UNBOUNDED_CHANNELS_COUNTER, UNBOUNDED_CHANNELS_SIZE, +}; use async_channel::{Receiver, Sender}; use futures::{ stream::{FusedStream, Stream}, @@ -102,7 +104,10 @@ impl TracingUnboundedSender { /// Proxy function to `async_channel::Sender::try_send`. pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { self.inner.try_send(msg).map(|s| { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "send"]).inc(); + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, SENT_LABEL]).inc(); + UNBOUNDED_CHANNELS_SIZE + .with_label_values(&[self.name]) + .set(self.inner.len().saturated_into()); if self.inner.len() >= self.queue_size_warning && self.warning_fired @@ -140,7 +145,10 @@ impl TracingUnboundedReceiver { /// that discounts the messages taken out. pub fn try_recv(&mut self) -> Result { self.inner.try_recv().map(|s| { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "received"]).inc(); + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, RECEIVED_LABEL]).inc(); + UNBOUNDED_CHANNELS_SIZE + .with_label_values(&[self.name]) + .set(self.inner.len().saturated_into()); s }) } @@ -155,14 +163,16 @@ impl Drop for TracingUnboundedReceiver { fn drop(&mut self) { // Close the channel to prevent any further messages to be sent into the channel self.close(); - // the number of messages about to be dropped + // The number of messages about to be dropped let count = self.inner.len(); - // discount the messages + // Discount the messages if count > 0 { UNBOUNDED_CHANNELS_COUNTER - .with_label_values(&[self.name, "dropped"]) + .with_label_values(&[self.name, DROPPED_LABEL]) .inc_by(count.saturated_into()); } + // Reset the size metric to 0 + UNBOUNDED_CHANNELS_SIZE.with_label_values(&[self.name]).set(0); // Drain all the pending messages in the channel since they can never be accessed, // this can be removed once https://github.com/smol-rs/async-channel/issues/23 is // resolved @@ -180,7 +190,10 @@ impl Stream for TracingUnboundedReceiver { match Pin::new(&mut s.inner).poll_next(cx) { Poll::Ready(msg) => { if msg.is_some() { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.name, "received"]).inc(); + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.name, RECEIVED_LABEL]).inc(); + UNBOUNDED_CHANNELS_SIZE + .with_label_values(&[s.name]) + .set(s.inner.len().saturated_into()); } Poll::Ready(msg) }, -- GitLab From fea7bcd6258a49676f70c8da0f8525de0b7b83d5 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 12 Sep 2023 14:07:09 +0200 Subject: [PATCH 129/633] [CI] Disable runtime logging for benchmarks (#1463) Changes: - Disable runtime logging in benchmarks by building with a specific profile --------- Signed-off-by: Oliver Tale-Yazdi --- .gitlab/pipeline/build.yml | 4 ++-- .gitlab/pipeline/short-benchmarks.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 924d648e3f9..3085d223006 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -146,7 +146,7 @@ build-short-benchmark: - .run-immediately - .collect-artifacts script: - - cargo build --profile release --locked --features=runtime-benchmarks --bin polkadot --workspace + - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build --bin polkadot --workspace - mkdir -p artifacts - target/release/polkadot --version - cp ./target/release/polkadot ./artifacts/ @@ -273,7 +273,7 @@ build-short-benchmark-cumulus: - .run-immediately - .collect-artifacts script: - - cargo build --profile release --locked --features=runtime-benchmarks -p polkadot-parachain-bin --bin polkadot-parachain + - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build -p polkadot-parachain-bin --bin polkadot-parachain --workspace - mkdir -p artifacts - target/release/polkadot-parachain --version - cp ./target/release/polkadot-parachain ./artifacts/ diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 81601fba32a..7b7704ee66d 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -18,7 +18,7 @@ short-benchmark-polkadot: &short-bench tags: - benchmark script: - - ./artifacts/polkadot benchmark pallet --execution wasm --wasm-execution compiled --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - ./artifacts/polkadot benchmark pallet --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 short-benchmark-kusama: <<: *short-bench @@ -45,7 +45,7 @@ short-benchmark-westend: tags: - benchmark script: - - ./artifacts/polkadot-parachain benchmark pallet --wasm-execution compiled --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - ./artifacts/polkadot-parachain benchmark pallet --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 short-benchmark-asset-hub-polkadot: <<: *short-bench-cumulus -- GitLab From e005aef59b229cf173d0aa84b73a78af49860a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 12 Sep 2023 14:12:10 +0200 Subject: [PATCH 130/633] Make the node version independent of the crate version (#1495) --- polkadot/cli/src/cli.rs | 11 +++++++++-- polkadot/cli/src/command.rs | 3 ++- polkadot/node/core/pvf/common/src/worker/mod.rs | 2 +- polkadot/src/bin/execute-worker.rs | 2 +- polkadot/src/bin/prepare-worker.rs | 2 +- substrate/utils/build-script-utils/src/version.rs | 1 + 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 66205902b79..aaf8f170576 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -19,8 +19,15 @@ use clap::Parser; use std::path::PathBuf; -/// The version of the node. The passed-in version of the workers should match this. -pub const NODE_VERSION: &'static str = env!("SUBSTRATE_CLI_IMPL_VERSION"); +/// 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)] diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index a2a00d0ebd3..a081e1b5181 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -55,7 +55,8 @@ impl SubstrateCli for Cli { } fn impl_version() -> String { - NODE_VERSION.into() + let commit_hash = env!("SUBSTRATE_CLI_COMMIT_HASH"); + format!("{NODE_VERSION}-{commit_hash}") } fn description() -> String { diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index a3f8e777c48..bcdf882f300 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -33,7 +33,7 @@ use tokio::{io, net::UnixStream, runtime::Runtime}; /// spawning the desired worker. #[macro_export] macro_rules! decl_worker_main { - ($expected_command:expr, $entrypoint:expr, $worker_version:expr) => { + ($expected_command:expr, $entrypoint:expr, $worker_version:expr $(,)*) => { fn print_help(expected_command: &str) { println!("{} {}", expected_command, $worker_version); println!(); diff --git a/polkadot/src/bin/execute-worker.rs b/polkadot/src/bin/execute-worker.rs index 72cab799d75..1deb3658098 100644 --- a/polkadot/src/bin/execute-worker.rs +++ b/polkadot/src/bin/execute-worker.rs @@ -19,5 +19,5 @@ polkadot_node_core_pvf_common::decl_worker_main!( "execute-worker", polkadot_node_core_pvf_execute_worker::worker_entrypoint, - env!("SUBSTRATE_CLI_IMPL_VERSION") + polkadot_cli::NODE_VERSION, ); diff --git a/polkadot/src/bin/prepare-worker.rs b/polkadot/src/bin/prepare-worker.rs index 695f66cc7b7..d731f8a30d0 100644 --- a/polkadot/src/bin/prepare-worker.rs +++ b/polkadot/src/bin/prepare-worker.rs @@ -19,5 +19,5 @@ polkadot_node_core_pvf_common::decl_worker_main!( "prepare-worker", polkadot_node_core_pvf_prepare_worker::worker_entrypoint, - env!("SUBSTRATE_CLI_IMPL_VERSION") + polkadot_cli::NODE_VERSION, ); diff --git a/substrate/utils/build-script-utils/src/version.rs b/substrate/utils/build-script-utils/src/version.rs index 4ee5376ed32..309c6d71d77 100644 --- a/substrate/utils/build-script-utils/src/version.rs +++ b/substrate/utils/build-script-utils/src/version.rs @@ -41,6 +41,7 @@ pub fn generate_cargo_keys() { } }; + println!("cargo:rustc-env=SUBSTRATE_CLI_COMMIT_HASH={commit}"); println!("cargo:rustc-env=SUBSTRATE_CLI_IMPL_VERSION={}", get_version(&commit)) } -- GitLab From 730edeb68c3d2c31c65861bba17aa5e540bbddc5 Mon Sep 17 00:00:00 2001 From: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:22:39 +0300 Subject: [PATCH 131/633] add tests for `find_potential_parents` (#1338) (would have closed) https://github.com/paritytech/cumulus/issues/2831 --- cumulus/client/consensus/common/src/lib.rs | 2 + cumulus/client/consensus/common/src/tests.rs | 574 ++++++++++++++++++- 2 files changed, 553 insertions(+), 23 deletions(-) diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index 29ee7356ee2..08bceabb2bd 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -211,6 +211,7 @@ pub trait ParachainBlockImportMarker {} impl ParachainBlockImportMarker for ParachainBlockImport {} /// Parameters when searching for suitable parents to build on top of. +#[derive(Debug)] pub struct ParentSearchParams { /// The relay-parent that is intended to be used. pub relay_parent: PHash, @@ -228,6 +229,7 @@ pub struct ParentSearchParams { } /// A potential parent block returned from [`find_potential_parents`] +#[derive(Debug, PartialEq)] pub struct PotentialParent { /// The hash of the block. pub hash: B::Hash, diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 15586d81d9b..22d3dd3abd4 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -19,7 +19,10 @@ use crate::*; use async_trait::async_trait; use codec::Encode; use cumulus_client_pov_recovery::RecoveryKind; -use cumulus_primitives_core::{relay_chain::BlockId, InboundDownwardMessage, InboundHrmpMessage}; +use cumulus_primitives_core::{ + relay_chain::{self, BlockId}, + CumulusDigestItem, InboundDownwardMessage, InboundHrmpMessage, +}; use cumulus_relay_chain_interface::{ CommittedCandidateReceipt, OccupiedCoreAssumption, OverseerHandle, PHeader, ParaId, RelayChainInterface, RelayChainResult, SessionIndex, StorageValue, ValidatorId, @@ -42,12 +45,21 @@ use std::{ time::Duration, }; +fn relay_block_num_from_hash(hash: &PHash) -> relay_chain::BlockNumber { + hash.to_low_u64_be() as u32 +} + +fn relay_hash_from_block_num(block_number: relay_chain::BlockNumber) -> PHash { + PHash::from_low_u64_be(block_number as u64) +} + struct RelaychainInner { new_best_heads: Option>, finalized_heads: Option>, new_best_heads_sender: mpsc::UnboundedSender
, finalized_heads_sender: mpsc::UnboundedSender
, relay_chain_hash_to_header: HashMap, + relay_chain_hash_to_header_pending: HashMap, } impl RelaychainInner { @@ -61,6 +73,7 @@ impl RelaychainInner { new_best_heads: Some(new_best_heads), finalized_heads: Some(finalized_heads), relay_chain_hash_to_header: Default::default(), + relay_chain_hash_to_header_pending: Default::default(), } } } @@ -110,20 +123,17 @@ impl RelayChainInterface for Relaychain { &self, hash: PHash, _: ParaId, - _: OccupiedCoreAssumption, + assumption: OccupiedCoreAssumption, ) -> RelayChainResult> { - Ok(Some(PersistedValidationData { - parent_head: self - .inner - .lock() - .unwrap() - .relay_chain_hash_to_header - .get(&hash) - .unwrap() - .encode() - .into(), - ..Default::default() - })) + let inner = self.inner.lock().unwrap(); + let relay_to_header = match assumption { + OccupiedCoreAssumption::Included => &inner.relay_chain_hash_to_header_pending, + _ => &inner.relay_chain_hash_to_header, + }; + let Some(parent_head) = relay_to_header.get(&hash).map(|head| head.encode().into()) else { + return Ok(None) + }; + Ok(Some(PersistedValidationData { parent_head, ..Default::default() })) } async fn candidate_pending_availability( @@ -135,7 +145,7 @@ impl RelayChainInterface for Relaychain { } async fn session_index_for_child(&self, _: PHash) -> RelayChainResult { - unimplemented!("Not needed for test") + Ok(0) } async fn import_notification_stream( @@ -210,8 +220,23 @@ impl RelayChainInterface for Relaychain { .boxed()) } - async fn header(&self, _block_id: BlockId) -> RelayChainResult> { - unimplemented!("Not needed for test") + async fn header(&self, block_id: BlockId) -> RelayChainResult> { + let number = match block_id { + BlockId::Hash(hash) => relay_block_num_from_hash(&hash), + BlockId::Number(block_number) => block_number, + }; + let parent_hash = number + .checked_sub(1) + .map(relay_hash_from_block_num) + .unwrap_or_else(|| PHash::zero()); + + Ok(Some(PHeader { + parent_hash, + number, + digest: sp_runtime::Digest::default(), + state_root: PHash::zero(), + extrinsics_root: PHash::zero(), + })) } } @@ -238,6 +263,7 @@ fn build_block( sproof: RelayStateSproofBuilder, at: Option, timestamp: Option, + relay_parent: Option, ) -> Block { let builder = match at { Some(at) => match timestamp { @@ -249,10 +275,17 @@ fn build_block( let mut block = builder.build().unwrap().block; - // Simulate some form of post activity (like a Seal or Other generic things). - // This is mostly used to exercise the `LevelMonitor` correct behavior. - // (in practice we want that header post-hash != pre-hash) - block.header.digest.push(sp_runtime::DigestItem::Other(vec![1, 2, 3])); + if let Some(relay_parent) = relay_parent { + block + .header + .digest + .push(CumulusDigestItem::RelayParent(relay_parent).to_digest_item()); + } else { + // Simulate some form of post activity (like a Seal or Other generic things). + // This is mostly used to exercise the `LevelMonitor` correct behavior. + // (in practice we want that header post-hash != pre-hash) + block.header.digest.push(sp_runtime::DigestItem::Other(vec![1, 2, 3])); + } block } @@ -292,13 +325,14 @@ fn build_and_import_block_ext>( importer: &mut I, at: Option, timestamp: Option, + relay_parent: Option, ) -> Block { let sproof = match at { None => sproof_with_best_parent(client), Some(at) => sproof_with_parent_by_hash(client, at), }; - let block = build_block(client, sproof, at, timestamp); + let block = build_block(client, sproof, at, timestamp, relay_parent); import_block_sync(importer, block.clone(), origin, import_as_best); block } @@ -311,6 +345,7 @@ fn build_and_import_block(mut client: Arc, import_as_best: bool) -> Bloc &mut client, None, None, + None, ) } @@ -372,7 +407,7 @@ fn follow_new_best_with_dummy_recovery_works() { let header = client.header(best).ok().flatten().expect("No header for best"); sproof_with_parent(HeadData(header.encode())) }; - let block = build_block(&*client, sproof, None, None); + let block = build_block(&*client, sproof, None, None, None); let block_clone = block.clone(); let client_clone = client.clone(); @@ -638,6 +673,7 @@ fn prune_blocks_on_level_overflow() { &mut para_import, None, None, + None, ); let id0 = block0.header.hash(); @@ -650,6 +686,7 @@ fn prune_blocks_on_level_overflow() { &mut para_import, Some(id0), Some(i as u64 * TIMESTAMP_MULTIPLIER), + None, ) }) .collect::>(); @@ -664,6 +701,7 @@ fn prune_blocks_on_level_overflow() { &mut para_import, Some(id10), Some(i as u64 * TIMESTAMP_MULTIPLIER), + None, ) }) .collect::>(); @@ -692,6 +730,7 @@ fn prune_blocks_on_level_overflow() { &mut para_import, Some(id0), Some(LEVEL_LIMIT as u64 * TIMESTAMP_MULTIPLIER), + None, ); // Expected scenario @@ -711,6 +750,7 @@ fn prune_blocks_on_level_overflow() { &mut para_import, Some(id0), Some(2 * LEVEL_LIMIT as u64 * TIMESTAMP_MULTIPLIER), + None, ); // Expected scenario @@ -749,6 +789,7 @@ fn restore_limit_monitor() { &mut para_import, None, None, + None, ); let id00 = block00.header.hash(); @@ -761,6 +802,7 @@ fn restore_limit_monitor() { &mut para_import, Some(id00), Some(i as u64 * TIMESTAMP_MULTIPLIER), + None, ) }) .collect::>(); @@ -775,6 +817,7 @@ fn restore_limit_monitor() { &mut para_import, Some(id10), Some(i as u64 * TIMESTAMP_MULTIPLIER), + None, ) }) .collect::>(); @@ -809,6 +852,7 @@ fn restore_limit_monitor() { &mut para_import, Some(id00), Some(LEVEL_LIMIT as u64 * TIMESTAMP_MULTIPLIER), + None, ); // Expected scenario @@ -830,3 +874,487 @@ fn restore_limit_monitor() { })); assert_eq!(*monitor.freshness.get(&block13.header.hash()).unwrap(), monitor.import_counter); } + +#[test] +fn find_potential_parents_in_allowed_ancestry() { + sp_tracing::try_init_simple(); + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let included_map = &mut relay_chain.inner.lock().unwrap().relay_chain_hash_to_header; + included_map.insert(relay_parent, block.header().clone()); + } + + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 0, + max_depth: 0, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), 1); + let parent = &potential_parents[0]; + + assert_eq!(parent.hash, block.hash()); + assert_eq!(&parent.header, block.header()); + assert_eq!(parent.depth, 0); + assert!(parent.aligned_with_pending); + + // New block is not pending or included. + let block_relay_parent = relay_hash_from_block_num(11); + let search_relay_parent = relay_hash_from_block_num(13); + { + let included_map = &mut relay_chain.inner.lock().unwrap().relay_chain_hash_to_header; + included_map.insert(search_relay_parent, block.header().clone()); + } + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(block.header().hash()), + None, + Some(block_relay_parent), + ); + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 2, + max_depth: 1, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + assert_eq!(potential_parents.len(), 2); + let parent = &potential_parents[1]; + + assert_eq!(parent.hash, block.hash()); + assert_eq!(&parent.header, block.header()); + assert_eq!(parent.depth, 1); + assert!(parent.aligned_with_pending); + + // Reduce allowed ancestry. + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, + max_depth: 1, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), 1); + let parent = &potential_parents[0]; + assert_ne!(parent.hash, block.hash()); +} + +/// Tests that pending availability block is always potential parent. +#[test] +fn find_potential_pending_parent() { + sp_tracing::try_init_simple(); + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + let relay_parent = relay_hash_from_block_num(12); + let pending_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(included_block.header().hash()), + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + let search_relay_parent = relay_hash_from_block_num(15); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, pending_block.header().clone()); + } + + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 0, + max_depth: 1, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), 2); + let included_parent = &potential_parents[0]; + + assert_eq!(included_parent.hash, included_block.hash()); + assert_eq!(&included_parent.header, included_block.header()); + assert_eq!(included_parent.depth, 0); + assert!(included_parent.aligned_with_pending); + + let pending_parent = &potential_parents[1]; + + assert_eq!(pending_parent.hash, pending_block.hash()); + assert_eq!(&pending_parent.header, pending_block.header()); + assert_eq!(pending_parent.depth, 1); + assert!(pending_parent.aligned_with_pending); +} + +#[test] +fn find_potential_parents_with_max_depth() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let included_map = &mut relay_chain.inner.lock().unwrap().relay_chain_hash_to_header; + included_map.insert(relay_parent, included_block.header().clone()); + } + + let mut blocks = Vec::new(); + let mut parent = included_block.header().hash(); + for _ in 0..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(parent), + None, + Some(relay_parent), + ); + parent = block.header().hash(); + blocks.push(block); + } + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 0, + max_depth, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), max_depth + 1); + let expected_parents: Vec<_> = + std::iter::once(&included_block).chain(blocks.iter().take(max_depth)).collect(); + + for i in 0..(max_depth + 1) { + let parent = &potential_parents[i]; + let expected = &expected_parents[i]; + + assert_eq!(parent.hash, expected.hash()); + assert_eq!(&parent.header, expected.header()); + assert_eq!(parent.depth, i); + assert!(parent.aligned_with_pending); + } + } +} + +#[test] +fn find_potential_parents_aligned_with_pending() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + let pending_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(included_block.header().hash()), + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, pending_block.header().clone()); + } + + // Build two sibling chains from the included block. + let mut aligned_blocks = Vec::new(); + let mut parent = pending_block.header().hash(); + for _ in 1..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(parent), + None, + Some(relay_parent), + ); + parent = block.header().hash(); + aligned_blocks.push(block); + } + + let mut alt_blocks = Vec::new(); + let mut parent = included_block.header().hash(); + for _ in 0..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + Some(parent), + None, + Some(search_relay_parent), + ); + parent = block.header().hash(); + alt_blocks.push(block); + } + + // Ignore alternative branch: + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), max_depth + 1); + let expected_parents: Vec<_> = [&included_block, &pending_block] + .into_iter() + .chain(aligned_blocks.iter()) + .take(max_depth + 1) + .collect(); + + for i in 0..(max_depth + 1) { + let parent = &potential_parents[i]; + let expected = &expected_parents[i]; + + assert_eq!(parent.hash, expected.hash()); + assert_eq!(&parent.header, expected.header()); + assert_eq!(parent.depth, i); + assert!(parent.aligned_with_pending); + } + } + + // Do not ignore: + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth, + ignore_alternative_branches: false, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + let expected_len = 2 * max_depth + 1; + assert_eq!(potential_parents.len(), expected_len); + let expected_aligned: Vec<_> = [&included_block, &pending_block] + .into_iter() + .chain(aligned_blocks.iter()) + .take(max_depth + 1) + .collect(); + let expected_alt = alt_blocks.iter().take(max_depth); + + let expected_parents: Vec<_> = + expected_aligned.clone().into_iter().chain(expected_alt).collect(); + // Check correctness. + assert_eq!(expected_parents.len(), expected_len); + + for i in 0..expected_len { + let parent = &potential_parents[i]; + let expected = expected_parents + .iter() + .find(|block| block.header().hash() == parent.hash) + .expect("missing parent"); + + let is_aligned = expected_aligned.contains(&expected); + + assert_eq!(parent.hash, expected.hash()); + assert_eq!(&parent.header, expected.header()); + + assert_eq!(parent.aligned_with_pending, is_aligned); + } + } +} + +/// Tests that no potential parent gets discarded if there's no pending availability block. +#[test] +fn find_potential_parents_aligned_no_pending() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let included_map = &mut relay_chain.inner.lock().unwrap().relay_chain_hash_to_header; + included_map.insert(search_relay_parent, included_block.header().clone()); + } + + // Build two sibling chains from the included block. + let mut parent = included_block.header().hash(); + for _ in 0..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(parent), + None, + Some(relay_parent), + ); + parent = block.header().hash(); + } + + let mut parent = included_block.header().hash(); + for _ in 0..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + Some(parent), + None, + Some(search_relay_parent), + ); + parent = block.header().hash(); + } + + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents_aligned = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, + max_depth, + ignore_alternative_branches: false, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + assert_eq!(potential_parents.len(), 2 * max_depth + 1); + assert_eq!(potential_parents, potential_parents_aligned); + } +} -- GitLab From 09630fc38f9c603d77b7adb9859f6ee1ac139289 Mon Sep 17 00:00:00 2001 From: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:15:36 +0300 Subject: [PATCH 132/633] lookahead collator: only build on top of scheduled relay parents (#1429) Partially addresses #1400 --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- .../consensus/aura/src/collators/lookahead.rs | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index b1a7cde55c2..57cd646fbcd 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -45,11 +45,13 @@ use cumulus_primitives_core::{ use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_node_primitives::SubmitCollationParams; -use polkadot_node_subsystem::messages::CollationGenerationMessage; +use polkadot_node_subsystem::messages::{ + CollationGenerationMessage, RuntimeApiMessage, RuntimeApiRequest, +}; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{CollatorPair, Id as ParaId, OccupiedCoreAssumption}; -use futures::prelude::*; +use futures::{channel::oneshot, prelude::*}; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; use sc_consensus::BlockImport; use sc_consensus_aura::standalone as aura_internal; @@ -181,6 +183,17 @@ where while let Some(relay_parent_header) = import_notifications.next().await { let relay_parent = relay_parent_header.hash(); + if !is_para_scheduled(relay_parent, params.para_id, &mut params.overseer_handle).await { + tracing::trace!( + target: crate::LOG_TARGET, + ?relay_parent, + ?params.para_id, + "Para is not scheduled on any core, skipping import notification", + ); + + continue + } + let max_pov_size = match params .relay_client .persisted_validation_data( @@ -444,3 +457,41 @@ async fn max_ancestry_lookback( }, } } + +// Checks if there exists a scheduled core for the para at the provided relay parent. +// +// Falls back to `false` in case of an error. +async fn is_para_scheduled( + relay_parent: PHash, + para_id: ParaId, + overseer_handle: &mut OverseerHandle, +) -> bool { + let (tx, rx) = oneshot::channel(); + let request = RuntimeApiRequest::AvailabilityCores(tx); + overseer_handle + .send_msg(RuntimeApiMessage::Request(relay_parent, request), "LookaheadCollator") + .await; + + let cores = match rx.await { + Ok(Ok(cores)) => cores, + Ok(Err(error)) => { + tracing::error!( + target: crate::LOG_TARGET, + ?error, + ?relay_parent, + "Failed to query availability cores runtime API", + ); + return false + }, + Err(oneshot::Canceled) => { + tracing::error!( + target: crate::LOG_TARGET, + ?relay_parent, + "Sender for availability cores runtime request dropped", + ); + return false + }, + }; + + cores.iter().any(|core| core.para_id() == Some(para_id)) +} -- GitLab From ee6eeb74668502798d40f0c83e3710300fa9368e Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 12 Sep 2023 17:47:43 +0300 Subject: [PATCH 133/633] Allow justifications on non-finalized blocks (#1211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One assertion was unnecessary because of the check right above it, second assertion resolves https://github.com/paritytech/polkadot-sdk/issues/1159 --------- Co-authored-by: Bastian Köcher --- substrate/client/consensus/grandpa/src/import.rs | 1 - substrate/client/service/src/client/client.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/substrate/client/consensus/grandpa/src/import.rs b/substrate/client/consensus/grandpa/src/import.rs index 8481b395847..ca5b7c400bf 100644 --- a/substrate/client/consensus/grandpa/src/import.rs +++ b/substrate/client/consensus/grandpa/src/import.rs @@ -552,7 +552,6 @@ where .into(), )) } - assert!(block.justifications.is_some()); let mut authority_set = self.authority_set.inner_locked(); authority_set.authority_set_changes.insert(number); crate::aux_schema::update_authority_set::( diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index a0983d823e5..09c1673884a 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -603,8 +603,6 @@ where .block_gap .map_or(false, |(start, _)| *import_headers.post().number() == start); - assert!(justifications.is_some() && finalized || justifications.is_none() || gap_block); - // the block is lower than our last finalized block so it must revert // finality, refusing import. if status == blockchain::BlockStatus::Unknown && -- GitLab From f204e3264f945c33b4cea18a49f7232c180b07c5 Mon Sep 17 00:00:00 2001 From: Oleg Plakida <112385193+oleg-plakida@users.noreply.github.com> Date: Tue, 12 Sep 2023 19:44:47 +0100 Subject: [PATCH 134/633] Oleg/ci cd/add new tag (#1427) Update CI tag for docker vm runners --------- Co-authored-by: alvicsam --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71518428b94..10dd69f12a7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -114,7 +114,7 @@ default: - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] tags: - - linux-docker-vm-c2 + - linux-docker # rusty-cachier's hidden job. Parts of this job are used to instrument the pipeline's other real jobs with rusty-cachier # rusty-cachier's commands are described here: https://gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client#description -- GitLab From 35de1f2769fbd9df97153512712394dfe449dfe1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Sep 2023 10:33:12 +0300 Subject: [PATCH 135/633] pallet-beefy-mmr: better logging on BEEFY key to ETH address conversion (#1520) # Description Each time the validator set changes, BEEFY validator keys are converted to ETH addresses and merkelised into a `keyset_commitment` to be used by light clients. This commit downgrades `error` to `debug` when individual conversions from BEEFY keys to ETH addresses fail, and adds cumulative check that reports total number of failed conversions, if any, on `error` log-level. Fixes https://github.com/paritytech/polkadot-sdk/issues/1305 Signed-off-by: Adrian Catangiu --- substrate/frame/beefy-mmr/src/lib.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/substrate/frame/beefy-mmr/src/lib.rs b/substrate/frame/beefy-mmr/src/lib.rs index b12eb95f650..a0bf7cdcf86 100644 --- a/substrate/frame/beefy-mmr/src/lib.rs +++ b/substrate/frame/beefy-mmr/src/lib.rs @@ -79,7 +79,7 @@ impl Convert> for BeefyEc .to_eth_address() .map(|v| v.to_vec()) .map_err(|_| { - log::error!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!"); + log::debug!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!"); }) .unwrap_or_default() } @@ -199,7 +199,20 @@ impl Pallet { .cloned() .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); + let default_eth_addr = [0u8; 20]; let len = beefy_addresses.len() as u32; + let uninitialized_addresses = beefy_addresses + .iter() + .filter(|&addr| addr.as_slice().eq(&default_eth_addr)) + .count(); + if uninitialized_addresses > 0 { + log::error!( + target: "runtime::beefy", + "Failed to convert {} out of {} BEEFY PublicKeys to ETH addresses!", + uninitialized_addresses, + len, + ); + } let keyset_commitment = binary_merkle_tree::merkle_root::< ::Hashing, _, -- GitLab From 72de70c72dddedbbb30747d180facf49e936a47e Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 13 Sep 2023 17:34:53 +1000 Subject: [PATCH 136/633] Stabilize `VersionedMigration` (#1503) `VersionedMigration` has become somewhat widely used for handling version bumps in migrations the last few months. It is currently behind the `experimental` feature flag, requiring every pallet that writes a new migration with version bumps to set up the `experimental` flag in their own Cargo.tomls, and also for every runtime using these pallets to explicitly enable the `experimental` flag for each pallet. This is becoming quite verbose, and I can only see the number of pallets requiring the experimental flag increasing for no other reason than using what has become a commonly used feature. Additionally, I'm writing migration docs and would like to avoid stepping through how to use the `experimental` feature to get `VersionedMigration` working. Since the feature has been used in production for some time now without any reported issues, is becoming commonly used and ready to advertise in docs, I feel this is a good time to make it non-experimental. --- polkadot/runtime/common/Cargo.toml | 1 - polkadot/runtime/common/src/assigned_slots/migration.rs | 1 - polkadot/runtime/common/src/paras_registrar/migration.rs | 1 - polkadot/runtime/kusama/Cargo.toml | 4 ++-- polkadot/runtime/polkadot/Cargo.toml | 4 ++-- polkadot/runtime/rococo/Cargo.toml | 6 +++--- polkadot/runtime/westend/Cargo.toml | 4 ++-- polkadot/xcm/pallet-xcm/Cargo.toml | 2 -- polkadot/xcm/pallet-xcm/src/migration.rs | 1 - substrate/frame/society/Cargo.toml | 2 -- substrate/frame/society/src/migrations.rs | 1 - substrate/frame/support/src/migrations.rs | 7 +------ substrate/frame/support/test/tests/versioned_migration.rs | 2 +- 13 files changed, 11 insertions(+), 25 deletions(-) diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index ce7db99b9ea..7d8e6a04ca4 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -64,7 +64,6 @@ test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../pri [features] default = [ "std" ] -experimental = [ "frame-support/experimental" ] no_std = [] std = [ "bitvec/std", diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index 656e0836bba..0e88b27a1ff 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -63,7 +63,6 @@ pub mod v1 { /// [`MigrateToV1`] wrapped in a /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the /// migration is only performed when on-chain version is 0. - #[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs index 7d3dda54e0e..b767985489d 100644 --- a/polkadot/runtime/common/src/paras_registrar/migration.rs +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -60,7 +60,6 @@ impl> OnRuntimeUpgrade } } -#[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< 0, diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 9d26217a20d..b69bf4183ce 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -77,7 +77,7 @@ pallet-recovery = { path = "../../../substrate/frame/recovery", default-features 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, features = ["experimental"] } +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 } @@ -103,7 +103,7 @@ frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarki 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, features = ["experimental"] } +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 } diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index e5c25c1843f..4bb29b756b5 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -82,7 +82,7 @@ pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-featur 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, features=["experimental"] } +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 } @@ -94,7 +94,7 @@ pallet-session-benchmarking = { path = "../../../substrate/frame/session/benchma 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, features = ["experimental"] } +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 } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index cc5b242ccd5..ea8cc2916ef 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -65,7 +65,7 @@ pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = fal pallet-recovery = { path = "../../../substrate/frame/recovery", 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, features = ["experimental"] } +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 } pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } @@ -76,7 +76,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-xcm = { path = "../../xcm/pallet-xcm", default-features = false, features=["experimental"] } +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 } @@ -84,7 +84,7 @@ frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-fea frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } hex-literal = { version = "0.4.1" } -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features = ["experimental"] } +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 } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index c8e182f3469..a6ee22edf5e 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -83,7 +83,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-xcm = { path = "../../xcm/pallet-xcm", default-features = false, features=["experimental"] } +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 } @@ -95,7 +95,7 @@ pallet-offences-benchmarking = { path = "../../../substrate/frame/offences/bench pallet-session-benchmarking = { path = "../../../substrate/frame/session/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, features = ["experimental"] } +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 17ee9840e8f..4946a8d11ce 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -32,8 +32,6 @@ xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } [features] default = [ "std" ] -# Enable `VersionedMigration` for the migrations using the experimental feature. -experimental = [ "frame-support/experimental" ] std = [ "bounded-collections/std", "codec/std", diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index e28ca56563c..ba3cdb5c51e 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -65,7 +65,6 @@ pub mod v1 { /// /// Wrapped in [`frame_support::migrations::VersionedMigration`] so the pre/post checks don't /// begin failing after the upgrade is enacted on-chain. - #[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 1510e17b8b5..d38875836aa 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -34,8 +34,6 @@ sp-io = { path = "../../primitives/io" } [features] default = [ "std" ] -# Enable `VersionedMigration` for migrations using this feature. -experimental = [ "frame-support/experimental" ] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index b50b0e088a6..553eea1a795 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -95,7 +95,6 @@ impl< /// [`VersionUncheckedMigrateToV2`] wrapped in a [`frame_support::migrations::VersionedMigration`], /// ensuring the migration is only performed when on-chain version is 0. -#[cfg(feature = "experimental")] pub type VersionCheckedMigrateToV2 = frame_support::migrations::VersionedMigration< 0, diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 6fc1834f01a..8f490030c25 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -24,9 +24,7 @@ use sp_core::Get; use sp_io::{hashing::twox_128, storage::clear_prefix, KillStorageResult}; use sp_std::marker::PhantomData; -/// EXPERIMENTAL: The API of this feature may change. -/// -/// Make it easier to write versioned runtime upgrades. +/// Handles storage migration pallet versioning. /// /// [`VersionedMigration`] allows developers to write migrations without worrying about checking and /// setting storage versions. Instead, the developer wraps their migration in this struct which @@ -69,14 +67,12 @@ use sp_std::marker::PhantomData; /// // other migrations... /// ); /// ``` -#[cfg(feature = "experimental")] pub struct VersionedMigration { _marker: PhantomData<(Inner, Pallet, Weight)>, } /// A helper enum to wrap the pre_upgrade bytes like an Option before passing them to post_upgrade. /// This enum is used rather than an Option to make the API clearer to the developer. -#[cfg(feature = "experimental")] #[derive(codec::Encode, codec::Decode)] pub enum VersionedPostUpgradeData { /// The migration ran, inner vec contains pre_upgrade data. @@ -91,7 +87,6 @@ pub enum VersionedPostUpgradeData { /// version of the pallets storage matches `From`, and after the upgrade set the on-chain storage to /// `To`. If the versions do not match, it writes a log notifying the developer that the migration /// is a noop. -#[cfg(feature = "experimental")] impl< const FROM: u16, const TO: u16, diff --git a/substrate/frame/support/test/tests/versioned_migration.rs b/substrate/frame/support/test/tests/versioned_migration.rs index a0766f6bec2..03dbd948df9 100644 --- a/substrate/frame/support/test/tests/versioned_migration.rs +++ b/substrate/frame/support/test/tests/versioned_migration.rs @@ -17,7 +17,7 @@ //! Tests for [`VersionedMigration`] -#![cfg(all(feature = "experimental", feature = "try-runtime"))] +#![cfg(feature = "try-runtime")] use frame_support::{ construct_runtime, derive_impl, -- GitLab From 71630dfb1441ef61e32fa7946a5e6fc64d29bda5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 09:58:34 +0200 Subject: [PATCH 137/633] Bump the known_good_semver group with 1 update (#1530) Bumps the known_good_semver group with 1 update: [clap](https://github.com/clap-rs/clap).
Release notes

Sourced from clap's releases.

v4.4.3

[4.4.3] - 2023-09-12

Documentation

  • (derive) Clarify use of attributes within the tutorial
  • Split sections in the builder and derive tutorials into separate modules
Changelog

Sourced from clap's changelog.

[4.4.3] - 2023-09-12

Documentation

  • (derive) Clarify use of attributes within the tutorial
  • Split sections in the builder and derive tutorials into separate modules
Commits
  • e9668b3 chore: Release
  • bc4986e docs: Update changelog
  • 3d53641 Merge pull request #5122 from epage/docs
  • 32586c7 docs(tutorial): Split into separate modules per section
  • 5f6d4a3 docs(tutorial): Split out into a module
  • 20987de Merge pull request #5121 from epage/docs
  • 9e7404b docs(tutorial): Attempt to clarify attributes
  • db97a2c docs(derive): Clarify value attributes are for PossibleValue
  • 37ba607 chore: Release
  • 3234c74 docs: Update changelog
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=clap&package-manager=cargo&previous-version=4.4.2&new-version=4.4.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 58 +++++++++---------- cumulus/client/cli/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 26 files changed, 55 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb13ab4b76a..5323165e761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2334,7 +2334,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.2", + "clap 4.4.3", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2464,9 +2464,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.2" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" dependencies = [ "clap_builder", "clap_derive 4.4.2", @@ -2490,7 +2490,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", ] [[package]] @@ -3085,7 +3085,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.2", + "clap 4.4.3", "criterion-plot", "futures", "is-terminal", @@ -3250,7 +3250,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3935,7 +3935,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.2", + "clap 4.4.3", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -5141,7 +5141,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.2", + "clap 4.4.3", "comfy-table", "frame-benchmarking", "frame-support", @@ -5233,7 +5233,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -8135,7 +8135,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.4.2", + "clap 4.4.3", "derive_more", "fs_extra", "futures", @@ -8172,7 +8172,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.4.2", + "clap 4.4.3", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8298,7 +8298,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8352,7 +8352,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "generate-bags", "kitchensink-runtime", ] @@ -8361,7 +8361,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8404,7 +8404,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "flate2", "fs_extra", "glob", @@ -10794,7 +10794,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11530,7 +11530,7 @@ dependencies = [ name = "polkadot-cli" version = "1.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "frame-benchmarking-cli", "futures", "log", @@ -12350,7 +12350,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.2", + "clap 4.4.3", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -12965,7 +12965,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.2", + "clap 4.4.3", "color-eyre", "futures", "futures-timer", @@ -13111,7 +13111,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "generate-bags", "polkadot-runtime", "sp-io", @@ -13873,7 +13873,7 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "frame-system", "kusama-runtime-constants", "log", @@ -14581,7 +14581,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.4.2", + "clap 4.4.3", "fdlimit", "futures", "futures-timer", @@ -15685,7 +15685,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "fs4", "log", "sc-client-db", @@ -17216,7 +17216,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17933,7 +17933,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "sc-cli", ] @@ -17975,7 +17975,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "frame-support", "frame-system", "sc-cli", @@ -18434,7 +18434,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "futures", "futures-timer", "log", @@ -18482,7 +18482,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.2", + "clap 4.4.3", "futures", "futures-timer", "log", @@ -19128,7 +19128,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.2", + "clap 4.4.3", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 6c44d5f5fd3..15f28d73b36 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index b1f1946e3ed..6de57b185e4 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index c0be39461ad..8c250300cc8 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index c65eb0dd024..a2932cf755f 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.2", features = ["derive"] } +clap = { version = "4.4.3", 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/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index c8c3f91f983..794d8c4714a 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.2", features = ["derive"], optional = true } +clap = { version = "4.4.3", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.48" futures = "0.3.21" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 56053b8814a..08d203281cf 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 5c93d716528..a2ce15c21db 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 9cdacbc5657..9a5e580af1b 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 98a0a9b6a88..99948cb68b1 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.4.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index bbdddf75064..ed49f77bb81 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -19,6 +19,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.4.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 38eba5ee0e1..b510ed34c23 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 2540e213f10..84191e40f57 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 2e94098a63c..2e60f5c2ff5 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.2", features = ["derive"], optional = true } +clap = { version = "4.4.3", 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"] } @@ -135,7 +135,7 @@ pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] -clap = { version = "4.4.2", optional = true } +clap = { version = "4.4.3", 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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 2b6a5e1aea1..f28ceb45957 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index fcc97e7809b..c626a1612eb 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } rand = "0.8" node-cli = { path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 98276863f8d..8a5f4ec49c5 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 5456ad27f23..299c766cd3e 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.2", features = ["derive", "string"] } +clap = { version = "4.4.3", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 5354819e3a3..6d425749a91 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.2", features = ["derive", "string"] } +clap = { version = "4.4.3", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.6.3" sc-client-db = { path = "../db", default-features = false} 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 69ce42559a6..fe84c4c0ef9 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 86927786c58..1e9f0517df1 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 6c4cee8ece3..63611ae8da6 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 69c8fdf932e..8cc12772d4e 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.2", features = ["derive"] } +clap = { version = "4.4.3", 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/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index d191506a2ac..89aef533865 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.2", features = ["derive"] } +clap = { version = "4.4.3", 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 43005ca5c4a..b06674a62cb 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 7bde09b8cf3..9a21f68aa0b 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.2", features = ["derive"] } +clap = { version = "4.4.3", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -- GitLab From 2daa47158e9c93cc5b6ff47d84ebd6a9435bab30 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Wed, 13 Sep 2023 05:28:32 -0300 Subject: [PATCH 138/633] fix(ci): Add logic to check and calculate secundary image to use (#1529) Add logic to check if the `BUILD_RELEASE_VERSION` tag is available in docker registry, if not calculate the previous version to use as secondary image. This fix the issue in test using the `secondary image` and bumping the `NODE_VERSION`. (e.g #1495) --- .gitlab/pipeline/zombienet/polkadot.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 349807a610d..e420baf486a 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -7,10 +7,18 @@ - export BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" # from build-linux-stable job - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" - export MALUS_IMAGE="${MALUS_IMAGE}":${PIPELINE_IMAGE_TAG} + - IMAGE_AVAILABLE=$(curl -o /dev/null -w "%{http_code}" -I -L -s https://registry.hub.docker.com/v2/repositories/parity/polkadot/tags/${BUILD_RELEASE_VERSION}) + - if [ $IMAGE_AVAILABLE -eq 200 ]; then + export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}"; + else + echo "Getting the image to use as SECONDARY, using ${BUILD_RELEASE_VERSION} as base"; + VERSIONS=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/parity/polkadot/tags/' | jq -r '.results[].name'| grep -E "v[0-9]" |grep -vE "[0-9]-"); + VERSION_TO_USE=$(echo "${BUILD_RELEASE_VERSION}\n$VERSIONS"|sort -r|grep -A1 "${BUILD_RELEASE_VERSION}"|tail -1); + export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${VERSION_TO_USE}"; + fi - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" - echo "local-dir ${LOCAL_DIR}" -- GitLab From 6402ff91905e0b01b03907e32154f6079f92aa4b Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Wed, 13 Sep 2023 14:14:40 +0400 Subject: [PATCH 139/633] Fix PRCR's Zombienet `exclude:` behavior (#1535) --- .github/pr-custom-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 40fc53cbd02..ac13d862a4a 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -8,7 +8,7 @@ rules: check_type: changed_files condition: include: ^\.gitlab-ci\.yml|^docker/.*|^\.github/.*|^\.gitlab/.*|^\.config/nextest.toml|^\.cargo/.* - exclude: ^./gitlab/pipeline/zombienet.yml$ + exclude: ^\.gitlab/pipeline/zombienet.* min_approvals: 2 teams: - ci -- GitLab From f7c95c5fc12d3abde866bc1ee106909f950e5427 Mon Sep 17 00:00:00 2001 From: Maciej Date: Wed, 13 Sep 2023 11:46:33 +0100 Subject: [PATCH 140/633] Inclusions struct unit tests (#1518) In follow-up to https://github.com/paritytech/polkadot-sdk/pull/1432 Some additional unit tests for the inclusion struct used in the scraper. --- .../dispute-coordinator/src/scraping/tests.rs | 275 +++++++++++++++++- 1 file changed, 274 insertions(+), 1 deletion(-) diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs index ae722fcb1b4..0a971ad5d1d 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs @@ -41,7 +41,7 @@ use polkadot_primitives::{ GroupIndex, Hash, HashT, HeadData, Id as ParaId, }; -use crate::LOG_TARGET; +use crate::{scraping::Inclusions, LOG_TARGET}; use super::ChainScraper; @@ -662,3 +662,276 @@ fn inclusions_per_candidate_properly_adds_and_prunes() { assert!(scraper.get_blocks_including_candidate(&candidate.hash()).len() == 0); }); } + +// ----- Inclusions tests ----- + +#[test] +fn inclusions_initialization() { + let inclusions = Inclusions::new(); + + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} +#[test] +fn inclusions_insertion() { + let mut inclusions = Inclusions::new(); + let candidate_receipt = make_candidate_receipt(get_magic_candidate_hash()); + let candidate_hash = candidate_receipt.hash(); + let block_number = 0; + let block_hash = get_block_number_hash(block_number); + + inclusions.insert(candidate_hash, block_number, block_hash); + + // Check inclusions_inner + assert!(inclusions.inclusions_inner.len() == 1, "Expected inclusions_inner to have length 1"); + assert!( + inclusions.inclusions_inner.contains_key(&candidate_hash), + "Expected candidate_hash to be present in inclusions_inner" + ); + let inner_map = inclusions.inclusions_inner.get(&candidate_hash).unwrap(); + assert!(inner_map.len() == 1, "Expected inner_map to have length 1"); + assert!( + inner_map.contains_key(&block_number), + "Expected block_number to be present for the candidate_hash in inclusions_inner" + ); + let hash_set = inner_map.get(&block_number).unwrap(); + assert!(hash_set.len() == 1, "Expected hash_map to have length 1"); + assert!( + hash_set.contains(&block_hash), + "Expected block_hash to be present for the block_number in inclusions_inner" + ); + + // Check candidates_by_block_number + assert!( + inclusions.candidates_by_block_number.len() == 1, + "Expected candidates_by_block_number to have length 1" + ); + assert!( + inclusions.candidates_by_block_number.contains_key(&block_number), + "Expected block_number to be present in candidates_by_block_number" + ); + let candidate_set = inclusions.candidates_by_block_number.get(&block_number).unwrap(); + assert!( + candidate_set.len() == 1, + "Expected candidate_set to have length 1 for the block_number in candidates_by_block_number" + ); + assert!( + candidate_set.contains(&candidate_hash), + "Expected candidate_hash to be present for the block_number in candidates_by_block_number" + ); +} + +#[test] +fn inclusions_get() { + let mut inclusions = Inclusions::new(); + let candidate_receipt = make_candidate_receipt(get_magic_candidate_hash()); + let candidate_hash = candidate_receipt.hash(); + + // Insert the candidate with multiple block numbers and block hashes + let block_numbers = [0, 1, 2]; + let block_hashes: Vec<_> = + block_numbers.iter().map(|&num| get_block_number_hash(num)).collect(); + + for (&block_number, &block_hash) in block_numbers.iter().zip(&block_hashes) { + inclusions.insert(candidate_hash, block_number, block_hash); + } + + // Call the get method for that candidate + let result = inclusions.get(&candidate_hash); + + // Verify that the method returns the correct list of block numbers and hashes associated with + // that candidate + assert_eq!( + result.len(), + block_numbers.len(), + "Expected the same number of results as inserted block numbers" + ); + + for (&block_number, &block_hash) in block_numbers.iter().zip(&block_hashes) { + assert!( + result.contains(&(block_number, block_hash)), + "Expected to find ({}, {}) in the result", + block_number, + block_hash + ); + } +} + +#[test] +fn inclusions_iterative_removal() { + let mut inclusions = Inclusions::new(); + + // Insert 3 candidates in the specified blocks + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + let candidate4 = make_candidate_receipt(BlakeTwo256::hash(&"c4".encode())).hash(); + let candidate5 = make_candidate_receipt(BlakeTwo256::hash(&"c5".encode())).hash(); + + // B 0 1 2 3 + // C1 x + // C2 x + // C3 x x + // C4 x + // C5 x + inclusions.insert(candidate1, 0, get_block_number_hash(0)); + inclusions.insert(candidate2, 1, get_block_number_hash(1)); + inclusions.insert(candidate3, 0, get_block_number_hash(0)); + inclusions.insert(candidate3, 2, get_block_number_hash(2)); + inclusions.insert(candidate4, 2, get_block_number_hash(2)); + inclusions.insert(candidate5, 3, get_block_number_hash(3)); + + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); + assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); + + inclusions.remove_up_to_height(&1); + assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); + assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); + + inclusions.remove_up_to_height(&2); + assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); + assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); + assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); + + inclusions.remove_up_to_height(&10); + assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); + assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); + assert!(!inclusions.contains(&candidate3), "Expected candidate3 to be removed"); + assert!(!inclusions.contains(&candidate4), "Expected candidate4 to be removed"); + assert!(!inclusions.contains(&candidate5), "Expected candidate5 to be removed"); +} + +#[test] +fn inclusions_duplicate_insertion_same_height_and_block() { + let mut inclusions = Inclusions::new(); + + // Insert a candidate + let candidate1 = make_candidate_receipt(get_magic_candidate_hash()).hash(); + let block_number = 0; + let block_hash = get_block_number_hash(block_number); + + // Insert the candidate once + inclusions.insert(candidate1, block_number, block_hash); + + // Insert the same candidate again at the same height and block + inclusions.insert(candidate1, block_number, block_hash); + + // Check inclusions_inner + assert!( + inclusions.inclusions_inner.contains_key(&candidate1), + "Expected candidate1 to be present in inclusions_inner" + ); + let inner_map = inclusions.inclusions_inner.get(&candidate1).unwrap(); + assert!( + inner_map.contains_key(&block_number), + "Expected block_number to be present for the candidate1 in inclusions_inner" + ); + let hash_set = inner_map.get(&block_number).unwrap(); + assert_eq!( + hash_set.len(), + 1, + "Expected only one block_hash for the block_number in inclusions_inner" + ); + assert!( + hash_set.contains(&block_hash), + "Expected block_hash to be present for the block_number in inclusions_inner" + ); + + // Check candidates_by_block_number + assert!( + inclusions.candidates_by_block_number.contains_key(&block_number), + "Expected block_number to be present in candidates_by_block_number" + ); + let candidate_set = inclusions.candidates_by_block_number.get(&block_number).unwrap(); + assert_eq!( + candidate_set.len(), + 1, + "Expected only one candidate for the block_number in candidates_by_block_number" + ); + assert!( + candidate_set.contains(&candidate1), + "Expected candidate1 to be present for the block_number in candidates_by_block_number" + ); +} + +#[test] +fn test_duplicate_insertion_same_height_different_blocks() { + let mut inclusions = Inclusions::new(); + + // Insert a candidate + let candidate1 = make_candidate_receipt(get_magic_candidate_hash()).hash(); + let block_number = 0; + let block_hash1 = BlakeTwo256::hash(&"b1".encode()); + let block_hash2 = BlakeTwo256::hash(&"b2".encode()); // Different block hash for the same height + inclusions.insert(candidate1, block_number, block_hash1); + inclusions.insert(candidate1, block_number, block_hash2); + + // Check inclusions_inner + assert!( + inclusions.inclusions_inner.contains_key(&candidate1), + "Expected candidate1 to be present in inclusions_inner" + ); + let inner_map = inclusions.inclusions_inner.get(&candidate1).unwrap(); + assert!( + inner_map.contains_key(&block_number), + "Expected block_number to be present for the candidate1 in inclusions_inner" + ); + let hash_set = inner_map.get(&block_number).unwrap(); + assert_eq!( + hash_set.len(), + 2, + "Expected two block_hashes for the block_number in inclusions_inner" + ); + assert!( + hash_set.contains(&block_hash1), + "Expected block_hash1 to be present for the block_number in inclusions_inner" + ); + assert!( + hash_set.contains(&block_hash2), + "Expected block_hash2 to be present for the block_number in inclusions_inner" + ); + + // Check candidates_by_block_number + assert!( + inclusions.candidates_by_block_number.contains_key(&block_number), + "Expected block_number to be present in candidates_by_block_number" + ); + let candidate_set = inclusions.candidates_by_block_number.get(&block_number).unwrap(); + assert_eq!( + candidate_set.len(), + 1, + "Expected only one candidate for the block_number in candidates_by_block_number" + ); + assert!( + candidate_set.contains(&candidate1), + "Expected candidate1 to be present for the block_number in candidates_by_block_number" + ); +} + +#[test] +fn inclusions_remove_with_empty_maps() { + let mut inclusions = Inclusions::new(); + let height = 5; + + // Ensure both maps are empty before the operation + assert!(inclusions.candidates_by_block_number.is_empty()); + assert!(inclusions.inclusions_inner.is_empty()); + + inclusions.remove_up_to_height(&height); + + // Ensure both maps remain empty after the operation + assert!(inclusions.candidates_by_block_number.is_empty()); + assert!(inclusions.inclusions_inner.is_empty()); +} -- GitLab From 07bad23ec068fa0ce20015755d76586ef7c52870 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 13 Sep 2023 12:59:14 +0200 Subject: [PATCH 141/633] Reintroduce and fix Docker image build for production (#1536) This PR brings back the GH Workflow step and some fixes to build the docker image from the Debian package. --------- Co-authored-by: EgorPopelyaev --- .../workflows/release-50_publish-docker.yml | 136 +++++++++++++++--- .../polkadot_injected_debian.Dockerfile | 27 ++-- 2 files changed, 123 insertions(+), 40 deletions(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 7fdfc230354..04b3ebd3e79 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -1,10 +1,7 @@ name: Release - Publish Docker Image -# This workflow listens to pubished releases or can be triggered manually. -# It includes releases and rc candidates. -# It fetches the binaries, checks sha256 and GPG -# signatures, then builds an injected docker -# image and publishes it. +# This workflow listens to published releases or can be triggered manually. +# It builds and published releases and rc candidates. on: #TODO: activate automated run later @@ -13,6 +10,24 @@ on: # - published workflow_dispatch: inputs: + image_type: + description: Type of the image to be published + required: true + default: rc + type: choice + options: + - rc + - release + + binary: + description: Binary to be published + required: true + default: polkadot + type: choice + options: + - polkadot + - polkadot-parachain + release_id: description: | Release ID. @@ -22,32 +37,25 @@ on: jq '.[] | { name: .name, id: .id }' required: true type: string - image_type: - description: Type of the image to be published - required: true - default: rc - type: choice - options: - - rc - - release + registry: description: Container registry required: true type: string default: docker.io + + # The owner is often the same than the Docker Hub username but does ont have to be. + # In our case, it is not. owner: description: Owner of the container image repo required: true type: string default: parity - binary: - description: Binary to be published + + version: + description: version to build/release + default: v0.9.18 required: true - default: polkadot - type: choice - options: - - polkadot - - polkadot-parachain permissions: contents: write @@ -65,7 +73,8 @@ env: IMAGE_TYPE: ${{ inputs.image_type }} jobs: - fetch-artifacts: + fetch-artifacts: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest steps: @@ -101,7 +110,8 @@ jobs: path: | ./release-artifacts/${{ env.BINARY }}/**/* - build-container: + build-container: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest needs: fetch-artifacts @@ -157,6 +167,18 @@ jobs: echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT + - name: Build Injected Container image for polkadot rc + if: ${{ env.BINARY == 'polkadot' }} + env: + ARTIFACTS_FOLDER: ./release-artifacts + IMAGE_NAME: ${{ env.BINARY }} + OWNER: ${{ env.DOCKER_OWNER }} + TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} + run: | + ls -al + echo "Building container for $BINARY" + ./docker/scripts/build-injected.sh + - name: Build Injected Container image for polkadot-parachain if: ${{ env.BINARY == 'polkadot-parachain' }} env: @@ -191,3 +213,73 @@ jobs: run: | echo "Checking tag ${RELEASE_TAG} for image ${REGISTRY}/${DOCKER_OWNER}/${BINARY}" $ENGINE run -i ${REGISTRY}/${DOCKER_OWNER}/${BINARY}:${RELEASE_TAG} --version + + fetch-latest-debian-package-version: # this job will be triggered for polkadot release build + if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} + runs-on: ubuntu-latest + outputs: + polkadot_apt_version: ${{ steps.fetch-latest-apt.outputs.polkadot_apt_version }} + container: + image: paritytech/parity-keyring + options: --user root + steps: + - name: Get version + id: fetch-latest-apt + run: | + apt update + apt show polkadot + version=$(apt show polkadot 2>/dev/null | grep "Version:" | awk '{print $2}') + echo "polkadot_apt_version=v$version" >> $GITHUB_OUTPUT + echo "You passed ${{ inputs.version }} but this is ignored" + echo "We use the version from the Debian Package: $version" + + build-polkadot-release-container: # this job will be triggered for polkadot release build + if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} + runs-on: ubuntu-latest + needs: fetch-latest-debian-package-version + steps: + - name: Checkout sources + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # v2.1.0 + + - name: Cache Docker layers + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to Docker Hub + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Fetch values + id: fetch-data + run: | + date=$(date -u '+%Y-%m-%dT%H:%M:%SZ') + echo "date=$date" >> $GITHUB_OUTPUT + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v4 + with: + push: true + file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile + # TODO: The owner should be used below but buildx does not resolve the VARs + # TODO: It would be good to get rid of this GHA that we don't really need. + tags: | + parity/polkadot:latest + parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_apt_version }} + build-args: | + VCS_REF=${{ github.ref }} + POLKADOT_VERSION=${{ needs.fetch-latest-debian-package-version.outputs.polkadot_apt_version }} + BUILD_DATE=${{ steps.fetch-data.outputs.date }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile index e2c72dcfe2e..7ad092476fe 100644 --- a/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/ubuntu:20.04 +FROM docker.io/parity/base-bin # metadata ARG VCS_REF @@ -16,38 +16,29 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://github.com/paritytech/polkadot/" +USER root + # show backtraces ENV RUST_BACKTRACE 1 -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - libssl1.1 \ - ca-certificates \ - gnupg && \ - useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ -# add repo's gpg keys and install the published polkadot binary - gpg --keyserver ${GPG_KEYSERVER} --recv-keys ${POLKADOT_GPGKEY} && \ - gpg --export ${POLKADOT_GPGKEY} > /usr/share/keyrings/parity.gpg && \ - echo 'deb [signed-by=/usr/share/keyrings/parity.gpg] https://releases.parity.io/deb release main' > /etc/apt/sources.list.d/parity.list && \ +RUN \ apt-get update && \ apt-get install -y --no-install-recommends polkadot=${POLKADOT_VERSION#?} && \ -# apt cleanup apt-get autoremove -y && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* ; \ mkdir -p /data /polkadot/.local/share && \ - chown -R polkadot:polkadot /data && \ + chown -R parity:parity /data && \ ln -s /data /polkadot/.local/share/polkadot -USER polkadot +USER parity # check if executable works in this container RUN /usr/bin/polkadot --version -RUN /usr/bin/polkadot-execute-worker --version -RUN /usr/bin/polkadot-prepare-worker --version +RUN /usr/lib/polkadot/polkadot-execute-worker --version +RUN /usr/lib/polkadot/polkadot-prepare-worker --version -EXPOSE 30333 9933 9944 +EXPOSE 30333 9933 9944 9615 VOLUME ["/polkadot"] ENTRYPOINT ["/usr/bin/polkadot"] -- GitLab From 0bebc8ae96523a2109cad5c60cc4fb3cfea83d59 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:18:12 +0300 Subject: [PATCH 142/633] Update trie-db version to 0.28.0 (#1522) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates: - trie-db from 0.27.1 to 0.28.0 - trie-bench from 0.37.0 to 0.38.0 (deb-dependency) While at it, also adapts the recorder to take into account the newly added `TrieAccess::InlineValue`. Needed by: - https://github.com/paritytech/polkadot-sdk/pull/1153 @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher --- Cargo.lock | 8 ++++---- bridges/primitives/runtime/Cargo.toml | 2 +- cumulus/pallets/parachain-system/Cargo.toml | 2 +- substrate/primitives/state-machine/Cargo.toml | 2 +- substrate/primitives/trie/Cargo.toml | 4 ++-- substrate/primitives/trie/src/recorder.rs | 11 +++++++++++ substrate/test-utils/runtime/Cargo.toml | 2 +- .../frame/rpc/state-trie-migration-rpc/Cargo.toml | 2 +- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5323165e761..40cf78b1008 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19024,9 +19024,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f54b4f9d51d368e62cf7e0730c7c1e18fc658cc84333656bab5b328f44aa964" +checksum = "a4680cb226e31d2a096592d0edecdda91cc371743002f80c0f8cf80219819b3b" dependencies = [ "criterion 0.4.0", "hash-db", @@ -19040,9 +19040,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767abe6ffed88a1889671a102c2861ae742726f52e0a5a425b92c9fbfa7e9c85" +checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642" dependencies = [ "hash-db", "hashbrown 0.13.2", diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index ef8d2b8b40d..6e2762bc118 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } -trie-db = { version = "0.27.1", default-features = false } +trie-db = { version = "0.28.0", default-features = false } [dev-dependencies] hex-literal = "0.4" diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 3063083c0ee..5470dce4748 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -11,7 +11,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" log = { version = "0.4.20", default-features = false } -trie-db = { version = "0.27.1", default-features = false } +trie-db = { version = "0.28.0", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } # Substrate diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index 8546345e5ca..ec5d9b5ea14 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -27,7 +27,7 @@ sp-externalities = { path = "../externalities", default-features = false} sp-panic-handler = { path = "../panic-handler", optional = true} sp-std = { path = "../std", default-features = false} sp-trie = { path = "../trie", default-features = false} -trie-db = { version = "0.27.1", default-features = false } +trie-db = { version = "0.28.0", default-features = false } [dev-dependencies] array-bytes = "6.1" diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 0bce597414b..0b54514f600 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -29,7 +29,7 @@ parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } -trie-db = { version = "0.27.0", default-features = false } +trie-db = { version = "0.28.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } sp-core = { path = "../core", default-features = false} sp-std = { path = "../std", default-features = false} @@ -38,7 +38,7 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "6.1" criterion = "0.4.0" -trie-bench = "0.37.0" +trie-bench = "0.38.0" trie-standardmap = "0.16.0" sp-runtime = { path = "../runtime" } diff --git a/substrate/primitives/trie/src/recorder.rs b/substrate/primitives/trie/src/recorder.rs index 728dc836205..154cee3f37d 100644 --- a/substrate/primitives/trie/src/recorder.rs +++ b/substrate/primitives/trie/src/recorder.rs @@ -379,6 +379,17 @@ impl>> trie_db::TrieRecord // that the value doesn't exist in the trie. self.update_recorded_keys(full_key, RecordedForKey::Value); }, + TrieAccess::InlineValue { full_key } => { + tracing::trace!( + target: LOG_TARGET, + key = ?sp_core::hexdisplay::HexDisplay::from(&full_key), + "Recorded inline value access for key", + ); + + // A value was accessed that is stored inline a node and we recorded all trie nodes + // to access this value. + self.update_recorded_keys(full_key, RecordedForKey::Value); + }, }; self.encoded_size_estimation.fetch_add(encoded_size_update, Ordering::Relaxed); diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 4f6c47307ea..9921d6b1c06 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -40,7 +40,7 @@ pallet-timestamp = { path = "../../frame/timestamp", default-features = false} sp-consensus-grandpa = { path = "../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } sp-trie = { path = "../../primitives/trie", default-features = false} sp-transaction-pool = { path = "../../primitives/transaction-pool", default-features = false} -trie-db = { version = "0.27.0", default-features = false } +trie-db = { version = "0.28.0", default-features = false } sc-service = { path = "../../client/service", default-features = false, features = ["test-helpers"], optional = true} sp-state-machine = { path = "../../primitives/state-machine", default-features = false} sp-externalities = { path = "../../primitives/externalities", default-features = false} diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index d82377593c7..8ce9d06c2d1 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1", features = ["derive"] } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } -trie-db = "0.27.0" +trie-db = "0.28.0" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -- GitLab From 61be78c621ab2fa390cd3bfc79c8307431d0ea90 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 13 Sep 2023 13:32:39 +0200 Subject: [PATCH 143/633] Bandersnatch tweaks after backend update (#1482) --- Cargo.lock | 16 +- substrate/primitives/core/Cargo.toml | 4 +- substrate/primitives/core/src/bandersnatch.rs | 205 +++++++++--------- 3 files changed, 114 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40cf78b1008..944cd153f66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,7 +513,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" +source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" dependencies = [ "ark-ec", "ark-ff", @@ -561,7 +561,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" +source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" dependencies = [ "ark-ff", "ark-serialize", @@ -1240,13 +1240,12 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" version = "0.0.1" -source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" +source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" dependencies = [ "ark-bls12-381", "ark-ec", "ark-ed-on-bls12-381-bandersnatch", "ark-ff", - "ark-scale", "ark-serialize", "ark-std", "dleq_vrf", @@ -2704,7 +2703,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213" +source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895" dependencies = [ "ark-ec", "ark-ff", @@ -2713,6 +2712,7 @@ dependencies = [ "ark-std", "fflonk", "merlin 3.0.0", + "rand_chacha 0.3.1", ] [[package]] @@ -4424,7 +4424,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1" +source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" dependencies = [ "ark-ec", "ark-ff", @@ -13961,13 +13961,14 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213" +source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895" dependencies = [ "ark-ec", "ark-ff", "ark-poly", "ark-serialize", "ark-std", + "blake2", "common", "fflonk", "merlin 3.0.0", @@ -16971,7 +16972,6 @@ name = "sp-core" version = "21.0.0" dependencies = [ "array-bytes", - "arrayvec 0.7.4", "bandersnatch_vrfs", "bitflags 1.3.2", "blake2", diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 4e5186f1687..9f1f0127d7c 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -13,7 +13,6 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -arrayvec = { version = "0.7.2", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } @@ -58,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 = "3119f51", default-features = false, optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "f4fe253", default-features = false, optional = true } [dev-dependencies] criterion = "0.4.0" @@ -76,7 +75,6 @@ bench = false default = [ "std" ] std = [ "array-bytes", - "arrayvec/std", "bandersnatch_vrfs/getrandom", "blake2/std", "bounded-collections/std", diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 01f3538188a..832ef6c77bb 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -53,9 +53,8 @@ const SEED_SERIALIZED_LEN: usize = 32; // Short-Weierstrass form serialized sizes. const PUBLIC_SERIALIZED_LEN: usize = 33; const SIGNATURE_SERIALIZED_LEN: usize = 65; +const RING_SIGNATURE_SERIALIZED_LEN: usize = 755; const PREOUT_SERIALIZED_LEN: usize = 33; -const PEDERSEN_SIGNATURE_SERIALIZED_LEN: usize = 163; -const RING_PROOF_SERIALIZED_LEN: usize = 592; // Max size of serialized ring-vrf context params. // @@ -69,7 +68,7 @@ const RING_PROOF_SERIALIZED_LEN: usize = 592; // 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 = 147752; +const RING_CONTEXT_SERIALIZED_LEN: usize = 147748; /// Bandersnatch public key. #[cfg_attr(feature = "full_crypto", derive(Hash))] @@ -278,7 +277,7 @@ impl TraitPair for Pair { let mut raw = [0; PUBLIC_SERIALIZED_LEN]; public .serialize_compressed(raw.as_mut_slice()) - .expect("key buffer length is good; qed"); + .expect("serialization length is constant and checked by test; qed"); Public::unchecked_from(raw) } @@ -356,7 +355,7 @@ pub mod vrf { let mut bytes = [0; PREOUT_SERIALIZED_LEN]; self.0 .serialize_compressed(bytes.as_mut_slice()) - .expect("preout serialization can't fail"); + .expect("serialization length is constant and checked by test; qed"); bytes.encode() } } @@ -506,7 +505,7 @@ pub mod vrf { } fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput { - let output = self.secret.0.vrf_preout(&input.0); + let output = self.secret.vrf_preout(&input.0); VrfOutput(output) } } @@ -539,24 +538,26 @@ pub mod vrf { #[cfg(feature = "full_crypto")] impl Pair { fn vrf_sign_gen(&self, data: &VrfSignData) -> VrfSignature { - let ios: Vec<_> = data - .inputs - .iter() - .map(|i| self.secret.clone().0.vrf_inout(i.0.clone())) - .collect(); + let ios = core::array::from_fn(|i| { + let input = data.inputs[i].0.clone(); + self.secret.vrf_inout(input) + }); - let signature: ThinVrfSignature = - self.secret.sign_thin_vrf(data.transcript.clone(), ios.as_slice()); + let thin_signature: ThinVrfSignature = + self.secret.sign_thin_vrf(data.transcript.clone(), &ios); - let mut sign_bytes = [0; SIGNATURE_SERIALIZED_LEN]; - signature - .signature - .serialize_compressed(sign_bytes.as_mut_slice()) - .expect("serialization can't fail"); - - let outputs: Vec<_> = signature.preoutputs.into_iter().map(VrfOutput).collect(); + let outputs: Vec<_> = thin_signature.preouts.into_iter().map(VrfOutput).collect(); let outputs = VrfIosVec::truncate_from(outputs); - VrfSignature { signature: Signature(sign_bytes), outputs } + + let mut signature = + VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_LEN]), outputs }; + + thin_signature + .proof + .serialize_compressed(signature.signature.0.as_mut_slice()) + .expect("serialization length is constant and checked by test; qed"); + + signature } /// Generate an arbitrary number of bytes from the given `context` and VRF `input`. @@ -566,7 +567,7 @@ pub mod vrf { input: &VrfInput, ) -> [u8; N] { let transcript = Transcript::new_labeled(context); - let inout = self.secret.clone().0.vrf_inout(input.0.clone()); + let inout = self.secret.vrf_inout(input.0.clone()); inout.vrf_output_bytes(transcript) } } @@ -581,30 +582,23 @@ pub mod vrf { return false }; - let Ok(preouts) = signature - .outputs - .iter() - .map(|o| o.0.clone()) - .collect::>() - .into_inner() - else { - return false - }; + let preouts: [bandersnatch_vrfs::VrfPreOut; N] = + core::array::from_fn(|i| signature.outputs[i].0.clone()); // Deserialize only the proof, the rest has already been deserialized // This is another hack used because backend signature type is generic over // the number of ios. - let Ok(signature) = + let Ok(proof) = ThinVrfSignature::<0>::deserialize_compressed(signature.signature.as_ref()) - .map(|s| s.signature) + .map(|s| s.proof) else { return false }; - let signature = ThinVrfSignature { signature, preoutputs: preouts }; + let signature = ThinVrfSignature { proof, preouts }; let inputs = data.inputs.iter().map(|i| i.0.clone()); - signature.verify_thin_vrf(data.transcript.clone(), inputs, &public).is_ok() + public.verify_thin_vrf(data.transcript.clone(), inputs, &signature).is_ok() } } @@ -627,7 +621,7 @@ pub mod vrf { pub mod ring_vrf { use super::{vrf::*, *}; pub use bandersnatch_vrfs::ring::{RingProof, RingProver, RingVerifier, KZG}; - use bandersnatch_vrfs::{CanonicalDeserialize, PedersenVrfSignature, PublicKey}; + use bandersnatch_vrfs::{CanonicalDeserialize, PublicKey}; /// Context used to produce ring signatures. #[derive(Clone)] @@ -649,7 +643,7 @@ pub mod ring_vrf { let mut pks = Vec::with_capacity(public_keys.len()); for public_key in public_keys { let pk = PublicKey::deserialize_compressed(public_key.as_slice()).ok()?; - pks.push(pk.0 .0.into()); + pks.push(pk.0.into()); } let prover_key = self.0.prover_key(pks); @@ -662,7 +656,7 @@ pub mod ring_vrf { let mut pks = Vec::with_capacity(public_keys.len()); for public_key in public_keys { let pk = PublicKey::deserialize_compressed(public_key.as_slice()).ok()?; - pks.push(pk.0 .0.into()); + pks.push(pk.0.into()); } let verifier_key = self.0.verifier_key(pks); @@ -676,7 +670,7 @@ pub mod ring_vrf { let mut buf = Box::new([0; RING_CONTEXT_SERIALIZED_LEN]); self.0 .serialize_compressed(buf.as_mut_slice()) - .expect("preout serialization can't fail"); + .expect("serialization length is constant and checked by test; qed"); buf.encode() } } @@ -711,10 +705,8 @@ pub mod ring_vrf { pub struct RingVrfSignature { /// VRF (pre)outputs. pub outputs: VrfIosVec, - /// Pedersen VRF signature. - pub signature: [u8; PEDERSEN_SIGNATURE_SERIALIZED_LEN], - /// Ring proof. - pub ring_proof: [u8; RING_PROOF_SERIALIZED_LEN], + /// Ring signature. + pub signature: [u8; RING_SIGNATURE_SERIALIZED_LEN], } #[cfg(feature = "full_crypto")] @@ -741,31 +733,27 @@ pub mod ring_vrf { data: &VrfSignData, prover: &RingProver, ) -> RingVrfSignature { - let ios: Vec<_> = data - .inputs - .iter() - .map(|i| self.secret.clone().0.vrf_inout(i.0.clone())) - .collect(); + let ios = core::array::from_fn(|i| { + let input = data.inputs[i].0.clone(); + self.secret.vrf_inout(input) + }); let ring_signature: bandersnatch_vrfs::RingVrfSignature = - self.secret.sign_ring_vrf(data.transcript.clone(), ios.as_slice(), prover); + bandersnatch_vrfs::RingProver { ring_prover: prover, secret: &self.secret } + .sign_ring_vrf(data.transcript.clone(), &ios); - let outputs: Vec<_> = ring_signature.preoutputs.into_iter().map(VrfOutput).collect(); + let outputs: Vec<_> = ring_signature.preouts.into_iter().map(VrfOutput).collect(); let outputs = VrfIosVec::truncate_from(outputs); - let mut signature = [0; PEDERSEN_SIGNATURE_SERIALIZED_LEN]; - ring_signature - .signature - .serialize_compressed(signature.as_mut_slice()) - .expect("ped-signature serialization can't fail"); + let mut signature = + RingVrfSignature { outputs, signature: [0; RING_SIGNATURE_SERIALIZED_LEN] }; - let mut ring_proof = [0; RING_PROOF_SERIALIZED_LEN]; ring_signature - .ring_proof - .serialize_compressed(ring_proof.as_mut_slice()) - .expect("ring-proof serialization can't fail"); + .proof + .serialize_compressed(signature.signature.as_mut_slice()) + .expect("serialization length is constant and checked by test; qed"); - RingVrfSignature { outputs, signature, ring_proof } + signature } } @@ -774,7 +762,7 @@ pub mod ring_vrf { /// /// The signature is verifiable if it has been produced by a member of the ring /// from which the [`RingVerifier`] has been constructed. - pub fn verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { + pub fn ring_vrf_verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); let preouts_len = self.outputs.len(); if preouts_len != data.inputs.len() { @@ -782,43 +770,37 @@ pub mod ring_vrf { } // Workaround to overcome backend signature generic over the number of IOs. match preouts_len { - 0 => self.verify_gen::<0>(data, verifier), - 1 => self.verify_gen::<1>(data, verifier), - 2 => self.verify_gen::<2>(data, verifier), - 3 => self.verify_gen::<3>(data, verifier), + 0 => self.ring_vrf_verify_gen::<0>(data, verifier), + 1 => self.ring_vrf_verify_gen::<1>(data, verifier), + 2 => self.ring_vrf_verify_gen::<2>(data, verifier), + 3 => self.ring_vrf_verify_gen::<3>(data, verifier), _ => unreachable!(), } } - fn verify_gen(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { - let Ok(preoutputs) = self - .outputs - .iter() - .map(|o| o.0.clone()) - .collect::>() - .into_inner() - else { - return false - }; - - let Ok(signature) = - PedersenVrfSignature::deserialize_compressed(self.signature.as_slice()) + fn ring_vrf_verify_gen( + &self, + data: &VrfSignData, + verifier: &RingVerifier, + ) -> bool { + let Ok(vrf_signature) = + bandersnatch_vrfs::RingVrfSignature::<0>::deserialize_compressed( + self.signature.as_slice(), + ) else { return false }; - let Ok(ring_proof) = RingProof::deserialize_compressed(self.ring_proof.as_slice()) - else { - return false - }; + let preouts: [bandersnatch_vrfs::VrfPreOut; N] = + core::array::from_fn(|i| self.outputs[i].0.clone()); - let ring_signature = - bandersnatch_vrfs::RingVrfSignature { signature, preoutputs, ring_proof }; + let signature = + bandersnatch_vrfs::RingVrfSignature { proof: vrf_signature.proof, preouts }; let inputs = data.inputs.iter().map(|i| i.0.clone()); - ring_signature - .verify_ring_vrf(data.transcript.clone(), inputs, verifier) + bandersnatch_vrfs::RingVerifier(verifier) + .verify_ring_vrf(data.transcript.clone(), inputs, &signature) .is_ok() } } @@ -840,16 +822,41 @@ mod tests { } #[test] - fn assumptions_sanity_check() { - // Backend - let ring_ctx = RingContext::new_testing(); - let pair = SecretKey::from_seed(DEV_SEED); - let public = pair.to_public(); + fn backend_assumptions_sanity_check() { + let kzg = KZG::testing_kzg_setup([0; 32], RING_DOMAIN_SIZE as u32); + assert_eq!(kzg.max_keyset_size(), RING_DOMAIN_SIZE - 257); + assert_eq!(kzg.compressed_size(), RING_CONTEXT_SERIALIZED_LEN); + + let pks: Vec<_> = (0..16) + .map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into()) + .collect(); - assert_eq!(public.0.size_of_serialized(), PUBLIC_SERIALIZED_LEN); - assert_eq!(ring_ctx.max_keyset_size(), RING_DOMAIN_SIZE - 257); + let secret = SecretKey::from_seed(&[0u8; 32]); - // Wrapper + let public = secret.to_public(); + assert_eq!(public.compressed_size(), PUBLIC_SERIALIZED_LEN); + + let input = VrfInput::new(b"foo", &[]); + let preout = secret.vrf_preout(&input.0); + assert_eq!(preout.compressed_size(), PREOUT_SERIALIZED_LEN); + + let prover_key = kzg.prover_key(pks); + let ring_prover = kzg.init_ring_prover(prover_key, 0); + + let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], None); + + let thin_signature: bandersnatch_vrfs::ThinVrfSignature<0> = + secret.sign_thin_vrf(data.transcript.clone(), &[]); + assert_eq!(thin_signature.compressed_size(), SIGNATURE_SERIALIZED_LEN); + + let ring_signature: bandersnatch_vrfs::RingVrfSignature<0> = + bandersnatch_vrfs::RingProver { ring_prover: &ring_prover, secret: &secret } + .sign_ring_vrf(data.transcript.clone(), &[]); + assert_eq!(ring_signature.compressed_size(), RING_SIGNATURE_SERIALIZED_LEN); + } + + #[test] + fn max_vrf_ios_bound_respected() { let inputs: Vec<_> = (0..MAX_VRF_IOS - 1).map(|_| VrfInput::new(b"", &[])).collect(); let mut sign_data = VrfSignData::new(b"", &[b""], inputs).unwrap(); let res = sign_data.push_vrf_input(VrfInput::new(b"", b"")); @@ -987,7 +994,7 @@ mod tests { let signature = pair.ring_vrf_sign(&data, &prover); let verifier = ring_ctx.verifier(&pks).unwrap(); - assert!(signature.verify(&data, &verifier)); + assert!(signature.ring_vrf_verify(&data, &verifier)); } #[test] @@ -1006,7 +1013,7 @@ mod tests { let signature = pair.ring_vrf_sign(&data, &prover); let verifier = ring_ctx.verifier(&pks).unwrap(); - assert!(!signature.verify(&data, &verifier)); + assert!(!signature.ring_vrf_verify(&data, &verifier)); } #[test] @@ -1062,10 +1069,8 @@ mod tests { let bytes = expected.encode(); - let expected_len = data.inputs.len() * PREOUT_SERIALIZED_LEN + - PEDERSEN_SIGNATURE_SERIALIZED_LEN + - RING_PROOF_SERIALIZED_LEN + - 1; + let expected_len = + data.inputs.len() * PREOUT_SERIALIZED_LEN + RING_SIGNATURE_SERIALIZED_LEN + 1; assert_eq!(bytes.len(), expected_len); let decoded = RingVrfSignature::decode(&mut bytes.as_slice()).unwrap(); -- GitLab From f1994c8690baa7f718f3fc5a351c8c6c9661e156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 13 Sep 2023 21:53:05 +0200 Subject: [PATCH 144/633] wasm-builder: Disable building when running on docs.rs (#1540) This pull request changes the `wasm-builder` to skip building the wasm files when the build process is running on docs.rs. --- substrate/utils/wasm-builder/src/builder.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index 208b5607766..e0a30644b23 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -203,7 +203,10 @@ fn generate_crate_skip_build_env_name() -> String { /// Checks if the build of the WASM binary should be skipped. fn check_skip_build() -> bool { env::var(crate::SKIP_BUILD_ENV).is_ok() || - env::var(generate_crate_skip_build_env_name()).is_ok() + env::var(generate_crate_skip_build_env_name()).is_ok() || + // If we are running in docs.rs, let's skip building. + // https://docs.rs/about/builds#detecting-docsrs + env::var("DOCS_RS").is_ok() } /// Provide a dummy WASM binary if there doesn't exist one. -- GitLab From cc39edd5a84ce14f5a5bfbf3cb949086d18e2c87 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 14 Sep 2023 10:25:50 +1000 Subject: [PATCH 145/633] Add tolerance to nom pool pending rewards try-state (#1236) Closes https://github.com/paritytech/polkadot-sdk/issues/158 In our last FRAME call it was discussed that a likely solution to the ED imbalances is lazily fixing the pools as they are interacted with. So, we should add some tiny tolerance to the try-state checks so next time there's an ED change they don't start failing until they've all been interacted with. ### Update 12 Sept Rather than adding tolerance, have replaced the `ensure` with a warning. --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/nomination-pools/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index c4bebc5a1d0..485cdada717 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -3134,6 +3134,10 @@ impl Pallet { // reward math rounds down, we might accumulate some dust here. 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 !pending_rewards_lt_leftover_bal { log::warn!( "pool {:?}, sum pending rewards = {:?}, remaining balance = {:?}", @@ -3142,10 +3146,6 @@ impl Pallet { RewardPool::::current_balance(id) ); } - ensure!( - pending_rewards_lt_leftover_bal, - "The sum of the pending rewards must be less than the leftover balance." - ); Ok(()) })?; -- GitLab From bdb3f98d8e7067d1a5b321acdf342a9c131efc1d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 14 Sep 2023 10:31:24 +0300 Subject: [PATCH 146/633] frame/beefy: add privileged call to reset BEEFY consensus (#1534) We want to be able to (re)set BEEFY genesis in order to (re)start BEEFY consensus on chains which didn't run it since genesis. This commit adds privileged helper call to (re)set BEEFY genesis to some block in the future. Signed-off-by: Adrian Catangiu --- substrate/frame/beefy/src/default_weights.rs | 4 +++ substrate/frame/beefy/src/lib.rs | 30 ++++++++++++++++---- substrate/frame/beefy/src/tests.rs | 22 ++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/substrate/frame/beefy/src/default_weights.rs b/substrate/frame/beefy/src/default_weights.rs index 091d58f47f9..8042f0c932e 100644 --- a/substrate/frame/beefy/src/default_weights.rs +++ b/substrate/frame/beefy/src/default_weights.rs @@ -49,4 +49,8 @@ impl crate::WeightInfo for () { // fetching set id -> session index mappings .saturating_add(DbWeight::get().reads(2)) } + + fn set_new_genesis() -> Weight { + DbWeight::get().writes(1) + } } diff --git a/substrate/frame/beefy/src/lib.rs b/substrate/frame/beefy/src/lib.rs index 77e74436dd6..0760446753a 100644 --- a/substrate/frame/beefy/src/lib.rs +++ b/substrate/frame/beefy/src/lib.rs @@ -33,7 +33,7 @@ use frame_system::{ use log; use sp_runtime::{ generic::DigestItem, - traits::{IsMember, Member}, + traits::{IsMember, Member, One}, RuntimeAppPublic, }; use sp_session::{GetSessionNumber, GetValidatorCount}; @@ -62,7 +62,7 @@ const LOG_TARGET: &str = "runtime::beefy"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_system::pallet_prelude::BlockNumberFor; + use frame_system::{ensure_root, pallet_prelude::BlockNumberFor}; #[pallet::config] pub trait Config: frame_system::Config { @@ -152,8 +152,8 @@ pub mod pallet { StorageMap<_, Twox64Concat, sp_consensus_beefy::ValidatorSetId, SessionIndex>; /// Block number where BEEFY consensus is enabled/started. - /// By changing this (through governance or sudo), BEEFY consensus is effectively - /// restarted from the new block number. + /// By changing this (through privileged `set_new_genesis()`), BEEFY consensus is effectively + /// restarted from the newly set block number. #[pallet::storage] #[pallet::getter(fn genesis_block)] pub(super) type GenesisBlock = @@ -174,7 +174,7 @@ pub mod pallet { fn default() -> Self { // BEEFY genesis will be first BEEFY-MANDATORY block, // use block number one instead of chain-genesis. - let genesis_block = Some(sp_runtime::traits::One::one()); + let genesis_block = Some(One::one()); Self { authorities: Vec::new(), genesis_block } } } @@ -198,6 +198,8 @@ pub mod pallet { InvalidEquivocationProof, /// A given equivocation report is valid but already previously reported. DuplicateOffenceReport, + /// Submitted configuration is invalid. + InvalidConfiguration, } #[pallet::call] @@ -265,6 +267,23 @@ pub mod pallet { )?; Ok(Pays::No.into()) } + + /// Reset BEEFY consensus by setting a new BEEFY genesis at `delay_in_blocks` blocks in the + /// future. + /// + /// Note: `delay_in_blocks` has to be at least 1. + #[pallet::call_index(2)] + #[pallet::weight(::WeightInfo::set_new_genesis())] + pub fn set_new_genesis( + origin: OriginFor, + delay_in_blocks: BlockNumberFor, + ) -> DispatchResult { + ensure_root(origin)?; + ensure!(delay_in_blocks >= One::one(), Error::::InvalidConfiguration); + let genesis_block = frame_system::Pallet::::block_number() + delay_in_blocks; + GenesisBlock::::put(Some(genesis_block)); + Ok(()) + } } #[pallet::validate_unsigned] @@ -452,4 +471,5 @@ impl IsMember for Pallet { pub trait WeightInfo { fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight; + fn set_new_genesis() -> Weight; } diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index e04dc330d0c..bf1b204e026 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -791,3 +791,25 @@ fn valid_equivocation_reports_dont_pay_fees() { assert_eq!(post_info.pays_fee, Pays::Yes); }) } + +#[test] +fn set_new_genesis_works() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let new_genesis_delay = 10u64; + // the call for setting new genesis should work + assert_ok!(Beefy::set_new_genesis(RuntimeOrigin::root(), new_genesis_delay,)); + let expected = System::block_number() + new_genesis_delay; + // verify new genesis was set + assert_eq!(Beefy::genesis_block(), Some(expected)); + + // setting delay < 1 should fail + assert_err!( + Beefy::set_new_genesis(RuntimeOrigin::root(), 0u64,), + Error::::InvalidConfiguration, + ); + }); +} -- GitLab From 76724ce9471bf4d08dc737164c7bbb29d85eb838 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 14 Sep 2023 10:00:52 +0200 Subject: [PATCH 147/633] [xcm_builder]: Do not consume `msg` on `NotApplicable` for remote exporters (#1519) ## Summary Implementations of `SendXcm`'s `validate` should not consume `dest` and/or `msg` parameters in case of `NotApplicable` error. This commit aligns expected behavior for `UnpaidRemoteExporter` and `SovereignPaidRemoteExporter`. ## Testing Added `remote_exporters_does_not_consume_dest_or_msg_on_not_applicable` test which checks two possible cases: - `dest` is local - no configured exporter for `dest` --- .../xcm/xcm-builder/src/universal_exports.rs | 101 ++++++++++++++++-- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 0ee627e0ee9..d1b8c8c721f 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -163,15 +163,19 @@ impl, - xcm: &mut Option>, + msg: &mut Option>, ) -> SendResult { let d = dest.ok_or(MissingArgument)?; let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?; let (remote_network, remote_location) = devolved; - let xcm = xcm.take().ok_or(MissingArgument)?; + let xcm = msg.take().ok_or(MissingArgument)?; - let (bridge, maybe_payment) = - Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?; + // find exporter + let Some((bridge, maybe_payment)) = Bridges::exporter_for(&remote_network, &remote_location, &xcm) else { + // We need to make sure that msg is not consumed in case of `NotApplicable`. + *msg = Some(xcm); + return Err(SendError::NotApplicable) + }; ensure!(maybe_payment.is_none(), Unroutable); // `xcm` should already end with `SetTopic` - if it does, then extract and derive into @@ -224,13 +228,19 @@ impl, - xcm: &mut Option>, + msg: &mut Option>, ) -> SendResult { let d = *dest.as_ref().ok_or(MissingArgument)?; let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?; let (remote_network, remote_location) = devolved; + let xcm = msg.take().ok_or(MissingArgument)?; - let xcm = xcm.take().ok_or(MissingArgument)?; + // find exporter + let Some((bridge, maybe_payment)) = Bridges::exporter_for(&remote_network, &remote_location, &xcm) else { + // We need to make sure that msg is not consumed in case of `NotApplicable`. + *msg = Some(xcm); + return Err(SendError::NotApplicable) + }; // `xcm` should already end with `SetTopic` - if it does, then extract and derive into // an onward topic ID. @@ -239,9 +249,6 @@ impl None, }; - let (bridge, maybe_payment) = - Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?; - let local_from_bridge = UniversalLocation::get().invert_target(&bridge).map_err(|_| Unroutable)?; let export_instruction = @@ -452,4 +459,80 @@ mod tests { let x = ensure_is_remote((), (Parent, Polkadot, Parachain(1000))); assert_eq!(x, Err((Parent, Polkadot, Parachain(1000)).into())); } + + pub struct OkSender; + impl SendXcm for OkSender { + type Ticket = (); + + fn validate( + _destination: &mut Option, + _message: &mut Option>, + ) -> SendResult { + Ok(((), MultiAssets::new())) + } + + fn deliver(_ticket: Self::Ticket) -> Result { + Ok([0; 32]) + } + } + + /// Generic test case asserting that dest and msg is not consumed by `validate` implementation + /// of `SendXcm` in case of expected result. + fn ensure_validate_does_not_consume_dest_or_msg( + dest: MultiLocation, + assert_result: impl Fn(SendResult), + ) { + let mut dest_wrapper = Some(dest); + let msg = Xcm::<()>::new(); + let mut msg_wrapper = Some(msg.clone()); + + assert_result(S::validate(&mut dest_wrapper, &mut msg_wrapper)); + + // ensure dest and msg are untouched + assert_eq!(Some(dest), dest_wrapper); + assert_eq!(Some(msg), msg_wrapper); + } + + #[test] + fn remote_exporters_does_not_consume_dest_or_msg_on_not_applicable() { + frame_support::parameter_types! { + pub Local: NetworkId = ByGenesis([0; 32]); + pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234)); + pub DifferentRemote: NetworkId = ByGenesis([22; 32]); + // no routers + pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> = vec![]; + } + + // check with local destination (should be remote) + let local_dest = (Parent, Parachain(5678)).into(); + assert!(ensure_is_remote(UniversalLocation::get(), local_dest).is_err()); + + ensure_validate_does_not_consume_dest_or_msg::< + UnpaidRemoteExporter, OkSender, UniversalLocation>, + >(local_dest, |result| assert_eq!(Err(NotApplicable), result)); + + ensure_validate_does_not_consume_dest_or_msg::< + SovereignPaidRemoteExporter< + NetworkExportTable, + OkSender, + UniversalLocation, + >, + >(local_dest, |result| assert_eq!(Err(NotApplicable), result)); + + // check with not applicable destination + let remote_dest = (Parent, Parent, DifferentRemote::get()).into(); + assert!(ensure_is_remote(UniversalLocation::get(), remote_dest).is_ok()); + + ensure_validate_does_not_consume_dest_or_msg::< + UnpaidRemoteExporter, OkSender, UniversalLocation>, + >(remote_dest, |result| assert_eq!(Err(NotApplicable), result)); + + ensure_validate_does_not_consume_dest_or_msg::< + SovereignPaidRemoteExporter< + NetworkExportTable, + OkSender, + UniversalLocation, + >, + >(remote_dest, |result| assert_eq!(Err(NotApplicable), result)); + } } -- GitLab From 49c4b2014b10236fbb333dc22e29dbcca5f9aff5 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Thu, 14 Sep 2023 15:38:50 +0200 Subject: [PATCH 148/633] Enable `runtime-benchmarks` feature for crates (#1544) Enable `runtime-benchmarks` feature for `parachain-common` and `cumulus-primitives-utility` crates' dependencies. After adding `runtime-benchmarks = []` under `features` category in `Cargo.toml` files for the creates, I did run, > zepter lint propagate-feature --feature runtime-benchmarks --workspace --fix --feature-enables-dep="runtime-benchmarks:frame-benchmarking" This changes required for https://github.com/paritytech/polkadot-sdk/pull/1333 --- cumulus/parachain-template/runtime/Cargo.toml | 1 + cumulus/parachains/common/Cargo.toml | 14 ++++++++++++++ .../emulated/assets/asset-hub-kusama/Cargo.toml | 1 + .../emulated/assets/asset-hub-polkadot/Cargo.toml | 1 + .../emulated/assets/asset-hub-westend/Cargo.toml | 1 + .../integration-tests/emulated/common/Cargo.toml | 1 + .../runtimes/assets/asset-hub-kusama/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-polkadot/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-westend/Cargo.toml | 2 ++ .../parachains/runtimes/assets/common/Cargo.toml | 1 + .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 ++ .../bridge-hubs/bridge-hub-polkadot/Cargo.toml | 2 ++ .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 ++ .../collectives/collectives-polkadot/Cargo.toml | 2 ++ .../runtimes/contracts/contracts-rococo/Cargo.toml | 2 ++ .../runtimes/glutton/glutton-kusama/Cargo.toml | 1 + .../parachains/runtimes/testing/penpal/Cargo.toml | 2 ++ .../runtimes/testing/rococo-parachain/Cargo.toml | 2 ++ cumulus/polkadot-parachain/Cargo.toml | 1 + cumulus/primitives/utility/Cargo.toml | 8 ++++++++ cumulus/test/service/Cargo.toml | 1 + 21 files changed, 51 insertions(+) diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index f26b7be2353..4e51f16dca1 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -128,6 +128,7 @@ 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", diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 18cafde0d30..963de03fa16 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -79,3 +79,17 @@ std = [ "xcm-executor/std", "xcm/std", ] + +runtime-benchmarks = [ + "cumulus-primitives-utility/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-asset-tx-payment/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "polkadot-primitives/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-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index 4f17b1ac55b..788b2482be8 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -45,6 +45,7 @@ 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", 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 index ed383207228..023e8b84f11 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -44,6 +44,7 @@ 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", 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 0c60a30a0b9..80c41c24aa7 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 @@ -45,6 +45,7 @@ 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", diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 925d2fc1939..f1db26c2a54 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -80,6 +80,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 53555499842..1d0c7bc9856 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -100,6 +100,7 @@ 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", @@ -118,6 +119,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index dfc3d5416cc..4a6ce4cbf59 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -88,6 +88,7 @@ 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", @@ -105,6 +106,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 8c25842cbf3..f436ae9537f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -92,6 +92,7 @@ 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", @@ -110,6 +111,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index a8b5f3f8c6b..0cd5de2ddcd 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -56,6 +56,7 @@ runtime-benchmarks = [ "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", 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 91eb7adc61f..67c3fa37df0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -137,6 +137,7 @@ 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", @@ -148,6 +149,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", 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 52a866b7097..77923ee74f8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -137,6 +137,7 @@ 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", @@ -148,6 +149,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", 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 395edafa651..70c62d1a34f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -173,6 +173,7 @@ 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", @@ -188,6 +189,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 1f17a0ef0e6..167f460610d 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -87,6 +87,7 @@ 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", @@ -106,6 +107,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 2e298e05ec7..f6fccc04354 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -138,6 +138,7 @@ 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", @@ -151,6 +152,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 0caf00340d3..2e2975ab87b 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -55,6 +55,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-glutton/runtime-benchmarks", "pallet-sudo?/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 99caf2f27d0..547695e7621 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -135,6 +135,7 @@ 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", @@ -147,6 +148,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 863b9edd725..54055ca732b 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -105,6 +105,7 @@ std = [ runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -113,6 +114,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 8c250300cc8..ab32a820745 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -116,6 +116,7 @@ runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "glutton-runtime/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 47c5442574f..9ed1e664ac2 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -38,3 +38,11 @@ std = [ "xcm-executor/std", "xcm/std", ] + +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index a2932cf755f..b8469cb66a7 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -101,6 +101,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-service/runtime-benchmarks", -- GitLab From 756347ab24bc19bd93960a7247394fab01332c38 Mon Sep 17 00:00:00 2001 From: Maciej Date: Thu, 14 Sep 2023 20:40:19 +0100 Subject: [PATCH 149/633] Inclusion pruning tweaks (#1550) In follow-up to https://github.com/paritytech/polkadot-sdk/pull/1518 Adding extra tests for inclusion pruning. Primarily focusing on various cases surrounding candidates included in different forks (with different relay parents). All cases fall into a few buckets based on 3 degrees of freedom - number of candidates, number of blocks (height), number of forks + extra case for pruning multiple heights at once. Added small tweak to the original pruning function to disregard stale candidate duplicates which should keep the same behaviour. --------- Co-authored-by: Tsvetomir Dimitrov --- .../dispute-coordinator/src/scraping/mod.rs | 8 +- .../dispute-coordinator/src/scraping/tests.rs | 439 +++++++++++++++--- 2 files changed, 384 insertions(+), 63 deletions(-) diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs index 58f409b9311..fdf39cff0f2 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs @@ -117,13 +117,11 @@ impl Inclusions { self.candidates_by_block_number = not_stale; for candidate in stale.into_values().flatten() { - debug_assert!(self.inclusions_inner.get(&candidate).is_some()); match self.inclusions_inner.entry(candidate) { Entry::Vacant(_) => { - gum::debug!( - target: LOG_TARGET, - "Inconsistency in `Inclusions` detected on pruning!" - ); + // Rare case where same candidate was present on multiple heights, but all are + // pruned at the same time. This candidate was already pruned in the previous + // occurence so it is skipped now. }, Entry::Occupied(mut e) => { let mut blocks_including = std::mem::take(e.get_mut()); diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs index 0a971ad5d1d..748f9a16f49 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs @@ -149,6 +149,11 @@ fn get_block_number_hash(n: BlockNumber) -> Hash { BlakeTwo256::hash(&n.encode()) } +// Creates a dummy relay chain block hash with the convention of hash(b). +fn get_relay_block_hash(height: BlockNumber, fork: u32) -> Hash { + BlakeTwo256::hash(&format!("b_{}_{}", height, fork).encode()) +} + /// Get a dummy event that corresponds to candidate inclusion for the given block number. fn get_backed_and_included_candidate_events(block_number: BlockNumber) -> Vec { let candidate_receipt = make_candidate_receipt(get_block_number_hash(block_number)); @@ -760,59 +765,6 @@ fn inclusions_get() { } } -#[test] -fn inclusions_iterative_removal() { - let mut inclusions = Inclusions::new(); - - // Insert 3 candidates in the specified blocks - let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); - let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); - let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); - let candidate4 = make_candidate_receipt(BlakeTwo256::hash(&"c4".encode())).hash(); - let candidate5 = make_candidate_receipt(BlakeTwo256::hash(&"c5".encode())).hash(); - - // B 0 1 2 3 - // C1 x - // C2 x - // C3 x x - // C4 x - // C5 x - inclusions.insert(candidate1, 0, get_block_number_hash(0)); - inclusions.insert(candidate2, 1, get_block_number_hash(1)); - inclusions.insert(candidate3, 0, get_block_number_hash(0)); - inclusions.insert(candidate3, 2, get_block_number_hash(2)); - inclusions.insert(candidate4, 2, get_block_number_hash(2)); - inclusions.insert(candidate5, 3, get_block_number_hash(3)); - - inclusions.remove_up_to_height(&0); - assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); - assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); - assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); - assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); - assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); - - inclusions.remove_up_to_height(&1); - assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); - assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); - assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); - assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); - assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); - - inclusions.remove_up_to_height(&2); - assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); - assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); - assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); - assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); - assert!(inclusions.contains(&candidate5), "Expected candidate5 to remain"); - - inclusions.remove_up_to_height(&10); - assert!(!inclusions.contains(&candidate1), "Expected candidate1 to be removed"); - assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); - assert!(!inclusions.contains(&candidate3), "Expected candidate3 to be removed"); - assert!(!inclusions.contains(&candidate4), "Expected candidate4 to be removed"); - assert!(!inclusions.contains(&candidate5), "Expected candidate5 to be removed"); -} - #[test] fn inclusions_duplicate_insertion_same_height_and_block() { let mut inclusions = Inclusions::new(); @@ -920,18 +872,389 @@ fn test_duplicate_insertion_same_height_different_blocks() { ); } +// ----- Inclusions removal tests ----- +// inclusions_removal_null_case +// +// inclusions_removal_one_candidate_one_height_one_branch +// +// inclusions_removal_one_candidate_one_height_multi_branch +// inclusions_removal_one_candidate_multi_height_one_branch +// inclusions_removal_multi_candidate_one_height_one_branch +// +// inclusions_removal_multi_candidate_multi_height_one_branch +// inclusions_removal_one_candidate_multi_height_multi_branch +// inclusions_removal_multi_candidate_one_height_multi_branch +// +// inclusions_removal_multi_candidate_multi_height_multi_branch #[test] -fn inclusions_remove_with_empty_maps() { +fn inclusions_removal_null_case() { let mut inclusions = Inclusions::new(); let height = 5; // Ensure both maps are empty before the operation - assert!(inclusions.candidates_by_block_number.is_empty()); - assert!(inclusions.inclusions_inner.is_empty()); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); inclusions.remove_up_to_height(&height); // Ensure both maps remain empty after the operation - assert!(inclusions.candidates_by_block_number.is_empty()); - assert!(inclusions.inclusions_inner.is_empty()); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_one_candidate_one_height_one_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + + // B 0 + // C1 0 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_one_candidate_one_height_multi_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + + // B 0 + // C1 0&1 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 1)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.inclusions_inner.get(&candidate1).unwrap().get(&0).unwrap().len() == 2); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_one_candidate_multi_height_one_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + + // B 0 1 2 3 4 + // C1 0 0 + inclusions.insert(candidate1, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate1, 3, get_relay_block_hash(3, 0)); + + // No prune case + inclusions.remove_up_to_height(&1); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 2); + + // Prune case up to height 2 + inclusions.remove_up_to_height(&2); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 3 + inclusions.remove_up_to_height(&3); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 20 (overshot) + inclusions.remove_up_to_height(&20); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_multi_candidate_one_height_one_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + + // B 0 + // C1 0 + // C2 0 + // C3 0 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate2, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate3, 0, get_relay_block_hash(0, 0)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.inclusions_inner.len() == 3); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_multi_candidate_multi_height_one_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + + // B 0 1 2 3 + // C1 0 0 + // C2 0 + // C3 0 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate1, 2, get_relay_block_hash(2, 0)); + inclusions.insert(candidate2, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate3, 2, get_relay_block_hash(2, 0)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.inclusions_inner.len() == 3); + assert!(inclusions.candidates_by_block_number.len() == 2); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.inclusions_inner.len() == 2); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 2 + inclusions.remove_up_to_height(&2); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(!inclusions.contains(&candidate2), "Expected candidate2 to be removed"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.inclusions_inner.len() == 2); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 3 + inclusions.remove_up_to_height(&3); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_one_candidate_multi_height_multi_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + + // B 0 1 2 + // C1 0 0&1 1 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate1, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate1, 1, get_relay_block_hash(1, 1)); + inclusions.insert(candidate1, 2, get_relay_block_hash(2, 1)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 3); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 2); + + // Prune case up to height 2 + inclusions.remove_up_to_height(&2); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.inclusions_inner.len() == 1); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 3 + inclusions.remove_up_to_height(&3); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_multi_candidate_one_height_multi_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + + // B 0 + // C1 0 + // C2 0&1 + // C3 1 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate2, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate2, 0, get_relay_block_hash(0, 1)); + inclusions.insert(candidate3, 0, get_relay_block_hash(0, 1)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.inclusions_inner.len() == 3); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_multi_candidate_multi_height_multi_branch() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + let candidate4 = make_candidate_receipt(BlakeTwo256::hash(&"c4".encode())).hash(); + + // B 0 1 2 + // C1 0&1 0 0 //shouldn't get pruned as long as one of the forks need it + // C2 1 1 + // C3 0 1 + // C4 0&1 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 1)); + inclusions.insert(candidate1, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate1, 2, get_relay_block_hash(2, 0)); + inclusions.insert(candidate2, 1, get_relay_block_hash(1, 1)); + inclusions.insert(candidate2, 2, get_relay_block_hash(2, 1)); + inclusions.insert(candidate3, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate3, 1, get_relay_block_hash(1, 1)); + inclusions.insert(candidate4, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate4, 1, get_relay_block_hash(1, 1)); + + // No prune case + inclusions.remove_up_to_height(&0); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); + assert!(inclusions.inclusions_inner.len() == 4); + assert!(inclusions.candidates_by_block_number.len() == 3); + + // Prune case up to height 1 + inclusions.remove_up_to_height(&1); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(inclusions.contains(&candidate3), "Expected candidate3 to remain"); + assert!(inclusions.contains(&candidate4), "Expected candidate4 to remain"); + assert!(inclusions.inclusions_inner.len() == 4); + assert!(inclusions.candidates_by_block_number.len() == 2); + + // Prune case up to height 2 + inclusions.remove_up_to_height(&2); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(!inclusions.contains(&candidate3), "Expected candidate3 to be removed"); + assert!(!inclusions.contains(&candidate4), "Expected candidate4 to be removed"); + assert!(inclusions.inclusions_inner.len() == 2); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 3 + inclusions.remove_up_to_height(&3); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); +} + +#[test] +fn inclusions_removal_multi_candidate_multi_height_multi_branch_multi_height_prune() { + let mut inclusions = Inclusions::new(); + + let candidate1 = make_candidate_receipt(BlakeTwo256::hash(&"c1".encode())).hash(); + let candidate2 = make_candidate_receipt(BlakeTwo256::hash(&"c2".encode())).hash(); + let candidate3 = make_candidate_receipt(BlakeTwo256::hash(&"c3".encode())).hash(); + let candidate4 = make_candidate_receipt(BlakeTwo256::hash(&"c4".encode())).hash(); + + // B 0 1 2 + // C1 0&1 0 0 + // C2 1 1 + // C3 0 1 + // C4 0&1 + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate1, 0, get_relay_block_hash(0, 1)); + inclusions.insert(candidate1, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate1, 2, get_relay_block_hash(2, 0)); + inclusions.insert(candidate2, 1, get_relay_block_hash(1, 1)); + inclusions.insert(candidate2, 2, get_relay_block_hash(2, 1)); + inclusions.insert(candidate3, 0, get_relay_block_hash(0, 0)); + inclusions.insert(candidate3, 1, get_relay_block_hash(1, 1)); + inclusions.insert(candidate4, 1, get_relay_block_hash(1, 0)); + inclusions.insert(candidate4, 1, get_relay_block_hash(1, 1)); + + // Prune case up to height 2 + inclusions.remove_up_to_height(&2); + assert!(inclusions.contains(&candidate1), "Expected candidate1 to remain"); + assert!(inclusions.contains(&candidate2), "Expected candidate2 to remain"); + assert!(!inclusions.contains(&candidate3), "Expected candidate3 to be removed"); + assert!(!inclusions.contains(&candidate4), "Expected candidate4 to be removed"); + assert!(inclusions.inclusions_inner.len() == 2); + assert!(inclusions.candidates_by_block_number.len() == 1); + + // Prune case up to height 20 + inclusions.remove_up_to_height(&20); + assert!(inclusions.inclusions_inner.is_empty(), "Expected inclusions_inner to be empty"); + assert!( + inclusions.candidates_by_block_number.is_empty(), + "Expected candidates_by_block_number to be empty" + ); } -- GitLab From d81a2e2fa958432ac9e0f0cf26ecdc5237fc8fe7 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Thu, 14 Sep 2023 22:49:37 +0300 Subject: [PATCH 150/633] Fix code duplication in tests (#1575) --- polkadot/node/core/backing/src/tests/mod.rs | 516 ++++-------------- .../src/tests/prospective_parachains.rs | 27 +- polkadot/node/core/pvf-checker/src/tests.rs | 6 +- polkadot/primitives/test-helpers/src/lib.rs | 14 +- .../runtime/parachains/src/paras/tests.rs | 8 +- .../runtime/parachains/src/shared/tests.rs | 5 +- 6 files changed, 124 insertions(+), 452 deletions(-) diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index a981487db44..4c2fd6becb4 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -18,7 +18,7 @@ use self::test_helpers::mock::new_leaf; use super::*; use ::test_helpers::{ dummy_candidate_receipt_bad_sig, dummy_collator, dummy_collator_signature, - dummy_committed_candidate_receipt, dummy_hash, + dummy_committed_candidate_receipt, dummy_hash, validator_pubkeys, }; use assert_matches::assert_matches; use futures::{future, Future}; @@ -48,10 +48,6 @@ mod prospective_parachains; const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; -fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() -} - fn table_statement_to_primitive(statement: TableStatement) -> Statement { match statement { TableStatement::Seconded(committed_candidate_receipt) => @@ -299,6 +295,81 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS ); } +async fn assert_validation_requests( + virtual_overseer: &mut VirtualOverseer, + validation_code: ValidationCode, +) { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code))).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) + ) => { + tx.send(Ok(1u32.into())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) + ) if sess_idx == 1 => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); +} + +async fn assert_validate_from_exhaustive( + virtual_overseer: &mut VirtualOverseer, + pvd: &PersistedValidationData, + pov: &PoV, + validation_code: &ValidationCode, + candidate: &CommittedCandidateReceipt, + expected_head_data: &HeadData, + result_validation_data: PersistedValidationData, +) { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, + _, + timeout, + tx, + ), + ) if _pvd == *pvd && + _validation_code == *validation_code && + *_pov == *pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: expected_head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + result_validation_data, + ))) + .unwrap(); + } + ); +} + // Test that a `CandidateBackingMessage::Second` issues validation work // and in case validation is successful issues a `StatementDistributionMessage`. #[test] @@ -334,65 +405,18 @@ fn backing_second_works() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, - candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && - candidate.commitments.hash() == candidate_receipt.commitments_hash => - { - tx.send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: expected_head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - test_state.validation_data.clone(), - ))) - .unwrap(); - } - ); + assert_validate_from_exhaustive( + &mut virtual_overseer, + &pvd, + &pov, + &validation_code, + &candidate, + expected_head_data, + test_state.validation_data.clone(), + ) + .await; assert_matches!( virtual_overseer.recv().await, @@ -499,32 +523,7 @@ fn backing_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is the PoV. @@ -702,32 +701,7 @@ fn backing_works_while_validation_ongoing() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is PoV from the @@ -893,32 +867,7 @@ fn backing_misbehavior_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1098,32 +1047,7 @@ fn backing_dont_second_invalid() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code_a.hash() => { - tx.send(Ok(Some(validation_code_a.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1163,32 +1087,7 @@ fn backing_dont_second_invalid() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code_b.hash() => { - tx.send(Ok(Some(validation_code_b.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code_b.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1300,32 +1199,7 @@ fn backing_second_after_first_fails_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1408,32 +1282,7 @@ fn backing_second_after_first_fails_works() { // triggered on the prev step. virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code_to_second.hash() => { - tx.send(Ok(Some(validation_code_to_second.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code_to_second.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1494,32 +1343,7 @@ fn backing_works_after_failed_validation() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1722,32 +1546,7 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; // Subsystem requests PoV and requests validation. // We cancel - should mean retry on next backing statement. @@ -1810,32 +1609,7 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_c.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -2026,65 +1800,18 @@ fn cannot_second_multiple_candidates_per_parent() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, - candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && - candidate.commitments.hash() == candidate_receipt.commitments_hash => - { - tx.send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: expected_head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - test_state.validation_data.clone(), - ))) - .unwrap(); - } - ); + assert_validate_from_exhaustive( + &mut virtual_overseer, + &pvd, + &pov, + &validation_code, + &candidate, + expected_head_data, + test_state.validation_data.clone(), + ) + .await; assert_matches!( virtual_overseer.recv().await, @@ -2131,32 +1858,7 @@ fn cannot_second_multiple_candidates_per_parent() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; // The validation is still requested. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; assert_matches!( virtual_overseer.recv().await, diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index d6e93fb04d3..14f720b721f 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -208,32 +208,7 @@ async fn assert_validate_seconded_candidate( expected_head_data: &HeadData, fetch_pov: bool, ) { - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if parent == relay_parent && hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); + assert_validation_requests(virtual_overseer, validation_code.clone()).await; if fetch_pov { assert_matches!( diff --git a/polkadot/node/core/pvf-checker/src/tests.rs b/polkadot/node/core/pvf-checker/src/tests.rs index bd8817000ae..4ac6e5eba31 100644 --- a/polkadot/node/core/pvf-checker/src/tests.rs +++ b/polkadot/node/core/pvf-checker/src/tests.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use ::test_helpers::{dummy_digest, dummy_hash}; +use ::test_helpers::{dummy_digest, dummy_hash, validator_pubkeys}; use futures::{channel::oneshot, future::BoxFuture, prelude::*}; use polkadot_node_subsystem::{ messages::{ @@ -94,10 +94,6 @@ struct TestState { const OUR_VALIDATOR: Sr25519Keyring = Sr25519Keyring::Alice; -fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() -} - impl TestState { fn new() -> Self { // Initialize the default session 1. No validators are present there. diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index 8ee5f180d34..d532d6ff57f 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -159,6 +159,11 @@ pub fn dummy_pvd(parent_head: HeadData, relay_parent_number: u32) -> PersistedVa } } +/// Creates a meaningless signature +pub fn dummy_signature() -> polkadot_primitives::ValidatorSignature { + sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]) +} + /// Create a meaningless candidate, returning its receipt and PVD. pub fn make_candidate( relay_parent_hash: Hash, @@ -244,6 +249,11 @@ pub fn resign_candidate_descriptor_with_collator>( descriptor.signature = signature; } +/// Extracts validators's public keus (`ValidatorId`) from `Sr25519Keyring` +pub fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { + val_ids.iter().map(|v| v.public().into()).collect() +} + /// Builder for `CandidateReceipt`. pub struct TestCandidateBuilder { pub para_id: ParaId, @@ -298,7 +308,3 @@ impl rand::RngCore for AlwaysZeroRng { Ok(()) } } - -pub fn dummy_signature() -> polkadot_primitives::ValidatorSignature { - sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]) -} diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index a024525c817..c511c65d473 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -17,11 +17,11 @@ use super::*; use frame_support::{assert_err, assert_ok, assert_storage_noop}; use keyring::Sr25519Keyring; -use primitives::{BlockNumber, ValidatorId, PARACHAIN_KEY_TYPE_ID}; +use primitives::{BlockNumber, PARACHAIN_KEY_TYPE_ID}; use sc_keystore::LocalKeystore; use sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; -use test_helpers::{dummy_head_data, dummy_validation_code}; +use test_helpers::{dummy_head_data, dummy_validation_code, validator_pubkeys}; use crate::{ configuration::HostConfiguration, @@ -39,10 +39,6 @@ static VALIDATORS: &[Sr25519Keyring] = &[ Sr25519Keyring::Ferdie, ]; -fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() -} - fn sign_and_include_pvf_check_statement(stmt: PvfCheckStatement) { let validators = &[ Sr25519Keyring::Alice, diff --git a/polkadot/runtime/parachains/src/shared/tests.rs b/polkadot/runtime/parachains/src/shared/tests.rs index 91891ba8d75..ae12b4b3fc1 100644 --- a/polkadot/runtime/parachains/src/shared/tests.rs +++ b/polkadot/runtime/parachains/src/shared/tests.rs @@ -22,10 +22,7 @@ use crate::{ use assert_matches::assert_matches; use keyring::Sr25519Keyring; use primitives::Hash; - -fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() -} +use test_helpers::validator_pubkeys; #[test] fn tracker_earliest_block_number() { -- GitLab From c6df36415748209248e0d0f0f051d31482d4a0cc Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 15 Sep 2023 01:03:46 -0400 Subject: [PATCH 151/633] upgrade to docify v0.2.3 (#1555) Upgrades to docify v0.2.3, which includes a fix for https://github.com/sam0x17/docify/issues/7 and full support for multi-byte UTF-8 characters --- Cargo.lock | 8 ++++---- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 944cd153f66..bbc9a5dd431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4455,18 +4455,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029de870d175d11969524d91a3fb2cbf6d488b853bff99d41cf65e533ac7d9d2" +checksum = "ff509d6aa8e7ca86b36eb3d593132e64204597de3ccb763ffd8bfd2264d54cf3" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac43324656a1b05eb0186deb51f27d2d891c704c37f34de281ef6297ba193e5" +checksum = "b135598b950330937f3a0ddfbe908106ee2ecd5fa95d8ae7952a3c3863efe8da" dependencies = [ "common-path", "derive-syn-parse", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 4d6f3d768aa..21cdb4f8983 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.1" +docify = "0.2.3" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index a2aa769620c..224067d4fa7 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.1" +docify = "0.2.3" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index f3165a2f5f9..9fbc3fdb2c6 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.1" +docify = "0.2.3" 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/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 3ad49ef5e66..7fa14e861e8 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.1" +docify = "0.2.3" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 9b148c0b471..bdd4252414a 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.1" +docify = "0.2.3" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index f81bdd3b20a..435a58ba095 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -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.106", default-features = false, features = ["alloc"] } -docify = "0.2.1" +docify = "0.2.3" static_assertions = "1.1.0" aquamarine = { version = "0.3.2" } -- GitLab From b35b28ca4beeb7318006e7bdb7927c9309e7ad7a Mon Sep 17 00:00:00 2001 From: Rahul Subramaniyam <78006270+rahulksnv@users.noreply.github.com> Date: Fri, 15 Sep 2023 01:12:45 -0700 Subject: [PATCH 152/633] Modular block request handler (#1524) Submit the outstanding PRs from the old repos(these were already reviewed and approved before the repo rorg, but not yet submitted): Main PR: https://github.com/paritytech/substrate/pull/14014 Companion PRs: https://github.com/paritytech/polkadot/pull/7134, https://github.com/paritytech/cumulus/pull/2489 The changes in the PR: 1. ChainSync currently calls into the block request handler directly. Instead, move the block request handler behind a trait. This allows new protocols to be plugged into ChainSync. 2. BuildNetworkParams is changed so that custom relay protocol implementations can be (optionally) passed in during network creation time. If custom protocol is not specified, it defaults to the existing block handler 3. BlockServer and BlockDownloader traits are introduced for the protocol implementation. The existing block handler has been changed to implement these traits 4. Other changes: [X] Make TxHash serializable. This is needed for exchanging the serialized hash in the relay protocol messages [X] Clean up types no longer used(OpaqueBlockRequest, OpaqueBlockResponse) --------- Co-authored-by: Dmitry Markin Co-authored-by: command-bot <> --- cumulus/client/service/src/lib.rs | 1 + polkadot/node/service/src/lib.rs | 1 + .../bin/node-template/node/src/service.rs | 1 + substrate/bin/node/cli/src/service.rs | 1 + substrate/client/network/common/src/sync.rs | 33 +-- .../network/sync/src/block_relay_protocol.rs | 72 ++++++ .../network/sync/src/block_request_handler.rs | 168 ++++++++++++-- substrate/client/network/sync/src/engine.rs | 5 +- substrate/client/network/sync/src/lib.rs | 212 +++++------------- substrate/client/network/sync/src/mock.rs | 35 ++- substrate/client/network/test/src/lib.rs | 24 +- substrate/client/network/test/src/service.rs | 24 +- substrate/client/service/src/builder.rs | 46 ++-- .../client/transaction-pool/api/src/lib.rs | 3 +- 14 files changed, 370 insertions(+), 256 deletions(-) create mode 100644 substrate/client/network/sync/src/block_relay_protocol.rs diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 211a5cc3b79..82890666eba 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -484,6 +484,7 @@ where import_queue, block_announce_validator_builder: Some(Box::new(move |_| block_announce_validator)), warp_sync_params, + block_relay: None, }) } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 7f4eadaba7f..75e853d0ef8 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -894,6 +894,7 @@ pub fn new_full( import_queue, block_announce_validator_builder: None, warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + block_relay: None, })?; if config.offchain_worker.enabled { diff --git a/substrate/bin/node-template/node/src/service.rs b/substrate/bin/node-template/node/src/service.rs index 7303f5cd6dd..40320282924 100644 --- a/substrate/bin/node-template/node/src/service.rs +++ b/substrate/bin/node-template/node/src/service.rs @@ -183,6 +183,7 @@ pub fn new_full(config: Configuration) -> Result { import_queue, block_announce_validator_builder: None, warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + block_relay: None, })?; if config.offchain_worker.enabled { diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index e49c60fe2fb..977c90e73e9 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -388,6 +388,7 @@ pub fn new_full_base( import_queue, block_announce_validator_builder: None, warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + block_relay: None, })?; let role = config.role.clone(); diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index 461c4ae411d..5a6f90b290d 100644 --- a/substrate/client/network/common/src/sync.rs +++ b/substrate/client/network/common/src/sync.rs @@ -22,12 +22,12 @@ pub mod message; pub mod metrics; pub mod warp; -use crate::{role::Roles, sync::message::BlockAnnounce, types::ReputationChange}; +use crate::{role::Roles, types::ReputationChange}; use futures::Stream; use libp2p_identity::PeerId; -use message::{BlockData, BlockRequest, BlockResponse}; +use message::{BlockAnnounce, BlockRequest, BlockResponse}; use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock}; use sp_consensus::BlockOrigin; use sp_runtime::{ @@ -226,28 +226,6 @@ impl fmt::Debug for OpaqueStateResponse { } } -/// Wrapper for implementation-specific block request. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueBlockRequest(pub Box); - -impl fmt::Debug for OpaqueBlockRequest { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueBlockRequest").finish() - } -} - -/// Wrapper for implementation-specific block response. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueBlockResponse(pub Box); - -impl fmt::Debug for OpaqueBlockResponse { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueBlockResponse").finish() - } -} - /// Provides high-level status of syncing. #[async_trait::async_trait] pub trait SyncStatusProvider: Send + Sync { @@ -392,13 +370,6 @@ pub trait ChainSync: Send { /// Return some key metrics. fn metrics(&self) -> Metrics; - /// Access blocks from implementation-specific block response. - fn block_response_into_blocks( - &self, - request: &BlockRequest, - response: OpaqueBlockResponse, - ) -> Result>, String>; - /// Advance the state of `ChainSync` fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()>; diff --git a/substrate/client/network/sync/src/block_relay_protocol.rs b/substrate/client/network/sync/src/block_relay_protocol.rs new file mode 100644 index 00000000000..7a313458bf0 --- /dev/null +++ b/substrate/client/network/sync/src/block_relay_protocol.rs @@ -0,0 +1,72 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Block relay protocol related definitions. + +use futures::channel::oneshot; +use libp2p::PeerId; +use sc_network::request_responses::{ProtocolConfig, RequestFailure}; +use sc_network_common::sync::message::{BlockData, BlockRequest}; +use sp_runtime::traits::Block as BlockT; +use std::sync::Arc; + +/// The serving side of the block relay protocol. It runs a single instance +/// of the server task that processes the incoming protocol messages. +#[async_trait::async_trait] +pub trait BlockServer: Send { + /// Starts the protocol processing. + async fn run(&mut self); +} + +/// The client side stub to download blocks from peers. This is a handle +/// that can be used to initiate concurrent downloads. +#[async_trait::async_trait] +pub trait BlockDownloader: Send + Sync { + /// Performs the protocol specific sequence to fetch the blocks from the peer. + /// Output: if the download succeeds, the response is a `Vec` which is + /// in a format specific to the protocol implementation. The block data + /// can be extracted from this response using [`BlockDownloader::block_response_into_blocks`]. + async fn download_blocks( + &self, + who: PeerId, + request: BlockRequest, + ) -> Result, RequestFailure>, oneshot::Canceled>; + + /// Parses the protocol specific response to retrieve the block data. + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: Vec, + ) -> Result>, BlockResponseError>; +} + +/// Errors returned by [`BlockDownloader::block_response_into_blocks`]. +#[derive(Debug)] +pub enum BlockResponseError { + /// Failed to decode the response bytes. + DecodeFailed(String), + + /// Failed to extract the blocks from the decoded bytes. + ExtractionFailed(String), +} + +/// Block relay specific params for network creation, specified in +/// ['sc_service::BuildNetworkParams']. +pub struct BlockRelayParams { + pub server: Box>, + pub downloader: Arc>, + pub request_response_config: ProtocolConfig, +} diff --git a/substrate/client/network/sync/src/block_request_handler.rs b/substrate/client/network/sync/src/block_request_handler.rs index d90a00b3767..c24083f6328 100644 --- a/substrate/client/network/sync/src/block_request_handler.rs +++ b/substrate/client/network/sync/src/block_request_handler.rs @@ -18,29 +18,35 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ - schema::v1::{block_request::FromBlock, BlockResponse, Direction}, + block_relay_protocol::{BlockDownloader, BlockRelayParams, BlockResponseError, BlockServer}, + schema::v1::{ + block_request::FromBlock as FromBlockSchema, BlockRequest as BlockRequestSchema, + BlockResponse as BlockResponseSchema, BlockResponse, Direction, + }, + service::network::NetworkServiceHandle, MAX_BLOCKS_IN_RESPONSE, }; -use codec::{Decode, Encode}; +use codec::{Decode, DecodeAll, Encode}; use futures::{channel::oneshot, stream::StreamExt}; use libp2p::PeerId; use log::debug; use prost::Message; -use schnellru::{ByLength, LruMap}; - use sc_client_api::BlockBackend; use sc_network::{ config::ProtocolId, - request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, + request_responses::{ + IfDisconnected, IncomingRequest, OutgoingResponse, ProtocolConfig, RequestFailure, + }, + types::ProtocolName, }; -use sc_network_common::sync::message::BlockAttributes; +use sc_network_common::sync::message::{BlockAttributes, BlockData, BlockRequest, FromBlock}; +use schnellru::{ByLength, LruMap}; use sp_blockchain::HeaderBackend; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header, One, Zero}, }; - use std::{ cmp::min, hash::{Hash, Hasher}, @@ -129,7 +135,8 @@ enum SeenRequestsValue { Fulfilled(usize), } -/// Handler for incoming block requests from a remote peer. +/// The full block server implementation of [`BlockServer`]. It handles +/// the incoming block requests from a remote peer. pub struct BlockRequestHandler { client: Arc, request_receiver: async_channel::Receiver, @@ -146,11 +153,12 @@ where { /// Create a new [`BlockRequestHandler`]. pub fn new( + network: NetworkServiceHandle, protocol_id: &ProtocolId, fork_id: Option<&str>, client: Arc, num_peer_hint: usize, - ) -> (Self, ProtocolConfig) { + ) -> BlockRelayParams { // Reserve enough request slots for one request per peer when we are at the maximum // number of peers. let capacity = std::cmp::max(num_peer_hint, 1); @@ -170,11 +178,15 @@ where let capacity = ByLength::new(num_peer_hint.max(1) as u32 * 2); let seen_requests = LruMap::new(capacity); - (Self { client, request_receiver, seen_requests }, protocol_config) + BlockRelayParams { + server: Box::new(Self { client, request_receiver, seen_requests }), + downloader: Arc::new(FullBlockDownloader::new(protocol_config.name.clone(), network)), + request_response_config: protocol_config, + } } /// Run [`BlockRequestHandler`]. - pub async fn run(mut self) { + async fn process_requests(&mut self) { while let Some(request) = self.request_receiver.next().await { let IncomingRequest { peer, payload, pending_response } = request; @@ -197,11 +209,11 @@ where let request = crate::schema::v1::BlockRequest::decode(&payload[..])?; let from_block_id = match request.from_block.ok_or(HandleRequestError::MissingFromField)? { - FromBlock::Hash(ref h) => { + FromBlockSchema::Hash(ref h) => { let h = Decode::decode(&mut h.as_ref())?; BlockId::::Hash(h) }, - FromBlock::Number(ref n) => { + FromBlockSchema::Number(ref n) => { let n = Decode::decode(&mut n.as_ref())?; BlockId::::Number(n) }, @@ -448,6 +460,17 @@ where } } +#[async_trait::async_trait] +impl BlockServer for BlockRequestHandler +where + B: BlockT, + Client: HeaderBackend + BlockBackend + Send + Sync + 'static, +{ + async fn run(&mut self) { + self.process_requests().await; + } +} + #[derive(Debug, thiserror::Error)] enum HandleRequestError { #[error("Failed to decode request: {0}.")] @@ -465,3 +488,122 @@ enum HandleRequestError { #[error("Failed to send response.")] SendResponse, } + +/// The full block downloader implementation of [`BlockDownloader]. +pub struct FullBlockDownloader { + protocol_name: ProtocolName, + network: NetworkServiceHandle, +} + +impl FullBlockDownloader { + fn new(protocol_name: ProtocolName, network: NetworkServiceHandle) -> Self { + Self { protocol_name, network } + } + + /// Extracts the blocks from the response schema. + fn blocks_from_schema( + &self, + request: &BlockRequest, + response: BlockResponseSchema, + ) -> Result>, String> { + response + .blocks + .into_iter() + .map(|block_data| { + Ok(BlockData:: { + hash: Decode::decode(&mut block_data.hash.as_ref())?, + header: if !block_data.header.is_empty() { + Some(Decode::decode(&mut block_data.header.as_ref())?) + } else { + None + }, + body: if request.fields.contains(BlockAttributes::BODY) { + Some( + block_data + .body + .iter() + .map(|body| Decode::decode(&mut body.as_ref())) + .collect::, _>>()?, + ) + } else { + None + }, + indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) { + Some(block_data.indexed_body) + } else { + None + }, + receipt: if !block_data.receipt.is_empty() { + Some(block_data.receipt) + } else { + None + }, + message_queue: if !block_data.message_queue.is_empty() { + Some(block_data.message_queue) + } else { + None + }, + justification: if !block_data.justification.is_empty() { + Some(block_data.justification) + } else if block_data.is_empty_justification { + Some(Vec::new()) + } else { + None + }, + justifications: if !block_data.justifications.is_empty() { + Some(DecodeAll::decode_all(&mut block_data.justifications.as_ref())?) + } else { + None + }, + }) + }) + .collect::>() + .map_err(|error: codec::Error| error.to_string()) + } +} + +#[async_trait::async_trait] +impl BlockDownloader for FullBlockDownloader { + async fn download_blocks( + &self, + who: PeerId, + request: BlockRequest, + ) -> Result, RequestFailure>, oneshot::Canceled> { + // Build the request protobuf. + let bytes = BlockRequestSchema { + fields: request.fields.to_be_u32(), + from_block: match request.from { + FromBlock::Hash(h) => Some(FromBlockSchema::Hash(h.encode())), + FromBlock::Number(n) => Some(FromBlockSchema::Number(n.encode())), + }, + direction: request.direction as i32, + max_blocks: request.max.unwrap_or(0), + support_multiple_justifications: true, + } + .encode_to_vec(); + + let (tx, rx) = oneshot::channel(); + self.network.start_request( + who, + self.protocol_name.clone(), + bytes, + tx, + IfDisconnected::ImmediateError, + ); + rx.await + } + + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: Vec, + ) -> Result>, BlockResponseError> { + // Decode the response protobuf + let response_schema = BlockResponseSchema::decode(response.as_slice()) + .map_err(|error| BlockResponseError::DecodeFailed(error.to_string()))?; + + // Extract the block data from the protobuf + self.blocks_from_schema::(request, response_schema) + .map_err(|error| BlockResponseError::ExtractionFailed(error.to_string())) + } +} diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 23847d16c97..c93ba89c622 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -23,6 +23,7 @@ use crate::{ block_announce_validator::{ BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, }, + block_relay_protocol::BlockDownloader, service::{self, chain_sync::ToServiceCommand}, warp::WarpSyncParams, ChainSync, ClientError, SyncingService, @@ -300,7 +301,7 @@ where warp_sync_params: Option>, network_service: service::network::NetworkServiceHandle, import_queue: Box>, - block_request_protocol_name: ProtocolName, + block_downloader: Arc>, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, rx: sc_utils::mpsc::TracingUnboundedReceiver>, @@ -392,7 +393,7 @@ where metrics_registry, network_service.clone(), import_queue, - block_request_protocol_name, + block_downloader, state_request_protocol_name, warp_sync_protocol_name, )?; diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index df0ed2c4541..20c0034966d 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -29,13 +29,14 @@ //! order to update it. use crate::{ + block_relay_protocol::{BlockDownloader, BlockResponseError}, blocks::BlockCollection, schema::v1::{StateRequest, StateResponse}, state::StateSync, warp::{WarpProofImportResult, WarpSync, WarpSyncConfig}, }; -use codec::{Decode, DecodeAll, Encode}; +use codec::Encode; use extra_requests::ExtraRequests; use futures::{channel::oneshot, task::Poll, Future, FutureExt}; use libp2p::{request_response::OutboundFailure, PeerId}; @@ -63,8 +64,8 @@ use sc_network_common::{ }, warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress}, BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, - OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, - OpaqueStateResponse, PeerInfo, PeerRequest, SyncMode, SyncState, SyncStatus, + OnStateData, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, PeerRequest, SyncMode, + SyncState, SyncStatus, }, }; use sp_arithmetic::traits::Saturating; @@ -93,6 +94,7 @@ mod extra_requests; mod futures_stream; mod schema; +pub mod block_relay_protocol; pub mod block_request_handler; pub mod blocks; pub mod engine; @@ -320,8 +322,8 @@ pub struct ChainSync { network_service: service::network::NetworkServiceHandle, /// Protocol name used for block announcements block_announce_protocol_name: ProtocolName, - /// Protocol name used to send out block requests - block_request_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 @@ -1167,72 +1169,6 @@ where } } - fn block_response_into_blocks( - &self, - request: &BlockRequest, - response: OpaqueBlockResponse, - ) -> Result>, String> { - let response: Box = response.0.downcast().map_err(|_error| { - "Failed to downcast opaque block response during encoding, this is an \ - implementation bug." - .to_string() - })?; - - response - .blocks - .into_iter() - .map(|block_data| { - Ok(BlockData:: { - hash: Decode::decode(&mut block_data.hash.as_ref())?, - header: if !block_data.header.is_empty() { - Some(Decode::decode(&mut block_data.header.as_ref())?) - } else { - None - }, - body: if request.fields.contains(BlockAttributes::BODY) { - Some( - block_data - .body - .iter() - .map(|body| Decode::decode(&mut body.as_ref())) - .collect::, _>>()?, - ) - } else { - None - }, - indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) { - Some(block_data.indexed_body) - } else { - None - }, - receipt: if !block_data.receipt.is_empty() { - Some(block_data.receipt) - } else { - None - }, - message_queue: if !block_data.message_queue.is_empty() { - Some(block_data.message_queue) - } else { - None - }, - justification: if !block_data.justification.is_empty() { - Some(block_data.justification) - } else if block_data.is_empty_justification { - Some(Vec::new()) - } else { - None - }, - justifications: if !block_data.justifications.is_empty() { - Some(DecodeAll::decode_all(&mut block_data.justifications.as_ref())?) - } else { - None - }, - }) - }) - .collect::>() - .map_err(|error: codec::Error| error.to_string()) - } - fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { self.process_outbound_requests(); @@ -1248,30 +1184,18 @@ where } fn send_block_request(&mut self, who: PeerId, request: BlockRequest) { - let (tx, rx) = oneshot::channel(); - let opaque_req = self.create_opaque_block_request(&request); - if self.peers.contains_key(&who) { - self.pending_responses - .insert(who, Box::pin(async move { (who, PeerRequest::Block(request), rx.await) })); - } - - match self.encode_block_request(&opaque_req) { - Ok(data) => { - self.network_service.start_request( - who, - self.block_request_protocol_name.clone(), - data, - tx, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: LOG_TARGET, - "Failed to encode block request {opaque_req:?}: {err:?}", - ); - }, + 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, + ) + }), + ); } } } @@ -1301,7 +1225,7 @@ where metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, import_queue: Box>, - block_request_protocol_name: ProtocolName, + block_downloader: Arc>, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, ) -> Result<(Self, NonDefaultSetConfig), ClientError> { @@ -1337,7 +1261,7 @@ where import_existing: false, gap_sync: None, network_service, - block_request_protocol_name, + block_downloader, state_request_protocol_name, warp_sync_config, warp_sync_target_block_header: None, @@ -1710,13 +1634,6 @@ where } } - fn decode_block_response(response: &[u8]) -> Result { - let response = schema::v1::BlockResponse::decode(response) - .map_err(|error| format!("Failed to decode block response: {error}"))?; - - Ok(OpaqueBlockResponse(Box::new(response))) - } - fn decode_state_response(response: &[u8]) -> Result { let response = StateResponse::decode(response) .map_err(|error| format!("Failed to decode state response: {error}"))?; @@ -1780,22 +1697,8 @@ where &mut self, peer_id: PeerId, request: BlockRequest, - response: OpaqueBlockResponse, + blocks: Vec>, ) -> Option> { - let blocks = match self.block_response_into_blocks(&request, response) { - Ok(blocks) => blocks, - Err(err) => { - debug!( - target: LOG_TARGET, - "Failed to decode block response from {}: {}", - peer_id, - err, - ); - self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); - return None - }, - }; - let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( @@ -1915,22 +1818,34 @@ where match response { Ok(Ok(resp)) => match request { PeerRequest::Block(req) => { - let response = match Self::decode_block_response(&resp[..]) { - Ok(proto) => proto, - Err(e) => { + 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:?}.", + "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 }, - }; - - if let Some(import) = self.on_block_response(id, req, response) { - return Poll::Ready(import) + 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 => { @@ -2010,31 +1925,6 @@ where Poll::Pending } - /// Create implementation-specific block request. - fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest { - OpaqueBlockRequest(Box::new(schema::v1::BlockRequest { - fields: request.fields.to_be_u32(), - from_block: match request.from { - FromBlock::Hash(h) => Some(schema::v1::block_request::FromBlock::Hash(h.encode())), - FromBlock::Number(n) => - Some(schema::v1::block_request::FromBlock::Number(n.encode())), - }, - direction: request.direction as i32, - max_blocks: request.max.unwrap_or(0), - support_multiple_justifications: true, - })) - } - - fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { - let request: &schema::v1::BlockRequest = request.0.downcast_ref().ok_or_else(|| { - "Failed to downcast opaque block response during encoding, this is an \ - implementation bug." - .to_string() - })?; - - Ok(request.encode_to_vec()) - } - 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 \ @@ -2909,7 +2799,7 @@ fn validate_blocks( #[cfg(test)] mod test { use super::*; - use crate::service::network::NetworkServiceProvider; + use crate::{mock::MockBlockDownloader, service::network::NetworkServiceProvider}; use futures::executor::block_on; use sc_block_builder::BlockBuilderProvider; use sc_network_common::{ @@ -2947,7 +2837,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3013,7 +2903,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3187,7 +3077,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3313,7 +3203,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3470,7 +3360,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3612,7 +3502,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3756,7 +3646,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3801,7 +3691,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) @@ -3853,7 +3743,7 @@ mod test { None, chain_sync_network_handle, import_queue, - ProtocolName::from("block-request"), + Arc::new(MockBlockDownloader::new()), ProtocolName::from("state-request"), None, ) diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index d37095c17d2..859f9fb9c54 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -16,15 +16,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Contains a mock implementation of `ChainSync` that can be used -//! for testing calls made to `ChainSync`. +//! Contains mock implementations of `ChainSync` and 'BlockDownloader'. -use futures::task::Poll; +use crate::block_relay_protocol::{BlockDownloader as BlockDownloaderT, BlockResponseError}; + +use futures::{channel::oneshot, task::Poll}; use libp2p::PeerId; +use sc_network::RequestFailure; use sc_network_common::sync::{ message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, - OpaqueBlockResponse, PeerInfo, SyncStatus, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, PeerInfo, + SyncStatus, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -79,11 +81,6 @@ mockall::mock! { ); fn peer_disconnected(&mut self, who: &PeerId); fn metrics(&self) -> Metrics; - fn block_response_into_blocks( - &self, - request: &BlockRequest, - response: OpaqueBlockResponse, - ) -> Result>, String>; fn poll<'a>( &mut self, cx: &mut std::task::Context<'a>, @@ -95,3 +92,21 @@ mockall::mock! { ); } } + +mockall::mock! { + pub BlockDownloader {} + + #[async_trait::async_trait] + impl BlockDownloaderT for BlockDownloader { + async fn download_blocks( + &self, + who: PeerId, + request: BlockRequest, + ) -> Result, RequestFailure>, oneshot::Canceled>; + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: Vec, + ) -> Result>, BlockResponseError>; + } +} diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index d350b0e54ae..11505903e35 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -798,12 +798,18 @@ pub trait TestNetFactory: Default + Sized + Send { let fork_id = Some(String::from("test-fork-id")); - let block_request_protocol_config = { - let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - self.spawn_task(handler.run().boxed()); - protocol_config - }; + let (chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let mut block_relay_params = BlockRequestHandler::new( + chain_sync_network_handle.clone(), + &protocol_id, + None, + client.clone(), + 50, + ); + self.spawn_task(Box::pin(async move { + block_relay_params.server.run().await; + })); let state_request_protocol_config = { let (handler, protocol_config) = @@ -848,8 +854,6 @@ pub trait TestNetFactory: Default + Sized + Send { let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); - let (chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, sync_service, block_announce_config) = @@ -864,7 +868,7 @@ pub trait TestNetFactory: Default + Sized + Send { Some(warp_sync_params), chain_sync_network_handle, import_queue.service(), - block_request_protocol_config.name.clone(), + block_relay_params.downloader, state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), rx, @@ -877,7 +881,7 @@ pub trait TestNetFactory: Default + Sized + Send { full_net_config.add_request_response_protocol(config); } for config in [ - block_request_protocol_config, + block_relay_params.request_response_config, state_request_protocol_config, light_client_request_protocol_config, warp_protocol_config, diff --git a/substrate/client/network/test/src/service.rs b/substrate/client/network/test/src/service.rs index 68e780545bb..62d7f9f9d1b 100644 --- a/substrate/client/network/test/src/service.rs +++ b/substrate/client/network/test/src/service.rs @@ -156,12 +156,18 @@ impl TestNetworkBuilder { let fork_id = Some(String::from("test-fork-id")); let mut full_net_config = FullNetworkConfiguration::new(&network_config); - let block_request_protocol_config = { - let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - tokio::spawn(handler.run().boxed()); - protocol_config - }; + let (chain_sync_network_provider, chain_sync_network_handle) = + self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + let mut block_relay_params = BlockRequestHandler::new( + chain_sync_network_handle.clone(), + &protocol_id, + None, + client.clone(), + 50, + ); + tokio::spawn(Box::pin(async move { + block_relay_params.server.run().await; + })); let state_request_protocol_config = { let (handler, protocol_config) = @@ -177,8 +183,6 @@ impl TestNetworkBuilder { protocol_config }; - let (chain_sync_network_provider, chain_sync_network_handle) = - self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config::Role::Full), @@ -191,7 +195,7 @@ impl TestNetworkBuilder { None, chain_sync_network_handle, import_queue.service(), - block_request_protocol_config.name.clone(), + block_relay_params.downloader, state_request_protocol_config.name.clone(), None, rx, @@ -214,7 +218,7 @@ impl TestNetworkBuilder { } for config in [ - block_request_protocol_config, + block_relay_params.request_response_config, state_request_protocol_config, light_client_request_protocol_config, ] { diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 917b3be8dc7..3838accde02 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -50,10 +50,10 @@ use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, engine::SyncingEngine, - service::network::NetworkServiceProvider, state_request_handler::StateRequestHandler, - warp::WarpSyncParams, warp_request_handler::RequestHandler as WarpSyncRequestHandler, - SyncingService, + block_relay_protocol::BlockRelayParams, block_request_handler::BlockRequestHandler, + engine::SyncingEngine, service::network::NetworkServiceProvider, + state_request_handler::StateRequestHandler, warp::WarpSyncParams, + warp_request_handler::RequestHandler as WarpSyncRequestHandler, SyncingService, }; use sc_rpc::{ author::AuthorApiServer, @@ -696,6 +696,9 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { Option) -> Box + Send> + Send>>, /// Optional warp sync params. pub warp_sync_params: Option>, + /// User specified block relay params. If not specified, the default + /// block request handler will be used. + pub block_relay: Option>, } /// Build the network service, the network status sinks and an RPC sender. @@ -734,6 +737,7 @@ where import_queue, block_announce_validator_builder, warp_sync_params, + block_relay, } = params; if warp_sync_params.is_none() && config.network.sync_mode.is_warp() { @@ -757,19 +761,26 @@ where Box::new(DefaultBlockAnnounceValidator) }; - let (block_request_protocol_config, block_request_protocol_name) = { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = BlockRequestHandler::new( - &protocol_id, - config.chain_spec.fork_id(), - client.clone(), - net_config.network_config.default_peers_set.in_peers as usize + - net_config.network_config.default_peers_set.out_peers as usize, - ); - let config_name = protocol_config.name.clone(); - spawn_handle.spawn("block-request-handler", Some("networking"), handler.run()); - (protocol_config, config_name) + let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let (mut block_server, block_downloader, block_request_protocol_config) = match block_relay { + Some(params) => (params.server, params.downloader, params.request_response_config), + None => { + // Custom protocol was not specified, use the default block handler. + // Allow both outgoing and incoming requests. + let params = BlockRequestHandler::new( + chain_sync_network_handle.clone(), + &protocol_id, + config.chain_spec.fork_id(), + client.clone(), + config.network.default_peers_set.in_peers as usize + + config.network.default_peers_set.out_peers as usize, + ); + (params.server, params.downloader, params.request_response_config) + }, }; + spawn_handle.spawn("block-request-handler", Some("networking"), async move { + block_server.run().await; + }); let (state_request_protocol_config, state_request_protocol_name) = { let num_peer_hint = net_config.network_config.default_peers_set_num_full as usize + @@ -860,7 +871,6 @@ where spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); - let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (engine, sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config.role), client.clone(), @@ -872,7 +882,7 @@ where warp_sync_params, chain_sync_network_handle, import_queue.service(), - block_request_protocol_name, + block_downloader, state_request_protocol_name, warp_request_protocol_name, rx, diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index a132cbc46e9..73cc513708d 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -22,6 +22,7 @@ pub mod error; use async_trait::async_trait; +use codec::Codec; use futures::{Future, Stream}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_core::offchain::TransactionPoolExt; @@ -187,7 +188,7 @@ pub trait TransactionPool: Send + Sync { /// Block type. type Block: BlockT; /// Transaction hash type. - type Hash: Hash + Eq + Member + Serialize + DeserializeOwned; + type Hash: Hash + Eq + Member + Serialize + DeserializeOwned + Codec; /// In-pool transaction type. type InPoolTransaction: InPoolTransaction< Transaction = TransactionFor, -- GitLab From 11088bcfc044a983db1271d57aa2853acae20240 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 15 Sep 2023 10:30:20 +0200 Subject: [PATCH 153/633] Added `xcmp_queue_send_xcm_works` test (#1422) This PR adds test case for successful `send_xcm` for `XcmpQueue` according to the opened HRMP channel to the sibling parachain. --- cumulus/pallets/parachain-system/src/lib.rs | 6 ++-- cumulus/pallets/xcmp-queue/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/src/tests.rs | 33 +++++++++++++++++-- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 +-- .../collectives-polkadot/src/impls.rs | 2 +- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index a8e9a0bf9ae..a7e59a61c9b 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -1400,12 +1400,12 @@ impl Pallet { CustomValidationHeadData::::put(head_data); } - /// Open HRMP channel for using it in benchmarks. + /// Open HRMP channel for using it in benchmarks or tests. /// /// The caller assumes that the pallet will accept regular outbound message to the sibling /// `target_parachain` after this call. No other assumptions are made. - #[cfg(feature = "runtime-benchmarks")] - pub fn open_outbound_hrmp_channel_for_benchmarks(target_parachain: ParaId) { + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + pub fn open_outbound_hrmp_channel_for_benchmarks_or_tests(target_parachain: ParaId) { RelevantMessagingState::::put(MessagingStateSnapshot { dmq_mqc_head: Default::default(), relay_dispatch_queue_remaining_capacity: Default::default(), diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index de4ad61de9e..5aab57da91b 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -38,7 +38,7 @@ pallet-balances = { path = "../../../substrate/frame/balances" } xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder" } # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system" } +cumulus-pallet-parachain-system = { path = "../parachain-system", features = ["parameterized-consensus-hook"] } [features] default = [ "std" ] diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 2929e8452be..ba005a5badf 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -14,9 +14,9 @@ // limitations under the License. use super::*; -use cumulus_primitives_core::XcmpMessageHandler; +use cumulus_primitives_core::{ParaId, XcmpMessageHandler}; use frame_support::{assert_noop, assert_ok}; -use mock::{new_test_ext, RuntimeCall, RuntimeOrigin, Test, XcmpQueue}; +use mock::{new_test_ext, ParachainSystem, RuntimeCall, RuntimeOrigin, Test, XcmpQueue}; use sp_runtime::traits::BadOrigin; #[test] @@ -341,3 +341,32 @@ fn xcmp_queue_consumes_dest_and_msg_on_ok_validate() { ); }); } + +#[test] +fn xcmp_queue_send_xcm_works() { + new_test_ext().execute_with(|| { + let sibling_para_id = ParaId::from(12345); + let dest = (Parent, X1(Parachain(sibling_para_id.into()))).into(); + let msg = Xcm(vec![ClearOrigin]); + + // try to send without opened HRMP channel to the sibling_para_id + assert_eq!( + send_xcm::(dest, msg.clone()), + Err(SendError::Transport("NoChannel")), + ); + + // open HRMP channel to the sibling_para_id + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(sibling_para_id); + + // check empty outbound queue + assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); + + // now send works + assert_ok!(send_xcm::(dest, msg)); + + // check outbound queue contains message/page for sibling_para_id + assert!(XcmpQueue::take_outbound_messages(usize::MAX) + .iter() + .any(|(para_id, _)| para_id == &sibling_para_id)); + }) +} 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 309a5cfb0b1..dbdc2133ec8 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 @@ -1070,7 +1070,7 @@ impl_runtime_apis! { ) -> (bridge_hub_rococo_config::FromWococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks(42.into()); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, BridgeGrandpaWococoInstance, @@ -1113,7 +1113,7 @@ impl_runtime_apis! { ) -> (bridge_hub_wococo_config::FromRococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks(42.into()); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, BridgeGrandpaRococoInstance, diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs index c970d82cfe5..9f4c2a6a4c9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs @@ -184,7 +184,7 @@ pub mod benchmarks { impl> EnsureSuccessful for OpenHrmpChannel { fn ensure_successful() { if let ChannelStatus::Closed = ParachainSystem::get_channel_status(I::get().into()) { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks(I::get().into()) + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(I::get().into()) } } } -- GitLab From 1882e9e4570781289442ffd1dcc63225e9ab2f23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 11:45:49 +0200 Subject: [PATCH 154/633] Bump the known_good_semver group with 2 updates (#1553) Bumps the known_good_semver group with 2 updates: [serde_json](https://github.com/serde-rs/json) and [syn](https://github.com/dtolnay/syn). Updates `serde_json` from 1.0.106 to 1.0.107
Release notes

Sourced from serde_json's releases.

v1.0.107

  • impl IntoDeserializer for &RawValue (#1071)
Commits
  • b6e113f Release 1.0.107
  • 00626a0 Merge pull request #1073 from dtolnay/rawvalue
  • b9d296f IntoDeserializer for &RawValue
  • 4ea34a2 Merge pull request #1072 from dtolnay/rawvalue
  • fe30766 Support deserializing from &RawValue
  • 2c22077 Merge pull request #1062 from osiewicz/remove_build_rs
  • 04f7758 fixup! chore: Remove no_btreemap_get_key_value and no_btreemap_remove_entry.
  • 83bdc5f Omit return keyword in remove_entry
  • 89a2741 Revert "Remove limb_width32 and limb_width64 features"
  • 16e04ce fixup! Remove limb_width32 and limb_width64 features
  • See full diff in compare view

Updates `syn` from 2.0.32 to 2.0.33
Release notes

Sourced from syn's releases.

2.0.33

  • Special handling for the (/*ERROR*/) placeholder that rustc uses for macros that fail to expand
Commits
  • 5e3f55e Release 2.0.33
  • 3e04809 Pull in proc-macro2 error placeholder change
  • 2cd5608 Merge pull request #1508 from dtolnay/error
  • 84cfe09 Fall through to 'Unrecognized literal' error
  • a80570c Parse rustc's representation of macro expansion error
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 108 +++++++++--------- .../relay-chain-rpc-interface/Cargo.toml | 2 +- .../parachain-system/proc-macro/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/kusama/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/polkadot/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- .../client/consensus/babe/rpc/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/grandpa/Cargo.toml | 2 +- substrate/client/keystore/Cargo.toml | 2 +- .../merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-servers/Cargo.toml | 2 +- substrate/client/rpc/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../primitives/genesis-builder/Cargo.toml | 2 +- substrate/primitives/rpc/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 55 files changed, 108 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbc9a5dd431..a994d14a322 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,7 +1138,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -1160,7 +1160,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -1177,7 +1177,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -1351,7 +1351,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -2514,7 +2514,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -3574,7 +3574,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4057,7 +4057,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4097,7 +4097,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4114,7 +4114,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4412,7 +4412,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4474,7 +4474,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.32", + "syn 2.0.33", "termcolor", "toml 0.7.6", "walkdir", @@ -4695,7 +4695,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4706,7 +4706,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -4851,7 +4851,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -5207,7 +5207,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.32", + "syn 2.0.33", "trybuild", ] @@ -5359,7 +5359,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -5370,7 +5370,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -5379,7 +5379,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -5602,7 +5602,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -7612,7 +7612,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -7626,7 +7626,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -7637,7 +7637,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -7648,7 +7648,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -9334,7 +9334,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -10405,7 +10405,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -11271,7 +11271,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -11312,7 +11312,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -13291,7 +13291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -13373,14 +13373,14 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -13419,7 +13419,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -13810,7 +13810,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -14573,7 +14573,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -15786,7 +15786,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -16140,7 +16140,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -16154,9 +16154,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -16206,7 +16206,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -16634,7 +16634,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -17034,7 +17034,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -17078,7 +17078,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -17309,7 +17309,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -17549,7 +17549,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -18324,9 +18324,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" dependencies = [ "proc-macro2", "quote", @@ -18571,7 +18571,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -18751,7 +18751,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -18932,7 +18932,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -18975,7 +18975,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -19524,7 +19524,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", "wasm-bindgen-shared", ] @@ -19558,7 +19558,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20694,7 +20694,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -20813,7 +20813,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index fb409dc4a6c..0f09377e106 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -32,7 +32,7 @@ jsonrpsee = { version = "0.16.2", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" -serde_json = "1.0.106" +serde_json = "1.0.107" serde = "1.0.188" schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 22eb6014b3c..77e298363c8 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.32" +syn = "2.0.33" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index ab32a820745..e6fedb5f1fa 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.20" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index e7645201224..0d6cee2ccf0 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.32", features = ["full", "extra-traits"] } +syn = { version = "2.0.33", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index a50f33b98e1..667f9b86d3e 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -78,7 +78,7 @@ futures = "0.3.21" hex-literal = "0.4.1" gum = { package = "tracing-gum", path = "../gum" } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0.48" kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index cf0921ccdfb..ce4148b459e 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -58,7 +58,7 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" } [dev-dependencies] pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -serde_json = "1.0.106" +serde_json = "1.0.107" substrate-test-utils = { path = "../../../../substrate/test-utils" } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 7d8e6a04ca4..17617bf4ada 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -58,7 +58,7 @@ pallet-babe = { path = "../../../substrate/frame/babe" } pallet-treasury = { path = "../../../substrate/frame/treasury" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.106" +serde_json = "1.0.107" libsecp256k1 = "0.7.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index b69bf4183ce..565b34637e2 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -116,7 +116,7 @@ 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.106" +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 } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index f39ce3ffd0d..9f1ec57257f 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -62,7 +62,7 @@ test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../pri sp-tracing = { path = "../../../substrate/primitives/tracing" } thousands = "0.2.0" assert_matches = "1" -serde_json = "1.0.106" +serde_json = "1.0.107" [features] default = [ "std" ] diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index 4bb29b756b5..a659a455322 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -107,7 +107,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.106" +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"] } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index ea8cc2916ef..8f38659b84f 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -99,7 +99,7 @@ keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyrin remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } sp-trie = { path = "../../../substrate/primitives/trie" } separator = "0.4.1" -serde_json = "1.0.106" +serde_json = "1.0.107" sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 2d3451705df..a8f26eb5b3d 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -70,7 +70,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.106" +serde_json = "1.0.107" [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index a6ee22edf5e..f4bb66f68cd 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -108,7 +108,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.106" +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 } diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 99637772131..3e137c42843 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.32" +syn = "2.0.33" Inflector = "0.11.4" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 84191e40f57..05c13e312b2 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -22,7 +22,7 @@ sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" kvdb-rocksdb = "0.19.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 2e60f5c2ff5..84d8de11a35 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -106,7 +106,7 @@ sc-cli = { path = "../../../client/cli", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} node-inspect = { path = "../inspect", optional = true} try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} -serde_json = "1.0.106" +serde_json = "1.0.107" [dev-dependencies] sc-keystore = { path = "../../../client/keystore" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 8208383043d..e326d84ae50 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] memmap2 = "0.5.0" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } sc-executor = { path = "../executor" } diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index e92e66e9046..ff1ce5141e6 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.32" +syn = "2.0.33" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 299c766cd3e..b781e8782ec 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -26,7 +26,7 @@ rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0.48" tiny-bip39 = "1.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 52440970e77..f54edb29684 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -30,7 +30,7 @@ sp-keystore = { path = "../../../../primitives/keystore" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" tokio = "1.22.0" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 6ccf42cfa58..74733ea9edd 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -23,7 +23,7 @@ sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" sc-rpc = { path = "../../../rpc", features = ["test-helpers"]} substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 13b14b7e287..472bdd1c5b8 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -25,7 +25,7 @@ log = "0.4.17" parity-scale-codec = { version = "3.6.1", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0" fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index e89a6148e16..6303ff5c27e 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" parking_lot = "0.12.1" -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0" sp-application-crypto = { path = "../../primitives/application-crypto" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 65a9e5e8aff..05d8547d243 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -23,4 +23,4 @@ sp-runtime = { path = "../../../primitives/runtime" } anyhow = "1" [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index df0b557e6d8..8b188176fc5 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -34,7 +34,7 @@ partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" smallvec = "1.11.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 08c480214f6..a2ee090b1c2 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } sc-transaction-pool-api = { path = "../transaction-pool/api" } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 61280ad224e..674a8db39cb 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" -serde_json = "1.0.106" +serde_json = "1.0.107" tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } tower-http = { version = "0.4.0", features = ["cors"] } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 4998a89b60a..64aaa7c94aa 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" parking_lot = "0.12.1" -serde_json = "1.0.106" +serde_json = "1.0.107" sc-block-builder = { path = "../block-builder" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 5ca3c726971..ccf23bc8994 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -35,7 +35,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-trie = { path = "../../primitives/trie" } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 60089074160..e582d0b7e4f 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0.48" sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index b2fd2bc7e43..fdf987ed45f 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -21,7 +21,7 @@ rand = "0.8.5" rand_pcg = "0.3.1" regex = "1" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 3f2a3002873..6d59b9dfc1a 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0.48" wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 52ecd1a89e7..bf45111de88 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.32", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.33", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index d840c097370..8779f97b9cd 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.32", features = ["full"] } +syn = { version = "2.0.33", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index d2c42fd68f3..50381d83869 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.32", features = ["full", "visit"] } +syn = { version = "2.0.33", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index ab25fdd35c8..fc1f1b4b3ee 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.32", features = ["full", "visit"] } +syn = { version = "2.0.33", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 435a58ba095..62a7b5e41fe 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -42,7 +42,7 @@ sp-core-hashing-proc-macro = { path = "../../primitives/core/hashing/proc-macro" k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features=false} -serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } docify = "0.2.3" static_assertions = "1.1.0" diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 308384f0363..b582457e4b8 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.32", features = ["full"] } +syn = { version = "2.0.33", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 48c8d9eb509..211dc3bd66a 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.32", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.33", 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 e5a05627a6e..472e288c3df 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.32", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.33", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 72ba8234839..5c65ebd4c73 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" pallet-balances = { path = "../balances" } [features] diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index a262e15956a..d3f040e9893 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" serde = { version = "1.0.188", optional = true } [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" sp-storage = { path = "../../../primitives/storage", default-features = false} diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 131f7dcf5b9..d53b9b702e7 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.32", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.33", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index de9168eaf78..5e7cd9e3a7a 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.32", features = ["full", "parsing"] } +syn = { version = "2.0.33", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 4eb24634e65..82f4e8cf604 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.32" +syn = "2.0.33" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 4016a34e9dc..8f083e2d7d5 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { path = "../api", default-features = false} sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} -serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } [features] default = [ "std" ] diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index f65259df135..4739c96740e 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ serde = { version = "1.0.188", features = ["derive"] } sp-core = { path = "../core" } [dev-dependencies] -serde_json = "1.0.106" +serde_json = "1.0.107" diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 4d090937f2d..0884efc56d4 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.32", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.33", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 34e60febb6f..fa3c3ae2e6e 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-weights = { path = "../weights", default-features = false} [dev-dependencies] rand = "0.8.5" -serde_json = "1.0.106" +serde_json = "1.0.107" zstd = { version = "0.12.4", default-features = false } sp-api = { path = "../api" } sp-state-machine = { path = "../state-machine" } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 1824c97b189..a3478e3e5ca 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.32", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.33", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 04681789560..12863ac184c 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ "test-helpers", diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 9921d6b1c06..727d46cb8f5 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -49,7 +49,7 @@ sp-externalities = { path = "../../primitives/externalities", default-features = array-bytes = { version = "6.1", optional = true } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } -serde_json = { version = "1.0.106", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } [dev-dependencies] futures = "0.3.21" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 8cc12772d4e..017e4b4d503 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ log = "0.4.17" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" thiserror = "1.0.48" thousands = "0.2.0" frame-benchmarking = { path = "../../../frame/benchmarking" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 9a21f68aa0b..c736c3f6cc5 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -40,7 +40,7 @@ hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" serde = "1.0.188" -serde_json = "1.0.106" +serde_json = "1.0.107" zstd = { version = "0.12.4", default-features = false } [dev-dependencies] -- GitLab From b300efcb574e478aeb867c2149d7bc1196b7a31b Mon Sep 17 00:00:00 2001 From: Lulu Date: Fri, 15 Sep 2023 10:50:23 +0100 Subject: [PATCH 155/633] Enable publishing of crates that are deps of other published crates (#1573) --- bridges/bin/runtime-common/Cargo.toml | 1 - bridges/modules/grandpa/Cargo.toml | 1 - bridges/modules/messages/Cargo.toml | 1 - bridges/modules/parachains/Cargo.toml | 1 - bridges/modules/relayers/Cargo.toml | 1 - bridges/modules/xcm-bridge-hub-router/Cargo.toml | 1 - bridges/primitives/chain-asset-hub-kusama/Cargo.toml | 1 - bridges/primitives/chain-asset-hub-polkadot/Cargo.toml | 1 - bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml | 1 - bridges/primitives/chain-bridge-hub-kusama/Cargo.toml | 1 - bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml | 1 - bridges/primitives/chain-bridge-hub-rococo/Cargo.toml | 1 - bridges/primitives/chain-bridge-hub-wococo/Cargo.toml | 1 - bridges/primitives/chain-kusama/Cargo.toml | 1 - bridges/primitives/chain-polkadot/Cargo.toml | 1 - bridges/primitives/chain-rococo/Cargo.toml | 1 - bridges/primitives/chain-wococo/Cargo.toml | 1 - bridges/primitives/header-chain/Cargo.toml | 1 - bridges/primitives/messages/Cargo.toml | 1 - bridges/primitives/parachains/Cargo.toml | 1 - bridges/primitives/polkadot-core/Cargo.toml | 1 - bridges/primitives/relayers/Cargo.toml | 1 - bridges/primitives/runtime/Cargo.toml | 1 - bridges/primitives/test-utils/Cargo.toml | 1 - bridges/primitives/xcm-bridge-hub-router/Cargo.toml | 1 - cumulus/parachains/pallets/parachain-info/Cargo.toml | 1 - cumulus/parachains/runtimes/assets/test-utils/Cargo.toml | 1 - cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml | 1 - cumulus/parachains/runtimes/test-utils/Cargo.toml | 1 - cumulus/test/relay-sproof-builder/Cargo.toml | 1 - 30 files changed, 30 deletions(-) diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index fed82cc781a..5c3fefc69ce 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -5,7 +5,6 @@ authors.workspace = true edition.workspace = true repository.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index daef4f5061f..05d6a8e5c26 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index c6ae68d88c4..7b7ea061981 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 1c433394cb3..4eb09ed78d1 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 1dc7e9f8152..46fc3bb43b1 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index b180985cd64..c61cab291e1 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml index 772130b6e51..adb9a57bc13 100644 --- a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml index db73bc6e14a..857ead15b0d 100644 --- a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index a4afec8fdc4..24cf7236d45 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index bb3798d11e2..387f5e8ade6 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 4321138dc50..40b386e22d2 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index aa15656fc3a..05b8163e9fc 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml index 7ae16cfb754..17c134f4412 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml index 7670dc9acc3..2d63c3f374f 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml index efcf516f5db..539b10ef9c6 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml index 2906bf1e267..3c4d3917bc2 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/chain-wococo/Cargo.toml b/bridges/primitives/chain-wococo/Cargo.toml index bb7ada6c04d..05901821b36 100644 --- a/bridges/primitives/chain-wococo/Cargo.toml +++ b/bridges/primitives/chain-wococo/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index ecde073c35e..e3e83235960 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 411f10f44c2..b30d6d2559f 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 9d6f865cc1d..ca69523dde3 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index f2e38030143..aa7eb8024fb 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 93625a05855..99cd79c6841 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 6e2762bc118..4454066b59f 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 652ffe985c6..7081ce90f97 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] bp-header-chain = { path = "../header-chain", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index fe68183f904..725a7d94564 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 4ed11e39439..931df9d9273 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -3,7 +3,6 @@ authors.workspace = true edition.workspace = true name = "parachain-info" version = "0.1.0" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 7fee710f000..0a27535ed22 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -4,7 +4,6 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Test utils for Asset Hub runtimes." -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 4a15640952d..d56c32d8afa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Utils for BridgeHub testing" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 681e5e64d41..378d9ea4c42 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -4,7 +4,6 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Utils for Runtimes testing" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index c987a2b66c9..e044b92f7c4 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -3,7 +3,6 @@ name = "cumulus-test-relay-sproof-builder" version = "0.1.0" authors.workspace = true edition.workspace = true -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -- GitLab From 841a33ede4c991521d5c3ebf852170e978660742 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Fri, 15 Sep 2023 11:52:05 +0200 Subject: [PATCH 156/633] asset-rate pallet: box asset kind parameter (#1545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `AssetKind` type parameter of a dispatchable, defined by the user, might be large — like `xcm::MultiLocation`. To prevent inflating the size of the `Call` type, we `Box` it. This changes required for https://github.com/paritytech/polkadot-sdk/pull/1333 --------- Co-authored-by: Oliver Tale-Yazdi --- .../frame/asset-rate/src/benchmarking.rs | 10 ++-- substrate/frame/asset-rate/src/lib.rs | 27 ++++++---- substrate/frame/asset-rate/src/tests.rs | 52 +++++++++++++++---- 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/substrate/frame/asset-rate/src/benchmarking.rs b/substrate/frame/asset-rate/src/benchmarking.rs index 12edcf5aee0..21d53a89e39 100644 --- a/substrate/frame/asset-rate/src/benchmarking.rs +++ b/substrate/frame/asset-rate/src/benchmarking.rs @@ -54,7 +54,7 @@ mod benchmarks { fn create() -> Result<(), BenchmarkError> { let asset_kind: T::AssetKind = T::BenchmarkHelper::create_asset_kind(SEED); #[extrinsic_call] - _(RawOrigin::Root, asset_kind.clone(), default_conversion_rate()); + _(RawOrigin::Root, Box::new(asset_kind.clone()), default_conversion_rate()); assert_eq!( pallet_asset_rate::ConversionRateToNative::::get(asset_kind), @@ -68,12 +68,12 @@ mod benchmarks { let asset_kind: T::AssetKind = T::BenchmarkHelper::create_asset_kind(SEED); assert_ok!(AssetRate::::create( RawOrigin::Root.into(), - asset_kind.clone(), + Box::new(asset_kind.clone()), default_conversion_rate() )); #[extrinsic_call] - _(RawOrigin::Root, asset_kind.clone(), FixedU128::from_u32(2)); + _(RawOrigin::Root, Box::new(asset_kind.clone()), FixedU128::from_u32(2)); assert_eq!( pallet_asset_rate::ConversionRateToNative::::get(asset_kind), @@ -87,12 +87,12 @@ mod benchmarks { let asset_kind: T::AssetKind = T::BenchmarkHelper::create_asset_kind(SEED); assert_ok!(AssetRate::::create( RawOrigin::Root.into(), - asset_kind.clone(), + Box::new(asset_kind.clone()), default_conversion_rate() )); #[extrinsic_call] - _(RawOrigin::Root, asset_kind.clone()); + _(RawOrigin::Root, Box::new(asset_kind.clone())); assert!(pallet_asset_rate::ConversionRateToNative::::get(asset_kind).is_none()); Ok(()) diff --git a/substrate/frame/asset-rate/src/lib.rs b/substrate/frame/asset-rate/src/lib.rs index 8b55f3d1d40..c3dc551f876 100644 --- a/substrate/frame/asset-rate/src/lib.rs +++ b/substrate/frame/asset-rate/src/lib.rs @@ -61,6 +61,7 @@ use frame_support::traits::{fungible::Inspect, tokens::ConversionFromAssetBalance}; use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128}; +use sp_std::boxed::Box; pub use pallet::*; pub use weights::WeightInfo; @@ -155,18 +156,18 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, - asset_kind: T::AssetKind, + asset_kind: Box, rate: FixedU128, ) -> DispatchResult { T::CreateOrigin::ensure_origin(origin)?; ensure!( - !ConversionRateToNative::::contains_key(asset_kind.clone()), + !ConversionRateToNative::::contains_key(asset_kind.as_ref()), Error::::AlreadyExists ); - ConversionRateToNative::::set(asset_kind.clone(), Some(rate)); + ConversionRateToNative::::set(asset_kind.as_ref(), Some(rate)); - Self::deposit_event(Event::AssetRateCreated { asset_kind, rate }); + Self::deposit_event(Event::AssetRateCreated { asset_kind: *asset_kind, rate }); Ok(()) } @@ -178,13 +179,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::update())] pub fn update( origin: OriginFor, - asset_kind: T::AssetKind, + asset_kind: Box, rate: FixedU128, ) -> DispatchResult { T::UpdateOrigin::ensure_origin(origin)?; let mut old = FixedU128::zero(); - ConversionRateToNative::::mutate(asset_kind.clone(), |maybe_rate| { + ConversionRateToNative::::mutate(asset_kind.as_ref(), |maybe_rate| { if let Some(r) = maybe_rate { old = *r; *r = rate; @@ -195,7 +196,11 @@ pub mod pallet { } })?; - Self::deposit_event(Event::AssetRateUpdated { asset_kind, old, new: rate }); + Self::deposit_event(Event::AssetRateUpdated { + asset_kind: *asset_kind, + old, + new: rate, + }); Ok(()) } @@ -205,16 +210,16 @@ pub mod pallet { /// - O(1) #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::remove())] - pub fn remove(origin: OriginFor, asset_kind: T::AssetKind) -> DispatchResult { + pub fn remove(origin: OriginFor, asset_kind: Box) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; ensure!( - ConversionRateToNative::::contains_key(asset_kind.clone()), + ConversionRateToNative::::contains_key(asset_kind.as_ref()), Error::::UnknownAssetKind ); - ConversionRateToNative::::remove(asset_kind.clone()); + ConversionRateToNative::::remove(asset_kind.as_ref()); - Self::deposit_event(Event::AssetRateRemoved { asset_kind }); + Self::deposit_event(Event::AssetRateRemoved { asset_kind: *asset_kind }); Ok(()) } } diff --git a/substrate/frame/asset-rate/src/tests.rs b/substrate/frame/asset-rate/src/tests.rs index 8990ba9fc28..45226547609 100644 --- a/substrate/frame/asset-rate/src/tests.rs +++ b/substrate/frame/asset-rate/src/tests.rs @@ -29,7 +29,11 @@ const ASSET_ID: u32 = 42; fn create_works() { new_test_ext().execute_with(|| { assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); - assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.1) + )); assert_eq!( pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID), @@ -42,10 +46,18 @@ fn create_works() { fn create_existing_throws() { new_test_ext().execute_with(|| { assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); - assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.1) + )); assert_noop!( - AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1)), + AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.1) + ), Error::::AlreadyExists ); }); @@ -54,9 +66,13 @@ fn create_existing_throws() { #[test] fn remove_works() { new_test_ext().execute_with(|| { - assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.1) + )); - assert_ok!(AssetRate::remove(RuntimeOrigin::root(), ASSET_ID,)); + assert_ok!(AssetRate::remove(RuntimeOrigin::root(), Box::new(ASSET_ID),)); assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); }); } @@ -65,7 +81,7 @@ fn remove_works() { fn remove_unknown_throws() { new_test_ext().execute_with(|| { assert_noop!( - AssetRate::remove(RuntimeOrigin::root(), ASSET_ID,), + AssetRate::remove(RuntimeOrigin::root(), Box::new(ASSET_ID),), Error::::UnknownAssetKind ); }); @@ -74,8 +90,16 @@ fn remove_unknown_throws() { #[test] fn update_works() { new_test_ext().execute_with(|| { - assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); - assert_ok!(AssetRate::update(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.5))); + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.1) + )); + assert_ok!(AssetRate::update( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.5) + )); assert_eq!( pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID), @@ -88,7 +112,11 @@ fn update_works() { fn update_unknown_throws() { new_test_ext().execute_with(|| { assert_noop!( - AssetRate::update(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.5)), + AssetRate::update( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(0.5) + ), Error::::UnknownAssetKind ); }); @@ -97,7 +125,11 @@ fn update_unknown_throws() { #[test] fn convert_works() { new_test_ext().execute_with(|| { - assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(2.51))); + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_float(2.51) + )); let conversion = , -- GitLab From 76c68ee2037cd525b63f07fcb7c0ca69d796d9e2 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Sat, 16 Sep 2023 00:29:11 +0300 Subject: [PATCH 157/633] rpc-v2: Change method name for provided events (#1593) This PR changes the method name of the subscription that provides JSON-RPC notifications (ie subscription events). This brings the raw JSON response in sync with the rpc-spec-v2 format. Changes: - `chainHead_unstable_follow` to `chainHead_unstable_followEvent` [spec/chainHead](https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/chainHead_unstable_follow.md#notifications-format) - `transaction_unstable_submitAndWatch` to `transaction_unstable_watchEvent` [spec/tx](https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/transaction_unstable_submitAndWatch.md#notifications-format) @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- substrate/client/rpc-spec-v2/src/chain_head/api.rs | 2 +- substrate/client/rpc-spec-v2/src/transaction/api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index 682cd690dd1..d93c4018b60 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -30,7 +30,7 @@ pub trait ChainHeadApi { /// /// This method is unstable and subject to change in the future. #[subscription( - name = "chainHead_unstable_follow", + name = "chainHead_unstable_follow" => "chainHead_unstable_followEvent", unsubscribe = "chainHead_unstable_unfollow", item = FollowEvent, )] diff --git a/substrate/client/rpc-spec-v2/src/transaction/api.rs b/substrate/client/rpc-spec-v2/src/transaction/api.rs index c226ab86787..3eb6cb204f2 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/api.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/api.rs @@ -29,7 +29,7 @@ pub trait TransactionApi { /// See [`TransactionEvent`](crate::transaction::event::TransactionEvent) for details on /// transaction life cycle. #[subscription( - name = "transaction_unstable_submitAndWatch" => "transaction_unstable_submitExtrinsic", + name = "transaction_unstable_submitAndWatch" => "transaction_unstable_watchEvent", unsubscribe = "transaction_unstable_unwatch", item = TransactionEvent, )] -- GitLab From 11d1a3955e4bfd536e7716132f5440d7e75e43e5 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Sat, 16 Sep 2023 12:42:43 +0200 Subject: [PATCH 158/633] Include `bitvec` in `std` for Broker Pallet (#1558) When adding this pallet to the [Coretime Chain](https://github.com/paritytech/polkadot-sdk/pull/1479), this dependency results in conflicting implementations (rustc error below). This toml change fixes it. ``` error: failed to run custom build command for `coretime-rococo-runtime v1.0.0 (/home/joe/parity/polkadot-sdk/cumulus/parachains/runtimes/coretime/coretime-rococo)` Caused by: process didn't exit successfully: `/home/joe/parity/polkadot-sdk/target/debug/build/coretime-rococo-runtime-7943703d2770a119/build-script-build` (exit status: 1) --- stdout Information that should be included in a bug report. Executing build command: RUSTFLAGS="-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table -Clink-arg=--export=__heap_base -C link-arg=--import-memory " SKIP_WASM_BUILD="" "/home/joe/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo" "rustc" "--target=wasm32-unknown-unknown" "--manifest-path=/home/joe/parity/polkadot-sdk/target/debug/wbuild/coretime-rococo-runtime/Cargo.toml" "--color=always" "--profile" "release" Using rustc version: rustc 1.71.1 (eb26296b5 2023-08-03) --- stderr Compiling sp-io v23.0.0 (/home/joe/parity/polkadot-sdk/substrate/primitives/io) Compiling coretime-rococo-runtime v1.0.0 (/home/joe/parity/polkadot-sdk/cumulus/parachains/runtimes/coretime/coretime-rococo) error[E0152]: found duplicate lang item `panic_impl` --> /home/joe/parity/polkadot-sdk/substrate/primitives/io/src/lib.rs:1749:1 | 1749 | pub fn panic(info: &core::panic::PanicInfo) -> ! { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `std` (which `bitvec` depends on) = note: first definition in `std` loaded from /home/joe/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libstd-67dfbacfb4b441ef.rlib = note: second definition in the local crate (`sp_io`) For more information about this error, try `rustc --explain E0152`. ``` --- substrate/frame/broker/Cargo.toml | 3 ++- substrate/frame/broker/README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index edb3c5f63bb..d6c5399d56e 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -bitvec = "1" +bitvec = { version = "1.0.0", default-features = false } sp-std = { path = "../../primitives/std", default-features = false} sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} @@ -30,6 +30,7 @@ sp-io = { path = "../../primitives/io" } default = [ "std" ] std = [ + "bitvec/std", "codec/std", "frame-benchmarking?/std", "frame-support/std", diff --git a/substrate/frame/broker/README.md b/substrate/frame/broker/README.md index 65b6179863e..a3c4b251a45 100644 --- a/substrate/frame/broker/README.md +++ b/substrate/frame/broker/README.md @@ -4,7 +4,7 @@ Brokerage tool for managing Polkadot Core scheduling. Properly described in RFC-0001 Agile Coretime. -## Implemnentation Specifics +## Implementation Specifics ### Core Mask Bits -- GitLab From d787269cdfba050d5f966c377df645094a53df14 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 17 Sep 2023 12:19:18 +0100 Subject: [PATCH 159/633] FRAME: Revamp Preimage pallet to use Consideration (#1363) Make Preimage pallet use Consideration instead of handling deposits directly. Other half of paritytech/substrate#13666. Depends/based on #1361. Script for the lazy migration that should be run manually once: [migrate-preimage-lazy.py](https://github.com/ggwpez/substrate-scripts/blob/master/migrate-preimage-lazy.py). ## TODO - [x] Migration code. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .../collectives-polkadot/src/lib.rs | 18 +- .../src/weights/pallet_preimage.rs | 15 + polkadot/runtime/kusama/src/lib.rs | 16 +- .../kusama/src/weights/pallet_preimage.rs | 15 + polkadot/runtime/polkadot/src/lib.rs | 19 +- .../polkadot/src/weights/pallet_preimage.rs | 15 + polkadot/runtime/rococo/src/lib.rs | 16 +- .../rococo/src/weights/pallet_preimage.rs | 15 + polkadot/runtime/westend/src/lib.rs | 18 +- .../westend/src/weights/pallet_preimage.rs | 15 + substrate/bin/node/runtime/src/lib.rs | 15 +- .../balances/src/tests/currency_tests.rs | 14 +- substrate/frame/democracy/src/tests.rs | 3 +- substrate/frame/preimage/src/benchmarking.rs | 77 +-- substrate/frame/preimage/src/lib.rs | 224 ++++++--- substrate/frame/preimage/src/migration.rs | 33 +- substrate/frame/preimage/src/mock.rs | 35 +- substrate/frame/preimage/src/tests.rs | 68 ++- substrate/frame/preimage/src/weights.rs | 438 +++++++++++------- substrate/frame/referenda/src/mock.rs | 3 +- substrate/frame/scheduler/src/mock.rs | 5 +- substrate/frame/support/src/dispatch.rs | 9 + substrate/frame/support/src/traits.rs | 4 +- substrate/frame/support/src/traits/storage.rs | 40 +- substrate/frame/whitelist/src/mock.rs | 3 +- 25 files changed, 787 insertions(+), 346 deletions(-) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 238db08a0c9..d9125c2645e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -67,7 +67,10 @@ use frame_support::{ construct_runtime, dispatch::DispatchClass, parameter_types, - traits::{ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter}, + traits::{ + fungible::HoldConsideration, ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, + EitherOfDiverse, InstanceFilter, LinearStoragePrice, + }, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -209,7 +212,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; + type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<0>; } @@ -545,6 +548,7 @@ impl pallet_scheduler::Config for Runtime { 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 { @@ -552,8 +556,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -589,7 +597,7 @@ construct_runtime!( Utility: pallet_utility::{Pallet, Call, Event} = 40, Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 43, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 43, Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 44, // The main stage. diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs index cf2f0ae39da..e9f565d9387 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs @@ -50,6 +50,21 @@ 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) diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 659a7052d2b..fc9fd61790e 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -63,8 +63,9 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, - PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, + StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -239,6 +240,7 @@ impl pallet_scheduler::Config for Runtime { 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 { @@ -246,8 +248,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } parameter_types! { @@ -1560,7 +1566,7 @@ construct_runtime! { Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 31, // Preimage registrar. - Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 32, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 32, // Bounties modules. Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 35, diff --git a/polkadot/runtime/kusama/src/weights/pallet_preimage.rs b/polkadot/runtime/kusama/src/weights/pallet_preimage.rs index 8c04eb2cd4e..d0bf2056660 100644 --- a/polkadot/runtime/kusama/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/kusama/src/weights/pallet_preimage.rs @@ -50,6 +50,21 @@ 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) diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index 45ea561b33f..6d06ee46933 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -47,8 +47,9 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, - PrivilegeCmp, ProcessMessage, ProcessMessageError, WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, + WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -221,9 +222,9 @@ impl pallet_scheduler::Config for Runtime { } parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; 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 { @@ -231,8 +232,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } parameter_types! { @@ -297,7 +302,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; + type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<0>; } @@ -1326,7 +1331,7 @@ construct_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} = 10, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 10, // Babe must be before session. Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2, diff --git a/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs b/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs index 91605e072f0..a283f09eae5 100644 --- a/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs @@ -50,6 +50,21 @@ 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) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index e043852901f..6446ac4f00c 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -60,8 +60,9 @@ use beefy_primitives::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - Contains, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, - PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, Contains, EitherOfDiverse, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, PrivilegeCmp, ProcessMessage, + ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -224,6 +225,7 @@ impl pallet_scheduler::Config for Runtime { 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 { @@ -231,8 +233,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } parameter_types! { @@ -1449,7 +1455,7 @@ construct_runtime! { Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 31, // Preimage registrar. - Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 32, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 32, // Bounties modules. Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 35, diff --git a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs index b067e6a6d91..e051ebd5bba 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs @@ -47,6 +47,21 @@ 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) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 7dfc781d246..9a7e7c4548c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -29,8 +29,8 @@ use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, Se use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, InstanceFilter, KeyOwnerProofSystem, ProcessMessage, ProcessMessageError, - WithdrawReasons, + fungible::HoldConsideration, ConstU32, InstanceFilter, KeyOwnerProofSystem, + LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -193,9 +193,9 @@ impl pallet_scheduler::Config for Runtime { } parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; 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 { @@ -203,8 +203,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } parameter_types! { @@ -268,7 +272,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; + type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<0>; } @@ -1311,7 +1315,7 @@ construct_runtime! { Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 20, // Preimage registrar. - Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 28, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 28, // Sudo. Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 21, diff --git a/polkadot/runtime/westend/src/weights/pallet_preimage.rs b/polkadot/runtime/westend/src/weights/pallet_preimage.rs index 39d3626b189..0c4677a7d96 100644 --- a/polkadot/runtime/westend/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/westend/src/weights/pallet_preimage.rs @@ -50,6 +50,21 @@ 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) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 4f34e4ecd81..a97f2b09118 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -35,11 +35,12 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - fungible::{Balanced, Credit, ItemOf}, + fungible::{Balanced, Credit, HoldConsideration, ItemOf}, tokens::{nonfungibles_v2::Inspect, GetSalary, PayFromAccount}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency, EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter, - KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, WithdrawReasons, + KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced, + WithdrawReasons, }, weights::{ constants::{ @@ -447,10 +448,10 @@ impl pallet_glutton::Config for Runtime { } parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; pub const PreimageBaseDeposit: Balance = 1 * DOLLARS; // One cent: $10,000 / MB pub const PreimageByteDeposit: Balance = 1 * CENTS; + pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); } impl pallet_preimage::Config for Runtime { @@ -458,8 +459,12 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } parameter_types! { diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 969731b49a2..2449638788d 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -22,7 +22,7 @@ use crate::NegativeImbalance; use frame_support::traits::{ BalanceStatus::{Free, Reserved}, Currency, - ExistenceRequirement::{self, AllowDeath}, + ExistenceRequirement::{self, AllowDeath, KeepAlive}, Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, WithdrawReasons, }; @@ -33,6 +33,18 @@ const ID_2: LockIdentifier = *b"2 "; pub const CALL: &::RuntimeCall = &RuntimeCall::Balances(crate::Call::transfer_allow_death { dest: 0, value: 0 }); +#[test] +fn ed_should_work() { + ExtBuilder::default().existential_deposit(1).build_and_execute_with(|| { + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 1000)); + assert_noop!( + >::transfer(&1, &10, 1000, KeepAlive), + TokenError::NotExpendable + ); + assert_ok!(>::transfer(&1, &10, 1000, AllowDeath)); + }); +} + #[test] fn set_lock_with_amount_zero_removes_lock() { ExtBuilder::default() diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index e5cfcc5b400..9b885fb5915 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -111,8 +111,7 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = ConstU64<0>; - type ByteDeposit = ConstU64<0>; + type Consideration = (); } impl pallet_scheduler::Config for Test { diff --git a/substrate/frame/preimage/src/benchmarking.rs b/substrate/frame/preimage/src/benchmarking.rs index b719c28be64..d7c643ff904 100644 --- a/substrate/frame/preimage/src/benchmarking.rs +++ b/substrate/frame/preimage/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Preimage pallet benchmarking. use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -26,11 +26,9 @@ use sp_std::{prelude::*, vec}; use crate::Pallet as Preimage; -const SEED: u32 = 0; - -fn funded_account(name: &'static str, index: u32) -> T::AccountId { - let caller: T::AccountId = account(name, index, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); +fn funded_account() -> T::AccountId { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); caller } @@ -49,8 +47,7 @@ benchmarks! { // Expensive note - will reserve. note_preimage { let s in 0 .. MAX_SIZE; - let caller = funded_account::("caller", 0); - whitelist_account!(caller); + let caller = funded_account::(); let (preimage, hash) = sized_preimage_and_hash::(s); }: _(RawOrigin::Signed(caller), preimage) verify { @@ -59,8 +56,7 @@ benchmarks! { // Cheap note - will not reserve since it was requested. note_requested_preimage { let s in 0 .. MAX_SIZE; - let caller = funded_account::("caller", 0); - whitelist_account!(caller); + let caller = funded_account::(); let (preimage, hash) = sized_preimage_and_hash::(s); assert_ok!(Preimage::::request_preimage( T::ManagerOrigin::try_successful_origin() @@ -89,8 +85,7 @@ benchmarks! { // Expensive unnote - will unreserve. unnote_preimage { - let caller = funded_account::("caller", 0); - whitelist_account!(caller); + let caller = funded_account::(); let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); }: _(RawOrigin::Signed(caller), hash) @@ -115,16 +110,15 @@ benchmarks! { // Expensive request - will unreserve the noter's deposit. request_preimage { let (preimage, hash) = preimage_and_hash::(); - let noter = funded_account::("noter", 0); - whitelist_account!(noter); + let noter = funded_account::(); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); }: _( T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into(); - let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) }; - assert_eq!(StatusFor::::get(&hash), Some(s)); + let ticket = TicketOf::::new(¬er, Footprint { count: 1, size: MAX_SIZE as u64 }).unwrap(); + let s = RequestStatus::Requested { maybe_ticket: Some((noter, ticket)), count: 1, maybe_len: Some(MAX_SIZE) }; + assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } // Cheap request - would unreserve the deposit but none was held. request_no_deposit_preimage { @@ -138,8 +132,8 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) }; - assert_eq!(StatusFor::::get(&hash), Some(s)); + let s = RequestStatus::Requested { maybe_ticket: None, count: 2, maybe_len: Some(MAX_SIZE) }; + assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { @@ -148,8 +142,8 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; - assert_eq!(StatusFor::::get(&hash), Some(s)); + let s = RequestStatus::Requested { maybe_ticket: None, count: 1, maybe_len: None }; + assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is already requested, so just a counter bump. request_requested_preimage { @@ -163,8 +157,8 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - let s = RequestStatus::Requested { deposit: None, count: 2, len: None }; - assert_eq!(StatusFor::::get(&hash), Some(s)); + let s = RequestStatus::Requested { maybe_ticket: None, count: 2, maybe_len: None }; + assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } // Expensive unrequest - last reference and it's noted, so will destroy the preimage. @@ -184,7 +178,7 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - assert_eq!(StatusFor::::get(&hash), None); + assert_eq!(RequestStatusFor::::get(&hash), None); } // Cheap unrequest - last reference, but it's not noted. unrequest_unnoted_preimage { @@ -198,7 +192,7 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - assert_eq!(StatusFor::::get(&hash), None); + assert_eq!(RequestStatusFor::::get(&hash), None); } // Cheap unrequest - not the last reference. unrequest_multi_referenced_preimage { @@ -217,9 +211,38 @@ benchmarks! { T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, hash ) verify { - let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; - assert_eq!(StatusFor::::get(&hash), Some(s)); + let s = RequestStatus::Requested { maybe_ticket: None, count: 1, maybe_len: None }; + assert_eq!(RequestStatusFor::::get(&hash), Some(s)); + } + + ensure_updated { + let n in 0..MAX_HASH_UPGRADE_BULK_COUNT; + + let caller = funded_account::(); + let hashes = (0..n).map(|i| insert_old_unrequested::(i)).collect::>(); + }: _(RawOrigin::Signed(caller), hashes) + verify { + assert_eq!(RequestStatusFor::::iter_keys().count(), n as usize); + #[allow(deprecated)] + let c = StatusFor::::iter_keys().count(); + assert_eq!(c, 0); } impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); } + +fn insert_old_unrequested(s: u32) -> ::Hash { + let acc = account("old", s, 0); + T::Currency::make_free_balance_be(&acc, BalanceOf::::max_value() / 2u32.into()); + + // The preimage size does not matter here as it is not touched. + let preimage = s.to_le_bytes(); + let hash = ::Hashing::hash(&preimage[..]); + + #[allow(deprecated)] + StatusFor::::insert( + &hash, + OldRequestStatus::Unrequested { deposit: (acc, 123u32.into()), len: preimage.len() as u32 }, + ); + hash +} diff --git a/substrate/frame/preimage/src/lib.rs b/substrate/frame/preimage/src/lib.rs index 5ab1e7643b2..e603f1a32e6 100644 --- a/substrate/frame/preimage/src/lib.rs +++ b/substrate/frame/preimage/src/lib.rs @@ -37,7 +37,10 @@ mod mock; mod tests; pub mod weights; -use sp_runtime::traits::{BadOrigin, Hash, Saturating}; +use sp_runtime::{ + traits::{BadOrigin, Hash, Saturating}, + Perbill, +}; use sp_std::{borrow::Cow, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -46,8 +49,8 @@ use frame_support::{ ensure, pallet_prelude::Get, traits::{ - Currency, Defensive, FetchResult, Hash as PreimageHash, PreimageProvider, - PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, + Consideration, Currency, Defensive, FetchResult, Footprint, Hash as PreimageHash, + PreimageProvider, PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, }, BoundedSlice, BoundedVec, }; @@ -61,7 +64,7 @@ pub use pallet::*; /// A type to note whether a preimage is owned by a user or the system. #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] -pub enum RequestStatus { +pub enum OldRequestStatus { /// The associated preimage has not yet been requested by the system. The given deposit (if /// some) is being held until either it becomes requested or the user retracts the preimage. Unrequested { deposit: (AccountId, Balance), len: u32 }, @@ -71,13 +74,31 @@ pub enum RequestStatus { Requested { deposit: Option<(AccountId, Balance)>, count: u32, len: Option }, } +/// A type to note whether a preimage is owned by a user or the system. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum RequestStatus { + /// The associated preimage has not yet been requested by the system. The given deposit (if + /// some) is being held until either it becomes requested or the user retracts the preimage. + Unrequested { ticket: (AccountId, Ticket), len: u32 }, + /// There are a non-zero number of outstanding requests for this hash by this chain. If there + /// is a preimage registered, then `len` is `Some` and it may be removed iff this counter + /// becomes zero. + Requested { maybe_ticket: Option<(AccountId, Ticket)>, count: u32, maybe_len: Option }, +} + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type TicketOf = ::Consideration; /// Maximum size of preimage we can store is 4mb. const MAX_SIZE: u32 = 4 * 1024 * 1024; +/// Hard-limit on the number of hashes that can be passed to `ensure_updated`. +/// +/// Exists only for benchmarking purposes. +pub const MAX_HASH_UPGRADE_BULK_COUNT: u32 = 1024; #[frame_support::pallet] +#[allow(deprecated)] pub mod pallet { use super::*; @@ -93,17 +114,15 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; /// Currency type for this pallet. + // TODO#1569: Remove. type Currency: ReservableCurrency; /// An origin that can request a preimage be placed on-chain without a deposit or fee, or /// manage existing preimages. type ManagerOrigin: EnsureOrigin; - /// The base deposit for placing a preimage on chain. - type BaseDeposit: Get>; - - /// The per-byte deposit for placing a preimage on chain. - type ByteDeposit: Get>; + /// A means of providing some cost while data is stored on-chain. + type Consideration: Consideration; } #[pallet::pallet] @@ -135,18 +154,33 @@ pub mod pallet { Requested, /// The preimage request cannot be removed since no outstanding requests exist. NotRequested, + /// More than `MAX_HASH_UPGRADE_BULK_COUNT` hashes were requested to be upgraded at once. + TooMany, + } + + /// A reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The funds are held as storage deposit for a preimage. + Preimage, } /// The request status of a given hash. + #[deprecated = "RequestStatusFor"] #[pallet::storage] pub(super) type StatusFor = - StorageMap<_, Identity, T::Hash, RequestStatus>>; + StorageMap<_, Identity, T::Hash, OldRequestStatus>>; + + /// The request status of a given hash. + #[pallet::storage] + pub(super) type RequestStatusFor = + StorageMap<_, Identity, T::Hash, RequestStatus>>; #[pallet::storage] pub(super) type PreimageFor = StorageMap<_, Identity, (T::Hash, u32), BoundedVec>>; - #[pallet::call] + #[pallet::call(weight = T::WeightInfo)] impl Pallet { /// Register a preimage on-chain. /// @@ -173,7 +207,6 @@ pub mod pallet { /// - `hash`: The hash of the preimage to be removed from the store. /// - `len`: The length of the preimage of `hash`. #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::unnote_preimage())] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; Self::do_unnote_preimage(&hash, maybe_sender) @@ -184,7 +217,6 @@ pub mod pallet { /// If the preimage requests has already been provided on-chain, we unreserve any deposit /// a user may have paid, and take the control of the preimage out of their hands. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::request_preimage())] pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; Self::do_request_preimage(&hash); @@ -195,15 +227,80 @@ pub mod pallet { /// /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::unrequest_preimage())] pub fn unrequest_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; Self::do_unrequest_preimage(&hash) } + + /// Ensure that the a bulk of pre-images is upgraded. + /// + /// The caller pays no fee if at least 90% of pre-images were successfully updated. + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::ensure_updated(hashes.len() as u32))] + pub fn ensure_updated( + origin: OriginFor, + hashes: Vec, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + 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; + let ratio = Perbill::from_rational(updated, hashes.len() as u32); + + let pays: Pays = (ratio < Perbill::from_percent(90)).into(); + Ok(pays.into()) + } } } impl Pallet { + fn do_ensure_updated(h: &T::Hash) -> bool { + #[allow(deprecated)] + let r = match StatusFor::::take(h) { + Some(r) => r, + None => return false, + }; + let n = match r { + OldRequestStatus::Unrequested { deposit: (who, amount), len } => { + // unreserve deposit + T::Currency::unreserve(&who, amount); + // take consideration + let Ok(ticket) = + T::Consideration::new(&who, Footprint::from_parts(1, len as usize)) + .defensive_proof("Unexpected inability to take deposit after unreserved") + else { + return true + }; + RequestStatus::Unrequested { ticket: (who, ticket), len } + }, + OldRequestStatus::Requested { deposit: maybe_deposit, count, len: maybe_len } => { + let maybe_ticket = if let Some((who, deposit)) = maybe_deposit { + // unreserve deposit + T::Currency::unreserve(&who, deposit); + // take consideration + if let Some(len) = maybe_len { + let Ok(ticket) = + T::Consideration::new(&who, Footprint::from_parts(1, len as usize)) + .defensive_proof( + "Unexpected inability to take deposit after unreserved", + ) + else { + return true + }; + Some((who, ticket)) + } else { + None + } + } else { + None + }; + RequestStatus::Requested { maybe_ticket, count, maybe_len } + }, + }; + RequestStatusFor::::insert(h, n); + true + } + /// Ensure that the origin is either the `ManagerOrigin` or a signed origin. fn ensure_signed_or_manager( origin: T::RuntimeOrigin, @@ -230,26 +327,29 @@ impl Pallet { let len = preimage.len() as u32; ensure!(len <= MAX_SIZE, Error::::TooBig); + Self::do_ensure_updated(&hash); // We take a deposit only if there is a provided depositor and the preimage was not // previously requested. This also allows the tx to pay no fee. - let status = match (StatusFor::::get(hash), maybe_depositor) { - (Some(RequestStatus::Requested { count, deposit, .. }), _) => - RequestStatus::Requested { count, deposit, len: Some(len) }, + let status = match (RequestStatusFor::::get(hash), maybe_depositor) { + (Some(RequestStatus::Requested { maybe_ticket, count, .. }), _) => + RequestStatus::Requested { maybe_ticket, count, maybe_len: Some(len) }, (Some(RequestStatus::Unrequested { .. }), Some(_)) => return Err(Error::::AlreadyNoted.into()), - (Some(RequestStatus::Unrequested { len, deposit }), None) => - RequestStatus::Requested { deposit: Some(deposit), count: 1, len: Some(len) }, - (None, None) => RequestStatus::Requested { count: 1, len: Some(len), deposit: None }, + (Some(RequestStatus::Unrequested { ticket, len }), None) => RequestStatus::Requested { + maybe_ticket: Some(ticket), + count: 1, + maybe_len: Some(len), + }, + (None, None) => + RequestStatus::Requested { maybe_ticket: None, count: 1, maybe_len: Some(len) }, (None, Some(depositor)) => { - let length = preimage.len() as u32; - let deposit = T::BaseDeposit::get() - .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); - T::Currency::reserve(depositor, deposit)?; - RequestStatus::Unrequested { deposit: (depositor.clone(), deposit), len } + let ticket = + T::Consideration::new(depositor, Footprint::from_parts(1, len as usize))?; + RequestStatus::Unrequested { ticket: (depositor.clone(), ticket), len } }, }; let was_requested = matches!(status, RequestStatus::Requested { .. }); - StatusFor::::insert(hash, status); + RequestStatusFor::::insert(hash, status); let _ = Self::insert(&hash, preimage) .defensive_proof("Unable to insert. Logic error in `note_bytes`?"); @@ -264,15 +364,19 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: &T::Hash) { - let (count, len, deposit) = - StatusFor::::get(hash).map_or((1, None, None), |x| match x { - RequestStatus::Requested { mut count, len, deposit } => { + Self::do_ensure_updated(&hash); + let (count, maybe_len, maybe_ticket) = + RequestStatusFor::::get(hash).map_or((1, None, None), |x| match x { + RequestStatus::Requested { maybe_ticket, mut count, maybe_len } => { count.saturating_inc(); - (count, len, deposit) + (count, maybe_len, maybe_ticket) }, - RequestStatus::Unrequested { deposit, len } => (1, Some(len), Some(deposit)), + RequestStatus::Unrequested { ticket, len } => (1, Some(len), Some(ticket)), }); - StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); + RequestStatusFor::::insert( + hash, + RequestStatus::Requested { maybe_ticket, count, maybe_len }, + ); if count == 1 { Self::deposit_event(Event::Requested { hash: *hash }); } @@ -288,24 +392,25 @@ impl Pallet { hash: &T::Hash, maybe_check_owner: Option, ) -> DispatchResult { - match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { - RequestStatus::Requested { deposit: Some((owner, deposit)), count, len } => { + Self::do_ensure_updated(&hash); + match RequestStatusFor::::get(hash).ok_or(Error::::NotNoted)? { + RequestStatus::Requested { maybe_ticket: Some((owner, ticket)), count, maybe_len } => { ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); - T::Currency::unreserve(&owner, deposit); - StatusFor::::insert( + let _ = ticket.drop(&owner); + RequestStatusFor::::insert( hash, - RequestStatus::Requested { deposit: None, count, len }, + RequestStatus::Requested { maybe_ticket: None, count, maybe_len }, ); Ok(()) }, - RequestStatus::Requested { deposit: None, .. } => { + RequestStatus::Requested { maybe_ticket: None, .. } => { ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); Self::do_unrequest_preimage(hash) }, - RequestStatus::Unrequested { deposit: (owner, deposit), len } => { + RequestStatus::Unrequested { ticket: (owner, ticket), len } => { ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); - T::Currency::unreserve(&owner, deposit); - StatusFor::::remove(hash); + let _ = ticket.drop(&owner); + RequestStatusFor::::remove(hash); Self::remove(hash, len); Self::deposit_event(Event::Cleared { hash: *hash }); @@ -316,25 +421,32 @@ impl Pallet { /// Clear a preimage request. fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult { - match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { - RequestStatus::Requested { mut count, len, deposit } if count > 1 => { + Self::do_ensure_updated(&hash); + match RequestStatusFor::::get(hash).ok_or(Error::::NotRequested)? { + RequestStatus::Requested { mut count, maybe_len, maybe_ticket } if count > 1 => { count.saturating_dec(); - StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); + RequestStatusFor::::insert( + hash, + RequestStatus::Requested { maybe_ticket, count, maybe_len }, + ); }, - RequestStatus::Requested { count, len, deposit } => { + RequestStatus::Requested { count, maybe_len, maybe_ticket } => { debug_assert!(count == 1, "preimage request counter at zero?"); - match (len, deposit) { + match (maybe_len, maybe_ticket) { // Preimage was never noted. - (None, _) => StatusFor::::remove(hash), + (None, _) => RequestStatusFor::::remove(hash), // Preimage was noted without owner - just remove it. (Some(len), None) => { Self::remove(hash, len); - StatusFor::::remove(hash); + RequestStatusFor::::remove(hash); Self::deposit_event(Event::Cleared { hash: *hash }); }, // Preimage was noted with owner - move to unrequested so they can get refund. - (Some(len), Some(deposit)) => { - StatusFor::::insert(hash, RequestStatus::Unrequested { deposit, len }); + (Some(len), Some(ticket)) => { + RequestStatusFor::::insert( + hash, + RequestStatus::Unrequested { ticket, len }, + ); }, } }, @@ -359,8 +471,10 @@ impl Pallet { fn len(hash: &T::Hash) -> Option { use RequestStatus::*; - match StatusFor::::get(hash) { - Some(Requested { len: Some(len), .. }) | Some(Unrequested { len, .. }) => Some(len), + Self::do_ensure_updated(&hash); + match RequestStatusFor::::get(hash) { + Some(Requested { maybe_len: Some(len), .. }) | Some(Unrequested { len, .. }) => + Some(len), _ => None, } } @@ -380,7 +494,8 @@ impl PreimageProvider for Pallet { } fn preimage_requested(hash: &T::Hash) -> bool { - matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) + Self::do_ensure_updated(hash); + matches!(RequestStatusFor::::get(hash), Some(RequestStatus::Requested { .. })) } fn get_preimage(hash: &T::Hash) -> Option> { @@ -423,7 +538,8 @@ impl> QueryPreimage for Pallet { } fn is_requested(hash: &T::Hash) -> bool { - matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) + Self::do_ensure_updated(&hash); + matches!(RequestStatusFor::::get(hash), Some(RequestStatus::Requested { .. })) } fn request(hash: &T::Hash) { diff --git a/substrate/frame/preimage/src/migration.rs b/substrate/frame/preimage/src/migration.rs index 0f3337e39bf..821cb01bbaa 100644 --- a/substrate/frame/preimage/src/migration.rs +++ b/substrate/frame/preimage/src/migration.rs @@ -37,7 +37,7 @@ mod v0 { use super::*; #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] - pub enum RequestStatus { + pub enum OldRequestStatus { Unrequested(Option<(AccountId, Balance)>), Requested(u32), } @@ -55,7 +55,7 @@ mod v0 { Pallet, Identity, ::Hash, - RequestStatus<::AccountId, BalanceOf>, + OldRequestStatus<::AccountId, BalanceOf>, >; /// Returns the number of images or `None` if the storage is corrupted. @@ -127,21 +127,22 @@ pub mod v1 { } let status = match status { - v0::RequestStatus::Unrequested(deposit) => match deposit { - Some(deposit) => RequestStatus::Unrequested { deposit, len }, + v0::OldRequestStatus::Unrequested(deposit) => match deposit { + Some(deposit) => OldRequestStatus::Unrequested { deposit, len }, // `None` depositor becomes system-requested. None => - RequestStatus::Requested { deposit: None, count: 1, len: Some(len) }, + OldRequestStatus::Requested { deposit: None, count: 1, len: Some(len) }, }, - v0::RequestStatus::Requested(count) if count == 0 => { + v0::OldRequestStatus::Requested(count) if count == 0 => { log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash); continue }, - v0::RequestStatus::Requested(count) => - RequestStatus::Requested { deposit: None, count, len: Some(len) }, + v0::OldRequestStatus::Requested(count) => + OldRequestStatus::Requested { deposit: None, count, len: Some(len) }, }; log::trace!(target: TARGET, "Moving preimage {:?} with len {}", hash, len); + #[allow(deprecated)] crate::StatusFor::::insert(hash, status); crate::PreimageFor::::insert(&(hash, len), preimage); @@ -176,6 +177,7 @@ pub mod v1 { pub fn image_count() -> Option { // Use iter_values() to ensure that the values are decodable. let images = crate::PreimageFor::::iter_values().count() as u32; + #[allow(deprecated)] let status = crate::StatusFor::::iter_values().count() as u32; if images == status { @@ -189,6 +191,7 @@ pub mod v1 { #[cfg(test)] #[cfg(feature = "try-runtime")] mod test { + #![allow(deprecated)] use super::*; use crate::mock::{Test as T, *}; @@ -203,19 +206,19 @@ mod test { // Case 1: Unrequested without deposit let (p, h) = preimage::(128); v0::PreimageFor::::insert(h, p); - v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(None)); + v0::StatusFor::::insert(h, v0::OldRequestStatus::Unrequested(None)); // Case 2: Unrequested with deposit let (p, h) = preimage::(1024); v0::PreimageFor::::insert(h, p); - v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(Some((1, 1)))); + v0::StatusFor::::insert(h, v0::OldRequestStatus::Unrequested(Some((1, 1)))); // Case 3: Requested by 0 (invalid) let (p, h) = preimage::(8192); v0::PreimageFor::::insert(h, p); - v0::StatusFor::::insert(h, v0::RequestStatus::Requested(0)); + v0::StatusFor::::insert(h, v0::OldRequestStatus::Requested(0)); // Case 4: Requested by 10 let (p, h) = preimage::(65536); v0::PreimageFor::::insert(h, p); - v0::StatusFor::::insert(h, v0::RequestStatus::Requested(10)); + v0::StatusFor::::insert(h, v0::OldRequestStatus::Requested(10)); assert_eq!(v0::image_count::(), Some(4)); assert_eq!(v1::image_count::(), None, "V1 storage should be corrupted"); @@ -234,14 +237,14 @@ mod test { assert_eq!(crate::PreimageFor::::get(&(h, 128)), Some(p)); assert_eq!( crate::StatusFor::::get(h), - Some(RequestStatus::Requested { deposit: None, count: 1, len: Some(128) }) + Some(OldRequestStatus::Requested { deposit: None, count: 1, len: Some(128) }) ); // Case 2: Unrequested with deposit becomes unrequested let (p, h) = preimage::(1024); assert_eq!(crate::PreimageFor::::get(&(h, 1024)), Some(p)); assert_eq!( crate::StatusFor::::get(h), - Some(RequestStatus::Unrequested { deposit: (1, 1), len: 1024 }) + Some(OldRequestStatus::Unrequested { deposit: (1, 1), len: 1024 }) ); // Case 3: Requested by 0 should be skipped let (_, h) = preimage::(8192); @@ -252,7 +255,7 @@ mod test { assert_eq!(crate::PreimageFor::::get(&(h, 65536)), Some(p)); assert_eq!( crate::StatusFor::::get(h), - Some(RequestStatus::Requested { deposit: None, count: 10, len: Some(65536) }) + Some(OldRequestStatus::Requested { deposit: None, count: 10, len: Some(65536) }) ); }); } diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs index 2fb9f36dec4..2e7051a99a4 100644 --- a/substrate/frame/preimage/src/mock.rs +++ b/substrate/frame/preimage/src/mock.rs @@ -22,13 +22,13 @@ use super::*; use crate as pallet_preimage; use frame_support::{ ord_parameter_types, - traits::{ConstU32, ConstU64, Everything}, + traits::{fungible::HoldConsideration, ConstU32, ConstU64, Everything}, weights::constants::RocksDbWeight, }; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Convert, IdentityLookup}, BuildStorage, }; @@ -80,22 +80,28 @@ impl pallet_balances::Config for Test { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type FreezeIdentifier = (); - type MaxFreezes = (); + type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); - type MaxHolds = (); + type MaxHolds = ConstU32<2>; } ord_parameter_types! { pub const One: u64 = 1; } +pub struct ConvertDeposit; +impl Convert for ConvertDeposit { + fn convert(a: Footprint) -> u64 { + a.count * 2 + a.size + } +} + impl Config for Test { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureSignedBy; - type BaseDeposit = ConstU64<2>; - type ByteDeposit = ConstU64<1>; + type Consideration = HoldConsideration; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -110,3 +116,20 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn hashed(data: impl AsRef<[u8]>) -> H256 { BlakeTwo256::hash(data.as_ref()) } + +/// Insert an un-migrated preimage. +pub fn insert_old_unrequested( + s: u32, + acc: T::AccountId, +) -> ::Hash { + // The preimage size does not matter here as it is not touched. + let preimage = s.to_le_bytes(); + let hash = ::Hashing::hash(&preimage[..]); + + #[allow(deprecated)] + StatusFor::::insert( + &hash, + OldRequestStatus::Unrequested { deposit: (acc, 123u32.into()), len: preimage.len() as u32 }, + ); + hash +} diff --git a/substrate/frame/preimage/src/tests.rs b/substrate/frame/preimage/src/tests.rs index fa621c8f558..a473a0ae8e2 100644 --- a/substrate/frame/preimage/src/tests.rs +++ b/substrate/frame/preimage/src/tests.rs @@ -24,12 +24,11 @@ use crate::mock::*; use frame_support::{ assert_err, assert_noop, assert_ok, assert_storage_noop, - traits::{Bounded, BoundedInline, Hash as PreimageHash}, + traits::{fungible::InspectHold, Bounded, BoundedInline, Hash as PreimageHash}, StorageNoopGuard, }; -use pallet_balances::Error as BalancesError; use sp_core::{blake2_256, H256}; -use sp_runtime::bounded_vec; +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>) { @@ -52,7 +51,7 @@ pub fn make_bounded_values() -> (Bounded>, Bounded>, Bounded::AlreadyNoted + Error::::AlreadyNoted, ); assert_noop!( Preimage::note_preimage(RuntimeOrigin::signed(0), vec![2]), - BalancesError::::InsufficientBalance + TokenError::FundsUnavailable, ); }); } @@ -171,7 +170,7 @@ fn request_note_order_makes_no_difference() { assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( - StatusFor::::iter().collect::>(), + RequestStatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); @@ -180,7 +179,7 @@ fn request_note_order_makes_no_difference() { assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( - StatusFor::::iter().collect::>(), + RequestStatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ); assert_eq!(one_way, other_way); @@ -207,7 +206,7 @@ fn request_user_note_order_makes_no_difference() { assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( - StatusFor::::iter().collect::>(), + RequestStatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); @@ -216,7 +215,7 @@ fn request_user_note_order_makes_no_difference() { assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( - StatusFor::::iter().collect::>(), + RequestStatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ); assert_eq!(one_way, other_way); @@ -249,13 +248,14 @@ fn unrequest_preimage_works() { fn user_noted_then_requested_preimage_is_refunded_once_only() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1; 3])); + assert_eq!(Balances::balance_on_hold(&(), &2), 5); assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_eq!(Balances::balance_on_hold(&(), &2), 8); assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); - // Still have reserve from `vec[1; 3]`. - assert_eq!(Balances::reserved_balance(2), 5); - assert_eq!(Balances::free_balance(2), 95); + // Still have hold from `vec[1; 3]`. + assert_eq!(Balances::balance_on_hold(&(), &2), 5); }); } @@ -270,7 +270,7 @@ fn noted_preimage_use_correct_map() { assert_eq!(PreimageFor::::iter().count(), 8); // All are present - assert_eq!(StatusFor::::iter().count(), 8); + assert_eq!(RequestStatusFor::::iter().count(), 8); // Now start removing them again... for i in 0..7 { @@ -287,7 +287,7 @@ fn noted_preimage_use_correct_map() { assert_eq!(PreimageFor::::iter().count(), 0); // All are gone - assert_eq!(StatusFor::::iter().count(), 0); + assert_eq!(RequestStatusFor::::iter().count(), 0); }); } @@ -327,20 +327,20 @@ fn query_and_store_preimage_workflow() { Preimage::request(&hash); // It is requested thrice. assert!(matches!( - StatusFor::::get(&hash).unwrap(), + RequestStatusFor::::get(&hash).unwrap(), RequestStatus::Requested { count: 3, .. } )); // It can be realized and decoded correctly. assert_eq!(Preimage::realize::>(&bound).unwrap(), (data.clone(), Some(len))); assert!(matches!( - StatusFor::::get(&hash).unwrap(), + RequestStatusFor::::get(&hash).unwrap(), RequestStatus::Requested { count: 2, .. } )); // Dropping should unrequest. Preimage::drop(&bound); assert!(matches!( - StatusFor::::get(&hash).unwrap(), + RequestStatusFor::::get(&hash).unwrap(), RequestStatus::Requested { count: 1, .. } )); @@ -381,7 +381,7 @@ fn query_preimage_request_works() { assert!(::len(&hash).is_none()); assert_noop!(::fetch(&hash, None), DispatchError::Unavailable); // But there is only one entry in the map. - assert_eq!(StatusFor::::iter().count(), 1); + assert_eq!(RequestStatusFor::::iter().count(), 1); // Un-request the preimage. ::unrequest(&hash); @@ -392,7 +392,7 @@ fn query_preimage_request_works() { // It is not requested anymore. assert!(!::is_requested(&hash)); // And there is no entry in the map. - assert_eq!(StatusFor::::iter().count(), 0); + assert_eq!(RequestStatusFor::::iter().count(), 0); }); } @@ -413,7 +413,7 @@ fn query_preimage_hold_and_drop_work() { assert!(::is_requested(&legacy.hash())); // There are two values requested in total. - assert_eq!(StatusFor::::iter().count(), 2); + assert_eq!(RequestStatusFor::::iter().count(), 2); // Cleanup by dropping both. ::drop(&lookup); @@ -422,7 +422,7 @@ fn query_preimage_hold_and_drop_work() { assert!(!::is_requested(&legacy.hash())); // There are no values requested anymore. - assert_eq!(StatusFor::::iter().count(), 0); + assert_eq!(RequestStatusFor::::iter().count(), 0); }); } @@ -489,3 +489,27 @@ fn store_preimage_bound_too_large_errors() { assert_ok!(::bound(data.clone())); }); } + +#[test] +fn ensure_updated_works() { + #![allow(deprecated)] + new_test_ext().execute_with(|| { + let alice = 2; + + for i in 0..100 { + let hashes = + (0..100).map(|j| insert_old_unrequested::(j, alice)).collect::>(); + let old = hashes.iter().take(i).cloned().collect::>(); + let bad = vec![hashed([0; 32]); 100 - i]; + + let hashes = [old.as_slice(), bad.as_slice()].concat(); + let res = Preimage::ensure_updated(RuntimeOrigin::signed(alice), hashes).unwrap(); + + // Alice pays a fee when less than 90% of the hashes are new. + assert_eq!(res.pays_fee, (i < 90).into()); + + assert_eq!(RequestStatusFor::::iter().count(), i); + assert_eq!(StatusFor::::iter().count(), 100 - i); + } + }); +} diff --git a/substrate/frame/preimage/src/weights.rs b/substrate/frame/preimage/src/weights.rs index 41e58a10278..c11ab74c1e5 100644 --- a/substrate/frame/preimage/src/weights.rs +++ b/substrate/frame/preimage/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_preimage +//! Autogenerated weights for `pallet_preimage` //! //! 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-06, 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-mia4uyug-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_preimage -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/preimage/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_preimage +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/preimage/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![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_preimage. +/// Weight functions needed for `pallet_preimage`. pub trait WeightInfo { fn note_preimage(s: u32, ) -> Weight; fn note_requested_preimage(s: u32, ) -> Weight; @@ -64,319 +61,410 @@ pub trait WeightInfo { fn unrequest_preimage() -> Weight; fn unrequest_unnoted_preimage() -> Weight; fn unrequest_multi_referenced_preimage() -> Weight; + fn ensure_updated(n: u32, ) -> Weight; } -/// Weights for pallet_preimage using the Substrate node and recommended hardware. +/// Weights for `pallet_preimage` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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` + // Measured: `42` // Estimated: `3556` - // Minimum execution time: 30_479_000 picoseconds. - Weight::from_parts(23_381_775, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_670, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 15_936_000 picoseconds. + Weight::from_parts(16_271_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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_104_000 picoseconds. - Weight::from_parts(18_393_879, 3556) + // Minimum execution time: 16_468_000 picoseconds. + Weight::from_parts(17_031_000, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_669, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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_652_000 picoseconds. - Weight::from_parts(22_031_627, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_672, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 16_342_000 picoseconds. + Weight::from_parts(16_535_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 37_148_000 picoseconds. - Weight::from_parts(40_247_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 31_047_000 picoseconds. + Weight::from_parts(34_099_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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: 19_909_000 picoseconds. - Weight::from_parts(21_572_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 32_559_000 picoseconds. + Weight::from_parts(36_677_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `188` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 17_602_000 picoseconds. - Weight::from_parts(18_899_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 27_887_000 picoseconds. + Weight::from_parts(30_303_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 11_253_000 picoseconds. - Weight::from_parts(11_667_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 17_256_000 picoseconds. + Weight::from_parts(19_481_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3556` - // Minimum execution time: 14_152_000 picoseconds. - Weight::from_parts(14_652_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 22_344_000 picoseconds. + Weight::from_parts(23_868_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_267_000 picoseconds. - Weight::from_parts(8_969_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 10_542_000 picoseconds. + Weight::from_parts(11_571_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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: 18_429_000 picoseconds. - Weight::from_parts(18_946_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 29_054_000 picoseconds. + Weight::from_parts(32_996_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 7_910_000 picoseconds. - Weight::from_parts(8_272_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 10_775_000 picoseconds. + Weight::from_parts(11_937_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 7_936_000 picoseconds. - Weight::from_parts(8_504_000, 3556) + // Minimum execution time: 10_696_000 picoseconds. + Weight::from_parts(11_717_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1024 w:1024) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1024]`. + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `193 + n * (91 ±0)` + // Estimated: `3593 + n * (2566 ±0)` + // Minimum execution time: 2_452_000 picoseconds. + Weight::from_parts(2_641_000, 3593) + // Standard Error: 19_797 + .saturating_add(Weight::from_parts(15_620_946, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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` + // Measured: `42` // Estimated: `3556` - // Minimum execution time: 30_479_000 picoseconds. - Weight::from_parts(23_381_775, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_670, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 15_936_000 picoseconds. + Weight::from_parts(16_271_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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_104_000 picoseconds. - Weight::from_parts(18_393_879, 3556) + // Minimum execution time: 16_468_000 picoseconds. + Weight::from_parts(17_031_000, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_669, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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_652_000 picoseconds. - Weight::from_parts(22_031_627, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_672, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 16_342_000 picoseconds. + Weight::from_parts(16_535_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 37_148_000 picoseconds. - Weight::from_parts(40_247_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 31_047_000 picoseconds. + Weight::from_parts(34_099_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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: 19_909_000 picoseconds. - Weight::from_parts(21_572_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 32_559_000 picoseconds. + Weight::from_parts(36_677_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `188` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 17_602_000 picoseconds. - Weight::from_parts(18_899_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 27_887_000 picoseconds. + Weight::from_parts(30_303_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 11_253_000 picoseconds. - Weight::from_parts(11_667_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 17_256_000 picoseconds. + Weight::from_parts(19_481_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3556` - // Minimum execution time: 14_152_000 picoseconds. - Weight::from_parts(14_652_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 22_344_000 picoseconds. + Weight::from_parts(23_868_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_267_000 picoseconds. - Weight::from_parts(8_969_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 10_542_000 picoseconds. + Weight::from_parts(11_571_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, 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: 18_429_000 picoseconds. - Weight::from_parts(18_946_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 29_054_000 picoseconds. + Weight::from_parts(32_996_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 7_910_000 picoseconds. - Weight::from_parts(8_272_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 10_775_000 picoseconds. + Weight::from_parts(11_937_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 7_936_000 picoseconds. - Weight::from_parts(8_504_000, 3556) + // Minimum execution time: 10_696_000 picoseconds. + Weight::from_parts(11_717_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1024 w:1024) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1024]`. + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `193 + n * (91 ±0)` + // Estimated: `3593 + n * (2566 ±0)` + // Minimum execution time: 2_452_000 picoseconds. + Weight::from_parts(2_641_000, 3593) + // Standard Error: 19_797 + .saturating_add(Weight::from_parts(15_620_946, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) } } diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index e44167ed561..c23fa4609d4 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -89,8 +89,7 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = (); - type ByteDeposit = (); + type Consideration = (); } impl pallet_scheduler::Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs index 28e334958d9..b6eb1d044fa 100644 --- a/substrate/frame/scheduler/src/mock.rs +++ b/substrate/frame/scheduler/src/mock.rs @@ -100,7 +100,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Logger: logger::{Pallet, Call, Event}, Scheduler: scheduler::{Pallet, Call, Storage, Event}, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason}, } ); @@ -155,8 +155,7 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; - type BaseDeposit = (); - type ByteDeposit = (); + type Consideration = (); } pub struct TestWeightInfo; diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index eb1fc524200..75e94827fea 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -138,6 +138,15 @@ impl From for PostDispatchInfo { } } +impl From for Pays { + fn from(b: bool) -> Self { + match b { + true => Self::Yes, + false => Self::No, + } + } +} + /// A generalized group of dispatch types. /// /// NOTE whenever upgrading the enum make sure to also update diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 40e348b5e37..10ae5d83b5a 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -90,8 +90,8 @@ pub use hooks::{ pub mod schedule; mod storage; pub use storage::{ - Consideration, Footprint, Incrementable, Instance, PartialStorageInfoTrait, StorageInfo, - StorageInfoTrait, StorageInstance, TrackedStorageKey, WhitelistedStorageKeys, + Consideration, Footprint, Incrementable, Instance, LinearStoragePrice, PartialStorageInfoTrait, + StorageInfo, StorageInfoTrait, StorageInstance, TrackedStorageKey, WhitelistedStorageKeys, }; mod dispatch; diff --git a/substrate/frame/support/src/traits/storage.rs b/substrate/frame/support/src/traits/storage.rs index cfa24d73f94..e0ce1c0fbd3 100644 --- a/substrate/frame/support/src/traits/storage.rs +++ b/substrate/frame/support/src/traits/storage.rs @@ -18,11 +18,13 @@ //! Traits for encoding data related to pallet's storage items. use codec::{Encode, FullCodec, MaxEncodedLen}; +use core::marker::PhantomData; use impl_trait_for_tuples::impl_for_tuples; use scale_info::TypeInfo; pub use sp_core::storage::TrackedStorageKey; +use sp_core::Get; use sp_runtime::{ - traits::{Member, Saturating}, + traits::{Convert, Member, Saturating}, DispatchError, RuntimeDebug, }; use sp_std::{collections::btree_set::BTreeSet, prelude::*}; @@ -152,6 +154,20 @@ impl Footprint { } } +/// A storage price that increases linearly with the number of elements and their size. +pub struct LinearStoragePrice(PhantomData<(Base, Slope, Balance)>); +impl Convert for LinearStoragePrice +where + Base: Get, + Slope: Get, + Balance: From + sp_runtime::Saturating, +{ + fn convert(a: Footprint) -> Balance { + let s: Balance = (a.count.saturating_mul(a.size)).into(); + s.saturating_mul(Slope::get()).saturating_add(Base::get()) + } +} + /// Some sort of cost taken from account temporarily in order to offset the cost to the chain of /// holding some data [`Footprint`] in state. /// @@ -239,3 +255,25 @@ where } impl_incrementable!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::ConstU64; + + #[test] + fn linear_storage_price_works() { + type Linear = LinearStoragePrice, ConstU64<3>, u64>; + let p = |count, size| Linear::convert(Footprint { count, size }); + + assert_eq!(p(0, 0), 7); + assert_eq!(p(0, 1), 7); + assert_eq!(p(1, 0), 7); + + assert_eq!(p(1, 1), 10); + assert_eq!(p(8, 1), 31); + assert_eq!(p(1, 8), 31); + + assert_eq!(p(u64::MAX, u64::MAX), u64::MAX); + } +} diff --git a/substrate/frame/whitelist/src/mock.rs b/substrate/frame/whitelist/src/mock.rs index d91f43b33af..e6ddbf02bb2 100644 --- a/substrate/frame/whitelist/src/mock.rs +++ b/substrate/frame/whitelist/src/mock.rs @@ -90,8 +90,7 @@ impl pallet_preimage::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type BaseDeposit = ConstU64<1>; - type ByteDeposit = ConstU64<1>; + type Consideration = (); type WeightInfo = (); } -- GitLab From c7dbfc21b661c39f5dc2e181109d00945638350c Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sun, 17 Sep 2023 22:06:19 +0200 Subject: [PATCH 160/633] Babe epoch newtype (#1596) Removal of verbatim duplication of BABE's `Epoch` struct in the client. I think is better to have one single definition and wrap the primitive `Epoch` in a newtype (required because we need to implement the `Epoch` trait). --- Cargo.lock | 3 - substrate/client/consensus/babe/Cargo.toml | 3 - .../client/consensus/babe/src/authorship.rs | 21 ++++--- substrate/client/consensus/babe/src/lib.rs | 55 +++++++++---------- .../client/consensus/babe/src/migration.rs | 4 +- substrate/client/consensus/babe/src/tests.rs | 10 ++-- 6 files changed, 45 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a994d14a322..efefda5c878 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14754,17 +14754,14 @@ dependencies = [ "num-traits", "parity-scale-codec", "parking_lot 0.12.1", - "rand_chacha 0.2.2", "sc-block-builder", "sc-client-api", "sc-consensus", "sc-consensus-epochs", "sc-consensus-slots", - "sc-network", "sc-network-test", "sc-telemetry", "sc-transaction-pool-api", - "scale-info", "sp-api", "sp-application-crypto", "sp-block-builder", diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index d9588794535..c8cff0981b3 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -15,7 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -scale-info = { version = "2.5.0", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" log = "0.4.17" @@ -45,10 +44,8 @@ sp-keystore = { path = "../../../primitives/keystore" } sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] -rand_chacha = "0.2.2" sc-block-builder = { path = "../../block-builder" } sp-keyring = { path = "../../../primitives/keyring" } -sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } sp-timestamp = { path = "../../../primitives/timestamp" } sp-tracing = { path = "../../../primitives/tracing" } diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 758d5321a94..3580caba746 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -132,23 +132,22 @@ fn claim_secondary_slot( keystore: &KeystorePtr, author_secondary_vrf: bool, ) -> Option<(PreDigest, AuthorityId)> { - let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; - - if authorities.is_empty() { + if epoch.authorities.is_empty() { return None } + let mut epoch_index = epoch.epoch_index; if epoch.end_slot() <= slot { // Slot doesn't strictly belong to the epoch, create a clone with fixed values. epoch_index = epoch.clone_for_slot(slot).epoch_index; } - let expected_author = secondary_slot_author(slot, authorities, *randomness)?; + let expected_author = secondary_slot_author(slot, &epoch.authorities, epoch.randomness)?; for (authority_id, authority_index) in keys { if authority_id == expected_author { let pre_digest = if author_secondary_vrf { - let data = make_vrf_sign_data(randomness, slot, epoch_index); + let data = make_vrf_sign_data(&epoch.randomness, slot, epoch_index); let result = keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &data); if let Ok(Some(vrf_signature)) = result { @@ -232,19 +231,18 @@ fn claim_primary_slot( keystore: &KeystorePtr, keys: &[(AuthorityId, usize)], ) -> Option<(PreDigest, AuthorityId)> { - let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; - + let mut epoch_index = epoch.epoch_index; if epoch.end_slot() <= slot { // Slot doesn't strictly belong to the epoch, create a clone with fixed values. epoch_index = epoch.clone_for_slot(slot).epoch_index; } - let data = make_vrf_sign_data(randomness, slot, epoch_index); + let data = make_vrf_sign_data(&epoch.randomness, slot, epoch_index); for (authority_id, authority_index) in keys { let result = keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &data); if let Ok(Some(vrf_signature)) = result { - let threshold = calculate_primary_threshold(c, authorities, *authority_index); + let threshold = calculate_primary_threshold(c, &epoch.authorities, *authority_index); let can_claim = authority_id .as_inner_ref() @@ -274,7 +272,7 @@ fn claim_primary_slot( #[cfg(test)] mod tests { use super::*; - use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration}; + use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration, Epoch}; use sp_core::{crypto::Pair as _, sr25519::Pair}; use sp_keystore::testing::MemoryKeystore; @@ -300,7 +298,8 @@ mod tests { c: (3, 10), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, }, - }; + } + .into(); assert!(claim_slot(10.into(), &epoch, &keystore).is_none()); diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index 90b7523ec18..ccf72939631 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -69,6 +69,7 @@ use std::{ collections::HashSet, future::Future, + ops::{Deref, DerefMut}, pin::Pin, sync::Arc, task::{Context, Poll}, @@ -156,20 +157,27 @@ const AUTHORING_SCORE_VRF_CONTEXT: &[u8] = b"substrate-babe-vrf"; const AUTHORING_SCORE_LENGTH: usize = 16; /// BABE epoch information -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, scale_info::TypeInfo)] -pub struct Epoch { - /// The epoch index. - pub epoch_index: u64, - /// The starting slot of the epoch. - pub start_slot: Slot, - /// The duration of this epoch. - pub duration: u64, - /// The authorities and their weights. - pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, - /// Randomness for this epoch. - pub randomness: Randomness, - /// Configuration of the epoch. - pub config: BabeEpochConfiguration, +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +pub struct Epoch(sp_consensus_babe::Epoch); + +impl Deref for Epoch { + type Target = sp_consensus_babe::Epoch; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Epoch { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl From for Epoch { + fn from(epoch: sp_consensus_babe::Epoch) -> Self { + Epoch(epoch) + } } impl EpochT for Epoch { @@ -180,7 +188,7 @@ impl EpochT for Epoch { &self, (descriptor, config): (NextEpochDescriptor, BabeEpochConfiguration), ) -> Epoch { - Epoch { + sp_consensus_babe::Epoch { epoch_index: self.epoch_index + 1, start_slot: self.start_slot + self.duration, duration: self.duration, @@ -188,6 +196,7 @@ impl EpochT for Epoch { randomness: descriptor.randomness, config, } + .into() } fn start_slot(&self) -> Slot { @@ -199,25 +208,12 @@ impl EpochT for Epoch { } } -impl From for Epoch { - fn from(epoch: sp_consensus_babe::Epoch) -> Self { - Epoch { - epoch_index: epoch.epoch_index, - start_slot: epoch.start_slot, - duration: epoch.duration, - authorities: epoch.authorities, - randomness: epoch.randomness, - config: epoch.config, - } - } -} - impl Epoch { /// Create the genesis epoch (epoch #0). /// /// This is defined to start at the slot of the first block, so that has to be provided. pub fn genesis(genesis_config: &BabeConfiguration, slot: Slot) -> Epoch { - Epoch { + sp_consensus_babe::Epoch { epoch_index: 0, start_slot: slot, duration: genesis_config.epoch_length, @@ -228,6 +224,7 @@ impl Epoch { allowed_slots: genesis_config.allowed_slots, }, } + .into() } /// Clone and tweak epoch information to refer to the specified slot. diff --git a/substrate/client/consensus/babe/src/migration.rs b/substrate/client/consensus/babe/src/migration.rs index 2b1396c41c2..bec2d0a61f4 100644 --- a/substrate/client/consensus/babe/src/migration.rs +++ b/substrate/client/consensus/babe/src/migration.rs @@ -62,10 +62,11 @@ impl EpochT for EpochV0 { } } +// Implement From for Epoch impl EpochV0 { /// Migrate the sturct to current epoch version. pub fn migrate(self, config: &BabeConfiguration) -> Epoch { - Epoch { + sp_consensus_babe::Epoch { epoch_index: self.epoch_index, start_slot: self.start_slot, duration: self.duration, @@ -73,5 +74,6 @@ impl EpochV0 { randomness: self.randomness, config: BabeEpochConfiguration { c: config.c, allowed_slots: config.allowed_slots }, } + .into() } } diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index b3843f8acfa..02882d8baae 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -501,7 +501,7 @@ fn claim_epoch_slots() { let authority = Sr25519Keyring::Alice; let keystore = create_keystore(authority); - let mut epoch = Epoch { + let mut epoch: Epoch = sp_consensus_babe::Epoch { start_slot: 0.into(), authorities: vec![(authority.public().into(), 1)], randomness: [0; 32], @@ -511,7 +511,8 @@ fn claim_epoch_slots() { c: (3, 10), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, }, - }; + } + .into(); let claim_slot_wrap = |s, e| match claim_slot(Slot::from(s as u64), &e, &keystore) { None => 0, @@ -551,7 +552,7 @@ fn claim_vrf_check() { let public = authority.public(); - let epoch = Epoch { + let epoch: Epoch = sp_consensus_babe::Epoch { start_slot: 0.into(), authorities: vec![(public.into(), 1)], randomness: [0; 32], @@ -561,7 +562,8 @@ fn claim_vrf_check() { c: (3, 10), allowed_slots: AllowedSlots::PrimaryAndSecondaryVRFSlots, }, - }; + } + .into(); // We leverage the predictability of claim types given a constant randomness. -- GitLab From 2ca30ed10ad2f68f4a8769e61f045299ae362162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Molina=20Colmenero?= Date: Mon, 18 Sep 2023 00:27:38 +0200 Subject: [PATCH 161/633] fix: export-genesis-state command (#1521) # Description Currently the `ExportGenesisState` command in polkadot parachain uses an asynchronous context to run, which seems to display some warnings. See the screenshot below: ![Screenshot 2023-09-12 at 17 12 15](https://github.com/paritytech/polkadot-sdk/assets/2722756/0140b48a-2edb-41fa-b046-579d526f8305) After the changes in this PR, which essentially runs the command in a synchronous context, the command works properly without any warning. ![Screenshot 2023-09-12 at 18 23 46](https://github.com/paritytech/polkadot-sdk/assets/2722756/31506917-ece2-4a5f-8909-f215cc1ac0de) The remaining runtimes were added to `construct_benchmark_partials` macro in order not to fail if the runtime was not included in the non-exhaustive initial list, similarly to the `construct_async_run` one. For completeness: tests were made following this [tutorial](https://docs.substrate.io/tutorials/build-a-parachain/connect-a-local-parachain/). --- cumulus/polkadot-parachain/src/command.rs | 52 +++++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 596b7baf671..32e363aff74 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -381,7 +381,7 @@ impl SubstrateCli for RelayChainCli { } /// Creates partial components for the runtimes that are supported by the benchmarks. -macro_rules! construct_benchmark_partials { +macro_rules! construct_partials { ($config:expr, |$partials:ident| $code:expr) => { match $config.chain_spec.runtime() { Runtime::AssetHubKusama => { @@ -456,7 +456,41 @@ macro_rules! construct_benchmark_partials { )?; $code }, - _ => Err("The chain is not supported".into()), + Runtime::Shell => { + let $partials = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + $code + }, + Runtime::Seedling => { + let $partials = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + $code + }, + Runtime::ContractsRococo => { + let $partials = new_partial::( + &$config, + crate::service::contracts_rococo_build_import_queue, + )?; + $code + }, + Runtime::Penpal(_) | Runtime::Default => { + let $partials = new_partial::( + &$config, + crate::service::rococo_parachain_build_import_queue, + )?; + $code + }, + Runtime::Glutton => { + let $partials = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + $code + }, } }; } @@ -679,10 +713,12 @@ pub fn run() -> Result<()> { cmd.run(config, polkadot_config) }) }, - Some(Subcommand::ExportGenesisState(cmd)) => - construct_async_run!(|components, cli, cmd, config| { - Ok(async move { cmd.run(&*config.chain_spec, &*components.client) }) - }), + Some(Subcommand::ExportGenesisState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| { + construct_partials!(config, |partials| cmd.run(&*config.chain_spec, &*partials.client)) + }) + }, Some(Subcommand::ExportGenesisWasm(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|_config| { @@ -704,7 +740,7 @@ pub fn run() -> Result<()> { .into()) }, BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { - construct_benchmark_partials!(config, |partials| cmd.run(partials.client)) + construct_partials!(config, |partials| cmd.run(partials.client)) }), #[cfg(not(feature = "runtime-benchmarks"))] BenchmarkCmd::Storage(_) => @@ -716,7 +752,7 @@ pub fn run() -> Result<()> { .into()), #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { - construct_benchmark_partials!(config, |partials| { + construct_partials!(config, |partials| { let db = partials.backend.expose_db(); let storage = partials.backend.expose_storage(); -- GitLab From cf5c195237873d3741be11111283698e70f3e752 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Mon, 18 Sep 2023 00:28:35 +0200 Subject: [PATCH 162/633] [Backport] Version bumps from release 1.1.0 (#1580) This PR backports version bumps for `polkadot` and `polkadot-parachain` from the v1.1.0 release branch --------- Co-authored-by: Mara Broda --- Cargo.lock | 6 +++--- cumulus/polkadot-parachain/Cargo.toml | 2 +- polkadot/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efefda5c878..06d4b34031f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11395,7 +11395,7 @@ dependencies = [ [[package]] name = "polkadot" -version = "1.0.0" +version = "1.1.0" dependencies = [ "assert_cmd", "color-eyre", @@ -11528,7 +11528,7 @@ dependencies = [ [[package]] name = "polkadot-cli" -version = "1.0.0" +version = "1.1.0" dependencies = [ "clap 4.4.3", "frame-benchmarking-cli", @@ -12340,7 +12340,7 @@ dependencies = [ [[package]] name = "polkadot-parachain-bin" -version = "1.0.0" +version = "1.1.0" dependencies = [ "assert_cmd", "asset-hub-kusama-runtime", diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index e6fedb5f1fa..5591e80317c 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-parachain-bin" -version = "1.0.0" +version = "1.1.0" authors.workspace = true build = "build.rs" edition.workspace = true diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index b9c132bbff9..e4494b1abb2 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.64.0" readme = "README.md" authors.workspace = true edition.workspace = true -version = "1.0.0" +version = "1.1.0" default-run = "polkadot" [dependencies] diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 794d8c4714a..a9631fb9a7d 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-cli" description = "Polkadot Relay-chain Client Node" -version = "1.0.0" +version = "1.1.0" authors.workspace = true edition.workspace = true license.workspace = true -- GitLab From e38998801e433ecc569ff6d58d1d0aa80eaff771 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 18 Sep 2023 13:53:06 +0800 Subject: [PATCH 163/633] Executor: Remove `LegacyInstanceReuse` strategy (#1486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems the old strategy have been depracted more than one year. So maybe it's time to clean up old strategy for wasm executor. --- polkadot address: 15ouFh2SHpGbHtDPsJ6cXQfes9Cx1gEFnJJsJVqPGzBSTudr --------- Co-authored-by: Bastian Köcher Co-authored-by: Koute --- .../pvf/prepare-worker/src/memory_stats.rs | 2 +- substrate/client/cli/src/arg_enums.rs | 8 - substrate/client/executor/benches/bench.rs | 7 - .../runtime_blob/data_segments_snapshot.rs | 87 ---------- .../src/runtime_blob/globals_snapshot.rs | 112 ------------- .../executor/common/src/runtime_blob/mod.rs | 4 - .../common/src/runtime_blob/runtime_blob.rs | 19 +-- .../executor/common/src/wasm_runtime.rs | 10 -- .../executor/src/integration_tests/linux.rs | 84 ---------- .../src/integration_tests/linux/smaps.rs | 82 ---------- .../executor/src/integration_tests/mod.rs | 11 -- .../client/executor/wasmtime/src/host.rs | 2 +- .../executor/wasmtime/src/instance_wrapper.rs | 104 +----------- .../client/executor/wasmtime/src/runtime.rs | 149 +----------------- .../client/executor/wasmtime/src/tests.rs | 19 +-- .../client/executor/wasmtime/src/util.rs | 30 +--- 16 files changed, 20 insertions(+), 710 deletions(-) delete mode 100644 substrate/client/executor/common/src/runtime_blob/data_segments_snapshot.rs delete mode 100644 substrate/client/executor/common/src/runtime_blob/globals_snapshot.rs delete mode 100644 substrate/client/executor/src/integration_tests/linux.rs delete mode 100644 substrate/client/executor/src/integration_tests/linux/smaps.rs diff --git a/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs b/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs index 7904dfa9cb8..c70ff56fc84 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs @@ -151,7 +151,7 @@ pub mod memory_tracker { /// Module for dealing with the `ru_maxrss` (peak resident memory) stat from `getrusage`. /// /// NOTE: `getrusage` with the `RUSAGE_THREAD` parameter is only supported on Linux. `RUSAGE_SELF` -/// works on MacOS, but we need to get the max rss only for the preparation thread. Gettng it for +/// works on MacOS, but we need to get the max rss only for the preparation thread. Getting it for /// the current process would conflate the stats of previous jobs run by the process. #[cfg(target_os = "linux")] pub mod max_rss_stat { diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index 40d86fd9798..67acb82c2c3 100644 --- a/substrate/client/cli/src/arg_enums.rs +++ b/substrate/client/cli/src/arg_enums.rs @@ -38,12 +38,6 @@ pub enum WasmtimeInstantiationStrategy { /// Recreate the instance from scratch on every instantiation. Very slow. RecreateInstance, - - /// Legacy instance reuse mechanism. DEPRECATED. Will be removed in the future. - /// - /// Should only be used in case of encountering any issues with the new default - /// instantiation strategy. - LegacyInstanceReuse, } /// The default [`WasmtimeInstantiationStrategy`]. @@ -92,8 +86,6 @@ pub fn execution_method_from_cli( sc_service::config::WasmtimeInstantiationStrategy::Pooling, WasmtimeInstantiationStrategy::RecreateInstance => sc_service::config::WasmtimeInstantiationStrategy::RecreateInstance, - WasmtimeInstantiationStrategy::LegacyInstanceReuse => - sc_service::config::WasmtimeInstantiationStrategy::LegacyInstanceReuse, }, } } diff --git a/substrate/client/executor/benches/bench.rs b/substrate/client/executor/benches/bench.rs index 66a82a17522..86c769f8881 100644 --- a/substrate/client/executor/benches/bench.rs +++ b/substrate/client/executor/benches/bench.rs @@ -150,13 +150,6 @@ fn bench_call_instance(c: &mut Criterion) { let _ = env_logger::try_init(); let strategies = [ - ( - "legacy_instance_reuse", - Method::Compiled { - instantiation_strategy: InstantiationStrategy::LegacyInstanceReuse, - precompile: false, - }, - ), ( "recreate_instance_vanilla", Method::Compiled { diff --git a/substrate/client/executor/common/src/runtime_blob/data_segments_snapshot.rs b/substrate/client/executor/common/src/runtime_blob/data_segments_snapshot.rs deleted file mode 100644 index 3fd546ce445..00000000000 --- a/substrate/client/executor/common/src/runtime_blob/data_segments_snapshot.rs +++ /dev/null @@ -1,87 +0,0 @@ -// 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::RuntimeBlob; -use crate::error::{self, Error}; -use std::mem; -use wasm_instrument::parity_wasm::elements::Instruction; - -/// This is a snapshot of data segments specialzied for a particular instantiation. -/// -/// Note that this assumes that no mutable globals are used. -#[derive(Clone)] -pub struct DataSegmentsSnapshot { - /// The list of data segments represented by (offset, contents). - data_segments: Vec<(u32, Vec)>, -} - -impl DataSegmentsSnapshot { - /// Create a snapshot from the data segments from the module. - pub fn take(module: &RuntimeBlob) -> error::Result { - let data_segments = module - .data_segments() - .into_iter() - .map(|mut segment| { - // Just replace contents of the segment since the segments will be discarded later - // anyway. - let contents = mem::take(segment.value_mut()); - - let init_expr = match segment.offset() { - Some(offset) => offset.code(), - // Return if the segment is passive - None => return Err(Error::SharedMemUnsupported), - }; - - // [op, End] - if init_expr.len() != 2 { - return Err(Error::InitializerHasTooManyExpressions) - } - let offset = match &init_expr[0] { - Instruction::I32Const(v) => *v as u32, - Instruction::GetGlobal(_) => { - // In a valid wasm file, initializer expressions can only refer imported - // globals. - // - // At the moment of writing the Substrate Runtime Interface does not provide - // any globals. There is nothing that prevents us from supporting this - // if/when we gain those. - return Err(Error::ImportedGlobalsUnsupported) - }, - insn => return Err(Error::InvalidInitializerExpression(format!("{:?}", insn))), - }; - - Ok((offset, contents)) - }) - .collect::>>()?; - - Ok(Self { data_segments }) - } - - /// Apply the given snapshot to a linear memory. - /// - /// Linear memory interface is represented by a closure `memory_set`. - pub fn apply( - &self, - mut memory_set: impl FnMut(u32, &[u8]) -> Result<(), E>, - ) -> Result<(), E> { - for (offset, contents) in &self.data_segments { - memory_set(*offset, contents)?; - } - Ok(()) - } -} diff --git a/substrate/client/executor/common/src/runtime_blob/globals_snapshot.rs b/substrate/client/executor/common/src/runtime_blob/globals_snapshot.rs deleted file mode 100644 index 9ba6fc55e49..00000000000 --- a/substrate/client/executor/common/src/runtime_blob/globals_snapshot.rs +++ /dev/null @@ -1,112 +0,0 @@ -// 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::RuntimeBlob; - -/// Saved value of particular exported global. -struct SavedValue { - /// The handle of this global which can be used to refer to this global. - handle: Global, - /// The global value that was observed during the snapshot creation. - value: sp_wasm_interface::Value, -} - -/// An adapter for a wasm module instance that is focused on getting and setting globals. -pub trait InstanceGlobals { - /// A handle to a global which can be used to get or set a global variable. This is supposed to - /// be a lightweight handle, like an index or an Rc-like smart-pointer, which is cheap to clone. - type Global: Clone; - /// Get a handle to a global by it's export name. - /// - /// The requested export is must exist in the exported list, and it should be a mutable global. - fn get_global(&mut self, export_name: &str) -> Self::Global; - /// Get the current value of the global. - fn get_global_value(&mut self, global: &Self::Global) -> sp_wasm_interface::Value; - /// Update the current value of the global. - /// - /// The global behind the handle is guaranteed to be mutable and the value to be the same type - /// as the global. - fn set_global_value(&mut self, global: &Self::Global, value: sp_wasm_interface::Value); -} - -/// A set of exposed mutable globals. -/// -/// This is set of globals required to create a [`GlobalsSnapshot`] and that are collected from -/// a runtime blob that was instrumented by -/// [`RuntimeBlob::expose_mutable_globals`](super::RuntimeBlob::expose_mutable_globals`). - -/// If the code wasn't instrumented then it would be empty and snapshot would do nothing. -pub struct ExposedMutableGlobalsSet(Vec); - -impl ExposedMutableGlobalsSet { - /// Collect the set from the given runtime blob. See the struct documentation for details. - pub fn collect(runtime_blob: &RuntimeBlob) -> Self { - let global_names = - runtime_blob.exported_internal_global_names().map(ToOwned::to_owned).collect(); - Self(global_names) - } -} - -/// A snapshot of a global variables values. This snapshot can be later used for restoring the -/// values to the preserved state. -/// -/// Technically, a snapshot stores only values of mutable global variables. This is because -/// immutable global variables always have the same values. -/// -/// We take it from an instance rather from a module because the start function could potentially -/// change any of the mutable global values. -pub struct GlobalsSnapshot(Vec>); - -impl GlobalsSnapshot { - /// Take a snapshot of global variables for a given instance. - /// - /// # Panics - /// - /// This function panics if the instance doesn't correspond to the module from which the - /// [`ExposedMutableGlobalsSet`] was collected. - pub fn take( - mutable_globals: &ExposedMutableGlobalsSet, - instance: &mut Instance, - ) -> Self - where - Instance: InstanceGlobals, - { - let global_names = &mutable_globals.0; - let mut saved_values = Vec::with_capacity(global_names.len()); - - for global_name in global_names { - let handle = instance.get_global(global_name); - let value = instance.get_global_value(&handle); - saved_values.push(SavedValue { handle, value }); - } - - Self(saved_values) - } - - /// Apply the snapshot to the given instance. - /// - /// This instance must be the same that was used for creation of this snapshot. - pub fn apply(&self, instance: &mut Instance) - where - Instance: InstanceGlobals, - { - for saved_value in &self.0 { - instance.set_global_value(&saved_value.handle, saved_value.value); - } - } -} diff --git a/substrate/client/executor/common/src/runtime_blob/mod.rs b/substrate/client/executor/common/src/runtime_blob/mod.rs index 07a0945cc2b..8261d07eda5 100644 --- a/substrate/client/executor/common/src/runtime_blob/mod.rs +++ b/substrate/client/executor/common/src/runtime_blob/mod.rs @@ -46,10 +46,6 @@ //! is free of any floating point operations, which is a useful step towards making instances //! produced from such a module deterministic. -mod data_segments_snapshot; -mod globals_snapshot; mod runtime_blob; -pub use data_segments_snapshot::DataSegmentsSnapshot; -pub use globals_snapshot::{ExposedMutableGlobalsSet, GlobalsSnapshot, InstanceGlobals}; pub use runtime_blob::RuntimeBlob; diff --git a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs index 24dc7e393a4..becf9e219b0 100644 --- a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -20,8 +20,8 @@ use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; use wasm_instrument::{ export_mutable_globals, parity_wasm::elements::{ - deserialize_buffer, serialize, DataSegment, ExportEntry, External, Internal, MemorySection, - MemoryType, Module, Section, + deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, + Module, Section, }, }; @@ -52,11 +52,6 @@ impl RuntimeBlob { Ok(Self { raw_module }) } - /// Extract the data segments from the given wasm code. - pub(super) fn data_segments(&self) -> Vec { - self.raw_module.data_section().map(|ds| ds.entries()).unwrap_or(&[]).to_vec() - } - /// The number of globals defined in locally in this module. pub fn declared_globals_count(&self) -> u32 { self.raw_module @@ -190,16 +185,6 @@ impl RuntimeBlob { Ok(()) } - /// Returns an iterator of all globals which were exported by [`expose_mutable_globals`]. - pub(super) fn exported_internal_global_names(&self) -> impl Iterator { - let exports = self.raw_module.export_section().map(|es| es.entries()).unwrap_or(&[]); - exports.iter().filter_map(|export| match export.internal() { - Internal::Global(_) if export.field().starts_with("exported_internal_global") => - Some(export.field()), - _ => None, - }) - } - /// Scans the wasm blob for the first section with the name that matches the given. Returns the /// contents of the custom section if found or `None` otherwise. pub fn custom_section_contents(&self, section_name: &str) -> Option<&[u8]> { diff --git a/substrate/client/executor/common/src/wasm_runtime.rs b/substrate/client/executor/common/src/wasm_runtime.rs index 5dac77e59fa..d8e142b9d55 100644 --- a/substrate/client/executor/common/src/wasm_runtime.rs +++ b/substrate/client/executor/common/src/wasm_runtime.rs @@ -115,16 +115,6 @@ pub trait WasmInstance: Send { /// /// This method is only suitable for getting immutable globals. fn get_global_const(&mut self, name: &str) -> Result, Error>; - - /// **Testing Only**. This function returns the base address of the linear memory. - /// - /// This is meant to be the starting address of the memory mapped area for the linear memory. - /// - /// This function is intended only for a specific test that measures physical memory - /// consumption. - fn linear_memory_base_ptr(&self) -> Option<*const u8> { - None - } } /// Defines the heap pages allocation strategy the wasm runtime should use. diff --git a/substrate/client/executor/src/integration_tests/linux.rs b/substrate/client/executor/src/integration_tests/linux.rs deleted file mode 100644 index 68ac37e9011..00000000000 --- a/substrate/client/executor/src/integration_tests/linux.rs +++ /dev/null @@ -1,84 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Tests that are only relevant for Linux. - -mod smaps; - -use super::mk_test_runtime; -use crate::WasmExecutionMethod; -use codec::Encode as _; -use sc_executor_common::wasm_runtime::DEFAULT_HEAP_ALLOC_STRATEGY; - -use self::smaps::Smaps; - -#[test] -fn memory_consumption_compiled() { - let _ = sp_tracing::try_init_simple(); - - if std::env::var("RUN_TEST").is_ok() { - memory_consumption(WasmExecutionMethod::Compiled { - instantiation_strategy: - sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse, - }); - } else { - // We need to run the test in isolation, to not getting interfered by the other tests. - let executable = std::env::current_exe().unwrap(); - let status = std::process::Command::new(executable) - .env("RUN_TEST", "1") - .args(&["--nocapture", "memory_consumption_compiled"]) - .status() - .unwrap(); - - assert!(status.success()); - } -} - -fn memory_consumption(wasm_method: WasmExecutionMethod) { - // This aims to see if linear memory stays backed by the physical memory after a runtime call. - // - // For that we make a series of runtime calls, probing the RSS for the VMA matching the linear - // memory. After the call we expect RSS to be equal to 0. - - let runtime = mk_test_runtime(wasm_method, DEFAULT_HEAP_ALLOC_STRATEGY); - - let mut instance = runtime.new_instance().unwrap(); - let heap_base = instance - .get_global_const("__heap_base") - .expect("`__heap_base` is valid") - .expect("`__heap_base` exists") - .as_i32() - .expect("`__heap_base` is an `i32`"); - - fn probe_rss(instance: &dyn sc_executor_common::wasm_runtime::WasmInstance) -> usize { - let base_addr = instance.linear_memory_base_ptr().unwrap() as usize; - Smaps::new().get_rss(base_addr).expect("failed to get rss") - } - - instance - .call_export("test_dirty_plenty_memory", &(heap_base as u32, 1u32).encode()) - .unwrap(); - let probe_1 = probe_rss(&*instance); - instance - .call_export("test_dirty_plenty_memory", &(heap_base as u32, 1024u32).encode()) - .unwrap(); - let probe_2 = probe_rss(&*instance); - - assert_eq!(probe_1, 0); - assert_eq!(probe_2, 0); -} diff --git a/substrate/client/executor/src/integration_tests/linux/smaps.rs b/substrate/client/executor/src/integration_tests/linux/smaps.rs deleted file mode 100644 index 1ac570dd8d5..00000000000 --- a/substrate/client/executor/src/integration_tests/linux/smaps.rs +++ /dev/null @@ -1,82 +0,0 @@ -// 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 . - -//! A tool for extracting information about the memory consumption of the current process from -//! the procfs. - -use std::{collections::BTreeMap, ops::Range}; - -/// An interface to the /proc/self/smaps -/// -/// See docs about [procfs on kernel.org][procfs] -/// -/// [procfs]: https://www.kernel.org/doc/html/latest/filesystems/proc.html -pub struct Smaps(Vec<(Range, BTreeMap)>); - -impl Smaps { - pub fn new() -> Self { - let regex_start = regex::RegexBuilder::new("^([0-9a-f]+)-([0-9a-f]+)") - .multi_line(true) - .build() - .unwrap(); - let regex_kv = regex::RegexBuilder::new(r#"^([^:]+):\s*(\d+) kB"#) - .multi_line(true) - .build() - .unwrap(); - let smaps = std::fs::read_to_string("/proc/self/smaps").unwrap(); - let boundaries: Vec<_> = regex_start - .find_iter(&smaps) - .map(|matched| matched.start()) - .chain(std::iter::once(smaps.len())) - .collect(); - - let mut output = Vec::new(); - for window in boundaries.windows(2) { - let chunk = &smaps[window[0]..window[1]]; - let caps = regex_start.captures(chunk).unwrap(); - let start = usize::from_str_radix(caps.get(1).unwrap().as_str(), 16).unwrap(); - let end = usize::from_str_radix(caps.get(2).unwrap().as_str(), 16).unwrap(); - - let values = regex_kv - .captures_iter(chunk) - .map(|cap| { - let key = cap.get(1).unwrap().as_str().to_owned(); - let value = cap.get(2).unwrap().as_str().parse().unwrap(); - (key, value) - }) - .collect(); - - output.push((start..end, values)); - } - - Self(output) - } - - fn get_map(&self, addr: usize) -> &BTreeMap { - &self - .0 - .iter() - .find(|(range, _)| addr >= range.start && addr < range.end) - .unwrap() - .1 - } - - pub fn get_rss(&self, addr: usize) -> Option { - self.get_map(addr).get("Rss").cloned() - } -} diff --git a/substrate/client/executor/src/integration_tests/mod.rs b/substrate/client/executor/src/integration_tests/mod.rs index 37aed8eef96..0bd080c2435 100644 --- a/substrate/client/executor/src/integration_tests/mod.rs +++ b/substrate/client/executor/src/integration_tests/mod.rs @@ -16,9 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#[cfg(target_os = "linux")] -mod linux; - use assert_matches::assert_matches; use codec::{Decode, Encode}; use sc_executor_common::{ @@ -81,14 +78,6 @@ macro_rules! test_wasm_execution { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling }); } - - #[test] - fn [<$method_name _compiled_legacy_instance_reuse>]() { - let _ = sp_tracing::try_init_simple(); - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse - }); - } } }; } diff --git a/substrate/client/executor/wasmtime/src/host.rs b/substrate/client/executor/wasmtime/src/host.rs index 9bd3ca3dade..f8c78cbb660 100644 --- a/substrate/client/executor/wasmtime/src/host.rs +++ b/substrate/client/executor/wasmtime/src/host.rs @@ -32,7 +32,7 @@ use crate::{instance_wrapper::MemoryWrapper, runtime::StoreData, util}; pub struct HostState { /// The allocator instance to keep track of allocated memory. /// - /// This is stored as an `Option` as we need to temporarly set this to `None` when we are + /// This is stored as an `Option` as we need to temporarily set this to `None` when we are /// allocating/deallocating memory. The problem being that we can only mutable access `caller` /// once. allocator: Option, diff --git a/substrate/client/executor/wasmtime/src/instance_wrapper.rs b/substrate/client/executor/wasmtime/src/instance_wrapper.rs index 6d319cce509..acc799061c2 100644 --- a/substrate/client/executor/wasmtime/src/instance_wrapper.rs +++ b/substrate/client/executor/wasmtime/src/instance_wrapper.rs @@ -116,14 +116,14 @@ impl EntryPoint { pub(crate) struct MemoryWrapper<'a, C>(pub &'a wasmtime::Memory, pub &'a mut C); impl sc_allocator::Memory for MemoryWrapper<'_, C> { - fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { - run(self.0.data(&self.1)) - } - fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { run(self.0.data_mut(&mut self.1)) } + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(self.0.data(&self.1)) + } + fn grow(&mut self, additional: u32) -> std::result::Result<(), ()> { self.0 .grow(&mut self.1, additional as u64) @@ -153,11 +153,6 @@ impl sc_allocator::Memory for MemoryWrapper<'_, C> { /// routines. pub struct InstanceWrapper { instance: Instance, - /// The memory instance of the `instance`. - /// - /// It is important to make sure that we don't make any copies of this to make it easier to - /// proof - memory: Memory, store: Store, } @@ -177,7 +172,7 @@ impl InstanceWrapper { store.data_mut().memory = Some(memory); store.data_mut().table = table; - Ok(InstanceWrapper { instance, memory, store }) + Ok(InstanceWrapper { instance, store }) } /// Resolves a substrate entrypoint by the given name. @@ -280,11 +275,6 @@ impl InstanceWrapper { _ => Err("Unknown value type".into()), } } - - /// Get a global with the given `name`. - pub fn get_global(&mut self, name: &str) -> Option { - self.instance.get_global(&mut self.store, name) - } } /// Extract linear memory instance from the given instance. @@ -311,76 +301,6 @@ fn get_table(instance: &Instance, ctx: &mut Store) -> Option
Release notes

Sourced from cfg-expr's releases.

Release 0.15.5

Changed

  • PR#64 updated the builtin target list to 1.72.0. It also changed the MSRV to 1.70.0.
{ /// Functions related to memory. impl InstanceWrapper { - /// Returns the pointer to the first byte of the linear memory for this instance. - pub fn base_ptr(&self) -> *const u8 { - self.memory.data_ptr(&self.store) - } - - /// If possible removes physical backing from the allocated linear memory which - /// leads to returning the memory back to the system; this also zeroes the memory - /// as a side-effect. - pub fn decommit(&mut self) { - if self.memory.data_size(&self.store) == 0 { - return - } - - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - use std::sync::Once; - - unsafe { - let ptr = self.memory.data_ptr(&self.store); - let len = self.memory.data_size(&self.store); - - // Linux handles MADV_DONTNEED reliably. The result is that the given area - // is unmapped and will be zeroed on the next pagefault. - if libc::madvise(ptr as _, len, libc::MADV_DONTNEED) != 0 { - static LOGGED: Once = Once::new(); - LOGGED.call_once(|| { - log::warn!( - "madvise(MADV_DONTNEED) failed: {}", - std::io::Error::last_os_error(), - ); - }); - } else { - return; - } - } - } else if #[cfg(target_os = "macos")] { - use std::sync::Once; - - unsafe { - let ptr = self.memory.data_ptr(&self.store); - let len = self.memory.data_size(&self.store); - - // On MacOS we can simply overwrite memory mapping. - if libc::mmap( - ptr as _, - len, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, - -1, - 0, - ) == libc::MAP_FAILED { - static LOGGED: Once = Once::new(); - LOGGED.call_once(|| { - log::warn!( - "Failed to decommit WASM instance memory through mmap: {}", - std::io::Error::last_os_error(), - ); - }); - } else { - return; - } - } - } - } - - // If we're on an unsupported OS or the memory couldn't have been - // decommited for some reason then just manually zero it out. - self.memory.data_mut(self.store.as_context_mut()).fill(0); - } - pub(crate) fn store(&self) -> &Store { &self.store } @@ -389,17 +309,3 @@ impl InstanceWrapper { &mut self.store } } - -#[test] -fn decommit_works() { - let engine = wasmtime::Engine::default(); - let code = wat::parse_str("(module (memory (export \"memory\") 1 4))").unwrap(); - let module = wasmtime::Module::new(&engine, code).unwrap(); - let linker = wasmtime::Linker::new(&engine); - let instance_pre = linker.instantiate_pre(&module).unwrap(); - let mut wrapper = InstanceWrapper::new(&engine, &instance_pre).unwrap(); - unsafe { *wrapper.memory.data_ptr(&wrapper.store) = 42 }; - assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 42); - wrapper.decommit(); - assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 0); -} diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index 23b069870aa..ae78137959b 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -27,9 +27,7 @@ use crate::{ use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ error::{Error, Result, WasmError}, - runtime_blob::{ - self, DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob, - }, + runtime_blob::RuntimeBlob, util::checked_range, wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmInstance, WasmModule}, }; @@ -69,17 +67,11 @@ impl StoreData { pub(crate) type Store = wasmtime::Store; enum Strategy { - LegacyInstanceReuse { - instance_wrapper: InstanceWrapper, - globals_snapshot: GlobalsSnapshot, - data_segments_snapshot: Arc, - heap_base: u32, - }, RecreateInstance(InstanceCreator), } struct InstanceCreator { - engine: wasmtime::Engine, + engine: Engine, instance_pre: Arc>, } @@ -89,40 +81,10 @@ impl InstanceCreator { } } -struct InstanceGlobals<'a> { - instance: &'a mut InstanceWrapper, -} - -impl<'a> runtime_blob::InstanceGlobals for InstanceGlobals<'a> { - type Global = wasmtime::Global; - - fn get_global(&mut self, export_name: &str) -> Self::Global { - self.instance - .get_global(export_name) - .expect("get_global is guaranteed to be called with an export name of a global; qed") - } - - fn get_global_value(&mut self, global: &Self::Global) -> Value { - util::from_wasmtime_val(global.get(&mut self.instance.store_mut())) - } - - fn set_global_value(&mut self, global: &Self::Global, value: Value) { - global.set(&mut self.instance.store_mut(), util::into_wasmtime_val(value)).expect( - "the value is guaranteed to be of the same value; the global is guaranteed to be mutable; qed", - ); - } -} - -/// Data required for creating instances with the fast instance reuse strategy. -struct InstanceSnapshotData { - mutable_globals: ExposedMutableGlobalsSet, - data_segments_snapshot: Arc, -} - /// A `WasmModule` implementation using wasmtime to compile the runtime module to machine code /// and execute the compiled code. pub struct WasmtimeRuntime { - engine: wasmtime::Engine, + engine: Engine, instance_pre: Arc>, instantiation_strategy: InternalInstantiationStrategy, } @@ -130,26 +92,6 @@ pub struct WasmtimeRuntime { impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { let strategy = match self.instantiation_strategy { - InternalInstantiationStrategy::LegacyInstanceReuse(ref snapshot_data) => { - let mut instance_wrapper = InstanceWrapper::new(&self.engine, &self.instance_pre)?; - let heap_base = instance_wrapper.extract_heap_base()?; - - // This function panics if the instance was created from a runtime blob different - // from which the mutable globals were collected. Here, it is easy to see that there - // is only a single runtime blob and thus it's the same that was used for both - // creating the instance and collecting the mutable globals. - let globals_snapshot = GlobalsSnapshot::take( - &snapshot_data.mutable_globals, - &mut InstanceGlobals { instance: &mut instance_wrapper }, - ); - - Strategy::LegacyInstanceReuse { - instance_wrapper, - globals_snapshot, - data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), - heap_base, - } - }, InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator { engine: self.engine.clone(), instance_pre: self.instance_pre.clone(), @@ -174,39 +116,12 @@ impl WasmtimeInstance { allocation_stats: &mut Option, ) -> Result> { match &mut self.strategy { - Strategy::LegacyInstanceReuse { - ref mut instance_wrapper, - globals_snapshot, - data_segments_snapshot, - heap_base, - } => { - let entrypoint = instance_wrapper.resolve_entrypoint(method)?; - - data_segments_snapshot.apply(|offset, contents| { - util::write_memory_from( - instance_wrapper.store_mut(), - Pointer::new(offset), - contents, - ) - })?; - globals_snapshot.apply(&mut InstanceGlobals { instance: instance_wrapper }); - let allocator = FreeingBumpHeapAllocator::new(*heap_base); - - let result = - perform_call(data, instance_wrapper, entrypoint, allocator, allocation_stats); - - // Signal to the OS that we are done with the linear memory and that it can be - // reclaimed. - instance_wrapper.decommit(); - - result - }, Strategy::RecreateInstance(ref mut instance_creator) => { let mut instance_wrapper = instance_creator.instantiate()?; let heap_base = instance_wrapper.extract_heap_base()?; let entrypoint = instance_wrapper.resolve_entrypoint(method)?; - let allocator = FreeingBumpHeapAllocator::new(heap_base); + perform_call(data, &mut instance_wrapper, entrypoint, allocator, allocation_stats) }, } @@ -226,24 +141,10 @@ impl WasmInstance for WasmtimeInstance { fn get_global_const(&mut self, name: &str) -> Result> { match &mut self.strategy { - Strategy::LegacyInstanceReuse { instance_wrapper, .. } => - instance_wrapper.get_global_val(name), Strategy::RecreateInstance(ref mut instance_creator) => instance_creator.instantiate()?.get_global_val(name), } } - - fn linear_memory_base_ptr(&self) -> Option<*const u8> { - match &self.strategy { - Strategy::RecreateInstance(_) => { - // We do not keep the wasm instance around, therefore there is no linear memory - // associated with it. - None - }, - Strategy::LegacyInstanceReuse { instance_wrapper, .. } => - Some(instance_wrapper.base_ptr()), - } - } } /// Prepare a directory structure and a config file to enable wasmtime caching. @@ -338,7 +239,6 @@ fn common_config(semantics: &Semantics) -> std::result::Result (true, false), InstantiationStrategy::RecreateInstanceCopyOnWrite => (false, true), InstantiationStrategy::RecreateInstance => (false, false), - InstantiationStrategy::LegacyInstanceReuse => (false, false), }; const WASM_PAGE_SIZE: u64 = 65536; @@ -409,7 +309,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result { - let data_segments_snapshot = - DataSegmentsSnapshot::take(&blob).map_err(|e| { - WasmError::Other(format!("cannot take data segments snapshot: {}", e)) - })?; - let data_segments_snapshot = Arc::new(data_segments_snapshot); - let mutable_globals = ExposedMutableGlobalsSet::collect(&blob); - - ( - module, - InternalInstantiationStrategy::LegacyInstanceReuse(InstanceSnapshotData { - data_segments_snapshot, - mutable_globals, - }), - ) - }, InstantiationStrategy::Pooling | InstantiationStrategy::PoolingCopyOnWrite | InstantiationStrategy::RecreateInstance | @@ -679,12 +559,6 @@ where } }, CodeSupplyMode::Precompiled(compiled_artifact_path) => { - if let InstantiationStrategy::LegacyInstanceReuse = - config.semantics.instantiation_strategy - { - return Err(WasmError::Other("the legacy instance reuse instantiation strategy is incompatible with precompiled modules".into())); - } - // SAFETY: The unsafety of `deserialize_file` is covered by this function. The // responsibilities to maintain the invariants are passed to the caller. // @@ -695,12 +569,6 @@ where (module, InternalInstantiationStrategy::Builtin) }, CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes) => { - if let InstantiationStrategy::LegacyInstanceReuse = - config.semantics.instantiation_strategy - { - return Err(WasmError::Other("the legacy instance reuse instantiation strategy is incompatible with precompiled modules".into())); - } - // SAFETY: The unsafety of `deserialize` is covered by this function. The // responsibilities to maintain the invariants are passed to the caller. // @@ -730,13 +598,6 @@ fn prepare_blob_for_compilation( blob = blob.inject_stack_depth_metering(logical_max)?; } - if let InstantiationStrategy::LegacyInstanceReuse = semantics.instantiation_strategy { - // When this strategy is used this must be called after all other passes which may introduce - // new global variables, otherwise they will not be reset when we call into the runtime - // again. - blob.expose_mutable_globals(); - } - // We don't actually need the memory to be imported so we can just convert any memory // import into an export with impunity. This simplifies our code since `wasmtime` will // now automatically take care of creating the memory for us, and it is also necessary diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index 65093687822..e185754b076 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -30,7 +30,7 @@ type HostFunctions = sp_io::SubstrateHostFunctions; #[macro_export] macro_rules! test_wasm_execution { - (@no_legacy_instance_reuse $method_name:ident) => { + ($method_name:ident) => { paste::item! { #[test] fn [<$method_name _recreate_instance_cow>]() { @@ -61,19 +61,6 @@ macro_rules! test_wasm_execution { } } }; - - ($method_name:ident) => { - test_wasm_execution!(@no_legacy_instance_reuse $method_name); - - paste::item! { - #[test] - fn [<$method_name _legacy_instance_reuse>]() { - $method_name( - InstantiationStrategy::LegacyInstanceReuse - ); - } - } - }; } struct RuntimeBuilder { @@ -330,14 +317,14 @@ fn test_max_memory_pages_exported_memory_without_precompilation( test_max_memory_pages(instantiation_strategy, false, false); } -test_wasm_execution!(@no_legacy_instance_reuse test_max_memory_pages_imported_memory_with_precompilation); +test_wasm_execution!(test_max_memory_pages_imported_memory_with_precompilation); fn test_max_memory_pages_imported_memory_with_precompilation( instantiation_strategy: InstantiationStrategy, ) { test_max_memory_pages(instantiation_strategy, true, true); } -test_wasm_execution!(@no_legacy_instance_reuse test_max_memory_pages_exported_memory_with_precompilation); +test_wasm_execution!(test_max_memory_pages_exported_memory_with_precompilation); fn test_max_memory_pages_exported_memory_with_precompilation( instantiation_strategy: InstantiationStrategy, ) { diff --git a/substrate/client/executor/wasmtime/src/util.rs b/substrate/client/executor/wasmtime/src/util.rs index c38d969ce9d..7af554c35e1 100644 --- a/substrate/client/executor/wasmtime/src/util.rs +++ b/substrate/client/executor/wasmtime/src/util.rs @@ -21,33 +21,9 @@ use sc_executor_common::{ error::{Error, Result}, util::checked_range, }; -use sp_wasm_interface::{Pointer, Value}; +use sp_wasm_interface::Pointer; use wasmtime::{AsContext, AsContextMut}; -/// Converts a [`wasmtime::Val`] into a substrate runtime interface [`Value`]. -/// -/// Panics if the given value doesn't have a corresponding variant in `Value`. -pub fn from_wasmtime_val(val: wasmtime::Val) -> Value { - match val { - wasmtime::Val::I32(v) => Value::I32(v), - wasmtime::Val::I64(v) => Value::I64(v), - wasmtime::Val::F32(f_bits) => Value::F32(f_bits), - wasmtime::Val::F64(f_bits) => Value::F64(f_bits), - v => panic!("Given value type is unsupported by Substrate: {:?}", v), - } -} - -/// Converts a sp_wasm_interface's [`Value`] into the corresponding variant in wasmtime's -/// [`wasmtime::Val`]. -pub fn into_wasmtime_val(value: Value) -> wasmtime::Val { - match value { - Value::I32(v) => wasmtime::Val::I32(v), - Value::I64(v) => wasmtime::Val::I64(v), - Value::F32(f_bits) => wasmtime::Val::F32(f_bits), - Value::F64(f_bits) => wasmtime::Val::F64(f_bits), - } -} - /// Read data from the instance memory into a slice. /// /// Returns an error if the read would go out of the memory bounds. @@ -140,8 +116,8 @@ pub(crate) fn replace_strategy_if_broken(strategy: &mut InstantiationStrategy) { // These strategies require a working `madvise` to be sound. InstantiationStrategy::PoolingCopyOnWrite => InstantiationStrategy::Pooling, - InstantiationStrategy::RecreateInstanceCopyOnWrite | - InstantiationStrategy::LegacyInstanceReuse => InstantiationStrategy::RecreateInstance, + InstantiationStrategy::RecreateInstanceCopyOnWrite => + InstantiationStrategy::RecreateInstance, }; use std::sync::OnceLock; -- GitLab From a8e82a365e2a5f57a3bd51cb293dd6fbec4bf4f5 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 18 Sep 2023 11:04:47 +0200 Subject: [PATCH 164/633] xcm-builder: PayOverXcm supports fallible convertors for asset kind and beneficiary conversion (#1572) `PayOverXcm` type accepts two converters to transform the `AssetKind` and `Beneficiary` parameter types into recognized `xcm` types. In this PR, we've modified the bounds for these converters, transitioning from `Convert` to `TryConvert`. One such use case for this adjustment is when dealing with versioned xcm types for `AssetKind` and `Beneficiary`. These types might be not convertible to the latest xcm version, hence the need for fallible conversion. This changes required for https://github.com/paritytech/polkadot-sdk/pull/1333 --- .../xcm/xcm-builder/src/location_conversion.rs | 8 ++++---- polkadot/xcm/xcm-builder/src/pay.rs | 18 ++++++++++-------- polkadot/xcm/xcm-builder/src/tests/pay/pay.rs | 6 +++--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index 26b48fc88ad..ec23116e0e8 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -18,7 +18,7 @@ use crate::universal_exports::ensure_is_remote; use frame_support::traits::Get; use parity_scale_codec::{Compact, Decode, Encode}; use sp_io::hashing::blake2_256; -use sp_runtime::traits::{AccountIdConversion, Convert, TrailingZeroInput}; +use sp_runtime::traits::{AccountIdConversion, TrailingZeroInput, TryConvert}; use sp_std::{marker::PhantomData, prelude::*}; use xcm::latest::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -322,10 +322,10 @@ impl>, AccountId: From<[u8; 32]> + Into<[u8; 32]> /// network (provided by `Network`) and the `AccountId`'s `[u8; 32]` datum for the `id`. pub struct AliasesIntoAccountId32(PhantomData<(Network, AccountId)>); impl<'a, Network: Get>, AccountId: Clone + Into<[u8; 32]> + Clone> - Convert<&'a AccountId, MultiLocation> for AliasesIntoAccountId32 + TryConvert<&'a AccountId, MultiLocation> for AliasesIntoAccountId32 { - fn convert(who: &AccountId) -> MultiLocation { - AccountId32 { network: Network::get(), id: who.clone().into() }.into() + fn try_convert(who: &AccountId) -> Result { + Ok(AccountId32 { network: Network::get(), id: who.clone().into() }.into()) } } diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index 39e09e05677..0f3a622f4ec 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -20,7 +20,7 @@ use frame_support::traits::{ tokens::{Pay, PaymentStatus}, Get, }; -use sp_runtime::traits::Convert; +use sp_runtime::traits::TryConvert; use sp_std::{marker::PhantomData, vec}; use xcm::{opaque::lts::Weight, prelude::*}; use xcm_executor::traits::{QueryHandler, QueryResponseStatus}; @@ -71,8 +71,8 @@ impl< Timeout: Get, Beneficiary: Clone, AssetKind, - AssetKindToLocatableAsset: Convert, - BeneficiaryRefToLocation: for<'a> Convert<&'a Beneficiary, MultiLocation>, + AssetKindToLocatableAsset: TryConvert, + BeneficiaryRefToLocation: for<'a> TryConvert<&'a Beneficiary, MultiLocation>, > Pay for PayOverXcm< Interior, @@ -96,12 +96,14 @@ impl< asset_kind: Self::AssetKind, amount: Self::Balance, ) -> Result { - let locatable = AssetKindToLocatableAsset::convert(asset_kind); + let locatable = AssetKindToLocatableAsset::try_convert(asset_kind) + .map_err(|_| xcm::latest::Error::InvalidLocation)?; let LocatableAssetId { asset_id, location: asset_location } = locatable; let destination = Querier::UniversalLocation::get() .invert_target(&asset_location) .map_err(|()| Self::Error::LocationNotInvertible)?; - let beneficiary = BeneficiaryRefToLocation::convert(&who); + let beneficiary = BeneficiaryRefToLocation::try_convert(&who) + .map_err(|_| xcm::latest::Error::InvalidLocation)?; let query_id = Querier::new_query(asset_location, Timeout::get(), Interior::get()); @@ -196,10 +198,10 @@ pub struct LocatableAssetId { /// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`] /// value using a fixed `Location` for the `location` field. pub struct FixedLocation(sp_std::marker::PhantomData); -impl, AssetKind: Into> Convert +impl, AssetKind: Into> TryConvert for FixedLocation { - fn convert(value: AssetKind) -> LocatableAssetId { - LocatableAssetId { asset_id: value.into(), location: Location::get() } + fn try_convert(value: AssetKind) -> Result { + Ok(LocatableAssetId { asset_id: value.into(), location: Location::get() }) } } diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs index 28b2feec0c2..491a2bcef7a 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs @@ -29,9 +29,9 @@ pub struct AssetKind { } pub struct LocatableAssetKindConverter; -impl sp_runtime::traits::Convert for LocatableAssetKindConverter { - fn convert(value: AssetKind) -> LocatableAssetId { - LocatableAssetId { asset_id: value.asset_id, location: value.destination } +impl sp_runtime::traits::TryConvert for LocatableAssetKindConverter { + fn try_convert(value: AssetKind) -> Result { + Ok(LocatableAssetId { asset_id: value.asset_id, location: value.destination }) } } -- GitLab From 1d5a9d25e23df2a641b83b839c0a1a88b2e6b5ee Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Mon, 18 Sep 2023 11:05:12 +0200 Subject: [PATCH 165/633] [improve docs] Example pallet crate and Basic Example pallet (#1546) This fixes the broken links in the crate level documentation of the Examples crate. It also updates the documentation for the Basic Example pallet by removing the template for documenting a pallet (we now have [this](https://github.com/paritytech/polkadot-sdk/blob/master/docs/DOCUMENTATION_GUIDELINE.md) to refer to instead). Note: I found it unnecessary to provide a link to the doc guidelines as I don't think this would be where someone should discover them. I also want to flag some ideas that came while making these minor improvements in [this issue](https://github.com/paritytech/polkadot-sdk-docs/issues/27) (for a subsequent PR) as part of ongoing docs work. --- substrate/frame/examples/Cargo.toml | 2 +- substrate/frame/examples/basic/src/lib.rs | 267 ++-------------------- substrate/frame/examples/src/lib.rs | 29 +-- 3 files changed, 42 insertions(+), 256 deletions(-) diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index b072416b612..9c47d744211 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true -description = "The single package with various examples for frame pallets" +description = "The single package with examples of various types of FRAME pallets" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index 426e9b7ec64..31d20e07f5f 100644 --- a/substrate/frame/examples/basic/src/lib.rs +++ b/substrate/frame/examples/basic/src/lib.rs @@ -15,258 +15,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! //! # Basic Example Pallet //! -//! -//! The Example: A simple example of a FRAME pallet demonstrating -//! concepts, APIs and structures common to most FRAME runtimes. -//! -//! Run `cargo doc --package pallet-example-basic --open` to view this pallet's documentation. +//! A pallet demonstrating concepts, APIs and structures common to most FRAME runtimes. //! //! **This pallet serves as an example and is not meant to be used in production.** //! -//! ### Documentation Guidelines: -//! -//! -//!
    -//!
  • Documentation comments (i.e. /// comment) - should -//! accompany pallet functions and be restricted to the pallet interface, -//! not the internals of the pallet implementation. Only state inputs, -//! outputs, and a brief description that mentions whether calling it -//! requires root, but without repeating the source code details. -//! Capitalize the first word of each documentation comment and end it with -//! a full stop. See -//! Generic example of annotating source code with documentation comments
  • -//! -//!
  • Self-documenting code - Try to refactor code to be self-documenting.
  • -//! -//!
  • Code comments - Supplement complex code with a brief explanation, not every line of -//! code.
  • -//! -//!
  • Identifiers - surround by backticks (i.e. INHERENT_IDENTIFIER, -//! InherentType, u64)
  • -//! -//!
  • Usage scenarios - should be simple doctests. The compiler should ensure they stay -//! valid.
  • -//! -//!
  • Extended tutorials - should be moved to external files and refer to.
  • -//! -//!
  • Mandatory - include all of the sections/subsections where MUST is specified.
  • -//! -//!
  • Optional - optionally include sections/subsections where CAN is specified.
  • -//!
-//! -//! ### Documentation Template:
-//! -//! Copy and paste this template from frame/examples/basic/src/lib.rs into file -//! `frame//src/lib.rs` of your own custom pallet and complete it. -//!

-//! // Add heading with custom pallet name
-//!
-//! \#  Pallet
-//!
-//! // Add simple description
-//!
-//! // Include the following links that shows what trait needs to be implemented to use the pallet
-//! // and the supported dispatchables that are documented in the Call enum.
-//!
-//! - \[`Config`]
-//! - \[`Call`]
-//! - \[`Pallet`]
-//!
-//! \## Overview
-//!
-//! 
-//! // Short description of pallet's purpose.
-//! // Links to Traits that should be implemented.
-//! // What this pallet is for.
-//! // What functionality the pallet provides.
-//! // When to use the pallet (use case examples).
-//! // How it is used.
-//! // Inputs it uses and the source of each input.
-//! // Outputs it produces.
-//!
-//! 
-//! 
-//!
-//! \## Terminology
-//!
-//! // Add terminology used in the custom pallet. Include concepts, storage items, or actions that
-//! you think // deserve to be noted to give context to the rest of the documentation or pallet
-//! usage. The author needs to // use some judgment about what is included. We don't want a list of
-//! every storage item nor types - the user // can go to the code for that. For example, "transfer
-//! fee" is obvious and should not be included, but // "free balance" and "reserved balance" should
-//! be noted to give context to the pallet. // Please do not link to outside resources. The
-//! reference docs should be the ultimate source of truth.
-//!
-//! 
-//!
-//! \## Goals
-//!
-//! // Add goals that the custom pallet is designed to achieve.
-//!
-//! 
-//!
-//! \### Scenarios
-//!
-//! 
-//!
-//! \#### 
-//!
-//! // Describe requirements prior to interacting with the custom pallet.
-//! // Describe the process of interacting with the custom pallet for this scenario and public API
-//! functions used.
-//!
-//! \## Interface
-//!
-//! \### Supported Origins
-//!
-//! // What origins are used and supported in this pallet (root, signed, none)
-//! // i.e. root when \`ensure_root\` used
-//! // i.e. none when \`ensure_none\` used
-//! // i.e. signed when \`ensure_signed\` used
-//!
-//! \`inherent\` 
-//!
-//! 
-//! 
-//!
-//! \### Types
-//!
-//! // Type aliases. Include any associated types and where the user would typically define them.
-//!
-//! \`ExampleType\` 
-//!
-//! 
-//!
-//! // Reference documentation of aspects such as `storageItems` and `dispatchable` functions should
-//! // only be included in the  Rustdocs for Substrate and not repeated in the
-//! // README file.
-//!
-//! \### Dispatchable Functions
-//!
-//! 
-//!
-//! // A brief description of dispatchable functions and a link to the rustdoc with their actual
-//! documentation.
-//!
-//! // MUST have link to Call enum
-//! // MUST have origin information included in function doc
-//! // CAN have more info up to the user
-//!
-//! \### Public Functions
-//!
-//! 
-//!
-//! // A link to the rustdoc and any notes about usage in the pallet, not for specific functions.
-//! // For example, in the Balances Pallet: "Note that when using the publicly exposed functions,
-//! // you (the runtime developer) are responsible for implementing any necessary checks
-//! // (e.g. that the sender is the signer) before calling a function that will affect storage."
-//!
-//! 
-//!
-//! // It is up to the writer of the respective pallet (with respect to how much information to
-//! provide).
-//!
-//! \#### Public Inspection functions - Immutable (getters)
-//!
-//! // Insert a subheading for each getter function signature
-//!
-//! \##### \`example_getter_name()\`
-//!
-//! // What it returns
-//! // Why, when, and how often to call it
-//! // When it could panic or error
-//! // When safety issues to consider
-//!
-//! \#### Public Mutable functions (changing state)
-//!
-//! // Insert a subheading for each setter function signature
-//!
-//! \##### \`example_setter_name(origin, parameter_name: T::ExampleType)\`
-//!
-//! // What state it changes
-//! // Why, when, and how often to call it
-//! // When it could panic or error
-//! // When safety issues to consider
-//! // What parameter values are valid and why
-//!
-//! \### Storage Items
-//!
-//! // Explain any storage items included in this pallet
-//!
-//! \### Digest Items
-//!
-//! // Explain any digest items included in this pallet
-//!
-//! \### Inherent Data
-//!
-//! // Explain what inherent data (if any) is defined in the pallet and any other related types
-//!
-//! \### Events:
-//!
-//! // Insert events for this pallet if any
-//!
-//! \### Errors:
-//!
-//! // Explain what generates errors
-//!
-//! \## Usage
-//!
-//! // Insert 2-3 examples of usage and code snippets that show how to
-//! // use  Pallet in a custom pallet.
-//!
-//! \### Prerequisites
-//!
-//! // Show how to include necessary imports for  and derive
-//! // your pallet configuration trait with the `INSERT_CUSTOM_PALLET_NAME` trait.
-//!
-//! \```rust
-//! use ;
-//!
-//! pub trait Config: ::Config { }
-//! \```
-//!
-//! \### Simple Code Snippet
-//!
-//! // Show a simple example (e.g. how to query a public getter function of
-//! )
-//!
-//! \### Example from FRAME
-//!
-//! // Show a usage example in an actual runtime
-//!
-//! // See:
-//! // - Substrate TCR 
-//! // - Substrate Kitties 
-//!
-//! \## Genesis Config
-//!
-//! 
-//!
-//! \## Dependencies
+//! > Made with *Substrate*, for *Polkadot*.
 //!
-//! // Dependencies on other FRAME pallets and the genesis config should be mentioned,
-//! // but not the Rust Standard Library.
-//! // Genesis configuration modifications that may be made to incorporate this pallet
-//! // Interaction with other pallets
+//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/examples/basic)
+//! [![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
 //!
-//! \## Related Pallets
+//! ## Pallet API
 //!
-//! // Interaction with other pallets in the form of a bullet point list
+//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
+//! including its configuration trait, dispatchables, storage items, events and errors.
 //!
-//! \## References
+//! ## Overview
 //!
-//! 
+//! This pallet provides basic examples of using:
 //!
-//! // Links to reference material, if applicable. For example, Phragmen, W3F research, etc.
-//! // that the implementation is based on.
-//! 

+//! - A custom weight calculator able to classify a call's dispatch class (see: +//! [`frame_support::dispatch::DispatchClass`]) +//! - Pallet hooks to implement some custom logic that's executed before and after a block is +//! imported (see: [`frame_support::traits::Hooks`]) +//! - Inherited weight annotation for pallet calls, used to create less repetition for calls that +//! use the [`Config::WeightInfo`] trait to calculate call weights. This can also be overridden, +//! as demonstrated by [`Call::set_dummy`]. +//! - A private function that performs a storage update. +//! - A simple signed extension implementation (see: [`sp_runtime::traits::SignedExtension`]) which +//! increases the priority of the [`Call::set_dummy`] if it's present and drops any transaction +//! with an encoded length higher than 200 bytes. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -381,7 +163,8 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); - // Pallet implements [`Hooks`] trait to define some logic to execute in some context. + // This pallet implements the [`frame_support::traits::Hooks`] trait to define some logic to + // execute in some context. #[pallet::hooks] impl Hooks> for Pallet { // `on_initialize` is executed at the beginning of the block before any extrinsic are @@ -686,7 +469,7 @@ impl Pallet { // sender of the transaction (if signed) are also provided. // // The full list of hooks that can be added to a signed extension can be found -// [here](https://crates.parity.io/sp_runtime/traits/trait.SignedExtension.html). +// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.SignedExtension.html). // // The signed extensions are aggregated in the runtime file of a substrate chain. All extensions // should be aggregated in a tuple and passed to the `CheckedExtrinsic` and `UncheckedExtrinsic` diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index d1cd32bb50f..a7084fc6ef9 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -17,24 +17,27 @@ //! # FRAME Pallet Examples //! -//! This crate contains examples of FRAME pallets. It is not intended to be used in production. +//! This crate contains a collection of simple examples of FRAME pallets, demonstrating useful +//! features in action. It is not intended to be used in production. //! //! ## Pallets //! -//! - [**`pallet_example_basic`**](./basic): A simple example of a FRAME pallet demonstrating -//! concepts, APIs and structures common to most FRAME runtimes. +//! - [`pallet_example_basic`]: This pallet demonstrates concepts, APIs and structures common to +//! most FRAME runtimes. //! -//! - [**`pallet_example_offchain_worker`**](./offchain-worker): A simple example of a FRAME pallet -//! demonstrating concepts, APIs and structures common to most offchain workers. +//! - [`pallet_example_offchain_worker`]: This pallet demonstrates concepts, APIs and structures +//! common to most offchain workers. //! -//! - [**`pallet-default-config-example`**](./default-config): A simple example of a FRAME pallet -//! demonstrating the simpler way to implement `Config` trait of pallets. +//! - [`pallet_default_config_example`]: This pallet demonstrates different ways to implement the +//! `Config` trait of pallets. //! -//! - [**`pallet-dev-mode`**](./dev-mode): A simple example of a FRAME pallet demonstrating the ease -//! of requirements for a pallet in dev mode. +//! - [`pallet_dev_mode`]: This pallet demonstrates the ease of requirements for a pallet in "dev +//! mode". //! -//! - [**`pallet-example-kitchensink`**](./kitchensink): A simple example of a FRAME pallet -//! demonstrating a catalog of the the FRAME macros and their various syntax options. +//! - [`pallet_example_kitchensink`]: This pallet demonstrates a catalog of all FRAME macros in use +//! and their various syntax options. //! -//! - [**`pallet-example-split`**](./split): A simple example of a FRAME pallet demonstrating the -//! ability to split sections across multiple files. +//! - [`pallet_example_split`]: A simple example of a FRAME pallet demonstrating the ability to +//! split sections across multiple files. +//! +//! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. -- GitLab From f6072e8be3adede66f5e56104f77920fe5c3b5db Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Mon, 18 Sep 2023 11:09:17 +0200 Subject: [PATCH 166/633] [improve docs]: Timestamp pallet (#1435) This PR improves the docs for the Timestamp pallet by following our [Documentation Guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/DOCUMENTATION_GUIDELINE.md) more closely. --------- Co-authored-by: Juan Co-authored-by: Francisco Aguirre --- Cargo.lock | 1 + docs/DOCUMENTATION_GUIDELINE.md | 33 +++-- substrate/frame/timestamp/Cargo.toml | 2 + substrate/frame/timestamp/src/lib.rs | 162 ++++++++++++++-------- substrate/frame/timestamp/src/tests.rs | 2 + substrate/primitives/timestamp/src/lib.rs | 2 +- 6 files changed, 126 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06d4b34031f..f09db7643e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10502,6 +10502,7 @@ dependencies = [ name = "pallet-timestamp" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", diff --git a/docs/DOCUMENTATION_GUIDELINE.md b/docs/DOCUMENTATION_GUIDELINE.md index f6c8cac7cd2..dbb4298d50f 100644 --- a/docs/DOCUMENTATION_GUIDELINE.md +++ b/docs/DOCUMENTATION_GUIDELINE.md @@ -123,9 +123,9 @@ explicitly depend on them, you have likely not designed it properly. #### Proc-Macros -Note that there are special considerations when documenting proc macros. Doc links will appear to function _within_ your +Note that there are special considerations when documenting proc macros. Doc links will appear to function *within* your proc macro crate, but often will no longer function when these proc macros are re-exported elsewhere in your project. -The exception is doc links to _other proc macros_ which will function just fine if they are also being re-exported. It +The exception is doc links to *other proc macros* which will function just fine if they are also being re-exported. It is also often necessary to disambiguate between a proc macro and a function of the same name, which can be done using the `macro@my_macro_name` syntax in your link. Read more about how to correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and @@ -189,6 +189,7 @@ fn multiply_by_2(x: u32) -> u32 { .. } // More efficiency can be achieved if we improve this via such and such. fn multiply_by_2(x: u32) -> u32 { .. } ``` + They are both roughly conveying the same set of facts, but one is easier to follow because it was formatted cleanly. Especially for traits and types that you can foresee will be seen and used a lot, try and write a well formatted version. @@ -203,7 +204,6 @@ properly do this. --- - ## Pallet Crates The guidelines so far have been general in nature, and are applicable to crates that are pallets and crates that're not @@ -223,6 +223,14 @@ For the top-level pallet docs, consider the following template: //! //! . //! +//! ## Pallet API +//! +//! +//! +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, including its +//! configuration trait, dispatchables, storage items, events and errors. +//! //! ## Overview //! //! @@ -233,20 +241,12 @@ For the top-level pallet docs, consider the following template: //! //! ### Example //! -//! . +//! //! -//! ## Pallet API -//! -//! -//! -//! See the [`pallet`] module for more information about the interfaces this pallet exposes, including its configuration -//! trait, dispatchables, storage items, events and errors. -//! -//! +//! //! //! This section can most often be left as-is. //! @@ -272,7 +272,6 @@ For the top-level pallet docs, consider the following template: //! up> ``` - This template's details (heading 3s and beyond) are left flexible, and at the discretion of the developer to make the best final choice about. For example, you might want to include `### Terminology` or not. Moreover, you might find it more useful to include it in `## Overview`. diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index a39c79892d1..6759d90aaf4 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -27,6 +27,8 @@ 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" + [dev-dependencies] sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } diff --git a/substrate/frame/timestamp/src/lib.rs b/substrate/frame/timestamp/src/lib.rs index 4eb95941d78..ad055bab004 100644 --- a/substrate/frame/timestamp/src/lib.rs +++ b/substrate/frame/timestamp/src/lib.rs @@ -15,53 +15,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Timestamp Pallet -//! -//! The Timestamp pallet provides functionality to get and set the on-chain time. -//! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] -//! -//! ## Overview -//! -//! The Timestamp pallet allows the validators to set and validate a timestamp with each block. -//! -//! It uses inherents for timestamp data, which is provided by the block author and -//! validated/verified by other validators. The timestamp can be set only once per block and must be -//! set each block. There could be a constraint on how much time must pass before setting the new -//! timestamp. +//! > Made with *Substrate*, for *Polkadot*. //! -//! **NOTE:** The Timestamp pallet is the recommended way to query the on-chain time instead of -//! using an approach based on block numbers. The block number based time measurement can cause -//! issues because of cumulative calculation errors and hence should be avoided. +//! [![github]](https://github.com/paritytech/polkadot-sdk/substrate/frame/timestamp) +//! [![polkadot]](https://polkadot.network) //! -//! ## Interface +//! [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 //! -//! ### Dispatchable Functions -//! -//! * `set` - Sets the current time. -//! -//! ### Public functions +//! # Timestamp Pallet //! -//! * `get` - Gets the current time for the current block. If this function is called prior to -//! setting the timestamp, it will return the timestamp of the previous block. +//! A pallet that provides a way for consensus systems to set and check the onchain time. //! -//! ### Config Getters +//! ## Pallet API //! -//! * `MinimumPeriod` - Gets the minimum (and advised) period between blocks for the chain. +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. +//! +//! ## Overview //! -//! ## Usage +//! The Timestamp pallet is designed to create a consensus-based time source. This helps ensure that +//! nodes maintain a synchronized view of time that all network participants can agree on. //! -//! The following example shows how to use the Timestamp pallet in your custom pallet to query the -//! current timestamp. +//! It defines an _acceptable range_ using a configurable constant to specify how much time must +//! pass before setting the new timestamp. Validator nodes in the network must verify that the +//! timestamp falls within this acceptable range and reject blocks that do not. //! -//! ### Prerequisites +//! > **Note:** The timestamp set by this pallet is the recommended way to query the onchain time +//! > instead of using block numbers alone. Measuring time with block numbers can cause cumulative +//! > calculation errors if depended upon in time critical operations and hence should generally be +//! > avoided. //! -//! Import the Timestamp pallet into your custom pallet and derive the pallet configuration -//! trait from the timestamp trait. +//! ## Example //! -//! ### Get current timestamp +//! To get the current time for the current block in another pallet: //! //! ``` //! use pallet_timestamp::{self as timestamp}; @@ -83,7 +70,7 @@ //! #[pallet::weight(0)] //! pub fn get_time(origin: OriginFor) -> DispatchResult { //! let _sender = ensure_signed(origin)?; -//! let _now = >::get(); +//! let _now = timestamp::Pallet::::get(); //! Ok(()) //! } //! } @@ -91,15 +78,52 @@ //! # fn main() {} //! ``` //! -//! ### Example from the FRAME +//! If [`Pallet::get`] is called prior to setting the timestamp, it will return the timestamp of +//! the previous block. //! -//! The [Session pallet](https://github.com/paritytech/substrate/blob/master/frame/session/src/lib.rs) uses -//! the Timestamp pallet for session management. +//! ## Low Level / Implementation Details //! -//! ## Related Pallets +//! A timestamp is added to the chain using an _inherent extrinsic_ that only a block author can +//! submit. Inherents are a special type of extrinsic in Substrate chains that will always be +//! included in a block. //! -//! * [Session](../pallet_session/index.html) - +//! To provide inherent data to the runtime, this pallet implements +//! [`ProvideInherent`](frame_support::inherent::ProvideInherent). It will only create an inherent +//! if the [`Call::set`] dispatchable is called, using the +//! [`inherent`](frame_support::pallet_macros::inherent) macro which enables validator nodes to call +//! into the runtime to check that the timestamp provided is valid. +//! The implementation of [`ProvideInherent`](frame_support::inherent::ProvideInherent) specifies a +//! constant called `MAX_TIMESTAMP_DRIFT_MILLIS` which is used to determine the acceptable range for +//! a valid timestamp. If a block author sets a timestamp to anything that is more than this +//! constant, a validator node will reject the block. +//! +//! The pallet also ensures that a timestamp is set at the start of each block by running an +//! assertion in the `on_finalize` runtime hook. See [`frame_support::traits::Hooks`] for more +//! information about how hooks work. +//! +//! Because inherents are applied to a block in the order they appear in the runtime +//! construction, the index of this pallet in +//! [`construct_runtime`](frame_support::construct_runtime) must always be less than any other +//! pallet that depends on it. +//! +//! The [`Config::OnTimestampSet`] configuration trait can be set to another pallet we want to +//! notify that the timestamp has been updated, as long as it implements [`OnTimestampSet`]. +//! Examples are the Babe and Aura pallets. +//! This pallet also implements [`Time`] and [`UnixTime`] so it can be used to configure other +//! pallets that require these types (e.g. in Staking pallet). +//! +//! ## Panics +//! +//! There are 3 cases where this pallet could cause the runtime to panic. +//! +//! 1. If no timestamp is set at the end of a block. +//! +//! 2. If a timestamp is set more than once per block: +#![doc = docify::embed!("src/tests.rs", double_timestamp_should_fail)] +//! +//! 3. If a timestamp is set before the [`Config::MinimumPeriod`] is elapsed: +#![doc = docify::embed!("src/tests.rs", block_period_minimum_enforced)] +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; @@ -123,10 +147,9 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The pallet configuration trait #[pallet::config] pub trait Config: frame_system::Config { - /// Type used for expressing timestamp. + /// Type used for expressing a timestamp. type Moment: Parameter + Default + AtLeast32Bit @@ -135,14 +158,17 @@ pub mod pallet { + MaxEncodedLen + scale_info::StaticTypeInfo; - /// Something which can be notified when the timestamp is set. Set this to `()` if not - /// needed. + /// Something which can be notified (e.g. another pallet) when the timestamp is set. + /// + /// This can be set to `()` if it is not needed. type OnTimestampSet: OnTimestampSet; - /// The minimum period between blocks. Beware that this is different to the *expected* - /// period that the block production apparatus provides. Your chosen consensus system will - /// generally work with this to determine a sensible block time. e.g. For Aura, it will be - /// double this period on default settings. + /// The minimum period between blocks. + /// + /// Be aware that this is different to the *expected* period that the block production + /// apparatus provides. Your chosen consensus system will generally work with this to + /// determine a sensible block time. For example, in the Aura pallet it will be double this + /// period on default settings. #[pallet::constant] type MinimumPeriod: Get; @@ -153,23 +179,31 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); - /// Current time for the current block. + /// The current time for the current block. #[pallet::storage] #[pallet::getter(fn now)] pub type Now = StorageValue<_, T::Moment, ValueQuery>; - /// Did the timestamp get updated in this block? + /// Whether the timestamp has been updated in this block. + /// + /// This value is updated to `true` upon successful submission of a timestamp by a node. + /// It is then checked at the end of each block execution in the `on_finalize` hook. #[pallet::storage] pub(super) type DidUpdate = StorageValue<_, bool, ValueQuery>; #[pallet::hooks] impl Hooks> for Pallet { - /// dummy `on_initialize` to return the weight used in `on_finalize`. + /// A dummy `on_initialize` to return the amount of weight that `on_finalize` requires to + /// execute. fn on_initialize(_n: BlockNumberFor) -> Weight { // weight of `on_finalize` T::WeightInfo::on_finalize() } + /// At the end of block execution, the `on_finalize` hook checks that the timestamp was + /// updated. Upon success, it removes the boolean value from storage. If the value resolves + /// to `false`, the pallet will panic. + /// /// ## Complexity /// - `O(1)` fn on_finalize(_n: BlockNumberFor) { @@ -185,13 +219,17 @@ pub mod pallet { /// phase, if this call hasn't been invoked by that time. /// /// The timestamp should be greater than the previous one by the amount specified by - /// `MinimumPeriod`. + /// [`Config::MinimumPeriod`]. + /// + /// The dispatch origin for this call must be _None_. /// - /// The dispatch origin for this call must be `Inherent`. + /// This dispatch class is _Mandatory_ to ensure it gets executed in the block. Be aware + /// that changing the complexity of this call could result exhausting the resources in a + /// block to execute any other calls. /// /// ## Complexity /// - `O(1)` (Note that implementations of `OnTimestampSet` must also be `O(1)`) - /// - 1 storage read and 1 storage mutation (codec `O(1)`). (because of `DidUpdate::take` in + /// - 1 storage read and 1 storage mutation (codec `O(1)` because of `DidUpdate::take` in /// `on_finalize`) /// - 1 event handler `on_timestamp_set`. Must be `O(1)`. #[pallet::call_index(0)] @@ -216,6 +254,14 @@ pub mod pallet { } } + /// To check the inherent is valid, we simply take the max value between the current timestamp + /// and the current timestamp plus the [`Config::MinimumPeriod`]. + /// We also check that the timestamp has not already been set in this block. + /// + /// ## Errors: + /// - [`InherentError::TooFarInFuture`]: If the timestamp is larger than the current timestamp + + /// minimum drift period. + /// - [`InherentError::TooEarly`]: If the timestamp is less than the current + minimum period. #[pallet::inherent] impl ProvideInherent for Pallet { type Call = Call; @@ -285,9 +331,9 @@ impl Pallet { } impl Time for Pallet { + /// A type that represents a unit of time. type Moment = T::Moment; - /// Before the first set of now with inherent the value returned is zero. fn now() -> Self::Moment { Self::now() } diff --git a/substrate/frame/timestamp/src/tests.rs b/substrate/frame/timestamp/src/tests.rs index 317631eeb70..cc49d8a3296 100644 --- a/substrate/frame/timestamp/src/tests.rs +++ b/substrate/frame/timestamp/src/tests.rs @@ -30,6 +30,7 @@ fn timestamp_works() { }); } +#[docify::export] #[test] #[should_panic(expected = "Timestamp must be updated only once in the block")] fn double_timestamp_should_fail() { @@ -39,6 +40,7 @@ fn double_timestamp_should_fail() { }); } +#[docify::export] #[test] #[should_panic( expected = "Timestamp must increment by at least between sequential blocks" diff --git a/substrate/primitives/timestamp/src/lib.rs b/substrate/primitives/timestamp/src/lib.rs index eeec73efbc8..d1bd2a3446e 100644 --- a/substrate/primitives/timestamp/src/lib.rs +++ b/substrate/primitives/timestamp/src/lib.rs @@ -140,7 +140,7 @@ pub enum InherentError { error("The time since the last timestamp is lower than the minimum period.") )] TooEarly, - /// The block timestamp is too far in the future + /// The block timestamp is too far in the future. #[cfg_attr(feature = "std", error("The timestamp of the block is too far in the future."))] TooFarInFuture, } -- GitLab From d569e728ca710c64392e524c9ccd4ec10c370269 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 18 Sep 2023 11:11:08 +0200 Subject: [PATCH 167/633] "Common good" vs "System" parachain clean up (#1406) ## Summary The term "common good parachain" has been abandoned in favor of "system parachain" - e.g. [Joe's speech at Decoded2023](https://youtu.be/CSO-ERHK2gY?t=456). This pull request tries to fix and align code with this vision. ## Impact The important change is implementation of `trait IsSystem` for `Id` [here](https://github.com/paritytech/polkadot-sdk/pull/1406/files#diff-0b7b4f5b962a18ce980354592b55ab2a27b5a2e9f6f8089ec803ca73853e8583R225-R229) where we changed condition from `< 1000` to `<= 1999`, which means that all parachain IDs bellow 1999 (included) are considered as "system parachain" IDs. This change has a direct impact on the following components: #### [ChildSystemParachainAsSuperuser](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/origin_conversion.rs#L72-L88) This origin converter is used for allowing to process XCM `Transact` from "system parachain" on the relay chain - e.g. see [configuration for Kusama](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/runtime/kusama/src/xcm_config.rs#L92-L101). Only configured for Kusama, Westend, Rococo runtimes. **No need for this feature anymore.** See [comment](https://github.com/paritytech/polkadot-sdk/pull/1406#issuecomment-1708218715). #### [IsChildSystemParachain](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/barriers.rs#L310-L317) `IsChildSystemParachain` is used with `AllowExplicitUnpaidExecutionFrom` barrier for checking XCM programs (they have to start with `UnpaidExecution` instruction). Only configured for Kusama, Westend, Rococo runtimes. **Overall the impact is low or mostly ok because it only allows unpaid execution for "system parachains" (e.g. AssetHub, BridgeHub...) on the relay chain.** #### [SiblingSystemParachainAsSuperuser](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/origin_conversion.rs#L94-L114) Not used anywhere in `polkadot-sdk` repo. ## Unresolved Questions - [ ] constants `LOWEST_USER_ID` and `LOWEST_PUBLIC_ID` seem to express the same thing now, do we want to keep them both or deprecated one of them? If so, which one? - [x] determine impact for `ChildSystemParachainAsSuperuser` ## TODO - [ ] when merged here, open PR to the `polkadot-fellows` ## Related Material https://youtu.be/CSO-ERHK2gY?t=456 https://forum.polkadot.network/t/polkadot-protocol-and-common-good-parachains/866 https://wiki.polkadot.network/docs/learn-system-chains --- .../collectives/collectives-polkadot/src/lib.rs | 2 +- .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- polkadot/parachain/src/primitives.rs | 10 ++++------ polkadot/primitives/src/v5/mod.rs | 2 +- polkadot/runtime/kusama/src/lib.rs | 2 +- polkadot/runtime/kusama/src/xcm_config.rs | 11 ++++------- polkadot/runtime/polkadot/src/lib.rs | 2 +- polkadot/runtime/rococo/src/xcm_config.rs | 11 ++++------- polkadot/runtime/westend/src/xcm_config.rs | 9 ++++----- 9 files changed, 21 insertions(+), 30 deletions(-) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index d9125c2645e..70e62a4dcdf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -20,7 +20,7 @@ //! //! ### Governance //! -//! As a common good parachain, Collectives defers its governance (namely, its `Root` origin), to +//! As a system parachain, Collectives defers its governance (namely, its `Root` origin), to //! its Relay Chain parent, Polkadot. //! //! ### Collator Selection diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 97d2e63370e..f2ffc451b10 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -163,7 +163,7 @@ pub type Barrier = TrailingSetTopicAsId< // If the message is one that immediately attemps to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, - // Common Good Assets parachain, parent and its exec plurality get free + // System Assets parachain, parent and its exec plurality get free // execution AllowExplicitUnpaidExecutionFrom<( CommonGoodAssetsParachain, diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index 5cea9d3bbf4..5f77810f5c2 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -199,13 +199,11 @@ impl From for Id { } } -const USER_INDEX_START: u32 = 1000; +// System parachain ID is considered `< 2000`. +const SYSTEM_INDEX_END: u32 = 1999; const PUBLIC_INDEX_START: u32 = 2000; -/// The ID of the first user (non-system) parachain. -pub const LOWEST_USER_ID: Id = Id(USER_INDEX_START); - -/// The ID of the first publicly registerable parachain. +/// The ID of the first publicly registrable parachain. pub const LOWEST_PUBLIC_ID: Id = Id(PUBLIC_INDEX_START); impl Id { @@ -223,7 +221,7 @@ pub trait IsSystem { impl IsSystem for Id { fn is_system(&self) -> bool { - self.0 < USER_INDEX_START + self.0 <= SYSTEM_INDEX_END } } diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v5/mod.rs index 30782f95611..81743225403 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v5/mod.rs @@ -44,7 +44,7 @@ pub use polkadot_core_primitives::v2::{ // Export some polkadot-parachain primitives pub use polkadot_parachain_primitives::primitives::{ HeadData, HorizontalMessages, HrmpChannelId, Id, UpwardMessage, UpwardMessages, ValidationCode, - ValidationCodeHash, LOWEST_PUBLIC_ID, LOWEST_USER_ID, + ValidationCodeHash, LOWEST_PUBLIC_ID, }; use serde::{Deserialize, Serialize}; diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index fc9fd61790e..0681db23bc2 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -643,7 +643,7 @@ impl pallet_staking::EraPayout for EraPayout { // 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 or common good chain is the number + // 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; diff --git a/polkadot/runtime/kusama/src/xcm_config.rs b/polkadot/runtime/kusama/src/xcm_config.rs index 6a9cea22bbc..59ea937e11c 100644 --- a/polkadot/runtime/kusama/src/xcm_config.rs +++ b/polkadot/runtime/kusama/src/xcm_config.rs @@ -37,11 +37,10 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, MintLocation, - OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, + IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; parameter_types! { @@ -95,8 +94,6 @@ type LocalOriginConverter = ( ChildParachainAsNative, // The AccountId32 location type can be expressed natively as a `Signed` origin. SignedAccountId32AsNative, - // A system child parachain, expressed as a Superuser, converts to the `Root` origin. - ChildSystemParachainAsSuperuser, ); parameter_types! { diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index 6d06ee46933..441a5132eda 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -552,7 +552,7 @@ impl pallet_staking::EraPayout for EraPayout { // 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 or common good chain is the number + // 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; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index d561df14a02..288ee8400dc 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -36,11 +36,10 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete, - MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithUniqueTopic, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, + IsChildSystemParachain, IsConcrete, MintLocation, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -80,8 +79,6 @@ type LocalOriginConverter = ( ChildParachainAsNative, // The AccountId32 location type can be expressed natively as a `Signed` origin. SignedAccountId32AsNative, - // A system child parachain, expressed as a Superuser, converts to the `Root` origin. - ChildSystemParachainAsSuperuser, ); parameter_types! { diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 264830c693e..afa0733b4c9 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -35,10 +35,10 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, MintLocation, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, + IsConcrete, MintLocation, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -74,7 +74,6 @@ type LocalOriginConverter = ( SovereignSignedViaLocation, ChildParachainAsNative, SignedAccountId32AsNative, - ChildSystemParachainAsSuperuser, ); /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our -- GitLab From 614aa31bf7a4b0e04595835a80562ce5eac96c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 18 Sep 2023 11:18:19 +0200 Subject: [PATCH 168/633] Implements a variable deposit base calculation for EPM signed submissions (#1547) **Note**: This is a lift-and-shift PR from the old substrate and polkadot repos, both PRs have been reviewed and audited (https://github.com/paritytech/substrate/pull/13983, https://github.com/paritytech/polkadot/pull/7140) --- This PR implements a generic `BaseDeposit` calculation for signed submissions, based on the size of the submission queue. It adds a new associated type to EPM's config, `type SignedDepositBase`, that implements `Convert>`, which is used to calculate the base deposit for signed submissions based on the size of the signed submissions queue. `struct GeometricDepositBase` implements the convert trait so that the deposit value increases as a geometric progression. The deposit base is calculated by `deposit_base = fixed_deposit_base * (1 + increase_factor)^n`, where `n` is the term of the progression (i.e. the number of signed submissions in the queue). `Fixed` and `Inc` generic params are getters for `Balance` and `IncreaseFactor` to compute the geometric progression. If `IncreaseFactor = 0`, then the signed deposit is constant and equal to `Fixed` regardless of the size of the queue. ### Runtime configs In Kusama, the progression with 10% increase without changing the current signed fixed deposit is: (term == size of the queue) Term 1: `1,333,333,332,000` Term 2: `1,333,333,332,000 * 1.10 = 1,466,666,665,200` Term 3: `1,333,333,332,000 * 1.10^2 = 1,613,333,331,200` Term 4: `1,333,333,332,000 * 1.10^3 = 1,774,666,664,320` Term 5: `1,333,333,332,000 * 1.10^4 = 1,952,133,330,752` Term 6: `1,333,333,332,000 * 1.10^5 = 2,147,346,663,827.20` Term 7: `1,333,333,332,000 * 1.10^6 = 2,362,081,330,210.92` Term 8: `1,333,333,332,000 * 1.10^7 = 2,598,289,463,231.01` Term 9: `1,333,333,332,000 * 1.10^8 = 2,858,118,409,554.11` Term 10: `1,333,333,332,000 * 1.10^9 = 3,143,930,250,509.52` Westend: Term 1: `2,000,000,000,000` Term 2: `2,000,000,000,000 * 1.10 = 2,200,000,000,000` Term 3: `2,000,000,000,000 * 1.10^2 = 2,420,000,000,000` Term 4: `2,000,000,000,000 * 1.10^3 = 2,662,000,000,000` Term 5: `2,000,000,000,000 * 1.10^4 = 2,928,200,000,000` Term 6: `2,000,000,000,000 * 1.10^5 = 3,221,020,000,000` Term 7: `2,000,000,000,000 * 1.10^6 = 3,543,122,000,000` Term 8: `2,000,000,000,000 * 1.10^7 = 3,897,434,200,000` Term 9: `2,000,000,000,000 * 1.10^8 = 4,287,177,620,000` Term 10: `2,000,000,000,000 * 1.10^9 = 4,715,895,382,000` and in Polkadot, the deposit increase is disabled in the current state of the PR, as the increase factor is 0% -- so nothing changes from the current behaviour. Closes https://github.com/paritytech-secops/srlabs_findings/issues/189 --- polkadot/runtime/kusama/src/lib.rs | 10 ++- polkadot/runtime/polkadot/src/lib.rs | 9 +- polkadot/runtime/westend/src/lib.rs | 10 ++- substrate/bin/node/runtime/src/lib.rs | 8 +- .../election-provider-multi-phase/src/lib.rs | 13 +-- .../election-provider-multi-phase/src/mock.rs | 34 +++++-- .../src/signed.rs | 89 +++++++++++++++++-- .../test-staking-e2e/src/mock.rs | 11 ++- 8 files changed, 150 insertions(+), 34 deletions(-) diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 0681db23bc2..5cf2b3b83b1 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -93,7 +93,7 @@ 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; +pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; use pallet_staking::UseValidatorsMap; @@ -511,7 +511,8 @@ parameter_types! { // signed config pub const SignedMaxSubmissions: u32 = 16; pub const SignedMaxRefunds: u32 = 16 / 4; - pub const SignedDepositBase: Balance = deposit(2, 0); + 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; @@ -584,7 +585,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SignedMaxSubmissions = SignedMaxSubmissions; type SignedMaxRefunds = SignedMaxRefunds; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = + GeometricDepositBase; type SignedDepositByte = SignedDepositByte; type SignedDepositWeight = (); type SignedMaxWeight = @@ -2484,7 +2486,7 @@ mod fees_tests { 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 = SignedDepositBase::get() + (SignedDepositByte::get() * 1024 * 1024); + let deposit = SignedFixedDeposit::get() + (SignedDepositByte::get() * 1024 * 1024); assert_eq_error_rate!(deposit, UNITS * 167 / 100, UNITS / 100); } } diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index 441a5132eda..da27771af40 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -90,7 +90,7 @@ 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; +pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; use pallet_staking::UseValidatorsMap; @@ -382,6 +382,8 @@ parameter_types! { // 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. @@ -456,7 +458,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SignedMaxSubmissions = SignedMaxSubmissions; type SignedMaxRefunds = SignedMaxRefunds; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = + GeometricDepositBase; type SignedDepositByte = SignedDepositByte; type SignedDepositWeight = (); type SignedMaxWeight = @@ -2352,7 +2355,7 @@ mod test_fees { 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 = SignedDepositBase::get() + (SignedDepositByte::get() * 1024 * 1024); + let deposit = SignedFixedDeposit::get() + (SignedDepositByte::get() * 1024 * 1024); assert_eq_error_rate!(deposit, 50 * DOLLARS, DOLLARS); } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9a7e7c4548c..5cb6cbbab20 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -79,7 +79,7 @@ use sp_runtime::{ Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, }; use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -90,7 +90,7 @@ 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; +pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; use pallet_staking::UseValidatorsMap; @@ -481,7 +481,8 @@ parameter_types! { // signed config pub const SignedMaxSubmissions: u32 = 128; pub const SignedMaxRefunds: u32 = 128 / 4; - pub const SignedDepositBase: Balance = deposit(2, 0); + 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 WND as reward pub SignedRewardBase: Balance = 1 * UNITS; @@ -553,7 +554,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SignedMaxSubmissions = SignedMaxSubmissions; type SignedMaxRefunds = SignedMaxRefunds; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = + GeometricDepositBase; type SignedDepositByte = SignedDepositByte; type SignedDepositWeight = (); type SignedMaxWeight = diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a97f2b09118..df8fb06467d 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -58,7 +58,7 @@ pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; -use pallet_election_provider_multi_phase::SolutionAccuracyOf; +use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; @@ -694,7 +694,8 @@ parameter_types! { // signed config pub const SignedRewardBase: Balance = 1 * DOLLARS; - pub const SignedDepositBase: Balance = 1 * DOLLARS; + pub const SignedFixedDeposit: Balance = 1 * DOLLARS; + pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); pub const SignedDepositByte: Balance = 1 * CENTS; pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(1u32, 10_000); @@ -822,7 +823,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type MinerConfig = Self; type SignedMaxSubmissions = ConstU32<10>; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = + GeometricDepositBase; type SignedDepositByte = SignedDepositByte; type SignedMaxRefunds = ConstU32<3>; type SignedDepositWeight = (); diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 0d751e3f9cb..8b6e0827c71 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -279,8 +279,8 @@ use unsigned::VoterOf; pub use weights::WeightInfo; pub use signed::{ - BalanceOf, NegativeImbalanceOf, PositiveImbalanceOf, SignedSubmission, SignedSubmissionOf, - SignedSubmissions, SubmissionIndicesOf, + BalanceOf, GeometricDepositBase, NegativeImbalanceOf, PositiveImbalanceOf, SignedSubmission, + SignedSubmissionOf, SignedSubmissions, SubmissionIndicesOf, }; pub use unsigned::{Miner, MinerConfig}; @@ -572,6 +572,7 @@ pub mod pallet { use frame_election_provider_support::{InstantElectionProvider, NposSolver}; use frame_support::{pallet_prelude::*, traits::EstimateCallFee}; use frame_system::pallet_prelude::*; + use sp_runtime::traits::Convert; #[pallet::config] pub trait Config: frame_system::Config + SendTransactionTypes> { @@ -649,10 +650,6 @@ pub mod pallet { #[pallet::constant] type SignedRewardBase: Get>; - /// Base deposit for a signed solution. - #[pallet::constant] - type SignedDepositBase: Get>; - /// Per-byte deposit for a signed solution. #[pallet::constant] type SignedDepositByte: Get>; @@ -668,6 +665,10 @@ pub mod pallet { #[pallet::constant] type MaxWinners: Get; + /// Something that calculates the signed deposit base based on the signed submissions queue + /// size. + type SignedDepositBase: Convert>; + /// The maximum number of electing voters and electable targets to put in the snapshot. /// At the moment, snapshots are only over a single block, but once multi-block elections /// are introduced they will take place over multiple blocks. diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 05d151e51ec..d4659eba566 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -16,7 +16,7 @@ // limitations under the License. use super::*; -use crate::{self as multi_phase, unsigned::MinerConfig}; +use crate::{self as multi_phase, signed::GeometricDepositBase, unsigned::MinerConfig}; use frame_election_provider_support::{ bounds::{DataProviderBounds, ElectionBounds}, data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, @@ -44,8 +44,8 @@ use sp_npos_elections::{ use sp_runtime::{ bounded_vec, testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, PerU16, + traits::{BlakeTwo256, Convert, IdentityLookup}, + BuildStorage, PerU16, Percent, }; use std::sync::Arc; @@ -283,7 +283,11 @@ parameter_types! { pub static UnsignedPhase: BlockNumber = 5; pub static SignedMaxSubmissions: u32 = 5; pub static SignedMaxRefunds: u32 = 1; - pub static SignedDepositBase: Balance = 5; + // for tests only. if `EnableVariableDepositBase` is true, the deposit base will be calculated + // by `Multiphase::DepositBase`. Otherwise the deposit base is `SignedFixedDeposit`. + pub static EnableVariableDepositBase: bool = false; + pub static SignedFixedDeposit: Balance = 5; + pub static SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); pub static SignedDepositByte: Balance = 0; pub static SignedDepositWeight: Balance = 0; pub static SignedRewardBase: Balance = 7; @@ -393,7 +397,7 @@ impl crate::Config for Runtime { type OffchainRepeat = OffchainRepeat; type MinerTxPriority = MinerTxPriority; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = Self; type SignedDepositByte = (); type SignedDepositWeight = (); type SignedMaxWeight = SignedMaxWeight; @@ -414,6 +418,18 @@ impl crate::Config for Runtime { type ElectionBounds = ElectionsBounds; } +impl Convert> for Runtime { + /// returns the geometric increase deposit fee if `EnableVariableDepositBase` is set, otherwise + /// the fee is `SignedFixedDeposit`. + fn convert(queue_len: usize) -> Balance { + if !EnableVariableDepositBase::get() { + SignedFixedDeposit::get() + } else { + GeometricDepositBase::::convert(queue_len) + } + } +} + impl frame_system::offchain::SendTransactionTypes for Runtime where RuntimeCall: From, @@ -553,8 +569,14 @@ impl ExtBuilder { ::set(count); self } + pub fn signed_base_deposit(self, base: u64, variable: bool, increase: Percent) -> Self { + ::set(variable); + ::set(base); + ::set(increase); + self + } pub fn signed_deposit(self, base: u64, byte: u64, weight: u64) -> Self { - ::set(base); + ::set(base); ::set(byte); ::set(weight); self diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index 76068ba99d3..a5fe8ce5558 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -17,6 +17,8 @@ //! The signed phase implementation. +use core::marker::PhantomData; + use crate::{ unsigned::MinerConfig, Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, ReadySolution, SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, @@ -32,8 +34,8 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_core::bounded::BoundedVec; use sp_npos_elections::ElectionScore; use sp_runtime::{ - traits::{Saturating, Zero}, - RuntimeDebug, + traits::{Convert, Saturating, Zero}, + FixedPointNumber, FixedPointOperand, FixedU128, Percent, RuntimeDebug, }; use sp_std::{ cmp::Ordering, @@ -348,6 +350,32 @@ impl SignedSubmissions { } } +/// Type that can be used to calculate the deposit base for signed submissions. +/// +/// The deposit base is calculated as a geometric progression based on the number of signed +/// submissions in the queue. The size of the queue represents the progression term. +pub struct GeometricDepositBase { + _marker: (PhantomData, PhantomData, PhantomData), +} + +impl Convert for GeometricDepositBase +where + Balance: FixedPointOperand, + Fixed: Get, + Inc: Get, +{ + // Calculates the base deposit as a geometric progression based on the number of signed + // submissions. + // + // The nth term is obtained by calculating `base * (1 + increase_factor)^nth`. Example: factor + // 5, with initial deposit of 1000 and 10% of increase factor is 1000 * (1 + 0.1)^5. + fn convert(queue_len: usize) -> Balance { + let increase_factor: FixedU128 = FixedU128::from_u32(1) + Inc::get().into(); + + increase_factor.saturating_pow(queue_len).saturating_mul_int(Fixed::get()) + } +} + impl Pallet { /// `Self` accessor for `SignedSubmission`. pub fn signed_submissions() -> SignedSubmissions { @@ -520,14 +548,14 @@ impl Pallet { size: SolutionOrSnapshotSize, ) -> BalanceOf { let encoded_len: u32 = raw_solution.encoded_size().saturated_into(); - let encoded_len: BalanceOf = encoded_len.into(); + let encoded_len_balance: BalanceOf = encoded_len.into(); let feasibility_weight = Self::solution_weight_of(raw_solution, size); - let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len); + let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len_balance); let weight_deposit = T::SignedDepositWeight::get() .saturating_mul(feasibility_weight.ref_time().saturated_into()); - T::SignedDepositBase::get() + T::SignedDepositBase::convert(Self::signed_submissions().len()) .saturating_add(len_deposit) .saturating_add(weight_deposit) } @@ -541,6 +569,7 @@ mod tests { Phase, }; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; + use sp_runtime::Percent; #[test] fn cannot_submit_too_early() { @@ -779,6 +808,56 @@ mod tests { }) } + #[test] + fn geometric_deposit_queue_size_works() { + let constant = vec![1000; 10]; + // geometric progression with 10% increase in each iteration for 10 terms. + let progression_10 = vec![1000, 1100, 1210, 1331, 1464, 1610, 1771, 1948, 2143, 2357]; + let progression_40 = vec![1000, 1400, 1960, 2744, 3841, 5378, 7529, 10541, 14757, 20661]; + + let check_progressive_base_fee = |expected: &Vec| { + for s in 0..SignedMaxSubmissions::get() { + let account = 99 + s as u64; + Balances::make_free_balance_be(&account, 10000000); + let mut solution = raw_solution(); + solution.score.minimal_stake -= s as u128; + + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(account), Box::new(solution))); + assert_eq!(balances(&account).1, expected[s as usize]) + } + }; + + ExtBuilder::default() + .signed_max_submission(10) + .signed_base_deposit(1000, true, Percent::from_percent(0)) + .build_and_execute(|| { + roll_to_signed(); + assert!(MultiPhase::current_phase().is_signed()); + + check_progressive_base_fee(&constant); + }); + + ExtBuilder::default() + .signed_max_submission(10) + .signed_base_deposit(1000, true, Percent::from_percent(10)) + .build_and_execute(|| { + roll_to_signed(); + assert!(MultiPhase::current_phase().is_signed()); + + check_progressive_base_fee(&progression_10); + }); + + ExtBuilder::default() + .signed_max_submission(10) + .signed_base_deposit(1000, true, Percent::from_percent(40)) + .build_and_execute(|| { + roll_to_signed(); + assert!(MultiPhase::current_phase().is_signed()); + + check_progressive_base_fee(&progression_40); + }); + } + #[test] fn call_fee_refund_is_limited_by_signed_max_refunds() { ExtBuilder::default().build_and_execute(|| { 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 501f9f89ab7..ec646c31197 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 @@ -32,7 +32,7 @@ use sp_runtime::{ }, testing, traits::Zero, - transaction_validity, BuildStorage, PerU16, Perbill, + transaction_validity, BuildStorage, PerU16, Perbill, Percent, }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, @@ -47,7 +47,8 @@ use frame_election_provider_support::{ SequentialPhragmen, Weight, }; use pallet_election_provider_multi_phase::{ - unsigned::MinerConfig, Call, ElectionCompute, QueuedSolution, SolutionAccuracyOf, + unsigned::MinerConfig, Call, ElectionCompute, GeometricDepositBase, QueuedSolution, + SolutionAccuracyOf, }; use pallet_staking::StakerStatus; use parking_lot::RwLock; @@ -182,6 +183,9 @@ parameter_types! { pub static TransactionPriority: transaction_validity::TransactionPriority = 1; #[derive(Debug)] pub static MaxWinners: u32 = 100; + pub static MaxVotesPerVoter: u32 = 16; + pub static SignedFixedDeposit: Balance = 1; + pub static SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); pub static ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = ElectionBoundsBuilder::default() .voters_count(1_000.into()).targets_count(1_000.into()).build(); } @@ -199,7 +203,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type MinerConfig = Self; type SignedMaxSubmissions = ConstU32<10>; type SignedRewardBase = (); - type SignedDepositBase = (); + type SignedDepositBase = + GeometricDepositBase; type SignedDepositByte = (); type SignedMaxRefunds = ConstU32<3>; type SignedDepositWeight = (); -- GitLab From e05d3690bc6c2c1f5abc05a378753eda9e0fdaec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:51:48 +0200 Subject: [PATCH 169/633] Bump docker/setup-buildx-action from 2.1.0 to 3.0.0 (#1551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2.1.0 to 3.0.0.
Release notes

Sourced from docker/setup-buildx-action's releases.

v3.0.0

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.10.0...v3.0.0

v2.10.0

What's Changed

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.9.1...v2.10.0

v2.9.1

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.9.0...v2.9.1

v2.9.0

  • Bump @​docker/actions-toolkit from 0.6.0 to 0.7.0 in docker/setup-buildx-action#246
    • Adds support to cache Buildx binary to hosted tool cache and GHA cache backend

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.8.0...v2.9.0

v2.8.0

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.7.0...v2.8.0

v2.7.0

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.6.0...v2.7.0

v2.6.0

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.5.0...v2.6.0

v2.5.0

Full Changelog: https://github.com/docker/setup-buildx-action/compare/v2.4.1...v2.5.0

v2.4.1

... (truncated)

Commits
  • f95db51 Merge pull request #267 from docker/dependabot/npm_and_yarn/actions/core-1.10.1
  • 998a87c chore: update generated content
  • 28bae59 build(deps): bump @​actions/core from 1.10.0 to 1.10.1
  • c215341 Merge pull request #264 from crazy-max/update-node20
  • 02e9319 chore: node 20 as default runtime
  • 5c9160e chore: update generated content
  • 1283140 chore: fix author in package.json
  • c6afe06 vendor: bump @​docker/actions-toolkit from 0.10.0 to 0.12.0
  • f35e0d5 chore: update dev dependencies
  • baeb468 dev: remove unneeded binaries
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/setup-buildx-action&package-manager=github_actions&previous-version=2.1.0&new-version=3.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-50_publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 04b3ebd3e79..5cfe53e641d 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -242,7 +242,7 @@ jobs: uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # v2.1.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Cache Docker layers uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 -- GitLab From 519a0f0688d8740c7944bdb7986a540cbf7e3917 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 18 Sep 2023 11:56:35 +0200 Subject: [PATCH 170/633] Replace secrets with the new ones (#1564) In the monorepo, secrets used in the various previous repos have been renamed into: - `CUMULUS_DOCKERHUB_USERNAME` - `CUMULUS_DOCKERHUB_TOKEN` - `POLKADOT_DOCKERHUB_USERNAME` - `POLKADOT_DOCKERHUB_TOKEN` This PR makes those changes and remove one of the GHW that has now been updated for the monorepo. --- .../workflows/release-50_publish-docker.yml | 8 ++-- .../release-50_publish-docker-release.yml | 44 ------------------- 2 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 polkadot/.github/workflows/release-50_publish-docker-release.yml diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 5cfe53e641d..535f54abc68 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -198,8 +198,8 @@ jobs: - name: Login to Dockerhub uses: docker/login-action@v2 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ secrets.CUMULUS_DOCKERHUB_USERNAME }} + password: ${{ secrets.CUMULUS_DOCKERHUB_TOKEN }} - name: Push Container image for ${{ env.BINARY }} id: docker_push @@ -255,8 +255,8 @@ jobs: - name: Login to Docker Hub uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ secrets.POLKADOT_DOCKERHUB_USERNAME }} + password: ${{ secrets.POLKADOT_DOCKERHUB_TOKEN }} - name: Fetch values id: fetch-data diff --git a/polkadot/.github/workflows/release-50_publish-docker-release.yml b/polkadot/.github/workflows/release-50_publish-docker-release.yml deleted file mode 100644 index 81e5caa718f..00000000000 --- a/polkadot/.github/workflows/release-50_publish-docker-release.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Release - Publish Docker image for new releases - -on: - release: - types: - - published - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # v2.1.0 - - name: Cache Docker layers - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - name: Login to Dockerhub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push - id: docker_build - uses: docker/build-push-action@v4 - with: - push: true - file: scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile - tags: | - parity/polkadot:latest - parity/polkadot:${{ github.event.release.tag_name }} - build-args: | - POLKADOT_VERSION=${{ github.event.release.tag_name }} - VCS_REF=${{ github.ref }} - BUILD_DATE=${{ github.event.release.published_at }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} -- GitLab From f14bf347e8c89744ff6b4b8e76548d1137dc9c34 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:02:15 +0200 Subject: [PATCH 171/633] Broker pallet: `RegionDropped` event fix & additional tests (#1609) This PR includes the following fix: - [x] The `duration` is always set to zero in the `RegionDropped` event. This is fixed in this PR. Also added some additional tests to cover some cases that aren't covered : - [x] Selling a partitioned region to the instantaneous coretime pool. - [x] Partitioning a region after assigning it to a particular task. - [x] Interlacing a region after assigning it to a particular task. --- .../frame/broker/src/dispatchable_impls.rs | 4 +- substrate/frame/broker/src/tests.rs | 119 +++++++++++++++++- substrate/frame/broker/src/utility_impls.rs | 2 +- 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index 54cf5d71dca..0b08a7b665b 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -76,7 +76,7 @@ impl Pallet { last_timeslice: Self::current_timeslice(), }; let now = frame_system::Pallet::::block_number(); - let dummy_sale = SaleInfoRecord { + let new_sale = SaleInfoRecord { sale_start: now, leadin_length: Zero::zero(), price, @@ -89,7 +89,7 @@ impl Pallet { cores_sold: 0, }; Self::deposit_event(Event::::SalesStarted { price, core_count }); - Self::rotate_sale(dummy_sale, &config, &status); + Self::rotate_sale(new_sale, &config, &status); Status::::put(&status); Ok(()) } diff --git a/substrate/frame/broker/src/tests.rs b/substrate/frame/broker/src/tests.rs index 3c326010ddd..e1b489bbe6e 100644 --- a/substrate/frame/broker/src/tests.rs +++ b/substrate/frame/broker/src/tests.rs @@ -77,7 +77,9 @@ fn drop_renewal_works() { let e = Error::::StillValid; assert_noop!(Broker::do_drop_renewal(region.core, region.begin + 3), e); advance_to(12); + assert_eq!(AllowedRenewals::::iter().count(), 1); assert_ok!(Broker::do_drop_renewal(region.core, region.begin + 3)); + assert_eq!(AllowedRenewals::::iter().count(), 0); let e = Error::::UnknownRenewal; assert_noop!(Broker::do_drop_renewal(region.core, region.begin + 3), e); }); @@ -90,7 +92,10 @@ fn drop_contribution_works() { advance_to(2); let region = Broker::do_purchase(1, u64::max_value()).unwrap(); // Place region in pool. Active in pool timeslices 4, 5, 6 = rcblocks 8, 10, 12; we - // expect the contribution record to timeout 3 timeslices following 7 = 10 + // expect the contribution record to timeout 3 timeslices following 7 = 14 + // + // Due to the contribution_timeout being configured for 3 timeslices, the contribution + // can only be discarded at timeslice 10, i.e. rcblock 20. assert_ok!(Broker::do_pool(region, Some(1), 1, Final)); assert_eq!(InstaPoolContribution::::iter().count(), 1); advance_to(19); @@ -378,6 +383,41 @@ fn instapool_partial_core_payouts_work() { }); } +#[test] +fn instapool_core_payouts_work_with_partitioned_region() { + TestExt::new().endow(1, 1000).execute_with(|| { + assert_ok!(Broker::do_start_sales(100, 1)); + advance_to(2); + let region = Broker::do_purchase(1, u64::max_value()).unwrap(); + let (region1, region2) = Broker::do_partition(region, None, 2).unwrap(); + // `region1` duration is from rcblock 8 to rcblock 12. This means that the + // coretime purchased during this time period will be purchased from `region1` + // + // `region2` duration is from rcblock 12 to rcblock 14 and during this period + // coretime will be purchased from `region2`. + assert_ok!(Broker::do_pool(region1, None, 2, Final)); + assert_ok!(Broker::do_pool(region2, None, 3, Final)); + assert_ok!(Broker::do_purchase_credit(1, 20, 1)); + advance_to(8); + assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10)); + advance_to(11); + assert_eq!(pot(), 20); + assert_eq!(revenue(), 100); + assert_ok!(Broker::do_claim_revenue(region1, 100)); + assert_eq!(pot(), 10); + assert_eq!(balance(2), 10); + advance_to(12); + assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10)); + advance_to(15); + assert_eq!(pot(), 10); + assert_ok!(Broker::do_claim_revenue(region2, 100)); + assert_eq!(pot(), 0); + // The balance of account `2` remains unchanged. + assert_eq!(balance(2), 10); + assert_eq!(balance(3), 10); + }); +} + #[test] fn initialize_with_system_paras_works() { TestExt::new().execute_with(|| { @@ -654,6 +694,79 @@ fn partition_then_interlace_works() { }); } +#[test] +fn partitioning_after_assignment_works() { + TestExt::new().endow(1, 1000).execute_with(|| { + assert_ok!(Broker::do_start_sales(100, 1)); + advance_to(2); + // We will initially allocate a task to a purchased region, and after that + // we will proceed to partition the region. + let region = Broker::do_purchase(1, u64::max_value()).unwrap(); + assert_ok!(Broker::do_assign(region, None, 1001, Provisional)); + let (_region, region1) = Broker::do_partition(region, None, 2).unwrap(); + // After the partitioning if we assign a new task to `region` the other region + // will still be assigned to `Task(1001)`. + assert_ok!(Broker::do_assign(region1, None, 1002, Provisional)); + advance_to(10); + assert_eq!( + CoretimeTrace::get(), + vec![ + ( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(Task(1001), 57600),], + end_hint: None + } + ), + ( + 10, + AssignCore { + core: 0, + begin: 12, + assignment: vec![(Task(1002), 57600),], + end_hint: None + } + ), + ] + ); + }); +} + +#[test] +fn interlacing_after_assignment_works() { + TestExt::new().endow(1, 1000).execute_with(|| { + assert_ok!(Broker::do_start_sales(100, 1)); + advance_to(2); + // We will initially allocate a task to a purchased region, and after that + // we will proceed to interlace the region. + let region = Broker::do_purchase(1, u64::max_value()).unwrap(); + assert_ok!(Broker::do_assign(region, None, 1001, Provisional)); + let (region1, _region) = + Broker::do_interlace(region, None, CoreMask::from_chunk(0, 40)).unwrap(); + // Interlacing the region won't affect the assignment. The entire region will still + // be assigned to `Task(1001)`. + // + // However, after we assign a task to `region1` the `_region` won't be assigned + // to `Task(1001)` anymore. It will become idle. + assert_ok!(Broker::do_assign(region1, None, 1002, Provisional)); + advance_to(10); + assert_eq!( + CoretimeTrace::get(), + vec![( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(Idle, 28800), (Task(1002), 28800)], + end_hint: None + } + ),] + ); + }); +} + #[test] fn reservations_are_limited() { TestExt::new().execute_with(|| { @@ -866,7 +979,7 @@ fn assign_should_drop_invalid_region() { advance_to(10); assert_ok!(Broker::do_assign(region, Some(1), 1001, Provisional)); region.begin = 7; - System::assert_last_event(Event::RegionDropped { region_id: region, duration: 0 }.into()); + System::assert_last_event(Event::RegionDropped { region_id: region, duration: 3 }.into()); }); } @@ -879,7 +992,7 @@ fn pool_should_drop_invalid_region() { advance_to(10); assert_ok!(Broker::do_pool(region, Some(1), 1001, Provisional)); region.begin = 7; - System::assert_last_event(Event::RegionDropped { region_id: region, duration: 0 }.into()); + System::assert_last_event(Event::RegionDropped { region_id: region, duration: 3 }.into()); }); } diff --git a/substrate/frame/broker/src/utility_impls.rs b/substrate/frame/broker/src/utility_impls.rs index 99c4de32f77..2450198050b 100644 --- a/substrate/frame/broker/src/utility_impls.rs +++ b/substrate/frame/broker/src/utility_impls.rs @@ -101,9 +101,9 @@ impl Pallet { let last_committed_timeslice = status.last_committed_timeslice; if region_id.begin <= last_committed_timeslice { + let duration = region.end.saturating_sub(region_id.begin); region_id.begin = last_committed_timeslice + 1; if region_id.begin >= region.end { - let duration = region.end.saturating_sub(region_id.begin); Self::deposit_event(Event::RegionDropped { region_id, duration }); return Ok(None) } -- GitLab From a50e6ba7af50a4be9ae78ebb90e86a61f3dd85e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:18:49 +0200 Subject: [PATCH 172/633] Bump docker/login-action from 2 to 3 (#1531) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
Release notes

Sourced from docker/login-action's releases.

v3.0.0

Full Changelog: https://github.com/docker/login-action/compare/v2.2.0...v3.0.0

v2.2.0

Full Changelog: https://github.com/docker/login-action/compare/v2.1.0...v2.2.0

v2.1.0

  • Ensure AWS temp credentials are redacted in workflow logs by @​crazy-max (#275)
  • Bump @​actions/core from 1.6.0 to 1.10.0 (#252 #292)
  • Bump @​aws-sdk/client-ecr from 3.53.0 to 3.186.0 (#298)
  • Bump @​aws-sdk/client-ecr-public from 3.53.0 to 3.186.0 (#299)

Full Changelog: https://github.com/docker/login-action/compare/v2.0.0...v2.1.0

Commits
  • 343f7c4 Merge pull request #599 from docker/dependabot/npm_and_yarn/aws-sdk-dependenc...
  • aad0f97 chore: update generated content
  • 2e0cd39 build(deps): bump the aws-sdk-dependencies group with 2 updates
  • 203bc9c Merge pull request #588 from docker/dependabot/npm_and_yarn/proxy-agent-depen...
  • 2199648 chore: update generated content
  • b489376 build(deps): bump the proxy-agent-dependencies group with 1 update
  • 7c309e7 Merge pull request #598 from docker/dependabot/npm_and_yarn/actions/core-1.10.1
  • 0ccf222 chore: update generated content
  • 56d703e Merge pull request #597 from docker/dependabot/github_actions/aws-actions/con...
  • 24d3b35 build(deps): bump @​actions/core from 1.10.0 to 1.10.1
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/login-action&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> --- .github/workflows/release-50_publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 535f54abc68..e787d83616f 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -196,7 +196,7 @@ jobs: ./docker/scripts/build-injected.sh - name: Login to Dockerhub - uses: docker/login-action@v2 + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 with: username: ${{ secrets.CUMULUS_DOCKERHUB_USERNAME }} password: ${{ secrets.CUMULUS_DOCKERHUB_TOKEN }} -- GitLab From 20052e1675f96fb25d5b19c26a4e1d5e7425e724 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:37:38 +0200 Subject: [PATCH 173/633] Bump docker/build-push-action from 4 to 5 (#1552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
Release notes

Sourced from docker/build-push-action's releases.

v5.0.0

Full Changelog: https://github.com/docker/build-push-action/compare/v4.2.1...v5.0.0

v4.2.1

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.2.0...v4.2.1

v4.2.0

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.1.1...v4.2.0

v4.1.1

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.1.0...v4.1.1

v4.1.0

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.0.0...v4.1.0

Commits
  • 0565240 Merge pull request #959 from docker/dependabot/npm_and_yarn/actions/core-1.10.1
  • 3ab07f8 chore: update generated content
  • b9e7e4d chore(deps): Bump @​actions/core from 1.10.0 to 1.10.1
  • 04d1a3b Merge pull request #954 from crazy-max/update-node20
  • 1a4d1a1 chore: node 20 as default runtime
  • 675965c chore: update generated content
  • 58ee34c chore: fix author in package.json
  • c97c406 fix ProxyConfig type when checking length
  • 47d5369 vendor: bump @​docker/actions-toolkit from 0.8.0 to 0.12.0
  • 8895c74 chore: update dev dependencies
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Chevdor --- .github/workflows/release-50_publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index e787d83616f..d01d78631e1 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -266,7 +266,7 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile -- GitLab From 5d346643ca0d1b6d9ddcfb2d01e490858ce4cb0e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Mon, 18 Sep 2023 13:54:44 +0300 Subject: [PATCH 174/633] chainHead: Add support for storage closest merkle descendant #14818 (#1153) This PR adds support for fetching the closest merkle value of some key. Builds on top of - https://github.com/paritytech/trie/pull/199 Migrates https://github.com/paritytech/substrate/pull/14818 to the monorepo. Closes: https://github.com/paritytech/substrate/issues/14550 Closes: https://github.com/paritytech/polkadot-sdk/issues/1506 // @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Sebastian Kunert --- Cargo.lock | 1 + substrate/client/api/Cargo.toml | 1 + substrate/client/api/src/backend.rs | 16 ++ substrate/client/db/src/bench.rs | 23 ++- substrate/client/db/src/lib.rs | 17 +- substrate/client/db/src/record_stats_state.rs | 16 ++ .../rpc-spec-v2/src/chain_head/chain_head.rs | 17 +- .../src/chain_head/chain_head_storage.rs | 40 +++- .../rpc-spec-v2/src/chain_head/test_utils.rs | 21 +- .../rpc-spec-v2/src/chain_head/tests.rs | 190 +++++++++++++++++- substrate/client/service/src/client/client.rs | 23 ++- .../primitives/state-machine/src/backend.rs | 14 +- .../state-machine/src/trie_backend.rs | 14 +- .../state-machine/src/trie_backend_essence.rs | 42 +++- substrate/primitives/trie/src/lib.rs | 42 +++- 15 files changed, 449 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f09db7643e0..ea4cf4a1817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14641,6 +14641,7 @@ dependencies = [ "sp-statement-store", "sp-storage", "sp-test-primitives", + "sp-trie", "substrate-prometheus-endpoint", "substrate-test-runtime", "thiserror", diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index b59149424ed..2b64c86038d 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -35,6 +35,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-state-machine = { path = "../../primitives/state-machine" } sp-statement-store = { path = "../../primitives/statement-store" } sp-storage = { path = "../../primitives/storage" } +sp-trie = { path = "../../primitives/trie" } [dev-dependencies] thiserror = "1.0.48" diff --git a/substrate/client/api/src/backend.rs b/substrate/client/api/src/backend.rs index 2d8fdef77cd..31b100433c7 100644 --- a/substrate/client/api/src/backend.rs +++ b/substrate/client/api/src/backend.rs @@ -33,6 +33,7 @@ use sp_state_machine::{ OffchainChangesCollection, StorageCollection, StorageIterator, }; use sp_storage::{ChildInfo, StorageData, StorageKey}; +pub use sp_trie::MerkleValue; use crate::{blockchain::Backend as BlockchainBackend, UsageInfo}; @@ -470,6 +471,21 @@ pub trait StorageProvider> { child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; + + /// Given a block's `Hash` and a key, return the closest merkle value. + fn closest_merkle_value( + &self, + hash: Block::Hash, + key: &StorageKey, + ) -> sp_blockchain::Result>>; + + /// Given a block's `Hash`, a key and a child storage key, return the closest merkle value. + fn child_closest_merkle_value( + &self, + hash: Block::Hash, + child_info: &ChildInfo, + key: &StorageKey, + ) -> sp_blockchain::Result>>; } /// Client backend. diff --git a/substrate/client/db/src/bench.rs b/substrate/client/db/src/bench.rs index 38c37a42ede..03ad4817b53 100644 --- a/substrate/client/db/src/bench.rs +++ b/substrate/client/db/src/bench.rs @@ -37,7 +37,7 @@ use sp_state_machine::{ }; use sp_trie::{ cache::{CacheSize, SharedTrieCache}, - prefixed_key, MemoryDB, + prefixed_key, MemoryDB, MerkleValue, }; use std::{ cell::{Cell, RefCell}, @@ -382,6 +382,27 @@ impl StateBackend> for BenchmarkingState { .child_storage_hash(child_info, key) } + fn closest_merkle_value( + &self, + key: &[u8], + ) -> Result>, Self::Error> { + self.add_read_key(None, key); + self.state.borrow().as_ref().ok_or_else(state_err)?.closest_merkle_value(key) + } + + fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + self.add_read_key(None, key); + self.state + .borrow() + .as_ref() + .ok_or_else(state_err)? + .child_closest_merkle_value(child_info, key) + } + fn exists_storage(&self, key: &[u8]) -> Result { self.add_read_key(None, key); self.state.borrow().as_ref().ok_or_else(state_err)?.exists_storage(key) diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index 73fb4f8ce6d..194bec8a88e 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -90,7 +90,7 @@ use sp_state_machine::{ OffchainChangesCollection, StateMachineStats, StorageCollection, StorageIterator, StorageKey, StorageValue, UsageInfo as StateUsageInfo, }; -use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, PrefixedMemoryDB}; +use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, MerkleValue, PrefixedMemoryDB}; // Re-export the Database trait so that one can pass an implementation of it. pub use sc_state_db::PruningMode; @@ -214,6 +214,21 @@ impl StateBackend> for RefTrackingState { self.state.child_storage_hash(child_info, key) } + fn closest_merkle_value( + &self, + key: &[u8], + ) -> Result>, Self::Error> { + self.state.closest_merkle_value(key) + } + + fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + self.state.child_closest_merkle_value(child_info, key) + } + fn exists_storage(&self, key: &[u8]) -> Result { self.state.exists_storage(key) } diff --git a/substrate/client/db/src/record_stats_state.rs b/substrate/client/db/src/record_stats_state.rs index 29ece84f97e..d9a35c075d7 100644 --- a/substrate/client/db/src/record_stats_state.rs +++ b/substrate/client/db/src/record_stats_state.rs @@ -28,6 +28,7 @@ use sp_state_machine::{ backend::{AsTrieBackend, Backend as StateBackend}, BackendTransaction, IterArgs, StorageIterator, StorageKey, StorageValue, TrieBackend, }; +use sp_trie::MerkleValue; use std::sync::Arc; /// State abstraction for recording stats about state access. @@ -144,6 +145,21 @@ impl>, B: BlockT> StateBackend> self.state.child_storage_hash(child_info, key) } + fn closest_merkle_value( + &self, + key: &[u8], + ) -> Result>, Self::Error> { + self.state.closest_merkle_value(key) + } + + fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + self.state.child_closest_merkle_value(child_info, key) + } + fn exists_storage(&self, key: &[u8]) -> Result { self.state.exists_storage(key) } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 14364c331e6..a8c1c4f7e08 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -27,7 +27,7 @@ use crate::{ api::ChainHeadApiServer, chain_head_follow::ChainHeadFollower, error::Error as ChainHeadRpcError, - event::{FollowEvent, MethodResponse, OperationError, StorageQuery, StorageQueryType}, + event::{FollowEvent, MethodResponse, OperationError, StorageQuery}, hex_string, subscription::{SubscriptionManagement, SubscriptionManagementError}, }, @@ -329,19 +329,10 @@ where let items = items .into_iter() .map(|query| { - if query.query_type == StorageQueryType::ClosestDescendantMerkleValue { - // Note: remove this once all types are implemented. - return Err(ChainHeadRpcError::InvalidParam( - "Storage query type not supported".into(), - )) - } - - Ok(StorageQuery { - key: StorageKey(parse_hex_param(query.key)?), - query_type: query.query_type, - }) + let key = StorageKey(parse_hex_param(query.key)?); + Ok(StorageQuery { key, query_type: query.query_type }) }) - .collect::, _>>()?; + .collect::, ChainHeadRpcError>>()?; let child_trie = child_trie .map(|child_trie| parse_hex_param(child_trie)) 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 48a673f47e3..7095548a2b1 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 @@ -145,6 +145,36 @@ where .unwrap_or_else(|error| QueryResult::Err(error.to_string())) } + /// Fetch the closest merkle value. + fn query_storage_merkle_value( + &self, + hash: Block::Hash, + key: &StorageKey, + child_key: Option<&ChildInfo>, + ) -> QueryResult { + let result = if let Some(child_key) = child_key { + self.client.child_closest_merkle_value(hash, child_key, key) + } else { + self.client.closest_merkle_value(hash, key) + }; + + result + .map(|opt| { + QueryResult::Ok(opt.map(|storage_data| { + let result = match &storage_data { + sc_client_api::MerkleValue::Node(data) => hex_string(&data.as_slice()), + sc_client_api::MerkleValue::Hash(hash) => hex_string(&hash.as_ref()), + }; + + StorageResult { + key: hex_string(&key.0), + result: StorageResultType::ClosestDescendantMerkleValue(result), + } + })) + }) + .unwrap_or_else(|error| QueryResult::Err(error.to_string())) + } + /// Iterate over at most `operation_max_storage_items` keys. /// /// Returns the storage result with a potential next key to resume iteration. @@ -286,13 +316,21 @@ where return }, }, + StorageQueryType::ClosestDescendantMerkleValue => + match self.query_storage_merkle_value(hash, &item.key, child_key.as_ref()) { + Ok(Some(value)) => storage_results.push(value), + Ok(None) => continue, + Err(error) => { + send_error::(&sender, operation.operation_id(), error); + 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 }), - _ => continue, }; } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs index 6e92e87608b..a901f3039ff 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs @@ -20,8 +20,8 @@ use parking_lot::Mutex; use sc_client_api::{ execution_extensions::ExecutionExtensions, BlockBackend, BlockImportNotification, BlockchainEvents, CallExecutor, ChildInfo, ExecutorProvider, FinalityNotification, - FinalityNotifications, FinalizeSummary, ImportNotifications, KeysIter, PairsIter, StorageData, - StorageEventStream, StorageKey, StorageProvider, + FinalityNotifications, FinalizeSummary, ImportNotifications, KeysIter, MerkleValue, PairsIter, + StorageData, StorageEventStream, StorageKey, StorageProvider, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_api::{CallApiAt, CallApiAtParams, NumberFor, RuntimeVersion}; @@ -198,6 +198,23 @@ impl< ) -> sp_blockchain::Result> { self.client.child_storage_hash(hash, child_info, key) } + + fn closest_merkle_value( + &self, + hash: Block::Hash, + key: &StorageKey, + ) -> sp_blockchain::Result>> { + self.client.closest_merkle_value(hash, key) + } + + fn child_closest_merkle_value( + &self, + hash: Block::Hash, + child_info: &ChildInfo, + key: &StorageKey, + ) -> sp_blockchain::Result>> { + self.client.child_closest_merkle_value(hash, child_info, key) + } } impl> CallApiAt for ChainHeadMockClient { 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 1336cff84b6..3ab47991c4e 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -43,7 +43,12 @@ use sp_core::{ Blake2Hasher, Hasher, }; use sp_version::RuntimeVersion; -use std::{collections::HashSet, fmt::Debug, sync::Arc, time::Duration}; +use std::{ + collections::{HashMap, HashSet}, + fmt::Debug, + sync::Arc, + time::Duration, +}; use substrate_test_runtime::Transfer; use substrate_test_runtime_client::{ prelude::*, runtime, runtime::RuntimeApi, Backend, BlockBuilderExt, Client, @@ -2583,3 +2588,186 @@ async fn stop_storage_operation() { ) .await; } + +#[tokio::test] +async fn storage_closest_merkle_value() { + let (mut client, api, mut sub, sub_id, _) = setup_api().await; + + /// The core of this test. + /// + /// Checks keys that are exact match, keys with descedant and keys that should not return + /// values. + /// + /// Returns (key, merkle value) pairs. + async fn expect_merkle_request( + api: &RpcModule>>, + mut sub: &mut RpcSubscription, + sub_id: String, + block_hash: String, + ) -> HashMap { + // Valid call with storage at the keys. + let response: MethodResponse = api + .call( + "chainHead_unstable_storage", + rpc_params![ + &sub_id, + &block_hash, + vec![ + StorageQuery { + key: hex_string(b":AAAA"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + StorageQuery { + key: hex_string(b":AAAB"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + // Key with descedent. + StorageQuery { + key: hex_string(b":A"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + StorageQuery { + key: hex_string(b":AA"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + // Keys below this comment do not produce a result. + // Key that exceed the keyspace of the trie. + StorageQuery { + key: hex_string(b":AAAAX"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + StorageQuery { + key: hex_string(b":AAABX"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + // Key that are not part of the trie. + StorageQuery { + key: hex_string(b":AAX"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + StorageQuery { + key: hex_string(b":AAAX"), + query_type: StorageQueryType::ClosestDescendantMerkleValue + }, + ] + ], + ) + .await + .unwrap(); + let operation_id = match response { + MethodResponse::Started(started) => started.operation_id, + MethodResponse::LimitReached => panic!("Expected started response"), + }; + + let event = get_next_event::>(&mut sub).await; + let merkle_values: HashMap<_, _> = match event { + FollowEvent::OperationStorageItems(res) => { + assert_eq!(res.operation_id, operation_id); + + res.items + .into_iter() + .map(|res| { + let value = match res.result { + StorageResultType::ClosestDescendantMerkleValue(value) => value, + _ => panic!("Unexpected StorageResultType"), + }; + (res.key, value) + }) + .collect() + }, + _ => panic!("Expected OperationStorageItems event"), + }; + + // Finished. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::OperationStorageDone(done) if done.operation_id == operation_id + ); + + // Response for AAAA, AAAB, A and AA. + assert_eq!(merkle_values.len(), 4); + + // While checking for expected merkle values to align, + // the following will check that the returned keys are + // expected. + + // Values for AAAA and AAAB are different. + assert_ne!( + merkle_values.get(&hex_string(b":AAAA")).unwrap(), + merkle_values.get(&hex_string(b":AAAB")).unwrap() + ); + + // Values for A and AA should be on the same branch node. + assert_eq!( + merkle_values.get(&hex_string(b":A")).unwrap(), + merkle_values.get(&hex_string(b":AA")).unwrap() + ); + // The branch node value must be different than the leaf of either + // AAAA and AAAB. + assert_ne!( + merkle_values.get(&hex_string(b":A")).unwrap(), + merkle_values.get(&hex_string(b":AAAA")).unwrap() + ); + assert_ne!( + merkle_values.get(&hex_string(b":A")).unwrap(), + merkle_values.get(&hex_string(b":AAAB")).unwrap() + ); + + merkle_values + } + + // Import a new block with storage changes. + let mut builder = client.new_block(Default::default()).unwrap(); + builder.push_storage_change(b":AAAA".to_vec(), Some(vec![1; 64])).unwrap(); + builder.push_storage_change(b":AAAB".to_vec(), Some(vec![2; 64])).unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + let merkle_values_lhs = expect_merkle_request(&api, &mut sub, sub_id.clone(), block_hash).await; + + // Import a new block with and change AAAB value. + let mut builder = client.new_block(Default::default()).unwrap(); + builder.push_storage_change(b":AAAA".to_vec(), Some(vec![1; 64])).unwrap(); + builder.push_storage_change(b":AAAB".to_vec(), Some(vec![3; 64])).unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + let merkle_values_rhs = expect_merkle_request(&api, &mut sub, sub_id.clone(), block_hash).await; + + // Change propagated to the root. + assert_ne!( + merkle_values_lhs.get(&hex_string(b":A")).unwrap(), + merkle_values_rhs.get(&hex_string(b":A")).unwrap() + ); + assert_ne!( + merkle_values_lhs.get(&hex_string(b":AAAB")).unwrap(), + merkle_values_rhs.get(&hex_string(b":AAAB")).unwrap() + ); + // However the AAAA branch leaf remains unchanged. + assert_eq!( + merkle_values_lhs.get(&hex_string(b":AAAA")).unwrap(), + merkle_values_rhs.get(&hex_string(b":AAAA")).unwrap() + ); +} diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 09c1673884a..26dcd0f9e21 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -78,7 +78,7 @@ use sp_state_machine::{ ChildStorageCollection, KeyValueStates, KeyValueStorageLevel, StorageCollection, MAX_NESTED_TRIE_DEPTH, }; -use sp_trie::{CompactProof, StorageProof}; +use sp_trie::{CompactProof, MerkleValue, StorageProof}; use std::{ collections::{HashMap, HashSet}, marker::PhantomData, @@ -1545,6 +1545,27 @@ where .child_storage_hash(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } + + fn closest_merkle_value( + &self, + hash: ::Hash, + key: &StorageKey, + ) -> blockchain::Result::Hash>>> { + self.state_at(hash)? + .closest_merkle_value(&key.0) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) + } + + fn child_closest_merkle_value( + &self, + hash: ::Hash, + child_info: &ChildInfo, + key: &StorageKey, + ) -> blockchain::Result::Hash>>> { + self.state_at(hash)? + .child_closest_merkle_value(child_info, &key.0) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) + } } impl HeaderMetadata for Client diff --git a/substrate/primitives/state-machine/src/backend.rs b/substrate/primitives/state-machine/src/backend.rs index 2a25bdc54d9..ea9cd442d70 100644 --- a/substrate/primitives/state-machine/src/backend.rs +++ b/substrate/primitives/state-machine/src/backend.rs @@ -30,7 +30,7 @@ use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; use sp_std::vec::Vec; -use sp_trie::PrefixedMemoryDB; +use sp_trie::{MerkleValue, PrefixedMemoryDB}; /// A struct containing arguments for iterating over the storage. #[derive(Default)] @@ -195,7 +195,17 @@ pub trait Backend: sp_std::fmt::Debug { /// Get keyed storage value hash or None if there is nothing associated. fn storage_hash(&self, key: &[u8]) -> Result, Self::Error>; - /// Get keyed child storage or None if there is nothing associated. + /// Get the merkle value or None if there is nothing associated. + fn closest_merkle_value(&self, key: &[u8]) -> Result>, Self::Error>; + + /// Get the child merkle value or None if there is nothing associated. + fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error>; + + /// Get child keyed child storage or None if there is nothing associated. fn child_storage( &self, child_info: &ChildInfo, diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index cc7132181f9..afa80addd2b 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -30,7 +30,6 @@ use codec::Codec; use hash_db::HashDB; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion}; -use sp_trie::PrefixedMemoryDB; #[cfg(feature = "std")] use sp_trie::{ cache::{LocalTrieCache, TrieCache}, @@ -39,6 +38,7 @@ use sp_trie::{ }; #[cfg(not(feature = "std"))] use sp_trie::{Error, NodeCodec}; +use sp_trie::{MerkleValue, PrefixedMemoryDB}; use trie_db::TrieCache as TrieCacheT; #[cfg(not(feature = "std"))] use trie_db::{node::NodeOwned, CachedValue}; @@ -405,6 +405,18 @@ where self.essence.child_storage(child_info, key) } + fn closest_merkle_value(&self, key: &[u8]) -> Result>, Self::Error> { + self.essence.closest_merkle_value(key) + } + + fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + self.essence.child_closest_merkle_value(child_info, key) + } + fn next_storage_key(&self, key: &[u8]) -> Result, Self::Error> { let (is_cached, mut cache) = access_cache(&self.next_storage_key_cache, Option::take) .map(|cache| (cache.last_key == key, cache)) diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index 4bb51f4a134..ad7aeab899c 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -32,11 +32,12 @@ use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; #[cfg(feature = "std")] use sp_trie::recorder::Recorder; use sp_trie::{ - child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_hash, - read_child_trie_value, read_trie_value, + child_delta_trie_root, delta_trie_root, empty_child_trie_root, + read_child_trie_first_descedant_value, read_child_trie_hash, read_child_trie_value, + read_trie_first_descedant_value, read_trie_value, trie_types::{TrieDBBuilder, TrieError}, - DBValue, KeySpacedDB, NodeCodec, PrefixedMemoryDB, Trie, TrieCache, TrieDBRawIterator, - TrieRecorder, + DBValue, KeySpacedDB, MerkleValue, NodeCodec, PrefixedMemoryDB, Trie, TrieCache, + TrieDBRawIterator, TrieRecorder, }; #[cfg(feature = "std")] use std::{collections::HashMap, sync::Arc}; @@ -574,6 +575,39 @@ where }) } + /// Get the closest merkle value at given key. + pub fn closest_merkle_value(&self, key: &[u8]) -> Result>> { + let map_e = |e| format!("Trie lookup error: {}", e); + + self.with_recorder_and_cache(None, |recorder, cache| { + read_trie_first_descedant_value::, _>(self, &self.root, key, recorder, cache) + .map_err(map_e) + }) + } + + /// Get the child closest merkle value at given key. + pub fn child_closest_merkle_value( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>> { + let Some(child_root) = self.child_root(child_info)? else { return Ok(None) }; + + let map_e = |e| format!("Trie lookup error: {}", e); + + self.with_recorder_and_cache(Some(child_root), |recorder, cache| { + read_child_trie_first_descedant_value::, _>( + child_info.keyspace(), + self, + &child_root, + key, + recorder, + cache, + ) + .map_err(map_e) + }) + } + /// Create a raw iterator over the storage. pub fn raw_iter(&self, args: IterArgs) -> Result> { let root = if let Some(child_info) = args.child_info.as_ref() { diff --git a/substrate/primitives/trie/src/lib.rs b/substrate/primitives/trie/src/lib.rs index 94155458569..1a1ed670454 100644 --- a/substrate/primitives/trie/src/lib.rs +++ b/substrate/primitives/trie/src/lib.rs @@ -44,7 +44,6 @@ pub use storage_proof::{CompactProof, StorageProof}; /// Trie codec reexport, mainly child trie support /// for trie compact proof. pub use trie_codec::{decode_compact, encode_compact, Error as CompactProofError}; -pub use trie_db::proof::VerifyError; use trie_db::proof::{generate_proof, verify_proof}; /// Various re-exports from the `trie-db` crate. pub use trie_db::{ @@ -53,6 +52,7 @@ pub use trie_db::{ CError, DBValue, Query, Recorder, Trie, TrieCache, TrieConfiguration, TrieDBIterator, TrieDBKeyIterator, TrieDBRawIterator, TrieLayout, TrieMut, TrieRecorder, }; +pub use trie_db::{proof::VerifyError, MerkleValue}; /// The Substrate format implementation of `TrieStream`. pub use trie_stream::TrieStream; @@ -295,6 +295,25 @@ pub fn read_trie_value( + db: &DB, + root: &TrieHash, + key: &[u8], + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, +) -> Result>>, Box>> +where + DB: hash_db::HashDBRef, +{ + TrieDBBuilder::::new(db, root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build() + .lookup_first_descendant(key) +} + /// Read a value from the trie with given Query. pub fn read_trie_value_with< L: TrieLayout, @@ -397,6 +416,27 @@ where .get_hash(key) } +/// Read the [`trie_db::MerkleValue`] of the node that is the closest descendant for +/// the provided child key. +pub fn read_child_trie_first_descedant_value( + keyspace: &[u8], + db: &DB, + root: &TrieHash, + key: &[u8], + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, +) -> Result>>, Box>> +where + DB: hash_db::HashDBRef, +{ + let db = KeySpacedDB::new(db, keyspace); + TrieDBBuilder::::new(&db, &root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build() + .lookup_first_descendant(key) +} + /// Read a value from the child trie with given query. pub fn read_child_trie_value_with( keyspace: &[u8], -- GitLab From 372929fa256f5839047bb5d569ad523cb4b15094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:49:39 +0200 Subject: [PATCH 175/633] Bump the known_good_semver group with 1 update (#1606) Bumps the known_good_semver group with 1 update: [syn](https://github.com/dtolnay/syn).
Release notes

Sourced from syn's releases.

2.0.36

  • Restore compatibility with --generate-link-to-definition documentation builds (#1514)

2.0.35

  • Make rust-analyzer produce preferred brackets for invocations of Token! macro (#1510, #1512)

2.0.34

  • Documentation improvements
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=syn&package-manager=cargo&previous-version=2.0.33&new-version=2.0.36)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 100 +++++++++--------- .../parachain-system/proc-macro/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- 17 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea4cf4a1817..a5ea33e1ae4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,7 +1138,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -1160,7 +1160,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -1177,7 +1177,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -1351,7 +1351,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -2514,7 +2514,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -3574,7 +3574,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4057,7 +4057,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4097,7 +4097,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4114,7 +4114,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4412,7 +4412,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4474,7 +4474,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.33", + "syn 2.0.36", "termcolor", "toml 0.7.6", "walkdir", @@ -4695,7 +4695,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4706,7 +4706,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -4851,7 +4851,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -5207,7 +5207,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.33", + "syn 2.0.36", "trybuild", ] @@ -5359,7 +5359,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -5370,7 +5370,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -5379,7 +5379,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -5602,7 +5602,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -7612,7 +7612,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -7626,7 +7626,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -7637,7 +7637,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -7648,7 +7648,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -9334,7 +9334,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -10405,7 +10405,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -11272,7 +11272,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -11313,7 +11313,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -13292,7 +13292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -13374,7 +13374,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -13420,7 +13420,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -13811,7 +13811,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -14574,7 +14574,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -15785,7 +15785,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -16139,7 +16139,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -16205,7 +16205,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -16633,7 +16633,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -17033,7 +17033,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -17077,7 +17077,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -17308,7 +17308,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -17548,7 +17548,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -18323,9 +18323,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.33" +version = "2.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" +checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373" dependencies = [ "proc-macro2", "quote", @@ -18570,7 +18570,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -18750,7 +18750,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -18931,7 +18931,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -18974,7 +18974,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -19523,7 +19523,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", "wasm-bindgen-shared", ] @@ -19557,7 +19557,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20693,7 +20693,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] @@ -20812,7 +20812,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.33", + "syn 2.0.36", ] [[package]] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 77e298363c8..ee0943bb99e 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.33" +syn = "2.0.36" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 0d6cee2ccf0..be302e46ad9 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.33", features = ["full", "extra-traits"] } +syn = { version = "2.0.36", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 3e137c42843..6beaa1d667f 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.33" +syn = "2.0.36" Inflector = "0.11.4" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index ff1ce5141e6..f0ad4c68d1f 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.33" +syn = "2.0.36" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index bf45111de88..270f34b6d04 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.33", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.36", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index 8779f97b9cd..ccc80a2eba4 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.33", features = ["full"] } +syn = { version = "2.0.36", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 50381d83869..1b432204470 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.33", features = ["full", "visit"] } +syn = { version = "2.0.36", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index fc1f1b4b3ee..7646bbc9a55 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.33", features = ["full", "visit"] } +syn = { version = "2.0.36", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index b582457e4b8..e1606854605 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.33", features = ["full"] } +syn = { version = "2.0.36", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 211dc3bd66a..fb0a1b51cbc 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.33", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.36", 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 472e288c3df..747d3bacd42 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.33", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.36", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index d53b9b702e7..71f1ff95d55 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.33", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.36", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index 5e7cd9e3a7a..fce09b452e5 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.33", features = ["full", "parsing"] } +syn = { version = "2.0.36", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 82f4e8cf604..689a1250569 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.33" +syn = "2.0.36" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 0884efc56d4..fe06c56d5a1 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.33", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.36", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index a3478e3e5ca..3cd1b7a3a76 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.33", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.36", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } -- GitLab From 8900d5b23a8e0be100552801207e174c47821ad6 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 18 Sep 2023 16:08:57 +0200 Subject: [PATCH 176/633] Move ISSUE_TEMPLATE (#1567) This PR moves the `ISSUE_TEMPLATE` to the root and removes the old ones. --- .../ISSUE_TEMPLATE/blank.md | 0 .../ISSUE_TEMPLATE/bug_report.yaml | 5 +- .../ISSUE_TEMPLATE/config.yml | 0 .../ISSUE_TEMPLATE/feature.yaml | 2 +- .../.github/ISSUE_TEMPLATE/release-client.md | 20 ------- .../.github/ISSUE_TEMPLATE/release-runtime.md | 54 ------------------- polkadot/.github/ISSUE_TEMPLATE/bug_report.md | 13 ----- polkadot/.github/ISSUE_TEMPLATE/release.md | 52 ------------------ 8 files changed, 4 insertions(+), 142 deletions(-) rename {cumulus/.github => .github}/ISSUE_TEMPLATE/blank.md (100%) rename substrate/.github/ISSUE_TEMPLATE/bug.yaml => .github/ISSUE_TEMPLATE/bug_report.yaml (92%) rename {substrate/.github => .github}/ISSUE_TEMPLATE/config.yml (100%) rename {substrate/.github => .github}/ISSUE_TEMPLATE/feature.yaml (98%) delete mode 100644 cumulus/.github/ISSUE_TEMPLATE/release-client.md delete mode 100644 cumulus/.github/ISSUE_TEMPLATE/release-runtime.md delete mode 100644 polkadot/.github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 polkadot/.github/ISSUE_TEMPLATE/release.md diff --git a/cumulus/.github/ISSUE_TEMPLATE/blank.md b/.github/ISSUE_TEMPLATE/blank.md similarity index 100% rename from cumulus/.github/ISSUE_TEMPLATE/blank.md rename to .github/ISSUE_TEMPLATE/blank.md diff --git a/substrate/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml similarity index 92% rename from substrate/.github/ISSUE_TEMPLATE/bug.yaml rename to .github/ISSUE_TEMPLATE/bug_report.yaml index ae40df08eca..f828a5d9d89 100644 --- a/substrate/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,6 +1,7 @@ name: Bug Report description: Let us know about an issue you experienced with this software -# labels: ["some existing label","another one"] +labels: [ I2-bug, I10-unconfirmed ] + body: - type: checkboxes attributes: @@ -20,7 +21,7 @@ body: id: bug attributes: label: Description of bug - # description: What seems to be the problem? + description: What seems to be the problem? # placeholder: Describe the problem. validations: required: true diff --git a/substrate/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from substrate/.github/ISSUE_TEMPLATE/config.yml rename to .github/ISSUE_TEMPLATE/config.yml diff --git a/substrate/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml similarity index 98% rename from substrate/.github/ISSUE_TEMPLATE/feature.yaml rename to .github/ISSUE_TEMPLATE/feature.yaml index 6a59522ab4b..828e8b461cc 100644 --- a/substrate/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -1,6 +1,6 @@ name: Feature Request description: Submit your requests and suggestions to improve! -labels: ["J0-enhancement"] +labels: [ I5-enhancement ] body: - type: checkboxes id: existing diff --git a/cumulus/.github/ISSUE_TEMPLATE/release-client.md b/cumulus/.github/ISSUE_TEMPLATE/release-client.md deleted file mode 100644 index bb7f2061576..00000000000 --- a/cumulus/.github/ISSUE_TEMPLATE/release-client.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Release Checklist for Client -about: Release Checklist for Client -title: Release Checklist for Client {{ env.VERSION }} ---- - -# Release Checklist - Client - -### Client Release - -- [ ] build a new `polkadot-parachain` binary and publish it to S3 -- [ ] new `polkadot-parachain` version has [run on the network](../../docs/release.md#burnin) - without issue for at least 12h -- [ ] a draft release has been created in the [Github Releases page](https://github.com/paritytech/cumulus/releases) with the relevant release-notes -- [ ] the [build artifacts](../../docs/release.md#build-artifacts) have been added to the - draft-release. - ---- - -Read more about the [release documentation](../../docs/release.md). diff --git a/cumulus/.github/ISSUE_TEMPLATE/release-runtime.md b/cumulus/.github/ISSUE_TEMPLATE/release-runtime.md deleted file mode 100644 index 0f3543759af..00000000000 --- a/cumulus/.github/ISSUE_TEMPLATE/release-runtime.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -name: Release Checklist for Runtime -about: Release Checklist for Runtime -title: Release Checklist for Runtime {{ env.VERSION }} ---- - -# Release Checklist - Runtimes - -**All** following checks must be completed before publishing a new release. -The release process is owned and led by @paritytech/release-engineering team. -The checks marked with :crab: are meant to be checked by [a runtime engineer](https://github.com/paritytech/cumulus/issues/1761). - -## Runtimes Release - -### Codebase -These checks should be performed on the codebase. - -- [ ] the [`spec_version`](https://github.com/paritytech/cumulus/blob/master/docs/release.md#spec-version) has been incremented since the - last release for any native runtimes from any existing use on public (non-private/test) networks -- [ ] :crab: previously [completed migrations](https://github.com/paritytech/cumulus/blob/master/docs/release.md#old-migrations-removed) are removed for any public (non-private/test) networks -- [ ] pallet and [extrinsic ordering](https://github.com/paritytech/cumulus/blob/master/docs/release.md#extrinsic-ordering--storage) as well as `SignedExtension`s have stayed - the same. Bump `transaction_version` otherwise -- [ ] the [benchmarks](https://github.com/paritytech/ci_cd/wiki/Benchmarks:-cumulus) ran -- [ ] the weights have been updated for any modified runtime logic -- [ ] :crab: the new weights are sane, there are no significant (>50%) drops or rises with no reason -- [ ] :crab: XCM config is compatible with the configurations and versions of relevant interlocutors, like the Relay Chain. - -### On the release branch - -The following checks can be performed after we have forked off to the release-candidate branch or started an additional release candidate branch (rc-2, rc-3, etc) - -- [ ] Verify [new migrations](https://github.com/paritytech/cumulus/blob/master/docs/release.md#new-migrations) complete successfully, and the - runtime state is correctly updated for any public (non-private/test) - networks -- [ ] Run [integration tests](https://github.com/paritytech/cumulus/blob/master/docs/release.md#integration-tests), and make sure they pass. -- [ ] Push runtime upgrade to Asset Hub Westend and verify network stability -- [ ] Push runtime upgrade to Collectives and verify network stability -- [ ] Push runtime upgrade to Bridge-Hub-Kusama and verify network stability - - -### Github - -- [ ] Check that a draft release has been created at the [Github Releases page](https://github.com/paritytech/cumulus/releases) with relevant [release - notes](https://github.com/paritytech/cumulus/blob/master/docs/release.md#release-notes) -- [ ] Check that [build artifacts](https://github.com/paritytech/cumulus/blob/master/docs/release.md#build-artifacts) have been added to the - draft-release. - -# Post release - -- [ ] :crab: all commits (runtime version bumps, fixes) on this release branch have been merged back to master. - ---- - -Read more about the [release documentation](https://github.com/paritytech/cumulus/blob/master/docs/release.md). diff --git a/polkadot/.github/ISSUE_TEMPLATE/bug_report.md b/polkadot/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index c2214ab7d93..00000000000 --- a/polkadot/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -- It would help if you submit info about the system you are running, e.g.: operating system, kernel version, amount of available memory and swap, etc. -- Logs could be very helpful. If possible, submit the whole log. Please format it as ```code blocks```. -- Describe the role your node plays, e.g. validator, full node or light client. -- Any command-line options were passed? diff --git a/polkadot/.github/ISSUE_TEMPLATE/release.md b/polkadot/.github/ISSUE_TEMPLATE/release.md deleted file mode 100644 index 37b422a9b3e..00000000000 --- a/polkadot/.github/ISSUE_TEMPLATE/release.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: Release issue template -about: Tracking issue for new releases -title: Polkadot {{ env.VERSION }} Release checklist ---- -# Release Checklist - -This is the release checklist for Polkadot {{ env.VERSION }}. **All** following -checks should be completed before publishing a new release of the -Polkadot/Kusama/Westend/Rococo runtime or client. The current release candidate can be -checked out with `git checkout release-{{ env.VERSION }}` - -### Runtime Releases - -These checks should be performed on the codebase prior to forking to a release- -candidate branch. - -- [ ] Verify [`spec_version`](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#spec-version) has been incremented since the - last release for any native runtimes from any existing use on public - (non-private) networks. If the runtime was published (release or pre-release), either - the `spec_version` or `impl` must be bumped. -- [ ] Verify previously [completed migrations](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#old-migrations-removed) are - removed for any public (non-private/test) networks. -- [ ] Verify pallet and [extrinsic ordering](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#extrinsic-ordering) has stayed - the same. Bump `transaction_version` if not. -- [ ] Verify new extrinsics have been correctly whitelisted/blacklisted for - [proxy filters](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#proxy-filtering). -- [ ] Verify [benchmarks](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#benchmarks) have been updated for any modified - runtime logic. - -The following checks can be performed after we have forked off to the release- -candidate branch or started an additional release candidate branch (rc-2, rc-3, etc) - -- [ ] Verify [new migrations](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#new-migrations) complete successfully, and the - runtime state is correctly updated for any public (non-private/test) - networks. -- [ ] Verify [Polkadot JS API](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#polkadot-js) are up to date with the latest - runtime changes. -- [ ] Check with the Signer's team to make sure metadata update QR are lined up -- [ ] Push runtime upgrade to Westend and verify network stability. - -### All Releases - -- [ ] Check that the new client versions have [run on the network](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#burn-in) - without issue for 12+ hours on >75% of our validator nodes. -- [ ] Check that a draft release has been created at - https://github.com/paritytech/polkadot/releases with relevant [release - notes](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#release-notes) -- [ ] Check that [build artifacts](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#build-artifacts) have been added to the - draft-release -- [ ] Check that all items listed in the [milestone](https://github.com/paritytech/polkadot/milestones) are included in the release. -- [ ] Ensure that no `freenotes` were added into the release branch after the latest generated RC -- GitLab From e6f5e23b0f894954c0f04ba379966f2466f51de6 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:35:40 +0200 Subject: [PATCH 177/633] [ci] Publish implementers guide (#1615) PR adds a job that publishes implementers guide cc https://github.com/paritytech/polkadot-sdk/issues/1614 cc https://github.com/paritytech/ci_cd/issues/879 --- .gitlab/pipeline/build.yml | 2 +- .gitlab/pipeline/publish.yml | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 3085d223006..5b53798c403 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -127,7 +127,7 @@ build-implementers-guide: - .kubernetes-env - .common-refs - .run-immediately - # - .collect-artifacts + - .collect-artifacts # git depth is set on purpose: https://github.com/paritytech/polkadot/issues/6284 variables: GIT_STRATEGY: clone diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 9e24b8606a4..a03d407c040 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -16,6 +16,8 @@ publish-rustdoc: needs: - job: build-rustdoc artifacts: true + - job: build-implementers-guide + artifacts: true script: # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we # exit immediately. @@ -34,15 +36,21 @@ publish-rustdoc: - git fetch origin gh-pages # Save README and docs - cp -r ./crate-docs/ /tmp/doc/ + - cp -r ./artifacts/book/ /tmp/ - cp README.md /tmp/doc/ # we don't need to commit changes because we copy docs to /tmp - git checkout gh-pages --force + # Enable if docs needed for other refs # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} + # - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud + # - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} # Ensure the destination dir doesn't exist. - rm -rf ${CI_COMMIT_REF_NAME} + - rm -rf book/ - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} + # dir for implementors guide + - mkdir -p book + - mv /tmp/book/html/* book/ # Upload files - git add --all # `git commit` has an exit code of > 0 if there is nothing to commit. -- GitLab From a181ced46b6924d6179288e5142e81fdd0927d30 Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:17:14 +0300 Subject: [PATCH 178/633] Replace free for all collation in `cumulus` runtimes (#1251) Partially fixes #103 This PR removes instances of "free for all" collation in the `glutton`, `shell`, and `seedling` runtimes and replaces them with Aura instances. Aura is configured without a session manager, so the initial authority set cannot be changed later on. --------- Signed-off-by: georgepisaltu --- Cargo.lock | 14 ++++ .../glutton/glutton-kusama/Cargo.toml | 16 ++++ .../glutton/glutton-kusama/src/lib.rs | 80 ++++++++++++++++--- .../glutton/glutton-kusama/src/weights/mod.rs | 1 + .../src/weights/pallet_timestamp.rs | 75 +++++++++++++++++ .../runtimes/starters/seedling/Cargo.toml | 14 +++- .../runtimes/starters/seedling/src/lib.rs | 76 +++++++++++++++--- .../runtimes/starters/shell/Cargo.toml | 13 +++ .../runtimes/starters/shell/src/lib.rs | 78 +++++++++++++++--- .../src/chain_spec/glutton.rs | 32 +++++++- .../src/chain_spec/seedling.rs | 8 +- .../src/chain_spec/shell.rs | 14 +++- 12 files changed, 378 insertions(+), 43 deletions(-) create mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs diff --git a/Cargo.lock b/Cargo.lock index a5ea33e1ae4..670d9c9e771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5788,9 +5788,11 @@ dependencies = [ name = "glutton-runtime" version = "1.0.0" dependencies = [ + "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", "cumulus-primitives-core", + "cumulus-primitives-timestamp", "frame-benchmarking", "frame-executive", "frame-support", @@ -5798,14 +5800,17 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", + "pallet-aura", "pallet-glutton", "pallet-sudo", + "pallet-timestamp", "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", "sp-api", "sp-block-builder", + "sp-consensus-aura", "sp-core", "sp-inherents", "sp-offchain", @@ -16058,20 +16063,25 @@ dependencies = [ name = "seedling-runtime" version = "0.1.0" dependencies = [ + "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-solo-to-para", "cumulus-primitives-core", + "cumulus-primitives-timestamp", "frame-executive", "frame-support", "frame-system", + "pallet-aura", "pallet-balances", "pallet-sudo", + "pallet-timestamp", "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", "sp-api", "sp-block-builder", + "sp-consensus-aura", "sp-core", "sp-inherents", "sp-offchain", @@ -16302,6 +16312,7 @@ dependencies = [ name = "shell-runtime" version = "0.1.0" dependencies = [ + "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", "cumulus-primitives-core", @@ -16309,12 +16320,15 @@ dependencies = [ "frame-support", "frame-system", "frame-try-runtime", + "pallet-aura", + "pallet-timestamp", "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", "sp-api", "sp-block-builder", + "sp-consensus-aura", "sp-core", "sp-inherents", "sp-offchain", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 2e2975ab87b..0ffe59b927f 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -16,10 +16,13 @@ frame-system = { path = "../../../../../substrate/frame/system", default-feature frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false} frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true} frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true} +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true} pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true} +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +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} @@ -36,9 +39,11 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} # Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", 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 } parachains-common = { path = "../../../common", default-features = false } @@ -55,6 +60,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-glutton/runtime-benchmarks", "pallet-sudo?/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", "parachains-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", @@ -62,9 +68,11 @@ runtime-benchmarks = [ ] std = [ "codec/std", + "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcm/std", "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", "frame-benchmarking?/std", "frame-executive/std", "frame-support/std", @@ -72,13 +80,16 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime?/std", + "pallet-aura/std", "pallet-glutton/std", "pallet-sudo/std", + "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", + "sp-consensus-aura/std", "sp-core/std", "sp-inherents/std", "sp-offchain/std", @@ -93,14 +104,19 @@ std = [ "xcm/std", ] try-runtime = [ + "cumulus-pallet-aura-ext/try-runtime", "cumulus-pallet-parachain-system/try-runtime", "cumulus-pallet-xcm/try-runtime", "frame-executive/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", "pallet-glutton/try-runtime", "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", "parachain-info/try-runtime", "sp-runtime/try-runtime", ] + +experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index dde8f747d46..41cb0fceebb 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -46,11 +46,12 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod weights; pub mod xcm_config; -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use sp_api::impl_runtime_apis; -use sp_core::OpaqueMetadata; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, + create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -64,24 +65,37 @@ pub use frame_support::{ construct_runtime, dispatch::DispatchClass, parameter_types, - traits::{Everything, IsInVec, Randomness}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, IsInVec, Randomness, + }, weights::{ constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, }, IdentityFee, Weight, }, - StorageValue, + PalletId, StorageValue, }; use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use parachains_common::{AccountId, Signature}; +use parachains_common::{ + kusama::consensus::{ + BLOCK_PROCESSING_VELOCITY, RELAY_CHAIN_SLOT_DURATION_MILLIS, UNINCLUDED_SEGMENT_CAPACITY, + }, + AccountId, Signature, SLOT_DURATION, +}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton"), @@ -178,12 +192,35 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = (); type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded; + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + 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 pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = weights::pallet_timestamp::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; +} + impl pallet_glutton::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_glutton::WeightInfo; @@ -204,6 +241,7 @@ construct_runtime! { Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, } = 1, ParachainInfo: parachain_info::{Pallet, Storage, Config} = 2, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, // DMP handler. CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 10, @@ -211,6 +249,10 @@ construct_runtime! { // The main stage. Glutton: pallet_glutton::{Pallet, Call, Storage, Event, Config} = 20, + // Collator support + Aura: pallet_aura::{Pallet, Storage, Config} = 30, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 31, + // Sudo. Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, } @@ -295,6 +337,16 @@ 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_block_builder::BlockBuilder for Runtime { fn apply_extrinsic( extrinsic: ::Extrinsic, @@ -332,12 +384,14 @@ impl_runtime_apis! { } impl sp_session::SessionKeys for Runtime { - fn decode_session_keys(_: Vec) -> Option, sp_core::crypto::KeyTypeId)>> { - Some(Vec::new()) + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) } - fn generate_session_keys(_: Option>) -> Vec { - Vec::new() + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) } } @@ -402,5 +456,5 @@ impl_runtime_apis! { cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, - BlockExecutor = Executive, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs index 990558538ac..955010505d3 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs @@ -15,3 +15,4 @@ // along with Cumulus. If not, see . pub mod pallet_glutton; +pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000000..8edae065f1b --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs @@ -0,0 +1,75 @@ +// 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_timestamp` +//! +//! 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-kusama-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-kusama-dev +// --wasm-execution=compiled +// --pallet=pallet_timestamp +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/assets/asset-hub-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: `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: `86` + // Estimated: `1493` + // 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: `57` + // Estimated: `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/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 2cd09d3a9eb..1b68b720d97 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -12,10 +12,13 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive" 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} +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } 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} @@ -26,11 +29,13 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} # Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-solo-to-para = { path = "../../../../pallets/solo-to-para", 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 } parachains-common = { path = "../../../common", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -39,19 +44,24 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", default = [ "std" ] std = [ "codec/std", + "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-solo-to-para/std", "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", "frame-executive/std", "frame-support/std", "frame-system/std", + "pallet-aura/std", "pallet-balances/std", "pallet-sudo/std", + "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", + "sp-consensus-aura/std", "sp-core/std", "sp-inherents/std", "sp-offchain/std", @@ -62,3 +72,5 @@ std = [ "sp-version/std", "substrate-wasm-builder", ] + +experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 5f6733faf70..34e82737f82 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -27,11 +27,12 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use sp_api::impl_runtime_apis; -use sp_core::OpaqueMetadata; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, + create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -46,7 +47,7 @@ pub use frame_support::{ construct_runtime, dispatch::DispatchClass, parameter_types, - traits::{IsInVec, Randomness}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, weights::{ constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, @@ -61,6 +62,12 @@ use parachains_common::{AccountId, Signature}; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + /// This runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -80,6 +87,15 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; +/// Relay chain slot duration, in milliseconds. +const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + /// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); @@ -174,23 +190,49 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = (); type XcmpMessageHandler = (); type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded; + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + 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 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; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<0>; + type WeightInfo = (); +} + construct_runtime! { pub enum Runtime { System: frame_system::{Pallet, Call, Storage, Config, Event}, Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, }, ParachainInfo: parachain_info::{Pallet, Storage, Config}, SoloToPara: cumulus_pallet_solo_to_para::{Pallet, Call, Storage, Event}, + Aura: pallet_aura::{Pallet, Storage, Config}, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config}, } } @@ -233,6 +275,16 @@ pub type Executive = frame_executive::Executive< >; 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 @@ -298,12 +350,14 @@ impl_runtime_apis! { } impl sp_session::SessionKeys for Runtime { - fn decode_session_keys(_: Vec) -> Option, sp_core::crypto::KeyTypeId)>> { - Some(Vec::new()) + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) } - fn generate_session_keys(_: Option>) -> Vec { - Vec::new() + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) } } @@ -316,5 +370,5 @@ impl_runtime_apis! { cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, - BlockExecutor = Executive, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 6f904605710..46cef8d4ae0 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -13,8 +13,11 @@ frame-executive = { path = "../../../../../substrate/frame/executive", default-f frame-support = { path = "../../../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../../../substrate/frame/system", default-features = false} frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +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} @@ -30,6 +33,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} # Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } @@ -43,6 +47,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", default = [ "std" ] std = [ "codec/std", + "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcm/std", "cumulus-primitives-core/std", @@ -50,11 +55,14 @@ std = [ "frame-support/std", "frame-system/std", "frame-try-runtime?/std", + "pallet-aura/std", + "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", + "sp-consensus-aura/std", "sp-core/std", "sp-inherents/std", "sp-offchain/std", @@ -69,12 +77,17 @@ std = [ "xcm/std", ] try-runtime = [ + "cumulus-pallet-aura-ext/try-runtime", "cumulus-pallet-parachain-system/try-runtime", "cumulus-pallet-xcm/try-runtime", "frame-executive/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", + "pallet-timestamp/try-runtime", "parachain-info/try-runtime", "sp-runtime/try-runtime", ] + +experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index ef914a246ef..477933b5c8d 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -32,13 +32,14 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod xcm_config; use codec::{Decode, Encode}; -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use frame_support::unsigned::TransactionValidityError; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; -use sp_core::OpaqueMetadata; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, + create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -53,7 +54,7 @@ pub use frame_support::{ construct_runtime, dispatch::DispatchClass, parameter_types, - traits::{Everything, IsInVec, Randomness}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, weights::{ constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, @@ -68,6 +69,12 @@ use parachains_common::{AccountId, Signature}; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + /// This runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -87,6 +94,15 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; +/// Relay chain slot duration, in milliseconds. +const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + /// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); @@ -177,16 +193,41 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = (); type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded; + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + 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 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; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<0>; + type WeightInfo = (); +} + construct_runtime! { pub enum Runtime { System: frame_system::{Pallet, Call, Storage, Config, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, }, @@ -194,6 +235,9 @@ construct_runtime! { // DMP handler. CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + + Aura: pallet_aura::{Pallet, Storage, Config}, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config}, } } @@ -263,6 +307,16 @@ pub type Executive = frame_executive::Executive< >; 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 @@ -328,12 +382,14 @@ impl_runtime_apis! { } impl sp_session::SessionKeys for Runtime { - fn decode_session_keys(_: Vec) -> Option, sp_core::crypto::KeyTypeId)>> { - Some(Vec::new()) + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) } - fn generate_session_keys(_: Option>) -> Vec { - Vec::new() + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) } } @@ -346,5 +402,5 @@ impl_runtime_apis! { cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, - BlockExecutor = Executive, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index acd5b5bfbe1..881fae39882 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -16,9 +16,12 @@ use crate::chain_spec::{get_account_id_from_seed, Extensions}; use cumulus_primitives_core::ParaId; +use parachains_common::AuraId; use sc_service::ChainType; use sp_core::sr25519; +use super::get_collator_keys_from_seed; + /// Specialized `ChainSpec` for the Glutton parachain runtime. pub type GluttonChainSpec = sc_service::GenericChainSpec; @@ -30,7 +33,7 @@ pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec { // ID "glutton_dev", ChainType::Local, - move || glutton_genesis(para_id), + move || glutton_genesis(para_id, vec![get_collator_keys_from_seed::("Alice")]), Vec::new(), None, None, @@ -47,7 +50,15 @@ pub fn glutton_local_config(para_id: ParaId) -> GluttonChainSpec { // ID "glutton_local", ChainType::Local, - move || glutton_genesis(para_id), + move || { + glutton_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + ) + }, Vec::new(), None, None, @@ -67,7 +78,15 @@ pub fn glutton_config(para_id: ParaId) -> GluttonChainSpec { // ID format!("glutton-kusama-{}", para_id).as_str(), ChainType::Live, - move || glutton_genesis(para_id), + move || { + glutton_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + ) + }, Vec::new(), None, // Protocol ID @@ -78,7 +97,10 @@ pub fn glutton_config(para_id: ParaId) -> GluttonChainSpec { ) } -fn glutton_genesis(parachain_id: ParaId) -> glutton_runtime::RuntimeGenesisConfig { +fn glutton_genesis( + parachain_id: ParaId, + collators: Vec, +) -> glutton_runtime::RuntimeGenesisConfig { glutton_runtime::RuntimeGenesisConfig { system: glutton_runtime::SystemConfig { code: glutton_runtime::WASM_BINARY @@ -94,6 +116,8 @@ fn glutton_genesis(parachain_id: ParaId) -> glutton_runtime::RuntimeGenesisConfi trash_data_count: Default::default(), ..Default::default() }, + aura: glutton_runtime::AuraConfig { authorities: collators }, + aura_ext: Default::default(), sudo: glutton_runtime::SudoConfig { key: Some(get_account_id_from_seed::("Alice")), }, diff --git a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs index 3ebfb80d468..6a584232097 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs @@ -16,10 +16,12 @@ use crate::chain_spec::{get_account_id_from_seed, Extensions}; use cumulus_primitives_core::ParaId; -use parachains_common::AccountId; +use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; use sp_core::sr25519; +use super::get_collator_keys_from_seed; + /// Specialized `ChainSpec` for the seedling parachain runtime. pub type SeedlingChainSpec = sc_service::GenericChainSpec; @@ -33,6 +35,7 @@ pub fn get_seedling_chain_spec() -> SeedlingChainSpec { seedling_testnet_genesis( get_account_id_from_seed::("Alice"), 2000.into(), + vec![get_collator_keys_from_seed::("Alice")], ) }, Vec::new(), @@ -47,6 +50,7 @@ pub fn get_seedling_chain_spec() -> SeedlingChainSpec { fn seedling_testnet_genesis( root_key: AccountId, parachain_id: ParaId, + collators: Vec, ) -> seedling_runtime::RuntimeGenesisConfig { seedling_runtime::RuntimeGenesisConfig { system: seedling_runtime::SystemConfig { @@ -61,5 +65,7 @@ fn seedling_testnet_genesis( ..Default::default() }, parachain_system: Default::default(), + aura: seedling_runtime::AuraConfig { authorities: collators }, + aura_ext: Default::default(), } } diff --git a/cumulus/polkadot-parachain/src/chain_spec/shell.rs b/cumulus/polkadot-parachain/src/chain_spec/shell.rs index 7eb65591b12..0899c1af3b4 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/shell.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/shell.rs @@ -16,8 +16,11 @@ use crate::chain_spec::Extensions; use cumulus_primitives_core::ParaId; +use parachains_common::AuraId; use sc_service::ChainType; +use super::get_collator_keys_from_seed; + /// Specialized `ChainSpec` for the shell parachain runtime. pub type ShellChainSpec = sc_service::GenericChainSpec; @@ -27,7 +30,9 @@ pub fn get_shell_chain_spec() -> ShellChainSpec { "Shell Local Testnet", "shell_local_testnet", ChainType::Local, - move || shell_testnet_genesis(1000.into()), + move || { + shell_testnet_genesis(1000.into(), vec![get_collator_keys_from_seed::("Alice")]) + }, Vec::new(), None, None, @@ -37,7 +42,10 @@ pub fn get_shell_chain_spec() -> ShellChainSpec { ) } -fn shell_testnet_genesis(parachain_id: ParaId) -> shell_runtime::RuntimeGenesisConfig { +fn shell_testnet_genesis( + parachain_id: ParaId, + collators: Vec, +) -> shell_runtime::RuntimeGenesisConfig { shell_runtime::RuntimeGenesisConfig { system: shell_runtime::SystemConfig { code: shell_runtime::WASM_BINARY @@ -47,5 +55,7 @@ fn shell_testnet_genesis(parachain_id: ParaId) -> shell_runtime::RuntimeGenesisC }, parachain_info: shell_runtime::ParachainInfoConfig { parachain_id, ..Default::default() }, parachain_system: Default::default(), + aura: shell_runtime::AuraConfig { authorities: collators }, + aura_ext: Default::default(), } } -- GitLab From ffe5db0f7662f80dcf4805d093c6736880c0fb4d Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 18 Sep 2023 18:32:30 +0100 Subject: [PATCH 179/633] Staking: Add `dest` to `Rewarded` to aid in reward calculations (#1602) Addresses https://github.com/paritytech/polkadot-sdk/issues/129. Returns `Self:payee()` from `make_payout` in a tuple alongside an imbalance & adds it to `Rewarded` event. --- substrate/frame/staking/src/pallet/impls.rs | 23 ++++++++++++++------- substrate/frame/staking/src/pallet/mod.rs | 8 +++++-- substrate/frame/staking/src/tests.rs | 10 +++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index e0f5c955878..3d9b1157ca8 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -236,11 +236,12 @@ impl Pallet { let mut total_imbalance = PositiveImbalanceOf::::zero(); // We can now make total validator payout: - if let Some(imbalance) = + if let Some((imbalance, dest)) = Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout) { Self::deposit_event(Event::::Rewarded { stash: ledger.stash, + dest, amount: imbalance.peek(), }); total_imbalance.subsume(imbalance); @@ -259,11 +260,14 @@ impl Pallet { let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; // We can now make nominator payout: - if let Some(imbalance) = Self::make_payout(&nominator.who, nominator_reward) { + if let Some((imbalance, dest)) = Self::make_payout(&nominator.who, nominator_reward) { // Note: this logic does not count payouts for `RewardDestination::None`. nominator_payout_count += 1; - let e = - Event::::Rewarded { stash: nominator.who.clone(), amount: imbalance.peek() }; + let e = Event::::Rewarded { + stash: nominator.who.clone(), + dest, + amount: imbalance.peek(), + }; Self::deposit_event(e); total_imbalance.subsume(imbalance); } @@ -293,9 +297,11 @@ impl Pallet { /// Actually make a payment to a staker. This uses the currency's reward function /// to pay the right payee for the given staker account. - fn make_payout(stash: &T::AccountId, amount: BalanceOf) -> Option> { - let dest = Self::payee(stash); - match dest { + fn make_payout( + stash: &T::AccountId, + amount: BalanceOf, + ) -> Option<(PositiveImbalanceOf, RewardDestination)> { + let maybe_imbalance = match Self::payee(stash) { RewardDestination::Controller => Self::bonded(stash) .map(|controller| T::Currency::deposit_creating(&controller, amount)), RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), @@ -311,7 +317,8 @@ impl Pallet { RewardDestination::Account(dest_account) => Some(T::Currency::deposit_creating(&dest_account, amount)), RewardDestination::None => None, - } + }; + maybe_imbalance.map(|imbalance| (imbalance, Self::payee(stash))) } /// Plan a new session potentially trigger a new era. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index c6c75326b80..0bcf932d90b 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -664,8 +664,12 @@ pub mod pallet { /// The era payout has been set; the first balance is the validator-payout; the second is /// the remainder from the maximum amount of reward. EraPaid { era_index: EraIndex, validator_payout: BalanceOf, remainder: BalanceOf }, - /// The nominator has been rewarded by this amount. - Rewarded { stash: T::AccountId, amount: BalanceOf }, + /// The nominator has been rewarded by this amount to this destination. + Rewarded { + stash: T::AccountId, + dest: RewardDestination, + amount: BalanceOf, + }, /// A staker (validator or nominator) has been slashed by the given amount. Slashed { staker: T::AccountId, amount: BalanceOf }, /// A slash for the given validator, for the given percentage of their stake, at the given diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index fd7dabac74d..78183cfde92 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -3759,6 +3759,16 @@ fn test_payout_stakers() { ); assert!(RewardOnUnbalanceWasCalled::get()); + // `Rewarded` events are being executed. + assert!(matches!( + staking_events_since_last_call().as_slice(), + &[ + .., + Event::Rewarded { stash: 1037, dest: RewardDestination::Controller, amount: 108 }, + Event::Rewarded { stash: 1036, dest: RewardDestination::Controller, amount: 108 } + ] + )); + // Top 64 nominators of validator 11 automatically paid out, including the validator // Validator payout goes to controller. assert!(Balances::free_balance(&11) > balance); -- GitLab From 122086d3d582b1e86190507f3a377667e66c729c Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 18 Sep 2023 21:32:19 +0100 Subject: [PATCH 180/633] Revert #1409 partially (#1603) Futures channels that are used by default has a side effect of `Sender::Clone` that efficiently increases the capacity of the bounded channel by one. This PR fixes the undesired backpressure removal that was caused by the #1409. This issue has been discovered by @sandreim during Versi testing and needs to be treated as critical that should not be included in any release without this reversion. This PR reverts the original behaviour. --- polkadot/node/network/bridge/src/rx/mod.rs | 63 +++------------------- 1 file changed, 8 insertions(+), 55 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index e1125ebc904..82c67061d9a 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -20,10 +20,7 @@ use super::*; use always_assert::never; use bytes::Bytes; -use futures::{ - future::BoxFuture, - stream::{BoxStream, FuturesUnordered, StreamExt}, -}; +use futures::stream::{BoxStream, StreamExt}; use parity_scale_codec::{Decode, DecodeAll}; use sc_network::Event as NetworkEvent; @@ -1044,65 +1041,21 @@ fn dispatch_collation_event_to_all_unbounded( } } -fn send_or_queue_validation_event( - event: E, - sender: &mut Sender, - delayed_queue: &FuturesUnordered>, -) where - E: Send + 'static, - Sender: overseer::NetworkBridgeRxSenderTrait + overseer::SubsystemSender, -{ - match sender.try_send_message(event) { - Ok(()) => {}, - Err(overseer::TrySendError::Full(event)) => { - let mut sender = sender.clone(); - delayed_queue.push(Box::pin(async move { - sender.send_message(event).await; - })); - }, - Err(overseer::TrySendError::Closed(_)) => { - panic!( - "NetworkBridgeRxSender is closed when trying to send event of type: {}", - std::any::type_name::() - ); - }, - } -} - async fn dispatch_validation_events_to_all( events: I, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, - metrics: &Metrics, + _metrics: &Metrics, ) where I: IntoIterator>, I::IntoIter: Send, { - let delayed_messages: FuturesUnordered> = FuturesUnordered::new(); - - // Fast path for sending events to subsystems, if any subsystem's queue is full, we hold - // the slow path future in the `delayed_messages` queue. for event in events { - if let Ok(msg) = event.focus().map(StatementDistributionMessage::from) { - send_or_queue_validation_event(msg, sender, &delayed_messages); - } - if let Ok(msg) = event.focus().map(BitfieldDistributionMessage::from) { - send_or_queue_validation_event(msg, sender, &delayed_messages); - } - if let Ok(msg) = event.focus().map(ApprovalDistributionMessage::from) { - send_or_queue_validation_event(msg, sender, &delayed_messages); - } - if let Ok(msg) = event.focus().map(GossipSupportMessage::from) { - send_or_queue_validation_event(msg, sender, &delayed_messages); - } - } - - let delayed_messages_count = delayed_messages.len(); - metrics.on_delayed_rx_queue(delayed_messages_count); - - if delayed_messages_count > 0 { - // Here we wait for all the delayed messages to be sent. - let _timer = metrics.time_delayed_rx_events(); // Dropped after `await` is completed - let _: Vec<()> = delayed_messages.collect().await; + sender + .send_messages(event.focus().map(StatementDistributionMessage::from)) + .await; + sender.send_messages(event.focus().map(BitfieldDistributionMessage::from)).await; + sender.send_messages(event.focus().map(ApprovalDistributionMessage::from)).await; + sender.send_messages(event.focus().map(GossipSupportMessage::from)).await; } } -- GitLab From 6079b6dd3aaba56ef257111fda74a57a800f16d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 19 Sep 2023 12:07:21 +0100 Subject: [PATCH 181/633] Remove Polkadot & Kusama native runtime (#1304) This pull request removes the Polkadot and Kusama native runtime from the polkadot node. This brings some implications with it: There are no more kusama/polkadot-dev chain specs available. We will need to write some tooling in the fellowship repo to provide them easily. The try-runtime job for polkadot & kusama is not available anymore as we don't have the dev chain specs anymore. Certain benchmarking commands will also not work until we migrate them to use a runtime api. Some crates in utils are still depending on the polkadot/kusama native runtime that will also need to be fixed. Port of: https://github.com/paritytech/polkadot/pull/7467 --- .gitlab/pipeline/short-benchmarks.yml | 14 +- Cargo.lock | 5 - polkadot/Cargo.toml | 6 +- polkadot/cli/Cargo.toml | 6 +- polkadot/cli/src/command.rs | 47 +- polkadot/cli/src/error.rs | 6 + polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 21 +- polkadot/node/service/src/benchmarking.rs | 166 +---- polkadot/node/service/src/chain_spec.rs | 667 +----------------- polkadot/node/service/src/lib.rs | 6 +- polkadot/node/test/service/Cargo.toml | 1 + polkadot/node/test/service/src/chain_spec.rs | 14 +- polkadot/tests/benchmark_block.rs | 31 +- polkadot/tests/benchmark_extrinsic.rs | 2 +- polkadot/tests/benchmark_overhead.rs | 10 +- polkadot/tests/common.rs | 39 +- polkadot/tests/purge_chain_works.rs | 189 +++-- .../tests/running_the_node_and_interrupt.rs | 17 +- 19 files changed, 193 insertions(+), 1056 deletions(-) diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 7b7704ee66d..5b0ea276773 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,12 @@ short-benchmark-polkadot: &short-bench - job: build-short-benchmark artifacts: true variables: - RUNTIME: polkadot + RUNTIME: westend 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 diff --git a/Cargo.lock b/Cargo.lock index 670d9c9e771..9dfff599300 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12779,7 +12779,6 @@ dependencies = [ "futures", "hex-literal", "is_executable", - "kusama-runtime-constants", "kvdb", "kvdb-rocksdb", "log", @@ -12825,9 +12824,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 +12879,6 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", - "staging-kusama-runtime", "substrate-prometheus-endpoint", "tempfile", "thiserror", diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index e4494b1abb2..aacc6ad405c 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" } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index a9631fb9a7d..83fd64759b7 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -67,11 +67,7 @@ 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" ] diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index a081e1b5181..19437ce8753 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 { @@ -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,17 +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<()> { @@ -471,8 +445,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 +481,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| { diff --git a/polkadot/cli/src/error.rs b/polkadot/cli/src/error.rs index a4591e2508c..62ee4d13907 100644 --- a/polkadot/cli/src/error.rs +++ b/polkadot/cli/src/error.rs @@ -58,3 +58,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/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 08d203281cf..9fa22aef4dc 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" } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 667f9b86d3e..ee092e27733 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,30 +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", ] diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index cfe1c873c05..400daf1aee3 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 1e5aaa807b8..7fd9ce61c95 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,7 +80,7 @@ pub type WestendChainSpec = service::GenericChainSpec Result { - PolkadotChainSpec::from_json_bytes(&include_bytes!("../chain-specs/polkadot.json")[..]) +pub fn polkadot_config() -> Result { + GenericChainSpec::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 +142,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 +181,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, @@ -539,214 +439,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], @@ -1062,39 +754,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 { @@ -1239,12 +898,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 +916,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( @@ -1612,26 +1096,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 +1116,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 { @@ -1779,67 +1205,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( diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 75e853d0ef8..5286631fbbb 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")] diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index ce4148b459e..1924418a485 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 9aadd7d203c..bedb1250b2a 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/tests/benchmark_block.rs b/polkadot/tests/benchmark_block.rs index bc91b31bc7b..99f95ef611a 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 e701fd9c923..529eb29362d 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 295479594eb..b0912225347 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 940a0c6f18d..10859ead5fe 100644 --- a/polkadot/tests/common.rs +++ b/polkadot/tests/common.rs @@ -16,49 +16,25 @@ 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 { @@ -67,6 +43,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 3e9a3781478..831155fb4d7 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,95 @@ 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()); + assert!(tmpdir.path().join("chains/rococo_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/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()); + assert!(tmpdir.path().join("chains/rococo_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/rococo_dev").exists()); + assert!(!tmpdir.path().join("chains/rococo_dev/paritydb/full").exists()); + // Parachains removal requires calling "purge-chain --parachains". + assert!(tmpdir.path().join("chains/rococo_dev/paritydb/parachains").exists()); + }) + .await; } diff --git a/polkadot/tests/running_the_node_and_interrupt.rs b/polkadot/tests/running_the_node_and_interrupt.rs index d3935cbb02a..079c34e0421 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}", ); } -- GitLab From f3061c14bf51867400e56deb8248094ab37f3f0c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:29:22 +0300 Subject: [PATCH 182/633] archive: Fetch body, genesisHash and header (#1560) This PR lays the foundation for implementing the archive RPC methods. The methods implemented by this PR: - archive_unstable_body: Fetch the block's body (a vector of hex-encoded scale-encoded extrinsics) from a given block hash - archive_unstable_genesisHash: Fetch the genesis hash - archive_unstable_header: Fetch the header from a given block hash Added unit tests for the methods. This PR is implementing the methods without exposing them to the RPC layer; which are to be exposed by a follow-up PR. Closes: https://github.com/paritytech/polkadot-sdk/issues/1509 Closes: https://github.com/paritytech/polkadot-sdk/issues/1514 @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- .../client/rpc-spec-v2/src/archive/api.rs | 56 +++++++++ .../client/rpc-spec-v2/src/archive/archive.rs | 86 +++++++++++++ .../client/rpc-spec-v2/src/archive/mod.rs | 31 +++++ .../client/rpc-spec-v2/src/archive/tests.rs | 113 ++++++++++++++++++ substrate/client/rpc-spec-v2/src/lib.rs | 1 + 5 files changed, 287 insertions(+) create mode 100644 substrate/client/rpc-spec-v2/src/archive/api.rs create mode 100644 substrate/client/rpc-spec-v2/src/archive/archive.rs create mode 100644 substrate/client/rpc-spec-v2/src/archive/mod.rs create mode 100644 substrate/client/rpc-spec-v2/src/archive/tests.rs 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 00000000000..ca94779c887 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/api.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 . + +//! API trait of the archive methods. + +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>; +} 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 00000000000..4fb2e5671d3 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs @@ -0,0 +1,86 @@ +// 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 super::ArchiveApiServer; +use crate::chain_head::hex_string; +use codec::Encode; +use jsonrpsee::core::{async_trait, RpcResult}; +use sc_client_api::{Backend, BlockBackend, BlockchainEvents, ExecutorProvider, StorageProvider}; +use sp_api::CallApiAt; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_runtime::traits::Block as BlockT; +use std::{marker::PhantomData, sync::Arc}; + +/// An API for archive RPC calls. +pub struct Archive, Block: BlockT, Client> { + /// Substrate client. + client: 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, genesis_hash: GenesisHash) -> Self { + let genesis_hash = hex_string(&genesis_hash.as_ref()); + Self { client, genesis_hash, _phantom: PhantomData } + } +} + +#[async_trait] +impl ArchiveApiServer for Archive +where + Block: BlockT + 'static, + Block::Header: Unpin, + 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()))) + } +} 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 00000000000..767f658ecd7 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/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 archive API. +//! +//! # Note +//! +//! Methods are prefixed by `archive`. + +#[cfg(test)] +mod tests; + +pub mod api; +pub mod archive; + +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 00000000000..bc75fc749ac --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -0,0 +1,113 @@ +// 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; + +use super::{archive::Archive, *}; + +use codec::{Decode, Encode}; +use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; +use sc_block_builder::BlockBuilderProvider; + +use sp_consensus::BlockOrigin; +use std::sync::Arc; +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 client = Arc::new(builder.build()); + + let api = Archive::new(client.clone(), 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); +} diff --git a/substrate/client/rpc-spec-v2/src/lib.rs b/substrate/client/rpc-spec-v2/src/lib.rs index 7c22ef5d523..9a455c5984a 100644 --- a/substrate/client/rpc-spec-v2/src/lib.rs +++ b/substrate/client/rpc-spec-v2/src/lib.rs @@ -23,6 +23,7 @@ #![warn(missing_docs)] #![deny(unused_crate_dependencies)] +pub mod archive; pub mod chain_head; pub mod chain_spec; pub mod transaction; -- GitLab From 2d96c8d27cbb54c3bba4699b22603e0f7997c146 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Tue, 19 Sep 2023 13:46:28 +0200 Subject: [PATCH 183/633] Add Method to Establish HRMP Channels Among System Parachains (#1473) Solution to establish HRMP channels between system parachains. --------- Co-authored-by: Muharem Ismailov --- .../src/tests/hrmp_channels.rs | 14 -- .../src/tests/hrmp_channels.rs | 14 -- .../src/weights/runtime_parachains_hrmp.rs | 42 ++++ polkadot/runtime/parachains/src/hrmp.rs | 212 ++++++++++++++++-- .../parachains/src/hrmp/benchmarking.rs | 73 +++++- polkadot/runtime/parachains/src/hrmp/tests.rs | 194 +++++++++++++--- .../src/weights/runtime_parachains_hrmp.rs | 42 ++++ .../src/weights/runtime_parachains_hrmp.rs | 42 ++++ .../src/weights/runtime_parachains_hrmp.rs | 42 ++++ 9 files changed, 592 insertions(+), 83 deletions(-) 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 index 623b3ff599c..7bb64333db5 100644 --- 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 @@ -159,12 +159,6 @@ fn force_open_hrmp_channel_for_system_para_works() { // 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, @@ -179,14 +173,6 @@ fn force_open_hrmp_channel_for_system_para_works() { 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( 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 index a1423f2ea90..a6286c619f6 100644 --- 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 @@ -159,12 +159,6 @@ fn force_open_hrmp_channel_for_system_para_works() { // 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, @@ -179,14 +173,6 @@ fn force_open_hrmp_channel_for_system_para_works() { 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( diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs index c13a8413e41..f2bc2aa2b08 100644 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/kusama/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/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index cdb38ba6a8e..3f0a5e0830c 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. @@ -279,6 +290,12 @@ pub mod pallet { /// An HRMP channel was opened via Root origin. /// `[sender, recipient, proposed_max_capacity, proposed_max_message_size]` HrmpChannelForceOpened(ParaId, ParaId, u32, u32), + /// An HRMP channel was opened between two system chains. + /// `[sender, recipient, proposed_max_capacity, proposed_max_message_size]` + HrmpSystemChannelOpened(ParaId, ParaId, u32, u32), + /// An HRMP channel's deposits were updated. + /// `[sender, recipient]` + OpenChannelDepositsUpdated(ParaId, ParaId), } #[pallet::error] @@ -321,6 +338,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. @@ -600,8 +619,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,7 +647,8 @@ 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( @@ -640,6 +660,146 @@ pub mod pallet { 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, + max_capacity, + 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 +977,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 +988,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 +1337,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 +1385,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 +1403,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 +1425,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 +1458,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 3fe347a7bcb..9ffa264a7dc 100644 --- a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs +++ b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs @@ -304,14 +304,13 @@ frame_benchmarking::benchmarks! { 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; @@ -351,6 +350,72 @@ frame_benchmarking::benchmarks! { Event::::HrmpChannelForceOpened(sender_id, recipient_id, capacity, message_size).into() ); } + + establish_system_channel { + let sender_id: ParaId = 1u32.into(); + let recipient_id: ParaId = 2u32.into(); + + let caller: T::AccountId = frame_benchmarking::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; + }: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id) + verify { + assert_last_event::( + Event::::HrmpSystemChannelOpened(sender_id, recipient_id, capacity, message_size).into() + ); + } + + 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 = frame_benchmarking::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); + }: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id) + verify { + assert_last_event::( + Event::::OpenChannelDepositsUpdated(sender_id, 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()); + } } frame_benchmarking::impl_benchmark_test_suite!( diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 8cfaf48d10e..236745b7cc3 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. @@ -171,13 +175,16 @@ 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(); @@ -193,14 +200,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. @@ -240,11 +252,127 @@ 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(para_a, para_b, 2, 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); @@ -275,8 +403,8 @@ fn close_channel_works() { #[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 +486,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 +508,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 +572,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 +630,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 +660,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 +693,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 +733,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 +771,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 +803,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/polkadot/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs index 82d8c30baca..73a08d33eed 100644 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs @@ -292,4 +292,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/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs index 9f1cf65efa6..417820e6627 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/westend/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs index e6ff97fa087..9beb15303d8 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)) + } } -- GitLab From cdbdbc7546b34907a0c5843699d4287179b692fe Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 20 Sep 2023 01:27:42 +1200 Subject: [PATCH 184/633] allow governance body on parachain to have sovereign account (#1291) The goal is to allow Fellowship on Collective chain to have a sovereign account on Polkadot so that we can add it as an identity registrar. This will allow Fellows origin to be able to provide judgements for Fellowship members. This currently allow any body on any parachain including non system parachains to have sovereign account. I cannot think of any reason why that may be an issue but let me know if I should change it to filter only system parachains. [This](https://gist.github.com/xlc/ec61bfa4e9f6d62da27d30141ad2c72b) is the testing script. Original PR: https://github.com/paritytech/polkadot/pull/7518 --- polkadot/runtime/kusama/src/xcm_config.rs | 11 +++++++---- polkadot/runtime/polkadot/src/xcm_config.rs | 10 ++++++---- polkadot/runtime/rococo/src/xcm_config.rs | 19 +++++++++++++------ polkadot/runtime/westend/src/xcm_config.rs | 18 ++++++++++++------ polkadot/xcm/xcm-builder/src/lib.rs | 4 ++-- .../xcm-builder/src/location_conversion.rs | 11 +++++++++++ 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/polkadot/runtime/kusama/src/xcm_config.rs b/polkadot/runtime/kusama/src/xcm_config.rs index 59ea937e11c..40ecc83fe64 100644 --- a/polkadot/runtime/kusama/src/xcm_config.rs +++ b/polkadot/runtime/kusama/src/xcm_config.rs @@ -37,10 +37,11 @@ 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, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal, + DescribeFamily, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, + OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; parameter_types! { @@ -67,6 +68,8 @@ pub type SovereignAccountOf = ( 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 diff --git a/polkadot/runtime/polkadot/src/xcm_config.rs b/polkadot/runtime/polkadot/src/xcm_config.rs index c7b15f7256b..1110c0d8eb9 100644 --- a/polkadot/runtime/polkadot/src/xcm_config.rs +++ b/polkadot/runtime/polkadot/src/xcm_config.rs @@ -40,10 +40,10 @@ 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, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal, + DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; parameter_types! { @@ -68,6 +68,8 @@ pub type SovereignAccountOf = ( 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 interact with the runtime assets from the point diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 288ee8400dc..445cb801435 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -36,10 +36,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, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, + TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, + WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -51,8 +52,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`. diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index afa0733b4c9..92dcee150aa 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -35,10 +35,10 @@ 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, IsChildSystemParachain, IsConcrete, MintLocation, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -54,8 +54,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: diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index e3f91040963..26f2aadadf3 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -32,8 +32,8 @@ pub use location_conversion::ForeignChainAliasAccount; pub use location_conversion::{ Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32, ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal, - DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeFamily, DescribeLocation, - DescribePalletTerminal, DescribeTerminus, GlobalConsensusConvertsFor, + DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeBodyTerminal, DescribeFamily, + DescribeLocation, DescribePalletTerminal, DescribeTerminus, GlobalConsensusConvertsFor, GlobalConsensusParachainConvertsFor, HashedDescription, ParentIsPreset, SiblingParachainConvertsVia, }; diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index ec23116e0e8..4a5fbbb123b 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -86,11 +86,22 @@ impl DescribeLocation for DescribeAccountKey20Terminal { 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, + DescribeBodyTerminal, ); pub struct DescribeFamily(PhantomData); -- GitLab From 771c3fbde7ba3849298d6fc7df390fc6b5a04d2f Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Wed, 20 Sep 2023 07:28:05 +0200 Subject: [PATCH 185/633] Disable Calls to Identity Pallet (#1476) This PR filters calls from the Identity pallet from all Relay Chain runtimes as preparation to move the identity state and logic to a system parachain within each network. After this change is deployed to a runtime, no more changes such as adding new sub-identities will be possible. The frozen state will be part of the genesis state of the system chain. After the system chain launches, the pallet and all state will be removed from each Relay Chain. Applications and UIs that render display information from this pallet will need to read from the system chain when it launches. --- polkadot/runtime/kusama/src/lib.rs | 21 +++++++++++-------- polkadot/runtime/polkadot/src/lib.rs | 19 +++++++++++++---- polkadot/runtime/rococo/src/lib.rs | 17 ++++++++------- polkadot/runtime/westend/src/lib.rs | 18 +++++++++++++--- .../xcm/xcm-builder/src/universal_exports.rs | 8 +++++-- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 5cf2b3b83b1..8d8bd4baacf 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -63,9 +63,9 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, + ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -158,11 +158,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(_c: &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(_)) } } @@ -172,7 +175,7 @@ parameter_types! { } impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index da27771af40..5956b0e155b 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -47,9 +47,9 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, + ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -149,13 +149,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 = 0; } impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 6446ac4f00c..7046c4640c0 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -60,7 +60,7 @@ use beefy_primitives::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - fungible::HoldConsideration, Contains, EitherOfDiverse, InstanceFilter, + fungible::HoldConsideration, Contains, EitherOfDiverse, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, }, @@ -135,11 +135,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 +152,7 @@ parameter_types! { } impl frame_system::Config for Runtime { - type BaseCallFilter = BaseFilter; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type DbWeight = RocksDbWeight; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 5cb6cbbab20..9af18b5be2b 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -29,8 +29,9 @@ use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, Se use frame_support::{ construct_runtime, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, InstanceFilter, KeyOwnerProofSystem, - LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EverythingBut, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, + WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -141,13 +142,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; diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index d1b8c8c721f..a24631ffa94 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -171,7 +171,9 @@ impl Date: Wed, 20 Sep 2023 15:56:43 +0300 Subject: [PATCH 186/633] Refactor availability-recovery strategies (#1457) Refactors availability-recovery strategies to allow for easily adding new hotpaths and failover mechanisms. The new interface allows for chaining multiple `RecoveryStrategy`-es together, to cleanly express the relationship between them and share state and code where neccessary/possible: This was done in order to aid in implementing new hotpaths like [systematic chunks recovery](https://github.com/paritytech/polkadot-sdk/issues/598) and [fetching from approval checkers](https://github.com/paritytech/polkadot-sdk/issues/575). Thanks to this design, intermediate state can be shared between the strategies. For example, if the systematic chunks recovery retrieved less than the needed amount of chunks, pass them over to the next FetchChunks strategy, which will only need to recover the remaining number of chunks. Draft example of how a systematic chunk recovery strategy would look: https://github.com/paritytech/polkadot-sdk/commit/667d870bdf1470525d66c13929d5eac7249dd995 (notice how easy it was to add and reuse code) Note that this PR doesn't itself add any new strategy, it should fully preserve backwards compatiblity in terms of functionality. Follow-up PRs to add new strategies will come. --- Cargo.lock | 1 + .../network/availability-recovery/Cargo.toml | 1 + .../network/availability-recovery/src/lib.rs | 824 +++-------------- .../network/availability-recovery/src/task.rs | 830 ++++++++++++++++++ .../availability-recovery/src/tests.rs | 51 +- 5 files changed, 953 insertions(+), 754 deletions(-) create mode 100644 polkadot/node/network/availability-recovery/src/task.rs diff --git a/Cargo.lock b/Cargo.lock index 9dfff599300..ce0d7011204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11508,6 +11508,7 @@ name = "polkadot-availability-recovery" version = "1.0.0" dependencies = [ "assert_matches", + "async-trait", "env_logger 0.9.3", "fatality", "futures", diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 07ff09c7e70..42c3abef547 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 99f42f4bf9f..e2146981da9 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 00000000000..d5bc2da8494 --- /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 60c2d38ab31..63ccf0e94f9 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()); -} -- GitLab From e7d29bc349881d6f62bbe7079a2f7429649cbffd Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 20 Sep 2023 13:56:57 +0100 Subject: [PATCH 187/633] XCM: Deprecate old functions (#1645) Two old functions should be deprecated and have their code altered in line with capabilities of XCMv2 and above. This means we can use the proper `Unlimited` form of weight limit rather than guessing weight from the local chain. --- polkadot/xcm/pallet-xcm/src/lib.rs | 48 ++++++---------------------- polkadot/xcm/pallet-xcm/src/tests.rs | 4 +-- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 9dfb63c2c9c..5acd093d3bc 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -787,6 +787,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 +832,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 +883,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - None, + Unlimited, ) } @@ -1055,7 +1059,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - Some(weight_limit), + weight_limit, ) } @@ -1109,7 +1113,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - Some(weight_limit), + weight_limit, ) } @@ -1197,7 +1201,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 +1222,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 +1245,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 +1266,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 486887598c7..5d8aee8d665 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 }, ]), )] -- GitLab From 1517eb8dd47722830c56ab1498806707851f2540 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:56:40 +0200 Subject: [PATCH 188/633] Bump the known_good_semver group with 2 updates (#1620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps the known_good_semver group with 2 updates: [clap](https://github.com/clap-rs/clap) and [syn](https://github.com/dtolnay/syn). Updates `clap` from 4.4.3 to 4.4.4
Release notes

Sourced from clap's releases.

v4.4.4

[4.4.4] - 2023-09-18

Internal

  • Update terminal_size to 0.3
Changelog

Sourced from clap's changelog.

[4.4.4] - 2023-09-18

Internal

  • Update terminal_size to 0.3
Commits

Updates `syn` from 2.0.36 to 2.0.37
Release notes

Sourced from syn's releases.

2.0.37

  • Work around incorrect future compatibility warning in rustc 1.74.0-nightly
Commits
  • 9681088 Release 2.0.37
  • fbe3bc2 Work around unknown_lints warning on rustc older than 1.64
  • 75cf912 Ignore more repr_transparent_external_private_fields
  • 299c782 Ignore false repr_transparent_external_private_fields FCW in generated code
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 162 +++++++++--------- cumulus/client/cli/Cargo.toml | 2 +- .../parachain-system/proc-macro/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 42 files changed, 123 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce0d7011204..2ed92d3240b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,7 +1138,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -1160,7 +1160,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -1177,7 +1177,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -1351,7 +1351,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -2333,7 +2333,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.3", + "clap 4.4.4", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2463,9 +2463,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.3" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" dependencies = [ "clap_builder", "clap_derive 4.4.2", @@ -2473,9 +2473,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" dependencies = [ "anstream", "anstyle", @@ -2489,7 +2489,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.4", ] [[package]] @@ -2514,7 +2514,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -3085,7 +3085,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.3", + "clap 4.4.4", "criterion-plot", "futures", "is-terminal", @@ -3250,7 +3250,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3574,7 +3574,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -3935,7 +3935,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.3", + "clap 4.4.4", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4057,7 +4057,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4097,7 +4097,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4114,7 +4114,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4412,7 +4412,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4474,7 +4474,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.36", + "syn 2.0.37", "termcolor", "toml 0.7.6", "walkdir", @@ -4695,7 +4695,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4706,7 +4706,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -4851,7 +4851,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -5141,7 +5141,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.3", + "clap 4.4.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -5207,7 +5207,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.36", + "syn 2.0.37", "trybuild", ] @@ -5233,7 +5233,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5359,7 +5359,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -5370,7 +5370,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -5379,7 +5379,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -5602,7 +5602,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -7617,7 +7617,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -7631,7 +7631,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -7642,7 +7642,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -7653,7 +7653,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -8140,7 +8140,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.4.3", + "clap 4.4.4", "derive_more", "fs_extra", "futures", @@ -8177,7 +8177,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.4.3", + "clap 4.4.4", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8303,7 +8303,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8357,7 +8357,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "generate-bags", "kitchensink-runtime", ] @@ -8366,7 +8366,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8409,7 +8409,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "flate2", "fs_extra", "glob", @@ -9339,7 +9339,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -10410,7 +10410,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -10800,7 +10800,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11277,7 +11277,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -11318,7 +11318,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -11537,7 +11537,7 @@ dependencies = [ name = "polkadot-cli" version = "1.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "frame-benchmarking-cli", "futures", "log", @@ -12357,7 +12357,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.3", + "clap 4.4.4", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -12967,7 +12967,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.3", + "clap 4.4.4", "color-eyre", "futures", "futures-timer", @@ -13113,7 +13113,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "generate-bags", "polkadot-runtime", "sp-io", @@ -13293,7 +13293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -13375,7 +13375,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -13421,7 +13421,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -13812,7 +13812,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -13875,7 +13875,7 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "frame-system", "kusama-runtime-constants", "log", @@ -14575,7 +14575,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -14584,7 +14584,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.4.3", + "clap 4.4.4", "fdlimit", "futures", "futures-timer", @@ -15686,7 +15686,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "fs4", "log", "sc-client-db", @@ -15786,7 +15786,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -16145,7 +16145,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -16211,7 +16211,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -16643,7 +16643,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -17043,7 +17043,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -17087,7 +17087,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -17225,7 +17225,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17318,7 +17318,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -17558,7 +17558,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -17942,7 +17942,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "sc-cli", ] @@ -17984,7 +17984,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "frame-support", "frame-system", "sc-cli", @@ -18333,9 +18333,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.36" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -18443,7 +18443,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "futures", "futures-timer", "log", @@ -18491,7 +18491,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.4", "futures", "futures-timer", "log", @@ -18580,7 +18580,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -18760,7 +18760,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -18941,7 +18941,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -18984,7 +18984,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -19137,7 +19137,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.3", + "clap 4.4.4", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -19533,7 +19533,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -19567,7 +19567,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20703,7 +20703,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] @@ -20822,7 +20822,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.37", ] [[package]] diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 15f28d73b36..c45b669fc6d 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.4", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index ee0943bb99e..a1510847fc2 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.37" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 6de57b185e4..223a78dacc4 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.4", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 5591e80317c..ac8ad53b524 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.4", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index b8469cb66a7..5285376f3d5 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.4", 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/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 83fd64759b7..53961c90a2a 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.4", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.48" futures = "0.3.21" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index be302e46ad9..83d064cadbe 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.37", 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 9fa22aef4dc..42dd4af73c1 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.4", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index a2ce15c21db..fcbba9bbe21 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.4", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 9a5e580af1b..3fbed4046bd 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.4", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 99948cb68b1..d270cabd3f0 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.4", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index ed49f77bb81..cb9547ac7dc 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -19,6 +19,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.4", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 6beaa1d667f..1ff73c64780 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.37" Inflector = "0.11.4" diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index b510ed34c23..35654e7d564 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.4", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 05c13e312b2..33560bca492 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.4", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 84d8de11a35..c47f8a5c3e5 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.4", 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"] } @@ -135,7 +135,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.4", 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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index f28ceb45957..06e9674117e 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.4", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index c626a1612eb..f564ff19af0 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.4", features = ["derive"] } rand = "0.8" node-cli = { path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 8a5f4ec49c5..4e8cb606c94 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.4", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index f0ad4c68d1f..202817438b7 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.37" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index b781e8782ec..cfdcb39b1fa 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.4", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 6d425749a91..7538f5ba602 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.4", 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 270f34b6d04..f18e0aacd37 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.37", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index ccc80a2eba4..a04f5544067 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.37", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 1b432204470..39e535c6c3e 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.37", 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 fe84c4c0ef9..6ac09dd45c6 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.4", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 7646bbc9a55..484afb6136b 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.37", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index e1606854605..6381e430f2b 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ 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.37", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index fb0a1b51cbc..7589fa353d1 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.37", 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 747d3bacd42..5bf67d43d06 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.37", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 71f1ff95d55..de5ddcf9dac 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.37", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index fce09b452e5..64b46ab9c19 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.37", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 689a1250569..9d3930ac257 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.37" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 1e9f0517df1..eeb9deebb71 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.4", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index fe06c56d5a1..5569e31c936 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.37", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 3cd1b7a3a76..cc28b8f176b 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.37", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 63611ae8da6..c0e02758724 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.4", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 017e4b4d503..9ba22e24faa 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.4", 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/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 89aef533865..5a3365dc900 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.4", 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 b06674a62cb..e1490aa363c 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.4", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index c736c3f6cc5..3f693ca6c82 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.4", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -- GitLab From bb792af268fe60f8489494ce25acb4dab3cfe7e4 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 20 Sep 2023 15:28:28 +0100 Subject: [PATCH 189/633] Preimage: Check that at least one is upgraded (#1648) Sanity check. --- substrate/frame/preimage/src/benchmarking.rs | 2 +- substrate/frame/preimage/src/lib.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/preimage/src/benchmarking.rs b/substrate/frame/preimage/src/benchmarking.rs index d7c643ff904..d0c3404f40a 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 e603f1a32e6..4dda0207e62 100644 --- a/substrate/frame/preimage/src/lib.rs +++ b/substrate/frame/preimage/src/lib.rs @@ -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; -- GitLab From 41e38b2c093a17ef1faa6fad7eebc703683c010a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Wed, 20 Sep 2023 19:11:42 +0100 Subject: [PATCH 190/633] Fix minor typos and file name in contributing docs (#1651) # Description *Please include a summary of the changes and the related issue. Please also include relevant motivation and context, including:* - What does this PR do? This PR fixes two minor typos in the contributing top level docs, and fixes a broken link to another file. - Why are these changes needed? While reading the guidelines I noticed two small typos and a broken link to the documentation guidelines in the same directory. - How were these changes implemented and what do they affect? Both typos were fixed. The file has been renamed from `DOCUMENTATION_GUIDELINE.md` to `DOCUMENTATION_GUIDELINES.md` to match the link, as the link seems correct vs the filename. There are no other references to this file within this repo. There are no open issues related to this --- docs/CONTRIBUTING.md | 4 ++-- ...DOCUMENTATION_GUIDELINE.md => DOCUMENTATION_GUIDELINES.md} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename docs/{DOCUMENTATION_GUIDELINE.md => DOCUMENTATION_GUIDELINES.md} (100%) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index d134188e25d..245369b7020 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,4 @@ 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 the `.maintain/update-rust-stable diff --git a/docs/DOCUMENTATION_GUIDELINE.md b/docs/DOCUMENTATION_GUIDELINES.md similarity index 100% rename from docs/DOCUMENTATION_GUIDELINE.md rename to docs/DOCUMENTATION_GUIDELINES.md -- GitLab From d6b3fc0dbb00a7478558041effae9eeb5b7a1970 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 20 Sep 2023 15:37:52 -0400 Subject: [PATCH 191/633] upgrade to docify v0.2.4 (#1653) Upgrades to docify v0.2.4 which adds support for exporting trait and impl items in addition to regular items. This fixes @liamaharon's https://github.com/sam0x17/docify/issues/9 issue. See the release notes for more information: https://github.com/sam0x17/docify/releases/tag/v0.2.4 --- Cargo.lock | 8 ++++---- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ed92d3240b..9d3535bdf8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4455,18 +4455,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", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 21cdb4f8983..f4644890e2b 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/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 224067d4fa7..85548c6600d 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/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 9fbc3fdb2c6..eee099fff5f 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/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 7fa14e861e8..e81b4dbeff7 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/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index bdd4252414a..a4934346d5d 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/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 62a7b5e41fe..5cb5d6d12ab 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -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/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 6759d90aaf4..291f6b1cf59 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" } -- GitLab From 9e403629d590abcd57c13f4010eb0714a4ee6642 Mon Sep 17 00:00:00 2001 From: Muharem Date: Wed, 20 Sep 2023 21:55:56 +0200 Subject: [PATCH 192/633] The Ambassador Program (#1308) The Ambassador Program on Polkadot Collectives Parachain The Polkadot Ambassador Program has existed for a while; more information can be found [here](https://wiki.polkadot.network/docs/ambassadors). In this PR, the program is being brought on chain. ### On Chain Structure The on-chain program consists of nine ranks, divided into four categories ([full list](https://github.com/paritytech/cumulus/blob/c238fb26b75569a11abb57437fd14acd26e05f18/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs#L52)): - Ambassadors (1-2 tiers) - Senior Ambassadors (3-4 tiers) - Head Ambassadors (5-7 tiers) - Master Ambassadors (8-9 tiers) Each rank has a corresponding `Origin` (e.g., `HeadAmbassadorsTier5` - [full list](https://github.com/paritytech/cumulus/blob/c238fb26b75569a11abb57437fd14acd26e05f18/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs#L35)), which represents the collective voice of members of that rank and above. ### Referendum The `AmbassadorReferenda` instance of [referenda pallet](https://docs.rs/pallet-referenda/latest/pallet_referenda/) consists of [nine tracks](https://github.com/paritytech/cumulus/blob/c238fb26b75569a11abb57437fd14acd26e05f18/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs#L51), each corresponding to an `Origin`. A referendum taken on `senior ambassador tier 4` track invites all members from rank 4 or above to vote and commands `SeniorAmbassadors` `Origin`. Every member gets one vote plus an additional vote for every excess rank. The referendum proposal can be submitted by any member of a senior rank or above. ### Membership Management Initial members will be brought on chain via migration, with subsequent member management handled through the `AmbassadorCollective` instance of [ranked collective pallet](https://docs.rs/pallet-ranked-collective/latest/pallet_ranked_collective/). Both `Root` and `FellowshipAdmin` `Origins`, commanded via public Polkadot referendum, can promote or demote members to and from any rank. Members themselves also have the power to promote or demote via its referendum, with a senior member vote by the rank two above the new / current rank - [full configuration](https://github.com/paritytech/cumulus/blob/9ab6aa47063d7e8b67ddc10d9c136037f99c03a3/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs#L67). ### Content Management The program's on-chain content is managed via the collectives content pallet, allowing for setting its charter and making announcements. The voice of head ambassadors have the authority to set the charter, while announcements can be made by any senior rank member or through a referendum among all members. ### Additional Functionality The `AmbassadorCore` instance of [core fellowship pallet](https://docs.rs/pallet-core-fellowship/latest/pallet_core_fellowship/) decorates the ranked collectives pallet with features like salary determination, activity/passivity registration, and the handling of promotion and demotion periods. While the usage of this pallet is optional in the first version, future updates will make it the exclusive method for induction/promotion. Periodic salaries in USDt, payable on Asset Hub, are introduced through the [salary pallet](https://docs.rs/pallet-salary/latest/pallet_salary/). This requires induction into the ambassador core pallet. Please for more information on the pallets' functionality refer to their documentations. ### Next Steps: - Migrate to seed the program members - Mint ambassador NFT badges on Asset Hub when promoting - Treasury pallet instance for the Ambassador Program --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 17 + cumulus/parachains/common/src/polkadot.rs | 4 + .../collectives-polkadot/Cargo.toml | 1 + .../src/tests/ambassador.rs | 65 +++ .../collectives-polkadot/src/tests/mod.rs | 1 + .../pallets/collective-content/Cargo.toml | 48 ++ .../collective-content/src/benchmarking.rs | 88 +++ .../pallets/collective-content/src/lib.rs | 206 +++++++ .../pallets/collective-content/src/mock.rs | 107 ++++ .../pallets/collective-content/src/tests.rs | 204 +++++++ .../pallets/collective-content/src/weights.rs | 41 ++ .../asset-hub-polkadot/src/xcm_config.rs | 4 + .../collectives-polkadot/Cargo.toml | 4 + .../src/ambassador/mod.rs | 255 +++++++++ .../src/ambassador/origins.rs | 135 +++++ .../src/ambassador/tracks.rs | 282 +++++++++ .../src/fellowship/mod.rs | 32 +- .../collectives-polkadot/src/lib.rs | 29 + .../collectives-polkadot/src/weights/mod.rs | 13 +- .../src/weights/pallet_collective_content.rs | 94 +++ .../pallet_core_fellowship_ambassador_core.rs | 223 ++++++++ ...pallet_core_fellowship_fellowship_core.rs} | 73 ++- ...ranked_collective_ambassador_collective.rs | 177 ++++++ ...anked_collective_fellowship_collective.rs} | 73 +-- .../pallet_referenda_ambassador_referenda.rs | 536 ++++++++++++++++++ ... pallet_referenda_fellowship_referenda.rs} | 195 ++++--- .../pallet_salary_ambassador_salary.rs | 190 +++++++ ....rs => pallet_salary_fellowship_salary.rs} | 61 +- .../collectives-polkadot/src/xcm_config.rs | 20 +- 29 files changed, 2945 insertions(+), 233 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs create mode 100644 cumulus/parachains/pallets/collective-content/Cargo.toml create mode 100644 cumulus/parachains/pallets/collective-content/src/benchmarking.rs create mode 100644 cumulus/parachains/pallets/collective-content/src/lib.rs create mode 100644 cumulus/parachains/pallets/collective-content/src/mock.rs create mode 100644 cumulus/parachains/pallets/collective-content/src/tests.rs create mode 100644 cumulus/parachains/pallets/collective-content/src/weights.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs rename cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/{pallet_core_fellowship.rs => pallet_core_fellowship_fellowship_core.rs} (87%) create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs rename cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/{pallet_ranked_collective.rs => pallet_ranked_collective_fellowship_collective.rs} (82%) create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs rename cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/{pallet_referenda.rs => pallet_referenda_fellowship_referenda.rs} (87%) create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs rename cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/{pallet_salary.rs => pallet_salary_fellowship_salary.rs} (86%) diff --git a/Cargo.lock b/Cargo.lock index 9d3535bdf8b..ddb19c24e1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2564,6 +2564,7 @@ dependencies = [ "frame-support", "integration-tests-common", "pallet-assets", + "pallet-balances", "pallet-core-fellowship", "pallet-salary", "pallet-xcm", @@ -2606,6 +2607,7 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "pallet-collective", + "pallet-collective-content", "pallet-core-fellowship", "pallet-multisig", "pallet-preimage", @@ -9282,6 +9284,21 @@ 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" diff --git a/cumulus/parachains/common/src/polkadot.rs b/cumulus/parachains/common/src/polkadot.rs index 52cee939224..4f459b9bb5a 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. diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index 5a28b127415..99caccc8159 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -15,6 +15,7 @@ sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default- 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-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} pallet-core-fellowship = { path = "../../../../../../substrate/frame/core-fellowship", default-features = false} pallet-salary = { path = "../../../../../../substrate/frame/salary", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs new file mode 100644 index 00000000000..d9fd78fbcbf --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs @@ -0,0 +1,65 @@ +// 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 Ambassador Program. + +use crate::*; +use collectives_polkadot_runtime::ambassador::AmbassadorSalaryPaymaster; +use frame_support::traits::{fungible::Mutate, tokens::Pay}; +use sp_core::crypto::Ss58Codec; +use xcm_emulator::TestExt; + +#[test] +fn pay_salary() { + let pay_from: AccountId = + ::from_string("5DS1Gaf6R9eFAV8QyeZP9P89kTkJMurxv3y3J3TTMu8p8VCX") + .unwrap(); + let pay_to = Polkadot::account_id_of(ALICE); + let pay_amount = 90000000000; + + AssetHubPolkadot::execute_with(|| { + type AssetHubBalances = ::Balances; + + assert_ok!(>::mint_into(&pay_from, pay_amount * 2)); + }); + + Collectives::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(AmbassadorSalaryPaymaster::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::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { + 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/collectives/collectives-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs index fb3e235a25c..42d2432d223 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs @@ -13,4 +13,5 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod ambassador; mod fellowship; diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml new file mode 100644 index 00000000000..1c831ac7268 --- /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 00000000000..1f145f725b1 --- /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 00000000000..7a685858acc --- /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 00000000000..2ae5943f332 --- /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 00000000000..4910b30b89a --- /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 00000000000..7ebbaabb5ac --- /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-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index d59507e4bd0..65cf62a610f 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 @@ -186,6 +186,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 @@ -372,6 +375,7 @@ pub type Barrier = TrailingSetTopicAsId< ParentOrParentsPlurality, FellowsPlurality, FellowshipSalaryPallet, + AmbassadorSalaryPallet, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 167f460610d..6a5806d3b90 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -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", 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 00000000000..b055ffc8abf --- /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 00000000000..3ce8a6b9e5d --- /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 00000000000..073d8e6ee36 --- /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 b97e44dda1b..2a2757ea5ce 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 70e62a4dcdf..d833c75d470 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::{ @@ -292,6 +294,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 +330,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 +632,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 +708,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] ); } 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 9ddf53792ea..b5a3a892f79 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 00000000000..e66907b9453 --- /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 00000000000..f40940a8b25 --- /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 d053513b53a..434986b03bb 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 00000000000..a6372c4b89d --- /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 561edda953b..7515aecbb52 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 00000000000..fdc451c5d31 --- /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 12d92a803ca..5b4aed06899 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 00000000000..0522420f2f5 --- /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 3a6825cf641..9bb7e68d314 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 b4db73e3ab4..02e4913fcd9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -26,15 +26,16 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_constants::xcm::body::FELLOWSHIP_ADMIN_INDEX; 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}; @@ -46,6 +47,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 -- GitLab From a56fd32e0affbe9cb61abb5ee3ec0a0bd15f5bf0 Mon Sep 17 00:00:00 2001 From: tmpolaczyk <44604217+tmpolaczyk@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:22:42 +0200 Subject: [PATCH 193/633] Add graceful shutdown to prometheus server (#1637) Fixes prometheus server not stopping if there are open connections --- substrate/utils/prometheus/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/substrate/utils/prometheus/src/lib.rs b/substrate/utils/prometheus/src/lib.rs index 581666635ab..ed1f9137aec 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 } -- GitLab From 93bb4926b34cf46401f8c5f2b7c01dd07e19309c Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Thu, 21 Sep 2023 12:20:22 -0300 Subject: [PATCH 194/633] bump zombienet version (#1655) Includes: - fix for https://github.com/paritytech/zombienet/issues/1360 (root cause of https://github.com/paritytech/polkadot-sdk/issues/1647) - Improve default concurrency to spawn nodes. Also, fix `var` name in CI file. cc @skunert --- .gitlab-ci.yml | 2 +- .gitlab/pipeline/zombienet/cumulus.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10dd69f12a7..ee6b9c98733 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.68" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 3347eda1baa..3f2c6f64fbf 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}" -- GitLab From cb7559f698ad5059a501fd620d0bacb5867f9b0c Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 21 Sep 2023 20:25:48 +0200 Subject: [PATCH 195/633] [Trivial] Use 'into_inner' for WeakBoundedVec (#1664) Prevents authority set clone --- substrate/frame/babe/src/lib.rs | 9 ++++----- substrate/frame/babe/src/tests.rs | 2 +- substrate/frame/grandpa/src/lib.rs | 10 ++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 9549fac9fe2..4b99cd51796 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/tests.rs b/substrate/frame/babe/src/tests.rs index ae0c3e3873c..ec4e6fd9727 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/grandpa/src/lib.rs b/substrate/frame/grandpa/src/lib.rs index 2a0e707ac41..95d1c8aa609 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(); } -- GitLab From cfc6cc65cc133f69f472149b2449a673597e8530 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:45:06 +0200 Subject: [PATCH 196/633] Bump quinn-proto from 0.9.4 to 0.9.5 (#1670) Bumps [quinn-proto](https://github.com/quinn-rs/quinn) from 0.9.4 to 0.9.5.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=quinn-proto&package-manager=cargo&previous-version=0.9.4&new-version=0.9.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/paritytech/polkadot-sdk/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Liam Aharon --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddb19c24e1f..ccf546b16b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13596,9 +13596,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" +checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" dependencies = [ "bytes", "rand 0.8.5", @@ -19257,7 +19257,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] -- GitLab From fb0fd3e62445eb2dee2b2456a0c8574d1ecdcc73 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 22 Sep 2023 12:19:09 +0200 Subject: [PATCH 197/633] Use correct target dir in polkadot readme (#1643) Closes #1372 This fixes the target directories in the polkadot readme. I verified manually the Ubuntu based install works on a fresh cloud machine. Build from source also worked as described. Since #1304 landed `--dev` also works again (not on v1.1.0 though), so I would consider the install instructions fixed. --- polkadot/README.md | 87 +++++++-------------- polkadot/scripts/init.sh | 16 ---- substrate/.maintain/init.sh | 12 --- substrate/bin/node-template/scripts/init.sh | 12 --- 4 files changed, 29 insertions(+), 98 deletions(-) delete mode 100755 polkadot/scripts/init.sh delete mode 100755 substrate/.maintain/init.sh delete mode 100755 substrate/bin/node-template/scripts/init.sh diff --git a/polkadot/README.md b/polkadot/README.md index 93e93cfba0e..3c234bb8e3f 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/scripts/init.sh b/polkadot/scripts/init.sh deleted file mode 100755 index cf5ecf97926..00000000000 --- 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/substrate/.maintain/init.sh b/substrate/.maintain/init.sh deleted file mode 100755 index 1405a41ef33..00000000000 --- 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/bin/node-template/scripts/init.sh b/substrate/bin/node-template/scripts/init.sh deleted file mode 100755 index f976f7235d7..00000000000 --- 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 -- GitLab From b09ab37119acf0f3c4c8b9e3662255afd6d0ae53 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:48:48 +0200 Subject: [PATCH 198/633] update `genesis_config` related docs and tests and error messages (#1642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to https://github.com/paritytech/substrate/pull/14306. I hope this also showcases the important message of: **It is really not that hard to make the examples codes in rust-docs compile, and therefore remain correct. Please embrace this :)** It moves the documentation of proc macros to their re-export, such that can link other items in frame-support. This is a patter that we should embrace for all of macro docs, and apply in PRs like https://github.com/paritytech/substrate/pull/13987 as well. --------- Co-authored-by: Gonçalo Pestana Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: command-bot <> --- substrate/frame/support/procedural/src/lib.rs | 46 ----------- .../src/pallet/expand/genesis_build.rs | 2 +- .../procedural/src/pallet/parse/helper.rs | 2 +- substrate/frame/support/src/lib.rs | 76 ++++++++++++++++++- .../pallet_ui/genesis_invalid_generic.stderr | 2 +- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 9957cf1cff8..b7aaf7c7cc1 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1417,57 +1417,11 @@ 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, -/// } -/// ``` #[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`. #[proc_macro_attribute] pub fn genesis_build(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() 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 15ddfcf1d49..248e8346943 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/parse/helper.rs b/substrate/frame/support/procedural/src/pallet/parse/helper.rs index 1e6e83d7eeb..bfa19d8ddc3 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/helper.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/helper.rs @@ -494,7 +494,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 { diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index a7106780e02..8c4b3de49b5 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2188,10 +2188,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/test/tests/pallet_ui/genesis_invalid_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr index e3dd0b7aa1d..b54a23c91b4 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 {} -- GitLab From 22d9e2abc65f06ae68297f390658ab61037669d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Fri, 22 Sep 2023 17:02:15 +0100 Subject: [PATCH 199/633] Update HRMP pallet benchmarking to use benchmarks v2 (#1676) Updates the HRMP pallet benchmarks to Benchmarks v2 and fixes a small misconfiguration in one benchmark. --------- Co-authored-by: command-bot <> --- .../parachains/src/hrmp/benchmarking.rs | 280 +++++++++++------- 1 file changed, 179 insertions(+), 101 deletions(-) diff --git a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs index 9ffa264a7dc..7d82bcc99a7 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,68 @@ 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_id, recipient_id, capacity, 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 { + + #[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 { + + #[extrinsic_call] + _(sender_origin, channel_id.clone()); + assert_last_event::(Event::::ChannelClosed(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 +223,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 +242,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 +254,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,73 +265,108 @@ 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(); @@ -315,47 +382,46 @@ frame_benchmarking::benchmarks! { 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_id, recipient_id, capacity, message_size) + .into(), ); } - establish_system_channel { + #[benchmark] + fn establish_system_channel() { let sender_id: ParaId = 1u32.into(); let recipient_id: ParaId = 2u32.into(); - let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); + let caller: T::AccountId = whitelisted_caller(); let config = Configuration::::config(); // make sure para is registered, and has zero balance. @@ -364,19 +430,23 @@ frame_benchmarking::benchmarks! { let capacity = config.hrmp_channel_max_capacity; let message_size = config.hrmp_channel_max_message_size; - }: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id) - verify { + + #[extrinsic_call] + _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); + assert_last_event::( - Event::::HrmpSystemChannelOpened(sender_id, recipient_id, capacity, message_size).into() + Event::::HrmpSystemChannelOpened(sender_id, recipient_id, capacity, message_size) + .into(), ); } - poke_channel_deposits { + #[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 channel_id = HrmpChannelId { sender: sender_id, recipient: recipient_id }; - let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); + let caller: T::AccountId = whitelisted_caller(); let config = Configuration::::config(); // make sure para is registered, and has balance to reserve. @@ -403,23 +473,31 @@ frame_benchmarking::benchmarks! { // 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); - }: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id) - verify { + + #[extrinsic_call] + _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); + assert_last_event::( - Event::::OpenChannelDepositsUpdated(sender_id, recipient_id).into() + Event::::OpenChannelDepositsUpdated(sender_id, 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()); + 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() + ); } -} -frame_benchmarking::impl_benchmark_test_suite!( - Hrmp, - crate::mock::new_test_ext(crate::hrmp::tests::GenesisConfigBuilder::default().build()), - crate::mock::Test -); + impl_benchmark_test_suite!( + Hrmp, + crate::mock::new_test_ext(crate::hrmp::tests::GenesisConfigBuilder::default().build()), + crate::mock::Test + ); +} -- GitLab From f79fa6c8bd6042d34bcf18bb71b3393c615c26c7 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 22 Sep 2023 19:22:18 +0200 Subject: [PATCH 200/633] pallet epm: add `TrimmingStatus` to the mined solution (#1659) For tools such that is using the `Miner` it's useful to know whether a solution was trimmed or not and also how much that was trimmed. --------- Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> --- polkadot/tests/common.rs | 4 +- .../election-provider-multi-phase/src/lib.rs | 4 +- .../src/signed.rs | 2 +- .../src/unsigned.rs | 99 +++++++++++++------ 4 files changed, 73 insertions(+), 36 deletions(-) diff --git a/polkadot/tests/common.rs b/polkadot/tests/common.rs index 10859ead5fe..15721c990e0 100644 --- a/polkadot/tests/common.rs +++ b/polkadot/tests/common.rs @@ -33,9 +33,7 @@ pub async fn wait_n_finalized_blocks(n: usize, url: &str) { let mut interval = tokio::time::interval(Duration::from_secs(6)); loop { - let Ok(rpc) = ws_client(url).await else { - 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); diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 8b6e0827c71..05f9b24f8f9 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 a5fe8ce5558..7e4b029ff8c 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 f1c9e92a704..e3d0ded9751 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); }); } -- GitLab From 3d9f5e8bfcce054c3722d52ac3a0f19ffd7252ec Mon Sep 17 00:00:00 2001 From: Maksym H <1177472+mordamax@users.noreply.github.com> Date: Fri, 22 Sep 2023 22:48:38 +0100 Subject: [PATCH 201/633] update contributing guide and ui-tests scripts (#1668) - Updated ./docs/CONTRIBUTION.md to clarify how to use command bot and update ui-tests locally or in PR - Moved update-ui-tests.sh to a root of project to run them along for substrate and polkadot together --------- Co-authored-by: Mira Ressel --- .gitlab/pipeline/test.yml | 4 +-- docs/CONTRIBUTING.md | 16 ++++++++- polkadot/scripts/update-rust-stable.sh | 39 --------------------- scripts/update-ui-tests.sh | 40 +++++++++++++++++++++ substrate/.maintain/update-rust-stable.sh | 42 ----------------------- 5 files changed, 57 insertions(+), 84 deletions(-) delete mode 100755 polkadot/scripts/update-rust-stable.sh create mode 100755 scripts/update-ui-tests.sh delete mode 100755 substrate/.maintain/update-rust-stable.sh diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 3a4f5e71247..ad0ef4d9b8e 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -314,8 +314,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: diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 245369b7020..1e05755a9b8 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -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 output 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/polkadot/scripts/update-rust-stable.sh b/polkadot/scripts/update-rust-stable.sh deleted file mode 100755 index 6aae75d8cb2..00000000000 --- 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/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh new file mode 100755 index 00000000000..785cc7bd329 --- /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/.maintain/update-rust-stable.sh b/substrate/.maintain/update-rust-stable.sh deleted file mode 100755 index b253bb41053..00000000000 --- 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 -- GitLab From 6a897f0694232fa9bc83d3f98fd47a5f69282601 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Sun, 24 Sep 2023 12:27:55 +0100 Subject: [PATCH 202/633] docs / Update PR template to reflect monorepo (#1674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove: ``` Polkadot companion: (*if applicable*) Cumulus companion: (*if applicable*) ``` --------- Co-authored-by: Chevdor Co-authored-by: Bastian Köcher --- docs/PULL_REQUEST_TEMPLATE.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 284ad15afc9..c93ac90c7e3 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! -- GitLab From e67a879ca07e0efb5aae6b158e2469cba6cf09b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 00:47:09 +0300 Subject: [PATCH 203/633] Bump aes-gcm from 0.10.2 to 0.10.3 (#1681) Bumps [aes-gcm](https://github.com/RustCrypto/AEADs) from 0.10.2 to 0.10.3.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=aes-gcm&package-manager=cargo&previous-version=0.10.2&new-version=0.10.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/paritytech/polkadot-sdk/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccf546b16b6..dade37f9a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead 0.5.2", "aes 0.8.3", @@ -17431,7 +17431,7 @@ dependencies = [ name = "sp-statement-store" version = "4.0.0-dev" dependencies = [ - "aes-gcm 0.10.2", + "aes-gcm 0.10.3", "curve25519-dalek 4.0.0", "ed25519-dalek", "hkdf", @@ -19257,7 +19257,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] @@ -20060,7 +20060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a00f4242f2db33307347bd5be53263c52a0331c96c14292118c9a6bb48d267" dependencies = [ "aes 0.6.0", - "aes-gcm 0.10.2", + "aes-gcm 0.10.3", "async-trait", "bincode", "block-modes", -- GitLab From fa4c672abcb7492e23a51bdfa2129a723bd526ad Mon Sep 17 00:00:00 2001 From: Gabriel Facco de Arruda Date: Mon, 25 Sep 2023 05:14:11 -0300 Subject: [PATCH 204/633] Uncoupling pallet-xcm from frame-system's RuntimeCall (#1684) --- polkadot/xcm/pallet-xcm/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 5acd093d3bc..321bb294b88 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, @@ -902,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)?; -- GitLab From b5fcdff9f564e113efa0aff1e3e53d9bc807c28c Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:38:02 +0200 Subject: [PATCH 205/633] tweak pallet macro (genesis_config etc) to cater for RA users as well. (#1689) Small tweak to https://github.com/paritytech/polkadot-sdk/pull/1642 to incorporate the ideas from https://github.com/paritytech/polkadot-sdk/issues/247. I think this is the good middle ground, where we have good rust-docs, and the RA users will also have some hope. cc @wentelteefje @aaronbassett @sam0x17 --- substrate/frame/support/procedural/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index b7aaf7c7cc1..466ceca4296 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1417,11 +1417,15 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// **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() } +/// **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() -- GitLab From c0a4ce1fc87b7b39bc307072e60db97ade3cd6be Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 25 Sep 2023 13:56:43 +0300 Subject: [PATCH 206/633] Fix documentation about justification and `finalized == true` requirement (#1607) I was reading source code and noticed these two places that are no longer true after https://github.com/paritytech/polkadot-sdk/pull/1211 --- substrate/client/service/src/client/client.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 26dcd0f9e21..da4a4f66e2a 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 -- GitLab From e8da320734ae44803f89dd2b35b3cfea0e1ecca1 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 25 Sep 2023 21:13:11 +0800 Subject: [PATCH 207/633] contracts: Fix incorrect storage alias in mirgration (#1687) # Description We are recently trying to upgrade our Substrate version from `polkadot-v0.9.43` to `polkadot-v1.0.0` and we noticed a critical issue: all deployed contracts seem to be experiencing a `CodeNotFound` error. After a thorough investigation, it appears that the root cause of this issue lies in the mismatch between the storage alias of `CodeInfoOf` in the migration and its original definition. This PR corrects the storage alias to align it with its original definition I am uncertain about the proper approach for adding tests to this change. Would the team consider taking over this PR to bring it to completion? --------- Co-authored-by: pgherveou --- substrate/frame/contracts/src/migration.rs | 26 +++++++++++++++++++ .../frame/contracts/src/migration/v12.rs | 2 +- .../frame/contracts/src/migration/v14.rs | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/substrate/frame/contracts/src/migration.rs b/substrate/frame/contracts/src/migration.rs index 3e3d6f37884..27146207312 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 eb045aa42e9..4ddc57584b3 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 efb49dff4f1..94534d05fdf 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")] -- GitLab From b18fb35e0dada9a23761f511d502b9a73fac9593 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:53:16 +0300 Subject: [PATCH 208/633] Bump actions/checkout from 4.0.0 to 4.1.0 (#1688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0.
Release notes

Sourced from actions/checkout's releases.

v4.1.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.0.0...v4.1.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.0.0&new-version=4.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check-licenses.yml | 2 +- .github/workflows/check-markdown.yml | 2 +- .github/workflows/check-prdoc.yml | 2 +- .github/workflows/fmt-check.yml | 2 +- .github/workflows/release-50_publish-docker.yml | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 4d0afefc47a..a5c4f2577c0 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - uses: actions/setup-node@v3.8.1 with: node-version: "18.x" diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index f1e46ca2735..be676d3c1e8 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - uses: actions/setup-node@v3.8.1 with: diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index d153184941a..23ae2d1aca9 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@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0 - 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 df785404036..db93a3d53a7 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - 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 d01d78631e1..15631c172b9 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 #TODO: this step will be needed when automated triggering will work #this step runs only if the workflow is triggered automatically when new release is published @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Get artifacts from cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -239,7 +239,7 @@ jobs: needs: fetch-latest-debian-package-version steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 -- GitLab From f209b31b48586bca81c0ffafa150e1796ee05845 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Mon, 25 Sep 2023 15:46:36 -0300 Subject: [PATCH 209/633] Make downloads in parallel and give more time to complete (#1699) Fix flaky test (e.g https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/3787906). Sometimes just timeout when trying to download the artifacts from ci. This make the download in parallel and allow for more time to complete. Thx! cc: @michalkucharczyk --- .../misc/0002-download-polkadot-from-pr.sh | 8 +++++--- polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) 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 0d4b2807579..b5553455927 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 fdf16b7286c..9191fb027de 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 -- GitLab From bc5005217a8c2e7c95b9011c96d7e619879b1200 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 26 Sep 2023 01:43:36 +0300 Subject: [PATCH 210/633] Implement more useful traits in `Slot` type (#1595) I had quite a few conversions to/from `u64` because these were lacking. Let me know if others are desirable as well for symmetry. --- .../primitives/consensus/slots/src/lib.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/consensus/slots/src/lib.rs b/substrate/primitives/consensus/slots/src/lib.rs index 30bb42e2c75..a299ce395ea 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; -- GitLab From cc50eda0988337a3174f9f86f4435aca0078053d Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:36:24 +0300 Subject: [PATCH 211/633] chainHead/storage: Fix storage iteration using the query key (#1665) This PR ensures that all storage keys under a prefix are returned by the `chainHead_storage` method. Before this PR, the `storage_keys` was used with just the `start_key`. Before the pagination event was generated, the last reported key `last_key` was saved internally. When the pagination is resumed, the `last_key` will serve as the next `start_key` to the `storage_keys` API. However, this behavior does not function properly for non-prefixed storage keys. Entry keys `a`, `ab`, `abc` share a common prefix and therefore the `ab` key leads to `abc`. However, for `a`, `ab`, `aB` and `abc`, the `aB` key does not immediately lead to `abc`. To mitigate this, the PR saves the start key of the query, together with the next pagination key. Improve testing to ensure we have a key entry that doesn't share the prefix with the descendant key. @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- .../src/chain_head/chain_head_storage.rs | 43 +++++++++++++------ .../rpc-spec-v2/src/chain_head/tests.rs | 20 +++++++++ 2 files changed, 50 insertions(+), 13 deletions(-) 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 7095548a2b1..6e19f59a5d6 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/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 3ab47991c4e..1d5b45260a2 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -2352,6 +2352,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 +2431,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, -- GitLab From 7d3ce4df72df7a25e0d71c75aa8c78959b2de3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Tue, 26 Sep 2023 14:42:37 +0100 Subject: [PATCH 212/633] Allow debug_assertions in short-benchmarks CI job (#1711) Add debug_assertions to WASM builds in the short-benchmarks CI job. Disallow warnings, show a full backtrace and remove the WASM output colour to improve information from this CI step in the event of a failure. This is motivated by a [case](https://github.com/paritytech/polkadot-sdk/pull/1676/commits/23d64918be3ca68413050383c5d8a73f63d451dd) where a benchmark was misconfigured in master and failing to send notifications, but passing CI. We don't want this to fail if the problem happens in production, but ideally we'd know from the CI if it was misconfigured and the messages weren't getting sent, as that could (would?) affect the weights that the benchmark generates. Enabling debug-assertions in WASM builds for the short-benchmarks would catch "soft" failures like this in future. --- .gitlab/pipeline/short-benchmarks.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 5b0ea276773..5bfe4b729e6 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -15,6 +15,12 @@ short-benchmark-westend: &short-bench artifacts: true variables: RUNTIME: westend + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" tags: - benchmark script: @@ -32,6 +38,12 @@ short-benchmark-westend: &short-bench 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: -- GitLab From a846b7460465ddcb70450359b0c92a1be59afb2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 23:25:46 +0200 Subject: [PATCH 213/633] Bump directories from 4.0.1 to 5.0.1 (#1656) Bumps [directories](https://github.com/soc/directories-rs) from 4.0.1 to 5.0.1.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=directories&package-manager=cargo&previous-version=4.0.1&new-version=5.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 17 ++++++++++++----- substrate/client/service/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dade37f9a02..683289adb45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4367,9 +4367,9 @@ dependencies = [ [[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", ] @@ -4386,13 +4386,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]] @@ -8694,6 +8695,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" diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index ccf23bc8994..2386bebf24d 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] -- GitLab From ab3a3bc2786673bfda47646a20f871b8a2e4d59d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:58:39 +0200 Subject: [PATCH 214/633] `BlockId` removal: `tx-pool` refactor (#1678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It changes following APIs: - trait `ChainApi` -- `validate_transaction` - trait `TransactionPool` --`submit_at` --`submit_one` --`submit_and_watch` and some implementation details, in particular: - impl `Pool` --`submit_at` --`resubmit_at` --`submit_one` --`submit_and_watch` --`prune_known` --`prune` --`prune_tags` --`resolve_block_number` --`verify` --`verify_one` - revalidation queue All tests are also adjusted. --------- Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher --- .../service/benches/transaction_throughput.rs | 4 +- substrate/bin/node/bench/src/construct.rs | 8 +- substrate/bin/node/bench/src/txpool.rs | 6 +- .../bin/node/cli/benches/transaction_pool.rs | 4 +- .../basic-authorship/src/basic_authorship.rs | 47 +- .../client/consensus/manual-seal/src/lib.rs | 23 +- .../src/transaction/transaction.rs | 8 +- substrate/client/rpc/src/author/mod.rs | 30 +- substrate/client/service/src/lib.rs | 14 +- substrate/client/service/test/src/lib.rs | 11 +- .../client/transaction-pool/api/src/lib.rs | 11 +- .../client/transaction-pool/benches/basics.rs | 37 +- substrate/client/transaction-pool/src/api.rs | 27 +- .../client/transaction-pool/src/graph/pool.rs | 168 +++--- substrate/client/transaction-pool/src/lib.rs | 44 +- .../transaction-pool/src/revalidation.rs | 109 +++- .../client/transaction-pool/src/tests.rs | 20 +- .../client/transaction-pool/tests/pool.rs | 480 ++++++++++-------- .../runtime/transaction-pool/src/lib.rs | 12 +- substrate/utils/frame/rpc/system/src/lib.rs | 6 +- 20 files changed, 609 insertions(+), 460 deletions(-) diff --git a/cumulus/test/service/benches/transaction_throughput.rs b/cumulus/test/service/benches/transaction_throughput.rs index 83981a91d46..81ecc84db7b 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/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index f14f89fcd3a..23d0a0cc1ee 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 a3524ac5bc8..e56bb559a7b 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/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index d3e8c02a958..d21edc55bba 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 { @@ -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/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index b3a8f0d8970..0fb61b6fab1 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -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/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index 1e5db966e66..41cd5f3127e 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/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index 44f4bd36c8b..fe16310aeff 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/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index feee22641ef..55d0a504aa6 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/service/src/lib.rs b/substrate/client/service/src/lib.rs index cd720e1c1e0..ff9eb982b86 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/lib.rs b/substrate/client/service/test/src/lib.rs index 38a811acc74..9700c7643c4 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/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index 73cc513708d..a795917528f 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 d114acc343d..0caf00bf295 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 871d8e9c817..cccaad7c899 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 4d34737a7ba..5305b5f1c12 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 ffaab89d982..faa3f455a58 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 62911d5cbb4..325add3fb1c 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 4adf811b425..e5ab01ffbf0 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/test-utils/runtime/transaction-pool/src/lib.rs b/substrate/test-utils/runtime/transaction-pool/src/lib.rs index 7b529200440..8c8345b06bd 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/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index 1eff71e3390..f467a879890 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); -- GitLab From 5a2833cceb87cf227fc49b8b7441adb5634cb1f1 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:59:19 +0200 Subject: [PATCH 215/633] genesis-builder: implemented for all runtimes (#1492) This PR implements [`GenesisBuilder` API](https://github.com/paritytech/polkadot-sdk/blob/a414ea7515c9cdc81f1d12410e646afc148250e8/substrate/primitives/genesis-builder/src/lib.rs#L38) for all the runtimes in polkadot repo. Step towards: paritytech/polkadot-sdk#25 --------- Co-authored-by: ordian --- Cargo.lock | 21 +++++++++++++++++++ cumulus/parachain-template/runtime/Cargo.toml | 2 ++ cumulus/parachain-template/runtime/src/lib.rs | 11 ++++++++++ .../assets/asset-hub-kusama/Cargo.toml | 2 ++ .../assets/asset-hub-kusama/src/lib.rs | 11 ++++++++++ .../assets/asset-hub-polkadot/Cargo.toml | 2 ++ .../assets/asset-hub-polkadot/src/lib.rs | 11 ++++++++++ .../assets/asset-hub-westend/Cargo.toml | 2 ++ .../assets/asset-hub-westend/src/lib.rs | 11 ++++++++++ .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 ++ .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 11 ++++++++++ .../bridge-hub-polkadot/Cargo.toml | 2 ++ .../bridge-hub-polkadot/src/lib.rs | 11 ++++++++++ .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 ++ .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 11 ++++++++++ .../collectives-polkadot/Cargo.toml | 2 ++ .../collectives-polkadot/src/lib.rs | 11 ++++++++++ .../contracts/contracts-rococo/Cargo.toml | 2 ++ .../contracts/contracts-rococo/src/lib.rs | 11 ++++++++++ .../glutton/glutton-kusama/Cargo.toml | 2 ++ .../glutton/glutton-kusama/src/lib.rs | 11 ++++++++++ .../runtimes/starters/seedling/Cargo.toml | 2 ++ .../runtimes/starters/seedling/src/lib.rs | 11 ++++++++++ .../runtimes/starters/shell/Cargo.toml | 2 ++ .../runtimes/starters/shell/src/lib.rs | 11 ++++++++++ .../runtimes/testing/penpal/Cargo.toml | 2 ++ .../runtimes/testing/penpal/src/lib.rs | 11 ++++++++++ .../testing/rococo-parachain/Cargo.toml | 2 ++ .../testing/rococo-parachain/src/lib.rs | 11 ++++++++++ polkadot/runtime/kusama/Cargo.toml | 2 ++ polkadot/runtime/kusama/src/lib.rs | 15 ++++++++++++- polkadot/runtime/polkadot/Cargo.toml | 2 ++ polkadot/runtime/polkadot/src/lib.rs | 15 ++++++++++++- polkadot/runtime/rococo/Cargo.toml | 2 ++ polkadot/runtime/rococo/src/lib.rs | 14 ++++++++++++- polkadot/runtime/test-runtime/Cargo.toml | 2 ++ polkadot/runtime/test-runtime/src/lib.rs | 14 ++++++++++++- polkadot/runtime/westend/Cargo.toml | 2 ++ polkadot/runtime/westend/src/lib.rs | 14 ++++++++++++- .../bin/node-template/runtime/Cargo.toml | 2 ++ .../bin/node-template/runtime/src/lib.rs | 11 ++++++++++ substrate/bin/node/runtime/Cargo.toml | 2 ++ substrate/bin/node/runtime/src/lib.rs | 11 ++++++++++ substrate/test-utils/runtime/Cargo.toml | 3 --- substrate/test-utils/runtime/build.rs | 15 ------------- substrate/test-utils/runtime/src/lib.rs | 5 +---- 46 files changed, 307 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 683289adb45..dcfd8cd6601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -774,6 +774,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -866,6 +867,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -961,6 +963,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -1859,6 +1862,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -1922,6 +1926,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -2021,6 +2026,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -2636,6 +2642,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -2846,6 +2853,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -5815,6 +5823,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -6811,6 +6820,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-grandpa", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -8448,6 +8458,7 @@ dependencies = [ "sp-consensus-aura", "sp-consensus-grandpa", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -10919,6 +10930,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -11251,6 +11263,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -12633,6 +12646,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -13061,6 +13075,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -14075,6 +14090,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -14160,6 +14176,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -16103,6 +16120,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -16350,6 +16368,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -17764,6 +17783,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -20293,6 +20313,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 4e51f16dca1..68db2f041dd 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 038597096f6..b9bf97d7786 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/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 1d0c7bc9856..4853195d329 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} @@ -209,6 +210,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 828d1b4750a..40ce122112d 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-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index 4a6ce4cbf59..f0eae31f53a 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} @@ -190,6 +191,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-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index 0051af21f9a..d4f7d6ef361 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-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index f436ae9537f..f7f6fdf68e4 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 4887fce1b0a..759cd727f1d 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, @@ -1353,6 +1354,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/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 67c3fa37df0..d54e66c42dc 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} @@ -118,6 +119,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 54b15e6b327..791751e7736 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-polkadot/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 77923ee74f8..d9dba557681 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} @@ -118,6 +119,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-polkadot/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index dbfdc249a3c..928b9d091ec 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-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 70c62d1a34f..fec00fe0794 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} @@ -153,6 +154,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/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index dbdc2133ec8..4c850f92b8d 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 @@ -45,6 +45,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}, @@ -1233,6 +1234,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/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 6a5806d3b90..8cb5519a24d 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} @@ -201,6 +202,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/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index d833c75d470..ff16f93d8f5 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -68,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, @@ -939,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/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index f6fccc04354..a85aa8dcb17 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} @@ -120,6 +121,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/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 399ada1be2c..70392c5ecbc 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/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 0ffe59b927f..63b658ca977 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} @@ -91,6 +92,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 41cb0fceebb..d3369202aac 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, @@ -452,6 +453,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 1b68b720d97..d9711b57b37 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 34e82737f82..c2bcaf8a126 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 46cef8d4ae0..675abc07b77 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 477933b5c8d..4aad553e6a3 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/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 547695e7621..6c4f8c3895a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -44,6 +44,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 +118,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 9a758cdd978..fe0f19c3063 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/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 54055ca732b..029d5d10f98 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 362ad0383a2..50c5a445c25 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/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml index 565b34637e2..ebbcfc71e95 100644 --- a/polkadot/runtime/kusama/Cargo.toml +++ b/polkadot/runtime/kusama/Cargo.toml @@ -28,6 +28,7 @@ offchain-primitives = { package = "sp-offchain", path = "../../../substrate/prim 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-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 } @@ -211,6 +212,7 @@ 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", diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 8d8bd4baacf..082e1aca375 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -60,8 +60,11 @@ use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, generate_solution_type, onchain, NposSolution, SequentialPhragmen, }; + use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + genesis_builder_helper::{build_config, create_default_config}, + parameter_types, traits::{ fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, @@ -2478,6 +2481,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/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml index a659a455322..5e283b49669 100644 --- a/polkadot/runtime/polkadot/Cargo.toml +++ b/polkadot/runtime/polkadot/Cargo.toml @@ -26,6 +26,7 @@ offchain-primitives = { package = "sp-offchain", path = "../../../substrate/prim 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-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", 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 } @@ -193,6 +194,7 @@ std = [ "sp-api/std", "sp-arithmetic/std", "sp-core/std", + "sp-genesis-builder/std", "sp-io/std", "sp-mmr-primitives/std", "sp-npos-elections/std", diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index 5956b0e155b..c9e3ded6dad 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -45,7 +45,9 @@ use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, generate_solution_type, 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, Contains, EitherOf, EitherOfDiverse, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, @@ -2228,6 +2230,17 @@ 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/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 8f38659b84f..64cf6207236 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -21,6 +21,7 @@ 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-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } @@ -175,6 +176,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/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 7046c4640c0..c7d429bc99a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -58,7 +58,9 @@ 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, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, PrivilegeCmp, ProcessMessage, @@ -2232,6 +2234,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/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index a8f26eb5b3d..2e9c773a3f8 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 94852ad39f5..99d6e58bc40 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -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 f4bb66f68cd..e23d322b5a7 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -25,6 +25,7 @@ offchain-primitives = { package = "sp-offchain", path = "../../../substrate/prim sp-api = { path = "../../../substrate/primitives/api", default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", 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 } @@ -195,6 +196,7 @@ std = [ "sp-api/std", "sp-application-crypto/std", "sp-core/std", + "sp-genesis-builder/std", "sp-io/std", "sp-mmr-primitives/std", "sp-npos-elections/std", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9af18b5be2b..ad08360f382 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -27,7 +27,9 @@ 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, Contains, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, @@ -2153,6 +2155,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/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 65d0cfca59c..caca54ce2ba 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 = { version = "0.1.0-dev", 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 216be9588bc..4653b49bf2c 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/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 09c1fd9c6f3..7771b5f2097 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -32,6 +32,7 @@ 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 = { version = "0.1.0-dev", default-features = false, path = "../../../primitives/genesis-builder" } sp-inherents = { path = "../../../primitives/inherents", default-features = false} node-primitives = { path = "../primitives", default-features = false} sp-offchain = { path = "../../../primitives/offchain", default-features = false} @@ -231,6 +232,7 @@ std = [ "sp-consensus-babe/std", "sp-consensus-grandpa/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index df8fb06467d..c90b9076dec 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -30,6 +30,7 @@ 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, @@ -2750,6 +2751,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/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 727d46cb8f5..4d279c7b703 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 230606635f7..dd79ce2c5ae 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 b116c855681..687790f2ffa 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; -- GitLab From 7cbe0c76ef8fd2aabf9f07de0156941ce3ed44b0 Mon Sep 17 00:00:00 2001 From: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:32:02 +0300 Subject: [PATCH 216/633] Migrate polkadot-primitives to v6 (#1543) - Async-backing related primitives are stable `primitives::v6` - Async-backing API is now part of `api_version(7)` - It's enabled on Rococo and Westend runtimes --------- Signed-off-by: Andrei Sandu Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- .gitlab/pipeline/zombienet/polkadot.yml | 30 +- .../chain-bridge-hub-cumulus/src/lib.rs | 2 +- .../Cargo.toml | 3 - .../relay-chain-minimal-node/Cargo.toml | 4 - .../src/blockchain_rpc_client.rs | 10 +- .../src/collator_overseer.rs | 11 +- .../relay-chain-minimal-node/src/lib.rs | 12 +- .../src/rpc_client.rs | 25 +- cumulus/client/service/Cargo.toml | 5 - cumulus/pallets/parachain-system/src/lib.rs | 2 +- cumulus/parachain-template/node/Cargo.toml | 5 +- .../emulated/common/src/lib.rs | 6 +- cumulus/test/relay-sproof-builder/src/lib.rs | 2 +- polkadot/Cargo.toml | 1 - polkadot/cli/Cargo.toml | 1 - polkadot/node/collation-generation/src/lib.rs | 7 +- .../node/collation-generation/src/tests.rs | 8 +- polkadot/node/core/backing/src/tests/mod.rs | 2 +- .../src/tests/prospective_parachains.rs | 8 +- .../dispute-coordinator/src/initialized.rs | 12 +- .../src/fragment_tree.rs | 10 +- .../core/prospective-parachains/src/lib.rs | 13 +- .../core/prospective-parachains/src/tests.rs | 12 +- polkadot/node/core/runtime-api/src/cache.rs | 74 +- polkadot/node/core/runtime-api/src/lib.rs | 33 +- polkadot/node/core/runtime-api/src/tests.rs | 22 +- .../network/approval-distribution/src/lib.rs | 48 +- .../approval-distribution/src/tests.rs | 16 +- .../network/bitfield-distribution/src/lib.rs | 19 +- .../bitfield-distribution/src/tests.rs | 10 +- polkadot/node/network/bridge/src/rx/mod.rs | 44 +- polkadot/node/network/bridge/src/rx/tests.rs | 29 +- polkadot/node/network/bridge/src/tx/mod.rs | 28 +- polkadot/node/network/bridge/src/tx/tests.rs | 19 +- .../src/collator_side/collation.rs | 21 +- .../src/collator_side/mod.rs | 52 +- .../src/collator_side/tests/mod.rs | 49 +- .../tests/prospective_parachains.rs | 39 +- .../node/network/collator-protocol/src/lib.rs | 11 +- .../src/validator_side/collation.rs | 2 +- .../src/validator_side/mod.rs | 44 +- .../src/validator_side/tests/mod.rs | 25 +- .../tests/prospective_parachains.rs | 36 +- .../node/network/gossip-support/src/lib.rs | 2 +- polkadot/node/network/protocol/Cargo.toml | 3 - polkadot/node/network/protocol/src/lib.rs | 62 +- .../node/network/protocol/src/peer_set.rs | 23 +- .../protocol/src/request_response/mod.rs | 24 +- .../protocol/src/request_response/outgoing.rs | 14 +- .../request_response/{vstaging.rs => v2.rs} | 8 +- .../src/legacy_v1/mod.rs | 30 +- .../src/legacy_v1/tests.rs | 12 +- .../network/statement-distribution/src/lib.rs | 55 +- .../src/{vstaging => v2}/candidates.rs | 2 +- .../src/{vstaging => v2}/cluster.rs | 4 +- .../src/{vstaging => v2}/grid.rs | 8 +- .../src/{vstaging => v2}/groups.rs | 3 +- .../src/{vstaging => v2}/mod.rs | 69 +- .../src/{vstaging => v2}/requests.rs | 8 +- .../src/{vstaging => v2}/statement_store.rs | 4 +- .../src/{vstaging => v2}/tests/cluster.rs | 46 +- .../src/{vstaging => v2}/tests/grid.rs | 86 +- .../src/{vstaging => v2}/tests/mod.rs | 12 +- .../src/{vstaging => v2}/tests/requests.rs | 86 +- polkadot/node/service/Cargo.toml | 4 - polkadot/node/service/src/lib.rs | 8 +- polkadot/node/service/src/overseer.rs | 18 +- polkadot/node/subsystem-types/src/messages.rs | 24 +- .../subsystem-types/src/runtime_client.rs | 46 +- .../src/backing_implicit_view.rs | 2 +- .../src/inclusion_emulator/mod.rs | 1435 +++++++++++++++- .../src/inclusion_emulator/staging.rs | 1450 ----------------- polkadot/node/subsystem-util/src/lib.rs | 4 +- .../node/subsystem-util/src/runtime/mod.rs | 29 +- .../test-parachains/adder/collator/Cargo.toml | 3 - polkadot/primitives/src/lib.rs | 31 +- polkadot/primitives/src/runtime_api.rs | 30 +- polkadot/primitives/src/v6/async_backing.rs | 132 ++ .../src/{v5 => v6}/executor_params.rs | 0 polkadot/primitives/src/{v5 => v6}/metrics.rs | 0 polkadot/primitives/src/{v5 => v6}/mod.rs | 12 +- polkadot/primitives/src/{v5 => v6}/signed.rs | 0 .../primitives/src/{v5 => v6}/slashing.rs | 0 polkadot/primitives/src/vstaging/mod.rs | 118 -- .../node/backing/prospective-parachains.md | 2 +- polkadot/runtime/kusama/src/lib.rs | 2 +- .../src/assigner_on_demand/tests.rs | 2 +- .../runtime/parachains/src/configuration.rs | 2 +- .../src/configuration/migration/v6.rs | 2 +- .../src/configuration/migration/v7.rs | 2 +- .../src/configuration/migration/v8.rs | 3 +- .../parachains/src/disputes/slashing.rs | 2 +- .../parachains/src/runtime_api_impl/mod.rs | 3 +- .../src/runtime_api_impl/{v5.rs => v7.rs} | 103 +- .../src/runtime_api_impl/vstaging.rs | 108 -- polkadot/runtime/polkadot/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 15 +- polkadot/runtime/test-runtime/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 16 +- .../001-async-backing-compatibility.toml | 34 - .../001-async-backing-compatibility.zndsl | 23 - .../002-async-backing-runtime-upgrade.toml | 54 - .../002-async-backing-runtime-upgrade.zndsl | 34 - .../003-async-backing-collator-mix.toml | 40 - .../003-async-backing-collator-mix.zndsl | 19 - .../zombienet_tests/async_backing/README.md | 9 - .../0002-parachains-upgrade-smoke-test.toml | 4 +- 107 files changed, 2410 insertions(+), 2792 deletions(-) rename polkadot/node/network/protocol/src/request_response/{vstaging.rs => v2.rs} (93%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/candidates.rs (99%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/cluster.rs (99%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/grid.rs (99%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/groups.rs (96%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/mod.rs (97%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/requests.rs (99%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/statement_store.rs (98%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/tests/cluster.rs (95%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/tests/grid.rs (95%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/tests/mod.rs (98%) rename polkadot/node/network/statement-distribution/src/{vstaging => v2}/tests/requests.rs (95%) delete mode 100644 polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs create mode 100644 polkadot/primitives/src/v6/async_backing.rs rename polkadot/primitives/src/{v5 => v6}/executor_params.rs (100%) rename polkadot/primitives/src/{v5 => v6}/metrics.rs (100%) rename polkadot/primitives/src/{v5 => v6}/mod.rs (99%) rename polkadot/primitives/src/{v5 => v6}/signed.rs (100%) rename polkadot/primitives/src/{v5 => v6}/slashing.rs (100%) rename polkadot/runtime/parachains/src/runtime_api_impl/{v5.rs => v7.rs} (79%) delete mode 100644 polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.toml delete mode 100644 polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl delete mode 100644 polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml delete mode 100644 polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl delete mode 100644 polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.toml delete mode 100644 polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl delete mode 100644 polkadot/zombienet_tests/async_backing/README.md diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index e420baf486a..0402c194134 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/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index c1dbc6db36f..cd281324ee5 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/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 39eda5075e2..bc8d0d430c7 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-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 39056d6b651..226474d3d38 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 57e16bc4283..3f4c08ecbb8 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,16 @@ 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 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 bea2fc330a2..a83a18f7cd9 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 366d428eda7..08e4e8e34ab 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/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index c1e92b249d7..b1fd7d1ab7d 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, @@ -599,30 +598,22 @@ impl RelayChainRpcClient { } #[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 b53bdbdfc81..b7c274ceecd 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/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index a7e59a61c9b..a8f0a49223f 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -1447,7 +1447,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, }, diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 223a78dacc4..114b25d1261 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -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/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 7461165f2a1..2804128ec01 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -64,7 +64,7 @@ decl_test_relay_chains! { Hrmp: kusama_runtime::Hrmp, } }, - #[api_version(6)] + #[api_version(7)] pub struct Westend { genesis = westend::genesis(), on_init = (), @@ -79,7 +79,7 @@ decl_test_relay_chains! { Balances: westend_runtime::Balances, } }, - #[api_version(5)] + #[api_version(7)] pub struct Rococo { genesis = rococo::genesis(), on_init = (), @@ -94,7 +94,7 @@ decl_test_relay_chains! { Balances: rococo_runtime::Balances, } }, - #[api_version(5)] + #[api_version(7)] pub struct Wococo { genesis = rococo::genesis(), on_init = (), diff --git a/cumulus/test/relay-sproof-builder/src/lib.rs b/cumulus/test/relay-sproof-builder/src/lib.rs index 69a82d05d81..fbd2692a36b 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/polkadot/Cargo.toml b/polkadot/Cargo.toml index aacc6ad405c..6e82cb69f6e 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -68,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/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 53961c90a2a..799a229b6ad 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -76,4 +76,3 @@ runtime-metrics = [ "polkadot-node-metrics/runtime-metrics", "service/runtime-metrics", ] -network-protocol-staging = [ "service/network-protocol-staging" ] diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 27779f3d1ac..4e13755deed 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, @@ -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 da6b343e6ae..9094f40cca8 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 4c2fd6becb4..bdc8b3fa1af 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(); } diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 14f720b721f..b79515ed37a 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/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 9cd544a8c53..e44530b3f1b 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 ed2988fcb39..292e4ebe528 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 6e5844a62a1..fcca0dd0b53 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 eb12ea4537f..d2cd23fe95f 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/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 7f41d74e616..e05e5823a28 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,11 @@ 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, + para_backing_state: LruMap<(Hash, ParaId), Option>, + async_backing_params: LruMap, } impl Default for RequestResultCache { @@ -100,8 +97,8 @@ impl Default for RequestResultCache { 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)), + para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } } } @@ -401,14 +398,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 +413,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 +428,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 +445,34 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } - pub(crate) fn staging_para_backing_state( + 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 +512,15 @@ 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), + 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 ec9bf10fa6e..19b2f5565a2 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -166,12 +166,11 @@ where .requests_cache .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), SubmitReportDisputeLost(_, _, _, _) => {}, - - StagingParaBackingState(relay_parent, para_id, constraints) => self + 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 +296,10 @@ 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::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,19 +565,18 @@ where ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT, sender ), - - Request::StagingParaBackingState(para, sender) => { + Request::ParaBackingState(para, sender) => { query!( - StagingParaBackingState, - staging_para_backing_state(para), + ParaBackingState, + para_backing_state(para), ver = Request::STAGING_BACKING_STATE, sender ) }, - Request::StagingAsyncBackingParams(sender) => { + Request::AsyncBackingParams(sender) => { query!( - StagingAsyncBackingParams, - staging_async_backing_params(), + AsyncBackingParams, + async_backing_params(), ver = Request::STAGING_BACKING_STATE, sender ) diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index bb7c2968961..fb97139a802 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,18 +250,18 @@ 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") } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 70c20437d12..f76826d7fdf 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -26,8 +26,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 +602,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 +642,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 +1056,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 +1086,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 +1099,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 +1391,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 +1421,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 +1436,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 +2013,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 +2029,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 1e9ae7b6200..29c7d8aa45d 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/bitfield-distribution/src/lib.rs b/polkadot/node/network/bitfield-distribution/src/lib.rs index c85d874bc4d..68e381ab6be 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 d6795247e78..ba2434ea47d 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 82c67061d9a..7e86b46a7e0 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 127f46e0fa3..7c69cce4839 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 7fa1149593c..f15635f1f41 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 21cd134c54f..48287f8b74c 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 627c38b776f..53f947142d1 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 ad2ab99568c..304cabbaac8 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 b452c84c2cd..7dd2287dab6 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 bd55c35852f..fd9d7a746eb 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 62c033954f7..1edc6766417 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 4c92780f2da..a53e0028b9e 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 e8cf769d2e5..fcb408d54b1 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 1cb656e325d..9812998aab7 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 e2a007b308e..4da0f11da39 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 c5dc1ba14bd..4fa23507e86 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 c33b9eae325..379334ded24 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 1bed2c12fe2..901ac99b669 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 c2163783c2c..8dd68b297e3 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 baed4b84631..96f7adeb29b 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 ddc6b85645b..c613d5778f5 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 34a17b4baaa..6b90c579237 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 9ae76047383..fc2aff0da30 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 17a66a9ff79..ca3038f9b3f 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 b2eb9cccced..eead7df5224 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 d6b68510f1c..e660df5da17 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 55d847f8315..8adb8353ca9 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 4fd77d0ced1..3d53ff6d321 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 b2daa1c0ac7..d917b209052 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 4639720b322..e11d66c41a0 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 79925f2115d..f13496024fc 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 9ea926f24aa..74db431eda1 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 50d0477eb51..80dec1d75ab 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 0739f301943..a0af9579823 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 48ceebb1949..4150377a0c6 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 5eef5809b4d..0734b75c971 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/service/Cargo.toml b/polkadot/node/service/Cargo.toml index ee092e27733..ba5976fdcee 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -223,7 +223,3 @@ 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/src/lib.rs b/polkadot/node/service/src/lib.rs index 5286631fbbb..5991744dc3a 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -854,7 +854,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) = @@ -862,7 +862,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); @@ -1051,10 +1051,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 33127b638e5..7d1add11824 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/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index a53908d3c2c..eb94f1696c9 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,12 @@ pub enum RuntimeApiRequest { ), /// Get the minimum required backing votes. MinimumBackingVotes(SessionIndex, 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 +724,8 @@ 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 STAGING_BACKING_STATE: u32 = 7; } /// 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 06aa351efb4..3007e985b4f 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,21 @@ 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>; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -454,7 +454,7 @@ where async fn unapplied_slashes( &self, at: Hash, - ) -> Result, ApiError> { + ) -> Result, ApiError> { self.client.runtime_api().unapplied_slashes(at) } @@ -462,15 +462,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 +489,19 @@ 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) } } diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index 83c15fdef95..a14536a1766 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 1487077d9ed..c7b91bffb3d 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 eb063229752..00000000000 --- 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 daee4a8350e..e60a9ff82ee 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, @@ -227,7 +227,7 @@ specialize_requests! { 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_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 c078b17d217..8d7cef88a70 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/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index fcbba9bbe21..73b1fab529e 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -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/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 9121b379085..5adb6d25313 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,20 +33,21 @@ 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, +pub use v6::{ + async_backing, 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, - OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, + 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, 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, RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, @@ -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 e5f1aa4276e..6cb66d40204 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,37 @@ 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; } } diff --git a/polkadot/primitives/src/v6/async_backing.rs b/polkadot/primitives/src/v6/async_backing.rs new file mode 100644 index 00000000000..1abe87b6dec --- /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/v5/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs similarity index 100% rename from polkadot/primitives/src/v5/executor_params.rs rename to polkadot/primitives/src/v6/executor_params.rs 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 81743225403..cf900835517 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, 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 ea341ee5b4f..1429b0c326a 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/src/node/backing/prospective-parachains.md b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md index a48444a46e4..286aeddb986 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/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 082e1aca375..1709c1bf8b1 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -46,7 +46,7 @@ use runtime_parachains::{ 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, + runtime_api_impl::v7 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs index fe9a4e52bd0..d07964b6916 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 33039cd08ca..f53f986a553 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,7 +26,7 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, LEGACY_MIN_BACKING_VOTES, + AsyncBackingParams, Balance, 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}; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v6.rs b/polkadot/runtime/parachains/src/configuration/migration/v6.rs index beed54deaff..19031a90bab 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 11365138120..1754b78e0a1 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 5c5b3482183..d1bc9005112 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 b27a7ab1ad7..9b2b7a48dc8 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/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index e066ad825a3..ba74e488cd3 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 46a609e0368..35d92f71084 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 deef19d9071..d01b543630c 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -15,111 +15,3 @@ // along with Polkadot. If not, see . //! 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 -} diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index c9e3ded6dad..0b2dd12b154 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -34,7 +34,7 @@ use runtime_parachains::{ 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, + runtime_api_impl::v7 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index c7d429bc99a..dd05082d291 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -46,7 +46,7 @@ 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, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -1724,6 +1724,7 @@ sp_api::impl_runtime_apis! { } } + #[api_version(7)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1854,6 +1855,18 @@ 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::() + } } #[api_version(3)] diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 99d6e58bc40..99fd2198400 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, }; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index ad08360f382..e7cae7248bd 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -65,9 +65,7 @@ use runtime_parachains::{ 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, vstaging as parachains_staging_runtime_api_impl, - }, + runtime_api_impl::v7 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -1582,7 +1580,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(6)] + #[api_version(7)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1715,7 +1713,15 @@ 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::() } } 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 918fb5bf4f6..00000000000 --- 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 46c1d77acf4..00000000000 --- 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 e61f7dd47ef..00000000000 --- 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 6213d1afb81..00000000000 --- 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 4dca4d3d531..00000000000 --- 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 98436b0459c..00000000000 --- 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 9774ea3c25c..00000000000 --- 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/smoke/0002-parachains-upgrade-smoke-test.toml b/polkadot/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.toml index 0becb408550..d72e3ebdb33 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" -- GitLab From 8b061a5c5d29a4ef8efa0f2919fdc5c3cfc36361 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Wed, 27 Sep 2023 14:46:14 +0200 Subject: [PATCH 217/633] Associated type Hasher for `QueryPreimage`, `StorePreimage` and `Bounded` (#1720) I hope it's enough to fix #1701 the only solution I found to make it happen is to put an associated type to the `Bounded` enum as well. @liamaharon @kianenigma @bkchr Polkadot address: 12poSUQPtcF1HUPQGY3zZu2P8emuW9YnsPduA4XG3oCEfJVp --------- Signed-off-by: muraca Co-authored-by: Liam Aharon Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/democracy/src/benchmarking.rs | 7 +- substrate/frame/democracy/src/lib.rs | 54 +++++---- substrate/frame/democracy/src/tests.rs | 2 +- .../frame/democracy/src/tests/metadata.rs | 6 +- substrate/frame/preimage/src/lib.rs | 10 +- substrate/frame/preimage/src/tests.rs | 29 +++-- substrate/frame/referenda/src/benchmarking.rs | 4 +- substrate/frame/referenda/src/lib.rs | 29 +++-- substrate/frame/referenda/src/mock.rs | 2 +- substrate/frame/referenda/src/tests.rs | 3 +- substrate/frame/referenda/src/types.rs | 3 +- substrate/frame/scheduler/src/benchmarking.rs | 4 +- substrate/frame/scheduler/src/lib.rs | 35 +++--- substrate/frame/scheduler/src/migration.rs | 2 +- substrate/frame/scheduler/src/tests.rs | 2 +- substrate/frame/support/src/traits.rs | 2 +- .../frame/support/src/traits/preimages.rs | 110 ++++++++++-------- .../frame/support/src/traits/schedule.rs | 8 +- substrate/frame/whitelist/src/benchmarking.rs | 4 +- substrate/frame/whitelist/src/lib.rs | 32 ++--- 20 files changed, 189 insertions(+), 159 deletions(-) diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs index e4a21a4e1d9..b4aa17726b8 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 e538d31c6ad..089556191cd 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 9b885fb5915..ebccf32e342 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 5a36d80b726..1b6d66a8bc4 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/preimage/src/lib.rs b/substrate/frame/preimage/src/lib.rs index 4dda0207e62..e344bdfe2d8 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, }; @@ -531,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) } @@ -555,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/tests.rs b/substrate/frame/preimage/src/tests.rs index a473a0ae8e2..7609ec83e90 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/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index e884a0bb6ec..47d43cc0600 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 d4dbbf8a3c9..be21375f526 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/mock.rs b/substrate/frame/referenda/src/mock.rs index c23fa4609d4..dce91f7dbfd 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 d748c524605..8f51136de0b 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 ba89383888a..8d6a13ef27c 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/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index 341a19cdb23..cc86a179737 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 3da4aa03cae..532ffe7bd71 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -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 06259768f0a..9c8b0da03fc 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 25a60732e06..1bf8b3e5f3a 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/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 10ae5d83b5a..2179ee38f84 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -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/preimages.rs b/substrate/frame/support/src/traits/preimages.rs index bf08a286dd7..647af029c16 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 74a5951142d..7a7d1357da1 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/whitelist/src/benchmarking.rs b/substrate/frame/whitelist/src/benchmarking.rs index 1982f5eb873..9d356f09a9d 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 decf010b067..44551abd107 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); -- GitLab From 69ed3087e182d1f08209233eda20cb7531a69f44 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:37:00 +0200 Subject: [PATCH 218/633] OpenGov in Westend and Rococo (#1177) Migrating [PR from the archived polkadot repo](https://github.com/paritytech/polkadot/pull/7272) As per https://github.com/paritytech/polkadot/pull/7272#issuecomment-1559240466, the changes in this MR include the following pallets into [x] Rococo and [x] Westend runtimes: pallet_conviction_voting pallet_referenda pallet_ranked_collective pallet_custom_origins pallet_whitelist And only for westend-runtime: pallet_treasury Following [Kusama runtime config](https://github.com/paritytech/polkadot/tree/dbae30efe080a1d41fe54ef4da8af47614c9ca93/runtime/kusama/src) as a baseline. Benchmarking of the following pallets done for both Rococo and Westend: pallet_conviction_voting pallet_referenda pallet_ranked_collective (only on Rococo) pallet_whitelist And only for Westend: pallet_treasury Removed Gov1 from Rococo as in https://github.com/paritytech/polkadot/pull/6701 Rococo Gov1 storage will be cleaned in a different PR - [issue ](https://github.com/paritytech/polkadot-sdk/issues/1618) --------- Co-authored-by: Giles Cope --- Cargo.lock | 39 +- polkadot/node/service/src/chain_spec.rs | 18 +- polkadot/runtime/rococo/Cargo.toml | 18 + .../rococo/src/governance/fellowship.rs | 343 ++++++++++++ polkadot/runtime/rococo/src/governance/mod.rs | 93 ++++ .../runtime/rococo/src/governance/origins.rs | 194 +++++++ .../runtime/rococo/src/governance/tracks.rs | 320 +++++++++++ polkadot/runtime/rococo/src/lib.rs | 311 +++-------- polkadot/runtime/rococo/src/weights/mod.rs | 11 +- .../rococo/src/weights/pallet_collective.rs | 196 ------- .../src/weights/pallet_collective_council.rs | 322 ----------- .../pallet_collective_technical_committee.rs | 324 ----------- .../src/weights/pallet_conviction_voting.rs | 195 +++++++ .../rococo/src/weights/pallet_democracy.rs | 525 ------------------ .../src/weights/pallet_elections_phragmen.rs | 315 ----------- .../rococo/src/weights/pallet_membership.rs | 204 ------- .../src/weights/pallet_ranked_collective.rs | 175 ++++++ .../pallet_referenda_fellowship_referenda.rs | 524 +++++++++++++++++ .../src/weights/pallet_referenda_referenda.rs | 522 +++++++++++++++++ .../runtime/rococo/src/weights/pallet_tips.rs | 161 ------ .../rococo/src/weights/pallet_whitelist.rs | 116 ++++ polkadot/runtime/rococo/src/xcm_config.rs | 50 +- polkadot/runtime/westend/Cargo.toml | 14 + polkadot/runtime/westend/constants/src/lib.rs | 20 + .../runtime/westend/src/governance/mod.rs | 97 ++++ .../runtime/westend/src/governance/origins.rs | 194 +++++++ .../runtime/westend/src/governance/tracks.rs | 320 +++++++++++ polkadot/runtime/westend/src/lib.rs | 107 +++- polkadot/runtime/westend/src/weights/mod.rs | 5 + .../src/weights/pallet_conviction_voting.rs | 194 +++++++ .../pallet_referenda_fellowship_referenda.rs | 525 ++++++++++++++++++ .../src/weights/pallet_referenda_referenda.rs | 523 +++++++++++++++++ .../westend/src/weights/pallet_treasury.rs | 150 +++++ .../westend/src/weights/pallet_whitelist.rs | 116 ++++ polkadot/runtime/westend/src/xcm_config.rs | 108 +++- 35 files changed, 4964 insertions(+), 2385 deletions(-) create mode 100644 polkadot/runtime/rococo/src/governance/fellowship.rs create mode 100644 polkadot/runtime/rococo/src/governance/mod.rs create mode 100644 polkadot/runtime/rococo/src/governance/origins.rs create mode 100644 polkadot/runtime/rococo/src/governance/tracks.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_collective.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_collective_council.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_collective_technical_committee.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_democracy.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_elections_phragmen.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_membership.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_tips.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_whitelist.rs create mode 100644 polkadot/runtime/westend/src/governance/mod.rs create mode 100644 polkadot/runtime/westend/src/governance/origins.rs create mode 100644 polkadot/runtime/westend/src/governance/tracks.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_conviction_voting.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_referenda_referenda.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_treasury.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_whitelist.rs diff --git a/Cargo.lock b/Cargo.lock index dcfd8cd6601..7a11c5b7f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1152,7 +1152,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -1193,7 +1193,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -5601,7 +5601,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "waker-fn", ] @@ -5658,7 +5658,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "pin-utils", "slab", ] @@ -6067,7 +6067,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -6110,7 +6110,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "socket2 0.4.9", "tokio", "tower-service", @@ -11366,9 +11366,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -13172,7 +13172,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "windows-sys 0.48.0", ] @@ -13951,7 +13951,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "rustls 0.21.6", "rustls-pemfile", "serde", @@ -14128,6 +14128,7 @@ dependencies = [ "pallet-bounties", "pallet-child-bounties", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-elections-phragmen", "pallet-grandpa", @@ -14142,7 +14143,9 @@ dependencies = [ "pallet-offences", "pallet-preimage", "pallet-proxy", + "pallet-ranked-collective", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-society", @@ -14156,6 +14159,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", @@ -14171,6 +14175,7 @@ dependencies = [ "serde_json", "smallvec", "sp-api", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", @@ -18789,7 +18794,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "signal-hook-registry", "socket2 0.5.3", "tokio-macros", @@ -18835,7 +18840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tokio", "tokio-util", ] @@ -18875,7 +18880,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tokio", "tracing", ] @@ -18947,7 +18952,7 @@ dependencies = [ "http", "http-body", "http-range-header", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tower-layer", "tower-service", ] @@ -18972,7 +18977,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tracing-attributes", "tracing-core", ] @@ -20257,6 +20262,7 @@ dependencies = [ "pallet-beefy", "pallet-beefy-mmr", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", @@ -20278,6 +20284,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -20293,6 +20300,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", @@ -20308,6 +20316,7 @@ dependencies = [ "smallvec", "sp-api", "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 7fd9ce61c95..97b3fab89e3 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -425,6 +425,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(), }, @@ -716,7 +717,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), @@ -724,13 +724,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![], @@ -992,6 +985,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(), }, @@ -1062,14 +1056,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![] }, diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 64cf6207236..106d8aafa76 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -24,6 +24,7 @@ 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 } @@ -48,6 +49,7 @@ 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 } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } @@ -63,7 +65,9 @@ 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 } @@ -77,6 +81,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 } @@ -135,6 +140,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", @@ -149,7 +155,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", @@ -163,6 +171,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", @@ -175,6 +184,7 @@ std = [ "serde/std", "serde_derive", "sp-api/std", + "sp-arithmetic/std", "sp-core/std", "sp-genesis-builder/std", "sp-io/std", @@ -201,6 +211,7 @@ 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", @@ -215,7 +226,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", @@ -226,6 +239,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", @@ -252,6 +266,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", @@ -266,7 +281,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", @@ -279,6 +296,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", diff --git a/polkadot/runtime/rococo/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs new file mode 100644 index 00000000000..b5df6cf2df3 --- /dev/null +++ b/polkadot/runtime/rococo/src/governance/fellowship.rs @@ -0,0 +1,343 @@ +// 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 . + +//! Elements of governance concerning the Rococo Fellowship. + +use frame_support::traits::{MapSuccess, TryMapSuccess}; +use sp_runtime::traits::{CheckedReduceBy, ConstU16, Replace}; + +use super::*; +use crate::{CENTS, DAYS}; + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 0; + pub const UndecidingTimeout: BlockNumber = 7 * DAYS; +} + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + static DATA: [(u16, pallet_referenda::TrackInfo); 10] = [ + ( + 0u16, + pallet_referenda::TrackInfo { + name: "candidates", + max_deciding: 10, + decision_deposit: 100 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 1u16, + pallet_referenda::TrackInfo { + name: "members", + max_deciding: 10, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 2u16, + pallet_referenda::TrackInfo { + name: "proficients", + max_deciding: 10, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 3u16, + pallet_referenda::TrackInfo { + name: "fellows", + max_deciding: 10, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 4u16, + pallet_referenda::TrackInfo { + name: "senior fellows", + max_deciding: 10, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 5u16, + pallet_referenda::TrackInfo { + name: "experts", + max_deciding: 10, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 6u16, + pallet_referenda::TrackInfo { + name: "senior experts", + max_deciding: 10, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 7u16, + pallet_referenda::TrackInfo { + name: "masters", + max_deciding: 10, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 8u16, + pallet_referenda::TrackInfo { + name: "senior masters", + max_deciding: 10, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + 9u16, + pallet_referenda::TrackInfo { + name: "grand masters", + max_deciding: 10, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 1 * MINUTES, + 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(0), + ceil: Perbill::from_percent(50), + }, + }, + ), + ]; + &DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + use super::origins::Origin; + + #[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(9) + } + } + + match Origin::try_from(id.clone()) { + Ok(Origin::FellowshipInitiates) => Ok(0), + Ok(Origin::Fellowship1Dan) => Ok(1), + Ok(Origin::Fellowship2Dan) => Ok(2), + Ok(Origin::Fellowship3Dan) | Ok(Origin::Fellows) => Ok(3), + Ok(Origin::Fellowship4Dan) => Ok(4), + Ok(Origin::Fellowship5Dan) | Ok(Origin::FellowshipExperts) => Ok(5), + Ok(Origin::Fellowship6Dan) => Ok(6), + Ok(Origin::Fellowship7Dan | Origin::FellowshipMasters) => Ok(7), + Ok(Origin::Fellowship8Dan) => Ok(8), + Ok(Origin::Fellowship9Dan) => Ok(9), + _ => Err(()), + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +pub type FellowshipReferendaInstance = pallet_referenda::Instance2; + +impl pallet_referenda::Config for Runtime { + type WeightInfo = weights::pallet_referenda_fellowship_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = + pallet_ranked_collective::EnsureMember; + type CancelOrigin = FellowshipExperts; + type KillOrigin = FellowshipMasters; + type Slash = Treasury; + type Votes = pallet_ranked_collective::Votes; + type Tally = pallet_ranked_collective::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} + +pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; + +impl pallet_ranked_collective::Config for Runtime { + type WeightInfo = weights::pallet_ranked_collective::WeightInfo; + type RuntimeEvent = RuntimeEvent; + // Promotion is by any of: + // - Root can demote arbitrarily. + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a vote by the rank *above* the new rank. + type PromoteOrigin = EitherOf< + frame_system::EnsureRootWithSuccess>, + EitherOf< + MapSuccess>>, + TryMapSuccess>>, + >, + >; + // Demotion is by any of: + // - Root can demote arbitrarily. + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a vote by the rank two above the current rank. + type DemoteOrigin = EitherOf< + frame_system::EnsureRootWithSuccess>, + EitherOf< + MapSuccess>>, + TryMapSuccess>>, + >, + >; + type Polls = FellowshipReferenda; + type MinRankOfClass = sp_runtime::traits::Identity; + type VoteWeight = pallet_ranked_collective::Geometric; +} diff --git a/polkadot/runtime/rococo/src/governance/mod.rs b/polkadot/runtime/rococo/src/governance/mod.rs new file mode 100644 index 00000000000..ef2adf60753 --- /dev/null +++ b/polkadot/runtime/rococo/src/governance/mod.rs @@ -0,0 +1,93 @@ +// 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 . + +//! New governance configurations for the Rococo runtime. + +use super::*; +use frame_support::{ + parameter_types, + traits::{ConstU16, EitherOf}, +}; +use frame_system::EnsureRootWithSuccess; + +mod origins; +pub use origins::{ + pallet_custom_origins, AuctionAdmin, Fellows, FellowshipAdmin, FellowshipExperts, + FellowshipInitiates, FellowshipMasters, GeneralAdmin, LeaseAdmin, ReferendumCanceller, + ReferendumKiller, Spender, StakingAdmin, Treasurer, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; +mod fellowship; +pub use fellowship::{FellowshipCollectiveInstance, FellowshipReferendaInstance}; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = + frame_support::traits::tokens::currency::ActiveIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 1 * 3 * CENTS; + pub const UndecidingTimeout: BlockNumber = 14 * DAYS; +} + +parameter_types! { + pub const MaxBalance: Balance = Balance::max_value(); +} +pub type TreasurySpender = EitherOf, Spender>; + +impl origins::pallet_custom_origins::Config for Runtime {} + +impl pallet_whitelist::Config for Runtime { + type WeightInfo = weights::pallet_whitelist::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WhitelistOrigin = + EitherOf>, Fellows>; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = weights::pallet_referenda_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/polkadot/runtime/rococo/src/governance/origins.rs b/polkadot/runtime/rococo/src/governance/origins.rs new file mode 100644 index 00000000000..e4639f40dc4 --- /dev/null +++ b/polkadot/runtime/rococo/src/governance/origins.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 . + +//! Custom origins for governance interventions. + +pub use pallet_custom_origins::*; + +#[frame_support::pallet] +pub mod pallet_custom_origins { + use crate::{Balance, CENTS, GRAND}; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Origin for cancelling slashes. + StakingAdmin, + /// Origin for spending (any amount of) funds. + Treasurer, + /// Origin for managing the composition of the fellowship. + FellowshipAdmin, + /// Origin for managing the registrar. + GeneralAdmin, + /// Origin for starting auctions. + AuctionAdmin, + /// Origin able to force slot leases. + LeaseAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Origin able to spend up to 1 KSM from the treasury at once. + SmallTipper, + /// Origin able to spend up to 5 KSM from the treasury at once. + BigTipper, + /// Origin able to spend up to 50 KSM from the treasury at once. + SmallSpender, + /// Origin able to spend up to 500 KSM from the treasury at once. + MediumSpender, + /// 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 { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + StakingAdmin, + Treasurer, + FellowshipAdmin, + GeneralAdmin, + AuctionAdmin, + LeaseAdmin, + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + FellowshipInitiates: u16 = 0, + Fellows: u16 = 3, + FellowshipExperts: u16 = 5, + FellowshipMasters: u16 = 7, + ); + + macro_rules! decl_ensure { + ( + $vis:vis type $name:ident: EnsureOrigin { + $( $item:ident = $success:expr, )* + } + ) => { + $vis struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + $( + Origin::$item => Ok($success), + )* + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // By convention the more privileged origins go later, so for greatest chance + // of success, we want the last one. + let _result: Result = Err(()); + $( + let _result: Result = Ok(O::from(Origin::$item)); + )* + _result + } + } + } + } + + decl_ensure! { + pub type Spender: EnsureOrigin { + SmallTipper = 250 * 3 * CENTS, + BigTipper = 1 * GRAND, + SmallSpender = 10 * GRAND, + MediumSpender = 100 * GRAND, + BigSpender = 1_000 * GRAND, + 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/rococo/src/governance/tracks.rs b/polkadot/runtime/rococo/src/governance/tracks.rs new file mode 100644 index 00000000000..3765569f183 --- /dev/null +++ b/polkadot/runtime/rococo/src/governance/tracks.rs @@ -0,0 +1,320 @@ +// 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 . + +//! Track configurations for governance. + +use super::*; + +const fn percent(x: i32) -> sp_arithmetic::FixedI64 { + sp_arithmetic::FixedI64::from_rational(x as u128, 100) +} +use pallet_referenda::Curve; +const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_STAKING_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_FELLOWSHIP_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); +const APP_AUCTION_ADMIN: Curve = + Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_AUCTION_ADMIN: Curve = + Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); +const APP_LEASE_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_LEASE_ADMIN: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_REFERENDUM_CANCELLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_CANCELLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_REFERENDUM_KILLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_KILLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); +const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_SMALL_SPENDER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); +const SUP_MEDIUM_SPENDER: Curve = + Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); +const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); +const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); +const APP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); +const SUP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 100 * GRAND, + 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, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * GRAND, + 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, + }, + ), + ( + 10, + pallet_referenda::TrackInfo { + name: "staking_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 11, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 10, + decision_deposit: 1 * GRAND, + 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, + }, + ), + ( + 12, + pallet_referenda::TrackInfo { + name: "lease_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 13, + pallet_referenda::TrackInfo { + name: "fellowship_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 14, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 15, + pallet_referenda::TrackInfo { + name: "auction_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 20, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 1_000, + decision_deposit: 10 * GRAND, + 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, + }, + ), + ( + 21, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 1_000, + decision_deposit: 50 * GRAND, + 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, + }, + ), + ( + 30, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 200, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 1 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 4 * MINUTES, + min_enactment_period: 1 * MINUTES, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 31, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 100, + 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, + }, + ), + ( + 32, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 50, + 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, + }, + ), + ( + 33, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 50, + 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, + }, + ), + ( + 34, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 50, + 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, + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + _ => Err(()), + } + } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { + match custom_origin { + origins::Origin::WhitelistedCaller => Ok(1), + // General admin + origins::Origin::StakingAdmin => Ok(10), + origins::Origin::Treasurer => Ok(11), + origins::Origin::LeaseAdmin => Ok(12), + origins::Origin::FellowshipAdmin => Ok(13), + origins::Origin::GeneralAdmin => Ok(14), + origins::Origin::AuctionAdmin => Ok(15), + // Referendum admins + origins::Origin::ReferendumCanceller => Ok(20), + origins::Origin::ReferendumKiller => Ok(21), + // Limited treasury spenders + origins::Origin::SmallTipper => Ok(30), + origins::Origin::BigTipper => Ok(31), + origins::Origin::SmallSpender => Ok(32), + origins::Origin::MediumSpender => Ok(33), + origins::Origin::BigSpender => Ok(34), + _ => Err(()), + } + } else { + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index dd05082d291..4bdcc123739 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -62,8 +62,8 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, Contains, EitherOfDiverse, EverythingBut, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, PrivilegeCmp, ProcessMessage, + fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, @@ -88,7 +88,6 @@ 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; pub use frame_system::Call as SystemCall; @@ -103,6 +102,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); @@ -117,7 +123,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, @@ -186,11 +192,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; @@ -203,11 +204,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, } @@ -220,7 +216,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; @@ -380,171 +378,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; @@ -563,16 +396,11 @@ parameter_types! { pub const MaxPeerInHeartbeats: u32 = 10_000; } -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; @@ -584,7 +412,7 @@ 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; } parameter_types! { @@ -625,17 +453,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; @@ -746,8 +563,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; } @@ -771,8 +587,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; } @@ -913,15 +729,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(..) | @@ -948,17 +763,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 { .. }) | @@ -1184,7 +1000,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; } @@ -1217,11 +1033,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; @@ -1229,7 +1040,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; } @@ -1425,13 +1236,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, @@ -1466,9 +1283,6 @@ construct_runtime! { 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; @@ -1563,6 +1377,8 @@ 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, ); } @@ -1629,28 +1445,27 @@ 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_whitelist, Whitelist] // XCM [pallet_xcm, XcmPallet] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] @@ -2143,7 +1958,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 {} @@ -2152,7 +1967,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 @@ -2165,7 +1980,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; @@ -2204,15 +2019,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)) diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 21558ca3fb9..e0c1c4f4135 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -20,27 +20,26 @@ 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_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_collective.rs deleted file mode 100644 index 9bf6671e229..00000000000 --- 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 835bdef7e67..00000000000 --- 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 6d66dc871cd..00000000000 --- 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/rococo/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs new file mode 100644 index 00000000000..ba505737f1b --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs @@ -0,0 +1,195 @@ +// 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-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_conviction_voting +// --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_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: 151_077_000 picoseconds. + Weight::from_parts(165_283_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: 232_420_000 picoseconds. + Weight::from_parts(244_439_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: 205_017_000 picoseconds. + Weight::from_parts(216_594_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: 84_226_000 picoseconds. + Weight::from_parts(91_255_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: 78_708_000 picoseconds. + Weight::from_parts(2_053_488_615, 0) + .saturating_add(Weight::from_parts(0, 83866)) + // Standard Error: 179_271 + .saturating_add(Weight::from_parts(47_806_482, 0).saturating_mul(r.into())) + .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: 45_232_000 picoseconds. + Weight::from_parts(2_045_021_014, 0) + .saturating_add(Weight::from_parts(0, 83866)) + // Standard Error: 185_130 + .saturating_add(Weight::from_parts(47_896_011, 0).saturating_mul(r.into())) + .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: 116_446_000 picoseconds. + Weight::from_parts(124_043_000, 0) + .saturating_add(Weight::from_parts(0, 30706)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_democracy.rs b/polkadot/runtime/rococo/src/weights/pallet_democracy.rs deleted file mode 100644 index 00629a5c110..00000000000 --- 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 fe6aca5ab88..00000000000 --- 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 4486c7a270c..00000000000 --- 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 00000000000..8a556c3a248 --- /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 00000000000..96f172230e1 --- /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 00000000000..b7cc5df28b9 --- /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 c4710afd78e..00000000000 --- 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_whitelist.rs b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs new file mode 100644 index 00000000000..7c307deec4c --- /dev/null +++ b/polkadot/runtime/rococo/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-08-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-aahe6cbd-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-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=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_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: `223` + // Estimated: `3556` + // 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`) + fn remove_whitelisted_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `352` + // Estimated: `3556` + // Minimum execution time: 20_247_000 picoseconds. + Weight::from_parts(20_808_000, 0) + .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: `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`) + /// The range of component `n` is `[1, 10000]`. + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `352` + // Estimated: `3556` + // Minimum execution time: 23_833_000 picoseconds. + Weight::from_parts(24_698_994, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 445cb801435..b84d2335a69 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}, @@ -38,9 +41,9 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal, DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete, - MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithUniqueTopic, + MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -110,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(); @@ -119,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; @@ -129,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, ); @@ -193,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()); @@ -201,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/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index e23d322b5a7..de9d6666059 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -24,6 +24,7 @@ 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 } @@ -65,10 +66,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 } @@ -84,6 +87,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 } @@ -147,6 +151,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", @@ -168,6 +173,7 @@ std = [ "pallet-preimage/std", "pallet-proxy/std", "pallet-recovery/std", + "pallet-referenda/std", "pallet-scheduler/std", "pallet-session-benchmarking?/std", "pallet-session/std", @@ -182,6 +188,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", @@ -195,6 +202,7 @@ std = [ "serde_derive", "sp-api/std", "sp-application-crypto/std", + "sp-arithmetic/std", "sp-core/std", "sp-genesis-builder/std", "sp-io/std", @@ -224,6 +232,7 @@ 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", @@ -244,6 +253,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", @@ -254,6 +264,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", @@ -280,6 +291,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", @@ -297,6 +309,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", @@ -308,6 +321,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", diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index f9830dab332..0dd64d092c3 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/westend/src/governance/mod.rs b/polkadot/runtime/westend/src/governance/mod.rs new file mode 100644 index 00000000000..d027f788d71 --- /dev/null +++ b/polkadot/runtime/westend/src/governance/mod.rs @@ -0,0 +1,97 @@ +// 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 . + +//! New governance configurations for the Kusama runtime. + +use super::*; +use crate::xcm_config::Collectives; +use frame_support::{parameter_types, traits::EitherOf}; +use frame_system::EnsureRootWithSuccess; +use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use xcm::latest::BodyId; + +mod origins; +pub use origins::{ + pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, + ReferendumCanceller, ReferendumKiller, Spender, StakingAdmin, Treasurer, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = + frame_support::traits::tokens::currency::ActiveIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 1 * 3 * CENTS; + pub const UndecidingTimeout: BlockNumber = 14 * DAYS; +} + +parameter_types! { + pub const MaxBalance: Balance = Balance::max_value(); +} +pub type TreasurySpender = EitherOf, Spender>; + +impl origins::pallet_custom_origins::Config for Runtime {} + +parameter_types! { + // Fellows pluralistic body. + pub const FellowsBodyId: BodyId = BodyId::Technical; +} + +impl pallet_whitelist::Config for Runtime { + type WeightInfo = weights::pallet_whitelist::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WhitelistOrigin = EitherOfDiverse< + EnsureRoot, + EnsureXcm>, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = weights::pallet_referenda_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/polkadot/runtime/westend/src/governance/origins.rs b/polkadot/runtime/westend/src/governance/origins.rs new file mode 100644 index 00000000000..e4639f40dc4 --- /dev/null +++ b/polkadot/runtime/westend/src/governance/origins.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 . + +//! Custom origins for governance interventions. + +pub use pallet_custom_origins::*; + +#[frame_support::pallet] +pub mod pallet_custom_origins { + use crate::{Balance, CENTS, GRAND}; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Origin for cancelling slashes. + StakingAdmin, + /// Origin for spending (any amount of) funds. + Treasurer, + /// Origin for managing the composition of the fellowship. + FellowshipAdmin, + /// Origin for managing the registrar. + GeneralAdmin, + /// Origin for starting auctions. + AuctionAdmin, + /// Origin able to force slot leases. + LeaseAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Origin able to spend up to 1 KSM from the treasury at once. + SmallTipper, + /// Origin able to spend up to 5 KSM from the treasury at once. + BigTipper, + /// Origin able to spend up to 50 KSM from the treasury at once. + SmallSpender, + /// Origin able to spend up to 500 KSM from the treasury at once. + MediumSpender, + /// 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 { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + StakingAdmin, + Treasurer, + FellowshipAdmin, + GeneralAdmin, + AuctionAdmin, + LeaseAdmin, + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + FellowshipInitiates: u16 = 0, + Fellows: u16 = 3, + FellowshipExperts: u16 = 5, + FellowshipMasters: u16 = 7, + ); + + macro_rules! decl_ensure { + ( + $vis:vis type $name:ident: EnsureOrigin { + $( $item:ident = $success:expr, )* + } + ) => { + $vis struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + $( + Origin::$item => Ok($success), + )* + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // By convention the more privileged origins go later, so for greatest chance + // of success, we want the last one. + let _result: Result = Err(()); + $( + let _result: Result = Ok(O::from(Origin::$item)); + )* + _result + } + } + } + } + + decl_ensure! { + pub type Spender: EnsureOrigin { + SmallTipper = 250 * 3 * CENTS, + BigTipper = 1 * GRAND, + SmallSpender = 10 * GRAND, + MediumSpender = 100 * GRAND, + BigSpender = 1_000 * GRAND, + 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/westend/src/governance/tracks.rs b/polkadot/runtime/westend/src/governance/tracks.rs new file mode 100644 index 00000000000..3765569f183 --- /dev/null +++ b/polkadot/runtime/westend/src/governance/tracks.rs @@ -0,0 +1,320 @@ +// 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 . + +//! Track configurations for governance. + +use super::*; + +const fn percent(x: i32) -> sp_arithmetic::FixedI64 { + sp_arithmetic::FixedI64::from_rational(x as u128, 100) +} +use pallet_referenda::Curve; +const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_STAKING_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_FELLOWSHIP_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); +const APP_AUCTION_ADMIN: Curve = + Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_AUCTION_ADMIN: Curve = + Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); +const APP_LEASE_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_LEASE_ADMIN: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_REFERENDUM_CANCELLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_CANCELLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_REFERENDUM_KILLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_KILLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); +const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_SMALL_SPENDER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); +const SUP_MEDIUM_SPENDER: Curve = + Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); +const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); +const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); +const APP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); +const SUP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 100 * GRAND, + 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, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * GRAND, + 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, + }, + ), + ( + 10, + pallet_referenda::TrackInfo { + name: "staking_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 11, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 10, + decision_deposit: 1 * GRAND, + 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, + }, + ), + ( + 12, + pallet_referenda::TrackInfo { + name: "lease_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 13, + pallet_referenda::TrackInfo { + name: "fellowship_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 14, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 15, + pallet_referenda::TrackInfo { + name: "auction_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + 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, + }, + ), + ( + 20, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 1_000, + decision_deposit: 10 * GRAND, + 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, + }, + ), + ( + 21, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 1_000, + decision_deposit: 50 * GRAND, + 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, + }, + ), + ( + 30, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 200, + decision_deposit: 1 * 3 * CENTS, + prepare_period: 1 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 4 * MINUTES, + min_enactment_period: 1 * MINUTES, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 31, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 100, + 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, + }, + ), + ( + 32, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 50, + 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, + }, + ), + ( + 33, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 50, + 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, + }, + ), + ( + 34, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 50, + 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, + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + _ => Err(()), + } + } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { + match custom_origin { + origins::Origin::WhitelistedCaller => Ok(1), + // General admin + origins::Origin::StakingAdmin => Ok(10), + origins::Origin::Treasurer => Ok(11), + origins::Origin::LeaseAdmin => Ok(12), + origins::Origin::FellowshipAdmin => Ok(13), + origins::Origin::GeneralAdmin => Ok(14), + origins::Origin::AuctionAdmin => Ok(15), + // Referendum admins + origins::Origin::ReferendumCanceller => Ok(20), + origins::Origin::ReferendumKiller => Ok(21), + // Limited treasury spenders + origins::Origin::SmallTipper => Ok(30), + origins::Origin::BigTipper => Ok(31), + origins::Origin::SmallSpender => Ok(32), + origins::Origin::MediumSpender => Ok(33), + origins::Origin::BigSpender => Ok(34), + _ => Err(()), + } + } else { + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index e7cae7248bd..b1231a5d95f 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; @@ -31,9 +31,9 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EverythingBut, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, - WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, + ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -80,7 +80,7 @@ use sp_runtime::{ 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::*}; @@ -107,6 +107,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; @@ -122,7 +129,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, @@ -197,7 +204,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; @@ -683,7 +692,40 @@ 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 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 = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type SpendOrigin = TreasurySpender; } impl pallet_offences::Config for Runtime { @@ -699,8 +741,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 { @@ -814,8 +854,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; } @@ -912,6 +952,7 @@ parameter_types! { pub enum ProxyType { Any, NonTransfer, + Governance, Staking, SudoBalances, IdentityJudgement, @@ -944,6 +985,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{..}) | @@ -989,6 +1033,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 { .. }) | @@ -1184,7 +1235,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 { @@ -1193,7 +1244,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; } @@ -1207,7 +1258,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; } @@ -1247,7 +1298,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; } @@ -1352,6 +1403,15 @@ construct_runtime! { // 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, @@ -1445,6 +1505,7 @@ pub mod migrations { UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::VersionCheckedMigrateToV1, + pallet_referenda::migration::v1::MigrateV0ToV1, ); } @@ -1485,6 +1546,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] @@ -1498,14 +1560,17 @@ 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] // XCM [pallet_xcm, XcmPallet] // NOTE: Make sure you point to the individual modules below. @@ -2059,13 +2124,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. @@ -2078,7 +2143,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; @@ -2117,15 +2182,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)) diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 531de5527de..faa94bcac58 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -19,6 +19,7 @@ pub mod frame_election_provider_support; pub mod frame_system; 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 +30,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_conviction_voting.rs b/polkadot/runtime/westend/src/weights/pallet_conviction_voting.rs new file mode 100644 index 00000000000..8965a7392ed --- /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_referenda_fellowship_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs new file mode 100644 index 00000000000..a4ac0667911 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs @@ -0,0 +1,525 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_referenda` +//! +//! 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_referenda +// --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_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: 28_969_000 picoseconds. + Weight::from_parts(30_902_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: `404` + // Estimated: `83866` + // Minimum execution time: 53_500_000 picoseconds. + Weight::from_parts(54_447_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: `2042` + // Estimated: `42428` + // Minimum execution time: 114_321_000 picoseconds. + Weight::from_parts(122_607_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: `2083` + // Estimated: `42428` + // Minimum execution time: 113_476_000 picoseconds. + Weight::from_parts(120_078_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: 194_798_000 picoseconds. + Weight::from_parts(208_378_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: 69_502_000 picoseconds. + Weight::from_parts(71_500_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: `317` + // Estimated: `4365` + // Minimum execution time: 30_561_000 picoseconds. + Weight::from_parts(31_427_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: `167` + // Estimated: `4365` + // Minimum execution time: 14_535_000 picoseconds. + Weight::from_parts(14_999_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: `349` + // Estimated: `83866` + // Minimum execution time: 38_532_000 picoseconds. + Weight::from_parts(39_361_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: `450` + // Estimated: `83866` + // Minimum execution time: 78_956_000 picoseconds. + Weight::from_parts(80_594_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: `140` + // Estimated: `4277` + // Minimum execution time: 9_450_000 picoseconds. + Weight::from_parts(9_881_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: 98_126_000 picoseconds. + Weight::from_parts(102_511_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: 99_398_000 picoseconds. + Weight::from_parts(104_045_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: `1807` + // Estimated: `4365` + // Minimum execution time: 43_734_000 picoseconds. + Weight::from_parts(46_962_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: `1774` + // Estimated: `4365` + // Minimum execution time: 42_863_000 picoseconds. + Weight::from_parts(46_241_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: `1790` + // Estimated: `4365` + // Minimum execution time: 57_511_000 picoseconds. + Weight::from_parts(64_027_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: `1831` + // Estimated: `4365` + // Minimum execution time: 56_726_000 picoseconds. + Weight::from_parts(61_962_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: `301` + // Estimated: `42428` + // Minimum execution time: 24_870_000 picoseconds. + Weight::from_parts(25_837_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: `349` + // Estimated: `42428` + // Minimum execution time: 25_297_000 picoseconds. + Weight::from_parts(26_086_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: `208` + // Estimated: `4365` + // Minimum execution time: 16_776_000 picoseconds. + Weight::from_parts(17_396_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: 37_780_000 picoseconds. + Weight::from_parts(38_626_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: 85_265_000 picoseconds. + Weight::from_parts(89_986_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: 143_283_000 picoseconds. + Weight::from_parts(158_540_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: 143_736_000 picoseconds. + Weight::from_parts(162_755_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: 139_021_000 picoseconds. + Weight::from_parts(157_398_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: 78_530_000 picoseconds. + Weight::from_parts(83_556_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: 174_165_000 picoseconds. + Weight::from_parts(188_496_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: 142_964_000 picoseconds. + Weight::from_parts(157_257_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: `352` + // Estimated: `4365` + // Minimum execution time: 20_126_000 picoseconds. + Weight::from_parts(20_635_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: `285` + // Estimated: `4365` + // Minimum execution time: 17_716_000 picoseconds. + Weight::from_parts(18_324_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/westend/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_referenda.rs new file mode 100644 index 00000000000..accaa0ef10d --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_referenda_referenda.rs @@ -0,0 +1,523 @@ +// 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-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_referenda +// --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_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: `186` + // Estimated: `42428` + // Minimum execution time: 39_146_000 picoseconds. + Weight::from_parts(40_383_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: `439` + // Estimated: `83866` + // Minimum execution time: 51_385_000 picoseconds. + Weight::from_parts(52_701_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: `3196` + // Estimated: `42428` + // Minimum execution time: 70_018_000 picoseconds. + Weight::from_parts(75_868_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: `3216` + // Estimated: `42428` + // Minimum execution time: 69_311_000 picoseconds. + Weight::from_parts(72_425_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: `439` + // Estimated: `83866` + // Minimum execution time: 64_385_000 picoseconds. + Weight::from_parts(66_178_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: `439` + // Estimated: `83866` + // Minimum execution time: 62_200_000 picoseconds. + Weight::from_parts(63_782_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: `279` + // Estimated: `4401` + // Minimum execution time: 29_677_000 picoseconds. + Weight::from_parts(30_603_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: `269` + // Estimated: `4401` + // Minimum execution time: 29_897_000 picoseconds. + Weight::from_parts(30_618_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: `347` + // Estimated: `83866` + // Minimum execution time: 37_697_000 picoseconds. + Weight::from_parts(38_953_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: `588` + // Estimated: `83866` + // Minimum execution time: 106_001_000 picoseconds. + Weight::from_parts(107_102_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: `102` + // Estimated: `5477` + // Minimum execution time: 8_987_000 picoseconds. + Weight::from_parts(9_431_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: `3116` + // Estimated: `42428` + // Minimum execution time: 55_344_000 picoseconds. + Weight::from_parts(58_026_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: `3116` + // Estimated: `42428` + // Minimum execution time: 57_003_000 picoseconds. + Weight::from_parts(60_347_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: `2939` + // Estimated: `5477` + // Minimum execution time: 23_001_000 picoseconds. + Weight::from_parts(24_812_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: `2939` + // Estimated: `5477` + // Minimum execution time: 23_299_000 picoseconds. + Weight::from_parts(24_465_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: `2943` + // Estimated: `5477` + // Minimum execution time: 28_223_000 picoseconds. + Weight::from_parts(29_664_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: `2963` + // Estimated: `5477` + // Minimum execution time: 27_474_000 picoseconds. + Weight::from_parts(29_072_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: `299` + // Estimated: `42428` + // Minimum execution time: 24_405_000 picoseconds. + Weight::from_parts(25_184_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: `347` + // Estimated: `42428` + // Minimum execution time: 24_572_000 picoseconds. + Weight::from_parts(25_287_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: `206` + // Estimated: `4401` + // Minimum execution time: 16_042_000 picoseconds. + Weight::from_parts(16_610_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: `347` + // Estimated: `42428` + // Minimum execution time: 33_639_000 picoseconds. + Weight::from_parts(34_749_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: `347` + // Estimated: `42428` + // Minimum execution time: 36_467_000 picoseconds. + Weight::from_parts(37_693_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: `400` + // Estimated: `42428` + // Minimum execution time: 29_857_000 picoseconds. + Weight::from_parts(30_840_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: `383` + // Estimated: `42428` + // Minimum execution time: 31_028_000 picoseconds. + Weight::from_parts(32_154_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: `400` + // Estimated: `42428` + // Minimum execution time: 28_594_000 picoseconds. + Weight::from_parts(29_092_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: `404` + // Estimated: `42428` + // Minimum execution time: 27_246_000 picoseconds. + Weight::from_parts(28_003_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: `404` + // Estimated: `83866` + // Minimum execution time: 43_426_000 picoseconds. + Weight::from_parts(44_917_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: `400` + // Estimated: `42428` + // Minimum execution time: 30_285_000 picoseconds. + Weight::from_parts(31_575_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: `350` + // Estimated: `4401` + // Minimum execution time: 19_254_000 picoseconds. + Weight::from_parts(19_855_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: `283` + // Estimated: `4401` + // Minimum execution time: 16_957_000 picoseconds. + Weight::from_parts(17_556_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/westend/src/weights/pallet_treasury.rs b/polkadot/runtime/westend/src/weights/pallet_treasury.rs new file mode 100644 index 00000000000..e2eb6abfc7b --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_treasury.rs @@ -0,0 +1,150 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-13, 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_treasury +// --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_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: 13_644_000 picoseconds. + Weight::from_parts(13_988_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: 26_304_000 picoseconds. + Weight::from_parts(26_850_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: 40_318_000 picoseconds. + Weight::from_parts(41_598_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: 8_250_000 picoseconds. + Weight::from_parts(10_937_873, 0) + .saturating_add(Weight::from_parts(0, 3573)) + // Standard Error: 1_239 + .saturating_add(Weight::from_parts(82_426, 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: 6_170_000 picoseconds. + Weight::from_parts(6_366_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`) + /// The range of component `p` is `[0, 100]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `175 + p * (251 ±0)` + // Estimated: `1887 + p * (5206 ±0)` + // Minimum execution time: 39_691_000 picoseconds. + Weight::from_parts(29_703_313, 0) + .saturating_add(Weight::from_parts(0, 1887)) + // Standard Error: 18_540 + .saturating_add(Weight::from_parts(42_601_290, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .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/westend/src/weights/pallet_whitelist.rs b/polkadot/runtime/westend/src/weights/pallet_whitelist.rs new file mode 100644 index 00000000000..6177ac799e6 --- /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/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 92dcee150aa..66a2e2230cc 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -17,26 +17,31 @@ //! 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, DescribeBodyTerminal, - DescribeFamily, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, + DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; @@ -45,7 +50,7 @@ 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. @@ -77,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 @@ -94,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<( @@ -121,10 +139,10 @@ pub type Barrier = TrailingSetTopicAsId<( ( // If the message is one that immediately attemps 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>, @@ -141,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; @@ -161,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; @@ -179,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; -- GitLab From ec9274eea6d0755fad165b3fe15e02738b003941 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Wed, 27 Sep 2023 11:48:24 -0400 Subject: [PATCH 219/633] remove unnecessary hash string (#1722) This PR removes some unnecessary `r#`...`#` around a string and the corresponding comment that it was done because rustfmt wasn't working for "some reason". It seems to work fine now and clippy prefers it this way. --------- Co-authored-by: Joshy Orndorff --- .../support/procedural/src/no_bound/default.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/substrate/frame/support/procedural/src/no_bound/default.rs b/substrate/frame/support/procedural/src/no_bound/default.rs index da05f19e0f8..35d0eaeecf5 100644 --- a/substrate/frame/support/procedural/src/no_bound/default.rs +++ b/substrate/frame/support/procedural/src/no_bound/default.rs @@ -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 -- GitLab From 02284a3e82879f3a6f3ea2d44af1d7e69ccad60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Wed, 27 Sep 2023 17:39:45 +0100 Subject: [PATCH 220/633] Add custom error message for `StorageNoopGuard` (#1727) Expand `StorageNoopGuard` to be able to add extra context through a custom error message. When the guard is triggered it panics with an error message which can be defaulted, set on construction, or set after it has been constructed. Turn `StorageNoopGuard` into struct with `storage_root` and `error_message` and added `from_error_message` constructor and `set_error_message` setter. Also added `new()` aliased to `default()`. Closes #375 --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Liam Aharon --- .../support/src/storage/storage_noop_guard.rs | 70 ++++++++++++++++--- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/substrate/frame/support/src/storage/storage_noop_guard.rs b/substrate/frame/support/src/storage/storage_noop_guard.rs index d00e6e18ecc..c4d40fa99a3 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"); + }); + } } -- GitLab From 14e5d233480ded48cc9801454924c402fbba7cd6 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 27 Sep 2023 19:44:37 +0300 Subject: [PATCH 221/633] Move requests-responses and polling from `ChainSync` to `SyncingEngine` (#1650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move request-response handling from `ChainSync` to `SyncingEngine` as part of [Sync 2.0](https://github.com/paritytech/polkadot-sdk/issues/534) refactoring aimed at making `ChainSync` a pure state machine. Resolves https://github.com/paritytech/polkadot-sdk/issues/502. --------- Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + substrate/client/network/common/src/sync.rs | 28 +- substrate/client/network/sync/Cargo.toml | 1 + substrate/client/network/sync/src/engine.rs | 382 ++++++++++- substrate/client/network/sync/src/lib.rs | 612 ++++-------------- substrate/client/network/sync/src/mock.rs | 12 +- .../network/sync/src/pending_responses.rs | 114 ++++ substrate/client/rpc-spec-v2/Cargo.toml | 2 +- 8 files changed, 609 insertions(+), 543 deletions(-) create mode 100644 substrate/client/network/sync/src/pending_responses.rs diff --git a/Cargo.lock b/Cargo.lock index 7a11c5b7f19..55a8e0c748f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15380,6 +15380,7 @@ dependencies = [ "substrate-test-runtime-client", "thiserror", "tokio", + "tokio-stream", ] [[package]] diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index 5a6f90b290d..8ef0fafa1c7 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)] @@ -204,6 +204,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,9 +306,6 @@ 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. @@ -369,10 +383,4 @@ pub trait ChainSync: Send { /// 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/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index f10dd7869bb..39312cc4b32 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/engine.rs b/substrate/client/network/sync/src/engine.rs index c93ba89c622..8b8874ad4eb 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -23,10 +23,12 @@ 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, + BlockRequestEvent, ChainSync, ClientError, SyncingService, }; use codec::{Decode, Encode}; @@ -36,24 +38,32 @@ 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, }; +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 +73,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 +109,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 +120,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 { @@ -277,6 +299,18 @@ 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, } impl SyncingEngine @@ -381,24 +415,32 @@ 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 +497,10 @@ where } else { None }, + pending_responses: PendingResponses::new(), + block_downloader, + state_request_protocol_name, + warp_sync_protocol_name, }, SyncingService::new(tx, num_connected, is_major_syncing), block_announce_config, @@ -682,11 +728,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(event) => match event { + BlockRequestEvent::SendRequest { peer_id, request } => { + // drop obsolete pending response first + self.pending_responses.remove(&peer_id); + self.send_block_request(peer_id, request); + }, + BlockRequestEvent::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 +773,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 +875,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 @@ -860,6 +923,7 @@ where } self.chain_sync.peer_disconnected(&peer_id); + self.pending_responses.remove(&peer_id); self.event_streams.retain(|stream| { stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok() }); @@ -991,7 +1055,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 +1063,278 @@ 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) => { + if let Some((peer_id, new_req)) = + self.chain_sync.on_block_response(peer_id, req, blocks) + { + self.send_block_request(peer_id, new_req); + } + }, + Err(BlockResponseError::DecodeFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to decode block response from peer {:?}: {:?}.", + peer_id, + e + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + return + }, + Err(BlockResponseError::ExtractionFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to extract blocks from peer response {:?}: {:?}.", + peer_id, + e + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + return + }, + } + }, + PeerRequest::State => { + let response = match Self::decode_state_response(&resp[..]) { + Ok(proto) => proto, + Err(e) => { + debug!( + target: LOG_TARGET, + "Failed to decode state response from peer {peer_id:?}: {e:?}.", + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + return + }, + }; + + self.chain_sync.on_state_response(peer_id, response); + }, + 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, + }, + } + } } diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 20c0034966d..ff00e8f90f8 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -29,44 +29,31 @@ //! 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_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, 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 +68,7 @@ use sp_runtime::{ use std::{ collections::{HashMap, HashSet}, - iter, ops::Range, - pin::Pin, sync::Arc, }; @@ -92,6 +77,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 +117,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 +153,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 { @@ -261,17 +232,12 @@ struct GapSync { target: NumberFor, } -type PendingResponse = Pin< - Box< - dyn Future< - Output = ( - PeerId, - PeerRequest, - Result, RequestFailure>, oneshot::Canceled>, - ), - > + Send, - >, ->; +/// An event used to notify [`engine::SyncingEngine`] if we want to perform a block request +/// or drop an obsolete pending response. +enum BlockRequestEvent { + SendRequest { peer_id: PeerId, request: BlockRequest }, + RemoveStale { peer_id: PeerId }, +} /// The main data structure which contains all the state for a chains /// active syncing strategy. @@ -322,14 +288,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. @@ -491,10 +449,6 @@ where self.peers.len() } - fn num_active_peers(&self) -> usize { - self.pending_responses.len() - } - fn new_peer( &mut self, who: PeerId, @@ -1145,7 +1099,6 @@ where 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| { @@ -1168,36 +1121,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 +1139,14 @@ 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,16 +1166,9 @@ 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(), + block_announce_protocol_name, import_queue, metrics: if let Some(r) = &metrics_registry { match SyncingMetrics::register(r) { @@ -1289,7 +1187,7 @@ where }; sync.reset_sync_start_point()?; - Ok((sync, block_announce_config)) + Ok(sync) } /// Returns the median seen block number. @@ -1413,7 +1311,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 +1325,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(BlockRequestEvent::RemoveStale { peer_id })), + // update the request if the new one is available + Ok(Some(request)) => Some(Ok(BlockRequestEvent::SendRequest { peer_id, request })), + // this implies that we need to drop pending response from the peer Err(e) => Some(Err(e)), } }) @@ -1524,6 +1422,11 @@ 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> { self.blocks @@ -1588,117 +1491,12 @@ 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( + pub(crate) fn on_block_response( &mut self, peer_id: PeerId, request: BlockRequest, blocks: Vec>, - ) -> Option> { + ) -> Option<(PeerId, BlockRequest)> { let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( @@ -1741,10 +1539,7 @@ where self.import_blocks(origin, blocks); None }, - Ok(OnBlockData::Request(peer, req)) => { - self.send_block_request(peer, req); - None - }, + Ok(OnBlockData::Request(peer, req)) => Some((peer, req)), Ok(OnBlockData::Continue) => None, Err(BadPeer(id, repu)) => { self.network_service @@ -1756,20 +1551,14 @@ where } } - pub fn on_state_response( - &mut self, - peer_id: PeerId, - response: OpaqueStateResponse, - ) -> Option> { + pub fn on_state_response(&mut self, peer_id: PeerId, response: OpaqueStateResponse) { match self.on_state_data(&peer_id, response) { - Ok(OnStateData::Import(origin, block)) => - Some(ImportResult::BlockImport(origin, vec![block])), - Ok(OnStateData::Continue) => None, + Ok(OnStateData::Import(origin, block)) => self.import_blocks(origin, vec![block]), + Ok(OnStateData::Continue) => {}, Err(BadPeer(id, repu)) => { self.network_service .disconnect_peer(id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(id, repu); - None }, } } @@ -1782,165 +1571,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 +1593,8 @@ where } else { None } - })) + }) + .collect() } fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { @@ -2086,7 +1721,6 @@ where } }) .collect() - // Box::new(iter) } fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { @@ -2288,13 +1922,14 @@ where /// 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. 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 +2434,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}, @@ -2825,21 +2457,16 @@ mod test { 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 +2484,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); @@ -2891,21 +2519,16 @@ mod test { 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 +2567,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 +2582,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 { + BlockRequestEvent::SendRequest { peer_id, .. } => + peer_id == peer_id1 || peer_id == peer_id2, + BlockRequestEvent::RemoveStale { .. } => false, + })); // peer 3 should be unaffected it was downloading finality data assert_eq!( @@ -3065,21 +2690,16 @@ mod test { 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(); @@ -3191,21 +2811,16 @@ mod test { 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(); @@ -3348,21 +2963,16 @@ 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(); @@ -3490,21 +3100,16 @@ 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(); @@ -3634,21 +3239,16 @@ mod test { 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(); @@ -3679,21 +3279,16 @@ 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(); @@ -3731,21 +3326,16 @@ mod test { 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 +3356,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 +3374,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 +3388,37 @@ 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() { + BlockRequestEvent::RemoveStale { peer_id } => { + pending_responses.remove(&peer_id); + }, + BlockRequestEvent::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() { + BlockRequestEvent::RemoveStale { .. } => false, + BlockRequestEvent::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); + pending_responses.remove(&peers[1]); + assert_eq!(pending_responses.len(), 0); } } diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index 859f9fb9c54..b51eec8d149 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -20,7 +20,7 @@ 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::{ @@ -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, @@ -81,15 +80,6 @@ mockall::mock! { ); fn peer_disconnected(&mut self, who: &PeerId); 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 00000000000..c863267e780 --- /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-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index c93006753af..f4068d1bc59 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -31,7 +31,7 @@ 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" -- GitLab From 769bdd3ff33a291cbc70a800a3830638467e42a2 Mon Sep 17 00:00:00 2001 From: ordian Date: Thu, 28 Sep 2023 01:07:32 +0200 Subject: [PATCH 222/633] runtime-api: cleanup after v7 stabilization (#1729) Follow-up to #1543. --- polkadot/node/core/runtime-api/src/cache.rs | 1 - polkadot/node/core/runtime-api/src/lib.rs | 4 ++-- polkadot/node/subsystem-types/src/messages.rs | 2 +- polkadot/node/subsystem-util/src/lib.rs | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index e05e5823a28..6cf7fa744d3 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -96,7 +96,6 @@ 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)), - para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 19b2f5565a2..1b18941e546 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -569,7 +569,7 @@ where query!( ParaBackingState, para_backing_state(para), - ver = Request::STAGING_BACKING_STATE, + ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT, sender ) }, @@ -577,7 +577,7 @@ where query!( AsyncBackingParams, async_backing_params(), - ver = Request::STAGING_BACKING_STATE, + ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT, sender ) }, diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index eb94f1696c9..01ccee3add9 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -725,7 +725,7 @@ impl RuntimeApiRequest { pub const MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT: u32 = 6; /// Minimum version to enable asynchronous backing: `AsyncBackingParams` and `ParaBackingState`. - pub const STAGING_BACKING_STATE: u32 = 7; + pub const ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT: u32 = 7; } /// A message to the Runtime API subsystem. diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index e60a9ff82ee..57e4f9cde09 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -226,7 +226,6 @@ 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_async_backing_params() -> AsyncBackingParams; AsyncBackingParams; } -- GitLab From 4bc97e481fb10039f669f4bcadbee0657e8281cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Thu, 28 Sep 2023 11:02:08 +0100 Subject: [PATCH 223/633] Add event field names to HRMP Event variants (#1695) Update the HRMP pallet to use field names for Event variants to improve metadata for a better client experience. Event variants are now structs instead of unnamed tuples. Partially implements Substrate issue [9903](https://github.com/paritytech/substrate/issues/9903) which doesn't appear to have been moved to the monorepo. --- .../0_xcm/3_hrmp-open-channels.yml | 14 +++- .../src/tests/hrmp_channels.rs | 22 +++--- .../src/tests/hrmp_channels.rs | 16 ++--- polkadot/runtime/parachains/src/hrmp.rs | 68 +++++++++++-------- .../parachains/src/hrmp/benchmarking.rs | 36 +++++++--- polkadot/runtime/parachains/src/hrmp/tests.rs | 46 ++++++++++--- 6 files changed, 136 insertions(+), 66 deletions(-) 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 1038ec8dc42..17a16d9ccd7 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 index 7bb64333db5..bf583ae33f8 100644 --- 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 @@ -79,9 +79,12 @@ fn open_hrmp_channel_between_paras_works() { }, // Open channel requested from Para A to Para B RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( - sender, recipient, max_capacity, max_message_size - ) + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender, + recipient, + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size + } ) => { sender: *sender == para_a_id.into(), recipient: *recipient == para_b_id.into(), @@ -133,9 +136,9 @@ fn open_hrmp_channel_between_paras_works() { }, // Open channel accepted for Para A to Para B RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { sender, recipient - ) + } ) => { sender: *sender == para_a_id.into(), recipient: *recipient == para_b_id.into(), @@ -175,9 +178,12 @@ fn force_open_hrmp_channel_for_system_para_works() { vec![ // HRMP channel forced opened RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( - sender, recipient, max_capacity, max_message_size - ) + polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened{ + sender, + recipient, + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size + } ) => { sender: *sender == system_para_id.into(), recipient: *recipient == para_a_id.into(), 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 index a6286c619f6..e5bce267b90 100644 --- 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 @@ -79,9 +79,9 @@ fn open_hrmp_channel_between_paras_works() { }, // Open channel requested from Para A to Para B RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( - sender, recipient, max_capacity, max_message_size - ) + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender, recipient, proposed_max_capacity: max_capacity, proposed_max_message_size: max_message_size + } ) => { sender: *sender == para_a_id.into(), recipient: *recipient == para_b_id.into(), @@ -133,9 +133,9 @@ fn open_hrmp_channel_between_paras_works() { }, // Open channel accepted for Para A to Para B RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { sender, recipient - ) + } ) => { sender: *sender == para_a_id.into(), recipient: *recipient == para_b_id.into(), @@ -175,9 +175,9 @@ fn force_open_hrmp_channel_for_system_para_works() { vec![ // HRMP channel forced opened RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( - sender, recipient, max_capacity, max_message_size - ) + polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened{ + sender, recipient, proposed_max_capacity: max_capacity, proposed_max_message_size: max_message_size + } ) => { sender: *sender == system_para_id.into(), recipient: *recipient == para_a_id.into(), diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index 3f0a5e0830c..b3bbcb433c0 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -278,24 +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. - /// `[sender, recipient, proposed_max_capacity, proposed_max_message_size]` - HrmpSystemChannelOpened(ParaId, ParaId, u32, u32), + HrmpSystemChannelOpened { + sender: ParaId, + recipient: ParaId, + proposed_max_capacity: u32, + proposed_max_message_size: u32, + }, /// An HRMP channel's deposits were updated. - /// `[sender, recipient]` - OpenChannelDepositsUpdated(ParaId, ParaId), + OpenChannelDepositsUpdated { sender: ParaId, recipient: ParaId }, } #[pallet::error] @@ -499,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(()) } @@ -516,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(()) } @@ -532,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(()) } @@ -611,7 +621,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(()) } @@ -651,12 +661,12 @@ pub mod pallet { // 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()) } @@ -695,12 +705,12 @@ pub mod pallet { Self::init_open_channel(sender, recipient, max_capacity, max_message_size)?; Self::accept_open_channel(recipient, sender)?; - Self::deposit_event(Event::HrmpSystemChannelOpened( + Self::deposit_event(Event::HrmpSystemChannelOpened { sender, recipient, - max_capacity, - max_message_size, - )); + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size, + }); Ok(Pays::No.into()) } @@ -796,7 +806,7 @@ pub mod pallet { Ok(()) })?; - Self::deposit_event(Event::OpenChannelDepositsUpdated(sender, recipient)); + Self::deposit_event(Event::OpenChannelDepositsUpdated { sender, recipient }); Ok(()) } diff --git a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs index 7d82bcc99a7..2cb49c88d43 100644 --- a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs +++ b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs @@ -166,8 +166,13 @@ mod benchmarks { _(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(), ); } @@ -179,7 +184,7 @@ mod benchmarks { #[extrinsic_call] _(recipient_origin, sender); - assert_last_event::(Event::::OpenChannelAccepted(sender, recipient).into()); + assert_last_event::(Event::::OpenChannelAccepted { sender, recipient }.into()); } #[benchmark] @@ -191,7 +196,9 @@ mod benchmarks { #[extrinsic_call] _(sender_origin, channel_id.clone()); - assert_last_event::(Event::::ChannelClosed(sender, channel_id).into()); + 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 @@ -411,8 +418,13 @@ mod benchmarks { _(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(), ); } @@ -435,8 +447,13 @@ mod benchmarks { _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); assert_last_event::( - Event::::HrmpSystemChannelOpened(sender_id, recipient_id, capacity, message_size) - .into(), + Event::::HrmpSystemChannelOpened { + sender: sender_id, + recipient: recipient_id, + proposed_max_capacity: capacity, + proposed_max_message_size: message_size, + } + .into(), ); } @@ -478,7 +495,8 @@ mod benchmarks { _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); assert_last_event::( - Event::::OpenChannelDepositsUpdated(sender_id, recipient_id).into(), + 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. diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 236745b7cc3..4fc0b0b448a 100644 --- a/polkadot/runtime/parachains/src/hrmp/tests.rs +++ b/polkadot/runtime/parachains/src/hrmp/tests.rs @@ -151,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. @@ -189,7 +192,12 @@ fn force_open_channel_works() { 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. @@ -224,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. @@ -238,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. @@ -266,7 +284,12 @@ fn open_system_channel_works() { 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(para_a, para_b, 2, 8)))); + 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. @@ -397,7 +420,10 @@ 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() + }))); }); } -- GitLab From 4384c613afc936048e91572a7ca14dc2029acad8 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Thu, 28 Sep 2023 12:59:35 +0200 Subject: [PATCH 224/633] Added `review-bot` to fine tune review requirements (#1673) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created a Github Action that uses the [Review-Bot app](https://github.com/paritytech/review-bot) to require more fine tuned requirements to review pull requests before allowing the PR to be merged. This uses [`pull_request_target`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target) for the event, not `pull_request`. This is a security measure so that an attacker doesn’t have access to the secrets. All the rules have been copied from the original `.github/pr-custom-review.yml` file. I want to clarify, this particular commit is **not intended to replace PRCR yet**. # Advantages it brings over `PRCR` Most of the features available in `PRCR` have been duplicated and enhanced. For a complete detailed write up, please see: - paritytech/pr-custom-review#114 -> Proposal for the rewrite - [Review Bot Documentation](https://github.com/paritytech/review-bot/blob/main/README.md) The most important features are: - `include` and `exclude` fields now accept an array, making it easier to read the regular expressions. - Ability to skip a rule - We can set that PRs coming from a particular user or team will cause the rule to be skipped. - This is used in the `Audit rule`, which was requested by @the-right-joyce. - This resolves paritytech/pr-custom-review#136 - Ability to request fellows instead of teams - As requested in polkadot-fellows/runtimes#7, this bot has the ability to request fellows by rank instead of users. - We currently have polkadot-fellows/runtimes#31 which is using that feature. Aside from all the rules available in `PRCR` I have added a particular rule to lock the review-bot files and require a review from the `locks-review` team, the @paritytech/ci team and the @paritytech/opstooling team to ensure that the file has been written correctly. ## Next steps The next steps will consist on paritytech/review-bot#53, once this issue has been resolved, and `review-bot` has worked without any issues on this repository for a while, we will upgrade it to be able to fully replace `PRCR`. --- .github/review-bot.yml | 121 +++++++++++++++++++++++++++++++ .github/workflows/review-bot.yml | 31 ++++++++ 2 files changed, 152 insertions(+) create mode 100644 .github/review-bot.yml create mode 100644 .github/workflows/review-bot.yml diff --git a/.github/review-bot.yml b/.github/review-bot.yml new file mode 100644 index 00000000000..c9eadd6e58b --- /dev/null +++ b/.github/review-bot.yml @@ -0,0 +1,121 @@ +rules: + - name: CI files + condition: + include: + - ^\.gitlab-ci\.yml + - ^docker/.* + - ^\.github/.* + - ^\.gitlab/.* + - ^\.config/nextest.toml + - ^\.cargo/.* + exclude: + - ^./gitlab/pipeline/zombienet.* + min_approvals: 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$ + min_approvals: 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/.* + min_approvals: 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: + - min_approvals: 1 + teams: + - locks-review + - min_approvals: 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/.* + min_approvals: 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: + - min_approvals: 2 + teams: + - core-devs + - min_approvals: 1 + teams: + - frame-coders + + # Protection of THIS file + - name: Review Bot + condition: + include: + - review-bot\.yml + min_approvals: 2 + type: "and" + reviewers: + - min_approvals: 1 + teams: + - opstooling + - min_approvals: 1 + teams: + - locks-review + - min_approvals: 1 + teams: + - ci diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml new file mode 100644 index 00000000000..aeb33b5da3d --- /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@v1.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + team-token: ${{ steps.team_token.outputs.token }} + checks-token: ${{ steps.team_token.outputs.token }} -- GitLab From b50d8e6f7f7a2e1b679b307656fe426d0cfc7117 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Fri, 29 Sep 2023 00:04:35 +1300 Subject: [PATCH 225/633] add some events for pallet-bounties (#1706) Add missing events for pallet-bounties --- substrate/frame/bounties/src/lib.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index c64a35672c7..c099fc48b7a 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()), -- GitLab From de71fecc4e58d99474ff655789801e5edf3764b1 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 28 Sep 2023 06:08:05 -0500 Subject: [PATCH 226/633] Add `MaxTipAmount` for pallet-tips (#1709) Last week we experienced a governance attack. Surprisingly, there was no upper limit on the tip amount. Due to the mechanism of pallet-fragment-election, the council members will be refreshed immediately. Attacker is easy to control the council and give a large tip amount. --- substrate/bin/node/runtime/src/lib.rs | 1 + substrate/docs/Upgrading-2.0-to-3.0.md | 1 + substrate/frame/tips/src/lib.rs | 14 +++++++++++++- substrate/frame/tips/src/tests.rs | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index c90b9076dec..2fcb20ad8da 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1289,6 +1289,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; } diff --git a/substrate/docs/Upgrading-2.0-to-3.0.md b/substrate/docs/Upgrading-2.0-to-3.0.md index 58066ce074d..3f2a3e7c5be 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/frame/tips/src/lib.rs b/substrate/frame/tips/src/lib.rs index 6e8f72e0540..8764486d5f4 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 a700892d427..9cb90c37980 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -172,6 +172,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 +184,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 +398,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(|| { -- GitLab From c1eb342b14bf412982297b3a629b6f72da2d74a8 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Thu, 28 Sep 2023 18:24:29 +0200 Subject: [PATCH 227/633] PVF: more filesystem sandboxing (#1373) --- Cargo.lock | 3 + polkadot/node/core/pvf/Cargo.toml | 1 + polkadot/node/core/pvf/common/Cargo.toml | 1 + polkadot/node/core/pvf/common/src/error.rs | 41 +- polkadot/node/core/pvf/common/src/execute.rs | 2 +- polkadot/node/core/pvf/common/src/lib.rs | 35 +- .../node/core/pvf/common/src/worker/mod.rs | 283 ++++++++--- .../core/pvf/common/src/worker/security.rs | 444 ++++++++++++++---- .../node/core/pvf/common/src/worker_dir.rs | 35 ++ .../node/core/pvf/execute-worker/src/lib.rs | 122 ++--- .../node/core/pvf/prepare-worker/Cargo.toml | 1 + .../node/core/pvf/prepare-worker/src/lib.rs | 104 ++-- polkadot/node/core/pvf/src/artifacts.rs | 7 +- polkadot/node/core/pvf/src/execute/queue.rs | 17 + .../node/core/pvf/src/execute/worker_intf.rs | 219 ++++++--- polkadot/node/core/pvf/src/host.rs | 120 ++++- polkadot/node/core/pvf/src/lib.rs | 1 + polkadot/node/core/pvf/src/prepare/pool.rs | 52 +- .../node/core/pvf/src/prepare/worker_intf.rs | 246 +++++----- polkadot/node/core/pvf/src/worker_intf.rs | 300 ++++++++---- polkadot/node/core/pvf/tests/it/adder.rs | 36 +- polkadot/node/core/pvf/tests/it/main.rs | 55 ++- .../node/core/pvf/tests/it/worker_common.rs | 13 +- .../src/node/utility/pvf-host-and-workers.md | 8 +- 24 files changed, 1531 insertions(+), 615 deletions(-) create mode 100644 polkadot/node/core/pvf/common/src/worker_dir.rs diff --git a/Cargo.lock b/Cargo.lock index 55a8e0c748f..d3811ed4ad6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12035,6 +12035,7 @@ version = "1.0.0" dependencies = [ "always-assert", "assert_matches", + "cfg-if", "futures", "futures-timer", "hex-literal", @@ -12091,6 +12092,7 @@ name = "polkadot-node-core-pvf-common" version = "1.0.0" dependencies = [ "assert_matches", + "cfg-if", "cpu-time", "futures", "landlock", @@ -12132,6 +12134,7 @@ dependencies = [ name = "polkadot-node-core-pvf-prepare-worker" version = "1.0.0" dependencies = [ + "cfg-if", "futures", "libc", "parity-scale-codec", diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 478d1952d9d..27f4df117e5 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 621f7e24f72..0f7308396d8 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" } diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 6eb0d9b7df4..6fdd06057c8 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 399b847791a..b89ab089af1 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/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index c358ad6e134..53c287ea970 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 bcdf882f300..59973f6cbbc 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::{worker_dir, 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,39 @@ macro_rules! decl_worker_main { }, } + 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()), + "--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; } + let worker_dir_path = + worker_dir_path.expect("the --worker-dir-path argument is required"); + + 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, node_version, Some($worker_version)); + $entrypoint(worker_dir_path, node_version, Some($worker_version), security_status); } }; } @@ -95,61 +156,181 @@ 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, + #[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, + ?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 socket_path = worker_dir::socket(&worker_dir_path); + let stream = || -> std::io::Result { + let stream = UnixStream::connect(&socket_path)?; + // Remove the socket here. We don't also need to do this on the host-side; on failed + // rendezvous, the host will delete the whole worker dir. + 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 +338,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 +444,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 6c5f96e0b5d..b7abf028f94 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 + } -/// 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, + 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") + } + + // 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,14 +211,21 @@ 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. /// - /// # Versions (June 2023) + /// # Versions (as of June 2023) /// /// - Polkadot reference kernel version: 5.16+ /// - ABI V1: 5.13 - introduces landlock, including full restrictions on file reads @@ -83,46 +249,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::new().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 +355,114 @@ 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()); } diff --git a/polkadot/node/core/pvf/common/src/worker_dir.rs b/polkadot/node/core/pvf/common/src/worker_dir.rs new file mode 100644 index 00000000000..c2610a4d112 --- /dev/null +++ b/polkadot/node/core/pvf/common/src/worker_dir.rs @@ -0,0 +1,35 @@ +// 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 . + +//! 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"; +const WORKER_SOCKET_NAME: &str = "socket"; + +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) +} + +pub fn socket(worker_dir_path: &Path) -> PathBuf { + worker_dir_path.join(WORKER_SOCKET_NAME) +} diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 36793a5c71e..9d7bfdf2866 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -16,7 +16,7 @@ //! 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::Executor, 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`. @@ -28,22 +28,21 @@ 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 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 @@ -81,8 +80,8 @@ use tokio::{io, net::UnixStream}; /// The stack size for the execute thread. pub const EXECUTE_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024 + 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 +91,58 @@ 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. +/// - `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, + worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, + security_status: SecurityStatus, ) { worker_event_loop( - "execute", - socket_path, + WorkerKind::Execute, + 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| { + let Handshake { executor_params } = recv_handshake(&mut stream)?; + let executor = Executor::new(executor_params).map_err(|e| { io::Error::new(io::ErrorKind::Other, format!("cannot create executor: {}", e)) })?; 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 +151,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 }, }; @@ -187,22 +185,11 @@ pub fn worker_entrypoint( 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, + ¶ms, + executor_2, + cpu_time_start, ) }, Arc::clone(&condvar), @@ -215,24 +202,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 +239,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)?; } }, ); diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index e7a12cd9a80..886209b78c3 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 caa7d33df12..a24f5024722 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -33,25 +33,24 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, executor_intf::Executor, - framed_recv, framed_send, + 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,34 @@ 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. +/// - `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 +116,23 @@ 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, + worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, + security_status: SecurityStatus, ) { worker_event_loop( - "prepare", - socket_path, + WorkerKind::Prepare, + 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, @@ -172,14 +172,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); @@ -200,7 +192,7 @@ pub fn worker_entrypoint( }); } - (result, landlock_status) + result }, Arc::clone(&condvar), WaitOutcome::Finished, @@ -213,20 +205,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 +234,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 +282,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)?; } }, ); diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index dc5921df968..5a1767af75b 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -172,9 +172,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() } @@ -295,7 +296,7 @@ mod tests { #[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 acb260e2569..aca604f0de2 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 d66444a8102..783c7c7abbc 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 5290b2760f4..81695829122 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 0e4f2444adf..1b8d8377381 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -111,6 +111,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 92aa4896c26..7933b0319a6 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 5280ab6b42a..b66c3604434 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/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index 795ad452444..9825506ba88 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::{worker_dir, SecurityStatus}; use rand::Rng; use std::{ fmt, mem, @@ -39,99 +40,106 @@ 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(); - 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| { + let worker_dir = WorkerDir::new(debug_id, cache_path).await?; + let socket_path = worker_dir::socket(&worker_dir.path); + + let extra_args: Vec = extra_args.iter().map(|arg| arg.to_string()).collect(); + + let listener = UnixListener::bind(&socket_path).map_err(|err| { + gum::warn!( + target: LOG_TARGET, + %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, &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| { gum::warn!( target: LOG_TARGET, %debug_id, ?program_path, ?extra_args, - "cannot bind unix socket: {:?}", + ?worker_dir_path, + ?socket_path, + "cannot accept a worker: {:?}", err, ); - SpawnErr::Bind + SpawnErr::Accept })?; - - 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 - })?; - - futures::select! { - accept_result = listener.accept().fuse() => { - let (stream, _) = accept_result.map_err(|err| { - gum::warn!( - target: LOG_TARGET, - %debug_id, - ?program_path, - ?extra_args, - "cannot accept a worker: {:?}", - err, - ); - SpawnErr::Accept - })?; - Ok((IdleWorker { stream, pid: handle.id() }, handle)) - } - _ = Delay::new(spawn_timeout).fuse() => { - gum::warn!( - target: LOG_TARGET, - %debug_id, - ?program_path, - ?extra_args, - ?spawn_timeout, - "spawning and connecting to socket timed out", - ); - Err(SpawnErr::AcceptTimeout) - } - } + Ok((IdleWorker { stream, pid: handle.id(), worker_dir }, handle)) } - }) - .await -} - -async fn with_transient_socket_path(debug_id: &'static str, f: F) -> Result -where - F: FnOnce(&Path) -> Fut, - Fut: futures::Future> + 'static, -{ - let socket_path = tmpfile(&format!("pvf-host-{}", debug_id)) - .await - .map_err(|_| SpawnErr::TmpFile)?; - let result = f(&socket_path).await; - - // Best effort to remove the socket file. Under normal circumstances the socket will be removed - // by the worker. We make sure that it is removed here, just in case a failed rendezvous. - let _ = tokio::fs::remove_file(socket_path).await; - - result + _ = Delay::new(spawn_timeout).fuse() => { + gum::warn!( + target: LOG_TARGET, + %debug_id, + ?program_path, + ?extra_args, + ?worker_dir_path, + ?socket_path, + ?spawn_timeout, + "spawning and connecting to socket timed out", + ); + Err(SpawnErr::AcceptTimeout) + } + } } -/// 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 +151,28 @@ 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. +#[cfg(test)] +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 +186,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. @@ -219,12 +234,32 @@ impl WorkerHandle { fn spawn( 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 +341,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 +358,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 bad7a66054c..8bdd09db208 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 dc8f00098ec..f699b5840d8 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 875ae79af09..5379d29556c 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/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 bcf01b61f21..6a14a3a013d 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 -- GitLab From 50242a61d7b2dc1d1da5a0021e5535b37ccce5d4 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:29:12 +0200 Subject: [PATCH 228/633] rococo-runtime: `RococoGenesisExt` removed (#1490) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [`RococoGenesisExt`](https://github.com/paritytech/polkadot-sdk/blob/a414ea7515c9cdc81f1d12410e646afc148250e8/polkadot/node/service/src/chain_spec.rs#L152-L171) is removed. It was the hack to allow overwriting `EpochDurationInBlocks`. Removal of `RococGenesisExt` prevents from manipulating the state to change the runtime constants. Changes: - Environment variable which controls the `time::EpochDurationInBlocks` value was added: `ROCOCO_EPOCH_DURATION` (epoch duration will be set to the value of env), - `10,100,600` versions of rococo-runtime are built in CI and put into `polkadot-debug` docker image. `rococo-runtime` building examples: - to build runtime for `versi_staging_testnet` which had EpochDurationInBlocks set to 100: ``` ROCOCO_EPOCH_DURATION=100 cargo build --features=fast-runtime -p rococo-runtime ``` - to build runtime for `wococo_development` ``` ROCOCO_EPOCH_DURATION=10 cargo build --features=fast-runtime -p rococo-runtime ``` - to build `versi-staging` chain spec: ``` ROCOCO_EPOCH_DURATION=100 cargo run -p polkadot --features=fast-runtime -- build-spec --chain versi-staging --raw ``` - to build `wococo-dev` chain spec: ``` ROCOCO_EPOCH_DURATION=10 cargo run -p polkadot --features=fast-runtime -- build-spec --chain wococo-dev --raw ``` It is also possible to change the epoch duration by replacing the `code` field in the chain spec with the hex dump of pre-built runtime wasm blob (because the epoch duration is hard-coded into wasm blob). --------- Co-authored-by: Bastian Köcher --- .gitlab/pipeline/build.yml | 6 ++ .../polkadot_injected_debug.Dockerfile | 5 +- polkadot/node/service/src/chain_spec.rs | 72 +++---------------- polkadot/runtime/rococo/Cargo.toml | 3 +- polkadot/runtime/rococo/README.md | 7 ++ polkadot/runtime/rococo/build.rs | 15 ++-- polkadot/runtime/rococo/constants/src/lib.rs | 7 +- .../functional/0002-parachains-disputes.toml | 2 +- .../0004-parachains-garbage-candidate.toml | 2 +- .../zombienet_tests/misc/0001-paritydb.toml | 2 +- 10 files changed, 46 insertions(+), 75 deletions(-) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 5b53798c403..029c0f6a3cd 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 diff --git a/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile index 80ce8258987..09fc4f764d0 100644 --- a/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile @@ -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/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 97b3fab89e3..ce25c08b877 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -84,7 +84,7 @@ pub type WestendChainSpec = GenericChainSpec; /// The `ChainSpec` parameterized for the rococo runtime. #[cfg(feature = "rococo-native")] -pub type RococoChainSpec = service::GenericChainSpec; +pub type RococoChainSpec = service::GenericChainSpec; /// The `ChainSpec` parameterized for the `versi` runtime. /// @@ -96,30 +96,6 @@ pub type VersiChainSpec = RococoChainSpec; #[cfg(not(feature = "rococo-native"))] 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, -} - -#[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 { GenericChainSpec::from_json_bytes(&include_bytes!("../chain-specs/polkadot.json")[..]) } @@ -780,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)]) @@ -817,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)]) @@ -1130,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), @@ -1153,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"), @@ -1177,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), @@ -1239,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), @@ -1278,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), @@ -1317,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/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 106d8aafa76..49a4a4e8299 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -110,7 +110,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" ] @@ -196,6 +196,7 @@ std = [ "sp-storage/std", "sp-tracing/std", "sp-version/std", + "substrate-wasm-builder", "tx-pool-api/std", "xcm-builder/std", "xcm-executor/std", diff --git a/polkadot/runtime/rococo/README.md b/polkadot/runtime/rococo/README.md index 465afd25549..5b2c296f0ce 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 e7134e0ef72..ed32d33105b 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 214e2f3fa98..2200f7ddefe 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/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index a0a87d60d4e..e6aeb8e245c 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 7c4f5a9f1bc..ef27d7b92f0 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 38fa5689819..99dc9c66e26 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 -- GitLab From b5a0708fb74aede2f1d4e177e69366a88726331b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:19:27 +0300 Subject: [PATCH 229/633] rpc/client: Propagate `rpc_methods` method to reported methods (#1713) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PR exposes the `rpc_methods` name in the `rpc_methods` response. This feature is useful for servers that only forward requests to methods that are reported by the `rpc_methods`. Jsonrpsee exposes the available methods registered so far. Registering the `rpc_methods` requires a closure that already stores the result. As such, the `rpc_methods` method name is manually added to the available methods. Closes: https://github.com/paritytech/polkadot-sdk/issues/1627 ### Testing Done ``` $> curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "rpc_methods", "params":[]}' http://localhost:9944 {"jsonrpc":"2.0","result":{"methods":["account_nextIndex",... "rpc_methods",..."unsubscribe_newHead"]},"id":1}⏎ ``` @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- substrate/client/rpc-servers/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 92b31937a0c..dc625c3d6c4 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 -- GitLab From 945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:20:56 +0300 Subject: [PATCH 230/633] archive: Implement height, hashByHeight and call (#1582) This PR implements: - `archive_unstable_finalized_height`: Get the height of the most recent finalized block - `archive_unstable_hash_by_height`: Get the hashes (possible empty) of blocks from the given height - `archive_unstable_call`: Call into the runtime of a block Builds on top of: https://github.com/paritytech/polkadot-sdk/pull/1560 ### Testing Done - unit tests for the methods with custom block tree for different heights / forks Closes: https://github.com/paritytech/polkadot-sdk/issues/1510 Closes: https://github.com/paritytech/polkadot-sdk/issues/1513 Closes: https://github.com/paritytech/polkadot-sdk/issues/1511 @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Sebastian Kunert --- .../client/rpc-spec-v2/src/archive/api.rs | 35 ++++ .../client/rpc-spec-v2/src/archive/archive.rs | 120 ++++++++++++-- .../client/rpc-spec-v2/src/archive/error.rs | 66 ++++++++ .../client/rpc-spec-v2/src/archive/mod.rs | 1 + .../client/rpc-spec-v2/src/archive/tests.rs | 153 +++++++++++++++++- substrate/client/rpc-spec-v2/src/lib.rs | 73 +++++++++ 6 files changed, 435 insertions(+), 13 deletions(-) create mode 100644 substrate/client/rpc-spec-v2/src/archive/error.rs diff --git a/substrate/client/rpc-spec-v2/src/archive/api.rs b/substrate/client/rpc-spec-v2/src/archive/api.rs index ca94779c887..0583111cb48 100644 --- a/substrate/client/rpc-spec-v2/src/archive/api.rs +++ b/substrate/client/rpc-spec-v2/src/archive/api.rs @@ -18,6 +18,7 @@ //! API trait of the archive methods. +use crate::MethodResult; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; #[rpc(client, server)] @@ -53,4 +54,38 @@ pub trait ArchiveApi { /// 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 index 4fb2e5671d3..bded842d8fd 100644 --- a/substrate/client/rpc-spec-v2/src/archive/archive.rs +++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs @@ -18,20 +18,34 @@ //! API implementation for `archive`. -use super::ArchiveApiServer; -use crate::chain_head::hex_string; +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, ExecutorProvider, StorageProvider}; -use sp_api::CallApiAt; -use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; -use sp_runtime::traits::Block as BlockT; -use std::{marker::PhantomData, sync::Arc}; +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. @@ -40,10 +54,26 @@ pub struct Archive, Block: BlockT, Client> { impl, Block: BlockT, Client> Archive { /// Create a new [`Archive`]. - pub fn new>(client: Arc, genesis_hash: GenesisHash) -> Self { + pub fn new>( + client: Arc, + backend: Arc, + genesis_hash: GenesisHash, + ) -> Self { let genesis_hash = hex_string(&genesis_hash.as_ref()); - Self { client, genesis_hash, _phantom: PhantomData } + 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] @@ -51,6 +81,7 @@ impl ArchiveApiServer for Archive::Header as HeaderT>::Number: From, BE: Backend + 'static, Client: BlockBackend + ExecutorProvider @@ -83,4 +114,75 @@ where 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 00000000000..b858212399c --- /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 index 767f658ecd7..eb7d71d702f 100644 --- a/substrate/client/rpc-spec-v2/src/archive/mod.rs +++ b/substrate/client/rpc-spec-v2/src/archive/mod.rs @@ -27,5 +27,6 @@ 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 index bc75fc749ac..36f7716e393 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -16,16 +16,23 @@ // 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; +use crate::{chain_head::hex_string, MethodResult}; use super::{archive::Archive, *}; +use assert_matches::assert_matches; use codec::{Decode, Encode}; -use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; +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, }; @@ -38,9 +45,10 @@ 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(), CHAIN_GENESIS).into_rpc(); + let api = Archive::new(client.clone(), backend, CHAIN_GENESIS).into_rpc(); (client, api) } @@ -111,3 +119,140 @@ async fn archive_header() { 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/lib.rs b/substrate/client/rpc-spec-v2/src/lib.rs index 9a455c5984a..d202bfef4a7 100644 --- a/substrate/client/rpc-spec-v2/src/lib.rs +++ b/substrate/client/rpc-spec-v2/src/lib.rs @@ -23,6 +23,8 @@ #![warn(missing_docs)] #![deny(unused_crate_dependencies)] +use serde::{Deserialize, Serialize}; + pub mod archive; pub mod chain_head; pub mod chain_spec; @@ -30,3 +32,74 @@ 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); + } +} -- GitLab From 7b9861a2f0e8be1c44e941145b068e637e7b0f2d Mon Sep 17 00:00:00 2001 From: btwiuse <54848194+btwiuse@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:36:40 +0800 Subject: [PATCH 231/633] Fix `subkey inspect` output text padding (#1744) This pull request is to fix the output text misalignment of `subkey inspect` command: (the `Network ID` line has an extra space at the end, and the `Secret seed` line lacks a leading space) ``` [btwiuse@railway ~]$ subkey inspect '' | cat -A Secret Key URI `` is account:$ Network ID: substrate $ Secret seed: 0xfac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e$ Public key (hex): 0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a$ Account ID: 0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a$ Public key (SS58): 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV$ SS58 Address: 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV$ ``` The output should be in the same YAML-like format as `subkey generate`: ``` [btwiuse@railway ~]$ subkey generate | cat -A Secret phrase: awkward eagle survey resemble novel resist modify memory pistol shed flower run$ Network ID: substrate$ Secret seed: 0x20502f79366325b7dc7620664e8844ae69d441baf6e5b571a57d3b3ff28e9586$ Public key (hex): 0x468874b9e5b6b77333fa702b9201b924d6834bf956e33e2bbe37d131134ca830$ Account ID: 0x468874b9e5b6b77333fa702b9201b924d6834bf956e33e2bbe37d131134ca830$ Public key (SS58): 5DfBkAMg5xQmsePFr3BWLZm99smiNyy9axWSgembvFgDKh9v$ SS58 Address: 5DfBkAMg5xQmsePFr3BWLZm99smiNyy9axWSgembvFgDKh9v$ ``` This change will fix `subkey` as well as all binaries that embed it as the `key` subcommand, for example: `substrate key`, `polkadot key`, etc. --------- Co-authored-by: Liam Aharon --- substrate/client/cli/src/arg_enums.rs | 2 +- substrate/client/cli/src/commands/utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index 67acb82c2c3..c55b97675da 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/utils.rs b/substrate/client/cli/src/commands/utils.rs index ff159909b87..fc725f570e5 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 \ -- GitLab From 7ca0d65f19497ac1c3c7ad6315f1a0acb2ca32f8 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 28 Sep 2023 22:38:16 +0200 Subject: [PATCH 232/633] fix(review-bot): pull secrets from `master` environment (#1745) --- .github/workflows/review-bot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index aeb33b5da3d..89c0f509bf1 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -16,6 +16,7 @@ permissions: jobs: review-approvals: runs-on: ubuntu-latest + environment: master steps: - name: Generate token id: team_token -- GitLab From 379be3d7c37df322f578fa8a59c409c3ae9eedf0 Mon Sep 17 00:00:00 2001 From: Tadeo Hepperle <62739623+tadeohepperle@users.noreply.github.com> Date: Fri, 29 Sep 2023 09:08:19 +0200 Subject: [PATCH 233/633] [RPC-Spec-V2] chainHead: use integer for block index and adjust RuntimeVersion JSON format (#1666) This PR adjusts the serialized format of the the returned RuntimeVersion in the rpc-spec-v2 methods. This is done to match the format defined here: https://paritytech.github.io/json-rpc-interface-spec/api/chainHead_unstable_follow.html#about-the-runtime - ##### `apis` field as object `apis` field of `RuntimeVersion` is now returned as an object, e.g. ``` "apis": { "0xdf6acb689907609b": 3, "0x37e397fc7c91f5e4": 1, } ``` instead of ``` "apis": [ ["0xdf6acb689907609b", 3], ["0x37e397fc7c91f5e4", 1], ] ``` - ##### removed `stateVersion` and `authoringVersion` `stateVersion` and `authoringVersion` are no longer returned in the `RuntimeVersion` JSON Object. - ##### block index in chain head events as integer ### Related Issues Closes: #1507 Closes: #1146 ### Testing Done Adjusted existing tests to make sure data is returned in the correct format. --- substrate/client/rpc-spec-v2/Cargo.toml | 1 - .../src/chain_head/chain_head_follow.rs | 4 +- .../rpc-spec-v2/src/chain_head/error.rs | 1 - .../rpc-spec-v2/src/chain_head/event.rs | 54 ++++++++++++++++--- .../rpc-spec-v2/src/chain_head/tests.rs | 9 ++-- .../rpc-spec-v2/src/transaction/event.rs | 24 ++------- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index f4068d1bc59..1eaed65706e 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -36,7 +36,6 @@ 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/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index 0fa995ce73a..b981e69f2e4 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/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index 3b2edb2b00c..811666428c5 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 65bc8b247c8..b5f9d6cc2ff 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 1d5b45260a2..8aaeb413cdf 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), diff --git a/substrate/client/rpc-spec-v2/src/transaction/event.rs b/substrate/client/rpc-spec-v2/src/transaction/event.rs index bdc126366fb..8b80fcda17b 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(); -- GitLab From 4902db21980c6bacff07c79b33b030cfe18687a1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 29 Sep 2023 09:37:51 +0200 Subject: [PATCH 234/633] Use `Extensions` to register offchain worker custom extensions (#1719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1671 Adds a `type_id` function to the `Extension` trait, allowing to properly store an retrieve boxed `Extensions`. --------- Co-authored-by: Bastian Köcher --- .../externalities/src/extensions.rs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/externalities/src/extensions.rs b/substrate/primitives/externalities/src/extensions.rs index 8b0bbd2c592..282e6ea914a 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); + } + } } -- GitLab From bf90cb0b73a2d2e0b3e79b2956256831ae79c9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 29 Sep 2023 09:54:11 +0200 Subject: [PATCH 235/633] Remove kusama and polkadot runtime crates (#1731) This pull request is removing the Kusama and Polkadot runtime crates. As still some crates dependent on the runtime crates, this pull request is doing some more changes. - It removes the `hostperfcheck` CLI command. This CLI command could compare the current node against the standard hardware by doing some checks. Later we added the hardware benchmark feature to Substrate. This hardware benchmark is running on every node startup and prints a warning if the current node is too slow. This makes this CLI command a duplicate that was also depending on the kusama runtime. - The pull request is removing the emulated integration tests that were requiring the Kusama or Polkadot runtime crates. --- .gitlab/pipeline/test.yml | 4 +- Cargo.lock | 356 --- Cargo.toml | 8 - cumulus/parachains/common/Cargo.toml | 4 - cumulus/parachains/common/src/kusama.rs | 14 +- cumulus/parachains/common/src/polkadot.rs | 14 +- .../assets/asset-hub-kusama/Cargo.toml | 53 - .../assets/asset-hub-kusama/src/lib.rs | 90 - .../src/tests/hrmp_channels.rs | 198 -- .../assets/asset-hub-kusama/src/tests/mod.rs | 21 - .../src/tests/reserve_transfer.rs | 414 --- .../assets/asset-hub-kusama/src/tests/send.rs | 195 -- .../src/tests/set_xcm_versions.rs | 93 - .../assets/asset-hub-kusama/src/tests/swap.rs | 364 --- .../asset-hub-kusama/src/tests/teleport.rs | 363 --- .../assets/asset-hub-polkadot/Cargo.toml | 52 - .../assets/asset-hub-polkadot/src/lib.rs | 90 - .../src/tests/hrmp_channels.rs | 192 -- .../asset-hub-polkadot/src/tests/mod.rs | 20 - .../src/tests/reserve_transfer.rs | 414 --- .../asset-hub-polkadot/src/tests/send.rs | 201 -- .../src/tests/set_xcm_versions.rs | 96 - .../asset-hub-polkadot/src/tests/teleport.rs | 363 --- .../assets/asset-hub-westend/Cargo.toml | 2 - .../bridges/bridge-hub-rococo/Cargo.toml | 1 - .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../collectives-polkadot/Cargo.toml | 38 - .../collectives-polkadot/src/lib.rs | 83 - .../src/tests/ambassador.rs | 65 - .../src/tests/fellowship.rs | 75 - .../collectives-polkadot/src/tests/mod.rs | 17 - .../emulated/common/Cargo.toml | 6 - .../emulated/common/src/constants.rs | 541 +--- .../emulated/common/src/lib.rs | 264 +- .../assets/asset-hub-kusama/Cargo.toml | 2 - .../assets/asset-hub-polkadot/Cargo.toml | 2 - .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 - .../bridge-hub-polkadot/Cargo.toml | 2 - .../collectives-polkadot/Cargo.toml | 2 - .../collectives-polkadot/src/xcm_config.rs | 3 +- .../contracts/contracts-rococo/Cargo.toml | 2 - polkadot/cli/Cargo.toml | 3 - polkadot/cli/src/cli.rs | 4 - polkadot/cli/src/command.rs | 27 - polkadot/cli/src/error.rs | 4 - polkadot/cli/src/host_perf_check.rs | 74 - polkadot/cli/src/lib.rs | 2 - .../node/test/performance-test/Cargo.toml | 33 - polkadot/node/test/performance-test/build.rs | 21 - .../test/performance-test/src/constants.rs | 22 - .../performance-test/src/gen_ref_constants.rs | 99 - .../node/test/performance-test/src/lib.rs | 89 - polkadot/runtime/kusama/Cargo.toml | 352 --- polkadot/runtime/kusama/build.rs | 25 - polkadot/runtime/kusama/constants/Cargo.toml | 27 - polkadot/runtime/kusama/constants/src/lib.rs | 128 - .../constants/src/weights/block_weights.rs | 81 - .../src/weights/extrinsic_weights.rs | 81 - .../kusama/constants/src/weights/mod.rs | 28 - .../constants/src/weights/paritydb_weights.rs | 63 - .../constants/src/weights/rocksdb_weights.rs | 63 - polkadot/runtime/kusama/src/bag_thresholds.rs | 234 -- .../kusama/src/governance/fellowship.rs | 358 --- polkadot/runtime/kusama/src/governance/mod.rs | 93 - .../runtime/kusama/src/governance/origins.rs | 194 -- .../runtime/kusama/src/governance/tracks.rs | 320 -- polkadot/runtime/kusama/src/lib.rs | 2754 ----------------- polkadot/runtime/kusama/src/past_payouts.rs | 312 -- polkadot/runtime/kusama/src/tests.rs | 177 -- .../weights/frame_benchmarking_baseline.rs | 108 - .../frame_election_provider_support.rs | 83 - .../kusama/src/weights/frame_system.rs | 147 - polkadot/runtime/kusama/src/weights/mod.rs | 69 - .../kusama/src/weights/pallet_bags_list.rs | 109 - .../kusama/src/weights/pallet_balances.rs | 99 - .../src/weights/pallet_balances_balances.rs | 154 - ...allet_balances_nis_counterpart_balances.rs | 178 -- .../kusama/src/weights/pallet_bounties.rs | 230 -- .../src/weights/pallet_child_bounties.rs | 202 -- .../src/weights/pallet_collective_council.rs | 322 -- .../pallet_collective_technical_committee.rs | 322 -- .../src/weights/pallet_conviction_voting.rs | 195 -- .../kusama/src/weights/pallet_democracy.rs | 513 --- .../pallet_election_provider_multi_phase.rs | 272 -- .../src/weights/pallet_elections_phragmen.rs | 303 -- .../kusama/src/weights/pallet_fast_unstake.rs | 203 -- .../kusama/src/weights/pallet_identity.rs | 359 --- .../kusama/src/weights/pallet_im_online.rs | 77 - .../kusama/src/weights/pallet_indices.rs | 117 - .../kusama/src/weights/pallet_membership.rs | 202 -- .../src/weights/pallet_message_queue.rs | 193 -- .../kusama/src/weights/pallet_multisig.rs | 165 - .../runtime/kusama/src/weights/pallet_nis.rs | 252 -- .../src/weights/pallet_nomination_pools.rs | 603 ---- .../kusama/src/weights/pallet_offences.rs | 222 -- .../kusama/src/weights/pallet_preimage.rs | 233 -- .../kusama/src/weights/pallet_proxy.rs | 224 -- .../src/weights/pallet_ranked_collective.rs | 176 -- .../kusama/src/weights/pallet_recovery.rs | 186 -- .../pallet_referenda_fellowship_referenda.rs | 525 ---- .../src/weights/pallet_referenda_referenda.rs | 523 ---- .../kusama/src/weights/pallet_scheduler.rs | 207 -- .../kusama/src/weights/pallet_session.rs | 85 - .../kusama/src/weights/pallet_society.rs | 437 --- .../kusama/src/weights/pallet_staking.rs | 796 ----- .../kusama/src/weights/pallet_timestamp.rs | 75 - .../runtime/kusama/src/weights/pallet_tips.rs | 159 - .../kusama/src/weights/pallet_treasury.rs | 154 - .../kusama/src/weights/pallet_utility.rs | 102 - .../kusama/src/weights/pallet_vesting.rs | 241 -- .../kusama/src/weights/pallet_whitelist.rs | 118 - .../runtime/kusama/src/weights/pallet_xcm.rs | 282 -- .../src/weights/runtime_common_auctions.rs | 143 - .../src/weights/runtime_common_claims.rs | 169 - .../src/weights/runtime_common_crowdloan.rs | 225 -- .../weights/runtime_common_paras_registrar.rs | 218 -- .../src/weights/runtime_common_slots.rs | 135 - .../runtime_parachains_configuration.rs | 157 - .../weights/runtime_parachains_disputes.rs | 64 - .../runtime_parachains_disputes_slashing.rs | 101 - .../src/weights/runtime_parachains_hrmp.rs | 327 -- .../weights/runtime_parachains_inclusion.rs | 75 - .../weights/runtime_parachains_initializer.rs | 69 - .../src/weights/runtime_parachains_paras.rs | 289 -- .../runtime_parachains_paras_inherent.rs | 345 --- .../runtime/kusama/src/weights/xcm/mod.rs | 290 -- .../xcm/pallet_xcm_benchmarks_fungible.rs | 179 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 341 -- polkadot/runtime/kusama/src/xcm_config.rs | 311 -- polkadot/runtime/polkadot/Cargo.toml | 321 -- polkadot/runtime/polkadot/build.rs | 25 - .../runtime/polkadot/constants/Cargo.toml | 27 - .../runtime/polkadot/constants/src/lib.rs | 150 - .../constants/src/weights/block_weights.rs | 81 - .../src/weights/extrinsic_weights.rs | 81 - .../polkadot/constants/src/weights/mod.rs | 28 - .../constants/src/weights/paritydb_weights.rs | 109 - .../constants/src/weights/rocksdb_weights.rs | 108 - .../runtime/polkadot/src/bag_thresholds.rs | 234 -- .../runtime/polkadot/src/governance/mod.rs | 97 - .../polkadot/src/governance/origins.rs | 151 - .../runtime/polkadot/src/governance/tracks.rs | 319 -- polkadot/runtime/polkadot/src/lib.rs | 2633 ---------------- .../weights/frame_benchmarking_baseline.rs | 108 - .../frame_election_provider_support.rs | 83 - .../polkadot/src/weights/frame_system.rs | 147 - polkadot/runtime/polkadot/src/weights/mod.rs | 64 - .../polkadot/src/weights/pallet_bags_list.rs | 109 - .../polkadot/src/weights/pallet_balances.rs | 153 - .../polkadot/src/weights/pallet_bounties.rs | 230 -- .../src/weights/pallet_child_bounties.rs | 202 -- .../src/weights/pallet_collective_council.rs | 327 -- .../pallet_collective_technical_committee.rs | 327 -- .../src/weights/pallet_conviction_voting.rs | 195 -- .../polkadot/src/weights/pallet_democracy.rs | 528 ---- .../pallet_election_provider_multi_phase.rs | 272 -- .../src/weights/pallet_elections_phragmen.rs | 318 -- .../src/weights/pallet_fast_unstake.rs | 203 -- .../polkadot/src/weights/pallet_identity.rs | 359 --- .../polkadot/src/weights/pallet_im_online.rs | 77 - .../polkadot/src/weights/pallet_indices.rs | 117 - .../polkadot/src/weights/pallet_membership.rs | 207 -- .../src/weights/pallet_message_queue.rs | 199 -- .../polkadot/src/weights/pallet_multisig.rs | 165 - .../src/weights/pallet_nomination_pools.rs | 601 ---- .../polkadot/src/weights/pallet_offences.rs | 222 -- .../polkadot/src/weights/pallet_preimage.rs | 233 -- .../polkadot/src/weights/pallet_proxy.rs | 222 -- .../polkadot/src/weights/pallet_referenda.rs | 523 ---- .../polkadot/src/weights/pallet_scheduler.rs | 207 -- .../polkadot/src/weights/pallet_session.rs | 85 - .../polkadot/src/weights/pallet_staking.rs | 796 ----- .../polkadot/src/weights/pallet_timestamp.rs | 75 - .../polkadot/src/weights/pallet_tips.rs | 164 - .../polkadot/src/weights/pallet_treasury.rs | 154 - .../polkadot/src/weights/pallet_utility.rs | 102 - .../polkadot/src/weights/pallet_vesting.rs | 241 -- .../polkadot/src/weights/pallet_whitelist.rs | 118 - .../polkadot/src/weights/pallet_xcm.rs | 284 -- .../src/weights/runtime_common_auctions.rs | 143 - .../src/weights/runtime_common_claims.rs | 169 - .../src/weights/runtime_common_crowdloan.rs | 225 -- .../weights/runtime_common_paras_registrar.rs | 224 -- .../src/weights/runtime_common_slots.rs | 135 - .../runtime_parachains_configuration.rs | 157 - .../weights/runtime_parachains_disputes.rs | 64 - .../runtime_parachains_disputes_slashing.rs | 101 - .../src/weights/runtime_parachains_hrmp.rs | 337 -- .../weights/runtime_parachains_inclusion.rs | 77 - .../weights/runtime_parachains_initializer.rs | 69 - .../src/weights/runtime_parachains_paras.rs | 297 -- .../runtime_parachains_paras_inherent.rs | 353 --- .../runtime/polkadot/src/weights/xcm/mod.rs | 290 -- .../xcm/pallet_xcm_benchmarks_fungible.rs | 208 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 327 -- polkadot/runtime/polkadot/src/xcm_config.rs | 290 -- polkadot/runtime/rococo/Cargo.toml | 5 + polkadot/runtime/westend/Cargo.toml | 5 + polkadot/utils/generate-bags/Cargo.toml | 2 - polkadot/utils/generate-bags/src/main.rs | 8 +- .../remote-ext-tests/bags-list/Cargo.toml | 4 - .../remote-ext-tests/bags-list/src/main.rs | 58 +- 202 files changed, 49 insertions(+), 40336 deletions(-) delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs delete mode 100644 polkadot/cli/src/host_perf_check.rs delete mode 100644 polkadot/node/test/performance-test/Cargo.toml delete mode 100644 polkadot/node/test/performance-test/build.rs delete mode 100644 polkadot/node/test/performance-test/src/constants.rs delete mode 100644 polkadot/node/test/performance-test/src/gen_ref_constants.rs delete mode 100644 polkadot/node/test/performance-test/src/lib.rs delete mode 100644 polkadot/runtime/kusama/Cargo.toml delete mode 100644 polkadot/runtime/kusama/build.rs delete mode 100644 polkadot/runtime/kusama/constants/Cargo.toml delete mode 100644 polkadot/runtime/kusama/constants/src/lib.rs delete mode 100644 polkadot/runtime/kusama/constants/src/weights/block_weights.rs delete mode 100644 polkadot/runtime/kusama/constants/src/weights/extrinsic_weights.rs delete mode 100644 polkadot/runtime/kusama/constants/src/weights/mod.rs delete mode 100644 polkadot/runtime/kusama/constants/src/weights/paritydb_weights.rs delete mode 100644 polkadot/runtime/kusama/constants/src/weights/rocksdb_weights.rs delete mode 100644 polkadot/runtime/kusama/src/bag_thresholds.rs delete mode 100644 polkadot/runtime/kusama/src/governance/fellowship.rs delete mode 100644 polkadot/runtime/kusama/src/governance/mod.rs delete mode 100644 polkadot/runtime/kusama/src/governance/origins.rs delete mode 100644 polkadot/runtime/kusama/src/governance/tracks.rs delete mode 100644 polkadot/runtime/kusama/src/lib.rs delete mode 100644 polkadot/runtime/kusama/src/past_payouts.rs delete mode 100644 polkadot/runtime/kusama/src/tests.rs delete mode 100644 polkadot/runtime/kusama/src/weights/frame_benchmarking_baseline.rs delete mode 100644 polkadot/runtime/kusama/src/weights/frame_election_provider_support.rs delete mode 100644 polkadot/runtime/kusama/src/weights/frame_system.rs delete mode 100644 polkadot/runtime/kusama/src/weights/mod.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_bags_list.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_balances.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_balances_balances.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_balances_nis_counterpart_balances.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_bounties.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_child_bounties.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_collective_council.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_collective_technical_committee.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_conviction_voting.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_democracy.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_election_provider_multi_phase.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_elections_phragmen.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_fast_unstake.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_identity.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_im_online.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_indices.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_membership.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_message_queue.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_multisig.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_nis.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_nomination_pools.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_offences.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_preimage.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_proxy.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_ranked_collective.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_recovery.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_referenda_fellowship_referenda.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_referenda_referenda.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_scheduler.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_session.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_society.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_staking.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_timestamp.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_tips.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_treasury.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_utility.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_vesting.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_whitelist.rs delete mode 100644 polkadot/runtime/kusama/src/weights/pallet_xcm.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_common_auctions.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_common_claims.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_common_crowdloan.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_common_paras_registrar.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_common_slots.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_configuration.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_disputes.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_disputes_slashing.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_inclusion.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_initializer.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_paras.rs delete mode 100644 polkadot/runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs delete mode 100644 polkadot/runtime/kusama/src/weights/xcm/mod.rs delete mode 100644 polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 polkadot/runtime/kusama/src/xcm_config.rs delete mode 100644 polkadot/runtime/polkadot/Cargo.toml delete mode 100644 polkadot/runtime/polkadot/build.rs delete mode 100644 polkadot/runtime/polkadot/constants/Cargo.toml delete mode 100644 polkadot/runtime/polkadot/constants/src/lib.rs delete mode 100644 polkadot/runtime/polkadot/constants/src/weights/block_weights.rs delete mode 100644 polkadot/runtime/polkadot/constants/src/weights/extrinsic_weights.rs delete mode 100644 polkadot/runtime/polkadot/constants/src/weights/mod.rs delete mode 100644 polkadot/runtime/polkadot/constants/src/weights/paritydb_weights.rs delete mode 100644 polkadot/runtime/polkadot/constants/src/weights/rocksdb_weights.rs delete mode 100644 polkadot/runtime/polkadot/src/bag_thresholds.rs delete mode 100644 polkadot/runtime/polkadot/src/governance/mod.rs delete mode 100644 polkadot/runtime/polkadot/src/governance/origins.rs delete mode 100644 polkadot/runtime/polkadot/src/governance/tracks.rs delete mode 100644 polkadot/runtime/polkadot/src/lib.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/frame_benchmarking_baseline.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/frame_election_provider_support.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/frame_system.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/mod.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_bags_list.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_balances.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_bounties.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_child_bounties.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_collective_council.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_collective_technical_committee.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_conviction_voting.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_democracy.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_election_provider_multi_phase.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_elections_phragmen.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_fast_unstake.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_identity.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_im_online.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_indices.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_membership.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_message_queue.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_multisig.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_nomination_pools.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_offences.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_preimage.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_proxy.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_referenda.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_scheduler.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_session.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_staking.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_timestamp.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_tips.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_treasury.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_utility.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_vesting.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_whitelist.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/pallet_xcm.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_common_auctions.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_common_claims.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_common_crowdloan.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_common_slots.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_configuration.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes_slashing.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_inclusion.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_initializer.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_paras.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/runtime_parachains_paras_inherent.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/xcm/mod.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 polkadot/runtime/polkadot/src/xcm_config.rs diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index ad0ef4d9b8e..e1e8b96bca5 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -229,12 +229,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 diff --git a/Cargo.lock b/Cargo.lock index d3811ed4ad6..e0ca0b012c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -692,30 +692,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "asset-hub-kusama-integration-tests" -version = "1.0.0" -dependencies = [ - "assert_matches", - "asset-hub-kusama-runtime", - "frame-support", - "frame-system", - "integration-tests-common", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime", - "polkadot-runtime-parachains", - "sp-runtime", - "staging-xcm", - "xcm-emulator", -] - [[package]] name = "asset-hub-kusama-runtime" version = "0.9.420" @@ -738,7 +714,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-asset-conversion", "pallet-asset-conversion-tx-payment", @@ -790,29 +765,6 @@ dependencies = [ "substrate-wasm-builder", ] -[[package]] -name = "asset-hub-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-runtime", - "frame-support", - "frame-system", - "integration-tests-common", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime", - "polkadot-runtime-parachains", - "sp-runtime", - "staging-xcm", - "xcm-emulator", -] - [[package]] name = "asset-hub-polkadot-runtime" version = "0.9.420" @@ -860,7 +812,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", "scale-info", "smallvec", "sp-api", @@ -900,7 +851,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", @@ -1835,7 +1785,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-aura", "pallet-authorship", @@ -1918,7 +1867,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", "scale-info", "serde", "smallvec", @@ -1957,7 +1905,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", "polkadot-runtime-parachains", "staging-xcm", "xcm-emulator", @@ -2560,32 +2507,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-balances", - "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" @@ -2634,7 +2555,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", "scale-info", "smallvec", "sp-api", @@ -2824,7 +2744,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-aura", "pallet-authorship", @@ -6379,7 +6298,6 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "frame-support", - "kusama-runtime-constants", "pallet-assets", "pallet-bridge-messages", "pallet-im-online", @@ -6393,8 +6311,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", - "polkadot-runtime", - "polkadot-runtime-constants", "polkadot-runtime-parachains", "polkadot-service", "rococo-runtime", @@ -6405,7 +6321,6 @@ dependencies = [ "sp-consensus-beefy", "sp-core", "sp-runtime", - "staging-kusama-runtime", "staging-xcm", "westend-runtime", "westend-runtime-constants", @@ -6836,19 +6751,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" @@ -10952,7 +10854,6 @@ dependencies = [ "cumulus-primitives-utility", "frame-support", "frame-system", - "kusama-runtime-constants", "log", "num-traits", "pallet-asset-tx-payment", @@ -10963,7 +10864,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", - "polkadot-runtime-constants", "rococo-runtime-constants", "scale-info", "smallvec", @@ -11579,7 +11479,6 @@ dependencies = [ "futures", "log", "polkadot-node-metrics", - "polkadot-performance-test", "polkadot-service", "pyroscope", "pyroscope_pprofrs", @@ -12484,23 +12383,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" @@ -12569,111 +12451,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-genesis-builder", - "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" @@ -12725,19 +12502,6 @@ dependencies = [ "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", -] - [[package]] name = "polkadot-runtime-metrics" version = "1.0.0" @@ -13157,9 +12921,7 @@ version = "1.0.0" dependencies = [ "clap 4.4.4", "generate-bags", - "polkadot-runtime", "sp-io", - "staging-kusama-runtime", "westend-runtime", ] @@ -13919,14 +13681,10 @@ version = "1.0.0" dependencies = [ "clap 4.4.4", "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", @@ -17703,120 +17461,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-genesis-builder", - "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" diff --git a/Cargo.toml b/Cargo.toml index d1078e3c86a..7edc28daf76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,11 +59,8 @@ 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-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/parachain-info", "cumulus/parachains/pallets/ping", @@ -141,7 +138,6 @@ members = [ "polkadot/node/subsystem-types", "polkadot/node/subsystem-util", "polkadot/node/test/client", - "polkadot/node/test/performance-test", "polkadot/node/test/service", "polkadot/node/zombienet-backchannel", "polkadot/parachain", @@ -156,12 +152,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", diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 963de03fa16..cb389b4b607 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -29,8 +29,6 @@ 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} @@ -58,7 +56,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 +64,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", diff --git a/cumulus/parachains/common/src/kusama.rs b/cumulus/parachains/common/src/kusama.rs index 308f7d081ce..073971a7075 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/polkadot.rs b/cumulus/parachains/common/src/polkadot.rs index 4f459b9bb5a..744108bce2e 100644 --- a/cumulus/parachains/common/src/polkadot.rs +++ b/cumulus/parachains/common/src/polkadot.rs @@ -48,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/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml deleted file mode 100644 index 788b2482be8..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ /dev/null @@ -1,53 +0,0 @@ -[package] -name = "asset-hub-kusama-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" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -assert_matches = "1.5.0" - -# Substrate -sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} -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-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs deleted file mode 100644 index ad74aa2301f..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/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_kusama::ED as ASSET_HUB_KUSAMA_ED, kusama::ED as KUSAMA_ED, PROOF_SIZE_THRESHOLD, - REF_TIME_THRESHOLD, XCM_V3, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, Kusama, - KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, - PenpalKusamaAReceiver, PenpalKusamaASender, PenpalKusamaB, PenpalKusamaBPallet, -}; -pub use parachains_common::{AccountId, Balance}; -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Kusama as KusamaId}, -}; -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: Kusama::child_location_of(AssetHubKusama::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubKusamaReceiver::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-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 bf583ae33f8..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs +++ /dev/null @@ -1,198 +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, - proposed_max_capacity: max_capacity, - proposed_max_message_size: 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(); - - 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![ - // HRMP channel forced opened - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened{ - sender, - recipient, - proposed_max_capacity: max_capacity, - proposed_max_message_size: 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/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs deleted file mode 100644 index b3089a3b382..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs +++ /dev/null @@ -1,21 +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. - -mod hrmp_channels; -mod reserve_transfer; -mod send; -mod set_xcm_versions; -mod swap; -mod teleport; 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-kusama/src/tests/reserve_transfer.rs deleted file mode 100644 index 645dca5035b..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/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; - - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); - - assert_expected_events!( - Kusama, - 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( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubKusama::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)) -} - -fn system_para_to_para_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 630_092_000, - 6_196, - ))); - - assert_expected_events!( - AssetHubKusama, - 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( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, - ))); - - assert_expected_events!( - AssetHubKusama, - 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 == AssetHubKusama::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 = KUSAMA_ED * 1000; - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::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 = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - 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(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 = KUSAMA_ED * 1000; - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::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 = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - 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(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 = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); - 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: PenpalKusamaAReceiver::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 = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); - 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: PenpalKusamaAReceiver::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 - AssetHubKusama::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubKusamaSender::get(), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::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(), - 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 - AssetHubKusama::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubKusamaSender::get(), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::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(), - 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-kusama/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs deleted file mode 100644 index 5891b694c8e..00000000000 --- 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-kusama/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs deleted file mode 100644 index a7af96096cd..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs +++ /dev/null @@ -1,93 +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 = - Kusama::child_location_of(AssetHubKusama::para_id()); - - // Relay Chain sets supported version for Asset Parachain - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::force_xcm_version( - sudo_origin, - bx!(system_para_destination), - XCM_V3 - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Kusama, - 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 = 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 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 receive the XCM message - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); - - assert_expected_events!( - AssetHubKusama, - 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-kusama/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs deleted file mode 100644 index 3a67b543582..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs +++ /dev/null @@ -1,364 +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::*; -use frame_support::{instances::Instance2, BoundedVec}; -use parachains_common::kusama::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_one = Box::new(MultiLocation { - parents: 0, - interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 1000, - )); - assert!(::Assets::asset_exists(ASSET_ID)); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 100_000_000_000_000, - )); - - assert_ok!(::Balances::force_set_balance( - ::RuntimeOrigin::root(), - AssetHubKusamaSender::get().into(), - 100_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - asset_one.clone(), - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - asset_one.clone(), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - AssetHubKusamaSender::get().into() - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, - ] - ); - - let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - path, - 100, - 1, - AssetHubKusamaSender::get().into(), - true - ) - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => { - amount_in: *amount_in == 100, - amount_out: *amount_out == 199, - }, - ] - ); - - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native, - asset_one, - 1414213562273 - EXISTENTIAL_DEPOSIT * 2, // all but the 2 EDs can't be retrieved. - 0, - 0, - AssetHubKusamaSender::get().into(), - )); - }); -} - -#[test] -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 foreign_asset1_at_asset_hub_kusama = Box::new(MultiLocation { - parents: 1, - interior: X3( - Parachain(PenpalKusamaA::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())) } - .into(); - - let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalKusamaA::para_id().into())) }; - - // 1. Create asset on penpal: - PenpalKusamaA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalKusamaASender::get()), - ASSET_ID.into(), - PenpalKusamaASender::get().into(), - 1000, - )); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); - - // 2. Create foreign asset on asset_hub_kusama: - - 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); - - AssetHubKusama::fund_accounts(vec![ - (AssetHubKusamaSender::get().into(), 5_000_000 * KUSAMA_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), - ]); - - let sov_penpal_on_asset_hub_kusama_as_location: MultiLocation = MultiLocation { - parents: 0, - interior: X1(AccountId32Junction { - network: None, - id: sov_penpal_on_asset_hub_kusama.clone().into(), - }), - }; - - let call_foreign_assets_create = - ::RuntimeCall::ForeignAssets(pallet_assets::Call::< - ::Runtime, - Instance2, - >::create { - id: *foreign_asset1_at_asset_hub_kusama, - min_balance: 1000, - admin: sov_penpal_on_asset_hub_kusama.clone().into(), - }) - .encode() - .into(); - - let buy_execution_fee_amount = parachains_common::kusama::fee::WeightToFee::weight_to_fee( - &Weight::from_parts(10_100_000_000_000, 300_000), - ); - let buy_execution_fee = MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: Here }), - fun: Fungible(buy_execution_fee_amount), - }; - - let xcm = VersionedXcm::from(Xcm(vec![ - WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, - BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, - Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create }, - RefundSurplus, - DepositAsset { - assets: All.into(), - beneficiary: sov_penpal_on_asset_hub_kusama_as_location, - }, - ])); - - // Send XCM message from penpal => asset_hub_kusama - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalKusamaA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - sudo_penpal_origin.clone(), - bx!(assets_para_destination.clone()), - bx!(xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PenpalKusamaA, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_kusama - )); - - // 3: Mint foreign asset on asset_hub_kusama: - // - // (While it might be nice to use batch, - // currently that's disabled due to safe call filters.) - - 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() - ), - *foreign_asset1_at_asset_hub_kusama, - sov_penpal_on_asset_hub_kusama.clone().into(), - 3_000_000_000_000, - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - - // 4. Create pool: - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), - )); - - assert_expected_events!( - AssetHubKusama, - 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() - ), - asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - sov_penpal_on_asset_hub_kusama.clone().into() - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { - lp_token_minted: *lp_token_minted == 1414213562273, - }, - ] - ); - - // 6. Swap! - let path = BoundedVec::<_, _>::truncate_from(vec![ - asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), - ]); - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - path, - 100000, - 1000, - AssetHubKusamaSender::get().into(), - true - ) - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 100000, - amount_out: *amount_out == 199399, - }, - ] - ); - - // 7. Remove liquidity - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_kusama.clone() - ), - asset_native, - foreign_asset1_at_asset_hub_kusama, - 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. - 0, - 0, - sov_penpal_on_asset_hub_kusama.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(); - 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(); - - 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_ok!(::PoolAssets::mint( - ::RuntimeOrigin::signed(pool_owner_account_id), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 3_000_000_000_000, - )); - - assert_matches::assert_matches!( - ::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - Box::new(asset_one), - ), - Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) - ); - }); -} 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-kusama/src/tests/teleport.rs deleted file mode 100644 index f69878f3543..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/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; - - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); - - assert_expected_events!( - Kusama, - 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; - - Kusama::assert_ump_queue_processed( - true, - Some(AssetHubKusama::para_id()), - Some(Weight::from_parts(307_225_000, 7_186)), - ); - - assert_expected_events!( - Kusama, - 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) { - Kusama::assert_ump_queue_processed( - false, - Some(AssetHubKusama::para_id()), - Some(Weight::from_parts(148_433_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 534_872_000, - 7_133, - ))); - - AssetHubKusama::assert_parachain_system_ump_sent(); - - assert_expected_events!( - AssetHubKusama, - 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; - - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); - - assert_expected_events!( - AssetHubKusama, - 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 = KUSAMA_ED * 1000; - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::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_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::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_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location().into(); - let beneficiary_id = KusamaReceiver::get().into(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::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 = KUSAMA_ED * 1000; - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::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_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); -// } 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 023e8b84f11..00000000000 --- 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 e8ba8e44f25..00000000000 --- 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 e5bce267b90..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs +++ /dev/null @@ -1,192 +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, proposed_max_capacity: max_capacity, proposed_max_message_size: 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(); - - 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![ - // HRMP channel forced opened - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened{ - sender, recipient, proposed_max_capacity: max_capacity, proposed_max_message_size: 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/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs deleted file mode 100644 index c22de4f1c3e..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,20 +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. - -mod hrmp_channels; -mod reserve_transfer; -mod send; -mod set_xcm_versions; -mod teleport; 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 e53693d85d2..00000000000 --- 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 244b428a752..00000000000 --- 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 e121c416799..00000000000 --- 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 644c51d75b6..00000000000 --- 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-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index 80c41c24aa7..af9776cbcd9 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 @@ -23,7 +23,6 @@ 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} @@ -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/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml index c02c96255e1..7ecf8715824 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 122d6546115..1c73124c512 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,7 +17,7 @@ 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, + asset_hub_rococo::ED as ASSET_HUB_ROCOCO_ED, rococo::ED as ROCOCO_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, 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 99caccc8159..00000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ /dev/null @@ -1,38 +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-balances = { path = "../../../../../../substrate/frame/balances", 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 aa716c7c948..00000000000 --- 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/ambassador.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs deleted file mode 100644 index d9fd78fbcbf..00000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/ambassador.rs +++ /dev/null @@ -1,65 +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 Ambassador Program. - -use crate::*; -use collectives_polkadot_runtime::ambassador::AmbassadorSalaryPaymaster; -use frame_support::traits::{fungible::Mutate, tokens::Pay}; -use sp_core::crypto::Ss58Codec; -use xcm_emulator::TestExt; - -#[test] -fn pay_salary() { - let pay_from: AccountId = - ::from_string("5DS1Gaf6R9eFAV8QyeZP9P89kTkJMurxv3y3J3TTMu8p8VCX") - .unwrap(); - let pay_to = Polkadot::account_id_of(ALICE); - let pay_amount = 90000000000; - - AssetHubPolkadot::execute_with(|| { - type AssetHubBalances = ::Balances; - - assert_ok!(>::mint_into(&pay_from, pay_amount * 2)); - }); - - Collectives::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(AmbassadorSalaryPaymaster::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::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { - 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/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 c08a660205f..00000000000 --- 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/collectives/collectives-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs deleted file mode 100644 index 42d2432d223..00000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,17 +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. - -mod ambassador; -mod fellowship; diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index f1db26c2a54..e47fdfcdfd6 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -30,10 +30,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" } @@ -73,7 +69,6 @@ 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-bridge-messages/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", @@ -85,7 +80,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 8725ebd140b..33a9ac38c8c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -27,12 +27,8 @@ use sp_runtime::{ // Cumulus use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; -use polkadot_parachain_primitives::primitives::{HeadData, ValidationCode}; use polkadot_primitives::{AssignmentId, ValidatorId}; -use polkadot_runtime_parachains::{ - configuration::HostConfiguration, - paras::{ParaGenesisArgs, ParaKind}, -}; +use polkadot_runtime_parachains::configuration::HostConfiguration; use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; use xcm; @@ -138,144 +134,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,149 +244,6 @@ pub mod westend { } } -// Kusama -pub mod kusama { - 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 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: 5_000_000_000_000, - hrmp_recipient_deposit: 5_000_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, - beefy: BeefyId, - ) -> kusama_runtime::SessionKeys { - kusama_runtime::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - beefy, - } - } - - pub fn genesis() -> Storage { - let genesis_config = kusama_runtime::RuntimeGenesisConfig { - system: kusama_runtime::SystemConfig { - code: kusama_runtime::WASM_BINARY.unwrap().to_vec(), - ..Default::default() - }, - balances: kusama_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .map(|k: &AccountId| (k.clone(), ENDOWMENT)) - .collect(), - }, - session: kusama_runtime::SessionConfig { - keys: validators::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(), - get_from_seed::("Alice"), - ), - ) - }) - .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 { - authorities: Default::default(), - epoch_config: Some(kusama_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - configuration: kusama_runtime::ConfigurationConfig { config: get_host_config() }, - paras: kusama_runtime::ParasConfig { - paras: vec![ - ( - asset_hub_kusama::PARA_ID.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - asset_hub_kusama_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() - } -} - // Rococo pub mod rococo { use super::*; @@ -627,63 +342,6 @@ pub mod rococo { } } -// Asset Hub Polkadot -pub mod asset_hub_polkadot { - use super::*; - pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::polkadot::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 - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: asset_hub_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: asset_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables_asset_hub_polkadot() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_polkadot_runtime::SessionConfig { - keys: collators::invulnerables_asset_hub_polkadot() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: asset_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} - // Asset Hub Westend pub mod asset_hub_westend { use super::*; @@ -742,31 +400,31 @@ pub mod asset_hub_westend { } // Asset Hub Kusama -pub mod asset_hub_kusama { +pub mod asset_hub_rococo { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::rococo::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_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_kusama_runtime::BalancesConfig { + balances: asset_hub_westend_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_westend_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() }, - collator_selection: asset_hub_kusama_runtime::CollatorSelectionConfig { + collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { invulnerables: collators::invulnerables() .iter() .cloned() @@ -775,19 +433,19 @@ pub mod asset_hub_kusama { candidacy_bond: ED * 16, ..Default::default() }, - session: asset_hub_kusama_runtime::SessionConfig { + session: asset_hub_westend_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 + acc.clone(), // account id + acc, // validator id + asset_hub_westend_runtime::SessionKeys { aura }, // session keys ) }) .collect(), }, - polkadot_xcm: asset_hub_kusama_runtime::PolkadotXcmConfig { + polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, @@ -859,177 +517,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/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 2804128ec01..dd971befa7c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -19,8 +19,7 @@ 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, bridge_hub_rococo, penpal, rococo, westend, }; use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; @@ -34,36 +33,6 @@ use xcm_emulator::{ }; 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(7)] pub struct Westend { genesis = westend::genesis(), @@ -112,164 +81,6 @@ 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(), - on_init = { - bridge_hub_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_polkadot_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, - }, - pallets = { - PolkadotXcm: bridge_hub_polkadot_runtime::PolkadotXcm, - } - }, - pub struct PenpalPolkadotA { - 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, - } - }, - 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(), - on_init = { - asset_hub_kusama_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, - ForeignAssets: asset_hub_kusama_runtime::ForeignAssets, - PoolAssets: asset_hub_kusama_runtime::PoolAssets, - AssetConversion: asset_hub_kusama_runtime::AssetConversion, - Balances: asset_hub_kusama_runtime::Balances, - } - }, - pub struct BridgeHubKusama { - genesis = bridge_hub_kusama::genesis(), - on_init = { - bridge_hub_kusama_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_kusama_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, - }, - pallets = { - PolkadotXcm: bridge_hub_kusama_runtime::PolkadotXcm, - } - }, - pub struct PenpalKusamaA { - 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, - } - }, - pub struct PenpalKusamaB { - 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, - } - }, // Westend Parachains pub struct AssetHubWestend { genesis = asset_hub_westend::genesis(), @@ -329,7 +140,7 @@ decl_test_parachains! { }, // AssetHubRococo (aka Rockmine/Rockmine2) mirrors AssetHubKusama pub struct AssetHubRococo { - genesis = asset_hub_kusama::genesis(), + genesis = asset_hub_rococo::genesis(), on_init = { asset_hub_polkadot_runtime::AuraExt::on_initialize(1); }, @@ -363,7 +174,7 @@ decl_test_parachains! { } }, pub struct AssetHubWococo { - genesis = asset_hub_polkadot::genesis(), + genesis = asset_hub_westend::genesis(), on_init = { asset_hub_polkadot_runtime::AuraExt::on_initialize(1); }, @@ -399,31 +210,6 @@ decl_test_parachains! { } 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![ @@ -475,16 +261,6 @@ decl_test_bridges! { // } } -// 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); @@ -497,65 +273,31 @@ impl_assert_events_helpers_for_relay_chain!(Rococo); 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); - // 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); - // 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); 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 } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 4853195d329..eb0f249aaae 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -56,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} @@ -177,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", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index f0eae31f53a..df38e4d9d64 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -56,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} @@ -185,7 +184,6 @@ 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", 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 d54e66c42dc..bfb0b9e7127 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -49,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} @@ -94,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", 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 d9dba557681..eb0c18f5b46 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -49,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} @@ -112,7 +111,6 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", - "polkadot-runtime-constants/std", "scale-info/std", "serde", "sp-api/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 8cb5519a24d..e66cef31e56 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -58,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} @@ -195,7 +194,6 @@ 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", 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 02e4913fcd9..f802073bfbb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -26,7 +26,6 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_constants::xcm::body::FELLOWSHIP_ADMIN_INDEX; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -39,6 +38,8 @@ use xcm_builder::{ }; 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); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index a85aa8dcb17..414c7ad9d94 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -53,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} @@ -94,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", diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 799a229b6ad..4646fb1c588 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -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" } @@ -57,7 +56,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,7 +63,6 @@ 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. westend-native = [ "service/westend-native" ] diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index aaf8f170576..faca2b25e23 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -58,10 +58,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 19437ce8753..a7f429d6eca 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -167,26 +167,6 @@ fn set_default_ss58_version(spec: &Box) { sp_core::crypto::set_default_ss58_version(ss58_version); } -/// 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. @@ -509,13 +489,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 62ee4d13907..21928979652 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, diff --git a/polkadot/cli/src/host_perf_check.rs b/polkadot/cli/src/host_perf_check.rs deleted file mode 100644 index adfdebce677..00000000000 --- 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 057592fa8a1..35a467146b4 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/test/performance-test/Cargo.toml b/polkadot/node/test/performance-test/Cargo.toml deleted file mode 100644 index 5747ac88b1e..00000000000 --- 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 304b24c3b85..00000000000 --- 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 158646ffc6e..00000000000 --- 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 ba10ed21555..00000000000 --- 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 15073912654..00000000000 --- 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/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml deleted file mode 100644 index ebbcfc71e95..00000000000 --- a/polkadot/runtime/kusama/Cargo.toml +++ /dev/null @@ -1,352 +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-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 } -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-genesis-builder/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/build.rs b/polkadot/runtime/kusama/build.rs deleted file mode 100644 index 404ba3f2fdb..00000000000 --- a/polkadot/runtime/kusama/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. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU 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/kusama/constants/Cargo.toml b/polkadot/runtime/kusama/constants/Cargo.toml deleted file mode 100644 index e8daac10cf4..00000000000 --- 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 78f96b35106..00000000000 --- 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 8423e1f810c..00000000000 --- 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 6a2fb7dd206..00000000000 --- 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/constants/src/weights/mod.rs b/polkadot/runtime/kusama/constants/src/weights/mod.rs deleted file mode 100644 index 23812ce7ed0..00000000000 --- a/polkadot/runtime/kusama/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/kusama/constants/src/weights/paritydb_weights.rs b/polkadot/runtime/kusama/constants/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/polkadot/runtime/kusama/constants/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/kusama/constants/src/weights/rocksdb_weights.rs b/polkadot/runtime/kusama/constants/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/polkadot/runtime/kusama/constants/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/kusama/src/bag_thresholds.rs b/polkadot/runtime/kusama/src/bag_thresholds.rs deleted file mode 100644 index 82dc4c3a811..00000000000 --- 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/governance/fellowship.rs b/polkadot/runtime/kusama/src/governance/fellowship.rs deleted file mode 100644 index 8837c19e0eb..00000000000 --- a/polkadot/runtime/kusama/src/governance/fellowship.rs +++ /dev/null @@ -1,358 +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 . - -//! 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. - -use frame_support::traits::{MapSuccess, TryMapSuccess}; -use sp_arithmetic::traits::CheckedSub; -use sp_runtime::{ - morph_types, - traits::{ConstU16, Replace, TypedGet}, -}; - -use super::*; -use crate::{DAYS, QUID}; - -parameter_types! { - pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 0; - pub const UndecidingTimeout: BlockNumber = 7 * DAYS; -} - -pub struct TracksInfo; -impl pallet_referenda::TracksInfo for TracksInfo { - type Id = u16; - type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - static DATA: [(u16, pallet_referenda::TrackInfo); 10] = [ - ( - 0u16, - pallet_referenda::TrackInfo { - name: "candidates", - max_deciding: 10, - decision_deposit: 100 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 1u16, - pallet_referenda::TrackInfo { - name: "members", - max_deciding: 10, - decision_deposit: 10 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 2u16, - pallet_referenda::TrackInfo { - name: "proficients", - max_deciding: 10, - decision_deposit: 10 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 3u16, - pallet_referenda::TrackInfo { - name: "fellows", - max_deciding: 10, - decision_deposit: 10 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 4u16, - pallet_referenda::TrackInfo { - name: "senior fellows", - max_deciding: 10, - decision_deposit: 10 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 5u16, - pallet_referenda::TrackInfo { - name: "experts", - max_deciding: 10, - decision_deposit: 1 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 6u16, - pallet_referenda::TrackInfo { - name: "senior experts", - max_deciding: 10, - decision_deposit: 1 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 7u16, - pallet_referenda::TrackInfo { - name: "masters", - max_deciding: 10, - decision_deposit: 1 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 8u16, - pallet_referenda::TrackInfo { - name: "senior masters", - max_deciding: 10, - decision_deposit: 1 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ( - 9u16, - pallet_referenda::TrackInfo { - name: "grand masters", - max_deciding: 10, - decision_deposit: 1 * QUID, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 1 * MINUTES, - 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(0), - ceil: Perbill::from_percent(50), - }, - }, - ), - ]; - &DATA[..] - } - fn track_for(id: &Self::RuntimeOrigin) -> Result { - use super::origins::Origin; - - #[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(9) - } - } - - match Origin::try_from(id.clone()) { - Ok(Origin::FellowshipInitiates) => Ok(0), - Ok(Origin::Fellowship1Dan) => Ok(1), - Ok(Origin::Fellowship2Dan) => Ok(2), - Ok(Origin::Fellowship3Dan) | Ok(Origin::Fellows) => Ok(3), - Ok(Origin::Fellowship4Dan) => Ok(4), - Ok(Origin::Fellowship5Dan) | Ok(Origin::FellowshipExperts) => Ok(5), - Ok(Origin::Fellowship6Dan) => Ok(6), - Ok(Origin::Fellowship7Dan | Origin::FellowshipMasters) => Ok(7), - Ok(Origin::Fellowship8Dan) => Ok(8), - Ok(Origin::Fellowship9Dan) => Ok(9), - _ => Err(()), - } - } -} -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); - -pub type FellowshipReferendaInstance = pallet_referenda::Instance2; - -impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda_fellowship_referenda::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type Scheduler = Scheduler; - type Currency = Balances; - type SubmitOrigin = - pallet_ranked_collective::EnsureMember; - type CancelOrigin = FellowshipExperts; - type KillOrigin = FellowshipMasters; - type Slash = Treasury; - type Votes = pallet_ranked_collective::Votes; - type Tally = pallet_ranked_collective::TallyOf; - type SubmissionDeposit = SubmissionDeposit; - type MaxQueued = ConstU32<100>; - type UndecidingTimeout = UndecidingTimeout; - type AlarmInterval = AlarmInterval; - type Tracks = TracksInfo; - type Preimages = Preimage; -} - -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; - // Promotion is by any of: - // - Root can demote arbitrarily. - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - a vote by the rank *above* the new rank. - type PromoteOrigin = EitherOf< - frame_system::EnsureRootWithSuccess>, - EitherOf< - MapSuccess>>, - TryMapSuccess>>, - >, - >; - // Demotion is by any of: - // - Root can demote arbitrarily. - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - a vote by the rank two above the current rank. - type DemoteOrigin = EitherOf< - frame_system::EnsureRootWithSuccess>, - EitherOf< - MapSuccess>>, - TryMapSuccess>>, - >, - >; - type Polls = FellowshipReferenda; - type MinRankOfClass = sp_runtime::traits::Identity; - type VoteWeight = pallet_ranked_collective::Geometric; -} diff --git a/polkadot/runtime/kusama/src/governance/mod.rs b/polkadot/runtime/kusama/src/governance/mod.rs deleted file mode 100644 index c8a7b360ed4..00000000000 --- a/polkadot/runtime/kusama/src/governance/mod.rs +++ /dev/null @@ -1,93 +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 . - -//! New governance configurations for the Kusama runtime. - -use super::*; -use frame_support::{ - parameter_types, - traits::{ConstU16, EitherOf}, -}; -use frame_system::EnsureRootWithSuccess; - -mod origins; -pub use origins::{ - pallet_custom_origins, AuctionAdmin, Fellows, FellowshipAdmin, FellowshipExperts, - FellowshipInitiates, FellowshipMasters, GeneralAdmin, LeaseAdmin, ReferendumCanceller, - ReferendumKiller, Spender, StakingAdmin, Treasurer, WhitelistedCaller, -}; -mod tracks; -pub use tracks::TracksInfo; -mod fellowship; -pub use fellowship::{FellowshipCollectiveInstance, FellowshipReferendaInstance}; - -parameter_types! { - pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; -} - -impl pallet_conviction_voting::Config for Runtime { - type WeightInfo = weights::pallet_conviction_voting::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type VoteLockingPeriod = VoteLockingPeriod; - type MaxVotes = ConstU32<512>; - type MaxTurnout = - frame_support::traits::tokens::currency::ActiveIssuanceOf; - type Polls = Referenda; -} - -parameter_types! { - pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 1 * QUID; - pub const UndecidingTimeout: BlockNumber = 14 * DAYS; -} - -parameter_types! { - pub const MaxBalance: Balance = Balance::max_value(); -} -pub type TreasurySpender = EitherOf, Spender>; - -impl origins::pallet_custom_origins::Config for Runtime {} - -impl pallet_whitelist::Config for Runtime { - type WeightInfo = weights::pallet_whitelist::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type WhitelistOrigin = - EitherOf>, Fellows>; - type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; - type Preimages = Preimage; -} - -impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda_referenda::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type Scheduler = Scheduler; - type Currency = Balances; - type SubmitOrigin = frame_system::EnsureSigned; - type CancelOrigin = EitherOf, ReferendumCanceller>; - type KillOrigin = EitherOf, ReferendumKiller>; - type Slash = Treasury; - type Votes = pallet_conviction_voting::VotesOf; - type Tally = pallet_conviction_voting::TallyOf; - type SubmissionDeposit = SubmissionDeposit; - type MaxQueued = ConstU32<100>; - type UndecidingTimeout = UndecidingTimeout; - type AlarmInterval = AlarmInterval; - type Tracks = TracksInfo; - type Preimages = Preimage; -} diff --git a/polkadot/runtime/kusama/src/governance/origins.rs b/polkadot/runtime/kusama/src/governance/origins.rs deleted file mode 100644 index c5cb035a526..00000000000 --- a/polkadot/runtime/kusama/src/governance/origins.rs +++ /dev/null @@ -1,194 +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 . - -//! Custom origins for governance interventions. - -pub use pallet_custom_origins::*; - -#[frame_support::pallet] -pub mod pallet_custom_origins { - use crate::{Balance, GRAND, QUID}; - use frame_support::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - pub struct Pallet(_); - - #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] - #[pallet::origin] - pub enum Origin { - /// Origin for cancelling slashes. - StakingAdmin, - /// 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. - GeneralAdmin, - /// Origin for starting auctions. - AuctionAdmin, - /// Origin able to force slot leases. - LeaseAdmin, - /// Origin able to cancel referenda. - ReferendumCanceller, - /// Origin able to kill referenda. - ReferendumKiller, - /// Origin able to spend up to 1 KSM from the treasury at once. - SmallTipper, - /// Origin able to spend up to 5 KSM from the treasury at once. - BigTipper, - /// Origin able to spend up to 50 KSM from the treasury at once. - SmallSpender, - /// Origin able to spend up to 500 KSM from the treasury at once. - MediumSpender, - /// 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 { - ( $name:ident: $success_type:ty = $success:expr ) => { - pub struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - Origin::$name => Ok($success), - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(Origin::$name)) - } - } - }; - ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; - ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { - decl_unit_ensures! { $name: $success_type = $success } - decl_unit_ensures! { $( $rest )* } - }; - ( $name:ident, $( $rest:tt )* ) => { - decl_unit_ensures! { $name } - decl_unit_ensures! { $( $rest )* } - }; - () => {} - } - decl_unit_ensures!( - StakingAdmin, - Treasurer, - FellowshipAdmin, - GeneralAdmin, - AuctionAdmin, - LeaseAdmin, - ReferendumCanceller, - ReferendumKiller, - WhitelistedCaller, - FellowshipInitiates: u16 = 0, - Fellows: u16 = 3, - FellowshipExperts: u16 = 5, - FellowshipMasters: u16 = 7, - ); - - macro_rules! decl_ensure { - ( - $vis:vis type $name:ident: EnsureOrigin { - $( $item:ident = $success:expr, )* - } - ) => { - $vis struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - $( - Origin::$item => Ok($success), - )* - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - // By convention the more privileged origins go later, so for greatest chance - // of success, we want the last one. - let _result: Result = Err(()); - $( - let _result: Result = Ok(O::from(Origin::$item)); - )* - _result - } - } - } - } - - decl_ensure! { - pub type Spender: EnsureOrigin { - SmallTipper = 250 * QUID, - BigTipper = 1 * GRAND, - SmallSpender = 10 * GRAND, - MediumSpender = 100 * GRAND, - BigSpender = 1_000 * GRAND, - 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/kusama/src/governance/tracks.rs b/polkadot/runtime/kusama/src/governance/tracks.rs deleted file mode 100644 index 08a87a677c3..00000000000 --- a/polkadot/runtime/kusama/src/governance/tracks.rs +++ /dev/null @@ -1,320 +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 . - -//! Track configurations for governance. - -use super::*; - -const fn percent(x: i32) -> sp_arithmetic::FixedI64 { - sp_arithmetic::FixedI64::from_rational(x as u128, 100) -} -use pallet_referenda::Curve; -const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); -const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_STAKING_ADMIN: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); -const APP_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_FELLOWSHIP_ADMIN: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_GENERAL_ADMIN: Curve = - Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_GENERAL_ADMIN: Curve = - Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); -const APP_AUCTION_ADMIN: Curve = - Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_AUCTION_ADMIN: Curve = - Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); -const APP_LEASE_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_LEASE_ADMIN: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_REFERENDUM_CANCELLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_REFERENDUM_CANCELLER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_REFERENDUM_KILLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_REFERENDUM_KILLER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); -const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); -const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); -const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); -const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_SMALL_SPENDER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); -const SUP_MEDIUM_SPENDER: Curve = - Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); -const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); -const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); -const APP_WHITELISTED_CALLER: Curve = - Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); -const SUP_WHITELISTED_CALLER: Curve = - Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); - -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15] = [ - ( - 0, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_ROOT, - min_support: SUP_ROOT, - }, - ), - ( - 1, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_WHITELISTED_CALLER, - min_support: SUP_WHITELISTED_CALLER, - }, - ), - ( - 10, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_STAKING_ADMIN, - min_support: SUP_STAKING_ADMIN, - }, - ), - ( - 11, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_TREASURER, - min_support: SUP_TREASURER, - }, - ), - ( - 12, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_LEASE_ADMIN, - min_support: SUP_LEASE_ADMIN, - }, - ), - ( - 13, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_FELLOWSHIP_ADMIN, - min_support: SUP_FELLOWSHIP_ADMIN, - }, - ), - ( - 14, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_GENERAL_ADMIN, - min_support: SUP_GENERAL_ADMIN, - }, - ), - ( - 15, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_AUCTION_ADMIN, - min_support: SUP_AUCTION_ADMIN, - }, - ), - ( - 20, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_REFERENDUM_CANCELLER, - min_support: SUP_REFERENDUM_CANCELLER, - }, - ), - ( - 21, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_REFERENDUM_KILLER, - min_support: SUP_REFERENDUM_KILLER, - }, - ), - ( - 30, - pallet_referenda::TrackInfo { - name: "small_tipper", - max_deciding: 200, - decision_deposit: 1 * QUID, - prepare_period: 1 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 10 * MINUTES, - min_enactment_period: 1 * MINUTES, - min_approval: APP_SMALL_TIPPER, - min_support: SUP_SMALL_TIPPER, - }, - ), - ( - 31, - 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, - min_approval: APP_BIG_TIPPER, - min_support: SUP_BIG_TIPPER, - }, - ), - ( - 32, - 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, - min_approval: APP_SMALL_SPENDER, - min_support: SUP_SMALL_SPENDER, - }, - ), - ( - 33, - 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, - min_approval: APP_MEDIUM_SPENDER, - min_support: SUP_MEDIUM_SPENDER, - }, - ), - ( - 34, - 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, - min_approval: APP_BIG_SPENDER, - min_support: SUP_BIG_SPENDER, - }, - ), -]; - -pub struct TracksInfo; -impl pallet_referenda::TracksInfo for TracksInfo { - type Id = u16; - type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - &TRACKS_DATA[..] - } - fn track_for(id: &Self::RuntimeOrigin) -> Result { - if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { - match system_origin { - frame_system::RawOrigin::Root => Ok(0), - _ => Err(()), - } - } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { - match custom_origin { - origins::Origin::WhitelistedCaller => Ok(1), - // General admin - origins::Origin::StakingAdmin => Ok(10), - origins::Origin::Treasurer => Ok(11), - origins::Origin::LeaseAdmin => Ok(12), - origins::Origin::FellowshipAdmin => Ok(13), - origins::Origin::GeneralAdmin => Ok(14), - origins::Origin::AuctionAdmin => Ok(15), - // Referendum admins - origins::Origin::ReferendumCanceller => Ok(20), - origins::Origin::ReferendumKiller => Ok(21), - // Limited treasury spenders - origins::Origin::SmallTipper => Ok(30), - origins::Origin::BigTipper => Ok(31), - origins::Origin::SmallSpender => Ok(32), - origins::Origin::MediumSpender => Ok(33), - origins::Origin::BigSpender => Ok(34), - _ => Err(()), - } - } else { - Err(()) - } - } -} -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs deleted file mode 100644 index 1709c1bf8b1..00000000000 --- a/polkadot/runtime/kusama/src/lib.rs +++ /dev/null @@ -1,2754 +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::v7 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, - genesis_builder_helper::{build_config, create_default_config}, - parameter_types, - traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, - 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() } -} - -/// 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 = 2; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = EverythingBut; - 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) - } - } - - 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)] -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 2d8b67902b8..00000000000 --- 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 053c3054ab4..00000000000 --- 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 e9f934f5656..00000000000 --- 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 9cdbd67d5e1..00000000000 --- 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 927977e9be0..00000000000 --- 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 b3642d49d46..00000000000 --- 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 b138ae3003b..00000000000 --- 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 a8498f52f8b..00000000000 --- 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 f65c5722d8b..00000000000 --- 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 730d622e9ab..00000000000 --- 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 07ddb5240e6..00000000000 --- 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 252060ba37b..00000000000 --- 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 84157595f7c..00000000000 --- 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 0bf5d2839b0..00000000000 --- 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_conviction_voting.rs b/polkadot/runtime/kusama/src/weights/pallet_conviction_voting.rs deleted file mode 100644 index ba505737f1b..00000000000 --- a/polkadot/runtime/kusama/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-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_conviction_voting -// --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_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: 151_077_000 picoseconds. - Weight::from_parts(165_283_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: 232_420_000 picoseconds. - Weight::from_parts(244_439_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: 205_017_000 picoseconds. - Weight::from_parts(216_594_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: 84_226_000 picoseconds. - Weight::from_parts(91_255_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: 78_708_000 picoseconds. - Weight::from_parts(2_053_488_615, 0) - .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 179_271 - .saturating_add(Weight::from_parts(47_806_482, 0).saturating_mul(r.into())) - .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: 45_232_000 picoseconds. - Weight::from_parts(2_045_021_014, 0) - .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 185_130 - .saturating_add(Weight::from_parts(47_896_011, 0).saturating_mul(r.into())) - .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: 116_446_000 picoseconds. - Weight::from_parts(124_043_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/kusama/src/weights/pallet_democracy.rs b/polkadot/runtime/kusama/src/weights/pallet_democracy.rs deleted file mode 100644 index 794c8c81596..00000000000 --- 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 d670d324aba..00000000000 --- 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 a5c1c4dfd3d..00000000000 --- 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 34fec8e784f..00000000000 --- 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 f4952db592b..00000000000 --- 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 3bb3d65c4a6..00000000000 --- 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 b26562975cf..00000000000 --- 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 6b144bc8794..00000000000 --- 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 f149eef194f..00000000000 --- 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_multisig.rs b/polkadot/runtime/kusama/src/weights/pallet_multisig.rs deleted file mode 100644 index 108189c6ca1..00000000000 --- a/polkadot/runtime/kusama/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-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_multisig -// --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_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_299_000 picoseconds. - Weight::from_parts(14_368_762, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(557, 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: `301 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 45_147_000 picoseconds. - Weight::from_parts(34_161_081, 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())) - .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: `320` - // Estimated: `6811` - // Minimum execution time: 29_650_000 picoseconds. - Weight::from_parts(20_868_716, 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())) - .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: `426 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 50_649_000 picoseconds. - Weight::from_parts(34_736_758, 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())) - .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: `301 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 32_162_000 picoseconds. - Weight::from_parts(33_215_652, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_093 - .saturating_add(Weight::from_parts(133_715, 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: `320` - // Estimated: `6811` - // Minimum execution time: 18_073_000 picoseconds. - Weight::from_parts(19_038_713, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 681 - .saturating_add(Weight::from_parts(111_279, 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: `492 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 33_867_000 picoseconds. - Weight::from_parts(34_896_470, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_002 - .saturating_add(Weight::from_parts(116_935, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} 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 2dc8b261eb5..00000000000 --- 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 65bb76860b3..00000000000 --- 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 12a045d6676..00000000000 --- 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 d0bf2056660..00000000000 --- 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 d30547d7d01..00000000000 --- 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 21f3f651f2e..00000000000 --- 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 6f2fdfa334f..00000000000 --- 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_referenda_fellowship_referenda.rs b/polkadot/runtime/kusama/src/weights/pallet_referenda_fellowship_referenda.rs deleted file mode 100644 index a4ac0667911..00000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_referenda_fellowship_referenda.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_referenda` -//! -//! 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_referenda -// --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_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: 28_969_000 picoseconds. - Weight::from_parts(30_902_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: `404` - // Estimated: `83866` - // Minimum execution time: 53_500_000 picoseconds. - Weight::from_parts(54_447_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: `2042` - // Estimated: `42428` - // Minimum execution time: 114_321_000 picoseconds. - Weight::from_parts(122_607_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: `2083` - // Estimated: `42428` - // Minimum execution time: 113_476_000 picoseconds. - Weight::from_parts(120_078_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: 194_798_000 picoseconds. - Weight::from_parts(208_378_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: 69_502_000 picoseconds. - Weight::from_parts(71_500_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: `317` - // Estimated: `4365` - // Minimum execution time: 30_561_000 picoseconds. - Weight::from_parts(31_427_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: `167` - // Estimated: `4365` - // Minimum execution time: 14_535_000 picoseconds. - Weight::from_parts(14_999_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: `349` - // Estimated: `83866` - // Minimum execution time: 38_532_000 picoseconds. - Weight::from_parts(39_361_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: `450` - // Estimated: `83866` - // Minimum execution time: 78_956_000 picoseconds. - Weight::from_parts(80_594_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: `140` - // Estimated: `4277` - // Minimum execution time: 9_450_000 picoseconds. - Weight::from_parts(9_881_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: 98_126_000 picoseconds. - Weight::from_parts(102_511_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: 99_398_000 picoseconds. - Weight::from_parts(104_045_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: `1807` - // Estimated: `4365` - // Minimum execution time: 43_734_000 picoseconds. - Weight::from_parts(46_962_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: `1774` - // Estimated: `4365` - // Minimum execution time: 42_863_000 picoseconds. - Weight::from_parts(46_241_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: `1790` - // Estimated: `4365` - // Minimum execution time: 57_511_000 picoseconds. - Weight::from_parts(64_027_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: `1831` - // Estimated: `4365` - // Minimum execution time: 56_726_000 picoseconds. - Weight::from_parts(61_962_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: `301` - // Estimated: `42428` - // Minimum execution time: 24_870_000 picoseconds. - Weight::from_parts(25_837_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: `349` - // Estimated: `42428` - // Minimum execution time: 25_297_000 picoseconds. - Weight::from_parts(26_086_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: `208` - // Estimated: `4365` - // Minimum execution time: 16_776_000 picoseconds. - Weight::from_parts(17_396_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: 37_780_000 picoseconds. - Weight::from_parts(38_626_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: 85_265_000 picoseconds. - Weight::from_parts(89_986_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: 143_283_000 picoseconds. - Weight::from_parts(158_540_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: 143_736_000 picoseconds. - Weight::from_parts(162_755_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: 139_021_000 picoseconds. - Weight::from_parts(157_398_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: 78_530_000 picoseconds. - Weight::from_parts(83_556_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: 174_165_000 picoseconds. - Weight::from_parts(188_496_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: 142_964_000 picoseconds. - Weight::from_parts(157_257_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: `352` - // Estimated: `4365` - // Minimum execution time: 20_126_000 picoseconds. - Weight::from_parts(20_635_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: `285` - // Estimated: `4365` - // Minimum execution time: 17_716_000 picoseconds. - Weight::from_parts(18_324_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/kusama/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/kusama/src/weights/pallet_referenda_referenda.rs deleted file mode 100644 index accaa0ef10d..00000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_referenda_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-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_referenda -// --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_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: `186` - // Estimated: `42428` - // Minimum execution time: 39_146_000 picoseconds. - Weight::from_parts(40_383_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: `439` - // Estimated: `83866` - // Minimum execution time: 51_385_000 picoseconds. - Weight::from_parts(52_701_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: `3196` - // Estimated: `42428` - // Minimum execution time: 70_018_000 picoseconds. - Weight::from_parts(75_868_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: `3216` - // Estimated: `42428` - // Minimum execution time: 69_311_000 picoseconds. - Weight::from_parts(72_425_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: `439` - // Estimated: `83866` - // Minimum execution time: 64_385_000 picoseconds. - Weight::from_parts(66_178_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: `439` - // Estimated: `83866` - // Minimum execution time: 62_200_000 picoseconds. - Weight::from_parts(63_782_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: `279` - // Estimated: `4401` - // Minimum execution time: 29_677_000 picoseconds. - Weight::from_parts(30_603_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: `269` - // Estimated: `4401` - // Minimum execution time: 29_897_000 picoseconds. - Weight::from_parts(30_618_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: `347` - // Estimated: `83866` - // Minimum execution time: 37_697_000 picoseconds. - Weight::from_parts(38_953_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: `588` - // Estimated: `83866` - // Minimum execution time: 106_001_000 picoseconds. - Weight::from_parts(107_102_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: `102` - // Estimated: `5477` - // Minimum execution time: 8_987_000 picoseconds. - Weight::from_parts(9_431_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: `3116` - // Estimated: `42428` - // Minimum execution time: 55_344_000 picoseconds. - Weight::from_parts(58_026_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: `3116` - // Estimated: `42428` - // Minimum execution time: 57_003_000 picoseconds. - Weight::from_parts(60_347_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: `2939` - // Estimated: `5477` - // Minimum execution time: 23_001_000 picoseconds. - Weight::from_parts(24_812_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: `2939` - // Estimated: `5477` - // Minimum execution time: 23_299_000 picoseconds. - Weight::from_parts(24_465_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: `2943` - // Estimated: `5477` - // Minimum execution time: 28_223_000 picoseconds. - Weight::from_parts(29_664_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: `2963` - // Estimated: `5477` - // Minimum execution time: 27_474_000 picoseconds. - Weight::from_parts(29_072_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: `299` - // Estimated: `42428` - // Minimum execution time: 24_405_000 picoseconds. - Weight::from_parts(25_184_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: `347` - // Estimated: `42428` - // Minimum execution time: 24_572_000 picoseconds. - Weight::from_parts(25_287_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: `206` - // Estimated: `4401` - // Minimum execution time: 16_042_000 picoseconds. - Weight::from_parts(16_610_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: `347` - // Estimated: `42428` - // Minimum execution time: 33_639_000 picoseconds. - Weight::from_parts(34_749_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: `347` - // Estimated: `42428` - // Minimum execution time: 36_467_000 picoseconds. - Weight::from_parts(37_693_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: `400` - // Estimated: `42428` - // Minimum execution time: 29_857_000 picoseconds. - Weight::from_parts(30_840_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: `383` - // Estimated: `42428` - // Minimum execution time: 31_028_000 picoseconds. - Weight::from_parts(32_154_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: `400` - // Estimated: `42428` - // Minimum execution time: 28_594_000 picoseconds. - Weight::from_parts(29_092_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: `404` - // Estimated: `42428` - // Minimum execution time: 27_246_000 picoseconds. - Weight::from_parts(28_003_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: `404` - // Estimated: `83866` - // Minimum execution time: 43_426_000 picoseconds. - Weight::from_parts(44_917_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: `400` - // Estimated: `42428` - // Minimum execution time: 30_285_000 picoseconds. - Weight::from_parts(31_575_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: `350` - // Estimated: `4401` - // Minimum execution time: 19_254_000 picoseconds. - Weight::from_parts(19_855_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: `283` - // Estimated: `4401` - // Minimum execution time: 16_957_000 picoseconds. - Weight::from_parts(17_556_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/kusama/src/weights/pallet_scheduler.rs b/polkadot/runtime/kusama/src/weights/pallet_scheduler.rs deleted file mode 100644 index 3e8e8810b2e..00000000000 --- 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 3f5469477e5..00000000000 --- 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 2b564349b41..00000000000 --- 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 a7268a21bb9..00000000000 --- 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 ab127fd9606..00000000000 --- 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 64729ed6303..00000000000 --- 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_treasury.rs b/polkadot/runtime/kusama/src/weights/pallet_treasury.rs deleted file mode 100644 index fe2e4f9cee8..00000000000 --- a/polkadot/runtime/kusama/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("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_treasury -// --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_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_076_000 picoseconds. - Weight::from_parts(14_546_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_324_000 picoseconds. - Weight::from_parts(27_723_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: 41_722_000 picoseconds. - Weight::from_parts(42_638_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: 8_332_000 picoseconds. - Weight::from_parts(10_971_007, 0) - .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 1_480 - .saturating_add(Weight::from_parts(78_440, 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: 6_465_000 picoseconds. - Weight::from_parts(6_632_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:201 w:201) - /// 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: `264 + p * (251 ±0)` - // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 67_339_000 picoseconds. - Weight::from_parts(61_523_213, 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())) - .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())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_utility.rs b/polkadot/runtime/kusama/src/weights/pallet_utility.rs deleted file mode 100644 index d6843617fe3..00000000000 --- a/polkadot/runtime/kusama/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("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_utility -// --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_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_750_000 picoseconds. - Weight::from_parts(7_924_668, 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())) - } - 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) - .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_747_000 picoseconds. - Weight::from_parts(12_311_060, 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())) - } - 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) - .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_708_000 picoseconds. - Weight::from_parts(10_795_859, 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())) - } -} 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 b33a9174bce..00000000000 --- 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_whitelist.rs b/polkadot/runtime/kusama/src/weights/pallet_whitelist.rs deleted file mode 100644 index fe2d317651a..00000000000 --- a/polkadot/runtime/kusama/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("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_whitelist -// --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_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: 19_893_000 picoseconds. - Weight::from_parts(20_176_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: 17_393_000 picoseconds. - Weight::from_parts(18_076_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: 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())) - .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: 21_190_000 picoseconds. - Weight::from_parts(21_802_426, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_465, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} 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 4b1a790a57a..00000000000 --- 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 2370f98f070..00000000000 --- 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 ecf29f0cdc1..00000000000 --- 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 1785e0e5d38..00000000000 --- 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 9426d667346..00000000000 --- 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 8c76ff2c693..00000000000 --- 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 22609209c73..00000000000 --- 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 be78e3ac86b..00000000000 --- 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 bcde1ef418d..00000000000 --- 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 f2bc2aa2b08..00000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.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 `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)) - } - /// 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/kusama/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index 9ca4b2fe2a7..00000000000 --- 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 31878846d32..00000000000 --- 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 9e66592fbdf..00000000000 --- 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 9a9a3a3dffb..00000000000 --- 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/mod.rs b/polkadot/runtime/kusama/src/weights/xcm/mod.rs deleted file mode 100644 index 5958abe40df..00000000000 --- a/polkadot/runtime/kusama/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 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; -} - -// Kusama 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 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), - } - } -} - -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 KusamaXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for KusamaXcmWeight { - 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()) - } - 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 { - // Kusama 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 { - // Kusama does not currently support universal origin operations - Weight::MAX - } - 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 { - 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/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 07f3ccb48d9..00000000000 --- 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 fb0ca3c19f4..00000000000 --- 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 40ecc83fe64..00000000000 --- a/polkadot/runtime/kusama/src/xcm_config.rs +++ /dev/null @@ -1,311 +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, DescribeBodyTerminal, - DescribeFamily, HashedDescription, 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, - // 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`. -/// -/// 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/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml deleted file mode 100644 index 5e283b49669..00000000000 --- a/polkadot/runtime/polkadot/Cargo.toml +++ /dev/null @@ -1,321 +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-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", 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-genesis-builder/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 428c971bc13..00000000000 --- 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 554b72f2317..00000000000 --- 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 304d86d1dd7..00000000000 --- 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 9608fd53406..00000000000 --- 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 fac87924821..00000000000 --- 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 23812ce7ed0..00000000000 --- 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 ae7bedc394f..00000000000 --- 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 029f892b01d..00000000000 --- 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 56c764f7a69..00000000000 --- 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/governance/mod.rs b/polkadot/runtime/polkadot/src/governance/mod.rs deleted file mode 100644 index 79c904622dd..00000000000 --- a/polkadot/runtime/polkadot/src/governance/mod.rs +++ /dev/null @@ -1,97 +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 . - -//! New governance configurations for the Polkadot runtime. - -use super::*; -use crate::xcm_config::CollectivesLocation; -use frame_support::{parameter_types, traits::EitherOf}; -use frame_system::EnsureRootWithSuccess; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use xcm::latest::BodyId; - -mod origins; -pub use origins::{ - pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, - ReferendumCanceller, ReferendumKiller, Spender, StakingAdmin, Treasurer, WhitelistedCaller, -}; -mod tracks; -pub use tracks::TracksInfo; - -parameter_types! { - pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1); -} - -impl pallet_conviction_voting::Config for Runtime { - type WeightInfo = weights::pallet_conviction_voting::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type VoteLockingPeriod = VoteLockingPeriod; - type MaxVotes = ConstU32<512>; - type MaxTurnout = - frame_support::traits::tokens::currency::ActiveIssuanceOf; - type Polls = Referenda; -} - -parameter_types! { - pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 1 * DOLLARS; - pub const UndecidingTimeout: BlockNumber = 14 * DAYS; -} - -parameter_types! { - pub const MaxBalance: Balance = Balance::max_value(); -} -pub type TreasurySpender = EitherOf, Spender>; - -impl origins::pallet_custom_origins::Config for Runtime {} - -parameter_types! { - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -impl pallet_whitelist::Config for Runtime { - type WeightInfo = weights::pallet_whitelist::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type WhitelistOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, - >; - type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; - type Preimages = Preimage; -} - -impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type Scheduler = Scheduler; - type Currency = Balances; - type SubmitOrigin = frame_system::EnsureSigned; - type CancelOrigin = EitherOf, ReferendumCanceller>; - type KillOrigin = EitherOf, ReferendumKiller>; - type Slash = Treasury; - type Votes = pallet_conviction_voting::VotesOf; - type Tally = pallet_conviction_voting::TallyOf; - type SubmissionDeposit = SubmissionDeposit; - type MaxQueued = ConstU32<100>; - type UndecidingTimeout = UndecidingTimeout; - type AlarmInterval = AlarmInterval; - type Tracks = TracksInfo; - type Preimages = Preimage; -} diff --git a/polkadot/runtime/polkadot/src/governance/origins.rs b/polkadot/runtime/polkadot/src/governance/origins.rs deleted file mode 100644 index 551e05e556d..00000000000 --- a/polkadot/runtime/polkadot/src/governance/origins.rs +++ /dev/null @@ -1,151 +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 . - -//! Custom origins for governance interventions. - -pub use pallet_custom_origins::*; - -#[frame_support::pallet] -pub mod pallet_custom_origins { - use crate::{Balance, DOLLARS, GRAND}; - use frame_support::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - pub struct Pallet(_); - - #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] - #[pallet::origin] - pub enum Origin { - /// Origin able to cancel slashes and manage minimum commission. - StakingAdmin, - /// Origin for spending up to $10,000,000 DOT from the treasury as well as generally - /// administering it. - Treasurer, - /// Origin for managing the composition of the fellowship. - FellowshipAdmin, - /// Origin for managing the registrar and permissioned HRMP channel operations. - GeneralAdmin, - /// Origin for starting auctions. - AuctionAdmin, - /// Origin able to force slot leases. - LeaseAdmin, - /// Origin able to cancel referenda. - ReferendumCanceller, - /// Origin able to kill referenda. - ReferendumKiller, - /// Origin able to spend around $250 from the treasury at once. - SmallTipper, - /// Origin able to spend around $1,000 from the treasury at once. - BigTipper, - /// Origin able to spend around $10,000 from the treasury at once. - SmallSpender, - /// Origin able to spend around $100,000 from the treasury at once. - MediumSpender, - /// Origin able to spend up to $1,000,000 DOT from the treasury at once. - BigSpender, - /// Origin able to dispatch a whitelisted call. - WhitelistedCaller, - } - - macro_rules! decl_unit_ensures { - ( $name:ident: $success_type:ty = $success:expr ) => { - pub struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - Origin::$name => Ok($success), - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(Origin::$name)) - } - } - }; - ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; - ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { - decl_unit_ensures! { $name: $success_type = $success } - decl_unit_ensures! { $( $rest )* } - }; - ( $name:ident, $( $rest:tt )* ) => { - decl_unit_ensures! { $name } - decl_unit_ensures! { $( $rest )* } - }; - () => {} - } - decl_unit_ensures!( - StakingAdmin, - Treasurer, - FellowshipAdmin, - GeneralAdmin, - AuctionAdmin, - LeaseAdmin, - ReferendumCanceller, - ReferendumKiller, - WhitelistedCaller, - ); - - macro_rules! decl_ensure { - ( - $vis:vis type $name:ident: EnsureOrigin { - $( $item:ident = $success:expr, )* - } - ) => { - $vis struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - $( - Origin::$item => Ok($success), - )* - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - // By convention the more privileged origins go later, so for greatest chance - // of success, we want the last one. - let _result: Result = Err(()); - $( - let _result: Result = Ok(O::from(Origin::$item)); - )* - _result - } - } - } - } - - decl_ensure! { - pub type Spender: EnsureOrigin { - SmallTipper = 250 * DOLLARS, - BigTipper = 1 * GRAND, - SmallSpender = 10 * GRAND, - MediumSpender = 100 * GRAND, - BigSpender = 1_000 * GRAND, - Treasurer = 10_000 * GRAND, - } - } -} diff --git a/polkadot/runtime/polkadot/src/governance/tracks.rs b/polkadot/runtime/polkadot/src/governance/tracks.rs deleted file mode 100644 index 2b6d470e516..00000000000 --- a/polkadot/runtime/polkadot/src/governance/tracks.rs +++ /dev/null @@ -1,319 +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 . - -//! Track configurations for governance. - -use super::*; - -const fn percent(x: i32) -> sp_arithmetic::FixedI64 { - sp_arithmetic::FixedI64::from_rational(x as u128, 100) -} -use pallet_referenda::Curve; -const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); -const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_STAKING_ADMIN: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); -const APP_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_FELLOWSHIP_ADMIN: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_GENERAL_ADMIN: Curve = - Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_GENERAL_ADMIN: Curve = - Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); -const APP_AUCTION_ADMIN: Curve = - Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); -const SUP_AUCTION_ADMIN: Curve = - Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); -const APP_LEASE_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_LEASE_ADMIN: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_REFERENDUM_CANCELLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_REFERENDUM_CANCELLER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_REFERENDUM_KILLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_REFERENDUM_KILLER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); -const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); -const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); -const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); -const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); -const SUP_SMALL_SPENDER: Curve = - Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); -const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); -const SUP_MEDIUM_SPENDER: Curve = - Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); -const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); -const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); -const APP_WHITELISTED_CALLER: Curve = - Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); -const SUP_WHITELISTED_CALLER: Curve = - Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); - -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15] = [ - ( - 0, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_ROOT, - min_support: SUP_ROOT, - }, - ), - ( - 1, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_WHITELISTED_CALLER, - min_support: SUP_WHITELISTED_CALLER, - }, - ), - ( - 10, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_STAKING_ADMIN, - min_support: SUP_STAKING_ADMIN, - }, - ), - ( - 11, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_TREASURER, - min_support: SUP_TREASURER, - }, - ), - ( - 12, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_LEASE_ADMIN, - min_support: SUP_LEASE_ADMIN, - }, - ), - ( - 13, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_FELLOWSHIP_ADMIN, - min_support: SUP_FELLOWSHIP_ADMIN, - }, - ), - ( - 14, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_GENERAL_ADMIN, - min_support: SUP_GENERAL_ADMIN, - }, - ), - ( - 15, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_AUCTION_ADMIN, - min_support: SUP_AUCTION_ADMIN, - }, - ), - ( - 20, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_REFERENDUM_CANCELLER, - min_support: SUP_REFERENDUM_CANCELLER, - }, - ), - ( - 21, - pallet_referenda::TrackInfo { - 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, - min_approval: APP_REFERENDUM_KILLER, - min_support: SUP_REFERENDUM_KILLER, - }, - ), - ( - 30, - pallet_referenda::TrackInfo { - name: "small_tipper", - max_deciding: 200, - decision_deposit: 1 * DOLLARS, - prepare_period: 1 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 10 * MINUTES, - min_enactment_period: 1 * MINUTES, - min_approval: APP_SMALL_TIPPER, - min_support: SUP_SMALL_TIPPER, - }, - ), - ( - 31, - 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, - min_approval: APP_BIG_TIPPER, - min_support: SUP_BIG_TIPPER, - }, - ), - ( - 32, - 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, - min_approval: APP_SMALL_SPENDER, - min_support: SUP_SMALL_SPENDER, - }, - ), - ( - 33, - 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, - min_approval: APP_MEDIUM_SPENDER, - min_support: SUP_MEDIUM_SPENDER, - }, - ), - ( - 34, - 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, - min_approval: APP_BIG_SPENDER, - min_support: SUP_BIG_SPENDER, - }, - ), -]; - -pub struct TracksInfo; -impl pallet_referenda::TracksInfo for TracksInfo { - type Id = u16; - type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - &TRACKS_DATA[..] - } - fn track_for(id: &Self::RuntimeOrigin) -> Result { - if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { - match system_origin { - frame_system::RawOrigin::Root => Ok(0), - _ => Err(()), - } - } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { - match custom_origin { - origins::Origin::WhitelistedCaller => Ok(1), - // General admin - origins::Origin::StakingAdmin => Ok(10), - origins::Origin::Treasurer => Ok(11), - origins::Origin::LeaseAdmin => Ok(12), - origins::Origin::FellowshipAdmin => Ok(13), - origins::Origin::GeneralAdmin => Ok(14), - origins::Origin::AuctionAdmin => Ok(15), - // Referendum admins - origins::Origin::ReferendumCanceller => Ok(20), - origins::Origin::ReferendumKiller => Ok(21), - // Limited treasury spenders - origins::Origin::SmallTipper => Ok(30), - origins::Origin::BigTipper => Ok(31), - origins::Origin::SmallSpender => Ok(32), - origins::Origin::MediumSpender => Ok(33), - origins::Origin::BigSpender => Ok(34), - } - } else { - Err(()) - } - } -} -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs deleted file mode 100644 index 0b2dd12b154..00000000000 --- a/polkadot/runtime/polkadot/src/lib.rs +++ /dev/null @@ -1,2633 +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::v7 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, - genesis_builder_helper::{build_config, create_default_config}, - parameter_types, - traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, - 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() } -} - -/// 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 = 0; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = EverythingBut; - 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) - } - } - - 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)] -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 bb27fdc880c..00000000000 --- 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 109c8288421..00000000000 --- 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 e6ece50fc8e..00000000000 --- 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 596b594c937..00000000000 --- 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 47decc88d73..00000000000 --- 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_balances.rs b/polkadot/runtime/polkadot/src/weights/pallet_balances.rs deleted file mode 100644 index 37471808261..00000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_balances.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 . - -//! 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: `[]` -//! 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_balances -// --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_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: 56_740_000 picoseconds. - Weight::from_parts(57_361_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_767_000 picoseconds. - Weight::from_parts(43_195_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: 17_405_000 picoseconds. - Weight::from_parts(17_754_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: 24_580_000 picoseconds. - Weight::from_parts(25_063_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: 59_923_000 picoseconds. - Weight::from_parts(60_797_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: 52_587_000 picoseconds. - Weight::from_parts(53_496_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: 20_257_000 picoseconds. - Weight::from_parts(20_977_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:999 w:999) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (135 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 19_254_000 picoseconds. - Weight::from_parts(19_508_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())) - .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/polkadot/src/weights/pallet_bounties.rs b/polkadot/runtime/polkadot/src/weights/pallet_bounties.rs deleted file mode 100644 index 62a41783290..00000000000 --- 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 0e885883f09..00000000000 --- 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 0d75865bf2e..00000000000 --- 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 07fb1209b0a..00000000000 --- 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 ce42464c292..00000000000 --- 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 069b10a2bcc..00000000000 --- 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 f16da40e8ec..00000000000 --- 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 e93de0c14c1..00000000000 --- 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 38771e04cb5..00000000000 --- 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 8ec244ea127..00000000000 --- 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 93264c0c699..00000000000 --- 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 94f2285efc2..00000000000 --- 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 a4e5ce4a7bb..00000000000 --- 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 b0b9776b011..00000000000 --- 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 70df8a78d4f..00000000000 --- 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 7273389a080..00000000000 --- 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 1233133dfa3..00000000000 --- 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 a283f09eae5..00000000000 --- 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 662b610f86b..00000000000 --- 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 7f6fb0419c7..00000000000 --- 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 79ad62954ec..00000000000 --- 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 53f470ef534..00000000000 --- 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 80a60467eda..00000000000 --- 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_timestamp.rs b/polkadot/runtime/polkadot/src/weights/pallet_timestamp.rs deleted file mode 100644 index 27d92d609fd..00000000000 --- a/polkadot/runtime/polkadot/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("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_timestamp -// --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_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: `345` - // Estimated: `1493` - // Minimum execution time: 10_314_000 picoseconds. - Weight::from_parts(10_644_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` - // Estimated: `0` - // Minimum execution time: 4_852_000 picoseconds. - Weight::from_parts(5_026_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} 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 62e08e017a8..00000000000 --- 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 669bfdeb7cf..00000000000 --- 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 1315ad6f8c4..00000000000 --- 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 916ca4bf6b9..00000000000 --- 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 fd3831a3ef5..00000000000 --- 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 abbd5b1f2b9..00000000000 --- 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 8fdac199062..00000000000 --- 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 b16ed97bc3b..00000000000 --- 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 f9b84ff2f3e..00000000000 --- 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 d176b83a648..00000000000 --- 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 7197c8721d8..00000000000 --- 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 39b0d893edb..00000000000 --- 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 2746924dc87..00000000000 --- 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 eda2f14214b..00000000000 --- 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 73a08d33eed..00000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs +++ /dev/null @@ -1,337 +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)) - } - /// 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/polkadot/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index c1e89a1ea98..00000000000 --- 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 87e60aaeb24..00000000000 --- 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 06f67211ead..00000000000 --- 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 70eb764305e..00000000000 --- 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 acef102b446..00000000000 --- 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 038e9f17361..00000000000 --- 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 0b61e7cd8d1..00000000000 --- 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 1110c0d8eb9..00000000000 --- a/polkadot/runtime/polkadot/src/xcm_config.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 . - -//! 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, DescribeBodyTerminal, - DescribeFamily, HashedDescription, 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, - // Allow governance body to be used as a sovereign account. - HashedDescription>, -); - -/// 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 49a4a4e8299..ab9b2f11acf 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -308,3 +308,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/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index de9d6666059..c9721935c32 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -332,3 +332,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/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index d270cabd3f0..873b0c0030a 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -12,5 +12,3 @@ 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 6d0b0e19e89..511980518c0 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 cb9547ac7dc..c59d354dc4a 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" } 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 6fb66ab2160..1b7b6c5b694 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; - }, } } -- GitLab From ef3adf9a019aacaae7d19541dad0de9db167ea5a Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Fri, 29 Sep 2023 13:44:28 +0200 Subject: [PATCH 236/633] Revert "fix(review-bot): pull secrets from `master` environment" (#1748) This reverts commit b749ff226fe9f775282836acc6e7256b8021ef9d (#1745). --- .github/workflows/review-bot.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index 89c0f509bf1..aeb33b5da3d 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -16,7 +16,6 @@ permissions: jobs: review-approvals: runs-on: ubuntu-latest - environment: master steps: - name: Generate token id: team_token -- GitLab From d8d90a82a7a81edc0f3a36a94fbdbd1602a9e31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Fri, 29 Sep 2023 15:39:13 +0200 Subject: [PATCH 237/633] Enable mocking contracts (#1331) # Description This PR introduces two changes: - the previous `Tracing` trait has been modified to accept contract address instead of code hash (seems to be way more convenient) - a new trait `CallInterceptor` that allows intercepting contract calls; in particular the default implementation for `()` will just proceed in a standard way (after compilation optimizations, there will be no footprint of that); however, implementing type might decide to mock invocation and return `ExecResult` instead Note: one might try merging `before_call` and `intercept_call`. However, IMHO this would be bad, since it would mix two completely different abstractions - tracing without any effects and actual intervention into execution process. This will unblock working on mocking contracts utility in drink and similar tools (https://github.com/Cardinal-Cryptography/drink/issues/33) # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works (if applicable) --- substrate/frame/contracts/src/debug.rs | 56 +++++++-- substrate/frame/contracts/src/exec.rs | 17 +-- .../frame/contracts/src/tests/test_debug.rs | 115 ++++++++++++++---- 3 files changed, 148 insertions(+), 40 deletions(-) diff --git a/substrate/frame/contracts/src/debug.rs b/substrate/frame/contracts/src/debug.rs index d92379a806d..e22a841e6fb 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 f93e7a2b21a..9090aa9cb11 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/tests/test_debug.rs b/substrate/frame/contracts/src/tests/test_debug.rs index c7862c7f03d..2d7ed474365 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, + ); + }); +} -- GitLab From 0691c91e1558f235081475bfd60ce71035f272a5 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 29 Sep 2023 17:58:16 +0300 Subject: [PATCH 238/633] Move import queue from `ChainSync` to `SyncingEngine` (#1736) This PR is part of [Sync 2.0](https://github.com/paritytech/polkadot-sdk/issues/534) refactoring aimed at making `ChainSync` a pure state machine. Resolves https://github.com/paritytech/polkadot-sdk/issues/501. --- substrate/client/network/common/src/sync.rs | 17 +- substrate/client/network/sync/src/engine.rs | 77 ++++-- substrate/client/network/sync/src/lib.rs | 247 ++++++++------------ substrate/client/network/sync/src/mock.rs | 6 +- 4 files changed, 176 insertions(+), 171 deletions(-) diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index 8ef0fafa1c7..4ca21221f87 100644 --- a/substrate/client/network/common/src/sync.rs +++ b/substrate/client/network/common/src/sync.rs @@ -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, @@ -309,6 +316,7 @@ pub trait ChainSync: Send { /// Handle a new connected peer. /// /// Call this method whenever we connect to a new peer. + #[must_use] fn new_peer( &mut self, who: PeerId, @@ -340,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, @@ -350,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, @@ -379,7 +389,8 @@ 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; diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 8b8874ad4eb..1a383cdde47 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -28,7 +28,8 @@ use crate::{ schema::v1::{StateRequest, StateResponse}, service::{self, chain_sync::ToServiceCommand}, warp::WarpSyncParams, - BlockRequestEvent, ChainSync, ClientError, SyncingService, + BlockRequestAction, ChainSync, ClientError, ImportBlocksAction, ImportJustificationsAction, + OnBlockResponse, SyncingService, }; use codec::{Decode, Encode}; @@ -41,7 +42,8 @@ use futures_timer::Delay; 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}; @@ -135,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 { @@ -164,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)? + }, }) } } @@ -311,6 +329,9 @@ pub struct SyncingEngine { /// Protocol name used to send out warp sync requests warp_sync_protocol_name: Option, + + /// Handle to import queue. + import_queue: Box>, } impl SyncingEngine @@ -436,9 +457,7 @@ where max_parallel_downloads, max_blocks_per_request, warp_sync_config, - metrics_registry, network_service.clone(), - import_queue, )?; let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); @@ -501,6 +520,7 @@ where block_downloader, state_request_protocol_name, warp_sync_protocol_name, + import_queue, }, SyncingService::new(tx, num_connected, is_major_syncing), block_announce_config, @@ -728,13 +748,13 @@ where ToServiceCommand::BlocksProcessed(imported, count, results) => { for result in self.chain_sync.on_blocks_processed(imported, count, results) { match result { - Ok(event) => match event { - BlockRequestEvent::SendRequest { peer_id, request } => { + 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); }, - BlockRequestEvent::RemoveStale { peer_id } => { + BlockRequestAction::RemoveStale { peer_id } => { self.pending_responses.remove(&peer_id); }, }, @@ -922,7 +942,10 @@ 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() @@ -1181,10 +1204,14 @@ where PeerRequest::Block(req) => { match self.block_downloader.block_response_into_blocks(&req, resp) { Ok(blocks) => { - if let Some((peer_id, new_req)) = - self.chain_sync.on_block_response(peer_id, req, blocks) - { - self.send_block_request(peer_id, new_req); + 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)) => { @@ -1230,7 +1257,11 @@ where }, }; - self.chain_sync.on_state_response(peer_id, response); + 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)); @@ -1337,4 +1368,24 @@ where }, } } + + /// 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 ff00e8f90f8..10eaa245051 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -40,11 +40,8 @@ use extra_requests::ExtraRequests; use libp2p::PeerId; use log::{debug, error, info, trace, warn}; -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_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; use sc_network::types::ProtocolName; use sc_network_common::sync::{ message::{ @@ -52,8 +49,9 @@ use sc_network_common::sync::{ FromBlock, }, warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, - OpaqueStateRequest, OpaqueStateResponse, PeerInfo, SyncMode, SyncState, SyncStatus, + 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}; @@ -200,45 +198,42 @@ 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, } -/// An event used to notify [`engine::SyncingEngine`] if we want to perform a block request -/// or drop an obsolete pending response. -enum BlockRequestEvent { +/// 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. pub struct ChainSync { @@ -288,10 +283,6 @@ pub struct ChainSync { network_service: service::network::NetworkServiceHandle, /// Protocol name used for block announcements block_announce_protocol_name: ProtocolName, - /// 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 @@ -449,6 +440,7 @@ where self.peers.len() } + #[must_use] fn new_peer( &mut self, who: PeerId, @@ -642,6 +634,7 @@ where .extend(peers); } + #[must_use] fn on_block_data( &mut self, who: &PeerId, @@ -903,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, @@ -952,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 }) } } @@ -1093,7 +1087,8 @@ 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) @@ -1107,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 { @@ -1143,9 +1135,7 @@ where 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>, ) -> Result { let mut sync = Self { client, @@ -1169,21 +1159,6 @@ where warp_sync_config, warp_sync_target_block_header: None, block_announce_protocol_name, - 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 - }, }; sync.reset_sync_start_point()?; @@ -1229,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 { @@ -1260,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) { @@ -1311,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}"); @@ -1338,9 +1314,9 @@ where // handle peers that were in other states. 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(BlockRequestEvent::RemoveStale { peer_id })), + Ok(None) => Some(Ok(BlockRequestAction::RemoveStale { peer_id })), // update the request if the new one is available - Ok(Some(request)) => Some(Ok(BlockRequestEvent::SendRequest { peer_id, request })), + 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)), } @@ -1491,12 +1467,14 @@ where None } + /// Process blocks received in a response. + #[must_use] pub(crate) fn on_block_response( &mut self, peer_id: PeerId, request: BlockRequest, blocks: Vec>, - ) -> Option<(PeerId, BlockRequest)> { + ) -> OnBlockResponse { let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( @@ -1521,44 +1499,53 @@ 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)) => Some((peer, req)), - 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 }, } } } - pub fn on_state_response(&mut self, peer_id: PeerId, response: OpaqueStateResponse) { + /// Process state received in a response. + #[must_use] + pub fn on_state_response( + &mut self, + peer_id: PeerId, + response: OpaqueStateResponse, + ) -> Option> { match self.on_state_data(&peer_id, response) { - Ok(OnStateData::Import(origin, block)) => self.import_blocks(origin, vec![block]), - Ok(OnStateData::Continue) => {}, + Ok(OnStateData::Import(origin, block)) => + Some(ImportBlocksAction { origin, blocks: vec![block] }), + Ok(OnStateData::Continue) => None, Err(BadPeer(id, repu)) => { self.network_service .disconnect_peer(id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(id, repu); + None }, } } @@ -1897,39 +1884,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. 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(); @@ -2454,7 +2420,6 @@ 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( @@ -2464,9 +2429,7 @@ mod test { 1, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -2515,7 +2478,6 @@ 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(); @@ -2526,9 +2488,7 @@ mod test { 1, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -2583,9 +2543,9 @@ mod test { // which should make us send out block requests to the first two peers assert!(block_requests.map(|r| r.unwrap()).all(|event| match event { - BlockRequestEvent::SendRequest { peer_id, .. } => + BlockRequestAction::SendRequest { peer_id, .. } => peer_id == peer_id1 || peer_id == peer_id2, - BlockRequestEvent::RemoveStale { .. } => false, + BlockRequestAction::RemoveStale { .. } => false, })); // peer 3 should be unaffected it was downloading finality data @@ -2686,7 +2646,6 @@ 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(); @@ -2697,9 +2656,7 @@ mod test { 5, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -2761,7 +2718,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); @@ -2769,14 +2728,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 { @@ -2806,7 +2767,6 @@ 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(); @@ -2818,9 +2778,7 @@ mod test { 5, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -2853,7 +2811,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; @@ -2909,7 +2867,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); @@ -2936,7 +2894,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()); @@ -2970,9 +2927,7 @@ mod test { 5, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -3030,7 +2985,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; @@ -3073,7 +3028,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()); @@ -3107,9 +3061,7 @@ mod test { 5, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -3168,7 +3120,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; @@ -3233,7 +3185,6 @@ 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()); @@ -3246,9 +3197,7 @@ mod test { 1, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -3264,14 +3213,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()); @@ -3286,9 +3234,7 @@ mod test { 1, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -3323,7 +3269,6 @@ 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( @@ -3333,9 +3278,7 @@ mod test { 1, 64, None, - None, chain_sync_network_handle, - import_queue, ) .unwrap(); @@ -3394,10 +3337,10 @@ mod test { let request_events = sync.restart().collect::>(); for event in request_events.iter() { match event.as_ref().unwrap() { - BlockRequestEvent::RemoveStale { peer_id } => { + BlockRequestAction::RemoveStale { peer_id } => { pending_responses.remove(&peer_id); }, - BlockRequestEvent::SendRequest { 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); @@ -3406,8 +3349,8 @@ mod test { } assert!(request_events.iter().any(|event| { match event.as_ref().unwrap() { - BlockRequestEvent::RemoveStale { .. } => false, - BlockRequestEvent::SendRequest { peer_id, .. } => peer_id == &peers[0], + BlockRequestAction::RemoveStale { .. } => false, + BlockRequestAction::SendRequest { peer_id, .. } => peer_id == &peers[0], } })); @@ -3417,7 +3360,7 @@ mod test { sync.peers.get(&peers[1]).unwrap().state, PeerSyncState::DownloadingJustification(b1_hash), ); - sync.peer_disconnected(&peers[1]); + let _ = sync.peer_disconnected(&peers[1]); pending_responses.remove(&peers[1]); assert_eq!(pending_responses.len(), 0); } diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index b51eec8d149..ed7c647c797 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -25,8 +25,8 @@ 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}; @@ -78,7 +78,7 @@ 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; } } -- GitLab From f820dc0a1fde925b11d1b3f4d18dcc0e7a0c72a1 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Fri, 29 Sep 2023 17:48:40 +0200 Subject: [PATCH 239/633] [NPoS] Fix for Reward Deficit in the pool (#1255) closes https://github.com/paritytech/polkadot-sdk/issues/158. partially addresses https://github.com/paritytech/polkadot-sdk/issues/226. 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. ## Notable changes - New call `adjust_pool_deposit`: Allows to top up the deficit or withdraw the excess deposited funds to the pool. - Uses Fungible trait (instead of Currency trait). Since NP was not doing any locking/reserving previously, no migration is needed for this. - One time migration of freezing ED from each of the existing pools (not very PoV friendly but fine for relay chain). --- polkadot/runtime/westend/src/lib.rs | 8 +- .../src/weights/pallet_nomination_pools.rs | 842 +++++---- prdoc/pr_1255.prdoc | 22 + substrate/bin/node/runtime/src/lib.rs | 5 +- .../nomination-pools/benchmarking/src/lib.rs | 59 +- .../nomination-pools/benchmarking/src/mock.rs | 7 +- substrate/frame/nomination-pools/src/lib.rs | 249 ++- .../frame/nomination-pools/src/migration.rs | 771 ++++---- substrate/frame/nomination-pools/src/mock.rs | 68 +- substrate/frame/nomination-pools/src/tests.rs | 493 +++-- .../frame/nomination-pools/src/weights.rs | 1650 +++++++++-------- .../nomination-pools/test-staking/src/mock.rs | 7 +- .../frame/support/src/traits/tokens/misc.rs | 7 +- 13 files changed, 2355 insertions(+), 1833 deletions(-) create mode 100644 prdoc/pr_1255.prdoc diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index b1231a5d95f..34f116eb9f0 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -292,9 +292,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! { @@ -1311,6 +1311,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; @@ -1398,7 +1399,7 @@ 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, @@ -1505,6 +1506,7 @@ 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, ); } diff --git a/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs b/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs index 9d43eb24989..49bc687a3e4 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/prdoc/pr_1255.prdoc b/prdoc/pr_1255.prdoc new file mode 100644 index 00000000000..793b5c3c859 --- /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/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 2fcb20ad8da..f018639b732 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -521,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>; } @@ -882,6 +882,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; diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 45f0ca0ecfe..fc86a6f56c0 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 2d75df63b51..1e6a5c24999 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 485cdada717..2ec9b537d32 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; @@ -1005,10 +1008,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()) } @@ -1201,8 +1209,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 @@ -1300,13 +1308,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 +1397,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, + ) } } @@ -1487,6 +1507,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 +1525,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(6); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1518,8 +1539,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. /// @@ -1685,6 +1710,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 +1796,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] @@ -1845,6 +1875,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 +1900,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 @@ -2140,7 +2180,7 @@ pub mod pallet { ensure!(!withdrawn_points.is_empty(), Error::::CannotWithdrawAny); // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the - // `transferrable_balance` is correct. + // `transferable_balance` is correct. let stash_killed = T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; @@ -2175,13 +2215,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 +2277,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 +2671,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 +2735,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 +2745,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. @@ -2838,7 +2913,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 +2921,6 @@ impl Pallet { pool_id: member.pool_id, payout: pending_rewards, }); - Ok(pending_rewards) } @@ -2881,13 +2955,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 +3077,7 @@ impl Pallet { &bonded_pool.reward_account(), &payee, commission, - ExistenceRequirement::KeepAlive, + Preservation::Preserve, )?; // Add pending commission to total claimed counter. @@ -3007,7 +3085,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 +3106,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 +3220,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(), ) } @@ -3135,9 +3267,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 = {:?}", @@ -3199,9 +3330,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 diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 2ae4cd1b868..606123daa9c 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -23,55 +23,251 @@ 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::*; + + /// Wrapper over `MigrateToV6` with convenience version checks. + pub type V5toV6 = frame_support::migrations::VersionedMigration< + 5, + 6, + v6::MigrateToV6, + crate::pallet::Pallet, + ::DbWeight, + >; +} + +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 +279,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 +418,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 +570,7 @@ pub mod v2 { &reward_account, &who, last_claim, - ExistenceRequirement::KeepAlive, + Preservation::Preserve, ); if let Err(reason) = outcome { @@ -304,7 +595,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 +621,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 +640,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 +757,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 28c24c42803..3884518a992 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -17,7 +17,7 @@ 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; @@ -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 { @@ -51,8 +52,8 @@ parameter_types! { 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(); @@ -221,8 +222,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 +252,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 +270,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 +358,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 +442,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 d0fe4e40a18..67183e25689 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] @@ -99,7 +99,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()); }) } @@ -298,30 +298,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,7 +635,7 @@ 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)); // When @@ -525,7 +663,7 @@ mod join { StakingMock::set_bonded_balance(Pools::create_bonded_account(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 @@ -661,12 +799,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 +826,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 +892,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 +916,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 +929,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 +942,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 +958,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 +971,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 +988,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 +1001,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 +1020,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 +1037,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 +1050,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 +1063,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 +1098,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 +1148,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 +1198,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 +1405,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 +1448,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 +1501,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 +1554,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 +1573,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 +1607,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 +1659,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 +1704,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 +1773,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 +1848,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 +1861,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 +1904,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 +1982,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 +2201,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 +2253,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 +2269,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 +2318,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 +2340,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); }) } } @@ -2530,11 +2668,11 @@ mod unbond { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); // Given a slash from 600 -> 100 StakingMock::set_bonded_balance(default_bonded_account(), 100); // 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)); @@ -2574,7 +2712,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 +2741,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 +2782,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![ @@ -3173,14 +3311,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 +3331,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 +3344,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!( @@ -3240,12 +3369,12 @@ mod pool_withdraw_unbonded { #[test] fn pool_withdraw_unbonded_works() { ExtBuilder::default().build_and_execute(|| { - // Given 10 unbond'ed directly against the pool account + // Given 10 unbonded 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_eq!(Currency::free_balance(&default_bonded_account()), 10); // When assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); @@ -3253,7 +3382,7 @@ mod pool_withdraw_unbonded { // 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); + assert_eq!(Currency::free_balance(&default_bonded_account()), 10); }); } } @@ -3274,7 +3403,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); @@ -3293,9 +3422,9 @@ mod withdraw_unbonded { let mut x = UnbondingBalanceMap::get(); *x.get_mut(&default_bonded_account()).unwrap() /= 5; UnbondingBalanceMap::set(&x); - Balances::make_free_balance_be( + Currency::set_balance( &default_bonded_account(), - Balances::free_balance(&default_bonded_account()) / 2, // 300 + Currency::free_balance(&default_bonded_account()) / 2, // 300 ); StakingMock::set_bonded_balance( default_bonded_account(), @@ -3340,7 +3469,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 }] ); // When @@ -3407,6 +3536,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 } ] ); @@ -3423,7 +3553,7 @@ 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); + Currency::set_balance(&default_bonded_account(), 300); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300)); assert_ok!(fully_unbond_permissioned(40)); @@ -3454,7 +3584,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 +3647,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 +3666,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 +3677,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 +3697,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 +3804,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 +3840,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 +3851,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(), @@ -4258,20 +4389,21 @@ 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!(!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(), @@ -4280,7 +4412,7 @@ mod create { 789 )); - assert_eq!(Balances::free_balance(&11), 0); + assert_eq!(Currency::free_balance(&11), 0); assert_eq!( PoolMembers::::get(11).unwrap(), PoolMember { @@ -4316,6 +4448,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 +4521,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 +4540,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 +4551,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 +4580,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 @@ -4569,7 +4710,7 @@ mod set_state { 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)); @@ -4693,18 +4834,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 +4862,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 +4878,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 +4917,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 +4927,15 @@ 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); // 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); // 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 +4944,7 @@ 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); // 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 +4968,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 +4978,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 +4992,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 +5013,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 +5248,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 +5295,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 +5317,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. @@ -5219,7 +5360,7 @@ mod reward_counter_precision { // 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 +5389,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 +5457,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 +5743,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 +6493,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 +6707,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 +6750,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 +6808,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, diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index eb33c9adbbf..2cb414fc2a0 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 02c253e62c0..54f578f861e 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/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index 84bbe3e8d9c..e8587be1017 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 { -- GitLab From 9485b0b4921a0ed21ef6cf21cf1270aa91cfc94e Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 29 Sep 2023 22:33:26 +0200 Subject: [PATCH 240/633] Point documentation links to monorepo (#1741) --- bridges/modules/parachains/README.md | 10 +++++----- cumulus/docker/scripts/build_docker.sh | 2 +- cumulus/docs/release.md | 6 +++--- cumulus/parachain-template/README.md | 4 ++-- cumulus/parachain-template/node/src/command.rs | 4 ++-- .../emulated/common/src/impls.rs | 4 ++-- .../integration-tests/emulated/common/src/lib.rs | 2 +- .../contracts/contracts-rococo/README.md | 7 ++++--- cumulus/polkadot-parachain/src/command.rs | 4 ++-- cumulus/test/service/src/cli.rs | 4 ++-- docker/dockerfiles/collator_injected.Dockerfile | 4 ++-- docker/dockerfiles/docker-compose.yml | 8 ++++---- docker/dockerfiles/malus_injected.Dockerfile | 4 ++-- ...dockerfile => parachain-registrar.Dockerfile} | 2 +- ...-parachain-debug_unsigned_injected.Dockerfile | 4 ++-- ...ile => polkadot-parachain_builder.Dockerfile} | 6 +++--- .../polkadot/polkadot_builder.Dockerfile | 4 ++-- .../polkadot/polkadot_injected_debian.Dockerfile | 4 ++-- .../polkadot/polkadot_injected_debug.Dockerfile | 4 ++-- .../polkadot_injected_release.Dockerfile | 4 ++-- docker/dockerfiles/substrate_injected.Dockerfile | 2 +- ...erfile => test-parachain-collator.Dockerfile} | 2 +- .../test-parachain_injected.Dockerfile | 4 ++-- docs/DOCUMENTATION_GUIDELINES.md | 2 +- docs/container.md | 16 ++++++++-------- polkadot/cli/src/command.rs | 2 +- .../test-parachains/adder/collator/src/cli.rs | 2 +- .../test-parachains/undying/collator/src/cli.rs | 2 +- polkadot/roadmap/parachains.md | 2 +- substrate/bin/node-template/README.md | 8 ++++---- substrate/bin/node-template/docs/rust-setup.md | 2 +- substrate/bin/node/cli/src/command.rs | 2 +- substrate/client/consensus/beefy/README.md | 2 +- substrate/docker/substrate_builder.Dockerfile | 4 ++-- substrate/docs/node-template-release.md | 2 +- substrate/frame/bags-list/src/lib.rs | 2 +- substrate/frame/contracts/proc-macro/src/lib.rs | 2 +- substrate/frame/examples/basic/src/lib.rs | 2 +- substrate/frame/fast-unstake/src/lib.rs | 2 +- substrate/frame/scheduler/src/lib.rs | 2 +- substrate/frame/timestamp/README.md | 2 +- .../primitives/consensus/sassafras/Cargo.toml | 2 +- .../primitives/consensus/sassafras/README.md | 2 +- substrate/src/lib.rs | 4 ++-- 44 files changed, 83 insertions(+), 82 deletions(-) rename docker/dockerfiles/{parachain-registrar.dockerfile => parachain-registrar.Dockerfile} (93%) rename docker/dockerfiles/polkadot-parachain/{polkadot-parachain_builder.Containerfile => polkadot-parachain_builder.Dockerfile} (85%) rename docker/dockerfiles/{test-parachain-collator.dockerfile => test-parachain-collator.Dockerfile} (96%) diff --git a/bridges/modules/parachains/README.md b/bridges/modules/parachains/README.md index d3f52c791ab..9ca60803834 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/cumulus/docker/scripts/build_docker.sh b/cumulus/docker/scripts/build_docker.sh index ba445449301..752d6bd00fc 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 38d1915013b..8302b7b9b7f 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/parachain-template/README.md b/cumulus/parachain-template/README.md index 2d71bbd71f3..01e9cc26d9a 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/src/command.rs b/cumulus/parachain-template/node/src/command.rs index 7acfb0c2035..4dd8463f6be 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/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index eed61d94171..024ae65c51e 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -80,7 +80,7 @@ impl From for LaneIdWrapper { type BridgeHubRococoRuntime = ::Runtime; type BridgeHubWococoRuntime = ::Runtime; -// TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged +// TODO: uncomment when https://github.com/paritytech/polkadot-sdk/pull/1352 is merged // type BridgeHubPolkadotRuntime = ::Runtime; // type BridgeHubKusamaRuntime = ::Runtime; @@ -89,7 +89,7 @@ pub type RococoWococoMessageHandler = pub type WococoRococoMessageHandler = BridgeHubMessageHandler; -// TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged +// TODO: uncomment when https://github.com/paritytech/polkadot-sdk/pull/1352 is merged // pub type PolkadotKusamaMessageHandler // = BridgeHubMessageHandler; // pub type KusamaPolkadotMessageHandler diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index dd971befa7c..2c9581c3a18 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -248,7 +248,7 @@ decl_test_bridges! { target = BridgeHubRococo, handler = WococoRococoMessageHandler } - // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged + // TODO: uncomment when https://github.com/paritytech/polkadot-sdk/pull/1352 is merged // pub struct PolkadotKusamaMockBridge { // source = BridgeHubPolkadot, // target = BridgeHubKusama, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md b/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md index 387bb24bb0e..10df15ba727 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/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 32e363aff74..b96163f63e4 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -332,7 +332,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 +368,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/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index f295192c3b1..9235a0c45c5 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/docker/dockerfiles/collator_injected.Dockerfile b/docker/dockerfiles/collator_injected.Dockerfile index 0c9ea1e0ca8..999203b93f0 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 8dc8540353f..0e34e54562a 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 762a2e442c8..dd8702ea101 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 00908395101..594bff44906 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 75cc2b9e629..f249612e776 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 4d110d6af47..b56b8c1a1ef 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 f8dc374a14a..7e460bb22e8 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 7ad092476fe..529c82e6af6 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 09fc4f764d0..55d23f3a805 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 diff --git a/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile index c13f2db982a..2632968f8a2 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 2d825f5c6bb..47a917013a8 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 0d56949152e..116520284dd 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 e5d0df7aad6..317312a18bf 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/DOCUMENTATION_GUIDELINES.md b/docs/DOCUMENTATION_GUIDELINES.md index dbb4298d50f..29029b894c7 100644 --- a/docs/DOCUMENTATION_GUIDELINES.md +++ b/docs/DOCUMENTATION_GUIDELINES.md @@ -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/container.md b/docs/container.md index afd3b27957c..dd44b31bfe9 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/cli/src/command.rs b/polkadot/cli/src/command.rs index a7f429d6eca..11c9014d1d6 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -62,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 { diff --git a/polkadot/parachain/test-parachains/adder/collator/src/cli.rs b/polkadot/parachain/test-parachains/adder/collator/src/cli.rs index 9a865d75b60..14b25970683 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/src/cli.rs b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs index ab37fe20eeb..cd16133dbf1 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/roadmap/parachains.md b/polkadot/roadmap/parachains.md index 77e97433676..5d6fafffd39 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/substrate/bin/node-template/README.md b/substrate/bin/node-template/README.md index a07328df88c..6390c9524ce 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 38fddd5026b..00089ab6a06 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/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 8fb413dba17..6bd8b76581a 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 { diff --git a/substrate/client/consensus/beefy/README.md b/substrate/client/consensus/beefy/README.md index d9099dc7c66..1a5a9667fdb 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/docker/substrate_builder.Dockerfile b/substrate/docker/substrate_builder.Dockerfile index 03b6b46caf4..b37acf4d201 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/node-template-release.md b/substrate/docs/node-template-release.md index 0acaf3bdc61..2536d186b2d 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/bags-list/src/lib.rs b/substrate/frame/bags-list/src/lib.rs index a5d3257b734..8e3d4cc1f01 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/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index b31403c29ad..ad9cd2dadec 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/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index 31d20e07f5f..5eff74922ca 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/fast-unstake/src/lib.rs b/substrate/frame/fast-unstake/src/lib.rs index 39783271e65..2b99ad79a7d 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/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 532ffe7bd71..e94f154eee3 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 diff --git a/substrate/frame/timestamp/README.md b/substrate/frame/timestamp/README.md index 69dba60550e..55c8343187b 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/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index e848f280f5d..cb887fd40fe 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 diff --git a/substrate/primitives/consensus/sassafras/README.md b/substrate/primitives/consensus/sassafras/README.md index 5024d1bf700..b0f3685494e 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/src/lib.rs b/substrate/src/lib.rs index 16a60677896..409515ea505 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? -- GitLab From 7d4f82968cdab8fc5b104d9f863f8ab1ac56a4ca Mon Sep 17 00:00:00 2001 From: Muharem Date: Fri, 29 Sep 2023 23:47:17 +0200 Subject: [PATCH 241/633] frame-support: `RuntimeDebug\Eq\PartialEq` impls for `Imbalance` (#1717) Derive `RuntimeDebug\Eq\PartialEq` but do not bound any generics. This achieved by using their equivalent no bound versions: `EqNoBound\PartialEqNoBound\RuntimeDebugNoBound`. Deriving with `Debug`, `Eq`, and `PartialEq` for the `Debt` and `Credit` type aliases of `Imbalance` is not feasible due to the `OnDrop` and `OppositeOnDrop` generic types lacking implementations of the same traits. This absence posed challenges in testing and any scenarios that demanded the traits implementations for the type. --- .../frame/support/src/traits/tokens/fungible/imbalance.rs | 5 +++-- .../frame/support/src/traits/tokens/fungibles/imbalance.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index de85924a4de..32a63fd25b2 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, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 1668268ea2d..9f660a5f168 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, -- GitLab From 8fe947af602965eb7e7895f7d34b54356823804a Mon Sep 17 00:00:00 2001 From: yjh Date: Sat, 30 Sep 2023 12:52:47 +0800 Subject: [PATCH 242/633] improve service error (#1734) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- substrate/client/service/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/service/src/error.rs b/substrate/client/service/src/error.rs index c871342c771..c0a2adf2d19 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}")] -- GitLab From e8baac7848c1ce075efad4793b6afc92b6f66106 Mon Sep 17 00:00:00 2001 From: Piet <75956460+PieWol@users.noreply.github.com> Date: Sun, 1 Oct 2023 03:36:48 +0200 Subject: [PATCH 243/633] Tvl pool staking (#1322) What does this PR do? - Introduced the TotalValueLocked storage for nomination-pools. - introduced a slashing api in mock.rs - additional test for tracking a slashing event towards a pool without sub-pools - migration for the nomination-pools (V6 to V7) with `VersionedMigration` Why are these changes needed? this is the continuation of the work by @kianenigma in this [PR](https://github.com/paritytech/substrate/pull/13319) How were these changes implemented and what do they affect? - It's an extra StorageValue that's modified whenever funds flow in or out of staking for any of the `bonded_account` of `BondedPools` - The `PoolSlashed`event is now emitted even when no `SubPools` are found Closes https://github.com/paritytech/polkadot-sdk/issues/155 KSM: HHEEgVzcqL3kCXgsxSfJMbsTy8dxoTctuXtpY94n4s8F4pS --------- Co-authored-by: Liam Aharon Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Ankan Co-authored-by: command-bot <> --- polkadot/runtime/westend/src/lib.rs | 1 + substrate/frame/nomination-pools/src/lib.rs | 155 +++++++++--- .../frame/nomination-pools/src/migration.rs | 87 +++++++ substrate/frame/nomination-pools/src/mock.rs | 48 +++- substrate/frame/nomination-pools/src/tests.rs | 225 +++++++++++++++--- substrate/frame/staking/src/lib.rs | 10 +- substrate/frame/staking/src/mock.rs | 1 + substrate/primitives/staking/src/lib.rs | 2 + 8 files changed, 441 insertions(+), 88 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 34f116eb9f0..6085b6e3745 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1508,6 +1508,7 @@ pub mod migrations { paras_registrar::migration::VersionCheckedMigrateToV1, pallet_nomination_pools::migration::versioned_migrations::V5toV6, pallet_referenda::migration::v1::MigrateV0ToV1, + pallet_nomination_pools::migration::versioned_migrations::V6ToV7, ); } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 2ec9b537d32..909a930e382 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -538,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()) @@ -1189,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( @@ -1224,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) } @@ -1239,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. @@ -1437,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 { @@ -1525,7 +1572,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(6); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1602,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>; @@ -1825,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, @@ -2114,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. @@ -2127,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(()) } @@ -2180,9 +2237,8 @@ pub mod pallet { ensure!(!withdrawn_points.is_empty(), Error::::CannotWithdrawAny); // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the - // `transferable_balance` is correct. - let stash_killed = - T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; + // `transferrable_balance` is correct. + 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. @@ -2846,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) }, } } @@ -2871,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. @@ -3242,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"); @@ -3257,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(()) })?; @@ -3280,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!( @@ -3300,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(()) } @@ -3424,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, @@ -3445,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 606123daa9c..eef2a976f1a 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -27,6 +27,16 @@ use sp_runtime::TryRuntimeError; 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, @@ -37,6 +47,83 @@ pub mod versioned_migrations { >; } +/// 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::*; diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 3884518a992..d806ba071bd 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -20,7 +20,7 @@ use crate::{self as pools}; 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; @@ -46,7 +46,8 @@ 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; @@ -60,6 +61,19 @@ impl StakingMock { 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 { @@ -105,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(()) } @@ -116,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()) } @@ -144,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, + }), } } diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 67183e25689..2749e89ecff 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -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(), @@ -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. @@ -637,12 +634,12 @@ mod join { // 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![ @@ -651,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(), @@ -660,7 +658,7 @@ 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 Currency::set_balance(&12, ExistentialDeposit::get() + 12); @@ -672,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(), @@ -2359,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), @@ -2669,8 +2675,9 @@ mod unbond { .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { let ed = Currency::minimum_balance(); - // Given a slash from 600 -> 100 - StakingMock::set_bonded_balance(default_bonded_account(), 100); + // Given a slash from 600 -> 500 + StakingMock::slash_by(1, 500); + // and unclaimed rewards of 600. Currency::set_balance(&default_reward_account(), ed + 600); @@ -2702,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 } ] ); @@ -2863,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!( @@ -2883,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!( @@ -2921,7 +2931,7 @@ mod unbond { ); assert_eq!( *UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), - 100 + 200 + vec![(3, 100), (3, 200)], ); }); } @@ -3020,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)] + ); }); } @@ -3298,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!( @@ -3368,21 +3381,58 @@ mod pool_withdraw_unbonded { #[test] fn pool_withdraw_unbonded_works() { - ExtBuilder::default().build_and_execute(|| { - // Given 10 unbonded 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!(Currency::free_balance(&default_bonded_account()), 10); + 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); // 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!(Currency::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); }); } } @@ -3412,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); + Currency::set_balance( &default_bonded_account(), Currency::free_balance(&default_bonded_account()) / 2, // 300 ); - StakingMock::set_bonded_balance( - default_bonded_account(), - StakingMock::active_stake(&default_bonded_account()).unwrap() / 2, - ); + 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 @@ -3465,6 +3524,7 @@ 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!( @@ -3552,7 +3612,7 @@ mod withdraw_unbonded { // Given // current bond is 600, we slash it all to 300. - StakingMock::set_bonded_balance(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)); @@ -3572,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, @@ -4051,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!( @@ -4058,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)); @@ -4070,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); @@ -4089,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); @@ -4398,6 +4467,7 @@ mod create { let next_pool_stash = Pools::create_bonded_account(2); 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)); @@ -4411,6 +4481,7 @@ mod create { 456, 789 )); + assert_eq!(TotalValueLocked::::get(), 10 + StakingMock::minimum_nominator_bond()); assert_eq!(Currency::free_balance(&11), 0); assert_eq!( @@ -4701,9 +4772,10 @@ 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 @@ -4729,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 } ] @@ -4927,8 +5000,10 @@ 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!(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)); @@ -4936,6 +5011,8 @@ mod bond_extra { // then 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); @@ -4945,6 +5022,8 @@ mod bond_extra { // then 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); @@ -5354,7 +5433,7 @@ 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 @@ -6868,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/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e59b2a3324a..dcf57a46432 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -671,8 +671,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 } } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index cf08f8be1f2..c41144278f2 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -278,6 +278,7 @@ impl OnStakingUpdate for EventListenerMock { _pool_account: &AccountId, slashed_bonded: Balance, slashed_chunks: &BTreeMap, + _total_slashed: Balance, ) { LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 1621af164b3..8b5797d7918 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -121,10 +121,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, ) { } } -- GitLab From 2ed66a0960367b2ea9fc23fa5ca59ee240b89db6 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 1 Oct 2023 16:16:14 +0200 Subject: [PATCH 244/633] migrate alliance, fast-unstake and bags list to use derive-impl (#1636) Moving a few pallets to the latest and greatest `derive_impl` to give it a try. Part of #171 --------- Co-authored-by: Adrian Catangiu Co-authored-by: Keith Yeung --- .../xcm/xcm-builder/src/tests/pay/mock.rs | 12 +------- substrate/frame/alliance/src/mock.rs | 25 ++--------------- substrate/frame/bags-list/src/mock.rs | 26 ++--------------- substrate/frame/bags-list/src/tests.rs | 6 ++-- substrate/frame/balances/src/lib.rs | 19 ++++++++----- .../test-staking-e2e/src/mock.rs | 12 ++------ .../frame/examples/kitchensink/src/tests.rs | 8 ------ substrate/frame/examples/split/src/mock.rs | 8 ------ substrate/frame/fast-unstake/src/mock.rs | 28 ++++--------------- substrate/frame/multisig/src/tests.rs | 16 ++--------- substrate/frame/proxy/src/tests.rs | 11 -------- substrate/frame/support/procedural/src/lib.rs | 2 ++ 12 files changed, 34 insertions(+), 139 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index c663b0a4d76..5b6fa3ee5a0 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/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index f04e7e414ed..82dbbe9c0bb 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/bags-list/src/mock.rs b/substrate/frame/bags-list/src/mock.rs index ae50adabd50..9946a2198ac 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 9e8508698d8..0b382a4fcef 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/lib.rs b/substrate/frame/balances/src/lib.rs index 5da6600d879..a2cacc45369 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,12 +227,17 @@ 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 DustRemoval = (); + type MaxLocks = (); type MaxReserves = (); type MaxFreezes = (); @@ -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 + Ord + 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,10 +299,6 @@ 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; 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 ec646c31197..2e3cb15f9a4 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/examples/kitchensink/src/tests.rs b/substrate/frame/examples/kitchensink/src/tests.rs index b2af7c8983f..abded83e482 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 bee3633ef68..caab4f1ae90 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/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index dc24a823c0d..cf274c784f9 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/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index e7fc5b3e4aa..17982725529 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/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 0667be6e1e5..89bd8b68f09 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/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 466ceca4296..16921994a7b 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -877,6 +877,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( -- GitLab From c54ea64af43b522d23bfabb8d917a490c0f23217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 1 Oct 2023 21:45:32 +0200 Subject: [PATCH 245/633] no-bound derives: Use absolute path for `core` (#1763) Closes: https://github.com/paritytech/polkadot-sdk/issues/1718 --- substrate/frame/support/procedural/src/lib.rs | 6 +++--- .../frame/support/procedural/src/no_bound/clone.rs | 12 ++++++------ .../frame/support/procedural/src/no_bound/debug.rs | 4 ++-- .../support/procedural/src/no_bound/default.rs | 10 +++++----- .../support/procedural/src/no_bound/partial_eq.rs | 2 +- substrate/frame/support/src/tests/mod.rs | 14 ++++++++++++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 16921994a7b..da4cb41fe4f 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -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() diff --git a/substrate/frame/support/procedural/src/no_bound/clone.rs b/substrate/frame/support/procedural/src/no_bound/clone.rs index bbea2feffa9..2c9037984f5 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 ae182829a49..88f5dfe7bec 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 35d0eaeecf5..ddaab26c441 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() } }); @@ -105,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() } }); @@ -114,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() } }); @@ -149,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 27f5e98810e..1a4a4e50b39 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/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index db458880db6..3690159c599 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; +} -- GitLab From db3fd687262c68b115ab6724dfaa6a71d4a48a59 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 3 Oct 2023 02:11:56 +1100 Subject: [PATCH 246/633] Init System Parachain storage versions and add migration check jobs to CI (#1344) Makes SPs first class citizens along with the relay chains in the context of our CI runtime upgrade checks. ## Code changes - Sets missing current storage version in `uniques` pallet - Adds multisig V1 migration to run where it was missing - Removes executed migration whos pre/post hooks were failing from collectives runtime - Initializes storage versions for SP pallets added after genesis - Originally I was going to wait for https://github.com/paritytech/polkadot-sdk/pull/1297 to be merged so this wouldn't need to be done manually, but it doesn't seem like it'll be merged any time soon so I've decided to set them manually to unblock this ## CI changes - Removed dependency of `westend` runtime upgrades being complete prior to other ones running. I assume it is supposed to cache the `try-runtime` build for a performance benefit, but it seems it wasn't working. Maybe someone from the CI team can look into this or explain why it needs to be there? - Adds check-runtime-migration jobs for Parity asset-hubs, bridge-hubs and contract chains - Updated VARIABLES to accomodate the `kusama-runtime` package being renamed to `staging-kusama-runtime` in https://github.com/paritytech/polkadot-sdk/pull/1241 - Added `EXTRA_ARGS` variable to `check-runtime-migration`, and set `--no-weight-warnings` to the relay chain runtime upgrade checks (relay chains don't have weight restrictions). --- .gitlab/pipeline/check.yml | 63 ++++++++++++++++--- .../assets/asset-hub-westend/src/lib.rs | 38 +++++++++++ .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 35 ++++++++++- substrate/frame/multisig/src/migrations.rs | 18 +++--- substrate/frame/nfts/src/migration.rs | 5 +- substrate/frame/referenda/src/migration.rs | 2 - substrate/frame/uniques/src/lib.rs | 3 + 7 files changed, 140 insertions(+), 24 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 5cc2337bf40..4f92e6c15d2 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -113,13 +113,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 +131,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/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 759cd727f1d..94333208762 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -857,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, 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 4c850f92b8d..c4e510ee409 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 @@ -123,7 +123,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< diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index 3be55080b24..330613bb3df 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/nfts/src/migration.rs b/substrate/frame/nfts/src/migration.rs index f90d332062a..94635a96aeb 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/referenda/src/migration.rs b/substrate/frame/referenda/src/migration.rs index 281da83d656..a80897242ee 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/uniques/src/lib.rs b/substrate/frame/uniques/src/lib.rs index 1b75d0b078b..8334a8d943e 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")] -- GitLab From 3ea497b5a0fdda252f9c5a3c257cfaf8685f02fd Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Tue, 3 Oct 2023 09:23:22 -0500 Subject: [PATCH 247/633] expose the last relay chain block number as an API from parachain-system (#1761) re: https://forum.polkadot.network/t/blocknumber-vs-timestamps-should-we-abandon-blocktimes-altogether/4077 This exposes the `LastRelayChainBlockNumber` storage member of `cumulus-pallet-parachain-system` with a getter and alters the behavior of this storage item to only be updated in `on_finalize` to ensure a consistent value throughout `on_initialize` and within transactions. Parachains, especially with features such as asynchronous backing and agile coretime, should not use the parachain block number as a clock. Any feature of Polkadot intended to optimize core utilization and parachain coretime consumption is likely to worsen this clock as it is practically applied. --- cumulus/pallets/parachain-system/src/lib.rs | 23 ++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index a8f0a49223f..eaf15768e29 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>; @@ -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 { -- GitLab From aad80cce318fd492ce0d9c9951f2d7ec949710f3 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 3 Oct 2023 23:16:46 +0800 Subject: [PATCH 248/633] feat: compute pallet/storage prefix hash at compile time (#1539) Since the hash rules of this part of the `pallet_prefix/storage_prefix` are always fixed, we can put the runtime calculation into compile time. --- polkadot address: 15ouFh2SHpGbHtDPsJ6cXQfes9Cx1gEFnJJsJVqPGzBSTudr --------- Co-authored-by: Juan Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + .../basic-authorship/src/basic_authorship.rs | 2 +- .../bags-list/remote-tests/src/snapshot.rs | 4 +- .../bags-list/remote-tests/src/try_state.rs | 4 +- substrate/frame/paged-list/src/paged_list.rs | 12 +++--- substrate/frame/support/procedural/Cargo.toml | 1 + .../procedural/src/construct_runtime/mod.rs | 38 ++++++++++++----- .../src/pallet/expand/pallet_struct.rs | 8 ++++ .../procedural/src/pallet/expand/storage.rs | 42 ++++++++++++++++++- .../support/procedural/src/pallet/mod.rs | 2 +- .../procedural/src/pallet/parse/helper.rs | 16 ++++++- .../support/procedural/src/storage_alias.rs | 11 ++++- .../src/storage/generator/double_map.rs | 29 ++++++------- .../support/src/storage/generator/map.rs | 27 ++++++------ .../support/src/storage/generator/nmap.rs | 31 +++++++------- .../support/src/storage/generator/value.rs | 18 ++++---- substrate/frame/support/src/storage/mod.rs | 32 ++++++++------ .../support/src/storage/types/counted_map.rs | 2 +- .../support/src/storage/types/counted_nmap.rs | 2 +- .../support/src/storage/types/double_map.rs | 15 ++++--- .../frame/support/src/storage/types/map.rs | 13 +++--- .../frame/support/src/storage/types/nmap.rs | 13 +++--- .../frame/support/src/storage/types/value.rs | 9 ++-- .../frame/support/src/tests/storage_alias.rs | 10 ++--- .../frame/support/src/traits/metadata.rs | 13 ++++++ substrate/frame/support/src/traits/storage.rs | 27 ++++++++++++ substrate/frame/tips/src/tests.rs | 2 +- substrate/frame/tx-pause/src/lib.rs | 2 +- 28 files changed, 263 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0ca0b012c6..6d079c53b0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5289,6 +5289,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", + "sp-core-hashing", "syn 2.0.37", ] diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 0fb61b6fab1..57c2996ab40 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? diff --git a/substrate/frame/bags-list/remote-tests/src/snapshot.rs b/substrate/frame/bags-list/remote-tests/src/snapshot.rs index 13922cd3ca6..81a8905e6b4 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 338be50a93f..83930024c89 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/paged-list/src/paged_list.rs b/substrate/frame/paged-list/src/paged_list.rs index 3597c3dea68..beea8ecc644 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/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 6381e430f2b..704f355ff6c 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -26,6 +26,7 @@ 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"] } expander = "2.0.0" +sp-core-hashing = { path = "../../../primitives/core/hashing" } [features] default = [ "std" ] diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index f42dd837e3a..e8c3c088921 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -211,6 +211,7 @@ 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, @@ -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(), ) - }); + }); 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::

(); #( 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 e519e34d1df..c2102f0284d 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 c01f0f3926a..e7f7cf548f0 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/mod.rs b/substrate/frame/support/procedural/src/pallet/mod.rs index 3618711051d..42d8272fb23 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/helper.rs b/substrate/frame/support/procedural/src/pallet/parse/helper.rs index bfa19d8ddc3..446ec203d2b 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. @@ -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/storage_alias.rs b/substrate/frame/support/procedural/src/storage_alias.rs index a3f21806e18..4903fd1c129 100644 --- a/substrate/frame/support/procedural/src/storage_alias.rs +++ b/substrate/frame/support/procedural/src/storage_alias.rs @@ -17,7 +17,7 @@ //! Implementation of the `storage_alias` attribute macro. -use crate::counter_prefix; +use crate::{counter_prefix, pallet::parse::helper}; use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; @@ -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/src/storage/generator/double_map.rs b/substrate/frame/support/src/storage/generator/double_map.rs index 00a3f1bc7c1..a4c1f58203e 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 1d2511e324d..b2919bff8d1 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 5d3d689aa98..4b49ad3eb38 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 4ffe40bac53..21166b39467 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 d52908fa366..851b0687bd1 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/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 5b750a74098..50e2c678248 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 54f8e57cf24..5da31c05922 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 e7879218410..519ffcbafad 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 816b90162f6..7f936a8a35a 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 e9a4b12dd43..406fd42eaf7 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 3c7f24715ac..3e1f2fe9551 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/storage_alias.rs b/substrate/frame/support/src/tests/storage_alias.rs index 05ea1b5f712..6fc5cfefdad 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/metadata.rs b/substrate/frame/support/src/traits/metadata.rs index 85d8f9a5a74..bd29b600916 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/storage.rs b/substrate/frame/support/src/traits/storage.rs index e0ce1c0fbd3..fe1b9bf13bb 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/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 9cb90c37980..20d4b2c1a4c 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -489,7 +489,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/tx-pause/src/lib.rs b/substrate/frame/tx-pause/src/lib.rs index f8abf678e5a..a3be0f50172 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) } -- GitLab From d80171ec229d903ca13673f2bf0d759b7bbb830f Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 4 Oct 2023 01:14:01 +0300 Subject: [PATCH 249/633] Update bridges subtree (#1740) Co-authored-by: Branislav Kontur --- Cargo.lock | 17 + Cargo.toml | 1 + .../runtime-common/src/priority_calculator.rs | 2 +- .../src/refund_relayer_extension.rs | 928 +++++++++++++----- .../chain-bridge-hub-kusama/src/lib.rs | 1 - .../chain-bridge-hub-polkadot/src/lib.rs | 1 - .../chain-bridge-hub-rococo/src/lib.rs | 2 +- .../chain-bridge-hub-wococo/src/lib.rs | 1 - bridges/primitives/chain-kusama/src/lib.rs | 1 - .../chain-polkadot-bulletin/Cargo.toml | 41 + .../chain-polkadot-bulletin/src/lib.rs | 215 ++++ bridges/primitives/chain-polkadot/src/lib.rs | 1 - bridges/primitives/chain-rococo/src/lib.rs | 1 - bridges/primitives/chain-wococo/src/lib.rs | 1 - .../src/justification/verification/mod.rs | 1 + bridges/primitives/runtime/src/chain.rs | 16 +- bridges/primitives/runtime/src/lib.rs | 3 + .../src/bridge_hub_rococo_config.rs | 20 +- .../src/bridge_hub_wococo_config.rs | 20 +- 19 files changed, 1017 insertions(+), 256 deletions(-) create mode 100644 bridges/primitives/chain-polkadot-bulletin/Cargo.toml create mode 100644 bridges/primitives/chain-polkadot-bulletin/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6d079c53b0f..b3ffd4b9fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1654,6 +1654,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" diff --git a/Cargo.toml b/Cargo.toml index 7edc28daf76..9c936024e5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,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", diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index 3d53f9da8c2..fd103448125 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 f0c2cbf4450..876c069dc0f 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(); + call: &CallOf, + ) -> Result, TransactionValidityError>; - 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()); + /// Check if parsed call is already obsolete. + fn check_obsolete_parsed_call( + call: &CallOf, + ) -> Result<&CallOf, 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, - }) - } - - 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,54 +533,294 @@ 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 } })) } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let call_result = Self::analyze_call_result(pre, info, post_info, len, result); + fn post_dispatch( + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + 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( + reward_account, + &relayer, + reward, + ); + + log::trace!( + target: "runtime::bridge", + "{} via {:?} has registered reward: {:?} for {:?}", + Self::IDENTIFIER, + ::Id::get(), + reward, + relayer, + ); + }, + RelayerAccountAction::Slash(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(); - match call_result { - RelayerAccountAction::None => (), - RelayerAccountAction::Reward(relayer, reward_account, reward) => { - RelayersPallet::::register_relayer_reward( - reward_account, - &relayer, - reward, - ); + 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()); - log::trace!( - target: "runtime::bridge", - "{} from parachain {} via {:?} has registered reward: {:?} for {:?}", - Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), - reward, - relayer, - ); - }, - RelayerAccountAction::Slash(relayer, slash_account) => - RelayersPallet::::slash_and_deregister(&relayer, slash_account), - } + 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, + }) + } - Ok(()) + 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 } } @@ -655,7 +837,10 @@ mod tests { }, mock::*, }; - use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayersState}; + use bp_messages::{ + DeliveredMessages, InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayer, + UnrewardedRelayersState, + }; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; use bp_runtime::HeaderId; @@ -690,7 +875,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 +893,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(); @@ -849,6 +1045,30 @@ mod tests { }) } + fn relay_finality_and_delivery_batch_call( + relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_relay_header_call(relay_header_number), + message_delivery_call(best_message), + ], + }) + } + + fn relay_finality_and_confirmation_batch_call( + relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_relay_header_call(relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + fn all_finality_and_delivery_batch_call( relay_header_number: RelayBlockNumber, parachain_head_at_relay_header_number: RelayBlockNumber, @@ -931,6 +1151,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 +1277,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 +1290,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 +1311,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) } @@ -1674,7 +1955,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 +2018,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/primitives/chain-bridge-hub-kusama/src/lib.rs b/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs index 3a919648df4..66e0dad0589 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 bf8d8e07c3a..c3661c1adca 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 b726c62ac42..a50bda23ac8 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; diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs index 5e4758645d9..ce4600f5ff3 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)] diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 8c3fbd9c203..d5748aa132c 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 00000000000..4311aec4727 --- /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 00000000000..fcc6e90eb1b --- /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 d1d6f745431..61c8ca927d8 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 1589d14ea51..5436ad84646 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 5b5bde82690..b1df65630be 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 bb8aaadf327..a66fc1e0d91 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 5caaebd42ba..e1809e14524 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 ece782e352b..7f4a1a030b1 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/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 bc8f97ad97c..f59c9e238f5 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,8 +29,8 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundableMessagesLane, - RefundableParachain, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, }, }; use frame_support::{parameter_types, traits::PalletInfoAccess}; @@ -136,13 +136,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); 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 5178b75c303..a0b16bace51 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,8 +29,8 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundableMessagesLane, - RefundableParachain, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, }, }; use frame_support::{parameter_types, traits::PalletInfoAccess}; @@ -136,13 +136,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); -- GitLab From cd076d7044029c1728881e5f86766d1c9c85f375 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Wed, 4 Oct 2023 09:07:20 +0200 Subject: [PATCH 250/633] Upgraded review-bot to version 2.0.1 (#1784) ## [Updated review bot version](https://github.com/paritytech/polkadot-sdk/commit/677610ba330a8e03f24b46889787e0475f354954) updated version to version `2.0.1` which contains https://github.com/paritytech/review-bot/pull/90, a fix for the team members not being fetch in its totality. ## [Updated review-bot.yml minApprovals convention](https://github.com/paritytech/polkadot-sdk/commit/b1446832ddd14f55b2720a65b0ff86b139999419) Renamed `min_approvals` to `minApprovals`. A breaking change in https://github.com/paritytech/review-bot/pull/86 which was done to standarize all the cases (so now everything is camelCase) --- .github/review-bot.yml | 23 +++++++++++------------ .github/workflows/review-bot.yml | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/review-bot.yml b/.github/review-bot.yml index c9eadd6e58b..581e3376260 100644 --- a/.github/review-bot.yml +++ b/.github/review-bot.yml @@ -10,7 +10,7 @@ rules: - ^\.cargo/.* exclude: - ^./gitlab/pipeline/zombienet.* - min_approvals: 2 + minApprovals: 2 type: basic teams: - ci @@ -27,7 +27,7 @@ rules: exclude: - ^polkadot/runtime\/(kusama|polkadot)\/src\/weights\/.+\.rs$ - ^substrate\/frame\/.+\.md$ - min_approvals: 1 + minApprovals: 1 allowedToSkipRule: teams: - core-devs @@ -54,7 +54,7 @@ rules: - ^\.gitlab/.* - ^\.config/nextest.toml - ^\.cargo/.* - min_approvals: 2 + minApprovals: 2 type: basic teams: - core-devs @@ -70,10 +70,10 @@ rules: - ^cumulus/parachains/common/src/[^/]+\.rs$ type: and-distinct reviewers: - - min_approvals: 1 + - minApprovals: 1 teams: - locks-review - - min_approvals: 1 + - minApprovals: 1 teams: - polkadot-review @@ -83,7 +83,7 @@ rules: condition: include: - ^bridges/.* - min_approvals: 1 + minApprovals: 1 teams: - bridges-core @@ -95,10 +95,10 @@ rules: - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) type: "and" reviewers: - - min_approvals: 2 + - minApprovals: 2 teams: - core-devs - - min_approvals: 1 + - minApprovals: 1 teams: - frame-coders @@ -107,15 +107,14 @@ rules: condition: include: - review-bot\.yml - min_approvals: 2 type: "and" reviewers: - - min_approvals: 1 + - minApprovals: 1 teams: - opstooling - - min_approvals: 1 + - minApprovals: 1 teams: - locks-review - - min_approvals: 1 + - minApprovals: 1 teams: - ci diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index aeb33b5da3d..b9799935abe 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -24,7 +24,7 @@ jobs: app_id: ${{ secrets.REVIEW_APP_ID }} private_key: ${{ secrets.REVIEW_APP_KEY }} - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v1.1.0 + uses: paritytech/review-bot@v2.0.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} team-token: ${{ steps.team_token.outputs.token }} -- GitLab From f4827dcd16fc5585a8d15c6a32bc27ecde00e7f9 Mon Sep 17 00:00:00 2001 From: yjh Date: Wed, 4 Oct 2023 16:36:06 +0800 Subject: [PATCH 251/633] remove outdated scripts (#1769) --- polkadot/scripts/build-demos.sh | 28 ---------------------------- polkadot/scripts/run_all_benches.sh | 15 --------------- 2 files changed, 43 deletions(-) delete mode 100755 polkadot/scripts/build-demos.sh delete mode 100755 polkadot/scripts/run_all_benches.sh diff --git a/polkadot/scripts/build-demos.sh b/polkadot/scripts/build-demos.sh deleted file mode 100755 index 285da143c17..00000000000 --- 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/run_all_benches.sh b/polkadot/scripts/run_all_benches.sh deleted file mode 100755 index 923013f3515..00000000000 --- 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 -- GitLab From 0a6dfdf973b8e7b669eda6e2ed202fb3549a20b9 Mon Sep 17 00:00:00 2001 From: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:27:59 -0700 Subject: [PATCH 252/633] Updating glutton for async backing (#1619) Applied changes from the [User Update Guide](https://docs.google.com/document/d/1WQijD3bZTCsudOyPcDvugv659nCa2hEp2b_8eRU0h-Q), diverging in the node side where service.rs is different for `polkadot-parachain` than in the parachain template. --- Cargo.lock | 2 + .../glutton/glutton-kusama/Cargo.toml | 2 + .../glutton/glutton-kusama/src/lib.rs | 58 ++-- cumulus/polkadot-parachain/Cargo.toml | 1 + cumulus/polkadot-parachain/src/command.rs | 28 +- cumulus/polkadot-parachain/src/service.rs | 287 +++++++++++++++++- 6 files changed, 345 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3ffd4b9fb6..46f6b6ea1fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5739,6 +5739,7 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-timestamp", "frame-benchmarking", @@ -12325,6 +12326,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", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 63b658ca977..ad13bf05a3e 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -43,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 } @@ -72,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", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index d3369202aac..f5d52239e54 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -81,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}; @@ -123,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; @@ -184,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 = (); @@ -194,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 {} @@ -209,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; } @@ -217,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 { @@ -340,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 { @@ -348,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, diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index ac8ad53b524..9d5a5ecda1e 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -87,6 +87,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" } diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index b96163f63e4..0e948d24f82 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -876,12 +876,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 +954,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 f7b053b4b6a..2f86f54f12a 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -17,8 +17,9 @@ use codec::Codec; 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}; @@ -696,6 +697,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 +1389,104 @@ where .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, -- GitLab From 86955eef90138941beabf4143b645d652ac98d14 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:05:42 +0300 Subject: [PATCH 253/633] Remove deprecated CI config files (#1799) This PR removes deprecated CI config files --- cumulus/.gitattributes | 2 - cumulus/.github/dependabot.yml | 31 -- cumulus/.github/pr-custom-review.yml | 48 -- cumulus/.github/workflows/check-D-labels.yml | 47 -- cumulus/.github/workflows/check-labels.yml | 45 -- cumulus/.github/workflows/docs.yml | 39 -- cumulus/.github/workflows/fmt-check.yml | 22 - .../.github/workflows/pr-custom-review.yml | 42 -- .../workflows/release-01_branch-check.yml | 22 - .../workflows/release-10_rc-automation.yml | 87 ---- ...e-20_extrinsic-ordering-check-from-bin.yml | 86 ---- ...e-21_extrinsic-ordering-check-from-two.yml | 120 ----- .../workflows/release-30_create-draft.yml | 311 ------------- .../workflows/release-99_bot-announce.yml | 39 -- cumulus/.github/workflows/srtool.yml | 122 ------ cumulus/.gitlab-ci.yml | 201 --------- cumulus/scripts/ci/changelog/README.md | 77 ---- polkadot/.gitattributes | 2 - polkadot/.github/dependabot.yml | 26 -- polkadot/.github/pr-custom-review.yml | 42 -- .../workflows/burnin-label-notification.yml | 24 - polkadot/.github/workflows/check-D-labels.yml | 50 --- .../.github/workflows/check-bootnodes.yml | 31 -- polkadot/.github/workflows/check-labels.yml | 45 -- polkadot/.github/workflows/check-licenses.yml | 26 -- .../.github/workflows/check-new-bootnodes.yml | 28 -- polkadot/.github/workflows/check-weights.yml | 49 --- polkadot/.github/workflows/honggfuzz.yml | 137 ------ .../.github/workflows/pr-custom-review.yml | 42 -- .../workflows/release-01_branch-check.yml | 21 - .../workflows/release-10_candidate.yml | 71 --- ...e-20_extrinsic-ordering-check-from-bin.yml | 81 ---- ...e-21_extrinsic-ordering-check-from-two.yml | 97 ----- .../release-30_publish-draft-release.yml | 199 --------- polkadot/.github/workflows/release-99_bot.yml | 49 --- polkadot/.gitlab-ci.yml | 287 ------------ substrate/.gitattributes | 2 - substrate/.github/dependabot.yml | 12 - substrate/.github/pr-custom-review.yml | 39 -- substrate/.github/stale.yml | 18 - .../.github/workflows/auto-label-issues.yml | 17 - .../workflows/burnin-label-notification.yml | 24 - .../.github/workflows/check-D-labels.yml | 48 -- substrate/.github/workflows/check-labels.yml | 45 -- substrate/.github/workflows/md-link-check.yml | 19 - substrate/.github/workflows/mlc_config.json | 7 - substrate/.github/workflows/monthly-tag.yml | 43 -- .../.github/workflows/pr-custom-review.yml | 42 -- substrate/.github/workflows/release-bot.yml | 31 -- .../.github/workflows/release-tagging.yml | 20 - substrate/.gitlab-ci.yml | 412 ------------------ 51 files changed, 3427 deletions(-) delete mode 100644 cumulus/.gitattributes delete mode 100644 cumulus/.github/dependabot.yml delete mode 100644 cumulus/.github/pr-custom-review.yml delete mode 100644 cumulus/.github/workflows/check-D-labels.yml delete mode 100644 cumulus/.github/workflows/check-labels.yml delete mode 100644 cumulus/.github/workflows/docs.yml delete mode 100644 cumulus/.github/workflows/fmt-check.yml delete mode 100644 cumulus/.github/workflows/pr-custom-review.yml delete mode 100644 cumulus/.github/workflows/release-01_branch-check.yml delete mode 100644 cumulus/.github/workflows/release-10_rc-automation.yml delete mode 100644 cumulus/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml delete mode 100644 cumulus/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml delete mode 100644 cumulus/.github/workflows/release-30_create-draft.yml delete mode 100644 cumulus/.github/workflows/release-99_bot-announce.yml delete mode 100644 cumulus/.github/workflows/srtool.yml delete mode 100644 cumulus/.gitlab-ci.yml delete mode 100644 cumulus/scripts/ci/changelog/README.md delete mode 100644 polkadot/.gitattributes delete mode 100644 polkadot/.github/dependabot.yml delete mode 100644 polkadot/.github/pr-custom-review.yml delete mode 100644 polkadot/.github/workflows/burnin-label-notification.yml delete mode 100644 polkadot/.github/workflows/check-D-labels.yml delete mode 100644 polkadot/.github/workflows/check-bootnodes.yml delete mode 100644 polkadot/.github/workflows/check-labels.yml delete mode 100644 polkadot/.github/workflows/check-licenses.yml delete mode 100644 polkadot/.github/workflows/check-new-bootnodes.yml delete mode 100644 polkadot/.github/workflows/check-weights.yml delete mode 100644 polkadot/.github/workflows/honggfuzz.yml delete mode 100644 polkadot/.github/workflows/pr-custom-review.yml delete mode 100644 polkadot/.github/workflows/release-01_branch-check.yml delete mode 100644 polkadot/.github/workflows/release-10_candidate.yml delete mode 100644 polkadot/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml delete mode 100644 polkadot/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml delete mode 100644 polkadot/.github/workflows/release-30_publish-draft-release.yml delete mode 100644 polkadot/.github/workflows/release-99_bot.yml delete mode 100644 polkadot/.gitlab-ci.yml delete mode 100644 substrate/.github/dependabot.yml delete mode 100644 substrate/.github/pr-custom-review.yml delete mode 100644 substrate/.github/stale.yml delete mode 100644 substrate/.github/workflows/auto-label-issues.yml delete mode 100644 substrate/.github/workflows/burnin-label-notification.yml delete mode 100644 substrate/.github/workflows/check-D-labels.yml delete mode 100644 substrate/.github/workflows/check-labels.yml delete mode 100644 substrate/.github/workflows/md-link-check.yml delete mode 100644 substrate/.github/workflows/mlc_config.json delete mode 100644 substrate/.github/workflows/monthly-tag.yml delete mode 100644 substrate/.github/workflows/pr-custom-review.yml delete mode 100644 substrate/.github/workflows/release-bot.yml delete mode 100644 substrate/.github/workflows/release-tagging.yml delete mode 100644 substrate/.gitlab-ci.yml diff --git a/cumulus/.gitattributes b/cumulus/.gitattributes deleted file mode 100644 index 2ea1ab2d6b9..00000000000 --- 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 349a34690d4..00000000000 --- 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 fc26ee677f0..00000000000 --- 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 91062720931..00000000000 --- 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 004271d7788..00000000000 --- 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 6aab3f27be6..00000000000 --- 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 7571c51116b..00000000000 --- 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 8e40c9ee729..00000000000 --- 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 afcd4580f17..00000000000 --- 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 d1795faef09..00000000000 --- 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 d902e57ac9e..00000000000 --- 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 93c0050ff6f..00000000000 --- 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 2d11dfe18ce..00000000000 --- 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 5c2604924c4..00000000000 --- 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 ae473b48137..00000000000 --- 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 f032901c6f4..00000000000 --- 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/scripts/ci/changelog/README.md b/cumulus/scripts/ci/changelog/README.md deleted file mode 100644 index 5c8ee9c9b91..00000000000 --- 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/polkadot/.gitattributes b/polkadot/.gitattributes deleted file mode 100644 index 2ea1ab2d6b9..00000000000 --- 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 a1fa925970b..00000000000 --- 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 136c9e75ff2..00000000000 --- 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 536f8fa2a3f..00000000000 --- 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 9abefaa6fa1..00000000000 --- 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 897a90d3ae9..00000000000 --- 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 df0a0e9cf02..00000000000 --- 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 1e654f7b307..00000000000 --- 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 25b2a0a56fe..00000000000 --- 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 e6a6c43e0a6..00000000000 --- 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 27fa0d9967f..00000000000 --- 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 8e40c9ee729..00000000000 --- 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 f2b559b7c17..00000000000 --- 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 54a937a7819..00000000000 --- 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 0613ed04d35..00000000000 --- 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 6513897f4a1..00000000000 --- 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 206b1871d80..00000000000 --- 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 5d45c0d44ed..00000000000 --- 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 b2d91e61da9..00000000000 --- 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/substrate/.gitattributes b/substrate/.gitattributes index a77c52fccdb..4cb3ef4972f 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 04cf0d1e1a5..00000000000 --- 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 059f4a283af..00000000000 --- 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 61d0fd0228d..00000000000 --- 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 12ffce702cd..00000000000 --- 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 f45455d31db..00000000000 --- 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 7bb358ce118..00000000000 --- 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 55b8f7389fa..00000000000 --- 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 e1387f6da13..00000000000 --- 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 e7e620b39e0..00000000000 --- 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 055207d85a4..00000000000 --- 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 8e40c9ee729..00000000000 --- 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 05bea32abc6..00000000000 --- 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 1862582f40e..00000000000 --- 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 f0083652897..00000000000 --- 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 -- GitLab From 51c0c24213aeed7b7c230835a7e381cc2147df82 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Thu, 5 Oct 2023 18:37:54 +0200 Subject: [PATCH 254/633] PVF: Add back socket path parameter, use tmp socket path (#1780) --- .../node/core/pvf/common/src/worker/mod.rs | 24 ++- .../node/core/pvf/common/src/worker_dir.rs | 5 - .../node/core/pvf/execute-worker/src/lib.rs | 4 + .../node/core/pvf/prepare-worker/src/lib.rs | 4 + polkadot/node/core/pvf/src/worker_intf.rs | 140 +++++++++++------- 5 files changed, 111 insertions(+), 66 deletions(-) diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index 59973f6cbbc..d0bd5b6bd7c 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -18,7 +18,7 @@ pub mod security; -use crate::{worker_dir, SecurityStatus, LOG_TARGET}; +use crate::{SecurityStatus, LOG_TARGET}; use cpu_time::ProcessTime; use futures::never::Never; use std::{ @@ -115,6 +115,7 @@ macro_rules! decl_worker_main { }, } + let mut socket_path = None; let mut worker_dir_path = None; let mut node_version = None; let mut can_enable_landlock = false; @@ -123,6 +124,10 @@ macro_rules! decl_worker_main { let mut i = 2; while i < args.len() { match args[i].as_ref() { + "--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 @@ -138,16 +143,24 @@ macro_rules! decl_worker_main { } i += 1; } + 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(worker_dir_path, node_version, Some($worker_version), security_status); + $entrypoint( + socket_path, + worker_dir_path, + node_version, + Some($worker_version), + security_status, + ); } }; } @@ -177,6 +190,7 @@ impl fmt::Display for WorkerKind { // the version that this crate was compiled with. pub fn worker_event_loop( 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>, @@ -190,6 +204,7 @@ pub fn worker_event_loop( gum::debug!( target: LOG_TARGET, %worker_pid, + ?socket_path, ?worker_dir_path, ?security_status, "starting pvf worker ({})", @@ -237,12 +252,9 @@ pub fn worker_event_loop( } // Connect to the socket. - let socket_path = worker_dir::socket(&worker_dir_path); let stream = || -> std::io::Result { let stream = UnixStream::connect(&socket_path)?; - // Remove the socket here. We don't also need to do this on the host-side; on failed - // rendezvous, the host will delete the whole worker dir. - std::fs::remove_file(&socket_path)?; + let _ = std::fs::remove_file(&socket_path); Ok(stream) }(); let stream = match stream { diff --git a/polkadot/node/core/pvf/common/src/worker_dir.rs b/polkadot/node/core/pvf/common/src/worker_dir.rs index c2610a4d112..1cdf43a61e4 100644 --- a/polkadot/node/core/pvf/common/src/worker_dir.rs +++ b/polkadot/node/core/pvf/common/src/worker_dir.rs @@ -20,7 +20,6 @@ use std::path::{Path, PathBuf}; const WORKER_EXECUTE_ARTIFACT_NAME: &str = "artifact"; const WORKER_PREPARE_TMP_ARTIFACT_NAME: &str = "tmp-artifact"; -const WORKER_SOCKET_NAME: &str = "socket"; pub fn execute_artifact(worker_dir_path: &Path) -> PathBuf { worker_dir_path.join(WORKER_EXECUTE_ARTIFACT_NAME) @@ -29,7 +28,3 @@ pub fn execute_artifact(worker_dir_path: &Path) -> PathBuf { pub fn prepare_tmp_artifact(worker_dir_path: &Path) -> PathBuf { worker_dir_path.join(WORKER_PREPARE_TMP_ARTIFACT_NAME) } - -pub fn socket(worker_dir_path: &Path) -> PathBuf { - worker_dir_path.join(WORKER_SOCKET_NAME) -} diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 9d7bfdf2866..02eaedb96f2 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -111,6 +111,8 @@ fn send_response(stream: &mut UnixStream, response: Response) -> io::Result<()> /// /// # Parameters /// +/// - `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 @@ -121,6 +123,7 @@ fn send_response(stream: &mut UnixStream, response: Response) -> io::Result<()> /// /// - `security_status`: contains the detected status of security features. pub fn worker_entrypoint( + socket_path: PathBuf, worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, @@ -128,6 +131,7 @@ pub fn worker_entrypoint( ) { worker_event_loop( WorkerKind::Execute, + socket_path, worker_dir_path, node_version, worker_version, diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index a24f5024722..fcc7f6754a7 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -87,6 +87,8 @@ fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<( /// /// # Parameters /// +/// - `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 @@ -116,6 +118,7 @@ fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<( /// 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: PathBuf, worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, @@ -123,6 +126,7 @@ pub fn worker_entrypoint( ) { worker_event_loop( WorkerKind::Prepare, + socket_path, worker_dir_path, node_version, worker_version, diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index 9825506ba88..bd85d84055c 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -20,7 +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::{worker_dir, SecurityStatus}; +use polkadot_node_core_pvf_common::SecurityStatus; use rand::Rng; use std::{ fmt, mem, @@ -67,71 +67,99 @@ pub async fn spawn_with_program_path( ) -> Result<(IdleWorker, WorkerHandle), SpawnErr> { let program_path = program_path.into(); let worker_dir = WorkerDir::new(debug_id, cache_path).await?; - let socket_path = worker_dir::socket(&worker_dir.path); - let extra_args: Vec = extra_args.iter().map(|arg| arg.to_string()).collect(); - let listener = UnixListener::bind(&socket_path).map_err(|err| { - gum::warn!( - target: LOG_TARGET, - %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, &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| { + with_transient_socket_path(debug_id, |socket_path| { + let socket_path = socket_path.to_owned(); + + async move { + let listener = UnixListener::bind(&socket_path).map_err(|err| { gum::warn!( target: LOG_TARGET, %debug_id, ?program_path, ?extra_args, - ?worker_dir_path, + ?worker_dir, ?socket_path, - "cannot accept a worker: {:?}", + "cannot bind unix socket: {:?}", err, ); - SpawnErr::Accept + SpawnErr::Bind })?; - Ok((IdleWorker { stream, pid: handle.id(), worker_dir }, handle)) - } - _ = Delay::new(spawn_timeout).fuse() => { - gum::warn!( - target: LOG_TARGET, - %debug_id, - ?program_path, - ?extra_args, - ?worker_dir_path, - ?socket_path, - ?spawn_timeout, - "spawning and connecting to socket timed out", - ); - Err(SpawnErr::AcceptTimeout) + + 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| { + gum::warn!( + target: LOG_TARGET, + %debug_id, + ?program_path, + ?extra_args, + ?worker_dir_path, + ?socket_path, + "cannot accept a worker: {:?}", + err, + ); + SpawnErr::Accept + })?; + Ok((IdleWorker { stream, pid: handle.id(), worker_dir }, handle)) + } + _ = Delay::new(spawn_timeout).fuse() => { + gum::warn!( + target: LOG_TARGET, + %debug_id, + ?program_path, + ?extra_args, + ?worker_dir_path, + ?socket_path, + ?spawn_timeout, + "spawning and connecting to socket timed out", + ); + Err(SpawnErr::AcceptTimeout) + } + } } - } + }) + .await +} + +async fn with_transient_socket_path(debug_id: &'static str, f: F) -> Result +where + F: FnOnce(&Path) -> Fut, + Fut: futures::Future> + 'static, +{ + let socket_path = tmppath(&format!("pvf-host-{}", debug_id)) + .await + .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 + // by the worker. We make sure that it is removed here, just in case a failed rendezvous. + let _ = tokio::fs::remove_file(socket_path).await; + + result } /// Returns a path under the given `dir`. The path name will start with the given prefix. @@ -169,7 +197,6 @@ pub async fn tmppath_in(prefix: &str, dir: &Path) -> io::Result { } /// The same as [`tmppath_in`], but uses [`std::env::temp_dir`] as the directory. -#[cfg(test)] pub async fn tmppath(prefix: &str) -> io::Result { let temp_dir = PathBuf::from(std::env::temp_dir()); tmppath_in(prefix, &temp_dir).await @@ -234,6 +261,7 @@ impl WorkerHandle { fn spawn( program: impl AsRef, extra_args: &[String], + socket_path: impl AsRef, worker_dir_path: impl AsRef, security_status: SecurityStatus, ) -> io::Result { @@ -257,6 +285,8 @@ impl WorkerHandle { } 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) -- GitLab From d21113c13fd33748f3fe8cc77c14a6c9407b9c38 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 5 Oct 2023 18:44:03 +0200 Subject: [PATCH 255/633] Delete full db directory with `purge-chain` subcommand (#1786) Closes #1767 Until now the `purge-chain` command would only remove the `full` subfolder of the db folder. However there is also the `parachains` db that currently remains and can cause problems on node restart. Example wiht old code: ``` polkadot purge-chain --database paritydb --base-path /tmp/some-folder Are you sure to remove "/tmp/some-folder/chains/polkadot/paritydb/full"? [y/N]: y "/tmp/some-folder/chains/polkadot/paritydb/full" removed. ``` In this case `/tmp/some-folder/chains/polkadot/paritydb/parachains` would remain and might cause problem on node restart because of version conflicts as described in #1767. After this PR the whole `/tmp/some-folder/chains/polkadot/paritydb` folder will be deleted. --- polkadot/tests/purge_chain_works.rs | 4 ---- substrate/client/cli/src/commands/purge_chain_cmd.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/polkadot/tests/purge_chain_works.rs b/polkadot/tests/purge_chain_works.rs index 831155fb4d7..f5a73e232e0 100644 --- a/polkadot/tests/purge_chain_works.rs +++ b/polkadot/tests/purge_chain_works.rs @@ -57,7 +57,6 @@ async fn purge_chain_rocksdb_works() { assert!(cmd.wait().unwrap().success()); assert!(tmpdir.path().join("chains/rococo_dev").exists()); assert!(tmpdir.path().join("chains/rococo_dev/db/full").exists()); - assert!(tmpdir.path().join("chains/rococo_dev/db/full/parachains").exists()); // Purge chain let status = Command::new(cargo_bin("polkadot")) @@ -102,7 +101,6 @@ async fn purge_chain_paritydb_works() { assert!(cmd.wait().unwrap().success()); assert!(tmpdir.path().join("chains/rococo_dev").exists()); assert!(tmpdir.path().join("chains/rococo_dev/paritydb/full").exists()); - assert!(tmpdir.path().join("chains/rococo_dev/paritydb/parachains").exists()); // Purge chain let status = Command::new(cargo_bin("polkadot")) @@ -118,8 +116,6 @@ async fn purge_chain_paritydb_works() { // 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()); - // Parachains removal requires calling "purge-chain --parachains". - assert!(tmpdir.path().join("chains/rococo_dev/paritydb/parachains").exists()); }) .await; } diff --git a/substrate/client/cli/src/commands/purge_chain_cmd.rs b/substrate/client/cli/src/commands/purge_chain_cmd.rs index 2ff3d4b9a04..6e7b8143a5b 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()) })?; -- GitLab From 0c592329e9cbb5d68373ac16be4899223b2d8de8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 00:09:10 +0200 Subject: [PATCH 256/633] Bump the known_good_semver group with 1 update (#1752) Bumps the known_good_semver group with 1 update: [clap](https://github.com/clap-rs/clap).

Release notes

Sourced from clap's releases.

v4.4.6

[4.4.6] - 2023-09-28

Internal

  • Upgrade anstream

v4.4.5

[4.4.5] - 2023-09-25

Fixes

  • (parser) When inferring subcommand name or long_flag, allow ambiguous-looking matches that unambiguously map back to the same command
  • (parser) When inferring subcommand long_flag, don't panic
  • (assert) Clarify what action is causing a positional that doesn't set values which is especially useful for derive users
Changelog

Sourced from clap's changelog.

[4.4.6] - 2023-09-28

Internal

  • Upgrade anstream

[4.4.5] - 2023-09-25

Fixes

  • (parser) When inferring subcommand name or long_flag, allow ambiguous-looking matches that unambiguously map back to the same command
  • (parser) When inferring subcommand long_flag, don't panic
  • (assert) Clarify what action is causing a positional that doesn't set values which is especially useful for derive users
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=clap&package-manager=cargo&previous-version=4.4.4&new-version=4.4.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 70 +++++++++---------- cumulus/client/cli/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 26 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46f6b6ea1fc..340587d268d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", @@ -2303,7 +2303,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.4", + "clap 4.4.6", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2433,9 +2433,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", "clap_derive 4.4.2", @@ -2443,9 +2443,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", @@ -2459,7 +2459,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", ] [[package]] @@ -3031,7 +3031,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.4", + "clap 4.4.6", "criterion-plot", "futures", "is-terminal", @@ -3196,7 +3196,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3881,7 +3881,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.4", + "clap 4.4.6", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -5088,7 +5088,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.4", + "clap 4.4.6", "comfy-table", "frame-benchmarking", "frame-support", @@ -5180,7 +5180,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -8074,7 +8074,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.4.4", + "clap 4.4.6", "derive_more", "fs_extra", "futures", @@ -8111,7 +8111,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.4.4", + "clap 4.4.6", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8237,7 +8237,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8291,7 +8291,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "generate-bags", "kitchensink-runtime", ] @@ -8300,7 +8300,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8343,7 +8343,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "flate2", "fs_extra", "glob", @@ -10756,7 +10756,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11493,7 +11493,7 @@ dependencies = [ name = "polkadot-cli" version = "1.1.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "frame-benchmarking-cli", "futures", "log", @@ -12315,7 +12315,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.4", + "clap 4.4.6", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -12792,7 +12792,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.4", + "clap 4.4.6", "color-eyre", "futures", "futures-timer", @@ -12939,7 +12939,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "generate-bags", "sp-io", "westend-runtime", @@ -13699,7 +13699,7 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -14411,7 +14411,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.4.4", + "clap 4.4.6", "fdlimit", "futures", "futures-timer", @@ -15514,7 +15514,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "fs4", "log", "sc-client-db", @@ -17055,7 +17055,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17659,7 +17659,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "sc-cli", ] @@ -17701,7 +17701,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "frame-support", "frame-system", "sc-cli", @@ -18160,7 +18160,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -18208,7 +18208,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.4", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -18854,7 +18854,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.4", + "clap 4.4.6", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index c45b669fc6d..5dd18f0c156 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.4", 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/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 114b25d1261..e73c7b50726 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.4", 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"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 9d5a5ecda1e..778b056b89d 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.4", 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" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 5285376f3d5..c996a01a12e 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.4", 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/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 4646fb1c588..8057342aaea 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.4", 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" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 42dd4af73c1..9ce725f1682 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.4", 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/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 73b1fab529e..70f2ae769a8 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.4", 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/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 3fbed4046bd..4569d4e153b 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.4", 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/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 873b0c0030a..95ca57ea728 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.4.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index c59d354dc4a..e305edc039b 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -15,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.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 35654e7d564..23840cce222 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.4", 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/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 33560bca492..c111d345623 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.4", 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/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index c47f8a5c3e5..5ce4c73f98c 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.4", 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"] } @@ -135,7 +135,7 @@ pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] -clap = { version = "4.4.4", 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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 06e9674117e..4a92db29185 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.4", 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/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index f564ff19af0..c7690faf7d0 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.4", 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/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 4e8cb606c94..6606d8ac365 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.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index cfdcb39b1fa..b78287be890 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.4", 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"]} diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 7538f5ba602..021ee76240b 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.4", 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/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 6ac09dd45c6..e4859201454 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.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index eeb9deebb71..5e75f926f87 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.4", 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/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index c0e02758724..73ffce8645b 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.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 9ba22e24faa..e32fe47b729 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.4", 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/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 5a3365dc900..24c04f47391 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.4", 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 e1490aa363c..13e61138356 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.4", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 3f693ca6c82..65380a22ce6 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.4", 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" -- GitLab From 1835c091c42456e8df3ecbf0a94b7b88c395f623 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 6 Oct 2023 10:08:09 +0200 Subject: [PATCH 257/633] Revive Substrate Crate (#1477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/paritytech/polkadot-sdk/issues/1450 Bringing back the Substrate crate that was forgotten in the monorepo import 😅. It is a doc-only crate. Version number is set to `1.0.0` and publishing is enabled (so that we can link to docs.rs). --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 19 +++ Cargo.toml | 25 ++-- substrate/Cargo.toml | 28 ++++ substrate/src/src/lib.rs | 297 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 12 deletions(-) create mode 100644 substrate/Cargo.toml create mode 100644 substrate/src/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 340587d268d..e925c445b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17663,6 +17663,25 @@ dependencies = [ "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]] name = "substrate-bip39" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 9c936024e5f..aa0b93737f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,11 +110,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", @@ -134,10 +134,10 @@ 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/service", "polkadot/node/zombienet-backchannel", @@ -165,8 +165,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", @@ -174,6 +174,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", @@ -182,9 +186,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", @@ -216,6 +217,7 @@ members = [ "substrate/client/keystore", "substrate/client/merkle-mountain-range", "substrate/client/merkle-mountain-range/rpc", + "substrate/client/network-gossip", "substrate/client/network", "substrate/client/network/bitswap", "substrate/client/network/common", @@ -224,13 +226,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", @@ -257,8 +258,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", @@ -398,12 +399,12 @@ members = [ "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/substrate/Cargo.toml b/substrate/Cargo.toml new file mode 100644 index 00000000000..d77f02c6060 --- /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/src/src/lib.rs b/substrate/src/src/lib.rs new file mode 100644 index 00000000000..16a60677896 --- /dev/null +++ b/substrate/src/src/lib.rs @@ -0,0 +1,297 @@ +// 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 +//! +//! 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) +//! +//! This crate in itself does not contain any code and is just meant ot be a documentation hub for +//! substrate-based crates. +//! +//! ## Overview +//! +//! Substrate approaches blockchain development with an acknowledgement of a few self-evident +//! truths: +//! +//! 1. Society and technology evolves. +//! 2. Humans are fallible. +//! +//! This, specifically, makes the task of designing a correct, safe and long-lasting blockchain +//! system hard. +//! +//! Nonetheless, in order to achieve this goal, substrate embraces the following: +//! +//! 1. Use of **Rust** as a modern, and safe programming language, which limits human error through +//! various means, most notably memory safety. +//! 2. Substrate is written from the ground-up with a generic, modular and extensible design. This +//! ensures that software components can be easily swapped and upgraded. Examples of this is +//! multiple consensus mechanisms provided by Substrate, as listed below. +//! 3. Lastly, the final blockchain system created with the above properties needs to be +//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the +//! application logic of the blockchain (called "Runtime") is encoded as a Wasm blob, and is +//! stored onchain. The rest of the system (called "Client") acts as the executor of the Wasm +//! blob. +//! +//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as Wasm blob" +//! accord. This enables the Runtime to become inherently upgradeable (without forks). The upgrade +//! is merely a matter of the Wasm blob being changed in the chain state, which is, in principle, +//! same as updating an account's balance. +//! +//! To learn more about the substrate architecture using some visuals, see [`substrate_diagram`]. +//! +//! `FRAME`, Substrate's default runtime development library takes the above even further by +//! embracing a declarative programming model whereby correctness is enhanced and the system is +//! highly configurable through parameterization. +//! +//! All in all, this design enables all substrate-based chains to achieve forkless, self-enacting +//! upgrades out of the box. Combined with governance abilities that are shipped with `FRAME`, this +//! enables a chain to survive the test of time. +//! +//! ## How to Get Stared +//! +//! Most developers want to leave the client side code as-is, and focus on the runtime. To do so, +//! look into the [`frame_support`] crate, which is the entry point crate into runtime development +//! with FRAME. +//! +//! > Side note, it is entirely possible to craft a substrate-based runtime without FRAME, an +//! > example of which can be found [here](https://github.com/JoshOrndorff/frameless-node-template). +//! +//! In more broad terms, the following avenues exist into developing with substrate: +//! +//! * **Templates**: A number of substrate-based templates exist and they can be used for various +//! purposes, with zero to little additional code needed. All of these templates contain runtimes +//! that are highly configurable and are likely suitable for basic needs. +//! * `FRAME`: If need, one can customize that runtime even further, by using `FRAME` and developing +//! custom modules. +//! * **Core**: To the contrary, some developers may want to customize the client side software to +//! achieve novel goals such as a new consensus engine, or a new database backend. While +//! Substrate's main configurability is in the runtime, the client is also highly generic and can +//! be customized to a great extent. +//! +//! ## Structure +//! +//! Substrate is a massive cargo workspace with hundreds of crates, therefore it is useful to know +//! how to navigate its crates. +//! +//! In broad terms, it is divided into three categories: +//! +//! * `sc-*` (short for *substrate-client*) crates, located under `./client` folder. These are all +//! the client crates. Notable examples are crates such as [`sc-network`], various consensus +//! crates, [`sc-rpc-api`] and [`sc-client-db`], all of which are expected to reside in the client +//! side. +//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These +//! are the traits that glue the client and runtime together, but are not opinionated about what +//! framework is using for building the runtime. Notable examples are [`sp-api`] and [`sp-io`], +//! which form the communication bridge between the client and runtime, as explained in +//! [`substrate_diagram`]. +//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related +//! to FRAME. See [`frame_support`] for more information. +//! +//! ### Wasm Build +//! +//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both Wasm (when a Wasm +//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate +//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a +//! crate is being built with the standard library, and is built for native. Otherwise, it is built +//! for `no_std`. +//! +//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find +//! in any Substrate-based runtime. +//! +//! Substrate-based runtimes use [`substrate-wasm-builder`] in their `build.rs` to automatically +//! build their Wasm files as a part of normal build commandsOnce built, the wasm file is placed in +//! `./target/{debug|release}/wbuild/{runtime_name}.wasm`. +//! +//! ### Binaries +//! +//! Multiple binaries are shipped with substrate, the most important of which are located in the +//! `./bin` folder. +//! +//! * [`node`] is an extensive substrate node that contains the superset of all runtime and client +//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the +//! modules that are provided with `FRAME`. This node and runtime is only used for testing and +//! demonstration. +//! * [`chain-spec-builder`]: Utility to build more detailed chain-specs for the aforementioned +//! node. Other projects typically contain a `build-spec` subcommand that does the same. +//! * [`node-template`]: a template node that contains a minimal set of features and can act as a +//! starting point of a project. +//! * [`subkey`]: Substrate's key management utility. +//! +//! ### Anatomy of a Binary Crate +//! +//! From the above, [`node`] and [`node-template`] are essentially blueprints of a substrate-based +//! project, as the name of the latter is implying. Each substrate-based project typically contains +//! the following: +//! +//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file. +//! This file typically contains the [`frame_support::construct_runtime`] macro, which is the +//! final definition of a runtime. +//! +//! * Under `./node`, a `main.rs`, which is the point, and a `./service.rs`, which contains all the +//! client side components. Skimming this file yields an overview of the networking, database, +//! consensus and similar client side components. +//! +//! > The above two are conventions, not rules. +//! +//! ## Parachain? +//! +//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways +//! 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 +//! library on top of Substrate, empowering any substrate-based chain to be a Polkadot parachain. +//! +//! ## Where To Go Next? +//! +//! Additional noteworthy crates within substrate: +//! +//! - RPC APIs of a Substrate node: [`sc-rpc-api`]/[`sc-rpc`] +//! - CLI Options of a Substrate node: [`sc-cli`] +//! - All of the consensus related crates provided by Substrate: +//! - [`sc-consensus-aura`] +//! - [`sc-consensus-babe`] +//! - [`sc-consensus-grandpa`] +//! - [`sc-consensus-beefy`] +//! - [`sc-consensus-manual-seal`] +//! - [`sc-consensus-pow`] +//! +//! Additional noteworthy external resources: +//! +//! - [Substrate Developer Hub](https://substrate.dev) +//! - [Parity Tech's Documentation Hub](https://paritytech.github.io/) +//! - [Frontier: Substrate's Ethereum Compatibility Library](https://paritytech.github.io/frontier/) +//! - [Polkadot Wiki](https://wiki.polkadot.network/en/) +//! +//! Notable upstream crates: +//! +//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) +//! - [`parity-db`](https://github.com/paritytech/parity-db) +//! - [`trie`](https://github.com/paritytech/trie) +//! - [`parity-common`](https://github.com/paritytech/parity-common) +//! +//! Templates: +//! +//! - classic [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) +//! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) +//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) +//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) +//! +//! [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 +//! [`sp-io`]: ../sp_io/index.html +//! [`sp-api`]: ../sp_api/index.html +//! [`sp-api`]: ../sp_api/index.html +//! [`sc-client-db`]: ../sc_client_db/index.html +//! [`sc-network`]: ../sc_network/index.html +//! [`sc-rpc-api`]: ../sc_rpc_api/index.html +//! [`sc-rpc`]: ../sc_rpc/index.html +//! [`sc-cli`]: ../sc_cli/index.html +//! [`sc-consensus-aura`]: ../sc_consensus_aura/index.html +//! [`sc-consensus-babe`]: ../sc_consensus_babe/index.html +//! [`sc-consensus-grandpa`]: ../sc_consensus_grandpa/index.html +//! [`sc-consensus-beefy`]: ../sc_consensus_beefy/index.html +//! [`sc-consensus-manual-seal`]: ../sc_consensus_manual_seal/index.html +//! [`sc-consensus-pow`]: ../sc_consensus_pow/index.html +//! [`node`]: ../node_cli/index.html +//! [`node-template`]: ../node_template/index.html +//! [`kitchensink_runtime`]: ../kitchensink_runtime/index.html +//! [`subkey`]: ../subkey/index.html +//! [`chain-spec-builder`]: ../chain_spec_builder/index.html +//! [`substrate-wasm-builder`]: https://crates.io/crates/substrate-wasm-builder + +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] + +#[cfg_attr(doc, aquamarine::aquamarine)] +/// In this module, we explore substrate at a more depth. First, let's establish substrate being +/// divided into a client and runtime. +/// +/// ```mermaid +/// graph TB +/// subgraph Substrate +/// direction LR +/// subgraph Client +/// end +/// subgraph Runtime +/// end +/// end +/// ``` +/// +/// The client and the runtime of course need to communicate. This is done through two concepts: +/// +/// 1. Host functions: a way for the (Wasm) runtime to talk to the client. All host functions are +/// defined in [`sp-io`]. For example, [`sp-io::storage`] are the set of host functions that +/// allow the runtime to read and write data to the on-chain state. +/// 2. Runtime APIs: a way for the client to talk to the Wasm runtime. Runtime APIs are defined +/// using macros and utilities in [`sp-api`]. For example, [`sp-api::Core`] is the most basic +/// runtime API that any blockchain must implement in order to be able to (re) execute blocks. +/// +/// ```mermaid +/// graph TB +/// subgraph Substrate +/// direction LR +/// subgraph Client +/// end +/// subgraph Runtime +/// end +/// Client --runtime-api--> Runtime +/// Runtime --host-functions--> Client +/// end +/// ``` +/// +/// Finally, let's expand the diagram a bit further and look at the internals of each component: +/// +/// ```mermaid +/// graph TB +/// subgraph Substrate +/// direction LR +/// subgraph Client +/// Database +/// Networking +/// Consensus +/// end +/// subgraph Runtime +/// subgraph FRAME +/// direction LR +/// Governance +/// Currency +/// Staking +/// Identity +/// end +/// end +/// Client --runtime-api--> Runtime +/// Runtime --host-functions--> Client +/// end +/// ``` +/// +/// As noted the runtime contains all of the application specific logic of the blockchain. This is +/// usually written with `FRAME`. The client, on the other hand, contains reusable and generic +/// components that are not specific to one single blockchain, such as networking, database, and the +/// consensus engine. +/// +/// [`sp-io`]: ../../sp_io/index.html +/// [`sp-api`]: ../../sp_api/index.html +/// [`sp-io::storage`]: ../../sp_io/storage/index.html +/// [`sp-api::Core`]: ../../sp_api/trait.Core.html +pub mod substrate_diagram {} -- GitLab From ddf5e5c04c149f335f2274b9e920e411e83749a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 18:07:01 +0200 Subject: [PATCH 258/633] Bump the known_good_semver group with 1 update (#1802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the known_good_semver group with 1 update: [syn](https://github.com/dtolnay/syn).
Release notes

Sourced from syn's releases.

2.0.38

  • Fix "method 'peek' has an incompatible type for trait" error when defining bool as a custom keyword (#1518, thanks @​Vanille-N)
Commits
  • 43632bf Release 2.0.38
  • abd2c21 Merge pull request #1518 from Vanille-N/master
  • 6701e60 Absolute path to bool in custom_punctuation.rs
  • 7313d24 Resolve single_match_else pedantic clippy lint in code generator
  • 67ab64f Include unexpected token in the test failure message
  • 137ae33 Check no remaining token after the first literal
  • 258e9e8 Ignore single_match_else pedantic clippy lint in test
  • 92fd50e Test docs.rs documentation build in CI
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=syn&package-manager=cargo&previous-version=2.0.37&new-version=2.0.38)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 100 +++++++++--------- .../parachain-system/proc-macro/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- 17 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e925c445b6b..1559ae20180 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1091,7 +1091,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1113,7 +1113,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1130,7 +1130,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1304,7 +1304,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2484,7 +2484,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -3520,7 +3520,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4003,7 +4003,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4043,7 +4043,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4060,7 +4060,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4359,7 +4359,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4421,7 +4421,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.37", + "syn 2.0.38", "termcolor", "toml 0.7.6", "walkdir", @@ -4642,7 +4642,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4653,7 +4653,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4798,7 +4798,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5154,7 +5154,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.37", + "syn 2.0.38", "trybuild", ] @@ -5307,7 +5307,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5318,7 +5318,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5327,7 +5327,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5550,7 +5550,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7551,7 +7551,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7565,7 +7565,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7576,7 +7576,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7587,7 +7587,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -9295,7 +9295,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -10366,7 +10366,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -11233,7 +11233,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -11274,7 +11274,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -13117,7 +13117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -13199,7 +13199,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -13245,7 +13245,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -13636,7 +13636,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -14402,7 +14402,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -15614,7 +15614,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -15974,7 +15974,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -16040,7 +16040,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -16473,7 +16473,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -16873,7 +16873,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -16917,7 +16917,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -17148,7 +17148,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -17388,7 +17388,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -18069,9 +18069,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -18316,7 +18316,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -18496,7 +18496,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -18677,7 +18677,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -18720,7 +18720,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -19269,7 +19269,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -19303,7 +19303,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20444,7 +20444,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -20563,7 +20563,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index a1510847fc2..cb5d9904c7c 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.37" +syn = "2.0.38" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 83d064cadbe..1ffaf6160ba 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.37", 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/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 1ff73c64780..56df0d94f58 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.37" +syn = "2.0.38" Inflector = "0.11.4" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 202817438b7..74b8b656a40 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.37" +syn = "2.0.38" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index f18e0aacd37..b134cbce3cc 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.37", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index a04f5544067..3ada9e0c23d 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.37", features = ["full"] } +syn = { version = "2.0.38", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 39e535c6c3e..f4ea4ef6e36 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.37", 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/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 484afb6136b..0a725996115 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.37", features = ["full", "visit"] } +syn = { version = "2.0.38", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 704f355ff6c..d2854a2a79f 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.37", 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"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 7589fa353d1..fd42e18180d 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.37", 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 5bf67d43d06..06f8e0f3d53 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.37", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index de5ddcf9dac..25c87b5d0a4 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.37", 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/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index 64b46ab9c19..187b5559b93 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.37", features = ["full", "parsing"] } +syn = { version = "2.0.38", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 9d3930ac257..c97c8a0a399 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.37" +syn = "2.0.38" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 5569e31c936..fbc49785ae9 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.37", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.38", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index cc28b8f176b..7fce559e3ed 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.37", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.38", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } -- GitLab From 35ed272dade7a339605a9f8df25dd451b199deb9 Mon Sep 17 00:00:00 2001 From: Dmitry Borodin <11879032+Dmitry-Borodin@users.noreply.github.com> Date: Sat, 7 Oct 2023 04:04:00 -0500 Subject: [PATCH 259/633] migrate babe and authorship to use derive-impl (#1790) Moving a babe and authorship pallets to the latest and greatest derive_impl. Part of https://github.com/paritytech/polkadot-sdk/issues/171 --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/authorship/src/lib.rs | 33 +++------------------------ substrate/frame/babe/src/mock.rs | 28 ++++------------------- 2 files changed, 7 insertions(+), 54 deletions(-) diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index a9bd0c38cb6..56a516894de 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/mock.rs b/substrate/frame/babe/src/mock.rs index dbffe9f312e..a3f755902b5 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 -- GitLab From 5a6912606a7724932e68a034998327af17e2038a Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Sat, 7 Oct 2023 18:14:21 +0200 Subject: [PATCH 260/633] chore: bump zombienter version (#1806) Bump zombiente version. This version includes the fixes needed for `mixnet`. Thx! --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ee6b9c98733..61451a9c462 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.68" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.69" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: -- GitLab From cb944dc54882222453071fc99f2e5014c51823ef Mon Sep 17 00:00:00 2001 From: Muharem Date: Sat, 7 Oct 2023 19:32:35 +0200 Subject: [PATCH 261/633] Treasury spends various asset kinds (#1333) ### Summary This PR introduces new dispatchables to the treasury pallet, allowing spends of various asset types. The enhanced features of the treasury pallet, in conjunction with the asset-rate pallet, are set up and enabled for Westend and Rococo. ### Westend and Rococo runtimes. Polkadot/Kusams/Rococo Treasury can accept proposals for `spends` of various asset kinds by specifying the asset's location and ID. #### Treasury Instance New Dispatchables: - `spend(AssetKind, AssetBalance, Beneficiary, Option)` - propose and approve a spend; - `payout(SpendIndex)` - payout an approved spend or retry a failed payout - `check_payment(SpendIndex)` - check the status of a payout; - `void_spend(SpendIndex)` - void previously approved spend; > existing spend dispatchable renamed to spend_local in this context, the `AssetKind` parameter contains the asset's location and it's corresponding `asset_id`, for example: `USDT` on `AssetHub`, ``` rust location = MultiLocation(0, X1(Parachain(1000))) asset_id = MultiLocation(0, X2(PalletInstance(50), GeneralIndex(1984))) ``` the `Beneficiary` parameter is a `MultiLocation` in the context of the asset's location, for example ``` rust // the Fellowship salary pallet's location / account FellowshipSalaryPallet = MultiLocation(1, X2(Parachain(1001), PalletInstance(64))) // or custom `AccountId` Alice = MultiLocation(0, AccountId32(network: None, id: [1,...])) ``` the `AssetBalance` represents the amount of the `AssetKind` to be transferred to the `Beneficiary`. For permission checks, the asset amount is converted to the native amount and compared against the maximum spendable amount determined by the commanding spend origin. the `spend` dispatchable allows for batching spends with different `ValidFrom` arguments, enabling milestone-based spending. If the expectations tied to an approved spend are not met, it is possible to void the spend later using the `void_spend` dispatchable. Asset Rate Pallet provides the conversion rate from the `AssetKind` to the native balance. #### Asset Rate Instance Dispatchables: - `create(AssetKind, Rate)` - initialize a conversion rate to the native balance for the given asset - `update(AssetKind, Rate)` - update the conversion rate to the native balance for the given asset - `remove(AssetKind)` - remove an existing conversion rate to the native balance for the given asset the pallet's dispatchables can be executed by the Root or Treasurer origins. ### Treasury Pallet Treasury Pallet can accept proposals for `spends` of various asset kinds and pay them out through the implementation of the `Pay` trait. New Dispatchables: - `spend(Config::AssetKind, AssetBalance, Config::Beneficiary, Option)` - propose and approve a spend; - `payout(SpendIndex)` - payout an approved spend or retry a failed payout; - `check_payment(SpendIndex)` - check the status of a payout; - `void_spend(SpendIndex)` - void previously approved spend; > existing spend dispatchable renamed to spend_local The parameters' types of the `spend` dispatchable exposed via the pallet's `Config` and allows to propose and accept a spend of a certain amount. An approved spend can be claimed via the `payout` within the `Config::SpendPeriod`. Clients provide an implementation of the `Pay` trait which can pay an asset of the `AssetKind` to the `Beneficiary` in `AssetBalance` units. The implementation of the Pay trait might not have an immediate final payment status, for example if implemented over `XCM` and the actual transfer happens on a remote chain. The `check_status` dispatchable can be executed to update the spend's payment state and retry the `payout` if the payment has failed. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: command-bot <> --- Cargo.lock | 12 + .../assets/asset-hub-westend/Cargo.toml | 13 + .../assets/asset-hub-westend/src/tests/mod.rs | 1 + .../asset-hub-westend/src/tests/treasury.rs | 126 +++++ .../emulated/common/src/lib.rs | 2 + .../asset-hub-westend/src/xcm_config.rs | 22 +- polkadot/runtime/common/Cargo.toml | 7 + polkadot/runtime/common/src/impls.rs | 106 +++- polkadot/runtime/rococo/Cargo.toml | 6 +- polkadot/runtime/rococo/src/lib.rs | 52 +- polkadot/runtime/rococo/src/weights/mod.rs | 1 + .../rococo/src/weights/pallet_asset_rate.rs | 86 +++ .../rococo/src/weights/pallet_treasury.rs | 150 ++++-- polkadot/runtime/westend/Cargo.toml | 6 +- polkadot/runtime/westend/src/lib.rs | 57 +- polkadot/runtime/westend/src/weights/mod.rs | 1 + .../westend/src/weights/pallet_asset_rate.rs | 86 +++ .../westend/src/weights/pallet_treasury.rs | 207 +++++--- substrate/bin/node/runtime/src/lib.rs | 11 +- substrate/frame/asset-rate/src/lib.rs | 5 + substrate/frame/bounties/src/tests.rs | 23 +- substrate/frame/child-bounties/src/tests.rs | 14 +- substrate/frame/support/src/traits/tokens.rs | 3 +- .../frame/support/src/traits/tokens/misc.rs | 20 + .../frame/support/src/traits/tokens/pay.rs | 35 +- substrate/frame/tips/src/tests.rs | 24 +- substrate/frame/treasury/Cargo.toml | 7 +- substrate/frame/treasury/src/benchmarking.rs | 255 +++++++-- substrate/frame/treasury/src/lib.rs | 496 ++++++++++++++++-- substrate/frame/treasury/src/tests.rs | 426 ++++++++++++++- substrate/frame/treasury/src/weights.rs | 223 ++++++-- substrate/primitives/core/src/crypto.rs | 14 + 32 files changed, 2212 insertions(+), 285 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_asset_rate.rs diff --git a/Cargo.lock b/Cargo.lock index 1559ae20180..48ac004a859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -840,20 +840,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-common", "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "xcm-emulator", ] @@ -10567,6 +10574,7 @@ dependencies = [ name = "pallet-treasury" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -12485,6 +12493,7 @@ dependencies = [ "impl-trait-for-tuples", "libsecp256k1", "log", + "pallet-asset-rate", "pallet-authorship", "pallet-babe", "pallet-balances", @@ -12519,6 +12528,7 @@ dependencies = [ "sp-staking", "sp-std", "staging-xcm", + "staging-xcm-builder", "static_assertions", ] @@ -13900,6 +13910,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-rate", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", @@ -19941,6 +19952,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-rate", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", 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 af9776cbcd9..bf141dafebf 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,17 +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" } 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} @@ -37,15 +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", "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/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs index b3841af0e6c..0c9de89c5f9 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/treasury.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs new file mode 100644 index 00000000000..cf06f58682d --- /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/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 2c9581c3a18..068f0238f49 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -46,6 +46,8 @@ 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(7)] 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 6981c290c98..a0921c50dc5 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 @@ -38,11 +38,12 @@ 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, NativeAsset, + NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -75,6 +76,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 +226,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 @@ -449,8 +456,9 @@ pub type Barrier = TrailingSetTopicAsId< // If the message is one that immediately attemps 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, ), diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 17617bf4ada..2d1aad6a575 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 0d0dee2e9ad..590593745ed 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/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index ab9b2f11acf..0b8a8624bb6 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -52,6 +52,7 @@ pallet-collective = { path = "../../../substrate/frame/collective", default-feat 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 } @@ -72,7 +73,7 @@ pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-featur 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 } @@ -131,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", @@ -207,6 +209,7 @@ 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", @@ -258,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", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 4bdcc123739..fd3e656f695 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, }; @@ -79,7 +82,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, @@ -88,7 +92,11 @@ use sp_staking::SessionIndex; #[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; @@ -385,6 +393,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); @@ -394,6 +406,7 @@ 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(); } impl pallet_treasury::Config for Runtime { @@ -413,6 +426,23 @@ impl pallet_treasury::Config for Runtime { type WeightInfo = weights::pallet_treasury::WeightInfo; type SpendFunds = Bounties; 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! { @@ -1202,6 +1232,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 { @@ -1279,6 +1321,9 @@ 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, @@ -1465,6 +1510,7 @@ mod benches { [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_asset_rate, AssetRate] [pallet_whitelist, Whitelist] // XCM [pallet_xcm, XcmPallet] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index e0c1c4f4135..9c563a67d98 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -16,6 +16,7 @@ //! A list of the different weight modules for our runtime. pub mod frame_system; +pub mod pallet_asset_rate; pub mod pallet_balances; pub mod pallet_balances_nis_counterpart_balances; pub mod pallet_bounties; 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 00000000000..da2d1958cef --- /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_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index 041d976d825..144e9d5b872 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/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index c9721935c32..58a6cc21eec 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -41,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 } @@ -143,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", @@ -228,6 +230,7 @@ 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", @@ -283,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", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 6085b6e3745..d61acf36b4c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -53,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, @@ -77,7 +82,7 @@ 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, Permill, @@ -87,7 +92,11 @@ 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; @@ -698,6 +707,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 37). + pub TreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(37).into(); pub const TipCountdown: BlockNumber = 1 * DAYS; pub const TipFindersFee: Percent = Percent::from_percent(20); @@ -707,6 +720,7 @@ 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(); } impl pallet_treasury::Config for Runtime { @@ -726,6 +740,23 @@ impl pallet_treasury::Config for Runtime { 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 { @@ -1331,6 +1362,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 { @@ -1443,6 +1486,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, } } @@ -1574,6 +1620,7 @@ mod benches { [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. diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index faa94bcac58..9ae6798d70b 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -17,6 +17,7 @@ pub mod frame_election_provider_support; pub mod frame_system; +pub mod pallet_asset_rate; pub mod pallet_bags_list; pub mod pallet_balances; pub mod pallet_conviction_voting; 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 00000000000..810dd01a170 --- /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_treasury.rs b/polkadot/runtime/westend/src/weights/pallet_treasury.rs index e2eb6abfc7b..144e9d5b872 100644 --- a/polkadot/runtime/westend/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/westend/src/weights/pallet_treasury.rs @@ -17,25 +17,24 @@ //! Autogenerated weights for `pallet_treasury` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-13, 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-o7yfgx5n-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-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=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_treasury -// --chain=westend-dev +// --output=./runtime/rococo/src/weights/ // --header=./file_header.txt -// --output=./runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,103 +47,177 @@ 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 { + /// 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: `6` + // Measured: `42` // Estimated: `1887` - // Minimum execution time: 13_644_000 picoseconds. - Weight::from_parts(13_988_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)) } - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `107` + // Measured: `143` // Estimated: `1489` - // Minimum execution time: 26_304_000 picoseconds. - Weight::from_parts(26_850_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)) } - /// Storage: `Treasury::Proposals` (r:1 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `265` + // Measured: `301` // Estimated: `3593` - // Minimum execution time: 40_318_000 picoseconds. - Weight::from_parts(41_598_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)) } - /// Storage: `Treasury::Proposals` (r:1 w:0) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + p * (8 ±0)` + // Measured: `470 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 8_250_000 picoseconds. - Weight::from_parts(10_937_873, 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_239 - .saturating_add(Weight::from_parts(82_426, 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)) } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `90` + // Measured: `127` // Estimated: `1887` - // Minimum execution time: 6_170_000 picoseconds. - Weight::from_parts(6_366_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)) } - /// 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`) - /// The range of component `p` is `[0, 100]`. + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:99 w:99) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:199 w:199) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `175 + p * (251 ±0)` - // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 39_691_000 picoseconds. - Weight::from_parts(29_703_313, 0) - .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 18_540 - .saturating_add(Weight::from_parts(42_601_290, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `331 + p * (251 ±0)` + // Estimated: `3593 + p * (5206 ±0)` + // Minimum execution time: 887_000_000 picoseconds. + Weight::from_parts(828_616_021, 0) + .saturating_add(Weight::from_parts(0, 3593)) + // Standard Error: 695_351 + .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .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/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f018639b732..9e3b8153e2b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -37,7 +37,7 @@ use frame_support::{ 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, @@ -1186,6 +1186,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 { @@ -1211,6 +1212,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 { diff --git a/substrate/frame/asset-rate/src/lib.rs b/substrate/frame/asset-rate/src/lib.rs index c3dc551f876..d4afca8b73c 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/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index a6fb89bb860..4083b05b629 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/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 24a6410f29f..1fa3d944f3d 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/support/src/traits/tokens.rs b/substrate/frame/support/src/traits/tokens.rs index 253b49c6671..3635311e643 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/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index e8587be1017..fd497bc4eda 100644 --- a/substrate/frame/support/src/traits/tokens/misc.rs +++ b/substrate/frame/support/src/traits/tokens/misc.rs @@ -277,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 78f8e7b8734..18af7e5e548 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/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 20d4b2c1a4c..8fe111afc26 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! { diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 785564cd988..f7f7a6ae89c 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 24c290ddb66..f5f73ea8dda 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,81 +95,245 @@ 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); diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 730fae2a4e9..b2b3a8801c1 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. //! -//! ## Interface +//! ### Example //! -//! ### Dispatchable Functions +//! 1. Multiple local spends approved by spend origins and received by a beneficiary. +#![doc = docify::embed!("src/tests.rs", spend_local_origin_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. +//! 2. Approve a spend of some asset kind and claim it. +#![doc = docify::embed!("src/tests.rs", spend_payout_works)] //! -//! ## GenesisConfig +//! ## Pallet API //! -//! The Treasury pallet depends on the [`GenesisConfig`]. +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. +//! +//! ## 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; @@ -75,7 +91,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use frame_support::{ print, traits::{ - Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, + tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, ReservableCurrency, WithdrawReasons, }, weights::Weight, @@ -87,6 +103,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 +111,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 +151,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 +256,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 +317,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 +382,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 +407,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 +416,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] @@ -328,12 +465,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 +507,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 +547,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 +584,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 +647,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 +686,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(()) + } } } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index ba45d5f6ff1..4bb00547d9f 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,6 +207,14 @@ 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 { @@ -151,6 +229,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } +fn get_payment_id(i: SpendIndex) -> Option { + let spend = Spends::::get(i).expect("no spend"); + match spend.status { + PaymentState::Attempted { id } => Some(id), + _ => None, + } +} + #[test] fn genesis_config_works() { new_test_ext().execute_with(|| { @@ -160,46 +246,49 @@ fn genesis_config_works() { } #[test] -fn spend_origin_permissioning_works() { +fn spend_local_origin_permissioning_works() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::spend(RuntimeOrigin::signed(1), 1, 1), BadOrigin); + 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() { +fn spend_local_origin_works() { new_test_ext().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); }); } @@ -578,14 +667,49 @@ fn remove_already_removed_approval_fails() { }); } +#[test] +fn spending_local_in_batch_respects_max_total() { + new_test_ext().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(|| { // 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 +717,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 +736,251 @@ fn spending_in_batch_respects_max_total() { ); }) } + +#[test] +fn spend_origin_works() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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() { + new_test_ext().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()); + }); +} diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index 8f1418f76d9..030e18980eb 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/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 8c7d98f00cd..be9f56eb2ba 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::*; @@ -1171,6 +1178,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); -- GitLab From 1dc935c715ac715ac8f8fce2907ef8b2af2c8c38 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Mon, 9 Oct 2023 12:15:30 +0200 Subject: [PATCH 262/633] [xcm-emulator] Decouple the `AccountId` type from `AccountId32` (#1458) Closes: #1381 Originally from: https://github.com/paritytech/cumulus/pull/3037 --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- cumulus/xcm/xcm-emulator/src/lib.rs | 57 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 9fda0632bae..caf73ae1e41 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(), -- GitLab From a808a3a0918ffbce314dbe00e03761e7a8f8ce79 Mon Sep 17 00:00:00 2001 From: David Emett Date: Mon, 9 Oct 2023 15:56:30 +0200 Subject: [PATCH 263/633] Mixnet integration (#1346) See #1345, . This adds all the necessary mixnet components, and puts them together in the "kitchen-sink" node/runtime. The components added are: - A pallet (`frame/mixnet`). This is responsible for determining the current mixnet session and phase, and the mixnodes to use in each session. It provides a function that validators can call to register a mixnode for the next session. The logic of this pallet is very similar to that of the `im-online` pallet. - A service (`client/mixnet`). This implements the core mixnet logic, building on the `mixnet` crate. The service communicates with other nodes using notifications sent over the "mixnet" protocol. - An RPC interface. This currently only supports sending transactions over the mixnet. --------- Co-authored-by: David Emett Co-authored-by: Javier Viola --- Cargo.lock | 311 +++++++-- Cargo.toml | 3 + substrate/bin/node/cli/Cargo.toml | 2 + .../bin/node/cli/benches/block_production.rs | 2 +- .../bin/node/cli/benches/transaction_pool.rs | 2 +- substrate/bin/node/cli/src/chain_spec.rs | 32 +- substrate/bin/node/cli/src/cli.rs | 4 + substrate/bin/node/cli/src/command.rs | 19 +- substrate/bin/node/cli/src/service.rs | 66 +- substrate/bin/node/rpc/Cargo.toml | 1 + substrate/bin/node/rpc/src/lib.rs | 9 + substrate/bin/node/runtime/Cargo.toml | 6 + substrate/bin/node/runtime/src/lib.rs | 45 +- substrate/bin/node/testing/src/genesis.rs | 1 + substrate/bin/node/testing/src/keyring.rs | 1 + .../bin/utils/chain-spec-builder/src/lib.rs | 4 +- substrate/client/cli/Cargo.toml | 1 + .../client/cli/src/params/mixnet_params.rs | 67 ++ substrate/client/cli/src/params/mod.rs | 8 +- substrate/client/mixnet/Cargo.toml | 36 ++ substrate/client/mixnet/README.md | 3 + substrate/client/mixnet/src/api.rs | 69 ++ substrate/client/mixnet/src/config.rs | 88 +++ substrate/client/mixnet/src/error.rs | 56 ++ .../client/mixnet/src/extrinsic_queue.rs | 94 +++ substrate/client/mixnet/src/lib.rs | 44 ++ .../client/mixnet/src/maybe_inf_delay.rs | 111 ++++ .../client/mixnet/src/packet_dispatcher.rs | 198 ++++++ substrate/client/mixnet/src/peer_id.rs | 44 ++ substrate/client/mixnet/src/protocol.rs | 42 ++ substrate/client/mixnet/src/request.rs | 119 ++++ substrate/client/mixnet/src/run.rs | 388 ++++++++++++ .../client/mixnet/src/sync_with_runtime.rs | 228 +++++++ .../client/network/src/protocol_controller.rs | 13 +- substrate/client/rpc-api/Cargo.toml | 1 + substrate/client/rpc-api/src/error.rs | 1 + substrate/client/rpc-api/src/lib.rs | 1 + substrate/client/rpc-api/src/mixnet/error.rs | 48 ++ substrate/client/rpc-api/src/mixnet/mod.rs | 31 + substrate/client/rpc/Cargo.toml | 1 + substrate/client/rpc/src/lib.rs | 1 + substrate/client/rpc/src/mixnet/mod.rs | 47 ++ substrate/frame/mixnet/Cargo.toml | 57 ++ substrate/frame/mixnet/README.md | 4 + substrate/frame/mixnet/src/lib.rs | 598 ++++++++++++++++++ substrate/primitives/core/src/crypto.rs | 2 + substrate/primitives/mixnet/Cargo.toml | 30 + substrate/primitives/mixnet/README.md | 3 + substrate/primitives/mixnet/src/lib.rs | 24 + .../primitives/mixnet/src/runtime_api.rs | 52 ++ substrate/primitives/mixnet/src/types.rs | 100 +++ substrate/scripts/ci/deny.toml | 1 + 52 files changed, 3010 insertions(+), 109 deletions(-) create mode 100644 substrate/client/cli/src/params/mixnet_params.rs create mode 100644 substrate/client/mixnet/Cargo.toml create mode 100644 substrate/client/mixnet/README.md create mode 100644 substrate/client/mixnet/src/api.rs create mode 100644 substrate/client/mixnet/src/config.rs create mode 100644 substrate/client/mixnet/src/error.rs create mode 100644 substrate/client/mixnet/src/extrinsic_queue.rs create mode 100644 substrate/client/mixnet/src/lib.rs create mode 100644 substrate/client/mixnet/src/maybe_inf_delay.rs create mode 100644 substrate/client/mixnet/src/packet_dispatcher.rs create mode 100644 substrate/client/mixnet/src/peer_id.rs create mode 100644 substrate/client/mixnet/src/protocol.rs create mode 100644 substrate/client/mixnet/src/request.rs create mode 100644 substrate/client/mixnet/src/run.rs create mode 100644 substrate/client/mixnet/src/sync_with_runtime.rs create mode 100644 substrate/client/rpc-api/src/mixnet/error.rs create mode 100644 substrate/client/rpc-api/src/mixnet/mod.rs create mode 100644 substrate/client/rpc/src/mixnet/mod.rs create mode 100644 substrate/frame/mixnet/Cargo.toml create mode 100644 substrate/frame/mixnet/README.md create mode 100644 substrate/frame/mixnet/src/lib.rs create mode 100644 substrate/primitives/mixnet/Cargo.toml create mode 100644 substrate/primitives/mixnet/README.md create mode 100644 substrate/primitives/mixnet/src/lib.rs create mode 100644 substrate/primitives/mixnet/src/runtime_api.rs create mode 100644 substrate/primitives/mixnet/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 48ac004a859..cc80e2542fb 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]] @@ -571,6 +571,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" @@ -1276,7 +1282,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", @@ -1353,6 +1359,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" @@ -2180,6 +2198,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" @@ -2236,7 +2264,7 @@ checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" dependencies = [ "aead 0.3.2", "cipher 0.2.5", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -2269,6 +2297,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" @@ -3134,7 +3172,7 @@ checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3146,7 +3184,7 @@ checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3161,6 +3199,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" @@ -3168,7 +3216,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]] @@ -3178,7 +3226,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]] @@ -3741,7 +3789,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", @@ -3968,7 +4016,7 @@ dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3981,7 +4029,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3998,7 +4046,7 @@ dependencies = [ "fiat-crypto", "platforms", "rustc_version 0.4.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4313,7 +4361,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -4582,7 +4630,7 @@ dependencies = [ "pkcs8 0.9.0", "rand_core 0.6.4", "sec1 0.3.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4601,7 +4649,7 @@ dependencies = [ "pkcs8 0.10.2", "rand_core 0.6.4", "sec1 0.7.3", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4801,7 +4849,7 @@ 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", @@ -4902,7 +4950,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]] @@ -4912,7 +4960,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]] @@ -5065,7 +5113,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame-benchmarking" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-support", "frame-support-procedural", "frame-system", @@ -5093,7 +5141,7 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" dependencies = [ "Inflector", - "array-bytes", + "array-bytes 6.1.0", "chrono", "clap 4.4.6", "comfy-table", @@ -5204,7 +5252,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", @@ -5261,7 +5309,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", @@ -5791,7 +5839,7 @@ checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -5802,7 +5850,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -5888,6 +5936,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" @@ -6663,6 +6720,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" @@ -6711,6 +6774,7 @@ dependencies = [ "pallet-lottery", "pallet-membership", "pallet-message-queue", + "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", @@ -6764,6 +6828,7 @@ dependencies = [ "sp-genesis-builder", "sp-inherents", "sp-io", + "sp-mixnet", "sp-offchain", "sp-runtime", "sp-session", @@ -7366,7 +7431,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -7449,6 +7514,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" @@ -7779,6 +7856,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" @@ -8080,7 +8182,7 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "clap 4.4.6", "derive_more", "fs_extra", @@ -8116,7 +8218,7 @@ dependencies = [ name = "node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_cmd", "clap 4.4.6", "clap_complete", @@ -8157,6 +8259,7 @@ dependencies = [ "sc-consensus-slots", "sc-executor", "sc-keystore", + "sc-mixnet", "sc-network", "sc-network-common", "sc-network-statement", @@ -8186,6 +8289,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-keystore", + "sp-mixnet", "sp-runtime", "sp-statement-store", "sp-timestamp", @@ -8277,6 +8381,7 @@ dependencies = [ "sc-consensus-babe-rpc", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", + "sc-mixnet", "sc-rpc", "sc-rpc-api", "sc-rpc-spec-v2", @@ -8723,7 +8828,7 @@ dependencies = [ name = "pallet-alliance" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-benchmarking", "frame-support", "frame-system", @@ -9026,7 +9131,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", @@ -9249,7 +9354,7 @@ dependencies = [ 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", @@ -9583,7 +9688,7 @@ dependencies = [ name = "pallet-glutton" version = "4.0.0-dev" dependencies = [ - "blake2", + "blake2 0.10.6", "frame-benchmarking", "frame-support", "frame-system", @@ -9751,11 +9856,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", @@ -10553,7 +10677,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", @@ -10946,7 +11070,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", @@ -13787,7 +13911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -13800,7 +13924,7 @@ dependencies = [ "ark-poly", "ark-serialize", "ark-std", - "blake2", + "blake2 0.10.6", "common", "fflonk", "merlin 3.0.0", @@ -14420,7 +14544,7 @@ dependencies = [ name = "sc-cli" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "chrono", "clap 4.4.6", "fdlimit", @@ -14436,6 +14560,7 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-keystore", + "sc-mixnet", "sc-network", "sc-service", "sc-telemetry", @@ -14490,7 +14615,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", @@ -14655,7 +14780,7 @@ dependencies = [ name = "sc-consensus-beefy" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "async-trait", "fnv", @@ -14731,7 +14856,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", @@ -14886,7 +15011,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", @@ -14973,7 +15098,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", @@ -14983,11 +15108,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", @@ -15102,7 +15254,7 @@ dependencies = [ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "futures", "libp2p-identity", @@ -15122,7 +15274,7 @@ dependencies = [ name = "sc-network-statement" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "futures", "libp2p", @@ -15139,7 +15291,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", @@ -15209,7 +15361,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "futures", "libp2p", "log", @@ -15226,7 +15378,7 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "bytes", "fnv", "futures", @@ -15286,6 +15438,7 @@ dependencies = [ "sc-block-builder", "sc-chain-spec", "sc-client-api", + "sc-mixnet", "sc-network", "sc-network-common", "sc-rpc-api", @@ -15317,6 +15470,7 @@ dependencies = [ "jsonrpsee", "parity-scale-codec", "sc-chain-spec", + "sc-mixnet", "sc-transaction-pool-api", "scale-info", "serde", @@ -15346,7 +15500,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", @@ -15459,7 +15613,7 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "fdlimit", "futures", @@ -15632,7 +15786,7 @@ dependencies = [ 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", @@ -15752,7 +15906,7 @@ dependencies = [ "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -15826,7 +15980,7 @@ dependencies = [ "der 0.6.1", "generic-array 0.14.7", "pkcs8 0.9.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -15840,7 +15994,7 @@ dependencies = [ "der 0.7.8", "generic-array 0.14.7", "pkcs8 0.10.2", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -16405,14 +16559,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]] @@ -16479,7 +16633,7 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "assert_matches", - "blake2", + "blake2 0.10.6", "expander 2.0.0", "proc-macro-crate", "proc-macro2", @@ -16747,7 +16901,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", @@ -16821,10 +16975,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", @@ -17029,11 +17183,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", @@ -17231,7 +17396,7 @@ dependencies = [ name = "sp-state-machine" version = "0.28.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "hash-db", "log", @@ -17353,7 +17518,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", @@ -17659,7 +17824,7 @@ dependencies = [ "md-5", "rand 0.8.5", "ring 0.16.20", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "url", @@ -17825,7 +17990,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-trait", "futures", "parity-scale-codec", @@ -17850,7 +18015,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-executive", "frame-support", "frame-system", @@ -17964,6 +18129,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" @@ -19055,7 +19226,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]] @@ -19065,7 +19236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -19814,7 +19985,7 @@ dependencies = [ "sha1", "sha2 0.10.7", "signature 1.6.4", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "webpki 0.21.4", @@ -19908,7 +20079,7 @@ dependencies = [ "rtcp", "rtp", "sha-1 0.9.8", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "webrtc-util", diff --git a/Cargo.toml b/Cargo.toml index aa0b93737f7..75da6681465 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -217,6 +217,7 @@ 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", @@ -298,6 +299,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", @@ -394,6 +396,7 @@ 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", diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 5ce4c73f98c..49dc39099be 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -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" } diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index b877aa73502..246de8f3e92 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 d21edc55bba..47f89057415 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -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 { diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 51beaad0368..52b480925aa 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 4e0d6303870..f3c0435fd32 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 6bd8b76581a..16d0415ff26 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -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 977c90e73e9..5a85f4cde0a 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/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index ec8d16bd27d..43db4ab9d34 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 6d8aa5ff0a9..acc58777e91 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 7771b5f2097..e5bade12029 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -35,6 +35,7 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-genesis-builder = { version = "0.1.0-dev", 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} @@ -88,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} @@ -185,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", @@ -235,6 +238,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-mixnet/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -281,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", @@ -354,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 9e3b8153e2b..2070e3f12d0 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -589,6 +589,7 @@ impl_opaque_keys! { pub babe: Babe, pub im_online: ImOnline, pub authority_discovery: AuthorityDiscovery, + pub mixnet: Mixnet, } } @@ -1048,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 = @@ -2028,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 { @@ -2104,6 +2128,7 @@ construct_runtime!( SafeMode: pallet_safe_mode, Statement: pallet_statement, Broker: pallet_broker, + Mixnet: pallet_mixnet, } ); @@ -2663,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) diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 6e7bcebfc00..ab5311751a5 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 b4b714d9083..22a8f5deb19 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/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 528b6b70115..2b88e40ef74 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/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index b78287be890..98928700328 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -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/params/mixnet_params.rs b/substrate/client/cli/src/params/mixnet_params.rs new file mode 100644 index 00000000000..4758a84ec45 --- /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 a73bd8844fe..f07223ec6a7 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/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml new file mode 100644 index 00000000000..86c5a37754a --- /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 00000000000..cd8d1474083 --- /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 00000000000..42a2e395345 --- /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 00000000000..b716237ab7b --- /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 00000000000..88942dbe3b3 --- /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 00000000000..b6f6f9ebae9 --- /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 00000000000..dfbb50dad6b --- /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 00000000000..feb0d038560 --- /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 00000000000..856208ecb34 --- /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 00000000000..7984da8c75b --- /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 00000000000..555c267b86e --- /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 00000000000..18a74c7ea5c --- /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 00000000000..09020469d5e --- /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 00000000000..4a80b3c75f4 --- /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/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index c9baa0a77d4..3a305011ded 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/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index a2ee090b1c2..9dca2e72fcd 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 72941e3145b..58b75b8fb16 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 b99c237dc85..32120d37902 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 00000000000..0dde5f32e61 --- /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 00000000000..bc478cf3bf3 --- /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/Cargo.toml b/substrate/client/rpc/Cargo.toml index 64aaa7c94aa..dd1120e5b0f 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/lib.rs b/substrate/client/rpc/src/lib.rs index 475fc77a9b5..94fdb2d734f 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 00000000000..3f3d9c5aa45 --- /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/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml new file mode 100644 index 00000000000..68ffdad20fc --- /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 00000000000..59b81851ed1 --- /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 00000000000..c7a5b624157 --- /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/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index be9f56eb2ba..e1bfb80046f 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1161,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"); } diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml new file mode 100644 index 00000000000..3e2dcc7ec5c --- /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 00000000000..47c109f6b57 --- /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/substrate/primitives/mixnet/src/lib.rs b/substrate/primitives/mixnet/src/lib.rs new file mode 100644 index 00000000000..58b8a10f0cd --- /dev/null +++ b/substrate/primitives/mixnet/src/lib.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Substrate mixnet types and runtime interface. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +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 00000000000..28ab40e6337 --- /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 00000000000..fc214f94d1c --- /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/scripts/ci/deny.toml b/substrate/scripts/ci/deny.toml index 5297d07143c..ca059e384a3 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" }, -- GitLab From 98286ade0b5e8edf1521078c454404c7afaab438 Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:39:12 +0200 Subject: [PATCH 264/633] Fix Asset Hub collator crashing when starting from genesis (#1788) --- cumulus/polkadot-parachain/src/command.rs | 6 +- cumulus/polkadot-parachain/src/service.rs | 155 +++++++++++++++++++++- 2 files changed, 154 insertions(+), 7 deletions(-) diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 0e948d24f82..c47555a3216 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -836,21 +836,21 @@ 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::AssetHubWestend => crate::service::start_asset_hub_node::< asset_hub_westend_runtime::RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 2f86f54f12a..fa61f534784 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -14,7 +14,7 @@ // 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::{ @@ -44,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, @@ -54,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; @@ -1389,6 +1393,149 @@ 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. -- GitLab From 93d9c8c24e5d470e036caaa23df08dcf0c527dd6 Mon Sep 17 00:00:00 2001 From: David Emett Date: Tue, 10 Oct 2023 09:14:56 +0200 Subject: [PATCH 265/633] Make CheckNonce refuse transactions signed by accounts with no providers (#1578) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See #1453. Co-authored-by: Bastian Köcher --- .../node/executor/tests/submit_transaction.rs | 2 +- .../client/service/test/src/client/mod.rs | 25 +++------ .../system/src/extensions/check_nonce.rs | 56 ++++++++++++++++++- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/substrate/bin/node/executor/tests/submit_transaction.rs b/substrate/bin/node/executor/tests/submit_transaction.rs index 7678a3c6e5a..5cbb0103d47 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/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index c40ac33da4b..f8200875587 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/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index 2939fd6534c..7504a814aef 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)); + }) + } } -- GitLab From 2b4b33d01f22b1f4037a404597357f398e21224f Mon Sep 17 00:00:00 2001 From: Rahul Subramaniyam <78006270+rahulksnv@users.noreply.github.com> Date: Tue, 10 Oct 2023 02:46:23 -0700 Subject: [PATCH 266/633] Check for parent of first ready block being on chain (#1812) When retrieving the ready blocks, verify that the parent of the first ready block is on chain. If the parent is not on chain, we are downloading from a fork. In this case, keep downloading until we have a parent on chain (common ancestor). Resolves https://github.com/paritytech/polkadot-sdk/issues/493. --------- Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> --- substrate/client/network/sync/src/blocks.rs | 25 ++ substrate/client/network/sync/src/lib.rs | 397 +++++++++++++++++++- 2 files changed, 421 insertions(+), 1 deletion(-) diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index 240c1ca1f8b..cad50fef3e3 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/lib.rs b/substrate/client/network/sync/src/lib.rs index 10eaa245051..a291da4a90d 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -1405,8 +1405,27 @@ where /// 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 @@ -3364,4 +3383,380 @@ mod test { 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()); + } } -- GitLab From ebf442336f14f45d0a6522b65e68f567107cfb46 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 10 Oct 2023 14:20:25 +0300 Subject: [PATCH 267/633] Update bridges subtree (#1803) --- .../runtime-common/src/messages_call_ext.rs | 29 ++++- .../src/refund_relayer_extension.rs | 107 +++++++++++++++++- bridges/modules/grandpa/src/call_ext.rs | 21 +++- bridges/modules/parachains/src/call_ext.rs | 19 +++- 4 files changed, 164 insertions(+), 12 deletions(-) diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index 07a99d2c0a1..5303fcb7ba0 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/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index 876c069dc0f..6d8b2114808 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -838,21 +838,23 @@ mod tests { mock::*, }; use bp_messages::{ - DeliveredMessages, InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayer, - UnrewardedRelayersState, + 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}, @@ -1592,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(|| { diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index e0648d5dd0f..f238064f92b 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/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index 99640dadc61..198ff11be49 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(|| { -- GitLab From e3c97e486010d443cb20f8bbb29d404527665a1a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 10 Oct 2023 13:26:22 +0200 Subject: [PATCH 268/633] [xcm] Use `Weight::MAX` for `reserve_asset_deposited`, `receive_teleported_asset` benchmarks (#1726) # Description ## Summary Previously, the `pallet_xcm::do_reserve_transfer_assets` and `pallet_xcm::do_teleport_assets` functions relied on weight estimation for remote chain execution, which was based on guesswork derived from the local chain. This approach led to complications for runtimes that did not provide or support specific [XCM configurations](https://github.com/paritytech/polkadot-sdk/blob/7cbe0c76ef8fd2aabf9f07de0156941ce3ed44b0/polkadot/xcm/xcm-executor/src/config.rs#L43-L47) for `IsReserve` or `IsTeleporter`. Consequently, such runtimes had to resort to implementing hard-coded weights for XCM instructions like `reserve_asset_deposited` or `receive_teleported_asset` to support extrinsics such as `pallet_xcm::reserve_transfer_assets` and `pallet_xcm::teleport_assets`, which depended on remote weight estimation. The issue of remote weight estimation was addressed and resolved by [Pull Request #1645](https://github.com/paritytech/polkadot-sdk/pull/1645), which removed the need for remote weight estimation. ## Solution As a continuation of this improvement, the current PR proposes further cleanup by removing unnecessary hard-coded values and rectifying benchmark results with `Weight::MAX` that previously used `T::BlockWeights::get().max_block` as an override for unsupported XCM instructions like `ReserveAssetDeposited` and `ReceiveTeleportedAsset`. ## Questions - [x] Can we remove now also `Hardcoded till the XCM pallet is fixed` for `deposit_asset`? E.g. for AssetHubKusama [here](https://github.com/paritytech/polkadot-sdk/blob/7cbe0c76ef8fd2aabf9f07de0156941ce3ed44b0/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs#L129-L134) - [x] Are comments like [this](https://github.com/paritytech/polkadot-sdk/blob/7cbe0c76ef8fd2aabf9f07de0156941ce3ed44b0/polkadot/runtime/kusama/src/weights/xcm/mod.rs#L94) `// Kusama doesn't support ReserveAssetDeposited, so this benchmark has a default weight` still relevant? Shouldnt be removed/changed? ## TODO - [x] `bench bot` regenerate xcm weights for all runtimes - [x] remove hard-coded stuff from system parachain weight files - [ ] when merged, open `polkadot-fellow/runtimes` PR ## References Fixes #1132 Closes #1132 Old polkadot repo [PR](https://github.com/paritytech/polkadot/pull/7546) --------- Co-authored-by: command-bot <> --- .../src/tests/reserve_transfer.rs | 11 +- .../asset-hub-westend/src/tests/send.rs | 4 +- .../asset-hub-westend/src/tests/teleport.rs | 168 +++++++++--------- .../emulated/common/src/impls.rs | 16 ++ .../asset-hub-kusama/src/weights/xcm/mod.rs | 17 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 78 ++++---- .../asset-hub-polkadot/src/weights/xcm/mod.rs | 17 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++++--- .../asset-hub-westend/src/weights/xcm/mod.rs | 17 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++++--- .../bridge-hub-kusama/src/weights/xcm/mod.rs | 17 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++++--- .../src/weights/xcm/mod.rs | 22 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++++--- .../bridge-hub-rococo/src/weights/xcm/mod.rs | 17 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++++--- .../runtime/rococo/src/weights/xcm/mod.rs | 1 - .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 +++---- .../runtime/westend/src/weights/xcm/mod.rs | 1 - .../xcm/pallet_xcm_benchmarks_fungible.rs | 60 +++---- .../src/fungible/benchmarking.rs | 5 +- 21 files changed, 381 insertions(+), 454 deletions(-) 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 51fac43be12..805c8811b2d 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(); 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 424d222bef3..d0a71e88c67 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 @@ -119,8 +119,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/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index 8de73a7420c..d94fd4b97d9 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,75 @@ 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_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); -// } - -// /// 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 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); -// } +/// 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 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); + 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); +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 024ae65c51e..5e11922d859 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -503,6 +503,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!( 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 9aff4902d15..ce6e9206515 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 6e663039b0c..9b8611fd663 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-polkadot/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs index 55fed809e2b..eb140c4bf32 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 4f64ea3fa1b..96d86ec423f 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-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs index bb850ac72c0..3e47cf077a2 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 d6763d2fc66..f482064e84e 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/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 0e740922f33..ded5dc6702e 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 6c8c7ab66bb..17ee5cb6a8d 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-polkadot/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs index 4f8c2dec7a8..7e9f2184272 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 7c525dca051..f45f3936365 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-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs index 40a2036fb49..78a0eed9174 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 8f9fbc91245..cd1a673cb53 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/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs index 1d613717dc5..cc485dfbaf7 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 59c49e4f8c8..60c40429b1a 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/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index c6fa6bb93eb..d5b3d8257ba 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 b92749bfa15..87e63fbe310 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/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 504b7954039..760fa33b693 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 { -- GitLab From 64877492c5680af48cb97e0b4d1e3801a18353f0 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 10 Oct 2023 16:02:35 +0200 Subject: [PATCH 269/633] [FRAME] Warn on unchecked weight witness (#1818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a warning to FRAME pallets when a function argument that starts with `_` is used in the weight formula. This is in most cases an error since the weight witness needs to be checked. Example: ```rust #[pallet::call_index(0)] #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] pub fn remark(_origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { Ok(().into()) } ``` Produces this warning: ```pre warning: 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: --> substrate/frame/system/src/lib.rs:424:40 | 424 | pub fn remark(_origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { | ^^^^^^^ | = note: `#[warn(deprecated)]` on by default ``` Can be suppressed like this, since in this case it is legit: ```rust #[pallet::call_index(0)] #[pallet::weight(T::SystemWeightInfo::remark(remark.len() as u32))] pub fn remark(_origin: OriginFor, remark: Vec) -> DispatchResultWithPostInfo { let _ = remark; // We dont need to check the weight witness. Ok(().into()) } ``` Changes: - Add warning on uncheded weight witness - Respect `subkeys` limit in `System::kill_prefix` - Fix HRMP pallet and other warnings - Update`proc_macro_warning` dependency - Delete random folder `substrate/src/src` 🙈 - Adding Prdoc --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 8 +- polkadot/runtime/parachains/src/hrmp.rs | 40 ++- prdoc/pr_1818.prdoc | 16 + .../elections-phragmen/src/benchmarking.rs | 2 +- substrate/frame/elections-phragmen/src/lib.rs | 9 +- substrate/frame/root-testing/src/lib.rs | 2 +- substrate/frame/sudo/src/lib.rs | 5 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../procedural/src/construct_runtime/mod.rs | 2 +- .../procedural/src/pallet/expand/call.rs | 20 +- .../procedural/src/pallet/expand/mod.rs | 1 + .../procedural/src/pallet/expand/warnings.rs | 102 ++++++ substrate/frame/support/test/tests/pallet.rs | 5 +- .../support/test/tests/pallet_instance.rs | 5 +- .../call_weight_unchecked_warning.rs | 38 +++ .../call_weight_unchecked_warning.stderr | 12 + substrate/frame/system/src/lib.rs | 11 +- substrate/frame/utility/src/lib.rs | 6 +- substrate/src/src/lib.rs | 297 ------------------ 19 files changed, 243 insertions(+), 340 deletions(-) create mode 100644 prdoc/pr_1818.prdoc create mode 100644 substrate/frame/support/procedural/src/pallet/expand/warnings.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr delete mode 100644 substrate/src/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index cc80e2542fb..cc8415a5a23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13327,9 +13327,9 @@ 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", @@ -13338,9 +13338,9 @@ dependencies = [ [[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", ] diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index b3bbcb433c0..42592d9d9f1 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -554,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(()) } @@ -575,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(()) @@ -592,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(()) } diff --git a/prdoc/pr_1818.prdoc b/prdoc/pr_1818.prdoc new file mode 100644 index 00000000000..cbafa02f9af --- /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/substrate/frame/elections-phragmen/src/benchmarking.rs b/substrate/frame/elections-phragmen/src/benchmarking.rs index 56ea19578c8..9878f7fd41c 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 6912649bd12..93f9fc2b6d2 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/root-testing/src/lib.rs b/substrate/frame/root-testing/src/lib.rs index e04c7bfa13d..bbcda09c306 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/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 0c869bec7f0..fb29c0da42a 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/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index d2854a2a79f..9781a882514 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.38", features = ["full"] } frame-support-procedural-tools = { path = "tools" } -proc-macro-warning = { version = "0.4.2", default-features = false } +proc-macro-warning = { version = "1.0.0", default-features = false } macro_magic = { version = "0.4.2", features = ["proc_support"] } expander = "2.0.0" sp-core-hashing = { path = "../../../primitives/core/hashing" } diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index e8c3c088921..c3d433643fd 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -414,7 +414,7 @@ fn construct_runtime_final_expansion( ) .help_links(&["https://github.com/paritytech/substrate/pull/14437"]) .span(where_section.span) - .build(), + .build_or_panic(), ) }); diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index 3ed5509863e..ed6335159cd 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/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 2b998227c1d..6f32e569751 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/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs new file mode 100644 index 00000000000..ae5890878a2 --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -0,0 +1,102 @@ +// 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/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 1898246470c..83ae5b9253c 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 8d2d52d1885..724734ec4fc 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_weight_unchecked_warning.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.rs new file mode 100644 index 00000000000..8d93638f5a5 --- /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 00000000000..89fc1e0820f --- /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/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 84b6dc03145..897d3bd7ce9 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/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index af212a31eb9..7f963e3637d 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/src/src/lib.rs b/substrate/src/src/lib.rs deleted file mode 100644 index 16a60677896..00000000000 --- a/substrate/src/src/lib.rs +++ /dev/null @@ -1,297 +0,0 @@ -// 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 -//! -//! 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) -//! -//! This crate in itself does not contain any code and is just meant ot be a documentation hub for -//! substrate-based crates. -//! -//! ## Overview -//! -//! Substrate approaches blockchain development with an acknowledgement of a few self-evident -//! truths: -//! -//! 1. Society and technology evolves. -//! 2. Humans are fallible. -//! -//! This, specifically, makes the task of designing a correct, safe and long-lasting blockchain -//! system hard. -//! -//! Nonetheless, in order to achieve this goal, substrate embraces the following: -//! -//! 1. Use of **Rust** as a modern, and safe programming language, which limits human error through -//! various means, most notably memory safety. -//! 2. Substrate is written from the ground-up with a generic, modular and extensible design. This -//! ensures that software components can be easily swapped and upgraded. Examples of this is -//! multiple consensus mechanisms provided by Substrate, as listed below. -//! 3. Lastly, the final blockchain system created with the above properties needs to be -//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the -//! application logic of the blockchain (called "Runtime") is encoded as a Wasm blob, and is -//! stored onchain. The rest of the system (called "Client") acts as the executor of the Wasm -//! blob. -//! -//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as Wasm blob" -//! accord. This enables the Runtime to become inherently upgradeable (without forks). The upgrade -//! is merely a matter of the Wasm blob being changed in the chain state, which is, in principle, -//! same as updating an account's balance. -//! -//! To learn more about the substrate architecture using some visuals, see [`substrate_diagram`]. -//! -//! `FRAME`, Substrate's default runtime development library takes the above even further by -//! embracing a declarative programming model whereby correctness is enhanced and the system is -//! highly configurable through parameterization. -//! -//! All in all, this design enables all substrate-based chains to achieve forkless, self-enacting -//! upgrades out of the box. Combined with governance abilities that are shipped with `FRAME`, this -//! enables a chain to survive the test of time. -//! -//! ## How to Get Stared -//! -//! Most developers want to leave the client side code as-is, and focus on the runtime. To do so, -//! look into the [`frame_support`] crate, which is the entry point crate into runtime development -//! with FRAME. -//! -//! > Side note, it is entirely possible to craft a substrate-based runtime without FRAME, an -//! > example of which can be found [here](https://github.com/JoshOrndorff/frameless-node-template). -//! -//! In more broad terms, the following avenues exist into developing with substrate: -//! -//! * **Templates**: A number of substrate-based templates exist and they can be used for various -//! purposes, with zero to little additional code needed. All of these templates contain runtimes -//! that are highly configurable and are likely suitable for basic needs. -//! * `FRAME`: If need, one can customize that runtime even further, by using `FRAME` and developing -//! custom modules. -//! * **Core**: To the contrary, some developers may want to customize the client side software to -//! achieve novel goals such as a new consensus engine, or a new database backend. While -//! Substrate's main configurability is in the runtime, the client is also highly generic and can -//! be customized to a great extent. -//! -//! ## Structure -//! -//! Substrate is a massive cargo workspace with hundreds of crates, therefore it is useful to know -//! how to navigate its crates. -//! -//! In broad terms, it is divided into three categories: -//! -//! * `sc-*` (short for *substrate-client*) crates, located under `./client` folder. These are all -//! the client crates. Notable examples are crates such as [`sc-network`], various consensus -//! crates, [`sc-rpc-api`] and [`sc-client-db`], all of which are expected to reside in the client -//! side. -//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These -//! are the traits that glue the client and runtime together, but are not opinionated about what -//! framework is using for building the runtime. Notable examples are [`sp-api`] and [`sp-io`], -//! which form the communication bridge between the client and runtime, as explained in -//! [`substrate_diagram`]. -//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related -//! to FRAME. See [`frame_support`] for more information. -//! -//! ### Wasm Build -//! -//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both Wasm (when a Wasm -//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate -//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a -//! crate is being built with the standard library, and is built for native. Otherwise, it is built -//! for `no_std`. -//! -//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find -//! in any Substrate-based runtime. -//! -//! Substrate-based runtimes use [`substrate-wasm-builder`] in their `build.rs` to automatically -//! build their Wasm files as a part of normal build commandsOnce built, the wasm file is placed in -//! `./target/{debug|release}/wbuild/{runtime_name}.wasm`. -//! -//! ### Binaries -//! -//! Multiple binaries are shipped with substrate, the most important of which are located in the -//! `./bin` folder. -//! -//! * [`node`] is an extensive substrate node that contains the superset of all runtime and client -//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the -//! modules that are provided with `FRAME`. This node and runtime is only used for testing and -//! demonstration. -//! * [`chain-spec-builder`]: Utility to build more detailed chain-specs for the aforementioned -//! node. Other projects typically contain a `build-spec` subcommand that does the same. -//! * [`node-template`]: a template node that contains a minimal set of features and can act as a -//! starting point of a project. -//! * [`subkey`]: Substrate's key management utility. -//! -//! ### Anatomy of a Binary Crate -//! -//! From the above, [`node`] and [`node-template`] are essentially blueprints of a substrate-based -//! project, as the name of the latter is implying. Each substrate-based project typically contains -//! the following: -//! -//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file. -//! This file typically contains the [`frame_support::construct_runtime`] macro, which is the -//! final definition of a runtime. -//! -//! * Under `./node`, a `main.rs`, which is the point, and a `./service.rs`, which contains all the -//! client side components. Skimming this file yields an overview of the networking, database, -//! consensus and similar client side components. -//! -//! > The above two are conventions, not rules. -//! -//! ## Parachain? -//! -//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways -//! 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 -//! library on top of Substrate, empowering any substrate-based chain to be a Polkadot parachain. -//! -//! ## Where To Go Next? -//! -//! Additional noteworthy crates within substrate: -//! -//! - RPC APIs of a Substrate node: [`sc-rpc-api`]/[`sc-rpc`] -//! - CLI Options of a Substrate node: [`sc-cli`] -//! - All of the consensus related crates provided by Substrate: -//! - [`sc-consensus-aura`] -//! - [`sc-consensus-babe`] -//! - [`sc-consensus-grandpa`] -//! - [`sc-consensus-beefy`] -//! - [`sc-consensus-manual-seal`] -//! - [`sc-consensus-pow`] -//! -//! Additional noteworthy external resources: -//! -//! - [Substrate Developer Hub](https://substrate.dev) -//! - [Parity Tech's Documentation Hub](https://paritytech.github.io/) -//! - [Frontier: Substrate's Ethereum Compatibility Library](https://paritytech.github.io/frontier/) -//! - [Polkadot Wiki](https://wiki.polkadot.network/en/) -//! -//! Notable upstream crates: -//! -//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) -//! - [`parity-db`](https://github.com/paritytech/parity-db) -//! - [`trie`](https://github.com/paritytech/trie) -//! - [`parity-common`](https://github.com/paritytech/parity-common) -//! -//! Templates: -//! -//! - classic [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) -//! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) -//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) -//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) -//! -//! [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 -//! [`sp-io`]: ../sp_io/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sc-client-db`]: ../sc_client_db/index.html -//! [`sc-network`]: ../sc_network/index.html -//! [`sc-rpc-api`]: ../sc_rpc_api/index.html -//! [`sc-rpc`]: ../sc_rpc/index.html -//! [`sc-cli`]: ../sc_cli/index.html -//! [`sc-consensus-aura`]: ../sc_consensus_aura/index.html -//! [`sc-consensus-babe`]: ../sc_consensus_babe/index.html -//! [`sc-consensus-grandpa`]: ../sc_consensus_grandpa/index.html -//! [`sc-consensus-beefy`]: ../sc_consensus_beefy/index.html -//! [`sc-consensus-manual-seal`]: ../sc_consensus_manual_seal/index.html -//! [`sc-consensus-pow`]: ../sc_consensus_pow/index.html -//! [`node`]: ../node_cli/index.html -//! [`node-template`]: ../node_template/index.html -//! [`kitchensink_runtime`]: ../kitchensink_runtime/index.html -//! [`subkey`]: ../subkey/index.html -//! [`chain-spec-builder`]: ../chain_spec_builder/index.html -//! [`substrate-wasm-builder`]: https://crates.io/crates/substrate-wasm-builder - -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::private_intra_doc_links)] - -#[cfg_attr(doc, aquamarine::aquamarine)] -/// In this module, we explore substrate at a more depth. First, let's establish substrate being -/// divided into a client and runtime. -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// end -/// subgraph Runtime -/// end -/// end -/// ``` -/// -/// The client and the runtime of course need to communicate. This is done through two concepts: -/// -/// 1. Host functions: a way for the (Wasm) runtime to talk to the client. All host functions are -/// defined in [`sp-io`]. For example, [`sp-io::storage`] are the set of host functions that -/// allow the runtime to read and write data to the on-chain state. -/// 2. Runtime APIs: a way for the client to talk to the Wasm runtime. Runtime APIs are defined -/// using macros and utilities in [`sp-api`]. For example, [`sp-api::Core`] is the most basic -/// runtime API that any blockchain must implement in order to be able to (re) execute blocks. -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// end -/// subgraph Runtime -/// end -/// Client --runtime-api--> Runtime -/// Runtime --host-functions--> Client -/// end -/// ``` -/// -/// Finally, let's expand the diagram a bit further and look at the internals of each component: -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// Database -/// Networking -/// Consensus -/// end -/// subgraph Runtime -/// subgraph FRAME -/// direction LR -/// Governance -/// Currency -/// Staking -/// Identity -/// end -/// end -/// Client --runtime-api--> Runtime -/// Runtime --host-functions--> Client -/// end -/// ``` -/// -/// As noted the runtime contains all of the application specific logic of the blockchain. This is -/// usually written with `FRAME`. The client, on the other hand, contains reusable and generic -/// components that are not specific to one single blockchain, such as networking, database, and the -/// consensus engine. -/// -/// [`sp-io`]: ../../sp_io/index.html -/// [`sp-api`]: ../../sp_api/index.html -/// [`sp-io::storage`]: ../../sp_io/storage/index.html -/// [`sp-api::Core`]: ../../sp_api/trait.Core.html -pub mod substrate_diagram {} -- GitLab From 373b8ac78db5e0ca5bc6261874058c748fff0f8c Mon Sep 17 00:00:00 2001 From: Bulat Saifullin Date: Tue, 10 Oct 2023 16:40:57 +0200 Subject: [PATCH 270/633] Update testnet bootnode dns name (#1712) # Description Update the DNS name of bootnodes to unify the deployment. Each bootnode have 3 port exposed: `30333, 30334, 443`. Before, we had different DNS names for `30333, 30334` and `443` ports. It may confuse people and give the impression that it is two different nodes. Fixing it by using a single domain for all --- polkadot/node/service/chain-specs/rococo.json | 24 ++++++++++++------- .../node/service/chain-specs/westend.json | 22 +++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/polkadot/node/service/chain-specs/rococo.json b/polkadot/node/service/chain-specs/rococo.json index 43dc959b576..2648063641c 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 e57786f78a6..fd1f4550127 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", -- GitLab From 55f354429c41e56a66c0b0142834280b77f31d4b Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 11 Oct 2023 01:41:58 +1100 Subject: [PATCH 271/633] remote-ext: fix state download stall on slow connections and reduce memory usage (#1295) Original PR https://github.com/paritytech/substrate/pull/14746 --- ## Fixing stall ### Introduction I experienced an apparent stall downloading state from `https://rococo-try-runtime-node.parity-chains.parity.io:443` which was having networking difficulties only responding to my JSONRPC requests with 50-200KB/s of bandwidth. This PR fixes the issue causing the stall, and generally improves performance remote-ext when it downloads state by greatly reducing the chances of a timeout occuring. ### Description Introduces a new `REQUEST_DURATION_TARGET` constant and modifies `get_storage_data_dynamic_batch_size` to - Increase or decrease the batch size of the next request depending on whether the elapsed time of the last request was gt or lt the target - Reset the batch size to 1 if the request times out This fixes an issue on slow connections that can otherwise cause multiple timeouts and a stalled download when: 1. The batch size increases rapidly as remote-ext downloads keys with small associated storage values 2. remote-ext tries to process a large series of subsequent keys all with extremely large associated storage values (Rococo has a series of keys 1-5MB large) 3. The huge storage values download for 5 minutes until the request times out 4. The partially downloaded keys are thrown out and remote-ext tries again with a smaller batch size, but the batch size is still far too large and takes 5 minutes to be reduced again 5. The download will be essentially stalled for many hours while the above step cycles After this PR, the request size will - Not grow as large to begin with, as it is regulated downwards as the request duration exceeds the target - Drop immediately to 1 if the request times out. A timeout indicates the keys next in line to download have extremely large storage values compared to previously downloaded keys, and we need to reset the batch size to figure out what our new ideal batch size is. By not resetting down to 1, we risk the next request timing out again. ## Reducing memory As suggested by @bkchr, I adjusted `get_storage_data_dynamic_batch_size` from being recursive to a loop which allows removing a bunch of clones that were chewing through a lot of memory. I noticed actually it was using up to 50GB swap previously when downloading Polkadot keys on a slow connection, because it needed to recurse and clone a lot. After this change it uses only ~1.5GB memory. --- Cargo.lock | 12 -- .../frame/remote-externalities/Cargo.toml | 1 - .../frame/remote-externalities/src/lib.rs | 190 ++++++++++-------- 3 files changed, 102 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc8415a5a23..5481f917be4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1096,17 +1096,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.38", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -5286,7 +5275,6 @@ dependencies = [ name = "frame-remote-externalities" version = "0.10.0-dev" dependencies = [ - "async-recursion", "futures", "indicatif", "jsonrpsee", diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index ad6ab006da1..7067aed238a 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 072ea6ef5e5..71e9320ebee 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()); -- GitLab From 3f5edc52b22f39516c3e1d3bef0023bd6a48daf6 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 10 Oct 2023 17:32:11 +0200 Subject: [PATCH 272/633] Use safe math when pruning statuses (#1835) Co-authored-by: Francisco Aguirre --- cumulus/pallets/xcmp-queue/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 1cb92f59518..7ee07a7beb0 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -1129,7 +1129,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); -- GitLab From 5adcb3e10638c8abcfd532b9163990d584fc5832 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 10 Oct 2023 13:48:50 -0400 Subject: [PATCH 273/633] upgrade to macro_magic 0.4.3 (#1832) # Description Upgrades `macro_magic` to 0.4.3, which introduces the ability to have `export_tokens` use the same name as the underlying item for its auto-generated macro name. Ultimately this will allow for better dev ux in our derive_impl feature. --- Cargo.lock | 16 ++++++++-------- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- substrate/frame/support/procedural/src/lib.rs | 9 +++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5481f917be4..d8e7d055d77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7616,9 +7616,9 @@ 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", @@ -7628,9 +7628,9 @@ dependencies = [ [[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", @@ -7642,9 +7642,9 @@ dependencies = [ [[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", @@ -7653,9 +7653,9 @@ dependencies = [ [[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", diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 5cb5d6d12ab..65f4885b159 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} diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 9781a882514..45ed1750a52 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -23,8 +23,8 @@ proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.38", features = ["full"] } frame-support-procedural-tools = { path = "tools" } +macro_magic = { version = "0.5.0", features = ["proc_support"] } proc-macro-warning = { version = "1.0.0", default-features = false } -macro_magic = { version = "0.4.2", features = ["proc_support"] } expander = "2.0.0" sp-core-hashing = { path = "../../../primitives/core/hashing" } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index da4cb41fe4f..b4f6acb07cc 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -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, + true, + ) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -1565,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(), } -- GitLab From 294e99831dbcc52d8d167e16551b214a5bb536c2 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Wed, 11 Oct 2023 07:26:13 +0200 Subject: [PATCH 274/633] Fixes path issue in derive-impl (#1823) Needs https://github.com/sam0x17/macro_magic/pull/13 The associated PR allows the export of tokens from macro_magic at the specified path. This fixes the path issue in derive-impl. Now, we can import the default config using the standard rust syntax: ```rust use frame_system::config_preludes::TestDefaultConfig; [derive_impl(TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::DefaultConfig for Test { //.... } ``` --- substrate/frame/examples/default-config/src/lib.rs | 7 ++++--- substrate/frame/support/procedural/src/lib.rs | 6 +++--- .../tests/derive_impl_ui/bad_default_impl_path.stderr | 8 +++----- ...nject_runtime_type_fails_when_type_not_in_scope.stderr | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index d2eade0ccff..8a1f6f9d6a8 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/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index b4f6acb07cc..07b5a50da41 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -34,7 +34,7 @@ mod transactional; mod tt_macro; use frame_support_procedural_tools::generate_crate_access_2018; -use macro_magic::import_tokens_attr; +use macro_magic::{import_tokens_attr, import_tokens_attr_verbatim}; use proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::{cell::RefCell, str::FromStr}; @@ -751,7 +751,7 @@ 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") { @@ -868,7 +868,7 @@ pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenSt attrs, item_impl.to_token_stream(), true, - true, + false, ) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), 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 5cfbd8c8862..c91226ea9c3 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 79b50a940b8..f3ac6b23281 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) -- GitLab From cfb29254f74412cea35e8048d8aea94bc789fcb1 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 11 Oct 2023 10:32:49 +0200 Subject: [PATCH 275/633] Xcm emulator nits (#1649) # Desription ## Summary This PR introduces several nits and tweaks to xcm emulator tests for system parachains. ## Explanation **Deduplicate `XcmPallet::send(` with root origin code** - Introduced `send_transact_to_parachain` which could be easily reuse for scenarios like _governance call from relay chain to parachain_. **Refactor `send_transact_sudo_from_relay_to_system_para_works`** - Test covered just one use-case which was moved to the `do_force_create_asset_from_relay_to_system_para`, so now we can extend this test with more _governance-like_ senarios. - Renamed to `send_transact_as_superuser_from_relay_to_system_para_works`. **Remove `send_transact_native_from_relay_to_system_para_fails` test** - This test and/or description is kind of misleading, because system paras support Native from relay chain by `RelayChainAsNative` with correct xcm origin. - It tested only sending on relay chain which should go directly to the relay chain unit-tests (does not even need to be in xcm emulator level). ## Future directions Check restructure parachains integration tests [issue](https://github.com/paritytech/polkadot-sdk/issues/1389) and [PR with more TODOs](https://github.com/paritytech/polkadot-sdk/pull/1693). --------- Co-authored-by: Ignacio Palacios --- .../src/tests/reserve_transfer.rs | 2 + .../asset-hub-westend/src/tests/send.rs | 51 ++-------- .../src/tests/set_xcm_versions.rs | 38 +++---- .../emulated/common/src/impls.rs | 98 ++++++++++++------- .../emulated/common/src/lib.rs | 14 +-- 5 files changed, 89 insertions(+), 114 deletions(-) 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 805c8811b2d..8f8b7a7dde7 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 @@ -349,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, ); @@ -384,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 d0a71e88c67..e603af685bb 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, ); 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 2720095aac0..2133d5e5fb7 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/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 5e11922d859..bb4c9d102e9 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/polkadot-sdk/pull/1352 is merged -// type BridgeHubPolkadotRuntime = ::Runtime; -// type BridgeHubKusamaRuntime = ::Runtime; - pub type RococoWococoMessageHandler = BridgeHubMessageHandler; pub type WococoRococoMessageHandler = BridgeHubMessageHandler; -// TODO: uncomment when https://github.com/paritytech/polkadot-sdk/pull/1352 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 ) => { @@ -616,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 068f0238f49..c2e065ccadc 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -250,30 +250,22 @@ decl_test_bridges! { target = BridgeHubRococo, handler = WococoRococoMessageHandler } - // TODO: uncomment when https://github.com/paritytech/polkadot-sdk/pull/1352 is merged - // pub struct PolkadotKusamaMockBridge { - // source = BridgeHubPolkadot, - // target = BridgeHubKusama, - // handler = PolkadotKusamaMessageHandler - // }, - // pub struct KusamaPolkadotMockBridge { - // source = BridgeHubKusama, - // target = BridgeHubPolkadot, - // handler = KusamaPolkadotMessageHandler - // } } // 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_send_transact_helpers_for_relay_chain!(Rococo); // Wococo implementation impl_accounts_helpers_for_relay_chain!(Wococo); impl_assert_events_helpers_for_relay_chain!(Wococo); +impl_send_transact_helpers_for_relay_chain!(Wococo); // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); -- GitLab From 132ba0c89fc1d48d770f28a5d5448c9dd1bb164a Mon Sep 17 00:00:00 2001 From: Marcin S Date: Wed, 11 Oct 2023 16:13:07 +0200 Subject: [PATCH 276/633] PVF worker: bump landlock, update ABI docs (#1850) --- Cargo.lock | 4 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- .../core/pvf/common/src/worker/security.rs | 52 +++++++++++++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8e7d055d77..58bacc9db73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6874,9 +6874,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", diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 0f7308396d8..4bdacca72f4 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -29,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/worker/security.rs b/polkadot/node/core/pvf/common/src/worker/security.rs index b7abf028f94..1b761417744 100644 --- a/polkadot/node/core/pvf/common/src/worker/security.rs +++ b/polkadot/node/core/pvf/common/src/worker/security.rs @@ -223,13 +223,22 @@ pub mod landlock { /// 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 (as of 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 /// @@ -335,7 +344,7 @@ pub mod landlock { A: Into>, { let mut ruleset = - Ruleset::new().handle_access(AccessFs::from_all(LANDLOCK_ABI))?.create()?; + 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(); @@ -466,5 +475,38 @@ pub mod landlock { 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()); + } } } -- GitLab From 1d9ec572764d1fc74c0f46832318c0ce4e99114a Mon Sep 17 00:00:00 2001 From: 0xmovses <35300528+0xmovses@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:21:01 +0100 Subject: [PATCH 277/633] Refactor Identity to benchmark v2 (#1838) This PR refactors `identity/benchmarkings.rs` to use benchmarking v2. These changes are needed to improve the readability and maintainability of the benchmarking code. Changes were implemented using [this](https://github.com/paritytech/polkadot-sdk/commit/9ec80090f5065ce0e3234886c43bc623e8e60d77) commit as a guide. The logic of the benchmarks remains the same. No known issue to backlink. ## Local Testing To test the new benchmarks: 1. `cargo build --features runtime-benchmarks` 2. `./target/debug/polkadot benchmark pallet --steps=5 --repeat=2 --pallet=pallet_identity --extrinsic='*'` --------- Co-authored-by: Richard Melkonian Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre Co-authored-by: Oliver Tale-Yazdi --- substrate/frame/identity/src/benchmarking.rs | 427 ++++++++++++------- 1 file changed, 272 insertions(+), 155 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 4b51d23f6b3..059de204bbf 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); -- GitLab From 447e7533237d038d43b2de68ff39e0a179503ac4 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 11 Oct 2023 19:49:59 +0200 Subject: [PATCH 278/633] ci: bump ci image to rust 1.73.0 (#1830) Co-authored-by: command-bot <> --- .cargo/config.toml | 8 ++- .gitlab-ci.yml | 2 +- .gitlab/pipeline/build.yml | 2 +- .gitlab/pipeline/test.yml | 1 - polkadot/node/core/backing/src/tests/mod.rs | 4 +- .../node/overseer/examples/minimal-example.rs | 1 - .../cli/src/commands/inspect_node_key.rs | 2 +- substrate/client/network/common/src/role.rs | 4 ++ .../src/protocol/notifications/behaviour.rs | 1 - substrate/frame/contracts/src/wasm/prepare.rs | 3 +- substrate/frame/nfts/src/tests.rs | 2 +- substrate/frame/preimage/src/migration.rs | 2 +- .../deprecated_where_block.stderr | 12 +++- .../tests/derive_no_bound_ui/debug.stderr | 2 +- .../call_argument_invalid_bound.stderr | 2 +- .../call_argument_invalid_bound_2.stderr | 2 +- .../call_argument_invalid_bound_3.stderr | 2 +- ...ev_mode_without_arg_max_encoded_len.stderr | 16 ++--- .../error_does_not_derive_pallet_error.stderr | 16 ++--- .../pallet_ui/event_field_not_member.stderr | 2 +- .../inherent_check_inner_span.stderr | 4 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 72 +++++++++---------- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 72 +++++++++---------- .../pallet_ui/storage_info_unsatisfied.stderr | 16 ++--- .../storage_info_unsatisfied_nmap.stderr | 20 +++--- .../primitives/npos-elections/src/lib.rs | 2 +- .../tests/ui/no_feature_gated_method.stderr | 12 ++++ .../benchmarking-cli/src/pallet/writer.rs | 1 + 28 files changed, 156 insertions(+), 129 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4796a2c2696..042dded2fa9 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`. @@ -30,4 +35,5 @@ 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 ] diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61451a9c462..0d7e7adb956 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + CI_IMAGE: !reference [.ci-unified-1.73.0, variables, CI_IMAGE] # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 029c0f6a3cd..fefa3739a9f 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -91,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 @@ -99,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/test.yml b/.gitlab/pipeline/test.yml index e1e8b96bca5..12ce2140b14 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -181,7 +181,6 @@ test-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" script: - time cargo doc --workspace --all-features --no-deps allow_failure: true diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index bdc8b3fa1af..35d17f3d905 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -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/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index e78941776d5..cffdfd9f8aa 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/substrate/client/cli/src/commands/inspect_node_key.rs b/substrate/client/cli/src/commands/inspect_node_key.rs index 19b5a31ca12..6cf025a2d11 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/network/common/src/role.rs b/substrate/client/network/common/src/role.rs index cd43f6655b7..fd02c00e232 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/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 89513e004c6..b78f15f8529 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/frame/contracts/src/wasm/prepare.rs b/substrate/frame/contracts/src/wasm/prepare.rs index b129c17e13e..dfe8c4f8f9b 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/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index 6e264048f11..a82fcca0151 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/preimage/src/migration.rs b/substrate/frame/preimage/src/migration.rs index 821cb01bbaa..a86109f892a 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/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index cc2c2e16009..08954bb6ab5 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/derive_no_bound_ui/debug.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/debug.stderr index d86292d71b7..3291f658f10 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_ui/call_argument_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index c86930f8a64..08ea7c0bec3 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 1b04f44c78f..80316fcd248 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 7429bce050c..d45b74bad84 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/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 74ee0e4aeba..531e8bdffeb 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 cfa0d465990..ea1d0ed99cd 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 4df6deafa0d..fc4a33b7215 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/inherent_check_inner_span.stderr b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr index 3a26d1c0495..5ea3be470a0 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/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 e290b22a0ea..930af1d7fcb 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 0e3a7c9f1cb..79798963c8b 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 9a31e4b6bdf..e04de98800e 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 cdcd1b401f8..31fe3b57338 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/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 0afe1ec5bb6..62ae0502114 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/tests/ui/no_feature_gated_method.stderr b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr index 23e671f6ce3..10012ede793 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/utils/frame/benchmarking-cli/src/pallet/writer.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs index 69c95d13c09..9493a693bbe 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, -- GitLab From b5aee6e23f2d397cf3da389a821b4f344a8ae65c Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 11 Oct 2023 21:20:46 +0200 Subject: [PATCH 279/633] ci: set CI_IMAGE back to (now updated) .ci-unified (#1854) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d7e7adb956..61451a9c462 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified-1.73.0, variables, CI_IMAGE] + CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" -- GitLab From 70d4907a32708e921de78e18fc9c7e3dbcfe4fe1 Mon Sep 17 00:00:00 2001 From: Sam Elamin Date: Thu, 12 Oct 2023 10:48:32 +0100 Subject: [PATCH 280/633] allow treasury to do reserve asset transfers (#1447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pr resolves https://github.com/paritytech/polkadot-sdk/issues/1428. *Added only to Kusama for now* I did raise it [here](https://github.com/polkadot-fellows/runtimes/pull/19) and we discussed creating a chopsticks test to run an end-to-end test however, to do that I will need a build agent/custom runner that is powerful enough to run the build I will be doing that separately as I still think having chopsticks test your runtime with each commit will be very powerful and extremely useful for the ecosystem For now I have used XCM simulator and replicated what the other reserve tests do --------- Co-authored-by: Gavin Wood Co-authored-by: Francisco Aguirre Co-authored-by: Branislav Kontur Co-authored-by: Bastian Köcher --- polkadot/xcm/xcm-builder/src/lib.rs | 6 +- .../xcm-builder/src/location_conversion.rs | 105 +++++++++++++++++- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 26f2aadadf3..9fdd55d9f92 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -33,9 +33,9 @@ pub use location_conversion::{ Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32, ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal, DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeBodyTerminal, DescribeFamily, - DescribeLocation, DescribePalletTerminal, DescribeTerminus, GlobalConsensusConvertsFor, - GlobalConsensusParachainConvertsFor, HashedDescription, ParentIsPreset, - SiblingParachainConvertsVia, + DescribeLocation, DescribePalletTerminal, DescribeTerminus, DescribeTreasuryVoiceTerminal, + GlobalConsensusConvertsFor, GlobalConsensusParachainConvertsFor, HashedDescription, + LocalTreasuryVoiceConvertsVia, ParentIsPreset, SiblingParachainConvertsVia, }; mod origin_conversion; diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index 4a5fbbb123b..25d16f7eb8c 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -84,6 +84,20 @@ 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; @@ -101,6 +115,7 @@ pub type DescribeAllTerminal = ( DescribePalletTerminal, DescribeAccountId32Terminal, DescribeAccountKey20Terminal, + DescribeTreasuryVoiceTerminal, DescribeBodyTerminal, ); @@ -328,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`. @@ -442,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; @@ -936,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 + ); + } } -- GitLab From f0e6d2ad52a8edb277f4144dee620eb1ce8a8a94 Mon Sep 17 00:00:00 2001 From: Kevin Krone Date: Thu, 12 Oct 2023 14:53:01 +0200 Subject: [PATCH 281/633] Adding `try_state` hook for `Treasury` pallet (#1820) This PR adds a `try_state` hook for the `Treasury` pallet. Part of #239. --- substrate/frame/treasury/src/benchmarking.rs | 6 +- substrate/frame/treasury/src/lib.rs | 90 ++++++- substrate/frame/treasury/src/tests.rs | 252 ++++++++++++++++--- 3 files changed, 308 insertions(+), 40 deletions(-) diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index f5f73ea8dda..61fe29dafca 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -336,5 +336,9 @@ mod benchmarks { 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 b2b3a8801c1..5e429d3914b 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -89,7 +89,8 @@ use sp_runtime::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use frame_support::{ - print, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, + ensure, print, traits::{ tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, ReservableCurrency, WithdrawReasons, @@ -456,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)] @@ -1020,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 4bb00547d9f..1748189723e 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -217,16 +217,28 @@ impl Config for Test { 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 } - .assimilate_storage(&mut t) - .unwrap(); - crate::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); - t.into() } fn get_payment_id(i: SpendIndex) -> Option { @@ -239,7 +251,7 @@ fn get_payment_id(i: SpendIndex) -> Option { #[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); }); @@ -247,7 +259,7 @@ fn genesis_config_works() { #[test] fn spend_local_origin_permissioning_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_noop!(Treasury::spend_local(RuntimeOrigin::signed(1), 1, 1), BadOrigin); assert_noop!( Treasury::spend_local(RuntimeOrigin::signed(10), 6, 1), @@ -271,7 +283,7 @@ fn spend_local_origin_permissioning_works() { #[docify::export] #[test] fn spend_local_origin_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); // approve spend of some amount to beneficiary `6`. @@ -295,7 +307,7 @@ fn spend_local_origin_works() { #[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); @@ -304,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) @@ -316,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) @@ -328,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)] @@ -341,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!({ @@ -361,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); @@ -374,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!({ @@ -394,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!({ @@ -417,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)] @@ -430,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)] @@ -443,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!({ @@ -466,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); @@ -487,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); @@ -514,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()); @@ -613,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); @@ -645,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!({ @@ -669,7 +681,7 @@ fn remove_already_removed_approval_fails() { #[test] fn spending_local_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![ @@ -694,7 +706,7 @@ fn spending_local_in_batch_respects_max_total() { #[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![ @@ -739,7 +751,7 @@ fn spending_in_batch_respects_max_total() { #[test] fn spend_origin_works() { - new_test_ext().execute_with(|| { + 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!( @@ -764,7 +776,7 @@ fn spend_origin_works() { #[test] fn spend_works() { - new_test_ext().execute_with(|| { + 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)); @@ -796,7 +808,7 @@ fn spend_works() { #[test] fn spend_expires() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_eq!(::PayoutPeriod::get(), 5); // spend `0` expires in 5 blocks after the creating. @@ -816,7 +828,7 @@ fn spend_expires() { #[docify::export] #[test] fn spend_payout_works() { - new_test_ext().execute_with(|| { + 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)); @@ -838,7 +850,7 @@ fn spend_payout_works() { #[test] fn payout_retry_works() { - new_test_ext().execute_with(|| { + 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)); @@ -863,7 +875,7 @@ fn payout_retry_works() { #[test] fn spend_valid_from_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_eq!(::PayoutPeriod::get(), 5); System::set_block_number(1); @@ -895,7 +907,7 @@ fn spend_valid_from_works() { #[test] fn void_spend_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); // spend cannot be voided if already attempted. assert_ok!(Treasury::spend( @@ -926,7 +938,7 @@ fn void_spend_works() { #[test] fn check_status_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_eq!(::PayoutPeriod::get(), 5); System::set_block_number(1); @@ -984,3 +996,167 @@ fn check_status_works() { 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.")) + ); + }); +} -- GitLab From 7aace06b3d653529ab992c8ff96571d54bf00a36 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Thu, 12 Oct 2023 16:01:07 +0300 Subject: [PATCH 282/633] Disabled validators runtime API (#1257) Exposes disabled validators list via a runtime API. --------- Co-authored-by: ordian Co-authored-by: ordian --- .../src/blockchain_rpc_client.rs | 7 +++++ .../src/rpc_client.rs | 8 ++++++ .../emulated/common/src/lib.rs | 6 ++--- polkadot/node/core/runtime-api/src/cache.rs | 18 +++++++++++++ polkadot/node/core/runtime-api/src/lib.rs | 10 +++++++ polkadot/node/core/runtime-api/src/tests.rs | 4 +++ polkadot/node/subsystem-types/src/messages.rs | 5 ++++ .../subsystem-types/src/runtime_client.rs | 9 ++++++- polkadot/node/subsystem-util/src/lib.rs | 1 + polkadot/primitives/src/runtime_api.rs | 7 +++++ .../src/runtime_api_impl/vstaging.rs | 27 +++++++++++++++++++ polkadot/runtime/rococo/src/lib.rs | 11 ++++++-- polkadot/runtime/westend/src/lib.rs | 10 +++++-- 13 files changed, 115 insertions(+), 8 deletions(-) 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 3f4c08ecbb8..1e78df71154 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 @@ -346,6 +346,13 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { Ok(self.rpc_client.parachain_host_minimum_backing_votes(at, session_index).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?) } 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 b1fd7d1ab7d..5924716adcb 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -597,6 +597,14 @@ 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_async_backing_params( &self, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index c2e065ccadc..f8fe8831d3c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -33,7 +33,7 @@ use xcm_emulator::{ }; decl_test_relay_chains! { - #[api_version(7)] + #[api_version(8)] pub struct Westend { genesis = westend::genesis(), on_init = (), @@ -50,7 +50,7 @@ decl_test_relay_chains! { AssetRate: westend_runtime::AssetRate, } }, - #[api_version(7)] + #[api_version(8)] pub struct Rococo { genesis = rococo::genesis(), on_init = (), @@ -65,7 +65,7 @@ decl_test_relay_chains! { Balances: rococo_runtime::Balances, } }, - #[api_version(7)] + #[api_version(8)] pub struct Wococo { genesis = rococo::genesis(), on_init = (), diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 6cf7fa744d3..69eea22b23b 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -64,6 +64,7 @@ pub(crate) struct RequestResultCache { unapplied_slashes: LruMap>, key_ownership_proof: LruMap<(Hash, ValidatorId), Option>, minimum_backing_votes: LruMap, + disabled_validators: LruMap>, para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, } @@ -96,6 +97,7 @@ 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)), + 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)), } @@ -444,6 +446,21 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } + 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), @@ -520,6 +537,7 @@ pub(crate) enum RequestResult { slashing::OpaqueKeyOwnershipProof, Option<()>, ), + 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 1b18941e546..bdcca08b10d 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -166,6 +166,8 @@ where .requests_cache .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), SubmitReportDisputeLost(_, _, _, _) => {}, + 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_para_backing_state((relay_parent, para_id), constraints), @@ -296,6 +298,8 @@ where Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, 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) @@ -565,6 +569,12 @@ where ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT, sender ), + Request::DisabledValidators(sender) => query!( + DisabledValidators, + disabled_validators(), + ver = Request::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT, + sender + ), Request::ParaBackingState(para, sender) => { query!( ParaBackingState, diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index fb97139a802..979b3587d26 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -268,6 +268,10 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { 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/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 01ccee3add9..6bc87438459 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -695,6 +695,8 @@ 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. ParaBackingState(ParaId, RuntimeApiSender>), /// Get candidate's acceptance limitations for asynchronous backing for a relay parent. @@ -726,6 +728,9 @@ impl RuntimeApiRequest { /// 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 3007e985b4f..f7adcf9862b 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -255,6 +255,10 @@ pub trait RuntimeApiSubsystemClient { at: Hash, para_id: Id, ) -> 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. @@ -497,11 +501,14 @@ where self.client.runtime_api().para_backing_state(at, para_id) } - /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. async fn async_backing_params( &self, at: Hash, ) -> 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/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index 57e4f9cde09..a5f3e9d4a0c 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -226,6 +226,7 @@ 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_disabled_validators() -> Vec; DisabledValidators; fn request_async_backing_params() -> AsyncBackingParams; AsyncBackingParams; } diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 6cb66d40204..5ec897c8cbb 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -248,6 +248,7 @@ sp_api::decl_runtime_apis! { #[api_version(6)] fn minimum_backing_votes() -> u32; + /***** Added in v7: Asynchronous backing *****/ /// Returns the state of parachain backing for a given para. @@ -257,5 +258,11 @@ sp_api::decl_runtime_apis! { /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. #[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/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index d01b543630c..24a076f3a44 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -15,3 +15,30 @@ // along with Polkadot. If not, see . //! Put implementations of functions from staging APIs here. + +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/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index fd3e656f695..9933f644297 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -49,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::v7 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, }; @@ -1585,7 +1587,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(7)] + #[api_version(8)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1728,6 +1730,11 @@ sp_api::impl_runtime_apis! { 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)] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d61acf36b4c..0e93b3449fe 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -70,7 +70,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, reward_points as parachains_reward_points, - runtime_api_impl::v7 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, }; @@ -1695,7 +1697,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(7)] + #[api_version(8)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1838,6 +1840,10 @@ sp_api::impl_runtime_apis! { fn async_backing_params() -> primitives::AsyncBackingParams { parachains_runtime_api_impl::async_backing_params::() } + + fn disabled_validators() -> Vec { + parachains_staging_runtime_api_impl::disabled_validators::() + } } impl beefy_primitives::BeefyApi for Runtime { -- GitLab From d2fc1d7c91971e6e630a9db8cb627f8fdc91e8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Vilhelm=20=C3=81sgeirsson?= Date: Thu, 12 Oct 2023 21:29:10 +0200 Subject: [PATCH 283/633] Fix links to implementers' guide (#1865) # Description In a couple of cases, there were links pointing to the w3f github pages domain. In other instances, there were links pointing to the old polkadot repo's github pages. Both of these are now pointing to the relevant links in https://paritytech.github.io/polkadot-sdk/book/index.html. These changes were made specifically because the w3f github pages returns a 404, and while fixing the links, the old polkadot repo links were touched up as well even if they do redirect properly. This shouldn't affect anything as these are documentation link changes only. --- polkadot/node/collation-generation/src/lib.rs | 2 +- polkadot/node/core/pvf/src/lib.rs | 6 ++++-- polkadot/node/network/approval-distribution/src/lib.rs | 5 ++++- polkadot/node/overseer/src/lib.rs | 4 +++- polkadot/node/service/src/relay_chain_selection.rs | 2 +- polkadot/roadmap/implementers-guide/README.md | 2 +- polkadot/runtime/parachains/src/session_info.rs | 5 +++-- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 4e13755deed..b8c9c1a36e4 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -193,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(()) diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 1b8d8377381..e3c6da9c4c6 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 //! diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index f76826d7fdf..d8949b1c112 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)] diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 84d5d19c3b9..673569ab946 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/service/src/relay_chain_selection.rs b/polkadot/node/service/src/relay_chain_selection.rs index 189073783f0..5fae6a96de4 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/roadmap/implementers-guide/README.md b/polkadot/roadmap/implementers-guide/README.md index 996041f176b..e03c0c45ddb 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/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index 0043851be0f..9e1b3d05842 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}, -- GitLab From 6b27dad359793a873c91d09cd3f6267d66ff543e Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Fri, 13 Oct 2023 07:48:51 +0200 Subject: [PATCH 284/633] Adds instance support for composite enums (#1857) Fixes https://github.com/paritytech/polkadot-sdk/issues/1839 Currently, `composite_enum`s do not support pallet instances. This PR allows the following: ```rust #[pallet::composite_enum] pub enum HoldReason { SomeHoldReason } ``` ### Todo - [x] UI Test --- substrate/frame/balances/src/lib.rs | 4 +- .../expand/composite_helper.rs | 70 ++++++++++++++++ .../construct_runtime/expand/freeze_reason.rs | 40 +++++----- .../construct_runtime/expand/hold_reason.rs | 40 +++++----- .../src/construct_runtime/expand/lock_id.rs | 40 +++++----- .../src/construct_runtime/expand/mod.rs | 1 + .../construct_runtime/expand/slash_reason.rs | 40 +++++----- .../procedural/src/pallet/parse/composite.rs | 24 +++++- substrate/frame/support/src/lib.rs | 17 +++- .../test/tests/construct_runtime_ui.rs | 1 + .../pass/composite_enum_instance.rs | 80 +++++++++++++++++++ 11 files changed, 264 insertions(+), 93 deletions(-) create mode 100644 substrate/frame/support/procedural/src/construct_runtime/expand/composite_helper.rs create mode 100644 substrate/frame/support/test/tests/construct_runtime_ui/pass/composite_enum_instance.rs diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index a2cacc45369..c408bf3f35f 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -256,7 +256,7 @@ pub mod pallet { /// The overarching hold reason. #[pallet::no_default_bounds] - type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Ord + Copy; + type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Copy; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -300,7 +300,7 @@ pub mod pallet { type ReserveIdentifier: 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/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 00000000000..3c81d2360cb --- /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 b142f8e84c9..18790850d6b 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 ed7183c4a15..1bb7462133c 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/lock_id.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/lock_id.rs index ba35147a051..e67c0da00ea 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 830338f9265..a0fc6b8130b 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 2a3283230ad..892b842b174 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/pallet/parse/composite.rs b/substrate/frame/support/procedural/src/pallet/parse/composite.rs index cb554a11617..ddcc2d07f93 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; @@ -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/src/lib.rs b/substrate/frame/support/src/lib.rs index 8c4b3de49b5..700d777a148 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1646,8 +1646,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 +1814,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 +1957,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; diff --git a/substrate/frame/support/test/tests/construct_runtime_ui.rs b/substrate/frame/support/test/tests/construct_runtime_ui.rs index c3197c99a72..0cf857e2d73 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/pass/composite_enum_instance.rs b/substrate/frame/support/test/tests/construct_runtime_ui/pass/composite_enum_instance.rs new file mode 100644 index 00000000000..ad637087476 --- /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() {} -- GitLab From 832060000bbdbc87cac233bde8954ae7263f6500 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 13 Oct 2023 10:12:30 +0300 Subject: [PATCH 285/633] sc-consensus-beefy: improve gossip logic (#1852) - Remove cached messages used for deduplication in `GossipValidator` since they're already deduplicated in upper layer `NetworkGossip`. - Add cache for "justified rounds" to quickly discard any further (even if potentially different) justifications at the gossip level, once a valid one (for a respective round) is submitted to the worker. - Add short-circuit in worker `finalize()` method to not attempt to finalize same block multiple times (for example when we get justifications for same block from multiple components like block-import, gossip or on-demand). - Change a test which had A LOT of latency in syncing blocks for some weird reason and would only run after ~150seconds. It now runs instantly. Fixes https://github.com/paritytech/polkadot-sdk/issues/1728 --- .../beefy/src/communication/gossip.rs | 156 ++++++------------ .../consensus/beefy/src/communication/mod.rs | 2 +- substrate/client/consensus/beefy/src/tests.rs | 12 +- .../client/consensus/beefy/src/worker.rs | 11 +- 4 files changed, 67 insertions(+), 114 deletions(-) diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 8c025ca0676..342cd0511a5 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 7f9535bfc23..10a6071aae6 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/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 3bb65e9d57f..90b63c9cd44 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -1302,7 +1302,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 +1332,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 a239e34030c..309d8c5135b 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); } -- GitLab From 82bfe28424464ccafbe1ddff2d79491e0ddf7080 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 13 Oct 2023 11:37:48 +0300 Subject: [PATCH 286/633] frame: use derive-impl for beefy and mmr pallets (#1867) Part of #171 --- substrate/frame/beefy-mmr/src/mock.rs | 30 +++------------- substrate/frame/beefy/src/mock.rs | 36 ++++--------------- .../frame/merkle-mountain-range/src/mock.rs | 31 ++-------------- 3 files changed, 13 insertions(+), 84 deletions(-) diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs index b2d8758a04b..b85096813de 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 b55a65dbd73..9480fd0406d 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/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs index ecc254278bf..d3cb4e57029 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 { -- GitLab From 681e7bbfb2e24b41f6c45825532e6a976596d9db Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Fri, 13 Oct 2023 21:52:04 +0800 Subject: [PATCH 287/633] Check executor params coherence (#1774) Co-authored-by: Marcin S --- .../node/core/candidate-validation/src/lib.rs | 11 +- .../node/core/pvf/common/src/executor_intf.rs | 17 +- .../node/core/pvf/execute-worker/src/lib.rs | 6 +- polkadot/primitives/src/lib.rs | 26 +-- polkadot/primitives/src/v6/executor_params.rs | 198 +++++++++++++++++- polkadot/primitives/src/v6/mod.rs | 2 +- .../runtime/parachains/src/configuration.rs | 11 +- 7 files changed, 231 insertions(+), 40 deletions(-) diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 3281fcc59a1..21a7121d47b 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/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 79839149ebd..508a12998fc 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 @@ -106,8 +106,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, diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 02eaedb96f2..65185b6f45f 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -27,7 +27,6 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, execute::{Handshake, Response}, - executor_intf::NATIVE_STACK_MAX, framed_recv_blocking, framed_send_blocking, worker::{ cpu_time_monitor_loop, stringify_panic_payload, @@ -36,6 +35,7 @@ use polkadot_node_core_pvf_common::{ }, }; use polkadot_parachain_primitives::primitives::ValidationResult; +use polkadot_primitives::executor_params::DEFAULT_NATIVE_STACK_MAX; use std::{ os::unix::net::UnixStream, path::PathBuf, @@ -69,7 +69,7 @@ use tokio::io; // // 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. @@ -78,7 +78,7 @@ use tokio::io; // // 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; fn recv_handshake(stream: &mut UnixStream) -> io::Result { let handshake_enc = framed_recv_blocking(stream)?; diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 5adb6d25313..4ba8b8b031f 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -35,19 +35,19 @@ pub mod runtime_api; // Primitives requiring versioning must not be exported and must be referred by an exact version. pub use v6::{ async_backing, 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, 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, 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, + 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, RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs index 6fbf3037fd6..8ea0889bd23 100644 --- a/polkadot/primitives/src/v6/executor_params.rs +++ b/polkadot/primitives/src/v6/executor_params.rs @@ -26,28 +26,83 @@ 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}; +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) + /// 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 + /// 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 + /// 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, millisec + /// 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, millisec + /// 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 @@ -55,6 +110,17 @@ pub enum ExecutorParam { 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`]. @@ -130,6 +196,126 @@ impl ExecutorParams { } 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 { diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index cf900835517..9371b3db406 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -62,7 +62,7 @@ pub mod executor_params; pub mod slashing; pub use async_backing::AsyncBackingParams; -pub use executor_params::{ExecutorParam, ExecutorParams, ExecutorParamsHash}; +pub use executor_params::{ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash}; mod metrics; pub use metrics::{ diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index f53f986a553..a65fda37048 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::{ - 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(()) } -- GitLab From 24840290af20ef67956c48b7548ab184d45b8889 Mon Sep 17 00:00:00 2001 From: 0xmovses <35300528+0xmovses@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:54:45 +0100 Subject: [PATCH 288/633] Refactor alliance benchmarks to v2 (#1868) - This PR refactors `alliance/src/benchmarkings.rs` to use benchmarking v2. These changes are needed to improve the readability and maintainability of the benchmarking code. - No known issue to backlink. ## Local Testing 1. `cargo build --features runtime-benchmarks` 2. `cargo run --locked --release -p node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1` --- substrate/frame/alliance/src/benchmarking.rs | 567 ++++++++++-------- .../procedural/src/pallet/expand/warnings.rs | 8 +- 2 files changed, 315 insertions(+), 260 deletions(-) diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index eb32c6c466c..77294c6b664 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/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index ae5890878a2..030e3ddaf32 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,9 +33,7 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } - let CallWeightDef::Immediate(w) = &method.weight else { - return; - }; + let CallWeightDef::Immediate(w) = &method.weight else { return }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") .old("not check weight witness data") @@ -66,9 +64,7 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } - let syn::Expr::Lit(lit) = weight else { - return; - }; + let syn::Expr::Lit(lit) = weight else { return }; let warning = Warning::new_deprecated("ConstantWeight") .index(warnings.len()) -- GitLab From 1f28cddd6fcaeb54220d4c410abe80fde826fc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Fri, 13 Oct 2023 23:06:38 +0200 Subject: [PATCH 289/633] Remove clippy clone-double-ref lint noise (#1860) The lint `clippy::clone_double_ref` was renamed to `suspicious_double_ref_op` in [this commit](https://github.com/rust-lang/rust/commit/5c99175a9efcaa3d65712c119f361add22e3a859) (thanks @liamaharon) and now generates a lot of noise in the terminal when run both in CI and locally with 1.73. This renames the lint in line with this, but does not change functionality. May cause issues for people running earlier versions locally - @altaua requesting review to get your opinion on this. --- .cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 042dded2fa9..a5ff1d8dffa 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -15,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 -- GitLab From 7c87d61f5a8e979a200d3f2676a5c83e35c31db4 Mon Sep 17 00:00:00 2001 From: Juan Date: Sat, 14 Oct 2023 08:26:19 +0200 Subject: [PATCH 290/633] Macros to use path instead of ident (#1474) --- Cargo.lock | 17 ++ Cargo.toml | 2 + .../frame/support/procedural/src/benchmark.rs | 29 +-- .../procedural/src/construct_runtime/mod.rs | 14 +- .../support/procedural/src/crate_version.rs | 4 +- .../support/procedural/src/key_prefix.rs | 7 +- substrate/frame/support/procedural/src/lib.rs | 10 +- .../procedural/src/pallet/expand/error.rs | 8 +- .../src/pallet/expand/genesis_config.rs | 3 +- .../src/pallet/expand/tt_default_parts.rs | 16 +- .../procedural/src/pallet/parse/composite.rs | 2 +- .../procedural/src/pallet/parse/config.rs | 181 ++++++++++++++---- .../procedural/src/pallet/parse/mod.rs | 10 +- .../support/procedural/src/pallet_error.rs | 8 +- .../support/procedural/src/storage_alias.rs | 8 +- .../support/procedural/src/transactional.rs | 6 +- .../frame/support/procedural/src/tt_macro.rs | 13 +- .../frame/support/procedural/tools/src/lib.rs | 90 ++++++--- .../support/test/compile_pass/Cargo.toml | 4 +- .../support/test/compile_pass/src/lib.rs | 7 +- .../support/test/stg_frame_crate/Cargo.toml | 21 ++ .../test/stg_frame_crate/frame/Cargo.toml | 20 ++ .../test/stg_frame_crate/frame/src/lib.rs | 21 ++ .../support/test/stg_frame_crate/src/lib.rs | 75 ++++++++ .../pallet_ui/event_type_invalid_bound.rs | 3 +- ...ent_type_bound_system_config_assoc_type.rs | 44 +++++ 26 files changed, 489 insertions(+), 134 deletions(-) create mode 100644 substrate/frame/support/test/stg_frame_crate/Cargo.toml create mode 100644 substrate/frame/support/test/stg_frame_crate/frame/Cargo.toml create mode 100644 substrate/frame/support/test/stg_frame_crate/frame/src/lib.rs create mode 100644 substrate/frame/support/test/stg_frame_crate/src/lib.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/pass/event_type_bound_system_config_assoc_type.rs diff --git a/Cargo.lock b/Cargo.lock index 58bacc9db73..ed5e0a29f71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5098,6 +5098,14 @@ 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" @@ -5426,6 +5434,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" diff --git a/Cargo.toml b/Cargo.toml index 75da6681465..9e8ead6cf7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -345,6 +345,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", diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 6f8f1d155e1..fb55e8c9f66 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/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index c3d433643fd..ce34694275b 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -214,7 +214,7 @@ 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}; @@ -272,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 } ); @@ -283,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 }] @@ -308,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 } ); @@ -319,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 }] @@ -372,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); @@ -799,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 3f728abdb0b..8c8975a4259 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 6f793d0e37b..7f1ab6866d1 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 07b5a50da41..9c551b9f230 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -33,7 +33,7 @@ mod storage_alias; mod transactional; mod tt_macro; -use frame_support_procedural_tools::generate_crate_access_2018; +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}; @@ -754,9 +754,9 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream #[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() @@ -1612,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/pallet/expand/error.rs b/substrate/frame/support/procedural/src/pallet/expand/error.rs index d3aa0b762bc..877489fd605 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_config.rs b/substrate/frame/support/procedural/src/pallet/expand/genesis_config.rs index b00f9bcd1a6..31d519ef292 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/tt_default_parts.rs b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index 86db56c776d..c9a776ee247 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/parse/composite.rs b/substrate/frame/support/procedural/src/pallet/parse/composite.rs index ddcc2d07f93..6e6ea6a795c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/composite.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/composite.rs @@ -92,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 { diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index e505f8b0411..fbab92db196 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/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 0f5e5f11366..83a881751ef 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 7fd02240a62..693a1e9821c 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 4903fd1c129..c0b4089a274 100644 --- a/substrate/frame/support/procedural/src/storage_alias.rs +++ b/substrate/frame/support/procedural/src/storage_alias.rs @@ -18,7 +18,7 @@ //! Implementation of the `storage_alias` attribute macro. use crate::{counter_prefix, pallet::parse::helper}; -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 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>, diff --git a/substrate/frame/support/procedural/src/transactional.rs b/substrate/frame/support/procedural/src/transactional.rs index 23117ffa39c..e9d4f84b797 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 01611f5dc4a..d3712742189 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/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index 541accc8ab9..62c77ef7a99 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 extern crate #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/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 9c165cd03e8..167aec8a171 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 bf90d73acb3..6ea37fb27e7 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/pallet_ui/event_type_invalid_bound.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs index 665d2a984cf..34b563ffb64 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/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 00000000000..0a70c4a5e68 --- /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() {} -- GitLab From 9f7656df15690965215bf24171c45640f4f1a73b Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Sun, 15 Oct 2023 05:06:00 +0800 Subject: [PATCH 291/633] Discard `Executor` (#1855) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #622 Pros: * simpler interface, just functions: `create_runtime_from_artifact_bytes()` and `execute_artifact()` Cons: * extra overhead of constructing executor semantics each time I could make it a combination of * `create_runtime_config(params)` (such that we could clone the constructed semantics) * `create_runtime(blob, config)` * `execute_artifact(blob, config, params)` Not sure if it's worth it though. --------- Co-authored-by: Bastian Köcher --- .../node/core/pvf/common/src/executor_intf.rs | 120 ++++++++---------- .../node/core/pvf/execute-worker/src/lib.rs | 18 +-- .../node/core/pvf/prepare-worker/src/lib.rs | 16 +-- polkadot/node/core/pvf/src/testing.rs | 8 +- .../procedural/src/pallet/expand/warnings.rs | 2 + 5 files changed, 77 insertions(+), 87 deletions(-) diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 508a12998fc..58d2a90371c 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_intf.rs @@ -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() { @@ -121,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/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 65185b6f45f..af73eb16e68 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, worker_dir, SecurityStatus}; +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`. @@ -35,7 +37,7 @@ use polkadot_node_core_pvf_common::{ }, }; use polkadot_parachain_primitives::primitives::ValidationResult; -use polkadot_primitives::executor_params::DEFAULT_NATIVE_STACK_MAX; +use polkadot_primitives::{executor_params::DEFAULT_NATIVE_STACK_MAX, ExecutorParams}; use std::{ os::unix::net::UnixStream, path::PathBuf, @@ -141,9 +143,6 @@ pub fn worker_entrypoint( let artifact_path = worker_dir::execute_artifact(&worker_dir_path); let Handshake { executor_params } = recv_handshake(&mut stream)?; - let executor = Executor::new(executor_params).map_err(|e| { - io::Error::new(io::ErrorKind::Other, format!("cannot create executor: {}", e)) - })?; loop { let (params, execution_timeout) = recv_request(&mut stream)?; @@ -185,14 +184,15 @@ 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 || { validate_using_artifact( &compiled_artifact_blob, + &executor_params_2, ¶ms, - executor_2, cpu_time_start, ) }, @@ -257,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/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index fcc7f6754a7..fa5d3656a35 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -32,7 +32,7 @@ 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, + executor_intf::create_runtime_from_artifact_bytes, framed_recv_blocking, framed_send_blocking, prepare::{MemoryStats, PrepareJobKind, PrepareStats}, pvf::PvfPrepData, @@ -145,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(); @@ -191,7 +191,10 @@ 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) }); } @@ -317,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/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 4301afc3cc7..ca69ef9e4d0 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/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index 030e3ddaf32..110c4fa5198 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,6 +33,7 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } + let CallWeightDef::Immediate(w) = &method.weight else { return }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") @@ -64,6 +65,7 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } + let syn::Expr::Lit(lit) = weight else { return }; let warning = Warning::new_deprecated("ConstantWeight") -- GitLab From c9b51cd49c4315f2c744ab977941136e6dd6a571 Mon Sep 17 00:00:00 2001 From: S E R A Y A Date: Sun, 15 Oct 2023 10:00:58 +0200 Subject: [PATCH 292/633] add link to rfc-0001 in broker README (#1862) # Description - What does this PR do? - link added - Why are these changes needed? - improve docs - How were these changes implemented and what do they affect? - only concerns docs --- docs/DOCUMENTATION_GUIDELINES.md | 2 +- substrate/frame/broker/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DOCUMENTATION_GUIDELINES.md b/docs/DOCUMENTATION_GUIDELINES.md index 29029b894c7..5d1164e8ca8 100644 --- a/docs/DOCUMENTATION_GUIDELINES.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. --- diff --git a/substrate/frame/broker/README.md b/substrate/frame/broker/README.md index a3c4b251a45..eae0442dbf6 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 -- GitLab From 9e1447042b648149d515d53ccdef3bd3e4e37ef6 Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Sun, 15 Oct 2023 16:39:03 +0800 Subject: [PATCH 293/633] Include polkadot version in artifact path (#1828) closes #695 Could potentially be helpful to preserving caches when applicable, as discussed in #685 kusama address: FvpsvV1GQAAbwqX6oyRjemgdKV11QU5bXsMg9xsonD1FLGK --- Cargo.lock | 1 + polkadot/cli/Cargo.toml | 1 + polkadot/cli/src/cli.rs | 12 +----- polkadot/node/core/pvf/src/artifacts.rs | 55 ++++++++++++++++++------- polkadot/node/primitives/src/lib.rs | 7 ++++ 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed5e0a29f71..855700f3c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11635,6 +11635,7 @@ dependencies = [ "futures", "log", "polkadot-node-metrics", + "polkadot-node-primitives", "polkadot-service", "pyroscope", "pyroscope_pprofrs", diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 8057342aaea..9cad7e88dfe 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -33,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" } diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index faca2b25e23..bc060c21fba 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 { diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 5a1767af75b..d7b15ece7b2 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) } } @@ -253,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" @@ -281,16 +301,19 @@ 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()), ); } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 463c7f960ba..dab72bb2a5e 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 -- GitLab From 1b34571c0c423115813034783ddf524aac257bf5 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Sun, 15 Oct 2023 05:42:40 -0400 Subject: [PATCH 294/633] Paired-key Crypto Scheme (#1705) BEEFY needs two cryptographic keys at the same time. Validators should sign BEEFY payload using both ECDSA and BLS key. The network will gossip a payload which contains a valid ECDSA key. The prover nodes aggregate the BLS keys if aggregation fails to verifies the validator which provided a valid ECDSA signature but an invalid BLS signature is subject to slashing. As such BEEFY session should be initiated with both key. Currently there is no straight forward way of doing so, beside having a session with RuntimeApp corresponding to a crypto scheme contains both keys. This pull request implement a generic paired_crypto scheme as well as implementing it for (ECDSA, BLS) pair. --------- Co-authored-by: Davide Galassi Co-authored-by: Robert Hambrock --- substrate/primitives/core/src/bls.rs | 44 +- substrate/primitives/core/src/crypto.rs | 2 +- substrate/primitives/core/src/ecdsa.rs | 54 +- substrate/primitives/core/src/hexdisplay.rs | 2 +- substrate/primitives/core/src/lib.rs | 1 + .../primitives/core/src/paired_crypto.rs | 662 ++++++++++++++++++ 6 files changed, 723 insertions(+), 42 deletions(-) create mode 100644 substrate/primitives/core/src/paired_crypto.rs diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 951aa1828ea..8ce6eb166f8 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 e1bfb80046f..ccb61c12f32 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1213,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 05bc679386c..603fa515a30 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 30e045dfc52..72bb24a186e 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 3a0e1f33f16..75b84c89ae6 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 00000000000..355fc690779 --- /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) + } +} -- GitLab From 8ee4042c3bc86d4232e51a9bdb5ec1ae5ca444ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 15 Oct 2023 22:50:07 +0200 Subject: [PATCH 295/633] Refactor staking ledger (#1484) This PR refactors the staking ledger logic to encapsulate all reads and mutations of `Ledger`, `Bonded`, `Payee` and stake locks within the `StakingLedger` struct implementation. With these changes, all the reads and mutations to the `Ledger`, `Payee` and `Bonded` storage map should be done through the methods exposed by StakingLedger to ensure the data and lock consistency of the operations. The new introduced methods that mutate and read Ledger are: - `ledger.update()`: inserts/updates a staking ledger in storage; updates staking locks accordingly (and ledger.bond(), which is synthatic sugar for ledger.update()) - `ledger.kill()`: removes all Bonded and StakingLedger related data for a given ledger; updates staking locks accordingly; `StakingLedger::get(account)`: queries both the `Bonded` and `Ledger` storages and returns a `Option`. The pallet impl exposes fn ledger(account) as synthatic sugar for `StakingLedger::get(account)`. Retrieving a ledger with `StakingLedger::get()` can be done by providing either a stash or controller account. The input must be wrapped in a `StakingAccount` variant (Stash or Controller) which is treated accordingly. This simplifies the caller API but will eventually be deprecated once we completely get rid of the controller account in staking. However, this refactor will help with the work necessary when completely removing the controller. Other goals: - No logical changes have been introduced in this PR; - No breaking changes or updates in wallets required; - No new storage items or need to perform storage migrations; - Centralise the changes to bonds and ledger updates to simplify the OnStakingUpdate updates to the target list (related to https://github.com/paritytech/polkadot-sdk/issues/443) Note: it would be great to prevent or at least raise a warning if `Ledger`, `Payee` and `Bonded` storage types are accessed outside the `StakingLedger` implementation. This PR should not get blocked by that feature, but there's a tracking issue here https://github.com/paritytech/polkadot-sdk/issues/149 Related and step towards https://github.com/paritytech/polkadot-sdk/issues/443 --- .../src/disputes/slashing/benchmarking.rs | 2 +- .../test-staking-e2e/src/lib.rs | 10 +- .../frame/session/benchmarking/src/lib.rs | 2 +- substrate/frame/staking/src/benchmarking.rs | 14 +- substrate/frame/staking/src/ledger.rs | 259 +++++++++ substrate/frame/staking/src/lib.rs | 40 +- substrate/frame/staking/src/mock.rs | 17 +- substrate/frame/staking/src/pallet/impls.rs | 177 +++---- substrate/frame/staking/src/pallet/mod.rs | 145 +++-- substrate/frame/staking/src/slashing.rs | 18 +- substrate/frame/staking/src/tests.rs | 500 +++++++++++------- substrate/primitives/staking/src/lib.rs | 17 + 12 files changed, 790 insertions(+), 411 deletions(-) create mode 100644 substrate/frame/staking/src/ledger.rs diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 3ede1c90880..f075ce5ca73 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/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 e40bac3e9fc..1d3f4712b1d 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/session/benchmarking/src/lib.rs b/substrate/frame/session/benchmarking/src/lib.rs index 722bb14fb56..84258d84994 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/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index ce5c35524c7..f94d9bf4b32 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 00000000000..cf9b4635bf5 --- /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 dcf57a46432..227326763a9 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, } } @@ -927,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 c41144278f2..26d05d3a8c8 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, @@ -778,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 3d9b1157ca8..ad2de1d5931 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 0bcf932d90b..f084299be8e 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 bb02da73f6e..0d84d503733 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 78183cfde92..cb620f89f12 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/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 8b5797d7918..dfc18987d15 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))] -- GitLab From 91c4360c3cd4a2bba756e9cbc19f08377bea6d6e Mon Sep 17 00:00:00 2001 From: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> Date: Sun, 15 Oct 2023 23:32:25 +0200 Subject: [PATCH 296/633] fix: GoAhead signal only set when runtime upgrade is enacted from parachain side (#1176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The runtime code of a parachain can be replaced on the relay-chain via: [cumulus]: [enact_authorized_upgrade](https://github.com/paritytech/polkadot-sdk/blob/1a38d6d6be42b30e8be3ffccec75a4ec995fef9d/cumulus/pallets/parachain-system/src/lib.rs#L661); this is used for a runtime upgrade when a parachain is not bricked. [polkadot] (these are used when a parachain is bricked): - [force_set_current_code](https://github.com/paritytech/polkadot-sdk/blob/1a38d6d6be42b30e8be3ffccec75a4ec995fef9d/polkadot/runtime/parachains/src/paras/mod.rs#L823): immediately changes the runtime code of a given para without a pvf check (root). - [force_schedule_code_upgrade](https://github.com/paritytech/polkadot-sdk/blob/1a38d6d6be42b30e8be3ffccec75a4ec995fef9d/polkadot/runtime/parachains/src/paras/mod.rs#L864): schedules a change to the runtime code of a given para including a pvf check of the new code (root). - [schedule_code_upgrade](https://github.com/paritytech/polkadot-sdk/blob/1a38d6d6be42b30e8be3ffccec75a4ec995fef9d/polkadot/runtime/common/src/paras_registrar.rs#L395): schedules a change to the runtime code of a given para including a pvf check of the new code. Besides root, the parachain or parachain manager can call this extrinsic given that the parachain is unlocked. Polkadot signals a parachain to be ready for a runtime upgrade through the [GoAhead](https://github.com/paritytech/polkadot-sdk/blob/e49493442a9377be9344c06a4990e17423783d41/polkadot/primitives/src/v5/mod.rs#L1229) signal. When in cumulus `enact_authorized_upgrade` is executed, the same underlying helper function of `force_schedule_code_upgrade` & `schedule_code_upgrade`: [schedule_code_upgrade](https://github.com/paritytech/polkadot/blob/09b61286da11921a3dda0a8e4015ceb9ef9cffca/runtime/parachains/src/paras/mod.rs#L1778), is called on the relay-chain, which sets the `GoAhead` signal (if the pvf is accepted). If Cumulus receives the `GoAhead` signal from polkadot without having the `PendingValidationCode` ready, it will panic ([ref](https://github.com/paritytech/polkadot/pull/7412)). For `enact_authorized_upgrade` we know for sure the `PendingValidationCode` is set. On the contrary, for `force_schedule_code_upgrade` & `schedule_code_upgrade` this is not the case. This PR includes a flag such that the `GoAhead` signal will only be set when a runtime upgrade is enacted by the parachain (`enact_authorized_upgrade`). additional info: https://github.com/paritytech/polkadot/pull/7412 Closes #641 --------- Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- .../runtime/common/src/paras_registrar/mod.rs | 4 +- .../runtime/parachains/src/inclusion/mod.rs | 9 +- .../runtime/parachains/src/inclusion/tests.rs | 10 +- polkadot/runtime/parachains/src/lib.rs | 5 +- .../parachains/src/paras/benchmarking.rs | 8 +- .../src/paras/benchmarking/pvf_check.rs | 1 + polkadot/runtime/parachains/src/paras/mod.rs | 50 +++- .../runtime/parachains/src/paras/tests.rs | 227 +++++++++++++++++- 8 files changed, 280 insertions(+), 34 deletions(-) diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index f2751803a41..8b8c6d89d01 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/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index bb16c804150..e34286d750a 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 7677108d73d..6bb731671f6 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 64365f17b7e..e0ace86d379 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 5c060547601..554f0c15af2 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 ab5e1312443..05c4c9c37b4 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 2f370b5bfe4..cd73d23bdad 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 c511c65d473..cca200c2765 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 -- GitLab From 19f38ca3aa111f8f0cbddaab2d2e894f7c190c2b Mon Sep 17 00:00:00 2001 From: shuoer86 <129674997+shuoer86@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:01:01 +0800 Subject: [PATCH 297/633] Fix typos (#1878) --- cumulus/client/consensus/common/src/tests.rs | 2 +- cumulus/client/relay-chain-interface/src/lib.rs | 6 +++--- .../relay-chain-rpc-interface/src/light_client_worker.rs | 2 +- .../src/node/disputes/dispute-coordinator.md | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 22d3dd3abd4..9658a0add79 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-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index a6970732447..3dda6163580 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-rpc-interface/src/light_client_worker.rs b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs index 84e66f95571..6fd057e170b 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/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md index daba416e263..a9cb2741b08 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 -- GitLab From 38ef04eb53d43acdf504eea86ee3b1c8e08115e8 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 16 Oct 2023 10:43:52 +0200 Subject: [PATCH 298/633] Arkworks Elliptic Curve utils overhaul (#1870) - Removal of Arkworks unit tests. These tests were just testing the arkworks upstream implementation which should be assumed correct. This is not the place to test well known dependencies. - Removal of some over-engineering. We just store the calls to Arkworks in one file. Per-curve sources are not required. - Docs formatting --- I also took the opportunity to bump the `bandersnatch-vrfs` crate revision internally providing some new shiny stuff. --- Cargo.lock | 174 +-------- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/core/src/bandersnatch.rs | 33 +- .../primitives/crypto/ec-utils/Cargo.toml | 31 +- .../crypto/ec-utils/src/bls12_377.rs | 103 ------ .../crypto/ec-utils/src/bls12_381.rs | 219 ------------ .../primitives/crypto/ec-utils/src/bw6_761.rs | 103 ------ .../crypto/ec-utils/src/ed_on_bls12_377.rs | 56 --- .../src/ed_on_bls12_381_bandersnatch.rs | 94 ----- .../primitives/crypto/ec-utils/src/lib.rs | 337 ++++++++++-------- .../g1_compressed_valid_test_vectors.dat | Bin 48000 -> 0 bytes .../g1_uncompressed_valid_test_vectors.dat | Bin 96000 -> 0 bytes .../g2_compressed_valid_test_vectors.dat | Bin 96000 -> 0 bytes .../g2_uncompressed_valid_test_vectors.dat | Bin 192000 -> 0 bytes .../primitives/crypto/ec-utils/src/utils.rs | 39 +- 15 files changed, 218 insertions(+), 973 deletions(-) delete mode 100644 substrate/primitives/crypto/ec-utils/src/bls12_377.rs delete mode 100644 substrate/primitives/crypto/ec-utils/src/bls12_381.rs delete mode 100644 substrate/primitives/crypto/ec-utils/src/bw6_761.rs delete mode 100644 substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs delete mode 100644 substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs delete mode 100644 substrate/primitives/crypto/ec-utils/src/test-data/g1_compressed_valid_test_vectors.dat delete mode 100644 substrate/primitives/crypto/ec-utils/src/test-data/g1_uncompressed_valid_test_vectors.dat delete mode 100644 substrate/primitives/crypto/ec-utils/src/test-data/g2_compressed_valid_test_vectors.dat delete mode 100644 substrate/primitives/crypto/ec-utils/src/test-data/g2_uncompressed_valid_test_vectors.dat diff --git a/Cargo.lock b/Cargo.lock index 855700f3c20..2b2f09c19ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", @@ -1195,7 +1147,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", @@ -2683,7 +2635,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", @@ -4415,7 +4367,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", @@ -5730,10 +5682,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]] @@ -13923,7 +13873,7 @@ dependencies = [ [[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", @@ -16721,100 +16671,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" @@ -17051,25 +16907,13 @@ dependencies = [ 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", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 9f1f0127d7c..b9607eadb58 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/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 832ef6c77bb..78b7f12f9ff 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/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 15a6e85abb9..e091385071c 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 78f20297299..00000000000 --- 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 b2ec48a42fc..00000000000 --- 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 4ad26fc54b1..00000000000 --- 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 e69dbd79846..00000000000 --- 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 7e9cd87e543..00000000000 --- 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 22e24e61f7b..c5cc8507739 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 GIT binary patch literal 0 HcmV?d00001 literal 48000 zcmb4}(~>9(5(LM#ZQHhOn`dm>wr$(CZQHgzv-cOa-}(c(I~RaQ1|zDMZgoUF@F#l2an7&N5i3n_BtD6)Dm-l24C$QRZ1+ zq`j&E*`;H4tw9svcLlOLZ6S@k9}@QTm!)k`f98ST;rI(Es9DKe5lXblvz`8D?_qkv zwr*^tKdm)ZffX%wk_oU~;!+2X@rArydQNXstOOr2vgi}Xlso+ink>HnX+_{96CwF; zfhw0OGfhM(#}R3XBM6ZTrlte3gW{>TgBA034p4M6o?D=J!eEL%i1Bv9C%DJ~O)Ew;xf^62y$oQ7=Lb==q z+i{u*wZtu{E?|@N`e9sJ-S4h<#}M2zU|YBz7z9w8TGO)C58xOlv)m(i_z7FEb5|M*eYoZ{;lI7ZfYsYirxm+uwV{w>+u3#oC%Aq`74 zNOZ^l?+&hZJQ0rbs_o^XHXGN_;{qwmUXyswonh3EEq-b^RB{v8Px>^0dgL_pZcOSB%sz$-HWqAT@jpg&?MCKt2md2Eom6p>Cj zjUg``srVJ&MILd7cPa{eMav8Kw^SdqKq3<5_oEmk1%frOjISf1l4zzadDCv@L`%pI zO7^9=4EB&KJxWi1e0W{t)g}YTiOf@FhfqDst295fKK;S{U4Bft%&L_g@}f84cIZ#v zk4s;I?MeQ;pmcRaJtl6QK%M7~3-GY-j<1d@QK`6^mGZr@^&BHBr4%~c^xiKs%jqLV z_YFc3m*3o&M#cw^8u+wf;jkZr(}ilY(SbmTe5{iES)ZV(lLPj*yan&`0)L54mE3tE zmkNo!QnP=UU#W5Fk3!5JIxqk^d$}_A z7W6#}EM2|m%zLi#z)(Ls&Hr5aeb#r=jpkp%q8<@U!D1C`3zj=c8-NkK=Y$NHac;sy zRBP2*0LA@vutdX`DnxK0D8qp#q^4(r>JAg?{ zbxU+WEle$4j;x546C@FF2Jw)nv)rx5UF8a zcT()2fI`Lv08uevRHZ^-(IljEqx61v6!^*C=Z#74{XC6qUuzL~VCJ_@RnXpD1Hot8 zKP>|v=iCQZ{VtyVP7U%xC}b6&{+x7gd)zH;gZmdr1+oC&$kt1`)*8f<1%0;x6mGOM z7D>d8k$6P-otXKY$CIcZ7e@=UoZH{1BNbUWkh~^0yZY|05Y)3*oP2ROG%b-u@j`y| zN9orihY&HZo3?Zu1mH{iuIn&$;J2im7{n9HPe13*nqV<$&VSe1H|J8tVV`r8?!}dgD)$Z-a9@(TKPWpP#hh~Jy*8;jq$=|F9yjcau2 zs_YHuiCIHGTp0i;0ZeY;H6YLeZo}TNWfX$xzVd`QDvzxdmm|Nn?)G9LEGFl6*Ar6`NK*(5z1Vpnij0Vk236@9lB0_3f*`&+R4%9+M%^eb)#se;_Jh85qI zD%t`kgZp4I%7Sr{Sfm;90DxCq*XnD@sgiJg>K0R0jYYFN=8CT1Sm{*=AjwA2={csy>ao|^nwXFMOgQ{Q zFHUWE?^v!1xZyXstD~{VaU(!gE$cmN;_sg?8TGH!ID#m;47c2N4=40V_9WmMm%~4; zYhR)_q>;imSFe1jN!XXtV|F#fo!QK(L_7UwixD7Y$jW1=Y+M!l9ItX2aIbf+-}u9f z9b*h^JK*isMUyujgC*-1M69{5dD*P(nz+iO59k@DuyV%!SnDDHq4`-3$M;<=Z7~*aXnR< ztLXTQ2!2ltb$K*c{_b7IP`&Kw=4LR4@1Odhh2HM31wZ~Xry7F3FRK-bK^}3k)8zdz zGsKMAw-8e4gipCQGOTx^oeCbiNoRAC#(bAH@C=PGq%_I+hWgf1aX|P=Q>()k9)<}3 ztWcZ|DtiEvhj(YxL^ZIhX5wqR(zi2Nn6mKpXvceEP{!q#5nF<#7(DdH-Y>Fv07G+? zC%msLMKseZb1+a&7kc}m@I&(kUFPoY@O}CW8;6jw^NCwI6KP`K-$XOPWm22v-x7S5eHLEp z72KP27x^yLMZh0^nudDI=k_T<>B?4|vD$t}u5VL9cAap8?e(qloo*qQN>NugmM7M* zx0)}DDW5WF1*3%5)!%YMZ9!#FI3F*3KD2urR+j-4;wNk{`gqXyAm6uJ1Ww007;sOE z8`!sAI9lNgbqhF>3DhDmvOEE9`AD+`(;A36-DW9uLlJB|ZWeulS;>msyRM?4b7TX0 z8DN(xK|a7(F;N%PyO9qad&n#0H<4U`m#w!l??G$n-nj1lYa1!VVYi^WTONDC^~w z3E0i4s9eSBM+|i3XCmaOG`20iX^?iNlfR;c9B-WMHqsujS1V(zc^FS7v_5V!&F9i* z0J={A@i2D!W^)ul&PP1_po0(4HuP^Q7j)(7KB^sfM6-qNL<;5IK2*;(#pln(@Ax75 zVv1DnGgA|_k-kkSW%|f^supb;Y zg4w))X^t^!cd4c(OkX2-Z8uI_VOkzqfwe@^0L!Mi4X;J@ zB(I@;<3Lg1eTkgZ#E2cDbwf*4ES9*khr89-`q{p)aVNS+q;8P4!So@?ANj?wM@unP zdx4Eu2A$Q3zDhR$BR@jV6QF`{)tm3{6)7a~)mJk+Z`BHkKp$IjU;Ud2jxSz(VsTm4 zh}KrfGVw-g#;_tok(k$T(rVcXfF=1dHI$z9cls{{tBNf$>@U~`L@U7%I9vH)xVZh*X_^Ak)eQCPE z%G++_{F$BN<5%W`^=8_$XQovDCTIs$P<`(>z{!SE8wOvR590Oz5(t3X&f=f&TU2OY z{P4x}AW_fqD}sv*pRYi(E%<^#!Lu3!XJ_L~QYdFee zr^MU#|AR;z1T~f;tWkmKg|>5}TmW1dHqHu_y@c%b6DlU9G1C>>i7)(z&6RvUSt)|X zo0sOwNptd;hc`8i?iZQx7(xCL0b@qO+*~x#SR}y^Oq-Ott%fY2fETXy73RFKA~HO! z!QU!5-_;p9xY$zF+|Q}&gIf(zg+()#0t~&ieR@R5sIvSxCNaHv7p^vhr2y$o(?5}) z7x5oWjdN$ab2JX|n&_p>KPfV(WwLm7O9S6eA(bbkwP(z`r-3m7o?FYwmqzTS5O#T} z>#dQGcx1n3qxT(=0y6=8Ur%~eT&J?NZSdKcype0Vh2vvkjh0x7-wQq`{+lm65F64H z>I)mB${OTiVq$jz)bQRFJcV@by5jwKyvXgVozYW1K_7y?;%iJ1nw#a|t+m=$IZ0imQ{&es6c_ z(P35Mm7$Hm8?tctDbG)sNRm`F%IV3G2o!Qz-i+pMf z9sgvS%CHhOA4>yZl83D#PuE?rgW5?S{9mWWM1$ zTUQ?~;sS3td-o$E&00}`hTQ~6@BL4O?y154GVX2K;vW0~C13)_E{nh-B0YcbqA)S) zI`+~9e5}T)Vqphm?uda<+1`)R+$m1bpQ%(m%jB46% z#aaMZCLQ80VaCHgjqVzpWhKG^s5VM@_7E9bhLU8u6aCKc6O8KssBb$vQ$7ls312;G z1=BGEOz1P6gr?J?Kw+*Dl+!iE^Wm|A!UTi=ZS9HY14686jx$8s(CnJ^mCFLy6u{aI z=`|6CbDuP^R#`_Gj!Lt<8Aq9)sONpmSRQ1cVG^dN^1!(NgQoEq+U&$1{CszNm0&mh zc{VxXXZu6N&8t7y2XYI$Cp>%aI^5^BtkuVZ5?@dwBOVH2wq<^M<*moDXNKFkf9H~C zY(yI6y}vph>F)(A#}y%i6oLV)&Q&^iN{;(bs!vuCwK}Z4AgGb8rsMSEp|m3#NEPvT z9&((J(l;m3f4hn^*8^!@L2YgPMG)$!$p{3%?A#cYtmv&9z0+_PQM-vFui{Y zU(`f=bZc8SmX5*=cQ+g}s9PawbqJgRCgi8Ka_^{frRe(rM)!&3A5LH&)04v0$}xU9H`c}i6=8ibP_Vb{=*DT{t1u#3~nrL z8zC?ZWP$Sd8e=+-z@{4t2EM3i=%F&;2Eue(kz5dMo2UA4@kQMlxyXP?0=<}dkVL=( z?~8gD=}GP*?`cHBa7Y^P+(*atk^9ov&3)qNHMIP*T!`hex7ZwFSr=zPjp>a5)5_cz zzT(m!vew?3xQsv<^zq>Y-Nx09MWkllv75oj0Y^8v#i0>RA~zT~fk}RaricmVb_>u< z;o70u$KLsQy-|x>lLZ6DEwXU%K5Wse&_mC@O1_$RiiX2tOt8f_{%v(26()v_M~({x zH}AiYxdMGJC?yPajWC$7%Qh9ii818fbNTHc9YQY!0X0p21BAIiac#{p#$-qmqZ^#7 zF|yH%16=a{^%JbvsUYHU?QCKT1`zYvHy;M@>h(2!Mmv$qC7Jhc*!~W#|8B1>oWnD$ z97;;?A~n)q=r0=KA#$jS@N%K}53R{*_QU@6mLy^M!ZZ*y&-3*~G(d;j^v~X(D~I>0ul}nC*4$gOn$igkhkG z%C93-#lKbl)Dt*p1PtDJh*65a*Xi5N&xtC|DLZFv2UNG*Mohb#$`86DO_IKS7n7c4 zG8$tT)o>&*(j^j30=yF!?I#2R1!t>^rRqHda*(HCKMoJVVl9_7n4UXDUw$3piB8)s zUhz=T)`L_-+kjkU#HH`fLlPVbL^lPiQYydhIecd@YVAniJhLkKIAWVXX%JUhs}IQA zJ>CAL!8UnlOTT>M9(cx{E5&5p!CKzUwR*Z4CM^EK?JihzmM3(ADPwN-9rh0ayqvs@ z%QL=?5Q{*_L$|_un8FY2oi7&J9Z4^I=3nzUlwlSsLDWn*fHe^LCn9`4YoTwEJivcp z^`m?aRHYObr248hge>nFk%e@emn{Gx495kpdPY9ICxa2EHPST472PLU11AF*M?kz> zxNf*JrBtrhWsU;9_HiSW1)8IyZ&>RZS1=CW28&Mu0gj~LD_Vxxx^H)*MRW|$spmr( zj{d+VvSCR(@-X<)#__w~vTsdwyUQ1r>4EqHy*o#~8=F3*;(TKhg6gSKi(Lb|LFndN zpzP26_AlKR`?D5jVU(N_aVnh|VdxBgB)(ntEPQRumx;N8uIirtMqJ0Qxld8BJ|9+{ z%eQ(2MLGG2uQYl{V76=n5}T)-20sYcMdiU}=3D7E*>qZC=>3kVw)rHJ%x47$n0VGbX&e~l@Di=ceuO%am)AVrKNz=%Tgys{YiE8IBryu)8Zq*g&}07 z$Fd~xQ4Sh$%NfWLV`>A7mDwe(;DF16&oa@TAM`$Cu(-K-!*x_#=%Bgl=lh`ZLtyeN zs7S}b`nr?VyF^mo{LIVF9xHnp!d{Guj~>JCL8N&+T>GL;qI+kvMjK69_7qgq0j&(X zEp|QkLjo|x@dFR*>)~0AW@;a{RSzmtCGulV$x1cz!qN*}cVIQwE_3*9aKwWu{i6t( zX_eTmb2|MlMA!=$u;;6WDE!cYfhFB6${Nq)O7(TjT4(lFF~zr|gJw9%_c6l!4*{q}5gZ>ySb4$$AN zZUwm+8~eTA={QEO>rentlxHdD19V{W;+fc(?_rPwF|(qBNLTGPvy#qG{A_OhC1mu6 z@1msfMn~nV;D{g6d+#bP17VCl^A4)B$}SpRoPcfRM2;GU*@-VY6xt4BygxV-d7XO) zuh+M!cBQMN_|+K=>b8*4gbulGeq2fC5j<3i6>FzcoIh``Ls&*&4An+(d7-xgoY`p; zMhx=XJhJ3sV_8-#uF-N(C-Qgg2eco`(r2^TnqVdq@E&}uF?i3&P}J2Z#kJK@{BYO} z=tA3}<6m(YCfPpq)F~*LjmtAh9v} zN?+q3zo~QXZ@e@fkr{L56$Y?&YM+o8LwEqe^BPI#-z&`xsu!ULcEjTF4S_rK>n}O( zn@wxsp#hVVYiA+@r@SR?=c)|qQs;XLN@ytWmX}W&?VnamuUJAFE1%ZA!?tNlW6%Wu z&QB+?&D71dnSnEO^l};1BtZvKj}Y<@S+v957Gn@?BM%TxOUuTJ>p-H4Jwr+oM!|J>rSHZLBI&R?Qa)UCHXh z)pNGeoIan=KR65_#$t9Lq!LbZxwj(YMGY866Zqt=t&R;e#UN}rUKm&7PM`m!xed<$ zyL-!WEH<=UP>!tiat1SX`IqCpZ(8>3Q;`wYX$@EZBj2MyP`IUlNO6^8nTgKlEJo^( zt^)kTsrgN>WR)o-Yk^wkfsm9p)R26x`pKKw!qeBCcD6q&#!f60)lfs4LXLddFAHJy zDB!i_{@#wx4_@h^y>gte9ZHNMt&BsV^yQ)@8zqy)zy)M;`jLefUT}e5PCWo??U@r( z<3ZNiR=0>#eA7V!k)l0qHK}}7T9<#$6D-Uo2Zw|&Xk$Q9EJVtSm*cMj{y6rwkt}Y% z#SY1O?ntMvSWYj2S#A|EF}1p2a-sPPV0c>51{z9zm_p0*D%677qqli{${Z_qm8KOR z_(!1K7U?pg1fiiAFgp7xMb=_tiA{bd-kM<4s2oP3u0#6=qBkOy!-RioUR6e2&sN z1*YLBp-WIrYx)t`Z1E3$fsSFoq7Px~2p7E%q^xJDJJc?>m+M#K@rQ|J*jS5D$0M+W z_xVdXb;D3ffx(}ki4DWRQdly0QXs+@k~=QJreH>zWsDqiV$t45bS9w?Sp|35>@oR~ z^Z?c2hYsh`vRXR11LQgvm2at<6+*2hEvZ4ti2yERt1qEZK5VlBJQIj#=6Sa-c=2O? zu%J(Usev`2l^REpuRn4T{t6JoC8QSaePc4irthjbuk_jzD`oF-(Z5kXZ4|kEADSaq z10EitQY%MK0NtaA+`ujzg6~jyY*aT?wg_EAMt;aXLsR!&eXN73nkpDN{yB$c6bNO< zbY#=>S8u+T8#?HtSF^nYR_m~gSltw(3&5V5G@{$5%~;W*3s}eDs$(_YPI#oJX>p#j zY*t_Q4uWZ-iGe^76MZk+DMhaW7V--@)rx3=hw=1imsS)LIY-MvX#`T)`BF}aM8s=) zj?#>OEkhX&V7d8X?R*E`_ZPTj0ta}e*)YIJsA;5s1bKnNRi3k(EDz|-!$23t(^Om` z>+!FvOZ^kJ&`?u1?taIgUhJ6OAel|zm+{?ZvOx#!#=paW0)>Iz$#m-48&)Hyz?>rp z5uGhRB3k);;LVVduFZ`sY%Wd%^`v;mo$f;K7EnR43hV`b;@_uthuR#Rk+R7};ffvL zQ$)|mJB3>yyKA}NOl(q^H=G`{YRznCT^)n0i9r?767`I)*oDxwY&g?p8Ebt6aWrQJ zqi?jC^3i#!;z_69ZUt7uPO;sV1<>`30Ba{2MuGdn4CCup=d>G>>KbKAQ)o|pKFemS z(7sO7vEZto!G7m6e*p>{3qDXJjWo#9b0o~R-oaR)?#wV?7Jyv8Q{XOKdVK`xlgC2i zFdPG>z9EF5KxUJp)Y9XElOi8(xJ(pz-80Y(u<~23;aGFcR+|jGwjgOdJi!5;IOc0s zbxhV-;%Phvzy`mcq!afr^%saE!3ZNe7m>WGN$cr#SM#cUTaL+jX&au^{t(F@7+MXM zZ7f5t+Mxei427(JjRO0 zjSJPr{>XM?C>Xrl z99@fD^@)L;40ney-b;^g+*=?jaYf|Wi7Zi8HJU7Q;*?a!?$tkp=+!XnC4s34ba={T z11cJFbNU?mq8fk9Q;=3b%Osqwut%~Q`)gbHXWw7~30w#`^%NB08h;VQvbLDP$BXQq zM={<_&edM34IOZXgHka_x119NkLZIojCkoEJJe&`5lfWB$cEEr?#|#fu$Ng*AS#xl zFFHi7*OU6T9Vs4K(xi;yGwFT}Jf0$&#Fzt~zuPSlKV2FUPuY)UOCbrv}Jh7bJ zRN#ACu~_eBhy7bN~RSWEm@KH#9jYBFCX*gr9?0 zjSR{+=<&YmmwClx~|m#x>|=Vr0s}C-sbF0V$I=_6v+H)!Q*z(vY1t zy-(22N=F~lEXYOkR3S{uaUP!+HK0OAeycQr6ADq=s}h_Wlk}o9^jxYX&=9XD zvc=)1M5$-@HjoODVzlROfnE#z685B8x9v}X%*|Wr*$v>mhS;_po@p>N9S)=ABU-=t zOb$LEvQM!1oIN=U4xk?$VG;qK&>`A~pJCx}Www~s+0frd!x`=A6>G+v1#6XZ+7P9H!cF4^7=_vff>v^NxzJ-%QcBQ74e9ieO2 z67o>#^8mN&FM#oi!Om%q@*Cip&S92f1xJyQ$6qzs9n4m>i*Ew;_*HGe#9W8(^51Dx zcYPzGu>mRxRmRQqQ)aJiQ*|{K`}TA|fYc^T z_Xul1MjKUC<_*M50P?xh{)-yFI=+_hoh;Nz5m0*h)0-xAUO66*s|LN&A*++lG7|Hi z2x{HzHW^=1z-yRL zD3r86N{c>lYF2#}R8&{>&D~49BsQ^EBB<7W^vl%cb?rxF8ICe+`XfOXAmt6pPD6@^ zwz?yoovKrGc!2UjnI0Uja)-OG4n3YD*8EX2+05{kXD$FsZ-}w2=MA(ltoCS=CH>b> zR@>mGFjUXRIO0zKZdcY_y>?Rkx>DPR_bM*(*qTc=?hzo2+e z&KV__s#T+z^PHf;Na|Hxg96Gmv}tdRY{5M`KvZ5=f}} zKWrJ^eJKm#GcYqbDhK1)_s1_dN6X}!jZ(@w>DA#Nhuc9sHJG=&K7LE1&IPcSRfRz? zepNzxp#_JtmMq>Cwtg~jjtY5RB86dXmBt}+XHQ+soCW}c4vt2{@Y-bjqLMg;%QV7h z!LU+sG7KO0tz<|Zhr?4syD3hnL=n1kTqNz26|*IqTmFR=w2w=;A0TY|Q7mb}IYwzKXViYLp|5|ZUHUhCqUxFd1yR)5Tj`?`k`mY*QC&79Gd=iDklvUmNn}4#-{Pw=q)shto`&DHo?MVu zN*2!u6+qhSD12(%a4?rp5h&QHO(P3McTYKq2bW5W*c|A+N`pJ@I;2e7^2+gzE7W6$ zTF>^MLvlGXVo%GUB)Qf7(=c(E6rt5OyzUBjXQc;B+PO>&2dybvQf#B0Eh@5W4q#Dod(*HO`gHj)$l|47mXv|>7#JuYg)ZV;jx9*As*%v@in8vR{OJrqbMHG+H2x%Y z92ZsQu(dsAQ53jrw$0i48_Bs*Scx?XlSAFS)N3;Ol&V~ESfzlrE?Qo5{l^$u zA+CcPs&oJ3O*EC8U=8p=?~uQi`8l@d2>%Zv;1FJt#Lh&84^1_{Dnk?)4kbhycO!g{ zA$H06+mJ!Sglu#Ut+*L8Lw3NL^o z4QX_28P7Q?+9xsDLl?|Wk7NbxxvA0>xt)Ol#-jdr_A`KI^hpRNiwftjR(si(%acs5cKF6^5Eq{wa1I%SxIequL}2Z&g!koypFB0GvgNCS<|Idhx}|*&lG_hoPxyJlmb`AgZ5%LlWil zD->cyh8+NOI6mYz=8*PvUxK1OaPZelQ+qu)-Nrmf^raSJh`Jh&Z{Uy=0=U5)+aKhv zvBr;3kN*6(Z{@Ga7cC;3B~@kQ=k?#UnD|mUX7(s#R}`-zM8}C)R1A!Zv2YxJ z_s0@c)1B@kRZY&QQ)6SU@}C!K3cDhkJsZHH5PQ=qgR@*x$5=FRB&!W?QNE*%9E}8gE(>;){Ym-^i&O`k+2Ss#9BH@CETiqpC)!hROaKLv8J3{Vj<|Alb=IP7yeOe_;xY zX3Qx0jK+))%l;0iZe8L;cLcExmo8WJOLAS>M{fN+l^rV+2gg6MTQf15jlwiGMu3Nu zJ&gguN+xH40??`>!sn~e+QO9=Yy37Ry1o(tV#(J{$5IR$tKQA45HtVtvt6{1@Rw?R z?mYUc$!!>Ug)x)Y;;MIIG?(82B)8>UC-tG0)&MnIOJ1fH^@DigtW^_*=V^$dV4#|Q zG7%w$p9pRj8lP{m4CQ!{f*;OKWS*WOhPH1^SfsbP+NHNFy?KdPx=rWftg@i zE2CaC{k(HBBOm2D!KU&lsc77qt4Ws)GAw~wT}V);q4!5)Xw7*7p%>I3tb$y~o{Zfe ziN_&$GaqX*w?(V_#%ln%= zk{y=0m!5M!Ool2^dWNdt%(=5yPh@6q2xOSZJzEMp5~xC)!D(geRGNjs11_u zPgz%{0p!-=0nrtQaE}-_mRnCmh=5*f zpE+{bxMUEPf}*4an@GLmx3mr?ZF#-5Vn_8%xeaRXRiMUF77hVYg zE}!BJ$f7;pH!n_R5@Z4?ZqVJswPw6q7SZcW$m(EwsNI_~t}Q}H<5;c}KrU7MVJ#F^ zw-G<0$a04bQ3<4tTWLjGMBOX(HDzgkYnVu_QUV@iP-<%nK@GCdjz-{PvrXjB5*(6T zg&z6eqm8Z%4j)U*7VeZudAhSyEQW~RHFX|07*y`JlbnFmh!cpCMr?j<3shipl{yE^ zUWn@z!``(u!TuptJyPn_39{xi+sv*DLp@E_DUQ0GbKbl|vPDyffIE$-7(%{dBtHkp z4G8RZalrku<66Dj)e8Spn13{wmUP*p*OkG4OsxAe(BGjUw6OuidQ=SuzsZD1Yn(J$ zA1}H4rFRws0F&X|`V$77T<}6#j;~Y_DF9)my$0a&&EqD#I}aRirn~4ZmhBSNw>)GL z+aq@OzxnC)lvCD~`7^SL)inheQr+kJnAEosfA{@iZhBX<6pjZ1VOqej1=F{l+dlE>6KRlYRb$sLxiStH_kDq zd=H)ie~}O5O$=;*>j;$EQ2Xp|;HQ7q4wlCtv)Ft>f1@0}>gsN#f3ao0!E~kQ|F!MM zzoEK43tvCGC#HTVdY(SqxK>T=yiLAr-iV6BPHF+u7~S+yp9Fk`{JQbn*YkXD$pFZbSI z8vwxnq%|ihG(L|N&o_HcVL6KqYr!nnLdOIH8c0m?9N6Q>fL}U7*qm#VQRpFR=m@u3 z5_QfO{E~(#)}2b@PPfwAA_P?=D9J$}!p_P)0KUugI4UbF;R@;_oU{IhR4z#$>1#T+ z6zQ6Sy<@vQn65$XrG!#f-b?Zu&}3o(WU<3r);h7OmS1)p(gDqm&iAY;o*J?%(9QGdnz*@Dxj1<>N1eVq0C7_YAc9&$zi#!VXdO<dfk_hDcW<4dfp2<;?bQNvEcLeap7fw3x926wQQ;}~X4 z9gGw17k@0Ff5^OXyFZH|3OU`4HXJfGN{=2!#gk?=q)u@Jrh`S>Gyq6Zocj_n<_$V{ z{R$4GakEgWr*llFH@jmb;7y0lP%n54K!3E=92L`BUtc8pD@O6y)6ZF*_ZMO!)Ed_I zBG~mzW<=lbRB|ti$B=H(!HA3MR?<&+2jOdRQkTcM!;*j=N%|pOw{ze*$K* z3E(@R6`#p=ZH4A|F=XD#ol>?Kknmdq7BuXz5Q{NfA%7CY@KYL@4ti{8z6dW7>`TRI zrM9!`waJ*+x=Vm4c)UGXs&J>8^k z4^DB2dkT>BBAi=Z!a5LLMdf_X$I%*WJ1xH*@Uccm)EmgtNdd8%qF4J=$DAy%`Mp3_-llP zKGK?ucC9JO9Y`C?co;-2dOP|EC`5}1O%}rtco$v zY8ryv_vnpf0gL1;a$Q<%IRd#7-gRnW1uy)VLo)iX+dQ=*o+%2SHpk^tB^klmr*W;8 z7JVQB<9uaWY0v9dP% zwA@r}m&yM`&Oq?Mab5688^rWBM`lxM^DeH)7#5PuxD_=^KdU|*7VC;IgzB3E@^N{I zRq5ahvt5gkIzjO^2j&w;dW#il1|fYf3_z2wuz=Q&U-h3Z__^nv8(=3+H5tszKR0yB zI`r4H^s8N9Q;4Y?5uiSA61z3-tdMJR2o%bJ)T$W$cDflIr!|Vs_Wx~jU%l9<;zHHs z!9a}5rX25cfRE!LiGDx@dqV_!vIl*I%U#0KzZhjaS1}rjJY7OuM)pZ5BGs-fd}N>)`+6Sv ze%X^y81ODVjbm#*at@C*`2~5-ttb_Qs+rL15^O4@Pwh-wlO1j>Vy&1SFm7~5mBqGO z$w4X&&>XCck5U$6>;=P&kP;k++ZSLyARA zay|@+!Y$RMXUGk%0!L#HU*{8;Vb6Yq#y z4f!L+b3LwIV4G>cP6Sb`>QfWMX5eoNZa}$g?kQ}R3f{nn;Al_;!uG&?seNz9sK)oE z6a1#q0yWd8+J4*e9CzWbHBOqzl(mmG6Mc*k05En&HAKPY18wv87_*jco z+BTbPlLCP$B1XQHb%qAme)S`P@Teah`}j62NG+>O))>y(Oh(L?ngZ-C8>@EFA#I0N^Z%<3_mL3Th47^m(fvOSxTGX`^d7M_lXOudSVf&Qa* z&Jj}?t2iJ^y0oWuz6lFM9AX~1@+@yqQokkd)k`7yGyXdzMjgQ#^X)wc zFM^v^3HgU5)pSRX;@}<-7s4A1kk~dMKF?%O{WaK83P9w1%NhsEwTj`v9QWr~e5jG( z?S6Q~Bb0N~^y{7D_y(hPjzV;L$RAv{&bqvw4EkmjC3i>FU89tJN4V2=b5s=J-`FtN zXf$_0Hc7$gNzyV)pYfz)o8{Lcg&IMW4eOx8W(b!Dcl{4SpHt zKnEi-9pY6J753^1y2Q&&_v#Vva8lXFBIB-{qlm?=A}v+wpW&IZl1meo&1a~r0MU{5e;*B?=1b=gCgG01UAE>T|l*@_Hf%RQeV zv`#0<`m2%nS#NvoQ8bL0olypkxrbEUv7AuCCb63sGsc5g_+E4;kuPPHYm+k%h58OI z2o14pg;s@$B1g^nhfH(zFxD6|b!u0-#$ox)D7G7RpATDBiU(4lXw$-U@lv-K3HfT! z_!eNwC&-i!m>FX-#r&UeuPA)P_>Z!RquP8nD8j(`MQNbIzDkJd&e!+yNJl+OXm=Du zXx&(fa|bJsx$4V2#qgJZ=KNEq1Esb4{x8mnmoM{( z8wRV1w$!}!;fmr@*z1~B%ykUY|=0iw|9W_&BWh>dhDOR-e3)xn$Sqt4gY)31E+E$A=OWG zed0|F+4feK`1XoWGQKobHo(h5G0M)5Tn}$z0IJX|S=x3Z9Wkgb9)Q?}c>#Yp){a88 z#=(a)6)qJq1d%T~IiE}dMI_+=04G4$zXrS}@L+G!<&WhhrKggDK|uOvzJ8fXNVRkf zfKXif2_MwpX|I;3)&Xn!N5L`?4JAx5zh4Td6|2&A5riB`5h4GG^rA?7z#4N>4q52V z)lPCUAZm7H;Cb_XW;b%8%q`!HV zqS}lF`R6G;h=d)dXoxM@E=7p-woT|xl7gks8)GkW3 zlEVy7qu9=@3ywdG&liccJ3wxAlBE;F@E>1FP^SV942cx4z$MwXT8hvv&WX+RpV34N zVkW~y`IETWoy5esQN(9a?3wbiPqK{3_!z#(Pa#R!?V7BqSL7(3?sr)kpRqn)*hHW2 zx2!OeU<`akacsG|x;6qU91oLmL6-R*rUg&Y&^8{J9Rw3-ucS?$iqsl|)3*>PPN@lj z?^SP(nxC4lDz|oBw48C>JI&=DP50Cbj7Yb9FiDDWPw2M~8V?K>fOm$Rh>IoYeH1jsWxZGI zD4U-7t_cTGxI|FuGZM_H|B{sGF|nc`ML@7w2rOg((7rTj!%J?_>M45#jY88>WDnVf8sXMk@U_;SpU@o-<6p22XZqXy^3 z27__AIt&^vn3uanUB+anKR5RX50~lKKwCV;chON2 z;UPtRwAlW)6!SZ|%rEc*W~T@haoXK&a&Y3Afsmht4yP>XbWNHHmH5|FK$*ZWrj8{i z%%?d!7$mVX(+>D8)Q9qTz%MLi4!7x;kDZARc7LctP_rE$et2;>8VBYCwYOA(cWhKN zFTDxv7;l8k{-d(kcgn^04Lz7CaLQRyBQ}GvH0z?CmZ{~73n%N4q?rdKe2c(&qK031 zA@r9D-Igy=ZlNF6sh0RdvJF}?54#8dWJ*< z3@ll7|DSc?Ze44XK~vBDP-dwvR{Lf*D)*WK3+~+~au!{d)52`zqSE_oGlNGufF1m! z$83QIHUpy?`O@=A$GhBg%?yrzP21V`BYdno-E%W{47hZ8UuP_YsH5%TU9J(nRKb+p zJ`m6W#l|p1$GdGWW-?KI+lmm?;2_(d=FCbbx}(_to%AS>zJf^=`X{LmqS63+c3I12 zOO(Wq!iE3C@dxsUZ9wua6hY%4O@5G0&7MlHwxjv@__5Gp2%{+J!1MrbHP)D#fz_n9 z_3<0n+XRw$PXk(-IHq!@|7A>oQ!k~on>O=SVW7v&4O0i4@oEF_iSB$91ma}691V8` zx75#p4SfmX4a$>7e=9`32AZ!P4-wO(KC=dsaj*0^GT;PzcNtFp(r~f>_-hdMIk_e6 z#vbhM6?UE7?tyDY73WTeksx4uhm#3OUO6EcnQ&$1@OX>c8hwRJQ^2cB!x_6l;?7c5 zF-#?d+QP_Yq2lZhoZfB9hqzUgv_t-8C{p5c@>vLxJsoK@uk1R|=eWLH+X&EmbLpoo zX=@}`YI4qHP`2F5R&x_Zhgw>YR(!qvjm&waA9#jW!++=*x&iM+BdL`yOoqfXh46$=G+`#|b=%|^9V%7+ z*|&W87x$&nmFhhw1zx%9-;oJ#f1PchUDDcceglq<%sEl|X z)&o|YWL<`Vv9Mtc8NsJe!Wn}#HdbB6ewdmcjP>oIMGI`YGO`dL zpLBC0wfZlP<*E0UAye7wma0q#K}1s(n&)Lh@-V(l0gR&eC%E5Q)&r(O$;vwkXxe_t z$HLzOBvW_3QKBIR(l0O+Q(lZa1g?%H7)+;((x!fJ-=Llu;n)Hzuj{O-iew8vFwaak zh!1-)Y^|@lX9~ZZkThnMGUsQ3KqxwSb)z&0t>N*H-GnuG5#9;-ST6I+| z5VLB(JK-&wMC2w6cJER*{fHHQMwmI&(x3mKsoqOEg#GBZRjeZQ+1ZQy1sMQCXVxu4lUW<%2!f^cbDt1Xl9X9r6 zOhx%#Mwuy^FJmi^vwASdb`5ZQf#TPSF|+&s2-jo$2!{^n8`9}GDuVE`5|^Vf)t;O@ zu9XwACK&Otz0^QHpqwS48<=yh7-j7rAwc)$9wL1Q1JpYe&9+K`Imr1uw{4EJ;)>S) zXvPU3INnqbmSWuRVkD?BNE9L$u!>D1z85&I*qmxbq2jMmO9{leB8fkDij-m7%w8nZ zfRTI+P4P+JQJb|o_dPxfvVG%p@>r<(rxpoSTr}#d?}>N|4~$^W0HfL!H`cx_1FRP2 z8OGC{bOpsVmT3ykoc2--DI;6EqK@Z7vqYYB00OS-NqGbd$oJ$+&DZSOcOuA3zK|@Y=B)pPf!nN#BG4_OXNJE$ z!e@UbTX5*SvPpz(1(bYm+7)z|M0|W!95KInU9Tk8nAzekzwgzJAg4kHRQc&7tyi)% z0~S{~aWMgcb$7~+o%e#Cz;+XfVX0^N@){eYa_bNUSR7w8*AW}k^`iiDG>wI zm4cS02-mKhLuj=YviX(nCwG6R0i%&qko9bfxuGYmmz+q0xl;V$25X$$huUFFIPtSh zQ}QREgv=woYeyFQa7c)SET;3xM6e&vrFsR)85vf{RGY7jAkj>9LS8zUEYV$$uHoJ# zGK5Yz@)iAbjko&jr?Qbc%#-AgG(bd^vXA{wX%s!&lDWBJ7CRx#wd%8dU{Jc|oEx$4 zXg8{M*3ZibyMi7Flx^&alRGmBLEBQj$#KSbV(%d4*)R>>U~VAL=J%+r@#ucHpr>CR zjm?DljzsLcNmsJZVkZ`ja_$EN(Tc;9b;7b$9vIs5%)0 zuN(E!f&ZhtxB&I|47dg<_@V`sP~${GPwN#pNU=Oa+IS#73=GU0c0ak>n)dj@fMqvG z+t+@9RbR-pxVW{kLFqqe^|9gOUY$$$thPY{c=uecgYaI1&OQ6&ZNup6qc)+q(&~xs z0MSPM5U}Iu~o(ocpH#wL6(j$f-ud&inN+n`oZL@>u z(3THxS{JUycLuhzUPONEc9>&y2VLL8(TO~E_>lY;d5DtivZ8PsZJ)h_x_M#o2pWq%D*)BySlS) zY?;~%k`0bC!+J9GjfoXiE7&{S(6L<0yP^b$U9PS&lQQI@`^-V%68zz76#&#`B(}4Z zyN5ghbxYNitqxt8?J_={`x{Dwzd~+~Czkp`zWz0@O$(79WGb3+(ZRE3p|2iUmA#xd z)c8Kv$-11H1^uUJJkc7~7>hmPXAitc?3JPN90?m9>m+rHRXZyQJ*I-2DqRwbp)6Y< zIK#p1hq05lM9#7nno|hgShV}Nso#~0?hhVY$`*V1 zML*xbK}S|OlaKn>(PrjaR(gJ+QgXs5mD2Y`xuuECM5jrT>J3XMwqA0yl?mRoM4T-2 zldfl@c8cdTrL*}&{z9H1ML2$|%!yc$X|!8x-j!mX+ikAFQ@oU>!fxpYDZ$>nmbLEu zk3-|C$oBVUGqD*d0_Tygg&v{eAV{2yMXZL;+(=51MPLYjLEAecCjz(id4TJV56qS-SznP9Eu)Lo-2{!PwWfTYm7;O*WPomKN?{Q@n185w% zn_f;JOb^C0?y8P4+77)Ca;E(6o4;ssh|-vE)Fg_f$q1KIDs|FZdEhv{8;oX{q4n}| zHOF`{eUe`;mUB<<*yYc@o?CKh*P$S7ESKS}kPANj{t4%t0alRiv(Ghf-9-LV=E-p0 zZ>vT5Tmd2}!4ki8j;wd_Kx6>VYpGMYs$z(SY(_qB8q3Vu&{lRALQT0_x0!T^?nuWMSog4 z&RtQmOQzfIeet}+!b@sE$nLG3C6*)y9gK!i_XoiB^IA_HuH6o}A*fHnTQEG`{BLxA zU{i60Sn#7DWzoB|P^M_ehPALx=3P?YO;Lto%_%N53^SXWvOnn^#Qb0&byT;n=g9jpa-sT%K_Qv*T zT)5!#Z*ru{X6O`q>Uy-^qo@=2rvcd5INhx=Yr0jwwF^DEz~b@hZbUsi;r_ zVQ>I*%VyIDxvi23EKwvXrM5;0@T^`nlBKmA^Af%9J;X|-wy_9pHf+G7Oxp2(mY!BA z?7htl+P!p5XGs!iBDh%Ukph3F?PU%Q0lI=E9sz#0ksrdT{ z(BZe$cc}B5n6DfXdu3{q2XzM=w*~pJl~#7isvXzK%frOo^oD}*(HS~EiagG-6eV@A zO7I$gn}I>r=%k2TlX#TfBAeK#cJEmX9+M=ar619AvuXb~)Q1j2AH485YEKNsDTfo_SyYoXF;;Xs;%{5c?07R0xu7tO7w_ zKI`@qIIc19ptclqt~WYqX|bK)J2^s@qu>psBBVcUmauZ-P5R%{Ofh(8tMx?eq(_#X z?+ElkT16R-jy)?%=6|h){OS>L%j zX^Agxlw!JLA8cyJE^{5>96-wMb(R%a5zbH|8cIy*!!q5CC9@E}x-LJ$u1(*Uyk@`Y zN_;O2zh-(l5e~`1XO4vAN4Xds>4&Ie5j`rcTZf0304M{O0djWBp%wbD*%0sleSrnQ zIBcMZ)$t0entwV4gR{?DFNjQsSPX&ksBCdoQ1kb=$3i&Z)yBup9QQ; zXuK>e_vak6#juj0g|!S%5Mnz92{lGl4330luu<^;1`qrSj-bNTeNhXfzk4+gFKCGk zUwbr^WuzC#;Y@Im^Bn8;Jy~+T2acdqqrZxQ)h-Yz6Z9^{zKvN@2kJ%O`lw~ zS<*bqHDrYt4JerN`(bV-2)g_6pywtmiZwKJ41hD=ulY3^ipEYc#E`@8&Ng2JFz-SG z*H!&tzPMl_zmWWk&v^x(G?^N$q~^}yLocwZsLF$aUH(ZZ!-GNkyqpm}@@B*FQD5IQ z99KQF<*B{sc3R{BSax$W@M$jYg%(3oaa8N| zBegE%@Y(B6Z#<<#k(Sv_opCp-3pSRYiVffyD^+@S`!q)LG0XO-aI?S_^>ex@CI&TL zCi#xXrDxP%0k4kK^3H&&ct&121OVh}oLdk=9SA*h-p_wn#_%e9omo$34vLqJr--wR zm!4l5f`L!*N+QTC@;s$fQ_96QN+VFOT%`E2+ZV~nnb%yDQp39vQm9q$!kg7bG`DJz zag0e7%{K*^(3K((B9cEN2|6cSs?=Mh<_L^Q4nik}J1~!0gcdkfR!js2h(X}K;g0Fy zXfzMa8#TpkaHtKg?5V&ZfUMzD+pHLREg@VG?26?LV zQC~+CzY^-^1WN1=jJtX`>u81yvmyd^k?Fn>4}Q*>9#l($;J-^C0;Fiz9puxa(-~u< zFKox9%YknENu+S`i`5(9$ef;f;6s2u`R!*Aw2;WMT6);8dAYL;jgAL^ciT|Z0duOJ z^?S|G8$cj@Qy|1FurW<=3}FntW+`Z&#mQco4I+0rhl5dtzRG5Oqwo*GJQ=CAtERdlTM&%DFncx9h6N$`}QcV>pj63)DYk@>>)dhEwWD4W*NO#|Gr($Va>Aih$S`OcVrTlcy1=a|KU;_Fa!f*apOZCB>d@tVhy1 z{+h!!|AdEHf*t}b@jBqkh(gqr*Y$Zf$(Ca8p@?3=IS>CuQabnWO5Qf)5sJ3B?6f~i zaIud}Wj`_6Q4w}l>}YvFHo5vp)uFT4-;-HIQQEL)(*d1BSY2-X8Ni#uB6=qtbM$#GgtCR5o<9!{mU!_x-jhi*ho<;Ih7-Lly!{@A|moL zLKjRD85-RoAf|M4k&jBYrV4+`@I$fQB&HNxJVc7$2J6hF2W9+a0vkIgo!yDzc{0_s z>f*4%0woS)o~{lmzpEfHwpsrf8UA{2i;t!9IVDW5MRi{Lsb3B1FBnCMHLAYY^T@0* zBDaKDzO{s64F9D)lwowm_v2XYCcVitjYD!>lgxi1BsN)%UO^yIe6CGs$GQX_(E7?I z6%E0u#jC0#WGkwmcIgqk{MYi+rrc;eaojO^#%up@KlT3n%c+Dt#z}j)0*u?PrND)_ z=)#M&7%b+I`kJ*cJ7qbt#aR`NP!4 zkRcMiv|jOofxpBQJ0u2T)KoEGlC0~m+<&wu%d7e~MEv!}pph!bL+Ar2w?L`UG24P_ z!sZREU7m^QzFOg)IT@_ZwkV4*LdikZbA%GV1z?EvM#4f#uz8BA0BDNH&ohK=Mn=>I zzprCQj?;e$fpVefSte{WMe10*!mR!=+z~SHQi_e~jnhV%Kg7Ty(d~K1M&e|h)l4d) z$=kf3P%W0+T(85#jV1#KW~O7=C4~iTU{LLypB!~^ayj3}hs)K~IELIB8NU3wBHwx< zo-Yz1RRGlj8d*S?(y|xY;1wROO-c)F)D%J!(L@F>63@8+Vz$z$TI()t32(4zH56jc zzqZoP_j$4&nvxC4(VlON@0Bn6Y-IQMPjJd2HkK{BtM$ew7+Ym=by*i$@5pxio~ev^ znowLOf{jTSR`(3-G*tshE> zAd80Z$kTs(6a%xJv*0M9D|mT-4y_8gQh}wL-lB+N82Y$pQiqFpWt>hAeVqSKxT=A@ zVHy0CscaQU&WmEX@p{x0QhS1IgmtI9PX6lG)%7(l?M!|Dn8{*Kx)DbctfBE)b9#z}q4z->H?_DV{S3dAEm4;hj)how16V*g>iECzJqNizQ+=HKzOg z{s%B$)&9vka#B5uIrk+~`8p*Mm41LNg|JO)+wd;sa$P1K>!yfVXah4$#p@*0mOrx& zu>ETRiN2o}PkJXONTMVnGqj7Eiy-2L24{hAy{YGl|Dyij!v5d8W;hpuNciV6-7U_% z!<7kL$-&z>9zsDO@-mVXT?ec>Y*%TJP!XivEUESRA&hDyiWGmbkafms?^gOuMw+$$ z6(S;P;$xj9t1iJF#=vGtb~n-xj^uncoq@?-&|36{xT22UzcdJom3*?Sul>m^1Om5p znh}!?HwTB`MCs!rHE;Qza5eu7vZ0)gfZf5$tze;Ywr;XcgYO^>cLPg47Q60EmFX#^ z!K8CmIde0OBIl)M{k=6WWwH4!8eu6y`zCB2LvM{ia)R%ofL&Tzfu21F<5;H-`|!*b zaX~KWhRrlAJt9@3B(*YRJh*~NFTIhL!3kmWtuGESoHi1>6{Q+9R9Qbna$|$=20~me zSyHi9rr}D?u&1HGyRDL)z$TgLC6}gRX1m!_G#P0!aLKi6z3OB<(%#u-O{2;Ejj}kB zceUk(%$XU4E$&59X5`#=$3Td^+x@jQxuLt~T0G9s zL$vL4z$$@jsnR>3;3Jm@a`-LNqbh~&{gNqI<2%Z?`N&=%H!evKc4d-m%7rV7ny}E{ zuXK6!lNr9X6TabY8ufOdbP9SBN|{IOd^jfCz@^pO6;YmqBiE{EKVy$Qqqde5t@e#r z_ttR`*Ur&#tCLK*bMc&D%eXONMut_yFX5VisObX(22j7MmJ^|?Ev$)rh?1uB@BGqs zm^n+tD7oUo zy}&SGr>hcMx*C-K%U`%2eU*vnLlr@GWsv^!M2ue&T!`pff`~5u%&;$Kp)+@k?Vrg( zkB&gZIOZeh%`awbK934MUOqZT+JS7&83z9Exc2E^WIPJXuct$z9Q)FJ=ffbeX_oFq z>>!=s6aL;UHHw2^rRTe}1C(i5YFgi@#UfbwMb9(cCi*T>uLqIR&xzIyy#TA2^nOM_pYxyWn?om!il(aD&WqkWt2ayQ)9hecfdei}{`BtB0rgd7*5CjG2Um?BAB2 zsT$auD1cX!rKXtYimqI(;KIjSVjA`Zr`Xk{-Vd3M6Y+7Kji_ms8cdDd+{&21SjILk zyu6rnagg=6!~8i3d=!~yk46zXja?l5E7ea9sT7ep^D+2qz+MyfNpD{!Jjh^9o&$$)CkzcNy8M_0s}P2`WTdU* zo1!f8ig3D7=8|A|_Jh@nS-;KkKM-vz7DF7}WotW4D27$W13?*Yob!YmYf2lPE%-dy z%q6QeK{pd6?Td?>$oKJm+nbr{IOy>_^$rANKbA~z>}U9*i_4cEIT#<;90;~_xk&(S~^q(3>1DN1n_F$)dOj6S6+CI39o1bh>ij?rC4BB!$BG zib|LxBAliZ59m)IHmu+6D1WR03Jty*?BYHwSr#|9WW6H7v2922Zv2{@sYbI!Kv%y~ zFWwtCwQ=j^6sVY*B0*Cm3Z~!v zHSg|igRjNWJxgkv6zzCWqAUYY9Cmy}hV=t}Gq1eRa~sxapfs%v!mi56NvEnQ!56<_ zL4oKt*#2?biqtUG5OK$fTcvyXr13oVws^&P1mtOb{Fq0YsDl`IE`l62i-j+G?T5JV z4=2~~eKtx{y6jTMXTIA33z5_|U>YmV*cs2(V|2gwtj^#ftA@j|l7`}v!k51YGjo(| z3w+eh*VYbO4M+TZbu{D`N+;{m-e?k|og+KX{NF4E?h5~bU|9Kd1+g2I=6K_L+v=vD zCh*Ji@0d;LJnUY}sqg*3&MYq3GSh`g- zTW3#9{1ItJs$EJVipLEFo@{VJfzjg+h`Nkf00AiL>A1w);#N;TsjV>B(erpltz353 zRFMbajc+%iBs4pqx(Hu)_>0Q^tc-{ial@4*bgKAuiQh5}4B-gW%#2^kK8(WPK^8_w zLFip^_94F#y5VmB{_oQYZ!aB1!tf7Ifu$ZPUrLKhlnj5`i_4%PM=WXUiBhxOv0Z87 zWPJDG{7#!M&sQ==9hdp_J`<_jPM1wx=@?}F@io>!834e)szuUlO6t+x@ac$c?X=wZ z32kb?*b~l68qad}fl67dC#203=gIDkpn(ulbL_GyJRK@o=3O=`PB;K_f4;`E{dzUE z5zkPX!1zPZpRbKAQUyrM%CPJCx0MS%5&305PBxLAY|}ZqgiOw)g4&zB4iPb7 z!W>^2u~TQiqmUM4ioa+0-%ju3PRZ~QJN^5MJf*_4P!k!%>_HSdo@EaP4%ap=wdzfh zM87D*FRd$+s`=XS^Ht5;@~n$BweB@}Mv&|omfoomEFo^xQ*2X0wmXUnG%H%?rI6qR z?URFLzcE5S({N2yJ7#{Q`66iFLXPRxM5zM<)|#DR8N!JYPPYc3f0hi6AQ@n6^T&Rj-YZnCy}^qi!Ob1 zeB*?_Im7^P)df5$(5IK1w@-`4@#Sv-FyL(^bDbR@ z?--8r!bFE9fzj}?)7jb4^*6^AJeZ!l1T`hnV0@K7h43oO(U07p+o{mI?DF<)9P{3D zw-#AgI>Z#I&Bz2^RT3a4yoc$WvsP?oW5>qDjiq&S~PQKh6y=5^F|Kz?#Kc3TG>5j zP}ard*e}?xl(V6 z^dja|tAc=oq1h@7II;bu*pk{-^uSE9^{DV*s@$WMc=_fd7llV-r>N(s?XGUFsHuwu7yCCLli-Dw~eazV~g9{ z+8LxwA9U!jF0!fNG!wN6<~^B+7!yeZ2_`$Q#XrG!1~@U8PEq;5Q_7pUOq)G(Ox#Tq1D#BoDYUvNK`Zj8xkk#W;gW+OD5YUs@V8_5t7 zR#4m4vi#~5t$rPh#(b>QDm>8zdSnz4@AxZ%9(|58Na z9X%6wdGUiaCm8&D*w)z##Ie(_J!PHPYBX=z7eypmduO=Tb13+4^FiE?JJ)%a1n>zp zAu19yuFRM^nsW@fn5uqt_=A1KBOt}w7{jlwdwoL69h?Ks(LeSl?jwciKpi_6V@4rZ zR5Gj$>?blsg{~C@+7JFGj&E9KFOQ|BT6+WDuYY9DUp%3s!upa;Zdz&B&h9lrzNklf4qT z?}PU1q=BMD1{~!h@qbu$D=^wWlU9P)LEM``!{B58Ayml=pmbdkqEsuXH2u|$eu{lM zudYaFsvn4U$f0_^x7UXD|2 z2NPxe_0bnB=Hw?mXrEgz4`=42&w{m0!hO)V+j3rk_O(an5_j=Ez4bO;3&o4lUML4v4Es0VgPNFYy4^>)hJ0} z-}fN=USYAIi*FC-{G_44<*RWEl7v_8nG;dhFj!}Q0a0r2P1MvKz{aLm@9T5xlHykG z*Kt=u2e*i?bDohM4cI1x-K*~S>5VwRl$lATQ~d7JBC_BICWrVoe#!j!*!~6K`xgg# z71cX#AYkt|Qad|8xT<$;Q_}k}T-z#i`4l|R!?OjDC0%OL810%|YKK?Pp#1R9HO*GZ z#|9f-x3&aq8;UTYNPDVUdO!hw+6Kp{7;Z1#>w_XCD$5T{(fn1yA&sivGYW4u68trP`u8Y@KQVl4{RGu3=0w zl(X8cn!=5Z1hk8JBLzuTuuUzP&dEsRziFsh7p@=btjP#~Yi@|ZdpRq)57s=FVT7T8 z>UG+2i85UFoa_sA;h0@5*xpW*5ovYUIgaa&vhUW47;cMK&w zAAVZ@X%XQ>VY2XG>Dz|oPI?kDT7XiaTxE6kC9Jm zQr(MxCw$V`GOkQ8U_>v$P7N!s9E1?FFllN^(6b-dS?8Ean}3J6t>}q6p1sgV!Wq%1 zJ#%}9&Pj_f*PSFg6AhpEK$W*J8DCK!o`*(3b25mLqYzzM{P<~snFc@2%TPtogcWiV zi1)id<4AHhL6`iJ94UKTQ4{-TID@--91>|Ng09;Md|wHhF&!GC8&c-7U2UXh~>-9g0{^M`E^tMizX2w=UUi+yHnSbNf94JyiNx>#IQOuO(r_^31rRM zZqjFJ6_@WdgRk@OEurrn3CBtd-eRH5IYSc5#d=5luHz1$@9M1J1i|!2NaA@6+rt=QwouQjQ>9JGCiZ^M-NwT^RPq3_ zM6I(|MvW-)!Xg4rH$~m2 zwvfi|@)v(*_kP1rH5ggtCF~j%0-Nw^;F76W_3%~7guegS8-QLd4)H(V zZb0nFo`kJv|8RfQeB2#SJ4>Kaw=fcuIhekl#^XhxqN;s9D6lW{>C|z8Js`>BVw!ds z38KMX4U6^)n^V{La_oq*8N4X6%qLz&6|P~r*N@IAO$7)%X&cm?4F4rms3K^9_k~+- zK5Eqo+IIBL!Yj%iU}f|UvuEH)y0=og=IL%Wr-EnTdVAAyhez&F{Z{=y0;s4qiwwAN ziAs4`({3ucKN+dUp3XHc_ z@zFXP+SooRrT&!lq`jQ5@V#V}6{xZaZaxIYHW?9S3pv z?8PXAL+{4rW{iHM%S=5QRW{>(E^((t0PUS%}%LntFlYFqSd3vW@1lp-Nwt1mUpt-PhWnXQ;0Q$c4ENtnm}$N&dCqydJsuxqa-bn(2(Gh7LdJv`2ietiWl_bf-Y;Jt&afU&_DR~ zKi5`dofzhFGb-R>(XlOZ5sn=ghP=5DJ(>Mz)7jq-*HgE3pSGGbgNf+4Buk2LGT_Lo z?B(0h-vkzFztl*}1yAWg6b@IuOEzyN*_|Pt8%rpO9OnR#e4~RIyEtLmlo+-h)_$|il9~RKmMJF!Ev-3?v?eb)uf1wAr1TA5J)v1{*=m< z9AyZc49Y1xqN>q9rP@tkkb7$1n$Zrp*)$*L|BQC2JEXz_f!7HLbj&Vxv*=wZFI-i| zp+-a*=!Pn`x9pK73||8X3!Z{!1LM{#)u7dsK04j(tXv6v$6=dL&R{JeMf^>7#g?r~`$6SU$j7Sx##Acut|tqi=) z(Ukv;iBJ$$R*WLA(b8{Mv8i>9E^2wvX*yG{7IgvBE|uzNJ+;&BAe*_68~?xf6&{&M zma}9tAD_d$c)UZ!oQSA^dpZY7kup7nOC!lp&sZ1jt7yL(ZDaceM|OXqAiFzjig`^) zsa5(seJFa{HG>%n(4*|4Y!^H?qEc1I#7L~wGZ>?6wRs?77;R?)X*JvBv63=ML9I3k z<&#N}zlLrNC=aj;H`pU?(`vgWa%BOcT5F=pYMwd-mc8o<5gT)byv6z^D6$~ydPG?s zagMNoR*eU)ls#pM0N;&xp~t|1-F{xMt4_h-0QXK6yR_Yn)T?ag z=w-wa|1%(7x5WzJpY&BBbJ-JtNDKJ>QqI&AN$^I_kAU@QCYmq;CfEzd(WBaw4^%+3 z!6Yu`Sf|R^{Ds-ZI5uvMx-2JKktAN74T{`FR2AxY3GoV>!J4f`t$<&MRq9f=9&B7(j4Cq={4ve{IluG8`o53_iU#`LCzj`Hw-3iCy8 zr^kA80?{BkENu(^Jb60GtH#P1w8X9OHD9OJ;TPZAA&!&SrgaeiW>Q*5ew{zA54}M5 zs+G7skL&(fcHA{1XwvsnVBFK4d4wPhURBk-kD21mdUCL?UMF<{?7tC-t^cCH=g zk%pI{-C&o)g=yu6!pS4LkQH^k&l$L>8;AdLQb^LyBu4pa$9Dd>HVeLlnjtlLP6}ap z)2t&pQ)vqtN=riX}EqzWRJ8WZWsd;2ujPj}38 z_aCRZdN0Q^{`GGzFdEL^GPE(Gr)Fk#`dFqumFMO&Occ3>7=l%*yvAV69YnG~60M&& zCQG-H_x~{an$OzOJd@q+OZI8ln!rWF-)JcXVxW1zqGe9r8c)y@FdHS4YQjE$;D5Y1^1LzLtUlpQ0Uq95|EZgU zK1Jzr=B#@(i!7tO!fSsT80)m@G=;FAK>MqcXw{Vah+mx^f^ul`!LzNUwU1R@I+CMy z`MH7Y{X?Q-Y2IixXWG`k(G!D;<`x?@{}0BqSmZ2u$=K6K9&PJ?Y~b{n90&*{kBV5N z_gf*_ygw~ICN~XfGR_`M#?-!nwKHW6X``4jnw0QS5}n3}xPaLsfGgZDaJD}<8PMiU zB0pD^zF?=11$>;=zy!yCpf$Mse8V(wG6?s}5mtR3dkT7iz-J_(N~fO9=EsxPS0E;aP=>>-o4~dc9~9MQ$F(1^%;<231?1PBMrO)(7@T-#&rmP z_mwWHCxwmsMj1M8ZlS?>Z4?jXA{0%_hFUIcCZNu7#flqzG;~!29;IfE#We=+Hc2hm zVBl1+t+7SV{8EdMULjIk%URN8-Yk312D1Hh1Fh^Al$7j>csIYp>NQd69(G!#nIUFn z(;9sFe1V;^?d1^jhgp)jP@pY(sBGV2p_Q%+FVUn1Qm#n&omD((gjCy?Vx9Uawh$I( zWu*1b;hEQeqh#+zhK%1N0Tnyy#DcXu8r!ccJ?Hp6JyP9An&lX}zFmT7N`Un!M2mkp z0a{dv?-`GQc2a?MbvE9|SjojVZ)P1?BXRuu6joIW2045gT0UzQGR*ZSX z_~hbQnU1ER#S}Nhe5FBB`t}@JjC~L zbCvSlot$sta))m*vi&5g)Vg=0@`RWy>IzzF#0 z@Msslm64(c*H?+#CM7QRsnQ=UgEnlBHCPba)M~PUk2vs3>W~8`q8McE>2|Q(07%8G z%&od2gAIonld~0lC4trmTQ_m{pf>McZdga|sXFU4pla#Ucy-G~F2rZbFKmWB6^cw? zF}9-uNp~+wrmO5v(r+$^OGwDoMz>(>%OERlD>P*89{VK0dRh%Ic%Om-n<6St{VAzq z;{a_^CCdwfR&_j?38gd%G!W@_%-%-+=rNvZ6$p#F%>S5E=HLjeV1bU%f|j!OBX_^U zb!hx`?sgGcDmg#Ii{=p%EH)|jn?ZU1*Jr}5ewzv&hX84)6qjg5IAoL5*WNAusp$z? zv!|yq^|8R#r7wq2Vt|yVAR6@3^ft`8+iu2n4wZSL#}iW!+0?92%b^UU&Bj~T*ow6j zM|4X&#kcoRh`9^nOrBkwN4izdsnymcwPp3_hC@^r2sD^a6)9fb0u3ZUrXQgkz+;DQ zGD4=YzSlwn1DY<1TIMEZg(lcB!)0UiiMFP|w&<%?6<1ji$WccFI^zY6OZ~Ogw24-t zs+A&Ivyq`?0W_85DwC`*`6v0Rsc?<$e=L~GT;^)D!YZfWO-Z(r&K*}}e?+0mX80RL z_Y%rXC4?n9Bo^&6pAU)$0^9(xx2uR@>-?`PxJ`&Z9G}jeqf^aU6?%`SMF%{`3*h`u z3AsZcYl`&*&U*#4iPfh@MC+tQ%=g7zVP4HVi%SL!E@gE>Wus`?wP_rMDq)rT0kY;( z&%?ggx?@S5Ab{rP)oGbfJEIAlJiG zj$WQ|DjkQ$|A{6yxTQFUxkRD)aXG%zByt4jnJ0 zr(w0~6^My5*IUYwUYRx?gIOf_<#3(28>etUl4OyX(Aljk6I6^M=mQo^FhHq~W-o_j z{l5KFH2_-+aM{ZE%mfs2Hwnc^KcW)C`8kQGix|R{HXt*LXs6~S@sw93@7DlB$ch0> z0EC2&=Lc5HpFF1VbcW&0mqx1T;^nk%@7!}yf&=&$*GQ66083B3PLKY%* zkU2Qj^Hw@d{0@AzSy`xeo+6fiD+M`h?e;4Q`rB~svZ3UyUv&3PC?_fm=p zcPXP;N{ec{Zp8oX;SZFd!;(frtMu&C%l&45qh1GWOO;4;rdkk#=w|_n=GRog#Czq;` zuE@3;95)<^3|>ikhHS(+=bMVN7#1J#){?#Nx>iA=$gUX&dxgwzz~ctc`JfX+z;map zL;dr0vm2PVwb z)zKX5Bx~0GAQn+cQB;CnHVp3L%%R~sM7vJQj!dfe@sgJt~aO_f_1N+D`=!bBl1GU5OKT@T~*5665(Lu z3Mx8CZp|3aw~=@(Q|1)&76a*LR<=1MvwD(no$~{LauZ?WcJ!J$uGt7;H{P~$jZVy- zwak%{X?Evb&~A`q08U4~dR5oV-VT9*r1t>yj1dYXl7$VyPsh+P4%)alPF0Ip(-R}sOHCOkT}vV z(~3?QL>4c+uTZ?ni64*>pjPRU>8aXKfX2)|Tl9nem6A<6pcaUAO^Tt@5f zeSuA_M^UaCf30O3ufDnidcH^gTQj=buJXzM6i)3Bt$RJkym3#zO8f#v2 zC9{Dq)QzH&x%5!#RqyozkK$y0TmWv9q=&_aG#hc~cS>@+O*=lnhb+VE;{YAJL0y;>i|l zJoAy9yjG5yeND44Zj}F5Fh{huVN&07EmeMK@J%gA}ykA|2c4Vgb zG#`-Ie$4W&_=-u4jVU8G61A)y?hn-@21qV-;}(~K>KZH=0C5; zIJb2Ez}s7C#?zn7{~4Vb%PxID26Nj@O{swlfC#uX=4!79oR6}p?Rl|3on?O|4QA64 zibqDbl*1FMTwhsgGG_S=X>^OWJomKSi33YeGtb_m&LumrdlU8frD50p7|3#H87j4? zxlDGf8#!ToxU|UikZ{^h9jU4PPO_uG$Jr`^x7ffc1cFBQN}0bXd75#Z&7CUK^33pH zZ?;u=&X`0V$Bg7yM0$ZBm8G@kk`>qcqpp_sNabH^`4|1oetZlT@Mf9gg;>_MvQ?Fv zRsVmVH-wt>(3zq1RyQ$yJBXlLYfCxeBJutFm6z|Jo~Oj=z(Ie^h3Ukbjpo)W2V!oM zdP9mf@}7j~VcfDAP- zc3zYhuLy+bNMDK$eiAbi@PAK3EEd2nl?F&#_*gbz04KP?yFbWtL!X&ocy+9`47h`+ zYL2P>EG23EwjPyt^s_mROa4uf`sSXFI%rv6O>XaRtx$5Ue3d|oB!3)-C#{*y zBc6+R(YSzDe$$0YRKgECv`i%s@<-~AfG0nR7KQz3?FlTg{XzA-U zVVu)2Xpblu_dJ=*wQ3FNUg3Ge3e{|Qi~p&q4%LaiSszquLCggMn#h)NXgC~KSNC|K zGsjLpu?n1??b5<$5>AOWw7R=W2-;eoB!#sE@JtXkmC>5D(sVAn7~e!9Rah!2nZJa% zleN$SxQfn`W zsC|4<3=Rs$geC@=;d~U9VSkY=eiF#x%>x7A7 zWK`kP1Xi_t!A}AJ3iGM<=re~3y~;>=?1PMOeuc+GEj}}o718$^#q}>imG4S5ueLHU zyNyhTCSbQ#$`+~SBqR~q4`LBS-ZV}>eXf!N)+3vh&Dk9d6ZQ!bQu=byaKxap4(mr1 z*flpKU#hdN*_ zxIFG11dGrFZ#lL0>-`9(J$lA^@t9GJ zEnvE{Vq!u_$xL#g!aj68Q>=_T(;B{`JJu?f1TXzxjrTJ2Hk7Lurc2S0VNF5C4`nJ> zAdJlQM6o1ic7kT=_t0uE{`IP{hE!4SS2e zIXJjfP`k(ywPlks^Ok7c*I2~u$ZeI`%%Bf-nBZl1#e$5SE|jPRpD#WGGv}c{S`gb*96RK3G zY8r2zHMu$9Q=O-HuH$g1zuMI;Ht;^AGf2k4tb{19a;2|R;`goiWNmI7A_>0J7pq9j ziKHnCOEIybiCMJsz_Z(HK@dpTv5x*>Y*{5-ZNQYcc_FpKtZF&qYO_XsPLSS0Lz;09 zST(DFKN-w7;l|nN0`7Ls&CXz(NS)P{AEK(k^%v_Gv@0w(*2ypf(mhKPf+2b58~CGJW?|??Q|Cie1!@u8$fgT9Suj zw`8mLmU9JSV9%4^IuEW)2VHK`U!-qEi(aW zH#tQ)Aqn%V>Di0|h?wd|lJ!q%B`mt_Nt2sejUwAsLyvVr`!PLGJ0RZ$a0m(YxNPL0 zhrE=M0$zzg`uggc0L(-qXI)e^EJ9|vCs5AnST%qw0NYx$j*W*K_LQR=aeqNrwFg;z!k5$ z&^#R;0(rZr_EV0ook7llOuaWRrwGAJ>~fe9VbcH61;g)X2_;k&lB-LYev6fbx|*Az zaV3_!!82I0s!Nt)5Z&sK&#oCxz&7Xj2yZYTtN&Z4>+em>$Fr8CPPC<3w*W*~RmQGD zM4A>hs+;E-o<#gzeX#d$;&*YLH`xa!){Fm4$f4{SX z7$Yt#T1#hQc9}qbGSSA{^H?sYz$vBzDsai86sAJo_5F*Pimxu8J7&$7bS-U?!A(Bs zxOW{skDc$dLn-Ki`?cy}3jd0U;BIF%QLNvCv4f_jA)k+$u~EF|K)0no;kAOD6d+OM zbF_k1|Fq}XO$LUa`kA^kh5e+p2$=C>heVrn5c&w*P7$EAH73izYN8oCYPw>K zR4j@xZV}S4-;wf&F>Z$12!fHA3dbMWCEgM)Z;z!f#lxZFyUhOQ&iBOq>Qp!$+QfV` zb*Lnp!H#%XWJ?@@cqXroGny~aQLph2Y>(dauY>t3Lm~r~O9~b-)#i1cN~`(|fh2$C z{Wl#fZ62^Uq2s8v7(TXXV1KXGmU2^A@_IFic(bY5wTo{BPf|9kV0iel#wE|EjP@$M z1ls`>r8|}!Kx^jFFmR>Z%WtbD9|0ByOaBOBecuxQSGWb+1WnR7t5V!3HhS>+s}48t z+7*q!;j=Z&cCZBmqct>T$gN}7;&%rSBE${qmY$&330}e5)4GyGG;ser=ksDkHG`FS z)0U+kr737Ox>$cdhNp0(Eh!iFW51;;U6l<;fBoqh4m{&^UHt9k*#(-~`|4{Z=!505gxSI{3HL%lto@$E-@*45|z%_Oi%n$30?3&o{7 ze-b$r^qP?rwcCMIg5t!WTIk;!o}YpsV>Pe%9qhM!nOXr$47;ujtND9t{u9%7_4z@xkBeW^*PXP`t#v^PKqR;+zV(-&3-_XYbuoMFBlLJq#f#R$ z5Y4@{^)c(^*`jw-K`;QkO;>4bV^CwN%({x{f>ut_&XZQsD+7o(IfKezve_k-JK(uEq@RQ?x1X^51Yxl z)&|_sHZme?$lgzJ0f(@}pn23%d3G49Zo4YLo@`a{l>KcAfdGH%@Wk(hVc5G3Z8g+- z(f_yTA#B@IOu2))E9q^1$HtA{26-Bc6x!u?hv0l?trGrR?!}u zI=I#&V+NCgYr9$v4lGd~!3~--fXD;=M&);7=VW*x;Fhw_=-=zs2*8t9*(Iz=_c%|a zH@K8y7Yp=4u|5I2COqgfb$vxeIA5ukU8N05ZfKkkn@UD+`SV}d%xc_xYzPMRc%P-i zIimczVD|emQI9IxnIMfd!hyPVPn{oPP!Mltw7Rvosg2h98K;`%xFzww-!hXn=`c{VQinrgw$a$~6j6ACj7F4u7&8?BA$?_% zUajY9lw(;I&Z@D(yB&As{Nj_Lb5I5mEe1h5dy1F?czcTz+C8#<{qDZe5dp$XB81xT zgZm8LWRVjk&;I()e7*sSTYg~+cdIipy2u!ysJwv|$iJfy`+0EA%;J8bOw(QWjjQ9o zh;%1SY%-0yik|h z6XLKRf~#=rg9OvJtx%FqOC{=!W84p~McE$1keK|f!4)a~KAs#H4ndn9tLWgoi_OKI zwk~qg@L6KAp(BcUf3OChSAZ9?(XZQ(ySSC1$WLzgU%5{=3UHlUD|#e&TO ztUQx9&bt0EuZdbqtRDlCkWTc0HIL<*ctlO$D&5ZL@>u>01AX3=LeT9A$ z;l|YNVc{52eXB27Y6cecipk&7#0(+D5#yu?$uF%ES;1@)2w*W5!@@|=?EUcZmWewA zEsLP1;6FYus~(Vy63~jE&Vr(JJTS_|F7Jzi#LDC!y3oaQpf)VNhw66q^3c3v!K(FC z78A==d?>_^bVKPfRIMm4(&t+$x)zq<2&k-js8TFMNAQvNjNBL$-SZtjsrqhUT0ihKb~j1> zQ{2N>q3OX^QyTVvmNBYUq{SvhM~q_8G!Y{JhzcWBYHr)2`9b|bhQK*tyWbebY@)RT z)gm8}dI4}7bP%wyQf(;m+w*nn=hTuT%=w>BMJTf}b5i?sy$dcq{xr1? z;W7%&$u+C}1l_fy&h2?4s|JnA^j5S9ox^(d_ZH#F3#~b2Q=`mSv=Xfofpg7E`G=c_ zxXO+FiR5WN_%|_#3IdLSSk8bG+G+tzzF9!miuR4~WmpPUZFzqd%@JxSN)*_h$pw(% zQ;1#E$_OuB<3aD(D=JVi2Ld@6V4K}7iE#OkTL)36nEYYNK`@?HOTdM@MqsI2r0z2% z%I!d3dg!Rk_CTE5SggCVGqrSmbQKa8HGbH52NOS3doez_n5thbLN|pHQapeBY?5|T zsqk#_1X9R)PY-=FpPrCXF??dA=+`$ME{q{(a2GuMPb||jZV;|C41vE1lt0(3*emI! zt@{hm>@R%0o1%PPY&_(qC8kOFY8T3pU^(o5gXlzTL-LrsHo-w(SXh^hEUfL*PN~KV zGXB&XU?#@}MmI@0Hkw#i%*rE^H>LAn+OX;pmjthfBdj5Ew&+T`H1nSe)44C*_D&nY z3Y4#g84mW8bop^=oRV_R`hc)-Y`uR#V?wOypKn9`sIDjMyNA&M>=4_|{iJuh-_32Y zcpbUWqd~uyjh&|IH%CvJcV9EUNU^xogtMByek1IH9mr-k4*m+6kOV z&5c?L#TI)%U1W>XO%s2|d5zRl4 zu!PuE#rT-DNH?YHb>@0@Z}Iy1-tUkI#un9C*pIv>x&%q4i^m)L=bddhKeoXwd-vSRPdFu{=lDo)ENgZ{KWOGZj!2XQ3V47jlRA?Ayq&JbJ4e_2vFIuW$ zWhdwz`HK42{*6^STVsx_7%mMZk<}snQ49Kb3DvhjK=O1>98rK=e;TaOzcew?I$-u; zfLt|g9+GbO(K&4Y4bitr-EW`r^J3Ge@2F^qFBE2d! zi;y6B9oh)+TdkD+_|X+I=9aW!Wx|%BZbl->6dt*H-G2dzzDgfPn;^%>0JWlu{k4*V z)%Ph%Hj!70bDGGa<#Xm=D1>#rBqC|t4qjd5A{xO)-qEx0sn+$V^ zvcT(z$8?^u@!T54leGtuWWrPpON^r1r6j^xJtl6r`np2%2^6h5ut!RdU<^g30)SN`}O-Eb&uV{bS#XNv+K3 zm^rnEulw{N5U7XuiDJGv$7iky!f?NvN3%Cm=c>F0`tb)aL`FMfP2bZ!plrd5#5hBc zmf7(Lt5S!cZ9mEWSd!8!ArWC1(5{cZeLSg3!sL0k!V|A`lBN!5@9uFZJo?HyFzpsO zTHcFCq{+-$Gl0*DFH*@?MdyE@(VS-EhGaC#?D{w^khvf`NVjyCcBnDQeGx!grsIVydDSp-`#mbGPS@84Su%bbbwzy zf#9W-DI6k#7SaB&N9T#B2Y#?$0+MWnQWc1kEa&V609UuPJ^~Do_A{`2=Muq)NApqx zpJ16F%7E-uNZ-T1iaIf%n3Xn)x~p`94B5FgjYGSnGbXqcc3kM~?RAAZZ zh0(=6Vx-P1wQcPFY6m~O}^-l zi^KbrL`I{W$@V-DJGR7(>XTc52=iJ%fb+&>VN2{(Cg9QiJS&z5@ZT#J9LZ|*9Y)m^dPNY%;7K!29qS63p@-1)qd3T~juhj_ z4Cl~4{qz^cHyNN0WhUxK<}}f(Jb4dy|Ivw+i|!R{mtfFcbpyt!4zy6V8H@t`^B?uEGX)l2!9B3(}G>b>d$788wSaS zRn%lePyu0%zk40fm&ld!Z}=>+>x)oSl%NPHqj&wStKl`+GNgcgY@KL80>bh&SP&ZB zoZw#cOB<1bH>9GlS;)qpCy&*r@Yd^tM^E3SXO=c>8~K+zK#bL=w!`#5YIIWdk3iIe z^DkASs|kf(G=UJY;3V3MMck3c0_$Cy=cNTm!;w6R6a(X>rhkb}=4=a2(m5<;BW$6; zKeDSKBu35p1$!Q=@X-E=Ab(0#5ljfqq5T2@(RyzcvH9RjCsHI28#6(KeHg%X%h;Aq zj?A_`N+qn4$ntvBZeE($exV zC*FOmHA53D%)Dv$#A##Ueb0eGP6E8UB`%xIh23A0NLGt548+R^MHRHVz%x)g-X+K9 zJn(ysN9Jp-%Ot4a)md}Y|DoN?NJguH646+{N>I^&w2GhHe4isQeSu^0wymhaTNn zs>~PEk|xG*Ip^HlfpZMXHWzf#`j?`SF@=^G(O%_laJc}|DVV_QlDAbSsdp~0C#cO0 zL#oP3CE09fC4mw97aKluH_%4~-gBwEwck;eF=R<(7+ut&^s<<0{89bPPSR7{} z073RA&nZUU}9(W3_Kwji7tOqkF;R=XI1gu#*LXUpZLAP0sckxER z>-5%d)RRPEUO>=PFLtgi;XGVYbyusmJk$~j{)7STC$?Q6uBkB9O?*EJG&-_caD9Ml zA2(bnM42-Bk^{t>RT8-PcBYNYTS6;CR6qj9)8O*T^dhV zlqA$pEImLyK1 z*pWe8e+5GfBXoppk>=`IM(Yn{0sRgUUZlYEZtaYglN4*JG?BX&hDTII%+DbB@vQQ$fUTtk-1e1^Q z{J1vf?K1qS@x2)P5(N|p{A7L%sAQTCW}bgAP0N{8i;oBzda2(fn?R|x3F!>Yze_k0 zq5~&c>8VxB0c$Lapnm(}s^_+eJ6{lrzQTv^UfBe-hatGJloOK~*3tbyp@xYFE+T=9 zq;GjEeOXPdMgr+WbFX)d6L+#Yd%m?hAgEWqMa%0NgzLN#u1~fCi{Ip!KcQBve9j}? z@rBWvrPIDu510#iXg;ouE0>lu0!DT13@b5tL5`?K zRsz-BLc6y$ePm{C<`EvLg+v$=OQd*=0(>hv6XyNVN-2MbpcUE8ebBU4Lblx@aqzNh zn-`bM@3hg!R5V--aUtDJ8=s~!8biwM2F6YI$&(^4hWi)qxS;J)igf;)7#HPN+qcY_{cVAIK)#*6i;Z4}wEZ!(~fB`;ZU-(XTKi`4ju6(eR z!hcDurIB^C8ai+clE&bEj_XdKK2ETqCnilxwHwjZO7O#zp);HhI9P~YHSX*nm4Ban zY*HYmY}gU1;m7b!s25i&GwM_B8-3Ogx1yg?JfTpQ=foOLEwHBxnd)Efu!!?d$PpWU zrv01MR+f_G7Ud`aa@x@vDF$)43OpNL3LltAM^O|SZs+#P>7rr@W&eD^j7F1G@p4PJm%_aOQ z4O!E|dQTnWT>wnf{o|$wlB0(=ed70wWf-!&3l}IVqmoe1;1QSoyZF4MHu!zniGZTi zST0vd@kPT;x35Sswf={*C92$o&tgI=H9`QoZb3)`jZz3zZ!}m|8#6b1S^)?0PK93s z5&g6@GGSFn`W3N_7USn(*LX{e^W4S2*xqv?vAah2a6BBJe?cD=|Fo}0?_`Fynpz=2 zcr6R3e?F}dKEQ9cA-s&jj*lmA@4pB3D@bSQ8L0~$?3UYn8t3bI7!-3Mh{C1E zl*DLt6RUrd*f|d-Z~NPlN2uk<#pv(a#EY4b4>0d?L+*0}7g+vZNjy58&QGQr;^5GH zwG{P=QqUg+-?qSqGaH5$pdus5Qa@>Rc&bzbB=mQNvflW5UAxM`-^K(oJmOj?Yo)$r~91H&z9VyOQ zh#L-uq%vjoh>Mt;Asme0jprAn|Z*PE1_D-IsGP&`&im^x4SO;`LbrlMfhozd(9 zc@nXw^U<}Iho4C;J&ud2=sCk21tgf6IoUp2W#RI_8c@KaFA=U8l0vnGn-_6T?E=Rx zSO~FevnT|qKo$DzXLpFZ=ZBC61{5k42KtEuRAfky)bp{w1(lMgrc}S-&Om|l>vSa5 zYMkE4ghaME&B{)q5|WK8U)XxqF~6r7=av)BQSn3mMMU#T6wEGRtc_F2($F8elq+XS zAqgKXDNC@<+ck%^8@cIC{FnCt8(ay15o!Q@Hk6j<(mqGBl*SJSNEajdN%1fP^^jyc zydr%5No};G6{<@5vvum|hp5sL2z@^wXYs#?Y0wCJXdQg7tFW8N1-8Oj=KX%EET~RdcF||Y?rE|FA znFC)DPV?Wz$4{WEu&8T8;gnhlP+OqIcrbnt9h98&%g;PN6OGvba-|~Nm7|E@k^Lll z(iqd*b16{eH?_|3>a-eBtqU}!7Q45d#JrS=c`Wr}nLlDLHgkjHwsxgY9lON{L0V7x z47LM^Xs}h-UR9HGuGo#2+hs3|KCj@wLlj(8y8hG@m`mbtT9Ttb1n^;x0^MY5_<%!i z#(ITec=0K3VLRJUb`eCk9?p&GD-wKvviAOIRXPNkx7~&oIcdS0(kH@Uj*O-lT+a|Y z=WV_fq(V($;%F;rQW7?Ewuu=NEvh(pu1OEgM$WRB`Fv@Kyl%H1I~R;+>ER$^ZBJUm zk)fhc>KsCXTXRJap{9k%Dm74M{zf*&^of+bj1gvnTigL9PRMks9n(&%8#JeC7e>Qw z3Fva`fT~cIZo3SbnKDU|k_pz?IGU`Du#R#Xy4)w4} zD;#KUKror;#gf;AsO6PfV1r^&M^ArSoG4b+PjDgzl2rbT$)1N2u@tP=TCJ|O4+R}Y z>QE7=ZB&QmXp)4LAGC0U5hRHR{c-73xkHwPZrjTCqlQVTPOjAOU-348lRLF4NOK9j z0>D+W;;@KPufDih>ZgthX{A|iV`QY@gxiUfbl!mYbGEt(Sf842MQmL$J+iu2vK03A zqfdd7-WpXZOwz56W_01NAl)5GO451h$goHJHeBBI3Pi|x$&qQwW`>dfwWKJXM<%5> zOwIw!>ZKLk|DbriEL%y$ ztF|r4C8-S<5Tx2D(Irv0lA5>vBkVtD`j>8N91#?$(PWE1#Z$A9J;2No%x$YbQ@4nA z=r)wB9kcmEMIO=1Y32{Hsjv1eRoV zqQgh9k;%^s)Bh1(?pR>XNbZFjqi^<8<+*4kBA1cmlxMAG&zo2xebedj3XPEdu~b38 zj`#pfM-cOLf7Hl4kTJVQWu6GL?e+wdA!w2)*h&KVOUxRhk^Xu=CobEqi^4aUK<9lw zQeaH{t>P7Kp6vjfE{$=-S%^4IP`9wBXR*vxy=f04m0Qfpwwkgf8u^T#plm!$-k5Ay za-ceFxzQAb9-^H;@Y6x$cB)`osLjE z3xl^V#PG?KWJ|kMq6>pYy5`gW#+YHU2pj;5-l*ok8VR>~g4RwU&oqk<+^r~lZ1ps{ zLounm3CuZc))|j;RPQ6|Ii_6Js}H4zy}p1l{`#7h+h$T_R+bpkgFH+5aA0tBYE#}N zA6t^z%22f2p;d|UP{jSWYE@WqMa|^4nP<+G=@6mABl?svmY2YWZ%hn!YrorVSYan) z81keSxaOv)r_Q>{JN~5ykai+je;|BKV-Hakkx7Q$yV1Yu{Ahmp0c{nq&P(#Jl--Uj z_iUOoCkG=T0l4BdF%FZ%%@{zmRkqi08^afU-T;Q}3Jmy^j$8NTc?9Wx;B>CYX6Gqo zaRVZtj>fd<1oxsdQ;{35pow|BVq9Ii6TfXh8!#3PW7+cOAQpGRg^!G)UH?=5XYObF zayZ=B=Y>|~9y6r9$|Q~h_9)k(X?_t~WS~}aO)ANJ`|uHg zT+5(_px-R3O!h*wb7erw3E1!UM`ZNwuWN@jAIp7iB<_|>7O{4_gl{l}f^(KC6wg0v zff(dsz{qmLBOswYRCN95P~@6$h>=c0wzbO+G<2XDYI)Qt8= zi!6@L2g?m9YAXNO88%gzWcZ(g90HEYK0W|yM%6z`5V*T!_V-^Sua_o=@hv1iJ(R_{ z7{|bzXeK2ZsE0Qe4v=;4A|#lXwu?}u;v!qq~EUXJncBn6u7vF^~LjbxYAE6j0*j$cdJb07Mr-OcHvobfkeZ zegUCfyFEjCI<m0j1oPJo}DQtX)oP>`|-pFqKr?AduL zFa04K5*mG<5_bK_htDTnPG^lQ(>45I@N#3%nw5htZOoGt@lTZwhHCTftlGndT`(|@ zyHMCwJ5EMl9si+*YUTfW*%>4YsN{D|CF^;YZ3m$(j75mF+OfC0#f9If@P}!^gp#&a z{t+q2=yry*Z+wV-7}WHwt8RKbD@}n|D&d zQLanz{X6pt*y`fi{F?1;;isn%$zJw%L+yOTLuZS_)Hc?Tm+vo(T}8Bm(W+XU8ErtP zvA^dUgBK9oPjeSfZ1bnn`{V})02f#5d?0Fm2RLdPG~bt8kXmz(xM7;P7ugxM=02DJ zBoFPTTFlYt{Jn#sflvI@hHLgvP+GYp5SS%0+OJL}5za3qj1nb(5;Yysv7;A8A37y* ziMlGxGJ}oP<72^&6nvZ~KU+cnFz8CttYj< zNY&Fb5l+0+LX)z&H;={x`V^FsvtQpO#Gv##?x9k zKxE{C`TC;+(RT%yH0_!tMEI}&*2Qq;p61!&p@z(RZdcsS#c{jNn!jB1_eu)i` zZag~Q)NDfG%upq2txca-?UT%`tU#-hSDFhpl8T=3x^3^ zj8U7&W-}uNImX!9JMXHup>{UriL+ahTBT6zZ)%<-m$0-;QD)$gmC3=vfAQku?1`rL_={{NyY4A%~dRSGI3-a6=UQhN)( zV&^4NgUfnvKS?5}bO#IrD=J{co0a{|w>74P$LxBC)g0Nssv0>3plqa!b!M!t#5N>=;FDIEjHdaH)RZj6zXa&j6k?aQkoE*w92E|Ve! Rm?nepfGSPSF*XppvfIk?3d#Tg 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 GIT binary patch literal 0 HcmV?d00001 literal 96000 zcmcGU!(t_h5=CPtC$?=T9ox2T+ja*X+qP}nwr$(*{=}Ka~RT?&`XZ-J8*teftcQBj8Bb`uT|5T}Z0dnY8+5aj>oC}G+OPt-aV>pOA z_$I>~jtpP9+d=U3SFL2!)|aNyyKy?g!m&JEvMHgj4x!%X?@%yIiRiA%Q&Q`ZR|qoC zi|-#jU=&%j`QHOwykKbyFfvmX`o=-zlt@8o0v1c2>vAJQj94Ou-{49z;I=CVq5ZS7 zD3}0C+$X1^WH!c9PdbI-+~9FFjPr1r2FtaR%Vu1WBCW%D3|Qx-UUh}qD;m(9I_6gz zv=RQ7U^`Qm(kOeOe;okn$)90Cu=|N zx>n)MM-Cv)7;KA_0HMPRzOl?XQy<_-^7GKvgw8S%l4kSNIn)`cB1+j#$cr4oNL+B$ z?a&x&h#apgus89D>wPQphztkoY2)e-F-%vKGJS%qyD{QtZw!yM^adsC7LlUH;yzfE zk3H>dSU0o4q8oAC0!8D#6F?0F$W`!>_HM%QcJ* z=CJw>jM$#d%lrBo)_xfu&z9Khp~zB>PsQj6pL_n8e2ep`zt3Ww?p8*6N?Ud2h8(+d z?qE|fiCCX;iZxF>Xg&sYp#)MjgsT9!s2ah4n5pkg?|V$xL%ON({1oxzj4Lu zm;$E*>=$tv9a}k%b{bf_bFhHET`#9#h)i;r+`DGbglzMU9&{}zKc7IOW&IYrMTmCz zUho`VlPtWE8|;XT*an-$OGZh>lx=8JP0+l zR&ZS@wzNA@sN+CIw*!7}5o*Q~5I8SepU-Qu@C-fAkux1MNp?LLNBr62CWpc#mmqVh zpE;d5HQ=ClxogRe7$`;8J~U-F=m7#nD-PR50LBfNU--Z=ufdhSKOtA846LK0s(GSj z|L(yFB4L9{){H<(aJ#qxysh&o3hk&G-aF!GQ;SafM{t$Nite6k0)lqvo?}wB4RWwn z##Iunt7bN{v-rMy&^~&0*j00EkPH0nu4@}tLZRMV;y90A;;3XT9433BPrFz>cUqPC z7h?XC<3ohchiE+6H2RqjqX(xiN%o-v!baYrbx;Q08Szk^DUbbq5sNUJ%nBW-bSDHtT`{`pXA%7Uz=b}>h z1Fp0vJ^itvHIWzFbP#89FO_W~^-S-Qyf93%j%m!7WHy2jHloXm4MH|r9!^su`?M|@ zi<4g;xoeK5Smq$G&h}|BG^7Q&-bTcyI+MYsF5 z>BBidSp(UTP>Eu+g5pV^u(5*!{->-N|KprskzSR;Wju!(`A>yr-w?l2#d>DPpWq7y z_99fs-+}&uA8w%ecYFf*%jrTyu-8FgNS!#QVco^uGDK-KD=TgXjIU{mH(crm;#&}> z^Z8{MsSDp&@Zh9?xViACV|RZ_u>jbhK$NVdikutpw@ipM^}6KQxJ{Lc5v{%=m2FV5Mxof-wLkTTFDh?D{!$nLXUcCgejDzz zX7LMp#BliwmGI5j9;B^6MgXsI83^N?`0=Qg%GE&1yQ>i0w_9lKeqJr`k+1`J?>O0} zL}aHmS#WGc`%aRo*EBrN-VaXUxyZ~tf}t2C!RaV>-ECNj3fhsUyiVih74KuI!J2tc z^6f&f;hOeyp(c1cH$?GZcMF(y1ZevE2t6YY11Nxf9~?v~QU)tK4@gqg3)EHNNWdC! zaB)^dla|?*D|&eI>^=psaQR2nR08QW|VM(j^1Zc$A@!@Yb-Qli&EVK4_9& zE!HY3tFQ)`>ogccGsn-npqTQ?RSH_M6^_tYVgGud=KG^u8I%1V8b0umMf)f2>)?pG zo;*Z9o1@O~F+PqY9ai;w&mIN_CaLk~0UCOYxl!e0vyP4_6@W&I`UU;1k9tQ%#QHRn9fANZ#9dqz2ycbi-u(f zlFKW1qbsn0tUX-wzrY%}8v1Nm5o>2?Vv=-{K~WdE8;#qFP4@G=1Xa=c$TY86*lMvj zwubmaCrfmXneTO>7qEclmsF0DqM73Ta*}MEJ>7uUK;505u z>R;fg{v7Vam;nKW^m8EMBBH1Yg`mO-XqN`*y{;(8?rlBc zN2{5Zfv-!>y_^IdbhoeT`UL1i9Y6T@=iIQkhaT}_3QEP^ zNhXs3z!cJe$cRj4#lyX%Fiq}*!cB=%YK@#uU%=5$UvTrp5zw_n7Q_qqF&?B}4jn_q zysul+a1lW-96GQ5s)N2JZbu^>TYdPubO7%z!is^ET*OZt;v8)5FCZj$M&_lLf7}-NA>5NpqTAX zZU*IS926v_V49yiQMSrMOZmm{kDZ5un20M6o9C%pp(Rc~i3|TfV|RqPS8B)ebCb>I zSYdc88j6Q4hJbKgZ+6dB%sx(!5fc)di=*zg{QMU@9aNTPj_oG?TjH#zx;p-9r&EN* z^QTTxv~AY^r-nwv{5#(Fsln0c@OrF)ye*;!%32gX7ojB5z ztce#T($GJuOv}aBFEQMOiT70Yj91LouHedC{~{t zymqOJ3S@>Jie zvl~=iu_$Td*DXwhP2H|1LV9w`a)?{N+x>twtIp6M0twPjqYr zLi1yMtw|`Sie-;j;ul(Mv**nw9a)biA`9?>e!0Y(puxfq zCYhS_xhO7(Vgj&h+ZAeHw1LtI?u}rNz8_-l% z+kkGqvkwzGPdHX0!!v(lMYR9D3NSxHOFj0mPNJEuZFcz8r6dPFMT$Hm#C}`nPHQf} zuSEc>Rui0pOG;<+Pz>p-Bk^=UprjD$0t6mMdX@LySPD?I!0&Cs?(uQDvV8vq@g zQn7&{`i)m$)(m~h0zY4eFuWT?X*g^QDllIlVl(0Z-d+yUE%Ac6(3OONnb8Hg=?u%i ztW>lGjtBN2WRwMCC9%oUBN^ zuHK#Gt#N}tRd*s#kav5Z1Dyu!{$e3Q1=LsgRM>8mLKsw&gdivyZv}WgMU7D`e229T z`W_dW%q@cr3}oQIkg@{5@IFI%pVmle4v}?6so+VS}W*1 zf0Yz+nzq~vd3sQnp|DaKm=#1^@`Jxx$B^hjjKCc>dwXJ}3G*+KxUxn}jCU1rr|ndH zT*p660z)#^;B(Z6O)Yvsx7DoB9&lS`NdWz0HKII{pdWytd0j5}ak+dP&5WnRfh~70 zb8fNs%8U}y(DLXTz%$#hLUZ%`t_K9x=Nud@&HWmOjBr=AhIWAueG#8LD??@t{rZ78 zENLX8v4}Po6!mfGB950+)g~b8>>3DdvY(n-$ zh_S_7UB|kASp%nkyb8Mfbuhj8?GXY3=9LGRr63;MJiw3R%~9j_GevF4%;B-LIgyPR z1wRU}DTUAqdToeb>^u8ZGV5vkmx`Psc|v%-Lm>AdQBE7e0}-CmjXdAA6r*N3C>0C8^Il^ z+JR?o0Efg`0*4(_fzwVJ536nh@)m1|JnUSKIxVMw8;F8)Aw6neP12FYl0v-Qce)S( zR*IrLipI`WzQ^$*myYmq>-I%3#MC~@$i5BPW&b9&biGjKBjcFh>?)nL*r}6uO{e!Y!6urjEeXYce-K1iO+7mJdh_GcD0iS(XvCI>>bZ7ijVLMj8ygg{_JFm+_=5smse*1w`Vv^_Ghv4A66G=(UMiam@R|T1Y#! zJPQZoe6F`A3K*O-=(O%J&5T}x+0gq*Q97>`Q{rs@Kwct(<#<{yfjMsu1+uU(--;>C7QH z7zusf?S>AESvMpO-Vwl2n()EG9;sG*uG?lMOSusu6RV21C!}gdr(don7*+2ijj3$S z8Kdow?Dje-WZ!`>&{o$X-{Bs5p%is_ZFOt|f1~-lko+N&nm1p61@%WvS{q97tjU%>2P3!?2KW7$&zEkO z!}=nyT>O|FP9Gok4(#h@lhFBS8x!GiVIAkj8&@lQzIGm05^13;XH{t#>HPNH4FQHh zUk~N`Qjv*MXPj_~Xra*S)Zzw?su2yA2U($o#R&qU0*OWhPL?OoJr8*%e@X*Mr^`IK zb})jS$KA45Ff&Q9YsXDAY?i!VFCF4SCD<1f8@AUKMxWf*!U1U~AVW+(E#eHUf9>^hPQ_@d=T<}G+N%?Hn; zZ*{$yD~wTvVEg%yv}INjNLU;14H_CwCADQ>6T7mMP4}vdQSo2hc`=mO;VpR6ay`NN zul>AV3M(z9dztd2XF)Yw_7J_NzSYM!bDJHMhfG9HHlT4 zd$L^*cAkWZyhu1rDQH|p>W7T$@R!S@Y`K_^ zCUm~;GT_LtFO{3rc}?aW61;DbkfOamw<{1W$QCGFDg{;Z#cs%hGb|P&_{1{>9>fY|UB1*$w(vRS zK1yi)Ed9-dKfuK-yUzsW``^#+I11kXs@M)(R0Z9t@!CUCFb&~Mddk^D+x43nG2f1q zG;vlx(d8*@K-b9Q`amcsNLZ;q2TET?95wq`wzH+=f-|&UWX+A>&y) zs6ePkYwc_$idtrro>b_bAV%AWHNW?nh=K2r1!ic_`}8M%H5y_Y=e%f1V5!~ zpy6+!r*UvWgsP3VxAJ7tILN$JOsWFgOx=GIXFtK2uY4wo`NU!~ZIEoNQDowb)QsUp1|zYq z5Tw!sXDa6-5TdN}MgHCXyz)4LdE!>pB-AX>z3se%N&}E^sGpwLl{B|zCdKjzV;9-v zr%{>GYyBLC^09I6B#kY{bRn`{W#QSof>^|O)YlR0ZJL2pinyv~nH%hQj${pH01!J) zM76QYopJ}!)he8+(|g0y{>4`r3+==qCwz#GDpRDrf(MGq1qHAZht#}##;WN6e$)xKzz9A3g0dle^>LnDs)Jp;nO8}mL*>ZIHXpfSiE{5zQ-U&Cr^Gv zz0LAqL$UdYu7?`J!$k5v)Rq|5Mm!>AR!u`3ut59uTfx@ksA6I2jf3bAHH z;y-3nD7F@KP5BPgTV!su5X>5H^=I#A@NIIEqBx8V2Qz(bf2~nj(Phlwiav`#F>k#m zDwFQSUjTQUToC7J6O!w)KO<&@8S5DKbo#FaQHuCgNL#i>DMe}M7@HX5zyZ#FJB^W~ z7?4h`H^()TEn1vipBYrb0JyOnQMC$O53IdA)jaU>ka1?1>;-g>zfchwt+}q)c3goO z4p-9I1QfcP|3^`RLJyoYl#OmA{7~1AkcQ62a0BTtg*PC`TESy+D@HJD0kqCfYprmN z2u1{*H#gOdllJ%_7k_dJ!#^_qA%fyL0?wS2rKxbdp-_S`gf1~TxUnvz(R9nQy-_UFJ2W?B{uD7GAQik*2y6elgiS=sKnI9Eu>G2Ix)UUthE6W zG!rWLr|vb`#QB5&{S_05{`$|Af#5hE!ueo7GJnX-XM=v&B$V19wgR*dZQpoaZp43d zYK%L}gQH=P*F-OQ?op9ZErZpoOB(cU61glfwJm+l1C-?xiG^hIuwq)=J694S!#Ln7 zRf1lX>fPcUrUMxq;q7I>IMHO3atoaW4SS1Y2m^u%_{>I5z9eENnW)oKU2m0Q*fZ-T z3#0dt43rt@>uSQY{3?aLb)C=FdXNyb~f_l z99dpCKj)wxXk;-DzXv^*Wyspj+3M3vA71!H(e-%}nGPeUDGu>&do$NurSqIyUtgmU zLyHR!uD}2G6kN46L=dB$3IMV*RvcuTp2>&K;k8djw*4IE>iXnXEB!(h z_lDNyjT?1SYls)}IOa5`*|I!W%!DTEQx#E71en!_+g z5p{s0->zxn{NfDuPL>aL<$M3ZGxqBGigWvFheoj2fI3Zn_xaI#wv5NJyaFOaBTtfN z`d|_9J2?d(XpY!ynlP7leMo`Xmh3sy$_n!p960nTIDSRMbDTS=xyJIQJ7BoU|3q3a zo!J<#BP1M_>-Fh!``ta*{4QrtIez1MTNwIPnTa|7d)-l=pae2v=iE+!m7dLrMxY~V=tIlFKzXxvKEUbWIrw4V<&_#2(kYLqzXbT;XpLKhIB20SPjPrapojD z6j4N;x9=_ERyG~0Br|uyUnRN~7&bhEM1f9o6^y7sv1@Zts*HorGWbsl!fHLPW&ijjXG^74h?)aC2cs5DvSinbtU)mV57tQg=vX z<@y46=D;Z}1{_Z(>(8D2g=f2Uu{U}EI<&Wb0mHXPd_>PPI9b_gDS`ZwU(e0Fv7_}V zA;5n3Ze2%ZEH=r$AEY;TD-25;kvDYx1dxgkKJ1M>(<|C-Y0(57XOr_&%yYD*j$Op6 zCpjoBBAwCFLWgo<3=6S4SX=iUL~68Ehy&)osWDMsyO${rO^U(t{W6h*jJbTH^u^3L zVtmoH5Wq<%=Bs$Jez%55wV9zYkr!Qr=#P9(SXvYX7RWal$afY zI&UsJk`LarGRYmVMbiJ?eaBU#gcxaXqS~U^Ip_$oa}Ae(pTb#~307J?D7edc%g)Jl zRgYRh7F?bVVK*{SO3mM&6R?(OZ=tp%z757zUQb?O+*L8=Ms6Dr&*VXsN(*6|pNNZoY8j0_0Yp}h`De>;?W zC!lK)Lc!)ujK|E`&ZWE~z0u$pQQ_OK)#Xs4x(OrKce5F4>I}{s0qMPqUt&!FVbv2MP@4=a3lBmC}mlvo>sXC5~cX>j{Ta%G5QI7Qa z84-I%cyhP7pouxc(3$J@gQqsK6R!c@9PK2)UKJjym{J|se|e&@jA*LuIqqM|tnqNM zi4%0+pMwirwRcm5KE^hN?-{p6H>Y)>BW);@!cWY}e*%GtkhM#xb_<)459ftgc<6vm zeMsUt3OU{>#-D#+C_v)7IVxACj9yUBDlqBp-}I+DW$f3ywZ(JwUs<~P=n?1mLs>iT z5vewc3bcPrK=j^zRp=k<9WD^%3sMlv3D0zmOrR~fQ~og;RI?ZdWxP@Vf6x341cWjj zcu15nUZ6#Y%+4IS1I7WbQkEbG~-dt=g>XET5m-Wt9C zU~aKqC>EfVMg|G5JlOL-c|%SIQ;d4bZzgowEJD8HC3~ZBu@lx({Q^j+)j{)5e0;=7 zF%zmK&|@h+iH@*)B)(Q1_)c^*V0#)<^tI+;ccyxKc0W`A6b3tOvb5X)(~OCyybqX$ z4qU9leP>`<1)>fGe>tGfv%jX*u3-Yw+FOG%w|q4aB7+|3hbaAik5+dT!3w08)t52m z_ZUYm0^QQr6|8yO1Mw!SPfUi@SV6HR#W8SwGcJE?oWS<-&FpxY;S~mPA6y%?ENhS) zJzYsM&6#0)=n>AXAKb6)4|5(Wx(Qz$S~>F(6kOO7y@aOof&dzSLj7z(^QWA`YYHY* zqC17G=f4{~Ofp?(&86!+#3az_HQ5z0rc19hi59Y1{`E^>r*pS_=y_8i`yFIjO4AbTKHo((B=i@S)Qhxt4;+5}{KDXvPByg5gyzo^$;^k^=0kYOU0mvaAD zz`dsNDEiF!FJP{#tx~Xy;Vg>+=>y>F&iux>sT~ONBAiEN%CtM1)y!7}YO)~478f@q z5YNRvfc1|K1ni8{LNa=j~C!i&lMA&ok`ydb!dou<>& z!-2FDI~Zi>0yF9N2wc=N&BOjv>&jxLz?rbUP>T)$kbl?SSIEW`#(u*ekb^EweL%g> zu>vf~ST0JekkS_?@qha&E?oCyx%o9Uap%EkBPPR8Kr^$W)Uu*C?hMXDoy2V>_5ilI zoWm~C2_dv4#$KK0#`#RG%Ah>y*zmu7DGxF^82_vf3LPcop|ODl$Og*XlrY)6IENSl zlKG;>Y;l>YPb%xL3{C0`28IWix&XEV;>={V|Q!8s*sAPsJda6fY|V^;^jgg2ALJCtlU} z5|H*bT?O+*Cd~Z8mcGIL5+d9Shwo(_Wj;xB2tviE6)~EMR$;KW5l=I_AO8@yfXKNQ zeXrV9AjXMMYm1+`;(NMs9~OY9L*PKOxd9P34C(WZu_&D}>+3v@*h%Fe_XFRTe%16( zEpL^`)mA5nx(UE;;+PMauO`(1vqe6hMy8jL2?-ctbPkAr;AeDabzcvKVpzCS1|BHOT`G2fiw`N--J|jpd&@>o{9Qq=zMj-R1A`?o`p@#Cjstvy0k(X0`OlO z|Jh`F#_2K0h1<+v=z!sZYTY=|M~Exz(#SypP88_D%7rEd?SEU)J5NjW7=BA77DhnU z0B|23)kW?}<3Nsh$j#WlD5(eU=%!d1A~&8 z`^0R7padRX=M;rSG>Tkf;sz!97nmZ&TiDOTGKXu2WgYqC<@Q7^Y)<6&8)M|uWJngT zvr)1>?a+E)Ms|?M(JGV2>tROIxNT9MP1mHX=?coK0b#S*7^8Fz+@Z-L0DRg1t-uaG z`6>Bn-YOani7~?$T?e$*f|Z*XHXJ(5=U>15K<5bbKBE>h)?#>#+b6c+*&1}E&CXyx znCV;oMH`bNON^{@u0+fJTj=MK55SPpko!3Qk4YFwEjdZ9%^|OE1nnh3 zaPEP2r3P8<63zaDHTs%Z&dpQLw(tpIOhz1M!$|=Xk8NWYn>T=(%esCy0I1hh_Zn?S zE){3oz2XEox|!WvS-OO$TRRpPb(x5P$-@hJvMX- zcbtx%v=HC3!C=F80Tm4uL&0dIJu{p)0HCs|3-NPc_z!F-X!rj9?k-Bg^ULQ?OkPQN zKEF=8Lmdc~X!PhwF#xG|`HW{}_t+=P>$%|`LAf>gXov(|npXP$#lu;QSbzdPMb&@8 zD`q~6?P%ki<%S(#l^tU$>O#ODCv2{Jb?G)SeFaW$NpWSOl}s#r+*SCIXSC#FzRc2( z;c_@S9YXeXH&RRbC!|?3F>}&5z?EgO=T)QmaQChi;tD~;yBB(kpSj_#FgE5oQ-zSc z;e&QD#kB=JMxn{CfgeM+XVEM3JlA(gb^M0`o`hXI{05MDi9{Rem&E|*1jgc^a|i0& z_kbpCf>ylPunoM(a`1VxVVyhtQ06^n9m&)Pp;y(f?<5>5$k`SPekE?hCu3Vf*ju1J%_FTaJvCzDcbcGSDmNb~3Iz*p;9OH;j+ALr2(a_g| zRl{0A++@V1Z_h&God`uY1S^v(KJPgErZIt~Kz#z|gWwE#O=K$f?NBtL@fUzQF@m6zEFlo=NfEp7GxgOFDaScjODmqY0f+jTt5neHZYoT7oYkSTfmuRY_(9m2x8W>{?|@Lo+UPy#8w7ejejbx&dKo4Wfs%)9f%h~8 z^zWW66xbh1&wqfnE#QI!ZETO(+%w+lG!utV6Zeuwgl>%{H8{#54f@>Ks&yYuk#7B0 z5KvIw=JWww@i~@a6(~Vfk2^xt69*(9emrSmY?9ssKC$~yKl&?^i}F+aRO>^Rc8$nG z+s_b*n^(S+7pgi-ik7A-JbTTR)T%{Ht6j?aIL&^5^X?}fQ%!cp3mLZJ(!a#)@n0GKwf&e5lhi|>Zycp z48vrouq?x)Q1yKB^;z~)v;QFS0#{sY2%LL3AC^$f+XOzPpo8rB_M3rNU|_7<=o*(Z z4c&x@Pk;aqCle@I{k8Mh>OzlbADUIqgE1WWhEHI}mUiM{^rHjy-&)whdXr_|f@!$q zXDSMtA@LI;^8lj%9;EAA4rm=JfF%8FO;*Oc>>op9By9)qd))llob2+DFDTUm^878R0(FPd&9g+^oBioqyeopfuBXB)F@>sB{%})SOe||ioX@ES z1uq`}3$HOH1;Ul)B3M?|gr8Jk`sgg1E_ zvHY&jtYv>clV8bCuf3n_7`7n@RY!6-U24ENInU<7qE}Yh0n;d)^D`!u));( z8C7ldO(LDk3<g;w} zub`kKKtw=5efY{T8|hF&y7Dk;{6Px)AbQ4H44yk0X(-z0eRu?NOmET{Us?{ zR~kO)`N|#1+?aogwFr{=A+2+M(6UZC+C$H$v%3$q8qF^(Yv7MXW6jPuMM);I6Z94{LK`ShB1HU$2d z)5&6x5WBLsveRT7tzS&xL0X8%s(o{|!g`Rlt1yTnIHYvfoV$o*(vP^NL#$>3^U z>0FCnC7yKmtbznyLHRV8YLEg=r|Pe3 zS>+1@B{~lVrkdZExSNnRMir?-4IGmHu3gSeWz+RO#+&txAU9J(pU)dT$H-Ofe{@B8 zhH4IGm@BUM`uuYJY^enQqg->{kCbxxir0jHn9R-nmL)oh8J>(+mv0^W&{*i%27MA( z2QD{`nVsbh4kZXH^ItI8iv31r;wh@X?M;A$jQ-GVlr;XxhF4mzdM5iE`P!Z}G5)Q+aA#x~LHCi4 z?+hY`w$YXk2`wPvPqt-i+%|S0LA6MZ(ufu_WO%!yY1Fq|DH?lcIPn9CY znyF-$kDIGd)?qk9wP8G7*v&wfKXmcK26?TXnQ}3RHX^FF{(eR{T#VO=J6@mnSY`;^ z(HxRjZ4zT8D;{?j!8J2D93^(Ao5;Ue-oNDttjm^H=-FuFc{>jM+V`btGg<77a1-(P z_r5lmyr<-->S|Qt+UltOxPJ^7$X0D2dG5@?4<*J$+MVf;V@ro@uia-&ri6%y>5qsYM@|so+XJXjU zH@D7VUE15$coUPMaWH!!-`7gJ`Da9X(7};-z^nEjI}uA%p6q~Nj~$nX?hY?o;d#nF z<6#ASj;o=*{N1`BUSgrYXtM9Fy)_-`mwib9+8Bj)g0|~paX#JZQTmQuvVe8!)~aL+wt2!7f}oIr?EVb8^$x31^D|l?UM*q#;d5Yr zyx&tryx_QNGOYo?0w*QaOh*Py`bgT%RvOf%%ys7%(^B0oEgd&FJT9AFvW7NPJg)h` zx3g7D?Db5RD3Ugfa+uU4!TVDV5p$7PwZq*PqLJ((_YqG@N=J);`g%;Ysf*Qq zY82m}*e%+B%!059tT2xT_xcw6pH3PwV6=QbTjqhgJLn$-9Ga2=U{OV0VI}j3Uoq|^ z<=K`gNXUi^s6a+j`H72Pi9XM$VUDFyHWj(T#j_+?ybX+~sHOpNM43yNh!W8IHvGU^ za*(E9lkYEpb*`%CS#2?6S&URYl&IR5@vbGgkYIJ>K6M2;*`q|Aw_5iH++t4x6Qi)2 z>L6Dxqun~&ZVd2U1uKyIWQ?jw5e%Ou%f}-~n;=|~uils}03COIOrh;;0hNIKg$V_as*b4>#d?a z<_<5N760(i+i}PI?vVr1^JN;>XZsi}Pq=9C^&hRz3!iStD;TiuY%KinZ%q-g zRE|>3D!5(f^uHZ82zB4`-3o*Sn+iyjm)TYs75v89kFD4k5{LaH6Bf7`=y-?azKeC;ktZa1SNUQ&IWKpG+aVeEP zUA1JRWHK4KKx|LmGx5Xo&k4$C`r&Q7vZJd#$y-`$7jTQN+ex9|7Cuh)CWcNo@6@#4 z>fVKkv#))fTT!UA{eoX)(E?>6VDeac#1o5B4M>ZG$awLy15_X%Mqk&H#2q&OK(n1W(d#QhZQ$Uq?ho%CufH}y&P=U2b_r1V zTZh(*m-nXIcDpwa!lT%#87;iGbfRl)x4ex)F-TyQSx1aduFRX9YyJQko|LzOhtV7) z)A76rHKTRwZ5*Aj#K>KyYQ+Wp5^A@i&*jk8%b+Kb&qx>k*`pf%DfkYmh@`$L|9~yD zXTxKqzJ>VvS1J~ZkV7M>uMKkq#&uW;N<%SlWadSRyxGD99BwPOY^t4y>>H$tkkGVNos4*VZSCdV}*oKNcnED2x?ot zf(uv;U_us6sqlLQ3iQO+noPycV*wyHSqpAu1Plp;W|Jfk9Q#n9(EF;9Ty=2l8Mvp~ zX^;M^%A57eXEvg!p;1UFyYrG2-hnYt^2GDi(X5vRS$po`=#O2ll#0m3$1LnHA5pKA zpt2P7Y0l@(7sy$k^^$Ii7)U@~Tyt6^`!Wu0i0gK`$e;}nKsvS!S0DApXQ&;M5E@Pr zx`b79rtd*bmS!09^o;$My@;EKco@B4rQM5ND7!FH#e!CGdxNPa zi~)p=?3e~t!jd5q0ujd0+_CYtP*5m%MD7kqi>Ft%aVFuq1+moj)-NRqo zY4MaKC@da(JPp5$G!g4Zz|+#KqZC-<3l6@b)A0o;DtJrg4@nPX`)H2e^tcyRRnkfA zU{^V4e2Z0VP-@kwNFg^_A#fKXir~eyT)NG*1s}Cf?hvb~0wX&!4`T4NRe=A#;wdeC zl=tZO{86Z5B}h+?f*)dF z@EU}-^@()b-pi)kk}EIl-|B zRB05HnlZw*Cve=bq2|0JLSWmQduHtqW9LkakL~+ADfM?d0tOzk~J17d@)Vg#)=%nWA+m)Z5@fD9%8h^mPNDBT*4gdBQq ztdYtUT$yOC%?S`E+sJ$edpY!mt%(nCz0%@1 zy?3xbmyln2Z~C8%giE*|MAOGBmZ}*Xx16qt7HF`zrGhn^|3I&DjG`+~`aWW6x}n0w zA^Mt}V(@{7Hip(dR)b`)%^ZXcswU6}Uq!O->T##io}Zt_PiuPSc4UmCcmd*;uCE?S z!Xba-L7yK^EZQ%8i$JIY871Bg>T82G#^@B=zk`72H&_-E)diC!LSLVr7rMvT*tJ_1 z8Kp*a(-wH%P?Bsf`-%_V=wg@l&1LXxX*sXjHBy$OHA6YSjIT`+iumDv8ObB$h$A$dc%He6i zRbpWs#tCQVM)6~Mf*s@xbz)YOcv!lmZGmPcXxXO`^S}BHD4+prPGd|72_Z)>)@`d=Qug424TP&04 ztAb{Y?_MEb7>N4A(!kC6M@S5p2%Ds>1m}j-w{ggrjCBd|>iS*ZWr1)f{4x%ms!p;w zylm6SSn5??M_=!|2o!~d#$zl}6_lk(X`#esfO!@aWKMEwqDv4ZP0*$}NRkokFF2-| zX0^kaaR#2CMz}uVeDLWVr$FHzWt9*KBY zj^j*kfa99^46dCezyC=6ZTy09J$rZV%dw!R9B2?%$(jUVO)BNQSxO9Jo9%0A9l>2- zfDnX>M_o9bLjV&-?O#zHse{a2_A72l!z>Q&=aQsA2<8g&6cA#;a1-!$bcL;kGU73&locfS_AQGns@ zhIT6w1QGxGe7RQ74q{Ve>7vzd0rL&ORpxGi335=!%;(U3LNV5U>+w}8Q9IuG+}2y{ zp0wTqV|T(pc}?0kWh9XOJ97!W#rP<9f;V=kLCubnhkOoR3stSoy05P=O=MuJBGW6) zen#m+>`jO=>ZdiZi6aKCo;9^z<0z2bFWPkDBp(Iq5o|I*BOOOZy*%4&9Y)E?aaM$Z zI)%dU1Q>h)g*Oa2nK6EhXH( z#90Qtu%I;BwnE@sv*bb6e_-Ic^gp2#4m2MEiY!Y6^Yn@g++N|wf?dtT0h<6$z;g(+ z#Ba+s1DuZ%Jgt6{JhQ`H`P^^eXNY&NJiMWpXe^litd4^Jt=m;)F2%>L0JZ|&4w$fs zCG&aFvcwKB8DC)tK|q?ba!S+k(Q{Eg9f(YeC$IDZ%>z^So?*wdt=kBrMeLAcbt49E zdsCW*+yuDR5eT)>=aJQXg=%%+GYv98q{{|MV8cF-I zhu6O+j>VP=5t6Vf_?-lijWa}bPqQdXQ=u1Y_oRxtFo~U!;Cjv8OS<4X>O^wLC>5}C zYZ5`U7k@u%uftvWn(Rz@x@c3~oi7Gm{c)14!j|%Gbgol;*riM;MGqL&dF^#7+2F<8 zvW6}e4pQiNS=S#!Iz3NZqmv0xL&}8uGi3hrQ9gLz0mmGSU{ykm(O0j?mc|I@4;$$! z=#MP_XtmdG7xd-~bhia8(Ob34o85fxC$nTjRxynasWTswi0#2EAWkl|Z>;5DPE0$w zV;=RrLyz}@6(bodQvo+tw01xD&)z5Be=P}Yd@>Ds`XL|Wpmf$Xk`@$0o3?9X?G`Us zWkB~{hMNhB=jBZzo2(X1Gm^_nx!&t$5RBG`8`D6`$rleP)L<$sCulF7FQcu18Ri7G z0csS!!2=QiJ&~Qb)q|he{rk@(EvAoWE5cHVa3T78xORjj05l!*EuS?eNYwVsBG3~Y z+lTTdt#Isa5A=S7AV?hu4p)^FL#=>B5vR9}!t&{yz4Asq+Bw#~D%o5IFyRXsO>b>h zj_Y6~gy<9w#>W{3Fu88^{h@?|xUuEL4I&y!_nshy_@qCwc3U3l^AcsGIE4WJxllcF8Kk)9k@3A9!5Ago_jKl_NWOk50Es>DSRam4FPC zA%|PVk9(^}34{oN`}^VR6EZgLt)E7n-j)OKZblU-qHj6m#1=mnfwPDjNwhoTKRw<^ zY7=*S_q}F?swB(s=sWhDU`jxURw&<{uwo8;v=fC6%WoYm?U+&Hg4so={@@>vRTxZr z2p0eVbCgVLY zGc@NYS$XAPxcLR$w_f@Mx~g)0Wt$1oXtoCU5Gi?X5NlQcjYs{rN_``8hTrPl=FBG5 zJysx2|78UB2;>mHU^-}X!#v9i6p^W+XBF#LS5uuRM}NreP21oP7RoDGL~419YkUPk zTt5IgXkd>&6i1OOwl(qq?OO}N^R41@Ys|1(aL7D;^;QC+azAUAK;o-gZ8sZ)r%BQygWP@;plmUsX+DJ4T$j6@NWoo5cW-8{?&7F;-D)Z;CG z(3&_t0w($fke%O7X*dG?Ttg&4eTKs=@%_X@h*LI=w$1}3EC*JNNyn3RCS%^M?9GaP z_K~(yEF5yw$CFb|6gH9H_RthB&xfVZL0OWzI@$*Q@?p(e%++jiyP?0!Q7n5!0aAn8 z>U3DvqdKwe`{?|iH{lJ2-c$O@IE9>I4vkF3bKxq^^xEftJ z!WLzLr%U?(l<=D+b7K?8p%|iDU_on6Z=MUs%SuuUBC(h+O>3lmKS)msn9u<3*!2OB zQG|4t@=w_Znsg6%&yu`Zs6pkoh2D5M9Gx`b-H_(tL^RifJ0Cm9-NF=DtCO(h!7480 z*84FtJV*y>Mxo=1isbvPoVhb=uG05Fupg_pgd;lQ_)q+oD(}C=MUH_~k*j00FUx24 zx623p^6%580rkAB+UEeHK?A)}JW6aY<<3%5qlSl=K8Sq90~5kM$}&H))8l+|j$ea?jC-Y7*i%-^&2^KgQ8$xo55e;2|nrCyhk6BeGRMu38X|;5Zicig?l5 z1q_bCCDYo%FkyJq^+(ys3)PD`g`y8{?@)crf$$L50%F;#t7ru0zqXeBPmIA{#Jc^7 z{-Zbxh@Cfnt^$dPo^}dj7BFM{dZJIDDox7A<-UtVd4LfkG5}AW%z)BZ{#<@)54tof zlZgsmpv>B2E_xgU0e*#_bC0WU zyix7E^RO!tb~9}sf;k>ZS0n7cGkyZ0BdFLLQYgS!VZfbL0O^d`VL%CH6=#C|pWZg7 zMo)qgY21wxGPG(n=yvkWQUCyLPnQEk3pQKa(MN0vdQsPNMlcObq_SjCTnP!~pI$OMCB+d(%ua4OML0}bLhKRh&IPa{1U_B( z8%YrD@?pDb`mO}Y3=}CX{Zi6>4pwWwsVXY#u(Z6>JtS?8>qHf7e=pQ4sIR!=CYf?f zHebbq=>!xa$k@b;t*;h}R+VPY4r|W-yq&eKs$=}cc2m3)PK^hK{k#mx?GSO#6@}(N z>fi{mQ**;n;%;5Vy1G@%E*=3-gPM6bc245n_Hn&>#cV%|Oq??hYUgzT)AtdMw&)c| z&n5RTE35{3d*A24upegV%C#a5=WxncBdq_UWg zy^FDUkggg~q|^I;PF@$v23{xC>V|y*VNgabeQdSulZXMonky602E+sfZbStc*rDcE z@=4jM;S(i!WCXhej2DujFN)pwswu^SD3i#{K!qoHJ!%i#1b1S)o(}$vev(;TK97Fw z_x-w@Z%5yEupMjDDIeyD@Yhz zn#G%Qa=Zn_wRS!k2yE)_wU@Z!vKug}tlko>U}(@Oz(6{Ow_S#y(}{{(PHTytf^ds& zdHxZhA+g>`g|W##PDu%+jG9k%K>`HPtSAi9L&gE#^0v$ja{CHB<>)a<)2vmD zGoOn`sdu-J*2%2#@B=#M8i)vOV;y~tToROTV&T8Ifm_@#8&i-3$qglbgcu>JzVBYb zmnT{BzORIpWK%%3?w1L69D~^+&e@Swe3=uz-@Y_Zp2m$dr;#Ko!1-=4_9cZc@kzp3dfVXLG>;gW==GhaR^~e~XhjL#J4WEe0Bv9GPMA;A>1I^28J-z*)Aw zyZKA$pIc4@I5Q5T2P%elQ4?hP)`{Dn$^y zo{t`9I5q!ICvz(~RJOOxHyse9Q@VLP{rb;L;tZ%6F%DD_n6(0qyh;%076a8QTGQS!e+2Nx#Gd|?UzX6J;pcUy2BLz0Ch=llu?{Xw6$i3p}5FM zc;OJ-e=F3IV2?R>-`rD=9F9MUK~*JEuM!@smvR-lGc6nxaq@RTb8ej>v;#_+pB-o= z3)ko@nA^S&=TMkzhx5I;4Qif`pj%|YJsb;LQ<<*(*B99Qm+FAA`JF*G>u;ud{Zn=> z=O%}1XOQ%GP|p@w0r7K0hvcF&J5~ZL#@Y!0_xy7)5ZM?|3zWMAG{S@|@eut7uf34x z3NIYVM)FMr3%lkzo*6j#w%r-B_XA;^L~@}6pHnOOe>ZWcaDz_>)3{H`6sK5O{Rskc zTR`!q+P;5~8p*;x2to#0B!LW*4`QKQ-uA07)_+pRb;v`k?kpuRVWDiEO_vceEj z63&sm`PoIR>rWDXZixPNK^0zT|AQ#6aBE)`AtfMh<0|U0lrr&t$tCS%Qb?TgEAAgw zFqX^F+U5y>h9%d~%U3yIn~@=1-Tal)SpP*oA8V--%jlhQFGIX#mG`82Q`osghXgOxBqVVV|lrEoepZrM597hE^j&ZA2VCRP>9Zaq#u z$WX8whHTEj=m|P{o#%0w++VeGqzcr`Bplili)hy?`J4KoWnvH;y- zLew73+r%}f9E2F=j=zsv7REvcG9|EhXZBl_aGHJY0->E1HLVS&(^0oA%%tRPahTwy z`sEol`O`KwS-w5`rLT(|13gSqM~{myzlQfQfkN`4N>CH4_G6w&nmvQ#;x?Fqtc|`t2u^-> zZ5Cl6iFB9hzT}m1gJs#*x!F0I6oVZYZ}9}FkmhYqaO8Aj9yH$&m5tC^2y{riRR`Gd z@lVl0@Wkg{Jm zTrUHt0W!A$-3CHvv4R6R)Q+K%YpqCHyNhhS%Kf^97I?qoQDgcga>zwfIBss_G*Lk6 zv~Hc-|HYl{P}L6K5>(%T;f6oLu?xdZv4ykbx*ZWRz*A`bw(Pan>jcY@^iJZLXYc4Q4ThsYhHLhFtLTd?L%9k!%3@ zFL429xh&me1M-O`y=_wt@xz=^QZ-;yoBlFBrF$)b-OlO(aAG~0lg%SHM2F)i8z=zR zn)=7zat~$*f#MHIByVI?J{DD=tC>Xu4itq;9odNAFpkr7{9!OyWG2SX7NiYrRQhfT zvF|Nyw8b%yW>*oxXP6A*$OT)Rb?6n6ciq&n;bl1CJL8yTwinISCt(YLD@7`mpV`aG z2a-@lF)x(lUa_YVn~3Ug8!RKo3gL=8N*;kYmlDRu)E;z;jC~Ut{taSvn>XOB+8RCs zip(lBO$!x&gu1$pRdP)?j!TwWtYanl_+YUEBevR{PW=*;d0hr?UL@59^s}mV6Sy%s znIz8T92N|c>sPASWGQ_DzuJbBs{INizGIf_0xAc4?t?@JX(<#lwVcwSdZ~@XcNsaV4cRybTgw@Q4$teVO~V%$)>TA*4IcjF%zAH%E&7 zJ%Q$8--JnhscqZ#W0_?Gv@`uiuP6rG@M(h%YU{I$M=#dhcCUG|9{r^gN)t8sZ`qt5 zTjXLw7DU=U1VnzLZD^FF6+I27_Qrp<0f3UDpCsFEreU$_*MP!Y4d+4In&8jCBk*hE zV};&oM}?$(pOO<^qkRD3?Qx4VHL18w*L!+Cil=X2wK8IS90ftOWDKV-e@7{Y!v|Z) zLkxwqCJ7EDGR^^2TTWSqk+vDdcDm3{GB3vdSeT_aWz#STbYS2$>CovGkcpyp@n4B| zqn{`FuEP_a*;9Famw2Px>Z}=6()V`0I@$D(P{fD@{($8?$n&z@s{UH_{)VV;AN5YY zB~}6zwSCYfQ^|7$ENQU*&ia8o#`8i9n<^atu3OZ8I(jBfuEgzk!W|zk0nZZzBftxz z`xUTMVW0HAvE(y4yXO4;3Sz>grk%m_bas%O$Ie!nrvQd1X$-l$vMI@XF~bbtZX{V)I+xg;92VF7jt zCw-(T5w25pFg=Jc0gI??aL*a9l3EghO6Cd?fZFjA^@{Re<%$!t$eegS;fug9I7t-x z`-TYBOg8`p#E^yljp8l#;7BO2g2MiLSzFkIm~Ci-MfDe|l{>!CNAWd4U;UPDk4Hk` zA}w`;JDhJySl0y?v`|1~g^ECKA54+Oxgca0iW3e9!z-*FKEdK82m`Tr8-N7wvaNq1 zUN7kWx%uo~!9iE4IbWX+k_HVJ^tU@Rz{3)mle<@Kc@RJ;JW^W=fR2UBQiPUR-M)oa z5i=sd@d26DgamOaCzHTxTlt0b$mR#-G6TEqYTBusRQHBrC6e5#OxFVGs;V_xjn6P6 z0riSV$c6{`2bA%>f7N}iNiyE3H(Vtl36-;1@=M*MeW zvhoz&+dAcKQ~mlw)6x)uzP!+DNp{(i*@{V%m!wUi22ia^9uKiy#yz-nO<>mz{|s&{ zJG4IIT^T@VJsSpa>f;DN>nQ;V<$uft&fVp;E%%lVY@j)N^uPKrbX{qRi~gc~uHM;0 zlCd`g@8lRq@0))^XN$EqqI$Eg&gjfO?f!#K5)|sLunoX_!VlJ(^D&$RK4PMt|JDDq zeijL1?MZ#2GcNDu4MI0%&IJcjjF+Z9!;TQuV3%Rn&XSM}cJUO`o>Eagu8r{4>kmTi5*h!42L4^$A3|_%NE+cTp9OmpCp=g-eCnnnm*E z?b$~Gg(E!3N6Q1QwGra>g_cX(DZE_Tn&V&1L7?)lQqC2_k8{@MUuShH(7JYpU z7|zhjg`w8Dx>1(+ocXTP6sOn=kr)QmF$ILJ!MF+SB?&5R+i=fJ&C&d&P#ETkSev!c z_qLGwu5ofN-r5#kKtzKCm^hp>d*AWn(g_cwrgV`UC&@5j2LH@?eidsc+P9{B=i>p- z*FBe$G5GDxO*5BaZPJ1pWa%4Cl1BmH+9ose^W-B!VQU>2H`r@>%GMIqeulM+y%*^h zm*#^}uhMc2T>p;-S-F&cN9P#jQT0%OKE>vD7s6ik6p?Bw(*vlZ`BY(jJ`Cynj(#OJApN z?R#eT+L^!{>lGCYS&hag%~;KSG~nF@U9XbKyon=RI$b)f^^~ud`JS-wDsMG1I5=h| z?q^0U*`f(372NL$Ayv>ov+TmUcPb`ro^^SvMCG(H$}Vr9a#5zXY1_lKK)$mwegR;# z5&jo8F#z$E-&nyxsxovyp#`hsA@u9UuAW8@h;{_H;?|`Ev}0ZcKxEi=2N3CD-`s?z25-n=iU~D zi1n;rJD)GB%G?Z3P{(BUq^tNN7Ipr?5_i;|b63N)wt-e|YCSTwSK$L(S?e2$bgpKO zFuxawB;nUOWbG&o!`Kyr$+6;Scf~iN?I@r!fn~~SLCCdl=Hoba}j*XBjyW{}zxC#dx zsbgLpO+ds8I7?&zAr_pbAe-1^8Fh;I5QCB|QS}1K6>`j=v^pkI-BFNZF%SdFZp^D* zWuL^Oog@)pjuPU6l$ScLTjqG$V6em-rSKC9hE>k5aOViUwAj54ZJbZky2iN?bjwvo zj)T`crOJ#^!{dymS;pN=>Kgi0kth_7R=s9r3fmq}3~0AS^Ir(rf|>@~)y8`)z&+1Q z#rddQgk?{amKHl%)|2Y7Of(Q&RYSb41)!7weWQgm;8{%Hz2Kic%=v*|(Mpf5PBupp#@;z`;r zcCM+)!<7^w_yA6hd`Hhq#+*7;8#IxTZb4guOf3dN1l3$dU$%poG^6us37l)=w2eEb?9d{^=^yruJRIT31>VOMHFEFcwn$PFKThgJR zBwWs;qw3R{OlZDQRGEd&_yDMz%+-=Zc>@uY%*a=oMp-fp;X{dv(nUmoW`;X@@Z`!l zcnup)%}7~`Tn_tbEB2N$fZCoAfMpa3ROZwAkR9}8RheZfZ?oDT%NeVeOQyb0Ft6b; z^w41}OvdO7J4YsGT36(ndAbHvZUWwNLrWM5ZQl*{L%+@2RbqWhE&;j{>c z6@3x6sLVZ63@h!_)gx``70|wQSu`kin=E~od>puH(m+2n@qrt`grLGFZ2}Aig*KDs zK`+DxD^CUjK(1W^!EKIop)fid=X&9M%nUJdw~%F!fg*{?b1-aPeSij%+5j}f<67ua z{yM=xP^}xA*GhmOk4-+)ws7q9pA~V-tSGKWn&kE;k{v>IMmi7|6VOhx)VAeBA_Dbp z^f;b2I!qALgNsW+vn70x+gjqvZasWjj>cYPJ7B$qtvd!4mFm)-J?Uaul1yEyfYt>d zA$|JqaN-Qut}T7kSR!8R19*qta6NRO&7bv;NxI(?+s z38UYB_j@@rBoiP?I|bh2*R&q)G)3&139JmS2gVwf-TxXzlvE#_IEzt%k$tos=^VNT z#y{&@afgns{&M_Rn6Mezd&9+ifV2c~3f}FfI@=)$V~#rI0XkJ5#996T%c(FwBSbYjwrXV~M1uJZ6L0Be+xv~S~XWA3`r5q%lP`yw77=~<(+|+iRB2TvKv2JX%z!#RIhOvz6k8qVZPVbLBPXRUL`A* z$tDI0oI+SMexg_57)hkloip6=zmpP zzF-GWw8&&V-SIdMW!@LHYPd+O?mQ+)+{JJ3{-6Vx0vyXeE+o&?RSncwqXIl(Rm)rC z1k5ZCIpF#8^Ahb&lTl4jAp!)@D7XNjbX^#*Da&lCpv_HDtgWFKO1uvjP15C&D(J(* zZY3VtrOZZ(G^I23(sCo4FsD_C3(E%2WO;&?zkxmwWbs`rq{m$+ASO0SPSeExiQM1Z zo#@f))Mns>;uO_z{`Pt55acblQ&Ko{L|He3eS66qY z|Bk1Agf0e{7*7*qT-&9LM*24rA_9VW<97@w*KxdmKS893-u*j5(Au=iKdl!Cl;mL7 zQfmemY!0yG{)W_$B%A3O7MV_iI2lShd4j-_GM}wH z#;vsaxJv{Iwx;#S0uU#0TGjhT2mBRMAhqcskG&CSnM+*SZ?3)b-tQm;qNFMt~-C_>n6_z``N7^Lup z+t8(RUZE8!!OaZTQKXz`IMIgzlFZNXKaWB1YIiAc-b3$4|I%~oqLUiGFMC^4@QpZW z4d(#~)2f-u7(UCg@h=Exo&jHoSs77}w^F-L*VPK+J)A=W?2uDsoK9>rR_u-&BtH|z zDPi=Ve=|s~mvEMGdAWDw!YPe0e_Tl+k13)F3FA3DzUBA=f-yPcAgm&Tf8iEc6m0Z5 zfa?hOwsG-Bj65@h^}*2wg{D?kv6~nbm$kASUqwk^GnjdfH~O*mj(HXs7igd^vpYLg zIypUA#&i6+0Uebf2!pnU`|e*#Epg?j2%7fL&(?t(pb|_)YRnN3^`o&s8)(LJJ%h>m zX-``N@^4SL^7<=Wq))6m31w&G)*rx4CwYqLD7%SWEJqZ)j%%@(VS(Y?>}jv*zIf9U zD7c+sz4)QIkXCaVNKE`ibgfI0T1K1c^#IK?MF12UMWyBL@GXue14=`>ETl%3reg2l zQtTP7Rzd?7KAc9_j+)Xq9;9^jM{W7UurU%l6w+{uzaZMa;0-JW2cXmG`jcql(UFr; z6^G@Ah873J0~)E-!rdCwk1)+;abpQTY5Sc$h=DK~5AfP1GnU1dl*=_@)Nt1T6BgF% z;z&pf2H#g)haGL~93jzfe)JLW(*0@+{U&@Jy!xaFqB(eC*>RcKrsMI(N0ZK2O6D9u z%!Ea^SO6sybia}q&|n2%f=n>^`UXZ5Iw^Z40m#6harjtu4_D?>9N1h zwCRx2izPnWnR*#Lf1%+^9h(%a%$;S-+PsZO4`svW73n-+1^ruAa#5JJ_Vq}>sm2~R znCLZh;L#b=wgdP0kO_;CJ$5dsql=UCp1xQhk&ya1N>D@t^1g155lc{dr+;0%Bf!lP zVw(+#RjosUiwp&HY*xDM=1X^ix;F z{ejJ#AP>0I>ZbHvJ7)MGrASN(LHjF!+JZZY>MFd1qJwhro}~23B(dI;k|7v`yuKOaHdBs zO5B^UTP89#yrlvtJbZdIs~yX;U(Hh#f^t9_cn}eY`J)pGPWk+Og?6|OB8yM*qpO_u z9fDYZoKC5s=`Td924_Kv^z81W4?dOIyro~V{oDnQFtGp0xB8^#7b=ToMXsF4;tbZ_ zOVxBCYVj{UaWVgQhOiZwpv6+r%!SFId6xz^+Q)Hjs+Q2M zO)zBjgK6wIt&GA&Hn-y3{6-nHphxn{nba>}1Dpd(8d{pRii+Lv%WXWnV44_xP#1F# zFxlb?%f}&WEksN1VyO|)&yfMS_r?Odic3r+EN91wO^?IlQ6k6C;pQA8y`d6biFCE~ zhq)1UMNWO_$QBioFDMLa=cA0sMqjLDo!z}@{jz+M{;P#){N8w%@_%IFA(;E zL+ciJX=pm6`WWQhw0woYA1<42mqAD{E3GQ&@Kw^A4S=+!gOs-DoF_k}TYZ_RY9|AM z{f_j&|DXVrUEmr`Jsa5VA<_Cm*yohC=B3OF9eEZFRjgp&5wLC)w4f2X@w^II_sy9D z0se$&RptWAS7J&01Z6vL;GM&eOF4At+wuQq`j-qIa1S5&<%)JUZd(NQWc^o573Rh! z&+hezHepPFJsT88dqdk%(R*M(=Y$4wt$+miDqq?z<738jLdpsa1zcVw+3&N4HW*T( z-s77JiaX1)lCYm?Mk6R4Y87rg+VaP%sgTNb%-n(BVi^}sQN}@!NkdDlAg|Z2ckTWM zG`=`xFik_~+vuVwEydz=Bm8I^){E;6ru(<=1_boB zo@BFWKY&X+6vOxtQ}6^aYfn8v=7lD(B~QC@ zh@aUsB%Yqir{XH$%jU!#Ww8@t-fSqR@tX$6Cbg)HwL?1ZoePpJggmY<{a_$oQPGFxvDeVuTKaKGD^CSuT?;$=6b5BJ9EKZY53drf7|an!UlX26srywJ-!^4*1s1R z?LJ=pFGO7AC_lP9X71=eYKZEPfZRFb+mWXQwtR|KtUSG zYor(!t+9i6-!EfL0i#Z7o^`cuID$Hn_*||HLFs=pg_*w_w|ZKM^e76?_59M65zl4Q zP$KZ!V*b#r8_1AWOp4=JK~LjT#1_S*$E!?q5uWd&e=mrVw^su5+Q?6qNihbv%pGgf z(tQYmkA58coEAO80hT0h2tv6xKin$1ZSwdLwgq@W#(od=F^d$?(S7|qSpjC0vaInq<(q)Uhrfv=5dyK~Ubr^ofuw~y8VOpQa0r@uVw|>J( zmrSb>ITd!no4>7o>pO`R!>wipOP=|Zi47z}Mk>&_e#dRMf?q0%g zLw8~U#xWvl_M&0 z5DNP3lDt^&YZCyH4PTR8Ou03Ycy%BEbTa=Nw4I+~`xgdraAks7d*IWy*Jit+kUtIu z{hE#Ycz_L^AW*0RR;w|8-Mle!%vhu6;AY%A>-B9_9SX0X3<$_gmE_6N62?6|HN}y@pNSGJ@1|3HvDJx%HxG?_2GVL|b4*#)OW^x32 zH-r0#PU;OW^P-#uZ{_p6MdDVC0nkd@-QgJ`}D>9_1{QP!F;CXk2VM0=rc+s0ABt)Ddr3= zavUlX#%z*JUmTU!SAsN(SXJc(ut-tkkjk2KCQ*)c$hs8cbcl{*{si=%sir{+t;t@y zL9?PSmb#bMO~kUJHL1+OW3qS^O&f33of4*jS;7`-e;H9Kf{gK!*e2(Mz>DxG!va4D zMEr}nx}dRsGhhKVef1OXltY|R0f;|(`8x`bi&I81z6KeINBSrBqy8&QWY5{?m*bm9;}yW}y*E4gsQXv-48%~H`1ULGxy_h}ko4-_>R zE{J6vLiS4HZbAVsdwOtw#gPSz9j09`FrI{JB7Ti>5h?jD;!!r~4W3tc3=iKCOzizc z5C>BK7bv3I`PRKYN4W?N49F;q0b1eQe*}1ti^K|kjRxjkAgxMbmII&Rz z8+jS^uJ{CaV&iS4dy<26jZy=X&DkNpyK-S&7aKX@Kyy2}@HJS%0a0+s%#SYJX4DD& zUk4Z%tRH+XLHsIO1!rF=;Pe13{Rb)~U>Umta54a`)VrPlPdHFiXCLtA|Cc8Q9h4a* zxxjf}mKnoBEG$&0nid_>UEbTBTU*!!#PQED8{Y#y6iVkP$fMCq_(9cbwcHHIgNKUt z(-^3SWF327b|ZW)hF$0#2kupc6zC*-m|#u!qWt9kH=I0*^a02nO34v1ehoyL-e#2Y zjQ65-RW|&+g+Lsa&SO5OC}*$WXn|H~x|Pym=vASECSe+~GHS|{7L9^? zMs*t?i580A4Q7)gd`tf#J5vqu#`mkSIYh(GYy3s&SRt3PR~bfmP3(i?&~Zakk+j!& zL8;^9t=%Oz-mNZjz!?ijJ<<9(g&X!%JH(~q48_7R#yP%MYq@x2&=t*fhol5dcOlfa z1#AVg`tDzjDcleaJ?n+0d!LviQtj`?OdDnEl|((ujH+-hirNoHx7m8A7^)@6I!pz4 zMn)bSDZK)!ZCz^5Bd&bFTU}jYDO<4OC#Q!U)p*GE_#5nyeDR%bT09E|>$KLV_Dhx$>!<~GFz7nZP22Doxzh@VEVY6lzh^PpX-{bCZ= z(#;r!sy|(E!#V^lZwmDGSt01Iy4fx0F&h$! z3o9n%tGF4$T9einU+up>$L~0Zw3*B))Gt4myUCC@s&zG4Cw{qSQHtNxHyDLBh$Ui7Vmg=mV^^iN== zu-i|2z9>ok$o|VlD~UCY{Cv+3L>&;%RpdK=8mO@~yrDAytd%xzvXhhe#n*TiSR8?| zG~c0jZA&T)4sO?d7W{`*%efb-3I7^Ov+pkyad?4`g*}7-lDEl6&@y1G`@*@V03vkm zHIEHC));v+kNf1+qacrAX*{%0> z`6sx45Ll@;^7$Ejc;e$cLY?ii{(PNs_Y79(6e8y0KZLK?HPqOY1@~)Fs_Yh2vH~N zJiG~jva!OlV$bO&$|x~}DR+&Ar%2R!5neV7L;&B>ZIJ~+BD?=9}t(nmQ0T*Oe zo_`j&s4GuS$c*INhl()u!=Ny)I4}X~4yV+Ki;k~p*{)fms5%fnTF_z1FjiDb%G2pj z|6UFHr0UXUu^i>W_%bYp$oH3Lu@l1NyI+t;Z!cfD5rqP_yMxS=OiiAWd1hNzbY!o8L@3A8ggGvf&9u<9~!Cl7uFA^W%F<3}e>_|w* zWj8f+e%!YD)l4z9@IGM+T)HIK_F_lp zzPPUAj0{F^VwoIhc}lP3PC^;HTw*ZJOLqOC1|nxOwY?ibWVRcEGZXWiQk^*G#mZuO z*XXX?a*Hs_V;o+WI(re?BX>qK81Z|E-;BB1EF(>+TB&4FIIZaU zOth@T8pks$mb(do9fa`)kzP9taiUmn#CYC;{w6(&=j(dUNyip$wA-*-)9^%f%)c;r z0?UCNT)G%o;;7BW8+RMOeKwnwc@ly}v(e0?)4WC`C)R_=+X0pO1j~H}XEBs0(Emfe zMGpy>n+*CkT$*2R$iL9Gy~u>nLzX z8?GuYkUTXLG_Wo|xW+tpemEfw3CK)D9JzYO<~OAET_OuOJ@|}3rVjwJ*yu#TT2)ii zDp{?~G09t*UsfO4P#yj_K)P~Bitrez61Lm8yP?Hwuq=M~zt{-I**KE$3Se3v4u-bf&8t!1?`)>LzY4` z&(L<4)O?bcnt@FJ9cVTQzA)>!wmyT5#kCMOf^3f4Zo@?oIvWI&Ao4_Y zj-9luO$kw_4j|3-`)CKkZ4kLK#+hCwyU99LDSGu3VQvQSY)XJ~_P4h2EYQ)DgwJb~ z!^OIQ4)ROJ{agv{Fl))TmY>+fsifu&?5(yL*lkQbrVU}?u4BqZ2C_&s(`tVRkhd1C z&BWOK$|nX~n4MLaYj}b1>6Tx|KuTYzC71g&PKZDQ-fRuq^Irkp%D!M;?yV$3Jsef# zad8ro+Tnrz@D-b#N8S8tXSL3aIeRyG+L3Ewjcn^fJWMqarLtUESf3yz330O za*~D$k2`bbQRiIumv+n9Oy*I3Nt zPX6fn`;iy&9!v^?@wMX~no6xk%3+EfzQHB;WPo`q$7Ww%!mTD&Ld6;X?*E5K{Kax> zILeKc7Z^`F_)x&mKlr`zIa9JBD*cSG zlI@Kq+}pcH+|@#qA4@8n0QJ$N6y5z!y*-kF6++G?m)s0_dn5iC2|llsG7kCD+{xV}YluP8!s?Ca(!kbW2 zfH`u>HWNfc&j28Ya1jcA6%fD#97z!&|A_RWNPNH=b5agj=+4znaxx%lc4gy+zoXgf z+@C1}#e~N80&{;ZwUM3#bPplo6Rjg6m*Uk!++?W{J2+?>(~J^k616s&bTBq(6oB#R zq|Dk;`v8PM;0kjLDOm33jJ(aa+R0h439_#!uqd*u=t3EE01d`E*`|IKJU>e>ZAnxI zuR-BBe`j$O0SJ9w-GwxQo9%wFW%^LRdPSz>sr4ZSk>75Wtk9LjmZgH=cb3v9?;Fi`o0Fqk+#>V5jtSuzA`aq@h#pkdl)|S!< z?ki<4Hgf&iaWYXdeFD_ex7~a1h+*gOR{G{)D>o0>TsPYxqmY}?Gu9mED@CahbkQs8 znKcZAl~iN`XZIX~d=_v$$;R`(V*1QgY#x4gfZ>Y<;o!_13zYqU*2QiM7-`_~XZBwj0Z;`gK>^dpWb z==uGsLxh`Seaj}fu{q&qH*2K7d6uHuj0O4UDLsgU9j9mr?M0*kiHXi_xrwbi6bvN( zrPNsKJT#O^d!%OZCqutPug$TUi_CFAa@s7oao7n6E!i$bi1oHj=uVP?rO+E=FPnYf zjnKH~)0e`9Yx#zlQ&1z+^uUtC3{Ruj&a4Xxj=BzyBug$08Pm$h(?vE|9ia!|(X7q0 zmGLRTli{P!$EEYzK1rUP87V7;-|X`aKa9^8iM2aGZgrBS6T|QyUrJD?0uKy{6tBP~ z*|u7W&@Rr2&GetqL=0jk!$tWBbZRUTG`Jm(<8$rYL#^TS;D%uZeCj8{1<{wa@P)mC zz@OOSP9{JS|K^Fmd_{3=xw^VG0xKL3lW{?o`5vYPPtnje9+({j6KJobO`eL>8iUif z5GYO3ikfzNJ^$h%3xxNM;Be*_8RT%W z97#b?i^}e!M2H+$|B%{hcwug>No*5e&s;o8dQ@t7Vhnh%1;mAPQ1Olp<1sMWH@N3L zXKzbWxp|QZ7n=Q5q%oFkouiFZz$Dm{@@r4%w+|W*3>JWQhMb55(>Jqd(?192&M)3NN)Uppr9pB^d}q)>s=EA(H(4^a#*2m9`ZH5n{a7=O-8EY^;ST z0)$)Vqb%=Z!uP1~+#jL=EjZ-4)@p$l!8~yBk~lT_Vb4mIm<@f`jte(-aaZTc*lajY zfQ%CLX48p~@Sr1#?XCXG03qB1b2+Li&x{t`yLezCQq482H#K+fh}K|$b-D2OiQzxh zZCy@?O+7wWV=X7M=L?z+@*{Uv36otGh+FqX5vMTBJAa#4?6-Gf);lNsw2cVLgTs=7 z{4ZoO_0L*l^c#W>N4_WeGEeS${kV%$CTS3S>!Lh1>UBg7>pGAjaI0s}j!l>!{G<`# z^&jKS0Ve4KMrpTw!}^NR68+Ovc>C*f8HV=U0`f=(>Ae@2s;JpEgDeNyVD!kr> z@wMX)CZn00Y?EhzZyfk?%#iVLUzwi4aHpdN=f(zuak)AS8ZMZZyG32bWT-zk_XrOY zsL&^&az)p|Hc~CD*ibu;@A(Sq=m#?&4{62>a91JkxCHC(#`NDgl1wxtN%RjF>DWN% zEsEr~VBBMjovZxg`}m9RF5l~WzRY*gQ4--HMSZl`{qFxq<`msvq4*nWsxKW$WoF98rPkRt;0r9LUvCF2o-VK-EDGk;+cVv zpM?&mEa`MjnhKTp*Hb{5z%ZtcB`3_MIXf66u`|;S_$|~8PnfPM_3pA%`MiF8K>(?m zY&l5Fs~olV#=_rm^7G9ge!NS~*iy{Rz$)Zgm1`jf@_4{6EM*S2>6nk5i4S&vs6$Y* z9Up#paX1eEG3@lsOb&}ULK_hS~?KYtUveyV_G2PAxpzVJZYm`A#&;3wlsV-LgW;ZJLngR>%-6wJuU6#|rY~-TS`)e}^b)?^z z?|gNwcc+6Zs$exr!okz+-h24Ut~p2{q6mW#wwMGQePz!RUoN*nhV6g@M>>EV{G-Qg zfd@7NqZ;|r^GV0M+;q(hj(<(t+4m!StUKLvGj|NQba`KAEQF{4qcu%%uH@E~zOwJ? zK=EC2V|E`}p0O>LP=9kUDLCad z0)eTCDmHtU8!8m?7_am0c0(1_G>%VtZI#E-&-|HJVI z@`r6e@-7rX;~-6bkWS5>O0Tw~`S|z-AFkouWlG|{-G0ihGltP>AG*k6fdQp!c=9}U zotq(q=2vjJ(4__`AMo$ftreva&|(OqDCxlT0B<$cn3{prq__3)8`#?fl6X%8TADbf za;E=fOn_4_rL>zi^HyOH2b}S01Mi9Md=v!YWV##;cLlf9&w&kn3E~aPlSY3lM7{=^ zuO1H()1*EYHlzlWHOXbfs49;GH||FyBn^ebBKC^HTmilcl*yWyx9awW4O?@6>6e>F z+{N(|29t5G^f)r$1bcTGPX5wxvH<^sYZOVrOtDt~0yxJ60 z(40&{H}^aBuRCl~{fs7cpgy~m-=!ImNU=Uf2%!=`TgvChr05A4Rg~km+8aqzAE(qS z{xR-j_^m!0cT5r`b)pE`8SrA=RX4CcbO}nX)mAwKJQ9KvX;cT*eHNZ^$$gwwH7~{2 z*GGp#J+97iuJ6}=UGu0b^T;cw((!!&&bToJn62;v|K_9|L`Jkj{$?mr;&bv@2$4M< zX*93wI?(61zFgY~(0g;~r!8q~Bv)#3&Sg*)K?H3tI|r4n`&ztQWQWE+0t7+aGc8x% z#A@KXZpimtepog3S;sAk+AD)_X)A~p+{;#T6Gn$xT98(Jz5R{Md8HqChF8OX=oz{J z??of8MKQDN{o2IIczZ6M8Xm$I1a7;qDhqFOd5d}vve3Fo#hsc$-D#*MBf-fSmLQ!}D&BgZ_%D zOkDa=h}=aNeEApmrO}n@JtqZVLR{IPsUK1Wg#j#$S=Z}|?lr&RX}caGq0wKitL@6_NLiVR%*!$SVRp(K#Ad zAt_0ytip)rW9>O(J79%K>{Hh%WQb%ZTgxT-Ye2FJ7;Qt#;{@gXgs;|=>%p$bI3VBS z_-}9)rSbpAx>xK9DUc82n|mG0>$4mF(e1Vww?~Zi?V&{rY`QYC5Fnp)b0f9-FOKD@ z_m&}3+3S|7Ob0j5`FbjwKjOr;O4Ehp}GV_$MtFl~#}Drzy;SdDv5D_8|R+{)-2oF;`?H6(+!h zTrZYUBn9v)VOEC*esJHQo*CiT0xPfUtf`7*3qLT=OgD%RdogUSuexUnznqXXW|cDM zXMsQ{I(c;xFq=|o1^hPCVPRjaUr08}r-UVhUTV4)iT{SRo_DxTdeB8j4q87Zh?yeE zmA6&{GzhKX@sHhvHFy!;3HVqp^ULF{wC-*(U9lOcW$_W%f_JkOaMx#o}v6@EsTIn>gh|Dmbg zOFD%FHI$hvyU^A`gHl^pBJi_~pT2Pc6o;MIrjEAfe@UbYi0y^Z{Vh^X8Lx2ZC%Eu- zThX1z62cWHLP<_~&@Yh0I@6*O!mGY1act@G5ZH}=4A=x`aL=gK2b*G}APHWJ zj5fk>{PZezNkttt_GU~)`CdjAGY$9Mql5vU>Dqcl(%DVi^1E0D8#FvxZdaC?E`*NQQ-`~L{nWBdq*4(J=w={PEa z@Ujw@qcPQV=lZtsnxGr}1 z%x`Firl;x^6S5{4@v*(sKt77I~C2gN`X1Z`8>C6 zj${s z*8gb62_QJ$R1cP7-0xx}s4++sA{VfVO(VV+IIh^7YDJ;quTe`0#JM7gKX-};W)5IT zV^tXa+b{MDUxb-9_E<%?aDL-s#4{sB`{E|JxdGp^Fj57T(WeCwkxT6qVcX1JB-4PA zd<{+UN#9YMwL14bJ`1va<8<;^sQITB2~}J)>Z|XGcnc4VV9o#uVf^FlS;?*D+6k2U zW`RF*+`bY50fRF<_=IPjUP0=e`m8k>hp&=n@q=fxqd&9*+7&m}zAXc+7Umho)17n$ z#Wj{`3eKGNQVc00Tf3r;c!G%8I_lduvw7R^_uq zo^${LuIov81PjRbh9th#Hw|R&!Tf2W0t$ zdQ0>wyZd#ALL!djydAAcGBRcmET-nH|Am3utcoJgEuv?Jzdgcde+i}&Of5M!Lh5oElqwDs;?_RR8;aDcd`JYle> z{;QD=0aFR(eZ*%EB-WVO;x51M)r}yhLI+g&=_IXJvNQu0S2=Mp0fKdR%8s4)f}X&3 zAjQTXy(oYXZ!S|2b&_m7CuLPDX5@IQ#LEwXbrGhdky)XV$LqHLw=EJIfP$=f&p2nr z{vli!VzWwV6Jcv3y3Jl->pB~2;FgjDq?{=c1Jsp*mZk{TuADTuQBACxoSB0X}9aF2KTWn$`E+vTiSlTM6_-K!oB0kyDWM zY>T;}C#{#9NQ1dj{NV;`oZN@nVM{pivrSX-C!mDPBfV=!7W;5Wh=nW=kk)h*^2eCE z4B?c-+`6A{CVD7X=w&vf*B`I|$i}ve!PV9p7^O(%8duu@jfHdu^T|Z8AJ3(F1<4s1 zR>)MFuZ}T%Luy|v1ZB}ql@QVfRrlY8uL7j)KbDIP4dbb zB7=!I4c6-v^dj$oE*@$gb^hQM?~alJ9tf0e?23~+GYLW4QoYG>#&}}yAm-UH4c=gG zAkgObsIBqnez%~fUmlIkg%hj{EU-XEehD_Z#mQ{c0pOe(dY#+=GhRZM!4uWoX;2wF z++O(MqH#GJp4HWVHlubE0?s&8ax&1U;TWsFub*5v^7(@+Uh&M9&L~tkafXgW?7K-< zvd>~C6edCf=?;noGOdgC0aD>4xWx+!&@}jUn+Ku3vFL0sljf}?nFJ&6yF~$R)H@?S zD&~y~^_XQ32C|SM>j)g_9%xmkt;dFh!D?>%({G)=3SXWF66)HjY*jIb09kSr02j~2 zmn%^dH>a-;tNoV@tF}RHZ-ZnNDnukLX^8QU3^Cmn(0_FmDL`v%WEJTd_Dkg+=aI)5 zyJzFx&HJKva}V14pD`9-G8v3dcnM{xowtvoKw08C0e^A5d%P-9e9yYDpUQ<4E1XURP8OFGVxTaC{8@Je z?hej3MgVNbZ4}2l)Wm*Kr`)PU+M8;$Jf|SS&oSK%n3)Rz=G<}9*Rtgn6KVrEv6naP`?}xW64qtz*JJqgU%{u$RUrpkbFTqA9>pFR%jL}kK12YJovXK z8CLohK>~R9T&{!gUW3j(`{ZrI=Xk7MJe57Iw+Zx($9JCV$@uV^Mk4O+f1=0CsMI$~d4e;Wr5pa0@^Nk!jxT~R z&B2Pan?W=3NWgF3-Rry-!VK&1R#a`XgXqwf4{ur*uEuu;wzFPDe(ZJwVztOEiJ>EX zm@e!=%|JR>7ostiBsxrI4vS)RJ?dvqSr;6%!MeA@_u8!+C67@UV{`{&m*cJQZ79Bq ziH{-B5_?#9!mmE6@|T3p-jL-zmb$xpOT#}Npk9C?b7fWnU`b_2px*OsT5+t?>>Z7p zI zl2XEV55m8^^(OS7enb=*Er?vva>zN17qjD&KFLKY4|^;JArA6bF2fM ziEi!{G7^!$k36hjsIogCGIyH-Pg_c$7U~-U1|6JxK6KCqkXairkVr4|L@)-><3(8u zb$D{|Td-&M+2DGfkT47e-Aq!aX9k>1LFyY@I8ZKo;X&bZS%`}O&%LQmCb#$gkYbyv zQk%-ZH1@l?vu|t>B$W(@>Qnpf5faJOQ`)~*QS9Fx{*@)#0Hkr$N?V;M6D*OgCcs}1 zN8lLXD2J^X+6$5mjx)o0GW3m!6;&(PJKWH*T+6$n1c+U(t}>G{bZjL9G`a-_`HLpzzkso9#nsU*>vu2?ZPx-^n zbg5`DYzsS7?{u=|IAroo0ZhzOV?%?-oamk;x=Li0ku@OYK^r9X5)!Bn9$A&WoHx|? zKG(^*oSFswr)WIU8rB$#J>q8%yh!Yoq4FFF8y@Q4L5nbw|s{yhjd4uBg7bO|fZ^oRkAdp6Y0g9!?7=Jvor3NU9$U&5d-+8_-@rjfRymW8 z`q$BB=2}*IexXuw!YGx}_eHs-iOoa`a*+D-c^U@LhtsR5Udoh)G>H~`C81}SWZYyh z%w(YFDYlv)!5I82Bbv4_eFD)3Ns{UfODMKpauEA5hl%~RN=?5vn-n^Ez?);BKTCmMzR*23F@0|w@OCqd@WpyPzlteyHlF_*R_es!N)`h=w}WDl%-BMdbx z*a{R3hR@tcN|8li2!BD_J0m9oxDs)6M^*8wd34o|7JOrjZ)VN)Z89b}SS}}Af{$4f zAPVk2oLgXbQJ1wcuOBbl?h^-&ExP}AxMSq79@ zq~2|8RmI~yMgK5XA$R9}Qej733Waf?$ zgYsK9sD!TeGE0Usm^-TEE?NsC8Udo;51{T<6<&efku?nrx|r$MiCHHqhYMvQr3Ccl zsLI`we3Ot)om$+4JqHD)yPM!lt*lECoKom7w>u#N_9zsUk~P1XjwZ0YpE?OP@U&$V z2m}~y58zLt(EjgnWfcQx9J!lbP9RJV#xw2+&j}(5p`|kr4@08Z#87I)x(kp47!RN& zD?Zu3q^;Nr3iraMkgbcci#v(bW0iFZjxpK}y%2Jy{O_B;XmW_sm~Yf1ilxa2ms2Wr z(p!1pIKCT)A*OEB<&1*I{8!&c zg{yAkA1<9ed$~TOwq&LfUoMt&Pw&{}&%T~pa%tD0AZ;v{;jNGhKK=d)=bQmnknXe3 zHE`WT{!`}3aNchVyq*h({|f)?&vTl1bUen%9iPeMFJ(!S^KuAOaX7dCu(&zE4c)!W z$HW-t5e;k$MfqF-A}PTVzjThQckw{yw+$BF{?G(JopU^zZs1t4A#|xz99dW_ACd7N z)-UH4S1?C`no@^6&ur2l6vmr|ifK(5Ne4V3!X*i-RZg5~MD9CkaJC65)~e!B(w%q} zp{9|J`1^A|MlqhywlkoPUI{+Nw0+l!LSHdh4AGNPGajP8P~@&(0h^{w2^!xJ12~C- zp2>U1CNIk<)8e+o5~bz{@u(*alwqiQZwF!hmRWG2<{5kqT}ROeeA)XEnZhSVF@LqJ z96NR|SN{D`%$LIdHJxE;_PH)$r?PFz>1C+MlboU+!+!DEf&?WNEH_q`JJ-y6y>E9> z8AUE)V`tzf+9rtlNzLqKV0;|1Kq6}7d~P86!|8n`3IG2SVWmtGuk!R{bk!>0LW~HH z^bR1mZ*cip`|h7`^%p-v?D}MJVAK=120tkt6{}$oUdx>}l^7%?#=xuwvz&SR$ zHXzM+Zt<}|1Zrx_*Ran4D+lG}Sab|klZYV?S(07J{m9+-qtujSTW!sCcR2Gy%S>bS zh66Z{M5qnr+2QYp&UVd|72GBwAlj7`OWZObV=Y@-kAaQV@k+k4QaB9aIUD7u`fGX~ z%k%GR5{^#BF?jbnJ-(&~$7O;7b&W%y9IPp@2td7GY*YWpouOEfzi^$>6EV~#xqP8> z!X9C`QL1ao$V6CVoG>C4?n)~YNk~+?T^ykPohsYbh`&+LdJ>zF7AS$Qrb2XFDXL_! z`;xDABs^|YPEAe+wOhwyu`vwYCy>D zt(_&7BnKS`<7AxvRaONN@^o!M|E$lBSi0-Helr0{-dHwgqazuYd(v`k`UVhyPFr`8 zysigxy(fzl0KvtbE&0#eG5(>MFs- z9=TZUF$8*BL0*Q3Ag~**^18M&`3V<;=lAf&QVYru2_kj0J{f3Q;}vxR6ZJw2#~oFg zBQ67|@Ak+clD)Mb$yNycDE<(=d5WBJsPhJn!!_gWrr+l147O4U6K9yuYaqfO0)Q@e zhC3%C;a8zxc$0WjvIC}+=f@ClOfLeFalH15AXr=!%uhrJpcs=zx6SiGoddjWR#rfD zpSPxbM)oKx5i|gm))6|H9LhOyI$O$))HN3a!S&(^UMCtaQLE648A%E~6YpHIspW9% zce<$)+j+m&xw)K1M588-&Cx#Tk6`2(U0=2bF5I*b1~^k99s7ZO37jY;r^a}NTW-2N z6VxHi#53F1IasCanpAJRD&aXcr9>bL>#5+MBo-^DAZ`IM6x*{fMm2_sQ4V@U_Qzn3 z!KRrVM{n%}=jF)KVDqOHc%1kMN>+6yD<&xHi!$9Pqs?0A446%n z!>UYSDdt6nO1ub~a6%9ig&0mL4;czbKZfAYJX82EmzVRpehf@~9RpH8NJ_iL+U$b| zB6r^A8#DIC_GnxTAzCB>?IluUblPLP&@2rbLHq&xUsgR#7vJY9vI%F6^_NU#VSufL zU&Hh=$Cq{?RK6npA=wBDnr6ZfY92!I>l7W@xkLCRB;*T6#j}5y&qKI;w$X6xFhOigN5A8w>5mYhDP5VTTbccg3uKT@yNOVl3cx51Gj-Q-&|!5)s1_q$zSY z8$XWwSkr_SGZqSJ@=LCBj1{dhc9|``+p}5~2Cj|`>eaOz?N&B(ic19)3$J8&1sWqh z1y13!$zUkbltpHifYyB!x1IgWoiuy{C+q6=2T)r3n1y38 z`*LO%Mbzp%CWgyl{CKKH>FK&m;fZIH3OJArPgf}FVeQAJuL&mPLZSUMz9spLBoF1y zYSdDF%rNLOt|Bj$3=SJto`k zq8Y;83n@L5{kO%hm4w5f2M9?EoF5s@8QjeflM*=mfeL@#P6ak}(yR{gEU-`~oL+^= zQf4y*-dsp=d&0h*Z8=c`SGP1%-Oa%kr8S$znQmN;^Q=fik{Tq_CIhXRPLC2)L5sm& zyej9j)lk+Qc{UId1%cQ;0j8)VOvnm`{lCYik>YW6PhR#&5?#Q4;1YMZSRov-^nTJ^ z)fEZQ=?~ouHKry@#(!MN(DuOz7!G&AW$pJX({Ok#fo{_kg#Vu6+SwyFKJkJc!PNN% zyB*j8sd!E`KlU*i4pzv}TWArPt+sBh+teA&zH@u;|9JBX2Cxa=AuWjgyJ%Gah?(sP zNo26vl>#pfHzyyHp?CuIHlM7tr+x*mSi(pFPqb=7c}c<^;86D;(i5ZY@L4qs*#t7q zxIB4@6==Fk)_9I7KLRNH!;$eS!#=5~Py%6a0CUS`(+9b&k_jwPBr2r|@DhMjFs*Cr z6QVLjNG}iqPz;822ynLw?Hb&|KeKEe0iPf#Asx9YP#q;Y2%8KRMhNh%UNw@XwH)&j zz3)B5N~N~32yHfOz@tps@qd<{Rw?Yg%?#STbWLYT5@{k0c-gRmy|(l5BNia^Gtk<6 zR_V8$12Dy+NRhH25cj`A#!X7{i0|JJ?2)ItPqe}qSn81if2Qqa4h{jjf+ZdSez%by z&EW`f6mAYH?W+u_17)O+8U)bcx7By3^P89z2ufO%bq-HZn80>+#4a|L5oK1VoAlyk zE3MjF%Ym5dISh}H8354saToS>Fl(|891?qFYLf?b2OPHr`LUH&cFC$8*U8Jn#NG6U zg7MKAIzEa#&ao6Fb+AhC8h@J^Sy^cb?c@mfPiSu2H~>jM@smr?s^~+vJCdcZtH0a) z_s^mWIP>K6E}Y@djs~y+LDuM`h+LC+l-(km*r;~zSqvVNB%`Gt(Xw{S3el?sRds(< z3};5B1EP?vna>x9Q5HQ&b~t!^ob?unnrg^I zYMD3kXa9c&!BVN(uZowl#znZC^vSn&+j1cXdM>ke2DG? zuH886Qpog%{Qa=Xm`pSJKe&8lrF5mHW2rc#rK;Go%d@wu+Qf~E3bzz=u#b5IbDF?; z%sns$r?n}U7Yeb*j=CrCnfHyjoKN1YOB+tJJ(JuyYdLq23{QLqd7w-Xj*q4tjDF=$ zT_k+^7m-BS>2I((S&*(>IASc|(*={ojq#aj`Wn~J!B2|pVF-T*`6(SJsedIi#FLeX z9N>nF+tqT&Qx*aSyW<)wv7C(PLH92o3q=+qkK>W$2C4)Y6J0%x(u1-Ge0Mf?93M=+ z=Zc5NliKkJF%iIDc&z0pS4bMyRkxw+Y<7fe{4dlDc+{Y#JQmz@qu>vtWnGe6qbW906-N%&cIzz` z1Lgk6o4qksbUNa1Tg~ivGZML{Xpo-(MI-Z&C_0s%7rw;e1^2TwO-T(V(lg|x7oeDf zHm}+xHKl>aMjj{Zg3jWYr4u*-BTBu$^YiUJRI3J-W_7ga+G4PQ(vwf>u|8O=z8mu(-4z$vPNmagTe**R&6FK(1#x?>+~YR4{f9pM~6%I9@MB_ndlw>h44Weofl6<86@ zP$C*iOzFci-Hj!)5Wl)EKfj*R)cU3`s4&|2gKCPykpN7#-<{sACa5Dy>_G zhnN5;1D64EcFUm^`mos$@Be*)1;99LporD+3agrbIt7Ckxr^S=si{%i^?x{M;@GZU z(}RKiorwv03xIBbQd!ICnz??`1U7=Fe{gk3h@4Cl&s#5uOovzuf%2-je~RD_h?S1R zT_T)?x=84jdGl{+{9>O4tW0RUEG+lu9JIw0%IzIZ=*_E`)@gVa`utiUR)L8bY3YZE zy<22XN6pg!P=_KY_t4m+34FsE?((G&lA(pQ3{MbZI|d0gMpX=sgk`W%@c#x6{0fes z!qt6I3#7k$H4iUni49+SG?Zl*5Gd%Q9j31}>odvH4c~(pEegjGd4k~N?r9tTh>qT7 z6db!Z70HmFWbrCH*#z$d7s%mEaFO#I>-Ifaa=r(Spi`s2ihOt@|L6 z+Fp5(XIaG==%j}i%?*XLQ$P;Iysuyv4MMhO255F$2du|W?WP<~(z0Ly>d=LT&;R(O zI1&wUgFONe!&9kM48yyWCcWh5b;t={M;Un~K1C!?Fl2gpmQvWD)OkMP)^ zg)+hu^&LPc@8Hhb0v$V3B$wnU|JDew=cnG5EKIr+EyT0ANCZv1zK;^5?6TMU{Ljh; zHm;I|w%f!68(7c^Ul=}0cl|}ydOHS*U#mw&qYq^C4 zoaMrUS>GuN&rQ%~1=sPYCa}%PoR%trr3fcw@;PBFw2a7^>bW1qRyBdPTS zzg-7Ht|~&7>|sa^UsJHf`IKGR1%o4~P ziOE#JH}fu=O~f2D3{{PrAS+&4^^~M*Nu{O(LHfL$5kB%}!|_pH-!vRoJ+tHy&F_vT z?^0S{PuzwW`XNo6NLq#4Nx~${=*5}~J9jS$_{@2nDdVgmy}4VlH=`*K$h8#MW+{CEE4E7^$f&YkX@q(9Y5+q<^TY|LiRKKnT(UGp*Flw&Ekz<7 z4Vn4oldh#10Gl@)7B7$Fy(VZpYaFapM!V9Nq~UfGd8v4YWmB)mw8n4=9H(-s91qp% zhprxBY|C@L8;-8hGF68jp>rZbyr9+Vka1)>z^SUy+$ZBAfg?a@n z35|;*uHHSCQy~P&#&?Zg|NNmma??0}CO$U!gSW62*-f2sH>(RamY<3Z;2A4bdUpFX zM)NVt_NZ{Pz!mj#x+x|GHC`t9j>n~E)L#JwgcuRFNg=F^wRgQzMvJXnU4aq{cV;uM zLj)qvp|)gZTO%_BkBPgOaxn(HdO$D_j@0tbfU0;#UOEH-<^1zEnB4WE0Yuf};doozf@v(>M)E)1flGO% z%xdu8ut)t-E3C=n+z>ngPw`43$Sm?arBqYO#WqSKP_JC1__Es<$;p}5T$ED7yAo2U zRqw)^)kZY8YLRgR?oDn}#L!9J*GOPzYXuu1R_?q$Rt?cGH&1C)P-@z=UE4guBm}CE zcPBTh1|-D{NfpgE1)0#5A`l{yKO+e`CtRx3Tczd*j7bhcCx$yPk6MHlI966n1O|vf z;J)DsChDSCZJX^nxl177l9B*KOCp`1M9t3fp2X+I(i!;@>d#Kn_}vu3KDW!9_1S?A z>EUQJ56v4j#cgn?4X*5|z#)LF;ZxhJ7^pu1@c(bNCJLS9us@vS{^>?_y6lAkmc+Fi z0$(Yx5WG|2|DK-wIxe1yOgq=RU>S&VpFt48Gj;(VQiboS<;LexSQ)JX!qx_Ps`OD` zM-;yj>gEJW><^5)dN}K7h77YJ0(Oz9POCSOS+T6;kccC&8N&@hb zF*wYNUDMrH`Dh1`2YMyGYys;cY@JwA5^>f5<;a#^hia$Do_gRzfIj){XArcI$g)~`*spmRK_kPRL?qo92IP_J4D)2Tuqf9Z zO9Zq-bthih483M4XrIN&UYQLdcR7a-F##mksk0+2yRtSS_y6m(VLY~ub-{oHt@|Ev zp;YGwL}%N|iQk~!#AB9A_^QYQQH8$BW__dZ55YVcm=ipFBuAUONtVtnY9y|_x6FAw z>FjrCl4|0Y0$yah9;EUDUKY$v@HT{QdSb3x(9;4!aQVhk=dbjJ|5eBWAS}YvtsG1? zJ`5(s0#;qvYzHt8bHjM$S%TD>R#SPBS|SMUU2t(!8D?dbptF9#=zr`Hrjjg>p%g~t z4=I`80a_CUkZs5}-;TgW4}qz%>M9I2sEzsoyU?^)~a0sHBVQpwM3w z=_(ir%#>116)B86_xEdoL~qpvcamfhfl%!ePW{w={w6Y?@mwCzaM=NSiuQ?ytwiyDF96q zOci@Wx;EE%dgzp;9EFbf3&gG2!E@fddxbB+0->#XVjZjRFnmEQ7RgwHd=e zRK)(qulj2?k54st2xD&{l6I9sf?QpIF* zu9=MBHiEp!7%loKib^686&CcWpfQC}24t*DbvE_^L&*>luDE#~XA}T?b159nAZaVF zQx#AkQS$>2lqHr9ql4M?0B<$jsqVJ+YA-wMzV{$n-nmU%X+r_iZzQGd8wOHYfs>mg zNFlj4H<4Ea@<7gC7S?@yC&SmU4KbRkjn9uHt%$Hk0RrujM+UsOS*n zjg=_|_7AlvR{J1rYJtEQ^9yA_)_oMJ&_Cw zL|jyqUSwpyU+)c|Nb+^QMVFEVb&ZEgUbExp`+lA!}i$d(N^I*^Pg7l-){?+7Mft6lR+M@k0e4n?L7x-v@ZD zY}G>0uC%`FQ094x$Khx4jaR3@bQCUv&T>^oB+SpTQLa@1oNbFQ+M^74{mk~e@Bvce z`W*77Z}Bi-H&)tQvWqC3^=J%!1QYNY8|$;9H*4<)LMWNY0()z_pm~uq^+lghPIxYr z;i#wsFTcrwrltz8awu}l2(!XCobUc^a2ps7B4|I&^Dnbt##}P=!_KyAmPeGttGy-t zB`d)dm$ySVOQy0tRz26zj<5cNi|)k~V!>(xK|-~o_w`Ns8fx%Pe$bjK2s8DLw)2+( z-hC<~W8;}z9L3p4;8ya)GFJi`s8lYGYp zs_b z-A)^dCguBH>j>}h9vh}X{>jLg4NFr39`E6v!rlelMkPo~Ku?$%@NK|@viD-QOnCK( z^h)k$RYjZ#wW*`8mC>ugp}pOBWv}bjU^62_)(U3&sxz(%nfH#ab<6__PjaH0P|P*E ze#6o|_d||BY2c`jSC_o@-spgOcEIy-60?r9rW_!I4;e8op%d|ni)=TEPHn@(=4{7 zgj()Sx!J5X*ZbLLi?2@sma;!3wYk&=baRo9O17p7f6DMfvEC%66kI$+ir)t7%%ulq z{AB_gJ13ppiQ;)O)wJs3u)+csWZf<{w~?Q7$!pl)6f1(e6Rrt2IbAvlyZx4Le%y^8 zyPhq;%Z&FG(WlVtyEMoT$w>wmH<^r&svZ5#zZ!?gT8ObJX_IGN@1K>U${)=a^fEDY ztR4B$JR%uz_|&ToZh}i(s%IjWC=0mTpVKo6!0Xz-ON=!4$Fp{k;r*b{GL=FNZ1NmV zj>I5Z;`B5Tv3)iF%9GZdJ7Z+TH@nA>J#d2~MPp@!c`c<*jzB&axH10(azViaN#2-t z3zR7pU^T8G+11=dR9XXrbF(5YOi=1i`!(+Qgg(|TF!rNF8XjO8`RzxsFeHeFUbNd4 zgD>_b%1!Hk?mwQc4l2K^ATYLB{}~zndT)!5rSdr?Os_?CUi+zE4eBo#MTs>L$_}py zv6WqYO4S&b4Go6dZmZ}g2t5)9^kSt`TqH;8UGc}$>zk4o{R3{sHKw5ozS#4~tT7_D zgjv3|gklW;r9G5kbjA1MSnVdg$ux~aa$S?me<36`S&d#nAX0o4CIhV6)FeF4#jt2x zQnjP|S|S(U%F@qS1J)t~<9dgRyQ>;wVdrcL;Ta_Q)V^~LO=!ou1Rl`($|e;J!KuZo zsv~48s-Sl15xo4@^3$f=XgqP;F?q&o|8PI`{`|`gANy?hZTZ&ZeeCDV`WoU$PY(XT z7V^rxgJVfG5ZIwLs||VzNz-f8OgP-ys>a|6ggwSdd$Qu5!J+4e$2QGCfke2zw)W(n@61}uu@q&TB#1uOu z24d7yF<_Fc>#y8@v?t3GxNB%p}*!?M&FR7zO2`=ko)_+HPKZxETOzlE@-mANE;cS=9VfY_CMAv{TkZQ&1akvhyOkMX!8Zn4{ z4E{0P5i;;nijC=w(?*#;#K0oa?Rm#W;$)rGOe&(u+q|GqEtcF|ufxQRCIbj&5;~>} zKe~IL63X=&ek1X#O^C%rGx{~Zw}`m9No~q5+@eKU3egu5&V$@#xyr{r24mSJg#~S3 zQ0<+c9CdPXIp4>J%hlC5hTIw%zWll(-+CgRFA^bD0M!B-SwNW55N&6b_Tk=1E2#u^ z^KqWBF`!Sx0Dx#s^hFpaxdrR=R2f;ms;wn?2xZ?I`K6k^Z6w$jh{d9ogw7>^&)3Bw)Ugf<))d`hMvx7VO5 zk0q7GNQ}G{==t$Q?d!z16J0KS(og`N+{+MN5)H}Go^Oorl`s2jWcT+^aLOV!mMy!h z^~NU{TV-)|Sr=OG$aegmsf>A=P+TU01bRv(PV9qa$(%IEWK3W6BLT4M`YQ_YCYbcvqW%3Ma27zNAEpX@FE+P#P6q(O)uY zp&z$3u8wlL>wt5uA4-WJ1H$5;js4xbQyjU*sqA=X^gS3A8X`^`67ofSzc{V}b@mc9 zW}!u1ikmI~qYYW73x@E>(|>#v1GAm8;3%OhczJ>qQqPfu)=+V25x`O;{FOj>aH_^$C+rkVC&c`cs zGC3#$3W2?08T^!~Y!yh(i(e{_5A&^))W-Onv{D$zo5s5l0iO z6VZ?25JNhxcaH=WBn)Uk_L4Yy=3KKHREk&|32t+NLw0xtEo(3HZDW>P&lmD{0r6g@ zkF(o-+t}w}(sNolskyv5K15L8eIWQay_~_a#&LIwca7et<27uuW^*@Gj+YT_zsu0t*VU(xe`2{|mWL;X8Gp z)sZm7m$+^jY(8@3XYv>do$&#Uo;9y`I_#28dZ`12as;>m<~cKeG<7{c8b< zzMmFPdM77Hq9h_Sw2PXHAmWAwXMu3NsppFS6>RY`mx|lN-N~Y|eYJFAy|pkvc8e1) z6}xp#d7jJCRI58u<*s4`lz+1qBuQx-0{-B_{@=T1I2VFQ_~$a+EzZ2dl?h$R!P_|= zLO~(&GLjTs2dp}5S80$?5v1KL7dTokcN0)v58BnGy1>3-D7KuHiRhTpKER$W@FDsu zkTQWMx-df~LD%YQno)@=3HA9QjA|r`6o0Xhb;fD$R{BgvnzjBFA|h(yW1S_dF2Nqg zz-CEyH_{M}Ek0cZ~2~Z zHUA8<3Kfrq)t)|Z94|W8UC7dmB!B}u=t8C2$*+JXdl|n@(y=skEwj;8qPZ>(U;-q| z0i2G2-NDMOV4-rhZn92;?;s6#14}*@yY5Yu=_#ebq;pm|b2E)1=cQ)-y)`do5y2&{ zxxo_L`pSv*vKAE@>b>WB&w|1qKrDqCZxaJ~FA~K~jY3f)QDHvZj%;iG5&10|VJSlU zCTt!vA@XQu*K`!Zr%`_}MB2}X#8Lg&*Xbmd@#s&io zGtwn5AA1;LZ14*Q@9DG@Ly+GCv``SgPf=6*6QzxPnSAy^)r|31RcC zFAg!BHWIrPr5ZF;SwBQ_V}tMpLR>CcQn6O1;Y!Z17ffJ2C_-xi9HO%Z@jN8enhVX+ z+r?{*IDvPB;F?;YB5I^Bg2R)XUFLx--}@5R2cf{bt&*LSR39-q~hNqsje^vN)1=wdIA(6HYH8*r({jCe@M~W_u$Q&M=WD2^kXr-4_8< zM9Z(xN9AqH17=|rQ;-}kM|iCv85x8v?nP2&$5)O`y^rL|=OcAP1%9^MYn~bp?DV+*fJ?Y%qic{nnyvq(=R?W&hE$!E|4OFt zAhM;KqE=q{NWfpq6zy}sDuHXM(mSBwBbNtq_$||;DuwR-k||i@JIc5D$X*~fE=dq} zWs+>lg)57i6Ud#ynn_8f=sJJYA_=#69D|yOh1Y%6GDgoK>+L)K>}A>*joics1RV$B z0gb$C5YXSRbb0lY8NRg>zTs{f^>(0i3VISsnMdq=I40Y`rPbRNQJ#b&*Q#hgV~;(f z7LPOeK9@1s>2`bw1h8IkzwWMq7%!0PpPoJD>NOF=YCWY|7Yp73T%%Y`$7UTd7M2vP z_KjHg)^QNm&e3tJlT5jD@tk1GxG`ZyhE>Eb;hKP`=>r1>P`|2{6QQdu6}I+i#$N2@ zSxuO3O-tQl^^GvtWSG0JhkxI2Dqnv`kg|YSzT=JYpImRt5czh)42gV*lBVU)dy%oV66l`uB3ENTM*$ph@4ABH zo^tINhiCbWcxX)~m)Z*?0-C*;CKJ#+ij{D*X{Eme2bBFkPF`l_=odBBa%n?@JA%>g z*VuRDm8ipMRkz={TR&|4?}lI3mY<^GeqxHb1)^AV3+v^8P6GR*IGAFxjvgfE%e>>) zj#O{7mCF8_@PX<}tHayyKf%dQeUU}i2*STlhp`II0WCGY=DpCU8u&vmM4$W9i<#?f zSi$Ko{BOmVn1&oee9Ub)d2KLB0k%0rh?4=Ju_BkHVP!mG30(@ePxQp{m0Kb5N1fsP zHTFa&q~pt;h_zrTO*3ER3toT8{nKK-(HmKyZ-ro(IZMPSx#GgTz%XH_s}ftf8kGOb zU$`E9m5J#?6+w1o0yT^9dU=rCwOh(1o`NsJ!NL!Q=wFJQ7WyUDvFgpkK1#QgDt&tc z6c2o3rZhDF5dQN-j9(I5i0E5_h%WxjurFt!Gk1*bpUFXwjzGjX<|F9MFJ^2$j|x6s zJ~~F)2wQ{)oyoJO8H2QJ$O$-zxla30XkKbR_|7{3*ls(DnCxA(6$=9qj0IwYL{0?0scgUoY~QO0|_sz2I& z-DMJs`JLyhho|{@p=^YVnS_Px-- zPuQUc+PE&^FvsrJ@myDKLxt^P2k&F!d%7BE2AJoHu3W9)!pB=;8ukUJ*wv-p51Eb= z@o}AvsA-lOOpV>#%9y}d#x^dzyqI)x4^?WWe-|gAWOKSQSKzh3kkGFvDkk=bwZYU7 zj+*isouI=Pdn3l;76sW3rClIgR0}OykUemi$4MWbfswf36`ll(Lm!cq0MXWbVN}A@e6T>R<SC+b=e*yM&o`@2-w9+KxQ>T{U_--2~%So@B z%KSHD(x#904k!|c$n??+b|u!}b-Ju+37+PYNQ2%cznMep8U2?Dz`*Sd%vc0ASdfUZ zY0$KlArzZAe~#jxNQA0BdP=N%v=jL*9teaso3W@o4hYNw0wUP#XK6iTq^;wdqAc=? zaJo_El3;lDgVl>!zs>PK5N#_KLmb^@YdcLS3^j=j>CiZ0s}76=UQN^yD?-nJWd$jb z)SMg;4-O`r5G+&l>Bv|&-{;GVi18Xj235ubK^bqH^Mo5~N*kRm_&nLnC95?-Hxni8 zi;J7c_wjw(o0;l3=symy3ifYV0(8pHFt62woMicTlc$uy?xa}fBc5g zzB!rC4{c>MS=TvB z2X3Sc#b+#fy5{({!fvH-mnW!nB8cLu1h5|fAGF(5ww3m`F(p*2jC^4F0o`Yd~?#U?+>}dCJ*C@tFTC~3jowsd2MWp%8Hrb26+w8n;b7k zp3DcyqPPeXvOcmn9)Hzzx^m#|Xcu(XIs!r0s?Sh4q9vwhQS)*#eGg<(Bst!y4Bzc2f2;ut4Za%e;yx@{ z7B{zKy&}S~ZAb8K{F_vOKO`G?RZe4ECWy+c6>yJ^#gu0ue{K68`f!{ zG_4H6uFA

ZHz7r$Xa7vf-n!`&GB-9f8-11+6`HfGVu1qFt@XB0y40%4!VG@|Rc zStI6_jYpFdf3nq^0q8c^{&Cxi)G*Z$amR{VrF;3L@jUjnc*S`H{7;OzS{u{k<>O|8Y|A&8PC>Zbienk&fp@ehQqOvhT@XK z0wiu07P67A&6Vgxk6bz)$niqsg?h#uT*wRe%0#EaNfItZFasL#{$5TR$V>797rzKI zbChfgeALd@)(%?@NBn$sG~^dbC+pJQXcD8HBRkLh-z)|03jcv%Sow4X3)_PpzX;c^ zM4Kq=g(!OXQS29<{PEQcw-D@99KtyQEyVq>{!lmV!uwNVcSv^25gV1}c;kHA>ZYG2 z@XQc(F`4P-lmJ@ef}t#LoW>L^4`e&|sose&b>?dUb!{)17sA8*kHftGNS=u^Ag_k=Zf(Gp7&BSxU5@7zLTqATvx4%Yn=XHQK0 z5ot!MT}mQ~#|;IZY;Zz>(c=$@x{O%>0VwO~3tM?J>}f+OwfO5}>JF05_3$W-@c#_O zz~y=h1^k1}53NI|1so$m{lYQ|#1~#17{uJ-R!={vtuWZp^LR$BTz1z~kq6<8Z#SYO zG&`WW2w!*ji^~42jEEI+!<8j;7pQP!^8T#BSH0a!V#bz9*JW4e?rx4&Md34L-O$1l08!OkZ*3WS&~>% z#CirCwCsic1s*A1N{dUB41d~-%b+1gENSbBQnTH$U1{TFeD~q}PMa^!S29K&m-+QR z6RF%z6kBc~lAq;1R>!M7Be2+gANpbZ^H+cQd8eEd_ZQj7?BMSgE%xt8X{HB6>}bNm z7foI17-aqNHP%2G0KmVhMbd0a>e1ft>4S6V6K-&vN#GN?EKY2g{VE zZ;j!<+=p-*SxVoD49hRblXQdR_=YzlwV-}|@Nsq+{kO=bI4~;ES1xU-vuc0?OwOc&+MB!%5iw!H9A6o+Q)j=U75IJ+8>n;^XzE!BCLE%LLe7@D z)SlS9rpsXd*uECc?!|*+6}USy`eg9dg@Qq;5Ef*Lzi0U0PVeMS$?y?7{rihNrNXpO z6B)$pK@>WkWe)}p*ETM->P?bFzbL~m3=J`@8*TK9vaEm;lzSVL7Ha7^*#dSi zzsggWrbvZif%Q@vpeic4%C#nU4J(tX`P%XGRn6P-tcx|Z?lpNvkn9e`w@Z{#&2 z;g66dCB#l9HmT~P6N6>HF+x7ma7|S^W`3mkB52=2j_K7zsRIMnnw?=8!^=mJ4N~9~ zFeIWRrt4NY48i1wi`{@SNxXnDbBx19iC~iand!WF!eig+PvO8)J<}sxnG1J=XKD!k z%+cz07Qr!UG?MR^;wy~%R)zEtr3&`{piBQ&#pmI7V z7foW4K0pya2sSv?7~X%1ofO;kZVe`QfA+C)ensyly$9S#)?bWi*!yYPmAx$`5x8xO zE`4--ullu!zgtZGF%0Q6}lx3X5m2R}eg0tpx1`P**xQyry13Md2eXk$RIaz|-P#9dZxGVTa4?UjikA|UhogE+V z7>@J8M297T(eSd<+1b(cH^&t`n4Y@?H6_wue3d_i@G8vF3J5HQW{s&=}}K_ej0b|k6f$xZ#sJN)a5!%)1-V*|&!WfTdy$TX`dzD_*J#77tX#WqJgkTD zEHwmUlu$IN0tpz_CE$K3ONMer0q9_2a2vY9K5ursd9fDaAs7bZM^j^9r=hxogcp7Q z(*^oUm!CP4jC%4|Nxdi$hchn%U{Hh^sryF@B}2ITuhDP-EO z47G%uzHVwN9as2TG;?Q$2{}CTMh^7u$N}_P**#`Z*2U!5FW9}7Fmn&!>!RIb7=7i$ zx&G6B_b~f(I}WmfLk<|c;0zV~oBW_7blut!fB2k*5e-xoBQE-><>SY{7BS_J$V9RK zJ6&=S`GxbJZze~FJZ)s!C*h%M0c#$)Qg4d%BIZ=9f`Ege*(wY;1cj6rfg(bWVA>i) zxZ#w$&a!KMlUqxt(Zu#c^$gCXgXXMgV+2UWp=xP0>QRW35&fmumBa}-7PEp+=Y{Rk zB@@`|67*ZIMGP|AY=2BNGo!jADH>!m3j6oJpAm@s6Gv$FpL|M;Po)RYpKie%b5}H* zIP@P{T8g!*t%UA!d(-QD@NyAOQ`F|)5{EGu15gn0?=unUCpc)6_)M|tIowNUMqPm9 zwd{xFrKq2}$^MEpUY)FBfBQ0I&wN1M3E0G`i$QGxc{xLn!SXRp(C+<=<)5s8gUSAL z#cVpwQ7a^t^P-)A0hXdukXC&b3aIg|r$rBYi)FJ6Ieu?_%`I@n9t7zPzZ1lm*n zz9}wt?h7S!?%u_p3AdZ9uCnDSYRt9P=A{#u(Wou%t40B9W$_IRQ}=EaYu+%fg+P}> z6hU;ijjH!!2x;`&SyzNF7n6=x>9l046s^4=R!tVt>@tB8JD2hHR#i@VD$4*0J6Bo8 zs&OW^3)|b;8Kg`fbnHX4iUCuMkN4kxPc|&65cuc@B|ic*6SWEEJ(-9Y6G;RKCOfaj z0AGHr3CEQ57|A*qdYF~)7r%QheS7aa;cb!ij1Dbr{1L!zdRZ@~W~>gB$rGww7nS-C z2FLdGk4jF;mRA4jmHER4I5C(`QTf1A%A2`Nn>}+(+)XI18? z{sr)RFRW;|oS_&b4i>*1$23&ThWq7}u#TP4Lj{gcByi>v1u2*S5Rph4X$CeT$@GO5 zeQL}Bj|3PEZ!20ad=5cpXmsdlm-R*s$zM`a zcC!6Gydq5oi4rzT6;r0B{W+OSGqt7|RUl*v82aXms$-Bdy|NAi?R3fd@%oK)fmpfB z3T6g~Gws066=6Whr0s705_1i^Zxb`cj5!<87J)VL%w_$vxFgP_)J(kBc#-Q(7kQW0 zAzaiH7i@oO%^f=M)ci3dv`+sD$E_~F#;Lq@)&J)=!;rhXYh{3@esVOg)x2rRf1nJ% z3Ez_CkAyzN4qbdA)*)cP>e0jECCJaX;k@hrQbgh%Jrj3%@q;xd82o$K*4Ych60?&R zru=%_QO%xb31OU*s^gKX$};+^ipV^GrVi>?VBv~L7=jj?U)PZ4@x{0l5!0_dWu4e+ zG;i4#MI>5#XSmjLDEM#lLEMi!*Ljx&@Ch{`DiSoV%$Pcwa}2qd8Ks~E-p?vn325%B zz4;ViL1{IejWpy@2KrZTMQ7<}yU{&?P%V2hvmKmEbU*tV3VwC?gMGv!AjR7l!>_J; zeL~6|oCD6$KlUf?BZcWe9Xl9fMj=>KGOP{kCo)Ba4LJP~F5<9YoS(0M&_oQbw2QS_ zIgbot(}jfv&`IqosCT8@KbUwl;}F0X=3{`i4iyC25B?{PZ(3$AkENzsdjsCDgU7Gl zm@vGMbk`A%gM}CfTR<{ZNLK_1jzE7q6m>D)X#|l6YwXN?Hi$IdL0evU?rwnE#r$A) zoe=V_2lvcqKb#HqmH_o%e3q=B5BhhBZncE1rHJx?-pEPOBU=QrmtG_secT`mR(z^* zsYHj($ez=bGsO0jy%M?a5mr=1G6_lU4#xU-?!ueaHuE!)HXVjBx{zlfY1LLEHH7LG zCoEPkUG1cI801=d1NQ5rfuckP9OWbNe^_=aFxo$pR)W_-+?zqe;A8(GRLKjVbX^gm zR4b`8{nd?r4Ds?s!m}soE;^W&;n233Y?d;>g&g7Yz;If8zB8^7nMU*S@VqKrZh7s;Fx zLZXVAa==#@oI-=yGo!jGA)U7ewWsFyZ9R=Ziz~2>7klPWpdvM13V2&1DYp=qeHktO z<~7X{xF5V(qnKFrWpitK*Cs2{EXsR{J5Q8^#Pa7e99i@&55K+=G=>P28<|Z^0gg+z=bXKp4r4v(gTJN%?D!vEj#F$06J`DN z(HAV{NS+=c5{TWfTSs60Bw|O{AwfBC`n=8_aOXUVX>f#Zx84Eq@lp& zt8ojG19;A>vQXp;#Th0aaTeIw}`KEo{=35*d~PC13Nz{ ziV|H~O6cegD-QCqa~!Z7i$Vo+t?kudi^gQ$qG_}pUUP(_~Bn=&6B3A3U_T&()%%7+bVSV6g<$w zvjvbPU24)8?V4O_hgZ*_{P52;%~r|B1{+?twghY&5s%a`EosJPbZUNG$_o%WI{7g8 z|5x_*?Fkr%$6KkZS``QuHUFzQ1u3NWEad#YM`KmmT*2FIuvZZF>JgCZp= z%MVP^{8hps&MY~CEKkt35d;hAJhQ1010_3Z^xQ=D+Eqsqig2Q!!y$5yEqIOmhJyP4 z>o4nAVWeWZ)j_XM_P>Q;0FT-_1s8%L$}NjHMH5Bx#;OkqZ{8A6$XOYR{=h2^e}d7a z+M+saooWD*YR^NiVN5fW61C7v>c?nm{4e9iX58a|3yM6TY7zKUMWfh2g?c(lzkn%Y zk<2%(!jvX`l__-e6WXns!i|jtw2OHo1xZ%0O)Z$t$w=hCX{cEjt{>{G$q0aJZiv8p zIV-sj);yPC73qOzcqv<3C7GrR{y;3pX!?x)Dh+)r(I1PN(tA8*tVYteG6a+&-+^u^ zd3isQ1fhWHb=q;`yq?WmE!~eAhI2}g>Gzcosc%sC$SUdr(lLsk;p!W*n|rl!TU-KO z159&*El1HhovL8JFo^!qMevD2%P-*H`*G<)~{To>;e}szmV=EJ*gAG94v5Flx(1?{|0j^2QXCn|e z7^DWgf@j2^E?d)8-rIF^Q~!tYhiv?^x2kQwTL6%c82nF-(g$&v5Jd~{RM%Ghyta`3 zr_QyX=)Tq`2j2z(C1mVH3Je)5w)IkO&9yp$e2$?p%5S; z)>GDGN>e%_HwPi~xj88mcJZiH%B$EPpfWcVohCV03Pq|Zu+xVTeCZ42sa954HJmxI z%ztLJj2j&MAmd<}aU|&Jxw*yg&|6aKfgbBL7!rgdkTWq*=fnQeN|?4wd(8XV_cv{* zEhu!Y|0}u<&8`F=#M*CbhH7)Iy`Vkx2%YzwenlfGgHDEV81Iaakxyz;-HU%GeA3x6 zu1qjsL@&Wk4J)r4gb=eZX=+N)3oK>DKU2)~S+HKXNPeetaQucp0&K05(wkVobw#zx zq`h=l^M1t*T8)6ziZTcm6Cc=F=a@>He}}lO=!rX?z0gO(8PTXcb9;x*NsBPoog_OG z4WIZxmA5b%Ur`^P5^%+cWa)86rOePUaI=pS&CmQV8W|GqM1cfBk({ooYZq3mt;6Tn zH~T57F+Mjn2S!12GKi6*5M5gQ_-TQe20zWqP({#$6><}Z_q#yjNOCtpm;90(DSKQ| z6Z>a43ebgK!9HD3naUJ^64TQyx(WC(!W4V2*fjqdECvS%iQ(mj|IdlD5^stl9OT~);_q8vVL537+Ph3Ck5F;yS%h5N|e`w1n~91 zvtOJc>(7c06=_(=n5@Sm;fSN-i9T4*E1MEY?3MjxQ1IBH^9kdEBL$;L1&X^sQa5X; zu=l*}94s(=NzJOkr>90<4m@W#AMG(f84A%T99vQr;R7a!<;%{35HfmS=BnuSLTPa$ z*iBGm8W8Iss^6wX7@>6Qa6coBgNg3`<6kV;1v*i~e>Ba-7R?X&byNL|CJ`d%TG)WQ zQ`eJ85g$anP6s)}usSnMCOY*AWX;-c(r0QFm+v)$5%lE%i*G~lNvdq)!+if&$9W%R zZGHmJ-Cz7pJBL{qCy9Qp>@l~?-ck?Hw2B3h5A*OXq3<0D$4U&|Vxi1ALlVoydPn@O z;|`zi>a5@d!SqK+;&}|*d_#ab%B|c&5+!lI$9&TjjdOq;WHb|%s1P{Z;0{h7IwOe5 z@8l_ztivI=(ECA!myrR7^eg@r4G>pev&wTs`GjRCgoIjnzQc66tNQ@!QLopwP|vGV zrA^5u_I}UZ#=|>Q@&K|#6O1t=vAJk92ztj8!Zd``n2Y6IE{iCtoD$eXVz1tQE|F^! zzPWI#S}muW4|-+<4YOB9jVSWMA_7h~MdlfEHt`MObed_;-a=b zU$C@O25jItYRTpl3|;{hvV656SMIyD-F^ZBVHe^3jL#)XiM}TAYnNfl53lne<}#ZM z7)*8L!zN;%v2?t({5w~RFWbok4vqcL)l!6eZx@Iq^wCAq58M^aC5Z?jrPQQD5H@^V zG0ip%Jm72fv0LNjP_Y?yKS$22(*V=10y?X7&AES1ZUTY&f69iX@tYX}0uVGRd-kJR zmf^NpRd_nb)ilkXv?z9=<7|HIp&4jbgOR*izgfGu>p4!1`xO(X0@55w?76671^D*1 zkjC!v7k_5=e#1~T7+K{d>>3pUp=GU|IU~lizwtj_TfSYD5Oo-%s)82e`TJ-Xf7tR_ zd8xF(mE6U*=ggBTwMy_@m~--wxn;hbziVyt!SN#h5-yLCxZEz6NEUaLsBCjl+Y98P zlN1-LiP5hn-^p9P^U)~q5qqJw+ZG0?$y}vN2%&H;ycHJfTG~uA-?iBf>j)t#5@y*s zw#+)GB4iXv6};hl1U?tO8#4W(8I8H{1sH>YXES|k#N&UHlz;mYOMw2+eWw1$fjb1o$%*4gTO(^&W zfOyI&m`7|dbnt2N@cICF5fPJw;e{w1)X^E0aNwrxOlJ(gvQdc~W?$dZN|z~ZQsajg zeS2qh0FE7ETFlp04pxc9x9&CMwRLjgL~|Er>lg*v33TXOKrx6(ZHhNP`2_!B$sT{Q zf4kw*NAl9Y1n7|obaOdE1M-j(uHVC@TqTS5k9S2%in4SjH|0N5dt%^SQ44KL;_pPE z*I^E71kZ}9U$181PD1J?eqUMi=5m}D1)O-#$9%UnLVUnwEz(>vD z0i%kohmvvat+`T$w8IYtf{&QgrE|0Ag1K@DKsJVJ(3i4#7fV z9BpdRE7m`mS72axVZwTB52w&^y7Y+&wR%-=U zV1Kjv3Gea|kyvBI-env}#J$6wm$kaEV$PQJ7qmxl2yZI4F)Wrz1a%aV@%KS}od(7J z>S388!0(o46(n2%(*3f#A;YtDDBb~lQAYO!=QUo}LjgNM74j+SIOaYs?h_eI?S^83 zp@V+kg=lg`B!A`|RALXm64f|Ab0z_Qe{Rc`iMZ6Ll$Hux@}(NN2(E`e}x z2|A-HAi91c$8rzASo~p;gC6>AK(!A1hIwNt zzG4;i@Kwr$zW>-8fL<*Q@ju^gKFcOnFn7*FI<3*sNs(n5v zurKrJ)Nz76Aj#umnsyio2NGli}nheQ`h)%?1-`%yeP8FCtgJru3@^@kIpGg1qeK88`PZ) z|0PtYB4~j36Sg4=afpgJinI@VhckEqjzO+CMAIRtA8o1j6nM2zcCsJ!=#cE{SC9s~ z^Zo?K1zT=DYSjtacJ$7|E6N^VW%LfSXW&S>w^F+1>25Zsf@k1*d((1R?QJ{d2&guT z47hQLN_kk*ZYsGy8U0NXsb*Gn3>OKqVo-P90VxOdJy4cQfgM`fMs})h5uvqiJA~~r zj~(qj4tc1at(RN~r%jAjc0?_}1s58w`5amS<2Q{y*^JqfRmnlJ6S3Ef0A2s@bUtpy z^wtMfo^-9S5x8xNcx-Ghx)u4TJ-9I;>f6o?xLasiD5FHRuLdWDjtv*AEDPF9x zJ;Eq>nCjiA-qyB53kQdBja8C1plrAgpdA(f~5_7$S00Ot%_7So7ZFZ6yr z(<$}wO724k!K`F;krL1ax)&mA2}VsF+|wbhL}-}=+ZY1FtBe{H9?$4&VXlGLj<=QH z0VFBkwXuDim#iXDI>qSh8MWesbuDfEXDpeG8+&&Y>0r#&KdaB({V{GGMDKx@D6)4p z1M|}PrUZfnS4eEZ{T+F&;J^5216;5t~Lx)BZQT7*%d) zchI7`Steg8j+)e&#ldKu4qM?gcb3gn^7tuN#Jl@xA;&s|3+abswkCih)h5ht=%3{6 zTl&VcQ!WYSX}>+MZz_lCn`R0f2XXl9#VCYB@5be35o(23J=FgqnXZxjKW?)LA9sVz zmorkatM&s#dJD0w6=q z7CsP!V+Z}wY`6*@K9!lSq|bSd!YcP!2{*}F;>|f6iEv^PR8{$ppQ?GsILXc zg}D!`@e|`o{>m19b@;VT2bMUd@;Rd1X_7tK@T&3a>`FgS30KMFW-1^JW`kthU8dPu z16Pj)WdfYEe1=L&1u&u0g+5daUq(qcZ5RB!C2QR13()_XMa5_J_`wu&Vzae?CpUVh zoj0jAaEMe)1Jf)}!v3wGgr`$G4xYXc($Zngt8Wfc(VO>QBuE~3J+!p*SFPA9z3gE& zR4_8M4m@pokt#%FT&)ilk{IK#{W?>65J_jFBrTE9kl>RRkiCET0UULT7xd$TE^DE! z2#7?T^+|t|mOI^Is17@N+2MZC?1%MjMB&@jKrZ9-dP%bFs6ZTOB2-Arg-*a=4*=lM zKlt@O*H&bm80K;_D&S(#u`O~DjvW|=ytxoPnf++f+20S>Q@3@Wwwg493dE8S?INuAMr`(7QoL)H)haD`uz;KWcK>D#a~Uwc~9IhZv>~G3Fx>aONwwZ;K-}& z<=fHU1Qu$))JV$(Pw7Dv4p+WQHg6``ogtnZODKsP=Kzp=3zJR#EuhM3+Hh&_va*0T z-`fK^JW|brr8&;kr~w&r8{|h?M9%jkL?sqIT6ow#+`pUVN7U^1uP)pc~pjGcb{+)=yakLxm7CMi6T~Y9$E=~rHYhRV9W!B!Oh@W0e z)YJiQJt0afZg_(J0$Efn0qO3m9<&3b74@psq=<|m4g22^NHre*l**MHWeA)M$|*ad zs?k5C+D%}PdurdB(GIxTG#}^x1efh44euewr2U$l^j=`JtTS&C;7p7>NC=`c0>M@| z__4Zdm!Gfoi|rfgUeaEx40fqIq{0G$*9i!8%r17b=v^r3rQT(UaifWV+fwJ*W&#qH`A{9+pkat}A^GO+C=P z0f%}#AhEAV0M(Q}I^FE7UDg4`Wlz8>OwUA+#(@+rJLl??Icpf!1M9Cq_UO9uoO?jA zm?G}y8NsQ%A>C=s0o-~@)Zdy0P!LvDj3Tem(r;I>5}%KM zYxx5!iJ`Zyl|3DVvYJ--o`Dw4XKpjW23WPqZ!;Xq1q*hk_cI$3_{eTv33ZJwYI)IV zI#aI}bpg{ZmFj3cwbSk(o4Jr1|G)SZ9+^p&vt%9AAD%@m!sjkn=`$2&jO2ItNOTGChS$Bgs(D zSQqW9Xule5WBUe2c7LHDyE|)&c}+;ERr)-AD0=1{OO;8cj%wf?Dynp|alw%B(WLU* z7e$!IHtgp~8<9?HPL?B8MvVnt25t=~53mb2*duP!YP%+KWdWjEYof|(o;n1Uz3T}P z8*_!c#rh^FvLNevL|Gnj2z3`>PUDY;o!v7tBaK$P-i%dG0aR%ZIYH_hFz*F5Q7Dk5 z%{LQ`@ZyTNaI=3g4zPh%kfo$H0NzeqOMvPQl;+ z_f8eNwB3!=1?$+q0Dy%go^34ry9z>=F$(R$)lyPT1KXdSY9myr=%lm=^--*;XNgQM zy}&A!3vB1;WyBHxGaz2K#R}k`^i?5q*%N_C3;6z0&eRl1@J7y$fc0r6nlJ(;*bB$e z7`i9HGfNmhs;j&CG-WKIqjhx%FM0=iRqBgClrh4wfgrVQJay1;BO4h1W~H`51KN}i zR6w-BBrfJyr^?v;h1te9Hg1l(EGJu$Bwn2jirht173z2i@d}&4nyp5y7E?Agj}W2E zWIj3DB1Oed$qV(r-&Icdzs^rfWIg8F$rNP8-warWuI{}A;oT!N08@FDK_{kRuVq5o znmzz~m6F<&3;eF-j>V)Mi3#T-g1z=9MZ?pw*;J#h)AAAz1@p3s_&LCnerUL{&_4{u zQ{dSEU_V9Nxz6Cv8H=^9JZ}CK%d*mq79yukI&WIq6L^ir^rnT5^6-BO^F?o`$9i)D z(I7f3Z43T9c{<9g#>yGA#I5i(U#HgL7vI|<5J)*1*bCD%JtzxvFFt-{D~CN2N$&Oe z7Ud@8d=}*Wxu9wQdw#4xA`l%8itMHd4wKlXbrAn%Qd&oTojmAE~R>;74G z+%+R;()Uwf+|!+Tgdh!GRn@(Z1J-kswe7_qEhMELPgl&+bqv$upt&`BgBQM)MN4F` z2mu|{(2#r_Ch?5nL8FyV8RE`*a1cg%G6AE&u`FUKo-##$e1HM6y5OhUeyN(Uxg??0C26W#4g_G#Ffz(vE~Xelk8 zjmSxBU^3u*TbA;~rh%CL@G*YW6e7r^fCz!r^k@#K3RKg0QUSD%7bfp>>f)`Uh5KtM zhOJs{t}+i^8sR3r5bB%j-$~HcHXx6Do+BSo7FuUwpn1TeWlr82PtX%E8zqx!!ajfC zf4n*JyfNOaKH*IP9^PF4shfj7Md@0jOl1zeY-J&!53d!pM1Z&EA z%0ihP%(p-FYu1U=$ZQ$0g~^VY40|+-ETg=_YkwLT>$K@Kg|MGM`>T^^)s*{)U!5L; za%l3wv#q7Ik5yedlB0I{5%SgWv4c-M8n0tjILP5+wNbKw* z;Pjas2nZ#Q5rmk^rRIk`qH}$wBESFPP3QZ`>JHEFEm2_h4~!E{%<#l zqY8ln3RtA~TOr!KKP^5cHw|er&K^w0)V_hWGi42FqnI+9l<-j!oyLc_fY~E}E8H(| z0i-gv5_XU?6fJBCbtauAX$RxaRueXNwG87iWKwOKmX!M~scIIcFm7&<#R7|G7C$%{ z(B@4dKUbB$V5g4-e4N(61jm1%HMsnI!!&R*2=~hoR(&3O3VMOSXC$FY7;R|eAlyuz zdYYu9Ra&@b|EV>h$jb`SG`fgB73J=39Sg6J-U~mrGTJW(lT%LO2cFI5$CL(@8&%ut zNIOd5S%r%0`M6+uy=W6fZXU)3{7L+l*Q66rZ_0~BP`SoP+$yz0my zP8){TO~ut2+239u*f@Ow%(f(}lX`U1AV3)5(OIlK6RnYhDnkX(z}efzbqIg=l`g6$ zg^l}089Hump}~1=6c6Ph6iv&9S}trRpw4l{6dyC~=@HF$Zd+l!dHGNSV?U-JWPSA- z`vKbXcXgv!m+?gQrwd;sO&NL@N3LAVhbX5c%rDl%BH3siCNiEo5;8d`!u|?1P zQj3sYAyQn+S<+?REPKxevi)=e1kBBYN6gU~a;!2+Tm5y%x{Q8;9~FHaP701;xMjpA zlQr9tZ%=xuP}%w^)Sct^4eS?`lpe=f+Y~Ny`4Ur3cB5asiDLA9x+`S=4`qO4)MfZzAnRArR^exAFJhCH?QRniU zMv>7mtFv`86|M^}(WC}au1NTuRXk~gRNI$go%$)Z5Ef=-r1j6?nb&`#WbZ|WjNc@J zwL2Qy3XEwU(ZmNbRL`r}t_Q>$tz(q^{)jH1rkZhVSB}si*qEh)L7(!~7c6nZwf=Is z4=X+A_&q&R-A9_`7`nb)f@n&B^(aJ(e>nkKREh5ykAZelfp&E^^TIX6WA~!NoqZYKqax>3${X+j% z2mO*(&^eV>Q;gt;L9pf}Es4fF#P@M?mI1?#X9^YPb!J{dpAV5j{AYOR zATiOK$9aW5!BUhs0I@g5nW^{WgWpkxr?kFz7s(iEsucJnl{e+qv?SK*W`PgMAx^c` zT)FDajmS`iV^3{WG?Jje2>9smXcxYfk)j9JR|rl>a+H+^_9{Mr=9W(lIb%D@2`E$; zN>B@`rb2(Zo3O7Uon(lTj{E+Ko;k+watYfeB`)@<(jP5@Hf)bISP87-a70cCg$4NX4wot-2zE4G03J{oWwsJRJ8BCNR$Q;V;1{sI8`aOQo%xil20q z6QV`rc(4VJjr9zZgU}8PAqN?gvlV?Mfz}9HH*xo%Ht%0b<0IA z#AnJcY=%A+icDZJwhI6IUl(2Zx1?$>SrrXQrgP@|)_$qcfjPSvVLbb}n#tH~Bi|Cm znkLkAH-JVy*aHGdcP~n&tL#tGZ!U;SNXXSjw_xncAS-PvG-U1``y|17S`9FGpMnCL zA}UY)DHZ@c%ycpLyrf&JB>#(l}78LG% zG6`ej0Buqw%L{^5bv&5~r8EgN5b1Wz-bViDF`jA_2#dSS|Cm$e;0Uc?fsW9EmJ+du zhSFmG;l>?HIs3e3kh6kIgGfp7Z!(vwpUXzsw|-#aonD4^PT>$f7-OJJ#}f70BNWcmuN;fWDl)KdHY!L*?)bM zxmo%(dvddjGwc>HtUE7m4DC&-*8SX3U{S@v^T7gT5#DUhVH4EX-Yx#A=?Pl1r>8OX zvB1`)FNaWKfRv{o8uZijHq5%)ZpL*Em3gAa6H^e`)C%S_>H@O1)_myNQ|Ovn{?nez znUr$&oZN8U=qy25w#|N~L%_YyG5){`0IczgOAJxVp$w$W##`6einSC+bW1zMxA#zp zxeMb=o?Ve7q)z&4oW%cNWLsS%P4+ad%MkuZJ zk9jmk{gv9*gB%xWQ2+DDDPDH*=on8GDPG+I4J1IOAE6w;V~1`sLZ-34*FpmWnl6f3 z<|bx^CfG5^ge5v87VR^i4~ho@+yJq+ zs|8?LYgp5;5xQJzlUW-YHK$__WMzs4;)p8>jl0t`>3F? z+>j08pb{$6wx5rTS&{1dsqgj%azv{>a{mH3!9xUY>C(Ac?7|mH@3udz_62klHef6dhHSILNCs|Xs&)DpBDSv4|%dD8Sq5YI4Uzh`0kMci9q(3i;ffYr0k z>}AJcdf4cE5_um7T`7648X477MnfMI(ymKs;>@Tk%ZZbkg zmPq=qQ^j>H+ztZaQ5wMdb@|veTOllzO=RBF+651&T8 zdIZ>VQoD^TzBjgVV3XCX@~1$7w7u8PDgG&oIhET-o&o@sI?rMwmpXc9F+WBX_d$CO2Y35B8FcDe)P~FaB9fM-ZLOcX{f; z^G3lM0J-;9{|l`3`u=%K+uFA-AWE)tEAXyMKM2zwY}QQSSp0S$$OCC=hF}}b>KOKP z4BRI`Qv^qdAotqR7>+m+TXq>$H!3r>j(39tqj_*Oe>w8TQ!uJr_@yj`nYPfIxi05 z;0{S)d;QbW_pbQ&8I^EaiiI!ip`;JYV+Ch-qh86K6}vovu33D+Lo=hp%N)39ooH=c zN5?i4&Rb7X0`TTgs7M znKmASStR)7aGkgtr*J@$WEVr}^F*qH+rOi|~f!4a6y*{v%RRE#3%0~Sm$K&g*rFNbCQzWr1+09y-i*~<9L1Qc>N z3B^c1q7uUSIS13lHpV?B4>9t6+x;byZ}|c^E?XQi=(8DWh3Ri)y=W#Q*K#4+MTkNM4MERmefoUymN& z7U;ITAGx8`Ab4F=t0pz#;g9k)G|e(g$Hu|=ygCR}Jru{quFRBXeh))TeLc_4;E2Tz`V-z}=MNE%cnJ@?o1mtTWew+Ssxi$Z;#GT@&!V zp99bCQPmJ&KeJ!N+_*1ytLts|gA@tr@U_!1)xB%!wWb%-sA@|suP0r*2?9mv8U|7O zn9x?nIDgj3)?!g;_@(??T4ju;pi&$u;D#B!OIK3q@Ds-h+fuy;Cd}2<(H!d} zYu5fC7Ewu2RDyQE>?-7+#J`)G^az33lLH;X`6x;qT1i_yz7C-(>Gf&~lV%FzHkgmE3RJY?ffm zLc8w6iF>gm8O4*fd4CDiMD>39r2u=rSO6JrFZ5KDFi5@jKG!X`|8n_X!_4|IP(Ggm zSJw#!U+ojD-qK`}a@&yo+ehR>@(vOI{>nIdftyN`h^2E~Q}LouXcuGc{5Fh3zc6;F z(*8qIk_?T1OiKK&H>ehZbr0|9lT-+&ErHf0DYG7duZs+6Zo6Ve|G_&%OHhz?LP$Wg)Z_MVLQ{mt8AyST4tNGt??CGhcGa-u^f&CG?@-}B+4Fad$2 z_W<;a5eg)dg$=<^$Ivkj+d})33k}ErQbAx_(TgX3S9KY7%`PiQhkuXDA_cu_{o0Lq z#_7XKr-#pydZRJMa1-)|+ASnVl+k#+WDkNj5=ErN0IMOcDicT0r7B9T7P`t^B9}vIWg#QRdu(l7eQJa|& za8{NCQdYrw*3(N)S%6tU6zOAXj@I>iB{|qiSFkAFR1gxNR_T)IsoGG0#>_rj^n?DD zl1*5>Kz3=uXXYDykMJtRSYLA}{QoWZA6g4QRSF495Y(QWB7>96AHgg8Xiol?v#AF+ ztua5QdS?HnN=V-=UbUZF^PYt^XnJ&sOjLH z_~1nB2dmq09P27vM(gi=flaMPQ3BE#Fw@aObi7-`2dS$YywSTWv~`uLu;ueCZ1D|3 z*_)L*yoFm7f`vj7#Cn*oISv|stz{dpzPbZ?zDNFBGrHTZ^2#zrfca=`>vK7aWL@dV zAXfa9d<0h-YhH6Dvk=kS@!Ie_AS03K0R;NNUPu~FJ^rWl#OjFnF*Dqn zN$56y^c2(l-~lhxjiQpd^ib+m@AU$Y;$(hY?Nwsz)F&f%r_A|IauBhX5}(CENOg`+ zY%S8KF$;Rp&Y;fy8e4w#%xw*G=dQ<8EQO6ZXMH=urY{$kVhD76?~^L6H^cKvPJL*g29K5EvkPkC$rfxp z^O2mqR*sr|O|vj=l>eKjI^ovn_NU?!Ffp5m#v=kr`e$O6(kc%Ftj;d(gEQN7j>>`LJ9S8P#+iIw(Hd;lb;IRiMXF$>);tC*fY-tTLo;<{?le)*GA zK}F;>MwO65-qcK@+tp}ZogFjtrVmTq=CFggnQMjT2p&bvZ&M^MTRU{chD?jQ1I_E; zaAcVi;1i-NMyoADJpLZ}o)nVq&pfnb)=wc!O=YB_Ea4LG*I<^pG|KhqDc~amE`!ZB zcvH^JNugCZ)aqs7>j9RM3t-X=XK*%b(qghe`)z0DKd;9)w{-r%+goYI)1S=$8J!u+ zE`2}-bK6Z#sRU#96gYjC=^Z9mAD7D!`_jMBsNR8pQVIP|vZKJq*(!p! z*uW|Tf=2gBnZGD`nsJ@YohsAv%_ zB?-q^5c2VFRciMlnldiX@}UwS6W>Dh*8%iaH!*!Xh@e|*OF7~q@%{Xjm+zpSr^M;N zL4VAJ>BO6j=GH0)Vs4XqLy9)?o((3x*E3@iFg{Mkh=iT6%X54$1-2tS)_UTJeze|9 z3+r7jI?p~8pYZI3-Y$I3-vsDk;6c*KECAAkM{#Kj$x+uc(gs^5;>dA|F@{4-cM~w{w5N;1=TV$9$9LxQGIvP z!2_sjj;Z}DC29S(9+h|WvpJ4S{!Nkk=AMo^XjxxPZtricP;#w&l|YIle;kJ=tO4dj zW}EqM2f#+N=?fWJa0PKif2_LWuv+NI37#fiKLJohp6o!u@hJ;7j>J!%^#)2N&A)xs zADgT2HZSk2DtZ#YDuRQjrGZ*nyo#qq8;56I$ zw|-KxC(XjnntLfCUCe8Y%F6W=RIL0cpl%IsM1T_~8A2;!(+TIt3{Q@lW>s0WIju>f zU5}B>FmYWajACrP2(>ddsfJr1+rC^iyE=N!Q(AmM)evt$s?DHk=kQDMp^Jm7WuMI} zEVT6Yz}u@AkttYDwoyj0t~bV&iwQ$6Z-hu1D*`4{n(7$!%n`IMR~Abno{M%NvBV{Vwe^lrzbtK`9s4 zU87vJdEUh*V9w67{lETm_)VyI<_8Kf&ARtLG`z+zXLOoq>FYINoYOF9k0==TJekb3 zY7OaL;d#Rf)ogf+|EZ}C)dgQW2HvVaKf;dGr7hs*yHy1pMwx}e&QU2X;tgXxJ1A7t zhXigwkWu_VT%rs_D+#_?A5?2W%mo9Q$d+13_jsW*$4)=73Y?zp(!ysFPKh?O zy1PmU+FG9^g$#j)4(o`S|Er-g5-;26##jA-I}=Qt15SEYQ=eeEw^ROUF}y*7T_XMF z)zY;PER<(S=PXYi6^8n6-(CHxF7Rrl0^?>dE zMmog&%3_Tt#Q_yG-uxqEgG7qG((Ca6$?BueSCKv7mkIXhGlvSj%1C+agN$%~g~voK zJ~NXQ(f1m~^)Eq{?@BeVwlXlgjZB9oV7FGv78qFB5liz^HbI{MZ{uc3boO<@+`m<= zJpqSOcMTfkQSHj8ZVG-s+e;vBBg}g}5((xcBoW#VVi82%G)_N#u95@RBb$}Y*&PiN z_6ZVF`f|~5#GtYc>qiyXH8&(*st%2(DX5v2O4o%pI3ed;|Ic)M>)0n(EPKBwz_hK# zgp)G&(aI_CeajI8Ph{da#uMPX(+&kBnOEL?H1|i8@>n}#4e-_&ojb=;*EB_rclvE{ zk)9KhhmN%E{cfdcQ4$eC0N;u^@;jkwJyJ_`-6!<4F!(yy9brq+WG}qSuO~0v^s)M15&qH{L0s#`$rU3xX z4_tO-m@~(q_hoc;^*#OWnj1CnrD)qwtq^wxF-ADOgSgU68w+(MwbQs=^$30+vZtAt zoj3hBcGV82?A^#uc-O2SUhkjvzsrxBD3LrVmvyezAfB?s*|2@#i4wFOPh8|o&js}6 zutCpCy!By|F$G{11Z0m36WFgF1lgN7zc`y}2j%-`XNxz+UGO+m&FWhz%7jLh}q!xmVy ze5@*ri=C2eS>jAE=b}P+NH+R9w-h?9y%_%EdNEN4tE5O~p%v8xy$EDn`9Nu|$v|09#K64`dyBp~IJi_$yT}r?Ws@@VmT2AA zSivr;6;&!y85M7*@15J$AW%WfMFP?r6q_BaSI!9o5L`UR12?bR4%93WF zusXgyp6CSMAovW&oq~29%sbV;^5e=aOe5BIz5)VVn?8uCcUQ``*%9&NyZGIqJ?YBb z5eQMHe%H(f-Fmz?ed_&fi`VtXk-U0tq=rALo4m!-Jc&^dmJLMud4C0ZGd6MLS~ACA zKvwv;drdKqu}8+UgBlcw$T^h~F5A!k`NPotriMyOV*mno6%@RZN1T$}db#ryaS==F z16n^S#HG-*XPvkDcQs)Xs#K_I8gHI8xjEodoez`nM6H`7HpMcR@@e1+m;H(2RZU(~ zRS)E1rPiXw0t^{{RBFCMN@HPw1{3I(ng@8U<8Y|I+SM&K@IIt7NXEgegeb3arLR-s z_pSJ3ZEhSQ3BJ=8t4Pd=q$vtZF&3hW)Pd0i^n!4oJrqn{Yf3g)657wZ?aD=a-)!4AEN@Dpy_ z&~&vhh#0=D$s{3U&n+U^Moo(LhfuYBS9Y>nZa`@l7Ux|D&^b1C+_pysp87R+boe>9 z))@Z^`=;U{Y4Is8)HJSch9Wvpxt$1aaa`Lr=9XLRhFx9^U_GV`3D$qDQW?sc(-$CU ztAs(;<&l(CoMPnN{;iZKsg0;}gYiA43c(@~pz1rX+&4ix{+}&|6OhHsZy6^-5EOFy zVEcXMW0SJ2*yM(Im?W=5C8#NboY-gaBSR3lyGgyH_?a|t6*tk9q!FCuAX1wgay^Lf zWP!eIW7M)p{b6(V#vdb%k#Nr};3wqK0 z+D*Rn{2F=1lU`p(3GtWW_Uax^v;HejtFTZgKbyfAxB{9RoZBWrKQPcuz|UJ|hl?{* zFDx|-T1diVR%!&_N5G%oD)7JkESdZ?y=WBG^bGVxa-sCGYYo3aU^sxC#_W|*bK7am ze&$~3SC;E6MSCpqYQZJe$uI-bJxddUAs8J(&HTQT6+>`{IxZhg2u2}*Tc?V@@cF_n zflxGg?!;-in($i+%lTz#CsX&?CI$1pxHK0H{_q5ZQBnhX-e$YJCCnrOGwip))()jb zl@{6xPnRjyA-$6q(xUjOTmtNz@d3k;h4}H^RN-FF14LQ~C0lH&qUxJwQV8opdE_BP zi$^k+Bj!k^0AxDqj0{I`{yWYBYS(mhdVm6$b<~7fDp@}CE4-xwG0Vt61+a3|ZdR&R z9epN@l-ZH0v>38UAfTU!W70mbIxS-UHAgB7dOn;M^|&hTh6x3eLO`}E{t@i>#@unV z{~^xdmK49mUNe1ayr{4Iba8O}G4Wmt2AB2GJ0bRwir(DasF+L>u8=#u*QqlvWjigN zy9Iu4FVZ(TPffbIA)Qf;DEh5&s{I|w1X}0KU!;+V-5vt~Oa9YvYBG#t-KF#;q6$vS zL@q?=Z!L$87F}A=yVXxb#_`O&uQK4~OxyM4S&7}SU1oGLu38#i*Zg6u`~+Q|s?0rE zMDwc61xfK`4+H;;i#MZaQ=LiX_dfGx!0<`|QafW>Ql%x{QS4>TlmiI(F2U zI#<}tAOMCtJ-r|rt+wIRkf^nmOm?^ZVT-G##eyDj&JIimU2f7}q;Eyz{}k5cIb1u- zkMh8Se}I?SSKd~HjxV(8{-2gNIYl`k3G=Jz*$uoByD4Lr(}P^Vp4qK_6HrtsD&Zn^ zGZ}WVp!%u#ogm#!q^lXg)C{xf9^T09#0&z6nCeE7^-pOfEV}JUlbc$NBHL9%k99)( zF+ET_Am0UW2nqGLY~-Mayp)mxUJNA2SwD5uc_+|8Rk`D~cF>C?0I34qvU&w&GHfCc zja5fMwo!NdYNtSba~8W#_v!urT|J{ftV0z*IZHM(xG&-6Z-e-I0_c%;6_&VnmJAp&9NlrF)i z2(ReC6&1>A&W}HMn%NrPW|(P}Lg!^|jIZTMf`ZM{ys7ky%$!K@0v~+2#uI{%|Im^> z&kwrLJRKeadAq3gQ;x2kLC%3py*DqX2*FJ3a+nce(*Mx~!|!MbB~%rXt4o-Eiw!QO za{~#%Sp|mv`ZgvE!v`{HDX3ZKr0GomVO#QY8FsrPckO%kKq8KX72Pb2RTYK0nwz0< zC6>FvGgz{!OO|2~-Rh9ft{G0iHs|;VZ!jRM|68Z)?@i3dvzDYzv;@=IjRCI^iI*$I z71mmGyf_)Qv=O3Jcjx%6OlFCB4uO55zPH4z0G2D5J>Vcicm-Ow07O_-#;!s{nie*y zo97vxMEqTSu=j7`cX6IK*#{=pi~mf>q3jxIT~OOO%n^MVv~DmQ9!|pt396lNcpbd; z7Gj?oBbQ2iO{|9Ki|E;5Z#f+0K7hqz`MR(Ix(}+qaWId~L}RIT?Lzq&BQ7giOJ`zs znLvLs(Z<{JST3i)DW(D{aLJ<-rb6HK{Q(NtnBDcYQiL*o9G&K>ke6h?om(b+Q(4wg zoyrpbUgzXl;X&Do$s_mDd>Uw zwd!FC|B8v=Zf7-7tlxvNg9|*kD}*xWo>knTYh6L~_d@u+Rg6)(U|?JFS7Sdw{}Nh) z=%{eR<$C2Ai1Kc#od%{MpO2ccQM~6sx1~SfwSt`#AW`LWw1QUuwB(h0SZPTkgL_qu zM)&oFFriMhdJY)+T4z4<5L}YmV-@j|xiGhbz;vlm)-_lQcRs*wn)hE^*owI=acE;D z@ovWeZ30c+uCnDcDtiJ1&W!}$o0owzIku4hfg)D{C~Wwv5`CuO;yiUt28N&dnYuKE z{RtHTFHE5qCIoe-uc<_Zt&0AlYG@Jb0^e+1#IE*x`@XQMnSEz2jf_b-V@1PU_XM>F znDJwWM4NOF`Uu=k5umg+CdL)j_r(3`R5%{m#C$Y$s3e=gj(AvPOB{iCCId9hdKMAhsG_ohbPHi{ z8~m=Ut!@wWGsGG_;(#S%uvmfDhjDN|p==lK(~yXvLJy8JnlI5&ukjCTkKXgIgZV2% zA_JC73KlWd=5?M*tNILqB!A}pHytc(9uIB0Tu>J{|I7z-xB{YJIP5%DzKGW6&R~fmU5^x zi`ka`c^H7JdI7@I8Ed2uZ4g`!k21ek&>tT|y*-}s?MHjo)#v@qBocjMyhjQn_`NEx zFCQEe>!D&Y_1>)^y_n7t?m-qGg<~LG^OpJh0xjQr22RK+ksSq;>4g@=-(TjpMoG`HLv&`?6-WGS^-N8yBJU=I4ejyab+(jMv_ST>u)&L z77zflLfs+fqN3jZet~j1Ov}+e7x%E>E;W}Fu?`HZ04W_?4{d-ES6FUpC)n=S$4a|X zZ%1tK{NYT(kB$e>atX=zMfyuxLl+*WzE8##+xMycj9I^_QRv_o94tF?;MI^mtCii`K#r&AqktG3({oUC_b1h)5Cw zbZ(yZ#0@R_l@`0WYc%ZF`hosh`+P!KAdX0=o3tx{C$TNj*cBIw&^g7cg)u38lL{<; z9;(B;QUi+nj~5`~#GZrmCr#MXb>Qkl(bixU^(o>W4diJc!GiE2>0MJ84H=*JYJWCE z&k^^#2tEA18v{|IO#EVE1CGHjv?7xW*6U)~Z3@>`omdKT-pAr0UvNLNdC&GHdhX6t!@5^is=Bd%vri96) z0dEVbZzw60Pw!)}12&$eMT$M0P!IK0UOBnf+#@0Jf)K=@dDK#Qb{MN}yDGq*Y*p}- z{cQ??0DtQ6#P5Y+*t-pFHPm|1|F`HNY}->zxe>x4Jhs&=O$5J3LSHMx2}66@tjB*n zwGxp4yn~2#gD7h#R&G%hQ{7jlgO{Vp{sX!z>1}?;#*N`j_^3w+hViaN*3-m&k)x%AbhAN!QmL@UI~w`rNL8hlL`tE z?*+p-qWrmF_WLqXk1E=kAdNM`fx2~1ogZRQ5N~I+y0y2djn?`Zr<&!sCGo%Cm>9!X zE!J0%a<%eFmqL-?rd=n41Vf$ZDVmrFc3i*384EyY6b0@d_^PKCt5G7shY7Bq-WoBP z(IRhFg%pJH(w@Zl-%}Fk@BYy1q^0`lFi^BoheKkv(b)17QFw!lMhE8q21?@p8I!ne z?6j)!s;%0OI|(rbUAN`Kz!AK+i*|x1Zl7Z&q?Oy_T#mB?pcH!;GZg?KePxnft>krO4) z{`${+z5$9`eqjrDt1~jX$QYogynznHy{z~{sR#Ed2r6m;(nn_(_QzCtK+|jbSF)0GL5>6mP+Gn z29ToP8?ItLVi=_&^p8`jaqJjLOl7!TFAbwk5yS6FSqlbJpe(K?VOtJD zR+s#EEWrkXcriH}RTM&Qh&j2T8DlV?I5+YGc~Ta*LBE92u33sgaRXP13^c_goy< zaAQ~V8U}+mc$u_P1$VQF=&_c^&)@!|gs2E$vZ($6se4}(3Sm^-PR)Yl7SE{_B(0YL z{|YfIFRK(dpN5qK7rep**X`T$RzqYj_IiJ7;Pk}W$002j0%SQ=x*}%axTaL}mkp;f zWZ({Nv~j6t8|;c&(qkk*TaR7R*sQJ+mDe-^j>JlcZ0x_Ib^bfyE*Lz(YzngT35cLS zpwSDeNI?u{mGya;QeEqNtm5BTf8lRttUgm$2`;RjpcNY-%D;r{^BB=R>t;f*2}D2g zoifMN&Y1Nz|toxT7i20e`6Y;YkVt!6^WlI(H|i+Vp=??w-QcECF+f1+z+os*&f4?nEb85 z6)FBco*WnsL7N_{=-|AI&BdLzE^^ZFSz@xGBLtm}=8OIHS&FJi`z1w!4tQ>vWD*r= zZOWE8@8H#FjpMw<`Bu<$kJ|R3QK&2j{R(-1um+!3fETjSuiKEjxRs&EPj2{MxlcC= zaHbL*eaXI@Y>PXs1hEv zub?5BQ4(25gKQl-xQ9=>U(K(dulC>~AP|Tb^(077(5* z37wV@0M1hXoevluyu-6==XZ@(LFl5fHoUr0M;Z)%pc=bs^)To(GgZJC9RRPzg3SV~ zJd-!j2}AgKT7$7JiArY@>Nkg6Sp=Q)`#<@tYdvsy)Z{~*C|Lv-v={SEw%BPOB2B{6 zxscJf*o_XQW06CSB$vStq|G?^eZ7!d1Nh33J$(}@AlwG$N)Az~!Q%d+dk581c{W0_ zGNtHHE1&A>yTGxofEUuUYralw#rIxLs`A{fUQ0|wW)JB=K+bobd7ofym5(OkGZ8sU zI^n?hC>$lRTPGh?)M3MML-O*eJ3BCWA5iYc#0b^p_ZZT}dK@Y^HS$PM2-F)a1p|Cu z^{tQo#L!M|SHK2Tfdf@!q=$ew&OtM*+XST>OG#GlH#Svox9G2OCa30CKm7wa!ua5l zMfl^8&a=AiSdfG-#AzOtBb9v+}5FBZw^*c3W@3F{uGHDqQ^aSDeGzyLUlXguX2U}@kXD}h8C zPfanQ#H!RiE^!DfS`89e!E6!;U@;cM!bs5U{qXUYi8}->i=e0AKRz$39*~R@(2AhW zf}(UhFv`U)?-!kll`5RqOz^jzvv^#{Cjx!7zUH&GB`~sky~V6epXkBR4@mh0$S;v< z)u{w}rwf9_%H$uq(8Y70HY~n}>UQ<=(7a>8s`XSB6U$Y6D8!F+L+LV9vcFKUVM}8* zNC-=Vip^Z;-XR=Ody*861VCr;8UX8yPS7gL$zshF`R<;&QxGB4ss}i{KgHLDI}#J6 zHH3Km$HLbFxiYYNHC2vJXWR^-=V2R1jkhbJsC9iTV|p6K#q-$G=UXbe77d43!^4`5 zk<#@6-@l+9V!uA|L2LA_Z08uovdF$7H4MVY(9&fUrEN`wQm zPC87@d8?_M!6XW`8`h`Qv%u|UV61 zqsra|<~3s^9iM(h$`xi6F*dYF+RDNs$VTaHxGJ={WF+`nOSvY z@&_}C2YDJlDeC@Tz8cwsP4beqSl7p`w@j?#uf_UPz@6*=W*EFS!9ibGSeK0~tnJfIsm2R3{?r>_CdUOvH%U1* znpjxO$|I9ErSo9gu<8<*1OrpDpjU)l`7Z85Ipu8E9OmJOqxB9LY0mc0|M5*UU@aiC zeJn4vQ6w9c?m4nf^ACt4tRZr?=t{dZ^PdaTxi8)JP8-1rl&^*v4)&CE`EhETl5)=a zfUt0Ey?;PsLK#P2tMhj52)C{}W~vw2vT`g>b@k4~DT$R7UA~n$Yj@#eMq(6x4F;CS zODgb^ZVc(4Z$tg4t|#ofhtUD-5ZliEq<6dD&26!G9l6k>LBE%cou=wHM^Bn}Uo*Z) zu@8{nYmp7T8#bi?Vobb%=7Rji5jaYA@p=B(PNairSjOAN%N*UZ!Cs=%eprbtG zL06m(sjwt_yCcU-LdI7%*)k{J6r7R3^U5wP#4(|4gbyh(;0}%>eAox5jNf|AoBZco z;$j+H$fiwd`UTHFXIMrv%hhx^G5J=7_pxLe)`g)e?hVzD{p!>-$2lSsR5599dP~|J zE^E2eX06zVzrlsno*tnL?t{j8#djsdYEEYIX| zhF&GH?WmR6X<`V}0?DgLD`865F6^XX_W}Ym1g<#@lQjy9k`a#B!TP*;yaeT&%0IZy;9^DOb42 zFP-1{9x<$n?~N8{+I@^~R2a2LH>K-!=6ZH-@%s7R?~n+_7S&nUkGv+j1WBfg#~b_S zoozTjxl{Kmnm#AfH375MEQ*BYlBS<{QfRAidlE4%XBc2uTOX0cY;H#07J-sKdXYHT zEKEGaY$=3Gw*fj&p5Uv!qtd0#hVMxRRiAl*Ae{^4~@%FMfG+=b#DE5~Sx@#-dZrf56f zZV4}MeCIikqNb66`#?+nPQZvI{?7A1l&%T1%h~=p?;o2K^&M-kYl?>-0zDz{eizhN ze$rrWB`#|RW>h8X|5^hNm?AcGn~-{Rm!bTKvFt=C66@t#I6TB>1XC+Hpd ziu%|7ja52ZV~(sCE)6A-)gk>+3;K8o)we-F@^nrdQ3tXlqX{XE66%4TDr6qgf+@-i z;b+Bbaz0KnXufh(r(H;r=d{UBddkm6AT!XbivV1I8m!U3G%?XSVD@2vTs3VTl5Y6X zIc)zAAK1w9c<&YG;c3cjo)U+i?yC}X!3N)bfM7i+33~kBnzAdikfjEOTFw{73QPK> z(}Mq#LyC8w?PHtC;lHAjii5wW5mswUUF?_bEy?kyndzn#iK%bLL+t zgmt|nDHH5{Xc;ymH?C;o%}EMv1~dMf9*)K|8~T0B2=M;Bk@9g~^2{qH*_Dri3#YyK zT{{5OeiH`r32J%i)Ng>Jbn*ZGF__b$RHj3l40DLG!0U*|be^*D+#1D`wFi=9!c+}Q zj2Zc|*xooHF{PB@g+@fn__<|oi7>deQ~g~-*G4!w1tAPEJL0zxoFSMG*CQMu00P^k zB*IxeCT_U;xuAM2 z?u+>i>|U4upVGwmqoZ(e{MczwWjNhu)~)H+0!LO?0vE!Fb4RhQ*N#8%{tUw#R{P+B z$@qavhQzTf@l#m+W8aDael>y0Nv+K3m^rnEulw{N5U2}^mG-r5rq;TlgXTLl?&xMe zJe!;yJdGN27E45VagxONF0 z`tb)aL`FMfP2bZ!plrd5#5hBcmf7(Lt5O1EC5HW-VtpPrVQ|9((I}~EvTIIpMCT?{ zsYO}HDXil=M(10RvirK;7@8B)crXW`Z9mEWSd!8!ArWC1(5{cZeLSg3!sL0k!V|A` zlBN!5@9uFZJo?HyFzpsOTHXTSSI&;9Ez5!v-j4|Aqn%2A^d9hmzsxWymxyJpIMiV4r(h>cbMC4@_F_f7B z4)oXZfzK7h-}eM0bjS1PtaMT*xpgoLdtw!_@?UX!GOkBetd>IVydDSp-`#mbGPS@8 z4SoQyok1*vY)AgqFoI;D@+LR}Cj;gGwPQVd1X`p$#`p%ugrSM!3xrc=Bcy?B+I))wQdbCG1*+z3&BEPJh9!A;wnmm? zB#sslx?}Gw`t|LylZq#Mie?CpO|^9(db1P+IE-0q8ufM4^OBEgE5FgjYGSnGbXqcc3kM~?RAAZZh0(=6Vx-D3xF}&1&Vo?>f$^O!`a4sk|B1rSR zt^a9f#5zY$Ds`fffXevAvYU&|c-Cn?(7YH5j~Kc!HN^v-5nX)U&RLQ1i;OP1wQcPFY6m~O}^-li^KbrL`DXUDOe+p+g^acsG3eyV9-g1@TX7*vLfo> zHCteyxj(FMq9R|#7?9LK8#EBVFYg1K$@V-DJGR7(>XTc52=iJ%fb+&>VN2{(Cg9Qi zJS&Z=`xtQDLW7dJA#&u8o3e&j1 z{TqYhxSHNXC!EGOEt3~gFZObI)FnO}49ejz&sCS2ir(BC0MITQ_I87DY@E{clQs^1 zh`(1(TQqFcqiYf-oulMv-5szn;dR_zK5Q7TAfC@mb@EtRT)&}r4V6(~c-~ByE1ySk z{;l)YxjP7#&8wxxU!Fo;>z5@ZT#J9LZ|*9Y)m^dPNY%;7K!29qS63p@-1)qd3|9Rs5qV9YJB|1mD4#yixH8!i?OUBU@m#P@{xr#U18=rbfCgsbgcnn zjuhj_4Cl~4{qz^cHyNN0WhUxK<}}f(Jb4dy|Ivw+i?VZ8}i<>BttyxzEA!fWVHI0tNY*r zx(Z~2Bl`7;1aH}yGBTYKY^+A&YCTzP`YIR|{mtfFcba- zwCES!5kmHXP4IPEzdNO&vzZCWG=%lp)wb;eTp8`kn!JfAxc+ri!!u@e{U;aWqKe{$ zjK+v1WVjoW zQC)Fcva78A|3Ju8up7?n1q)lD6tdN&$9QgIcDy+y%b>d$788wSaSRn%lePyu0%zk40fm&g{4;-x!{-qvb6 z>yz`mMP&cX6eQmo*d>uv#-Mv4Vwu_Gs%f*38R||?WEs(-`nwhKZ}=>+>x)oSl%NPH zqj&wStKl`+GNgcgY@KL80>bh&SP&ZBoZw#cOB<1bH>3>evwxy6|J=&}pm@^$Ik8Dy zJ|n>2#B(8|WWph`iYr1Dcp%_(nrXVmqVx~-cD4erS;)qpCy&*r@Yd^tM^E3SXO=c> z8~K+zK#bL=w!`#5YIIWdk3iIe^DkASs|gYp#RwOw4C4-uBn~3Uxr^_cA;!;qxPqU^ zgPw}#xb4O>8&&udrs`f+JbRnRCtn3#G=UJY;3V3MMck3c0_$Cy=cNTm!;w6R6a(X> zrhkb}=4=a2(m5<;BW$6;Ke7V1ls*@i`+e1T8gB|APWd@d=V(~ct>=D+X%RH(%Qj~1 z0;FkWhmdTxh$g6w2XPA_Bu35p1$!Q=@X-E=Ab(0#5ljfqq5T2@(RyzcvH9RjCsHI2 z8#6(KeHg%X%h(X1FVmbynxS;a&MbKO{9?8?rbQC5+c^p$TXY+J|0=KdViJNJaj?A_`N+qn4$nt zvBU#n@#n`V5UfdpqfGf_+h*cugpXeT&v~b6iZ25KGRDTqNL}@zgfdi6q%;cxF~bPC z($exVC*FOmHA53D%)Dv$#A##Ueb0eGP6E8UB`%xIh23A0NLGt548+R^MHLC@oBY{# zENxQhl#E_ezg1mvKwQ zA}fD~zfOSm?aiqS2b9_Fwf=ZQKPH{J1DEM?^_A4$o{5*LSIcix`_QMW{kZObkT6J$k_ zWtI)Iq{;EreSPON1Er>KX}b#W^&w2GhHe4isQeSu^0wymhaTNns>~PEk|xG*Ip^Hl zfpZMXHWzf#`j?`SF@*&iz?*c2QKVP9v~m^^NK^mhVSYKM{Tm0sO$-NdE?=2=Mdt8x zQYca_B4v^`!4wu4(O%_laJc}|DVV_QlDAbSsdp~0C#cO0L#oP3CE09fC4mw97aKlu zH_%4~-g5&b09?O~*cUML!2FHEypk=%hqMegi+l{{%yUY?z(s18`k0`fGTy^T-`aq$ z8~6#lwck;eF=R<(7+ut&^s<<0{89bPPSR7{}073RA&nZOsj z_d?Q)J)#fjrmTk4V{7;4RYjLX7f3uTf-hld7G99EYMuQKKCCo#6p5WLVeT0}9(W3_ zKwji7tOqkF;R=XI1gu#*LXUpZLAP0sckxER>-5%d)RRPEUO>=PFLoBKXv)v>ylq|X zvy5Z6AqexZGDNQC3I>j!{zT7}&)GHI+JI8smE|!wx+>P|C65j*;XGVYbyusmJk$~j z{)7STC$?Q6uBkB9O?*EJG&-_caD9MlA2(bnM42-Bk^{t>RT8- zPcBYNYTS6;CR6qj9)8O*T^dhVlqA$a+uZyxVLLGNbpry&{_~;X~n#;Y3m$Wvxeu*>pEImLC|X&?>r>Ij@(5@&l>nzriB!NWXxtmt<18U9D%KWXTx#18*>yK1 z*pWe8e+5GfBXoppk>`>UOF4%?t+iDKtdehd&tRuSV(rUc3mD z>=`IM(Yn{0sRgUUZlYEZtaYglN4*JG?BX&hDTDx{L1&JF+KKfZp5EW#(F9&bk&Q+4 zS+8dZ;POb*&J*g>f>G;*Aj;QT9=H8}R>c4l+DbB@vQQ$fUTtk-1e1^Q{J1vf?K1qS z@x2)P5(N|p{A7L%sAQTCW}bgAP0IkgmAOk?5#abdsxf|vpaKj=&mLo&HlWWNs?}qU zY`i@75x4!Hy38C27LeP*V2Bx2i;oBzda2(fn?R|x3F!>Yze_k0q5~&c>8VxB0c$La zpnm(}s^_+eJ6{lrzQO`TdYy)u#0_i+u7$UCBSGD9dAe^=rNRk1TGQz~_>B%%Nq!5Q z9-V$8DK)`=(c; z`PJ$*h@8HGm+g#A5#iRl{=J-o8i~Q#23t6?uG|1yECoRJet~owcahLZ+9)8MM8gx2 z+dmwVzn!te>!DT13@b5tL5`?KRsz-BLc0g?ER&%~u^$s){W(LJhPf$F8`wB%N%Z^F zrfh9Qp3&3UazO6-<67;t3fRhv6XyNVN-2Mb zpcUE8ebBU4Lblx@aqzNhn->qN!t-2j(O=duz9Eo^?@HzvZM{1GQu=)qxS;J)igf;)7#HPN+qcY_{cVAIK)#*6i;Z4}wEZ!(~fB`;ZU-(XT zKi?Shvdk}q)f+fScww2M`1O^-SreawS}-+}8AaE+RP8$>Iu5D}tt9u6Yy+(;3oZfS zu6(eR!hcDurIB^C8ai+clE&bEj_XdKK2ETqCnilxwHwjZO7O#zp);HhI9LaBa!fD8 ztXR#)l*?076JDsqRj*%VEx9Np+d%78X+A@C|9`)##Z_zCFDN@n>vafTHSX*nm4Ban zY*HYmY}gU1;m7b!s25i&GwM_B8-3Ogx1yg?JfTpQ=foOLEwBMN-O4ynGGPDC8jt!Y zS;9fe#~Ryd?p_s#2tAM^O|SZs+#P>7rr-j3zfHeM9J@& z2`jaf9npkwTlDVoFo{Ok3G4^NX~oF_8R&ME7KX%b#BnI|skB*nI3V1C@l=|kN4|1t z(Pyq=<4JTES@?8TQKyblOT`toR06*#GK2_u4bx#dJXKkv1r zNy6P(KtqzPtqm1a!%d;WcrqojV4us-y5!qG)A}nMy4;PL0c6b=iQTrD85wOtc~4{x zssF50;HMGP75H^Di@F488}8WGi?uKm+F4De1M5pQJReoCvVC#>V3wVwzLYSaucbir zt;!BcN3&iE0c};2A5+z>&eD^j7F1G@p4PJm%_aOQ4O!E|dQTnWT>wnf{o|$wlA{)| z-s+{*1i1f!tp}B6+COyxeKsZ@M@uCe8KEQ9vs}hRI6xP9$pZ zAW(<&y*}i{ujT*-Iouh0*S#3#tj+~#-X#>cA-s&jj*lmA@4pB3D@bSQ8L0~$?3UYn z8t3bI7!-3Mh{6ihfTcKGItWrnnE9KbEFr6@N_s_V1#w>;ODH&R29Z}cOO$lRVrFUH z%tH(f<~9Y#l*DLt6RUrd*f|d-Z~NPlN2uk<#pv(a#EY4b4>0d?L+*0}7g+vZNjy58 z&QA`4w8Xr-bGmclZVy z;^5GHwG{P=QqUg+-?qSqGaH5$pdur~tPaeRS1KaH?n%HeR; z=5=3ed&H!et6yxUi~lDdHf(W{f%QRR<_sm!rMVXlZ=eFcXv(geW`-l-dR7T117S)VrK1hCjgW+D?*=sJKvwHzU95;tcn`lpLY}enLT71}!-%^rahLMc) z_hvJ>a@>Rc&bzbB=mQNvflW5UAxHuz&US8i;%Hi?hdrcI^bv8kOxNuzRXsr6p}BBd zjf{UmPLi5h5pS(Wq$nB5s%IBQ^K(oJmOj?Yo)$r~91H&z9VyOQh#L-uq%vjoh> zMt;Asme0jprAn|Z*P9F?TZz9##AKf&`ivcXRn2ZuwB+}h%Avi2*0OD9H}c`0E%lqW z=iW)_%|#FwU~&|kD-IsGP&`&im^x4SO;`LbrlMfhozd(9c@nXw^U<}Iho4C;J&ud2 z=sCk21tbRKLwWF7S=qrR`{jbAiT(%x_Gwo;^CvjZvLQwjxT1WY9`BX9q;dNQ#;7Sy z^RXD2IoUp2W#RI_8c@KaFA=U8l0vnGn-_6T?E=RxSO~FevnT|qKo$DzXLpFZ=Z6Nd zhHb~t+?3wM?@d_0wVb@*fOWc49L`bKTST!H1+}jWa1{5k4 z2KtEuRAfky)bp{w1(lMgrc}S-&Om|l>vSa5YMkE4ghaME&B{)q5|RfRE&YI?ge@)1 zrdI#nM&RQr3I55Bj`N0%`2Y2JI8zrb#wg#%pR~mi4_6gVv(61GU)XxqF~6r7=av)B zQSn3mMMU#T6wEGRtc_F2($F8elq+XSAqgKXDNC@<+cgH6BK>H&B?#mo_)sm|KClO( zb16l>lp$X!U+Fo@g|m_MfVltTpVN6c9V<#iW0eQB8@cIC{FnCt8(ay15o!Q@Hk6j< z(mqGBl*SJSNEajdN%1fP^^jycydr%5No@?^7Qc9Tg4jN-MPfePks_E>YSK1S7@p3| z+LO7xV7XSqAO{h5g>|hp5sL2z@^wXYs#?Y0wCJXdQg7tFW8N1-8Oj=KX%EE zT~RdcF||Y?rE?Neicl!)AQ!%x`M01Zq3>ZafI! zk^Lll(iqd*b16{eH?_|3>a-eBtqU}!7Q45d#JrS=c`Wr}nLlDLHgkjHwss5Ws0!&m zIe_8+q7gm3X~uY==Uk~V=!=6``}EMtpn=$5KFcRYr5spA$W^%H)0G8J9lON{L0V7x z47LM^Xs}h-UR9HGuGo#2+hs3|KCj@wLlj(8y8hG@m`mbtT9OqP?8-MiRUBK~hHtca zGjBb(mX}BBMz5rzo~I9PAq{2?d!YY4uM#zB0wqv1lPCi}1n^;x0^MY5_<%!i#(ITe zc=0K3VLRJUb`eCk9?p&GD-wKvviAOIRXPNkx7`z`kkcy5L)Z8A-!mQIKrx*XBoYq_ z!VUgVb%JlmnS>+5kl6EcT#pFyZth1(<2(iyIcdS0(kH@Uj*O-lT+a|Y=WV_fq(V($ z;%F;rQW7?Ewuu=NEvh(pu1OEgM$Q8)cf`iGdCq^6GO2x(NYBw2ic8TW=rQ4+kV%*- ze7Qk$%5!-ww%JlV5O>EcaHtZP`Fv@Kyl%H1I~R;+>ER$^ZBJUmk)fhc>KsCXTXRJa zp{9k%Dm74M{zf*&^obH8o~M?sGF$ZrKv7nA?*ttd>@J5vq$dpL?Jj!DA1`yp%ocGp zmBusSddS94sLvFQw3Fva`fT~cIZo3SbnKDU| zk_pz?IGO_Vwt5`zT}9^CTd$lDGqA5?H&q5?8e#R~Gwyr(Wpai@L1hLWESCB<6hs^X zJYNiru#R#Xy4)w4}D;#KUKror;#gf;AsO1d1=hvWFN(6`& zFhArx4ypEUr))$Ry%IF~K^DpZi(XpxciV#ISy$oCQE7=ZB&QmXp#Z~yDra0K?~o% z8bYAGC0U5hRHR{c-73xkHwPZrjTC zqlQVTPOjAOU-348lRLF4NOK9j0>D+W;;;yi4An~}$d}OwL4E%>(>U)a!acRq9mo5^ z-jif{d=(*3Td~f`;i3hPaVgU|Dt-u3ufDih>ZgthX{A|iV`QY@gxiUfbl!mYbGEt( zSf842MQmL$J+iu2vK03AqfZAbz^jGl`d7v~;Dq4^WkqiSkXkNm)2}kV^)D|++Ko35 z==tNuPE0={t5UP&h|2+z-WpXZOwz56W_01NAl)5GO451h$goHJHeBBI3Pi|x$&qQw zW`>dfwWKJXM#yqQSl$8A0`bTbAVH3cguRLnJql=|A**iX2Y`ZKLk|DbriDY)|fD9H1BvKkO3g2j&_p<|JB4jB>EL%y$ ztF|r4C8-S<5Tx2D(Irv0lA5>vBkVtD`j>8N91#?$(PWE1#ZwO0q)dIC%^VFLjN;b& zGR7G_`bJU&l@vh>EJ2u;A`J7#biJydf!A95&&dNQIHD7gJ;2No%x$YbQ@4nA=r)wB z9kcmEMIO=1Y32{Hsjv1eRoVqQgh9k;%^s z)Bh1(?pR>XNbZFjqi^<8<+*4kB9{&8f#^MVSr|HGoj!CI3c{Af^4xu|-*~T~KIYf= zza8Ur94VOl!XaqEm$oI_Wd#xBlxMAG&zo2xebedj3XPEdu~b38j`#pfM-cOLf7Hl4 zkTJVQWu6GL?e+wdA!rP)p`#n%*yu&?zlfg;-9I0Qs-j`^@moYn4-OPVrc2Y?3DgYP zA;}BOw*_w=sH+kv*h&KVOUxRhk^Xu=CobEqi^4aUK<9lwQeaH{t>P7Kp6vjfE{$=- zS%^4IP`3!tSU=)`N}T+SqRFU}e*u_W_STF_rXj3Nk{-uZ{KIid_Bzg8I@gSPe`X>3 zBB>CkXR*vxy=f04m0Qfpwwkgf8u^T#plm!$-k5Aya-ceFxzQAb9-^H;@Y6x$cB)`osLjE3xl^V#PG?KWJ|kMq6-Pq-3UGIRG%Bf z-C-x2tA%-TU4MPoPKiOuRaa0373nk{ZffcqYlZUivZSbqCYl3Ay5`gW#+YHU2pj;5 z-l*ok8VR>~g4RwU&oqk<+^r~lZ1ps{Lounm3CuZc))@-1U6pppD*}+{G|sfHnGkej zXU%^ISb&9cRR;eLP;M0}G(ajjwTq2wc=yAQo7)d_RPQ6|Ii_6Js}H4zy}p1l{`#7h z+h$T_R+bpkgFH+5aA0tBYE#}NA6t^z%1{YM$PcmAu(;p?xbb4BNVNL)Znz#^$%Bf* zK&7xrDx?hv2N(%m1qnlrJD%SWe%aP%j>Ch#$4yAbBrPW+S2W zXUOk$zAJ5qbfJT?r91=|xaOv)r_Q>{JN~5ykai+je;|BKV-Hakkx7Q$yV1Yu{Ahmp z0c{nq&P(#Jl-&(N-SFc-*35L&I-c=ih)my^5b`z6Tt9T)I>>@?d^|q5j(H7@s_(od z{Yjv&HJA=8_iUOoCkG=T0l4BdF%FZ%%@{zmRkqi08^afU-T;Q}3Jmy^j$8NTc?9Wx z;B*1A4A)Nebv)P0jm%E84#Xn)Xi_VYLr+n~5txMHTa689#@gOK5lM}e?;~kA@eU5i zX6GqoaRVZtj>fd<1oxsdQ;{35pow|BVq9Ii6TfXh8!#3PW7+cOAQpGRg^vyWcww6+ z3|4|U=mz@Y;-zsDpef(iHyY*`GVUH?=5XYObF zayZ=B=Y>|~9y6r9$|Q~h_9)k(X?=4v=5Dd^{GqH`8%Hx^ z-<^?wYnp`~Vbyox5I(NU@-pnd*l@nj50USe{z=i%gC7cEWS~}aO)ANJ`|uHgT+5(_ zpx-R3O!h*wb7erw3E1!UM`ZNwuWN@jAIp7iB<>U9G;tM2It2*yj~iU%a5J1w@53gNO`bK2{b?7O{4_gl{l}f^(KC6wg0vff(dsz{qmL zBOswYRCN95P~@6$h>=c0wzbO+G;|8Y4QCfDNKd#+X8rguG>BRL^*s$f+!zFCY3?{2 zDTlKc-=FH&v+AdebSAj-jzs_&YI)H4J2xBGc?BG=(gTlhVXtVKhW&XX(8PoD46 z%8yQzRY=Efe8Ua(ULvwXJ&)G`X_bjlx-u<7Lh+|K>Qt8=i!6@L2g?m9YAXNO88%gz zWcZ(g90CE`{>Mt1$mLZ!i)BR-u|AZS7QpVsv_gzwTe)!uCdtjT2f|C(BL-oizjlbn zV{8t}K0W|yM%6z`5V*T!_V-^Sua_o=@hv1iJ(R_{7{|bzXeK2ZsE0Qe4v=;4A|#lXwu?}u;v!qq`C$s>_Ou5M#dg z4rG1RJ*lWS=q>p}^Ojhaz<{v&bP2ju()wCqyS+zR3j*217smsTXJncBn6u7vF^~Lj zbxYAE6j0*j$cdJb07Mr-OcHvobfkeZegUCfyFEjCI<*F8z5}M|c2!?)MKBaaiU`*P z-m|;D7{`Clh+x4hpfUeqJFT_*9`4H{*?DsI7T*Akq_1MRzr_Zc2)c(2!u<4uUMk?? zsYn+}qQD{Shsw;8k93+j)E-;Z(~l~S1H=dB6QpBj8k?Zlpv%ctnc-5MIDf-+o<;pO z`BQML7hL|z$a9A%li>)}$bce9q_P;Z(6Tj@_&iIV9-?OTwgye8Op(+jMCL7=ur>m0j1oPJo}DsMG!`}kbAlzR$a3dw1 zF8wtLE8*TbAGgNWCP;32jgZuOSfnW}HqPH{+hu!UEAo%>QtSq+8NxwAwCqk+-LjBG zA0S^^P>A7GuFuSDD5uOCbLXuWEvb~I0XIMiu9Fz--Ub;2P>`|-pFqKr?AduLFa04K z5*mG<5_bK_htDTnPG^lQ(>45I@N#3%nw5htZOjPjU0(j0H@O09xO29hBoE6H{t=5v zG1l79XX9)1_XiNUf!nrK=Vl>$I~^I18`KjN@lTZwhHCTftlGndT`(|@yHMCwJ5EMl z9si+*YUTfW*%>4YsN{D|CF^;YZ3hHM>}5uEcWW_SAg*h|+MC_&%aB(v)!8RfU~a>a z*C4Yt>?I8mot1s1CH>4NADjU#j75mF+OfC0#f9If@P}!^gp#&a{t+yE-8 zT1^>^PG-=>q2=yry*Z+wV-7}WHwt8RKbD@}n|D&dQLanz{X6pt*y`fi{F?1;;imwM z#{0D6-X%vVOUNZOkuZjMCJNjsQ9FbFXSn+J+Q8QRY(#Knjy$T|?XV)QZm98W zWm$#(55lj`k)M%E=q`uu=Gq|EE<7;*=iFpVXa_x#J@Vn@edPz!`{V})02f#5d?0Fm z2RLdPG~bt8kXmz(xM7;P7ugxM=02DJBoFPTTFlYt{Jj;qKZqOvHl~$^{GrtK6-|&Y zycLuz+*7cQMUX#As2I(%X)-dEHH60yR+Rx|99RRQflvI@hHLgvP+GYp5SS%0+OJL} z5za3qj1nb(5;Yysv7;A8A37y*iMlGxGJ^^azj*J^=!^kK67#%+7S~-?9b%|KG9-7Z z3xDR9IwoVV`lve5JRMDkrEHADKR*rC<72^&6nvZ~KU+cnFz8C+7j^-_H~PX7#rlYMFno7hcMHPR ztb##3PDXB7Ck|W#UuF|h%XRZj)K1@Z`4fuvX)+HCXQ?Y}h;EGeh4##1F`4UA95v6c zN6h9J3o+>CttSU}^y#x}7*pfLKSfc%qt8i4d`Em89~CG?v>G<>!JDu6oO7``$@oS& zlOz+1khT@RNY&Fb5l+0+LX)z&H;={x`V^FsvtQp zO#BlK`_(<-*GPI6$nKL(5*nM4JW;BTRvJrF?Vl|s3-!5Z->SsQ15x(&?u+s@<)Z_q z#?x9kKxE{C`TC;+(RT%yH0_!tMEI}&*2Qq;p61!&p@z(RZdcsS#c{dh?8D=0a zifaw?gFCVM(TAk6X^wd#H;GzANJ1SW#>7V~e^Q1^zTrImt55s{PXrkp!jB1_eu)i` zZag~Q)NDfG%upq2txca-?UT%`tPlh!mf9Xu6{UriL+ahTBT6zZ) z%<-m$0-;QD)$gmC3=vfAQku?1`rH>GQ-27fF_qSBb%CJS|MzP}86S3>%6FDXsg`uK z(RNt+h3y-c5D82-aEoNJlBfxj{{NyY4A%~dRSGI3-a6=UQhN)(V&^4NgUfnvKS?5} zbO#IrD=J{co0a{|w>1Ln;A9=r?2d=7PYOoVs$>Y80$k}R$hbJI{P@8jf4~X02YX&n z*>L^YVF>LN$R!4a$LxBC)g0Nssv0>3plqa!b!M! zt#5N>=;9EQvSp?6^V~e4_@4y)2jrmG67JCb>luK%`-C`$dkMEOv}+$P3;t~rUUt#Y z%RL#4EjHdaH)RZj6zXa&j6k?aIIn|kA?v)A*5~9o@=Xa~+M>=gMYJ=8Jb8Q(*rd39S zYeSyf{GF&w94#vI(Cz5Rj>QkoE*w92E|Ve!m?nepfGSPSF*XppvfB|1@VocWWJU)s pGPZ@61hS8xgix&1=Vr@TcWJ|~F6YfZp;(%l<}bhX1O1gcc-GL3qFev~ 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 GIT binary patch literal 0 HcmV?d00001 literal 96000 zcmcGVgN`T)5=6(gZQHhO+cxglwr$(CZQHi3eLu1N2c1-%uB6ia0RP`f+NU;9a?CUE zsb0ztCzm(Xw4R^OAZW#E*);6h_EV5#mU%!zPS#aFsrCWY1)=r@k}7PxkAq4eg8(I` z9YIhWJ@#Dw6yOGGR)jY3JX&yrt_CJ62kp9B_E#GpAna+cl-vCnxbbt!Q-TwBhC-5G z12d`s=|pgG3P4!^#zS=)9S?nN@g1Wwbf<_GA7XVw<51>QUlFKSWQRwe_FW0(?(axx z57dJ@xWvPg1=y+$c#wvEGQ@VDP^z44C(l=o-~e*%8b8^-^cmjq1y%T?8upJ@PQ58n zFfxUYA;n3(k^pl~@*dq-EtaZOn>5=-qC_1h$q(_RJ4Pwmo+7Tb#5xhCbVo+bAJcv4 zm$mg&$Y=NtwTE0m1A==eCaJ3p10r8~U<>|fn`LYV(=MuR()Zf6Kiv8KWX+3WosZ1y zQ1%i&l$ZZ1Rg70!=yUs)&JCj%ilJ zJPJm__Hjt`mOPyo`3XTEvL3ymKrT&TN^A$@15;#ql>LvTMiZG3f0djur zW4vJ>YG3say5@}~XnCAQhcA@Q(mv8=xdG(QOvJ~jK@(Z-X%KTEabg(<$zIrMTpZHC zQ|S*!*1uy@(6S(2#STek?;Fc9bYR$y5;&r+!7ta&hG&a>U5epJ>@~&GFC}1s6%1!l zvSlxyU@|2Z6@Zr6Smucn?Dv1hvQ5!IjP0$;5whrVK36yZLZQ;=Jako)vNfKvUL~_B zwY~!{t%@%4%7HFizWbW~i5Rdn$@77WV)sT+1@T2>R@=E~=K zW0bM^@c$&<;cnkz*0AK7H$Z$XZ7BJxYc+i-Q_ZgbLhHEKdNxCW&gw zD`M(4?nzjTJhg-UK7Ugwi0=*YF(3-&WCrcqFU+MZO{ZJBmzk`pYdgu__T3B_q#ioA z1Xdl(|8kA56?mwJWZ(x`u{ewl>d4D>7KedGLBBg3spChF#_mx{Rq7&4ZL*Eu@c3#=-A!jn= z;ERL@biUC5wZ2Yw5tHR79y(iErd%B_F#q=BWD94wF6W%T3N%=iDJOm%3mL-?iQo;6 zdW%ehFju%jvkbk76^brc|{4d`rrukxail!uikFxR!_h8PdVs?)IIwLG19PVIZ( zWZU{qxO==Qsui-pWR8$2+*|0?_9oJSP!T;OGWg@~p3>`(^%Z#(0C+yvI`+r!ks}mH zVyy6q;5<#%u{hCr$@`bg%LyaD06*$TwnxWo=e0W}K7sOZjtTiQJZ)p8X%1K1jkgzg zTZsjXS4x!zNUJ)ul-1wGKgs$XPpJ7lG-&oArt&hDn57Jv(S|EiBW|fYD1Ih5C--1E zGE_0;8l|yv`s<5Ck6lkm;cWPKF)m~8Q2=HFa$QT6WT6Sg;2+mpJx8Jwb*(pHIz>%N zpvHv6WZnBRxf|qIVN9ckr3`lhS`ug0zdp+Ke7bZR%L{9bwGC2=&X-}L8)JU_2KEhB zpgSgUeDMe<3|x2OrgGc9$?XY-TICdar5HnB7b>OWN8wS_X$mynA?$T9n9vEDl=Pjm z({DY{H7J&`0+~O30eI#)n?XD4*NyzHVZwfRW&3{XT0!ol%!8S(^6_uGhRJM|fp_Q6E_OBuj?)DY6;@DgKXV9onxoaA7mEl(X z>O%maLnid5HL3yAXmeG)1`8+Z#QA?tbN=+SI1hXaj0bL%HRB;frRq-vMQq@aNg3m( zSlm5FEA&eyF|2N5$lu*y5|eQ~n^4g2JWf_dptm54OET4ei7jEIlRRl=1a?I89ypCm zpOINZXp?LHKL7A(VC*08+^upKQ$=Xct4H9S${jg79_RbkTc&U1NuZKs8WfO1w0Vpq% z1|O~@8d3sO9WMbTFykH?l8p?bt03mtO{_KPCR<9arAH0^=4r7rY>M1A%gl~P?WIKM zA6~IMWifrI#dnBo;oONT>P-=%zfE|So>po#Z)lEZ4){07pj+Ce5lkNo7c(=Qh5zXj zXJ_PNNW#r7Lk-hUFrn`q!bS<-5~02-n$j z|KPtv3a&bjusBRiJYdpi1E{Y?;{NWB#+~f3kxmQuftHErtJW;s=%BEW%-->83i%(Q zO^9H{S`5{su{#RRqxOYG?aje{e9eGTKA$5%L>p{gkSG!u#~(rKRyr!KvXSf_r@Hcl z?WkOCCvK+#LEzT{6_jvSr(Fb>I3{xGLQx*Y6fV;*I}#}Q!+6K6UdV5}fL(}zMOKbw ztU@Obt|_Wp{_QYbrYt1@GhB=B27Q6lN^VI9gD(vo`4~< zFjs$bHzFNsaJgLEm$5r6$nR6EuM-Z8HmOfvjW0%#RBZ@eJg`x8nbsCZGZ)~Kj0>G( zZe?4iJK19!Ly~MG;9b!SWnWGP2U>fiNC?fc*1c+-oWgNh`wT*VyP3nJrT0Z(;KKvu z=UGeORAbLP0!#U*JF7POKQqozKTheTXrji8o0ZV2H&vIO4^LP3n{ zW$_&+H6pxTlcu|vM>z8 zmA@4^?X~idx|H)4asW^4Nnzd=c~H$-V+xfAh@9fu?*J^jxgE)#Jkjoq#S~L{ zq`i=UcVn7)u{_4Gf-)LjAPjJ<=JsJRlp?>h6hz4vk2LQ{w>!Hxi@>vzDO$n~w8_7G zt=|hl1!(lafzNn8*fmQa@EJh;Amz}VraocS+$s1A>IyCdHogOx>%OUFoQ~r&z-j(G zi$!Y%dB-5#ANGZB0=v*2rgN3Nw2KoK-|dZ*Xx_sH zL^#)6q5s7}J6;C&^Gy(L!q{LX$%J-inyE)dG5t7(MC8lY3QkK%hzNki?Vz(6I@KO+ zg$eoFna$p=Yu0b?*HIVndqw527q2dHFE?-PX%O277gMd>V?(f5+@_sI_cup)WUY~5C^V%%MJAuByIk=VwngnInBq*%(FPx~^a zsfkE2KTzlIjlmE39UY0fKim`@F!W0;xY91{v~Ekb0FbxGt{s`AM1_?D|RAs%O37SugGrB(WiI`AXi^bd#@RM5c59XHsL^*?rIz_SZZG31Of) z=Wi!kog9jTVniepXRhe%R{PG&6T0+q>38FCU+q`Q`_0kylUic_CaJ(QX`$q4WFjEPNa+st1#IH5`JtM8nS2%e_Po7gTKf#)RK zod?=-ds5Wc@a;~w8zA`v!O$)u(hBdm_&zSFwn3zleUaTuXk+#_Nz>7u7WTIxRyjR5mu!HMmJ2SX_vf>5gR?rW=Tbx3;=LvGF@qCy~PBA#+ zAffvwl}xs5hM@!67H*=R%wLMmt~EHa|HLvN<`Hn{aYBXi5>X4jUKh3cs)aw$pSc*q z2Nf-B&eA0lh9R*rq;U%p6Xo|sRbL~C4gdQ?Z-Opof#GQ)Th1&Ji~bMb`G@N9A5KKEG^a+m8z$jMU#3^bov1Y%6VKU@ ze+sBt)NGQhXV|r1Oa$lyZMKm>SBQ384EIxDd=6}LRMT|u*Bb4#sKYa^2rKQA)m7mU z2)F1Kr$oQpzQ!KJCU%i#8KJ%-Xhr1pNhr!j1-c0xQzOO80D^@(SmEwcU9YAy7SVRH zjK(Ci-10L8l3?D9;l;`0Kg$8;Ml+>n{S2}}VnZ9uTl$2R*p+E`>R9aeZ~BDhLRg4f zUJ;6=#rb2&8bXSa` z(b1&VE`^{DZ|c{Zqnb0;wla6XLSj!}Zz9}4X2eUEDxt-#+j*nl4Yv)IF7m=ykFxrNxV7irl)E*P^KOP{YZonQlAqN*tBM_>h6A{MIy?RQNazx zzyG@$W=qz>pNN84_9f`8LIc9nRO`k<_B8HH6BA!XKRot16B2+*?13LmUj7vWeh{54 ze?Ho>eI$yO(^w=h%?NA(SP{doMvtb`rWTdVCoW6Hy9<-)Q+O%6sW67QBuoY%dZ@@N z+{H|6W;*16%XL%qU@t73W8@cA*|Nxg;foaHb7o%XM~~AtgHe2Lw1mK&h!yTa`0QLq z0u7QZi1CcD|LW&()YeU=xh|_aPzC$aeR!(YXUdR*WWnw|XN{fSm7r{;Yt95jSY@7+ zRog!yUj*#*s4is&J^x;u%o7>XR(Yfndb}-5r83mS7EzaQ*VdzfS*KN+O}*VJW<4)9 zEMbqQkY&(8O|Rei3P>$kBFeBgE}@Z>e}I#AT@c4@5v$NQa~{{SYP$|%eM=?EDf(>q zyS7L+SVh+XeMfn~6j;N-Y3;~g=7Lu&<@#={k4y})A;68t<{Ib*C0%Q|h8K7CJKY;V zwjUx757-Nu^IbV6If&&jra=aNo_xmwjY%-2_kHuuYxt_}77FivXBnsb?{sgk&1`|L z>W4iU^Gt@nZ>GPj11k5CaQM)az6BFg1?1Q=5IDIJ?OeN@N%K(1J6>X~XN84sk>?M| zV36TX4`#RNi{Yau8^US_68l|B0sb&LUMT@IuyF^@BN|TOray`Vje)};)uuE`@-FH< zZkgpixJs}+w@dfP%g)TJ3HXdZuye9@r`}n$1(1&+YuYcb zy5o0L6O4IGb6f+&<+BvRH`a@r8ffcgw5LJJzUx6EcOW*yLlXZUc^85BWS?C(E7qFwlbj%GZt9$5G+#6M&+YFW9hOo_>_~>^oq<%cusZ??dZsc*FAsVxFv5IEj^33@x?8X?MfC2X<+zTe1vbYg&K-@B*zxKzlD`Z+&q~L0C-7exy)|(JHom@ zwUl6sq41tVD1d`Q!m|ZRqRz`&>Ct<+vFM(cVh+9=*_&6Hzz6h!PlN<@J=Y;l6NuC| zsR&Y+GpWE)zJu$+ryKB?Im6po{i{6FfR=15gONn!V55(}ZI5*-n9sTz%)BwSJI0-} z9z~KlAIiqs_L|ILy^;UjIP!RIGh2C16(7ZF>kv}vhe;rQEYSGkMYR3tEFk+iw8%XH zrTO81D0Luv+qX&p34S(B#tuUeW`wVApJKrFuGz0#w99V^t+8ufX5gb|3aA-y3|!lE zEiRagassKev96{$V zkvlkXz#cDW?Wm)JR0DA=(fPhM8n!&VC`tr;dLv>E5P{vZq#HTie--N@>u*n8>E3Ys zvK0I6$QtiYL>Fmq8L|*+JfhUM#1zcPtdTsr*r{|F;(cgH0dr8dCxh1LTEXGO80Dj^ ztd`5fa8mr><%|@5zymwY_H_K-Y!d%`+`nN(a+bXXs(?ie$SG$3&Obd|+dp^|4g#4T zLX$w;PFm%O1)Mb%IJ0$ZokFP>R0tAif$(&`EQ)2~g9LCW1~1PIhJdvV_b0eLhY{0o zjUl7BTA0i2~}>6b(~-REtz zn(gvY97dPNX7}#D#itkTL;BI>jU%s?`-6Ju`BFq5eBAjq9FFMRz{_d!4d-$8Q2kX= zO?f}&=C%UhJ_7y<;fDl$z6W08IZr&BjSCx;c5yKY2}@c{FEi2VSQvoh`-PuV5I3mj(ZBeg2^4R(@|}x&_(}0Q_u$=x|HS47*NeZ~C06bju8#O7EJ7Agh)+&RPW~g*z1V&Ayg%byO;Xz>tjCe_PCyCBiW#4Z zlZIqm6j{-E)&Z%H;h|x!bnmix7RQE;u4jRd5IsTQffuqVYKOz!!a+r9B`cx%`N!yz zFcA@S6IG&HH}k~F2Jdq8!$fHdMytoR#Y5_Fz!jdwp+E!whGEi>%OpK9YB-n$J~7Q6 zrHMIUYUyDT^?C;m%XH{Kv?@G#^?$WdJv38g2W46jaL*Xi;z;T&`; zG8&G6+j=t`yjWXe{}_lpjJ1Uj5(BWR^5nkO1csTvH_Bx#SMxAF9U=L*dykC1w*nOu z>1$+QeIWMaUU1w-dkr~@H}MjYJoOLP0W39ig#Elpw;%KAe)ykOI z$e;a$KXza@E_iW$Ok+hJ_nnYlFSKfPF`8H|+18+9)4LWGMqmDq`$$|cRQ{HcEloEZ zqsl!FI&#YT;$DyZwKDjWcbfkB6X`pLY!RYfpGl7{8 z3mEUYR@znr0g}H5=FXy(Nj}nB$>MH^cNK>*CYMNGC z0{Xe)!<6c9%cD;@pnf48pUJKdA7N~92VXI|9Tv4^c9lL6r%idtEf)O-!t9ibYl@7B z^!_7Bzy;^Nz8z!a%zE5-eNFH+{y3NGd~S;S50*tEzo}>x)`S1l?J8!YaevK4FOt9x zJLCfL2Lf4=aP3e$-;piqNg^Q6)&B)tIx&^SVc|0%^~3L4^ttfO6au9r4W7MB`TPa3h&$kIWHg=zSd$QI3gaP|H8doKId;fpFuYSeF=Bv>_UL z8lBLfjX&^p7jd7kfwk5&qqhs}+U$_D;Pt}^*QsxS(f5B$Hm=KYC}7YKbHTuJc7J0B z5AIACV{ucrH7K+LTkq;gxgP4F#_Lt(2_4&lW#@eNAk=HQd&e#3>Pmk9-Hdsse#)I3 z)4~52^o1U0_h!naC&WbOT89WY9E#JLX)#W7_vfzuBWG{`0`f_}ifP1h>(R!W=+ama z{K)u{=EO4uWk(XBWUM?%>1eW$BpAwmAdtJ}P?Gy#XAtzjF6Vjt(79U%pYGINeiY=Z zYBjo+w!%%{A!`1Lj3{@(>vFp^v7FESH3D%bh|uz|Hp@g*pP)nIT{!UU2|AVs4lKC( zg`z&Dy5eJgp+b!WlV;sqN)(dvDB!5)~OA9hI=mW{;TD z6Ip+F4}|YnZ|tuqaYePjeYZR(KIQ84)kBhGQ;akY;{Beet*I8QgqQYIR#|z&tDZ=<4H}PGXA*BZwz+3Yrj$?6Y)g_OsYot{0{&mRN!xduJI8V zJ9wwBj67Ug*T_oM$Q={S1j&CLTJ~(^i=cu-0z7*g8#7pxlg`5jW|9@a zx4RiZgwrEJ?r30hpg*nem&O~;qFa?sz%J1w;!z4{3xO}&FjWM=^&|XcCHJy4M(064 zgKOTW#!aR?$DCLffoRi;Vc?R31S8?Sv#UIi85yo}h-lZauK<*YMj#pXyy)P+Qpt*U ze(G@F)Z`~)_9F&fkN0v31_C2dK0&^DV5bg2qlHGseVz@lUxXBK0B>Nx!CK+M?BaiA z0IM<$zPfO`rgjAjbYH-cH(JsMCk^a)szbd=E#@s<`4qonu;~D$Dy>B4w_QiEr#&I~J z2ILOd;z1=BX4DKprpR}Pc7^F3h*3vq13SHRSzimS+ZXdz4H=!~ZZV5K6O#G(T%Efv z-14>8O4!xTbrpKyUyMWTA7P*jDCG~>yxS>rYiptU-IsDX(&u4WH_xoMx60U>Lr@t` ztJXriPf8gH@;MfwkbfcgnxnmTptH!Ny!4L#_Dygkuou)%v#LgjW!g`XB^r&BbDjBq zA@mEd9f&NuPU!$>{3j-dZb4#I-JU>30eRYJcpT5i6X$ZI7iJ-HHJW;%#+f#9aI~qS65g;JG84`9?tm*z z9<^->({mYa@~YN&Y%B9-#x;*`AOV`3oY6?yVA2jxqU6*aniJq~8y(`}RuR#{@4QPyF>b6yI)7l>f4``! zR}e;;%M4PSkxM=Q1S=SL(2=zunR(+vV2={q$*SBU%~ZDf011G)5QPH6((xcP*S#+S z7u!%%6J1ma_o2KROxmAAzsykMGNMysjEBWsSgeY3A4cl7snl{P-RVEx#M$}PnhiG> z&0_o!3~QTCs|?speV~J&&kbs8l9DXDdCKvP=M3-YYp-#cEOQ5=%L8w{mQ0dt^WwUv zt&!!;cAPU)5lM?GhWm2e{t!UK3boe63J;2z3l7&Ij>o@vLo@j>A^0 z*i0~-Nd1Wl=%c&2Nl+S!UhCRyO)elg!hB?bqInP!?6I@`jkEc-8d(8C+(5N|`P14s zA1gJiK(+(Rp&UThm|}&mcjZ4_VVi&zMzuML3(#6){2GDxO&*kLAOgytPZB1T!M!-* z_f_&)#icAMq;{P{=68*x5qRI?AvIP(Ds|mQpSAl7;+G&5#36+xIU0J;NU1`N5J@d> zs+vDyDa*6HXuzq#D={Jb`?eWb&K6SqVCFI!Lqn`*#!|$TP~eOTtHkmcsVmQMhlgt$ zIW4e{Q?zKu%$GD9R6XLvN<0Pb_CSM2LWPdqu)%q^nTQy&?kQS+HKEiijsM!$fb(ns z8=_nklBW%+CxBTvRG;p*d@q{Nh z9eG?56iF#y>c<+x&Xq$X@(&0`A$!po3~mLip#Ip}8y|eD5ZUa$6H^d!YScZp^FD|L= z*T%*OPN`y&4)SPu(?W4|GAs9%bu288ivGjMCU);iHGnYv z#wa(H{G1u^%;r%cfQg-Ov`!2+8en*J@8)YpW-UJ;eC>`~aI z8q+aUZr*v`D$dlf|0vtN_e#0J*wvkSDqqam16r|1qwD;uI9Iv?E+1%w301{BDhEj` z8Dpt2+j38oC_EV?YEjX#U$bVgZc2m^00o0Qo9k6Rj5;3?k1P0=yD_;aTvM;QK`U-5E7A9tiouS`mAxsidzO#k9#6DzIGAg16-6Vd1=E-p4G_4e%sm1 zC+vN?;sVkg}M5+ZY|egRJTvki%d6+B9Qt*C!?l*wIZ# zVFojo%5t^Ge|0d>m&{A3q8dbj?}>j>Ac0RYu9Q;-@35tOI)Sb!4#PD5H)dPTH=QwK z%#xY4r9ry#uts1vCWv+2w9(2q(Ug$LilC^5gn_x5A}=UpWWrWVU`4aNJHs)`wrpR7x;h{ChJFW{1u?_ zQQ|SeBvU9fZPMl|rYn?;Hy+XU8628hd04^&pT$|fV z12YOx!;#|(?)<$H9ZE^Wgb2db`@uDK1}P$TI6>yg%Svx_~ZzF0K-`B z<2Ws10XjF{aGv%GG>)z%he;W=YAW6Kzz0(3xZ)q0NVpXBD;}8PD*kQsJ&`uhNNVUo zV!vMaC4G-S9Z?WuMMTk*IX-dKpc3Vdv;GDQ8g~im`R&<9mjIdVQRT)zS?clcm;xtg z9alqE(gk(Oy82u)s~7DgS%c^OsL9c>L1oCH-|Ml)z2f{NmkIXOFMj8f)K`m;qTbW# zs5VYK$(Pc*w#)H%P^)Fm^t?5CZhdmcW4?%u_|QMAgiPNT;lrB1(NrQ%wa1?t*%FN+ zN=exqnTi^#ADh`GnRJeWc1w+TS_J~1_UU+GYeNnb_?WSuz;?6seL}#$Ng$)KYhkMM z%xk@kWe|n@8mjJLLjT4~yXAf68^?w}L9T*L1Ou(R|9&;$__OL(2?-s|nnE`l>G$f5 z1gKQly1x)vcS-tPx8)d&w`0XFG6NV~{hrG`50Wjq_A;0^^0Tn_pVJ;beDX3r#?d%?2A+F7PHRFi||bZAugv;yI1b&vW3Mx zv^$s(jAi@t1EU>ZThc`w9$#DNjDzW0U(qFlj)|fG;{X@zoF95#%rms26C$~(5K?=- zPEt`!Z@Xj}GQqs(5iC0rEisub))Lz<80!8pX&2C*vJcNE>l)v2kKlo*>cZS_D^p6y zrl{6gR9(Hyy^be5j8e`8hoVlt^B4LUlBw09$V$|RZ&$-#+Q{42nmg${?EO*gX!Ed7 zPY)IZmA6$BU z3gRbOedW^-V_~|X4a=wxN6MfDqwO>&SwuWk!|9dFGwD3E@9=w^!|zNPrCwx+-CmjO zV~=k5@}wL@^|ZJ3a9*1GUJ$RHdp=7JD?y&J#(PRd(#e?qeRzw_bIiSPWylsfGeV7P zm_b_UA^-68$)UiJz3zODnknwfDZ?3vs#8t2DR*Jde#HNxGz;0(9wVUDSuP>F!glbf z{8Rzo5Ro)wn}oUIXhBurKSU<~T48j>s&%1xmQ`KSnIswUI%7n&C7lKKMvRA>ja@WFkog_7Y%5UScuT2O4 z0uTg^_L3|ST+lB!3|KUDNC9!F8qp5XLDUvNP`60xglAeJEJBaU@)Z7KR2Z1dH8VNV zr$WnK1}&GwQyd3NC}l80{CkeAq&^?uOpnXFCxhIELkf5K7)f53uDWKnE)0kUG`e6n zoh2RACKjyta_%aFxhAk45n$v-(E;&}3>>dtxdrM^j^tLoc8yk|5X#XzdkdZM%1Idz zo9UVEsH+9*H1j=s_L;#*bTN%3sOU@=+igXcnL|8@|Fg=B9;wKr^mZW;PftTSaI2|u z?zNs|wajCMbUW!Y`Pjza*NW0iAV9X2Y>l`u-;fc(xT@6Od+1Z<{Zz78iI61u2^;q3 zxMIoB=!UB`EE>TF*Nxv*uBaP%*Yn)AxzuJ)tn<#RSgIa2J#yCd^GF+ zr$2YTsd^zX$VfNhxQO^#{uY-{@Np@)olUKB0POAdk~0;rQSkPcl8->k&{l)7UsJGq z7}c*BRQ2w?g;xz~zT>8#{>$OJ>`GKPxt!4nYv^0cRgt}~==m3x-3^udVAenr*4cqH z{nl2=zz48T<{>-M71rX>p7^n46HUOt2VWhW-f|uOaj~*U$wA=psXK`)N)+4P$mg^F zoE+*vPBqlro(Rx15VF(5Dc~6OJq@{hm;ZY1sFd{a0ek=j?A9=zd_#@%ve#ciE($&S z(_Q>GWa)3We6G9H_^u^7t0owj);xybtY%2NcPw@DJ~ODJ^?SpH7gM93e;*bQ76QM_ z`80i#AH|cV%mG!=n8$K+#WRyy)FTWtda%@ba$Xi{8Mq>_M%0522M1j40DQgQ&4n}O}0%B=YM%@ zxYzZjWve8`Dn@vR&!x8c)~qdlq*rpy^F{P^lZQMNbMCyW$b63GfZ9h*VR-(|s)r8R zs~->pmhwTL-C?S2LvFuX^fI`o;($Sx{$}Qf*D^S}`QE@}*Ze3Izf5=VU?nWx!MAcA zquO1@i8q4#g88E3c~j^!%#t%m+d#*(PFp_hwsy)OD)^#S(UuBX|KoJf-w5L^gDP{S z_=5l$!e{7yPM*wDNHGv%)x_YTmo2MHInKVc-#vPJob{WwZ5|nnG@`W^*1`!M)!-rPG=Lw1)2#&zD4T2 z5270i??_>JFnJ6rBnLAM;xOcO?nN=DDA2_r$G)Zg^b${ht>PNA2PRzK7=KaNvf!9n zFH)6-Z!0VDe@1T;IE#{!5Dk8I$z!-R4%8~%?p2Z`Z`@qN)LGjw9insVCN}k$}Yz? zBEskx!AH5&iB1LXPV4`(=A}uf$LvrOlZWhoqLVmg4ub)<;3;r5AvpjaDlTc3Woq7Z&hM2(`{I_jDfnK(|APUT`bg)NNK<56M@w; zHc8Ea8Hn`96h_?PzRN& zU+4n-0y?YzYEY8enAm(1Zn|B6_a*tH-Dulpi$IEAk9sa2!(vKD_Vyv%PK|qS&+vZe zqJ%nPN#o}ar6|94_{slF*R^5uV(18Gbn~8HHW*Z9l(&ydg?lF|=ZBiKrOuYVHRM&6 z&ln0_vLi5kXXJ6R|NKt0)6YxF+U%pii>=WBtztEO|-*&EF;~$VnBiThW518i~|{OH5+srxDM>;WuEU^WBZoV zus@#6F!OHYLASI)n+M-tUzr;C*%EPwpr1kwjca08!SdQc`58xyM=F36yv9)-gbkLZ zGe+W4kXh4mBDxsUSa5FU>mUE*Z5T~|okG!`GIQ!9i>o{p5fQ>{!^|VoIm2JLy_ZGj zpDc(f`co7>|J5EFFWJ0=1{(<~32Sd3P;;%$Z#s2*tHIf@tYri|$8pgdSVibown|#D zjViVxtzlXq)bhFg+xQ^WVg_lU{d>k#SiosMgDEsPI=bFI{{D$E1AVN_ZGjXGJ7h|L zFFm9-4-4j;T|O~a4~}ZhjZc4P{16{=dS})RIL3vz5)rkSjK$BIDRVgyK$agR`|qPm z6*ZW`UJSJF2OX2*%o%tIlk{73l*B~&LWu*nJ?+xn^zbejFl4zsO9*!Vq;`QS_#}CR za%1NhjinX!VHypD(@V_#XDy^V`}=Qtws%g)X^|cUAd)*$Ty&q@g{_csD-KVqq#W;ie-9n=TRduB{1}&2R%lFA+1qlb!lyii`+p?~8TpCz`L$ky5 z!ZJV-%_#Q8ROu<8=e*}{|Bc<>;GObbtKu$0VAgfYDl{b{luy&m7xd|j+bifP+b(uM;Q0wq;S9f@Kt=$*4{>7Uk-02^4n3>4looeR za6mh;50NKcd^aA5I4Gn!uBsqWU8*B(iNsnWS1-g-PREL|rinxH8^w87&JDJ#%RR4w zR7d8sjR?Cm-1O^dR)4+(oym1FN1brkT~32X?Gwny4hgBq!%g_?8%yHkFMTupu z_o(NzZ1pWSdTmW{<={^d{88?~;v7cxOa;} zLJ zxE$w9rUhM+s}-%PMCOEBpB((K#J4-qd%U$_RxLiY`j<%jHbO-3dh~D3Y})*M_tb5c zD4|3}sb6j$qDSoN-4;wcV`*}N3dQoEW*kL%NiF;Zqp9*OtBLP8)}qRsho(l2q6{NR zIPxI0F1sIs^@qEMZ5KVZekchpK^Clj$#wfPx>gi`r;umE9Aj+sLM>@2u`Ft$D~#wJ z345_|k?PPFD%@i+Z^QrmpUJ%h+K~nf*JJ5Gvh0?HZ(ucjixt`-EYkPhp(-$It*Ar*c)d@nAh- z%B*Bi=WurB4pdctg9>ZR=0S&6CRoiC#aBkU+&sA{=@aZ}Ws(&Fn@B`xTfR!5K7OR089M zZZkza!CwV-oU=jUERrC3-a{Ho&fdcI=LR|vS9a({qL{>JE`Dc$ru27QW(rruj|ykq zJgiLn<}SUF8%mh>t@5{3p?*uyP-#jI?ZjeisjL7M4=n2w`*L}-=N1K{u)Ep^Ghe-{ zFA%6%Kc~4I-qjQe#=tgliyr38)masbKFnQMIj(o^VVW5bB>})-?jo>RgrTFO#7*i5^_3b=*`p|+;u)!l_orxefDy+ z$7I+gIz(k1?^4?ZhV%|X@h@Of>5tQ8*bdS31b#UL%W)7@B<#4nCa)+`!i`@K-tFSc^V2Ba9riqGTs{m7>FHNj zAP}XAb!|bTAEbu#iCwSt1LbbcK2XHngs*Bd)hE7@^o$(i(koT%!LTUop&aRCoyNS_z4cBwYXL;s!dyVQ+Ghi3(H^n=Dn*RrVh=3jy;_r^KqLqU z>jPd2>v-&FR}#dMWT!RR-FKClb(qD}cz{5*Iy7NcDK3%G!bh0XVW7Z|`3t}oGF+?wYfdq?_AEFNGSsp3v< zVSC*FZtKI^efVV?C|<=v*lH+SZBp_bk!V^>s;WLrKX6rRKEYS1kl7Z}QsWKA%d4bz zYrj4L+FmKLjTz%(Q=Ou*Lb~4y^0=XeMGedUn0K(`kjzhrzJB|ZUD!;=0s9^$ZpWS&AFDYRP@ zt^;8mifpU4Zgds_4V{4r0v{bCvH&O}95(1I{)Q5x2Bn1%nt^GcFitBA>8vhTwrZdJ zi2ti8xx2#4gksvZlqf2Np0Ux42#?fWg%N!y>O2HNIu3Wrr!gN@XH&ny^aUpXtzs&O z^+$3Us!Sn1N`F^eUQoCkc!<^FgUvK1lSX5h3;*3U)2#MzU+ z1R65Z==dIXdgD1^#`F(Ar!#M~wT5nA_!Hm^;r+I(d(q1Chqk#;up$RegD9E=>4Yyy;?yls6ofj=0RK*J3iV)?KZgJ z=WXu*^q?iJcs^N7JFd$A`X2xzK-|CLatzlM(trmY@ofDOOst(}ra~-ZTiHF@i9TqB z;-tED0e~1hVh8kmFXvU*p$ZmDezA$A_&Dw4(d~?fJ`pmz{C>Vj(F2c7!GriS7Ic9A zPGujo6*&tj)hhcuPfK2eV4QiZK^AQFhQk=zeudGw3XT&b%%0>BzlyHAv!s~p)&ep0 zzTHH1#?@4@lvNxYwHD)#1(4xb!0w|6t|xT6f)MtC8saCm&?c913`^ROvi^RYC?^q zT!0bDo#HA--{T0Q$D}=C_ea*zG5fdXcaNt)SSu9J$cX*?&Xu+ICN$w0;p#q%!An); zCS(CzGt({%;|BY`TpFnjvOB_|8A+_P-nQn+rbrvKUR(qwseh)qJMSua9R^Z zr5QfeAqG`{l_=2&-&{yL)s3D?CVmXr!hx&9K_?gzV&7+5Ab!`t_1N-pa}_&Q5Va~e z$ahn;c+B{;iw=vzpQt&DVAT^Y{?dlNa+u!%yY0drCJdk}&E1jV{zOh?`ULIxlbN;s zn{f?>d8%?(+wcj3*ULe95|3Mjg00bo14*prXocEavIGpH{dhGydYJ;Kt9QPh zQxFh_kF4Ie7VZyWU1Z&9`!?uBHnuqgQQaNV$z7L3s;f0!OSDRkuPS06GHpD*##J7Q z@dAG@D+~NS_=^-AQNom-$Pc%aM+(Q8`=^yaSQup6Y9O{J2PK^V;oz_AGG=RuUmhLF zP;n;U($)GQ9Vcu>)%jNNB{Gl%WhuDu1eko+X>NH0(Qkko)O4U0jTo(hFNn+2q^od) zO4b9GYbRWuZV_sAg=;n2DYe=rQ4ORGgtjwnh<)@TIoQ;_E%Z&)yV73S-K# zY~w@?fnEn2Ne~RbujW>vL#_M2Xl(MVQ~ac7({SO_!ON}AtS1zthUpsJUvL(r#JAhb++JS;S~10J2GAZd`_z_uY4syYEDtD@rn! z-ljEDM6l+?C})^LtABbf+4=7h^o@+GdK4CHmQ8L0{ycADj#!k=1C=lQV&DYGvl*an zSzH)$Lp^DCihzJ*0WPL)Eb!kNZYR1iNl7LiTVQg4%fC(?G)j}(T&ymuwwJw-$x8Ew zeR=wi*DNtO(Xba?2Hoc3`J{0TorU)0+g8y*c{**713MXeyY>>da}g3C*#`9V5yb}b zB;sYRE9JtndA;R3L7N4C5Z%&0sQbDRN2N59Xq8LO?3a(swXV9C^~H}B+aWm;Pe$>3 zc8XFBuCcF6!`F2>q^;a!Ye;6_b>{N0YB``fR8#YB7yyu#g#pAuGZFl z%mYY*8xqil6Zj%~Ooff%7oa%14j0?L!^3-%uWP2O|*jwVqySztVbtLv3cim)DF`_#+ka0`8geP~ctUPR(r<;Lu;kWRQ}EevtcfM;Me zTEz!m?T88C&$WoTw{7btUz_?t*6ev7n4{cITx?ePaJbH75_3)vE~nm&Rz>FNnXNzw zc+;9<+9FQj&EvU;=VZAM6iy%m=U@HYO+Gf{sWM2zS_uw&mI{{l&3@RtXRsw$v4E(I zIRUT4tA=^6x_eKj0;Ck7N7(V2Q7Gbs-d*4xn{S*({!sp(r3$ZR2=gqtVy{L5yrpI6}q(RPe_njSCl-~qI7@e@5lxd2@*QGMolgB{LF*Ib-?l>KGz6-^pZ z6wxu>zd6W2#;-wcMJRg&q^*8I`t-JIEG7NKJ})Ltwt59y#ahg`eSF*RhNJfR;QvN6 z0W|c)))YiEz%j`!ViMEi5D-pJgH_pLbloHLp4iTPJWi2>veLD6pUIH!)MJRpy2X4f zp&z`CGl8O`<&&fueBpk8t2c?}LhM$8+vN*qV}DeXCuw;J78Q{$3v?EzIf^I>eWH(g zZ(Qe;cpd|GsECBWqICw8X7;`!mje5Rm*qddZ=~){ChvRfRsdf~ zamEWJ`e}^+4Pk{fz2Gw=yEsM-?w<-Rc(JcCggyQ-XXnZ9_wBur*vbp6u%e3@gs7Tl zs>(kmHVH0A)2|ZZ-`8up-Fn`a(bCtI>J|h4ehBhSf4K-?Je7@$)eZa#tT4ai*((A( zy&D`nSQE1dZ;&<_(Qc_!hM<)2MZfr1GFmZB`C&SzaMqT}t$-db>$c*C$jWO)Zv?*< z1O_xT2pPWCv^QdA7N|Pz<7OG@H3LkvK;Lf%<8^pAUA>s^m}v|o{19*sO5}zv!zLG zHf3^Yrn(l-XP((S_zl6ga$0zuLF%wt0SqO9*VAdR4pDuP)ww|*rs)mYgu}xUs>1li z(Si1+;)fCCNy_-XfZug|dv`MOrmi`f##9oP9)dOB9&?M@;L{EcB>28z^`X19x)Et$ z`F@w5V7K&hk15iTcVV&epaI#cj27EVw{$#rRzh=f3<*5}Z`1@-1(7o8hn9t>Lu`1~ zRN2#oa&WKxPKNb-!mKm zCKJ2sD_puA=Bjls{k($CW`4J;#*crwFz->~b}Cf(II6xFlthHUV8~a@SPTxA%#{OC z##F8`i9D^K=z$utqctuwdRET-cy(BdoE{WxK=)C1^L?e&7jy|(pVmLdI1&j4laWo! zP0&jB%b#xCcSBKRY?M}-ebhZO08LRfeA0nZMmhC)Phv|FXonA1!=)?+(uP72X^Hk` z3+A!IIo5SRRR*K{Dkgz!Qeu%~0g33aTiP3=P`*b@=5Nwi-U(t5V*@|{)o2Sb;LIIq zEjjTT+WXQi3Y4z*UAp7+>%X)mL2Y_}h}i3n1$9vmKBh6f_^r1p-{+*>o$E~0W zv0anaV&|9Xq42VHyAKjOx|-lo+H;&3Z<#vpO#wkmQ&zKBQQCc@-$7!MDuBf0CX2e~ zIe;&OJdof34{zbSmDjqmRzdq>>YPCJ&7rnl)HRHMLYyv_!NIuJk-rPck~%fu=iG3M z#Nj7Vqi~Nn@zKnfl~}i2uUAcMF%-LMC-8skk6VV=WYIsGv8T%i3S@}yVRI)j!de}*EI~Y(&AvJlV%#0^>Ewy$VOsDW3k;Hjx9rY@$7$eGBINg|D(r2*? zS5J2agSKh%y{{Y-{?S~F^W+q-~P+=fK?cf3ch3qqV&f>PFf&m(^c^}@&)j18U(AT6Ff_jw&iLIFo< zQBTFcD7i3H@vTm1UIvmvwL!fhYBEy~a`6VJK#UwIN%$A7u7%P=sl)iTc$iC7xGo+e zwcTD8U%yK|_@5oBOuoZo%IEjV%n)O?Y_{mpE)#q?QI#9kD3=gRVo)(+K&VGH~ zM2l`=p`pi_kc@Ig&yxJ3DAQ76wlh3Ipy}`Pm#N7xgBZq_@8+=>+;+e&P(ocTv*aC zxb*Qn4+Zfo9sG^bx zgc8RmY;bke@KAn@f6k8%97JNkf0+Geo6v;<%hn&2D*Gh{TMI0MSzV7kIa_0w$hioK zOT>l^nBVxHiI}R9($q>?KNKn0SF`JDHkRvz<~~^{Uf70a&eDxb+5P7ohRszGx!=t!xbx@^F1j8s8D=<44rCr5_d<($cxc z;L5&4!61hjLE_DO%4?%6%6K2cM86a%vzod>Mj(?i`{)mz(;LF zG%7ualdf*f`5$79J!ttK?2+V1%BQREJ_e+@Qj1&Fz@CmhL52IH=TS9_TmD7ji~9Nh z76KBW#97eU*AFQ*MBLflndLW<#p*Pgm#tRRjt0hihhtOhS_3dy-V0pxEX>i&*PzCU zVy(#@#bBsC>r$xD2JTX5*L9Kr0zzK^f+$8Hy|#t-uV%@~E08au2jz~4y#!{y#CY+J=xH7T$0b`Gh~f`+$V_Oe3`w1D|nipqoYc} z(f{O$?mSr_&3Ccbmx^aBy{$w_{M~KK%iOyN#T!LZO~nabQ3|Nfp*w%O`Ciyqwt2r2 zr@2UjjX{wwK213vWtXM_4Oy-0#_Ru*9wpM99KD`@f`Cc=FAawkI`V*|E3+G*GxPu2 z$Xw35Z&DEdy9!;pH{5>Qj8Kp_k(RH+^=06=Di~R8IZo@78EH(FmMP?iECr9c>Cl~U z)mer2HviHhAv1^r4D7x%sCy{jE@0ac7MBETrlB>=vHtXR=v`J2O#6S(4xLs`!U75p zZ-zd-JKk?iI<~>LDZ7*xccwVu4lfDAqaJkFOzz7PW zTaYa#sKJ1tSF8|-z3}gbMLI^Vlich+YFr@+p@o@L9^FaLhd@}3hlUNSsN;{7;S(hudH)1vZ!*(8Hrqzq!w&9Me zurKflo>T8n#f~||#b z&9-BzJuJlmheN2BQ=2Dyt$xz6L7q2-LJe9f>i%HNe{`K~2+tinRGScaHWrQnKC*PvhpvdgMzPJ3;Qau@>;?@U^%!=2h+x{hKHa z9GW+d2)YU%&m|JSt~_4Z_8F~+z2X$-!=KIA+?E`b&np0L7P6G}MIK#}Hqi@{jm^Ik zCF6SUg+6N(9-vAV)3Z^H?cdm}o--i9K75w!$%9i}n)h~OEm2}E3$$D>XIVOO?EnQu zjWV3ALpV*e4+Dj?3VP4V$@e9AyXBu2nxJ|0YoS(OHjes%-c+Hf@dZA-#Ba@XVT| zs|0DxRtbc|@RleZ=iZd01iGo9^djS*vjPq>(w?DRFw1vd4JCu&<_Tm*T%n&N^Qgc6 z>FO@_@4!bbFp27BoYxkx1)<30I=6_+(XasOn>zL4)&n*ckDxwrE{{vEU zhf?khd`sy8Un$4X42P|3X|XF^e=6C~d{kA|oVMYS>zp<6G^be;;@1VLasWYL_0Ea@ zSLP)Z*|r#S428Fv{{)FjClAT~A{FRto_W8$rUqRISn3bk#k(Xq!ZGBQ`2%R04e~%YsD}aI zYB6JM6bIG5?**)rmiJ)Yz$uX*$k8L2FkkEq^^s2w`pk}~gUf2T%lyIRvqJGu<4Of0*2I4nCb7ql1!yI@r5Vq2cPv{S9k2rL<;Ek%W;$N?P49(2dhSB00r5qA#AU z&@TNUT)_^y5R=x9@$%ZBAV?o@^NDHUSh%(h3*+U$P_o_ClW=+C^gE`#Wt zz>9I3CmILgtN|h{(yh1|{5f|~;9(9a*Y^(fNPH66kL%KEa>uk^D$L{%dm8|bVj*Y2 zhjIocpS05){rEEXws8T=l#Ai^BI}hsE)XANqA9p;QF*$HH)TEnpU}#q*~je-d^PJs zBnty?Ejq&(=gx@&MhR9$l)M({K6`+u&95iZcd#4jnEY7YU#&0#npON`koUzQB!YjO}vy#gn{)3vD?hSBxb+jO*-h;3b1(=in&hJO5^2<4) zjcaYSHb(#%Nq_Bt$Fg}gt-OYW$GZ+dsmebRqqWqnE1%vigA&i_(3-<~`a)NKKyQNc zm$9iz@2yp9&E1m!;NgER-}|h&sv3cT84K{eSO|(Y$F+crjgP_~#}WRQBMVZN;N!EY z<8DfAYuWng3$3ary&)+lk12P9Z>0A;b{z33+yx?$E>)@2SD8TA4GQI!tCLEY{&p$t zbTDCC(rdw{5bGSjF}y=ror=ClOQ=AHkC=vTv<_q@V%fRs0zhl$q@8}D4HzR}*jacCvndCghXdAg z_b;q$0$`=r6Kf#k6zr3DDulor@*1G>7l(EuBto9|dzaQw2XvTJJa8fa57wBh*qdOW zYSq-2v2nB|Dpb8o5e~r-KF(Vm&SVJ{*-qc15(PN+eSr+s`axS@7mcNHiK3@#T5>`^ z-SH$_B$IfB*`qCg0xPh(f2$)NpdIPe8h&%_jFs-pEqGE*SM6jdJbl&irPt8J_Z8h= zJ8DMyjR6OxL8E-2L%K|t;f)fR>C z6yRdy&4_p*btk6YF6~!wEaY5pg+Ot; zbSvH;&TL9Qztt*AF|w3LTZb6YwK-BfNGV4@a~FyQd4M&4&N#u-mKFHm6r$sukmGUF zYEGykBU$(iGLOPslR3BT5GRbX?PS-6N+8cvDmC8hbgC<0Y^~|V+1Z|_Cy&rJf^p!Z z7(tnK?ShXnBX%zdy7kS6oJ01V1Gm4x0-J^!!DPpNmlJA7**^52Gcmi4?{_B7ZWc0c z%tYP!2w2d>U4G3%;NU;viH>LpyP7)AHEA)dGplWiMaw7qs-qTXS~NE?#`0sR&5_rB z^@nPiqHMftwU@RX8cdfw(UrWv*6$Q<>G%4l@qsb{3_YotT*R_RP?@vRZ^-J7wn+MzUAj8q=~6X(1;A;zJVdR{naJD-Os zML#;hBQhzzx*=;ujGetK1_NRCCam-%OWwk9mfEnIuxLeje$j)}3?9$Xu1B-AXF&rP zMLCC>zy&RBgRR^!$BwZa$AQ9R#`G9<^dt-0nTi;mvHMS^<8U_Zi!s)K6?sEX|41ng z3*+nLvYU%5B@_2nceC4>({d@%pLZ5aUt(j(U~VL{1Xyph1`)AD@rko;3H`c%0s>Z* zLel6Ue3=1{g@=$ZQv=-2L*cz;wEt{SZxoKw5UXKn&zwUHs$zNvJ(n19>bm|)pCtDq zbQSHb#jyXYa1SA(FMpgi;5%V|;jJYq?`Di&$ZX}qc+b>^QA|Pdrb+cev&X9~?1I9> zF`E%A{mvD$WQwp6aSv=j@vrH{a2JsFZqj|;nBLjm|GPS^Cjw1DhjP0e?h^|vnYBKm z6hCj}qj%5cJVLYdVg%xZRMe!k1d{t||I*LOKQF8nqw9is%8mrDm4f&7%mA=}%Q}CF zcEn8?hy6CFGflWLz9yV+VMN1{wM)4)F+E?%GVDRp`J}h%kpvROZEu4W zazPyv4(?19*ear)M9WRNwd;%su&x!1-j@xXDY`a?fU*6bCrfGMUGDEVzh+$~k+XGY zGEJk`r_;O|}k=vkM`r5y?u7kOa&Q_a9>$WmvLa{h3TsgR&CRZ+;J} z>#55xxleB6P(ZQob=s9kmxgU4=LW0e)7|5>MMw^fI5! z-;wx)-{Z>tceHZ)#j;RS%5TkGB~lEoeLzcQXz`leoDIrqT8PG)7-SEDo*>9)=kQn&m#~U}!c1z3VZjEgFExFl$o;{PEWda03Q^ zzYDt8giR6mRiZTAwpuT_(`Z%!&(QSEm?c$ry^XUsf-9(fzILjt%u76kOPDNT#`Y1| zpNV}~T+8LaO7&#t!MiU+B!Hdn9_qRC_nq47)i2tF(s8aLA@p0Bj1KD(Q`<4V>~G_y z=jLR`-~9B4Tni_|z%%ze@eC4dgD#r6bh-H^pWL!G+j5^4Nuk$1UsNGOJT8ch{et9hq=L%d-{McQa+p38&9)1_G_2^CoAI{L_NzT}d}wz!~SX zU7F{{E;K`~2n0XgH2D@yhO<+l$@{`-7Jp<}o`~fec_WXt`(fTs6gn_m=4pS}FghW| zV#|J?V5wn>B?|iO50ccq%8B70N9Yy}ixV*rEgzyOO_7j{YZ7k_3|(+jeT%9tn@qqK zF~`$EnLc1s&Ck$U(|mT!UYlFu0g1+Me*uW^*CE~ebCP-nm|KO2#QdBDf?BnpGa>pm z(fMU8{47bd7OD21-d`kcXA$@RBf4p=`|CNVOSx`{B1YBI&YYR0Uy5+B`nmH?r&4r( z37jpM-E{=*SnZ?BO^ITyH4wZao+n6I*M3+Es7%6Q#9<=rW5=*fC3^MVmj zL%X7d5b>WPGZ>;jockolB5>7KNG+q9xJd;o<~Yuq9{cE9`#IRv3z9=T4;eD(HQwAX zUiyvw8iw2Ee4CiLAHB0})mzd6;l)Nto^Cm~7D`aJte=6-qNT-u`W>QiV8lO4-ZR7P z{28%{)_g)l0-KhxqvfeLxr-Q;cVq^#CMo(z=?csEs$J*dPsyKh@o%gA;gX>b zZXg;?_HhskO?ye{wuGgSC)ATx!)*)`&>r{)E!6}tF{{64ZDEBJ)28A`60eL3PI^On_ z#6E84b0uomoMPKa1DFW)MW2iwsCkI>t>J=#Y}c#d6{Q^|E)m7kqn6Yb$MDi=*$9;? zeOv}0>VcmIC$+=j4k;r8*C|H<LTR}k7)?gB|Cp7K;>6WrGs<+OAWYnD#4 z-T|m@lXYu#vjUDgRq|lq(s4j=b_}dWsu2wVm-p^>gKShM4NW5{3`ziv(`CN}umQX} zl*!c|e~ZQ{n_Cp2Y{KR9s)i7~k(dY$jXMm;vaEO~{jL)so;V_x>CNxbAA`mNA z#f=TgD%_*kGm7BzZVEhDbHpcRoXsFPHa7FmTO%ig`zVQU3jrG>*wKa2*sYU3}64Qgb6I<>j-64WQss>QMF83-^Nvo9M;v2y=M9VHn;23FqE*|ku*iDGd4nvw5juTzyTJC6$K0wH z7aGLtw)!K-MTy2#?8;4X{d!?e3fogIm1bb^d{y{!xdOF6JW~*Gij^=&zBQykh4p=y*X&V5}pGv-r3D>Me&MW z7FM+kB|*kuIZ#C1wh&5>O%VBzAb~RtdjdJDC7$2Rn#l;3rQ7${H|Y_Z)NhX|+g08w z$@tv0KbaSLs*>{#S~J}LP6h0935R@=H6iH=6NmLDZRk%;g>|mm>qD=4H^+pESlxVX zn+hT~Z@!lwu1-rq9PKj%YYF62=VZHlENl07Y+PjMt0o=V_k zxj8q4x9A42t+MBcyse^Eu@_I6+>I3AbNP48Tmk9=pLN>U-veW3fFn%KW4Mh{(d8lK ze_9_RQ+S8A{Q>X$Vx^*N$mNzxYd0hWcb&TYsZ+OPt|_h)V%bLaL$u+U6Ze7M6y^{< z19alu@1G? zkPucrV9fP0te9Ma?aLkZRN1%)O7(p_Jj@NgTw3xb)T8}0L|w&M5zbq|Jb^%;%&W-9#sv6TNaz^fWk84;e+&*}IZ zltHQ?4Xj-?JlU`AoV2V!VUG#~jd_byPMY_|L#@S3#Agw{t(zh1^^}vkWB)GNn_y* zGwC>}A_>#ZB5J`+wzFb_heROyzTkY;*sbr`=~JeBf2!S5Sf8J&UZw@Z&5^&+1cuHVfDxV) z31uIAXQ32zSoA=R00MoRmh9dRp#rLbgCX6}cLbaK0UDC5q)T@6Apj!*=}_@fE_5TF znz_2OHUZ5r3EipvzPh`dx2(?$GscwAlpdl5ncF*bq_fJx0KTP+s3(nsK$##PvrcJH z`lD0QZlflz<%lJx_6t}|>E#N8wO>?(Yb<=z)Ldl4IKd>^ptb|}&)rs+@_(Zc_$ZHD z_Le_2Q_4>o0;okG`p_5x6iqFx5lvy-j&O2^qO3uj<1u6ESrk(IRP@i<7WZlRvRNOX zLS?d5!2ulxfeq)bH5vpS@dvEw$Lvy5l&+R-yD_-~{fE<}3R=vBIm}VuX{mQRn9JX| zF^Irx3Un)ugy~z&2LJbplw<04<4DVCFNoA!?MHTV(aNcn5&AB4t$CD5gs7$$*BM{z zDU>kHjeo^ZKMC;Th?@8bZY(wX1enQgT*;wjkg(Z=SaoIV42Tjhp6IlPrm83CB#~#( zbHer0a6ri|q71Ek3!Gb?&Vr5AbwR1)yuYR8c6a(YI)>e-Dd~1m5CZip4`K%$5z3nZ zd2V22&X6^A5AZ~rB)G7UQ;P4SDSV-Dk(YUHL?^dvasiaBi-IZJrA5RkZ9ARe`cB4~ z@Z!6nW_HE?N(s!1Rv+{gi#B00P}f7-zjg#_z1WrR*%oOK6$x*oAs$W^Nis`iVQx{u z6FHh&_;C*6aMz5O*h>#P6Mi>F*R(Z35LD_qfUFu7JdCp)2OEkxCh}Pan#ga?^nq;m zu|8#L0pa_EH)!z9g|ATn<^$lbJ~b?}r~}wxcVaXiEpqB4P`aST*<78$O35pbZQHaX zCgAV-l^r2R(ku!TpXFnanQJUhysduakLel(onGByZA-YE84U_rG1Sn*%O}cJc<1lk zdx5uBN@O&^lkL+uT|DLscLdFUfqZd>hG-|5VR1T3J`+FVGnY*1Mh_lNI&xW^iMNDc zK)r4KkJ_@(mxuBnrL4So&u8az%3&1u6fCfeS)O2wE5Nhg(N94AqkZ&I;R`RP{}V#p zhroAT3?mw+i3H?$(6ESI*PW_4=Q|(&(ft4f8A@mdw?SUprN?BD*e@0vTg8b+&h)IF z5P;i%45;}W>1o0QNw@7X%dF(2&{Oz~1vW=~Dct(!0b^CP;$%E#$PVd5OMl%LXbS4C zz7Z3$iRtno=FN)DzbF?%<@+~puGVZp7Sh91$>P?!{D=uyH8lpLN)&Mz57FlDu z^8{a-cL*Gyh|yCq3Kf>80&d)LkLj<(4?%pUi`a#EjB4p?>c1e_m$;3nrFgNN$tnoA z_e<|o|NOaR-Z%Gq)j>*;GT!ntKeiTq2SMaiV8Z4nb|s3+Eff7HzNZ9+t`7e2K$~Ng ziU1Gt@tLWesIXD6AqyO;<+}9>>YpB+8Q{AW>7018WTk1C_a(fbfcdZlDG4Qy+9L=+ z?OX@_KzX^Ncrsi^>lZR^I9wCk_au{gZ-dn6i55CR;QKmh%eR9EM|3)_HP;6gxXfqb z*v+R-vmC7^mLJO-*+)$=jt)Guw5_XwlDM-qUgmva@w09leO*~rG3xJQlgW>fFIXaH z?B`#*4I)l(uzXZ(6HThh-JtXQZF3nrzW|p(^gYT80CM1{ zn=VS!k<>kVljbinYoSzIJr%4ZfyZ-UB=6>&D$$sGNpz2cEUpOFc*h@mp&yO|s_b|| zHXy~D_i){Qpn-~p_oDt_wFjsvv4-`s`eAKFC{mAuXaJV_{c&Q?lTVk&#)PRgGgSDN z5@rW+AH0{?!`!qs3zSZ8yY~zuxmvQ&(%P5x0-)p~(mR>yoC9^TUv8b}oJIHWrtyf9 zLjvbqKawGGi{_;tlo}NbRZ_0Nb%B^Mg$Fw8SXm1D-NbDt1e#^aT)gX15I`F?@Qsup zB9B3Pb*;m_AXk~ff9alkS?)hv5v)Wx=xPt|s5R#+n*43Z@<9!r!qMH3kdvzQMa=?@ zGWSYMYz&nzD^`7ALnIm<8U>Ttzk?w)x`$rcCwtfceLywFEI5@JHzIJ3a+M9058%*@ zTqKsHz}5JbA?I%IGKi3QR5I9UPl1!#5We&#bU8Td^y>=1)#!oMz6(`&CtNl|Z6kTr z5wgu#fM*#NaRJ*e*);15W$!qS$$kR3SVe@kycVx=MuCS!$h~mea&wtF+8^kXGUWAc zP||)pA(S@z?Ju32!9X*m$YkX@OP=Zu-vJQzOpP%Ppm%fK#a(vUf{9N#yVaw1{1^dB z@dgWTM(5cBAR>A!sU~1h2{-8*&{13{CZExJ9cD5wmwpV6%fOdY9)g^w_>b;}2ACrj zeeM89W^cR%Kal3sex9Mqq)}8(+W8Ecr0#ijI;uvvPwWkGv;IG9)RIMVUk>0v1$fzW zEhD;#V7?=d?ku$t6%q?n*I+R>y8Dz@S93G+bfma%YYYO>U;JO8@R`>&jt};MG=@on zA%&&hIGHp3SDz|z#$;Qb6VL!ry8z=D&A@nrHKWk%n$@S1g%RBpSKpWnHZ{nHyOeKW z111Z~O-2EBL0W9~3!LROEAz}%(f0%A+g$q=mHUfsy|MtXQ9c(!VAGOaKpZYpqL}(1 z6f&c~+1*fi2(~DQ={$aUspjc$(y>w9b($y5Ll?8qZ53cjzDC0~787`S9#U2%6_8aY zc6i=Y*x9q1XZTVM2orEywPsW4WS8}=Op3>sAMT~l)bYm)c5BLipuCX3oCW>+X}_cW zV_(6DY)Nn7n5QO0!2+&WH?m!@Mir-X>36}ZF)Du4P!fF7p>k*1+j%00iJ4^?NExxPu*)+2=titv50jEO&44 zJZPC1k9*$RPYU;E3>Fg2AHzxpXWL|cnse`VX-CmjV;@CPU#&WwSG z3|8+#X$U>=2C-Mc`!!Hn5daU2X7VLvWUaNrY#b3t>{OZ`h-%sgm?KN~F1{Z(D62{P zW}pN2!@|z7EH7(`$Z_p+8y|LZiBi!WyJ1f z9TybXvi-KsE5H0{kvu_L$|#|@aVZeq8>`R+5egYi4S>qZmy&x$It=fx=;57$J{lvy z1i%#X!nWkHcWIZ3BrK%d9K=v?6SZZ`Kbg`#3%Htj+fo~6|Bj=ZxDH;JG42+Qnby{R zvGCI7O?;s5P(_*FO|ti=vj=q2jq<z85-T2>DF5P6RI8; zn|YU&FN+cerq2S+hw8z~^@OgHD=3CCT#DrAlc>*&W+bdbb~-prV+jTAXz3imC0|Om z4wnfquZmN5`+|~gO0X@m_rc_s*Q*eTS{b-#7)|Np74M~;guX@mN&@3U*vIJlgTz*` zLywM$}I>eD>57sCG+@q_4105z>Dc+OHb}FhZnnehiIujgoz7R!-yYQK9E$>g@1dYE% zkyNTnvrW7k$`*{qu(_6DR%z~pV!<$V9WolSnx4A)@tH=$&a8VqiBG9xeuZRZtV`Gx zF)3Euc&;;Zgs4snTi#Fz5|voD2pqX9y;G*|djkn-?|^=LViAXrfCqee!7P@%&yNWC zRS5DK7`^tXCSUth_di%M&7Npd6Q^`hZ5PcqBMYtoK_8#EPxc&|s41my$~8#SjHnY| zpi5G`JxqJNGSj!`Ke-J8;I4;PYN8RLG(C;{3@AyIvBv)N&c6w6OhZhE`<0iHw1s3>rObCauMqd?ehsK?!Zd;(P%L= zJnUv3RP=mNDmakY_i)6^{vf6Jv~x?=@s%AN+)4%Vb)*R+ok$#rGyLjmTxvRFpb#N+Wl1~q*B z5@rUI)N zS)8X8O(nJ;Y4=qO%L?T2YopDr;v1$`MlQ_kA61&F*Syaz>PN&i_*`SaU<{Fob5Hxp zBQ6vzYx~e@k(FosP>5dajb8`-7;=gxVJ_0yo7w{nV@EuxqpoTiw9e^LQn^lEx^fBg zbJM~$`Vq#nRw!Bkw_dQR039wSDN&bzi4B@ewdJ2rx@QwU@_JNuGk;2St z5RtntTy4BvgGp+sXNkvju9spjF3(bF49Ze@yx+3r2YG`h4SAH24gVX!pI`$6-VwMn zNJ`Jo(4e;ov~|f`b$Y}Hh(R*KW-7xdHW&WN^4+2CNcbARG;e#vU!y1TH;JP3n^`&h95gaD^bdQowkuf&ZD4gwRTQO^IUB(m#ru_ithuj?D_(Q$^ zX`0bBx*4qvA78eQcy7nL1rQV`h46uxgutwP?tK=I;D0iE+seM*ql9gbYBkYR5*g?d z`@)~2F$?C2{B4YbVHReW(H zW-&IjCjz1v+6hSms2)mn$7nq#r{HHPyrttpqDZg&FDSrJEP^2QbGuf3r?1Dt5Ge+U z8m^QR<&i#wbjsuke=B*fl$p!~H-R^~4o(u(9q(I|+-8C2d>aZjGn$ZYyZ{7V$c%zU zY7R$H=Fw7lZpZoe?)vIPo&oMC;;s`9DDP|XoTtsP2J!^$zA4mNhzhLURlDfVrwRN#tO`DuYqRsp z6Ycz}ytT2prg~Fsti&U@vDwZ+ws+ON_Xk+AYoC{A&|w$L^rFk?v8~GBY@2O1n!CLm z<;)AYD;E%e>J8g}j5dH0!5%KMDhXp-e}VVKnb4sqXrAiB)D)eapxwm`H7gbUnb#h; zdb}XzTgCjU$ZIXviV#eDz{!c$sO2Z^Zl%ney7tX$>Z*HTJb*@ra;u9IU?$jD@MYLV z^-U`ay!h?8XVN<=BSOx88Uc@HCd_mQC0K=M#1^l)OK zMdO>~(cdF|^Mg}-1zPEm*t>-YK>)nEFjdq!SbD7#car=^lLR&Fu~Zg3k2s$N6?SIM z@@r!a_)QC$w{Cji;o^C&{F&+gu4Zf)Z!P@AMD|4gu!>(wX_AqCERpO^kP~P=2K0|l z{MQC2R`31_fV>-+As1m#NEDX<`wdU4Tl>SW@x<^D+sS@yLpgQ*2_+cr>I!(7c_9m* zY85t!v7}lM1(iF-AnLU-omAGIGo?8heB^zIBs zYppc_(FpK9TS{>RGoqpNdCJ)MPO{Y$f%o2uejKZQC0*Y zi?R%IJT|ka&Z*bSeDVqOerqvThZG&F5w+SszSqjV_#&X%i^YyB9-xi0TQjW?{>$ye2bH$ zayglHe{1VnI}`_1VV?#(S!pW%(`6m4SZx(w#Sat+Eq34}7_PLM?>G0an3oRBMsD^q z_gVn^>A3l|P{jEm7J0r&ErkE8jSl1@+o>JRg*K;>M+Qa=m(9^f;kt1-_4#Gc?_7FI zhH-a40De9ah+I3Xa+{o09k1lV|2rUnL}D8w=C*E+mmgNY)z#dpoyFQlnrhCui3!Bh zuWyMApqtk>y_EdulEvPf!_B1$3DN=X@edQ&UUfqhO)d>w;wd93vyua!>BEo-+Gy>p zG$-x-sbBRoP7(k$K+38Vz5Q{j_h5Sy!3~YroFed=gaKnA zegdxC2oDX8OY&r$EFxVbfYc4M9WdTY(zkhP;(=>%Fs@iiwea-fNBegd!KCs9i}-2T z2yv4q3`3?WZ*MlMtIC1hsFTu`RO(Epl&6IM3(C^B&&!m$#w^i`WQ3Tfg27vkLHZIh zUWvmsLO~-ObX-377U`BU!nh0F;&r1sE>7G^n&sj`02!7G5+4zQt{LyI*uhmIH*1Em`atO$KCbL{OVpH zeW%mQ-Qz?o8l)em@|uAAV$2Y+?cWWat?{*Ku=_7nQ*Q?%!?EePYwmB&$EK!*dl98& zMRd#9LE^$-;LLp$76mH(R;w~6w9XCSsQfJu8olNC+i!+)ZZ35eSn`=X|4OO% z9X}6mL$WDjhWM0t#JKSrUVJe(0ZxYMod~F?wID7DiFV3T`Shu`3umv$?j~)65~9~1 zLe3~{TCIW0^rLM7otLg08rcOS?@;V9u(1u$8_)Th+p8?bNZ{t7K@iLB%64$vV@`oP zNb`qMx>ygk7wpx1h(?8FyM;*neM|U8FpmB4Mx5>Z8v%{CL?00RX8t7-I1^k8X!`}i znPkoPnv{#22v`;s?f+U?Rb^PscyIubpU=@XdA2nri-+JUPpXo1BQ%5z1pr`JA$f@d z21$URf4Za}Az7mZxp2|}s@!}f0z=(XRW+zWrfmKuIV6*sxy4zLnMN@b7z!(}n;!~{ z#i|IY&S9j8EqiJ9pJ$wxy!&MYDHHw=ont;@<=W&J5iv>$w=-=o#uh1&h({*a$#Ru| zd+R*=PN=?K4}v;T;YXg)>i_6A1C?jqE|Gdd_dG`_&p!xzPac;55ic7IdEOICN1ryR zL}TFr9xDWkN=kW_W-ziKFX(?~UsYE?C2iqnnxp)R|y#EwO}zJUZ!-?M0

$9U(OKLj0MtiWOqryf2L?iHd3`go*TxCvWFt-isxDA)VQ zVDWqTyw{1YRh{`(oR!^M*KbqxhP2L7z5jGAM`8@fV+MV}@DLT}z~Py5MNz z%lQ*X*jFK>Hil5M^g9+qn&xTxf*;Ca-ifESn=g*RtsJ?Ks6=*Y4ijHO*FaR1`_Y%0 z&NHtDIDsvE+ck(MxqLvGPxg|(|KAlw?Yki+Rc<8UJ7&aP*|&rX< zb? zXhHzm$Y&PINcoCUB6bp>JURZb3U@ZAR^;0j&ODwQj9e@seU|YDTsS=lxWn+-9Zjx> zCYq9kt&0of;3DW+4LsRIG%`%wC2y;41f$LLw=)xxwA`!6%}4fl-0@ zVNo|mYDZiTkF#BE(dH7dpXC(TmfMdEWGU`u2fjCxAi}W|Py1Q=+$RFg_a%S*BI}Tc z-I))yfs&uaB)1LbDaN4+wbZQ0p!nBTW4;HSz@mJ!=3NQ@s5A2Q~mo99}4i4_g00752+U%32l7SYUl?~C))$x-W1b^OyEA;c} zvs;Jcych(1zO*KpWLco_q9DiRv_5k0^1M4?Fv+H0DFZH#tP97r49Z_s+pFxLbMN^3 zg0>6<*QSz}3fR2OYYjw=WO-P%@%mR-ez#xb-EV3;QLIBP;}_f4 z2Meh$VjjJYBXWyZk|$X04$~_N+;O2|d57o@qfxUnk#$X9O5vW!$W9)fKs1lgHk=E_ zVUjTm+EgdB*GR|J{kTJT?5GJA(jm9{VSX}mLRco*04VR=2t=G3-#w(Rivs1ik1r6F z^DN1eU-oI*&(FDf=?1QVZXrs>5U$TL?<^xD#p#}0FGtlc7p6Wf!?|@Svp` z=XSUtIBru^`%ng?U+Lsrmz095b!&6?UL(ojI2=34`RKL+`Z4q5MtI14n!v8Koh|nE zdFW7iyhNc(dE}qZ6pQeUvWT=LzeIiZ3#y#iq7fmK7U;zfF$7 z5%*-gq#T70{PZc>%NgTxW)?WLKeE^;))JrP04AnOATMc7$s^6FtnCfla)$;g8L5gR zM6zqEzl(<~W?I}5if8N5j?IouI{b0cFG0^8CDfqzbxsQg&!6Be(OaQpb?p8h;=-se z(R33%*d<^2&qr@v`&fEsX6j$QX0RsT!7H**1ocJ~T9kmb$-=(OPF%xEi2zkL^x;J zSe}f~fudFPLcNS%E^RO7W2zAZ9b#)4W2lHYO|Hfo{?4AMwDf3YWZ}-qeW%Te{baim z48cpJEmBg)Wq{5`#YKWbUjnbUI4uLd4@T~?4ry>FlV%k_$I_kfw0}r$<@*a?bI6`6 z^fkkl2GU+n*lj8>wPKRxPmY6X20l<%4v8H*8|+dZfOxR1;3y!{%jNUBzLde6bmZGk z?#-t{(2PN|{zfN8MrR6-2q2$n?ryiFx!$;1WmqJH&Hf*UiU4vHR2XIp4PmM2^`y|F zl^Tpm@fUMlwiTdgk8b?^uFvt9$|TAAZ|z&rQe;kq6LyyLgL+@?RhQJazHm0|4R|X4 zwRjl#py&c|eDz~6Xv-o-gB6J8S@-KPOnl>mrG7wgulX(z#4}m^Bw)K`VS+K~rAWM& z<}HHxYk0Z)$|rT+{&~z$2oDQV7Ek;5ukFQB`>g3?P53UrJ0J#vJh4$uet4yPALSAN zgPPPrS8tA{S#eBI`ne{eE5`%3qN6#Um6fU$DNXi$Jx1DcweHlzD!UL z$69uFSIFu}bR5^Uuy+{c4k$?5Tt97q+*hQ-W(S6mFW|6|oHj$^XQmTAj0446+^)_y zvjk2><{G+NmLBXOR&g#aH|2kX%zE7EMWNsZ!VOv%t|85`{brP^!IY^tqOhG4Pd9fo zt6H}4!p_fgw<3m0^@GD^wON<<$8`9u10jkYEp8;qRzDT|2k7JV9JBAnUHoP_kX14Et!9_;|b4?h5t`h1g&z?Wt&+_)Po8cgfXCQJ6%EvcgU z)s78cAraiJ$LIKRvw%xAQRwGO+BygXjU5+e;7Vl@(6?=Lmwdhf+T=f^H6!g3l9tkM zqvQd!C7LR8_bDKGodG_)o>7wFbKkhpzwT2QVp?$B>kFE17F-kt;3rziqGkX>tJ$|e zlor#aC}63TK|V`Z|v@tqS)4>eE70?GB>bO?MV1SGx|myH?gTM z-(f}+N=3b_fil2YWr19d&BjfeYUXGa2OI6j)qD0RxrF*)40h`R)AcfX=l=sS8~`~a z2KCkPx~C6n7w^S-9;D(u)~zQEj(&9!0jY{>23tG`br5vyBJfPN%oUhnxwpEV(kG+% z@;b|XUzZtaM|lg{8kPk3Ff(Idh#)yeP`vj#TPL-~8ln#X{pSZUK!6H{Ou}?BLPwXT z)cAR~!=0n7(;ZpF+5h`*?WhVt3cogtZS2P#+UDOHk8`C22}C1vFceWpKEKy^N6pH* zcz1P%GCmS3Q}!kYas|byLzHw;01qcm8DO*dM(F|RJY&13nvluU@G}!u%CX0iSXdFo zKXEr3*i^&6_0F>u?y4rQly`~hc7{sV3y`HR+Cp%WhpMQ33(J#uE|*(llUP9(T()ld zAs6_E!iBFTkF#e^sa`-uybqWJ{15?ws+cr7@2WeqIG{mzG0H~rm>m(dc!#S?`4l6h z+al7yuzFVX1db|$T&m?-ZKAmpB4qwY2f6FIT$S@$q_{g%QYsN`Qm)?IoB4nS#hA8R zd%ypf!=OQvs+RzIqks-Exob2U*}Sc1&7uqR>tR8mt^SFnTB_{iQ0%q{p_ETA?~e!;>Wq*8KJ8iK$HDA* z-pheu57w57Ky=FONVAJe7hlx9^cu?%Lppq{`WS~V&d~JhNtuw3G79z{E3aZ7z2_MK zKi-G;WGN52RB#9OqcRCKPy#I1zd$TDTmqaIzR(ie{CGL1rI;Q~x_qC`#@v+*k~8qI zzFwws5Xl@*&zx?`p4j{byRve9q9}E^tzt1=Na+<{Cg9r0O9QkeeuxeE-2bBdzR{qb z@<}K$@@L zdBDe1bN1$IDo4U>?fuNyN?hv%T3Mh>5>Sd!M`j;kiWvm0Q59rOZAVDV{D2@25IjG& zmC_AfB05&G@y&J;ZWM=y7!Vut*UfDWy zNs8C&*T*z%AFZa_w_+Fb1{Nb2@{{Bo8d2@J(jeh z3voEB8Qc9a&&!}vY!Y!~17bUcHRq5Z13#nJ$xO|W&TT!MNd9ea0n1yYDyAN!P2c2b zQ=2<&+=VKx*b3sD?{9_giN_av9gV8dIyeT3z6-m!)=AJL$c{&B4xF^EU?|_B?GL8^ zG+|SY!T=!qrI>!?k_n?sdk^Z45tCk9G^5>K9bYC&o|q0J?Wt)_LDoKItDg#HOL*{l z=-@p_graoCfm{X8KhlGRN|X^Ru9s3&cG+jb1JYE1MrtcpHTl}*dRQI_{6%JY$yTkx_c0U_X#W|_($NGeWP3gm#0&xw6H zT>230J7m7F-h|PgWw=D$H?HIjt{?S+zxIF{#LP8Ick=kKJV0*MCFVP!=ZgH(!ho!j zEFFzgv9*nWQ>>2Avk&=sL!;}+uQ6CP{WzVZ!5w5QECnxqW3M0pUo_3!E1KDE z7FNqLdYZn6q{h5rV4%A^wK|{Q4lw~G)Y~B~FZGTh?c!eb%-8_KkQOHdQFK%;Et$@R zZ2?v4j}HtWn$8ftb2_q$hvM~naMMG+P|Kl7KWG}3-ZPG#EkT+;Jj#3vj)hyE1Yyo{ zz;0*;fBc|Zm^6qW<$7g1-^<)ZBTkK!FQ2w^karIxIaKRhPK_VyY(Pe@7CHR+QXT&A zA&*T?BHk)(@{RerQ`uy$3ycO7{-b=@^s=t30FNTC2jP39G!{NG)=r&r5_ZByLvTeObxRTzuB6U!bLwogC$rKR9NKfa7C8+2VWPsqOU`7Or%tF`fMsOyVLFtP2 zh{aPd9gox0@Jv@T#oVcAn;bfaBf7p==@He-m zs}i8J&5H)8FoW##wh^-WBr0 z(rWpIpZ#T!Cs-Yq4uQB>(7*<4WlP4stp zR5ySMEdZ(gp8a`@P^nCfx9(LT!2Rn`E_pZtXKx6_Tp7QL%In@J`SNk8@FIy4!`ca0 z+!o2le}Cg2-n~3wy5c>%eaHhGn5Zu><6N2O1ljj>sMK9L=%?d^N*eox)JC{X!hPyP zWa|{u@;PG;;wE;7tJd#9q9vW=a?`e?ID7H3n4~$0-f9Ep<*N9(_l^)xk6$N}Gv1wo zdAx%?A*m=MYn3P02whB(TWccv_wZ4qrIw!9!a&zX&*6V=I|QV;Fr5O7E<-Bo(4>e^ zcpCq_z3+2N|IHKULUrs@e(R)O9by1Bo&uz93e?w1e0dPG6NJXAyNrzEnrS9beR-v? z&`ecj;|3V;<{kO0^ox*}-p!Qq{5g!+7f&eJD$=nJAaM~jC2W^LscmR2aHr-+WqA?J zL5uLm0%0lyat=;6fRe8g#L6a5^d|qJ{GbTsRdLkVJaseV*3keaQT_UBzvBI-OPB&Cu`6n}>}8b=maj*pwK=CB2P55?kYn3Du^&o!zf zDIW7V>{*d3v{>ciH_#JZ^!^N{Qqvuet61i8!~{c8%iFQX%!Vy;#*XV7U+6-%yp8$I zirL?mg~V^QLHlfao!5!9zQZ5XY$jsbqbAfJQ3>i2>D~B20%`&%Ac}IIjOJ zuQ;u^92mpdeQ^m&D|DS@mG#1|Be>W7mu&HAT!jE+w~j0Y;dDgO#${Nir}sSd!Q({j z1EXELOCF>|Y*a|=i)Af=JPCM|(em9h>5Jan#vBb^G|ZBBM5g2Ykh_i?Fhud!CMR5` zKvo$=+jMZei(RxVNtqs(Bapx)b|E7W?*Nab!pT=|KI44IxWsItB)NL9+}{HapbW7~ zQQ-MomZZ}HKeOr~iklxiHVz`?ss*T%s|=jm!A@c)i?8Xlu4tl?zjGOt`&15$)TdY| zz>4PMIxP_9Tp3^W*h3p%6nJ#Kfi`va`r)@|9&|%=OZmdh%Z$5-I!3mHs6QdrLKdIV z&M^xF7hxhc=A5)I?ev`56W-z@AbFtNyloLrE3yg z@Ce#IV9F~EPm3vPrh|r-4F{;6ZEqG~*t2CL?!N}cAjk2^+g_0rPBl)vKT9QtLl8B( zOb1+bl^MUBWK+xE^{Ele-CeVI_o%LNCdeIA zRs66@`EE;(+$7?9EvW|x6xtS@Gg~H3Ji8ErhvYq}w^q?MWK>tJY$2{A=7O&By7YLy z56yl`NzrL8SL&z*QiNJv>B1R&)zUBzZjNNBMl|r_uWSeOn?~0jddNEnb;SZ*q6NDC z0J?p;qIUpir$4ANRTnm$eRu)!)*SE4Bw)|4=^nzw+2y?=ybZ*q-J@_?jCqM|?Awu^ z`a!KDIxNqS0Rzid(mc9Uj^a+WZPq@PDg~0xbOge z-21rHH9@H^yD8|l7#cd_*p=|*pC*{*WfMmN^TMy{dkG#@hfE+Zf{;W6>H(PI-un!N zVXBQSl)Px=Noc2Fa2-;#U%i%@SnG1#-e`HTq%>$mG1`Mm^PC=>dyc8Ufx)pVcZz$UjwKvHINIzJCm zh}z(s=$St`W_sB&!a#2MuO=2h!FapudOP$#o@cJUG3L2aBi+bq(Anjfb2__#;G0>s zI7F}k5V0`iPDHVO_!*7KpwTq|l{3)sfCfVG<8wvjg@y+cVwK7>_is&q22@o#F@4#AB52h6i5GA?qXs8+-Bo~ zZmFzq-MlK`l8Df?Jm8@HhIe~*wU5@z7?=zbVmuDYRL#d`gpzSmGSI!&5jSDOevDYE zEj!%kiM-AHrqvHi<{hy>IZXs~f~Qi&IEeac>IvOE*T3l2aiHKL$RP=UC{RJ(mZJGP2@lbxio zlajGRCKrK%&up`er8}v|9`N6-nG{;q5d87((UQS+O=)Z;Qy0o<2RJq~f0q@}AeLUS zAhjuSG^Ta|JyB`SzsYxS<5#RiUXs3R$h_-2$32O}x!?cmrOYi#W;(UKNB{*hoeHs- zlX&}ku^yXSSYXlg{Z^4s>tD{Bkc9r@lIy0MUJW6W#XDcBjoA(7D7+~9gUZ$f&Yw-= zpwusDk{t;HE`4-#27oDGqg7c7CmRP{wgeg&jaORiVNQ!+;;;qLqM06afbu!XY2oEXq5KzzPnLVp3s&isfz5X>`*5C=8d~L8TMJ zhxdlH0WuJtJ1KZIr8uK0Iul$eGw4MWfc~h>!f=FS`SDc%=lzt|vNvDYPNgF8ayM{< zHU);Lx2=mw$oFDBrS4$X2wfFXZnzSdr0C^K4f*hsLs-jxL5{WLcZ0SV9EWMJp)CHk zP9DD8xypXdl-)F~2tR7(nbn1)I!g=gEDhJ-V@^m{;k6)M}?G^y{wfQm%?STdLf3wm>+PP_%){w7_ixB#cCyP@?XXW|N_AGQSSi2Ygppe_Bo-8W}#|K&RplB4H zwxfB>*EefPiyGuumOw2^0`?UTR;2wV|8Ct!du4oC;W|EUgV-8 z`pfm@I$XbXdW)C%;}6vEo+dw3zjbV7GaxrmEp^d)3?ym1QrTasBZC6i9WJk%&ygS# zaj7O5MxyeX?8zD-N+TaZ81@EHUlXm8WD~67CEUd(#Q&wynkaz1p^O_9zPRA3r^g^{ z5omLNm+YC6LkNHj$g+0~MH zJDs+@lNhQCWtfhLl{9!!@T8>S4i^S|92$r7Cjh9=W$K>ZcZB-d)dF!%|oD zSf4FW_fiZ6I(VFWy1|n3G#ZyoBaYOoTZj~%!zF-@CW1T$6(@+INsYj(yUWEHk26Ym zfth_t+bByBwVt_PNo2Gb6F$qy<65*+N#j1F9S%|JC&@^=fb=6NP-hF9W}lYGZXYwoP5e+m^KXv|DWoqv08cr%A|nREGbMOb zJL)8~7V#Nftr5;Yi1V<>=3Tl2ez_$nd`rg=aPEFs9Bs7|n!GDm`v=(0kF-cF*h0My zWcUdI-O0RrN|gasLHK}V7Xb=MN*Vw_QW3jq-zy}`$S6BhYb&v`#7ZfmQ7MoKEF82V zKdfpp5F3KE4LJEk13-4uJpP(x0>Is4g@Tt z7p)Vp)w9=W-j&V=JE&c7&m6XW1iNQtu|ILTFj1PIR4Ea_|GfLJQx&(pj&O_l74M-s zJfj`Y90UKaF8wa^L;4X--wFQU$(}=TglX9 zzP*Nlu}_?MN>YsjtuHa(GhzZ?MqGex(E|nF>|#zYU3@y-#5sve&bhL@Kd?>u`?51d zEey>9tsAk*1adQB_37P&dVAM6h+)-#%6uoK=rRU~Rc7sYAQBB=AU!XVGjB{m0IRB#Q7YS2n4Pbzl?ki*QPIj>3 z$83eGU+;BX1~BUu(cZex0%i+n!1Z|2qpwW;<7N-4(nxuPZhqZDuP;7n{|y^8$^|1i zF5RQn8Ek1KRIYr(x3UJZEtT%pD_S|dcfo_X)i=yL$8!5lXrG~Bq~DQdN^neVnAbxs zc9CO+{omoXgFu4BVwk=*1VWNN`o;)#4%v~It}Q9>91&;U?-G39<(ap)K4h`3F%Lm_ zCM;4(yJMk%lppN7r*;n0=_#&Aeoa$7iX*7EYxHUg za7hGqkr74S4>gr6lJ6RQzTspOY%FqfXFD*-a?`coE*3;5RoxVqa_S4%X;9Bc$z1xx zJv7dMWGoO2ZQ@I-sh?+9G)3x3XdS;Ep9i9+;m74of-UXqk+>sf1<(6ueU*YydtcWL zt<1C{R|W+^_H{Beko_a!SSjBWnVCb?eL#Ni6=2ny=5b%ItLQtfU5MpSaDyrHTKf$f zN1wpKQTK+DblHo&9~g?aX!U{CD$`8;Q$DNRT2xlF{c4nF|Fk4 zZVK0=DhuZL`Rxe&Q7Q*Lm=Mo<$f!65iQ)7HdYNUAgFB5hjf9WY#!kqh$uLZ4Exy&9 zTZi3qPqVWDMRRj7x4w{f$%GP%TzNCHfZw%lfcC4RKwFse0HbeNl@%5XO3qRbl32LoL7oro8vOUZ#jh-1X<^fL%-;-2h~_grA5g;tJq^)-rhQZv z<9v-2sz}vN`9eHg5Vxog1+#$L_mKLG0MCo@)m(LPH2Tq=cqjt)cpoJZYb|(r9-ymh z>;yV$?g3SEV}%WFi^TQ=z|j!7>pY3P7$O0S$E%>c|MH(H>&n=-^t$Zb_X*(y%ogqd zRJEp^IV*LRt~Y^gl|4SyMkn-L1`^%$`f)Y=XvmW>cDHh!Wn**DLX&QWy7w!92PJ#JEDR796iSqJ#_FlRjmXI6Rz0?$z}Ur`ILD4E>=*dJLv?) z`mamDhT*Xm{HQtq{R)|dT7U!8>Dq$Kw^VF60iZWBZfPieDg%2!_mhRzQ771 zO^}69uxH5)6S}(8j?0#Zj>7{zfnW;sL@K(rXJ}kVb2c-6=s;Ne;|L#Cljq~Pj=vtD z4Ilt~gXj)Qxr;e4+dI769 z|BugxcAwN>+v^^&Nw@*rKsfW~wvJ@wjXwU*qI#)neEUhUBZ8+k$r%lq^Q!)!fBKt; zZk1mkRl~h+S>lz{vlm4BtON`JFk3WUyEk;r3{flRKKPsq;G9i*!3{n<*;*JH={QCo zhX0oKeD($^@X`ykM#3ePwN9W3s86E;b~2IWZ*81V_|aUsv(Kd41*8lF=gXGYAZ2mk zNvpJnQ(-doXACX@3mc}7R%Gf?$ zh!kZ3+(5?giK*KFxqnjBr%7Wb0#G^NtMEhbs}DTf`kZoUUOYNKj!YP8KZfamyZs66 z1(4;rq9e6rs0x10jCp}05!+G9n>ybBHHpW{GoFeRMROz=R`>{clP<{V=fEYy$EwyM zj$O%S#TaH-ZKb@dE!PBF!6P9HvV*gXVJGSy9n1tB-&?=afjxpL=|ojec7N^?rZCd9 z8RsbeN~4ok9Plnl?yC2ch*JS0r>F$5K!I1l-Ll;D-X`*|xX?enoR0@S$#KL6G7cUl zPb?7ol`DG!z-0Wo^dPC(utdISjxm!xDleXq@gSp0B@s*wh?wmBAt-0`9al6P1HuLQ zxAN_kII1v4A8HW<2c0vM=2hk)?J^k}rM*$BcchnGP16pqyJaVqGFF@Ambqv5-e}vn z40GOu=1!sv0}hFx+8#@E!Ou=ahx_Hc-0EpM*p_%ep&@C@ekOAKY{Iw9sm#eg%epZv zD`X9#;BNdJO=V^lvm_E9A9kPEesfN zn0wbt#Yen0^S_mVWq!JXX~V^<`)jq&z|h^@`8UH!&Ze19UQuDZm>andTc?#rOmsY3 zQS^xKs0-~6i#x@DW&~|S@Ob7%$Tj`>^TYdy<3kCTS_#LIZy}BU!@pskCBXVP)10$Y z=b(u=JA568e;O`~x>`Rxos{(FIAWx$W#vX=SdCTIgN6b3;6^Iz!I7O+*ElPT5>;IJoL5pV1MNH zDPfyz6gyx%tzsV04A>nzq4kwoE9as@TrUBYU*DgCjOEa@L$dnH-9Ii$NgijUcnK>u zY`2RpeRcExu*^UV9=8eDJAFj{+zKM{&xJ)5>Bx4X6GQA;pPca`+&r;NLr0P>i=+Fz zkwNu4FgY&tU6!Gi*4tc8>=p#9{5huMmfItdlYWI7E7WbDJ_;;!Ns?O^i2#3I!ciW# z0?15)Oy>lXmc2)qX;Ganf{b4^Me&=xv4({64K&k=UpHq_+F_+W{ShmCswUzk(Tw#F zyN#Akar4ackrC&yX(InzHwn%e`dzJRvVi8Q!&R0Zw3X=TXF%6dA`jkq8Y|kglq>>& z6Du>1s9Of1Toi~;gXO4jw`Fj4h^XAvu$l-&ogQ(T4~Pp#{5!#0JQ-fA*k*|N&MI8& zeGtduQO051)>kOwQ{oGLX)5K!qBnuxgh}DNSZevoeK+umm{g(r3R%kk-i|tOb zChd$Ch4%>tU!a(Cdp8x|G3*!ZhhtCZ6R$s+SUi-Sq>yqVHNcBTLKv2f2@4xW)a54~ zQ@hG?5pP)T|#ioVgYse*Tvp0ji$HC~FK$s;ujb z#W=0`A*a2`p-u%xJvFlUZr>4r8ks(2jWv~HB%zx=ZEE$_IRiyt-r16Mc4YCW?VwE9 zXKbMSWsQOg0?!6opyuTL7aO(`Lwu+>+Gr<{gya?tD@tTt+&SvcnyDIl?QBOq(`x5{ z(pKgI*QT(4wSE%gRT^X5Sln{ArFcKkf=XTeN}wyA1;kKjxnmLQT#T0xF|-lMHl3Sh zoOA{qW+?;x&|>Ba=i~hIcs8RHbnD^l2=rMIrIo3?Ny-z?7h|sO8*6&|>><96gWZLJ zT$D2m<0wwcmjE%1NqObud-FS4b?J66Vj~Zx zEP$650VjMngn2M1xVOVqzm8EENV=}H5d<5v`RLIe=;U^s+8)2~y5x}2Uft>=?Eo(; zCgj=fjpy1INAyZd9K{1udSBG5;P+|Rk(=E@2z#diP%72=(w+qG_a8vpO$vf+Bul85 zW8Z3DXmU+fvOe1@*W4>|+*AN~Ecmni%B*G>qJ1)Z;y<_aO;%<-TFltgD$}$R=M1vm zh#gl%Yq=eJ&J=R@I1SY`Y;qqkm=T5%J&6ykVkiH&5rK^{(OnV>Jc8rkfz zry)zxSFPfGL+ZSNxRX$y zpaGVvorrr40HlvDdZ)&1iJ0Sr0IH;@uXIQd{mg*sqU=~>djzLSYzLN z04p5dFW(aLA7Y@e)W3_SddMGs5hFY_ovu7q*Xuj9fmC%G2X0~Ydh$|J;X1en;JNsM zOsRo*_UF5k@|A_M;15(Q56Q&=I=u^EK$%G+q7@@3|oru}pEIG${oAOwI*ftCb~3_37Q> zZYiaOdc^A9R&3yX#n7Mv*X0)Ez0d>TfX^dkXg1dDK*A6ZJ_WQzxW528?zi4AW9C^g zVA^w`A?IEku|BWxukF4xN~lsEmv_AWDIB*j#K0Z3Iraon@=WYd>XJRa7mvT3z(Y4a z-FYf%QR4v)-OYrDob`j2T70Ve;%RG_)*0)J48xPFB3DFA9^nRTXtz&YzO+kIrE#49 zi*z%Sw&{#|lgy zNZB>uVOKi_g>Jp%uRE<((0Ye>ce|O(=gtM&FmO^oc(YAS49CZQ^va_ipCs;uhI$JN z%a6kdu~NWxXf6`gqz2XOiQUrU_v9!%a2+*Qr~4?drj6S|vf9RQ{wRCc`F z4X;EHzqt9L!2A_#wS7;yMpjOUnMM0p0O}^?dNNJv@6E6n4?ctZ|AX{uw76Xqixb&L zf02>qfAN4`AFOHz-Rh$k2XS@BlL)y-FQG5NUi_+-xW?$Ntyyx!61o0M#(>_okrk9QwjoZV@wx*C7lpLQY3<*dT1|C)-8|>Wex_x zbZ(sfn+fk8=vEWiqB&ayjcAUn&CQnTQ@o5U$l3n7(?CdfQWDb}qPW%9174a=BF-$C4-M&k*SW+Y{y_?xYG)}Muw5W{wVu+Q+{Llw6=DLl8b{NE1`TgfE%DRFft)$> z?hoC;moZF;qHUQJ<@q~xH28MtQHbXXmFjaeOOdy41eg4g)xO2N(Z?Xn6AGHH4ho#nEfSIf#FtV3mqO}A>JU+7wyxEE6pQDFSWN?Msw0urq(gVBZECd&KhQ* zg{-6_fn@tlLIkHtl!E(SKFs+lT3Mt7^U~%rBlY%4E=BJT^VxQ>C>F=n1A(TPDui=$lLG;a>8S#R*+{S*O>3S{45(&#QEL^*mrZ~x+*(mf zr6bV|I`0>iWQs?M`p~-+=jCI@o)@iKil ziT=*mn;>g%jxmB)shyq3lJtY&A%X5XA7tlU@!`AK9ne&M2W_s4Z)5aXO$27O(2NVb zbW6M5G~)0Op0RusO?Pa4FF?&&WY>9}W!d<~-myK;wvz@e{WrhXot4)Rj%(Z`@imV% z(&i_@kd;n&NY{ufiU{dR|B{o`L4KI#(>}5jqI0?FSa>8?ht95){8n|;F0-21&!>JT zLEt>i0e+{Uq+prk91e49pEEm8$s{)uWxWOLZP-$LeD8HkR7Lc!GDZSuk0`d4)NtK= zZVx%gCV$*dr&cMo(seF;P{Z70Dg>8u8i=G1l=+8oAj$LTXwNQ3q8`roe1)0ZP(7-J zz&bvKGTd3v;h{Tx8pdc@&z>3G+KuQdCaGVtj2Eecl$a9S3};L!TgWfGKzo2^?>-;HLqj$%SWC7|UK0BM)uww)r-1+{L%Hh5u`U z0|OLw1hy|r$osbE(rjoVT0kr|$N))R0c`F~0+axP~NRCh#As4$dJGBkAwKeS3 z(qQJ<#^%bM5~~fZD^y=@)~Rg2B4g9w*zjL7+uZ|CXqrbyoe60k!2_9lPR6EITmK?q z^*PYG3;o0-uBtMF)xL5O%M&1dyrmSCAF-%0<&F^1DHG?BRD}j*RhT$^2k6q5w$XnJ zgnCq6tMg=n*h#X69}%Hl|9#1(rQzxVv{t3!0%BFTT8E}Zw__kXido;)G4d7pZZ+Qv z9uo^hbmBGZhm#3{ic;fsy6EhAUBEFrtPLA*hG!Uib^j>+d0*t zi&Rgb0Ih(P!xUyW;=h$0dYPYbK-YI5pf9&KkXp%T3xHQ|T|p!-H9?Wq@rXtG*&~h2 zG28&WLZBoG<$J6@QUQ|{aE2Bw2s0jI;$-E593Afhf z)nMH48uAke(jb2AEVPV{)(w;95jSd%_}u=SdX5O(%4n!=29;((BH}*s7#cX+;ISkk zPGp*VEHc$3qXNG%iYg2=@zVMwEvpcucksinynL^khwb1QR*(_=y5FV9_m}6j_yi1h zWLa4pD+*qp{lK`n$hl0)J`tkLR16teAO#?Y*p9=fgKcmj2#<>U#(5}7;iFCOJ|xN} z56I5`j^G9qgX5{y&@4l+$)7>qk1asuLqFgRY)Dyd?Ug7P<#i%;cTYXbHpE#*KvyMs zm*bB6;I))TZiWY*iM$N&e~fmU=f-EF9cMJV61vA^(#~*OS;wJVX3y3|s@b(29BcrP zEJ(a33BCrG;570Reh>*ihTKd7{mPST8nM+=i*2u%b1+;y<7A@vI|$`z>(IE9VO?!Q z2d{Baz(Z?bvDdFp__y&%GSfW~2X0whRo9(_o*0g5Tx@`o>HcyPW*HaqRF3Ng|Osu1Y&)8Y5!9sK)SX z#9sV&$C{PA_T~zIANyv@LyyD36X&Q8mL|(*B2{;Pj{E>h^}3U&AO3cw=nsn^>(uW? z?jcbrP?upOoVxADT>kgy2sX%agB1)()1)Yh=^3(PGhrXh6|>rn?e16IH|S&B8rgE{1<7Q~m2^iFhvKGZ7`M(25Ob)TJb=Tx?`*)e5Y8 zLSL$~T3)mF60s?Qx`I|!_3Ey-lA;?F<1CyjN?RUhq9~}(s7B+)}!@rYfmvYv}v}fbH}Zi+l+aodXqL1TQwQ zm45KBR~JMDJ;U^*C0Ve2Q9;|+(t6u1$%wccz-)e*gP;5*mhZzwbI7)M>9fQi9_kLr zOOzT1Iw{{)RouyI?`Cm1?M0M;7-Hc#TZhq{E6TO#EVP6lYugDc#(t8Y5UN?Tn-X>A z6!-=hh<;zP(RGFV6JaPR7`1EI*o^1eyA%IcBBw{~8Fi#$`wvZTqZ{nS;O4)fc4old z*d30ff~r4s%Zsx9LEyyNxRXKu{&{~qZ#rk@u%8${sVd-ev^|wk-0req59C6It+RFk zbYF6jQ-nQKZi-RRci}iU$wsD_k0t`7gBgNo&&y5ALpOe#;p9^-7hN06##$zw$U_?^+x1k}!sWIPVZlv2lZ1D;~3Zdiy>E z4)N8{EYq5~nZJ?Y^8?-K(kbv|6 zl*K0Cf#tlmTM(>vfYY2y0Ks#E8Hk7zm*m6NvoVO|WSr3KS@IwREqUCLCD968QGys^ zr@^xqW^V2HnLKLqxJ?s=VLjKtf;HL68g%2o1HmFDah1`f{egmTUIM>`+Hc%iyKw}w z6Kr0U?_u^!FzC*qMK4&@bM1aLZ2EY_S>LGZLC6q!^{5kcvquC5m`ltq&vfzzG@#K$ z@c>%hP#o^RS**Z&fbW&{NjFJ`(`Gn;x4DDT!_vjT`MsglQip}-QAC1~HLX)7$}Df; zUjTYU$0V7bI5orE9uBwBBC~3GU`_K&+4YBuk)$%BH-MawBHUgWmBL(9KC zvL2W^oU^CtlzKA(Db;2AtBf9OnNB+b5q-z|W4XxSw>=J2jo`l5aP9$_^0g8gd+zAz zf^K`W@4AH_VA^3eOxZ2vcd(eTeCcdYVsvp}5B8}{_UQ~w4o?#9j)9VIp5aaA>V5b# zb8IO8(lFF5YMPL`pCaCPL`wzTuX<*nL5lJUw7gIHt3yt8-w5C_oAm*bRAult?wkK-= zc&qs|`Y`ddm~}(&iPcSxN4m)O;dx#)se9j=$^JHnl$gUE1YLfN+-Hpnmal)Ywu-DZ)czF{gk?0cJ$_kb)oVkI%LT`S9}SuaoVV+QN_oM&=}x#k8t+ zK);Ti9n>c|Nt+a>#Dbxdq31KA$iP*_#f@uqfuhknrKWl1V8%_e!3m(@g!m4$R|uW= zL`?!NGS4S-639j67YYxUp*8KDqfKcBhxzK>WIGU0{t~beeL>=P5v{blN5YHA(|Q-| zAoWNjV*OWrpdmoyj}FCM-JIjg8Z$u0-PAcq8n@1~TP-6?WZzQ=@uj9${bj6R2!3VaKKL@;tY0?*Z+hp}>Z zFcS0!Nb6{u82!;bSZCEuV!ZB6JOL1#LQ-Rib{J5Lq0!!4h47IC%N+!9E){q`I=uCQ zbVL#G?dpJp$&USi%}wWSzxdqw_*D(Q_L!)WasFY8+y$1v%+ZuTy|;1l_t~Hk6gAnc znb?;d2g&hoU}kjmO~{Pgs$8!#?OsyR_#|0oe>aeYYjsGDH=lL@vwDh_q`|{`#6>lk zwen3yoIC_th{}>a(5iWJn@ohxjYgX1_0uS$HI>r0n8^8`qKSn8NrF{5oHR4u_?md_fVw)^sgi@=YJ*}S%6grH0aaIaSs$f*p*LR6GT zTqBmxjW(GemYaZBny_c&#Go;{age4At7tLL5PQuv(XWyo%1+lLKyL+;k|>ey-8

%Hx2ZAIHnts4G@9v=&6?dC3lcU``T7g^Wb%v73478F)%_g`hKHER7 zCpSxQ*<(un`}z=xgHEU`KWkfKtW= zaD;%6h#AeU0~t%(y1j33+}^sX$1&ve)%Y5QwB6Y+rkN?&%VJRzf=`r%UjR=6wD02u zS$C@BzErnE8?KZ%Ix`(oj2sHKZq5CX2=8JC2!GlwwG}w|W>iqDC?_8R~ z#{J*q{&P%_dMKh|{AEB*2^6;bZTr5Jc|sSXFI5aP;RfVyS>H4qCTVX7%^T7Ni=q7V zWpXqO^c7JAH!(P~?Q|W^P=``e^Rv~=<=?W;Zt}?(HRo7sW?6BKI!wS+XgVO%UmGa> zKqmC+JUTpX>XP3Xu=DYeYhn*xCy*`&NI3{tS9C%-V78Gjs`S^B z-lgZ1TA|i|m6=u)1$9|8BSgfZ!qXo2{rp$gx~gDbUDZ90y~DX(^i)qPU|QCrYb8eRozQf}ILrUZrUa7g&OL zq6-jly$xQcN3l2!-i(V-Eu(zD^pb&zmk?VoD(yF>X4OnTxt~hb6A(n1z9!#kjU4~O z@iYt1!YK2$pIftXeu4H5CJwg@M-o>^`GP1#W(85_UrtTy9=u`64f!$*ft##DoQK!A zutX&8pJ~)g92+D0le(m9%uM*+5}h=i7| zF-ejSE0T0~dnVQ#uTZLvmk1N}KihC5R*QhNZ@Awik#~uCZe5MMJ{X~u-5vf&rI|~a zSJ*&%=Z#pLt0h;x;bnhz2rG{>e0?DNejSw9SLnkGP1`D*>OKdTYO%GGSQWMz-wT65 zL-p(7Nk72h@M1h>B-ZD{3b6*bKBh~v%Dv27FgWyx-V4DI6lWJeZR>-NgUF*y#ms=+ z^XalG2=j#rihb#n4xP) zEpMlk=$)w+IotHkh*m&HVC7&Y(tK&C-AMp#2t5WHVbffTw7AzrcKW@$ zwOFTnd|nxp0pk6uboVXH#2JQtE@=wulS1cV_(opA@gV6AAu9Z6BdQ7DnVr~_J_vrf+n4cm3emV(R|*vZMMAcs$$A*syoD3lYz&-x}TRo(yGeGG;pUP%)y0j89+1JaZ zDBmu_v?P&pJQSDYrmf}!CE56=K7(Vee%6MZ5sDE-)XqmV?w=M6>r217mBQ?z3C1;;Ysr9mwu1?6IXv?Kv^SV*{?lsPZ6V7<2QozwQ~=uBuU8;O$h zFU&xaI7@8#DcEwD1&-wPboo=>qJdgP#|n5RF|0`=*6hO%Nu=3SQqd14+0rVV{1IFO zd9)llefX*^HE|MozSy(ocJ#kV^_fT^r3oQH_*A2=nRX$tj8MY;T}s`#5}tX9ZTE+4 z(*yEtmv)JxVDcatbsw?>#J1@AVXko3z36j1!^fRFPkI#Ihsh}Ea!H;L#J5?&oD}n$ z-CQk0|MvA}P>}Us43-e{Mq;R|%^$-xc@0!=oclt=l|MzdSkT3{#IB3^2~-y;gp4d8ts1wIW6LHc!?h|B-!2?YoAbV~6M0r8H26gm z$;6vdjlvjv|3-wjy~r1*GA5cXhX{)aG|r$zY`kugpirIjO?b+PLyc6CY%5n~(NR~=Fwg=IDIEL{)zEP#uSOk*j>{JFqHs1e3bqpYp%!vR zf+(Bd(1V0x8(XMFlM?ai#7|LMHV(1e)1A$^OXZysmAHr%gA8^*mzN=9QKe|Crx7B9 zWNBS;pdI#hwf>mbc@*3-)hr+>Au@v?Ts=mF%T(yEQHc@j>!7p{k@H^Ht>DHp=5JniJs_*jaJfDm5U z#FybjN1&X33u#K?l9-ADH^wQnphauVBgX2Vx2@5)NCip1jXXeRIrByAU&dAylo13} ziRhwzoD7g)Q42u5tzvE-c8$AyCi}<;vOY6fk=4V&;wFxS;%eB zP$|39^_j{5-E@EB?p+ou0G3{g@XCAQE6jh{!*hzR$A&a|vbU(KL2%;;sHD+DRwXf| zd}{2Ws+ZIBOsw5mk7iB&4S;SF;Rur8{Gi2Ve;zjPA<|kwLC~C)Yi+pNv(;Lby(WVK zeXeKnyb+v~&_RQwoGV$(S&h=C)`|#UBEjr#KNWK&vvu~eJiI?a*NXaDS`a{oC7Qb= z@D8tilu#4NDa2qb&>A=Y+XOZ+uz}=x;>7KClW-w03m4m6t0}f0Mk3Y;+z%rgbQuAr zg2NG}-fkf5{{lY$Bu8GAdP@(Pk=H~5%}(SA2e!W-MeZRHcv7O9KsyL)r}$kbJplRCL*KAA)&-{m>xtZhQ1-t_qXs6Y&?XK1FY3 zkLMOhQ^H~YNcr1J;|WOGGTf6hpHMjpTG$qtj&Z*VMvCxkuWtX_3AR+uQr9H99p>t;es6G8UU=rI(*%+ z{5snF;~8&oCf>_CjS7aDcTBhx{@;aJZ->6BL59y;umU;F#Mp2*%mK6jr{jWJ1M)N0 zYRlIF&>y0aXgoWBlKB6jh0bpM20?vLZ)Sa0vrU=K;S!gf5-G1%UN$(v@H1T;HYz^@ zc{M)fV8^g4HHp9%!OAR59GnaZpV2z0G(8c1xH}C+%7U5kbe1~jPw)PQp3FfG0C(*>)~A3Na`c-2Wg=^$Wtw(p zb$wXamYB%x9u3}agoYORW|9YUD#zloI=V*$C*ouV_*k?cZkxKPIM@4v0O@w@zgAlMIY7^$M2BmtN`GDit68 zP+B?!IX1qwYZni3f{9cL-kqePlI;K>GDLb=%{DG9DP+`HXgRdhST54;kHa3F5&ulc zHVYY{X=ixVTI|%LK}6!u%P*~f%VHpA_FVh?NV8{!3j;_8IoeNey8rR-Wdydg-u`aqWhcM|aGFs}$Mwzuo7PY?tS z2Q@r;G5-n~L&Jabom{y`#BUo^(?kWdbbG1rhx?SYa3i2wFW6V_UD0|L^cc9-nOBHC z4!X?qUvmU}<^2XQpsB?-(-zSB(uwd~gYap3jNCs^gnIRYnA9hLX5S2jwgswA(>f|5(yVrwj z=N$W9dDUbkXJ`2$>PkazE|o+~}ix111Yg5*0Oas0ZvOFN9bxk&oo7EP8N zU&>!WV(7;ac>2r;tWIcRiQ2CKlpP8YwSGT`76amxlZdK`ZAXvA@~QY)vOgRAU!U_^ zN-znJ*UV6o^FvzAO^wdesG!RhzX!<{#x-`4M?dYUl7m;s-Kt4)NEJqC;nL*kcY`e` z{$C&k2DAjPyj*Ss5W*NGD9ptmA7N?}X9*cZ*SP8K|E*r5;&3F*$=ZUSagTTZFIG;e zbwqlz;W}^j34xuOG5lfx)l;BzuFvgxW{G<5K>X_osOCAg z{~ZNzT54|cLt>%p5B-FV|ElkU-w;fUhuSA6lF7iokgD^vhS(W_5Ghrx6L2|$k~)S* zdMKnD?cjYTJs0GD{sc&!G^NHP&q4_qmO`k9bm3*?17q5VwV_T6(JaeH=esmV3G3TX z8+D(rK0(n~&wRzU?23uW4#j+>lwE`YKwpGl(3yyHRGKTGpsEbAm<}Iuzq59ok7N$g zfvUIEL?@>-Y@-ucHi$u3q3mkU_{!E+v1&( z!JW30e#N*ThY6{n$LVqsx+kuKz|FV0(&1p2p+qKviSUp_8zJVR5E;mlxy@xoOLjNu z_9G+!RvsB#F-18uw5+R#$UvG9osZB5QSm=4X&$VDV7d9{X^om7Z6`x)U)u$=K!I1>z{c9t^(Pet>Dvp~oO#8x7S75yTNT zw{s24D(N1wMqFHt168aE4H^8+IiEU14g@5dChiw~dQYrKw#t+yULy?30g(UjZ)Dym z;tvaDheQ)GZ->*Mq|^?#kiLvec#at0!q z+`hYT!PEwH5cd*ga`=WLRNc2UC&8YoDMzT;Q3A|phXd#&w09=Omp2!-vGvrtb zsyU9iPSfod@KmJw>yi97%+Ll^H@FbENc&TNV`Qlx70bGpG#mH0)q z5WSxhQwk(}QTZDPW zuGy%(|8dd*x?w?yg14;=04Ucof#;k>UHFc2A+m&yQ|a%9V+h~>tNQa_`zyo^IBBep z)zLP&Ui{A0gmZvG8Cz`*lK%;R;#zS>9MRw;0IQ?JCMiAn8OyD-0df?rBdV;dBPv<^ z)llUbR(lRhdQcT^=N<{3zA?A`eKQJ&~h`~5zSm=ExT z_5iQ+dz4H4WLOWdtLYUL+APD}(ut;-@2#ZDOxCcd;am%s443Fzs&lCduZmfOzbW)y z+7cq95G+D^(wx2PXmN-r7OyJ8Ej{;hhW*0GMlZ0Jz^Mr5zdvF^z%oW|QnZ}sqKi*?(#j9&I9Gry~-Xt>?k7Im2 zyq-K7naM7XHn|#<4tV`St~fNb;L`mJ;B*y1pgyi|aVgV{>NWKlS5uKX%((A1tn>D@ zunX6?`FLU9Nf@M7;fOvffi_-(G=d{VgF5trCZx968c~&!mL6uzG558*D^g(aj!FEA z0pi&GY2{X0-nZ(rXPFxj{2%wC-e5j(=PbV4Ic;IHk%awq>PN>XqbsHHm-Vd~I(f^AP zNzTiMHL4i>_moXu5|hB}vERcu2FSFjGV2#!?ee;-^_(R83A}Y-uZM34u4b;KrR!c^ z^pnq8Serum!CIjOkfa$V;<`;lywouW@b`~}UoSvn-3W1mh(K%ZUz_D>o6S3M!<<49awU~is$voR;?)KmB0}bt zPfp3A+7%BLTEEj-hecCf`-RqyqIM?y-e`Ybrn+Lu z@K~K@r(ulhXcG8Mp84&TY)ZpN9??Re0-o>rF63mp^m@w`tXpg@=|ZvkbP~kahZx$>|A)b%5bUdtQ=!B?8h5* zDJ(oZXMKfk*u!}xRSv+t9H{P8B%KV(#UR!!a;p_#&6bPl#K)JxSiwq`9tOL_I75TXu%CoOn zYXe3(GMIFkmr|-034#Kq^_zzwF_kXyB^v^o_(0o14T`m4Wne6*h5lxO`zPFGGZzYx zsZosu7DlDA^x`!sH|I(bIG~LnDiqN>i5yh4&$1gb&~tM8VIW zvu8J{!+aZL9KGzO8uxH)xL0JOT@C2{v(#rIQOIu!6wDm@q zPycK2Q3sJh4L&W+!z<1&-z2!d)F1Qp6Hfow_Xa?V{u>C;i>-tY?D--=NN8W+{7&7V z*OwjxnS~F#q0NalhK6&%{)m_)FEJ6=Ur6*J5&dU-cPH7H;a%!1&m)M88M!?9pvQYD zR)juLX z=4Giu`Oyqh+Bnw8U-4GdKYFTNT%*FLH<{|EG+OUPaIOoJp7b#&l#!kvsmKca;sMJ@;vrrKN(ktdeUq)hphl$MmQ*qZ#AXbH8 zHBt`1$o^l5Nz1W}QafFSgIPpN>KV*ZxZUlx63ptbL0C;=8F5K){lF`{_HlM<_5*qj z(;M9-aU-n)S^W@{INWN2 z5Y&tK7s{|^WM-dZle>e5V?d!5Y~x?8`(Y(k+cd8EDA!IbxA9rI&x9)DE+k^yXyKlN zZSjt^%M8&CQAw6N1d0RKwC}`zin(+ z#KFb;awtk!cMFmxDVp(IYK_B>2Pvu#Y(#7hK%MjrcE4x{8y8KrN<^^w+>?_Mmp5VY{wE`d<{Md^P5*rx7q z?zXW$)dcECc||F0PP(JCeB>euVX5a!F8z^Y%ap4XPZjbRV`U}x;|;>fnNdE~RS{!l zGIs1GxKQH7jE|fDph=CZkx7)B_i)PlNsU~u>8&+M*{d=*vkHSBO%%};jtjAr8G16! zzK$R$aLxsUh3}jIwE7}NTo zYd#GZ-nfx|EK>Yp{Daz{GN3hh3L?0glcNwePPH-9%X0oe$-Ql|FC36ntkWS162d34 zZ8XH3o>M!ysYKXJB*Tj%@?fdwa@Xs};Ne;L#Z%C53TMjfv*e?TH~RvLXT_)#NP}Fo z)I}(GAZ){2I4NBlse*e$@Fo9^!TL!G3$wlZq@UKvX!qeBr&XH)H@^&3+HT-D9L|tE zMW5@Vxtn{z)Coh_H5koa|R6iu|^0jBUsmT&CD8epgm&pE1D|>BzxpenH4>X349&g8mTPZ|A4V#wvyS#0{x2>) zy=_NCEEG)Y11W+;t0#PUOx0xCI}G;>()ER>Uv4dez=GYd9SLlY#jJ!>5lg#8iQWwA zd26Ze9~ygCuQ4o^=Q!lJ_HamsOfFM4L1N@X2SYh+`>)7?=M^|uIvu5~{Q@+b(=)W4 zh753>gXy#q&FRh!G%s)r^Xq(}2;ltyTx7*9`AEs|Gsny${IL@(1z>KQ^G+a< zKmC5L+StbK;WLQ`dz=>OSn0sda9=XA8r#<}bP{?#!!QcP5_M6QRA@=sJ3|^#F*UIk z0I0Iqib?eun)>S21C}Fh(mvh=6G&>Q4y2grd#HT-(I?oeBD8I(=Z0h zjFP<3Q%-#(4(4Uf)c}WK3f#7Prx*2@JOv-wgoQM75gA6`RN(#0{8}%bzw4#92n1 zcytAG+AMgJ1M}xshfGS8sf~vp#xmy?%0imEE*nd23d#z@sZy%y56WY%S_PxR9QOp)^r z7Wr;REnfJ6pCt{_+!Gz~`nonEZ^eP)tGYH=00tj3z}3!8ZN4ZWiqwgq(!ly5s&NCm zXe}{={;-vICoz#Nr#{jNPc5SGqq6d$2H-sgXOJy4s&kc`22OwriJ68WACi-pj>SN? z;&QQpvl;jTfmQX-h}t8Fe=NT@3>wWU%4AunBZQ%?1=CYOwlYmi)q(y`6Nl_+2 zO1N*o~iNiWgJMO-=$f!L8;Y_$-pm86Oin<@XO}ke|SuV&eSA{*Z!`GHjHi!Bb*28$q zGrtAzcfgEzeI(sNsq31;>Dg%v8|+UJUu z0^P``&?bn&#e-h=6`_d;?C6FLn(kObu$+IAczfy5Q#=OfLP(ZtA<-Ea_m&{o;_+M+ zfA1IquAi?s#8yRJzcc^;wTpt zIC&e+)-N&R#w=-QyRf=qUwTWY_*y{bmpfw;dD0j=P@84LdqDSh9WLl_(H&%PaA9ZC zubWvAyQeb-SLBzr_jt-un1$khaTrv#5GhTroF^~4+^`R&mZNN7F~MC{*4NnP;nJ8#&O3i5qxt=q9&7Llh#eJP}nWXJMyF2@SNAC}QFAVW^b|tBccsJ=$IAr`#O2>CqJjJ=Gu1N2Ed0PTOwm@LoP zST6+<*B!z$n|R*KPw00;uz5I9=P1ZT@!)1z{yjbt)kP!jRxPH4w_2>fXrrZ8Yq?;T zrG?hs_PR&zCb6Q6$#M90=>tZKpz))q$^D4^!UwwKurV@b*iAjY-~%>$9Qe- zdnGY4tv%!cECkKQ6cnPYhSTu_ERkSk$Q__TsYbirCWLxCl|*r2i1#`04oBxkmOq8_7pY~XAN*(!mT7)&%1l*7ps+RU zbUb=#Pwq8=7@mxhe^uewE9plo28n$;N1^1zlESR}>bC`^5)>#5^(LYQuwtx63!SV8 zE>(@4)vH4RKlAAUJh0jByzRK|H)&OG`-)_?=+Wws;ph%@0dU{syHqc6-kLsv^!l0C zZs!oLvvJp%7PV4Tm6JgnGq{22le zhgE}o*WNQYejB{gM5`9=6XV9-AqW7eZgL0iCw+t8PEVUWAzd~SvQ987N2BPr7L4Cy z*Z+w>keoa8D9IZa@nj3XXDyC zo|RJ-C4JmM!!uP&;-B|Yj&NkU0$`|loveECz?Tj62|3$wOU8$y^P|Sb<7pG?=qUH` zRwGAM6aEqHzaGoQV+JWML`Rh!^Ig4E2P`C}nQtawGIMD}zG#xHLQ&0+TVsH? zBfDTGmKq9g)i$2o%w!#CgH+AH~xp8jE=z*sK!OG=pJhn zFh$Bp#MorUNv36T|H^U58vC+j3XU_O$3QWb>3CC0MFf-uSzm((nTwBx;2~wFPC-CA z3@ZxfoFrfLJ86ZGLWY=nqv+BHg*0hA#l;zS%lT~&qFRvehdfl-bCxPohe*ggIafQb zfqJNU_=#v75A^)XiC=}8MFPI2dTJ5zc6B*I+wtC>9jqo_NtVTnT^P^+5F}3SOTG_ z{QW{8JK;O2WMzvxA-V)Dyu&G=6@V(Lu+0^_q1RYSyeJJ^wdTLk+$-eb?@RRKnm`rE z6R@BF7_Q3>z0nG=14M^x64fL#Uk;TOf>of?=~zDb6UVcpQm)YeLd6|d0*>6 z#Iw&rLmFy7z)b`FxUrz`!YGlxs3+f+tX=413A}DyBaCYLPLBz)5 z(I5r!$o!{-#YjxXD$O_Q=fiXCYQr;5U&$B$zyeVAlCmkYIzLVUR|_JmesSc*GTr4| z;b^n{GNuD3Gw_04kbLq!VI_wtZyL+Ntk;!Zp1>tC(rH4a;^JzSCZt|@&&^hy6Q`!q z&m!hZAiekfDg&6mO}djTZ$1&8+_hxP4ehb}bqd58Y&aCT<`8&NLJY!$*KDXKi~!8H zH$|%dO+!bmk^NY6G-P=7`DmvU177WETL`t;A|X6ha*~0TN5W4XqCS zP`psG5f4ub>*o}sckRolL6oyX;2fBl3fu7Z0RJaL@j$(8RqOWmsON% zXf(x^q>po$1L5+1DIF0|Z5YZAJF;`f-9;@I^Me@*E@Pjp)Ze#{f;psEahDiZ=6Ul8 zcoS&Yaq)eM*r*-6t5A*EaRc<&T&+~fXVk@3QHq(-qyAKQxA!>F&92J7M&-Z%LR=T!oU7QDIpZVswl`rk@GQn|+5^7&yF;=3WL8e0Ec zU_2~EcrAx1gW@dqTLBSXRi)1ygH_ew9U91Le^_Kp8+UQ*2>FOHoty-8r({B6j@+ZfNj%Hpej~|Rs7hEb9USandaa;^wVq+JY|_lNKWDrYpI7Y!pM+QCSlAjLEpI`1NI=YKP5F1 z7pXY)03o=%J^w|3PU?Y=0Dse=xa)c-Ia~wNK=f@l5=!aKBP}sC(Ol&Qj(oFVCVEB^-8wkh zsok?=u+LX_arBQDWM^y3_N8*{GOGd8??U|cHF(jCAl;OO8U??q4lwNrKaS=GolRO? zw7JZ^HrO1qex6LZ=eZnW4cXJdEUx4?gh56KJNMMF^fs9glwu>%+^`wDi^TG0jIbVpnxpfO3RxFUH{X9MQ!O*Rm1qb)vl;SbsIL_4_C^tak(qxnBD|nSZ?^KfK|U`*7PGGLFWQ$68{IiKjQ90JT%-7lF-uYXC`xudKnQ{JK8LpEfMmT)y!o z*9ONtQuQa3C@VI=xrJ@d>DR(6)i>oTgI$zROPC}U{=~v|X2iPrya!ooyOmuI;graO z9Ofq$AKjO8YZtu@JpS^}+12RO?pNnZm5afz;|SIIGhaXJDo5}S?ht-ERVi}@m&%?4 zFbX{pm;;~EFyKzYvdBRDJ@ptexhxx9E%#nJq`;J*_xnRuM(H$&wv>@9rZjQ>| z?Euh_{B}K`{{@vizFvw33##m-OiSZ$sMW~4m0FiyS&!;@20#t@2!0DPpA$YuJVxS8 zHK0~3YxpnGwoh`b1(3!u?wNXEQA9-6#Z>Tde+|OtiVHa9y{~BHtV5)@P-=2&Sv;jy z`M!4t8;Ido52ae;eiCVMKcBCLiETnnX7vk6D6?|t1suIJYIwrMgmS$jIt6_n8e)SPShy>V!)`L<`l^V3l}+uikCfpp{MKM}riIwO zcVxHlskDA6SLMtT$fvtAP_N#RcrR4Vc=S?6C5_nM%m!`&v3mDy=oNr{cX!LM?IETu z`iHR>05g>gzn?a++4yMrUSvl-J3Th-*~5n~R@pIVW=a3xm2GS}|X) zMt#aeev8?>y_b7r1XQX04%4xQAeNVxyx3F;pdqVfnJVp}PkvAbwPhrf)bKgPi;OXp z(60;(X17hmeH&#q?8=F033}x}a|r~AlA4<9MDw;h_*2fbP>|VfNawp@D5kuMF+%<6 z6;zZ@UdR{`qqYzfQ{ojSD}<^MR#mP~+#Og#ToDi~Y09OYC*=;%>~tlO{lC=Hm$CZm z$RdMvT!?(S=O>}>gO-J(x5{a)LQ*oYM*myW!*&CfBZwQhDWkuXy0;t=TR_l3d$Uuq zZZ*@ewi|GyIMQDkaNGLp%^eK~w~#ty&F9Fsxf980wU>25XD7Vu5I*Al!i8X)ah2;p zztF}{um{zQ(MpUg3U{+lfI!-fB2KR6tn@YdF}pyP6rDdi>!d6~YpYz_LM*)Q{Kc0D zvIgJ~>jls4-u`m5`eC%b!lme*cv6_R@z75Gm!jaMU*m7KG#+IEQuu-!hr&n7M0C8h zm9W$=tg$XY+^CEyL(1+>J)m@cCPA8bJ=fR~muPbUMCzpmyz}S006Rd$zqC|i9Rc>T z5s97NhvE0z%sn+thYwUDa8Rs1099YLSmv}wcXbSN#$*4K=1oN*T#v--fHVxtr56E@ z(R@pZzD;w!I%WCmK-)E9D=lIWo7ql1QVGu{0P<(5G|&W2I5bL4rs3fO5`GhWO0pRlBZRYS{(YG~4A&?PU0dS26>FRfg#@ruZwQ(MRaFK(@mi24!>x^5`qs z8q_>Y-n@6ds}Y`FNEc+o0dt!z=9kCKD-hNoGHNR^EHx)(*UcMk&5$L)0@izaVl zsB5=-%a+bG#Hyi>5WR_9Pvz`l?e+iTljN5^QP_nD;tRg*Jqj+Z!b?~j&dLLBR~#7vlBv-_Nt$g30Yr>p{Zfri%s)*me?$brMVnCzqU zue};Z0vrir{4r(xBs&@^J!keyBhoD@5(K0v1)QS?iZ;pw6m+E;FjS^q@ktpc0C?ZF zxWAR$J!w|3%1uj!m4b+5cbHj|U5R9)#9nlak-%BZ4Z_OIsHs3}uJ*9E<-*y=1sT^p ziiXklf-u~}0u8$tbHYYe^Fx#iwAl%({|qKhOxZ-p|=aD zyFw-Lu|JKEQ*_?>$~^>HWe3}{$hgU;4{d1sE5*Fz9qnk1M&Z{;~p zaIrKjo(QGV8YUt>ULEl97W`sETjN(Dde!qoxZtuO%Jyu*q5qda9Kbk~ZyX{iRcOYj zLkd=ZAc z_yJr=0A{?>%-vah3_&EWLb$4|v~n3>Zzqu8&J>NNt9DYyOdnEsVg}5GX6f_cptbs- zmm$Xzl+-h2<3iEho*IB?3C>B^6o7C0uGZnbIxRFfYBirhK*oz~B1s^O+f$PkKG0?g z1d5E@+;&s3LjFl3xUsT+?pf^tfD>|;QAJs0`sQQB^@SJ|lAayb4~YusE?C6d4`dZj zk4p`Lu`hQK0gi`DyID#tRhEn4oS8z;QFQ*WcK+@vMxPI^rX-P=-8$AqO-H9v9*7Cp z18x`YrQ+Zn_~V!byCr%e3yx>HRRy_$0}(5-5WwZ6asC`Af~v3R5v z5Pb?@007R}hv%%eOAGnZqbR5^o8@NRf^2p4>x)cf5bMQ;bpsQ#Xgez%r-3*_qZwjF z8#5aEH8;&`KX4ggT`vI>e{b&`Q|koJes~Iggr9P${8y4>fC2WwKAh z@Mu8vVb^+CyiF@4c(s8+Si$M=D~}QXGcWSM=`A400zfG?dI~KRVA6A`o7#dLk7Y9rwIAgzOSvL#ZJckp@<`ppLWcG;p zq|h{cRZJ9^_+}$rZ}5xwk3=xAol_}%vsOK7F2Rml>OxC=jJ++`GF$;N)pX6G#w~g*UsQtpW473BhqomanpkIK3-WBJI+uT7c zr>yCNk@-XuL4d{tRqKl~9BrWdyx35~Deb6aRa(R={M(0gp1p~~S1owIST zD4Zu3yFtWmF-Ep8CW1#wOe&GE!lTetPkh%N!HzFWnyQJTQq?(60n#;$suMF#)_1>;TFC0jx2q}o? zSh=S@Jl?-XrTBmT7kqp`QZ}%|en_|MU*d+Yt{Vw|jOeqXL<6}v7%bPIywug!Y!&d9 zRB`9051`MxJn9(K7Iy5eSOGYLs1brKn-hFoey_X?&#+jiz@Q4P_ZH5DI0DaH zTav{j<(=`FA3dA_sRc7F=S(eq6^Ei5UG6FwM-xW#+5_l5i#zAxA2TwmrO`!X0)Jt{ zqV!KQJ}1VJ54#);-y4Ug!8DIH_&X9nU-$=aL z>zy&_r9t|to>r$Vxu?N^X47St0Z)l@<7u0>N~z^i@K!fh^T_QiZ(4*_Uzea&=@Kb} z2PK(}eH_0e7)!bhWfSf?%EJ!;409qYh~|88Wq;+ z3bRfubA;^xaH06N#OsB4%T`VhDy;CZ#wa9XP`hi}s_WKQZ zW-MvmO1k$9pyDVTt9;UXbz=pwvPi&{eJcZx7<@E{?g3as62nYq(Dy?`{^{bhcLN(^ z63u8X`r3DdVq{Conz&N2QnM~Twpug2-Cis}4b{#YnO?W2?av|^V~@)=aM#A@a4~8& z!}sJjG~z?oJ*@QiBMk0znQm>0*0IR{2lb)17V+n@K~Y zj6+1H_AO_Ao)MApBSZ0g|DJF=v~BoQ-%T!cnWY;0?|W2x$HSCcnWhT8pE9f)wm4g!kL2+lS08Xm{9|E-_3VI znfKY6VDB9- zkkd1GY{_-}eu@0s-cv1iQ8z2?J zxfmz*_IVkjS;izdMUi%`m7*HSKsL((7`NYavSOFcK6oA>Lbv^&L7e{0tavRLi{WOp zDN)3qLLAw3$rCs%9x+>N_$@0Fk@l0B*U9H?^liC?cXYnd7~bM%%l)(Ypt1@w`|a@{ zbG#jSu9&L#S2i*qGz|ci0@hD+;N;r60VCmJd^akp53&8}3?vyTxam||VZ3Rx;pe=> z7y-rPR>wqL#(s5RjfoQPcO0l1dT85kw16-9T=Ry?Fk0hk;#RNt93G2hooPvwc~ehJ zYj^leO$5096J7SD;-=Mr`Y*QFKE-G%imgnfZQ_-SEwH+c))~2%fnVx;K zRdZ2>Z@7+*P#&L7`U$d4y6+G(a@mvr_3*|X__;qi+1cp_J*C+L?g?3lLSzku0i>Nu+4?G3f;&mzp0!Xo!28BCH;mq0_nV?>9A<%Q2q4a+# zoFKb|d5PB(LXCIJXX()%t1O77*NJNkNQ6r^UF=yv!TZFy7?e9K{5_~%r30+e+foxl z_ROSV7@c5>U_|6;Cv9!Z&-7SV?8=`opwDh3R}>xVYkz_4cD6 z0R?MU99rPzU4;Pr6$;hAV*KNCAyMWS&*^5?8o13YcUbHrhGjTngYc<-=LyH=HxMcr zwA)o45K?7)u**>Y`C{1kIeEn0fyU_Hbmr7*yzf3cF#4qPmFrwroT1r5g!j~}S{?fG z#w+=e6`dl$XWcEw%O=dx&+k7mU61NYO+XdDs7!_x&y$@@n#$jB z!cBQ*h9_-}NQLp11Socs=*1yfr&n=Cd4Z0RM5gkU#MouP&Fel~7O)xxJrB5#ik7*| zWf!ZbTlRjuHZUVwN)A$0o0Q8?Qupq+RxFZfz)($!sVbRlwx4zfFo>^A(sz~`DNI|W4=R1pI4!! zY@q%jg}};ktDzBo0@E%!2E7^j@AeZ0d5erPCN_ri*9-%LH*cc4VV_f_p#WwjB516AtIB{8+P@fG4ps zmc6OZo)7b8qC?)8NI8o&6ucHPad;C)*G%geQEj4@!N^eM{x0#xm`8NJHuKAH*(jv2 z_Y2ej7xS}XyF<<>s$bJaH0PCmZ)PeF=e+IS?1X?-z9s{7r+?+-BoCD_OSRA35k<2# z$R->~`}5GU4tIYuGJlNMvSZ4!=;xA*Q#vBbsisUPdt=0nOO9(?HcPY5!Sr~4Kk^D0eX0-Z_+5yhuOG40tvW135K7dL9~+6~5Q z6!uURKsg#Zmw1ce@R8S9ndmg?oTy)b+C{qyUnM**pj4OvEfR_sqMm?ud=aTehn9Y~ zbnG7akdBaADg4x=L!`S~i6m052T^rG7s{Pop9w?4+i3G1Tg6AiNOKcg1TaqTv%D5_ z?(@T7ITbJW9|amFF(Xu}csxa5!y-)(@+_v+r)#`qCXzQ=q^rmfuw__tXD~-dTE5t{ z-;etgzaM7c{3|H8&RL+0JUho&Y1c>lb5vsQ8qRdLs_fK>b! zeSCcDjHoaLy+UD}?kZ4kZC-(G4`>d$ z!crgiXF%*2dj;MO7a7jehP};Z4YQHnD+5U!4oIe=5@e3|c#=TkC~+G$G{l(ljtB0; z9z?0Nsb*h4XSo7z@Bt(A-?-m+6|bYXY*UzxP?y!ify~f(kpZDj({GJkHm?hL4#maSi~b!I`W*-B z$A;q(+QhD=XFWD{L3($OKfzyaLIelw{)eCXni&kyGg~L3Hm+ zeobpp%Ec$Ex=(ZVh)6}8Y`se2h?KWUjIQBD_$94f2Jy5WgB^=XM#3laeA<55Bu-&; z3xR#bf^c9lDHH-KZ*g4pEKcX;@TqO1=gGwxu}Wpo!0AXsyX<6<`XTT|A|bcNr9P5$ z#cdG#sCpZUWVqKmU@eLT)ms2$Hz4^?20Ys%;tJ~*25tmw7fi)PtJm8H%c$d9sLqcY zW36AUcKGIxjyC7I+8rSfQdBTAXE!10_F=z1hed(1G0)QmW>O%m;sj5aURFtwN<@gb;V)bko z&p^a^r@@Ey(wbJps&8%TaO%#-34sUTd=_SjAXa?;ff`nU;x(Qj%v}Y_=Qpu z5*FzK1hXyh50lq$$M)y}3}0rEy}8Gs&qepB37WbBYX$^f)_pV#5*PcqW=?LQBenZwt$&Eij6*^ z0_6z5?@(s%iE2(?mzz-`#FO=+fY`UNJL{~KIX7Z^6WjQNqo{&A$h;@<2y!?UQ3rbR z6UeHH?g$eBy=rfb!?OzUe={nE98wAvD0Bt!ZP?W3vf_IXc%LofkObD~ z6Td%JrSXE!Jku+Ux1e)Y{4!4(?{P|r>KZvle$!uv)<)S22)iXY=qKLgX&oT!>gWBO zyT{b&il4%#UbdWN@eVITexc-^1+7_sb29!{{RVe@rcu%26Gt?NzVyz#?eKM|ljvew zM}1ib2E*zFD{K_am-zg$TX#T8}%t8Hs*OVt}jO;l`Qe6p*0JTNqkhC3;>* zi&|nr&j940@{3d7X9XAgaC@dvJqSBbr_|}I3uQ=zA{X-Upfj`u5Do-Dnl5AqkhDpY zQ*cql^=Xu2R*lg(l*f_L%X47L|wU_x0U#ywB3Ra(54GlO$1PsF!OXdUc$R*`5M zt-mH`>tS{7;}M5R*~>FziV_p)p(% z&rtGZPxYexjove<6u19ijz=S4x{(!g8%2bY(0j*w_%;=d?P$a!pK{aEcX~%RRMgB2 zdt#p3c|92^Zx*G zsrka~LM};&GGgxYQ8}r^zmo#3n`3qNFRf%R<83$Bl)%>*i~QD1bn?8H{Q_qV2m1Ne zo7Ct3Y#(WS?##Jiby?4-F+m5|bKxk-fDlGbg5^#$-5C~e;hQzNPmr*(rT8psQoswy zLTP+k1LU&}Z$B8zM6xkPg-^*an$o;%Db4=lXsjVqGZb+zVgjz-0T_Q|^?L~drzZLH zcF0hIEh7VO3F2%}2S}Jjivgv6BQAiab8bbNt^rgg@c;z+gSbl|A5ed~xVuDUGOl>qQa2)8*}d|q z@QZ|yG{wt@f0VX#{A@My9G7ENEYFav7`eG42p1|xCVS<<31=PV{^YDoq3VmwdI-u} z{C^jrd~vNw`7M0t;dcMZV~{$QqaIS#=I;ucdv0uhz&CnxbvcpQnM+H75zKSDyie`# z0PQSrM}NK?aD`3G2|ROi%|1cR7kl)WLXcieDm0}v&l)F!4pN#nn3J6_?se>9ajl7p|gvD?Vt zQ?S_|sq1_UAmKKYHo&cadW9=PiXHu=iTSEoL}NhMWrTVC%pEi-=k@sy7b#b)F$Hli zr19+9zuyHYM;u2%gnNBg{#Yd;%8- z^6z}9I||@!#RoR;Rj=s+K8cGdSE3;@O$RG7z+HR+gKF$F50qxfA2|Vm8ayzirLML? zG}7IcI%eOi`WNFtM9w`~vMOYU_eltkaBw+UzYMAr1!g3#RHJiSe=xLAoe6?-~=-?|V7COFT8i>84gEZ}{g2+PaN zEXAa1WRhF1BC<}uY2pc4EkmBc=?Hn9ju2J3bhd^)m_S-pHpYb1{eTHz)H*uH77V8n zcw{GX#-a&R24+Gn?$Fk6!PO`!35A}zZLa^bhzgmbt#3+s8i(|}^9onkm#iuP#mfOb zZrmOAUoANoa=RZGXQB0PnKSN?7CoD$$UB&MFLw`vyo+MXx!736*K?fLa4IOWSHW+Y z@dbxl+$3{a|NFiu6>zJal^j#wKqu}EgF4=)7|yLdkSW_pBfI-A7CwmIiprZfln|i& zj7@-E6Oj3?xz8e^R%9iVF zfe`GPTE`ADqD8l9Ic0OQvfKTFvtGmILRC2&u@aB5WxwAAPlhM0HZ$n@+`B1w5aCYQ zRP+&V1_2J}2LX?cN(BL1W?$1KzBNF1!zcm?hC~ zVzyC_RYR>`2w-7svp5t#2V0osk7c6-FX!oF|F3l%T;6wD-_&3<4@r~0DT=fL3 zG48BVHPAF3pZ$rereaijxE>RC3#K-^mL7SAW7YCmC%20#w@Z`g&(y3l+6?#_#kFpk zPmK#n%?WZN=Y$XBBrE5}lLy0R3!}UhU;PL1jF8Bv21$#xnLHNmBF}N1B$~ya1`(9T zhhL#)>6r=qWjtx)5Enk(Io5pHMs$AIH&AX*hsc#j=S^q_aH*TMCs|=FLl7W0-m`@cq%5F(=j@3b~Y{n&D|3rLp(@6^ywTFXn)0HV&<zWhMd{bimFPbc~b}uxMh(nX}3CF0caC8LO%d^MVC2e0qA}W^IqD-33Et z7&!g*b0g(~JCkJbE+dPnV1f|qOY zk4YS=uX~TqPoGrcg>m}Dh;=;(GbFuRwwg<*g;*7CaJ26>*4_DOWRlr{-K8TEd&u*) zWtuw;6W<*>4~tFA2_#67xRnGW=w2OT95`P1>=~oywMsd+3xznKx+pPJsVn;J_EC4R zp5hXmgcgcY_5o#R?Py!z^-t7;Yx|#k;f>PA{##QWgb#!j6*HX_`6RsqUwHHTHdLvF z1W-6HR2#fUFpHc5GlxoXvA5=GK`IhHeGUX|)PTIuLS^b-ewY8axpk4KQ^iklutPY)TK=7LD&u(|Cn+BVV2VP2J?84)j7;hM=S&1PwLhuBhk= zpsH?}JRAq;4(^!H&GbD23(8+f#cs2~(DR$>H(360d-i1ssQS9bPzLnbl{Ic>kTF>M} zQZM~@OpO5dZ`%JQT#@>pQo5i0O72>=D*q3>!_%`H6nbc^94b~Cw4!y+3QDxu=NHL< zOgPQ?7~;r?H$4Zc8ElrC-m&%EPxB%cgAY~rm^zU1&Il;IE4^#r+ms&uI!hP+(u=%) z0h(N8Injdx*_J5~#H(;<;9W4?aG*vG77g~WaE(6gBRlCCB2&OBj86$L$5~s-+GR^Y z875~4k&jXsWzc{$<2mf3*&-7Ivtq7Wif-c|mi0vNO9Jgp+fZ;QCI!CP@H{54ykwlO z7TJ}bf4%b-=@L=E1^{;hrt41Y3uO8+NGxhjc;h z#}A;Zs;KK>S$|q2K#kNv)+9}5LD!o>)r!s&8Z39j&x|**orO4|5efI*m?)dMb4?{j z0ap%V#KJm-s8C_~GBG^*PCx_*0qrT80fb#IRWVxDE9tH!4>&9p&kyVxN{8S>um@On zTynE*J5X6l*S82$_Yn|3ZWQCiVJ>L~4sQK6=bfq276D>*V-h2L-@^jD1rS2FajOb% zd)TOxX3evRr{e<+24PGK7YpnTZCY_>P}2Yz@K?vU2UXEetZdE#nI^<^QU5oPQaPXm zqhN=8-M5Ss8q6#SmIQz%O(TjWxgzXY6r9zPHDE{U!y?RH+&J?w$2*HMCq?T1C32Ma*^!{ViVV2k%04m7k5L^jwZFv-|E}xuAL6e|5 zGkTL@dQE;qp!`2jVy!cDt*Tyh9&~WG2*7eXc;M=u0W83%l#!>Ka)~Z zpu>=Pv@`fTUt!2Yaf8XwzNkxrH48}<4yaFN$(_ANdU3N36zzE=0L&vyXeM+$3v+hT zIcYL12Um>1{2hnU8ou@0;MOC~1sy54>!UUHzD0h+pKlb1+`^-cm==^deSKDf)AMeYL0+$^Cj}(%|ZKdz5EqR@BlDQPHk(evQvkE1v zkjc8^KI!iHYmsf#iPggidr3K{gp?m!(NPU~`NC%?znYJcxi*{9v zsiU8XfWY%u3tzL4W5=cIBPNR)#fmc{|`|x284GjT?Slk?y z6C~b6siZSQFC4*fX}KkyJ{!yuMpBNK^0caj(^+!CIr6-5YAt5jwP}kMQtPBari9B= zl3rrPKMD>;^YpxxZMv={hQaRyzRKj0f_|dzo(rg*E}(?h7X@RH4zse`piQD{ zU1WMUjD|$WOY9lH@mhQg@Z!uy)jesluo#kEz3~6pvJ6nyvx>dy3wq}hMlD8+7B7*n ze*|}5V581)ce`CLevL$m3r1^&n4f$zio+jr2OKJfiaMBD0G@jCff*DE4(t_3RRR0& z30l`#5?BKqaz8Wv2^Lj&FO}~7GKzy;fzqT36#R~{N9|(e-FgUIwCX(~%-w0&;%=rh z_|2qX;}-$ns%lFkDk{xcC9LfH60jABqWp^$=PaF;2o^^%kcoF7*CqsV#$a4O-9$`Xgz7_ z=qTLV4Tn}gsAe0X5{Z#kvnDWWz`1KQ)#qjr$F3Er?$3=)cCbk~GhkGZ&r6uyr+rbj zf?Sz7R6mHseVd=e3LQ)mr}x5JI^y^yhh11+bl;QK6~6MT@=@|)h25r1CQLf35&L2;ft2PV`O34GdC0RzgMSwj z!|C?9ZlEI%PybU4uGbP!I*X!#bZ!k43GW{?g4%%0zgfpXk0}$jPDmf7Htw;6W?2e_ zJv^~+6`52S7dFqMVsfNub2;HNNvexZ1eW_1i@NkJr#kzAJ&sAPx=fI-s*`cf*kH-xJ7-71D8mPD&j-!GWQh;Wgs}WJqNpVL(6`r4aQVJI!gBi9 z2?_~4skR61Q4PYCb$5u28(sSViAhghjlmn5@}G=4)e7PNTNhwCZ&EMZe_UQ{g*`dp z@3oBCZ?R%@38X^fp|Ni;VwxVpn=ktviTpmwx3gLC+R|&qjzpvH@7>6e23<=k7vebx z6(YVtOvbN=E*uQ*p`La1<>S8?c~-6!&<-jw{8B687}1fa<%EB zMAw~(<*L#n64QRV-5`mS&-sKe^J2O|&C%3E%mGIlW*~Bt8AADpDQ{!YMbmyzlpC_t zB@mMyB`z&55U(VgcmVVDut~=X@0zC{qYZhwxk}O*h1)%m8NDgzld<7~Cl)Z?!UlA5 zrKBA*%L!gGG*~JbGf5M*&3fCY;RZQ>5ub*^23Rrk%SRpO{GAbAj2bSSfBR~)7xRzB z_y>|3CXX*cq?E2~dm%w_(f7;$m>D$?tWi%UUcG$>VkyVmsO^W(0p(Q@Nc~LM$4OVT z2)qatXqk9m^()8;*bG&RJX+n!5)jYv+0U68cp~tQd}|P^CvC43!;~^Z)kw|OBpKst zA5iG2`l~&}-a{JaU5sc;j8K+-#Xm3;Im#I|A~Rm_UiI|Bny8yOM+*gf79t2Dw@K71 z$Sk*eol6Dh60l9G5T`^HPFL{jP>WsFtgg03O-g-|EF+9_br`qRBFWv5|B+_fjOv59 z=Jx&%qDwh`uXEVU#jZ)n*@QxvLQ_oTHz#(F{_B$dY;d4>XeYV=u)got{mD@z%5W+k z+0}`e6)W%(*ND-Wm2;tGu9d2{_#!z1hC{C$#p=xE$L{#DSOPlq*$zXEX!tivzgr?x znCWKjCeXbR*iGm`F5B74yWVzYgT*OjIlD$D{fnS*WajJM)vNAr`UjCt{m(lm1$2>M zYM>(AL9vdkcToC7@Nk0OG4WV_udQB4%_+u&v+9g)(T=h{#)6zt6>4$$vrS~HuXitk z>_zGL`BB|Xdzb_&j{61CR^1uCq|hLKiI89{^42oL8f60tS!o-Ni^M+<3&%(*i_fzvt#bi8oD&C3zk^2$3o zsP&$9=E(1K`aHD|bzi@~HhN2xu%1WiJ|JcH3Ugoa0OjSgs&{q2{nQC=QUj?}BlI+G z$clg(y&2$?jhe?l82;bA{&RKnHUTM>$d@7$rGL7sEcbyS?#I|(xd3_74EP2wLdNH9}a^rP7;lulk~|5K zwIwPAoY!h-t)t92QEP&2y))&bqi7Evn(wh8TVej%%1xFsYYbahGZXn&1BpPcvOwC87JvgO_A^)1W^%LStEoQk zL@PmFmWQh}Pg2MXFw==xtZTbte^BPP9+Y~94VH|E_({nYO_`2>*Ed>4Am?RVVsQhm zDYYg^0qxb9b-KJ=bO-H+wio3+pN%;1gMwJ2AJ3EK~e@O zy3aTtpy*xY>D=@kEd9w*QVl2K*?E`>iNaF=i8jk7&b+QHDa}34RAB znxj$xegz_W17#7YV8g->3aYemF*n99^bjY(jc0?l*8_wWAzOhJ|F#9gvERMQTb>dh~*L|!Wq{M?**Qf>JwlA9mMQ7KUn6^K_9C_-47!B~Jb!3FbaZqKN> zHMlV+iV-`S`MA9Q{$xc(NV;7$3sE9}A^PzZgyQ?wk@S&-!?B<-w!fWX1tQu?F5UG_ zu@HnX^_JFbw{dzy?-H-+p&%NpZo;p?2;n9NI*hmQCcV>grWsDPS4yrPSNaLu`*hco z(fTTo;dW=q98IxVU?-yvsGc{7xds*>;wa*9Y+}($JpvPUI@hF&xCD87j_XIyYN}f4 z4+{iq#roLBZ2yE_)Yu6;6fS?tJJGc@#z6uR+;|8ERn8R!{;#5S#YWo+P11 zRCN)BHpBxf-tSvDs|ncmg0GlyGii#vg-B7bFOHt4dYfm_37EF;#He;mT0Az#?x}tk zbS>&V*#M^i5Rz52oTt#(wq@IllJ53*X)|OQMh<@ScB*|c7uI;6@f{J&&Noa!`TmMF zAtD^$keN*c7vL}AOJsw21=OG@yb0-#%i~|Hy!n`nf5_Jx^uq-z6xy@j{J`K@I)S|d z290JqNUEz19=kjVRB_2v0$I@y0&&EVQOT&cR5a<>}d}k^^l!MIY(feTT4`+cS2)cPl$H^*o|~EO&2G#M(dHLAaji4(#sFVwd}{ zai&wMPBP)qlq2)!5*A%uA~ZfV9s=mR@zA1fzZ#h?Ft%UR-Yv8@jX?Nqjy3KL2BW`4 z)#RYIwfHRK?}#M@cL?p;MfG0YE`8-Lm0v76)7LMl>sQMp5%t0?uO2ZIn&ViS%a920 zg;pl`{wpI^vw1`BZy>46kIiN>vMt2X7SwaKGDE*yqi(0Jg%@2COIc(ZW|~4b$H2m} zl{2FYwc`9V0y~A`Ef;kc-kl+C-Le_RLF_Hy6_BAP@{tQ!F3R5}6Sa!a)FYHf4)o3( zHJ<5SQ$@WDxsGt0_5Gtqookm#qRK-wi+7qAh15s#UJ)C5s^B$lOah4%Ng3M|^1~|& z(~|pz)EWzl&0Bw6Um0j8WzA@g339|){;v;;?mdjVxy`lexztu_^i_AaHeX>5TovY1 zuAjs^dq2(KT*&h|x*Kc6sP8r5XB}CxGI`yOc};JAT;LP_P+ElG$HO}kgvb;18@Xb7!)0cQPX_j0{87Sn8d zgUKc}7B6VUvtZiuNj-X+AigFZII&Oc;i*Jt78c2Nov593!>-(3_MdxxzvkVCXl8H^ zw_M`$)}zg~3&%kdJeM-CDv4?bo}SXxPJCA4<|QNew^ps9)i%xMU8Qb9+7ZdN2`MMP zQ;7*9Ee$6z#lXyCQa^PF63;F>E?XA*094x7t{*QS`BB&_++)az#0k2Phf!Ob^bQ$H z`BDXKi_Aj-(Oq{zy+PD>sE)WN%=phRp3x`N@p;D|&m%N6W=7SG3GR`?@tddNuTVeO zUIM^hVR7Tsyoh&_tMsF{Y~^`>apN}%NQc<$Lqj|RiNQeRiPPQftiwB&0WtgFJM);D zBiN{RE&pR7GW9g{R-tLv#_@!65tqpeOy-z#kRe{D4O1Y%@^#05_yv5m9;QfdxjpF& zs194Ap0-PkA#oz*lJfAU46>{RzT0A>)(+uVt&3{O28q4BJ_QCTJ`)%>OaHgoJvLL0xuEbFHz-O>9HY#4vuz6@WXPp%^>(nI{zg87Qn0!;jPF*m@55SlDt) zUkM&TP8YFTMP;CtW;z$Bcx162w8{jKh+;iv-TF5OvFnW8m@$xBH09fmiQD0}##zi| zLF^{NtDno0uVppwGkLD?5mq(ejw?|!1OEu=^gH)3ezk~MElfY=Ss_J4BjsmHzkzo( zu1$`56Xbx99LBR>q@c$XF17JuaJ^u1KX_}17T%5I!vilXsY1Y+ixE{xTVM- zQyBNdwnFh>^rMrN!T$3AuwjO%J09U-P)#d<7pT;~Fmm#nl6P|;OdR!1EYD<)eEA$q z1{(yLd!1O*$e{(weF2CENF^4*xdr*#9}P)(_^vWWJp0aDOQlfrlP&eYFV63Oqa#)P zk*15I6G$Mvyg~RjI;9G2Pp1r*xqgOZELn_*iN#*6_mu>Ux9g85xcwoQ1z~g1f=BAN zJ9odLb6=DxAZTzNa&3_*0l#&ss7FBk6l1hU`++nqlrQ3LBmZGNhV6aYWv>)C^==gH zJWx+3r3M0+BDe2KTI@b_wkx!k3biZl-pmw{Z5`*Knl;)08HFv2DCbDigcTEi`qc8K zOvLb10lYOs%0FH4p0ldPWkqM`4RDaXr%@1s4&NK;q?*?4cB(zqwN%#UznTAlYT4tI z@R58un@M`@%G7~X>+krv&7E}mW?#r;+^?PWcSrM~T@PNBn<<-*hCK~JRjrI!5F5v6 zvX4$9d(v+Md3aU+tZr^KOixAn@2T;zJ!YS(`k4Xz^vfCIGrK#khSgZ|lMwDg51Ltg zOa8p9^AMOdHfcX47|p%c%-Ts?xu2)?{07u8yU=02LV-}p^w%cmLTOxId~fjihUgMQ zg!U0yU6g;;^#h{$^E1_;zF>`1E2i}NYO?zQ!U#Sacw@TgVJq^oV`gkTTQ49ZJMjZT zS%J2pH!?Rb!y2TCP-|Q_?+ZO`=YB%@9TM1ae%03*3(2M){sP9o-z%GV+r6LuK&2D4cJ&*c9BYYx@6Q7BfEmo+BDD79D=%^e{Xzj^MP4T1SWM6TRn&H|X(v9OGu(22jH`Y2X;u>cCdOlW2x9;@#0du=5ySROS_{GW$irj z*BNo=94CA0FLYTH5K@_fu5;G_zw96=_L;>-Bb`|#25(Q*T!byE@Qa3(;b!JkRj;wM zd;sy~?3gvs3t}J0X7?e<`oq4vvUdlwqYbpfQ&;+WkTvAuy}Y*hDZlwT>j>ZQ)lXZ> zXkS&xD+m`E5)UgUCYLkjnVJ8=es3kMAa`ZftJkLJ)yx5`8X?i_!o1@-zlEZjqr}vl4Y3V*ZPKn&P6?8t8MGTjB$|CE=trPD z+o(v$Z}P_}MB8%fw`Ccngd*Z>?~Tj%C<8#sdHfISE~UawyFYBQY~>w9^|#18#D`ib zJ2LzV+aZ^2C-Gz-{N8(|M?&5-JGN0%scqsldK9s1ao|^5ajw)k>Buo1{ZjKzDw9k> zw*1u~3mKJs@UI(75&s+G_lWw+{9Er#U4U(W0Z(1t#*4p{JXN?X5HcCNMLT`Jiz3wJ zbMnb!R?&A_?@DDy&KvvYC|vestjefT(fjeg&8kuah&lP1vr9#1X5Mo0Bb+LU1Sd)<4fXETAin$4rIvvODjHX^+d2eva56qNKtdS&j z=eEsBw7)rMDp@Q4A6%aWDMRF9z~UXGW^`T*Q?YtP2wfY*|nQi^5Ot>45t zCgl^%5%Ah5q(H4;c|wQ}sl(^#^q=vYYz!rj`cYN)GukVpU{kI2NVrqdm+AzW?Yf87 zI_De^T{CELjcPHux3JO_+De|Gd9febpC_C7dkzGgF`8gGn#RU2&aI7CHlQ1th&H~O zcb)3dfJY&3Gp5AH%J@vE84t9d9)O58D%jMs*x}0JIQAvq1D|dOo8DS7^gJZY^Y}W z&;yECU#J@SEGCsiuYl)>M)iT+P`xl=tx=ghi({3n|=7gBC*z<4}7tAiiS{VHzRSWl($eu|qwS6)n1TElj!IAj4*36ioG%r_lN`a(2 zo^PpJ7((+mCx7T|9@L7fRAC^M=Ms>JEK&8qI$IYk*z(@wqX#OI#57RjhZJt0#r>S3 zlRoJ>if*dp=s1-4x(6kJZLcoZiQ^#zoKUv%M%gM@kLNC_BowXU|Buc|aq}6J4R^;N-;bDLU14%Z2?-%~ zb%edW$%&BCCrqV3c&Yo0ggdUz8F3H2E5SsR6%9S>lJ<|nx~eN#VsQwVm1})FGu; z*|q`b(iJA;ic&=DgVB02erZvj(HDNUc1OrY{4kl=JI@AGOXaONj&Fx6_w0*CvKdyo zFe=~O9JuCXMP_1!j(Gm=lc^5Jo2?jS32$6-8`Os~_LPZrGMJlO+juIAk15dYpDOZI ztFUk+9Vv{^f~(HRj{vtjv-o6Q@pL9%gHVw2XLL84+BZE5gK6vuhpKesXC zu_@{$>fnpeFA2V%pM7O_g~YmAteV-i4-?m2dgBjV$R61h0|u?^C=qC8zt z<=D=@iVgsV*`$9~1cP%~T^hBEhw8T!zbn3)%sUq5C`ye?7v9N$5zgQ06N!R-Re%}Q zsf6wXeOnb~f<@LlMD;7s8IAp^BvzhxF|E_=iqSaQ$W4D}c{_Qr^N%qRi2jET`vydS z?*0`PK&?Z!&EY>jY$s+Y@GD@~krjf^Emc53eq#5B)s8Mw-Git5#wNl(eC+*&Dya@lpbrc=hZt)` zM;C2k{=^fKL*WX*Ga5M#HtM!;2*y_lRTp8KP^PQTrH9}eL^5X5ZgQfA6Y#g;6r%X9 zU_!&`B=Tu1*{*|csi?+@-zeKxLbeD*Ck0#O)=9}NGan5`w3Ssj6-GrpB{_J|nm@En zxV*TH8H|mO-*n`{(BBFYRR=A44Nbn8=2!g5n={|GAL0m3La^pseNIhd2&Op8^7R%; zVVX!Gz{fLjdu{n4(Sco+GaX|jpp-_b8JldI^+GFAJO!R@{mqE@Y$63n5H?U^=yTCs z_(RX zH6)Ke$?u(UHK>-c7*e45|3ox`SuVQ9bz@vTN_f5ADh+4meBe4S z5zNQPx_P5whxl+=mnfSE71Ce5eX}NMcVmBlPR_X^|K8|Lj`IL9|5L#W@ax*OPgtP`KM|ORL}B! z4>ZE7S8>RPw?mxCnNHNDwn`^Xg=rTCuYtY&paT>0$gxI}8p9fE(3nQ;`Wb2qFGb;0 z(SvY+&H#b5;`w6eYiyL_bynZiu?6rLyBn#hrGS!fq1J%iq#Y?;Ow;7J&ET|co|1}^ z7uS;c$@HIi<;1!&V!^H~mysyP*G*zfTDJ&=p_K1rMf7IkYneUyka2^uU#7-l*}8qj zJIjs#@1=2JjY{Gj0}ljperf>kz_wKQHw#ujFG{hT3q9Wzvc*Bx1FSw!;`EvD8DoHb z$f#!1ib|l9x{xd*vhqZDo6&1n{%q*0r*7uG!pvJ6Y#yet_nHl^4$ z=WN`bpJFf})tR?`z&9aWt3)%@K%U9_zpI5r2dCe&0Owiqh)zP5cGdL! zsd5g9HKWz5JsWc7kz!fYrdj3#^|F&3bpg5QM{X; zP^dqIE;~VQzPScuSlT`UYQiR%384t&F9LPaLL&1A@757@0)VOCzmGCcrNju`?+reO zdQ}}Oy7|CRI^VbJJ}#M^EDNg7P^JxJ4{rc$Ji2a2_z4LTTVE*(#6SU*@XdXIs=$$dFGmmtB`J$SOSb5luJ`!HFFcmLG*Jwdr2T+w-x z-Xi_oAiz-kAU(mBHa|4o5&YHk)goCRjqW>tyM0(tHike`c@8-qcgdus^zVZ$FeTYSz z0QX+I$~+VZ3I(9Pqau!01L~xWWfbvyjobPb1oSl^KRxpUvnAHL`XiF8hGNe}rdKJ31)xQ+h z@O7OmlKhKuoU~#*1r6f~}~AdK%yHT-94F!%1k=c4rWq>qp#r%K{gg23vr1Ue+5 zOy9zvH@8j)((;CpG?8n+elE*BfP9#EuTRDMkpc2~qkv=N_FoAC9uEo_7byMN2UZ+1 zC=aKrcrCeLZFiN@vXJ>Y^EckD`uCM=JCG_9T5hgjTt$B#UN}<%WRF?QXU-`6ZzAr3^9q z$Og>@`75mwNN2h1=}1V6&AxzJU5K)so|YzzU`A`{IHZWQ!$eoQDI1~GysW+nMySKN zc0ourAlMqXc3a}X>e{FN50GPTSrQVbjIEn#uEpj0CP-VBbYxTb`4)!a`w3$&k5lAa z>tW@9)^HsX7s?L=j8||=q7!;4yVkDgJb+^EG0w}gz57)D#jv)a$7q%yJ_y4R)YVjD zjSv@&XIj%gYJvDJpl&Im_TO?^_Qb(d7Ofr5Y=zH%K?1=p{7aKMyIzvh#VsGj3sP@O z>UnwUU4tBulOHRtd#N;vv)nJ`$O~v1UXRVf?vJ|ZD?&z1!0SBP5Oa%$ly3xCnyQb@C|fcjzeS;XK5%< z0*R#juN6IaDdTnUH%_i*cPy6#-ldYugL>jthR6a{4YR}x)=3cOBdpl{>1{4Wt1^{> zGQ*>&SINYC%X)r{3eDH3{|dy9P|(KuR(!D8T``ihrNz}p>vW5%F1jqTW~Xs7Oo}N( zGDT8Xb^NDtKMyoVw5gPhT2Kx%t}2yX05oN3zZlah;kcc{+44Vj0ICvSb2f5aBu|;L zq$=xD04g^GstH5M;olea>VQvMrRUgWm{5)#UTfr?1qkZQ>4n=;wuq|-j0ff4p`*_oF zJ_ZxzNl7~&k_5^{Caq4W0&DCudV6Lo#aFaR#Wh>RZWgMdZedc=ERP=+Q%`}(yP4C7 zwT~5xWK~#(%0Dei3l$!vtvR$qnUnyL7WcJk%`>Q-{ITnUQ=jAI505BDYy&gH&bR$= zN>nj#pm!BU#;jfpw@oDccB6Ry`>TXQ%2HR{AV(UjQ~X+Ab~UttbCSP*2orMpwS!k! zlF;ln;G77YQB@&4xqS$jzZLuQ1q#A-_MfdcEWM;43C|<5Dh%Lk{MQpoJs~^8EJS!S zn?iTHV!$)-jrL<<6DKA}RakY3K0!jB=xc8vQSu4cdbpP~@1IU}ENhJjW;t)Z^Z?J6 z$gXL-XtH^_j2|^8`gS`=!7H~-L=`n(J!D3 zb4|6$U0m_E+zzaIlZND>pFvAji%2@Nly(^XUKiB z6@Kh|1-2Vt`W1{nVWUp*YqH)NA~O01787=BNJ(C1O)!`&CRIVw_|#!*&Pd>lrg;2A zfIflpP7}GQ<(qnM0{~h22uOZHfVka}6l^~o;}vu$E=5XCF*B`j@tOYg{Ojx`Y4Pv80;Gf@?-1Et zqEF_G_7auwejOfN${u@8{V^z?=mPyQR!jxL2yQABUhxe=% zjJxLD*Wuw3DB({#_pbd%>Gke-C|v`xdUqcKOu_c%&Qv=^j7Ru@`4KhVaH>hUq<#L> zyLR9Go~Zy4b1H`|GXF@ksozGx%`Q%+{Si41;ZvSjQooZJgNYK|Di#t0#i0(VHySAe z1XBBpJY>@Ui2>S+96N_x2fcOpQW>dUi~ z?U>U$G5Cba`HfWkmAJoOcGTT2_ud@ZT3F36gs)Rs+c9i91CgD}$DNO=1v^KP1p35b z5DM8QK8qKae?@p$9(MGceq4$M^CdIH3kBC&+H0efBUQw20iScOx12!2_B!Rev6^wWTcyBff_aOSsoV48~~J zJM^{VRJ;)^2BX5g#7Ro2o(wU?H&#UpW}LyYDe!|s6c7wDtX7?Z&GYILI2mGj{UW{E zUN)x@uaErHRSbUreToV}2aDi4HNqnC4s2iVVeGDr}m=FBESOP$(okf1BFocG6t`6=A6GCc}pqPYpc?Z#{lnNu5^LZ;9__^z*#XtDi z!j>Xq&TFKvkhfb{loe zDt%A7TM*cc(c88x7?L;dL8Rx->1tc$AdQz>^8kX78g*6>6F%~CYhJz-rimC2_?@ah z4;0<=UeD4~&n0-X4ie(Ggpr-Fnvn-^>r-+V&|mQS;NpMg@?tXHWmJbCqrI2X3PY=% z3I-b@d$2vi2C219I3(>TIt>;KH!E@swJIXY>UfOZ#q<^{rMo+pON%bk+%((UXqhq? zMJ5a{TMeP&H?BzPhU9Fd_LFY?r6nF`JwA*9-piFX)!Fefrag}be3y_Y&VaYg5{zB! z`+&$>LkWFNGT32ds1t#40)^oOqkV)3s5|+1lgF>@$Ta94t}a>cJ!H_PLCUd_dJ_?M zxO|6Jy~RxnV#aO*@pY^}t6iF+{aHPJ)Co26KuQAqs!$`F<^cn+MpOlT9)stQmE98> z9XONjv3Gd4iDxALOqNL-g)i6MMNc#GeX{U1O#F#3B&OjP&qO(3wg$Z)cq-XLLQPQb z%)f$qnj*=Ky^ZR>WK6$k>oUed)c`2T3BgX2d95+$Rz)nNMo#(v zIs=gV5&N&|0wzI%%%%K1=p(8u6<>;0cItlKUxq{sAGRIu@-esJ79$!M8oycNLh<D3EMHWhb zt^i?EUOfU4USm*}nH8d3rU?h1!^_AA!7`?6r7?nb#wGf;ePQuzuRn98`jitM7%ODS z#sFaAlF4l!!FHFrX0PlVU?C%UzWsgi@vsV1&j8Y2^zc|{(X4Xc!xqopMFYfCAnO%u z2%iQMNpazF-ViE}s&CIEwvLxgQkd(8=cPyDxwS6})DDHz*2(WQV~r{iBULyq3^OQ& z9aZ3Pp_5wPal@P4r;yIANq~}w5~Ul)By@-^a2Xs`A}y_cM!|2Gi?{0ZQ)XA!tIx1u znhA||T88R^G?T%t5xdG%8ob?z2TacFsO>*U={+V=Q~q6R#Wf(;KVDBMMT2M7_>)mC zu9eQL7J1=}^^$j2r(I~h_G^hce`bCXN8RGY^a zYXkfpVM^!$C{Cy{t(apv5;nzE)(1WEY8Al!KT{sF;bavPW?w)lu#8p8vLavC>mTK0 zzd>r6^+(Y%I9JGUqCHHZJ&Lj4SMjsN2CN~%1LFkR3<%NeR2NQ3U)6NMJxThG#40_< zE%uZ5?)RUaLQ~v3SDB$qLWDZYdy705C_CEIjyUP9U9(8K|LJgI$OpfWtlyRK@m@0E z)H9K{%V6%=igkcyr^V6GjpkQSo6s1eA+OJ64G)lbyueA+eEj=C*fy9u754{!jmyH1 zeJ9uB9GPm{m8aTHhv~?UmyWbatJ>Kj!=jWj6n6w&fl)3g*uT|!Ce7z^y$NDjW5 zlR->*nGO&QR9e`3n_B8wZlzE)e-&(pkSp;-T_Erl^BO0>5!0tyVe)Rm#YAA`dA1Eb zK`;}wi&Kza*uwJw>sc#yDwdQ(fb9k16Pwyo5>*#{UKXE%fSnDWg*q9vGt=-;P;U}5 zD}^ebl~J!;z?e(xnGV$Zy}bz$8{XgwvhC~rtsy86pZ=@72M5141xGFOiIN7*CThZ4 z3f?BOEC&=9fVmxBdmgJNQbcxa27YZd#zEq_i8Ixq%`Ve65JKI~%QMduQ}$ltSFRm+ zPCIzjK^E`_3)b@_#OtbV5H-i0c{3mN87Qt|jEZJQ+0QL*X~pG|G_~am|9L^_mluHi z__XcbJ2KyXzX|RIJ?z*5m1*{UxpmRwsZ&@N2ko24S3=3Dn!~5dF_jAV2ZtX`gbVb< zi1uN!*D=vHb#|0>UJTI~B3anykjbs03w~8l+i8{8{z~)FAEb{2sI^${s*0mlI;59S z-JpZ0S-!aRMTufb_mW9tYW)D4m~|vNB6h$D`ADS(+Q;qD!_ha;@gRH2=ugFBUhq61>ol|3a8)qLLb|-*vN_g?kdZSIlfxiveVJd1c7_O6V>;IEfx#v zx7PchAAvV2RzX)~I-@=d!cWe%7tWJyDe9T1;NJz4+*c>|^AckjCn9%dJmpV=&eTn| zCICs^$7tK37|IVJ1$*LN$97!6GVdkVav?V{g_OqUkA(SGEg7Y^oYI}x5gai4708|t z|G%x#4=H|8WCq8BK3*+!7^01L&?>D+Z+jzC^~iSlLzC0C%5c# zXu7(97+x;BmdIjHllh2l!A#e6qC>u0Y_0*Z&dmje$mXpa)xSH%joG4ts9d|(Yit-0 z!LeE)0NsOYZGCw42tTl{`GH$)y$JmNcLw>l(&aL2`J>{RGCt^SLtlEDh#2JIN$xTS z3*D|BO9L!*E@v2!Ox~)jL#i)>130HQmDUXSxUL&?Ij_1M{>HX=*BMPy4!2=D++INK z^rHjKW;EH#Sa4e>7z!^Mrz$1RU=7afj9J3<^)tVY1*R=EfcvwtihQfRmVYGl&@HqG zQJ!PNZuwsIb)-3(Guv!@629{0^vX&F($ZWOiD$wcmS*j~h`x}`?x_v>BiNEfgN%pj z_OsK8fDJ~oJoF6&Gzh^@%kQcIP}cv$p^Igi6TCvIN2%;NT^;}2m-9rSzuo`PnGqxH zdx>fuPZ$T-JF>ktrx+5A3Kl5wM*l5ja1SIZr-m!u)^Zie`#HYUsp)`f{f=X;ti3(2 zKC8{~T5$IOSa&b-lO9GvfwaFX51_}p?C%j~9S8nz$KLC}f&7v$sR9Bw$9@V@VzE1L z*ocl7$d$O>l?Vn(Q}uYcVY^V&l-j4VE#u_oxEdOd*@l**h>h%Yxv8xJ*8b|Tp=1yl zg?M!@t!`BuVp$nKo{7$*li4)mvu!Q%3V7K>BQGEl+impY`*MmGD&uP~t`rW(s2 zsF?6v5kkA_5fT=WmqP!RmL@p|J4BN#{t{A4PkXEnf%uX;E#Z(2HK-bSeJSw6G5kt{ zLBUO0xZCQ*6fOb{SA;F?7bZGI8pze zMKv98l2L9uXx`;;z^x{=t+!_Z_eTfR?|}_z>K=ANF!L4_+i>0G0D2pC)?hn5flt%R zn@hQGwi3v_y%GboF^CrFmy%`!JMiI4B5m_T`CLgp5>*c0TBQz~6%TL;sQNC>``Rc8 znYPZTRE;GM?khk3l{shEh+Rv85w+4$X9ya~G!}&z?bvAo+y`mbYl~PN)yrG}4-M*} z1qF!bCr%l*OEvbkN|o{AVpbP~T2>LugyThBSPxZM;>AN3Wq;vknoBTQJk(q^l8U9P z*kgG?&U554+<{tsHdMIcC-Aou`lh1OSjlRJ3_0vZ9Wq) zA*m(9FcHMjHg#UBpSUX>*L!7T0aI~X8#tj-uhZZgo-BYQ4HB)lGI}fXx*uqcd>dOI z=|M@%4jZXxakk!8&|E#f7M&RDiM>?;{Necdr%zHDw~)a40fA`K{a$xV@X~rqdXANR z^zOkq9Mc&H!8g3Zz}cFztwMzgWI@L3My4splLo;>;}N+@vz1-PXUfl$7M!5bYh{F4!} zmjgB1;NgOOtW<^$nfc|dbSQ?afD|)3M`l%8D2(9tQrUBI=WcLFwNsDLkaQ_miyCE zpf4p#@nE07vFu*F`U^`DvJ+Sz0RAm#03Ue04F)-#Q}h0XXqg9|uuP;Kye!ag|%;GHB;DUb?z0e|tKmpxV` zA3@q`j1@rM+>^KRNr9go<-*%yYx;oS@TO8yHm$uPlvDsvytpi;D};`hYAy^AR+Bm)J1*Bp2DSZMKqlN-%7N_1T& zwI?I;O3(k^$fcYRB1r+!E+omlVM7JH8>HT~-ixSgK!kVH9||B!;ntF#8LEA;=`)q4;_+b$%aa zRWj>6S1b1a{QOQssRW0O7j_W^D1vFpi<@}|e>d6fC`vK6Bl8}CWNV?&0{Ufy9RpF{ zRl{ijEYeJcv4>;8dVP@kvKOOWcgsp=#* zFRUXb=^%)@F3JfJ%C*1nXSMB|tn|Zo>@l>8iv$%42D(jH>71f*Xi%9qOgO$tm{g&Z z8Vsax{O6fzJ_ej)>ed8oEUU*|AJ!o|&{(;E6uo~Zbbqw*CSJ)<>#9Pja~Z!j@N#P+ zI?ljSqofKjnk5i94OG%8xFeEIBMhjfTl>-YnlMc`V(lP`-*7u++^FSG7f)0NNS?~m zg$TO{qO7!fl|Ph3n_u;EcFU6Wiina9;+aF(+^N1Iml4Ndrq&t_1@|&cPNa4O`=-rH zTXZ^3=U8MIo!@eEXBBVvo_|*F!>qyxfqXjDoG|96OJ(uw1E|g5Ya_p-cL6%GQEo^K zraVvib`W#+JB@fno@v$hHtgn*!jVI_fNP*#Zn{8*LPfSNHp?(|BB^Dbk+V^Rjl~xIviZ2H(#djE5ynNqdgqEtUP|?*Gz6upB>IK07BAb}nXu%_>fAnhw z4(^@vvIpAgA6x}O@;`|vA&?h0Y&F-T%jqJ)x)-P-fUpVVmn4b|5Y;B}J|haLijC9I z;ODPoU{Cy)B%mewAw=Il67E1u+aq%ktWD2baT9ybmcBy`^%yBJ_!uYGMl*SWLNtLY z^ktmbbvJ;tPAB)`;<$Av;K3x(odJui5~Bhe@8EUVvm|u=6rpFSpdC4nyEy`xhzj7n zmv2GCEgjxq04|JjJhvH#wuF5l;0jbw39sdLEE$3)olGNtZ8pK(rbrdOC9iNbexxbF ziErmiDmN2G1>JWo4m+%g4WB~^p z>0s>%*fz@`v=4*VhX-^DdTWB*JLjU^I3T$l5Ia9{F1@%H>ps+m^ zM5P=)R)L+qg@G#sz=)_1mKZb}J04`RC2HCa4Q2UEU*rvap~m3$tkN)wu{HwykwW? zv5-rRID>7>a=VBntkJS#J1vahNiS-ka!I&2C)5HxAB$N>s3*;6wi4q6@#=eKDY%W2 zj(U}j@cr4qt}zrwA_M{3R42z8KL&F$`3VCP9gb|XeO=~asEifJ&j`N>=0@Px#N+M+5&wQN^YQ6S0Lwn57`bkm4aE>}owG4a==vGYo_1^&xLYX^>x3|6Q zh#1yNv+zT`JzyMAI94h{;Qs$e$@p0^oZg`Pb%6i^gjT8_+HPI&%u-~X7SbHK_YQ3gD$-Y&f=GT zj0#ggPv{|Zv6K`&{W&0ps0OR1zp<`eAzrp0v;sq)_4zFh2Dus)tikZ6gm>QjHr6+k zq-I=h(D9w@O+CW9Xny5X;Ru?+=k)^M-H_w)g;>YD$iRc)$rWHy#QO_{-nek{4(^m3 z4t!sRVJ|HL5DTUWJ(PT6e4oo1J6~;D%e)Dz@CFcqlB1%tHeY-7Gtx49SdVn#Fv)iW zr|ESaU_yyY5Cw*o0%E;afmnfincK_w!vIa8=P{e*L~T6Y^=1-nZLT%A(I{Y5rIx9* z$Z|^d)2D&8w9`mM8Dn)BaGG4mdKrgj&1A-301JK~#Go&gg8O!3euUP;Dno17!5aZt z@&jwlT8t$Wc*+9B+kq>o_RjVkWhRI=LszUut$j>0LhpJe;eb)WUk_UfF{K%p#<5qn z!HH*j#Lr;!2G_nu@2OgOVPpo$Sz{<_NB;}N?Fn3c{RSjf?;|nLG6|Flnhi8Q9IOZ6 z+LV>2Gqty(S-qEs;@<5OgVm!wx0>eb)3C5}C}L|16tA(cu@HCBxswFpsqKZ%k>D$! z;n(zUaYwk&0IP;ylKyUe?uJRAAND+t^OP7-Xo=#pd{B{q zy8y5$>mxGOAQRKI?rPFQ@Hw)M@Ou5!IM3R4>lPk~FLGhZS?=3k8ZZRhRsz+lXLKbM z2;)*+P1Lq0#5d^kWF`z_B93G}JGsQYL6lX{sdUZSQ84P-UhshImBEj%=v&Ks;PZK7hfbq~ui$=)H-VTDo-2cvzPUewFf zRa&{us(`YQT|R5OsYOV6i-c1J8&UEyopEDE3a(gg?5(*CI(SpFD>*SL4p-#K)I$2r zxZ^W4bY7?~Uinp*x(1j-!-0T5{_ZN6^S`={WW>@}3ZVTg2`zWQ|M5Ur2m7pEF)r(c z#!;6f1qthIKM8TGWO`iOZ0j5=^-L~()%RYE_^6&$Q%MfVf;i7sZfZ)N@T3VU&Z6M{ zW`;dzBFJQ{+?EPFXNpQWryi>Z<}s-n+LY^lk>tRFEPctF0NOk<1?_fM0odRe_Zena zGL1*YoulJ@FGwHv!H7}t0fHVL`pu2B$Vs9xkhPD27T_+0 zXE)!>+R&%*0QeKbZ<;kUo_?k;tg?bkl6So{=2#v0J?itpCg&3IUJEbS>x$^&-%^3( odcR{d${xdb1`$Kfd>nvE*~AINEvq!gjh%S}sC7)TfqIk2>Tz)%vH$=8 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 GIT binary patch literal 0 HcmV?d00001 literal 192000 zcmdR!19m8i0t0K?wr$(CZQHhO^VYU)+qP}D|83)E6PYuK0KorukoTz#lpOO7e5;oV zBFN=UHLd68GYML;S~d;4w*3_(nPnc3kW+NkPpW-EbwQ~8fTaF4-p4~Fl0kry(~cl0 zjvjk0e+qB|H7i1!cpWXcLstWnm4kNOEeEKL4-odWgMkef(3P=FGgU9vQx8UGPVrIr zg_arDk+~#Qsncav@w3B{>s;d&R#t%P-|Kt!!kny-JNeon#!SqNZql)0)%;{v#`G+e z*$QP@DjF=%Bymklb65Y1JV;gvgJ`D!gp%9+7`X9w%2$FDcZNceUjs9$0O>?WBZ4c6eJGjKdlLgqS z4SbM>elo=Nm{6*mY$q>JhPM?}`ZV1k<7hHe;g4`+D`ryO7_|{ZO9$ZhLLP#65u(E? zD9MR5uipKMwqu)q0`Mg5={xNq!V|BII*+}+aFc%O z$;?e%!;{I#gyaBn?HWJXzVsd5@dH)(qZ$rKP)@rkQ7|%vk0r%PyOIENPWBnySS^;S zRGT#0MxsO=Cn*T^qdP_^+MXh=wZu9Rru0BYEf~{%=$EziQYc{f4zq_`K?8z&Cnl+@ zg?QxbWXk3=|CLz7D6;w0H!3@(gMJveaTHW2H0$fJp0noG=y2`0xl~)>CoVXbgeKhd zR87k>1cdRz>c+AMWJ|-v<0fb*W3n3K_QMF;K9raLa)Q=^-lPh8g!5uZ&x%kka2J(p z<&K>_(?>8OY&43nZr{g->H=Z5*bI7w$ecz&I^q)~z|GeK6HY&BI zV}*RCRsLh<`_BH&0$}i2e2oTh0~4{$DAR9;CScwrekWh!mB^0Qd^_0NE-hWTxB_Gl;f9!cAv39w3$q z+ri+jdq8r?`EW=ZxhO1ixXtw)6)aC#1wky?HD~y{K6R{k#5Dzq>3={V_Si)dHJZYI z&TYL1`CgE zT}?sMEcVi}%N@yweNrhIhS_rdvRp<_?HY*HA5!*?!su+!IYMt$g?hV;)_j-AvEMTs zrZYG^|C8e9V@djh0{q;3W|(Z7@T0H#kr0j?1zwu2S|cTPyn{pYYm3N^httoDhy|K@ z)Kw7+uN>Q~hcnWgF?u}XqU|b zh+c#xKmDce7DcG8=;L1eUU|QJ{%Eja2Xuh06|OR$29U&kxlaX{_08mM`tPUf8y3j< zwU6kle^wGcP7RvKa!-Sp3yBlUI7rUIR^#H3 z2A)cP1hW1en}U`F@hWy`3VYvJwxI*VcC^3|bq#*Gb`CsS)az0#59sv=n@U?@gj#Cl zZQJBCHW25w=m8M*i7q=L)?@ALyL+Z_^tC$exs?lhWZb6%0YqD^Y+nEkdZ|f-P!dgw z`LRJ6PQ+63t=E&vOeXU54pOfvmVPM#3#?!Si;^vS`2>?G zv8VvF%*HZLykLL8GnQ?t24Y-qRj!alm-D&80T2q6M(3fcnv|{al=Ui^O{w)AcxhEk zk#{cizva8H>7U2}OOt$GxG27Qun<$v8nEx`rduT@6`or=>@N1Ijru-tNZsVTB#i&y|*zfZ<6@*GvkY-CE zza|YS3d2N{d>tMw7k%a+kDXLzpG9U{9ywR0jkt!$PZbW5R6ZXZbYLOcuHynL8Jqk) z))RS`<|Rn;-d|c9?fMx0GpQaUCUG2e**jN9Yymm$J&w-yuj-fLa&W93nbfd=4J# zuEVAig8LigN@KAJP1x232zTc_is;RBEm`<`)S7UuUcTj1XY`T~at;a} z{0~$fJT(}a2L<)l@oynxz=m!P%t*{mYs(W@B)RWT$M2_>5Zpa8w z0tG;zPV~fl zMUhooLC|ke=@8}$S7?@DH*rESg^OHAUGI&z=AyX1>ms6zc+ulks?pH>5SaPuj;Y_A zZK#9@=VlM3=OZlfb^y9P$-Cy*zVLkovSujVJLE-ER1WvM)lCM`6-s1eA%O+GK2VhL zmOrMXiU&lPq|}v@4S;U(qo&A^qHvO9OI=EBD*lAANV_I!SY`K`K-zIIEfAu;iZ!qf zVd{PLn{n4BGwz-vun8?$T%-R$bZS5iS5@k=LUs^zE>$2GYaYW|43Ux=XI=5_L-WQW z=ujZ|sxt)ZSwB{8lA{9EbG!F_uW5jQ+Fl!#$bxY;Mm)}w=K;tSIZ2x_Uq=ExLOs|s zQz@Z3#N!~Y7cz78us}xwMHWBq?c2wGP{W??tkSvo)*x)f@l)gZUp)iV6&r%Tj1kTq zJDs|Ae>6wpQZJ2mAqZCLehtvok1(n#wP46md(fY3i&Ie69E>1WC>ype{-qnDLGQn67tMO1a>0xWLXLW~P}_FD+qA+@dM$a}7-y^}xZNOx zg^qZEFWL#*@ajmj8Z_c5=C*|EN}u(Xf2!~^CU zMNm_k?qUF3514m33IaUgxgpH(&m&AyW^>8_Hk4=mAl55hP)5Eo+qRr85zSrAv434}CI&FpTnOew#U7a4V?_n#^ad2g%&F$k`Yufu}Q*7qte z8cBItc>!}>Yi@|~V5~X~D_+afndjEN2TiuE??iYcn4(%C3ryw;nZmt=U2Sh79S9ZC zLn4De{_ZKg4q0E3M+1NtaIIs1{2n<%fh5HVp9s#=WFLzYouj6-oBfLvYh4!U0|``( zKyu3~BBIy*PQxkU^Vq*Mx{WU7U%0-Q=3~_AtFTqJ6hVwzQXrQe)-%4Wl#bm)%;tUy z!D#7l2~EHG7PZYDIybp?3Kp^pfnUrom-CIBU;%yql6g5{Q)-$R3DA7UymV~JhL zlo@TfGBx6s%7@}-f^+f+kt0JDQ%2srhmKdSbGM<3fmqQ+lPXjoH$;p$Od$qw-^NKY z1cHbMQ6!>Yy!!~CZEp{$$^p^o)EoNDn!!dqc#HzP>Zf?mPkTpEWKkYbehClloQ&!b zRCr=(2L0?x(sq1)-hovbE2qD{Nb=nEk`&H?e;4C2_8A3WCLq_fR7nwzvhrRaPa zCb}`^$4A#su*#fR)e#d9@bEmj@<3(U!jPpXBD+gVe0PqzH*YNm6z{QQ@+Hi#@d<@; z6$RVrtg#ue$up|o%&Nz<{ktGi{{EuN#)E z`E5*5dtm5#b(t+7vtDRC+a>-eqZCME@)jkh5X32onodb~|AdJ5kDeOcn+^bNXNXz$ zfK`_bWw_AuU_7B~oG6bDu~0fdEa%AM@lKbYM1Vk<|WU! z98S3v*|Io7(+O)O@6_Y;J4k2bZ)tN)C(p=qX2P(-EfSub!$9pAZyg7JVI#@y+tOU~ zeolf~#EgOsuK9=W!?|k@R-&0tq>fWX5sOe-@{=&5FW;)7f%38krVW7L(#22tD!D_3 z6sY@Dn8gI|uCl``8Ygk~g)OO^9uFRTCdrrI0QLzBq2~j96=-6yKx4Ym<|cdt-cK65 zocO$@+bpN1tFS&@nYI4*ehx~Z2^aJXc^Pw|d_R(l3IQ0pZO4S!nm<|eZ~QwKIuCl_ zOmB3AjN|mOSVI7`g##%^QuNnIIhF$K?_RB@n&hdg{J>9Wosg*R*J=@o*TO?sqAXqY zA?4?&X;~skfC<)apALWQgeng2!OxY!G=j!{8fDXP)BiVB|6D4U>Z4O#jmC0|A;OfB zu@6ZaRvBZPFOuKIDVKall39A&s_9u7qCdjv?;BykQ^CZ zTta6yONS}gD@{5EEb`A`N*riZ37&|cDixE~xi%GIq$A_6zE?mAk}SmL=m97QoKtGM zkAW0w5Gx+Hm4Y>(TaObplR=eEZ;SMlP{*uQ6e#Ux9JZT_Y6eNS3Jnsb6mP*s1}~uc z_l@oL-xjP3=>{T93!jY?RndD%-svdx_W7O$DIkK`vh-cZVj5&+77vxJ;ynOjS6^L_c#FgoBedZY}@Y?7pES!zQ>qo?A#aFj}@fOHa; z(5L5a0T04qE^xvgJW?=O!$x`xx?fH<-j^e9tBn^gEA}l@aJI$l{Vr^U&XUD^p4_X`! zJv0^8+J|}`UJ@-_6C_mC?DAp9ak29m^<%>{%vlxkt}-L|9ueqG9(4sRzE29{J}Xt zSr}9oICX3S z;yF&fHgRXzPb+6mcvSJ_?y-KOgw?O6?B59Ysjy}g@rh7GN|C+R&@8yw@urt= zmX|E1FSYm%ku97DQANEeLd>@b&(hOMt>z8Q@yr4L1{riq+cbjdY0bd_PUTg(X^%*xIHOgay=`3wKdXGT2M|nU5`T~K ze*D{$m*JmNcA1a+0$v=C{t2Q`;@IJgAV!$fN}Uil3i;!*>aJxNBpE;W?~sD4&Lb=i z6B7@Z^f>_Pt5LYW`=jwEdu*iB!hN7+BKoQ|3pY9_EF`mcyqZD*M`#lwSaB9ZHR+|}t9 zAtjDUT)I${N3s8w>6aY|lmcLUVplKZH(tOl#K58|$1+!;QwG-*)h+*am@ZS75`h`6 z#dkr?WdT&w_kZ!>H#}B3(?*^a^Aja+)J9vX{k2N)sr z(}0WoABTC3Ud@0MY-_Y*aclcJ$I7<&6{er}{>Xi=5OjdQKx!qo zq(g8(8i9^Sm!`NEo?B}T<~2Qv^>^15Ha71+NEU0EUUMRB8(C9l7jrSXj^-+z3~|CO z3)?)hb&`oE`tE4R{~1d|Wr6DD`Wc>pA+s=7e{(k?9cpm7T--yP__C^Z0E;Lby;HWWR=vK(~Dgjyau7O-GA11L0S?t8a$Z@huCJ1ofWQ>?EO4vaRbPhX8MMw3)+ z2wps}QFNKs7RN9b;**REonvn0SZ6rdV;e(~Y$M=Z(G2BWPKE?od!|YV&9c_LYMq?I zaa#KhLVvrP!=z{QMPlH?0~O?3OW+``|DjUr=*>#S30b0Ytijq2Yo3rUr=WqDh^7OS zw@JEA5W1fa=LdcPos1I3YFyyswiG0po@3 zHLQi^z#J&(n6oUi&YrO1&QU*3>7{C-CWxDr(5g38m!1z#SUo8R z?T@mBKbN_a08+yftqm{pbSZKqpYYjyq>jPK>z9qRK9~nb6MB#?EpBeM+`F6HSuTk^ zZl@127QMn8hKyLYcd5>aW_Pz zLPanA`@Q>f7&}MrnM>I#Kh#t$Xs)*Z{z-9PBZdSL<@M+s>YlglYF0-%{xK-Uh%QG| zM6WmL$@phqqm(AH!0l~z}3*sEybDHL2eL9Um*gMNdQOaIT{ob(3sI;tta zY{uSe112%E8O&v4Wjoy+`IoJsX@4%pM>-T!!)S0RrWG5t?_k-w$Ay=LVHmFbt;lJw zm50=&ocA9`P<&sEUx(ar@)R@N$(=$R-yOHh-UI;#T7xz5+iVab9mRs|4xIj|Mu5&N z4Z!s!XbdpJ)M9u9saSBSR>-+W<1oF&5pEeAx<+h#9qa6Q>pXg)y)=gT3qQsyOX;Jr zKVQ!0Cl~FjZvezv1jC1gon77bS#u;9@zTE6z6wwI($cKD3T=?c0^~!`=_lV453Hf@ z+uz3wjJi<(4V5BflUOIE5wjwEXP&Pu#_7AtTa~8xIc%|3<170eTvOVYLE)9awFei^Kg_}Q+C;-Zcp|9D4 zvp-@`SB*427dVCE%E@I^DzRsEj+OehJf}D0$-r(QiGsXa8t{6>C}B~F6mTDPsoRz(%e|IZ+ic?E5IkY^pX{F;e=bX zc&0xMU`^j*mS*@e_weM)>X@PP`!#*;7mY~LxZX10+@UTYerI1FgI8)fvkc)t|AQNF z#j-Yqd79jp+i=%7|FhK}LuvheKXM*3Ey+V_*!|ATD%K1vYEOpmz5j+Bisj5M+ znz5lGu02g~p#VFx+1qu^`tAKX>Oy|+=v?;V)g|ub=B+&qV*8L{s|9Kf8;_@pF0)c3`<{V=jNH-VQfY_!Y^9(t)Ojx;t;SGZ$*c88xS7LP<@)v)=@6m{^{Q0fKO0FF&v&wfPXK8Vm7AG=#V!{J{85nugf?5tc98nOBdTJ zQgdvpD7mGMrV{z*^C}%26~`myAtZM~lz(h+Ba@VfP~1%o`#1exE<%e+oz7l~9}$XO zKZ#rQtT#OC#eIS#HUutTDZ85P@^y^JbRKRdHMX7I2VLQR%~OyN2AXpLcB0iOVK^v8 zL^AQ_iq7t}@4P%=OCOj1H=g&f#X%weURMvLUmqm=gkfpJ_30LSeM<4k6ugoV{@Ynk zBtKMII$;XCi@I>G|dY%>HdVEjaZ)^n}|Vi>NBf{ z(y}HQ;r*X6v1x6a`RfKJH0k~Hoih-@({*{1+Jz(WoMgN6L0fK5iW(cfJ?M4=C7&P| z+C@YVlg0`$pe96SC3@}}3Jxl?vL+2p#@Wd)QDR6cwBgNCur>1ea!6K3t94#pcJabM zd|MA_r*(kF_e77S=ryjwnhTNE+`O|*%R4+qR(z6F3Z#vGs7%30jj4))^;mb%;2js= z$0gM^h*WYea(W4E%>E{6I{NiRjM>WgQ>HcmW|k%v+zHpou5p{&P|2fVd0#I9*Yw+m zYq~V`JqX?L0A$T`&r3SI@FN`YgQf@|Q-dU{hHj5#czRrakqp*C%jO_z z%~06xbP(AE;jwG3-htjGsgia|cddlS@A(A?Pj>Cq)oGDAP< z^1d+v^s6$CpAVPOQa!MtkS&{G=zz9Gn5d`lm!h+44UX(Tu?&cL1|E8zP@%j;)`G9s zMX$bU;Scm@Er#+z#R!|TbjgHcNNfyg+=9eL`+rf@*GOW+|NhXMpvxKgd9Rf~22~Q+ z{|boYy2|N;Rrh1cz2Q25)Ip>yj#h&AIN3~5&67U%P}2~4V`cGMEocNHS?;OW4SRb> z+?pyO0dB?-TX*5mF=r+zrA~>9k9W(hYbIeC>T>r zxX1Rt%J^&SUnvM-G)blLF7mW!OZm8lBXk1!#Zm~TV0IpZ_Hx&7g(1;SOl4s zuL`L5J!YNn;Zrxd$CgblPJc8kbXtJp*}+H>p?_)+uPHl9Fc%^Eah<~gd{vMA3@r@w zTWk;1z-QY=Mwo(VVTA>ZEeIU(ou2MtautmJq|4_#R1z5OL8r;X4+-Mtk)WzOXC+c% zM4sKe7b9WZ3EDm>Rm;66B@kkNa{4Fce30+b13$3_w!vfob`qFFz5?niMD=b5h53_! z3}l2tY2{jAc$vtSGmFHby8%4^P(8ZgL>5bPYDBnW5{~p`d3W52TC*|noDBt}f~rN& zCd+z-Ukk=Yf9J-eR#IJkX4b@2!c(AGLwRJ!`#8VI*IA zVkx7dDN^)8Ntjc$vuBi*iq#e&PltT1(N2pxJmZS6(mq*T{W}8T7Tw~M=$G5q*n`-_ zF48O`)OQ4}h`K%rL)oZ6H=$!{q<9%Xuyre^+yA*Ew&{~}ydloQ z5h!Xo<(Yf~I*yTMU|y<7uqBs--krEu;)PNK280vwjZ@O?-%m77nG`Y1)A-Kbb`t|0h=8Uxs0trrD z^(tib>+$Ee%e+6^!Q(@fQk9{6p6=fvBcJ@ei#H$f1}m!idR3+nd7u zklU&~f*;P>0RM&m324qwRoEL{Yy12kVp&P#o+Yc^GZIF==t*M+xCh`rVlO`*BHSQm z#7mbdp~bD+d83dG_YKUF0YcwJkc*FuVutwpM1pUj_gE`XiiY77?5qzw<})6 zeT!F=#eF^U!+%8tR$ctsA$YsKotGbjh}U%@XciT=VQpIefSrgss2BJ1Ok#4JF9h!P zJjKkfrs+Q3=6FajP)+Q42QEQ%3iT73E1I7*=WkaKMI=`bZCsTI-E5%PO+!5^$OI{7 z;lz#w#@X7ek)9g^QQL7ij=COvUK2D)d^qf;r)oD)rXB?SNrVy7o)Z(!#?zURXHC$SBu1A%^;)FH``E6*&-R6+ns)k^NrU1`KKbp!wWs34uEiD?Eho*}0Ac8YEc|6BuFL z>gRCO)=j3lE~`6G1^Y65d8*cD%8-I(!S20gjh)_=plqdU&ICkQWuBB(+dm;+1nl&v zE@cM2{$8BSlNi!hd8871d@M_)Ai|K`+Y+9-Ycu;2192_hfZ>w*w+qRQ%w;M*<~BYC zT#i@Q?*_c|Npn*43)Ff~i&bJyEF;y37#wVWs#k7uKORxX z|EyJOLW9kY^mr#xFxA8sQI~Mn)?C{xP_B?R^&3eO}9EKuwXOv-?o;b#J9bKE=}z^T`qd71>o zQHlaDJ!nUef_-*n;R6pitQG{5enNH@q2=QZ1`SyV{4SUY|8t4WkU2D097kBnMJsLo^AEFKq*bAErTsbB=h~+S*K?Z)F{KkTe zNie1N{qoOi_^R#}{@wk~GEN2D>E2$O*#ceF4|_4@n+$*7On+GiLWvta8NGG1#;4r2 z5oh{!?W=HPGs~=(1Cv<7e$-NAAz+#zlua?yp7pscS!c(kBc^~8#UJ+II(+)y7!(&u zLr7P#X_uKeq4@F^Z|zWcnuEHd*R{LEVu{1D;IJErL+vBs@S!Pv3nrxr$gyQ2aB?Hs zxpp~|=A)2zyu?}03JcvL&mWS(Aj6#=%x=>c!^ccEgx3xv^}Cb;{9$ywQUYjT;|`oh zHk`sue-sHC1BXMZO=*)<59P#O*ysiH`>bT4B+++`|YL8g5XbC&fhX#`Lbo@iOgb?G>TYn zVcV_CAk$~8Fb-E!;LLoBJxDPSgrGVC^|LAn*pLb-_K%t;lhNf^OO#MQ1ojuG>BfQw zqEl>jC+w&u8uOUux(15NXDdW(tQR*m(ALdpPlJ?w*MmguKx~GK4mj~FGyY=w0QiCR z(lMip-z4l$ys^oGHD{x$fVfxlz_gdvE%@v5E&}n%KD%yKtTh!RJ3-Xk0HVkHg}FzM z_FW~6P4=VK*Zu|Gla~ipbr?Y^r4s|+fGsGf``{F%(-bV9+3ZdA1KMq>a{~?pYFb!z z49CdJSa*I?$F8MYKJT$;S|ALo!Zs?X0p$@tcprqaOJdju!aGr8o35!X0B!>f+&&(o zbo}E+Nq-sxuWWRflNHKRY;W|*^=~T$i=M*ooryhFf-$2-owiCd#;*V zD_JC@f#GZM6~4t5Lg$_Y7Gknl z7cSMMhRnX)mU7AYIzUs$?0g0gRay2?n_E-$otr{<>TN73x6Q8s0nyGHQ00{lv}9u$ zf+Qjb8*}_^d#qEzeAd-q=7X`_G47oGD3ZeYP&U@K*JKXsgY0(W$m6xmY~?jod=#gx zLrAF~E`j*5K;wrO+4iTifb8$kBKHK8?vMYW)Pd|{56SY$j^mWa+SYl~zY)l=;QQ}& zId|-PwG8m^2#OS9=6IJdEOy{6cmq*WE;1Kc8a5m4xOwcz&m&M_z)w(gag!(R#%WzO z)BT?BZ*j)H5?FGkJPro(Cjc4NU?_@Uv+$ZWw|vGh%)F6a%(*&3@&gU4Bbw zja~CH6CXWGK+S+-;M%5Zalu@a6G){cFU-x;%Cv+Gp<_Ib%|5r!e``lGxOl%cv1kb4 z{Ysa50NsPR=Mx88XmTo*A9;RUb9@TR!k5mc~Vw~&n5~2C-I?-bB19W4UMA@lI@P(5Gq=qaplhY!#AKqDBPo96nxwZ?$ zNG)y5{SraU9++kp)b?F_4ub%eoicf=(N!Pz*U!JWc~I1(dt4t=foz1$d%T>rqmB+z4aBiT=lj}d*z)kAC<*ZCjfgo=1a{AoZsc_TRjiAw zA5yY7XqU=|Bxy6SG3)7d!SU4jk!f$=x6l?keL;Y9MJ2{y`}m18Gzk?7gsAee5(Oa2 z!mV}TQ97Yg;BEiv>}O^73p`?c(cH$|cu0&Vuz#GA_dN-X`gHty3ws{46eDe=d&BX| zQtY=Qd%QmhU8KEb$U>;`h*IAYQ!q2DM)K%lr_y1F_n{#b%t76r3|gaW1&0%3l#jBq zS}qI2N%4c1GfMaY59~C@%kg`&N&NG1|ArOGS@ssF0v0te7unJ&2?l^0WirM_ei!z< z04GHoq`%c|wc(Z)q{~Gy2^qnTuGVjZLQoP7OoZ*70Y2ceWEIL_7_K#t>)rjtC}b{^ zrCHF&HD?T=*Y*jO#Ic z(dOMd!hx-$#~>1zQA3LUU3q6E7mbn!f8j|FvTx|0$l_40who^^z_VQw%P?mD3g^0! zn&xuOy%C>t#`G)=?0%g*J9PC!s+%=I+Rr1RzZT?E+g0@(Rto5@59a`==|y1+rf|ee zUMSx)zK02rizT0x7F<~iOy3fZS*vCb;4Cdmza+}(K5wJdY?rU%FuFW8yHEcuKD}rk z(vL20JbAU;AJjw7mm>P$aU7w>iaP_w-o^Q5%5) z`0zn#7Z;Pz@Z{BuG83(ig#k!Dj<4dZ%qm*dv|kmG0Ek28_^iN)3Wia5S@7@H=MQRb z<@ZLWTcGVgz|R(l4)@g0O6YYhucoO$PotVv7f!Kxy@b16V&#tEYJl;Bshs;HAw(e) z#j>?6lHhNi*s-L$vsCkr;&;0lt~&^Wk5-Zz z;8!3rQAe1a26cNO&{YK^k+JsZQOM;96a!6c^i!B?S;%j~B4h!Dgp}lzls`hFv{g(ckKAtytjR=68FF5dIqnTl; zKwCNjwr(ug9<4r6A;)s@Vlb@*VF0tgd%z_Aw*dffjKD6&5{q{PN|;Yl0BjN=+$_8k3rbOSX&68u>h+oPabPcV3-Aaqg>W<8Dg66w3VJ-eNBU-YGq%F^s#Ou$`P_}P?H$XkifgF3IwNKrpW$7 zdBgd~^8mSqwU=}`>mooD)>Y*OK!pr|?>Y(KG>sdzd3fV^Y&6v*E#9hHtP=w@`NR>s6e0qiII zaRa;YA&cu{8Y}X+?}YSvVO6V(F~o8ywgwfOK42q{_RLDyJLd`ROe;xntZ(WSyV23r z3sn0qu5KFJc(Kh@xP(? zk)2X$1SPo@dPeh>GWwwO$^mBD=y0eo`tpC=N8*BE^0$m^>ADdZRUYxsQB&3z_j=^7 zl_96ZOIKm?(VGr+v0!rZq6zH!vft%>AQ*Hy}_okCErGb0`Zg097k;a9)Fjj!19P~0mk+y!q zD&*2BObsqLTbmo*Vee4K z;|O?P-x9&f*pP#9j{y_t-OgM;LV#koC7e8X2=+Op=LRY;BBso;*BV?*!S@#^Yg4?NDefy4JUI~7>?0-a z2%?~<0OefiPH6yJH~eBS3}IJsHn^mqj3&M3n{Nk*cV()>j}QC8j=f#LpQ8By_h7_- z^tjs3ySi(b2FbUz|NhEj;FK=~j8I!5rBegbA&2%OGK3EM`sX zY99)V9_Ry`zqIw_ky-Y&3fvqRE?*AFLLr@jG3-~Tb$xGu+`fI&md1p~|3{f!+m zxHDah#ZBGTpwJF%y{jkXdZ>q*pjVYIbZiTjll$F+P_O0T13TL=>WPw5OJ(*JTl0tE zY!}vS7ZYl8DatU0S4Z07SFWJEsaJX+1Z*VrEpNt80u=hX^zUNK_Ayaapq~^G33#A-u;#HESFB&lcMbxTTj*_K_`X z&~^+*2m(|axZR@wdhxIq4E#sQx9x`G%k@J8So^6Zd`LD40|TkdF*>u_ar!A{lS@MH zS!J-Ko8TXvkO9YIH4ag`2)Z)PfZmQSQRm z<#uUeIp6zh1maE*q2*z1mWk*-L5Ie>2;kWhbSzICSa9_VMSVJzG>lCF+*UZ;D+jf-QQ&6Ze$L6n+OjPQ0r{d8PS&}^RRbt>n{%u&E}pSf=A zJ4;(Hsj2nHk%Xhl5POYQn=;dL#;vdJcoPb;d3K0BA*%)MyX86YDOabj9+D-SVx@5q z@ApJ)O|@VpytSvY%gP&G^+dWUzA-pkaIa05p_{1k+=y588Y1RSBD8xZ*V68< zIrtq&lY&Gvs46ml;~p%dtH|BM-C5L&k<7X_%2S&1?ictf^^$h-W|iwdS3pOb_&$r2 zY_e~(*k7rPqHy_jJ9OLMff?`#CV1w{R?vZap;|IdtQ!*lfnp(s!^)frb^xN2 zeXq$eYpV9EXMaoxPu0{tBX^m_1PXbCGAPipd%@yB0&W3by@`pK zd;lP!0)G>9jgP?C!8?6r=Ht@3Mpddt?U-mLO1gDu*|U`|f(j0i>wVwY*O%PAU_~Xp zpQ&eO(UEOHqmtK{-$C07u|ociZKR8@m^+S}eZn9`NjK9eC?X*1?(vA0&8syX=#KIU zONt*aBCNz?a-5frRl^*2^^J7I{sBga^D)L6A$}*r&Ai)=B*zt9_s+7^!=kz6onuT=KJ3Q$cgwuNK37}S-;ncyh zI%C|#ZZ$NnG)-6bM?Bm#B!Sb@L|9fR(ECDg1~;6K;b|nyFxT=#3z5N>V{`YCzPBj4 z(EZgYn$WiLJRQ`)I3#OS|3R)R~Q5N3SO36|xaQ#tp zpf4Jeqs*12y_ot-Lw1e7yuE-3qp|%}nR!@01qdCkAGY3ke^M%JasCioBA~4@_J_vM3{M88Xv&}B-&+Xv`AYP|6l7;2-uoI0umYe`e z+?0*-Awrt#zyF5V&}mT$Veyy(3JuV|dG6?^dv@~%&iL=W)?2Pu6Vvj05MRslf?{up zlP_TCdeD^iyH`JKy+hEk<_0Cy%jyU(qFogP3owCtzOu5JG*gr4h{4U2PzT(+F$6=H ziG}Yh4V?@6Yw**^vFD7oQ)C9}7D$j3p)H~V>bDtGKnGumfK5r?n^?xs1^R@o_{+#- z%X-IhHPQktm!u31l!HNv4}6>mdA@SA68Vue>&4_DgdE~@ilgK_2Y5#tDCR!ZD_CgWjb7=RD)n zp6sloJr{M*oG`Nsc@r@(>zyJk*Bk2qQX<6(FyDJF5BruTq}~0m9rspG%8lTO!S>|e zo*==3iWK?;{5%cI;suOC#mIg1U>o&9Q5*s73KrjxzJ02S=h+WVXykq)&BJg2xZtpIag z)o17pu8hQ!vJ=x;+ZlNW;y-oVv7eLku03@-Z}EeX^BaYjenq_$EQp27mf`%+^C^)+ z?|j}OmZbik!}c^^D4|q7;!;Ee)NBNTV4v4Qqf+`U8hj@5<%l?Z>cgKU z<5#Fp_lwTGsEv^S4C%=Dn^;^5l-gdzVR;yHu$X578D`As4sKrygB2zpy)s=FLf287 z>5YuwwXHnfEmFy^b*g?#0vF(9Bg(TfxQ2tKrod)*70CQ5r={>Ld>7^Qoc@eeBm8^BzUh?feOl8}OTo>f6c^ zW0anAKK=+_p&M`_X}jhw04#vX%EawcZ_`cyAtE~&r)H4!(G9!}t*X+6Y2tzpCtl1g z=ZUMN_Spr@!6{&IuFIUgreddvvd&*mpDE}T3IUO(1OXo&zMIT(OR^FTt~?%37g7BN zv>+&E3BcCf5=cLf(1^I^fPqAwQI0$UJgzH*CcY9PpOzg0Hs3xEKt$A{j~vSoSO9*= zJu&Gh;SW1(7JZQVrlA9bVlKs;#)~WNL=FXY@R@<1Mm~(B>8$i7#tlBZdZ#$ zv@uY2m$Y^lA7)9PF~K6rV?zQ*c{)D}{y@VKXJ&sz(NIkW@@L>$Qq+4@L`Al{2wG&y zdu)PEnp){Xuc4Tv_U&&05NKW#z6!`P*_|9)DvOc#8gQDDXI}3Es$}w8Y@(Q+FzuhK z*F0^ipUucw5ACcsA75@AVy z{XKZx)vx)ZHcT32n1{ ztQ~X^?9YsWJBKl_b`z!}jZ1qht&e;qN>)aWYgcj4`lCANWFPWzO9L|KX-MAWTM<|c zlYdQ4_c0A0)BT0gb+33&8`o0y=7idOH9szZ18sKx71rwrVp-HMN;!(ty>>wi!slB; z>Fl0(6?Cl6o)z9D34m4WDk`AKiuX@!%DRRYmPQ}`**2)Ee(lXG5MKQWZ#K9-Dcj_C zgfjdLf0Ai(d)@z^u7)V{^Qa_KQORnwbr7Jil1ejRpA=(laX(QBFgzC%S_v~fkA)56 zk$5JncZz0I+rI%I0=p4Hf`^zM2wB*C>4MU?6_%28RHEPtd$DA=^oILp6_1&WmW^Y? zMszf4q@MA`uiPqDohf)P`S(XRKUTD1+R|o?fDmCAHe_0~w0qP39+TXyWdtLl{eZWTMJsAIKExMZ>`ewY)G zj%GU-SZED4?)PVsb>`t9T1)vU9e*wkv*xQ{H)VYbgA3?juC0@kX}mnBA7js9?=PvETTjckZD`UzeUi@EcleqaQX1``G|X|T zf&L+)44z2TxOvYI#%{e?fVU}Tuz>ApRy;i4pNXQ>r=LJBM%(&UuLuJ0gJ0V6ElvvE zdotfBpJV(7)oM0m7;+_mBB3vgygMWmv7`2{w{2wU2{?y+O#+NO5Rq>ioPcATKHIW2 z0EKr2TmCk2vSZV~^f~X2`1=li;L+sv9`gIMn15n0WIHaK#wvB(X1K?!wQmqIG z7&|*xA6pn~*B`AS#bLQUh~U$yUrRcC1|-0W%S7D%to-j{#=5Le{$6kR8ntW`gHlTH z28UBVbr=NRy?_o_=MhRM8XRAetyb?wJEPOb!|>c&A+^P=`JOz5u$b}zsPyHL%2Nk> zIFR5}pfyKIX(&qGbA`~}VoMM`_mBx#)�uc*gWwz@d=S2~bA~LrFNXzUL(>hGG#V zY3-}D`Hm^5oO>(>D+j6>2!OxbF*N7Vm46J+nX-n3Yt6?7FHFT#4(mWisGICV!AtkT zX5ud%fx9AgD!9rjz40u~m)5r$an@HpB$DedYwd3W2PwQYOmHc%1<=&QPk0T~&kqml zulp*RCKK-F?G;F*H|^nSl)B0=!G3gnHLG70Mp6_GVxp@?pD`<{=pDqwuCh638|0N* zEyrimS+P}lk4B|>K=0oLgvOA-YA#m}N6s8tS;XU(?VK=mY982GDv^GozI{d8P?C8b zNCwx4%h4lN*rXf_nd&JHZ86#bP6IjbdWlNV5Fm0RUPEacy#IglekatpWYNy$H>Io? zoH5hW@C*liD+`chJ2KZ38&C*f*Eb1Dd*wH6NZC#b09LgJ)rY2^0<{Y8WajFlqu4hA zPDV-zh*6Tj=z*dSR=1`cA9|K~0N1>XZS7k>C8y6V`zJQfMIA!E0v&o4I-SU`5%a<8 zj-&*cw~AQ}gTsbGSaci4V8O?5uluqGL4Zd&~m~5xY@qMoYPT||7Q4kvBgh(tae6~s-nRH|GYK>1WRfO zTTKP$Rb%oe&_8Umwt$u|Ke-I$k%_T5xDq^wk#ggC>L8;^P#IqXFw2Z%ZC!1Q#oRxD zUm(m#(I)Immn{8Q15kwlR5sUVXt{u0df3^9N5Lq%&}exOh8%%x0qvsp)>J&-sB_U( zhk0KNv*WKdp01x+s5MRhgBfNn_U(^0nf5kKbj7$1V-3%!2$Da+L5mZ6E?~mjfz=iL zZEs`Y{8S=r-uNRZAvsvD^0+nIrj z(Vp}9;eb8Q65QPnxn`{KuZ9{4`3qNqOYHGUcWAxd8N#}d)1~pIZu5P2CI1Ypbbl&= zev^Ac=@AKJDOla1zHiwMjX}#*870CzT6`@EI=VAczNfj-(JjU0N%Fzx=_$3A=PstO zm_0>y7@Q+`yOv-GW&9YZWl8$Y!Frj0Qljevg6%y_9^)ifs(86TU`Z0;@VkHkQww%- zJ*2^DaFGH94@ur^hxlec&_7j^z_uR@wuqzWfFBKzmcl7dM^K12Ums5znQaE5RFJ0` zDR%!4>n0Dy;Z6RoG$P4-%?A9$=zovBX}NFp4ph=Iwo{RP5Nq0GX#t+U*oD-k1iO#| zedX9n(qNJdUtia0gu4?8wdjbBN)`YHmOJ?HOKAD>OYYvV#yQ|V4Rrxl&cmAu@Fo!= zunr5&`6|5ue!GYW9$y2b?lc;EkAtLl^y*kKAl!yn8pwnVV*WN(qzkbN96wT3o5nu- z5fzhNVj=i1RVc;;)D|%JyxomePl+=e+Myr3bIIdqDZHQZ+F!U7n`xCMPnpiS-a{x@ z#4JCQ@||p*Q*`RdV^+iNEht`YJg@xvtd%5-%3ap*YWrvtk07j8B)Y)Qma&Hp%k*71 zNuP2&#`@+exmP+DJv=(a~PvEcGeyx;aI*)hAkmgY~SIlToADXv1c4gh)xNj3N%l%N6?L7VCQ$`=%~ zhN~#+kttPT=0rviGiavhjniZT|L2VX9t-B^*EJ0H4fJ4+;eQ*eYZ_9JmfESfp1k9e ze_@jKWzE=7HRa9X$uDQSof{+x-z;5o{!!1S)dx?4Vi^jnGsaE{ElG`OSkATZB9cSO zgGFemx!|qWVAy3M7=a256V9G{sKgb}iI5#Z_nz6x+$VA~K99p>zj;%P%pC zD?7MaT}apG+_KsfE}$`G(8T6y?o9(&y(e%(2Np;DR>3Yj?R@csjCxJ?3x__n8xv6f z+2d(IPQ>8_yV2dw~_ zcMZ)(=g#Ull&Wt-bJ}Ro(DaZlh2J-U(wlW81ii^=_3jZ(U3ub$(+H|iJrIQq^cL@M z)TY`6|JNh@(qys=9Fn`A)$2+%IIjIQL&^A?MyNtpBTiz`Rnk6+6y^N{JLhMh-6ZoP z6t|=yryvy|jhx4-9X>g|4sWEPLo2gcpSQB# z46q&LO32sgjeP^7o=NI#Jtv#8HaG6Nv^;XW480PrtJLulszSM=M`QdgTfg53-hzH* zK}Qtd?Bdr7Vzts8B(*v?@70dbX;4SLMA^D0O1d%vRLfMk_hq$p6P}s6NaVGD}%1xRQyce4IOv^v(e&y?mP`38#OeM&YMD;J#I+_sG}}>~A_+Z**ILZ8$7Eg`UI~d0yWy z^4t3J2^L=&&0{p0o7-3=)$!LLZpTF#OnXhf$upG+(Mdkt7$*KvMs)9rSK=V656+eI39Cq5;G`+M=U|SK`}OaGUW^%Ft4DzI>oi*i_0{uWNJx z#HxVr$*E?_Qq;Zq+4PyA@lkF(15wMwhJl*m0~S;+FdVsI`KSIVSLav?kNxcsV|R-L zM*Kr3lxJ(uN*elFpB~95`=SDx#*`#%+8&;@po=}2ESWC)CoR^ST$6o8z&bJ=E-3*sy(dhYlLdcT747KcrLDCGNr zSox)S#WGByLd;~henwqFlpe^5xB7&Jo}}vsy>BXSV4)Zn0Naz~@!|bn;rY_5Q6r>z zCQ}p+p3eH7<8dVBN}CPgoIY^ihx6zN)y_`m{pwV1PPnF6W|P83nPqa$v|$6EIt zh8(6R9{#34@FL%@Ugh<1rN6}w<-wN~N1P)22$05%7T!YQ^wzA(Jc>Bp$o*%Lfv(i@ z+oxm#T``MR50K&C^2WRw_mE9!3A1mxA6JbXc2TAa-;5fmAIr>KzaOE|&8%@qRni7&K8y0;pS;ePx)3wS3sbd!w@bU2 ziH7H`Zh43X+6(?tARCf&A9D=y9fQ!Q)td%}S`Y_KPeZPrzAOyJ0IfKkbq90)Q@9`F zjLMx8xFLDQ&v{Z<+rB0G!;_Q^Q#o04I{_H=&^^ZRr5vUoT|?z5i%+lw-L8s(xl0BG ziJoq)Zy-@Jok;lhc7t7=e8n2To_!vqt22We0xrgT*h7F&NI)-zP$v>|S!3x5*?Y{# z3cF{B!H4UQZ)e0UdNree;mZ_)4U+S52jL7csC{wFL}&%i$g${`_5#QkT22`$i`HdJ zxA8s%qH)!LhLR!Ei~dJ~nRQ3}V*JUM!LlV`c_eSxqWeqmAIymXF_JjX9P&QcXHCy6 zOSP{ap*XRFCy_^k2$4sWfha`;XRh6xdvnv6V6vmZ(H-v!q#|^yw*=5hO5b;brK1_z z07d;*3kNW%*>wf#Xy7p>aT{91kvy69g3e zPG4rWyD%&`H*#DT7)pZ=N0WXje6G83{=!SgjL+E0-FeWXHY4JIo24dSeh~R< zAaP|#k5#>ZD-&rJD2q~4XA>$b8o(PfY?LL>I4#>&Bg|9?A1(9b(c9Th83W`oz#whf zw)n|FfU`gcCYETj2L|0bhh1g@w`c`6by2h%z;!jc4sP)kWERgI<%=B;8xE+mP;{7$ z8^JvdND}gDAy&!+vtHw-H>R=X2Oh@z{RBBTJbdWoju?(hjl?2mEGnJKY{h-3g=elA zvb)jCy61b?w=}{OC+rHZ@yTE9dt0^m&HNl}KaozUHbfW}yuk3*k>vWT?otvL7HcS7 zoD%-)_ap+QLuj?}Ct zy*BS>U|}G{-tT{5TBQd>I53mc{@Re=ToV@&J~r^5i;80dEC?glrl70Ufs=djki>{1 zw2}DD9`)X27Uh*Y0l)pugj%)Fqo*}KIFTv=P}e6CvTEOednqA`T{V6!A$=aH7;RZ& zFmFkk2)v}#PX`oUs;=McWK><#eZI^3g)na!9m0=^F$=OH4~W4|c=v2V6+amTSzbCd z3!W#gplNibdq;3dgfvbnMQ=!4EUY^gsnChi91yht*DoIg=_;EaVpO~OE2!9R0;DgV zgCGwDOL89&(F7b-PdxmpyE=~qmTuCU=%}L~WI+h(%oV)V@2{LgM|oShG7w`;z@UPR zarU*CL~!!45(5x><2VS zbSK#ktrp$`C47QKCda2)_$9qen%*)59z4MiT|A_K^#+<~C+du~2wkMQwD(R4kP{_P zl^k*sxalyjb~0O`E#^1G(3D+c?>ogF1XW!O@Z3`=NKKVhuV}05_0RUmk@3bU&xD2* z%J@H`ePJe6uM|y4tw-Ff59(}BZ?0!@T=C!kD&1Q=H_Xh!7c0YScwRVWkcQ+10ZJV! zWKJ3w-A(2cG7p!C)&Tzinq;0@bVY)jZSh`7@T9E*1_?b(@>};wrjQO1_S_G)d4~E<_rNmur;TPfRd-_2ilWO~*EF&5jcNWAC6qssUPu*l>O{nSE)rmNR~dCwl~Hs^R{)`3+* zMu*a2O-F%ARIq z<6kNkoYV!VNgh$i29c&PViEuJj;br@!8w?Zn(!tG+zt{1EkshQqCRF_90teB7*gxx zNH%l>nMyfyk3&&&m?POeKz;Fa@osQ->_EAIlR!oa1qnDAs0lKAJQm~Rd}#PIMww*; z4c$AFFA?;&Fu-6r-bmC!hKbSa5Ug!6Q&3m1d!A8x!%(<_w z2D)Z`=k$He7?N~ljv%SJm`2_Ou&v{84-;FBbgjfCfzhU(%R5KU#gC1%et#;eq6D&g z4rRancd*mA<;lt>O`zBfdrj;)1_K3|TIR0&Zu4cHacVQ(di7bs4!74Nw$)8))+J@u z!`yJWm#_GDq9Y3y7fjC)<&ghsnvBJ%nkjsABuAK+65)5Pt8>0<$~9@9H3@g+zhwE` zAK+SxS&<+UZArF?>1WwYL>TL;U*GY+Q$6}pXw`{HB>jiPfH>pQ+QV#AV}nUqEF-lD;|#-_r7CymnvD=-O53NWw8L#c|RR_Ne!dpdk6` zLEM}xRN(`BclDjikXWJj|COK+EikvO7~rj;-r|eEQG=`aeA^xkollh`5LW$v%ua;b z)Tz}{Gv!7hG!cqS@=m~0LsqOYk_gEOG^V=?lENT zrMZ?K1+8{yh{D-hbBXRPr7YulTFzfO92$iH!^5Bq1!vuNP*?sqe$;g$qRP~nx(#7| zt~#ll;8A-2hn&0$p7Ca}EQh+e63q9vsxUqP;3j!Z#k+^KdAO4K+iZ*=Fg_2ggqXGL zi23Q&(kVC~dHP+-9YrFJxUxQd;PjLg!@C10&)Rl|rA9h*&ktGC)~kECq6Ilu22CSx zRc`GvcXibo4p?d{ucFxUhRJCIuS%+oW*rwV4S%?)=`KC=b6#8hiAvq)Th{V4nv0v) zl4ywY0cq|b`oXyD!br9Ta3?Cmw78N0v%!Vky*WT}i~P(9)bF77=y6h$`S}Ck3Ilhs z$dv6X9QEJ8r6)xT&i%Zk|HEm3Zq(>q)3W$lMb1`1f|s<%5OY>xE#Kry?fA{YTw4C^ zHXe?&MTZ$+Zz#>rGatw8X`xNQra`@&PDNHd62Sb_U>G5^gT&mPJbUT${`AS zx9;5r-HO#Bx3tWJpVF-*mkrsh6~~G$A6NL}ik^l=4C}wJxUKUeUE;`A!}JQi<5QY;6kIr?5Pbr31W{+_f6%96tSe&O#7z?m2W{l&2d8xPiE zm0vlW&!()`h<7g~^)?2`{F<)PMZfZ;?OIb+CYgX!kYEjge>6)Ki`9Q<$Qig7Lrt8o zkQYDtUqopTc=tig3O@kIm>qiJsE0)@FdvJ7GA}i{N0X!lqOCE}al}c$R%so}=Z|l% z50*%L_CVV~LD_1ntzTP=ya8hAojdc{BD` za;>Xope1F=Vu{TpDHvwC>OJQ!28WfynQU7VS$cUig~R7TiG*n!U-d@OW*$@|<3mI+ z_MObXBHErgvR4>!B+v6DBk3IQv`cvyrGe92+S+y2YqiJZ?YvegU>$gKJImdy`LYEno2=N;fg+JBGs zclhwx^WJ2m;a(CF2D2E+8j&_0#nRT_{x&WsHeFp)g^zBI3hS=D@EVTWhGsLuD}RI> zEQQf;65`qxoJV(Wo~NaY3AUKpD-`mgdrWj`?5{2}a_e66T&&_)ZF2zS@OYZ(eFtb` zfQ)1Vhr_Jz@zwk7?Yy`Vwa>`G!Xzs+pBZ3besuzYp2(c+?N?Xra5X#n0z2{dY>uH9 zE>bKShwtA6MYa5ixT{<{LgB@L(PM|b-GSQ_}AqfU}% zK+hQTiWCgl>{P4sfWh4wwuS!2LjQ?Z!+<~ZKsi%ZKjWG8vrX0(w|=eH()pOGI?z6e zzq}`f^Q1Z5_*6{##+?Oki^~{#{?1p1!f#jMBLSv93+L|{R@@2P_GrE^c$ORn38wy< zpop$8b9a9244kd~Ql$0FxjY(?((ezpIph^?>W@bSvzdy*ZW+^;Qmyn=C0f_^y3Vm_ z95zblV}=2Z#x-^ID!d<=k&rDb)$tS`N*iqnEYA7an{lUog%mFiUI;jke5b^WL_)Oc79i z6{{_#LTh$8a9`PnJ*Nt%btwM`1j8RNy!4dHpHP)xLN!?!JTFbBua)GS>TllTk4bSU zYgcCFv=;kg!*OhnOs!`Q_M|XFOm3tqX@yi*+!C6&^`c3jsAUBTuQogbL831Dmza}Y zNHAZepLtyeKbc|yx*PXaFy5^?yYO>MCL_Mg;io=E?z4ns8uV6-0= zl#j-ASlx;FRqFROi#mD0>aC}0|LEa*e9dYL0q92+#)B$ro&&~Iyf?!EUO^W!OHw`1 zsHlyc_%*4gq#tR*@0xcFO_G#aA){p|n}VH|S&la0SH4zt3Unh4Vg_|Jg@Dzrd^A2% zsiNzSi*iAPKdcp=Y#w8ITj|oKY#x%WHTeNPR}I_NNt!7F)zF+ZT?_r1HX)0+C;cll zd1lW?-m!@E?13!$6YIdZJW?H1vu`q+ib0@4^@nT&iAj+vR$Gu_{$EzOF$L6DNHEgn z0_;bAYy+u*x<@XT>rTDtfVH2RI5^ys^5&=z#P8F%F~O^Q0v+JK)h}H_tZhoPD$WUj zvF{RT{Ps~|mzyzibN`4GNZsC$LHdRZo9Y!fopcVA>Hy`*9#>|05bvzI3+_sH+-3`I zCW?o6IDY0=>?UO($7rMRFJ} z3%d~3mqCFJfBzVL%C!-%<+H1TBegQ6z} zWrH|jJ#)SkXDFdv948y@E&6*$nD(nW!fyj1*xAVSP}^uY%h;n;O%J!HrGWGow?OBM zN=QW&{(%*?8oXuZq$!(D1RmvVt&_ELOX%Xi|LW1^NHffFwVyEVLK>wRQPxbI&CpN) z@eGgaOKZEe84SU6ah=jcbN1BNF1EtqXl3n~al=1a4;o!-I_RgNpNq>^(3yjSu`znVM z&q+9sM|XY%0TVA06NA8ClbStB3bW}e=?J1d0%cp8gUnV!iAq-IS1nH~)W zRy2&(yWcOri?!|sZOHGBGcuqhAlKmFJsn&8o~$|+1H6~O|7$%gk+2!LRz^<=!1FFh zAyq`USnhcyU2rLW*B9*6F6?+lh6n?8Zqer7~T==O?X0= zn6rO2s2r`I5!=yS)YhiYq6*Chwn9bX6Ha{Vb0db4`0W6?;h|u%dk>eVr7_#eKI#4K z2BzsGLgbKIkN>%2sAsbloeaT>fEhy;-M(12-3fiU+I}m`=)hAkBGZ7oIGI{oRDnsn zNK35V*{>RWi@K&%7vkV{mpgZw_XP&u&Sd;q&Yx3Pj5Is;-wB93Z` z^X`ZTOBv{%DJdP;BhYETHsiRXM)q`D1(;1nKr)=BVV0tKw6X! z__&#T@w+Js<208)KZYo%>~Q^{`j}m8HhVC+h%tA3(9~eUQ!!6(kCqPjBB(zK%55v0 zOYUJkQ%{-0hSP2!W%w~Xa&P+ll51TMhr-zR7wM@+wM?-`nc_X;ZMgvizcaB^E9X1^ z0!O=_O?`s+WQBhwnjr=nQ7Ox7mp&k#ZWW@_BwNdR{$cr0vWN;16BY5l@rkaZVGDsh z6t#lr&ZzxLyMY67&Sfexv%@RR2?d*v3atDwVPKHDv1(@kA|7KMUPoLpvEOB^l93*Z zCv<1%$10DC_KGGEIku8+8Sc6rZCQ^5$hKy}cfss}y}mQhyVo}SPFQc` z%9&<-vOE`QY!=W5;Mmp6!TsArcnB}c6^4%yE1syrjEq@14?G37O{DB}VbrXMgz2LW zP6WzxiXQ0Cuu(E-;j%?DRk)!^$@L8nzDMxU5qQrU3!x45Zxfu1%_+)c?@4M)1!CTz z-3_Xr7=I(+NgQbTO!Tk&?jnT<+M*?nQLCH7cCEaw;F~e+GQnR<0jKD0))E%cBqQ^`f zW9BSak>7O@06~tP=|gVB_QL+~oZIjb;V%s-Cq8MTg=tkq@TgD`$s{R7hxRKg%XW)^QmSe!D2S3d$C8$=w`HRc>-WqCIXww{of_%ZoM$8z{H zU4i5s2eXv&Tso6VeEm%klid65S29u(y=(4p;oihUy+z9gQ;7TNYOo>wAGQt zv4uWD(nd7y8?s!st=BI_A2pspn&Yq*74gg#1UY*~c>ULfyqx_1%+9{gTyoMc6ab1l zibqA@Cv-NVG(51amWhLH1VX+SWzgwu^VZSNjs&5&qD;hphTV!cj{UP*lbTO|`vS3q z=s0Z<8hS>DPcM6YzceBdKN|5@h_BiAOdql@LMWokl4Lw1@IF?9vPa#1mRN!Y~dm^r$_O`ojzz*f9kb`5EV&pXY)pW zQQz2iCh+C0tax_jw&=N$7)d{g2EiZ!cz&P`s@>X1r{bdaGa+sk{Crh?*#>gTooX%P z-sFle1-ud~2Af9XC^`$~&3E<%<~H6Nfr9Ae0;0`7e?XZ4MT!kPIRP?E81dm%AeAFR z@Hr}8Y}TleFBC4XJo@Qu+b{q*&RmGc!B*Miq7oh#7L|}Q4>WHv+D@@xB zj*Z@m-xj+t$VP+_d9L#W`Q0QXM9R#WwDrT&9ZclE_h_YQo_xl7%uTHBI~T64q^iRG zqYvYr;nL3-tj(z^&EDAcQ*n~9+6xz5P_iscySOMh0Y%Z8-AVR>MJ^}o_jAPHOe>Kd zz5DSH2Rs-Ed4Qw2E`YH!go^oR?KS(~GXUz&{Md`%C!s|rd*$`TsmAanU5lT*1iPjU z7Yf{!i=Ssk=mg$w$eyH&8)!!uI~-w4F~OOtoURj(vZ`)2(VJP%9{%p5!_KwG3(vV@fSH$E>4cyt!_qj(hz6U?$4`~{Vdwe4@B>i>jAv!+Vf zA!MJ)vK@-cR3Tba|!$to0S;jPFNQ`1(6^%%3N_nWgm znQt~m`>0qWhL_s=9;0MkH)O_|5Uo8Jl)3)uN3)4 zu5a&fPW!Zu{e&<*YLcfIQHrNiClqqP&!aU2e)^`o#PRT+vBw$VyxM*Eoa!MJu6PUU zo3A#Xf15@iB#-1O#p;=4(kD8S_sr^(ruh0!lxZ2(?Vs{jW zeC|{HYNB7YgTtl+dQZbZQ+CXn_pzui5t*75@dix#@HO>C0B#s-$OBKZ(oCljtI89) zDuHYFZLl2yyuX$oWk-G;30F^Vf#q#4Xr!3EdpO80Aa5x9z@|dWX}x{dMd|d`K2c= zGYi_5ogLUd4OFup4B$7Y7V?x0(=HKHTzsZ&(J+{~AxHZIB}@6{)D5{sn2|qD4s6u$ z`CqWOX{EiMDVq5qDynD^4CxR{cuMlRDbTK*IQ2e?E$E`1coM9sTi-x@k1#j5n zXoT08J9RT3MIpR;?5B_Y}Vc|F{u>geW+J>55- zD;+)xb(#h96$W2Wm>Tf&DK zV6LFb5rvXzQKqL!uF1w9E;%EHsdFy<;rX>ObB>a3t3|pMp*jI(Q1@_T(oOdc@=G-J zb=5Yhh{z5@E&*ySZnB0WM)r&xPhG>{I8t6~`0hZnU|4ZlQ={{)t3Rm=8^fJTlsv*S z84t`eyrpcpmA49V<7@e+!(Q0B4r@RWEux+QF0S-o3q`#~;Hyy>#HDi_ln2CkXE#uUyuOp)`FZ*Z3 zrHo99=FW&bYhOm)N|oSDxmywXTnT~Q%Thv_D$eWy;HslDdx24@b8io0Ok^&HoUvZ4 zO~opKF%~Lw!}905$0Jhl>->#iI>mM7&wh*sPydl-N>%O^fY8-*kcwVVwa+`)iGFIy z56ezPy4Y$1v2z&gmuL=w>CxKwcIg-c$#wON`#V|a`QPJTGBkMxIF?6pcZc6QcJ8o; zxP3oOu_*RNg*L4zwrrK4aS|*50ReO4t@C<;fuA_PF3*^ zOQ0O?BCxEvDqt~U7q2u^{TgB!+3LzH{ZkE~?+fpd1Li8IJVj<&J_CpbUD6e@z z1i9kfsLUDiRnC_D246wR0cwq@BVWayFso$<`KJEWboCTwG<-GtP#pOG;m6Z$V=fk+ z5l;U+(VS5Ucg+r3WZ39L21hrO`#`Y}OrJpNyYeW(mCufT>h*Z-M)}H498#M`plZ`TUx{J^*@mgVGn=XYrYn!pu^lc z6dH=b=7T7+KyRWH2sx!ZP75qHJ@xXpH$L#MfHe>|c62&A$>^V(bEJ>Zfg5FX?v=%? ze{z$o;;>>00I;Oop(T}V?@%#2T@&mD1c8`ja_vh13?#e=wjkVTj-EhAabDrf7D>D> zbYf!^SgFwPZgtAZ1%_XmsBvI-q|i*c6FblNpP=iE35xok9@*>=H%~3=QN;tHQJvlf zgf06v`4R?C{W`2E%|^3tR0ESCoP0$N`HERfQm$1n+sPTdeP zEEJ78g7jQ8_B&I;do2gt<6<;hbxyWWWuicenjB~FEdz83shgS60@ zm&~=5Z-G#IDEl_)8{=l;KWC8YnW2;kzL&D?b?em@p{*AfTRaieM&#q(6}({SKRvj) z0eLMYsr2R2m*lIU`{Hs8*A>!$2OaTj{SizLY!n9Bhl6{NbrAGsI`Zz&GF|YMAJotX zjwQi`KBoBhY%9`Q6<>g<>h4<1J>0tsmL34bZs^ooA*(EMr^Q06{>$zdhQCK4^vFq`GwhfEYYt2lRX| z=T+FD3KmO#v5BSlIPK)o?Tm*$5i+~{e!fW21CLF?gZMKRbb$U&WgoN^ISVP(D*HT7 zOJ0OvoO!H47Hsu~!x-9r5b_kE4RCTQSh$HZtINoRxp)QKT;6}(37P9V(-N2O7I*`q zm_}9>H#Dp`(>otV1`JW`HENQ624ACPu*rlgcq_YFd6|Q-6jH0*qN&HnMD>w{yToJS zqH+>hlf5O>1<|<*juRxzp5zd}imtn}q?qj10x|Wz-9&Z9)l{v$9tv%a3QA|#0Mx(* z9h^F(3dW~Fj%OPzSwwGhownY+5bUfv%BYXD7LKl^{(awKUckxTphz-w_ z1WmcN)QNH~qYZ{`dA}=_m@-i)IPy`NPt!LsQ+P8hQ@&#~CkP0fd9P zRyy&{c6~&q3D<85lOgXrpLE#y-~t!Z>4)Qrv{zEu;oCZS1hzxBG3_@54JZL+-5fG? zi8ve@J@0|d9P7Qc>^BRF61O9E%vep4ZttL4UCDIuQm0RA>jjd;6>9c%WIm4+x1R?T zGSCvLXD(cfDy@^;wneq;|Qb26Jmga{a~ap3{eGHReh@o z4G9wWjpYw9Ua6(PP+SU>Xec^3H+gD)@SwZ3er3dp2rt`5$?Icxc0@&N8tyb0<4;_Z z&jwB4vuFhtPM69PNXq?KqoVMZ9_^iHC#6vc1U+K+N7m6X`?uzIkEcLbD-_Vki2eM| zm9_UKG~pTH>OPCXOI772WC2_=(=H6-2K&EU8mSGkJHnwENvyQwGkUOD5PJ&cXiYRx zK2?p;>MS~8v&3^9gtq}x&y4=? zN!r^wV_P%MJ83J8)7=G0Lx1wJsBw~;>!TFzwp6w8GBV1z8hxTq<#r_X7 z!QMU)$Oc^6B0OE#1v?g_MS1|b77chxiXL*HEYbk)Yy1)G`J+@T_1z{Eacr`nEnF6S*cfOue5D)%qbFCu~L4`Bv~H zGLQsiDY)4z4!xNd!?TbAG?TZ4%Z>ge^Y zjc8Z81zxi@@V#6Qk@oTYRDcUF{>0xRL)ivfJ_l&Ent@309yT`F3L0aP>Fv6xX79xB z7<|`hZg~XJZ-5)rbf6ZE7_EXYh|ANYt8jx#)&rJnCtRLx5o&dXYc<;`wb~|84Wve` zjkRg%^@4S_MiGnfrMArC>pj8G-V{U%W6H5?<3tUCUI!aV5DdSs=2oFY2v$Y#8+Qet z?EkSHgOxO8g6*v{k2+jX^GZU=`HwX29ZR0upzgz3)bj&Hf!M|L76-h8XKKB^Za!TN z2&i>bdxmYQnvgmn`@s0qGgt>#+Xh!#dF=)MaE13-2*%8c4g0@nZ1SvA{G?~oaN*Oz z%dO6=ClsWH=^GQY$j@wKE}5AgaZjWoY7!-ZCM!&O3g7R3Y4e5@uR%T7*^Mc%Qz=dF z<&VDhbQFqt=W08F{~?&|9tY7EYLx-1Q2~2(6CdrYHKsBR%vCma77QfVJMRTt5O7@W z*R}VDYhGQPuXZYgQ(tp<45tNs;ZOmj1hgsLL>1Bd>|iPNx786vqW*Sbuu|i&!BU3T zb6HFY8R4<|{0zTqs>ttclSHOH1F`E_JG+#yE0aoN>#d3l2+bqky`5kI66(C4@_3&tQ>VBu567X$6J>)0lm-$| zK?Eo}C#ezE7(R|__>8X1_sk2P7JJa1x-Sd`8Kl`s5a-~`CC z8K7=iTo`ggJ!yA}fPiEHE~aiQ@ZTD4C%Q37NhTg!U~+)VzfK)AN|W1MtS+mz7919| zI7a7h8@hgO))+k(!Qz(B-?=#sCqxjK_o(4kdc<^K#61iow^43L|Khw^7V$ZqE;g=p zzF2OaCaYPorlU3nqv2%A-sE@)!#fQIWD+_q2+MGjgi{K3*Le=z7rl_lO7n+(dHRpn zEHOCIuoqnh-R9!?q;Uu;$^NY z<-)Rgz2!SWn+1Om-O@j(`??WFr8JUgl}pa-mygV~2>FDFJ+>P0S;HTS+!i&5)m25E8%+nQWVGQ?@-AS;QKA9T}adUkAs!VGob#26<3d} zBWMAsOQeB_R$@Er5Yxd3hp=0DT;X^}hOR@~rx7<~>+*))^opwh#QPUFp&>~~-dKhP zmW<6WUb5e~2d;+lc%_Vh#*W&HW_zn=uczv(>%~5FT5?brgM7p+%XwX+Gt<^UtKN;7 z+Oe*h578;frg{_*0)5COar=dLldwH9pzqC;$W4FA{(|@X+@0UItK6&x-o(Z;JmC^` z2z6#gjeieXOA-fnCVc?pfb%&vPAF7EbV5~M=%)oqqR5RrmLdw&*E>y)Y@(%h5rkqw zrV+svO&0Zb+}Ba8oXY#{I}RDm z+g+-8adUz-OX#PfmvLRn66yO1nFR zAI^FtWx5d94fOB|m2N(P3O!#TZ64uK%B97kWzYYJzIO5Vji;0AKda41@_j7?%Dxzx zOtq~mPbgLarW_242Rzb_-5?Vio5SaE&-5J$m>qip37Xzy@RqPw!86s6y{zY+!Q??# zkv9#)N}lt~14x1!63~Vd_#%5ug^l4Cpg6k@7u&wW!+VpjYo^?_-7l%7L0kcC4ktn2 zY)u4Y3YNTMn%<6Ur1=`hx=oE3>fHm?Kfj(?^%pBpYOXdsg7j^*Q8*9P&DAy>t-23M z7t_fgjYg^RwU;fuc6c%EoNSz$OPWe?JSTIm8?!DJBzKU&5FLR`RnKP++6ZtI38i~b ziiMAkCQ&w7U_6AY>y=K5upVIh)XU~@3w?%tXi!#OMB-ZI#_X<;PPk?*3~|taXJ9p2 z#Rp#Phza4(wTQX5ZR;jqoBBc4?0FxUqufqhY*zVjxXxq}b50O051nV2Z}~uL1>DE5 zx)>e3GZU=j0}wqPd->Q&1Y*7!$Ogy$7CcEDRA#lXb#gg{3xF!}*x~!F$ZGX9XFexw z35Px+B~SuvW3fj~CQ=p8lb{?#x+lbRswOf~!%d<^2i}cVMds<5tw0EP)0$%1B2MAW zp1oQY;!CWDpc0@H#D2KFS$JFN5EUiA>|-q0lA{Oj}RnJgX=s|}6f z0;%SF8WQHtQ;v=SIhWY;5=sw<)Yx{jekepaxESeqY)|uMQboLVArzVppmj~zVM&d% zQ2w8#3a@4e^DMbzAzi{!eCX|GxM9%Vw~jSK$WHc8q$O9xw6W0km-O z6Fow?09`Ioedc+C9nMPET%3E9{blbJO&U=Y(J|h?Imkf9uR(4_D0>8?4L;nb^XMlK zk=RsfwY3gx-Nxl_$I{@}Zy)t=$h&l-oAhw`Us~CBGh2V#o15IZ4GmRe2s~G&vc53V z7|X~f6y|{P1><*Qu@p{D!-=;|^I$446^_S?eegA85b5$d4SqrT^tNj(CH=%cFD6d5 zdIej>TFkh8eB1AaqxSjW|3)+cH1x#Q6ht(@G081r64T=l5Kd2nRoP;6-6Qm#*v@@C zPLYJN(zSJ;$&l{UV~EGP#e6KGAH0q;fuf`37FSh0vC4LWi6+??XxjG?i78I)9_urq zH@|@+rzkM+SIJ|`F)*&5k@>Em5irKM2ATXbn&H?!S3OT??4s4Wl(9%1L(}c)z)_Ij z6TZAPb$@TT^7qh*xj9E~QB__x6Qmk^;eLRtH;Lv#>{f!?4urQ5QU^oPjy?&Lh$Md({@ zR`}uR_sww+73k$uH|u&ri{_(aCHqTk<0@@L@&5X9$&i}q;I7SWbp9(E_v9B_OJ^nFg=gIH)?Y)uM$_uQp3IuO? zf5T-l+p?~2qEmn5n4yGx_|nK=@ezpl%xshyF8t4dOGN_P`HqqnkhmF!6Y?9B8zjyE zAm;R{akIED&C3MIQ|M3BUcI6)taipOrVN}z)3MwW1{klM!k>l~0*e`hsG4W0%0DJH z2`)#|uM*o9m5qzl4g3nMFu&y4D*`;d8yq}X z6SD|!kTx07ZmCp;pp@`MzxY@(S}{%eVLGR9)|Sex7q}$X$CbH|TN+y0qhN(8)A`3& z6-#~gvZZ_uXeO!nFTyXpRW)-S$oXiinHIoP6*B&LP^(}=v!)zfE~3bei&km>Zs@{@ z9Zg<9lz_zjY>$hKMu=DlJ=_x;i+zL*03I&uw&I4!%4n1>x98J5GbL*d+i5jfOT)=h+Rh zy(k5@dwvB#UH~1q`H3|P0bxX$d%vrtT8${Dqll|){KEO(6Nu>yA4G0p6*1oxt??b< zIZ`Nq!VyE1fqEke55zO~qn+^6nbDna3@+%zjq&Psyr9>2>5LWk>_WII7Ans`PDabb?3?+fr(`m2{QGJosxj`SM=?&S0!^0A)!uZ9}f%c~2hY{sT%J{y3-*tR@cQW#( z2zTn=Yy&fje@Ye?Qoi|U`c+S{+AJA{0S*)+8tE0_CdqYDJ7~zRykc{ggL`}o0JXdF zJt^QkO0-P$1Q{Xl5m ze-dAQe;n@q>GyJn7=#uAZ)eqdQ%y4*gQaQE4=vyAi5Z%79R z2+s!{Zf#C_7XC(6?&Rpwpyxjp%c@E>lPXehRJUvG+N!%$@2f}={TzdRSwet#6$4Sm zRIV|JJguPUff}--H7+xHR?hr*by$m>9u#aq_fdEAeWleGbO~9X)<4EL5(x&Akxk1@ z&`S5qpKjcDLs4XGlvbL3)IBo*O;I&`(t%P&IrVu@VoMTehYwf72u_d9tRN8hx5Kq-1E0TTC{&5-kq7u*ad}#le|z49n`H z0ulp#gO{HYbhI*3j{kZ#FZsPmMcJfKOTXVooCKL@1uO>AhC&f(iS}j-=CQ*$)^$Kt z2BZ8cCV^~HVv%D3iRiFf+8d)#zDG>vZ_-%a31Sdq13&=PXbUmm%pGYhIq@3W`_e56 zl&<$(y5scgzqBPmZF+x**z1l3bx{vK6=5t0!f@E9bM_zaNVvUr<*2n`7U$b^=6)wp zDNuH81G?u}u%e962mOe59szqt7IaUKNL?^hxzqwFBQOj4YKL8-P+GhOn9m9P&aejp zrv4XKa8C?K<@>*yG+rV&1~I+(t+y)Q=cL}9>rEYHcEl>NU6a;g=a=cB@UnKh4-z}N zn&45|bDS7&nL6)H0YOVsRnRkl+9hZ{fR@*SfM+ zLHlCroIv%>85|C2TjkkJ*tuJL3h*d3!q#UEbV0vsI7*rrhk0Gl8%5_j3A|(r$DL4^ zpc;vO8GdzDGDNofq&I5dW_p`8UR;DQ1SWCg)a#PaY0u%v(3Mzzg;C^~DsWnR*PMXv z0k&S$HH?2koGzEa!MN6uzYEEdIyKB4H^7tpXMZ%{p&pOyHK(dnvN@=F*hz6a7*I(eHF>1Wj3;$1wRRg!r|=$; z#CdBS^(w6xBg$Gh-I!j|XR!-cPj?1`wrTRc7As+(5p6gb%pl(5K0GFS%O7hdIc-2M zEv;z(s8Lty65-JMR%A;ch5XPTdAD!_4J(9zk2n$IBX{`m>0~ZXdGAg)8@IF|2|;~B z^zUm!U;_MIY_H z6my>A$&BXR$Ppbisvbq4&}dJuv`pS}aliJc!{=Fr zfe=Oc(HB=@o*;7S5|dkM#ZtO$U3R}RX+t5pSyVHm<4)6WVt7Mf%srAVGj$cDZPiV) ztd?G6IR3GK1q$U91Q3WF8CykU`4+_f4ib-6qRteaM}SE*>Mb-Ch=7 zze_#%pB<`9zQbe6=l99X5M#D%w&>9=6MQ*Ql^fP8AaCUi52*#77MsJ)etq6Vi*8|| zp~sW5rpx}=<67J3n9VJFkm=pisGpj_>T_WV-sk594i3CSQy-e z9`7m%(1QOI&)S(e<@V%H7?9F!iI%T~-E;CNG_Rbn*47$VuRBXuem61e5xZ)+9clCUpLsaz^4u5BOYU-9Skf=J^zl3o1^d#~e>}RPIS-Zs?Tl=$ z=lVF>2n&1r#qc1iF)-y`r&1=b1HT29L+7M$N#_jDmlTc64`Tp)2GDU5fgsX zXQd9L%xPP7k~ktxPDGd|N&xU)=ob-VLL75UK3D*%zr?e5!@X18q=5T=dA|a&-F->GM{PtjDm{pk5{2b_)a;i~lpdZX12e`$q-PC!0|}K`*fU7RYyB1) z+YINrYp6qr>pNi2Bf)Ci(A#eo{l|1h5MuDQ8kNO z{zc-8`uYDB0urFaSNJ{{tya{I2F81bV^i!}129?M3taRp z%+bu(7`Zp$%uOUECsZn@I}^2|OS-YC|1wA1@BtRN0%}Q9T+LB1d^d+FHfgt?CKb&0 z0gcnVL$o&(OsHQKfKkd9YAJ>wI{Ej^or+={iAZqMU#=RX`%BJ3EqF?8QUmM60LF=8 zt;rt6V5mLoQmD`d?ow#ib&>!ALSF!aC`KT?wuSevX35DbkT0SK<&KEG1ZKX(eK;l3 zJcH}UGQ8VZzz*YaMc3Cb<|E7WydxYv+0b-clF#NdWQ~B_Cy3yD4^7kkQ>6exw-|DR zW-`R+l}aC!I~F_W1q63DZffT>S00O z-VquZO|2ZXE0?>fqgf_dFhhO@Lw3WlkGpK`bDB{Q8NGrlc$%N1qe{Wi|Ky48JXs*k zcd^))if1gntwc)v-EGUu+`9;IA-CDNT7y`F!90pQzTy#y{1h#2Ol+1OLs=T0Qr{-*^tf9$ph z91kT&9W7fEk$5_pM{m~f^gVEt5qt>Jx0|ns{eM9o9(XZNab2oNaG8MfT&>osv+IPZ zTmxd_J8R(edYe-q_&ip(07?BX4Tlvv@_?i(vm2l@^Z(k&T+X|1QV{>U3SGK4+?r~maoJ0W#G6f7+GvNPV18yX-t)tDddMN1&_Mv(4BDAS%vpD|I#8MGl&BW?7lRp zdnn*8VA~NE1Ov_tS1T;G`1!$YxUZMVZsXoDBqwX#~f{-*c8kY>5T3Sf!pL=8SNO+hy5 z^-g3GMJ6B_>J`%z6BUtBIxkMTsevKW^+YC!Y&wesEwDcv17JQmv85f~dqm^MZWG#v z?g$>biw6}9ghRF-X%EoPw2!pV3x4sH5-N(f0sVZY#G{=Y*xVspzR z(tE?m5{^K5=){ND*m-88%=9I%;~Zq0 z-x)NrL?wroMcfD_=;9RZ_68?V4b$p#zd%A+Ed*pq1iCgYM32A!7-}HAi^h^J&7Dbm z97M-6!I8h-y6p4MsaVo~2YfQ#BhI%Qzh;WAvp+KS05ow~qey~o?h5*CFKftnUa@Ss86 zvm$<=5G^LC!GNJxtPqI3@b892I!3PLHBB=_I(GUTd!DxxLx>|7TmF?)a(@>cVpBCY z1y#JbKsp$c-0VJTTpuUTI|bVY8{RYj31R67Cby;LTO&P)x?8& zA19gKZ7G5e@8I;%wA9IkFh9lhH*0z{T#tUHgp?AZ`0@lM2dj1D*h3H)blGXpm;Nih z=)FvL6%g1GUV_C636S)%LgcTJd*jGclnY+h<}wkEKDGDFwqvS2EX4tbL#UTinB#SN~9f_V3{mT}_0v3fFCNi<`6oD~b~ZdHbgwD~x9j`lcG z5YsFcV1+`UpM$`v6e7}Nqb{4q&F6$`4?M{$RTEh^>|swAt9F50CTVHjX-hKd4A_9H zi5JK|!Suxcxh!2=t8&55nG-qS4>@ladNSlGOD*$g6vXu2j9$k_)(F>D}&A$^R<9hFfK5G;nph_0g5HqE0;BId7UM&_%4Jduj z8Y3*j(3~}wm$&uagq>Wyng}m5bESs{ylhQLf1G%d3G5=7*zH#pv8y%8mqdY0YLk_6 z2Sit`^(u^h_3_|=k?N+4X8zELU@dA)at`ERV(`2gX$3MX^ISGPpCugBa5W)Z$I@%sjPOQ zO|aYk;kpU*hN3Ut2}k^D19iqbotu71_BRF{C+f`@Av@pqO<@be)S}O9kWZvGZH@6E zy?A%<%$lUD1Zm7x353J&mM9+Q-jt*Sx~ZV_BIBR40uD0Lo}pbZ%XeN4C4=GS31miG zp`Rr42mwxQ^tsHu?vw*%-lYfHd;-dR;cv+p=mPw?>sK%M&p=v2lM2ap>}>HG#&d7l z4eo_H#N16OBdp0ZeayefYu_6nw_9V@yvu&iNU05Ns{$Mr*0z(*}GiRxyY*A}n^p~&Srw}{Rqyh*}n1aMUAn9!NeEeR+pq7*Iv1s6uUH(j}f z&<>T8!A=aei93#Q8?Y5=d4vO3Qd1laYJ;%CSafil-wMCIgNJL+58ctu7$w;2rv^tq z`s5fGXH_c;vgPKKGAFri!$G`TTX(DHaM8(8-ExGj-_Pih5ZF$AY9&MocUDc5%XBQm zwZJ%v;JC~HsZvc%*TM0oFwqFjz}8QM6=ZRJY+f`O7BjgSMM6EQ_#||=9%egH4oh3o z?DnZqBpL=Z@gcPhT88tiwwi0>{@zX*n?0Mt4aGweb`lrf5=e-MDmVg~bpzqYD}T%A z6=oFS^$|t!JrebAwj3~-&--B!1@$z_4MRU^JCTwGDk;X3b=M4+B~+B8tYOw{9(a*e zB0D45x_JKU75BUpDS=r?~kjeSK4R~$6 zI{wcqR5la}T-%^avm`=Vj^*bm;p=YGJJ&adQtl0WOX&e$DaX(ZhplXB5sOh~a?P zR3gm>Tt0>8O)BN_Q+f%0l9qqEM^49*g(}J|6UC3aJu|iH5*l-b{OG4{1+=wR`fB;F zrm5Xm7{%9x^!wvn6{EOy^o6qlsg>(ephW=uzIWM=Z$&HZZx2;plt zr2z@<`gZB7VuFD3dr~OfSDJQt+yCgZnG31u{ z18ABJ@<2DJhXLSfF=K2L2i3ms1+0^n_h8+?DUlz@*jce47JE3LYaSrsCO%_6YasPq6N>w6 zR=5Id35i-l8U7PPH);LWr;v#*(0kvo2{Z}y;d>{Uyy*&SAw~VJo9TADlAwjow*50% zF}mSo5V4u%G$%CssV{;sU+fL_kxvf#%#Nso%WAmG{K4h3NbVW696cv#CwXvs_ACGkZ&8$FCC>JbJw>iNeIG)<8?3sbKVVM@4Bpd#(4A{v z8ZV`Ou(Tr2@lJ8_Ar4h|NjIq44vL_2#kIG9*)=DXZ;Gnfs*~KH1M&SlVEh?5)>ut0 zdaY^*>OG<#Oj@eD5sJ z!RdBTWThXIq68hfj*QqNmA{R8F^h2_hE?>RvVIDD2S7dP^PgsGPDxA)qTEN4Ol(+< zlm9`z=1@BI!BXvPdo`X*z^3BYZ)R@^!=_MS1rO!;fw?U!z880L?A_VM$z)5PymH^T zEz>5)F>dm?tztz-NtFy$MwMvp#+WQ0wz86yr?l^1q= zJTalpk*}@2vdXW^nRwpB@l99t**fJ%rxX`50QE05)UYhm+l3bHRE78{6=L7awnxv} z?0*QJcbFXL&%CrQgXo;Vi*cGK8VBL50U|8Yt+*NdId@UuVGb$R_YU<)d=lA@>(Xj+ z$FyH6%;XSz8vu@CA!osdat0=!1nFxEs>)2pNeJ9ki2QR3AcJ=+EiYMA&6?OE3A>VW zJ%jB-#la=EU6gq(G6F-;2Yp4XU!=Vwp`A4lZbeI)xS$@`K}yQ*}&WQp>306gvycX#`dw{6TuP4)Yup8-^{8--PTntxd*Zv+_ z3Ko+r4I*h;2+mg|hZhRs!jo;%3-i&BVt`6!Jx{sUs(CYeCW+JVEn{j3VoH(nfk*Ox z25VN_8~hwWAp)XNfv_;5lJNsqjac`M6;fJ!q=&uB^zDJE3nF%4^YN4|jv-Zg1;c!C zjn}rCB74)?Mxmgxn_}|Dn}=nw#9G1sopJi-e}rBzr}AU@mRtPG($}z!5wM|LiHYdJ zsDLxZZ#BiAk@;AhvCNvnE4-+)lFJ|dgPNM|4RCpNv>>J4gRl|>6De?TENSk%mQfcK z`V17!fce_3y|=U^S8aC*wkd#V5h6iz>iCd}!DJ<8R?UB13lv#3pP<>ZjvL&hb+oduR*q4+zNqYi+eQM*tZ~ zf9-(BvUxVGyoQ9wyAD99%0CjLwbZREpWZEl63^+-n!|efLRWu4Z-Voev8hV$tyOEy z-ID*{;eRgQ`>eUD8i9cs3-G;I2#Pny0MJIl!|%b!|1aamz;5oRaR(Ebuvljf22!1< zYf<0hcE;@AfIZb{Rurj2r}>*6@ZM5kHR0v5&oAW3sRQgm0u^yhB-? zioQros6dC05&R)Cq8BfFgRgjJVM6VS8u^Ci8_W3qtr&h1QOIpK{={9n_rROK_orqC ze;{H%6Np<`P*YGh6fOr!T-V6PepW1^($1mgON~l#^>UJP1ET-tOCHB+-ZcotUC^&m z7>l}@Jd23@F!=U~i=z?k<@rsiRvK2t|B+E_!VkR^4@eY*Ow2l2&xy@6e6(V;4rC@` z*}3WhKx^luoqnMW7$acVS$GVyDF>T}1J-l*FRW|=V5Qd+Yarwl?2~vZ1Cr?$15I(+ zSiLr1HXpAeb-l0}gbY6U zaj6Df>Q<*BQhuKZwXA!a3PM&!nD-|bj>uf{hiwb}iMA5G1i%~e8ldtQhjt?*LZ0_~ zm)1}RbeL2;a3TN?)|jl=n_!@7)zp`wHBjFjP!)HFkfGPkb(ICRHE`+j* z_HV%;0nkToL*H%j)5Sv*UCzImf~H2sP|6rI_OBd1kxh{Y4q`#8w0^=1wWb%< z7KQH=;9}&>ht5QlA9V6)lBkjzznXq3>pRhmqT-* z5Sb9HACQp_3X@H&kiGyc*uUn-6&|Z$lqs3W^W05HTWj*D2B*wt5Bi;jKykZtE8ZW@ zY)U`B)hbFcvXn<#hZxbdIZ{1HDMvqZ7m5XWfHi;4IKk7F75Ly3qT`*A<8jk!PN*Uy zS@;YxkHTD&Ik)W)CycV~WY>mDAkS1PHQwxWsw-e@5P{Z8OOc!G5?13!WudsYJ`lv_*4e7<%*`B8-kI*)Pap0pEL78^#f{!sHb}tFK z_05NzL-w5mx4*ywn}!;}WXFD&6KY4e$7JQ z;6LJtj%WzGnmW!kX)&xb4w4>r!KY9W7rX=^Y8%=3@2Yrz69^U}iW);A7C`TCIeumr zHnsW|m#W^+4nyAG55n)R{sn2fOo$Wtfkw~-V$qSM^uSnRdS~x_H`D?QMG>z}g#-mAt>! z?-Xw20ANqp=D!04Qu{2e334uyLGKU9FoW5t`{JG>QPLjDXmsJJXQb|Hq(kvm=}c1#-WvZUN~qwpNA<$KRUr9GAX{gA!|mAoxLmu17Y?itn?&H-okN~ z+OV3iXhnH`(Sy_s9?#LPN3*qOK?4{?Ift6S1uboZt=urj5*BFluaj<{Qa!ct7#V*a zyuu;#7_uNEiiir(`}69=pjSJ%mjqb_ISNp}J65bI1IgEks5XfVh3zoHabwZ;7daCG zN5=o9DmnXW(3Y?-`KmRj%^&UHmo%L~idce54zV1^fx=|Q^cZ#YBn#V_iWr`;`%k9h za5n9WG1h<;c|%YCNGT2r$q_^i7Kz%L$9~gLJfB?;EUPY0WPz5TPN- zVxB9`QPmC845Djn%sh=K3eHwF#-Rgn9RiDXm21pH+LFba*%P-!4bSXY%Y4b(N>!(S{0-|t9Y`_`B=w8VLP@+MpWHP z6M0}A2|V2a6^+K4Rq(rVLW?&>#uMZ;F zn-MJi&K0v{im(xJ4{Sj3uj$2b7m)UD(tX~T-r3&&yE?5W0!=}Oa=RVw6ALVvwLYR0 zKX2uuchBWKLbLQ@1mc8L)TFfplKX1^($C62FRT`$>w`nc@rXspc%;oG>n1)29*&&)j0{8aJ0I-0|I)90F#7!B8{WhpG zO}H_>CY*0!M8lG`OSv>LJzvN&>_O7`q_^sk1QPbL<9`3g;cZrJZ-W(bK^+qg?o1Wf zDx#i5%T2kp>x>Ant`&^lmkpgMx;BS^3i9BSpc=gTHnI=JeO*!B*FC!iwmI<*k{^q* zb&D)N5Mnx_Y`>h&m{!cuye1x+8UODC2ZdYhmRD3q%Sx0&$sWfmk>tq`e7|9uJ)H6l z@pv(*i)GAh?|}?gy6Bd0sjszyapPgcRG-dzAS zK+3-<8AD7w2?bTm^Wi1gy6+%Yhw@ha+lEX8)9{k#+>anfX_8=Piv6PA>xKhTX2?W~ z?|NuYlK`(6!O&);iPfV=_Ze2%@~?SspA#Ub{wO+wO(Ar)yL56rRw_VO>`r_;O|}k= zvkM`r5y?u7kOa&Q_a9>$WmvLa{h3TsgR&CRZ+;J}>#55xxleB6PhIY8r;KF5_hUlbm<2W2G;`dEV8M-`LbWJ-+Yy?4CC6z|KFXi?> z(ZQob=s9kmxgU4=LW0e)7|5>MMw^fI5!-;wx)-{Z>tcNR-72@P2$j{iWC2H}O#5`eLprWnkhIE`{O9bfHgBJ_e&vHuK2LLL_i-B)uO*Nq9 z6n7p$ug>1jdNpKe?2ShN{kB7L@!_79zZ7!%#j;RS%5TkGB~lEoeLzcQXz`leoDIrq zT8PG)7-SEDo*>9)=kQeqw)&OdESjuoP#07Eeh}0aVuoF3jWaw{X_F_q4@o7qgTqrQuOn&m#~U}!c1z3VZjEgFExFl$o; z{PEWda03Q^zYDt8giR6mRiZTAwpuT_(`Z%!&(QSEm?c$ry^XUsf-9(fzILjt%u76k zO95AYz&i=mlNbYY%ygw?k~~tZUfSGTZ5{J+VBcacBx6{nW~QT}UZus4o#pm>EDjlV z8a=$r`1?5DmKLj|m(&lVE$KnHq*#s9+jSBGgKEFgZBHsFO_GhCx8rTnau_UP#`Y1| zpNV}~T+8LaO7&#t!MiU+B!Hdn9_qRC_nq47)i2tF(s8aLA@p0Bj1KD(Q`<4V>~G_y z=jLR`-~9B4Tni_|z%%ze@eC4dgD#r6bh-H^pWL!G+j5^4Nd=92PpbCp4 zdqF?4s=f1{8R7(fgTRMhBxUItyY`Sjn>sxAuL0MFsH+_KE};O)b6dVa!0EQ}>1UsN zGOJT8ch{et9hq=L%d-{McQa+p38&9)1_G_2^CoAI{L_NzT}d}wz!~SXU7F{{E;K`~ z2n0XgH2D@yhO<+l$@{`-7Jp<}o)A_E+dd>flZGD4yaQYU$HiViJM-)9^y`4$-tgfF zrpaBD3CBBrPy+aG1#^<3c>+aw)tR2mC2$eii;RMbQf{70Vcso!V5xkDl1psQepZ+h z!OWC{8q>^Zz7F%tg$U&vc_WXt`(fTs6gn_m=4pS}FghW|V#|J?V5wn>B?|iO50ccq z%8B70N9Yy}ixV*rEgzyOO_7j{YZ7k_3|(+jeT%9tn@qqKF~`$EnLc1s&Ck$U(|mT! zUYlFu0RoFNk(V~s5w!b#z}ZkYk1dCnTOkW~;(p8)rggy8N)bIGsTjxZDQzWKhhlzI zRTzfy74zqH?1MOrlbeGyDNOVVrwv0nJQ48tHxNQU_}^nxMx7&y;!LuFmAEDQCJDxG ze*uW^*CE~ebCP-nm|KO2#QdBDf?BnpGa>pm(fMU8{47bd7OD21-d`kcXA$@RBf4p= z`|CNVOSx`{B1YBI&YYR0Uy5+B`nmH?r&4r(37jpM-E{=*SnZ?BO$f?MMoc+7opRDH4wZao+n6I*M3+Es7%6Q#9<=rW5=*fC3^MVmjL%X7d5b>WPGZ>;jockolB5>7KNG+q9xJd;o<~Yuq z9{cE9`#IRv3z9=T4;eD(HQwAXUiyvw8U!~7%hl244~s!W`h(#_M?$_Lbf7?&V_H|> z&R|IMnO!^w)CVwH7IY4S;(G{(Vh&;#1l(Z`u(OCY2(l_bvCHY9@Y zw-$DAhfokPywxi+pr{)0dQiV8lO4-ZR7P{28%{)_g)l0-KhxqvfeLxr-Q;cVq^#CMo(z=?csEs$J*d zPsyKh@o%gA;RfXEqDT*&>LPWn+iWaz{*tc@@SNs`ItbV0{Z{943Ic@}F59(1Pa93D zKAv;k%!)6e}bF7-DL9vcy7haeF+qgd+Ww687$QUAVC)q54!i;1+G_kr&17|>uW zP!gdJZXg;?_HhskO?ye{wuGgSC)ATx!)*)`&>r{)E!6}tF{{64ZDEBJ)1`LP-qT8%n z*G>IAhkW1kp97|Qzhcl`yOI$<_On}z;I7Wjo^RVXdwEJTURVO}ZwlvZqWA8-r`#^?=brs#b%)&!D>ebWY!-8a&sAv`)K;BM*Q)5?gcfP0eL3PI^On_#6E84 zb0uomoMPKa1DFW)MW2iwsCkI>t>J=#Y}c#d6{Q^|E)m7kqn6Yb$MDi=*$9;?eOv}0 z>VcmIC$+=j4k;r8*C|H<))mqk+ZE6gk*8gjt?P?1K>;x~NaVpSi@!w6ze~R@ z^c8sRbfr|zBCXM!IksDMCAI3Lj}X>8V;yr<@YyVf|M&{eM+vIy@U1Tx>S2_d%YF*{!&axV zP`%~+GIAx)0}hYgWf=9H-myj6Zo!o&)KcJNjMRrGlgYTNaMAEW7;1y3*29D`HS6WrGs<+OAWYnD#4-T|m@lXYu#vjUDgRq|lq(s4j= zb_}dWsu2wVm-p^>gKShM4NW5{3`ziv(`CN}umQX}l*!c|e~ZQ{n_Cp2Y{KR9stHso zHK_nizc~|Od!w@1%A;AEVf`56k)pXF8L8{jL)so;V_x>CNxbAA`mNA#f=TgD%_*kGYIlf3RsUG2M*SXR*8=5>GzgQ z!t+v8aMm@$xQ}^$kQr+Ky8pMhUSX#(S@8D)p8*oraPlbrf^6nZm2{7jrg?2V6fWEz zDkHM-3jrG>*wKa2*sYU3}64Qgb6I<>j-64WQss>QMF83-^ zNdyvI3L^{XeF4@vdaAeAiv=T$#qX!*;u)BMV{XU6DqcIzNZg(%HkYOc6Sw@E00&n? zD~aI!o`6=;NJbU!bbbo@Qpyr2L9;psV31a2cO!b`od{|?%fG7wbTUT=1q+nn;v2y=M9VHn;23FqE*|ku*iDGc@G4Q4x54VC8S*fM>*v5 zU;q!tGDO6|`c%y)&e?*vbI7_s?`+l478)QnD(IUQ$p`W6LV+N#hMPc*5=&Auzkz-m zodbneZtX&RzSGAFo4+#!DQAbwTkk093=AHX>jNyi5juTzyTJC6$K0wH7aGLtw)!K- zMTy2#?8;4X{d!?e3fogIm1bb^d{y{!xdOF6JW~*Gij^=&k4v!I|V(KD=vG9iP%XAxJY!Pz3~<Me&MW7FM+kB|*kuIZ#C1wh&5> zO%VBzAb~RtdjdJDC7$2Rn#l;3rQ7${H|Y_Z)NhX|+g08w$@tv0KbaSLs*>{#S~J}L zP6h092@9Dm60nYJ`1a%W_;HiL@2N?&IuTQY+{7L9kU)^`7je`TXY^lj7bryYx|mm>qD=4H^+pESlxVXn+hT~Z@!lwu1-rq9PKj%YYF62=VZHl zENl07Y+PjMt0o=V_kxj8q4x9A42t+MBcyab!rGYv^K(*GWz z{dt2AKZ$lmIfgYQam)Xe9$P8fqJAK;HBLHwB|*P^IKkQSN+QxgR`2vpedDd`}mTg6{a8&*#iXrwyW3u@_I6+>I3AbNP48Tmk9= zpLN>U-veW3fFn%KW4Mh{(d8lKe_9_RQ+S8A{Q>X$Vx^*N$mNzxYd0hWcb&TYsZ+OP zt|_h)V%bLaL$u+U6Ze7M6y^{<19alu?-*skp*5&KGm05+J%dBo=QLCtWwPW#dprdt_tOCy#x(LY}i&^ z3awSDNIOl;UO>G?kPucrV9fP0te9Ma?aLkZRN1%)O7(p_Jj@NgTw3xb)!^Mq zWVwM*IuY8eUmOt{=aa4RdvT8}0L|w&M5zbq|Jb^%;%&W-9#sv6TNaz^fWk84;e+ z&*}IZltHQ?4Xj-?JlU`AoV2V!VUG#~jd_byPMY_|L#@S3#Q_FK*@x{y%N}@Y2r3KK83vtuGRQqVGjn)< z&6vz$iBV$VAHuzUWY(W_`AVL^a+z(K_P{dDn;L6!?`;H9QxZDeroXFoVS}Oegk!{0 zYQC_qINj%L7|Y`C;7UwBaBkV}2Tk#?qk5PhP>Agw{t(zh1^^}vkWB)GNn_y*GwC>} zA_>#ZB5J`+wzFb_heROyzTkY;*sbr`=~JeBe-b5D9*!7V{}~s*T;2!r_`U+H24T|MPRkUl<-^P0}8+24qm;|Qr0MIC{mEion<2i5mm z{En!nm6y6sofQur&vfe=qrH|^Hb+H5)xSY)i)4u_NqFyjHZihCisZkMQR+fDcu)a* z&_$(FO$;ZOfyv}@?37JlLKHeyOQW<>1cuHVfDxV)31uIAXQ32zSoA=R00MoRmh9dR zp#rLbgCX6}cLbaK0UDC5q)T@6Apj!*=}_@fE_5TFnz_2OHUZ5r3EipvzPh`dw-!%m z%zdjk&~JqE)l{tl;^Uav6zs3gwXu{|!DmClfk8-69;nD?s0y}oQ}sak}}*P(p7+S#~Q9t_V6GscwAlpdl5 zncF*bq_fJx0KTP+s3(nsK$##PvrcJH`lD0QZlflz<%lJx_6t}|>E#N8wO>?(Yb<=z z)Ldl4IKd>^ptb|}&)rs+@_(Zc_$ZHD_Le_2Q_4>o0uXI-tGz+DKE*Dbe$Ti`EzNdh zn!{nWTBrz<7&spmA4NGd>sESa)Lsrf)k7O20%+p* z$?=1M5iwUz`z=%*we1^gnkO9(&h_+(Y6wLj`p_5x6iqFx5lvy-j&O2^qO3uj<1u6E zSrk(IRP@i<7WZlRvRNOXLS?d5!2ulxfeq)bH5vpS@dvEw$Lvy5l&+R-yD_-~{fE<} z3R=vBIm}VuX{mQRn9JX|F%7JFLB#>@)$+7`zfjkHjeo^ZKMC;Th?@8bZY(wX1enQgT*;wjkg(Z=SaoIV42Tjhp6IlP zrUlOIHs!xs~tKEVYv9jyZ_N7h(q!|u4%uBswKx1{E{*~CtQWC|zfB#~#( zbHer0a6ri|q71Ek3!Gb?&Vr5AbwR1)yuYR8c6a(YI)>e-Dd~1m5CZip4`K%$5z3nZ zd2V22&X6^A5AZ~rB)G7UQ;P4SDSV-Dk(YUHL?^dvasiaBixoEhZ1m5r!|Mb)Z~Jot z(dy1#zu^hK@}Gif`PErd{=>Mx0_F|nP|fY2_GN*NgaA9dNK#YsBLS`bv3ztP+SJ0W zhPWnSZ|a@LaSzg0sEY2VX*5qth8~L0Uzp^krvfS4rA5RkZ9ARe`cB4~@Z!6nW_HE? zN(s!1Rv+{gi#B00P}f7-zjg#_z1WrR*%oOK6$x*oAs$W^Nis`iVQx{u6FHh&_;C*6 zaMz5O*h>#P6Mi>F*R(Z35LD_qfCz+(^lg2<7RYmmUcE;(L&y5?Se)#rE8ym7IJj4L zjHx8mm%PV*0m0xF$Dz!mLk8)}t9@7FdPyD2_TDnn@g-JN2U2zVzq{BIS3W5i^mQQ8ZdiO5?h>BRugfK1)*~IBNzQBrky^X6crg8EY>irW4<%#H*Q_}%QJPm&3 zkLel(onGByZA-YE84U_rG1Sn*%O}cJc<1lkdx5uBN@O&^lkL+uT|DLscLdFUfqZd> zhG-|5VR1T3J`+FVGnY*1Mh_lNI&xW^iMNDcK)r4KkJ_@(mxuBnr4I55+T|yx)du(Q z%kEHGm}Y|Ht(^K_9Ex81iHi#Uc<0;l*HLVR9OcX& z5C^25@=Vmwp$scAUYTVSpact^34254;S9yzOZ5gAqzt@x&u8az%3&1u6fCfeS)O2w zE5Nhg(N94AqkZ&I;R`RP{}V#phroAT3?mw+i3H?$(6ESI*PW_4=Q|(&(ft4f8A@md zw?SUprN?BD*e@0vTg8b+&h)IF5P;i%3>U62UlJq7AndiT%zX2`1+d}UK3ujeNGfyp zuYO`7+ZJM?J4x{?EYJVaonBnW(E`IORnN?9WzD!_VW}F#>9|agOGXtMN@CaF zV=1o0QNw@7X%dF(2&{Oz~1vW=~Dct(!0b^CP;$%E# z$PVd5OMl%LXbS4Cz7Z3$iRtno=FN)DzbF?%<@+~puGVZp7Sh91$> zP?!{D=uyH8lpLN)&Mz5 z7FlDu^8{a-cL*Gyh|yCq3Kf>80&d)LkLj<(4?%pUi`a#EjB4p?>c1e_mjU_YG5So6 zUpDs!ky7*;GT!ntKeiTq2SMaiV8Z4nb|s3+Eff7HzNZ9+t`7e2K$~NgiU1Gt z@tLWesIXD6AqyO;<+}9>>YpB+8Q{AW>7018WES?Ua+JRMS+VZ#4rvi8;N0PvvUHrG z0tn`|5m!G3#@keYUI^I9W6}uul{WI-Z3AnjUa5`o`XEwzB#1EX4Q<4*j#fjjNKzo? zAx`GvneSC~Ju>D-K(?^dDdKFr_62E}_a(fbfcdZlDG4Qy+9L=+?OX@_KzX^Ncrsi^ z>lZR^I9wCk_au{gZ-dn6i55CR;QKmh%eR9EM|3)_HP;6gxXfqb*v+R-vmC7^mLJO- z*+)$=jt)Guw5_Xwk`7%Gug|=@HVCdL3-${)MBUSpOomc0(?C&*u|oaPmqh1D&VC`IPo)UejVi z8^U#f+ZeMoUgmva@w09leO*~rG3xJQlgW>fFIXaH?B`#*4I)l9q#PMBiFUBs#wb-Gr>XeqF0f2&tzh^bQY0yKbn-FG}?ZRco-Hv9ac&1e0Zl{DQy!GPjM}|qNA>ojU;N}cpe`g5q zi~c>KiHZPy_6iC?2#N3Y*?Xs!)k}?RW^FIWUneqD9qy$t@6k{nG7I}Ch!xj*okqO% z*=Eet#uN(R_TStb2sXZ5dW51(HC2I`dOlwFQ@^3VTGkDIqiQg1P1KnEHl%oJ8ma`5 zt{Evl+Fdl_MgKPrC40nGd8*B|9h)z61;jy9quwX(dar5%$}b?te0<1JIPeD}l@*NU z!d}F+onF%3W$;!PRS~eE3I>oRbE4|1s`(uzXZ(6HThh-JtXQZF3nrzW|p(^gYT80CM1{ zn=VS!k<>kVljbinYoSzIJr%4ZfyZ-UB=6>&D$$sGNpz2cECG-*6z;?ZU5m@4L%yWD z@A#+Gl1MQa^B~Up2l04nHwP+D?3)tsCdq2{5qL$2R0C~>!yWQ?NDIP%NtB5G`-+1? zE$MU{ViZC+)PPu0nuktEmG393=r4LOk0Y(%E)EFRc*h@mp&yO|s_b||HXy~D_i){Q zpn-~p_oDt_wFjsvv4-`s`eAKFC{mAuXaJV_{c&Q?lTVk&#)PRgGgSDN5@rW+AH0{? z!`!qs3zSZ8yY~zuxmvQ&(%P5x0uHK;CZD(-VM<>`XuAU42;C;D#769N`7Oq(R#BE) z0AX9M*twn+jn*-&M2nigF$Ved(>|9gkZF!2zGyoC9^TUv8b}oJIHWrtyf9LjvbqKawGGi{_;tlo}Nb zRZ_0Nb%B^Mg$Fw8SXm1D-NbDt1e#^aT)gX15I`F?@QsupB9B3Pb*;m_AXk~ff9alk zS?)hv5fc zNC=qn93MhUABjKgp!aOQR3a5-at}|Dt0KCGujvQN!`-^p=1w)0Zj}tFf7M$Q1q?(v z=xPt|s5R#+n*43Z@<9!r!qMH3kdvzQMa=?@GWSYMYz&nzD^`7ALnIm<8U>Ttzk?w) zx`$rcCwtfceLywFEI5@JHzIJ3a+M9058%*@TqKsHz}5JbA?I%IG7tKZXR>8F2iY@q zw+o?5L_db=YCYG=@6cw^C0E6Lr8W1W%}o(QNd@<~8L!vP-vgTtvfF{h!8K|qslKgf zs&4;QF2SpT$nX){+|YJS5iAYS&zBF50M`$J|C}+fkqD4^R5I9UPl1!#5We&#bU8Td z^y>=1)#!oMz6(`&CtNl|Z6kTr5wgu#fM*#NaRJ*e*);15W$!qS$$kR3SVe@kycVx= zMuCS!$h~mea&wtF+8^kXGUWAcP||)pApnIoJ`sh9#P0T_o+kTCzi#*n^GS3%7JdMi zo&YHdu{`BqJ?g;qYnh4T#U?H5#s(`A!sU~1h2{-8*&{13{CZExJ9cD5wmwpV6%fOdY z9)g^w_>b;}1_{tKhfwtPuJxJo%O_Ocs4fDbY5)BmVsX5i5L9np@{yxaUTN7*DkS=H z+vR_kuMk4-{2x>p7!x%p+-XpHJCnx!lRZd{21Gqc%Fse<-)IPnhO)AMla&Uu_-eJy ziWnmneeM89W^cR%Kal3sex9Mqq)}8(+W8Ecr0#ijI;uvvPwWkGv;IG9)RIMVUk>0v z1$fzWEhD;#V7?=d?ku$t6%q?n*I+R>y8Dz@S93G+bfma%YYYO>U;JO8@B#`86u6c{ zfT_keq{MoeH+Jg^IA8w(7J;IHpBJU^yS$9e{}DJI*x_C&fB7Ding@;nX2z9c-(ZRA z)K6LBd=DM8$}^OFD#Hd|={)pQPovrAaVvB>vrO!qQ{|ZR<{8&Djt};MG=@onA%&&h zIGHp3SDz|z#$;Qb6VL!ry8z=D&A@nrHKWk%n$@S1g%RBpSKpWnHZ{nHyOeKW111Z~ zO-2EBL0W9~3!LROEAz}%(f0%A+g$q=mHUfsy$O6jOv&Tnmy!1ZFDI(>TMP9YDScZK z?6HsjLIv~Qk$m}l>*bF6(`*Sl{=@~0TNRtdK!qw-9cqK0E`n7acu6~q&o-VdFf4;y zEEOzMZSejB1&TT9azPM`op#PH{1O1LQ9c(!VAGOaKpZYpqL}(16f&c~+1*fi2(~DQ z={$aUspjc$(y>w9b($y5Ll?8qZ53cjzDC0~787`S9#U2%6_8aYc6i=Y*x9q1XZTVM z2orEywPsW4WS8}=Ob!{sX_)TWvYCJ^;GzT2_rbh8q?`ZeW>L)3(fm&IuO;jYP_7BJ z0&On0j;ITqTp9B3HHb*CaGmak=ga%yu7cv?8Y!c5;kn(u2*^+X}_cWV_(6DY)Nn7n5QO0!2+&WH?m!@ zMir-X>36}ZF)Du4k*1+j% z00iJ4^?NExxPu*)+2=titv50jEO&44JZPC1k9*$RPYU;E3>Fg2AHzxpXWL|cnse`V zX-CmjV;@CPZVGli=fJ}mzd*~byv_V|jtK`K2g~BDl zzGBzITDAuMRoeyvH1knWR2kVI?|62y$_BIl@JiNk(HGHKQV*zoo~B$1Aqh^f(DYQn z@nhL;$78&{A4>U#&WwSG3|8+#X$U>=2C-Mc`!!Hn5daU2X7VLvWUaNrY#b3t>{OZ` zh-%sgm?KN~F1{Z(D62{PW(xKBweEqJLlYYUe3NCTZ84o-6CzR1Q{V5{y_sY7C7F9E zO98*aZ=XQ@Z-@^UKM_Z8=3b--%YpN2!@|z7EH7(`$Z_p+8y|L zZWounD_MpKwbS9G!f}X}Iv`iZe-{L&pZOBiG~VYi%ub(wzx=_yMyAgUDvR+C;S5v8 z%>wG$XTN_a|9NLy5ClDted>H;9;7c05177092B0$-`R+5egYi4S>qZmy&x$It=fx=;57$J{lvy z1i%#X!nWkHcWIZ3BrK%d9K=v?6SZZ`Kbg`#3%Htj+fo~6{{Xy`U`;C-99#&Ssot#= zCbo#Js6*IlyHETm1@pGo`*K9+IO7j3P0H_ZFiH%um=t=`yTkG%5L^w$<_u_;JzyVt zAyL(f!+UGr?yNUocXB75)Y{wjjue04a+FXolMbVsxDH;JG42+Qnby{RvGCI7O?;s5 zP(_*FO|ti=vj=q2jq<z85-T2>DF5P6RI8;n|YU&FN+ce zrq2S+hw8z~^@OgHD=3CCT#DrAlL{!!fB0FN3RIsW9KS3ksit7BRz8~hJ#;mXL#JLJ z{9mhiID4-@4R_JbH4}e}@C4*o099M%KzQV0RM?)pHZY~g?ULmS{)&1*KH+m1!l%}U z8j=~QVP;tb$E6;mrwGrBW+bdbb~-prV+jTAXz3imC0|Om4wnfquZmN5`+|~gO0X@m z_rc_s*Q*eTS{b-#7)|Np74M~;guX@mN&@3U*vIJlgTz*`LywM$Y9hGjL4j78fQW~pbf|bkia-Z*4)(g#FMt%p@!_1dxKqDfCh6aRjg2ujZPZB4} z$CbZCFX}zeSi}I>eD>57sCG+y-cqEBM0q0u5l$ zVwXxR2~JXa%;$7+HEO*qwJxt8%ebpdC=bUt_#)Y%-(b`prU#w3M|m|_NNdRHhf!Rx zvb<$hKb%kW9^_So_7t9)`9*yKlp^4bc8zMu6bRpS6$7h+105z>Dc+OHb}FhZnnehi zIujgoz7R!-yYQK9E$>g@1dYE%kyNTnvrW7k$`*{qu(_6DR%z~pV!<$V9WolSnx4A) z@tH=$&a8VqiBG9xeuZRZtV`GxF)3EucoVu3f;5M1ndseV_%g%|{H0JBUswJJ36hjQ zjEfH@603lA9lv7GW+ih9cB2+)_5+aMRZwLZ#Q@6gV^-xUl&81+WMWL z(4=}~Q{IKRt2!DN)SzB3{SGs8gs4snTi#Fz5|voD2pqX9y;G*|djkn-?|^=LViAXr zfCqee!7P@%&yNWCRS5DK7`^tXCSUth_di%M&7Npd6Q^`hZ5PcqBMYtoK_8#EPxc&| zs41my$~8#Sj2YDH0YRJ@%!a>w2|gSl z6bKVvpi5G`JxqJNGSj!`Ke-J8;I4;PYN8RLG(C;{3@~so*|u$utjIye+fOoDP{w%s6yQ-G3I&W zLRVEQnvw9WisznK#=-B zheSqT$Y~wF9|g|FWp!DxkfC0ZAO@K2ao5o}v_gqAo?Xm*O-kep&9Jf$2d4%K-U>Ay zIvBv)N&c6w6OhZhE`<0iHw1s3>rObCauMqd?ehsK?!Zd;(P%L=JnUv3RP=mNDmakY z_i)6^{vf6Jv~x?=@fX0+a8NGK&=s8085B=l?rXiCL37%2lXIeWq;WBAei?_!0_R}y zc4D^H^>t#hwi4QBIPRF&(BIOO;!4uqW)J-$|00YO%jX65$4JV*+4b_`uNNh-WF+I5 zv8iu82NfM1+)4%Vb)*R+ok$#rGyLjmTxvRFpb#N+Wl1~q*B15H(oy&0KJZk^&sRGl|&kc8FEN;zHcB?uffW5Zy|nyQUO9V;)|E-LF~8D ztLYbe3!24a`a)stCC0chWI>5@rUI)NS)8X8O(nJ;Y4=qO%L?T2YopDr;v1$`MlQ_k zA61&F*Syaz>PN&i_*`SaU<{Fob5HxpBQ6vzYx~e@kr6J7vISE&_^;Ivxh!W~`bDpV zGn)a_m9rB~I8HW?N?Lmvbi}X5JJ?7uV~cRL0ubw87*eQND4Gc43={WL^Cx7MXJsJ* zstB87l0@*a~{1TT#+BkO-;F$c8Arxj=XP>5dajb8`-7;=gxVJ_0yo7w{nV@Eux zqpoTiw9e^LQn^lEx^fBgbJM~$`Vq#nRw!Bkw_dQR039wSDN&bzi4B@ew zdJ2rx@QwU@_JNuGk;2St5D9U~pWOT=M$gKmRW3iA#6Rq4J$IJ-tqK0PW}AWmHSw~R zRg+V68iK`~n)cat>;}xofG0?^aDMh8GMAF={kd_)9Qgi87hPYq+7hy~b4)B8I(!7y zrI&h@$(=Tuu@Sp3Ty4BvgGp+sXNkvju9spjF3(bF49Ze@yx+3r2YG`h4SAH24gVX! zpI`$6-VwMnNJ`Jo(4e;ov~|f`b$Y}Hh(R*KW-7xdHW&WI4^DAyth}wpNtFslt5dc7R~I4e+Wc_Cw51rBD^P**|G7yyR*-=^EZI|Dgs=aJT1tw!&h7o@B!!*n(4;g zg}wg%(4kgxWU2D=X0Dnjf(!eSeS#I>N^4+2CNcbARG;e#vU!rvXuu=GkCkYZb&%`}NAp&+ zI7M>07-*+V`vt!#7*XZsW(I$q#oIGEpauWhx-Tg25Ot*sW8@0>g%3GOpdX>LJC8$z z$x~guf2HB3flteFpbNv*_f(U|V^06ZtLD_N*gw}(aPRs$ci9uC4N58m+|$zO5T6y1 z%KXv7kfZ!T%?%^~NKCMBH@HT62$?^cD$&xCY`@EQ)MV-tUiLyN>y1TH;JP3n^`&h9 z5gaD^bOV^IFrem9sydJ5J=j2m&e^>$r>Xejwpa?;qQO6?IVy@hyD8I4W>~T4;I{Im zjTH;N&R++``b*xX9aON{8^^+l^3Ay^z`#f^BfyAZCip!8C+hkcX&`O<4mu>a#1E2A zkuf&ZD4gwRTQO^IUB(m#ru_ithuj?D_(Q$^X`0bBx*4qvA78eQcy7nL1rQV`h46ux zgutwP?tK=I;D0iE+seM*ql9gbYBkYR5*g?d`@)~2F$?C2{ zQQ73)=j4-{{NN8QCol$~4yF60;!`0LpjNVyCuo(7-WVAfx0pcTmCRqCY;vj&tMZK8 z2}QsiVBFS1S*Q>B4YbVHReW(HW-&IjCjz1v+6hSms2)mn$7nq#r{HHPyrttpqDZg& zFDSrJEP^2QbGuf3r?1Dt5Ge+U8m^QRz=JwLFZ#E8?Oh{8u0c_raZj zGn$ZYyZ{7V$c%zUY7R$H=Fw7lZpZoe?)vIPo&oMw)YAdHi1TqynVhOo5w-&fVnZ1L*g5IHhB$ z2Im%_{|riJOUWE!gmqHCjf6>Bph*y#8Ut<2Eg#`9Y;XxGvM3InxgXv^S_8@>%5*8E z4h<{@PPOqU2{PeQR(S>C;;s`9DDP|XoTtsP2J!^$zA4mNhzhLURlDfVrwRN#tO`Du zYqRsp6Ycz}ytT2prg~Fsti&U@vDwZ+ws+ON_Xk+AYoC{A&|w$L^rFk?u?zB5dz(7| z1UPk|5sYq3=Up*~kv*g()e-;h!7C|o=SZLhWhx+!0pD1%Iod_*#|A$CW{kAf>J7@^Y@2O1n!CLm<;)AY zD;E%e>J8g}j5dH0!5%KMDhXp-e}VVKnb4sqXrAiB)D)eapxwm`H7gbUnb#h;db}Xz zTgCjU$ZIXviV#eDz{!c$sO2Z^Zl%ney7tX$>J<+(EI&Gdt)cz!<&$U>x0bZM-6ZfT zD`Uwtx+j(eL|>-ddHs*VW(&paS{n_VwgB^czQ!ck$$^|vQ-#3G9kQt|@cg^` z<72ya%NDVprh4kLzyKc=mp{nKgunB5?ny{>^l)OKMdO>~(cdF|^Mg}-1zPEm*t>-Y zK>)nEFjdq!SbD7#car=^lLR&Fu~Zg3k2s$N6?SIM@@r!a_)QC$w{Cji;o^C&{2BO@ z8D9N!pKE}NV}+a=8oe$ciCbP@A0U`_`ZSlJQCIj7JBv5>|Fu&*S6M07Sr4696z|Z< z>kwzy$+M3mBmMHaN0)-6n0x~B&6dC`=ADt;Vit=RxV$=g#Rta&bs6dYu4Zf)Z!P@A zMD|4gu!>(wX_AqCERpO^kP~P=2K0|l{MQC2R`31_fV>-+As1m#NEDX<`wdU4Tl>SW z@x<^D+sS@yLpgQ*2_+cr>I!(7c_9m*Y85t!v7}lM1po)90f}y|jpa7{$R|ehkMmY; zb~835u!r_!EK)gK9e4E}gT9c;{V|a*{ma(E=nqJ*<(i=2UU5ZO@<^C9{0%3mLI8%A z*6Qth6fxtI+COJp7PQ*NxIe0{NRS_%gcUo+AnLU-omAGIGo?8heB^zIBsYppc_(FpK9TS{>RGoqpNdCJ)MPO{Y$f%o2uejKZQC0*Yiv_X^@nSg$nrSH*r7{s*P}G+E?SlWHpdUP*bV%l8;DD-D zE3BnN2#ds?u597$Q4Qj_Roy@BN+9-JuQxNVDNlNX#N(Gfp{V7=E)cuMlGf;kE`DjO z3-Fzk{hE8?yb=s@JT|ka&Z*bSeDVqOerqvThZG&F5w+SszSqjVDiG^#I#2IaWtBTK~+t7 z#1!eS@yUF)j7=+?4;rNDDEzwJFPkB3{>J#q`U~n$WutMOdo_=#?H$-FiWysm2aln# zm!_W}w91d6{QcKy0IYwp=M1}_R-1Ozh(c^S>_#&X%i^YyB9-xi0TQjW?{>$ye2bH$ zayglHe{1VnI}`_1VV?#(S!pW%(`6m4SZx(w#Sat+Eq34}7!zA+zJ4Q!mRIr7jra;+ z11{>ulz!R0&^<@4N430pF86jOC@X_cn)5<<4Q*;gyA#$qZOD;PYvC2aTMA*QKKi$* zf>`sVGL`TiaS(WNp40OsupanmqK7c?-zU@VB@VQj?>G0an3oRBMsD^q_gVn^>A3l| zP{jEm7J0r&ErkE8jSl1@+o>JRg*K;>M+Qa=m(9^f;kt1-_4#Gc?_7FIhH-a40De9a zh+I3Xa+{o09k1lV|2rUnL}D8w<`(z+iPENbIweST0DtSBT6D5SN7IKi$(1=boe1Wv4+{-jvwXsNe1JD}+5ghO z{2ydFG3KPf5du$^_ZDuCmmgNY)z#dpoyFQlnrhCui3!BhuWyMApqtk>y_EdulEvPf z!_B1$3DN=X@edQ&UUfqhO)d>w;wd93vyua!>BEo-+Gy>pG$-x-sbBRoP7t$aAOtp-LaZZh#zVD ziCCc_yY_q*CXws1LkzaMmO+P?N7(@PuFL6PxANz#>)rev-4z6ihjS)L4GTISk5wE8 zdtw@+3Q)y=-wAv`vgeOP_|;%o&;j}IZmYO%vAQ0;*OC|5e#RxR;foiIkwKlsj^|SI zcx^_{HXN-F@C6Wc76?1BNA!%#HDSe|m}A%3&)o$OeV2K9q(H~9#GSg@cdj9s_-B|B zmd>nHf)m;;Z=Kn>Lk1xI4q}-f1@l1yBUlF`1FL4&%Wkf-cMAe{c*s+?xBml^VA25n zJnYUamnrZvt8l()P456OGu7r8Vz5Q{j_h5Sy z!3~YroFed=gaKnAegdxC2oDX8OY&r$EFxVbfYc4M9WdTY(zkhP;(=>%Fs@iiwea-f zNBegd!KCs9i}-2T2yq4&TOn=Dq}V>YU8r~%!iu|dscFc`D!_=5YoeiJ^V&zX744GH z5aT$9K8wKRBrH81hBJemV=AvX{9sBktx>FJx>2@O6$lLBh4- z;#_*gU@;RX3`3?WZ*MlMtIC1hsFTu`RO(Epl&6IM3(C^B&&!m$#w^i`WQ3Tfg27vk zLHZIhUWvmsLO~-ObX-377U`BU!nh0F;&r1sE>7G^n&sj`02!7G5+4zQt{LyI*uhmIH*1Em`atO$KCbL{OVpHeW%mQ-Qz?o8l)em z@|uAAV$2Y+?cWWat?{*Ku=_7nQ*Q?%!?EePYwmB&$EK!*dl98&MRd#9LE^$-;LLp$ z76mH(R;w~6_CyBm~)ZM=5Ni%0u82go_f zBRQEAO1RbD6~_|FO`~_&zdkw9XCSsQfJu8olNC+i!+)ZZ35eSn`=X|4OO%9X}6mL$WDjhWM0t#JKSrUVJe( z0Zsv6Hup|Z5)N#JPqEx&Ub;OVv9seCB?A8N0qe!Cls-{FP}Tw!E^^N_0K=j}e7^|* zR@Y-raFa8XJI?Y}4fgD`+J$boI>O_AwtwWWkc@oh-G4#9c#FgEx{Yh5-rol5od~F? zwID7DiFV3T`Shu`3umv$?j~)65~9~1Le3~{TCIW0^rLM7otLg08rcOS?@;V9u(1u$ z8_)Th+p8?bNZ{t7K@iLB%64$vV@`oPNb`qMx>ygk7wpx1h(-$5&@zCUgtsQbc*iSC zZKt6Owc*xHVM%CSk8d&Dpl|w*W4(IP3g`%1W+D2&^eYfN1Qr$4hJo{Q>B=wbtv!ia z2r?5i6sLW{DQ^AFQeEljM%}j@%e%r2VQK5{15O2HyM;*neM|U8FpmB4Mx5>Z8v%{C zL?00RX8t7-I1^k8X!`}inPkoPnv{#22v`;s?f+U?Rb^PscyIubpU=@XdA2nri-+JU zPpXo1BQ%5z1pr`JA$f@d21$URf4T>3?!A1t_{@q*CK1{}(1Z6JD4AtoxG1=-<6a`h?89N?}>l z<=9UM`Vc#tsXPfSqgDhTAz7mZxp2|}s@!}f0z=(XRW+zWrfmKuIV6*sxy4zLnMN@b z7z!(}n;!~{#i|IY&S9j8EqiJ9pJ$wxy!&MYDHHw=ont;@<=W&J5iv>$w=-=o#uh1& zh({*a$#NCQVs%dI3fQVuD}fqfbvcLd>_ha;G5l3Alq0$Ml5GmOzm6gcMEXWJK1MEW z%a#bT*h*;o;nYK>X9J!g*X(S_z0~h0HOlRo#PHa*vMgR*@Be zd+R*=PN=?K4}v;T;YXg)>i_6A1C?jqE|Gdd_dG`_&p!xzPac;55ic7IdEOICN1ryR zL}TFr9xDWkN=kW_W-ziKFX(?~UsYE?C2iqnnxp)R|y#EwKy{ql4t|qvp?q zIzIACI&E=65sHVlbs%v0uVlH`7btw_FfdzX`TZjaNJUZ!-?M0$9U(OKLj0MtiWOqryf2L?iB@iW=#^;ENlwkmd8$ZKOq;h8$GG;vICbs zIVZeo9#MY4QjyLByQokakeDZ<1ZxnU+tcAi{2Y?yOYpgAzQF5m&=ud61)Nj`go*TxCvWFt-isxDA)VQVDWqTyw{1YRh{`(oR!^M z*KbqxhP2L7z5jGAM`8@fV+MV}@DLT}z~Py5MNz%lQ*X*jFK>Hil5M^g9+q zn&xTxf*;Ca-ia5d07L|hUDI6^yQF1&ZJfESkhl_rxy31eY6Bh(QU6}@n$1bmSfm&% zTholfO(6<(+(%wXmxR_xQuOu-ULn!{m)Z};vn=g*RtsJ?Ks6=*Y4ijHO*FaR1`_Y%0&NHtDIDsvE+ck(MxqLvGPxg|(|KAlw z?Yki+Rc<8UJ7&aP*|&rX&N}FHu|>+kLdepTO!Je_yBX7`ism<$6%IR*hv?MJK}VxG;jyAPPf%hh!L^DW!UpX z7OyQL1kUCMukR=dL)(Lu?dhf8?5`AO#NEL$XKETl>rYtPC%Y|2dfQrbJj~w?XhHzm$Y&PINcoCUB6bp>JURZb3U@ZAR^;0j&ODwQj9e@seU|YD zTsS=lxWn+-9Zjx>CYl#`Fuilr7#yhX%ioqTyG)^)O48Df$LLw=)xxwA`!6yb` zGs%5dYn;S9DZ90rfKJ)GeNQcb*NVi8L~!vIYksKdsk{|!Mx5U$-Oub9SxOfe5&!Dz zi+N|kg9Az$%jUXj{HimT_mh%^+!)d>Was?AVwW82!t(j3@GA!+S4J6tP>3NQ@s z5A2Q~mo99}4i4_g00752+U%32l7SYUl?~C))$x-W1b^OyEA;c}vs;Jcych(1zO*Kp zWLco_q9DiRv_5k0^1M4?Fv%C)XL)z&ZzU&MvFw@%=}4l&5&yWhGj+t6`B@;I7ZTj) zF77bi5LA=L!+fTva5E2u+x53EZqMA}aFKFha5Q?)R`M0<-d^2Ne}hx-tM& zPXbXyb@5jH4fY0KDFZH#tP97r49Z_s+pFxLbMN^3g0>6<*QSz}3fR2OYYjw=WO-P%@%mR-ez#xb-EV3;QLIBP;}_f42Meh$VjjJYBXWyZk|$X04$~_N z+;JAvETggtxHBB{gU`k>Z*y~AnR-+TFv^lVxvDGXBJ+~G`*MsbcJY@K0XuZFM;ir` zX)J87yjVV0a1&v#piJT?Yb4(Z{TA0OT+{14QF4vhK~pwGOO66^5$pv$im}#xc7Ovo1EO>^ zl7P;}IlC0at8pnbikC2ecuA#2%6n*$k4|1KbRG_XZXrs>5U$TL?<^xD#p#}0FGtlc7p6Wf!?|@Svp`=XSUtIBru^`%ng?U+Lsrmz095b!&6?UL(ojI2=34`RKL+ z`Z4q5MtI14n!v8Koh|nEdFW7iyhIMI90|Se_Ph0*2*ElyQd?ZBF~OwfWgYt6==)pD z3d5N~=seC8Den#AISSLLv-}QV6|lmWQZ(_AG61a#0JvJYxdKG{9e(}9F|supy;F+p zfXt_-WMM#NAig@O-=+aedE}qZ6pQeUvWT=LzeIiZ3#y#iq7f zmK7U;zfBe~Mw3vV51u8#LrXq3kdq)SH=kb728V}ljD-pkPMHsu=ZCdVEzg<0nAe|R zojwo@$qnEhyS752=IU(?J^t6LY@$>dU7K6I&mXN7`?vhOmuHmE^uuE(l6v+sP$~|< z5%*-gq#T70{PZc>%NgTxW)?WLKeE^;))JrP04AnOATMc7$s^6FtnCfla)$;g8L5gR zM6zqEzl(<~W?I}5if8N5j?IouI{b0cFG0^8CDfqzbxsQg&!6Be(OUzzTC0MAfj}qz z@vN&Hf*AumKl>WPn=O5$FlY!6JG;3z=aRf6gNgZn;6_vLLEr~^NB-=(OPF%xEi2zkL^x;JSe}f~fudFPLcNS%E^RO7 zW2zAZ9b#)4W2gi3bVst1FqGFVo`(7e5Lu;`0vkV)g907gTFN19If??0}Rply%`qKXxT|1y;wn!?`;{>HQ# zH(m%hO|Hfo{?4AMwDf3YWZ}-qeW%Te{baim48cpJEmBg)Wq{5`#YKWbUjnbUI4uLd z4@T~?4ry>FlV%k_$I_kfw0}r$<@*a?bI6`6^fkkl2GU+n*lj8>wPKRxPmTe5Tzu*e z({NR^Lq{~w!{Y5(;ZzT#A!)Q;qz_YM`+j40Hj4YS&{AS$YX$;7N$>{)Skc|9;pf!j zSfGO~}W(4H$j(C8Yppk8b?^uFvt9$|TAAZ|z&rQe;kq6LyyLgL+@? zRhQJazHm0|4R|X4wRjl#py&c|eDz~6Xv-o-gB6J8S@-KPOnl>mrG7wgulX(z#4}m^ zBw)K`VS+K~rAWM&<}DQzoQP;K!2(ifO6_wiW3d6A!>r=IV?xM<`}2awI*6d*J| z+Jhm`O=Qe|sg3?P53UrJ0J#vJh4$uet4yP zALSANgPPPrS8tA{S#eBI`ne{eE5`%3qN6#Um6fU$DNXi$Jx1DcwY+D za~zPA0U=0am^rbanezeCD3f+UDBSc)n7Q9 z<{G+NmLBXOR&g#aH|2kX%zE7EMWNsZ!VOv%t|85`{bmkqS=KjKBlcg-VdDQ?xhfYG z#W<7{wRC;N0E$OXKdc+ZRQiQa*v1I!SW}+DoGuLY%mQFtdXOiIl8|HNF*1!dT5Bud z+i(&E`<${=Z)mH0neT%5vX1}Po%ETFOqvv`!IY^tqOhG4Pd9fot6H}4!p_fgw<3m0 z^@GD^wON<<$8`9u10jkYEp8;qRzDT|2k7JV9JBAnUH zoP_kX14Et!9_;|b4?h5t`g{qBwg@R9cchVNcKqPM)X}rfIW$Jyjvje9z)G>Qlh{Y3 zlQ6zN-mPSI5JxNYsr(eYod73dnJXr&_%BCx(A6#8K|HR z)hEmOs`=5knK~1Uz?Wt&+_)Po8cgfXCQJ6%EvcgU)s78cAraiJ$LIKRvw%xAQRwGO z+BygXjU5+e;7Vl@(6?=Lmwdhf+T=f^H6!g3l9tkMqvQd!C7LR8_bDKGodG_)o>7wF zbKeTxMINa0vv`Ojl+`JZXLb&k_dt#2wE%iuCIucm(7g~t?XdTiJ4owg^FzwT2Q zVp?$B>kFE17F-kt;3rziqGkX>tJ$|elor#aCG~wvxgs{OL2`77r}+`dqP%Y^4?Ku0jqF@}UcmrpyU?as#5VeuB2vuyjok)T zKk#^tKUmcSWTL*jQi9MX7bwR8Pa)^jqzMV)-Uba}xHMWhcK``p|JoL5eh%#yg}63TK|V`Z|v@tqS)4>eE70?GB>bO?MV1 zSGxG zm(B>)*wDwzokGcjgsx?3Bn}N1T6PgMRzJiHC$Rig5iW3zhr{E%ByTN`SZb4_R29K+ zSX@w*IzOf_Fq4AZ02B+Xbq{#-d|Fp?px@|LX$_J=vJ`iil*0+jKU5NJ?+i~r)s&d% z#IGGesn2?xEl?DDi=xO)XI{{$m?9F&=34!S|myH?awQk>UQkg9cWivfu}&kg%CCsQDPf9(U3%ffF@lF%vj+FDNW-9Y)aHmJYFd zvBn6!D+Zg2-iwFAVh{?v5h1SFr)WpCf0t~Yu+)|ODM55%0wqhk%e^hPtU$C=a$pHA z-(f}+N=3b_fil2YWr19d&BjfeYUXGa2OI6j)qD0RxrF*)40h`R)AcfX=l=sS8~`~a z2KCkPx~C6n7w^S-9;D(u)~zQEj(&9!0jY{>23tG`br5vyBJfPN%oP_=DPCQ!m@CO* zl@!YSu?y4rQ zly`~hc7{sV3y>NB5G=dfLGJPO5=wf^lz=vU@PpfqArNklF&MX$TFeXZlRDvKti-p` z9JXk39i|qhQkf2v#~v#MFFao-q~?6Ndm(dc!#S?`4l6h+al7yuzFVX1db|$T&m?-ZK4gpHyvYI zSwAOcOoxIhu2^szc!s%1rVrw>&>vAPSfm)2rnI=!h%o&HSo7gEF~0{oOlFjvH}=~S zc5kWzuc;r@6+_L2|MHOa+|NcAa!(8|K*Oaf7Wd{TI~|13a`hP$B4qwY2f6FIT$S@$ zq_{g%QYsN`Qm)?IoB4nS#hA8Rd%ypf!=OQvs+RzIqks-Exob2U*}Sc1&7uqR> ztR8mt2D1LRomZG8t)1DUw#k9|4%3 zP<-2hE4mn{i9lRWw-)BRHCUkkGadzFb~qyL&;lk^FJZ(KLKfI_<`YZV7ru(7SfnlY z(se!9A@xt1%=QLh#g*b5Rec$S{CicW1xedMxdml?>^SFnTB_{iQ0%q{p_ETA?~e!; z>Wq*8KJ8iK$HDA*-pdIWJ7v>_=);x_m^*6xC_h#?+IfeUuPJj~0JtLrN!qCJ5%LKF zuG^!QYzw_UB25@7r`8@=4X?bZ@lxE@*N}gP-QOguSID@}y**3v|nQQe);kLZ^sr`1JdR=3+?%*#7{MgyfKE#gcg;$|qpWSGyD*?98ms zejOrAm?9d7(dV&L#!RQLXeYpm?fJY_d@{EZ;w&fzH3A`)=@n?0zD*Sjk~8qIzFwws z5Xl@*&zx?`p4j{byRve9q9}E^tzt1=Na+<{Cg9r0O9QkeeuxeE-2bBdzR{qb@<}K< zh|x1NQ!H9yz2N{il;0#01;l1ln`Z_kjn zex_6DxR)EuB2=xg{%h94*_dGlGY81MQz0# zWv9KL#;%zP1a@LWqIRdBvq2;h&j|Osfov1%C3!rWt#H1O>$@@LdBDe1bN1$IDo4U> z?fuNyN?hv%T3Mh>5>Sd!M`j;kiWvm0Q59rOZAVDV{D2@25IjG&mC_AfB05&G@y&J; zZWM=y7!Vut*UfDWyNs8C&*T*z%AFZa_w_+Fb1{Nb2 z@{{Bo8d2@J(jeh3voEB8Qc9a&&!}vY!Y!~17bUc zHRlQ7=B(|lwSlnDhSn}t0)+Ko0r>}0Z)Cpa>aGQm3MO}7e|#uDNSXuE7VFc3K1~hk zNLYv0l%2di<@UFyXHgzaYz9|B%(pJ}Y!?k_ig`lt+R5L7+0atP;>+ ziuf4Td{?}CqU9hf%*I2^&0e26<7_X9hh(x;>->2UVF3aHaWu;pZ3=93ar*N`;-Vwp z4iuiHdI~brHdb4qHHb3p-<^zh(BMGGcbq|h+#Ul=dk^Z45tCk9G^5>K9bYC&o|q0J z?Wt)_LDoKItDg#HOL*{l=-@p_graoCfm{X8KhlGRN|X^Ru9s3&cG+jb1JYE1Mrtcp zHTl}*dRQI_{6%JY$yTkx_c0U_X#W|_($NGeWP z3gm#0&xw6HT>230J7m7F-h|PgWw=D$H?HIjt{?S+zxIF{#LP8Ick=kKJV0*MCFVP! z=ZgH(!hi^ZhIM5kr(IDjvn+*9ElgpPx~SDSu2k0EQ%!2h3DpxxXT%I#7E-Dc`f3Wu zMY9%f;SD;E@TQ#DLoIVpu3h6NoEHe&0GQqYmk_;$Sc&Y)_s?PTF2`n8%rkQMg?S8; zEFFzgv9*nWQ>>2Avk&=sL!;}+uQ6CP{WzVZ!5w5QECnxqW3M0 z(ND&P4v0T)>25$OLC6s+dByLvTeObxRTzuB6U!bLwogC$rKR9 zNKfa7C8+2VWPsqOU`7Or%tF`fMsOyVLFtP2h{aPd9gox0@ zJv@T#oVcAn;bfaBf7p==@He-ms}i8J&5H)8FoW##w<0LID-(h^-WBr0(rWpIpZ#T!Cs-Yq4u zQB>(7*<4WlP4stpR5t|cr~?-c8O}b`8saT!<;yOz_4Hpb9<(ODs|9&XhJ4(pN-9yi zU{)KF$=GR*F)b2f|0?3ZOB2J5DX)_rh6ai%P0&VIF7_9->wUe#&C4rtxwPyIFm4-o z&V``rrFH-cEdZ(gp8a`@P^nCfx9(LT!2Rn`E_pZtXKx6_Tp7QL%In@J`SNk8@FIy4 z!`ca0+!o2le}Cg2-n~3wy5c>%eaHhGn5Zu><6N2O1ljj>sMK9L=%?d^N*eox)J6m}Gcd3_X1k_;4HRC=7}Mv)_?rwqL3!r~XKFjz-Ed@@B`EJ*|>eu4=V(@Fr5O7E<-Bo(4>e^cpCq_z3+2N|IHKU zLUrs@e(R)O9by1Bo&uz93e?w1e0dPG6NJXAyNrzEnrS9beR-v?&`ecj;|3V;<{kO0 z^ox*}-p!Qq{5g!+7f&eJD$*AqgB8y*ZNx64D5PfN>YR8k4$0Dh3f=6&#`>zM-WC`GqE-;XGC2~AEtt(?B(7Kln(#M|cT<=kEmnT`sw(eP;O zuu+CT+?c&`r$iACAaM~jC2W^LscmR2aHr-+WqA?JL5uLm0%0lyat=;6fRe8g#L6a5 z^d|qJ{GbTsRdLkVJaseV*3keaQT_UBzvBI-OP zB&8LeN(2EihmNnq#BxIc8o?h8*Wfh0Pl8}k?gVe`cPYINLfu#~xxZfwq5bwhCOZ}~ zn?hQKeRyoKuq0(%;w-+)zNeYgEe%_JiR4(AXO8?Jkz>dU3HDsm>ORZsAIK6(6n}>} z8b=maj*pwK=CB2P55?kYn3Du^&o!zfDIW7V>{*d3v{>ciH_#JZ^!^N{Qqvuet61i8 z!~{c8%iFQX%!Vy;#*XV7U+6-%yp8$IirL?mg~V^QLHlfao!1B?&e@=bHY!5kDn!9B z)297EXyF23`N^lwN$iYWIm1jBU`K(9sm6KK$*pCW7m5TA4pofu;F-3c3=?pGGC7w_ zIU&;OpNS1s@|0w(p1iVuA;3-@gxMH|x-5i2>D~B< zPn3aq>20%`&%Ac}IIjOJuQ;u^92mpdeQ^m&D|DS@mG#1|Be>W7mu&HAT!jE+w~j0Y z;dDgO#${Nir}sSd!Q({j1EXELOCAG8H`nW%2*ZEHU1ZGnrO1UIK-y*DGO3Kw0!(94 z;XV6-7GEA2SiinHb-KNpbI29hYP8>JoKfc&VKH^5nqaDE{A2>ugu5Jan#vBb^G|ZBBM5g2Ykh_i? zFhud!CMR5`Kvo$=+jMZei(RxVNtqs(Bapx)b|E7W?*Nab!pT=|KI44IxWsItB)NL9 z+}{HapbQvU9CN~^!p1?w?|1_%5aYBuYrHji)=J^<`bY*dKU5%-aeMQW7!E)cghCz1 zAy5jap*O9sjN9J+)30yW2))vRaT{eBFtEVGT`8=J9-l81@*yKq90OVVqzH374k8gt zQQ-MomZZ}HKeOr~iklxiHVz`?ss*T%s|=jm!A@c)i?8Xlu4tl?zjGOt`&15$)TdY| zz>4PMIxP_9Tp3^W*h3p%6nJ#Kfi`va`r)@|9&|%=OZmdh%Z$5-Iz|wSkNO9E(sKyq z>p1$LOHGgtewdw3^Z=7dC_bN)JS^q45JDUG`NUvrU_7-fQn@Znp~PB-U=GC*+CJC4SVyro|6!`Fs5D z^&?+9pbyv4Rz0w~VvaJ>7%m1EPxJk@v2n4T^JuHdDkavF6_CBWG6VSzC8+e2O*G_PVy1W2Cx##3Qs_nj%;Tg#8k_3=mWttCH z^S5}650?Q5cy$_BWCm8`Yjk;gY%`TBfcqhxGeS^`nCx4@AbFtNyloLrE3yg@Ce#IV9F~EPm3vPrh|r-4F{;6ZEqG~ z*t2CL?!N}cAjk2^+g_0rPBl)vKT9QtLl8B(Ob1+bl^MUBWK+xE^{Ele-CY%wEez7> zE8@#iAucq@X2d+Rbr}B1`d%f-g`UJI@kB~d7=s@d1mIT@j5@8Ny^0nA=rBh{FM_IQ z;I;O$KwTvL&IdB-ddi}hvXA@_o%LNCdeIARs66@`EE;(+$7?9EvW|x6xtS@Gg~H3Ji8ErhvYq} zw^q?MWK>tJY$2{A=7O&By7YLy56yl`NzrL8SLzK-`5QDLJQ!6Y+$~wkJIebRqj&gX zT&lzgh^s3)@RB1R&)zUBzZjNNBMl|r_uWSeOn?~0j zddNEnb;SZ*q6NDC0J?p;qIUpir$4ANRTnm$eRu)!)*SE4Bw)|4=^nzw+2y?=ybZ*q z-J@_?jCqM|?Awu^`aux0YTi#89!U5>oG)&+o{|@yXV(N;8+9aPbU=j>omNhI)p-dP zSn0{3x2@fiqcsa5gxudR%}PpaWv$jojKp`rKpq0+(x&kwmv81pDtlrhZh`vsY{jh# zt#dMoINc2+IxNqS0Rzid(mc9Uj^a+WZPq@PDg~0 zxbOge-21rHH9@H^yD8|l7#cd_*p=|*pC*{*WfMmN^TMy{dkG#@hfE+Zf{;W6>H!o% zy7OdgQ0mF~Sac{KUVc6*cyK2`i}RFY>L6ccF6OU1A)$PJF#K!TY*j;Jq80*8LjZEH zhz45;lkkd{=WV6C6Oj_lrXZ;0(dncgepYKElBB#Zj=WwU0gBts0EQUi-un!NVXBQS zl)Px=Noc2Fa2-;#U%i%@SnG1#-e`HTq%>$Z=Qmc$o> ze6nDa6TtG}7I2+reuI4`1g~_IS=AkGjkOm(58=p09@Z{)2bk<{xnrTnO%-@iB!mG1`Mm^PC=>dyc8Ufx)pVcZz$UjwKvHINIzJCmh}z(s=$St`W_sB& z!a#2MuO=2h!FapudOP$#o@WwM6+KNUtN#7iAJT}Fj_`4-ZlP-In=L0;(k(z!wS8O2 z4h(UCxNPNeRnJ&3Y?%`lIeTbOW&li5SmvWI5}B)#xrJQotUCow_0-~X(-Yv+!<{e% z@x#u!fy`fNsJjlnG3L2aBi+bq(Anjfb2__#;G0>sI7F}k5V0`iPDHVO_!*7KpwTq|l{3)sfCfVG<8wvjg@y+cVwK7>_is& zq22@o#F@4#AB52h6i5GA?qXs8+-Bo~ZmFzq-MlK`l8Df?Jm3cX_(v<5y_YQ+n1@kt zn`i=Ax7!F%0J;@4sj}s+OEKq}`z;i(lRfaIk6DMrqSxdIwFjR! zuGJf5JU1@eY^_~%hv)SARqiP>@X{D;vAE=Y?}Y&UhIe~*wU5@z7?=zbVmuDYRL#d` zgpzSmGSI!&5jSDOevDYEEj!%kiM-AHrqvHi<{hy>IZXs~f~Qi&IEeac>IvOE*T3l2aiHKL$RP=UC{RJ(mZ zJGP2@lbsfQc~=-t!ul|7c6Ijz0H3?mn;<#vNJ)oS>M{gXl&Jv21Q@T(@+3(=mPgt1 z%Y_hkd2dcsls%4^p914w^=+lS7K6%Bw2FFp4Heqh5q#mo`sZHyI;u3hMotC1x>f|S zlajGRCKrK%&up`er8}v|9`N6-nG{;q5d87((UQS+O=)Z;Qy0o<2RJq~f0q@}AeLUS zAhjuSG^Ta|JyB`SzsYxS<5#RiUXs3R$h_-2$32O}x!?cmrOYi#W;zW^)#bCO{@o!) zFjw)P?+^3onms8=E0?qwNCh`?Vy!D2Aq#&B!?uW=X0+&z)IJ!q8g-#zc;>rD-`TJl zy?JKMX)>@YlL_*#Le>Ue*ja20Ra`xv8zdnZ4P?-SnWYuINB{*hoeHs-lX&}ku^yXS zSYXlg{Z^4s>tD{Bkc9r@lIy0MUJW6W#XDcBjoA(7D7+~9gUZ$f&Yw-=pwusDk{t;H zE`4-#27oDGqg7c7CmRP{wgeg&jaORiVNMs7RHzxg`gAm$B18n%@C179GvUD(J$)ya z!vdxzM1)l_846eh!&)#}$K>#R(SQ;GgLW#{q*)eI=Z2Cs87myo7UOexb<|(jjVgoI zA|W;GnNj2>epEu6e z6afbu!XY2oEXq5KzzPnLVp3s&isfz5X>`*5C=8d~L8TMJhxdlH0WuJtJ1KZIr8uK0 zIul$eGw4MWfc^&p3@%z@T<^cPuJ(j{L+*-e6LtvF85Dl)zn@U@-Q4teaFBKrcL;^& z0S=ps*I5Ha@r* z1ZYp*I%ANtIF|>@>VBDHSTE=2f#GX)*Xj{E@5{zJk)2uXWiL|34y8xoI!g=gEDhJ-V@^m{;k6)M}?G^y{wfQm%?SP2?oF!+B&HbIw+RqQ?&S$u%Ihj%FLpbWkzC0+@IfdAO;FOg^ zvhw|S7w;(;X_g6$tpv$A@;kFP;d@l(Uz7@eJ)KMOn=l!IchxLLjTrj`B79`sC*Wki z780NBz=r`uf3wm>+PP_%){w7_ixB#cCyP@?XXW|N_AGQSSi2Ygppe_Bo-8W}#|K&R zplB4HwxfB>*EefPiyGuumOw2^0`?UTR;2wV|8Ct!du4oC;SBg z1G6Q$sXCc08_a_3>Y^tr?!(gH$PQ6b_=TMh6|wfGrJNUgV-8`pfm@ zI$XbXdW)C%;}6vEo+dw3zjbV7GaxrmEp^d)3?ym1QrTasBZC6i9WJk%&ygS#aj7O5 zMxyeX?8zD-N+TaZ81@EHUlXm8WD~67CEUd(#Q&wynkWevlshAMrXh_UIbmo0>Vl~* zD^Kvr5QFp5(B@6D9BAn>KNID{dM((dWP|+rt)>i3CFNNG`4hNh@b~u*=E{d703P`3 zbdvQYW16Qym%~<7NZ1NhM>1n1&3j+>@NHj$g+0~MHJDs+@lNhQCWtfhL zl{9!!@T8>S4i^S|92$r7CjbNY6(Ll-PfuY2F|a~jttWtNtbW~kT2GvXDpY%m5o_Js z-(`ADMNbbw%(MUVtE?3iz&?qSkFvbnH|>m@Y?ED96NN)se|QYFPvr2K0TL74kf z=v+mjOFB*km7WOCW$K>ZcZB-d)dF!%|oDSf4FW_fiZ6I(VFWy1|n3G#Zyo zBaYOoTZj~%!zF-@CW1T$6(@+INsYj(yUWEHk26Ymfth_t+bByBwVt_PNo2Gb6F$qy z<5~|5Qd!JRz~LgxQBhd96zNfBD%X{%IK0 zKeMk90jzi_BKK|ut^U%+6z5iX$C!-d>OxYAuN#j1F9S%|JC&@^=fb=6NP-hF9W}lYGZXYwo zP5e+m^KXv|DWoqv08cr%A|nREGbMObJL)8~7V#Nftr5;Yi1Q9FHO>}nLZ+hJazcqw z9A>jdejDTz=iv>KW?x8NWMxlCBh*I~W!KM{N-xR3ngGdrFl7RYCZGWETMnNlF?3KvEIAYTqj) z%g87@RBJ1-vcyU$qERW32`n76B0sEZG7uXWoSn`|h-JJq1hkU(Fg-Ked&GFR3K=G~ z(r~Wdgw6V})RfZAhPj_!(T1_8ukh z{pQIWUeef8K%sTTuNSQou+_8IY2KC22Ro=;aL*jJeFVE_WwAeTx-e0ipj0Ul!2i7a zuTvGby^e5;`4#U81=Ro_&g1lK)uJV2xPu4r$MECJFBmivcJjXnK9IKcGv+v?Udh_j z@|O6wGIAFUo|jq)uXBlgcV-0max2G_A5cW_PbDl12zh1~3XC-l`kNHkU)1Z8@Kz8H z^^hF_Iy|Et&m05)uP*&A^F#U(P2UOr;K`mtapRgE4i%PCdaHAedxWH1f;PqYn1MqO z*Xrr4GQPcrfw51VcuG=@1FbJH-!ozYUq)PjZP5b--|S*eFI{{(-NZSGOU}6!t1fsb zy_hJpJ~-xme4iio=5tPUExzFuM`v@zr$4+?N-_=s5Y{=z>T?THK@-3kr6y`d8aToh z``I&^ZD{`nY&&|L5zu`g2p~YbCwKn&cibesNxP_hq|6=j;jEz&yg#r_`unmoMJ)`? z0<9ad$^>#VVfE?VgnE0|IEZ1^7TXjQ4Tqgxsb(!rMY+iVYdz6YMF8lO25lr&{uJm- z@q8ZdVHCY;4yEVjQFen$8&OT&IA5SQ*o<>!ML7Qvtbf!u6h7eIXaiu*wDWqu!-nin z&$ey+ABD+~dZb&SifCmm)ImJjVePTZKA*G#DC!g#_+B9CmMA&)2UO9*`uV0eN?D;? zo>F@+ij(Z+EVCV|t;7YPlb53XN?g|h=@$u8XboV1mhLNK@lJNI;>T=-t6%SRTm~@f z7SZ0i&jMx(Xu$P&(xb0T{o`g2s?tb#gl>M_La#4AY5xryHOd7eIWFC!)){PRB~-3_ z!?&^qvMrVF)+<^$y?4PDdCgVqtl~X9FYnQODTnfl{{YuoaA;GrJO~g?R1eTr}xoq3-qPqrHkKQNXEQrZ+jCH21bLp~_avy7s@PY%egc>Qf)~r-Fb8L0_1$ zy6V@1o`nXAjSm{{NtoYx^`?2)sm}ZK8*lkwhi!|TutxhEd(SJSpnIqg;<%T0)EzC} zE5Ex^Vp06TbZRLh3&M?NYFLAz=T5+b1Q|jC;u??TI`&Yyd0tlx8bXTlT1A_4TOhOw zw`k{)oZqjU)9ER$NPbOIJ&Gf!w`=rj3UEmTc99W9-VZehI0c5nQ;9*SmV`apKId6? zJ@>-MtRQEy58#B2;}mH5ZG5i?9pG9nZ7TO&Z@rlcwH-@-{jJxrrFLAGzX3+A8X+6U z91$t#r*+cb2KO}MS39$FVwSIQ3Q`+;F6wC&ERydUeZJvj6KpJUb7wm+$#T=R;4T(K zCso}PmvZV0*lAGDN6B3J#62|5fMhHX3~k~|tEr!7STsfINoXCv9-jxIr{TxtO@b}$ z>yfx4W(CjtXML4|QF~w44Xw-zReJjHiRzj#N!C%mYuwFkuetDbvkMeom`3PPhDgAr z>F`byp)Az^2xr&M=r`pOvA{py@3wp^2p7Z^t4)y{oZKs7EP?QrmF5)N;cwATX(Jfc zIAwnzF5yf(VaM(iB3A|lLH2brG?4ux;aDl(6q%Vr)qOyI?-gLxo91y}udC=gu3d=b zP;i4O^IH228%LkO!BO{yl62XNy&oIpm{v+ls)XG!;=##o^G^CW#e5EDL^fr6zal%^ zTpKJ8JckQgAQ#@9zwNQyfC3txCa|62(a+2OLT!a0c1Y{T?0U+-AHhr1~8)Bz6s(FDZ$86*9_l?lfVqE*Jv4?wgXa!X;>%(FrD)y zvjHhUU>4#5v$IsvA?|6p)2~)enHFfY#og{B2XQ{dh9%cCE#UwNf>ja=yfLQ%S23;R z>TU|xq$&&M`1$P!{81_gJ(v*Bd&sCb28rSH26~xgkb^soG>wD-G+ZgvwT(*KC?R`= z#dd#{+->A0>IPIxmP9g3F2*FwNHh!tTN%bLtqTN7l6cmIo$?x? z8n~h^!5cK~k8pksYh~`wv1xm4=aWctz}|zbDYQus)y7W9qRB8!Xf3|goLh(8b5FCg z0Y!6jFt@&tcgchza!`2yb*`PQmXrd&W$pV0p#J_JlCb$bjM@Cm88z1Tx6IIA4(x{; zQTw#Gugg?34mN1>1e3tT>QuwiN_=(*aE@d*e_5PAxhMj1pd@Dvo98%k&yM&L?W`ZO zyv1$CCd2#;U0P{9%&kvCu}WS8{-8(1sd#W!QYit};ib-a7zKjpcJnB-658G(c~+N* z^Tp59aiZ)!XmQAcxuJ~{>^VTJTn$+I){~EGO|=ejYF1h~)brmPbAe(SU5kJhvRwe z!Gr<|HwwiLSzh6IwD_3nE;`YxRWp!SoGlhG0Ou6+h7;s3VkR_>5dF!JgV(SmX6nDJ zlTpzOG}n!udMmv9KCU}HVTgH)A;zogG)EM<|T!_nVtL1dJ8M;-4)|C|&3rfyX50Y58<3XMe?Hc^| zzQwOBUuj{}cFf-lNr>h%Js(iR1U(JWfTn#^7UO)46skzoPWeJSToAVvV#I(Y)C0ZW zF)PTANOd#ED-W{2!F0fcxm|8ml)nr)b&nWHZEvHSYgn^@(n0|dE=X0T%J>Cv+ZU)P z${@ts#~EbDbqw^t9z{$;#cdg^e3R^LX-v`F+BS{@WQ6$$4+XP;+xL+Ai~!Gz@zq>) zaWwkTo_Ht%_IMv95o;}Yc^;svYwQF%YVHA5b7O@KZi~eB1HjP`x$8WMyci+@i^r>= zy#Ml_DeKDExAeN~-S-LM1k4uh093WDyqonFrFMgU*=b!NB*fEL`^q(K{|3QjmcI%O2cqp1DKlhXuv%$xO! zBM!rN&SELYSiV6NISlxK|Ken-30F3&lsU;O+^7{7IfT|+=c$>sAyg%3Sr6p{G_}4^ z!L`Gh?y)%(-EL&ki!VZLiQQo!9cYE?cgb{~j|%f`)J3|lV#HXX!2;`nNJ)P zB>EZyBq!j=e0YvrQw-a!>w;d#5$FID$7Ux23SAY-0j`t5KcFQGQ=?%RV13D@ zjP>teb|g;qO5M9*-E1`EX>ux|DM*(KUR*DUIrvT3G8K`#QwO6C0uEg7AB2?EemN_3maaE}ZIwMf)kY`uT?P`}^!jl%{bU% zqeL~@#a1?DEz!_K4W+y~ae2UT)k6Q5E;~#Y;1m`#6pAjJI!_G8?G|1sjK>VV_UlOskmV>7F?P3don>Rw`LC7!8z1yH*U6FqeBH&v|!3lpx{2FYdnU-^`H{4Q2dr#tBc#rm&H!G__n7W}9= z|NRP?g<60E)a(q{7wG;42I^)b%hkqg;)tv_1>B+_?@yz%C>>(G#dnm1s4)EZC{B2S zhpf2E>H-sIz1dm$vzA6jprfCL)-A~WBHKj9vb z_F2eDa!L3L0zhJeJ`%72u_J~%oP6^{qQlY06TZL-B2AEmP_Spo4HLS$)Q-!RhmOMo zJ%L~f^h7GUwr6NuNOLwbe&|40`{M{7R+H!BxsJacpba1Ze1q!~k{T-av>MuLRGU~A zeQM?7D5xaL_?I1{K?n#I-0Ye#$%Ao%7TdaCvNV57CS13z6(yDxoVHkg=GEg2eHsQ> zX6I)pa~y4|2i&*VCR_BA?-YaBIZuSbI+YNbRI*PBLaeyxV=$Ng)*bp5^dl)Ks*2CK zUW%Sg8p9Y)jUhQjwCe~Lg{O{{&w2r?H~){%hIXISVB6~+u}QcA+(0<<=eCYy<&8f6 z&!T#%YJB@iu_J<~Hpv+cne(dtpnv+Chi;W$AXUS?Z&~6J271kl&H~4BJhjvlu08`2 z1K)h>OjbM@)WrPoow3z2NfHFU)B6fCU8X42(~W`@V#W0o_08eUz;Yd{xBduB3=ACu z%b?bRAKe*Z4-aY$UNn|BDgIM6h>b`j9F@ft)Uy{v`>X^E0We!MUb{DR%?wd1=RWwH z3*ekhdch4oJlR?p8tFJjABO*y_I&mRD)7<^v_`@um9nKa%A z&K}4VfBGwv#+226K#^vb8b&E7n>=xL-w$?6a9d)4iVVAZjzljE)?qZrAzed!&$ZbL zf9c%`T%ATuJyGttQ!1RU zUWgQB0o*{w@QJD00J(os)Tc>fCIV17;H&UM@2d|y-1?kyXkrF+#??GVDL z{|GM6tj6!_0^yXZWXHGzi5KNEq5JiO4)_ZK(Yr?jHGofi4s&;CcN3X3Kw9s%-#g5d zmJw0_ygjln{r1((%2_K@^ah+oMnmBV@9=$)3A|LlfhR$jIHSp8{W<^k5E?^`S*ZrL z!3kiY-oZU9sHl?VuX)PRWhyEY9j1Ytx6m7AZI;EGP_%-RMy>HCgRWCzslfZa2$?$g zhA8J%IkUXlA~t?r3Y+f*nIzs*9ZGf}p=w8~sE)i-bgdGqOQxHwR8BSUGzy(9)Erh5|vPyMn!WZ7*_ZQd6O>4>F2;D!^f)DB92|jX2lq0SZ$@etS#3B zTfrkC3$lX?X+3jZto49q^i#ZDe;Jm53<6h=GAHm6&u`tR&{&eA>CC50G_?(2f)=XfooUhGjmwynw& zjA1A09v#dC9p78O(}6vLDd|L2Pj-Lq5~eWHv>E3p{z{{hR~+yzN$#rml!#LSBd4eY zut0%Vz}>Rk^xh`&uei`Zy_}B+KFM*!1~LvFCQmF7`;{wu0>EVay7V9rbx&rGy36IQ zZ{2$xhacE(&TkaB*id?b?gXjD5C6I)77$!svgfj_%b(tr8Fc#wEwABu;}QJSc-W7h z!>RQIqS!MA#z*F$A^&X;FQ52Xuw>>>P$eO5);(Whs|_a!*|0>uXpS+HJt{Ark?|m- zN+l6Y4TzZR{2?f3^c`0;8w0`x`M2`zl{l&}MjvVs1P7fnljc?CA?-358l}Bat9PWA zTusvsue)U@mNHhG<(9c;_ugpRxD0dNgyv2VXFsWg^8j^&S&hcyiH$v=o@m*^;V|Mi zI0Wh3iOyln&G0C87;x{}?2O;Kb}H8dq>quVK%O#djATvs=87K?V)6s+krlfG(MfWM zEBqF8$!gJnjDDEPG{2+8{s}1p3!mmk|ZP3Cv>PHA|kI1P|o= zk%MVXXYbDsY6>i*2{L^lK5P}g2)O1GVC{1_{(pmp+Zyges1s&w_5?=Ayc64c*fkG; zmK-)05_LYh^decrHL57aIZQ7BGG4vP zY+JJBt0UZ0o(fn_%EV)pOV0Llyruj*j&(+RXs&s@^~|#N6DG|O2$*9M$CQ zPL|?N#hMftQk-V@N*b`k$GbY!krHRm?2NbJ%5u+|hw?Q8lYcny5FB4@+bs+jaF~17 zOT|aLHuJxgfMtHVf@#CWtNUxU&%n^#-T61eNzSGVw&}MRP5g9GLBx&bTc>H?gPYst z;FPEQSXue@piah(N2!L5h zbGz85oBHKa2J1`P< z_2)?q-Z_nOmJ9g=3BVGX0Nhl08Cr5bTRil&_F#YH_9N2&|6oZClBonGePG>5+v;Bz*V=-V# z9@q@5FiflQ9$CXhWx%$v1_7^@fn5*J%o9sWE`CL?2Qtxw46Ch1g*jCfS}W(GLR>Ea zm0#bVf{f+Rv_rD`%H2OMN=Y7Pq<9G{Hf*`g_s_hP7u$zY(OLNBaCbZ%MGfVyq`t>WDp?Oz=OMwVPg|wg1YHMfG zTgi^|N<=qBR{ZejcXY>L}a>&8I+{X>f zeNsU2s^EhIDLeuZkjz95Z@RcghPLo8`g2bVj=^pLh8XXMtAr08KBK0jR|944G=twD z4;59<-I{>1ROKQX&uD zc^WI)w3I9Ye-kS+kEmM)pEgAXxU-yrzEu7@^p-9p7Uccr6K=}{vzGGk-)6y`-`KDb9*sQBUg$K zS=kB~9FQd~Vne6$FoIBJb;E}VG`IZYpkFw%e~8hRa1ojG`~upT8?b>2?UD@$`OYd_ z?0pc&;!(z7+}2kp<5S`berYP@#G*HW--JowyjW`a%6&KRisaqoGyRtXYF21Eql@iM zvL@|}7KQf-24A3RhTD-d+(-hzEm!CG?mJMnV{tjR^}IM%3je9pwCVXvHW- zvQV$ECd2pJFJk|PeX3SZ|0{H!-5e)MP{+j&E12>5%hk^K-3GA6R~gpSCqnAMQn8hF zs_5E^p;iNTQH|`PCeSVwIr7uxxfHqyGWBaG&#a(p+a3F85-Sf%K5BTR6>0C8UYZ(Q zomGQ=f>ojO;zJ~pvc8hK4y5=C&oQDfN?~=f=z(1_RrH`Kho}DSVwN;gWDwYL?T_(% z$7=)XtdKXO4My;fi@$PWhd zo>q+zkX@X)Tfgz+B`UtsgB*bkFdxPUDVW#yb_5gpA&_7MQq{%?cDRFos*YN5HYk7$u^yvW}I{e9cC#5{m^3O3g_ee^LRF+6m;w1>yh+Lv&lh8^ z?i*`*`|KgUj)UD7e`vm3sh`sn=xL*a&1NS<&pf`;liHwbu;CFpWHj{G878_-mYCo*7A;1`C0uV30adqGq zLt-NjrYwM$76B)GH-vdGD7d%7Rlkl=8A!UWv=Iawv-#-J9_ZwDoZ240@Vev!zw+@q zVq5P6%8(MQ$YiRDq3@YTOp-@wW3wQ6aAe;|rBbY0sf%OxI|!Gye~K;wqF3nmQ5zCY zWC5gfvEblwGOSs)s+nIzO(`7u^@Iw*aM!6eKgl#4^uwmTH(SXN(O%u^Bkce$D<sqEF99Ct2 zFgp!cM7BPHHD>7u-d#sl@x}C!O*DBI^i5V~JzC7z)GE`o6Xy)F-iRGnL~FSnd(ISc z_c#sJHEePw5+cEb(dM|ihu$>{&=<)dzQ?M|@ySuWxZRobNJG?Y9;etL9Gg*=BWCz) zroBF+hTn#@9sgBAPpCl^+#$yiA3|I_Dy&5!(FJ zK&ON38>5m0yrX|*=@IeY&Anf4=A8UC;tM7bh#G2EvYaZbbWM5L73&RX$~RYIX%`z% z<{ZNlZsGY=KJY!e5FJDPrJw8aVL={FYMG!fyc*f;v8N$R(O0eFeM9QJv#^@gTe1=v z(7%`;^(7$s)R|RY5-d=vf%e!5Ge~IqPu7ajS*)bTiz?0J`DL#YZ8FZTa3&86`rI## zPX5wmUP4sz76JS0H5*3`$F*;L;2%4Xnf7lwzM$p>AKjU)t&uLBek=k8`#`lhrJ*k| z#g0}|c2J#vkX{l8%~+_&)g)mpVc9!7fC+lKZ4`N(s}fkJi-SoKF<{5>1~$dDnwo4t z|K>xqCC|zM_B~W%Uu*Vj-<|=E=(v+mpP&JjtDT5@4FIGSKb?!}eIsNE8ish#{BXbe zU!O$w>2)TAQ=2WtZR$n4#ESEvQkVAL@~WKjrYezqaKxt@)?G$7*o%1 z%-{G9(t5Xg5H3)Uw^LWSU^11!eV@}uZpb_jE_$cNZHbuUgaE3fsIPQL5dF-6{evMY zz1R}_AtmL;GIOWa!=LMHkS)}0z5b(88_OVd*9CgD&RZBAR% z{2E#6TMC5 z;%+IWg?hy5-d1ejeZ|nA0@vjh_Ea05IzM3B)&h|SB|C3v=)7s? zft^$|luJy3ZI&~W#{tpBYmzA8{M8yc626)I>+F#fMYz8JI_|gLFJtCeF<{zrp&{p9 z9I-yH@UQK@G)kya9+!8#{wW-{FvP$ewK?_#Qu0jfQ0kIBz88 z4&BX!hn)3;mRfwO`{HS9m)05Uj10pQyY{C%9udI=&HtZ#>#-jO!7;YRAg7|Kp-eCK)hxraRio`4k_6 z_S=tW9!S|W;9*xg28C|D@w%4qDR1@u60bPYgpe1Qd$b=%&q(CE8g+@r)Y!6>~I zoa^8i5nSiw9&vAoyEF>?37!N*!{QraWYP7gr6pIttM}Lu#=6~@6boLpd!$ryM8nqA97+`K-{Z|2LYGX2u z54<3WyfIbou9^8_QEXmp(8)bfWb!5$+Sj%sVY=*SVVBM8p#$Xuu-H?F3JjVp37GLW z;X!O!&AE!dpbT$9F?cDTG$`%>ULUM#2i@wU7YA{5$CC)TM=zl-!Cw5TmgF2;HiMgI ziqrJ{eHO&#l!0H7=Q3>vXQte}O#{#ncNhU*l%2$*wJ@b+L)bd0{pNti9`FeMUoB#% zK^D=wUik;lqy5qX->b3%7yFYh{}Cu5B7?cr>yNxrK-|bSjN8)PY(rh199ZgeyAvx) zKFL#Vc)@}e6vK(e@@W@5?JPd()1+nnd2mG4<*v~?Xy>bJe@D6`Sr?=O?k~D0=U49b zVBs1B;t^T+EoNWZmb~Zg#{}^fh|@k$A*Pp(7>>3ct{P7gEJB^H8Zt4oe$=6576qvl z#^)-2njAD#*@^IkmjkJNlF|>!cq?MoJ5pIWEhiZEvMe}1f6vPU#EE`7#{h%?^OoVT zCtrjQlTE(B-vy3@DBlEPq!pyZWZqXdVZf837DHaje)_kF!4yyuB;t z(JMJkTQAeARPrbouNl>>cCZ7)r=yK~Yg|3QG#QZ1YEYJ;!DfVm_yvT-mTvw7avOzl z+qE~^Ze1P>EXdjZy3;^NcTy758=|bcMtKJv{yZ%z>wqYN zr7dg-V!x?hU3(+UlU4scTG-^Pq8BrkCYf-gCTi22r--JaMPF#cFMHo&J_*BKt08>| z>q2m42K#nM^c;>PW@8_ZVB%-%tW!OdlFqGmp-9OK8Wv6Xsq;#_dfbgOejIRl& z62~7{AmaHAhyBA{Ne`59mkdIzst+Fzw(0L!*$)lreb>3fA^t%Mn`&n%8?apih@x!}8U#kJm68WrjQmtip6Dy| zVr@4Y�~o*k8y~kPRf%r=r;Zzvx~~w(z~z%pziP=uwF03YF?}G)s}UZv>b8 zk=4G%ywS%X%o7T&T{c8cNAmsaG&K(y;h6m;R)OJGWeXi1Vj8~iYv_{MlZFu zT1IoyR;Jc5#Uq0~L(UpzpoOdmwlFkYQ6c6a40o>?!#1&X7!l|v;mJ%=qT2{;n`C<< zh69gU=Sz;TD}RvsAy@DbE=?qK)ExhhQAYGWD+|{te%#im5l*(%fyn?O8jI%GFFy=D z&jz#TPHW8OmbKjkBY|Z5O+o~xNtA;7UOvqEDq2~j1oP77G9&f&NiIe25A)e}u_zYD z)#Oc#N*Bc$g0QD)ftbW_h*UYV3Il z$d^qOuE(vz3fxuJXi&h5<^)61*__XK*&{c`6b(1i-YW9g*YfO)NAeiSC022V=cHyA zDF00Bh$<6&cAfyDgnD_qehDB;{2ki8Jjj=yz?UT@0BZ)D?Y*48C4e4bViZ~cE8JR9 zOQj>x4La`^m1K%Xiu%yIm=~^v)^U=96Z@c~Q(y?_v#Sz1cFlihf9w1M>m~TK-LTfSGYMzrvj*lyv3n0C4S3b@Ti*IA}Sxp3Hwa|j16QXk!SJYZxe$}Yh9lMWU%NPbM4C>%p3{XMj1^=QZ z1JuSNaTwM<#nf#9=W<#c9Uiz83RebdHkW0T5zA@Alc89Q2w_beoys_FPs{bc%PsW+ z?I=iwdx>vRlnhgU1I!i~=~#FqSBK87l>An8)Go7{+0UnbCqdvm%>jO=p`>7$}}Xme0=Y9OjJemuQEmgXpbnimDF(Ed~Odp$R>Z>Pp4KXwbFGi zd{D#OWGVy|0su_4X$g8DkC?K9gpK{+6^E8tC6iD2#t_K@NWfc9Y&Y+!_$i=w0iAX? ziuR@rM9)8#f>_E*0d_y8Rus&cHhuwSlr&CIlEmnRF5Gq*25S_??e9vxO*uCtUtdKR zavF%F50v?baUjX_>1fX`N1`6i_k4w!+)zELg}^#Kg)-b((BYvwd>Y1RS+u4VqH7bLPKFp3v6Zt+iCn*&Mhw$ z{{!x`aK^x{`q}@ap@i6dp0le&nH<*xd7c72#CkHNn3M_5kt=OXI9U<( zBh(ICTAxrxjR;pfQxrN5LbV(W#_jf+9z&lXa)2p#5D6S_vf!ryqsfJ5RT#@&6C)38 z@3#3iZ`{SVwuS#|f&&8-bp*CAOUV1S=hAFwB3eK!Hswv)BqO`{O@aztgbD-F7v1|_ zs7J>+x?PyIQV*B{YAVh#8DWwR?d2u^B_Oq2r+yTl6gZUYP950E-HyNQ?!%o|_VD4m zpge#5z|9I16D|>niM*f%u9Vi|l92jHENtYt=hTV{?Dk?uI8W$p(qO5~J8Fe}DfF{M z?YwgWl*;{^ucMm8Pt(yt!n5JQdZjKi;Dmu{dP)?k_IWEGk=rCIen^f`7$FzCGdr~n zwzW0v)zV<**~aF|of4}Jtt(VtZq})6zanGP;MnkAGuzz*PiUG)N1X|29>D_6T~CH*%%D=3R!e=osVbp`H;D^2prs4`MU( zS2RRQgp75B{=O%L(?*DMC`kV6|I0T(?V;8a@yO70rO-$vg24b8drrotR$KofVf8uC zx(ofpB(AD5gVnxr5z7-GeY~XkyM2SWmT9seFx~$m$uP=3xs-9 zU90nCg4jv2h9423UH^T_rlsNP0<>18;sRn-xLSt-kuT_$RyARK52_y^G+%X?WcnY0 z11p!!qbX4mm=z`C?vElTx8Rrob{=~(HagV+6~BOb8sPP75Om&g66_8YddKc6aJWoB z*Y+4^*$N_}YBm^i0N^g!#zMJYf90eGMYm%hJBnG~)iLrF`EE7e3my{-M0Dac>xYvG zf{Ie(b-L*6xMO+NCU>$5z|>z0wjei&*rx5KB-lia$cjoYN835op^H>cpa89amBSQf zH{!pQ9eSCcaX{C1AfPV|WM{D=#}8P)f#Ml*4jo^hxMLPLAXLXC7137;FlSM*DsXF- z#%Lk+I*!(@hqQ1F@Z?S`Muo57l=1)Kb@~Tj)=uPDnJ$7#s-aHNYoX-eg`w9;Z2^oM zVi_5$KT`k~H;`J%XbXT>Z(TtoFEv4t*71l%`q?9m%rV>myh5NP3FUjNJ6W!M)m?{! zyaUVwULMfI^6pCRM_yD`8!MwpKd1=#oyoim%L%vE=G9=_@EYwYz$ap`d`Ht3`G+pBvkfEoB1A$H<`Fk)j`-aE zoO+H3+{$REZU&WRK_cQl@)#O8+u*SzB2HwQd@M56B%=bqF^Vb-H1X2`w*MFTSd^y`DN zOBxN2SS95mA-&au;*hk?SS}c=&dXlb4iazguZvO$Y*h)z33E{#@tgXvs6vK}YSyz< zT-Vpi0q#Iq?Re^{3Z9Xtd;2TCJ)HY{*K@V6occb)zB$b$3ra%QnPWMnG33d6(lDNcIavV9}(v{;CJq;lB5D+=RbVvmTf5v$l;Iea0CN z59*MRe-XJTsK@B^4#b2ELVbwe1-%|+L0sutGQ0iuj4o9;h`XQ<#6_lSYk(;ucqbN# zY`H-cyS|(=GG@mP`{1>dM{b4(o{78+?|+PTo9D)7qa9~7yAry`WYW%XTUp1UTxQSK zMXK4g9UN=`kSs{NCkeg=m*6z=6Mhg0KZe{)0{zO9YZ|fDQ;Th{m~${(JmX}d_&W&Y zY3tAgnBlL(c!fTnKcE@GD+INP&Z>PsZ#A zU@#~ZIluTz){{G&>Bu6%3>q*0K$xBPD@3gSg;Hk?>Z%WSYnrr@VL-xS=qsBTlVM$L zLkF*MQNTlMV6oS)Px!a-Nix$t5eIHrTvgYdgq|3VYFuo9lj;6)6J{9~@>aA*pU>lX zr9(Qmi}-)z886-_s(t#H0DqgQk^H#e@Z2P;+#VfIj%}OWf~)5zNp6VYs6mscgLEQ zy!Pe_e;@m1%R`UD!4v1G50)m&XChU1e~$bBO7*&vs2~1zrRWcfAnVlcM(!a|DNvVT zB%HeK$6WsR=m<8*a)T8NNzchhJeRDVhPx6{<+Mf@ z0Nm}DT-64S`Hlprc-A^Q2A3ZPfF3bg?JfwUD*C-6XSb_L2KlD&dpIRi8541ZJi=%( zE^@5;^&wx3-)V%$M>=p4V>4kN%oVfYIu@oaQse7}C{hwm>$Z}EbV+!*33b|!(ojvI z_8K{=#J!o8fVOuAx}3MFhMowvl9;jzm6u?gA!ZS}H~DC0f!$>z1vyzJW#9dc_h{x= z5JYfZOAFEvxVXu2s>FxC&g%!b96dl2xPjL^v=8+RI^Hc3B5j|3pYV4dA9$*0$ zAhS#2@HT=)X|{krw+n^zvr&Q=Jvqpw^TTW6*Wx}!+*b6dpGLNv#X@r|o5|4$(y$wo z2Tl1g{485+_V*GF$LeZlXc!U$*h|>e*FqoOKZvNKh2iO{ zCGFxOI0$l_SdwH|@UC2<%>iSqgC|>0Nj3u)rKYqSKfzPeBk^>35y}n#)ZDd30Ay*m`_Y$!wg1UlMRrTtwx00e86yq$MD@t1)XQC*m&!|S@ z#^kE9-t?D>l6sVP|MGYgCb2Ye({hu5PbbFs^Abz9q$2yg>%5Xwn_ADMBhQvTtV%zp z@wqM*GC_-YDIabR0*mAVFMZ~j9_%{`kW`*pmz5s;s3roc!nlJRTcoC^219q!Hi)~y z=(1Xx#vud-c^%R!f@j8q=awAfFrb}E(dxsVOV)vQu@zX^_VR1S{tW0ZVi!Irr)9p_ zYRw%Frd6QbORxIsfve9*g{1ag)DHyeD*w~Ec+Pf3~S0blJ?HP3!5KEG=h6M{?m*)_=MfExe;~V{~ z0dj$|w`vPW*!O?U_%RCLwFCkr=c7aVRP+4|$9xZ*AF97FY-tkwdU~z$d-Y1e0_N?e zFRc0Tn58``n@Rh2xKn*M!T6+x58tx{V*3wGZ=)OR#o*?@p>}4#-q;F`RCgQ!o&^-hyV zX%M~_rL;R8$cC%o^ZGfeqGg0JG5&BA7D#b(KE1@BBYH^D3RK>mPIq?#US~uhq(lP( zwk@NkSD#M@z@7c7Q7iT{%?DEfvo59Yz1sA`c2#>|4!AOK1j3HO<~jN5fc z-qk;eA+w9mrb+G#%HMlq5Tv~rOg!H3#+TE1DbJ~m{>r0u9C9ZG@*I7Rb*-seR(i>2 zYe8bAqjovba;Ldbl;7(4J;HnPVBc0e)-xl4&FAM%8H9fmzHWfmtR1LLyjOU zagakAltsoJlw8XT&epB^67@=zmhw1c?^+x1k}!sWIPVZl zv2lZ1D;~3Zdiy>E4)N8{EYq5~nZJ?Y^8?-K(kbv|6l*K0Cf#tjua19amBHMSQUp}a1_GBP801D=;9XAgU*tf%>mI~ms zu%brw95`zs4G5F|0?L{JX8=M#y}xvfBpPuThuCy;k6N~+;&lQ{Ngg2L|K5XJgPvc3 zf-p6DSORyPpI2>kwMF4u7F!Ukc7W5IO8~)hgBgg36PM(}*0V8){;?41TA^o zktNXzTv37;VyD5g7iMnl_?bLv^SDhDhG9L|z=Ac|$r^OyzXQP{CUKR~rTu||a9#qx zh1zf2TDx%s5-7+cc=l7nV4bSE3D#K#NGf+luiUKqC0y0`{(4YR(s}KB2J732DlsDb zflzeU5^VGd&2VUX4D0%b|0z=?%ee@^Gc&DX`D2xx3$u&Auv@1lNp@~yp_y5?OSGH| z6BBG+mG5EpOEBopp+zrP)pPBBHEjBL#97~{>p{p6dG)9hbhAeU2AE6CF3)uG1~j12 zMDYMx-cTIwzgeundw}ni^+`8LhSO#^fVa7W(!WW9eIUZjS-85bMQ{uL{-S^bV12j1m^F#cZPlDqiG0#r7Z>P5^pQhTSm zo919$V?DJ_A~g*0V+h!iI>+Mt?}p}Ius}27VyW&bv3{ey5jCw-Cdw>t;a>oHM8_nV zpExzc+#U|M(IT^IdSFfSOWE~@i;<)RcUd)f?O169#OJS@2ACmpHa2jIWedj=cgyjj93q9T~1 z>~4&+C~D-?>Rn~b>wV>m4V?m#7MCH9J>}I<+7{#&QkK=f@4wIh)9*x>;o_)o*M(a< z$qpA0RwjeWcIh=g=B9rP5PoDuA(Q{!cd?{ZFnRAP7eWcw9;nb2dMc*j!&^dbtW? z+SK2|0DMN3j=4xCcJmfqxX3xbV!Z?p6Cgi0V&mG`m2l{Y?)3w z0ug=3`(wGt;I};vRE^-i*KqCunew#~8hh^O>4I*1v+ufvA7I*HHcZ(q<#(`{6fOjr zf3`gFl+V>g@qV%VxnCV~M47`clahMjw6 zlR_c!UscSclmC;48-)G2c)92O!;zk2CUafL(-;MS6pbcrdRBm*5q#-vPhxa&U=Q}G zO!nyvO%6{I?v8w`xu7LR)f8@(onO^T#Ax-kBe6Y+G0 zO@_Z@#wIM_fsB#wB|VK&ZnN~u>(uF>!ykw72n$3QHn0o6sy)A`iC4ukPd7a!4i1q( zG`?GU&TAYN;v7%T4zs1j^l!oO?pbZ(01*iQ?aGPC#Pr^?9SVnRR(VUN2RFUaGEr6n zmUIfO1+G+_66M8FO@gIx?jQ?74*7_-%g~c(jsy0Lf3ZNHb z364iuprdxCE@k2ET>`APQ60fPgAYP26}zbCv})}6)6M%#usg}JX|=-h@^)c@16rop zk!$`AL{fXr(^3Gh|6vk9o(spFS+Gn(=WV0nK=F1N%nYD76cA6Q{1}L85##aV0OGiO z+@)|1+F%^h_9?h7h?2pg32l?>w=&zIQnA*aS1V-j0l*P2Fc0j+5 zogLICIZ2xor^JGxlcDD`qR7Bi#l?+lb%CPMJEf+10P6zp} z1Oh;C;3xR?gHwTEzqj&mwFW@64!(mF2r9gs6Tu0f;e_}Ov{wk7_e4zsE;7$2a}vl! z>%|>Bx3z#82@Ga zOvv=!Z;9wj@N!iFU=J;y>6TVa4NxG>`M}Q^xD+h#w-FO?(CBbE)}@LMvwOO1h@|iQnJ*_)h+#`y$hcLBe6)PtfNj0RBS9$L(=-Jk8IV30WI(paAFf zPkp_&Ay~tU1zwj&*W0N2WsXmwzYnYvfVLmAf4Z!S$@9|CDkD!o5bX;Oe1wnMRE#@D zj~fFO#N&{(*p99Wfx{uDJe4K!qJ28B$+$ar;x2tVa|a_z5=44EZnQG%&eTwfr^uWR z8j#sa=_xjileoYhvwh zQY4()nxoLFwf?78Nb+Qrv<&*lXE?i@7+ix6wyaVA6R8<^(YnTH_*a$IAJWCFDT+Dg z&ci>h*r(QbNDs9FE^!=*xw6dT5W7h84N^-}7@({IMYL@M-PBoSt*I?~qzZ<6F&_>@ z%s_)xoPB?4=r(P+5+1KY6H&u?p4=Kub2uCh78ksw&lK?9`XS>dql`X>mI{0efVeO=7(6O*{b*oI+A#iFO!Ji=olpT!rwF1j`)+ zaV`~jKRUei7nuv2bRMt%P`g~KbXQ1r+U_hE>H}1hx~Q*VQd>Pf0shL1b* z-18X~2o^F&g0|W%T7qITD<>TiiT7g{wqwTO=v)Musii{NCVQ{tDyC|VJxb(Y*i8ys&WE4_3b;cW~idURk!bD}m7qD7V15;7DPtheeUe>uZ zkuVOdqRHy@wX9q-ZDm2x7ev;A7_;NnoRX~Q(j8WK`NTzV7No($d&EUGnYHpwMw~nZ zT8PS$KG3RpbDKYIh-^~sWl;a^F-{^a@|=a z=ww|Wn_y4DX+})Kg~l5MrxIp=^t#zd=*4rua|TYTNr_@sbW=F+)? zU;E)>3ZxEC>P>S;kV$T@5ZHp|33$@3By zW$A{Zj+W0Fp0@k)56+Rr*W3P|PJ~@3AxT;K%bve@Zq*~UW6`#{;J22DMV>=bwWgfI zGrQv^zyy-567?l~Sqnj0^J8kwrvOP z?ZzNO4}nKoR;cab9TBWGHBB$|yMqb5QwDjzN*j3UM76Q^zln_L2T) z+Ei1%D71FSVX>6FVFA1r<2_i&9q_%a46o#OU(-Cg8wY|U4w`XH z1+&5TlX9t=I;gCoA0-i9Jn+5O(>hU*6>jOF6dU9piajg+WoA&R?6@Ry{?lVO|F=gh z+d|nP$0*>7I}4lg`F|)+$m5nl)gGca21&cG<75Up%OCY?jY4_gF{dHD3T_U{mO49;Zt9ZX z8L;#5k!xhD22sB_8jze1X-#mx6eo}_2S_;xSXXpHIbgPtFRJv{lisE0lv<(If0db5 z6a{rzG$TaBp~BN9zm8f@P*wP&3{F)NBBYY$x4U42#nCR?(EmS#g=;M`LRzMYpQ*#J zzYR}->YX}WY~4O$L0yYp2P2gg=$E2dgD*7vSrQ0!TAh0y4HK&q-t!*V1zCp>g+;G5RLv;9XY=H=C`fLCCROQz_8M zU>pZyhG{9A7NWSL8z)MuKz(;sB!Zm^U|ywZ3>R2}c%lmsalH**r$@0k4c?54P%Wc; zzx0xU3Bg7;{<{@QTQt?GbTR>_|gaw{Q*4E^{bmF z61e;1sS;fujax1+{`9Xl$$i=sr`8PNFI;Oj7`GdJ`|0}MnJJTV#CZ$av33Yl36~IC zFDmUfre@VlKe?Yu))Np!nZ739X^kBJ!|^l=&%!A4wx3(Ga(;pK4kiw_3`Y`INcn;& zMP>z2=U+}u>mIye$qo5341t@hL!5`#xUfVd?w@JYOdJ~{`jfh(0@pPLPElQYFjJgg zF68&kK{iq_F(d&el~pR^`UO(ATW1vv!Vp}uUpnKfyxR`V251$!ebXB|H_ zj=xDY6tL^KOqV@AJJ34+W{=dJ0>B324+deIj)Z9p)1bPow-@`P?2ijHuji&f6SndYc#M@_AXloY zdGo}X8J%wm>65_w~3iu4}-{~OvTKA-Sg?PDhTt1 z35tE`ln$c}q$*@(lf|yZC)SaQO&&EZU!MGP9pe6P0}&p_TKmpoQF$Kgz%6g5l<1wQ z7CGDW&WKh(M_}b(CenOqsNG2bZ3sOE8)4I23OPmQD=9&%w3C1qRvqGXq$Tt70!)<; z2;j>Q-co1X5f21?T^zY(CrIGF%a;Ce8MEM6s7j!*v5f-0Ru5yy!id;2ny`i2ytv~VfaR00DSA@?H890fV%H;-OrKh9g2+Rpq7{h79sOz-XDPz#1j^U zttvrfF7}7U?}8?s2uSx_wAC~Uyp9b;W&;v+JU(58jgd*MXHcY5I^ypfyb3LSJUa}D zn3Utz-dO187_*T^cL-0u1`nu6L-ut*F%Yv4S=Rs(Y4y?)x;AWiy%2wBbxX?MDfXU< zsGE?a3YB?w?$LbSwr#v(bPIDeMthD51nvz}vXi-VA>Kf!`nij$;2ZzsOGMRQ9LI)_ z37iZe1He8109!qzsWU+7K%dHHbGoz=GTGP5r6}Jn!?Yxkb37E6(G+Ojsp_bSxxr2!E9&10Q?qhaKjy52$h_RLvX)Y zaog81m@)Eek6Kvh{{MKei48|3Xsv8Py|V2ih|5b>LjXph>WBB)2R?&it$x;qoDqr< zMbyqmH13}k4C_n3y5r3orb0EFI+72`E!i0|kW;i{Gr1R06?9*4{2ACqE{fkky>@^c z(JA8z@`37(>GdD9>X8BAu!5C|`m5 z$~TZ7GLavE*)Gl?Ox0qGt*3+)ddI{B1F`5HmOVX~=j7mhL-t7}>)DaWJE2#2@dhQ{ zs6@h>=Q;ogy%B6`r9VH~2+dYy6mSTAYX!$L;iW+>Bn9PSezYV3bXZ8Zos>B*vtYfp z@14{3>*!2qD;tTD^DoRm6U+Tng4wy%9*-UG;?ILAtVblGcUM<1%}x{^$<(=!C(dm+ zufa>WeN)$TIxjI{3ernMp;d#9OfjvieSuQ7$2a!vMAA-*q%Yad{%r_DPgKTu&HGB! z!wz2>+5m6m5;#k2`6<|Pm<5jH^>q1D-lBn8MaK$wCNZo@Bi8K04@soiR8r9oCfU*| zo%|7819`L@I(_)6Ej4ixdA``Q=63YIN%fgXA*Bf+LHJaou9zUsJ_z?|QB!nx>cptN!bUC6{|HIL6CGsJ@jd@UeAq+2Z_Jc%U8l*zn?_4m4zJXs z=K;X-UC2)EIzH=Z@kZ4jMIxr1z*X|=Q9*Y|{hs zZI^b5qhRtN8Fe4B1jM%J`eCkc*S+X-Jj2JGJ5PEP-iOI3>2gV)5X84x!JHKHo84S3 zL;v>mW>ApzUksKI^G0H*tIZ$7HF*tGZ=Cx=#Falqw^-1{1CXsgWq^@|>IM1fyczIDi`lQX5Qy6$jL&-rUqoaneM^f=_m+4}%uAsQFQ2#hI}Aj}EymA!`?o zTTB6%$x&%E`;`@sR9esxh;#;<_ZM^G$flh(nE3k!&khWz#4S*tsmrj-oO8T=61}@fxj4rQo^Z z6j|0owbul{7L>eBlIR$F=h#S;N?tlQIQ^=+^Yv!|n@q*cWq^saWR*jA8FH*C#ocCf zrkn}@2>gl8!bVtZCiA%mZ-T?Ez99i6T1x0 zd8hk>wSa?6!{w#D!7)$1k9{eSqFkncH=qG9(~y2H64HnW>95--MB6fj8RkPausEc+ znAj;t^`av1@1D|~L?|@+pgG_7eac7Su4w7#)dy5jQPJlE@X#kB4S3~>*#TT{=VWxR4(3gN8b0^v2PRJP7_6aBZJ5|a?AAZ{`x8vm&ko3%`+ zY=*y1(J~1+Mjrwj^Mi4#F*vozYj4TZT9#iyB85Gz3+I1|B5X#VONu8yxoM|lDGSQb zcDa1PJzO?W1$?&C>~$zFT~|;YwGKK|*wV~(6fyOY_PW1t5z)Daz@zs%Fs!h8=W8e^ zv{LZfKA?BaS;j8gL5}~0OAk^&+&KF16Y_(8cKdT*aGd?!+ui^14d!10ZU~&Q9Q})r zA=+g6!FP&Q`4NprpXE}ei_8X21%NdZN66cQ-P7Qr5yC^U#~(S^`XhH+!nNoBjd$g} zp66_i*KCt3-IO~Vsbe#U7HD!*=39fTfd{Xc?Nd#9=(QNI_%GVeaLADOXQgGsI~$Z$ zL+01Eyv98TApdIH6A!9ruotvlNHMgjYyh>Xjqb&!w&%_MCi^4lPFV$rUtFa$%|*g9 z(oID0dVr;^1y+3^BjpEf3Q1@tA6#U1i}4w>RwT~jA+j2BdWXjBgY3oAU-F>{T#tCo z!38W=32_}=iy}OM&gCPP|NC#P<}OyT*WIwM*Co^+6`t1H-xEZ+T-Mh1nLs&a4Mv@b z4-tDbB`9EQm*A~6geA_ECzTm{FZih%ZY^Sx?qr{Y6j6Pz!ka_Qu5wjNjL+P*0cK?_ zjQl>27rkjMRSNcT^&AxuYL|Bn%IYC;oppkRVqhR06jA3%z` z(;pzI0(EKwR_R_}$G9}0&jr!I3$k(H2ew|ZHAL&IY&F{*MvVD7cN)<+8_=}bE?HVt zaT&+m^qBtV4+#$v>L2}rbAB=E2ad}Y^P+GzGzzv7`JonaMuI4t;LwAFVjEkiMUxWo z>BLV_TQ&}{+|!-Sxl84p5|y}!6@v_RKbMywV^O7OtfvtogJfx4a-bddcD4SP*Lf7& zGSw^~DIqe0AY4602mjsgF>={>T@_PY5sZQXV}@l#1-+#|BRA&Zaj33nFON~|ViU#z zt5!XLZdtdM3<`uhaf?V^Mzyv1iu*O&v`}lV3U2c{*q`+T5A_2>L(*~NWVd)SXg~S~ zQIe|e1j|(DuThB+>+7Jj5Rvm<*R9~jNm!=h)jV{GTq=@jBGo4&VfF*)~;h>zOpuc>OZFZyD?m>--r01b@p z3j)H)l}QNR_0HjCt}zQ^0iBofYbDQ^Y>FkPUi4wQ-Le_dM;W>K9qT$w1G;u6kZImM zO(2PU*cpDIU~RsI(rg}WttMZ(XA*}r&~UclhvL`DX1?Z=CFpgn4zE3Qewfc{Jsin* z`S(NT$hub?EIjSx(fC-3jDQec*~FLOL`R^UehX|e%K6_gPKREg-KeV#!(4^~Z&2ONvg{^r=bwugfgEfU;MFe7iA zab$1R_U}eN8+cM+Xg^g`S<)quC(V`=bAz9H40N%47H|XD$K=ienx17(&6@pr2zLS6 zh|z)N+_EQ&a6OM6_?W?JR84TQmx|_)1r{mZ8Dlh3K-7m++!2__@ZL?^SGy#FJmMZD zHGxQY+|UD3YFWr_&`>G6)AgCk0Nr$dWitx&N;w#L5*~4>+uE&Nnda}2u zt3hz%2&kmdLslg*rF?4a6Kd3>tCwu0jihN^h~VXS&wE-{tbX`6X6Jw;QXM)W`7x} zrrvHK?EeBj|0G9Vm3m7LnUU8-0?kh32?w^nA4TpV5#$;e3)N4j_>FR(IZlbf`c9ie ziZxx%r~UTUl2BO1C2N~zSg@52TGiqlQ;~o#fgQ?j)nvLiVcS0lE)A=$o26=!dErHlM%=Ags-V zMqx;X2}rmfmgMQM*heyNR9^bC0*J(EVez3X)z^Zv9bOYpoS*Bq$(KR%yR`^IXTyC} z2Id_92+V7}CP>qbK_7Vt8JJXqfsISJRmV^#<2Rga)cQn5%u=%=a2g|;yykLi6_GGC zD)s6z-LE!$*=3vLLD>aG07s1LbOdOmH37^qAsWf*gF4qTG09-{0 z3%!8SoF3V@A!kxV{V(GW=;3ZI?yQPT8CccNDkH7`GWMH_3`m~)-_#s|P7`HoRF!`MR2`)RBQQCH zRtMO{(13~%D>-GGXa?r)4zUt3xeBMkn;@l*Rpw6c{9+92i;{bCPZoAyDH3BOeOil8 znI_>@!0gI8ue{f(7OJo+Tsxm=p|!Zk*1*e*b&0atZFja;W`D_4Hj%>Bl=c(LVn9(w zdQwW*Hn@EN4B=9tD(MhiQ_E-eo76UUN3gdA3Po7q3 zG43Zd=I=j#db8R-L2+yec$-HZ5ajlJt1Z-_(45Z4shf!L0IDxbyAufJT=IPT#~VWoMAwX!k&q{*y84x7YhU?%Nl2|-OMZ}j!{Gv+<^B?Uua zL?x8|N~F|r-6U_!H>s6!w$xNs1*U+*5AT}F93bzl?QRr}_F2Y-=#YeYh z%}vG-lqy>)#TFbrY0U-(a8NvM0muVsSaa(#afH|0if0cw<0}FmU1|<7{HzH(TP!Vu zRcft@uN^{|@xO_c7GnX<2jlA9piyH_D6w^olF-xZ*Ld02n$qTg%k>p!?VdamIM8`A z7ec`h^=O6Oc5+kv4?=pST28wG=zMkJ6wDb|AeZx&v8)BTia9l*I|nGpv3I}s#)ldX zz-lG5mNlTd6dQKe5UJ9k%7sN7_m?!~$_}gB|0|sY5LsVGMJPT>pE!bl{{9ywxI{v( zwzy+m57ZRcfoz>Crc3Y12Qhk8Au88eAN7fg^X8l*^n9+Lp;1M=GWBq$B(G>v8SUR^ z20tdImJWzL&bLlv^pgyXF!c(S$(LT~+A0+v{!m&v1UWXowrdv;ae|3d3f`Th74csz z$2%TB(2El6`2tT>gQu@tHZa~?X48j;XOlbWPYu_ezx4N$BHrzw`$TkZZp=oD$)mrS-*R0HE69S7!U5C;h2~0!%T&(*1 zpmu{yJWIcsln)4hBKYve5-`dMX8YHv*t_B)|1{7(674}BJSAuj%8*HVkiq!Ig4Hab zyD0c}RD&e98n^K0heMzyNY-V7sYvyJZ0ha^5`4wDDZ;QkVtU!+vJv2!e-YM8RO)Du z9UrNi425VZ&i;&DD?AUV7Xm-R4qrJM6p{tbLAM-n%5W=gDq>^HBN3~fu371hrd0i! z3i<+O3xx9wYZUHBWAmU(N{{2>7%;ak_&7*_mti(rYjol}w@-iKLwYA3Vl+RP%t>$u zIx_JHp07I0_6MMU2+%?C8NLGRO95Oa{Y5;z!$TFSaF+s>_tfl$aT&pku7sllVOc7Lp`&DU>u(o;4WpQ zIC>vAxke?P0&ai_JK6D<6NLGN&d0-y{6R$G&&w~ZfXiYaX7*hB{7AZjXL=JWSX`%m z01F084Nye9w`MVjiABB*Ive5zf8y$d-+fTO&!y~II=mrBy!t?w19uYe>M*YeF1EMp z3va1Z0!5LK#-`ZA7NI8u5Vm^*azDI~-lScUd6)4#s#nlHAhXUr*mM5?X|E!eSNgT`{i}@K_|d=1|E6PYr!e^L$MjC4PV6)!NWpo!nai122c?^*W0 zy$A$J$Dh*O9@1C#Fghu&hI4Hy7eJQCQ7Vgt*s0_Q6aTwx)AV-?QEy)Mv=z!3ig`!pY8sJw*V^|7+yz!R~!{n?(cPJ zcj`j$;9nQ3p=T@128V=E<|#g^9H$9|5Z=oHsB%US^oi$d>dBb6_b+gY<4+ZURwh5C zWQk*)^y$%I4VfVr2_JSz>=2be{)DbGhw9`X{=3(MYv&yMUU}7IC23ppQdb}qF?9$2 zBKd1;5k4=p-ou!RgaQ~RG*?4!=J0D2$y6|djZL57)e~)DlpY-0{h1A;Xx9K-5g)t$ z4L^Y*GiNI%-8UStJA|4?`iWe7Y+7Vw8}~^gk`>GK9F&|6$wh#e_7dU*FP|DS70fUW z(xJN*$Eazd9;9S&*?$6Eu-8RR<9-lC3X6`zpvaRhDnA(Or%P&d11*zp7HN)Pr9Xnl zJ~E8yj7!>WzjN{=8qv=vQGqBlprOh}$!Fw^vZuG=;Kd3fu?GKI0mL{>u;-wMu>WKW2C1);7@?8c)y68QsMYLIvDubwMC&$pZqXoBQB zAaVS|4KGS5UhM_n34%IDE?m{1qQSPue@At1Q5a)B`D0rARl3B6K4q-MAx|K?*FY`qvCKR&B@w= zpK*_O|1VZf2QcMBl2a!TLmGk-n4A|C-T0`&va$2azX|-op<13r6o$G!;KhHEV$E3r zIw<4U0q{<&8Jl&|9BqnOE*CqR3pJMHSm%^yw#?yPJ5-zubA)qluAuP2E7}j9t4&u( z33Wtzv*9{#_6dQVnlb!h0M%2VbFR<#x6M}?EWVme>UUR_F4bneL1u}1??C+P38>~d zw*MUka9V0^@w>ks{ejsL3egWnKLjECAMCz8p)zmTf)w1(Ijfe0c%b*XR z2CATCka@$dK1~){G(r1n>SWb|7T%6Q5G&?7U5qD(4xO`W^7=%0&(&uj>f zc94Ub0fSRkeuqT(UAf&9vwApRSNJ-h0BKplzW5)- zMgAZwxDR?E8Bk*F6cPRy9Gvvbyp8vOXbN$WEA5*}q4BX!ac80w#l7(*ha1WLntB*~ z*sS|^7okKZf{E~uL>nRIq7WI#lDW-gMN4)!>GmTe09GCuTrovCGqkL$hsZ#h5S@?E z2T}1qENLFBgJ8M&=V^_aAZ;f@Y+u_2v_OY-WTni&RKJ!hYkwrgOvZ<-;Vj%g1Su)5 zDYyK%hA=F;)v3eb13hp7wwm$wGmdOTnWpusAF1;@BPECH@!)B!9t0a0fHJc%g1=fEKg{60QT8r~!ixe+A+w zz#a^~+J1m((4og5U>gn92@%8*Hn(#P%PQ#}vPN87jRRGz2@M(i%{iYsLki;{1jEplm0AhwG;Ym92aD$4ZQ1gO zt#19sIg@T-=iXl`_YV5Jk*==$LBZZWA5WN>6{$>4wIfknL1IlY*$7&-1A=UwH(cd05>Ro(Q$i7b6hC! zbO_eI_OqM=6Ku_djNEy>7ib9*A9W5@-+^ah5!%)64U0}Cf{DRq(;>PT1tOi9{m3$? zI(edTu*KfpO^C+l1nI&zUk9<2?Xi{nea`h+tX2hOJ z1DJIBY0h3FJe6sEwDKUP38p2A${0ObOI`ghlvb&ctV(#8*H4$gy$HO<&4UC~| z_r7)lK#&BXtU15?O$>fakev3&Vn*mJL1bhSHpq%qn0TWJuh=s(?ZzpG5JFxq1?-ve zoLEjzm&*r@PDqh-$QP}NS*J)xvk{Mt)|!%U=`-4Api#}6;G~C52;Lz77ryGb&`u;_ zu?XDhu;~v~p-zzR>E;B$)6>_~`9SZS2&wpmfJ9iwDV+ZS=1zD( zUA+@VVsVBYO#M0KoO3fegul^XJ*U3&8<1*;J)Nk)4w#k?(Of_h&x4RSr#EiD19U`% z#fqC!fb`@+0X3~J72Lqqw)i)JL=gNNG!Z{EY1y_kr5ee7=YB} z-|H=;e%8zwkR3GD39`OQ^O&)`tl?_uQpCxRGgUB=qWRW~V-HASXLGVU%nId}*5bad z}M+C1B+@2>SykO!A&OaVa4F8zclJ`53biGG{nI9_J%X~yT_~L?md7T3 zmpUlQ!dQA|^fHKAE@t=bo))4K(x*vd7!+G76D@Bt79i<(t;t9HtGzThY`O=qHyQ28 zEVqw-T;FehH)3-aP4(G~M z7#o3mR2L=QmLbsZp~<;t)0WHy2%R<(@*+jvt1Od`Ob>f7Sl34{oUY;Pa!NZ#Bsd_} z-TZ*ui;-EP2coq>EDs043Cz$2RX4a0xJdg`e`92+9~IBMk%u$$9%2S9qS{9EiC9-+ zIdi(fPnGyZwGh3Z6H^K#d{Oxu2;_-yPz@K6I{N_*RQ;#^e&Ej{1(Dl0Ml;M`m?5Hs zr^3mli%Ae17TjACm6bWFqoeQv#~x+aDCtxT&N#_qlGn7lcQz{)F~+S}F9J1}+p%#B z6W9N!8KBeD4^ZU|!V0s&D4@2sLwPi|BZU6EuMw{9o1K4LE76 zkJZsOxnBIv)r50^LK$0a4wC-~f8ttkM;y`MBmk?U!zL*``5DWtv;lGy8BjYJxm4mA zkww;BJRr5zVN-D#sJXWlqjVG_&5ntqflz<}#}~E+TlZ`Gv+8hr1jF$wcypCEzj=f& zHJO$u*wvL8C_Ok`mcJbmtygX)bksx)v)z+Sv$RB=ntKEr4I`?otRpH}{MAt98CH7^ zOL|ZhZs#5ep1v`+{eL5=@rTk{-$shW#BgEpOosz|4pE-yQv3Zrj+hVdg!TZh^m~*` z{bX1Vu&e1671}Jr-O`DsneVNn%1qXfMpL!*RU7Yvu^TdH%Z3a^S;guf~DUfL2Oq!27ZdeWS|>u7O^ zC>F0O!Yw`bk%!`)d_*<|8JA3a{ZF0~i#^2^UIDYHV?}nMmCNWR!d44mg2rLX#QFA?z$;TmWana~vh6 zvBBR|GUP+~6r+gprwtX!*{!r0BwvJ8HxWaQ^pE{q?+K!X8zDBhq$+P_c8dIsjg-cI zc~z{151Gc8^2ET;>vY%OPcOre>qI6gmNhQ0yKgnMT0u@f+nQ4 z*&0!ml9nE3%rW=1yDL&)@Qz9RiUH!-{b}V^THd$nvuBwb5&R$bqTXOWcDih~`bvbG z)G8l5XCSm(t6$?*3($_Zr$6vu?3&c7xk*4ld*85vMSx2W$)j{ebHD`SW-W#T^$sBCv3AwnMtoKNavy4eapU{9E9gu|} z1&QNj3|g7!616(6=TjSciuz#FOKhB#={-fZ5l<%>*LdJ&!^@R`zD}sjaCI9QG2Rcf zZ_)pY5lPO=hc&7g{r8kjUJ{eQ?6Kd&I0neHsWR&qUhVR_tM!~D06jp$zxxTibz!fE zZwRhtt_euQvG%TF5Kqgl`SwyYym#HG84w;zOa=ImjF6zA78hUlK3XPjjzO^cC2AZQ3a*z zUS9N*&stcULixd3p#_kn87AVoO+>uZF$nPYkA+_^Kw{kpaf66JYwlm0`4|_2ydkfR zv6(8Y1p8I5kq}hfoefU#)hG23QglQ8vNmqq>UuA|J=HIud@n`${l6OD)PWb(6Mp)in zZXLjaM+>H%0MwQ;>UBSXQ6R9-q@)q^UNi^fn7*|tJyOb(Z2(J-A%b+S?10b#yL7Mq z8UO;G@A)p|WV`fw&)g0vn1CgqTRK9*r|QGAlU6GpOVZNY#D>JbpJ}sQjKck791;5P zkgf7kZ`qK2ZL)EhidF1fc(}@NsqCyAV>Il?8+9oxJUnN8g>K|;$r*seaTvl-oE?iI zmc8cgiR-++XIKh)fm9lajuNuSOhP6kEz+0;l&E`{WFSxf;r|uUKmXMmaK=bPS2)J-3uk-l*zdV{TWDzI7KL#B$Pf z#}@l_mRgW90K?4poqUI{lBmN9h-4Qj?iut}#!3o&2o9DI<(l`*cqK1s0m6S1-IxoB zdc~H*q`@xK-P|Z*i;;2Q5C1F&xEYsHsul@?0;ctwhaoYQF7YKB0-E?h+d&PAwP9so zEU1P4W`g@C++{Nt3X!Q%jRh7)rLy$mH7PgeN)b4qjUXx%(L0G8RQXHfO`*T3j=*mh zZ-R$FkVg*v351=%U~K|ZwmVAe%Y388dpvpDPAVU z_hiHn0#q2ufybuIkJQp~hk;FHA52i2ZOGlg0@NIY?{KHi7Afw}ONZ z;21=~&!4krH>tyzGz?Dqs#;k!FKhm>RPfs&goi%Y4mq%A-S0tJ0@d&Yuj$gt^bRq@ zn(hlg{9H<}s((!u>DXnQPIq;dprXoIW;5jzV<!sK^9qO?I-wfJAoRfz$xs6yD8Hje3+{~y)m|Je5iK#Tqx2+)hIgb(cbB0)%KU*P;s-JsW( z9s`+$54)kwi8h9YbHM(Hm?SST5!hcy^dS-bXM1-i*#YLf78%e9Nk-|rN99FQ(94rv zA4@*#B}I3u8b(P~n*b~$7wz-M)9tXMrLeL{#}g6UnQkPp5L_CsOc|s3F{=%H>K|um zU=#0oeka<$G{~jLB>kJqj2)e;aU@?^`556{>MYMAh>RJzJo%u8!lyTx>Id?IOD-6&2lu)BeVYtu-Pw)pHFH%&3R5Q6s?b))jXGO_Xjju??rH~3zMGoF({Ogrub_q8YFk?Zd~H6`Q`>$+xR#bNm%uk|EfWq zG|}|5dJjk9o{V9^^#kakldc(}0?y&eiV`Nf`9K@V6%Gfl;zc_tLZ&00pBrIt3AQ7h9x>sQ^ zT|C=**O;{`|K@6Rb3nvTy+8K4c=p%M>)@^P2p7Coj12T$bDWuVKL}j@{N0uqh-RqN zSIDza5dzXH=0jgbVt|K<%=}Yv*G(W+g<&;P4#3F%Ux-P|u?LEzFSJpl{2qZuDnKML zjR>ElVa+hf`bSAT`CJh-#t8qDvaEWxsueHpUg!(_FHq*XA--VrM*=Z}MT zIjIt#-IQQWJ-Bz9pdhN5p<=pKu<2{O<*&*hl?+llU50~ML`&)!%u=}B?Y0uk>aamr zO=B5xNpStZE4=n`c53zmdJfYY-6e4&tpZv75R^FFduG8ky;F?)#t*2%(W)Ki@nWG{ zs3X?TUw@Jy?_B2wJa~fzY|XLo(+HDipY)cqNoDX&*P;!JG)lq2?UtsnSKcSG`fz6& zU7-|&(bscdvaq(}da2LrPz+?r^;qkI?ck=O&1FOk4IiEpFz`D3%lU!~w6EaK1NU^j z*)}h6oevV@w=lM{o(f=`+(AXg?l9vgO1GxKtadx-!JQI_H!qzr*@t#i7r+S<2T08H zbgBL<@AXzgHV%~4BzPJryr24lCHGYaajR9)WLn;cKVw6dV&y)HMdFE24gke~IdmBr z6J|m2AOjAscKXRMI;-37s!sX;=Ejm4Rb~NNV~{y3>RTWj5G?8XS+Jiu4|&}I2?_5~ zIt>d^;mnGb_f;6U0GogRjm2RKG=>D_!-iw zE$Lrh&HxvGotdFdf%YveIBVJ*H$Oug_&H_!%e6Y2FNhY@6EV!7w>Hv@0SsD%#h+bY z*%lDgi})AHux4atpJS7|gNI{4p%rZ7U#j!h65nE_{w!PO1v8d9URt?2#=9hFzTkoEEgS1mP zjLjC|@%r)pBexjrs(p0E@!c8Yhyv4=v>FT)Y};<)2N}DpouL=~3n!vP$Z^Q{?I*_7Q;ZV$%NFS&ZT zZyn&joi+lyTN^fY9v4PXz>8U1it@M#))||}?Z>K0M1n1}UH@nn8+P71E04MY0H$hr z?+33k^x(D(iRV~%h#wG+=uZ7|!vS~${jg-h1zBQ3i$zLvek=BO&gGp(!e70ree5WO z9J6)iRkGslkms*nb5(V(2@>@a_v22REiKdj;|^(YkdOlvUb4f|%AsP!$oZ%H zw9RIW)c~oo%s8H*ROY72yV`TW6YyT>CGsLLtxeNaT{FW7KZjy%pWfHM^z z78frRpj_z#rws32EVvM~@YybbQ2Ryce*xI0?r`q5u|CxV>PLA+DQ!-=qqKbFA_`%t z=SwdAkz~u1s})Zb@)=`gCHLbE!pfOZKGjtbV`VaS>?OER;>C=QoByCmjRYCj^qFus zUbskWHWQl4aMxZYK{rxKWR{Y@9%Y6kyI`A8E_Ug`)P zYnP)-+ZnRDWmce}Ej-!{qQCi4iSbpWl?#jbqEDF8Z)Fb7DGQNFl$-Z(%KJ%;T(9Y^ zHA&g4GB~pegC9*4(G`vhv6LBlGR?k@ASiIo1%!p~oB-sj_WnzTOh&AKzXolbjxZM{f)4*f*m$euRGnwAI{Tf z4V2*j27;sC&_DE1_B_jpHOpI+W{7aMiF3>S zz^Z7=!yRGy;T1^=pnyqZfl{hhT^(`+xl4~oV2)h!>h?GzdJHQan@q$h)JyXJ?aC(0 zx_ciI>i}y$4Hw?Hk$x;v{9^or+MqI^HFydlxSErr5H?P=G1JR({y@pSZL%*MkX5YH zAqo=0C$eoc#GIZ}JGrSu*i0nDizD)2spoRn>&M{XS@^|M&~OT8%Ive`ql-8D0uK?n z!r_r2ayPcx{2BELJEJ(iC#EIP>ByZ&ztDU*Jt>0@vD=-lk^z&V>bI8WMHHzT2HSjd z2wfwyAbBiuK;eQ0A>Lp#R!tH9Zl|-H73<5<{ZTt58fqO_Lj+La+6rgIs1!(pT(s0h zD0m=j!(2EiT^p%_dqeOg|Bb==NeTyTn@;48}G>TvT>SD{O~?f?%)y_w>@s00#XgBd4;512v^ ziF><9`Vo_el9Hk1eB0O4^r*yanPvOQs6qEDyANrl`yJBI=w40TBt`}TPD&Ezs|VDt z2j=s)A(XNm$ey*0Aek54Xray2&*u9_l@2XzN9U-BQN%F;_r*9Qj3#D=Z<9TAd>>+? z663&1IFj~k-0^b;4EwQ0AX=YHAQO^%;bv=(YfhNCR+A~J@Zprc=7rUxfbVRGeeGXX z=T9Zj`Iv-u=_v!BdG5dZD;Yd(TBhLbEYdv{UXSwWvo zMI^1Rsv_91hX6Gan;;C$y~UPmZ;KyBDyp-N_8k5%E&mPgj5kryG4oK4C;AnsqP;ddsnY9ESBduydiSz%H)!<^465eWE$(f1M7evCq0BM#&~ zA%gQ$e7tqxj`TC>$8x#gU5J7VU^pdzW@NNt{#Ma8Is|f=r_fdYBpv0R-ZBE`XKW2t z1`>^hEc2*wZ8J|Q5isBasT<1@9)%OC(e4hA9ubirsn}Buw9Zkh0RZ5c0E>Uwv4_V& zHlbVH>c3DQObI#_?4+~)SJu!?l?UUYs{keLKuS(5+{CG&+uDH6K>&}phha<2v}h2Z zgyC1QJu}9%NqCHGF?RD#Adx@)eh-C_rOzQ-EnOwIbK4w=1URJtQWelF&6)D4LDFmm z_JDza)Odv%vM-k*$ed66BW}_@-USm#YN-ySnCW|{eEZQS*sJ7<(OG<_ z#ANBiWffO&=1`=wKK0X}|PlM`QE+M4h9JQw$WJatL*vI8BxJYxYmG|f7n2lARg2MNxwiy?DJ1(E_=;Kga>U3qDE)XDty)GMo(yf}} zICa*qzRO6w;|Q4Rl#ev47-Gk(-+RdF=w7^8^X2(im4B3qItsEZEYH;cJA&cb2?phN zCZRWcZL31J*(iJ{e?kxICRe9N$Focz8|0`YbmGYY1hXk+aIYhSG zin}CI&uoBk_43_#4A)VJMmvu$qQua`y$WS!=6NSybqBxpkya70+rTs$6Tsg0`VztK_d&jWBX<_cZB!^N%aD5zB{?8;^d8?^5uIuHmBa~ah;|6$(iz_C zX|q_7y0(c;bBRcFe$7&v;zS$8Tndix9z)KD4tfC7EeT@rE|w4%#77>HbOw%p1I;+W zpMfBMb3aBS#8n&zKgHAH)B+e#=ZeVN#)HPx(6OmDYwnNl?G2-m#so9-5A*z>oD?gz zv%2HqfK_hGD!RD&T_&##jh3NCquYXII=NK}L)?Qz<9AfcJrZn&$UGN^XqBdRmyCa+D0+D zJdmo~aycg;yqzzoKoHG9E2r+a=Mw|-=U0bJN|dRMhabi==N8IBn!7F=OKl3u3d5;V zs`pFzx?t?>ZubfIB_=>_-2|Iq(v`++HfOAVlKR!n7pt5MCLlgI-=?xCx(H{ajz-04 zLKs3`Qa@MjUMaQfX9$-)Rq$XBj&tUjVy#f(om#HB4N6;N#ahbBtzJh|m6a*wWad`g zWj;xmfAsNNgBfqO?p~mYu``Z5>)ouz$fn15(Gz#|c>TejmmyyL*R(U9at1k(KHqJe zE2pTL8wofW3r|X#4=QPvwJw77^Pqu`xk8X_(3a0c#pe|=#QJ{ejx;k`NJjeslFty=cx@8Qtt+5d&<}%!@)$ zOC5B2A1+K)0{1?D&_(^QJvL59Ss$C|#eT;?@qm$V>`^z|uQQZDQ}6O}HV ziPEFxgOb``flLq|s01r2*-+2k4zE$mZstkP-HD8pp+_o^qE7>ZWq#t{73oz+me+C` zS(!Z1CE$LzNe*b!ldk3&u~+5pYF7XEpoS~1sY8SJ=qPh(T0zpXtuNX+YNqmvz|>O4 zr|{aU@CADcUJ?w}1kP>Y3;X7>mI{-AQHi8QgY8LCCP7NLZ`Q+T-k8URo(`eza0fi1 zv<BVL4{<+9+Avw5Tqq!+%O|CWj$ZmYcYUg*Q;Rn?Z1hojN0lnBu< zSEN9@^-Tq;1+V+HLWZ`~+5=1jgRXt|V)pB6f4!))|010+%aEG;>LDjN1sTE#%FKA5 zUgJ4+@e*gu9sFCX?o$)L$eAiIoz=es1d*43xPytqI!!z7zP8AyJp|!QxL}}hACZc> zAG}SwS4UYc$SqfeJ+s5tmQXf_`WM#2c*`@t8mVl-OjOq2G7YP8jNH9%YU!A5d-xT* z^j{=Xh1NZc@A5S2x-P^<)U7Nl{pCnHa6}-%tec}(s1Ot8epI7T0-(8Q#pbZ|!@$3a z?&h+fXJ)_DINp=B2lIe;ztE!pgRr-~VpR5#m;+ZG8y6JzjF<|t4C||&Xj9D?c2sTg zqJ5l>mevhlbv+6fks_dX#b=_aBcA~o&kFdkvi%1GBwn%}B5^Bzxb9ylHNs^Gv6?c}!;N!B%EN9ZxU} zJGiPwz3=2isQN9Qw+GNBh{DB#UiTHDi3sfIh7OwUSVOR!f0B56>Csa>2IxXamTMu= z85sALAlTyZTor%s7y_=JuQSQ-&-{l9$(u;N(|~ zzFbXP@jX35*UwT1>Aj;t>@pKNBt4#k4$6?=LHbUzCJ^dyScqeAJ-^N`-N5EiK$IA| z#z%|Xr#E~)R{~0HE&=`Or|1X0dn>_)>ZZ9mxEYb$sQH{j8+qKUIXo|*b5<2*W0NZm zxMo|=eoJ$qK$ZlyT-IgMsodzIp7_}DGZx|uuwkf>x8KoGk7JJVRCBzyeD|>l2R|gB zt8HFgEbsl~hCPdY%;&HwhX3C1uoX@&bEbPCRvT=M78zZYG17bn*Rw30%FAu}J#DE7 zwhDo4<7*j?Rq+E~suGC6m>EyXS;(&~1uWS$)#GjzW7M`6Q@}WR8_w1*G2_N8X=uB! zx?*2?OQ-l+K<1Y_V-k7N7&}m#Wy5g{XVR~mSrEIYGX_`Wm$vtK z%2Jqx;(u`%R2I0gn>`rU=XJXd3aeaP00gR1*0-4#62o(jc=PyYFxDMZvb!m~_| z5gYJD1Mv$~rPE0+%l7=$`G!6H#-e7*OS78n(-FzVg&nf>;~FWNTM9AjBVIwt)W(B{ z@uuhcVCAErYiyjm%lz8k(Rtul@B#RkhYW;X46T%ke9D^K8SX;A^Tkqg5oO^|%Ov!_ z#1J#*#DQB`{T96DWt$yH6Cy+aU;|698h29t2TTe^%vAImFOQ6b@?|m{`>P1~Jk*T6 zjJ5;xNjm`Tf6SOH&)HZn1rpaC!ZVwA-pfzucSEpwI8o;)$VBnrW?B9{J`&YMBkoo$ zri8aztiNcZrB-XXUr@fD?EfV+*u z;Ot^xs1J7W!hF*FdoY>cr0Z{1L3w6`EliHsfDOkIbacrQOryQDP2o5I-6)JKo%sj) zftb7;e!2xmIVuWlf}oUYr_xoFPDWWw+7TtwkSvh)3>5b_ zS|8)LpA9s0hb>FF%94muIR2A^DifMAg{VvcafRm$n60m;y`7zXbp%Vy5}Gn7P0d4r zCB4|7yPHaj;W%LQ|2y==#|Ld=UnHRALM7sq$y3-OsYcc-rFCTuy5RZ1DJlNtMa6ZC zHc$sHI$cs(FI{x;WdW-zrjr2jcDNW@O9evi82aRiIjb$4&0rHABPqZ-txc)4kN|K7 z8p&*K{4!b)qzNZL1O7J+3FjWHXGLl;*xevC*i||4j+wyFJ$kyK0+Nra|3KDJ!Q9o* ztGg=hF&G}H(9-;!FVYU){SeGMYE^W$y0FrrGH(!eXuP@zsivLl!v`^DNj_>@h6UoF zIRNcDKT9Y9Dmv)WkGEW4bFYRlbqIj6G6hU%^#}noO}cPTOcTVngcwv* zVJJ~kp@AfHXZyYd@MnWt(u$9(97BtbxU+F(dTO8wu*IP0r)>dJ{{LsTqZPa)_d-^= z{xk!7(908~hDchf0fx!Pw=qsE@*Bb13#l$by1L0;^2i!Sq9Iy#7XtBecy5UIIq(ig z=SG%4h4UAwWu+hdXb+ZYes0Q4RYjn%HSBaedTCGYHGvqOj1LypckAdckh33fVsqV_ zd{|IR6WZBnNc-&XH$%vmHU#g;Jls~m6ai}%(lPfh^BFZSm0}U_02MjClpn>?(W(G3 z)SKR~8Ehvk{MWa+lqzp4w;}HWd}$cJ*9~cPViJE<;n*wbM=J)2eLF{? z1*Q@dC=B%`q6V;HtVRo+tOzbujh)r2LjgbY=>a^j+3vjUxb8P;Rd4%>WVYzh>X6~+ z4s-!<-{iYgFLBkd~eD9P8QNSKILt zmT7l$cRGi_e``6+KlvL})(dJ&Pmj4Sa`40u<{3BMcQ6Fahk%(urjF|fn~g|w**bK% zS|kWDwP06OdCawh;|{ZN*O?ZzQdE_bOK_zh8O+#9lDFLGcn5b~r5F0M<_4VW)upIX zdaLT`-zxkW0uYB)gM8QCGdO-5ywgOh7VZ<{#@--<1HWIQ< zFe^u+=nqX&{M+5W%iqUr5dpG8B$OvDn8Ni}dvIOGm;w#3*cLL8Q!s-z1V-{8h9XO( zvjjfSVJM`qP6h5koOtnIi_F8A_RhP+Mom^yp`qn;R1%YCE4rA%nwgPh5tO{r2 z+B=?=QxzqB+(E-LRZHTZ_fn2V4m6YJxw)qGSJ%JXdMsV|b|NN>-jY|vuu zb`94JiH`H`D3Du zcOG{^*o!laT|tE}>kOUwetst5!aq0uho6j&!4s&)MX=}|YZNd=%1Ff6WX4IRWpe+@ zamX6`vSbR5GZc7UDYeaNs^nNqp8O7>@DenNPGvf64)irms0Sc(8Dey~VEFR6L>}KJ z-F?#pBMq5aF*|TCqWz!ssUG5c0QCVtV3?5WSHs_Bfun&jr%UmxnL;yl(EnB4Mem`H zQ~}38F_!6gQ%Xeylm%H|g9n+5kA~nOWv5O-KspR73g?_8U-Ua^g^)sqn0lk=(g%e! zX*|Wn8F$P1Z4aVakne{)RM~TuDpQ9@$UHe$JFbCxsCoE_XdDmp{K|=6g%T>d7gJLm zg;DQr(s_)@qH(XBVZhC}E&c#o#)%Mkm!YgUeS(>wENRj~2I*Ql<`dy_h$j1KVtbHV zf^y_=iT5i|MLxebh#-#*1Wqe#s1)#`;GCF{FuVAicgKj(b{RzizNUI=5%G3)I;G51 zLS3Ovmew^9fic^jV#wx~8iepy{-|R&TMlG?9uoFPFy&qj$(gTNra7>>_$_oKiX<<-UAz(Sv=bh~{$ z)EIeR>p{e`&q6~QYCphD1O2$Mpzp#ck-n%W-R;4(K@Sm(b;=*{a7S7#NsJJTdj@nx6qpaU1fzpTtW&d+QHC5d=uB|uGYa5|NR z$~_+EIc7O*__1wSrUoiZf;VlK1BWR-F^4rqa(M=1L&F_x&mZ zn7>WBlPqsO5uV(&WXuiivHNuj#2IWj6uIUQcv3l~lV;x@WA4Vk&>p<4VYEE_Uoq0QNg3v%1QJP-;aTU* zhZ_ME@0Tc&EyHPY`c{eJa1bo);5jy!)zqbO(oPXV=)TcY8mS)_E&_yR03x3IR znE9ZnSqhrMS!I;piTx9)(v&c7J;CO2d?FQBt4)BU_MKrM1fQ!=MR$#n-KxJ>Cyv1{ zYX)oobAuIM)&|_79N384=%p~GL*@~ycbHQKMXCMnQ|rx$c3ZWpYN{d;NDXn}uNmc; zS_b-2qUtKj4LtjUvfQ^D_rFwfwuxa61@Tc48Gx8fs+ml-PtKp|TTze1-vYlWd&23Z zPN%YR$--n80MxC-YD5%59X0_HOTi7T4*gKPP_hvZRJRLDWJiB0XB41{hr1vc8S1zH z&I%7V8$Z~MhK`UTZJ!i|PYLA(N1mBbnAbgoZBVX{$Gz!tCJsBA!=Z)(FsvUX2Sr3{ zh-M3aPY;O7-y^IS`LUuhV}KT}1i7QNR$8ktU0lY+K@O*o$dOwDKiz|R_hp4+ZseRI zl5Daf1#PbLRIyvf9t21%Qimg zztp)}VE+b+AYe*A&uzKeZ5L;y0Q}Z=@93Mu=M^RS2F3v)-panJYUYJW z=J|`!<7i79XCszV~~{P#ZhMP1&-whelg^azr{Zi%;r@}Z6ZiDIiURJdYxvymH-#C zv>0U(H{&1MirK@cua^ev;uzjH`3vV&0*My9x%+Mos$KfuNNEcROg5nffL&m4nQ)!-c($ZCIBWK0`(aqlsr3=uis?XB;xF&ydO zQnfI~d=*8WH)x8GDug4Ozm0axm+QKQ!0^Y#lNtf^Pwy&l)e@hS_z41|{9+u;D>;1u zcNv8=w+J!VBV^fKj*h>6FV!v9aUTwgpg!1$Tl+u9K>*0CFa@$YNN7_lg+`SswS$e= z!dteBFOcc#8ttuGm_O5Q`|k25$BK?-UMh~X2^O1G;pQE=a_&m2=-k)=sXF-XJkQa` zn>Az~j(eAu5+ASDOX+DM5OmO|S>vB}Ib`O%dUI!2)Mh`#25!HnWEXzXbey~#m{is#^*o|{`+z6TG z;5_uxY!N(VnMp`a;t^}9hcLp(kW(gM%q~ISxgZ1fAhJItH4+!8IQ0M_xV+@@>QW%1 z+>0Fk08Ps|X$bSuud!A~DvAN|e{WA=xLrgM9~8FxYl=vRL-{s#vJu^wZEi%Uz6)LN zLdsr#gBA_Am7~49i}Gic-Pk3CEbC@u5A*>1wcrStw(h1ep;J~zF#5NRxm#a%wGbB1 zP!r5UA&hhdH^!5BAi_;bgTt(aiIYbf4R~Z#405Eny6G+b|Ihwh<&0vuXHqpfrP&uLK`R^11z zO#pq;DEEf+1xv!WO#tPa1y|XluBBJIQ3ey022E$;MZa;N-T}DldMG(u1JgkCZ8s81 z>CGc8F*VU#bfa_lmz0n_h7{Ps0? z(TpJ7l!Y1vzp4%}?Fm1Q<_4WjT3ocb%)K_)92dTo%nMJkB(w)4W^*eg%zXtn1}`SN zh@;E@mkxp+EU#C)h94PQ5D zBhlQj8M}+b@@M5w)(ZyQ${5l`s=+`gQ9A4jp@rhS2SR&mXEcoCpt-}a%^uspbZWrW z=~Q~BKhkLNa+7B!s}`iiX#~T5LdJb6WBO&{!$Ka6iV#IvQZFGJF$Ph{n|(U~#~cPl zUwW)W$$WG;bd_BlFQ{m4;Ai8a`GiHL96>>k^N-uR zRevzkf{yC~m+qi| zG!S}e2HX!-RK-fmn+RS1(}G29=~Gq1_`TJxs6=%eHr)?b%CK>{E998o1YlTh_yBh7 zwq7KsSGgf28>`Wh=vAf-arsTuxg)e^Ps5srQVP23*xnuW~L4rGqcBiUfdI<({DX!o~$cf@d<)Hf$HM>Chn^# z=B%qRUtc*ouhzs$) z$~h&nbogUC4~UZPBZ1<%WHMUY_yP8@h0 zVKSoB2ZFl%R_~xDacxnB!cE3Hwhzf%5C*TT!KVDWKFOapEZAJW@g>&=$2?N?CzB{E zHo&=sZO`e~!YtJ{zlu0$9(CWjEALHsUuJ2`~@3eAJV zFQ}3fJONwj#|A`T2MK47KmV9wwFH#8fTyYq8{b%u`YtHNE~`){l1R{-WDVVo+D$R5 zV*8cT?0;+Ioe$#()%r7EKkF(-@DJ_~emhkua|V~no&zunJrS4#pVBbkPQtRtK>I!Q z7&5smAO$?5h0>Q8O0x}pwn>MGl}Ccv1w$+`#l%La>aIL&Gc6loTep9!EUiHY z@)z*cf~EqRx@jw-aIYsZywvlG2rsYFyJ{{i2{?dgk3YROVT_I-sT5YG*pb^k0|}z( zg9-^H=e@Bb%EFybO<*p#Ik9g@lZf|j8*yWswF8=TKab@mGHAPd9O}-v{}EavH&iik z8T`zVda(PBS!=mq%-PW$EOfLW+b?d8%HQn((2)FgJ)i#tl{~&)iUtd+?4(Rf<8P?d z$h?(WmtR?r>Ujo04fzOu3o@S*K1V!8;!QQ6RxE4yFVVJ7assoPj7lx%TiMWhEb>r% z_1q$S??t~!3|hjR9@GTv5$ z^w1(GempyJN6ASEmZ6$Sq@}syF&6O@Qa3*tQp zUgn;)@+(C@2oOJD=$?patFT&efJg}GVtjFf)C!Ni1Dsk-^s%dGXbP*=Fta@WKj$?? zwnep<{}N518SO$vM3pp;-qse>+=7>PB^Pvbfaj@DRK+d;9Yq|8u5)K|=|1&O#Ebwr zCl4JkP~uH)v8=pf=1=2o{*9p3vP(D1G^Bu&F=s&(LgKE#>o_)`1Cs)>ArW2+wGg8b zGET7TH#JT{(X-YdzjWE~yer_cTfhg7AVw^tdDa)=*X0#_X9(pjv0M(? z6aI-JfST)D7+z|4!o`Ggy(2mWeIFWPgBe)3D~-c$GUWQIh<}w$?F3OBrQ7kAM)o_@ zwhQw%`@6Dvi>nKp$4rCWC9s9qF!iuuqc((%OUT2@NynSAaR*(LfvvYlNCwO5;*1=) zS0B3nzql88B-Uy`lKR*x$?sZUM1+_igAEfPHs&%dqVsrY-u1u@?X{ zl?=b1Hn7?FX!&3U8huTfOl8b1M@^L1$r)*akHc1fId9Q?%YKfoFrvYIFE~IQ7~XHz z#NJX!Gu`e@Q4&k!LgmG3?pHK-)&tdwm9z8;jdv|pORKRF7cQMetDYi;5BDxkKNwU} zGqL(8OccU~K(sI1KH9#(n-Pd>RJ@yupKLiNa{CK|x*S?DU#>=d%0zyP*}T1%dt?Mu zsr?Sqv4$X)mzTWQR0*IVt7e%h?V(S8PzSYTB$U+fImC;MF_h4+3=C$sO~id0Wj5@} ziD?OXIV8*|HVVXv3n)oOC2lMw*U^g&FjSxd4QzIdgLPbpe7ff+q3?s1g$e8naKN|G zRF%jLzRmejnbg#T%H+(=T+3EF62S8$>1bI^)ZAw~LebT-OvQDEj|;?3?|2}XwC0+E z$)9b`_tqWyIe;md*wmbD1#b})_EW!y&^*`-G$iaXd4F|W7I%Lh~$hWx@ z$!WEhbwXz+yzCG@;{C#fV4HE3>p;KI#!s*Z)fAu=lXiBT#-jmVS}IwaVd^}Q8_0v! zu+Jj3*|h{zkT2ojJ{e8WZV*dL%%b$YW(>!TZMiO@(GI3O8~F(9>QP##tMH<#IA%v; zZCL%BHt^>4&yzQ3`E`J?$ujktunf^kj4TRwvrm9P+KnPkuI8-tHTp5TK$aApKRfHB zEJACmT-!n{yzczPmk6>3;1KHt&+Xp+awq*2%NK$u zWVfr5Eusq6K>d`xNkmr+;5o4jEArrBx&vm?(_SIYyg4cGnG^>2@6KWqQx{5PS3J16 zH)}&erWbEmPyls*a)vjl;t=&-yEKsX^her9C3LcHiinBWkY3A5Pz4tOkI{TfiM~y9 zzB*<3>p%cSK)S!%HDW6*Vi23zPCZfy&n5u!XR0*N1Wq_KN=>HW;R6zW6MRavfYf7; zI}f3q%GGwv^34pc?Ia^>72_6j2b>6Rx92OXV|3@8m8}x_Y4sEQZ#42~78dd1=B&72 zTp?tk((%PAo}l$e#dW3jF#}x*yrk^$0idR$Y5%SO?KTE6DlR}2Fx$bSw)bz{061yt zi(1nvp4&qt=ut&UQ1(6Q6bP_1*7y;)gCw8tN9Yb$`kXnNViWtIHKj5lZ-%($BP%(Y znc&MPZi*(q%ChS_()pIp!!`+=ypXtgkkt}2!H%5KTFdaI2ORXM)L%eBU{$0L#rNp` zY{qKY1=uv(cVK)vf*Hcui+fxfq1FJ2QI+LbUox$l@Do|#LIQibNg~90eyb;wVdt1VP&2QJ z%LV)bs}NV6k86}3@p%ULE2Pm!=(j+&!yE=>bO!S1E7=;ft%Z5NJBNRX=8RW34cbNr5 zC(jm?YY!nr1Vwiab=@?}_;evDQVw$%_IX*U4%ZvU`Q-k5Gt<(oDpuU8*TOs{D4GVsHyJ zL4okidj2Pc5W#@OEW=q~hN!rj&aQz~4*no3_%h!C&0o9GT@4LW9VFOCOlDtyDZC}u z$*s@E5!K|&d||pabZV$-5#XZUx`~bKT2gONjM+4j0a6*YBSSdh3_yL^S}7e0@QI4S zM8rF?#K3nC0@26qbs~!|*Wp|KpS7mp)P0g$Uvc z$rY$qs)iqykSwmBVuBhFa&(^aje5$Jp7m|?T~oR!F{6Yr<20(XIi*8$ca zEh)%>!@HR5qx7%68b$&f31j>*W&9*N8Y(?!_DdtuEh-WOq$vfQqX&vM$^;a2r5Z3) zre5($87BaE-?j-aGLgq!Tov!)KG+F+{s1~cSM39&oC)Ye-|G^8OgP|@27e*LKGhy< zpr7pEgYF0%FL*#Kx?k{u(##H*~bML z*FB1c(e{Ec+`|G5yBBl9MppAflnb=k39J7MCQjq_aQD9#n&z3Rp!{%v5C{_LPA#JZ z;EB64lqg8LjPOCCiHRez%{iU$-}Y{HW^91f>qwZ+CpAEqaa=xqOSTWQ*PGR7Zb3Hm zKG}ya20e*>JKHx?ucK!&`hGyL-XQi zY^~vjd}yDQl5o9=EjS03ECQ4DY8IZtr0G%TJ7rP3NEB0gRn z@bMP>VnbWwS0Q@U^FtI3*8+$xPi+=eu`B*Jo)mDvs~5f$i#I=Qu=*$HhFX+K+mU6M z2Ky5(Ax>0iXc7Xwl1XyLP7*f=w?CZIbVco1@`#N_Ha6ykT1-HwHLMBJe70@>d-;XD zR%hp_lXw{5vLVX$Y{8-bmp~lAIFxT3A}Lj9#;D~svycHtaQfBzBP-2l3*QtViHrh2 z^kElrO9y-aeVE7!Jr6)IMYQK!%GfXkYmIynhP?OzTuA_Cywc3wS$qsZB(6fZs;m~b z5KgE>z5zL(T1!7|=m%2%P2Tbb5|?%iJLkKVZJzUH`J4?nAH-3NYKgs z3NI!nAqwyyjV{|4R}~eX6wMAMt_sMSLe?D{0nK+5MbE0k3mFLEL`oEL8DMWGkl@Y~ zji#%1QpZdmQg~tp%!Ov@^WmVi`k1v?>y7IaliGs zCZrzyc8g=7gIS!Md>W5xA_7!;D8 z9o7$t3g|9a#M=*K6;F>#4T7;RcM$=OhfBLzN-b5Ei{YG^LeEij{;+ob?kYx~53Z&p zk(k{&)3D^T}7w#8J7><2j%_yxCsZ_atxj%t9IP~kkaKD-9&d^~ri7F3w znAC9BK9Ym2v~p3f_+JWKKdfz{o3tr_Y>?#z)A*3PKqTRf^YACkq`{4^FVQr!gR3$n zz6EiZw68rO50(YvJ+tHXa?SS~pO@Pi#6@DgHwvdr{Pnt1O%=VGb28AaYK*nMzyT;l z3Wu?Hq!kc-3Sa;L&e@0OthP%F`O>2(s4tu4X5E5pb@c0tOl1)3#fEhQ6SHVLD;=kS zI71aDDPN%ook@Pg<`uxV;0|@UvEMk7t3}`DJ9u!x5U9N^6uWeZs!>QeotM7A`4&VnrJ> z8u~Ri&1*k!8DU*70TX|3?;KO>1kdB!d!rb*`o}uNp9?vUnov+Fp>_{7Yf@#hPs8wN zK=fhPdRV+oDF_I$5&ttU^1$gWArZq0c!9@3u4)zW>L*&+0=8RUaclo^raZG){VTei%yT#K$tH~KKODf`8=z>qgzG#Nd`hx{GnI8NawU4au0_N|9=I0jTB1Mwr3^cxW222wL%$PZ#)?uMDB zpiLW==2(@3oap-We|HT=SE%A&-{rJ91?*P1>`A;!im34uN6BM zx4<7(opcx)Q2-YQOeHvDzh_xD3*0=16U*imFz96Vi20<@G<;P|6qxvCBVBLsi};U3 zFtD9dDSQwK+#WpHNZX_)7VSoDl3OAuMe{I1o}l?nh0QWVU9P9*dDdpzJ?9lboxk9W zk~j;;uGURWs=Q|gjS`>J$GeALnq++CG9}6VzA`O`SX>BizQJGbTf7NJo8c+<^)3@u zJ!&ysAh~vB62l%2*ydEsDsO`ii5YXKfQ1cgNJ+jcuOKtFXbTlhN9e62Zx{t8wDcxu zi{dIFIhbKxhoW`FAd@&zv7hv4Pc)?d`9+F9KLj&wNNHU)2D?eelI#}tH@?1#*cr|m z;h+@vBY#^=ua9lsEPdXJU=d1~0KOJ_k*h7g-F8-TdBl^4@4pEJ0&DYX31>uWZ;-&QT$AD{Hstl$TbkjZr5wl~iXbDQ43Yv6eZY$`d`i)Cv1411^d0lA ztKsn)HaV+Dq`$(QImpgQ}$*&75~_^q=n{ zbo!P2YQ}MUx8`F5+g6)O4%HZd^;{keBCLd;&}db@HxX?veah~!yZ^Qo?jnt9usH4a ztot5`C+>=F?DvvADW?ZJX7^0iyrMm|peHd4d5)jtTD7;0?mwvg!nO>w1H7Z8)f1p! zfP&r?=Zo9iK`aB~DUI*5IIvbN@suRJA~N5>5VaQDhOQcwFqgC8|vBd$P^GWK1L z-`=Ry6`dCoZ6N5h84LdRwK10@`Pejhaqy_pXYC5VUyxsNbNe4YsGrrh|IVQwbqlg| zycP$n>9wdFMYrR-zOt#z0CtY%7hH!~{-Ozo^?G55(~1HR0e{YGxXAgsEU@jEt(zAz z(?-%*amWzi?wff18fV@lJsEseSzbT<5fi2tw;KtKuivchmk)3`llKjg6EA8;S&MM;Rv0xajz(xCl|Xx z#BMQ0wl5}vM@md8k+8y}&{a=-*B-%+FH4%LiK9~0IZpx7HH_swT}^nHpgK)7J1?kJ zM3=vybU~hYr#)A0N|demh==Q28Lq~Pl)B*-z4RGsvm9u8DJ9bdp0qv&p{$ejux4DK zXU=?4EppSRD-IUE+BS^Wfw~~~Jf(l35WyE#!K-7xPrFYRD6t?>eEMY~NY^Y-K>l^C z*Nn*cGeL?fc#b>4j!9f7SL`J^qV2gw`yz_)NR|>#nZNZl?}V=qoZL%nfbk zVr9spM;V}@`uotpS1Kq!cvczTA94=0jR~@8Ds`G&Z;l8li04?jr#?L1zec6_fBqMI zd_Yn*u)}^xx9nfyhOPn`?go>WG7bVmG<<{&{u#yr<>)UCTly&FzNdR&9Kq`0&;mj! z1;X9S1X|Gw#`+KopMZUgdxmK97FoSlw!P3|s$vme2qFa&J0Q}jGLOvtkF#W*^9G$y zu%{HLqe%`M34e^}v!X-;xi}as*Py)A)z)kk@Rn3@=cf;#&%5PkiQ2g|$48Y3h6Qm) ze5e#+KdXGmU%{G2DvBSR4HFyf%tiacSbZ=Kyr`_S1HxkUXc%1N86;g&7h28R!1WfG z$!=W7cWcv=!LK!S&2ZvRg&=cE{B5}-P;mryC0?M8HnQwazTh)Xqagh$TzVOY{7orM zVl&9`tP7T1HHgw4RD$l5DS4uH7Oknqf%$Jb2_q!K7d(k zRU4hk!l2o2gSy1Q`&FZ)2{nO3gsKoTgvUDIk{7&7afG3gTr!%_EG=E1sSFbFyj)N>YyldU=Uzdttxe7<5KdT@!SZay9$ zSX?44RFg?s^JE1<`l_B*r!Bds!GLDdWtRa@iF4y=o3~1-?JRFvgjQdd zpjGJ-DT4rMza$t-x(#I$?mEiD4*(2vA}fgId~s!e<dq za21ctP6AkH@_M>V<*|MH5q)Sk*y#JQad}2#1ON@K-UHs!P5EZ6XM8e=aNP=+8$t@R zPAqeT?ErA0__oCBg?P(WP7o@s1p!IBJKS9}$d;K!gV_K@WMMi`#C#Y9r_K@46wAS( zw?b!Shd~`1TS)a!ir;Vwmi{C}z*PN(tCAd1+lV7z?FR~1CJPdG>Gm2SVI!SOlQ#dLqz`R;9sp*DX0j~?C7tz6Ldo6mBGvW_wJ&^>uPpns5rt23z^R& z!SN1s|1GItf$A3W$>_G~tK%cYkyDAB-P7W{z;LDOS{aiL5ip2Zq%Hi^kDTNWYTFOT z$K#hPvU+hZfS8I#Cyp{57L-RF8WsH7H}4yR&@4hm7qVlE?VR*6vEbm9zPl7QRy&`5 zglsi79XW@JHjWtn^(I_hQ}(6CsH#k2mk=q;Kb)e+1BPczk$n8F&uF2ALeC58l$ARl>yuz z2RZcl1l370%M{}Uz`#C5WiVQ%%y~1ECP4dVp#7>65wB8c7+vk~N zdrs8g;X?*4*uz6g%4CnKkeF1`x$dFGa$GXIpvjy$KK-SH@&x5N%W^(&W+R*QAc)EH zmkt7x(8^#w94w}LjusJ~`g)C&Qs<(Ksg8U+hx&V-m{YX=ux!Y1CDaavrXKEhnDYbr zm+C$I4pRlxz^^`p)qHYS2TGz0jS?SytTnBv0jDGLSWIOhv`NnMSs=~tuw4;`Ti-06 z;A_FdgUwoFJPf`=9dx5uxV6710P6=NKz#SK%{0;leMw%@-a5cuW8Mjgv?!h6Cap?Q zrZ0Kh{J!S5rlChcQ#hRFMm^h;{m2^K-|I8-B6QqD;NWt)6N?y819sodcS4&f+(-mn z7`WbAV@krSJd{|Kj6JBYRu8ut_7#XAvND%_^lT*{-j)VB?2nGE(^z0Y(g{#*_GmeN ztq)o%X5&xwYiG z+L08cdQ$n%%DG+7p53m~wJkYQO$Ba*&c7D@@}3fwD!*_jFX6yEYXnSw@_w$mM+_zQ z+7Mm(Fl{0{!42+s7_Ft0EjWGJ(^~_GsA1jpU2kU}|=s{blcH z3gRXN25RQ@E3y~STDck$S6i{^ds`I)*2dnX@K!*Vxe#lojy~!K8#lrDaZ_U^6hQG6 z{w15P%MlCr;x&hYE@xdqbo(>P7*BI@cxD?Q6~eg~C-(Mv8KYUoBsfKpcCD478p%L5 z%K;d--*mEKm(D(T9w9=v{hvXc{>`j-Ef|a8X0$0$#GgVO*>%YiI4mA9TWt6(D-#7b zeXMzY)*O(&&#>Z=Q-^ABDI<=gs2fgBImu9MfYX2{VYp%{*z6scrlbP4a=WXR!u>9jf>j!2 zZli$a;uA&_tEaahRQHn<7(no zulO7ui)Ec@NtAh0PfTlf_)JX%xc(De_NC&c)qwghw%9(!Xex@WOr&k%mAF$|AetTu zV4H*!^?_|Xs577<7iPvl`tSp0x<84KObPJ9+h}qV+u?ztMm@zySN9awwq!~|n!NNm zueJKul^gS4(beh=na&C3XS%zS%zc{)5c&AvcB}iem`QV_xaVJP1N=W8gvV}!i2)Z| zN4RZ>{Dl|_H4zVJH^R7N1EP+fs*HJrOasl+(zwu&*O_52tIhp+Os5j#EYJ2zsV;?q{{@O6C{bTQkQQ=30%kxPN3cLoZ@IM{B2U() zviJk6h6l^DJfl_Wz%et#94?`8Aj@V^#uofdZ<9GhU z5Vs#8&%mNPT_sC(kY@tA1^eta1%~*m|CtLt757pJSIG%iUx`M*3ti6tk;I1^$JdMm z>!UsASR6KdglJjetzWp{XdP_@{H7yS`a{bP=yn;PUT`7MbDW{{e<_?GyM%d(*AqgG zcgtt#(H^TTh^E(xYYa$)OEz8XSwO-2#JL!hJ1qP?s9vQ5tkT<36GQgQq+uAHV2WTw z)zjXX;&2{@RC2#BK337s;|WL+7zU zJw^FIbP>3;6BO04@zJ2P7~2sh!|jp^`D)jcI|#n?yr|Rf2!uWH@coQoBZ(!P@?WR& zwWaP`TrSKt&G2txqWlcVIA)!wZyMf_ZA0a9`R3UUHu)-+3bJo1LR}vmv{AQ~It|m} zA-Wviq8(`Xdb$7uY%GxffVUDmY?O{ZIb-lzf}M#03a|Q15P4D*(^RE)RkfI-PJr-l zBo)yi!Xg7Oo;W$Q(!LpZ{T*a%f-A;DvSd?}LD24Tq`nt@E39PKp&1RJl9CI8a9FEX zO9Bn{Y?Y%Khxv;+`zm{_v|0OB?t|$P=sMLg16zSa-@jwrXt3)A@weEe6UiEEDwNjInDccC*>JH8-SvMa%&cT_k5UM6(&=<$1-Gad5r* z|5{GE>jTk_XDx~8PiuZHznC=M0kE`-J1%vl0mq3?*_t=$$)p4WIg@kl(00opExakB zJQ!Mq&ZF;|c06Ft$}64{r=GQrOJQVK9tD+7u8pg?eBl>?4L{IAVkFseb1P$L2Q>DjBrfRUQyhWqbpO)k;Xnus%an$4CmxOjwW*8efHb!5$mp zx#3?2*6DFw^Si$AScP2aO|cSUyUqu$gu>B;yl!#eg*t`vcUpbOxRj(sm6|0?-&;&t z_~Mt3U>?dGe(1#CVTMK%b}kUhQ2+U2*!Vel#NC0$=-+ha)M~u%K07e_r1O>QTvwc- z*+PW()T~+^`trsr`H>Z!BFP}pr4Ef`{f+_i(dY{rR*e!V4aSQ)?SiPg<#_m#+hcac zUDM~XXqb;?(`OhTDtS_V9(R=U36f-c$y5I^l5wrlr5fUqZ;aTyR-(>zzSg*LR7pDi zWrTcJTu>R~za9qwIfIGdEGE3;<*rJ^M4CW?{vkN#MB zL1hC8U;NMxQ~jKxy)r3tEXG` ze!Mm`-RI11grW!WyLJXc*%HXz1hJT#38-rxT@J z3ennLyb26cm&kQytR(;$&9n(~GDM1jg@0$0RC$P{fNyw0Rv8a3(hjv%8XE!BlJxCy zMmgHg(WZgabalezpeGWcMmugnI(&*c5y=w((#7KGeBmG1L48QI=i25d#~kY1f_a9B zt$+D)dREGPDfbyKD9DnCEG-^{5jvut^j+|b_@wo zK-?CA>Hh{~OOEDjzmWGAJB)wKk1I)GY;7y@R}SkhgT%~&>vr^Bo;GaiakI# zFNz1pYB|C`^33}zp4q%QPb@34B}X8nZK7L{%7?z>o$UGtS@o6Gzuf>ljgO zqL#tPQ04wE@y3`(biOw8%W&B!q_Fo3)BqRrvtqkL&L|I_%^gJCumQzHh@>Yr33VNb z?p2H!VNL8qhqE6enIHn-jMfPb1M`RIA9OWkTxtZ_!XqoHL`zfe;(UE*1%**oZwsa> zzOCnCJSVt^-T|EO0s{Exn-%F^HRPziB)tk>(?&Gsm40t#Di7zp?cVH!fK|RG19Yc< z<>Vv}l`%`T&)gA3vo**j97+50(6SD9e={ud)Y9JTIVBm;o&kiWj1ufOdQl zsYVm#A5EU$UK^mSh@zTz!*KS6I%o@PVck47IW_N z!(cfTFZUk>8YVF#RH}G9MPS1sO%U=drq!owyksVlH(I2t$Pfd(Uk`Z*U$QpRkKe$M zqtygu-2`v=F31+WBIPb+O!$xrMB>>|#_dNd4tB7rhMWU_sJuI>A!BAo8wEhy$OtT1 z+dHxKR3iO|5aE-?*WMw^QDmnO{cNL6KdV;sU-1xSSaWAEM@U+}*tFk|`xL()X5joQ zD7VlFE|Sz}b%sBGC1K%9BVJ?q`Q64=kCGAF4Nam(wsoh`+wmgV1$dk>-qU5{?hcZ zb;JoU#-fs_dod6m`SW#6kNw71K&pTn3}4`Vbf!jwg9H-g$V(8ey0D0R_B#pYDuxsA zv;96t>GF)IFa^CrVVv$NP;YHsfo%_H4!XipANOZK>==6m-VPTT&eMjy&1Ma=k=`o< zNgNJHrlJyLj`w(yK;kHI8#Xk=nDUMX?!z8LskNzQUq5HL0&ns~xSkYCm|hd$Av?v= zdU!F9L^fjA`0LEc)A}zOM^hSDto4F06(<2dj33j~08;C;(WniFRA~E@_ex`E`*uzz z8qS(k2;M!J)omfQ*`P1e)a2+QhVVA#>Hr_-89_s@X(kgTJY@)gJ}x8+2kJ@HIRw2K zKCPJ%nH6WG7GM9Rtsq;9Hi^y@);>E4t!T0z{JZ);vp23BolLX_J5 zd1)X@-pmAvH|C|z%bLHR2k8|D=rB=oF>gXhQU7iOl)C=pIwDj{1h9FmTF3l+t__p2 zWs1S|yEmfCL3d?WKz9(uP<5*%#_%W*4MPqW1hD|p*-#S0Vxe_P4>=OvF200kNThwV z$fV)LHY=Pg9PSdq@%Lv<-@2yJN&6>$NX(+iH2}~MIGFEnmb#o1l*+kL2xg9r%?Z%4 zNNwWPRrU*|m~ByOC66l@ZpC)ciSjj7i&FSGz5JLMkNpb5Hc z>fZs1zB4iC#GRd(Ipn6cprw)GglTNmV`gRT0YS2RDc1U z)$TGbv`B<_U1ZwuGG`+j)WvdAY@Pw}-rR{6#KGghB2G$_O??g)A~3HW3$PJ(PJ>iE z9ZlJPRyVHTg)yXPAV;o!mzl$S%b#t7TtJ*OT`PmJA5laRsBSk52%e{M! z_|YqD7wO0ZRK~ml$)6Os9L59-zH%5y)!7BGh@vA}9l0KB zDeJZA<@6JB#h1=aTKN<>- z)F-ew+4a?H4mF<*qupo;gqZ*s(DxK%;`Szx>Y$NR=`cZb?@NA7Yf;L@C#$+obM}Zx zMVxHCO5%u=w@Hky;YIi*tz8E3v>t;Ui%LeqC-Z#Te%T~WVRQ?DeZ_)sU@<8a0xEBD zT=gtY=jHIJZKLPO#Tf+5tdovY=Xdl%1uQ)UmNWj+p2d>?())4HNKMALoCd4{cQM*E zgT=w(ZTt|723HPi)<}gnogwl}+*AW2Gr6XA{eb)>E(jXe)>FP>?Es!MTQ>%=5Vlf1 zd)u2Jbt@4{WzfLsNJG2qWRdzI@I@jax5lMDl61vw5c{Zl8;WGO*E?V>iUrkM0Ax2H z`A`Nt+aux%>lX%Y1Z)>f#YL;v+Xu_2<6EfCj~ipHU#)id=8ujx=epc^(~$oskWd-B zvyqLz*2sZ7>CK<&hkLOL*5S*yso#u%syK zGaSTxq}taDEDR==EGD`P{l&VNgmUflHb-}nqZ$mLUa5S8u$kzXFbZ6$z-G~OUo3v_6EMNb9WaHuh7@b-P_l@kJh zB+lwX0K}=PMlMv8vL@yD5v^kNY#7f##CfN|hxO8$R>T+t!z>qo1(Bdz{h*WMgCAGv zosT(o7SvpGY4n&QX*6HeYYgoN{GgS^ZYicI4vGcVa6m`CNkyIrS|9Ye16%)QyO@ND zmp|6=93$20O)T?9(g#uwK2aHNRFCtn%47<5k0;6mU=mx89F5%tY|dM-!1;`1xA@_T zC7)mb*5Zz8(X9A|QW6pt=>i0^E$|PM*Ko)7=m890W|6(Q$Dz+f_oxY)x&mtk1YXvC zGz=0K`?+RLCv$5sExl*o+#MBtI%LYpGE*5mbI;Gfv|E7{3ub2BF2rY?+@_uC;aFh? z$Zx#(xXKdnnjKT_i{^kYjV)182YI%D znLQ3ecY=Usi{w*p3Kju456S6Ft>rNl=H5BfQjv;Eo^Qei+3JT=6tTH>rK`H;I4u}< z?wIw_ACDoX&OfzNYHGPXtgkE`O=RKbvbp^?D5c%nDP3$9ZGNPjP>)7N`wR+=KB5BU z2*2-8X77n=PG6UsQ6a>W^`d~-x3D|wtd%)8VtW(Y_=KaVf;-5(C-De!I2KU{dh!#< zs*3Ii69K(yZ;ivaW2;o1n=0bQ+U|cdDux_V3Kl4I1@Udz)aMLChoB5QamnK5aVE6Z zNBUX)5x170Xl#r3lDrtYcW3{68Yf+xYf?+!W0ZcOqvI1Z{vbJ2O@cyT=mZdk}b^E#r^`*60(zKUSsjg3dhC zD~-3Hb5{H^Pa5xWN{Q+kIYxfdUx(I4*$W7}B{}FP-sNc>AnfYr{hYhU)aiown!XN zIK>=(c%+FG>E?R&b;mLb*Pi*Vp~UjSqBEg>IExo6wR0T{IXkj zPZiiMSV3BkJG>c*eoSJ3tKQ+pndKCapv_wtT3sc2UPp^sVnWXV74Q{QI=7yEE~ zrcpfzJ5LT9KqfL3XrJOU2M|&9@KP#pS4l;;;%1jKPJM2X=~!nG!wx0O#aSx9uFJ;y z8z%viu>J-Du*H~2Flkl+RtodkC-l)G-OlN#n-m-&nl44!?sG99ONO@R&75y1kPrvd z>8lH6NQ5F6^6{WEv;`0j1VEZDWCxJ6Nt07>QN;CWlw($n(Ko~@Gb4g`@!t%#7hqsQ zSt7aqX-obO;| zvYE$y{HHsY*_PxP3ZSCYzzwzzDGb$A1q8&k%uVZc_C!%Vu09wSUYJCi-+DKwVU>;s z=#(J+ZwY!9OQmT0_ckG^n*s5j|3{nxo9Mp}O1nA4zrqR;XvbGu4LTdNWw&w$<#Wk= zRjwgI}R!gp$yE$9woT z6^-p^#3P?_)6#c(M>kZ|%nW=7VlpO4TN(oO>Vri5kEg@PV!-avknK-r`m`MCSNlDD z@(QLHD~vJgYIR0&aHR+U4HQgBqbRV+jGn&umej!x;P48Ut`A@i*DcmImfq1~ z&UL!F=@E3qibgekE?*U}tia)=Z!I{R>a8=f8O-7ZPq{k=CN(X+Q8$Wb4Nu||gU3^< zZpI42vV!yf0C5XDb-tplvY#0L;*@JNamQry0y5r{)1Bk`#p1DBV^0M>sd06c} zh^Yzr!tFvXNr*CH?(mN0^LrGDd`w0?U;ItrB)aBW$YvJ?-vD**N0>%@Wa4vN=>Iy607d!c0w zP+NFLusubc!Vc3+>iNx=#n0TymOSEk>7xulSW7wF4uHh6n_yR=>MyV}lyzMP5I#BI zIHS*T6a&uAAqGLzg}zHSLcx;Q7=E7yU!hJwxd0m_23Fi*8&g9yJL|P0H%9pQ&oI8V{ zIAF%(--k^mt;&k@<5p>eXBhrVRD~a4rY8}$CJq>L@vcAZ^HCW_rSbED@_em^1Y^t$ z`DeZ;?cVClNuHVRwSI>CPPAj?V#-thB&G-EQJ+{zY()-lK>6 zsLi>oyPi4_1xgB$>Y)i65)zJPm)CC zIi;PW)(iuMa$V$=J;UE8onU`N1+i5FUP?Sjp$Y>KC85+NraVdGziT^Q;kth`l{u1w zuekvdmxMItc6cGkolg2+x!>X$EB!Qllz%IX^8MyHa2IkfW4OTQz@AE0;W8tYhzS7* zRg_)N`57!&$%@~F^9}Si{G@OPAQYW@{{f)hvc&w#73L(M8pS=rCzAO*73mS%$lz13 z*&nIvd<-DrHk3BNt$%ujD?^GM{iKQcs#!#1K-gu3dHu{CG%4rx`41N=xM?r;Lvvc{52^U#_29VAT^z8w1jOmR)T{~f04hj{8lLQ$d6#d4ivrt_o zMOlL))lt+ITqe*>3y1z0o6k#yU3Dhg5$rCX!;NLbS5yR_Z0AIVI{Nq^!?n8suCB#WsW1vNt1j67YFk1e5pGM;BCbR zHt$uh=>k59iz!#4Au>$|D>A@cd;x=M>@*LQX2~Bp0f8DkFr}rgwm~$~-Ih9L->do; z<3U8uJz26UWQX@j2#;`ZIa$99zW@`mnkdw|hPsDaPdluYb`B6Riiso(E6v~_smK<4 z*b!M&&fwuH&F*{8xfbEF2c`{G>rh>gZ;+?of27`g3!!WZ_Di|ojt;f#S3v)$b!A5f z=JxuaIx7-Cxb#>6cJK@ymLC}UyGeQTAN;l^O|IH2$&5f3Hlc->S87m6*hINK9|fB#jOb zRk?JwhCP@-T2(g2gw*|j31HMZI>#0arxJK%CvwK32~!4ULM`sl)^EYpC@Berp1N(W z|Feh+nWL?5N_iTG^t|&5SJ;=VDgedH0X=Tq9rj->ITv!f9~ft$^=}N`U}+o_Th_$t z28uzA%Z(XGt*DB>M)tHv4JIKghC)5-=`FvswH!|2rtW}|1s4yca7|CudNfoeU3!QT z_tAIVs;C5F+go#w1k{5m7eTEB@X$~B%nS@|ogp>GU$Gf8?vNHeo2JM+n0YUE4}-jm zV#~SMSjE?KoY!zFD6&_dsZp!|$YfL;@j`K|}p%ke{kJG+EX@N9~ZQ}_W%XNe?{ zC*K6~wNO1}kO*7)6if!xfm_Ov`tet~1|-z)Q(huWjkYESWD?ptP#}k%h9bgMnoVpX zmxqhDTYSov>ueK|Y3diNQ&$X*3XA_Q3bNKuWm*`Qe8?HPymIIxL1-jJG`*#pT1L6N zrs~9+-}nUA5f3I+v4^8q6nCGt0$dQhA(D=WB7MTpZhLn_(QhHS+ue{WZ(ptQD{f#{ z0qp@0?3!A~4l<%ew`na! zPT5rS5pMCH-E8X_yWN!|5F7CsSO&>%Dy1;s992XczML68BJpAa3o(A@fJks&(`Ua$_y48fQs(Qjh5QIAza ztzQUWVQjNF6h8-BnB|XUqXaMK>0|$|bsSvYcUs@nU^EX&lfLBg)?Qro1gtUctWq`5 zG#;P*iL0h!RC>4`6L$-yHoKM{d4^-v@>wUhiz)&~8H&Xc2y<(}70X4_@(z~)BCB&` zn$3!vKcD3uJ}U^lB^cRO*v#hXJL)|Y$W08dBX8r?04G4$zW}EayIR7|e0T~5DmVMu z3hbH4{O{|t&~ENE=C8_g+vk;HAxQh#E^WIPOOxo&)T}ew4EP$wwQiYDjSET5334On zgb(B-E9b_O2g7Fzqr4Sg{Ri=kkjSV8NsG0aJQnUE&vBh3n#G?65tPPLMvdtTp?)2{){Q1OzXN>r0W{zx6}UD zvO`;QnDbkMLdP9@g*t5#LIVrKfz8^pg+j*pTQyUb{V1HIxV;zRg4tQfUN}4m$%Xky2i zv&r->umaT?tEvt2f(0>rdV1kzZI7wl1w&>SIQ{l>BjtCP2{G1{6lk6jGgUaQB>BKZ(QqiGqN$fr`=%kizVm&Gf(IbCsJ=Gi$@A{1T9bDLo}nK61ly~9+$=eH-IN;i zdQdtw7aHd3=S@McyzM~`{Gy^r+9j7)69djSf-yJ&-i%rZ4BuJ6Cl>{T`UL9i`I9~Yd8KdX5 zN;$U+g*c$PC^1y2EBfvBQFpMO;u4$;B!9)^p1Sa-;au#9qe!z=^N@yvkir;1LX8dv zfvYWZxFk({G2WJQC4A3;G%Z02kBD<5CoD>O|Ey?wc*{&X116nD`zoMmx3S32F+!UX zH07bvo<)}nnL4sGjlAgu7K&2#0cB|IXj|a*Pt=2J`=5N_jnc>dTT>l`4}=vJGo2Lq zB)tP)c=P)5*IFp=1`j#MK539~t>I$HkrF7F%lVbK_g%B0A(>jrbs8^xW z?}WJv%oh3<*@;mT2UV(yv;LsTq7LL0Fx4TheYSwte!&!~EdA9y+KkcVA}SOQmHJW; zNQc?2Dz8}QxLbOJ2ijS};X~VON)Ooc!hK$U!DF<-Q=PU^g>vMprj!L4K?Jh zsOSoys%>KAWDw9vV#1K_z8crLP8BgCeW&??Xi{c;=iYb%O zYQ>Dd9?990%wQ?wJUSX}QXoZh6xP7Wgo5bVad1fR*(osGmkhWKBvB z?0HX%4Ns9z_28Jc4f74te52bLR~=V#1qHnls#tg8rzEn0VG%@Oe48bFJGkRMjxHEz z*H8W*b=J=YZTBP=GxA<7ngdP?Ewb4TlFbaWTOJLyr&QdgU`6vV#L3OYUu=wmVAU%_H%$~;9f4V z1+5}41w~eI&L>GQ-LTLY+TcHK#Dg2R~V(lu^h$-aEP&|g7NZxFmR9B_Q&7w`I6O~Kd z*>pyggBWQ7hD}ATwQonG9V|dxSD#7~Gw}nItwLl1!jGjEIs!qk(Jfy~{fca>!uo)f z2F6+uK5=nHfh7&3Dl-#Ugc>Ts+*Q7XUP&nf5B!Dd0eQbDh2_cHQ+qZEQ zuYo_T=+s{VH|Mxv0l&ywVt~X}AO_Y_{(n$b3cU2ORQ?tE?O1KsrAbJsByHLhA_>r- zTDMUxV?UzL-uv@Ic4u{_0?6)tIScBEl=g`5$g`wW$aI}6L$=S6GMFF&p=b|}P>nX* zX^}5l;QPfqd4-^Q5Q+q1ai7M=Zz6pYUQVlz`Y!0CdOWhMz^@Ak(Xf)hMwX)uEMV71 z23fOC3U_A`y?EUT=!u1|=`p>C_A_T!cJ_GW!BMf2R|4zE zZck7c>Vp1Lv4eVDbwRr@RU zwcBo|^WZO|x>bu8u+pV}XMdP`EA=5Sk6!h%C=>9IIVMM#aQg#QYCMBoX)``-_BlIN zJJfdix}p99z=;}0dCzyv)8kbwM$(_{mG%oYv}UReY`-9;%FnyaRNjWv{Q@#tNS$X! zbaasoq2?EckGP3ewsQH1pC@CHrG2r)3BdU81LO&vWE;&;Q1Z24HyLkoa35w*3I)Fr zUG;-u&$Jbo=V+JW<4Ws!T+`dZx1CDx9&zJ>q)n6Wey!sg>|Mf{GE$Uf5%{1PTE&Qa zqH~w|Dm;E&9+dWrDeiq5M!9ts((}>YTd}TAJMxA%6x5k87Ha+(v;YwlwWz;yu}_I1 zVYxYe2~y7BGw7I0xW07skUd8b+-G4G-(GNE9K$QjKikmM#1L{AKC{kauylQDxDSqL zfqL?EHhQA&WFZ3XihrPul+GyP<>6urB-WYE-e&y1^Y9oGK~WqC3+1qN7r*!eK><69 zW+R*}a%_=Mu_z|@VStZhNm!ly9yp@Ty!xQ|UiXO=u*26PRuha{(K+vRHJ>St##KD# zreLIsmcd+RY93sUQWgj*j0i#m@Gk?F*&-Jdr(#~}B^<5%vhp@s&*Vf>Fa3B-jR5y= z+W#e7k@}xfx}W_@?pn4g{|~&w)3X~CdT6X1Dpne_qIJ#+O0?PM7s-H3IL-MO;>d_M zJqM~8Y?hkdvGv?f^CA|54^{UW5^dxX$(i8GF(c9uXiK0R<WPYE!`SzF55WlKRBCT9qdk5U+A(10}KIqaj^ zA`=4(K2DoD5}o^F7KJU{9$~C0N~Fh<1p72}=db1@R8l<8$W}CU^F?O=REtN0Zm5_M zg&li;*t03Z+g4Z&x1>uz1`?e|rMSNTXmLI~cY4gn60E#sY5Z~8Sy1qR{&EEqVy;_? zZsQ=9^+fPX0_{!PP;e+F1-{wvJSMQbWSp-S*_EGvz4I375>dbf&Xcee-O{A)aR109 z8k5zqZ8O>njl>L3+JjGh=&$~N`66cxXR>WqMv|s}75ea0n_d7IloS#(+W_9-uwa2i z+&Bs+v0Rx&CeV*#@^S2r6@MfUc*$EH`aj$L~z@C8JChgIRKm~=wL%Y-#*zqnLXdi1EN ztdmeDFVNg8L?dldRwK7Xhqtc{CWJt8mj3exS1{ZxB**GV!SMsWpj2N5)s(v-yO7itP@%v?OMDB zKx-@bRzMVI*NhXifIo-+SWlM-xoOI4+l|#f@d7`n`9v7SDq)Z+yUulR_@wC^_TS>B ztpxFf#rKvo@lXu3mh89+sOw=_e_A9!jnqNbBu!^Q*PB7rip~=nEO*4uj5o2Jg*c%R z3HRNYD4V%+O(jPGR}N#u!a9YhP+|EpF+BQCKm-T@?J1f8gk3LHF8>RYI4l*< z59}IBhu}jGhdD(AFS?P$L+3iu>Tw`YOPhccuSya{RIK8)(AMO6MfQ)LZqXG2E4GBj{x$8<@vsQbrWaf!-1B=S8f9S@Ki+4>N%f z2UvDoa*r=0c&9jK7;{y!_VN44b3+xVUT5)Gk(*POpSI4*qRnbqZY|a7}*vlJ1gy-ln zIOO%Ga2?>h0O3>e6BaJybsEz~Bh|e87Yh%V8N;^#(@I?vSM@9f7ziimOWWE-e5PCK zfA(?nf8oGjtHIMCvmYzu#1PWKDZ|!*YuS@LKr6b5uCL{)eJNm z|8lchR`icA>uV0*lt;71tYLNC5*u2htvM+KU(lA;vBwPa+~?OhQDyW2BrJ^eS##+O zKiag;+MsurQ5-R<~a& zQ3FU1GM=n^xiAB-by#aorkBVJq$bxjSt`Z(f*vy*m%cyPj%i!lMAiCS7+m z?0cTcBBQAf2ca+H^oZDVxe&2Wch3-wuHmz%N(m}mQ^MR zYQ+rn{$tc(me?BrD#+y!TnTS&c@(TJpPWiTlb|{?dXr&#O@2e5{6A1)tuu5Fn3K6A z{U`p4=<8+Ob#RwZd&om%d)jeMgQveq!hmnuQD40ZcxS_5ul&nh{Fwd&1<3%s6+KxH zG^8ypEmgG~EtqJ?@bp_mUXtn0z?u43Ugbfl?r!)mjW95hHik|Os$O&+ba1x_$FB&< zfP6tR$VTbDwTK?DQ9#Vrz6uwB3|Pq9w~UEdg7tEup~tii1aWSemu?X;lbeCYdfPwv zT6hMq@%A=Z3@wMA0_hMot1eod&QK*op#y$vzhcf5((HQHY81)8{ecnYXkw=-Va}Z< zC+20@iFNZ@iwgdjs?0+SeW0LxeNZ5^^9iXDTN*td?GVo4t2-B%G?6Ne_4bWsx6d|i z$i$fuDz_BlO?%FB_?eIgP9OrU_?aybE=|Mq+7Nca=Od-F#ru07%E8a@G|D8tX0!A- zyY2wtn=txYu#ag=a#`WCfY+x0>$L4Gbb5L(&X4l9&OfdZdLE?rsf z87ZHxK#+sW{UuyKlTuRwd0ZjC!dE$~owUI~#@t$?1++lS4T4iF!s)SYD!{<`%}uAO zfr>!GGb@SZ^FDO}lmz|se#U@eCY(Jbw~F+d^gX#s770>ZaW+gx2?_-5_RmshlmbhJ z%8-*`(AQ`H!;pEjGx$7TVaP*qgUQgos7r!13rQ6Ys843eoxMkTakCB-?Rg{s%p*)_ zCUiXub9T}>X)-JaSB${?9f#2xzV+MS)+5dZ9Vxi$qc!%vMSjDdZxo2!!lWq1oI$Y{ zyXGts!MK;9>`wtdura>rzJnQ{*bwmtU$j47dQuwPP9y-6svS zrHoA0YutyUSa)iOjfIZGsd@w*PBu}4TIitx?^R%Xu09+FjQk}yKslZHmX%HvCSQyu zL*h_~Qv!5FqR?Tx4iAqCM`^)wU3>Nx&!h62>qwh_?MO~4dxw;xZ&}}Zph#<#nB?&P z9gbN{v@+{e#?it0YQ|=~Pxs>#D=`_4^P>PRmKf{4a=b8s8lT9)Ggka~I09>rpf&n{ zqeRq5@7`EVIHlGp?j6kzq`>4$eN3n$+{w?iORXJ@0}9Cte`u;~0cSMG4m=Q|s1y$O z;>Nabb(c3YC}vCsF)V!k!{q8)x!yU zNjazpDyXj~c&;iT;Twx7$_V=F89Alo*!YsNoTBGP(o&Eljv&Ko&XpZ-mds(AG`nFI zN8v9C451qiaTm549)whN)6S(}VKXCOC$)-+tzTxQ| z`tL&H5Gc4{A$3!NNK{Dv(aq^xW=awBG6z%sc^r)7;MGIgaPF822C+X81cH4Vy>W~e^Hqhc=3Yq%WpZ0U7yw15GA-8yDI%#9U23(XE&Z1+ zS~O!GNeMS;<0OCs%`@@_dPk$yEqy_5nx3j{U z$~}qK0KbXwuPO%-WV&R~uUk%mS4_Sb6}#Tf9aH|@7p~kYGvQxGCI>y!5=-D-Ab9@& z4^9;bOkuMKo|L@N4}XCwQ2FyZN@Z9D`=l3EXqR(%fecq@5 zTdo@eo4;`LyqiFR?XR0SCtZ}d_j!PYnu(RaE1jF08`PSPU2Th}z`~%18s5hYlt)e% zXt#(KyWaVu(B>rCVX2u9K~~Z=dw{#5(uy*+eN}=NPiAj?B_4bgNImt~cZ`m%Bonr@Wr7vdNswHd|aEhxx33$~^w5hZd zymSDieS*L<$z~!d-Zgv(QsUSh>R z3Jyl|^t_dAx~?UL!S4jV%H)xPexmN43#gqgpoG^K1!Iv8v$ETvTk19H`V#|PWO_G@ zhD69q>>0oDT6_%f;>8h(TFAoGxwlb&u z^wW|=E*`32pr{T~2T=2Uh9^-FFjE;7#&TNcTu?+Hx;l}u$YCYV>2vv9vSC77HE@j6 z^q1M1IMt--z$?^H-;6zO1h#w<3{cmzioNO!dgl{HEk=wMFOjc*1b1Ixqt0=6yIn7S zjYNtIMr(zbpL{cl!yj@794dy2I+$7jo_g|u859Z*>=j5=0sHR>TGv?;SOXk#KQsOb z7FBpJmG1pAii2Ggu}95Gg12+p)(0~kveF-|qPYSdj4Jn8g|r2A-VfhXRu|*P{<^>? zVG^n<{v6TQq1SN{m)*xR2i4+^q!U)Q> zFhKPI(xeI${Eo3l?PBHKdI(&!>OCUN-D%k3Zl*K%&7@%C7Xja@YD*(3D$Q9XtnB;} zuoZ}+{EHRmES;7J7Dq9ViFY8^CIoWhsjM~t$ssTvJto%N^ZxoRYakt@w$N||(oZgc z)9_>j+=z2S;}W9{Jyk}p%QL=6*EF~r*>qg1)*+!75Jh*CEz4x6R39n}!!w5!bVNxJ zTw8P6wXJZV#5$Ln6$^`!0d72hop{b2IWyZMRud1uKunMRdb6z#WK35g*+h$T1wK=6 z8(7;orz;cTR>h+$sCOvKU6o|wB$(!W;ywp23jNlnNDN@yipo%G$_48vZ?xY)s@4@2-tN|_5HO;^H$K^vH*_-I8)HV9 z@#l;+#zjF-yNnYnG3;-Uj!&&V*rqc^9stY^1ukL)ixbH+uma^13(#;=L$7?g<~vo$Uq>-#HHml0TYc z*R2`ruvTVGM%UzMJ!$IbDBRl(hgLtRW*eariIG;bCNOKjxob4l=VlSdt`({7&y7uX zut_;HU{sLLOPJlKeNnawci+C%hf?5t6l*>&$azuaCXrJ--P6i-xc}c@D<0lAMzti5 zVTe<;{Ds>;Z?Gi*;K=tdveO1MaIQq=u#-iB42QeU87${|D*tk)Y!s*fto!8^8GLNS z`21n=n8p$UT$wpkKZwMAo1erA9ZV9Z_rhB`;`kolRvW&1|6fZyE z<(df#gh^0z-!12oU_a35#NEOY*Y4sIq+H8M{UezX*z zpWKgm`OXrPD)!8D=~5p6YFNG|S>=J`bX}@vHKO%XV*(}DbSU>UZ52To6Nla-kMXFL z%>NA(yWI-WUMEmO2_!u^9be4{w%uY1@-f$iDgb*=6rMv<9;rkEL}63EdQ-Le2h~j; zAdj`Rp$La1w{mxXhdCPKG1(GKSf*_x#$DT$a}@5j2g(Epr|Z#CN%*KiXJu(bYY8fn zV?LxE#*a2ofkl~3xperspi`ZS@z!~c7c)y}c-f8%kiH>9_lacHPmB`^(xZ`8=dl9% z_@F3ycGLD3b?guf0(mbpcb)(|>9js<7yXO{?1e{jKU#cNHzkSYm^zPQtqiqPvN!_o zNT|efumn;R;%Z`EK<)_3jJTCWu*cgF^E}CSr|Z42bA8JVTg6zZI}8D(eiJ9W=*R{h zkTSvPNu}bcfBaD*OA_kutiMbchs+kHumq=OMGfqNMwRq>o~9R*_D-|s3FXdWDZ}^n zI!KQ#Je*#EIBwRj$EYU{8MY9h&m}3xWGl&#Yg?ZnT(j5qO7X}PEmEbg&4G>}>d+}t zfro@}1mTEKlyO)FJ@HA#L|;KNIEEPpEhTxtA*@3a=k#$`Mc>xDT~QS8k9#5eFc*2T zGk8=83)YtlX1KFH0(xA3caieREWDwEV?i}o*k%@jnGJ(2(3kb0l(oXuH>0&XV-VRH z-vWFJAL60%oSACc)U#a5bvsemo>L(QhJqfIyB&xx0&+5JV`m5gH=L6QHDvhy-B*wc zdi_==z2=ZiNFc!*q$7{w0s3%2L_&iH?yv}{2&8tUwYT{}#}Ja-HU;VnH=f)IuY8!r zC{Q|5<&~hT-KNUnWVXA|jc!++1skH*y9Zw-`YbM5E(8%7)zzVfT`QSxGi z-KIGrv9pd$}Y|5FSH(UYb#R>u(enJXEU ztXtGQ>(-eVJ;&)^&D;e{5xQP2XZ+5!L`QCm31n$#_3V=Z zf#EAA3q6SJgP+~?8sy&p6h}-CD?yna`c4Rxd;NoEa*u^S{~{NARC@flHnA2oNb>v) zJ)(*wZQO*T5RPppn!i^G-Az5JlX1@2V9DY;XGg&(!v}BA2hG4_i4V<$u>3Zns3iK( zx7SW^`My5Fa{AZ_3JE=_wg>J}4Z@XmcZiG|UHbruNl#vl!5fd^0Eik*P?;%Y#fyJLT3 z^jMb>vLWu2M*yysTdc)eWNuO>G*DI0DiS$N+olq6Y=~ev0TEF=VDyKP#j!%0# z=Lh^@2@8NVl~KQKKszUDbl&+gge);a>u~(n)Tz2xt9;-VP#UE`Gha?V!A=i(bPoD0Y@5UAaau#Liva(Z)4C!(|%Bt8?w|T5R)Dy zE-fz*uOypz0Q2>*NyiHBnx`M54SBk`O41n?ts?PusNj0UOU@Ql`6%>hKlmHF@!u`` zMZb4j2)>OO>0!qWI#~14jzW#nv;ez!g-VPwWQKE+dYvPy(#CDvEhOz7BJqz26S?zq#ZNM30^WZSSlGa zNfWirdfTYs204EbpN7E(STXa&2a+2mk1s)_l&)-h zAwhA`_sjp788r|C+_YNoWAT})6|uARks?iECQ+cCq45qG+*&+F+kYPH&wKVjm1my1 zENpQ5X4Ci;uQ3Lf7uSM^fy`77WE6+{3kKg@w`HW5C^YHI5(-9fh4?B{3SXslhGbNV zjIKe{SEp$_7g0>Eci#cu#P?mnhKQI$H${95x zGhXms_4L7-sGB)Q3k7@@A_yY4Nz^OIEVp}|O9kf=uuZBEr$iM_SMcjli(S>MuC_)^ zN_~VvrE_Wlo|OF4c4^e-75*SrsxetgJEc!)~KJi^n% z*qOJrNCFRir~xn*g_w40?20ZG836c5s~fHargs>7|F;LascA$tLsU4qCUCQ%c)EcX zeT);`WDX%GBePoe#~5m8DUQK@!w#_zbJ)zqu1Uz*ghH4?Q%vPICw7ni>yrL#aG-c- zC%OQzzVFxl$x$TAa4H_z)rpxEEASH6h|!ppbD?Ffm8!S+A~^zvL$4gg>dfWG?)b7; z0y^~B4nvJ-_%}1vwcxRS;1Bu4a9n zi4bA7YX|Tc>1OUG(7h4ZP3S=`+u6#y-gah##VKVuyGAGdi=c31=Ih?otL|_52a!(w z&pRgtbdg|cpd#Esv5u^FQ2IphaDv`3@mPMZtzJmYDaM4e>WpsDjlpH3MvWeU^jQgT2&@%xgY1bDO=PRDcQ1nM z2s=OQMd|qYQQb{@m;@@0`vuWf-5I{5&>((^kYFtG)-uBzl9pKw+FFeJR#$6)q50?u z1;YR`a7SKa2>6ZNU%G57Lc9MGu{H0WE!I{?3u%VTxidf)1*CEPJCxUuBtI3JReq_X zJY91IKjENU5@C>2wv}~AL4zaDfKhBUIo!DM$}SKF53bfK4K($%>KSNdynCy-tMnR; z2EgcAV(AQslG4Nol60(>euoyl}wH%MsY}$~!rz^`3U-$nSLe zJhc#YU%$ULdP|hBo=56FAZ7Oob6@cQ<>j-gcXhx0)Cq1<1F2La^fYeBihvru8Q_$S zn#VsF{@=a+b9M7J0V$Qpmm(7c({peoZoj;=@n=4IA+50$kdD=HrvddZu38Pxhnnqm z1Ls?!$@LBayAtN;hB%%Sv>>^F{vLP1-fwM`Yk7417og!MGE~G};eCQ%7Er8Gsv5Qm zSe~lQQ?!x?5UtMzf4ZwI_kkhq$Jk_xn0P8^XRQaOeZ1RO8MQYFYM!eKf>N)%v)3H! z)kXXE4*Ac|FTi+cM+boB`O7+*J^03qs%!`Yl3aP zGv%WaO+V&J-sm+AfsE-4#buq!3+}ux3uKxxGRI@mB+VWNha(lI0=GN#MsU_*Vnlxe zbL|?dvT0d*8ENNQwAZ9CtUB(ukIB|67GSH)-wT2VTw&!LhQRnl4j@PJIBz!tXb&Em z@3A3UVgB06Pb0#Ijx!8MGn%Kxmut*`t&cN2rUudiBe?>U;MsSx^gUJxR&friyny5k z$E_xq@(cN*(I0yu#oJtyW?`Z4@-Mk8Mi;F9*G`d|HazMgcN8TTu}N?<6EOTZJJ3DSx$h4iFaWLTZ<5t{-9ud zZEEeT%*^>^qxmzVY=(ILpPCWT4X}Ik9O7vKnvwhf3|Y{C&X~!SGSuQq6IRnSE_DwN z%5?MHqAgAvx)yOw@CqG!!B~_h$CzwqA0wR*klL1|RO@KBF_fN3QJ^}U)^9ga?u;D9 zim^w;ixaZusp%vY2}DwN(pBCy6~kr~x6B*MfYUOh+tJ&vDoncy$q;%-idcZ^$?&df z+D40exxj6`Y;pNF>d%6opz*;0ZVH0XJf2xFct{T++4z(=08vrEJ;SQtDp`$y(}k(Ozlg}+{%1HKl)_Z7$bkLek@j@uwjV@aO_mJ2V)0ByAeP9~t= zi=8TNBmGVjKKJNMRUBpqL?t?qAtKROM3WGI`aoEY`N;hMir!lxikq#5dqH?AR(Q*+ zWJY}%hBf0YiYCR?dOM>%6seq_nWJ+fRAcNbZ_lWrHF|2ywA){|48hVE$6iExiCHiK zkVl}kZ9HG_XU1G;Pp)L=4OhHb)uH}sk*sjBEA>|c`6uxy)K?q$Rz$4XS1$Yk@a_$z ze#c!&0y5PTo0{$CP8#d%+9LG}Z(6|6hS)rvd4JYpmk|keMG+)8q8 zmio+*>o*AedWmUve0_}E$XNhWWk8vxsNwJG0@in8Lc6ZOj8j_%#Ft=y+s7C-Xz$LB zC>BZUNmqu6ar1Aqi;I$JJ8@AEJd93YyU)EXORNL0?6xTg1AT|7L+l_Tc-9G_Aq@8h zhzkfEQ^N9-?1-*DbG6T@rZDE=QFBE9+vL>R<@@*uNk!ViHm<}S<%opCprGl)lcK+# z>++x>eY|bZ@e1HX95_g83|m+;6ZuyIi9oIddIYe{gSTy4$_JXr(T^-P96m^4i?A^? zlM*K3JT-1n?)h)xQI{=nc@TU>gZSSTNqzYR`;SNP>!@9U<`sVMGsXB1Ec~rEz+JXh zY{MP3gS0K-!NMfCDM^Ggs7Rar$1ffbJAf#t zKHZWM@k~Yf7%PX_C7D_mst5qH``&ThdVUh^0ovX6f3z~Fe^la-MsWhL&0<%(xw?Y@ zh3!-Hx_5%i1dzZph_#ow)cd_Xzmcomu_u4y$;|=|ra6$U*a)U)UyNrD5m}}Kwt@vF zX+v}wmm)_V?6-p zo6u+5@U(&3tk9VRsF%(LnAhwsy|qCTvmRzh$X-f;#Bskh$pJ+)GlR<()j zcKbdWxI8VgYFeU{#HwPyXcJUlQ?H5y_Meu5>u$Ct+T|F&yqOBOfWCCiVFe^R((86^9s3WBGBU?(VU}Y@Cu=|P$X_ag_H#OM|vRk_g4}? z80Wc&I%^jdTi}HhohQmzUZ7@&S%wk5b+;Q(K{cNVL@TuPc+aPG{GJcWdvQ|fqsy03 zhC<^Beg`L-qf!8V1tNL_Wf7=g!@>^=s9B3x~sw1A%ckf^g?+$lHJ``gHfQ_9ShfgZLI-@VFPo*hW$ zpJMnAxcAgt&4NfoUudi%Ho{`7jdD9XJNg@-N?1Z+)%jqZ{TadxYe%1&9}NhTfwZ1h z219DII?(r!V|*OBFM5~!d2h{=QYE3z&C&u*xV%y#lD?7?Eg5%21W|0Q-y8kwnPB%C z&!Q!gneB@ho2WoD-GIEi!ukPJ#cRWPB73;wyP}2*TwCaKsy27;&r@Lh7iLlWe8q&w zQ@VsDAzf|JQrP3lC~fOk|CDb1t9c^&-FDdy2<*G2|6P+)BMgEC+Y~B}U?y0i$V5r% z%`dVSb#Ob1@mccXIxG^V+5j&ds zxV-=VWJN_tx?MF3Q6hgK`tcPCeJN!0y>?3Y>0MS`WsO=!k2q6a9*d(Dsk$=%*={vc z#**j|#c!Ewu*I&|jX1Fj3Uy0L+p8Mt)9AJ6vv9UO%dCFM5#IHoyae71V60hl@ zAR4T0!mq#x;U)(qpOOs#@s}3j}M$`q;*7|Ab!D*a`uncnAjMDs1Q*rT<4(Py#^^oA%P4B%w!CbrFR&!~-kd?^`$+ejC1@Wf-`|IL9Wd zt1(lMI0J^6bOHbF|L$*x?JAo~3}Kvi>Y=4*<+kt;G=;hexbu*+PvK4dUG}kXnFoPT z3O74vc&@&k249>55zYo(ecp;%nX7BapE!~HZm}8*3E207ub6Q&X^OmsNKvpaj-ID_ zn`hApn6~f4sCGvr_k88W!sFB?)G^wUv5x8dq9C zP_RnhUBk+wUA(Hg6HxY^w=SgtVJF$Fo>!$MRhHpxQGUy{?izWnVQqcf30=3T5aejO zpORp&(11l2A>P7{(Id?enN0*2;4k7!WP^DH)SxK53F(i^<6o@2`IwA<$k!Y6!v!i7 z+OyyMz~EUrfxQC;jb=JXs;dniyF3Y0amiEySR18qA+AL-hChp?L4Gj_grD?2mwJfeRrcW+X}+CSVuxSr?^?C#HE zm;11Brc2si(bkHL|r*WKs|P|CPNIGwo~ug0XUbT@)Jv$_Q@wq}il{whF*- zfv0B~Vs+W~t!bV5TX5yH(bRYnpw{a>#@DCGkfA5?kqcQa%HJguwTjTxBa}xD^v)bLp6OmwMZFBUj&Pjy z{i8>nYnMr)%0n~{(Nrzrj{Mo}DsYZ1c=r9fR(MSS@dglC3a2q2Y@9N#)Qhi-Y71-U zMWK~^%H_5 z4I2^*cbXT4)JO7O5gU4{;5BYc0*Mq!8QT={!z&BZlKX|!8ViceTYp_&8E7YE&1jAZ za>QBwuMdjuJ&e1#&9&;e)K+TrRd=^GUttbh73Nc}pTs+RKh5A=$n!b68*9V|AEnR$ zt#0N;h3bc#Dg55&MZQ;Gem7Z)L)HA^O+A1+zubuC$u#Y^TbelPKM_6{=+&lH3QH{T zclDNi#WsDzGH+?hg+opYC&oqT$W;d@6b{Wnr^ze+MZ^=o8qBQ-?=|6P9a*w6dEJhA zO>cf&>w07>h}Ws6vJFJQU6RsX>zfFJR-}-2FRQ6?5cDA#9n;tT`O;|urozg!ls2@$ zl4Q2_zVt6NA?{jY`|y1xJl{Cu#621Z(d%X4n(@XDO$O44=G}*AW^fMx3rpg#$Q`;(Ov6Br2W_!udoH)3F0c40a|qK3dJF*W%-0_1 zCZSg%i>u5pWq>>wVTQChQClKA#yq9|XB~+;Z8v`71*!nPbo>yoN<D$d{*M-B_sH^R;{AdHqGW;rEWsn z5y`d*DJQ>Ei3uYu4JR?hz|3P(KXnKa&n`PITNe5NRNB|BA1@#IQP?ZoW5|ib3A&IL zId{)e+VCqJQ6?Kqg8m$=m-u&b>Kys@3N14 zjo&s8EXslbTla26sXz*!D7vOBYLL;FF&c%#-&JcB$puVf;b;Bs2SEEkapTmyh#GlG3g&O9C<{ZM^9fjKIyy(U#^4}Zwaq#b7kJjIR6q2+eQ@gDR_N4R!}GtmK) z9JZJ=+5Ue&8MT!C=ZrwIz|SEiP>#qi^w5S0)7|Z?!#kD%G5g><^O%|=*r;|b|6?IC z^)&QWp=sB~@q}{`m&prE=9qJkAzr5qQy{?db;p1B1$?z0rbutOJ?RXn4qKw0wo8p6 zaU$iC^6;k&vaAKZ+hU{E4&hh{JX^$);O@4N>a+roQlkT;%s)i6aY0YXZQZSf|9C)} zxCJ4zMaOFwI^Is86jZzp)yk2e*wS{>BF-xM7;|noytJ=B>VAJh%E1I#;@}{Ir@I6> zD16gDUL_Bh4t(wni)zURiM_o(1qLZT6Bsv3|F_va%U*Bw;pmYr^|p^eU3N}$t+B~X zY(vk)Fn-AufIFR`7(4ixClvn~D6A60kJIPadJgzl*m6r>2_8XC7qMGKWuTU3Iv1#T zWU(F%{`IFWP9G_Xs|94r>=?rF@X7DlCr^xuyf}O z-^JhKKtivj+y=vKey)@FiPcdQ?@^<3{#Wbxd2>EJ)3X8oxdO)DF=JQzwr@-n$^?*z zVm)Tv`Zox%>x|u)F_2p{<=c;m+u^pxS?XpipUac4Wi{_Jd9LsgRyE*`D^W88 z{|M>yJNGbtwTM|QOh4vXAw@(Z{^znJ=s^LcbBc+^h!cJU*Doi^4;L_^a+5-5ImuJ6kdkEs+pQb} zVP!iyOsQ08s^Hk$Zy!9krN|&t827^uQQN4p?HZx7(QzQ-zQ)~G?itMI#@W#a$wnG1 zTbs;;jL~GL_$kRdv9KaQi99|EcY0wQgh*s7nfL&E_=1ToUJ5z;xOC#_9ADCX;%ztc z5dNM!NefTj@WmC9bF=OiLh)eqqmz}v{__B^VTPzX9^qk7O)G#GsMNnOa`Ky!cXJ?2 z9Q92s&t#5#`5a6J8w8qromkVzp#{o)0f+}kB^JTC1^L?_4M}+Tt};eE`_5ZSrBL&e zE%m@J&hLL1n!gQ=oqJ`sxq)6Fq1-oy26V%o@Xgz(m0g|Kr)?HvA%k(0>X;pu#yIb6{UMhHVRO-f zN9wmbcfX=@Uz8~zXmB2KZILMfzjdmpM?n1)W3)&6fix|YFXC<^|6x5ACp6K_cLY80 zgO9rB1}={U|J@vNkzDw&HUYqEW1%s|wyK#{$Oe50ZlEEWvEj%A%W>H#B8Mt<_av_# zzshsa)vod-Lx<}otQ$JKd|FrJPE?S0y1uM{}-ZWQf2P){eN z1_GEOx9>_?>^^k1E3}siwJYx4%oLGr9p|B%HQE3fg)NIH=Sb6p6%&8@)bgfG#PC!< zUGbi?s>WqSXXp)ZkiDl-5P}Zh8|kE)*6nr%G7yf1w{Lv!C(h=q-w$TL8Dnfo6=8fmQ48__@uU zboypr$Yk8Fo%MG|^Pyc2UX`0En~#P)4MJ6|08K!$zl>QB8^>s}k4__d(r*KKcvb$a zZf-S9PeuCgsqwKrW}mA15lfAr3k*3*=G4&4`9^*t;G5|BgijNmj{5Lw0NJx04(pJv zsQg8gKqZ`S57MeX0EZ|L^wS+StCK}!2ZC)tH$SvB$^4XmCzVy*Rgp{55zaJm7;39% zhE#wTv-M);83FwC%NgP`yF0Fi)mZYA5bi<`npu2H{=BU75STSKX+I?x&Ar#m+DTiv zpQrWw2GlUS&|$tpfl$fx*CyveXSJ~wF?Z1pwl}iv6H6&g!4nzD49VBZvqb!4Q#E5 zD(n;QwH=qhoB0^}5%iY{pN!CO(z7B|a-{nd1!MdiyS|?C6aHvE4ByFm2K4%BvikwT z2tFHlW4h>JEAp~qW^6oLFCZg3@dH9xfwrMHGB+>78l;I(Yg{+)3q5V;enR;j64-Hm z)z=vd$)+Cu0>;1JE1P)ZjgK2Vf9)<{Shp*sA{C6yZe!a$4L=g-y;y#CPFyyKH!O@G zH-B;E6zaYj|8Ke5d(U_+x3EpUY;mfqk%R~bSrBpk6|8^4S+~>gF9B;+F|P?RWx}mZ zaOp;m3!{2v-jvVM*bplU5BfnPd?JezpNW?(R;Y<6?N^`Zs2omc z?a50`@uTBrK1UX0cD+2pyVZv62m#vf2XZW3WbR}p{cB;EMAcT7q?zjl?6p|t%~x)v z7Ds0c7R-ZH)ON9HTE5D(rnw`>3=G-8LxKk?vLteBuXMX2tWz6vTru;GW_baRou+aQ z4icG}yhHJkt=@O%%^cwB3am5_J3qRf)laR-DaZ9S#l4f>uwSe;@5;4khs;znJW-Hq zw2*~!JY(`m`JWi^3dnef{>w!inZ-sUomnLYZ%@@+ge|J@i-wiq zX695?6egGx&J>u|Ig#$#_Kn{(H8qTx8PC5?`GcOwwtQ8P{d?oHV)H(e3PB3T!!AI> z1PI>Qj(0vbjFwG!b&KF>c_i5DO!6lQ21o6zycPwL`53#g- z0P*GQm^IJ~Vjsw6_aVvp!@j$+cL%eh4Yb2kSNeL8HRR&Gyter%zxg`r2;cD4Pg}}p zUscE}2p1U=4=X1omow&>ng79lZzZiDcV+f^3Y@RF&OS-OX&*`v6JamO25dQ=hs3>I z4jgFvdtgqpi;fAL*&%ke0TbAmdxR zlQK_CtW#Ofa1cIV!ZY!rdF|wIG7c%wX9k3I4^@S?7mobCh7mY#5MXB7%3^k_*QV&z z%mJ(#A<^u@yyH2)g`%3H#MGP(u?=}`(ymiZ36i22v>QYuntdneN1#00s7T0f^2aGe z+j8r-Wf`S}BI0cCjm!5a13=1o{159c0hBH=Drj@<`CFdHzu;SG9cb`U&lO?uRk5r{ zN1TSio1OW0$4;a`+#Uh*o-4K^0@`9ItwK*OQciy$GYLzPr5;ej+9e*!4OtX;-z00y zi;iGhpoCAj_eO}YlYagE1;S3dKWwsWTklL=4X`j*e?+X0Yi(CQx_$S~*r>u0NLS8Y zQFm=)3!-Iv6_Scvt9c^I@JqyZBM-D4FMt51w7n4)iU*WmgZ}h3rehEPf%62u!c1y= z0BwH(PhH-|i@%gSRk$n=G8wx?JAJ>4BGlz`^2uXX(RW(!Q4j$m3V$H!H5F+~2{vJb zSCer}b8O_PE$XstRrKf0)2)6#MqMOh%jEEnjARIiJ2sSH3%q;&+;DCd1KP|DHro?@ zuciLjSkzkU|u;=gE|yFw48kdGE~?TkJV6?;#$?O|U#21?7ktB8J7R8Td4r1uIMzzQKKc|l~3DmF$CS27}BV#W|yE-4_fy{~G)MDte zu1KY?)r}qP0k-O1P^hYmknQ=l8{nDewBsy3hHD24HDgJAn(pU9E=1?6{WZ(-e@8iP zO;MhK7R^btzd2|sSu6h^T%QFgL*!!RC;#6TtQANmk~~nT2;%G6^d3++;Fdv-*!Bb5 z0V%0(Zeb9&@8eijg3MA#QOm^jC=Ae;l{vJ7v852bry((R2I%S)6bTEdM>cLu7R}qv z!4>jU=)5V#-KTRU`8btKKub|8^R$~z_Mniz);y7d=Af}r0lXOh7QCG40>}|;?ka;M zEMt;N-@*>Wyy6nVZjEvddJ=APH|Dy3TtiZq%QULu;I^*>;8`{b6xcBMO!+GT+64?` zJjNK(CB$xSSURoK(CTBfJ!5mA%HD*Xbfj39XY}iVmGP?t452lTD^NK9^g62EiI_tf zuJWNtI4sA1$5f=9sJKs^^?vj{&Bu_Hd%mn6lK&mh2cRAvqZTIXpkmwNn0?`}dORQ; zsv!x(jjqS4NAA;#g*Dty9UT2Su@znl(D%Qr>~}EqKNmlaHVNF9Z%yscg>~ z63-B(>edkTc(26>MDnS-lohcWx$lSzqmW!8vo zsE+EY|G)aX4wuRL0NiwI&&J|_*OHr3ie=TU-^4m5I9kXx`);}=Nu4SGiY&*YB9ODu+kLTN}i#4 z1hWm6Upcg*&u+UkDqKV>({AGktN2i^;$rRF^*~QmgEhz$A{qd!ad6kk`_FA=Eb8J4636TI?;tWfccr2;5g*#0C!6_u z4g{PrnqWDa#>Owst&LYUpc|TqHols7o$AqmM#C00pYGU%3q%z)@Q<}BeRy78AEPhem^JPZ4nAs^GuFO zwFrhx=(ueEE#4zIoq@wY+BJ%P6EhzB=&fgxe=o2_6YAkoU~yA+=~$i)HOPqLorv60 zn&><2#hxbE*#ro{qZJx)>FMBwJy(FJFJmFS0;Mh_i>=#>oHCb;#964J z)!ipdf#DYzr!?7YsAl=l1BzH*6>a7v;AK8y#s+2wu>1ZsR#oy@FNx4iVUk!tos2vH z2j8?|{&MgsT5gj};plxl7w6+$bBY{EJY^`&8d)mJU1w-C(nmo~s7md1@+D8cMsJ1o zAzQkPLBC{E3LIf!2pcAg7+;-NqkI&K_hGf_FqRhDzjGnzNLloUZWv0NefYv6vDTjD zHb~Ih`&p^m5Mg`E#RprMNt7 z5-mK#`=y_gly=I@0~V29M<@$O-alw3>|iiN|Hfw+#Lm79xl)h8dYnO*b3qSr0i-;h zZ>d`tLi0B#f9P!<)QYQAVIY;~5|D^2QT4z&TNfeB_6EIdn=1OBa zJAnZ?U*Sj0`MB6>R>iSALmld!{7I_`MnABNsZ9xGhwv)I48weE1a3~g*1L~((qPrw zl$NJ2*(;B}*@9Bo<&PSL|KKhz;kQb8?UX%93Ef+->TnK42@c1btr%qqZ(MR4)Q2+m zl!ZfgL7G38nugu>bDfXE54e{I~L|BN{vhx-pPOw z&fn@2iGqDqfEm@P1GDCPRp~qu+dgtru0ZJ0_H*ZzAv&CSi(<64sS366ApYi#5w$Y4 zs$|$?2K=$t2j0uUD}akDf1#K&Z#`GKDsk^kbXV$0Fy4NJjkxqn-HM--J_4W_|hX}p6PmbN>DpD>iRx_3YJbwB@2o$n0BggL<(!P{qTxBvJ9zX^VCuDi75KV1mTfQJ&F<3e-kta$^vHfL zfRIWyM$r+AgEdKvkSH0^TGdt}nAK26Xny6-4C)jRIVLebkaP^ZEw43H>=Po7z704o zn}DV}h2~I`K2D>_LRRqRd`&j{@4D2|16!GqEpajfur_vfU=Ns5&M# zJO+&2Isr;)+)74&5HpC#8N~kxn$!rhj6Ynr396tEl7WGJ%~W6j9Vv`P-Xq{vd?*U6 zbz-~i*r>B-1E>4OCc-{^?EQr*sSZt`4-7en7;8mG7j0tx#1oQ3;R?Vr8aWO&>b7tQ z##aed7h#)FrmN4Thu|7SGG@|la-xP4@VDUsK$xkDBD*; z3z9`fTu07AYW&&<84BPmvpAxXqPO4f&y!?C)mhq|b(d|v$xEF$k(d4Q0ApNo33GOx z&Xw}7Pd5_t?5%wdhZquadR7S0^7fBzf2heC6!kqxjsVx5K+h(36;d#{76?Qq1zY9T zNy#lU9}Pydl~p(uMnyd(Ie5^TKeSD_yts`SjE#@qbmYR&-wF~{2Q7LHO}?4tSNzGF zGvBr!;s{Pcu;yHSPEBJ7rZ~&;^%hBCnn)qQ$1`zzZTTV54Lo+^M#JL17yvoI;*nSL~r+U6_E;rxEUo0u$s6tn($N{zLaulGF}#cT+$ZsBS% zJtaODwiO@0R=Ab#7@)PPs?HyA7B>1z-j&L}0bP|d9b+V*lt!r;n{1o)LMu@`1)gpF z&4~DHA_YhgHc(>dbJ1P+Na*U1NrY+i8CR_&KSxD_gHGlLlqsv8C4&~0gs4g*gOr)^ zn>Sfp1Ou}-S7*m-W3l5G!%{e`0)>!O(*F7K(3#%xo_cKbIQ!Lf@0JR5yjkP#5n0Ji zk2&qpLze6AbqEU_Os#wTAcOs_K$+L!+$b0nL?^QYD(R|@C?3^70 z|G!9IHh-&WakNl!7xqy&9~h7oe!e-KzOFmNl7>FAj8t%qQ7{be5+@l+rkeVS#5x+4 zsw#G|$n9g~6_(tH3%pfun`KkJb5NgOy18^_`U%aY47l{`F)*kYMGegz)%TUNkn9NPgu;^YQA#P7Z(866Af z#)d74o0=-4SOuRoB#%GI@11cqsFtx9QlR<&L^Og~F1p5bV_ZE-c)i{#4QJ+j;5si6 z%*V*Od81;7_;6X5D4Pfs(qFxOvnFYGW0UtJeMUNRS`vUdT%B#S@px)RLJK83vNAVkUs~h5_?Fm+o1-4J`VrNS=(@5ekmVS%z zWteIQsZ18mJ5xQ_0UCC~DY+z^7{3UA3P-7atA-OQ0!8QTj#9p>8)R)s#sP(d=!0ia za=&{SLLW`#E|LEuItoWaN-oCXAKz=VkUe$?1xXL>T(92I=%qdJ%@8^B;tOp#FkO!P zhwe$n=4@1Xv!SJ_D1Ep2QNqr@1W=Yr$-JUGk5Qq8KSnaS6f(5Fx+X-|TZJQqAJ1@ZxWM`Q&M}{~f6noJx z4jHtQDYgUkvkgW=1!@f+0j79nW-m!gn`v|Tr)msT&+>c^G{UP_ama_aL!8N(PSmBg zN+(W*X%_~s6H}FJZ@CKm+)*qtzO;NTzjO?savRWrC?UyCB#+7n44S0>s^l5XV zXimlq64R4pTpaUtcQ`n*lDk4%KX4B4Ry?YU#ifHbGlTwwY7QJ89%2`)A8Sla4sJCD z0lod80~7Peu||>_!y0SQm`3gT8EOkJMd4J@gK&V(0D-jP`C{m6Y?R`4R^QdJ1@IWV z8>yb)_~ol9VuN*)8x3#;IwU?l8TZS*OK|k^q+X;#JVzK!LBTq36@kX50ud; zW$c$E-V}_iV2?qXnI*INh$AyD&3tT(=b7edDuAwIp5-)2yS3w50SnXGu&wFQvTlZg z3@l?c>aRQQ1;iHl^ zJ>M0w#X;5stUgfU^qKG(V}O0gsAkiON}!Xv0N{eu1(gt)V4<7?C;(i!igi!?tdyuB zIetDOXp_L(J*8JXz=jpicJ5uNX@o=p6@>1qWa~t8(`hjjl~!d*QE33U<}B15Vh9;=#!6tuY1`xyKYeFJQ83 zVTZqs)$k;A0#owPXb>hR7oiRRXY)PEGy1896D#SnZSPP;MpwS~NJ4JAUJ1VK;S6%1 zRoaXl6Wt;kQ*m`J`Tu%@)#`JebIL-T?r&bExnjmw?_u@%*E-Cbz4(uKLkSrolhT8V z6+a*6xUR2ZuVlCM1|{}KUxt0=cP|*CeI`X2%=rFgrgYk^ZA6nezS_5@X!}2J57ryNPb%R`@0fI9thkj8fw>F0)2K2+J&Rc z|G(sdjZ8natA#`d43b37($0^KA*BFFNEMhdC6b*i z)|2Pti9*N9NC9no0B?wPP8(6hV~ecTYhPP~7vIF5qcx;+Q>}S+_aSgRCdZF92-j}H z!1Tca0WV^Ob41B&%u-gEW$Sanb%Vtj2j8;*=UMWIPC}M;)%5(Sat?_#qt&ZDAN3Fz z7qyUKX}P`cd+JG0wZfY|8RG#_7}c3?RZP`5!Z{QQKdFd9BM5WQEH=b4#<%hzey@>7-4kOgrwy=E-xLWt0kZr#%k(n{lcFsp!zxzA+HN%yF1`T8nZvbpO zx^74K2?-KgUnvU2KmnBS&3%BXz?5)wm*sb*cqxo_$UQI|304-y3%20vw(QlHAi>r> zc(Su|Q%P9+FjGnv*{wd}DkUxRW2 zueGc%N88#5C2di<5aK5EKK5jf7gW`Y+iX2Q0W|F$5}o%K{{KHuWKII!$+Fx{+;ceH zU*sAWZ0e{qN7MyL!E_6t3 zJGGh1wb~O&57S*}tKix1JAz|#1CmkBn!s;_gR3N>|0u>pdfau2nqZ*s=EdHGA$i%p z@(ucZ6Ne&`U9oUAIE*io!DiOn8?ZZZybo}!vf~6(YqGUxl z3DN~C=1*ft2#HzVf6Rz9pZ3v9aCBmt4C?}uElDC>Pox{<2;|b`?YK(T^@yVQ2t}L# z_g~LeeYt?Z>pqjniFzs8d>?vYyk@=}@V6eo=tg9?!Us*WkkPqMBiebD8HQV*&G0PQ z7ei)C34efqTgQh~B4+yI`4sgJB6d5b1jG%NK3KpxYbQ=+UL<}aEuP+S6+={t&B@GPn zg=y(y0*P4aqjPFV{{AX$~_wK>x7PXE8?V;>OQ|SqBb#4RAsOP_i@+yuKVW^{X z>qJ@AMbAJvLaBe5FwVg(!pflb3AAb>+37m0w}sb;$wITw)6&+ERfJzF)*NXVU>KYj zo4C=o9OojyQ@`F8YFm#h0`&EykB}v&O5#<5!0NFCIwYb@-@>0aw@wGr@`jN#k!!zx zF3UZDe3*EzPsRI@0rGjHfMewLUkL&p4+Sdq=&#&)~7#OGj(IAuJ zJ?)+k1F1}qLPR~!^hd}PJY#Vpp@`y9%1iv8#DoJ`@G-k6Fy*G8Ry9FD=<`K_;7#BG!NC3w~JMQK_=?5C3PZ6YbrG z%8Rs{X)QR!M$(y-GEpu5*PFBsf+1wDUK`f5hAaX0vCMBk4sE+$DVun?1{}4Xdw&tw z?!>;C*ZOseG+Gh}aW-5DEhqv!R<7_}8L8gBVO{My<1DbYiA zE82rJJgU-$c4wQ5=zMuK1nqZ`i><6t+5fE?{Lw#!1_=7Ocl5%Z7$4lNaFS`PW7|D4 z^H!`{C1Q>nafYP~W_5VC)}L(pxA@UZ&wsyQ8S>U|$L*E_{}K*3lF9zRLHuf`c3)GY zlb;=ERaMbYK1mw|vQqvA&{-Eq8LGm~0>EBgPJrj&#>mmy9(6=O2Bah&i$h2H=RES< z{ALaTKLKf?xet~E?EX^m#84q=8MukBrFCY#Y6vw*rV7NA%{lLMDMT2^J2ZxhXuaJ> zjmC9)aipI3E3}}aA3vi?1=a?lSU^_|&0v6a3Ubd6m4+o`0){U@o`?ZuPCN*~$#D!o zh>UV2t~c2e>UKaA5!=m-tO~@jaK*KP{mOSkt~ByU>wEFIeMJ_eNcd6t%c(Yed~RoSbgjvI z9ytCo0xE9J*1&AnZ1bg_CAf1|uCIna?-#J(`4 z3^Du22F(WfE3FbpXSwX@NJxv#zJOa@h_aoYmL`l~Mr-Lfq=>Y`L|3{g8==&^02@9& zcM!jk_L6(lC;QFZXyn0L3aWl}un-O^W@|0N@7z8&#B|*Gt zY`aCBv>(>#{82)7mYusVIv^}gs3LGh9_XVU)}Zuhx85d`fm6BX4893QsKdE-K}aLi)OOragUXs(rEg!`TQg2J@d3owxgB*~PA1khV zsWghS+%M(G3uqc%kIlmF4wJC4Y>A+G1H)G(1F+nZ1Pnx<4llO z8))<2cGRgO!X4ng3!IRe#!#JUfD;-*7ehMG(i+%G^9`Jxf7|vpa>JbB+K-)Qr{*j)-cJWu*E}lRFV3)*GRgIX3R0xgC?H zHxmn533Ph-K~c2G;5b<)C<)B)4Rl_PLu3+XX(&(viKP6m6+L$;<8|;iPOfHmESCh{ z0+@(P(ViE9+KJv3*IH28v<@nEZpMze=mUc@pEFJxMQWPyF5$E*_3Q6rmYRhl6{frL z2~y5xK;%VkxaS*(3fqQ)R6&YWnL&WF_h!U*idF8i1(M5ydg4}w z$O2Ujv&0M5Nf75Ftl0hOZ7xNtGL?cd!=tEI$;5lhdVY)w&DW^^3dE04(8l^!e6ZPF zF_N^U#nngabc?Dkx-7D0r*Se&iYY@fMN(IF{HJn14>U)#6QKLPcg%zbCu1;%ITows zhl~xhr%`jP_=j;Y`ujDXztOK^vm5Yvh`!pMUMy zSX|v3Auy~Vk&;?`j2zWl?>={E87Ve{d()!8$k)i3OI_&|=T(2OS)bOPzA~kZ(NbgP zw#K1Dma}hYYBB}IwKB571hu-tGH%A`harkKy$L`am(5@E;lTtpCMindI=j6dgp}&) zF}ADh@}U?ql+a*U3a!Z_+RlA0DAWOOS4p);p9|qZm>r%H>$9Yzedj_BMSi`oEpXle zgu0#kc++t{1{38;Njo2s1j z8Nn+aS~T+py*a}I#(m2Ht*7XvFn3VpX22Zk0?fL12eSaO(gtwqj>)NtAs5qqMnt;dct48 zqXwu8Hy;OV^csnzC@e5}Lw&`XRc*>fFCQMx&8M@+62E^46LR{sgI8FR(CjwgoCusz zRUtgNeF&Jp75noA3c_{vpRG46y`&%s&m*%c4B%}1*Aq%TAv?n?M0hisLU+4jz%%fT z_G4iaCniW$Sapg%K|-GBYi}S?@(I{_1ru@TbNhhoL<$_Rb+H@hx-D}Jjrc~Z(FJ*p zwpzV(qkC^*&;$INC>A&g)!AUn4R|Z0MemBE3ohqpIse4(+O9L!Tf2vZfQI4%t2gen z*0s7$-*IB1EEVBExymbQ4+2M9I)rH zFG^Q10Bbgmf>PW%>G$;tBBp5J#47`k^(g-xCwewPPm%%`-A?A^-S=`G=r_<}TZ4X1EVnm2cph`E+8HeEL65bjjGWrJ=6LxDzNnU16 zFqkYRRYB7D)M0DRNZ^d7c>F_vK7sO16S=A7n|f~p09pD7NPa?qxZRNyY(E|26?8F` zVMzOVCJQ4VTBl$*WYcmn1-uM{Ie45}2d*Mn7;7+JxqP+nOIP9+Nzj=OG z3%0yV9OF1Y0XVqoXI?zx+Rz#e1gg=`spYTQ3XdT!MM_RFGp%s(nf~+B_I@$b9>q=X{x z5ZPU#PvnluaSZIDBAWxtAXKB-cTQRtA36<;=*C(88$b7BRnWkeNz87-lv<^`2G8U= zbF}9OGJZfXEGA&;5p~4}O?Xe8y`hZmQm2O-jE{5N``Bfm6Nd~v-78xS29+t@kOoN{ z?H3k@YKp_3n5mT?4XucOL^x!S?3PR69kCNBDsG5jEa$s!6$|eg4$DcHjM; zsQ?jkDu*pH|46f`-$uaAE>5QX5jhUwQ=VB;zmph)4s;t5{%QKD&9x)zgln|rw(h`= zpirA&A#0zk>|!7c{H06tju`8S2-%$N6egH{0x3YxhjT{#$WX_e%LMtP1#2w2?sJ>P zw!)4w#A`Io_}!ZXOwM;)%nobn*+I-$2@>5Z77_!+p$@4x8Yu$=Qu~WMWYYhM0osck zJB3wc{SxgcvdLTJabKILg>&p}4kUr3BUI(=MXdC9B0!t!%d?d2nA1Bk_=L*&ja2-V zxW8X^)ZH%k-W=LmSj{km0{TTIpOi68i(ykNQoG#C1pxF( z>R(c$5Q^S#4^vs&F>E>mk)6xOosX&oJ4cZO`ov)n3fU$;ix-%GMR-^qcJ!QnT#5$s zB{Ree1=m{IYp!Z&yF)loP|rVpJ*u0+|FQ2RS&Lydf<%TLMQ<+`5|D`0^J;B<_Anr{ z6-C!<+OsS>(0z&QvF(d~s_|{gHl56EooTpk2^S-mae}pD0&8eV)nhl~4~w4(%@!ssxhtj*_dR1o(L|x5LI2(nN)_fBmEx-3}P0 z$wo64)3QK{v$c#IC!<{>eP%!EW5NED5V&0(3JO67l75u3+#?W9>frukiBm5d zwUAauu^RI!fDOsI3MY-`dwM)y%Cq9+YbOGDV_w{8pm|SmL|ozJ4Z$_buv&TLyI}_? zlznLOn|rt;63~dO>t(M2?{&ssqDDvpmy{c*?RVT$*dA^M60lOV3;ptp@F(cd?A)P? zq$^9X0=tS2tMaQd_7_(kxk&rV#n@*Be_A>mM@w6vNn05j+yD;w%xqI6))X58==nJn z6jRg!73Q~+9IQFCrjhLJ)nf3x8*Eo}Dw+4U(UMBAyd4%tw1&%No z2Vh_UrUR|RzX_f({-2jW=U8rkz47W_(>f>Vv zP*%{79g_}bwi%;D+pt7SFvie0f4f{91nkc4?NTNn00=SPF0o*t53y=(=v!tGh#|tH zT9R4Z8NjD>J;0>L?m^G3MgSyeqp^x+?LIlw?XmKz7}vdJEK9|N0=rUq*PMO5? zBR=k}f5>aco5DeyXBE=+KgAYJp!9oCGjB?Ww}8b>hQZE51n17_YFp(Xjh9>V0D_Pj zbyg4)KJs#FUcMBji5L&~ovJ?%6y5V)&(c%RC3v$A65_Xnk)5!bkq2<=Q*s#4U-0_i z;(zAyVlv)kREHp=y_eDoL#v$%1{)%Kusy;C7(Hb1-zBLu+ff9N9UTiO-Rd?>S3>a& z7Ao_sY!Sz)6>VDunXVj`Q>t-|!1hnE2xOmH?c(RromLiDZ|m$O9l3Rhn|Fy#MYek; zB4pG)4Yzf5&O!7Jti{*PD6ADk942c#Pe}^cE|nyE~Rk zi!RgLG~3%~nKBqfCJZlI4WZ&Uu1M;JUV?iqqQB!sx z>*cj9KS9do6DU$&i+I}ylU?xB0^oLYtYZF4TGFYmzU`|axZaE%L>Qvm+XItqJUErH zozQl30LWWI34Kj6*kNU;6M=C8h2aFFeS`?8JNbB%$FJ0Ryl`R0Vw=3zsS>PeAQYZ3ZTbQr~#z4c5xw0W+kTbw4RE6k(pw>il>^vQhTk zv0!{${?WVbS>xslj5X|luPY7-!A3*KgN<$b0=#qAGq)@q0msCWL*&@R-(l^7#+rHx zAu`wcc>5h$gW?L+t4~j!B#Er8?7r9a?++sF0>ZHBv z+_7YuBFT-tjq1N-OuuOBGR8vH04T``!A_HTtug0TMJ%L7PWk^j1CaX>`>*N(CP9MC zrTjeTBdRPFUy4?C>VDo|44CA728d}Doq@nSH;ELoG?-W6qXa754oUz>N0`_DD<^dQ z6g=(S$e9Or1=j>r5r`lPFVM>lRTiMZjI}PvTuHR1`)PbKNiv!*t5?L-O|;>x%yP`&JZg+z%p$W)Bp@5;{X< ztkSETLgA9U>p~{`kVVDhw^16WVvlBPmDzmgPlVb5Jyz#K>ZDoMb(Sja6Q!&`n2V}F z0@4Js2mTs_pcI%n#Mg=_7I&>h7D|7v0AW*JJpvJ4V^Efv6{1|G2?w9U%g6`8GNx;# zF@ko+CHl5~VexFQKXaw}loK8pD`d&W0AS*h$!#COc9*(l27>LtLs+tuT^tg9tlJJWp9T|2ap7{_5Gs$VZ_gyQj+aeRnCph;rAOkqwJ!?P4u#a# z$?r5{jVci%RX8pTGbn`}Rp4-;4aNM~y(2d(U9N|ePhC&#E^8U?Eob-zEZ?{hi{3+p zu`(neHIE3qdN=qG&Z~E*5v9_4z>(Fhsn2@o+6I$MJ!<*fwkj|}1fRcz3r5na1bcii*85~t2Ev?p%&#+;d35|AIhU$VelfkVKyUJ7=yxoWgOwR16?LSEAJtk69{#|RuH6YhNUQa1S zgJ;(G0-2Tjko=83(NfBS@|i-j7#2hYcnGV=3uA*UQJN=qY|`>Fdukm>yJ$?W(szhh z29aBA$SYl)JOuB5|3kTR*ZK3ql~ZIc_=|cz1b%im+D`HjZm@(Atd;Tt_U;PV0U{N7ng8Qeo>ZO(VVp!JRb; zKn$*S@ygaOz?D(GkcFPy6G*!M>2PAm2fvW4-<9$4UNYd+Gm*E;VD8z9b%184#nI4> z=2uXg&={j3ug_%-50H4gz)946{QE)JHkdmV_XmHC%fgR+C)eW~nQGgWr`k@3>Bx?k zjyC#<3)x#AxM$kz9e=U7 zmi%8i76)qLd#sF^7vgRZASc}olk1ABYA<_Z+E(U>*&Wx28_QuDuOpHhKq$a;LZev9 z0+ccocLZI5Q7!?tDoNET*uT|!Ce7z^y$NDjW5lR->*nGO&QR9e`3n_B8wZlzE) ze-&(pkSp;-T_Erl^BO0>5!0tyVe)Rm#YAA`dA1EbK`;}wi&Kza*uwJw>sc#yDi}qB zKN{e)OKAnCqA6ywEkNsMTXR2COqiF~d)V_miZ1x2%frt}oH5etEeM;ue%cfb9k16Pwyo z5>*#{UKXE%fSnDWg*q9vGt=-;P;U}5D}^ebl~J!;z?e(xnGV$Zy}bz$8{XgwvhC~r ztsy86pZ=@72M5141xGFOiIN7*CThZ43f?BOEC&=9fCp+!`7-6bupXf~PqreC)y)Ud z^=X=|;@gShCHGt+LD$KIQ4lF!Yc8GCJ4RRH@eHfunY43Z)7M z<@%TGN+w>x@gj+s;Q&34ItN|=+!@2#>T;8^`^o-?PcZj&Vu3jBF!#Y%UJTI~B3anykjbs03w~8l+i8{8{z~)FAEb{2sI^${ zstw!-^G9d~r)HYqjV3x_p+^qt10K0h*&h% z%b&rm#_IWbnPG@FTh!lh8P59e>glM;t=NzP3R_20KNLY5LpuW&_gXju8UW4_+^c)u7_#HdE#k`C{^tx0graIG zZu8TN*tlY70)VpO_$g`r{iJJ@id}nT5dc~4Y8l)d7H%=h?z&fTN^R)&+jHjYZCoth zcApdSqLdA{zWXD}ACkzC2Qd-j3=W8N9Y#NEgyVR_m?}lU$%<0{~T} z{+?(9t-%Fa#cTufDLwtr@U z;)kv9xa%eYgbdwzPpxWJTWo%v%C+Pfw_#hNF0Jh<&B@;hLs8QE7Ui6YlHpm!#TNC|^3V7RB~xpYd3zs^kiwbE+7LeeMPYe@d-rGZes z3(-_stli%Fv>qtk5@CR~`T!zQ^J(h1{?cgRH z2=ugu09t>x$JchLiy@SVH;|muezL zXHPbF9}EUJ{S`AcJw{K(g0Mm*mLW%#LT>-UjZuJ0szf@r1Mo0qB_ZyWJ)su9Ts%+Z zW*M@h65}qyG`N?IL){N297;fTVq?`D)hcL`7hrTAJehhpAYdL=E$CG#qjAevP!oGM z?k&!PwK?&ud@|>FBUhq61>ol|3a8)qLLb|-*vN_g?kdZSIlfxiveVJd1Ous=8&@II zn73qbx8RAujG|LDcxZ@7sM(iPi{b~t;{GKiP^&sS6V>;IEfx#vx7Pch zAAvV2RzX)~I-@=d!cWe%7tWJyDe9T1;NJz4+*c>|^AckjCn9%dJmpV=&eTn|CICs^ z$7tK37|IVJ1$*LN$97!6GVdkVav?V{g_OqUj|Q2Jc0qI5h)BuabOgylLlZqA@cRWP zlLIxx=8zOSDWIqKk(}B54h;V9Q>@kciUz-g++}&BPOb)jyQ(CMhb48hK?M0%Eg7Y^oYI}x5gai4708|t|G%x#4=H|8WCq8B zK3*+!7^01L&?>D+Z+jzC^~iSlLzC0C%5c#Xu7(97+x;BmdIjH zllh2l!A#e6qC>u0Yy*R%%`#paRRCMYZP8qNwH$q6zY>ng?vml?$^Cvk_}r#Rt57-# z6x(+k?hD`#u>%Yexzg5;aYYlMf?s~w;U1Am6&eO6i9%kjZfw5i6WK*V-#!*YcpN>i zzZU(1l@0;1&dmje$mXpa)xSH%joG4ts9d|(Yit-0!LeE)0NsOYZGCw42tTl{`GH$) zy$JmNcLw>l(&aL2`J>{RGCt^SLtlEDh#2JIN$xTS3*D|BO9L!*E@v2!Ox~)jLldR@ zgak4{LSO9XrdQOhD;$5#AvCVwuR22o71Q7Dn76+%x&!MZKxZAw0XZ#HBo6(TIorJ9 zO%yHa-w!)VI1zOO$!dd2bXt&M;{)_LWho6!_D|dB{e$O%1L-nd-U=^+130HQmDUXS zxUL&?Ij_1M{>HX=*BMPy4!2=D++INK^rHjKW;EH#Sa4e>7z!^Mrz$1RU=7afj9J3< z^)tVY1*R=EfcvwtihQfRmVYGl&@HqGQJ!PNZuwsIbq+hlJyz1(MiyHWBiNEfgN%pj_OsK8fDJ~oJoF6&Gzh^@%kQcIP}cv$p^Igi6TCvIN2%;N zT^;}2m-9rj*dY`c2ZLpC0MVFK~}7XiyvB8vJ``QzX+o!Ir;Z7Mq$lkFPXS z`l`f;bZ%7w9TE5u`j1X{2K!$9aJYmW(b$bq8q|7C$+_2{te5w*v`tzq92D|~-(<>S zzuo`PnGqxHdx>fuPZ$T-JF>ktrx+5A3Kl5wM*l5ja1SIZr-m!u)^Zie`#HYUsp)`f z{S54m^Gjgab~$1^>4&f>hYAYOGYwL6Hb3X6!97m}di6ykXVjjhBAQd_n*EOdOat_> z^fd|_x^tIrcbSbO5E{66X{pT`t_C_^eE0z6xA5Vv#K+pMCX4i00jti3(2 zKC8{~T5$IOSa&b-lO9GvfwaFX51_}p?C%j~9S8nz$KLC}f&7v$sR9Bw$9@V@VzE1L z*ocl7$d$O>l?Vn(Q}uYcVY^V&l-j4VE#u_oxEdOd*@l**hzymjc%sqvb6wD_lj)g% zru@V~3!f1aHmMO*CpdT2V_;yftLrmOi`g9nqOfSI)Cslj_>2BU#uoIU*|vv@=`^E! zVSV`wdpoKlQbi!>BaXdpqY7uB9XG?^qXPEZF%9f=xv8xJ*8b|Tp=1ylg?M!@t!`Bu zVp$nKo{7$*li4)mvu!Q%3V770$8#YTsTmovz4v8W9DaI$l!wh@`vmog)P2b%Jh zWa&85cZM$prn%ntWf|~x^aW3odd?X~BN){LO~?|gvH6th|6OH}vfD|#=NlMFv^Thw zmfZ(9?8d+~W#)-Q;|o*IGEl+impY`*MmGD&uP~t`rW(s2sF?6v5kkA_5fT=WmqP!R zmL@p|J4BN#{t{A4PkXEnf%uX;E#Z(2HK-bSeJSw6G5kt{LBUO0xZCQoTvTMUHVRIDr%=^+fFPftE)d2|Q;XB`0?nr`9>|XcqCWnF zR0bnI)K_F{%E$d0yuWCl8PB#y=mopC;*sl0S{O@X|Hzbr_?;s1-wO0%c!A7jCK5`; z=F+wJj++!L7p~tdreEvXt&*)v1;5g70Y|!2i$4S``*6fOb{SA;F?7bZGI8pzeMKv98l2L9uXx`;;zzywVQN>sX>apee zk60@>dn7XrVn0+=P=BKcfX&oEILJHvI|GRY?4$O0X}2M!I?~8 z7_1pVUJd2?#!5+_hXN}sjA~NKu{XPQ#i9agdF^fH?+qrkt+!_Z_eTfR?|}_z>K=AN zF!L4_+i>0G0D2pC)?hn5flt%Rn@hQGwi3v_y%GboF^CrFmy%`!JMiI4B5m_T`CLgp z5>*c0TBQz~6%TL;sQNC>``Rc8nYPZTR1|{3)(?q!SoWQydaz?-k7+z1vx8BU8HshE znwhxk-JfW1tnYZqSe$IZ5>K2XmkA?0!i@Ldn2AbDrFS#W@pcIo8qu=BbpbaGt?khk3l{shEh+Rv85w+4$X9ya~G!}&z?bvAo+y`mb zYl~PN)yrG}4-M*}1qF!bCr%l*OEvbkN|o{AVpbP~T2>LugyThBSPxZM;>AN3Wq;vk znoBTQJk(q^k_%aWWwN^v+42tcOjkbc066=`lh1O9aH{l}|XR z!d#PDAT>oT5vs?!r*kzB6ggG?>XIl+Z-a?ZcV)byQPo%~%l$}#s0bpqC>Ze1QuxVm z-9gj*L!7T0aI~X8#tj-uhZZgo-BYQ4HB)lGI}fXx*uqcd>dOI=|M@% z4jZXxakk!8&|E#f7M&RDiM>?;{Necdr%zHDw+~cI^sdJES}hwuLN}y+_y{*;XL!Uh z&DzLZyre$onzDv{S>OlyUK`->lVN8mPM5DG;}N+@vz1-PXPTJRCx6+VJ zDVZPkK)S|_>Ufl$7M!5bYh{F4!}mjgB1;NgOOtW<^$nfc|dbSQ?a zfD|)3M`l%8D2(9tQtU* zIjr=d1~rupi8t4nL=U5v3@>mNq|IpnBaT^_CLX2){Dr*1?W#Fhb_X_=AMb8@9p5*_ zd;a3@o>rUBI=WcLFwNsDLkaQ_miyCEpf4p#@nE07vFu*F`U^`DvJ+Sz0RAm#03Ue0 z4F)-#Q}h0XXqg9|uuP;Kye!ag|% z;GHB;DUb?z0e|tKmpxV`A3@q`j1@rM+>^KRNr9go<-*%yYx;oS@TO8bZVMi z7qXtcQl;^&^qY0e%RdE)BsyaCbipA_JuS{MG4z;oy_ zu-@oMN0@CWfcRA7$(jb(0QL~?TEDp+cy0Gelwho{=JXzQdBW;+%j?j#0YWb%EQQQWI z4>yHm$uPlvDsvytpi;D};`hYAy^AR+Bm)J1*Bp2DSZMKqlN-%7N_1T&wI?I;O3(k^ z$fcYRB1r+!E+omlVM7JH8>HT~-Ug#ZHmo|UK?M=`)q4;_+b$%aaRWj>6S1b1a{QOQssRW0O z7j_W^C;-3=QH>1*iWyMv}>z(1N&; z?i1E`vOgU3eae74xHtP?v8sbdXtdXk;3Nrr?Td6fC`vK6Bl8}CWNV?&0{Ufy9RpF{Rl{ijEYeJcv4>;8dVP@kvKOOWcgsp=#*FRUXb=^%)@F3JfJ$_Aar*cE4N7)GAL z9Vklof*q<#?{e-^j}r^q&XX*Ox9<-rPhVJ)N4;Y}&^@xZ$_$Ip-kafCZpPuSpC?riWR@`XSMB|tn|Zo>@l>8iv$%4 z2D(jH>71f*Xi%9qOgO$tm{g&Z8Vsax{O6fzJ_ej)>ed8oEUU*|AJ!o|&{(;E6uo~Z zbbqw*CSJ)<>#9Pja~Z!j@N#P+I?ljSqYu%i5`?w%oqD&Je@MsACGbj6T9KLeoAiF` z{DwM!T%?$3=2+=hR|F)!r~dpc>-YnlMc`V(lP`-*7u+ z+^FSG7f)0NNS?~mg$TO{qO7!fl|Ph3n_u;EcFU6Wiina9;+aF(+^N1Iml4Ndrq&t_ z1@|&cPNa4O`xwi(@Y?wPS;>21@NpsbKKss0_u1MtfUZ23-0%(U=HB3y!Wy|r$4>{-lwQo!o+Wqbj$c58t(u&vN+KBm<3j9$ z(+15;TXZ^3=U8MIo!@eEXBBVvo_|*F!>qyxfqXjDoG|96OJ(uw1E|g5Ya_p-cL6%G zQEo^KraVvib`W#+JB@fno@v$hHtgn*!jVI_fNP*#Zn{8*LPfSNHp?(|A`kglf;X*y z%Nd1(_H{cPc!y`t&hRpoW|cvjl~xIviZ2H(#djE5ynNqdgqEtUP|?*Gz6upB>IK07BAb}nXu%_>fAnhw4(^@v zvIpAgA6x}O@;`|vA&?h0Y&F-T%jqJ)x)-P-fETYvpNm_XQl0TwYPtTDX3z743E(*` zpuTce-7^(c=pb(lNhw1N?0Ap!F?wBm&?{F_m@0vpNeTt;eXHwPY?;@mn4b|5Y;B}J|haLijC9I;ODPoU{Cy)B%mew zAw=Il67E1u+aq%ktWD2baT9ybmcBy`^%yBJ_!uYGMl*SWLNtLY^ktmbbvJ;tPAB)` z;<$Av;K3x(odJui5*FuUB8*3OirE$tOJo-JYmN+-f9it7JMjGAOc$0^;JbK16Q(U& zbD7ZPIsJ)JO$8dBkO^msWX>Mzch|%B4{ZRWXGv)BzfeRDD%|)2f$gK2RV?lrLNrmiDmN2G1>JWo4m+%g4WB~^p>0s>%*fz@`v=4*VhX-^DdTWB*JLjU^I3TwAM&u!GBmqr4$lxbkqCi1?Ca21OEDTgyA%+5WNr2xoiVs~k;$qt{h5;Qv~Tnwz1#4I1tA_Hl-PO)D=McB})#GBTcxRV8< zu64TjzCs~}E;213+(wlt1l0lfqz91tgk2tAU{1YwV|Nq3t-n*%t#*UaQaD!kg{|n| z1>$l5Ia9{F1@%H>ps+m^L<^(VJo02Jm-6p^Bk}GrEh+){;P+1bzg~u;SW1R`he6_s zaFa4Q2UEU*rvap~m3$tkN) zwh=WWjUzTfH2#{NgpbV`+_|Rgd0&p^u7~Rc$$8|FXM2?l~)HA3*2LZN6 z;>BOKZBlr1ntQ%vdw@bj2L90~+j>2Ue}U7JS?K1R=(t_47>a=VBntkJS#J1vahNiS-ka!I&2C)5HxAB$N>s3*;6wi4q6@#=eKDY%W2 zj(U}j@cr4qt}zrwA_M{3R42z8KL&F$`3VCP9gb|XeO=~as0M-!v2~+2cog)LennB4 zim=0@Px# zN+M+5&wQN^YQ6S0Lwn57`bkm4aE>}owG4a==vGYo_1^&xLYX^>x3|6Qh#1yNv+zT` zJzyMAI94h{;Qs$e$@p0^oZg`Pbqsbb4$&@s2m!GmS(NFEhQm1&MHE$x>FmT-hr-O7 zI+#9=DNi0DaI&%u-~X7SbHK_YQ3gD$-Y&f=GTj0#ggPv{|Zv6K`&{W&0p zs0OR1zY2L@I63S=+WDFzXj^pUtM~WeXEJVW9i$%x#WeKi$t78T3onL8w8S&J@>hKb zNfD&nuKguH-ln>V6RJufw8_ITuj~@>R<`$4XBT06j*Ox^>y2E;wM%vAD@+zRIuWj2 zAzrp0v;sq)_4zFh2Dus)tikZ6gm>QjHr6+kq-I=h(D9w@O+CW9Xny5X;Ru?+=k)^M z-H_w)g;>YD$iRc)$rWHy#QO_{-nek{4(^m34t!sRVJ|HL5DTUWJr>W;eKXfM6LV5k zw*+~r0^+8({5RT3zKLoD-xVTv3&DJ76W7W&R#u7WZFCKJ773sgtw0!V&CGKH(ue=f zv}w`A95xLvqrO$@4PlrSVr7RN5DLp#TRMr7P(eNd#}s^Ge4oo1J6~;D%e)Dz@CFcq zlB1%tHeY-7Gtx49SdVn#Fv)iWr|ESaU_yyY5Cw*o0%E;afmnfincK_w!vIa8=P{e* zL~T6Y^=1-nZLT%A(I{Y5rIx9*$Z|^d(+A8cYK7Q2y=xcx=5;^lPeS*&CdO4o(`g&9 zdg$LkqHMsJFn$gSqVnY#qrU1e4-dsFaPix1-g_o_RjVkWhRI=LszUut$j>0LhpJe;eb)W zUk_UfF{K%p#tk7#7%nX8u4MF_-+4u-`M>M!dPmfFxCBn4H+y&g${QM#7AIqV!{Bc? znd5deRszmD+=L>72wMzmV4C@vjE-x8MAx&-sn&CzbhZ|t*+%6C1ApHOdlg50zy-{K zauHXy!HH*j#Lr;!2G_nu@2OgOVPpo$Sz{<_NB;}N?Fn3c{RSjf?;|nLG6|Flnhi8Q z9IOZ6+LV>2Gqty(S-qEs;@<5OgVm!wx0>eb)3C5}C}L|16tA(cu@HCBxe}IU47co0 z=Z#?;wO29^aEI8%kHqYPD2><}d`JQBq5Px^1rr3}sqKZ%k>D$!;n(zU zaYwk&0IP;ylKyUe?gKT$!>N&B^v3skN<^X;^|?LCmxGOAQRKI z?rPFQ@Hw)M@Ou5!IM3R4>lPk~FLGhZS?=3k8ZZRhRsz+lXLKbM2;)*+P1Lq0#5d^k zWF`z_B93G}JGsQYK>{@nVb91Io}VbK*!x38VtQ}5FhZ3yK$d?)tGc6?3q)f}sIFEfM+rr;`I{O}JObDwqe1I161^CL(r9`{01Vw-# z1JKzE8WdH~sdUZSQ84P-UhshImBEj%=v&Ks;PZK7hfbq~ui$=)H-VTDo-2cvzPUewFfRa&{us(`YQT|R5OsYOV6iw2aH zT0ldq=R1ndeo!T!n+S@7T(Eu&^NEd>?XVk1+{bR*yy<@Ghmk*47vw=SAOSV!EiR@8 zQYV!9tr*@O)_C5?!KdB7*1&gcz}tV}mE5mm)FM5P4&#Uw4Wge*2?SFG8&UEyopEDE z3a(gg?5(*CI(SpFD>*SL4p-#K)I$2rxZ^W4bY7?~Uinp*x(1j-!-0T5{_ZN6^S`={ zWW>@}3ZVTg2`zGL@3S7LJfaXC zbj@wQeaA+knY_IUx+%PJV;@sC0Ayxki#tUK5)LDR9L{}%p48baPc58K{)x)5a;rnM z>w@reAfm5C1zRM85G9h@OI5~L_j8BQX$4pG5?y-?Q}X@VndWQ|M5Ur2m7pEF)r(c#!;6f1qthIKM8TGWO`iOZ0j5=^-L~()%RYE_^6&$Q%MfV zf;i7sZfZ)N@T3VU&Z6M{W&l5BPx0U1Ax%iO$7T49f=QXt8Fo9tC;ao!CNwe5^UknS zyyJwr6jTB9F84C^T^7f4*R$-xdZ_v=7MC0ZgaMLNGfN(E(K$3dPhW+T!uM^4{jkKG zPwr-u{(ZQ&Xa+rKBFJQ{+?EPFXNpQWryi>Z<}s-n+LY^lk>tRFEPctF0NOk<1?_fM z0odRe_ZenaGL1*YoulJ@FGwHv!H7}t0fHVL`pu2B$Vs9x zkOR<$*gvvp>&iRp+kNOmr-rZOtiP~w7X)c#jBbw0wXqGAzN{m2ooAZH9U+yc_6l+q z2Kv%}RznKoc0Ti5YH(X|XNjsNW;ndseJiauqupQ*6^HS9SfVG4!&@VoHx-Y87T_+0 zXE)!>+R&%*0QeKbZ<;kUo_?k;tg?bkl6So{=2#v0J?itpCg&3IUJEbS>x$^&-%^3( zdcR{d${xdb1`$Kfd>nvE*~AINEvq!gjh%S}sC7)TfqIk2>J{RV1*iVM*v%WK%#Cyb zy6- = 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, ()> { -- GitLab From 86fde367c0b10303b71a5f52857e254a2ee1e953 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:47:20 +0200 Subject: [PATCH 299/633] Adding migrations to clean Rococo Gov 1 storage & reserved funds (#1849) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following [polkadot#7314](https://github.com/paritytech/polkadot/pull/7314) and after merging https://github.com/paritytech/polkadot-sdk/pull/1177 this PR solves https://github.com/paritytech/polkadot-sdk/issues/1618 The following is a summary of the outcome of the migration. | Module | Total Accounts | Total stake to unlock | Total deposit to unreserve | | ------- | --------------- | --------------------- | -------------------------- | | Elections Phragmen | 27 | 1,132.821063320441 ROC | 1.465386531600 ROC | | Democracy | 69 | 2733.923509345613 ROC | 0.166666665000 ROC | | Tips | 4 | N/A | 0.015099999849 ROC | The migrations will also remove the following amount of keys 103 Democracy keys 🧹 5 Council keys 🧹 1 TechnicalCommittee keys 🧹 25 PhragmenElection keys 🧹 1 TechnicalMembership keys 🧹 9 Tips keys 🧹 --- polkadot/runtime/rococo/src/lib.rs | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 9933f644297..3c08b9b2f94 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1414,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, @@ -1426,6 +1472,21 @@ pub mod migrations { 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>, ); } -- GitLab From 8f1f2f35ba704981ae90b67f739e0f9485150b03 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Mon, 16 Oct 2023 11:09:46 +0200 Subject: [PATCH 300/633] Publish `xcm-emulator` crate (#1881) Remove `publish = false` to publish the crate --- cumulus/xcm/xcm-emulator/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 72007ba98f7..c77d350bdfe 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" } -- GitLab From 73ec161ebc981f001213bf9d6ad27900e2027e17 Mon Sep 17 00:00:00 2001 From: Bulat Saifullin Date: Mon, 16 Oct 2023 15:15:50 +0400 Subject: [PATCH 301/633] Update the alerts to use a new metric substrate_unbounded_channel_size (#1568) # Description Follow up for https://github.com/paritytech/polkadot-sdk/pull/1489. Closes #611 Before we calculated the channel size during alert expression but in #1489 a new metric was introduced that reports channel size. ## Changes: 1. updated alert rule to use new metric. --- .../ci/monitoring/alerting-rules/alerting-rules.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml b/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml index 4171f92f68f..ac89c58bfc3 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 -- GitLab From e0e566bc2ea59d508bc97f2a6f6fbf0bd26fe62a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 16 Oct 2023 14:19:45 +0200 Subject: [PATCH 302/633] [CI] Add link checker (#1875) Adding link checker to the CI (closes https://github.com/paritytech/polkadot-sdk/issues/993). It would be nice to have the docs people own this and extend accordingly. Currently all known-bad links are excluded, but we should one-by-one include those as well until all are fixed. This check now ensures that 1) no new broken links are introduced into `.rs` files and 2) that no old links break unnoticed. --------- Signed-off-by: Oliver Tale-Yazdi --- .config/lychee.toml | 50 +++++++++++++++++++++++++++++++ .github/workflows/check-links.yml | 40 +++++++++++++++++++++++++ .gitignore | 1 + 3 files changed, 91 insertions(+) create mode 100644 .config/lychee.toml create mode 100644 .github/workflows/check-links.yml diff --git a/.config/lychee.toml b/.config/lychee.toml new file mode 100644 index 00000000000..9b2ae069931 --- /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/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 00000000000..ec606f1b148 --- /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@8ade135a41bc03ea155e62e844d188df1ea18608 # 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/.gitignore b/.gitignore index 35e02e706b4..7feea8ada5c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .env* .idea .local +.lycheecache .vscode .wasm-binaries *.adoc -- GitLab From 4e98bec3f19bdf1b930c264521b275403296123a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 16 Oct 2023 14:41:44 +0200 Subject: [PATCH 303/633] sp-api: Improve error message for duplicate runtime apis (#1877) Co-authored-by: command-bot <> --- .../api/proc-macro/src/impl_runtime_apis.rs | 14 +++++++++----- .../tests/ui/impl_two_traits_with_same_name.stderr | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) 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 74cfa098062..e439a796e28 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 9e014e3ea82..2197bbc99cf 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 { + | ^^^ -- GitLab From 646ecd0edb70035d114a0c85be9f0a1d85028db7 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 16 Oct 2023 17:35:42 +0300 Subject: [PATCH 304/633] sc-consensus-beefy: fix initialization when state is unavailable (#1888) Fix situation where BEEFY initial validator set could not be determined. If state is unavailable at BEEFY genesis block to get initial validator set, get the info from header digests. For this, we need to walk back the chain starting from BEEFY genesis looking for the BEEFY digest announcing the active validator set for that respective session. This commit fixes a silly bug where walking back the chain was stopped when reaching BEEFY genesis block, which is incorrect when BEEFY genesis is not session boundary block. When BEEFY genesis is set to some random block within a session, we need to walk back to the start of the session to see the validator set announcement. Added regression test for this fix. Fixes https://github.com/paritytech/polkadot-sdk/issues/1885 Signed-off-by: Adrian Catangiu --- substrate/client/consensus/beefy/src/lib.rs | 12 ++-- substrate/client/consensus/beefy/src/tests.rs | 56 +++++++++++++++++-- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 72df3cab855..89a5d51c887 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 90b63c9cd44..902feca1639 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(); -- GitLab From c422e3f5778c11e4c8ff93e7d77cac39866bd1e2 Mon Sep 17 00:00:00 2001 From: Muharem Date: Mon, 16 Oct 2023 17:16:59 +0200 Subject: [PATCH 305/633] `extract` amount method for `fungible/s` `Imbalance` (#1847) Introduces an `extract` amount method for `fungible/s` `Imbalance`. --- substrate/frame/balances/src/impl_currency.rs | 10 ++++++++++ .../support/src/traits/tokens/fungible/imbalance.rs | 7 +++++++ .../support/src/traits/tokens/fungibles/imbalance.rs | 9 +++++++++ substrate/frame/support/src/traits/tokens/imbalance.rs | 7 +++++++ 4 files changed, 33 insertions(+) diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index c64a4929dd5..1ac882ade70 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/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 32a63fd25b2..995797bc8f6 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -113,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/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 9f660a5f168..7c0d7721a2e 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -109,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 40332172504..e487b812234 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, -- GitLab From 4145902f1c663c91e4bdb0eaa55a7e9003fe93ec Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 16 Oct 2023 18:53:08 +0200 Subject: [PATCH 306/633] Add missing env (#1892) This PR adds a missing env to allow publishing the Docker image. --- .github/workflows/release-50_publish-docker.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 15631c172b9..71677fc36d4 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -114,6 +114,7 @@ jobs: if: ${{ inputs.binary == 'polkadot-parachain' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest needs: fetch-artifacts + environment: master steps: - name: Checkout sources @@ -237,6 +238,7 @@ 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 -- GitLab From e0065cb81b7db07fba7869d123fac307a435e843 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Mon, 16 Oct 2023 19:52:33 +0200 Subject: [PATCH 307/633] Make System Parachains trusted Teleporters (#1368) Make System Parachain trusted Teleporters of each other. Migration of https://github.com/paritytech/cumulus/pull/2842 --------- Co-authored-by: command-bot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 54 ++++++---- Cargo.toml | 1 + cumulus/parachains/common/src/xcm_config.rs | 83 ++++++++++++++ .../assets/asset-hub-rococo/Cargo.toml | 24 +++++ .../assets/asset-hub-rococo/src/lib.rs | 26 +++++ .../assets/asset-hub-rococo/src/tests/mod.rs | 16 +++ .../asset-hub-rococo/src/tests/teleport.rs | 28 +++++ .../assets/asset-hub-westend/src/lib.rs | 2 +- .../asset-hub-westend/src/tests/teleport.rs | 14 +++ .../bridges/bridge-hub-rococo/src/lib.rs | 10 +- .../bridge-hub-rococo/src/tests/mod.rs | 1 + .../bridge-hub-rococo/src/tests/teleport.rs | 28 +++++ .../emulated/common/Cargo.toml | 2 + .../emulated/common/src/lib.rs | 12 +++ .../emulated/common/src/macros.rs | 102 ++++++++++++++++++ .../emulated/common/src/xcm_helpers.rs | 27 +++-- .../assets/asset-hub-kusama/src/xcm_config.rs | 26 +++-- .../asset-hub-polkadot/src/xcm_config.rs | 26 +++-- .../asset-hub-westend/src/xcm_config.rs | 26 +++-- .../bridge-hub-kusama/src/xcm_config.rs | 9 +- .../bridge-hub-polkadot/src/xcm_config.rs | 9 +- .../bridge-hub-rococo/src/xcm_config.rs | 9 +- .../collectives-polkadot/src/xcm_config.rs | 9 +- .../contracts-rococo/src/xcm_config.rs | 5 +- 24 files changed, 465 insertions(+), 84 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs create mode 100644 cumulus/parachains/integration-tests/emulated/common/src/macros.rs diff --git a/Cargo.lock b/Cargo.lock index 2b2f09c19ec..f12e16276e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.10.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" dependencies = [ "aead 0.5.2", "aes 0.8.3", @@ -792,6 +792,17 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "asset-hub-rococo-integration-tests" +version = "1.0.0" +dependencies = [ + "frame-support", + "integration-tests-common", + "parity-scale-codec", + "staging-xcm", + "xcm-emulator", +] + [[package]] name = "asset-hub-westend-integration-tests" version = "1.0.0" @@ -1056,7 +1067,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -1097,7 +1108,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -5550,7 +5561,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "waker-fn", ] @@ -5607,7 +5618,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "pin-utils", "slab", ] @@ -6024,7 +6035,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -6067,7 +6078,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "socket2 0.4.9", "tokio", "tower-service", @@ -6337,6 +6348,7 @@ dependencies = [ "cumulus-primitives-core", "frame-support", "pallet-assets", + "pallet-balances", "pallet-bridge-messages", "pallet-im-online", "pallet-message-queue", @@ -11372,9 +11384,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -13047,7 +13059,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "windows-sys 0.48.0", ] @@ -13493,9 +13505,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" +checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" dependencies = [ "bytes", "rand 0.8.5", @@ -13822,7 +13834,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "rustls 0.21.6", "rustls-pemfile", "serde", @@ -17270,7 +17282,7 @@ dependencies = [ name = "sp-statement-store" version = "4.0.0-dev" dependencies = [ - "aes-gcm 0.10.3", + "aes-gcm 0.10.2", "curve25519-dalek 4.0.0", "ed25519-dalek", "hkdf", @@ -18513,7 +18525,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "signal-hook-registry", "socket2 0.5.3", "tokio-macros", @@ -18559,7 +18571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tokio", "tokio-util", ] @@ -18599,7 +18611,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tokio", "tracing", ] @@ -18671,7 +18683,7 @@ dependencies = [ "http", "http-body", "http-range-header", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tower-layer", "tower-service", ] @@ -18696,7 +18708,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tracing-attributes", "tracing-core", ] @@ -19811,7 +19823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a00f4242f2db33307347bd5be53263c52a0331c96c14292118c9a6bb48d267" dependencies = [ "aes 0.6.0", - "aes-gcm 0.10.3", + "aes-gcm 0.10.2", "async-trait", "bincode", "block-modes", diff --git a/Cargo.toml b/Cargo.toml index 9e8ead6cf7c..6ec4a21f219 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ members = [ "cumulus/parachain-template/pallets/template", "cumulus/parachain-template/runtime", "cumulus/parachains/common", + "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/common", diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 14667144145..534253b4aae 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -15,6 +15,7 @@ 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, @@ -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/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..f280afdda4a --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "asset-hub-rococo-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +description = "Asset Hub Rococo runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} + +# Local +xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} +integration-tests-common = { path = "../../common", default-features = false} + +[features] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "integration-tests-common/runtime-benchmarks", +] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..f8a917afe1b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.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. + +pub use frame_support::assert_ok; +pub use integration_tests_common::{ + constants::asset_hub_rococo::ED as ASSET_HUB_ROCOCO_ED, test_parachain_is_trusted_teleporter, + AssetHubRococo, AssetHubRococoPallet, AssetHubRococoSender, BridgeHubRococo, + BridgeHubRococoReceiver, +}; +pub use xcm::prelude::*; +pub use xcm_emulator::{assert_expected_events, bx, Chain, Parachain, TestExt}; + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs new file mode 100644 index 00000000000..516ec37cc10 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs @@ -0,0 +1,16 @@ +// 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. + +mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs new file mode 100644 index 00000000000..36b65c6d010 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-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 = 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/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index 6e0f3434aed..c25cc601fbe 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/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index d94fd4b97d9..81471c401f3 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 @@ -357,3 +357,17 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { // 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_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/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs index 1c73124c512..3c4dbe18a9a 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_rococo::ED as ASSET_HUB_ROCOCO_ED, rococo::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 48347557ae7..1eef05c6b92 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 00000000000..4c7e37fab62 --- /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/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index e47fdfcdfd6..bc661ce3e20 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} @@ -70,6 +71,7 @@ runtime-benchmarks = [ "cumulus-pallet-xcmp-queue/runtime-benchmarks", "frame-support/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", diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index f8fe8831d3c..e9a30aadedd 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -15,6 +15,7 @@ pub mod constants; pub mod impls; +pub mod macros; pub mod xcm_helpers; use constants::{ @@ -22,16 +23,24 @@ use constants::{ asset_hub_rococo, asset_hub_westend, 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(8)] pub struct Westend { @@ -120,6 +129,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, // Rococo Parachains @@ -156,6 +166,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, Assets: asset_hub_kusama_runtime::Assets, + Balances: asset_hub_kusama_runtime::Balances, } }, // Wococo Parachains @@ -190,6 +201,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, Assets: asset_hub_polkadot_runtime::Assets, + Balances: asset_hub_polkadot_runtime::Balances, } }, pub struct PenpalRococoA { 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 00000000000..e87c361ebea --- /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 4096cdbba0b..7c218bfbc09 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/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 0c197598f88..cf91c1513ec 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 @@ -31,7 +31,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,8 +42,8 @@ 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, @@ -470,6 +473,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 +492,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/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index 65cf62a610f..46d508d0fed 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 @@ -27,7 +27,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::*; @@ -35,8 +38,8 @@ 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, @@ -394,6 +397,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; @@ -404,13 +416,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-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index a0921c50dc5..b1ec6be5b7e 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 @@ -31,7 +31,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,8 +42,8 @@ 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, @@ -481,6 +484,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; @@ -491,13 +503,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/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index 696462be9c4..ddc5fc0c4a4 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::{ @@ -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/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index 0965600c246..84672a6c394 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::{ @@ -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/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index e3d8645d49e..1639a507091 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 @@ -30,7 +30,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 sp_core::Get; use xcm::latest::prelude::*; @@ -224,6 +224,10 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +/// 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 +237,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< 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 f802073bfbb..a170cd6ba51 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-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::{ @@ -240,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; @@ -249,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/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 7433b8e94d6..aafb61132b9 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::{ @@ -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; -- GitLab From 9c1a2b38e5dd2ca038c010aa59cad5a211de08b0 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 16 Oct 2023 20:03:53 +0200 Subject: [PATCH 308/633] Workspace maintenance (#1884) Changes: - Add missing crate to the workspace - Remove versions from local dependency links Maybe it is finally worth it to add this scrip to the CI to find these things earlier: [check-deps.py](https://github.com/ggwpez/substrate-scripts/blob/master/import-runtime-repos/check-deps.py). @paritytech/ci what would be the best location for that check? It takes only a second to run, so maybe we can squeeze it into one of the existing checks? Otherwise creating a new GH workflow feels a bit wasteful... maybe i can group it with https://github.com/paritytech/polkadot-sdk/pull/1831 --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.toml | 1 + substrate/bin/node-template/runtime/Cargo.toml | 2 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/primitives/consensus/sassafras/Cargo.toml | 12 ++++++------ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6ec4a21f219..6ba153329d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ members = [ "cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo", "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", diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index caca54ce2ba..eb3ff37b425 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -39,7 +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 = { version = "0.1.0-dev", default-features = false, path = "../../../primitives/genesis-builder" } +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} diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index e5bade12029..e356a7b6024 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -32,7 +32,7 @@ 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 = { version = "0.1.0-dev", default-features = false, path = "../../../primitives/genesis-builder" } +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 } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index cb887fd40fe..700f5160c22 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -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" ] -- GitLab From fcc1bb414b62ac5e3e196662cc0ff5ee54547aa3 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 17 Oct 2023 08:06:03 +1100 Subject: [PATCH 309/633] Allow Locks/Holds/Reserves/Freezes by default when using `pallet_balances` `TestDefaultConfig` (#1880) Allow Locks/Holds/Reserves/Freezes by default when using `pallet_balances` `TestDefaultConfig`. --- substrate/frame/balances/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index c408bf3f35f..c294779a0e0 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -238,10 +238,10 @@ pub mod pallet { type DustRemoval = (); - type MaxLocks = (); - type MaxReserves = (); - type MaxFreezes = (); - type MaxHolds = (); + type MaxLocks = ConstU32<100>; + type MaxReserves = ConstU32<100>; + type MaxFreezes = ConstU32<100>; + type MaxHolds = ConstU32<100>; type WeightInfo = (); } -- GitLab From e10de2e2839f2b6e9c16f64df57829a6c462fe28 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 17 Oct 2023 09:09:03 +0100 Subject: [PATCH 310/633] cleanup a few hidden imports in frame-support (#1770) Just making a few hidden imports cleaner and hidden in docs. --------- Co-authored-by: Keith Yeung --- substrate/frame/staking/reward-curve/src/lib.rs | 5 +++-- .../procedural/src/construct_runtime/expand/inherent.rs | 3 +-- substrate/frame/support/procedural/tools/src/lib.rs | 2 +- substrate/frame/support/src/lib.rs | 8 ++------ 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/reward-curve/src/lib.rs b/substrate/frame/staking/reward-curve/src/lib.rs index ecf3af55379..1986357edab 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/support/procedural/src/construct_runtime/expand/inherent.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs index a77aad66dcf..34b9d21d8ce 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/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index 62c77ef7a99..be439613362 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -99,7 +99,7 @@ pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream quote::quote!( #[doc(hidden)] mod #mod_name { - pub extern crate #name as hidden_include; + pub use #name as hidden_include; } ) }, diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 700d777a148..f54252ff9d6 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 { -- GitLab From 5cdd819ed295645958afd9d937d989978fd0c84e Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 17 Oct 2023 11:11:03 +0200 Subject: [PATCH 311/633] [xcm] Small enhancements for `NetworkExportTable` and `xcm-builder` (#1848) ## Summary This PR introduces several enhancements. The current implementation of `NetworkExportTable` lacks remote location filtering support beyond `NetworkId` lookup. To provide more control and granularity, it's essential to allow configuration for bridging to different consensus `NetworkId` while restricting access e.g. to particular remote parachains. Additionally, the `StartsWith` and `Equals` and `StartsWithExplicitGlobalConsensus` helper functions, which are in active use, are moved to the `xcm-builder` and `frame_support` modules for better code organization. Adds a new `LocationWithAssetFilters` filter to enable location-based and asset-related filtering. This filter is useful for configuring the `pallet_xcm` filter for [XcmTeleportFilter](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/pallet-xcm/src/lib.rs#L212) and [XcmReserveTransferFilter](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/pallet-xcm/src/lib.rs#L216) to restrict specific assets. Furthermore, the `BridgeMessage` fields are not accessible outside of `xcm-builder`, limiting the ability to create custom logic dependent on it. --------- Co-authored-by: Francisco Aguirre --- .../modules/xcm-bridge-hub-router/src/mock.rs | 13 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 8 +- .../asset-hub-polkadot/src/xcm_config.rs | 8 +- .../asset-hub-westend/src/xcm_config.rs | 8 +- .../runtimes/assets/common/src/lib.rs | 8 +- .../common/src/local_and_foreign_assets.rs | 5 +- .../runtimes/assets/common/src/matching.rs | 28 +-- .../xcm-builder/src/filter_asset_location.rs | 177 +++++++++++++++++- polkadot/xcm/xcm-builder/src/lib.rs | 7 +- .../xcm/xcm-builder/src/matches_location.rs | 50 +++++ .../tests/bridging/paid_remote_relay_relay.rs | 10 +- .../src/tests/bridging/remote_para_para.rs | 10 +- .../bridging/remote_para_para_via_relay.rs | 10 +- .../src/tests/bridging/remote_relay_relay.rs | 10 +- .../xcm/xcm-builder/src/universal_exports.rs | 124 +++++++++++- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/members.rs | 8 + 17 files changed, 412 insertions(+), 74 deletions(-) create mode 100644 polkadot/xcm/xcm-builder/src/matches_location.rs diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 58df21a6d90..2152b4eb28f 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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index cf91c1513ec..2935d8b07a4 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, @@ -45,8 +43,8 @@ use xcm_builder::{ 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}; 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 46d508d0fed..54455837585 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,9 +18,7 @@ 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}, @@ -41,8 +39,8 @@ use xcm_builder::{ 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}; 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 b1ec6be5b7e..36534a1d11a 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, @@ -45,8 +43,8 @@ use xcm_builder::{ 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}; diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 560a89b131c..f45c3289aab 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 5c66d1cabe5..9f429016f53 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 08d39117001..cb071a12f23 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -14,38 +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())) - } -} - frame_support::parameter_types! { pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here); pub ParentLocation: MultiLocation = MultiLocation::parent(); diff --git a/polkadot/xcm/xcm-builder/src/filter_asset_location.rs b/polkadot/xcm/xcm-builder/src/filter_asset_location.rs index 68dd86d9bfe..df81f536f7b 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/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 9fdd55d9f92..21ada3244a3 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -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/matches_location.rs b/polkadot/xcm/xcm-builder/src/matches_location.rs new file mode 100644 index 00000000000..cfc71eafd02 --- /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/tests/bridging/paid_remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 7593ea5f17c..45dc2d4a3b9 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 124a909bc07..f11143ab9f6 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 2ff1f9fb976..7218e0a0488 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 cdd6b89b7b1..45b5efbc44c 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/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index a24631ffa94..dbe9571d461 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)) } } @@ -329,8 +367,8 @@ pub struct BridgeMessage { /// The message destination as a *Universal Location*. This means it begins with a /// `GlobalConsensus` junction describing the network under which global consensus happens. /// If this does not match our global consensus then it's a fatal error. - universal_dest: VersionedInteriorMultiLocation, - message: VersionedXcm<()>, + pub universal_dest: VersionedInteriorMultiLocation, + pub message: VersionedXcm<()>, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -504,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) @@ -539,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/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 2179ee38f84..69885b2873e 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, }; diff --git a/substrate/frame/support/src/traits/members.rs b/substrate/frame/support/src/traits/members.rs index fbba742ebeb..d667eaa7e9d 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] -- GitLab From d9e266f432b7a9efb5c2c73a2592c0e380ab0824 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 17 Oct 2023 11:55:59 +0200 Subject: [PATCH 312/633] nit: use traits::tokens::fungible => use traits::fungible (#1753) Slightly less verbose use of fungible(s). --------- Co-authored-by: Liam Aharon --- .../runtimes/assets/test-utils/src/test_cases.rs | 2 +- cumulus/parachains/runtimes/test-utils/src/lib.rs | 8 ++++---- polkadot/xcm/xcm-builder/src/asset_conversion.rs | 2 +- polkadot/xcm/xcm-builder/src/fungibles_adapter.rs | 2 +- polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs | 2 +- substrate/frame/assets/src/tests.rs | 8 ++++---- substrate/frame/balances/src/tests/mod.rs | 2 +- substrate/frame/examples/kitchensink/src/lib.rs | 2 +- .../frame/support/src/traits/tokens/fungible/item_of.rs | 2 +- .../asset-conversion-tx-payment/src/lib.rs | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) 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 7a8d571403c..f1e4f1e5ef5 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1190,7 +1190,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/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 8289a80baa1..3241ac179d2 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -415,8 +415,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 +428,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/polkadot/xcm/xcm-builder/src/asset_conversion.rs b/polkadot/xcm/xcm-builder/src/asset_conversion.rs index a246436a9d6..5b76ed764a8 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/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index d7fded01e2d..2179421b3eb 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/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index 6cf5980df0e..4aebb496d49 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/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs index 06d4ec12117..f1b116a0f4a 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/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index d15f8e89118..a0a3085c54f 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/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 0fbffc971da..56117c59dc6 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/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs index 88b9de7fdbf..a47998eb134 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/transaction-payment/asset-conversion-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs index c2d9ed56c7a..04a71e2ff42 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, -- GitLab From b14018fe483925d87c9a98ceba73d8cc149b4b99 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 17 Oct 2023 12:22:02 +0200 Subject: [PATCH 313/633] ci: remove obsolete `allow_failure` annotations (#1886) These two jobs are now required by github branch protection settings. --- .gitlab/pipeline/check.yml | 1 - .gitlab/pipeline/test.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 4f92e6c15d2..559ce093cf6 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: diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 12ce2140b14..eb70b46af60 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -183,7 +183,6 @@ test-rustdoc: SKIP_WASM_BUILD: 1 script: - time cargo doc --workspace --all-features --no-deps - allow_failure: true cargo-check-all-benches: stage: test -- GitLab From a1171e6e81d5c103e36d40c0a50d2e37157c3dcc Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 17 Oct 2023 13:58:49 +0200 Subject: [PATCH 314/633] PVF worker: Maintain lists of used syscalls (#1663) Co-authored-by: Mira Ressel --- .cargo/config.toml | 5 + .cargo/musl-g++ | 7 + .cargo/musl-gcc | 13 + .gitlab/pipeline/test.yml | 20 + .../list-syscalls/execute-worker-syscalls | 74 +++ .../scripts/list-syscalls/list-syscalls.rb | 608 ++++++++++++++++++ .../list-syscalls/prepare-worker-syscalls | 76 +++ 7 files changed, 803 insertions(+) create mode 100755 .cargo/musl-g++ create mode 100755 .cargo/musl-gcc create mode 100644 polkadot/scripts/list-syscalls/execute-worker-syscalls create mode 100755 polkadot/scripts/list-syscalls/list-syscalls.rb create mode 100644 polkadot/scripts/list-syscalls/prepare-worker-syscalls diff --git a/.cargo/config.toml b/.cargo/config.toml index a5ff1d8dffa..bd46659f799 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -37,3 +37,8 @@ rustflags = [ "-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 00000000000..656adcc2ac1 --- /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 00000000000..5bc7852dbc6 --- /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/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index eb70b46af60..7d7007acd8a 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -503,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/polkadot/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls new file mode 100644 index 00000000000..05abe9ba736 --- /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 00000000000..9cef6f74b2e --- /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 00000000000..f1597f20675 --- /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) -- GitLab From 38c0604b46eb46e020d796d0d0f6dd3f553a0e8e Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 18 Oct 2023 03:47:48 +1300 Subject: [PATCH 315/633] increase MAX_ASSETS_FOR_BUY_EXECUTION (#1733) Partially addresses #1638 Still need a better solution to allow devs to have better control of this. --------- Co-authored-by: Keith Yeung Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- polkadot/xcm/xcm-builder/src/barriers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 0d04e0971bf..3b13cab2c1e 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. -- GitLab From 58b792728410b9995a64e4f67eb24714efefcb09 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 18 Oct 2023 00:19:34 +0200 Subject: [PATCH 316/633] Fix para-scheduler migration on Rococo (#1921) Closes https://github.com/paritytech/polkadot-sdk/issues/1916 Changes: - Trivially wrap the migration into a version migration to enforce idempotency. - Opinionated logging nits @liamaharon maybe we can add a check to the `try-runtime-cli` that migrations are idempotent? It should be possible to check that the storage root is identical after executing a second time (and that it does not panic like it did here :laughing:). --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Liam Aharon Co-authored-by: Francisco Aguirre --- .../parachains/src/scheduler/migration.rs | 36 ++++++++++--------- prdoc/pr_1921.prdoc | 19 ++++++++++ substrate/frame/support/src/migrations.rs | 5 +-- 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 prdoc/pr_1921.prdoc diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index accff7016ed..c1ce95b10e3 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/prdoc/pr_1921.prdoc b/prdoc/pr_1921.prdoc new file mode 100644 index 00000000000..5ed0137cd5f --- /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/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 8f490030c25..d6ae6c6291b 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) -- GitLab From 024fce70f4c6c2f87bbbb870e96a269258d9f3a4 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 18 Oct 2023 02:36:53 +0300 Subject: [PATCH 317/633] bridges: add missing crate descriptions (#1919) Adds descriptions needed for publishing bridges crates to crates.io. see https://forum.parity.io/t/crates-need-descriptions/2115 Signed-off-by: Adrian Catangiu --- bridges/bin/runtime-common/Cargo.toml | 1 + bridges/modules/grandpa/Cargo.toml | 1 + bridges/modules/parachains/Cargo.toml | 1 + bridges/primitives/test-utils/Cargo.toml | 1 + 4 files changed, 4 insertions(+) diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 5c3fefc69ce..d001e96efe8 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/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 05d6a8e5c26..45adf09af27 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/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 4eb09ed78d1..6e9ca870ce5 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/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 7081ce90f97..9836c1877f0 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" -- GitLab From e73729b15f7ecb656f5d51341b8e8b44bea18761 Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Wed, 18 Oct 2023 08:47:23 +0200 Subject: [PATCH 318/633] Publish `penpal-runtime` crate (#1904) Remove `publish = false` to publish the crate --- cumulus/parachains/runtimes/testing/penpal/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 6c4f8c3895a..a7fd4b30b75 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"] -- GitLab From 8b3905d2a5847ff6bfc552fb30009bdefe788170 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 18 Oct 2023 09:47:45 +0300 Subject: [PATCH 319/633] cumulus: add asset-hub-rococo runtime based on asset-hub-kusama and add asset-bridging support to it (#1215) This commit adds Rococo Asset Hub dedicated runtime so we can test new features here, before merging them in Kusama Asset Hub. Also adds one such feature: asset transfer over bridge (Rococo AssetHub <> Wococo AssetHub) - clone `asset-hub-kusama-runtime` -> `asset-hub-rococo-runtime` - make it use Rococo primitives, names, assets, constants, etc - add asset-transfer-over-bridge support to Rococo AssetHub <> Wococo AssetHub Fixes #1128 --------- Co-authored-by: Branislav Kontur Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Francisco Aguirre --- .gitlab/pipeline/short-benchmarks.yml | 5 + Cargo.lock | 120 +- Cargo.toml | 3 + .../xcm-bridge-hub-router/src/benchmarking.rs | 8 +- .../chain-asset-hub-rococo/Cargo.toml | 26 + .../chain-asset-hub-rococo/src/lib.rs | 52 + .../chain-asset-hub-wococo/Cargo.toml | 26 + .../chain-asset-hub-wococo/src/lib.rs | 52 + .../chain-bridge-hub-rococo/src/lib.rs | 3 + .../chain-bridge-hub-wococo/src/lib.rs | 3 + cumulus/pallets/xcmp-queue/Cargo.toml | 5 + cumulus/pallets/xcmp-queue/src/bridging.rs | 95 + cumulus/pallets/xcmp-queue/src/lib.rs | 20 + cumulus/parachains/common/Cargo.toml | 3 - cumulus/parachains/common/src/lib.rs | 1 + cumulus/parachains/common/src/wococo.rs | 17 + cumulus/parachains/common/src/xcm_config.rs | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 27 + .../assets/asset-hub-rococo/src/lib.rs | 77 +- .../assets/asset-hub-rococo/src/tests/mod.rs | 4 + .../src/tests/reserve_transfer.rs | 416 +++++ .../assets/asset-hub-rococo/src/tests/send.rs | 102 ++ .../src/tests/set_xcm_versions.rs | 83 + .../assets/asset-hub-rococo/src/tests/swap.rs | 364 ++++ .../asset-hub-rococo/src/tests/teleport.rs | 341 ++++ .../emulated/common/Cargo.toml | 2 + .../emulated/common/src/constants.rs | 120 +- .../emulated/common/src/lib.rs | 117 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 2 +- .../asset-hub-polkadot/src/xcm_config.rs | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 241 +++ .../runtimes/assets/asset-hub-rococo/build.rs | 26 + .../assets/asset-hub-rococo/src/lib.rs | 1566 +++++++++++++++++ .../src/weights/block_weights.rs | 53 + .../src/weights/cumulus_pallet_xcmp_queue.rs | 77 + .../src/weights/extrinsic_weights.rs | 53 + .../src/weights/frame_system.rs | 155 ++ .../asset-hub-rococo/src/weights/mod.rs | 45 + .../src/weights/pallet_asset_conversion.rs | 155 ++ .../src/weights/pallet_assets_foreign.rs | 534 ++++++ .../src/weights/pallet_assets_local.rs | 531 ++++++ .../src/weights/pallet_assets_pool.rs | 531 ++++++ .../src/weights/pallet_balances.rs | 153 ++ .../src/weights/pallet_collator_selection.rs | 225 +++ .../src/weights/pallet_multisig.rs | 165 ++ .../weights/pallet_nft_fractionalization.rs | 115 ++ .../src/weights/pallet_nfts.rs | 773 ++++++++ .../src/weights/pallet_proxy.rs | 226 +++ .../src/weights/pallet_session.rs | 81 + .../src/weights/pallet_timestamp.rs | 75 + .../src/weights/pallet_uniques.rs | 467 +++++ .../src/weights/pallet_utility.rs | 102 ++ .../src/weights/pallet_xcm.rs | 290 +++ .../pallet_xcm_bridge_hub_router_to_rococo.rs | 124 ++ .../pallet_xcm_bridge_hub_router_to_wococo.rs | 124 ++ .../src/weights/paritydb_weights.rs | 63 + .../src/weights/rocksdb_weights.rs | 63 + .../asset-hub-rococo/src/weights/xcm/mod.rs | 256 +++ .../xcm/pallet_xcm_benchmarks_fungible.rs | 190 ++ .../xcm/pallet_xcm_benchmarks_generic.rs | 339 ++++ .../assets/asset-hub-rococo/src/xcm_config.rs | 942 ++++++++++ .../assets/asset-hub-rococo/tests/tests.rs | 1157 ++++++++++++ .../asset-hub-westend/src/xcm_config.rs | 2 +- .../runtimes/assets/common/src/matching.rs | 39 + .../runtimes/assets/test-utils/Cargo.toml | 6 + .../runtimes/assets/test-utils/src/lib.rs | 1 + .../assets/test-utils/src/test_cases.rs | 7 +- .../test-utils/src/test_cases_over_bridge.rs | 621 +++++++ .../parachains/runtimes/bridge-hubs/README.md | 227 ++- .../bridge-hub-kusama/src/xcm_config.rs | 2 +- .../bridge-hub-polkadot/src/xcm_config.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 +- .../src/bridge_hub_rococo_config.rs | 63 +- .../src/bridge_hub_wococo_config.rs | 65 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 74 +- .../bridge-hub-rococo/src/xcm_config.rs | 42 +- .../bridge-hub-rococo/tests/tests.rs | 90 +- .../bridge-hubs/test-utils/Cargo.toml | 2 +- .../bridge-hubs/test-utils/src/test_cases.rs | 213 ++- .../collectives-polkadot/src/xcm_config.rs | 2 +- .../contracts-rococo/src/xcm_config.rs | 2 +- .../parachains/runtimes/test-utils/Cargo.toml | 2 +- .../parachains/runtimes/test-utils/src/lib.rs | 61 +- .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- cumulus/polkadot-parachain/Cargo.toml | 3 + .../chain-specs/asset-hub-rococo.json | 80 + .../chain-specs/asset-hub-wococo.json | 80 + .../src/chain_spec/asset_hubs.rs | 249 +++ cumulus/polkadot-parachain/src/command.rs | 59 + cumulus/scripts/bridges_rococo_wococo.sh | 734 ++++---- .../generate_hex_encoded_call/index.js | 17 + .../bridge_hub_rococo_local_network.toml | 66 +- .../bridge_hub_wococo_local_network.toml | 66 +- polkadot/runtime/rococo/src/xcm_config.rs | 2 +- polkadot/runtime/westend/src/xcm_config.rs | 2 +- 95 files changed, 14130 insertions(+), 754 deletions(-) create mode 100644 bridges/primitives/chain-asset-hub-rococo/Cargo.toml create mode 100644 bridges/primitives/chain-asset-hub-rococo/src/lib.rs create mode 100644 bridges/primitives/chain-asset-hub-wococo/Cargo.toml create mode 100644 bridges/primitives/chain-asset-hub-wococo/src/lib.rs create mode 100644 cumulus/pallets/xcmp-queue/src/bridging.rs create mode 100644 cumulus/parachains/common/src/wococo.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_collator_selection.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nft_fractionalization.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nfts.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_proxy.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_session.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_uniques.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs create mode 100644 cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs create mode 100644 cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json create mode 100644 cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 5bfe4b729e6..6d060077a7c 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -59,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/Cargo.lock b/Cargo.lock index f12e16276e7..40b11be0c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -796,13 +796,103 @@ dependencies = [ name = "asset-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ + "assert_matches", + "asset-hub-rococo-runtime", "frame-support", + "frame-system", "integration-tests-common", + "pallet-asset-conversion", + "pallet-assets", + "pallet-balances", + "pallet-xcm", + "parachains-common", "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-parachains", + "sp-runtime", "staging-xcm", "xcm-emulator", ] +[[package]] +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", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "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", + "pallet-xcm-bridge-hub-router", + "parachain-info", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "primitive-types", + "rococo-runtime-constants", + "scale-info", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-storage", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", +] + [[package]] name = "asset-hub-westend-integration-tests" version = "1.0.0" @@ -925,6 +1015,7 @@ dependencies = [ "pallet-collator-selection", "pallet-session", "pallet-xcm", + "pallet-xcm-bridge-hub-router", "parachain-info", "parachains-common", "parachains-runtimes-test-utils", @@ -936,6 +1027,7 @@ dependencies = [ "sp-runtime", "sp-std", "staging-xcm", + "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", ] @@ -1490,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" @@ -1908,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", @@ -1989,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", @@ -2027,6 +2140,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", + "sp-tracing", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -3577,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", @@ -6335,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", @@ -10992,7 +11108,6 @@ dependencies = [ "sp-std", "staging-xcm", "staging-xcm-builder", - "staging-xcm-executor", "substrate-wasm-builder", "westend-runtime-constants", ] @@ -12410,6 +12525,7 @@ 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", diff --git a/Cargo.toml b/Cargo.toml index 6ba153329d5..c98fe6d1a3a 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", @@ -69,6 +71,7 @@ members = [ "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", diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index 4bbe414f663..c4d1e3971e7 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/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..a888700a060 --- /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 00000000000..f1ea1e9c88c --- /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 00000000000..87273228385 --- /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 00000000000..5ce66054d64 --- /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-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index a50bda23ac8..6da5cd3818f 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -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 ce4600f5ff3..0c771736804 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -68,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/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 5aab57da91b..77d0551b511 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 00000000000..0fc3f1f39ea --- /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 7ee07a7beb0..b53eb7cc0e1 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 { diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index cb389b4b607..29528b169ae 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -35,7 +35,6 @@ polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default 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 } @@ -72,7 +71,6 @@ std = [ "sp-std/std", "westend-runtime-constants/std", "xcm-builder/std", - "xcm-executor/std", "xcm/std", ] @@ -87,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/lib.rs b/cumulus/parachains/common/src/lib.rs index cb2ac1a1e3e..89e74b2f9b7 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/wococo.rs b/cumulus/parachains/common/src/wococo.rs new file mode 100644 index 00000000000..5cd6121135a --- /dev/null +++ b/cumulus/parachains/common/src/wococo.rs @@ -0,0 +1,17 @@ +// 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. + +// 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 534253b4aae..91ad7d902bd 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -14,7 +14,6 @@ // 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}, @@ -22,6 +21,7 @@ use frame_support::{ }; use log; use sp_runtime::traits::Get; +use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// A `ChargeFeeInFungibles` implementation that converts the output of diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index f280afdda4a..52682c6eefd 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -3,15 +3,32 @@ name = "asset-hub-rococo-integration-tests" version = "1.0.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" description = "Asset Hub Rococo runtime integration tests with xcm-emulator" publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +assert_matches = "1.5.0" # Substrate +sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default-features = false} frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} +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" } 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-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} @@ -19,6 +36,16 @@ integration-tests-common = { path = "../../common", default-features = false} [features] runtime-benchmarks = [ + "asset-hub-rococo-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", + "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index f8a917afe1b..e0e9dcbdce7 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -13,14 +13,79 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use frame_support::assert_ok; +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_rococo::ED as ASSET_HUB_ROCOCO_ED, test_parachain_is_trusted_teleporter, - AssetHubRococo, AssetHubRococoPallet, AssetHubRococoSender, BridgeHubRococo, - BridgeHubRococoReceiver, + constants::{ + 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}, + 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::Rococo as RococoId}, }; -pub use xcm::prelude::*; -pub use xcm_emulator::{assert_expected_events, bx, Chain, Parachain, TestExt}; +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: Rococo::child_location_of(AssetHubRococo::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubRococoReceiver::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)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs index 516ec37cc10..b3841af0e6c 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs @@ -13,4 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod reserve_transfer; +mod send; +mod set_xcm_versions; +mod swap; mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs new file mode 100644 index 00000000000..0c136e2789f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -0,0 +1,416 @@ +// 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; + + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); + + assert_expected_events!( + 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 == Rococo::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { + 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) { + AssetHubRococo::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) +} + +fn system_para_to_para_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 630_092_000, + 6_196, + ))); + + assert_expected_events!( + 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 == AssetHubRococo::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubRococo, + 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 == AssetHubRococo::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 = ROCOCO_ED * 1000; + let test_args = TestContext { + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::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 = 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: 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::(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 = ROCOCO_ED * 1000; + let test_args = TestContext { + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::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 = 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: 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::(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 = 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: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::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 = 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: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::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 + AssetHubRococo::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubRococoSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + 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: 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); + // 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 + AssetHubRococo::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubRococoSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + 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: 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); + // 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-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs new file mode 100644 index 00000000000..b8ec370e3f8 --- /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-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs new file mode 100644 index 00000000000..8faba50fc88 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs @@ -0,0 +1,83 @@ +// 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 = + Rococo::child_location_of(AssetHubRococo::para_id()); + + // Relay Chain sets supported version for Asset Parachain + Rococo::execute_with(|| { + assert_ok!(::XcmPallet::force_xcm_version( + sudo_origin, + bx!(system_para_destination), + XCM_V3 + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Rococo, + 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 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(); + + // 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 + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); + + assert_expected_events!( + AssetHubRococo, + 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-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs new file mode 100644 index 00000000000..f9da0bf946e --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs @@ -0,0 +1,364 @@ +// 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::{instances::Instance2, BoundedVec}; +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_rococo_runtime::xcm_config::TokenLocation::get()); + let asset_one = Box::new(MultiLocation { + parents: 0, + interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + ASSET_ID.into(), + AssetHubRococoSender::get().into(), + 1000, + )); + assert!(::Assets::asset_exists(ASSET_ID)); + + assert_ok!(::Assets::mint( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + ASSET_ID.into(), + AssetHubRococoSender::get().into(), + 100_000_000_000_000, + )); + + assert_ok!(::Balances::force_set_balance( + ::RuntimeOrigin::root(), + AssetHubRococoSender::get().into(), + 100_000_000_000_000, + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + asset_native.clone(), + asset_one.clone(), + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + 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, + AssetHubRococoSender::get().into() + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, + ] + ); + + let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); + + assert_ok!( + ::AssetConversion::swap_exact_tokens_for_tokens( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + path, + 100, + 1, + AssetHubRococoSender::get().into(), + true + ) + ); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => { + amount_in: *amount_in == 100, + amount_out: *amount_out == 199, + }, + ] + ); + + 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, + AssetHubRococoSender::get().into(), + )); + }); +} + +#[test] +fn swap_locally_on_chain_using_foreign_assets() { + use frame_support::weights::WeightToFee; + + let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); + + let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation { + parents: 1, + interior: X3( + Parachain(PenpalRococoA::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(ASSET_ID.into()), + ), + }); + + let assets_para_destination: VersionedMultiLocation = + MultiLocation { parents: 1, interior: X1(Parachain(AssetHubRococo::para_id().into())) } + .into(); + + let penpal_location = + MultiLocation { parents: 1, interior: X1(Parachain(PenpalRococoA::para_id().into())) }; + + // 1. Create asset on penpal: + PenpalRococoA::execute_with(|| { + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(PenpalRococoASender::get()), + ASSET_ID.into(), + PenpalRococoASender::get().into(), + 1000, + )); + + assert!(::Assets::asset_exists(ASSET_ID)); + }); + + // 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_rococo = AssetHubRococo::sovereign_account_id_of(penpal_location); + + 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_rococo.clone().into(), 1000_000_000_000_000_000 * ROCOCO_ED), + ]); + + let sov_penpal_on_asset_hub_rococo_as_location: MultiLocation = MultiLocation { + parents: 0, + interior: X1(AccountId32Junction { + network: None, + id: sov_penpal_on_asset_hub_rococo.clone().into(), + }), + }; + + let call_foreign_assets_create = + ::RuntimeCall::ForeignAssets(pallet_assets::Call::< + ::Runtime, + Instance2, + >::create { + id: *foreign_asset1_at_asset_hub_rococo, + min_balance: 1000, + admin: sov_penpal_on_asset_hub_rococo.clone().into(), + }) + .encode() + .into(); + + 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 { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(buy_execution_fee_amount), + }; + + let xcm = VersionedXcm::from(Xcm(vec![ + WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, + BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, + Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create }, + RefundSurplus, + DepositAsset { + assets: All.into(), + beneficiary: sov_penpal_on_asset_hub_rococo_as_location, + }, + ])); + + // 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; + + assert_expected_events!( + PenpalRococoA, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Receive XCM message in Assets Parachain + AssetHubRococo::execute_with(|| { + assert!(::ForeignAssets::asset_exists( + *foreign_asset1_at_asset_hub_rococo + )); + + // 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; + // 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_rococo.clone().into() + ), + *foreign_asset1_at_asset_hub_rococo, + sov_penpal_on_asset_hub_rococo.clone().into(), + 3_000_000_000_000, + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + + // 4. Create pool: + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + asset_native.clone(), + foreign_asset1_at_asset_hub_rococo.clone(), + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + // 5. Add liquidity: + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed( + sov_penpal_on_asset_hub_rococo.clone() + ), + asset_native.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_rococo.clone().into() + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { + lp_token_minted: *lp_token_minted == 1414213562273, + }, + ] + ); + + // 6. Swap! + let path = BoundedVec::<_, _>::truncate_from(vec![ + asset_native.clone(), + foreign_asset1_at_asset_hub_rococo.clone(), + ]); + + assert_ok!( + ::AssetConversion::swap_exact_tokens_for_tokens( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + path, + 100000, + 1000, + AssetHubRococoSender::get().into(), + true + ) + ); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { + amount_in: *amount_in == 100000, + amount_out: *amount_out == 199399, + }, + ] + ); + + // 7. Remove liquidity + assert_ok!(::AssetConversion::remove_liquidity( + ::RuntimeOrigin::signed( + sov_penpal_on_asset_hub_rococo.clone() + ), + asset_native, + 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_rococo.clone().into(), + )); + }); +} + +#[test] +fn cannot_create_pool_from_pool_assets() { + 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"); + + 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()), + ASSET_ID.into(), + pool_owner_account_id.clone().into(), + 1000, + )); + assert!(::PoolAssets::asset_exists(ASSET_ID)); + + assert_ok!(::PoolAssets::mint( + ::RuntimeOrigin::signed(pool_owner_account_id), + ASSET_ID.into(), + AssetHubRococoSender::get().into(), + 3_000_000_000_000, + )); + + assert_matches::assert_matches!( + ::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + asset_native.clone(), + Box::new(asset_one), + ), + Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 36b65c6d010..21afed17918 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -15,6 +15,347 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); + + assert_expected_events!( + Rococo, + 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; + + Rococo::assert_ump_queue_processed( + true, + Some(AssetHubRococo::para_id()), + Some(Weight::from_parts(307_225_000, 7_186)), + ); + + assert_expected_events!( + Rococo, + 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) { + Rococo::assert_ump_queue_processed( + false, + Some(AssetHubRococo::para_id()), + Some(Weight::from_parts(148_433_000, 3_593)), + ); +} + +fn para_origin_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 534_872_000, + 7_133, + ))); + + AssetHubRococo::assert_parachain_system_ump_sent(); + + assert_expected_events!( + AssetHubRococo, + 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; + + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); + + assert_expected_events!( + AssetHubRococo, + 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, + ) +} + +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 = ROCOCO_ED * 1000; + let test_args = TestContext { + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::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_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_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_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: 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_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 = ROCOCO_ED * 1000; + let test_args = TestContext { + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::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); +} + +/// 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; diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index bc661ce3e20..1691d21e173 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -44,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" } @@ -61,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", diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 33a9ac38c8c..592269e9aa3 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -27,8 +27,12 @@ use sp_runtime::{ // Cumulus use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; +use polkadot_parachain_primitives::primitives::{HeadData, ValidationCode}; use polkadot_primitives::{AssignmentId, ValidatorId}; -use polkadot_runtime_parachains::configuration::HostConfiguration; +use polkadot_runtime_parachains::{ + configuration::HostConfiguration, + paras::{ParaGenesisArgs, ParaKind}, +}; use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; use xcm; @@ -331,6 +335,41 @@ pub mod rococo { key: Some(get_account_id_from_seed::("Alice")), }, configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, + paras: rococo_runtime::ParasConfig { + paras: vec![ + ( + asset_hub_rococo::PARA_ID.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + asset_hub_rococo_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() + }, registrar: rococo_runtime::RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, ..Default::default() @@ -399,32 +438,87 @@ pub mod asset_hub_westend { } } -// Asset Hub Kusama pub mod asset_hub_rococo { use super::*; pub const PARA_ID: u32 = 1000; 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 * 4096)) + .collect(), + }, + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + genesis_config.build_storage().unwrap() + } +} + +pub mod asset_hub_wococo { + use super::*; + pub const PARA_ID: u32 = 1000; + pub const ED: Balance = parachains_common::wococo::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + 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_rococo_runtime::BalancesConfig { balances: accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 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() @@ -433,19 +527,19 @@ pub mod asset_hub_rococo { 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() }, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index e9a30aadedd..8a8081c9fac 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -20,7 +20,8 @@ pub mod xcm_helpers; use constants::{ accounts::{ALICE, BOB}, - asset_hub_rococo, asset_hub_westend, bridge_hub_rococo, penpal, rococo, westend, + asset_hub_rococo, asset_hub_westend, asset_hub_wococo, bridge_hub_rococo, penpal, rococo, + westend, }; use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; pub use paste; @@ -72,6 +73,7 @@ decl_test_relay_chains! { XcmPallet: rococo_runtime::XcmPallet, Sudo: rococo_runtime::Sudo, Balances: rococo_runtime::Balances, + Hrmp: rococo_runtime::Hrmp, } }, #[api_version(8)] @@ -150,23 +152,60 @@ decl_test_parachains! { Balances: bridge_hub_rococo_runtime::Balances, } }, - // AssetHubRococo (aka Rockmine/Rockmine2) mirrors AssetHubKusama + // AssetHubRococo pub struct AssetHubRococo { genesis = asset_hub_rococo::genesis(), on_init = { - asset_hub_polkadot_runtime::AuraExt::on_initialize(1); + asset_hub_rococo_runtime::AuraExt::on_initialize(1); }, - runtime = asset_hub_kusama_runtime, + runtime = asset_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: 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: asset_hub_kusama_runtime::PolkadotXcm, - Assets: asset_hub_kusama_runtime::Assets, - Balances: asset_hub_kusama_runtime::Balances, + 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 PenpalRococoA { + 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, + } + }, + pub struct PenpalRococoB { + 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, } }, // Wococo Parachains @@ -174,6 +213,7 @@ decl_test_parachains! { 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 = { @@ -187,38 +227,25 @@ decl_test_parachains! { } }, pub struct AssetHubWococo { - genesis = asset_hub_westend::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 PenpalRococoA { - genesis = penpal::genesis(penpal::PARA_ID_A), + genesis = asset_hub_wococo::genesis(), on_init = { - penpal_runtime::AuraExt::on_initialize(1); + asset_hub_rococo_runtime::AuraExt::on_initialize(1); + // TODO: manage to set_wococo_flavor with `set_storage` }, - 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, } } } @@ -238,6 +265,7 @@ decl_test_networks! { AssetHubRococo, BridgeHubRococo, PenpalRococoA, + PenpalRococoB, ], bridge = RococoWococoMockBridge }, @@ -272,6 +300,7 @@ 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 @@ -284,6 +313,11 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); +// 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); @@ -291,6 +325,10 @@ impl_assert_events_helpers_for_parachain!(PenpalWestendA); 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 Westend { sender: ALICE, receiver: BOB }, @@ -305,5 +343,6 @@ decl_test_sender_receiver_accounts_parameter_types! { BridgeHubWococo { sender: ALICE, receiver: BOB }, // Penpals 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/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 2935d8b07a4..57e745d2e5e 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 @@ -449,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. 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 54455837585..8a4b24407b5 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 @@ -367,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 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 00000000000..af0ce6d5814 --- /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 00000000000..60f8a125129 --- /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 00000000000..3328ff0edaf --- /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 00000000000..e7fdb2aae2a --- /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 00000000000..26ce4c8c9c5 --- /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 00000000000..1a4adb968bb --- /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 00000000000..4f993155c19 --- /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 00000000000..59f97d2c8e5 --- /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 00000000000..4514fbfa876 --- /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 00000000000..5148edb0ee9 --- /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 00000000000..4ee235830ae --- /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 00000000000..df7ad2c6338 --- /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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs new file mode 100644 index 00000000000..d373d0f8e65 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs @@ -0,0 +1,153 @@ +// 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_balances` +//! +//! 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_balances +// --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_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_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`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // 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`) + fn force_set_balance_creating() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3593` + // 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`) + fn force_set_balance_killing() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3593` + // 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`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `6196` + // 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`) + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // 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`) + fn force_unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3593` + // 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`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 17_259_000 picoseconds. + Weight::from_parts(17_478_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // 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 00000000000..d98abbbc2d3 --- /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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs new file mode 100644 index 00000000000..cf9c523f657 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs @@ -0,0 +1,165 @@ +// 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_multisig` +//! +//! 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_multisig +// --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_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_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(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`) + /// 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: `262 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 44_768_000 picoseconds. + Weight::from_parts(33_662_218, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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`) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 29_745_000 picoseconds. + Weight::from_parts(20_559_891, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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`) + /// 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: `385 + s * (33 ±0)` + // Estimated: `6811` + // Minimum execution time: 51_506_000 picoseconds. + Weight::from_parts(36_510_777, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_create(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 31_072_000 picoseconds. + Weight::from_parts(32_408_621, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_approve(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 18_301_000 picoseconds. + Weight::from_parts(18_223_547, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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`) + /// The range of component `s` is `[2, 100]`. + fn cancel_as_multi(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 32_107_000 picoseconds. + Weight::from_parts(33_674_827, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // 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 00000000000..97cec5d82ec --- /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 00000000000..277cfd1747b --- /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 00000000000..0e680011e79 --- /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 00000000000..6cfa66a4bea --- /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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000000..38e1fbd822b --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs @@ -0,0 +1,75 @@ +// 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_timestamp` +//! +//! 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_timestamp +// --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_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `86` + // Estimated: `1493` + // 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: `57` + // Estimated: `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 00000000000..c4e220b7fac --- /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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs new file mode 100644 index 00000000000..a82115b9d09 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs @@ -0,0 +1,102 @@ +// 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_utility` +//! +//! 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_utility +// --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_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: 7_103_000 picoseconds. + Weight::from_parts(7_226_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // 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: 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]`. + fn batch_all(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_070_000 picoseconds. + Weight::from_parts(1_321_270, 0) + .saturating_add(Weight::from_parts(0, 0)) + // 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_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]`. + fn force_batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_852_000 picoseconds. + Weight::from_parts(7_007_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // 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 00000000000..909d7f28907 --- /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 00000000000..3ce9e4e7d31 --- /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 00000000000..1ee0e933715 --- /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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs new file mode 100644 index 00000000000..25679703831 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 50_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs new file mode 100644 index 00000000000..3dd817aa6f1 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 100_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs new file mode 100644 index 00000000000..22c2f2450b2 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs @@ -0,0 +1,256 @@ +// 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 . + +mod pallet_xcm_benchmarks_fungible; +mod pallet_xcm_benchmarks_generic; + +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}; + +trait WeighMultiAssets { + fn weigh_multi_assets(&self, weight: Weight) -> Weight; +} + +const MAX_ASSETS: u64 = 100; + +impl WeighMultiAssets for MultiAssetFilter { + fn weigh_multi_assets(&self, weight: Weight) -> Weight { + match self { + 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, weight: Weight) -> Weight { + weight.saturating_mul(self.inner().iter().count() as u64) + } +} + +pub struct AssetHubRococoXcmWeight(core::marker::PhantomData); +impl XcmWeightInfo for AssetHubRococoXcmWeight { + 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 receive_teleported_asset(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::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(XcmFungibleWeight::::transfer_asset()) + } + fn transfer_reserve_asset( + assets: &MultiAssets, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) + } + fn transact( + _origin_type: &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 { + // 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(XcmFungibleWeight::::deposit_reserve_asset()) + } + fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { + Weight::MAX + } + fn initiate_reserve_withdraw( + assets: &MultiAssetFilter, + _reserve: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) + } + fn initiate_teleport( + assets: &MultiAssetFilter, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::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 { + XcmGeneric::::universal_origin() + } + fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { + Weight::MAX + } + fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { + 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() + } +} 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 00000000000..9d95048c0ac --- /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 00000000000..2c51afde7b3 --- /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 00000000000..6db4a787405 --- /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 00000000000..7f48d576288 --- /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/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 36534a1d11a..99f8d5ae589 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 @@ -454,7 +454,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 treasury pallet get diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index cb071a12f23..91497281252 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -19,6 +19,7 @@ use xcm::{ latest::prelude::{MultiAsset, MultiLocation}, prelude::*, }; +use xcm_builder::ensure_is_remote; frame_support::parameter_types! { pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here); @@ -56,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 0a27535ed22..30d3cf90b47 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 7177726e070..3c62faf3d5e 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 f1e4f1e5ef5..62faa384781 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, 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 00000000000..a967384fb6d --- /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 487c601ef84..9acdfd6d053 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/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index ddc5fc0c4a4..563115c8938 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 @@ -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. 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 84672a6c394..6e9d6d58619 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 @@ -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 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 fec00fe0794..ab56430bc94 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -65,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 } @@ -73,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 } @@ -98,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", 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 f59c9e238f5..73eb27e9216 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 @@ -33,6 +33,7 @@ use bridge_runtime_common::{ 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 { @@ -164,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() { @@ -215,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 a0b16bace51..fcd9a6229ff 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 @@ -33,6 +33,7 @@ use bridge_runtime_common::{ 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 { @@ -164,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() { @@ -215,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 c4e510ee409..3a8507ccf93 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}; @@ -92,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; @@ -473,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; @@ -486,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; @@ -528,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 @@ -562,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 @@ -617,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, @@ -982,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), } ]; @@ -1004,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; @@ -1020,7 +1050,7 @@ impl_runtime_apis! { fn get_multi_asset() -> MultiAsset { MultiAsset { - id: Concrete(RelayLocation::get()), + id: Concrete(TokenLocation::get()), fun: Fungible(UNITS), } } @@ -1042,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)) } @@ -1062,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> { 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 1639a507091..b35011b095f 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, @@ -36,12 +36,11 @@ 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,16 +218,13 @@ 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 type TrustedTeleporters = ConcreteAssetFromSystem; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { @@ -246,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 e5fe67f2a8e..dcde07dc287 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 d56c32d8afa..2ad79bb2488 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 aa7fa16a979..d4e5aac3436 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/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index a170cd6ba51..79d4c53c2ee 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -225,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. 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 aafb61132b9..ff8f46b9d11 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -130,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. diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 378d9ea4c42..1ecbb212a0e 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 3241ac179d2..3215242464a 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!") } } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index f2ffc451b10..710dfd79877 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/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 778b056b89d..3c2069c81ef 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -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" } @@ -108,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", @@ -129,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 00000000000..064a2dfc0db --- /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 00000000000..b364139b87e --- /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 c1edeb98cd0..8c8091aaec3 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 c47555a3216..52aa1c8bd57 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)?, ), @@ -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::( @@ -850,6 +902,13 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), + 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, diff --git a/cumulus/scripts/bridges_rococo_wococo.sh b/cumulus/scripts/bridges_rococo_wococo.sh index 1117ed68109..4bfe9b32a83 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/generate_hex_encoded_call/index.js b/cumulus/scripts/generate_hex_encoded_call/index.js index 25e094df905..09f0e6aaf61 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/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml index 80b398ac724..d83cf13607d 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 9727b4a087f..76b368cfa28 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/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index b84d2335a69..a766e2179ea 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -151,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>, diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 66a2e2230cc..f025e5f1f3e 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -137,7 +137,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, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, -- GitLab From 6c39bb4a61070befdfabdd1fe767c165e7abf655 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 18 Oct 2023 10:36:26 +0300 Subject: [PATCH 320/633] Start BEEFY client by default for Polkadot nodes (#1913) Fellowship companion: https://github.com/polkadot-fellows/runtimes/pull/65 This starts the BEEFY client by default for Polkadot nodes. Governance/sudo call is later required to enable/start consensus. Part of https://github.com/paritytech/parity-bridges-common/issues/2420 --- polkadot/cli/src/command.rs | 5 ++--- polkadot/node/service/src/lib.rs | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 11c9014d1d6..3da6e54b812 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -195,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, diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 5991744dc3a..ced89c3843a 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -749,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(); -- GitLab From e34aa4b78ed2bcd2d80858e54ae86609feab3286 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:39:57 +0200 Subject: [PATCH 321/633] Bump actions/checkout from 4.1.0 to 4.1.1 (#1925) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1. --- .github/workflows/check-licenses.yml | 2 +- .github/workflows/check-links.yml | 2 +- .github/workflows/check-markdown.yml | 2 +- .github/workflows/check-prdoc.yml | 2 +- .github/workflows/fmt-check.yml | 2 +- .github/workflows/release-50_publish-docker.yml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index a5c4f2577c0..fab788c8057 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 index ec606f1b148..3ed6ba84b82 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -24,7 +24,7 @@ jobs: # This should restore from the most recent one: restore-keys: cache-lychee- - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 (22. Sep 2023) + - 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) diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index be676d3c1e8..991fdd171ce 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 23ae2d1aca9..3bb9a4fcabf 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@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.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 db93a3d53a7..55e67f2799b 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 71677fc36d4..414cc8b07cd 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 @@ -118,7 +118,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Get artifacts from cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -241,7 +241,7 @@ jobs: environment: master steps: - name: Checkout sources - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 -- GitLab From 9c333a5c2f9fd6ecbfc919304af8038861163d18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:40:21 +0200 Subject: [PATCH 322/633] Bump paritytech/review-bot from 2.0.1 to 2.1.0 (#1924) Bumps [paritytech/review-bot](https://github.com/paritytech/review-bot) from 2.0.1 to 2.1.0. --- .github/workflows/review-bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index b9799935abe..dd0783c4e21 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -24,7 +24,7 @@ jobs: app_id: ${{ secrets.REVIEW_APP_ID }} private_key: ${{ secrets.REVIEW_APP_KEY }} - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v2.0.1 + uses: paritytech/review-bot@v2.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} team-token: ${{ steps.team_token.outputs.token }} -- GitLab From b665409462587934b542dae16818c22cfb91b8c9 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 18 Oct 2023 10:14:33 +0200 Subject: [PATCH 323/633] Switch to the release env (#1910) Follow up of #1892, this PR now switches the env for release related workflows from `master` to `release`. --- .github/workflows/check-licenses.yml | 2 +- .github/workflows/release-50_publish-docker.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index fab788c8057..e8def665bd0 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -20,7 +20,7 @@ jobs: node-version: "18.x" registry-url: "https://npm.pkg.github.com" scope: "@paritytech" - + - name: Check the licenses in Polkadot run: | shopt -s globstar diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 414cc8b07cd..891f43e605c 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -114,7 +114,7 @@ jobs: if: ${{ inputs.binary == 'polkadot-parachain' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest needs: fetch-artifacts - environment: master + environment: release steps: - name: Checkout sources @@ -238,7 +238,7 @@ jobs: if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} runs-on: ubuntu-latest needs: fetch-latest-debian-package-version - environment: master + environment: release steps: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 -- GitLab From d3ea69b7acadcd02da3480616544effda8901771 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:56:03 +0200 Subject: [PATCH 324/633] Add Runtime Missing Crate Descriptions (#1909) Adds descriptions needed for publishing to crates.io. --- .../parachains/runtimes/contracts/contracts-rococo/Cargo.toml | 1 + cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml | 1 + cumulus/parachains/runtimes/starters/seedling/Cargo.toml | 1 + cumulus/parachains/runtimes/starters/shell/Cargo.toml | 1 + polkadot/core-primitives/Cargo.toml | 1 + polkadot/runtime/common/Cargo.toml | 1 + polkadot/runtime/rococo/Cargo.toml | 1 + polkadot/runtime/rococo/constants/Cargo.toml | 1 + polkadot/runtime/westend/Cargo.toml | 1 + polkadot/runtime/westend/constants/Cargo.toml | 1 + polkadot/xcm/pallet-xcm/Cargo.toml | 4 ++-- 11 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 414c7ad9d94..d59fe2fd29e 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "contracts-rococo-runtime" version = "0.2.0" +description = "Parachain testnet runtime for FRAME Contracts pallet." authors.workspace = true edition.workspace = true diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index ad13bf05a3e..b419f099815 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "glutton-runtime" version = "1.0.0" +description = "Glutton parachain runtime." authors.workspace = true edition.workspace = true diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index d9711b57b37..e3375a21715 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "seedling-runtime" version = "0.1.0" +description = "Seedling parachain runtime. A starter runtime for solochain to parachain migration." authors.workspace = true edition.workspace = true diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 675abc07b77..5a1e14e8b11 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "shell-runtime" version = "0.1.0" +description = "A minimal runtime to test Relay Chain consensus." authors.workspace = true edition.workspace = true diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 29c6be44454..1ee39da30a4 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-core-primitives" version = "1.0.0" +description = "Core Polkadot types used by Relay Chains and parachains." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 2d1aad6a575..89312acc913 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-runtime-common" version = "1.0.0" +description = "Pallets and constants used in Relay Chain networks." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 0b8a8624bb6..ae68ab7e2d9 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -2,6 +2,7 @@ name = "rococo-runtime" build = "build.rs" version = "1.0.0" +description = "Rococo testnet Relay Chain runtime." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index b1eb3f48f65..a0ef1edf08d 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "rococo-runtime-constants" version = "1.0.0" +description = "Constants used throughout the Rococo network." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 58a6cc21eec..6fc1f066307 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -2,6 +2,7 @@ name = "westend-runtime" build = "build.rs" version = "1.0.0" +description = "Westend testnet Relay Chain runtime." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index 779b2cb3110..ea9ff3499f9 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "westend-runtime-constants" version = "1.0.0" +description = "Constants used throughout the Westend network." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 4946a8d11ce..7e69d5edd2b 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "pallet-xcm" +version = "1.0.0" +description = "A pallet for handling XCM programs." authors.workspace = true edition.workspace = true license.workspace = true -version = "1.0.0" - [dependencies] bounded-collections = { version = "0.1.8", default-features = false } -- GitLab From 3aaf62add46d09329372f4447a24bd7025dfc858 Mon Sep 17 00:00:00 2001 From: Alex Bean Date: Wed, 18 Oct 2023 12:33:29 +0200 Subject: [PATCH 325/633] Trading trait and deal with metadata in Mutate trait for nonfungibles_v2 (#1561) I have added some Traits that are missing and are useful for dealing with non-fungible tokens on other pallets and their implementations for NFTs pallet. - In the Mutate trait, added methods for dealing with the metadata: `set_metadata`, `set_collection_metadata`, `clear_metadata` and `clear_collection_metadata`. The motivation of adding this methods coming from a StackExchange question asking for it: [Setting metadata of an item of the Nfts pallet in a custom pallet](https://substrate.stackexchange.com/questions/9974/setting-metadata-of-an-item-of-the-nfts-pallet-in-a-custom-pallet) - A Trait for trading non-fungible items. The methods in that Trait are `buy_item`, `set_price` and `item_price` An example of where this Trait can be useful is a pallet that deals with [NFT Royalties](https://forum.polkadot.network/t/nfts-royalty-pallet/3766) and needs to perform this actions. --------- Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --- substrate/frame/nfts/src/impl_nonfungibles.rs | 67 ++++++++++++++++++ substrate/frame/support/src/traits.rs | 3 +- .../src/traits/tokens/nonfungible_v2.rs | 16 ++++- .../src/traits/tokens/nonfungibles_v2.rs | 70 ++++++++++++++++++- 4 files changed, 153 insertions(+), 3 deletions(-) diff --git a/substrate/frame/nfts/src/impl_nonfungibles.rs b/substrate/frame/nfts/src/impl_nonfungibles.rs index 4e2593b4057..4a6b70eb997 100644 --- a/substrate/frame/nfts/src/impl_nonfungibles.rs +++ b/substrate/frame/nfts/src/impl_nonfungibles.rs @@ -320,6 +320,33 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig }) } + fn set_item_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + item: &Self::ItemId, + data: &[u8], + ) -> DispatchResult { + Self::do_set_item_metadata( + who.cloned(), + *collection, + *item, + Self::construct_metadata(data.to_vec())?, + None, + ) + } + + fn set_collection_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + data: &[u8], + ) -> DispatchResult { + Self::do_set_collection_metadata( + who.cloned(), + *collection, + Self::construct_metadata(data.to_vec())?, + ) + } + fn clear_attribute( collection: &Self::CollectionId, item: &Self::ItemId, @@ -362,6 +389,21 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig >::clear_collection_attribute(collection, k) }) } + + fn clear_item_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + item: &Self::ItemId, + ) -> DispatchResult { + Self::do_clear_item_metadata(who.cloned(), *collection, *item) + } + + fn clear_collection_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + ) -> DispatchResult { + Self::do_clear_collection_metadata(who.cloned(), *collection) + } } impl, I: 'static> Transfer for Pallet { @@ -398,6 +440,31 @@ impl, I: 'static> Transfer for Pallet { } } +impl, I: 'static> Trading> for Pallet { + fn buy_item( + collection: &Self::CollectionId, + item: &Self::ItemId, + buyer: &T::AccountId, + bid_price: &ItemPrice, + ) -> DispatchResult { + Self::do_buy_item(*collection, *item, buyer.clone(), *bid_price) + } + + fn set_price( + collection: &Self::CollectionId, + item: &Self::ItemId, + sender: &T::AccountId, + price: Option>, + whitelisted_buyer: Option, + ) -> DispatchResult { + Self::do_set_price(*collection, *item, sender.clone(), price, whitelisted_buyer) + } + + fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option> { + ItemPriceOf::::get(collection, item).map(|a| a.0) + } +} + impl, I: 'static> InspectEnumerable for Pallet { type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; type ItemsIterator = KeyPrefixIterator<>::ItemId>; diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 69885b2873e..1532d67facd 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -27,7 +27,8 @@ pub use tokens::{ }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, - nonfungible, nonfungibles, BalanceStatus, ExistenceRequirement, Locker, WithdrawReasons, + nonfungible, nonfungible_v2, nonfungibles, nonfungibles_v2, BalanceStatus, + ExistenceRequirement, Locker, WithdrawReasons, }; mod members; diff --git a/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs b/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs index c4463e0070f..788a4d25e81 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -119,7 +119,7 @@ pub trait InspectEnumerable: Inspect { } /// Trait for providing an interface for NFT-like items which may be minted, burned and/or have -/// attributes set on them. +/// attributes and metadata set on them. pub trait Mutate: Inspect { /// Mint some `item` to be owned by `who`. /// @@ -158,6 +158,13 @@ pub trait Mutate: Inspect { key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v))) } + /// Set the metadata `data` of an `item`. + /// + /// By default, this is not a supported operation. + fn set_metadata(_who: &AccountId, _item: &Self::ItemId, _data: &[u8]) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + /// Clear attribute of `item`'s `key`. /// /// By default, this is not a supported operation. @@ -171,6 +178,13 @@ pub trait Mutate: Inspect { fn clear_typed_attribute(item: &Self::ItemId, key: &K) -> DispatchResult { key.using_encoded(|k| Self::clear_attribute(item, k)) } + + /// Clear the metadata of an `item`. + /// + /// By default, this is not a supported operation. + fn clear_metadata(_who: &AccountId, _item: &Self::ItemId) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } } /// Trait for transferring and controlling the transfer of non-fungible sets of items. diff --git a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs index ec064bdebf6..868afbdf7ee 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -233,7 +233,7 @@ pub trait Destroy: Inspect { } /// Trait for providing an interface for multiple collections of NFT-like items which may be -/// minted, burned and/or have attributes set on them. +/// minted, burned and/or have attributes and metadata set on them. pub trait Mutate: Inspect { /// Mint some `item` of `collection` to be owned by `who`. /// @@ -307,6 +307,29 @@ pub trait Mutate: Inspect { }) } + /// Set the metadata `data` of an `item` of `collection`. + /// + /// By default, this is not a supported operation. + fn set_item_metadata( + _who: Option<&AccountId>, + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _data: &[u8], + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Set the metadata `data` of a `collection`. + /// + /// By default, this is not a supported operation. + fn set_collection_metadata( + _who: Option<&AccountId>, + _collection: &Self::CollectionId, + _data: &[u8], + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + /// Clear attribute of `item` of `collection`'s `key`. /// /// By default, this is not a supported operation. @@ -345,6 +368,27 @@ pub trait Mutate: Inspect { ) -> DispatchResult { key.using_encoded(|k| Self::clear_collection_attribute(collection, k)) } + + /// Clear the metadata of an `item` of `collection`. + /// + /// By default, this is not a supported operation. + fn clear_item_metadata( + _who: Option<&AccountId>, + _collection: &Self::CollectionId, + _item: &Self::ItemId, + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Clear the metadata of a `collection`. + /// + /// By default, this is not a supported operation. + fn clear_collection_metadata( + _who: Option<&AccountId>, + _collection: &Self::CollectionId, + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } } /// Trait for transferring non-fungible sets of items. @@ -370,3 +414,27 @@ pub trait Transfer: Inspect { Err(TokenError::Unsupported.into()) } } + +/// Trait for trading non-fungible items. +pub trait Trading: Inspect { + /// Allows `buyer` to buy an `item` of `collection` if it's up for sale with a `bid_price` to + /// pay. + fn buy_item( + collection: &Self::CollectionId, + item: &Self::ItemId, + buyer: &AccountId, + bid_price: &ItemPrice, + ) -> DispatchResult; + + /// Sets the item price for `item` to make it available for sale. + fn set_price( + collection: &Self::CollectionId, + item: &Self::ItemId, + sender: &AccountId, + price: Option, + whitelisted_buyer: Option, + ) -> DispatchResult; + + /// Returns the item price of `item` or `None` if the item is not for sale. + fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option; +} -- GitLab From 1cf7d3aafa0e7edaa20d34581e0f1656895cb9c2 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Wed, 18 Oct 2023 14:04:39 +0200 Subject: [PATCH 326/633] upgraded review bot to v2.1.0 (#1908) Upgraded to version 2.1.0 which has paritytech/review-bot#94, a change in the logic of the action to overcome some problems with permissions coming from PRs from forks For this, we needed to divide the actions into two files: - A first action that triggers on PRs and reviews and uploads the PR number. - A second action which is triggered under the completion of the first one and runs as the action normally runs (but won't have any problems regarding permissions because it is triggered from the master branch) --- .github/workflows/review-bot.yml | 20 ++++++++++-------- .github/workflows/review-trigger.yml | 31 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/review-trigger.yml diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index dd0783c4e21..178193da338 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -1,14 +1,10 @@ -name: Review PR +name: Review Bot on: - pull_request_target: + workflow_run: + workflows: + - Review-Trigger types: - - opened - - reopened - - synchronize - - review_requested - - review_request_removed - - ready_for_review - pull_request_review: + - completed permissions: contents: read @@ -17,6 +13,11 @@ jobs: review-approvals: runs-on: ubuntu-latest steps: + - name: Extract content of artifact + id: number + uses: Bullrich/extract-text-from-artifact@v1.0.0 + with: + artifact-name: pr_number - name: Generate token id: team_token uses: tibdex/github-app-token@v1 @@ -29,3 +30,4 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} team-token: ${{ steps.team_token.outputs.token }} checks-token: ${{ steps.team_token.outputs.token }} + pr-number: ${{ steps.number.outputs.content }} diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml new file mode 100644 index 00000000000..40e2918df2b --- /dev/null +++ b/.github/workflows/review-trigger.yml @@ -0,0 +1,31 @@ +name: Review-Trigger + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - review_requested + - review_request_removed + - ready_for_review + pull_request_review: + +jobs: + trigger-review-bot: + runs-on: ubuntu-latest + name: trigger review bot + steps: + - name: Get PR number + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + echo "Saving PR number: $PR_NUMBER" + mkdir -p ./pr + echo $PR_NUMBER > ./pr/pr_number + - uses: actions/upload-artifact@v3 + name: Save PR number + with: + name: pr_number + path: pr/ + retention-days: 5 -- GitLab From 3dece311beda44669b90e5dec3c049ed18cef2a7 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 18 Oct 2023 23:22:25 +0800 Subject: [PATCH 327/633] Introduce XcmFeesToAccount fee manager (#1234) Combination of paritytech/polkadot#7005, its addon PR paritytech/polkadot#7585 and its companion paritytech/cumulus#2433. This PR introduces a new XcmFeesToAccount struct which implements the `FeeManager` trait, and assigns this struct as the `FeeManager` in the XCM config for all runtimes. The struct simply deposits all fees handled by the XCM executor to a specified account. In all runtimes, the specified account is configured as the treasury account. XCM __delivery__ fees are now being introduced (unless the root origin is sending a message to a system parachain on behalf of the originating chain). # Note for reviewers Most file changes are tests that had to be modified to account for the new fees. Main changes are in: - cumulus/pallets/xcmp-queue/src/lib.rs <- To make it track the delivery fees exponential factor - polkadot/xcm/xcm-builder/src/fee_handling.rs <- Added. Has the FeeManager implementation - All runtime xcm_config files <- To add the FeeManager to the XCM configuration # Important note After this change, instructions that create and send a new XCM (Query*, Report*, ExportMessage, InitiateReserveWithdraw, InitiateTeleport, DepositReserveAsset, TransferReserveAsset, LockAsset and RequestUnlock) will require the corresponding origin account in the origin register to pay for transport delivery fees, and the onward message will fail to be sent if the origin account does not have the required amount. This delivery fee is on top of what we already collect as tx fees in pallet-xcm and XCM BuyExecution fees! Wallet UIs that want to expose the new delivery fee can do so using the formula: ``` delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee) ``` where the delivery fee factor can be obtained from the corresponding pallet based on which transport you are using (UMP, HRMP or bridges), the base fee is a constant, the encoded message length from the message itself and the per byte fee is the same as the configured per byte fee for txs (i.e. `TransactionByteFee`). --------- Co-authored-by: Branislav Kontur Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Giles Cope Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre Co-authored-by: Liam Aharon Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 22 ++ cumulus/pallets/parachain-system/Cargo.toml | 4 + cumulus/pallets/parachain-system/src/lib.rs | 129 ++++++++++- cumulus/pallets/parachain-system/src/tests.rs | 50 +++++ cumulus/pallets/xcmp-queue/Cargo.toml | 12 +- cumulus/pallets/xcmp-queue/src/lib.rs | 201 ++++++++++++++---- cumulus/pallets/xcmp-queue/src/mock.rs | 22 +- cumulus/pallets/xcmp-queue/src/tests.rs | 82 ++++++- cumulus/parachain-template/runtime/src/lib.rs | 4 +- cumulus/parachains/common/Cargo.toml | 2 + cumulus/parachains/common/src/lib.rs | 8 +- cumulus/parachains/common/src/xcm_config.rs | 24 ++- .../assets/asset-hub-rococo/Cargo.toml | 5 + .../assets/asset-hub-rococo/src/lib.rs | 1 + .../src/tests/reserve_transfer.rs | 34 ++- .../asset-hub-rococo/src/tests/teleport.rs | 57 ++++- .../assets/asset-hub-westend/Cargo.toml | 4 + .../assets/asset-hub-westend/src/lib.rs | 1 + .../src/tests/reserve_transfer.rs | 42 +++- .../asset-hub-westend/src/tests/teleport.rs | 50 ++++- .../bridges/bridge-hub-rococo/Cargo.toml | 3 + .../bridge-hub-rococo/src/tests/teleport.rs | 4 +- .../emulated/common/src/macros.rs | 22 +- .../emulated/common/src/xcm_helpers.rs | 9 +- .../assets/asset-hub-kusama/src/lib.rs | 19 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 17 +- .../assets/asset-hub-polkadot/src/lib.rs | 19 +- .../asset-hub-polkadot/src/xcm_config.rs | 15 +- .../assets/asset-hub-rococo/Cargo.toml | 4 + .../assets/asset-hub-rococo/src/lib.rs | 31 ++- .../assets/asset-hub-rococo/src/xcm_config.rs | 47 +++- .../assets/asset-hub-westend/Cargo.toml | 4 + .../assets/asset-hub-westend/src/lib.rs | 31 ++- .../asset-hub-westend/src/xcm_config.rs | 57 ++++- .../runtimes/assets/test-utils/Cargo.toml | 10 +- .../runtimes/assets/test-utils/src/lib.rs | 1 + .../assets/test-utils/src/test_cases.rs | 53 ++++- .../test-utils/src/test_cases_over_bridge.rs | 10 +- .../assets/test-utils/src/xcm_helpers.rs | 108 ++++++++++ .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 19 +- .../bridge-hub-kusama/src/xcm_config.rs | 16 +- .../bridge-hub-polkadot/src/lib.rs | 19 +- .../bridge-hub-polkadot/src/xcm_config.rs | 16 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 30 ++- .../bridge-hub-rococo/src/xcm_config.rs | 31 ++- .../bridge-hubs/test-utils/src/test_cases.rs | 4 +- .../collectives-polkadot/src/lib.rs | 20 +- .../collectives-polkadot/src/xcm_config.rs | 11 +- .../contracts/contracts-rococo/Cargo.toml | 16 +- .../contracts/contracts-rococo/src/lib.rs | 6 +- .../contracts-rococo/src/xcm_config.rs | 43 +++- .../runtimes/testing/penpal/src/lib.rs | 4 +- .../testing/rococo-parachain/Cargo.toml | 3 + .../testing/rococo-parachain/src/lib.rs | 4 +- cumulus/primitives/core/src/lib.rs | 2 +- cumulus/primitives/utility/Cargo.toml | 11 +- cumulus/primitives/utility/src/lib.rs | 83 ++++++-- cumulus/xcm/xcm-emulator/src/lib.rs | 6 +- polkadot/parachain/src/primitives.rs | 2 +- polkadot/runtime/common/Cargo.toml | 7 + polkadot/runtime/common/src/xcm_sender.rs | 169 +++++++++++++-- polkadot/runtime/parachains/src/dmp.rs | 47 ++-- polkadot/runtime/parachains/src/dmp/tests.rs | 2 +- polkadot/runtime/parachains/src/lib.rs | 16 +- polkadot/runtime/rococo/constants/Cargo.toml | 3 + polkadot/runtime/rococo/constants/src/lib.rs | 20 ++ polkadot/runtime/rococo/src/lib.rs | 18 +- polkadot/runtime/rococo/src/xcm_config.rs | 33 +-- .../runtime/test-runtime/src/xcm_config.rs | 6 +- polkadot/runtime/westend/constants/Cargo.toml | 3 + polkadot/runtime/westend/constants/src/lib.rs | 26 ++- polkadot/runtime/westend/src/lib.rs | 16 ++ .../xcm/pallet_xcm_benchmarks_fungible.rs | 34 +-- polkadot/runtime/westend/src/xcm_config.rs | 42 ++-- .../src/fungible/benchmarking.rs | 74 ++++--- .../src/fungible/mock.rs | 15 +- .../src/generic/benchmarking.rs | 142 +++++++++++-- .../pallet-xcm-benchmarks/src/generic/mock.rs | 23 +- .../pallet-xcm-benchmarks/src/generic/mod.rs | 5 + polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs | 34 ++- polkadot/xcm/pallet-xcm/src/mock.rs | 63 +++++- polkadot/xcm/pallet-xcm/src/tests.rs | 68 ++++++ polkadot/xcm/src/v3/mod.rs | 6 +- .../xcm/xcm-builder/src/currency_adapter.rs | 6 +- polkadot/xcm/xcm-builder/src/fee_handling.rs | 58 +++++ .../xcm/xcm-builder/src/fungibles_adapter.rs | 12 +- polkadot/xcm/xcm-builder/src/lib.rs | 3 + .../xcm-builder/src/nonfungibles_adapter.rs | 12 +- polkadot/xcm/xcm-builder/src/pay.rs | 13 +- polkadot/xcm/xcm-builder/src/tests/mock.rs | 4 +- polkadot/xcm/xcm-builder/src/tests/pay/pay.rs | 26 ++- .../xcm/xcm-builder/src/tests/pay/salary.rs | 13 +- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 4 +- polkadot/xcm/xcm-builder/tests/scenarios.rs | 12 +- polkadot/xcm/xcm-executor/src/lib.rs | 32 +-- .../xcm-executor/src/traits/fee_manager.rs | 8 +- .../xcm-executor/src/traits/transact_asset.rs | 28 ++- prdoc/pr_1234.prdoc | 20 ++ .../procedural/src/pallet/expand/warnings.rs | 10 +- 99 files changed, 2229 insertions(+), 468 deletions(-) create mode 100644 cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs create mode 100644 polkadot/xcm/xcm-builder/src/fee_handling.rs create mode 100644 prdoc/pr_1234.prdoc diff --git a/Cargo.lock b/Cargo.lock index 40b11be0c24..033219583bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -798,6 +798,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-rococo-runtime", + "asset-test-utils", "frame-support", "frame-system", "integration-tests-common", @@ -810,8 +811,10 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-parachains", + "rococo-runtime", "sp-runtime", "staging-xcm", + "staging-xcm-executor", "xcm-emulator", ] @@ -871,6 +874,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "primitive-types", + "rococo-runtime", "rococo-runtime-constants", "scale-info", "smallvec", @@ -899,6 +903,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-westend-runtime", + "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "frame-support", @@ -920,6 +925,8 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "westend-runtime", + "westend-runtime-constants", "xcm-emulator", ] @@ -993,6 +1000,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "westend-runtime", "westend-runtime-constants", ] @@ -2000,7 +2008,9 @@ dependencies = [ name = "bridge-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ + "asset-test-utils", "bp-messages", + "bridge-hub-rococo-runtime", "cumulus-pallet-dmp-queue", "cumulus-pallet-xcmp-queue", "frame-support", @@ -2013,6 +2023,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-parachains", "staging-xcm", + "staging-xcm-executor", "xcm-emulator", ] @@ -2894,6 +2905,7 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", + "rococo-runtime-constants", "scale-info", "smallvec", "sp-api", @@ -3617,6 +3629,7 @@ dependencies = [ "log", "parity-scale-codec", "polkadot-parachain-primitives", + "polkadot-runtime-parachains", "sc-client-api", "scale-info", "sp-core", @@ -3701,6 +3714,7 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "polkadot-runtime-common", + "polkadot-runtime-parachains", "rand_chacha 0.3.1", "scale-info", "sp-core", @@ -3797,8 +3811,10 @@ dependencies = [ "cumulus-primitives-core", "frame-support", "log", + "pallet-xcm-benchmarks", "parity-scale-codec", "polkadot-runtime-common", + "polkadot-runtime-parachains", "sp-io", "sp-runtime", "sp-std", @@ -11095,6 +11111,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "parachain-info", "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", @@ -12714,6 +12731,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", + "pallet-xcm-benchmarks", "parity-scale-codec", "polkadot-primitives", "polkadot-primitives-test-helpers", @@ -12737,6 +12755,7 @@ dependencies = [ "sp-std", "staging-xcm", "staging-xcm-builder", + "staging-xcm-executor", "static_assertions", ] @@ -14084,6 +14103,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", + "polkadot-runtime-common", "scale-info", "sp-api", "sp-block-builder", @@ -14216,6 +14236,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", + "staging-xcm", ] [[package]] @@ -20205,6 +20226,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", + "staging-xcm", ] [[package]] diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 5470dce4748..64e238ecab6 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -29,6 +29,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features # Polkadot polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} +polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} # Cumulus @@ -63,6 +64,7 @@ std = [ "frame-system/std", "log/std", "polkadot-parachain-primitives/std", + "polkadot-runtime-parachains/std", "scale-info/std", "sp-core/std", "sp-externalities/std", @@ -80,12 +82,14 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index eaf15768e29..369281ccd8e 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -29,10 +29,10 @@ use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_primitives_core::{ - relay_chain, AbridgedHostConfiguration, ChannelStatus, CollationInfo, DmpMessageHandler, - GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, MessageSendError, - OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, - XcmpMessageHandler, XcmpMessageSource, + relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, + DmpMessageHandler, GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, + MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, + UpwardMessageSender, XcmpMessageHandler, XcmpMessageSource, }; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ @@ -45,6 +45,7 @@ use frame_support::{ }; use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor}; use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; +use polkadot_runtime_parachains::FeeTracker; use scale_info::TypeInfo; use sp_runtime::{ traits::{Block as BlockT, BlockNumberProvider, Hash}, @@ -52,7 +53,7 @@ use sp_runtime::{ InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity, ValidTransaction, }, - DispatchError, RuntimeDebug, + DispatchError, FixedU128, RuntimeDebug, Saturating, }; use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; use xcm::latest::XcmHash; @@ -177,6 +178,20 @@ where check_version: bool, } +pub mod ump_constants { + use super::FixedU128; + + /// `host_config.max_upward_queue_size / THRESHOLD_FACTOR` is the threshold after which delivery + /// starts getting exponentially more expensive. + /// `2` means the price starts to increase when queue is half full. + pub const THRESHOLD_FACTOR: u32 = 2; + /// The base number the delivery fee factor gets multiplied by every time it is increased. + /// Also the number it gets divided by when decreased. + pub const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05 + /// The base number message size in KB is multiplied by before increasing the fee factor. + pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001 +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -240,6 +255,10 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { + /// Handles actually sending upward messages by moving them from `PendingUpwardMessages` to + /// `UpwardMessages`. Decreases the delivery fee factor if after sending messages, the queue + /// total size is less than the threshold (see [`ump_constants::THRESHOLD_FACTOR`]). + /// Also does the sending for HRMP messages it takes from `OutboundXcmpMessageSource`. fn on_finalize(_: BlockNumberFor) { >::kill(); >::kill(); @@ -326,6 +345,17 @@ pub mod pallet { UpwardMessages::::put(&up[..num as usize]); *up = up.split_off(num as usize); + // If the total size of the pending messages is less than the threshold, + // we decrease the fee factor, since the queue is less congested. + // This makes delivery of new messages cheaper. + let threshold = host_config + .max_upward_queue_size + .saturating_div(ump_constants::THRESHOLD_FACTOR); + let remaining_total_size: usize = up.iter().map(UpwardMessage::len).sum(); + if remaining_total_size <= threshold as usize { + Self::decrease_fee_factor(()); + } + (num, total_size) }); @@ -721,7 +751,7 @@ pub mod pallet { StorageValue<_, Vec>, ValueQuery>; /// Storage field that keeps track of bandwidth used by the unincluded segment along with the - /// latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with + /// latest HRMP watermark. Used for limiting the acceptance of new blocks with /// respect to relay chain constraints. #[pallet::storage] pub(super) type AggregatedUnincludedSegment = @@ -860,6 +890,17 @@ pub mod pallet { pub(super) type PendingUpwardMessages = StorageValue<_, Vec, ValueQuery>; + /// Initialization value for the delivery fee factor for UMP. + #[pallet::type_value] + pub fn UpwardInitialDeliveryFeeFactor() -> FixedU128 { + FixedU128::from_u32(1) + } + + /// The factor to multiply the base delivery fee by for UMP. + #[pallet::storage] + pub(super) type UpwardDeliveryFeeFactor = + StorageValue<_, FixedU128, ValueQuery, UpwardInitialDeliveryFeeFactor>; + /// The number of HRMP messages we observed in `on_initialize` and thus used that number for /// announcing the weight of `on_initialize` and `on_finalize`. #[pallet::storage] @@ -976,6 +1017,31 @@ impl Pallet { } } +impl FeeTracker for Pallet { + type Id = (); + + fn get_fee_factor(_: Self::Id) -> FixedU128 { + UpwardDeliveryFeeFactor::::get() + } + + fn increase_fee_factor(_: Self::Id, message_size_factor: FixedU128) -> FixedU128 { + >::mutate(|f| { + *f = f.saturating_mul( + ump_constants::EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor), + ); + *f + }) + } + + fn decrease_fee_factor(_: Self::Id) -> FixedU128 { + >::mutate(|f| { + *f = + UpwardInitialDeliveryFeeFactor::get().max(*f / ump_constants::EXPONENTIAL_FEE_BASE); + *f + }) + } +} + impl GetChannelInfo for Pallet { fn get_channel_status(id: ParaId) -> ChannelStatus { // Note, that we are using `relevant_messaging_state` which may be from the previous @@ -1019,10 +1085,17 @@ impl GetChannelInfo for Pallet { ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize) } - fn get_channel_max(id: ParaId) -> Option { + fn get_channel_info(id: ParaId) -> Option { let channels = Self::relevant_messaging_state()?.egress_channels; let index = channels.binary_search_by_key(&id, |item| item.0).ok()?; - Some(channels[index].1.max_message_size as usize) + let info = ChannelInfo { + max_capacity: channels[index].1.max_capacity, + max_total_size: channels[index].1.max_total_size, + max_message_size: channels[index].1.max_message_size, + msg_count: channels[index].1.msg_count, + total_size: channels[index].1.total_size, + }; + Some(info) } } @@ -1427,6 +1500,23 @@ impl Pallet { }) } + /// Open HRMP channel for using it in benchmarks or tests. + /// + /// The caller assumes that the pallet will accept regular outbound message to the sibling + /// `target_parachain` after this call. No other assumptions are made. + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + pub fn open_custom_outbound_hrmp_channel_for_benchmarks_or_tests( + target_parachain: ParaId, + channel: cumulus_primitives_core::AbridgedHrmpChannel, + ) { + RelevantMessagingState::::put(MessagingStateSnapshot { + dmq_mqc_head: Default::default(), + relay_dispatch_queue_remaining_capacity: Default::default(), + ingress_channels: Default::default(), + egress_channels: vec![(target_parachain, channel)], + }) + } + /// Prepare/insert relevant data for `schedule_code_upgrade` for benchmarks. #[cfg(feature = "runtime-benchmarks")] pub fn initialize_for_set_code_benchmark(max_code_size: u32) { @@ -1468,7 +1558,13 @@ impl frame_system::SetCode for ParachainSetCode { } impl Pallet { + /// Puts a message in the `PendingUpwardMessages` storage item. + /// The message will be later sent in `on_finalize`. + /// Checks host configuration to see if message is too big. + /// Increases the delivery fee factor if the queue is sufficiently (see + /// [`ump_constants::THRESHOLD_FACTOR`]) congested. pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> { + let message_len = message.len(); // Check if the message fits into the relay-chain constraints. // // Note, that we are using `host_configuration` here which may be from the previous @@ -1482,9 +1578,22 @@ impl Pallet { // // However, changing this setting is expected to be rare. if let Some(cfg) = Self::host_configuration() { - if message.len() > cfg.max_upward_message_size as usize { + if message_len > cfg.max_upward_message_size as usize { return Err(MessageSendError::TooBig) } + let threshold = + cfg.max_upward_queue_size.saturating_div(ump_constants::THRESHOLD_FACTOR); + // We check the threshold against total size and not number of messages since messages + // could be big or small. + >::append(message.clone()); + let pending_messages = PendingUpwardMessages::::get(); + let total_size: usize = pending_messages.iter().map(UpwardMessage::len).sum(); + if total_size > threshold as usize { + // We increase the fee factor by a factor based on the new message's size in KB + let message_size_factor = FixedU128::from((message_len / 1024) as u128) + .saturating_mul(ump_constants::MESSAGE_SIZE_FEE_BASE); + Self::increase_fee_factor((), message_size_factor); + } } else { // This storage field should carry over from the previous block. So if it's None // then it must be that this is an edge-case where a message is attempted to be @@ -1495,8 +1604,8 @@ impl Pallet { // returned back to the sender. // // Thus fall through here. + >::append(message.clone()); }; - >::append(message.clone()); // The relay ump does not use using_encoded // We apply the same this to use the same hash diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 626196790bc..3f5b4f649e3 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -1496,3 +1496,53 @@ fn deposits_relay_parent_storage_root() { }, ); } + +#[test] +fn ump_fee_factor_increases_and_decreases() { + BlockTests::new() + .with_relay_sproof_builder(|_, _, sproof| { + sproof.host_config.max_upward_queue_size = 100; + sproof.host_config.max_upward_message_num_per_candidate = 1; + }) + .add_with_post_test( + 1, + || { + // Fee factor increases in `send_upward_message` + ParachainSystem::send_upward_message(b"Test".to_vec()).unwrap(); + assert_eq!(UpwardDeliveryFeeFactor::::get(), FixedU128::from_u32(1)); + + ParachainSystem::send_upward_message( + b"This message will be enough to increase the fee factor".to_vec(), + ) + .unwrap(); + assert_eq!( + UpwardDeliveryFeeFactor::::get(), + FixedU128::from_rational(105, 100) + ); + }, + || { + // Factor decreases in `on_finalize`, but only if we are below the threshold + let messages = UpwardMessages::::get(); + assert_eq!(messages, vec![b"Test".to_vec()]); + assert_eq!( + UpwardDeliveryFeeFactor::::get(), + FixedU128::from_rational(105, 100) + ); + }, + ) + .add_with_post_test( + 2, + || { + // We do nothing here + }, + || { + let messages = UpwardMessages::::get(); + assert_eq!( + messages, + vec![b"This message will be enough to increase the fee factor".to_vec(),] + ); + // Now the delivery fee factor is decreased, since we are below the threshold + assert_eq!(UpwardDeliveryFeeFactor::::get(), FixedU128::from_u32(1)); + }, + ); +} diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 77d0551b511..034b640a0ed 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -14,13 +14,15 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive" frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} sp-io = { path = "../../../substrate/primitives/io", 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} # Polkadot -polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} +polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } +polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -54,7 +56,9 @@ std = [ "frame-system/std", "log/std", "polkadot-runtime-common/std", + "polkadot-runtime-parachains/std", "scale-info/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", @@ -69,6 +73,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -79,6 +84,7 @@ try-runtime = [ "frame-system/try-runtime", "pallet-balances/try-runtime", "polkadot-runtime-common/try-runtime", + "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] bridging = [ "bp-xcm-bridge-hub-router" ] diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index b53eb7cc0e1..b62dc0a47fc 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -22,6 +22,16 @@ //! Also provides an implementation of `SendXcm` which can be placed in a router tuple for relaying //! XCM over XCMP if the destination is `Parent/Parachain`. It requires an implementation of //! `XcmExecutor` for dispatching incoming XCM messages. +//! +//! To prevent out of memory errors on the `OutboundXcmpMessages` queue, an exponential fee factor +//! (`DeliveryFeeFactor`) is set, much like the one used in DMP. +//! The fee factor increases whenever the total size of messages in a particular channel passes a +//! threshold. This threshold is defined as a percentage of the maximum total size the channel can +//! have. More concretely, the threshold is `max_total_size` / `THRESHOLD_FACTOR`, where: +//! - `max_total_size` is the maximum size, in bytes, of the channel, not number of messages. +//! It is defined in the channel configuration. +//! - `THRESHOLD_FACTOR` just declares which percentage of the max size is the actual threshold. +//! If it's 2, then the threshold is half of the max size, if it's 4, it's a quarter, and so on. #![cfg_attr(not(feature = "std"), no_std)] @@ -49,13 +59,15 @@ use frame_support::{ traits::{EnsureOrigin, Get}, weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, }; -use polkadot_runtime_common::xcm_sender::PriceForParachainDelivery; +use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery; +use polkadot_runtime_parachains::FeeTracker; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaChaRng, }; use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; +use sp_core::MAX_POSSIBLE_ALLOCATION; +use sp_runtime::{FixedU128, RuntimeDebug, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; use xcm_executor::traits::ConvertOrigin; @@ -68,6 +80,19 @@ pub type OverweightIndex = u64; const LOG_TARGET: &str = "xcmp_queue"; const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB +/// Constants related to delivery fee calculation +pub mod delivery_fee_constants { + use super::FixedU128; + + /// Fees will start increasing when queue is half full + pub const THRESHOLD_FACTOR: u32 = 2; + /// The base number the delivery fee factor gets multiplied by every time it is increased. + /// Also, the number it gets divided by when decreased. + pub const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05 + /// The contribution of each KB to a fee factor increase + pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001 +} + // Maximum amount of messages to process per block. This is a temporary measure until we properly // account for proof size weights. const MAX_MESSAGES_PER_BLOCK: u8 = 10; @@ -77,7 +102,7 @@ const MAX_OVERWEIGHT_MESSAGES: u32 = 1000; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, Twox64Concat}; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -109,7 +134,7 @@ pub mod pallet { type ControllerOriginConverter: ConvertOrigin; /// The price for delivering an XCM to a sibling parachain destination. - type PriceForSiblingDelivery: PriceForParachainDelivery; + type PriceForSiblingDelivery: PriceForMessageDelivery; /// The weight information of this pallet. type WeightInfo: WeightInfo; @@ -374,6 +399,17 @@ pub mod pallet { /// Whether or not the XCMP queue is suspended from executing incoming XCMs or not. #[pallet::storage] pub(super) type QueueSuspended = StorageValue<_, bool, ValueQuery>; + + /// Initialization value for the DeliveryFee factor. + #[pallet::type_value] + pub fn InitialFactor() -> FixedU128 { + FixedU128::from_u32(1) + } + + /// The factor to multiply the base delivery fee by. + #[pallet::storage] + pub(super) type DeliveryFeeFactor = + StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>; } #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)] @@ -403,7 +439,7 @@ pub struct InboundChannelDetails { } /// Struct containing detailed information about the outbound channel. -#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] pub struct OutboundChannelDetails { /// The `ParaId` of the parachain that this channel is connected with. recipient: ParaId, @@ -503,56 +539,90 @@ impl Pallet { /// length prefixed and can thus decode each fragment from the aggregate stream. With this, /// we can concatenate them into a single aggregate blob without needing to be concerned /// about encoding fragment boundaries. + /// + /// If successful, returns the number of pages in the outbound queue after enqueuing the new + /// fragment. fn send_fragment( recipient: ParaId, format: XcmpMessageFormat, fragment: Fragment, ) -> Result { - let data = fragment.encode(); + let encoded_fragment = fragment.encode(); - // Optimization note: `max_message_size` could potentially be stored in - // `OutboundXcmpMessages` once known; that way it's only accessed when a new page is needed. - - let max_message_size = - T::ChannelInfo::get_channel_max(recipient).ok_or(MessageSendError::NoChannel)?; - if data.len() > max_message_size { + let channel_info = + T::ChannelInfo::get_channel_info(recipient).ok_or(MessageSendError::NoChannel)?; + let max_message_size = channel_info.max_message_size as usize; + // Max message size refers to aggregates, or pages. Not to individual fragments. + if encoded_fragment.len() > max_message_size { return Err(MessageSendError::TooBig) } - let mut s = >::get(); - let details = if let Some(details) = s.iter_mut().find(|item| item.recipient == recipient) { + let mut all_channels = >::get(); + let channel_details = if let Some(details) = + all_channels.iter_mut().find(|channel| channel.recipient == recipient) + { details } else { - s.push(OutboundChannelDetails::new(recipient)); - s.last_mut().expect("can't be empty; a new element was just pushed; qed") + all_channels.push(OutboundChannelDetails::new(recipient)); + all_channels + .last_mut() + .expect("can't be empty; a new element was just pushed; qed") }; - let have_active = details.last_index > details.first_index; - let appended = have_active && - >::mutate(recipient, details.last_index - 1, |s| { - if XcmpMessageFormat::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut &s[..]) != - Ok(format) - { - return false - } - if s.len() + data.len() > max_message_size { - return false - } - s.extend_from_slice(&data[..]); - true - }); - if appended { - Ok((details.last_index - details.first_index - 1) as u32) + let have_active = channel_details.last_index > channel_details.first_index; + // Try to append fragment to the last page, if there is enough space. + // We return the size of the last page inside of the option, to not calculate it again. + let appended_to_last_page = have_active + .then(|| { + >::mutate( + recipient, + channel_details.last_index - 1, + |page| { + if XcmpMessageFormat::decode_with_depth_limit( + MAX_XCM_DECODE_DEPTH, + &mut &page[..], + ) != Ok(format) + { + return None + } + if page.len() + encoded_fragment.len() > max_message_size { + return None + } + page.extend_from_slice(&encoded_fragment[..]); + Some(page.len()) + }, + ) + }) + .flatten(); + + let (number_of_pages, last_page_size) = if let Some(size) = appended_to_last_page { + let number_of_pages = (channel_details.last_index - channel_details.first_index) as u32; + (number_of_pages, size) } else { // Need to add a new page. - let page_index = details.last_index; - details.last_index += 1; + let page_index = channel_details.last_index; + channel_details.last_index += 1; let mut new_page = format.encode(); - new_page.extend_from_slice(&data[..]); + new_page.extend_from_slice(&encoded_fragment[..]); + let last_page_size = new_page.len(); + let number_of_pages = (channel_details.last_index - channel_details.first_index) as u32; >::insert(recipient, page_index, new_page); - let r = (details.last_index - details.first_index - 1) as u32; - >::put(s); - Ok(r) + >::put(all_channels); + (number_of_pages, last_page_size) + }; + + // We have to count the total size here since `channel_info.total_size` is not updated at + // this point in time. We assume all previous pages are filled, which, in practice, is not + // always the case. + let total_size = + number_of_pages.saturating_sub(1) * max_message_size as u32 + last_page_size as u32; + let threshold = channel_info.max_total_size / delivery_fee_constants::THRESHOLD_FACTOR; + if total_size > threshold { + let message_size_factor = FixedU128::from((encoded_fragment.len() / 1024) as u128) + .saturating_mul(delivery_fee_constants::MESSAGE_SIZE_FEE_BASE); + Self::increase_fee_factor(recipient, message_size_factor); } + + Ok(number_of_pages) } /// Sends a signal to the `dest` chain over XCMP. This is guaranteed to be dispatched on this @@ -1004,9 +1074,8 @@ impl XcmpMessageHandler for Pallet { // Record the fact we received it. match status.binary_search_by_key(&sender, |item| item.sender) { Ok(i) => { - let count = status[i].message_metadata.len(); - if count as u32 >= suspend_threshold && status[i].state == InboundState::Ok - { + let count = status[i].message_metadata.len() as u32; + if count >= suspend_threshold && status[i].state == InboundState::Ok { status[i].state = InboundState::Suspended; let r = Self::send_signal(sender, ChannelSignal::Suspend); if r.is_err() { @@ -1015,7 +1084,7 @@ impl XcmpMessageHandler for Pallet { ); } } - if (count as u32) < drop_threshold { + if count < drop_threshold { status[i].message_metadata.push((sent_at, format)); } else { debug_assert!( @@ -1023,6 +1092,13 @@ impl XcmpMessageHandler for Pallet { "XCMP channel queue full. Silently dropping message" ); } + // Update the delivery fee factor, if applicable. + if count > suspend_threshold { + let message_size_factor = + FixedU128::from((data_ref.len() / 1024) as u128) + .saturating_mul(delivery_fee_constants::MESSAGE_SIZE_FEE_BASE); + Self::increase_fee_factor(sender, message_size_factor); + } }, Err(_) => status.push(InboundChannelDetails { sender, @@ -1120,6 +1196,21 @@ impl XcmpMessageSource for Pallet { result.push((para_id, page)); } + let max_total_size = match T::ChannelInfo::get_channel_info(para_id) { + Some(channel_info) => channel_info.max_total_size, + None => { + log::warn!("calling `get_channel_info` with no RelevantMessagingState?!"); + MAX_POSSIBLE_ALLOCATION // We use this as a fallback in case the messaging state is not present + }, + }; + let threshold = max_total_size.saturating_div(delivery_fee_constants::THRESHOLD_FACTOR); + let remaining_total_size: usize = (first_index..last_index) + .map(|index| OutboundXcmpMessages::::decode_len(para_id, index).unwrap()) + .sum(); + if remaining_total_size <= threshold as usize { + Self::decrease_fee_factor(para_id); + } + *status = OutboundChannelDetails { recipient: para_id, state: outbound_state, @@ -1172,7 +1263,7 @@ impl SendXcm for Pallet { MultiLocation { parents: 1, interior: X1(Parachain(id)) } => { let xcm = msg.take().ok_or(SendError::MissingArgument)?; let id = ParaId::from(*id); - let price = T::PriceForSiblingDelivery::price_for_parachain_delivery(id, &xcm); + let price = T::PriceForSiblingDelivery::price_for_delivery(id, &xcm); let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm) .map_err(|()| SendError::DestinationUnsupported)?; Ok(((id, versioned_xcm), price)) @@ -1198,3 +1289,27 @@ impl SendXcm for Pallet { } } } + +impl FeeTracker for Pallet { + type Id = ParaId; + + fn get_fee_factor(id: Self::Id) -> FixedU128 { + >::get(id) + } + + fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128 { + >::mutate(id, |f| { + *f = f.saturating_mul( + delivery_fee_constants::EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor), + ); + *f + }) + } + + fn decrease_fee_factor(id: Self::Id) -> FixedU128 { + >::mutate(id, |f| { + *f = InitialFactor::get().max(*f / delivery_fee_constants::EXPONENTIAL_FEE_BASE); + *f + }) + } +} diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index a3f10fa5428..bc0710e3465 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -85,8 +85,10 @@ parameter_types! { pub const MaxReserves: u32 = 50; } +pub type Balance = u64; + impl pallet_balances::Config for Test { - type Balance = u64; + type Balance = Balance; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; @@ -196,6 +198,22 @@ impl ConvertOrigin } } +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(RelayChain::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: Balance = 300_000_000; + /// The fee per byte + pub const ByteFee: Balance = 1_000_000; +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + ByteFee, + XcmpQueue, +>; + impl Config for Test { type RuntimeEvent = RuntimeEvent; type XcmExecutor = xcm_executor::XcmExecutor; @@ -205,7 +223,7 @@ impl Config for Test { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = SystemParachainAsSuperuser; type WeightInfo = (); - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index ba005a5badf..cf6d947609d 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -324,13 +324,14 @@ fn xcmp_queue_consumes_dest_and_msg_on_ok_validate() { let dest = (Parent, X1(Parachain(5555))); let mut dest_wrapper = Some(dest.into()); let mut msg_wrapper = Some(message.clone()); - assert!(::validate(&mut dest_wrapper, &mut msg_wrapper).is_ok()); - - // check wrapper were consumed - assert_eq!(None, dest_wrapper.take()); - assert_eq!(None, msg_wrapper.take()); new_test_ext().execute_with(|| { + assert!(::validate(&mut dest_wrapper, &mut msg_wrapper).is_ok()); + + // check wrapper were consumed + assert_eq!(None, dest_wrapper.take()); + assert_eq!(None, msg_wrapper.take()); + // another try with router chain with asserting sender assert_eq!( Err(SendError::Transport("NoChannel")), @@ -370,3 +371,74 @@ fn xcmp_queue_send_xcm_works() { .any(|(para_id, _)| para_id == &sibling_para_id)); }) } + +#[test] +fn verify_fee_factor_increase_and_decrease() { + use cumulus_primitives_core::AbridgedHrmpChannel; + use sp_runtime::FixedU128; + + let sibling_para_id = ParaId::from(12345); + let destination = (Parent, Parachain(sibling_para_id.into())).into(); + let xcm = Xcm(vec![ClearOrigin; 100]); + let versioned_xcm = VersionedXcm::from(xcm.clone()); + let mut xcmp_message = XcmpMessageFormat::ConcatenatedVersionedXcm.encode(); + xcmp_message.extend(versioned_xcm.encode()); + + new_test_ext().execute_with(|| { + let initial = InitialFactor::get(); + assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); + + // Open channel so messages can actually be sent + ParachainSystem::open_custom_outbound_hrmp_channel_for_benchmarks_or_tests( + sibling_para_id, + AbridgedHrmpChannel { + max_capacity: 10, + max_total_size: 1000, + max_message_size: 104, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + + // Fee factor is only increased in `send_fragment`, which is called by `send_xcm`. + // When queue is not congested, fee factor doesn't change. + assert_ok!(send_xcm::(destination, xcm.clone())); // Size 104 + assert_ok!(send_xcm::(destination, xcm.clone())); // Size 208 + assert_ok!(send_xcm::(destination, xcm.clone())); // Size 312 + assert_ok!(send_xcm::(destination, xcm.clone())); // Size 416 + assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); + + // Sending the message right now is cheap + let (_, delivery_fees) = validate_send::(destination, xcm.clone()) + .expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + assert_eq!(delivery_fee_amount, 402_000_000); + + let smaller_xcm = Xcm(vec![ClearOrigin; 30]); + + // When we get to half of `max_total_size`, because `THRESHOLD_FACTOR` is 2, + // then the fee factor starts to increase. + assert_ok!(send_xcm::(destination, xcm.clone())); // Size 520 + assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), FixedU128::from_float(1.05)); + + for _ in 0..12 { // We finish at size 929 + assert_ok!(send_xcm::(destination, smaller_xcm.clone())); + } + assert!(DeliveryFeeFactor::::get(sibling_para_id) > FixedU128::from_float(1.88)); + + // Sending the message right now is expensive + let (_, delivery_fees) = validate_send::(destination, xcm.clone()) + .expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + assert_eq!(delivery_fee_amount, 758_030_955); + + // Fee factor only decreases in `take_outbound_messages` + for _ in 0..5 { // We take 5 100 byte pages + XcmpQueue::take_outbound_messages(1); + } + assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.72)); + XcmpQueue::take_outbound_messages(1); + assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.63)); + }); +} diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index b9bf97d7786..b6bf8419ec4 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -10,6 +10,8 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -412,7 +414,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 29528b169ae..2bdae91ef4d 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -40,6 +40,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } +parachain-info = { path = "../pallets/parachain-info", default-features = false } [dev-dependencies] pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false} @@ -61,6 +62,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "parachain-info/std", "polkadot-core-primitives/std", "polkadot-primitives/std", "rococo-runtime-constants/std", diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index 89e74b2f9b7..4ebc2cc6e1e 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -73,7 +73,10 @@ mod types { /// Common constants of parachains. mod constants { use super::types::BlockNumber; - use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}; + use frame_support::{ + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + PalletId, + }; use sp_runtime::Perbill; /// 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 @@ -101,6 +104,9 @@ mod constants { WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), polkadot_primitives::MAX_POV_SIZE as u64, ); + + /// Treasury pallet id of the local chain, used to convert into AccountId + pub const TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); } /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 91ad7d902bd..4b0215d672b 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -16,10 +16,9 @@ use crate::impls::AccountIdOf; use cumulus_primitives_core::{IsSystem, ParaId}; use frame_support::{ - traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair}, + traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair}, weights::Weight, }; -use log; use sp_runtime::traits::Get; use sp_std::marker::PhantomData; use xcm::latest::prelude::*; @@ -80,6 +79,27 @@ impl> ContainsPair } } +pub struct RelayOrOtherSystemParachains< + SystemParachainMatcher: Contains, + Runtime: parachain_info::Config, +> { + _runtime: PhantomData<(SystemParachainMatcher, Runtime)>, +} +impl, Runtime: parachain_info::Config> + Contains for RelayOrOtherSystemParachains +{ + fn contains(l: &MultiLocation) -> bool { + let self_para_id: u32 = parachain_info::Pallet::::get().into(); + if let MultiLocation { parents: 0, interior: X1(Parachain(para_id)) } = l { + if *para_id == self_para_id { + return false + } + } + matches!(l, MultiLocation { parents: 1, interior: Here }) || + SystemParachainMatcher::contains(l) + } +} + /// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain). pub struct ConcreteAssetFromSystem(PhantomData); impl> ContainsPair diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index 52682c6eefd..db58d8d3303 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -25,8 +25,11 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} +rococo-runtime = { path = "../../../../../../polkadot/runtime/rococo", default-features = false } # Cumulus +asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } parachains-common = { path = "../../../../common" } asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } @@ -47,5 +50,7 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", + "rococo-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index e0e9dcbdce7..42f54bdf49d 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use asset_test_utils::xcm_helpers; pub use codec::Encode; pub use frame_support::{ assert_err, assert_ok, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 0c136e2789f..fb25607c635 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -14,6 +14,8 @@ // limitations under the License. use crate::*; +use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -182,10 +184,16 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { test.set_dispatchable::(relay_limited_reserve_transfer_assets); test.assert(); + let delivery_fees = Rococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after); } @@ -244,7 +252,13 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { 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); + let delivery_fees = Rococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after); } @@ -306,7 +320,13 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // transfers } @@ -338,7 +358,13 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // transfers } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 21afed17918..4b2ea0e160c 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -14,6 +14,8 @@ // limitations under the License. use crate::*; +use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -171,11 +173,17 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.set_dispatchable::(relay_limited_teleport_assets); test.assert(); + let delivery_fees = Rococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -212,8 +220,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -247,8 +261,14 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance does not change assert_eq!(receiver_balance_after, receiver_balance_before); } @@ -274,11 +294,17 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.set_dispatchable::(relay_teleport_assets); test.assert(); + let delivery_fees = Rococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -315,8 +341,14 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -347,11 +379,17 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.set_dispatchable::(system_para_teleport_assets); test.assert(); + let delivery_fees = AssetHubRococo::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance does not change assert_eq!(receiver_balance_after, receiver_balance_before); } @@ -359,11 +397,12 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_ROCOCO_ED * 100; - let native_asset: VersionedMultiAssets = (Parent, amount).into(); + let native_asset: MultiAssets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( - AssetHubRococo, // Origin - vec![BridgeHubRococo], // Destinations + AssetHubRococo, // Origin + AssetHubRococoXcmConfig, // XCM Configuration + 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 bf141dafebf..4b6b8874b6a 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 @@ -30,10 +30,13 @@ xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", defaul 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} +westend-runtime = { path = "../../../../../../polkadot/runtime/westend", default-features = false } +westend-runtime-constants = { path = "../../../../../../polkadot/runtime/westend/constants", default-features = false } # Cumulus parachains-common = { path = "../../../../common" } asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } +asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" } @@ -59,6 +62,7 @@ runtime-benchmarks = [ "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "westend-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 c25cc601fbe..0133cdbed5c 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 @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use asset_test_utils::xcm_helpers; pub use codec::Encode; pub use frame_support::{ assert_err, assert_ok, 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 8f8b7a7dde7..3b48e6529ff 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 @@ -14,6 +14,8 @@ // limitations under the License. use crate::*; +use asset_hub_westend_runtime::xcm_config::XcmConfig; +use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -179,10 +181,16 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { test.set_dispatchable::(relay_limited_reserve_transfer_assets); test.assert(); + let delivery_fees = Westend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after); } @@ -238,10 +246,16 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { test.set_dispatchable::(relay_reserve_transfer_assets); test.assert(); + let delivery_fees = Westend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after); } @@ -303,7 +317,17 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( + test.args.assets.clone(), + 0, + test.args.weight_limit, + test.args.beneficiary, + test.args.dest, + ) + }); + + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // transfers } @@ -335,7 +359,17 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( + test.args.assets.clone(), + 0, + test.args.weight_limit, + test.args.beneficiary, + test.args.dest, + ) + }); + + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // transfers } 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 81471c401f3..4fe0062dafc 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 @@ -16,6 +16,8 @@ #![allow(dead_code)] // use crate::*; +use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; +use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -173,11 +175,17 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.set_dispatchable::(relay_limited_teleport_assets); test.assert(); + let delivery_fees = Westend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -214,8 +222,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -249,8 +263,14 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance does not change assert_eq!(receiver_balance_after, receiver_balance_before); } @@ -276,11 +296,17 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.set_dispatchable::(relay_teleport_assets); test.assert(); + let delivery_fees = Westend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -314,11 +340,17 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { test.set_dispatchable::(system_para_teleport_assets); test.assert(); + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); } @@ -349,11 +381,17 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.set_dispatchable::(system_para_teleport_assets); test.assert(); + let delivery_fees = AssetHubWestend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + 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); + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml index 7ecf8715824..b3ce2a99f70 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 @@ -19,13 +19,16 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} # Cumulus +asset-test-utils = { path = "../../../../../parachains/runtimes/assets/test-utils", default-features = false } parachains-common = { path = "../../../../common" } cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} +bridge-hub-rococo-runtime = { path = "../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} 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 index 4c7e37fab62..f00288a4d8c 100644 --- 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 @@ -14,14 +14,16 @@ // limitations under the License. use crate::*; +use bridge_hub_rococo_runtime::xcm_config::XcmConfig; #[test] fn teleport_to_other_system_parachains_works() { let amount = BRIDGE_HUB_ROCOCO_ED * 100; - let native_asset: VersionedMultiAssets = (Parent, amount).into(); + let native_asset: MultiAssets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( BridgeHubRococo, // Origin + XcmConfig, // XCM configuration vec![AssetHubRococo], // Destinations (native_asset, amount) ); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index e87c361ebea..5ce94026402 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -15,7 +15,7 @@ #[macro_export] macro_rules! test_parachain_is_trusted_teleporter { - ( $sender_para:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { + ( $sender_para:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { $crate::paste::paste! { // init Origin variables let sender = [<$sender_para Sender>]::get(); @@ -32,19 +32,22 @@ macro_rules! test_parachain_is_trusted_teleporter { 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 = + <$sender_para>::sibling_location_of(<$receiver_para>::para_id()); + let beneficiary: MultiLocation = $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); + dbg!(&origin); + dbg!(¶_destination); + // 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()), + bx!(para_destination.into()), + bx!(beneficiary.into()), + bx!($assets.clone().into()), fee_asset_item, weight_limit.clone(), )); @@ -89,8 +92,13 @@ macro_rules! test_parachain_is_trusted_teleporter { <$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; + let delivery_fees = <$sender_para>::execute_with(|| { + asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< + <$sender_xcm_config as xcm_executor::Config>::XcmSender, + >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) + }); - assert_eq!(para_sender_balance_before - $amount, para_sender_balance_after); + assert_eq!(para_sender_balance_before - $amount - delivery_fees, para_sender_balance_after); assert!(para_receiver_balance_after > para_receiver_balance_before); // Update sender balance 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 7c218bfbc09..dc6d19d06f4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -14,14 +14,7 @@ // limitations under the License. use parachains_common::AccountId; -use xcm::{ - prelude::{ - AccountId32, All, BuyExecution, DepositAsset, MultiAsset, MultiAssets, MultiLocation, - OriginKind, RefundSurplus, Transact, UnpaidExecution, VersionedXcm, Weight, WeightLimit, - WithdrawAsset, Xcm, X1, - }, - DoubleEncoded, -}; +use xcm::{prelude::*, DoubleEncoded}; /// Helper method to build a XCM with a `Transact` instruction and paying for its execution pub fn xcm_transact_paid_execution( 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 40ce122112d..5c51a3a5232 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -34,6 +34,8 @@ use assets_common::{ AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -88,7 +90,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; use crate::xcm_config::{ @@ -645,7 +647,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { >; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -1211,9 +1213,21 @@ impl_runtime_apis! { use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + KsmLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(KsmLocation::get()) } @@ -1269,6 +1283,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 57e745d2e5e..3628641544b 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 @@ -16,9 +16,9 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; -use crate::ForeignAssets; +use crate::{ForeignAssets, CENTS}; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, matching::{FromSiblingParachain, IsForeignConcreteAsset}, @@ -34,6 +34,7 @@ use parachains_common::{ xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, }; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ @@ -532,11 +533,21 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(KsmLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; 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 d4f7d6ef361..b58d094deec 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -66,6 +66,8 @@ use assets_common::{ foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -118,7 +120,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; use crate::xcm_config::ForeignCreatorsSovereignAccountOf; @@ -581,7 +583,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { EnsureXcm>, >; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -1090,9 +1092,21 @@ impl_runtime_apis! { use xcm_config::{DotLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + xcm_config::DotLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(DotLocation::get()) } @@ -1148,6 +1162,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 8a4b24407b5..91663a75970 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 @@ -16,7 +16,7 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, CENTS, }; use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset}; use frame_support::{ @@ -30,6 +30,7 @@ use parachains_common::{ xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, }; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ @@ -456,11 +457,21 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(DotLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index af0ce6d5814..ba846a850c8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -55,6 +55,7 @@ sp-weights = { path = "../../../../../substrate/primitives/weights", default-fea primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "scale-info", "num-traits"] } # Polkadot +rococo-runtime = { path = "../../../../../polkadot/runtime/rococo", default-features = false } 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 } @@ -130,6 +131,7 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "rococo-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -165,6 +167,7 @@ try-runtime = [ "pallet-xcm/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", + "rococo-runtime/try-runtime", "sp-runtime/try-runtime", ] std = [ @@ -218,6 +221,7 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "rococo-runtime-constants/std", + "rococo-runtime/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 3328ff0edaf..a0eef7e43a4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -93,7 +93,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; use crate::xcm_config::{ @@ -636,6 +636,20 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::TokenLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; @@ -645,7 +659,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -1315,9 +1329,21 @@ impl_runtime_apis! { use xcm_config::{TokenLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(TokenLocation::get()) } @@ -1373,6 +1399,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 6db4a787405..d25f336f1af 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -14,10 +14,11 @@ // 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, + AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, + FeeAssetId, 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, @@ -31,10 +32,17 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, - xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, + xcm_config::{ + AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, + RelayOrOtherSystemParachains, + }, + TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; -use sp_runtime::traits::ConvertInto; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use rococo_runtime::Treasury as RococoTreasury; +use rococo_runtime_constants::system_parachain::SystemParachains; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -46,6 +54,7 @@ use xcm_builder::{ SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeesToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -67,6 +76,7 @@ parameter_types! { PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); + pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); } /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. @@ -521,6 +531,23 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = ForeignAssetsInstance, >; +parameter_types! { + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(::index() as u8)).into(); +} + +pub struct RelayTreasury; +impl Contains for RelayTreasury { + fn contains(location: &MultiLocation) -> bool { + let relay_treasury_location = RelayTreasuryLocation::get(); + *location == relay_treasury_location + } +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); + /// 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 @@ -588,8 +615,7 @@ impl xcm_executor::Config for XcmConfig { 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 FeeManager = XcmFeesToAccount; type MessageExporter = (); type UniversalAliases = (bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases); @@ -602,10 +628,13 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// 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, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index f7f6fdf68e4..cb5fba1684c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -60,6 +60,7 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} +westend-runtime = { path = "../../../../../polkadot/runtime/westend", 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} @@ -116,6 +117,7 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "westend-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", ] @@ -149,6 +151,7 @@ try-runtime = [ "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", + "westend-runtime/try-runtime", ] std = [ "assets-common/std", @@ -210,6 +213,7 @@ std = [ "sp-version/std", "substrate-wasm-builder", "westend-runtime-constants/std", + "westend-runtime/std", "xcm-builder/std", "xcm-executor/std", "xcm/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 94333208762..a7dc3a84777 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -88,6 +88,7 @@ use assets_common::{ foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, }; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; use crate::xcm_config::ForeignCreatorsSovereignAccountOf; @@ -604,6 +605,20 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::WestendLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; @@ -613,7 +628,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -1262,9 +1277,21 @@ impl_runtime_apis! { use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; use pallet_xcm_benchmarks::asset_instance_from; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + WestendLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(WestendLocation::get()) } @@ -1320,6 +1347,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { @@ -1421,7 +1449,6 @@ pub mod migrations { }; use parachains_common::impls::AccountIdOf; use sp_runtime::{traits::StaticLookup, Saturating}; - use xcm::latest::prelude::*; /// Temporary migration because of bug with native asset, it can be removed once applied on /// `AssetHubWestend`. Migrates pools with `MultiLocation { parents: 0, interior: Here }` to 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 99f8d5ae589..1306b00e2f0 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 @@ -14,9 +14,10 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo, - ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, + FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, + RuntimeEvent, RuntimeOrigin, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, + XcmpQueue, }; use crate::ForeignAssets; use assets_common::{ @@ -31,10 +32,17 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, - xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, + xcm_config::{ + AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, + RelayOrOtherSystemParachains, + }, + TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; -use sp_runtime::traits::ConvertInto; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; +use westend_runtime::Treasury as WestendTreasury; +use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -45,6 +53,7 @@ use xcm_builder::{ SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeesToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -65,6 +74,7 @@ parameter_types! { pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -482,6 +492,36 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::COLLECTIVES_ID | + system_parachain::BRIDGE_HUB_ID + )), + } + }; +} + +parameter_types! { + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(::index() as u8)).into(); +} + +pub struct RelayTreasury; +impl Contains for RelayTreasury { + fn contains(location: &MultiLocation) -> bool { + let relay_treasury_location = RelayTreasuryLocation::get(); + *location == relay_treasury_location + } +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); + /// 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 @@ -531,7 +571,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = XcmFeesToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; @@ -542,11 +582,14 @@ impl xcm_executor::Config for XcmConfig { /// Local origins on this chain are allowed to dispatch XCM sends/executions. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 30d3cf90b47..d8b5ca5c8e5 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -34,11 +34,11 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } # 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} +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 } diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 3c62faf3d5e..e0f05fa7b0a 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -18,4 +18,5 @@ pub mod test_cases; pub mod test_cases_over_bridge; +pub mod xcm_helpers; 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 62faa384781..b0616acb1a4 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -15,10 +15,13 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. +use super::xcm_helpers; use codec::Encode; use frame_support::{ assert_noop, assert_ok, - traits::{fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{ + fungible::Mutate, fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait, + }, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -175,6 +178,21 @@ pub fn teleports_for_native_asset_works< target_account_balance_before_teleport - existential_deposit ); + // Mint funds into account to ensure it has enough balance to pay delivery fees + let delivery_fees = + xcm_helpers::transfer_assets_delivery_fees::( + (native_asset_id, native_asset_to_teleport_away.into()).into(), + 0, + Unlimited, + dest_beneficiary, + dest, + ); + >::mint_into( + &target_account, + delivery_fees.into(), + ) + .unwrap(); + assert_ok!(RuntimeHelper::::do_teleport_assets::( RuntimeHelper::::origin_of(target_account.clone()), dest, @@ -184,6 +202,7 @@ pub fn teleports_for_native_asset_works< included_head.clone(), &alice, )); + // check balances assert_eq!( >::free_balance(&target_account), @@ -232,10 +251,21 @@ pub fn teleports_for_native_asset_works< &alice, )); + let delivery_fees = + xcm_helpers::transfer_assets_delivery_fees::( + (native_asset_id, native_asset_to_teleport_away.into()).into(), + 0, + Unlimited, + dest_beneficiary, + dest, + ); + // check balances assert_eq!( >::free_balance(&target_account), - target_account_balance_before_teleport - native_asset_to_teleport_away + target_account_balance_before_teleport - + native_asset_to_teleport_away - + delivery_fees.into() ); assert_eq!( >::free_balance(&CheckingAccount::get()), @@ -370,7 +400,7 @@ pub fn teleports_for_foreign_assets_works< fun: Fungible(buy_execution_fee_amount), }; - let teleported_foreign_asset_amount = 10000000000000; + let teleported_foreign_asset_amount = 10_000_000_000_000; let runtime_para_id = 1000; ExtBuilder::::default() .with_collators(collator_session_keys.collators()) @@ -400,11 +430,11 @@ pub fn teleports_for_foreign_assets_works< >::free_balance(&target_account), existential_deposit ); + // check `CheckingAccount` before assert_eq!( >::free_balance(&CheckingAccount::get()), existential_deposit ); - // check `CheckingAccount` before assert_eq!( >::balance( foreign_asset_id_multilocation.into(), @@ -540,6 +570,21 @@ pub fn teleports_for_foreign_assets_works< .into() ); + // Make sure the target account has enough native asset to pay for delivery fees + let delivery_fees = + xcm_helpers::transfer_assets_delivery_fees::( + (foreign_asset_id_multilocation, asset_to_teleport_away).into(), + 0, + Unlimited, + dest_beneficiary, + dest, + ); + >::mint_into( + &target_account, + delivery_fees.into(), + ) + .unwrap(); + assert_ok!(RuntimeHelper::::do_teleport_assets::( RuntimeHelper::::origin_of(target_account.clone()), dest, diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index a967384fb6d..9852453d283 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -20,7 +20,9 @@ use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ assert_ok, - traits::{Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError}, + traits::{ + fungible::Mutate, Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError, + }, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::{AccountId, Balance}; @@ -164,6 +166,12 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< }), }; + // Make sure sender has enough funds for paying delivery fees + // TODO: Get this fee via weighing the corresponding message + let delivery_fees = 1324039894; + >::mint_into(&alice_account, delivery_fees.into()) + .unwrap(); + // do pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs new file mode 100644 index 00000000000..0aebe38fef5 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs @@ -0,0 +1,108 @@ +// 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 . + +//! Helpers for calculating XCM delivery fees. + +use xcm::latest::prelude::*; + +/// Returns the delivery fees amount for pallet xcm's `teleport_assets` and +/// `reserve_transfer_assets` extrinsics. +/// Because it returns only a `u128`, it assumes delivery fees are only paid +/// in one asset and that asset is known. +pub fn transfer_assets_delivery_fees( + assets: MultiAssets, + fee_asset_item: u32, + weight_limit: WeightLimit, + beneficiary: MultiLocation, + destination: MultiLocation, +) -> u128 { + let message = teleport_assets_dummy_message(assets, fee_asset_item, weight_limit, beneficiary); + get_fungible_delivery_fees::(destination, message) +} + +/// Returns the delivery fees amount for a query response as a result of the execution +/// of a `ExpectError` instruction with no error. +pub fn query_response_delivery_fees(querier: MultiLocation) -> u128 { + // Message to calculate delivery fees, it's encoded size is what's important. + // This message reports that there was no error, if an error is reported, the encoded size would + // be different. + let message = Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + QueryResponse { + query_id: 0, // Dummy query id + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: Some(querier), + }, + SetTopic([0u8; 32]), // Dummy topic + ]); + get_fungible_delivery_fees::(querier, message) +} + +/// Returns the delivery fees amount for the execution of `PayOverXcm` +pub fn pay_over_xcm_delivery_fees( + interior: Junctions, + destination: MultiLocation, + beneficiary: MultiLocation, + asset: MultiAsset, +) -> u128 { + // This is a dummy message. + // The encoded size is all that matters for delivery fees. + let message = Xcm(vec![ + DescendOrigin(interior), + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + SetAppendix(Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + ReportError(QueryResponseInfo { destination, query_id: 0, max_weight: Weight::zero() }), + ])), + TransferAsset { beneficiary, assets: vec![asset].into() }, + ]); + get_fungible_delivery_fees::(destination, message) +} + +/// Approximates the actual message sent by the teleport extrinsic. +/// The assets are not reanchored and the topic is a dummy one. +/// However, it should have the same encoded size, which is what matters for delivery fees. +/// Also has same encoded size as the one created by the reserve transfer assets extrinsic. +fn teleport_assets_dummy_message( + assets: MultiAssets, + fee_asset_item: u32, + weight_limit: WeightLimit, + beneficiary: MultiLocation, +) -> Xcm<()> { + Xcm(vec![ + ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited` + ClearOrigin, + BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit }, + DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary }, + SetTopic([0u8; 32]), // Dummy topic + ]) +} + +/// Given a message, a sender, and a destination, it returns the delivery fees +fn get_fungible_delivery_fees(destination: MultiLocation, message: Xcm<()>) -> u128 { + let Ok((_, delivery_fees)) = validate_send::(destination, message) else { + unreachable!("message can be sent; qed") + }; + if let Some(delivery_fee) = delivery_fees.inner().first() { + let Fungible(delivery_fee_amount) = delivery_fee.fun else { + unreachable!("asset is fungible; qed"); + }; + delivery_fee_amount + } else { + 0 + } +} 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 791751e7736..190987b1cfe 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 @@ -26,6 +26,8 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -75,7 +77,7 @@ use parachains_common::{ }; // XCM Imports -use xcm::latest::prelude::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; /// The address format for describing accounts. @@ -314,7 +316,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -671,9 +673,21 @@ impl_runtime_apis! { use xcm::latest::prelude::*; use xcm_config::KsmRelayLocation; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + xcm_config::KsmRelayLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(KsmRelayLocation::get()) } @@ -714,6 +728,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 563115c8938..85b983a6ab9 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 @@ -16,7 +16,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, + CENTS, }; use frame_support::{ match_types, parameter_types, @@ -26,6 +27,7 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -220,11 +222,21 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(KsmRelayLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; 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 928b9d091ec..dc23135f05d 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 @@ -26,6 +26,8 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -75,7 +77,7 @@ use parachains_common::{ HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; // XCM Imports -use xcm::latest::prelude::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; /// The address format for describing accounts. @@ -314,7 +316,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -671,9 +673,21 @@ impl_runtime_apis! { use xcm::latest::prelude::*; use xcm_config::DotRelayLocation; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + xcm_config::DotRelayLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(DotRelayLocation::get()) } @@ -714,6 +728,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 6e9d6d58619..7378961f576 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 @@ -16,7 +16,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, + CENTS, }; use frame_support::{ match_types, parameter_types, @@ -26,6 +27,7 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -224,11 +226,21 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(DotRelayLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; 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 3a8507ccf93..6b6d84649d7 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 @@ -75,6 +75,7 @@ use bp_runtime::HeaderId; pub use sp_runtime::BuildStorage; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use xcm::latest::prelude::*; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -362,6 +363,20 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::TokenLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; @@ -371,7 +386,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -1014,9 +1029,21 @@ impl_runtime_apis! { use xcm::latest::prelude::*; use xcm_config::TokenLocation; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; fn valid_destination() -> Result { Ok(TokenLocation::get()) } @@ -1057,6 +1084,7 @@ impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 b35011b095f..0f6dfb13684 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 @@ -15,10 +15,10 @@ // along with Cumulus. If not, see . use super::{ - AccountId, AllPalletsWithSystem, Balances, BridgeGrandpaRococoInstance, - BridgeGrandpaWococoInstance, DeliveryRewardInBalance, ParachainInfo, ParachainSystem, - PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, - RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, BridgeGrandpaRococoInstance, + BridgeGrandpaWococoInstance, DeliveryRewardInBalance, FeeAssetId, ParachainInfo, + ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, + RuntimeEvent, RuntimeFlavor, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; use crate::{ bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, @@ -30,9 +30,16 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + TREASURY_PALLET_ID, +}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use rococo_runtime_constants::system_parachain::SystemParachains; use sp_core::Get; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -41,6 +48,7 @@ use xcm_builder::{ ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeesToAccount, }; use xcm_executor::{ traits::{ExportXcm, WithOriginFilter}, @@ -55,6 +63,7 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); } /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. @@ -253,7 +262,12 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); + type FeeManager = XcmFeesToAccount< + Self, + RelayOrOtherSystemParachains, + AccountId, + TreasuryAccount, + >; type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; @@ -261,6 +275,9 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } +pub type PriceForParentDelivery = + ExponentialPrice; + /// Converts a local signed origin into an XCM multilocation. /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; @@ -269,7 +286,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; 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 d4e5aac3436..e77af189b4f 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 @@ -186,7 +186,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< XcmConfig::AssetTransactor::deposit_asset( &ed, &sibling_parachain_location, - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ) .expect("deposited ed"); } @@ -194,7 +194,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< XcmConfig::AssetTransactor::deposit_asset( &fee, &sibling_parachain_location, - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ) .expect("deposited fee"); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index ff16f93d8f5..cec4152bcc3 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -45,6 +45,7 @@ pub mod fellowship; pub use ambassador::pallet_ambassador_origins; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; use fellowship::{ migration::import_kusama_fellowship, pallet_fellowship_origins, Fellows, FellowshipCollectiveInstance, @@ -98,7 +99,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::BodyId; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -401,6 +402,20 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::DotLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; @@ -410,7 +425,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EitherOfDiverse, Fellows>; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = + polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { 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 79d4c53c2ee..c64d688e5f1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -14,8 +14,9 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, Fellows, ParachainInfo, ParachainSystem, - PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, Fellows, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + TransactionByteFee, WeightToFee, XcmpQueue, }; use frame_support::{ match_types, parameter_types, @@ -26,6 +27,7 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -279,11 +281,14 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index d59fe2fd29e..448cc4f4160 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -54,13 +54,14 @@ pallet-contracts = { path = "../../../../../substrate/frame/contracts", default- pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts/primitives", default-features = false} # Polkadot -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} -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} +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 } +polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } +rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/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 } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } @@ -115,6 +116,7 @@ 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", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 70392c5ecbc..1ea3eaa2e47 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -224,13 +224,17 @@ impl pallet_balances::Config for Runtime { type MaxFreezes = ConstU32<0>; } +parameter_types! { + pub const TransactionByteFee: Balance = MILLICENTS; +} + impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter>; type WeightToFee = WeightToFee; /// Relay Chain `TransactionByteFee` / 10 - type LengthToFee = ConstantMultiplier>; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; } 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 ff8f46b9d11..71a789e3e25 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -15,8 +15,9 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; +use crate::common::rococo::currency::CENTS; use frame_support::{ match_types, parameter_types, traits::{ConstU32, EitherOfDiverse, Everything, Nothing}, @@ -24,8 +25,14 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; -use parachains_common::xcm_config::ConcreteAssetFromSystem; +use parachains_common::{ + xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + TREASURY_PALLET_ID, +}; use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use rococo_runtime_constants::system_parachain::SystemParachains; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -34,7 +41,7 @@ use xcm_builder::{ NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WithComputedOrigin, WithUniqueTopic, + WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, }; use xcm_executor::XcmExecutor; @@ -44,7 +51,7 @@ parameter_types! { pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const ExecutiveBody: BodyId = BodyId::Executive; - pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); } /// We allow root and the Relay Chain council to execute privileged collator selection operations. @@ -167,7 +174,12 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = ConstU32<8>; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = XcmFeesToAccount< + Self, + RelayOrOtherSystemParachains, + AccountId, + TreasuryAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -179,11 +191,14 @@ impl xcm_executor::Config for XcmConfig { /// Forms the basis for local origins sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; @@ -231,6 +246,20 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(RelayLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; @@ -243,7 +272,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { >; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index fe0f19c3063..86389425eb5 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -33,6 +33,7 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -50,6 +51,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, }; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -488,7 +490,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 029d5d10f98..a662a5e8066 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -42,6 +42,7 @@ polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", de 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} +polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } @@ -86,6 +87,7 @@ std = [ "parachain-info/std", "parachains-common/std", "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", @@ -118,6 +120,7 @@ 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", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 50c5a445c25..dcea349f3a0 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -23,6 +23,8 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::ParaId; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ @@ -511,7 +513,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; - type PriceForSiblingDelivery = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; } impl cumulus_pallet_dmp_queue::Config for Runtime { diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index faaef09b26e..f216af2aaee 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -96,7 +96,7 @@ pub struct ChannelInfo { pub trait GetChannelInfo { fn get_channel_status(id: ParaId) -> ChannelStatus; - fn get_channel_max(id: ParaId) -> Option; + fn get_channel_info(id: ParaId) -> Option; } /// Something that should be called when sending an upward message. diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 9ed1e664ac2..691a4599b2c 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -15,11 +15,12 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false} # Polkadot -polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } +polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false} - +pallet-xcm-benchmarks = { path = "../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false } # Cumulus cumulus-primitives-core = { path = "../core", default-features = false } @@ -30,7 +31,9 @@ std = [ "codec/std", "cumulus-primitives-core/std", "frame-support/std", + "pallet-xcm-benchmarks/std", "polkadot-runtime-common/std", + "polkadot-runtime-parachains/std", "sp-io/std", "sp-runtime/std", "sp-std/std", @@ -41,7 +44,9 @@ std = [ runtime-benchmarks = [ "frame-support/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 7d07bc329ed..c4ce6719485 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -28,29 +28,13 @@ use frame_support::{ }, weights::Weight, }; -use polkadot_runtime_common::xcm_sender::ConstantPrice; +use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery; use sp_runtime::{traits::Saturating, SaturatedConversion}; use sp_std::{marker::PhantomData, prelude::*}; use xcm::{latest::prelude::*, WrapVersion}; use xcm_builder::TakeRevenue; use xcm_executor::traits::{MatchesFungibles, TransactAsset, WeightTrader}; -pub trait PriceForParentDelivery { - fn price_for_parent_delivery(message: &Xcm<()>) -> MultiAssets; -} - -impl PriceForParentDelivery for () { - fn price_for_parent_delivery(_: &Xcm<()>) -> MultiAssets { - MultiAssets::new() - } -} - -impl> PriceForParentDelivery for ConstantPrice { - fn price_for_parent_delivery(_: &Xcm<()>) -> MultiAssets { - T::get() - } -} - /// Xcm router which recognises the `Parent` destination and handles it by sending the message into /// the given UMP `UpwardMessageSender` implementation. Thus this essentially adapts an /// `UpwardMessageSender` trait impl into a `SendXcm` trait impl. @@ -63,7 +47,7 @@ impl SendXcm for ParentAsUmp where T: UpwardMessageSender, W: WrapVersion, - P: PriceForParentDelivery, + P: PriceForMessageDelivery, { type Ticket = Vec; @@ -76,7 +60,7 @@ where if d.contains_parents_only(1) { // An upward message for the relay chain. let xcm = msg.take().ok_or(SendError::MissingArgument)?; - let price = P::price_for_parent_delivery(&xcm); + let price = P::price_for_delivery((), &xcm); let versioned_xcm = W::wrap_version(&d, xcm).map_err(|()| SendError::DestinationUnsupported)?; let data = versioned_xcm.encode(); @@ -280,7 +264,7 @@ pub struct XcmFeesTo32ByteAccount, - ReceiverAccount: frame_support::traits::Get>, + ReceiverAccount: Get>, > TakeRevenue for XcmFeesTo32ByteAccount { fn take_revenue(revenue: MultiAsset) { @@ -288,9 +272,7 @@ impl< let ok = FungiblesMutateAdapter::deposit_asset( &revenue, &(X1(AccountId32 { network: None, id: receiver.into() }).into()), - // We aren't able to track the XCM that initiated the fee deposit, so we create a - // fake message hash here - &XcmContext::with_message_id([0; 32]), + None, ) .is_ok(); @@ -542,3 +524,58 @@ mod tests { assert_eq!(trader.buy_weight(weight_to_buy, payment, &ctx), Err(XcmError::NotWithdrawable)); } } + +/// Implementation of `pallet_xcm_benchmarks::EnsureDelivery` which helps to ensure delivery to the +/// parent relay chain. Deposits existential deposit for origin (if needed). +/// Deposits estimated fee to the origin account (if needed). +/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded). +#[cfg(feature = "runtime-benchmarks")] +pub struct ToParentDeliveryHelper( + sp_std::marker::PhantomData<(XcmConfig, ExistentialDeposit, PriceForDelivery)>, +); + +#[cfg(feature = "runtime-benchmarks")] +impl< + XcmConfig: xcm_executor::Config, + ExistentialDeposit: Get>, + PriceForDelivery: PriceForMessageDelivery, + > pallet_xcm_benchmarks::EnsureDelivery + for ToParentDeliveryHelper +{ + fn ensure_successful_delivery( + origin_ref: &MultiLocation, + _dest: &MultiLocation, + fee_reason: xcm_executor::traits::FeeReason, + ) -> (Option, Option) { + use xcm::latest::{MAX_INSTRUCTIONS_TO_DECODE, MAX_ITEMS_IN_MULTIASSETS}; + use xcm_executor::{traits::FeeManager, FeesMode}; + + let mut fees_mode = None; + if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) { + // if not waived, we need to set up accounts for paying and receiving fees + + // mint ED to origin if needed + if let Some(ed) = ExistentialDeposit::get() { + XcmConfig::AssetTransactor::deposit_asset(&ed, &origin_ref, None).unwrap(); + } + + // overestimate delivery fee + let mut max_assets: Vec = Vec::new(); + for i in 0..MAX_ITEMS_IN_MULTIASSETS { + max_assets.push((GeneralIndex(i as u128), 100u128).into()); + } + let overestimated_xcm = + vec![WithdrawAsset(max_assets.into()); MAX_INSTRUCTIONS_TO_DECODE as usize].into(); + let overestimated_fees = PriceForDelivery::price_for_delivery((), &overestimated_xcm); + + // mint overestimated fee to origin + for fee in overestimated_fees.inner() { + XcmConfig::AssetTransactor::deposit_asset(&fee, &origin_ref, None).unwrap(); + } + + // expected worst case - direct withdraw + fees_mode = Some(FeesMode { jit_withdraw: true }); + } + (fees_mode, None) + } +} diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index caf73ae1e41..3da7814bec3 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1335,10 +1335,10 @@ pub struct TestContext { pub args: T, } -/// Struct that help with tests where either dispatchables or assertions need +/// Struct that helps with tests where either dispatchables or assertions need /// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`. -/// These arguments can be easily reused and shared between the assertions functions -/// and dispatchables functions, which are also stored in `Test`. +/// These arguments can be easily reused and shared between the assertion functions +/// and dispatchable functions, which are also stored in `Test`. /// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. /// `Destination` corresponds to the last chain where an effect of the intial execution is expected /// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index 5f77810f5c2..3247e841422 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -333,7 +333,7 @@ impl DmpMessageHandler for () { } /// The aggregate XCMP message format. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] pub enum XcmpMessageFormat { /// Encoded `VersionedXcm` messages, all concatenated. ConcatenatedVersionedXcm, diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 89312acc913..8af7f11f1d7 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -52,6 +52,9 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac slot-range-helper = { path = "slot_range_helper", default-features = false } xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false, optional = true } + +pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } [dev-dependencies] @@ -89,6 +92,7 @@ std = [ "pallet-transaction-payment/std", "pallet-treasury/std", "pallet-vesting/std", + "pallet-xcm-benchmarks/std", "parity-scale-codec/std", "primitives/std", "runtime-parachains/std", @@ -105,6 +109,7 @@ std = [ "sp-staking/std", "sp-std/std", "xcm-builder/std", + "xcm-executor/std", "xcm/std", ] runtime-benchmarks = [ @@ -123,11 +128,13 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index ff529143c50..4d31c92cdd3 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -31,38 +31,63 @@ use SendError::*; /// Simple value-bearing trait for determining/expressing the assets required to be paid for a /// messages to be delivered to a parachain. -pub trait PriceForParachainDelivery { +pub trait PriceForMessageDelivery { + /// Type used for charging different prices to different destinations + type Id; /// Return the assets required to deliver `message` to the given `para` destination. - fn price_for_parachain_delivery(para: ParaId, message: &Xcm<()>) -> MultiAssets; + fn price_for_delivery(id: Self::Id, message: &Xcm<()>) -> MultiAssets; } -impl PriceForParachainDelivery for () { - fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets { +impl PriceForMessageDelivery for () { + type Id = (); + + fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets { + MultiAssets::new() + } +} + +pub struct NoPriceForMessageDelivery(PhantomData); +impl PriceForMessageDelivery for NoPriceForMessageDelivery { + type Id = Id; + + fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets { MultiAssets::new() } } -/// Implementation of `PriceForParachainDelivery` which returns a fixed price. +/// Implementation of [`PriceForMessageDelivery`] which returns a fixed price. pub struct ConstantPrice(sp_std::marker::PhantomData); -impl> PriceForParachainDelivery for ConstantPrice { - fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets { +impl> PriceForMessageDelivery for ConstantPrice { + type Id = (); + + fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets { T::get() } } -/// Implementation of `PriceForParachainDelivery` which returns an exponentially increasing price. -/// The `A` type parameter is used to denote the asset ID that will be used for paying the delivery -/// fee. -/// +/// Implementation of [`PriceForMessageDelivery`] which returns an exponentially increasing price. /// The formula for the fee is based on the sum of a base fee plus a message length fee, multiplied -/// by a specified factor. In mathematical form, it is `F * (B + encoded_msg_len * M)`. +/// by a specified factor. In mathematical form: +/// +/// `F * (B + encoded_msg_len * M)` +/// +/// Thus, if F = 1 and M = 0, this type is equivalent to [`ConstantPrice`]. +/// +/// The type parameters are understood as follows: +/// +/// - `A`: Used to denote the asset ID that will be used for paying the delivery fee. +/// - `B`: The base fee to pay for message delivery. +/// - `M`: The fee to pay for each and every byte of the message after encoding it. +/// - `F`: A fee factor multiplier. It can be understood as the exponent term in the formula. pub struct ExponentialPrice(sp_std::marker::PhantomData<(A, B, M, F)>); -impl, B: Get, M: Get, F: FeeTracker> PriceForParachainDelivery +impl, B: Get, M: Get, F: FeeTracker> PriceForMessageDelivery for ExponentialPrice { - fn price_for_parachain_delivery(para: ParaId, msg: &Xcm<()>) -> MultiAssets { + type Id = F::Id; + + fn price_for_delivery(id: Self::Id, msg: &Xcm<()>) -> MultiAssets { let msg_fee = (msg.encoded_size() as u128).saturating_mul(M::get()); let fee_sum = B::get().saturating_add(msg_fee); - let amount = F::get_fee_factor(para).saturating_mul_int(fee_sum); + let amount = F::get_fee_factor(id).saturating_mul_int(fee_sum); (A::get(), amount).into() } } @@ -70,8 +95,10 @@ impl, B: Get, M: Get, F: FeeTracker> PriceForParacha /// XCM sender for relay chain. It only sends downward message. pub struct ChildParachainRouter(PhantomData<(T, W, P)>); -impl - SendXcm for ChildParachainRouter +impl SendXcm + for ChildParachainRouter +where + P: PriceForMessageDelivery, { type Ticket = (HostConfiguration>, ParaId, Vec); @@ -91,7 +118,7 @@ impl>::config(); let para = id.into(); - let price = P::price_for_parachain_delivery(para, &xcm); + let price = P::price_for_delivery(para, &xcm); let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode(); >::can_queue_downward_message(&config, ¶, &blob) .map_err(Into::::into)?; @@ -109,6 +136,94 @@ impl( + sp_std::marker::PhantomData<( + XcmConfig, + ExistentialDeposit, + PriceForDelivery, + ParaId, + ToParaIdHelper, + )>, +); + +#[cfg(feature = "runtime-benchmarks")] +impl< + XcmConfig: xcm_executor::Config, + ExistentialDeposit: Get>, + PriceForDelivery: PriceForMessageDelivery, + Parachain: Get, + ToParachainHelper: EnsureForParachain, + > pallet_xcm_benchmarks::EnsureDelivery + for ToParachainDeliveryHelper< + XcmConfig, + ExistentialDeposit, + PriceForDelivery, + Parachain, + ToParachainHelper, + > +{ + fn ensure_successful_delivery( + origin_ref: &MultiLocation, + _dest: &MultiLocation, + fee_reason: xcm_executor::traits::FeeReason, + ) -> (Option, Option) { + use xcm_executor::{ + traits::{FeeManager, TransactAsset}, + FeesMode, + }; + + let mut fees_mode = None; + if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) { + // if not waived, we need to set up accounts for paying and receiving fees + + // mint ED to origin if needed + if let Some(ed) = ExistentialDeposit::get() { + XcmConfig::AssetTransactor::deposit_asset(&ed, &origin_ref, None).unwrap(); + } + + // overestimate delivery fee + let overestimated_xcm = vec![ClearOrigin; 128].into(); + let overestimated_fees = + PriceForDelivery::price_for_delivery(Parachain::get(), &overestimated_xcm); + + // mint overestimated fee to origin + for fee in overestimated_fees.inner() { + XcmConfig::AssetTransactor::deposit_asset(&fee, &origin_ref, None).unwrap(); + } + + // allow more initialization for target parachain + ToParachainHelper::ensure(Parachain::get()); + + // expected worst case - direct withdraw + fees_mode = Some(FeesMode { jit_withdraw: true }); + } + (fees_mode, None) + } +} + +/// Ensure more initialization for `ParaId`. (e.g. open HRMP channels, ...) +#[cfg(feature = "runtime-benchmarks")] +pub trait EnsureForParachain { + fn ensure(para_id: ParaId); +} +#[cfg(feature = "runtime-benchmarks")] +impl EnsureForParachain for () { + fn ensure(_: ParaId) { + // doing nothing + } +} + #[cfg(test)] mod tests { use super::*; @@ -124,7 +239,17 @@ mod tests { struct TestFeeTracker; impl FeeTracker for TestFeeTracker { - fn get_fee_factor(_: ParaId) -> FixedU128 { + type Id = ParaId; + + fn get_fee_factor(_: Self::Id) -> FixedU128 { + FixedU128::from_rational(101, 100) + } + + fn increase_fee_factor(_: Self::Id, _: FixedU128) -> FixedU128 { + FixedU128::from_rational(101, 100) + } + + fn decrease_fee_factor(_: Self::Id) -> FixedU128 { FixedU128::from_rational(101, 100) } } @@ -142,21 +267,21 @@ mod tests { // message_length = 1 let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + m); assert_eq!( - TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![])), + TestExponentialPrice::price_for_delivery(id, &Xcm(vec![])), (FeeAssetId::get(), result).into() ); // message size = 2 let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (2 * m)); assert_eq!( - TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![ClearOrigin])), + TestExponentialPrice::price_for_delivery(id, &Xcm(vec![ClearOrigin])), (FeeAssetId::get(), result).into() ); // message size = 4 let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (4 * m)); assert_eq!( - TestExponentialPrice::price_for_parachain_delivery( + TestExponentialPrice::price_for_delivery( id, &Xcm(vec![SetAppendix(Xcm(vec![ClearOrigin]))]) ), diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index bc7491a2c61..15147e9210e 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -17,12 +17,12 @@ //! To prevent Out of Memory errors on the `DownwardMessageQueue`, an //! exponential fee factor (`DeliveryFeeFactor`) is set. The fee factor //! increments exponentially after the number of messages in the -//! `DownwardMessageQueue` pass a threshold. This threshold is set as: +//! `DownwardMessageQueue` passes a threshold. This threshold is set as: //! //! ```ignore //! // Maximum max sized messages that can be send to //! // the DownwardMessageQueue before it runs out of memory -//! max_messsages = MAX_POSSIBLE_ALLOCATION / max_downward_message_size +//! max_messages = MAX_POSSIBLE_ALLOCATION / max_downward_message_size //! threshold = max_messages / THRESHOLD_FACTOR //! ``` //! Based on the THRESHOLD_FACTOR, the threshold is set as a fraction of the @@ -144,7 +144,7 @@ pub mod pallet { FixedU128::from_u32(1) } - /// The number to multiply the base delivery fee by. + /// The factor to multiply the base delivery fee by. #[pallet::storage] pub(crate) type DeliveryFeeFactor = StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>; @@ -243,10 +243,9 @@ impl Pallet { let threshold = Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR); if q_len > (threshold as usize) { - let message_size_factor = - FixedU128::from_u32(serialized_len.saturating_div(1024) as u32) - .saturating_mul(MESSAGE_SIZE_FEE_BASE); - Self::increment_fee_factor(para, message_size_factor); + let message_size_factor = FixedU128::from((serialized_len / 1024) as u128) + .saturating_mul(MESSAGE_SIZE_FEE_BASE); + Self::increase_fee_factor(para, message_size_factor); } Ok(()) @@ -304,7 +303,7 @@ impl Pallet { let threshold = Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR); if q_len <= (threshold as usize) { - Self::decrement_fee_factor(para); + Self::decrease_fee_factor(para); } T::DbWeight::get().reads_writes(1, 1) } @@ -337,32 +336,26 @@ impl Pallet { ) -> Vec>> { DownwardMessageQueues::::get(&recipient) } +} - /// Raise the delivery fee factor by a multiplicative factor and stores the resulting value. - /// - /// Returns the new delivery fee factor after the increment. - pub(crate) fn increment_fee_factor(para: ParaId, message_size_factor: FixedU128) -> FixedU128 { - >::mutate(para, |f| { - *f = f.saturating_mul(EXPONENTIAL_FEE_BASE + message_size_factor); +impl FeeTracker for Pallet { + type Id = ParaId; + + fn get_fee_factor(id: Self::Id) -> FixedU128 { + DeliveryFeeFactor::::get(id) + } + + fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128 { + >::mutate(id, |f| { + *f = f.saturating_mul(EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor)); *f }) } - /// Reduce the delivery fee factor by a multiplicative factor and stores the resulting value. - /// - /// Does not reduce the fee factor below the initial value, which is currently set as 1. - /// - /// Returns the new delivery fee factor after the decrement. - pub(crate) fn decrement_fee_factor(para: ParaId) -> FixedU128 { - >::mutate(para, |f| { + fn decrease_fee_factor(id: Self::Id) -> FixedU128 { + >::mutate(id, |f| { *f = InitialFactor::get().max(*f / EXPONENTIAL_FEE_BASE); *f }) } } - -impl FeeTracker for Pallet { - fn get_fee_factor(para: ParaId) -> FixedU128 { - DeliveryFeeFactor::::get(para) - } -} diff --git a/polkadot/runtime/parachains/src/dmp/tests.rs b/polkadot/runtime/parachains/src/dmp/tests.rs index a65984840da..f9197b156a1 100644 --- a/polkadot/runtime/parachains/src/dmp/tests.rs +++ b/polkadot/runtime/parachains/src/dmp/tests.rs @@ -233,7 +233,7 @@ fn verify_dmq_mqc_head_is_externally_accessible() { } #[test] -fn verify_fee_increment_and_decrement() { +fn verify_fee_increase_and_decrease() { let a = ParaId::from(123); let mut genesis = default_genesis_config(); genesis.configuration.config.max_downward_message_size = 16777216; diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index e0ace86d379..2509edbee3c 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -59,7 +59,21 @@ use sp_runtime::{DispatchResult, FixedU128}; /// Trait for tracking message delivery fees on a transport protocol. pub trait FeeTracker { - fn get_fee_factor(para: ParaId) -> FixedU128; + /// Type used for assigning different fee factors to different destinations + type Id; + /// Returns the evolving exponential fee factor which will be used to calculate the delivery + /// fees. + fn get_fee_factor(id: Self::Id) -> FixedU128; + /// Increases the delivery fee factor by a factor based on message size and records the result. + /// + /// Returns the new delivery fee factor after the increase. + fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128; + /// Decreases the delivery fee factor by a constant factor and records the result. + /// + /// Does not reduce the fee factor below the initial value, which is currently set as 1. + /// + /// Returns the new delivery fee factor after the decrease. + fn decrease_fee_factor(id: Self::Id) -> FixedU128; } /// Schedule a para to be initialized at the start of the next session with the given genesis data. diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index a0ef1edf08d..f99dbd12336 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -16,6 +16,8 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime", default-featur sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } + [features] default = [ "std" ] std = [ @@ -25,4 +27,5 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-weights/std", + "xcm/std", ] diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 2200f7ddefe..19225c68151 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -100,6 +100,26 @@ pub mod fee { } } +/// System Parachains. +pub mod system_parachain { + use xcm::latest::prelude::*; + + /// Network's Asset Hub parachain ID. + pub const ASSET_HUB_ID: u32 = 1000; + /// Contracts parachain ID. + pub const CONTRACTS_ID: u32 = 1002; + /// Encointer parachain ID. + pub const ENCOINTER_ID: u32 = 1003; + /// BridgeHub parachain ID. + pub const BRIDGE_HUB_ID: u32 = 1013; + + frame_support::match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | CONTRACTS_ID | ENCOINTER_ID | BRIDGE_HUB_ID)) } + }; + } +} + #[cfg(test)] mod tests { use super::{ diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 3c08b9b2f94..f4264ea3533 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -2072,14 +2072,29 @@ sp_api::impl_runtime_apis! { use sp_storage::TrackedStorageKey; use xcm::latest::prelude::*; use xcm_config::{ - LocalCheckAccount, LocationConverter, AssetHub, TokenLocation, XcmConfig, + AssetHub, LocalCheckAccount, LocationConverter, TokenLocation, XcmConfig, }; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + pub ToParachain: ParaId = rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(); + } + impl frame_system_benchmarking::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {} impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = XcmConfig; type AccountIdConverter = LocationConverter; + type DeliveryHelper = runtime_common::xcm_sender::ToParachainDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForChildParachainDelivery, + ToParachain, + (), + >; fn valid_destination() -> Result { Ok(AssetHub::get()) } @@ -2116,6 +2131,7 @@ sp_api::impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index a766e2179ea..fb1653c549e 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -18,7 +18,7 @@ use super::{ parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, Fellows, ParaId, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, + RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, Treasury, WeightToFee, XcmPallet, }; use crate::governance::StakingAdmin; @@ -29,7 +29,7 @@ use frame_support::{ weights::Weight, }; use frame_system::EnsureRoot; -use rococo_runtime_constants::currency::CENTS; +use rococo_runtime_constants::{currency::CENTS, system_parachain::*}; use runtime_common::{ xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, @@ -43,7 +43,7 @@ use xcm_builder::{ DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, }; use xcm_executor::XcmExecutor; @@ -53,6 +53,7 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); + pub TreasuryAccount: Option = Some(Treasury::account_id()); } pub type LocationConverter = ( @@ -100,22 +101,22 @@ parameter_types! { pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); } +pub type PriceForChildParachainDelivery = + ExponentialPrice; + /// 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<( +pub type XcmRouter = WithUniqueTopic< // Only one router so far - use DMP to communicate with child parachains. - ChildParachainRouter< - Runtime, - XcmPallet, - ExponentialPrice, - >, -)>; + ChildParachainRouter, +>; parameter_types! { pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); - 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 AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location(); + pub const Contracts: MultiLocation = Parachain(CONTRACTS_ID).into_location(); + pub const Encointer: MultiLocation = Parachain(ENCOINTER_ID).into_location(); + pub const BridgeHub: MultiLocation = Parachain(BRIDGE_HUB_ID).into_location(); pub const Tick: MultiLocation = Parachain(100).into_location(); pub const Trick: MultiLocation = Parachain(110).into_location(); pub const Track: MultiLocation = Parachain(120).into_location(); @@ -125,6 +126,7 @@ parameter_types! { 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 RocForBridgeHub: (MultiAssetFilter, MultiLocation) = (Roc::get(), BridgeHub::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -135,6 +137,7 @@ pub type TrustedTeleporters = ( xcm_builder::Case, xcm_builder::Case, xcm_builder::Case, + xcm_builder::Case, ); match_types! { @@ -188,7 +191,7 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); + type FeeManager = XcmFeesToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -206,7 +209,7 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); + pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); } /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index 2113bbae66a..400658b1386 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -60,7 +60,11 @@ pub type Barrier = AllowUnpaidExecutionFrom; pub struct DummyAssetTransactor; impl TransactAsset for DummyAssetTransactor { - fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult { + fn deposit_asset( + _what: &MultiAsset, + _who: &MultiLocation, + _context: Option<&XcmContext>, + ) -> XcmResult { Ok(()) } diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index ea9ff3499f9..2243210975b 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -16,6 +16,8 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime", default-featur sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } + [features] default = [ "std" ] std = [ @@ -25,4 +27,5 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-weights/std", + "xcm/std", ] diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index 0dd64d092c3..4851303b589 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -96,6 +96,24 @@ pub mod fee { } } +/// System Parachains. +pub mod system_parachain { + use xcm::latest::prelude::*; + + /// Network's Asset Hub parachain ID. + pub const ASSET_HUB_ID: u32 = 1000; + /// Collectives parachain ID. + pub const COLLECTIVES_ID: u32 = 1001; + /// BridgeHub parachain ID. + pub const BRIDGE_HUB_ID: u32 = 1002; + + frame_support::match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | COLLECTIVES_ID | BRIDGE_HUB_ID ))} + }; + } +} + /// XCM protocol related constants. pub mod xcm { /// Pluralistic bodies existing within the consensus. @@ -108,14 +126,6 @@ pub mod xcm { } } -/// 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/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 0e93b3449fe..a7ddfc52ce6 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2182,9 +2182,24 @@ sp_api::impl_runtime_apis! { }; use xcm_config::{AssetHub, TokenLocation}; + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + pub ToParachain: ParaId = westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(); + } + impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationConverter; + type DeliveryHelper = runtime_common::xcm_sender::ToParachainDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForChildParachainDelivery, + ToParachain, + (), + >; fn valid_destination() -> Result { Ok(AssetHub::get()) } @@ -2221,6 +2236,7 @@ sp_api::impl_runtime_apis! { } impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { 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 87e63fbe310..9939f16aa29 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,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! 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 @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 24_642_000 picoseconds. - Weight::from_parts(24_973_000, 3593) + // Minimum execution time: 24_815_000 picoseconds. + Weight::from_parts(25_098_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: 50_882_000 picoseconds. - Weight::from_parts(51_516_000, 6196) + // Minimum execution time: 51_268_000 picoseconds. + Weight::from_parts(51_857_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -85,8 +85,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `210` // Estimated: `6196` - // Minimum execution time: 73_923_000 picoseconds. - Weight::from_parts(75_454_000, 6196) + // Minimum execution time: 74_113_000 picoseconds. + Weight::from_parts(74_721_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -111,8 +111,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 29_035_000 picoseconds. - Weight::from_parts(30_086_000, 3574) + // Minimum execution time: 28_919_000 picoseconds. + Weight::from_parts(29_703_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: 22_094_000 picoseconds. - Weight::from_parts(22_560_000, 3593) + // Minimum execution time: 21_685_000 picoseconds. + Weight::from_parts(22_528_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: 24_771_000 picoseconds. - Weight::from_parts(25_280_000, 3593) + // Minimum execution time: 25_192_000 picoseconds. + Weight::from_parts(25_445_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -152,8 +152,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3593` - // Minimum execution time: 49_777_000 picoseconds. - Weight::from_parts(50_833_000, 3593) + // Minimum execution time: 49_349_000 picoseconds. + Weight::from_parts(50_476_000, 3593) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -171,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3593` - // Minimum execution time: 51_425_000 picoseconds. - Weight::from_parts(52_213_000, 3593) + // Minimum execution time: 51_386_000 picoseconds. + Weight::from_parts(52_141_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 f025e5f1f3e..dd6a29885ad 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -19,7 +19,7 @@ use super::{ parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin, GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, - TransactionByteFee, WeightToFee, XcmPallet, + TransactionByteFee, Treasury, WeightToFee, XcmPallet, }; use frame_support::{ @@ -44,6 +44,7 @@ use xcm_builder::{ DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeesToAccount, }; use xcm_executor::XcmExecutor; @@ -53,6 +54,7 @@ parameter_types! { pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get())); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); + pub TreasuryAccount: Option = Some(Treasury::account_id()); /// 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. @@ -95,29 +97,38 @@ type LocalOriginConverter = ( XcmPassthrough, ); +pub type PriceForChildParachainDelivery = + ExponentialPrice; + /// 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<( +pub type XcmRouter = WithUniqueTopic< // Only one router so far - use DMP to communicate with child parachains. - ChildParachainRouter< - Runtime, - XcmPallet, - ExponentialPrice, - >, -)>; + ChildParachainRouter, +>; parameter_types! { - pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::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 BridgeHub: MultiLocation = Parachain(BRIDGE_HUB_ID).into_location(); + pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); + pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get()); pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get()); + pub const WndForBridgeHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), BridgeHub::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } -pub type TrustedTeleporters = - (xcm_builder::Case, xcm_builder::Case); +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); +} + +pub type TrustedTeleporters = ( + xcm_builder::Case, + xcm_builder::Case, + xcm_builder::Case, +); match_types! { pub type OnlyParachains: impl Contains = { @@ -174,7 +185,7 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); + type FeeManager = XcmFeesToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -191,11 +202,6 @@ parameter_types! { 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; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 760fa33b693..d32eb8d4a52 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use crate::{account_and_location, new_executor, AssetTransactorOf, XcmCallOf}; +use crate::{account_and_location, new_executor, AssetTransactorOf, EnsureDelivery, XcmCallOf}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError, BenchmarkResult}; use frame_support::{ pallet_prelude::Get, @@ -24,8 +24,8 @@ use frame_support::{ }; use sp_runtime::traits::{Bounded, Zero}; use sp_std::{prelude::*, vec}; -use xcm::latest::prelude::*; -use xcm_executor::traits::{ConvertLocation, TransactAsset}; +use xcm::latest::{prelude::*, MAX_ITEMS_IN_MULTIASSETS}; +use xcm_executor::traits::{ConvertLocation, FeeReason, TransactAsset}; benchmarks_instance_pallet! { where_clause { where @@ -45,15 +45,7 @@ benchmarks_instance_pallet! { let worst_case_holding = T::worst_case_holding(0); let asset = T::get_multi_asset(); - >::deposit_asset( - &asset, - &sender_location, - &XcmContext { - origin: Some(sender_location.clone()), - message_id: [0; 32], - topic: None, - }, - ).unwrap(); + >::deposit_asset(&asset, &sender_location, None).unwrap(); // check the assets of origin. assert!(!T::TransactAsset::balance(&sender_account).is_zero()); @@ -78,15 +70,7 @@ benchmarks_instance_pallet! { let dest_location = T::valid_destination()?; let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); - >::deposit_asset( - &asset, - &sender_location, - &XcmContext { - origin: Some(sender_location.clone()), - message_id: [0; 32], - topic: None, - }, - ).unwrap(); + >::deposit_asset(&asset, &sender_location, None).unwrap(); assert!(T::TransactAsset::balance(&dest_account).is_zero()); let mut executor = new_executor::(sender_location); @@ -104,20 +88,27 @@ benchmarks_instance_pallet! { let dest_location = T::valid_destination()?; let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); - let asset = T::get_multi_asset(); - >::deposit_asset( - &asset, + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( &sender_location, - &XcmContext { - origin: Some(sender_location.clone()), - message_id: [0; 32], - topic: None, - }, - ).unwrap(); + &dest_location, + FeeReason::TransferReserveAsset + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + let asset = T::get_multi_asset(); + >::deposit_asset(&asset, &sender_location, None).unwrap(); + assert!(T::TransactAsset::balance(&sender_account) > sender_account_balance_before); let assets: MultiAssets = vec![ asset ].into(); assert!(T::TransactAsset::balance(&dest_account).is_zero()); let mut executor = new_executor::(sender_location); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } + let instruction = Instruction::TransferReserveAsset { assets, dest: dest_location, @@ -127,7 +118,7 @@ benchmarks_instance_pallet! { }: { executor.bench_process(xcm)?; } verify { - assert!(T::TransactAsset::balance(&sender_account).is_zero()); + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); assert!(!T::TransactAsset::balance(&dest_account).is_zero()); // TODO: Check sender queue is not empty. #4426 } @@ -150,16 +141,33 @@ benchmarks_instance_pallet! { } initiate_reserve_withdraw { + let (sender_account, sender_location) = account_and_location::(1); let holding = T::worst_case_holding(1); - let assets_filter = MultiAssetFilter::Definite(holding.clone()); + let assets_filter = MultiAssetFilter::Definite(holding.clone().into_inner().into_iter().take(MAX_ITEMS_IN_MULTIASSETS).collect::>().into()); let reserve = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; - let mut executor = new_executor::(Default::default()); + + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &reserve, + FeeReason::InitiateReserveWithdraw, + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + let mut executor = new_executor::(sender_location); executor.set_holding(holding.into()); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let instruction = Instruction::InitiateReserveWithdraw { assets: assets_filter, reserve, xcm: Xcm(vec![]) }; let xcm = Xcm(vec![instruction]); }: { executor.bench_process(xcm)?; } verify { + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // The execute completing successfully is as good as we can check. // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index f5759afc064..9adc706fc18 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -19,7 +19,7 @@ use crate::{fungible as xcm_balances_benchmark, mock::*}; use frame_benchmarking::BenchmarkError; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, Everything, Nothing}, weights::Weight, }; @@ -75,20 +75,10 @@ parameter_types! { pub const ExistentialDeposit: u64 = 7; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; - type WeightInfo = (); - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; } parameter_types! { @@ -157,6 +147,7 @@ impl xcm_executor::Config for XcmConfig { impl crate::Config for Test { type XcmConfig = XcmConfig; type AccountIdConverter = AccountIdConverter; + type DeliveryHelper = (); fn valid_destination() -> Result { let valid_destination: MultiLocation = X1(AccountId32 { network: None, id: [0u8; 32] }).into(); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index 4583ecdba89..c6b76e0ffad 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -15,27 +15,45 @@ // along with Polkadot. If not, see . use super::*; -use crate::{new_executor, XcmCallOf}; +use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf}; use codec::Encode; use frame_benchmarking::{benchmarks, BenchmarkError}; -use frame_support::dispatch::GetDispatchInfo; +use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect}; use sp_std::vec; use xcm::{ latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight}, DoubleEncoded, }; -use xcm_executor::{ExecutorError, FeesMode}; +use xcm_executor::{ + traits::{ConvertLocation, FeeReason}, + ExecutorError, FeesMode, +}; benchmarks! { report_holding { + let (sender_account, sender_location) = account_and_location::(1); let holding = T::worst_case_holding(0); + let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; - let mut executor = new_executor::(Default::default()); + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + let mut executor = new_executor::(sender_location); executor.set_holding(holding.clone().into()); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let instruction = Instruction::>::ReportHolding { response_info: QueryResponseInfo { - destination: T::valid_destination()?, + destination, query_id: Default::default(), max_weight: Weight::MAX, }, @@ -44,11 +62,11 @@ benchmarks! { }; let xcm = Xcm(vec![instruction]); - } : { executor.bench_process(xcm)?; } verify { - // The completion of execution above is enough to validate this is completed. + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); } // This benchmark does not use any additional orders or instructions. This should be managed @@ -182,11 +200,26 @@ benchmarks! { } report_error { - let mut executor = new_executor::(Default::default()); - executor.set_error(Some((0u32, XcmError::Unimplemented))); + let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); - let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let max_weight = Default::default(); + let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; + + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + let mut executor = new_executor::(sender_location); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } + executor.set_error(Some((0u32, XcmError::Unimplemented))); let instruction = Instruction::ReportError(QueryResponseInfo { query_id, destination, max_weight @@ -195,7 +228,8 @@ benchmarks! { }: { executor.bench_process(xcm)?; } verify { - // the execution succeeding is all we need to verify this xcm was successful + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); } claim_asset { @@ -360,10 +394,24 @@ benchmarks! { } query_pallet { + let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let max_weight = Default::default(); - let mut executor = new_executor::(Default::default()); + + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::QueryPallet, + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + let mut executor = new_executor::(sender_location); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let instruction = Instruction::QueryPallet { module_name: b"frame_system".to_vec(), @@ -373,6 +421,8 @@ benchmarks! { }: { executor.bench_process(xcm)?; } verify { + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } @@ -394,11 +444,25 @@ benchmarks! { } report_transact_status { + let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let max_weight = Default::default(); - let mut executor = new_executor::(Default::default()); + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + let mut executor = new_executor::(sender_location); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } executor.set_transact_status(b"MyError".to_vec().into()); let instruction = Instruction::ReportTransactStatus(QueryResponseInfo { @@ -410,6 +474,8 @@ benchmarks! { }: { executor.bench_process(xcm)?; } verify { + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } @@ -491,14 +557,30 @@ benchmarks! { let inner_xcm = Xcm(vec![ClearOrigin; x as usize]); // Get `origin`, `network` and `destination` from configured runtime. let (origin, network, destination) = T::export_message_origin_and_destination()?; + + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &origin, + &destination.into(), + FeeReason::Export(network), + ); + let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap(); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + let mut executor = new_executor::(origin); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let xcm = Xcm(vec![ExportMessage { network, destination, xcm: inner_xcm, }]); }: { executor.bench_process(xcm)?; } verify { - // The execute completing successfully is as good as we can check. + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } @@ -517,14 +599,30 @@ benchmarks! { lock_asset { let (unlocker, owner, asset) = T::unlockable_asset()?; + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &owner, + &unlocker, + FeeReason::LockAsset, + ); + let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap(); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + let mut executor = new_executor::(owner); executor.set_holding(asset.clone().into()); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let instruction = Instruction::LockAsset { asset, unlocker }; let xcm = Xcm(vec![instruction]); }: { executor.bench_process(xcm)?; } verify { + // Check delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } @@ -595,13 +693,29 @@ benchmarks! { .enact() .map_err(|_| BenchmarkError::Skip)?; + let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( + &owner, + &locker, + FeeReason::RequestUnlock, + ); + let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap(); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + // ... then request for an unlock with the RequestUnlock instruction. let mut executor = new_executor::(owner); + if let Some(expected_fees_mode) = expected_fees_mode { + executor.set_fees_mode(expected_fees_mode); + } + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + executor.set_holding(expected_assets_in_holding.into()); + } let instruction = Instruction::RequestUnlock { asset, locker }; let xcm = Xcm(vec![instruction]); }: { executor.bench_process(xcm)?; } verify { + // Check we charged the delivery fees + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index 1b244f316de..710ff0d8019 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -19,7 +19,7 @@ use crate::{generic, mock::*, *}; use codec::Decode; use frame_support::{ - match_types, parameter_types, + derive_impl, match_types, parameter_types, traits::{Everything, OriginTrait}, weights::Weight, }; @@ -40,6 +40,7 @@ frame_support::construct_runtime!( pub enum Test { System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, XcmGenericBenchmarks: generic::{Pallet}, } ); @@ -79,7 +80,11 @@ impl frame_system::Config for Test { /// The benchmarks in this pallet should never need an asset transactor to begin with. pub struct NoAssetTransactor; impl xcm_executor::traits::TransactAsset for NoAssetTransactor { - fn deposit_asset(_: &MultiAsset, _: &MultiLocation, _: &XcmContext) -> Result<(), XcmError> { + fn deposit_asset( + _: &MultiAsset, + _: &MultiLocation, + _: Option<&XcmContext>, + ) -> Result<(), XcmError> { unreachable!(); } @@ -133,9 +138,20 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Aliasers; } +parameter_types! { + pub const ExistentialDeposit: u64 = 7; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Test { + type ReserveIdentifier = [u8; 8]; + type AccountStore = System; +} + impl crate::Config for Test { type XcmConfig = XcmConfig; type AccountIdConverter = AccountIdConverter; + type DeliveryHelper = (); fn valid_destination() -> Result { let valid_destination: MultiLocation = Junction::AccountId32 { network: None, id: [0u8; 32] }.into(); @@ -151,6 +167,7 @@ impl crate::Config for Test { } impl generic::Config for Test { + type TransactAsset = Balances; type RuntimeCall = RuntimeCall; fn worst_case_response() -> (u64, Response) { @@ -183,7 +200,7 @@ impl generic::Config for Test { fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> { let assets: MultiAsset = (Concrete(Here.into()), 100).into(); - Ok((Default::default(), Default::default(), assets)) + Ok((Default::default(), account_id_junction::(1).into(), assets)) } fn export_message_origin_and_destination( diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs index f207c238a39..cbdfa8d0112 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs @@ -38,6 +38,11 @@ pub mod pallet { + From> + Encode; + /// The type of `fungible` that is being used under the hood. + /// + /// This is useful for testing and checking. + type TransactAsset: frame_support::traits::fungible::Mutate; + /// The response which causes the most runtime weight. fn worst_case_response() -> (u64, Response); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index c6a96343595..3bf4aea1b25 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -22,7 +22,10 @@ use codec::Encode; use frame_benchmarking::{account, BenchmarkError}; use sp_std::prelude::*; use xcm::latest::prelude::*; -use xcm_executor::{traits::ConvertLocation, Config as XcmConfig}; +use xcm_executor::{ + traits::{ConvertLocation, FeeReason}, + Config as XcmConfig, FeesMode, +}; pub mod fungible; pub mod generic; @@ -41,6 +44,9 @@ pub trait Config: frame_system::Config { /// A converter between a multi-location to a sovereign account. type AccountIdConverter: ConvertLocation; + /// Helper that ensures successful delivery for XCM instructions which need `SendXcm`. + type DeliveryHelper: EnsureDelivery; + /// Does any necessary setup to create a valid destination for XCM messages. /// Returns that destination's multi-location to be used in benchmarks. fn valid_destination() -> Result; @@ -108,3 +114,29 @@ pub fn account_and_location(index: u32) -> (T::AccountId, MultiLocati (account, location) } + +/// Trait for a type which ensures all requirements for successful delivery with XCM transport +/// layers. +pub trait EnsureDelivery { + /// Prepare all requirements for successful `XcmSender: SendXcm` passing (accounts, balances, + /// channels ...). Returns: + /// - possible `FeesMode` which is expected to be set to executor + /// - possible `MultiAssets` which are expected to be subsume to the Holding Register + fn ensure_successful_delivery( + origin_ref: &MultiLocation, + dest: &MultiLocation, + fee_reason: FeeReason, + ) -> (Option, Option); +} + +/// `()` implementation does nothing which means no special requirements for environment. +impl EnsureDelivery for () { + fn ensure_successful_delivery( + _origin_ref: &MultiLocation, + _dest: &MultiLocation, + _fee_reason: FeeReason, + ) -> (Option, Option) { + // doing nothing + (None, None) + } +} diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b09bcb80ed6..a85fe0fa2af 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -16,8 +16,8 @@ use codec::Encode; use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstU32, Everything, Nothing}, + construct_runtime, match_types, parameter_types, + traits::{ConstU32, Everything, EverythingBut, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -25,14 +25,16 @@ use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::origin; use sp_core::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; -pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; +pub use sp_std::{ + cell::RefCell, collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, +}; use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, + SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, }; use xcm_executor::XcmExecutor; @@ -154,7 +156,7 @@ pub(crate) fn take_sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> { r }) } -/// Sender that never returns error, always sends +/// Sender that never returns error. pub struct TestSendXcm; impl SendXcm for TestSendXcm { type Ticket = (MultiLocation, Xcm<()>); @@ -193,6 +195,38 @@ impl SendXcm for TestSendXcmErrX8 { } } +parameter_types! { + pub Para3000: u32 = 3000; + pub Para3000Location: MultiLocation = Parachain(Para3000::get()).into(); + pub Para3000PaymentAmount: u128 = 1; + pub Para3000PaymentMultiAssets: MultiAssets = MultiAssets::from(MultiAsset::from((Here, Para3000PaymentAmount::get()))); +} +/// Sender only sends to `Parachain(3000)` destination requiring payment. +pub struct TestPaidForPara3000SendXcm; +impl SendXcm for TestPaidForPara3000SendXcm { + type Ticket = (MultiLocation, Xcm<()>); + fn validate( + dest: &mut Option, + msg: &mut Option>, + ) -> SendResult<(MultiLocation, Xcm<()>)> { + if let Some(dest) = dest.as_ref() { + if !dest.eq(&Para3000Location::get()) { + return Err(SendError::NotApplicable) + } + } else { + return Err(SendError::NotApplicable) + } + + let pair = (dest.take().unwrap(), msg.take().unwrap()); + Ok((pair, Para3000PaymentMultiAssets::get())) + } + fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result { + let hash = fake_message_hash(&pair.1); + SENT_XCM.with(|q| q.borrow_mut().push(pair)); + Ok(hash) + } +} + parameter_types! { pub const BlockHashCount: u64 = 250; } @@ -271,6 +305,14 @@ parameter_types! { pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]); +} + +pub const XCM_FEES_NOT_WAIVED_USER_ACCOUNT: [u8; 32] = [37u8; 32]; +match_types! { + pub type XcmFeesNotWaivedLocations: impl Contains = { + MultiLocation { parents: 0, interior: X1(Junction::AccountId32 {network: None, id: XCM_FEES_NOT_WAIVED_USER_ACCOUNT})} + }; } pub type Barrier = ( @@ -283,7 +325,7 @@ pub type Barrier = ( pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = TestSendXcm; + type XcmSender = (TestPaidForPara3000SendXcm, TestSendXcm); type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); @@ -300,7 +342,12 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); + type FeeManager = XcmFeesToAccount< + Self, + EverythingBut, + AccountId, + XcmFeesTargetAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -322,7 +369,7 @@ parameter_types! { impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = (TestSendXcmErrX8, TestSendXcm); + type XcmRouter = (TestSendXcmErrX8, TestPaidForPara3000SendXcm, TestSendXcm); type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 5d8aee8d665..d267eece2c0 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -522,6 +522,74 @@ fn reserve_transfer_assets_works() { }); } +/// Test `reserve_transfer_assets_with_paid_router_works` +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +/// Verifies that XCM router fees (`SendXcm::validate` -> `MultiAssets`) are withdrawn from correct +/// user account and deposited to a correct target account (`XcmFeesTargetAccount`). +#[test] +fn reserve_transfer_assets_with_paid_router_works() { + let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT); + let paid_para_id = Para3000::get(); + let balances = vec![ + (user_account.clone(), INITIAL_BALANCE), + (ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE), + (XcmFeesTargetAccount::get(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let xcm_router_fee_amount = Para3000PaymentAmount::get(); + let weight = BaseXcmWeight::get() * 2; + let dest: MultiLocation = + Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); + assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); + assert_ok!(XcmPallet::reserve_transfer_assets( + RuntimeOrigin::signed(user_account.clone()), + Box::new(Parachain(paid_para_id).into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + )); + // check event + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + + // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount + assert_eq!( + Balances::free_balance(user_account), + INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount + ); + // Destination account (parachain account) has amount + let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating(); + assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); + // XcmFeesTargetAccount where should lend xcm_router_fee_amount + assert_eq!( + Balances::free_balance(XcmFeesTargetAccount::get()), + INITIAL_BALANCE + xcm_router_fee_amount + ); + assert_eq!( + sent_xcm(), + vec![( + Parachain(paid_para_id).into(), + Xcm(vec![ + ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), + ClearOrigin, + buy_execution((Parent, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]), + )] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + }); +} + /// Test `limited_reserve_transfer_assets` /// /// Asserts that the sender's balance is decreased and the beneficiary's balance diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index a428f1277a5..a3490108e8b 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -45,7 +45,7 @@ pub use junction::{BodyId, BodyPart, Junction, NetworkId}; pub use junctions::Junctions; pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, - WildFungibility, WildMultiAsset, + WildFungibility, WildMultiAsset, MAX_ITEMS_IN_MULTIASSETS, }; pub use multilocation::{ Ancestor, AncestorThen, InteriorMultiLocation, MultiLocation, Parent, ParentThen, @@ -70,7 +70,7 @@ pub type QueryId = u64; #[scale_info(bounds(), skip_type_params(Call))] pub struct Xcm(pub Vec>); -const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; +pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; environmental::environmental!(instructions_count: u8); @@ -932,7 +932,7 @@ pub enum Instruction { /// should be sent on arrival. /// - `xcm`: The message to be exported. /// - /// As an example, to export a message for execution on Statemine (parachain #1000 in the + /// As an example, to export a message for execution on Asset Hub (parachain #1000 in the /// Kusama network), you would call with `network: NetworkId::Kusama` and /// `destination: X1(Parachain(1000))`. Alternatively, to export a message for execution on /// Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`. diff --git a/polkadot/xcm/xcm-builder/src/currency_adapter.rs b/polkadot/xcm/xcm-builder/src/currency_adapter.rs index 23dc7958fe1..8ecf1dee72d 100644 --- a/polkadot/xcm/xcm-builder/src/currency_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/currency_adapter.rs @@ -191,7 +191,11 @@ impl< } } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> Result { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + _context: Option<&XcmContext>, + ) -> Result { log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who); // Check we handle this asset. let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotHandled)?; diff --git a/polkadot/xcm/xcm-builder/src/fee_handling.rs b/polkadot/xcm/xcm-builder/src/fee_handling.rs new file mode 100644 index 00000000000..1386747c977 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/fee_handling.rs @@ -0,0 +1,58 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use core::marker::PhantomData; +use frame_support::traits::{Contains, Get}; +use xcm::prelude::*; +use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset}; + +/// A `FeeManager` implementation that simply deposits the fees handled into a specific on-chain +/// `ReceiverAccount`. +/// +/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets, and also +/// permits specifying `WaivedLocations` for locations that are privileged to not pay for fees. If +/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be +/// logged. +pub struct XcmFeesToAccount( + PhantomData<(XcmConfig, WaivedLocations, AccountId, ReceiverAccount)>, +); +impl< + XcmConfig: xcm_executor::Config, + WaivedLocations: Contains, + AccountId: Clone + Into<[u8; 32]>, + ReceiverAccount: Get>, + > FeeManager for XcmFeesToAccount +{ + fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool { + let Some(loc) = origin else { return false }; + WaivedLocations::contains(loc) + } + + fn handle_fee(fees: MultiAssets, context: Option<&XcmContext>) { + if let Some(receiver) = ReceiverAccount::get() { + let dest = AccountId32 { network: None, id: receiver.into() }.into(); + for asset in fees.into_inner() { + if let Err(e) = XcmConfig::AssetTransactor::deposit_asset(&asset, &dest, context) { + log::trace!( + target: "xcm::fees", + "`AssetTransactor::deposit_asset` returned error: {:?}, burning fees: {:?}", + e, asset, + ); + } + } + } + } +} diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index 2179421b3eb..b2802c90809 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -274,7 +274,11 @@ impl< } } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> XcmResult { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + _context: Option<&XcmContext>, + ) -> XcmResult { log::trace!( target: "xcm::fungibles_adapter", "deposit_asset what: {:?}, who: {:?}", @@ -371,7 +375,11 @@ impl< >::check_out(dest, what, context) } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { FungiblesMutateAdapter::< Assets, Matcher, diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 21ada3244a3..34371398cdc 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -67,6 +67,9 @@ pub use process_xcm_message::ProcessXcmMessage; mod currency_adapter; pub use currency_adapter::CurrencyAdapter; +mod fee_handling; +pub use fee_handling::XcmFeesToAccount; + mod fungibles_adapter; pub use fungibles_adapter::{ AssetChecking, DualMint, FungiblesAdapter, FungiblesMutateAdapter, FungiblesTransferAdapter, diff --git a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index 4aebb496d49..357dc534a5f 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -207,7 +207,11 @@ impl< } } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { log::trace!( target: LOG_TARGET, "deposit_asset what: {:?}, who: {:?}, context: {:?}", @@ -307,7 +311,11 @@ impl< >::check_out(dest, what, context) } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { NonFungiblesMutateAdapter::< Assets, Matcher, diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index 0f3a622f4ec..4c9b9a6088d 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -110,11 +110,14 @@ impl< let message = Xcm(vec![ DescendOrigin(Interior::get()), UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination, - query_id, - max_weight: Weight::zero(), - })])), + SetAppendix(Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + ReportError(QueryResponseInfo { + destination, + query_id, + max_weight: Weight::zero(), + }), + ])), TransferAsset { beneficiary, assets: vec![MultiAsset { id: asset_id, fun: Fungibility::Fungible(amount) }] diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index e73b62f0073..7a7c8837fc1 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -253,7 +253,7 @@ impl TransactAsset for TestAssetTransactor { fn deposit_asset( what: &MultiAsset, who: &MultiLocation, - _context: &XcmContext, + _context: Option<&XcmContext>, ) -> Result<(), XcmError> { add_asset(*who, what.clone()); Ok(()) @@ -526,7 +526,7 @@ impl FeeManager for TestFeeManager { fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool { IS_WAIVED.with(|l| l.borrow().contains(&r)) } - fn handle_fee(_: MultiAssets) {} + fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {} } #[derive(Clone, Eq, PartialEq, Debug)] diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs index 491a2bcef7a..178b9384273 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs @@ -71,11 +71,14 @@ fn pay_over_xcm_works() { let expected_message = Xcm(vec![ DescendOrigin(AccountId32 { id: SenderAccount::get().into(), network: None }.into()), UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination: (Parent, Parachain(42)).into(), - query_id: 1, - max_weight: Weight::zero(), - })])), + SetAppendix(Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + }), + ])), TransferAsset { assets: (Here, amount).into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), @@ -130,11 +133,14 @@ fn pay_over_xcm_governance_body() { let expected_message = Xcm(vec![ DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination: (Parent, Parachain(42)).into(), - query_id: 1, - max_weight: Weight::zero(), - })])), + SetAppendix(Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + }), + ])), TransferAsset { assets: (Parent, amount).into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/salary.rs b/polkadot/xcm/xcm-builder/src/tests/pay/salary.rs index 1d40345f302..e490fe326b3 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/salary.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/salary.rs @@ -148,11 +148,14 @@ fn salary_pay_over_xcm_works() { let expected_message: Xcm = Xcm::(vec![ DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination: (Parent, Parachain(42)).into(), - query_id: 1, - max_weight: Weight::zero(), - })])), + SetAppendix(Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + }), + ])), TransferAsset { assets: (AssetHubAssetId::get(), FixedSalaryAmount::get()).into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 363748940ca..19ced591951 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -171,13 +171,13 @@ pub type Barrier = ( ); parameter_types! { - pub KusamaForStatemine: (MultiAssetFilter, MultiLocation) = + pub KusamaForAssetHub: (MultiAssetFilter, MultiLocation) = (Wild(AllOf { id: Concrete(Here.into()), fun: WildFungible }), Parachain(1000).into()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 4; } -pub type TrustedTeleporters = (xcm_builder::Case,); +pub type TrustedTeleporters = (xcm_builder::Case,); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index 426efcaccdb..36780b9f007 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -174,7 +174,7 @@ fn report_holding_works() { } /// Scenario: -/// A parachain wants to move KSM from Kusama to Statemine. +/// A parachain wants to move KSM from Kusama to Asset Hub. /// The parachain sends an XCM to withdraw funds combined with a teleport to the destination. /// /// This way of moving funds from a relay to a parachain will only work for trusted chains. @@ -182,12 +182,12 @@ fn report_holding_works() { /// /// Asserts that the balances are updated accordingly and the correct XCM is sent. #[test] -fn teleport_to_statemine_works() { +fn teleport_to_asset_hub_works() { use xcm::opaque::latest::prelude::*; let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); let balances = vec![(ALICE, INITIAL_BALANCE), (para_acc.clone(), INITIAL_BALANCE)]; kusama_like_with_balances(balances).execute_with(|| { - let statemine_id = 1000; + let asset_hub_id = 1000; let other_para_id = 3000; let amount = REGISTER_AMOUNT; let teleport_effects = vec![ @@ -222,13 +222,13 @@ fn teleport_to_statemine_works() { vec![(Parachain(other_para_id).into(), expected_msg, expected_hash,)] ); - // teleports are allowed from statemine to kusama. + // teleports are allowed from asset hub to kusama. let message = Xcm(vec![ WithdrawAsset((Here, amount).into()), buy_execution(), InitiateTeleport { assets: All.into(), - dest: Parachain(statemine_id).into(), + dest: Parachain(asset_hub_id).into(), xcm: Xcm(teleport_effects.clone()), }, ]); @@ -246,7 +246,7 @@ fn teleport_to_statemine_works() { mock::sent_xcm(), vec![ (Parachain(other_para_id).into(), expected_msg.clone(), expected_hash,), - (Parachain(statemine_id).into(), expected_msg, expected_hash,) + (Parachain(asset_hub_id).into(), expected_msg, expected_hash,) ] ); }); diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index a48cd3259d6..e11ec2630e4 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -248,7 +248,7 @@ impl ExecuteXcm for XcmExecutor XcmExecutor { reason: FeeReason, ) -> Result { let (ticket, fee) = validate_send::(dest, msg)?; - if !Config::FeeManager::is_waived(self.origin_ref(), reason) { - let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?; - Config::FeeManager::handle_fee(paid.into()); - } + self.take_fee(fee, reason)?; Config::XcmSender::deliver(ticket).map_err(Into::into) } @@ -618,14 +615,18 @@ impl XcmExecutor { DepositAsset { assets, beneficiary } => { let deposited = self.holding.saturating_take(assets); for asset in deposited.into_assets_iter() { - Config::AssetTransactor::deposit_asset(&asset, &beneficiary, &self.context)?; + Config::AssetTransactor::deposit_asset( + &asset, + &beneficiary, + Some(&self.context), + )?; } Ok(()) }, DepositReserveAsset { assets, dest, xcm } => { let deposited = self.holding.saturating_take(assets); for asset in deposited.assets_iter() { - Config::AssetTransactor::deposit_asset(&asset, &dest, &self.context)?; + Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?; } // Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot // be reanchored because we have already called `deposit_asset` on all assets. @@ -944,6 +945,14 @@ impl XcmExecutor { if Config::FeeManager::is_waived(self.origin_ref(), reason) { return Ok(()) } + log::trace!( + target: "xcm::fees", + "taking fee: {:?} from origin_ref: {:?} in fees_mode: {:?} for a reason: {:?}", + fee, + self.origin_ref(), + self.fees_mode, + reason, + ); let paid = if self.fees_mode.jit_withdraw { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; for asset in fee.inner() { @@ -953,7 +962,7 @@ impl XcmExecutor { } else { self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into() }; - Config::FeeManager::handle_fee(paid); + Config::FeeManager::handle_fee(paid, Some(&self.context)); Ok(()) } @@ -985,12 +994,7 @@ impl XcmExecutor { let QueryResponseInfo { destination, query_id, max_weight } = info; let instruction = QueryResponse { query_id, response, max_weight, querier }; let message = Xcm(vec![instruction]); - let (ticket, fee) = validate_send::(destination, message)?; - if !Config::FeeManager::is_waived(self.origin_ref(), fee_reason) { - let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?; - Config::FeeManager::handle_fee(paid.into()); - } - Config::XcmSender::deliver(ticket).map_err(Into::into) + self.send(destination, message, fee_reason) } fn try_reanchor( diff --git a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs index ad2e108e7de..2b2f21927f2 100644 --- a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs +++ b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs @@ -23,11 +23,11 @@ pub trait FeeManager { /// Do something with the fee which has been paid. Doing nothing here silently burns the /// fees. - fn handle_fee(fee: MultiAssets); + fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>); } /// Context under which a fee is paid. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum FeeReason { /// When a reporting instruction is called. Report, @@ -53,7 +53,7 @@ pub enum FeeReason { impl FeeManager for () { fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool { - true + false } - fn handle_fee(_: MultiAssets) {} + fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {} } diff --git a/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs b/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs index 34cdb0c7141..c51befff88a 100644 --- a/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs @@ -87,7 +87,11 @@ pub trait TransactAsset { /// Deposit the `what` asset into the account of `who`. /// /// Implementations should return `XcmError::FailedToTransactAsset` if deposit failed. - fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult { + fn deposit_asset( + _what: &MultiAsset, + _who: &MultiLocation, + _context: Option<&XcmContext>, + ) -> XcmResult { Err(XcmError::Unimplemented) } @@ -139,7 +143,7 @@ pub trait TransactAsset { Err(XcmError::AssetNotFound | XcmError::Unimplemented) => { let assets = Self::withdraw_asset(asset, from, Some(context))?; // Not a very forgiving attitude; once we implement roll-backs then it'll be nicer. - Self::deposit_asset(asset, to, context)?; + Self::deposit_asset(asset, to, Some(context))?; Ok(assets) }, result => result, @@ -195,7 +199,11 @@ impl TransactAsset for Tuple { )* ); } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { for_tuples!( #( match Tuple::deposit_asset(what, who, context) { Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), @@ -286,7 +294,7 @@ mod tests { fn deposit_asset( _what: &MultiAsset, _who: &MultiLocation, - _context: &XcmContext, + _context: Option<&XcmContext>, ) -> XcmResult { Err(XcmError::AssetNotFound) } @@ -330,7 +338,7 @@ mod tests { fn deposit_asset( _what: &MultiAsset, _who: &MultiLocation, - _context: &XcmContext, + _context: Option<&XcmContext>, ) -> XcmResult { Err(XcmError::Overflow) } @@ -374,7 +382,7 @@ mod tests { fn deposit_asset( _what: &MultiAsset, _who: &MultiLocation, - _context: &XcmContext, + _context: Option<&XcmContext>, ) -> XcmResult { Ok(()) } @@ -406,7 +414,7 @@ mod tests { MultiTransactor::deposit_asset( &(Here, 1u128).into(), &Here.into(), - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ), Err(XcmError::AssetNotFound) ); @@ -420,7 +428,7 @@ mod tests { MultiTransactor::deposit_asset( &(Here, 1u128).into(), &Here.into(), - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ), Ok(()) ); @@ -434,7 +442,7 @@ mod tests { MultiTransactor::deposit_asset( &(Here, 1u128).into(), &Here.into(), - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ), Err(XcmError::Overflow) ); @@ -448,7 +456,7 @@ mod tests { MultiTransactor::deposit_asset( &(Here, 1u128).into(), &Here.into(), - &XcmContext::with_message_id([0; 32]), + Some(&XcmContext::with_message_id([0; 32])), ), Ok(()), ); diff --git a/prdoc/pr_1234.prdoc b/prdoc/pr_1234.prdoc new file mode 100644 index 00000000000..cc22a02d88b --- /dev/null +++ b/prdoc/pr_1234.prdoc @@ -0,0 +1,20 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Introduce XcmFeesToAccount fee manager + +doc: + - audience: Builder + description: | + Now all XCM sending, unless done by the system for the system, will be charged delivery fees. + All runtimes are now configured to send these delivery fees to a treasury account. + The fee formula is `delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee)`. + +migrations: + db: [] + + runtime: [] + +crates: [] + +host_functions: [] diff --git a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index 110c4fa5198..6ce2097c268 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,8 +33,9 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } - - let CallWeightDef::Immediate(w) = &method.weight else { return }; + let CallWeightDef::Immediate(w) = &method.weight else { + return + }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") .old("not check weight witness data") @@ -65,8 +66,9 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } - - let syn::Expr::Lit(lit) = weight else { return }; + let syn::Expr::Lit(lit) = weight else { + return + }; let warning = Warning::new_deprecated("ConstantWeight") .index(warnings.len()) -- GitLab From 3e980219862d58aa52fd0b4dfff907d69ce92790 Mon Sep 17 00:00:00 2001 From: Bulat Saifullin Date: Wed, 18 Oct 2023 20:01:58 +0400 Subject: [PATCH 328/633] Update kusama/polkadot bootnodes (#1895) closes: https://github.com/paritytech/devops/issues/2090 ## Changes 1. Updated the list of bootnodes. 2. Merged the Connect node and bootnode into a single node. 3. Decreased the number of nodes. 4. Updated the DNS name. ## Description The initial 8 bootnodes were planned to be replaced by community bootnodes, the community node was added but we did not bother to reduce the Parity managed bootnodes. Fixing it now. --- polkadot/node/service/chain-specs/kusama.json | 23 +++++-------------- .../node/service/chain-specs/polkadot.json | 22 +++++------------- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 4ee48cf7d98..6676bbe154b 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -2,23 +2,12 @@ "name": "Kusama", "id": "ksmcc3", "bootNodes": [ - "/dns/kusama-connect-0.parity.io/tcp/443/wss/p2p/12D3KooWBjxpFhVNM9poSsMEfdnXJaSWSZQ7otK9aV1SPA9zJp5W", - "/dns/kusama-connect-1.parity.io/tcp/443/wss/p2p/12D3KooWAJRVca93jLm4zft4rtTLLxNV4ZrHPMBkbGy5XkXooBFt", - "/dns/kusama-connect-2.parity.io/tcp/443/wss/p2p/12D3KooWLn22TSPR3HXMRSSmWoK4pkDtspdCVi5j86QyyUNViDeL", - "/dns/kusama-connect-3.parity.io/tcp/443/wss/p2p/12D3KooWSwnJSP3QJ6cnFCTpcXq4EEFotVEiQuCWVprzCnWj5e4G", - "/dns/kusama-connect-4.parity.io/tcp/443/wss/p2p/12D3KooWHi7zHUev7n1zs9kSQwh4KMPJcS8Jky2JN58cNabcXGvK", - "/dns/kusama-connect-5.parity.io/tcp/443/wss/p2p/12D3KooWMBF6DXADrNLg6kNt1A1zmKzw478gJw79NmTQhSDxuZvR", - "/dns/kusama-connect-6.parity.io/tcp/443/wss/p2p/12D3KooWNnG7YqYB9eEoACRuSEax8qhuPQzRn878AWKN4vUUtQXd", - "/dns/kusama-connect-7.parity.io/tcp/443/wss/p2p/12D3KooWMmtoLnkVCGyuCpsWw4zoNtWPH4nsVLn92mutvjQknEqR", - "/dns/p2p.0.kusama.network/tcp/30333/p2p/12D3KooWJDohybWd7FvRmyeGjgi56yy36mRWLHmgRprFdUadUt6b", - "/dns/p2p.1.kusama.network/tcp/30333/p2p/12D3KooWC7dnTvDY97afoLrvQSBrh7dDFEkWniTwyxAsBjfpaZk6", - "/dns/p2p.2.kusama.network/tcp/30333/p2p/12D3KooWGGK6Mj1pWF1bk4R1HjBQ4E7bgkfSJ5gmEfVRuwRZapT5", - "/dns/p2p.3.kusama.network/tcp/30333/p2p/12D3KooWRp4qgusMiUobJ9Uw1XAwtsokqx9YwgHDv5wQXjxqETji", - "/dns/p2p.4.kusama.network/tcp/30333/p2p/12D3KooWMVXPbqWR1erNKRSWDVPjcAQ9XtxqLTVzV4ccox9Y8KNL", - "/dns/p2p.5.kusama.network/tcp/30333/p2p/12D3KooWBsJKGJFuv83ixryzMsUS53A8JzEVeTA8PGi4U6T2dnif", - "/dns/kusama-bootnode-0.paritytech.net/tcp/30333/p2p/12D3KooWSueCPH3puP2PcvqPJdNaDNF3jMZjtJtDiSy35pWrbt5h", - "/dns/kusama-bootnode-0.paritytech.net/tcp/30334/ws/p2p/12D3KooWSueCPH3puP2PcvqPJdNaDNF3jMZjtJtDiSy35pWrbt5h", - "/dns/kusama-bootnode-1.paritytech.net/tcp/30333/p2p/12D3KooWQKqane1SqWJNWMQkbia9qiMWXkcHtAdfW5eVF8hbwEDw", + "/dns/kusama-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWSueCPH3puP2PcvqPJdNaDNF3jMZjtJtDiSy35pWrbt5h", + "/dns/kusama-bootnode-0.polkadot.io/tcp/30334/ws/p2p/12D3KooWSueCPH3puP2PcvqPJdNaDNF3jMZjtJtDiSy35pWrbt5h", + "/dns/kusama-bootnode-0.polkadot.io/tcp/443/wss/p2p/12D3KooWSueCPH3puP2PcvqPJdNaDNF3jMZjtJtDiSy35pWrbt5h", + "/dns/kusama-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWQKqane1SqWJNWMQkbia9qiMWXkcHtAdfW5eVF8hbwEDw", + "/dns/kusama-bootnode-1.polkadot.io/tcp/30334/ws/p2p/12D3KooWQKqane1SqWJNWMQkbia9qiMWXkcHtAdfW5eVF8hbwEDw", + "/dns/kusama-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQKqane1SqWJNWMQkbia9qiMWXkcHtAdfW5eVF8hbwEDw", "/dns/kusama-boot.dwellir.com/tcp/30333/ws/p2p/12D3KooWFj2ndawdYyk2spc42Y2arYwb2TUoHLHFAsKuHRzWXwoJ", "/dns/kusama-boot.dwellir.com/tcp/443/wss/p2p/12D3KooWFj2ndawdYyk2spc42Y2arYwb2TUoHLHFAsKuHRzWXwoJ", "/dns/boot.stake.plus/tcp/31333/p2p/12D3KooWLa1UyG5xLPds2GbiRBCTJjpsVwRWHWN7Dff14yiNJRpR", diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 6452c892715..53349208816 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -3,22 +3,12 @@ "id": "polkadot", "chainType": "Live", "bootNodes": [ - "/dns/polkadot-connect-0.parity.io/tcp/443/wss/p2p/12D3KooWEPmjoRpDSUuiTjvyNDd8fejZ9eNWH5bE965nyBMDrB4o", - "/dns/polkadot-connect-1.parity.io/tcp/443/wss/p2p/12D3KooWLvcA24g6sT9YTaQyinwowMbLF5z7iMLoxZpEiV9pSmNf", - "/dns/polkadot-connect-2.parity.io/tcp/443/wss/p2p/12D3KooWDhp18HYzJuVX2jLhtjQgAhT1XWGqah42StoUJpkLvh2o", - "/dns/polkadot-connect-3.parity.io/tcp/443/wss/p2p/12D3KooWEsPEadSjLAPyxckqVJkp54aVdPuX3DD6a1FTL2y5cB9x", - "/dns/polkadot-connect-4.parity.io/tcp/443/wss/p2p/12D3KooWFfG1SQvcPoUK2N41cx7r52KYXKpRtZxfLZk8xtVzpp4d", - "/dns/polkadot-connect-5.parity.io/tcp/443/wss/p2p/12D3KooWDmQPkBvQGg9wjBdFThtWj3QCDVQyHJ1apfWrHvjwbYS8", - "/dns/polkadot-connect-6.parity.io/tcp/443/wss/p2p/12D3KooWBKtPpCnVTTzD7fPpCdFsrsYZ5K8fwmsLabb1JBuCycYs", - "/dns/polkadot-connect-7.parity.io/tcp/443/wss/p2p/12D3KooWP3BsFY6UaiLjEJ3YbDp6q6SMQgAHB15qKj41DUZQLMqD", - "/dns/p2p.0.polkadot.network/tcp/30333/p2p/12D3KooWHsvEicXjWWraktbZ4MQBizuyADQtuEGr3NbDvtm5rFA5", - "/dns/p2p.1.polkadot.network/tcp/30333/p2p/12D3KooWQz2q2UWVCiy9cFX1hHYEmhSKQB2hjEZCccScHLGUPjcc", - "/dns/p2p.2.polkadot.network/tcp/30333/p2p/12D3KooWNHxjYbDLLbDNZ2tq1kXgif5MSiLTUWJKcDdedKu4KaG8", - "/dns/p2p.3.polkadot.network/tcp/30333/p2p/12D3KooWGJQysxrQcSvUWWNw88RkqYvJhH3ZcDpWJ8zrXKhLP5Vr", - "/dns/p2p.4.polkadot.network/tcp/30333/p2p/12D3KooWKer8bYqpYjwurVABu13mkELpX2X7mSpEicpjShLeg7D6", - "/dns/p2p.5.polkadot.network/tcp/30333/p2p/12D3KooWSRjL9LcEQd5u2fQTbyLxTEHq1tUFgQ6amXSp8Eu7TfKP", - "/dns/cc1-0.parity.tech/tcp/30333/p2p/12D3KooWSz8r2WyCdsfWHgPyvD8GKQdJ1UAiRmrcrs8sQB3fe2KU", - "/dns/cc1-1.parity.tech/tcp/30333/p2p/12D3KooWFN2mhgpkJsDBuNuE5427AcDrsib8EoqGMZmkxWwx3Md4", + "/dns/polkadot-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWSz8r2WyCdsfWHgPyvD8GKQdJ1UAiRmrcrs8sQB3fe2KU", + "/dns/polkadot-bootnode-0.polkadot.io/tcp/30334/ws/p2p/12D3KooWSz8r2WyCdsfWHgPyvD8GKQdJ1UAiRmrcrs8sQB3fe2KU", + "/dns/polkadot-bootnode-0.polkadot.io/tcp/443/wss/p2p/12D3KooWSz8r2WyCdsfWHgPyvD8GKQdJ1UAiRmrcrs8sQB3fe2KU", + "/dns/polkadot-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWFN2mhgpkJsDBuNuE5427AcDrsib8EoqGMZmkxWwx3Md4", + "/dns/polkadot-bootnode-1.polkadot.io/tcp/30334/ws/p2p/12D3KooWFN2mhgpkJsDBuNuE5427AcDrsib8EoqGMZmkxWwx3Md4", + "/dns/polkadot-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWFN2mhgpkJsDBuNuE5427AcDrsib8EoqGMZmkxWwx3Md4", "/dns/polkadot-boot.dwellir.com/tcp/30334/ws/p2p/12D3KooWKvdDyRKqUfSAaUCbYiLwKY8uK3wDWpCuy2FiDLbkPTDJ", "/dns/polkadot-boot.dwellir.com/tcp/443/wss/p2p/12D3KooWKvdDyRKqUfSAaUCbYiLwKY8uK3wDWpCuy2FiDLbkPTDJ", "/dns/boot.stake.plus/tcp/30333/p2p/12D3KooWKT4ZHNxXH4icMjdrv7EwWBkfbz5duxE5sdJKKeWFYi5n", -- GitLab From 411a4e38d3634d22bd82e7db21798dc1f5cc9304 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 19 Oct 2023 12:19:16 +1100 Subject: [PATCH 329/633] Use prebuilt try-runtime binary in CI (#1898) `cargo install` takes a long time in CI. We want to run it relatively frequently without chewing through so much compute (see https://github.com/paritytech/ci_cd/issues/771) so I added automatic binary releases to the try-runtime-cli repo. A small added benefit is we can use it in our existing `on-runtime-upgrade` checks, which should cut their execution time by about half. --- .gitlab/pipeline/check.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 559ce093cf6..5a304d8bc4e 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -112,12 +112,16 @@ test-rust-feature-propagation: script: - | export RUST_LOG=remote-ext=debug,runtime=debug - echo "---------- Installing try-runtime-cli ----------" - time cargo install --locked --git https://github.com/paritytech/try-runtime-cli --tag v0.3.0 + + echo "---------- Downloading try-runtime CLI ----------" + curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.3.3/try-runtime-x86_64-unknown-linux-musl -o try-runtime + chmod +x ./try-runtime + echo "---------- Building ${PACKAGE} runtime ----------" time cargo build --release --locked -p "$PACKAGE" --features try-runtime + echo "---------- Executing `on-runtime-upgrade` for ${NETWORK} ----------" - time try-runtime \ + time ./try-runtime \ --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ on-runtime-upgrade --checks=pre-and-post ${EXTRA_ARGS} live --uri ${URI} -- GitLab From 21b32849db4ac5f284d7ca2f93927b0d35bb783a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 19 Oct 2023 10:07:29 +0200 Subject: [PATCH 330/633] Cumulus: Allow aura to use initialized collation request receiver (#1911) When launching our [small network](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/zombienet/examples/small_network.toml) for testing the node was crashing here shortly after launch: https://github.com/paritytech/polkadot-sdk/blob/5cdd819ed295645958afd9d937d989978fd0c84e/polkadot/node/collation-generation/src/lib.rs#L140 After changes in #1788 for the asset hub collator we are waiting for blocks of the shell runtime to pass before we initialize aura. However, this means that we attempted to initialize the collation related relay chain subsystems twice, leading to the error. I modified Aura to let it optionally take an already initialized stream of collation requests. --- .../consensus/aura/src/collators/basic.rs | 26 +++++++++++++------ .../parachain-template/node/src/service.rs | 1 + cumulus/polkadot-parachain/src/service.rs | 4 +++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index 3c904915cea..dc0078b0d6a 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -23,7 +23,9 @@ //! For more information about AuRa, the Substrate crate should be checked. use codec::{Codec, Decode}; -use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; +use cumulus_client_collator::{ + relay_chain_driven::CollationRequest, service::ServiceInterface as CollatorServiceInterface, +}; use cumulus_client_consensus_common::ParachainBlockImportMarker; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_core::{relay_chain::BlockId as RBlockId, CollectCollationInfo}; @@ -33,7 +35,7 @@ use polkadot_node_primitives::CollationResult; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{CollatorPair, Id as ParaId}; -use futures::prelude::*; +use futures::{channel::mpsc::Receiver, prelude::*}; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; use sc_consensus::BlockImport; use sp_api::ProvideRuntimeApi; @@ -81,6 +83,10 @@ pub struct Params { pub collator_service: CS, /// The amount of time to spend authoring each block. pub authoring_duration: Duration, + /// Receiver for collation requests. If `None`, Aura consensus will establish a new receiver. + /// Should be used when a chain migrates from a different consensus algorithm and was already + /// processing collation requests before initializing Aura. + pub collation_request_receiver: Option>, } /// Run bare Aura consensus as a relay-chain-driven collator. @@ -110,12 +116,16 @@ where P::Signature: TryFrom> + Member + Codec, { async move { - let mut collation_requests = cumulus_client_collator::relay_chain_driven::init( - params.collator_key, - params.para_id, - params.overseer_handle, - ) - .await; + let mut collation_requests = match params.collation_request_receiver { + Some(receiver) => receiver, + None => + cumulus_client_collator::relay_chain_driven::init( + params.collator_key, + params.para_id, + params.overseer_handle, + ) + .await, + }; let mut collator = { let params = collator_util::Params { diff --git a/cumulus/parachain-template/node/src/service.rs b/cumulus/parachain-template/node/src/service.rs index 9fa6d60c2e7..84dcd6dd1b3 100644 --- a/cumulus/parachain-template/node/src/service.rs +++ b/cumulus/parachain-template/node/src/service.rs @@ -411,6 +411,7 @@ fn start_consensus( collator_service, // Very limited proposal time. authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index fa61f534784..438d09a4c77 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -988,6 +988,7 @@ pub async fn start_rococo_parachain_node( collator_service, // Very limited proposal time. authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = basic_aura::run::< @@ -1380,6 +1381,7 @@ where collator_service, // Very limited proposal time. authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = @@ -1520,6 +1522,7 @@ where collator_service, // Very limited proposal time. authoring_duration: Duration::from_millis(500), + collation_request_receiver: Some(request_stream), }; basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) @@ -1925,6 +1928,7 @@ pub async fn start_contracts_rococo_node( collator_service, // Very limited proposal time. authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = basic_aura::run::< -- GitLab From 099ef8fe11fc5fa1a864ec61c412a400a6160156 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 19 Oct 2023 12:02:13 +0200 Subject: [PATCH 331/633] [FRAME] Message Queue use proper overweight limit (#1873) Changes: - Use a sensible limit for the overweight-cutoff of a single messages instead of the full configured `ServiceWeight`. - Add/Update tests --------- Signed-off-by: Oliver Tale-Yazdi --- prdoc/pr_1873.prdoc | 15 ++ .../message-queue/src/integration_test.rs | 17 +- substrate/frame/message-queue/src/lib.rs | 54 +++++- substrate/frame/message-queue/src/mock.rs | 36 +++- substrate/frame/message-queue/src/tests.rs | 182 ++++++++++++++++++ 5 files changed, 282 insertions(+), 22 deletions(-) create mode 100644 prdoc/pr_1873.prdoc diff --git a/prdoc/pr_1873.prdoc b/prdoc/pr_1873.prdoc new file mode 100644 index 00000000000..6f3bc7646db --- /dev/null +++ b/prdoc/pr_1873.prdoc @@ -0,0 +1,15 @@ +title: Message Queue use proper overweight limit + +doc: + - audience: Core Dev + description: | + Changed the overweight cutoff limit from the full `Config::ServiceWeight` to a lower value that is calculated based on the weight of the functions being called. + +migrations: + db: [] + + runtime: [] + +crates: ["pallet-message-queue", patch] + +host_functions: [] diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index a1003edf3c9..965b96a99ca 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -17,6 +17,13 @@ //! Stress tests pallet-message-queue. Defines its own runtime config to use larger constants for //! `HeapSize` and `MaxStale`. +//! +//! The tests in this file are ignored by default, since they are quite slow. You can run them +//! manually like this: +//! +//! ```sh +//! RUST_LOG=info cargo test -p pallet-message-queue --profile testnet -- --ignored +//! ``` #![cfg(test)] @@ -96,9 +103,6 @@ impl Config for Test { /// Simulates heavy usage by enqueueing and processing large amounts of messages. /// -/// Best to run with `RUST_LOG=info RUSTFLAGS='-Cdebug-assertions=y' cargo test -r -p -/// pallet-message-queue -- --ignored`. -/// /// # Example output /// /// ```pre @@ -121,7 +125,7 @@ fn stress_test_enqueue_and_service() { let max_queues = 10_000; let max_messages_per_queue = 10_000; let max_msg_len = MaxMessageLenOf::::get(); - let mut rng = StdRng::seed_from_u64(42); + let mut rng = StdRng::seed_from_u64(43); build_and_execute::(|| { let mut msgs_remaining = 0; @@ -145,9 +149,6 @@ fn stress_test_enqueue_and_service() { /// Simulates heavy usage of the suspension logic via `Yield`. /// -/// Best to run with `RUST_LOG=info RUSTFLAGS='-Cdebug-assertions=y' cargo test -r -p -/// pallet-message-queue -- --ignored`. -/// /// # Example output /// /// ```pre @@ -169,7 +170,7 @@ fn stress_test_queue_suspension() { let max_messages_per_queue = 10_000; let (max_suspend_per_block, max_resume_per_block) = (100, 50); let max_msg_len = MaxMessageLenOf::::get(); - let mut rng = StdRng::seed_from_u64(41); + let mut rng = StdRng::seed_from_u64(43); build_and_execute::(|| { let mut suspended = BTreeSet::::new(); diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 7c38dec4b08..04bbea121dd 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -584,8 +584,9 @@ pub mod pallet { } /// Check all compile-time assumptions about [`crate::Config`]. + #[cfg(test)] fn integrity_test() { - assert!(!MaxMessageLenOf::::get().is_zero(), "HeapSize too low"); + Self::do_integrity_test().expect("Pallet config is valid; qed") } } @@ -759,6 +760,47 @@ impl Pallet { } } + /// The maximal weight that a single message can consume. + /// + /// Any message using more than this will be marked as permanently overweight and not + /// automatically re-attempted. Returns `None` if the servicing of a message cannot begin. + /// `Some(0)` means that only messages with no weight may be served. + fn max_message_weight(limit: Weight) -> Option { + limit.checked_sub(&Self::single_msg_overhead()) + } + + /// The overhead of servicing a single message. + fn single_msg_overhead() -> Weight { + T::WeightInfo::bump_service_head() + .saturating_add(T::WeightInfo::service_queue_base()) + .saturating_add( + T::WeightInfo::service_page_base_completion() + .max(T::WeightInfo::service_page_base_no_completion()), + ) + .saturating_add(T::WeightInfo::service_page_item()) + .saturating_add(T::WeightInfo::ready_ring_unknit()) + } + + /// Checks invariants of the pallet config. + /// + /// The results of this can only be relied upon if the config values are set to constants. + #[cfg(test)] + fn do_integrity_test() -> Result<(), String> { + ensure!(!MaxMessageLenOf::::get().is_zero(), "HeapSize too low"); + + if let Some(service) = T::ServiceWeight::get() { + if Self::max_message_weight(service).is_none() { + return Err(format!( + "ServiceWeight too low: {}. Must be at least {}", + service, + Self::single_msg_overhead(), + )) + } + } + + Ok(()) + } + fn do_enqueue_message( origin: &MessageOriginOf, message: BoundedSlice>, @@ -1360,10 +1402,14 @@ impl ServiceQueues for Pallet { type OverweightMessageAddress = (MessageOriginOf, PageIndex, T::Size); fn service_queues(weight_limit: Weight) -> Weight { - // The maximum weight that processing a single message may take. - let overweight_limit = weight_limit; let mut weight = WeightMeter::with_limit(weight_limit); + // Get the maximum weight that processing a single message may take: + let max_weight = Self::max_message_weight(weight_limit).unwrap_or_else(|| { + defensive!("Not enough weight to service a single message."); + Weight::zero() + }); + let mut next = match Self::bump_service_head(&mut weight) { Some(h) => h, None => return weight.consumed(), @@ -1374,7 +1420,7 @@ impl ServiceQueues for Pallet { let mut last_no_progress = None; loop { - let (progressed, n) = Self::service_queue(next.clone(), &mut weight, overweight_limit); + let (progressed, n) = Self::service_queue(next.clone(), &mut weight, max_weight); next = match n { Some(n) => if !progressed { diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index 473c5faac4c..e6af0d9f1ee 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -71,7 +71,7 @@ impl frame_system::Config for Test { parameter_types! { pub const HeapSize: u32 = 24; pub const MaxStale: u32 = 2; - pub const ServiceWeight: Option = Some(Weight::from_parts(10, 10)); + pub const ServiceWeight: Option = Some(Weight::from_parts(100, 100)); } impl Config for Test { type RuntimeEvent = RuntimeEvent; @@ -91,6 +91,7 @@ pub struct MockedWeightInfo; parameter_types! { /// Storage for `MockedWeightInfo`, do not use directly. pub static WeightForCall: BTreeMap = Default::default(); + pub static DefaultWeightForCall: Weight = Weight::zero(); } /// Set the return value for a function from the `WeightInfo` trait. @@ -111,40 +112,55 @@ impl crate::weights::WeightInfo for MockedWeightInfo { WeightForCall::get() .get("execute_overweight_page_updated") .copied() - .unwrap_or_default() + .unwrap_or(DefaultWeightForCall::get()) } fn execute_overweight_page_removed() -> Weight { WeightForCall::get() .get("execute_overweight_page_removed") .copied() - .unwrap_or_default() + .unwrap_or(DefaultWeightForCall::get()) } fn service_page_base_completion() -> Weight { WeightForCall::get() .get("service_page_base_completion") .copied() - .unwrap_or_default() + .unwrap_or(DefaultWeightForCall::get()) } fn service_page_base_no_completion() -> Weight { WeightForCall::get() .get("service_page_base_no_completion") .copied() - .unwrap_or_default() + .unwrap_or(DefaultWeightForCall::get()) } fn service_queue_base() -> Weight { - WeightForCall::get().get("service_queue_base").copied().unwrap_or_default() + WeightForCall::get() + .get("service_queue_base") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } fn bump_service_head() -> Weight { - WeightForCall::get().get("bump_service_head").copied().unwrap_or_default() + WeightForCall::get() + .get("bump_service_head") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } fn service_page_item() -> Weight { - WeightForCall::get().get("service_page_item").copied().unwrap_or_default() + WeightForCall::get() + .get("service_page_item") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } fn ready_ring_knit() -> Weight { - WeightForCall::get().get("ready_ring_knit").copied().unwrap_or_default() + WeightForCall::get() + .get("ready_ring_knit") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } fn ready_ring_unknit() -> Weight { - WeightForCall::get().get("ready_ring_unknit").copied().unwrap_or_default() + WeightForCall::get() + .get("ready_ring_unknit") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } } diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index 092bd1d8334..5a235a8750e 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -266,6 +266,44 @@ fn service_queues_suspension_works() { }); } +#[test] +#[cfg(debug_assertions)] +#[should_panic(expected = "Not enough weight to service a single message.")] +fn service_queues_low_weight_defensive() { + use MessageOrigin::*; + build_and_execute::(|| { + DefaultWeightForCall::set(21.into()); + // Check that the integrity test would catch this: + assert!(MessageQueue::do_integrity_test().is_err()); + + MessageQueue::enqueue_message(msg("weight=0"), Here); + MessageQueue::service_queues(104.into_weight()); + }); +} + +/// Regression test for . +#[test] +fn service_queues_regression_1873() { + use MessageOrigin::*; + build_and_execute::(|| { + DefaultWeightForCall::set(20.into()); + + MessageQueue::enqueue_message(msg("weight=100"), Here); + assert_eq!(MessageQueue::service_queues(100.into_weight()), 100.into()); + + // Before the MQ this would not emit any events: + assert_last_event::( + Event::OverweightEnqueued { + id: blake2_256(b"weight=100"), + origin: MessageOrigin::Here, + message_index: 0, + page_index: 0, + } + .into(), + ); + }); +} + #[test] fn reap_page_permanent_overweight_works() { use MessageOrigin::*; @@ -1150,6 +1188,116 @@ fn permanently_overweight_book_unknits_multiple() { }); } +#[test] +fn permanently_overweight_limit_is_valid_basic() { + use MessageOrigin::*; + + for w in 50..300 { + build_and_execute::(|| { + DefaultWeightForCall::set(Weight::MAX); + + set_weight("bump_service_head", 10.into()); + set_weight("service_queue_base", 10.into()); + set_weight("service_page_base_no_completion", 10.into()); + set_weight("service_page_base_completion", 0.into()); + + set_weight("service_page_item", 10.into()); + set_weight("ready_ring_unknit", 10.into()); + + let m = "weight=200".to_string(); + + MessageQueue::enqueue_message(msg(&m), Here); + MessageQueue::service_queues(w.into()); + + let last_event = + frame_system::Pallet::::events().into_iter().last().expect("No event"); + + // The weight overhead for a single message is set to 50. The message itself needs 200. + // Every weight in range `[50, 249]` should result in a permanently overweight message: + if w < 250 { + assert_eq!( + last_event.event, + RuntimeEvent::MessageQueue(Event::OverweightEnqueued { + id: blake2_256(m.as_bytes()), + origin: Here, + message_index: 0, + page_index: 0, + }) + ); + } else { + // Otherwise it is processed as normal: + assert_eq!( + last_event.event, + RuntimeEvent::MessageQueue(Event::Processed { + origin: Here, + weight_used: 200.into(), + id: blake2_256(m.as_bytes()), + success: true, + }) + ); + } + }); + } +} + +#[test] +fn permanently_overweight_limit_is_valid_fuzzy() { + use MessageOrigin::*; + let mut rng = rand::rngs::StdRng::seed_from_u64(42); + + for _ in 0..10 { + // Brainlet code, but works... + let (s1, s2) = (rng.gen_range(0..=10), rng.gen_range(0..=10)); + let (s3, s4) = (rng.gen_range(0..=10), rng.gen_range(0..=10)); + let s5 = rng.gen_range(0..=10); + let o = s1 + s2 + s3 + s4 + s5; + + for w in o..=o + 300 { + build_and_execute::(|| { + DefaultWeightForCall::set(Weight::MAX); + + set_weight("bump_service_head", s1.into()); + set_weight("service_queue_base", s2.into()); + // Only the larger one of these two is taken: + set_weight("service_page_base_no_completion", s3.into()); + set_weight("service_page_base_completion", 0.into()); + set_weight("service_page_item", s4.into()); + set_weight("ready_ring_unknit", s5.into()); + + let m = "weight=200".to_string(); + + MessageQueue::enqueue_message(msg(&m), Here); + MessageQueue::service_queues(w.into()); + + let last_event = + frame_system::Pallet::::events().into_iter().last().expect("No event"); + + if w < o + 200 { + assert_eq!( + last_event.event, + RuntimeEvent::MessageQueue(Event::OverweightEnqueued { + id: blake2_256(m.as_bytes()), + origin: Here, + message_index: 0, + page_index: 0, + }) + ); + } else { + assert_eq!( + last_event.event, + RuntimeEvent::MessageQueue(Event::Processed { + origin: Here, + weight_used: 200.into(), + id: blake2_256(m.as_bytes()), + success: true, + }) + ); + } + }); + } + } +} + /// We don't want empty books in the ready ring, but if they somehow make their way in there, it /// should not panic. #[test] @@ -1447,3 +1595,37 @@ fn service_queue_suspension_ready_ring_works() { ); }); } + +#[test] +fn integrity_test_checks_service_weight() { + build_and_execute::(|| { + assert_eq!(::ServiceWeight::get(), Some(100.into()), "precond"); + assert!(MessageQueue::do_integrity_test().is_ok(), "precond"); + + // Enough for all: + DefaultWeightForCall::set(20.into()); + assert!(MessageQueue::do_integrity_test().is_ok()); + + // Not enough for anything: + DefaultWeightForCall::set(101.into()); + assert_eq!(MessageQueue::single_msg_overhead(), 505.into()); + assert!(MessageQueue::do_integrity_test().is_err()); + + // Not enough for a single function: + for f in [ + "bump_service_head", + "service_queue_base", + "service_page_base_completion", + "service_page_base_no_completion", + "service_page_item", + "ready_ring_unknit", + ] { + WeightForCall::take(); + DefaultWeightForCall::set(Zero::zero()); + + assert!(MessageQueue::do_integrity_test().is_ok()); + set_weight(f, 101.into()); + assert!(MessageQueue::do_integrity_test().is_err()); + } + }); +} -- GitLab From 3706a75f3764445b84c0140074dcbdb504f83301 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Thu, 19 Oct 2023 08:22:40 -0300 Subject: [PATCH 332/633] bump zombienet version (#1931) Includes: - PoC for new `spot instance` infra for jobs. - Fixes in test-runner/cli --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61451a9c462..069068369ab 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.69" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.71" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: -- GitLab From 68d2363701deca5a46f063e239cd79281e10805c Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 19 Oct 2023 15:30:17 +0200 Subject: [PATCH 333/633] Update bridges subtree (#1944) --- .../verification/equivocation.rs | 7 +++ .../src/justification/verification/mod.rs | 59 +++++++++++++++---- .../justification/verification/optimizer.rs | 15 +++++ .../src/justification/verification/strict.rs | 9 ++- .../tests/implementation_match.rs | 4 +- .../tests/justification/optimizer.rs | 20 +++++++ .../tests/justification/strict.rs | 16 ++++- 7 files changed, 114 insertions(+), 16 deletions(-) diff --git a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs index e2d7a8e804c..fbad3012819 100644 --- a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs +++ b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs @@ -101,6 +101,13 @@ impl<'a, Header: HeaderT> EquivocationsCollector<'a, Header> { } impl<'a, Header: HeaderT> JustificationVerifier
for EquivocationsCollector<'a, Header> { + fn process_duplicate_votes_ancestries( + &mut self, + _duplicate_votes_ancestries: Vec, + ) -> Result<(), JustificationVerificationError> { + Ok(()) + } + fn process_redundant_vote( &mut self, _precommit_idx: usize, diff --git a/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs index a66fc1e0d91..c71149bf9c2 100644 --- a/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -27,7 +27,13 @@ use finality_grandpa::voter_set::VoterSet; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, SetId}; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug}; use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + collections::{ + btree_map::{ + BTreeMap, + Entry::{Occupied, Vacant}, + }, + btree_set::BTreeSet, + }, prelude::*, }; @@ -44,23 +50,40 @@ pub struct AncestryChain { /// We expect all forks in the ancestry chain to be descendants of base. base: HeaderId, /// Header hash => parent header hash mapping. - pub parents: BTreeMap, + parents: BTreeMap, /// Hashes of headers that were not visited by `ancestry()`. - pub unvisited: BTreeSet, + unvisited: BTreeSet, } impl AncestryChain
{ - /// Create new ancestry chain. - pub fn new(justification: &GrandpaJustification
) -> AncestryChain
{ + /// Creates a new instance of `AncestryChain` starting from a `GrandpaJustification`. + /// + /// Returns the `AncestryChain` and a `Vec` containing the `votes_ancestries` entries + /// that were ignored when creating it, because they are duplicates. + pub fn new( + justification: &GrandpaJustification
, + ) -> (AncestryChain
, Vec) { let mut parents = BTreeMap::new(); let mut unvisited = BTreeSet::new(); - for ancestor in &justification.votes_ancestries { + let mut ignored_idxs = Vec::new(); + for (idx, ancestor) in justification.votes_ancestries.iter().enumerate() { let hash = ancestor.hash(); - let parent_hash = *ancestor.parent_hash(); - parents.insert(hash, parent_hash); - unvisited.insert(hash); + match parents.entry(hash) { + Occupied(_) => { + ignored_idxs.push(idx); + }, + Vacant(entry) => { + entry.insert(*ancestor.parent_hash()); + unvisited.insert(hash); + }, + } } - AncestryChain { base: justification.commit_target_id(), parents, unvisited } + (AncestryChain { base: justification.commit_target_id(), parents, unvisited }, ignored_idxs) + } + + /// Returns the hash of a block's parent if the block is present in the ancestry. + pub fn parent_hash_of(&self, hash: &Header::Hash) -> Option<&Header::Hash> { + self.parents.get(hash) } /// Returns a route if the precommit target block is a descendant of the `base` block. @@ -80,7 +103,7 @@ impl AncestryChain
{ break } - current_hash = match self.parents.get(¤t_hash) { + current_hash = match self.parent_hash_of(¤t_hash) { Some(parent_hash) => { let is_visited_before = self.unvisited.get(¤t_hash).is_none(); if is_visited_before { @@ -117,6 +140,8 @@ pub enum Error { InvalidAuthorityList, /// Justification is finalizing unexpected header. InvalidJustificationTarget, + /// The justification contains duplicate headers in its `votes_ancestries` field. + DuplicateVotesAncestries, /// Error validating a precommit Precommit(PrecommitError), /// The cumulative weight of all votes in the justification is not enough to justify commit @@ -168,6 +193,12 @@ enum IterationFlow { /// Verification callbacks. trait JustificationVerifier { + /// Called when there are duplicate headers in the votes ancestries. + fn process_duplicate_votes_ancestries( + &mut self, + duplicate_votes_ancestries: Vec, + ) -> Result<(), Error>; + fn process_redundant_vote( &mut self, precommit_idx: usize, @@ -216,10 +247,14 @@ trait JustificationVerifier { } let threshold = context.voter_set.threshold().get(); - let mut chain = AncestryChain::new(justification); + let (mut chain, ignored_idxs) = AncestryChain::new(justification); let mut signature_buffer = Vec::new(); let mut cumulative_weight = 0u64; + if !ignored_idxs.is_empty() { + self.process_duplicate_votes_ancestries(ignored_idxs)?; + } + for (precommit_idx, signed) in justification.commit.precommits.iter().enumerate() { if cumulative_weight >= threshold { let action = diff --git a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs index 6552b359170..3f1e6ab670c 100644 --- a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs +++ b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs @@ -33,6 +33,7 @@ struct JustificationOptimizer { votes: BTreeSet, extra_precommits: Vec, + duplicate_votes_ancestries_idxs: Vec, redundant_votes_ancestries: BTreeSet, } @@ -41,6 +42,11 @@ impl JustificationOptimizer
{ for invalid_precommit_idx in self.extra_precommits.into_iter().rev() { justification.commit.precommits.remove(invalid_precommit_idx); } + if !self.duplicate_votes_ancestries_idxs.is_empty() { + for idx in self.duplicate_votes_ancestries_idxs.iter().rev() { + justification.votes_ancestries.swap_remove(*idx); + } + } if !self.redundant_votes_ancestries.is_empty() { justification .votes_ancestries @@ -50,6 +56,14 @@ impl JustificationOptimizer
{ } impl JustificationVerifier
for JustificationOptimizer
{ + fn process_duplicate_votes_ancestries( + &mut self, + duplicate_votes_ancestries: Vec, + ) -> Result<(), Error> { + self.duplicate_votes_ancestries_idxs = duplicate_votes_ancestries.to_vec(); + Ok(()) + } + fn process_redundant_vote( &mut self, precommit_idx: usize, @@ -118,6 +132,7 @@ pub fn verify_and_optimize_justification( let mut optimizer = JustificationOptimizer { votes: BTreeSet::new(), extra_precommits: vec![], + duplicate_votes_ancestries_idxs: vec![], redundant_votes_ancestries: Default::default(), }; optimizer.verify_justification(finalized_target, context, justification)?; diff --git a/bridges/primitives/header-chain/src/justification/verification/strict.rs b/bridges/primitives/header-chain/src/justification/verification/strict.rs index f899c6c8efc..858cf517a43 100644 --- a/bridges/primitives/header-chain/src/justification/verification/strict.rs +++ b/bridges/primitives/header-chain/src/justification/verification/strict.rs @@ -26,7 +26,7 @@ use crate::justification::verification::{ }; use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::Header as HeaderT; -use sp_std::collections::btree_set::BTreeSet; +use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; /// Verification callbacks that reject all unknown, duplicate or redundant votes. struct StrictJustificationVerifier { @@ -34,6 +34,13 @@ struct StrictJustificationVerifier { } impl JustificationVerifier
for StrictJustificationVerifier { + fn process_duplicate_votes_ancestries( + &mut self, + _duplicate_votes_ancestries: Vec, + ) -> Result<(), Error> { + Err(Error::DuplicateVotesAncestries) + } + fn process_redundant_vote( &mut self, _precommit_idx: usize, diff --git a/bridges/primitives/header-chain/tests/implementation_match.rs b/bridges/primitives/header-chain/tests/implementation_match.rs index f664a419621..1f61f91ff4b 100644 --- a/bridges/primitives/header-chain/tests/implementation_match.rs +++ b/bridges/primitives/header-chain/tests/implementation_match.rs @@ -42,7 +42,7 @@ struct AncestryChain(bp_header_chain::justification::AncestryChain); impl AncestryChain { fn new(justification: &GrandpaJustification) -> Self { - Self(bp_header_chain::justification::AncestryChain::new(justification)) + Self(bp_header_chain::justification::AncestryChain::new(justification).0) } } @@ -58,7 +58,7 @@ impl finality_grandpa::Chain for AncestryChain { if current_hash == base { break } - match self.0.parents.get(¤t_hash) { + match self.0.parent_hash_of(¤t_hash) { Some(parent_hash) => { current_hash = *parent_hash; route.push(current_hash); diff --git a/bridges/primitives/header-chain/tests/justification/optimizer.rs b/bridges/primitives/header-chain/tests/justification/optimizer.rs index 21bcd7e86b5..8d7e2d65025 100644 --- a/bridges/primitives/header-chain/tests/justification/optimizer.rs +++ b/bridges/primitives/header-chain/tests/justification/optimizer.rs @@ -158,6 +158,26 @@ fn unrelated_ancestry_votes_are_removed_by_optimizer() { assert_eq!(num_precommits_before - 1, num_precommits_after); } +#[test] +fn duplicate_votes_ancestries_are_removed_by_optimizer() { + let mut justification = make_default_justification::(&test_header(1)); + let optimized_votes_ancestries = justification.votes_ancestries.clone(); + justification.votes_ancestries = justification + .votes_ancestries + .into_iter() + .flat_map(|item| std::iter::repeat(item).take(3)) + .collect(); + + verify_and_optimize_justification::( + header_id::(1), + &verification_context(TEST_GRANDPA_SET_ID), + &mut justification, + ) + .unwrap(); + + assert_eq!(justification.votes_ancestries, optimized_votes_ancestries); +} + #[test] fn redundant_votes_ancestries_are_removed_by_optimizer() { let mut justification = make_default_justification::(&test_header(1)); diff --git a/bridges/primitives/header-chain/tests/justification/strict.rs b/bridges/primitives/header-chain/tests/justification/strict.rs index 188c9f5baba..639a669572b 100644 --- a/bridges/primitives/header-chain/tests/justification/strict.rs +++ b/bridges/primitives/header-chain/tests/justification/strict.rs @@ -149,7 +149,21 @@ fn justification_with_invalid_authority_signature_rejected() { } #[test] -fn justification_with_invalid_precommit_ancestry() { +fn justification_with_duplicate_votes_ancestry() { + let mut justification = make_default_justification::(&test_header(1)); + justification.votes_ancestries.push(justification.votes_ancestries[0].clone()); + + assert_eq!( + verify_justification::( + header_id::(1), + &verification_context(TEST_GRANDPA_SET_ID), + &justification, + ), + Err(JustificationVerificationError::DuplicateVotesAncestries), + ); +} +#[test] +fn justification_with_redundant_votes_ancestry() { let mut justification = make_default_justification::(&test_header(1)); justification.votes_ancestries.push(test_header(10)); -- GitLab From 18ae22483bb77b988f7fa60b88ec9c0f66343249 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Thu, 19 Oct 2023 16:52:04 +0300 Subject: [PATCH 334/633] [prdoc] Start BEEFY gadget by default for Polkadot nodes (#1945) Just adding a prdoc for https://github.com/paritytech/polkadot-sdk/pull/1913 --------- Co-authored-by: Adrian Catangiu --- prdoc/pr_1913.prdoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 prdoc/pr_1913.prdoc diff --git a/prdoc/pr_1913.prdoc b/prdoc/pr_1913.prdoc new file mode 100644 index 00000000000..155057054eb --- /dev/null +++ b/prdoc/pr_1913.prdoc @@ -0,0 +1,19 @@ +title: BEEFY on Polkadot + +doc: + - audience: Node Operator + description: | + The BEEFY gadget has been enabled on Polkadot by default. + If experiencing stability issues caused by BEEFY, it can be disabled using `--no-beefy` flag. + BEEFY doesn't (yet) support warp sync. So, attempting to Warp sync as a validator will throw an error. + +migrations: + db: [] + + runtime: [] + +crates: + - name: polkadot-cli + - name: polkadot-service + +host_functions: [] -- GitLab From 961a8fd77ee73511eb6ee1acee7446d35bb90dca Mon Sep 17 00:00:00 2001 From: Chevdor Date: Thu, 19 Oct 2023 19:26:09 +0200 Subject: [PATCH 335/633] Pin PRDoc image to v0.0.5 until we are ready for v0.0.6 (#1947) This PR prevents failures until #1946 is merged. --- .github/workflows/check-prdoc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index 3bb9a4fcabf..690f7a3f133 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -5,7 +5,7 @@ on: types: [labeled, opened, synchronize, unlabeled] env: - IMAGE: paritytech/prdoc:latest + IMAGE: paritytech/prdoc:v0.0.5 API_BASE: https://api.github.com/repos REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -- GitLab From b967ba53d3a3b22e0b87e586f017eecb381db71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 19 Oct 2023 21:45:33 +0200 Subject: [PATCH 336/633] Do not force collators to update after enabling async backing (#1920) The validators are checking if async backing is enabled by checking the version of the runtime api. If the runtime api is upgraded by a runtime upgrade, the validators start to also enable the async backing logic. However, just because async backing is enabled, it doesn't mean that all collators and parachain runtimes have upgraded. This pull request fixes an issue about advertising collations to the relay chain when it has async backing enabled, but the collator is still using the old networking protocol. The implementation is actually backwards compatible as we can not expect that everyone directly upgrades. However, the collation advertisement logic was requiring V2 networking messages after async backing was enabled, which was wrong. This is now fixed by this pull request. Closes: https://github.com/paritytech/polkadot-sdk/issues/1923 --------- Co-authored-by: eskimor --- .../src/validator_side/collation.rs | 7 + .../src/validator_side/mod.rs | 161 +++++++++++------- .../src/validator_side/tests/mod.rs | 43 ++++- .../tests/prospective_parachains.rs | 158 ++++++++++++++--- 4 files changed, 268 insertions(+), 101 deletions(-) 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 a53e0028b9e..d6f34fc81b8 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -31,6 +31,7 @@ use std::{collections::VecDeque, future::Future, pin::Pin, task::Poll}; use futures::{future::BoxFuture, FutureExt}; use polkadot_node_network_protocol::{ + peer_set::CollationVersion, request_response::{outgoing::RequestError, v1 as request_v1, OutgoingResult}, PeerId, }; @@ -160,6 +161,8 @@ pub fn fetched_collation_sanity_check( pub struct CollationEvent { /// Collator id. pub collator_id: CollatorId, + /// The network protocol version the collator is using. + pub collator_protocol_version: CollationVersion, /// The requested collation data. pub pending_collation: PendingCollation, } @@ -307,6 +310,8 @@ pub(super) struct CollationFetchRequest { pub pending_collation: PendingCollation, /// Collator id. pub collator_id: CollatorId, + /// The network protocol version the collator is using. + pub collator_protocol_version: CollationVersion, /// Responses from collator. pub from_collator: BoxFuture<'static, OutgoingResult>, /// Handle used for checking if this request was cancelled. @@ -334,6 +339,7 @@ impl Future for CollationFetchRequest { self.span.as_mut().map(|s| s.add_string_tag("success", "false")); return Poll::Ready(( CollationEvent { + collator_protocol_version: self.collator_protocol_version, collator_id: self.collator_id.clone(), pending_collation: self.pending_collation, }, @@ -344,6 +350,7 @@ impl Future for CollationFetchRequest { let res = self.from_collator.poll_unpin(cx).map(|res| { ( CollationEvent { + collator_protocol_version: self.collator_protocol_version, collator_id: self.collator_id.clone(), pending_collation: self.pending_collation, }, 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 fcb408d54b1..00bf50013a5 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -85,6 +85,8 @@ const COST_NETWORK_ERROR: Rep = Rep::CostMinor("Some network error"); const COST_INVALID_SIGNATURE: Rep = Rep::Malicious("Invalid network message signature"); const COST_REPORT_BAD: Rep = Rep::Malicious("A collator was reported by another subsystem"); const COST_WRONG_PARA: Rep = Rep::Malicious("A collator provided a collation for the wrong para"); +const COST_PROTOCOL_MISUSE: Rep = + Rep::Malicious("A collator advertising a collation for an async backing relay parent using V1"); const COST_UNNEEDED_COLLATOR: Rep = Rep::CostMinor("An unneeded collator connected"); const BENEFIT_NOTIFY_GOOD: Rep = Rep::BenefitMinor("A collator was noted good by another subsystem"); @@ -144,9 +146,6 @@ enum InsertAdvertisementError { UndeclaredCollator, /// A limit for announcements per peer is reached. PeerLimitReached, - /// Mismatch of relay parent mode and advertisement arguments. - /// An internal error that should not happen. - ProtocolMismatch, } #[derive(Debug)] @@ -252,23 +251,41 @@ impl PeerData { }, ( ProspectiveParachainsMode::Enabled { max_candidate_depth, .. }, - Some(candidate_hash), + candidate_hash, ) => { - if state - .advertisements - .get(&on_relay_parent) - .map_or(false, |candidates| candidates.contains(&candidate_hash)) - { - return Err(InsertAdvertisementError::Duplicate) - } - let candidates = state.advertisements.entry(on_relay_parent).or_default(); - - if candidates.len() > max_candidate_depth { - return Err(InsertAdvertisementError::PeerLimitReached) - } - candidates.insert(candidate_hash); + if let Some(candidate_hash) = candidate_hash { + if state + .advertisements + .get(&on_relay_parent) + .map_or(false, |candidates| candidates.contains(&candidate_hash)) + { + return Err(InsertAdvertisementError::Duplicate) + } + + let candidates = + state.advertisements.entry(on_relay_parent).or_default(); + + if candidates.len() > max_candidate_depth { + return Err(InsertAdvertisementError::PeerLimitReached) + } + candidates.insert(candidate_hash); + } else { + if self.version != CollationVersion::V1 { + gum::error!( + target: LOG_TARGET, + "Programming error, `candidate_hash` can not be `None` \ + for non `V1` networking.", + ); + } + + if state.advertisements.contains_key(&on_relay_parent) { + return Err(InsertAdvertisementError::Duplicate) + } + state + .advertisements + .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); + }; }, - _ => return Err(InsertAdvertisementError::ProtocolMismatch), } state.last_active = Instant::now(); @@ -705,6 +722,7 @@ async fn request_collation( let collation_request = CollationFetchRequest { pending_collation, collator_id: collator_id.clone(), + collator_protocol_version: peer_protocol_version, from_collator: response_recv.boxed(), cancellation_token: cancellation_token.clone(), span: state @@ -920,10 +938,11 @@ enum AdvertisementError { UndeclaredCollator, /// We're assigned to a different para at the given relay parent. InvalidAssignment, - /// An advertisement format doesn't match the relay parent. - ProtocolMismatch, /// Para reached a limit of seconded candidates for this relay parent. SecondedLimitReached, + /// Collator trying to advertise a collation using V1 protocol for an async backing relay + /// parent. + ProtocolMisuse, /// Advertisement is invalid. Invalid(InsertAdvertisementError), } @@ -933,8 +952,9 @@ impl AdvertisementError { use AdvertisementError::*; match self { InvalidAssignment => Some(COST_WRONG_PARA), + ProtocolMisuse => Some(COST_PROTOCOL_MISUSE), RelayParentUnknown | UndeclaredCollator | Invalid(_) => Some(COST_UNEXPECTED_MESSAGE), - UnknownPeer | ProtocolMismatch | SecondedLimitReached => None, + UnknownPeer | SecondedLimitReached => None, } } } @@ -1042,6 +1062,13 @@ where .get(&relay_parent) .map(|s| s.child("advertise-collation")); + let peer_data = state.peer_data.get_mut(&peer_id).ok_or(AdvertisementError::UnknownPeer)?; + + if peer_data.version == CollationVersion::V1 && !state.active_leaves.contains_key(&relay_parent) + { + return Err(AdvertisementError::ProtocolMisuse) + } + let per_relay_parent = state .per_relay_parent .get(&relay_parent) @@ -1050,20 +1077,12 @@ where let relay_parent_mode = per_relay_parent.prospective_parachains_mode; let assignment = &per_relay_parent.assignment; - let peer_data = state.peer_data.get_mut(&peer_id).ok_or(AdvertisementError::UnknownPeer)?; let collator_para_id = peer_data.collating_para().ok_or(AdvertisementError::UndeclaredCollator)?; - match assignment.current { - Some(id) if id == collator_para_id => { - // Our assignment. - }, - _ => return Err(AdvertisementError::InvalidAssignment), - }; - - if relay_parent_mode.is_enabled() && prospective_candidate.is_none() { - // Expected v2 advertisement. - return Err(AdvertisementError::ProtocolMismatch) + // Check if this is assigned to us. + if assignment.current.map_or(true, |id| id != collator_para_id) { + return Err(AdvertisementError::InvalidAssignment) } // Always insert advertisements that pass all the checks for spam protection. @@ -1077,13 +1096,17 @@ where &state.active_leaves, ) .map_err(AdvertisementError::Invalid)?; + if !per_relay_parent.collations.is_seconded_limit_reached(relay_parent_mode) { return Err(AdvertisementError::SecondedLimitReached) } if let Some((candidate_hash, parent_head_data_hash)) = prospective_candidate { - let is_seconding_allowed = !relay_parent_mode.is_enabled() || - can_second( + // We need to queue the advertisement if we are not allowed to second it. + // + // This is also only important when async backing is enabled. + let queue_advertisement = relay_parent_mode.is_enabled() && + !can_second( sender, collator_para_id, relay_parent, @@ -1092,7 +1115,7 @@ where ) .await; - if !is_seconding_allowed { + if queue_advertisement { gum::debug!( target: LOG_TARGET, relay_parent = ?relay_parent, @@ -1125,6 +1148,7 @@ where prospective_candidate, ) .await; + if let Err(fetch_error) = result { gum::debug!( target: LOG_TARGET, @@ -1477,7 +1501,7 @@ async fn process_msg( }, }; let fetched_collation = FetchedCollation::from(&receipt.to_plain()); - if let Some(CollationEvent { collator_id, pending_collation }) = + if let Some(CollationEvent { collator_id, pending_collation, .. }) = state.fetched_candidates.remove(&fetched_collation) { let PendingCollation { relay_parent, peer_id, prospective_candidate, .. } = @@ -1635,7 +1659,7 @@ async fn run_inner( Ok(res) => res }; - let CollationEvent {collator_id, pending_collation} = res.collation_event.clone(); + let CollationEvent {collator_id, pending_collation, .. } = res.collation_event.clone(); if let Err(err) = kick_off_seconding(&mut ctx, &mut state, res).await { gum::warn!( target: LOG_TARGET, @@ -1783,39 +1807,39 @@ async fn kick_off_seconding( }, }; let collations = &mut per_relay_parent.collations; - let relay_parent_mode = per_relay_parent.prospective_parachains_mode; let fetched_collation = FetchedCollation::from(&candidate_receipt); if let Entry::Vacant(entry) = state.fetched_candidates.entry(fetched_collation) { collation_event.pending_collation.commitments_hash = Some(candidate_receipt.commitments_hash); - let pvd = - match (relay_parent_mode, collation_event.pending_collation.prospective_candidate) { - ( - ProspectiveParachainsMode::Enabled { .. }, - Some(ProspectiveCandidate { parent_head_data_hash, .. }), - ) => - request_prospective_validation_data( - ctx.sender(), - relay_parent, - parent_head_data_hash, - pending_collation.para_id, - ) - .await?, - (ProspectiveParachainsMode::Disabled, _) => - request_persisted_validation_data( - ctx.sender(), - candidate_receipt.descriptor().relay_parent, - candidate_receipt.descriptor().para_id, - ) - .await?, - _ => { - // `handle_advertisement` checks for protocol mismatch. - return Ok(()) - }, - } - .ok_or(SecondingError::PersistedValidationDataNotFound)?; + let pvd = match ( + collation_event.collator_protocol_version, + collation_event.pending_collation.prospective_candidate, + ) { + (CollationVersion::V2, Some(ProspectiveCandidate { parent_head_data_hash, .. })) + if per_relay_parent.prospective_parachains_mode.is_enabled() => + request_prospective_validation_data( + ctx.sender(), + relay_parent, + parent_head_data_hash, + pending_collation.para_id, + ) + .await?, + // Support V2 collators without async backing enabled. + (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => + request_persisted_validation_data( + ctx.sender(), + candidate_receipt.descriptor().relay_parent, + candidate_receipt.descriptor().para_id, + ) + .await?, + _ => { + // `handle_advertisement` checks for protocol mismatch. + return Ok(()) + }, + } + .ok_or(SecondingError::PersistedValidationDataNotFound)?; fetched_collation_sanity_check( &collation_event.pending_collation, @@ -1864,7 +1888,8 @@ async fn handle_collation_fetch_response( network_error_freq: &mut gum::Freq, canceled_freq: &mut gum::Freq, ) -> std::result::Result> { - let (CollationEvent { collator_id, pending_collation }, response) = response; + let (CollationEvent { collator_id, collator_protocol_version, pending_collation }, response) = + response; // Remove the cancellation handle, as the future already completed. state.collation_requests_cancel_handles.remove(&pending_collation); @@ -1970,7 +1995,11 @@ async fn handle_collation_fetch_response( metrics_result = Ok(()); Ok(PendingCollationFetch { - collation_event: CollationEvent { collator_id, pending_collation }, + collation_event: CollationEvent { + collator_id, + pending_collation, + collator_protocol_version, + }, candidate_receipt, pov, }) 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 9812998aab7..3a974014994 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 @@ -269,15 +269,15 @@ async fn assert_candidate_backing_second( expected_relay_parent: Hash, expected_para_id: ParaId, expected_pov: &PoV, - mode: ProspectiveParachainsMode, + version: CollationVersion, ) -> CandidateReceipt { let pvd = dummy_pvd(); // Depending on relay parent mode pvd will be either requested // from the Runtime API or Prospective Parachains. let msg = overseer_recv(virtual_overseer).await; - match mode { - ProspectiveParachainsMode::Disabled => assert_matches!( + match version { + CollationVersion::V1 => assert_matches!( msg, AllMessages::RuntimeApi(RuntimeApiMessage::Request( hash, @@ -289,7 +289,7 @@ async fn assert_candidate_backing_second( tx.send(Ok(Some(pvd.clone()))).unwrap(); } ), - ProspectiveParachainsMode::Enabled { .. } => assert_matches!( + CollationVersion::V2 => assert_matches!( msg, AllMessages::ProspectiveParachains( ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), @@ -532,7 +532,14 @@ fn act_on_advertisement_v2() { ) .await; - let candidate_hash = CandidateHash::default(); + let pov = PoV { block_data: BlockData(vec![]) }; + let mut candidate_a = + dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); + candidate_a.descriptor.para_id = test_state.chain_ids[0]; + candidate_a.descriptor.relay_parent = test_state.relay_parent; + candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); + + let candidate_hash = candidate_a.hash(); let parent_head_data_hash = Hash::zero(); // v2 advertisement. advertise_collation( @@ -543,7 +550,7 @@ fn act_on_advertisement_v2() { ) .await; - assert_fetch_collation_request( + let response_channel = assert_fetch_collation_request( &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], @@ -551,6 +558,24 @@ fn act_on_advertisement_v2() { ) .await; + response_channel + .send(Ok(request_v1::CollationFetchingResponse::Collation( + candidate_a.clone(), + pov.clone(), + ) + .encode())) + .expect("Sending response should succeed"); + + assert_candidate_backing_second( + &mut virtual_overseer, + test_state.relay_parent, + test_state.chain_ids[0], + &pov, + // Async backing isn't enabled and thus it should do it the old way. + CollationVersion::V1, + ) + .await; + virtual_overseer }); } @@ -748,7 +773,7 @@ fn fetch_one_collation_at_a_time() { test_state.relay_parent, test_state.chain_ids[0], &pov, - ProspectiveParachainsMode::Disabled, + CollationVersion::V1, ) .await; @@ -880,7 +905,7 @@ fn fetches_next_collation() { second, test_state.chain_ids[0], &pov, - ProspectiveParachainsMode::Disabled, + CollationVersion::V1, ) .await; @@ -1010,7 +1035,7 @@ fn fetch_next_collation_on_invalid_collation() { test_state.relay_parent, test_state.chain_ids[0], &pov, - ProspectiveParachainsMode::Disabled, + CollationVersion::V1, ) .await; diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index 4da0f11da39..c5236ef3eb2 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 @@ -74,7 +74,7 @@ async fn assert_assign_incoming( } /// Handle a view update. -async fn update_view( +pub(super) async fn update_view( virtual_overseer: &mut VirtualOverseer, test_state: &TestState, new_view: Vec<(Hash, u32)>, // Hash and block number. @@ -212,6 +212,7 @@ async fn assert_collation_seconded( virtual_overseer: &mut VirtualOverseer, relay_parent: Hash, peer_id: PeerId, + version: CollationVersion, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -222,29 +223,51 @@ async fn assert_collation_seconded( assert_eq!(rep.value, BENEFIT_NOTIFY_GOOD.cost_or_benefit()); } ); - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( - peers, - Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( - protocol_v2::CollatorProtocolMessage::CollationSeconded( - _relay_parent, - .., - ), - )), - )) => { - assert_eq!(peers, vec![peer_id]); - assert_eq!(relay_parent, _relay_parent); - } - ); + + match version { + CollationVersion::V1 => { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( + peers, + Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol( + protocol_v1::CollatorProtocolMessage::CollationSeconded( + _relay_parent, + .., + ), + )), + )) => { + assert_eq!(peers, vec![peer_id]); + assert_eq!(relay_parent, _relay_parent); + } + ); + }, + CollationVersion::V2 => { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( + peers, + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( + protocol_v2::CollatorProtocolMessage::CollationSeconded( + _relay_parent, + .., + ), + )), + )) => { + assert_eq!(peers, vec![peer_id]); + assert_eq!(relay_parent, _relay_parent); + } + ); + }, + } } #[test] -fn v1_advertisement_rejected() { +fn v1_advertisement_accepted_and_seconded() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; + let TestHarness { mut virtual_overseer, keystore } = test_harness; let pair_a = CollatorPair::generate().0; @@ -267,9 +290,94 @@ fn v1_advertisement_rejected() { advertise_collation(&mut virtual_overseer, peer_a, head_b, None).await; - // Not reported. - test_helpers::Yield::new().await; - assert_matches!(virtual_overseer.recv().now_or_never(), None); + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + None, + ) + .await; + + let mut candidate = dummy_candidate_receipt_bad_sig(head_b, Some(Default::default())); + candidate.descriptor.para_id = test_state.chain_ids[0]; + candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); + let commitments = CandidateCommitments { + head_data: HeadData(vec![1 as u8]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate.commitments_hash = commitments.hash(); + + let pov = PoV { block_data: BlockData(vec![1]) }; + + response_channel + .send(Ok(request_v2::CollationFetchingResponse::Collation( + candidate.clone(), + pov.clone(), + ) + .encode())) + .expect("Sending response should succeed"); + + assert_candidate_backing_second( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + &pov, + CollationVersion::V1, + ) + .await; + + let candidate = CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; + + send_seconded_statement(&mut virtual_overseer, keystore.clone(), &candidate).await; + + assert_collation_seconded(&mut virtual_overseer, head_b, peer_a, CollationVersion::V1) + .await; + + virtual_overseer + }); +} + +#[test] +fn v1_advertisement_rejected_on_non_active_leave() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 5; + + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + + // Accept both collators from the implicit view. + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::V1, + ) + .await; + + advertise_collation(&mut virtual_overseer, peer_a, get_parent_hash(head_b), None).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep)), + ) => { + assert_eq!(peer, peer_a); + assert_eq!(rep.value, COST_PROTOCOL_MISUSE.cost_or_benefit()); + } + ); virtual_overseer }); @@ -469,10 +577,7 @@ fn second_multiple_candidates_per_relay_parent() { head_c, test_state.chain_ids[0], &pov, - ProspectiveParachainsMode::Enabled { - max_candidate_depth: ASYNC_BACKING_PARAMETERS.max_candidate_depth as _, - allowed_ancestry_len: ASYNC_BACKING_PARAMETERS.allowed_ancestry_len as _, - }, + CollationVersion::V2, ) .await; @@ -481,7 +586,8 @@ fn second_multiple_candidates_per_relay_parent() { send_seconded_statement(&mut virtual_overseer, keystore.clone(), &candidate).await; - assert_collation_seconded(&mut virtual_overseer, head_c, peer_a).await; + assert_collation_seconded(&mut virtual_overseer, head_c, peer_a, CollationVersion::V2) + .await; } // No more advertisements can be made for this relay parent. -- GitLab From e1e03813806c3fa093a52302abf456ff25c0e6a8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 20 Oct 2023 00:47:54 +0200 Subject: [PATCH 337/633] Expose prometheus metrics for minimal-relay-chain node in collators (#1942) Until now prometheus metrics were not exposed by the minimal relay chain node. Also slight cleanups. --- Cargo.lock | 1 + .../relay-chain-minimal-node/Cargo.toml | 1 + .../src/collator_overseer.rs | 3 -- .../relay-chain-minimal-node/src/lib.rs | 28 +++++++++++-------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 033219583bd..131ba788278 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3899,6 +3899,7 @@ dependencies = [ "sp-consensus", "sp-consensus-babe", "sp-runtime", + "substrate-prometheus-endpoint", "tracing", ] diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 226474d3d38..51889865944 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -23,6 +23,7 @@ sc-authority-discovery = { path = "../../../substrate/client/authority-discovery sc-network = { path = "../../../substrate/client/network" } sc-network-common = { path = "../../../substrate/client/network/common" } sc-service = { path = "../../../substrate/client/service" } +substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } sc-tracing = { path = "../../../substrate/client/tracing" } sc-utils = { path = "../../../substrate/client/utils" } sp-api = { path = "../../../substrate/primitives/api" } 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 a83a18f7cd9..49332cc350f 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -44,7 +44,6 @@ use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_network::NetworkStateInfo; use sc_service::TaskManager; use sc_utils::mpsc::tracing_unbounded; -use sp_runtime::traits::Block as BlockT; use cumulus_primitives_core::relay_chain::{Block, Hash as PHash}; use cumulus_relay_chain_interface::RelayChainError; @@ -209,8 +208,6 @@ pub struct NewMinimalNode { pub task_manager: TaskManager, /// Overseer handle to interact with subsystems pub overseer_handle: Handle, - /// Network service - pub network: Arc::Hash>>, } /// Glues together the [`Overseer`] and `BlockchainEvents` by forwarding diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 08e4e8e34ab..c8fba923dde 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -32,10 +32,10 @@ use polkadot_primitives::CollatorPair; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_network::{config::FullNetworkConfiguration, Event, NetworkEventStream, NetworkService}; -use sc_service::{Configuration, TaskManager}; +use sc_service::{config::PrometheusConfig, Configuration, TaskManager}; use sp_runtime::{app_crypto::Pair, traits::Block as BlockT}; -use futures::StreamExt; +use futures::{FutureExt, StreamExt}; use std::sync::Arc; mod blockchain_rpc_client; @@ -69,7 +69,7 @@ fn build_authority_discovery_service( ..Default::default() }, client, - network.clone(), + network, Box::pin(dht_event_stream), authority_discovery_role, prometheus_registry, @@ -160,12 +160,16 @@ async fn new_minimal_relay_chain( let role = config.role.clone(); let mut net_config = sc_network::config::FullNetworkConfiguration::new(&config.network); - let task_manager = { - let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); - TaskManager::new(config.tokio_handle.clone(), registry)? - }; + let prometheus_registry = config.prometheus_registry(); + let task_manager = TaskManager::new(config.tokio_handle.clone(), prometheus_registry)?; - let prometheus_registry = config.prometheus_registry().cloned(); + if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() { + task_manager.spawn_handle().spawn( + "prometheus-endpoint", + None, + substrate_prometheus_endpoint::init_prometheus(port, registry).map(drop), + ); + } let genesis_hash = relay_chain_rpc_client .block_get_hash(Some(0)) @@ -203,18 +207,18 @@ async fn new_minimal_relay_chain( relay_chain_rpc_client.clone(), &config, network.clone(), - prometheus_registry.clone(), + prometheus_registry.cloned(), ); let overseer_args = CollatorOverseerGenArgs { runtime_client: relay_chain_rpc_client.clone(), - network_service: network.clone(), + network_service: network, sync_oracle, authority_discovery_service, collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver, - registry: prometheus_registry.as_ref(), + registry: prometheus_registry, spawner: task_manager.spawn_handle(), collator_pair, req_protocol_names: request_protocol_names, @@ -226,7 +230,7 @@ async fn new_minimal_relay_chain( network_starter.start_network(); - Ok(NewMinimalNode { task_manager, overseer_handle, network }) + Ok(NewMinimalNode { task_manager, overseer_handle }) } fn build_request_response_protocol_receivers( -- GitLab From f4c4c0fe29300f765e3edd32c79ac0c856fa4bb8 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 20 Oct 2023 05:13:19 +0200 Subject: [PATCH 338/633] Switch trie cache random seed (#1935) Use a more secure seed for hashsets of cache. --- Cargo.lock | 1 + substrate/primitives/trie/Cargo.toml | 2 ++ substrate/primitives/trie/src/cache/shared_cache.rs | 6 +++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 131ba788278..3c533c4300b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17527,6 +17527,7 @@ dependencies = [ "nohash-hasher", "parity-scale-codec", "parking_lot 0.12.1", + "rand 0.8.5", "scale-info", "schnellru", "sp-core", diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 0b54514f600..1ef4318c51f 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -26,6 +26,7 @@ lazy_static = { version = "1.4.0", optional = true } memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } +rand = { version = "0.8", optional = true } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } @@ -53,6 +54,7 @@ std = [ "memory-db/std", "nohash-hasher", "parking_lot", + "rand", "scale-info/std", "schnellru", "sp-core/std", diff --git a/substrate/primitives/trie/src/cache/shared_cache.rs b/substrate/primitives/trie/src/cache/shared_cache.rs index 28b3274fde1..01ac41a1e47 100644 --- a/substrate/primitives/trie/src/cache/shared_cache.rs +++ b/substrate/primitives/trie/src/cache/shared_cache.rs @@ -30,7 +30,11 @@ use std::{ use trie_db::{node::NodeOwned, CachedValue}; lazy_static::lazy_static! { - static ref RANDOM_STATE: ahash::RandomState = ahash::RandomState::default(); + static ref RANDOM_STATE: ahash::RandomState = { + use rand::Rng; + let mut rng = rand::thread_rng(); + ahash::RandomState::generate_with(rng.gen(), rng.gen(), rng.gen(), rng.gen()) + }; } pub struct SharedNodeCacheLimiter { -- GitLab From f0d443a055ee7a6f6e0b0d4cfea2f98fe98d0864 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 20 Oct 2023 11:08:25 +0200 Subject: [PATCH 339/633] Remove some dbgs (#1949) Removed some debug logs --- .../parachains/integration-tests/emulated/common/src/macros.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 5ce94026402..a65b2057afd 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -36,9 +36,6 @@ macro_rules! test_parachain_is_trusted_teleporter { let beneficiary: MultiLocation = $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - dbg!(&origin); - dbg!(¶_destination); - // 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. -- GitLab From f3bf5c1acdccf953774ee055a8a0465e1e2a3475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 20 Oct 2023 11:21:19 +0200 Subject: [PATCH 340/633] `xcm`: Change `TypeInfo::path` to not include `staging` (#1948) The `xcm` crate was renamed to `staging-xcm` to be able to publish it to crates.io as someone as squatted `xcm`. The problem with this rename is that the `TypeInfo` includes the crate name which ultimately lands in the metadata. The metadata is consumed by downstream users like `polkadot-js` or people building on top of `polkadot-js`. These people are using the entire `path` to find the type in the type registry. Thus, their code would break as the type path would now be [`staging_xcm`, `VersionedXcm`] instead of [`xcm`, `VersionedXcm`]. This pull request fixes this by renaming the path segment `staging_xcm` to `xcm`. This requires: https://github.com/paritytech/scale-info/pull/197 --------- Co-authored-by: Francisco Aguirre --- Cargo.lock | 8 ++++---- bridges/bin/runtime-common/Cargo.toml | 2 +- bridges/modules/grandpa/Cargo.toml | 2 +- bridges/modules/messages/Cargo.toml | 2 +- bridges/modules/parachains/Cargo.toml | 2 +- bridges/modules/relayers/Cargo.toml | 2 +- bridges/modules/xcm-bridge-hub-router/Cargo.toml | 2 +- bridges/primitives/chain-asset-hub-kusama/Cargo.toml | 2 +- bridges/primitives/chain-asset-hub-polkadot/Cargo.toml | 2 +- bridges/primitives/chain-asset-hub-rococo/Cargo.toml | 2 +- bridges/primitives/chain-asset-hub-wococo/Cargo.toml | 2 +- bridges/primitives/chain-polkadot-bulletin/Cargo.toml | 2 +- bridges/primitives/header-chain/Cargo.toml | 2 +- bridges/primitives/messages/Cargo.toml | 2 +- bridges/primitives/parachains/Cargo.toml | 2 +- bridges/primitives/polkadot-core/Cargo.toml | 2 +- bridges/primitives/relayers/Cargo.toml | 2 +- bridges/primitives/runtime/Cargo.toml | 2 +- bridges/primitives/xcm-bridge-hub-router/Cargo.toml | 2 +- cumulus/pallets/aura-ext/Cargo.toml | 2 +- cumulus/pallets/collator-selection/Cargo.toml | 2 +- cumulus/pallets/dmp-queue/Cargo.toml | 2 +- cumulus/pallets/parachain-system/Cargo.toml | 2 +- cumulus/pallets/solo-to-para/Cargo.toml | 2 +- cumulus/pallets/xcm/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/Cargo.toml | 2 +- cumulus/parachain-template/pallets/template/Cargo.toml | 2 +- cumulus/parachain-template/runtime/Cargo.toml | 2 +- cumulus/parachains/common/Cargo.toml | 2 +- cumulus/parachains/pallets/collective-content/Cargo.toml | 2 +- cumulus/parachains/pallets/parachain-info/Cargo.toml | 2 +- cumulus/parachains/pallets/ping/Cargo.toml | 2 +- .../runtimes/assets/asset-hub-kusama/Cargo.toml | 2 +- .../runtimes/assets/asset-hub-polkadot/Cargo.toml | 2 +- .../runtimes/assets/asset-hub-rococo/Cargo.toml | 2 +- .../runtimes/assets/asset-hub-westend/Cargo.toml | 2 +- cumulus/parachains/runtimes/assets/common/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../runtimes/collectives/collectives-polkadot/Cargo.toml | 2 +- .../runtimes/contracts/contracts-rococo/Cargo.toml | 2 +- .../runtimes/glutton/glutton-kusama/Cargo.toml | 2 +- cumulus/parachains/runtimes/starters/seedling/Cargo.toml | 2 +- cumulus/parachains/runtimes/starters/shell/Cargo.toml | 2 +- cumulus/parachains/runtimes/testing/penpal/Cargo.toml | 2 +- .../runtimes/testing/rococo-parachain/Cargo.toml | 2 +- cumulus/primitives/core/Cargo.toml | 2 +- cumulus/primitives/parachain-inherent/Cargo.toml | 2 +- cumulus/test/runtime/Cargo.toml | 2 +- polkadot/core-primitives/Cargo.toml | 2 +- polkadot/parachain/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- polkadot/xcm/src/double_encoded.rs | 1 + polkadot/xcm/src/lib.rs | 3 +++ polkadot/xcm/src/tests.rs | 9 +++++++++ polkadot/xcm/src/v2/junction.rs | 1 + polkadot/xcm/src/v2/mod.rs | 8 ++++++++ polkadot/xcm/src/v2/multiasset.rs | 8 ++++++++ polkadot/xcm/src/v2/multilocation.rs | 2 ++ polkadot/xcm/src/v2/traits.rs | 3 +++ polkadot/xcm/src/v3/junction.rs | 4 ++++ polkadot/xcm/src/v3/junctions.rs | 1 + polkadot/xcm/src/v3/mod.rs | 7 +++++++ polkadot/xcm/src/v3/multiasset.rs | 8 ++++++++ polkadot/xcm/src/v3/traits.rs | 3 +++ polkadot/xcm/xcm-builder/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 2 +- substrate/bin/node-template/pallets/template/Cargo.toml | 2 +- substrate/bin/node-template/runtime/Cargo.toml | 2 +- substrate/bin/node/executor/Cargo.toml | 2 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/frame/alliance/Cargo.toml | 2 +- substrate/frame/asset-conversion/Cargo.toml | 2 +- substrate/frame/asset-rate/Cargo.toml | 2 +- substrate/frame/assets/Cargo.toml | 2 +- substrate/frame/atomic-swap/Cargo.toml | 2 +- substrate/frame/aura/Cargo.toml | 2 +- substrate/frame/authority-discovery/Cargo.toml | 2 +- substrate/frame/authorship/Cargo.toml | 2 +- substrate/frame/babe/Cargo.toml | 2 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 2 +- substrate/frame/beefy-mmr/Cargo.toml | 2 +- substrate/frame/beefy/Cargo.toml | 2 +- substrate/frame/benchmarking/Cargo.toml | 2 +- substrate/frame/benchmarking/pov/Cargo.toml | 2 +- substrate/frame/bounties/Cargo.toml | 2 +- substrate/frame/broker/Cargo.toml | 2 +- substrate/frame/child-bounties/Cargo.toml | 2 +- substrate/frame/collective/Cargo.toml | 2 +- substrate/frame/contracts/Cargo.toml | 2 +- substrate/frame/contracts/primitives/Cargo.toml | 2 +- substrate/frame/conviction-voting/Cargo.toml | 2 +- substrate/frame/core-fellowship/Cargo.toml | 2 +- substrate/frame/democracy/Cargo.toml | 2 +- substrate/frame/election-provider-multi-phase/Cargo.toml | 2 +- .../test-staking-e2e/Cargo.toml | 2 +- substrate/frame/election-provider-support/Cargo.toml | 2 +- .../election-provider-support/solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- substrate/frame/elections-phragmen/Cargo.toml | 2 +- substrate/frame/examples/basic/Cargo.toml | 2 +- substrate/frame/examples/default-config/Cargo.toml | 2 +- substrate/frame/examples/dev-mode/Cargo.toml | 2 +- substrate/frame/examples/kitchensink/Cargo.toml | 2 +- substrate/frame/examples/offchain-worker/Cargo.toml | 2 +- substrate/frame/examples/split/Cargo.toml | 2 +- substrate/frame/executive/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/glutton/Cargo.toml | 2 +- substrate/frame/grandpa/Cargo.toml | 2 +- substrate/frame/identity/Cargo.toml | 2 +- substrate/frame/im-online/Cargo.toml | 2 +- substrate/frame/indices/Cargo.toml | 2 +- .../frame/insecure-randomness-collective-flip/Cargo.toml | 2 +- substrate/frame/lottery/Cargo.toml | 2 +- substrate/frame/membership/Cargo.toml | 2 +- substrate/frame/merkle-mountain-range/Cargo.toml | 2 +- substrate/frame/message-queue/Cargo.toml | 2 +- substrate/frame/mixnet/Cargo.toml | 2 +- substrate/frame/multisig/Cargo.toml | 2 +- substrate/frame/nft-fractionalization/Cargo.toml | 2 +- substrate/frame/nfts/Cargo.toml | 2 +- substrate/frame/nicks/Cargo.toml | 2 +- substrate/frame/nis/Cargo.toml | 2 +- substrate/frame/node-authorization/Cargo.toml | 2 +- substrate/frame/nomination-pools/Cargo.toml | 2 +- substrate/frame/nomination-pools/benchmarking/Cargo.toml | 2 +- substrate/frame/nomination-pools/test-staking/Cargo.toml | 2 +- substrate/frame/offences/Cargo.toml | 2 +- substrate/frame/offences/benchmarking/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/preimage/Cargo.toml | 2 +- substrate/frame/proxy/Cargo.toml | 2 +- substrate/frame/ranked-collective/Cargo.toml | 2 +- substrate/frame/recovery/Cargo.toml | 2 +- substrate/frame/referenda/Cargo.toml | 2 +- substrate/frame/remark/Cargo.toml | 2 +- substrate/frame/root-offences/Cargo.toml | 2 +- substrate/frame/root-testing/Cargo.toml | 2 +- substrate/frame/safe-mode/Cargo.toml | 2 +- substrate/frame/salary/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/scored-pool/Cargo.toml | 2 +- substrate/frame/session/Cargo.toml | 2 +- substrate/frame/session/benchmarking/Cargo.toml | 2 +- substrate/frame/society/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- substrate/frame/state-trie-migration/Cargo.toml | 2 +- substrate/frame/statement/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 2 +- substrate/frame/support/test/compile_pass/Cargo.toml | 2 +- substrate/frame/support/test/pallet/Cargo.toml | 2 +- substrate/frame/support/test/stg_frame_crate/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/system/benchmarking/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- substrate/frame/tips/Cargo.toml | 2 +- substrate/frame/transaction-payment/Cargo.toml | 2 +- .../asset-conversion-tx-payment/Cargo.toml | 2 +- .../transaction-payment/asset-tx-payment/Cargo.toml | 2 +- substrate/frame/transaction-storage/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 2 +- substrate/frame/uniques/Cargo.toml | 2 +- substrate/frame/utility/Cargo.toml | 2 +- substrate/frame/vesting/Cargo.toml | 2 +- substrate/frame/whitelist/Cargo.toml | 2 +- substrate/primitives/api/Cargo.toml | 2 +- substrate/primitives/api/test/Cargo.toml | 2 +- substrate/primitives/application-crypto/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- substrate/primitives/authority-discovery/Cargo.toml | 2 +- substrate/primitives/consensus/aura/Cargo.toml | 2 +- substrate/primitives/consensus/babe/Cargo.toml | 2 +- substrate/primitives/consensus/beefy/Cargo.toml | 2 +- substrate/primitives/consensus/grandpa/Cargo.toml | 2 +- substrate/primitives/consensus/sassafras/Cargo.toml | 2 +- substrate/primitives/consensus/slots/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/inherents/Cargo.toml | 2 +- substrate/primitives/merkle-mountain-range/Cargo.toml | 2 +- substrate/primitives/metadata-ir/Cargo.toml | 2 +- substrate/primitives/mixnet/Cargo.toml | 2 +- substrate/primitives/npos-elections/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/primitives/session/Cargo.toml | 2 +- substrate/primitives/staking/Cargo.toml | 2 +- substrate/primitives/statement-store/Cargo.toml | 2 +- substrate/primitives/test-primitives/Cargo.toml | 2 +- .../primitives/transaction-storage-proof/Cargo.toml | 2 +- substrate/primitives/trie/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/primitives/weights/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- substrate/utils/frame/rpc/support/Cargo.toml | 2 +- 209 files changed, 257 insertions(+), 199 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c533c4300b..0267a0c1e55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15954,9 +15954,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ "bitvec", "cfg-if", @@ -15968,9 +15968,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index d001e96efe8..0ccf30987e8 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -11,7 +11,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 45adf09af27..dbbe18febc6 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -12,7 +12,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 7b7ea061981..d3d68b33802 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 6e9ca870ce5..0d1b61ddea8 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 46fc3bb43b1..10b60c3006b 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index c61cab291e1..56b9139d7d5 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.8.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies diff --git a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml index adb9a57bc13..3e53f9407ff 100644 --- a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml index 857ead15b0d..9c1b1a1f326 100644 --- a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml index a888700a060..088510adcec 100644 --- a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-wococo/Cargo.toml b/bridges/primitives/chain-asset-hub-wococo/Cargo.toml index 87273228385..e1a5a262157 100644 --- a/bridges/primitives/chain-asset-hub-wococo/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-wococo/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml index 4311aec4727..d748f5aa933 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index e3e83235960..19b2819bddc 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # Bridge dependencies diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index b30d6d2559f..7a61643a0bc 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -8,7 +8,7 @@ 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", "bit-vec"] } -scale-info = { version = "2.9.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # Bridge dependencies diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index ca69523dde3..11e9336f66a 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -9,7 +9,7 @@ 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"] } impl-trait-for-tuples = "0.2" -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index aa7eb8024fb..e2bd4c29522 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -9,7 +9,7 @@ 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"] } parity-util-mem = { version = "0.12.0", optional = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 99cd79c6841..93ad0789263 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -8,7 +8,7 @@ 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", "bit-vec"] } -scale-info = { version = "2.9.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 4454066b59f..48f6722c982 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -12,7 +12,7 @@ hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.19", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # Substrate Dependencies diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 725a7d94564..fb079b48e42 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -8,7 +8,7 @@ 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", "bit-vec"] } -scale-info = { version = "2.9.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index a804edb58b3..78d25f2285e 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -7,7 +7,7 @@ description = "AURA consensus extension pallet for parachains" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 1aba84aa29c..68e4a681c2b 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { version = "0.4.20", default-features = false } codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } rand = { version = "0.8.5", features = ["std_rng"], default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false} sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 9d61a2c99fd..2f3f660ea15 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 64e238ecab6..1b367f94e33 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -12,7 +12,7 @@ environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" log = { version = "0.4.20", default-features = false } trie-db = { version = "0.28.0", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index 6a3fe59b402..af419cc37db 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -7,7 +7,7 @@ description = "Adds functionality to migrate from a Solo to a Parachain" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 229edaaab4c..853dd86bb4c 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false} sp-io = { path = "../../../substrate/primitives/io", default-features = false} diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 034b640a0ed..358a0bec8bb 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -8,7 +8,7 @@ edition.workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.20", default-features = false } rand_chacha = { version = "0.3.0", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index af35ab651dc..92545783934 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } -scale-info = { version = "2.2.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true} diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 68db2f041dd..2e5bdab1e21 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optio codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Local diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 2bdae91ef4d..3393a7a46c1 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -11,7 +11,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { version = "0.4.19", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } num-traits = { version = "0.2", default-features = false} smallvec = "1.11.0" diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index 1c831ac7268..e85112ed8ea 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -7,7 +7,7 @@ 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"] } +scale-info = { version = "2.10.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 } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 931df9d9273..c63101bab91 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../../substrate/frame/system", default-features = false} diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index f0afa63d692..3acad9f371d 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false} sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index eb0f249aaae..dc401e3d8cd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -9,7 +9,7 @@ description = "Kusama variant of Asset Hub parachain runtime" 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index df38e4d9d64..db400f2977f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -9,7 +9,7 @@ description = "Asset Hub Polkadot parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index ba846a850c8..6d20ccc905f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -9,7 +9,7 @@ description = "Rococo variant of Asset Hub parachain runtime" 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index cb5fba1684c..294f7d8413d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -9,7 +9,7 @@ description = "Westend variant of Asset Hub parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 0cd5de2ddcd..56171c7212e 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -7,7 +7,7 @@ description = "Assets common utilities" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.20", default-features = false } impl-trait-for-tuples = "0.2.2" 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 bfb0b9e7127..603e74850cc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" 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 eb0c18f5b46..535a0516997 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" 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 ab56430bc94..5befb21c891 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] } smallvec = "1.11.0" diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index e66cef31e56..73d787caf86 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -9,7 +9,7 @@ description = "Polkadot Collectives Parachain Runtime" 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 448cc4f4160..a020b66baae 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -15,7 +15,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index b419f099815..e8abc61311c 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true} diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index e3375a21715..18bee9982d0 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false} diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 5a1e14e8b11..ef4b62f985d 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false} diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index a7fd4b30b75..13e52f8a3ba 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index a662a5e8066..616d92b6940 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true} diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index fc7573be138..3ce7b1da4a6 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../substrate/primitives/api", default-features = false} diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 39b70f20a97..026d5a61bc8 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] async-trait = { version = "0.1.73", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } tracing = { version = "0.1.37", optional = true } # Substrate diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index dbfe9f46b1b..445de328639 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../substrate/frame/executive", default-features = false} diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 1ee39da30a4..f843ec17943 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive" ] } [features] diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index c44ba02e3ae..681bee3c327 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -11,7 +11,7 @@ version = "1.0.0" # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive" ] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-core = { path = "../../substrate/primitives/core", default-features = false, features = ["serde"] } diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 9d17b70b817..c7c081e2f0e 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } application-crypto = { package = "sp-application-crypto", path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 8af7f11f1d7..18332156d99 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -12,7 +12,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["alloc"] } serde_derive = { version = "1.0.117" } static_assertions = "1.1.0" diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 9f1ec57257f..a3950083373 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -11,7 +11,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } derive_more = "0.99.17" bitflags = "1.3.2" diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index ae68ab7e2d9..6d0dee3e434 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.188", default-features = false } serde_derive = { version = "1.0.117", optional = true } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 2e9c773a3f8..db014a5d864 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -12,7 +12,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false } serde_derive = { version = "1.0.117", optional = true } smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 6fc1f066307..a4f1bfb007e 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -10,7 +10,7 @@ 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"] } +scale-info = { version = "2.10.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 } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index f04f31c3ec1..92024e69c1b 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -12,7 +12,7 @@ derivative = { version = "2.2.0", default-features = false, features = [ "use_co impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } 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", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } xcm-procedural = { path = "procedural" } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 35b0b7dc553..fb4f389b212 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -10,7 +10,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 7e69d5edd2b..e471e8cf269 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] bounded-collections = { version = "0.1.8", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/polkadot/xcm/src/double_encoded.rs b/polkadot/xcm/src/double_encoded.rs index c4c1276fad8..2dc9b012257 100644 --- a/polkadot/xcm/src/double_encoded.rs +++ b/polkadot/xcm/src/double_encoded.rs @@ -24,6 +24,7 @@ use parity_scale_codec::{Decode, DecodeLimit, Encode}; #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(T))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct DoubleEncoded { encoded: Vec, #[codec(skip)] diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index d3e2baf4f8a..d804e4bf735 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -89,6 +89,7 @@ macro_rules! versioned_type { )] #[codec(encode_bound())] #[codec(decode_bound())] + #[scale_info(replace_segment("staging_xcm", "xcm"))] $(#[$attr])* pub enum $n { $(#[$index3])* @@ -150,6 +151,7 @@ macro_rules! versioned_type { )] #[codec(encode_bound())] #[codec(decode_bound())] + #[scale_info(replace_segment("staging_xcm", "xcm"))] $(#[$attr])* pub enum $n { $(#[$index2])* @@ -310,6 +312,7 @@ versioned_type! { #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(RuntimeCall))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum VersionedXcm { #[codec(index = 2)] V2(v2::Xcm), diff --git a/polkadot/xcm/src/tests.rs b/polkadot/xcm/src/tests.rs index 10b14ffec99..a3a60f6477c 100644 --- a/polkadot/xcm/src/tests.rs +++ b/polkadot/xcm/src/tests.rs @@ -181,3 +181,12 @@ fn encode_decode_versioned_xcm_v3() { let decoded = VersionedXcm::decode(&mut &encoded[..]).unwrap(); assert_eq!(xcm, decoded); } + +// With the renaming of the crate to `staging-xcm` the naming in the metadata changed as well and +// this broke downstream users. This test ensures that the name in the metadata isn't changed. +#[test] +fn ensure_type_info_is_correct() { + let type_info = VersionedXcm::<()>::type_info(); + + assert_eq!(type_info.path.segments, vec!["xcm", "VersionedXcm"]); +} diff --git a/polkadot/xcm/src/v2/junction.rs b/polkadot/xcm/src/v2/junction.rs index 73a50299946..771931f4b56 100644 --- a/polkadot/xcm/src/v2/junction.rs +++ b/polkadot/xcm/src/v2/junction.rs @@ -27,6 +27,7 @@ use scale_info::TypeInfo; /// Each item assumes a pre-existing location as its context and is defined in terms of it. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junction { /// An indexed parachain belonging to and operated by the context. /// diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index a81468cd481..7f654ebfd9e 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -81,6 +81,7 @@ pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendR /// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum OriginKind { /// Origin should just be the native dispatch origin representation for the sender in the /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin @@ -105,6 +106,7 @@ pub enum OriginKind { /// A global identifier of an account-bearing consensus system. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum NetworkId { /// Unidentified/any. Any, @@ -141,6 +143,7 @@ impl TryFrom for NetworkId { /// An identifier of a pluralistic body. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyId { /// The only body in its context. Unit, @@ -195,6 +198,7 @@ impl From for BodyId { /// A part of a pluralistic body. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyPart { /// The body's declaration, under whatever means it decides. Voice, @@ -262,6 +266,7 @@ pub type QueryId = u64; #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(RuntimeCall))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct Xcm(pub Vec>); impl Xcm { @@ -357,6 +362,7 @@ pub mod prelude { /// Response data to a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Response { /// No response. Serves as a neutral default. Null, @@ -376,6 +382,7 @@ impl Default for Response { /// An optional weight limit. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WeightLimit { /// No weight limit imposed. Unlimited, @@ -428,6 +435,7 @@ pub type Weight = u64; #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(RuntimeCall))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Instruction { /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding /// Register. diff --git a/polkadot/xcm/src/v2/multiasset.rs b/polkadot/xcm/src/v2/multiasset.rs index fdd7797a123..5681e9ef8a4 100644 --- a/polkadot/xcm/src/v2/multiasset.rs +++ b/polkadot/xcm/src/v2/multiasset.rs @@ -41,6 +41,7 @@ use scale_info::TypeInfo; /// A general identifier for an instance of a non-fungible asset class. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. Undefined, @@ -119,6 +120,7 @@ impl TryFrom for AssetInstance { /// Classification of an asset being concrete or abstract. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetId { Concrete(MultiLocation), Abstract(Vec), @@ -185,6 +187,7 @@ impl AssetId { /// instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Fungibility { Fungible(#[codec(compact)] u128), NonFungible(AssetInstance), @@ -224,6 +227,7 @@ impl TryFrom for Fungibility { #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAsset { pub id: AssetId, pub fun: Fungibility, @@ -309,6 +313,7 @@ impl TryFrom for MultiAsset { /// they must be sorted. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAssets(Vec); impl Decode for MultiAssets { @@ -479,6 +484,7 @@ impl MultiAssets { /// Classification of whether an asset is fungible or not. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildFungibility { Fungible, NonFungible, @@ -498,6 +504,7 @@ impl TryFrom for WildFungibility { /// A wildcard representing a set of assets. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildMultiAsset { /// All assets in the holding register, up to `usize` individual assets (different instances of /// non-fungibles could be separate assets). @@ -543,6 +550,7 @@ impl, B: Into> From<(A, B)> for WildMultiAsset /// in this implementation and will result in a decode error. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum MultiAssetFilter { Definite(MultiAssets), Wild(WildMultiAsset), diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs index 7d6bdece335..81b67eee974 100644 --- a/polkadot/xcm/src/v2/multilocation.rs +++ b/polkadot/xcm/src/v2/multilocation.rs @@ -50,6 +50,7 @@ use scale_info::TypeInfo; /// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. #[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiLocation { /// The number of parent junctions at the beginning of this `MultiLocation`. pub parents: u8, @@ -465,6 +466,7 @@ const MAX_JUNCTIONS: usize = 8; /// instructions on constructing parent junctions. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junctions { /// The interpreting consensus system. Here, diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs index 8173beb19d8..6453f91a1f1 100644 --- a/polkadot/xcm/src/v2/traits.rs +++ b/polkadot/xcm/src/v2/traits.rs @@ -29,6 +29,7 @@ pub trait GetWeight { } #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Error { // Errors that happen due to instructions being executed. These alone are defined in the // XCM specification. @@ -165,6 +166,7 @@ pub type Result = result::Result<(), Error>; /// Outcome of an XCM execution. #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Outcome { /// Execution completed successfully; given weight was used. Complete(Weight), @@ -246,6 +248,7 @@ impl ExecuteXcm for () { /// Error result value when attempting to send an XCM message. #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum SendError { /// The message and destination combination was not recognized as being reachable. /// diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index b5dd5bc7c88..47429a8c36e 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -49,6 +49,7 @@ use serde::{Deserialize, Serialize}; Serialize, Deserialize, )] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum NetworkId { /// Network specified by the first 32 bytes of its genesis block. ByGenesis([u8; 32]), @@ -116,6 +117,7 @@ impl TryFrom for NetworkId { Serialize, Deserialize, )] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyId { /// The only body in its context. Unit, @@ -186,6 +188,7 @@ impl TryFrom for BodyId { Serialize, Deserialize, )] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyPart { /// The body's declaration, under whatever means it decides. Voice, @@ -261,6 +264,7 @@ impl TryFrom for BodyPart { Serialize, Deserialize, )] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junction { /// An indexed parachain belonging to and operated by the context. /// diff --git a/polkadot/xcm/src/v3/junctions.rs b/polkadot/xcm/src/v3/junctions.rs index f7624c91c86..d1cbc2dbed4 100644 --- a/polkadot/xcm/src/v3/junctions.rs +++ b/polkadot/xcm/src/v3/junctions.rs @@ -44,6 +44,7 @@ pub(crate) const MAX_JUNCTIONS: usize = 8; serde::Serialize, serde::Deserialize, )] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junctions { /// The interpreting consensus system. Here, diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index a3490108e8b..f9f31b752a9 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -68,6 +68,7 @@ pub type QueryId = u64; #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] #[scale_info(bounds(), skip_type_params(Call))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct Xcm(pub Vec>); pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; @@ -236,6 +237,7 @@ parameter_types! { } #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct PalletInfo { #[codec(compact)] index: u32, @@ -266,6 +268,7 @@ impl PalletInfo { } #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum MaybeErrorCode { Success, Error(BoundedVec), @@ -289,6 +292,7 @@ impl Default for MaybeErrorCode { /// Response data to a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Response { /// No response. Serves as a neutral default. Null, @@ -312,6 +316,7 @@ impl Default for Response { /// Information regarding the composition of a query response. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct QueryResponseInfo { /// The destination to which the query response message should be send. pub destination: MultiLocation, @@ -324,6 +329,7 @@ pub struct QueryResponseInfo { /// An optional weight limit. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WeightLimit { /// No weight limit imposed. Unlimited, @@ -400,6 +406,7 @@ impl XcmContext { #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(Call))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Instruction { /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding /// Register. diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 188555318c8..9d86fb8deff 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -47,6 +47,7 @@ use scale_info::TypeInfo; Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. Undefined, @@ -242,6 +243,7 @@ impl TryFrom for u128 { /// instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Fungibility { /// A fungible asset; we record a number of units, as a `u128` in the inner item. Fungible(#[codec(compact)] u128), @@ -311,6 +313,7 @@ impl TryFrom for Fungibility { Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildFungibility { /// The asset is fungible. Fungible, @@ -334,6 +337,7 @@ impl TryFrom for WildFungibility { Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetId { /// A specific location identifying an asset. Concrete(MultiLocation), @@ -408,6 +412,7 @@ impl AssetId { /// Either an amount of a single fungible asset, or a single well-identified non-fungible asset. #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAsset { /// The overall asset identity (aka *class*, in the case of a non-fungible). pub id: AssetId, @@ -505,6 +510,7 @@ impl TryFrom for MultiAsset { /// - The number of items should grow no larger than `MAX_ITEMS_IN_MULTIASSETS`. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, Default)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAssets(Vec); /// Maximum number of items in a single `MultiAssets` value that can be decoded. @@ -700,6 +706,7 @@ impl MultiAssets { /// A wildcard representing a set of assets. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildMultiAsset { /// All assets in Holding. All, @@ -812,6 +819,7 @@ impl, B: Into> From<(A, B)> for WildMultiAsset /// `MultiAsset` collection, defined either by a number of `MultiAssets` or a single wildcard. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum MultiAssetFilter { /// Specify the filter as being everything contained by the given `MultiAssets` inner. Definite(MultiAssets), diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index a3cbeada91b..1043d17b710 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -29,6 +29,7 @@ use super::*; /// format. Those trailing are merely part of the XCM implementation; there is no expectation that /// they will retain the same index over time. #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Error { // Errors that happen due to instructions being executed. These alone are defined in the // XCM specification. @@ -262,6 +263,7 @@ impl From for Outcome { /// Outcome of an XCM execution. #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Outcome { /// Execution completed successfully; given weight was used. Complete(Weight), @@ -410,6 +412,7 @@ impl ExecuteXcm for () { /// Error result value when attempting to send an XCM message. #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum SendError { /// The message and destination combination was not recognized as being reachable. /// diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 1f0e1cf3477..7d6c40eb841 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -9,7 +9,7 @@ version = "1.0.0" [dependencies] impl-trait-for-tuples = "0.2.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 9c48b11f622..f0caa5ab48e 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -8,7 +8,7 @@ version = "1.0.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.5.0", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } log = { version = "0.4.14", default-features = false } frame-system = { path = "../../../../substrate/frame/system" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 0ca57e680d1..acf28bec4f1 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -11,7 +11,7 @@ publish = false codec = { package = "parity-scale-codec", version = "3.6.1" } honggfuzz = "0.5.55" arbitrary = "1.2.0" -scale-info = { version = "2.5.0", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } frame-system = { path = "../../../../substrate/frame/system" } frame-support = { path = "../../../../substrate/frame/support" } diff --git a/substrate/bin/node-template/pallets/template/Cargo.toml b/substrate/bin/node-template/pallets/template/Cargo.toml index 3e6acc5ceab..77183c42cd6 100644 --- a/substrate/bin/node-template/pallets/template/Cargo.toml +++ b/substrate/bin/node-template/pallets/template/Cargo.toml @@ -16,7 +16,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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../../frame/benchmarking", default-features = false, optional = true} frame-support = { path = "../../../../frame/support", default-features = false} frame-system = { path = "../../../../frame/system", default-features = false} diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index eb3ff37b425..c6d75148423 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } pallet-aura = { path = "../../../frame/aura", default-features = false} pallet-balances = { path = "../../../frame/balances", default-features = false} diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml index bed63697b56..f73d97eb8cf 100644 --- a/substrate/bin/node/executor/Cargo.toml +++ b/substrate/bin/node/executor/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.5.0", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } frame-benchmarking = { path = "../../../frame/benchmarking" } node-primitives = { path = "../primitives" } kitchensink-runtime = { path = "../runtime" } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index e356a7b6024..bf6c540774c 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } static_assertions = "1.1.0" log = { version = "0.4.17", default-features = false } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 9dca2e72fcd..e07bdf0d15a 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" thiserror = "1.0" diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index f1ad9af50ef..d7d7352975a 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -17,7 +17,7 @@ array-bytes = { version = "6.1", optional = true } log = { version = "0.4.14", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 62e71663c5b..0fd2d6c19f8 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { path = "../../primitives/api", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 2338e8711ed..8de62aca5ec 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -16,7 +16,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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 24c7a3b32b8..a48964f1366 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false} # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { path = "../../primitives/runtime", default-features = false} diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 1b4eabaf0cf..8315330d7fe 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 3d2879bb89f..bfe9193e9b5 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-timestamp = { path = "../timestamp", default-features = false} diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index d1e37777ada..eb30ed3007c 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -16,7 +16,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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-session = { path = "../session", default-features = false, features = [ diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index ff089a8e7ad..bc1e6221a45 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index e610d34197b..2dc414a784d 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index f4644890e2b..5f8f31c192b 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # primitives sp-runtime = { path = "../../primitives/runtime", default-features = false} diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index 8d0fc96fe59..b91257df7b2 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 020ca52a277..fe0321bea51 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 1445658bafb..1da09321342 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 107f3b7d56f..79f35f62625 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = linregress = { version = "0.5.1", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-support-procedural = { path = "../support/procedural", default-features = false} diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index 3a08c7a67e1..0d935063e9e 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "..", default-features = false} frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 2fab40b3ef5..7da21140542 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index d6c5399d56e..142d0a0e35e 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/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"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } bitvec = { version = "1.0.0", default-features = false } sp-std = { path = "../../primitives/std", default-features = false} sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index b2ca01e3781..ac29bc4997b 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index c9180d2bc71..7f5e305e4f5 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index d5c809e1bf7..1b0d9529295 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ diff --git a/substrate/frame/contracts/primitives/Cargo.toml b/substrate/frame/contracts/primitives/Cargo.toml index 8a845f6db44..0394841aa1f 100644 --- a/substrate/frame/contracts/primitives/Cargo.toml +++ b/substrate/frame/contracts/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index 666a02e9b23..1dc723576dc 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 62e0186cd5c..523a5bb90a0 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 038e8d2cef4..c1477745848 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -16,7 +16,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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index b4a3337e418..91be97d3e35 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/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 = [ +scale-info = { version = "2.10.0", default-features = false, features = [ "derive", ] } log = { version = "0.4.17", default-features = false } diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index f2072b81723..f5d1991d199 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.0.1", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } log = { version = "0.4.17", default-features = false } sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index 09e1794965c..ed36630d0d0 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = "solution-type" } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index f4ea4ef6e36..1e3002d5dc4 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -22,7 +22,7 @@ proc-macro-crate = "1.1.3" [dev-dependencies] parity-scale-codec = "3.6.1" -scale-info = "2.1.1" +scale-info = "2.10.0" sp-arithmetic = { path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { path = ".." } 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 e4859201454..cc90ed119ad 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -18,7 +18,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = ".." } frame-election-provider-support = { path = "../.." } sp-arithmetic = { path = "../../../../primitives/arithmetic" } diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 2dfe8e42151..cb8bc1035a5 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index cb3bc3f2c82..d39a93e7abb 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true} frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 3a6b56b57fa..13b6ce74543 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index 8cd3fda6712..806af334bb0 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} pallet-balances = { path = "../../balances", default-features = false} diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 26018ad7d97..1275ef0b53f 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index f33de594a2d..e6b7715655d 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } lite-json = { version = "0.2.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} sp-core = { path = "../../../primitives/core", default-features = false} diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index e8714009c5e..db2a75e388d 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false} frame-system = { path = "../../system", default-features = false} diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index b3961009123..32983a32c4f 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} frame-try-runtime = { path = "../try-runtime", default-features = false, optional = true } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 85548c6600d..832369e5b58 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index c1dc926ff5e..3f47191cf0a 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 116e786a6c8..5eacc21721b 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 533e8e68374..cc2b50cdbd3 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 5f612c229f0..d83ff540648 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index 2018c7a063e..d392522718a 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index 57d4da45268..07c5e3997d2 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index 6b6109fbc53..a4942abf243 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 52d8ee560f7..18c771bf72c 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 3a21f5bc86f..2c30af43b67 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 19ea25198f3..831259597ea 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -10,7 +10,7 @@ description = "FRAME pallet to queue and process messages" [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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index 68ffdad20fc..665c606fc37 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -18,7 +18,7 @@ frame-benchmarking = { default-features = false, optional = true, path = "../ben 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"] } +scale-info = { version = "2.10.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" } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 83b9a09b1f3..b0fc189974b 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 0e6b85ee76e..a2cb9a4aec9 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 67113b656fd..3ad8707b9a3 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } enumflags2 = { version = "0.7.7" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/nicks/Cargo.toml b/substrate/frame/nicks/Cargo.toml index c8e8fa0467a..b8100d07435 100644 --- a/substrate/frame/nicks/Cargo.toml +++ b/substrate/frame/nicks/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index c8465285ffa..986568ea722 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index d666437e42e..e5a504e2a0f 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 4923af0ab0c..3c55822b9a5 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # FRAME frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 6375411b7e2..e4720f25fcd 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # FRAME frame-benchmarking = { path = "../../benchmarking", default-features = false} diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index a44d885d653..f0558f83142 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.0.1", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } sp-runtime = { path = "../../../primitives/runtime" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 2cfbfe6b5d0..ac204a7813a 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 141ea0cb466..acd8447c054 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false} frame-election-provider-support = { path = "../../election-provider-support", default-features = false} frame-support = { path = "../../support", default-features = false} diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index eee099fff5f..f0e439081e9 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -14,7 +14,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.4" -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index e56110c1eae..a80ccd5a40d 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -10,7 +10,7 @@ description = "FRAME pallet for storing preimages of hashes" [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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index ba30bd147bd..647193fad8a 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 9788b1df630..236489c54b5 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 38cecd5c44a..8e240546fdd 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index ac4f46d12df..9146bef79ce 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -17,7 +17,7 @@ assert_matches = { version = "1.5", optional = true } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index ae791011b16..ad04140ae9f 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index fa3cf981d7c..8e6fddb4335 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } pallet-session = { path = "../session", default-features = false , features = [ "historical" ]} pallet-staking = { path = "../staking", default-features = false} diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index 8c6c2dc46ef..bb19d90466e 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index a934092ee53..1b8054c51a8 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 89b92fa7e7b..6c66f01082d 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index e81b4dbeff7..d307cc87854 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index 5bd23ce22ce..81707382693 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index fa72d6c7278..246dec63bba 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-timestamp = { path = "../timestamp", default-features = false} diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index df423e162e9..87f08985138 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -26,7 +26,7 @@ sp-std = { path = "../../../primitives/std", default-features = false} [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = "2.1.1" +scale-info = "2.10.0" frame-election-provider-support = { path = "../../election-provider-support" } pallet-balances = { path = "../../balances" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index d38875836aa..fa13bc3bc8d 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.17", default-features = false } rand_chacha = { version = "0.2", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false} diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 5cd134471eb..c5cac9fefa7 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.188", default-features = false, features = ["alloc", "d 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", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-io = { path = "../../primitives/io", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 83218a13136..9e81397fadd 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index eded681c47c..ffb469051d1 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"]} -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-statement-store = { path = "../../primitives/statement-store", default-features = false} diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index a4934346d5d..25f10448d92 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 65f4885b159..3eb453d9b2e 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } sp-api = { path = "../../primitives/api", default-features = false, features = [ "frame-metadata" ] } sp-std = { path = "../../primitives/std", default-features = false} diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 8b891279914..fc10725e814 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] static_assertions = "1.1.0" serde = { version = "1.0.188", default-features = false, features = ["derive"] } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } sp-api = { path = "../../../primitives/api", default-features = false} sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false} diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 167aec8a171..19465d924ec 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } renamed-frame-support = { package = "frame-support", path = "../..", default-features = false} renamed-frame-system = { package = "frame-system", path = "../../../system", default-features = false} sp-core = { path = "../../../../primitives/core", default-features = false} diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 8db2e9ba7c4..c96e22ff1ab 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive"] } frame-support = { path = "../..", default-features = false} frame-system = { path = "../../../system", default-features = false} diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 340f08905c3..64c6147dd1f 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame = { path = "frame", default-features = false} -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [features] default = [ "std" ] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index d1d5897ce35..908d8092eef 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } frame-support = { path = "../support", default-features = false} sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 0bd9299f783..c1d241f4bec 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false} frame-support = { path = "../../support", default-features = false} frame-system = { path = "..", default-features = false} diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 291f6b1cf59..f0b4d0ce65b 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 0e9314a9f97..6df886b93d7 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 5c65ebd4c73..e3a2965e2a0 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -16,7 +16,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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 3ce7aa0a31b..2cac47fb3b7 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -21,7 +21,7 @@ frame-system = { path = "../../system", default-features = false} pallet-asset-conversion = { path = "../../asset-conversion", default-features = false} pallet-transaction-payment = { path = "..", default-features = false} codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [dev-dependencies] sp-core = { path = "../../../primitives/core", default-features = false} diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index d3f040e9893..2b1ee52692c 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -26,7 +26,7 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } [dev-dependencies] diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index a1aec7ef65a..e90f063427b 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index f7f7a6ae89c..6fb23380f82 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } docify = "0.2.0" impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 6d96cb8abe7..9af424f541c 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} pallet-balances = { path = "../balances", default-features = false, optional = true } diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index b0c063a83e7..4c1bcca573d 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index 1f803b6ca5b..8f7a368709b 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index 18e3a4aeaa1..ed13a15bc97 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index ec78b03c08b..c5246615320 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index 95b5dde3713..c3a68af097b 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -24,7 +24,7 @@ sp-state-machine = { path = "../state-machine", default-features = false, option sp-trie = { path = "../trie", default-features = false, optional = true} hash-db = { version = "0.16.0", optional = true } thiserror = { version = "1.0.48", optional = true } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true} log = { version = "0.4.17", default-features = false } diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 0cc3ce7969c..f207f5ff02d 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } sp-state-machine = { path = "../../state-machine" } trybuild = "1.0.74" rustversion = "1.0.6" -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 7c5e3173077..a4a1bc44a69 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { path = "../core", default-features = false} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } sp-std = { path = "../std", default-features = false} sp-io = { path = "../io", default-features = false} diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 4c2a78aec6f..249aebec68f 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 024711bd94a..e4f44e9da38 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false} sp-application-crypto = { path = "../application-crypto", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 55c81bd71ec..26f02bc3119 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-consensus-slots = { path = "../slots", default-features = false} diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 764e9550180..db8bb8cb154 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 6a12a5a7c7c..cfc98f19bcc 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index bee9092b986..8757869995d 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 700f5160c22..03fdd4439cb 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.163", default-features = false, features = ["derive"], optional = true } sp-api = { default-features = false, path = "../../api" } sp-application-crypto = { default-features = false, path = "../../application-crypto", features = ["bandersnatch-experimental"] } diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index faf5a9ee956..aa899d86e72 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } sp-std = { path = "../../std", default-features = false} sp-timestamp = { path = "../../timestamp", default-features = false} diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index b9607eadb58..7929833a2e2 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.188", optional = true, default-features = false, features = ["derive", "alloc"] } bounded-collections = { version = "0.1.8", default-features = false } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index aa0aa95b3f8..4a511c653fd 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.48", optional = true } sp-runtime = { path = "../runtime", default-features = false, optional = true} diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 747b967dd9e..166c1895445 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index d17c654aaf3..77c21b920f2 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../std", default-features = false} [features] diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index 3e2dcc7ec5c..bc6878086cf 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.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" } diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 68f1bef9166..90418e561f2 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index fa3c3ae2e6e..fcd1779fb5a 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -21,7 +21,7 @@ impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-arithmetic = { path = "../arithmetic", default-features = false} diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 9a5e77c9dc2..4c11762ffb7 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false} sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", optional = true} diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 825806078f6..ef96276a003 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" sp-core = { path = "../core", default-features = false} diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index cf41d9f8299..75bbf421ada 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 91d532b6e16..a3775d7f61f 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index 9efff2892bd..5a35dd8f11f 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } 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"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-core = { path = "../core", optional = true} sp-inherents = { path = "../inherents", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 1ef4318c51f..0822d84a76e 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -27,7 +27,7 @@ memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8", optional = true } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 1ab51a08bbe..41a83f01f66 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } thiserror = { version = "1.0.48", optional = true } sp-core-hashing-proc-macro = { path = "../core/hashing/proc-macro" } diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 03e06aad086..6642f97029f 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false} diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 4d279c7b703..dc0a6076a29 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -19,7 +19,7 @@ sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false} sp-block-builder = { path = "../../primitives/block-builder", default-features = false} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false} sp-keyring = { path = "../../primitives/keyring", optional = true} sp-offchain = { path = "../../primitives/offchain", default-features = false} diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index b0a00e1207a..22283fbf450 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -20,7 +20,7 @@ sc-rpc-api = { path = "../../../../client/rpc-api" } sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] -scale-info = "2.1.1" +scale-info = "2.10.0" jsonrpsee = { version = "0.16.2", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.22.0" sp-core = { path = "../../../../primitives/core" } -- GitLab From 69c986f405742ca99566dc7328ef5dc571f1bf08 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 20 Oct 2023 14:03:08 +0300 Subject: [PATCH 341/633] Revert "Check for parent of first ready block being on chain (#1812)" (#1950) This reverts https://github.com/paritytech/polkadot-sdk/pull/1812 until we know why it causes syncing issues reported in https://github.com/subspace/subspace/issues/2122. --- substrate/client/network/sync/src/blocks.rs | 25 -- substrate/client/network/sync/src/lib.rs | 397 +------------------- 2 files changed, 1 insertion(+), 421 deletions(-) diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index cad50fef3e3..240c1ca1f8b 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -212,31 +212,6 @@ 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/lib.rs b/substrate/client/network/sync/src/lib.rs index a291da4a90d..10eaa245051 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -1405,27 +1405,8 @@ where /// 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(start_block) + .ready_blocks(self.best_queued_number + One::one()) .into_iter() .map(|block_data| { let justifications = block_data @@ -3383,380 +3364,4 @@ mod test { 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()); - } } -- GitLab From 76994356fcaeda77a5c21958ef4e2597e1c74b05 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 20 Oct 2023 15:47:19 +0200 Subject: [PATCH 342/633] [testnet] AssetHubRococo nits (#1954) This PR addresses several minor issues: - Fixes the symlink for `asset-hub-rococo.json` chainspec. - Corrects the `asset-hub-rococo-genesis` invulnerables setup. - Relocates common bash functions for bridge testing to a separate file `bridges_common.sh`. --- .../chain-specs/asset-hub-wococo.json | 83 +++++ .../chain-specs/asset-hub-rococo.json | 81 +---- .../chain-specs/asset-hub-wococo.json | 81 +---- .../src/chain_spec/asset_hubs.rs | 104 +++++- cumulus/polkadot-parachain/src/command.rs | 7 +- cumulus/scripts/bridges_common.sh | 305 +++++++++++++++++ cumulus/scripts/bridges_rococo_wococo.sh | 307 +----------------- 7 files changed, 483 insertions(+), 485 deletions(-) create mode 100644 cumulus/parachains/chain-specs/asset-hub-wococo.json mode change 100644 => 120000 cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json mode change 100644 => 120000 cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json create mode 100755 cumulus/scripts/bridges_common.sh diff --git a/cumulus/parachains/chain-specs/asset-hub-wococo.json b/cumulus/parachains/chain-specs/asset-hub-wococo.json new file mode 100644 index 00000000000..6afb4f1743d --- /dev/null +++ b/cumulus/parachains/chain-specs/asset-hub-wococo.json @@ -0,0 +1,83 @@ +{ + "name": "Wococo Asset Hub", + "id": "asset-hub-wococo", + "chainType": "Live", + "bootNodes": [ + "/dns/wococo-wockmint-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJHWGqJW76brGnS4VXW9AFREKCW8L1mYmtTgChU1xrTCL", + "/dns/wococo-wockmint-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMFRVSLCGDgV9NR7whE1nYyRZvQPzPtwPEkatPi7N9Bpg", + "/dns/wococo-wockmint-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWQXxjpGQn8MoYeGe5kfg7WvUcGtKXUihCfXaWooZc4TD5", + "/dns/wococo-wockmint-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMzMAbKH6o6yQpGCpNFqQRJCivCUDszxN31KCF1QCGj8w" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "WND" + }, + "relay_chain": "wococo", + "para_id": 1000, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xe8030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x1002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d6318141ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9657ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x00a0acb9030000000000000000000000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x267ada16405529c2f7ef2727d71edbde4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x0000000002136c670a700600", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92d548e67179c2d8ec20a201550b5233b02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da931e06c9b9fb6579408dd7c7efc6971d21ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b46e8b924e2d9b5085de1837f6346bf1caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ca6e2d154871bec94e6469892e75acee08d401e08c1173a01aa54ac8f8e901370077df2f8ddfa3cbf275c496cd17fd16": "0x00000000000000000100000000000000000064a7b3b6e00d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d6da2c551fad8f5e3026ed1418ffcf4c7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x959220776573746d696e74", + "0x30e64a56026f4b5e3c2d196283a9a17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd005804e9047ed30530125110582a271d6243fb8525139496cd603b47cb23211a000582c82f9cd0f269f878309c9b48a767dd4259df66ab796efb233f2eff50842e693b8abe55048f05e4ecc33eeb840f6bef46f6de64cbbda54c29a5ac13fc102111eb29abe20759a5357413f5eced701f75e6d97b186885b455c5ccb3b3003d14ab66cf2fdc4886a616e8b45545ccc7d796106b5e75ca2c8449da77adcae93dd229b700d643f8c96f57015a2420499930ddaaecbca9334703eb8bf43b92f2ea93bd5b2e8428f3da12628a9ff2a107e0b545e5cd43edf2b48d1c0dac8746f62f9facbf3ec99e0a61a26b901b8acdd1c0fa56ee729eeb2bb27ff9f54956adebbea6e057d46dd19ed753418b5d2da2e991ee8acdce5f3b8c9711f6f620565ef114616fef6b462f6a877e5d2e79c57fb5343dd2c1df4fb20a3a742d478623290f157e1ad0943b47f2aa9d1dbaf20a6acc0dc1e56860416f5fb9be80a6bce2ded4d3b4850efef65a8e42b9f12a3af435bf1ed23e3b7b7bd0951b3adae8698bca1bafedb69e3e7bede9478f835bf4b425049a575e31f475c9abfd75e686767be58ac0af3fc91e0bee86a1698acad2f63fbc9a3138afa62a065e416f678157d8b777bcd21695d6b7ef30100b75eadb9557d8cf17be5ddb4d19a86b1f85bc2a625fdfe1157bbb3290b64f431d65d5c6aa75e81a6febdbba32900aa96fad575f8e5db922ecd08fb0c38d57ac2d364353d6d4353557e95957a9d39611657e95807a536f7645edfa7395f8b565049adf5f5fae869df2facd5582ae1e14f8ead04392f3eaeda91299d0798e981e7e4739afae69fccf4f8df3b39df5d55356a9b757baf57de502a82f77e447ddf7b74a4c46106082d852818e7dcaeff66eefee36dfdddda93602a28cf38a9d5dc5ab099fd9532d20ac006a2166817ff63cbbb23bf9d140a7ad29635e5b53b4fc543d3b015e5b4a6b5eb9a11abad90571d76dbc52e7e8afae454fbfbd7d4d5be8f6afdea277f972437db97234b0fed2963b12fdfa66f4e81a7347ba8fae1c6415740d6eeded6bbd5d5ef4e5945573e7d7354db9eb9bacbfbcbd29a3777b13fee541acb53715f0ed9a72d8377f78ccdb9bdafaf6e84d65d50f3df0a004876f9fcaaa69c3b7cf38c3b70775f4f431efa8e3c489f3e6a3b7376378e8da6eed418f9ebe7235607f7947d8c76feef777b471e2c489f393f5edd05356ed0759b5fef39a02eb5a3845d3588549d3152ad0694b69e9a59957df186885d451bcd296d29657ef79754da90c9abad0adab6ba669ca2bdd5f57d77294570a79c5aeaead0637e595fe94afaa4383196c58a5dfd0dbd99b1be24f57870633de6095fe7a7b0abfe58624abda959b41b921f6205e32347d665fe62f8859bb3468ebebd5d0b594947ec26797eb526a0329fbcceed767f7703787dee66d0fe2edeeeef5ee6576f9fcf1206187ce7b649dbfc9debcbba4696afab36bfad369da42a7deaedc90fa72457e5052529af2fa29aba67c768d37e5d53aaf9455ec41dc1e6415bb00bad93db36b286db78e57ec3bbc6a6747f16a9f5db9a1861e1414fe094bfebafcfd7890ac435f875fd27e7fca0ded37f7d783388835c55f91bfa6c0ea5d33347d4dcdeed935c9abf9438530ddfadc9e7db62babd4b5f624abd403d0adb7ab2b57c37a517f925513be7a106bebf5739b1241da350f653b69bbad077f532248ebe68fb087a2e3d7d9392582b44a7f24c343d97e9dfda4449056e98f647828d7afb3e72811a455fa23197e9d5db9235049e9d78358e34d95c8fa6c5756a94b5ecdfd7675ad3dc92a750074edeaca1981ac52ef4fb24a3d8835ded6e3df9408d2b61ecaf5ebec9c12415aa53f92e1d7d997aba153faf58d57faecca1d59a55f0fe2200ee220564f59a5ae29fe8abad71458bcdc86a6ace900ba7575cd546862798002294c2a7c514104418610c44d10230449820a4a418410e40841c2086226489620ad540c524da4d804f912a44baa8dd40e8234915a23d583d49a5412a92ba93641b0a4e2a45084940c5246a454904a416a05a92b525f82780942458a072914a48a4889204544ea88d496204ea49648654929118404292d41944831911a2265454a8814961486908211524042ca4a8a4a0a895495149210844a0a882050048141902f825c0962444a8a2052a4a808628220270812454a291544ca4b6a8e149690029c2060a4102788174196489d2088529029a9292931824c11a48814185f0f3e345f199f19df19dfd237836f071f0d3e361f1a9f0dbe1aec8862870952a8a291e181068f15de133b86d09474aa6865ec58e3616142e3a1d1bde1d4f87043c7053ddaf8aa300a5070506f744a3d92f0369a4ca7e1c3ca8e3578aaf04ac0e30b8bf121448f568a0b4e8d1e6cec68a2eb02cee151d1834c8e10261ab415de193d4b34989c22728ce01ff06871d2628ad3a34cd7dac4e0a1060b2105371e1a54125234e0c1c647123d6210a44a902372a8f408634715531a1d21b81ce820913325c74a8e928f367c48d18dc92122c525058649d0c34cea891d3bd8c1048f3382201144053ee0d0d122d5da2144cf14ed8c46c5cba2cfe420a1871841c8f070c3f34110227280c8b9d221a179d0030829287ac0c0c7154182d8c2c839420a4208522665028d083d28f871a647053d637ab6e84941cf173dad1e2f7ac8f474d123464f183d55b418f00dd412504340c1817a831202aa08a82304b1b20da15be0c30427256c32d862b099e9ced8c630b9d12df134919a022507cf123e48e04389078914e2f80105ca08419010248e206f82c0e1238814ac74657286f041c50714bd829c207c74f1c144f7850f25fa8a931c283676b6e8f185ef00d503d41cfc65478cbb01e33825c1d9745b745c9cb0742fd8c8f81af6927a415442e98047991d627690f154e0ade0e404d7859606cf1a3e84a073042a0b141729334180904ac8a8f01c3da5ada08220af7c40ec113d72a053e69bd263049f528e12761061471c3972f458a207971e5db81ff4d8d243043949e8f1c40f267e28d143891e4dfcd0e283cdc9049a117a90a047143b38d8c9c1ce0d76d4eca4d95963478d1e26e8712515450f2374ce48559113a7c7102825f800228545902a78d460871a3b64ecb0b1c1009503c9821d6f768cd829620712506eb604cb65a7053b2e40b9e1a3042928a1a9f041066a8d1e259e389a0c3e3578e0fca0a28de1a3891d2d76c8c06403f7018f123c47482c3a303a2f3a325b1c3da6f0e2f460a287961e59bc397a60e901c58e0976aeec28b19365a7cb4e133b5f76bcec50b113c5ce143b27d8916247cbce969d2476b8ec78c18e133b47ec9060078a1d26764ab0b3c48e2e7670b163cc8e2d76b0ec886007899d11ec3ca193041d3974defc3043478cb8844e1850c953e3a30a8a085b0b9a20a70a8f333bc6ca60cd6c0c568c0d63cb2c180b8325b3adfd62bdd82e76cc72b12fd82d56ccba60b5d8166c181d255071a0e2a0d490436c607440682ebdc4f64593e0b4c422d14df1408f979e2f3d9cf89125070e0a093e86f031a577c0549a081e5e4e4c9c94f8d6f010e3e30828858f2d7a80c1a3c50712a730a72c4e22383571d2c1c9cbe906a7149c707052c10905a72f272e4e579c5820e750c10b4cc20f32b83824159e25f0284133e34305a836bc07a81df07041bb00c5031f59b418ecd0018a4d2786b7f1c1c579e03f3865e92c38317614811bc309c105c14dd9e6d8e0702fd8caa43087b3c15ba0d49ce6f8318686841f65687058881e2e7a5ea02981c7153cacd0deeca4c133070a08a7383c49a07ed085715a024f16940f78b09ce0c038a835df18720a0f131d0cb42bb42a3414685e7498a1a30c9d317a62806ad36c78e4f8b1448f12ec70c143c8469035910121df4838520e9904f98614827423cd9065c81948154036d20b76042c0e06072b023607c606d686549256303798103038b020603bc0d86040c0dcc0da603dc07c80f1205e81418844c8206415094434024302468448453c41f4227611a788524415c42ba215714cd422b620868959c428a209629708457c229620728924884ec42de20be2185106d14c8c4114238611cb4430220c2299d88a5f442e220b2216114c5c0104226689494425229688443c220211a7442a31885804dc017403ae81338063c035200b6016b00bccd26d1a8e1642fba0d74875d169601852881ea3b5e830cd82c6a255d062fa0441ac48a901cbf4117da58de822b01fb01cadc47158094d8593d042f01bec86dbb00f98070c07b7c141805358058c055f21e1e02cb80590090ec32be017c0167301c9c02f980a36019f008a80a78056ac1c7bc52a61d37011f00a076c12568dd5c1b6b16a768dadc17ed9142c0ad6060fd8334b03366271b02a5834bb0218056c028201612097b04eec96c5b2599c34e18051510e36d0b04534400a039628a1c004248084b546cc60a4c82e3164480109100a42c001628001689360c147880a074c49dbd7e5d6c8b8899e2cd140921e9610f1902489b6ad4313a224494c3c574e3a4670b243932346464e12908000e8c4a14f887268b2c46889069e10196980c9069af85024059d22104188ce107e74dc18192dc9c1c868490284c043d2069a1019c1a144443b247192942489870d3021ea808f4e10f48911932549443a242122da61059d37d4c90e4d9824f10012910f474998f4f0494d8838e0812536b80e107a747e4094f4c4034f7cc00127494f7c68a344493e6880095252d2121d9d1e10191939c901a5c30345226ad28127493b3480d3d98112e5d0c44993244b9230e9e1897268e2a401494d7c7092430e0f44878d0e4e7220d201051d37f48907888a923c79e20122244d9c3079f28408029e4e1bda01263d3c125111929309d4e0e9b0a144494b746062b4044a12221f887c70c00d3a106d60034b6e0880ce1a7d529403110f39aca14f929a102111f1d08489eba8d184c90e3c3a3ad01c983c69c20429e907a2241e30eaa18725499088743062e28350510e4e8c847a74d4e8931f3a39d025497a7470a01c48b22469890e4b928818a0a373830f30315ac224894913263c74d268510e4e8c34908428c9871c887e20d2a19386223949c0a663037d42c424890992131e927c58b243a706dac40993a425483ee89024c989d193244c7af825483e3c0f5d22230d2c496ae2c30e499272204262a24313264992f808927dc1c09c99c1975796a62d25a55f56fbb8b029d894ed613118249e104f38e18418642320bb550783988e62dcaaac18c6183386618ca92aa6ac0d9b59bb19630c638dac1cb9b556d6c13adcac3730b309dbc62b4015042075e88e54a8cc18738c10fef8f1e3c78e1d58373304ba5b4a4d15728eb67563acf024a1840da1005a0733840f7000d41ada00610d1a94cc3b4ed287b2895b636ec654595b99b7ad6b40b72d037837d86dcbbcaa18c6baa96edaad3d54bba15e18ebd5da596fdce5c5306c555987064c0712c5305535811baa9432c2085b428ca5aaa658e7b09a3055b8ab92554a0e9e7c4028197664960d777084124ad6b61f526e10c2eeae1322840516babb75e860eeeed6341d3ab8000440051580f0c05831e514987b98997bb8879bb91976c3de95b29b6163dadccd0d2137774a47c70486404c600844a70340e7a30304009dcf0258f9c80c9baab2911e3d984dba8c754b29314c37d9cdcc41308c21434c8b70f70eb6dcade5685a8f5e55e62db58a61d8ea5eca97aa5e7da95e3c545587326666056012424d6b5695524ad912c2d3099e4e10b2a6490865b7d692a1d45825b166d5b4d3c907c60cb7146facdcaa2d318961ccd82ac6184bd6d61edddd2db16eaca564960c5bb1865ace2a2f6b6429a584cdcdddcc2a99b937664e00f3a6da0d25ef76a79042967177376498a3dc7c623e0935e7aa0fb995394618e12e841884b065c36ed8aa1cc618646eb88bc55db9bbca61905b42c5b09c886152ca66868d410ce3d61377ab6a3343d81242c8cc0c5b99595519c39495316dd588618ac1c817e44bebc62ec9bdda98623dcd7573ddad90399390a5067748c99d20638a61580761da43310cc354b9b1968d2994cc58378432608a6dddccac90bb2133c78861cc52aa6a430821e466c80a95592a63aa8ab162caacaa1062aaaa182b3702989b9931d8aacacaaaccdacd0c15723343664c95a12aa6513562ca504ac57461c4b0c5604308176bacbba3d458752933fbc0585b310c63e686aacd50c21327a1b6435ed7d52d99b1861a94522a86298c5019c266e66ea8ca98546e86d80130ec93b2314cee462c0618887c9f01620e866111c3561802d43107468961a76e6ec6300cc3ba31cc8b18a6187635841a6c08b915e36666be1846ac195356a10915b6f48eb207909c7080880317d292a4157c783f8a7258a2012323270058fd40e104147ca07aaea41c963c69b20429294912130e70c0898ae7e36942d4430f4b7a9603272811d20e49909c242dc9c18991d1929e02e8408444a403929324ab020c80880952120006f082ba90b40489a809d1069082987400444f9e1021f5c001273924412282e2240722a4244b9ee890035112178a560518400f39103d01f21d98201141496200170a508001e84094c449520f1e40ca21851756407e70d281a41356051880a3860cc0852403202a5a62a481241b68c28487274b7840415d20e20093a4263e207d437648f20108110f49929a3041ea21490e4f9870a027531788a0101925f96109075030415dd88013a3241b68c264031b7062e463c779fc40a4431326499a3059c2430e3bece0e42380911193a21f023c5961003a8024274e5cd061091192ca03444549927e206ac2024f12d10656f851179e243d61f20311005ad001fcc0640722a41e7ea03421ea1d75214913274c9e2011414982b484c8288724441b5882e424e949121d8c98f090439224231f96ec40a44392a41f887ca034216ad5b60366b158502a8ba552a4b05851ca2a4bca25056349694e096b73a44881dd4a582b85c54a54cab25852a448814a582b458a9456a22c2952a45c523425ac85ac84b55296b54a58cb92c26a2552a448912245a5b05889949522859528cba444599912d64a59252a450a4b9522458a14d6b23025ac9522e5522265951595b096c56225aa4a58cb624125ca62b15a89b258ac84b5ac55a2ac552281988355d5e5c093251a0ad7d5552f30901452d714029db6be74799dd7969730af9c083ae8d1d7513d73a3b7d3402c2a2aa0c28b11507421860884a04b5e09e0a177601efa0eaf4e0ffd8b170fbd8781b4a5a4a45445087a4ad5402a04bfd99fd14fc744a75d0349a17514afd8eb76d8671d96d1a15e5b5544f1a6d756155b7e76fb15f90c5230050ac4f4ec083a6d5561e55320a60a2514b496bb81958430d706ba9c5d530e6b875eb0eff2a0fee1e117a35794c40f3f28fdea3b5e39242bbc7e5e3c0057b0b9e3c46118f8d5f78b90f6354e1ca14b9508f44944b7afbe2ea197c4efe572e5242083d0f569fbf4e73007394040cdd5b053bcc9faa1e89767450a5d1ebd1b584948ca2b14f8d1798e6c978fb0bf29e5864e4889cc18bfa39c879f974b57e92f4fdb4721371b4d9374d0a79cf0a36bcbcb14edb1e3ec9e074d59c35c5dfba18216ed35f9f9a2f68d55ab984be7cba14fa39f979eb9263dd94487b93e679e7c6d2029c42e650d50f6f7c3be263f7f7d45d0e307572e1bd1ddddebddcbcc0ed5582dd1a1d1cfcba4fe233c5250832a7e1d7a463ff0d7e1aa19dad8dc50b787b12fb7ce5cf3ee11bc6cd9dddddd650fe2f53615c25eac7801e2893aa6628ebf5e5b54bcf94582d6804e535f57f1ca0a95166214ab76d4e341ddf3ff5922beb6ba50691f753da90b107ab32b82bec2cf75f6c88a521efacc18a06e7cfcbc480f62574f7af4a0171b0b3742f2535233b0409fd9b70735f456786d95abc00a2f655991190dd59ef2fdcd557ae590e43cf4f6a0c087edaaadaa2a447db968da802d005ac0fce6d1d97bb2cfcedc0cfad957b49e31d2aa90e849f28f34ce6bce5c91cd4d26edf301f549a8df4f554874ce3c0502faa6a5cb6f9eb9a6c58d4d9eb13759cfce1c127824f3cd83d808e69aafa779e66dde1c12e9bb93bf5521eb996bdee4df0c8afca39e43296959d7721056a107e0350d4107fdf225dafce5980d3828a1a585785ac52b9ecb3da552c2c312534421144e78e3230bbc9a97ab943faaf49e61c34109afa29aa18157fbd17f9458fae82f44f8f351d198f9e8ca2b9e9fcae62357430f8f39ab275d295e45245e0e4992c75c62ce8a7daa2ce8a76597e972f5b998b3273fccbbbcc9faabe8e28e609863df0cc1b3eb5fec75917646b2d787649da3f76859def8cb8b3be5a7746d0db1d4693bbcba3c3ae48c489f21887364fdfa264f79e99ab292c4bc79b97a505f537eb9dd481e68338657a01c57ef78c5b9fa0eaf4caeea3d9ee295747515af2e67bdc9e35c7a2c4dd33c88378f477a06c49587ce51b95ce3a2e902d1692b8b150f5d83ae69acdd3ccb34d756f3a37e4d5f2be241827984d80943829d30cda56b99c9f533d357447ae6999a876ef2330f8ba267dfdcc77c73e9ed67cd1531994ca6af28fa84fe8455c313d66f5e7439ac013af6cdcbb72ff3a0fe4c6a71536efb6694dffcf226fccb73bce62aaa2eac10951cafa2eac2e52b14d49ba7c5edf2da733c15921e92ec2be21c3ae7ca0da900a6e3bc2fcdaf6f72ae7d3c9a631e9140e73e1eed4322fd72a95d9ec9b122293124129347a067dfbc5c734df3e6e63c99eb6b7e793cd95724ba76b97e96310f5d738db722936bdfdc9f976faef566f2369ffb1b7345b423daa72a646ade9e7d2a6466ded0b56f9a7cf3b4fd6b7fffdaf9420cafae2db78581a7bcfa4989e8abff0c91b22c136f496041d358a808b11444126076caa6adafe728562d52a7eb9aaa7227f80a45c7abaa6ac7aa95ac62301a3b3b4f8cab97c7137d1f734c07fa0adf8e397bd1972fbef8c2d653e74b2aaf5e1ed497175f8b1ebbb6513af68dbd45b8c508828e5d8b5c11557361aa1347efe757bf8e552b7cb3b0ed1968ba5688e87805af2d11ace0198ad71613585ef5dad2d23a9214849b9fac31d74f1fb288f1ea394b44d730786d91408edf32af2d27b478165e5b2350633923a632d6fc919277f3c41f4939fd4c6a430d14143f93be40a1b5f133c98836e2cf27376841005eb0f4f38998a557a9a4f4aa715efdd59909ed689fa160f3de7befbdc61b7b91bfb9af18e8b445459b8f69fcba16b7fd66cb04587e1daec78324a651d4aecedcd084c2631dbad6de91c68913a706efa3c76fb25e5f831e141e58fc39a6f1eb253112fff63466cec8c6f9a38d133f9e23ebed46d6fb4bd2b4d5e5ca27f1c76fb243d96f677d7bdf9ef79ca4bd3a2b6e5719f39bf3ed6bcbaede5f40f6160b41a72d24ac78e99891cbe4d29b262fca5c7a74ccdb35f636d74e1ecfc9f527eb4f8e7993f93bca792849fc27df723c9e93ef77aec18d5d638fe70854527acde1f76bce1e3f73464e9ee3758e792767afb71c0fbe0637cc53237c8ed7afc50df354099fe3f16b90572306afce37c73c5dc2e7685c8627cefbb9cdd5fce6b1775e8e07758e17b50873e94d03eb0be92aa51659c7963b82b9e439d2bf79fff64dd61825a5674f736db9289de6274ff329aff176f234d71a8ed72011348ed7e276f29e600f857f0348fb9a436e08049de61ad45cd3d8bb90650a27cdcb2801f127efe7359337e167dac7b9aa1013e79bc99bfd996fd966ca5cf390368e63df347693a71c0dca42a6ae1bbf8e55f0fbbe3f14ab4e8bb1d1903af8da42a20b52175f5b484ca12a24058edb368ef3f576e0388ee35c53dc1b4d339934cdd7db41d3344d734d6944c83229b34c3ae65996652e9548e69acabea26edff0ac00a12dc7533c8a552a0463660fb20a932a04f3f576d8017398299121a94478a069063a0c732dc7887e4abbbaafeefeb4fbc2fcf23615824149d4690b092c1f1d831ec4d8e518e69767e4c2780acd887e8e6beae9138f629542f1aa42d6d5db5f4e85e46c2a24c7d923ea4ecef9e69a137526cf5c3ae644dde571cacfc9f14d89b0e738a744f4739c73d4d0dab5f6728e60469ab9ec7296de994bbfbae5956998f4f6a0ec4be9d82af7a9dbfbf3975f9174cc956380ccbec9fa6cb328b2bba507f55194e775c947fd2cd983b8878e7db51c55f778dad7dbd9e3696f6f86a0576561628e797bfa9863471be72552d2d6c34b57ee8892972ed508e64de945ed986bd2fb908ed48d92d227e9789377276d6f72e9cad5d0c3671ec4d2433a92e15985b4275d2ff9db330f497ad2f526570e4992cf1c85cf5c7a4732fcaa90acb34f958576ae487429bd756ceeab476fb2af2b6764bfdbeb58a5ce928b91a169d4e9e85a6cd7966317d230fe26eb7979bf19e5d7d5c354551dd35fef28ca6347fdcaad07b196a37ed4a3ae499e0a59a59eeaa79763dec41c4af7465069ca4ff6230cce94380f45ceac08ba74fd66f7eaec6dec50b0232428d83f61fd7e43ea41addee59cc46ff2cb4ddfd1c279987949fcd03f9e23dbfa76e686da2f4fe7fae5ed41e18be7e5df3c8af2d027ebb1c5e437a3bc74f6969959fa3e61bd3afb51175167bf8efae1c3afa87d5d392410c97a7f45eaacd95e705895c312b41c3ae68e38e34aba1c94c8fab71ecac5359703953aa5df557a3d82b6aee5e86faeae3f9fa9c995c86e9eab909f57bf8e48cf932e3b88d7d35fcea4998a6439fb9a72438ae974ac3279e69a2f37b4df64fd669ec9931e94fdb99ff97a50f6b3cca5a70fb5e6ed3eed77d4cf53a47f7d3f5721eafbd2cbbe22e99a43ee48fee5daa79ea3516773e8992f778479f6a9af26bd293d337d93f5a61d3269df8cf29aaf9779cdab2caccf05b0be785516d6330feaa328df599bbca3fe76cdbc1ebaeedb83983d7dcc13f297273d6d37e9cde8eb98c7b3dfd1fef5691925a50fc0637b51a1359687dedeec8aa2aff0337e7b8555fada1a6249db2bbcd2874ea444907ede8b3a4b79e0ebaadff551a92244e8722b3b84aef06ae7a1ff50818b6e1afd5e6115f49f1dd840e5f2f520e6a19b7be5a14fddc1438fa2deb58f11b8b8000a178059a3a4247439145a4f09568184144044d18510952a4284d6adec1052a752858530b78200a1f5cbb38200a12857dcb01ec586f681be4b0ffdf22857dc80f9f545096a1fe8d817e58a1b2edf2f8ab70ff4ebfbd1566b7dea921e6108197809020e52c0061afed055c0a25321161367ba78e20932695850042115529f3f0f5db91b5c494968aff06a8587be5898e1139a2a91f9c3ca5999a04708a57c47371e7e715e1874ec6b727df372a3c6c2cdc7eff2d9df8cf2b091a81949fcf57991d1a794376271f9abc901a8b43efa84dffce1bb899a81e5a3cf0f3cbcbe26cae6e3b7f4c58b16d280013c62ccf7bcb68e78e235dea2e7258aba949c3871e27011ca36ce7b51eaa1061641f84009fa1e759c38ef4509c81127d0d2052948971598514aea41d9bc17a516d280811294035069fda0a4666011529f1ff8e8aa30a8b630b565840d3e69df0b10ca4628fb94948d907e51d4a53479c204379802474949487e4a54949484d46714ef6ff6a0c14d7aead06b674e022da441268e90ba7212d061430d2ae608224e1c21f59d6fbebad01a422ffa2e2663f476e975315ebc2d37c423682efabeb68c38c1a358151d7afb5a6fd0af08a1b70f9975a02e95486f4befccfbf2bebc3dbb5c5eed7d7963dedddae5e9c721364110b35fbe97f340dfe7e781525c1eb16b1f7a50aa10e520681a1d2a91cbd5a312b9bc17581545f03fac8aae5c4f9983f4063279745503691ebd87579055d2a30f5122ae42a447d7bc8e7da49b3cc93ed204d94028f6911e1dc5abcca3eb9b9f2f7c741394c87ef44b7a6bb93cc5a4b717c1e67b58259d7d7d39e93c98f7f3f360dfd1c679ccb56504095e5b468ce051ac927e1dc1cf3e65958c2a445d39a842d483f8f2f6a5302b7263a129afb076f8cd7db861de7e34121d3a47ef68e31469878ec41bca31a01dba74f84df910f3e58e7ea002c414a53f9a1d50c212e2fce54f587f7d4fa22babb06f42e7e819492a404cf9a38d337f600e89fce60f9a7246a243875c91cb5585cc8879fb9777b4717e3d0ec18fe7483bf476f815b1c3ef28cacf7e8ecb6068986bcb0d69be7974e971ae4ae4e4976b27af08ebe7e69a2b57449e8aa4ab6fde94beaeed6bcb082c1f55c8e541ccec9c27dde4ed6b9a720c60cf32e7bccc4d9eae2b37947d3373cdbc7dcd8358536f73cdd3d79433a2dfdc57df5ce34d33627a5521535dd376d3360f62dd344f7a1babda75e836d7dcf4531e91bf7d4599b37b33f3f5a0560e097bb6dcd1c679930775109b3cfdccd397fa97173de84156e9b6bd45d30a74d027eaa31cc2abf8f3d1a3bf101dd5e6a3f730100bc5183eb2f0d13b5eb1c718a36b2a7e45da92a2a9aeeaeaa029a6b3b10aeed8c0abe95d80fc54340f3d3a26a33f76f9d4348ff9105e4d5410afa69c8157b3e3815798c7c02b9ec71c075e69ab88328ff90518080ab5a6d1328fb9f2aae7e7cecf218f450fe21e8d3d2ccdaef1986bbcb1c78f62e331d79457fb74b4715e31dfe115740c73cc35857d45eaa6bf689aa4d316124a3f650b8a38be5d9fbd67d75ea4e2959538781dd5a34bcf3bef461a85ea810cb442ed5defbc114d630abab9b55689a4b8d3f4a421759055fab9f2904cb4764d4d6d59e96e9e67f7ed67f7a98d553f1ea0714491459a23b460892c4010524f07aade871001068885d863686f7ff3f1ecdb7edb6b8b882e0f3f14ab565b72687a818e25afb6209aded0b16ba72cb4d796952f8fead158263841133e60c3043188020742de6a0b59b5906b80ac624d53cec8f54dffcba5623a9055df4c6a93a378a5797b0faf300dcbb26f666ef20cdb58d5f10acbbc5dc3bc7d2d63d5e6cb1941fdf6cdcd4d8e79fa9b97d49fb9b6acdb27ccd3d73c7d5386fa75d94044b890b28faa90d9f3fbcdcba3b76bbd7b79fa32ac4b2f29fe6e1a6f3ffce5ea4dd99c623aeb0a398d3a1bab52ac6ac7dc59857d41ad1ef4e6befae525f5abafd7b18a7db921fde22759c5ddbb6c20a8a4a4a4a424d4ae5222fd9d7ad3c612b4b7d7806e5d469756ba3cfb861a62e9d97b22e41ad0adebbef7a0296b9a6eacfea1adaf67267e93f5d1d7d37a5b6f5fdb343bc498e686d6b009cfdd1bcfdee3713c0b1dafa6f6dce388aef1471be7a792e78aa89a57d7e206b75c5b9c02dbae21c0687d2984715338a96b4a443f55211b0e63dceb8a314208638c70ee4479ec9b50cab8d7eeeec28d0b312d767b19ea1bcc0c61733333ef2e332f431823f7f2a2d1925b8707569934e69598668a30f3a4b775579a5e0385f0eeeeeeeeeeeeee4a1e4023fa0ca1b2a0ce0558255d51d8e5ec3b17ccbc6eefbeaede306f7b87b57bee185ba1f636981d4b505e4e74c4302c0e613b3e74d03c94bd506e52afbda48851ea60cebc9b2eb7db3697315ddea03777777d779b2bb2bfc6183863def042e9b5e505989fa86f2fba7c176eb49ce8f3fa26bc2ee831865756b124ab262bba4efe8d57907feebc7a81e5b5e5459a47bdb6bc68fd7247b0387120906c9f9e3b51348839f64dd66b92c782aaa3ac520c7ed0d3c0351f5d536ea8c7b5ec82f04b03311828a6817090f08b0acaeb877b52dcb52da373ef0a200e3ffd8038f47520aedc0201e2da6e403c7d209eb9a69a6983bcca5c5ddb366e0a795dc22f2b1d7af0cbee57645dba84d0cb3ccb56582850c75bc8d60f88d735100403cd7c74ec9ba808bf44f825c22f53df446155f41ffcd2344a441f68d50788666380f8dc612060b0cc817844c1198b133cf21a5eb1cb2d3a321f4ff0c93278361f39cd03f1c96a50b8b8a12324fe40540fc431cf3c4db9ccd7839e7946d6a1af43879ff42b3bc19bfb40e4976215100f622dd3cdfaa42a0408dc80b01806c3aae899c761dce84c7ef9d437569603f269bca24ec7aa8882a360e50aafb63410fce14df7e6cdd43753f553dfcc1f93b727df93af5f9bea42bdc9d73b5e20bebef14a2e8f2f37d4e3382c0c9747af8012811edd02ba3279749f92880e5705c2d4675d879bbc566d615d7aaa42260abfee99f0eb9eb3403c15c274d2a39bbcad4ba72f3dbb34b92d6744fa3a9c991526305fbe4c06c3667889d3f0183ec368b8f5b1ccdb6003abb4222bae2ff0cb97cbdb77c39d7250701478c7b4ca30981320ab4c2e3dc92a935f5e110a8eb40fc46d905bac79e9d0b5131756751becf2714bfb44d72dacca41d7c351ee63fb09bf7c815f78753990e7d161cb0caf7c7874b8c42bcda3c330bce2ca3cca273cf3118af908c77cbc723af8057e815640306dfaa6d106dd049f0c463afc8ae0273f1a5885c2a7ac3239902f691f5ef9b221ba66c32b143c7ab76920f71d0e79253d3ab4d240dc05889b3e2b1fddf3a052fb44d738c815b93c1ba29b6ac648910dac8a9eb44f03aba25f5f11e4b2a581b84bfb44b8e5a36ba74d37cc64312956c586abf1c47304bec9e19bbe1982bf50f0da0daba2bbd771b04ffcf298f4b80cb7784c97066230ed134ff8a67c20dce58737f77ff8c515c1fefa1a0e19dd3a8ff3f01ece60d0701a5ef1787456a3b2f3d9f944fd8eabeeb872433d3c887bbc28de2ab12a5e1c8369201cda277a940c067e3cdf0fac8a8e721f3ef5cd167bf2f5e6909c9cc1f08af3e81c86c52811fde89143723a82dfdc3cd3ffe1e9fbf05026785edc7b78ca2acd79a43efa8e87b43bbcb9a17e32988faec343c270c85ce79bb2fb669793e6a3cfc03ed04f9cb745cebee9aa5fbf3ad95d0ed7f0f00a6c689a9a0ce62f1d9ee3b0fd724d537ea6a2654e74ea41acdda7ddf97a2b86a7bf22ed9d775f63de1e14c32b6cccb2a1405dfb5c8ef2810fe1afcbe726e12f577d0cf31c9deeea7ebaae35cc83aceaa18178f80edf5c1b68c7351fdf6e721edeaa4ffb8eceb7eff0547d66f66354878e0e9ffc05e51d4a87a6f3c29621daeaa266bee81298bfdca4f3c20fab303799ae2c96e641d3b4c53246e9db3bd730cc14211b3367201aa806b2c93153a6753a6dd77d50166e8b65b1b0eaf20bfbe67ec7859b6fd7e19a94daa6c3db31acbafca781b6d53e973b4abbbbb821ec5b316c74db642b6c05afba6f76dba681760b5b69a01d7e396b612e3cc574ce734cbe6b78d5b90ebf7c3296bf78cbe42e7f4dfef297eff06c689fcbb1ddd240bba67d2ebfb46f8be9e3be2d399fceb7e52fd754a56b209cc79c4a9b2b6e3e6a79cce7bef9cbbbeebc731dde9befe2782c8739233c7f7e1aa59ee7685fc7a1c06f3fcaf9d6e14a7cb91ada757c50f675beb9deb97245ba8f0556615eb41f0facba5c0756715c664487f9aee9b4d306fff265c32be9972baf329fdbe6af53c3a8ed106b9dcb990aaf30bf5c5595f3f6fabb408e37f7739c39ccdba4cec9b5f502a587be62d48c71d3e2d5d4a53258ccf06aae965dd3403db4cfe59acf0ea58557397eb9a77ff2380f697fee9abf7cb1f04afff21e1a08a53eed976bb7ea3b93baf9cb95f894975f20f3a467c3857d0ce6350529cde2f8042eb4ddba897a45f973e63328117ecd8d7ee055bbe6471408d53e9a6bae8a3a437583d77e5ef3a96cbc06e73557e953ddbc16c77a5b2cbdbef1da12c3e6b5e524c7f1ebcd0d79139679d862d57af3e7d7233724bf9f0bf25e7a5d279e23d74b872fbf29e5b10fbad1365669ae52678755976b4bccd2cf21af798c81579acfa066d48c4fd4a31a08aacffaf6cd4d62dfdc91dfec79d46b657453cdbcf63b03ab349f28ff950a24d5675d25e6d8279d065e5d1ff41978255dc35c5ba58b0b2ed63c17695e657875819a576540af79c6c099319f39743272a8f9cc07e65387a71d7e8c911bc2fcf229678389994f5583691f1e6a8169a04dd33eec7c351894fca6ab7e36988b1bc29cb5742a84e936cdcf4d837d4f414627e7a6815d9a6614f6cdaee19706469f9b66d72891a37583f95c36be86cc611a5e61cebe6a78059d7dd7281124d9d166f09b9255d82715f69a6b0a6dd5e095dad35f4237bcc21e4a2f23418762d50eab78b98e55dc1edd216c1ffcbca65ba5d39698d69bdc4deae633d75cb921d6dce4ca2bd3c50d996860a92e7de6d3c7af9af9cca7ceafb63ef399fdfa2ad090f6c986f6e78734e7da4326ea35de4c12f3214a843ff30bf0c0abf6cc0da040b27d32efc8a064f0997fe653cff84cdfd07cea9acf7c2a9bcf586055e6ebfd689f8a5519d4d9587579f4a9facc8764dc37e5cf219fb9d47cfba6347db3d3959f797346fc4d26d77c7d4d269349ddc43234e8d0cb7f1ac45af4a00ae9de40a7ad15b079a84494882e15bfedc92e0653c8065219b0198384166e70792384807740ecf8cdfdf664145d34025555d715e5215428b1e566d08f5f1287e4ba3c7e50f8615cde3a3ea253d75437906a0d78f90c4de1eeaa105eec5b554510c06f0c5efdd1575bd828cfdecc45ec72edba30ec3beabf1442d6b5fcc551c781f3aba42a040aef878479927ca4a48e5bd86f42bf8e40f9a9aa26f4cb9bab210a8cd0973b1282c82189dedf84df648690a63923ac87ad611bf363aec9adb923b079fb245d7e47fdd8c58022782e183755222c375d18788a69d38561376e83afbede2667d0ad4be736552226ee503082c2cbef08853f757fb46e5e1eed9a971ad77cba62cea64a24be46377967a6ec9bcb7135446fe8d293e12567448697df910c2f5debb45ec80d4f4ff8a15c2fdbb12f7ef093d95e37203384367f390f922b7a43065c3d355bc798abe1f28d2ebd9cbf3eb81f3f69248785ed6ea1051c175c796d6981e5bbd796164a986bb66c3a19a48019fcd24ccb396ac8fcf9a9fa9d3ff9ec79e89ac93b719c07a5e66d1e6495941ec45acc32e78ce7fa7a58b5ce7acc97536e48f25cdfb6f49a024bdb26a34ded591deae75ca4486a462c7b8657d82b176d4ff10a097abb8a851f5e9dbc670cdffe020399bc5d93de3e12a8b9d4fce4ed33c0f4cd9ee650a86733cb21814bbd0f7ff3bce4b8c9f362c585721c7a4752941e6bfd64a5efeee507bdb9c5cbdb88bfc937bebe69fa784c1ebf8b39d327a11ce5bc74ce7b494d9b8e43e9ca9629c08c318366cd1bf04da4c22bf6a85cb1791517ba025e1c92cbe137bfd74ede3eb7c0cd6f9e7148ba0cab7658d5be7d274f3fe33a56b5ef19cc1de18f0eb9212423fa263f79fc1937c47daa2d4ccdd79743c24842f09ab7195e6ddebe7d93915c5f97f9a6f4b6056bfeda9663400ee6ebd2e335797d860a612efb8eb6cdb0aa5d8bbaba319e2074cc837e798dc69b21f8f8f0eb2515d24bddecd6b7cf5efaf66e75195e99e195462c1bcb2bd80d84107afb405f247433e7a177b0bb7394c80f76611786f9f6a09bfe18d6b19052753ba82b5e3f49200219dd0eab227345f8f9d32174dd0e0a4208d52c843ee866f710b643873146e8c55e925517abb8a18da39ba8bf1cc5abcb7b78c57eb943bfaecbb78e579e0a61306c17db6b061293d0e4d8857d451886993ee81183df0eaba49452ba94524a99659964e616f0d00efb44ef58157d79d04dff1823744f8530ddc597b73f6da47900bcb6c2585184305cb270f3abbc7d2ad2af6fba22da1bdd099aa6a0c211012074537ea330103dc8aa08db74b3fb181dd5edc4285ad7b1ea07ddcc79ce51229b8376844f33a2bf46f8f7db41b7ae3f3bdf1bfbb4ab64550721d538689a526e8dd0c120860e1bc002309f7a6d6161e6f282fd50214cc77304c6af287e3cfc79b1e242d87775d4154277e60c98eb2bea9637053a9255d12f9f7259d0692b8b2e3fe5840fb3d802a6d3160bd8340bd42c169db6b258f39f459a87100b330fbd87f59b3baf46d6374e05305d74fd9455fda93a05b9cb14536801a3050c9515c4b1808e612320e795cc1071ac5ad1b16bccdd0c61bf7e33ca0759d5dd2755218a85065df7ade8d6b55dde20ab34e5ed863c4762f4fef8cd28af2a04fa4235033a8a57ebda72019787dec30203a950eae10b9f825adcdbe786146e3ac44874db71ab6fb752da2a29294d11d2874090976324baae5500d3f93ac3dd4253065aa59f21af03f889fa07722525252084d455410c048574a4f84118379070c40da4107241d7f00111729439c34d9b2e8456bebf72eb3f82152c7d005e5b2a08f35a8e4ea3eddba3a641ef08f692bf23ecaf29e519ee15cc2347ef4fb785cba117ad3c841ed4456c0bd8b20b34d574bb9c7dbd9ddb6b1fcf0cfad28de8cb4f05309dff5c312fbd9df59837fd31e94dcc19f3e8ac8f5e527cc81ed4acb89b46cd6fdfe36c4605537c015e5b57bcf1578cb942cb5f71e6b5d71c6ed9a587ae99e0f3c7e453e5a82131f00a7375f63457ffe13e1ce52637a1b32ccb8a389965dd7bd47267ec71f94d7ece7bbec9df136e716e469ff18bd957d4ce79cc5c831be495ae725cbd7f62cedeec9e2f5694fd786708fe79c2297e5e9ec445994bf9e8cdfefe66c726e41287e67ef385f1b7cffd26dcf29727f1c77509bfbde136dc86dbebb3e736e1af940ab4d13367af178bc9e4f2874fe9c367876a1fc8006e9d3db667df7e3cdc6291de9de03a50f09dcd79a87a1c618f35b0475fdf300b43f455214c97c41f6712fffae5136e79cc353f71467a3c7e45d133e77abcb9cf982f16203ee56fae0cb4a1f09df0cd4e7e53465e3f817df66c9c11f6a295ae7135b44e00f2fdac9f74f6ebd9c1d1a5c9cc6b1dafe73cfd8e1efcae2172996e0b73c3fcfac51961d7fcba9cc7c33ca8d9376f7afc1ae8a77da09ffcc737a58efbf866b7c351df4445377dd3d94df8a6eaa1ff349012ceb31edf54f137553cbee9f19bbef34dd48e6fa2747cb3d3f966f7f3e7bbeff4e5642699699aa671f2d36261b83ce89b70fbf85dd1d9f9870a5a7c45d1315fd75cdbdd6500e6d9a7f12665d74dd46bae0aa4eac3aec5235c3657cc671f8f74cc2f57d240eed0170bf4f6996b25059fee3e519ecfeed335297cdb6a1fe8d33f29bd4f1b2e16ffb47d26eae762c9fc82f0393ff9848f25c5d77c26c5b9621ef38b33a27911f7993c72356caff9b63887f0333f7d13feb5ade75ccad93d549f897aee9b49f133dfbeb962fef2897ae8abc5c2a0656e72cc157243d807b7fc7a1aaf971ef8e89a2ef36982e0e391f8f0e511edb16fb5d816ae6fe935052990d5c33c6f3cf1f34412c3c84a4a4a4a49ac832762803134d7aef5ba7e3bb73a689083db0f15b8e89ab92186be5cbb724774ac9491e2b73fa3185ec74a99287e1dbe72fbe507d5798a57edeb2a16e2e7acdaf652ac1252f3c40dba94e08a3748f0c346378424e067f4f331c618bd5de30da4bba7823efd53ac5a6fa0ae81b0cfdb675d0a0de02083861a3669d84028b6f0b1cc47d347333e1a211463fca6d1cfc3cf5d3f4f712ff8e93f71cbfa76f964a13563109a5ae6d5033edb9555ec05cf1eec02a9d6b59adc9438993804bd8755ea2a4f2815a2de435746128c13c3300c5e49ad69d94df20c73c843e730ba75d5fd820531baf5ee6ea89a286dcc436f8fcd74eb6da4651eee98d1ad7b01a1370c5e73c9414a040715b2ce9d36161848d5a908593a1addecbaef2733699c42f2811aa4a00658dee8070d0dac5afa3d65fb9c07c9e872bc3d28c7d3f6d906da619ff6f69dcd69d04dd5b78a859f210d44e50ae9555c28c7db1590a63d68065eb1a947fba67f9bda680892283250620a306fa4693e3365df7a0ee60d595dba5c20b7f571aa1ec54033b44f041ad23e11aae920cc41076dd0cdddb25b78c5ce5c788575b18257d8e7050c0f7ff28a6e3e37908c2efa0c38f019ddd4351f5d890e3c28f5c05178358d54bf3fa0f9787d4970c31460eefcdc2d908c6eb774dfcc4bdd54375b3e7a0f493ff0ea0b952ba05771a12978b5de25065ead949f919679109c008d366bde48d7c0bf3cf8d02bc0fa0e03a990148a2cbcdc16968416a44262187281540c8c521fe30beaaad442d8c36756e3350438638c51fb52554729a1412fe6c65eb8dceb6ae525c57c767763faa3f2c28be86998cf8875efe5cd1d9fdbebf7820a815f3482a6290dac5a63c3b7efb2ea6930faf92db3df901874d37cfbd01056b191aef9766eaf89aef922fe9605b7b718f2bc838a9b945d54e65687bcfa0eeabafcbdeb533943f69d2172631a9aa7cec2cfb396f90ba45e3d4a0f49b3e78d52afae2ff07e73888a051f5a876b34e4d5212bb39196615ddb4740ef56f5e8f3bad42ff5a24bd55b7b7ad1ad4f46d3adef1a9a1655a36b5174d8b3139530996e1d26c5f8b964d5fa7a51fc027efd45e16b77372bab163458d0a0011a251a98f136385383d6c3a5e818a63ee177f7fd4de91dafc819b93cba5ad922b821c53cef899df2b631ddd456d09006ea54f08a02755c842ec131dafcf63ace5a6a0006cd9b4763064d1734695e5b36da4471997717100ff5385fafcb71ada594123349d92d4d5f513b66ea26ebb8e99bfc98eb7cde5c363f8c197dccf2c4df84ebcdee37b2a25c7bcd10fcef5c373fa3675e917429cfbbd96e9bbfa4af773e974d767d73d97cf4f66baffe8a78c2bfe075495fefea9f06521303b0cbf7636f26f595c38023be97af958581fde2a07ec93389e7b2f9ccb9136744c7f92b6297cee9641b5fbee3721d1b6764bde8d271ed7278ed307d3ad8754cdc50a6e5b5eb3166666679711e3deebccc773c1e1ed4cb790a5d773e2f62fb72bed34a9fddcb4f625f113be7b2888561ee5fccfc45a3ed257be6fbf5cbaf88fdf2cca56b7b79f62535d08ecb225c7a33a99ff7e3c13cf3e8be45181965fdeb33a99f73cde75ef96ce5fa0faf38e9db37218fa47ee9dab7452c0cfbcd27ac976ef2cc157243199bbf3c8d17333bc3c7ae6f8bd816e2b7e3b53ade81068e1e42123dba40b9d4ebbae013297620c51653b8588192d0b56606368038d0023bd40eabb6bbbaab0c4686115548a8351a2c7854878613afe3b58586959f9d4330203c230c11ddce1948f8d9b91860562d98438d1a0871e58d126b2cbdd971861128c0229734c880a383316ce0800b3596cee82ce9800455b40183840a4ac046195bac40074b54e82cb980892a78686026ce951fc029411b4251cd9252ce521222a822c86beb0c34cee8e22ae3cfcc2af79b523a0a5f246587da6fa69e255c499fcdccfed844cd4ebaaafc26f649223a7f7dde7ee337bbef9e5f15e2ef6017df84aeb08b9a59d0b56f10425e1ea47162852d6f54b10286cb521339603017bcaecf4bb1ca8c3836a520e267f4f3d7755df2baae207c70d1ab043b6600664a1512ca088029707cd9028d08a6e881d08583bf6680c55f331863c5e111da08981a6fc26bab8c185c8c75a129afe06baa2bf6d9ddddbf6a46e26f85013223d138719e5986e74f59bd3d84196cca40c2ff603e597875558fd14023c6046fb480a0411042f1061fbd4369155d9a17e3a7eabb8c30be7d07d5402c26e618428b11c670a2cd0984da8c4ebeb6cae8a26b252b84b458424d0ed480019b2dd278c0162c8802cc0dde14a10856d880958519699431c61073d80007358000a7805370843349fca822078f2a104208239b2e8e2a683a308210e314440b64b040870c3082c8796d959125abf2c514448c31461e4a104669076da0516283c609ed04417c700454c831471341f8c28b2e684006111c194d5011e20828c89041810b4680069c238a90f55002e6064ba172d8208e135061038b385f9c31c616dd183248418c31c600a4b1042c55b698011b6008c5a531bec431aeb8e2c2185cae31a2a8c225e0f1da3ac303127037883bc6151940c151f4344abd3cb344841084d093b03b630610fc44e7e3b575a605bfbdb6cea0e067e7657406970eb2704209166451c51b3f3f5da4fc49a5180a08533dbab022cc9817b801471b2135e31fc0e5870b971473f9896b064d0cdaf008a051ea2574a2eb5e5b3248a2b7872d19142184107c083df5e3b565c6cd5faf2d333ff8e93f48d0eb52b8c34050e8babe6994facbd5934d749743895d977766d8fc755d57fc44d0e9438750a452bc05c214339162268c523d6286c026755ab31b6cc56f876578e94c1a346bd47c676d9efb6b6566a4ec3a140b8c4249d91efb2bc21fdd3f0669beddc9cc01e6a11aee88cfc334accae0601b63e966f6e6e2867e70956e666650d91b35ad5fcede706999d858b162498b63cb986d0d952f673837272d4a8437c6a2657e12d33eec12c2e9a8a8472b6fa67dd8cd983163e624a6a5ecba9398931835300ef80664f3ec1967c43fc23469bafe60c713fd72fdf815e16ffd44c935134766e60713d1656f78354f62d8c036bc9a9999e7d5dcd49cf9359999189450f97266dd6811c36a94a630d36f60816194086f3f2fc05729bb0e85cae0b08a7da9d356a604020099945c5018b224680becda5ff64685b0f3121d06d350316daf42980ebaf168a58150304d03656fda87ddbfa0ba745b3e6291b2eb50a8ec0d4c03d33cbbd6c32f3ceb44f1d7a58cf837aa81a4b34f6f9fd81fb76548743c50e0637e94f3d877f9ccde3cfb05659f07c9c6afa83dfa55a43f99bd9962836e78c50d3904bf6758b57ebab847125c1e726e94c8462df10a472a10ceafc33818a8c5b4ef6c36cf5cbec5341057867dd8211cf9cd6e51c1bed9669e79caa55e7a8e5ae21b8f049bcdae5c6a2897e4925cd3402a24512d97201b91df1fd7f2e492966eee9aa5e734bc68960cd5aafc17f52b3b8d517013ba65b7aa5ab585765d7fc8716eb0155c41e5fdb555450cde8a38fee7b565050c5e0c3761b4f1eb5a941ea5ceedfa92b00bbb5aec1f87c4f4ad0e3923985fadbaa5b9218d5e0c433e1e1a48bb1bbaab543fff059da0c381d33c3b0f1dbf29bb0dfcda3cfb0c0aa1dc544b6ee6a1ebdcd68a51a04e7dd4a1eb3e6c6f63d575842c59b264c992254b962c59b264c992254b962c59b264c992254b962c59b264c992254b962c5a16cd92254b962c59b264c992254b962c59b27490558aa14003230d0cce747976bed2ad8a55ec26e89a9a16a01fbfb93dfcc14a7473b13c6f5ab6f04a73f6e5a28457fa271dce6ec4fe4303f5707665a01d9863dec3e3a17dd879784a7ae753f691ce9fb28fa6c33b9d3cc79baca11cd722376432994c65dee4ac6f6ffadcd9aee31da7f3cda43f79f4585c77f2a0ce399d9434d00fcb359ab6b9c60d6d9c739e0a603aad88e9db5408d369fbfad1afac378e06d66b5ebaab815668a76334b916bdbdc2aa18d447d8376b8bda27a9eacc9b3bdf5d1e121c8ace1e1dbaf6ec5ec360e327aabbe8702687c650a1d6587333ec63d1e4fbcb9fc98b99c7abb92193c9e4ac5f6ffa2be91ef3cce4ad43c97a96d1377e6cc6b68300b73c34132609c22d5ac02d708bafc7beca10b69cbdcbd55b1ef6bdf23be6835883565efdd257e81737a4d7857910ef62ebfbca62f6dd4bbfc9baa2df11f6acbf0ebdb8bf310563c86441a36504d1c2ae775b5a6c45358e5f3a63c51768055261b3a635a6b9f4963771a0590263055f612b6dd894696d97e502e7cda75134ffc2cffa7eeaab0ebb402e70dea44113064c63e92b6fb43153660aeec24a70d4a4111366b52c1637467a66061ea253adaea678880ee6a87ef385576f6ee84785e46c19ddfc7975a8fce3b36d199d7a5c081bf669bdf7bbb4198babaeb3867679b36b56baebbaaeab5fd334879ee69737537f7d13d54df917e7931faac290da163cf0d7a5a3c379884e59a5e39b51beccd2772f5d635eee930e5fae48ff51bf8e4f55888e4b6f2055fbb4b7a71606056c0bdd7d13d5e57cb33b7d92fb66917ee89b4703abda5599b72b6061506dc1e48d9af295dfe4935b219fa6943fea87df0c2aa49d97e8a06b9f9ad44cfbe54df9d328c583a47bccbbc73e093f75d3ed85455b8697346da76ebdddd9d683d2b55a4affdafaa208bfdec9dd5dee1e5d2084305e266821370cc33099f52843db4c269349db4c6e9c368ee3b853ce15049dadebba4e47878ed756ab083bdb8e1d3b76ecf0380961c2d6a3478f1e26a0e0123f361f3e7cf8f8c1a32302205b0f37b4dbe33d3e38230b84d34e6094b743a7ad1696dff1d1655f18856dbd0d8b4c625784cdabdb0e37301843c68c1ba09113458c7123175be6a0128695248268238330ba74618089420a655191c415247803c712aa80315366093ec268a2082914083d30c29b2ace00230b2308c5189459b39579238b1405786d7de1c5f7786d7df1e51263238c9e11fdb8b301600117a5295a10042410417ff00332259042046068c941735759f30c9548fbf6d1792edf8f5e11fe8efbdd1ecfba3e4f91e5df57ee860efbf8b5dda211f5f8978b9f54a8001a78f542d00c38bcf0c2b3cf212f740ad43520230d1a285de1461942ec280562695952c38c125a64f1023484d85d81582478220973a0a902040a9e1062572910048a98811557d4c8c10be4d0355da665032d54f5d985425f5859de2e344da912599ff1152a110de21d06ea7ad8150628f2d7b1879b47b8fc972f5743f7d3e87777f73b8ab29f177f6d79d1e627fc8ecf283d07292047e7b473e75d8964aeee290cd2d553502298aba794c8e5b3e7a7934266015e5778de61a0a0f6e11f751844951bd231999cf31966d0d1133483b61430830ede37fb060eaf7a4c9ee3416de2bc24fece81e40cbc82a2d3ef5c879b9a1b3a99721c72433afe33f4c2497bdd39bdce6e235744c737e1ebf01d3e6408ab7cf81cf2ed82cff4be5d15c886f6619f3e80f88cdfae0b438fcfeb7bf5c3e77682cf8e473b54223bdedf348ae1db7f5835c4045dfbfc31f2c237a481781e5021ec3dde07b605761ef61fec27784b857dd86d88ceeee39b28a0be8932e1ebf1f1f8f68a0a61dff17e5021ec0b6767d128117ef61d0fa240061744b1b40239b020a3c501948a40032bae70424c1a42ec41bc3239bb0278a56ed2e19c8e3de2d977fcf0aa75b87226d7117d4dd13766bf615408fbe42e6ee8866bfbe1157cf61786f02aea7439261318715cb9c11180b094c6107c8d11485c397344112de80db36258c57d0b66091d84428c830dacfac1f23386081e84a9c10e949cf881c2c1620c1a4a5520b1244687d084155a24f1850d1c255033569ca104a78a1928097103abd8e49ba779504d1f5211f84751dee447e09b4e5833bf79fa5a7f5b8655db62150e36b4a22c155e5df96195d60a6b6bc1045521021246e0860470c81881b58412644ce981d252173037246184379e88620d29e44040126914e1cb0872500432cade3e4d30e1fb9b26b06b99a77fb51a4885e62eadf4e7a6f1ec721bda30ac62ee9508f6fa270c7939c1334f7aab2db463dee54115d2bead068a3d69f0587ae6be7dae99e71398d957ccb7603e4845c7ec37f06aee057835b5a503afe68f0dbcdae75da38499cdcf9f67fee1554b815858e0484205282893051c6e08b1af1905da82c00512843082244c510421f65d52205609daf801992b5eba98a30c21f64da340444f4851831860a9e28c2f8458a9877bd0f011dd940f3b253193b93c0d67d0bcb656b006fa0f41bd58e62a3d94b1eb50ee2ad594bf3309fe99876e865bac82be54a820dca26aabd5df447d1241bc04a3d034087441f681aefb291539a49f2a9176ed6e96dea62e44c7bc2a52884a1517a252a513527561ee20c0d4f9e89c1620faa6d141940a619e0ab5a78b4687002b2e747d7193becc467043845f40099941803c94eed979e8a52b6ca59dee289175f555182084d0a1b3077db505e8cb15e1e7a13ed05f4041082ac8439f1d90875aeb8e36906a6bad210a13858f5e3828f22f5735900ded137d5369aa25d547d76c800ebfc9e37be988ff2c7ae81aebf269bf1d15d2a9aa3df33655b54b4f2a5455fbcec3df9e9fbfa328dc77830d5548be4ea0296b5d9001e351396464a04c346537ab06b28998aa0ae9642719b6e9eeeb724535c6d1c07abe30a99d54ee308a03ab3293a665507a2a3738d12f85ecd053214ce71ac60d6d51faeeeebe66dad52b935bd749ed3a4c88ddddf69eec376f1cddab06858231c6c8e97cdc2084fcf08aa84ea250dbca3590f2827a3af3984b18e375c5cb932a75af6518210ad4cc36ec356ec032178c900d8410c218e736bbbfd8b5c63ca46d869863dc10c69fc618a4e1a824cb94d5b12007a16388686624000212531440403820120d4704224d15561f14000ba0b45058a20ab424c86114858c21c810630021608c88008cd0d09800f40f0c638b469e26bd230e98288ddc9bc24d1fb3585e0cd9468b594011a94601b63a690eeb2e266a487c948927d4143bf522d2db796244f0bb6edaafebdcb440be312768b2983e671bb2b2b6a1d67edb566789620659ace33f194a8a921be0b1c38a594c0eafb24a5103c5552ee5fe9f06310a98333fa6a1177262cc1b519040bb1c6731153f5fc46af61179a5451c1837a7ca0c8593d90e2bf087aa533eb4363fa66362f0f10da10f87f75f1160d9e4ca69af7a64b731bb74da88abf0460bcbd9377eb8ff83ca2dcda3e1b185d77a722969f118698265c58aea1d32816d7719fc1ec998568c540d347e4e5a04d2fd405169fc4d39a4a21b167a8034744bc485fe7d70445b58fa4ed54655f137dd0595a4e5465fa90730da2dd171047bd829d9341f1771f530aa60dfb2d44d2811bea6228e341d9734daba9f71bf0b800a4a3d1c016d5deb60fdcb6130e16df5b435fb9499a09ac060bc88abb06415564be5a6ffa2e577bd3b8689755b87f045c5c70d137c066b8647aeb9283e84ee489a9a471b8a250c169e2a6fa3cfe40ff80b3b675feb5ae24638e644914f6a2bad2ef78e1774e61daa4c4dcc95969e3518a67187faeab1a748b7850aeb0201676f8e86351388171f08ef32d05af18896e0a5d471dd1f112e7b4833d98069953ec3a5a4925356291095aa4bf134f487c5ec53dc7e24e1a8c095028405cbf0767ff21da01d9a541daa18afb1644ffc3027bf82108c58f4b5607cc97ff6135172d1a585a5074405ba64be41476bac379a7d92fcb6d60f289c002c62a82bdde4f97e78a462f0ea2014d366ee64ab4315ee966fc2ca87c700d9623873512e2c72522f8afadffb712ed3f04660fb02ff4e3c5a620982585d1c70250cdbbc77d574bf61334475db3b278706bfc0847e4fa2a2d24b500e76bcd596c492da6537026843d30525e3a2d55bd6e1bd4477a18de7b924ac6c15bf115ba1e2d4b33fc8b48bb842119ff2b38505a09cb7e338daff0a755ea194ccce3f2a2fa255ecb271ac591fe7dd55100dc14a9b0dca02a45beb3bbb95ae7753e75c7b5cb1078ec8917bcda6440f9457fbfbbd5edff7600e85b29fd3d0fb53fde9cc6ee8f9a49f3ec0dfb0a0255f8cd38eaf5a0b36fc818392988f828a7b104ed184f60101974c611bcc54eb22106f459c2b626815dd2a5895ac6ae3e11183856aee51194bcfd0270fd6a0abc266f7d6f1edc17b80af3b2dd9510931e4e6ae48aafa931af5fa228c244870597ae848c097843491a5d950321e7e0ec55271bd933f836ba0092545bae57aff489146b87f8e928af8f57bbea36c5a85d2234fc9e1db4e1829deda15cb2b1948b01e5e9323114525401f27be01a37813612cad467c836aa91e1602acaef3f93854ee459d89ddcab95e71c3444654ea0c1631c4da25e69474c88a03ffc42cb2998d468160408b1b6456b46c284dd586abf3f9542e56538356f6417c137c8e1dc92a3262d7ec7c9dfa5fc79a61e5e33e0dacc1def9e34134795f7cd1d54c18682821ac55ee7f519a2c7e4a2dafb18b23908197861b54e66687afecfdc4c0609b00f347829b45b1b8b4f2c7de0ca777f05c60eda0e7af9d17767512c19873024adfe3a251aa7dffc2d1a8d0184378f0416430c20b3675e165614495b2b6df9a4b3f16eff2a6b2b239329bb755701b8aec423e074d96e4c5020df3fd2a44d56ebe571c3aa34ceb8975d20395ae73bcae9c7f538f74fcfe0c6ce63bc23e5ecdc9d3a5e322bb77b6f5ec4761f709dc8a4559c4743a904d387cde1e2b4225bb71c40f08730ecfcfe43b8dd4440220d0d854bc1edea2f4de56e31a91a6abf65660d0fd89db123f5dc6ddf1e122785bbcf4df050537b61368815d8ca95fd36cc8d699c0a75d60a2cae47ab6e97850ef906824217c4e51dd2aedba280f8b83130947bcbeb050b8d68bb4500bba08a70ef4701a68b61cbc758c14f7c1a734ed12319fc872a26ef6697c22e841a761d643640b0f4935f199d3788f6328e7d92d8ad3c19c7b2856a740d52398a86c2bc161668a0a8c52000c159ea9dfee555d7175c371aee093bee505ab91d238cb8a7c4ea1f12c7306674349e6df8721805b4a1b732ad9b0dd4a0256231c528b3d258e0c3ed4e4b6dcda8d65183c87d2107db38ac28bf52b9aad0ca78dd9046d0cc6be3a3596fc4698589a5c317ed7c79b406bb469abdc0f159c01dc75dc4ffaa87c5f436f98c73c000a724d82a8d44518ed25cf930484e7eaf0e601df602487fe7a85b4a735d84b80e4b411c2187359f45fc3344c382bfea7e4c8a076b7298610baa97b24d50173d6ee222a8c032d3a1135425ac553c29739c8207869a5bbadcf2388f63f11b0c45cb970a23c14472453605c378c015554df9037ad7997d38f4f753cedc4adb6d6a65cd4eb0fecf4884ef1f4502ca554505325f56c39f3299d1ad4e378b622def40342d38dea50266bf274a943374df4860eb27362daef651775c933d2f57cf886c964ab42a19973cd87b225ec72ceca6ee3daf93d274b39a91f65c19828d123af5c45029273ddc1ed2811d90ca0cdcf23b0f13dfc1215d56c83b6cd61ea0456a8ba9d44733a791a2146e90282190e16c26d4523aed68506ee07ce3d121fe4913358145fc2f288b32c3e1ddf01ff1f3e2e1730a4b3864691e36a33e541749ffb09fba0e94aea336990a3cbb20eb138eee6da10e90ef51a27f30380e0229450f6e3d4061e75726c6b70235307332542acac56db381498ab8b3f0b773858f88cf392ea1e6b9e25a00dab566f3adc54fc883b43acf6e6a33050543d5220856b07b3d737d839d3af542d0e231177716fff1c3edff133835bc7fe2167a0a0ba158f08d73488608acac4a1ec51762f3c6731493e98a067eb193795ce221ee9455eda27aa2ab2548a390df17121a3e411740de0a55d6d147a2be6048cb17900bf0d30df0ac26125c59c05dbad5a37d0e5f758ca55ff294ce936178093a36df7a69cf629ecbd2ae658b2785baade697b94a201c229b12d76776e9544cbcfafbee214eb120b5b4c297085f5260c0f122371f4ea8c5d19192318a8150dc4198fe2af6c28581dd684c5bc4579c0087a129ecb663fc420efdc5c4022fa90e52c559cfd17743cc757b551b6516e3d97c8d099ce31eb815c0c0d6c5c7d0b7a641679132e784b912c0de4a4b3385fa3601574012c9be558602218950c26ae0bb51a08606624df26eeff7ba6a852e35e4f35a996956dbfd47fba0e3131fdd4eb419872a47d23ba5bfc98880a053aaa2d21b14e8fe6789e924003f08b0b6b229812a4e3c03a86e4cc82c56a76b05bf7d4e550c167cc010ce3d87eacb1b043d69b3978b657c732f777415deff1fd357b19ae6b5a18b002d57c4ae58a4d1d462299723bc93fb3bc3b9194af91cfe8e0ea6a2bbf01795126a96ba69ea2980d6e88f0ec0242f2ddad280107392eafb77105625d3c65ced3e6027d589e720470170480721530eacec86708d977f356b361eb25ab94c69da7fbde79ae89f5c0900c6027c6713a20188248e9557f4df7560c8acb22cd792a8f50a7ba66b19c85fb858d46f5cb37faef58f495f49cb1589e96fa46fe2d0a21c79604b4dfc3c0aa4d3015583414d7e847d7de299a7a0d402450123cf9042376eb852953767d360e578bf8742e24efb0c11a9be2a281b4bb5c745e9371336bad82854dbfb08a7bb31cec4602e6d46f889447e620182f0d748a113023661a506c5a8d8905152054315a337a42b5724b105a6081fe0c0e16b0a6e6af3a7721600cc90562ae812655cf20bf5d4e65003a9689b0564b43b52b312d73f9eeac5a34f3b81c1c62c1981a8d141e98998f23f68db71f102a921d937522eab846e522c4849d6d2ffcc3ea4dc7a9e24041b6aa111c0e3843b812007661a4df9a362033433842e382d0e218462aaf5d8ef4f2a40a5383506b34346ffe639a79d9b5bac57f6fb47167382f88a3a14dd8b5d940ebc3ded973d11a7e59f9a03385efdecf6c7f421795c4dadf011c1412db5f9db0ae979a7c3130696b23181c0688335058c2ae8003555766c888bfc6036202039a531c8d93960fa110f3ab33b37045a0b1f41074ae5e5cee115dc3f9f1beaf7d083dbee45328e8bc891dc9151d5310c7dfbea6621a3ebb6a71015c8a1b382cffa015b6d78d8b610f544d51bf1a45b9e107dac18fdb84a65c98fac414411d84bc3b2016f31f4220eb009ccd3f2c811f34775c0bacc852cc2aab06a993aac74b3e04087c0aeea7b274c5f9b6fb356435f726ece2ffd97563457bad56ca3a844419b76bf7743709242156257ebfe8e1f505d207798d6542652d698eaaa4c00d3b93a37ef99ed522b465fc11f675a353f7f5c054d47e11f4c4a061e4c57597a636bb1cb788a62a67ec6130e0f23a7bf10dfd9bda1801cb87373dd7cc81c915984dd991000c90e870fc4992543f8470bde6a401e9461d5207e11a2c2e0abb6c0e2eb34fb5c6bf555fb78b7e78fcd68a331bf85662367dfb4a6d7118696797ae71df5947fcf9179128573fc1a6a2d43b611669ed92fcd32c2f9053f5675b83c35b38483c8d75ad268a91300ef6108c89a6b27c0d920f3434058f7d90d514d15165ee95175f19d89b10aa2617da63d97a555058659864533393a6c0c79020095843281cf38c51d95f67d84f0a032b0cf3b1e9910b9fe4fba608237e3a3fedc5b139f80e53077ca3b1a1ec02c5fb6a6efb68ebc4905e9cfcc8fd31d6aee3d94fd29ae397175980451a1e5f51f6dfb8619b6e2c7664d3bd7fc94777a3ea9e46e09f1659ef89e960a9a205b8aaa4829151b7585d43e09beaef1489ba410e14fdcc87506745a358f3fcd4435e3037c1f007da92b03162669b1f1b1678460bca4968b755d44e73fd38d65a2dfaf632207ad84f4d8f0f35eb1b2d5239e98d5520d041a466fcd2713ed0d831b3b6b8d1526f62ae8dd6b0d5eb5d53f138948a7cbf834c3abd7b35640dceffea2df6660c0b4ac469dd60c6ca8f8251dfb61b1399da5a4de0b3102e807dff9cdab5c946dbdbefeb632d54206fa088c1cb33829411ebc24e4cec3f8f99865e880e3ab5fb00244799324929cc75dc0c39da0f1d302f1dac94ce082555854950b541bea897248697aa9cba58cbce16b55de492223c18f3a1221cf5b8289bf92e07eed09a533b9e3ffa0859f840f7e78352af87df808f7b872e82231d90b52978ff3747babac1a6a0c3937b479f68f9cf9cb8ee973f2fee1d9d47888521871b64cebd3a2c9b2e316f703c37ea6b959668a822fbbf072cf1e872d3fb9c3a6bebf4726d8256b216f4c210a129dffa8cc5e2634f54b3069cee1342c8c9a6d16e4f1cb74690d599d028d653b5af8a0ce8eeab66049cd6c7579da2557832abe30126336c0a9028608380d13e39172bf50964f260d2e9cafc67e105af6a68994fb1bf15aad540258b72fad748cc33b89786bef5653dc57179002e6af70b3d64d5899bb6fc1b709b4a21ee3d5d8536139f89bf703aa5adaf01a5dfee4738215ff5ab7fbe1fabd29c4a259d2bf57d0300013c800a1f2ee274421a7d4a21afdf44aaf1e317949223e38d2caa07d70ddd21d62ac3c7fd79d63fee566e23baaa75825527702ff9f0e895452f3225f2aad03d748d4e88a594ef64a05bf66e6678a24bc388039fdfcef666bc1431d047702b92f2d7a94ae4547706ba12296ea6152b82aa91482224e6b3aabf631573540fd2d6c35cc1dcd9e329ed41e9c444ea71cf2ccb3b7402d4b6646e355008b2eefcca9843bc5fc39308b259a2e1cf16b0be47b67169c1c5ccd2490a3a3ff7d59415df9735e0b7e2f711f9d0a7d14b567c40499432e598392a9c48d6c4f4cc2e2c82eb790541af7cf11589008f4169cc213c549b39a0beb8d262c4f0c201ee748dc10844d04e780d7392731f37e8600de71aef921a713a6930d4a682622d78c6348c78850c1bf20b75e1d2b7277b972006747d9b8e247b98348d19203ba9c55c2ec4d42a631aab15406f16c19ea3438c4b47ceec7350e402b36a2deb17f592e852d14f41f49ee60094f52696aff93105d5a1490295de9de82c96889b247b12e2a324c265309538b48e7b9f7ff9bb10c58d42b7960ec3287fc085af0ccf47ff7c0c7d699ac099f0f52ef12fbc3a1ed408aeed72ba7c1d24798c2688b14e6b1a8e433a67684657e695db23400293bc31be002f3f8423d95c7d653de15285cda8f031e8a56d9fede084d21f27b6d4c3ef7b026701b92d82472c6bae8c08832b09ae7a553272f470bc36ede1fdeb5d70b7b98df88eea7beee4fe7546619036d5c7c9a8bba8ff606930b1db53f61eb245d04c30d41878ea73889166398133037ed099fa2159910cedf6484179f9c681a90dd290d870f82d6daa4e17348422e519bfab74d4164c91990143402b1be2dc8df6592a78417528a611b55093aab15a2255c1672d7e917294e7707ba406dd044fd9de14bbe389b34c0ee5df491364b6aa6788247886bd981efec9975dc5f2e39945cb4bad367dba333efc56521f57bfbeefa1c1c4ca3b112c12012e73ae65608c3a17f12fc5289be6a0b40f865c1c85dae78bdc9a55a944891bd9d9591645df6aae48f1fedb4870fabd63bd66009315cd9e42bc95e5d65300d79a35821576cc8dc758498593400daa4ed2497288bf7bc8303c1d8e69066a46766ee19dc710ccf7c638aeccd617260c3701fb120dd207c5102c54def068b6c12accef365f6b7fdca8300ca308382eb5f124ccf340d58f543fbeece6ef0fc027a3e56925d3d96660bbd26aa825b492d3dbef7ad853e88c08669698400961687940f07146c95fbbbb3c27f9de6530843d8d163e541323a07eab94aa3f9f3fe2809baf19d268fa42b5d82ff0071fe6253bf9f0f89751067e64664d88879d183820600ff63640a25c5b2849b1a722d521e2f8603c6ad60b3eeead78219f8ff207dd85141088407f9fcdf48bbfeb2e9baee6315c851f041f4c9a08f0548cb839cf3714efbd0f6530ab08659776f1840ad38485132700ddc00f15cf3859eaffc567019fb880dccd8971006dbd1d9580846ef70a459ffde443e858a416b8b99068511d0f2d15494d43ab2ac9d0e918d27c74f7bd420f0986bddf2b19b10d3702d161f55c326e9b0f77638b72dd62b938b66b21078f727af3ae55e96035c6ee3f98059ce29a4d5b7a96fce8b9e892874f5382c4d88cdeb05aaea8c5d06284d8229616abc456629458524c29568b25c410b15a4c25e690deefe3e5ba99fd0f87eb32fb9f1ef7cbe47d5eae3753ff69b857e607fa6bdba257985fe4ab3f5dae9fd9f978dc3fb3f7f1b8bfccefc7e5f233359f167716272321c8e5871dcfa66cd82d5460d9ce09094b58a13425bf5aa04babd977b52475d88630d8ce652a9bc2ca2f0559b3b000a07668cd29df36bc5aec40c8dabdcc5346386b968ecc95720028263ac9bf122e5d3bc619c890bbd31eb130c7cb919293c1549552140eae8b9d6d02439878c10b7ab39542989b89b989bb73b66b11c09877657c6a58fb78d86dd3376340e104c23b906159834671b87860235ab8a3d4c5a18a4ac4c9288f73e8db446a487301b6836b8d0c4c10e01ccfc8606947eb05baba540107429f50f249d2b5f33c5867498215db707c21455f789ae760cbe8f3dc55d1d34b4c0046bdafb94bb78c64dbb8bfa625ec9ab6c0ac3a840718d98b0cb210ec5bf38c794e85933f950c9a7c9ed5f2ccefadaaad0f66730ffdf6280a40caa5f73b5a16c89c90b48ca04c1c10a1113220dc44d7f1f90b2224b779908a52245d7cb224d1e42a7cb5e6d5531bab1b477630e73ca900516d8e53f9a454cb0b4eac398af34f3740007020a821d52536c2217d3d7cf5b7cd1bce86a1372aa6e560068a93dbe816a3427a4ad6182acccae113299e78b038a13b44532aee7c9c7e102241839cd98f9735f319dfb8f4e108943ca884af8d134889d97ebcf9c76f5913be1b61eae0a6cd6529d79758bb3777763ada2e251858d2a4cf84fe5465d77c9b803cb705f9bfb46671d9c056083c366a8e8107db4af8a714af5f0f9c3c04095b3d1b801c7a7e8f11d71019df15951be6e9bf685eeeb2abc8839782261ebc1c5f2654b5dbbd61e8c01f8ccc0d345e1ce4e695d31d12c683d5b54f39850f41a932fa7bfe29d25eafe6a4effe70cdb86057b32f1a9c18fa7fd68725de60c3c8853338fe53913586e4b6d9ff5c589aa8d590f5fc4e6a2b76f1467f82d825a857d5c945df0c1c76434bcd6c2fa0730529a3ae71bec3f93661a8fd9db88f570663058c0268dfd432c83b7b88eeed3ffa7f41a1a2568560a079464269d0e8460b3fbbb8fe4f290210e0d3cc33ae14f05c4404b09d478cee03335b65d6a1faa5e03b9f3b9336e2bdef658efd73e23d0525bdefbfb3d75ca7dd305e90317a692612deb4f5c5bf471db4798eafbf78a56ba24e24f18a542c9aa3982295574a4c547aad9b4a7ab5ee87f81fae3e1d1cc0a026e1e298e80e592343817d6ff77bd6104be681f56eed27d624ae0c07c27b81fc2eed2bd622a64c06f2bbd967ac2e310422a3f2b20f1023c54f5393f8c7b93144370119e80010f7d31c0c7d6ab046b54c88c29b009470688d3b9cc61d56630d8c29c5018d7c288d3b50515ea25ef74334eec0a5116f812d16251fd853ae4f4ccbb84633762709d18f4b2d386a8aef427885a507536f02142613bac697bc2f6951e79da28287499a0486207d3ebb94b7be2b54e521e618f81888bf4cba72f5e2b7c414fec27210620d73ea78e2b9c7607becec99a79242a7eb37de320ff046f8282e4e9e93e75497113bfd8fe9f6e1a1a5929aff41682c7a4b53864f62f17540bbdde0be30e274b79ae4c965ad5e212cd400373ece183160c8d03823d412b04b2b75730ef988ad4e139d247613945386c2cd23c2d7bdc8f20b91b1137dddf00e882689f3a5bf69ad473fc8051e48e26e65efb0f0720a3588681f05cd6e143e32b013b8cfff3ad890719c694391095dcad567c8356e43e7af35a6e001f67bbef8409dfa85f412036f7c7f64213add10bf60d90920e45ad72f93dc2a4f6dd710fc698f6d0d362e06cd21db980f895879e008f520ffcafff913fec6dff933fe36fe7159016239a45a621ada66f9e77d330cacc76e7ac5d43a97c50dd22f2e2814747ce4a73698dad8892f9e86aba6bd43a56e883cdafbc469db6bea9c54bdae7546d66668d23ba9665df28ca87da2a9f9ab7a5de517a9e5ae49e35085bbc81749eb54d3f76e4063eb6e6f215db74bcfb2c66c8e5f435de916cf510d2fb8bcc6bbea96759641b5640e98ab64c965582a53c09c0fd93f99eac7f6ce8b526a33e1fedbc5843366f86c2ca74a0a33244e75421c7498bbea84049ca26533b765c860008b814ba7f05d5e67d8786c970b1ac3c7bff9cc60f38a8c7750a81271d9c8073bde2d71983ad9e818653574e8991d4b4d1e841b21d8116b9920a253751b96bd6e14877d8d871b5b4f35946c99dc026a41de58830f2381b918b6ad59b7483ce08959bdc3e83217d6388be12617fcffbb49f3dc9e0319965ec8c5098eec8547f77f5f620721500fbf80943c8553ce0049fef9b84ceafa23f823e03f0af29496eb740fec981ab42657df7cdedaefe26160e549e93420a9171a8d44909457caa6c51ead49645b3db764fd900444028f4b00b1d3ecbb803328e1a5f456dce63507ec11ebe45d9349c08806979c4ef00d23d483686bdc23bde33e2706b23e4be3d0e59ac19b83106316040a2f370159404bd2757cb6e62262856df72ce0e16226797f1c40aa81fcd34319a5a048e8855aad0d5b69e73d16087d18f49b257664b5c456d0cb1eb0f03603edc3cfea642a15a04c65b04647c5b1216faaca3755fa9ee4a9148439585556b7d9ff6f83e83218259cec91e9f9306c1a52c3520e429c0ed70bd509e6ead23306e2979591b92cbfc53b001ed7743b437d84634a3d26ee3a066d7e3b0148b4b199f2689e9f54bfe712b415901113899a9ee4713b13b370d8f46dc729c13e5d91e4a948356ab587429b53407d01fbffe1427ab945ef85cc4a74aeb8d1fcfd3a750bcbe6b645f1c16eaa960499aeb1f58177ae23ecd4070293a15a1b8a9931172df8dc589bb7696a438c3e942c7886a44a2de269f40e04ed4f38716af0536fc64aca773742d59f3c1b7dd544226e4000cd20eb8790a853a78dde80b8518bf223531dd016eda6d61595a57c228262104ed90720955f5429356c16c73a7a54c2aa6c5dd565ae13b1c5d092c470e81519e92de0609d63f82b597533c95cae84db26a6c15ded7c5229b18a1a931ca377635311a6947b700b43e19910c28e01fdbe0ce0e13d8b4f78cdcf4348a3d824ba9811257687758285244ed9cd6b4f1bafd8d7c2e1b7460270dc84a94eda4034b9b945f67cd3198eeae8f576744b040b1b6123e6f15ed7d625b5291975ab9575611aee5e3461f76f23b0a781327a33f141d9ac9b81f98b487bfa7abb2a8873e325198ef562d03c77332c5ea20fb21a74186741ca115d072281223183637e7f09fc94fd2e5c28a32d8b266252ee3297ec406e3833575f1d231b05e349a7714f421b3244520e574ab96c7c524b8dbd4b6ac7505c036affd33acc4c27787c278f4e6dc3993a8a9a9337b049605d384153c3a95e93196ca21b226924a938955d72fa96eb6b7495948b9a05705e2a6564bc8ed0d8d7bd52b53f892a4b4ac2218aebd64aac37c93913db16aea16397ff96fa8d155b32f0b1a1fc14b67f9d6e2143b7fc6542ce02f1427183451606927ad3abe70a43459b88b8ec4476c15b73d7238dcc0f8a1d55fbc6b0ad01c6cd6aa331592d62dd87dff5a452a33e4986f9e30dabc64f1a086fb5b645cbf519f639dae4bb4683c737b8ef81b215805559ac9a14eb4f03c8d3f23fdde53fc0ce8bc0f3c92c10a0d5f65e33228ea54c57435738e7a334e2822982b300ccb6987c114d9ceab047696276a99ce490270a6719eda079c51f17b65ffffac3c64450e21f8a8646735d84ac96efe525f8b5f42b94c83dd426f0e0cb1b4b701234d675df815a61f0258158c7df13530a2e04f93b4012b589499607d422f8c2eb33a05333fd9bffe1bde787ef52b383b540548f6a604d038694773709b05586bfb624ddb143d5eb0d6c00d8e7b35f6ac53139f20465589f01abc59bbbc0c459ef1450c8ef5cf421264ed6d4fe6c7e4348a7c8c95642baa13b2018fad9e98fe31db79ac5cef0b07b0e7dbda5f3d68802ca986a91ff60af882e10080722968c88729aabbd4809c34624359c80e92548c5d2dd2e6f19f4643cf4e0ac5a5a4e404843ed8191ba7221cc2b4d9d32f2eaf6c1f2d34b4eb12b588de8abd0d8a08cdf80f9ecf2e7af37373985506c837f2adbf579ca75cb1f79d5605c3ae4305460842984830ec95cbbac1839fa518c3643396a968afbed590b74c4a86b22e5b80b70f63589dbd1d61b142cecc7c8ac19c00b2dab60bd10df68a55b0116e95ffdccd45eb408daf1687fdb639d85e8739370df5823e7540a6bc570078dd72cf524e5ed3e137024f12a9b7dcf4b9ff7e0ddba0cdbb719a157becb628c9be2f79bc819107378ab9fbc6307e0e9f5dff1a8d85878a35b3cdd9617ab2d4dccf9f08f4f028f0ba9b25eec06701feddb049f77499cdb444ec518726a88df71175361c5bc24ef9b4f42ba802d7d95e863baebe0771af51c03992447918cca3fea3f673b66170c40c71042c8a853764018116ed540a5dad84f8e917b49609d7443ae6e7b8152596a6c9a6b192fb87e86aa1abbd65ebb9d140672747f466dd96caea25af4ee57473a619e21c74ed417bc3f80d45d2449bdcf018831bee489bc37827a3784ad5d3874605dc9e7a4744a2a8fcbcfef564cf51ca443c34380c10c27d698b827ba6222f64c483cd109f2f53b45e581f65437b63b2c0dbbfc152afff6fe2471e0ae45345d9bd05814a6a6bbbcb49c3d3fefef928669d1d8669297faa7ec24031ace190d22bd02b4e49810e6ef19ec7d1b3590dff463c137224d286bfb066b0bc02e6b2d6eb4854b9a59c6e83bad00b373a9ba4c54f5309557e367c3c1a64a122a672650ce44fad49dd7da68578527635c9fe2c75d5153e0e8e8797adcd2311c499b1934344e917d5bf54db9608c78187aaf74e0b0a674a9bdf14b3ab3a8fb73816df44d6a792f7706964cbf1a8e49872ca78cd4c3128eeffe99f07d509ab231b9f4912692e986e3a91c73217a5985b338c35eaae25677ec2ad662a076e41ea3455d178fa6d6d73786bd776b807c8cef0e641b7f6a6e72b33bdb8efd94e37f88d3a5edcd86f05c80d65d7578054f08a3904abaf13df4860b601d7fa70e3c2d326f3e5f13ef7aa37578a75fdcff69ca11b7d2dbe688cef4a7558907e948df5f3cd2f6a8c4c0489b7f8f164461ee7a25f8266276b86822ec0b87686a36ba831b4c6a8feac94a049b1be25a4f34291992459bde01600719c7d0a677e0eb24a18d54ee4991eb240ebbb5d9afb6554d272c4ee9a1c400669b8a527150e2ea068218f879ff0dfb40ad0d9a50e2c401e51ca7458a7ae08a69d0292c896bb49695e048959480d4b997637d1624134250954dbe5ee833d51faa04d561408ae7c65bd91d7ddc9d5db911261c3bbf7863a0566dc534bec8114e932fe25a4569848a3872bd68aed8006e4f6bbf76bca4d1897e74de0371f966430ca4f7be1b6fbeb81736e5776dc7fa6cdc927456ddc9f462e38880d3115726c403803e704eb58104fb1350ef54f495ef40c81a2769bb2b24f5d209a4fcd6bbdc3f05dfd3fc0e5707ab4dc03d74ae6873952191cdbb66d9aeff820b5fcbced5df5d8b06e2fa0e127ffabe46d03a71ae5e0ff242ee01c2d222a5f5a4e8a10312a93cb0ba491fa0f46260a4d4abec19674b4cf57e4272b4a9a6d5e45160495c2dbddbb5c87ebba2bc8c7ae91081d5035a38c9a8eb506ba8b30689ba7bba37b1911746f2bd4eb93b075a2a64d50d8add07ca3153ce3cdc02439d90116f8e7f7a914113073c109c42852a212adc8de2d955122f3f19b43f6a72456e7ca83ac21cdffe6b14198e3f92aca325f43b3ef2286e412c2694f4761a078265291018c3f0214137be14183cbb91300ccdbca75eaabb0ad50b5c561d1979db92b56d0fbdf4e175c2493e9f485ed74eb20dcd4301c76da4c9f98f6542bcabd06b3daee9c293fc2868af4cc309d5b6801030b4de3dca1b1d825492b49e6ced0a17c9d0f9b7324cca60f949f13b83e32d5b45dc3b29122c987f31fc6789facbb689a9684cef4680acc2a4f60f3d9e9d845b314ff0ba220135737d1bf037a3988997c481c19dcbd43f3eadfad23ed75749c505faa8e37d423eaa21217d0f48d0338fd2bec95ae346e9768e736704180b489b79ea383d31f695151039d06e3844a8e413852e889ebb57163ef292ea9995d1644181e021a743a7dfbcd35e339667fef0719c06327a2e75a90c1de28dc2551f69dbc861219cbd5437e4888bcc1c7ad1c87202f0859e234b9640d1144bce3647bd2ab2449c9e4cac9dc3ff15cb89abc150808805b8b6265046a64a280bfca17f34685109cc49b6cda27b29c49e5b374d727eb241709f3ca363a1795c49df012f056b68fb6069626416a8bab9a637defaa4c0e25bce48a367eafb8152b473f02b5546d7705cb61ca75579db5a8327ebba1d746273a32de8d2883c72ff960a5ec940cfd12c1c1087117a3d836cb7e4102d2e1127c4862227f28d26e641aacb905b076dab950586e867e7451596d29feca6167c56acdeb3c2df97756d21279774b74bd6046f6ecef31076889483ccc8d2af7fdc29bab05a5a9395ad74c62a788407d04f36df4dc5b7e0ae2ce3ca534e891133ff12508a7424f440eb1057730df69ecf8ea7259708fcce218e7bc2a67805b45e96cf72978c262d1b273a00d32258c49bd6eacf92f42316aa7c42b3660ac25bea765e08d5cf000e51b1ca3fb205d014cd966a0f06a0c4cbe7860f4152c099cd0a9ea47be8be2b93abd5fe2802c61239ce057b462ad4e6bd0f717623d7a2f9af7703cccb5d3955ba286d47746548e1fd552ae52338eebb8f0983cebd1c95511012d3fcc75934b6f0cb3197fbe0527f1f728ffeab2a2c881f30b40bde3e5a8f06af886ce269f9b8d50253aa5699a6eac1e1c3b71b144897527852921b422c3dc29477491dba2659c9e1011def6ea92529fe90c405af60b6203c44c893214c32c004e156e1c14f01295e49a9267c5db29f499e2d246f41c0fabbb8b2fce1e67c0aa9e08e76542cc6c9e264e24c5971fd55aea756f625122083ab4dc93e8a6b30a90dab7f0d2dbaf304ef7690206e30c01be64436ae2961c0cec50431a5efbb20a4c6bd9d1d6161d2463644b8d506c7fc45ee322ce4f18f52576bb71cfc70b19b701ba9a63542d85f8adf4e90102f23c98228c3228188a0f0284a9aa2c40b3d0f413bf4c8a043a3921b84a29e2d85798b7b3a083c3bd9ee8ff8a4473c49905039775a5a480f47f5b39463037e4c2a8824b5e3d1d4b34dfd8475af5d046484b56aa7a641bd12a08903447691cb5cb23c3f2b158779266bd67843d3edcdc7803f108a4b299d2e7b7676b4b886c89c98f733e7480a1464b58f64be06e4b093746c94bce0e677a2c411081260718290990e6a254b6561d3f1649954302061a25f220614493716ee9166b981fae1ec96b91ecc7c30026fab561613ec247dc300767d5f37ede27cbd7a68d75b4440342b4c2e21dd79c025ad662278ac1b161af115073cbd6f91f53646aa81a88dfef452a1a6e2750082dd89b000d2146086b894d714c73fe3bf00d0088eb090c146736221bcd501ad958766567051d211c6b3d7964ce7d3a8ee0e59087060056ce22dc16eb3fc50c7264ec881754a5bbb26711bd4fc3911020885823a00fba84a6095ff9a95c52559b7919bf277402ad70cb690345e3de94199a5c227ab182b02829d7a842fba006db1db8a7e923f232ef3a3cbf8fb2cdcd811fbdb5f66a4a37078a810edcf67d8a0f2fc4109c3e881d6dce057b82f8cbb53252d733c270d1c9d44ca91815df377f75d02a937b25dc4439a6faca5b5253fe07cc7131808d76cdcf659809546c3e75a30b56a7c094632401d08cc87fc9350d6475c19086c88285885754c05444e5ee1e5e78e745d6f310d30494d5744140c8280902cf041b0aeebb9ee10d935e8842987e32551b68fceb919b3ca1751885ae718c0442c0b07895c17bf921740c5adf18980ed136be6e0a4a005d3e0c68a566dfd36bdc1e723ce9fdbf73dbd4fd4568ea27b26204abe7149c39f1da578c7f64157e8d48227452b9c92f5b489ccc2125e079fd37ca23e4e2d6d88fc4c9fa88b648dff32864b2d524366fd5f1139e016b300f95bf07b0eff2b864acf83bf7c6c716c658c9fef920e3a450cd09f3543f48ac25f36ea288aa67d6f131e6e5bc47f1e49793afb26db171802eaee8f64c03dc5c4d52de00481c05ac5bf7e9668543128c7663e639d4ac16e141118d16da772c37b39f31d0c9845c9ce471a4be909dcad6c4ae5555bd255cc6fec4079683c9fefc232450feed3ebce2faa39dac45c849d16743f3d7d3eeeffeea8d62471989a6aac9342099f90b8ca833111bcecc44b31e17ea6a000f30e600193c43ccb0fbc7d9ea0d190a6941efaa1e85d264b55d8325e69988aa724492000c61993ef3b764c67aca8106aa1776ff5608e4d5921983793d507e18ec487d92fb53673a966b2ea9d54a894e207f6cba097ac96f0f5abb8eea71bb87d4d5c0ef5e3c232b9e7c423df326b5b15775d56a46e925cbe02762428d4ed6d89a62aec03527b7d9ae453ac732b80d1ae2ad62769fb27cf3c484cd875265d574a053d86b569c9d7e7d1c77c13f11a26c3a562961ae9e376eb7be9363d95742fadf843089b3d2e9849ca27fb7e2c39473afce0b1b11348527285fd350ce9b30eccae167560f2f80d3c5217910eb8e399b7ac008b36a22dd3e6fd0ec4a9c8f22049b5ca7cd576cf586f9d42f1bb55c9485a87e300e4b0ff683b40e165b5695da24e851755bc56004c01b2f62798817d985a7bc57276f9112ea9de06dc2abd705a58e133fad70eb106823f7d3e27bcc82dcbbca9131581c9d2f64dc7b223caee2937508ad9381a97bab59e8cb1aa800c2447e3220ed7f962f16bbabc21b668731fc50e0757003e3a37f8275b0aa121d3f0306d774aa017b81e5cbb8714c7afc0b8506c92b3beab8fa03704f416a1108d041b1851ad8d637c2d94feabe191b9322f32345f3538111e270d048d11c556539a028cc7fa8745ed495a83b7a83094fb3ee7c0a6d75c248c4a137a672f4e7826d404c8d0d922220f8efe16c73b21fde124461aaf11a3a0c91d5190bce3b244b8873c417cae45852226c4997692bc26a4a5efc80ba77b2474bfd4a1e3ee4828d4d5ab749ec6024d2d8982a1b54532194db093a62365772f10269a58c1ee994ef2e4227e430a2dd917f6ed541ba58bcfa45e234eef988f8a018d1d6687d3617647777f9a8da5b39b2b15f56a82f3387d3e7817a6e087608c7bcf8cce24983aac4cf4319036f99f1ed2239a351fb0d04597d14ef432a0b1552495eb1ae10e50c10f0a8865c99a035988d83cea2b768841121be26e068209b3a15363e11b9e2e5314f59ed46a8dc5687ca064b89c5d0b46dadda00b3e1c4b3faf85751bc89fbd45c1ec32990ca71ffcfdf4f2baf16826d646691d26c16cfe1c4ae2bc68bfb7f9e01babde0fd7c1a8617af0e8f510d5d8d209f319caf8c9dbf36e02d5fc038d05ed93b000716c2226229274082a3fb0506c1a3c06ee27ef69935f72d98a0dc926281a630062a1d337a4088d07c34ff4d004122549ed27d9df9869174bb29181456136b09a28fd5dc529b079ef698679891cec2c75d7773e9ac803113a59d2ea7bcd8214be581590fccd66b78c773b213e51af6c48fd26e824495298243444291c7ddf0ba92aee68fe97df73a1c83dc80c1eadcd57b0268eb3062945c9928fc4feb7ef1a05534ffdf8a6e58941fa26b406ab5b05969dc8c492a4e623a2e7054687ac4f45852b22eca37e2fc9716298c3ee707b6ed789d9e2ac8dae65b15d0f7fedc875c3d764114a945fa0d68bf058729b9420305859ecf544dd8e2ede3f89dadf7a5610027b3a4cc9285b85529338bba8f72207e7a64c1e7930628c4ba57da682935932600bd2a29ed23e770f65d6e998413dce62e3022e793ea38e71991b0a1663202371234533347eddb0c3cdc775459242377e8827ccdbceda28c29c008b52e62c0d7139ef8706ee322acf4a19abd7004af0567b80de4e7a4176d53d783d61d218ed093fea716f5499faf9aec6e9136683e0eecea19f3e56ddffe4a066178a676b17b036076d202cb71c66d3b5bc09c35a8e4a4bc41e7da2bc1569ffd8501de0545830c94818745b9125458e541f5af63be2b9a29dc6f110d58cfd2d73c46e3564a427f986c29e3bdd0ace0f800ceaefa764bf36da3b828fe94fcbaea10211222429ce42c9650934811902808332eaecc908f18948e3571898d4ab131bb63f9da35aa1b8e3f327af4787209b4940b923bc5ec40b92d01d716eeb4470b907e197ccc26581282cf608c5abe4c7d18f985453e063ddbb881c902da84b2cedd2101a93ac1fe40ae8156f07bfda353ed93b79fb34d74f583f5fa910459340113442121ebd6661c2ded3dd4461afb28f90ef129965e789b31d26a2ec20c43e95394418fe0fb8d6fa348177828407873e8f63c563f9517eb3e120ed79385cb966145742acc48d70ce44a90ba4d77171620a0e7376e03c2ed7ad5105c4062435be77601ab81083d6cf186b14d4fc02c4a4b79b07af7b922912e0807552375821cf6777a03c81af4cb974c3845aae9d26f77585e35dfca58214a0421cc4f16c4dce5de2593727c6203b9172f2206cf1f0aa68748f9cab3e82dd53c9976f592d13d6a63054c91c99370824116245d3551356ff92d912519904ce11cc07c8a724ed17a8570af8645bdb66896dfca684c7684184dd2ce12818fdfc8746c19929cba0bad00891944a8c8a38ebd46062773c5687c3f335564e9be1085293842f15685ffc990898aa1e2f39b0ac0cb201272a79eb1c27e6e22d8460f1e411bac61df4f3bd506c500060bc5f5edb6f3a460b112e948f9843684a946f1055899aefb88e012ea2791b4d203e4436f289f58a3a728ad58e77f06ac34c0ad8c74a9570839e6960ecca48fb8eb7f1981a1431432a328aa9b5c4b09d16fc0db8ef53e803f76dcfba0003815f60ca2016aa9832590e0a462a0a231b1308801f0890f7133c5e2b495213650ad4c60219f0d0554f84ba28c6bd3ca2ff1746dd558778901d7a3d9c0b7a32d2d7199b18b9111a06fabd2ec555851fe29d14d73ec1dce79941cfb1c4e54a05f90b3ffe050084c590f50a492d8d3c2f028823c4a7c1393dbb43803794150721c4e5de599b35d578ca73b3bf9926004a41423fc7fe70b9ccecc4d324759600e74dcb5d8bae1c7590e51c729e3a58872c1f9bc26b37808ec60a1e43aa713cdd325241e94ac490b0d3104b944d2163fe592ffbaab3006db118b21ad4b3a8c55a98569973bb815e3a4d9745a90ce81c84c7e1bdc5fd0d0b787412523535e6825f50c11db31c77e9dffafe11cfdb0a62f076ca08c004adbbdc86bd1103102a14cd17d79745c66e23535e038cea0fee7bb66a302c3bad5cbbbcb4016fee578c804fbaa5697cceb114a75014c806eb97c682a147efdca9f31a6973476144637a83faaeee95077873e7520165d341192feb85dfbcd54becfe4c44c3b8fe222f623c0611dab11bffbd1ed5bd1ecc247781423e0add3797f8c7c3ce008b702b5b6c364bc20faa6c138d1fbfe3ba8748ef5f5b366e96aa0fd1cd00ffe418212d8b9cdd8522f6a08cdb368595c10c49b2d39ca3be1059bee9e567defd8453727d2bf327a35825823b989c7d6b8065c7dc4d9b48201fca3c7776cffb09809a4a993f522d02e880ba737bc216a9370796cf4193e5057dade88b152ac189b6ec8f8485bfaa64b43879ba17f2bf3015d12308e30a2cbafa339504644d10f9948c437b3fa9c5ae3302b6e8c4ca289bb56d5a70c934a8a662d70fc411b02df4d43fb49ede293db5c8315380f330c3a1cc9c32ea3232e50c597fe64045eac81f1c60c6334f06794d0db0cbbf2194508a91bbc090cd329af8c62394a50dc80a674ff3928b11e0ff41d8d5fce2eaa7d31b29d82444df3cc4767452ba85aa376c965dcf31180b36a535a034faa06c1a29e690fa22eef2361da6a751e83c36ed562e6a66b3a4511a959490e1fc24900ce851a597a9b459536417455defaa11e218625457e853b5289bc40f5cd7cbb82a4791d08c548790d1e7f020ef80d7ed90f359577f42106d0ad8fc515a873ce5bbf9d859051784e9a038b8252901fb8babbb853e7ffcba9b9541156494ec04886476e542d43e365902dfefb44f474bf07c066a813bfb919111019d380b94d44f0af2830b4dc007148fbe471a2438112fd406c8698afb4f0e8c8ddb399ba626c317d75bdc6a2ee03c340f35f425c16dd614ea7a56a7c172afdb2b069d6b0f226b820a4560bed26ad953859e677d1ba02b20b8df2fb8000ac7e4e5520aca43a1101919f238e8cd1822261e74473cedc288ff904fddff6ebe38005c160d6f69ad53c13bd04e4f598752c3ce8f31b3a3abf13ac68a09c0967bfd1c9f33ff86130344f82832390644e9916ab61c49f81f2b5e7ebc812fece27858c3a7656a70debc51d2149a3f13408c2377b50aa392e15e6f7a8de440139f1c381fa170e26c111d7dc05b926dfb97617458aecb1a4fc56d2c46e9ea90872eb1741128ef55cc7671f2ec4fe8ea58ce52f8606f28efb2e16531f7789e7f09a31644cd635e2f40411cd45bc6ac05f88dd8dc4655de01443fb31333fd525a053b9b87f728b2aaf1a3dce1dcc76c58452a0649418e6b7d03ea1b09603794d8e3229884a90c651524c1cdb02652111929601e3c346ba2816fa866d08382d61ad09ba635bade0f9be85014d73b28b6ca0dbf641f289b0cfca23b5cdefd3876a6a55c5d94dbdb8a2a010d72b96fb27df6bf3b6c149e1a17c2f8d8757f1fda82f777644371ea32e2dcfbc83201da59e27afb9566206153351c9e2e002537444b045f1dfea3f5a804910a4cfe15e4bb3e76b60c627f5306f3f5db1df971c45c370c841b2b5ed8a2437814f57aafad6fa5ff120971f49862c9fe8757b216aa2b9b22492c4c9ad9c2bf5015ebfe6ad3bce67adc381142cf5d0a4d7ef68fe8c031a86d38e5ab4314e40f3b39fdbcc0412decf2af8cff66ec06eadc0e1d30a53472d580140a9e535e5eff866242a675ded0574aafbcde7931927833117bbc8c2a5e8976a1663160d5563fca60370238b7021edd93541ca478fda0a98ac594767355a1e5908263f61cb6b95a6c60ac6f92be98e3c44ff3b50ff6c8f1561b0598f9697a8857f776ab6349276de3a40183884cad79bbc7d85ec023484a5ea37b4a411e728ee5751c6e83c93e06fcd83b805fd603de55081518687b017231bf35e0fb97c784e574584fede3860d997a38e4049c0f709404611052a5d77c267587803ec9306818e8fa5ff793048a7cc60b8ec8c6212da4b200c1a9dd160f80cce51dfbff3a569245b0349ad3dfdce207e073f2a7f7f6411ee2f49b04372a8205703e96dd1df2b617271ac04dec5f768004ff68943772a3991776c71919f755e243b2c78ee6b7e701630dce508d47b8304d4cc0a027168131bc84a168cfbdd5181ee11a5112b5be66b952bdfeb88b8f94196adc57bf358b9f42b59dbcbbff08c07135f65a92467307cd8a321df1b074ee0a36da066c58dfc763abbf54d67e8cf92a425f9b32a33b4f42c07d8225237ac042da5fc7ab7ce06913aa704d1a4033c45dd3c6e580676c3047aab3f29ca6fa939be5c36e01690210f09ed583aac136004ddc7a043ce056735d89da36ac8e7b4bcf6e517d752d03f6ca77a9b4b7070eef5518a08944d2198e67cd3c9ae5026fe85e48bf6e88fd7c657d2ff78efea72a8dcfae4b4c3c377bd4cc5b51542225c0a788a41ca4fed4b9c2578929cb0bee6a45c1697a0f20001a611522b35b7928e1af7136e988c58653e57002c33ebc735b566dd5664fae29c4adbac2631862f603f0524d8d2f04557ac509249ac000edaba257c1d405fe1438d2aa6bac3a8b0604276730b125087f7203d844f4c8e0ea7278ccf584dc5aea99df689285145a1e348612e56f254df6bdc7312b27ca5c45e366f3e50135445787c0448a44de715079230878c6d00acc5e60f3aa50a4ec9f91efc3e72b1c0c44bc489ee37e578b6671fc0732990cfa6c4e838a84dca0ba9c95506d81b10566d0dceabe0aa498590d74211458e02e63cf6179871e38d0345a2d0b2410e8683b279c8cf1992088f2e3a7cbe3f2ef08a1c3329f8f7fd0d5ddec928a23d829e02ec8416e873ba4b9e6820df5c71c26e7645fb77d61a903df199b3c560040ecec79814b406dbf152abaa87a3803bb1dec7af19cdfa07458df478ce1d3842fe744720b3b777163c1726ef4defc58c93d93bff1b8c094f6d0637419271f6631817e536758318e1b51014a55614a6c7d6b65018082a1ab2973ef4530cf3b71e3075bdcef47d635008890cb52d9a4bd152d4271029496a39491cb123a3295bb361b58c3e3a58b75e391474946674f3714d6cbc5639bddfc0eb3e780eb60fcb41fc63e939d84b5fd981297409b643c9aca76ad1d53a5e7d09292eb42b37be2a5a51c5b2072d394b73692c1e40191fce536b565f9f89e22d593367ff385667a38b96dba2d4d21fece91246877892b58389d7315952b4d7615e628fe994efb80aaa9cdc03e545e3ea2b46baa4d25901f934e0c5a2202581262c22c8d3e87b87a1833ea34994483555297b5eec40c797b9c2a5ad53889fda7df48b111ded26fee88bc479aceb05abf450bb095f4f58417bb8b770c2538dc9c5e05ed0fe0d33f117dd2a12160ae0c9f58d89b8cd5890f06c6d8b19c4c2f0e0b160c2a936e993a9389a8bd3f305b885df364b75690309b066e251da413bed06d1ee6bd88020c11ac0041138d84a320f664d704756cf851b42527181e7a3d86fd977dc74c96fdb05b9eff17ea865f54195fe845fb32f67edf4f2013a1e71b04cf1943d0249bce9786fe3126814699d7960e0fcb9a42498baa5c7e7f46d72e24be8470581e321d22c29da6005cfde219560449aa565ddd7d8e753a4788d345cff0de655261d5b1f23f7dc50936e228970f92a4aada3509f81f9f42c4087b309318c3d478107c04e82fe64fa69f3a701930f5c0d9416afea1a1a00facfb58539464dda19434851b2e6a1a70f85983327797fc8790a1de2c681fa65a02caee539c2cf27e56c556b6b61dc086bf425b3ee30871f224cc1b038c3e15de9847cb6bcc36d4f11a7231772d51125febd86372ed7ba63e8423be2cdbfbd2b26f3c86cad78a87c59f0de614442cc717f28f34bd1c0b1c5fdca408f880bc16f25d7981785e14ef7a5ac34ad5eae715ee76c6f2ccab737a4a805a77d88b6c4ca5f42dc9082c82d53c29f5658bf66dd6d53b1f8966df883577b3fbe0839f000ae416e8b078765d414685fbb7d8dc0124120c3505cd4ae2a0931c7305fd9eafc8417e03add2d0c40cb3c40699f5092b62e4950bc50c1e69b07c7c004852868e1f1798915a25498bbe45c5295cc69220fe807009221a445878871f23a0bef8b00ad4e58ec245e976226ebc5f0c3d009bba44f1bcd6aa5e80f08584f955ad36500c09c077c59bcd938adcaef6f9ed306cfde4fbdbb0766f88840f8afd10629d1d8049d159b8c17a3c29e3730c5834b5be46c2405331e77c5f78bc62ab9392a85f9df3b0b5c610ca36a5e850e2b9b73d3ed04aeaaa78a73de1fdc2e3cda8985c603ab6a22bc424b93202a56ca6053dc1837ec0c85a435c5c80fa77d299f330d8947d54ed9ebdc5ffcaf088f3fffa48ebfe7d8fb011b53a414878961a59fc879096a54cf5fbb35e09d04b470af17b4374404b0b09e112f2e82fefa9dec0f68124bd7ae5eb04cc8f1cafd83ec7f711050eb413c6b87b7efa14640398be1f9290128e7c91092b923147d1b7264f7c38134b9723c1cdee335c391aa5bc6d678157bb6a82c88bfacf5ff0fd1a9f01586bb2327c385811c8de5ac7179f3f7e3e895472e3ff208eb864d004c0071001fcced8bb028af138d002d2a56265efb7d7f1c1321c4eca9cc9f33974483363869bbab46be806905a3a1b8d655af49fec8894130445d8e9ba8802ff0a99167d1de32657e5a75b4a73f69f02e9c6a7b24d2331a7e8ccc5c8455d066e3464fb717f8ab3f0dc54254593cc43ff262a43d16c321b2ac58d6c8831f38da10674308be5e2a93a9a11eb81d55a23c3abe7233fae1c3b1335557ba146861d39ae262c447ad2c6549abed5667851a0c0477537e36bbb9dac6d604b79e5797378015f34e22be96a0a9678542481fc5ad565e0af82843d17520452ea81970547f1d0745a927be2a4eafc9e23b303bf3fe1c2e03753b27565aa9ec6a85cca8537f79ca881db3ef3dbe22b2ef205dcf8b242834c13f714777f3545acb020690ddd6fe9d15e64745ebde4fd6f21d0289599540bcf22b045afdd39020de604f792db723c17adadc5874b35ba4de3a0047c802497fbd530de1ebdb0098231fb48d2b50462e29004bc8572ce17b840ef7f15dfc6d05003ece0f255a42c78145f82f7e9aab11ea30042afde303b0e3436f95f04bf570a3cd6e40096f9ac735ce4556732adf4ad88a562a97975ff4334c2e393ac80544be9181c5006a2336daead506d31a5c6b878059fd1cdeecb1614ef9d6c55805474817c84415bec3b385607d6e45ab1bdc534e9c26427c82fb292b46064215e49f71c1153b335617ca0b7477ea6c0d748a94ec9c9e5e5c41a91711702666c14701c839ef49275d15cb83f09d90bfe57ff095d7f0762d613f866667379ef08d4dd2a28738f01048041a87e1107fbbbdcb8d2a6d36678d3983891b63881c49e0a49c3a09647daa8c180371589c5b4903ea5e3d51c731dd91a2dff9c1059e0b3d04f11cd2ce182f98d14d9552def90272e3d8ac5230aff3e89d8bf932d27f97f27b8235ad11e71c24fe0883481ee44dbc2c62c017fc7118d705b925a1aa69790b59f8a9ff6e675737328d995e3ba8aa44d014e7bf924023f3d1d0475ab908617dd937dda620747940598b278d626bc7c4cdc871e6811d6065d0487823073775a8e88204e42c56b3af7f5cd10460fae7920093c9337c19d42a1caee5cb037579f0347401b4b70229684f5cfe9b6b54dc789aab3c50b031206f748f47a25926eceedea00ddb6df2565590018f4a77ce5266bb8a5a74251b95763c7ded8e46a20e79b139b76e55cf9d7c3d4af292612a93b10ed63bfc40bcc7ebd877f54b25d13a1b100e43be1ec0b283457b346fb3d9133ccc7142000014f430cf1661dd80877bd312aa99822d8e609865f53b09719ea606270f84146fd59056acc1e0432790bb38f5b0ef84a7d6bc32378c973d3a320168ee768fe1effac4a3b04f439431df56bb549a4a3c77052956bccde3712f8c2fde204a167ec571a8bc741aeaa4ae758ce242fb1009d32e4288dc5e3205755a5bce871492d7193adb34f7bfcf27f84ceb3fbfd878128778e5e45ec3bc074ad030d6f383f278576abacafb204bcf19376fc9301267c30f24cef41fbf90010791294d25325704784e6132e7e60f5cf4dbc9d42cbf46de4e530028ccda45c10a6a247a45889fd9a85f5ce9b546c39b29f81078cf7f39dc169fa09a7814535e1e635fae2bc10f71121d2cb13611eed994e4f9274cfaf295968671cccd4be2702b76628b93dbea3c0048a1071d33da009862ba4c405f1167a1489791d206f406cb15f4242c5bbb5bac320119777958e7486343c1caabb70e62049ca6d0e5aa37bcb9410740aac13c83eae70c05d571ac8fa51938790634d76b30463a166e0c93823ac653a2d0ae6aa8bf43fb9964cc7dfa1ac412a413b8ce11632ac0552cb7f46c2997bf0209f284ccf0c12307500ba1dc0337e17944693c2bd2b467c80d202f20e03af65efd4faa467bcc93dd9ba03d13056796216b401418850180b1f7bbc10350656ad1d6afae7d1a0071d8e7188afe81b7f8a30a498725daea0124b0a8723c94d31dfe1aa8ba9dda42c251bf18bd28a768f74043040454ce095debe5bf4a20219c245d494a4a25ef0a629a847aa78e964b3eed0f0a1e5eaa454ee77e7162f85aa19f87d0a5e7a1b439b86ede92b127a172a68c23e3de3f3e8059955446b10c958a5ae4d95950f3d99e05e72ce86f5436d7693009449291a84e9342a75c2165289f511ef05e6020556748e13a1292e4e0bc57494e453437c154230042c22eef61e8f2e49a617d8ee77ab6e6bb0902f06bf9bb43ab345fba8a6414c08534e7ebda421824c943bc88573aba9b5c1c652391a1316f65d47eeaa5b5bbe1c932d3741b308fc515f4be874a09310e8b837983465a835e491585ea27c63c3f45dba9331f13d3ce3a2e77192982b5dd4258a5105baed6923b2e66cd673decda6701578018cbbab6bbcc3eec0e8b0cf43220b0de3f4862ac5cdff67c2b6a0715fc81a586aadfd9b50599bb095a0351c421c43eac82ff305239fb4235eb089a22cae26a82f6d40365e5c02065bc524c4e40a4b572a3722104dd511042f2109e999fea80db0a02daff876644f9f1760772fd3de435316dcb89108091304f63a45459840fc55d695cd209fc56a9f98945eb8debeeeb5fbb6bc0841cb6aa0017d10e947c400ea0ef48c80aadc2f89250600b96755de0fc364c3370bc6741450fd933850e6ecb317b4bab4b780d235187dcb4c89041b9b96faa2d78339b6fb467f544403fbaeb801f5976769c1d95ce9f82f531a8cad0aacb0f86b74d773afd18285d3b5b337cfb5dad58c58f9f47c02249a471c428f3233a29b96023da3b66b34ff13c71136fe4bcd12c99227fd7d3ac6f9889cf85e04917a0efe000bdf5f460b5315fa930a538eebc438fbbb3a7c42ee136ab78255d60082e68c97564006fa7dd8edb3467091b3ed5ce0acf3bfaea8e7e5b520531a6d9841ce954c017d350d8ef99ea74e12af4242759e38db4eecd38a44b0458b8be6d834ee0584f6d853629cb19128b112cbb07c00ba3f66c5918e3352626fcded5478a2fa0c787c9d1fb2e08c87ad2c5d9102a2244f99865c7cc8412b9303638fe16f0977d6ceeb9acc294faa75cc18bf31d78becd677c57a7c6374703b7b9fbd75d74ba83fc2ea1b28286c9ae4c296836e89842f4192ebc391c9c26ea7bca03741c710956f5bad3630b7695f9d5e04e2d4c2999af622e05c79f6a5a8b204b6c4e93fb4f88d8aaa9b07280db9f7b9462e1502677b7504935f01ad003371e9e9bd27399150aba9660d68e8ef400ecfbf72d3bb91bdecc1844bb8e9faa176c01a9eb817d42a615c959dced413dd28512e40a7cd072daab2adcee8bd7390b61cc8b5945e7201fce487c81b7df2f247210e3af78434cb5a28110abe0a7bf94b919e5e129286e74a8fdd224aa53722f65bf95e565638ded7a732a9042f74b38ef5fb376f81d9de9e239d0bc883112b447cb71cb11c74e1530ffc1b945aa7d3902ac84947f4c6163e492b7d12c7ad38fe1037097cd07c9f02f3766927c9993d9189091136f17c860108fe5fa8f781edbe0bbf008ae1c954b0058305e0d3cd0fa1ff61b0ced78f314f9ac66923efa579e5e89890f8a267fa3fcd72e59818c0ab181b495da3a17b4ae5bbe4824572998cae423646650106881c8c9c824c5beb5b617c6e4049d38cc5dc5acf2c31151b2c47b65c2a8d8cb43457ec140b9079c795533134985d418752af9c0f1ca405b1f6597deb6028d4186343f1911ca8743825775ccd445af943154d1678574d4d2e404a417ee29c47b76d1d9916326fbacb898042633e165a3e81e337cda34f64226b8d0e6a264f6940ad142a2b79cb50a5978d5b0e233b581a91e5e4e67d810adb98c636d648c34874b924af0bdd5452c7a54c24c3ac3586a8d7dc2d19b2fff3de2a641df5c168a2faaf4f6a91165049b17d56061dd184dbdc98c5701aa2c912289b6aa7ed92bc3bf0822be20034078a4a18bd297c2ae2e003e65a07f637cc8633222faaf83cdaab087243fcccb7cb17b23b29a94722b03a7b245d0377757053256b562ff43d8955e6615f229f347f378083f9b41a3d439b7e7c935b10b46654cb1af15192286a201fd84936415ae9dc4e29ce55c77b08190b666f8b1d11ddcc6ad54499be68c48cc349800465d6c820a50736f834af2894bb77d70fe4881eee13d0922dafb55951028515dda9edc25de9c1d78830e76e8fa7781b03dc7bcbf1de5f5f0a382e1aa864245d2ad898750e90b35a49ea10748cd32a32f8040d7acf749f3cb92b23f1f5d725286a545549a67fd87ba07b4bc0b2af37ca57ed27e0c32830684911d39c90bf6a9fabfa7740d1585296098143f927b4189daffa354c55f500d8c0b04ee4058d963451eba57ea22a6ef3976a55be169333a4012e65e487f9682a70aaecf14aa5fe2b4439aabc30ddee577d9f5121d507ed423de2b3f872bd215b1e3f562e54a93833370fd4e6406bbf0c5d378d666ced966f57988e9455bce157d430c77ef30014734366a5cf1694c476d096d62060860e7574b8e3d355ce85a3f21fb8607e1fe097bbd8a7fa05a4e847ad0cdba43e805788213f94a8873379cf7e14e4f2839b59514454d4c37b0af6b4180862065d3a5cb1f2a6141b26ef496e2689d2f9058a848244128f09644cfb10c90c860f877a0ce018676612467281bb66ceeaa5323a4d34f09e91f156bc2afbfb32ee0bc5d6180a44910dae8abcafc707f02d5d9a8bd9f4bfb1409ce1265317ba0ced83f02fa47a39b1d634430f07988e3aaabb620dd46a85c81091cb8a3ba2f7cc54fd6f25a1d018cbc1bacd482174abe3299718615323b65ee54260c024dcdd006414bf8d8bc4a19420a8ffbbc035e16e3530c33dcbfa84d6dc3bfc9ecf8faa621fb010b8ed52d7754b524da3595a59c797d6780c85139eaef31aa35047ae383204e952f3d38aac87c259924de9a76f4a2915f53f85f70d239f7eaedbe41300adce85d452a05ab4b4fd6f9168e2001831bc6a9e49710c2f5cced6214a1c37393fb588edd980ca5f7c481fd6c50cb0824259b71604956d48c7d45681dd2d6d06f2b5346576fdb710b1c6c8ae2d29943f18e1301dcaeaba5140b82fb93d987bec8d31baee6134e8ab8785ce2686d6b3637443dbf9ac24104dfefa5d7aab0b13afa460cdbffebc0dc2f0dc9502f4c3f177f1a77552cf2286fb701f8c4dd379d7a925c114d850e8deea4ef93d9b9d92a81deb7bd1e7578ac22c770f8ddd40116a621b7723e4342a0c12a8a20ea9c9e2da579cd5531354419ac5c3f1c40c9ddb65799357bb60d138d55f5feccef2ae9b8768bd582db4746efb7b65fe8fa5e34f93f15384f32abb4338cefe82e6029009e08b82d3defdc4d28a67f8b11650f80b075b5c11cfe5b3f10145e7a1300d6e7117735f250013f84ed4202a2cde40724ccdc289dbcd65ffdd74ecf7547f7d6565b7cc8191deba0f0c935aaae38932063a89308dc3057ab36f6d54f240f0a0edc4e4e53073ef2bb3995daa20dd4ebc25a122955ba63b53d45808550bfba052158f1d9904b6e606330e91450706fbc5fa1fef6426268e2918cecafb46d8f6da499d54d5be9afe306bbb0b8ab3bc92265001826b6421c9c4d9d37a92434ffdafa70ac463f29a3d2dc146ae88bf84f30442d68075844571a28151b625510c743c71405900a2ec33a335d7b8e70758abe05080959f03c54242c016fa3d590a153f5408d8bd4e5f36c7c8cb7f4abca6168a4e7d510c1c17a7715e24cf0c8f7e521c981224eeb6504bd0b39213f676f090501c88113b605b3650ee10fa9eee810281e240efb6b4bfc71e6540b0b9d47ebd6cd2144f7110f71a0574b306422f10595d8fad4c0d1eb60c25ae0e216c4de916d92d6174b7bb47c792b3b516fb6f5c29fd159c5bb6117a2dd5cbf3ad68ffc7135b0064726cbdce4842e9152f9919ab7ae51c734f5c626f1cef5f29ec9d7fc6c05640344c67768b2caa214d201be8b7986d6634800d2665a8a26e031b36c0e94526f8ed2a0b2672571ef14c10d86d2020c44d2a5b1f9332deabc1bde39f1a8d1ff6a1943253a03220453575a3c32956bec26c13e3e75b0db01396fcf5d33c5cc9ec1ab55a39c8ae136910039f4122e2f7ada64b81c7ae820bf94cbf4217ebd3fd6f660771ba5b6d2fdb891516b7348ca35a510723892936dcca0fff87999bce2c94087e672d3791367358bd8192fc36b449b2d4f8d640af7d9754afe40e9aafe0571665e5ee78d56e6c44ce9ab54c10b718adddae310c5fcc17aa178d2d94afd7b414b439f2c659305428c17d806357515656e7ea584214f785844b7c466b527a5c99615855b1cf872a5061ac0515e1b1accdfcff4c5a850c250d6f18fb06c6aa7afd1eb63d3d35c76744b73825acf0c39d82b9a22fabaa46dda1392b0ed60b3149806ce792f5e0b7bf69ca27214524d266a7b2739be36039746a6573b3c102e6b58395aab29d0119c62c5310728e05a60be81ebde3c2ae4be17b128dcf39488111f4619f40f3fd6a36ccee88c93ea2bbc3ae4b08b63280251a89ba98f74720b1cf03da560521a148ae1a9791ee8f279c8b294c12e05b84dfaab6c7a4ca1ec3f4036365955285269718ca87671a04aa512a210803fba6b14661877eb9233501ec39f2f4d8cc26aeba398c0893d31d90decead177bf5a3394098b07fb206ce62cb085d551ff85e39c4739e6158ee17ef819fa0a439f848a644c38e6ee813f50dcbb0e2b7826f533d1b8c778140529b21a3ebc61d0c9e06c369729c1629dd3a8f45a6369221127b7d02be90ea0c43d9b9b20c28e8f18f00a392b221e825551549c6f8ca4fa9e902bb63e3b5162bc8330c9805e134b491c5be108b466237cc082a7a8b56da9df4b46027104b51c07d74fb38708f7b13461c7adf4edbcc69838984f308c04321c2cb0018e0687500391bb44d83c2c4328d9a0563c6bddb9307983407e46a9f885e61d166346ef1f416e90b2d7dd8369911c1c646ce5c84a2897fb2e84167802173eaebefe291c1145c35449bdfc7cd96836a915458addee29fd0d34e2d9e132c17301824a280abd0eee90b4b6fdf2b8111a9c324d8c95d6e2a866dd796f9daa2075fb32f4fb9b02ccaab183ae6777c68861faa8c1266d8a9a09f3a411198262e33c1af30091d0a73278279ecad31266a382e2f2ee3ed3041af317808a9fbc249bfcf144be6c71cc084e904955a58d4abb0eee3ab923f16494edd856bb26ff2c6752aea586c7cdfc04a111e78f40a9423039a90a682592090424e07fad2ac3f313bf0cefeaff6ce9c34dbe744ee5e2e9dc2ff989a4c3c27a8e124fee9e038409605adabc2712c04148012e60406b57e7af909a70eafbab0ae7c294e5048912b9b40f5abfd16d2f6eeb6a5dc3225295315089c08a70762107591182bc46861b11a077756dfc0f2d2378ca1c4652c2ec3c27c11fb75e2843df4e5e3d83142e481f4c6c7baf23f97e9b9c69db81377e2cf0ca92324e3b26f1ca54be92480b159c1193b98315232e30c2f8cecd0755555b516c9c0c41a2762509489e12595c07060c46852b3306070bffabd24db487bb71bd95057dd1d8694db4a5eddffdddd514d3d5d868561834bee322c8c18c040238cedabe26d8b1cf11f010911c21fed082e7c1f1b8d3c113e33845128420805cd6446a5cc1e82d13118693064599665990bb6335496f16589ec4b0b603843858c288db1c3982f9c4461f3ea32c060f3608071eb65181858dcef5d920c162b8d3bcbe54243a9eb054410f1450c982368b620438406e6881fa494528209421be308181e4c603c216563169826364829a794609268ee4e012762d228b5717283a2315fcae8beb0b1e1cc972d4e5fc638f32c24988081a1a463f0a28a121a222f70f8f2e5e562bed0e0fa971a3c39a3ba0c034388bb5d8681c103d2c6accfd9d42f1ac5ffa25152f76461a05206917a27b32f64435cb2a52424b0c8052324aeee99efffed903f3df872ef7b2743929e5b1d15fce54bfb027d7ff16b83dcec0184bb02f095bdfca022d9fb4f5b247b9741472ac032464031f4a2ef1f54c416c9fe8522d30e7597314e865efe2e3f32a08796a2d117af5cf8463a2a20e9a8e09fbd7f96027c71efd4de89ef9e752914e3ec6173754f7cf16f28a30b517f7a167e4caf7dbce1ee2788fac414badf7eb32fdc7cf7fc9adfdb2bf56d7bf80d4d85b9f03de9c29f4a5de33de73d356fbea3bf75bf759bd589afc521a4de817fc345272e5df8a788244e894511ca852f5990df6df46ffec6be907afafcea6e1ee771ec0bf36f9e5fdb47db23aa1e27f5aae7ee673ece5604915cf81d940b5fe5e9642ff452fd263d16e2ffa05efb7e167e4c7ffafe212a046dcf3dea5508eabebee937d8fda49e3eec7ee6df3c1022fa37dcd3bfb13afe39462ef40efc9437a4e370ca855f03625179f0713c9d0c6691d55bf50e0b2dc03b64080b29a4f04358f8d151c1f4a847d9175ef4e3b3f0a3a302ea85ee51cfaf9b8fb6877cffd4cfdf52cfdd4ff7f3e1bdd9a1135fe8457ff32e057e11991ea5c2f6a68fdd4ff7a8f79f9f6a5156a7ff84e413398f7adc3b264fa72d102d5ca8a774a3d02bcc855fa40ac948add83866207c819264c595c1da46a44be94bd52fc3bca8925929a5172ab8524afb0961e9c0bd11e0051077f52c2fa4c8000138643a00010c1723678030c332e332e332c362fe1e9da424498a998d63120c48ba408368003998828b26200870015b368e3c91274ee63133e69149e6219b7974641e11320fc839b2e70c5aa0ecfbb32cdbe87c38679649e9de1db38792d2cfdea7a9173f3e77d30e9917287e7b5f7f0b423732dce2034b18ad20096646933362782943bda42192524a19420f5ec6c8e00b242b8e08c34b17e9e5cb922c1c015e90322f591c8959fcb3ba88a520eb52579d85865857ecddc5510d5bbaa87224eb228ac3bcc0b8b8a28b973362d8e2858d912d5d18b97e19e6a50d0c1366cbc6ab8d2390fc6cd5da67defc0ffa989739c74b69ebf70e5cb560652806b2961fe6e10146faf88ad4a3de549fff84c83353529bdffdd679274b354dd3ec273ffb80dcccfbb4d7fe03a2d9cf75b5cf7a9ceca7fdfca815e2bada4f5b3794c7264bb7c845fd5ecb78476c41576ce9903b6c4fd49dafdd63faf82b1ccc231b41eb02f9cbf9d2d3fee7f64bf9b515d2bafdbe725ba9ea8697fad51b61a47545251bc78db98523b6bed68daad8d2c99e61629cb9fe3a99f5010bf3c595ef3382d18dbf42e4e19e86c53f21f230ac4bd1fd5c5d6e7c7db5c617910f65b91f8721eaa60c0d0d0dbd8e18d685cbfdf8cc8d9f79275031c53b410a23ef0429aec45644a223f23098fbe57e21dc13a8a0125b7cd9b2aa4c5b7b27c61bb115a770125bff55fa1116bd600b172e4a64a194c5128a59718c363f7a3407d5f47cf9a7699a36d9f5d01c6eddfd980fed07341f76fed303ca388d5e76cfd5657e62ab4b84f099999919323f33335316a26547182b308a512b87e9dfe8bb47edc7613829e9caf845fd78c9858ef41d3a74e8d0a12ff9922ff9d2d7826e3f78e5c67799e4021656b04072a5f6917a23e030575a20b734c981d898f5412cd9cfeda594524a29e5b6bd7cd90387a8e572e7efe81e9c8fffc33c6e521f7b3ad0f14d118cfac121fa5276f2b9cd6f3c209c433e8ee78a3b7284b882fc5455a296be4f3fca3b79dfdfed3bef5bdded39efab77b32cf8fde010c33e96825a9a59eb104b2afa19168b8b3b4b8bae020b2cb0c0e26366768662e69c33049f42e60898cbf43ee6c25c70b874308fed59370775931201c9bf6aa8709effbb27c7b2e52de555a9f138aa6fd5556ccd8f7f83e3e5781f77e69bbc566cdd787c53ffdd5323f5f16b7834eecc4f7935b6e657cf155bf3519e8ed89a7ff24688adf99d57426ccdf99b078473ec883bd344234e94426ccc929dfd5c5cecd73dec84b8ee085c17887bd37fae0b3fce7eaecb3d4b957a7ed5c5f99b9417426cc557793ae20eac37def70e7c14ebc2a8eabaafdd73533ffe8dfdb89fdfdfee4fde576f6739f622900b349fc26a741ea6fd5a77b2f7d5d3f3d328ead393d7ea9df8b47b4eddc7f9dcfcf9db8d3bffe471ef4c1a5bf37d9af33c9566a72b0eb131ab094e2221b3900045546ee2c20845a5df81eee186455d5a57bc142b6e22842b75c41df9f3b95b72922bb6648dad0f3ac9acaa8ae69ae5b8039bb18f360863ec7697de47e1cfae4764a272a441659b4551f9e5896917b9dedc24b58ca391e7eb97b25fa2d00f24d94666669ea7cf85eb973e5fbe2634eebd4d9879c039f8a507f907178e105b55eaf71fbfb6778497155bd1abd4f831ae1c8bcbd503a52e16cba5b8b39c4a77dbf0e476370f3797633618b95f7d266ebae8c24b182bc65822e9256b58d2035d128492299734312d49a29d41464912877339b64489c883d0b2aa414a29a5122074942c51839221db85e5840d2c35a2e4b87b0d486e8c2459d3c5922c19f128b125b0ebc1e5d8922d9c18b1246162349ce154dc87254a2cc96283d89223624b5ae03c7814d70eac1d76702663668848ae40a2041457b2023546e2104dc468488a2131e34d6092180d4a33780daa005c8e21a9e1d2cb312446ee57df091db1d5905d3754c6d1dc85feec510877e5432faafc1f779d99991976195fe2364008c970f8524a292d941a1b66f23f0823accef2249ec491701d23ece073e7123eecbc90427793dd04609b0b2d074188ef9d13d5081db04d8e4a2eb688aadf8f93cc83becc7eb60928f87ef805ca5ed2df340e763ffcd297edb04f52da217da9fd917d7ff505cc23d9df799c393a203247ca1ce319f21de5bf49ffe1ed9d09dd8fd8d232f3606f1873d818c6d09fcdf0c5cdde6be4c93e8f9d09fdc33ffb111fc82d3bfc60438f426e11930189477f2d617777b7f71187dd6ad444e82cfd066666666666666676c8cc9176b7c69c11b165936a9491e014a508eba24e722c2eb34927d214a508eba22499cd0c698a528475111a349291a62845181a479aa2e4ed682a7c8e3132121a1e02db60e11cfc94892d9b54a32e4e824530a53805c96536e9a4b308c294e21497d9cc262c8229652f33580473e92e4e8245deae8f93e2c7cfd5624046fa1ee21c14c9356575a385630cec7e2b19b0dc8fae748064cf37481c7a694f7f528fe8c88e57f648e84bd32cfdac57588018976d151dff2086bd4c90bd09a6f37847cbfcfe3a6c81cc779b02bfa6f5288d88115d31026b3195633214c58860311990c48c68d1989967672ea567cdcc4c698f3f9daddee1eed6e0e59986e6b15b55d55428bdb90653b5db602abd104c9d1782a9d98560aabc0da6fa85606a5fa8a6c1d478e199da602a0453f9c2ee66e61740bc0c5dc2acaa7076b894dd4b9d06323377a4dcdcabeeee341542f66e4d3399ee10d8a604b75ad93802d9194ba8c42d861063e906234d9861e5c92ba361cc0f59e7e00be69e1e7fe7d7c99e8990d0177ded277dcd3bb2e335a54e6681cce71ba4be6896d921a8def14420a327b1351b88ea35951f46c7c2395cb0f1c3e6a2765b206653e3336c4f0e5125ae5c89c120e500172629c560d0a1c916de32dc8681c95dcd180c4aeef72e2e9d4645835935a1ffd7dd7d0673dd3b90fc5f77b7730e57357fdbaf5b751be702f5d6dd4b1e7d72b4ae2ce4876da03be55a0dd558b3c15580e71dd8530f20bddd5b07955e8ec14064a6f6e5180c30b49e955d8e0dadb9dfbb620bb8a7328ece85495fa2b4b719557539363405c34007b8456cc807dfa256558dcbb1a124f7abef63623118c56050e28b17328c911c7091e59003a53065a4e164062a7ed0021231216d90430ed264c96231c88028076d96ee0797616dbcd0a0d22e495dc884e992d405c6d8ed2edb5dca2c9bd429ed08a97332cbe6a454cbb849a9a6994c1be71cd7117294d34ca66de3b84e8a939f4e1de1498b89db38aeeb4e2714c79dae9c94885f2b961b3f15afdcf8cd4d4778138d622b3e1b36514944c2260eb1594292a20b172990a4d002af4023284542291742896c96988c129309c117426429be10766c30c66e779979967584198cddee5266d3e7ec08a7cb2c9b9352cde4265347689a54d34ca66de33aefba8eb0336d1cd775a713aa7aad1d61ed4e2854ada9d40d8ee3e074843837382a558d1a39393656be5a7584ab14d738385c7baa8e0478572aae6b6c35b8f6726cb80d1b1da10d7ad2f9a1dd7e786d0d7ad2f9416f3fbd6dbf166ee4125bf14900c0f52c9c838cfad19b8579d4b8f12512e6c1b208843436661ecc0f70b9ba50eaf262012d585ab8b46069e1caaaa8bd050e6abc0c6ba3050c6db8749b2daeac4d1549ce18da4193e9595cd1c689b6a24d12b77b6a66eb13b1a4ebaaaa56495dbbe7bfe600257eeb592d3645f1bba7c23648ae94affad51a2ebdc3d71b8b34966e1a4add130d33d0209399419a96ce6cce9f73ce39e7194b72cd90949a57a9a79a454f96b8bb9b6ccde64472e75cb3e4ce396766b9b2fd2289a4c314279aac408d14a32946d0e092a1e1c506ea3740038ba6ad29926b9e2ca162cb10a533a24471521403353138b90116353a487244120eae3002c240c514ac29a6602dc1d45c11c552185ab89cb4c0a12524b98485961a97614b692c29b95c4f50ea6a1bb86ce052d3449a2d4ca4c1228626d248414313695c90c60a0d583460b19c7067e9c0ccd25df1f4cf00564d976169a6b4d240e91dbe144d14344feef72e16d4bba1567cb32c6b256a9691893bec73e64cdce15bef193637434383925e227e218324584924e17259a1d4c562adc09d25b310638307667a20e308326069626d9c28992183929819be3872ca828b252d2ad690d1a48c18a041451a4c94aa9041490b0d4a324872c40c9d1589440198a8e2654b15675af0c3cbd1788256a144690a1532a861036592b0220d1b2c49b460c344c9891223251a9640c2fdcaf59beb468610c0655819626ef0949158dda86678c0610836a3063b1ca5c9218b1228af5e53c618f432ac8c2ff7abdf040737d4180ed496c102265e860f45b10c1b70f05a5565d0c892e818944933835119336df485195f28a5410207931129a5946664e08c0c718619674e666230d243dc5c8695c1c13d5d869569a24a952a5554506688895c1ac3c6114bd0a4a1010d63a64063258d1d90d1040e195b984c778ec20c152b4062e2023162f0924b6418a1c8386249fb50868832409041e60888a652260565a27897d9a14c9319740a905863460c9728a620238b57a6a67d6032e5871e7ae8a187282edd250a678ca802863136ec808997a7b93e6689a873305d869151811363c28859b3039929469e909142f484cc0e469ee45c86913172e765d818362e970e94baa0b4132762b28c2145331163461231638e8809539b536a3e516a9a465ff33e97cce8cc4cfef4a53702d6bdd973aea5726c49eb1fad49562b2456b12848775e8e45792216254b94a4bbe2784314a3fbad6edb703b1605caedeef662f4f856df52bf15d111fc23ff3a8adffd1e9bc4760873390685cd55c0e51814282e0acaa0c2cf3c787fd2c843a46596eaef55220109f2031d00afd472fdb1e0604eed43e0ddb7bad9f79fbe3ba3b195a962cb646b6c490d524fc8ea6631ce69893804628fbf9cd55b8c506cfddb07ce452da17bb867f65fcb1f429972dabe3b6da8e74fa55229aed6cad55aaba5b1957a2e95f284b0525bada93fc1d3e9943a3d4cc1f789a8f7899b4f8435b39fe26abf1b39aa3d7928ce7ef5b954f53e1db7fe16b9cefb84badf4e5e7fca7efcdca3de27deeaf1457944e23d71efd39dc7b1b5713bba07226993fd5c5a547ecd9660e1b45fad99fd562bcb5a5c8a1a83e24e7c487469fceaba291a5b90720e0e4c856d356c1c514fb7a7af3dfdff6edcff00a07d2c1caed953ffab97a5657a7214aabb4fad6de3bcc979d9d5e4ed3cd8bcec3f98db16b3d7a8e697b26e705e7bcf79f16a9c07afe0aaa7f25656d47e1c547f5336bdd79e3baac5ef366d66b4c1c6ac38ffdbecc7badb7f8f23f2a0e8b3224f2a46dabd94379cad410512793e22f2aa3e47f5f283dcd878c9fd0dcfcdcb2f21f2985efe96e3a9bc4fa272cff7a328705fe3732c8d2dc953c372ef4754be1cf71fe58bc3fd8dc7bd0dee729ff2b8af1ef7288ffbd35f8e7a94b3dff6d956db72f226ba0cf54d902b3cc2f4d06308bf4dde27c4754dbf2141e86ddfde10deacc93399ece7baa69fdf8f7ad8537b52ad4f556fe5791415e5d5ade3788bf164faf93e6d824e047df18f1367a2990c2148076cf263508ab8f3fde7671bc7ae049fcbb685865d8f21f3b5211c7013906e5a1fad7933f840c807eee24acb9c43c2b69a076f773ee0d3f9dc6f363cf9395e7b384477be8e09fdf33df8d963f5f2eb57b5f6f5618702a572670c8a93bb7df7587d7b355e7aa7dfb8f3c19c43fbd8a13051d8beed89db3a12e6e33cf570fec603dafee6abf76d5f1fe5e9ac9e6fce73eaddd359bd8de7cb1d09edc19b3c1d13b6f7e0b7f7c0eaacac0fa18b7a1d136c7cea6d7c0a8811f842c29c804f7ef61f7424f453fa363cd4e778a8afe17dddd357794037cf1776284c1cfb6d4f6f3c20fa295bbd8fa2bc9307d459a1bb591ff3a9d5f1e1d21b02dbb4a674fb7da2469f48763516b4a4db432070fbb7c9c14e024233c0417f7613f09f1ebb21f0faf09fdfdc75e61cdfe9c64f876b861a2fc7a07cdc9c71087d7bf03fef6714dc7e413a3ef8af4f8ccc2df67ed82a9a60d0dddd0dbb0b213b6ea83cd144c80e22d2894818ac0c8085952c56b4b9701834ec1f1a1a222205d0a64d1b28a7704ad77f63318fd4f3fb8c1079e67f37543938d3c9e4c5ffd1f9cfc6473f5a7bdb384dd334ce033231d5348ef3807b9397517d4462d3cd7ef172ef131b767777d79ce9eb6fdb9aedff9a6b3b5fca6ed96c8072bec86d2f763f24197ba651d054f3b31cf84462ce43ef73a59bc12d49558b2ae00a2eba03da2c673e9cf0e1e7bc37612b74cfd7edb9e973f770e4c1f9b6ed7d1e58cd9a7e7ef6a3f31fd8afae6ce4fc90d0c9400774777f1f7cf69f2bddd99ff3a80e8559df03fbd940d9cedab05fbd2b5bd4f0571f5894fc9366bbefa094fd2b1bb61f05bd4c8f29a7dc8df3f87673dddd39ed6464bf4fd7f052aff2268e777a68faea7d3662673b1efe67e33ab34a883c37cf34f53bba6705cd42fbd9b8b0a87ba01194b6e8735d0d6ad502c9e75ef33237f673eda8b0959616976b33a9c3c5713f38f8f235096146ddc3366aad151a5d7f2fa3e372ff09d171eba3fe73ddc9fdd7a5bc15e7804f3b12b807aaf68393f380e1969dea5df842745ced51f673716c755e063a80dbac97c994aec9cb401032eb2eb4826f84e57237fba5cb80cbb127b01b8b3909739f4cb9db855f7437d476ba71b97b6e9e9f5615f426b4f5662e1454e4c7f4452eccb6ffc9be61ddac4fcc5040db9bba2f5ed356ad9b3edfdef424f4fddcd21ffff11fff712940fd45aefb74ff1f4aa193217d81fc3b14bec89107f51f2ca2db7f5a51b6d9cc7ed31289d76d96c1ac33da3e0193fdcc7ed0ad8ee9e94bb7df0fff9fc843ddbf54d109c8bf33ea295b69e6d5a13ffd81dd6d93d7e4f1cdeee6b9dfcd7337b5cf979e7ff46ebef3389497fd4068a2f329a4260be4bf3d9d2aeee21f7cb85920a790c2ee895bf7126e6feaacf63744fa721ec796c97edce5caeda7c8ddddbd08143ac50a83d8f2a1e363000b112e229a103181d20212e82006145ccc20091d62b0a48913242c405d8ee1d0c4f5cb31264ee05f683f3f0395c00e85faad1e7a10872270c0b26a23eefe6cafbc62fb8eff98daee2ebf050984a83f3e34038729f7ab4546b75f5584453e67f64a0b42f795114909087deff44b8f9b6beff4b730a6eef4576f774a4759209144d1d0d08b5f4740fe2db82d81002e84c5232e445df5b3dea56347e4f9be69757f0e7a5e6babbd7eb2314b29a59452caa710ca876c81e4bb7f0b42574a6dce39e79c734ea6f4e79c43e6d52cd0fc6cfedc3408e9fb440ae16681e86bdab72074a9a59e7955b56a1394406c5bf450e8d5d65ed71f3d9d1ff2a3058a2fad4e5b17bab0ebe19ece8ff8f0210a11a81fc8bf877fc34e15d38072039beb830548961baf70a3fa715207da5ff63cec5350b3e7ac1eb35d80e3c6c295331195c59bdd882dcaed506f782cc09bfd06335b05ba0761191bb37a883832a09ba73797524aeb0f5f4e914929a515c2dd1891b01139a7121dad22035a95438d4f99d8200895738c105bfd21c456ff8ed8ba41fd7694c05dab6ac5ced560c1e6035e55edaf81c3a2f44607af56a9209bad55477777e3d8d1ea68371e54048fdd8daa686ca7ce5e8e5949e2320036669a3ae10667628bad1471e19543549746f57bce15792015f8acd8035f3a2e8435c4c8d37101f5a3d7dd5b273ec7ac5cb97c5da8a106268473ca19b7861c4f71072797632b7072755c8e59e1e20ea90c816d8b5919326f0b383693564f1f65cb7f116857d58da69656a2a3f9da536dfa4f6d121dc13833abd3b26374629b95e8c8e5db8da308fedc03a3dbac368cc0c62c8f2d2ab35459e7131dc9ec5954056796bc11b9ebb18aad4e511cb125bf155b3ad4afd5922f694b84ece5e37051f99c7c55579f088b336c3ee08d3a57beb81cbb72c545c0e5d8152a746aef1e07a5a5d2c9fc8d47fdaa08a69fcf6a51b973c6ae2c4958898eb46724e6c95eabcc437a268fe8a875a2151b57a2a3d84f74c4f07915e3cbe8c13b3de6563501059f048a59f6838478853208c11c51ba9f0b07100df8c0b123487ae2cb872b378ecbec8a155bf11b50fb617f8540fef287bfc41179dcfa0c153ec74c763da4f5c14952a09815e5931a4585ffd1937f8d3c6dab6bc110c2673845e50f7a28b850ba8c3540f51439f2fac7070448a2c667f931faf3abaad48fde8f0265b9abd8825e09ea105ca0b8f02bdb18637b6c8830b121963ec6311bc7addb6726bd23082ac78630ba2e042f81455ce900861152186152050b2aa0d8e0743936c40d3dd420cd10479e644963a4c464cc0f323c7183105474a00249bd1c33da6224867feeee325466668fc2e5428352178bc5c69de58f8158c70c3ce9c10a1bae4c09c24a961c60335471819ce189519635555470b7cbb12a501a1a195549e27277a476cfcbb12a4baa3881b033ce609d11132216841a5f7221ce18491313628d106a9a5083060d0721850a0b7460c21a1a9e10c2488c8a127412c4951bcc28c0e55810484140d18519259792cbe51a8352178b25c69d554605676c10834a0c48c4a092840631bacb312a405cd4e5189526b12958623e34e1654c81118589a960e86a97632ab8329f764ffcaddfb431eaa317741484dbb6f8db6b36c8e9db06c18fb6d6de993f9f0046f89b6cffb6451b9f53e36d7c8d0f3a0aa282f0fd83c0777ff89a0db2fab641fd2b0bc4061d05c97968835cbd333fe76dd89cf9d0ceaf6183e6abacc9db1ee59dbef3381b74a45301d36f1fc4f49b0d3ad23e887bd36b3608ea4f360816f5ce7cd4c38796b3412bf4cefcf8db66a30d8243bd337fb345f1a10de2de89366828e82808f7d00675a077e6731ff4d5957a7e7112cef36bde3cbfe07c9f3679fc4279fca2de47e7e378414741b6bfb141f0b53dea53de0bdc9bbe7a2f1c05e12c9cd23bf34dffc21402b400652dc4d23bf3096004675f083a4a815f2f937d413ebf3e88e5be4e1ebf3a8f5f5c7cf84311d783cbb11f90eec691e3a98ae417a7c0afec55802ff962d64409759c43b09c1586cbc3804c2a7ce67ca0925d8ef920855e8ef9e0e4ae78eae5980f45dc556ca954dc3d91d33c550caaf61f77551fb897ea7f23f2401190fc2b8a10bfbfb626e51639ceeaa810bffb14e27756e86ade4737ef83577b395fe89a3ce642659b622c636bc5166c4fb6ec9e340e81408c9db58c2fbd28a394d2e37b73941354f85e21ec87d2ec933c7ffc7f8aa8c77acda3dd8aad222afccfe5ea6f0777d140e4694fc54b5cee5f8e3591729d68b9aecb31273a5c1f887a58baf2a9f65473d8dddd6e3f95db4fb3707624ccef67befe4ad43ba1847a71700e20d588fa71988fb9505aeb6af5df0af3d33dce71f95c492d2e5a5cde700a17ce5ce9ca29fc19fb97aaa4a454f453e444165d08933f59d7c3852bb3222933e945ee45b248baa7a103951c90dc8f48949e8e9b7dbfbb5377ff22b1fb33cb1004ffe835991b63190842fcec63d643987b80cb31295de00b3e7cce05578aad289dfbf491e75f30270ff44a7f0533f86c03223eedc75dea2d82f6df3ddd2fe1778fa655e10fe1ac41f5f9124678d7be1f47f46a5cc96f4b1b5ace3d6700d21cba7f9194a80b91e70bbaf37d898f9588c0db1e77334f155b120ed51588c49e1adfdbbbb18aad88458d485ce667ef9efc2ca34f23fc0d72974d9841977186c8e3d33b9c5742e4690b2184d095a82bc4567ccea77bc7e57a404602b2421aa184cd7e9456cd7eabd57fabe5ba2e38fc2864c7bda1f20413f842175a874e9ea8aa1cd46fb56a4aeb675ba44871fdb31fcc03e68023f8300fc83ce03781268ffbf80df9d96f385e777323f264b02b5fc704fad9ab5ef2edeee633efa3ff657f9ad4a35f43fe473fe321e9ca9f3c20ddede9cd53affe0dd4670fe737954fb78e63759d0fa19bfa1b91c76977f33854f535bc2ffb56fdf62aab73f33a26e07cf738df7d47bf3fe771bcd4df783e846ecae6540f0865af0ece66d973cca305b865f6a394c24be9a42b5c3a69072ea573da2ffbfe4deb4af0819d8fecfdfd9d7340d9e307e72802855471b639c9f767aa924e4deef6747aee9db539eab93ba1e449ca93e41cf0396af22bbb1edac3ce07fdd94f85b06e6730f3bc6357025fb7425826dcc86286177d821d467d14e554b7d97ef3e5a33c02145151af7d7dee50b504be284ba44d70d489729388940240c1e6428a12fefdeef9c6713fbdeb411f763edc3f227ea394ceb0a1a1a1eb345aa10dc62628a594d2497f52da9a169d6ea8948c97753d2b95aa1908000000f315000020100a88442291581c282a3f14800b819a44684294cc22a124466110434110031886100490210619800c5310950db8b9487decbb16b870bb779ab33b89eecd4a8736ee4e54b10a74597fd539dd3c0962ae8d94a0b1330dfefa2323acc8938b83c455d7f86edb66ff51907e74422133d08a4ad7300e99c72e07814335cfe86ca3a006d9734a71854a6b826f0c5db1304fc6b2d620fac81763cc28f36e067bc69415b3ad4ab3028bed93f7b979d2e5a812716d5d392472d9586bf546d884cc0c732e5928c989cf89625f56a243df0d1316b46f48df0618d0857824e96e94b9594f0c4307d0b54e336cc0e38ea1326160a069f2e3296ec59eb1d41affcf7112dbbc941e1f4b63a980115710f101ae39d11874ea4d80c0f82028c09dcbc7743a6ed5e8a38d256a3c1651ee822c30b056b596b27f5947acdd0cfb364e6c296a2b16924099aeec05bc53c675c1a74e8681c32e548f3c0236092f8ef9006a017a6c2621c001554b7534b16ffde79d7ba54e31097bee1cd9c32047e3edf741789181dd0fd16bf769ad2be274e143432ea3407aaec67c858d1d85993126b5c3aa42bb3173eb70935716d341e26363e602df3ec3f27d4a9b27da55a3364e4398825148020ebf0468f31d5d19a0c87c201c35ee498df889ca976b531921bae8b6c80f43728d8821cf433593f60ce394331e811f74346342a82c0ea2c6d7fa66e06a350536fa15b0e3c4cf1848538b03fba583abf762dbbf5f45c9f08740b0b0f87f844687a81b796da2bb314271576bfc5d8216e8704f2ca98a7dc53c7112d5a7b5d6b6cd57452d7a79bdb5ce7f2305542be036ad9a2a803bc091874075fe3dd87b84b9d10eb7329a0d4ab3e91a3171cf0b7afd53b34136314abb0731c7a88ba0388d2127477d9cfa8523e0d5312a8b2e8cd47f1608863599087f0571239a352f61bfece7320464a6c3c4a8aa792e1bce66e4361497d114c4779c27aaa826144e6988815d79d8390db00de99a02d6fcffce31b6d51be49e6a8bc1439ca2a6e70512c805b9b3193f5fed83387c4a2845fcb6289590de2562bb7a341a0ac7e10499c1e8886687076c7998f2c7fec71aab4479a7c674c087513d4009e4047cc0d8939218a39390e05018255475db8b34a728e05b490f0c76f4fa9e5074619f7efc3d7ed6c9421948c1cc795f1808677a882ba372c3741fab95bd364dd0002fc6171d719d664c2c7daa63a3ee56e445f36969bd6400643c365ff4bb8f42e4b3c91a35deb352ef7230ba2de2402ca190508478dd43515a067a616c03b4f2fb7d860796ef4e0f9fce28626e50f5717c3a3680da6ee64db7114deecc45f9cdeb08a7ab284565c0fdc1808b46ee8a2440d39f4d6bb67639fe41187d809afbf3f8b043ab4cc7c705f0bb34f27f301837570d1fe8adefc3c25e124a1c0baf9d95480ba510bfbed4fac13a93205b4b031226033be1d3475919e59c75fe09bc6d7aa3fec84fcde876b61543d6d61e3b5aaca99690d15a292f149d3609f94f56a046e42cc88d6227650e63c7e18433253ac1ec7667b8dc138dd4d8b2c84af624f26a7279dd3badb908c0b3aafd8d541211c0b54513d810e5dc8d0502a8ec2479924d5f5a1edcef96e161a83e8fb1947ec8883d49fe8103aff1b8bec7cc613775a7789043995124ffdad24b5646e5967bd841da040ac1132d0cb55e01c4d3c261346848786eb2daa08e77b14ef13836bd086d6ea5c22f1104d80bb463c7b48e8d8dce2382befe04bc0cfd980fbf44cbdfcf5e394aa4afb93a338855b0112368970740c275a3279508546f2a34b2b7dc24b76f7e65c7a35969a574c913d5ad60306ed916aed0f559b92232ad5b1ff2add0a210299a5642e93f518218e5ca1baf7cefe9330dcd7486f6e355988d5c4dfceae45db0af3d2d4c587d664680377e9bdd29230d1fc4db7d2180e062baee918b725d68933710f6874e5cfc41c515e897fe1b688fde9a96de822d5d7cede8b38b54a177b9cb040efdcec84bdf56a4582cd55295bccc1807b1500ebddc7c28b8da64c5bc8fe78af41ae0f1bbf48208edda6873cdcb5d77180bd3d038d47edd4703f5096dd03e5b9222fc90c6c28282974ba37fd8d973220824759d07750e240b91518543256221d55c328195f8b5a01083c69a90068f89ede62f0bc40601ff289d58f04445a6a34fb0a9ec00a2a647cc5e9ed3ebe39ccf64fa04a31e4e72e5cfc495ec2d35a194874765498a3400272cd1ec68591f90fe8c7176c4eb6961b01c5309602261ce577b12a4b0d32f514ff0acc1584fea77d1b11d3246faaf0169be8adb51eec3ff63e8312a24270a5d9a7593940605d4df10ed39a900265c1afe1f9e4b2dbaeb4401ec90b406201ca8f4558ee5e2522b2e89d0a35f1537ea907e6616b5cbc97ed074083794b280fbadc5d714fa10f39913684f6b6927cb1a6265924b5368f31b18f090911857a281306310447addf598e307c6036a3db7f42e2ed14e6fa85dcc021aea87c864d22b34aef201bffab1e24d36e457d92363e27959b628f0f0d797e33807c9082b4b50971c27b3e1522bb5ba9f8e787187e138d06b2539e5ea0d961ad06dac6325fbb99a238fba34ae8012be6b85d4f52615e9836f31a71f5b20eac2bb463267e6b51d227ef3746a84b6e7b4b35d125f40eccd4d5368ecce02026f0c64680f4d7fed8656b304943dc954e89393fd4be6feb13713f8d7998671f58f9beb62079e440f0254ca6c64ee414cf58d1eb072a2fecd70d0a6ade34b5ac4c5b41b67fcaf6fc09edf332bc71510efeb1af6136700c503a602c29ae2ea59a6dd709c6c06a3ed10a50d7b9de4cef4d66fb94e9dd6b5ef22740997b2d1b9c45024f392af3e89ffda40d0609606b6e7616edd4d614960b078fe5a23900549c6f060917d6e6e46d59a2bb9b33b2abb73c0930b2ee773d2208aa2e2362a046dd49093cf92944bee1c173c2adc0bec65b925a8d5533714cfe058c07b24b6f98a312736ea4d0a42ffb011c69ff4ce544a00f7446d48d49c7bc47c99f7b76d47a8f1652d263d29954b249c6713f7e3a304e8cdf03398cf55a77e5e1e6f15ca0967a5dc8d425665c0687f1284737aed8c1690cd41086267a71e2aa31c2d8042d0c2fc5948e18c99641d3e23fd7f4462ef690f89db443499ccd987304da9e70d87a373b5c40a131eff79891b11dd3de640e6c22ada37a7653c2bb75470d2a5e2e2caa2e4884e87972f283f8ed3f920f0274dc8b1efc3362a9b1b45d0fd03293d787508e785e9ba01e42cc26d9a6b9ab08b98feb471961be1efae4a4df4e973d91eb1f294098e48a4f0ce6d3a6fb0cf64583571ee60d6e69caf361de4f8f0e82a02386aa11ef6831a1d012ca84093dceca2fc40011a23e8c5e83dd60004e50e0302c709a87fcab13e4259c8ea84b1fecaa1e583e9dbaaac2d04ef6edb744cedd7fee52d7fafd3296ab6dc2dc591372dce6b29c939440b1183c6e0731b868fb7e7573c0b44b68d95325e38314d4d793c888fd799dab845e4c6632a5ce4b9aff7a715f60e5ff14f074a84fe71ddb953fe7c25c29c2e581074313cc3d31932876ddb4610aa8696206d56dd7e746ea00b45c788e38b96111e94d7d87a1fc21d4795624fd6840bcbb1213682968b06a4ac6e861f6c1158eef1c4e7d07b774a7fccb78ef705830c51b516750c2fdaf09685b7bba85303d3ff87f144a1182ec91a31d4b94ed7a8541a2b08fed867e22c70392c45e0e62799905b1af6ea7a2f8efd0205bd1b14d1898b6e28f2104a27759f642f9773c8343af13c66e2228857e79eddf3c62ee595c2d1bca7f36b5b5753903a597c8fd7b57df548db65ca90b965541996619ab58bb1bb3ad07834560a358c30a0617b3685261ad0166c2002aab63fe35b22d825a8b41eccc3116552507a7f1f17b5d4d9d16f9071041e746c94ff5b839310279c5f46159702d971c14e2df44420461e0a510adeb8a22212ea2667045358899340b78610a7ba14e5412ec69be891c8f5cdb21363b86a31a879dca993350d88a9531d1b266e8780646ae2669689341f97edd51b5118cd491979b5070eb2cab717f6490f36fb9901d34c1cd4f533a9436a4c320c58776b97b4d564f57057e59817a9ef1d262b4189816b94435dfa6bb2eb5d22438d0f717d699c013243ad78eba644d3f43910e116ebfb823d1d662ac444adb5182c40ff484fe3517597a783ffe08fa15d69710d149a93b40b7fe07c9a5cd639bef74c44d72fc88361e378ee0c656559918d69a9bfb51a7384823ba7bc63f9ea8ec1cef9c7f2d73ac70a683fa949536eb29e70e5ad58a9a97b1fd85e72b6c51c0eff1de7893d5ff6fffe39c484800e1d093f186495e34a65a5da04eedc4cb02fb768da16d0394cd0acc8b8d8f9173c24fd5c0d47c0838c04a42dc4b1fe328c4e14dc310fb4403a8697815b5508847f41421387bc8af3f47716fc5bd01be1a6352f93807b989261d63fe7ee0b84c71401b0201b5b9da8fe78f353013c7d6edf3742183a04e1a43fe5fb9f8fde412fee769b58b2723a59b1955ffcceca60143fb2e53d8308b587ab5cef6be365cae962f9d0b65178845ec43dd1eb40fd02f324b739d23a57d066aa2c8735695c768643061e99f143bc1e4b654419ab5ac74817143beec154700e8002c166b5375ca98ef663fb5f76a912cac0f5482bd1411091054a651928cff3a8641622a6af8635de343c35c1a8cceb78a3fee0922a1cd02b2561fa14ff7fad17392a8545a06eda029c0096b1028678b54cb318d9019a85784f0d5f2e658eca799dd549802c2e46a6d41f405dafb8be0551a4cf2e3d82ee2f367f454ebbb579a3ffbc66e80e7f3a133a7f5cb5d5caaf1798c0086db9765d0caf8559d7929cef8111cec84a186d8891eb2a2e8f9c129c4d38414fb5a4e85e1b3ed8893ed3a1d3c258749cb5bbe3db2888c06835d1a64484292c6e1617259f3aec67f794aac4490ba86f5a29d83633e030b1b21a6d2d5b4331ac7c2cd8c68a26c25fcf45777907ce75afed7414955eb50ea640c39f20033b0518d5efca057d259d9395154536c2b0f6f097756e0d4a37cdc647620e06391e597dc347de0449486b9c8cfb29ef231fd306c85b850a03086c67e6b0355989d161192651c9a9b92fc7b6ad534274c6cf743a80842cb26049b02a4ff37b5751edcc4279b18544a86cadb0d8b3fe5a5a65ac822b31a020001f0ae5618942296673da4a9411b8099590c4c812729762c4655e04b5d2886fc27b348b53f9d2ca39da2284d6c69c7e98a21af99a74e2eee6db01fad56f91f11933d7c2bc8753785b29a654123101be02d03e0f3206e3369d63ed00ecfd299e87a821b2d56b3395e6714f5364cba0b4723ae672cbd89d4a73869127575ad5a4b9e0e4f4a704bf99c404d1700c0803ac83ced0127b4aae3e56b7099a2375580e6fde3a9a6c781c033c7d309a0dad60d51e480096ab9d9038c5a04d3f1940f82356dfed575ef67186f2c7df97911e2922367658f1e86f7bd9f0a63285e4a67320cb0a43660647c9b8b1391eaf1c8f13b8ac490258dd9cecbe900baa477648680ac5ae59ced62e56cba955bd4752de1babfe75a4c2174922cd028aeb4fc36c8b44e95e410e6f192cdc0fb130bca33df78213df77fd00f2ea8699de55cb9f8d0a595585073e2600530404e2f7084851421a7d0748488a438a9e6b72da854a7282ba6a00745584b44923d0b4ac52fba92109d980a1911516b3edaf98d61580b4870c914a7beaf955999fbdd7c801b7bafeb0b3821c00623f7d2438ec0173e80f11fb535f50ab3ea49bf3521fdedd4338b322e6c0d5ca34f1834b7134b1fa43d2c52af31fd8878ff5fd50e14a10a314798be0d3153629d44d23224ced63a61044a2aec12350cf5221ea100e42b4a124cadd584f416c9a9f2b0d8a85c20c62bfb42005db7cf47d3dc2be9d6ee0d164b19d32124eb436030fb091f97a78b84a871efabc849eb455884bb70797262418ac2de5bddfad7bca2107e129f7ec268d8a9ec3d2c3d35a229558a3664590a6c2ca801b8064983c3146ca2398a49adc1429b7c32452da5e499ec1ce2e0a90740e5585c67a4aec6cb2344dcb8cb438fb8557b3a82550934e860ae36a32bf77bc9b7e5079eade869abe2af8f2dde1730d772be56d5fc6d2023c01476a9a1e3d9302dbc177723e2c777784709427e10665357aaf45dc339a5666fe89d12814298694857be9761b3cbb5e8c3be3a07309f086eb7e98bac93b4d5fbc158f082bac2d6467e934d90b35bd5901f8bced8e2fe727a290cf828470d60fd0e24824d76caefecad41cafddca4681fd53878a9d27a40a6f942ec94f635149ca394af4dfa1c2c591533aceefb97876573d11fbb6c921aec099b8269c530e0bc825a33f7ef40015cd423ce40dc2a053a9346365653c48868d939346d7f524b5c26f27d14e8e952b06c6062193255555d057c7eecd2d4f8a77acffce9088e43dec79fa84169eb2bbb4b234d39aef8340279a62544927f5ff96a38a3d127f40e38325965208328fcf0796cb72981ff1f102068bb170af5b0a0bad31281876559be5b84ab8a68b59cb6c04955729a9d4183e54cd1d7622d4aa7b6277a60de2e41baad3665a339798c59eac62e9d41f2531426c1a17c6f77e247408cd1f114eeef94733732a4c6907eb634f7982cab9a8001826550a84c02336dcc746d713c8a27e3ebf2183e38e732d194b5cc3c4f9c6e49609c931ac405cf550f3fb73081b5b38d2646448163da41e384fdb592ab434195ccba2becd05cc02392acfc361aff70cb22f8a161c4b33536a5a674f00f9c1d36f331b3c7c51386ae9363fc2f2331c2ceb3ee1ee9ce5cd7ae6949050555bb61bd1ed61374b74927a7287d01104bf872c00bf3cbd892ec7010133f5b22eba18fb5dc7addc06ce2971eb40539ee47952e672aba117abbd4535e38cbaa58a280a2d7d75525b00658c1049480955afc4a053f876860df136a589a49639e500accb05cb093027c85fd56415d2be7ed6623a6ac5547975801a15d1dcaa60a34bd242d377aa36d7149c8cfde3a027519af65ea79f89cf76aee485903e93a74fb231d0faaa6632c5fba8884323ba77188a968b8dffd8e2866469d18c165c3ae791d33f66f8db8c2e935f6b167d39528c97db2dbbe57a1ff3d35b8112d9560d6c2aef6a95f36dbca3b6351ba7aa1fa478473837a09a7475c930a6a96a2496da2b370f9ac70ecc03c05485d0c1a67503fa765a6ecbce8ca7f075761a6c797b6d098ad2ac07090313f5914ffd488c2c889e4db679ab53796a71116291d6c60d6dc33e9bcb429bfb611d52c2b981998fe1aa37cb392f75a0a7283bb990be9ca34c3e8441c8eae40df0a7368f1d3d0ab60575359016cb5225b507d4844d9e05e9be665dab6d23fe76ffeef260a900f49e82d4cb1418525cc684b49cc3e8db6b7d49aacf1f765204ee4955cdc0750c454e758d297f5057833d27fcf2d2a9d427554147ab0920d001d723720cb85f7e843f46244ad72aa78f645972518a27dc43114d4aedfef5c7d5f148f103b99669952880e65138c95eab664c10c34da16dd381a69812437dc9156106439e7a9fb369e1d14df1e8597bec0c68407048e936d5cece053592cd92e96312924d6e2a6117878587f7924dade00945045fdbab82824c93418fa500f46b19cb063e5bfd022180dfa39f21802c267fe9f01b01b309117eb69af7d1af750304ae688e64f29baa554f1572251fad8118f60c5f0cd2e0f0eb295082e46706da5b012ec4fcd5063babd2b5c647ae08a1dd3362fff943bf59e883850e7b4a3577fb0124df9588f2ecefcd117a505fa111da07946ae088bd31f9c5d6d38a7f804c2f6deb2a870f9ade1b6db8359ff539faf478671429a982d10704e158fd3d64f9a42b90610da7959d381945a1f5ae5d4cb7119a61747224bcc8cff3406d66b1dfa6a66491c476c45d80ea4ef6370933f87c703d35fe6de2114619bc2a92000ef7e0c8cc2fbe286cbb0e1a425ea21a8074aa488e3e77f5825e2f0009edcdd71cdc5b7a3625dc56855d5de79d35c3c0d60bd5f69ee0c684c5466b494a036783b3ccaa573a2bddcc6b27c48823546a8d749ca5b98da42af9d053d207b1c1e27686bfba4cca16a023abb002ffbf244dee271fa9090b4203b3a12335d5ad6940a4dc0e4a627d1c4d49d2207c5f328e6d0720fca9cfea414da7cdd17702766f89259b605e1bad68291400f8a588b6dea4e96e9a6f5aa7d377cab6b51283c79d7c5ec9744757e28b76774d3b1d623a4d80af039cc5231ad6936f3135882636286e7014818f48658b329341c2fa7ccd17cf5eb470dc9c84ce3461f5a54726204fe48edec4a252c28de8365dec5cce59a89bad6619cf9393785c68804d4ac01a99604e794d7a58fbe30d8fe69aa2854e57b685b1645d7e0146a76823bbc1bf492089500f20694a5b316a37aec1c3689fc80874dc34e864009918c34e54173c79082f344c03126c969100e4e02be20d952fe2693306bcf9c0782cba95434023bc7a4544ef949e11a689f9b75ba1b3a22a5ac42efc204add8b4e5e9f6edb3b0d9856baf4aca772b6509478d4f519552319ead2c22e2ac292a10e8b9f01174b7218810706e168c907fd9585fede152bbc54f70351dd0cb7a5a95b29b98c29f342c1e39c0b877e7673fd99eb365b046f3576bb992fe2a2fa8e2365c1a910082dcb1a24205c001ef6ecbcf132c7a7f2e992f8fa49b3d15a6885047f311493fd94a22e7cf2fb2000cbf7037134b6421554104862286af50ad02e8e13d797e8be1681191c2473ba0969a0093c9e25a3d3ddbf8be77d6a0947525a1de6da7c8e9b7b76349b949f89c3e245fda1431a7bc28399d8c9a370619824738a9786332260db3a684c28158fe4f2e3641cb9cf44f6fbe96420cdd6a0ddd6c2ce4e2685a89921f92713675d77527fc86cafb4a87b9a4aab5cb60b1e41976e241c9b0aaa654d5f3ef2830026001d15130508154eda19d8bcb8a66cd9354765d5458dbdf82075211a7af0225734d14442ef83eb60beb50e5c26514eee8087107191e817d74ab2466934c451a1259124b933c9ff92e87ec358388004ae971ff00a9a9af7924bf646144e1e5e3a6204374532bd829a214cae9ade28b3115a7be393938aaca27f85ef0648c137c6bb38256ad7e790bd513375069db6ccc594da745f97480ac1b09a59eeeda7ff32789d48ebb25ff9f75733fdee77c1d88b5b5c14a81a7947950e2532b0432e32b79002f266aa557f9a5c3c8cd4cf7b4ace54089d2617ab2c0d190bb391af53a9ab14dca93775bb612275e8908fd44dd7398fd333fb747bd9872063c2b5da235bc80ab1103ab1257c97e689cca3bc323c295bde0d8aaab0718c040f4feb759f3ec6f3856a1e01f0cbfa54b38fd51d11203a4e76ded5eff7ca605a4c88f9d81a8508cf2c7a15eefda10ad358f09ae2f8af4ed2d36308e2f7b2b4c9b6c074f3cef23b6055c66b0c85a0aeda674c922d8f5ad4d2d1f79ec1c1b85f152485ad2948e224512af3442daabfb9ba6a1fb3ac56eb49f14922a03f0f84ef49bdc7fbbb6e0e811b45b89d006710016e893f67852d5949e1591042fd44fc42873b6d01ef4f4d02b0d384435bdea148785606349262631986605f9384319135e845f96002ee7b71689d45010272f35dcac969ba312cbbbb787df33a5f28cfd731a6fc75a51b35bba175feb16b1ee2a030a8044c909e18d0c73f84c79cb9d3c9267923b6d83680644a10c17ba83c058ea8eab6c3c84a942cd629d637959fe56e6e2b0121fd36523abee45f8001504f75f671e5eca372f24437a5122ab714c777e4a801d36c869f052c43b447ac993fc5abae9c319c9ac985e7a7d6339016a477249a004cd2e327e09db219b1a3c07f6975ae1ee117a6fb321acb84ab7832c92d904a243a5500d5fd20218fd63da0aa9293903b8459eeb081e0255ab2ac67dc1ede5753141898b711060c9380a4e21ed9f4b08a699e5385926f858485514cf89c60d37eb0b2d35c0c0efa3913c1d63ec30a8cacf0d8b94c607a4211eef0066a1f16243269ed4e8842f075a4e5f22e332bf403916f5a79f0bc9874d6f1ec3349a81207a085115c3b82391c584d8c29d3175488bab3ef948aa3529533d41a053fd8abe4b1d0e6735305412f3811a3d79c3ad2e8ad074fd9530dc282d18c4836fac87960cd38089cf05044e0938254d846408909c40aef514b229dc2b4baa8aab5d154a0427f92609af96a8c9146851875c6f47db3824a43bdf4a052ac72c16d00a27fc26e26e9cbb3a222fd13233458c54496d9212fd5f09a505149179905a8274b9ceadde06238d0888150b30e2e210fe224bb19f005924c5221eb0c6c7c4853c1c24c6b0604cd9d39d9f9beefce2985d46675f9648450897535984c6b527ea3c8ccae5886087f3bea0528b6709304f2945cc28f046cbacaa08c8d19e125f843351fecc822b301fe6cbbee267821148ae0ec3b6749427a059114b267fe66b17f2d1d7d9a2cd49b18b99ef1e632f5ce4904e950663dd55e3da0de4551b5cbc5064c6b04754454e1807019e4a88d1ee053bcc61d34e45e5c9fe0c8e472ca14612347f2c84bb81099dd904f4b66c6bd5e8089facdbcca5a515dc0046d7853f1553bae35a39df80dc632762212158890be7de1366b22968e1995ed9fc44cdd29b3dc9d9224851d7396577528d203bcdb1036a5d30a6f66daf58bb4ae8a32b38117009e08627ec2635f90a6b0bf25d01bfdae576409297a6896e8430269c85151b495c113309f99046a99687ea3f7d8655ca1b023151be89b3c7dcdd71e671bbe3b8fdd785f62ca523b76b26e213b9f4a815ac73e3b623573d8a679e30dcf8c474c2b0fd899e5e9413ebae93b8cf5884e7c3b25d760a4d4e6c53a7e1ed1ec4c918c9327bdae0a8b7da141a84b9d538a924f8922e32420581414b934d1e80f1b61a9780430bdce3f5cab0a02bd9bd1f5dcfcab883fd9e86cf855437ab84e66b67235f03f477aac0fe90f77a891efa49875520bdd6063f1cfc76c1dfc9f761ac51034c07411f287621848b5aaa2f6ae92034d8e229df569284d7f2d00bc1288511fcd845c4972d642beec2a47d7064cc0578ebed4f788476fd7c5044ff7856216e24d6793f50935a7dba16608dafc7d83ec48fa872458e81acb505dbfc321310e458f68f4ff5f918b0ac1c1825d3c993088c64a195e0b155d6119de777d599abed7ff5a23e79d88cc00228602e88e5e1560bbcd958c32352d02dd2b73e0cfe146747186f1a681f00975a5e65cf045846c0182827835c4e7a1316007f96a981a1d0882cb982e2c8a36e954facb1a4a7ee06c48def682c91aee9e2995919aa1590da68494a87cd02c21500def56778225a8f07e6e38ce48e054814dd4a2c9f7a71bcdb208f097cd2e6894606ecb3e37d4fd6d18591c9455d62978bbaae1b821d437f3d771a624f26b04df3c2441fdf579541f5d6aa2633c7182c721a0b5197a7dfe0767b00b34d8f04636e1c6bfecb7750dc7364c8d1c67ebe7900c61dc44c43c5a74d886d7279c985d20b2b0483a449276887f41f8161bb05e6d4e751d61172841dce59efcd3684e9bd7be371d16d958c7be6a79fbaf2b150f87c8fa3ab2935ecd623b5be9b0b3b9d31493f75b0ab44a7e9a099fc4ac18a777e8be0e450c280ff1ad88cfad712088b877ae506d8afe2728cb27fdcee15163ce06f12e82e91d91f98178f1d2bc8759ff208aa359b0883a32ae70cd22b7ad0927b3e476474733d899ac2e79fc8385d90581558d3074a09a3bfbf04c26285aede37caf835a61579a9ab23cc1f40edc89de0568038c39f91a00e12ff10e3db4949d5d7ec06559566fd2ca9e27d6e1336527915c77fd6298f387197205f0b2cc3e645f11ee8e942f230b4efc0d83e10537fc69f573a59a10767c254d74f232a6771c2724217b850916b9ada09fbb5d424b9847280f3edfc104fef8d8670621b2370e369cd68cbd418e74c18b825c415777d09faa021125bcd283a794e86f3f724051ddd1acd0a30b1f8a564746ab5ab265ddc4ebdb8bdaa57f6e097390ce6bc424bbb0e87f0040c8678ccc0fb460c9ff604d741c21ef28030f9fcd1f161f91caf79d3dd1c9836acc994c01e6b04a3571eafdd96541925dfd66481a9962771c1015202cd1eca436900d82aca8ac2c2ca6b451ac11ad0662386d23b31c33f6982b1e7e0a6f636df85379dc78c058cc84d5545545515fbe1c3606a7a30702d223c62de54671b7082e0918a1d781e4f37468eb301e01ff03c29104a251833a2a4f8724a23b0650c7107063f2617774e151bff7b7db3d7eba90580a771ca1d931a7b82a70b796100840485d00d8818383bc8265ef44911b3a207bf05b36c8076c0b4f0bc91e25da8a96be76dc12047a3751b192c70172c43121a10ea50af10d8da1cae133eacf219dc9d8e8d92be1b9414fc2c0ca47bd6721d540f92db5da30491304d3dea28f1527da36d3493768e7c1968ef8487d0e08db5e28cab7475c0fa8a3dfba8499888b7ff171604c825e4c1787e9cc960a8f8858ed6ce4dc015bc12cd59933466647ae906e06e36ca8379c273c4f8a7aca8e35102abbb0c01bde36ae04ead0370bdc3b5427f4a033a4cef92f1daa026808ee65679c504c86664e9010660615349b458efebe62e57ef06d97db4f14eea0f14101d6b6920acfa14f37405224c583d80c2c0b5060f54ded923993f59053d549b01e1770f29595b5c9f240bd2871ffe2a36655f5226812d28a8c80cfdf815ea340efe713312dd8b0514d4b421cb09eccddf8e17b4d5b43f1b10cc9f6214cb3ec3511a39cde9aed1310a4d083ae3924e5fd23eda69e3c40ba06b3a3abd6e0d32c6583624a91e8a49c88b68c44c6fc87471f574aa4ef32e540c84907f0a2ccc099f78a77236c1c08df3acbe469ab359110eb2129b21a57ec81417ce1129ea579eb94e0c284235d6e52f0bfa38ccd7f08324e1b3d374280034dd5705322c022e3b895082ca715699363f9131175431aba4912e364e7559d89147d99d65a5761ae54950748c830a86d20fbb472d390466a72f1d0d1d02df2a09b5ea1b7fb9a939b0b49f904fc7fa90e4e1f4656149d39e87b68b9cfad8b8a544a0ec6a34a11cba620f315051aeb110f4878b314f7d3ad9bf0b84f04e0bd35519f967eac13e9b947edb83e3e877040691cc25d6b2b05f283d56bf898e8d7edfbe23bb900e2d2e73f067ba197c8ed56fae2e344238af3b5a7db379bd1205deb399b25e524e7e0bfe21f0c93b26c4fa6930887bc1bb42989c3266fb3eb540e4abc477283e9870d1773ca01f3501076a00e382243c5f61c5316e301c852bcd4274653e420171638ebf81a81920d598223cf4acccf62434c398a433a76a0545775253f32fba4274fa8871a21da06b38f50563a39468ad34b38f449e0f31315afca9ffce5a8ca59c0ffa79dd640660ab0a77a4ed2047a65047f8c8f65bf420f4a640beb3a3d0c30906d758452461b6fbd2e631921f5846066badff5059f0bcfaf657b157eadd4172a7489aaea04b47f18de38ae0ca5159f2f9aaea2712ec7c51c0d982ae69300ffc86039724651080d23f54fbf8b766248364b455970e5f917e4055629075ef5027e286706894d814c8924cf91fb989d5df962ba3f0c31b3712390acd4a36592ef0753d4b6f40cb5d31303c5a3d658c0fbb84f79924f576e78ddd96fbad03a0436d123f3d4eb73923f735e501eaf33b059a721eb7513f70370ead11b8d2f286a57f7f4304b097419ab560c009d82462de52da8725676e42a3de20ae6b405af9a1a5801fbc813afc487a928869e5892e24f1829e49ab82492307b7c5c9edf959ae2fee1e10d8293ba8822a2dd62fa3a66b56eb14592f4ae4ec840954a628291bc0f34d02f65b13bd5ff9cec78394e2c348d690e6a85030da89c08d06c96a55230c18675b05828e9df2530e4cad139a86f5b9eecf8f0ac386789a7b8115c76f6e746ec320efe1924780ed635e6beda5b8fb37bd72da64e1e5e5bcf565c8fa27d77836259a79bd4de05091fda4753aab91ecdc39a0e2d297e21b9fdfbd645bf2f51f508440ab7d0e699ef06a2526ca5883e3456595ab740ae758d8d6a5167174fe03b6d42fb2a5582716177294efb71e7b4f5b1c7d9ea1f241e02fd099ec2c4153733e60f557c21021fe0af14159397f4e4bb6b89be9455707269dc5386c1775f564254dadad5d74f96da078ece2e9281b99c1eb67e5059de3152c86bbdc07cfbabbcac93b1bb20a24cad543bf20974112fded5c1665e1f104f78579c085f0ccba22d346a9b62073cc8475153ac00c39a4bda38776a6f5e6b789e4a1ccec1991330aa50a05fc8112636d8cc3f7ecca1a5457e8e7b9a2c9788407c0bb49ae04e6ecc95c5e4d134dcd205a0268040abbcd2cdba9452b768a63e28fef1f09fbfe4ec8649fe922c0adb5270f94ae26f6d228ae9e705f20cbbec26c59df20b6f0b043f1073d52a85a4bdfcf27b53bd66bf8b27922e8c7b4c44eef2434629e2be5a983b1654a87987a9bc716cba4a409990a7d3dbf6594cf425a1ceab02b77cdf15a84ab39c0b428c4e10e38ba81b6cf9c12de399dc8bcb8e476ceeed16cdf9d4e883c9c9e75758be1406ddb95d3d14b0592981cd75d5942a128afc8260484925e28c68d6c161baec2c21173667f7ee895f33be9414d7f9c94e0ed0bdbe2cb5d929d3f479a5f2fa7ab21ade01200364b408b005965918cba90630d894ef04a1a46882850ec755cf8f1aae688faaa0c87b67093c211ff5f1dc78b9067eff494e4f6652495f0e7c26cd7e54ea31f74ae8a97bfb497c1982a3f16caac75f36c8a502c87ca982dbafe2140a9ed03cf1783b9bf7aeb81410ef0e0a90a4519e8f310ea43da4cd4af02efe95cede715b9a6e795878c4428569ee77109ae7502c81a8174c8e327e6e18b106f1f3e63bb2e7dfd5986577df20db447ef10e8a8183685337a7b02f3fa78852ad928486f227eb9e1ba0eba95cf2144a055de7b45bb5701ac4f8b234d70b1f3bfd031b847e9affef977fd8d817fe64f357051fe71a9ba0943075d1f7800ff1f9cbe8e02bfd3e75fc7356a5088b567e0f9a330a6fc8676f62f3d4786bdf53a8b204fa35dffe960bdac31c5e902df61ef559d8d286cbe82dc6f34709246c4f1fe75317f6be97877a27bd45b26293e3477091d93aba6283a42902258d3138e1a2a02b626f138442d391d18540690047105e596ac303012c5c2f8a3c1731f0fe948c7ceb8f21b7e1033b36ac5b202bea8a830150fd0925ba509e17831de5573db26cb4ffca4464066073b41ee3e0150b94a90c4954334cb5e181558294961434e9b78f3c0249e3386d6ea4bc6ac4142264220b897dab1d615f6f18950bc5c2f0268a4aa935bf9fc96190f2af3a75bfa08983653d20129f3ea123301c16f4dfbf1619e93e0bdfc70c7302796a3471266ebcc25b08c9eb7e99560ed179a276391e0498677215252363e6e5df1f99d3f2bd011c6c332c010a54a88fdfe32a4dc73dca00c87d96499fe55d9cbbb997146303462f48c8fa803e7674608f36e38fd146a5b3b250ea8973e544181a18d12ad1c540f27c72c48c0357feaaea7f1084bb669109b2d7a3b14e7369f143a3c2863cdcc0afb5ef2c71beca4a50b79552dfc6cf3be2d0d45fcd332cfbe81653e69da6d2f89634644d96a44b31e009f74e02d8978e91f9bb0a7b183a167d607e0476b2d1734334cd3b440b5e2f9875ea3621e6a76c2b926012072377c027fa7dd57428635e0f4c708010a15e1e9980da1f141b180fc896baa034bdd34a005a20355073870a0b3e9e1dd5338aa27025b4460414bf5972b8d99b995e73cc4827588f2e0c884fd38a243fd22ee0f5c56b263ee4acc6818e193a997a19d6dab0fdc84f04929351eafe02943d4c84dd64bc2868c7e19cc980976b4ca6526033853119b92a91ea141931b227b532199d19cb56d9a629d780010826c358fb0a2b974c2fb5ffb85261adfe1580eef178b850a29150019504273078634fdc3bf8117a4867639d84d34d524db60ba419d9bc406306f2a712656bd64458ac349d3890eef07303f273f309be11c27a2c93ac2ee51256585ac63eeb4d9517fab9918dfd2c690d27813249c12ec914586057a8df5cadb40e100259960a4064cfa844a1f2b1f075cef85308a0439ed680688464842bbe71f2561f2cf36edf7c279852205666c9782545055450b0471172bd6795ee1b447f37011f2b60506743e533df3b9cec9aad2e1b81ee89bcb815f1a9ceb955003559610e86fb7915321cfa7bec975d5c48a07a42119dc6042ea73263ade5617dbf3b88f8bbb536f4124ebb98aace766d12f66b5a40bfa6a5590f0b223c8e229404682313731e40c1d09e1b8f3d95ae190680d591077bd9004ccdf0a2b7ae7a9a61e1cce37ceb6bd0b1d6b9f4552822f249107e29df26492fb6938d3c94a4cda6a543eac138e05b89adac66be15748f4315e570e1df80311d574ac628b32ee87f39f31d9a4a7fc92492e38f201dbff072f95f81632129cd08366a47c8e1b20838dfe82a565c8868aed0a6ab3a70749b0f489649d6c6a6e7f494ba6b6686f6fca82a5e0117786da85c741e284a48c2991c57d637cf69b8cd0cbcd3778478cd9b7b07ad5265a38694432482eaf962516516d10aaf088016a9fb8edeb671c09574409d071951c844083cc127601d8069c6ebe8740d8d778fc76ac1b3dcb1f3994627f9d4c0fa20ad223a265d6637ef822e2acfa60fa1b84e5a5bc8c4130d41175c2d8a33083afab62f6bd0c06dd2bb4c6879f6a5d6676196cd1724f83d69e8df7f44ce4e95745f92454140554746b7a5f4bfd812dac211ca2f252b33f83889a5ea8b28b709b83b602b15d40dde01cbdd7da6a44920993e29f91d2826b2b3206785dc3f6f67c9e3d72fdba9a10bc143cc4d0d70abad5a4c3178876e17f8007590f821d68973c1a7e79cc6ded77806a47bf1468a097dbbb4123488bfa4ff066831b8d999a41e9a661500b4588b79bae5e90b97839d2158863c5f308cff6a83c1cfc3326c880fe98dec68fd5ee48eba4c5b5b1f2015fc2f08992f0106ab06ee8580b5d6c7897b55f07185dabcebff9b2365667973b70ab0e4ef2b0009e1defa78decca39be1f0579692e1df7b9f731510c9969d02aac610f178740e7eba302785c8ebaab62573e1c7fc25a360b2fafc0a6b57435809ae30bf5b29119c0a529dc0b280aa259f64095380246dd97b18bcc6dd5c4f19c02ddce3001dd344cf577d48cbd1424ee7dc089a3bdf6b326455e2dc38ba73d669b364b5845c38ba7fded13064bdc45c119a7fded732c8aa84dc315a77d6d7b2c99a4b2862beb42f1cc624824b9a53a87f26bc7df33e5b1160619201860e00cf08a5df4579c279e9ec3c07010f3eb17aa1e30864b0fe1beec384e64db0265821d0ff95577c3e7e0d64b9df228ea765790f171e8143ac8efd3da6702bbb05725d16b0543f8466cc59ed5647316315dc1fc73766ccfef09496080371ec9cbeb75e433fb552f6261edcf731df608713c89bc032df3243f62e0a47fadee91e5379662881582309b6f7780a102bfc4126ef058403c594a4a2e3568b976de7aa80297dbff9de38e404d10b386fd67d8347a37bce3188edee21109b3a84891639c5bc66d984dcdaef028b03837a5990f65f68c58670f058f4ea5771431ced58cac96311b5d5969680feafdcaf924c7084fb5a3b63039cc3385abb62bfec3a91f8fedde73228ee399f6b9295533e0332f10bea5ccf969c38e1fd74744cb9c4151a1f548c2ab2c2b75615dae928c4dc41aecb974c9b6000b669cf4674101790101729520cbbb961439ffec4cb518ad11405ddbbc5e7e5f74d8501fd41d81fc3d8a0b56bedf9494b80e90f92a9ee769320efe09dca0ad21f20c250f8bab1c27a19806cc2a0e30a6c336327a36454e74384294516b21337331123e0283958cd60b915f6e4b5d56cbeca3f165db05e6c098b4965eeb213efc1401f3e8958e946c0616fd48a010bca7713178a7ecee00ad14a874d53901c57c24462a0a20b09c481f319d14f045856f37f5bd2ccc6809a9484b4b03862bf40bcc00d7c3a8ad971de3b9f23cecdb891958297d0105f49bc23dd0e91cefc9c464925aa41a8c195debba4b4c1efa68d184ef28a6f27e3f96a25386d2c2057819bf71a17b1709ab11e5cd3d6789c0c86a03d611e577481efd7f9c777fc77726a8e4866768f5742638b8058434c7be31385a6249e729ce85baec8bf9ee2a2730648db6c84cc53d43b9988da93b23b3857ef12bbddbb27bc3bbd35b71e09a2d9a9081ba0d42b199020725b09ec35b0905ab8a0a982f656c2d65b4a814493ee6c19f34dd38a03ec0021a61fa0ea86c1068868c80cec4889836675d2467b39c41aaa436080596cd8263fb7735cc519cc135795155692f7b67c093aaf045dabc40f02c644f24907024611d3d5a0383f8731fe4dce40fb30c6fc8856b838c508f256cb5706de7afd8bb5267e67d8f2b60f41fa652d13dd356ce9ed7bb7497f474b42b93e7d48071c3d182bce81f45c19f619ad4358288a0d705a3dc122f9247967a817c0d73dd4f7e734a1ba055ac365fd843eac66ab8b168845904d8f417925844dc0cb416965828df841671bc66be8a44f8ddeec0c8cf35df36b5a7417460c0c11f7fa700333261dab2bdaa23a69ec3aa823a8122d82107a9b4a3c801895997f079b051e098cabaea0b792e3cd9df5187ea2e1f8355b17d3fa872ebf83a919e4a5fefdd3d4dc65eb46c3a5cfd6327e45a07eef17a1c395ca0e91a76c52545209bd27c160db8d304d38f7434cffaae8406057421250b4fe6cf67b0263ab548d57d1ac75411f6d06f4c36ca62e3c194e64cb8caba3e43b0403403fb2eed25a8bf98f2cd2adc55e433f1cabae5f28393f9b48926dbe92c62b838df6cf268a4460c90478c3ba5bad35192042edc056a4a53c4acb0b3206ee36f50d7ec7029734ce87806342a622c534e5329a0b7eb1f4d703e2a8df9f8f1a22612ab4f924be7fe4388404a083e2429feba6752b025d490f5c567888c520ab9a15847f260d878b5d0521492da5b583e845ac5e7e73b3281040f7b5a26ba38a33516344fb482acb93436c2414758cb148f026f24477c72720bc33682a456f0247da050a5734829e96ab83fdadb085b151fd82636fc11478b1cc1adf47b06eebb72b21d4ca44438ff35bec63d04bb8e7f78efb2a97abd6c50ad410fdae7d55ba23e3dc2f052bce11d5adbd21e2e216e2035f7e91f55a205dc71775f21239742f331593b3e8a94ee2bf6106e8693c704d7b63719819d4f621a6c7143767fcfbfef8466fdd1764fdc33b30f1bed29d281188603db9960a8693bcca8ca36772d8717a0e79c461f78837fe9d8f7348db3a784cbb915eb56ef0e4c8db10202ce49ff8ceb62e5628e1a645d86d0f14a85e4090aacf01c34eb41809b8147193021a182789bb272fab02d28a1e79d75b29df7f3e4d69a03d49b0eeffcc92544701b3375b6187eacc2b5dbfbb06e76e38693bf162b82ba7ca1d722d57648b73dab36c176fa4f176eaf5a4dd7ecea5fe30c08b189815c6e94669999d708556233033756d8f1867d579a12e347cb8fef58c9c514432776823415d31422555738a0e8341e141c99d600d7287f46e8dd6062809d2e6c7b8774843b92015cf8acd29084abd686c249ea5459d09c0ed238c04e58ecc4b6c7b7085208f45fb26f5b1ecaace9c34328defec703c4808808e003d6c0865857f1a1f3481aa3fe3ee2dcb20523bac3ebcf4d0de6a9caebafe506b7f299b1305ac0e9f96998d814c4d1d1d2b52ae8d5d848a922da1bb97bb8812954da07f076f91e031013d5ab634e8ff228f5a992d89d9534711ae3ce24b9dc734ec7d48633e80f3a85cf8bcb9629af263833f6a8ae05b72af015ad063f63157818d8dc2b48692987452f7037f5319fe86c5dc1b26e42a334fe56d286adc89059e2d6b9be48ec9d6dc7288d396bd267f7770abb5be0ff734184ac5945b39a737c2f2bdb935839380224c15d19cd358737b30dd6aed65f6fd8f5c4785993caa0055f7d4ce3a51d9df477637bd67969053298fb9e2365f562af11066043d4470369463909ad6b290fb1a725bc9579067ddfcd188cb86dabc9d86882e0dd3e5b8e112220730aeca3da047a1cb0ca5fe1ab6e3dea0a682713ea374e8f036eb6e61ef00f1ab0d457bc25daff57cfe1616c3ff39df08ab784574a044d9a92bb4e75b7eca9b316a8164a140cc296cffefa455541c3199970865cd34950a18d348d6ca6575625b9828a91026b77ed5b762c5cc76cc2bee91d8e0e96528649258370e9eae60ff9e81509c61a63193099bcf717025b40a64781e69ac384dd00d53db06dcf1937d1d21b610d545f6899bbe635497151aa58a2b4409d26b08746eb7107defbcc1816ecacfe67672f4cc715414f1b3b92347e1bc8a81211f10a87bccaecf88c15edee4c96f1430170459d0d40727becbabadf19b50971673092753ae6bef0c7398b0beba046d4650f79a8e185d0e891df4292c7923b21b7b129dcdf2d3deab3d347c41b72b6a6734bd5cd65a759c4c7220bfcd56da0da0c19eaea17ce3ca8b2be300ff2304d6ff3491bd968967a03ac6ee3a00b7b323ddc845a51758fb2fc5d4423929c692974a697292449473a2bb6cf54e54e7b06b08c93cfef9bd5456df53213551fdb27bcbcecdf39010ced95eb9b94c8f9931823cc52ad318169fabc421a5eea33f54d319205d37e7782e54d4cd87affdc1495e69a6972c0ad5ea496e4f544f3f4ba9b1a928594230b3a7261990953f56d3004ede33563baeef9c737a58cc5e002a179ac7f4667dbf06d46e638850b1ebbb785cd260ec7b8e5f5abf0d30c2114eb80ac260b8a1bcfcf9c17a7b0990067ba3b867b2e6671bbc74a0b0d26fde09fe36596024247406e9af2f0f91d07f423bf5cd424306c7f3804f6cfa2620bec1efac49de38c93ab8d6fc54d02447e3bc45e5cd9ad5a116271272c10337e7dae9e4fb2bb5a6b99fd87adf3f7f437d4e20dc0094a80d98e30705247df6f41ca6349054219a9f5b53d025175956c36c5c15b4746a5b417ff2c11ab49015fcde18676074b7f3e262a1fdf6e43aa10f917afc9e0dccb1bf7e707d42e95e2af6bdd6a07de57c1eba5aec36e0440c553d1ef03905901c0208553c5b7a3ab666fed918559b82449852ae2bcbc856abbb94d3076cb59bacce2a075d903135f6c863c5d0df1c08d92de5e45a6d797b4afbc0480def944c7cf49d2098e276cb1bb84d29cea20d3f2fd766c1f5609cf6d0639b1c91268cfa6804e76e32d0af3ed3a71de2b0bcee4282d64eac5c8369fec71d8f8d1e183ae0e5ccefdb7f80843ce85284f8934d26aaefabb2f5e87f7bd23b0465e65c390b3966c261abdf9af332d8d5b050ff0cad66b572e2cfcde4e90572d8a4abeaf70b3ba30221d53a29c044f981fcf06fef7219229e2430067a19812a8ed3801541aa4d20d23dff5d192216f15fe3279571b568abba97681cae8cf248e54c1b205bcd8c6beab7b99e3ca5cf5854c1a2089e5f015f9fee771d796f91cf4244997f6e9100f4d2230e3b5d9d76ecbef6e0ecb8ade5bfa0583fe143515905881fff3a3dd6063e200259347404bb6421affafa6e71248b2014e29cbdbc65365a17370a49f8f74727be19922277d085c3a3b4f007433abcb38770b87ff77c0f220e9b10d57c11d65d9d47d0418e6adacc05764d181705ccc810120f84fa4973f53c598eb7e1e7e2bda9be0b69d4d6b6ad3d67166da0c6554d3493b80b6f9af9fac4ec833331aad6e0b9ca0f4736fa73aaab133865a028047ed950aec2d413848bd55a9e3b43e165119ad29101200d014924bdca1a915c2ef7c31301780a9192c2a1139c1027d261b5abbabfad54c22823a18bc5a24ab577b3583189226671d6157dc29d25f91b6f04ddc8fe93a3853a9721da17f98a578f4b650898c47b451cb6a91d1504c5d7502db3e1180aa4ce9a8541a5d36a949a3dbd76ef180d9eadf756b81496b9cc69502d5de0c1c397557317f07d1829938d5f5aae9a0feba2471f1e0b41250e409fb5cd15c53cc1e7968d18f75618be3ff2de8c86824d36220e9f259ce0191db8cd76804885147dc06a7da99a78a756fd04268f7f2e5653f8a58dd1122fd4c314d2befedca15a1e5af8f46cf0f5f728a1b0a5b6c187e1d74edbbb0d8fd28b09b1aae5c5c2d101ca435ca39c392f8e9e65521ba37215945b9700459a55d55c574d19d71dfaabb59073697ed77dc3eff32dcb5df2eac5c06aa2b67151d8501da482cd1b0e1e465e8a72d453468ab4d7ea88580fb8763afb805a9801a680eb8939527c0992b4945a151d7c4b8618ddeb290a1cee3cd81210a688f1c46d1ccbe74fa8381138fae65331c4706ae49527f95e8a98b90b29349cffbc47b84e6c65e7ec1b28ab186b49331f6bdb7a1e404148977f07a5791fda942f3e43f0abc42059bb0e58cbb44c92540f9b796f4c72d6870a7701d5572da1cb290614d520e85b4a06a55c7577359183693cf9074e0fe9249c6dbfba39ee517774f8be997f1375b238e0367342b595d07433a9278f10e1a780f4e9e214fd0e07603e4dbe147f1c841dfa4d81d5427f6d3c16d5e8fb19fa38d6eb6bb8819886a8b752a7b68d3c951a16b6193ef55411dc369bc10b31c1371f43fadcfd315c0fb7f0c96d18a3b5a0b93154954a1a36de31d34137bbc48dfbf6e9c565c6eca88a0c274ebb6707ffc6963b885ef6a2d7702088a440178c4b5541f92bf5dda5d3acba75a0140fd3a765d3172f159985b57bb09bc1687e03ac02653cf152fc30ca18248d32c36e8bc0bcad0c069178df309bf415f016812d70596e30a34287d1f134d12cd64b5248465443ec1e2e36067a1221eaf5b8f63cb252cfc8bc27082c9d37c98e464590b24d8bb41e1f329ce7ad10efe2cb035ea4ba77991453f9b7b49493f67df5359201e5c54f5904b03aa334f60a9c1856c9e62cb72b1f1b91d93f35c8a3cb1fa2782446047c7e626068c4146e0ac02ddcd8adad43c95a138ad184851d10aa419b712ef67ccee478a6ac320c98a94a72351b89e65b1f8d9906c678205445b5eceabfa347e04e749ced433b413e59dfcfcbd59133cc3d7794a1881224106ea5a33c580800177a3c3df66835720bd098b95aacd64d284647be02079049cdbb7d387d6898acf6104c185ee10231297aeba00eaffa52ab2d6a59160c9f9be076e35a6ca29f8dc65969e0bad5b423c2fd73c06a49b73519cf5222e3f673e9075608b2639a2de9750dfc6693b17f6a59515d45b5bc4ee40de38843d99dfc0f32109e042fe0e24fd630c472c6632fe332761a1a4bc0de6deca9dd8cedf4c0caf69d958886b16a725d3122492d99303b1e986c078660e66aacf4b2ec202d4aaa22c98af9babf64c728ae1080f676d2e5e4a2f2d173db7145cac31381da05f17f4a4c4a9a1242664477c0514f24cd24c02f06ada9e1c3536960899f0a192a627de1eacb9759a1116ad6ff572c2814e33fbee04c020a2784715e6db9d70a3534f2a369fcff610762392e787c3feb6c423b042be20c65c7178ff284285745927b79ccb654aeb12e55e6bf57fbde4b0c25656ec7850a482bac79b2ec1fcaa39edcda25343d216073a761ccf5f3c70813627ab3eb43d918d50bca626118bd1be56957c2be9a6cb813f29c38a3cd92d9866e500b9c551b01caaf6c207336dd274934344e0ab255693ffbb84bf663f91a99ef93d18dc3ed1726e998009c69cbd6c7eb0b57ef3a196c778eb27618d6eda44b18d1a232f0645ce594931c99573aa1c89773228299f4f24f18d38dc81d52c411ec747de7d3e5cbf66e90e8d5786386e0db0cc8154561488475532e3cd488faa892bdf34d42557727924d6f518054906d7d70354a374876389ca3c8126644aff1892f7eb7d09188ed26de5b7b46d3c9f12b583ed1372ab797198aa8eefa1867f65115f40433af8c7468e52d8409cc0060a957501964b402109f5fcf3136d53499f135f051a7f0ec680da0762680bd0658a7b43fd30e61f881e04e3578041688e010a7cd7400c0c95939146b8aa81f8f96f3881b0896ec4bb8e148ab6de245df1e37af156de9c5aacd85a6b51490cc4886f90184b03f304ca323acdb7b054f81707b04c92aa05749b79813a5f1530388cfdac5794227a0dcbeb602492d9032f734143551ab04b2a9155928babb891084de5121b144818b350a2a36d11088fd7d7c0cfaf497b2dfb9c24d70c5caa1145c8ded7c4d40598249c1b3a8acc78212eb47f7d9cf7f869ed030921e7452674313f6a56603286d102c0fea8cd9cf77541a8173599ad0e9172e9521942aec678af80c8e9791d046535960a947a1e484162be717ff021f2cc1d14439651a24ad2f24f73b885436508a007e0d568e14cde40703fe595f90c47f334e148d82b80348d44f6975cd415506b4ec011a78b14d5c40ce514a1b69e56acfbeb65ed934fba59b440113890842f49440304c237a3d1c634772ac96a537a3471bdbf406284309951dcf1c53fb8ed877803d064adadb3b409de266002cb3295822112634528b7008e8db6e4d526865777777ef5705fa044704978990dbc4876db3c316e5b861beeb44c98c0a46898b1ae74d929a21331685321726a6a2d162ab4cb164967459ba2f8440f161a3ecc092e3cef0bd5e336a98978b4bc39b2b44cd153356479915c418d1627b9872a52cb964962c1042ac0c3e2e8e1d974a8e223ecba669864da1c9c575bdb932a8a945989152e6ba10636568a9c1f194aa03c74b7860b22c10b14c8034c97073b8ae0d1cf64dab7b3f2fc40c35fc76f8c2e145f77ee68f4c32d5e7d3397f7ea8ec605302a698a46860a6218a2e12132c92221815490a4414c90b44130910222447903829ca3a7c21e9921d8931632f19c9d04b2cc4c8ae0e7e7bf03b832fb529b24333ea778302c1e373a61892a90951c784c504adc3d70d4ffa044d2dce9662f46d47ce6869ce49eb104d86bbadb5f662a78c49b673ce39d34b524b30be23b7d486a58772581fdfabd56ac57992e5b1939922c7d4a46fd267473bb1b3b373c105da09da317d61c2a2b3ac692f5127bc8e9821c2428fb0796c2174436b0d416cece03b9c57203e2a10a5126a16ec46d71f687ebcb845dc31dc46ed61a85f249e75f8ba814d5775f8baa187eefd0fd209387c1dd9d22f15a6eee1211dbe8ef0781d69e18851861d0af491a8236632a0b50e5f4c524c4368136c510a2f0079213982c4894b5f38378d939e9eba85d29eda65db2a178cb74d48191ad8c4f0f4f110c9d02541d674d1af1d6b7894f0e221830454720c42e09e4f4f97db8bc851ec91401efe305d3e4fa2238f07f66baf752c38e0f180f6aad75ef5b0a76f50fa400a640e05ec3e9001d20732206a3dd91dd1d313e9cfccc1be49a0e8a9d85a7827642bc47262d150ea58829ad0a9138fd3fbe9b027f6c75282f00ac2244e5c86c79f93888692045cee9a7f05897a7a058981012d017491d0498b2f71e2a4a901a64b9638452e402969be0d5a2df86600f94898894e5cc8e13b402b09cb97c3d774011106337c0838fa2010d492402b3211f219c0b6a8c4d1b1c3c702d8038e6f44eb4c8b143e1ebe6f417d5ccb480be29223d08d960d9660c05185060a683e2c546cb87a5a1668edd8014a479714e0380111b383b7e248f996be0bb45edfd0c76a4df930d08a4264aee5a98822578ec068ba12a48696abb6c07c0068f9b026478c6205881ebe305fd4475b302f6aee8b196374a0c10508a3272b4a64b850c3f7e4d3a055e3bb52e5f369692d182512a1e4e3f24da0f5e48b7d73a755c407a4d33a01062f5022d2d307ad347d5beb06269f980f56e18965720b42c53e1746aea886cd9780561025710534f00748442b4e552844d40106c1e633e173f215a005e653402bcc9b4f95410bce07a3a018d8e6c670f3e32bd1e2624374fa20992803ea30e5b3c013dc5224c298fa220a3dbe29374ed8c1e3fb7e7624c1e1ab40005a43c6c42f54a0191648f8983edcbaf111a0a5e51bc0103f7c6bbe9c56035ab08c8f0fc9d7420480f8742b886fcbd764b7a20a4a4d5ef8e098183e1a86804b8af81cd022b2c317b3c02cab16ec12afd068e3838db225c3b780160fb304473e24a5d9f14ae251a5c80c574cf3024a7d8922f851a40c9a3466a468500172a6e58a2550e095b5209637369ca4be335f4453f441a9f7defb3bf7de7be9941b27e47ca5f4fb5c02c1179016379474ad07b4200c4ec5626b96ef67ab577ae69c73ce08b9f4e0e26393f9e9a957762080830a0f3b12c617b404caa2731d6e0260e1dce1c79757fb40eb8045a77dca37212508f2e757ed830f74fa93f3bace7521fab2be7cab9d90f346a552a964c021d507e09b8c31caae87c709680370482db5db08ef78dd0037e7e4d2678305f81c71cf47023e90ee67a33b88bd002c4d000ee90046441efee24784f11c4019810a680c04c0e1434be5d6219490f3b60853facc6ddb38eeb649a208af0131fb8c144bc4cfb252bd527eccdede0b42fd95ecabbf9c9793ba4d01844530fd3e8414d8d76908c23278b3fb5ef63aded5cd4c9002187473de934e35f7b81d8f169d66908c5e60908cf17e46ba52e6a4a49e710dc55dfdea66aca9a4aa3b2ad979f3c9fd0e4012f7ee4ca5fbf46fa7a3dada892c3f759d73ce5caddaaacb3d3252d58fb9ec73386fb3b859e585419283600512a8beec22c4a619349ba67c0283e693f89c93ef45a92e3b4d5b69efed9e7b601087baa702c2202cfbd8c998b34cc5d6b44ebb5deea171d9dba7d93483f89c4f6050002009fa34c2ba749a41d16992a02fefea55efc5a19ead3ed31eaf3a2fde00c02008b50ea83a2fd28f4ef777ee114bc4dc23cbb29cd4f3bdf7e61e51033b5971ebe14bdf7df5928b6b8b54df62644bd116285df7ec65d17cfdda431c638cf531278463ac3216d9af992cea34621c238e594f9f8fe17ec9ed87197d4c1f4b222c75649cd0fd113a554999bd248a25e467d228fba8ea843296ac114be08f19cd79cacae93c298b68975d2a3fb8347a30837e74a6f4299544116359d4bd15bf394d43b17ada6d69599ccaf85c671e4cdc792a362a5727ac6cea3abb5996a5d01d4ba22e7f47aebe8ab36f624a59c327da8f1f71ece0f4f805ddcf24317fbeac91ed747c934fb72e443ffbfbded62f0d21d3bad6f1dc9f19e4c12431bbbdf56cbf7eaca1c85e6877397b0f76e7a9d83aedb2462c91755eee648da8417d2b8b7a9435603960e01a1a5690c8c482c878c243a7cf8f3a05a2c30696231a638c31c61863a46f4232799cefc06d44dcd76a135f4e66e8133f421f28fbe4668792b5012b4ca40fec3b1dbeb0bce83ad34e64a0c4e7670d45a69a9d551383cb87401b4739379e1d840cf8a2358658d64927e7cd8f31c608bdd8d92775d239e99c4e66fa9c73ce39a70de2b483edc269872fa7581503a6afe1573a4f872fa7214e3d7068d8f39344fcdb867b3ffd470253fe0612884e6ffe6cf0726af5d9e1cbc946f77e627082d1bd1f3070aa97355ecc4c89593760943855229e6449420291129254d8617358e1b2e0ca8d7ae6ca50858a63691061e34c91282b864b967b14a5d5042b728700a97060d8a2e3167d56ca8a0c3b6585846ba54d8d2090ec706b1803c3161ba6985142e5062b4a96870c6b58b85028581caa1059a22a2e7c1451a7d2dc2b5296894c6dd3c5a8ca3581090e4bd6480d178619507059352adc18546a6ca162829d317597a801e2831d93c37de1cbad726506273d90d8d610db828fcbe3851f38ce4c29ba4a534eb0435a906488da821f6c0c65ae92305706161750ec100e503678f9f1e2719d72d8afa52425c68d22a585106c6a1a205ee830c413102dd6871418afabc5482c88bd11837581054b4617499419294429c13eb9b937a079c2430ca84b840b0d54ca2cf971c47ea1c1b200a98e692196c20950685436505edc296fee1721ec911e96c0ae0b5e88b0628534c1c2f48390a81e55ca05eb3ab2e1898d9be4098c1b048e85b2a60633b54cac05989be4d4e4092c0918221647920a3b8856e0e2e4c615e364c88a8963b51071bf33954c940d23c6be90658828f748533553a40601e432c17003cf3a9ef0fc59a32633ac0e4d5cdc2c6fea17354b6676286382189b468b7532e5de58b2c2920f422e0d1fd5cd8e38392c91cfe66032e30d131735ea4dcd41cd8561064d19eb8318bb434b0b5396dc1296ea9310383e9c769c90c3fef0591296ccb82d96b8a83bbcb141a8b92c98b93bca14116391b4344da93c2cb12d580afc592cfe946bbfa2d9df57697b4b1fddb3ceb39f9f473ebe9dad6e5c95d7e73bc639ff0de39c6f18e77c4749a29744de1c9244bfadb4adadf888aefdeaf14a7b55277736de776cc7766cc756f18a01d3d413d0e10b8c51d7ab6c3921ef3efd117aac5a57ebaafe4abbd8a33df6fc26a486cae67e6db5d2562bed4d4c2dfb159c907ed8a3b6ea346d6bbfb35527c2ec2b6f842e1443d0afbd09b9daaf75bbd3b8b6d2b44ea5f24ec0c2e37d0665f2e76b0e775e2fba364c296152ca28b794dc36c9925376acadd2f6de5b4a2959acbf40b23695d4f68e6d3ce330a79df1f59cf9cebff7de873d725a07f4c678f3083dc2f8f9be8979e7534ea83eecf1de4befd31941a0f9b3f572d41fd0e1ab4b941758f6e2e40529e7fcf9578f41c62083219ef6544321743b2f665bbbdaef7befd5b4577150fa689db759af62751eef563a2a6d5f9d751e8b8d63364afdeea80ddb513b6a85b9aac50c8a479fbbd8e24afef2dedc795c074a12b9f3767ac624f20ea7c36d2ab6cebbee72abdc799248b56d9268db766cc7766cc794b8bc5134ecf1a6ab4b38df462a37a65848841574fc7376ac61dd5b213dda57482fcee712d521d0e18b8b52972d5d92ba9e1afe2e3a3a023a7c7159d3b5dc76efdccf865efb3c24f1abba216fefbd72e5bcc4f839e7edce1fca20d66f0e9360759e4a753b9dbdd6a9d8fd6a141e0b217de967f9e3c49d50fcfb56f73abbe9e2f292a08a4c445daf464820edaf8410c2232109372cdaf289a6a56f3dcb792ab66ea1eab59652caa30db5942be45ed915743fef3cd979184bfcfb3dbaa9ed78f6e7cf28b5526a1a0ad5d36eab5674a53f5b451939e7c8d435de9b831d63bc6517655c1d6540bc37cd97f513b3ba9f2464c4121abeefed7ea3f6dadcaff1be5bcf1c89ba0d22939a91de51b5850e09345d12e8f2309ad288de30cd09693867adb5ce764c6a99e91dd5a356bb5af9a6556c1b8ddeb02da5a3ee5bbda3e2c7ce8b51b362bcd249568e77ac6a6dc376d48eeaf7e7cce4e5546a92a05fdf7a3a1ecd2495a23954aa53d5a6529a51d75a6bbd631b36b17c16c7b949a34b67493487b2a6f14d6fdb8ef190445a4a29a5de22afaff9b66351839cafd174729a41d8494ba27ef57b2ab6ab336da9a66d3bb663f7de1dd5e38ed5160000b3779186291545230994fd6ae84e9973ce4258e72ce5cdfb76aace931ad6ef3cfa3c55e563fd4386fa2996889fe9a82b354c43c9ced3b06efffed4bdac2c598f3b0d25f39cfa29670dd3b09eedaf3be33f8f661075cd7a5f27675f9df9d43573a8abcfd7501a2adb455d4b2ca5ccaf9f34cd65f7591ce7269545790acb1753386ba8782481e6d4d454ee34541c92457b1e79f3284ff5f8daabac56a7baa7024ef5fc2ab935542c113514d5b07e73ce5943450d2c55da2173637e829293260856a8400265cf730832377ffee5ac53f41261936b9da5949c90065752decff9ca55279457df2396907f71cc71af76e7c97e6bad55aaa8f5d62a3ba1fcdad7ccd6bfb6fecd4656f26326a6e4702c91659ff9ab86227bdcf1a48859769d02cbae5f87a0b3da698f5a8ad8a245c74d3d4b811f771406f7f0be1c84190f0d257ec2efc3fe3d3ed25a6933ff7b317e3db51338c79efb82dcfafc4d3b4e8419e7679290ef83ffcca07f1c84cbaf1dec389cb3098eae2fed7b527642d262250e218467b66ddbb6a6268d2b842bfa7c9c84cb1e3756b1bbec324a1f28a412485ea8a10e5f63da740574f81a33a5e3fdd4bfc3171453d773d78753ab1fdc0bc28d1327ce54975bc289f761d55258bce989979c0c5937c2e6e0077eab7580535889dfe2d87952c82e1f0523f058c01e82b55fbff6da41977602cf6d6246a8e956b131775f73573fa4da09ad3b1efdd9531efd90476f5d9fdb0f95d4591dbea08eba9e1b27e13e12a85b1fe12da0cb13f9a38a7268d3a376225aad038c84536d37d450e80e73deee18630ef0c6633f7b1ac2ee78ecd78e1f7ec67994c7761fd48e3b082db431708867783d45bd9e64c849392923e51e4a34dfc9a2e630ec396317380edaf2334e7ed434dc91c3f425fecaf70b7cfe7dfa3d9bcbb60bdcfb4ebf4702e5a7ef2381f0533146c4286d400373536d03b0d7c7f5df462855754aa9ba1fe6871e26aad3dff4379a8112c76f515c19a56ac67e1f7674ffc0f49cf3e78ab288de8a6eedf5846aa762773acfe82d6f0b0ee8ecf0294f7e2198dfee15175f8e45b71ce5f0eeb4e326170d95a9de8454bdd62a0e05ecaafd50e300a5afea549da75f7e55a954aab7aab7af82cfa29b9051e3368b9e39155bc7dd8e4dc8b1d051bac94918e3d873c7e301ecf951c09e3b9eec85ba0c94384f8afcf473473fab9cb76fc6d987da65d12fa762776b6374033b8d54d26e47d51d5525d1e7bf99c3dcedbc5d3b6fa7d34e6fd88e4da63e87489ff93807973b96c3e5e281d424c53524816097c1101e87a00a344cc3a4cfbd1ae6a274ba7aa57148eba8c14bced34f9dbea59342450da8d151af2f8ba44fedfa5c416762d658ed0a5cbe1787e21091042ac2d4656fc08c8e74f4d86dfc35318142c569cb170a5568e24dbc89a3d0c4040a15a72d5f24909e5fe697f99484a48494a48463671bf13d3e4a5fae3b0a07c70ff9ce36e27b7c50e071671bf13d3e3bb6a5b81312dff9a42626bc69c764136f9a7fbf297badb3a66d4444caf0b663302243b1a8c72ec66e87f3d67e1dffc66e733885a83449ccc7986f1bec465c287fd551290e8946229304b24c221409a4a7916964325d1d3f6a1fd09e230fe9e3923e481149027911b7728df68f387ed8bdcd65c4e388eff15940fcddbdd83d0d1535883aaadbd74225baa2ab33e9f3476071f539803e3f2a4920f8d282d4e7c7214ab9a32154a5a92495665074cd1af36759ee94228fae19343b0fcfb79c869a4dfb864b67a3d1d1d952554747e7374c474767c3747474ae0effd58a6bd4d6fc392cdee5e88ce8fc731ee7b0e8b6633bb66314b3f0a2c71b1dbebca0d1af75395c7bceb5e73787131aa16bd16a57cbaf5dcc2308f8335bb7f61acfc9e13939fc4d4caefd8a135271564ece73bee2bfd27272de8464a954cf73567ca5d9f738bf39fc572baed1ca591eee2c7e73540193aea8848b9a6f6ac8680600021263170000280c0a87c4b2284962100ffc0114800c6eaa3e5c42925065712005610c04410c82300c83208001002180106390219e7b12285989061505bbf42a524ffccab071422f8041f131fb41f4ea57c88942580a91d21206dfd5957c35a087cace3608d4af53f631e923629cf242bd6b238b34e904b0ce5b7f01a4f816031b351aac327b018fb6e08de38248ec3c0406579836e40df680f21543d19647dca8c1709e25d2d2e42223b002236802cc048eda398371100d96029b142d45552b44d513346ca8e30419721618688100e2d54cb00e3b6e9282cb298871f17224332117c69fe52952fe1b85d9ae43eec032b537537551b0903e41287062332d29d0ba2baa6a3f39c895732053a45a408ca04cc99e106cb320380fbfd17a8a7e306cc4011c7c5f4b210706b847d4b28608e61da6c0932a7ba02383eee82cb8e40bd71dfbc57ece02b6a45a909dae7f4883497ee5eb436ba06fb5b546009cb726e1bc5c89fe6c80ff25cbf94fa41454aac0bafa08a913962517afb442b59dd5ed0a99e8017a90a43f83e9afc886b1d7f8079f3dc592d22052a7ddf6c40140b0d42ba52b1c9e048e8362aa53c99aa07f45516c06e0cf9f2690b77dfd36d63d03e3cca2a721bec8c19d0228ec2e10829aac8b1405831afa231d419579ef4ac00bfdade159f3d0efd14ceba8280e363e965f39efcd065099f47954557afb14a5faae48d512b934522c405f60f06b4b096254871cbb5cac52baba6fd501e45310654c026fb9cd18109988ced438ad539f0b139629e627598d09441e38c8402e25cd909a437ff7bed280415d27d9089243b2b78c7ba06b7c7efe132664d2e6c06e8f985a165f394c045ac2ae8f0eecae05e13e2cdb3e988e7323852480c5fed4e68995bd69addd322b905fd46cc52afea52bcff65077c51bb8b7689cbd01447aaa1acfb753eb39a73dfee37e857684450a649bc244ccd84972ad63c19a925126af4d9415062ef4b201a9a97dd2e82f60eb319f71ee148742c8de8804d711ab217dc0ae1e09b79a24e16700be7e6457fb8ea0b59b5cdcba1ca07fcaae7c3580b324954192cbf63918b35a1be051838fc7a5cf816d2d3919383f194f3a70b437ffc2b827dc5ed0f73fce51379a3478b9be8cec21b7db064eec248d1d3c6ebec5b3454c7e8a638f52192201e70624712214a8517ab964c97c2925b8d20d8bb29a1af5e9b72a2398de0511876c6d453dad12a739f4878845cb17298466153c89b67e19e1f0031141a0c5a614fc19a72e4982b104f9dd0ca88750acec475a4ed8ae5f173d9852e2e6cc14114f76667149c0c1922f9b89b6f1690cbc52026c51fab2e231791abfe1364a9d1703db4d3d54ee868a487911be2de2b639eae8d9d2509dc853244d8a36d8e991292349b101136531b5a890c115872e508b048e2c652afbdabd055e2bd9e38ffeb16f0faada31a32bb2461f7623713fd2d18e0890920fe4b86636bce3053b147047be03bfb3529d72c5e5802e0204454be567f52fcfd73f4b9d52d191af71f7e44b740c1da1147d5298ffb3fa9a4652106f7fc200a56f16315ec2e512fb65b0ca402976666e1a09e065c07957871234dc00a8b73131cb9ea2c6ea911be9da639322c56a1fef3dd319152a81513ba9d7db4a096c4c9f1b9582ee01ca68de7f274c49598b2592fed116b8f4b26f0403734cd12cb4c5de65e8f1ba23ccc247b2058693a204c72ed78c5ccb124d2edb8493b71576b3bc9b2e165ce5449996e816f38be4a2ce4cb41969253a7850498d55d2251106d16cf359e3489abbb41597c40144ebbd46d2377c070c7135ebe492ffb985c4162763c21dea30a5ab08c8158ec2a03acee282df7511fa57ab1b9d9ef4942eeddbd80d92ef0ed341ec4f4cd0e73801824ac66a78e8e4454a8f7a7bdb7f10edf0589c70342278a66e72a7824058147320c3347881e748d8f6752101d7cbfc429a17f18be2bcd9f6a68d63bd8e323d12846ce5975e32e1334ae166e5c469c20769f21fd061015a5c6a3eb40387fef6d6632248b3daa0572d09a8479f3900a037e93a976d5a594096cc59ba950c3742f9a3dbdc2f69a65a0920bf3701580df063a4b8f21084e1f33fd4ac43110a498884761d376b4e5c63046106a9acdb857c31dd66d8923f189cc33bdbd3004074818d10e7980f6056e9a8895fe77bcfb8280a49bdb9070ea3d9a3af6f5f9ec5371f8f06fccce7f871141478448b44a8e36cb3d6db05181dd8a2794891e1029c7029ad671fb96cd3d50e690a0a4a88dacc32fa3b62825e302f65cc46387877117d1c1e0e79983c5153b82ac19c7571d527ad327204b76ee2f86e769e4d505f58a390d26ec42ba120b25001084303ea5aed2ffff6ca1981fc87bb847a8d005c42bac986e49cd9b637c73097021b1013f16566162967fd72fd9e57ff1150229e2a43f64aac838ac38cc276a86ab93e876324de5543403f7d0a8f7c8f75d20206c00fab05063d9d7d39135b3e6b3e9056543e58a08ef323f4a3fe72fee3b31b4e3e2bc567eb5f2cb0b2b6183a1d85f632008dccc3246c61919826e10675b4341898dfc49f4ba208786ef151d01f82abd2777e70631310b439bc71bd88e08b562451f6c13ad40c0c30c818959500701185f5487c856bc90a1a18cbf306f67f60de17f186b07dbbb02ec6bccedf91219e0756470ac1f42be1ffc999362cfafb21ed2c2968809468d316c612baf839c2f7c3f96f305a2e92ceb9e17d75be738f641608099517e481214e1b78e6977743c8974b94efd6c2bbd1cfc333b891694a0de3006aae9c5aa2b72561b269f33c0513a4ccd3bfd188cf69ba98caf9e8af7ab279a76d8ada680a440eb0cfecef94e105918882f59205d1c8c805825ad4a9c30e13bcb5cccad949ebbb605232e39140cded5843c395edd6e1097019807e8079fc79f5c34f247719512da4a5b3571b58d6f18bd5c351214db35de8ea3b67df0fde39b2f4d231fb912cf13ec7337544453f8b591dffa5db801340cc3948f456f740fcb19ecda00a412502a18ed7cd7fe7b866d2a25514f9be2482ef115d2e21ce96b640f7e9a5aa3d3affc44a1418858f65431158c1ea9568b6385a4e220248a4908f0b3645d5e3be1eff1cca793bdc2c9750093dc66bbdb94215f9635b507bc40b7b2819e7e980d9ce23ea910ead898bc62caff1b1826bbfe2ce9c05ef3af21e170fbdc531a4ae23715b071156f55832c1573de93b8530763c5d6efca80b8605a84c2c646eee8896322edf47f634035016c2e2657c11cc623112f60cbca60433ee5b4fe73b69dd64c5b8ddc2d865b194d82b2e4b6699c488caf6592c89228e0254a97d5235da22c752f6f5ec2f82c1cfff3a61ec180611ee5eb6bbc848c185e43ee1d0e5f93adb9e8d22793a353e13396236f9b55d7a822aa4f35cc4fe3c8e60a61220a9bc42ba7335503661e28fba1cdcc5cea3410881196f7705b84d8f50fd09efa5024ba82bb415be9bb3227c09ce1962f3501fd15b9b36a244154443b59c4f1c27fea4cc7e089a5f126476d5610b78316be5c8dceff1db8a25c9f33e2608181d0afd407b0d987211a4c8e28da6cfcd5221b035d6d71f88bebb36891dd84885bc75124140356cac656dcd8caa024b84ff8165b8f9c6a2c3818121612cc690631739fee5c18e1b05611c2bac91ee1c9b7f5d3e6332169fd6e3f2c84589b08071db8944460142667b47fe71ba0df5dd3d7687d4af463978018e47c083f352981c2a86dfc3899f982e1f23180c343487a21296c82b06d19ae2fa4794a51b7a8f5dd33f042970f955d609e6135fd93568c2f229850b97446721a79b9d3e6be7bca61d3e12ca5f68af2e4ce716438f61d1d5ef55e02f030485e598ddc21d2847a11159c042c5783e8c0be10f9b0707f5044e7197c0140e167f2b2bb8939c6da83b570aed6c3f3a6e765b60a645f251dc9c4f6195339fb9e3999ec0e384cf6391e53883e5cc08d34ae58db4a0982ced47f77112119ceca8bd38e65042d17133ecff691cec16dcadfc16f9a0fde0dd015060f3b1fcf5273701ff70b1b2487a496dbfd8d0f245cfc909181bea33aa8de057d789db5f2e5b807aac8c39de7fa5d679bb1d628699cf460801b8b6669941812a2d40932c863166625e0b2193c5a0058786e8d4889a6998b03ec721bf088f6fbf775b8bebbe8b4c3cb7615e176f14c1c415e5c33a5b60db46937f9d18f6ec146c054cf801d19a4081a93fc12c40675273d1d5dcc9edbf003030ccebecf46ad296ec9ed5872b9f75540330ac76d06810c7d9075f16247dfb12a9f812b2ab6e80ef9deaa2886b0f6250f302280bb3d723b937e952ab9e39b196242178a6b85590ebc58b78946e1ec9ae1b8d28387c3e6fcebc7d82c5453e46f00992d3da5dfc3b2b60e5507058aadc114aee88f436404c83e447a1391fc62ece3e738f277a906ace77c2f3b8c0b1282349c0200121b4f91af0ad8711b42df1c8fe04c71ab8f1856e3a68b9a3f1f4f2f246157312698ca91eb3357cf3bd475dc736ef1ebadaea30c5cd21add8456b732ae701fa56ca1fc0e9833386df92c52ef2268aaf62f9e5fc7c80be053f478914bc4f0c4a564a549ac72783b785dd0c96a852fb7b337dff1af8ac34a30f42c4e29fb5333bb488c24a98bf7a375c06866cd722e7b319d83ac6996d7e64c00d7abb808d98069381ad45bbc940d5deb2cd38b243aff4f44e06a1337b2bcea17606df621e91afb89ad78882813f158a856dade3c3598b37839078cd4492fd97df384ca8578e7901147ec689a552d7bea48d4fc0384825a2f1861224ca6ac400928a985d69e88e1039977920d81cdc332134d4a23a779b15c26b2e1524f8968353a2857e4240805d5990f042c0ac72828e1a62649b3effe9ae27487f18b48964d21050514d7dc4945646fa3d075f64901719752252f70acc0582d447288922c6f1796773c4746814de5999dcd63e3ec73b9f7e0091b4bf4e620a4f801bbf89c22d38a9f3927852d7850e4da72ddee2d453cf940f1032471a3bb34701fb9e343e1d996d1dbb7d27c7f51f26c4e96c7bc89b7ad0c85cf4a37e45cfa3ba7c10306364251f68eae030bffa6f5894d689b18570ff5ab356433e14b7a46fb573349eadccef529bb6c67f55e58c1762ed6c847d64b5d91124a74d0bd79a71c9f14161576cf6e8c0a8aff3bfc5bb80859d0c14a13a3289478f9f9151634025ee203c77da520574aa464fdb01de988b0fa2b5c54dbf78fe59cade7d20e649aacb0872c28e986c8437362d2467b7b6ddadad81e31651044962f96957d73496fc7f9ae35f6097496263e68589fef7aef3b796a7fad04909e621c2070c7f80f581425f54cb3edeeb1e0bc961d84abb4dac1f08b3bc099fff8de6ebfcb898699f891d5abc5cc4b8cf7c7634ebe5aa30b44793c123e30c614f037b082e747a6e9075ba7aab71e0edbafaca6d25a2a547597b12ddb0c1c07fd409e83fab13a9205e844b0e87012ca7638c8ec6ecd76796bf692ec240c2ce19b6f3bf5a0c69506fcdae18aac1a76c8b669ca3abc43785cb4259e83c8bdb52303a29380a708a14dd391666515f32b65c68f23a91c9fc51067ff88ba8b155d9b72d108c03023b7dbb6a17e558f03d0e328766e0263896953f0e825e356f4c58f0d1e912cb6f2f7022bf535543a9ab2bf4cd3d90103ee0042a53936025d20dc3ba23a1ff0a9dcafe11039eee0f7a626c48b4fcc0e0b92e579f9864523688d463fa306934b3996b8a02ef49112d5b81b2e971c3a48847323ad4920851c79cb4b0e80169ad5448ce4558a0916e547121810510ed0e206db320f318eaa94cade60999537d28117abcf165f80c38e05d015c6981421ad270bf5e14506fd90e0cb38d91a5fba838550d7f0e53db78d89737ddc21459bb68a1fb10150240c180d558e5876a365108e0b5380a4911750a06e3dddf2c1085ab01ddc5ed9bd80ab8984f0c034f1815de7f29218807a76e13d2627290025ff30a473e155ee4c183932c4506c04ec31d35016c15a9e321908e1637521640a3f59a0c85386ddb5c65cf297fb72404f00955036a9ce1cdab79fcd821f707ce6c22fc30875a307b204cc8e886e26a4387452694e1fd30ae90c7a81776952f4ce127e6e54d850a87abb3f9ef7e37a7c5e5e15ae1695d76d70c14e73b15b7570e0f3e871928fbbced0b11b4ae64ed249f9c7e0b94dd6d2acb43724a2f5accaa85d615a54f2066eee2657c9a10ef10145d074e6945eeadcf5db53b8c25d25d25b8f3c9ef0186d26c477df9b27a306732599a14406ec202ff63cf0653cb81b1d56d556c93f40d86381149fdf1e79a49582f8a0fc1399897142b0f91214e90908828049f645e7de5580cf685569c9475fdfee17f1465148f36754fe8f01649026902e616786659d5b70c6271e0eb5c59ecf1e266a256dcc6c11eebde91e0e72af53bf529ce83d43684e26c509cc1a1dfccfd2dc29efa726a541daf583573c8565f04460bbb2f8de6c0a915fae5674f9d082b654ce2a1421474a70ea084d44b4a1e250aaadb09ab39fe8a67a9f094abb653c09e457b62440d1faa9e7528e4f86c5e1ba3b1ee7a54275a071f2f424efa21608db5e4b22a4368da19d8efb4bb3abd0d055865992dd9bd6a27ab54ddff2893ba3082ddd5978919901ab251961bac96050f53a8ba042fb554cdb5416cca7b2ef1fd5c8c8a6267f5001292297a6b79877a0ba4120e485492eb0e21f87b02dc6a92bdcb56ef71afeb5c19721657a753ba7021a9e90a87710293847d215e54e2f04b3038f05a0d49b107b114546fd02f3ae9ba4cbed4deb3875b635dc26129f68b5541c494adea44b00187267b0fd0c9735815947d1059b7a061d2e3c49abce8ef25d780ebb5bc3b44ac192beff2b497750cfa1e8d62ca8458e7029105d176cb0aea24362e7dfc200a30326e1298b1b4c0b598acdfd859d3640539d36eb7ee1e1eaac9421060ff108486fbdc03260808a696d8401140ca51804f06885c508fb231f815b0acfb967e7383546c8fe8041dcc89671588d6626dbfabc87025513101d8a6cfa0f9e98597a06ce54771e1089cef20be2ba89d3718007a2ee898794eaecd5ff42d90c3e8c5313cecc040b9a6f5ff50bd43e7cc5cabfb2a90254057a557a159c4b28aec0569be68de25df16aa9ff960e317a413b2f9e4c17ceaaf41ecd9e49feb09592baad4effe2bcf2fc889cc243b13b9fab62dc6d40f9acfc35a6628e9bd37e6a7fb137abfc7171fec534bb7f980ff181c3f82f5538ba3d140c75e209d00bd0d6f0b62a95d17ea5b39193ca67ba8594ecc633dafb4cdae6dcdec0d6292da67ca0f655b99980e1c35b5f3134bd9203e5e1d7faf0bc0d5cb6e6f087f46472913bdd840d2fad7ae696df9a9b846a9720dfd629a18eb525e3d859e58a5029165f494e2fb00d5dabee9524fa6de3314125a49d374d24a1b896bf7ed338999ab745b0c0fb2ba080b0ebff10d1a393099f486c88461612896ec090cc736904e23d634da34dd12ac4b5a563e1df2aa1926058ea39d347a805de97926474ebd055ff46509dba7a027031f6a245e30e42d98624dee00bc7689bb25a10e27d6c1623d3c4e1b1a851480bf58e6730fa9e19fe7e9f6a51ab2852c1365fef5e1fd8dd6b309ee5e9fab26d68e8937d4b45e1c77a58626f6f25d574d9d0e050bb667a24fae67222ad1e765d1b8e006678dbb04660b2d7a6193d0f6f6ea33caaeaf441fef11d878e1feaf05c78f70bb86190e0639c1ab3aa64c4c084840fd7b30d2c3831740c3318f0e0934170f0e915a7915c9a2c159b28ce2e2d2d86e6f2d4408b272edbe4d56911993946165d64f7c081440636bd14cc770afe339e4d8acf4d8089e788e94fab001bee410f86ec80f87b8530d864e6a4bfddab618b59f03daae368d783c9e042c9c4f7d3740acadf9c775c782c92a11c6a5e4f3189de621f4efcb0104adfce065af74965aa2ffeead8b0f0cc23403becdaeb06fb72a15f02d72e0601251f4f90efe0264a8739d156fc5f090ada03e624b556b858a2bd77e437268867590b33c04eeea7c2f0b7f4eab650cb467e0660a2b3cd2a1ee5b486d6bb124caf1f245b27b27c600113743b1715efeb72b2f6c2803a1fb0bb932544c8fd67d209261fc84f0f6df66e06a615084c269313e0e0c0a61d743dcf8239e921a6b0f975d250f0c1a060acecf849f46dc8d6387192461fb83305eb4de2505ca67b0f130c53ebd04e013b052b70e1d6f80651ac5b0c0291067b540949203f798dc1d478169f657d7eb1bc177af49cc3a35a14a0fd366b692c7b9894b639fe22e2a5fe9a970570a17018ca1fbfa2ea6fdbce313847edc41381c4be4f979e7d6a5bfbefce63db63f10e30a23e0c73b1a9061a7f06e5b8f254d3f7e9051563bef0dc2ce32efd08c4736889925f82b215b1ff2cef9626919562f6cd90a5c28f34ebe8394c134f9a1c8f35195cc3b1aa5bc41c41d88b637089af2888602ae972a751868940625a3ec39d7c3933f0a99f18ca03fa168f59984f82acc4bc9fd9d366a6785b591b7a265d18dfefb5cd34323f1b54e0a0c4eca6a61d789e95c0a816c3191817bfeeaef73cf1ff6838138a22bf23c8b9b9fb9f95a7a27986f43f43b6e087e101755c7973749156020962581cd75bc33e07f673b1bc55371b139389e27c2ca31a6f6aa4d275a404178f30efb77f9415de105989bedb879c7c56f80ac5af07e7604836af78ddb1140bb143c2d0dd662223a06b95e43c41b17cd73e2ccd1ac3c6d0616ed0b4ed3ab6bbe207c441b9dd1cf3c36fb0d0a0dfbfd5214bd13da7862193be2f3a546537239453a80f2bd36d6da0adbf4ce2af086128a7052d23b3179f3204f5fcc6decbf62585b2480428f85fb3610e23869a89f88e4a8e4fa2a070c1da0d433090326bf6cda47c74c3785e624be7f6c5d88d51cab4e73988603a916d0e36fc439e1fa14e27a6980616d4e0f80fcebd48df93b26225b21641deb76f1884139037c067e155af355987d0f489192a704fbe03a82174555bdcb64bdd9d1eb963298b83902440086596f67381c96618d67871a8eca21ae62028e384bc311e5a4a3511761ddb4c5dadf27c14f608d89e28940626a0df67a85c8bf5c66cd834c5701e45af3746367031cdb69cc9b97d5d43c4ce67cd74ccd83ac2634f9332648199e7d56c599734ec1554cda40a7e2584371f6123b782ac90439f52460c5012325ff74a2b6c74f297a04582a19a756179e20de9348e4faf6589a3cd670a5468f30b19553be117ccb7fe32943cba3c7e108fcee4cf4296af09e10076743d21ef253978e8e2899609ce949569b7b2dd7b059d4937894d66689b3e05773960bcf6b29547d69924eb9aba1c787f87420ae1cfe9c047cd0a86c7e99f3a2dce783888b8e44c2f746d3a407026ac3f946b060fb174bfcd0c19960214b5c85112bac95c41f391faa72bf90bdc35ddce8a943e0450572bceffb2d3a84aadd1b137148a220a47e3ab0e8ab913e8dc071914541c3c0cb93da0678aa8423d557cf144f23c8c0233baa84e3642b3a748f654d8688f6690441901e499f264b1eefa2f9cc8dc45e85b69bfa38f004d2a7a9762eac54204f41a7d19d13b25802d24d0a9948a1a5b5dae39ab7a0188214801a98c2f45685870b8e43a7dadc8d1c32f8bf7e4e1355e6e9cef20d7acc4871fae953e4f42a99c077e6d846ae117e4918ee8c4871bcb12cec36d9b12d470d4f998009a754d30be60fc35a9174e18185bdf1967a98e490b415d0c9c791fecc99241bc6e4729683b5cc591c316239bb91029cd5dc31a2c0661dcd952fc537bedba7161347d83102befd36e1bd57e6fde339c3094020bfa18f3a326294f2c272f34a4062d5e008cd59ef7aea58f8a8394c2aa82226ac78bd019872126b5898e9a39481cdb622a6a14867927b6cf8f34bbd283cdf7e6dc2a04a5f2c92a545f4f2d977f30860eeb814cf72f1755d4bc5af94522eefe3b730c03d782438e4121d0b6b88fe5d1c99c4388ba2a9ce98d24129ac007d757a07fe5d49095cd9cfe5a21ae80af8220696d08769ca37150debe585b77de2a016532a4d2a140e6655dfaf23a2433bca41ef460180734b82a916e082d6e9b3bc2228fafa291b779bdcbe30b5e2b8d901d5249387b6fe2f5ad61d7d21c57306a4360bf3659fd426a22032b7bea299d3ef25340e1c076cebe9d64852c70026c2e3fa259fceca5fd8f2244d3b5a58dfb0b5ff6422b4f69245e1cd6fb97932883500260eb2d68f296b7a20c51215d7648b02f9bf84482320d08e793ce47d47d60171165805cd95515cc9906d2e9f5c0c9485949637da7bc3647b8f7eeaea06122b9e07904bb6df1d1f17412c3ef78976426b54e1040ac3a82f1e4f6caf8f9327c9893ca533167769f7e240e97296f99329238b84ec141e2a7f328494da066205f3255044e3029318d5e847cb4c81cf7f790aad5a7ae4ed28d2ccd5f25cccbee53c707d61c427e30d347ceb90acec50f65d61a6a2f890cf250aa64941464e14ec2366126f25142a266d14a055b8f6242e9d3e7da85a711111b6422473ad49fa98e4f86fa3bced385ad64b2e07c342946b7d784fe49819830a8c5be1c73d39199d1761c46b3bbcc75cf577c7fc9069d97ace6fdc979e33e3c5660fd70a2f9a278ecbdce5ae2badba3dbcee236eb56a523ce1062bafd9af739f3409c9a3b8d973d5ab30fe941fd8b480c86da1611a9857faf14dc76450146a2e34ff44221e4dce5cf46ff3b16c35b9898a9b23357eb11f39aa128b8808a9f872c32bdfc35b355a740ef920a07cb650edc618fed4e819fcf4902ddf231deff3baf3e2d005426a3c6933a65633b6ca17b4b059260ac8feb3679d400af5af73880b1a1a68f69a170cc890c149eb2996b462f0cbec85149498d0ec39b9c11127025d5c9c7c4628f828e5e8ed3042e9e0e56e5e184c460ec5d99e5305e4095f5eb2ba28c565806dba73142fc46352e6f2d0898b0ec5fe2aae431a180a728c2bcb0fe2904757f9c9d4c8a4e4e3bc326e28e440e33a64897f8650afefa86ee51084eedc1f11d5022bd61f3bdc0595a1f0edcf765c4f4d1d0fafa79a9a4a6cb09ad7a46c8e886e2ead591c7147c16b7bec0cbc30b59675c416c6090b7fb043292a833453b0bd4a0d9bb02e1fdb7dc0d4e462d173a722de011b2e9be966da638d6596fb3f247a2a0ba37e63463668994e2fee5c4e86f263ee632143260703a91b71d1497c01abfe73829a5198acb5351d245247038683f9838d149b315a615904fb3862316f7d8b9eac09d132d721c564911dbaf375c6c9c271ff7cfc42aa056ce8c2f0c4a8612d96fa46471bad3c7e1c4d7f9e44e2d0de736f31968186c92c1bbb2a080878e0b89e603530cf6187f1614783962eee9eb1e2ca3a4e287ca8c6ab2398880841d8d5ba065624038d87b9647b06a4be2868158c3c1466815e6ae82bb3b5ad461289629de1b2db17b9a499894cd6039f0930543f999096629b5a4263c0a601f9609077bd8bcd0a4b83c037a7a32ab084c68085439932f36ad1f4a45a016034b9f9ef193bf53289ca7681a02e71f6d151a8283650f5db6e4cab8659a8a82fc9ae127dcd64940313e3b9307685aa8bd49433304020ebe494efaa3e7dc44fa3520b10c7b9034e8309899bfec0ee83780edce770b854f45192c390ed701855f450a7b4a9cc452227b4e5857a447021664762c42ce19abde150adbf3e7ecadf593253d494a4d77b0067e4486c361be7331d891ef64ed1b1ac3030a64038a36da0a8913f39f3e3a7f16838b65fdc9b4aa634f25f21db90e0c8b70ef4cfd5f7f349eea38e844ef17bf5dc17793b70172a61a134517a36499326bc70152e2ebc18205d2a1ffe41aec2c4851703189fac2ca8c55b852fe34441251a64c7f21ad073d4506520b651e35a47eeef3e449b59207650b51a05d77cf7481aaff869549fdd2a4e24a1bc62cbd5b7630562946e5be0ae376631f3245c660764264ddc2985c177edc27d8fb43a4896b827c3c78823a30d77d0bc49457e590bbcf27948a8d72810d46504a8da90fe871804eec5a1295b3e572f97e2c31fe9fe3185852ad02aaa2dc04e3f111928342501ec9edfce65da23dc7e3cccf67c9f2e57cbd57901766dcd122a42c91b601ee7fc76e256f9e731e4f5541d83b778add1d1e7b7bb281a2a5e2443e76c6750de1f421a08628fcc34704cc650ded92c0f9ec53fb9da85ea49af64198f0c8b9c82bff6ca593217860836bd65f139c2074dd9c9b4140705951ca03f1e42cc862b6eacf24d1a82d08fa46405a394d50337aaf46910f4bcaa2632e79ca138e32c9f1d85a705ed96688147baca3c963d1bd4207efe9780d17d1aa1360c1a8acf853633b5a3fd880bcbebb72d911f69d5b1a3488100864cc59680ee77e1debf39e179d2a47d0dd9e60b0469e0fd7ba6bc4f50be18c4309011af8c21db2bc4410255f34b5fed1adc0fa4eb11fd62c1f5dc4a333d3bc7b4de6014e3e88a3f40a8f4afc110f2f5cbc8568342210cb0f61f9e972a2bb2e4c947b098721ad0ee6c49cac74b4c70e2245729aa2fcf8e7256cb6b7ef67b3194f67314eeb298239fa193e7703431279767fae8399a210818d30694293005300adf80fdc2318a2919195237bfad27d1836491ceef42962a7b4bc6680f56b8a01f77ee8c1a90301ff02232534d1ccbbcbc3c92cb2c650240d93fffafd94896c7eb1032fbf350921195bf06abb05f98aca9f5d8067a6fd00ec6463a355e81087336af0cfe12287396091ca8a4796245b03aa6cf94d22ce59bc2c7cd2eedf10d8bd95ac03b2295a242cc75e5757f96934b744267e53457275cae5cf58f90e8031a37df20d8330d6f42d8e8a581b973f4e240a344d70f06c5d1a60801add7ed2e737a717a77b7a050526a2d32c62e4805a38325e87f71b937bb9fecb981c819a010ef6f11743a75e6a72bdc9bca815ba41f7e0fe549b56a22ec79186c515b1e1098004bdd162624bfa67a331e73981669c58e1e2816097a6aa81fac4fd1e7b00d20b167bfa4a16c637e7afe33cf01d99051eb2a36aab6690dd4f3975e6135dc65f730ea8395415d152f31acad10f93cda52c40544a177239cc18e6681af5ae616a75a1b237c43ec838f76b1f8b8cdb518f1713a2a22825af8501b50c45f0856c42847205ffae3f0ed82fbb3757c8dc070f9c8ab53abf991707408fa8828887445b0e8f8981ba511548cfaa836ce425ca03e876f2c747f34365e227cc3faf9d2b80171c1fd9c9d64047444bf225a707d4e6e3244474758f1fa5c62bba87d405c23a23b2230f61fa23816403ecd6f17ba4fdf9d15223ff56c17cb8fdd8d441c0be21fc11e4211a15023b0308b91f28c66fe0904d778607d1e25c20e06d5e71965341ba1a7f1f37601f9d377ac8bc0507e8ed2b100fe3cbf5de83f67e330463ee47455287cead62e463f4e378a64e629e1edcd29d32759a3414c3d72ca89394af6e673621b20db2e223ece73bfd17ff0ae5d8c7e9c6e19b11c81168218013a426e112db81f3b392450a6c959cb75f8c9396af87c9c76c1f96c9d4584256216c2f2a15918d028595f8eaf81646f87e436dee4300c9f8e772c383ead6d17d64f0fba169c9fad534b4415569ffa6a178d0f215b509a4f688d21c4742330ec3fa2762c803ed66b17f61fd9b97d8e7edce9802e3ff78dc71017c63ee27194ef3f6e0dc41017623f7da78f5046a4441082e0e8088cf727d206ba88a0f41f7bb40b4b1f9bcb28a2c5f8a7795cd0fde77e2386100b22bf102cda9fb69bc5116c8d7df4387d8432223d441247000afdf975bbc07caa1d70842f885690cd8987200e842fa21dc432444243e1aa459a0b10af2196230243f7398a0b0afc791e770afd07efed62f4e38e2ee8f2e3b77621eaf370ac889096f243d11a18e2c2ff39adc3b8fc08daba416c05b1844045104428748415eecf27b70bfa27d4312238217a2fd102f589af7580680b618b116ba53f71ad13d1268432023d041723c002ea7355c38ad8f4270e45c5b89809087403bcd5cdb7db3b2bc1212f661c2322acf07d6c346bc4354232116afdfd681b5f202eac9fef8e11c10162178112822082a32330bc3f423a16f41f0b6d171a1f2138b5ea1f0b69179a1f213a2bea1fa18d19818e08b5741fa73aa0413edd6b17fb4fdd1b0b919f876d141118961f51b9a0c01f7da783c052048bf4a7e1da45ee07b51d86f573411754f747eb78856071f9f4ba31467423a48b6821ed036f6327a272d6c7dd89468c0f215fc45adb1fb46b17a29fa763450486d2a76a030e627c1041d99f1b4d24c4b888ff8876c41284a4a1a8b7d0f035c4c5be887fef0266dd18233fc86b17facf9d134388dde5098dcc2fafb6e344334614851815f10e4a369aeaa5b9f158555483afb1de6854c353986a8610c408858260f1fa20d9e811f588e8087e8968c1fdbcd90d41fae3b8b57284cb8a4fd5114888a07d8cea19c494a0dd789ee9f3765173f4f2bdb279da5290fb24d30e7b1792fdada4aa5dff89f154d2a0ca47e29a2f498ca0047a2e617cb4578d637c316eada3c472fb6e614ebbb07e4eb0b1e0fe6c6f65056144d0297b700c8e123f5a1b7f6f7d87f55a0de5e0dd4475699938fd07a8797684fd3e52be1394cd3fb67edc3eed37f8ffd7d510d52df22b727ed63bb660a63ad6af28df3db1047b41f94b12602db41bfa0ec6d224eb054bb18851614200f6238c58a91e290db6ba7e6295eb6b8efbef7a6af030ac4259df5c837577afd2bb3baee5fcb0501cd2d52bed735df50af3bace196d717d06a90504fe4d6e3b5515974ebac5fefaa0e474d50e375c91acf9046bcd1cff68366e9774ae785adfa914dc81696d7cdb4febb97ee8ddc9a03f20dcc010b1cfb61bbdf7e21e3e5d9e18578f832303b4af2d4f98cd2cbf1f61f3816c78bef2ff0a3d369b8492a4f3011fdefc44d98a54443b38229e97c63d947dcef200500af81f883ba464a2960df043638bf77fd3175c92f9c340e1a59a5185660cc284e261b1f3b53ab8a63e17ae00a39f09d16717f94b5e7d668556746e330c088eab2e1fe913c7078e32c6e0db53edc8a3d0b3a40a7bb2d5f418f23760b2835bac8e71eb878bfb2691399cbdfbbefb17fcdbadc8adbe50352f938a1a264c9bfcc8157b4d2e44eafa11f652fa6728a90c1a91f24a6cab701e0f50a127fd0abb2ce99d277c1365da65819b539beac30b05d63af0b32bc002ec0404faddb28b59505a19a5036d62ae53137757f5cf7a1da4f5b492c008255402581418215cd40f34590561612cbaf8dddc2b34d19ceca920f47cd678c72b13af283eb8ba0bd68baa6846fcd645de38241c69f2db2df7967bef2da59452a624036d08dd0877083eed23c4446449c1e2b1a4604109921364e7081cbbf18e11213b468c6c6c44c8100fb58f152c7c80a0852351bcf0bdf3b1e261e2d9d1bbc109673b1ec9383a1548082c3beb3011e623424d82fcfeb9faae1535a977e208660c2cf42851de05c14677efa84f74d1b6e22184511cc9fd47d98223b9dfde3f6de39c1fc392284bbc3b1265c81f7977a4899eaf3018f73c848b4479e7ece368b0cfbb1cba65b483a3c13bb817cf6a5284efc18d7db8171cb9a554ed4c94cc70f5850ac13a3a04eb7ee39c242c5bf8dc6f4ee70a58f0b9820bbec2dad92bae7408969dd3234d187977e40a507ec6bb234dd83cfc691207358927e730d12426422c75da03bb8303bbb50fcfb30dcfd63ecf50ba87e166bdcdb34bf6e15edcc06e941f4777cf40a8102c4f0c65c00e468f103ae721cf4588bc2bf2cea9663dcdc976db7d43cfa74b6df41cba7cfddac2154d122561492e58f8b113809df31f4d727e83b3681243e9cfdd483aacb18da45bf23b910a5574c7226a748995edf4bd18638c2f366bd613d5a344682ae5ab2fd26da829af4eb594d2b179bd3ae7f482e7d48f27a7842c5ea8943c16c8429d58ae6c48446d741b12fd8acd57748bb330b72cafb5662e43dd52cf9cf29a9f3e399669ee7257274cabf9e9b27c6a1b7c2b5a95e536fef1e84459c5a546a3ca53712c60dce9eeae79926b1274697e2925bc23e8ee9f47f85e7cef3d9a13a5c9bf7e16dbb817ec4d08014295586b739a04eb9ee5e833deb1b8ebde24c7d243c41863ecb6babb8775cbba6fabdb67443f2d6f6f67ebde886fb9cbb19cf268b5e65eba4b5f98cb4cbfa6634e69dea2aeb6ac8ad236172ff9879b0c24ee80e7260a41ef8e3891f2d06d942032f698ee5e0bb64deac13750d7247ecfe3bbf1d21cfb9cad92cab52de20a37d2db86b41c9a34e988000fddd4eb89d9c126d15b64721bd3952b9a149da8889366b860e9514767a742900a16a140b0d3e438e4b003157d9aee68f2e9d51d4d934f93534e3518f79482d40cdad447f441ab88dd2c6dd91c13299dc548ba2f54d097d0c121073aa94f3ad3a4e68109264b94d425748a10b18e10120448e50307081b9a0bccf0108125ece694f0b834b4f5655e6b047df2e9de1bf13dc8cc31c218d9868128d1a1040f0e4d6aaa8ad49c6f4ebf1b0f1a12d79ce235ab187d461e44f1ea8857a446d1a7ad66defbde8bcf88dd1c4f741d3c3cf4f6f012ef28ce3b8a334d6ae7418711f6390e17765db7e0ebd21ee0c3d6a1048fd5564a0597e8097a56c2bb2356c8f9aa2d1ebcf71e84d159db620e4dc2a149458c34a9fd0d612158901cfec138d6816852dff4b84036538108e868523fa7bc01d2736812d46644ffdebb076852ebc06e2c232454dca5f9ddd1f317764d9ab0330d47c8774569329ad495fee0dd8d878f48a8f8d3369a8777c892ae2f52082f7841e83322e8d05b45b3dd02fa125cebb59a047d04fdf9751fbc37a20efca3179a03fb7cc62ab1bc1e5ede7d81f75dab496eaa3ec5fa52c518237bbcce2fa7340f7d6a9b93f2f35558f3d09aac4a4342c559c55f7d9954ee01ba45bbd8c06ef4df7bef8ddee8b9f459e346ef5a1f7aa7430e4d723eba11fff9832f3bbc0c07956301040bdd5ff3819fe6c0cecb5dc47cce5a2f7fb4898d5e3948dd462d6b59d4e5d14514e5556318e630eeb13bb22e83f974ec4eb73e79cdd35c6e31edbab49aaf1ad5a81a8a504a59b230d9304d62a769a2f9e96eec92254f53333b7637eb0bf385938f46d42777d4e3b34f3ab99b981d3b669f11c5fac277e47ce4ee8df8ecec95d3a8114bf39b731a5dba72d78ee6f4792d4ab350b00468924b93a20cabe347df44314ebef90b0e3dc0a746d829baa0afc412e9742101a838674c2cdd423dba0cea3c49cdb10de581255518f24ecabb235072de6df46964122bddddcdf98ce87b244752925e8b5b95d4266ad117587ee7a3e9d447d39df7f4f8d2a71bb179f84dfa8c68d4a3be3762843da048ba1b0a148968014d126237fef1cf690facbc4fca69c82c42d43853d8b57b61e75c7d81ee6ea277d3f9a4b3e2790bc7f97cad03be6b1cbc92c1d24f5a216a52d7e077de36be38ef7a234aa1537d715e31cf39a5741e1dce1835f91c4e53a8bc35a971bff7d8bdab9fd64f72cf29e59453cef9a406ad263976f33dd9ef79939c4b275510244439420e129a2061c843b1a1e066fd4539a4dd92551cd557ca2baabe502e4d5deef2e0065dbab25cb561dd8dbaa5aeccafc969adb7ca6e745a6f505f6785a93ebdba2eaf9afb595fae8aad7a434d7a22e79856fdbaa24b5f94bb3ccba2ea0b75be611bdcc7c81ebdeb4b9c1aefc0b20fae11ca25e8e4cc2372684e0e8dd3742d28d18822449a34a48fc84981ddd888c73e7eb0116c84d52181cd6bef8e24a1c957d873f0b7be81154f9360103536bf354efb68d24d10bb7110fffc4d3e3988394d53add561dcd7eab17af41afd7259691bcd5757a5dcd5aae62b6d52075f0e54017d62dbf27e1b123d0b8e2a97a13c3a755de5ef6935516dc6fa694108bb452fa1722c36de61061a05e89b5f0eddb295c3ee5b3912377e03a65d5e4547e2724cf380df10032929a596c3b8b7eea8ba8ce5d3ad9a6f6db3be69ea373563fdd49acbbb6ab30dd54f0533501ebbd1520c9e7763deee82b2354d4e695d5f285bfd62cd6a30eead77c5e13db7f7b9b5d661dcdb3bba5cc6baf4cbba74eb358f6995bb0a53ddbaea8ce8abc9597379d434a50db13c27543c0f690e47a3a7213f35b182e54222db44344ee37ceb344ee338a99a8907fb49d80e217cef69e09f9477ab6919e3ab5e04e275ec0721ac2fb01bc78470c7ac61f7aee710f6cb2248a99a543c939029fc9886d8a07a0285f989cf1328df0c28f2d3a51f7972c44fa77c3aada065edf4ad9d5a1be593bf0a33afcc95a136289f77c617c9e05a267ff35953832f6a518ba865ad39ad79ef2643397579e409134f9d7a92e49f9b4e51f1a9a3e1e0d36ee9a17fe2a78e064dff049d834e3ae5ee0356a6292d0c63ba4bc855acc778348c56bcd1b3281ae85df1463746120cc362b03cef19b4ea32b4e86ef455a49850641775193fb9ab281a43c6c7b88426d2441955556137460cb6617229e3278661986377a389325e7ad562c4783f62ccc02a66207a47543f5f619745e2c7e26850985f16ada629059c525c992a85ab10a510f5cff3e45be531f265d14a464d8f6753c50e52e15bffc8fe61e7bb754f55d148e10cf9b2a8a489d4c5aeb84aa87ffa4724920c63a2581979e6d257f8d63d32acf0d1dde80c5706d195ef88afaaaaaa26a8429b9e42a3fcba00804eef267abf2e32005714ba9b0800d7bd162b57e5d270dd6b915d8b4d16b5a40c8f5b7439f550c9305c442259f956fdf2ad7ba89e97aec22ae59cb37f9e25ac91a155144102021b242050820404384884e0412284112442f8d0389077effe0725ef7e30f22e080fc2c843670f42c843df6a1c0d1e70d617579d76839f9dd33848ab0eecce67d561dead6604fde11d69d25993cc1cb52dfa88a33b490367ac3ab00e5bcd68c2973862c8ce9fac1507fb731188a27ca2289fe674ba6487997867d189ce48f9ac379e532eab8de9c27b47935b35fafb7b3a5320a84f9d6ea1ce497e4ef9f3c208a9cc746a635e78475fa3bf9f09939e1e263132e900931e0edcfc740ac474fa3c22e940d047972b72925368655a51817649b7bc14b506ebccbb4d954c867af4cc561bf4c24ba95ba37f7ad5eff2e6662d110b1602e0b0001d3317000227481115b15a1de8b1262ab25cb7c8509f6ed51b8cc4034068b5416dc886bcf03564f7e2a58301691add0709103cef90000104921f98784758fdcf370eee3b09234838a0e49ff34dfaf4a7c9e99c2351d2532e272af31c3ee76f92f451f427dff597d32c66ac0859345a74725ad9a8aeea95c6c2d250937af3ea95369ad5acacaeac1dfc5d7154f7f2ebd21cf5aa6d24caabaa6e11870cb54d4836b0e4ab6fb1f26a6a3decc07e3a0d9c778bfeaa0e75341dfa05eb1d4d3a791c4197ce020775a74f77decd7b80ee63840cef0efe9d294af71426de1d19439431e84c243646be82168c7146870870df7192385a7ce40ad33e9bb60d272d69e73b1dba37c938e5ab355abaa3b1419fd2e1447a799f0c7b1f315d62ec8e4545847dee64a64f23b0ec684c0e1dca489f95d4289fa4537763aa83f4c9725efa909fc81903cecf31d8bc7bea486c843c00de21b1b9797ecbb719278553e596f4a95973ced1f438494fdd9ab4a2267cd3e3019f999d3df246f39ecab0b38fa8471bf4ce399f3bdf28cd8444d81dd8b37bc12e7bc4e0f3530c3cef5e0c3bcf6940286dc8b25bae8dd89d4b863c79bdb0e7019f3a0dfc6889a81522eb6eecd5a7cbe397ab07e83cea64ddadea405d1e3c8a3e391ad4374a3ad42809e108fa74d824e8ce25846f8ea0bb6892ab3c4750b58fa2572ebac58901e7dd77df51bc2e34f01c638c32d17d52977d6f90de45990dfa70473748efee0e19eeeb22081a62b0f9db8407fc1dd83bf48da22233d39174ead3237b9c9c9aae0bca91f4fa8994254fe3dd11295382a64079172e9ae41c8d1ed89d7bf17c7b2e478f448306bea90496dfb984ce1fe9a34f796f903e4217ee85eb1d8401663a648da77c8d1afc7c47369cb3c3b82befab79587144779707bff4e76c4c1979655eb78de5539094873e253fbba4a873d54754454dd6a437a4bb6a55148c8bdb3d526cbe721ae5610d9a20ec1d4d5d6334513ee201dff90eecddb576b00ef4f2f057714077f7dd1aecb4faee68ba37483f9dbabc2e9ac4cef513da5ffbebc7ef9a5ad5d1883500439087fec030e4a13f99e79086a311fdedc05ef6837d23b30caae7e32504a47c748e62d3e4dba7255f5802a35e6d3c2bcc34dac1ef9c077cf61dd8f3ade474b7e7d063c5119d2f0f7e77dd16bd071bf67de8aa79faa96dd16978f27765aecca481771a6bb0da80b4eec0de07e75e6c93bb17dbab38de8553843c98073fa4776463faf37965a0a4e18f3bf877500c91a8a0cf20d0e917863c75092d76d049e7587a7483f4f0addf586698526077f0b7b3b868d2736fb7a20bdbb9f8e733b868890ec7bc1b432b426eb1d19707d750c4727d81dc42ba8bd546ddc13f7ddead7970bb4cbc3c1da85cb7ecf86137beee0b3ebe1d5eaa8027be60a313903e3186a09bdfac3f27a60db04c99029484277680a430fdd004f543b4f1c50a3f617842c40e12429c7882871e79a2e787c9c61e01e2019091279ef87142021c68020927b879c2092bfc3831c509293f4dbce0439f704209d5092970202259a901088c1003213cf0a4e786e8851b401d040103cb08eb0710644e04f9013a7482034340c8859f28d38f134350275c3ad10527a0fce62c5511288c99266e10052953863042083770179edd16f1002384c007064178b2851e708185850251caf2437f581c0b29a54cfb8b4d64c13a879076c15a8e86dca101e8903a1afcd02747833af4ea684cef875ef10e7e007c7b0f0e806f07c0b71be065a4cf7ba300dfde83d3797947360af0ed05f87637e5390aa856356147d46b9e6e81c8cbf0eec816747e64837af57ab75ad50a408f4e01e8916a153f66b6aa3faff5524eabc35aa3bf564f6e30ee6566a05300fa7b9546bd9296d6030d7ce75e488f9a0c7b81e7f9f9bdb0f3eef9be446fab5b9e7bee5d2e6d69d39fbfade6d92b68515abfa5f19477ddb26960036fa36daa3b62efc92b8d523bb8c6df1aef298d6a93666955f47872808585628185b5a000ca85162d5022063f34e1841260c03e4c50477c9c88e0881688f0d6bb235ae8c1119f2447b6d004ca052b093e5cf0c2089a00a507bc05daa3052df0e04536a40525c440adf098e5393102b502a582f3f8547cf406428d702ddc6fd86b01c7b5702fef165dd22a5815efbe27b0a9786e1848814700de871013767c5c16826fd887af103589f20c91c54204769b3183f44a5688c4423464824ed53e2054127a189b8818db07ec26a271ba054e8d85bb2c5834c99186b09bd3812c627fdc1a8b153c3f624f429ef325be9de7953c096137bd601af234b6e9c157d424e77e84dcfe19068208bbb110478158ddc2856e78e0d3449dc301e73c1a8d82dd9ca65bd883fe3929ecdc9da980a3b1837be1e2b91128449a08616289c825b104a02cb0a31b1196dc0d6c53723738c73baf091f8bc782125c4311bbe29b8a4b6fa50e7fe5ca642b93fb743719296ef58dbad1ba3299aff8ca8d8162abc9ae0ca53706c390d78a31e2c498df4dd4ac77855a3a5ea5434a9e27bdbab4304da39675ec3154f4ca082a57b91ed2e5ad6196cc31731adddaece2e831d24335368279a661ac0435f2152b21b9e7a96466253696a79b0c56a265748db2cfe5b3e212a8e425691d7ebac4cb225bf5e9d472ea912bcf9c536ead8a3f7aad38d34bade69a3459a7d762f6ecce589fb1fc7477ab5c6164d8e16757a6ba993563b1bc7569fa3bbecc7c7ad71bd9bc34fdf7551cf1f9b2120cc329e19c4551a64c29a599f142596ba8682b2eb5cb2b57d1567c6a93ab3015f9943b1c85a17ed1158d4e2b9a5718ea9a60932a5a83f2aab22fd6416a895658eaf4b21258ab0cf9c08f2094fc9c6cbdcc58c9a0eae280f5a57a1aa5fe1e5050b73ca72eefd517cb2bcd7ace3d75e9d32dee839ef479d57434367e4204935e4d30b0328cf3e365788724044136e2db6e7129ea16faac90ab2f34eed024c9ce5d434ab0d239233c6584272f5da2784189381a5a03723409c50636f092af732fdedddccebf1af3e6b80d8049f1295e3abbcba326ad0796b78622f6f5b833caa0076218d1e3ab79e9762a10403bedb4d1caac2d312935b1a528d6969a586b4b3c739bf6c21cc34a4e4a4e4a4e4a4e228e8d85b5ca9f0965ad70f28a450bd336fb353d205621368190b930150cc33cdbf15430986132484eebdb8417e6985bcca14b202020a030d85a6b9db25638790d758f9499b5d066d66621cf329bd92c44999969669d9999332aa59c3f1882840820594d8f50c87384de922c14ca3c47f69284a255bd86b22c94798e2ce42e2fa46d6f49c86d080b856cc86dcdb090cd429ed5cc5d9752f8964d1b4a81659be341e1ce39e736fb190a1bb29eb97b2b2a34d156c76e4c4c4c0c54695ac47bef65999457adb07fb2ccca32785957c6cc4cafeacccc7c5129a59c1ca8efbd7759164ba06eaabbe54f77cba0e8afdd4ed5ac7609248124900432f2de7b35ce18afe8571613b3d9afe97165ee725c99bbbc4cdbde929ab975dd2cab99d7cbcaaebb3d9de7d776657eb9e52b948a3be75ce982ae2dc6313131313e978024043d4842b0447cefbd2b4ecbf2184bd52a51cfaad5aa5e6a62952cbf2cccb228bf2cbfa85adda5b1aa72ab5e5b29fadbe857cb2deb6e33f1a6542a95e40e608510c24ad55a1dd6fea1aa5a29875447a9b5764fad9572ca72aa5699c5ae5aa7699a6a75153b79a6590dd3ac4b13bf929314599ac4cbe8cc91d5f4c832cf91bd255996836d982f49966533cbb2f7224d9c9366ce3967765996756573ce2ccbb2ccaf2cc3ae6a5597e6c5c488ec64847c6f02217fa4141944abeb76a60492405597de7b6fd6f4982526a526b3146582a5262528734e3984cec7788764081f44dc0c1134c40e7d3d55d49d8935b3e444642510e7c8a0278364d0ce8cdba1dcce9340124802cd09bb674a082194b37ba8ee9973cecd5ebe89328b55d7bcbc35ff69bd6a51dd4df4532573ea2ab67a66318db6a877a316a5a494d26a79a4722ce8d3996dd11cf3e96c98532bbe5915df444faf5395bbe22a7e79e8bdf5cbba9b2885ab70ea825038f5143e299cba0acdb916338546431abd1b8daf68ceb5c8ec45137ffa4613a70a3a45d1dc9898981891acb13d6540e17489b5cdb6454b4c4a1dbb4b5389e79ffbf801bc430202262f05890f261a898f24487c04e99ef7c59bdf66e20d45dd2dded450c4ce3bdff49e974aa51285d36e87053420878e2944067d45c529a5fc9932884e193431e953555c98d247fe4c20a6f4913f534a995302cd29835efa36a504622e481ff9238364d053af2aea52c229e4ab39e79440f2a7a2aa4afab824fc733450bc731d1208c50a5c12daed480944718157f0cf2510e576dc8e119e57779b713b124802491f1924815ac7eed8f6e1a763b9a3ee34e89846432bf6551445510fa3a81cd414c3365098bcf5e93cbba43629a38c32caca9f4b4ade0d4a2973c8b7e4b729bb6296d4736c2fc96fb39f4e0cdb407db6ce4f6787dd529d9d39c6182966a65a8b32cae84ede18ea86acbc9b0de939d806e9f2289dede954184b39666f0cc3a02b377455ae6c76142a28aecb6b0cddcdaadccddebe2c9fafaaf7a4945252d235813e318d7a5b3e69977305e58ca46ee996ec8a611b441be5caae29d7946baa5e19e9d854b515436176695ee51bcd9b143b1e8aa228e9540cc360974edd51f418638cc1dc625e7d733c4faf8b726bf9e4cbe3e5f1f278dd8d263a9e8fa1dc72fa4275bed22a197fd2dccb97524a77694a833fc5308c4965d0b99881503dcfc20c7f30aa1da451280ceb91b4c73d6b9d48e4308c266ed47a27518f72564d8f1feba214422b8a65f95cb1422b21abc765ce5a271239cba74513a54575bc928b4ab642d50ac3985b2c57329b39bd1b53dc77a389543e205f5996654986111d529426596822a5d44625db50e7a5ee669dcfbb51499f573c8e7a2e234da494e5cf7ad6b32e95b27b9e29a5543e150e255139165b081271342c871e6fa28f6ec1e996e9d0e38f08c4fa0c9c12cf57149532762565a9899c9c2b8f51cad601d617eaaccdf881f801ccc7d6f428312935e952144d867257778949e5a52655094a75959c5c5455e279e94c83870e89381a98c3db15dfa06e6944718949a94989a7c4f3b4aa30969f4e3e51e91b56849470cec0e95293971e2dbfb48a7a4595985022883c1624e268d0f0ce23906e8951c6ea5d616878ac084a04544fe4a9f1e6db65a0dfbcbcd06bc909c3a83c6e5811ff36aa47d650c4cec49b78e31587c584df200dbef2cdaa9cc857779b893798cf3f2f39a16ec9498949b7b89f4a3c4fa594b2e42494a392c32fc9fb115ac162bad5fd1ecb63792c8fe561b41ac590e1618fa29853ef870e9764d22adf223be6f1a1788fe5b13c96b765e0e5bcf71ecb03c2930cbe61efc74bef472f4d7f855d9afee796b00cf9fad2b48e577216350376633c88652bef3d96b88dde8f9fdecd3102ae5b3638197e8c30348022965401865e8cc1a37292524617849a68cf3763e411df9015fc504477bcc9a4f7a00088eb01c0cb3b29712f9e6b60b0ec5b0412814c91180e0682b66a86135848e4e14cbc719456be459b872a9443f764030f5bca43e81d0583d09b892e35ce6b61e3bd7351b0a96cf1c9bfe78df34a13e7b5784ead48e43d75a66f7104ff66f0d4b7f8a4e2b817cf278de46e2da5e1a97be9b817cf5184a1d268f88943a9b522914f9c7f3bbf4d9d1a287eba168f0770d8bde887935791a37bd75633ddb7014883df289c7f1e6f78082b7842e3cd6313112a09a1e8a70c62a5aca8c9a38e971e2d1bfed2279c17c6005c1ef1fe480f891c522821b56e879b024bd363ccb1315ad16bf1bc732cfb83114a1979c097b1ef6398820c03d900cbc6f2f1aa1e5df44a7666c6cf99023b27c9b5885e35e75a3c27a919158024e848fe143a52f4bef2c9f87246e7282305663cbcf0880d09200fa2877046f431b6e05952939ecbe063d9371249240025bc40095034054847d9110819fb8a20e25c122e5e1d950ace396e42db821a7c3109142faf0ef7e279ad82753cceaa421245b89d874de297824a640613d8e7ce0851ee08914678e95bb6e2e3953c588fe4919247eef00994e040ee3cac524081f3cf2da033c30a2c9ca174deb2b42da3741ec23bc4c21e7cf42d637979a9141db0ec1bb5f3d4ce3f977186d2b9e19ef8c0030f9d8e6cb45f0a503a0f1905ce5b5241af3007217337d41e85b0f9df757d04fd8d7dd0c7642282e5ee8679ef3d1808218431c618a394524a0983412290080fcfc37938add33a3e3e9cc339b3ef44047b434e7a6d350ffd397cf14222cf1bde68136ddc0b570379e61421dec41b2a9750350b4bbf5771604822bdb88089bee7dd3ec0c0505f83fa47dd98bac2697a8f85851fce87de8e9b5eb0638d50854d3b76b3f86bded517f85b7cf62db68d487babf9f68617ba172bddd0db4684b0c264ee06203a3039f50e544e79aca3044c4e7d01d5a5d4a5b1c2581b7c2fbb17b2c2602318f77d6b2062435ff315ad70ea8a0355d5054c392bcca5806901d39d71674c153aae08700fa78a85e5ab0226a70e98ae7bee4d072184909b5eed15063a8ef601867ae830144ff97e78a97bc1d4bd704e2b4cc560d89d4fd5065f3855984a525352d45197c73be5ddc1533ede910d0aba051c4f790dc01ad9758708964a283dca19b713049d1826bc1f73564aef08063abd35ff9e4b9f3206c3e89ac8dc848a3ec7dd3db17b62f5695a0ebbaad339ddcd25944994b834c9fd412aa59447dc599076a89649e01d183694413208ba1df9237d24101fc142a20f6cbb0fec0e0b680013294145e266417a3af4e95038cdcb9dcb34ab611ae9ba1e78c5b8981d9af4bc6a39683834e93945afe82724a41824b67d23915cb0583d6540c5184b3cb3c43361bc29954a4c4a14454d3ab1542a954aa552a9542a95269d1863a439b188cab1d876704cf0b51606550dece67a78782556f25a3ca7aca427064ae80e134c9af0744bd5d31345fa4820e9b38411d631b2840e4fac0303f629b212aec7480c7aa88411b203310c96525eb2111e662eb0042b713dac4402499f1e09c4ae4702b10f0a3a6bdb18a969e082181ac820868a2922e1e482294eb08884329030e6257918c330a084998d91ef51c7340d567963d8f1584370fed177d5497a43d6bec0724ab3e0b592b09407d733c3f5cc9831cdc0ca488f140fdd32f9f3990ad05ca007c537906248e5e32a87d6001d0dc8a183a58ee90532521bcc9881e5df663c3c000e39744be54f320cda519ee98c0bcc20000e39789899c130585e58b1e895665cb75ebaf950f3d379a38974068553b96a82f9d6504464ad90aa442722768b3931e7952823afc5731a73620e65e44d43accce4b132422d41e95049ba45524ba89d6ea9983069522a31295d6a082584224209e916e814916e993c514426fb144b3cd30dec7437c432f51621dd3284482c128d944a483ef04309e9962de6504aba65a384c49c28ff3c1e41a45b9e53432823dde2907c60e79f534bc41cca48a9444b4c4a9b0f35cc37523c4b6077ebf198472d26e68ac1300ccb5155130e9823e6e94cda85c56039629e0e86c5b00b7ae97c5ecacdf150216dc66bf17c45d3322d068b99f1eab5335c6065a847db2d35a2908bd1414a9398637e69fd32ba457ae69b7d4a928e69de2449338dd417e8d100cba4925a773b0b9bbb919e9b9b9bd9a7b368329a5a6cdfc6a213a313a313a313a31373f595849803833c20fd436eec234ef752ee1eb4973b0d73d7dd2245d52bd3b752b25e938c31ca28a5a4942975a63c6a14a07c4e1f3e7cf8b87ccc3927631c1dc3c12e0fd3aec9cc3e26fbe039277b5503112b7d8241e2c66fc85c5ad8944f94addae42e6f7aecae4e0c6b0dcaa955d1c9faa87d6144aa49889599936f842fc20aa7492ffef8c793166589475e1c327a8949a989139ec9a536cd59b91293529312cfd4625541b85142fec17869f8692704051b73fe0181da7579d0e18b1891e9c6cac9b967baceba49525f58932cd9861e9707eb8bf549b36e32946c430f4b6af94b6963c551bdbc6c735953e468487f55bdd5f4022b133d8abac5a3f59c5239f9794a2b990a75524e1dafc436b7de8a9d6d28b596b2b3cd7b5724aa31b974db32fc7bef35752939e7ea2b0850848022c4e514ca5f17c775dd0801e51202ca8d1050fa8710d00a91798c41f0e7f97414d9f3f1e6329426459f61ba6eac94bbca312b6b8bfa6ca5ceb5a8a188a5ae83d331eaca4c97da30bf1c8bce42b00df5ca5c4e51f36e35d795a1f56e0ce5a564ead2a326e3cb36137a6a855e464d3ea71a05422f237d9a7caa5c3b1d09eb2e0dab02563ca32a9ad52de454d1ec6bf164e6765214e53c39455977905a2b9ae4dd828560a96d7bb0b2c232acacd0959588a22573141e3d06db80e2e24071b79a47e19996394b8c4c0647a1c990790cb6c17de65c5fb2958c856d88f17e740bcde8ca4a0caa4237026c32748454acc7a02b2a5288a21078c4cbe920fcf10289f7fda054387b4ce1d137cae3ddde0f1a7c856f74e49bfd19ee96f98abb6e41e19b2dd170578caece0c57e4446ed221ba9b5b227277734908405150141edddfa39b0dad68f1577ca389323ea81ea8e48d767541ea108d000020001315000030100c060483b180381134c90f14800e8ea04a6a4c9788c32c88510c21840c31868c8008800080cc6c080a026262995f7dc3f061364b102a9cd224f894cf9989d9d7abe28ca134fed691d4ad167ee535d460ba4b3b008542912ced2c84a21057c24c35ea8e835668ddd855c92ae28cca036ad8204f98cd8d4a09eba371016da3777a644986f1d418b62c215628855282bca18ab33126a14b080503651a0b574709596e2c836ecc29fe1f6d35f617efadef51ce4f04a8f1b3d39bd124f11dbe3d7f69f405d7c013bf68573dcd6bfa20ab17d37187e0e1de63193af1cd10ebd38c2d9fcc42ce148f3f6e53ec6b95350daf7f9d2745bd1b8a5a2cd5517f045ad56bd03b6db36ea27227d637a8fb9c35be9b044aae1ab1301db053e8c03eed3454f8913fd0324cf54752741d82282ad2671b112ce1580c2cca5efbe71e034f615e2f840a559ab449c258ad1f8f666003812e8568a646d8631f38b0201ba8b3a74cc643016d27143bb2b4ba4bbb86d5c4100fae1b062a0a20961852bd12d4653757e87d7f9ad60a770e59727b3765cf160581e70700eeec91e90f8708b8b48a563a446c54e12d4133002fb894f324998dbadc7700928bfa788fe89eabdbdbed94be29879320c987fe2c091d050279322c035c385f492cfbd4a47071ca0e5457181b8f65c660d72148dd24ffb10d04f7e07b87835356d627d7510268816c0fe53f939ab68c8b1ef4c715ee3069a83301a7a635766d1d779850f93ab29208a3cc567e52b49959c926b0e00260859cf1c9e7cd18fd00da180f5a4b9d72175144793be699a27bf98f7f84a6b19b1eed3c02f2d320a4441ecd6ec108b044d38eba94c239471fa77749f56be59e314c9cf15d34d9d24995fa94a1b3f2082e3c5af88009f4fa5bd488fe8c95ce779fba204524039650d30365d255ebe0c978f084aa19b3df7a0ea2a4b4beac9e83315246fd24e5ab948fce4a9958167b2d2b6e6ac820eb10b7c1a1c624302486224a810f7af216907e48dfef4252d6509d1058ee8c51755dc28cfd3ae58acd21abd2de43b0bbc6a41823e3bfa6ca6a87eb1791a49794e33f66dac4bc78fbb72b26b8fb464db81c85cf752bdaaece1287e18527d11683bb0ea8310a2fd36d4d1153a06e8e1716c27f2226e1f575b27e395f525dfd23040df1d4da190082b038b7be5ac13dc1ce8ce17f407340e3d0f7bb04c546a547c13dbdbbe2fda7fb717aba89fee1932b1a4509be1ea624a1ecb9803265e3fde3494a3eb3e80f5342029c660d4a3b240b60d41b0a0c2f5aa26a293680c4f6c80635db8fa3045ac3ea5cd437fc6b667bd95c0a6b2b33f3735074d00d2ecc88e6b63ce4fae1a26b01168998aac0894161d2cfb9be36bebb7c21a44097d544204cbf4f131a2d7ab5af423c13e2cc1fca0475a6e934cf2ca2808485b4fa38b4691c7c3e254c86c8ad63e10e93b007c03c03299ca67fce6f0cb342265c7b665ff2c14cf7e185ba0a0fecf6bfd5cf2399e22235e68f62cff5d5e3eb2086bf80b3daef50a3980cb09132e6b7e92bb16ae16418e8c7ce5454a405e9eaff5a1f097845fc0f6cbaff40bc1bccb58bfcb6d17f28a163788a776908396ed6acc707fc16fa21a3b138cd146406b49df79ab30b39df7f23ce93769374abdf3ea6bc9c592071c8e1c9fab436d3e86e0c9ce954fb5116fcfbcb8b65cbc7125b97fc2c4a52b94eea629f855f0ff8720e619c65e2e8087729e6c1b3748df4d30fb3dde23a7cc6f6af7096736a9865005d80f909239d385948c7a2b61b73002795c6604261c5aea38072aa5cf087ee454b90234301140a6cf3c9e134a1f542e30002dd2f96b5a016c558058b82a53b02df8af6badb6f25dc9933509602a86b97f0d802830b90d86e6ded9b86d301fff3ed63abed1b69ac14c09a93d103f41bb05768070bd50a9c4064b552fa40af5479713b85ba2bb9a1bc1db5d6d7590f98be7b0e65fa260c1f79e39ae6eac39c7b910b7fbedc8ff0237057d54e137606bc7f845a71b858c7eefe3c8829a6ac6b8e4f1f58e29c1ae75be68b656765b899e7431bc533a0524b35f6f6a97732724077295f252d9fa8c206118bba49f474d1a6bd2794ea5df5488a50283735a881357564a07ee934dfbfce1d1b42a29e4cd47f32d3400922c113679381197b86fee9bc794b022c64c82aadf3d476a71971cc20d27cbddb9103b41aa3791c6d232ee02db31f34009b46659d6ee7e267e3764563cf3353aaceadd8b823aaaaac63a4c52041e033909ada7676a5b3941d0c5e0b1fe027b0411ab743bd79e9bfc3d88f7ecf61abd9458af6398bf09f8008873926984da88d0c785be49c10ae1df9c7d181dbeba8b6f46fb48e43924afb9fb985436b6186ac8b50b4d9f8d39ca73a78bb1c78d3346455f22d600e42d23cd222baa15eed22b03689b3d0309efaafc717274d6dd3ac5aa74ea90838902f7ee97a3d38106e4898adbbab313b84d2f5ce5d91127f533dfc75b4a1d8206ebb84f69e4c09a264e95230d40fd1c10d62771cfd983954581d7f58f3b74a463da1003fa70d2e1217886aaa4fcb1e7c6b55b1f5c922777328eeea8fadd6386fe65f459dbd721c67984e52644a16aaa3baef3bcc9f101b56e5c84186844109bcaa5724517893f377b28a9ce9cb0f121b0986c723c2c24e171f453c3852d0336d2f6f857cf87e917d6c920faad68ecdc99b82dae427d9774442c4771f394989e8345e0ea33b97dcc8539833da0ad9199cc979c4755f169659bc710b1fd93605b819d0d546f07e15fcfa750a5871e2e2ce71d9674bedc3d322e3fa21c1646daaba0ccbbcd2df5dde784521a96dd200e34400e3907ee9e39d9fa10b4893eb92f11df667bf18e47d92e17a7eb4492ec866f5049f968248d9e9ba697f77abc0f91e3d39127769ca5271736e9f683e422a027d998df4822c4e5d08d32536843270ef90b762c8cd4fd2b51c745dcba91fda233736599603c6e30ab9ec5ee2189d5ac8b988dcc66de423717a30a420ed0cd4fc78dbc0890a08da684cbe894a7a663554d96b9ebd688ac43521d9a3999aa20ce14506a7d99c28c9f37588297f803bb3b4b740030f99d77823d2d0bb1af527ab02fe35aa3fd9a17dc643a4ca8a28c6e2ea8a85f1986ef0fe2a5f23fafae08b5e54f93ee2ef7016128c0b9333b7b43e062548c222902b7fda8dc87adae41bb0708daf082b4c76e747e92283decbc40376bf48245edc5a30d6e5cc84a83125a155296fb91207630f88e46024194976443cb4add453427e6244ca80822bb9759240178000d132232a07cd256b1bf7af0921a8f5920a7e19ccfa1a3e3bcb75b0d67e98b88cd97f2c8b793a9940616c3c3f4b3656582353b362fb08178793f581113903024d37e4eb7ff4f89fd418d184bf8b6b6e45618f6523823d283ec12d19ff5725235c3f3c1fe3454c83336a34d70577c932245f3085108a7b56c413137b7b3fd0a933b917abed6bb2f72a6dcc49a5ce89e129c0d7abc6d3d1056a6a07d3113c16bb7847b9239d32fc16a117c9e9eef72503b76b5ff7449cb4f4b5a03dc59fb5465b833999279de7704aae65fa67eb8b4c9b9b95a70d8f63a625be00c7d37d19beb2c946cdd3c43cc9ed975709fce58ebbbf1ca65c5903984fe1aa5402cc712e589ba3183be66c71824f47b6be50750e5d815218ee1ced98a4c36be9d9bfb76460ce40aa7253e682146e1e32aff144ac833818e98a8bab69dcd492c3ff68dd760036675cc39f39f5d155aaf23cc2301d25f4017bdb8741c094e83a69ca5acf4ddd42247ee68aa279679e2972b16591805b44dea0b7d75d3b8501bca11197309cfebb90aa381ae3dd52a44b6fd94abdd19462a7654f6cdf5021102cf63a34f800a2210a78e71bbec56029dc2ddc1fbc10d27ff83575e6c1b76c7c4387d46d21ffed722bc6a81e1c70b2e559d9bdb255f68a99d7527aafb27b419e102f253bca064bb81cb2e3c8a394206de01b0dc4ea2874cabedd87ea77afd86219858190e980bfdbf231458bdb37ea2332588ca628f312a13b295a042df84fe47560fc93a0fa8657f54f0d73dcd654d74f508130f82d011048d734d31883a737dc411cdf5f6867b0e250f6d75b1260dc01419ff5e8ea1e23183803223400f1a2219e6680a9dfb1f7b483d1667bedffd86b5afeea6326a311b921a58628c9cc45bd32137f9c889abe0990f1d31da5709343a6a9a229ec87f10f4dd440af4baf48dc830dd8226a7f0d3ebb873c6cdd54bc39dd1d85f8634e452dbeea363606547a727727dffbbdd08e9785401d53f9911bdfcf0fdf82724da26ccd08aa97ca43c1d022366722523dd1c946f86ca473d1ff3afcf12f72c37d51197c0f3e9421bdb7ec88da166c20b490cb031f35243613e8dc588efcf4c6ea00feacf097eebc5573e2b4f670ac18399806ef375efce33f8a1a27c08cba9fd5e12ee614d3d0094a688772d6a7478f3b1e3d44206465ca1ae4908968c08260531bc9bb906c2818461040b7547b944c605d4bbacbb49a0ec10b7e9bfcbebaa9713f61fe244be4c01ea42a83dd0f1058c394e6ea4eedbc9594e5e4b2f1f1a3fa156a8448b4a04f844c87b5c5e82ff1800145aa0c7598315610046eaf426776b723788f0f3722fbfb30ac75757511a36262c98187b09b64324698187e22c55c9fa4b8ae8afb5f8e0717f50220f73032cbfcd1a3a27a996a3ccd83a7899223770440e189454cf7f4fca09194c8e916f526a9403204c138a9d5c485b3983d3072d61e95f5abe21ffb3349b8f5beff76da515a67eb26472ec1b8d1b502174abb650281419d33a84b25696000c7c4f669e3238532fdda31920cd334e62b410f2b99374efb6b7705e812b2af2e552f7e0339171b4031f2b5b113fdc3dae0ddbaf695ca68bda8d68cf1bbd432b55016a99bf6f5aa3c3dfd084e99c223e4c4c0f86424d1b1c1bc4c48ae565f640082e56e87f4eb126b11eef4f13e342cb8d514e3bbf610a0e68fb8ddb5793456154e2771a2a42651d35ddd2f3bbcb380a42274a162a2205686535fabd42505013ec11db280c5c7af3e048287ef28f55f03820d2af1c1f4e81bae524a3940833e0644ec04d82f51bdf89860de35be2ff48992b59ab531ffc20897ee47e57a449c0af34b2cb2a14b59c9ed646d3cdc7582f246d64e9e63ed68096d9d3265f1986c9618b6c519ee053d50810a71824d4c2a45320ca780fa8b0029b57de7c5d5d6e3378220347bc005518038f8dd876b41ea5ab36f70ff84e72c2cfef2efaeb2fdb9354c9d44626b59f78a24442ec55541a1d7f368f5c680032e1b6ae36eeb71dd45933bcb66be17b131c5e0f12cf9b271a7e33d16d0e562846654f2fc5e62146cc8944595663ce0301ebb19e1e1c5185aa8c9269296f103dc0bb2e748072180ae3fd19df21898cda76109e059317fddadd3aec190a947b17752d61b2d8bbdee6306689b8aedcfbbe86ec326e6adee2352383c49cadce56c377198aea8a49b0972e450905910e99ee71579dd40c21210e35bc74d593e1096bee36cdcf05e46a8c1eff2e67ff98d835f63da0d5871ac8cbfd3ce69f8b60272075c3645118c11a35663a2c59f0bc0ec15c58f9a2b8bc68fcd2be0a1f100bf687cd4abde48da17ba30eef33c0114397e7552b49d254f0f8d3f30649526adeb42a4b35394e705ad633e9eedac1a06c907c6b881532567283874488cd1fe6cd670a8baecde95d938e3b58177bd4e9a8ab305e44e4c856e03fac6f41d9aff5d8eb5e2936684fb93a6c1f1a468eae1878da4b890f89ca8ef450dc3e2fc514b18990dc865cd837594adf1268813999f37b3025a4aa47795fc0cf1854f077631ad5ae9f7c48379c300a395f71020f7a03d987092ed3b19c916d39ed68044306d043328169c50fee3ecc2e65798513640dc26b9f060311a563453d12f5f481ebfa83ab2714a6c54f6dcc399e516256e382b61629b185adcdba8126201d2340b73634f0b29348b4433020370f08d937a4b4ead6f35649b0bd0902b3a73adc9b7aa27f402a330903da95e03b898e221d5d0fdba3108ac38c75d9be439ffe906b409e6f6e5081b8982173825e510e86274e12bf89202f235f546f13ebb59f83d846e418d9060ef03f4b36365a5c4d37435f7c559ffa91f4a4ceee11f91a08e4590f928c75466592078e85347a96bbde727d1c91fa708a1b15e115b56efb58390170614f9614111981bf9a6bf336c2e8228a0c22c7f495e886f8f1c28a0f7b5413755a77c0eacfa9328ab53b8714ff5c249c6f6e9d5635537b1e0f93d1bc2919ed7c7901cb0c67e98ae00949c3411e88cd93ae20f7ccf35e856ee268ef9c743f0fe828f6999ea2fcb734bc0e4599c0cc5af46c6ddfa4b59e58cddd1e73105a8441c354a45511137b7aa42f7e8631914754270c58271ac99f0cb7301c6d452e859f92f0768547cce4ba6f2e82ce8977d8794d58b1f8571db8e0490ea90031426ad074a5d4cc814a1e4ab862254a89129425b9b764a853cf274ea180d26edfc36539fbd20bd11d963600afccbfb774e60b44424c3871313fb62b820510a0bae07f5d37950008ec3c9901257f2ea19b868580898988960c3df4d8c49d0043b3c863c57f761301ceaf3a6001d5402192004d9bddc086fdf974f2e5606c2012a4730b181f7d6eb6629f5a68bfcc1853ec962dd82449dff04da2325f2d46c37b1925c86e1d77c07485e7cfcc41710e7ca49e458b28704b28f951ea200761ec3188f51274cb3fd241cfa55224adacd95edb329e9d9150b26379520d5d907a7b958511b81b81da9a0922c3cf14817a2736e14d6eada46c1bd6a08b7663853bd0e4c0a3f5cb508ebbe2c0bdae641ccc4d76b5b4d6ee2b44ec7eaeb235185a35a0ff08f245d4c12d2d0e34a4800120bcf89dd853fed0fc6e2b46750b617419b8d07d12202082a4635ef9ac2de3bc80c6231b8b1b285f64cf413a47c25088a74ca7df0072efa9f6d5d619a9a23d75e9044feab6db14cf51559146881a2423e640d897f22c3809811c515bde6f810957a843c0e2d6ddc07a8a0ce1958c2220e230f56dc8bcf616c2383d919cece2c5b232b7893e8afb99deb7ec7101a927ddaba014d185c467259a82fee1070e064e2ebc75897249bbbff7a5f4908ed954ef4365788a74811a2251d0edab9a19db86e0b58c725fe574c130bef71e9c2f6d503e09be200e488cf2044516d4c62b51a0d894606d91576d7b8f72da2d4891f0e69fdea8b8f9046e4727b7a0ddf4b4d5bb1dc5815579bb70baed6616d44322629cba0e5b24182cc2f21a4c2ed183a7594d55896014fbaf3fd2cef131c23b58803091e9dfcc7f2ad248e444f69fef4cb3ad997539f327f819062a90ce495b72b94ca3b598bbba7d35a9a9b0293502b50b598fd45fe346387fb801a435d5f673561d7cb1af9c25cba7e06e4864341f81f1b635eedfed9821732f42a60e40b35deb7e51fa3d144d731d71ec81aeb77ea6df1e0430ff9f32809e4894d7ad671570b18a4126f5ba56f0d8fe1e89d42dbbf3237a265b0e1245da14f26a753645a6e85b047bf2e401780df4395efc8059110c102d9745472b68af04645571b626938b55c008d4370655a652204bed0080f93101e5f5ee2b77e80ac105f0d652d4263cb4d5df1b227251ebcc7c6e3c72ec85f9b3284d0397b2e2c9dafd52f5fc8d0fd362e3726c3c98eccb56962cd97e58fda6237717e0000a3b4e67906f7231946aa135ef0580bbb62fa894f5f1aecfa3e526f4eb9fd3fcd8e07e910c748b5f1e253a728416dd3b49587271e8ddae7182fc2958ced643a48525198e9ad64afb6a596fd133964e33a4b15c6298eea5c136db746b7ca628b147244c93ea3b53267001b9caf3c93c2301bee9f6ead6eb12557fdc68a918a5e21ae4a571357b82336d5059470aa0edd2f2e9c62598c399ae3a6f18e1ee8fc9fe348e87d81b18ea71a9e3a2cf244d67264066563bb46d39341fc312c9a2c960e846d98458c17f44d89fbee3c534324c2df6d46c2126667ad7dd8bb76194b3c62230d681901462e935eb9997f786a5800dc158c7ce41d0a68875841fb7c8126583778d4f789adeaa0a3350b9ac6d86491eb248486781564688a701445624b56ba6b69004b9c9e0c98e9dd44cad4ed11792b3fc2b847330adf82a4ac86f8a480d4d33d8af3e4b3ddc13ee3b95d1081e75e295760634a085f1180e5c2b30d09f2d5c2e8a0c408caea7edd07c4e16d11c527362467d587cbf3f3ce1b426a56b0d5c90dafbab34876b424387588d507a17009f3fd4f6f2dbe28f99240f0ba1d6be3cf6ed3fea416b29c0dbe6302c99d760b7fcc0511a12fcd035ca0dc8cd5fd0d6c182684bca149e339202a42a6d6a0743704d6f19f35be458326f4d11eb3e41a32871e78069b731940f89380721c710a3caaee3aabbae826008a22dd5e4f0f2e86e33d005e3692cef9a8321cfc2316775613e635514400c9462180185bb4582d3e18f83b94a407662dc284d4dbcde698dc66e362edc8423b764cff518ab26564042e22310bf0882b558dd52af0fecf93205503db3664a266dd45a168d8ce792c6b4fc09819a350415461fb2e0db7c1e866fa1fd492100fc6027b25c7441b00583a2c2a2403f2917ac4a350cce001bfacf260c769cb13a44f842debfe6ddfd279ce59ffed17bcc0e0494af8483e2867300856bb1a88b68d6c60c8ce3c9425868b39f7339bbdff732fb666c4b135f89f4ba412a804fbe09324222641ef9cc17acd90353bd570e1470ee91d354e26cace88b0b21ff578af2501994097850ba27daa490277c4308cbe5248ecc256d3dde23d7ff020a866bd1a09b42b87a24b41a28c06bc9b57dde569a6eb88be32bcc8ed4074ef3ce477d30ad2eddf0a787c4b246f9581afebe67af67f6dd98e61fc904c9006748e083c2f7f7e4b24e49ecebe5a214464fc9a89d912d8c4f66ce0739501001726d4d612f31037030f6d6e5b92ef9022c7d17961d416d7dbb62da438fd8a0c18b90900a434f7fa88946857aadb29765229650675d70000a09cf40136abd9b373f6afe1ecb3ca9bb20f388d0d752b75dfd5a97649660343aef0c33c1e94ce135cca1612abd0f73d612247ab91ce62ae0a3f167c6d6ee6da1964c94af51e1729f21847e1cf949febebb8f830d984dc0bf69c2b0093b01eb48428e33c4d2c801457126e73ba91bd874cf6f1375b506af307a203da386c3e348ea12dc78f4fe42d072dde70eeb452e8f7b7f63076607f6fe407301f5cacd2e64bcf4e88dfa51b99db8a010ac9f896bb1fe020c919a34979a7e48de1a66536d13207c6140b315bfa78e04b837e7103fc7941ea3abefc983743d34102d6165d60bc6c13dbea4dfdef81015ab801e8ea0485fbbd08347e2354c3d304c0b8e55695dcc5240447b770347d999fba47d2f88f4a98f05b4004e3f7889c53de1ef353fa5b4a02154a1954de4a4d1fdb3f5b915b728034d60b7fada566e7b4e6e10b1ac6e38c523dfa4118ebbe28f291d1b152d5cddc9656cf9c04ebe8eeb7e570815fdd4f42f172347bd8f6dcc747611e2048f67e112089c697192790745d253f63aee89cf9b68a1ce5dddd54167fb3216f919daec5e4dd9effd404a035038f45dc2453e8191cc94acd9ed29eaafb6229dfae5bc398f12433f8a88a09f45a4929a66fe4fffe9fb884945dcedb8392228d62365fda8ec25bcd8d7052c2455b9d471846b316e4e31407ebf682df2c52f850a333bd208ae510e0b7c79a1fd5ded55ff27559b38016da3fd49fe0d72371651f8805797079ef512e69735fedf85d97e87d1f2973c5b3fd1303b0d5ca6047aff7b1be68605c228bf86c369ffeb262420432d57494952bb225cf4e468f7aa72a85486dc4755a78995bc0706ff94df9466aec0951940c259edacc1a7c3134697c04f6bf025258765353bd0d736dee0020b1caf50969d3354e5cbf18d3fbc3e88212daa77fa507ed65f3df9c09361670de7e00c4748c6dc982b29853d1c1723abf3e932fcd9a467ac32cdac7228820358e81717144ea93c1e0bc7630e856270b83601dbc558ecbd56b6d002e7aca95381d106ca696ab2d2e95d4fafbcfb2475a67dda02d0507dda66e2c8816c100a8eb35033b2690c19df9d4272e72b1ca0f96cebbbcbcd99fe0eb0bef373b31a43c5288e19f3e9b01e21c1bf8ab9b126ea21fa5534416cf693c628a8697d7d1dc7dad7f866cdd4f0513ed9a12260f6a3cb167c3dff0340776f181ffb71fa6db5833f0a39c00a359e6530f1e68daa2b620e233040d00c457207ac0cf36c9486ffec20bc2610e66880aef46d1c75fc8e07a55207262374d0750025741847075ce1d8c78939459c98b223e27481460bfeacdb450a316e43e1a25c89100eb4fdc767d8b91cae516bc03e1053f9ba8e698a440f7aa4ddcecaf381ba46dbb572ecb1fdb2bbf08b55c118a6d24dba5af399778945daf0cfde248bac0440f92cd8ea5e5683b613526cc55fa9483720eb669b59d1dfab241d129dd4bfd341978fbeb5598aa2b9547bcc29460383c222edcbced03ddbb324dcecddda98bc55b1faa7b0a6f9760d80618b60a7e85d3aeb30e28ea1ca9cc2c78ec2299ee0d49904a8e8389f108a5f0872b9fd30638d94bd4a1f2e8cb545bd0f4777dc4c44860844da1f983337bc7cea3679e9277d9c171174b7043fa2d2c2d83635657dd0ff1446382742d3c78e39968065f8b5f9b3be3e0141749e9427d9b20cd797c3bc0844157dc00605967ad5a7ef8448d07a769f1a1ad4f6ab53f1cd9fe693151a109602b22754b7b69c33dbeee9ce2cad705623c14e9d4b8fbda8c3828f65c9539be4ec21d2554e7613a9a3737f3dc24bf0ab25572149af469ca7bbfa1cee3b974433a61b2621b6dcb1c3943ff6b3acc1a7ff9c81e8ea3ced069939d4e42ccc13c77574689e28a223ac4c5498627a05a7e7b8db5816e8f81a5f4652c9df5865049cf895a9aabfe943feb8075fb1dbff235daf2ecfd6232f0250a0f762e35c028bddfe2b62a92c72f10df20a123f11c8d03edfde687bf8213a1ed3f653ebf895e2ea961bc97f952035b1c7c9984425cff0c0ef99c515bfc27c97d55e6aa3571549daa0aac32509492f091f08a0233ad84ac4635032cc2685984d7ef4caeb0965683a945f216e3ba4e7fafda9aa3879902b5d9c9f08d6e75de03317330b5701da5d52be8ca23fd216a517a4943a255ada71035f99cf641ab0c5b127f7acef9f4ec7b01145bd04c7619d4381849dde276a7aa5d25010b8e75e355c309156606e7128335fb85694215f3a5c9b814b47b341091026171688de4fe1f92e6c0abcbac4c31f757e596c12a991656f93d8132c54b05fb7d42ec40132b928fa38f1326364760c8fef47744aa0e49b27c886075ddd02dfbd416623b08aee99831e93958b730a60df6cec854d5ffba4a63d09bb451569082fe8e574102ed2b1fac505ccac75a10f40a41ad403cba0843ac4bd2f8af23e6563d82fd91b79c357e758a25ae4ba8cce1c34d4c8317bb333d497876065a9e1fb815e37ce01c78862500772f3445cb4a4aee20f3ccc3f80a260f68c7b40f41bf9c4ca83df215a6de73f598767de790ff9988a4fbe89a0346732c40346218ad564c1e4448e0b5549f68c13c4efd01317cae6db92f318c4f7f815ced1747928b1c057827f5719fc6dbddee2483643ae47e02d058968fb9cf13077bf2278699c2ab108cab7e497c20c07e231c2ef36d0b4e897e374a6af736bd24995d1a5f10b67b229028b59a274d43b3800f22ef0cabe9fec5ddaa540c2d6331de77fd8ce9a1917cdb3f22447aa493a1844f629244348431cfa8e7a6e16224716ac44529fdd37ea0189d225f489e66ac969d4eccfa555ffad31220d5cde85a920a2ec86df8f4083344fa66dd2ca2e6fc64e800d89939d71c2d51df9c1103bdbca57372f64646c69c0dd639ca10c1017a6ab32c51999665cc0edd3ee56751915b00212a89955839de07ce0133260e4f4977dbe553aba8056d457b3a25f302e34702f8b58173811d4b74a619a57525364e56fe170d8ac47853aa99eaa3767c9f5bdeb572d4348bd6b4bde996ba5e9829b9862aa36c942aa2b85f5aae8f543a47cb7228bae2955ef2ec3e22e49892d6e3f5a09b0730c9e76b6ff85669aa30f913edcb422eab3d63122af68586d28dc9ee47a383f0117a1210714505864888d26fc8e8637c6715f4bec837e4b15f591887c459017fcaf5d3fd70158966233a4860ff381cdf1578a23a630953e250b65b22922e05b7c033a48d3b6d68ebaa6a9de9dd40272551632ea2afa9a060c1be94ce1e369d7d849d9d10415d7177be15603a682dc4c01da9cddb5f092982c6e7ff45ff7b5d0df1d1c13fabf2f6809d31b0a2892148c5c3fc92f9871517a4ca50b80b5927156570c9116d15c52f5de875724c5a69d00b1876120e9cfdd48d88ec930783e7d7e0180be2ab3de286c1db015e551ad08654facf8334c0d9c902aac38f0a1a66d8f38e8314a0355d6ff5342740402d00d53e8453f860f56cd0ef9373c55990420d921d5364c812a6419e44fe9ffa1daf0f063c16fc862592ddf83ffd773c00ed0ce83d942310fe5f18544f01bbbc6d5e159afe8c67bc4f5b5be595335464c2cc41c47c454d3b944f5950f6948ce0a6c86f8a9eb2b408c851e732f6da36a79851605c3ec8bd96039c046eee2d0ef836953752522295a936e659e521d73196d8c76b2fe4d3c939cd86e47e1235756a5c3449e7596597f978f3c99c3fdd6b6defa5616c9077e96264433405aa6ab4f9a2429e28876fb40420355e22c5a54c38c34c6c783cf4f0f5e8eae2d3be34ab0a2f98343c02d31b361c0efc990e847a028e0e7b7f4bd92f6fc7dddf79fe5ed80a18d685030c9d05a111793b02a6e9ef9b2e4a87c7764c39c5f326bb8feddc69e92bc90856f73305e2c9ef399d8332937d32022e0a946188c8c849b8a7975159ff93ea4b89cc7338ae2c7a7f3ed0b8d4a884b8c8795fb760d959ba3d1717998d50e1f95c021a178035940c33f71097b7d0d41bb5c8724570c45998b345bcbfca2623c71997b3663cbd03e5dae25e417ce42b56a0594712f3febf578e468ce6016abcb4b74fb3f38ac9061ec1397b465e33507b24a8b33f761e2a92c42c7298046f07b079a7afdc5da77d702970dd5c3efb805b437dd05715b64f52ddbbeefabb356d271f8b4c3db39d9614ceaf356f676443396001df22c4ff67a7fb227dd6a37edf7576c0c63a405c605aed2713de65dedc52c9246312c5bc850c0b06b480a62db872f1dff31df676b550c5fca5ff0bec1604a8c9c0d5551ca6ba52df275eb97a5c792d8cda278383a766f9ba57d1bc5db05bff767e9a9505d7dda820f76f2d8691ebd0cba10d0b5b6b76dc7a8e1ab682a35a89c3d31d235dfb4d1c00e9a25505a61b8afb4c758fd6d2fdcd9ea03e6079a8e4a0f9e0a071ef4bb11e52515d433641f087c90dbde3022a93928baed41b0735c5d5ea9bb4012dd393c5a49da8ff0c462eaef9f8bf587fbae1b652604b0bf692f59b0f3fb6887f7e2c24bc1f740f7890860c1ee4a93de2c2ba2178c6e21bfb760f20f43cc2ce331f17e62f8ccb27d3ea084125a163c3b24fbf19ff9c1bde3f73b7b57df88ac66c2c71b431fdcf0d9b43fc24950ca0dd8664fc9280a942c9e9d9c12a281516b8279eb786386a62387ad898607a9afa9003e96fc7328f7e2f9f1267ca1f727d463e4f26f5e327aa8e6b836bf488994cc6e47d026e9f4322c96e472058a146939bd4f5214dc1671c17c16586260d8909f30a9f7650dd055e9a1d6955e3a8206e9b997cb08096b9937b68974ea31cbd3678ff27f8d056c9715ac5c58cd0ed445a2826488debbb198f8245870f7f122c11dad097068c21cd278ac01a47e774c86fe4f8f2020b4dd5c1af527f5d73e57eb72fde5f4a4a4717e3356866578d0239d8272a1dff14dbf32c25515186c7f13c813ac616de048fcbaa25620c524dc47deccdebbde09159df2d8892991812351034bfecdcdcf948f984a19203d22003798fcd19934f7b98d7c6741959da44e0ef3be5c854de85a40008d0b1c743857f00681998d432839a69fd6052fe312c12762905eae0476a3794c278c222ea47baabbe0802f50b9b7fe4da2b96866806a3cd52f2867d150f2d89b2ade2b9bd8de55f02511a7c7a9260637213a08f492e0b3b607897e1dc724e584fac365895cfb4bf1009f88bf9bc0529e1bea327acd81039ddd5f46084e0f92c6ca7997b8584761e62979905d53a75ffb0a515016c8dba320dad8af8fd1fce116b87fb6103a2a7cd435b3f727d9fed8d126d433348df60b69327725b38d67a2683f538c0e4c97914ecdbf733043192a45f6d38343d8ad5845cc5712019712d7a5c0799637a5d93b3c52ab3e45e100e19a96e06bf211d28f5fcdf4b02b06f6eac14496d2346bbd821aee6c8b164518a596d6ea4a76ca0cbf34136fb2eefca0740dc2fd1c0e5d8d9683b3be3d126c7b002ef975b87581abded67975e87040d58d0a3be1f99949dd8338cdb5528d2cc12f4d228b7013c7162053db662a702093e82385a8331dfe9cb4829093676e93600eb099d03d82d51a56b699ba87e1a0adf438f212b44b9112e49326582bd78c360ebb23b0f9498704d8492760b35c32b5492ae22ad0005d66d4150eb60664eb712d12132f8af4705b09534c96380cfd6bab525ab1703bc46c3768de739062c6fe63fa7fb2cea630936a42aa553a976acdad634ca685f34f380c38bb662a80a827c3de2c3961a77f929242e72492274fab8873c1e446bf6ac616ddc9f76449cd486221c2af91f1772a8676df37f10832e51d80b7d0d3d6f4fcca1841ef6e16640b70759070156a33ab989fa1d68d47e5cb6d8736f5d0f73a8b1016a4c14169f650cfc253dc247ef4cb6838667e4f4b4fc4a540c09f9ee130cf3234e6550bc49fe1997883c66d4f71387aceac144cb0a1d6654fcc79a93aaf93f4736a384a0b4529e3e1a9da798537d382b27f978484d1813bfffec52c9bcef7438e8fbbf503d543e1b665ab3e86b41ec43305072206eb4ee5db95870b37e0bd675e66144d914c082cb5e99cc456ef9a9f140d48a1af78c469a0b8bfd2765e690b0e8dcf6b2d7a3db0ea3d01f5356deca49ada28a20790120c5cb727f8de66de057a4685d7778c2b34e6bd0286a745bb4191c5cf7ca5b800f2ca3c0405ce85f9a3044ea3ed0821434ef5740a6341e9687133615089dcf0b8bda1ef1508f1f789bda69743e1393532e8853c17f7c6c557dcc7c74d3006e9af13a7533f49153acf0279b974f0f8a580080cb61ff30001c0f713492fe6579f609fb848e9d1c5f862dc5ef59edc3786316ab698b1ababbbd46c4c49f83fa57e58feea606d7358bc28f48336c870014071d27ceb659fcfe91d7ea6631c39683884189c136635ee63f3026458238c7dd47f24c2bf2f6bb58e43777572f16938dbfea974145f2399db6fa640761faa7d60db9ed28fec122e0db74ac9bf410307aee5714502c329a4926f12af82b1283469339032c666e3be1545ad109a612b058624a78cf24d805bdce6dea5d0d4d60316a6a3bf80ccdea0659faeab7038b7106006c2de6fe3f8778c5c4cb6b9e13f2d778c58148f7bf93578cd540145d1194cfc962a52b3ea595011b7552c75404e54a0a6ca887ef3a1994d86245693312570600c8b988a6a993fe0034d59c98a4b3340fddc619710e6940884f4e06f469c2912c020873f883e85c3fec0f6085c9252bcb48ae0f791c218e541682ca09d59bff7661c5e67303f81f4fdb6d09b1e21b4702ce1831bcb503172285b3f9b467ee0731057cdc5e7b1c622b94e35772545730cc63fa1a9b58353b46364631a5f9aa089699b601e5d457075bfff46bbbb162ec1c222a23f95e704e31326858a671b1f6d5cd93b9e9507764f1e98facb987663ba544dccd762759370ab1dddb72c3062ab6066463ca2d15123c608af73853b46014c6b39f3b752215565a7364d38899a25790ed3e49a47bc8640aaa2723978ab2c846b2a614bf964a91bff52f032b5b0c9a44b22761214b72dcfa1246af1b7c70913e613a97777ce342bb8950e5e493b0158037c62413d43218e8aceba3db83ef224af2724823c486c27f9470f68115e5d677ff7172ae9f2af24df045826e0f9996d284daa7889aab381432ed6f88b48783730a7b0e0d4a77ac3e3b1dde044bf2bb76274b0d99c0178ab5f0acb00f03051a32e92f889f98a8699298692f8aebf3a04755d52e399a0c8584043776ec30d91ff6e6e64e4149a0e27fd9ccf5b6e0b175f629ca7ae9e76a3e075881fa9ab103faafe217284a44e8470c4a937daa9f66a90d3f3732c1c9411a21ed988ef595d3610851e489c6329928fbabeca39df6dce58b7426661532d42b4e564e7150105d6ee91bd1e18561527c20d1408e8747ec2280630ef565c9675d21ee0ae9a62ec72007fd606b3ce3557a8102650ac0d42f6d4cde5f2c5ea2aea909d5ab96b1215ddc26f32af4b301d240a3a6106de35d8074b033600e38cc4cbda2dc0c483fc377d2b8a27366eed47646205dc6a217bd6ba85308a04803e7b0798f4601fb0aeda827fdc1658733dc38baa1dee1c40a6aee7fa43216f3b2acf8434591c0a131783af728609183fb8759e285da75991edcbf2e0836fc147fcea20824f223b0a50e318ceb2c1d1b8cbabada0c2cfd6d15d27ff470a3866cd226b7833b805a4833f6e38aac114c40adf52386f4dd938216729ce9d7d7a68476c052204e5eb5b6839f63029bd3fb894ed923ab1dbbe9f2fcc889b7c853ba6eaa3136756a8c13c96d8c99adb0c181f260c10c841e565aae20300ee8c163150f473be8d1457abb9bca7bd56a6fffce8f5b0d55d8520862d657653c5f405a5418b88df85749eeef8c306641667f672d7c6f010e2786fdc33529ed6474623d3c3fc4de806c1f154bc7d5f761090bd9129a7592b707a8b918fb8fe271e2b5bd5ff3e0d630cffe2c9e94c4cb4b2806326c69c20760a422cae77c1deae7c54b45dd43571bd5b5ce03f662c5b05989bb3ab144dd4d8600f53a8f0239f4de13e835cfad604aaa2a9ef6effc08a3270e7116d36b39ff2e51d360690c0612e318ba065ab95c6f0d0f3bd2f98fb4eb663f68d055518a69a9bf73c459cf491b40b087a16c0fa78451e37ae937bb940f82b9df0cbbe1c568d1195f5731cdd972953b4484eee6e197065c95fde7209e3e3e5aef75193332a88c581b3ac5d7c3d0c3aa2792f5e2449f4668e32b2b220ff965261e1632bc89e3a5eaee41b594bece66df098b626bc00cfbf49fe2b0e81af755c5a7fcc9212dba4881a31767ea2c43049c33723ddd1b0bc5d58b35e4190d2d9ab3f8693a1e1a6074cb533eb5ab35c96f16c944775feb2ce144754c6d98506b2bc301e890a83758168e708258a2c2686f6bc66bf67b26d83eae92745d08d88056830214a11f88c569d35ed6a660e9a4c2d44edd3f2872f21ec4ff8d8f0de0c4fa6e5cced8f9d4f962f7fec38080c28399581ab84fbf712ec7dfc1963b1d8a246eb5ba4b6f0ae0eb6963a4a66270e18797603eab844eb94cb37ef837123b59aaea67bf09688f61f44e14fb56833a4b2259a5af914ca61f7cbaaab66fe810fcb97bbf092e41448661857b0a992dd930263ca23caeb82aa9d05e4565bd51f10e5b2824fa7e622a9c034c89bc6af1c0acb16eb7f783b9b06372dd715d9634267fdaa05bfbc9833bb984ed074d84e306ab5cbc9fa4aec792c7bab69f13761977ea90f7b31f7a386f6eaebc9883ad86faba4f3d915bf324affc391b0e1f67e213594a4ca259d1ee92a96e4d984fe4a6aed46e31085c327f663a150b456069d899357f8efd76750cc3775ebb4daab503ef1645f6e6f150f025280da97eccf58c4b4287a13925b86f37f4fc391957e42d04789efe224645b6c1fad34f0046eb0f64a03e9b097821094699a380ec956445867bc25b74f498d729cf66fe707900f5de70151cc31d38f62fc1fed42e1c021f418b3cb3eb836940a2479cc305a2fe001560530764c469a23ed6a89d89c6b0268c706b9147aa01cd330c84fda197d322cf938bae83d3769755ab3144039f59cc8a1567b33fef5f7fc020f14ff48e6484b9e972e4c523d778c714e1f5dd9e030d72e1ec22afe58b04b7f33a28bd39e45438bb63a9b3d050312a34c09eef51d228066e40317226518a91452d3a90b63a0f0e60ff49e5a08b54fb2a2423117f35c948f721faefa0040897570273c730ffcc365baae658c991de76b2f2a1d27f362c8f6f52c26d8d8c61219bc9eebaf643d9fffc589ea7f1305861b0720d355a432af30957f9d36523b1221cd2fb426e94d14f82073259f36ad424fbd424579ec20a38eeba68f8313d72e4a11ec813bc1cdfbe18725fbb71545bb4802e7c6a2f62700e1109f878ff87a6d96283dccdf615a0f1e6267b1a3ced268b840faa0435a4baa7a2b2dfcefe91a9c668d587b5e0828c81fc2fc9285bda90bc6441a6a45bc0dce3288b2c1e6c4854ed7b89fd8607a9ab089bb1d84a35915203cd56535dfdf425a2e1f64a9e8bcaf32630b5f216ca136656444dc3eb5df7b248d63a70fdf73bedd0dc475112e343813a8d049eb28772c1702986581e6527e429ce67591d6ea5cd0baaad702815448b8240a54b59ca49d8b69d54053783b7053008d074df7970b6a30032e09b20ca2264fda9cbad1be159c878218addcd697a048a2b3ab6a0766a8c971d7b636bc736525ff8586d4bd9057dd01f775dda29e4a8bfdc4f34181870df81994153b03e23c310cf4cb7d41aa32d5861343d8ab32a584f8e134f882141050a505cb786fc9f3e2fe56ac2b776ae453028dcfeb8c4f3c392131f599e0edb46a0dd069144a3ec031323931bac37c8c8bed84f649248d9fa4bb695001eee2b4dcdffb9041ffc40a9b61198ab830088e0e89ab026c0bda19a7cabcb8fa9bebb3dc496b97dc1bc805150e56a4a229785444b3412817b36e461518711d9778c599145abf3d6d9d7bc100c76079e263d55e26460deb9eeebcbd4d523710d925aaa8f98b8594e1a8f6d67b75deda36ecbf5818766e2ad99b4ef3f1d391b62c5389373abf06a7b9d12270c5a64cab4928149629c4d82e55edebe2da33720633024d971351ea0dc7f63facd3db4256569cbf89f83b1f1038f9e7c1a713451822fd52c25e6cd5a96f16ecc6fbc28caa60946ba209d9172a5b439284b3d957707b04dc748fe1ea519a8f6707732fefacdc55e97679a3a021861a177afc0d249fa4d2bc198bb54e17da150fa946e7d98ec55ac728f1eafe5073cf1b5621560eaed6d8b958e3980b335a1d176bc5614a470b6cf87e6e53de57a71be766a9ec119562c1f0458b76760bd29c50c50c28ac6ec4767e31b585fc19e48b807ddf325037ad1ecc375437a057806b58ab40a41b2c3bec17320f3a3d4be2363589924d6e2280c068e77b60c6c7d25c727fd9651e2bf413b87204a846586d56f3481454b7e3a132703d1517765445292f8f2238eca7b5d123d73afeac362aba791a7bb45e441e336d9170fc6ccaa087fd1d27c226983f873861b68836e5fbe115088f81f3d27109a014c4e13df9b9505a609b1a1937daa1861250d40286458d1d9cf4d5ea01d30d2497d46d27cc52d30ca3052ef6562977172da932fe3759611671c25387d2f568d2b02687c31b665abe4a0a6982a2c06fac6e361bc5a45427c84ef0e36a8c15bf2bad721ca0afa9f32a23363a8b2f133f914eae4bbd2c2c8432066c74a2a1c0052f799b516ba9e09d4f1e0f376be37427eeaafc6178172b4dbfce202a61db63fb4efbc264223d1d22c66309faea7212447fb4a36897c7a46134dbf2bf843a782eab96a37a2b56bbdb2044eb3bc0dd5e2dc2adce6cfde9f166275707d74ac40d378773a2bda0604578b98487a3dfffbc92d206121a4fa8ec7dc3733f534720ed897ef11aaf7731e4eb842ffd4f9830e8cfa21f51a9efd2a8040b6c7d2e362addb6437a74069a528ae6ea8cd43ec4a62de2c0b6917cc343439eb40dcb0e8320277fda44ce1897578212aa4196313719f990fe29d426936c52cbd8f5f5c8dd009dd7c530e237ef78216e8162d0dba75a2dd26866064ccec7911b308d00c283318192e46e449657af1d8bd0f08439b3671ac46badc731e4f086f3cb0c6a56609765b8d9da8ad00cc3e68bf1af5636ad6941f9190ac8ff1cc96a0000eb8abd5ad63949602b9e6bf490c8e84c971488b1b2fb6a07beb639cb1e648e5fa7d889f50e5ae0a6c440b871e1e60aaba596a2f055a00c775f779bc89878e9eb29f4a9a91c191a426154fe25780a06d1458845bd0c16b44e6434051119821abee230340ef5fb93fd9d9b9ac3064b40a69164499ae8da3d5b7982d6986b044ce6d29478d75b67b59432c2ee6fddbf9b82418df34026920dcd4c73beba72e26d16c887ac3369815e6e810f8a275424a107ec4f6bca411013c7f38681bb380da6e5857b80d1d41a88dc678a2d63a95aa5aeed55d5b2f3c6cf32549c53d0762ec993c1316b7eac9739055d7c360c18d4474c2c06a98f273bd95d5909324293f07369f30312f51443e34d11e30912dddbe516512bb77a84a08d8f3bb2a452e44456cab60d50fd069006a8cebc92efbed3c4200c0c2736686d6459a283f389ccaaefc0202d7b36b0aaea4457aa3ea19c0ab98201008f7b0cc277f34ad8735cf0ff9d0793b8421787b7bc76339a9fedb63edd002db08e8ee1f2a3636ab569a97f9565e8c4b35765b87934619d6ee749b4743b108c5241aa82642b4250b7386941cda118a34ac5e08ea80182842519adcd29b0407651ee8c3a2f2911880fa32dc915ea9472ed1716293a94d0e672ed8309edab30da3654e0928f19e3effed85766a890d358647be4646f40e19d2c56ea98aafd5a77faaa4155a68988fc37c1a8ba733344a18509d389cdcfaeda4a69083e9393cabb7cfd2925f3e3e3d1a177830f951ab0f1a8ba2e7ab4ce2b030df515f0919cf29a935c42362f8428cd82d68c6f73d97b3ebec2347cd3f66e6a41f814804f89bb1f81e282c3a6497f1f0244ced22383aab588528c827ca7d74fe7ced6591142e68006456e08680afaef6af8d1fabf8a5aa29580c04289ece3767258c2aca7b5470ab2af859712fece38d68bc59187e854f2b703bff3f1723ad00ed17ba74a7252126a8f062fe985f19239f8fab986a1f6bd0c957ac2da66c5c60a0209a0c16a4007a3aa300b714a1d1c6b8f12c2cabbaf3d5706f5aa1148711bf0e8055e0dc174146d372e1bfb6a229ce9ab0903ad05d0b9baa1103a5613c689718f18a46b81aa3653b726ed511711dde9f51dfa1073012e75442ae1144df4f43572d282b791af54ed1f7b58285f270d20a2f9d134ec749ac9f30e1abd5e5382580d82c974d7797fcd2b408743aa3d6003b0e5f05e681a2c9eea183a55523440307e112635e606c06134e8dc769baaa48b32eb73b4bdc914b6613b47d80826b477ebe5fceb340d772295b93f08b46fb94f354e2298a66823d56c5a72df8323343e7b96b41be075cbae8b6f2b8a402c26d1f618a32f0dc9b654d5bcadeac519a3ac4de23b7e89a9cf92e7e5a1e7eb625e19baf0eef1ff7c9cb5b8d137930bc4de9b773d5f2de2f3b92d819457c7ca1accc79fc2d0396826061549b3ffdb5bf2ddc93cb497e1b0370527e62b0e3d9ccea4014a362d74d2571d8a6d094123ff7b04459b796c1b1548654c02792b88f3ae50c0c2df5c226584e640a6a0df1b4b9bd1c4aca937b600267d62b5b255264850cc966bbe1e6213fafd47a9767c476de260b9115ae57de82b921e72a1a914529a5b1944831dd6ddc8bcd83db00354af0e0ef61b32e73875b3e7cfdf1db0bd4db7b609b842720d7274e2f772a17ce44a358bf7c02d2799d3aac462028734bb9c83ed44614d1d3d61f9b36c25ac6d121d85511442bebc458a9f781992bf4b52e35dbcae93b06b6d2cd506d284a5fc8f2e23d9aa553020c8764f2418cf9362a55ef9e8297c9d2c60f67557ae286ca2cead33dc1aada41852ca2b61650e9535ea29c4e25c4e1422901b12842bea25d730c683d0204feb9828cab7d5b6891c96096170f6fc9664502135456b7492f1b2154d10190014d5fd3ff8087b441b5c061b7370d40c495e35feb317971b8663f8373cc85de120d820414050ba7ceeab26735a8042c50a3abee020163675c1713922b5bf824fa5c4cc762ef0477a49b7ab2ccaa2f82ae68de12082153687bd5e3995851e1e95b297c1aa059e39e60c6531e0aa9f12bac35796ac90b56189a72119c1327ad4595695c30875e346fb5206193f6324d1b097d408e069519aeb4266f2026a036b437f3ad3937b3cf1d6617759288b0bcaf31d1f57303e5238ab079b9187a440f4687b70c3ba505df30308f9e9f4412d027180766458092d03e8c48ef9a8f4ea5623f7074ef2baaa6e4b829d2cf3931e9345decfb6a07e7cbccb7c769d16b5c18d15d97b0946c4bdc41e6491c698348683e3ab6c84b5aeebf51067b35aa67acd3deccf6b2688a1dbf1bed15c9418e559ed4057248fcf1099bb11f333808f9bbf88aec97a32474ac17c7573ac9dc1b8dde113e2c68239d5627d55abb511c63b4e4002e41d0246b2b56a74dbedb2c4870d68f1a83ab05a3762b8b0361261ede88e256f0d03f733848bbb3646ff443a4da7422813898b1db10fa73ff3a972a37f921660dea2e228cd4a645491bd90c9ad9b8d669fb804c6c1e3a94bd258a8b571624165dfc44bd87a6622d8e5eca56bcaea71dda525f0cf007beb78b1c698583d154c8f495eda7c7095ee0b751bc91b2792ae8d59712770377e04790ce791747425d1bc4b8e60b9104339f50575a2ae5118511c0e6011aa050bc5d1731ab849f9ab0d2616388a90999fa4b1f14b7d47263ece9fd25911d9e31140a9abb23b3db4baa83628699e83d79996ee29fc5b40773835d475c298e6050b82aaf5cdc045b38d44c48e29a24d84ed4b96d9f55a4692a71410e89d3854474879a2bfc20d2344fa47a1dd47295f24698a4f7db465950d096562ae73f82a1f34b285063e121ca27c1e63c83f41f3ae7b2aaf1211a98083d117dd42e2c5ba7b34f6de809fa3e79abb35452f8252cd83f2889fb3330505bf22939d40360a0c5ac8cf0f6602a8df576b55ed3c4ffe60ee54b5cb8969e3cf8b9f7a8ceedc91bc632fccf19fb339b42c974bbddd6782e24f5ffa72fb9d29bde0b5dc3bf56af8896782df8ee99877b6d7ea0e9fbafa8181db35b3dc42d6be2fdc681983698ff10c4ff46d895e29ef000397e823b4f0a005f9fa242a49bbd0aae74532de36b1256ed519dd58c046d09c8d37b4c78120677427ef594734b454657ad410e038bf67ea4b5726e2785c28f4ce5c258b5b289f9ab9eb58df0a905588ec868fe49faa0b41817c04dca81f9278237c218802136f842f0c416540c104def7a619b508331d6024a75ca279a7322a18dd2964d866295be75601ee8710590e9763b469d87fd0991631bfdb9c191c3dc5939306bda24208647fa384dd284ccb3634c8f8ab66dededbf3fdc5de98b701e5bcea1f97128666d866c78a2cada14a1ee0cb528306bba57a840102f0d9766e79c1253a80aa1e59716cb26152c68fd5b1846a537bb2063438adfe2aeb66b6648b80f77a4d14f1b68e33a451de1bf67d97a47144b90552380480a2c5b4c682b460d286c4fea80b6b00b0e12706d9bb8a3513b511e9be71f4634b0d21a3ecc90df9f1767aa495481a71ef8fae908fce2ecc43a1456ab8461bff14214143707b3de2e79dc28b5f355063a5ce68fe034ddaedb3c7eefe6e2a328f8571599145324e0222e66220e62cd174485a7aedd3db5e931acd7c24e21cd168b3ffc64ce9289f75726c37ffffbba00f896bd3a644f45f3ca09aa9492855987461cb3dfaf7fc97c3cb92f11c807e2e985f96972ac1563aa9220de9e0c6fed1bbc3dd27abdf9c6c6b34889244afbb93cba11e12c3890cda75e0fc3aa52bd4131900973fa0d8d96fbc7b8b5e21dce918857c8c9f9db35265431ce1b04f694c68da7a224af94d5c35e6a5c1349570eb8532a902da7fbb99f34d9e9ac980ce765aa1cd52917f8d5dd8a4f3ada09badfe433b13ef6788703abd68481ef5a6351a853e56ecdcb0d7f7d2741dd50e3f4ab88293a0e8b5598d0fdd63ac45fbdfcd75591f163aac212287582fd470843cec4ec8ea8b0f97259698ea9ede799151d56d2c129440871899d09f25749cb3340189d0d655fbb6b659377e0486a5e00c8f2636bdca1201d624ab11b009e3a89133ccbd99d7142c73e266c3e89724d6c2a0743cad396c948c42f1eef48086277f130a7d72019f76bc40237aab0f4b7e6854f6b5d0d4aba3c6f97ec1e099de84a0ef803bc4e2534e9586242efe3a4a6d24fd93096c9e7a844963a1d1404d6ee6b09a20883fc79a991db9b493e97e410e2492709de656273b3bcbb3bf7601e1a7e363fe288540e0b3bffe52c0b39ba58293c810d932bba503ecbfa3e3c98943b7c65f9b0891909fcb5ce292b23f41cb26b66d1d4fbc9b6aa8753f631d48a72cac221257d6a08bf403aea5b09df43e06f39a5139a43082531c873dcf77038d744416f636ce3aa2442eac1844d2ffe10b545d2b77b4b0d906c58b4c4cdd24e5fceea5ee26d143032eef562d3e16eb778117fcf24c0f3e5b42362af5938be381d4ce05ce86b8dd20e861ff8578e8864d2f471484f5cebf37329d49f0295ff3b02cd17e2e7f21bfe89d4588d52f47fd7975eee5a8f41735bc3242a039867879ffb818f03365c4d9fa9e8357db553df3a8688b7642e1f0f7d673e90a2859944c59a66d904110ad7c19d4fa19a27385c00baede75a6973ad20931d90f611208324c13e213f16f97c8693aa34b68d4a49f6be4ef7f11d7764ce4554f9f5abe24309e3bf1e2928c6548b573a1eb4483cc44d2b92771d74cf3ab906a5d3d90a395893de3bce8e8a33c93d4e0c2a654630ef28d121c77d6de5d04082f767e02ab0bbefb7899cab93d5b3ac8117009a971c62ca238fc08d0bd6f337eaa495eae4afc5b36814f94da3883dcb6630449d73e951060be8d796fe838e297f7469cce5352cb6a04effcffe2e324e326f187118698bdaa11a034fc5387655804e7b4fc50133e67318bf190786019af2494e02cffce085652fa99e18ccf3b927c2fbf2fdd4850b463e3b0aa0c439f89544165f371e89adfe927112bffaa7d01f4625d221fc07525833ec401e22d06f5a33227392ba1e7307c329808a00d467e15c95970469f11a212c6cd8a36e30c0232e692409d3cdc85860469e46305f7566eccc7b92d44c1f6b4456be6202b24089abfdf2272f75b0f4268cdb18c03a51a22481cd829c9189eb420a4549f1a855c085d0525eb011858e4a372b242ef8e5f39387e7dc529b0572233cbfd1528a08cf60d9759ce7f20cbe778a60e2b2a367606592d1f54e4195615c94bfd4429faddec68e0077f825b6a23f25d081171401c47d59f9ba1aea34320fa93b798f0085265279a73ab7d3394da5952b9ab1bddbde9cf35aef5579ef22d6030a493ffcb84dc7a93694edf862fa703a982767f702c361ace7e466b76ad3cc5cd8610848875551e9261b12dc99d02d63e826e68f39456a713ab5e8bb7ffdd3bcef8f358a56fc6a5ca4ceabc81fa52871c93769d31e633058d96e96d1acad8378ec83ef1743941c7d814e21c753458cbe4172b63f86c27fb0de6a41098bf919a4adc9aa2ce3f21ab7fef26339fe9347daee1dcc3b7d47a9790299023e487aab10d8e02cb4a8c53ef529d9934eb8967e6d77a33bf6efac2130cc62d1e532bfc1b41d5f2005be5ffe8e1036c664bd73c104b40d57d172ead4b6520deaf2bdb6ff5dba5d006a559abc422070ad4737f4f970580237634b68ebb903debeaabcb3397c67c4754671a99c3f3579145b81b506a4baa761a781597ed110b97e78eb3a9987cd93403ab4fed0c4fee7146e058d50524284d15453d5d5f1e6152968b7730c45c32f690b011b5fc409a1b817617af0981794e9171c93e293f3005db3dd72dbfd74f770395927bd9828a10bba26a88980034db73335cda3b302d8e3c5e75407c67c7c43df80a809ef51ee07db7711ad568bb32e5b374a375020f03ba5461d041baac20f31483837d05a4edbd5c5ffaaa26321b86dd2f6692797f7cad43aa1b18d38301680a0c36174a1a980f41d8871325ffbbb0541df7e8c61550ddf35d81c3d1684992a3473a5005df8c50db0ac9ef4fd0cae1939ed1d75708930bb098b518ab64cb8befe6faac889d19764abdb651cfa8938215b9e02e768120f35259c9cbdaea5b4f3656e662d1e202902b38629f02ab8bf472266ad73320b9f6f2a5eac226cc7f1f5ec0118f939f1b3acf9b4278452cb42b5ba8b0ab4350237233b40cb0074513c8e930cf1f1d7bc22a7b052f86d8617d2f35d54124cd6eacd5889f119540342feed2d09f62ea1013826968b6fdf46ba1c92a80eff6f0f1818a20370d02f62b662915a6adb9850389b150b22ce97b1e22768ab4d7db3268f930fe3ccfb1d34b3129963f300be678cad901ae21fa7cb99f9f1b91a92325fc18f91bd944137e4fc62214de3f8377e16e5150ba2f56ab1205be90102428a5386e8887355f3aa4a7e2864d288c056b336cb87e629c2c4f19cdec063e15d987f4b97b4864941aba20cfb64a6f03e379c713efde57cdbf6cc7caad6ce11966087621e682e22c6d5b8df369287d55b3900522368e7db70889b0b18b8cc4f7a87b560259e69cf969c509890f2be1879030bd1c2c925cbdf2f24cd1bc0c35c552da3b24bbe02bac1329881abc1cd7135ce200b4c01667b6017281d78496274bd9b4042c7069a34b27f4971d6779d9f610c65b4211ce832f7d4947def6715daf1b899cd8911b59303224eababd61788964b60f962705a638d26c83e73b26a90fd35395b95c4f9eb6def690a6f22e2a865a03e04e65164a58dbf8ecbf4ed962b1b045c73451b020fc7823dc4268d1ed861270cc7e8d0ce22058ecaccd96b13a127116a570af520008a1c66855f547ecbf6da1d6ac4ba327ff305961d41cc02b82340dcc6d2f198dfeb4ed998e1cc2914177adbe73f9d995fb96aeb0e03f2e86fac84ded4355642c83c45cf9af28557a1b274127f17dec6f42627e9fba8f44e621918de94aa76d6252312d636e2f585c765ace029efe0f8e3668189a74d8b6f10a8dbab4d9a62d81eddb111af568371cc3b3f3bb4b44aacbb4ddb0a3e9b6e77545726eb98cf5778681cf9c242edfec9eed37e66c58c6b885c6679af578e3069345727d8ac9b71bca6419990fe4e8af8896b3252a86dd3e474ed1bdf0668f73b54c85db13886edfa36cd14f2f57bce937b368d09375a24577d3760167a6cc1fb19bcfd18820213ce0e0bd89a6f2183d51839bb9dd1b7deae3e01c8e5d84ac6a7c7bceeb67d8bbbc67a425eb72cae6291e7f2d563d2b4e0d318887a71e67f93329f073ef82172c2dd24b1ab7100608633a3fa0573ad2d32974cd133c95d841a9fad651bf08b75e0c0699fad9a2767400365b77f1f1b39a420f07e8089710dfbaa14ea0f5ef08a112f841f80ac87f4b4be079a661e862b2630ef25e3868440f3c27019ade6ca46b5f8f36c131eff630d967ba84014916619a1ed5cadae250f9ede4202de4933799216c12fca17f77aed5186427731bd5589f75f49814d429c7db4dd4033c07ac977de8ce5c837f16e2869dacbda14a00aa2a96ab89c43792f3e255471ab030d98d7f2ad5aec5e765b9e35d6f1c1c109f52d2fd2864c61c89da2724f414519458125c1bca07ab929ea6a5cafbc4dfcc87bb1c659651a5a2909aa0a3970243fb58a461bdd82c8543978d9bcff132008968433c1508baa8affc05d0134f061966e0206f4d2c06eaaa595f8af87d445ac37128904338afe48bb8fc7716c1d5476b12d43d9206852a251a68b53a81baa28b56115352f25c1e7a7fcab9f9f72ddacece40f669a8b4c0ebdec05782ace22cc076125d07e581049f7b153b8dab3281105b283cdad25dbd6b27dddf02c92fe0577166e218ea6880638cc75a8c5882a139fc164bbc9ad212a0d5ba8d71246b9a9f62d678c858cdb525cb206ae7cf5603fd687c5aad19344ef181ca07f9ca6ba13ef91a132311823228d1861b477c0bf703e8d811248a210f45aa1a00944c56c7e407bd15609121881d2ff559ee19be6569e23c4d333849767fff36e8521ec7b8a275d89fa19d5bbedab98ad7d5601890a433dd101a10f3018321340c39afb85762932251c30f0f20baadb7c0d545f19d58aea3609921f60c12cff1cbc98b8044e4d34412a8e949e384de32996ea3cc2832fafa79e96fedfbf70b2c08130867f11380bb47f794c9f305eec75a5486168757c929f9c4e964ffe3c6b12cfe99dd53f5dcb35a84ee4110b2c2ef69b76943a8f18ce3fad2dd4e454a92bffe1d419f1887433105a49ef91040bb6a0397ca16d23d05347c58e9716135bd393cd990b8014b05e7703ac091d900a5db7f78869a5f481a1c52ef688d18ad8829134fe89cf46c4740e9199667995cae0867799b3ddce1644f0297439c59082a2fce0d091787f2e6cc3f275d732a31d4d9df213e65c2aca3557a9b6a56457a378c8b13b35203ccc583d263037519f566d053fdc159a52058b2e40863f2a9111d6092c0c465534b52a0a5b6cd9c4ac855230b0f26b7c78846bee87c00881f8b54cb1726dc08beec0bf82ea0f4a4bf398be3024b40299ca3da5706f6132e4f3a760e951f03c809ca3c0f87178770f122dbb57eb13ea0b53552bfdd76ff22c61720403cb9c7c45687f0daeb0422737f4a1bda05a498efddee2c47642d1e28a41d56e8a9e7a027c81f2caa2166bf217f5c8c20d4319b353b350a92aaa9c1b425815608d6906652175d1e89fa88ad934f0d4856bbda8645a174286a01f6457eedd415481a95af58cdada3bb01652a585d4e0d2e6be4b18a30006399aa641e212be93651f9db35b2bc7f4999fa8343cb45c21df2e6c43351d950f3cb16c034550ef895b498581630765fab9a8a458024721b1b74df6f4a55f051c1fc01ce19e394618623fee461a5dbf48789573308421452593b639b0d1f0200cc13e7461c31cb68bb1451e2de11cf5648b1e1440aa96990add281d1830ceaac377b64fa720a184af1b383fe1f77bb0e9fc4689111d508031524a6f50cde660bd36e92746c2af5b4e74f5864d4ad061056522d2e1055b23b96f0befdce189caa1d2afc1d5755cfa9d95f18a628592665af6744cc931d75e41fabb4a8643dbb15a9cd069bf49ebb7ae64b2c6354708c9962d93729ac9f8dd3696dd7281fcf4f832dd3021bd219631318d33a91b171744e26b30e2ca1df459483f4e8f299e39691a091a771ea4b35e66ef06cf5222bf790fa0f8a533926c094065d789bc1622c78a60e3b7b4bbeeb9ad577e671cbbe0474cac8c1e3b37cf511ad616942895754249c24099453cc805b0d5bec06696e082e1cc4f91b4341235899d5550bb9ea6d19a16ea0ade3a465a1d86162362270cc89f15a3144f8e1892e95bc2153800ace6f54ae8889c3c6c0ba231b3edb1e65d1839e89cc16f25a65d5f63ff28a789e9e623755ebef1e10c6d4658d4501b388b60293f687549fa4bd864a5f6ca42276de88e144b51e5569a95848e81ebda69e26b50390898a4c169562a8331687d9cc318b209ed58c16011930674411074d3866640cbabe8b2ed979da4c0f18e776ff054620acb1cf70b890ab483834b92b730be04a7a5a51697b4c0711722b35dfc6ca5d0a75021516da1281f9584fe0561dd0ea61b4ce2f124f6e8d7eb72fc51222289ac095fc0d8831b66a6456728d66fac2e39f29acc3b27aa214744a2eba89a0c49346a24577b740f34a0d296e4c5b177ff38eb742ef8ed76f47bb0877e1069a37e14ca73ae65f259b3609462914605251e19020f4072fbd81ff3d1329bc3c81d7345a02c9cf8e9689e0089b8c3a74b0e94c98f92c0c3c25ba8c5d423ae482dcbb0e6363c75843a4b8e6090130f2fb1abb075da3ce327c91b6f68d021726c83ce78561129612b57fd2aa4d4c278e66084a55a23e06d070b5d65283eb133dedbf1c71e186bfe5b08b944405a501a4d5958a7eeb27d11906f0db2f25575d725a0ec06b39bbf85d8ae8538b6cf563072134ea9200288409562970ac36ba1d3454f5f980d731f8d087d9b6e67e6884519b436217cbdc5972cb8af133c3846d98647d14fdfc4e6ed456d9256cd7143e07887b166dd538b20ad4806d751eeffd7da7e277f31e0e0223474aad525f2efadc9ab8909104872edcc575406543e111f96a9e8cd3202e59ca031373e787639a0d03c511d2a123e77c24e1c7ae1440205a472a524582200874a17ec3d5428f3a8ee4f04ef23072bc6e635a89b8d2715b69f482d9e53d608f5ec1b86a05600ea740d240ceb085850ed2992383d83f4432491c82c92aa465418d19cbb4ad7a13e67c299a072129f470b4118925ed5e1cd915862b9c22a25147bab781243608fc804507e42321b70f906db8b4d2df42b7e84ad796905478360a32d5685abf177fb3b75fedd93ae97f8f3bd3fd7907ece0821d68ba187427bb61e8ab54e2f9992e7b91f0852566341c27bf01b73052ef5b7d71fa14ca703907b6f353bd073fc9aaa73f652a6aa570187479a96e8c9b1ceeb99b08ea55a90697bb5ab1cd2270c2e9645a4846cc97f26cd9ca6544d9ef4349c4b8890b36b091ceb3f4c7f99428b0390f5e2d376501a1ebf234deeb5c1d60ccb79d531e45e76c5be11a91bc1ee85fd2cca54f1572a9353343422b34774213bf22f916502943e4042e119d2c2ef0dcb92f34ceb239c1ab79231964744b7798e7426f754af0d319a3f4e7e184466ec101275754065343c97e0b0a4cf76b0cf4513f7ffb9b2565468e0c94211025c0109ea7411825fe9e002c88d72c0231173fe6723e279df1de976214418d3c2fe14f9db51fa29830d670906ab40c30d642b226ee9f60fa069961b14059a050200def4c0dcdb3577ac48bfb00092f9264b0ba1ca71946a901beb7a7a7bcc0545453bc4940896c7ec34c020287096fa42f5d7e39431d908bfa8955f55e12d3a72b64fecb68ebd6197c7b63a751f228bdbb72a2648bfc4722545354d9c0460d77210340167941474d82b5932264217055b6b73b881ff7b1c11446644090f264a6b4a96c243db161d283cce45b9e600cc7ba8c05db4353d9c7b64396bf2e071ecc84b0786538f985dfa85fa78623027559ba6a3372c9c1868c28d6aa17fe2c1d0ffb39acfd566cbd202421c9b154cc55a2ac963fb53897f9d333903b7249476e838a500bf6d6aec65ca4c15fa3f9be688d609daac251a62c7a1316425e2c6bbb483cc83d246e1613361f4e5881d8d1110ae054a4a4a5792c40f82d5cb20a9e04e130a8d88ab1970a903f1ee0ecbaea469aa66e81e584aba9b67be7a40db1dbc42ccdd2314d93f7f2583ff3fed118a610edd23d3640c983e771a0fba5366c50ad051a26cf2132e4e4960808cdc5efe1a21fef16c266fb00bbf24e272c7cbef8c42349f3972dc85833e2a746111669bd8c8e5b5170b358f7daf8710bf13a81b3d2bf1ed5d0e3a053e9760497292577a19535ba174c861ee88b7392b59cfb6baf29198c0122b1f02977d655642f689009b74934b0b9830d292edbfd0f99a341f3bb52c0927933911beed2e64b5a5796f721ef99008883119e30bb52d608560417bd88fefc6cb586f2440a7ba6880f494f7c2ee1a841a08f4849ce66d27c114861ba430e4d47e8cc230f6fb34037a0b8d2e015d439f9e64de2901f9345d2f7a6b810590779b449eba70fa8fa888949a552289fe67c1bfdc6ca2fd0fba9b07b0d25a322f97bcaec729237c01f79d5657b8ec8568d34b8cce917d1217bf87af10896f1861451953c7949db2c4880a84c84afab0f61968ea42bfaffae30d09f4e1c387965a21370cd74d3f3dba26ee9e76037dfbf12dcfe92715eff808603e2479d963a0cf2c0ae1d3b8a4de1d289c23800a46748cad90b87db5d25ae5e45c9f41922c6e4dd025d8e59790e46575b31501891f1ba9d52a8bb0c5ff62e910040344104860f2ccc7023505c91c2f7b6e0c02f649b6e49abe99f768125d9c008528dd06256d7463c2139340c13cc33331b1f974bed10b06bd4231ca335b14108c96b02557d4952b7967699892e30ee4f06de485dda2f84e9e31e6d5d0bb124cb69bf3c5888f1400e45984d8c19966f611169f1d1916ab02e20c11e497eeb3b3e82abbc6f7145a345b1bf53c07a9da070a9e6e18286497557866e5956ba6263a6b15d9e6ac0669efcee4c52be8514e889e4dddf32c71e0f469f3ac0e8998ae0f4aa9c9014ae0cb2226e9c4b678897af5a0946674917541c042bded71004dcf034e965d3e03c2e7cd1dbb2cf988173d1ad814b806d31f5c1a40ff00c28786796ed2e2d0356331a884bba3f01b83347684b7eb483113426c0976c84d179839f47163b9a4b003d10d64e44f4eb15c34dde2e69f9553fa39d1d655e25d33082cb9983fa91c6dee441bc8182de776925cb6257fbc560c79f1fe8f6ea5f75e0e54e6c19a0173c61d4d564ae11ec229fc420cf1270bd5823be97f272c31ee9f65506b1a03eb655ba4e83254c648c3d53e00db9f963732c09104d5886e89bd3fc5f01f797730aac405adeffbd14a1fc14ba6040480e30f433409582d3b047476a47fe76c1fc20b92efd06a150187c711c9c6bf29b0687f78ad662b3156b74cfe648ca279de65bd9870bf5f35771a354499b3cb51385639e3d4c44d4a69231703cffa9bb1e19d889cc0718ecd52be503a6d5d5c948d23f6280909d56eef9a59178d2aa36abd093660c7964e5463911e8bb363975f54421d911b7a7276ca0f6238ae955712eb65ff003f6556f129d6146967ac25a9768761bd31526ed8f2cf435219458fc54cb2e3376ab14e33b719e70f7faa7518de98bd294da529be1775fc7ee8e57d0834353a30fd052ae36f91c3beaa7a03a4c42a883841ddea93c85de5bd14b72af5a089468e1da8aecde70fc97df0835462d1d9251c60122995437d613459722601d6cfd2609edacf6086f98ff7513ba940f213ac2e3f3c09041b9ccfc182bab075845b68e25c7c4f9ebab2eaadaa3988e1793b5af9379847e5a7f6526efaea48ecb609459a770ac3418c60ebb463ef06c510110efefe92a291d927b05499899f70b01a9efdb2eaa2b0d08cbde47af0b3c863a2ce7a4b5c7fedbd1017ad30ca2c42bd09770d5228a145d298198711f68801f7d8cd7ec8afcac83c6d223b8513cea754ec1df19497d2227a1d9184c4989a114a2394663ab4c78b24bd97cbde9cf912b3ccb168e07eb0dfcbc83805f8b3fccf627b459cd4878908167ef9b288b1cba52cf60300bc4a234ab776b978ef5d7163851f5ee7baf9f697ee5e03189ea3107df87c2b8c821c4b3264dbdf3b29a0d836f165b6e5767aa628109a30dc04409cb1e798cd4c7aec8b82059e8d903b5d062536525fa6156d23bcead481f190a4931a0b6672afa80db1936539111e773cc0b7f0ef5253a009aab9e524748c3ec2b4f98fd012b7690312ef493a4b8529dc3e2566169333c9b535aa5d202ee07e20dfcd7a296c573cbb33e17ffb8e409786f58ee8aa24b113dda5e11eb1b3319de065204629730c6db0bb12b5372d9287ce8452062f7912a1e78584d6e890c97ec520d11b549cd711a0949a0a56b84e8de3e03b90dc5b56a35e0dad3d22408b27420bbf9085a0627b02cdf6f0092c9658f25f814b0d1e1f3f9355245c7a7f7847d23c449346e62faf024cc5a3ab0313f982abfab15a146124e6a67d6dbbb688506271cc19033a5dc6785b30d8554d0775e59ea49176ccd1929b22d2040a364b4ffc3b47b2078c780f64f54edcaa792213bba4b0078440f061351e367dfe3f3ce007ca93d7fc850259fc570c26d4a89519e16eb71924b6b9166da295ddf6dedde49652ca24533c075f078f075c24729f8b0841c4d3f9d16b5ebff2d16db040b35086a2bfd02b165241cfc718bd5d523c176bb55a2d1d26584805b20f39c9479d763a630b1f3d7a0b1186f8f1c9474f4518a4973e167d08f343d73f54999ea37031f906439c8f493e547dfc2325e062c5c92f627461c18de036c58dde793bcc36b1063d5723cfde83ab9b9543f31e5c470399985ea78cd46b774f01081af4c46771236a99d28e43e5e8bc07d7a11d58bb8adae6c8bb8b1ef5eacde0c24fe71d1bbfebdaa3e1e6a94f6f5aeaa518837a875a6117a87328167681baa52dbcee74b0a3411d55c10eb4af43dfd07a5ec1715c6cae6568bd9d3929ad55d36cdb518f82ecbc9e7df368cca73f1bc7759de791fab20d4754d8edccb7df458931364a8ad7dddd6c43f5dd2a5d44954237f5ca4a5ce98f60e8009552c9b4c26262616129a9a4b0b0a05c1616968f85e4b1b0b0c02045bfe18ee0b8187bb24b297b66dcd1e8ecd9b7282e9dd5cecef5ec5aa93474adedec0f0cccec247d9ebd8be276e792146640d67d3ca7eb461b75fa16c5fdbc1d9721dc087e1e0d98bf285f8a8c91d218636c1bf2153995141594abf2913c15151595ca2da4e831c0acc038ee7399621bb20d7199c2658aedd571caa0efa1b631093444b93381ec71e3d09266c521298786603616ca2124bdd2bedd4a964592e4e94bd0c678b8118cd14ae7647b04ce3aa79eb3b6566badb5761bb2bdaeb5d65a6baf70fd7d4d5ae7969b10ab55bf0f044be349337db4c5ed5a756dc7e346d0a30f379b95c3824c50ea5ad3063b9034831b9d70d1de126e0e1ee4175fe8905801adc343fc42870432d179f476463e472846795ce7d26b8742e1d07f830eadef9c9b9d871a7987c2216ece71ddfacd47a830150375eb3ab43e07fb231f81d42f4b8d1ff0129cbd44a314d4c04b9f5ad4a128bef286ecf823c6178e7f19d57f43460f4816f5ca341e78c93a141575d84b80951d81508960cee608438441c60825095efa8c09e8cf806c1e272c257b9204df0df1db67d886d993898179716939b1ac984a2a2928f723791db78dac56e994cd366c9384f4191d639420b70ef146772f91524e29254b2925bb94523ee19861e88e31c68d1869d4d00322ade29f3ce79c737673ce39e33ee61cda3766ec40113a2762115440278c939469adb5564989b61df0b43c6d50659d13cca1299db3d64a6faf426a3d1a34afae7933506badc68308d7129756a7dd12397ab8d1b14c00ea3946de83eb6c5b650250ab43bf05696d8f86486901e80866a55ad5344a2b9550a8b55a5a6bad5cd8eef2122aa5d1867cd1dab4883ac46e1d67e3e608e7547fe37e63027205901bdb728b5a6d9cbe32adb5d227ccd36ce245d4d3a384a88709252ea2180d5cae9e2994c043cf6f523481ce968c2e3d82b30695c87660285f52c74fd9f3f306eda3e421e29a9e5b55a5bd37496522f9fa396770e7a41e969868e52b587b5a251dc6c76d241fca20db5df96a214f08215f752e999146a74d298db463bcd4da189d523a279db376482082f7ea9912beabf994de0cd56775eab63abf56a96b5aad14ccc009ecbd9152526b6fdd541f9efeb400d6a92169a4b7fcdce8d3e24c22a804bed27ba21af7f03aa6be39679d86083c1d596da46916ec00fd0a668082d209b5d6da94d25825d35aaba4295075c1234a212f2484ec8043e081d6711b65cea1be669b507195ea26bc21c770ba941a92a502a69c4e28f7f2c88eec68e496d62fbef8a2fe04a9125a9b3ea92e212f24847c32273cf15cf84983fa695bf8c4399acbf0719ae181e1cc87a7e78e39de4656036df0e0ce39277351e794f13d4c9854ce392538a30f1428e06959c004e8081c75c8860f581baa9ff65e3fb14e9bea074eaba49fec4906136ef41087d63aa7ea6713d6d246425b333277553f38148a55d4efbd2c3c9df52be86c43514f552d4792e0846afac0559fa85a678ce0bd41d67ae7c8e79cd3d96b756d6a5d022657a7cb59bd19260872ed716fe914bb6747844a14c8d127385ba09e8008e6d08f9a4f5bde20bf488216f35e785af3b4e4a99e6ce40956799db5ee6ce4f3a14816938dcc28b884bc9010126484a0a048238631c61841ae241f8d001a23141bd1cf4f6ac44fcae327ddf1d3e90f38f415836d743acdccb804bdf4de549a046d3b78e974be70a0031cbc7e124da1d69f0af315ac43df16b556cf07cf09c29c38c6384b4f676863536f2e7294d9262cb5bc3ce29cc82520ccdff7e1a55f4115db48ef86507d3715b2d12dc1aada7d9d34d57ec0dae8f80a205700e9884a1cf588a231faa5f39e4ea37b9294baf548dda5051b4cd768774ba7d84d57f0b2dd075e1fdd8587a7809e606b317b2f06244bf309d6222df6afdbdd219e7da8d52205481d0db4dc15377aa80dbd64a20f35db5d2df6808411b4d774a2230241acbe78d49790fa42a20a095a2188a0a0972bf6f3fa8ee879854dbbdf88abb5d6ef66d3421910f0fde6374ef23a1bb60f8c669d617ea5ad9a9408b59c53a51234f4d75ae708a6fcfac5943fc126f2de52547d8cb17acf52d7f9a7cb39d4352ffdf47b02724ba77a6ad58d116ee7e18ded5a70e35370b2cd9caae9013621caeba506c6ccd846965e2f5f1a18f43eaec84da23ea33906f972b61069956c09025b52b6b8d1c316a097324152e038a097ed73c2ccc929184a238d30d2615ac5301fbd63937822c175b7db638c31461baa8fb1d452721338fe6247d953d2f91b609b1a285b2d46a3bf06b661afb951d96dc46d9da7b21dc9fb48f743b92976964a5d89db46a592d54aa552641752734577ce12d5346b471b67a4eb3c8f44fabed229254545a5542a994c2b2b2cde4e113b319d4ea7d249e5743a9d524edde9c46da791d54ea753a5a7294f1d5b90b2344bf4543f2db6728c46dbc671a58e44fabed2bd2514942f25e553515121a9789d8a8a8a0a9db25522b7cc4969ad5a6c3dbbf5c299d9c2303bc7b267c791f102d7759e47fa5e289dee45414949515129ada0dc8fe4ad742bdc365a59b1dacacaca4a64174a6bd53495b5a391ddb69b176aeca8a66ecdb38fa436e278c4d2146ed8d118a3f37161c16d90e3220782b6a023b6a018bddb5d5cb7bdce594219ed8c2ec7759e47227ddfbd37cfce31a3a0dc9d128dfe5ba2d1cf6c6377483edc23ddddd35e8e79443794f1ecdc4ef77594936d3c52c7ee9e51f6fc84705152be9d52d476b8274f6ed8755c77b72a7ad3e4edb828b90d869d56e95c911d2d29bce17df5a3537e1d2f690694ffbec190021f4103b438d9b58dde301d43cb2980e76494f1a52451b0b379761724bdaae99a6501f0ec2e40b861677b45f34c2357d941705cf7926797438d448664d2aa55cd8ed88e366ee33aaf632f3ae1efa6fb41223df1ecdfeb19751915f6cff38fe776b58abdc849e7e896932227443023486246604682e20f571c820e117bdac9b34b225ec24e9748e0857e81bef0b15bca39696c29e7a4b44e5aaba6593bd2ec68b46d1cd77531765d17bd482275f1f348df772f0a4aca083a4685934b6ce295958e595052544a343a7afc28002e388e33c1e4c7452f8075aca491722593b8321ff48ceae2466f49873a1c3b2ed7dce9e9e97074383a1c376ade0c7682337c5726709c0a65f4bca54043710777e41c4b8e3d495b2cc1b42c71cf1927e73d63dc8ed8503d927884cee8708bbd75246f7b3bd2b5c63abd7f82a1037e83b5cababc28d66914eb68dfcc8e1af5121dc5ab5fd44b0493a07e3dc5b90ac32569ac57148c1f49639db35da358e7a25887db6077fa36c5a5d7addbb4a40d8f6451b76ed32359d5e75bafd18273ba2d3867e41405c3d505b09ef2f3d62b8cd7025a8782307c78b8339fb7600b9cddb066c65e036a03a85fb0662669accf6814540d91a4b1be028e1bbec45470dc7e7d6872516fc7649ae28625a21251a988733ab75e7ac23923b76e6a49d616b4c1de96886ecffb38e176731e75e21624696ccdca0e6e4d9164bdc4248d75f9d66b8824abfd64d3f312b3e1793bc1f0f49b1497dbd98adcf09bc5d2aca44589890f4a3cde7ac927458bb79e32e39ccf4d2e94fcb260d5b7e4addb6f8797c587920e7e3dde10dbd8701bea611beb5c0803146f1d0620ce99cee2418979aeaf9c1246ccdb8adcd0e4e2cd698b6da47417237805c3a755765bc16801abac872e3fdefa379b60ebf30d45f20fb5390c9f8602460b36226fddfa480b0b058c18900b3cde7af8cd3e86166f3d045b31666cd39f872fb1989f6e81420a246b88bcb75ec3a457249f2fb15e91bc66564344c40d61c4c29a195dbd3827e6633ee50937ac994d3087c9d52ad38f5659d34fabac9b5cadb29b911b9a5ca69f5ef15b37b9242bea589f28b0d52aeb1105f2b40a6c7d106d61bc0001464c0b07d0b2456ef4d0e4a2e1e2621b9bc55b0f5baa78eb2d31cef9dcca216f3d3c19f1d64f2657373d1a323fc1d95be73a00bcf55100de86dbd05bdfacbd770b6a8971ce74eb2e2ece916e878426d7db09bae0c336d653486e583393ad9f1ebec468c4fc070ebd48288f66858aeb42110a3e7c89bd751ce28735b3b75e33e39c7e1b84b737a8d8c67a0c35cf817d3add5bc3a455d66774a90ab78608ac99b5ca5a4fd9e2b6873533193db6657cc0712a349174c4d8b4a3405c1a67bd624289a81773858a1bd2998e0f19d6e3a7d71f9845af602d98ce3887fb4997f8fc0ceb8ebac3939036f9e954c6ac93a4993eb90fe9155fc37cb125296e056b8032b46aa670a10267ad62d2aa099aa024e486744654414ad42ad5a474262951a9865e85a754932b5932cc1696b8219dfda4b35e3513a25e15599f4ebd68559e5ebd58e7aaa357b567885ef57079fd5183f4eaa5c1db2ac7a182b464eaa901c7a9b0babe9d9341023c188a2b4e6032c4bea2c749d61e15cf776d7d4b962da40d4298271c72ce10a239e8950db1b23c116425e03737cf2ac9ba91803d2da0752a68254debb0a4c00b5a24430d4963617614ab397a555bbd92b7552702300cd2431758d527eac436ed36441824d8c23124ab82f6e5db4316c25310c66f5970dc90699164516f1adea8aee7154c537811f42cf4c4c9932cbe8891224f70ae9737289d5daf6e744117d6751124e2d4d15edd98ce1e85b5aa3d0a1e2a7b4963924616b9eeb390153d6f64f62c6405ec43ce47c88a57a431d837e7d28e00400f3ce80f3b3efa8500c7d127f7f1084fd0c3c8110484cee9d98b13e038cb5d2057ba0c674729a5dbf6e1ac0c5f113c283e960082e4e3fa90810ecfc7e743073bba1e43241f5604c111c1e3f91832c1563a19d163844f777d2c0188118f18e7030a27b02f906d384ea0b95c231404515b00645d50025ac4907684cf3cc2a7d64008198311313ec2d3f7543a15012469985e8924bee0c70b824896ac2b69a20bb994bca63983422ec3627041ec9e9808ba25fa2c14640a1923a49042f628cf5244c185f6a1b7c42aad4882bc669470679e8582ec8039c2f52631565c991f50715b6ab0828ba2c4cc12aef62cb4c41132495c9667a1254c204385fb3d0b01f1e2c31b93e316a974801045212046bc9ccf42405c70038e53e14ceba7b3ab554c74c34ff6c97a15930c4916e7d3bfd9c7a4579b4fff883e272b54dc9216bcda80605569c639bc9de0e79c5ef2e19cf60f0b667d3e4c23e31cd34f1f2d60d6077bc1cb92b40a0837fc60b2efc817ebd517f337c42f3ed717e47b7d4f7c401f9156cdefa755d37dbe1ead9a0e6bd577a45552bacb11577eb10f466a72c30ff6c1c20ff633ce4fe65f92253ffd1bea95f7d32fcf10cd8aafd7b7a408243f3f9f9f1e7e4e8a7e461e433ebcad9f57c7cff09bfd8ca81a8e04f1e955f80df1d3d5abf083c17a3544afa67f3d7a15bb98c287df8f9f92f3c18e9fde33ce4ff6ddce6d41bf057d8340373e7597f053b215b92cc423e863baf533ad9112292db41625af397d1aa664436056aa25f6f0c518638cdf73dd459a840e81547a48655d4a3214298cca28ac57473eb64bedd94b828b30b5640a384e852d44df416cd39c9cb447ab9acafc7bcfd1a691e9a41a89fab4aafd7b6e76294fb8e1f683a46549cbac55aa6e99f58a252beab4c45a64ad6a4fd9e2520f5b6241e0d01f6e3f1186488bf8f619236a7bad5071b71fce51f9f62dc8f6922c4a8402b5aa5b86be5b865a969c5c7e4e1ddb4e7d24eba546f50a8e20eae850bfa15382eb5d4488207e82e106f4adfd16647b81db4fd1951f6e3fdf2d44d5081ca7c2175aaf794b8f46cc5b97d1471c8a9952768e4dad0740eb8b38b1e4190acf459ad0f15c05badbe6ed5ca06b391f6f27d5a3559afbb8ba144fab523a5aa53933335fa03b9f5332cee1d73c8505b35a644ca3852cf0a858d8e1b527af79986af21aca872919e7612a8bd7bc458955c26dc2490adef2c56ba08b0faff90acf45f11447f11487fd308de6f6ded80293ac948fa4d11c46c3c339d62f8f290a9fd4cf6b9e824a0dc9e8e3d3ab1e9a0f3da534153ddc8c841bec690cc95394a7295a2a954aa594940f0bfa62560948d244a73b7855823905923448b24c1e9dc224abe4d1b76dfb641f9df6700ec9a3531f66a53865cb39d7a38f4cade74c282b69aa97501ca9bb4057fb0b74ebaba0a24e2a08a53e37fa16947a9950a9a1526a56232593349a5f24dc30f523fb09d2da129ce4e386c5471ad9c7ad099a1f360f69783e8630b0f80843f6b17b61f1d1e5c56a91499a1f2a78888fa1cb8e8f3e13c439decfc03e7a3873e4634a06fba813ba007d7409fa18baf47c74f171717d34fdf0d1b720ced93ebaa9c5392a7f3d34f17c4c2949c998468b9e1a02a78ef05a8a2702a0f52d32c94ac952b05ecdf0a4a8e0d58c095232c92a01cdf0f4aa04eb1913f0aa4405ab341530d524c5d3abe89aa792f4aa73cd5343bdfa5cf31494cc4cd2682520c992299234b05ec964c1252a4a404f7d68b9a81619db68245066886d344f31e1cef0704ee9359fe9f11919e770aff94c925e5dd77c0520ce6179cd69863887e45a9892cdf0d0147d6a091da99f56691ed264f15a48337b8da666785c3ffd434ac753d7e8cf530f677a5eeb79ea28289fa74f02290fdb50d0067de125dfb54a2b4971fd8be860c287a9d96b2592e760bf73eaed5cf0b64af3155a37bcafb5bc5e73970f6c196a554b12b6d1bc43e190c3fd16256ca3790b113886d6226b4911a5643125db7e7af52dc1abcf095669be35c1edf061f77acd4371fe49d7fc9352460974376f44b7b8811c4a46948b73629cc3b9e69b11bcea5e9b8b733ad79c79d539c1aa50ee605d9c33721ca2d6bd7a45776055bbe69d1339be5deb1dbe3d9ce1094b556c4ef303cf6b30b078cdc3199ed77c848221631b1ce287a952152919db68de1c48c3c3365a4baabff891e3105b649c135de3c0f942c916dbb48f5a5ed32c28c3c3369abf0ce1862db2d752b2d7fc85d6d62822b6a08fe8abb34ce73de9b9579d6ba83be5ec38796a24fbbdea3b10888b6323eaca20592dbd7a7509f44a7ef5152aaeecabcbc039295fbd861a9255d334d5ab0a060637c4f98a23a36ab2e635bf912c49c43931415fb5d7aa6b2835f440072843ab6ac8b08f482ae138a57a8e2047e146970ae04c9799d239e3cb7074fc74fa8459340a2c98759271ce0a129e287eaab438650163969d93bd516a38e2a455fc118cb238a3715ad5ce3f033c6931c61863acf235d4aa99a45538ad92812aba11c7430ace68d5741c1c9c19bd622e164193481a167a5cea214e12d6ad645910072795831be2489605dba341653f5d80d0eaa2c04de754281374430c31eff312f6f286b663936e904f9f03329f83cc53d74469b775794079cdcdd5a54655bfadcb83d6f3b27ac7cc3aa8360d1920b691a721b661818920b400b1bb1824c5d846ca4897818257dfcfb7840c918f99718ee630409c635da24cff7e7ac7b7c410530772871d519e182d5e7af80d790903450b06880331a253144b9a9061fde4d5ab908b1e28567ff413416ad8f001c9baa886913c3c3c91e726f2449ec85374c3c8e392f527bc41b2418d588c818c2d9ed141f2c4e307d7a1f2e4c38cc562356ac462b11ab158cc0737e4d88cc9291661e81883c662b11a3562b1588d582c666fd0a1296ec841b369ba1a6344a72932d8662f202637a4402fa0d72b08689b6d33a057a90434d87ce8c18e930d2eb2b8d20511ce01ead51c7a421624f603f631f6c9042d87a898c69e02d0273b4fb2d30d1123479024b93142093ae4a35316247ad55e4575f52a642b5e010b8830f48aba91a7958b909138e915e7486740a444548dc50acbd2033b3a01915a9d615f036fb8c837c872bb31e252a21e1fbd7fd0a2204f10f9e861edf99e3c823e3af5619ba0d92f3f6432d9d08c488b1b52a219d14c362b2292c9886643488845b8d2ef9054329340b5a847b8d3258db5b7a9df3cabae0d7168ebaccc6e486334265933f68d63874c59a880d0789c047153ac1ba669e728eb0b0d332fdd4309beccf0b1e7a778558fb0a3085cbc74fefe01bfcc2aeea98567a1193cd1840b7ca86da215538421452750c77d91a99a97ce49273d17d981e3836995744fe978165e7a8d07342b0a0db55aad1d74248f1c2f7f5e7a2843debcfce955081344c2cc54498aabf28838d157cd41af7434c92e4dd9a372e99c3445cafbbad12765a62e2951ead5505d7cffd284e4712188d1d74b5761024b9f6eb439d0f3f46ab73927b779a3fbb29f76abeaf4dd93a634db4c3b4d3029a59456d2c852c7cce23c64ab7d0618457b24cda43c3db9958e3d66d3931b5d7ae7449552cacde77d9ee35de96090b8d12533af984a2a2928f723b18c1a003e2393134e526a524af95d71a3cb92901ba994527630b831bc304035e95b74a377114411dde8a82e2e0be1a49494522925a554a394d670a48b32da3a12cb664b1f8a4a0b85d1177dd1179df4896be43bb68862ab361dadb058961378d2c13dd55a9b5521d05a5c28a537b3e5ed48fa7a75a3a1d6a173b979b9d6c7f5938f1b29376f47725cb09c5c64a44bb725b93174f60d6ee462e28cad38135b92459f787df3bc98f03ae9805f292dd86252ca39a79472ce29a59c73064929e79c1be7b16cde4a67fa6e4a8b8c542a2527ebe2dcc09a5035afb5a69c228dd3f376e4643959e9edc896c82a1168159c1ae7d2d95e491a69cb07947b899e0f46453308c68e50968bb8a75bc48d4e25b533664f2d32d245e6a5db925c39397a84e5e0c69899196994e9e4acd3674e1fc9a247604d614da02168fa7cde8e8405c17882a322b6691aace49847c1718c524a1965e4a6d46777addddd0d863d513664ecd803c7a9906b8d935226b975c5235d97ad061960b7e53ba5a8989849cd4d3d121806f44856162de2991d5240ebd0a2260798b101d38bcb8bd522c9db991c61ba98ce3efb9c382c8891e96c4ba774a6c3113d0450af8ee2d12082975e5112bce0090797083764222b599a759e6f51de9d6ebc24549d6b4ecfdb99a425bcc0a064e9de18944cb725b933dded0d891b85ae94d239ef28cfb72723453d41757382dde456885e8c30c9a25ed0a256b5a398c808bbdecee4f92efa8e41e625b8fdb00dea49d126b9d64b1119b952d6e817b7ce186e3ca52e2905e23815d216eb4c20ce89138ae78e5470daea188c982486bc627e0cf98929724fcf42437a60a27057a6e03b2461c60897f42cf492f1f02a12b3e40564c72d3d0bbd56e03cbe701cd7b4854ceb7a4490795d2f0624048a280851a20842583073c5557916129263a6e75e27313aae6512d383eb292122063df02aee7c168ac10e66b0b8a367a11804c500488809180eda99f907ed21a9ebc737edf1edaa93378fa4e919a20e788a614202757dbbcb106e487bc0d01ec9da7c58e7e4fa7609f2ccfce6c2e2460f7568e9d18879eab49f83f8fe08caf8f9704ef50e493bf876128c73a87f4d787c7bc7a459282ee9f9708ef4f66ed6ab89021b2248079097e3e5c537ca4fe70425c67dae6fd93026403f149caf984771495623e92428bd04a599a0b41394f60265821dd36146ceb1cede0cc3284aa9798ce252af1e8d1819616c43dda341e29083fd669bea234982c836d5abc6c96e921679362f86991f01b10df5eb73a387b4c5399ad3264fa9cf174aec29fd5cb2c539f3837911e40488c9eb29fd7e9e52d0078a26df3f7c7b88127b1e14cc09d08f0447406cd36eea428bf9cf25595a92a6695ff2c3e4e50448f322e83bc7b7871fec7bf3f9f6d65c7ab86c43654882972e5b7a94d467349d2557e9488d74523a5d0821203eaee3871e80e088a184142af72ca4041315c879bad7235b15244a3c81f3d34972fa95ac1054e10317301f4c7ee8d08955b8801028bcc80112217e64a033a92044458f89f2e47e3e3acb3e3a179b1456e0676cc63847e64bf0f2a577de8efcd92b193f453bfd1df9a962bb69b55a3c380e0182208416495022880f48d0995ef404f1b3db887cf48d48aff8a34ef453d8adf06109064fb048c28aef9f187c7b3b60e1c3ee6751121820f9e9fd00091afcf4395df3b0f8d1858c9f5e63ecc041e21c6fa757ec839ffd23c80b907cab60c144f810e6e70a5c7e0a09f1fa29f48213a84871e3113bbce96728e3e77ca157dd4fc73940afdaa70c2ce24e8f31b2ceec15f86d8492ef2d88e463af7db12b1ad5b4229a94408547cb54441474a4944e31f8fcc892c581d2a34745470a2e1143293e7ce8089d6fa8a4ed3645350c15cd0c000000008315000020180e0ac542c1601aa891e03e14000b77883e70443e188783410ce4288a81200621420821c600c30c4086ca661d0000badcfe841fd157c7ec1f1bc9896871c79ccbf4f64a99a6e1b85ce87f2a4e7f603bbebd24ec13f2cac82a548a8ae0270b905c6f6d64efed24022a2aa063f2da8144cdb4cb5614bb280dfea13418bdd945509a2fb764b92ad0257696dc5cdcc1277a72e04e0b69b5c1a692c13967412c39b1c659aa6e6215c2ab820bc0f35641f0d1a81c8fabce74423ff4f091f3e94e6e0f62e454c0ce435b500f4db069c42c40a55ea051fabfa89bfc366488364225f5a854653b534c35b656daffe6647cb4964db922ea7d965e91c5e68938e297bb06f77cdc959bceaff4c74faa96a99a263d3a9381f6bce75d4e45719f8f5d77d3fc947e1cf8caee41d4a124274373e18e9afb8880665a5d8a94ea1f6cb4f7f979dcc8324e563219a3460455d948e1d78faf9acbbd22b7588393afea505150437b81aa3cade1c181a5393db4fbc8c9bc747e1c480dcc817b4571a302fb208b30e14f307fa18e7aa6a3bd4d0fc5c0ca8eaef4fc6866371c3dea72f54c2e2222ed9d30196b3c84122059d66f1fd92efde006408c8619f40366908b03b7f20e13eac0103a2aabd74e1870411256efcb3a1ca179fb247262d183c2173dded7da818536aa320c1ed777c07eec4450c7172a4c872683dd16de4e1a3abce6048fcfb68a25d6b20ae34d7afff50cb56452cb8bf476bbe959ec88a69828413adf5702261a412b7cc8fa4a4661f4ba8e300de9ea9b9349fe06470d228a85ccc09ec2e9b24b7978b55ffa56a1225fa9bda988114c983fe0c1e3b1ceed7c2d147184c15ba36148a96b4299c0263e7432ea05df07c376d1de827a8da2e0775ad8f057e53f03372ef8a0090dd179d44b866ea3a64c7ac32e32308affe6444392ec7d79454d435f8d5bb993a69d21ec23ff22de7396b684b4c8663a46c44e51f53f53973422e2cce849c6c2f615d37d8369dcbc994a1f899690c7861106444c83b4ea275364cd310a4d4d29506c7c13f44c5d304fb8c95cf58c18ae1235018c9cc047a7c7f204f89f99124e4d1fad087f88e4971ec5d2d8991231216b3b4ca3efa484cc0139efbee8e3b449a847a9644ffcca7a88bf61b98a50b9dd71bf26f6b0c627f6d24626ae875a343ee17b58691baf091fae8ede8501ffa8399632dcce6641ac74ff90783be2bd9ab40976971ef15e148de6bb3f9a0a8f79d2a4be4d8c7cd4cea7795910d150d21e8c7154e55b5b5a87b5160261f3c40abec513380bf57f27cf5d5ead24b16feb141ed1f44d90b39d842cf393bdead2239a11e222ce87697a1c26e2faf3d50f05f18192f71752aae25079443abb4f26037a9e5345a9bde1cddd5b7b8d9deb57088c32e34a5b607079859a0e6951221648664b4e66e05140b73088122a44f4174a60c4f6bf00ac563f20647f4e5d49746d0c24c25e853a22ce0447a6ec4baf0a84cb7892b41589587acb711afb1617cd5fa746871429370cf41b5e668287faa05175028542c2d4df9f00dda73b3afe919aba14ee07a91f9fdb7922076bf44145e372cf733990d8c209d6289d107ec16a75c0a8ed7767e1eab8a14e8135619d05ae92ab24322265b2407641495d8a79f122b6b5c8ae806689d62335fdf47df7632e638857628a94f618cdc6acaf9cd8ecf62dc588e1146e2e55c62cd283e7a56047bd92311f870f8d2fc08a624df47a04a7d9497ef954409dab0b5060ed51f5c47cbdce3af30f61056f9e7125f42f3bf7db87d9acce50d065153c9011961247ca15cd49c73b9f7f633b1d2fb308031d405e66a63f64c2070bfabf3800a831861fa77c2aebf0f7cca463edf815434b7d3b1111783b462ec4c686f7f0e68fc58d50918020e3e4fc758f14623230896c0dacb6217c488e499f87c5687234a657a657e9d76d0fecb8a1cb1656cc578aaa620c35ba88bdc48da19963224af22bc5a751ca56d43e320a5b66d144ee9833564a3494081d7454c5df940d95fa95ca530d79cc28e4cdc63aaa15a6b20280cbe0969c515d23d4da571b719682d98a74d622f74c10c153bc27f4e003770ad92990cad610f0e68828281c22fb26ce1ecd97f92de7dbc026ea0b2f2b97f93411d9c0b8a0fedc828e102b8680efe4a34536989177c6047ca4041cfe7037a17fef085fd2b9b8ed66b11a31c78871fea2e372cd74d8b3ce3eb732afa83fb2c35fd2d40c2dcc685525ff706fb715b3a0ca6ad9718a9b4582b31f633053f18887af51713415d9fc13e197f38b2d10c2ac965e7fcef18e7a2dd99911bbbf0789d4310b1feb79180d18e188d0c807fc39d6fd2019271d2ed07535e6600a3c6c0c64d64876d56a3eee2795d3f185b79c66b01507d92a7eca6a23b7ceb2338031236594a2e752f115abbe18373ae2bc7554f91ce445d9c36245fc04fac7049c34f39aea34d506ce41eeb124e2cf0b48e848b82de31c095df9ad3258a0d1ceffeb51a6bb186c65ad0611a44aa988fe3593e9c89b18060486ca55398b72ff8ac2fe9f59076cb416ec155fc3f0b82ff0c3b1dfb22306ab80c000965486113d2e3d7749e7dac4a9748c5b5f4275313ab1bc0cdd9210b86995b951cb71d7b9a7a09aa65d1c5a486f64d910b96985171701956ebd2ad375a23b846b30712496dca5910d2f49021eebc6338cbd35d67158ef0442e7614431bb6f89d1b4a6f5c59420d04478ac23e3ce9e0e714fbac95573fd8fd283cd6fa273b7a42b57ad5d129213d0e4248bb11cae8a72693db1445de77a568f7b94df3cdba4b9b2d9042156b05e63ad5f487406566a84f9d0841f50795f414787628e5a09d4d9a321e5363cfe589e323e7dcf92f16b8091a9b03fdc25ea02454b381d14076dd99dd55b761e504b29147d25c0b75e912ae52ba752d9a0b0ab0733b83228b2496284ce5719eda759dd649d3a313810494160cf698839b1b53d5ecba2df2f5c124c4a7e945fca41f948d094b2e935b4e7ea478ca1a0755d779771b129924d74e41f57ab6d894ec23af173fc00f15fac46284e5bec142d712b71431aae625464604a7694c5284d58a158bfa54bd4bc80f6ecebfa720bf45db05bb0569a042d12417069af0aae1be4d3bd89f31815e4839d315048514fb0233a6e3defd03bd2c8da69f7ce1f1f0f552e4dbdfe39ece1c1c983c5a985e250dbb1396a9c06208730a34bdf1b2f4bb22abaf2957cf0fe1932e9a5c1cc9f7bb688d3347ec22d353b535330bab075a017d49e659c3a1c98bbb381a49c1c60be28f56668c8df5065324d340b2815035294c3c88b437f8e28879a4621ef0ed320fe017616b645b7c9044466cc46ace41ca5c377243d5c233e4a38a4cc4c5e18e6494c7ef407542494f60297d5cdde8e56f7aaac3a3e4f08528b626cf83755023dc108a1a80b81f59c261c5466bd8d8f29d880334abd2e4cd3c81641d31e94cdef6bdb60ad4f7350ece719733acbb3500221c480b9453ad31ac4de37cfe8a1caaa469a037b185797ff83761d347ae677142d64d205cb30bc24bd6b7f935234b974b29ee20932b2b54b70e371b42c268f904638810e61303a6a251da1c486e69d8e1f9176b331c1f357047538412b37591d5a0ac549c51bb255dae93c00f17cf6aa6d39e81f4ebce47bff5cb987770491d0dd32922a3275d15109a50f6d7bd517e653284086db1d1960cdf199624e457f15c1a22446070589b443b69770692ea9d567cd7fec0d14c58df92e8a19977c65c1cc3512d0a6b2bb1180033a053293a1569f79af2c3f89ae40c86bb9b755e833e643314583b51ad5e1c8863f5d215ee777b6a36a2653e0de2700594b63a92598f68390acc66f286ac71b7d7bc7b861a7d56e9a08c8f1690519c18cd4cd43bfe8863fa0234cf90ec221042b7434a16f3c03df6ab4f4e2fd838b22841ddef4e339ae0820c158af913a7896c0db2dbc6e4a17b0b3ed504215c5b2be95a7f226f38d697963320dc72cf496f7ee2c5deefaf30e9d4c8adf1fb2624a3f728b0cc07e8f4360fcb5f72694bd78355c064082d3ce64976e2ca795706aeb55f71fcaaa734ff4622a949a4afe22fede974cf099705694d6d3185067ad41c86cec5664a3afc220bcabc337eec9bd257693dfa81cdff96dac90f88337f07d35b46a6c41b5ac5bf68fe5b12ce5ce63f21d49ff176f0ac1386f1eab350d99977bf9cd66f20239a1e30271419ce36368bbf2b3d003f14854cc397ae02deef75447f780f1af15bb1f483723782bff14d45249d835c3c85d0632f20fe15310163066573b3f4c1ce53add089882822db2b1c83a849472073da6e529c5ec62117a79e508bc72733c28fdc120be0a1c73b557264b0f38a3cc645a0c3f26176ec74cc9c7d45a9d0d63038a402f57e8570c8821c0d7af53974f7db468b8d615b47d44b31cac3b7da922509f43f421b37903a7211c0ab330e958c9e6c8f8118d3dbb1c3dba81540480066bd618600aaa8c36261021eaa9ffe67ce145607f496cdaf3a261cea8af1e677b67af92009d949811956d485e60593ac01612fb86273d008193dd59c313eae005a74fe2608c8f99d0e782717a2722afdbec3b5b952048593af96b0d112a287c0538612fe6379edc24ed8925ac40cf083bedec90c4bee06dfb3189a1b980b1b57bc25937d2a8ccc50af65c46712a772996f51692d135f0c24c6224e9d10936b90ecdfd607b10a7fd40857f106e384f10e202139521b3235400ea63ce46c49c19957aed244ea348763bfd74f68d0216b0ae5c6ff8a50e37f88bcb525f520acb5d416d1b73375ef12153ae794ee329ff97813f25144343f834e26893c8fe40722226d7b43a2b613b2e9a5f494c12948f0b57260a17e9f89cc036136b45e33ef2ae6c4328487c1f0d7a9db2139320df9eff64aa0dd7ef2904906aabbb6a0094852eb1cf770e095ea1df8af2151514743c9cec0f0954cf0745a44c0a171a480f31e0d3a2f40fe3b83dcfeabe9f4ed80bf41d02608faf39a02f82184b6626a0cddc52c969f7c7f6a0f83c8cf2e55603d0fcc00a2f45c2be7de6027888ac180f16a36399c92659a8cb9aec6063290c98a5a865922dd3a1845fd54ea007ed5bbebe5199eb71ddf3bb3db5bfdb1473762ce12965d2e0c85e42a65ae9d9152184ab116261c86d7c42d3820645a51a154c04637ba15b1b3f1e534e3a59902d1a48984e23028af5463cb2ca091ba4189515b0e7412be59e0b10e9b75d814b6c889df91506d7b95184e251c949b9c9d4f2588afc452d2056ee01aa04ab4a8026bbce4848b94905fe3b3175742e6665fca79e7e8afd6e9575a32a02c563e388fe1b3262b8d5879110e8db18f414a7ac71f2ec61f898fb54d506ca6385cf3f8932e23124d53db30698f5d0091954814c6d5626871f3564bcc18e0df8f9a4752f959e03dee7703e4e36a71019c81dd02e3f9bf4e54e9413b46b5ffed94d6e39c6e51f6fd471230d1c830c9db1c3391303cc2599d2835f88abc74b2109ec8c7a09ba7837f69d4859c5235b1c24315e26bf5e12cd9775edb7c12ba882cd173724bcdfc8d1ede711f65da6ca35ec7b2d2232833cf9f925eb432429cfe5e642e01c9c6c57e9b534c40841dec084c4a661461d27926d07b7aad059621ffad7b3ee5755fa4322b3f844ae52014136609c8be4df82845c06a2b94c968444ed1917929a64bafed560d89f0551aa4e2f4ac6d56780456ec3680b6855269d89897eac1fc36066c92feac37abb178ec814f1e9356c16dcfe8bafab5e949e8f43d7ebc466ea05423a08f1eb9ffe5b569877949ff63cc85756ef5c5ecaad5f9829c212da2f83da0218deeba88330fa93e41cfbab3affec18a165e86a86b9166de4c00fa1872ee2d092a3106e8443b165c883b3c3896f91311dfd74b0796a6e143a1415ee96462b2a1224efeb5f9c3145591f6e5980de45a380cb7a9bec1181efb2dcced8ab1044c2965ff44388c0465c7b61f0b1fc38611464c9bc77131820bd0bc3d28108b3058aec9e44f4c9acb1d4c561f3cbd39615162c90e709dfa0e50a14b01e144210cf107ad0e35843b6e841e161f5713d2a0408faf6ee95013356bf3a597a5c0e9def986e9e9e1a6fd33bf2bbca7488f19cc3c1588a06a96291b409c6c2e113e92b3ce5894de5b9be45595353692d35ab3827b5a19ebe179b1144a736b4a89ca0087914ad317313646d21734ae100bf5af4aac863f2ac117cd606cf7180b28be51e225a6e6c2fd6873ab450ae99f2f7c9232ba0a60d9ed9bab5225ec0b6787666738bdd0b18df706b5f77067f3a42a251af6d1b0f75a413f4adf9d7873d974e089191ed0fe55e6353e806f66f3bb75e36e60eebabe6ca8ceadcefda50939fd2435211972f9d3fb74de5f8fea7179805d8dbdfd524c96ea5e98ca600a3de853763d0747494834a540be7f8d7eff766933ee63017e62b87eaa6f8fafd8ed84769a29b9ebc7454f46cfd08802c6e562124132d8ad1c943c599aad853d939a72a63bd42d2993217d63dad9fe4fdce1d1050bc9056b88d2372932172db05fc3b621b666547361c182fcf6b5b68747e74b2f3bef83fede2ba2bf61322f34e20aeb4a54549b223c93b21d83b11ab1663c6e096ce2c42d3a8d2840aaab93a56cb328de5fb4de5f2f514c0552eb78de3f13324ceeee0b2b56e050d54d404eab5865fdb6f119e21830b563adacbeaa86b035f4905d0df7da1f250007e44104c061c33837af0d93f0f33d29c452305dc78de05bf8c13b23b368e9220e66749626f9da71eb49f97790f8d248f833e66287a4b0652f2ed7af062edd8bc5db61eb8d08ad6fccbd908ba467b7fb02040d29479548970fe2dbc923204490042961e52810d8c0e88e1f81c935ddac642ae8ff5a79cdb4f1a814fa04cd55bdd2fda8308cdecb7f718ed667a362ea099dc9a2477c83b315f0b54c06368a71103a3ebc8f0071a3a56471acdc7b9aa7bdd3078a2196d06b068bced412379758d13d7c64cc3fa52c6618eaf69ab9f42e820f5bdd16b7fd992be9a28eac95c58ece805f5b74b4a5dd3e9bc480f17dda7ca8a98af124faebff6a45a3892d58d25cb5b4720c1ead3f665b2bba278c46b755cfdda7e7004154bac3c947cb21eada4bb60c4ca169b7f254feca72de9178f58d922f3a1e409effde9e4a823d8d46966d2f974bab4e15177aa79d0085cc604ed368da3c286f05c94817bc251442a0e567d21155fa6f3df1200a4d0f63b1a2610943b3bac6052ee33e0095b6e99532f1591f1e90aeed945723f6be3aa620e96a9c00a3b30dfa21a296456af9e23a85bdcde64c9f78c7dbbaab45e314d6177d8f5bc0c6a8aade8f34de8611484a7ad8454f1209809da7d374378c33aa97d17d809000ef302b81a7a9be2b3c75f27d6f59f078d37f6da62708ec3dabb4025ff9f97bc77544f77c188cc2d1ede8750032b308e96ab3eff947177aa640f8cc7f713bf31324ee86624d22d35378be4b3b3bf97f01c149598c82caa748092b5723e95ca9b83b1246cbe192021703ec0b8487227e6d73a41872bb68cbc3f410b31a355bea48a242c561c99ce9055064d55685eb6a127da2e0aee3b2bbf1760526af12e11c9f8caae58b59f82e56e0c8aec891ac637a01196027474d2006bf10323e750bd0588f656061ce8669168c96682c6f93c66a3a9f3f4213c7cf443ad1c81ddb27161d437ee81494dbada3f18c1659378abbe030d8c71bed929a15371be0dd4e6db5468be0514375756b7f223d95a1ed1c19c0537e66c9f2e2b5bc580aadeec13da66c996871258a85aa073f6db3cdd5105a20e2f962a538ac5d1af2a15574ccb255ece4e020fd6f1721e301bee447cd8591f67a8ce672fec5771f471e85e9c2dd240153fce30985481019bcbd97cb7bf5ecb07c901c2b7c8afa483155a351d78e9d5e5ac54e13bad52e6ff1d5dab930fe1a0a06172c06abc47d096fb3fb954abfe6bf31e26eb01298c96f82554899a6a769ec5445b9d7d92ee1de2be6517e3e213aa00462ce80f34f34d3c69152ce108b7103ca7cc98b04acfe861455594dc6444c2ac5a1b72428872feeae9f61e6b56e3ba141d47750f6bb520766e023f546dfe7a71ae0bb8b1c26156cbfaeb1bb30acf5b397cc224e481019a0e2e4b95248b1184caba49b58dd3a4f60fc7ff29c6589b5192df11e5ff95903649700141428e0b844989cb786627155906a280fd419c5dca9e4d1dcea4cc6fce2ebf2d79c28b29fddbd352c239f153cd9a01762c729e55ad2c578d2ec450106199fe760c5e7c720a71101da8fb33a8429b40c6de8934afce37d75e06c6b4f9c575d455dda8569475e782fb68a5b94d44a9ff10bf17ad1d014ce275f711646401ce9c40090f0b1718a83317afa619302a214836afa0f30e36fb18e2e0cd48cb2b7e008adaae922db3dbbf62f9ce9e9720bd8fa5bd3423a430a15afb446ff3c0cc9d7203d0373b64cf29479a54885504601a9a27c57eba25b41f26f53221257b394ab0ed5fc44bb49104c4b1e91f1dede351353f1e0295da6e43d4c1db2e388ac48637d100baa04990a4f00de11ebb583f335b2935e0c7378ed18fe628b12abdb7b7fefc3445f02399fab7034921d7a77a44a43c3218fc1e50ec7f080ffa0792b9a3f85eff496d5e38737e2611fd5dc37d3aa2db17a843555dd72a52248652606a3519e80c47cf76984b047920fd3daa70cdf43ff72e6427d13f195c1f643109d50969f23a00ebc4d5ce9719a2669c652e0a1d9c01b3a01b66fab14f0f64022dd0cea9bbd2072074b97c04f806c6e82ae357615d9a7bea20db5751e70a86cef95558c005f05cef1888347836dcbf4fa4960d25390ddecdeca3f88e75b6d6704e85af0902bc96586dd3ba704f5a4370f0a02bc3bf3777f39ec88598adc094b80700e0e2f4aca4eaad5475beb2d38fc5a34b13298b61b98200b8f6d9e43717dc354f9eb39d0fba9cf5c75b629e4eb539741273e3c088d48bde2c25e54ed2d4585ba15a2079da0468e17d29684d3872bd4152785f4e00b818aa566438a6b4ce111dc76c905d7b315dd6a58b211625b52d44bda9f4064d08e8b7e21ee82e7e226a998a0ed8e8629b63d2fd0abc14e2207430676824f1d7817e2e613954c695e470e79573a2fd81add09797bebc0fbb58ddda56d672437b3202dc237dabd458d67bd8797512a9d82bd3cd4cace84d013285ea01606840db8ff5593142db00d16ae6964201bdf90633a2e004b9a3d758ccfa015a9628379936322994b2731039284a19304d3a2efd2f2d1d14fbc4933a9e2753624ea0a9e7872d7fccf2665ba0ab223fbe9f486f512150cd64a05711b98482cb664e204150a925d2eaca6df8e1bb79714f787d5536bd24fb957479a2e942ae69164c606389d49d71d08f5eabfb21910fa5d1c8c39d2a6f989614d5c35fb6458eccce13a2c287c4d1dc5216cf7a8f8af1a4e9ef5a24495f7c349e142a2cad7cc9fce12fb17a5df12e98ebfba3a1874e909687591afc463e2069484aeb83f1a943d011f36272e37efd649ffeda1b7d7b0ef11121975b79c58cb7ad17de8b7a4896ada068d729eb785313d7650fb9ab21321ab3490e65c6051449b89c99919880464370f42698ad9a5ebca25e96e4a6ee932b449f8b14dfde4d59210849163686e7460a6ec0280c8c83f0d5ed2996b4139727dd90871e00eb01e701a55b18b2022b2e5bbc63307664a8af9c92dfe5e16b030a7e1368de1c61d4ddb5a70dff4e15b3125aea7d3ad12beba8a98572854abb75ebbb383339b4cb4f7b86a4df63ebc42322c0fdb47ddd83fe53d936a82172c449a3233df4bf5c27e2eba5d3036416ac6ef124ac0f2bc0ad0568439c3ee00ffbc6609d7f8576e87bda663ce89bef481f032ef44f1c20da456344129c2506dab63e26176a059f3c23b5f7b839f494dce1eb535ceda95335c361fad64f92ffa389ae20393efa3068e6c7ebe9db670228cf8b5d629f7e82fcf641e74512a11fcf106120ea4899c9d95128e18745ff5ffc6c6cc17581237742ef81d14b409466a49ecf99a0d41fc73a00c3aa5dd1c49c880e34dc03bfe6663a03211481de09ee773c62025b256b7c1877b87b122bf9395f220dcb67dbffa47554e9c22447b9479bad64bcde7c092d08bb1e6b8480dc415d509a460888300e3937406ef196461fadfef4d4546e14328db2b8e3d7c9e20fdfaeaff5fdd065f94e224062dadeac9461c9c93e8b1a8c9b2c8d3860bb4813210d01b0015e87494828cec6efafa35ecb8647f898248133b7d9ae4b421e06fb04658c74b134b4c1f0ab3c5e9c6cb322c0dfb4c80710cdd2ae1f235916da10172aefdaccead5a93a0aa393dc43c12b4ac620191de149c719e62cd0c6e98a6f3ab7514cea8e3fd1256af7d5ba7c77985913afb4bf4e3adab15611f489343ff02891ef795b7f5939f880abe4b60595731d096f12e6dfc0b20bef5121ee75528a0597bd58e4b2fc35051f631e9df9373744bf212f733f762af95b25a44404532f722cde623cf0cb2578b66fd2d843e6ccfbdca30373b1c7551547c55d0a76a911520b79bd134dce985632a72760e991599be0ce31acc9eb3c9ce11cf1c93e14ee8068f9118acd32be12a136f7ebfc46f0d880aa587f0077398034c32344369b470204e4ee926ca3a4d98a06516086fdae7bb599921e98e4f81d077df10eb015d33d7e1bacfda76d07074284e8d3078eae6e65650b65bc361978881a78c6a3888d01ad318067f2e1c1ecae143303412061750772347353cd800708c1034bb9c33c92c373b28606d0d6fcdac3c264a2b7d700c431f917e9d37c91dabe6060c0c5dc18e6fc1805818bad4b91c817f30eb0bcf7f595a414f3e26656b63d7e7a679ad9a885682a509a8f6b71f346757c2bb3b25335cf19cebea6f937654efcfd76060454914094f40d37fc105211a5106e5cb9ba0d3a031964d55db4c77645f5e2c6402831e4c051958c4d8ebb8ea57db5c565ca7740c02facd9c615de54863d5d38da19177a1f39d0be68187d64bedb398d473898c6c55438a04b848757e8e450ca0402f2315098e89024bbd97968ea26349636a59ca1a4f803449f25530e8d651c110623b92ee5b73877fa3dbf336cac9d6eafa415221a8bb54dcc0aa583121a21c208de32eaf47ba6611be5487a180dbd023c25f830becc456d6ccea638135ba558b3899192b22b3056e23711344d66c502b8a040ce484754f609fce187de09863c2fd7ed6b7ef1fc57730a6913351b28977f2507d6b54e67a711eefcc7d9dd8894654df6bd2488eb8417ca1822f233577a9b3a1d6217d42bbce54b793dca4b27fe903032c1936b9000e6db720be5ad4605f7c2bb8dd280dd77ff1db31dd10a46d61e4a33186e374e59d6555fafcab24484374d70a975774faea595b79d6914f4b583b6c7ce46c71efedde77c4b7778f64f89dd75c58041977b052f7cd2d30ba7e4c0a3a3024356a3cd6e09ac1976306800d10d06b31e58bb25373eb4c387138917e008a504c6c767e90b04b9f3998c042d82971910b1054c13f025fb28e92b57fcf646c9aa3b7e693ec898a2af00a6b40f248a29952bb1eaf8886dacf92d5edb0d465f03e5db01e4a5485268b3bbc0a3fc55f0053d5447c082db07333b65fc1971eb378ea3dfb06a7f61ce419e6f0cdac53fe4199b82f5a6daa33c1d4154faf1941482aaa77948fe86710113ae3aa5a0024e07e1656ce8a939c236c3f75b06691ef30be28d280e8b6cdcedaac4764217e2e4fbf7ce134b9cbc66b885056d0b805f5a47cea5f95b19331e1407ace8095f2eac8b69c9c49f5ab239c1326289011824487ca3e60016ba41c60a6b14ec80ef87a335410860b7f50d2ba396ba814b68f7bfead4baebdcef571c5f8a57ad4cac94712efa9ba73e7242730660c0f5b45f51fdb710efefcbeefa3c39d056b607fd3a76e71da461f21c4eeda03fb2624005c746e465241119188b3022db779ca5e6de643b36702808644f84dcbe79555f4fd6b431a2f9017354b5ae1b9aef465e58f03ead16d434526afcf7f6f97697e913c8460a94ff2323128e917a8c373f0de7c80a470a69d7358ea3d3353325bdf73c90b83126404ba61f7895aa0caf4e560848ab19a1f404361d744b428ed0768d544b297ea86085cf91cf18417d50a799d137e0ba758d7a5d8cb229dc343b7a941b8e3c0ba84eb48296b5accba2686a345a3f3f0a274afc8d6586bd8eed15e952413f404e4f4304ec398c924917ba2d62a817a7fd1449201c11c37ca2c2178d43989d4574706bad61e1f91feb055d8fcf442c9845e26c533d63eefc244f64951aaeb55a61cfc7bcf604655724069e631962ca3270c05b89a7dd8a3d1526bf3c1dc133956a0e89f7f0a48a3db281ad6a091385028172e998ca144cd6ab2cf6db96e525aa98f8e8bdf4cf1b61ce6e7bc6d2c45fc23ad3a96d4860a05a44537082c5a00a5107bc3dae369f3396a81b9b550d2f7e3236d7db6217f0b8e9ed32cd84e4eb7f0d3c97b0081f83e543d29e4a22dc82571808801502c0b9ead517491e2f8b17d6e38e3d9546127ee8b4702608597a7709bd3a38f35fb9ce300da90b42442f84b81db6a8e8d0410fcb288d3b7458ad387181601d8aa945632a9f4c7dd256fed1bd8aa8f281980d46f3b88f780055030971d5e16fdf885f85a9ced23754f1c2de5746c42f0a21921aad1ec9163b6ca9e0702c13e82b0fcb34c8b3b5147b2c7bb0396a3c23fa144ca186adc81bd090ccd75741ed03a36b148d85ff223c52235ad963f7892aa610db046112a604bde42897522a3e77d294ba2deb15274287e6b4eb39d0ae742b1fea8375d0c16105e0c0ac29517645eb1929deaa821b5b32537bf07e6b0ffef84f0591bff8d769efd6a6282ee8c56c93d12bc6bc49053244e2b2541ba121fb7b1f3db75551931ec0ad907d8fb25d194a59b21abd9901e6313af7d464f00c900bbcbf8b8c2aaff067575d424cbf3b3d5ab149c8c70e7032546d80a390bba006cdd67d97efa0d37da2d35649e8e121aac9e73f4d5761ce0773625675ade3d87a7db4c59399fb84472b128beabc2f3b1bfacb5d0ec766391bdd97078934a826e8f8d881f5ad398d8fbc34e8e7db6f4adb4e0b9002d96c7d8b47b86945b3b7f63e67bf8a31b26e0379e10e97758a86ea9026f73529b3df6ab8012cf64ed11862069cfdd54883a2d9bb2058363b870a933f26e70317677c3c340813ffd833df0e6adb023a0bd5a5fdfc92b3f20b4239105c2b2ff5316d268183196236cd3b44d150f67e0da2dab0929e8ae87f1be7f10dc755407be681a109d1c2ec3f7f1ec3f108b9ec2a2dac2c81feacfa7865d9339b69ba3a6a1aa077204520d879c0881eb80d7044065c29b820b7442073a6edcd39afad9ea6bc58e1f28db57d893355a6d55be26d75363c0e77760a9570dcbfcb2d5a4b44bc3f55fc92b9a7547132bc9cf0f28edae1eb6ba09cf2be90b8931a6b2bfc7ae0bcb72cc995139d7c6ad6a4744fc419c0a5ab3f3ca1fdcd0de74332c18623c4e9cd5a2b932f9777c2bc5e1ae7deb2b1f8312496f218e5cd79b922e1537c4507c9e7cb524911f1ded80e45386e7dc871a499fc9b29cd90982db9b0c856b2618ab4d1dc1fe547b514f953de5faaec5520896eee9c97e81ca3978f2eb3b7aee140f223f12803fdb37f8b241dc33af19f1b4d9ca397bb9bf20a45a0ec87aeaea1087343a21333af13c325b0abe710e536ffefc553df50c38aa6aacd79b0f823c06354c71c129a70ecbec0fdac46cea283f323ce972bc35018437c8b6b0030f695fc483406e275eeb22a8e0d72a12d0a6de504fb58000358bb46083638119ef0d06a822d2e933fc64130291ad7be3b734618f290ef51a99b9b7805dabf352f477cd58f9113ef7ceef708839be20f46197aba096da0aa821491a80482b40bb5b2d18e55e65a21df35473a1f4c34c9ab2a8a44c2b5402a397329a64a92d659e7429c4f4188f1a7e84daca1187a37250f4e3ae9a1ba8b44c205723cff6f0a0a1e6c75407207d7d85b70fb66504aa01c5f0df9396a8c44f20901194cdcefa9385fe63b3858234e3e0352b7a9318950a0aa7378e07799809a4224a49168aaa01afac8efd067eef39b7708f487cdd768349854bbd309ab86ca2f016e655be12b7aaa600487759ea3ca32bb10202017a6cb6c2ef8e562ba2dc025799c5767c97e39f1ed1345230698d25b423e5b91b82c99e39322256ac8053583e50d32fe8865fbe7e67fdcd3004ea245e9ebbf1aa4e3c06ebb1dc144fce7f20dfca3d7ec4f3914af38286ecd50226d5712bedce4ad2c6c71fdd46bfab6f101216bba741c4bf336ae9f28f06751c12d722291e780f93120e4daa3950161a4c04b0d08dfd5dc4be2ebc77ad8e50212206e9ff82eb42aae9405c2bdf0ce0f08a2ee2472219ca808b60481d09dff723c31348b54e2eb442d0281687907d0941d8c4130ac85722abdc4b831e1ba8102e12bef57073a0254916f248130e0db82c5ecf991a8120d31bc4052dd2e180293bce19816abc4e7daca40d0ed093b7e0f4bbddbe383a5c21b8acc5d3b7d6201da14afe7901efaaa7df914062de317e7a2b74af497c836049a932a06778bbf2449ec4ab3af25f847f5439b1534b2831ee9a7be1f706e984d5bd38e94301a7ac084784d09afd1d8d0e8a1f2cae823a99e563aa0f78867276d3aa9711b7157a18c83f7637db8e66e70585c82b89d89078c02ae93422c91183633104851db10f6b7a85ce309eb3c332dd425bb412262c334a59277252187611c726c5a9c507d7efe94645be73dd0e4873e33cf674b97e2c48a92e20e06beff3db6c3c0838938fc252f7812ca318ccfee7c29225a745c766d561e39d789c3a7810cff65bbcb3f62a9bae515d016261bbcced6e92ea993f13eec5c9bbb0493e080634855045a45003d8da5c49f49e1e4d7c3a0987bbba457a16560dc93a592f3fff637f91992ad21d26b79ba29f7f280f410e037aea407d4f2096ef3a9300ebc44250dd190c6646a45af4be1ff17ef0542e421c51b80c50c7acc48b691e63f6414287719a1fc949c76e6ddfa09e047065b730c2322523719114c572d9bda2c2bbc658c826aa7c4cbf75625f35ed00cf0a02e762250e22cb5d44317664352746ac6ce6f18439e54b438d9b74e8886e51740191277c4d87082bb7abf03c3821062d40cba03e72dd22917da6a6c3ee9f4f06cff242352f734d2780505238c40e13040fc61e123fc1943f4a42215b78db411c7ed527711e30454586e5ceb82a6f66ad296581a8077dfebc24e7062b8bdcd5c2f7d397659b49c2c911005185c1782e478366441e8b37c4a905f19337fe15da83950f44e7518df5418921ad9675db4ab0718704b25c86b81060db8c67b323a8e80be7c5d36be21df11c4c2eecaea43db3d7cd9bc5f56d667b84144cc0e116cca13891249011415d0495e2804f0cc7353969713aa80edfc7cfa31a1cb10523aa8df8aed15f9a98a37ff4bcedb89a158d75cf7977381bf70887c58bb69682a91f8427f10c9d7fff664b18309a137af53ad19afd57703574ad464cba76852211a14070a73533a705b6ba595f3b31d97c23bbe4627dda0f7e89a6dc07815f2b82ed4ab624477855a0f9c26d1bce610c9183ee1968b57e50bf8f32f7409937cbbde45f56bf28c3067585ba86afec39c963f401b239b986d84ca87887471b9c313ab15d760f61d52f4f8854a9838581480eaaedf8cef6a0e401a548b9a8ab4e905989ff41b9df4a517e111838a706613cf421fb3e69c294878e5fc9d09d1891cb473efc7d0cd44df071e280095d818a910cb49fd5b087dbeae0916e0d162c5cdc001b38a7e7043231dd340aeaa71ea84b6f728a1edd243098705173742cfd66ffcf62ab1b1ae1234b3218489287cd59355b3a9dad941eb2803fa9de45d354baa1725363a21f59fae913ecedaf4bb76502f2b1d37454e07db751c3e98f78d95780609128bda3b3b5a0a3cb84858481d4a2a2b69e8904383de9d6fcf03d7e5bc8743741a4ac333efaa160684dd4134f2dbd0c70ffec3c4d218b4352f4f1773b72a3bcee509a75fd9a492b70f5c391870a75d094795ac7181be8d02caaf27920c74717c8b6fee8dfc441517993d4a6a392df447a93e120f8060c981c4720bd19623f018be5125192b4db44cbe0f37a2922c10a2060123d7ab4c2412e88e4f852e1de5ad2f368f345b0ff33dc883659fdc71a581c28b9caac03273ea8b6693d152f25991a9eee82daf4d68191be2305dc6f46e3f030d5c25a47cec6780a029c03395e28c24395883f6fe40ec8cf977c17d26fa953b46ae04d087baf794321ec7bfd9487fcd05488d99738629497cef03ac3a40974501fe6ec0131bdffdae34d66c619b0a8381bc6578e3266d1b29b46441835801f247c9710c03b5e9b3e426638657c0aaeec2c21566b35d03c634b5264bd7b3bb8e8cae3a9da6d07faeb16ae8d4c0ca7891d28078801088a97ff80222cb7ed52870f17873b1d9f0326ce23321f1d13ae98258e82fe4cc57503814eb7170a903570d8e09990776c1501f7baf87f7b3e6f013b720e9c93fe4130d7e4e1f8c6707252b0dc1217c1543bb6510381bf89dd9a3def0ecdbfcfccededadc3e40cca5dd111762b5fc8795cf5bda07936d7cb572887a3f65414321163ab0eeafc09a884f16c05cb6a2140466148c3b21f9ac32a050b67a0f2879ee331ea5ed4fbab08b9a0853655ca2e7ddf1d10b3109cbdeecfd9d9c6b87cae677934f74a574a37bcd597b8eeeb6f1b73225ddb180266bf5203a8638d3348c73e527073ea3c24532b8bb9e46dfaeabdc221464ee1cfcf42f3a6b0d84b24cb114e4f849d4ac07532a26d50d4ec54288481349aa82467d6988fac140f922103c500c40428915989741c0de1102d95845f722f0b1dd86e7ff155b3749f96dd51bde9940ba7f3a6776768edb7507a18052e106b94e9d64d5ebd847b33fea1641da235dcca2e1737c6f66e19c83be6251ffa08b3b05ea1fb43ccf350112c681165adfebe7235efdc5d9c1bd94cc2a737d8ffb30fdaaa97708278d165eb86dcc2f134d697e5457b849e649a7ecbf3ee227379c389bcec296709968f09b618d10e357d56d94678d54af69da23a7db29c808294c307aca3398a9b396186af622d2ef6d3e4d0d9068af2bbdc5ab49900aa2394e3ed145f1061590d113edcc9211ee123002ef73a60962ab118fdd572a2bd03c0636f128e181ba3180024427cea99d21e3c16ff42a8e0b13a7f0561ee0d0e056312bf3e381ca04d86e6e7354c59bbbe1392d44457ba0d36aa8e5365ab004063aad747c0d4161aa8589438aec51a2c6c4bd604a890a0b9cbd3ab158ecec3f23dc00bb912a4e88edcaadbe799b53e44cdffc6ef030945375afe24580928c9372c53482ce65fcb8c5b0979d6e6d7ecb92ae7e1ac7b1ba88849bd84230273dc0ff3f94dc7440e7bd22669a03fc49911e5938841e99b5b26f521244e8ba36287e539bafb2712c36de20770c5ca73cc6d047c64ff9699a082d2234993a2d9868e6c604fb821ccd0d0bf8fa2f29ee9aadcb3004da32bb291114144fdaac7f092d48d52ba8bf195987fef9a1fec34363498ddeb44d44b4faae5de8dc8c7945ae98f4759b686caf96bd5dcede266f8b4a4de80d0443cdc277f965b3d8e5c8d9b543dd08a406757fbcac0c8cfef09152a457e62d42d1b72c756cd92b991f2009ca08f2577da71766e82832d2b567acfb202b7f183e1f943ac255ba32704e6ab9c5a939e02b2cad76106ce4e0060f33f9f8fb92938227a3f2c2b8f18bc46532fd33bd668e02ba9922799c982a5cddaeadec23295b8a4fe05177b378a3ee22994121bba50cb60cc312facdc200c30f9b24b2617032e5ceb16fd8567678ff4c17d37da79e694782ceea0083552850b604d1cda4f4b23b1e8eecbf7d4897d250ff636483e15c5c8e7c125ef4f3fce9df1bcf24aa70aec2d62cd34171efa78fefc92bbc0599adb0842d4b376e338b6def01778de7807905d51ff98822ddbaeb81b689e2142ebdf5b6b3e01f90251cd628b9aa7d3b76dfa1a769dae6f1c8cd03973bbd5a4aa26350e61ac496eb9139223448f6a19eef78ccaf7bc34e57485a6a346220f8a4943d21baabc9878c1cceee0a60ee74dcb3e2b6e775327063ce28fcff6bbae25c9395c49370d18a6304dc8977eacaee9f52a0ee725d2d30f914544d2d5b12d66d5afb4c06c3197d41444a7404798c0798cc32f500e411537446d079495a3fb0956b3e514e68c0d627936d91ba2f768572e8841eb335c6acd4bf7f2832140d60c02c6140e49dfc412273872efa4e9db176f43cf4f022ba1b7a0a22133d6e63d96bbd41daf1781fa1a51a5365e5bad1d9ebf5e7b53935edbbad7fa7c5128be1288fdf55584a72904695100ba52278951384d7e9156f95c1a4c0d793f67377d02672a1a1f16159d1566043aec27d0ea2c56bed0e89e2fb6dadc8bac152002509e4d4075cfacccfc259469eeb24c751c0994e77d2896936598f265de60e15fbace0771743fa1b3d2aa8d199175e23505728fba29a24f5d6123fd12238971772ec9f0de90651790de8cd5297e389448cdfdb44d4203bf7801eea4b245d479365d77b76231c78bb651eef44634e3cee94c63a75ec938c79ea98278ef5d4714f1cef89639e3ace53c73d75c6034f4f6a8e5168690888f8e25c9303b88f62560ec11dd5b3380a6794ceea289c519cb5a3704771f6e3e085336ab385cbbdfd8b2f1ccc9f9cf7140762dc088cc1564aa41d9e345ee2abb70762bd08e2df1b7e58fc56f9af4c7b91561847f3c5da4f5fda0b71882d497a3fb8ae213049517a8d117c37cc5de7084f7a09464b224345a769d5696b27bd14004fe6ea256856eae3abb87aed580ebd6ae70c7248f866a9830c2d89cb9352744177c41df522499a0adce2b078708e78cd03c3030243f68c76b2ea1a4ca7ba6cc3304202c15230f9cd202fcbb3a03d9d4f19c47ff0b4edcb851efee3a1bb61c1f41af7cb8603ffcaf8ce0e70a0d43fcec2ce5f7a4f4668adb05f60d966a70622aebb9aa87efa5606a645a9ed63d299315fcf6493edda247fc9c0f6e078ae61533cb60f2bccae4f3a86dab32a7bec240a07deeb953534f6c8d96313a9d06034f6d8003f658f271985471a404c54f5ade0722ead480c9b7fe6002d2bc832765e49019851a2e185b7de688ea839a7a7baf3b52484cdf5971327c4f037687fc90bfffcf2df3fc0ae59feb7f7151ce61a50d33874d0a0dc80af297c193649acb68f1873b1361b3e6377ac36c0c5c5250c2571ae0a50f38533214c40e1fd69b60548eb4190223197a241656a9b06f7c46aa558a83ce1f392910f1996b6b54a1375037ab274c5872c4a463614ae9d81c0615253dab9b0ee39ed36a9032f63f3a8321b81fe7c6a0668ed8c8f4d18a3bcf60e176c7c9e82384a3f6a412d50c33cda7f1cc205cf14962a564319b6ff26313e5fcdfee533a4d54b3951f528ce2e8c3f1b358691abf48edbfb4d030525d03ed927e8d8b9881088b1d78eff842f763d3b8fe0c24ae62112769565e5fda22e04d03136049f2be54589a455b655e2c27cb05b407965857679e0e115ef10026aefae170e1c8bb2797af364431d0947b2b5f8ae24dcdf932fc53794884d61d5d65df21765c820cbb07af79c56d2e2934a00cc98df96820c2f5e7ed48c688ce84de9242b7ef7cecfdf1d194ed9f814bc3ab9620f1886fbd99d9175e98162a51f254e4a7410cb3782c94cb08d1a5d2a81a145b92a681457c253d3c0dd3686385f0cf3e09e60d5cd8c77dc3c2c6a671943d0829a3ddd36486b15b34c2fbee569b51fd0e50fee522a359e20be65b8be63c5308db479d987b4e9bdde69ad11cc03107919978496458064be4616329490298f395cbc2946743fbfc5a8178fba4b8daebcd0d1981427f738710ca9f54584842117a73d854e952fd62d78717c61de3b0ae30ad96d259918f279174449aa97ac92e96819937a5ba5301d095e45e08337d1302b85beb6a5411028decd89d75a82c2676c988f37fccf3294efb00788a85f10d020c556020deaa0e080da67f22b8ef408d2fa1ff078eae7356fd93ae986c7ce08d15e41803f397d3b7bd55e5309393257f109a4de658498b61a9b57b275fc4a26f9e14d28269d476a619f1b7e018ce8b3f61809c2d3b139b488b1b20847b310639bbd8888270ffdc2dcfa4b90eff966c87689d2ec1110e003ed5705165e446b4a2a4f14f64331b40b3655563a9061bbb295fb526da5772f0070382283381474c3e27653f1a9119c50e04c39934495dbc5ab581406e1515b08f110177ffd0c7260b9108c3b2b7149d06f06c6e0e676deb7af8872722e35912972865c22e54e9d3bae013516bed511411ab448876e6bc55d17e608235edc44e5acf435fba51c3d9652837e4dc9bfe562fa23e8feb0319cc9fae8a447c7bad34ac75689f051fff185fd196182e1bcc9c7dfec80492a8a1161753b0190b94b31efafcdd237983f4f5016a1f8a4d0359de7a9f86907e7b31b384ffbc80565069c26d942b2c3c3358d7b000d39cb1cc719e45e3073d7c91d3d10e9983f14cae0b092dac66b4fd7801f6a84901b2f34ccf80b311cf06b4da3b53273cdc915beb11dceae657f576d90f19e96e0aa2405ef3cdb61c7f69369ee1ce08c4e2829b65b974810fac7c36a10b529aa989563874fbb38b2f29c57d8cdb639b2f28e1b1e9b2c0df9e3d9a77bdb1adfed130ab425ed897d076c3fce2b550ee6ec42117564f763f74d4b209a26bd417b1f7391ce1e23ef72c8ccd2d0b5803b5a2047107fb1685aaaa4c96ccfe9757f358c24f12cd85930ff93edbf79cc13083b4bbdd98457824e24b8a3c1bba6167a1e8852b8cdfd34afa0466db4806d78055b1ee677e66842b7d051c59266b1413b02b6c6d80bfd9bdd6f9801ecbeb064d5690a4422d8c977b5252904e9a992f4a15b8ffdb0dd21a1e4e17cc2183055aa252870c45fb8a9a7a1f555c0a619cc891c3d7d15978011495fae8a8e195ec7e0046899cdb0667d9aefd529742aca5efb45ae67cfb0d143b4ea20db46002c65d57b86b793c63a4806008e4677b9585999f216f7e52e06f83250ed251b8ea333d6ee0cbf876d1da391aa56d0f8d5d7ff4a6d588ecbb99b7416e352a3f14bf3879076602c7c3ab5c8a0368d63f90a2a83fc4110884ec66008ccda69bf56cd68850573e90b2989096f500ad4ca6cbbd01f37690ddcb2eb05085019774487c261cc3e389f7dfeabc25ceb63093a8c473a6fde2f91021593a846c04f18856f0241b0c5c3219efb55636bee5792a28c0f046bf1aff0195884d3f7cbc80062f2e019cd9637822f9160d08033200cf0eabfa02d95a399d9cb6081d7f6894c19c85680a50a961792bb40366b9bf8117d92933202f6fe662d81ba0d7ebf8081b7d7d8af4af066ccb9f6512a4599822a45a85003e575b8f448b79504473c6d07e7304ab11d59a41050b2e5666256b22f14a5fdcc8c8654eec057284c5a8e061d1a62f42e059d3db499a2a278e09678a3a7cba9dcf84899667ba9b47069a770c529959c4194c60f556034648529295904f5fc54ed12b2c34c864c584ada7f9bea6d735205e6e01dacd1beaebc0d72d92329e32c604c7b5a03d3f19cbfb80f19b98ab497936980f18104e8722fdcbda552c9571ae10f39db206284524e59a643949ca97041865510ec7c27fb01f02c74839565d2e70104e06702ab905b981ae15ae399fdb013e9334f31d7c955f658998c81209c5449e0b094b2fe595844cae1e08dd7198e8221641559ab33ca46b3ff86b8e82d6007c702b91ab2ea4e08a19b223e1c1d834496f480b8b5e1ea5be691508b790729c46548682f0441c3b95b3049bb599465eaed31bce9ef94326f93c5b2c1689d5dff16769ac1e6fbae2c66170cf397172a8536d707900b6ae7677d6fddae6d780a77648a4f1a4eae6ff4caa59f5a7853171e9096133c7f9e3bbfe267a112ca8dc570d6b4aa1a5ca4d42bbd4bd58d8794df97200b67291f7c3220f2c7dd4a259315e92ff9a07406d67cdef466ca946538fcfd7729303c686c1cabf707fde6e8e8e17fc2597faf000a8813f14800cfb1c205401faaa4cbacf14cb2b9fcc86ab494d829895738c23bde9a9ea8e400faa01ccc27d295397c66160e09d9e143b3ea68cf6687ff3288a344ed1a6514f065b842b13bc8f055d6121ad4fdecf114c9311fd54f98c6b3169e8fd2a074c5082b6b6a17ac6fb73ad9c5b68775983f58978cfc8c848101ef18f84af619bb81064ceb9ed43a883d73b21c4c5126281ca20ac3b1c785d6767154891a42288770745c1d7cca3cb577d330239eecefe9b1ca02409046e8684f4baa697990f0df184d2430915483369409e2e282ef38de4b2c60c255e45b4fde08bd7b32a00d61d9eb3fe3eb05fa7aa19a1589dc55c3644ece95c0bd3ec035f7dd230add45c172ecb6d418a99505459ef5aa2a5dfececc0bdb8dbe69e37090dd4803e73cead12209fff6612df404fdf931f34e748268ba0e60b6e6615459c2bab8e649b351edf43cac6676e6cc43bdfde4a8f583327447978163160f2f2f714a455834c767c7d828e4cfdbbcf0707fc6b76aa40139f28506e0572dffe403cf4a1dfc123dd057e662e39d3146b236ee89d2be2bd23ca584d94515e56a9f15e8178d1a78d37eb9d65eadb4c80def84d9fcb4da9a399374c90469289eab034b7286b253832a7ceda9f6c284405c733491131fc9e40eb8cb40e92b7b04fa18b3afb2c19751b3f04fbf7720784438334feb3f6cbe5ee75fdf4266825b309048abb4485dc9dbb29c022d4dae41d572b35d44204e4d3ad01fbf4b8747ef199dc90fc7e62fb31d00807af85fe5e418c9df9f248ee45fb5d133534fab1895cca2f0b6e637fcea6644ada9342a938e8decf2ae55023d0c689c6954801c6f9c0b019f399631c7d812577ed14e48efc52504c14561b459e7f938c1794b79eeaf880a4c052b1488c566104c46d5cfa2f1472317ad07341b6b70fcfe4fbab3d308827284cf9a1391dc557bbf95098ad7e1462875903e7492a888c12881c1b84dcaf49a8f26ae8ba54e0f0cdd1ede6728a6dc042f7a1d71b3136cee1401c8a8d3c3b1d8df4280fd202f8d7aaac4d825cf0cb006b4101afe34eadb6eb79bb012227c5280acde45cf009e4d3624d9208f3f9e6cfe8cc6ef477860e96309cc4b869ac8d21b8ec2e6f9d73611b943bdaa2ae820b005be95015f6c8340cc8b6276b6e0629a49b1fb304f6787859d1e9d58217296b47e5d567490a46283c92132cfaae069e9dd8870d46c24381a8f6281b5e62f211ba935f1c077b5485c2d5784fb019ad405ec4a33adcc385b72dcd33052f75228bd27b82dd28975592904520624cbb5e633b0bec451a20f480025de4c5c6dbbf04422e3281b942fdb7e8821936d6ef3601cce035d17471d492d2f2ffc16742bf3d3c37c3def1be94190606a2bfcaa02ff8aaf7e678547923d48e397fae0067269ec03b4b1ba5a990a2f06b335287d33b29437dcdbd59bbf1953ce9572075d613057295dae1888f6ef845c188b0d5671e5887cc8b21ce08f10eb2dc26898cd44e246e1730bd04e5514174c768cb91167c7214253e6883c3621c112e23b160bc7c7a0a792da6e4bd68eac40384a9e306e5f3b4c69a425889526230a377f954675a6b000738d503a589c3e33a5e17e107fe4be90b45c29105b10be8c99a2a71163f50b70a0e8456b76b46313a17d73fe7b38c4d7523203a05d05fd645caa27d67a2598d4b4400d51ca725ea81ed8fedad71be75403233404d05d0a1cee023e23bf43f8cd11f8f6a0c5145e0ead1f97da37e106313556f3669a7bd450a87d7249711046fee3222bd135a3877ee8a8ee70450ae2a0411d887e8095d7baa3b8b9f06c5726dabb4b22e658f141abf366f2a749f193c0d5dc4b7949a0c620445cc9f0a1d4bd430775124d6ec6c54084bd9c4923884002e38585a8ee4829e056111071d7271022a4a42a166fa2221c15009c100d62ab66df82ab19b135d85b356339522ee4518785fdd21e5ddce812c800e97c6f14a5184f451656ae92af7e267f1008e43f239f338aabe9aecb291a49d87c251f43bb945a68ad8f762859bd26f2abb322419bc851b9adbca7d381cbf42cb9836962c5c1568ceec2952a441535bdc2e66fa53a5a5c1674557111ff13e50c2a4c33e1d4dfebc3f9a1855d1c79f381989bfcd6e444b4a4fa297f324a6e31c8b77517cbbfe1d1d603cfa65f6b06163382b8c1be328336ef920910f126e78a1b5d0d97e2d1dd4136a62fc4ce89b5da4027c4080808610d4ec818587a4a6b2a50c88311119b75215ec4e45e24c42e1e25aa83363a2dc733f93230a2d2f5a3833d00c17738be237f3c05c2fb743a5f5cef877b1b2aa45ff728fc4f4645d56f335426d624ede1962b04f00386b2071b133b94bf0875fcf0a2b528ba9d37a577754048fb62781d5b02f615125b33e0a5af70f01e50bfab2b52098c5bc3ef8bfb5864936e34105061c630a5df3bf13f86112d60eb2e0c06c6308b96afd729f21d03d1e5eb1b08e85fc6465a921029bc6531aae52b5bf203cf83746008326ebc7880ac0cfa16ab0194e0bb1c20d23cba17cfb1175babb4d3dbdc07c86eb7f77719a8f481a83e9db0bf2302253336ae365cf241c13a8c991a61b8329e705e2b605049e95dfeaea2500d6372e62408c230930c90d97860e07dacc0b20f91f9b52a898a89060e32a4b9e8f9e3efaa3f3a7a8eb400958fd286b22cb16b64c8bc24c4c73557ad7a3aa342d304c3fe201e28efd0f206011d3f04e63ced348dbc69f78d6529415729d8862527e9f9d07ead5bb94cac67a09e9b2137a8f1d6bc73fc8ef4ba0a5b66bda247372ffe32958b9060e4d6152d4fe65e952f1b113dbacd89b6b911c19a5f29bfa529c8c7514dab93d56de7da4cbdac65e07b85c234d4d6028a057e695d3054aa9a0e6a0566043648df8a781c00dbbe4c0f8609ebec800eb7d3a5001c762504bcf2e59d22ae78d18e86707c5728c7c2ad6170e0c3f90b019d78f36f04c59a6f1b7774ac60b0c2cbef5d9430ebfc6ea365edde7b6fb9b79432c914db0664066c063e3d3c16ca1559406e3e509d74b82b70d934ecb2cf91271a8db683310dd34e34d50e4d89988669a7a6e130f016abb94cab284653f64476b7cda89330c30e0c55d4a64bad45d3615db0c9c08e10842c4de63b2f63340d7659ad1897cc0c0c76314dd9cd3a155d602354c519643567c8c27286b6212eecb3e50c714970f725c946aab0db7dd1d908792f4d7a52310e4474e57c23c065d74a0e96fd0889ab95640993272c20da3393c57c601f28b6583d2d2019588c0b0c4b3013a6bc8ce0c98ca6684546352223435aae17cc5553115d2a5ab86a2b2f4ab86a2c2f2c609171821e19a49720a49697222d2e2e5fb8bcbc2c018ab166b82036b55a0d06186ab51a0cb55ad76ee8b9e20c1108975ddb8270415a2f12e6aa05a19b157366d0f801975ddb585b4f107f202efef8b86a4d83cb56803b554c1f2b9e96cb99e0a1d7a908c4a5552481450190f7b88fff0099d96d0a72e3987057c401f4015d8e2a2d10726da6566895d68805b2c0d5d111124fe24b9864184d919f2cf6057d40b9c702a16be8d79faeed454d1bac7b41a2f380bceaf43e972eee0782e08b13b8b446df4f0becb1e91afaff81611013194dad80e49b25f968fe46b916a6bcd4c81415980a164d70f14a112b2c2fae55cc0fc922e3c50b1991a352a49ba6ec33121ba212e2a7202cdaa2ae57cf68453248620fa9258a1697971a5c5e4416ec4524127f6658a3939135b24647ee10f88279c10a26a606b8b446406c16415694b2688bba4a6b9445d7d018d90847e0d21a7d304795e0ebe371b087e4f3fd64990fc86657e08ba66016889a6c5006213004f7e28498361c41c1777a0e4e8540abe8c312c123f6f8fcd84dec61e35e84b8fbd2c3f5702d47957d850f161d70d37c9d230aa5468424c992192341386cf06cb00a58c0454db5a341e78941b8fc7ba1e2035f78e0c3a25d33c150dc61492c269bd16a2d5798f2c2452c45450ca2826fc02b3eacb0882b88bd0f8b0c17306246b69f214282e8c8202921b5bc18697111797801c24b2c82a883195d04e5c5bd7286b817cccb106c84628070d9453f8dc551cb6581aea931608e6c841460ee95fd539747ecf18115713f3fdc8b83d1548fc0013d600726f3c6e6d9c1556e31778f9bd9ff79c8425b5affc54cbdc2a4b0bdbf8f305ba529f83cab208123c049a0fb1b43f73706eebb124c8edb8d97c2e4d8befbedbbb17447ae347de63084c990232c26469ce0903f150e80abbc7dc9738b0a705965333663b5fdab8ca6eea55446ca9e8e25ae323ade6da7a9e97e7f95b5e0e5fdf2bb245ddc58cec880bf8d654c4ee1663296bd041c63beb1a9a99c3dbe7d3993cbd993fdbfd90c2a51a2448972e37180856d2cc9b1145f2c541a35f907a58c3c2aacf6b8e971c3425313f8336441277c1bff4a60e952d3078e9df2608f9b07471ee0a78c97e648f96fe4f1d520587657288179e37d87119837e14852930d35f58325981cb7c7cd5782c9d1bdf7dec8c3fbee7bdc7c9babb4b16a542abb74a91135f9df8bababbaa851396346345567d4e4b426e217654f52239aea1b5ac32ba35c5bd9bfca4851f0eb70825ce2eca3133c62e1f3bfd93d690a7d9814c652cc3d328909fc57e4126799b2dad1092e9fda803db65a65ffc1cc8855a6a58debb1b94a185fcb945c2bfb7f3d593e451d9214d1ed45531870d37c1e1c4d419f3062027b02d4508278623db2e9331d0723269e62409be6f380e399024aa6fdc4934c9f462fc9f34b96502e679e74089793c523f31cf175a4a84f6020b5e60cd9982ce86848ccc88ead7bd1c96e234f3a526caf1c9da11927feac603aa80b989ae67de941ecaa60c8d980fbacd3d1025c4e56fb9c9d270ae1e50c7d26c0e564bd669f8e146017b89cac17188a40709030c505292a4e5e40602420aa828540d17ac22b55d41596196020243e83c88d74434819161932c0e564b5a0439728e9d4d82dc4f9a801c3004db20f408b1c1464e40c91b098a570b869c268ea446343325027db661b2d7b29931f49478a961715c01cc5a36b6cd778d798dfe2e212c5e5451ce2457c09429cb1037d4affcea0c1030d181faec7683ead5694671bad32c7caa919374da225d9936447628328c3c418e172b28c4c32169333348208039d1100f07202009020968084e7c1e564c9ae9be6e320395fb20297936544262b8d338c39432588ab958c68564fd434df2f877556eed832b2bf4c0f81cb594e1e998cc853dc3bc9635cc667268fa3e873a5930cf7e4dfb1a9c96fc41a70395933948e0e9aba013041071368bd4fc2d035e8e7cc1b75dc40d3d0d41d7538c9948e4d4d02d0f1f2041b71147d0ac2484099c604653a81a82c97e4d7260440a684b1f42400608418181a33c4175b05c0b52e20c666755ca069fcb751c7075387862b246673af789a62114266475fc8b869ce7c60dea0abd9a6f9dd5dc9f3e7dbd0d44915b319673823575281fbfb2921cea55b91134734b64a8d8a6a765430604c4c88633fa6fa91ed079e2b1e4e4e1ed5bc010211ec70e20866fb2d045f237831a7c7d5a9c241001bf7fb4fa6be9163d2b86863d2f8077a571b703337b2f055e5b8aa46627337ee740dff2ada10c7b299d8a8b5daadb3d66edcddb60b76a3eaf7a94b0180efadccf04a6da76ae4366ec6dd6fb54e0a311098867260f7dcf61b57ef56b7a6b93bb83005cf750bc10368aecf715da5dc0782e0e7dcbc170cc350050a012e736357ef0427ca7eff4f1ad9bf9c2995ed1be2a4f14f0153421cfb2973146318025ceec6d935eef5becfe53ba78e169cf457cd1b13681aa740d770313b1d77b00ccff7be0e8627c60a0ce61622f2440c11f6720b1121c24324080a22455c41e445c577af285654ad140527a9f738e94f3abdc72612e23815c57bfd467fe9eeee3793a63f778d7e777f6bad1d4b73e2275c65c8e35bc98afd953f95eea2febef3b10ce7f962cc4935448b99654d947ba6a38d6c70449e470d65f2cc164d2ea74b091e324c489edfe50c8ac99610cae59c65da4cf27d39974ca33c7fd6e617b99c477912b12197becab9749e3cbf749697de53ba4f9edfe17749ca61b804153944400ec3c7b111e4f0c5d8921c3e18e284af72854fec06c4df7749cadf4794bf4f09a3fc2d9144fe94f8c9df7b21cee7022321ab1bcffb2ec4f13a1b10c1e9ea103132f75b88c335ea71b66a6f904b52b6310ac8d55134d9da1ad8906d0d90642b342448b649d0c8dc9de28680c3eba682b99dc8654ca64632a5482c91291251321523d3ee54005af04488d58dbf72383f14d4f0c316f1a01901b2bb0c212fc1238e88228895fdc9638f0641e08e907534f02287ade81eb1eab145dc113d37d41c245adb1125c8810619d9235e2ccf49e2558f80b1664e0d58d4d4f708201b72825cd4d437b4c157b1c32c08163f76e862842cf0a5618413e83003fce516e2c18798283ca4e08130985b88072372c0430d76e0c188900f4868b4327d9727b0d7a4535626d3f79878b5ae99df5f8ad58e9e918a4a2eedcc7a4634659168137d6a6544c89448a69e8b9a68984b9801bb5ca30fb04cd7e8a73f0201979e51f6b4e8547b465d3333a56064fa5e934c69b4c4a0b76bd4fc3f63c64a1700eebb36d56f9cfb325dc3e57e6c8469ee6da3dfa4dff67d0df0fce98c00f27cb0d61b01689af99c0c9d65e905326fde58830315e66fe6c6db19b7f460d5e9d4311bfbf2376f869e748dce37435d344d8bd3888b7c7333d4a4c9be19f2a2693acffc51b0029d6cb45d3d99fb71d37eeba3699e63697df0e4d945b96531d509a1f7d71f78c16a3ba5e491374042589af973309c2a741ec89c03e6fdb014fecd617942a9ca5d80ecbffdcca4f1f79ff917c5b1bc9e67e68d15268dbf3b065a47d7f03fd1940bbdc2bce19dcb26f23a4f03738e30297ceefe73f7e51c77749cf41c3748e124cfe6babfb9bb639f4a369a9c4f57de903ae704593e70ced1fb597ae1946d8aca4af36ca599a46bcc5f29f128cd55e781960568fbba7d3b39ca6abd15638c31a6791b4b1e1b7040e7ee1a0db019fff4d135ee94fee09889bf863843c47c0d71708bd2167e8b639fc67ca53e4e564b5b4ed64f29824b6779cb51e504ca8ea28ef27107e2a9bef9c9d58f322d95b4c751d5513c8eaa4f598eb22f245b92e9ca515d7f0229c9f5b5080223043fec23d78f29bdc0e8b295cc2172fd2e9a365230e5fa3959abce474386374a4f3276a6824eb268caad6853fd1fe42d72fd12bb17b93a943904123c7a92ae51bfa588b75c8efa71d48b06912161f90bb48f9f32cc1b3456bebe8e0623d76e926b6b91ebdbf094b3f0c7bccad78ff114ccd7fae4f7b591944dd44668cc31f27c3b8b9027108ba6c41963298af365ac2e63f92d632992c612cb7056aeffe1ac88e2bd260075f702d5c7a5c972727e4c09a6d49e5282cd5ee6de38adc8d347fd4b45999916bac178c224d7ef5e92abad61e7efd8e1e47c0af4e2337af881a36017554053f4050847d9a24a6bf51b91066c69767a78c3b6d9ad68ba1461ba11aeb2a9895122e099755a5dc2a8d607bbc54045391722709bb5d984ecec4281cb2e2a2a2ad2f164d117b50d70d945508a2cb5aed54a1240399fc2a89aa2112ec6c02909eacb0fa675192365b1489e54767bf9e1744fc07f000f738f025c4ed6aba84aa52a55dc2da239388557f513d9bf64e95459a89a76bb4d0612600b5268600291062b5a793ed6e1333de6a41b71d2c589ece6781549fd52d3e012ee16b3580c7c03b3229bc47c75df2509140483a6a14f6590a90dca77bc2f7f1de1d2c63c9aa34a1b94e9db204a65311b2bf2a8d8620b994c367bc1c0c0a585bd602fd90b082693c15e331aed038a0979ad8bde01b9ddb05f9e7080dcbf95ac8dcd1b76b45a340d7d3a0a4188b4341a0db3a5750d2a237292084d96ba9f0fa5a4cc1279eafee5c2fa75abf6c74d5ea3d12c4d59206ef2777f1248e5c9f77d5fede80897f6a87654fb6adbeae8fb8e6a9fe785e7454b4b4b8be77d37e0d2f33cafc5f3bc9616cf6bc9220bfbfaba567b2fc6b6464df4bbb7b21a4d591835d1c737569380df74a37d95fc467c6116edeb711475155923da952ec76d1cb76d5b589f86d6e53aaad9977d595babb5b5e6fa5aa110168bd58ac9bac0e5268bc962acd84cc662c9b658d87a71bdbc9ce0f29b7db34ff6d1bed98bebc5f5c95e5e9ee779d686814b6badf5acb59e67ad071ad580829ee0720b020a02028a058146a051d006548382496e21285c9984dc42370023639a7217cd42384822840324300f42c49193ee240f5783b280ecef412e73224ff1dc1814483ce5b272208e6a21295634e537feb42bcb5165adb55b6b1de2d42227a7a840314755214146668e82a96305922b0c85a1b47f1cd5425040c90bc8b42b8e53da0d824eb607d55a69e98553a65f4b42e89020b057cb6b9e5203092402c33cc8512e4779ae3097a33afb8fa35ef5e5418038e935c868c58b2797ee82cd317059817a49ae41c904c82db4c551fe265885b805c328787b1b15479bea97a24cae33b932e1ae1256531c7fc0d85ace75f4a2dd6d2ddd364b9b369deeca2c537c47e06af5f5e0725b657ab4b24747acd577f41dadec11b80a5de18b0b5c6eb36db6c968b3d015ba669b2c7cc97229b7901028b9c81392d00c68b984dc4242a8c8e50b4e807202720b398965db8ac2486ea12884e420b7d02c89556129519b11e5169a0de91be416c20193bcb528fdcd35e44314b4c46a88670641b9dc5a3300da5e4d0320b9ac4c327d5a52dbf2d95a3e99fee6b301c9344a2eed4f15bd108c197192facc494abfc4292fe3299e226c7b7f5b8ba6f0d86e029f8e30dd685b4eb6ba080988c85d056f88038e4dff2b5df086b98bb48672b7b5485d3762ec8510982b1f7953d9ac6dc92177911e7cc836661345999f91bb484b8b6cc7727b653a53492e5461ae56991b47ae6f6aa966283db072b5f19424c64aee2223b821d711c7c804bf00975bcbb6b6168d5159a65f6e2c9f852b2b405176c07e2e6b2d53fafe26c0a5cf6a751c22e5e9fb38496528a27ecae65289e1726b656ac3146eb63938110425790b716cd7a8e50bf9055246e224fd0aa329aaa44df4b5006a1244c1c8f44b5a24bb61b643a6b4d6225ad43594a0cf819a4b2fea9a6d8894f71245e2a994a74f678eaa4f3fa5647ddc29a551db2279813f975b8b875c6eaf726bd1184d6d5456a3bfad688a5b5153add916cc112e67c762798ad9dacdb5b56ccbb626e85ceb7317259c6ac2e66c02c9266c523a5f5a804b95cab6706bf2e01279703961aa20b23f1744d7a864484c57cf1f680b971316032283c16030123661b00963a5268f9b56b4c727af58a917dcb44101220b3213628960b44cc7d2fe54ee05cee69c74d65aab0ab98e4dbbbb7bb64f2a8a2c2982e4456925b32dcd6cc30778d98ef42b054d33acb4d64a29755add12c16b2170aab5dbc671e0bdddddddfcaef3be0f04c31a5e3a670a8893e23581fb555a9627510649250d2170d36f65c593e112cb904122b5b4b8b4b8b8b89064b0b8b8ac60171717159794d0c5c5a54997c6970369087bb1f7624e4e52c64deea64cc777f2c30137110e7872f95e11786485ad23e775ce6e9ce5ec66edb6826b6fb84f9f34d676736eadb59674d25a4b27383e81e79341f0109e5fad9d131b61376fab96dbaae58a783f9cb55c1375b35c13b5daadb3d66edcdd38cf36c16ddce68921f8d5ba719e6da27676fbe97e304df7b5721cb7d926ea9c4f27ddeac8d10f04c1cd36f179b59b28729cddb8fa75b34d78d56ed46e958e6211afe39edeceeb386eb31410779aa085dd394c181fe5eef7c05da53b4f2ed781fbaa1c2b2b2b5506778f743fb89d0e386d5e1e104c1f950856585858647424193264906e0b89446aa974879afc55de07cecf7b00f7f75942152c905f034e1cb558ee1a15d5ec6c5425f3333242f207698049d33533c439b5ace0164b63d2f8b7841e90264beeb7500511642ed76fe19e7e4ba8c29602f7f441ae256cc08b48ed46493368d0a081315671e26886db4a8d8a541f0d189810873e4c0d64fdbf5f304124259733425c5c081921c31746ad1bea3d990a311194297df194995001132e253f3f3f400001840ccaceda3f6cff8811c11f7fc32afb7dbc0318b07c5f96b173a24dfe2b515c4c4556199564ffaed6c950a5f539b2adaee1de11695477ac33726b5d73df8fa87f7de2a8fa9815fad726b5c8fb57226db7aee1deab935c8db2886f8873ca9734fc94e740103c4165e5ef77f7fdbd3276326aeac68ec9c417ccde3d71d2bf497fdac9684aec8ec9bc21529a4bdc31d9be33dd70773476b5ee4957f3c031c65263f87e8de1efff45b18bd11afb66792b4d232e329efe2cd9bfce64f58ede2af450a6e2df854be0f262c051fe2e740d7dcfadd335481ecbcb097972b3e79c73da6de356ee1c4ff544533adae4d7167160e6f2d2ba594a6ba5a5e9d74dfe9d32537d73a373690200b2df942ef9cb46d5918edea103eadf5c2f105d04e3398cf8e290cb27e204b99cb921972a2dca36928f7491cb4e92a90e3d55b05c61c4200835b741e8480f38175c3184c805434ab618e32695032eac98e2e7872282b8e9f1230a22782812044b06d90d2dca9844e6163a924466c92d7404964bfc4356b1c7ab2eb239609ce07efb3bbf7d39df8e3aa51d276bef386a6e73ce3996dbefe894723859673b736b9d9d6a6dc03ab57ef5af45f5075793188d3dee1869f63cc15d676b3e1d27cbc9d99aabf9bdc3c9499bb4499b3b73b6266bb27a1cd5f239592d67dd8bb128fe4f166dba2ca602ca03a60b3c5f70d2fbe9b8c34987a1efed96e5ac4a3b664f6fba63ae6070d27dc03bbc7b52a74e9d3ab545cc707cd7e8696d2d810aafa07d7a5a5b65f0018515889e4cfab35afb755a5b79eccc069f9a09a64f9f3e7d5277ea3a40a18b39cef0988ad1b19e3f847d3bced98293736211e7d8883d3149c4628eceecf445750a1c24233ce7580215761cbae842c74e0bb41674e8d8d9d16199d85a145c366d5b59a31f1b8bfec6dab69eadb5b1b6160db86c1a6d031af2f9379be02fb7737f3b95f2772cfbbdd58eaec4e3a8bf1b7938b972548fa9efbbb1ec71ae76ec38d1d4bc09ff7bef03598a806714e194c76f717478be0f6b1deec870e1ce2a0f7ab89452828940ca7fcf42ca7f630c45c4703fe5fb708c011c7b545113d942e9fdfccec727bd9f3a7648ef743a9d3caf44becc77ff32a4f76437ea7092ae306d7a298db960bd7e83c0aa0942bed6bbb2021114145cacdc886db5d5fefc5aabadb65a4ec4b56e5f6bb55cad5b3de56a6b137cc4c662aa1a6c666c5436aa136973efbd362a1c2a150e1b95cd89075825dad812b4dad8e91aef9b1413eb264db4682594b68caa26a0a25e577ac149fbb4e48293f6bd840127c11bb3d91ed0f0515a5d84db54ea7b5291a727450a43aedf29b4c97e14d92aa1f6cb53b6d3472ca76405f66f51256622e6115110b19863238ad83149c4624e157f9aa753d7504b2291c0ed55d464ed2720972a27ec974dc47e99806c634ee8d404dab4033304acc2e126fb5d2a02f69f3acc59cc0cb9bf3a7366cea15f470dd09fa33b75ead49f8ea5fd1c1bf78a82a3e6cf7628b8ec98cdbd188be23fa61636abe198b151d9a84ea4cdbdf7daa870a854386c543627172e55e4bd188be27f97a7a13172bd8d451ff141ec08911379521b39fe74b47132a7df7f5439d99fe38e6b29a76443df06859c6a93d3745439397d601ba12122e4f2c1bfe316b8bc79f2ec202787a64aa6bc03f2656448f29ffc8fa9c87f0cb8a0c305162e5b9643534dafac041f5dfbf1b50c89a6cbdfd35404a8689a4c7f9855d04b61fe4a9ceff6b75d2787bf06fced9863c7513ec26c9ff23d6eecdf4ec16c234c04bc0f3f87f7e16f1f8e3c8ad8c61cdda78c3c52be7b1ee17bdfe3c68ea58f3b3a3877d6094bdf570a1d10661f6728c13184df37317c6fbfec59df84251e45b0409308c16775f33df8df0c6174c09740df806353130b3489107a8872f38d2e5013fdae74f375a5bee91ed9c7161bf01c4514444795fed345d7c07cb7b94f67df9238caf0e7d691b9c78e9a3da9486bc065cf5a797e975be8091ba818f5daa2cdaf0e5e227287703b06b843161ce086c13765668081491623dcad6204ee906526e32f23417e8cfc58c5303ed56f2ef0cce965485ee0f2b148f202bfcccc49e5289721f7e3f8ffff07ff7281cb5b899e90c228b717b99f88a287fe2c92208c4c9f74db9c6c4cff77824f381cf5ba691fb97f85aee9aeb5de3b96e2a94dfd5e6e23403ff21c4bdc3f9fe012f7ac069be1a8c42c9aea69ebd48c00200049001316000028100806c562c15816a5b1a67b14000f6c883e64483a9987233910c32808622086c100c3184200309a006394a9a11e679e82f972111765844447f297cfbf8eeaf20beb3a636dadc7291082ec5ca3078487d5234f68f6fc0805e34b84ed51d1a3ce7842464aa59986700432f08561eb590755bd1799a0b65a7a307d311a62dda246d81e5278934c5e9231fc13c045c3b7bbd9dceaf1104a3d7bda274591cba5cd32799136772897790db01f1e46b4222f27c942714d14ae9ad80e5eedebfabab263691e0aca30ff0b1b7a46c831a9a24e378d00e1a80af4cf88e93d121c7d6866629429a1eddd0d2417b9cf794f89b811440a18af94862a29301db4409148e145a9f294b24b033f18bcb6268d5080881e0a0019f2c9a145c82b03dbe7eb314c4b3d99235396276eb174e91082295de3e36b499de9215109186ce9932ce7beef28db0ca9a24460a2378989ec6a29a41450f4cc0f49eabb078a46ab3791bfb18910a91d31698a4688548dfce9026a3a0ccce13602b1af83ba0c238a30d04962c674a6166da0d7909dc501cb249cab5c545ac5c9ce4893794a29aa354f496471780bc5860e46270e50b06b306672970f17cb63162da6a0143824c274cf8e47d9e6deeaa448569426ba839e8bd693c2fc3e2970e4d05c732745a61b91bc9d93a24cbd49815d3d17801c4be189f41dd9bd905408187e5ecc8e84a9a6701d09d7349d23b144ecf8ec3930b91d4cb5245591168930b5258a7ba448a4df0e905713fba66e6e07a43cd84167de0063cab55a64f61c186c3210522484387c10b1902fdd5c665d0b137dc53ff1931062238b0979cf912b8980233bbac8461f765f3718372d0e871c640008c1bf0515580b6d411059905910e2e7358685603ddbce31cfe9c662cc5317dcfea29d9e6dcf39a1db3b8553861d77502ee29872c7d52f615f0c1ee043d087b6f3cd533500db196299074e79923be82d72b950d3dd61f8d804903422938b68d799f9f305cdd645056207060aa9d3a11f3f9e4b138e946d75e2154be9731e8a28b1e72b5203a0984b539d2bd2c7844d099c93473b616e8ffa30e6f2e4522e89c86e8b2dec7d0091f421f77a80ae475c2be36a50164d32ca2394eadaaf6a129c25332f6dba39b10f50b72843aa0fca87546317a254633f34b0bcc44e0b9b3545544ed9cf1b8e867b3608953ae777afb3fbf0a6840eed269362fb8fb611f8535f59005f641d81e800ced37f722ab4627c3515ac8f91a13503e9ff8037826cedf2457abb0f438578f59e784d1e3efe9fd9d8bb8f617e44a12ac2eecc4b496bb0eeacb6a92280723def6b3db8594edf82ae1e10a8a3e6475a882fefe6e2590cb60d4d3b2c841e3f5ef717f9526ea51c8eaae90c659e0ba7784db9281b628b8ce5e297a32971aa49a9572f7a7b4d19e1f6b2568a0cd2dc3ab143474957fe8869530aec72bb7b4dc5ad290a6e821423bd0c507e8a1ae7dd1dbb4e4eddac85adc203350f9187d3517c5236190539f525e8662fbcf7e4a663e15f1d940de4017b56427c8bf8984aa0a45f3e7219dd94d20debc367e4b319caf19ee0c0f64befced88c8b30eee123ddc5a5f173c3922ef77a98f83dc30fbc4c6e5e3eabf3c819368e468fab3d879c7d6b91c9a7290c7a5cbc15af963cd85462a81402702b009f744552d280dcf0d4f6ba6b0c2455246ec89198fb072f1f5c20e1607b1d5cae89aad6b4ab2de079a01a5843003d4ca971a96113e046c8ade7987350737bfbcaf0e6e4b02901f69caea5990f070d3969586d6dbe086dc679c566e6870c9e92b968cc92ba0c42d9ca0ed405ae8512d6853ca216aafb0106c30ff63f8656851aec0e086a52275e49dce69c42d274fed00a9b4b7c8145face7c44a76ff0c15a183ad9081a33382726a24d2b3ae8f72064509e2f49ca7b1545568c510f3bab5f662341ea4a27dfa7a65ac178af41563b16a6f32dee052a01fea8b757bb0fecd88dd1cd0e23aac64200fd689e3193c44405d4fe384ecb68d783460d373bef539eafde0f021f7cc838f10d3903416a0737466b4cd91cdd5d46000e320dc735da777067e7a9cd1a08729ec831dd4a514f056c0a4ee24ac67181cfc3d0a159f186361324538763ae591bf6a4901ffb0e4cdc2dc85bb667b3eb446b0c04e2f89adadda66a56e03c12fb4abe3ab5c349caff53315498a38ac34cb7404c827fca0cb169f594e104409cc39f8bdbb81ceab2b39f6208464b174622888d29a2a59fbff22c2e1bd89fd940e76cffdf9bf5c96519b8e582c408835ebf0fe6d2689bbd32c3670e24c8dc52ac9775b6135efe61508789516079945181ba0606cd26734a1c98596e424d7da5245dd934f51656ef664ac01ebff5ec7104d5c40db9b7506238ad506ff5a994579c3353e72fd1739b7ed2f5904cd9183f51401b05e8fc165e801e7b72b561ed03551538df8f9f3083e83b9e4a92420341c5370fe29badeae2507c644c6e7258a819346e0be02ae0e160d31dbc3d9570e7e8d734c52dbbab5e9154dd348df81fc5a5a8c2b8ed8fc4641c3627f1c8097aa821e617a8d3e5f94b742892b1316467207947f0292522df20a7bcc7785cddd67118cc4140c28b006807282f451b065fc03fa48d528ea4b1ac2dd78afff4c1a6d155978dc219e736155d6cd3769eecac5d04683429cc1fb9a6f86a6da7c36a22b6158c1660b472caeb419829352b422cfcfaf53b049bf748a18c88e7abe293caa18ae0c58c4ac42b57553b549f06ce79a73318133ce33d11d71caf72f9933f063cdf35e1413b4a483892b06aca112a5b226079c7db60dec0eb1d0fd5873bf4c6b0663d43b8d24d3f1c0181b43246d2ec65dd985371548f371d0ec3a5ffdd06d02a95ae33e0f8fab61c1d97225c8f3ed309ee09d981541d71c462732145a3c6c7ca4e778fc0a50478f9f53437c6760ecc30ad6e2e156a0a250137c68a686804ca4e54de7a0ad329c0096accd83b349e512be862df5a95adf0504b5004d42a522b1a56f00d69fe72abd8df71707ec5584f2a51f9ad1a731afb649a77962ded9d7f3c876210c9f5607a0046c192aa2338142ec0d16581c5a9f0b9ef93af0e5058df663d1d20730c50ee7cd6b3efa1caa79431b7b43e0e12941382180b5b4fb45cf0963a92c2f020d88bdae3e214b4f038add727f13bbacf611b26b2795dcdb9638ee093373677ec4bc487701fc20e61f5ef92b5bf22add85f3d74ff9590360ffeb196c5e00c93d2e62b0d221c278334152c168640e759ab1b3e11c70934e322d0de30ca01090a2f6511216e10cbf611ccd1704eb883cc9eb67c2da92385ff025b3c827999f36e5acaa1d46a4e20891987642843256c8f11d644dbaf8f0883963afb41ac9082c71eceed615676b75772e2688ef468317c02429d3fcc44a67eebdde1f603020ae1cccbbd32d04af864e05eb03838a6f05e24a53eea03f20f12441e9009752ce466192e8314364d3f352efa8e53d4e68a665ba4fea34a31610ef7ae3e69afa8a32d5a0c5a218847f20df900118247a92ff878079d372920006af437f243826cb879c5401ad880dfeea032ddbd05c3f04b585c240c71367036a08660764a705d81791cd39bec18012ddd27496876b307bff314826fceab590d4cfe69d04df97295cc600e57fddce0bdbcc1d422e57e7fb6a0a3201c8fd664115f80624236dbd3e69b29a2007d2dff6a252f5c270e022a46bcdf3f5f190427cba1e183ed7b9332994932acf389bb5935813d6a1a2535be3ff002ee7377afb77d6071c5e11039c355cdad6254cb01dbb7af73dc85134a0e64734af01f35fecbac84c4e730b9fbee72b87aeaf26464c997cd85b6fcdc9570aa751b089439b6e99e0c964f5aa5398d2bb5ef976898eb6c05d3d38c2f72d6b03ac69d9c7328afb3730bfcbdce04239a228f6850b1d56cecdd40d5b57c5dd7060277e6ebed8ce78c9ed5b8cd1c05e160b79a00d12f9e7d59af386d37084176f7fa13a6ee0ce3fb5f8de8537fa6be4f480bb427a6fd380f72a1d0dbb9be5858aec8ddca4a2037b49003417948db297b58226caa397a76ad32bd0d51d3544fe5121e51159ea91175bf93caaa478fcdf7656f3261a2f6f93edcbd4830db3ba43ee278fafa37dd680b76cbde069baef1e7e33d449bdeabdf3d14af3f00a9d878861a2900afef4506ab02bb5e3a86d7e9ed5c59a3400d0e851ed56cea9b5efc81231bcc6f1a9090dee68adda7eb0a31844940a90caf44946069429074017762d8c658e31c07db8e4e1670006e406dde710d06251c9a06075116f35802d06d6471c946209e9ee2fe9cd03030517ef84e2e07ea834b1cc39486d83e79f9c0282fffe41b2e7ca22c551756d39d3418347a9307ee0f9829179af8db9e204ee2c72a487e0f0e6dfa10b1f923bff0babb5bfe564c709ef985f40d5eaed973e16cdba0827fc90bac89c94016907751bbbbac72ea1769a28104bdba36e10871b6c425ba9b581299c311ce3f83aa10130f67898f063019ab106a9aee2221cd1e37edab1fc7e7999501e455e2f454ad1a73776af626b39d1e7b5636189a39c8f22ea3a76f2b4ba8c4664645f3109d1eeb5ee7b61cfad9643070fbcfcfb6bdfce91d01b7531ef9a3a0d13034bc979082998801c72608d96d0a8f45cd0edbd63b81f15318f3cd126cbf97ca88f97981f5d3c9dca4b97f7183206a4d931419eb44ba82853cba44c6c03a4b81425bef20c6c48e1f969534fd6d5ce06b3b2004626a59c5da32c33de825f6ecb98bd83c0c7eed673de06608b26d046c1040cd2b4349af9d65efbac23ff96402828c64ef4bdcb18bd3154acf23c00bcdafd34f771d20aa0c5156f2d4f6ebaa19de70c4f1a592e55d348baf6bc4ce5494daa538a7dd45580f56d6a8a603acd180eb63a4b32807a683e2dfb3894870e5309f3860da5c4b276002fe86b7d80176750181e41a7820d0eacfe40fde9d64f9fcb120bcc312e0552b8953082f5034e5608209d31066b0af71a304fb69220e4a405e535720a8f6f7395a6df48a84f62a379de31e1cd787023563ce600b124b4269b7c2bcaefcd1967b555b5cbaeb0627e17a832dac937af67a8f17927a6a28e177339382579107fa2c93047bca43ef340229a3e1b020ecef68d984eedabab330ab48a73968ab920e2c411d0a19ac096b5300fd386f3dbd3fe5b48206d4b65fe17de80db2f0432d29deed5f1d06a7f29eabd14132f52418e60756f1895069cfbd66d8750f496cf77752aa091727710fd635ba266e8f6b216a90d41a635d8c111fdd55792f02d09df9ead0efb8a6c03763f7092aaabbe9ee6c8fa800bc19ef548d8c51091352932f0953368c26672bb1a5cde165f73eee1f65f3e5d27468624d22469ed77b56bda82595c346ebb44a0f1089b2273b660afb35a233462f50eca9ca512736a5e9a0cb367f683593b4ba5057766ae74a4b9f7ec4084dd5527dd0d48a01ab03c99240ffc4e5394ec390ca6a54dae6d35ed57603357bd5236f9439e3cc0be39f5add6e4ab745199d9754e2912712e28ea935c66cb03fb0064bfd3b481cfc3b614410ed76bd44373c35827fcd991a2b1ca492550c8173c0f887a92ed42d448e3dddfd873985aad7aeae9d08debc94e9a07dc651204a6d9d394fca570d5f19488b07b0842c566590ec015e134dead8447433ff8108ae5e87affb749d66439579ac8ba6ec096b9e2f8c544d1868991b90fd8e99617b1fcd608ca3e4320a9c41faf97980b585825d9aa9ce4526c2cc99eee241b3a0efb90ab5da3a9c727d774a6e734dcfea06d01dec636d1f6815566aa43d8466159d32ec1194c3a407e00e8647b76b96f074c6e239b11d391ea8d1844f22510b56004a66b77fde19d57050b2c2ff40b106aafa63b053f022c803daf0b0f71ee1a1cefa07d0fca1b18e425b5f159a0531933196994d121c0dc4ccc855e7e15399e47e9db5eadb68d6a0640fcb20ab751fa8a4122d654a081b9867a1f13d5d94a3aae656823ca1b5f673cd0ad7b9536116cc63f6702d1fa8a13e2d1f2403f33351f8b5987c1447fd8cd76142d8ba08c766e29c0b24da92d3b2c05b36742d629afd70c0cf412d8937649589a0dbbd852119fe3e7e2c669121ae7bfb3b24b8bd1a1f883da822d7fd80ae4f6933a99a62fd8f1ddedce7d14d5957d3de82a65866525a7d0fe8d697683af8787c98f5f7caf7016a25acb1c96c0a8bf02453bf75d78b04b41e43df3d588261911173ec70c15bda394f0107eeb9a549c52c27bbf7dd264bddd89b8987c4d05937d4260293d80a2beecfbd7fe2236131d7b2689c6ca0e09de14089a0b24ae99b0d4533fe35fb4229a77d2501106c3d83cf3f6e7e0fe0f43c00eff7203038719d609d71a30e5df156638674bb2818b11958c5074a91fc8ee13ec83e6bbaa87969f774c88d70f4f3825034ae935bd3b864fc90ec03eb0a3613171b52cf0a20c62abd5d30c6eb114bc4df5da9986b3c615cc79c982a7c312b2ab55d79f05295f4f52fe7d403f908643012f79332cbab69d7f6e4a159ff1fdd34e57f156dc859b2f9cf3729de957c1c483cdecd418ae97e34acbf3433e226388daf07d9c17cace4570c1325495386199d26efe09acf117b5169d88b885a79ea08a2c9b9cb39d7a7045384a49b174f3b97485472f69304c8f5101fbc81d9afb1afbba65b3eaadf4f31b972b656cd50d15640c034dba70e87b4d109cdb3f140d7a24b7be197bcdbc43e49f5cf9dc29dd6928b98ac1f4cf3addb2880106ee8ba396b1c85e5e35719b0a6d31af93cafcb36ee00ac87db5c19e59eeef77062be5863041f2a1439e7d040f915bebd8fe70381c82947e8fbd0a56371477ba9e86c422a576eba39ac6c39f67573d5c366bd70666e6a1f2786e64bb188ad5113dc16785afc8f2a31373bf1869f0ade7ed40e53999e56c09f7c9e0e0c54528e17f731827f7a617602ec2e4c5af91c8ec1545a2c91d49fa6298998650089c511a821cda0bcd2e3e26b57440bfb4a674ec404affdc4c1db3c8fdd9e55b5c6add2380c93711191464a5bda987d981a5cd89746767626497ef0293a08089871563bfc2c29044a506b4cf4770d9166a7b94696cb69a7417f9266529b62fa7c20b2e6f351495f324a97048d18665a7ae53fed2544def6f1f88ec2c0e5a7e09231090c983efc39d1a38f07fc5806851f8ffe19311998b92f5212fce4b9b1a8cd891e3b3e8835bdc156c5d54ea4053805de36716ec00f969f399e20115a1589b88c1d0c08715ec70b48b1bb83942fb4c106172c8290154477ebd129b2cea86344279d165b8213add6f234efb2c56183729697e7ee6c050cda13129a0406c2c3bbe5cfce02c44272e636ff7e151f450f523aefbafcc1b799d0199b70eeee05dff8854e40c7b4c9cd59931cbf35df21b2bf142437c7e9cccaba63743371dfe8b31b4be1174d25f50c7fd2a5db21637ea7d3df6fd15c0d0d88353f36ee9743d2d6725861b2a1dc499653fb8169e1597c9b24b04edae230accf47c40721682b2ea146cfd7e0fd3b9984574ce3dfe60c6e446dbb7593efa722f58e263453be0ad9705b0370de4401589292bc43220f0a05935f9c17327c63d100540575b6ad558c4b4a3463a2d6a9e09426aa5606262b551c8349fc8c74937b3d10eb0a14d627443488d2ede0fcaa01b6658f822bea820814c0391bd097035402ae77a8a94d1164a88a912c950c3632348d716739e0c6deee792912a04a10b485b30216dce47f3cb232b6071fc510cea232dcac18b11867a2182335fc56d7a03f4d56f6e783d33a73933b12d9722e42888554414e71d7270ce76c53e6fa20406b7fbe6a22a32c1900a8bb5144b90288d806d792a51b3f489e5248c0ca8be9cc40c142e0f631533b3273b31f0146d7501b377bce98b94ed8fb0b156b97e62b30924292c0be958c91010334b222f0354a5b55c7a4c727146f10df3d5ca3a000982b34587127f7dc01e2b7d57ac3c8efd09fff56b370933a2e7c9877c0ab7d46fd258d129f1f859229d5bec808e177a147e4932bd9bb7670d7bce8254c394027d7f3d22c055ec671954a977d31f877e2e485b850b7010ae83426ba00689a8bdf7bdbf913d3cca2a3811fc74d562bfc17085747c124e092bde589ae142581f30d557b09b1104e77025bcbd4528aaa4a1f466316eee522eebdc903ecdb707a8d1f1c9f97118e687ff2cac500ce0640aba2303091875df27bfa924e1ff341074e6114b920bd9a32f280be71505176c66dc3f923ac0a04a8bc1497807323336bdc292e90bece6c4367e73c0f880d8fa475f633389f15bfbfec1dcfd173e3a889d71993dfac5e371c693de912ab3c86ed0d0d0773eda3d2ad639958c14d4bff4f66fa980555b3a99c92363d779cd017732ff3e48964d16aaa7016dcb8920fb12c9d1eca8a3911704b15751f34791fe5eb8f4810eb21843f05b4e48389ec1ea395b87523fe05921b13124110b6da2117528638e5c40a8b4513344f5ea895abc4e1f9be90845e3dcf2753f8b5b1bd5e4c263b5bd3332851d3676d662c0cac878085e84b18967e34ae9c16e394270dab3276e0f5eb806418d613c87be36302af1bf9b78e768948dc8c1e4eaa1adc6b5c1674de9a8e3b84f11d93a89ba0a33bc6bdb822f969441f69bd4a66c244651ce3c2857364cac51592bc55640f53f0abad1153eec654242e3ac65a92bb3eb376dcaebf026aa220a69fa182550a5261567371243cca1c06844bfb575bb273ec2ffec995a7c17a19dc4a002464e2fe012a938d80416fa5ea5975691102cbb50ce33529d830de9a7d0348a43010bd613ba59591639eda6b893e7e6c0a9468d14ea599723c4f24cbd01c54e74e0b227de6d2afb8a45beb2226366d962a4b674c95b15287782db07fb8962a2b30032aeff7651d8932fcf8ebc4dd1e1723d6ff0f09d440c0e50735994a4270c8028299dc1ead3e0caea632b568b93efe57a6826ee2f127789b432e4911e77841ea2b41327dd82fc19ce72828586de2dc6ddce026a086f69422e0d667a09db97c11206c827c74597b2dd526b6b9a0c0ac7ee25d4a15737333ed5c2135a01dc9e6f774c4d39a12ae6e22c07297a366f9902c07136b06f09591091329dad9461c9c556066a0f8428e2ab62fec170b2c452d7691938fcc1b592db13be0fc635b95d352bd803608eceb735c1fc211e36e49842684635b9a22b458b8515b5334c2fc51577e6d767d2c63c782ea1678f61333707d654b91f0b27f17e4ac7a8af85355c488a0222ab7342c522dbf0633b4ee14718b6c12c78a9dc56712bf60613ad78326719c055ba4ffd68660b34e74fdcedb799302e4690003e6f5dbcc4d00018c8e5b226db91da9f743a0cf4e731bbef713213d2cf35c95a736743d460eda95e483a054d2d75e2c063606f88e8056f9182f19c558258fb32d9f1888835d17495a471cc4539f7212a4ef3555a384cf3eb0d2c01440babf3e863a8040ef31e7968a216f503ed116e8ddcf83ffc080c7957bdd4d95ca43a10235a12e5d7dada53b99d3aea5161106acc423a038474074eb11502a4612f1195bab49e22dac0c3767cb03f85369fa66b924697bf7f9efe21add3da4e35e0907032c8afe34f769dbc0c6c0a493ae0870f7a7e7a8312f5b51f55be8e8f3f5ad0194868f1b80eb62a58ed31ebb49d5b3fedddb6a2f344687b8557f64dfa2d047df3a791a23299137ba0bdc3c0a7402496fda8e8e5d36cd9c7a5561f186c31d6a805b045bba444114252421553924d552403b51a31dfc5e0e51da7526379a1fe7fc90a01b7834c6bab7488ca57a8fc9ec3e46dfc41955d19c3de36fac7588923a4b339c8d9ec86f58802ebbd40f54f4505ebe7da00cff214b0fb994f80f606f336ce0c8497a41894433a1ca8b6e9219ed83f429f513ba858a1a7c437efb701db9aa74a989da1a0956cd7a4734d3f003ab9e577d93a18f5c094592371b590e060126611df9558fff21de3aca20732ae496c89a2f89a898276432f56655034d405e0618e16e1700a9ffe3c714dc1344cb8f0ecb7cfcdda73e1f4e2940abc9c1a31a1b87231528526590339cc5f591c023a9f21b3b4c1aaf6872886a5e5c67173c7837fc0b3b5aa446bd97e42d7306a39ea191a82903aa23ba2b059fb09e457d3720c7b7a73ba47a982ad221a28c54d9fc1969b67ad33bf740911cb8478ce58720b8b26da81063004f62642d0e998b4cf65237cc7b67cad6ec7f36db4eeeb7f9a28a1628e9133b4eaa5142963483b603190438db6126660a545069d990498f4ea079e1ceec14d89e197378bbd8e9052e3198fe8a6509a1ae1be3b296742e2c4df5d4a06a7e465faa20ca0a32f7339ac48b7888952a8fc49310bac4ca0574793ec61269364aee148c1210e63b3703de4194cea53ce7aa8976e9e5a38427b7fd8b1f2f7bf0f24025967ab516da205b0b3dcebc80646ae43beecae1dcc8ee54615e776de3010ff4fcccba15e860562bde705f11ac9acc36cbd1007433e5f5968f6792f6300744fae4b0367bfbb9b7c84592d301ffcccc5b2ff3968d68306071eb934c25e8f3ae40293a6bcf0501a844705269ed8be7e4771f7213ba962e8e6a70868673b3957a8b8b5a531006c5bec906af2ed1341e815f02d45ceb68d75907e5098225b659af1b7409bc29b30db837a46679ccafb4e34d0975c7bbdb5f192ec04309179300cd6711760b34f5a838ec7315ce42095b5000d8e358defafd4bb542a77dad6c1bd4e2eabe834fe9fa89765c408856d7140f3152ff7d152eb6bd7f995fee4fc1c14137b574fd290134687493f0a921c4dbc1718b42076ceb900f7d30289f444eac28b32fa205a4ddf5cb6cd1d185d46bbee87b99e3421364560652f624c3d1ab75dfe734206eb40c7a3a03c0c69921601df9c6b0f42d74d695a96b878c7a92572d42cd49ecd9d5f40d557f966dfde9d95353650599ecd5ed38bda34233a6ef3cb903ad233b6b98b9fd144cbca89ca4f8533f7f6ed44d6eeb0f27ac5f3c3b13fc421479109ff384c52acb6bd46ac4f4d46f91a4356938673800bae08aa3b0695f672f90347126a37743390dc745208b47ade62b2a5d0f02d650b3bd85032cc722c22803056a05223aa19e226806e3f65a65e47f20307f8f86c35cbecb38b9ccd8133512f1c9cab808fff6a0c664b9c186aae313fbf52588ecd1f8fe3fb93ee0e62f60c289bfd0c25918f19eaa731cff5572518822cb141fa97c22200548e9f1808d8c080e955eb023f198124eb64582bb4a1304cec414de90fed9555d2488dc7bda00261e3428a6fdf0b6e335b41d83ac414159743dc2b45f53f2a7731a83137a6abb653d6803d1f12ad365910431cc690f244acd331edd9c802ebf3483964ef0f5096320182455ce3850bc51a9ba0c8e721b149ac6480ef3f6c7c67f83166c8d89bfcb0db90e791a6be042d3a9ae5fc1080a67ec8aa827efe4d38bac908915ef2bc5be19bf9378f638d6bbc2243160cc44451ce9767ed5bc57ea416470067d67793dc3ada6f2dc1381b816331b9943aede56244aaa78472971c68bea7962e19591b13d30984b9eb38b400b2d25331221747da8e4adcbfbaab38c6d4c4695092e64ad93fac8ed8e0e379119351c8acb05f9b1a99b84e2cb4e1ea822dedfd26f1ccb31972b1b44e4c1d35db996188e5f68bb9e4f0ad947ec4d8b10ccecca58ae419c55a5223db466b90fe3c313ceaa78b7c098e0ea0b92d779583f76a03f2d2080904ce46ba68dd01e2df47eb4841d0b89b6b2ccf2d7955f31d90dae0806a0565c84c45ad259f70596e5cd2a629276a5a8aa6b7336592107d28d2c75e2aa0ef9d01d3b07afefd91a71f201378d87bc95fda97940e7cb79ceccf0821d0a4ef035a26d95071ecfe164c43f9034be36a5b07a302b4e402751e69c1b7f476828a4e936850c929b92b2aac68e5a9c7c78b70e16d362515490e6039f2e14f7e62058f4676bd4da59c89f2b55970c3c818c87e4ceee0fbfb0e381bcc5f1f3be23f777c31074c12660cb7d3156fa4166db27e2b68a4b74122686674bee6911f95e74295b3cacb037dd4962bf51af8056c3742b6a861ec8ab83b96fae5bdb274b7750729f83af4412ecd3569c81047e14663811298591d9a3de4c9b77f92892a5909102a2dc7cfbd8cc9d571054572f43e375acd30658627c19c6c46322253918e2d566da70f67a10d5cee7609cef96f4ea93291de78765b43b5bf0b66aef4092e06b901943be974d36cb23e5de4f75794ab0722ea8c2ea4c59fe4acfaca2ae543d2ffe86c55ccd611d7b81339c7f489cadeb40521cf5658899defe52c095deca336153e1038ddab448cca086ae53d4d36c61ed144bb01ddfd12f02c2fe68beeb5b55118b896896b41fd50433c63d7ec1de4136cb60ff3d253c5648da53cb11070fa8590b6113d5810445f765329a4d99ae951cf3a08e968f96846e0a6ba52b50a321b89ab217442fcc7c7a61f07d20f616da8d8f943aba0254cb78421db65f0ec81f1d8dc37d20ffff01535b69c0d0bb853d5f90a7a922570771a251f20fd836e10a6b5f5c2ccd19a0edc90c43a0359bb66fc962be6f51bb80ca04b203a0a59562aaa35e12392d638acf247a8591d29b6d2f2f69eb7924855e6c730508fb18988e36e0577fabd83bc8ef6b0db32218b37293965809e44ce11bcfb87f62b376a357a75997377e34e8663b24830887a453295b384c75987b50de670130daf0297148bc6eb4adcae42b444bfd98ac8150d7837d8e98617793e9f17da7b336dc71b08a092357e521cbb97abaf2838aa9ffd42ef911dfa3dbb5de6a3e7d2b1f46ae5c901bd5c133bdb45768fae256ce880697c215879be0f448f891886e621949986345c3d885732a86c60d627c08239a85f4bfd44974574497de4c1418c18ea4ed1b42ebc04b271d5ecdbffa9c036bedafaa8cc840e2edc4dae7ea7903e6b3ea8096765a3708042be38cfb05fa3c1250f033338b226a2428e3ff955f911d4706a474e2124d8886c35961b84a09b54137326df694f4bc4bf644b252bed1ecebc909d5876c7d596536d108fc3f923f47ead8b09a30f50cf5bf586070524f5fa1c612ea6c267b4db0172ce3508778b59687faf1f85ae28d0f6c47809a67874f53dbfa86a593afc443fa79cb9145ff094da2ec2e8138f23a367b002ca66410bb3e69a2c78f248febe1f600a5d64b9384a8f2f3f87839ecfb01a9fadcb8fb51baf26777fd145e2309ff72ab178e79bb74c5cebb91eb04a26640df80d483fd62e5d9534eda08bea4ced347cd2080f9678535a899f5e04f04f763b450c28ad95df470518c01cc9373d622d75569cd849348769eb002e256d4c497ddb316448f3c9de3de0464268490565536a9adca10af873660d9efcb721086a82ca66e3511fb603da763a5c761715bfb14eb587c6bc35ca7d09ec51e31654ce420a02acf064e521e470e1c4db35291522261d14de8cefe12585ddab81c307a8b202e63efcdb284c52c1f0ec68cb096cc6677fb902597c6f2a68a1fb5b282d0dc66ac840186520b4053b587bb5c9c6e0a060c1ec910f985d0dfb26e4417ffc846a0a943712b2ff9aacb3fe16370a9e9e114ae9e0d1c3d9275302da7875b8896084173198349da90e6c18bfbff1ff1763cf7d6dc2e462686f985dd80b057ff69a3c80caf1a375b57053ccaa4ba25155738077e7650635227e853c4e32e62199220d38e70a8b0c408f1c5ad4ca83957b58c8c9f4049c9c47d39f36b55703ed8620a393b38be48e42b44395d29d5c805ac783ab4a1c3a86fc7131ef98bd79c65a2085e6b8a6ff8e22495ee2429e1c7dd103ab5dbb03905bc32ff8a034b41d5cfe19e3626e6dbb680807ddd519bc0a93056866f8210a65c09027b524d7cd092e8437322542fc2c121f62fa08d9a720e6fd8ca9f75f85f6352236bccfcf5af165aa82b9f3182ae4e877183ba0eea360895afe36dcb3413ae5ad34cf2a1ab94749420a4a70ab55865494f7257af2ad74aafa5247f103f3675a32e4dafc8a4ccb6c1a61c3d00b2b79e89be4d5c1e919d42cf231749234d7bdb27ad8982d4e5688510a6573dda3fcea7695c588fed7f0e0f01c0a741907f5c5bf568dcc98f5b086beb2b1981f0a9bed8901b771a633926631a6f086b16664cd322b60be78b563f1881e45aaa1e61d354221fa3e46cf732c98cada8bfed0d7686cc30b33e87792528c08cc32a9d50c92e748fd5f507083cfdf8013e120fbe630a278d6d1199010d1943ba721e27a916deb0234bc9f3c1ec2b6f3ec08040a16e99ad6ae4feb3827ab59fed0d744867da6170d656793d088573089356d941eda72bca2c4a562d3a1246de70638732f542938ce599405d197d9f9175f99568b0590e331a34a83e06d22f3717d69bdef5d3693611c54f15c9f100c899ddfc53fd3e158f8fa34d93cbce0fe3847ff406f18e07f5877c16dc468e87a6b2aa9598562e5f110d5a3daf30e55cf6ce79282361131dbdd0e5ab6674d5d4e19f5af16a236d8d666f5346ab42ef0ba8956e8bb72724b26e16724eba92518de6d0c81e8c223ddf7e0db9ee6e02f258709223d39f8c64ea1aa0b29578dfee14b80b571bd8d1e3435f49c29b36d692fb562250a4bd8cdec086b4c154ba15c4faf55cf8ca44c37449cc0c5129436e91fa6261b368b56444e844e444352fcd40fd738801f75fcea41daa081bef2a7b6aade21d8bf9a5a2cf4a64678d55648779018001a9614a4529ba17deee26e007640d29d7b7155b0a10542fe70e479a2dd38a52f412a02c8ec4b1b1a84b17636368889f3b62c9107ecec8c2d05f92e01dd93db1973278cdea77a2693aec142bbaf402395293e8fc96a9ad5598794479035bd6ba359e2f9205f2da214f2e5023901b6aafe79d1fc1f3bf8e573e0855c0e2b954d43d4a239f22f2c86cbb1be64d655f658166578748d5c4ebbfd307d79705785723ad012f10eca2dcc808e33ef7fbae639d8e6ae26069ae9c8c8a1ec9ac6168cca87f9b290295a956ab13ca94fbb68cae77653de28ea20d805b1f2cf008eed459a8028d96a24f2ae85598f56e158d75185754927f983928da954f44bf5d143485a3c98efe586cd336fc9c5d0238976f6d1e715020844c13acb16c324a6227ff9d7f1c3628d25bc257d00d8cbc7f1d04e59802e51d458e634d803478c3410179ef429a3928507d220ae45f1d558584d2fb9a1b8ee5365ffdd28935d04f842da0a83bc60c63d9891964971137d71c2c1e5e696bb022b221c436468448163a34ee21535518e2bffd9fdefdb8e42ca0af89c1e8452cfbcde150a8624e67bedf1e84d214311dd779720062fffc80e8d51f0529c8d055c303092cb8b6519a57344f2b27ca805a13d54ea5fbaea8793ecfc4abbb13370b864c3ad5c44b3725776c68fecab9449e58344312ec3ac1798c301ec7641c1a027541443a708ec7fa6bcc85b0580e423b9341c68c583cb04f3a63626b231e1f30e0637ca7bc2a6b746947877c41d6d6f1d58e8ffaa20326c9a4a683ccee11f251e78b7f8b0408cc82d5684f756dca7122d47f97adcd03b6047ae6d192a0fc54e793766fe07a197ec445e3f892cfe67fccdd30c7ee46cd102c88e7671af143e1665c456ec55bfd5766ca152658aa702e4806d4116c9107fdd0075a5f2fd72a5cf31c2dcdd0cd7f41a223ba8407e0d3f0f2fba0b9aa1933b99da69d992331533116d6107402a8dbdc88decb312a4c18b5fa669495f9d1f21252313518d72dd1eb9c45e92a68af0aaefe323b6c72566ec6a6aa953c6ca6a7a2ea2d2ca02f5120ae80cf9b8b4215dbeaf204cd89839fb279e31c6d3f873e0138fc1f902f8829fb62eb16dd91aab2b9d167c406dec2c7e7e725546f838c8742dae9663baf6e311906adcdfe6e6db80d01c4e411f9204f19b697c95350e8d1c64b7cd74a0c98afa1b879d3800deef10a99285a5ef4457d143e75478ebd46fea904dd1e420de8ac8451dfd2a93d39eccfcf20dd9e2a944f2996054733d7ca775fa1d02501313a06b9a0b2a948189971b418f6a222151f711749725de070f361f3daa70b997fe9921348f20d4f5e5439263462f8e876104a468bf78392e9b83d900328236c5416c8c333e769d13bb18498fd2aa4980d7be53f745ed473c9ae8e7f8959c66477b7fa71c53f4c409612556a5c5fd954910d69fa1435e7ce503b5167286d98a6a842d3874cf80df8cefa8cebfdaf06927f6a3285480225563ebc30b0ae6abb04904ddb79d7e986b9a19bc0e944334f1cead234bf5dc4a21cbeb73c952f019aeee758c65d9f01fa1474a3cebb49b94ede19036f1adae5d0aa15c67213594b3c5aee54df42190e67a44d0f6a1e4b686ff646183314bbd21035475050c0b89608c635e0c83c0c19c5ca6d34f2df4809df17f1b142952b9fe83a1296cefc6704676441ef64a38ac7f96e159ea06fdad09c9e7cb58bf535d576e847c8504668611fcee83ccba2ba928b90df28c0e8689a7eb297d4d6517fb1ed4e59fbd1c7e4068e2610d19484a5169718f76d8205b4efb923e3de4896b5fd41246afe1818a5cb73d19980a4d7d2e8fa7344a27a055edca58d49bb0b7d80514eafb62a4a443b13e733fa67139740ee9460c1c05b309c68c655f6e143a6d8ce66ffef418a5754cffe0329274babdc751d9691ce576137469bab81e856c0ade55d0fac6c1d54be5ef6a67b150d2c159eafe2785e5bf7873f25b0f168ffa77da3a41a31825f2c7f9f20f5b07f181801d85561466ef3835f963a21380cd66625706c8aca2cb5d3164e21a61d7944ea7f0f7f330615ab327db985cd29f226a5db4dc55df0d7dd15da9247fa00e01dbc200fd3f5f26456cdf06fe6f085a7a6941fa7fd59e1bf3d0d55dc030419af7cb2d8f1e2dbd9b5b49e8f3800e423717a3da2429dd8be8168416440704474c231d1157688c8018853c15cd2fcc415cd6fb1ac8e7c986080c75f45d6040344180c331b3f0fb335a0d0dc99e516d0070fa4c2fd6a58509eff2def3636ee89b20a0e3e3b1d602d97bad262dedf7848a185b98be921399aa2783b2c745eba4957c8fc09a6308c0a6fa302911ae70c657f9c4d171c00f207119a5cb172cc8a7add900c9dd248c00d7042da6ff918eb1d25aeb5f0e2d9b02e62a1807db0cf8b43c277c1ac25f0baf22ef15443ce19c8244ef8b3e873083365c0c2870456d08368f95ce19727f5eb95afa7b97333fcd4fd060bca5bdc9ea0de90702d9f5642669d6d3087c62ef3da997f7a93d4c93f4eb3c5d16a973a18b90bb9c77c9921e7af7ad82d52495dea2aa9f00d96dbd957205395f05ed3f30a4811660fafbd49105230c644045523fe3377ab673b45bcdf64bb391d465839442e7c6a6e251b4a2b29d7846af987ff47f8ca55f29ae9b448c5f90d49833d6a4f4d6bcf9b1ce7f7dd98a7ea73d8c65dcc693f1478376cda5ea58ff0b571557c0f91ddc4206245f60eca60c4ce00580317d1b532a078b2c0f226643e3163a8cb120f00c029602a95e1ef0b2256ee2b31e130451fa33a621d820e3ce5371745f04675434cbf7d634722048700cd02499d755ac56ab649e468f65029651947c5879bda1cbbb40ecb17d640c4260d9ba6aa891a632836f8fda94ea231df5317c650746a09fcfbd458f19085b4e3fd2d50644de94b72e6c0c0bd15b323158a2e2210a3ab7bc569c5e3e0fe117acd216982e1048e995122e045d71ffc17813fd02170769959616d7e90afe454057ac7e28e2942511e96b33b59be90219560fed3b2b7da5be640defff5eda52453f6ecf299f68920a37e09304a89227076e08b5fa6fc4e7f77d71483f111a6d6c92eddbf10b9634d201941fc1a4f47b11623866b606abd3927312703e373780e45411e86d54096ef9d0f9994089becf1e614c44669d6c6560a7325079f5c52d37ce599cfe809bb49123d0f91d520e7c0ec0fcaf3f723cdef62d1f893af5f7815b0179682f4e092defb385bba8ae131e880a372f103e5cb2db2ebc39aca303f67bc02d88108723cd5c3eeb9d8d85aa8e8a166f3c321717a9f9ba2530c1205465746699675cdc80eb4e3f295788c8722e128cd4fe7f5fb14e38007060496b45080bf1813bdaa302210a107d69cdf7db25313274d7be84e3f348823c661be5c63ef5b917d1ab46766f9e0878b6bd0da8a1a38fc53842d845fe0ab962ffa8289805aa5923424de6e2b220fe900cf1697b44d0350de384a400e63c57c60fc3063eefeec24663390b2da05b6fc4e07fac814872e6e043cacfc35ad034a49f181f866111d74b90e4834732e08faf2d2136d7c4970cdb4ece0875c26fac6b74792d840be431744775e8778a2cbc40abf381813e2abbb65cf4fb1df73f15d3302658125749955a7299590ec56762dd6accc8d61aa897e15c3e4d64f157f6ef2685a43fdb03d28b04d2c84ebc34efa83690d30ed0e9b756b9a719b04215e6460d5cfe3202b2521a1bd18a245e551ce9b95e6d8c05cfd53284b4d2982419794079275f20a90b9d3fbf9e49ad0824105c5271c2c7e00847fb6f18ebd7e151e5d93552a1be0498a8bd99c39a10fcf2e721ca340e99ecf7ae88d4ef28939b6ae14a925db08b167112579ef8b8dfb21ed6d4450275c35cc131191ea36ced9147c06c0819784007d1fbf2f8d307bce6cb9265addb2588731393e07c0a439cd084682dc3e8f658cfa8eba916a080602a00efd8a1130d78e1ecf12f1af8d422cf62f51bc1b55ac758943bbcaeb4913fd070bab68afdaba8c909dd85d62bde66fa885bea15569b6b31d2c9e6a0c7021ae875e77c0a6595e5c8a2b29e25838277bd1ab32ff6b925aeee51d728eec7b3450ca2695a7642412592471b4246371fb1e7118e48b74679fa162576750b8d71943580587bb82b01e1d54541cbc5b87480031c93b921948889281fc1c2a22fcbacb4b79cd08934f7002c0994f32dd07d1a33e15e18eede506983acd57c87e42992ea27d37bec3d08259f57f42bafb78d491f7381f164705b18ff431828478421e0104d0e0a4bf29170b18d2de611d8364421a5b665cc4c36b11b8573a0cbc9f280121d9eb730e0eb17d9703dbbbdaf740e0bb6b0551ba8468bccfec62aeeb772539175e7de4decfc44951bcd9b1613e250fec93cd1d3b0cd768a92f90812bcaf1675b4a1859c098c116a9e5a3b541820f9bb5a193ec64ad41aa604371e7071710f4f80f4aff7b5a8774247bcf4ec7e12ace99476a76d4bf4788e43ba83f4e114ae65df96609d7bbee1f02c44670b9d059bd330319855c8f573ad840c12255dd382b292df4bf6450dabf18fa9d4f87f7cf8318f328955f5ef380aa8e8bef3b48f75ae35e2de109237914dd2afdc47cc14baa4f6295013d07917249d4a96668f07fa67d0a1d1ff2588859742a79992da00671dd00f8fc30a5cc7ba0f397587222a43e4a134148371107cf682d614682db4c949260bba6ea701494281f95ddff0fedf0db34202c0502e13843e08c369856ee2f101f467ff64ad06a697684a15f4fd76c09be4fecd795d335c39a2e6f9c706b70d574c6392a15c6618f707c6049f8879f1bda1b09aa7f80cce672509bc444569d005fd5932ba023c4dfbc546cb2e826ec80f8a6c8efd02566714811d4e33ac36005a2a1a9344d4c64ee940c2749f680d2dc84cf5604974680d0db69e4c9b5075cb0ab898878511830ef187070313068a0992519e6b64014f042e6ffc9d2ec0ff3042116b9a05f1d48a014d002acf110d5d14b414fbfd66ba9297d026e29ef64cf23e8196e0f62c29236b08eeb234169de64471cb6258e45e38090f353fb9839cb9cbdbacca3ecffed7b025f89f6017ef7ece98dc83e7d9cf5438c68276752082f48211167d3369ae171ec35b7ec650c97f08d7af6af0ae1b22a00a8e03a27484300c22463d7854d7cca6222f7a9abec3212f685ba485339ff9ed7edaa8d0458db617da08d55521504019ccd3447420ddaf35a9cdb6482db3b496bf1192719f3e2702062c988c8427603dd474842bfa7879c978e8b2aa8fc62406c2d025ec8b5b6776da2f38db878bfcfbc6bb708b9742de6a1174120e2686c7e597f50095b0d05e05609d8e0743ed233c9d103b848a33c101fbc7d7bed600550246a3fa2c4b5b3ca439b1edd8396c4995142d2c92472e98d7e789f10e63b288e1f8c7d4893b39fd28a63f09407e389df826db23917f2bcf8f3c9c3a4db9d05c42b14d06e400faeb01eaa45fe67d8e3b37b04ce000d5d7c4c8f9be86a675234b0e97be63a67e58e8792456cbb2431ddbeef8281164f4ff0cb8a20738d9ed3a1eed03ea0219e5ddfe4412b6b8936194e3052cde333422bbb1f9f9ad5da37f49ab90659dc652fe0a4dc0cfc92965f4704422d9b89202e69a74dc10150d63b180d590d75835b6c823563eab5e398098dac618a3ff0878888d3c1585fc66014a857112853aaf55e74634f8707163136febab789054f13aea41804169ac920ff09397306713c81fc3a5cacf2fee8afede4006889151b5d0841cb6b8b7c5da03e24951317dabbb64cea5d2c0ff749797a9b58c457924d3c918ee9c13168efde109afe9b4c136fbbc4c3e26d5d13770f0b96990651fc03846fa50a2990085194a13eb504b5fe21992cabc71210dae6f683883852406883300dffbd01ff1af0c208183b8a78179b2110df8b8938f201608e967ea178b12606a22247abdd2088d3748144f5cdaff7800fcd0b1dbefb3188ff708ae9c6a8195da563555a163b8142c68e2645e73ecb98f405add7754191c33a35cc0f6a3ac125d5c6871751d5ebc4dd921d568a619a8fb334903e9d7d1ceb44686a130d66b6d20b42780bdeea88df54ad7619c8c86194c98cea2e421a66b8126e9794a50083011c0529322068d492cd269ee173eb19ddf4878f8d6210316ca49ce2aaeedcf5526c9aa52c5d87558c53d58833a726e49405ca38b73269f97084b40c0983232c881c58fd7b85fda863f831faf459b91a7eddb35856c303c70db07b4b1ca7b15f2e05189d2cc8300c0fb57976a01facdb2ce13cfa9d808ff66c39570ca062447938b2d3c9f407e3e3218c0b0f11080605cfa432edfe91d1f0b6e53399945d3f58a4ec51dc774d5956791f331cb8691d65e499eb380667226e7058cd9c9f739e8f1b9c48e1fc108dd4f6dc42ec84add75f1b6f5b530f1599b766f62300f5ab59a2727c62b205ef12197762d1418be958b8a9bcbd4cd29ff089f11f90ad0631562e15a0bddb2645cb0fd0dc4bd9b82c82d434e5d82fac24e6a4a8038946698b83e57be2d93fd0e0c4baada066a4eefcb92b94a736b4fb0b365fdabd334e492818300402c0a98abe0b3ea3d27dab6a3ff6607bec091e0a8b373f974659e8ae50f4c9c58c467d22d0fe13dd81ad28a734957e71c223753ab2086cc470f42b4dad61ad63d19065b95158c22f5687f4e0ffa1877867848aa814c517cf16313da4d59e9597a2e3dfe56ea115aa8b5ff7d99a04bda07b105d6e50f3dcd8e1a55430f9900d256347b28e447bce9a7279ba5c913589823f19926d588968f0c1e600e37a549c4db8da10ed3e5c1eed5f79b2abca5bf187311beec2f509a723dcc47fa832470758780995ea2528850994f63194e92b5967db7660b8994aa08e7eb35db7c4083d13d3dba70965d7aa5d3d5bc9ffbe5ebc6c5c62fa544ca5d75ecb6f6bdb6345e821a0eb7f532e2657a123a6672a8fac1306a7e7107059baed9e5acf80cd87909c222148225750be23fe876bc2c688d7b2cc4416775acb72cf2ec957b7815ab8c732ee645506f42dab9a7ccc8dc6ab412b90c15d4b45c3d19f9182398ad48da3786b355b251c9ef7673156d9cd566dc7c7040b67a31003589a1803ca2d76e4d58106aaa9d0f70523d7565bd53d07e0b8d04104403c4ad210bb1cc8d1dcebab3a507629817f1cc36062ad79320cb64294c2760c9c4093b52cdb215250c93554f073f100c2982fd111bf594db8ed6b9985db87e130025f58e64fc516ee2fa55df2338220c1ea5527b1d5da4972c21edf5df419522dafb2860f35d0185e7e03d02cf58e7a4eb98ebd8b69e76d3d5b1a7beb3911977e01687caca79a74af99403cc46f01ad8ff012bcb3d13ca96f4bffabe18acb89e82760d9dcd4318a785ba0c0961067e85aea395035c04ffa09b95254ae74d5691c022458ddb55497e4417b92fd8865681194f97d8cdb7c22ca8a206da9161a12667d7caaa1e65fe0efba1a84443ddb2413d1f74c7f703a3249485351c0c68a93c1a4e85c1b9f022088110dbc1d4f4238bfa87d517ef95ce4fd459139012dfc1007f4e134b9faa702440bae4310a0264a2b8061950468b993885d3b69e243359ef25a29cf7b94895f0635a816ee6a0514f5802277d19547ca58c9325ec858d2c53f23ae0f0acca34fa67aecbe8e845b93b6edcbb6afa58869555cf371e866bf0d288f556452c8fa0560a6687382dee62a45558a90269099e317797d0f179b4001f46bc5efc63409f33117d63b85db0355021f5e2a84c609288ab686219b827ef92c2f0aaddb9d97f4ed27fc7dcb42ede6a94b3d09208412768e4842b6cd61b25102999515e22a2888b545aba1be2eab6ce1e27a8563af452900fd554e3eee274e45028ffbd399bac41f34b16ea8d110b6189fb137d28e0bdd1f4d9085f4065fa42e01d532d637ff7e4430bc0f8afc49c9c866afc600c20239a90b411696cf01d49141c059beaee9289f74ab96d004b06101b2cadfcb7f782531eb1f0507397ade04bb71db6b47ce412d314c7caf7700e2443036cef24913254e46f9850c35306979417e7d59f2fa9a78278ee42babc033cd7488a9af66d625fc7e954c3a33acddfd07d082a2456832e8584fdb8d3d903f0e9e7ef0ed4167e1503c8b9fd94489ef9cd0a755cb1035634096c45b64405b51e650f607ccaccdd75417c3e21fa15d8f2d4ce786fb2b89982f878e1d4c5173ebaed0e9ebba977429fb9c313734ab77883e5db2740f1be8922f6dd2f9b86a4ede7e28e9e9a43ba6bd51db6369b7259f46e2462a0b656bf7acedd4ce59c2cae5087a2c49c8f3ca1f6e2f4a37b08f0a707fd2d92efa0c672f13067c0d2321e687f1c329755aa0436bf2475d146dd03fcdc65870be5b691f0046494be679b524a2e4bc2264df61ffaf08dc1bb5492a47b5dada7d693a0ed376b467787d93f7ebefc060779e8b49a5474e8407133d2440d6d4c89aa31f01badf1e436c24d83ef164f2e6690f07ab9e38dc8190b1c29efdd8572be180ab23a00e04944f75a8d3a3bf8a1e380c305f4bd5d798b249602b4f10536cd40f8871c70f951600a38c1dce051d9cecfee7b7b391fb7c4d26cbea9c7c8f811f386b279804a4b303ba07139d541060a96a3ae0498be44023be9b37472843a89658e56523b906cfd474bd885a6764e0726df59d0cd2dde13ed82d2eb3b6150622f75499cdbccca49c84534e2aebbb59a9a1ce5f91b06e24a4eddd6defbda54c49cafb09c70973090fc37d7d01ee0befc285e1716e01be85ebc2bb2eceb3705bf899ebfa7b59787abf1c0347871deb9c51472c77eb27662966471c1b6396fcf5dfaf43e6af99efd731e4affbfd3a8876b83604d70e350c2dd311c33a623aa8e098bf40f0fd588687fc95e4fb3191bf74f87e5ce4af0f7c3f36f29707be1f1ff9ab03df8f91fc85e4fbb192bf8e7c3f9ef96bfc7ebce42f0e7cffcc8fbf8c7cff4c90bf36f0fd33307f69e0fb6784fc9581ef9f99e22f0c7c5fe0fb6764feb2c0f7cf0cf9ab02df3f43e4af1cbe7fa6c85f14f8fe19237f4de0fb678efc85c3f7cf20cd28cdcc66965c3fae2017cc25e49ae28ab964ae211791abc865e43a7221b9945c33d712cd0f4d90bf807c3f0dcc5f3fbe9f4688660a4dcc5f3418e887198758e5f4503891e6fb69643443fe12bf9f8688a688c68886068946896646b354f35313e42f9defaf81f9ebf5fd3535536a6235327fb9f0fd35433544fe6ae1fb6b8a6a8c6a8efce5c24055ea43e144d7f7d720f98b00df5fa3e4af9befaf99f96b85efaf59f2d700be7fc78fbf04f0fd3b82fc65f3fd3b60fe0abf7f8790bf767cff8e29feaaf9fe1d317fe16ffa4fe9ccd3d7017fb4ea5ffaff4e4417a11c453e327f311399c515315812659e5e9fd63f6622d1e881d8f24cdf3bdd27963c082e8e61191ec244b8081be1238c8495f00c2fcdfccc04cdc0668466a6ccc46664334333443345334638cc20cd28cdcc66967e8260425362b221a222a32324a5d912cd0f4d100d8c4688668adbd0c868866888688a688c688e689068946866344b353f354135b01aa19a2935b11a59cd500d514d518d510d528d52cdac6669c7cf8ea01db01d423ba6b84c2fa50bded7882161e8c7170887ffa1871f113fcd0de2c4259826e636f548c9370bdf38df2d14e0fbb51f7fb9f0c2370cfeca79e9f0f87e6dc85f3bcfd3c300dfaf1df9eb00df08f8eef97e6de6af2c26e0fbb7207fc5e02f1fdfbf09f9eb079020dfbfc9fc25c3f76f43fe52c0f76f44fe12f2fd5b91bf66f8fecdc85f347cff76e4af057cff86e4af1abe7f53f2d790efdf66fe22f2fddb92bf18f0fddc8fbf1af0fd5c90bf7cbe9f83f9cb01dfcf09f9cb86efe7a6f8eb01dfcfc5fc55e4fb3999bf20f0fddc90bf22f0fd1c91bf24f0fd5c91bf6ef87ecec85f34344234309a209a1fd7926be6527221b98e5c46ae2217916bc82573c55c535c422e982bc8f533b334339b519a419a39729b19a399a219a29919d94c6c66ca8cd00c6c2668e607e31956c248f8081be1224c84b10cc7a8c0e1b284640b20b82e4aae4b92eba2c375f9c075f1c075e9c07541725d8e5c97f1ba70e0ba18b92e1bb82e1ab82f19b82f18b82f17b82f16b82f15b82f39dc170adc9709dc171ceecb0df74502f72502f70502f7a5c87d79c07db1e1c238e0c2f85c98065c18065c1822172636e4c2c86ab830430bb83044345c98a2192e8c91900b73a4800b8324c385510a726166402eccd28fcbfaf1715941315c16ec745942f2a63f01973545bcac58be2c59cf650d21e0b2880e70594506b8ac1e97c573593b97c5e3b2742eeb7573e4dc1c30dc1c2fdc1c2edc1c05b8395ab839646ed38f7373b0707310e0e6b8b93956b83906707308e0e6b0b93996dca63fbc313b6e4ccd8d81b94d3fbe3134df4be902f82c23240cfdae4b71205d70e142c290a348def4ffad43b712b94dffbdb5c86daa8b504fcbdc7ff08eac24582f18e91479c4b191e2208f38a664c7951d4732f75f82407e0a769489c94831e42f1ddfef49d1610f7d6c58cfa3cc04e7932759502144040cac8cccdd21739bfac4ca6622d6e1cc8f1c9599c1d7dae922d4a18b940e3b0200f8d673600402f08f5b3e3f5d30451a3fe2bf13b1755b3ead977919cc4412010562eb9d881e0885a53fd623249715d6f3588f706c87ac5573246ffed9b02e42feba2ff3a37581f9eb62fc1c87631596fbc11f2bf38863f4ff4a51c7e5ae1403707f4c2206c0fd3189d26d2a8ee11895b9526c5d29c65c29ba2461ff081c6bc168024e58eda344435153260fc52f45938518c89d895f7e206f9cfbc9dc1152762f62599d211c4d29f49736e436fe9a92db6cdc698adbf86b435b18feb358d66a432c96b59b9112be62c7cd28e834c55fdda3a6ccb2ffbc2ea758f67f29422db918cd207577c615f3d7ccc7c697a2ec4a681e67904c5bd897a2c9e392c1cb0fe48e8b06f2c6df632d2558ff9998bfa48facf1433a13cbfe324bd97f13c218f2f5491ba3c933250bf3fdb721c82d0c994337a3ec2d48c8be8515a9e663c6b8b81669a698609ef497b4d328d7223bbf28aca41c1de7fcc9f3fd7696337f9d333187bbb0fd5e4a0a901b719bf9afcd486ca3ec40b37dd33a07817857eb11daa1e4b88ed33637993a24dcb57aa9944d08596effaa117f9974f017d73ab388dc33ca64a1b7af2010222d9adedb4c5b58077f68df12428f508a8fe4692477baef1fcc4d8eb396c5facf23c74da31965f2cc2bf34aee19e5b6e8993e23fe72510af98b9bb94d3fb734e5271624830d7542b939218c721007d4e1cf95c9c3f9f083bce91f27109af6e909ef2568c3143dcca407d1843925b7491d5193c83872d5fc24dbaef094f44f966fcaa82a9cbfa9f325c386fea6ff26557cbaf76fb23df7234e36b58868cf7d4bb67cea9b5a12fb689ce93dee4ad151323bda6c7a071930c5eda5f7f4534bfe92995bdffb6cdf3dd892dfa48af74dbadfbe491510fbd0e7bec9f6ddfb6d49dcfab04ff71b6ec997a2877db8a7df84e296c4dfa1e943b731bd14b9cf91c5b6bcdf5e8a2d0fb78874bfbd0ddd6fb849151f7fee9bd0efde06ce9f7b29ca1fff89ed7bda647ae92f97e909afb64f29732875da617757aad1323cf749678270ad7117b6dda94f6d0446b80b3be545a2c9e47f51b87b6b2d7881f6821e82562d0909cd37e786d084d8b8242438efeacc109285ced4252161aa943ba3dd9d6adba6849d3a3894d25a65582c4ae9465b88fb6ba00fd7f0367302aa6d529c7389c770ae33f920a5d3ba2510b699b6b05cf8af83a3719da9cab0589367f250ee6bfa26d00785652255dcf0f6e3363328f8bcc54e9ece50cc0ccaf2046559c9ccdb0c11d6d481429ae49ae94b4e9b718392fbe76bfb99db93f91ae236d3e80443a260bf0e7bf26c5a0772b2ae07accdb5aa699ab6851159abac0e150084d4f23a96c2f81c98f15158b04600886c97a515162c7d11c58700a0616b9656a20c61a508a59cc41ade94c28403ca5208297f4a9949c89dee596e58354699c4c262afc82c5c2bdc20bfc7cbc8979c7826a144a666e47e236498041272cf1618a184dc2a90216d411aee13266fa80a9a307fa40d7def823e603dcc72d380cafef2c725929329b9bd27b7e7905b86cf5dd72caa373a20ad8a098cd30f38a845ece087263e2021f08d21c490c21604ae4488420d620b3162a005914a024a0a1ca021702145ac09207eb0e28d1e020bbac516486c6f0c318697c715b2bbbff5fc7da13981230720a1b08519db1b43705a954328e241129d1652100292d54544128200a5880930f8410ab820827145265081e683a258f5c1163f04111dfaa3ee0e33abf00c1da6aeccb81ec5519d206f669f09ece8332b58a4649951ef815fd3afe58e9dedd7a32cfea92b3b94a86fb92ed58ace51bdbc4b1963854d7df775a643078b655b48da5ce99cd5fb57a3ce49bd7fc5d239a92bf3eabafc045718499853efa5aecd9eea43a1c28c7ad9a8f77cce76afa7960c34af9ee6151e9b64d5a7eecc2fd795dcc6bd6fb92dd4a14bea5137f5de958c72a3d41d1d29a3b264146ace72eae7cb2c1da2264a4ba5fc73a432aacb28d44ff99222ea37d04783a83af3570b499163a5f018e6b1aab02749f159e7b498c0cf935ac85f1b12d782eb6c433abd9ffefbc1a6f011d4a35ef51b2803ea53efa1ee8f99a5bc51a52e7dd5adefcd0ff529d4a3b0ecb051cff538eafae09450b0ce5af2e8574809cda3cfc67a45c9f4ff193a47b2b655c374e149d738c33adb290dedd1af412132a6ca62b51a59cea7de6b4410a26adb777a99fc4ddcf54d200dae91c39f899bff394e8f203e3920e1010826252605d195cee99ce49d2e5015af334dd3371e71d6dea3c185c79609da24ecf852494f83b7b3942c8c9af70d0a6992b50f3bc7ebacbd09bb34383295336b610bf2c6c10d27996187b4bd7dd6137dedbe80236f5e7260c7f7ee065ebf87fa31fb878340ec373fcbff417170e89c5e9d33749bf9a1db3448c489e8e8546d037b82442648a4816ceeee9eebfb00011053ae18c88f214026300187f231e50df76de08f0efcc199e4eca7281ff43d940f10c8cc443e5082200882d333259971e4eaa4ce8e099e748d30475bb873f2e67b5a077f1d75ce94334e86949ab6b06307cbfe9e1b1dfab694fde5369337ce1db98dd74037a40e37a33ca28888b858b18db98d8361fd37a42d49a973e6c350018cad0a6fd35ee2ba694e44dec8b74d58af55ca2b044f4e28565a718292879a9f9d7648587f2a639322f924fd5c089eec2daccc316737f636ea706eb906c99b398b70f79e13069ea49452ea9ecdee584e303ccf64832674e01cc7b574b5af31ec69220aca1882f4c081844b866191ec2fc32aeb0d2c96b5d4fd871e1df60472a9c69422674152603f55872513a85f2c7fe9f4c87205cdb1cb7ffb206e6367e8b03fc8e7efdf13df402125688a6d873388bf8ab81f55249d4331570403fd754a0162ca4604d6b4e2451af90668e040f15060d8e93ee5747fad7ad849a1113689637077242afcb8e0085cb4414692e8ed82ecee65777797c9734a39caf4c8d228374deeeee209b9af04215bf1028adc596c8f2c5bb27c9d183a474a2973e400ba68220bab84a7554a29a5f552e9d8092bedcc22db8cf2d48eb447043b5f22d98ce613268b65adfcfaf52548838e7ca4b6f4975362253453bca4e67e6f281ed7399afc8dce49ddc6bdbf6269eb4fdc3d7477119e4b9d7bb925d8d95282f16758fab2254f4a2992963cdfdd65e40dad4e9d622ba58dc2a50beba61ed9f4d4dd44a9e947fa1ced6993897bcf744defa6af8ebd9a4c263c769873ff50e7eb159e943b9226216f2665b5d426fde6b4979aa5b4a58cdad7f7b4dada4bb7714aabd63d5959d3f0e8df2dbf623af6c8f305d60a79bab89791368ee517218d90832018e1e00745fc40a588ce91a02b238094e0b8a28b32d668c11862fc10071536c041185e74942a74393608e84911ad4407701cf1431950cca8010b9cc460075aa40193020ba63042afa00b20ba2388943133630da1280081835681c402041b51f080882a32286a58153a8a12826d77c72142f5c81f437709bc1882104b08d18009618894884cffe9132b3f78639392873ec9fdddd3460091653e21b16c295bb66c5a69a595b6d4ef295f1dd7dd653ca672e3f97db1b05aedc417da06b7fa696e8cc3e1c0aa701f8d711bdfe4e4cd7479623f735a9658a8000979c4d1983014abefc5606464391256debe9bd3e1ba570078afe06fdf41fe7a3c8774e06fc31ef8d25f32610c5ee19173171d8c4858f99b4ae7f8b7c7c2e307e9b07a413afc96b66ddb6a90cef9b60ff778173b613d2031e02093cacbd7d58fac961fadcb8f5cfe5ef0a4d261589f0661f23cebf1e036f5bda7a00f6f52e91c995f539c4b7505643b68d3be2914fe88c32559efc7b994038f1c0b8f16068fac173cbe0b1e433ce2e4d59d3cd4af1c67e592cb1596562c1d24c449a8a5a0be7ec73ae7fbfa1eea7a9abc5c879be68d93895cadc8bee1af0b3b84e3aaf778900e67710452e6b094b9895c1ae583d00f82322a4b2b5c089165ca93aeb105a3fcf23d184a096bfade3ac70a9149d9e223e0cbecc9378e38e3c79b600dbfb0238eed88c99def9b0632ecef74c4340bab39923ba7a789c91d8af37daf23d63e64a0d14588ab3f997ab84f3f999e301eabfbe01e09661949851da13fb3047dd02762fe79bcb801114b0834e64defc5dc6a32e17ae41284056c88ec593aec7a6485fdd7d79a94fb717a5c61bac4f04bffde7bcf70d89f5987ed865b580b917faedc63981bc77a075ffc80349b886247cabbac1c57878c757550d111fb8b03f30df34bf9e5bd982599988c4c47918c8c0ca69f366778451b4158a060c710f83826775057088a2419118ad0111b710c47e783821d5d8470f2638cb3a81f2324774edf4bc830664a4c2c4791dca18f7a9690dce95e26e6b9fc18b3548f645c6296b0df1f33a55b7e8ce954ab1f63966862f24686e2e8f8d111cb16b682c91bdc42246f4c482625d3ec9a96ae098e0efbc8c24c41f2a61f3543cdfc85e238d40c658452e363c37a3fa28c728fafdc0f73471d45b9ffe5bab45858f561a5c2317711aa3ea46efdeaed2c1393a1d261cbb4beff5f9ab03252742882ab444a3002017819dcf291996c18010d2251e69d883dfdd2c557418b981a296cb79463626dd331b1dc984ae778068192243a7cc0031d407264e480910d68200318b880052a9003052680c30d128800048a3cc00607f83480014486d4b0001a6610a200198200f9e123069a0488b907010730400f9e1d1e3aaf1c185e70a1002de0b0e0ba3304b85941684a4c36b483c85f4bbe7f47118ec91d8a9ae5fe51f2a0669285feeebdf0d6fc8e8b5f00377c9bbbe357b802f8015c9b27c05de16fee007ee6defcbd04787a4f79c905baa8f7ee0d80e8cdefde4ff4fabb17143dffecb542d746e9b0ffde936861f7a2441d5474c8b08e988e98920b1482ff41879f9f9f1f51040f82bbc327b920f80fdc24afc355f21db81f780f5c1dfec8edc023b91e780edc233f5e24bf81cb813772c7cfc0ddc06be01af90bdc0c3c06ae06be02f7026f818b81a7c0adc0e7702df0385c0afc046e0e2f818bc3df7027f010b812f808dc1bfe0117025fe446e01d701ff036dc22df80eb80ff5bf33ed78627721bf00cb83e5fc325f2432e039e865bc32fe00e792197869fe12ee065b8425e017786077265f8205701efe302f92517ff8f1be469ae8f8fe1fe78f1d27c026e0cdf73c5cf37017f80dbf308b8f97bdc03bc012e027ee7f6789e6b80d7b93bcfe3f27cced5f9d7e5f12fdc9c2a993525d9512ecd33a638aa81164804810c23713eeb394e4ad644aa67e050f0a3e0d7efa2f96e951d9a8615ba77d1801486d3075e2952d4f75d096229b1f781940c76a268b0aa8fde1691d3835fe4047ee005025fba8d279e40eba552df4767835c8763ea6d053a78ae3f6f7edead22b90fa73e60ab57ab6bdcf5a153c2505b44c0ffbe4811e93656d82472492a6527a213b169c59bbd40df4bb731d5406193c8a52c45295bd0fe87cbec77ec21fb530d14e242f6b65aabbf67edab207dce35f7eaee14ec4ae4495715faf4fa50184ae01ff5b01011e43a76991ea99fabcc4e32c779df0485781c71740eddbef34c3f72ef5d204fca16b8f9c349aeef7d9f5f296e54c82a6f55ba39a7a99e3abc435319aa51956d661f0a03a5ed3e1d9ed2867622e0bcee56a19476b74a0529a5db2d125425894e3e12662762f79e0465708a47edbb0bd43d942a4974f2126f0104e224f7d3b187910a5965ad06cffedb9dd9ab5f77abecd0597bcf3777e7ea89c33b346d4116f98aef88ef082051983a4d9b796269772b1652ca90524615b4d22264e1b66d63011613508992a59a0e30033186c40e73b4ebbcd16af807fdfa1d152d00129998be874e02094062157f27a2d75dd395a00f6eeb01e7b67c3ad36df998a4dbcc37f57815b256bfbb5234d5c0caf393ccec01569ebfddb1fea6c9669e588d22d130129614ebe532bd5cee7c6b900d9b923b32cb2904319c60855ca3ca0c5d44460d1c480b1e48a1a80bd1a3b30540305043a457ae5145f4aa16704041123dadc8882755446fd3820a133f103dee9312c54cf4b8af4a232a4dccc48a397a5b3e9589cb0cb1623bf3c4861d4e69aa571605c18327447a5d6688d2d5dddd86275de39de596cfd920109457a4983134c20892852dcb614b11826d5899b9fc2d750efdf9146cc37ac044948ff84761c7ae38b9df93a0fbf8cd5cccb02d933726220dcf9f0e4fa7d92773e84f4e1c4d5998aee469c2a2c957f76077addba050f6b3a08f1697a0318ebed908237337acb52d150632e7e9d320e4f9d448eef83b0cf27c9f0224f3bdf1cda44d3f8c14b9ff6b43be64eae3ae13d19372f5cd7c7cee26a26ff62d75d85e10442722cc10d888891d861982913911b9eb44b447b0fd49b9a974d894527f1859e7d4dc0f238510b91f66a873bcdc0f03a346bfba198c159d23b180022837cc15a3dc3217e411e628f707c3028a19e4112629378cb750eeec337cc1841bfddf6c4626e5b1a58c3ce59ca62c4c45b905090607b96164d266862ac82db03ce55219798e2aa43ce7c344215fd6bd0cfa98e08f16f09b73fae775b78b98a5a048e4ae64c30bd173f9badb42a881124b2277a51b6988decbd7dd16a45489891eccc7dd8e7b0e33a14b90a224764e444feb402000c828c99dbaeb44f4bc967ae9fffcfe99feb069ab0c1bc4c8e44d0be99bc1c8fc67c2c8c2f0a08c9ab9a898e5fe3a1d53d909f441af9d4ac0c828cc108591e5aed4e9fdbaeb44fc408a79e8d0e361e94507768491c1c81c4606331f46161386a55f6384602b8c0cf4315b2f7451642472578a77a6f50b4fe84cde07b23c93046dc7cd130db98d3a6a0946582beb1158d26b45a2569fb39b02124fecd0d94ea59461f56cb1539b74cb8eff0416941c27a9b79472764dc368028542a1502814ca89eff4360582e05b107502bf6bc1995a5a62fb39df544dbfe126de7429d196ccec1ebd4ebb0ea7bfc739ce5a79a22c96b52387c7ee65d7d5ee7b5a2671f087e70e73f2a6fe89091c144ebf110ec89dadbf763feac8dc775d8771c04f7d55fda7f37dfdeed20ebf4f5daec3cfbfd63adb3bd28ce224d1c8e54f03e261fabd4dffe61dfbe79c9b36e79cc29a4cdfd3f39a7af66c1f663bf51eb9e3d9bb8d721db71de13aaee38e70df4fb9ae67f2cc5c2bb771db4c150465514a29a5947263387eb8828e8bfb426e4e262f1fe5b3bd867b68d93045eda7a8e1a04fdc3e888a40da43e17ca8b861283fa044ed5bec69adfa18a261db39f4c7123598020a2b60c83c28b04c39b0238bc5f2a0b01463a2c2f6d29209072e6b7812c736ad476addea56ebcbd095ceaedd3df1a6d524a80cf66d09e923daf67db59fbfd5d0afcdeda50adb9da95635af74a382922ad5fca6ea5757b55a7d4fab56ab956ab552a956ab55ea57ab95cbaf52bf52bdac56aad56ab55aad52abd42ab54a7ddaeafd57abd56ab55aad562bd54aa552a556af4aad3ea55aa956aad5e55ed5f2aad5ea532eab4fb9acde25d5b24aad54abd5eabdef5bad56abd54fd0c76af528946a85eb5bd47d797a6d0ac645d5a27a515d995b5e7e822d2faaf754a9d56ab55aa956ab96a7b925f5aa3b338ccb4a3553aa4fb9b4b8e03aebd0bf45858fac5ef5293cae3eb57a55eabdf9ad5478fc1ea72d0d63734b1ca4504d6a52d3a8e6dd0a6cd39ff4ebe6ee9ba443d879d4a19cb2bbd6937c5fa29f9cbe52c9f5412bf267edf108be1472fa0a3ef8de7677e0c00e8f4572f77d95f49299b7ede9c7bcf6600d376bb83eaabe89c5b2f633f7f43d8e729cf6fea8db48c28c6ad477cee9fbf1742ab2de9fbc3f72fa5314de69dbb6292c0882b8e7a4de3e58bbc906b8b2b482e54ac6620511a414b941ca9ba420ecf420acd7d339adfeec5fa570dc6fb848de6c26f0c7a9f34b1556fe4f9e99639233d0bcc3cca6f736c97db7dfbb9f938e987ec91d4fbfbd768f9c9e43e5ca715feb8338c9cca64bab098c2cd6c1c092fd5d8dd3d2b30237b27f0cdfe35f7fbd47b45f32731dbbe7fe48f7f57d851b6fbb49b8efe8f6b57677fb9ab51d26d7399ef4e672c563934cf169b658e149d78f373f3979fae7e8a9af20f773fd9a4a6ed3a677d864a11fcf2c53a961fdcda24a73e60df3b94528da295f9388fac442bee8d745eefe9311769c59744e51d73b8f3a9c54a3b2c1efc7ce9e943c3369b2e0efe17104b9f23089ee54a343ffed9be56d12258d967b107f3329b70bb2d75adf4ef96a98b4f11d16c84622bb87a792bc31c2366c56d92725b39b4a4a4979be7647245f87484221a84cf13c1abfe97e1a7bc8dd0ea451879e4a491c6453b2ea515420caab4761a192558f7a8ffb3829a5cb87bad58d0e25e8e33381ad491d1615b172c894447dbd52830a572cb816c1ec9125337f1dcc1e51fd929951afbabee46e744884bd2dcfea1c7fd49d3965039bfa80f0d974a7a8a71985c726b95ad1a1cf594671e08f2dcf2b1da230ea6d878e51980564ab5287fe295c913af49f499b92dc49fdcc1b1aa94fe196ca8234a03e95c22dd586d439ad142a95fa542a85678062513fd619d22c8f3e933ba9f7f750976b01b2f653a877d5fb7baa3b738d82ab706b75026940bd4a855bab96eab57781a00ca85fe1960a0b09b3ea55f8b3ea6b963d832c5f46eec85aeba42b6cdbb605e99c4ddbb64dd3eaac5aed9c992b4e871d3652a833be30c30b6da58ca33cb2e2b04f3ce99239c7f5518799532dbd7ad9598b1bb9beec83c3431283883cf6984757f248dbeb4feb376a82ecddbdb9e62a87bd8d9baf55ce39d7aa341ad223dfd03d720f2b6658c9dede34064899523a6484e5c8a88d58474633644dc9416544343b6e1daa436cd83a14b272ec605d59a6b429a59456a4256418863a2ce1418739e34187f97d4f0fe9913b59bebc573240d07bd123084734fd014c3f4a2e8238117cef0241d111c10fe244d403017348452a8612a77ec5895155b155087e216f546c7d8fbaec494f4f7c3e27dce21e7c29fa3c6e71b84504f5e0db807a1037a9e2737af09ba03050908ee83d144e34bd0de009fb43e144efa5f8e1216e43bf27cb2f3205f3288960182517458890661371dffcd180e8eeeeeed93bf0fafbc0d3a99b9e49123d8e6b86383a7fc4e34ccfd4716a8001eb1bfedf08fd274e6f4407b9c365fa49e48ef7f495c81df0e92fe1a173a807de99694ff7b427fd681f75c9e38bf2b6e60f39612e0812ac7fcfe0bd3fc545dcff860ea9d36eca7146f0f83df8de77732872c32c9203f85f0e9d233d3c442748874558b060f1e91c24fb47a1ab731c531ac44a1957f268f3b332e53e18c745777777f7ec6e8efbbb11318535265dc2e5fa81a753d79ec9eb6ecbbdf7e9defb0f3301df7b26dffc9a8a5fc52dddddefbd0bfec9c475dffd09bfdb80f77aa68e4383364563d266a2431a9b32a5c6ea94f92c1d1e32a70ad9b0222143fa638f4caded96667d6891b0ddaf63c3ae22d123531eb3caaaf0a48b2a51b2c4e6f949bc0a5aea1fccde906f693484368ebfc0373dfd2072877bfa32c81c56879f97d392214d32e3a0626a076e079b1dbb3aa4a8ffee29fcd511d6f4a697a2f6d5faf73ea6ffde2d66f23d13cfbfe977cb13f4d122023eea7d40ed51d8e7dd467310df20f286fe77df4db7754506e95284ddb01d3917ed9cd4ae4e78312f54ec685bfa2be5e67798f37a411f743ac91ad6260b5286f3adb4ee55fc6cf4ff757a8adcd02fcb92495f810e28a8480e72072653e9048946cc77861de551118eb396daffff96c934411f9e3771cb49ee3b3e386f8dcc3e783ff03ac97e97d4fce1be3dee5ddb216d912100d9ff06c754eab4b4b46139cc7548b52b7f36275a29bb1055d2622700a2b895401f9abcf96e0b3ba27a6290b9ab697bcff33c27995ed3739db65d0dbbe3ced267c0badb34bf677777d3f6ee9e57ae5c9961e628620d25a44cabf721c1fa10b5811d25564287748e9ce2cc1e8edc01730f923a47a9737a6747a6f42791dc61656a839029c78523c18e8f437f801947ded0b764582d480e240bfef71b11290281ffbd0485c80e9b890e694c488ad7efa4e57f7a2722785bfedf3b118bae8cb335df7bb7a2c3eb03fef7f31201ffc34caa38f6f98e9ec983611ee7504f257943c597c214a2cf71d6d2f79cb03f873aa7c3417e5ad13959c81da76a1821098ce9c5cba76de88f538b4c3fe633c36e3808c759cb628d619e5634fd31ccae9e432d6d580db3be32466b913a2b39e0b035097536bfa25a548b94903a7cbb86ad4a156986fe59e6d4291dd6a125b2a8456cd8ce632dea91375e8b42b7a94b64916518f3d85887e67704db5f67146812bd4063ba2b299ddf61dae19bdce4a6cddfe47526d33451ee6639521c44a7437f1c3b4aa41c8c8c20993f27ab916c0e9d6304031689bc620611f9b39c53415dc77f067518da35ec14a9c8c308648e3592b39270f85b27d8cea30e0ff24647ee80998a15e7e0362b384620437f236ee3ef5284a59dc5f64f4f22ba22cc9e47693401222ee2901571dc188f4b7c68888a215a895c7a9022c3081c3cd939b21f8f483e6e0d4a59f64bfaccf892bea40c46f992de80030e2f8b87e421d17e714f7570a8144343540c0da5e171fde2c62b93929266921a4af06a5085e5468294e973afa34cb187a232b913001e42f008e201cb3c887804d1e601f33af3a4dca95fabd35ab9973f76399595f278b3345d296d2e776b6d37deab7bbb511d456f75233b13b9a76bbbf175bb517d5bc2938d9b3e11eb3b47b64b4129a5747381d741ed3c5172bfc603e311a23c4299a728f7b45f1e188f100f3e4f4e1eed27cb0f65bef34c77e6aebfebaebdef388ef3ba9f5dd7756faa613e97b9eed2dcddad7beefbadbbeebafb30d76187db95dd6f5b833e3609cac0fdc418680de1dc46fb21d985086b24870e3595ccf68f1249ce8cf094c85fc2e5296b0991bf7d67cf328714e40c12a2593cf88bfbfa5138ae88e5aca2c9c456dd264adbd41fc2598e659f559dfc482ec41183b84d155d88b03336a774a892d929ab52ba5837838eca0a583228fa618c5c6b665919e38a6c9a29b1429656b250912d929531cec81f9631920490a5952c42e4539656c4f0c17cc2001c229a84420b55c842892a8690de38a263db1040143d41c2ad4da3684be30adb72b3b432861219ccd24a1a37a844380162092025981054c41a513ce1c41351dc108a021939c841161fb4aa562b165180e24515573801054d34d14c88a1c5b4224616464c11032a6734a103358a441c31acc8a37dcd5f6eef7c82086e5011fbfa932fc4994516031a887d35a42f44176860022491c98b0a281c41ec018c024610a27f5f261d4cec612505d1f1a42e40f1c5510f3d27acca788478a2f0c0788ae011e21122421a696e68330d0a4434ac8580c1907c42087182a0134c2160486ad02bcbebe845c60b89082e8f4b6a2b69291869ced37d73ea740e51adf6572c270bfe74fea555cae9d4b194f3256c8acee9f17594c725346b23921ac403c64388dc3c82780c1185078c07ac9a8cb0f3e5d74a399c5c39aee3386e48e3be5efadc1da714b956add2cad1d7ee562b45025115ecfcfa52939ad4344dd330d7e144cae3924a97787fd799a4eca8dc362c270bdd6b72029305ca4396b47322e9a4c7353a1d73b40a540c79018791f428d9b3c83ded511985d20278148f02075215485c5d802fec283fa60a48540c79d18242a5067d6bdd6a1daadb76b79f43792a695264ffde6a4fd7f75b9d1b976cee57fb4d47c3234e76dcdb3654eb56b75aeb3654b7aa51a16ddae6dadf39d4a16fb572450ce56009a562c88bd64f921515c8acc09848ca1d652635016826cd2432e69559a6c3963ab0a34cd892fd674b52a697b28ae61b76fcdcd3d54d25cf50ca1c862bb07ae4269a2f03db30e10a3830724752ea3fb0728474c54a2b62fce49135b312c62c0ca51410acb4726464e5e8c7ca5191953066703861e78c0c14c0c41e3610e7179958fae84e951a76944b4546960f96b821d6c894cef9933559d9cb0186ed1c3445ee81a02040e43e688adbb78670b825bf7b29caecd3e2865b12b7b8b761fb0e37a9e2b3e196b481099325a2a8f12372b825f190eeb99e969307b7f9d95c88b039e0221dce0f9ffda8040d35a6490c154233020000000000f314000028140a878462a150284b6455d90314000c86aa50684c1709a420c75114848c21c41862083104114444484668b8011e4bd82e8c8d1b6a73b1a465a3c7f4085b59df3eda020849fe15f0e7c9eab5efc632e7921ea28e00c1c021e15014ae5a94779e7a1b77bbfcd0e728e76ebb03c508832c9128bc85613bee27218526ea4e1c383171679b33c83a5a6c15d8d20ec7b35581a6ba8444d66ca59de9f9ea5531089771309dc2caf0a1192f9305a30d598f3639c523e6040a8530c9e040b5fc3dd30ab56555df177efc65e63f2ab2e8e4b321f535312424efedb62263b7a457d42e0a4c6af202db2b3041e7b220d82c4c253fe802f47f8eea2de7873f326c03b3c6278c95147eb9afea9f058f0db93d21494d320f4f685294c0eeb6f1de380985438a8d96546cc7d20f1d6167a0272b7c8643182814e29dee337bb99ef6d239323a00c3c065012c7aaecbb64081dd506fe4da8c2f0abe175ac61bb25f3d52ed68a8a9deb40708185d706499488ca9c8aa49b1af6de49ebd647b7879313c6c8d5c82df0e6e8d94f2b927405cde685f165054497aa92d2c0cb2f6c8e4ee26ca2941c4f0ca902963035f37257e26bcec2a2ec48d3c0c67010fa7ca0dd606988d26a4f80ae2c41a5ce318b5e55f920f2bfcb3d2ed48085f76d06c3974bb9f7840b20b3198b423f45f749554fb8f605a0740770aa00810489255497c4dfab2e524d166127f94f481b2250c9154e23037a6148ce43c92d05792605e71ee82b06c0a438301c8c42ff9a663eeee95a95aa10b5c4bffd437c1e82d91c3916a2fdc61838b6c9895e430996267f187fb9b8b3201317f085eaa4005164c20874d620654f0b4895443692436d9eb3723e94127203da5d82c4d3412855a43c6c3200487858dd3a5193b52220c17bb4803656c0edfd9afe534baa0339aaf907f17fe46019c64d1f772b9d9716de1cd0595e16c25c4df02c03caa458ded593aad0e7e7cb917a2ff0123adfcad2bbe9e8b5dc60189ec16e85086db52c1b4d8d216dcd47fd74ed35e3dcd7b75d42ff0717106fe337399ee227479aca6a37136099d1298dc42836a4a324e1e8d0c5c6608b73fa2e49367e0e66837e952013dbf6d6488a5271211449f4c498674e146c638e8bb9ee1e65a17eb7b35143d87a194a98d88ce1137ff73c5636c00be994c8bc277cf711fbf8ef26a4757cd186094f545d6c970f4041f4000f6a8d1b759d6e2aca69df70e5be6cd32733925e5bdf8f10682c12fc8e7482230d918ef22e498bed91113e4b9a2da29dc4ba09af342c8106aad42c50cffe96e638feb422aa1218ef930118747d96490d81c411058738a631b274b53a51490a6c21b5506bd1195dc8d28e50a99dafbcb85fd80dd5554430d836c1b71a6763d835f68e08a21c7aed8b7020051bedff6f63cfbe99b814a0a744a253c1c5b499740528449891d08f89144bbfd07894de92aec0e3ee9a175187b419b1a910dfe80ba53139abbe66f07f795a1fa51fa1c700e0fd6fc332395e0dc5907a9f539dbd4a71d5388dd4f68e4cd62db23664e25600c63473ca691dbb6d53d539c4c35f8db2e9463090941b820fd59a998c1ecbbf7d3bb8e72c1062eecfbef5a732cfa785112a8cdbda865d3ae90225fa79b2e02859c06a8f64ede7c68464890ffbe81847bcfb401ddba72e7f84e9df904c847017d52d7a9c1953fd00d62c804211eedf3a8939016dc7ddd6c6f243e71b8cd030c3b5b25648e55409699fc3e215761e9ad7ca0e42026eaa6e16ccff8cfdd33e61f226ee430b261a9f4d1b0b7417efa952cd43c81e214c4c3fb8805c17852f18682bb2495a213f96f8586628db195b6a3e1401ca780e8ac84a51fd253a00bd85682eed4b340ba93981111f5f78c3b614cf8700111c9d29df340512226b2ae56f24bee80be6ee009d698cc575bf8b53997c07a4350be95adf02ee8072575f173992ecd9c836db599cb09cc7171c57913ae885fb3367268ae78d1ed53ef4f2db32a7332c2c965d4367827530b116d447d2e5b1de45a9428b854fdccc4079b6e5a2ec7c4ceeeba57ad7dfe3b82e0a025eac55455df4d8a9f23b2a0f7bd90497162d6295a84e92a61c06fb79aff40dd032818088d7f884423eb46185ae80b53d5da44a62be3955649f463a2b7540f38df896b111b8aba17c88b6a43c7a011367757ca2d2dd5163209400c56b795b53ddaf43d5cdb71932c20b9b1e8bdd2bf0958529baa402834bbf9d6fca770850c59be9cbc72113e85b69bf07dcd2a60fd58035df1fc14624aa1967c55b9737edd8dec4b526782162cb84b9728c54f52864a42b209792f33efd9ff2c586ad95a0e7387a12596a139b34d7f0421abd71aa3cb9bc23e4b59a3b0c21a97c3a918a813319f0117a6b9e390d3f3246acbd05e72df798df587fffb19959bbcd10c5a51365e463433bafa12d5e4740b34b98092ffb810174a14beb241ad5fd7436d48f13a180084a19bb334fac07bb8f8fdd0858aefa312b2053c133dd2bb25e3fd3705e5da2742d666b9488eb19761e889bc551429d3410d3779f1ad7e850ee8d60b8eb60f38fff7ddc04f3e33d16da20ad1b668fd75bd2754d02a9ef68e84b0afcfa6aa416002611ee95552711a07480ad61321a4a25db941c5c0464ed4cdc970424cb89bfcaef4984e76831f0ab54ed72affabfbec94a92c8b26ee4478581a55edcf65064b0fb477fe1c4fb2610e5cff682bc68c84d8465d79893cb70868f3ead3d908ec36a2d91b022553c7359438770f95d936229383d8a09a2fbcd872342343d4b614cfc5d532f33c9c282adab692797c9e972d9a347bdc8c7197ce785ebc49ebc088c7a41c3d12577528697d283a37ddf87827bfd02734ab9b8b2610a12483bff2bca3d3fc72efec69e026fa471a38f798957af436d37bdc110d3a0512fb2c1861f8ab30231158d7fc1289580e528323e133cf35d3e280ff9dce06d4baec07871bb90c68cc88d6445afd4df3b26719ea1eb1740732ab2f6d6b9e9b573263addaca7ccb0bfd5846bffdec951dc62fc80b0e71138f76a474177ad6e9ce8e44c29c6ed1c97541e6996e7ca01986d8ff3ecdd5c3c963a5d88cc243ed71520db18059181e7ac73963df6b1115795922fcc2b2be603f809499ba479afba4c449c831955b6515805a583fbf2ee87bffc4772eba89ff52792789e4a1b0aa2294aba15c342da063a088a4d8e0d98532d09767a3252d5143c5e3c062aaa7d8c7ca5c8d16a83e88292740f5758185ffca328c68f4ad4ca7cd5e86ca9f6d2affebcabce9d6422ceac08c36531e0646ad2788c7ebe8b7377432d0c3e05d5c23328480bbaef1171984e4fac33fe8bc4fc391e1489cd89f8920f52033023a543b2d02b92c4bda76f3d5125f96d13d5f217340d3c1977746b92100365b746111112ae3ad1c5384d0fc6b5b2abc251a2915653addb605f02fa83ba527af215f79a99b6b6fa393570e33b77af3350662e769be27ef92d12d7c600c60afc68dba2d4261c43730612c2b40120a7a8e8c4fa1367cdec174a9245c46952f977950c6108cecb4c11cdf3ada3501c1da9762f5e182ce5556b6d0dd90841197eaba1ae8f2bc92f73f729e18a5d2630e6b358a1455a593b60fb1c3e9cf7fa1db7b78e127df17704d42846a0526df648ab4c700e9c76a4d29f7a6691bd89268e27951fd0315bbcdaf6506656100a9cbc9e4aa99f4a01345a132a79da64319a4518f68b1b531b2fb64915eb92bc40b1911bb289eda064563adc8eefdd143ec249d5a3c9e1644d514010b3186f35c67d6c466b5e1e2481bb8d68645da776f9a168476348b6215b04c01c09f744ae384a49311118d27986ceb4bce441e07097c1322d2d50386d51b30596a8ac33af6bdbe07c50ebc467c242e193f9477edd85636a5ebc98be82ecee29e1c5362383ac3c426cd4b3809ab67a719ab217f78200b7246f1833af9d8acc74271c1b78ecfd9d5b07f64394e82d61aa20ce57b537ea0203929cf33649c351676916fe2cf010981a79fb872ab5abd524660f6d22d02a2bd7c42fa3b0f403416a92166cee8cf046685c57786cd4b8a8278600d13a043b30520e6b1e846600ae22853acee140a962a89e164669cd6a02a3b0408177baad8bf25ca958170aa025e7fa5e269877abb4966ba2aa391b4e1cb5882f50f9657f49c4578d575ec25c28f3be4b7290a5c06557ccb05b001be64dd484c78c35d208ee4c2bbf8d09d2317e3cd41782f3301e4bb263a3b6a621c84503daccd6b3c553a7cbae469783222d7a47dab7a834455a0035e5001655b28efd576084949d934e148e5b201412c3d98d341d5153d8cea030d64ea7d57b32a32ed722e84e235a435852380b5e44b646f82513ca250fb474e6adc12673fd3e210206ddbf3735b18c6434788a74dc1e7d2cb913c31be82d68c748d990df8ddafa0338a07eb2ae2abd8958b2368eb9e7560dfa25b8009b73f9a05d5500ae6020df76ac5576fe73b62e6e9bcfcbe13735e2c00e6a8a34d12e31eb5ea9388e210b8d9583002343f625dc01e72b242277ee70048150239e298edce44c5c227e1601428bc34539ef0a6e0ae39c93c590e8b60828016c97dbf949cf6b72e1242125f7d81e48ac156fb4a78797105e5984fc9f13383084644038561d5a76412102b4ad1eb322ce81958ec4a0a9cd6847b8730cc89cad4e8f81fa02ef3d70f2e9c65e892442f0fb338248a41294296c7a40802c3d794e56e115234729463c581ce7041a808162b9413b7dc3d7781b23a0d3231eaec7c8cb07172141d2c912744889000ae424f4301fd19e51212edcec9dfbb0130d8df88c7c93ef90367c71254ec0222a09c167253caa04b0e3f1303a3341ac5a39ed044667dd5d34db86cf1a0903c20752ad19d7c717ce20e5c8941021a831a306a202161b586d484ad5684d8e067ddbaa7a5a94c16030a1b7f6fe61ffbbe27a5c48d53c7c4acd4eb424a6f6c1e57c4761ff3767a1b62d3f9801b6023c38d4c16803d1bffdec91f4a176de863d51a96a7528cab6ff12323eebc2e6881f5a18ed412e73c6b8e04f8a87576703dd9a0a16d63992c067d0dda87edf3492971e31ce532f55e9c4dca64ed594cb8a58a7b3ef3885963625098fcc7cce62570af47b1a4d59cf99522e81c8cc117bcdb3deba7dd09b1fb1f2d1e570dda07978f71db7aaa91d8e378049d2837b89a29cb2d6851976a8671385cc45bd75014ce923eaac063afb815339de564b3b2abd085831cd3e93dcabb7740f33515e5853596b1f22e59c0da0a9b010639cc5ee31aaf65900e65e11f72987966c53d945a086cf6fdbdd3b71bc451f9a4b1044a65578d579a98e841a5a6cddc45284da99f011fb1e8b58f1d98abbab1cd4470dfb494986e32551f8ecc506d1e94bdf92daa273dcec3c0aecae007938ff3f073874413bf34cd44032bfdd71ed28a6b380491ad1703ef2b62242461e48cd5d465a90d32c16de31095e8032928301acc69b923699e9e2a39178eef9200b08cacea3d408a84b217966ff76ea6c12b0facf36bba0fe41122ea2e729d20043f16dadb871227d2cf5870706eeec9b8e5c160d0cc6a851058583ef22c257c44ef9c4d8ac192afbcffbf5057aeacc7b98a489ab01d002d88b07c4d39ca88986c5b3477a4b99464b23e01477d33f72921246a159c0b19e04c4e33747f9b1e6f1bda7b59eaa74990d51ad2e09fc0cdd3b3d72ae82fa0863bf8186af7ba7b4946908bc19829046decf26c5830a2ef2183c6a26a1d8be90116ba8886ca07d0fce6839fa22fdee58baa08cdf108de138ab9b494705d184061dd67ff68282543178074320eaaf3a963e34758b6acd1e6f13c3983830f23dd76eb90166b2a32f689120b81cdd6df7bfa764b5c754e4afb30f4711b25c7813ecba4e671a28ab50543608eaef9ca31083744be78ef1a38c214c21a37b6d43acfffbed7c42bce4cc8df78adb17ee535be66a7014f384c83f2eee09337f18dee3a57376b07663893edf010e177c3033ca1af4389af07c465f69adbf82adaf243671a5586650d9da2dc99fde172095672e1ead1947871cdcd82dde67f7609f71fe3ce5957c1ccc1e528e639adb652c8fe3ff59edc579fee1bf1bca43e758475ff921bf153d61f3ed0734b411345598e4239a96eae168fc88823d8ec2cc1658c8a25a54fb78ce0539694ff6d195da4e1c8a258ca03c0296ce34a42cb4edb1fda02b6071d5a9c7e30ab4d8c364f1f8d4f880af46270e56e6d9aa308cf5feabe423b4321a4fae9748b138742e6c8515a29edd5218f4211ba25d79404a51ad70691339916d7f01cc3ade0822cca1a058315650a1d3de6b38a885745ceaaed8e7332bb8452d6a638b5134b0a5e5c57d41f5d2a50ed6406b7ce3057b725592c415bd2829d52b4806ae3dbb8d417f0813bad305ee818ea24bc9011d5d06238e0efc3bcae386e9beb44c83b0aee15a65cbf358f92808fa152ebf7651bf11a5408bd71ea3c7a5f21c7d6feafbb4c23d0847d640dc538838fd59b865dd93736a03b4b64778dd51c891fd520e6f37319742f9b7d4e1927d25218fed7e30475283fd9c3853ff7d88a6cc5ab6713956892f86fa13174bc3a09e35198d5d0b92419307a2b02a7cef8d391cf93dfd8618957f32df169a165dee832ce3c241ba11296831176442a64724028775817aaffb2902e886a216363ecd8b2f6c5a7305c403fb492af21a6a4ff24a24705ad9f86d3b5dde9bae1ecc093eee3bd0a712ec302b94f78b7c354c2ad21dcde1349a3be2b6427064a00e42d74d9936513854a0c42ee322810475eb877b28068ce6f7dfe4715c2ab731d936a3d4784a9ec436255fb4a84726a69c79c82fd0b8df914b0cdb99ca5145678505055bf1f7a653804c7ae47ca9aeda59d10cc5faf4be5d7eb891aaecc30378a32a6a54096fdcf7bc97d6a48beb7d984c85d80965fff9047464b12668acf2797e418a2785b5bdffbbb2d6a029a3c71a03ed9b98982aed721d863f5d7ef1231d6b664ef3759aa093407e75ffb415e85b6f1fc6c8ea3aea8eb97e0fd0da7362a21d7cd0a08acde89eaa45977d3ba4cc69811eb11f61956c73e3036e9d4806654845be273edd1fcde51d544ed8342d6e8580385eb2acc2c22e2dae57240e64a8d30f9f778b9454d40e76029b43f80a44dfcb697605d3d01ea7e0961dd27e9a8b61dc83179454deefd5f6d111390e64c9090d3e35a229a00f130f3235360e229e1bd9d746abb925708689f98f80664bfe70b48c8e9d78957509b69659a1cfc5a773d2c8ead4df2416d0390ebd9327b6bcf2a937963b1b3e616023be24254f7361f93cc9c0c390273a3053bd7e59d996541be3f3a6745ce2cd2f2f019adddd010e50e27f3b4b07adba647d5e74e93b416fe9b5bc557d13f8228240598d2989e04f57cd22496a35373163f584263ac26ebd8e3ba706b325ed8debb2df14d0b80b527d00b07badbc40945561a2b0493d9a88b2bbb1067ec679e58b3fe49a82387778c11cf129c4cd7a0b23a0787e1531bf7942c0e2c1d39acd840191ff283afa71c61c3fb187b4e4260718f3f02b23e25131db23fb690e622651bdbd53ce604e1b999c4657457430e985bf806ad7c37999819a5c07f99562e51c6e92fbb785060d26a094cb0cd17775404cacc7ca56e6308d6d266d0a3dddd6b655aad22902c11e63b49c94f988bc0927bc0f151c6b488ca479aa9a866eb24cb90685dba0f5641e4dd50fd0f2ec29f37ad0f7443b6d2b70101eee01d38cecf068534c9a22e033a1095bc60600a4caf750eae5da05c955be289b26535495b72c77cec9a3e641be74d11fca76863ce55b5424838aeeef2d14809be9371d3ccfe1179be39483af25aeaede46c6414a53128103d8c1752d76ca9cfd117e0c99e67529e174fb936f593d88f0560b449744ba4099c47d6a45e1b70f04a46d23b780e3f20086e07ab6dca68fb31f0110fe918d9a84c289be0040d9d894e1e3ada537e11cf682c495ce86c55950818bae946f6a90693fa3f6ecebdbe288535274b3f1fc9f832d0a78e25de2dc6e44daaa839c1150a99bc71c4698ef4ecc3cee54b7a3d43266fb47bffcc48d04e856e22ca5de0ff7a65a968f2060313f0f0e13e8abd50847e790d3c919c042e093e41fcbb1be68970df0fa8e680b120ad6d6147e8c7dcf073b1a1526f7d9f35a66e190edd51a1ab230312cfa1bf4e76efa50b7fbad19124ef6d2ae3a4dcbbbeb734ce10da06f6c681aff3a74043584281e4f2bde57511701683f955b1800c27720ef5646421ebb107242b9b0bfeeb063ae7f4671e91d39b168194e31506458f743a97eaa206ccc06e613eb47de4ebc037351b25ad49d02259b14592539248e2d2c76d52cf0348b88ca9fef1f241bf6e81752fc8ef488cb7ef3f7fdb04e374e14b7768e339d39f28fc8f87dd20700580033cdc4c577a68c3c904637e8904a9944d2cdcd237759599489a2029b9e09e4c40b11ed7d667dac27071d8ce882ebe3391ef4f29673813dbeddf12960945a1860c6da97446a8f9c701cfb20fe5489ac05f47961b70ccdcd75a4ed83f8c243646bb6f8d58234aa715fa776d1169b724a63444aeab44b019c4813a26241d0a73c7d12300691c965cdaf4e7e1d7f399bb1aa40981256ab76eb43c527da4c085d1453ba0ed9c188e1880568a134c199a962ede24acea93acadf90653520e2fe6474acaef08cce2b0a6e36d822d59cec1b779f07c0758ec33f963125cb648db2c5a990b5de01ed2e693f18f49d30b80d6d29d8fcb4d966e0ccfcc331a2eb648475fea5b6b238a31fd6ba4dacf32ab13c731cba3fc99645081854f49f43472cdb75fe8b91d97a81205c7d1ac6ecbf0be423ca613413cbda19cd5b612ff833ae1bf2e74e1cddfe290d103c13bc5fd15b34012665910fb46b32dec1125debcd2616b62794298a8733b40bae728bafbdb6a26ad43210d7795edba6c60ff0cd0d1005f144c26ca8f126fb31e262f9e3220b9cdd0813c041f2af61b629c64fa10b3a3c8979dc9c1aa80f43cd6ba5066ad4afb0a35d9383e8e3a829ed1328e120494e882a6d7078a11893a94283828e380accb19cc7d3bf68c94f309aab54e1e412e6b8327b5503bd8ce0b5e95357efb5a04e28bfd25f74d3e2b6a27822b0ca195a4f0096936e3fcf29fc4637e8936833022a075cd94ef3ff2874d9a8279f9b36de4dade908ad424cc9fdd525cf65e6ee8dca0692abf350dae0217f86f4db95b626c8ece2bd23f380081557689ca8c460653bce6a842877183ac9a959298649789f919030da4952623370a4fb773b415812a8141e63c290d28d7a5fbf260519e189994e43c0999025bb3e4c114e1154442940db78ab5e8343f3fd100979f0b212b349b7ff748fd29e33fadadb06e53e633fbe35525b4f3d8514028c49721e232b5d8a2e48ba4fead439449740418c57748ee8633130d5c622c46e027a497d88286ae3a8dfa910d61e9b59bceaacf64b006ae69a19bfb7857b60790fdb091de1205ccffff9929d658ce939911c46297ba69af66a89a580229b4ecc4dc15922ab8e91c5a3e388ba16581dac90f118d24ccb9481f65ce0f41399e670168c555c5c53d48d09b4dd3701ad1165efb429191bb318417b0fc8343c7aaea4aa5688faa447deb1d05308c4d401f07e771ebbc7b8f76a6e658aa1ced289a9590ae2432541d7fa65fb2aed37d3a3dc525377c76809cece3ba76a1894539bf5afb196cd55303e638138bfe67b6ad6cafe5fa3158fb98f8e69d24578ed346121df83bdb1182279bc48697f9e816c5b5f810e62a1ad11cfdf58869b5f8819a13c24152308159040979162530e7935c6d84b57e882321e8825468c8bda7451b060a9c44d39666d8a8cea944ee8e18664f786f526b725005bd12a67ed672b8b992eb3d2736dcf249b4d001e238ed9f60c343ae720d1f183d814913c626bf57c888dec28c9b246b15cf92c81d09a96b3378d753db029479dc87c881e3980a108e67138781dc40f490443791d879cf4fdc026cea1f66e72d96b85954d261f9959bc60a8b7b05d54bc7616b38b1ba101f20e4eb0bf0590970bfa624c1f778adcf12e7a74ac7176fb9cb4abf7559f5fce50c95000ffb006bf74cb0d0f091baba1d3440bf4d62617c2c0b8d44e286415b7c186eadd2a899588b8c6a18dd159f3bb18ae0e6043863cd7a30100e680c72040901867edcbc5d1020a506995cfb8868d6472fb1f31e5becef1062cdc5d77efece6096bdd658384a3e60ba7c2606ef91eb7d497a8d19824c8912dc0fd73bb675a8e47a16addb66a24c69d244c5c04cf4968e3df54741f80cc5b5e73e78e0257eec04270c82933a57b5797e124a3ec57bcba917abe44be0e58e9b176fd6b1c680d3e7af698210cae21609e3cdbb4d35bcbc3a58472108ff0dac1e583c1df11b05db27bc1118e9ad29a81301c096f4f10bca498a94db839ef09351829a316b50c62f7ba6451a2910231f38c4cdebe4b8f42af995334cd728fc0a29435212d0bcf05aa7ab97b8485615db192bb0ef5a7f5ad025e07dded54f1f58eb7c81eb512b2e758e918683badcb02766102a129db241e4c427ceb5d14908604073fb46240917716998390b6eb2307751cb8d40d8772e94d103736d25830ad5b1752b236941815d66ee6e0a4bbd5bf6de62e32038c39ea84b51c87e79e39b527dc2f97df69714104f1075c6921d5ce8b8aed6f94898b49977b5713f9e3eec01cfdffd67475bb06b12f41e937f644a678aca0fbfb2f59d14f6599d8ea02fe13643c6ecd0cc97cd5583578782541af7a3c394a1bafc8de827ec5a0270094526295d40aeb02354a2109a3bbe3d7c02683c3fe1479a1fe1bf9e48cc4d7969ee385ea308bcc6bc67fc5a90ac6b587ba1c058a4ac690822ba4c10ce75058c4c41dc602a778e79b37431728fa58211900fc00be916a1eb74040b51dcfe4012dc47fc266c48e962c30da79e92047b7a58b27861940a63fb2333bbf32013ba05bcfe9d3b19f075e5d1824ddbd8987a60246623a6aa45d03ad73c3d3006e1225c9eb3c74b7444bf3b4987b3ec29c8f202a1398391272cdd35b3aa1a09974ba8218d08cf1caf11c6c6294ad7fea165905be30d74927de02360154abf528bd22838222dbe6fdc608cdb164ead026664545183d0453dab3a2d60d3b4f095fe9934c8a70525357de1e8ac424ab7e6f1ab4303af8c07237c122340d9e8dbca030ac3cadf8e0c9171f72595f14c4f7317752ba4d61174e7216ee0d5316f4c8f446f127cc369eae76349a960028ba8acc8be411f583f70be1b000e425eab6e6b8eafc7ececeb86b60978599efcf8635da956a59ca2e2393895dd33dc0ca0cf3ab88d559f9a83e7f62603fc16f75a9cfe1949f560c3784f5ac7a99b5fd9ca986da573b295d16a2b7a870eb7fa973b472776c65594aeff647a4f6562af10aca72273540df597c261a5cadc22464f9beebca081c08363e33f3a266da9ad18ee16c3927cbf50f280aa97223435cf0bd1745612d04b7f5e0795fca1b232bf30bc84aaed77e8146922c770e8e42ac25252ec2334a38e1fdd8e0d6d8a9bcd618e0012200f69330fe269573020bdbe09b885b294a908880997ae4ccfe9a2bf2f03b39cf87ad9fe36a04f4ed5e6dffa59de874f3da9a46c651b1e7223dcab3a4847541733e2e752a0c7007a49453c429f3c989104ce4a2644e85f1d36acd8f20a9843b70a47701b171152f3d65c24b8a6872e693c79ed778905f8245d166a5220568dfad13f010d24cde8b18a26d009a0cdba3162cc9476109838e24eefbe167dfe545aa7b4cd96ff455ba9063fe3f2e470159e73402d5d5413c1aafcf78ba3ecedabf9f1dc30c1c830f1eb5babce617c291820fa0e84d35313316886e122a718fce96dc8d5344ff3e3d1d29a4b3952d4b6d6e6c65b0532aabe6655c3d3a9c0e8a12c746d12d298515a5860ab293878d549efb8414a90a38c6401d69f64282a680e61949a259157df82908a4560bf0748754d5cbd09796305d462c46f7e4431a299a8bb6d7f48d43f80c22398c92c5c89abe6a7aa620964247598dfdca8ddef80ea17313a9154d0dd2e7a1f2a55843b64cca9382d4f8c72b6733b8f1587c6eadb8b0472c2b58be5c9d6f28fdc6fc0fcd716c705e6948efbe6d9fee2b06d10224057aa35c4adf9a0414d1eafcbc863d44cc9b4923a8167b8652f1e742af423a6580c08eaea0c9a0bc6cc864fc2c1b4f5ebed71b1e185f7137185c52e1c611efb7fae6f1e066139e2b3e16223465282ca42f64241c5cb6f2a0f7ec757f5c6b0c0518f97058dfe99ce21e9e6c5a8de41b37850c5dced977a2a4650e0c92052f7aa5a981d4a861aa1828abb7fcad2d36f4177b3668128ccbcd90ef485ef41bec7c606f36a27d83cb03ea5a586ac9ffa48dbbd046732d110903ac24558f1e56d4aeacf53c51b67a860d424b9fb002e9e0ec80f68f69e198426e137c837efed02c7ab4d8e414085ed854fb6ecad80e3dceaffe1a1636233a1ced3652daecb80f3012e1ea0d58bc3432be551a91997d5d565286e7f60702e3a9601ce4479da3a2eabbc2fa535f3884610ff59b71ff97750a313640c499371962f986e1582bc6183e47a484daa5ed5a169c396a7422132dd41b006113f6d4dc0e15f04f51fbf0ec9a7f643d01fdb3c84bf5b3ebda2439bd86fe0a3dc50571ec9adc20d95e2885688729fc58a22e39cd3370d627ec9787f05af0c36ace4b5a2c758c23a1a6ea425e87f7469bb64dd3cf8950980f2bc11c80965b0bb4d32e96ea040666ea8d7fd2f5d79e8a961b44f684719d7bf6e5267f741e3d1fa7566bb47396a6f66fbe102b680ac3f4ed0127949263ac43d2033a76a7a285be993b0276b4083afe44954160e0efef1fc8a7746ecefe5ab84f1328b7e7a2ca545fa14070aef32abdc5a453c2cfaa1255cdffe348eeb4947e7fcaaddc7d0afb7c6be740501e282d8fd261ee64b4f1ff745ad56deb5a5a72e2aa0b17773d3b85c4ce05f9408d14946d8069ab65959527d14c26759327842d13b83f5b0f85d5ee2bb7fe89bda29a18b581500a48970bd870417b35ec1a049760765caf199158b202d3ce8c184214897edc60c977b696878c2e90524128fd65dcaefac12bbb36e5cc75de89f6af4b4567684ed0d4e53e1138381fdee9e9a35506533b9a6a2cb5266b3ed80d415d7e78072e87f41af850ded82045bd764a52bfd94e454a8169a1fc2d865305dacf06e5cf24676beba79911a21ef2e7e99c2ff3845aa3ede25d3238940971abc05d4bf43c73e31a5729877bd8bc695077cb7def68e3141f72920cd2ee9dd19896de58af49376034589a787f44be316d8347c203bc93c70e7d83f03b45baf8f485219a7470ee1c1a1c94931012ed40e5b2558ff975dfc61e823cdd9911cfef6792bbb3d3e000a6cba1bddf9c636763768415d20defd9507a04054d257e5d8ffca23fafd90c8c1c973fb7b416e8137a8b0bef18c1b81a82847ce023caea3b3925915a2af5127e27b4b6f9fdc0447cbde65fbd1a392bff01fe3fe2917bde2c98b278f5e2f5b29fd0ad0cba7036eba038dc2af94e13b87e60f34f136bf9eff8196bfd167af62e9a10e2068fc6050f36dfa8cb47cc8262151200041af731041a3ffb94c0a2b43dc362835133ce44a2acc0e78f618b69075561ee14cb343d4ec2927ae66cc9ea41eedbd65a074ade2276d290f119d28eb0d5704f97876b1da0d0dc2d263daf8fbb2fed35eafa6087303370488d3d03809f7bc91bccce26626b40e87439a506bcb7b5ecec840a27cb59feea3592905bc0f50a59564dc123eb98c3832a3c87196a4c46d5cad4b2f31b63a29658335839f5becb29110353b3e49a60617beeb96b26c4d87cecab98c2d48faec1c448be8c383ba834c7a38d9bdbda8e005a596c5856165d296f0c0d0bcdca1e879c08643aae4135251b8ca467a39b4b2ea36b06b3dfe130f6502f4199a3628592fac2895ff04415728cf46436c847ee5e3f72187a645807bbc8508a10e4b85f7bc546eb49f7f26c867b44af1aaed1b07a8b1c38084acaa34d344385c331bb564a6ed838694a7aeda294619f86fe424295e75a879dc55776512ed8a64882238ea25ed23c551782eb9f6aea5d7b64d0e712f015f5e19d6dd9ecd736d515e1fcebd65717da1e62de97090e66dbcec80a0324df24aba8ecf7dda0b2f797d158276c73122e976de3d5aaddad5c8ab7ca873649df5950a43354505c383f33154239e23a63d6caf8c4bf9c52f5902fb7d425679a6c10b37176ad18a4478695e9b260ce643fbb85549bf3227bd7275a75cc96f6e989bf190c569f19123adccbf1ded552e272fe9869cd7a2d51e5fada4d03009b7c14bc7128565eb0e912e95d8f884484f11de5333343fac54534eef25fce9ba54ae5222b21f5a1fdd6ceb789dd33ab4d81507c442fe253916a89f17672de07a5650dc667b6b5622a453df590b1c8c7f10cc1ef91dd5bf6d739cd308486c34de174fd0ec2f53985e5a4241751ee1397bc6f53e1b9233041287c4c7f556d28a230299076996136eaa22bc980de7514050c5c7a83a56e9c02dee7727845748173b17c51d3db2b860ceaf2f0f4d465dd41139c831e31dbd49655cf6b664eaa4089bde1c583a88055211b7becfef6ee65885e7e6fb41103687dc259297343ce465191924470466cb6cdf983a893d916abfb54c3ecd0b1ae0999579d8d59292a722f263ad2649f9077e2f1cf77b6d9c06e861fdcfbd770ad29ec5d3a9a0f26ee4578a275cf0717016d2b5598e389099e838a61e1cbf5144565fb47eac33af65ab15a588caa1cc6aecd6d1e91d36dda087348414c10097f15008ea6aadb67bf03786967b6183b62c29b2514fe38a7bffbdc80ecb5f8c7b334809e6682e3940276a983a5fb0849ff0a30e04d13397d2c1577e89820d67fd303e22f5d7c2c24485a9684f461423006250baea2210c860458024756bec908cdd0593d9b1e134f9f777fa15436665445aabc0af0794a18eae9035e20d393efa889059b988680313eb823347804670df4a9c7284d68a9d84a865703e1813328d60ef9cdc81e79289a9d79090142d1e1998c7b971d004486c18ff9b27a6aec070d9228e96b55d6214c402542980200243538a27b4e351c86ca8336b633fce3b9059ac02a15956571dd3186f4c00596d159d060d85c00d307faf401a33caf44406e76f3da2753ae2b522810db61103343e16b72889238bc1afc231774a11e8a52d20e505389ffb1b65211451466e1ef057277edeac0f9aeb2124e696dcc046c4a1385b29c95a2bc0609fc2bf139c96d24be8954fd4728cda4cfcf463ad129e4b797cf809946977124110196045fd2508f57d07b9b95d0a125c8330097df51ff2c4188feabcc575f956dcce1fc2f62747b3e47cbfcb6663a53a0da0e2c282d6a667e7450146b6e5c6325c765949bcd08b5a725dc8b1e049c6487f09915156adb4ff30726003c03214ff538f2b44de30e37797bfc61cbd01594d70058e30f3b2697de5591b48cc6c4296e0c12f0e46b43764438dc411d15bc80c0d85dbcceb016939bc63f3a7a5bfa2d78cc0fe4ca2e6aba4890d6ad7ae39415e221ced1688abec207d1293fbdbd3a7414f1ec3e590d5cdaea04c104bdb9b7bcd45ee1498c5a4050518ed7383e2023bfbbbba64388d4f3b4a3d9318e47b38a9781ad8974734a06749c955d1dc962648a56f270eab5f9d11e862e220aad1c85e8b00b725c5d1b54c4ea06986e7f8b28286f8d6b86cb8b6e061af4ef93c99e806219a2b23b82d376a958e6195b4f6550c5dc8896f0205a97605b4ee10a60ec49c37eff895c1ce08968a4a8a0534d12950bc23a5acd8afdf893886ea47dacf52dc27bfd113d62339553f7908cd5bc7fb50917f45a03ac6b4c346e6a4eb38d99015fa89bee60856e01e256964522f352191278438e68924552f70e8c2b4d9ccc9b483d171d8dab6c45cfcace7b42be013918fbe8c25a5447405b62ccf51b26b93690b1f4bc0f137f76fbea556cb6194e7f7368fbe307048333edd08a9685cb613f351d657e2bbc87ac98c00e79bb23fa28c1d3c00b51240aa7cea672919416cbff7cfb88077df8f1e916c70a787f13ca0d279365a796eb3abec0efe6765a9db7c5342859e402941ff8763ff23645bd1344892b1fac829ced021c88768741100ee9ac7b62203bb21abdf743a7c09a28b24b367ee9da009e8f70aa6f52007002dfe66b98a4cf6a9220b92c527c85a7ed2f09b0a63ad01b1cb9d7901e7c44c34e2b81244464b899be0ca884dd051c386b3ced7de821ef51cca106a315df1c2f4e47b0f60a3e1a91579525a6b2792d656eca39ada1640e20d33d936beed218b6bbe321f59705d2fdc45100078c28c17496483530e4a54634ccccb25cbc669ce15a44cbb32d10028c06be7ba5e30a4fe1623fb9f71c24e8344eade2822a7174703b565b7c53301170e022a057aca296abb1bd3b0d9a61f5d91bcc6155eae6675cf00173e3240737ae7bdc121db54b97e5d636a9625fe1abe5a12803cf2a1b43831979e0286848f0587de02c7247df0534e2c0791fab1683c422eadda111b2cc6b4bb88b11b7b8d2e0b1e9a379c42ba50045cd9ee3b164db8c5de5219b5947ffe4a112781e898236aba231d30376193bbed2d8d81992c1d4643b6fcbf31c52c0ad1e7f4ee4032ef1abc5bae7be99b67182a07de2bb200aa19f42272d5136a697fa41199b88396aa38eb8cfae375ed037c79a5f51872e44699d8b644c4c3d73cf72d5c05a7d1a8b90fa4ad3690533d162dd697fa793fa34a6a2b5358c6c4bf19028d89625f729a9d88d28ac320b7072af633fe4e32e60ab484301198f80482810fab9e569e1b4cc330025ed4fde34b04d815e2aa3d273bcad2e8aa98e95805335c4ef288085e226bff5950ea5064a132319b043a062154acebeece7e09646664addfba021b12d6f9fd78fb774e04ecdc6f2a09ce0974ce61b0ae5c0cb97044d4ef28333f5dca7ac5551bc19697459a327062f75b4e3b5a7519417387b5683e2a737e7518f82d1b1309ad9c018ce4e32dd9d65d1979e7943f09fac38c3d1216446f2d1a790094ee3907f28aabdc9294a234a046b3d0a077361f1ab6f46e6893ab71e613419a42d384a14169df010cec43b05ad93fae70f1d563c57db53042f42ce839be9b3d790d6c70f173c092bee86f98ac5ad19137cdfa4fc826723cac18d819f51488097ba065108d042da42987ce40c2f599dfec806ed17b52acb61a1d8d8d018a846dcc0485e1034b270ab799099509bb4f6db0d78c7a2e5776bb5d5d1460ef7e86fd0c0967a98472663a4b34a938412f8eeba5ca2db4fc0c6d3b9474eafed1b5749d7de60c78e827fa54b5d955dabfa2195d5672871aa0173b456d70881ac1c5b34590c4346fef964d3b122e80c2cf33ec211a20d5a2911272d42746fed729244c698259f391413aeaeb5a7dc91ad0d5aa98c1e245ed3102c5c6c62c902e155153b0427206e3ced2d8cd8f22c089fa90e8dec3e3cc5c030786ebe2570d9697d43787af8964a6ea4516cb31cf166c1bba093b038d99c6b2f71017aacb39dd61c53aafeb7a987f6d5680333dd7f26d621b44a1976480f29f93a8af4c61baf6eca7a4b248376bfee4f50136ab34d497dffc2454c0b54aade4a0e502447ddcaedfa243804de74dbe312c3485fa32cd3d9fb5d7bcc9fa50ccb11ece6dd0c7a63baa0b6c856241548943be22c378575909f706f5b5efdb61be3aaddeef85f9f37c1c5cbc6a1a2020a7f5a43529535c38e4a2b143484984960b2ebee7a790e967c992de3c2d1bdcebc104718e99866a18215b4bccda717decfc6e9fdfecfc0d4dde2ee649517a4c01f9ff62d9ccf0775ca7842f70b22fca6dbb5cd77ee1118b516f40c8e058cd89fc7f6ec75fd4fa47c8401075350a59de8b6a6055b06ea37b93500621064eddd357bd985d3a5088db3ff6456cdb396a983fe5216e19d8aa11ab7fc3cabf000971cda98eb8911a7b2089d73d0ac5bc71999786cb346d51d447a26ab98c693f4e0ad557f9ab20d41227386304afa0f81a2133792da3b1167434db519694f97576a34dae6cdf321f6347b27659d6206d8861ba9ee1ebc86164aaf2dc66c20dca106570e75a8f55bf28372a3699136e916270c6904ba0c1e8f28c39cd808486c634e608445c11a693793721331ecf0e0eddeaadaf326add1389ebab0cf5569ddb36e8b50644a84269445ad7826a0ce78023e56fb12c83355dc1760397c821295d12cf74122724241f0f15dd2779ceb394524880a876e5a73ce63a98f2a79651166d83d39e874e51699c948459af76f0ddbfd97c3131eac20e5014ad62c0ce24b24f1019324ee2497a1d62f895bf8a981e965a0fff871da1aa7e12844bd0c4b47531277df55e09b81a46cc777b624f531658ff2c8cbb7b6770a23b029a85d55f4b5a3ccb288505cac627ddf60a2a6f3230676081ccbf0a31ec73ea8992c1d61ea1b8c3710d1fe636773ab1d5a474dd6504e58bc23f85bc3174959fb42639dc9cf4deb490cf8b886dfe2be1506ef435237a995d484baec46245f6ce33cc45b6ce9e59161a029ac7ef84532b3929de0c5341f2ef809322d92f51b9e4ed859ac6b6ba87126d69cccac03f287c91251a779ca2f81c629501970846508de6fb647cd29290e3225602b80791b61c4e7bff8f854bbd2c241f81beca9ee897a7bbb9e08dce69e4ce8432836e54dce4790c7caad508a71e434c27894f75760806e6b88236fedb939dc3cdf76bca7e10c6a07a48a0831d9448b420a054e3a08cce381bd15024f285058f7a9c77c0bfda4640002af632448a847bd100113596c85a20b9c00961cdb1b45ef6ae65bfb7d43b2f79d7d2ef5aeaddcbbd6ff9f79605ef7d4bbd6759d644cf0113300a40dea24cd4acc408541355f55135acad5f9a15151e10c1b38bbad241f328c67157ddde5aa8c436ffafe1c87ae5ec5f9482e049ced792020e2956d432cd8551c9749587172752226cd533e2d63d273936706e93407d0df80ace70c771fd59a8458ccb7996638e0b2f126a83ef5868b55b7c128d587289240b2937682753061b81edf9be23544ed31d4c7c6e4f404c07c3f11253abbfb48049552a2aa0f5591b29bd68d910c78eaf976d7228d8b5366bcfaaa7958078cf844e8d7509f9d4ef9b9735642c1403b662991b57c9df3501ba6b3abe13c20951b51b4963b3c726b93e2b8e860a85365dd87a273c0715a66d9de2fd49036dab25cb5704e26d13216534f7d5efb6893e85122e3ed14ccab3c621d80605ba40721f23c2c4888879e4bc537e311f2592a716d3af23f42b5e6828fd56f6e3f83367e33a5ed1f01071f25a173397a7eaf7fad57e7d04b3b195c9585f55a435803138fe9d672fba263578869827ec6407fd259be15789b8dc58c5557e9a9a2d76e3fbd1bf8b5ee889105c329539a110a6e20ffbcae5da43aabc5ab04da5e9660332b0c272379c90bfbb0ba864c3897556de44da39ea89e14495ac1939d2b022367cdd35c132068bcd97d2f965539d16e5e53e43aaba8380f70b1ae930c806f4d13dd036879db711bbad9d526815e1f1732c2f7b85e52b5060a952d83918630104d1821c9ea87872456c2c8bb99ddfb8f621f11f822eb495ece11e504043fd40aaf277258ab8b0cf418924affe93d04aebbb78ef5b777123468c20aaf8be6342f19e3dc11622591e043964307051670f3aee9a186533e10938568a74f39f03074fe9eb4ed9ea714ddcb0036ac2ec3dc5c2c7f8a49a48390a0e0f645746cd8530c71118700961e6949cbe11744f14863b53f76f349fa64561a17f3d6f8429c97bd07124b5debbbeb3077e7846398d25c1ccb86c8f8826651d917ea0c3248be257246cd15e3ce8a2ae5ce29af1d68b7e18e666f4438e16bdf30468643d9625f75e50e2e15a3ba61caaae40482bc9a4f04d20716361d71de819e50b44c72760e1b3ed1b62f59d4026f594baa030e7b6a1802157f125663553d0410b5c25deac9f2d93c62e0110b6d330cf2fb1c1e204c7cd1e48d96c409d54d4333eef55a05bd43f6782430ba8527cc5b05fcf8fbbe083f060c2038853115219dec4164ea68aa158e329500fe5f3b172a60e1be5f793b03803248eeb69c6cfcc4f8ba8f01d16618fe1c4982cadfc279b39c95ad0cad58040d40f97d338e9def73047c5dce41268728cf8a0f09448613847e4a5eb9ea74f0b5eca10135ce85233bde4f050055aea4fd3ecbd86f16630ee94f7fe1675d11f0af5cebff03c44579cb8292a0d08d7768cf5f929a5f894e6bfd0c249214b1d68c088f91464af3e31f0196782794d1e2785ec680d7d21cc428bd5eb197c443de6ef2d72b886d2a26ec243febe8d7a10e63f0270de1b423013083be65c55424616350d21155f26027016d8acef9bcc15fe9cec8d411f8f294f0998b5117092473bc2b5f761d2a86981d6c6e4bd4c1c4485138080b5295a799faff38823c066787b5f85edb6d276cd078750b8c9623478484f07e5889764ee6c538ead82611a68868e150afef0d6a46cf93aa47388a2a82f943d49e84e838468a0465cd6ecb0f0a874885ca1dc85c79e5a6307e901498132c16abccb3a9be23135ac7824836a60ee79803f68b90281a47f2996f9bae6aca84fbc03749ad748b77e0370b1a02d578dae0c026ffebb212046f27e27aaf8d8910bb92016c638e0c9d2ac770b18ca43778d1a8b56f762ce064f8ddde23d72564860e7e049f6f5170e15b8b7ddb67dae4ffd7f7041b484dc09b3113cf1d77343c4cec415d5b7a4611289b0e0be206eb6808d0e86c5d0200c90d97408dcccdc32edf922135bd9971c9d1fae7abecac07572448864ca9693913495d4a272696873c47987e8d2949429098433d241912867c1ac29bebaec29acc61cbc12e9b0af4cd9a35e094b033345b883c9427632a2b4a85cc6784105a038172532c31a80b389e9d999af6c3c32ca39b43d2ecb180f7845a91acd0d11193e7c86bfb6622bdb1c3748688f1a6bdf10fb2cc101fcbf740330c59df64afc8dd66f73d58e4784232cef3b8dedf1d54e609c1dc1149ddd459d786068f7ef9be040f554e544925b425f2f510361396214e8c41e3de5f8949d6764040e0f82b5c5c49005df607ba09f603d77d16853f96984207fb4ef466af4e29d16abacba792872760e402725608ba91077151d1a9d824be949b775aa0271e8e82896782d234bd858921beb0ce72851aa0d3e9ce20de0d39ce89b38585a88de8e756ba8efc2c337dc34c02bf6922c3bf3616016f2d75d38b29abff219dbac0b134c584d406b7ad3e21d301a41d998fc4cc848fcbdb5e89243231d0380d7ecea5cf97bc1ebd783ab1207aec2d88f401d553f3a493362675a8d268c891a035eb21f52082af508f78d71ef671c84fd88b09feb50b65d4972f9895e347a5d3b2ac4efb99dbcd51e00076d92165f6b9413102157f49f200a3f97d532194074ad482a106871e4876f1709d517828c2f43672b0392e6a8c5218c0b892c002857095907d9047ca098dbb2dd1b798ac17f31dfd2305c14ab29dce599166c1cfcf38209824ef4bfa0cccc82a4dc340219d38a10c108e8ff0b061be3452635569b5bbb2b16d0859f16dd58b2ada663f3a412fc0395a6ab04b7bfa2978a56899c031be7aa4cbed1ce3c3a05efdc9f243238ed538e49995714a48c68502ad7934190adb7ee0bbcc6c1bd11a8d0a811f6c0a9fec5379337b39128768f70f70c845b129228413b487da43b91dd9464c52066bf4d644dfd23f1eb767c0a8d7b3185e157e64e341fc83857a336f075eaa869b280e047f3d2ef04ad7a14c62f5f36309fd5351775b23ee75c76dd91b012945e7254bc71f22f06601d3223b8b2557cef83ea01ef147df191de714484c614044c4f5e36d7e494758b5cccf94d1841f59aa375d8303c924c3d4e1b223338e73a81c5ca1a802b3d424df6620141341cfc435c1c16ce675f4d70daf14d2ad368d8be21ba5e2cd5bc98efc5bc783105a995e2d80fb0ba9dbceae628fed6087c566cb5700b245c7ceeb4bd8f29edd6d9e4a4755938315b4c25a29dcf0ff9f6593b8ded3c28eb9a47a05b29c2f4f26392b59e7363ca2a0b65bd322b2fdb35a8e9341b6774288a057554574be8d8709d0f4100bdb8d01457cefbb4a305aecf6250a682f48c27d11a9f6b22c5da86fa873f0ab52a313a34ee3bd37a52a7e639d113f2aeb1b1e293b1b5780893eeeadcc3da0a019c992c0be65661b9b5e4002c939100bcb544a5884811c2179438397d40079870c5363be6ad7a16849bcb13fba0f72013509a4eb7ff960f2285d5dc40c739066387ac43aa024b6abeb6cf40809c9e7f585504c749f71e0e2873b9421d6ad4e5b6f22873f0a605ef14a07b9b6a945197e0fbf94f1045e437a057c972a445819c13a70c3b2cfe7a0d9bb2abc2239c7b8b37c89bb1a1753e5cf186f5bfa3c7e6ed870502410073e2eb79fafe9b98baa1edf716943ffde7a47938d995dc19fbe15bc634768f237160bb790254cc99c504f649887b2563e5736311354a41756650dcde11e070c9d21c5ada731654c65ac68210840415cbcd179b050a3a62188ff98b3e851915562b971adf705b74a375468cfa588a655ec973eb6003261106a3432c656103ed3a8912ecd139870648c94996622463f14e1a2294296f54a452c400d24675731d08f41e91ee913ae58637396faf362966062907fe9807d7b876f381c537b8a35b10bf7ede02323232fa9b363bbee97b0b80e64b9189ca02563c65df9200e471ff8e089c052a308493d0a98637d290d744f824e287fb6a0fc11966ee1d0870f056b0a44705e20c518820582d0c80efae0685cf68ea78b823111089d00a9621f9f97216d4728a974414dabc454d8d8173ab899fb2690e3f77b2a60c3aee7dcbe64fcb7e813137d63414a79cded4bcea85e8e9829cd3193398fcb3346ad852428a053fe521495d54e3ba5a4d48be4c71102c8f4e22b64f1e9cd78ee561775c68918185d235c4e8f54b023e1d3a8a9ae85822d6eb481dc5da8a658aeb7a2dc836d45234f2f59ce92cae5c58543e6fdcd204147f6b82ac6602605b09d861b3c7513dcbec1ff1dc11b6da735fe1d023c7ef41684ec00f53bc614f9fbf475f9921ff0a471fa3b69b2ef18c49b56d15e86b41f0d8f4dd1c12ff63141d41b42e3f50a5d1693e61967bf10ef1b0f44900856166102626277e3ca7c2ad960277f42d5d9ed45faaf0fb3b643f157ea3b18dbbae7f6c5a35d7d198821cb76c73c630399304bbae044d921f31a83bdd4eb2f5302d6994434cf4fddcdb32b419ff730423f2e9fc32680d6745e223e613c232afc02a04c5d7c99a3fd6a4c01ae870777f85339340613503199d81ee8f740ab372c5a53eb6d6a36dda6ea5f8390a27458065b1186c1824ea5384f838a46b4ee914d576a6d100ec8553549a98111d0b5c2c67b5a4d1123ff4a3117addcf739109e2aba5a5459e7839aa03d42f1d84da0f4e81a6af9877d7bd7b09e60b4db280ef2b3158d15752a39de038abc68285c5dcbce87fa93aae915a937ddb3c87b5c18ed69ccdadd3c3726734cdddf847ff65991b9ee51459197013eaa1fd8a35e0cbcb6a96c6a5e0dc2bc3aae66562f81de0da7612768579a2f59253ae299124c2879494882238c258925286b5f8edab47411460c95bde914402b76d8e683474bad3dee476736a7a5ff70705c1522c357145a12614251fbbd11a31eb296f1cc3fd4c6645ffd2b0f6a5b5042e9a073c9fad059b7fa1e63b7db96354ba9bba1997870575600ab36a70765d790133386463c4de25b778870d4aeac48e05a35acfa660661a445923602c853ea8288f004e8da4307fed0ebdf1e25b25a816972449e554bba56dac67ae335c4c197adff913bf05eb3cc15fc7fba7a8e28cd40de4cd0f39ba94a47760c9d3499ed4a5ab3e786a751791ea19a91b929b5f52a0af5de6a87dc0e47a1564aba9ba13305d1ee5dce272de12fda0d9ee2e2d2e82f1cd85b7863a970b4d9f27896a73d82c1f7bb3a14b9f6cecc07d5fb5300ac950f2f368636633389455624cef2bfb304bd97b3260b1cecb123f3eeb9912240f625924abf144e149c1dedd70a928c7743a3039c01851d6626c4a056311e5e203a304b8cd0153ae9dcf741c5337e901176b18a2f732b8ceb722f525663fe055d4acf28bd3cf1915329fbcb0f9655c0ac524ef3c7e328b6238e431063fc59f78f63899bbff30271a6fdc62ed77ce44ec31c6bb5c7d30654a9c7f12370efad13d52cfe1d935ff768c7cb7707fca375d2285790857bee20747886d3770c55ef08ffb7872c0f33c00d03ebee32309cb576b8df2f11d3d8cd94accefd36af31c7d8846d3a619a2070f5430e12aabad2c28843f70937567e0c7ad283f8416e58d55d24cf265136995bce7469ba9eecad7094f5631469caf8839c19527a26e206bbe89d1b594bcd4eedc23a8c68829c27107b488635cc2192279ce21b7214ebb80652ccb2adc18cd676af8ae4fd8c69da777e71949f9ed0e6284c021aa72f4c45379c4347735d92fd0cf5ff1c0f03f323737528abf7ce2623ba358fdbda1a0899d04bdce7781e1299590351aaaa3f9c0828a0e01bfc51f952a8c777a0aa8fdcb853bb40e96d8ac25b80332ef04ea0eccbd03bcc61a6b12030dc0d054ae5873ed05eb2e1e652fb9e445e9b855a0ad19320e83d75521007285ef40323c1652fc5753fdab693e6b297eebce41f1b349f1b249f1b24df5dea679d9a578d71ae895b16d0efc0bca391327c5576a6e94e47d79b670bd4d7f8e97a04d1c9b606c497c6c29fc4c243bc4cec8aa1cffe2930b8f789110107e0af3992a5cbef00745263e7c8ffca4d2063f701b8fe45cbba9de4fd81afeca8bc69c16b000483cf500571543bc76d8b34d64bf21b424e4e6e7eeebf0e5e7be1c32b70550919d38fbd077d565dcab90599ce9b2e2cc2299a7d39c2d633004989c116a8bb89052cb6833784fafe6ad84178bc82c1f795c281b914f409c3fcde9b3bed5690f37d32f9d1b0243639c58f18ee9f8c44024f8c8422a823060b2f77a4d462ace6b6bd25899747b7b9b2a1d37d36534355b4d58e8ef5077b0e9bce3f705b365efc3c202e670143cf5aaa10b6abc74f8f6cb2f27db48590dcc56180f4974ad49f5b35ef422955f9f3cfa1b1565eb25ab393bf57c7caba913ee6b958d53975f514c07ea4ddbee8d4d32d48e57b9a759c7b31703dcf691a0e05379a1f9e99fd0fbdeb24b189f699bc56333c0217ee00d55778b12343de934b8dd6ed1c75af9fc5447afa5df38d07e70493c357940a7fb51805a1d7ec60207f00848601935206f29081ade220020ac0a75859b7cb4d8a1f038a63ba654535a56a0e680c1d20b503ca4ccf22f9eef6317c4134334c8741dfa5e9605a4270159488ccb99b6299fbd770c84379444561cdc15199be815b9a0fde325fe2156e9172a0d9734e1186b33539197571d805f63252360b108e21ee41d39ddf5e236c8fe8f9cd0b9d67e4da11838aecca1602f949bc7d6bcb202228bd7137bb9def02b972e0a011ac87735c9d00671b12e207ed7291b45c9accea46c607bedc3671e1e51fa359ec5f4b53f279a6a784a7f6cffb99f9ed42d889fe615dfd06bfde619949e8e2f45deeb05a2a878746c79f5c5a2774b1ea468b6d0920507c86cf1ec85185fd605dd45102b13c4118d64634ed686a48d7eede74437a456c44f9ef3549c8b3d35fceb6af049dfdf905f3fc22cf1e1bf9ad58d8fb15f4f06bafd1f11853d522b902f404cab3764e365114c6075ef969df26a0d7ce0cf68dbdeb46c6ed52142ebfee76d305641f03fca594dc4961b50699db2d4af7a6eb90bd1854d4026d665022d1ff6c03ec07f604cf08c6831d7880cdccb68941a63a94693c4a30fec3caf919a1d9d3750631479a957f3f720885f845cf340cbcf0b589c4a1d50fe0b0bd6020461cec5ab006b24b4ce88b7d0ab9110fc37a20e88882ffd0cad794ee9618358abe7eb6d0e7985d117bc550785c1979a09a703ebcdd2dcb3d4dbf674efe06210f612b907c95bac4b98690d571804546237d853aa3183d5e31d30ae3ab626c1d6881fd75656a82562989a819d3349016952fb4cf4da6790ba36c59fe48aea5cb858b70ae3e9e26abfa1a7c011664b9c3ec9c7a0cc514a57059b867614ca5010f015ae43091422b717e54678e895144bd51d09f6304c8f4cf42e97d9594453adce4c42831035f8d974773dc8efc0252d64736652c93e56b578a0e68f5aab3e25958a5f1b53f6a834e7d9c8c0dc93080f182803de069df811974cbf83c7ef3aed8c219ac1aa8be443ae12028be99bd9799f87fc4e38450122927d588cd675a25457a76a31976e5a13463e77954e19238331cedb4ed265386918242b3d8dd0e4bd77924d549763f16ec05213f1ad4f7638451e8fcbdeedda32fc7b6551250802e22697cb27991887ea0140f6f687c408d3c655be128c2a8159602f863c303587b8547df2b6a023ae032895e97bca149cb5854a70afea199aa1c671ed12fec3ba22bd3a8e34dacb0be41524b0d9e33f7ff574700f8b7f17b77cee03f4eae154fc1b15b0f8eb3e46de433868a8d4132cbf2a6a19ea8a2d658069c99f56d64fbf66ac976bbfac6d81797d58f68cdbe1a5ff298f6b5c301b4d26fb7ae07598cea29d04c58ece6c1e093be816d77398f2fdf8df74904c681ae3b0c579f2f70ca91ba244a359e7d157c5cd6c88c87fb53b4dc157c142192cc4a958f3b2d0b24f3c6653494c9323065343832ea725a70df0710d0a24811b18601dcaed9d47dfa67c9bb06477be92edbb4bccb6cbe12a6eb8fa1631e1f5e672aaedb8482bcb547ab609b91ab8049bac55e9cb8495f79972b62c6ba4ac647988cf658eaf66e5b4cb0dd916b9ccc63445c8c848dc36931141f293f838f00aaa68e48ff9491d68b9704f0ad859c983398d39db5664cb201b7eac5886d3ecc0abb181d24e538c4f06d890a94d244c9c993973e671359fd5eee9acdca0f64159c73c50d5ee8fd2b9e88a5d347188b432f5e1e41df9973dce0017022d05b4c018e0b416a52a561eef4010126e2cc8013fbe6abbba1c723a50f34616fb40b57e644a411ca0b77e0856bad266bd8335fb99964964f5389c05350471704b5721f2618a48c92fb71a097434eb133e10350d0b3dec814272374d4ff3ca4e1f1bccabfce4b8924702470e33350e8404831cd7f718f2561f29131ddb832d584d3c9ba39ad451483ce1fae1f0d515a9122a018e3582f11202034c9a6a71a0176ca62a115db6f6bb5d667e55444834d5d6a55663f2ef56851bfa211f0adcca83509660c1132218accb9f443d848b8086c0b860930f2c931b8be16070f3bc67d2db39c64847b2838f75d82d1586ca9bab5314044acb9ae39ab93d977e68d55413290c39ebe944e40dc4e1ebe96e94595d70291aba04daa1be0bb0c5d8c760f80dd3953f8230dda69aa10326df2dc904035d69d57cee76a50da549bd9697296219d54ef90e2014b3ac727f5b83c58db08f23dbc1d07909470b608e7f92dbf9932b3279cd15337f22f0fac1130112ef6d22b1a1050218ba5d5fd372059e01864034187d10b31b10b3d8cabe72f7ceb876bedf5f5a4ccee77bf73bf4ad2f12a0915e321d0455ad38c41c82ab1e9f91cf427b0e418b34c44a98a83244dab79a883a8f2b8254164d5a45aab1d102caaa5bb256e8ad5690a0924b84d834a8cd82da03d84a180aba28ae10e0282265b6fa9842cd5ce5df3df57dd719344741ead48014c24d90e19cc3508fac963c2482fdc9962eda66991e155ac592add9ba1d7a19c9f8422fbccce6c3c99a893d00faf938786bcbb57c07e41910597c8058d20c925cdc7fcc40dae79900e87ef3f5f99092073ccfe464f1e1f7b298366cc510c195cd626fa4f61945ca51997e34e363c3ca5a05e5bb8742fb57df8608f0a5ed56261077d850fad2c5c31d986733163dec4653c06ef924ade4800f9d2b59713f76a2fb4e5d327e08e3d2f8a9d4f6169ac8c6da2d466d1ed9b2b1adaa44b2e543eecf47a33e52c2d386d5586e54f324c5640822538685eb43aba35baec564f5721c7638fb86720bb6a5fd172d673e7e6aaf6996cf85dd3085c9034411d4751a138e5c73615d457625d7604d07efcbd5b37b14389c08336a82aee5b17d72fafe79443a404c6bfaf34c733bb6dc8141ba1cc80b98613d617fb315aec4a7347771dbb8b9f6478e23a91ad70ffb6d08d49c485602b1b14a7cf39524702bd416a1c0858a5774617ca952cfc792e6d412666d434be355311cd538a491eb22dba3ef22c2b6cd04fd225c6c85bc70947bdcf05d183a2944a1234c3f7ce9be4bc07eef79607138fa10c39d63288f19dccab87b585b80b729979bdeaf0b45d26ca981fdbaa6d4cd8c9ae3db49666852fb2c5ff306ea6ae5f576b94030521d31e9c13a4df0dc29236afacee35208a1e669f310de0d50f30c306afb03b53a21db6d36d88986c44d6d83a784687b6453833ad3eaa49881685f7261da92929695abc9ac462d83564e3a706759556bb872183afcc0a83a0b3b93b79e92926c86125151b2ab0659f505379c49093f273b2245e13620389430881e91e1ae380bfa1554d0023ae865625b3052b29a0e65b0802c01264208ddf6249d56545ab7552366cc480dbb787f33b52d97632721dfdca9ae96a0dd5c6031988b8703608a41dc02105c8e343513d7cf1aca6676603ab6f770fb38f06839a1a116d2f6de7bcb2da54c49a608066a06db05958bdc16b51a6326dd5dc2b4387f9829aab1d15ea0cb96275cbc205c78bdae2f5d292bf02202e7016143569c21c2f2c7fe208dd3efd379b1f11924a18acd408c71847234a1c8b26ae377919999bab3b333575b639c48f3d52b0f553eb35cf77066c1618f3e95809260524a29a594724a29a56c18aa08461cb9b8285c9dc1368f148a41a0d3d84241bd72202d02f5d8e1a3570d0bea1f9fa59a8ebd968462509258ccc7536f43dbeff22202a949598b03851f9f9f18909f1f9fd88fb5d6fef8008901f1f9f101f2d323d66852445f99854fe99994d6080844559670f4cb96524a29a594d25a2bad94544e2965ebb06c96eeee2a659294524aa9e9008ccc06560a8c1e6c68dfba5bd60b8a98cb4657fc400c2fb824196d59d29ccb565926b6ff892c799104438ae2861c454fd4d1efff427ab97f6a08627451047283c581c28fcf4f0cc8cf8f4fecc75a6b7f7c80c480f8fcf800f9f14cbaf4a0e6b667f7df525b68f6fd9e4550487f44b2efec5fe81fd22bef18a3fcf844b82a6448af5c08114dc81022e08f1e3b7cf40aa6458b160a8059fc6b9e0621c4a565826cedd57b4a78dce0a13fb9c824a0ae7c18861029b255bed19c021d4408f8d32bc961617f749f8f7cf93b1aa7470b1ebd73d353f12f82fa93833c27fb2790fb396b7a23f64f1fd6745fc6003bf863df88e9516fa4267a342ea0def43df64fcf45d4f7981e0516e939bd45812ab7892dfba4857a6e75308ffa1e98478146a8f09c1ef5464c0f03b2db74600feaf428905bfda68f5ba78f5b3cdd1f39997878a76f7b07f2f08d7c4fa96ab0b01464ad7456aeca85a90a8a68f28f322cfde93ff8a64b037550e3786c1793f86505b681629728c6950f8302311a27f6f01cd4cbf7e1393040dd2f01ceb8305be13934dedbe796e9d973526fbf27f5168c7923a74f8134dea7fe48ab27e6655e0634623f06a4f1401a17623ef53c319f028b50f1be088c09f4409e984f7d0a2c82fa18f0488b5bf1b767def1be460cf5f68dc0fce98da0ded6d846a818393dcc1bb15ed846be773d3076e11bf935acb0308f3abdfd30d278cf737a98e7b18ffae8d178a00ba787f91efba867180c0603694cef7d185dceb1c8f3bc0fff16a1c203f328b0c80066e01282a80503aedc46fe0846442d6e516918ec65bef1b885fab8c59daefdb8f5c3f447ae090ce34dc9a0eff449806d644be123d7956f027f446f4b7d6129e88dc0f6471411d7dc17242e5e63bfd813bc14faa2a085edf7ec179b310930573e909fcce7c7c7e7b0b0d9878cd4a3c244b1b47bed7b3aedb937b27d07f670df7d071ad19e03b9957d8d58cdcd7ec526c8a7a10609e9b434d0866de4d3505b390930e1ca472115bf7e8d60caab28f04d0a0bdba0832acf86d992cb9191155dcc0c29966991a7ce4cc3a13dfd50d3b4d73ed3aad5ac6635ab8161ad5956339e1fd994544a29a594728b1439a59c50967474542c57e9488077b4c836adca410ecef1217d78ad96697064063103ff0b2d70e5d37f77972ee3bc2234c41c2296a466aecc06472c3879506c587b84cbbcb23285e6b4414be7642e21de8934b3e2414599948c281be24c34c8e14e1ceefc705ae1b9f8663efdac7c9132d4a0e9c537f36586907597d436f3bb181283a8fb22e54e2fa8e84e2f89953bc3ec756717ebd5fc191aecfc7073a1f826c2dcf83303b77f520ddc9ecf4929a38c7d7265475660473ba8a0d0dd5b8eb8324cc9964c1b542a7e568f67798bebae7eddda3e186d66057bc30c5cf9c516274d28d495b741cb373ecb90af59a74829e39d586c96554b3489b24934896ca5f2a395f3a857fdaf5075bb67519c4c706c43a5e21d15efc8a7d56d8e8eaa09396c4cb0a9c13935547ce3839d1f56cbab1865d24c228a21f958c19c387efcf001fb61adb53f7cf0c07cf0fcf0c1f3c354c58b99648b175b8ab26469e1b291156478f185d111ec46adb54a67adbe246cbf7bbdeeef387a50ab842d1162207152caa04faf7e7ad5f1e303f9e18780ff3c33fff800e955fbfc74f4699c78bb81f4770bdd3f3c87e04265e82929a5934ec9b334a43d823f7cf4cab7d8b05b12122312b252115812cc87b747a01b666739062ab5d6396f05555d18367e683fc638b6412daf7ab256067291566cb53a09a01fa6510d868c88b8082cbc904ac5c0d0d4541dd4ad117e37b4995aad60065a8992268f85148e740a3519eb44d8a7aa718ba6fc298bbc566b3bc6c25844801b461bf39c0fb04dbf0c4a362cddc6c17b00ba1d896a4861bb1948846ffabd244bb77b3201804790e91a427f638c32bac7d59c524a29a5ac4938c91c3233c7088633c6586f6d9cd92ea504a3bb8fb3b33333f3f34f779f93098e6dd02eabdaa6a16ce33c7de6ba0d490f5dcddab7982cd96b65216e1b87637cffd8695a707852e69b78e4cb0844506aaaf801931164f84110165c2c01c0096b2f1b7111e302690b2515eaf2b3e72083472dec005a086531c5ed9fee4ac2b8fe38dcdd5d5271c3d4083c58c282085854713be6091b53495c772a4f14218b201031059293255c54362c969470fbe3111e622d98e18b25a6e0018b1239e4c08b495d08402b41ad5d134d341bb82d311eaa0d42db163274c884ac683730a142aeea439259832b13c2259768d21137380b342ccd242c35740d4732c90957cc614108c96db826f50007166a28721babda22a6d485ede18b9042083fc414343c1116e6b2d1144e02803405954fc11457ba207a1b3fc0c10d9f1505c736c218bbfd128c1c23478e71ba4f9f3edddd9f99e3cf08cecf9ebf2019ec5629e594428610e92211a873b667bb7d433c1e71dbc1cad6be21447ad542c2b01148089121bdea1fb2f1a717256c39c2ceb04337410350105bdc70a508586a200586872d4fba1d4c4dc84087212bb83cf105cb96259e3341050ac228e28a2b5eae1401b5434c18455051c3cb0b103730bae207312760f560861d980650bc9060890e4244b18406475c2c90c116af1cbe60117ae9409b21891c24b2b881881a242185881918d9ded14d846410ea41092520b41022092396643c3cc00450849a50d2c475850caea862124193ee0143a908d8175eac8c81c410b3893351042c08207088c59888c1154d6a745b6c0b6c7f68ab74411558ca50c1165792d8e008ae41184b36a8e1063e40228b11572cc99a87fea8002bae6c21c30932beb0e04760c51052335536115c3f419529505cb96107323882728222c890226025134031220b295390200a0c8e20a1022f576cf172c1acbc002935c3e54ed5ca2a57c6a0580a5a02090f455034115664e99a87c8748976b99994bba339fed96308400c15f8b6b7840d55574a0ff9f9eb91cb201de3ab8909b2fca18a55f16bbc1bbf074fe748980d2b90c0a1736394ceed828e1fc3220769e6c4ae8e8b7fe6204d202efed1d012395c94103685c5bad7e72f9c42da0d2c3f08ba64cf5e0c92e3835882bcd136fd5dd339bcf2c2fe0d75685cbea2c3971bf29117cbb98ece0953bc3ba473289051ecc9ed76981137e4188dc5a2b82177c171c5ea6ec1ed21dc1087b4a9303e232c778c31466721403a9318638c3ca59cd2250faa9492e365b6c102cbbf39b1fcf2fd9db3ac726fd10571bbfb6b8dfd956f6275ef5ec5f75eb67fb6ee8e069ab557ff1d114a1c93c944402c61b22602e67426bd9a93c3aaaa6ee34ad006b34e41d8227e849756911862905addc7905a41cbfb22ac050f7c88b56260268610238756075279214381773af4dfbee7ddb64f876584f5df60604019659411c5f4f28bd27d94d3ef689deee3b68f2f8be312bc50badb6f4a562e1b2949815d36d202e9f6f01cd3672f3bc9f5519ffd346efb88e3b9fa6ddf71fbf6786c271047dbf4490359f1a6bcd8bf39e4e06e713350e763b94dff8c1236e4a31f1468a117d07d47f140a16f75204d7490c62444532b8e8fc585bde2a2721d8c5da489dfedcf59c0124fe3b051154a49ae167c08e74b0ad78d3f9da583a328de689cf85b6f4fbc74a6cb73b449d438f2c1d58d39ab367f9855c98ad116140723ee7c4fd239d9cb0aef44a52a319f82e440c0fcc9cb992ce97031a201c5e1c5374a53908e5e4b4b21ebbe58385e9ee331f19e1c7940c0bc294855624828bd963c57c8ba2f160e96cecf10144e40e22e5cae6e9c5edeb54ba7c5dddddd3dc618dddda94f778f364b8cb1633e30ff6ed7740046e6c30fac8e1d3bba720862071b651307706c239c44b72d58abb0f199c88763458ebf707b4ac1babdb63d7fa87dff0b1f83a19602f30dfd4ddbaec645e1dea63a87036db48dff6682067f083603ab878333b1229b48d101794a5097532ad5bcadb2a86b7927a2aee51dd4f5af7147f3c75e0ef6f9c6fb061c6f68e35bdee96766666666e6c992f9fd7f38933e3066666666698db4701e65886cc8b1587ff8e8c1fa78ad3542118b6e64db96659c941b2725a755ae7295dbbe6e9c161948d3836ff62af0cdc07abbec0bfbe9f6b53b72eb3764de0dac806b927905ca5ecd395fde25120d61437645268de38d9335a0cae0cca0f1fd97759cb0837752301f83ea1c4e934fe3f3f1b5f0f548813b78fa84a8e37209313060a873db8221eb04860c862b0fecc0f039700339c982216b6900df2ce0f6338c617782748c3823ca2cb8f833586037a02d6813da92685278a77ec848b24be37c691ca019d438dadf190e0c35156852f8a689ee068653e8ce20e9dd85bd14621937945dc22944a7b3cb2e9bcba3c43ae79c3229e906a11b92a0c4e87d61fd3b7f61b13058154e0620c5dc2bffa6a45995fe71dc2639d9799ef42fec78d8930723a5fc826c92512c5de6fd0b9f068d4863faf775308c40cc8c2e45a393f15431302a15caaa54aa93cae4a954aaedb5bd362738eb3176d3f8eefeeea0cb65e4a434be0fc5f7a0d839a9a4557644377e96a5525615b3b5d68e4aa9a951bd924af3a15bbbfa5cd76f8f470dab07c57a9406a145b657f4a307e55473fa1a6b512818184a7fba6799bbbb478f203f2dba0118c3fbe28624ec2c8694724e4a5535b5569d1390b4703a5da7aa49a554f6744aa9ac85818189898949c9c8c8cc9831c3dddd65475535b194caaa6a52aa9a544a65553529554dcada946ace4929cdb255ad75dbb81bb6529ad9b09cf5cce362352de571b161777bf0b8d48eebba21eb3e7b82a13479ca761d17dd7b86c87a103aa775f776b7deb9c6715c673dcf33994ca7ee746218989818aeb5eba638f377d5360e43719ddb7d5ad9ed75bb7b4bef097e30a4dcc1b0b31685b226eb81613d306cd8c574168a75073b9fe9816d96e9dc4fd7c1f002b7c1b823b6025b35558dfe1112877c07888d9492ae732ce87a90f864be8c7dd447d7a30f6f8185155847f605e9550585b88d5310035c82bfc037fe4e58187e78a7e6fa0b89364419aeff9c9af070dd456f02ff512ad842db340bf2059aec7947fbe8a1c4bd7fb54aee6efda32bd3e26313c28651886502eff0e5b8c69045e5644a29bfbc0c5ed68db1841b85b884fef0660000b81129f46e7cae1d1806891f88021b3f2b810da3900af14814ea4fc69bc291cb1acb59b23e0dff06648cce72d6edf92dc69cb58b418d13659617959169536a7a0d073bbf67dc21342bd00b86315c06e5d2ddd19ca6c44611aaadedbb8cd676a3716eacfe55aa2f071bfe0ce5f561135d5c8c1340972cfba1062ada44e07a649bf9dcb66994526a81eb1b687d08deee2ee79c9e65ef31ca8eee3e25a5e017a63a63e618dacd871924d6bd57c8ccdccd20b1da0c921924b39b4142bb1924593783c4ca1924d66f7c4eabfe838d1f767703f10e69f619247688cf20d9ba4d0533486cbc33482c6b937651aa1684f7e2e2e643337b1dcb5615c57639a70f72d2acb6367fdbaa6f7163e99aee1cb76931e9dc80f8c49ef8a51f8f8fec495f5a9fd42727e83cd1919b104e409da0c718637cbe911bc77dabedff04cf91eb4c52b26cbe1a5a2a484aab199d9de7db945bcde8949ec98ff8a573f9592b2d4a29a35633bab916dc764d27af276e73cd4801c736c28eed92c51de77d03798e0746a00e64079fe87022ac57bd7d443c8a10540d9baf003dcd36f37deb40bdf4d3d8667e7c2243b1cdfc6eb00253ca96524a197933493a297529a913eac4afcc9c644e6475529db8e6647330c88f13a5e604cc99d50eacc0f58ff3398d3ef79d31486d8322137927729d496788283f6471492a484a46c773b48f400cc4400c04c4b106ce89b0b884827188db3f64544ef74c5d112c1ef5eadb1ba881600d046b205803fd8cb014b8db404e804e4e4eddc6694559cbc060abf57253cf668f9248ecdfd8527db3e001adda0dc58205bedfe60e1cdb9047ae8c49752c226cd3bfb2f94f55c3a2765297ff0883618c723bfea0e2c12ea9b186d52ac6bca418e3979c1344854e97d73f0afc4002e213f3eb5f0b3d8e7866783e4ed0d14161c7fc70a83cd634510cf04dbf0743bc3f4f946850b5a80cf18410e904f4cff024122b6fe468706f2609722b062635a3e3e768a8663a43c9782b80a9984ca56dffa1c0ca44fe18189a8ebf5696cdd1574347ab497901bf7d351fd89a0ed60645c2075ab877ee9d7be7aab0719535e7542d44d5b89acbd4031baeeed378345efdae99bdd5bf8ab2d1abfaf3b3d7fe46c6a1093703695858dde93dc09fab345bf6d25bc19f0369b6edb7ed6f7c35206b3ad8c87a3022c2942b49a64c4925d5b870e631a464f0bbaa8413fb43e48d1f043785843c46d0a710ef643c7c04354813411a4a93f5f7f83768840a4ffdfe9e3652bf9f5b1e055dd0def434f3eb6f4f13c19efadb576e6d200dfd13d1047bb437bd06d2649909a4a1208d0bfef57bfa4fa011effb2b68840a8ff7fd46baf7e7568f6684dd46f6d437bd093452dd464e24155677a2aed83aab6449e692dbc8dfaccca25e4998267682d34ad1d12ce21b94141b4ed886c43bf3e5d665e95b8a2b804dcb95e116bbe14afeaa05c03806e0957c49c13a612bf90688eff3b3f934d984c99f5048ee4abe39aaa5a965ca95ab2e96ae9441199df26f4829b97a44760d02c73642ee75e773a6245276bd925c445db332e14b87a4e46ae3d416a74c49a49414883ba9943ba96b7ef6c56e1797a2df0a692a651fa5a7e78f3f893cc73f8653ca8da6eeee7f538b14cf3175139c4824a4801be21d7a2748e382bfe969b2ef3f3d4d4fffe9fb4f208dfc13d1b5204d06f6f89b4ccfad909342bb74cf2e7fe736b32c7c33fff4d1229912d80d9c48304d6c6dff52bd9abe729b3937f051576c05e9d05394149b8134d9b3aa5773d2d9857b125660e7d32a9df3148aa659a6c64403824aa145da4f97dbcc57a9c00a86fcfa70881aa7ef8c4d2512a6d8fadcd7e7c01952d7eca257732a4da4a965be09c8d2ef7a359fe536b5740eb74c32d8f9d1e351e97c9a5ab3a7aec66152e5cea7438dc3ddf9f4d538593a072646bb0071e78774ca9db4e84ea2194cf9ea22c50d29963b29d19d5f33fab590650ace6c1bdcf9ab2c37bc71e7e45e2819382d2a64efa06bee1aa785d52333735556596595d2a57c8d8c181930328ec2602c1f2f71050540add30eb6ff4464b9676f02dc9f9c586f85ca0561e9d5ea3e6ecdc46c685bfe55ab1e06715082f38bb2fd06f28b552ff58135afe11e79c814e8cbcebac894842a7fab9511ac415449219dbde8b0640b911456968041cb9dd0610aaeeb003e8c2f6374314696abe2c668c1eddb7dc471e37480de17b8579104eeb9410e3f15b22eeb5cd58de2898a4efa2390609880096d020c265a1333a440047dc394095eaa30f2b284972a920a1a5248a1194620b4a3dd5dedca80daa518b4c5a8a2c3a56328490ea11c425936e79c3387cb8ae906da3141f8a29b52450e0dc1400e3173103333771095ab5dadc4e5449228442917fbad0cf6e2fb17dddda95377774a9d3a6da7d4a953a79452a79452a794d214e29dd4d59d6447d330882acbfc67c711156935c78bfb4eb5d6ef6618efc7f574fa6eec660e2539847228f142ed4d2fbf5086d3c2fce9abe7a0fe048643e43d3df733a7b7603d813994c412ea2987500e25a7490484e99b5264209adf3ffbb9ca24cce1ba358712edb33587508e2439841a47490e57ad395e37fb6a2783cde1ead5911cae1cae22535325b8a36c661e04b81b63f420a0a3090cf1c6ded15547138eeb66d1dd4c1f5ff3dee4813a9a782a789f3dd7c4e311e76b62e995ff3cdafae517ea78a263e8ea68a2c3d538f3e3eb60a2c3a5a3898e211d472620ab6348c7908ea1d9c5a9850d414642502c75e19501a5a59cb56adad0b66d1c4729a5d493a64a4f276bdd524a29ad30eeeeeeee3533356564522919198f4783fdbdbd68f494f80955b755d755b187ae5fe5386efbda11ddeefaaf9c35e5faeb9cd0394193880a26ae572237a262e8faab6c6c2b346b4f3fbb13c83beaf100415108806e7b3ca47784328db429a56e4de1110ec46e83617ded63d98155e2206909e8d6d73e158bd153217b1a2f05e29d17bae7be5e8efb4f7bf1cdb48183f014b39103eb3de77d369cb0dd8733b6cb49b38efbaa66ba3b7c26350e0df74aa6eefc393463bcc3ddf9da8b7768dc39378f0737e78c3b7f8604d64f3115b83b80db81cc371c183e43a05ede88ee7ceda3610194604753b12766b44072ddf75784f69d9951c4baaa9a9afdfc1b9d097c90dd26957d2a2e0b9b5da894adf824ad644a680000004000b315000020100a87c3219150248e436df50114800d6e96406850321707634192e3400862180619630c31c000630c410691a2aa0d00ffe0ccab8c9176b2dac0dc7f04b15d3d286aa8ba43390d5822007e77885ee5db24d68ffabe04e229bfc2d5d3e416ede6ac302ff663ee64507444d876a60cd4054849c917a22db79d7ca11cca17e50b79570b5b7a25a87ce19504ef031b48e22e1ab9b8e3daed38048d57d441615a470d6f65b00af3ec903f162acf67517542e73babc83b2f3c4175f02865dbd748e3c00fee0af535a4e2005868d8be9eb4b80cd835aece6e9c50778e16d7a1d247003a7c316d71bc4420e1179fae2c8a989ec4845296d9ce5c1d030828e04b0ffc5eb016f5ad48b11aeec8f607a39ef13c78d657e4f69382dc3fe7768392c47608218c58b0a2a3db138e97d481bd5340f98d72316bee70c536bdd3b399a1f82665c643231567cdb0dcfef5f59c7dfd5e7a7faf63d3abb4a81fd6edc7defa6ec7d0bb380aa2cf72e6ccb8ac478d1c52e5f2d5deed1006ad57fbd8b917195dfeb197478ac48b45ca81ba99e1c766de7b98354930586abc68d68784d4ff1f1708860ed2e9111c73af8b934a64efb6dc257ac680cd7f3feced064e50b7abe58cb6b60785360a77e36a56601cb86b33228a2eff6adcad3fb102608ad556813a48225926356cb2b937159c08296c12440a805d992d6693bd33f6c481a244854038d6ebb3796ab28d2d9b7db3e6f1ed288eaf4037abf67d877a448026a1f16bae67602b50b052f8b502a8626bf0a87bb548f48e41c21c6f328dca5bbc70f682d870dd16d4c83070c78bac1498da0bdd0a0a4b673e94645c9c4969b48f1d35803f85f1adbcf1b0612899efc55e2c8f5623a4eb3ccfee2fb514dc5965709c95e967713f778563d389f303b45d620cae1a7a02cf6331e838d989f3e0a644451b56f17c5c5c1d337b7606c40360f6744098856b3db9063bd61d3bee0862f350f94e9b2ca8cd82e8f1971d8e482889e53b384da41264a93254be41c2ade9deb0cdbf32ab55e61a223800d6aa736561adbc31c33bc3a19622e9a07d06fce8914659b61c3f1d68b47b8cf3d7caaea442c6bf3d4b3791586d6803bb3a3f8f878f5ac6c3dda7c39b968c54d2ed1f12023a7dc21e3a74accc10343f47c56e509d8a28085aa31be809f6f357334890cfa51f483005fe91b128462bbfe49f0db6956ef710e878b76f227ad07732c5f8aca3c0784d73ec248ad38f6ca5af88117cc31826b6f375e07b77fdbc7b6d434922dae40c9c5130d88a5601d6d486ba3f57543e281b7f8181722f601caa6af7899a1e858be5c66903b94460bc8e198abbbc8eebd43ee82297a538c5ada08326f8b8ce045acbaf8e27bf003db21cccb3056e07c5f2b5b8605f305f5285b8f6916156977de5090eaa069e4b1828ded3e1af211825da7f9d0ba55bdbdcdb68c6170dab99c0f4a09515ae557272422a69c02dbd1c6f4bd23465e470129761c2df7426e61223d3651c126ad478fdd9499c00f6948895570d40610db496c247a154ff1101646acd12d5b2e5b1c991ce162951a5c30cdfe279569a1e1bcbc54d71c9f2a5b14a62bf45aa9a5f718a75ed80c70b8b25d2b88820f863128e73831c234894447d0c6e42ca275d85a8e7cae967bd5ac5addd1d0c97b5b2991824bbc368388c97aed14554d925f1ea833387c2a7ca064a6312841cf1cd431b160d8665fe59e41a0f5d4194843ef3d99d41a51219272a424ce203a377e2ef31d5fe618b44eb7dddcf9bda0f3076137a776aa37bfdfb430d7eb0b3a0c75e21150f9589cbed7b2d86a08a099a97579a752e40b53f5f76c8623ff943aef180cf34bb49705595b8b5ffff451c123221b61d6d333c93e479048f3fbed1b84e6631c09724933125e6b03c0317f633849b35ce6d7bc35d390be0df28888aa20beb7569f0c32edef2a3949958272ee990d9242e389f5aea4df7d90688acb62c726c6f69b8b3211411b284e5501626df54eba84e5db979208e5f434cf24c0191134b5e182f25a492083c0ab5585afda80e00805decf58384df5b5a138e33380375cabc71bd9c344ad763d7161c4d999388b9f690e8d4ade06dd090294c445a78d556497a30c3605eecc97ad988bd1053ac2633d2abc8be6b43ea45a004195d2846387d5e1f3c8d2f104608441fab2ae58f0165792693845de9547fc25741366f7ba486d8b1797933aa27e20f1396d38b1608c1b1798ea2e8b78e16bdb591fe4c6dfd6ba90ad29085b6ab229034aed62883595a9c251ff5873e997242a203f2fec87318163db436834388cf1c7823f329fb5608309f169b0cce8d04db9e40f82cae24462553a4872ad7e1dafcd05ebb0d61c5912f25dd4a867de2a15e6894e056b28df727ba80050e691dc532bfdf457b7fcc85334c06d30d1fcb57f88367be1a0e433e6ea2c21a0d223d8d03e3aeae82711993f6672722a7ce9b3ac5c05d7f22131a143f46556a5ba69929abc214d79ce4c853b59405ecae314b84261f716fe65bb5a6b96e7ea28f2fab354564ae997861cfe0400d636e966ca50f49ba948783e4478d164be185a7af4bf3e9cf44e44c8b02c854aad008342e759dbeac9fea174396cc2473044625d70cc83d11d5a6ce2f764cd9f875bd8fcb2725a175cd57ec0f2c879bdfd99602dae66ec10e424fc5cb8aa6e9bbd061beb3282738f3bb39a8811e5a29b5154ea66c05e4ec1dcc6fc49c8e9274c021e75f1a7fed38bae859b5de3238e6ebfcc2b747f62d095c37eb6b0dafbd624b5301da445f55116667a4d34d74bb5f0740cff48ca9da930357fe115a149aea6edd60441528c8f46c5e87ee4a8665db49341e96e125adaf37a5eff6312b6148c929ff6ce2244b391659d696940d75f9be9f722d053b6ca4f7f83772d52176004fceb7e4239bc6ed97d936b702b64d0a827c1a97a478f39f06c249558e7f56a29309711fbba118e018ba0cfb1f6d22862be3252921bca9397b0880cc7dd2a8779ba44c2de6283adcdfcb16014bc8df3135919caa078bf649717075a0f6c227be8ea6789895dfb12a85c96b445fc299b04f9354bf44e870a71972c0549f326615570bebd139b7060eda8875a242c5c9c3449badee9c1c08662748715acdf9fc5943bea9e34e1eff75310abb42140dd3e73276a7135274051fe18955700eeb5235585021d38c6f5c9e41e9b5aa23a343ef9941bfac62bafc069d32f4f70c23c555a22884d2811bbfc7ac2713cc26de02c7ca00c7e574556f839520ccdb10d39c205ec36534ab21ace4e138d6ac34857614ad9931e293911a8e4b2c87111b46b1732f1c6a0567e938b551262c74e53aade99e06c05be55fde979bdd8492e4a8daa2cf82ef67512cab6345f40487676653b3e3dda7ce98f3ff29d5bdb5cfa9ce1484c5d660d1d0d90e1120407fbe537e9d496c203eddcae97f17424c8a2dd8fe808856971c45c336140a0ea24acc54c7b6df655a5c6ef8e44f3df0229ab6271c9c68d9394b0050f38181097dd2e19e8226984e1cbfc6ee77c00b021427274f51139499ccefcc5f40066e3b3e758a3728b1d67204165f2034930b9c963d04eda615f609ff01ca36c16bd0bdad3f7b029916f7b46203ea04fc7715b55cac1255c0ee170c64ff2b5d269cba1156ef43b18e9c8183d3a40687fb6c4165c774286d62a042a5e0109436921ee9063ce2d4fd938043c0ac53e44cd5660e645841d8f5a64009ac8ee3cfef91e27af745a292190ca3ef4a50fd391e7f863fcf562b34b3b68db880a9d851284377609898391c4d6b19305aafc16c212f23045d9feed0366a8295ac3b48b6c8046141a10c1d188111d5de7cd67d48a83c61d84173e58a79c62ec4192808322894e18201cfd33733b3c27c10be90b837fc3810b69a2435d19b24b9ebb202805a0a60193e970022c347291db464b70c2bc2f119fc93023c481d5b3b98380d8011dd3e03c52d9045097cdf6c9d5ea0bdf4673e49a7706ca1c6207fe3a27dd31012720f1be7f5770814a4abe963507c74337587eae014174814744ec48c120b096a182f33f878169ef8a4d4055b86cabaccd81e86b85ffc4139f57304ee5e36625b240fc00bb00d2cab3f0ae8021c28bcd4a4c25ee2c7cfa01bd410ccc05198c42157c170bc6f736d3a020e18a82bc6b46484daa27dee4d81847e418cd9c6075d4a8a7dc7e327a51fa8e575ac9940c9f179c7370b94e920a306df32255913beffc35510ec9d36d871378f7dd8cd95a6d17d5d661c07c43e30cf719ef5b2640dc52aff427145c062ccd26dc94692e01ad54020ab0c2f759670a1847eb8e4f9e45d701d194448a1695d5230daf75644cb7260c86f87c67bf7154439468f731fb5c548123d199e3b7e1d92b6f6a50f584e828bc2836d0539de8aae2773d1c788428d870d006ccdda98f43f3b9f38d471471f4fcb7cb8e3d2d2e93ca74ac701b7999984d721cc7d013d5afc552e62a00ceb1ef1a2ef16b3eb5b10a96814367b283d9b3b2f02c8687231b3415987349ec21451a08c0bd67740ba8f93d09d2fb790e1bcecb56d9f9801eaa1d196cbd241d9a25323c23ca73d58ece798b9a8774bacb9d2dd42265b59d6f5c940354d992bec4795e0ba33f617926b8bbdf59247ca744b0cea638470c7b221624e6004cfc564af0bba1b34625a4fcf7ffd8b28fbf072112e9889796976c37736adf445eeeb1a84d697e5fae89ed91b2172e9c6416a204b9ca68fda0a83fb00c429f757d80473175672ab5ec2c77c54673998ab304a664f8e078ca9af0872b11029c4b8010efc720d35b378a5aa321e2b608feba4220ac028adde00a2929c926ed85ec88c00d33b79044f135f007c91f43822c0da74f86922d66d1b81a1e99384b35e42e1c2938a39458000d7ee00ed8acf80d0672810ad1f507e54aa6d61ad4d285391f61b6b10c6cc53005cfa72e789557d30e9e661de0c79ebe091180379b2b53d42a01aa524501374405910aa7fe5b9696ff5197f64f135541ca027a639c19e224dbe34d656a80f5909b2e129878e465d9d4194be7788430d92432954eebb0caf7573467b89cc9dfefb46c98c66c913b52579fca24fb599009ff3e913217b15de4d24677c25fbd395a35ae254deb5893cd7b9d74c946b337a6526c933596d02cc7a4f85c45c166c6217e4d29ac5f87559b61ac3bb9c15c2cab7178cb6899006eeb84d7a8c2435b9d223b891366b26570725997fdbab8b79d7e890a1c28b86e3693e5c8262a48bb63cc67bfcab7993dff89b00b805020a94e100c054cd7a863c0bf0d308494e07ab84862be3323a9cf9f1fe5cbdc25c6346842e9dcb291373a5a4f30a22d39d005ba5a0b2a35d41a908e02b9822e0c60588d8fce8285d05581936eb43f61545acba3878a1c6fbb5626525a567cc695acad540cc15ce9463a9ccb195d25ab7657a7dd30ba2518452d6b710a9d844997612bcf705d18e30d3d1c244a1b5f602fb8968b9deef00effdd236c1d4bf236190b445b5b2c4bf4f521afab098b2d14964e00bad524dbed11c508788759aff4c7722ef32006017a686a91758e7be8f0774a3c395c60f8324b360c61ba20282f8aa5cc28017542e23436e0684e6d2c0b5b9621ecfa04d4a541d2ffab14ffcb2941c9d42d61c624b1ab152439a72ead415ca705a549f8c28f488634e51b6d62b294f07ae47beade113e8fa4dc1bf94507610c3f0182789455290e7f1494a81795e2eabf8b562389a30acea0e565d2d11b78a2b63c3ca03c17b18160f1f4623e7a2651c7c9c94532f916fa8a77bc1e13597689477d4247e1fd94694d7fc0ac4b7881d4ae798e8248c10b5dfaf6e1c2fd7a45100ee65b4066c645458e90f33afe1bf3bd7f812b3f8392ff7e949f965be4e1af7ad139dad5b292f51bb1ae9c444a457e1ae4394f7cfc6295519888db191f202717588822fe4848c3aec0d37dc09e2cce0770b775c2c80a0d7549feb8e83703ed4e59ace75a3c4288c18d3c797c9a518b186f850f0a07ba5078073428d50b31cdece630fb81c160d18a2475cadb8f8ab631c3abff814f4a21eac9c07f3a1592f67a13cafc7d5ed54b31617acf10d011ea3850d6ab953b7adc010f3d19f4a9ae1b53abe30a23b6988e36bfe56cc80101363496ab304cfe673914fcaf4332bc2e253b5cc3ecfef074a3ed31dea2a46d098dd508cf9bd591f9179961fecef463f51acca7e0189ddce57843994467a00f846066aad9866916b82c5311e1038b3ccc9fabf03f1188027fdbda731943712e58d250df995f7e5bfd44fd6b3509ecf80ba584d9fbaa28ce870a1363d78b0683d31e60159d2533a929c2ec94f9d1d10ba1364400622734a9cdda9f33c350d41d6dc2941e3cf64829788ae7bdfb5acfa90cb382760cd613b5160e2cc47d19ef46197bacdd69cc6d48d12bb3577425834af5c1c94647a74942eac49b502e2952ed9acb0bd99c17ee0a99bc485a03688603083b0e4aa736047c1407da2b396bd041eadaa4c0e76d2229ea37321bc50390c310fae24f346022d659b44905452afa19018ba418af00ec99f1144763fa7a2183a0a6cbcb3d91de995397c9b31b7c14d0b3557fba3d8345412f080b5cce25728f89d04a10a1b125d12dedae34c887c8993e550128455d55f8aec5412d59255a83a03dc81d3595e2d3f629640e9b4d80715f5fb31772642dcec508c2f4b4114bf2e8c9e75f15fdc048c6d36b98ec44926450f709d9cadeefa6d29be099255923de37ade043bd651bd5fcc84c052d013304502f4ecdd45f9383c88ee5a9ba11a71fb2cee059cefcced3660a0672f385dd8333f30f01a16128ac57e0fd21deebf73f1db49fd1e82fb94cbdf535ebdff110af145fa696d6420706d4fc5acb554623b31da44e682a0d3b249129cba1d751cf51fa2dc4e9f3287f5204903cfb68da92e5e1433e3a2c35c1652c92a068a59b3377f28c621ddcd726d03f7854de46c865fb6a15442dad4f272b3b1b0cf0ca280daabbd8835d052d36dc4e6edeb15d1ceb386b6a754d76276dcda0bce60eaecac6bae8803db1b343a2fad44bd5476cf4eb2e691e3d388c02831c6d7aef55f469789895b952940fb11bbb1b75f2b940ec0f28cd098eda028fed5be1175eee5eadfaa35ea97b3d469a5f2292c76e30d48260054fc27b16941da5df8c64e1c4ad0c98b1b72cca81a731aff33810a5206961e71aa5881af6bf909e886ab2af533e66e4c57bcbb49e656556f354ca01308244e849d60704f07dc8d47629193a8084bee3077ff7794da039ae06db8f3784872953dc25260f43d15eaa286d808e9c4ed4c32ba94526f1bc3934b7c654780c5ee2f31ab77e0282506e4c990c71a34fceb5ef122290d10cbb514cb7e7f3e4f95925d13255b0171a299e09b21c1158598ec8a8bc70af77d177f6ad9414c1e34749ede85ff0262722e066fc76d95c4531b9678f1753aa3df20de573ad1a877eb88be59dccf9fc324be522a50d9ebcd5593989a1b49cb36edb1f90cd202e5766ac29c363bf478368eb29c30116da9270cbf9f4c1866eb23a632f926493e2a7763c0a3fad21cf9c26404cb6e0ccb29d8ce82689255a885ec8e5898d4c5eca8eb4bc26bba74abe56d60549884fe48089425e614267b5ae37a1ca6c641b29547dd0993cdfa2b9fbb122d39c4844972cc4f1a4a44f48f0ee4881dd7e681b41f44d8336fa73b4fba0cc122306772b45ef4a86f8449998d7a4573f4958830a9bb9659f7036ac38e9e18c7cde50c26598290454e78f8ffd35c50e2ed7873303975a7f9a97ea3d41545e19d001a0f6f6a2a5696de49f987f614a8cd1078e482495b736a0e2561735e970766db8ef1cc74b51b6851144cdafa3306eb8f61ebd5ca1fb4824b1799afc698c3a135083dc8be25c57842304914f71a212a9656c2c9dbd989eeb62908b0b0e1a87adde9374e0023de17da9fb8179884db62a12a2683806a081f708544259ba1ff2e400a4c4aba26a86f886857ca3498d7ebebda16e862455364cdc322d707c418d252ca70722104fddd458fcc0d48385b46dfd2ee68e6778f5850a062be5ef608606ea9ebeff7a03f6032be54d8182696227d8cec61654bea87fcb1a81e758059aa07ca7cf6d6a45a64bdd963641d2ccf46de93e6b32d4a127ff9b24de2bb1fb882d4cb6ee52c7d481a5522391932154cce1e2cb86d0df020d8783b8a275a1ff371629d0026673b3e4285bb0cf7d9d79a0a057a032643c76ff1df95e729efabfdbfe4263b3941f4222dd630c66d7628cdd61a86fdffde9662ff2791bfe4f7a6f8cca04f94ca536fc35f521636e494c716e5c87cda60a20b89721cd8b3cc55ccd182d9cf95b01ec293924c20c6a84d5fbc4071f06657aa077bb43a2cbdbaae1c6cbc6a6c402a48b4a4c8189af43561b3a2d99e45f80ebe1e40824b26882c25e5829fc63b0f595d673ac45aab2fc0c6c22fb864922214e94f90c025e9dd607479f552e24c5dc2f85c87f748f5df92a608f9c7479ed580aa7192ba70758c981dfc4208263dff6d751ad6aeabbc182da99ecb8f979dfa2d790fde6daf72c6e5136fb1b76466160edda1b764704ae1777ac11b99e0054db236068e44b027fef423b4af8f03f289993703d84160d0edabd99809fb268ba7b772b02859a6b1a8f53ba06c4424de90da3a97cf055ca6e36f035074b5ab85b8ec3bb2158483cb64356a4541c0c5015b0203b084658ac82dd9ce451a082aefefad1bd48e753ca0df361cf66ba24d3f2589efd6f0c304e239b9a824a119604beaec0cf8bc54268fb2a3b0416a70a71bbe3d8a3447bd58683e83874b95b500ecac42c8cb0ac2949b7f4c272d67c5a7a49a117862519c58cd4ea366f46fe77e8f6d1052fc5acc2cecd303ddb953a8f4871f3a3408a1dcf68bb4a8caab6b36f76d04bf9d7a00018c451f2fcc14229fbca8e2be58c1cc4bc28944731d9124f7dc02b5601bc1ed87e5f9b4e84ee03988d80be45f2707ce212f5c78ce89052c0502694e91a93f9d219edd54a919026334f4f068087688dc40bbacfbdb484228103fa24e011d17438628d2db03d85b872736d03471cc8fa2377585c38acae6e7923fc0b22ff8361e7bbc90cc0a2c1c775758a6355d0fefa32dac046022decccd3d7188c585d6b7a78790af160c8cf021da7fc362e4025aab7445fa2aa7d7aa4315dd8243839a9598fc3b60a90d78440c90101362cc6a6420b07b212cbcae9b6110fe554f6c6bbaf669dc9693bb46920980689a77d5f7a0ce312c4ab307a18e2ba8312b736b01477a672ae74cb1de6925797603b9472444da50ba28f1b90e834915dc2e7bd8144dcd8da3f801ca2d1a9882855513953b99fc48d4cffa005bc69e2db5eda68d46fc3bd00241d246b2f798aa175c466a6ceb36056acf556dc254b58d872c270710612aadb9f2a7048a479ad18a34d808e9cdc8e41a48092563e7226c2c1e1fd0cd2045ef71f90ccc5405988d4b2ba5542c56472ec5ff1d56887fb7d65c27c819fed2341c3f9cb3420096af5e6b6d5c38d3e5a9dbd856f21dad8730710aad07e61b2179aac91a701c3177dfe1e819c0b2e53bd068ca95ce17ea2037e2cc578d4fe3975ad187a8beb7e7dfca56a0c608718927f496c243e18dc8954a8973ce7d6e86bb541b4bfe61ec1e922cbd25ab6d80982e6b7a22a515a0f01f409cd3d0966f4b1fe1980358c132d43cf4407155e9495b2adda51c7a3559ca2732aab2df3e4e382454ea53ac6c2ac07413abbd2696c90ae1e6ce5a2bb71c5e75d2071a992a65a7ddc7f88f94157c5460bc8da0700ac4cefda332dcdb27dfae2c902e3e54adf646f0da46f0ea19658bd51c07deb653cb9082cc95fcfcf19f4a6e19cad34bc5377f09dd65e93779876f0a2e63106842957442e9795829667f42d9f032fbee9b2fc6ef3ac11b1ec31d1fdbab2fa8ff80900b6c6e67037c98cc12db38890de9afd696fb3ab4c68652759bfc8a0ce9efaea4cdb73534f8a933703fb975994649f7325036d728305cd41067a0dc4491e4260de32db6e17a9300bf7921e8159dd093578dd621ceaa8fdc23d71e492608674cb327141144982f3bc46376a9bc4e68b7e77aa190570eae84000007718c176ade64e5a59895b6e1b60a7d41a44925d6f38582367b8f63eb3857708471e524441d883c24fd9c3f51f8ff01d1ea7fbbf090e07a2112cbe4d11d38c5564f405de597696ccb2e3859dcee228ee493747ed16e196810e5ae8fdb3b64c4f81f4b5109a7b7633bf81582771a1de2f0bef400d10aac361f017d75e081d4042a973a044fee18b6a8bda988ee1d729494ee0b7dd7b846d21703a5874986ed46dcaa92ea0e82eadb529bc298dd183b0533ef39002baaa5ce6a0d80345174fb760a16a9a11058c8f06a461f5376d8ae466fcecf143d3b35cc12384be9649d38f862858dea067ea18b7cc008a1a47bc123d7ee99d079427644156a3cc8c09d7f804394293a9a1a060a0a586c8f43f5a0f7c85850c6243643823407014d33fa0a09722e64c0a72dbb9fb5e5fcf40348a2f318a01308a0b218b7acc0fd3c3157b1dde8d45d7c16bec5542afeeb7fedff9cfbd2449d4548086af49a67afdf4e78ef33a9041a3d55979928107e2cb60cc83bd9a675f1bad792da471e90bb653ee77b39b9a81b862f5509551a2987fd57060ca53c6c098a2c114a0acc62e55b89ca86bab6f77e8a69e1252520775515529b1bdd6c4b210de8291c7d0394f917c4a3cc0850b44312e00bd21ca8466fbc99df19933d01fdd519593738c69382d417a191b6511db0f75db125a66a0b671f784806dba8acbc4f199933119c8ec8cac15b22f501f58d45299c5f7135c133ab7d2d547f8ad00a94ee5d7a77526db62e950b6090c711536654c8337b68a1e6e9a7151801ef9a3797885e63ee1c8ca3c62faa4a45c87a845b78245f3b4219756e367b818a7716e0b1d196043ca22c981c5aaa7fa79cdd20a248548155361570fd1d2f2c9e99a380764420b8e742c1f8a36b9b81ca5d16006e0a32d07c17cc1f0ade477628b933a4a569572450bf1e86fc2ad17faaa8973f0cd075b8fa4b9924a3d2f2da426b4c93e806f51ce7186be0b88ba6edab63c21d43501f72a42b1cd46efde36953f2a7a745e2d36fae902aafdfaafc94e87f1a59ac8562a4d49af9fb7c64028d7663af1cebb5dd634375ebf17200c6da9b442e0467946a74bf61fe2433a9c2c426d0fd240c2a76109041288c3d0818ffb28145978938f1a9ecf4c08389834eebc39751ba1a63f4d56dd0d4cb907ed00b1dceb2cf6f14789a0f405986a9f68a3892ae8cc5642b00626f082d544185e3041926708a7a13c4a05bb4bee897029a7d7db452e2848270311573399a447e58f362cac51059af16a4a0806cb29500ee36052b5b71d5a6088d6be342095c8d85654d139c28ef1dec1c18bf64269c30d6be3eb47edd21711406c8d2b9a71f81228a9f73dea9bee3af8a3e5ba2ef592a3a2bfe8913cf51637471f467842cbb38bc19ba3db8a790244198d89a3e23c35460025781d2455b05f3f5bd611241d59ddd6a37b1ef7b695f19eff38799098db5fd2bab15c066ffb083e21617cb8e705011fcd88476725f479682488d8e0bedaae78d6d9989d427ec6da19a536c4b89817cd7f765451b1287bc80c45a2413f462417ff620c312474ff2dc2c31676468a1d086585aba0e1d2e8d710d778064154bcdbda2343000e86f3809fd5ac8b616ad57762d72b48ef096b8e4fb095a0b582c0ff68032e300a829e60a0c877486dcaf82736c46a68d157239f25f4fce023421c43bf10dc8b3980b839ec4303d905927b99a5b523b0be53289bffb1d5e5bc0a3fec4e9a7a1f52520a63fd4f697c777a0cc089d0a9fe48bb989c1db8126e0071d80e93d04d49b7fc9d28176d66188482267eb96816074c6b23d97b7633367b1f03ff0a4d993b199273de7904f0fabede261ad5888d49e30d7957c044cba9c56e6fd916858fedcab1562ad5c5a19297130d56c411fc4a18f13a7148a73ba9d5db5c45d2505c95187cfbda79b3c2ef814effb7dc99ed9ca87451185335f50002759b1f94d26a6611ae9525dfc739fb66c7949e4b2c4eb0a7774ae607220f5d973f198db79bcbe793898c0f4a36cc061a5fe8ffa86bfc66abc6e52e9beac085759372982ce0a543c92871e134e7618c4e8ad6f43c25b12cca3fe28978e13c9e359f68dfbfb44a067ee5765cfa5f6627497966b5b0ec8034f8e7eb859ce8ea601c92c75dcf262b3c36387a734a019b3bbc4caa8784ca38f7594ad87cde7e87c1f7187fe1e11e319b2e0e297c9b1d1ee6e6cff3404efade0a953d70fd66ee5e7614464793f1dc099ca21d99a937fea3fc311de1e0f4bd8351faa1bba18e09c6f968b9d4360e6f1ecb7a6c8ac54315de5f1c6a29d6e1c8d148ab32c60d77e848c10ccc73742a29cbf393983c3ce29261284c54f32fca47e0ebf0e0cf7e69a6d33e42508e1dc635499b480a4df9cd7364cf522e7ae2c63279e1834c52f1d9eac4e6e2d4598ca09f72226ed112ec51149ac68a6c265e053fa87e480a1f479b0a46d03d711eb08d92496faffb44b339cbe5c932684cb704ab568ecf6f1caca31578756be6badffad3634465e9b119f59d8faa4d5cb8652108f4a62b52cace3c9c01a9a892af9bf82640e6904380654bf12c947706c1142a6b94c9300f1a7f035f86c9e76127aea575068ebfb9eeb1b19959f4ae6fd394532b4b55c913f49ccce76e165b21cf387cadd367023deb1e51be415475086cf4eb7d74e68e85e4adbece3e01af6af329f77a7608a9d9b4b4fe5529e706c64ad9075555e2600d66bc5e5dc522de0d3c6dd17df6f680db3fc945f14171d9eff5d329cfe405def9bec2cf5664f5fc9af6c4aba73f211ad944c44f4ca76d1364f65c362d420dbdf76aad4affceaeea64dd4222ffd85a3f85b7fdd0fd469280b0337279a61cd04bbb7e9ed6dfbaaa82a5d5f8d31b2d65012b87bf3786c0678d842d8d7bfda5ff595fba8fa81ee009c7dbfb65baa6da69c1a4640add054c3474579a12d22911c1a97169cf9ffbe38227866b32f5e88ac678d2f6bc88658569541a154099c7ddad6bcfc46ddd0c85105d9b439cb43d4c2802cd1593f0b6a820fcb661ea463526710b3fc612a8ce9885591b90c902d3937ade4a02f75c2f5684a51c8db96e4a6d07d7b0d6d22118c8bf75aaf2984a93e02be6e9a42c84186bae221dc71f476a81720bfb8ecddad2947ff06bd3658e6f90fb7f0af6c52fa6edb5b6cd86ef2b8bf1e349401ca88d41b2ca8c721b4a0dc6b39bf4a906958aac0cda36bf06ec263ffed444c90b6ccc954366e5c22fe2ca5e755e5202aad0bbe270d4b239c33c8fd2efb42d1b4ac6f770eb38920cf7c34e671a2c430c3c93a23e59d0d61421868e2706c19d3eba347606addaa9c93ed5b25b32bf97b30a7e1bd9b98592ddad0aaaf1b6d8b4ef35e4d372add18dfd789a82517fe52d00869fa21cb314a6572baaf650f31df41d22342b3c6a6adeb720820e979c145e10944048d1bfe7c07bc016f69813e5c0ae9387fe54c754a8ee29df30f04893998e844c43005d3488e47099b7e6f35f5ff3b4ad994af82f7c0545ca94e6dc96e08926689c44887cb131b2dd24b9236b6910e213f5cba94b4dd33f99d3838b108ca04759938483a9b29000c581e0df21ab7a3f3187f09e151f6e4cb18fc13510b6c2d99c57fc9de4756dcdeb0c651e7107fa18320986b428303af513f762012b61f332d04b0a0b2c21f6bcd08407273dcc1a9fb30a79a67ccc8183270c45b5853a59385a7421010907dcf84f96f38ee2cd44eb2542cf66dfba483fc8b8e052d406ce49974ccaaadce6cd08ff578b3fefd5df5f7c2d0ea9a052a9e3d696b1aea5a42f438d7e0db27d69bac06ef6772d44340f9c90cf7428057343953caf519913807010e3fb7f38f5e3cf726b004d0779c046433719911bd150762c932b17757e29484afb54a5f044ae9d68045228b520a90361bb06b51c169ab08600bc26f5e06ec2c4a30db764e35306a28cfbc3164274d09aa0d98ed945ab0aa8274dbd18e6d85cb819624ea2bd72fc4adf9f10a64d519d74479222035e09aa65c7a0fdde8bfed3c2ff203d081e1c14c257c1d9d11ea8ff4016f1046a8539b2330db4859570659a2b48837fb770dd94e6dabf118af6cf4a4799ff93efe2e9fa655250aa57b5b5677d4c8d27a05b37616cdcbb172d404c05e38561da62eb144f63ea040acbdf097a560bcdb13f61e513013bb6485ac5a0d022cfab479b771edddb89f906a08a7a52828a26233b0be258c11c84071958d98d04ee5f980130b58a2e5f215ce978b54784e42901cbaf0d794688e47d631f282b122b432f951d5ca83f31e6701dcb3ea4f189b5fd05dd979bad15fd889a8e1a8b24074ef0bec3922f2e09eb583d560dfced8e28a1f261c2368364fcbc2f5db4ba139471caa0438f575ffbdc48d39708fe760cf87fe32f1e13a11be830b1e83c42732063c40b23e9c418fe0682e28dbbf62f738f3b9b789b73abd460da3f47ad770815b042210228319e818bdefd5b236d2faec84fdb6165913b55d15ca77b029ae1bfec51598c55b0a0df20ace5a6bdb34a69238409203750383c488c1863051e1e23fe8f9dc6b941b75d8d41a29f90b6b4cab9388265188f9d2a170cd67d561a9a1c746beed657e78a05840d4ccf207e63f1238f9aba01e3fc1191b75616dc057c66da126b43eac67023fb040eee03969c44873f882e6628534c8fc99359c74a509dad0f4c64987733a8b3ef283c722cda30d6189e920a97c61d214a1a8fa7a8f52ff0bd71ae55587c72eeefea104912b4379aad4f74d231caae50ea84f1e8ceb84cae893cb6414b0665c0a1c3338e4c152125314a7fa17f0c961ac010067b612d989f9ca9657645d61d81e3f21682e30525533bc708e1ba72f13e91df2f5150bc7ec0288f2234acae5a71ca7f2bf1abb4e94b79ba911d493077d8aff1816c86ea06585a7484a0e020b4c4b57b3c3b690234f99b0fa72adcd223cf7c15bfb5f601d97e58a0e6d9432c5006d5e074503dcd81ca934140ceb13b9bd2cf1b6cd913ed685517de48146573f79587d1da860d3dae8a2a60a565d04f1e36c61bc61fe580cb4bf15124cb6e4941bc94fe8cfadbb88b718da0b4dfbb468e00a0f21d09eeb574921ac0cbb425227509476b9f4e998743190f05f260b07b026ccd8868f5b5538066119eb68ae4d10230997508f3e5b3f284c9281028ea26040ded82a6eddfd4d829f759dadea2c1a4409664f75832bb1bf7b096df54be7da4596ee9eccc967c183fea8e232a9b65834aad2514d27f2d45b340c1eb0d7862ebf2620fc4e07f04e732be90c81feff04034664073c8d583ccdca5ac0740eb1e650465f3b3401e6e5b863e22ee3004927e0013dbb3d8578e90124928b1e07384908ee546599a4488077dd7c3f60df7cba6ebdb5dae02cb5c4aed54e3c37ae04997a39c9321112974042e34bf692ffb9e6400eb5dc3c6408fb29d525ccc86e14819072108ef8b940dfe8458e02ded7527c7f45a0355e56c9e97b61a5548ae13b7214d6a77a30579c4a3029864c998a09014bb4506673074b5b726dd149a31118f61903650923b906458db0afdc7e0c0c296172ed79067315e1042a86a64738305448722d56ac217100147d920ba1e452431a137a225294e05a595453ffd4621ca07113ecbe842425576c8e22530cef97fa7896e23b181f5a07293937469460f155b2f375f80903f870ed5f9cc3bbf22b68c1b52ed18f79a1f63dd676721554aad9a0cdbf3e29ee8bc178ac92d3bc29a10f051823be3f00ee8ea1508ac98cad1686cc2a573d79998e4297ebab0d750963e87f1caccba3294b2d5a1da04d2c32f4bddc883bc1820db8325ad01a5cc737d01b0fc0002f2c8acece26a6a9513ed0f1edf5289ad33f023c74673e65085b3559a98526440c3d852c3705028182206f62951101db27203abaa2c8ebaa223e7fc6a5be3f29ec38c95303a429b8f5181c8685b595a4da48cf9fd3fb1993dcc4b396539278c40383c973413c174fa54a337f5cb7ca09290a5f49edde4ac2400564e160182f3249a0f8da737487e4f47610862518490c0743eac22f05637bc5501f0f5357802a5ce57e6b1ac7aa4b012486a790abd12f3266e7321a57bd2e24a980d8ba7e8836ae8eb5984acdee6b2a5ad87f80c2ca9da8ac8dabde36763903461167a69c02071d06a12ffcf6bf6c3b16fb8bad8d2311251f80fdd3e67060bdff8d05c2dc31b25333899fceab28d0c38c187ca3aa64ef5e89f5a7b9274182ac2130f9e342809f4f4068a83890606b57e8107732e55fabd1ba7d62343a07b36ba83fe04467eb81f6b1536bcc2dac9ee49cc367c455be6d5bdebb9c9d702030e64ed0a17c96d5526e34668eecd3061a0c495507efc95e6432f57709bb6c95ee843db9ca1514bb8f0668ab01f0082e9e7bd5774c93a2c95c7b00569f01e8dc34bec2d9b2ad40dcd42c600211357419d0347b7dcd3b63451ac0f24c61fbd82d8d5a96e235a909beb4e70b2a46f3c20c9f18dc2714d7712d34a3863c110e5a71a02f12d1110d4bd807f0f60b29c605ae4e54dc90a10446ba46de1052076d6bb3714403a2d6b063fe4882bfaa5a726e5e8c88a0d4a06f5b56243982f6f805887ab43b343e84603dcdd5ae1645b25acd94020a67a60c02d314748a80d45a6fc6aca6f89200464fc3b485a5e95f0721613c6c0915d4b653c5c1b00e4c84dc645dd84de64ade0e4a0348f27be572481bc0035e32011c64350e45943224a71d117a6b92e09e59662b51cd47765e6f0e8109d7cc6d43e1212eaf91839468c92100a6a9e6189566e0981c32a0a7dd24fed434cc21839b4fff4d43985c1b68ac2775c175c71b729223142bb66f550fccbcd42c28acd7fab4149e0ab3fc4553f1404d51b25a5e6821abf3bada145033f23d735e68aee28700705184f5a5067a30884a5c29ab3cf938c31ea3318b14b041e5c752f7b45c2c2dc87ce82698622acfcec3043990afe688123bc2e94d4be1cf9b8a4824c5fab05a24113418385b5c25684bb32dfba1925188b569216953d6072a1086382f9126689ca765ca59625abe455d96e95d6909de2ad713847c2314b255011f46222abb6a058f9b537685f6194987a3ecf82dd404782105da2b61370b532e559096e5ab6d0087aae5af5ef4b57d589bef549d2799c863811f2d8ce73fedd564609ed9d6b8ac546058a1a1a1c43302c7d097ef62d880f658e1787af11b8bd3725b7e0b74e39946b6aa890994d62659cc69da5dafda9643e27d577b0e571124185c4334ce9d56c36e8fbb96541f01602d61d84394311b03c153cce91a814888ecce45ef04563b1127a93f02ae8a63b137c344a9adf548b593a5ed7b0fae39c04140fb1e8f545c7c0e4cadfa49c2942ef18fe535f3431335208e91989230f3dc142757fdb1a408335da917fcf8c8bb20bb5cc46ec132c68cef00ba302b792e0df6119579095e4fc7967794261493634ae402cce3e55a56d51ce6828927687b2dfbd5385cbe1cb52cc215d623553e68ac0098b2e12077faa737ff82b854ef1468d062302a65f49e7c34b50f544911c39ca3db7687bfb3f48a9f51c8fd1d26d44abb4c84218491f83150a507aab022f4b9447705da1c2b29fde6c7885c0fa4c84c5dd6c7ff453ca88f852d30ea96cbdc4b3726b6e683b93afadb3732ed085aa15cf42721d6f08916f551285133d2c014563845fadc66b86d072c737d04d4520fe23d34119594da97d909ca6953c0e4b99b8a05316f6e9756b1e04690a4c226b832e2cc8e7b5cdd75c68e3e05c66a1a5044359f2fc5e91e6e75a0e0dd1f87e3d7a508572a3348cf4c6b0f1c88b1e561d9f51bb68263fac56bdaede28db713695821707304b613f6e8115f1aa5fcc8480dc34fbeb775e340a152984b41b2949ec3adb84c11467e6c8e7b0bee2fdcef4f6d3c4348ab8507eefa9a9c1e6f4dd7700e7e3a94934efbcbaef5d57f119cd5cdc738ac46aa5090d76abcaf40984a424df2acc542b83d168b431b48424add0867478ef62f5a2b7cd77994158784c2387006974715d3f00ed4378371b72f87d0d9ebf3fa6cc5d502e35a7ea85f211f25940215612f5161421f534e828b6cd933048395298b37b084877273c85447ed731a834825653a58f229df6319790aa6778041ed88b769618607062fa8932380ec5eef78803460d8650e2019249cb5b6325297a016f74485500d3295727a355377b85c51d79e236e98127d114b8a6f998bd9ff43f11351f6862d1f438bbdfa47e3d62ed3b89b31961b9e00ad99ab8e5e8c5d656f3821cec7414a19cd39e49f74838027717a6c884db50e67aba37d3a41dcca94ab5bb6ebbcec72b91829169a7bee2623c594e747cf3c7f6c901aab8c5af5985340f491935b76269a83d5722aa12cc4644edbb2cb5063439b2573f263c65612e8e117fec17f124d151430c4b0dddb3290ba6c639b20af0d70b83b033a02dc8a0ca73c83936470dfa4617667b8d69aafe467973893967d4fffae8925219c4575b2309c49987a2189b5e6d2ee01018db081d31ebce5e52271b014d6b9e72919fa67b20a9259d9cd22db74d6c26f0e5d5069754d5bae44f9d86dd48f1a080dc45b2cdc1278cb2c34b3f19b4538ce341d5b4acd29b8698694c136fa832e3ea557ec139ba304aa6d35fa9d297998d7f0278764d9b8384389f2a196f67160c6e526cc1a2b8841f8771ebb460a83bafc08fc8c743c3460a89a3204351846894664f61ed73a2740a58c97f0d6e24f5442d8c699d9f4299c0b07ab06017783d8063ded9dc9b6a8e8245e5436df694ebb6be4a9c44942b454109efe4e87ff742c96b340adcc0d6a77e5d999423343fd99f431cefa34bb691d2ee50e70851545aa19667310e29f4958b4fe4c2de943b1d08eec843648ab2406dde76eadb5802b5b2d4434fb386b90fc94df816b1b1502090918f193a53feb66107db31f7bee57405f87aa11f0c940dc646cd778a69c8114eefc49009176cc47835ee98a0275c7a04da49d4a4833ce64ee21a24a285ff83ef127e30e5c34954d047c4216c19835b9527924c207061b2828cac52905c2605d51d590f13517ea65ca38ff4f757fda77ffbf9f8ba67f7ae06e2a772f6941056dd8721f8794f84a247261f014330bae724487baf509ecfd48a812af0ee6b7621e276d1e3d47c8418c9641f37ea6e14feec14fcd68ec0fe25842e95c4dd6374cc6f2be468006949508e70349941e2132681b29be27c34640cca8a2685f9ead64c5e268e85b5c55064853d399050df52b4d60145e355a9d76763278c84187360371d7b8b81e16d30e08bc128e0bec3f75594b15a334208fad929f4acbc5dafc327134508506efe2d583d6462b304d1f5201fd469fcab9a8d37dd4ee6e35191b4ffc1bb20a1d28ae287d7af9545e39d68677e13a10146989cd43c0661153e83d756452d07a34815080cf3cdee0dcc0f81fd51b6e5006862df4a8431d89f854c82570b14531f82ab3bc214a0cb1c04364b107265ded638f73ee93908bd15bae217c042bebb1fdd4c0721d3708cef8014886fe634700dc1ebd08980aa886bd38db3e8e9e7f6620554650543ddcf6ea3004cbbd7a28a3f3f5f0d2f12abd5b6179c58efe0049485917928de116d8b687649a3c0984e5c7b0a6e5107b096942efa81225155a49944d52e859584d484a0523945fdb6d0eacdf3fc8207efec6c04d298f17c42886469795bbab948d57d38b206162d04b6586d1f4547c193314ed95d3f49c61009c23ca72186e96380c9974696a89b3c304f32e2c8cb0f4fb2a9561d69d72e438d802f2ec039de5e45f416b837409ddc9581032b7c854771962964e42d4aec8d4dab8942bbc68bee390d1bffd2d7d276722531f0b35c7cc8e383da6b6d852892680dae4e4f40818c2e720aeddf7a458c1e4a3054f0df4bc70d442db1e54e2acd385c4e0703192d69ba3457b57435d4954291ed5d5187582c335edefe2be8d50443da637d94e95aa23b7a7cfc5b729b5f162271ba0bc2db0aea2815a5317f1e5b715009df5ca76bf7039e951ed298d49befce8ec61b76067af3be6ad8f0a25f00480b7aaba0fb07bdab85875b0706ffd32cec0a78f0d6c77456cbbafd8ddd9218e5e9df3ef6645beb2011f05a007710d5aeda225548e0bd3dadb5f00ac1f231857e6a545c6163ad81bde7b66ab658f046e045ff987b70202939915dcb95169970024997799408b699bf64db94145806e85324703b0bd56c1ddf24be7e657b75a06d9d2e741158ba200272f60686f1460fd2031c88ebf7d37a33cbcf915d73021e7c5d11c07ffbf8e9f50e9463db9285e97904744e49582e35e7ecbb58a18d2be2df55e760a5c4c24f01b41e8aee7361ed47ba408b0571aeba5461559642e315446927626a086444615fdbcc802a1cb5603d166b9e86d2e4c533d37afb0e0793e463fbc8066ce915cf532aab9c95e22e348b0c589767278e13d9d2a55b83a0c5fa8d290ef2657592cb8d377bbfcd8a7b8bf8e5c1587e869eb7b7e2b7744c042cb371c44c34a8ed5a61ea77f934bca6a1ca37a30795259d1189eff0c39d8f62a5504f0a32ae1845dda45d9604653c8a602f62e16dc6526e895ac59c7211b15296bf373947cd389739135ea2895a7ff334dbb11d64fa4dc2c8e809794d05bb028e4e93df4e7891200d73aaa0a96a4c933dca4b53b215168ffcb3211e7b1e8f2d04151540a78fcf07ac369d6689da31d99c6075eb8dbcf7cb5feeae2ce293d7c5039500595647324f363265d930a9019172a587c47a83e5a3ce016f757e334b539e9bb523fa481ed38e02935c8ac36875d2ef02c84f9a7debf463e3cce718efd093bb72fa449b989aa05e2409f55af8e6c46331ecc0574343aeca7feda47920182e1d0636fb3af3b26106b63eda0112caf482fd0442dc97668f9642e047634c977c061414c2f9f57223c87a91d298f4a38d0c7bbe5dc6d3dadce3cef23aebecd8dcf6dc6f852794c7ef6c71802fd81614db51ca884735875653ba60cd3924f249b68cc44900714ca421373825d7afa8eda903af5c10ebf78bb28e1131ed6d8a5088143d2f410240d5c4391425bb574d54100f01cc246c8f5eada193a402fefa77675e766d279dccb29d7bb7ac5f90c3dff958f008cb9c6650bc1cda76892a564993fff13cb6af821c02ac9339867d4b5edc5dc1b846fee4e8df4ffd72675fed3b604894593dfa472657cb49e12debb5b23fd438c98e75c3a0be8a547eea7c17cbd9fed10e701e133610696cac2e545bca0ff9ab9e56edf10a64847536df6d0953aa8d8f70e5ce1f40d7b878edca7673870d648ed683f2cf4af0eae88618e9cf0ad8fe14b46555ad781d292a5731d800b8c8d8708f6c17b39b0a06e01c9dd48756a6fc9bb07d4a722d8567e1e3c03d48eec858932ccba8d863ace37ad63134461e49a42d65ef9bf94608adf5bd628b7f67868867e9fff3c13d02de840c8c926aa90f3daf33052fce7a1801fa86b6559de6f6aa0b33ddae36bc71a671b7b75ab747901b19d4fc118d320c3d6fc8948b393d7e64839c655abd6bc1fe2c694fbcf8c617ce370724bfe2435d0ad1893d3244e6e0664a36349762f157c84db0c7f1186a4486ed1a2859d640c0c3190833ad73c155678599de49042439cc94a271b94a43d92f46d5eea4f8c283506d28d4a83935e1d9b5d2e683d75569691a53bbe24d15a4394efa3669878f5bdd1aca182cbf35bd68031b2f61573b6f7a1541d782e04d1a4d209c77fe0edddc0e8fddc5342776a4ad975efe666a5e82e3e00e8bcddad84faaf18a2c360aa9f5c71d04307775db3f69337701bfeed22005a2eb94416346d204c90063ede628722b34eaa446b7d8586a7d310f4c77c5026a528e16258614ef741ed6e217a200b94a9e5809a43b443d28604362a5dcf5e987e9a2a8e2720add9d5f4677c21c4150abd97e0328463265e968a19db1553157832b976c5c5fd05a52d15905e65ea926470be4af12d59dd09ba95caafe61565e9dd02532000651b15bef051e4525c6d0429b3aba601782f5f43c04a2f8f9ee988a35a31ebef7ab45bff0c501261cf2bae541c78ff49178df6aafbb4dc0ddbf23751cd18fec069a95c3c985496b9cfd0a7a5f259598e68c7fd94110e42fd1183a7e050f30bd83503f4189324256b215e457912ab108809544e3cd5883eef74d4c7af046e8696a0af5a05d27eb0c9289804ef2f4c7e867a70ea44653c542031638c636b8b71b30646346254db3092405a61976cb8afcc1311066cc5d2356e1bc9d6fc9bec8810148a13ba1ff1c5becc93e3621febe8669b8114191dbd66d99928e2e7ee4bbd740d82e51a3744954b341dc563b5d5327ca6d2db0c0cd28261bc94102daefb7448f68e98260c8ccb4a1bd8fbedd1044bbac856fceec8c6aa8a3e44d5c190e6f58b7c099701468e14fa5f83a3c5a6afac714df8c699614a81a39071027ca441dccea434cce5799286dde7eadb4967d0d4d594475bd365042d4568e65666b2d5760ee03dcb87627752c5107b198218c853e876a399f24a71cdfa515d335ec43a3a797f244acd8c7329415cc693666d3d01623ab998848d2ae3c3a5aaff62992c0c2bc88b7a812b5062b24dabb898e1bb84b1c059de9c26ffa31d8fa2b553c45ccf636369bd4a98739e309b33b2f746e685cbe569d27cabc7552cfb6a0ef80f18106c963cbfff47b36ddaa1d1f83d561acc32314b6dfb57acdd1281ba55c912369a1ae87f65aef7c08cee23062bc93bab00a039f6c0dcad031aedb43b616850c6aa3c293d12ef03c54cd474e5e6940e10ad555d6bdb72594bc1408f81f8850baca7381575c61d7372e16c436a54f5e63975baee1024c6e5d805b894cc66f83349fbffeefd17afca61415805a0f9d631801ea0fe655b35d699744791039b6be3375e3b1b01d4e43c90412d53e879ed7fdd71e36657a85deba2cd97e704c8b235d04eb1d820f65d5d70bb935c1165a0e00f8a0bcd95ef951ad8cdea9c4ecb3daa72ff558758d0331bc871412010118980402e1368b76c4a7e6793648732892b23846d66e755bd2585c0fc4f3745c952a1a090214d4cbe8bc270947d260d55dbc67491509982fb19d976b00299a47007f2e04f6b4203fab759fec7e014c43543d7c4782881b22821fed284227a55922e73dbfd8103fa72f2a82d01a4b46c15b189d16c5f87fbea1d09d6960f5b7ba096ba2039abb9b62990c28a9bf7b3ee35e7e95a015f18f51a0aba2061caf2d33a84f25a57fe554d63ed022caf87f6862b811ef4f39b134a71991b06e6e2d9fc6ee7f0b20c2d1b0c3a64af58815cd6166380e46c8ea59aa7c614c1bc9019103b06a10246f9f82fe9b908cdb6b4604455dad52a42f2f382480b2e0e4a520683f80aa2bd27abb994ab742117393af15a22ac92386a0f0a54bb2a0f6b80050c049706563f1a7912c8a532afab65b849c03119b6cd036b0162515a2f01904d205a301e5835cc50da15ccfa319b25134b3b73232196944d91af3fd1febc4815810645934eb97bc452b4111b746a8468a9f3392a94f7e2bae5dc24a448f88648067d88a00da03a60b5e1eab8316913d0d60c61c09280d242380c74b124ee17a31a50048d913855b50b2c05030a7d027c5c505815a70d1923b63b94f45053a5a645554f76e7292429c929b6de44bd60112d7a7d985c7ee2f19e419cf716c0fd4911ba3524321f41e80fd30f51a4d54a431cd44e9d8602856c660abd9970159fe4a83d42ea26092112d9dd9b5b06a207a007f507f0e5c60e37f91793f8571f62475c0f703beee85a7fd2fc9c71d2dea60f27edd81ee7c0319bd532971166d403fd0365fc10762ef45da16fa81473b0bebf377d6f6601773fe2afe129f56e5e52f90c43a16b0dafe16e7252fd9824e6c852453d94dcee6aa63b2859a250c011fd10688a044a6b332adef4e1239ae5f9c33f3a67fca37ea2f1488ecda19d4a7dec3fbd6990f6acbdd945dbaff5ad575b289e938826ad7d342821fc816491d74b90ca77e9ee067a69284b31898cf69f3db47f7dd91f2ca8247a732c5ee3237720fe394a045c9c37b254a30a457c04758d2a18f10fde38096afaaf6d68be263d5914b5f907e1c71825f48070b910fa4f17f831efe0edc079e735f2ce2ce0e4cffb8306c245fbac712fc775ddffcd8da9a77f326f205c668cf1faa761cbf4dc70f29db4837f13c78c192e2edff7df751e1f70b7042cec755fa91f52ddbf54e8ab859701aec56b2dbc1988e84b241289442227c5cd7320d96ffa4add9b02725318f69e7220f40958aa008542d35a84a615094d5f8abc0ac892fb2a4577c041ffa68ce9eb5f4e24fa4d93885ef4bbf6a01643929f3ef14f1db5291445ec8a048de877fd914522d18b44a2dfa12f2442b8ecebef696a89a60f4d73cefe83fb344dd3344d93c7e3b958f6fae100088024db02c402ba20d0dbcbd20266dec438ae7ba5302458ea75b529b3cdd3344d53cad71ed5473555191c3830dd59b132759aa649969cc64e93e370e2c395782d3cee7571ec107a9aa49aaacc0bc77d8d03e21f7dea294f0b38d1abf894dfec975868504e4a49f57012fea1e9ac99d1d4872d99a6699a32f3b472efd778dd8b63079dd64d4d0b941b9d86c5d33e2bf0268563072034ae2159b1ef72c247297ec3971095e741fca39e4a398dcd12c934999c745b5976f2264f5b18d6ba99be569ebee04bac3fbaae7b08bb5f9932f3f49a26159ff27b9aa0c048763c9e979330921dcfa6c2db3cf5b2d88bbe3648ffc062dddc7befbdd7b258f8e887670778092080a10810a26801218a22294cb0681e2b0f20b6c1e2b510cb52962c7dddc7595558a410c9e477d5d0a3214a8a8ef01ff4c2fb18bc084725294c5022b08d90c953d1d395a72efa42a239dd89d64dfec9f847a79bfca3f6ed9c2727ef26977112e863fe4d594680a4d0d3a74980249317fda64cd0f4377582a6bf691448de6f4a054dafa0a90bef7570f19a064d4490e572060d78035752860bd6a39b2e59d6b9b4fdd06bdb46ad3411adbcd79a3af61699ac6964e6cc23b315ffae706e309ed686ec87f21051dbce49db7ee73287987274e84dbe5a69452bef4d171e84386cea637a4abc7817dee97578f15a0a135c8c27a19944c73731e9f8226fc53b7dd89c277ff2a078126dcc97278a7e88a943cfe3a3435947e84df210518bf29e6f77ccece25f68c392e0a807071c1c625a6938c474a335bcc539e3fca967fc156f47bd322dfcfb0fe17f9647fcc39c07ba252a1e0e31ed547984d29b04c497a620efe36bc5835a8507f22fff53b92347f44d9a3e28ef7b92bdfcbd3ce2a47b13f222fcec9b8856bc0d7ef1dff340f08befc2ebe028be16bd1d23ac56e7ea1a89a6af848bafe12d972d8eebba7ff71c312f14d1d87f67f2f339a73f45bfe223b6c1e2bf08539fbe0cf0253efd192069e5e9d5289c4679085f50507ec593f09b3166cb5ed1f35f787abe0b6f4e91f7228889b79d20c4715da76fbc9be4b6012eb244de167dfdb8f22f44b7f8d79a872241b6e812e816e40eb5827c5128481765d12350962c41085930caf9ff1ab703fab7a25365abb592f7d5ef84c949adb5aeac7cf5bc139fd1533c3dd2d261491cffe8af7872e51ff5e6dd513f88a8f33f188ee8f976825eb888610a50c790a515e0883e9561a079d18519ed226fe1245b31069552802df4f76cb13cbd1ccbefee750bd9e2597ecbd60a28245bb22575a44b6f7676fecdb7d6e69f595433c5a137324ef29ebaf8ee296be6dcfcd777e1491c1fd167f124ab85278d986c9d9b5ee4326e92a5f89223aa9d189133ffd4396f0ce895973731a555fc862bf7e11ff51e2f5972d3e7d70dab57b22ce21f95ad1b39a26f6202fa93a737a1a7a11bbde255bc1db58acd94e51ffd5ff1251b65511645e224489338297ecae6744aca4398c2c2933afe55cc92a56fb25664d9f28f6ecadab2c5841c8f2f238b1aa139d87dd16b150fea142f88a8c2a3df797b4be1ed0ec50bc286286b83f4a6acd6a4ffc95277bf4f77b1373910c4bc696dde69acc0060bcb075be2c7bf0ca5c77884ec049c7ba4c1c81770bca09ad6be36dda54b2dcea7f4a5379ffe4ba867b651ee204201042fd8e0d0e69c73c6a9899031e2408b7287061d7a716e161e58fc8b80a67de2a6210c096fcc48cb1934ba47066c6182e381868637b27b62cc33600b7c19737aa064a2031e201ecffb02396ae0082734048286438e4869cd0384dbd2e63a122fdd9964269191e9d1c3878ff9d232e0a4cd4d82cb7e642859aabfb1644a8e8ae81d7332eb1af1526673594e9af4b26c6c64102944dadc4c1a8842c9987369fe2f62764a8aa25b12353fb86813c44b74464a1b908da63514551373bc85658a922aff1c25835094b4a1bea54d0abe44ed9bc640a3288ad6d0149cd694a37962c06176be67e8483ce1c8f671fbb87dacaf4181f3af5ebdfa57bc65f4abcaab78ce712bae75ab358b1e967df5ea14fb107f7377edf7fc704cfc2dab68af654dcb30fcb3011a3f0c2fd9540f4ec21e3f0ef8321fbff81d83c6cf75f9b7d4f85d40188bc3025fbc64f14f27718f3f4218ab1363d0c7f85f601bf846cf932cc5162717a79a08a30121d5a464493bcd542a851361b4140e382b59ca5cae956be55a69fa5327c26832325cb294ad56d3b59aaed574c944984ce70699932c65a9d429754a9d6a224c8663438dce4ea7542a851361b29a1a7056b284b95c2bd7cab5d2f4a94e84c9645cf2768ddd2b1361309d18322759c252a953ea943ad544180c8786bc5d63a754aae24418aca6256fd7d7e55ab956ae95a65f75220c261331185547d3bb9223faabea928930576706197d53a953ea943ad544988b23438dbea7532a657122ccad892f7034b52e39a2bfb2ab95a6cfe269417422cc9589315c5326e7ed7a5b1dfd2f5dd235ca5346d397df2786a802f222bbc82c2d725465950644d377b1e261714a69294d9fc5c3efd264565c2c5c2e4d46d36fa1b2a5ac74545629ab958ea69f5768a22c85a392a552b25496f2526428d929ab49919d50b213ce4e598da6ff2ab0ce95c9a470a1b85c998ca6bf7272ed4ae764855776a5a3e9b308591096c239c152184bd99cc2d1f457d42ab1530d76c24ed8a946d31799d092ebc2643496cb755d988ca6afc20437f5963977a56357ab958eca8d3888a641fc4be1582ea7705226c529ffa8eb7baae9eee99e34cd35ae350fa7cda8f08d7f58972c69a72b1361b255c4f2ee3a2ebb34bd321affe03c2d48b68a305a0d600cfa5463759acd0d600bcdf00dd79fec0902376509cfc8117d97760d739ca4e51127456ec649d8977278faf80746e11a277d9b3cc9117d2953a7936bcd460ba2a94eb2a415d1543b6938da49b3812d547b82c06d992b73654e64afa8a2d9e3190f801c6d3225676449e3b8997b39aeeb3ea5e96b1f4fc2cfdfe3591844d4425c1d84109c8ee1afd9c8920647aef5e0445fe84d3c9302eee21927e11c9e2a9143c43eb419361a239e99614a8f3350cf965562a6de7eea2d6f0cf88e7ff45f3c4fe2a32cab30fa39785148c489ab22fed18851b204219e91a5a852fda76596323fb4205e922939da341b4d5fa6f08cb4913251456bc678467b5e323c9e80dc0c29c2a5efdf2ccb340df34f520aea6a3ce59f949f43c06db7c99ee29032c33cbcbef753340ddbb0d98518923008e7dbaf1afd0c9b221fe8672a18fd2cab605ae61175dd214b25b6bf9e12a7d761fb69134495fdcd6e7631a791239b204e925a0d305516b5631a9625c03ff9d1937fb1ecca78b725fcfe40d43df6147b8ad5a716c78c3485565b0ebe601b16621bf735778f47053095faf34531f4b15cbf661e515b9b77b8a99a61b2d60cc70ffe8980db8ed272bfa3e00b0be08badd63ec57af86173cc836b3f79366d9371f3e9d944689bdd07f48fc2f8eefbefbafbf6b1c770807210f3079c7f741bcc46abafd55a6bad15be7f0c0d92b85b6bad31beb5b6fed5628c31d6df3fe84dafbfcfaf3b689deed98f3bfe9d975a69ddda785f7a7346992d40848ed807ec77dcb1636687d683eeeda8015bea7b6e38fa3731b2ce7071f9beffaee36af8573f9ab215e53eaf510cc3ae7f9f7bf7e5bc1ff4c63c9e1a4ec2ee6f9ba7c334b0d270081a0e2962476b3177b2747d84fda7b1e7f27e8c7af2be794297a7e4e9ce0e7d0f7dcfe73d1f0de4684e5327a940bdb1c6b0df1bf47c3e9f1abe6d52d36d6e2234910a9410086452528263ee53cf85a1e2f3dce7e9f5783c3e9cf69468fef13c0f718ce73f9e0f473f9e946d3a89528ee33e1cfdd08fd4d0e1cd0e262f1f47c9c9cbd7265173d807fa25254f6fc96b13afc483737c9e3ec63137d3ac795bdcb60d031ed4ae37065cabc448bd33a0413a6a4d7a8452eae9692cb608b78bee39cc47f2b18718864dec334dd3b4dfefd21bde783cefc1363c3db4583aeef22b785a4ea259e5f3d507cf539a553e2d27a9d0af2f7fc3319eff64159a69defc8b7488a8e3bb1127edfbdccb1df773c4cfe7358663ee538fd6618dbd0cad70c162c31e7bede3b9f6783bea1c1e4d633e9a96bcd49a6f97db600bf6d80738faf63d38c7a70ed980110db1a0e1100db8b4c662c366b81df5ca868180b3bfb9f7bc1051eff0bc7dcdf3083d8f7a3c25796340df4c3db79582fcf3bca67984daf47c3c4fae2157e8dd4597dedd0f7adf6ceb6ba5b634bdf01573ecdb5bc23d674dea6b35f427a13f09ad527473be9d6fef7f3e7ff2f993d756b693b7276f43a14701813e743fc6df5e26474323683864033a5a1b657c43934186172c2d5a781ee4fdb3c068d9227ca9978b9847d49f508a0ee5c453f1ddc9778fe26d15b9cb338517b5877d38f9108435dcfb67b162450a67ed6336140aa1a8c03a428fd2e11b36c724336c7efaaee3b85abfab5f2beb06b5e70c13e00b8ff8cae958d588937252e01cf3adc7137acf495d3969c7c97fbe7ebdd1423847bcfff90f08c79cfcc7a2e4efaea26409ea70395409bee15a84f220949f344eda61ff04be745f7f8600bea84891f22a547c0a6fa7a8c89d177509f6c1fe8907f5b62538c6fe498ab729f21053a33c8f8f46f97df5893e7994141f77626c11beb86cf103dc47638f8980c31e3b717b9af4c96b3560479864541ae553bce318944f918788fa85881a25bb29044328281ffafa9ed0631c8312925be7419dc2831ac5db273f5bbc631e51a37cc843c97a839e871df3e45fad0f8a3ba71d9271d28ed083be3e06fd866342a01bb618b23475a0960e39c2c42980c21c0a3d15f950b3d08f165ee0024a29a5b4568a824929a593ce39e79c1306dc9c73ce39299d343f341cc2011f34bede775e0ebc341cc20197761c77a6a3898e29fe42a9530faee843192c3f23010a802fb03e952828028bc562b1582c168bc562b1582c168bc562b1582c168bc562b1582c5611e29513c34a6284a3d7131a9c1f5946b4341c62448ed67ceb8e9036cc061261ae991cb47f210cf0a31b80a31da249e828710f48765efe15d12050de33a5a78cde3131c95bb6f4ca0aad1c9610cd71794b1a8d04b3b6e06ae5783c793b4ba798b851d900d1db96b79f744e175eae968eceb2f843db5618765eae7b554b60ad6e2a34a2298d8b7691db2bd3f2b7a6e1832685b931067c899308fc8a00bf389100472d2ecc26789d52433c6fa60a606906027ecf171ce0f79c81017e4f1cfce026ef2fa180a506e8f83d8b28c0ef89840fbf67087af89324c0523ce5f82d9d4080df920a31bf651670385703588a363cfc963ab8f15bfec0c66f29841dbce4fda5076029e60ce0b724810ebfa50af46ff9821aeeb9022cb94900bffd8900fc762800f05b1641c33f4bc092a7607efb105e7e7b1272f8ed4e98e1ef38ce02587256e9b7c780f4db6b80c36fd7810cc751c092efdcf0db8db0e1b77ba086df4e0217cfde3f320196244a8ee4c7f81da340c3ef788596dff1090dc3b5ef773432fa1d8720c3efb8c40cbf630fb47fc4012cc9951c4996dfd126c6404716c4f03b9e40fbc710c0927cdd77acc5efd8231aa11d4601b9a0fd27004b93468ea4e83774adf80da30099b0e21f035fe08b7d873800d08e83f6160dfafd2ab4976877014b932542b7e133e44540def700d900336660373af2be05c89bf321f790f70a469323ef4b80bcb9981346a3e5e3c87be5be78c8fbdec89bb361f3d2f277b091a5bb1a40de5787bc391d73e4d7c87b455e9400f2be01c89b0380e9a2b47c1a79af48bb0393f77dc99bcb21cfc87b45beb36e29efcb915838b064ecc8924ddd90f7b5216fae06df91efe2a818795f1af2e65a50d6a4e5c358c952cd912f59aa3672247f86bcaf0c797323b9aa395afe275731e47d5fe4cdb9902f96bc57ea89b6c87ba5cb79779c9737f7349745dedc8a7923ca7b45fe745195bc57ba94bc3b8eebe6bd1c27e9cca6332b7a6326317cc7cd1ff3076c893750c861ad7676608be7dac473ad71184d0e6c5218ca8811d8125f1808b01366dab1b1812dd135b7b2422b87257bc81e17e503954dcae572ad6d3bd70477e69eae090787b505572bc7518e822d71f35c6b598a891b954d92249a35d915581a3b634f39399eeb2ca70b2f572b4810d8625384d58d2acec419d8125fd77aaa4a5454a5a9334e00615b61d879b970c016d7da542d81b5bad92c9a05b6c4c75cb0455e213bd1202b220585964f68f91e2250cff5f45c632e1a17a7a4e16f2091b3681830d84d8c2165c0973ddd5d47fe74c73a668e1e87c0f9bb3097bc912c93c676b474ec157f634070c14cc0d14d067cf107808670090de1c641c3190eb30c1d1f3301173f33405c40ab0921142952a4489122458a142952a489269a68a2092244881021428408112244881069a289269a6862c7a5b99674f90f3d41e0a07f97f5837c172967768fbefaccd7bacf39e8fef37632e8f95bc27c31c6744fc28ffe95250b3ffa2b3385fc68fae9392489978eeff74a25b8f8726f3a460f0d38951b54c33da38c8ef97910a16f4418b1473c7996e0e4d38faff9d2f35d62b7d886cb1beeee237869fa8179f80d7012f71ceb725cd7fd579233349ce4912e27adf66299b661cf872b99375a3b01855052742a5254442b58acbcf7448b0dd3c48c34f6e11f7d962db26c326593b249c9d4a745c1eda88a425c7bb1c17831478ee8735e6c4521f146a5b28982dbdae9e4a41e5e8279aa822f9a8d66536bad2fbe5619eae86badb57e5feb8cfa5f6bad75e56b2dd5fcb5d65abdaf9554455f6bad55e56bc5a1b2f85a6bad2bbe5619f5dd556bad29bed61b6acad75a6b55f1b5da50415f6badf5e46bada1a27cadb5d6d0d7ea524dbed65aebc75a63d4f8b5d61a7dd0506badb5b6d43abf967ce5bed65a2b8c5a6badb5d63a43adb5b25496fab3d607611bb5858b1866944838c8b8c1861a5c62d0d0026386172c2f5864088dbe185eb8606971f22bff26d973bd6bc55522da54563a2bd14a65c5b158812352f97429de93a2a24b8141ab93ba5aad36141b4ae1804e3493558661595c71d4f5369b379adeac74b25c82711c37ab76dd4eafdcb59e5aed745c5d7b3c389e952cbd3cfd8a7f601f9806c6932739a236f045f250e325292710398308d198e5f14f1540982933fa3d57a0f1cf1ff0e57bfcd3e4a5793a9de6cc69d22471520c5040985943fa2dbfb0035f568e7869a6523a29275248729cc422091066e2e0f05b2ec1087cf1545e9aabd5cd6ab5922c8d5f0671d23f7e590308337564fc9637d0f8a50d7c5179fcd28797a64bfea8c12ff14b0f40182a73c36f09028d5ff6802f2b5e5ea2a7d3ce499a4ef2e4849344578030b4c686df8e058ddf5df025c5639a4a19491d49e9ac9c84b20484a13835fc762670e08b8a9497e86a65b352e1eef13b0b200cd571f9ed2ed0f8e4f1bb8c97e8eda1b1cb7dfcd0380a08536562fc8e6148025f422d2fd5d3c9757a9d768e3809c40408536b68f81d9ba0f1c71cf8521fd7540a2755047f54451c40988a1363d096df31071a7f0c025f4c1e7fa4f1525dad226a95c21f61fc8e23d0f86308204cd571c9114d32c36fb8058d7f0210c6cac419f8121f7f059c943d7e20e0cb7d17d7fac14bf624475486df9088c61f03616c4d8c413f95a22123fb41ff9b43c9a1bce5ed493a93f6fb66db63f8797c347edf2e77efbd17b66e77effd19feb9fcd77de95eee5e7db7873aee762fb7e9cf86f16f99468b75dc0c01eda7263dd9c31301b7553e1b738e4fcb1c8dc49c167693e6a7ed48684d47f67e822f3047b6bd63188661d826a15ca1a6f6f83f2548f4d0f8fd9444cba0e190134bfb4bfc9e3ae74469ec35ecb1df66f47df9f2b3aff7fdbedff70b458f157cc3f38e2d4b0002193b82b332b0bf1290e1237f1ada1f853a128386ad7a12c7ed4b1b9554018c619f7ab2c69328ff2c6cb18f7992c6731d77ad405b277cf440d292129398942ba9310cfb0861e42ac6b0db639ee7f1d19ef7d7362dae300d0d770e1a638c317e8c31c61f8c57f86938497b0ca3f1e700f1cf802fdb638c31c6f831fe64ac037f30fee00ff7f6f3bbe43f1f6f05c794e421a2e65a7215b9eb1f77777777777717611beef156601df8be0abe71dff31a0d9807b574777793bfcb1558874b77d8d2a961ab618b36a2a4f7f7fc9b1b20c231330f1135cd1280804bfa14a2a06d986b366cd3755a2db99a326eb5b7dd0fcec7eca1edcb2892c097ed4b9115066dddbe9ce874387944dbc87292f5c77f7f7bfeda8f46ecabe0184fdefef8c68efb9e77097842448d3304b023360e3454ee63af84c9db87809354eefd9b630d4a021e8093b7bf7932604b44c9d2499e3eca2a5410331a41a2edfb4324fe59087364dd80619808c3b00c53f1d88dcede5f236dd193ab4ea4a262a5cc9f8275cc77a902e7982e232bb2228be5268eeba49b222bb2dc84656dc696036a895cf6378c1d6d7fcb70b92c3931c730ec66d97b1e22dec0b2eebf2963cbf1cfbe0c1c33d29e1a709a8cad7af1e4d1e44d0f02fed9a79e041e005bec3b00c6b0b19325207c643fa7e5adae9b71e68426fab811064e7745980538697acb5bdef296b76ee8de96564f36bab4653a484fea979b65d80cbd73909fcb7fdd4b96b672a50424ed0ff4fb438f92e2e5e70061a096305a7e0a4fae7c641fc5830ef2a08fa09b78d0471c16c2f2b6c2d8cbdfdbcbdf5316715236c1315b1e226a9cf783b00eecb53c44f4967f767b8b8571e0e6ed9f650cc38698fa3e8f8fbe5f5fbb99123a7fc45134bc14519fcb7f9db5f6a5113a48993dd42173c663137183cb3264c101847b4ce228ef616344ee78bdde0c8775481a54444554444594fc5d1fea191c53676cd2fef7df751cb7f24881dbd15b517b2dda879b07ebb8efa8581353f0056afb18e7b8ef7b077e7f6fc97b39aeebde7a2bfaf08f6693abd5ca7fcb712646f3224df4e15171db4dda7e03608b852fbed1b08ff32a62a3e908843f033302c7496511d8625f7a721505ae7eb4ef5168c197fbf655a828299110b678de40b064eed73fab651d5adeb63f8763b2f71ddcb643cb91c63f1b7d60477071e6da8f3ea211ffec663fd23829b21a204b337ce47f73575c4e0bb622cbdf3a8813752c6f5f93b16526de0cae8b2cb98e8fec5b6bad4da2ad95d1d65aff9a8398f65d078b9199cb9b7ff661743921f5d869a3390f1b244104468cbcc0c87c2925037ef430e96cf3d080db1c948153081fcd87f8c605e29f66ab6709dc7695c6f1f9d8d327653f75ba2352753bbd8005d8f78fda6fa922ddc097f8f3b5f8031d7d90bfe5f85ce524958a63e46fb5e6cd135d5872151ccdbfd1f337367f97384beff0f7dfaef254761b0d56ff1aee790b01b765cb7774bcf4711269cf1b5d6f56264fe2244d06be6c46c017ec79ec6d0fdebca8339c496923814895101fa9ac7cc5fc7ab9112fe2381ee0b654e9d7cf974234e8c99744e22357b9e611c3a095f8a864e993e5bd5276f2ff83db07b82d5f42442d7fc8d64bcf49035fa0f69d2d91e0b6a49134aeca23e0e010234eaeda99d225f423ee2a7795bbea2666a4839812897f734f1f7abec3e9c3bf295fb0653e12dc0ef94248959e53b6e468b6769cb443aa84481cf8b244f5f6967794291ffca3f697291ce312887ff365969e2370db537afe7c9972928aabfc03e22415cf39f27c69e324f9f59fa51371a04d6f29c4a7ceb37422776d6e0ec45336dc7e0da7f19793e63b122715893498abfc9b9f792ec41431117012899376265ff2896c27f38a7d70b7eff107f40ff354b43c3dd2689f5147254bf2f59dab5ef2a38a9c9bc7dd6f6e807fd7bf19c4d4918607aa39ffa80eee9bf3c19d477dce4309c2d91d3c76c8ceff6ea89526747fb93cfd3b82d394735d9fc6c395ae73e2f07ac041bf86d37c834a1c4e82af02de3a82d283539b48f49c73c239e79c73d621477c7d1c4efa1e3a792fc75508b11470f3a585ac283a904416727c4c8c05aec35e829c8459f8735eecb518edfd9b81d07173d2023474ad416fbb6c17191d4a59e51034c8726784516f38347cbb353d3d4f995d622210333c0accd03bb4c7af45896346c6f907fa93161ddfa484fbcf4358c27014dff320ccbb776e2f3ded4fbc1d4389b73b4f0e22e6ce1301314343fa2981db3027ca382901fed1efbfebe05f15983fffe8bb58b1433a4a158c417fb7502ccbbe7781c83ffa54251fca972a19efcd892af28398580f4464594562a1a77ef21384fb5a1b2efed924afc989a3ed4f6c63de649b866d788070d65a6be5f45865ad1efbdffc0be244dd7eb751f38da8bb9bd9a804ccd70b9b9eaa9a110000009315000030140c074462b168988599a8e70714800c8198486e5a1bca932cc8910c52c6104500210000000000002032533500819a244309f0b0544a8228b654742aa02111537474b1f8cc7d87a84e3f0b706ccc1b0ec8bac01862ec4bfff4b149263911ab7ff72b095e2e26069fb6246d7e3615134e2563e6b5929604659317243dee2c2e70eef5dd0ac7cb84340287a63b95e2a1a69d15107e28380e926a0e910ca11a98142789cd5129cdda890318f638102f08e1b360ea2eb5bdbc5e8d7ac0c362282b796f07dceea2d9929983ea304a7489b13d24af6ff352b0a749d31e80208f94777f58aef39dab5e13a5814d9b742de55126bb9d4be05d232439a4105c1f83c9300150c118613dab975dbbf1642352489b48e02fbae7cbe7132d1e575db8a266fef2c1d0e4000d697134618c79bb871b22a194563f3a71faf51e8436070c82026030a57e7c510600d2a24276b340b241eeef29a5d314db36ad5d204c377b1e0ea011b65d14ed90df295ed3291bc72f2be5c064841729b8f78575252132c59a2fe42894cfddca1f9f2c4a0eb1dbdeb41c9e61413c1a521bf2ed68a8ed0a3478cf6832b99a1beaf10826fcbf986af4377555335e70a67978cba2474ed0c09e05125180040622edb80781d833373a2feb62795183f75f4c6d6613e4f754ed1a2e69aa7548b52e6e74fe28783bb410f7efb0fe8f3d3bf3e5097d195de649350e5b7a9f896f6e56ffabccf2dd5ab8df42710123f54671292e76f4e5f9e2bd8b70bfb4183c6a15afc12cb60b938faca6de3a23bab5579f985a805aa1864db5fc9458b20989b9acc1013da97883f0404842c4341e45dae4cee3068bba8b63818b2a7a95166cad62fa632e2de189ad9fb084ff7fc4fa53c3e0373baba6f73148d3cdfc554292d5c86943e8992de446170f0797afa5161f668a8a57cf032d5e6b24aeb6c8711a8cf98e0fcdf154a432283b3d9f15d85b46016215238c562a76ad46145d5fd44f2a54b487ae8bb57051b960d90a8ebe7b223a3956eca62195c276ddc1a072a8536d97b09394a10ddfd28aa4e07a145f9f2e8febda44b1c6f62773756faac7155afdbc67748bd6ff43449eb927e024ba24fcf9445f1de672deff6168493019659f924de818041434a8f1648258841d7fec148adff8749f97fbe7717533a1c6bbfe25aedb89ce5d29335b896552113e191bbf3bed247bc5a5d6f317f0a269fe523dececbdab59cf735abbf51ae49e00274de880f71637501ea5faf696975598a1d264d7a5420255852f36b810e0b17deeb8814d8865850508e993bc6ccd0fc89b10686ee9af20de60164d5bf7a233cc1e48f5352d28b5d2cfe7774b08d2cf3d69791d2c4c71b442822e180b0b5a069341590593202a459315aa9968499c961d3dc17491131ad63ce6e39eefeaba6fe7517d5db7d3524fd7ace008f6a8da40ea9af23bec791938b3a076d2b0d629e413569843e2bb8c99c54732e26ae61b34d0782ed03f2218977331d199c2e7e449d8ea77730f9efacfdd91881bd1170d70e4d542b7a213b975036e4e0a6d748efacc850a430b85443f761e1e15876ef8fa0dbf60ab544b951b3bc692d503caf38fe2aa9a3059ae1cf0c9ddf485fcaa1ac78dfa7e5ad2ac920ebdc85165f456556c66d08ac494a7ea53e38d111bf9b9c5a934055e6cbc8d5d5561fc44253330d288ba659efb1a233199520ac2f2142f1851c3b21ee04f48c3d56982f37efdfe96fff2217d2cad37e5287bcb3aab7081dd3eae45e6e5ba49fb02fc873d8bb21d90f070746efcc0ec63cb3cc967f8b7c032af7c198ecec73413cba1a31d29531db804046969e14aedc460faf7ac8e91c3aefa465a4f221660cef8e58b7d4481b8ea6e0429c31784b6e5da6d830072b0e316606b3bbd5108c0f285dbce02204b56001eff7b8637eda032a28972151d529170f87f2b4256565d5a3e2cc7ed4248f27f705d5ffc858ea7494a57f367d604cf5f32adca17f3c9bff0629063de91d4b8ab542c841bd0fdceb9c06a65d10e59cb255d80322e17c4200092847c81a2e0b302e472fff917a541030d0cb806b85d370f547c5ee1dfa2dfc344c02b70e4ed068d127d74f59098f3bf98d1d240fdf43e92d6f73416916e2de45eb1b1a7836f02a9bad7a46ed12a189a5b781e79d43f5dff95fa3bac4420fd5461c23e2865af7d609a331b537481ba416c7ad7276f9452b5a970503c7f024d2668a60340268962daa07a456f489666c1f665ba74858fc82c44806d66aa8fb40108faeec422034267573c720f9f52c78004d35c99be3e1f6bc814581122488c96d7b9f03f8785525327f7c0f01cdb58715b970484fa3591a35cb3094d6f18bc4548d1d065490d93b12f920acee93d91d78b864fd25673ccb245b9d2a88ce5e6af30decdccb3a7013031576f017e0ed583905cfa143a5e14f6cf470b0142a59810f5359ae9601834ba0b57d0d92711cf983c8c9ed05b9665a6254201b9ac1279874c174702313c23f59e14cfb116a472d22df611b53e76868e54aff6c05eb4c5e7357f4af0eaffee8fb3c887274d9513341238180bfcc949d3695ceaafa38bb6c913586e783df4b49a9a5204af522428ef95a766b8e4bc1f37fb575ce2fa8bac6e35277782d2937e3876e0bb929e1910f3ee7ad7a3d079a2013be0956616fd131aa17a312fec92dbb3177df88a0c4698a7454688ecd8ab13355381924a454a07561d959bf88c1c6a156b2ad4ff617dab32142af4520e451016e0ef28a3e7d6997570343a4f398a9d4c626b45286e1005a089cbefac12bedafaebc0c5bd008abc118efca299d2085c9b61919acb8d811623d8f1d0cff3b0cee5e9bfca2c8c5008b048aace79ae515bb047d76456f8792d7a5af57bfd9371262e0ebe6e0f127e3d2f09856546063dfedffb5151cdb33c5b5f9dc0268f4101722fc9dfa5a4c720a38410a60dc94db6685eee8b48d905de8052dd38afe8c536ab028b76963ae8cd082da9f405a22add4efc5f04c010c56c35863a56a75ae7794b6c0c215b4008836ca7649540c0ea3bf8e815635bfc8f9fb3127155e1ae6ab8f55709fdc65cf264876989e9b1084abc8ad067321afa4b9d924094d0d7f2d7a89ef49c09b8cf3a41db76514b0158ef9a915000f380a0fe6bc28a0cce7a2d71ad60ed7697114cf25292307eeefc88f19c49ba2238dede05e204f3e58ce8719dcb90278a3fe64820889bd0fdfb6fcb4e894311525b6ee01282e1cd8d05f7800b7453281b28b9fc0b04830c99fd560539d866429aa56056485e5eea23f31b477aa42efbd2ff0f43c6812975e09821e7edafb01d40504e378cccfca62502d6ac415cee73c2fb265a3c43cae973e5b6b402ca61d94d89535caba5c235885295545ecc685a0cfedbef5bffeec15ab205f7d00be97ff454b7875071d6af013aa8efa14c33da187e4b12441272cc1484e6f6923a0fadaab878bb1c182e8448700eb2acb301681bde998aab4e8233786695793dc4ac3bdfe73936de3f58f44b004a3392b15d550abb32a2dc98d1f82e5e7272e8d405c93c0f2efc2987822254d2022f6f5b692d2d7652edeb68cf4aaf117813706e29204053a476e518673827e13d20f59c4fb38e353a93878ff2e47e89f1798ee89d6fe612d1f9d0b8eea89cf3467594a7245b09ac7b69b1baecc05bf017cf5485f7308d2185b8de092a8ca5206677f70721b6f82a48ca238b6b95e21fb815a9b86852f0edbb0dffc2c8ce67325264771520445989fb5599ad1182187781aca19b3deed910c4f6ad607e56342f92326d684a349f626337713f1db79212ddc9b25705cb8348cf3d7a42e9c58ce55b0afc17ebf15e6dbfcbd8e0a5b37157572f39473bf7f1878114110bd029b7f7ade49955f09a1c86702ec1601439262bcad592bf6b50c9f081909510006ee4de0a0b52f81206d18e359757acb1205e09815eca89cb39ec8bdba38bfafff338b002e3b37545315e0ae20b0024825199c79e28299f41a43de1117a8917665d1e5f3a3274025a24ce74ba310d66ed2a43972e8283854351485ff0a0938cbd9a96fb9ff6c17179093be36ff6cd683d62aee8caefb05d9d08efb617299dc04658775d836b9fc0209abf4d2e1772e52d20660387082bd5ebb36ad19ea0fe372c323eb09cb77ca2159bcb56b7f0d08413181be048107e662b56a7c1d168ca9701a6cf4ad488da7f61050b3740889700ba8e8dd8bd1a1f9c2aba19f2c9242af4174815281f89726b0adc014a2ba94ecd676557fda6002903237b23bc3eef14d5e341448d01a02f7d72a2aa0f6155ddeb2aa5a83d3488aea5e06a460a0e35176d1a00f23c23e19695d6c63570bd120c30b48837e5f72a18438c8c661f83a34f048f788c9a861bbfd3ebdf3e2b106d1420b0359aba688313a908a83a44fb63e2598fa707391759ace116dc948dfb498bb41e51aa651897ac6a09377400ccfd33f3bf8ab22f7372282570f3d781f9102676698d9f1ee59fb8252d886acbd9b14294940eef263c888c42525fb2a5a633062eb58a5a8fa4726e9ca7202df94c8a304394d005dc398f1133d20334cd9ce73c643f5cdd561177997c2ea6b3d0c96691eee967f2a2edbda9bb53493f63ce9e3f8b13e189683e2d2021e79ca7456da6fc3a4faa67f43b2d6fd672201cb4b86e578d751b246cb283977677df12c0d91787eb589ca478393a8c0e861544b693b80eae747eadbefe80a0a2b121f848371bf2b4889105947ee4dbebf8995d9d30ee2b0b237e57517086edf941632f167e916b911149d1c5af3c405fe64a38934ae9f70da8ef6ca297af28d36255f410b825065b86e675ecb79a6a7d062ef055fafd4c50e0a3a5f43cd84e4d6a72f815ca1badafe370923c5e2ed8f7b612c139b8ce089b000a58bee0783914cf478d1578a6ea1d0e25f8d73855a0440c90ccd238684e327256c2664702a9a1e179e3bfcc8cefc8e3361ddfc91866e230f7fad0a2679e76133c19064bfed97ceeb50af7223e7f264a887cd761c89cfd3d2027a4fa89f8f49aacd55c2ee1087ff30adf76004b8734beb512afe4189b37f92382732a69e6257588f2d1029eef8b1e15c6d3bba9308c01b9a03dd454c9419cdf3dc24f0c88a1f09360be7313ff09a3040e6bdc4177f183b661c77fa9dcf7bb06909a263164ab33c8075b098ba6e1ca135560b37dc458ee07558e49c5e4175a74ac0902aa1ab6c8bca5392029288d151b2cbc34e996c01462622f2ce953ea5828f38ece978bb664620c2a57d0560cc153203802dbd157e5b25f71e153a3d955c9b45f51178d606507e5a1ce27783d92e63b2af5b0eb75ab3b63a8d08dc2d322c552fae26d55db2c67ca2e3b7d12290a74374b0f9e0ad77ad481e846eac63c4ed17c2c0cb98d662c1e0befdc447437088e5c1a83c183a82adc00317661b6e39d15a4a24fd010534f2528522dc4a65539de27f5e2584dd4e04b734ec2c12862b21a06927f65c21f551e693eaa4203a432d0f91358c21cd50d06c0f7dbc8a2af5e033cfbbdf375b22025d573be9f54c822c456f327949480b3c8f88edd29a41110c94b2f488cb83abf088da3f1e1287465264243cce840e3b52e76ca9600b344d21e78286aa6a7319b5c480b2ef327f8394cbc5416c40ac7c6c57f23ffc28ad01d3b151a0d969412cb075109684ba822e1e7f462038b50cbcbb97a1502ca4abfab9231cb4c502a35747598c094d45df41b81f369c52d2f89571d209a7f9440cd2c28198a8c6c45603edb133bce1a26d9da7e8c11ff121f2f18fa8738d21ff6806771b921a6bdb93f13e8fa6dc53121abb504145136d5d0d8164ec1ac7488ebfcbcb5afc31e3ac31ca761b48eb5d2a13eb4d25f19addc2bd4b73df90682b82be17c8c114a95325ae50657af626c4dc3ddf7c622ebbe5e8376441ca7965d56a4fbf9d45c9fe3ddfdaf34300bc56a7676e4e0efe70538ec7feca37ee7e8ec485f6a8b38a037ec4d6747fc6d459d0f5d04f6a4f0a27f983e19360567883450e8c33eefe3e8c5c62147019db0035683810e803d8f5eb31aefe4d5635eb29806babeefab61cac133e6e37b038d624df6443a041c27a4d9ec2926d8c75cde562a1cbe60fe3741db07ab52d3a9222b428037b97527c02e50e3bc4f796c06372eab17abfe116795e7669b85477ffa0aac31e82865f3a0ce1a3fc765b78c60c0c3ba28237f70c2a77c2292d3c70f5fb893db8cc2f5aa67e9322731b33336d6fa290204f0f9535a8fee5400d076bc5096d0da63338d782d22f6a4a14dc5140572e04b6623c32b1ba964868e0b299c0e8f8841e392a44224f9a9dae394abc059c0dfe15352920f984563d0057830f9921ffc8cd834f0479bc760b4004ff4f8d8523f5addbd42f798b750a532bb2085d04c53efabd4e8a024435fb98ff55728495394fba951b630ee0b0026ec3710951f52563f88e81c20934a32b4fb89f8388ae0f18c27663666af1f65d92b53944a70f3c0b985eca876963f7f109b8ca00fb825de47f993c6f8e3e03e8ad62b95cea7fcb33509df4759e28eeaa48c5bb9e7ec9abb08706a69b0c4e0b51632c9baace8b308b50975f5c268d2ff24518a7e81f5548e7da5d2ffa361dce1bf3b7c14b96072921c51fbc3794bcfc3a315ea4ba3b11f887ba43dca423494bd9db9cac09bb8a74832f2a6cdcc67afb836704ad115d0eeba56007059482048e9f71302e3924a599ac10776604e81e420740b0de29603c749a11c2b4d3c40eb223fc98330e439aa2db4b235a4c73263bd08c5fdda408adc274d471ac66507c048917883940e95f3604f344735beaa8a1b0ad76404fa15f4f969736f8e3012485c9d9e66a41801cf10a25988aead275533aa554d2e05041f2fb45129cbf3ccc538a937b7f2fcf4f55445dc1ce275bfa06c8ba979c3f96659dcb6adf90cd99fb135c8fb446ba10b5f742522eaac52c5c9478a86bd994070d9d41008b977cbd0e50496f86eef771c5f1c1a9cb1ef241d6f32fac44fcb51c226d4661e7c7f0f3629f36840cc5a5e75069d611985f188446ddbe759e41e4bc6daf5e9f0394b03db7c30822d00a4b8d44ef938de0588ecf56825515eae67ef240ee390511fb3ed97a3e128a2524946f7700ee336e575ec8c0892d49861949057b66b6c00ae72c97394932fa0d3625c6d1f4913ad4d9900a6e15366284dd4bbdd19af79d6521c1704d371226482e96dd2eaaaf8e950121f894f4c6d3029a0dbcb9bb388b165ad3e8c2943c51d9236e15def4589972d8ebac39fa795e702f702d7e0f0e880b171680031b0e80031b0e800b1587400b158340031583400b158f4590bde15fd437345fbd05cd13ff42bba0ffd8ae643bba2f9d0ade81eba2afa77d30311fb257a45fde072cdf6c8c6c4d1f9aca8b147c9cac6a86da5485f8e9a521aa117763b6c6f9c83ae907566ff2f988cb923d8f2f8a9b8d7905119b5b729bdd4fdb7e1275f3aa6090e3653812a562f657a2c60b4e761a52bb619e78ea6632a8c1a1376a7bacfe4516c71aab351184a70d2afd08acaa8ab3ffeee6f306c462540107d527195f57312bbbd55e6d37d24f3e4fb7bc98701d4a3c4c829bff0d2489a2e26e8babbce10d63c58b4623a250a8dbd4e3e3a99bd00d7f7d86ba14ead8cdd7a89074340487ca9067f3f6bb42ee5f01e18681ba3a5dc4aff33a5c952b260c70a068059295caefa17cd5ff8e09f8d56a51eb54f03ba69a4d4b4f2bf061621b260c160441c68de93928018000202477c7f365a93fad53e1ad06d49653941b0d4b22cb39f355e92f2bc67a007b07a7d718c945b093f339321380f06011164ac0f1ea369703e6a87ab3e8bf316fe993c6375199380dfc9515b273117ff2bdc322a63d470393ba21863abbd32ff6b79c434fd29bb4ec8b74d1b304db3e46eebb9994d8e02bbf43a02b12060cbbe9fbae5c834b4f167257ae7ce133d08129c35354a654d5034a2406d0b6de293216c0532af6d448d682851b473df87caa79e23e1c276bda47c0fb82946bb0f17eb84be621c74f88c5368da2455df31ae548089b70a8838cd4d39f661de1b6c1eae10d1827134effb3d4974453985856e0795c692ea7f86231666e2cc2242c377f71a9e649d4539d702f605dccc4ceb7f06c616b6c2453d0498a2c92eef6136c6c5db396b630f9cf9b4ec0f5bede273bdb842cce8b4f7253de6de0ba82200836bffb2676007b312f180519ec240bd8fad0d0103b9890be87e0d0eca0441ae568149be65c1ee9491ac03c3a93703423258bf937dac88c062456ddc4da57aeee35343f6a0643cf9944514038abe1b4e701445be53224222344c5428e672786ff89635a10fa986a98bab6162a0ef87782d12f28e5f68dd0ffa9b5d18260d781ad2aead97776356d0b10a1a3fbb218d52b968c09af444a5962f950778f910597d657bb5f7a0e667466f90790442bf3ba1c9d5bbacab9aa696ea4eaabd04d004f7aff61fd76a066d16713d385887de60fd5f23a5f7273e57f710de558d5bc0307b525cb889e7d062daed7106375f212e716c20ba3398a5f71bb73417ef3c19eba548a6afb54c10bb151760cd03209976b207618de25820c5813a2188e6f64e5fafdf7a9b9b56ba2faabece53b113f08c24be95ff23e4ef65b9bdf847c240570084951aeeff73e6db3461bace5c8d19b6d301f06d1bf339d582107147d41d36e8a51e01c5afe116dfb1ab35f7e3141c23eb5a737f9d3ea7934d31a61617fb3b6236b343af31074053478135ba2dfc6b39c86eb35b0249451e8089e4debe54b7594740917bec6cf2b2828f5a97628845bff531151373c09b6d35da6a16ac2540d3694c4b4f27c6b78db9d546834fca923b32160050d84c239ce968ce6adb620a2e92e00c5ca74e8133e66daad2422ec019759320c50889d0737f33f859ef9deafcb4d413eece92f24f48bfcfa9c6cfdd2710f320ba64d1523832b84029607c7c6eefe5653f97c4fbb92072a742823be40c21a4153544d496c8824925627e7fc5fcd365329f232e519c18ec2db9b0cae1cee02dd53a109d89ebc808b58d7ff9acac876af304218b80241dc31044a13992649b5f31fe6c83f27d9e251bb823d75074fec710840f1ecdb4a10af65a5c7a2f9cf5e3a000f8630445000883e8e79000408ff928bb4458ce40703fb9a1f77dff9b517e345b7e8b787d2a84202ce78d84409e09c60d05980115002992c5e107e74624cb1574f7b02b4129871e9130a24d2158233df256de689344f4d8c61a2807301f31821832683e4d2a4dff5d87a2335212e2c4c18572a1b6235e8636e9486803c86890462bd2572864477c57c144ebce2ef9c844ef3ab5127c140d262f6b72b47c8834f1c8c39d3a209e0432e667f046d1c08f862e79efd9f65ef25922db1760120e21804e384e1d79ef43e6058b3f99e750cd7ae8585f488024161287d0bdab14d8078dd3da9fcf4337672c7879ff6ea40aa30311c382a75898f8c387a758e18d7a86f1c2f701869ea73c090071e15ef4dc2862daf03f968efb19b28e4f51c062654b7556953cd3a8d4dc6b62f2309309d8b4ff3796ff77000ca4a28a87c468b18f4449401737fbf77dd6c210c3a13ca3134e51303a073ed5a7d320a2780f1dc85c6b311d2bb6e5c00fac505b0c061c6034e43afe12400a7fa594b7a1bcf066a37ad95a7ef9fadd654ce1189131856346c6168e8d8c59382632e6e45803f5d65bef62bd81ebc958efe30fbf33e68fe632e68f7619fb8f7619e38f7619e38f7619233ff6c57af0d6c3b25e1fae7c26d95244a1f14f936ae353055bad0fb02d76d804a805bae3baab2332ece14cde842afeeafc72f20444afac76e9ab9165d9046249a45b7e98e349f5c6e1733cd2337e618eb718b677eac8780065e34a3bdb17d99803eb7b505b9102d1346a2dda47e1cd08236fdec6c2d190a95a1bf2a22407c94a38f58609eb346a9c5aa2f143ca784dfd4f305e4bfd4e3986000366b1e6fd4d867ee34d2839dbb319a95723e7072f8381a9d9f846ef2dbe82f58beea016ee8a7565488de33021af729ab38fb14b281bfa023a9d08f54737b440e46cdbbce0288be95018c8a2b43b7b39c65811d2deab0a935b55b0f054731ad293894fb8f020886c9a809651fae3d4069e795e9978635642e6bd051d57d730dcfa893f5d959f05351e2e135ca2dae5a9e193300482455f478442e289190658e8d8dc139c268ca12c5b4e6354b2a0befe902885f31f7254835731b509a5243114c4be676866dc45b3b237d09f3251ac32c892b40398094f4577052ba06b2952340eea3ef71a47436c2eac4de6e5e86cbd4dc11c223fda5d5d8bf28e577c03ed17af29cae15d675cbcdee09acc8908b6a3629ef115032ccdfee3eabb3b2a2caa5420b97cdc8934ac89c76482ae76e2ad1eada3ef8bb865fd1038a6a219ef828ab8d5979d963d6c1b5cee84821c1f69e0c10d0b152682be681f0299390f4c58c410418c88c4884b8c984488258648229668f010cd6e17bff786eb9b4f3efaeedbd7be7decd3c7be7d2f5f4cf9ccbe12e2a7d51fa032c8201a233bef4ab95bf3a017de961b921f2f604411ae5d7e47a315edaed420b78941185014f3078028094eaff37eec9f78707789737ac1a6419bede2203d1ea38d8ae94d8cecea1c977c71d35a4a55201bac92cbccc29c7ce874a24a68a508c1787581b17a0773afab796b9b199ebf10f41db68cd7a554b15a756f2374d59467a5ba5c1f22ecc6544369b1ca5e46e8d634d55a71f93e22dacdb4aac2ea5a3d46d2a5699e552137a8dc222c7d8da48b4965b5d5eb7a8da04b13440bd525fb886837d3aa0aab6bf5184997a679568523f415c92e3339544e9d7aa4ba6c74be22da6d26544e5e7bace46515c511f63e14c4a081d7b431d2c625071574e0f48f63eebac6a251794a2b23736063498e644bb1074303291c3a0c545ee3b9d1cf207469544665b7b5b9bc13747fb221fbde466747b3d1d8d16cb476741bdd8ed646b3a3b5d1ece86df43bb75f1095c169f7e264d0aee4852c1acacb02bc80359467b2883ff130eedffe06633de5b932d1292b8607589df24cbb07474167681b2212eaf207224404a3b2e9e047cdde863269c5989222637cf02531af31c8cac55c9ca31578be9277e6ac2894258fb0dc69753ce50a7529c9117352999e7261093956493fdc6451cf464b7d481c2290208554d021d8de43d9a531e6dc0207e0c6c923d65336cd84150f8d1b9eac3f1e5e5cb6a8d94c35d9f70b98c543fe405eedb9c2fa29e7d60d066f00339f2cee324173f87cae8c90e19f30615e4d06f0267f0da91a0d7e423439ffe95e989311324edd4039d81ebc0301209e0e31f7739b2beee8a025dc0a13535f8ee712e0c72c80a7846f2fab694603370bac5057d734a16224dd7ec7ec1b1e67d63f576ec3ca6cf49fa47fc9c60dfdc986d68ae6015ecbf5117e2ed1aea176cb341fb58967217c15f5e3c07c60980bfd39e8a09bc9ccb8bbde50e2cc9de7f9af0d64d4e18f5dbe50ce883b0a5d36e996a8a730145d79230689c4b75a6aabf658a41779723d79c9d83ebe5012cd572f1b60c2ce5e40e5feee64c572c1791c7b26d49f7bde89ffc748abf064deac728b130f0af563e31255e1477442ccbab89a214e5fd0f582b652c4975fd6dd9874fee0215eed7a1b6704a7fcd3f577b57ef39d13b3d2af24edf55f519cad78e3bcbf5271de1ad36eedea07a8b1f4c8d8c8201e597c31336ad7b657e92296b31f29672f412cc48cef97d8fab31bf95dc6e19127c4659fc6efa5b851019e40ec3ceea9e2569cc6c67e6094d45cc96bb2e029ac0db28b50c98c6867b2afb7c0c48b6d3f7760cae3f721a654d34876189d789ab01cb928e087f8a7a330a82e8e1f224ce7eddd895935658e4bcd87ebd6c6d909e31315cc3e25697827a0b708380d18979519448d68357e5b38b619fc30f8d3c958e09053ed1f4055b6ed727dafa4d721212a51692b7a8b1b383c3a1fbe8e2b9634f662b0f04b84a7b628c0d08d4546a502f8ee15c591bb5abe97102d136259ffb0eebccfcbfe1d1155029149b34f6b3a346d9d2ccab17ee3a661efe9d2dc792677b7592068f4cfc27fce7767a09794a8385005e01f10310b5fab0fe412a2654424ea1b9694f7ef2610e85c7c131130ce5a57aed95dff3798183cc50459fdeee31cacb7046964eceb92d0729bad1dfe9a7f2a7d097b33a28605e8ddda6e5fec39af856304c6888f31720cac983ddc7ded5ed5e720e2ffcb95e20b6fe5c333b4cfea3e3e0f5b2fc89bae17123c34710da51a38a00e57e51ea110deb4c031b0ecba9b38acdecce40d3cc24301d4844b11ced61cc1de2cd11a2474f43ba162eb57d75eaba502ec5f17ba215d875c256b9d1d67eda2b25d3e4055f4b7bda276f4649e6ac1f0fdcfd19007726cee0c47f63e51f9ffde418213009e6e3744a5659ccf0221f8db9b6658b89e9ec0acd7b6bc5c582409f80cf37a7825a833225a987d28a79bff1fead648e78fbe366b879341a651613123d844fcb7d8d89baf24095b6471d126845001074491126289d0081c09adf652aaac9870810712443ee0b1370038fbb528f441b2bf81d1737f7f33fb6bfa6fe3a883cb650a51a6d1eb2092b656bd3c88898854bbb454243a44598890c3490d81263f57497ff99987c49050e06f50f92933fc5455305349566cb19e440ba4479a665d0d2be25f1034b0d708e42253eed9edd90353f3ac2323553f4aac83b0fbbf7117d0b22915ba98b90d808a0d121d6603592ecc527933488cfab5b1ab9d862e870a7fa77b598f53f8064a48ea5afacdd86cb702cff847399edb5fa8344388e7ff5b08cd5261e9db2230ab3e18d3493dbb9c58bdda20f6d17e9a50b97e6a8958da277f0d09669a9b38043398a9c43ac9022f7ad7d414bd290bc3e66acf997f3a7366a26233134f84441444e4730dcd271db06090e1128c188bcbd4672d87410ffc005bbb0c6a275496fd14945db621723b2d1e3489296ae4678962588fa68c1722314f5852001ee2e1d7f25320c289128666ea48668fdbc18d11f1ce34294f627223ad3db92d180b8ca10775a33d9f5e2b4e85e74cd8ed7c7b3ffdd78fb28b9e316076e05538679264e2e10288208ce23db945e74e3eabdb2f8383dfa67dd89878794a8c742bc5ea428afebe1981e022490d171e7037501a784f315f8e86b11f6eb911537bb60fe91f2488a1e2ca508c9fafb6385ac894ebb8692f3629d6ba8e61fe924a06880bd87415a52e33b1bba204ff306143e25307fcc65fdf33463acc4ed2e3a1d3b11a5af52a1d45dba0c29d7ae6b72f07882f73e5a590ad85130b9fe14fc39f48b552fda86b625649f01a4326053473fffbc850d5959ad5ad0863dadb32bbe0db19ac796b81ac5712b59579593272047281e619dd7ead4cc73e16180a78e4441efc615a0ec9c388cc70b3807fa2b72912f611873f4beefeec88fb26a6718a6ef6692055b831127420884fdecb016da25c6e5aa491fd60001891c71c90a62d8a26a964a7d710be5746f298c365590118e9790b615d8b7e63f61d99b9f83dcb7d0a7ec00172bf8ffb930b616a4dce08877e73f4b0246059ea078af3672344ce31a6198476f127e0b94f5e69c6fdc6aedc31febd34ba31e6d260cff4ebb3140cc7bfb5b6c646e6e3f5fc61d8a292b1ff60936dd9c2a6df5cc891e5c298630740497ab3a3c612bd3ab05687d6a8998b4818774d590df767a540d526899f924fa06a87090f6119128633ffec8c09908fd183db9ccc10b5118077082d850a598b0bd6708acca0d821cc08e6dc9b8eb4744485aa70bb268f05d3a0e3c1e8a1d2e305d050c0ceae0e8b23d00aa374e09e89d84abfdef0c1233eb40234aa5a306988e3f06388e0e8e3353e424d6952dcfb9261f79869b507e868771fc2b649dd1abf584e0f1fb71079ae41b453329352c8e1278bd99d1cf72d5c612f22a75d5eb32bfcc0577e2aaf5a73d6bdc87f4b0bde289667791e30d78a7b2c28ceb0bcdbf384c0022dd4ac417cec2c07ce982e7c9d28679438d947362cc2c9ca3dca9e8292780cf9239db0caf438bc193044a629a0d09fdc131a777885f6da2d00bdb7f548196f994b3154396087699140b6b56dbcd6344010049e89e501bd651590612b3ff23409d91c1cf76288e27b5877bff25232e0dda8842e01544da3001dee48004698a974aea21e341e3dcd3d7832b86c1806e4e319fbd130742661f758675e8244ece4550cf6e57986599576da09a7fb7c86eb010c03738d796bb7b8e02cee7a217878e798d6932dfcb06a22fbaf779a7d236d9198391c77012a899d9dbd4b523183ab55ef3292ad1a21eb90c5c889ffe4054efffd5e194fa06d54f18e7a1fa7951ec68c1659ca6e46bc5a93e005603d7a7f290a6616297e0339e2c2e6100a0c44a2ecf350cd5382073ebacc4f8dacfdc99ddde3e44712ba4a2442223269ea749cdcd2db41703a85a6769471772e6248bff3e0d41d8e7a9360c65b181f7bb0ff9d8f3595bc57d90d2172da3fb755f20acb3fc594bb3e65f9bc4577d988cc964d4b651dc283f3e4ce941d1153ea9233daf558c78aa9d611c53806217ab8f57e676a4fbb81d9f525c611e2f42b7c33d9856ce4dea374d56ae60c4667d727841580e712b73c5cc9fca6c48554a2c0e0e4f1a2a98264409d63838309e2d3295809d59ff214137e16edfdb6ab9f7c6ed0d0a78e1581bd664d4b2af821f8065c359eb6f08ba4da9c4d726be3ce566c876c6cb2d1dbad12cd22e7d7e9ab66c4010e2cf2a06d123f26f059352e25c727613325ba9ac092bc01ae76da6953b198c2d8157444813475c36510b32d587ba029d013b37d4c8079282d0a2e26a43292858c07a1a70062d213dbca8530f9e6eacba8504b4064abbb6818cef59b151e681a8123aae4fb20e634dd872692ea3378003d9e2290cd88ae9061160bc07ed8218d53fa173875fba2f6aca8ac23a966da8df6e1e73a30a4b18f1f315d3f0d436fd63d8f84eb42304effe1b487ba009807d74580060201a4a201d6f17123b5a525d1e6672dcf00948aa53bb852b17bc0e4e4184b476e2aa480594f9cbc1fb9f219a27919868bcf9d4a95691d0c60e5ab447d8f91f1b9384b04e4429e54c0af0652a200d4a6414d965fced59a60205809b3ad64113a7b83ec1f473c9cbdb95b0f3e556a24a6affeeb8aff7878960eeb3fcfc4ad1370bb0cca277af783d463d875ae11d12296dd129402ed3410f409e51c619a41cf8a56d4f178767938e56aac3084ac056dee0bd437059bc9131b48004dc1ed3b0d00cebfdde8b81f76b6797ea9732958e78768e782c0e43fb2e5c49448b62e1c91df5d1ef4e808161a716838563fa22d7651fe7b1cd3b12219702669af3b419034565ec2a21fd746c8ae9be4f9e30147cc221c0ba0ae2466a15fe65b73d391a3bdb7919c0326dd1cf7bc91b547063cebba25764cb0a79093e31d2e7927208314d5f5454db84310a369564da1897a8126622ba0596e262286d29c74a2db85be41e855f7feb7e23a879edfe715c3a1715a125827508931469019a345ec126e4b55da021afd4ba0d835dd76b3669c0b03a93c0188f49d3b1125b5d7f939b9377cbc5809db71b8414f9333b7c5355bd3a659290966d028c6049c7f983a5254b1cce27ee842a24bfe98d59e51ed35c20feec2487b730cbdf005c87d29212dc2b5e2e33dab26d6742f914267c2850c12260704391bf7bfd131dac87b770daad48e5ce91ba7378af526f2bb7d41e9762dccbe110f97651c6e2bb38f5ee4072c28b55e0e2650552660f524d8bd6a830088687b5bd21efa8dc112430b45d228b3c1c6358848c4a7a017c4015e97b839b324336a29cbfe4771587776d7e5ab6723e20d83e1a9154d6499fcd4b221b8cb280cd15bb067f5e527a23c019de3a40e227fea9c9fde6d8a8ad92a49b831c20934a0b2a7a839ed020274905cd25223eaa338dfe58850a1dafddbae18095bbb9400159fbc379ea643a7dda77a651c82af913dbcff48e584a03b05419f569654696bc02d40876eb3d161eb8b8700ab740d17ab50c87d90d3c0aa660afc7d1365913e899e544f9c35e37acaeedc16bfaba30aba17eb321590335b7ab66c571c2db21b967b374a10ccc2861778fb171605d5bb3be588fa0b62a098c2971545d07682cd7d4a116e6bf36bbb7be3f82d04650dcd4851b696f3ce8d3d1b0b1dea6be40870c5479e4cf27097925b52e8fbd0fdc512eb233be5c1516a0c9d97756cab99e3dad216b37d1d9fd3b689cb4b078531f56bd7b95a23e4a527c3900cfe955fb100b26369dc26bc4f82a0105cc4182bdf6e263e41ce9e127b6fa3e963a4e208487406b43ad06a06809bc60e28fec171c5bd0262236b0afd30841d7c73000ef1fc0d25040b3c49c4a93cb1db7fc8e86aa9e7ad238b2d21ace79dd221bcf29cc24ecb991152191373455613600db31a94fb7db0bccb2d3c71e394c2d87fcb990698f9290a4b52a829b0af799e8737b069145e1aa288ee81a0490f0382aa1fb07120bb68cc2fb5d4dcaa16f8f52590625bc828f2b8ab8106ca761128eb0baada1654274d40687b021d3d03f77e28978319594d1268313f3ddb246badf387a4cca56d157f14856a31e38fef3ac8f1ac7a8a7e732a5d1d9af0778928b3d899f33101066c092222e18c728d793f883076c7ecf109222c4c60c12d96d0b47626a02936fcdab001df26a236bedb708f483c1f030eb2a9b730d62970f8f714e91d1004370f2f2d68a3a5932d655604d0e2884414ca0389feded2b4e52fc23f03e2919443143f3c97ce99570610373c1a9756d4b290878efe4b09e612a906bd7c5902835a0b128d2103bafef229b22ba1586843158c2e4a2f7631f53c43060a336fc3fabaf2100ec45bf493ce9f3f122e3b71283939f44521fcfcec41af0ec17208e62565b669ccee36cc677f416e0dc9623248c815a505e3c9020a55025264c8db9dcf4b0b26abf17a8a0a918651e69d3f121f41ecba69936ed0c9c96d9bb8637c0d0e6d197795c64ac1ac47fb0610976946b7e7c3fc5899a47e24665970d48792a1a513152d62b8d8361cce1aa82685e69d9513161af1689e235f10debd9f1bec0c290ab1756b623b60b7681464903ee0361891f4c88ac576a6e2f9d84bca14d05c99ae0c0f1d51fcce7e9402f5b3927cdf21d22e86f0f56d81856b47781d436dd94373843d1fe861378dc8d36da44ef5d08ca77dadc74b9ec20fe9448b63e8ef67b1ee55fe1c68c99d61b91c97ae01a5f326363bff5f7404453314c86608d2d393d4075e27d9d96f038887dbc281d81a314b22431b4af5c88736f1824e6c3e4b7c3e38a3c9de503081236d98ba552839a7ecbb3cfc0f43ec4044cfb9b2f5a1569eb3b94adda1bd0056d9d11fc340d1d8ee97a22a312d360c40e296f0490d16ebc2ee64b1ea43953ce286dcac4e9c21e03872bfd4e284f71a9611b596af3f16504cb9fde8fb17fe40fcf1a5cdb00e979fc09cca1bd5e876e8dab2a1eeb0b2c1feb766bbe18266c44af867172ea92b729e856660ec5148687d61bdc869b2470d52f8f2aac663f9cd2ea32fd71dd0f15c74fc616ae572fbfd606b071f96329591e3aad2f55643eac01f392872c29c48665d515fa61b626b0b4e294ff7c2b9d0c6c561c0721c289b6bc0f831d8dba524414c4b5d2372dc53321bc0941e2644538f5b61a73162f8113a2cf3bfb222c4e63c639e9fa1f78fcdb6f0292e27056558e58a7d48e2c2ae717db3c82cd3fa93e48990ad9430a8ff9922f9e7f205e06ebe0e3d7713eda6a69002d86fe74cc4e8c9e5b2b934b565719cfc43ee28d4723ded801c16c5668c35494a155d982021e3c6568b930fcd8944af3f6f87f791166097a8b59abf371a05cd10f84097d10f76479cd68befffe3d940cc0510c81d791b94901026d9dcdfee8f4267390a331c292a10bef2c5ad641c8cc3456823461c1b91813a45eb65c8fd693882bde67c23ac98786ef4f2d00ad2737d8f0a7a6ffcb8d841f0324fcd4cc7dc7c4d002b4c471b7816d397cf53a5fbc6dd54f89c42a4769c4a946a8083f2e2b1c31124306ff7611ff4e9f9c9f61861d09793ac27559d35773a30ccfe763ad2e4899fc275cabf4d6bc995a38e8fa8592a7d3fb56345ec206ae719738b8ff3d3e938afae2c656ef36a3e6030d85f7cfc21311bac978eef1ce61e496d1b25dde87e9f509fc932d0dc582867f20b788eb3ebc2aaeaee51409dc105d5818da64eabd8ec6fb5779c08459de5671f02eadda91313bb7ef9038ab2e312484414a23d50079b064c9da048d0258d80e3751bfc82ddc33e244726ac0f2d36f71d505c337d442d4e7ab6484a4b47cf03eddc2634268ca402c6f8bb30ccb35745acd2c79a2483f646cda03d4d904897d14ba10b76f013506f448763d336042f765e3a495d0a6c980089566cf30da894f5f87379166a7928b50e4e527e78b13b10866acc9b46c96a5a2f92a61ad0fe08e8ae347c71324c1e5e15168c23f84002a2b74fe25e7a90ba03b702200aa26dadf7f6dfbe05bd6a22433c493d8d1fa11283e93579bc1e5c62a05d41b37f02f9f73c90214efa1615921264ae8bf1c72f8452d32eeadf6649e76bfcc612660d1c81b0f1269345ca7cd68afa719359518b53c72799c3068b61bbd82d457e60b58b3d66251334a89e5a781665bd51106f6950637a9f6da63a890700788616a521e9355da7785679a55a0154c22610e1b4d108659d204fbd06963dc05ed44c8012790f796e17fb329ad191b39f2b1feb449ce9388e14ae0f268b6d1af170e4e09776b147a55e452a9d99345629d928a1643f3dc1d3774b74eb3f5fa2137cf6d6f1a37d0dcc886281819d1673fc20ff5b1375476dd4ad446cd1252527da5620c967f5da24e97eb9ff3286bdf7c837a34f9632a4751971384c249de72d466a555a10970d0d44521816588010c80d4546fc8ac01d0f1a196a00634c13d8e4b7fb68d565c3b98ef8e77a07da922a686425e3d222aa91dbdf7e27365a4b3726a44c68ace407ef5e383c896763cf02352cac120ecfd1ca25ddaa6c4ca12d80cc401d8c91142a3eda4213067037bca9d1ff3ced0d5f11072b1ca8856d448225b944fe1cde8c1c263283982a764d0eccdc12cd05569b757948bdd757340f55554c36277607e4dcb8dd59ecafb39ade9d6947b5108ef4e119fed659ecd08813226ba8527b9cc5cebf319801e292543f4f798c2fe35a00791983f549320317a62b5add143c94202097d92981957710ac019c0124c629df7c1e9a40429f82fd9132bd038695fc7c5abd39254b48ce3b9547f20a2a9597c17114b1ebcfa1155209d214efaf82931a998e16fafb4aa8352ed1e60cac1a05d4e92aed94fa382aad80646c7c7a5326df626b7cfd1218931e8cd364bd7905ad551f3f17726c6c49d721b336a5a66278e423261d1aff3506898d47185ef3bb9b52ebf188e789984c2b33822733787c9429b9157d60656b5b05ee17fc5cc8fe23d2dcc4130ad86551061555922477fc8cb2bbb07a96dee9511983b08fabc9f76b912c936151a6e0ce509ac43ed7ee68a0b993923669b89494915868cefa88ddfa324b3ef913d64349e2320e8b46db1f1973e6d31c67c4ce7c80bc2774d9ff8041020944d040a73da6d6e4e5faba832e117a2aab92771e0f26331544a4755fe346ad1ab1531966cc9a31f4bc5a17ff358da83db3d408bfed5e430f397286c68a7631a815b16f4883d8c5b96cd2988d9705dce71e341810bcf4706419af45a61413c674ce622440353b437a577de17cc0bf86c9b9e0cb531a317c76023c70828a4c2f46a528fb0f03cf972eb1f119955620524abb09661fb80e490853444d44cb138d9e140455c4359c2ab5481857b0c0a1786d861d9b88fc0d9071bbf503182a13e1710b54a9604a0065395e5270f1ff584355fe441fed4cbf0554d70a342c1ebd55399c21736448220d14a0adacb85c01f1c22d9cd6f67ba63cd8fd90898cb15e3e9ba161cf793cd7565790570e7cfdf8028b747405f70b8524e93d5a77bf17024e73a126f5bf73fc70c7740efb8d95b08ed1ddab4deb669c6b87a478ce7e023348e6fc69e6d94b1f2f380d4ba986dc6e2d3b2a411f5a5ce386326ea2730142fddfe39a9542274f56859e53033320f454eb83f93e83b6c65c91029c347eff2ff7fa1ad5fc57fa8d5c68f9148418eaee7a1f8e510d3b7388d2fb4079253bcf2b0e405fb164b827545818c917f6e2b5bec82094a5498f4b1932cc703850f10b47311be2592357aaad30e136c6104f04ba496028866e16fdd47ad35155d352fdec2de82cbd170469979f4972b9bec064ea0b7ad609f53f77faa6470e2c9171d3bdc8beb1e02e5957e4d5b54442e33039db0211731f4e127a2bb0d2b01ffabb8e4074b9ddc366caef438276c98075802a537af338191917112d11293dc4374fcc88f7fcebcd0d15ab7ee89419b46b257d41b82b5277fa2d3c6bcfd79ad4b00711718e6378dde9e74b3150116ec82db605b7749eb37ebb444e5c22a1dca860ab7671020c35ee6ceec02b0ed157fa077c78af6a5cb822f23708327fc4ceab2207773a9c8a00c5d6cdf5cf8e17acc6c3d1f5c5489f4764868a361485007272f3e04eb6e697e7596c4d7818bd2c848425ed9d8eb805dbf8a3d284c726a7f29d8396fbea5d0e1719b83f278757ff4b5c9ab62af06aa98408ef4147214391a368750c4ccfe535c49d9f7b467e6892c73fbae0a88f9049f9ad2e8bec9c4bdb005481d9e33b0ab5f7b602708789959c68d756e8558a5aa6726ee0e8bd80cb580f1c4f3c56925c4904df8a386de24bf20f8212602a765943b92632afc6499e0ef98fc109cb8c7993c04bc3c1b0de727fcd93f543a4d203ab66a02c48fe342c83941282144ff32bd8a37bbf820b9388baf20bc85a84ffa69999f3a5da383324df4d70ad5d8d9e1aa882eebe5c6ec7f0c2c80368c43cef28ee955af45e096595f32d1d9fd7b8ef9b3650d6cf78d5f6fed95fb766c2487aa9fa4beaa123551f46dbe097fc80baf7c7aad1b775b4708e2cbeda3f7c4c9527296a020fb2ee35d87adad7db8ef5d71eb59b2cda6f99caf54aca93617e67b7dea88ccf4e39b559d8887a30f6a6201c694b469b67d0733b95867f7925e1050380b39228ce2ab481ca4dc57e61b073a025eec9af3dd552a523d93d62366a5a3d22aace6b34ec0c1a30aed82d774d6d7fafb7611e7625937aff9603c61d481abb23fe717552767fa5c140fd60ba24690c6fbe545536621ea3b7941355538f9ae2f515b88f8badea943ceac4a32bdc61e9c0e5456a0815fee161fded1b93960a77738fd2c5765141ae0daacb61e64ba41ab2b2353debe95ae3016199fe31e7459d58a0aaceaa2eac03180af4410a7ca72910ef038b8645050ef2899046f7b883a4abf562c0de72ccc4b039a300e84337d2ca35f19ea6e6480ab7fbfd4aadbd08b4dc63ff59fa1cffe1f25247c91f8d03684548bcc4871d49b3045c4e55902cc0a6003ab544c01a227e6f6f9d4d03f3f3dcc83a7048f23717bdd42c06e6bbf45d63b6520ccc4dde8469bc4fc31e7fd03509b3166344fecabf7053a93b9ad3a8f653fffd630f48b39678e31e4906e64b6cea983503f32cc509d7c77225ad12dfb6da9cca6a0c273b28e3954e947ae4fb2a8d748496246f550e233656a5f77850781b14cf8c808b5f13a9689848aeee3e1073be76de0338f8d99048c849d07b0a121d950b62c3f6065252b4bf09d28fd3022ec8ccebe91eef4c134ea29bf56ede7f009928c1e7203e86776711158f109a6764e41be4d3a1db47fd38b00daeb0ffd3ea4ef13818603f9e2cd502052c87828f0cac4ad5c53210a8d1782b0149c02ab8889a2fd27faf7eb2e45b6c6504dadc28314237529abf511c16e7e03c2ccac8fda30000183d0c76e86b9067537012b0dd497c340796c91cf174600f509ef9e5576d9a0e75cefd60a47734ee1737b70f16a9e0fc9a0d48383e942ce86077f20386eecb4b090e994cb63be40290c938622a6ce01296eb5b5141b1802db1d1d9c81994bddd169ab66a96e3829a9a205252ca4ac34a1ebc4d2eb8b3054b4e1c1cb8192f321e0b8983dc0bdce0b79f51f992e5a178ac2175b7adb0db7959b158e9da96fee18dd11f77483fb061a2ad805d7910c2885253bf46eee7d9e89ecb77aa68f318cfcbf939b427a283222d1d09f4fdd55d737df2afbb21ba4fa2c8cbb97583102b9583bf7d47947cf1921c969d08e5504a6a566af2c90088ab775ebecaec27f95c31d003858268fbf0f4743b096f53a90ad6dd2c8cc003200206f26467ed9c6473a7ec7f75fa7c95b879184ab9554ae50c3730ae51ebb65b013ae564346bb2d17a514f4e06344dac4e877537d846a279a85b95337207dc91d7da493d1a1858a91f289e740bc4dc8ae5e661d3cd858d408c4d39c7f1808f11baf3d9c1092eb4b6a1bf4c31a2575b3080fe8e1405d057e2aa32de40ef1d2e9bcc73af4c09c5cca957d4e16692da478d1e8cf81d575a0d7fa458e5b4bd5ce90e8d32ad994e4c9e83949d907724a9ae6a49b83f6768b40cda6587d49c3d723cc349514a5cc14688cf5b726e7fde91c17d5f967e64833d38808e093234b94c856b7c7b8fe913700872db1088b731544e99aa5e8a1001267a7aa79ab83e04abd091225f5f556d580ced66328d8487309c651830ac17625a5ac316aad68b61f9ce80f934590963105f42f26030bef15af7a0ca97b532164c813051c50b0d466caa174015057c1f454b034b72182735f4dcdd4bb0b8fc4f036a0d3d84c95054c632040dd3ecd25acaffc174b7c7832c6c7cb6cd1642ef49f636d18fbe955fb4171a9fcdf712d4fe605578630f761d317f1d7bc45a6ea3733d30091fd7abaa187816f5543c6a9238a4beefcb2ceac957692d40d3463a14b33f0c88e5aa9e7ce54afe04357f3057b3ac21ecfbad8d83add624dc29ad2a1c19cb06c30743399705229422f0e179ab463b2525e0f4e8e2694ffc049eac3dabcf0727004b54bbe51b48ce65f29404095bb3e9b2615d7141830c03ff75444c96f6882d2895788e2fbc0e2b1714691bc81dece9e9ec2c17915f7542980ac93af90f232fe4253a3a31a7e2999b1f157ae057bec815277fcd0974e79762799b92cba1b561fb2452beed21887dc0872160564510b395ee1bd7baf6784ae09abbe1dc8856e0e6a6faf1b622051d5e06ef73715f02a66bf38c7f9c150fefe49e8416c5a881c6a1a0a6fa3201b3ed002501167ba5dd4aa5036a04965ff24b6c3409672a6bbd0c52611f918e8abcd7e095d3f6207f718f7435b6e68aea6b702e56773acd800fe9bfc75a7358dd71e170b330d8dc57bd5de59b460645a894d671b7c02810f89230eed22c53ec55722d1a7b3c6223511ccf4f073687851885afb2c0e632a4b9f19fd2d4ad5eb98546127b60fb928ccc96c7bc8da937e5d2b27fc59ae96f5020892ab21f9a328b74bd41b76b46ee9400e0bad8ce9e22f02419a7571ccc7e8970c990b9a22339ecb1cabb07c220941747ab92db0ad6fd94ad9021cb782e4a4f2943602afba9a062ea38dc0b98509f130969687e1d0c35c7e20bb170bd1c50d96e033d847b47b2e781c83f7a6e817cfc24b9d49e522c05d88174548364a7a8b626d2a5291111d9d6bcf82318bd146dde5f5bacadf691383194a5785d7c3a817979aab2a0ac64fec7b2a42db78b2f4be64e7503acfc022a5112755a305a594d07b561824d6484300d6e3945b531313f219390c7ac8a2e9c4a7c107841dac0c81e9d4ad6021a40715d1ba9c70b08b270ce1d951fc80b60822a975d4a6f72855c77fcf35698702df5982c59696d6fb9b7dc5bca94a40cd9061c078f071c4ce79cba9fdf7df73592961751449c193d7d17a2ef1fe5b6fb8535ebe8e8b88e89ea88602783392611414db6b16394f7e792e944bf5c3557b373a8904ee7cc0fe70cca7192f324d31c89e303be9ec7b4baa15c0da9446e11938dce914c75563c8d0f6990b21abc0d360b49d6a13f60cf33312dc9f4a5924cdf0582ff2693ebe8d07c3fb902baf765e73a39df393a71a67bfa3d8438f3813813845c4454e92022a6bca73f57128623912ee84f247209eef5e4ca07efaf77efd5481846c234ed741ffbfb139feeb3327da739dd8f0730dfbf9f11d41b6921514f1d07fcd08fd4f0a1dbd0d0e2519f5cdd0f04ff6bf856abd5ca517786f461f6288fc22272310aaecc8e4ffea15ca1e0930cd22045f9cc3f1ec08c4247ef0388fb189d8fc99c6167752ac67c7fde9fd787fbf3e30c799c780033f7dc6f8e44c2a01f7d80904c0d2645a6d67b4da60f6b98f8be87654763fee4fbf580c9378ff028cb5924c6d41fe511160d89f208774cba3cc29c8bcb236c7d88cd23bc016d798435255a1ee1da35358f70f624cb238cbdb03cc21487e6119e9226c65439c2de23c6d48fd13b78fe60624cfd893b8fb0ccf1bb61e21731a69fc338e4fe4b2995b363fa316c575a62df1110624209dddddd36bcbbbd5d067557277d9ff42411b224abfe6104fac1e38c5e7d4de63ae76b404ef487067b34100d4e6992928a9cb8f2312131ce1c9126c8734a18e4193de8871fa6d7225913c32d5876f48b99676af04787f68329a6a8c2bdb7e3d9d101c1ba819a5bcf767273b3cf757fddfdceadba05411004c1296aadb556aed3ecc6759add3a6dc3b175afcdadba05c10b821dc88153d46dbb95ebb6d7baaf1ac775d65a6badb5d6da6aabadb65afb2fda5a6badb5d676b6b3b6b39df7dd771fb55f8eed756cd677783ca8513256e3a8d3f94e7dbed79087e6b5d65a6b0e1d4e27d775a10be5ecbd893813d4a939bff325dc7b226e93dc5f5ae95bfa987d4a5fdbb6c7366bad95dda72347c5e10db91f87fdec73e8b09dfc7be556dd823c20088253d45a6badf5be8f51be38662e871c431cb2e538efc57decb8c37d0e9dd29e8391b9c72172dd731cc7711cc771cf711ee7719cc779de87a2f73eec1f1c2cb86a6badd6fb745c1cdcf7a9a3b1fd7d2b808d07dcdcb7ede59bcff0ed2d06757678e887a3caf9e9c8e1db4fb556eb6aad5354add66a3beb71bf7d787fc3713f6efbbb611d97fb728406c05173744a47a755ebd8414d6bd92aa65510044110d4b4da794efb536badd1d6fad569ebabc37285810de3c8a103020eb0e075d50e9e1d1d107cddd7656934bd72df71777777f71771069ba194526db3580dfbfd902a4ef36fec1984a918265b91524a29a594524a29a594eae8546a6e2f3f0729a594524a492da594d2b718f6f68b5af7d6067dac4883ad067da60ccb7e957e7393456ad5ac7dc7b66ddbb66ddbb66ddbb66ddbb66ddbb66ddbb66dc3366cdbb00d737777777777777777cbda3e3944a3c1f17abd5e2fcc6eaced0bbbef050782200882a317bde5eeb5f65aef1bc7ebe55d4b448c1922ba60d538ea6607fc5b25cb7258d2c8212f1c3126eb559cd96e72f63d449c8936cda2385e4042716855593fdbb6d9ed63d5b46f6eb6d6c97d92c67e72086bdb86d0e078bd5eafba4dec3bf349bd6a03645fb11032f3f099629007d479b17d5166a71a38d38f176062e78d7e0326cbef66292971651109c37f869147bab8619a73d2eab4b38c312d6bb860234ce83a39fb97968f6f85babbbbbbbbbbbbbbbbbbbbbbbbfb77c8fa43aba490a3b2971e8586e4cbf767f99537bd4a6ac5a794505ebe0d9d22bd7c994e792fef4b293bcebefc1e3ab5bdfc1b9dd25e7e0370b48ac5cbdfd1a969e3a59b6b21577d9fc90c08577d9fa4a9ff6534423973f97699df23f0c9a61c938c6027dbc955fcf213d76781ff2936c202fb0d6b6ff1f61cb6df75178fdec3f749d82b61944fc1a55f81535e05af781356f9156c7a16bcf28e59fe84fd5b30965f3e46bb6ecb87a6fc583a6954f6f2d2e52c3e9bdff285a6ec94f517d6137e7999594a4adcfa2d99cb209fb2efa14eb560995db00f204e2e2e2e2d3cb87c7f8c6e69f9eec982f24bbf248fab7ec8864ed805b7e0da60c534b7e019fd272c9d3438d460f62c583e6930fb159cbd297b15dc2b70a7e0a629e146c1ddea220d66efe1ae699bbee923b85d8d9365afe1d6c1ada477702f6914930633ed3d67566efed43e9459ab1b0fad524abf8d7067df12156ed8af9cbd6c1f2972f6dd43bdb341bffbd5d3a9c803a532baeb98ba5485cddeee1055269e1d395a45fa7803cf4ef623013987185101314565b60344183d73dfb48d7d1bb1ed6b915cbfabcf89b66db3b3c3f699368848d83e2bf725f3e65fa1efd038cb069896b0e44c1c04df64dabef0d60fa6729b8eae06c7cd69c3e7ba5ef1990fcd9cbd672188f201a24ff41bce3e91e37003abec1fc3379c891e7f2602c84aa7868615e40343ac648000888c0c8735339165894992213ad9234f8e3d34182900a66812d4a4495093264d82b290852ac4295b147f8831f4dbb9298bccd8a2f8bd28ec40a6314754a1c4b47049f11cba389f24c2b26249c2ede2baae5be29efb8cbc473485cb43491fca27f2b62397489e381379e0615f0899453fbfadd0548830ee8f0769154ace7d52aded6c58120945341467264da7ba6fd18f9abbb7530a71e6c7cd508830fce5ce8d33ddf53e4512e1ceb75d4d6002089ec5d28e76481e499483cb3591c961fb70c10240729783d71361bbbc5d3345763ad04cc6755d7e3d1957750e228afe0b8a27789ad819824e0f32fdf005126baa58e676b5cbb3f7b4eb469d8deebdeb3acf1c963fc418bc6362deed58d1fd567e54fd459ffdee8e4b2b64fa8db18f9e7f3f5cf47d4cee435371b436db142ffa8eef4c9a9c77996e2c9e61df7f4a24c826a20bef67a72687822590a3845c38f64826bd37b3444213d1055dd2bd8388a2df3ddd8476820920d8969cae062a8b5c37943b9e0dd9a1a1ebd2447043dff1913b3baf9d1d70c7df77620cfd13c7b98ee7b8ca8b348abecd914c713275154417f43bec173b91fe69201674132884bc0f610a43a6dfa28e06cda2af7da2dc19e2feead4ccf43583fc1393931bd43e5902d126d9b3e1bdcf9fc883f7cd06bdfaa2fe85b2d5eda06fb1cc1c96d9c33b1aac14a08142c84e18b8205b31867ab659d716851ec8f6eb9f18e323ba027d8f22aae490a7e5d05f71a67bd24aee9a307b7f39e43df5a8e7bd1d6a247eccecbd8f51f6bef8223cf3f4af0d7acfa37a1f8f9e4f2be2d23f798de36a57833b35f5e6ba4c39bfd32e97cbd5aeedaf4321a2e873eeba54a859b85498c890a90d39f41714fef29e18237aad882bfa52d977b24f7a7ab21f0f6026799fbf1acca1382e222cc8f445520599facb553ba24f75729f98827cf479c9f658a2221d0dd2ef2c95c499eda3a17d42c85c7f7ce6dca109ab4c672f7979df8e60ccddbdc6dddddddddddddddddddddddde58bd62e2d27961593ca8a94120ac9bb2351c7d9adbedb983eb1173cbfe26cc346589c308b0b6ef9c62eafe1e63a1a58adb789340d1a57b178fadd93b3ed9c86e78d74f2f2a1a4c21fdbd9f10184ed6cbcbcffd6f1f0f2fef2aebd68dacb238dd348329ded443a555ff06c916c17652f98e623ae06e9bb60d982e5094b2458ae9854566099822513f96ab047fa0005093979d2ab0ed2a821f2060b4de3347547833f7cd7962c3944deb05c3407f9a653d1156762a6dfac4d436fea777fed9ad59a615a966935c37cc5d22b60d0a40a4daa40a5fc62d34929362746a51238b8fd56fa7c14a62762133844954c0dcfa10758937377daafd852c8f44399a8ea1c478de026bbc83189085eb672d575262bce20a2277d44f9c8f2f1f4b1e523cc47978f29161273a9b54e592631e9524a293bc7b14cabd734c36575ea53b5788a65453aa54d1b6e7b2bf8e8e894c8fecb1db904c645da68ad1bcad50cdfafbcf6cdfa4d2997c499154ec49992cb9d4cbdbe0cd252ae56335b7d9eca9bde34f10c4fefd3efe9b792ee25d953ad7bead33fb663667134a516f5e69c7168cef0f7fbf9a54eadbca7b0d746cf7d0e3114d029949fbf43a7587e7e0f9d3afdfc1b9d6a81f9976ff1f377740aff9c1eed6c4c6f4e6f7a2b5779adf79a4ccfc22edf02778ea32876f9160cf327dcf22cf8f42898e54918e52d26bd08dbdfb0e839bcfd68f41aee3ec31af62bd82ffe2a9ee14db87e0bdc481ad52c9347f30b0b6ff1317a051b69f1cd72955c61d887b2fff0ca68f49bc5a22761fb9505a3fc09b3fc0cb87e0b3e3d0c6ef916d8851cf53dc67ff1ca0b66f133e0fb2ef8e561b0cb7fd85b50ef8786f9e6cff0857762bc83057ec12eb805df6870fe09f7d0e07c16bc4383f3513009c7c801bfb841c60610a6c139e705b114253af576cec58d64ae4c2a4f7fb2e2cc8aa73f85c499d2d397b28848444c995e4029bd2feff4e6f42ae679d8f4aa099f3c157cf27e3ef6d6c3278fbeef34a8644983dd7bdd7b45b09ba01aef7126ac253ac4acc92072e53df65809fb0002c33a1fbcefba1ade7772a57d9e4492d33d8833ded3ea79dfbd8647de63d87b6f9bf3bcc7de5927efb527c1fd31b5cf913062aed3867c2490e1267b3922810c44b2f73327cfef46d0baefdd9f4282324c8e49843cc9b672aea45560d04f0fea4367b204f46aa0018579dafb0022736f3d8cfd08cb2092e57d9ce179dff4f0c91be193e73d9847df7923efeb8af92bb0cc29388859d2de753cef3dcff3b0d14f67352884fcce87386b7af75226266751671920aa643c4064c24b6573b5f2cffbee57430ee5ca769cc80a37eac8fbf465901513fa31d207c2cd9187c9a15cb532a593e67e8c992b99679cd1a20e3ee23ac76bed1c4dc3220d771ae6346c35bc6958d370d570a6614cc354d37a68325bd20d3ddf84e804866559668018dfeb6858140e05c5c6997dee3599fe419036927f99785ad5ac9fab0dca7cc38b194ebf99698e3195319e574215fe09cec2064b08622d1124854f17a8f00206184eb860c40b45a67015f1f372a1228ec1880e7810e40b31306204533c13406090052ce0dc60080a1c90610a3c5450a208424354e002142c21850b6292259a50e288248a900212f844f1391940c10c7a3084263c31849e9682cb0b5e2f3a28c2850c404e30051dd0c0c6064a3042838ec213714827db11d7a91f33f3781d996e01120001105860851218010a43c8f04fc651920439464b28e4100432640b6078094902178c90420c839024987821e182127064e8e418ed0109a4bb5bc0220a2ea088214884fc771510535ce108125960020a353232382d542419c204257c694812920cd989a28d88d1aab90221b050f23f3865734e209ce03486960d5e77e698a4a5c4ea6e392669bd2087375fac75840854629d2e206889a00b77340624b4604449e772536031c4e59cd0d2e4de22b4f45c151c548144122c7a902881cb1297cb31091244bcfc5c9b6392140c3591022c244981cf08b63ce79c1fde92c9a507979484962e5c941f38b92b49bc80e0d61c93a460052d65b8a51c93a420042c4e70bb30bcbce0764153b82b9ce042849b92639223861074bb1c931c8193a74d72840bb22cc724472071841239bcaf2db1f5bb7ef5639e3feb739d0a658a47f6f5fbb152dddddd3f1f188b080cd73f7eecaa0f99b3b7d9176b267fe6fad9c7f02ab3cf07f619919fefc04698f073f330823df7337733e6c434e8dbb79c7dad6aef63abdf8f953cfa70bea66ddac87eccddcbdf5eb3cfd99aeb5bcad5ecbac21867e69d281f027165ee7ef4deda683b9c59f30d7bae9d6bdbdfb62fce689bf623202edcbd0ffa2106f2fc1867b6efc78a86678d9a7dd0b7000fedeff3d03e763d00999f8f52fd7cd0afdf7dd57ee29a4bdf771fa32bd63e1fdb67a444834b7af9140577df03882bdf27e1fb318b3e763ac8558e31667ef7230cc495bbb72c34f0e062df7d5833f65de54090588510a4b005308c810c65a84246e989903258990c10009151fa4efb1a58b5d1d5c82ae55429d8a7e02036e0e1bfcddffc354cc30feef6b28a1c6a6fb32aaaa8220cb97e7735b4af5fb87d613552faee8cb05e46e9f340e4916183538d996d7cc08d3a5678e5b00aaf961f130881e40a645908f721678d9ae777e2a1fefcea03c5be707ea4e6766064c3704b6945054e0ce34fa6df12b336d787a802e30e3562ca45a68fd11d0210552fc20264fa5e0c6e1877462db8a109fb4e35ec57dd3b4e33b255dcb17b871e9e74993e065c6a1ae02428d31fa04c5d5408c9b60b4dc8617c92a9c4c217981135b9730f4ab0e97cc08ca8c9f5adec6cc46fef683c86e18c1a617d9461c3097b99b10fa4822e0141142c433726194293b150084cd2549d2bccb732ff200872f50747cd380459079025488425bcb27c2b7110334fda8006a7cbc498b923c6ccd711744399f940f4e0f1428108a345ba983fff07937f3271c61bb4b165f67cc9f3693022a40862e652839811ae94373488bd8d7d630c06fec5ae0dd7c11d31067b1d3f37bc197b9f4ef5632f8960cfa3070857c57014f6d8f7a040849143bac01efb1fe24c7d0c08c3de562c63b82a072acbc776b2c4c218858c6552568e0537ce78cd14838d302195f2023a9b4e12b363ec8ff3d24db39bf6b560c921e1f6abac670f2257d837eeace14a893438e3023a9b4e129b0e6dd55a737b602e4aa441ff6891069da6417f5a436de80d116e486926b5697db4a6c129dc90baa88be2a09ae62929eb54f3fc9c3853b956d97728c26a93aba4d9ca9f78ea6444b0496c3a32033c214bcd8df3e9377129c62faa2a96d5ef363e0257cad3d664c7345bc9d520db961e7b8a56624c471d2770b2632dcb6e8629c6f47b4bdcd913095094c0e6091b1bfada6fefdbfb97c195fd6643cc9aa669efe3dafb5777b42ac6a0eceef4eb6cd04fd35cf35595186894fcec83695022c9e92091e3907d00d91f8c33314465ff8b4758d4841bfa4de637aeea55b5379ab05fad225dc50fe673e430c52fbcdb17a3ca6f3e9806fd2b35b83dfd5ae86ba006fde94a6adf568a1ccd9d2f6ab555963f7d629e3f930a71a67bf91df631c27058bb6fee70d84eb43c4bf0673b5510637676e8b7b3246b79bda66d6bb52b6947e23859ced77c899870e37c89fec655a2cfa54b972e258fc9d3a05cd2e04e6b67a509b9d56ffc6689a9e5969cf3230d063125922cbf672bc6481efdea14edf1e994e5e1bf752ad22171067bf9d48838c3bd7ceb3e4699fb88c3ee0be564f9e0bf7138f49fac06e596656f2dfeace12024d68a342869f01cf29906d1399c2d15c4991548155d515612e1a4c1d4018d5ead5c35a38828f95264b96ac28590b6e62bc6c817c5e0fac71cd252b6e954385979156782206990a5936ffce4eef22334b3358b6cff30a6965bda8edc38938731b594b8a006720feb267fae82c8ac35e4f2252804149a6ece4fafb6cd6967836edbcbbc7d3cfc94fdf6356fb2c877ca36993b88dce42667e86890fa2a87d3b36ffbec66d4669f06c618ff0674ea54a3e6fe1e59fee179fb6e1cb28a3ca375cf06ee7b258b341844489c914c34abc3df60ec3e6c189d235bf2a59238635fd66b7ad06fb60fab8c9b94b2255d484e6e3eda6e3411a2e7001019a2a738042261f8105d6c2f9590b7e7beb02dee01882bf3f8e1d98806441fb3df089fe1207470c978850e464a3a159a4639b58e72b81c97ac3971fb5d5ae84d9c41f12f7d2f11c14e6d2e911572c3e5d8124e79894bbfb93a05b32d11533544b0371f44315821299b0f72db0fad90949c18c37dc8e5e4ac008a31fd304c6ef7a39c58038c941f06400c2ba9847465f985f729e90b691052846f463941c8d087d87038733044ae5c0eed4159d6e42a7aa4513892de90726e483b2552ce6db05fa5242d0a5ebc7871a301386ef0b4a63d99462c10aeb21fe8f409fd7e1ca24a0e1151fdadbdc82fe24c47b53fc917b1722862e50c032b9fd99d2d262fdc1bf3e795a11fde6c0a7f44b1cf7e843bcc590ccb80495cec79c8ac90b1ffe42ac6487123cd366a3894a138bca1f5903162df8656d9c70d6854d70cbaaacae8ecbb21699ec8dcd0a0d47aa362d42c3fb8ae92328c682f9f5c05b44afbfe1846b4efa6d1651007178b021014bc906d733668dfedcd0120b48fedf5b0c40906786e34cfb5bfddc83cfc7b58bcf917cacca0c175bff6909961c3fcae70dfe77b72c35f61444e50b80f06223952912311a8409263d79fd0951ad88255811d8d4e70e3c79ef17bd54de4863753ca5dac66dd0cfbb6d6aa6933e6db6ddbacc5388ee3baae13c518e37d3b1a89de5e6eeb2a0a6ef4194914cbaab691628c315ad98946d75b1169326f58664b39ca5d6e84822bdf7a9d0f2b049f2ab2109107538e3a36324588fc901c3f08a54e727c1ac4f2f12910508eab56503ebeb75c65faf85ee32a95ef3144b0df0431d543434c1ee43e59c5efa056f9cae3f7ab7bdaa77f1ac87952be4479dc67461f7f6e1f715ce13865c4711b674b5ce51c933afa7384fa903eacde8757241377b695a3344d037ac5b8c2619a8625e6b84945482d8da5caecd8b74e3121d934d8cf22b72802c85577283707544b5886528c1b718e67a63437cb34addb31cd26ccf1a8b0fc0e4d83445a5c11ae099bf61a6f8d3ebc475837c5c7513f8dda3eea9355bb559cd1d7dd2ffb5557353dc9b1cd225c0a2a0939197a4243d221b51c95e3aab1211da9285cc5259fd24f29a8245472d2a87e22de22b5482ed20da9452a426a71399680504cda86659e72247346e11c77d5d53220d89476c591c156188bfa502021934f8ce1388ee37ea440d2931bd45e8e1a12f2f9096a31e59a51cd6edd9fa89bc1bda8d3415652cda66123286f9b4b4991f9c4391e65d3abc6e6864681f326b72f2f2fdcbd19cfd8302c894d67c6c739f6b2c55c4d83cdbde0383087da4bd32a90f6d25ed5a7de3478c4859313a44a112b123a4485a88f467d546cff0cedbfd361661f981b9de086d4470753108e662a35d856495ffffc88beae3f6efbb81b56901c521c0dd32354892cbf6b10aa24911dd582738cb2826dc0802883a56a4444505bb5d66a692d951a96a3fa45b8e2744e45527550dc8a5cbfea6ab9aa2a31cd4f6b612c3a84ad2810a63e1a90e6c372150dea2ae42a4dc851ab4e695144908898d27a22d84e72bf6bac97d0c532773474982866540002d0cda0cff2846b8300b88ab91a9b23987335d8388deaf7d5ca949538cd0ba56c587bf1b88a2725673368017bed05a384ce06630c4b8ccb1883f2c546316995e994ad0bce314bdeb01194a7d8080b0be569045c47c9708e5732c546507e7ed5515225db2cc338529106358da5e6621fc34935da8b08439dd230ee06ce71295b11477f465c0b1ca4749d0e356b9ff68a31fd2d72704352abe52a4fc851fdde505d5d96894413d44141721051476385eb86a416a9857d6165c134c751f2517074ab4221a5acc0811b99e08e4e60eab04fa586bef68a33dc8a13951aeda552a3bd546ab4974a8dca8a904a0d07f4d32a144c6b39aabfa6e7e6c71594e34427f7effc683c3548a58606692d577147381cad8643a2b538259a8b5ba2b538269a0ed7a3ed703f1a4f86b557832cdc4dcd4edd8cecd35e5935719b660bc089b0cc26b82d1df6915a284fb2edfbb597d6d32a949b23ad52a969951a9ccb2131714a96ece47efb851c93dc3d2a2fee47fba9715529a851fd252737a5273748ce10951a222a3b294578728a4dee0f555e4a7248b279e968a864ec2b01b5f0011630fa9afd56c9289854a451fd2cba19da47825172c31ed485d16cbf5b32e1c03916658a8d9c7e9e9e3269d58aef3f61951a5c7d70ad71f24286fa501f134e3d52937d56301542c174c8843915ccf938aaa90f10c71363fa2be65acd15e16a389b3168dc13d157eee4834c3fab55ff0aacbdb056c21a90a3fabfa361cadcc7dda03c0a1948addc1c50de380e0bda0a729308436b4917402a36ad42f97e951a14acf534aa7f866e06fdb4d78a19047142aeea1367705ac51d69547f4fcfcf4f50909327fd2c3a1a2979d67c5be63559727fb1d66a942cbfc581dd8cfa60a7c3ccdad3d0e99092edc7dd68e1366d01e57e0b76353a6b8fe12c6bf437dccad2d4aa18abd4b4cd520506e758b339708e6bc6f03c00e738cb58e6629c69b92311a9e3eca6b108c04502bca52733000214e00603b4885834205e5ba0062b2bb8e1c7f0c5a458a0eeee94624e29362526f3a4ee0f4e0c9b946219c3308c62189d18c5e8779ade848479cf5ccbff9429dacdc0e494fe4e1b463e58eada322dff206dfa8539487fe18fe1172f029b06a8940c179645ec10d10c00000000e314000030140885c462d17028d01355b40f14800d889a4670549c89b324c8611043c618420c20000000040000044686030038e9a79673ed379b84bc61c0f8b408651b0301048105e2e98fa46fb35fcd229a6cbf572c0a942f0da41d82a02b8b977dcc6c4ac665a0a0e342f4710835f1f6feb1deba0cd1e7c4d7333ab9bfe4da659599425615583da3d297d0107859f3ccdd33462f63a43f920fd59a871dc228963b67cef06ca60882e5f6438e09d0f218d1b6cbaa7a6ddfe176a8ea382cb91ac6332768c9675ed693dca76d2bac85f40f5e8d152609abda3c646e999cd5cd55a64bb39a10f04d987477af93c5c284e0b13a0149f01ea33431ecd1c72e3b2280396de6f2d4fbc8885fd4da71ceec13c560a4c9a793ea70875cf32011787fe8c41b6dec1343498d047307b7654908202d515e2349474bc9056e7568a3a51e3b036a9875ce2370b4447f4daaa7f0cf9a1068224e0b86a117eced5ab3611f76512ddb5fb1a05df81e55529b3e97804b889f58565d024939ee624b3a0854c2c1d533984f4914e020983a0bd4b83824b5b0019c90cccbd950a330e4b9b35fef45b5dd658add3796b73d1a732cb04fddfc76a541bb1254f162a2b90cdcbe05bfefda9b156ff5da35cd4e5186f8f7d9f10ccb2ea7fc205c055405b3291d38f6889a7e759426098a62d6dc8618f1b63c9e863fd660513d9e2b1cee7d43ba6c37d583b195435a1270ff4f390fea69d08f1a2eb599e746fc260f6701e6d5813279d40fed90a916cbd941b5904d1fd170b1378464b1fc955417cc61392b32bf5337d6281f66c1c99a052eac6794c26b600e536072eec653441ed7da7af221fb58b11c27c0be130d21128eb1eb11128fb3bbba8a7536ca879a81a5975ffb2fe59929d80c2df8c21dbda28fa47c5348493d53fa7b896a187fd937a820d2128d7a165143d03d3a294bf5bafce7539f0237074e224d4925a182a4f745212123d39789f6d3f3bde6a714bea6c22a2c5d4d3845de8d0831e1b89a3ca345730b2ed050a2c162282a269dd511d0342791f0d531c6a74addcad7c82739a81b132d2f0963e270b905cb0b132526932929a72e73811ff03469e4400ec988887902bb89d6c29b6cd228542d7fca18519000373d7a291e166e235fcc8e45295500b485cdd404b49f344cd701fe74e7711ad172dca022c78201f8cbf03c42894aa3d2d55e53692f3fa7fd316916060c912901675771bfab87b39e87e2c298ba4690b1e8de03544630a195135afee58208fd53a540a132614277802b0bb1d7aec791efd0ca9c7881c17096c68ef1b18445d64b92c4e8d332b580b9d2ba0c9c5e9f002a21a35c9209c5ca8458dca0222c0c5221bbe043a598dc438f594086352c6a19890314485ce13ded7382c36fc7fc4f7702a32d45a0056999e254f0bf11f2328fcdefea256a90b7d60f99debfa9663036bbedfea862cf523096dec6c30ba28ac3c7c942ac1c1f82e1530e7bdbc3cf9801f799a358afb10c740ef33d6cd90e2c7772d6e394a54d7814fba2c505ed1bffb1721eb2cd2c914e517202b109ac44062327886b5c1a0c971069092b55c3e06e13fd8458da4b65a1db8c927f3bafa29e3313cfbe2a3c065e4ab87fa6a7336058301b20544af9412945765ac08278aeb85ca165b401df0a11f650ead212e88a2b342c461307364246fdef3c557f689640e03a95c81d05044f28a04610d2ef654a083ddd12f43f835669703d68b511a0b99bcfbf0a3d032484096d8a584d104fa414eea72bf143191d1b46985a5db038da83fd3d26261b170605dbb95abe96950338558065bc983d4fcec77e934cbd09f098eeab1ac62fa56dd826eebf0b8b56859d6643fcaa88ea6b93caf52dfb1131a1443b610682dd5206715ae576f3b7c88c8cfbf9bc973dbb564b4ee534225e7321023e9b8b2a74d510d29eb565c2ac483d5c552dab413357add755d40a36e75512213c9ff6aee02bda61df985ea212a0e747299cf2a3ac76d596ba34bcf87971f17903b992015f573100c3d10ccaa733ebd22ecfcecef788d39a9367cbd9e44efec68272f2ca0ef2320c6f6ae1b97c4128b77c88520df9380d9d8f6b9a2966f4c73ab62719bcac06e55ce8bb8ceba8c38ce6fa5e93cf67a6fdea23e4c9a159c0a0257955599eae22516963a9c977efe99a6c6bde4656c218ebd72c83dfa1b5e0a50e9bda1297d6db5aab2bee449dc99476d88627b9e64e509d9813aa8b31558188ca75d58fcaa8a49f46e3167825a2c5f5ce48f638230172aa44b7e00e89f2427810c8db3752b9e49cc5bdad227d5f2a225475851be063542f042688dd487e3d2d51535fdb41d1368f41e74b8fc6974ab3282461329d46cf01291f49932c63fa9b970780cc41dd47bac971b775182385226e146c621c3e8dbcff37582e2aeb37854bfe93fe06a1ea8208096c76b56b03c5da15ab96e7c60f7ea3dfbfd50b5853fdcc5a726ca7aabe5c056ffd35768a731ea1068f9d9dc68125edae6c24a6cc0c2f0a7d863dd7e913da23d90174580ec89f00e9f668dd8bffca37c9372eeb859140f03e8145e2ab0f9039489e3c0450e424c078c793e621fab94c3e58288d954bf0362ef8979c2406d6a07cbc3b6f75c9192cbc21cffc4ef11328574256e1876967a083a1c5c60dafc55c1fd24ce861084f694d6e8ac78306f5e33fc0658077197ed76aaa25414911acc8119b4d23cca209840aba63294b4c5e2974ac5442394ed353d52ea13ccd3267bd681503782f47893250100d5837d8009604fbcaecf51a7c3c47fbe369c0c2bc7050b78c3807e8007aa889876b359e5b3c0cc69da72900980321d4ba2f231e7fcf5cb321870d04dde470697eb08c4233480197bee084ec70175aaf0de6bccf7b0e0c3147b2f81c1a96935c98c5e48811c2680a163a5f2b25b7abdc4acf8986b6db134b9d670a02bcfe203134cdfb3d361032b1930f999aa3fb762c46bcafaab95b50e1775cc5eb0dd54dcb60e13406fcfe0b7e062721a9441e503ae197fa3c1262ce751560e89f4d6f37789c90429101cc4c772ba1b563585d95ced93e9c10e04c06de5df2947b1c2d09d3f659337390d111977ff970d801d56cc515f22641651433330854bf36b65b4036a2005acd18aa348094cace169cf9a5d951282595fcab4bd59b2b08d232b6999fb5ca2d7be494fd1d04baddd76a33438fbc31c58c5056c6bc2b41faa7d262a28b615c606812edb3c215f4b56614143ef3ca195d2075678495eee6a50243055e7a20a417efa88cd9b4858e2068974b40824c910db676f83e9bd20f399a89444b1fd8d899a88440894c641ed64eeb8d564044107e6622c02ab17287dcf4a621840ae0f101108635413e3af4e24960a50560acd8af01515dd76ba3042c8c9bb2cd67161a9e88b7ddb227a693202ba0581ab2ec30df3812de1dcceecb9a0fb569a672960ba4305b10b4ceb0fc95b74f93a4f4b0b0c2b7420ddd96740cb311375f59ccd56e1d42249849b06cbe91267c18d4fce1b8ef65df413b8749a0f31a977266eeef9209316c5d6ec8904069421894a9e8ccb61acb04eca69d15cc64f8416633aefcb81a591eaeb1da932cfc057bd9022023144364d10f50a2c917a8df03ab7223d9a0e615d76f9d1d5059579dcf9f747009d64d4003985349a080f0fcf03fad20508c8b721e32cf33220aed002742b112341434d3e8551d594f9ed8c38b96df4daa0692a39e64d9b6c038c14e932ab1595a73ee8bcee998481d890c267bd160ac5d0ff3fb1306e7c5ba538dfbb12f462ad4bc8ad0cf8027f49cc5455fd1a96837eb773c0ea128d80c01689a32096fc546a4c0823d05320cd9b1a6ead069161583287c0cce3f21a24f72493036b4af4b979609d5040d7a9990e82d306cd06e3ae61a8ec7f60eca1f3412bbfbf9a73d8c487e06af8f0a6b2379cd9c25f7e57957132fde60ca00081ebd4f5d22971bd8b3c88cb90e09e03af136c24b91a5ac2fc5551b9f449897f0db084a023ea4f9847a90eb364d9739843643eb0604047b4ce949c14b0e909b026257ec9c485534fcf8b159a4876c143b50f7a2da2d45aa2bf2740163a60ac1a537bc8c84161007c35c0265da97029e165f319120b79a8df3e0134358f2e7d32e38e622df0dc0c0c1d26ec6536d9b5da9630916e59c91d37b671926c5f4f8238eeb1df7df67bcf1eb7100d0fff3ff4820f2424e4314a55e5130924f05f43dd9c074ce20b5520e6a53092b4423ed69d1ff9c4cd402d8ca4d7a9a481b3a501cfbb60ea9e9ac13ba32fae05b85861de080459c567d6733593f1035667c57325f4000cad5425e33338086d66083e62fd40c693bae982ef8fa7e2eef627e028156860ab24b169586a86be28a4fc2a899793bb474e2cadfcea584d379e8cd0ca46785184caaf2c65c6884ef91a7ceefd9e4fd1e207923b0267ab322e00d48373d4a02fe287cc53f2710c799ffe94ded9ad0eb26eabd60e8eea5e898610b7e087dee323415a864496b110b3c26bb05fbc755e28a2b62fe178381c224e20479982ad153022664e67e6447591896c86f07f784a03cb5c223c4a8117d99401f4e07cb5f08f5526a20b8c1230b2c534199d0ac1ab3285e12c2a9f425abcee01229ab1c4487b6bfd90b8b9f381241e449a0e29f6d0dd9343b5979b7d7a36d2ec5465559e53fac0a0247258f4c5603d0f3ba22e470b7dd19382767895aa1b40519030c53017247999bfb6c0776b534d1fb864c23938ef2ed57b1b57d43080c0991c39d406de262908cd7c966cba1b9eb56d9415d8f3cfbf2e975ac96b5ee1471129cb02d24635b5b8a86a95506e30cd1ef853a823ca5ac570d77c240dcfc09b29290244e097e3feaaf17f970fe873200447c821e554f5e508ea5712b7c526610f56bf63038d9a6a3be7d3ae7e828155c1a87fcb4878453f1ca54206d32950323b62daf67f9cd4de9366256d34abab7d7f35f03def1c4e11b8ce51bd25b24c7ca8dc6ffecc9e8444f44a763eb6d6e1d7332744e236f4183eec4a7c06b3d1ecb724bfedb96f028fa979783991acf093640ac03b2ee392b8bb753681e360a1aef6a3c5232365075836c2ee451d5bea3b5b2ca385d4306b9f165326769af274db0e03a8d2d5e0538596cd3d25f5ff5d8e69c2777259a8e279fe0d86b5b03e8452e2b944d6bde7eaa1d5927a983e26e1b409fe1e95a4be5c699e046deba86732174c6200977f7e119bf37bcbdbdd17bb7739ea213b87f68e29c6164961b471b05434ff2cbc2b2c28c1825a7c15734bfb61461e0fb6e6c6e04a8de4d4634cfde01f4ba7060643a443303fe90376cbaa7a13144990c2bced8d1992552946e17abea5f5706675ccc847a218c20d472178ab8e11bb89430ca640a62ffff536cc103abac2d3d93d1b499cfdd9a39056e094e674f4261c3fdf8719b8af0dae8a2808376fa9c750d7bd9e473c0f7ca88342b05d558eafeb55fdee40664ab8bf7e87f54b5d085c35a4ac367072da6d8a7778187420fe2d5f0a60fdaed08b13a5923ff2a7583bb23d41b49c92f85285259ba1c8ed77ea3a2a64faba1d5aeac2850bbc2a66a75ccff0a90746515e958c3d17bf364461f910f4821b2d1943a7dba9268ea8c973070a752aad3c49972d18e8477703de759687bbcc4805dc4f17efb6308420035c6a45aa5d50a84e84ec5e43db1af37b6b98970c19e5eaaedd5804cf6e8b0bbe3942e4827c9490d640d37b1ecaaaefbbba41b4ebce550c12e5986dab280798d4733c5fcc480694e7a201d3f4651f841091891a501bb1f2248f49ababb1e9a5c8b832d0153348f08d527b3181a3e98397211b9a33e8815906f8864704c951ea8c9ab105eb7748d193c6d12feb788a291b5493c8aaed6bc22fc346ea7aaee8c7c042a23458ca590782fe8e21c20ce1f6028cfb7999158411954cf7c65948fa71ca7a12876b10b44200ecfbe99045f8878599cc31f48627aa48d0e990329bf03abb867f6e2558560ec5ab8e03e8638b7067dbe5f01dd2a9fb6dc613ab878630ff2b21f5dfa98873c7c49728570e4397d56a445666659e002208014f13618f7f896e862bbb8a4a24cb0a6ed4d6e0ec4c1642fa0fd4ea0019d4f84931b26e7a9c32a668aa592091168477d3cc51417050c82f78d5954ba0ec5a3597f401820f6ee108b44fa15dc8c175b946f4723dc508511247af9d064c7b95dc43afab6109a2aec207b0ba1636e86d00389be2143f6ae443ab1e221217ec460971a3db63ce4ceea2053efa67b6e3eeedd416b0951b16deedec2f8935e81dc130d95cb8aec4d2ca9371d9d26cb1054c657662c4bf5d0706effa6e6047247a18107912370ac7320214c3e9cd479ef20b1fb566c692a021a855a400ffa6d0e4fa96622d6e1f993fa46860fc33deee2dbb14ef348a3e0e623e928b5456a057374234bc9c556df72f0edf7ca668f49a2b8e362bd9a5b95699e02e99be3f47b305e50d58371a4e72153d7225cfc77b959725f50b457eef4f56cd787a038c319430d8cecf9a003bd7d1784936a8516e08a4d01b567f65c7d7ba0a11123eff6a0035ddfce0efb92ef934619f9ffcbb135c0b703ea803772b3f382cae9578e6ede8ffef490a3f11e2db3b1cdbbfbf5b832e88b26a0e802b24f9f4729b209ec50fed01b70c0bfb9a70b30cafc3acd3f9a2eb524de4ac89621285584e0fc74cc7c775968dfcabc579b1888111d8b7962eff9d7bb4fd0122da3440749ac5913715773d6c51791fa06eb32ec5f3ac2146b67882ce28d66c90dfc1e0660da61821c07bd0d43dddd8ec6868c52df5856e5e36e0c82c4a1f126b02154b525d79bdce34fe453e90a73a111ad12fce58d15cb9598aa494eb022e5e170e267c4c978f0ec6e677a3e63fab0e10d2fb974b6cc0714029af82e7094c67cb7b76ebf48f0d6eaa09c457872a475beb92f0279a6f37d7a8baf90ea9f1557e8feaa4d2c9ec8fa28f958ddd1fdd331f69983ecd08ffec8bb263193d4e49d714e63d0bae76a52671964683d1b90c5d50087cd61437c8da518ea3fcb1d801533e52b90cad6169f461e075f337012a29ab3503725bbf69ca166e8ec5d9520bb97ceb229408cd932ea78e12be6db28d77602667ba8c45721d465dd82f9ba62f9078f0f56656a0bb3b42d794dfed90d9d4777f627f9a36fa8fa627182fb4096182a96ea5127ef9b6c892e1ef7dfecfe336dd1d589620019770918896b6f6bdcddb27c825dc0cc283a38c4cdd3abf26ae92a6088080d5a941558e9adf36ef5dd3616685c564e79892204b8f6a69c7593c221b6425f4d4a2090edabf0c1b8715ed9216f81b3598eb71fdf94597ce20e61030cd92198c3eefdcf44a2e814d09de2f37543c8a48e70d511b37f13cdefc27206a51b91c180575ed07ccdd2a2442a94624af340010431a56b20e9ea867d51ec32abcbf4289a09f548fb81c1fd0717aa13935573b9e53e70eee9c83c0a371ec359dd4bd69c6090c0abb4ee3224f53305d07a228c8b16fd429083d881b8a6166db5aeac48c5b5c268cfeb0e1a287136ec2b0dfa4855bd5406eca60ce627c0316a6bf327367da6f4e76d97da9fc5f37ba70def7ebab780364d0c776dcc6326a2003b4dbed9aba8220cdb5f4818e020de7b57bde3366de6ac174c8e15671de21fe2adabd76a1075663d495c43fc59042aa5034865ac1e9e3533106b6eccf8953f3b57d84906af652e2ee05b5c867028d7d660042789fbb96eaf035ef11a0b3174ab2359546a12bcf2eadd2987edac16e1e2546cf780c0624c456bf9a192d1c4565df5b0287c85b8e5723cc74eb9e001e89feb577625177e1b27aac14b2ee742ac942ffcb428e39b49e101e554e8ea2806c590e3b7f48705a7dc1eb69fdf0ccb1ca9520b323a7405bb8b0d5f7d673017d0599d09457c693cf76410991012550bb92915b6efd9767a793c4019a7502e08446fd3eb61726a7ee40f15bf6e30e523a3620b220c27cfb61fca4e8bb94cddb3689c1ca3c00d29779cc0d132c7b78dee3c09efbbd2bf867952cda347dae8004d2004eab166e84d80a795b01dd5b43a69181b15ad789b8341e02fcac350121731a8647d07948b8e61cd3c5015ff6a76315e392be50f00c9b3d32feb7cc9965a2cd76a6e685462c720a0c6f4a465154dcacaa4a7066189d0c4b1d49bfea698aac80fe4199f647cbc65be1eb12bb887da0fe2942d3b07cfd2d31ad06bc1045b0ac96e8b8d3659fbd026e6c2fe1514c2b901e22f63269cd9466ff5b2e412ef72a816f36a8d5103da8fa2538dee2b7b88be9a246cc538ae285fd0667e9428f501a6d034cc4b837102145d0ac2988e2afbaa3dc68d5d0dfd2c32cb5d0bf6c1c872ff73b5d1f35caa75c00dbc9d232eb3b788025017718b88fd7bd2145fa785fd3d25c15b54f0ba551b5b24ed28e209280fb418b006125bf4a5a46a09fdb1c9705b4e85b3e10508eba5b936a29d4510fb6178bdd9fea0590cf1e51ea1b86f9b24c0c4028ec7e3af435bbe94197ac0235f9c72e8bc760dda8967da1c734392e25a7aaadd9389c21104bf0179f9aebcc9645c47ac83c309a890764dfdeedf966329a380addd28b2be0c9c4a7e650a8ab138234d9376463dcbddba6c8f47be538c651a5a2ed0ad1832e01054558f5e1452af162907db2e624198b96bb645dec053a388cd1f3f6031dc67eb68a42934dca141ec5842810caef514dabb40102749a7d06786780d28acfedafe71ce9b95e5331806e5fe1aab79953d1a469511ba2fc36dd04bb5e02cb9353321775be0c179a0469a2fd78183292e9b30ea891180e8ae104a39081986c43db55b9edfac6096e4d5cc468f8555de1ac24018b0d053a2a957a2b212ce91ed73e0437963b55704ed1656a99767ea81ffcb0cc82f969d2476b5f574a45e6af6da19b26f9124ae3b9d090385d29b26d6ed920f35068e13c77925d6f7bb7c72821294f9412239fc6159503fffaa51d79038401918548e779d28fc403151803096a898ba0e43065c6a53e28cf590c679c18981ec64f3954693343e7623b2efaee2437f877416eb46530d0dc3caa0762efde181a7ffc671fad96fd84affd2a03658ca1553f7483004f9b891d875d1065b52d5e0394792cb3c94d39050714332323769f5962496fe01e7567d6b858826024446d0cfc6ba158807aaf303810b4a2ae70c91fdf489554c5bc9d1f654090ac233554540cdc41640bd882427756a01b78608b4cefb5930e075485e094cc3e4dbfd50967284bc10e65d933fa635a14593a8956a8e518e23cef9d8cc00af0dc8a63cc60e33ab641648888ac3b47dc875a058424a2d2fc9d5f8c303e7b3ce7f93b44c8fa7818ada0bd3e4818e8bc0731ab1331f99b7053e7de0f4ca8ad331516c6f584aaae903909964944b549230667aa9d43d4a3fafa00621d446c0c439e8d5abde3418ea00418aef90c3febda25da8622bcfb1667163e230f6782d82562582bcc22fe2bd75af44aa547b77115382159ae47bccf6e431042f9dab285a436de5974379f2e9f14dcff21ba905f9638056159e55fa34b4bdbd2b3c69630cf7a96ad50c0d090f9b038a5b5823c3d4ee1b39d8da34f6b65ea0b8a3d4cc4cddcfb3bff226c11c6a8cf76f69f3735cbff51e196271a12a004c85b7009044b4b2729453e083d88631f8bac560ab40e4368a4183ef41daac5d3a7b10c7a574801c8150d7d0ea55535cb1e8cf57a8c61c24b16a8d3ed40171da780bd7f7de0e2ffe610a5dea567e892cb90041f7629fb74eff4698dcf84484c64c403f42a39887fe8d58f1471c3882224c42dcfc9422d291ea140b02557f1e022612ead063d126042f20755e3cbc55a68cdff5ad516b32711a3559c962722f30f9e7aa2cea8be6e42765841975e426502945b7ff3608120a07340a0ffdeb1f4f69960ded5995e99c76922732cc1bd960786fa8cb36f7563dce1afd8f885ddc6c5b858dd22000d3689f4534b3bd4c287cfa45d05ade8cebb5859073760911452f26672236e7f38600e2604714a703e0104b88296b86480e04e2c2125be407282ecffb7e649df0ee2927d905b80da40addeee2450df177ccbfe1a2c32902dc9c7fb5096e58091dd224bc7b4adc4e62d776afae08b1a400ff9daec4ec536c9f19f9a1133bd023fb6cc4519036c763b2a399fe13151da841d410ddb3b5c275ec63e1c6bd7fd7797cb66138dc60784cafed4e35e3b71b8179898c1d55b782904a7697a6698f097ab4d74ea83246794c92c3c7f3a9a0c82f070e73b6e22a248d1daac76ef882674324b0a39ac0bf28e46928cd351fa9538fddf2228f37ce66b279cff44d6644882bddcbbec6c64076ae750db884bbe5f689937e93ec3e0de2d6c162609b25bfce9c1adaea2ff0029b7d4895787672fce844e58b63173cb62917884ef0aed70c2053fa147037749805ac7568fb61cfd0fe681460181eca998ad2ffa5ecc220d4e6e9644d4ee0f1f1641a178edb2a41bbb76ccb4101b775ed3140ef972147f10da015f4baa624c24aac4d4db50d7f1247bbcc1c5ff0f765192b122b451daf63bc75910d9995d6fb5614a18309accf3737c047f38a14c345626d83ce054b509628b5e546a26f000c061faf2d7f2b1000d5288e985dfea1e6ef8524321a984728b1db9890dcceacdd8e2a717d32faee62732bce3f4eafe7faa8f83e13a17d769c7061501e01aa4782720b9862cfc26bc70cbdd2e8dbc98be67da6046e13c384531076b479d2424454c62f79230836492317a4acec936768659bd75676ea0454460136cb4bf9dd0c55cb2cccba515bd283009376babb8ef42e478cb9091b60b4b900e2381a05197f8a49ff20c89a1ea40a3c5bf8d447641d81f6d4ddda510bdc100c95ff4f7bea0cd7e6bb193fd4f021bc7aead0ffb6e1baf93181fe2bc105c06dd3b9027a2e61304e821db621a42091ec7762b3160fc0d13bb73d8f299ccc861aeea3be3af95e49115827ed216ef012cf8dd400836d5e8064389595327a4b56a6cfd32633ae56bbb52b56cad0a9129d9ca4a1246087724b7c100ec763eff2e0780cc4015046f27d6bc38655658aa468c328dce25c1bdffab7db5a2175a209997fc9ca26b58fc42094590606baca81df9581a5fc07bd5ce248d66f2a0d17769cc0ce1e6815892d8f45b594fc67c9d1540444b9706918e76dc93192d0492e7069a5699454ddd80d33f9171bb02915b0ba4779f5c74b0345dec52963911e150c38c83f8f06aca7417b2fe4599db9892a2524734da2c1744ccacbd60f32130021372a173ad470b2cc0e1c4cdd784b659a6dbcab32e5a17674955e58439f1f5674dde43fee4611bdc12c47404f64aafea38d80817ce66fe374d660b72a6d11487166e2c9bbf9ee410424128f12a0beb1b271bbf3cc5f0d11b6853d059ac3517219cb25e574a36674951d3da9f84fd327048c5fb73b05b8b09af90b2290a461e462db7492b83322a93ce45cb944140bd7808244a49fffb36cad2d91e0fe4379bd1665365c68cf565df15ac03098f412aa8804d6d4503ed6186858676ed6b471b90fa1f68643104c68563ce5da9c1a19e2670f263972a20e84128870f143af6f0f9cdeb4c4e4c7c94e25835fbc2b5084402b283b47c9fd321e1fbddd727c6994b7b45e95971f5bc50f8bfc0d979f25818783de68a597b2ef7d8f5683320b7fb0dff82b9f1c0f95023fea048da2605a9a8110364138230edec69fba5083736b223a8a585b0e95e6a2f4125e1164d9ad32f9b2fd142f6d1ee3456c355dac7b11209996887c73015aa1fc9a50d3af32db695bf15b50a8468f863d26479cc19cd9853a8af4a8bba4371a26bd4aacec34df1021a00bef7fdab361ff91d0bf99e29988619a8676f074d29c61ed68ab7cd3ef20709e669cb4c1829561590b9c627b1c4dc443ad6f5094b3c719e191287aa993d99280e0376ea7cd151e3695f2995627cbbd800b344ac232e82197917d615d619c602587a0c17afaae900a218cdac7803b416f60792e8e95cdaeaf5f5b728d1c8c57f1810b27a312e849b6d1567d4dc11286106378e23e84eb016e5ea112ed1538efae327bf50fab5af8e8607d2b3329d6f7747221d14b11c6aa39694fc86444d700f75e0d06a58b5d85965d133c7ffd0a992d5100fa983510464220fbc1ee1a0983f9624f3837b4ad9c2078118a9debecb06969a91077912291fa1b6414f5e44f1ec4a338d153739a9fa1b1cc24173a4889ba50d08dc91684a4106c012ea8b22c12f3facba12e4161f9ab89383509341ff38118a0056d201de19743838362b0e5ac5738cedc6086427561b3216ac5b9a9b165565715387be7cd7cd888833ba95a7974e18ec7436e9b6705b76bc837cbb028f235795f95a4d9c84b8c68f74935cf3d4ba08837df46b2f41e6c917689fd93994202e180f6e70b5db4308d0604755936cd40e71196db472cbc45aa798962796749d89a22090403bb0d166386be5049fd7a38c3128e32c9a1a586bdfd42a44cd7fd86e490863b2e53a52d2a28663ceb7b1fc4aa21c63c7fa8ba7ad39c2214240335bd36b961ec8b7492f761cc8982a0a0541edcbd70de21818b1b5bc74823a1a472f98857e5178ad2acac56326c883aad6a6d29b06381ef3a9ed38b554eeacd9ddb1db5ed6891f4ccef11c02c6d379cf3e112762dff16c45e8db03183f8da5373f6ac638888092ada9a3e818db64e472f3546a54e10b32e021ba97a96f828719c5a8c3665f34fce5642e69ecd9f938c1e7f1c8b26428df3b5f8e3fe5da239863f6671a18e25edab43b3b3dc2720e5b6180ca47350b0928b3bd2426824313ce47ff40cd9c5f1b94ebca42bcc76679137c6c9646ca836808856007923c6ade6545cbf18207dd3b2dc1fee10b44400c9ee39685a88e1ed7054dc32934a1af1762c056296ea7f86a448c29b57f7124d13b746a2d56f27882c023ff2ceb61e723ad9ee68ae7c50e6a355306afc92853e448966f1470926592618f0233b135bb477fafbbd4f37369b630558be2021f372e76426aaa5b0c90fce7d21549d88fd9bde074d30c73de75822941ded0bfc36ffcb4e650a66c82944011177d991b358163b413b45e613c69f0a7309dcc6b81d1c97165ec8a8bb9327178f30463c9ad957bbf3bd32eda7dea60b951748e5aaba7f4760f9313c76ac1440aa45894f6d08d6d008a2a75ffe97b15fd594054e749074706f91238ef9e559341bd9d8ddfb2b62159fa9da6fdff286dedcd6a5a7aed2dd7ee306b9ddd2c7909c0546e91e108e4728ad2443b4e0ff45bdef538ede6f7c09043b1a75d7097a0ce50bf6139e4232bf9a6893b19e1687e0b8a0930c024868f37006c3af5123263ccbe2a311e4bc99350670bd5e89ef426f9152c2b200457f86b6246faa48d0049a4be4d36f46f717b67e8b3cfd2439848d43c9be362ac1f995f8deca7809be3443205e8fbca76920a015436c54d5845a7962e68f34a16af81f5ef9fb12eec1972fb61f2e8ba88593e07c04fa923cb04872db16eb1c13944cfb17ecc40c23a7f8999f874ba0700564d10ecc5f8dc5813c03029b2bd50952955e431fa15fc473729c85183369819e7d78c9e671d901b6cb6c76ea705cab81219dc0c565f19188c60265cc9ba3c4dd7832c2205610aa9213f777b61ebe37c8d292d0ca11a4778a4ff0c9e0bc0ff61f47573d557ac6bb91a738565714805e2f230325230dfba1c6c4aa6de8bc7f21ea163986a631d6051d0ceede56a97986524bbfb90d9d4c181073eac54ad7362b6853c22a90506ae15212ef81b9d346094bb2be711701e763c9a1f863aee03596488687cfcef9a8588637357c78a999cba878c4ca76b989b0bd799a33d345c886af0842113a0dd35d46511d42447a0e7302438cfba989b247395f8428a18ada2c6676ae4da77115e5350667252a1210efbc865f6f40a9aa785a2dfad070e8a4c13508958d2ff034e95f16e9f48a4ee02521ddc2e3119cbe9c04eb45d03937a0167a5ce3d1d78881d2e236c61562f9417d64e92a1acb2cefb838f63757cbc384bb8e520690748d58c1c059d3a16ccb521eae07b10564d01899bc1a2fc2772a0be0470b2a88b9b5a33b3c672ed29cd5597a2855869c00c490c9b510d18c9809ec0a10dfc244b3c233cda83557ca0edcd41561e71ed4eeb602dc1dabaa623aa395280c6e0c99fde914e97923d62367104e40212a3e22c7f2688d9d38f8a69f22144386421b4456d65aa144a4c26766f1c720382c8c03d40a4fe89d4b1b3e6aa60d76eed9c3eba074350f6bd612cf20a4f73c2443c13997583893e29999cbac8ad58d3553209aeb1bcca6f65732fd50dee96c84f48cc9648e0c4bf3777f17bcde68d0ab30d321b31c2e8a82cd8ce2fc15411603cd55abed82f1fa3bf7a6d79f2b10748a1c021d42b2b82431a3844ffd353f9974e8e80d42f7ed9d57cd4d283d1fa1305f75e6c29adc5dafd6e0f249e6a082110744b83e018003e215f7e6093c501bd898b0d65e64778967143057ed3c2281b471d76b1f29c4dac25796d00cf838b6e335cf842d5335ccb525ecef1941d56dc5cbeb5617a787c6302f8081a760cc772156de57deaa6ad40b66fb30ddbb06628822c6d9d38db08abc0a9424cc1ae35df26b92ec458217b7ec604869a0f985635c43ac91d59da86961a9ecf7e9dc60670b0c09e9269ae7036bf17d158d9e3b214a1778fab5f1ea4ecc4354136134c3e71a26670637ff73605b8daaa282e348f61eb62923ae333b11af1bd83f49cfa55588930a4c3e42cf62eb24571d0fe9f9b6631ba111a15815af9823df3be2e7ae75b1555a3b7a13092ac21ae0f554b459fa14ba382bc326a9a30d7aca4609f46da1c2ec19ab07adae77787cf7f0f89ec363b850a8512f174bbbba0f0dc92fe04cead05473e0449055b1d8b44b6f24deff6b66f175dcad1ec64a8ecb605dd1d672e040b676051e94828cb87ffd9fde05cf0b7025f882a8c4954a09976537f75b25c3606e6389e6570097af072cb63321db7207d8a3f559de99310c5ae317bbeeac7a42a51c13a84f4fa0e92ea566c8d92b4c1f227b46f5e4c172fc663ebc490cc195ca79f7aff6037bf7acfe4e21b34034ffbc59082fb6dc52249759b7ab57c4b3ca4580d519313a10ecb897f7ee4a69c9a8356b8d6003865c6df97c95c023acb76b17ceb42fbf1d74a72a7932b65ae38f9af0418bf0b975e1e73c08b4b1411607bd1c5d5f63b109a848b709105ecc233404352d788bacd76338d5b9329f2ea77b99c15d2ebc7c856677d8f907fea88728414f5e0da58edf5e76c733acd8aca27b8a0ab9ca42a4177e852b282d8ca63b69c14cd543b3fb703f913577432acfa710325f472797c1bd46a58734c55262030a6170b1aa7bf50218ccd9668346b11974eac4697a4eb7c9000e399d3f3a9703e89e314945320bcc6fdd096a2377c56e479cfafc6c0e56a8b4bd3f61156789362d614022f5d5c5ed80e5515525814512ad406e71ee94ff13cd10bcd5a6d618ec3acd82ac21e77df4e23b099ed1e7aeb1e242063de8b7fd4c184e9dbb81ebc7bf51c92b5c363c22d20407dc9b22839c741fc829d768661ec47a2a6516ca3e8aae0f603c595cbec16fb9a3c769a4556f3d8f0400ed3cde0fbb3e0d33456534831dfc5d454f15d42c3f23261d5c4c10a48b2839a9ce3a32f9db3b32dcb652211fa2052da6e2ce3de85785935b2611d63ae550e8ee7306dcda4b1c750e5e974800be02b0c79a2e3826a45af2975420a0a0248ca1375c302420f55593020b10b207b470fb06c2af079e14f9b8f566885b4f10fd1575674a9fa06daf73d1da8ea75933551a05b6c17c5e330958f1a7840ba4a50104e34099a4332d2abda671fbbb5ef7e76e6a617b7c4ac676465a9c3e388e6abb3f40cd36c080ff39a8691eda22bc6670d71eb9b20a09b61a39084d7cd444f784a3beb6d70055eb97ef582a51a578295aea812e1d4068d3677f0ef775227e33617ec10d56004a33655244b722562d0f961fc2c01b4287b59591670da87cd8f20b75f4ded484e86c8795fd609674d6c8d1a16b10425d63696b32e174921e9ea1522d1e83f1dcc886d2213a895df8b9fa41d8225f2caedd557f0fe069cd71e533decfd80f710fcc4af09c3240d925fd5b7fab066860b10cbde729f930ddc839f7d840371242bf04a32613f9535ffd5c7385824d0ac7514a298e577f7cac09bb08384ce3faab28d8dafc553a48347fc9412adda8fd379f261918494ef74a82e664eb9d42660b13b46206cf49d2fe6d58407683895c42f4444fb11d86b25208d191711da790a988a26684e22538c4119ed4032b4b02cbf4f72160364674e582996892ec0a7869241329f2eee441b3299dd30eb79c2150e7721567327b6afa498b4449d376c285dc9d9ff7cac07dcf905ec288193c946eb25c306923b09a756fd4922b85b341af4d7125dfce1589fbb48c89de6aaf9b866cdbe906f1b7be0bf9a1744d59a342bf609a0dd287ba4821080fb34021e608f4aaaf5c0540ac0fa95b8635fdc2b49cd3040c3a1d5457f84aa3860913149372124c3c54c424011772141abb8898fe3cfedb77f6dd42b9f425c3232d5f0199dcccd61a6ccf6a891b524bd31adadb08defce71b230c8ccfce8d10fa140a48c4da84a6f17ef2ff3d3559236aabfe177d374cd2a0edaff0c2b1009a70bab0481085b126b3e99167835509e8959923bc81a499cd0c377ae3029a13f34d695d5e531dcde1466610a939ba922bdca0acf4a9ed1ac5e276cebc8d7f654b826335def958dd535a261be6436215a265c768d4f83a97afe4f676a595e597e3304958f72757a69213f6769337adb5b2abb3e03a60fcbed9582634a02ec2327776ff672ed33056e08e9cf9de5927f38be0008828b0e94f0ebb1971b0c8cb1c34be4a0d958c4561aceb551a12941801b1fd95fe5fc313250fdae9e02a95cd4b8b3d3a4a8606170104ad5c74d4264a44980465fd08926b0e7d66d7249f8501af0f3eb377ec3e886166bfd71523230f6f8decc9542ad9b3e8906466886e6f1512af320e674985bf9749418b6ab3b0612cef40599bb26d3cb9cb93710da9d5bcd135939807b20d17be6e5281bce9659abd04539a3692a35ca410edd55d4c0fc357230318123de9e8deac393da9bef45a5f2bc962bb8017bd799f558e5378dc5f64dd2ee1d22d6c41ea0ee91ff7ca4eff98f5f7f3d20468370ce0f685fb05e8814ee84edfda347424069d3ed7ebe0dc28052026c6053a43aaa1849316c2ecbac2c52da94d6391ec381efcba06bd2e839a000bf111aa9b178add626b0db9608cf4e7f9e116857a8324ba6f4feae96958729a2e409b459f65f934d22df1f0f47d2c6f063f6212bbb4deefcb4dcea871c61c236808e52fb8c45be874ce41c44c2e8cc064c6cea1d9e50a0022bda98b07cdac81fa7a21728aa0450e7a19f33cf5417f6a7071c8145319b015b27a605754fd901897177b7ddeb6d1c04581f0ff782af542e28a5f1515d76891ce0f2c9b50b3cfd8e9e3e809d1a710df689b6f82281661b89752635ab916d088fb875433937df2fb40e5561d494b4c8ae2c4c481a7ccf2ed0c18bc8255c3b8c8c8722955aa287fb7a22a45804de2aac5455169dd77ed63b808c5635099c02181e74c30888ecf81c044e3264e0858638e5d85567a8807111138488b2fb0ea43d7884bea063aa55bfb082527096a6d7d49ce7de5b1b0fda8326eae959f45afa1a14beac348441b1cd29f0b03091c4daa45a071db67d60af7d355db038c61fb8383b24b98f0998e5fa32bd67dc37abe18f7dea06ac97c0a8219965a5894ebcfaac74547cb2607595e5bdb1fa82cb38dd2dd343b4988fe1a5f1e0f60471fa88b3f40d0cba185a0974312412f0719415f8e41825e0ead04bd1c92097a39c809fa720c14d4bf1fe291024e94a900590fd4ac0d3716e06b41bd184fc4c81a02af358c9cb40fe44bda279ba09ea770308f8f043cba460a39cdd9b2ca35cfcde84c9f78e21817b5852c83e38a186b31ec88effcde9832ed59cc85467498e45016266267872a3805d51a0e2b607342f2c56433810eafcdba1d2e62b2d76cb010ada22f3332c042e46e4e972ff064091597328fc613806aa8691f9db76d12308f9783be51ecea68a7fb7efa0372d6e5950af603e863e515a7c454962d026fb80669afaa9c2495ff94bfc6e3d56a43438aefca09ab233f3d07cf4cae0a381db091dcf81f25b3d37b0242787fb7dbb185c16a27ae4e342b0d0678f24285e98a13ec58589734e063d57844f35c54ad0a5f7c0880f61dd3844bcd70ebab80b07b0f136b092860d2f866116f027e10e9d481a0aec9eec3f4e59889de93860de6a888d6c99b0fd13710ad014b15f375be59e22bc1131d3e7cf8960ca91383bbecdb36a10c23794b4165f4d950ed6cfc0b9664d949d60307bf0da228b6c42718e6610215a97e5da5c7810d38fa21ba39f1e93a079f5c9400d1c6731f5ea2f4b711683f75cb184ed3b77b91feeb95aa2c11681a67d798c10a86218c2a34d878c37bea15200f5fc9ee734c74c6e98a45f4e2454d4297f4b5f2fe9983f0190d3d2ca08a4b816218048d4f0fe861f1aa89d1b675c0a0864a729dd34a988243b6f6293e133484b79e4fb10e31ec7a2f3e80679bbf9fede1b124bbb5a898624fdddc046bb8c09c3c90732cf95bdd39df2fda2234306053fa0274f73ccf36dbc26437ee888c6e8ea42e2988507cbc966015694458fbd7d4d6c8968a7afcb8758d86e033cccd83bdf8840dd63db9aa5b80e0173adb7de7530339a7de8f994508f81ff6f50d7537724c152a6bbda552a85337ac46394b0ee2ed6509dccc41763ad44b6d4b15ac31ec605e7235640df223f5403a3587ac86bcb93e3d14da5846702a76fd74ed078003e68fb9806653e2ebd7beb8f1f51aa8a492a2e1effb2ffe7463bf947429fbd79b74757f4c88039d08986089a995be3ed99321a7738f1f210bfd1a73ca095c4382b8f59cc107714efa4aeadff63d921ff3bd657ce928da66d7a1657502cbc4c742c5bf142b709f28208d1b4f7cd1dac5d77ecc632d320289e57e40988c8b74f258628ab5420fd83cd8111305a039f9803765a26d20b2bbe27125b5083336e3eae56c15c8ec220c82af0edbc1a2bbc09d39d59a3e4ca28104f10a35cb4eb79a9113e4691e1541bd7073e9a02e890928d34088cf4f6c8032dc2937a2f6d84cc412e2785121670d01c98bc3f0985b582411c86b8a1da4b939bc49a33e53be3b9118c61c30b03de3629a67c1d028f48f7abd07d4ab1f1510b4daa2c8b96d0802a3db122da988f969709ce8bc23c1aa19052373894040548868cd9b2f60d57813c59e9fc27c21645acc399078940efd0e10056dd0f264d1cd67bbd164c4e412cdf212c528e6b0f846af7e4a9c892be2e104aa1ff2ee0dbfcbceff06ca386854c5500d00246e8f85e6ef012705c54aebbc7d382684381db578b2674f285636deaf9f564fe39d3c2009ea7bb39bbda480f9f6eeab81c1bdb3800bf303fbd4d4d3210d77983ff9fb47e0441b4b525c9ced316036a71c1b4b07a7e83ce5085ddfa3281709d5786a3c1299f3fe01c9604df21ab58ac6387cbd7e89fe0ba16d809999a059dc23bc788028d27843f4dddc7fcd5ccaa7109bb84915367cf9af058e9d16d69faf92e7b51669990dfbbf50d1ea1516c2bd6c67069be40c03c58d85f938b92c1f0d21273963fa658531887f3a9858d1160b6be85a6b186b3a6c6720cf7fb64c04d87b42ee8c056a2c1b85cf9cc885f1cb9de021f1f0f24b467ca24e81ba80a875b11b0a4ea494b72aef81c87461702b839fb400bc70f13a3f3f305e16e5ff1094534d003be971397dc1c51c0e902dd10b100b392a7c977463dc3d062c4e2f799229476a48549ec2aacffee94875060f239fea8a447deaf452c72568b031b4e0d8d27e0e35976e6887c5019eba49968e68e85c48d607b68c7f63911ea3fb4c8d1f460fb3f57ea87761f03868ba808074d7f86d887213480fdf6c3e7ebed7c31c67137ca771b68373fdcd404503d4c7b870df3da23822e09077d2d4ea4a7dc82044c26bc2ffeffe83f73b4b20202f90ccf5131ec8c0063a60cbeaffefe1878c750b1c9c7351828a3c7f4007f4433fb41c4feebf5164261966ca012cdedbbac80a75fd19405c3d7d2e314ae5e3b4c1fc784b67fbbdd1407d0c4a531cb924c609cc90e4ee02748e692a7d5658a07fec5efda2243e381f1d87af8fc16aa67d184280593a5835932c92c88ee90bb860b28cda45027e055e1f94262142c0568f150e4eb98d166559ba317a4631a348c10d99549812abf19c6da15c1fcd3589dc9932579d224a1c251a6dc0057d483d1a3609d6d82f5815c90e5cfcccce15a372aa98f97d5e9a2522889d4e03f4c107eb881a78e567462e6eeb0ff9305329b12a05f2f1567169649045669d9bcd43c3310d1635473e360dcf4ab4b8f600cf7904f918863ea2dc1e41b8a559bdd44a68b7aac1bc84c0adbbd8f132d430bd2ad8d4e37b901b1450b28aeb638f1d5f2c15d30d77d184fe07f02cc5433ac0b32994da2fe7f08ee9d29d0fa13e8406a9150f7e60490dafb3aa5cbb1e97266c927a8ff349d35af109417fe6e61ed89ee1e42287bfe5fd812ed2d0a489354f37256ebef14d21693cc49224a08dc72beb62f3daf907e0ebe245351e24ac4bef91818fbcb5cf9bc11f59f9b8569516860ef7570c77ac675ffcc78a185116d1b60b4e797425750125f5ac6c7fed0d5fef0a7c23020c63591cca7e097fe663c1dc742cb640fc19cd0e361e03e562bc99df002f36ac3e1c493a6e5f732effd5f3a94ce20e9ac4d0de61409085d969a2200316ecc9a4ca341e5b09fe5898cd2a6a33d68dc74e319a447a62778db4a62b5284336d97bb55ca7f19879432ff501d8f9cddc505e56eb4548298806bbe3d1c0827c0805223b09493a04632dfb5780c90beb388daef81415fff5aca1bb4697efd52b8cccc9d9aecc6f2ee74a298cb54ca8fc7a89f3052810353a7c556ce1f8f5953f49fc0cb889bc1126ecdde3028c9032eef0d70d2d41c915bbbe814903c7a0d832e24e73ace3360481e125cfc278186e7d3fe2215b1b4dc9ea007457b8599cd5c7560644a64a6e0bae159deffc00e64a0838141e073e05e45556e923707ee66d8291809757a2530075ce7e8916ad50db67db015d4c4c0cad04dfbe1f153a28d334381b9550a38e96e3075a627708c5a193856c523b621befc37aecbe33e4063c22a16e211dfeec09154416877099e1f988671125d8f74d157eb24ca709cc5feaaef269817549a1b22551ee6113ef237410d57e4df06682771c409f82937fe018a81ff0f612bde9f56f85ed6ed078536f0da2e50f17b087dc19055815a6fd30a26fa20afc614dfbfa03b4a12d6247de469f637ad243ba4c641f346b878ee54bc81f951570d4cadebcb5ac1de1f3cb78259fb6e00fe850330e5c1d800d0d1812abaf6e44765c7672483489cd8f1c9d430142f3b88e643ca7f4aac10b83852ca13a45e548b366f0c442d1690521009a27523da83c2deead17f8ceef9d5f8a9681193d9a119887f44aa84181d3968462671431715b8543b211cc89b7948500d762c2bb70432179d66fe62576e314b5b379f737c32f4a826f095810af0abadc90b711bf484a1f22df22ed45becbe8e2f8aee4118df8c34d8de49985f058efeaf4746ea4a92318c038413ac9b4a9fb526f8c958377a874cd9ea9585ff00406ba72d9762f81d97373aaa9d9379ed559360bb57442a59c994523667a260e9c81886be8184031920a605ed2f810d5ce0176d8cf788847f58b204a9aab2591a8e902c06261618019528cd15aebf00966acaaaef117b131557824c63ac9b37a3fa80a804c100be66298d00d64f04424bbc2100220d6863eaf7d07f8cef90a0ef1abc23f29da64f16e4983c52cecc16e85fefec6786da2630be421e62633b9dc6ea06411c89af566b2f9afdeab46c454ba997182f48262834899b973e6c74148691cdcd41d4b0793da09ea54e446521c46ec81bf41bff1ab39191d556b03c06e42f7c95c42266a20baccf882d21358feaea24d92a32a857e689d8a997334fa52e003850f8027d240f006ea7fc42012665f146e780598a922ca83c59325e32e03c84998c7343cadf628736591d495b4f0800d64140dd77f397494ef1ce1c2ba31656c7d582148c1dbeb3de9bd4d37db4f1fedd665f79438db663077cb331805ec76a7c102f220e9372e5157ab2f2cb033a8e1dfb6fc9c6beb923497c50537e6b1fdb56899c25dee5aa5aa407de44bdc85e1b0fa588dfed23302b9506b724490abe68a2b0d36e75cc008190a4320c676cff3f2787e1b3fa210ac5aeace6d2d2a32a3becf643a43ea87a3628fe3bc4aebf1dd4b87f6408d26614a0e2ecf4c4d73a0416cf569391012f44647cd6fad4d8e73d37ac4f57f5a2922a25f24f359b96eca163eee780f7d6969a0b30e032eb29f5dfeaccc2374396ba3030b37e831a659d31ca62931c460934a45939515cafccca41be3f51b623e599a5c6f86d4583fa65bdb75577005a4f2ddf42c94401f24480d6dc40923d210225ada0443b05dd7eb04ebf4bb8cecde77d890705ad3566836e2f906217393384535c050842f2231b275e402701c6d1dd4f0c023b76b926bd9c8da4cd114cf034af5ae758968ff2bb3ca685397ac6648cd0a647c1cddd1c646781806bc23214fdcff271872e35d41025a1595759e94a9fdc370af85be8ce0ed725b8866ccbc45488c0e3e517352761076c2c4c5a63eee912290414cdad4b033ac6ab4351db7e87522f7009b3847f954cf6f21a50733d86ad5ac0a9698b446c59ae46ea58a528520b7f5e1313a49c58016e255a66edfb3dd3bfb2086fe954a3ff11f400f8d7083fb451e4dcd37ab99239113432c749cc580d6288c0732d22b4fbf24a7fa33a0c57eda754cc864eaa272af431bf40c00d94d9785d8759f32e812ddcc5977997a5129788d70247eb238fcef06851c7861184acbe922afee58acef37747d70f3b20588c62c182fe39dad5c1817d6ef72ee5267948d24f8dfffd829e852279de88ffe45803216210e93f37bfe0b16c93fffd2d9c0f5ac014ff552a79bf11b02b582989963732308741c04de4b4513599b98e2370e7259efe6e892556311a3efedbc2207a19f70357bd08af87226bdaf78553ebc00a81d5cdd4201e90bce4ac8f243c712b117bc331fcbd21cdca1c537384abf8508e336fa2e82c7033404974df6a38977fd344baf324e343960ca90be27d9ae08c642cc1a611912f0c41d76c4e5d8d34b3505588a065f49c8c8be85d951069d1acb8595220f66600b4ddb7d0455ab56fa1a73874c49db72bfeaa5310c91d06d7dccb52beb089c8d966a32e1ab6ecf5e8bcb131f8b467dd18160050200cc2c2c8560181ed393746267368607dc52832ce8ec4eee2ab5b3fae96ae8d9d7e9b9fb43e5c456ca3b95f5c882bcc4c0d0ee8f78c774f6f71138ac248df59d5c8b548c1621e86ef95fdc7157ed1fa581f3bd5e6850441610374e81dbf699ff937c776adf079d47fd97992c4a09d1a3c58ab1a6a5246ff3441cccde0994f20001c9c8143d79718a5241c36f8990f5bdda442ff90dd3c310f929574695c20b40d6eb47f07d77e59afe3c8c8b7084849a9c854cb0d0bcbf3b83d20e9a6d25583f533cca0eb7e1d66f4d2738ea309cf04cb6c1ca0a4747fe00001466648ab799aa1885ee8165ff98500f3c8a738aa5a0e9611c786acf2de7889234390735d3d9280f14c2bbd1bd3924a47556a621cb7a51f6a7b6607a7b62fdce79999c13e4f4ea87dc365860869a65be9ea40cb64d7cbd5e8a09dea27340d33eb5dd8e38591ebba2126169e3fc4df3c9e615494e584b1d8d8b565f66b87a80522304406f95e3fbc14084554e12fd0f110dfcc6994d0870f2433ba7351f4e5111d565302f205455833f978dbcd134d7e799608a585b6439d1ed003bc680f6e6152ba74794c3e8a084ec978ff6a7604bc76035a5f2e7c5e4052324e0759199a61682b25558c5c7af0b928b44d3801e16f75b3bb914ec09e7599334eb9257889e4f9620e9293aadb93cf4718dc05f637361c9846ca0129461418f5e0251e1d4ed310ba4d74903497db1c2159d476b7bdb794322599028107ef07aa0732f0255be865ba5c100a36c207e640c2b7bdfd91b018192b01c9a02012549f0fb9221df2c629e34c0dab4eee8ca32cc2c3234728c9977c9540e39bfd4797fbb62b5749e82ac92a498dcf246d88b4e836890ec94aad90ad4ff645491531a087a9c4c3afdf1a1f9883b5f98a5c910e75155da397bb9794dbdf5370ab652dbbe2b60c3f1916e0eb933514f00a68041a7d503e190b9f6c05134a2900d59fb9c2daf898f8643ce31668f43d715dced0602578a55b356c2abad6bd6ab7bf7bf5cd1137800e1b1f6885153f19730ee7ff64beea57bdf8dea243b2a1194a24530262b1582734ca643ae18684b1f60677477ad5dd4bc88a9fec75fb3f59df40e9169532a483fd865034a71919530c941d4500829b73cea69532db1f7f292533bb5ce9734e06b9be094f3bfae5ca3bdb671ef38d7f37c7c9cbb20a1920cbef0fbec072adc9dddc49ccf7fc29959fcfcacc5f6b153971ca198add9c4cd85e2a65ab98997d454391d2f749e9a4e1c943ae6913482945ee9bf472ca0871ce523f0ba1d8859c6c818419c28319c2f6fb9c93cef09b1208fdc311275ae6f3e8d9420b11fc9003268cc0810e3ea83332b05f096c3f6abadaf43ee050031345846ea0a4a6c5163920b1aa9ac97af2b388112caa85996110b8267810032d5050821b28d15a2401a3864aa5048b5906465ea0918d61beb530df3e969989978cc475151964b0032890004108a08052a4c5cb12e7bc65f2e774b4ea08cfdd391c0782d00e8e1022a449932037f880129fb46e9cc9a562f90eac1a3ba0eeeeb47aa54e3fea5e53a3d619daea465edbba60b5aa3fcb73b26a54356a983e8e6bd468154f989a1aaa9adb5d6bb0ac7ddb014cafe4374c0f2490eaaae6e7c24425a626afe87729140c7f29e60398ae28037775aee3a8a17ac148a5c3cd9e20746881152888662ecf72b01285c662b9bc7bb8c8349c157af48db7b6398e2e0f3902d410687b4a431680501cadea2de45868c1112b7379a60309aef85e85688a208b1f267280b7a6ff27c32eacc8c5d42cfb49863038b03fd3218bcb8fd38515718c8436aed2374969e107b7f083bbdbd4965bda2b49e0e363c50a3b0b94c8458985d9b6d0dafb5df1542c6943be48628982bc1c8a2e7c40b0240a3aa40df952d52a51e78afc53e41dfea580b8a7290e47afe67d6f4d16d75026a269b43d331017579f0620ae09c4c52515e43d29a0fef639f5b79a339f72685d3abadbbbb1b8341429322384fd1b455ab1fe2cf4cdfbcae97c196dbff814c757ec7267c1dcc0ce70904e53cccec3952bfedccfdd6f3fdb614732b37f77f76f2918dc6782a8514376cfcccc3e7d4e4ecdf7140cce753f6b789793ed3dae9442bfd7eedd6f5bc7b77d6cdf0901b364c992c5e5a59a3ec79ccffc0053c5d678a497e14efaf1e8af0ee432c967ca85ef76ef3eb855f472ea74807ee6f0c4839fb714df9a5ec9c7f22c43313333a9494430fdfa2df8cff0c77cff1afe7092f383afe0f7e929ae531f4a86620d18941d3712d755da711b976ad796aa1ff879c1897f3e10d789c39302e8fbe7bc873a4e38cc711d7f1a9e3804daaca9bbade0d9435252ddb8ce27370b2bb44a078eaf6a4a95fa94c95733453b6e4bb1aba6da4553f5033fdd2d8329785c6af6a5b0d13479abfe26bfbf070ba915ba140e4be52b293bd597949ae3e8ea52ec846cca6b7471ede2520a3d6c2ae7c81a19ba4c54e96cb7824acc4589fdfb2ec32b56bec79c8393e1fae077e1bbf3eff6dbeb68fa95df5df82617c2481b73c4feec55c51559ec49946072a404931958f3e533c05bfeed050c0e2c0e4f5c0e45ab6a95f4c28aaa2bbb7b4776dd1e8d1485d4dd7d6f241a8b446318cb759845a56a154da95ae5c4fad3bf514250bbaacb519828713d67a94073f9815c0e45b93d155281e67645322a8400c6e25296bc3527d84a29d4a0c08a31b691bf3df5ea274b3b686ec7a94073bb7012b18dfc1d3497db42b12b7d27bda780485fd32dd2cb7f528a146572245aabe453219a444953ab4c608d33c2072b329671649dbef11667ed2967becf909b4f43202e7ef9d65b2bc86c9b184787557239b44e7f9cf061e68915edcdc1882bb23e6be516de1029a91866fbe4d7c111f172fae68319929dd3373148cb52422b892611f92094cb55ba06eadb59932585d122be303f1c38aa1a55cdf4ee64c75b8b08c3a55e4905f09a6addb68de3ba8e440273b0b4cff4a14a251c8983033c623d10e4f66cc76d955a3badf5b6d2320cd49bd8c62349ee1653779decbaaeeb5e42b8cf5d0e450ab8f48b76046ba3b740a3918528324e581134028dbc253934ba52071f5c1124026b1294d997d7451230186bff1200c5592ccbe4d1141e2c1cbf344dce071e97e0a10ec0e1adfb71e0a464a02c1ff0a0c4913783c4724a05f4253e73162b984d268e63b50a07070e8b007dc321cb5bd225fb07320a4cca7ed665e1f4e36895ec968f43e6105661e29de4b3ab5bb20e56f8c02659c43b4996cc5c92347c25dc6651cee03119149a8c248b618232f6d8139a5bc2edf75437696c061a639b0bc85beac28a24a1a6b12b9264a41849e836ea8989142391c01a8d01c8353235abfbc3085d1bc25480f25c910347d787b52f72e0a804c58242ad028d00653042582904cafa86a5d3a0be09a25b26fac4f33870745dbac0a51da90a509eeb43056b7f06a6520a34864c99607c76ce486145fb3f313ee61cd35f2f2bc48a76c6769cd427a9ba205fb5773505e43d2925e485711c4797f75d90fbab063673671db2222a08753d1a8a10b8d353a7dba538999e91b36786ace8af2f56020ebcaec1f4cf0de1f2db17174b048aac96cb6f83d8aef54de9f24f2a24f5f95df7e484e97a76b7c90a1bc3bced35752927375197fb6060eee42c37396f4d4ae7ec50301e5a5bdf9dd6b9c35bd5d1975c959e970f443526a1948f9373fa4fc93633332b6ebf718e1c78dc9e5fe92e4709eae29aa23419a334795d93e48119a92ed7aa269e7cbeb39e710a2838e426010a0230a20a2a6450c4072080c0c58f7745bbb3822e824c41046589902a4ff8304509e797673b1cb9a27d26df083c8927f1249ec493789224d43d367b66cfec993db367f6502a2bed381a4c1c92c522008ed7f8a76af838f522be117424eef26f95eb1bef1eef93cf82bee1927b915acc4aac16b31233f530e79cd3a547f2d399eb734ef7e639e79cf374800981eba1c8ccfcfd203233b7cc3489cccc95c2d862b52ab5cb5f63607e902e732194122b7f86f0fd40ebf6b2d51ac4792497cffb26fda1a9d2f3046d4bc9bafb0c6a09ba5c612340f958f9b4ba7fdf0fd5fdfbc13d4e64667ee99cf3117ceecc4f6b0cd08a64b6c1ca9fef3f3f4577f7191b2c3333cf394ddff78305b9b0f22733b33723d3a7190ff571894351a78652c2fca7520afccd2894084cb4f064a007821ed1d090515111d366664e28130d0c1a1931200e64cc785a2bb5018c1e4c3221ad750912184368cc92999308ee5486c42041d1d4b85319128344841a77283148667c8a04a732c47d6290a442127c88fbc4201981045aeb929821146609092a1ed56afa083e73041f1fc1a7041aee3e34a6af7ce6cac7573e356c9cda80ca2c317916356c6cb0a80c8162820936583ec4a1d860d13abd2e3159107c7905214908e3edaf2d24fb5e32590c53ffc834ac878675ac837ae820999917cfcccc0965ea284ddb19471a18586864c4b014565e3132fa8a8888c0ef0504c18f26930dd57aa8bd18bd18d13ef0fb3e1db8d5f17c60d3684deb789ad6f1803410ec785e40238484c0ef05049fc462140682b0d70b0cfaf969dad75080df4ba7334269035e020d195af5020dbaad92504f5254c3c69bd6342c6c8f1568dfcbc606ab691d0e1d4f7f6703b75a48a8d3412603b500c1ef05146a235eaebc18bd18815040192833c18417231b2c2664336ebdbc804da3b09797ae48c7f37ddf1127000e0e08b6a9694d039b0676adf6a0629dd027dc903702c0df91ef05ca5e577eaba334ad69348431081ff77d9ccc4cddb6d34ffd39a16afd41a168644c2273462363c694193fe55361ddb64a03d39299534dddb69f1d4c446a8c1f140d00a49c4224c60e32668c20e51422317600c00852ce62ec900a4558cd2944664f8c1d44a8594d22b327c60eaa55ddb69f18442a8c9f55091e2881864f558fab7aa6aaa7868d943d363e69f4388d9e49a3c7041b7566514f3f3393c8041b27dc984264c6629d70631299b3136ed4cde7f6f326d3f77d5f105a69a54b5c423c29e7d4d171e1232905c1747727e203c66ef3d02294e7e3be8f8b8111c3446b910c11d1913432a272a836337342996860d0c888e16af40421c4683494321bc85a6a3d8ca30cfa913f8c442826633327115c50346d03477960486023570557e3a6e0568fdc15e338cee8f153245098f7f8e21932fac07c602d3524e3081b023bf2f279c1c6ad080909df065ef0d512a318c9332e19615cad079eb11bc16784114a1328f29c56f5f068cc6de5a3c347c6c20a3e341a04832191ad6f1c6145a8a458aa2526cfa20667638345613da4472a845b9487a76df8be6f04a98c634b8df2388f09269452e0a8685573b521a3106e7135f1b301b615cd0ce16acec1a08cb4ceb1a62cb7841bbd456173848d3f58bcc9c43ae1841b1f94ef4600680f14469370ebfba8083e28230a8c8555d41f2bdbe5f27649214f32dbf405e2320627d520836c759bdbe461e6daf975be7ab84de684c735e24becf67b1e9456b5e7d550312699194974fa9146b2a8e88492351a0a4523c3442363068c192fb1cc68f129af16ca8468201483b164e654f30383f10ea6183f41281a00b81c79b223220000c711bc2abc9a3705b73821ef8adb4292133a4a7142a1082b793439a117c8c37142f3f572a98950b39ae0c8d3f332dd49db41058e2b707c610231e408a304b4815509f2c8abc92c1e28814697d3433555356c5858a18766e392068d49a3a4a347268f6c5c797483d3cf0c4864e57b2678351b27dc9047dc119c9057ebe754c02d4fc6deecf6739b2e383a38c5a526f396b1bc5aabfa59a5143c2a5ad55eed841be01070048570cbab8136c8a3492352f3963c3af26ab78f50b313c0f1864f70f4553f387a4b1e1d1d81e38e19b7c71900d91b01e800e090029059e411affa81c02d70044721e038b3f245701400ca7d4689873f7d192fb194161eb394a1f3e460d902d6e5c98fced4895dedea6e611777c0f33eb65205d495547852c6e5d9deaacdea9fb91e5a98641b3a735197bf55f3ac1bf95faffafbe6747906f596935dc62d6b9fdd0b3462ebd691bcafd4025a97971060503127d3c7796ba683645200ea1fa198af7ae898ccccc779abca34ac5ffd9a9939a14cde45789ae714830646eff4d82a1931544a7741b0128b3c9262c5eee542deaa270821268d7cd5359445beba4216c560a07e4c325ff85273204993b4d72733c12072203924674e22b8a0ba174d8de520d088ade978e85ebceae74e076e754dec92dceeda501233ba963a725bbaf6e23e28ad92053127416825c10728a594a230a4053f50f2822f606004f7850db268623b293392c4000a4b2fcf80a8904921832cf1b9bf69063482fbf56ce13222e288222ae0220436f40fc67a440d36541074427666f084541e3810ac40080f4a3bf5881ebc1b86504a29ede206da11468678b111a94cc0e007540891105422540891ef22402be85aaec8505845d83004c7cd6ddb503a98e244074ba0aeb0a6cb331d0871c56f42074a663a0892a4efb66d43d84dc869a218697145fb33a32860ff4c8e38122ecf8488491ae3145599e28a0a809002218e9c78c1103704e18aaa1a224e2dcb1559c6506a5fd066b52a2e787956a305d9a1affa9aff1db8259428419013d40f504a29fd6192e00335d89660a28b10705c94ae58438a16273ffc1071220646296881cb674f843c21bae2b3bab1d25a290caccbe55913534c995df167d65e9e3551021a214d0415a0899f6de6030a2ebd3ca3c5aef82c25248d1ac5fae5191008beb07d79067444ce00a483cc8155818a5cf159404046fc881cb8785458d39a2c8cb5b583d86d0624455b18eef2ec082957b44f3f6052c091a3197ca218ca62892e78d8960ca9b5d60a441d42db074d8440d64ed040e4861070db131eae3f9bee112a38220a223f60b93cfba1c87de2f26c04485cea8158a45cfa3cfb22884b4319fa62c074c50d8ce39863c62d5dfe147d597295cf3b9f8a3414e7e5dbb4a1cc10e55ec05e18665cf9e20cb99091785c23cad895bf71bf558e4b999ed853cea663b25b785a00bb54be726decd2e911ea48d70a3f493220c62b9fe7ba663e58ae2877aefcd9a503f856bd7d7632123cf1d93428dd03045c0648140c206d380e16172108b12e7679962cd7df533ba40df99dda21af01a40df9f334af7c17fa86674d76ae2c5d29ab0c7dc3b3a02ba2dc118ddcb1091057943ef3693b03a038a06f445ee2ca974797a928b144d0e5185c56420928aed79f2cf1e81d12050f7f8612a755d2001205796faca382fe7c1ad267a7930a1598776a41476e1173d16fc049be09462e1d138c5cf5e7cb2bebeb0451767e7045bb6262c4f5f80196674c82b83c63e2736d2ecf7eac5cebc22d96104c0826921421c515d776ededa0b03cfbb1c175968fc735adaa61b4dd56f83353426482428bcd96747145ae7db5590f395c91a5542a7bb6a4e8d2ae587339db5e549e1625f647843b5fa4456e44603a03df9450efcb5bdccb13ee8cb93d764ef549d6bd277d0bde9348ffa37b8fb640e29e145ad78f4af3d57cef7fd4dacb4aa379eb94e37df75ec8be92b5e6ad530ee9b927855ccc57f3b954adb44aab51e6d7da51dfec740bf5aa541871e73395a23babd19d154b1dbaf3b74aabac6fc4f915caec525f6355c85bdb8bb6c09b73c2b0642a924816b13c32ba541249a2dec26f15db5cae72dc96a40824c9920cedb82c491757545d5112957c74b0dc567fc695db3cb830974b3ce68b16e66ea12c6a157d59e5fb98a8c5c7fa4b21f9248820aea65b383d834671e8b714a9de562b57b9a32a89bc91e32451df7413f50d6f44a2298827319b320171716fbd95e3dfa18e93ed75bef7907dc585a2a9f41e5a9e80749d17e4b7a46410bda28ff3511924832411edc539622efd4a548baa91b74a5f8fbed4c9062b7251f72cbbc195bbfda90b6545542e47857a3344b24adff0ec899d202c7d44725b8a852841dcf48d7c7227e0ad7e7f4a24894426ba12864a53d5a53f8373f0f6729949e676c2831962d251f247317d762b610e9778dc37ccadf932147da66eb7cc8164a7214b2e646ddadd2dbbbb5b8a77d281bbbb33cb18785cdf70b34d7777770dbc10ac384a8995927b07ef65bbec96227317f15c05e77ac70c2ddbf0733e9893092b290db9d66a35aa14cb945cac9ed049810eed57718b647dd537aa2ec571bb6c32db2a552b57b9b975bcaa4fc3d6ef5771b5ce8d86b26f0728e956ef1ef9cc2979484be7e4a620cd9073941d84e5e70aacca4b368fecd147ce51eb88b8cdcd100537a6b65aabfa83aac0783ab6a1b93d7a6ba3a257fd5278a8bcaadcdeae6c583a68ec180db79a8c193348e390ee2a650da6f7106f6318e4f5559b647498ddd2b2099f74d65a691b516b13f5a7c4c2b9bc2997da785840743980bd3ee6bbb8147b94abe4d9d20baf6337057f8fca2abd473e25c213c62e7b8b84025ef51bb9228db14863cde48a341674451a9b119284525726d36e99a1103b5862b6b34b1f22f732e4685e4b9ef53ee1b95c7573b1806517138f6be83863a17449d332e848e471eca703b40c5dd866ce97f36b6a8a16b8fdb2a72cc2ab73b6d390d9c6bb6748c1431314dbdfdf11f0b6f932c55d0fe4ee76e70532a50648d017089572885f498afa5a754f56ac54b54bff9afca49d91314d0a438a1a23c5e642de722199cc7f9c8386dac8bd828f743dd4376e8455f50abef123f5ce4461453f72e5bf684f0f1326b749933bbda7c78d4c3762e44a8779ab7fead652bf83fddcedd670bb9e77d43731b77f260aebd56b0daa413f93d65aa5c984624175e827282624abb45aab43d569f55a2ba55ea9f37024170eb2b01791bd3ff36561af4a89b8206af2aef229b7f90fdd269db0b96d7486b2e50b7a7d419c43fa4be9512addaa43beea6dfec673641b6b9123232c45b7bf12d5216f79587ad5bf4354a4e88891cf910fdb18040fe7af99286c7db10bf28e5ad55608c75c2eed8071290ca2be8971fb67866c8d716908fb781ce62bc9bd70537eadb2a4e7f7dc37a25cc1ec7a112860820856d1229e983ce49da18cb10d25028aebfff305dd58cd4bc91709f643d4a5e4482bad3edf01a3eb983222203fef7ffb67a843f67738784edfc42d29b539b817eb6f53c53694866103a11de8f61e78ab15ea6b4a39e404e279d7f7ecab5f710e29a50c814a217dc9e3c6a521d027fd6f5c0f53a4947de17a78049d94aa0007a7334cf0247679fee0014ae9cf1a8adc932597fe6cfa30434c6b2ac1152aa376fd59067cf90a461156941104f37a790b0626e8fa53f005c2ae03995c7d5a29a59492b859da41734db2201941f40df72e03f3d6f7fe323f323e90b0d81dfe304bd877eba5647c5ae55d1a1adbc880b18d4b6145ca0323c980f1dc26bd62d8baf7f90e925e52045f0b28c1a082bc402d9fe3ae961293c2e9a25ffabe5d32306fc99081c9c06460d7df931173193119b12e3ce5b8abf4f20295429d0eb85ef4080c1d182fad21e7ab5aa7051864c5bf27d7c9c39302e6d36f413e873fc21f4e72f8a5eb87fc199e1a0607f61be585154d77473ebfa4011145a0cc50420d3edc0b70170690881794f10a1380a7067709d95c4e2e3065e3381ee111e2fa915b80b51ea8b7b854a5dcd75047e5ab7e8e76b4ddd965fb6652a61232952b1bf52b74463543ece0b892a388aa1bf18399de9e8517820dac7caf4f4d7d2602281706b74278cd84305181338d6642c4aec844b3a0d715b9ca8d44a1af14ad7c7983a3a6068edd0294e31297262e4d5c9ab8347169e2d2c4a5894b1397262e4d5c9af4ef98370a0d4138e4d886d906c695cf4914980a0e9e92a51a29ace42b3f058b8575e6e11c538873c4d09712245850e5ca5c468205b54b1a2f1ba05b8657fd9c35b14dc704b12be868d53bca14859d21d02907cc92254b16d78f20f4ebeb6c5fc3530bf5b9e7c21f5b68432727ae55fdae2ef5a0213571a2cae44160d796b33d2984e101cb3d4924c972bce7421d55977248bf853aef2ba7cfd1afa18f19724ababcb9a5385f59d9935d5a440e5c56d7b8ee49298ef45ca8632235c0fb2ed4f114c02ece57fe3ada12b1cb05924c22607e0d7d70fdb3a50e9cc0fe6b28eb0b2cd7b304711d077db174a7573df4e1ef9779f475fad3a31efaf09f30ad6a8769d5e9075604c119785c23b908c808700eb772fb25c0adf9fdc4155d30c0ab7e4fc9c036400c5d5ee2f20c88d74d4db1a2a445e99b79f402103c2a11f8ce0fba1a72f05ad560842312048719a45443961b6048b17571438dd8a38a73f4953758d246ad51d9982996f4dd83312b7e0f93af2a0ff6d4a7e6be85efb9d2ffe8ff9e5d2d94be14965c5e6955adc236f54b2996afea7fa91824561e85d2a855f55f40605d94463d76bc904393afea03715f43ae862c5f9958b77a28fead5ca883d563b7c7c08b4106ee82447700a91cd20685f18415712e3b0ee7385dba318994c2611bfa325658fed2b79c1c0c755e900f129dfcc107e22aea3a30ac0db1af3e1c5fd1184c6cf3dd7fef2fe2b052cfde97e253e9fbbefb2fe49eb72c4118af0c616476056ffd041cc75b5e8bf4f45ff0d6f79c88138a2c1c95af803a66f18a1f8793795d68b986863ec0cd098f6bbc5771c9243303cbf7d46387fbed5daebcfc76e4aceadf5744acbcdf3f5f8658bede7fe1a987f7a705b0cb0bbf3fb5205ddf4bd717be9bd8a6be0b10b67b9dafc7ce0ee977baf7c21ebeaaaf53bbcf21755d17beafeaebb093424f7e26140ed6b2cd7ccec444b2e9109ead2ff695367a7477bb09065ad4ae3fb7c9f74acfdf7bdf02e94be18fd293de0b7f38c961d78fee49df02f75ef8e37bee49dcff20b16bbef7405c5deafbd2e77ca5d293c2d37cd20371e980ff85a7199e14d0fdf739dd7f3f6798c33d29d4f99e7b1dd2775c82619bfa3a4e9c8840df8fff851df811b27c554a9de6037181a9d30c63c8f91ee44c0b6057e9c15047c786405cff9542db12da1640fdef4b2fb288f842ae071761d9457a916ba61410172905c4355fa678f89523e9bd5047c701be015fc1b000767dbf007679a417e5486223ef3b257fe4eb07f6a3c353df9352a5e75202facaa76106240c2d65a5187274beff42590ad9570b60d78e14f295ff577a767d2518e47f2976b94829e9e2920c637c4b892e982efd1a9ee64bd7bcf367e8801a6d4e088fdd55ed5284ddeee41cad007af976d8a30adb4558ee8af3f2741d2daa72a8d8865b2b5ef99b4c2e2ed75788497203922b32117839cace16d7997c3fd78ce3f8e3ea672ec5fcb264a7b09f9c2d22907b85564a2b0590f8220b2244f0a303962f6842b010c2ad2ecf6236040551626a1f9a28828873420b1a90545b2f70a5861348b1d2822cb014f9c09d28fa41110b33050cc80a141ed7ef7123719965d707ffec663aa774666eb2ec4e1f33e40e5bd2254988f4b9adc403080b92b8536e554a29258f395bce23af2f12b7be286f122c602424cb700670c28a91b8f488ebcfb23bdf2f102a7d051e738ecf2331775cb7649badd2c95ceaeef7ee96cc51f13886619e734a77e77777663699388e12993e626068bb77dc163da4aee3a815b5d6984b7d5ca7ed9e842a99302ec0d076a79c4b8bc5e226a5f58915244143e52e9cdc908406168800044c1a082ea0a20725dd0e135b4b1135d0275e5cf1595c0e374c6bb230d60e79558ded891334be60c109aa00c2105f2c692fbca03b593c508b6e184229a5d40ae7c48e0fe690a1bfa8a44d9825a964886600000001e315000018100a888462916092a6691a6c1f14800a6b8c427660361c07234990e4208a8290310620438821c41042c8d0d01401fc7811664c3064a2f02d43d8cf11acd17ca051d2f09697e1f76a65a29007809ca5adc019da970e4683608457a0af4fec5d6c1188a43d024eb6b0fd1bb722edb1f6c4ea34c3952c0acaf9c7b0b6239bba5561d8031f8ed34d94d1872d3eb946aa6caaec022f2b3de9bca2c215025260ae93fcdd2d7b66d3f3a55d2780b8b4f2a9033a50b277a5dbfd7ea33c27e031c8029eb2ff691aa9f4f1b3042c7a08e2a7cd5660777df337d7879a96f8de7ad7fcbc08c979b7f8ca02a72eb2bd908dc700abc949ca0c4260f862aa20d3130c397006f554a0096dc9d563a37d0a100cd961b8f09d2e06aff42161c82ad7bb00ba211620a96b54b0fd8df2b8db6f1ed9cbe0590032ca621088f6120273712f1c77977a2272507e45cbb68607227b123d6cd76ac3f47ae5e3ae4a46854b81b50d6e5563a9b305fd70b622f5e36c4e2e2f6dc27e001c1b82f6f2b2540b08f053deb98924f0bb0dd164e2783a9ccad045b316df1a058798b8ab4889144f672de2e775ba64691c91f3b16c29923f8d8a2804a42a00fa9e3e73093de78c102b1758d5ff330e45b0a95bcd7867f7e146f4c7611b890e75fc3b98e7fdef0b25f7b1e642360f9744be1c4ba87ea1bcd162ec562e5a74fe572b2cfa41df494708a6db204ffe5ad5034e96c33d11abcc4292f07892c0619a81f954609d9b385b24d0e65d47379611dad61091f97d6f32285a2a5058790b69e1142640a8ddf463caaa6882e47a78614f870c7b79ebaadbe61e89b2cb0ca6cd0440a73827fbda0b0ca9543d4eb3f86e598407101a0d330a7b141733c2aab5a24ff15f51e9fc78a79b8670426228be84903a909fa2ebcebc89f8285b5c09a48f7d83d5e2c64e76bf69cc20bcd7618d71f69542d25565ae021a404b017b6ad0e2242d8dada0bc72ca89219ceea64cc98c0d96dc7a09011e1f3c78705c708c9e9b11c145a74aa96d872cbbd23cb480748a02310829c56982d4fe7cddd5c507658357c584cf425f6643e23849f7083f12ca6f94a1d454b956d92386bf9a078bc19ca1991496a985769aab6182e74a80ca8a94eb078bae623877844d4ea9aff937ab2d904b68209526185112b3692dad47a6fb0fcbd0a8c05011430d2dc2dd109c021a080980dec1b7a0bdba5e98a899e5e58f997bdc5ed6653903565185a9f7e65c1e9f8bdfeaacde628c2e9fe4a792804b3a3cada7df6ae21bc983c5859bf8a6ed77960bcca8004db117932db80a60be38bfb3ae3e8d7deaf66211e3bfcfd750e631225831fa8a9929da2628b202a569bed63d9c0444d965202c263795cb1ae1ef391a035c8361aa48e252383f52f56e847cadbf55b643726717be881bee8b2a1bd513cd0808666ed7d2aec6f408aa3ff21376cd0380799e69f36b747a6f79e83242fde08f3b92a2471911afb3f77fc131bf827236f4b5894e23df3f5201607641ec80457ffd236814b5cebb9dce2efe8247d168939507f91db5b5c0a366c60e0fb19cd14eb59160933c741aee6c0e78b61695d8a649be6a7bbaa0577cb6a3bd91a5c5136137fec1227a2c1a37a4f91787b10a666c42065a2764fcb3303a39495b66b57cc4f3ab47dc273a4acd7f819184d74579ab1a386031e04af585da9642865b0d3295a1ea840e0ff594d0c460b1c8b4b01b486ac162d50db0b3ba4bc6702bd99beec2f132276cf8c623aec82f3446ad787faafe04d01b67c9c1713e70796014096b0be84996e6124696263429ffb98cc831bb38fe763e4250f8a88eb4aef942b2b4909735a5423023324e8181cbf2a8e264cc5d8d6d175428492e1d69d5a600358e08f06748780dc7abc015890afc6357ee15896c18a682d1ca8ad70413701240b114698e66169aae5e9a04206f054106f54076587c9f6ca46a611b99f768a0e2a581124dbb13857770390509d72a20b266dae6a4850034f00c7d1fdca4eda8cd57da680d8ac1665f2b185a3fbe16051602828d0ea58cc1e9d79f209eb7057849a258564897f4967f0bd220e8e11cc40256cb34b39d23a5d4ad8a8d242d41d44d82648317d52318965f555a0e71101c40889fd352b1818c94427e6f91d8cd59deff9b2f377b4b929befc917ea9a365fd00e598443055718bcfe00a820611139916caa11ddf8332a509fbaa41bb611233dff25a83156a9b16d677f236d5c16a35cd9455d62a579c69af979de71ef321e5ddb53d3d52af062079dac91fb2a51fcac18ea52e16bfee4aff954d19295e72564ac8e6b8ae85c32bed3a568657f8fb2a4f3403acb00eca32208c335c4ba198565cc980949d37bf57e97b379110ba4e478e85c6c41117e7b9b098f217b2597bc8c261625b4fe15e6c1a05ca83aaee92338db6607d77a4ee8b4cb6f5b16ecbc154a647722b75e5a81b7e39ed444ae53b75fe2a44dd51477fb44b424e6c8d38f5abfb8c498ab77ca35b3a865a0d1caf73d2a06b61080e26d717189b172471b3c60edaa5c3841e03918465728321430475ba747c78ba2e4d295a8c7dbe8656847461f3277b8de83a2d5e81142465a3d7d1adf9f10a78ca5c738bf082bce602efb74368fe3ecdce911d6d78821d9064e53cf42adc829eef3049f4c9b92b9122812c5af9001d6116c111a981ec2eefe3d5bd15bd7c2f39f07de5b922bdd0e652c6806a0c7cbbf0ebbd717282103ab8afe500a34c9228f35de29ab0e82ff47d6e353281f6496e3ab9740746013bf28ec77e29ba8e568f708a0f3b03fdf7ab372ff2b9964048ac98d28b792444d411d7bc742334b12c4424748430bc5ddb8548ed349420b28adfb83d7de8701e38a72a853ff9869b435fd60cc44e56349b643bb5a685bfbc8bcdb49dcc60d215a23dea857ca57f0bffc4be71862783bf8fe036e5f02701cb81d390392f4cbcc440fa1184ac88794df75880fee0c3d76411f775ed02d6e0f4a1be46f830ffe8b73fcba06f4e254c3e5f2adb7a9ac8bd65da26f2da6dca447e0abd828003651289dd890003a51a640455655d46412563065b7f3bca288c8388ff9367fa4ca056822f07960594bf4db83cab3f935fa3d28011bc42680dfe643c1a55c7eb6882fcffc4a8160c7ea60661ddf824490c9ea6c21a6508b9984e683666a1f94cfbd615aac3c1ea42732b5ebc8535b4c3811381e1a585f75b48c2e38c50e88433821a9b995fa1efe16360614a1dd6e4269b5643d39ce247dd2cdfd41aab5bb34ce5d1b675ba7e10cdb3f3ebaf4a8b06e1eebac368842716943929e7da5dc8026623f4cf9256ee2a637dda30726a0b99158c91608a72ec9e01639c8038ceaf67d5267258465531691ab913c05b467e81c0ad18048c48bb887db30f149c101fa473ae36012c400b06d30962d38a955e78db80fff0427cc1940839b7ad9edd828ea52de15e9345bd3d3464c2b972a61c43032c72501844df54442ac26d5045bebabebe84dc53946a3cd6f6282fde8172e23b436e29cd321d75ec5ef54c616b6a1e19be98edd98d18113207b8817efe9c56250896ad06e11e1fe85e7f21231cc2192e569b3f8d55f0a1ed4f400e14bc4faead48c88fc5063dce49125edf1521270813875e16dec4fb92d18b5f81b8dcfc9314f59d80a4765ab1ef4b9dbc4a70f8e6664d7fb40eabdce5fb105c0ede0132376c0d4d7dcd8a172898bd017fcdb7951d54f322ed1fd70f5bc115536c0ea20ad27c0d21da0020b2363f666f757016598aa613c4e249ae949a1b7179d033153441179fa1d2c5bd0c09a3fd1af209d87625ed487074c918fedc48dc386073d886fdcfe65719e4a877be65004f0e50f4bb3075106ae8371fda145816dcd4aa91ef4151aed1306014ad515ca8549787837ee696982bccacdd9889087d4455f669ad58626f7d11d570cd8dda5b38dea32f071882c1f3d5d0df18de45bc7d540386590900f4eae74329849253533d8049d19a9a787a6e5ce27006d778badbc4024c31cc2504e19eae2da56c725ed976b0421b84de0dbad5516fa648461e4a9fa414f5619c1bdd72f0805619c6beaa8afa44bec0d28d10cfd0768e3d15cfb5c533f4dc2a9d7c897bfee970927e3e8c1ca513f43d69c75ff8224f0665b0abaf5f01904b6f8acbb0519f0040f68217e59834b14ee19ef06a5b5f61eab1b0973d43ae5eaa86fabd76e4822c51350a1accd96d693739ebf7d291a68d2814040f1422baa156b12ccb0d2c2418880d1a49ba2ecfb0c70e96fd4b3833e47348e066e93a2509f52cc3611285f1488e9db78131a00291ba407d0cd23a52a7d4457a6bd8eef329a94426a409006b36a434173072245b1af53e08b04545f0740f62160c23a30bf11574e57eb7657aa1bc9d96f9fbb4789a9ff9961f411af18cb9251e0ffb70d43ef6a4ac4088818427b715eea571e67acc7a1be97f1f0134b3fe0de99a66e02e60a690345116d88cdf51611792b4ab14239460087f423d1ce32134f65a4e35c94a06d10c74443505d89164d3c3a4c9eb3cec65f3719359c313a60b40956e342b50d35ab8f1239e252fdb20867793bd97c92b34169acecb50d82a1869dbdbd0ec9451215b5f563143a9d63fba136a5031bf081d718b7c6b96926a8933a8032b38b0656f4733ff97af074a0257d1663cf31758d906f3dba60918e94e9e9f3c67fcf45af54b23a8062d2d87c258acdd320c2206e5fc297363afc10857140e6ca23ac3cd5d2b6af880a6e73e4c921b7a90e515f019de310dc5e5e75702c7ce393241ec6cf8a9d51b1dce2fd16beaca0009105dfb60e3015ef7c437bcfdb7af5362b15bfcc2b15fa4466bff0335e7c6d75b6932a69b978aa42c4b9ddeae9f24d8007bc1c44544f1c8f557b2e3d385a24076793dab2913366f128001ef838f2fd620273e3c6039a8716cece0d094419e047244623176818def76f9c101c67e0850aa9b8ce30a0f962ed715ed2d49a09ba9422ad1bb3212be08d0536fe0d5287b98bc5a635b5d1c5aa4dad3d540923cbe2a21756ef050051bec9d29ecd8824f1fd6bfd43b605ee370c82fd6501683e3c8c91d73ae22e0cb609b250257e652d07183b3090ed0da6f548326e0115ee60641eac96855887e7058a44ab7072c1e15074dacb3b4f01a459ef45d2d3f1f6a786d85f119eb9f16fa532be0ace5494fc8a5ef3861d24bc78fa4033c717fe4832da54db94515f80d15a9b347fa79ab148031860da8e56ef07fabd686cc4bd5b67bc17fda2043345bc6596bdbaf99732cb6f3881c2615ff0c8b2d2b143efd1385655f0f1b02f29c27e42f6a0617aaaae8dfe9a4a0f1b7c2d434bef4bea75d5d5a9899045977abc62de8f847f8812c1b90b8662c36b589753233b72be27fd0f86b023602fd0511e8fd4552433a76a0225d94db14ec88bfb0617eafd51b4ac3206b23c394fc7f50765322aba5d0865e7158393c2d2a9e29b714f367fb867052ea368e77434b006222baa678b7e2576ccbe97a5d8701c212c80aec5a487ae006a5dd89f5f5e2a504325114574a24faff91a591054f58c4582edc2aa9470c5d3d0c21498e1094ab25112bab0c308c975d6348f240511d0bf0650a68c8a5bbbae8d54bc440d378c90f762a509d809c4d8c4efd792941af63b0950d026554e720333729a0cbd0f37236be5c653f7683a359ac447e8a9a2814bb5ae1211cf54cc321a1723c13a3ee074a6b6eb7fab240acfe92c40282826bed5e48358b2e0ebc3936dc407b52860487d0567c5676b843a097d8a27a8216e0129986dd942e61626809cff245e3f1d421356f0913fff70c5ce303844026550518d87bd47c34bd98ef4423fc8a904889d0390b7d0ec23372b0344156bf57b1e251b2694f7e69f38d3a0602d0cc8eaa7a95c6cb284edcdda4762b37eb0ccab3f604031a1d414fb468dd65a1adbea43f42af5d176f94adc6861e278236b5a43896240631f0f0d3e208c134005c67554b0b5190b43cbadb531c880e9e5b864e228eee23b24c0336c2541037517cbc93c33158bbe5143784643489e5c111b831041111aea82805ac5c2e07267caf10c3ca167c454c80aa729c77e2a160170a01a8b16133cd42f7900b32059350847722f0f21b6a97b84187589782ab4c67560974bc88fc4e3d7e8ee9750d7b616c636e6646e2850b3c8285da6de075de88a6b6ccd3d4848ee98a9a8ab3f5016d0ccafec08d8303833aa81b5e8ad66b2fee74cab7190a94daed29cfe605c80335d6e9b793cda0b389c418a4b26ce03c94abe6d96a1f7354016d5446a68268886a21f1081aada0067d958182aaed53da5cc86c445ff8b4a0721a1b2b857107242ff892eceb4705572cbe74c48953915269538d0b10568484a1db5fe2a0b9528252bbac613e42e5dec9e4ed8a047ff689f7a77115792c68b22d0bbeea8d937760c7296e83b81dc32220646a5de9aa4b4c4ed13ad17c1eab0671ad6a515b6c3314f10beadf7bb95ca12cc81a00dfd16d507782cc8645f2b598568012b665ccef2e022faff313934b059b77326977f7b8e538439002ec4e7bcecc51dd8c5d5a75c4e13034f32498004a2794956c466a9df144977a56cb7f7f9c8465f061c52d394452222ea2357e31d3ce3af6af6e3cd35a77ae0c9b626b6ed4400e2b2b386be2fa9d80878b0219b336f5768aad9df7a4f83223e2e4015d02d293fc367cb20b2bcd192d26a2bf00369ac147fc28b2942bd09e01230a6aacc5803553e2055efe81bcd09526174a8c985025e4854c0b0489ab96287460ea9c2cac4e6f13e1ef67869b8d5e333da5740128028bba301a2a10978a5678f9612b844cccfff5916e103cc84fae7aed28132589c4b328757e712a2a990122c12a607049870ce9a081e743fdd70ef8bc0cd82797f981696ded98b2825c7ad4492036528ddf9c08698c1846b70f88ae13f54303e86d803f60a2a3b7d2a5096a750ed094e0d3a3416fc4c1271fce6770adb9a1d6ba4728780a3e36881dda02904c9a03aa71490f0520a28b884022f4c1fdc2da4733c6dd4d5b1cd541618044e16013151be2b6e73883a5e7754324b101ed34785ca85ad78660ad721dd7a9af736ae4349d7092fbe09e0adf40d7d24d07823c84862ec77e8c06152b3b3ea6f6885fac31c39d073c705b26a53705f40aec646e3bb82792ee89f5a3afa0ed9dc5b809bac5277dfe41aaf59ffcb9dcd9ac88f02d252408268ce471549c3d5bae07757f95b34506d6073abc1e44e95b6f86256a5eaf79b961010c29ee7e552a01a9918f0cf78aaa465c730526da98486368bb25cff5941cc5f4040e5016d397c112d247c96603aad5252ffa07e03de5d0af04840043ac689223b3ad430f36bae4e416d520b18dd227fd8a06dc06002fbd0c907acc9cb76b298bcd1968ddcbbedc3ac61e678a3dc78db1da078543bf0dc19acb231e623600e31a8718363f8707459f409ac8e7505ea799c230c6f3f82cdf0886ec79c5bc90b48fa0b94a642132653d03831f40652c3023013caf6ee8e57e5430b83a6b849b8081952bbd07a0f54809a1aed8cb9680a63c93e9fe9dd01a82a80ca5d105bfe76c34e5558b608c9e0edcef5e96e21f16de8124cc93a6efc428047f6b9b875267d5ef23cdfe5f4a45c20aae9c3d09d451a7e1fc6cf6ca2dd32de46afd4810b4540d7e64f50ba8522a0e580819a40579477cf5eb23b4af1551ade2b49746fb35edd2ed735679a26b46ed7480926dd5e89568068d128014a2b82d8c21c0c5250bd37db202a5b3ea62480764b9ee17a0c45ad9d2e507c7e5670fc218901916fc80cddc0067181623798aa751e5cedd7c2f3f06f55fb85dd1f0c40b81c6b0087df2d0c49fa7a6d6e2b21e9def437c128f4dc2d7030130522a11413e4d10a983808ec56b6d264ea8287c4ccdf01569c6b2559c503c467354628a07da9b24ec159ef2cfadff5168125ca86805e2c82a4d9ff5857cfde1ad576f550feb9c0e1f66d39e4d063b82f73136ef193473b82ec4b03dba330a8625f8a2e1e51f3ef8ea91020674343e479d45a2e60fdacff7e0a069d58a05a0934a11a969085d227923598237e218c0256f77f976b7ad0639adda1d1dc421a750f7249fff30f3f2b1f74313664c316c204a336877e7aaa671739c6bf47a6533a9efda1942e99ab68f88575fdec5637ff09925e66faa61ef5830c9aabbf3b8b681ce0de910fa0729d4162e6b753e77ede27b62d09db00c9b780d2385e14eff1d9e4ef16ce5a8d571ba824eb56cf751e9c50f646f2dcee8ba603b16ca5c67509456f118e1149141020aa5ed918a44fd08505e94164ac77332764648d61e37839218dfcc5284ad73db22d9c6c418492af0ee83e3d93f01b34d7406f7c4eb944c63b51056c409a8297c13edb2fa84c21862682678661267ae69baf1e2bca9dc2b9414295e89004d8bcbc80a92406856081416054ac7cbfb0c9b85c3405d2bcab48786585148f937d21246e23a34af23fcce8030451dcc75ea89a7f678949a23793ce9842fdc4adef9c0358990a36a9a5aad34ef932d3653829f95c4cfd961dfc3858c770e26ba08499eef60161824dd718d97e7de2957ddb606c40b17387729b4831fea21316297c7f3dd0097b67abb586eae1709df17e0fdfb062a6468cd2ca21e696d0f7c5932b61484f5b6faa30f81a12e7f797504ec59c0f806101c0dfb009933fb5f19d489502fb0f447c2b40f1b59a7da40bd22c9dfdf5470165b0091b4411b0462d059fa53374ea039eb1456f78653c4e5c81b39a3043a1e0918e007c3b694ebf554d9840dddcd65ad044156ed9c0a3c9b8aa29d40c43fbd66f32f045b4a8350b6042d36cf577bf44bebc8f0d7a775a83393f9542ad5ab7d1c159cfeea65e2258360f9b4049c89a18d1e8c795ed7b320a66aa3142a7677792b078722e08504440ccffac1127a169937f54e3bc5a59f818076cbb209da243230795c32c67b146665218d4eede59389d22a88747a6b442392d2c1c18eb8928e21e2f4126e90a0fb9ea4705d1d9f799719dcfa13fa9159d318815690c32d80615b1720d4534c232a0e317e8ce3132747b42d7bcde511110e34cf1e499bfa8806d56fcccec20d8dba2a4863becce29a06d6befb857eb01c1407c8e8754d4503638ac12227b013d7a0c9152fd597d530cb5aaa0c64599b08bf08f94857a91b310a6dc12145d6f8f0de5b6132b21b0b080ceb09ff1e6061c1cf41aa8ca7dd8c1ba69ad275ca4bd76b1a3f6020085576a852303ecff9786f976a0950cae755e3498687ce3a5304e36baa71da4d5df3dceaa3da7e7814bd2035b91f8a04710fd617e29dbc1bc67078638367651c646f70e1595f3ee3ebd8c8910db939d091804432d993445c9f3c06e889f94c2a541afbf660f26af87cea13f088566ad967d78775754c2cac9f32a43aa478da603994ac51e9c54286f3e6aeaf01ceb2ed5daecce741759864a5804f660f4736399bbd80a8b61807647e0013a40aa1adf98585409d2f902dfb0c2f898e00014fc34d05e622290053929df36589c26c61b488a45e4cbf785b406a8afe47903ea4909811b0cb288e1d8658e84c3c4c3c1b6ac34c5d0bc6c20dcb8051a15cd67480333ab7c9a323a6f995e0ec5605afe818692217f3ab0bf50f32497ce512e70f0234add80b2c5c1d55b15adce3edb857815f530e9b56b6577424eeb57ece0f222036ed2d33827a1537b6ee767bbf40655150b7c9f4ec7d577728c55b8aae71b6fdc4f89f28dd0473e2e5697f2c81391227a6cae786b1dbcdb83442f9ec9ec063a277aeccc89e99084741c3036dcbb4da6a69df2346b1ca92554ad685e2df98e935c9d6ec813666a0571d749b5d8d357f51ca50ce3245d5f06711e93d49ec346170ff72ec7d5bd6a48ba2527c8c40221862bae82953755c7cfa2b05dace9ee53382ad0524fa6742ef68722d2e3f1a8f5880fc2da37cb708d642029055b37582e1023e9840b93f70734b066d4101b91491960645a51c6bda8406a876f1fab1a6c2d667a51a9c78e0d185aa719453007c3913526da71a749a3319a0e2fff9ec990a5028335f1a39646ce3ddb89a64e34f16c2675faf1baee5311525117d85ce0dfbe2213580961559f1a47626bd98b08b7377b91b2191c0747ffb85bdda5276edd5e896ab93aabc2d57cfd707821805cc2bc20edbc1d9a34a9c631c3c42ae66cffc53c8fba3ce6e7fdab84926ffe6810b93c756035d4e55ae6a2ab57a16b07cb169fa824998eb47799bdb32effc51dda935befff861d629ed4d454126fe1e8d65cdf12d7367ace3cf1703fde693364e86effb715d43ec8e4764488a6a5e90c707f3805d5a76b404d4d99a897ac6be4ed26ee201662f04ef28390e3c4c08194aee9f0816779be33f12b7254d9bd48b5c7c80643b2b320fe700bdfea9aaa2c89165f06afccdf802af2bf0871b4ea852657108ae85f30bff1c9051dbe1bdd50f9315861185c46f90196da1c6542d68d5923553759618bb342ce5715c74d7c59aba9d01dd8000727183322459d4befbf6aa43438b45fff627734ba4b7a88034f08067be23a006dff326c4ffad87cb437249fe524ef8a69a989299af0d563384b505b647296968c83fa91d8c679cde3c964300239bc70239502821b176ef147ea7a48ef3d87cf6b0caefe648a1bf94b3524ff82af66e822bfb6b8f1857a71e31a38b0ff3bce201d810b7b73f2193766e043efb390983b714a19b713ee6422f41642996e983dad08049a887f691e0483894927ef3526a272f816cd1793d70d3540e9281fb35bb90e91f0d64d70f9c935bb875a03fd40cacd4c044cd1a48e60d31f1e2dc2144ee3f68700fae350dcdb7e7d1c7f2331bd15fe536dc0f1fb2ce9ac20b86d057e56fb002b6e0b59c40089c502214cb65eedd05f5eda98a5b6c7eff51af5e07b9a997110dce3fa441f73bc6599a05e4c152853274d2afc1839c8c5cac4a40d775ccafa334556ecb06e604ee2d727022f97f03def48dcf14a25cd07b5e2f54a4d4658926089bd90095f950a1b65a1404a2a7854a0f4337e8f75065a0e91caff48828840a3fa473a112c6b7bd02358c480cd4eb033310553e10d553bb5305adfd1be278b85de2c1e21c35cd3d65cdc12f68bc2bd3b22cd9234ce71b0cac360e540d62025d7aaeb679f6b6b47be20bbd88e0fbe9dd7f86b004c7f8e61554791d03d16d8d2ba499cfd232df4650dc971c0fc40613de10accde1f726b26603bdbab1ada0ad5210ac70b0045214e867427640fd633d579729a86ca8953b4e6136bce1345559e75997c92257792c89be1a7d0d7f7981a16bf8ac69954b785f36ce1e510b04dff100a00621f597c8c32e179183f62b658f030dbcb9a8640b50bd4b8f9ca001e8f4d5da2b9fcf1e008ac9056c7aabba0787872c348faabf56d2e7df751283403c98619c7b17c4b83812101e2ff85829ba8e993185581e4f0b4691b843b92347181fa03f11b0e4927090d85aec0175e947986828ef0cdf28e17fd0465e0080dc273b835365f83eda58d10b4449bab03d139a9053a573260cf3102323f0f4e6d59109c9a82e6ef3fe9f4450e4ed126beaf317082aa750ce9f0104b2d705a482e4b83fa3fdef8367452313660711f456d2df5e3b73569cddb88669385a8522d5b89a4d8ebab47a90c0c0738512c0396d0f1c1e8d28045edb8d737aa821ff83f5b157543b25bed6ef6544a28f09336e203d3f653a97846e61196b3d88c588a984b33c25269307178b2ba55daa04c510cf4130dfdf63b2699b61067ff29782a12d0da68a2d69c8a379cde914d23007012f9891f716258e867cdd52c504d09de94de627d59a26f9e28ced4838a49b6e43941a49d99c3f502b9d6786710e5c271532e0ba3573c766e89de2c59aceb43c86eb8ce74c1678a83df900c1ce724fc189131279522f2875eb813de5cc0644ccbebb7a6e8a8df82b38363daedf42fa138022c503080419d45f305e02d6cc581791cb571f5884c4e67587eb4a49c58503253002808c6b6bfa3783099f6bfaa93202b2e26284f27dd4a31bdc00e49db053898762fb8458465ce65374319ec0760ceb16cd420eacee70835c1f7321a14f48045428f22c87d3f113e8f5cf3a976a804eeddb9658b3f2fb1be470bab7d230623e7e9ac6d56e859918c4b9ea20cbc6df8e6c533c2c585301d2e951511de4f3e9355b8cd6539999f52403e842e9c40544d2802b44af017aec90038cad169016d739404d2519e2a0863750f6463f08118ba46af7abff262fce378f7afad1afe2aa7fd9ec87aa23793fa818a1ceece1319bd8bf333d173ca5ebcca5047d6a19c135b0a14c893545a6687a13a532e44645022467297c812aa18087b6f2ad63079fa9491e253e803bcd30c71a69477d29028fe7298517da32fc584e11553468f1aeb72d93033ef668ccfb14eaaff1abb9c710c2c4b347ab4b83cb108d517159871abd1f1bf6846da868060afd2d3efdb740e8890ff8d7a88e89354fa011eb97a0d153f6d39773adfe194a61f1dd93f4fdbf32e2cb91106d909611a324a06db0b79b34e058a7a10b5f0bc6fb4c932fd96c888d62046e8d2b0f204526273f9faafb0cfdee3e576e34d4a1dd7e0a5fa3645d3349d56e2da5d741179434b2113c2cd19d169d3215628912b12f0f16f9f404e300a965acf0865846c7d0121dbf749744b1fe003adee414eca15867d82bb00eb63d4293e490f9278518a4a4bc3fa3d612d7c0ba50a8faac92babafc2bcac753cfc1bfedfb5bb6b78e6b2df241c150d92772aca1261aceb770fd0ead28894b0a8fc05c8966846146c44be9568429b16bc2e2b18d11898d8fd990200bcae21eb3e689c9deda6f0296a61a2eed01b8afe948fe6a6614cb91d9b43c0bf8732da7e208122f005211a50affeedc66189ee8c703de96ff58f3c5015ec22987c170643cc87745c34191a22a81d45a2f2698a5248e938af83d4527c926d89f6a112c9ce69d9602d259c7275a9977f0b6ff5f718cb820023f383b7b2f5a34d92228018ca7b98b8cc3af8e73425874a80914ce12a29a8a106e03c9b896c86aa243843ee075183aa988449410b3a8067e7031556262c6174eac251b09708cae2528eef7510e84eff9016e546e6bed13d5e9745b25e04669b32950323bbaf1184417020c8212117dcbc047e44aebc81c8b7d9bae4ae8671a20592630c4755069c72ab78f7f9f13c96c10cf25f3cf72ac4cc986509bbd569be75acc307e3577f52b996191d22ac502bf87f4394ce7a8486c83fbfc08f437fa6396240e3b121a32720e2f9547e43901eb00e5e335dec2c7e400ad000cd33acf568bb709243df6d6e350c10d801a27397377746f9f334de2afdda9d25ec341dc9d13acc92a766b88b1ebc7a4f4b6df90f77753e2bd231339dd6354ff62dd36c3c8d40c04e428b5ba7828b41138310273adba0cd6108ab01777c4aff9fb5bef3709e49bde5064827ec1850b1f6720c51c7927cd09ce405b6d2f65ae94d4c39951c1352df10dcf298ce5b4c87fa6644a9122dd4abff89b36ce41a3ff54c03be4563a9645a7f907fbe40c3ed41906281eab80751d6dc7e56b58fd1daff1a7d248f363aaf062e4db47ea61bafa06ed9f341d5201484134df12d45cc1a0297ec67706294f16de476645744d555ac503badeb9fe515e93592b18b658c4af5b93d3f8b4b0d7ef3ab19beeee27749503a51f69061259383605f27c2ce10564d9cf1513fb64bc1a27060f192f7ef11253b9e8e9de6bd26001bfee7837b36c12105995a5a832c60c0cd09b64227d8c87984317cf59f4843a7d2732e57493f44e89c1c54660fce68a649ccef3c02b89a2e5aa45dd9ad5967abde67da1a247961ad22f1bc7aab86a99203201ad47fb9258d4827979983210d96350bce2365efdd6b8895d4bc6878c1f1ffee2681591525f10a422ec4b1e07a6fa5d8f3594586eb8a8871962ee5e2df0e3d30f78b5f880cbd7c68235cf2facb0e8199d9c6d18ae0223b23198d8ac667aaa171f961db8b15b2a5e48877052aa57440493c0156154171364591c27ee2e0cb65d06f88e4fbff642de9871dd7f6900220e618bb56029fcd2be1f5af6768b21f2eae202465c2f78a383521a99487ff5b20873adc344a82a5fe6c6892a02e5e23246004b6f4b7163dc279f724f6439e57f31866d570e6e7d4d2b48ed991555b94fd98f0cfdbbd97c117052d4e714b434ca6f32e51d207bbec918eb1249832d71239553742efc5a07036743b030b40d9f12768a6272551a3b00a65e7e1195ebf80eaf2cdd1e6b85a5232223bb9550952376739eeaa0b55fd6d7245e8dc10c1df9de250673eca969ea2ecb3ed022fb836000fb10e949f007ff66e2dd5dbb5636b750e885688941c21974a00f1a7263acd741ba318f9c2773478fce2c4afb68a84ead0d59838002ea2d218be81055b71a360a35b860cbd67f85222a5a897a3eaa000283dbf5fe5e75f51efc5e947a2d447fa681d2a595ec4f8f34fe9024d81ee2de0725c12ca80f72f967fe3c6f7a0738b7702751ed2e53e76f8d001483c1ee00709e6818e6d56a6cf3b056bd08f37a15f81857cc9072cb5831875d557afc30cbf254e4741b06696d13db8b15979ddecd99d514babc3a7cdb4dd0f508540dcaeebb1f3d944ca0dfd8a9b755251415fe92cfeb5b2f3ef645f94969745e6ec4d4f080eebf9187f3419565ce845d558ce06dddbb480bc864db2faa0f997038466b4288069444f240dd0f2692c8dd22fd4fca0aeb37c7cc55e3dfb7cbfa7a4550cc6b718e069469b07f82459595036322c28ddadc2b2297e4bce0a3fa4508a6f83a1db45f15a625d33d4aba314b4078c9499be7c64d585ea2fbe1a197afb6c02008a7c8cc4c6d91799b4855f16fcf018bb0e9440eb3a7dc341acf33bca88bd22cd025cabd10088ac4d74b6d1f85af012e6f27b92d5d591cbeeffcd1aa2c6d17ec284f23ef0f7304611cbedb7fff1d1cbabb14fe8617f508793f1a91ca69ee97930ff408be84c373ff82a08db68a546d619858dd94070df7122f3b6b2b09d6da2b62bce33bfd4ebea9403b400cc171954466076e65a5253299076353fa985d4b8d282f7207c136c8d3271f335690263c8d99f60813061ea7e9fbd681709e2326bec50520fbff18c6e7469c57dfe56d7499ea502f0674e171b0e17e915067ef21b6ce24f871ffb19a953d9c36fb1ce45a153038211794201b4b237a402aa3b262f5ab3d320322b304b2d5062f5b37318737c0a93da4538704b7738c6e139d45923d7a403d47c206f181dd72435d6a987041852569fd199433fead1b15d9f8f2e5a6ed616cc388e0947cf036df1e89bdff2c7459415cd3496741995d86bfc70ffeda43e38d2e040916836d3b4536e02ef08d3a39d2c8d74b2e0c9b4945da13c2c4d93ec6794ea41a5013d474c39f26a699d716ca741a291788e803a1e606b30081fdf636b9cbe8584bdf20dd797aa734bdfaa864a855af60429ba7ec6043db099d2ed8aeb8e6815375c21ec5bf97a79adcc0647f45d0c0c4ab87a8bef3201f7539ac2c6ce921a42ef7683c9e9dd44bfcf5550a07977deb5a1685457427e56f29dc04fbec2d1ffed786279a31c3cb1c83e1f5731abcaed24f145ae150010c9d043aff97275e114d76d463619539e617a207d329289c04f83f222c89f8263e98a3d92ccd79bf349bc90f1e1791f11113f6128210052ee0d198317a98074d61094d68c1d797e95dc5b0ae632d40c199c2897641e83715d55fae714c47110655415e3741bd91023638a964f1542acc298f6a953799984f11e09ecf944ff334da633ac6d7795df926a642e4df006bd8091a8ba5ce1393682f027b4f665c1c6cc091be2a654f1f767ae1b89b85ad930db4582eb3458a61d27c69ca4bb1e953fde0db48bbb7d35bc4359c1b89e4a078b2133bc30eab535946e0b39f164ff778e37931e10010ac6632b4cb2906bfb7307b387fced692f5484a780a706946401699fd9c7ac0a1f47c93bf4a631c1e711d9f50404259e99bdfab73eeb246c02a50bedd292e324032a29502191ba1166a31ca7a89fe300365a5ef65a05af4255f2f00d06a223a0d15268054ed25d1a7e1ada5e2669b840c7fb07f16956c3aa89985727c3073eccef8b31da6033362a82d30178649d2c30b58a429da1cb424d614a0ca8ca7eaf417521a7d61df265a416668b01c6633fb27adf3678fdd6ff15654531bb4fb19fd9562a68234001e8bc264532debdf6457d14f055c220e4f8e46b11d806768eaa0dd4d835dd663212cf7220b230e3ab3abbac1e3ff0b549bfdcf30a0e5841da41b0fe1dc03a3a35fcaec477626f11681aec6aa7012d5e4a03e321f119730e74fac3ca1221d27b01743708e8b7267672d8342fd6c83e70bc321c7848dccf209acbf8d204f45ec0a5317b97d383845ae1a7707ffa08b67683be61d76305c1f3268329b30d2f4ca5462f7a629f6974e5206f613e4c522d59e4c410371e17cde3c051b7c134ea3a92f9ffa7a6e8bd301613b5fe799527a1fbe8342479e42c7267c9b645fdc247afd64827e51d798bc48fe53f8262194d062adde060723960bef922b8ce564a62cdb16bbe9345454127d966b2c6d1db60239bc8c09d2028754824cb10b4696b5ef93e1eb7173cb40bec08613e486e26b2fa7c5025081ae42d86a5ac59ed341411d9423cb290f7bb0cc948415fae55bdfeda9c2c0308ba966250db8bb9384e3e2650037ff899b1f5bc830f3a142d14c899a632c17850fa6a58e39d5951ba0b691132e365858b9aebc709be7da8c2b30b2293206a267d2484c707ee7a7398d561c867edac1e50e74deca1491d71e2931b3440590fd3017fed49404c5447cf2cfa87a00cdc91efe5b2df7dbb2b361ad7fb2a6aac9c91c8b01afdb3e7b23b292c2ca61ff11766a0d8b97072fee1c611798e1b4874cffe24e70a1361890aaaf0fc1fd54e327e37bdfb1f667f14b3b92650e38ece4a829f2081b283e1239e7e9e404dc60311d5d7125e2c482cc0cfb82dfef2c3e1ea0736f7297aef345dee3666dda6b7d44588d5d761a0de0a9937da6a2176473748aaac2d08f494864d1f0612e3039dffd1fdfeb6915c006809641210f56289b130528c4e379d28417122957e3cc55146997b38c6edb49634e40be989e4276d243aef9e4512a111b7085dc3ce0d8c8793ef85b7d72f1b1388c52462f0c57915bf880df1eed1b85a191713c847439e2f1b57120d8e8173091171f44480370754c05354c88423cc4f706872236af7dab3215e5a4b6c29b728f0d1fd55e2dcdfbab9bfae2b98a3479196af298c7b8e67cf0e48930df222134f74e6d461e407d1d27d6e393db54a5a2928f5970c43ffb99be942597bc4c16f7c0e681bad46a97b197cbfbaa5c310b1737c8965dc8e07252107d1baf740f3e2d4f0b9129f297d5b2468b2a99d06b418691db88fc063c539d0e90f2a9ad858e70590d528a0df8ab8cd75d1bc4803fbd0b1cae1e862701f83486ee2971ed4780393c6ec51de3e1668badaf7fd61c7dade0c5a8e5d8d4b2cc79b04a2cd327c39361aad615be43ed393b026b3431edb195c81c14a0c71e371916cbc1c371b4c23aa2b99ff7e56dbce0b2311d1dbe6dc4ec682495506fc0793f917e149c3171556179eb5fdcd205587a5a78ea5b7919a08f9b814fb5c86bb445ab4d4ff065d8a5bc11d9efaec4e80d2582e333d265e202272865fc02438f9da1f22b41bbcb3c8306b96a3f1de4e9d3b5a149eaaa8a8a082bab189d479a2f916c5aeb7de58d452d39e7427705ac4b887683a7547117f9650b1e900818864d584802e7372d5c8d341892959211dd8f79b0a4ee659d54b1d690c5737fc009d93e4ea4a642e5131434db6301fb2c889536758c6ee74aa5c25d0375c2f0e94e376031e6fea9b0987a98efbd34f978049558e4656316e5db694d12af21cc40ebb5e77a28615906f9ab802ca30a947084d593ba482d7adae07a53b3517ab724bc7ee48528264e3d56ba426acef0a260a9cd58fd3a82c1406a1cbb62c055e77d2b41414d84e004600d34ec5e9c1f781ce2cb98c32753368871ba9292d659a2d2004468a145426f0e431996714131a27c0a1d43adb28db5441d3dc0988289bfc267ba391ab5214b254bbc45509d4f8d4ae29b3ab78f2bb42af8922be774fca94bfe1bc76f448d9c737f220572e420f91b28eef9f8e1c0be092dd4113c358cdb5ff181d679cc779c996541950814953ea6b5af1aa292920d0209b89df6b99ee1aab5d8a8731e79d524a44559195817c748881419fbf28e4e75604f4e1d7e58fbe24cdc49e923d544797d6ed9d22b9de8517f90710e1b53e55a5fe1e40b9df9515e7d19597ebd294d5ba5f5150e3ac533d56cb81b02f8f3325df92bd2b665609ac6f5a1e1be56256e9e22b312c69508c22afa8a32333b7dff4efe2c1e0eff8a3a2345d15cc762911f84df23ea086a569074c96b07e09aa01a5e0db7a811ed7358b6e84f71b880bd09621e1797b445550a58a9389863c36c270826541d24c51793e01c64655ac6bad5368fbb550c47fbe397942268b4c86e67af496c71e31e2a2d390db526f2fa5837fd283e8d441ed0f2a1c91cfc6e0b4ff84c1a7922535f76b9266859693701f6e72c231262311956668947091814905b4caee7f0000003068e90210d26f4135178f90d0118b2dd76b51b1c691cf57331b983d19cdf32e23b55b4c91789c02e5dc8c0159d0f2909a4a0c99aaae23c4bbd2a4aab01d16a90d7b2e48403f9d1d61876f206b66426d75b89e30219425ba098bb73ea578d2b4cee6eac1134ce17fec397060ca46ad962cd0a125b492308d7a208a71a32ab9ba76e9e6370472cda85f6e932ea90739c977b2c8e4745192ae571eb4fa892eb82938c54ac44acdde4762ac91e8b184b120fb9d392a9b35c8ad7b561bb2748ae0acfdee6cb46b1fe64577d0527bed46d03f929a283094b0f5e77ac2906d45c09f5902f879320f4493220712168dbf72cf916f47f4fd8630a650ad099cbfa737caa41789234d621c18a93dfd54d4a4f429297ca9cac060c6cf3130b93563dcd64bf31583925045663bbf1e10e10c7623d4722242c22f7a2f4d5f7fa644d7536d30ee3c6181e41ec10cdb5d6a458084d77dac5391ee0d3453b1214b1d719647c391100e2c24ce1fab2a0eb69794acb2a09ae5bb4b148c22856f8fc5d7efa80e1294daa264b297db886eb02128e1c9b381cc697a3bac432f30e42d6435e4365975698976f7ef34a4108fd484effdab9a6ed739d3ee55432a799290f37cedb577bb0eb10de96ade83f691f583082dec415633d65a05d27afe4abb872ddee616faf0ce102cb983a734315b68a96e91d5620652567ea6929e79f5d1b6107a62908ec4c8182c31bb0a52f5553078467d95a0f9889ddf0a44e5aac18f40f622fca6f21e0a60682d9471d130148b348c42c6778d3cc316d0267fc8912f0d4d147f446e87f7b0210b6da76c452c5fec7e88f38630be720a449e2299921f06b3550172a4bbc646643935d27b5465043a7a7f66c1f408a9793bf6c036d8e45d2e6df11feea7e316318ee428f2db1124393b23db81526270f00744ba5080d468fdcc8cc7070932813fab6f812bec8c6e5cacfd86a18377547921a2d36ffc6ec641289a1c205f428e104f670723bd25d1f54e906dae55ac497c4f932f39b961d4d50be017e280b05155aa5a61663a6909d22f1e674ebd3febc94e3e36baf637ba1732a2dd0e0878658a33a07dc9aefa12e0bb09b558b19e26c753494779ce9c9bfd0ae52ff08e08c6039742365695e16c2aeae46450704d3e8466904323896feb84d9f91f92540fe064a8ac64d6c2d5e812a39bef1999e05d72f6b66f6addd491b7c8f9395ee55802ba98e242853f6d3ece93a5017cdac1d6f693275c12c73c6aabeec61f5e0dc72934433a1efba339646c67147861357fe5888fee67440533a5ce1584489064cdba33771598b7d23bcddc543ed98fd8cc342e575a1e8cfbe3d769b0e860b76e66380eeadf776af77fc356fff24460469aefebbe0298e9af446ab6fe08540b7c9f8ae369415f8c68e6e850ee3e91a3c4b5acec034c3d32f6325f9b5dc376373c235fa1557bd781ce60a3fce5154b41b9ef0434d9c6b8d082f1f64f162da094518ba25d91ebe515dd2aaa1b6debf115f511c0238896431e4116a08af29b06efc305b88326e3f7152e85ce670d474b7ec597c472e4c6cc9df81dabdf06c88f38e67ae2f9c49adaba80acb8b57ae8a700a3bc9bcdd05c6c8fa175de5b69a3ad2eb03635fde355669af49fa393f21084f89c0785a118ddb859484c5463ca1647d57383e9a0104d7e363100de9da43762f262e61a2830bb23b58987df8ce1a3bc80f6e84bc25db304136c73cb4408093983deea5eb0c2e3b44456cc6abe1f1d5d6e959860e2bd0c4e8147d80f5006a8624de28a301b3895d51720b0e0a880125075d2098e364144ad741f265b54c68c6b1f8d4badefc5f34d5b3b3a32970b651d20bdbceaac8d91bc7a28e3e1d1f4a224262ccf5e9800148702c26b9458a0106bb39dcc614e6a9fab8a644efced4a2d77e95a498e78b73a9ecef499121ca5cccb0ba0f8f1d928c3086d02b4430a75b2e38f84d591c78589f7aaaac2c5e0bf6280569d7075c182af7356f64f5101691b7c85d95c4346b021acb8b490da5a5e14a54824d13cec3193907593d0ff4e85694910738692075006298f61ae0d220f17f3f05bc2913ab76c443114715dce685505d6541d4e81252ea2a8f295d7485e0bed3bf624844693ec3139e32323b49a8b2de9e8289cb0ea619835d4ae47546ef410d4691370d8d524d7b94a8a44d34a143a00d41ddc6268eba5b29528c930c84c886374746659ed8313ed326203b3616c23ea7d1b0ae3438447f417da6d45ad6a54be3d8599caed75a5aa88e6577d520b72bf2e398c491318d3093823e25a70f326274ecbffa21975a88411a114be2a02018dcf96679f902cfa0b4de854c65c252f2f5c4f255176d3e9fd75f44280822338e661701cf21d55c7c3303b99d04337ca6875f1a20d4a57ac0b78fbd9889ba9263aff9883b35fb4868a1b9dac762a45db2de77b67b89737e15328bb543a3e8dbb99cdf217c5318c9503f91041c5c73a7e578cdceb1a94dd99f98950ba1976c195905975066846ce830f92847115d60dc93840be2b55c23dde2f2086520b6d548b217614f12c438166d5d3ac3ed6276c98fae79f6a8c5d5df30d2b1705cade2ccbad3285e9d016c1282bda8172cd940cd6b6eab06d3fad1d2010ed546a368ea199fba37b0a56ec99c1cbd31553009c15b157122cf7ae1fae3457336b067a7f4f997347b82bbe091edb0e2271464f91cbe7c343abfc8e1345b7d5da868c9409292559ba92e66752075d911eee20c30dc22bec5ea51ec1b55510ac238c546d0244fbfcfdef310444ead9710720762f10fece53ca804507f939d77486aca63a4e960f29fbbb6e4e9b5fe5e09486d19a9b75b7b3cbc19b3f5c24d411f2abe8d7f9c6e289c65755a20e9c52ea0f9c2a58f97ed9b65909c5e61a9e70a28c65230400522e328eed6dca99d4d66bffa9daa00700cb9dcb81a85981c1b58ae0cfd96679b8df2730691821c6353cd627ac1a1946e0cf29f756b7cd32a4c75a7c3ad8a7d50a6269c74479008904794d8e7bd08a85df387cfb9681f7d9a879714d1af8a6990c64120afd652fb56d49e545082ab1e94be549bb2584a90eee9324d42e7f0a1ed2306779d9a4f5e50ecb20af2ed82688a911dfbba0be004b822d291c48ac352a3850a848fd37dc13ae922c71aa3244113d02cc79bc051a60041e61b845e140042a165e9ef869df734b9e890f0d8f315dfe73dc3ca6ad9881d6358343a539baf1febd6b7130287283410dfaf378b2d6fca3c9b6aa367757ba7df4cf837e78cda9518f48fb940b8a9ec81a5c89ebdc7926e47e9eb33ec6b18e638f6659de5910cf7e65b00394f4cf3763e977ff2d73db7fa0eff26d9f68f4dbcb1fdae73095121c7e879a176433846c50a1e24d41d0913369c4bd7d9b7ce561e6745d79b5a848008aa2e09bf395fa9eb43e011b5cce88eaaa7a888924abfa4c3db02b6c2829f0f4c6d25c110f0d1818df4c36e820bc63e91845131c352bab1ac7ec8b1d52d2e37e5f351e124ec5cf1745b271ddff4f8fcc730310f0b28fc917d112c51b9ad1468ccdf2ae102e00810e429384f0c0af8aaabf3b6257a87dca68a7db0068d1d900845ea9cb715f60bae116fed931e2c1dc5ffe63d0f8b51338ddf103a8a879755acaf4d95301d72c638cd32f23cde0eed0c57288c84df583846e0d130f44723c74f770c53dc39072d35fd1b7bd00ef9f698512ce6fcd6208e237849b347e39644457cd467177b2a7c71b66d2aca2773809556b1dea658f6228f926b976f76cdf070df359273b4286bc0a990d5223dfdaf7aa312730c069f370e1d26ea1752cf33f7870e2464b24895b2a3a7152b25063fb60b428014b0725371068cd8edc9fcdaa5b13ce4bb47147a67f10ed4f9941536a0af8926e12cf36296d784107307cf6a0a01c02f093412b7892589512821287fb83ded79541827d85aeb8797ecc11c1238726e9435d6b07f20a0237b58e58900ddb744a1287af7424a53991a7d81f5eb84cddd07d0b586477e1eb142f5c44934d617850ca5c3a32900494c905271d17d5148d295a7f2c3e6779ed78b3616a445832d10d49711c6aaefe242e56ac3497de0bf987ec5014932ad15ecb84615ab4f5b2cd8c4996c360fc1f7e4eab4b2976d01430c0dc59871f4b872d8cf52e3f3c2d5959eb9472982d087ea8ffc3eca28097242bacc8506fa329285db2b3ff1226116a534c4dc981317b92e9ce76f6630f1e55bcb29ca368784a8f6d3ea670391f3742359bb77d904c96bc065a129450ed061366bb204b4b762e1dc877a61494bad02c18da91c62b1ad0c0f0441030ad6a5d2eaf9c19425084694564b3b1425c6be823c7fd9055efe173464a6546e5182a5237b11b51ef199e5fe3cb527c52abcb1e258b4eb291423aa7460308e72c26bcb207b39153b90a9cdeb0062090a0ddbe7deadbbbc083a0517e46c627bc37e2355bf52ecbffa00cfa0fbc6ed5e5acd87dadca8524163c9b80c4f7e19a6a90057368b1c633bdb7f5671f0bf61d9bc987228deb004d3bbf72f159933389abfb838dffb61e7249e47cd8331a5c2d7dc3860a46847dc06f34c2d7f74daee0cc48268a5f8c8c3fed6bd8b3dee0be0fe34a5ab30d9356f81743b7949e42d1e402407e68d2f1dc98f8c26ae2a123bb1312255345321c6271d67eeed4c8027bc1b4d06ba8c31c8b080b3098e6788da583e0ca7078553a506da93962b29fbd0a5091dc4acc9a43292a8aeb235f4cba45e460bb666d78d651bea705e242bdf95e8eb9e5195cf01458350d600a0a42ed5df2b13e7373202dc3162dab3a102696d572d0673dc11f0a558e4f95b06c59596e191d3ebb10d4393901ae1771c290e72d87d84eb7366283e8422affa3124255c435172ea19e1e9c4039ddf7f91e9681908987bfe29c512b512abfb46fa60874f4e4a7d98a3e7e2088d0d2b5dfb59bcb6bfc1648b580d00b17c7162780cdfee83bd148e8da0f30a65d7080952ae955a276cf67030ebe838e0eccc1812fd94cae03b0fc636c5b119d2477aac5a8fb87323f6ff03b590bf9853b185d1fea972345230df361f84d99338f1a741b4e619192a512c69201aa63a6a58cb6434a83451f11506df211eeab0d873f41513e21b3b1cb7f84cfce51c145d6e442711af22be8181d1d3b8ac2378f8ca9342cdb8f9dd8eeac352cc5a3e58ad7e8ebd7058e14d08b57a03c007f6dd792008d986f6fff7ee7b210a1f9028346924e3df67acc5bb37a8361619768531c8425bf95966cd646c8108f16dbe566243259efd007daea9cd0d67a3f701677e636a823689595f435fd23c5eedaae99e6ff715bfcdbe54af8e3bde2d40d4693fb85d6cb400749d7341a17959d885ce4f29ca04a37d5188c19c7d262c94144741d748288b9e7ac670094f5889b1e66072b639d9d3c61b2903870c09adffa6add7602f993031088ef5016e2643602c0aac8c0be068d93194ca928d19271916a77f20ece75091eb75240430e30bdd4c5670a92d8665a8bb75ef5fecedc5dd9406f682434ac98143a11ca1767a167dde955195781428d7b4c8e615a8b90483cc0b22ca23fab88682b50427e5c38263705723d3cd4fabb352a2213fda28f0f11d1c1a2e7f1179ff4d44a037b88e54bb1086e8090c8e4f9aff2972eda2388f259c52dd28b63a499cfa50884a3000c98011763893ecb757da09e2fb0c8590bbfbdf352e46ecb3432e4cf41e1bd78cb2a24c6c4d5a233163c2ebff2aa1e3acae6de74847084433dba5bcce7a04480491ed723fedc2f0f01cf6c898aa810c48d6781cfecee0c88df363785f1e098afe3b6c43f79b8a1a72781aff630135a59e82dafade8bfd00110cbb60f83cbffa025fcf18c39bf05afe3376c6d8a6ada37ec85cb5a2f65e6f5fbcea808a5ded399b2ebcaf1f8ba3366ab2f6496aec4ac717c7919ca80c90190d26a51c948603294a515af66ca0e4717450b318a38a3a472648dee46fd1bfcdba74c093c5d469898c9938bdc12976cfc9badcaf04160d9a84694b9e85a86bbb8a65b557f15104c8dbe7aa15e868b38416b584972a7868311bd992ef4699176f236f2ab4c631fdca8cb4c4c2738ab6f429f729fd80626da8036c7466e1e268b88d2fe2100a09ba350f86bdf85a393aa5d148e891f1dcb0aef5a1edc51551c1a15417e737c5c0f083ca83e09280e4bee8e74672011c3ddaf535628415fb9e49ea7e1a4fc1cf27ba755f46dc307376157f46db5964d77993993a257f55ac0ebbf923399ed1eb47e1f7ca93c008ecffcbe09112489f2b3a440c73e24c2e1b5d5f66169df2f45d33572ac26322ce374eb331757dab279c10c485a0b8ed8ae863044e29e0f18651516249d78154b3c7633febd02701676d5f2e1d0aaa6f4ec26fa54dcd009417ca7f04a56897976e0d8d462b5a4a83b2c057c114a7960786398dbeb14f9ef5aeb3378e946f4b1962f7457d40a557c7672a9dce69ffa067c5b7f94b4f1ea01b8fdbbbde6b15f9dcc50cb043e5919839f97d87e7083925a6892b44d405bf47d2a77a8b20778b9ea9a133945e37ca6d25f24baa2bb8cc3e48097dd90374e12cc93d4a4fd303be25bd564eb095458cbbc6722097c1f71c168d0f3db41af877fe4f2f5f904430975b01b35899bd339e28aa9ade898b8b0ab3ed04af33e0d6a66daa1f03d59e6d67319f83ce7104fda8d4ce9fa2acadc163c108fac3e4997eb899010a6316fd36ddf6beb667390a28e5083c6da9a38646fc81003a70ca107aaccfa668909c06438a901c4a8e493134121cfc6b91a4a9cc3cce1bf0a1483de9b9a981a471c509221b0bd426dd20d38c8d0e20bc1638dd5a47f0310963a1af98f87289e4568e0b6fa2c1e897092daf2466fe9d8448e9e83572a3e8552ae942f5db33f97fb8e860e569620428f04a5475c65b6e9a01392c6848724912f8b6b85c416b2261217847cc56d43a303428867f95c6b755a3cc4661606979e9227d0b9e90f6384c4adc21c9e3def3614c179f8cfa5575d4a8b17615f77ba776b3bbca98821ead51a967a20cff7f9464fc39ddb03035714b80103caa5713467f8084fdb9e6f2431a3a8a3340f450a2e64aef381a6cf0a1b4401c011763416c45b6250917b8a7a608963125199c697aa80c772df22e94d9ea2ef973be320e7d00de26065e4ba250f3e353844728a2f30c32d5aa02f7d182605d512fe48b75db1d9479524ea5975a007be9ed4fea2db136840b6264fb62a752e53c2abe3c5cf8c34f77608e6e87a9b2f548b5a0fff9cde301891c4a2e7561415565d1fbd37ac6cb7d6fbeab2806e5d02bbb43fb7d085d376c261c62432c0ba652549a7a44f0043854acf42e33aef26167e3d5b8c7bd55d3def6fea56fba4da61b11ae576cb2fa449dc214d1e89bc673aae39842e66d8f0487debff8245ae9567e57ac315f46e7309ec4d5862e063a462aa2948f6e326ab2d8a51688e55b14fa28bc59bd8a5d7f0253ee7eb92e6314371e8bef5c4efcd82dcd6605c50dc09f7d179304b436358dc954be6f4e2210bb238a9a80419a78712b22440479491f06d4095c251f4b8feb3e79b3c51c609ebe059fe1115ec6c00c15c5b0a6130fb9f3b37bb36c7dab8ccde9862be45f0d81f157eac24d26b193fbde1cc8e6b5372de4b52262df7520e58ebe1393f60c7d390e36fb603ec656e319b650c37d42261843c8b911cfcf435def9c731231c7da615cedd21f31f3f7b6a421753f18c0467ec3df29b6c1bd6e468ef704a07fac3227ef529faf92dfb2195f4577e52b211595a6f18e01c8d38e30101d0d6dc68ef093b70af13187c0f6c552a2c756ea580d66be899b48d3c43b2c54fa991f68e9c2987fa35d7153a8448a43ba957861a55dabb0231d2e45859d69941706027be40ac7df8d2f84367336ca3322f67b3fc07cc7a0535fe4f40a4f8edc8e9dd8d68bfc8cd353bc6a66261820c3a5dd92c1d02992f1bb510a803b434897a36e462c59e251dbfcb93d79d99f81d4b28f82784e0b8ed8e42466177b62b78b0dbeecc881d194e43b1980171c52cab65c7b16f9d407ecbc908f51a3dbc11c673570c7c1e1ed91edda02de734d92b708387099a55a06b56725821ca79e79abc506c0b1840ed2cebac11c613ad1d5a4f4b2cf7ed97a3340f2bec30d70e8e7f321be8b7bf31c7ea195f7788d8dcd4c9d3dd052c2e070fe6c85837707acd6d7893a05d81eb04811340e2f1559078dc3a86a60e3c40a5d8c3c69f3bc5bd2ebbb7b493950c82906dfc24ce7d2fbfcbe681d33ebd0058bb187cdb5a8468350e7e7b96647e2c45e234414656d1bf5ff1b7fa962b81605c215c37b4afab77500716d468d402b2532af63ac7efb00fb7d7f62265dc4fa3a111b1c02b8e4d898d2fc701d46a5e16bf6a7d79868f10038adeabf1d7b06c432e82f5cb229b1cbd9f14de97ebb8d30e3604e7949278399bc8918e1951b9e18764de38f671f8efed0b6c81791bba2ac2262aee6e0839b14772fb02fdedb46b9e337b9909cd19863e077be3a8c45c8707c15aff13d3df843c85af21ab5b7594b48f7bc04c02d0603e04257d32ad2c4863d162f3a522858861e5185c383326df0c60816c1425b3d153c1e2190b8190c42b5d2ee3abb876803740c088ed23519581e11c1fe8d4589713ce009b1a96a08eb9e7c0e2cc27c715bc7b54e64dd83847bc560d8905302ef8c1cb70ca55c7004f37be100ebb3400911aa2506f10167872afb6d95d6fa458605bc59ca4d29e0d2cf46062eabb14022cb315083c8fad7e076c1cbdfe0b14a760865bcede26536794c8caaa1d9d3176f383a5c84cf61b03d9f239b5e63012631fcc1fcf87b21ca26ffde3702d6ebc92dcd81a2ff0ce40d04ab1eca0001896e1ba14e67229fa6db73e88e0b09c19247deac4d20bd2377243899448dd4d05b0a274ed8a118f2d3456f761905b33a242a36b20d8e74d169ca6e56eefd1ec49baacf59f292cf2972994bee46a6bda47129e364d08222dff5c45313381cb79ec318e69758b26bc91fb262c4ca2ae9b0628fc2990ee45bfea9429962daa4a3e489f36a227a6e5128e209271419bd8ee87d3c30826a8985f6c5397eb7dea31440527b9e2de3495baca1179a2f2b06459ac3e260419e5284fe10c502a789c10f7677049aea0cde463793bb85b428a217e479d2205901e7ad229ea322b04fdd887fe1376cf07845dd6d6bd2a7225cd3ffba8a7077d56361fff54977428f59230593863d71fb48ac1d3bc5387aeee979dfe78e23eb51fbd21b17dc5495e6520cdc99a438ddb6c6651cb40893e2bf386a1bdb90f33cac9f18f3e2ddb4d874648d9411b3bd80e1674334004b652f51720affdcc7480789e845154566c79b6117a05d6afbdfa895bba610cc6389642a2076a38ae6a1a52ca72fb1e7c8891a87c27c4beda246898d4712302d09ade1574e4f8c604c967ea7147542b176a40b37c293d823aeb422e43fd20ea10b81131d67e46c373a8e3d8b438e5d2b1018434a45d3bbbac949ba66ed2402554ead9e2ee95a1bcc0646ee4649743e9ffe01006c2de1d0dd24d5687eee9a8b21c9c414e238fdc0ab25dbea8ce71e9b29598f535e00421bf2f28269169be85a760e659161cacfd1598539e5b282953953fcb3707d5aaa1340c80c3fa0ee991b0060cd6c9e9c89e820c64b94f8649a5519deadb1aa55b32d2200ca83110e71b28041c636fb8069ec01e5fc0280f47d29c5e6ba0618c5141eca3eca9d9ff6c14d651cc8c2090264231e541f1ef397d4a67ddf12a06d3273400b6b78f6a16a66db4789e0d45f4de600fb02ba7e691330d414dc26ce388c63647043a5e435b2af231f26c4f86863dac91a57e067c6f0fc02dad40e0400e4d9557e0d1f9a9787dca030a0f56db7e5689cc4394724bdabff1a0fbca00331751ff0172d46cadd21337f53d41e915904dc8821ba56f35d143dcf477786aac2a423cbf4757532a076bdc36d5d19172db5a49547c1755878078ffafcdd7cdaa19b6d262a0a9502359691f2092f7de82990c8c789ba12609d3bfd714d371ebb6625f5256cd495e3e1193e42fbcd8eda042778cc246c15d42fbf08ce2012dd2fa7b83f10411bca7abd6d8f7f97a491cdde0c7ccdd6e91812137cbc33e24af098cd5c2d69697cdbf19003259ffb41c60a74b5f720d5505ddbea48e910d71d00b9e462626a40cc5d1c569f50863ff758141be9141abfd57e03287196e313f863710fbcf82286fab9f533e23b0b145ebacff1c81bb0cd79b9ffb695319d1701d04a4c403cac906915e30d45d4d07059e0a56069fb8baa44e37042b61e30714764b37db7172d0619c393edba046911fed20c3fd5712578519b80160b0bb73789f0383849f9f6c2ef69720750d1d89ccc9a140fb22ddebd07bb23d9a68d2dade6d4d6e29a54c320501091109de0857365d253b6480cca0945d59e5e336c81e8eb88943e28aaa3c5569caf2a9741923f8b32ce2440d1ce843c6b8af66e785ca0718c64c159ca35d88905db60bf913070556f0307566cc5f81058f3b386628c3083c36930fa31e3a7c01a9f7cfb163ec2378765ec86817323acf967cc9d292023d22f0e86fc3e92f0303121ff2e4217f050a421cfe921e9331a5a75a931113d1528c486644f446a2d2bddf37a594dbc663f26071bfc65ff7e5df6fec61f3e5420af88dff16b6700061071923b2b6aa0e5a766f2b4b3d7e76f80b67972e97821072ae4683c1276b0261f92b4b1f9b4925cbf261f86cf5c3bbaeb420cb25f2c81a6b907ac8d30548565c70c5873cdfbd18ad4380a68b5194525ac409d494395cb2fb4c884929a5d45f36474ad403b65a5b9176982133a971d3dd6badb5d65a6bedd9b367d7ce526bddec0b5b374b6b0db71a4aa9cf39a727b9bb7b0baf3ee79cddbddff72c64cf462277bdc9ed28779a79c82e2d64b7f2c5ca94f455e96cf1554e578f1ace39a7cc4d941bc7c615ca02b4cf296ef26b5cecc726c0f22ffe39695805779d734e7ba9b7c5565b9b766ddb5bdf89da52b6d2ed69cf466bbe0f95a2b65ece836243a5e8b63dc594526aebe53a0f8a220e94d94ba59e762954ea296a7b8ae25277ab36cb92697fda4ae937a7a2b6666b9625aa28cf7977778f34777628da22ea395447bbdb35ea5a255bf37da88b4a79930685c2e952a28db7b5fbd75e8e4ba132aae336ceab2c4c53d6729d6ada958a6e296ea5da62c1da220a655b44a13890ed456d9676f7d2e7bace9b5465844e5493d7b98704d736a3179b3fe996f2b04c0ceba3a9bf76b335bb840a535629d792ac124ccdf7e1d58b8a9956d15fb7426902d5517dff8ca9e33d8d6823e2b85aecfcd4b1b58ba910fcb5ced6b8b0f6659817ccc2b8e3bcef4508de9e6645d7ded769af0af4ec920d5bcb0196466079419b042ad95a109b55eabc18371c250ad626b958b9cdd2f0ccc28a155e8cfab4ceef15dd2e5af05a056d9255b2b594104c2775d9d4a517e37c25c4a51f2582d3e2d52382a4936cca0e4cc8db5b2fc6d65ab245e205b9d629391831e5ab19c540a23cdae489a34451145268907225cf222372282afa7101d1c448ad01deeab6d166f0a818ad9ad0d01d21a47a92844362c9bb622465a4d4c94006d49418c724bb473f29284db20d091494a724d6287665f040adf2b345a1216900959f282838d214a5e848038e8ca224d1d0802943516a306b40152223a0975962736b2d1042e024041108112107224832c291087288c2d1af14e796a28318f27871cd27897841e2058917a317a397234858cab77a35ba0619f59cecf0ea6138d79cd7a6c2e41403284c515e681d1c3233b48c07fa03d98956b50cfa058df409a1b1149d83a973b3788da5e42f992dd17c419bd023cba95d4bbecf4aca97b544beffe283c7abeabeafe99c527a31661e3603b66ed89ff999b0a7936002b3616bbe8a5fc5e6cdfd1fb00d6cdd98e969cd300587d9df5e45a87a0a7ba4ec8813266001e5c10db026a8ff01e366d73d45861d9880f5b880da01d6e4e55d985128016b82ca01369b3a387eaa0c50ad696574e42fd5ffc8627a19d9c81a623de5fb5e0fb8c9616aea4508deb82e8fffe2358c7a316cb462543355b0cc0feb69eaecc808e5fb3240f9cad0f29589e52b23cb576696efb3945846b4cef624e4fbac27feeafe3e8bc85faabfcf92d22e2aab8989b5946f0d0b296f216b48260cc7550557b2ce59c1d037f7efeae7887c8fe41b13aa98ea8aa6b2011e554cf9fe13adb3a3626a1732df15907cc3114f91efa8da41be3f44b384b72625f9fef8416ccf229a37f7db53c13e6b88842078bc43f78e5f2304c7fc7865accbc2fdbd08c1236b0802dc8ff4fd57c07ca75ab8e872f17e671a5cc863aed801cb59be7f652e59917cff0508e654a18f8c2e8c815ce6a87fb3a0e4cb32d2610dd137f751de640d75ceddc29e2637b6b70f00209a1889dd97bfd58c62b08609995dbac09af88f3895e92572f13e5178875cbcf7bd1b76705c1870bc433eda45eaefe3983a2b9aea5eee05ec156deac87b871ec775ee95e2379788ceb93f9290fbc136e10ed105b8d2e50b105c2b754ab38f9fcb254ed40b102cb35bd6106b459b3a7768dedcff3e8c8768f9de97fb3e5c0cabe0b19f64cc47fdb03b8735d437f73feebbbf4fe3037c87fcd545444df9fe7de22fefef5f29d204ff2b25df57dd57dde9c9f0b217dea1ceb9ff12c3633f0de5fbaca1f9f77ef77ddca7d69251fe242c8142a0cc5e70f2c2961b4e4a2abd1904ee515b844300710f858b0253b3f31e20336833ea7e6d8f823c7017cf25444b3e5a5e289222b2645a69edbb9ad22756b08445e94d9f3fa97ba5efce02a5594e29a54351449390249f250810e2c485ec967576adb576ed4e706d5365b77d0d4e86115ed6886df288f3d20a302825a24495dadb4de995364db957c4d7b52d4184519e51f28ca9611b224220803c7fbb7ec28ebfe841b6430ab2ccc0c91398cf5876243e6477777721e8952b364350c943e0204f150c91671111b22c7e3f7ea8b2022c3e39e8e0e4d465b643103b79ec868aae64ff3b0492ec5ff19c2e3052f3e69cf3c64af6a2211c70923cbfc59c734e1f217b09aebfa60f8a4c4922e4640744e4e043485234e79c406029040d2c381cc8bb6d75db425c8381ae40c9622c43260d22596562068fd10e628b0db22fbdb5a98385105204631a2ca0e1af0859d1932554932540f0832b34204f94e6cd0e30c83477d19318f2f82e1c382e08cbe76cf4538f0fffec2fdeb4ce8c9a01b227203b1334b70e0d74ce068e3011439641b2fbe81ca7e18e1c2ec24071fd51df375710045111294268333f8c7852e09afbbd8331019652e77edb489d1bca23972f19ce1f5be4f92d75b6703e9602cfdc02cd1c951947e74c262c2911e0faee62adf7625c419f982cc8c5f94212c8c5580c47e7cc9740610b32c73a673a1307828962fee84112c85d2688c34081e78f32766f0bd4c636a5d18f8bf36568c0743e8c506c4aa1285cdb8c5c2dcf274108fe099bc0feb5192500e1b4454a902707a04574ce8bd61d17db7a0b17db27fd279dd353bee8d5ddb1dfd6a154deadbe5c929bcbbdb27696dc9472727c719de05a3466ee9f53ba7cd22edce5afed49bb28e25b2e699d15e68dff658283969c7c4a70111fa7d6927b1ef5f4bf681de0215aac1f3733543c19110731c8f3595e8cf9cd9e88f16250130e90270e684f4491e7c37c468678c1d21436fc4064682e910116c251703fb1a4052f2b2b1dab260a056467fae189ef213ca97283990c62b00315e43083d24b877375f1f762df8049f657ada848568d0d4e0b1b0c81e50648b23ffe5e74792b24b04de78201e411478b090ca065c909226c6024fb775e0c7735c5623122734200890e538a58d2b4c4086ce24003926fce3939a55696187c796c21031ae4a009239a58aac193ecefd262030d66d93fb5e3ee5e640a1a777747f51148e4f9d7dddd062cb9b37424cfb7eef386eceeeeee5ebb4a1e3b560b268658f261e2853c3f185e7a8e90c72e3b964c7d0642b2fb0c42907d06409081e83218f941a6294c36e5b106ca09b23391fd2f8ec12cfb7fb1ecff59a0c83e8028700a0b93224b86b0081d31c202a5480d1d80b0207da0068d8605073830c1c067c8b6b13e10cc40f0e3379dc78b611083921a1ff881810e496a2c891d8dd0c30f4c4982624f828e7c0e413d605142848b6c895c82491ee75c6249f69f7372c9fe4b6a7217bd8088ac0451ee2228b13ca298b27f4cee222582b21143598c184a32e286273704e5cf6dc4cf928c6acafeee524a29a59c96a39452c984c754528bc86a9d49a7ecb4494bae52e6531e82c75a6d9d4d2e6ea94dfeaaede1dca2949425d8b2b2b4620552130d8d95d8f729a95081b4343363652623835463b1acc8acf8f82b26e6090686e9e54586b1d06a65a45221d13cefa8a9eb621c8734944a1d3da150b37b7fb68de849e64102ca3c484c72f7c625b63d6d4d9bd3c665063c5e262e99e9d6aed2cdb271b94059965cf40aca70cb02f2905d362d2efa6f4bb61f95cff6b3290932db6445649b0f972dc675432e7a0fafa993356aaea175a21282c7cbf484925d262b7499ee167f550bc40515b3414e2efad3107c63fe925b93bf6e53d3e6b45da6eb93a56f71f13acdf0788f8e84f2adf96bbc4b49fe927f97fc356e4d598bbfba680927d97f6bf2d7589dfc35ce277f8d9769e3224de8ec7f9d50b476d14b1d9335acb72cfea236c83ab14ef6692ba2644bcabe29657f1e2b49fe9a3fb9730be4b1926445c98a92952cfe9a36e4ce2b401e2b599696b6f86bd6903bd3803c485b9a9ab8f86b7a2077fe401e242e566256624849fe9a4a726715200f521292129252167fcd24b9f30cc883946569a988bf2692dc5906e4b15264363bf2d73c923bb3401ea4a35acd8a8fbfe62c778e0179acf85891599139f96bd2903bc3803c484e4f4f5afc358de4ce2f200f921626261f7fcd1972670cf220f9c86441fe9a4572e715c8831424248424c55f5386dc5905f2204941324232425ae2af1943eeec813c484b68b4a32dfe9a30e4ce1dc873b4e5a8e9a8898bbfa62c77e6409e232e4831a498137f4d22b9730ae44172323474e4e4af39247746813c474e474f474f45fc355fc89d2fc88354643653e2afe9939194fcfc3cf1d714923b539007e90911110f12137fcd20b9b3057990982001b50bc98304d4397ec4913cd2f90d6121a7404253680a09b9386e7e05679db556bbd9ad6edb5b77262eba8bfef85f145dd989064cc3d195693205132bb1258f95c95f5da48496ec5fb7787daa5c32169f9c93bb4829897a28c89e2c59f8e87933c2904079d2ea4f70742249f3590d5d68ea8cf02ec2bb0db5b8ce08a1d5e222845629f4f119e7f755a6d6cf65faa62fcd947dcb74dac2e4220cf0389926d3d4c1f3e97354130c1ca8f7cf54c107903ab75dd2041ff2499deebb1a011e4511c75f7502c93dc54f0aa5747316dd04ed8692a6a2172c71ef6d3a40b2e0623b80ca2c9b6e4e374ae9cfe9356f83958ce812d73674fe669fe35aca2e9987ec72c3160df9f565c8af3a5ee41b8ef333207fe4bad55cd616fc5d73a4d4ac366d2a9f82439d23937bc608c6d94b908f1a6a17332959bbe8234952880411499249920d7122221b2126a5b437e5da79d1812e1ba24b04c13641d0f5a07e7de4f9b4fa44810b92a4a4c027b7141d6ec8fdbd6550c6b58dbc1d83e253f27b9adcb8ef4f7b9adc48853d3dfdef0fb3e1d3f3668637f47fc0646cde50fa148ad4a3bec98dfbdb6f614f93560adba7fec6f6a92d9ce18ded51610f8c7085b0611b95b3794365bb700fea1cea4e6470c03e14ba908b14a6063c7f742127aa2f80e24e4cac5e5773816cf6d7d83405d5998b49bffef46cdef8026ccb46e71bd88677ded09781b37b31e8873655863ac77f7e8dcd1aeb1ce954a873649d237fe652b4c068889321492ff9325a574beec01a17fdeb1ca7469de3b3fe748e0b81b89318f2b6269b2480dc9b8cf02d5694441677af4112ec8c595508e27fb4bb657777cbee22eefa4b4ad7ce8b3af52968dbca9efe77ba96d76ce93940beb714f2a673e4778b9d236d6ab29c4fab7f3fc633049c14ffc377bafbf4ec3fa5e064dc1b6e1bedbfb37bebfe2decb1c794d3a1d0c1a2b158dd26f4a5f4a72cc0bb4b2a0bd03f3ba7eb5b4ae78f2a9d063d74e8bad6162cfb7d4e9f734a064800b84f9fd3fd32a00160d3394de587cb7a846b1b9fb4b36917dcf7e7d8e163ea7817f582db0800b9c349852d48d4b6a55e76cfcd96aeba61cb1f2fb843806b3ef726b07a2f74a1a58284792f615e28eb60ab9751988ff7432e4cb601b6578112e62bef1db6bd45a9bcb0db00db66b9d447590114e9decd983b3ba3cb3be58e7a3b3d1a4dc4a5426b6dc43fe2679cdf2429257dcf31751cb663eab45d52a9944d9d15a810b5932550d836e079e377071bef25d0d49144a9500e155901e9c50c773a072321298dbbfea2f954cc5819560ccc0b5ea9bc8e4ba1ee662b9d2e6bbffcc7f9de0e58562be80a9afc6515f9829ff578c0e04c96c917bc1e0f291260f94e29a594524ae9051b4629a5331da594d250a2ae87c20fba59af0607327d16e810b72237cd9755588fc6e5b60dac7de361e06e974371298eeb268833d7712a55e654dcaa9b6097b9976e82a9ccc5741b2a73311c8b93e9266833a74205f771345d0d4d6b856a7280f6cc806b9b1e174c40420111acc9fcfaaeebf28155834785d29042b10318c460f3090e3f31189de1add586b25096df23264f70b167a5d4dd2ffd79c111e71b8e3ba64a07fc1ca5238f1d19c5e16cc371474685e38ecc82bfdd7edc916dd8c37bf898e18e1e2eca078f708b863f6dcd6f0ae62e9a0128cf13e0b19b720b348f2e1fddc8da21f1f7fd8ba2cbb5c3da826772171d8992034c3980a094fd75bc4d0b279b6fa66ea6cea1839602cea749db1cb968149332298d3a699425ad73803892b576e184e589ecde2b4c9d1d77778f43019631e903e2a0c00ef7dd4e154a2354b8d5af2d191911657f7914f351924a8117309a3a32768d56d8016d5aec17471c597e8b4d812c7d86dff72f62d7513ce07c9a489c55127814493882c50c04a0a6ac6eb1ff76e8220e0e3b405092fda910d3129e57b284806fc3ece0548856d999cda6e0a244c479b1443e7d0af6f7e1d9a14b942e2a451ce931f177d7628386e2bc5112030ee5cc459fb445f92e43798fd07e1a5b09c796ec4f012d4d245f336e80c756c2117e962ee79115c5acef419b8e38531eed5aa1023c62992b38a77b3c3fb20c5ba8b907cd787634d370cf3955e802db1e86e31d3129fbe360964d8b0ec76fc41e2feb7644db9429866cb21c3fcf8b43d145d70c71c40fc7756c60de428cf93586b43f8a99c78a17a325f003d672fb96f2b9ad9b8fe3372e6ee3775b3eab667be0648a9f9d9e2296fde9ce8b3eea2826aa7139a594dd1dae17e80ad1c0805bbc40fe0a923240e011d3306dea5c8c693bb2a9b39aa26ffc8164874176c42fd0eaa973260c355b71058fae0b94fd5d2d30d1f58136317e62d19838a9993ee0d1871a0808c883fcd5a1a4f913974c68093ec0a3036121d0855c7c0f72d19b748ecbb04317722019d439fe0e34856658ce24f625ee2f811ca80b1e6ff66e5627cefe9cddd2b505cbf0ce9a9922f0f8d5ec3c1d89382f6c7cc03b334411c75ffd3fbe60e1b83845203c7e5f0d66551f74d38e27a1ecdfe34e39e794735af976b39bddec66ad75df51827feb09cba400c794689b71a66945f312fc2bb802a28901b720b3ac2281fc257f4573710534ae682b2632bc15d0d398c80e5150651a6eb5ce81e13242f85aa6b9525a09f9eb27fb6f492bda8ac9cac99625fb6dda92b65ae7d021bb94c7158d69ab6597712fc0e39d69b2487c4f5f0dce9087d5124af05f21041eef259a495acd8696ec7f63269530e92c4dfae5cbd9cffcfe0ea59cc9ec72e62f257256bfd90c67b55928675d9b85b3daec7acc99c0a38ca9b224e105dc6296b52d0532f60323a9c41fc60952e625c46478bc31bf226d204312547200f3f71ae051de792fc6dff74d246373672793f0021e9b8888fef4cb504e29e594121c75d0ae5dbb76d823ec31011ebbe9e77f37fd60470fe953e79cac2aadb4d2ca9195e55759c39e1d3e7ab46ec0a35c5a925a5ce763feb7934dd7074ec2da46a604f867f41f192dfb143f8865ff6ed2f22895e42543c0fe1e6bc96fc107e329fb9f70bb1a170e6b8697e02f8304e609b2c56fda0907e1f2f97c1151898b47c812bfe99e4923c64cd99ff5362d9acc1ff2b0fa3cd0e7a0c0a17b139e477c7094fdb10f8a48b145c761acf9325882cd299fc993dcc333066846bdf058e1c2f15ca14d4e763c5768fe72a0ce3c4741fe6a284eb8e4ce3c576832cf90e70a2db78d3b916be38696ec527e964478c89c01d985055d8690db838008ce83ac49ffd6a54b17210c01263d080480015d863084dcc5045d8690a707011172879787cc19e8974b32f52070735b0f0233735b273d146abe2eba1783bae842be298aba9b4da526752a9b525a5f9c887d014bc801367b9a4a14279a80b940699801964bc80166615823484083213017680c4f60f56dd8d3546410020bcc051a640a58c5e1bcb3db6f3f602ad4dfbeda960af7b7bfa1adbf85b6c337d3ce9937eaec6928454152602e4c1dc0eaff809520921004d30f745eb7944cb38606659634efeef4349510ffc31d09765c9c94d639a773b9e99ca655ac73ce49e7db9a8945496968682c7202ba35078b1144a869ada0f954ccc8b062605ef04ae5755c0ae503295a82642041102f425e8e68974296bf9aa54c755af57fc0e6572c69296ebea37edeb0a7097e2ebc9c4f14d01cf10d5b36b4e17367b426f7b9bf719f0b7b9ad48bba5768de5c50cec4ccca9cf4a41fc92425afb908ee9837f449c6a4cc9778e0eaf7df0af3dd4fb09b313a140be43163a8c45c574f7fe6ab8a4e087b2b50b133777af0936f7217f1604be65e64c9e590322abea7ecce9995e67b72322a3e19159f7cfc3158da971729038e171c3f1c5074b1bec8feb2055e1044c22d9a3a431b33e64d7d1bf3a6c284a30e168ad54455117ef8bf4781df7b8e979797eff620f00cd852f1332ff32bb0a5e2572f33d781139ce901e79893a50ac71e35f770b1fe8ecafa56c5e4c028b13e0e1e1bfe9a9ffaeeec05c71ff982323f4116e64fd0fef5c2160defb997e13df73f7297023db05dec68be3d193af2387ffb9127a883263c802c00cd76c7c5fa81232ba35e05d8428cd5d798799970b2c06f258bb4403138ea6015f1204beea4dc453c9065cebbf92fc4a9c3e3a30bc7751a266303fe11e7ef088f72e8c3cfc5fa2ba4c063337d7d5964ceb013028fcd54bbeeb9cee3c2560dee532f83f33c25bd1853089cc3878e1dfedaecd7973129f3d70d5b9b8cc320716d01dc453b78cae32d723262819b94524ae588b3a50d05e33ce58c5965e763eaa47ea27e7e0a35cff933acb5da7ee9825bf551dfb5580cd6aaa10dee533f93486a8194186c8a33fc557f9b787ef366b29ac06f43239ae7cf9fd12ebe3c5f9c3a3492a8222c67be122a74d5349fe6ed5bdb37ac6bd9a7d97a3fd6b450620bee67ebc94b05e1319dd26d2c2e93e55806fc3eab7f26a24c702f4060fa5cea03f8bfde9ada01d770dca98113c610af78472cce19f0a47986e38e588560f92c6647022c5d738a734ed9dd8deb6c3aa977777376f7a6ba41f4a4f4c739e79c60e7f4d7bbc94c29a594527a27a594764eb04a082c7f86077f992b94526a53b06d38b86143011cc34c679dbe6d281cdc40034bcb414ab073ea8715b0d65a300726eaff48dab998df343c4f8c31a5ad02c7b48e346ac5208f582ac5286523179728a501f15d8925a6dfbf4bee502952970b072bf7e123614a536992410750f2fcf0eb5a0b72b0c18f0d3328019509022338bc3448001d24c9f3ff26f181868512511491e78fe0c5984e002451ac707717224802ccbf51d09083a13cbf06cf0004b6bc18b4cb730b972d3be4f92bb023792203c512793e9d4f73754822530d050de073779aa72962a86285a80734cc0f24a9c1dddd5578311c0a2101b0edc5a9d34a85ad14e8cf4f8537e6fc1eeee96ff466aeda2e05decc6d5d0569e62e9d6e656ff7aa78d87207360c860896d1d9863c649756eae9a3be956afd6da13ef53705fadda7c01bf46fcce742279a37db57cf873c806574ea022e3a49d139dbcbe08073b8b8fdb63d4c0dd8860ffd18145cd7409ba527e347bedf20dd68965e8cb631df82324fb0411ed0060d42587e2b85f9a85761fe8dd4166ee18dd4f7f8a7409aabad5d162cff7be6a79e8637baeff1efde82d3b6a8df811cf81355fb4749246bd37a976ba97e83b5ea5b9884b5d74a61b5e2be03f457a10adcabc20ecce7c2163bc74a991aa40f586113d65e8c560adc7baf02f79ef71da0cfbd0ade7760bee73029c5452b9f748efd0bca22fac1946864bfa603b77ddf18f0f8e97c351f0c0cd8bebcf7a2e6f54b3357ad6c5aab4a863b57cf2870cb9c7b17c444728a88cb3257bb0bdeccd9ee829748e6b6abda72db6c4ddcfdb619b758b6cfc5d8267af1d75a9100c5d82624324a848408d50c09133549a936f15c61c263014f2e562eb5d600d4923455f74ef6dd2840589f5cb45c5cb43132c0ea34420d079a94414f59da980f8e4a2eb4320f6d6cded8f721613bb27f4cbe2fc351ca48e51b0e651fb18c86f3b8b11891dcc36b7c990703b2879246cdfe15ac5cea53b7baed907d62892c9375721dd4cc4af959fab14356c92ed92dd628db6fe94e4f40b1d12a59c224a83a5d61f254b9f8abc664d67e4daa4a3a5244f66b167f59999afc850a4f98a02bac3517edcb10c7456b7fbc20e0b1d66a2ddbb73fd94a97e2af5a1b81360ee2b858bd56292314a454a5db882e1b11c7b57382bfeaa7a8e0160a22e4a6ec7291db401bb33e2e9230fb618bfc0bfad6851db0b4f0ce9beddb4b3d172ed99f7963bf8542dd9aad14234bb2f5711d4b8bc5624060f66f70196bf2d846b51e6c2724c5c80af2d85cb245dd6dc85fa32b96ed8ff6a7e6afb12ed927fe924148c27e8ff628db5a1e6beca7c0f92e1bb33ef6c7d2ead2bf7dfbd2b7187511a2706de333d5101b72dcc3c897e00b4c3852f932f3031e258d2699482019b4a3878f9e997715cffaf1eac8fcf62a401fe08e79e3bfc27dbf60a53f1506060606e6c76ec2f9a53e56adfe05c4e1d8e347963288a62e97e8ee8f6d77058ff74a59651569be306e9d8041ae2ccb0f1d6d6fdb567b03bbeb46e5bb4e185d8e53734b390112495c5bf9f625cddf5a3b24546d8a6bd93d553c384c820d4b7d36d9e5a2f5509c8101fbe760a2f7a9f4e8e3f88dc5b12ba0f8e8e1af5187ad651dbe80fbf673ecc0d12e6ab78fa9733b47bb00b3fd1d5367c2be99fd9e2b7e70fd16382e5afb2b6cc038aea3a31bc56cc11a1e5b0987bfecdba780eb489b442d9ea18cb8b619fb3e7727e72f60c3dca660bc8bba2814eaa65029ee2f57ab17830798e7543d68a6654ec6704b49c12c73bf7ace639c3003c64e7ee12f16ee735f6b707f514df0ad0f63f5a9af7f024763f5dc77e1b82377ff02f6bc3c067bf0e3898201825b2a386ea9205f5e7ec3eeaf50ad1aa98c7a54c8822aeccea19fca9d6f17f6a099fb1407935127c0802d5408a37e535f6604f886306082603b6b9cdb2db44c47f8be5fb75a7fbb9755698440431418f4391c7fd1dfee9db1f5acf001cb980f17e907c1313f6f680c88e3226585ae5ba5943dea2637d4c6a25d744fff3916b6b7976b18709419e6b99d1d9d56ad1fb8e3a2e1ef47978c16e18e8b9487d6b75767aa803d12f61b8cfeec47a552a99ea37d8fbf62bef516465fca6c9ebefc993a354f5fd2a68e084fbf6fc479b55abdeb65646454c8a8909199a1a1990169a6915e0b3436a618ed220d5f845701fc9a6fdd60f1007800843d2cfe078c35857a3b72cc6ea68a8f7601660aa3dfb3a78ef7321fa3e2e9539affbe82df576ba5a1f9efdb8bb1e2fbfea3f97e05c8a36968c29d185fe85e0c15a81e34cf3ccaabc1802e5dbae4996fcf01302a409a67c0560d140b308fface1ced58803d2c7e46cf086f63ded00e840182653ee6e9db842d15e60824d47c4dd80116ef8feadee54260d6d3efeb4160995678fda67ecce36781ed624c485dac35dc1ec684013bbf80e02897b4403d1083adfaada7b1180c045b35b421c2d73c006826308ac1a68782fded3b9045e7d07f50722efa3b74ee205f578d11409c019a6fc8428689e19145a62f025803b6401bf3863eab09297bfa94d27eca94c6fd50e1333c00919032832cb52465e614534285a41c71f29226c87c3424c89020f70042a6d80a9430a4070f860fccd061cbee96dd56f67c49dd1fcb981358ce6c4ccaa48fa44570dce7c846d5d4c8e0484d48132260f22925080210cc41f90210183785d881101d92830e866a3741f9020f503cc1383b3b5ada5c20850c42d7ca0fb52030176a8e40252d91c128d54db0a7938e3cf104cc85991e7c5366dd151b9888794088024815245bd5800351d73c5003a617214722800122c4034b2e04891630c11c6c262d3039040a2a46300777a8c0da0a0b74688239b8d304e366ba09ce2e410465618239286946cc605b12488cf8c10fcc417ff202198cfba2189d4088a69b60436972d40473b02606306e05cdf7f50a118238cd408339b8a305e6824b7a04b7bd70d16b5e4e79e9c5bd7950f0885f5880b924754088f7abc161c99fd9bf9af952d662a2c0e3f713d45185b2fc727f353aaa50c61d5e1292e0f1fbfafbaf4a6288f0d83de11c3334444c0c100632c2dd9391bf466bd43de5277f75111725d9bfe3e2833b4cd43d61a318a0eec9a87b1a6380b2c700c5047531444cdbc72c652fc135babc9ad20fd8f86597ff3f6046d95b296c4fffc6f6614f1319dea07f4321af6728fb6f1e50f6ed67def80c639462b0d830a61663042321081e5d314626688fe6afd1328dde8ff7e394fdbd251e9325f0e8c2b14bfe92de8fabbb3f5c028f962977485df47ebc9f3006d87ff47e688cd512842c57d2269ac4600d6b32df27168771e4b1196bc9805b3756983733eadbf0850e98763ae09d1b3b2f62338adaea69852030b171430b0de8095c33c3f232b94097d63929d4d080b10c86ce71bc7a9abee328990c4714d1ea8996574d2ecadac87f06cf8c26e17cea95e5007b8d9158cc5573d195574a3082108109bb4cf306081ec5d84bae9662489c9ae27497c849d274e4f81cff4c396034136b47bbf809e7e70aa1c8a8548d3656410cd18c0804000400d314000020100c88844291382c20d444457d14000c78a44278581a4ab3288951180519848c31c4100000010240666a68462000ebe665e0446cf23d2e6a1efaec586a783271d83f00dade271851b2f580454f01a83dbd6d525bf8e45cac0428285b2ab7f5817d5dee8ce122ea3da2235c7cc6f6bb3eeeb5359514573c6631503fe45d8cbd014f192ef29e619e5799cc06850e93611d4cc197d7e42ae7a825684d77d2fe9ea1b18d7f53a14d0f7389a2018c500690bea0100159fb08d2429f1752c87ee67c5d87ed6c9bf888f97b45e6757e722ddc0f48034ee98b8b9ab7b6c651c1b126784300ffb624bb942dd07a560beb42fbaf0feed19a21a984359725207d89aeaf6e539e2c1f16dd4377c0a554bce3678ef593c0bf72c2e687961804101d5f06818d215e89b0d989346880d8cfdf222270db68d64aea144d9b56df0a022da91f75b5551b87e70037fe2922528c2654d68e05e6f9f26fe414ad8e7452f4e85a5334e803fabab7849c811d952a28908c6f9fe690d1686c827078c66d3088089d86cc7357d20a8ec4d1bd2ea873e3feadcf63fb2d82d15247c97b20e3dbc317af574269ecc28a3d1fe448bd2793027a0f593ec8cf1cf8ddcb87cf3cb3d4585422258fb79437f92ed722401bde5bd5b89cce02d39d553241215a4f66ff2a17f200dbbadcea1147db25ac2987b12dd88356102682bd91e8845bc27a6cf946384c34acdab58decee3490052103d1486c0303a15532b2747f189e42c69c07395645ef81258fd4a485a57abd462dc8551c130e37f7a0505e28978d0047f28842d2b233aa933cdc19ddf3d929e212e21b67283f0fda623a3b327746df6ea2faf529c752d102fa0bdd2a5e0c518f895039daf762a686efd3ee2856ddcb9183d2f57b17eaa7a492627fdaa743fbdd88e825f776224baebd683047c313b4eae69e04b2f9a972818c203d46a1d424e958f8e05339ce076ba9ca4638e08208a1fa9ccf31f9493468080a0d38c0ac8f167e891c8434c954948582e5df27185d054c8e5d04149d40c8007eb62ae947d0c8aba090b1098233516d791c197ee91dd636ef5c099b29f74a999da9a11b5c2004160598035815c29b652d709f92a324776fca477ea1810c2cdff3cab309e8bdca1620b038df73c1ff7516ab9520a8636f4f9203256e5c8d06e1ef1966cf6dbcea227956f692ace43b01f64e48ddb99f12b86b021bce6dbb5d146daa7c54b74b68b9957f6008275b05df108102c879a6b3a276edefe8ae41d5ea1d011c0a59a1c05f5046ae9d9bee2a8abc4970747c502a8d753a3487acfa8225e11bca47040f1fd30401a2fc8c3cd3796c06119ce506b23303cdeaeb410ae3a8b533e0d6696e848fe26b07bb0549b19ed6b66546458abd1f80557ff19bef01e55e12f9564dbd7a0d711c4d2b60e9915cd613f0b6994cd865b79a779fce211cf22ce02505b87ee0d382b11dac45c29bf7cd35713db9a1e536807a6627435934b174e5181c800f86ebad433a18b2dc423a2198ddcc70d73d7db99e17cc9000e78b780c4cd45a4b75587db4765ba7071d8ab147cfb7edd3b7c38515cdd0f200198dc8e31c0cc0b60230b23ebf3687a48c4bdeec73569e083a95446926b8c34711e0792cacffcd32d7f9ec7465709d6130d46996bcb7d908ddd9fbb70248f3ca3a70cf35a80b05c004fdff769d803c509bb0f7c8348329c34b107d681800aff2721e9a29148a1766e93cbfce0f422c667a8dbf865747c8231bd04c903de87f2bb0872d2b0407fcba625d5d39beb55bc53cd1f084c8b9117dd6d961b613f0c5d93a24eee60de1caee5a0bb600ad13b592fe76495d5d1f927461e40a4049fe9512b538012c8c3d2224db4e49b655db12df9a1346208acab710d90dc1c64e4fe97516221ebb69de0948995684705fc978a95a4cd3e38d4d0f77460e96ebc6e4e68bc6d059f00bbcb100c4189dcd7e271974cc7eb38ce8232218a53b24bbe8cc71b63148255ab50cf403482642dfe4b9f5229a765ecbcbf639fc02de0b67b69742a40c918b1c60420475e5b313fc1b7ccf9cd206f30eecdfeae2112e63191b56dd30f80acb282284210835453926e0d40660ea3e2046bc5258288c9ac00158d7fa4237c6e32986b896d34ed52ebf39628c29829cdf3216e22c5b0a19d6f73294a3bcd0e284b4d0717749f7c8b7f2a115252d364b3647e212ae6875c75d2252e8040b0a90c1019ec7e31acaabae7391f0c1ddae55aac98c87f6e654875ee9cf9c416ca8470676eb8a1ce5b9a6a0f1360a5e016b9fe26e590cb2459f0b805bd32699771e20ebe96de32dbe41c1c649893278fe66ae129a8c38fa26436169859660077957d51d54b6118aed293aabe4afe11d5b19c114ba51ddfa22d350fc26d04e1bc49269f8225f8f3869242b9c4f9bd9d559118f3cd899face4fd1c5dc92e233461ec50a34a5eaed4c9e7c208815ddbc51706e2d59217f16572074c56c3fa1a2eaada005ca5961a019620f2895e2ab443f96ad59ff2a45f8141d16683cf3828ab256af1e1ba0dd01531fe3bdf8821b067b1dfb6d0741b8278fa8f1648690d0879b8b9af842864ce54deaa381eafde5f228674afaa3126162a0abab4e075e505095567c50b3cee74451f580e8779a5c59a3fa35102559bd927d183473f9cea4366158eb729b13966a11f0fc4e016bd3926fb31b02dac8554ba17d8879ffdb93ee9f1728a9a621506d9540d95bcf912091000489c70cd37f740dd23f12a3c70dff3f15521ab11464553d2a64cddbc8394976bbe47a4a1b39e3bb4981a7cb7dd7ae3e3bd90651d0453e80df5e61c4c22d6c70a679186914d3c8a272728a714cc0ac129b0b47297b032bc2cac3ca0ce4db12dbb985aa2f702dedb8fabde69bf6fff69bd0a825ed218a58e82a65c0b38e1726e0fb4ce9f6c8751a2822b843e2868c7e664732b57295ea289dcc366ac064c09c616ec240f6c3192f7d6bf7652b42d990dda274624e4c82e2fcc41b5b1c7736bd673de0e3d647229275234e26d757d3d6a347c25d4774b4b1035421a476bda84197a9df7bf97893d13ea5501ae7183e3817147c905641211174083b45a8c927032b6b63ff4f7ca38ef98ee7e431986fc33b3a5bff1f6550f3e26fbfe44bed82a61c35993e7d1eb5597ab201395ebbbd5723ab69d13513314e8455a4ff740712f18357100075417eb137b7f67ec7a93422b49ce18e0fdd0d6e393d8c4d7d5895123d769f1337bdbf8ca0f70e26eb0d625f8ea1387c8db2ebbe50928cbfdbe116718b81a25ce74d48e20e0dfcd6130a06d4c6886527ea3de5fb75a69c91d3255e49b6c770989abbb3bfaaaf6f18473493f7d61ed3a074c1245db5e937b774cec8b43cc3b3cd3bde6701e425eb7bff99e071bcf5818ad8b07bdaa55c28886617c1b7df2e36130c2bf9fdcf5b4ddee0727e06c73f2bf7003a13acd924fe835437b13b46189f7e7118ab3c911dae6415b20e6b9c6c16b093ae9b86882206ddea4f535b925b84d90a87a344d7bee49121358d3ae319e69aef4eae9e72769b1e7a32f2be4c94e6757d24b88dd6749fab3c8d18cf80109967e09a3436441c439aeb2f42273622a30270fed77c3d7316665a701f7ef69a89f521e2e2872d1972f3acc7d4ea2bb598e1e616a829ff84166b971b0911be397f7d91e480b8b14f02faa0aaa81f56acff0fac3e879d9d6bb1a0b4d259412c733f666445f84bd277156b212bca195ddc2f1bc4ba4cd093a32605a4753f8d388fd32fdeec75da9a76931917c960e0666aa8bec45aa4ac2df3461971d1e0d6b9825826582cd57e9295c8aadaab65a89a438b9a6f9b24726fd8bf9b04a7da986beda48d70d1ebd2803f299b904aa09e75fcf18b7d26d3b3d80a855bf35383bf195876018183d9667d49b76fe0d311ec33482b4c489af6907d5cc33d94b92987de2f3018f2272de368a489f0adf74a5cb8ea43c81fe849f2f973792dfcb741eef1e37edb0fe19fe2d45f3e0fdfc20b755a83d9238346ecd9f8937f9963b17a06ae164b3abcef8122e0dd853ce65548605d2605dd1f648378e2fc4438a27d49851ec38803e7d05ce3816f5380ca0c544137e20b0b0c2c7c8ba24c0c6fa5ea22a4ccc3d4582425580eea79a69850cd4bd629e1a208319e338ccb0fcad8a2cebd56889d615368705cffbef86cb900488c9492f1b9d9283e1f62747021db74e273005563c0c8544ee67b706368b4ea69bf6022f331096831ef985e304ac9b213a73167f54ca6a7c72d1f3b6e3157007ec9e4117560ff5ba75030db64247fd9c799ac43b19eaa7bfa31bac931712061d94c4edf4a9cf410b331fbcc218a1a7bf58e4052744d70ac416c2ee4322cc87277cf8644306c4c4a16318570d42f4a596e74b06c5ca9b74ed1febaa6c847b120c168408cd76ad615a781e14db87e3db94901985bb820b01e1fb90ad184cf0e415f430456f3be8abe37ce4659d412251c949a6ffd0a845f67ec5a872fd522b5f2667d00352692ef9a48d0a732129b4896fd67355d75fd918ecb57342407e2d4c3d694a7f61a00c11b4d1080bf9ce5399946e86f846ac7284e8c599e0371b09eb1eec3906efd5fdf80d5192568e2d26044df6e0601fe0f83a47ad505c9f1f30489f8523b38472fe2d33fc7be2f4524bb07dd542aa85a8481ff6e8e5a255f401e1be0ba7786f87d38a9fd9e8e4d5c22f24eddb129118a60fa07493ac5e01bc4ca8b511c5823937fb6a6dfe0834b338256f5fc9563d5bb73eb20670083189c744c130dd47ce53c122272833865990fa16e8819a166443b1093dae859164bee73d338c6b605fd1424722a632c37f59f62d04b30ca7436cd292e6f281d8dd0e2dd2d8bcb02e6de83b942097302239f0ba4b2e04e58e1196c60b2dbed24ba088dc073c59ffcac25821912fff94142767a916b48425f7e141132d11c129b481eec022b5124db73927986d13609a9f05b4424606f68ef911617cd17e181efee72f49eae511379ba3748ea918b9d971b0cb85e4c6f0b7bd1764c504d737aace1af9f153791a6afade8c4586d1e30ebcc797b628349400139a3fdadc43cc1b905245684df043c7b1f29cc8da21f03c4e11e5fc63745bd5d24b67c1f87b58b090205127adc78908c555a9f7cb72743d939ae9611c912a7e54795c971f39f903870a825f1c2997f5ae000988bb8a1f78882d5baddd7e6688111affb1ce759ae5d7db86d3519cb6920dad8ea66d41651ff44421ab76f6a8f97a43a739c792f009c89739c050489244b43e59e25620de7ce00d4ac6573d15779f283f8a36c18ae48184394e28d2271dbf27bb124776c07879dc7bf71a440cf75c7fb18a0ca24f3342daf994e973a2825375b732421e3879270e45a1aa9b5168eda945953ddab0e66989aa135345b9bdc53df7d0ea84ea798f92f57d007069a6df186bc24418dbed596d1b19483975a9ccfcb8f262b0cf519ec6611c5a411a2fa2a6e228c53e3443db6df4dbe7d79174ac7a6d519425ad7dffa8aff5982494339a75bd9c18d589ad24f1955ce1d67a29a388099a8f8b15929bff0d93cc31552cdca6bdee050972211b9d88c6631630c4cdd51171d46aa6b86ece4dbbeb48ab5a7876a7b2a5be28de1fd0cecf7b077f1d8fc9ce2c83d640a49212687ca89d9240551f235a6ece0848e5cb7229594b53791c47e5d73e686e219b2d6467a1ea85c02acef46c745d3402db354055ca95a13c511aa0e7ad8f517cdf8730db68df23cc991e27800041ce890351f0d5969f851f773676d582048235416769f0caf72353c65c1f58f793e7025a805ed531538cc98831c72c26835e2e810f20d836ce39f165b71aea137863d99c3e73ac81c7868104e84a88570514d98360edea3dc3b5246cf91a2faf0b328a2193b7dfc650949a378e50a2b809c5971cbb18acd79c8d98e77508cb3fe17dcde9d97aaa24267a62ea3060fc7ddcaa08c876c02c1c826ac42871d7193c122869431fc0b59e0edb911b58402f10351d396d14d739bffffa2a56b377419f95d41f280c330f5fb33d06bcfa9b58aab62806524dd217a4f243a97ad4ee9274e87d04fadc41c0c477e9f9ff780a40f563d297267ad58a6fb651fe721ae5df3b4f06b323a7e2528d4090fb6c187b4e6232b72dd5c1e1527f0e1bcdf73272b1f3d38af51302c7780a2f2481e8598182ecddeba1843f13a0f607311f73d2321d260672bef3fa1726eea02f22c7861bdebb4600904a57f6339cf602647481c2d7724a8faf59be7788f2bd54c903a70c1e2f30c07b72ea14a28e9e2b852b9a993e58651952448def33c4226d288f2d7c885be765ea857a145c705a9048822b8f8db8242766a3100f0593f07adc38212000e68cf2c4e17d6ace956c0e5f7e4fc6296ab1503471a6b455791b1dbd391b2541fe6c46ef2bf8b8448f62898792e55778d28fb66bf2128ae9cb07f5cc796f3bb370482117bce36381c5c18b11a8dbc12d5013602f8f4da83ac33365f0429dec6cc193e0bb24f9867a00b9a2fa8f83db099233d0b44a7eed09854eee5dffd73f15e7c5c6f64dc9dd4b798e355902edfb78529186ca447db98f543edfd1a3ce99057aab104e5f3d2b70512fa4345c706874325f04ae7427f758ef43eda92e33ec5925e52644fd9d110e34945fd02b14e9275a1640f0b215414598128552310eeaa903c7a099e8547acd728e16e457f7689cd3f5ea981cf5bed5e5035566c30f1d14d55ced075faa6bd25d44d878fb86f0614790926ab33060f331f95ca0b0fd51e88a78adfc6d5556fc6c8000dc56cfecaa6ef4256b745f610382f5edceaa5b668cc7310988e64f076d98a1d496b675885250c24afd9fa034117d6351006211910980180154efef8abdd971dddaf3245ec1cfbe59925f67ad7644919b71bc25a7dbb03f490dcb26d0f42c9d0ea5c39aaf5889b265ca45cbd5cb0d258ad26ec1766018e62d8ee30c48f62522fee4d008065e7498da07a5b14695b1e2e36fdaa254e8949cd900bd3fcf6fd64b5c00807f1db6e67eea235a553a10fcdbdf5ddff86cdb5b7ac7ac3da409aa4ff06f4f6cf2e2184d6fb4f7dc2429dbda0a9fea2aa921a16e475cad40276bb9b11f0a0d74de645bd8d37b74611143b99545717d5965c3857da467d7e59da7d1d8251061d21b70c006063623f494d017ebee2d6d2feaba2c24562a0856da5f2c5436e4332b4906acaa8731b42329d49c5a96997d582ad4776ab835e4192348c7a56a5287a54f4a98e8f08be228cd228626a7054af6d1a8fd98a4a81b7cf350e8103d2c7e9a191642b00748abddcd19e760bb54a17d7e9ec251ecd8f1e9b0f17ed1f15fb2840ab19b2c099b557e0afeee731cf5c779014a2f1b7065be32a0ae10e3bc51207d11ffcd3045d9fa7c83733a0176e288d0ed7c8f4040052450a9d953f0a56e6f5d394d9bedaf203d0c1b32d9d072799319dd51f69515667bb08057567a50b716c2c61c03f2c88ade2ad640fc080f11795dc8205b07ee33f33a94324a2b409e42848e774ef38110362dc6c40b0c9b2b0c8e451518c0be1f357127eae9e7ebff1e95a4e3828f6f0f569630c3a1c2ed746a3aebcf98cff4700bfb747d154d889689c38dc4f44939abdf096e2839ba633fb5b115abba4571bf08f630d02eede69e8fa0719a75cef2b640bf0d9fbfc2134b9e0a4a12b008140856693ffe5b40bc7400033e06cbe14a5cd917399a7a97ff17a2298c4acd888ee5eef178e8e98d0661939a2555ad1c84399386b126ba084b3680fa0b8f26308b339f46a26f288c13120c969beb3462dfd6a39203cabab92af58ad3ca75f071208409df02fde48ab905aede74db1130bb0b4900b315ce0120e2fa5d1b085c46473fb3b81fcb16fa8a73d5b68d18ebc6d1f8d38a065f14257ccdb73adac21e8874f32c0825f03d0257e38b75ea752d53606461552d80b6340be4ef2e27969d096193c6f8aa000866227da48ec95f822b214b41dee3fc0582060c50beb32d947831df6810e07d1f5e4fcaa42c4b6d2a345d219fd95de876f5a945d6f4f5811aa2440cd935a0947c020f26832c7cc64022ca1944bfd4e5ea7a9651885d1a08421eb45b84e44be5cdd3cec898f17bcd90593fa695e1af369d0919988ce79737d5b281139c00f3bf8cd65cd7ff598b1528d6c05b244af0e03782a05357a49e35c0d32befc22068df0e650809a4a341735144cacfb819a35417535dea380c79d37597531ae8aca9090830d289f0901be3860539484618ae5f7763ac42c9a79ccacb66c2ebc4413dd6b5567397712f2fb99bf4b8a584a3fc71e0151b6c91a7b9414e0969f8d2971c4590d53a294687ad5cf3ca77ba96d7bd8db31f99b4ca1f8cd99bed0d4504c0134b3ca2952f71d5b4bfffab342da901558fa497f4a7ffd8814f71193603a91d71b1e075b3db347f5d6e5f6829a0c871c6863dbd0582c1f4938b492621d87506b48bfc95041cc51f8a25173242a8421f932f2d5806bf451c766fdccf2541905427095154df74a53b8e714ce559a85203d597c90a074a10ad4845081731065777505a9e81ac536962bb3b3cc0b7b521c6196541ea8941930266e87d280b655d1a0334cc4a3013abd933b096b352dd36b20e84eedfc38d442326000e069a52b1d976ca32d6a9ea7ec2239be7fe7096ffbdc5c14018b39fdf4726225ca38e693d3ee306e1f770999363ca079f8450267c56890cdd8e75a322731ae240e59cf31a9e7b7144f25cf74381361cdcceed60643051c61cd0537e3d87a6cf229e6608662050a85bb0b49431eb8930960ea17446733ea643d0704611dfb165445751734909cdc81a565a465a47b396d576094bdfcc96329f5126203aaebf30503469a50e035595f7c9381211c482951aacf23abb93180c3ce55f075d3ae9ed4f52342128081a1c7a2e2b244a273116d300a13cb3b1ed1f47e748b3bc3282d38e3d4b80f55d3c4ba317840c2b910d51ff530fd5de9cc55e6227ff634d3d326c9494eab34b093efb1666e879d76796cbe2497793e44e08cf1e652df10aa37dc04764a5262b2b91da1d1b7df9294be9169779824678d7c8d6cd17bbf5d20c42b1ab95f5dbf2c9eb33eb1b505ed95fbd33ee6b150be589d340b9b447110cca5dae5966a00bf1d752bc85abc8a335aec4b748dded4bcd0bcc0af2b97b9b04f2df1fcfc4249613a28bfc8471e48cd3369aed4511654fa84c004408d9fb262d9f1a3e71035cf399d60f17f81e2235e68512009c60d6f57ac47f88d0bb1b7f14ead3723a810cd96418b7d7bdea590567f96e5242bda035ee18eaf68f3a6b2c35e126c1f0bcfb35e071456307a30413be1ad64970b120b9c95c7c0a6907f664a8d5758ec178e31aadd0a4c8f9658b2c2fe1ed0a85b61ce010bc8abc883d97e00da474d2c71f01dbf7def97bae95f13a34ed88dbc48e09b8afa0a677eb6d62a40dfcdbde44be1707878342b15b62ee26c3a5a9d3ebe0047a12362788d3120312c82017c5112ac3362b22ab94a52b107765560d53ca7d9f18798163b03c0863b414dce7ffa145062e7da7c8608c9c1e6784de269b07ec1bc05915502bce745205138d6050011e80d2e5eb6171289adc816fbbae6cc032dcfa629b31628e02b63eb64b12430262fc2fab0075d3616e59d9ddc84a785b2fa0d96ca65b55fff82617ac6d03e59dbbcf02c8243d1d6b24b5c65f53cc760272b02067bfae9c5139f8c633a7b8273821496af7f0f0e923831c2b7bdb047fe7fe78f9dfe498bdfd23e044fc2a717d15a0eeb1b661ea9a6b3ab589a642df510f26849edcae0a9dd5f1bc48ee4f7e719f98f19c3cc8eadf4e22bb8d8740a0ddeffc0c7f12da0371560b4fc67f767517f47c0f8d2bb94f1286990ac79996158260d8540e3cffdad4f733e5985dcb29fbdbd18c2c2f4945ba5efabd97db8a0eb1583bd78c8c0838ec243b4070a318dd777ea358b0fee0f01b4a633994c83fd1d4431919fd865763351f973028f2bebdd241a6521b7238e6bdbd1cedb054786d0c2d01f16061841507d8a04a9e86aa746e25f7d9a48e7ad77bee11c1e7c41b60a390d500a7777cd893f86a8dce5f9e64db120e921e7aa2490a90c5f0ff65fac594731eaa3caeada74d1580e83c738d233497f86a7ffb978e6f092e69dbaf5d2f4a7a384221b65bd10ccb13e738ffa628862ff307d0e7bd7ece788279a77153156122befbcb5ffa3500db565400a984a18d2517263a342caec24646c0e580415c57753ba6716b9d00c7ecff5e7ca99769bd0c6c026853c4770139c8f40a49afd931444299e3b5936bb9b2c05c917fe24c80278f83e3d02a3ed5c94e2b2907557b4464b7e038bad6566cb0e790c80ac9b8400682dc3f680d6a770837537a496dd2f2ce9126d7ed23240132a157c0704fd7e8b74a711a2861f84ada316e3ec8a4181aa3d13976651277b21881102f171aa9a26746fb3220f82a2c0bc0528e10201cae826f64efa1dc0a7d58d3357a087f410704292272af85d466742645624c55669138d682c702b7b85456b0ce0a580d920b84fe0350a5c7ae77b43b71260d5afbb3f0ecabb7f1182227cffb0faf60fe0fa0787916544502ec0080f3aa2efd6eb1c3d3d726937c978eb8ca2745622671ee3a7c62121cef44099a10482e046d30fbbf52bf748fdbe786163397573869bbce1264fa86846e3264d376ee2c0a0c966d02c3dc0a0aea7bdad16a5d51baf3238a5f794cde08eec5151fa7a5614f1c120aa27de60fb4469632bd1a607a142da4dbc0f6a5f5c577611c9d65db7a9f7e2ea1e5feaf20657b898430584f55ddce1ba343d0c369dbc45cf31be69db351535326843f8df0710de2d19c28d4ab51e8d565a4f1d38b4e1eb07901d5c936e572af46350b49f610b718ce3e073b35b044fc5cd5f32d908d6fe923deb2ff064b8a21e95badf95300ca461f356520439bd485c590b260ac78308a52a868a794f6ba1d19a56467347a4e7e2e49efb3065ecbd4158762560f8a78bd286a2cae589d7647165d55d7916b0da25ab56197b217da76fd66cd610a2c8fee56276b927018fd8feba8865a422e681bbc6e0bbaef6c58dbc10e580db40294d67e15f63960785c4b35c3f125906a69bf50fc6955266503f1783246ef697e7b7e9ca3a18ff5ef114d40683308f5529664c74c02c93e16a10494fb4e2ce3a63f05280efdea1843425d740e99a29ba560ad74ef97528bd06ca5c47f96b51f03aca5fff38193ac835d68a83e2076798ec6e3bef1db81caa3e2ef1c505fff0a05a0f1232efb09aac6d1c440c9adedc7dc044880e3a64e802e90aac199f986e857efccbca46d82e932ed85fa9f0b867aba4ce1598f0226733a1d3806f845c5d63ab3df0b3cb08b9a2369bb1c19805e9658a34e4be8c984fda307a59af33c2a36786d37f19f40d935e2ec27540103e992d5e8d4204402f7b56730cc0c5ad7cbdea75c5fb08f8bc5c01ba5dfa2543931dc0e7e518c93983945cadfdaeeedf5203cb50a700038df3728dd05329f16b8f67433c88b35ae8a1d1aa3df3f95e3d87bc4c1918af38c3abb1262f73cfc8117f81ca36fe8fd51d42a7f8eaec602c1be0f6abdbe8670661b3d2e53ac986b792c751026154f5b482143c3abd65126c7c4266e2f90d4835014b6d93394ff62d2ab2715c8acaf8f9e938e0e26cb587d0c64e3e52ac728a178eaeed04d7d351e16d325e8962cba01e7b5407b9e652e2667333f7972a704edb68062ce0d0f59af293936b74f6c21c1ff08795304dbb8e65725c734e94bda027b5b1f27e17658c3b7c544182193193cb6e5157f64120f6e104408e16708ce3c926ef8a1d2697f71a347bc0c17a7f6e1c80761285c77078b3b6f534cc37744d2cc49f7ef1726ec4bd277957b87682f0649559b196cdceee9c92a3252f2ee5b11d48a18e83fb096211629aa0fb1f413503f9686e9e09a5ecca4cfdc1904d22fad2630e94964b6e8d9a3a2ce41498d4bcb0aee3d2a5b75910700ce718b46c99284f3b1d27b88e4b08525916bab874025f17dca841c642a8175796b603b56bb4acc94148322de9f807818169d37451837639704a81b1bb3900678ef07d3aed355bb73d5fb4c48304e231a20613a2d5c13361afd2601cda023e88928443819d16f122b456f7274e578d71a51259f0a285bca56634842e18f4370a3f4c42e51034da59e2dacd48e7073f0d5c7e39b61b12a1da7d318cefed375af90ebb56f8396afa201410d5b84612e3facbae4d367a841c54b4381264bb0628df383d9024d46c9f621c5a305b1252c80657ad2bfc3d7936054e19c3d27fd1480360f89db7a940ebd170d0a90aba53469383596c3343fe2821188b6623331aedb625461d630d5800cfc7c01c570699e75e00fb784ebfe355a4c7c7ad2eed68f52880ea5fa1dcb1edadfec10a939da3d6f2d537b5a016b76a59ecac1c0d8e0c7885ce2120d400ef9e955048bede0bdfcf211898e65bee4956bcba2299e18d58d2a0a60e75bc435d779054fdc6a4e59f790144dce41de521552ac286f24cd3aa6f26babac4b7bea29383a294321e9682772c4731945bc78ee2e4e7b53cbe01830d8a508fe9306aea68a7a486be5b122dbb42726428239e30bb8c15694bb15f4330202ad7c15ef75780cc13da6a6c3db7340f2805ab4d0d3295cd245ddc606fe64f9ff10b223ad7b699054d0511e6eafb6325012b25e6f3d4fb6fc3c035619a701e9f4a7fed5b2842078e3a28e329848a930d36295e1a252c9b052cb029577e145cf9ccb62717dee7f0211b5dfe330037f399f04a06723c9ee927ab2d999fee278180e620d9de4ae1482f585df8ff57f375a3bd72c9a624fdfcb07aa58791b92ad49693163cbe4196b74021812582569e5317fe5528ae404f85fb0195a8868f56e0182eefe9f2007fc9075f80d2551d1c5c2846302710761163532022a94e9ca8c9fa3375c0bcccdabf62c6cb063333aabd23f087273748b54ed70b3a5859935b22334b9aad75d470d7d1659db552679bd407fb31191c7dfad636daf6498c3b200b2f024376d5f45f6f7cdf5289719cc686af69692a299eb5875326918f96aa62f82da6f6d5d029f990fde936e84512ba3a040a023592c5f0d1dfa8996dede511ef65516c6d086674c2b0def0ad48249567e4d969e88c6dff218562ce34da261f091ad2eb8fec4d733ca3c4a087224f60ca91b61eb0372686de3af2b3c13e8db39e98539c243a8f4456f57c4a580441e221b080d066c62face9b1667b8962d1362ab149d2f165cf83f9de1cd2928bbe5475afd8ca1d2d915a83d87cd40fba74a42104b07e38f749ad61df8c6fd611a092733f9999db20722a9f57c141e483800e3c9c565b92eafa56fbd78ccf406a62c0c2024e3a1fde7355cd720ca859e933178c89c58b017acafdeec82ba012800d1ecbf7013ac7e067c68f568c27a6950e005505976e989d9b893804951800076fdcfaa3f376c4e211bc8e7edea121cd6086e52be79f2c5445bcbb6cf75194057554ec5296adc26c4aba4a95758ebe0573719e4afdcf058583561e331f8f376b1c6fd5763678dfb612e6d77a4106426e818136106ff5057abd2e3c6ed5386b5bf2fb3255b01edd9f244da1cd2031db335c019fde1d4d393b13600b2c7af62f0f596d673168c17ad77820b3bfd83a7fcbd4022ab49405f122998b8d6b995b485837cf659d3b807a09230e6a874016a8d3b1ce0ce99d28e7e1a693d6e1dfe9e97b7db0948bae1843e0799365654ed549bfa1226c58eca0b95c0abb8b97ce54b76d6d5051d74a1d25b35b708ac9c37ceab3d4711a1150892f9799845e0893c7ef583ff586c1c62d1cee85dcd6e26f17300121931f20337c9e4130dbe5285a674a736249304c010220bdb69a8fd822aa739c7d5613874f50645275eef160f3ac9741fa1e1f5fa16478553efdca7b292a88225b661cb8cbb0afad2768ee536ed52e0b5a11cc57aaaa24e6313502ac4f6d395af1116e786d1f1e3ac00366ddbd696e217d7947018f9608b21ecaff57a3b93487b8bd4b94b696183215d3f0eee8833d1b525b04305cce926a55b352a489929641ac2eb73f74124683f291f20217523c3130d40b3e8b9ffec42a91e7f41cf42db71fcad196b3305db0bab15cf51f4d33e743179698b17b3fbee906defdbfa18141a70f269d560b683e39d18f17d1afeac060b63e1496632d353779b3fd69d4d2ae62ab66495aac995afbe604c515fc6b0d3d0bfeb63f070a0a74b02157272cb5169a636acde43a81a30931716d26932b856b56d8d69f6d21617294d1fcca760c7cc04202f723b1c70676dea9a8305f5394c8485172dca2fc340a2324b4e03a5a7c7573628f55197f73e6257ed4ff0a0485d5a6b86b0b2100ce18f8a2ebe6d9add354945307dbe3056473b8a3521208840e68c4373d2c1800014344b83bd61a4c204c5bd36241d314f1d8fffa7a07475ecc275a923f6003a28721252409e20719724be63dc270129ccc0c6f81b0f1254bbfa88acd7eee2d337fda7d6481b6a61150aa49e305d873dda2bf6ad9811bf266024ebbc58eca404e2649cc68d6124ef5ca95a3d1e03a1f0d76446dc114411a228c9eeae2a2f231d46394059891d0e9e2e468ac816f7bb1fbb665d3d416d382f1123a0affcd35c19ad7636fd748172013e5a219243562dc4a8f8e48d41a5e9be0e8c6211879a474c795aec39505d6e3171cdd21fbec8f0e32745987d26a96e3a550f5ff91c11dd85b44b0340b18a81e51518a27372436a84e93cd80bba2df37cc824be62f05cefdc94071405356bc2001f9d2b277f4155dc5019c029d7e78ff5f307cc7241a0cd658bb68a6ab7f961423696457d39cca7124f6fe435f43edf4b9b7a1637bad167799fa1b14064aca735717c4b4048e31e9c5a29be950f6f9fbd84bce80efe7c11e626cb9ec4408f0dd4d08ea3ea6ccfea17210bfb9ed62cca3ee66e48365bb92339ae22983be17f74c5ecff37950cfb3e1f3e0ad32fd5892a881013a640189c2f7efa7bde3ecaab7dc7e43e21de7f664bc9900cf99e158b79f7c84ca612a51a46e809029125bb7cba52186f2dcaffae2c0db1e85e65ebfb975c7085144fe1ba7117db36040586b351ca7a826ff905f207feabad8879f699afcfa4780769e566f11e5732b8fe7e525c43a3ea17d54e89707e2b16d2d5463b14e9d4805d393f2ed1a054ca7166452a45713f98b0283afbcf7321dd67325edfb78d1eb8cbc578a462c28081a6630493b000416f35491c8325e6e3b964231f785048cf8b19ee674c2994fcfe9289f65011b654913571ff25af79d145e8d37d2969a8059f5e8e9a97e8b9fcc9c7eeebcc00aab0586d4dc50d80d8d67d39c72c9fbe07c82af97aa068c6e57c84ee55d982e04d94e2f5f6204dc9b692a9c2b4bcd81c18c98ee44b4b67432252dd0dad6d3335fe6b985c3e171a2d485c13ca62adafc4bd0397f4abdecddafcfc640cc1aab69a6b9bdfeaab33254a012389564f36502cd68212c503e4849d5caf6ac72973b83b3fc9ba06be805cb72f3708367d9e80079c2ee591476a6d216b0518c4705b5f5201019edb77011ee16b4aa65335d3baa6283bd63e047aa78f77e41296aac56236bd4692d2f51f6b7a0a564790faedd74a44afeaf79fd9bd13de212cf910a6073fde9b2b73a3916b66473cc5e0264509b0809954363cfd552b5020bb0fd65b77b07afefe2dab30c03385a8e6b28136060006f646e4fa6ea2d113e084d7bc2003bf97815ad60715b3376572c437a34b32819a4d7d001645f07c56e6d61a00e529861cee6bfaf6f73c8ddadb1068cd8ec255d6eb94ed92acbf961059c6230d45b0699e9a085d18941db1b6d3c75c274cd56550eeb830ab9eef635acfed51b7ff1e29c47e0016d18032470b8e78f975b136f3b792b3df962a3c1996e28a601eb02c69b436393e5c3fb2807871cd3038c67400d5a976285ccc82cdcb0352b5e5e26722a4901cb931d3a9302e858bddee250518e6ec1d1440e8e9761968c5359a1e046a58e2d49d5b925f7c56a346d11ae9135a851bfd6ea2e09c69a1802a159aad09783dad565b8615b7f7e6d881b09c0a474836c7f56789a882440b6252f348d21e2a8c13c774e4c820e552080ae8b98d97bae180bccad8d11656192c52115c7900263a763362c81fb409a8fa2d89d504e0c254091632a5a42345466838958de497cfc4309177274f5e5a60438b1bd7f94434d709cdc21170df7d4ba0435b62285371c1ce7fd6835ba5043ed4a013a574d61eec8045542794fcbc079c165a739f1e5e47f9faae0691e8d7e9be4740a1366586221f7fb7beba61cb0fded34812d63d0efda82511c2ce2b3ddf8aea84a1969aa02d4c0cfa5caa0e66a8ee715fa51e866ab9c95abd83979b93665e3f22f13c708dcebaab03384d89e2dd574ac965951c7e1415bdbeb7ef85de9b7641ef0e0f351410666f703c1a51b54529f9e5f54ea7b4bd42ce2a7c80175d8b425487d0a5f28a28de25d70ebf268480319b12e92fbbb6f2fab9bf1ecdf0067341de42eb1407922bc6910f74d943b7d3735b551ae8bf2b83f07642da73d4247e266943c60064e60b8a21e4e94b9b022cf1d8596dc2387f5acf21d0c93c5985e0ec739f6d1c896f96de8abb6dc858d858e60cdb6bed0a9af35722fa030953fbeaa63f7351f7b5fe66878613c1d7cc9e0efebe56b5f24b5f6f51e472b4c077e08e42e4061a8f55b135a5b5fe75fb4b0c88dd48f0ecff8649d575d4b33e44b35f5b6fff408bc391f170827cbc92b185418ae796401840775b00de39bdb0280cb9857a848d73aa3a85d4799757bf6ff72291ff1fb9d1e29984f8454c5c396d5b465491ee32e74ae65e9f81570321d7e6687e291fecdf7af5b87f687870d940a28adc23af0e944c2cba54006bd15948746e2e1b770f2578a9501b9175509e23c6e37acd288e7c73f8d59e96a3e9e7804c7343892fabcf9ce97ee7423bf142ef2db4a14143a88d94dc873cf36470052a3575114b9d1bc372bf58f7af959f055291f5c4e07df9dd4226a57d24f7d7667defb8f562be1a1e17b14ea5102e2c082b2894f5c3699989270128bf2e0bfbec2d8a9aebd2ca9fccd0f682ceb7283d98497706d738eb3f8cfa5d4482bffd24e53961e579734c3b0863bfa959a81ea556ed176c1ebc5372ab6cc0ad1314e174780c87ce1348d8b33604e2864902771b06e771f76f3a01834c14673e951a56d2712c067a161cd9a1ed80b500aad41deb129a4afa19f2944700b1ee7d4c203a21c7526ad9abe307571d5b802e3960a455e9099152e167afa28b6edf9d2d18e04cea3c6d3b2648988134fe3fd4fb92581524648b410b5fff8c642c01e1ab5f8f5729c5d4c64bfbfd9b0215271c19ba86b3162afa018d4671cc4505ad23011f061d874596bdcf98bdedc3389887c9bbd44c0b01aa877f46c4ca860301fd717c2e8045014a8cf1ba555ad873d085bb11429ccb40add6580b7cb0ee8ac6a6e5303d42cac99a4ca9857c5774c209441ceea1a469b82beda36ccfcab7aeb8972bec34df4e6fa95081ec872d49f1024db5f7f3ba3585dfed2b0db2f11741e7dac86d564509952eb86c9cc230937be72793f3a3b4d404c3f9be632dd8da8a1a30f01977f9fd472f27192d0dca31ec0b0f31e539b0469782edf927e9e25d0088880c59f39388ea960b8ebb0264111c4eff602dd3860191562f93cc5677e380e3c0f03873fc9ce77d3c50571f76b675199d6b5713a97f9100decd588042be81be77969fe08e6b218f67a29b7ed1268b08c35a80c884e4e078d9b123abdf0fccd683dcc0950ccb21e3e25d36a97e7e2cc13476542cd7922076d239e694442d14fd5a87c9284194d74571477327b3711f7946f169e6a26a41eb4cd524166c73281d72ecb38166ecfd0bcf0ca485e30cb66a954fb081f7d36af4bbe1da022b31625543f73f58925ddb347a57ae7a2efdea877b5a083c404c6bceba6f676d76fa5dc008555e00ec0349abf1f90380453acc6f1e5658efedb8483a3aa184c50deb8276ce7ee02cb312b05ce863b6950ac7c398a41b5e609b11900666d1964b6ebef81bd1cf7b725ef9468a7a5364618f5fc99daf0982b8e5f93a1d90a3bc0a6f3ac57035aec70b97df1d81b6de19173b2a8aa715806d023c7f49cd8e135d90726a943b34951d336851f224b27c37ac0c6ed80182fe35f96c1ce5b0eb2c11f9910e1c88f29db44f61a7ff8a7c8a372f416bc100cb8f061e7650f0171458a85ed1a82d8469b08398322b916700dacab77abedd4ccd1a42518b062a53ec26c6c168d000218201b79ec24e6a2b33536910126417e11a1d299ffc692c40ca5572ab286e6af1ddc2d80a8350d94a4b44869fd681372f124adf8c3d9c6142d4a5964f082e3db8e8fc9ab81c65f5ea42aac52b6def9c1b92d45fc094dd87a00cf381af9eb7f0be6cfedb053bc515128a1b441770ec9e2ca908b0a99dfe70509abf9ef0f8084ee622c48445c7140cceb08472de10ec97cb1afe1b94c0c1d2e698939e2f3db372d0dcca67b0e723f0b0b4bd3b8be2e1e4bd25b97c4b2e39565b7c067b5a88dfa24b7080f4e26676f85f6dcdae2e1802f1f3347c42a113df0ae7812c1c811e888529245adeff6968b203d50086bef6f905afaf4070e23e91c21670bd47a25291886d16a7a918fab4e6821671149b153941ef252f9bc8391d3c6efe09c9e7c3b64a0e3e02325e07ff2f00e336ae0f613eae90111478943248ffdc7c9f467226827ed44b226ee99b47948c409bb370159a3a8aa2e7ce3587ee38ed1731cee9420eef1ebfe22d8be72603028e34a72572d01edb722f509e8cc81b2756aece90b0728604a5a3f6c1744761f28ba3301693c20cd2790a2cab6715817e86e763caf30e2fbd0db37378d61486a113989a441988244cc45d1eb8d5c34fa2096e4b95e31518370262b37069c62bc51e64955e4eaaaba4a373e2b8b0bb59c73428e56513356dd89734e525bbf05de22872594441be4deb7c955ae72cfb9c449f58b52a7673a9ce49dc50c2515bfcd33563da05e4e419786dad16a4bef85be143adf5e12f4b784c3ab8faf6db9d7be27c130c43bb8fa3bf6cd9f0c9fe25bca0128782555b17e481c63c816ebd4c4069b8c5dacda83fd41633c5facfe8cb14da760c56a0ecc67ef8809fa8a425ea9335b4bdaf407ec261801025105326f093faf8b63451dd4c4580616eba55bfd71476614ab3ace94260f1f74ab5fab42d87c1bba8ae0c23e4e1f5db3b0e2ec99fee82b80e64aa4fd37ba81bb916b53d90fad1a7c2637b3862f6b4010ae22cd9807af1ef9e4c76709d8f250e02bcd55cf5f234a7090dcbf0ed2361353bd9f5f3fe69f8293a9208f7d705efc626e8d369819e7bda417b175852b298d056d3b2927b1b36cb3c951462a1e648b32eeb2e998049ea680e8158a574f51accf1a2a4f2dc98879e0f998d429226ac533761d16e17f8b115d45ec80f7041eea81994480af2f0051065376c00306250509e482c74b9222144747fdeeb70ebf976961e90e252bb58ee958c8cb27c71a9a69bb0aab9952f1ccc88dd444a5a4a304ddc9e98aa596016c63d28e3f48518dfafc02963e5faabae96a1748659413f23c056f58d4eabfd1bff185f2efc4b54c61e0fb5d31b7e210ffa43b0b89f1584b1d5d0a88f23b4f26e14cea156a1912e5932c5472e9ad52ab224799f59ac4eca30396a05a5fadd2f1acb38171447f14ff2692c8d92a6a009f6948bdf0d8e6efe83be8a110103f70688e235eda15467165edb7e02c371768ee062d332a0c6be2a5342d10afb0f10f95a1f94feaa0e623ad81176ecb9ca18773e087a9922b4e6315b04f289268a2b2351c432aeedef0cf39298e8a977fa41b28eb36e610cfd4b48b9bc124119ee59805f02cd2a614a75025bbc1725e94e356ab2e04bab5c422f3968f9c80b50f6c05d5c36eafed867c78ca907af885371f1dff9d08e32136515d4207fd280c4247b37b1482855b77eadf3164e6f1a3570f4be45a5f0d71a914a53abcc0f7656e8eee3a87131a6bbac344b48135024b077bc5e4debd4224425fef7c26b26d86f54a3714f0a3e67088bf40ba6f9a41196a7295200e0574880b41ad5c553b019e8c8047b4a630760579322444ad0ef3114870f91d3d6feecdec8a5e861291ce0d1d3f1db4c2057d1cd8972a3357d16e9589ab3da5262242f20fbe60637a83fe663336758e620d28d3a1704266679ae275c32319ae239b0b3160bca3cba1aee69a9d5279d26e2bc40a423427519e174ceeeca138c7a5f0ab36254ac4085dd9fa85a8cc80aa3f3e573ac2e813501e67f490d1ce42d9af0065d92bb69c59a49e4fdc91fbf0216c9155554756ad9d5c216c80a3ca3214abfe6776bcb21186287e4640bde9a23e0121dbee14426ea3993ccc7dce0a2706be85b60f006028c754e08d815113cec64684b9455654e87171b82699de68144fea653b866a2a20ac3bb419cceede45a7fafc925badcbcf9231ab44dc7237df0f75dcad6017713cdcc1cc6b6d6a8005c39cb45a60e15fef1f7e7c515da62ca2911e30bb5243d97af976cbe0d5cdb00b0a5a1a783e94bd4e845ddf02ff7d2530315679af89d37d8919e801972c13de59d155c3e8c38b10e442e8930b7fabd2ebb5decb1b0d239511b126922fa33fdc988502f4244ea8ea4c1d723085c2d90e527d6973de756580f15d94c981be8e22ab204b3e4e2df4db55d195f4eeec8fd5b0517f140cdf2b47b4c3ff2ac969a063d5e3ad7b62543001bed6e520707a8c776844a9615ddb4df7c8d7f5a1e2e8a7f4227053768f867f4ca53c5f0c6bafa3537877ce26117a606480cc81e38b3284574e735717da83679053c951eee27f5761a486cd62620f598e7c6745f8549a885ec5a0eb5a492ccd7a490e2544e965f10dcab8e4ab666c66848a445b29baca0594802aa0048a865650259440d1d01aba4049a8024a4013680d454149a802ad13f4e4f606640025e6c445b147313bea6544137c4411847774b3b422ee5fdba9da2b9f126882fef22e7091accd39021652d122353c0cde39d12218c6a0e5d381f111af1cea589ff5b0c066e69c8d4c1fc7fd67ed25f3317725f0205143babed27bab0f5539be90e40ab0d4922bd1a5a1065ae1edc163130f1a3164ea094205dc74a91382e4838b69eb38cc035f002d2b9dec032c3afb67c1d47ccfd48d7e1f34d246debd6b9ca5b2ce48edd25b2c6b7fbe2e007935c83e337ec9f4c4c8e89cf85d0a23a70c0d7702ba19409ff3dd93736acd44479bd2678c18bf72cde0256476571eae39749b8468b76106ecbeca04fad4371c99691f1615f5147db831f1b9f06aeab2839955500723ba1ab117e6601db96ba18ca1906363d8244489edbc998728ce603c546b5c2096f72d3eb5c5ecfbf58c492898c9f6c92c6703381dbdf55aa8c566a952a329a8ebe11798a5a0d12bcfac263a2a7b0ec410674fde24ac760aaae2fe61ca47ed91a35fda2224fb5800d21186122c19e5fd67a5891fa757b3d0a138f1960cd466ef0cab614e139e70200d1eb06556fda3de0156536b21154961bac56f84df4fcf9a38162a8fa2c88c21f48ae8d51637063a352e84f62e71740bd284aca43a4d668998f379ae42da24e221152432e10edb57bb2c2feaae13314a81a73faceee30938c4b8df51e86bda29f431240624a2574cd54d1aac39f30b78e164668ffaa9e7c36fcef91003c2f4028c3c0b9f7ba6bff0e6c6c5bf44e1c5ed828bfb4d1fd8a26d2b0ccbd7292fa1c6f1886c8b2670520cb35d83130d1e67d25882533d396c11af05a9a96964db22f3ab2f208bc5050ecca13d014698e510aba2d7ff852876d8b58fc0ce5d4f59e5d00cfb6846282a632f440d41f5571d348d40e985a11ba5b88ee272032f0a87e663e943799d6bd4cffa199b7559bbec320cccdb018bd02e1171657f56855cd4e481cfbf543cfc0cc7b0b73311b166f350c8078044cabcb448a03c9e2185dcada02f9c1eda8738cf0299f9c1db47f98197ba6c14cbce275a40356dffc8d5726efe9fc20ec2aaf481eb2515530ff4c76fbaf5bb395de5e8c2167a566c906c1260fb0a9dfbd8ef95882b6446474fe04ab573ae716110461c8b46ab8a35a5469ce7f7403107887d2b80a98705c065ed88a36fec5e2154d2a888880b342f911ae45b75db99250868263148f487a81c53b601f957ca9d4f89854827bc95dae670683e79da787afb3f91a10ef4399ed0331fa56430ed03c2c60fc67bf3b3f3196011e62addf2ff9427d06643aef90d0689e13be221e9a723949566b7d74c9da0129e16de6d34f79f8b75c7b59c1961228214d9a29e85cb29ecd9bc524928581cc475db277c134dbe2a5a6b95db593db23f9d4701e30ae680f7a6dde8750fe002af7b030d74cf04124b500806f26ce0bf962551318b2aebfe1cd0d6b4a30942754a6101bfc47a58315f079dd48e5e1a2780042365717e933b95ebb7fff5e582a516861f005b3dd55a70df19e3df9c004c4cab0e9752352591bce830067dea94fff261e3f0189d0d66103cdd80e24f419a15b2240e6795f25bbbc57b0f68733556b586e433bdd4894b4a1fe238aa01627fa064f53c8fc4af4b2e5cf6bc9ac12b69f914cca65294b7071d0730529b81143793be3922c091295264f10b2814391ddd22ec26802cae596e1e729659b54b95c444c71adeb85131cf9a3919aadf36d8aa55802082d47749ceb53011bc0e807b967cf9a1a4e78112d8aeff6528f5b5da06c93a41e996f28b6fe68447466b6c0e7579f646e8b89f12cb194ed629381b4751b350a76653d28063a2141784ed2fd72799a6930503ccb2723ee12b7fcb1d4c14c78a160e6b0bc4b25f0264100da43d5414a6a6e105deb1aa666a4ad8dc190f018618143a9396566c723f1d76a180a29221470a0d890cbd2c2aa9234053fb88a40a77bee82c4c6a7706aeb4050f9b692043a8cf01bbb8d9eafaa805115557d7b13f8113b70f83b7918d2e1915900c5e6d61cfb4fb4ac3cffe7b9a336ab3c7ca22816bd2fd74afaf8586d9ee0890f8c1ae9bf1eccfa7ca9377293a1a738a92dc13772a4770c5f4a404ea9ea3fd09f1155cd858b76b0ceb0fb688b9b6c861bc20e7377e9752c1aebb5ec090a2e2bfef2d02ac58b75cfff436d73b6bd108dd0e2b2f718145370bc51541f980032c23ec39a44164cbd3ab41863dc44b4145ba7105e1030d85d650768f348c3dea3f66a78c6878c7446ce8184d9d0483f4b01ae4bf71089c7a5b7ce73be6c2bc05c62ad43710d1d17ccf46f0ffd0e68162d96fd5c9283ff2db8009295ce308b91d751b844b2a339f82cf893df86e338a572d1f86287adeaa764527eaa571905685961522fce4558805886e816bf3ef25412db1a309395a5268d49ccf24a4ef53221f7ca3e6cd0652116d55e51ef2135b2461a6efa70e84528450f08bab96d103b8c67182f489f765c806bc04234e04bbad163e80d42e0f1e5fc548cc58f5a109a97a744a145839e1db1cc6b5832b7048006d6142be208e623983d9aa28f83a566010c80f8b390bfe862a1e7ac520ef1c0387a8fa54d093b325dbfb15deeb0bd9ab4821bc009a674996815c1ab1f3a257f6ec79878001dec21627cb15da58b3606a7b239ce9070778a7b48269cbaf54b9ad87c7e809e6a686905e3d758947f79d1e3297ec836833ff9bd374bfc6629b0cc01b8c472bc0da8dc65ac06dcc7ba2f9c6bb7e6934c2704917e4fd211cda28b02c8bb70d2d5ecdeee422e1cbe18230f21758a4f3b3a430011896e9a57ed70adccb2be71742a7b04c68a6c5bee506bed12d99a478de0631aece731524d718749c35e8cab17130101dabafe7fe36b7e086f62a7f221cfa3bf68e4774cc9cd3a82f6e6b2eedd6027afc1c6915404eaaf714adf44239710ec36cc9ee25944ea0c112f1e73314c147d3b4253d477bff59a479103faac005e90a7b26dafd31064995ab3188ddfc65a407bb749164fff69a1fbc0aef4450d23970d40240abf40ec28cefbe81d0ce307399c699f847772f0f3cba9350dc84b0355cafefc111085058e299026835914830bc90685cdb7a8e8e540cb41171497fed3e40122f42e39ccd648df29d364870e5b1d41a81405fa320541a5d5a0ba0129ad3703c11bb20bcfc96c6cb17a855f2cfe46d5cd973c595140e48f1b64bda1820eb926736a75973ca7efe06e831f352ae8b56fa36b2d9e1fd23af5b0e0b5c1e6ae2270c6f050247b9fc1959513672b63b304ee92ca593c6a42613fd5ba328b6d50d7edba0704078d58c0ad23ea54870b7e72f26eabaa30eebf47de1564d99fba498b7a9673d995e5c172a033b76607642303828979796bc62569794aff5c2fab13f75af1851c56a5c429914be54028b177a390b630449b82874fb6871347d1ecc91594b9657be2c442b481287dc62d647ab65d63e16189f3afb109a8554f0c687566a9ab0296cc29bdd110a22698286216f83c7daa0da1abdb0c59fa4ae86db59ee07f79eea50ab313d730d64a040305480b057d02f771de9f038f0c074b4f2606ffac0465c7dd5d552cf174d046c9d322e2b08e3732604950e4ae20571818659becd83dbe61285e8dd7e97235da2dd928a98742c8ce35d2120d6b55423b38bf53abfc97ea38a9d582cd3c80fc668b18854bfbf7e5c946d6d7ec9f5ef713ff6ea935a0d9ea69624b7d37366b91e792a6a3d625ce8324d363e1fb5eb3ba77032d5006f868577fc3b5306fed19a8eb4657f3afd4ca8559f1383e6ce906c337f21ab65a7fc888da5e87353da86efa1af17dd49c3923ebad5530650195b96256d57c5960c6aed813be257a80155087ddcea8889175b8a409e59ca23b7840cc217db78bccd87eac116252ac3fac899583e3a23b95be0d9b5b72f10ab600235789e618f3c8dec83078a9985bb00f69591c23ec37f09de453c339c3dab4531495968604e253dec7860f6e7da8745ac90b46e35125b9f667134074872f425bb56e6c2d290b307d010de63f7ec916f349dc30ea3a91e0d8c82c9af4676dee700d6c303f438e09227768ef44ccab2cf4cdabe26953a5ca39d27afeb39623cf0f062350d05461afd90a3162ac91dd9ff1ddf0c00bdc68949613410787042f3be4b5fb478b0e7063f35b1762f1e6022d99f10ea2a56b881bf5662de01651deeef1ba20e34018d7afd966c9c6be7d25aeb076833fc3a193034b11d5d409032246e4d0710b82d4a659a149adea8ee1636dbee4f73b0549ac541a2350838eabbb203ffed2ef6a47261d468f316ce2f564f054fd221a7c6cc86a2c680358e49d6871c22bf206c72a64ecb1fb181aa70379c189a56c3161877a82d0568650833de9b99849278c9d44a4d8fa858acd13341a581385aad96998493baa8d92c4d43fa1f3e715c10a1b2e90108388a3e0ebc29e17a743ec5cad59cbc90c7382aabd60aec96a02a4b98ea8a54f147e3f57eab57031d295d819d815f75657d4a697ff3dc34d43f5a4379d646ab9176f148a1ed5ab260bb267a7b400a87e2ccb535cb1aa8c7edefc2453f0c7bb856b3564dc290e14035b0ac6f654edf62444c0234c90557879c753bd9c8b611196e84e9e12c0cac99467c761fa6ecddb72d1285e68672e822b7e5350b48c4f2e210ba91dbce47c478b0e8698bbe1be6369095dd16cdb3b86d5ece224dd10d11983a45b8cdb678566bdf002390c5731eaaf738ab668138326b56062143100e83e276bc0e37f469338eef36f326a996633bdd740472012f1b3d331a0b90cd2c7a0a6a79aef27bf530dc943e02ad74795f51376967708b1ee7b9c904a550d8ea9f6f2f1d836483bbe16436ef77aaa6d8eb056f826776d176aa5550c04f4774dad1aa555876f8bbe0d49d4e4560093fb73369a9a2170bf95d0d9f2a65c27e55e9f5855cb562d61430078c5f557d6e8b1ca5a0194ea13d5884edf783c1b144f00f2cd1f30a130703871265adf43370f594d28e554d2837613d910c202b7259e0022a6f6e632c78a4b2be3a00b574cd444eeddd0316792380173ba12c64e77957982e84ff890b7374294c4ad946fefae4c92b5e4f525951c9886f7f37ef8ba023b31acb4602232198101bbd9a3ff3569987c4a76eca9d32df3d29d3bc28351582a8606b1e320a7c5a09291302691e5dd3c3df403563e98d49eb8893f672d65d27d74877b7e80f815c69297a3724ae99596c2ca899954616288c021c37eb2ffa11e5a8979bb03cc02e63dfeb77971af4bf12b503e5d80ec845ef433962c37ab60c77cdece229350cd8bc8527b1123f389d57b751a7b1bc1f6c4c0f0f948bf6cbe13fed8f93a084316063a5c12d8b624e9a9bf6c1495112a69c7a66924c94de569a60e84838ca30270bbebb3b8a250909d6be9d22d15ef77bb12067490aea8e20b09100cfef1247747fbfa28c08c9c852410fa58371cf3576812b1b881d9c1bddd596054d24a3619a5059026411e52acc5251a4d67e1ccb228bac1792bc0642f81b8bf42ac95b7c8f32bf2a0dc39a500001269e45be5b760a63796fdc1a5c4c6b0a5e0400753a455f941e6c8c9e88803f06767362cef57e6af18995edbedc218cfe0c702fc061731cdc1862c3d61ffd7e5312e99bc740bb578fcde31a2cca655262be50d29606eae22342ba740f42e6d719efc385e3c64daa23304123538002217854a4ebef5ece36b7708b2e8fd929240c81f73953bc9755fb36fe5c4bbf7547193a6e47f1fc34348daa70dc9a9be35128fdda8c2db782d86833fd7749e8ad419e3ba30f566442d43c7941c7f050d312a7fb437c8621f07668c6c223972385e476fd3624c7507ad270cbe12e72b48f8ca1cf3ec7b502912184fcc715d032bb877827b17bcc48f1453fa3d9d0cbad39bf92d0930d0909507ba3096b347912b7667d7d958c7e807e596188d080c0f268f530053cdb5e5515392fbe940c01369803557eedce8f3afd2495658081bdf2a910e3c7709d9eb78a469b50dc576d41b09f291e49554d2223addb52c740b5ecd7539670b589fbac0924bf6b63aaa93042fbfb9f54c51d33573c4ac6607715ef5fd8038745298971b82c25d27b77ce634bcd16d3e614d6ca71df928292374510e184d3e674a619114b1dde5d00ebd100f181757800841b92e07a241c1f0013e11b16802d6371853a4d02bf4fef1f879f09b44c1494660d891385b54e8f18c171650b6f1ec3d0d10ae0e18893535df316aea0e738a433a4c69494a8215b9b08685f40472e2907442de74a4216810b753f2144be9eba9cb51307973655691dee5834e74ebae656f428845d12eb1ad37aff269e06eac3cb71e62e9bdbee7281600379bf87b0423d45ac288402147ef9907f791199e90cd8a9941c3145c8970aaba887d2d59abc9d61319f6e9a2fc8a7a92d5e5fab95ef2526736361b62225223cce531d441745932d755928cdae188c8550cca706dc47d92dbefa5a5ece458a51ac9672275a99cd8b0a60e75fd51669ed555237c7e6192d178331bd41f83d3919be0a149d4b22d4673a542831c0c7093b5690e7cc178a006cce97ad4e8f784633f877dd2de9f230a7d92213c7be4aba259cac1fa145e649ec30035c72839674c3e7b55f7e77669264615da84b051ec01476eaf1f26f3c1c76f9dd092c84ab31273507c3b2085558b6f4ba46bf7d9cf1983a700414bc019f20fd3e97fefab64f559c60a78abe4a48c46ba48569b433380d1dacbec79f9907f80bab8544834e270f6b3f5d2d4bde2d5be6e3596d7a2d4965fbe4c61322b982ec6f00a5e57485170d02793770a874c82322b956159095d8781e9cb28de785c99075905a39b69dc516734e27ad276fb8adaa35543b8b3efda7293ba8c3c7b91a91c2c595a2abb2eca73fa05c9c57ff259284dddcd00d2d53938522e8e2808d6be3dd35181c61945e72628b9cd69c4aa3f971a162d58809d324a055c5b516c1c7f832b17295fdfed5635f22ed1f9e19292566030662bc370f6084931bf74c253e450f7c5f82c7c93a5ed71c6b6e000da86f7bbcb9a011d785aa35e99cbcd0d8b8878d24489a8a9b4c1ea6154f41d7da8cbd2840b6bf7ef6a7c9ce3ad3ac06ed46e51dcce42cdf8e7c95cb3fc11e380d97e7fbe611c32e2652a87126c1e4816a97a602be2e698cb38f0facda0d86ea0c358a257927684303195497586000830ed6d5a85cf18aa27469d0a50a8bdb8eab7a1edec7d2130d0c8d0315e1dff5ca1bc3c1db7801c53c1d44f4bee1509b2c37bd58e661fc43ca83d5215003dfa85263bda401fda9d9cd08d9d2b076de6d37e519bef57586729f064cfb99f80a19a5cd4d12cb7cbc9559f82e0ce1c7345e68be8865be43df7ff8a32e776cb46806793c1dad1a53201f92470e446c6cd0a4e7402ae854cbb23c8e659268212429bd7b8584140cef6db939c0c00d71bd8fc7e9f52e14b152b55112823feea005427102c6ced5f812007e0cc1d00d3a100ca05dac1c6330b04a0f28b55623db7c89bc274ce58ed75b4bbf77af47501f21888b4c88757804cc82019cd5a3d463a4d70fcf15244941890797e1e9d14cc0216e4d2335b40fccc9656ab2ebe2545ea3312b032e4f109f9bffd51c946ed36a9e3288cf127b66993be5623eedde9f037405a8f60849266bff8446dba9cb159571b87809c9463b89c3d36b9ddeaae4766019b26d6c0b56061582f95d83408b550450fe9188dd984a65d4c83402f575bb26f9aaa12089c0f962d88d14245b441a3297d66b472ea8d007e3fc288e5be680482e5d64192945985afcb97abe97c02c6801d11e94080aec8c5b02f8305df5ffe3cd63184068adc1166c8d1a9a097ca7143a52336c20630c1da5842c0fdb820d9bd907e162513fcb6d242a6f86242aa5468910e30a37c49ddc534eb53aa43979c7b13af9abdd71ce16f964417c2802ff8deb7ecaa8b1bb7823a9e03dc9536a5ad7ce466989b352ee34c03d50c78919d8d331238301f8f49c0ac4f6b2bdbb36cdcd33b2ec48fbf6a8182fd2dadb28a0d97c8c3e069d932a000ff13aafda7f672826d56a83c360da8d862640033fde81b3e1d90dfb41807a1ff754a3881803c7a99011045133e2c4c64c6d75a973e5812a3772aa9d122a23ef79f74a69d1c95c9d5ffb0b59e3dc50a1cfc5f57cf3055b96c8f4f90ea40a19692ad2a745efa90a53a112fcc32ca55f2ca91dce2d1952134b533e693207cd4f1615395bac52982a4289873ec548d64f41d07963b4c8e0e1c588c813eb8e78e08dae3156f8ddc30d59915a5bd3a0ca3bfec6f62573564c4734194c67a4c2bc38546fe7db1917c4ca821a85d61b1d9bf098bf59989cac9d5c529b4fb0ae16fc89162e3a495eb74723e13ea34f0c415b7834ca2227d31ecc460aeebc0fd0f15aef198fc04a667b76d74ba2d7bd9c72b847840c7535aca20b6af5ee62e7dd54eb76f6ee6dc560971fc5f55846f11f85ecb71afdc14f65fe4635e0e6cc125cc6a279b35f80d7f6f28c79bbf1d50034b643a7619b7c013d1499ea05f8c050eb57db2d6d2b5028e3ca1ccc0c83b3f4abca58765274f6e7088969586c56f037071d23805250a794afd6c433078bc02c3ef0de9a77c65aed82d9a6186ccc2197944cc6be19f4f09c9f907d7a3b65772039fcd97949093832b5537f98d21f0a3bd598e1ca4686fce62923fae8a7b19caa7e0a77418e552462f06b0d78f1c778d47dcd67094bf4f1a5cd121a63a658eeae783d9c0e3ac870168681c7d213fc6783f979bb4a60659a964c874b759608005cfcaadab6cf7c3b4065e57c77e23caf1da1f0f31adfa12665099b14e576f4b8ac15ce94497db96e416c1e8de1746b689072ed3420d07dbd22df8f2454ed6f42c7ea04c094f609e2de9fbcbd3279633936f2e45ea666f7daa63c86532ca4996bfca8bed4dd3cc915b95b44f4b04490a817e2c72bc109e685dd200ee0f4dfadbcf20c9d323157e536919f3a0bf381da0a3d289f446164509c9cb1e3d4c5310baf9714973b5f0e822852f6c890ea077ef5c8659ba3ae540fbe7e068f440a0ed512531346e30a6236a49e1f29ba4afe265a5be4485920d63294f8ac9b1722131720676aa284f9589ed68709311e8a2ab7ae5890d04f6e927978646fa3d3640bc22207032b9357841a0599022d821828dc616d41551805118053fd2b184ae7e357575d3460fa04cf9aaf6b4d913465f92db14823d0eec3edb190bcffc2802069d08141a284816797e75af65b6a4b2547f720c7898ec9195c66faeb8d7e0c53c5ece7f24aebdf1f0f464302a55af8b0711ebf0af4dac801d0760a381706f1e03943fb2c43f0b67fd81278011a304adf607f54aa628e310f516d8d9273f77f3ace4c4ce811fc3a01953510ef605ccc599bcfa8181af52d73a4c3daf39d2d79b7a57eca27896871054e868def16f7f24634e01ada2ed9c8fa4a23478fa46907977476d08edc0f27509f02cfdf681c6f2b661a1ce3e7c31872e0131db416b8b1ecf111192e5498336c9c833fa5503528c935f95e3ce5cab34b8f0f0fadba8134880c9e82fab0ae829fc4c6768255b4f0035ad216935c305232520729af2d9cb2c8182327039c4df0ca5daa311c847114c2911a6aec97e5a623338e5e8540848964a342c56000d526220a8190425000fb1df5d0fd45d6db1a58ba0e90716cac7daf4ebf0af803d60461db265beebd654a4906c308e308fb0822156b7a53a7809071e34f8464cd2a8acc3ce95962cf8877e606cac6cf994ad9d894e5bf8927ae7311ed4b0d33ef33248b870d0e538a79d8cccfa96a989ffc67be97e810cc548d1992c55f5cff2641133325f30d8b89e23a508d0f7972bbcbcc17f3e43f4635038d0acc93ffcc27cee4c30fc14f8270fd6f8cec339a46c7325133e31ce958c71d6369ec310a6961dce9f2c888c4c3e01aff70743026ca5f343a15d3ad98a563314f8ce3415c939ae2fa7371c5e421981e6596de0491b9526208e33814aef1f71ee6a98af8841035a19aeb304b1c66e97fc46bb5d664fa2fcbb651a9aecc0fd6f68b84834981168a63667ae699bb3be9d2df5deef38cbbde33515ed21ca0594b7cde54d13fc5173d11f145a4122694842ff6e8c5174925a21f9134e0bcb1eb0ee4b0eb4efab84f90952ba6ca71e05a72d77ffa6de8769d5ec675e31a77dd5fd77de6ea7b7f97493155fd649e7c982ad6324ffe345a15554c295040a12cc7d1860d12c97dfa7afe5698c633dcf51779b0de7fbe02ca2bf9a52896bf71d23aa23c5f8347d08e524a29a58ce35b4729a5948273555eeaf4f98a2b268a3e8f30977beee8b4525ae335022c435cb6489745daf33acff33ccf871499d77b76594a820ca02f6c41230822838712cf756f85c0ba3cb7edfabb7cd7fc3467b556cb553324d3dc962e8b5bdd45add61291b0decce9d6cce798a65828b21f93f3e46a5db3e1859d393324cd4e0d36c7f4b37e5d9ba981b5f153d48932d357666cd8bad6a5f8b2de8b1f56113dafa691652d57d56a6db74a1b9fe9b2b972990b9d331369fa97dc4e40e9db5b73d564aaba09e84d260e06aa0e738501d3ed69d58cffcc387d0591ec2b5dd6baf437bd8daf85a6b7f133dd9a2877f9d36ab60676bc2ca6717b61edcbe24e048fbf2f641ea25137992a9679b7e64af4de372ae689a9985d93b9aabb98e168e455acd8d2aa9ef9c9e78a04db5cf1e8ce82eb14e83d8651d8be35ee3a8e9965f54cc6b84ef1f57e9f33917fd354e1569844cd5bfece3157f5953ef93b96eb1d13914d138565f10d1a2caba9b4fc3b51278462aff83b28fa9ed229999f287f364d94bff8637d14bead81dd71591d76c8ee02f335623e48db9f220b23cdef70af9566581b23d3c6ae31f2901d79cbc85946d238bb2c91ecc38c4c9362a6ba8b5906cd545f2991ac29bb2191ac1b9bf285649535990b9d334376098a6575abd52971e7e52a1ef3d48f825d3fe1b6006efbc700c1ba90372524eac8c64c54977862da06d0cba3d168b72cb8dbf7de0d77a3429b287f5b8697bb7971fd3f29e6f7647e3478399eb99a5f15d7ffcbc2e5595f17d7591f14ac4fcaf7f970fd6bc23b50cd8ea155a6209164d92ad5738f6495d599095f41bafc795eaec66bc4de09b488d9ac3b75f717524821851a5c2d36aa0389e752a740764b9734475a1cb37886bbb4b14c147d5d203b64db0e59be403c9bab112efd4b9f8598899965ca44d11f2c93952cbd2c9378cc80c92810da5f7fd69dbabbdbd8ccdc19047483cb7aaf26f0682c526159dd08442a6cc7d3a533f15a1e4f0c9065793c1e0f8e56752f98cbdcee055786be2c8f67041e8f47c344b905f88a39cb32793cf74d2ee8a07469badde3e813d9c1aef35cd5048241e0053501841a40d73fc7b7064d947f6ea2fc431e6a957f3d5dfabb8b097bdb322ce55c58c30acbb9ebcffa9cb8fe9f0fadb92aafffe7f349f99e5cff8648e37aad22d2d47d2d1b58be4998184226095f24dffb8744e357c70fcaf7038e9f6bfc5aa3cf88effc9cb8c1360fe74a3f96f5b538373b92644d2b7cc544f5d76a2d7f5fab06d047464908f72702be934a94885a897fcfee4463a7a8f79784e86eb06badf4bf71e670a5cf62999256c284f74a9c9fc5f7c821fdf55b647287890dfe2069437f25c5d96529876eff01f3e77d9ff77d1fd903f5843a57e7ea442fca433877d48eeb47f391342eb8d7774f4297e4f07bcdc1ba501ffc21f541320913de27a15f499acf2387809fc4c1b1569f826d94692cc435a6d59866b256ea649b0bacd43085106bd1a265562d25e58e320af841f1e552fa947d0721659cee6efeda22b0cecb1dcb80b093693468e4debdbaec5eb7dfdf858898a6eb35a036868090b8414a0de1dcd14cb265d0b800bef834dfbbbce86986b8bce85deadf50735c5e44d2f0933e7208f8e2832493d64d8ecbdf50734091a461fb44464f1abd1d914a46ff42e6b0ecc89661bbcba236a20b3487524a6f3afadfd84c268abe37b60d1345df6534c03412ce2c2efdc19a5b707129a594465da2d7fd18a75b8cf35dfbf90f968686e98b5e0933b9428bdad53e64d7eab2bb491fc5c9839d44444fe92b015f347388d057e24fc9cf139aa8efe9d8b9fcf4bda8963c60c191a6fb91a63e4d07824f534906d0179134f519e00f9234959c39251fecbcfd895e9dab811aa8639d9ab332c4e8baaedbe1a3794e3edaf5caf008703d1b156559efa9e77d0ff10476bd6711e07a0d047694c94479ecbd2dc3d2eb799ee7950152ef1b68a2bc1fedc0f34c3f352e7a5ecd5cf5f5dee42a1af0fd97e478a0e8e9832039247c27938c3efc24a2f7e16814c73446a06804862370ac371c8dc0b1e270437104ba782ed525caf4530ed863c1179134df8b9ee62387d01fe21f86230c7ef25e34967cb020595fa04ca80d130543912ebd9e791f8ddeba571d52a4f3b1d56403cbdf394921a896d6a673753ef576b57bd1269dad36a61482dc7479336a266d831023385bbb2c79c07a5d0b42e61eac87bfe379b0de83de0efe8d68a74438dcf9dd02effc5034a29daa38dcf9b527059f0bab46f5ae4df77d0f315144f0a9fbae97e8236ef7ac9bbba5cbee3dd765d9599ccd714e076699a8aee6d262eb0f314120d7ed5c7325deee3fb2814661d8fe7675aaa3f96ed70dc444755f47d29de247aed0b79d4cd49521c28ac89daff9e3ebdf3dcf0c28cffde89d2b9678f37de8e3f710e8d4e8fdf4fdfc1e72e3aa7e2205888a2bde50060496e54322d19689fa587659b363af89a23dea2753d550ccd3f71f0bbcfd1a69b1a4cba217021198ab7abfa7a3d562f9ca30ead75c89f7bb4c766ca2be1f91f1f5ab53ac6983758aa5badf7fdf53bc1f8f2cb2336daab96a1ad18f7e49fda487e8264dc31996e48429a524128944f221b9483eec506e5aac53caeece41909a30b53b23f6ef8fccf03dc3ca978d7df01b85f889eaec80640de0275992037e3f733eb2062541dc471adf01c959c9231f69c45a7bbbddf8e6d1e0eceeeeeeceeeeeee547c98ac250b0f7b889767f51329dda469e03370c05e80dcd331f8b7d059282f3f2e4e98c91c2259a5bdd24d2c9dbfc72f4ae2e9b47c34d429a42f7057482c54631acdb9935cac8a0f0571ac69a83c3d44fbd04d582827cb0d2961592897cb0129fdddbac99ff26b488adb67032d063f24bb9cb0f5bf37d2a9282597ab4ab5da6ffc1d1470119306734577cc959bb6b057700bb8044c5c17552553e9655e09ccc7bc92d2cb7cf74068b49d9db96a1ec24573b14b49ccc3bc12992fbd48d33f24e6617e88cc977e8a344dba10f3304f24864cc2c410982ffdf413111932889ffc4b64121e52b61cc1930343da99c34478d3a9907416e2faf398380cc4acf12f3dabc2f0ef9019d9354e3fc18c31949702fd61197e871fc6508a469b282cdf07d2a5cfeb3b37a4a3d67143236f328907e87f791e29d0ffc2d77ee82fa36561f4a327d118c0e5f959707926774c14e997dc2992e2b3e82591ac18ca6b97dcf07b9c97c579bb3e226797dc3357340cf9875d36ecb2b1a1d73d08f7d84a965ef7d22e4ebeb00161118bc5b674e9b906c3766731c5262ae6a21db2ddc58260bdff98f68deed3a5ab4bfadebc8d1bd55060594c4b51afd7854c327af12369c049537fe6b0805cffc2ffc8f2fb5ec559d038468b895fc8359269a52ad67ba60dd1844092a9d86aaa60571e5600a3f5a8b55617d202969b20a09e4bf2c0d21874ae53a45332f023a9570624f6721450cc1af71f21390264bd58ecc671376d6f9659086bd238c68492fa217d17ec12e0ce20217a2e8bac24fcfab43e91f02b1122a207c9242169f293bfd4c0894c889f7282dc8861060521a9586621852efd19098e981b7a6f8c40c5b266102147baf480f5489bd2092cbf80be76c84c2f7398cd9562aa984a9ffcab5411944517d7a9f833a75d5ec9e85f5cfec545f47d90eebeb3327ab1560bebdae758da6d0e833914351b6451ab8276a5f83c16a3035b49b6714dfc80fdface8912a1d80e6ac154317b21de84bc6573c5b75be6e2a44fe729e4da9ce18d906cefee3875425dd40776a98f88dcb129dfe6e90becf08583b933c8892fc8b094b28b5d2f34ffd88985f949e5d75c89ae3314ec044bb948baac24979eb09fd7793f2f9711164997ee22bb4eae99e39bd21f87a32c0bea9822e0914e31d7441ff2500bf9b9e99eb088ab4824924b5d640153c55dd466ad8808c57afd66710d86d11947fce433876b6c9a62a15cfffe7166d2cb888bb88af46eeb92d459124f3b56b6d56771fd232fe3113fc562a4dbaedad127ff1e3220b1b9e29a0b5d8546f44bae8864f1152580a9304f05668abb98e54cf19559facb98b9c613c71357c455ccc3368e31c73a555dc81c6ff1a13eb98a6dfee3a4069226cbb59105e2e5231a6dc7c789cfcdc7ba5c5d52ebf2f1f171756a861fa48fb891195c554d6f2a9f613b47e68ae6d2476212816da4734cd4746969f3652559a6ff4826ad93f5e6ed80a5a765d225b511e5650b6b5bb6655b3c5dd2795996e7d2b73cb6d5a9793f48c3e0aafaf48bb8ea33427d824c14e520f4c6a50f81227ef2294b96c965bd1a09dc764dd4568fbb3bb373c794d93f080876cdb8e2f38614fee9eeeeeeeeae3ea23ec08b772db77c9ccc70657ab094ac2fea83cff5916c5ee19af816c7b61c51843257dc03938e3253b4a9986dc56c31666a8c99aaa1488924e64ad4f13f3784f0bd83c6d25804310e12aef1efa1f6418771afd4e6020313e5df4ddcaadcda4fdcdb4d883642f6e262bf44829189a9619ab1f1568b6874f9707cf93a921e1c4bff8d31ef8d324f47d377e3ccb38c6f73c5e3fa336eae62b6dc78ff9b1b6b61905892c5e3da8779960843b26c58d5d23c8f3ac610c61c9f129f45b6c164923573b217172b2b91605c26a60616c6f19fcce230ae69c6c68b5c7315fbe418d9879dd08cecba31f20f141ba6991a32313025927d198f7489c49398285742871e98dc70fd7b07f324c48fa97d008e2dc62cc798564c2a66d9613496c6629e90304e0761608adb576a5c8460769459faeb184318bb8929c434e28a4ff0ed757bf1ed4504df82f0213911b2edf687a1949cee594b3c8ecdd5cc5cd15ac564b114b73f6cb1ab5d7edfe73ae08460f2b9d3b8738cabf4cbed6715f3c04141f0dce6da6dce72dba7b78b47b2de48975dd637c9f4609d04b24909e70e29fcc3cccccccc2deee1ae0ba202edf20be9d4cbe53f92a4551c848f93d9e5671b5cd6bc85b22027635cd6dc12d4c4e7b2e695cbdf351d09f113bf35d937b1cf38839ff8bf717ee312d397976f82c8f4609bac53c6afae3d2342afd56a31a06707f29803f91453e854ba641ce3d881ba8c395017b85a6daec49ad552ab716e94c58e7e76d9bd1021340700594b2e48b6e0fde1d7d92ec1a7a2ce101239e4c64ffecea3312c8b6bf54aa76a05c19f39e087f3e549fff24448ff422a616288fd975732fd442289bc3ce949a4124b563f89fe45f4568bf5cbe21a3b195d844413ad231b63c2f12e1b3568850e3e20ed99e8c16f17ee769b4d54e93f5d5631558d8379f2ef5bf3ecd6aa22429dea7f93151b74fdabcce027ffae0c56b16bae48b8e15d796f0a8145825d39b0ab03ecfac1f5ef3024594bd8efab8d373dabcefc4f54db204db5ce9064106f560ce3ed17c97eb98cfdd3566c7d9a2b5c3776638b2dc1dcc249e054e6eae5597ec5756f81a3e0fafb0f53c535770fb49669e3dfb8b91abd7b08ae3b12d7fd03e3b4deb73ea53d13fbd602cb37aed51892656172ae6a979f62ae9ccb555995c95bece5767b66fbe62e3f5d0cc976914ef66d849bdbe5be753bd64f5e848511f8d4ef3ca69cc5d9c0c485c522370053ca96e012814b587e9f281e13b5c24449a0e403d32519cedd0a8d67333d9bcd3c63992b1ca6eb303dca4c85603a15d3ad980e8687c138232ca6cae4a720c601c2354d4c87c23843b8c6df74c5c4456a8a5be589159189f2ef61aa7e84a8d55a93e9bf2c27eeba886c5f4830a59899175f34ba7c1d5ffe1bed7b63e9bb11e619a8677335c25cb95cff1632bdbf988435f9077547e665c8249cd3fdfc9b1e2e700e730b0896556a71cb1e36a4195c254396a4908a3aa4916f976658d6dc62334bff202ac494c6e9a7156c6e059284dd0ecced172c0ec896db7f23ab89ba0a1cb91e02745cefabb729dc29fdd43558180f66ecd1276a33f6e8fc4b2338b2a6956701b91d597679c54fe9b9979452276d8b326821a1379964617673095111266b5df5ff5dfe0e8fc5265b76d9e57fa9533fa66d1d77f4a9bb89c6e3c06689d0b37958bc9b67f36cd7bb756af21613a783c235fcfc3b2c6461dc41611cde82b9b8fc24b66cf260260f66f260260fc6ccece1b4082dc097bf5d8599909dd96c36eb9f968e57c30a2b6467ae7c7631bd9838e86498dffd8f8f9f7a6ced94b3d91c67edee16e2a7c67540e1dc31629f2edde7bacb7d769838315cd3299a15fac23ccd01e67c989275f9c9dd5df5f54c147f0ce3f80eb3867b6075b7d8f542b2aae94b8fb4b9945f8608eba4f5170cd3198d8ba1b6d57ace9169330f58aec9bc14fc303b3b3b7b0b463a12866e34d219e9729eda080c10b0c10001233da71018ba879425d75ae74df67db69b3730cb1a7d0ec73c6dd366c4080b862e7bda6030b253040c31c21105b676d9fc252d6cfb444138774c667ea6f133cbba6426f9a18421cc193067c09cd14f290efab2841996554550ba6c2a5d760ca8cb16055996084814eb14d0287a894a39b0f359a2978b044cc3035b7e290576b6371156c42a5de7753e0bd2de3a3809c2088e00c2944991f367d94f995be6259c0630520f8648e0440c8060693190a2f67dd43bafa333da7a05019d60cbe7b4d65a6bede87bb5abb73baf73197fb787d113ceb98427c8b4a9dca22c772699875bdeb7d75e7b1eb7bae461cadc6ae6619e1e5cf57e083db4433c43b61bf2401aa3321a446355680c77635a454663cd4404267621af794f3ff82cf099741a387aad1f7c0a80cfa0d73a5534364ffee087a2d16b4deb52a84b775abfd3da5b5dbad3689d6251d8754a6114b6438b653d0ee20d5dcc613e8586327f0ad429965ba1303a85ad748ac668b82dd6df5bde6a894c6cf79ec8c2e419e2dca4311aa3311aa331b761e23018b3c63f34828df8c09481276aae1acb4489c82037b3d70d8c6d3405966e9f3d46dfe8a74f504624f41df1c0facf0b86ed5a2f3e61bbef810d4b0b85b6e53c13e52372928dcbb19c0658973d0897e8601d50c3b0d8aedab0d9f047ef4063962e592d45cb7ec8b2f8369bcd46685816260bfc23b230a1b8a6e81b0683916042bc8a48d6b764ad9bf0c1256cc42a4ca205b500eb180ca89d682abc45d64233e9d2bfa343f7d52e86b95a5dfaa4350f0b591a066b29deb02cb021ce3251ed392dcc555fef1618c7b11830b620d17ed0dd3d7705c15a2b188eda48f84ac0b082fdd54f21f84ac22712823f7a22e08f461f86a37e96a99bf454509bdd5ef5befa8940af63dbc5209c3b58353e976cd2299689eab85d7f1db7b93a5d7f1db8b9a2402c9997daf5eeb502298ae53b4530916d8ba55a5896c964aaf11943cbe4617155cc296c5485266cf7d4394897330f62978dabbe770ea242f3cb63342c03312c16abd69a4cff6569138b31942efd77d8491a269ff97b3089e82be91f8b3114f3e4afa4fef73d914facff8948eb279f7d023b619f2e7dc75534ec4c1211fd68144e52059b209d9a3eb6a333a8661441d2468ac0e08007cc553fdd61637096dff2d01380c113736710d01964501c42e68a04d2a53fa453ddd7ffe8f7f5a3f4a64b1fcb3e03fb8273e21fdad8f4149b8bf05782821992cc152d01139c04103b8ce003e994bbcaf46daa619241f448ea750941ab8179f267720625315fe395c8bce9f987c47c8d1f22f3a69f220d932ec47c8d2712f335923031a4c6cfbc69a646932c0b2cb9a50f9f555e9887f990f668f46177256b6148249817981238228df685e6323265614d2c575427cc1b2013e52f3306b1f95ea4ae3790794d276191cbf55cd6bcb2a3bd1aa6aa1b639e727355ced5cbf5f768f03a30579eabebb24c56b7a547ab5ae8d35c75a43f0afe26ff4e95a0f7188d28cc9c3a362993b9c1e64c385ee6d5d520e373299ddd6d7671eb7073652fa5ed850fbe887aa3903a8a46ea4247bb1bed1d843ddc6fbe6f19d8fb4e257a242d1a63680a4c947f374e60d6dc6cdfd9fd4d0a2d2434f24a444f6b14117f3716195fe8932b197d387a713412a7c80860b2a2c076ff455e982bf0fd1b30530298a57f0aa3e8236dca1bee82b0f0bc04a10587fb737fd82a4c947f9886fdbe5bc85c8d606dd83a26e534a13e383269dde454f2869aa3ba5e9ec032e17aa40a5f6f614a229c8c23328e78e7bb6721059b20d046bc54f7be036bf258ad0c9ee75126349947798e98d27677c701e7eeee4e9b3b6f6e17af92ac8780110747939f2810172d1c33b33b3b7577671b765248902e4599654d59d008a85cc7c57e9899ddd93f77070224c8891d2ecb644607dcbb47bbd75aabbb7b3bcfb294ddf08df5a16f3d6416f1221db9d38d45baafd5da223b436893b9a35da46d6c96655364c8ec8599373501edc00c7c235afdbb59e3d400ded547526f3751de062a5849da71e0d2ef56a05d03a176de836820c0d348039ca568814bbf76487978fcc159334272313074e97ba20164001f49bde044f98b5818b8a24ec5405f50f4415a4456c02f48d689cac0fcee89af26a58dbb751903d4e1ba9b8dc1713d1c7d93ac49938105995b014e237c7921bd9c0ee86131516ea7b02c0f8bebcff2681ecd3d2c3c1e652ee802cbea6ee0cbdc297edd10ddad1bc23dd1bb8c32f0f562314c3a63ba741c345706084b4e6b6d9d0fada056b7bac7a75bdd6a9f4ecd701ccbc0811d3dab5bb732bad56ab5bad5fa7c44397093de2ce548975d77ddcdee481fe9ba27ed724224d9a856abe1b6e470b84985f84aab7e60589eb83a289c90d22e53d9ae2b1d6b2a3da561ed92220667d956ebb254c5962e7342b82d70381c0e4784895549b2135427dd50e385bb552ad588eae47be28be2e3e29bc1e7830f8d2a44fd4035412dc1e7aa51ea941a84ff97c6b7e5b3c127547b2a0e5f0fbe2c9f185f0caeffa7820ff659f99a28c3dd63aedfa8546a09aa09aa10f503d588eaa406f1a551a3d4291587daf3f9e043e39bc1c7c5d7836fcb67834fe88bc197e513e38be27be2737daf4f055f131fcccb79b98f0a2fe7e5bc1c11337027f9905c249f9b16da50b4145d45b91c93e6b1b11175bcb7a926fc00e22592cd66fb3cfa9acde8abfe8ce746b221f1d95e361bd799ab3a2667744e665dcf8c672897f3e1c3c70f20a2994c26bb52abfdf8f103c80920ecf5aa128b010102e48454e5168987c796fb6117bb4e38e18494ea23d188b994ca7ba1484d75d30dd9a1dda0405b10324361e543ac70b7320551a7fb14fe3d27b7ff4675e0e0883adde3a42000b6b9096de08c6bfa4ba46eec78e890cd551d9319e3d03372b76df446d1a0339a731d2974af1c2db2ce69e7947ae7b47ede480c459d531c3948364ab7a2348f9f4430985b8e1074f84b098ed1f1342693c90629c20ddced761bc791765e3f9bb73c3126c6c49818133b110a5148b422438a601241041176f098a9591a4d6607c9d2ce6d365b28ba72c55bb59a388ac5624242eda242a57e5e5f9645e19828bc128adc451cd54211f8d598508d7d3121af5d54aaeb6b1715191e23c850f7481075fc0400272690e8c7fb48286178e87c0f00ea5ef74999a866d88f28abd2a5e8c5e755da39105005f253b7bcd5b658cc5f0ef316e3f8136ff9147fe2556c4ec516034000ac8d00f478e98172419550420d16150808a8025512cc1a050bac80c16d9babfcf57ad9fc657b4d547f09a28ef725d41a137c90acbf68e7b6b6c5625cd36fdf5b9fd74f1ad9657d7cd847945589891daba4588528caaa78cb556290280a5911a37089b12a6c6c6c4cf021629edc0c39134c30c1c70fd0880d061a1f3e7cfc00526d1ec90aa940343f7efc0072c277c348d00039e184544aa5baf15b81a2dcae403731e63db3acc66ef35b93535314cb1fa4511075fc51a02b1cda39c9d6af02d9b8a6e7774586598639942e7d8a8d71fcc9aca9241095db3147c26b1b25fd55858e8fe6f33a642e34a1361004c391c8457c016970e488f91933ce79b247aa74f97263b11070501d4b9c4a970d04a4e31de63093c9648314e186fb78cb5b505e2ff04752041b15480a415668cc99388ff390229886729d1341041176f098b1d5bad6b52d381c8c8b5fec339f795a455f4c7c70e75f60e2502633244132572f6f679617786070e7bb3071280fd7f4db6c6e2b326467ae444332d9952197f9951ce201b854ca21ea903ed4318a509230e49ca8528944b2965cdb3252d4b1248dd231d185327111fbfd6514521e1791f2dc16916e1b729bdb865c76c5652ebb2244a3f11841860a50038dc02d228184fa8df8c34e3405464209d350fad52f1e3c441def4728551ca291ca28ad42d2d80d3168152a33d19818fde37291400209a5ad46169bb49a8ac6da898f0f000260bb47ec16f740b9f0500e5582b805d765ffac19c94c311af32cb79bd77d3bb3d67d0d6ae2b8adc75c7ddf72196d36ebbc978d712814afd7475baea2412e631c0a0515a22d6aa5e5322c369b8d8d8d093e444030182c482633c104137cfc002bfbc4b45a505e2f1f3e7cfc00528fdc8cd8f8f1e3079013be1a7304cc0690133c15829c90ea52b8b949a928101b1bd5bcf11e5d96fda26117b31275c05fd5236cadb57642402c0adbf128a020ea808fc20ac7c655323f77bcfcd420387168abca8c31229148445270a4325a85be5c4583688b71281434465fd40a7dd128688bc672882b6a2bc0d09c95ce29fe14754297ff4f64a1415138125d5e2ca904135363a6f37155e949394a24120d8e1c3c348efec9cea51c21d0d4a85163e6c71b3319cb64b59a0e1da20e7d1d6f63566deccd28271b8d723cca8d681d9d213a117b5e33981f4d30e3389222cc00c11806438ebcd7fc1a2f2fee6126a3f0c78c3bbf0213a77ffa56a4553d736171e72360e2b4ebc85cb9fc9cbfd3c25c819c73e2846b5bb6d08807e0cbfc34a28ed5318ea86880b6967cb1fff2a5915d2fead89717a3b0cfa87f4661ffdc7e771189ed1a853370c4b976c2b976b2a556db0223c20e991d319da25f27e24142c7fc20585f04d6eee331028c0822883adeef1895cc290b2e01bd7134d4a24e1d0d893c5878f0e031c29c2bd287ebd9ebf5cae57055c85e992db4aa6d7d9b314e7bf16deb2ced450fbd7acbed99f264674e00780140005c02d043ece14d363edc3cf567c654f5cbd1b8fdb5061d7eb85ddde6ddafb64d54bf8d1e3d449dee7b3c6ad4d566db5e2f20adea979f027039c735dd3de39ad7fdf733ccce7be55eafdc0addfdc8516ea2fa459ed1d0cc552293e61ae38cce9835fda213eb62cf088d89eae7da2857420925d4d8888cd860b0d5d4d4d89800eecc84d8d8d898e0a3ded8d8d830c104137cfcf8a298be9c0d1f3fbc1f403a2027d01352a3b6798b719b049b281e46b954d3fae56ef3cde846d4a97f23ea44694ad28e562fa752893af455220b3d51583990ab4a4f7ad387eb17d77c7796c027812008de1a4b979da54f2fc6692f664d7f6ff962a2ba6d968ab6e51057c8713f1f1e2c3fab6f72848083e6860d530e9739519452caa3802bd6da6aa24d9b3f6ba2d8237830128201891ac0cc216ef94069014c124fd460205e5c97bf5f0dbb72590dd4545cbaca7d795607f54c0928f7e55fde45d47949f9b82e2f8a3a2e7476c524aeb8e28f441d9135bae116374c82892028b51056f002b55cf0aba80356201778c19353ebe87e59dcefab1648d060a108918527c7f30670bb9f473ca1ea2d2c98018d871573eb932e9ed83067eabb5d4abb21ac8629bc251ee899c2678827b6c801085b60a1d5b480a5a4c4aeeb26195a7cf06304142018a28a50773b100401423ac2dae430dbdec1eda75d788395167387db7541467c71bb5711b713add81d2c84c2ed6ad7bdcd2d81e20a1a9a6431c60f4c8491d37dd92987c1eddea653dd03b95161a7aae036edaba2da6aaab4c64f1618283c323f3f68524a821653440d3d9094b0c114e1811e1b0557024193175aa5b8a4bc48364a1317265a16a8899884cf0b143b8c624c517c5cea14ad10099a58c40b442c7c711b1551d3018c02147ef1438df569caa6ccfa34afc854440f78f8a4e4402639784a541e6ce8a0d0be1f6e80021b020729b3570f0b64d8a634518227080425c861899935c1a2c82ecbfed721a8408b10b4681242931c408450023474d89e0812082df15a8490c65bc9b185871c523c151f031c58fc14386eaf448e30706002440e2e6c74d8d024cb657dab091affc47634b8c0926ed0b1c5ca08a1c30cfb32250421ac8d220426acd091021b7367500e34d021440e5a7484c0bad410021176e4430833b0b5881c3eb0a5246860454fc0ec480a2e2cbde26fb05e163b58172e72046161ee0cd2010c1d3fb6de19a443ae89a53cbf85a54c748cc0bab460967467504f10f781b0f6cea09e283e58f1cea09e2774dcece8cea09ea020ac7767500f4d8528b199254889313c6807105c7a679012627c4294b6a9cb57c1d4d4f4ff6fada983e0b0e110e64398b1d49130413f3e23985af303b4ebfddf9032a1b61e9fdbcf23dc7e864d15133188082fae6ac636837eb0dce69c19d444d4511b6858efbdc5efd2b7a906a5ffa8e46c173741ead08c00004010006315000028100a060482e17838d2d3c0d70714800f6ca644725618cb046a10c3384c1965083140000000000088ccccb601aa72704a7be73df01bcfa6356de84462478a11e119a7e9066a5caa7a5e3ee6eb4058900eb35831fe8fc1708a81bd2d302ec422cdb06495114692760254d93a7fabc0dbd7fd05277337c406f0e5935eb608bdbbd9ff6f635c7286539cd3ee5598fd284380df2309116a13cd93106991e2aade18b60e90c93c090fe2ea4a2dac1081b1ed0e897593c09c4d8458ea4a93ae8858075b6a5c22318b1b108be704c5fe125762914362a5fc19fddcc034910d28c5c6d9c79a78f076ed65abf9b10b34d6724122c7213767e180192309eb27f8ddb40680bcdd7c80933d91953c09f72f217484cd9b4be890af9527d8d9863929356d16ea045a1f9f3e6e0a481e3b9943573408b7c642215c78ee8e8816843abd00ce76f0683643cf339fa89bd8353bd6aa95aaf045a1a42b024f29eb2e55ee699867ce8aa7087c081be6c8c24d5866406d993cc4f974c3714a0f2a5b811204ef1c8112645fbfaf4f011791ae515254fac5472bf63b8410e9c09a06860ffd47812a376d3ab3c4c363086cd04f5871834affa7c5502c7586a614ca72b05584179268307cec07d5e742ec3bf81c85377f6d11f74a89b8f1763818b0e99430c4a8e0573a7a17ee2442319bcffa10ea049ae1946a016708fe78fa57366160da98a00e42f734c4c6b00a5b0711740b132adcc7d59b595e72045ce02c8572bb59674a14478369574a1155e8c8ea95a75774f44c76e5d4adba2ee3f486d7a6995961f73abe303a6225420bb119a3a2e1eaec84db3661646bc7df021285aab8d8fbb04978c9cd56f538a7862ce98cf8ebb900b0108055f3b6adfaeb85adbcdbf5bdabcfc87a2d518de55fbf8025a2af3e05a707868ddfa43b8f939e68f2e9f71ed930b16828961a5abcde44f736c4f33e85e34a86486c121db93306720431070ec8e2a51091d3f8698d9cc61e5f145509ef9e81d45b543aaec46e1cc512fb23b0b6df32209767bd9a82cedc74efb22b6e0601f9b059ac97fa28df0040edb05b9089c9c94368a48a06eb0c8b869873526fd58e182927f510ac32202a7b48e6f911902db39893b38659e41f16f7c3a8d4f076c15895dd4db32aa55c7ee35b7f28787d97acf7d34d36bd12701e2c577825b081b88fc53fde755294eb7f65f0ca1d11f5f2a8c44fc77b0f7c7af19475b637bdb219f4ce50e9f7466bbeb831a913185b28e426220c3a59ad4bd8d2beeec4c425a03c814595942c4a65732633d373094e3fd3b6646e1bde7d09cf3e858d7331b1488a124ea4be1ad6cd823f702d9314f5ec6e48f02d91c3cfd5c7385a82c880ba3ec4975101a0707c1787a1499eac4629f68fde0556fa5ed80a9cca1902bd5178ff8e0f89e59178a2568a27105d2c259b658a19e3b4dddff7c25df4b3518c9cbc145f744ee8bde8b6a4f86bb4c9f7cba8ea89f30aa2be4a142f157cb8dde2dd16da4e23ebab9a3c6926a0c7700696d0ab6fba901e617e653af689ac338e8a1bc6b80722b0d218087a5b4b8f2e541a06d91c1b356c0b30649b4562c645707bf1a5132d714259c2779b25d8fd22c8368bdd1dc4281a4f2e3644c5688a8fa5815a125716f12ddfa1cdd6b81fd5c36669dcca258e812738d08a6ea25bdfc8e42c5bd4beb3364b87b4412a5ebbe3e84f8cf0a053a70c29431f88a6958fd30f1a508b93b7be495fedd86fb3c8d7712ff35d280974a53618c8ce7880fc58ad247c6dffc8b1451d7e77993eacd15a8422a0b70747ece9a52276c667ff2c782a11c4336a1e3c7db6f5297371ba8dae77e1b19487e7da342f08742b20d52c0432602a752e8f9dad9988f83a73133bdc37d8d03f7805b3eed9d6d79d17f2d170e61e3324c4c8aa42f3b22fb1436b8ad535e2cb87479e2fc7ea39ab3ef4ae987b3691591bbaed06ec7b31a6d45f4aae0bfaa532f646c4abbc1be3d7724527fcc81b448f1d3eab3407015dfb15d06dc9b089f94a184176c7c9cc88ffce64e8113b7f834b99a52cb02fe40887359c1b4b472d367c6f78646b93a4c0b4faaa10d30946b48cb30852ac59e278c8e1fa5a88a6bc6f701925af2d0805f1182fb49faf9f74f010a6759620628733e1bd143d6f0cf94a2dc435f68e808f843d5313502a957e6f0fb544a0a5bda74cfda508352917132ddd3dd25fae90e21f0175ee167824072cdf453dd43df307c7820088e26700d568a88034dd3bd2978841a59404ba2bfeb76b09159d2cc5d5143f902244d0cd16d17083ef00b1e7deafc5cce7cf49b6c381033cf4814a79f8f548728017203c78f401f219ad18450852d0204bbc0481a07291745c726da4c26695df5516416003548a2980f8a9b3eb23e4750de15df96d8474c7eed05da1c58d066e2dc157e980b4d3717dc44764a0c70645b26b99db484a19c356cd56c9472ffd035ff3e893def732e9cc9f09b34e5f7d37216a17f959347a7891b79aebacde267f2f927eb318808bf2d5ee69a29782782272d0c0b3f0925e9f78bb119d9a62241445304cfb6ce2e8ba537be601001d105a10516b8824d53b7fe6351e3d30cec765de62e2a186bc3e4614a50f9037ad7604ecb94ad49bf95ee612d941f76b9128edd265e69ff40f3c092680dadcf4f6a9e6ea8bd1bda422c30d79e7cd5d516e11f6265851341cd33b0e3ba67c2f6c03622b745bfe1a394743d849fbd0ed63139df1ac02b160230814dcb2d57cacf5aa1e29c3d16013b25e28cec74c2d7829bf1652e20d1b9be6be28aa027b2af093e6eb3daa721ae19ea346cc325b32242696c2be6b6c9e632380cf9fe935ff358a58100a3be33e4d80e44d965f1bd0f0c3dcc3d1e0cebbec5f169e26bca753cb3a8c83ad0ebd2817b8a9debcf22e0327121437a70a80af910f3772c103796e5023f784802234581e5601576ef1fd8b80016b511478050a6947544953c6532b248a4e661cdededec4f54067f13e4e14496ed96978a514655743865ffa37617be256ddf6447bc3ab02d073a0d28f0f468514428aa9a761e669671c2d0a25cfb11f448344119f3a716a2f3ae863acbd68297c23aac0416f57291bea68895c7b66fcf8073d3047fef06cc58b6a62e88d91e6e9fe4d7e17f31359f20d366c7a066525412dcaf09b9968448aec0ebc367386077112eda944f509b16bb69a88611d5de0cb5ecb8fa06e2626ac1fdc5f1c51634c0b47c051fedc8a359371fefd8f5edd4b99628b033e63c16cd74b2e9c0e151b559e626d6b02d7125eb8453e7a4ca99c4838c98331abe0adb1c6d7dc3cd7d83997a0b0c6d1ea40abc3f0a670e7540f0b732e4071c3d20526b6938b83f21073110d8a9c985da628d5fe8203a7bddd2f25544904a0694b9855b004019d78d1cc61ef0977394850a6e98d84b199d67770b7c40bc028f781dc72f22242fb00ae655ccc192bfc4fa417681e09941b5a7a730d5b0a42c3dc83bb8d7439d6c85485082018355d61e6ce336ead30890a8cb5a8a5c62412a30db7eb8144c5ba2aadd3fd48bd5c2a07db1f6caf9cb91a846564a39e27c1887109bf050b92b367a92b1afdb04d589f9749c340666888a16731fe38fe2558d058ec54327e55928e8daffe40e07cb7239e7ea3619f8f39521905cd136151da11e000bebf88a0e0770a88632079d82cea422b1213eddac7b6efab0dd2c54934e2b16f085c60803633573bfd53a3c8d98e88cef89b539a9fc78cb946dd6acc3b5c7fa4153fd59ddcb9b8376180951e1fca00666557498e068c9e71677092c2938ef22821e0e569555dcb0bbf500de7f083f7a5f46a7af5a62c444b23744ed19386ef2b62899760688e3ea07be4312b523aec3e90242d7f442be2b208ca80c17a84a8b99e01d646276f0f1273deb634ba694e292153c77dfd9d7d4a3ee62d7d593e488de572119977782060d24e1b5f44400f23af008cc90cd9b465024baefe4401c74b1acf6d580216bd912c95b263cafd7aed579a13e5ae27e135432afc6b090108dbf5a68b7d4fa589b14968a5a18cae59d5ff42f646211f214a070a989d2c2a93f0051202aec5edb4d5c11a87d24cf0714d6a6b92e6c2b3e60286e494ee3f755a710291697cd2b51b5eb945b3fe6c2ca2907390fe67c9f4845c397f2f0dc429da0a2f12fe37817b581527f3b8b6d079d3ff98c89448ec595d93a43a1a8d6e52051891a3ad1796123251cfe51e5c884a4cc63dad95d7f31d80a2f891f0503b414341f6f02ae315e17418992afed80040b3826ee7bf3a41a54e95ca1abf4fa5a465c2664ec4d421ed1c9dad8419e4506cfb0fe351c1fe0e0574a52ab3956eed34185aab1af379a6f94c127a21a39f0e1dfe0067a9b2893f50e4d20726177df5c4d1d3feefc918ba273190e26ef73d28148f3a0d69c9538b79e8a64300be6835bb67bcb27f67fb396e7820e14c532faa46f515b50ca50d3ec26d82903106904d1d356af3f505ba9f360bfd09ab1c29619811921cb48294017c37ce72e756153402e20f35fe7707fc0be6960e812c19c2b819e66b8846ae9230ed90e4c02a762c2264f640b4be5a848e0ef9746bddc108bc4ed4dcfceab1c5230582c3efc98f97b625d49c31d028e1ad17c654d727df10c5e454c961fb1cd376c0757ea4bc37346d984ce2fa5094a7f1ffea4fc5a0748e0ddd21fe31bf23aa526b3a12e3071fc86de3e1d5ccf09ebbb8c559d8e7583f2b98ab7e2070ddc44b6516b68406673babded21b5163df4515d45852d6690611374e5a817491cf5df1389057cd82a134a34de18f1c609f657cc58b32778e5944ccded57b6c149371d1074c38de42dcedb3a83307862329daad345f9934110fc62b027b021af054a9dbab52ae8f526f9f6a6ea1515237416683b470f4b828d20eb75a73d1b33f4143b2f1ae458eea97de47418f9c2cfe366d8a214fbe43eb22bfde41e044b6854fe583e6f6efa76d2e3ba04dfb1aa9bf54c0364f0b8a89689232c9df4388c736bee0552d8d02b810e25b3a979f9b1ac4a1fa3952ff2f06191e0107d9ad0f7d258061690c3ff72aee53ed62be02322708ccd76b369bd6493aacc9e5b84c3195d8718a8b9b16d6645ac423982785d1c5ee94acd632321f4c7c9c1c1ad0eb3f27d2c16ac3a89100e28f3c353c740a655f25adca50271afba488873afe2ad0109d56b16297eef1e39765a56aeee9b53d28c6f6d3ffee594ea8ee300a5c61466e1029ad70d00b5ac90778838e42f215439d39f035079f2cd84bcedef4778aa1f1dda2daace70367564c463af545559e8046fa77486cceb2217df07e761435f3cacc5cc7bc99bfe8c6b92134a1fa88c09a1be6c92c07c2fe57a20fd7ab8142839d024612f1db5f9fbef46f01989649c3a15d3582d6bf8f4772e6120083e4cb5872c94d77ecee4f1be3b6cd77e0637c7864aedd20b2e6e203fb15c627c027cd7393e2f03072c5e0a93c5586e73299a2019d6652f3564e9eb343312c7ac2fcca460d0f8ddaa14c28d6593d19ed94f4e51d8ef6ca108a9f0775e6ff6518ef9dfa5e02e506e9b88c38278697b38ae02ef9bbd1d51fb4f9f59e3a3892c3f575ff6fc04ae44988e24f4ef4e377815713dad4fa8f897855a63c732bb32f6d525ced1f43ee04206e6b4985264b48ba6826fcd8812a836ccb2c38318be8c3a80e0f08b242a341c3d3bc30641d4ae042a491c919bf9aade8ccbca3e1a8bec4f0d3c495fd3302b2bab3ac1150d317e41e2a551dbd8dc8e824c6acf83a14fd90bf7b961375ef7346c06567369525e20d86dcb8ea1a259d086a5ebb50a46c3cc5a55299f5d8c10e8b5981773d976eba7feef35190e24e371bcbca94c9fbfd24dbc4f5f28ba1a4ed1068cf905bc543f907b39649d4c7c84acf64f8efc7b0b4ed776c4b3309b448e0c30c5830a07d8997127ca96687d8f1dd2bbaba9312fffd7183e9ff61cd2a059fc5bdf4cd08423cc7fb8c61f8395b84fdddaa82b2688e6cfcdf5b3118d9699d92ce66118db15828d1176eb63ea6ab3cab35652e1faa603e13a0d9c4617d7d37a87f3d66b351e76e734e3abc786a6a380cd0030d8e5c4c428a532ad44e3e78b7115289145e33f64ef77610fac3807bb2a89a16f7cbfc203e43eaf9d262c91526b7127fb81f57d862b4aef3b5dcf2b1ee7296cfb60fb5ed9fc2daf510a41c6324c301760479eda827f2e8140331f91758fb44d24741b3ebff3ee5265e8d4e85ace09b29b74f9cf4a40cb14ed60e1a729f886a92e79857957780a2d00d50bb984418413be3d711a527f230b1a4427c158076bbd1c7cbeff96d4c7d7911f4ccc192bf5bd9dd6b2cc5620f67866104edd63c7b221949ccca46ad929130645e06d5231b978a1917278829ab14781d04a2a94b131b623ed606b690aa2158316ab1480e744e6f34d1866246fb9884a4593ed0b37843e9a10f342748faf4c788361de7ec4822b53d60a77571567b439759d59bc8a97d2262638f2aa5e398d9d1548126442873f7fe3a43a4c733043d1a3e7d0345c04e1dabec300b2738847a998e82386f5e57b7a26965564e9ff0640c2fee4f31e125c2895a493de5ca4d2200846b00d5d127c40d00f379e7ff6302542daa803ab7dce132133833b300b9df186f05d5af10f9d9d70175879c14d1ac4b247a571fc62e2a208ea05dfe7037b187d56a0e660c047a69c3ea036c842a9ba0eb24a5433550769b8ae0808bf0a5354e01118ab54612d9cbb8050f6a4b5a84d53bcc06d147864497ed3582823a055a26ea6e58dda4590261590a20b77caa2b9d1e617d3f302a3749a642234e5288add5e94ad14f155e9e95c5a114def32a293205693ef0747260d7bc244538ae11ac2281c39225ef2e39f880d62bf5b965b5ac9294d428e6b15b34b1f888e72df463638dec7a11b5edf9762c95bcb780ce57e79d75040a08500ee96f3b3c4c31ac70ab19117e60e5a8c59d4c6b4704e420d26f2b6a83fca05c3fb91e0a6e3706fc46780421973198d6f9fe2b3e648aca499ad9de3926136289c3830ca0672a0923e0b6c8cd54c2ef125d48388c66faea2fd098dc287f89e14f33e945241c106a539a00ab22ec6266bd28852322b979e50f3d8b765d0fb0d460cbe8b1feb85477466b82f12ec251b733919bae22ec8af82566ae93a512e4d03ccc0aa7af77f24c14f9591d95ad66544b8138b3de9c2280a928bb8599de023fb377c9ac91089ab10cd4975e08389c00de5f1109f58567a8a63a75ab8802e4c157bf631f9859a532398ab5925d44c2813bbd193af9d051d5333810336766273a06d4dc2359a152c7201e6ed1560ca13178e7066a9144b446f7e91704d08d91aebffe12fd7ee02a5bee09ddda19c60b41ee2e4caec35b015b70d57c17808283515a80c02f5610ca10233f05527c812f86608abc5603351bb12f7bf4e8df47d2fce8957b97d9ac3586b2cec96b5457721df2206015c45aa700e5fa8a40b5a55ab488a0f538b55a4f6680b5aba0b92f3f1fc57e0903cdea88d1a4b72cd1f3f4612b11e0597a2b66c577d33464e246407746dfe606ac4ac8e834664ccaeb28ecc203b9b38b7ef8af1472cd5d1932d1843354b70a710a7a6f9c30a934275642982722561df2c392fc01a4f6887859609e4175f6daf58d05b9a86ae9353b5d8f6b7340f7c9dd3dea7a41420db2739405621c0eaa2c918191d6ba69632cc7f6cd770485d3b3619809af248b5e869fac7757d62e1970ed972d9d9f5fcce478c04b30ccbf2a1e337816694a01a9734b33c456852c5dfaaaa5161dc72cccb4e9b52604cf6d10669e888caeb51944dfb15d94f4b6dcccc95a9a68b1bc779a34ff2fb3e6138fac32bc35ddc6a06181dac9733465867f506427ae8b8442f88a2117181d4a2b5fa07cfbb18fa6569d6ab6c42b38dc79400dd23d01b6d19536d2fa62297666aa9fc15c1d9aa54db68b0d3ca0fbe8590b87cf684939ba02579cb6ee248991329fa1dc0017c631f2563ab38750535df86865b0575ae15ddeeea0bb3c4899485b6c49db5c369ea1fc6d9388d40fb564ff6f599777f4c097d33aae2f953abf979962cb4b9af8dce33d2ef4ee5f0e66a754f747a4d5130da69c3e85b6f421a56043fb7dd828393d7532f6b0c67d6611d962f2d12b490b3a0f01d0e5cda3e4e06b3babdd9aab19003c627f635bfb71080d919e24a198bf3dfc9bc03d33feab9e8efbc934306f1320bb26923d39e5320a23949c82816f1078481bf17b3973c8013f919c823018507fc0cca88cb08c7cee87a6af1ad0c884d6972b7fc2a014df3d120056165c0452c1ef76420fe7ea13581623221cce527e911deef5206e5de4e7268bbdb866b0995110a3a7eea2b8f9d0695db87ce09fad2b05360927bd53c53cf617dab87aea5898772d90b9ace349405a2c108774d699d38dcf4fc4179a16d4cb8358084f313afb5f5a62962fa8a7bfb188a87985119479dad34fb3c9381901bcd019cd7540f41269bae1840b99557f013c56e1a5906ccdb6127e215ccb07fc120080433961065ceaa84b04d93ce13154b1e9a8361fa18300326feee0bc9663fc1907582c937386fa2d5b55e514dc8774f2ccb16e6843cdee94df1a4a227e94e5b794b348112a400ae2fb5f600a60e6f362c714f047e788a022ef3f4747fefe7664cd7963134e8909147e6fc62aeb47a6d007213d3e385e3eb8feea1b0c5e3a3c90f44423e88386713bfb3159fa0285cf13eaf4889b666cef2b46466757af06a11c0b27d45ec52a81c4e6977772e4a515ec5854e8a560c141bcdb2d6c7172e0ac89a6dfba4bb128378fd41e7224bfe4da57b2e314cf8f5249ab263892931c042d13a127231e6f23423c48ea1a6244dcc18456cccb7874cba73e65e7eff957a82883b98ed4d69426c5508867305ec0412e21f78578a2eb108f5a9ff1cfff991715eacbd79913c2ac6bea13a35019bf6398854e65143cfd2b919245c704e2194246173481b7a1c57aeed024081e6aecb102e8648c21b91dfcf300eac91a6bcbebae4f3fff571e3514a761b270d2dbebf30803eef6407eb2d6f8840be90401f949b55f570792aa6b17c94325d0ba67c7442a31a6f99e8575cc5756ae3f9a1e996563dffc495eabd9aa28c9a815ae316adb49cd329eca9896d6b7c7a3ea40c5dc028cfa8810b31ae9d645953f3d60824590beb360c320630ba30c601101e700a67f8363b12ff09286e9cf01b6cf213b4898203c657e441f8240cbf4d2075e04d201ebf713b5fd58bbc86dd963bb336c7dfa946b7cb35dfb52196e142dac014611efdb1aacc4682c2cf76c855fc487cf8a851f0c61ff064099adfb166e4504f618d0a55f1a521c2b77686a5acd799e07f7623ff656659ef5e63e470c317ffb0f3000ac3905a8468d4124a08637bd187f41821749c7790f1f58f3d6c20026238e3886347cc69aedb6a1a08bf844158b31cf69d4900e449831cf17ffaf7f4424c298676559b1bb14b4c90dd9413ec2274f585656a52e31e5288b2e474b48c05081dac382cbbae7aca55e80bc01be1b63cdb08ac8306118f385d95f65d52d98a99d40928e757abd84724af74f2f058e06ff00faac44c72eff978a014aa9666cea8282a5044ddc459b981b2e4ce59aa15b2a92a58a4b757daf6851e77d8d35b085869aa7fe00d3426dab06f11c07e2146551f01da24a8b70fa10b0c860b9639bf46efc3cd1339ab78b58eb33df7ea7942e5219354708b49aa93191c349d226fdb0e350acc8d521603b8440bef2457e0351602923811a405c485608909ee31a4a16c8579b02238a08b85832db9db7fc92889192a42f54fe46b91b4d6bb03a02b8d3d806c2fdc12f57604b2dcfbb5a80c98242579e846506908137d19193cf0084c549c9341124be119389f23283fc2e6bc49688cd2bed9d46cb44fb45dd0acacce0067b6525aa00716351e0c74b9bad5349baaf82370e102234089d2f72ba9eb66171077c1c7eb7a6890cda91a29fcdef3a44304d5651db1c92a87f3428e271ce36699e0d5b82437a8f8e62b9d7481cd983161907d1dac2d55317407f1b63f80f59b4553fe2dd7355cfc2dd53c8028e5543983fc2dcafb0dbef58613823650d1e6b461da0fb5503463e955618492019c6208fe8d6fe201e4f89c0e1ce2ee69288f375569d016b947ba089a8af79f435d51bc5aa7b0dd1f5064869af2fd9510dea90442dd617d4bd2a4017a82138136da7b5e0652ee0887492a18d437fbd8a2a91a02ae0eafb783005a30ab81ebb04815de4650feeb023558046d2889aa1c5975bb3c943b301477fcf2fb0d4e85c335e8885ecc11611914d66e4eab8466a7a1937c2d8431555a9c0f9808c7b5ae879b743c3e28489a2515b74871ec1ed5e86d2f08b4e1275d4b13b8340db2d94ca532d8163a4a71657cf589ed10913ead31a4e5548553f23f432d9494deb5cf48dce1a778a8dd17c49345c898b355f03c7d4543c75e46c9eeaa812a995b7d8c74fca8f597be2cdc174d1cbb21e2e371eb0c091a0dd93eda8f4c999a65f487bd6da1ed2a2d0415b1b9008e97fe6a3ee0c6d79b06aa0aeaf678e2c095dcfe181ca381e4cea8cb93a974c97b2a50e2c4b2bdb7d76f744111bd193e598865a5fbdcf5b656d13a0b8f709727cba236e5a22d2399ace88311882c56a1472a2030c0914779f43624a917431072a2130416eeace4fac6adbb14a8775ced95fc69e0ad0e403f81599750962905fb4af55f33f2473cced57fb3ab14531e5e3f63ee4d8f1a951efe5925100b86b5fa4098d45834f59ce2d372fe4f6078958ef91fe09046b02c4fe57c04eb72af3fd0d8c0e155ab854c80ed5e1f83daef167e987c0fd35c309f639531ff6f3b40af1fd4d187ef52d3d3f861c7c77fb965864804e863395fd7baca1122e3a417a714b1abae7d82f3fea339894e19f8fd9598df3658267506012ccacd03ded5ce59ccca2da710091e136a6f44dc1aedb86d2730d746ef64e94da0ef435c870c3c59d11c1ebf86e5780fe735141e53d64a2d7f34ac2131e0ca3aa0dadcf33dbd4985021f2ca4948b768c647dc0eba1298a298a39407d110263a6a5689203b7913b7aae4a1a656757b3d38d7d46feee20069cca1623009a7c020ab667473514ac4c3c0d8faae0010dbcb2bcc6e1c051d0fadf8b758a120bee57b9556c0e99cb34df8447a3b16925e772e0a7cbe75f0b4a1557cd2d366b7136f5c2cf1c6f193466daacdf3dc94e38f7bfa53368ff4d22a7bc079c07a4322463c2838951b723c382c0df1382144d600e207139ab73ee8669dabe9a1df15d1a1cdca4c2fe544ca6fbf4017f3a2f34fc6a19a1d9b2850f29f70367c7cac1b7431d524f7908b52dfb344e9040b2a4f630a094dc72b51a521505771e8672b7003d6d777c1e0148caf9dbd6b1d7045ebbe373730b95a4ec4bf41d7cfb54ca1d4635260bcbda2aa18260957fa23db1a577157db79ca00aa75037bd8c56d093a4e127afc296c5675020385c9948bff70117da9af3a2b054f7fb6ad920637173bfb2a8af07ed05594555baa11021b86e664ec4ccc2d57e8d19d347ea2c5addd40973bc3aa84ee2d8f8fd804e42118221c7eba1f32ef2dd9123eae1db2ef9f2bcaa3377ae7a15604542d4fc3c9f7679bd46361e103867a1597b4d7e10edf880b8e3f00a6af0e8ca8a3fd8aeae4313afc64df21579eaa252b1c21a702702882f1e4983fbba96c565a90d0cd77f0595b5eb34144be271158868492db0e6cd1176ed216a60ed23883129042bdd69ca1cff09dd7ee9cfc676c2d55b836652b2ba906ea367f084d1bd5ccd9b4ec9a146affbbd31b5c8f685babb71a731caae771e2094cf994a8ee8f3e6512e374b647326c07648064d25e1197c67877bf0b4c26b3803100ef328099ae73f4f372511871a2d38c612be08386408830846f0122ce47dbdf40951e0b06c70d92f54a46b15d3eb7d789754d36ce06481caa2b131a3e1c4eccd81dde17812255501c372fd60b182d962eebd98951c47c514a6e922c7824c7c9ebb18d92383165e7f35dcd252e9aeb0691c856d35cfdcf00b61f16e808ad7b1a7fba0d94454a619e5c4609c311119a2bdce5eed864f0e110d5392bba9fc6312c4e4c5d81777a164f3fe61e56c8f1688016a445fe8e076c5c9203397dfa04fa81addfd3d7815dfd4531491bea0a6c6536e2af078bd6ac132d290f98e534c794c5feae5d237218149166a41ced646526c280cd9d6ad8f7c67e4df46b044c1006623b984f9d99d312c1a794ef18713c43bab531c3bf66a2e2914cfe028484529a9c6983e4ca477957e410878d2e4dc0160f85e745aa54f6817e1a3d98b4201c5a048e12079af968f66158f88652237187e5559e583156cc4235beb9487a671e987cc12cd3f61914604433a506edba4e91b43b4241bf9542ba7dd0f41d41d9ebc18712503c497ca7bddfc472da8fc3eb926a16539b57b0042d837662d8fac51052dcf98352836354edf83e6e15531f351f0f442242f1b063b471f56162eed1afe5c6385721f2291466ff06aec63c0fb942f5ce1a25bf23bbbf88ca0233a8bacc7905a9106276ecad26d026c034ea1547b5075cf28f456c3350385ad0c6356d7a8d1d816df228d1fb2e9ae49d76e5255a5742d75c5362047694838fae1084143c5d83493e4a5498af1511f5706cd230aae8bf3d337ff37815395c109e6e58f7a002a8a8efe13e83802b0a54a2d70a899aba18ccc30520eeee78fa766c20020fee69a5db67383986a77eb241aef039e56a6613d6d3ac3e36146ede7820562912bf41e8007f8e4c99544de9f425ae5966bc382efe896416cdc50004720e3d2e8e72bd5db343a87c12779cac7d919bd7ef9f6ae6c23ca112588345aa78fb843f51d58fdbfbb4b04d0415e1b4631a2f446f621d4e8b50cbf6fd84fac199389e785151e6b7a7c4b0ea909cf5113f3f4ec44f5947a69f17f92abc637d0bb1fd09ff688bed586320c5456dfd78b05d12b9f1811ca32caa0535e4d38f7aea48e32d3c9940998057c566431560fab8555f6942329a2b4c07debbc5b1cfbb41f4082ba362a5062dfdd5100a2fed117a37649b40abf3bfdd793ffdb6849897823dab86fd98e0c089c31394ad2882248e9aeca84244c42911a6909c2592bc0ea313cb1e5fc4c7c0b2fc31229ce0771d0080084e317e7ea53bb21401a1a5bfb044b7075fd4541d1c66d4e3393c7420458796a00ca22ae7c9c27d7134e91ea79020602cc4d59121235fa1266e47d6d45ef14f052682f83d64cc7098a8473202498f88530679cb864a0cbb940a3398b981c27a04a417049ab4dcab9577d5927a7c70a63859163768f28383265754d36141ba79be93b9f88f2053ccef8af3321c54338cbfb25f2cbb888f065e40c4fc4aeaea43553e721627512d91bb5b32e350c988f8da08c9b26e1b577c40794f84707dc31eba941606f903ae7055ad72568ceb84fb25b2728edb32d1829ab00562c305997674a588c9ca779fa9aeaf1b2853710bd061ded76cceaeaceb30d14297a03c33de6100e6368f7c8ffdf3c0661e7a75063da58bc180fe5282ab1349953dd2f4cc65e9101b7784c4a2d8bc4967ece49dac708b5bda88f0880273ca00388e6562ee01655d7eed760d32a9f647641d1b5434a2cc211d76d50bca64b13c54051bc70bcb173a0ede1a108373d43be01929d14c192488e7d11a0f1b88eabe3b29def7687f6834f39f7a7aee56ff31dd50937b7161f133893ffe3e98f8726ce6064b206b1e447000f790bec58aea556a22236b83e499774e105af1ea30aa1545288f1d3da16c3e1effe926851bc2fdf203acffd56c13c1e4e824fc4bd16ab98bf00ad424a0ca591005ac96ea9c0740302b8791c5d0e91e77916722c3c0b6ebe1d6c1ab48ca6860ee6cf65d400f6a3432b8f074e340a092e482828ac2ac0937197913ba0ad902a840ab90fa2bab91048a608d29a6672e5e91756a43ada69f90d02f3dc21c3d70f4495619cfedbf9336e715853461f0d298a4f9f8d1fc390596c22d8d2ae0e4650461b1e4ec377e4c583d88b144b45ead3976808bd7429ad01c4a3959d640b87ab6782c9a92b5ac09b9b330a73583126106a706678de101a331a5f225059cfcb6befd0956ede7c137ba832cf8d05f20ee35320869b8c257323f0f68861e28220eb467f183e479365b0dbe39a046d8ed54a59a2f1fef79205af2dbd92fb1e606dc53390102625c80d8080180c71ed31ba3487832cfc17cdab726114bde6c4930553ebb70b9d0b36af9b84fdf8f8ec283363319881903b1e6a1c3288e2c6cdb3fc7a837e8637f6095f90772a9128963abb5c782442b15032e3c80a431078e19e58c2e8295c67e073d9eb170627412601cbb096d20c4950ce669b28826bb4f693ec27e7da3d3e91f83a5cd8e4251a0c1ced026e23903312f8f64fb9ed2cad1555b44466e1dcd878b02b2787164b52854e806498a06894b7508a7998a2ac479cd156885c9b27155d41245ce4d671866812a120399fc2181634ecc8252a59324d1257311b0e90b9a51a09f1a6e95ff6221d119b398eebfaee0e5530a005549634c83f611ba2a6b32d3ed1fee452f55d1c34910a057605514fa3d9580555c8e22335e8b833b85a5942a34c55dcfe63b7a170f48c1de0c5e7e573dba7480d9df55ef1ef7284712a79ad8e4161731e51fc60f95acfbed2a634aeb224beb976f81a880af3b22a04e83669dba299a04b1e607fdd93438557c19ad12ca4df6718006ec2918b5f3e9d423ebd68952f48e047df77176dd752513c5181befb463420515e597cd1a032504017ad29c45cf24bc8f2039ae278ea6961805bf59293a009bf711d5416d4e53be382a7c01cb78c7c557a22817a49afc39647ba9ab1e1d098d50ea539b49953e4829c4b439b6964989033cf33ac29904b35fc33531e5683e7344c6da282d209b4cea3dc19ae82eba688beb51d4a2a3a45aecc499baf09baee71eb92d2125351e92243f4378d7ee4fc5bb2d862673a85a22130d2449492f558eb7b57e446730958789fc91ecc4c125216d66cc0c4651d5aab51338ae9dff5e895f2f886a58a334438a84a86e0e26c56b03481ec57aa88afdca6c802cb928b3ba3251a4151f8eabddd66d9b8512163ad392d53fd4c761e65a213471e0a4e888a32a25a3b1ca7ed61144fa5fe835b00d4013b9666063ad55cbe7f1842b3f0bb8aeb5fad70c442fe90498147fa225ebd5204c4238b3b7af9f6c3c4acf3ea023cc92898ce6db8c1a9a92b7693b800818a8b4d6c89ab603140729fdb6fd404090803934a077e333e549686b5a98bf84d51b42fa1c45b967bdf2c5a97eef2472855d11cd32d85eda65cea0bcecfbd221f5b7835f5dc5032558fa80dfb7c0ced44aa2c5eb74604ad277605ce7b71a2efbafd08cd90c5d0f745c175978cf135e5b7ee23aa90e3bb87435f08a4f76191087667ebb48f1fb602700908b0eec5aed19cc86bb95a77d512910c04c6560cf5f5803d70eda1a83a035300fdc628910c5db01c84f115ed57391a7f96c1af04a79316a6bbd18ad4e3d7342feeced5a61ab4642aa34888e373e1aab704166fe11f83cdcd1549da375ac98b7034b9b2c04993676206d4210c5c9cf07a0db30066e6289d8b95b458bdb2df87f5d15cbf2de026a57156b54c232a18ab40a733f2230f807725705061cc407c6aab867a4eaa3da4467942e21fe12f999390ca5717bf7b58d9c885b543cf3f091c530a9a2e15eb52330a77e600b93903e0e39dd49264c3361f9062803385cd4045c2190e0b87bd80576202e8f5cab23f6a5de1183bebe0c6a6e7dfae95963a62b614cf7b554b3ef7b222049721ac694cb50943f012c1e9d2131d65bf9368c4184a2f33e02c60d157d155c7a9e7d1a9de18c853a7d4cdc8f48f75232a6cd18a6f77ca9b1ef68f4429b613e2ea8168a20cbc06e039269c338a592e0fd1a0401d9524a7a64504ccb12cb693483764689c89e3a5b00ba32a7f40bc41d3e483d1adb06ce98f6be3258afeda74f7b166bcda9f97538d5ba656d1f154f89088a5e5de74bd0a375223a487c7adbbf1f7493b2ae27033019122375b5e1d01236c352e82031d7504d33b99ff19c4941298d92314f21ede3a43cf4e8bf947d0b4bf21638b996bb36b5a6b4f74a283aa9b1767ff531932dd0ebb7fed0562396e5581f20410297997b6e61a6b369c1d6955d937f5a44d8b280b068355a4df229819b739c2a793dfbe74e159d61b44124cb44365c8dcef37f0614090a3283c5f115b3a2750b194a868ce78c8dac53c16cc7823c4ffda7dd883ec15b84db907bb1d6b73b6850870b31a20b368d05bca606e7bc2c66e6c8b46faaa37e70fe98de24950e19bd6bdb4bf3ee1aed822d62b90d36683403ca95339c3538908bb82d706dfa6b33bee0391a9f3846dd57df39c5c87c15e9e3dbc87df31420bf0228ee3f3033db8d4023131e6495582ba8407f45a3c0d42aa5d19ebda2e110234b55134953bf20ad951c6e334be86ba72f504275b4d1391895ae357bd74cfffda96286cda4ef002a962183e3d3f860281a9b4c341f6cdb9eeb343439bb7c4d6f4cf0675d29c636e1d7853103dd2503bbedc586e373b6e5137a272cb341bd4f5c501d5a8f6739101a32587a4063020092109947228e1548232855f866e9f0ddd1e61e295ef2e55df753c33dacda56d0702f50e3b6bc6fa15e6c2d6c3bdbf244049ee51abe33346de630a53e1a05a8a76deefc97f95b4f9b4df377399a4439be42639562fdbe6474bd3f7a1a257dc6ef8fb9e7845fde71aa1bfee328c8deac69dfe8be18c6e78d5c900824ae93af95fe1654f775a87050d9716678d811e535593d7db17ac0b220a87a6d09d6397749c19091a341591007200bf2af4dca5b869dec8fd83c0bd8d26b68b238cc479cb6949cc2e0f04378db0ec763ed3d7cc07086afd25418ba8f0a861b198b575f53a46406607537b0579fa557bf17439932515fac444519c7b4770ad31e5b53a625c2cfab032538ac14e5e1f052e0e3e6448eb70a665fd66b7d8fffe04d314d034057e1966bf97c89db656513c3a8c35ad4d126f0322c6d919ae63d6579f62bc5cf1ea1455c4c6b014d32b099c7a975327a495ced53a6127fd6e049c6a1742e270fa7d78010b7b3c25977c998742528dd34b46009f75e3f6fab154fed8dafca05d74fbc9443584a156313e8cdf9391b1371383a21db22ef20eb6a7c3365a9b715b8fbd50390338ac2ad69bb02ab50c987583722b03f019831d9effb06a910655be2cacfcea83232d2bed421e3fca5aa99df350212000e46175d7440a872134c9c564a73bec0657d96bfa5e4b75b0afef5ddfc380a066d72f78155888d88fe6e1f16f408faa51996ae98364e0bc383cf6ff2521c6c77c283decd1ca6f3470c379241f6d8f24ec83b98ed8c0a0ebf3f3f6c8407a51defca174c5039e2cb8af3a31c3e5f8e163ba35536520a51c68d20640144464b3920b2002423bfffe7e3928414b2e8166b598147dd9b7881ff33c8e2c91f5e9696c870ef2ec2943097dec3b2300fe27259ee7d346816879c5a266a48478bfcb27dda4d65114ad205c4f92120f8e71dc71393a629df3674c733e8d8329f2a0261ac3687a75048059e2e8bab4b509dd39935c40200eb0cc7aa4f63e6773a074bbb85e010640146291c63e9b000630d48a9898eeb1093a1aa7d52846c7c0728b45b56e511b8dbe3f3eed2d1b29a3f8e709973d18c4abf3b0bbe590c70aba0c516a19fe3da9456fdd20c7d7cac258bde6e2d69f6d56c8befffa48f5187a521eec823b34865dd9530069d3a211c1cd56a905d105eabafaeeb0e536a201002491bb2054a7bc5f5d5ba92f8646d858bdafbbabce8c80a0ff04a0302bb301db914e4c3c6086700c891081d8a4546658c00b478f81772678ee370ec048b3eb20bf8cab7e25f3a11140b0f7a513bb89e2db36a0b0ddefb06801036a8687d8325869f9f3a1de40a640e106bf546df426722240defb1ef9a1f3a1a81e8c063f01b10c09edd405705024ce11b00f75264198f5bd6521c68ae6d32c1e3003417ab947e334507a35a12cef9e9003c84ebf7b9ea80270bb75679303ea1fc3f640283781bb2bd8ddedd466f791b101446f7a26fa5aa5b41a5e8ad94b0e2aa829301f94898df6f02d00b1a0cfa779e9530ff8dcb1eeaa48dff708de59c2f673c8710b33fffde679bbe8c25e13a963170128edd7562c6d5992977efe8b6e3fdaf721ac2e31e483d57b0468a6c0f32acb620c0f05f860d0105b08991982daa095961083d6ee2d0d8341ddaacb01511214d0513248c0a61fbbc5febc7055cae10064634ea20dc15b1aaf7ff169bf911648934e605ead6fe96e0f45b37cdfd4c8ede7757c3708b38c09deed513798e69316c61b24e41bdc08f734552f33d71175e96a964f90ba07321dc6934061476ae6b5ecc344ed0b629bd93ac7f24f1cf203acbbe59ce9a357e8a171913cbb34cfb01c0f0e7aba1f429854de1e46cf9a00f38ae14741372cbb6317035432e4471043ce6cfc083db11c97945629cfbec2cb9a84b64197526b141c2f57a776325590d1c75d228693cf226dcc5c6dec4161c7035b114c589694612fa15dfe670b2c7029eed947e22bb20752f10ed1d4fc6d54b9ee568adccbaabe58d6c4ba34a0a0f160aa5edd322a3c451b9ad9698feb7b8235ea953241c2f49c0e638e076724ee58d7d2723b347d9c85b941ef2c0114e7364d7c6269e4303d4c9714099b612515069957140fd3456c96888981998cf1ffaa2164e38da326821593cb13a689ddc71ce1bcea26683c949d38fc47deb548c34371c529443b0fd45889bb1e10524e8e65e58fad88e630ad04a92cba11b700dc5fe71acd875a5c18da0b0e7ffb7de7dd7ce93ab696166c57328c933a039abc7b5b37bfd7690d8bf841e578b2252b8046ba54034d725dc2c5145c2a547dbf6a791dfe367e553f06ad19d9318e7b6c14467b816def1e459e6d0bae391823097afe08fb786635cd64f2bc41f0301fce6e8a537247ee3ed73069c34e4cf50223ddd8e7cc0e8d105a0eff8ac1b8d42a7b47035785ddb26d9cd558298123cbd8500d79fce6122f35d4b9ebcafd21ed1be7cd43b7284ef361bcbc51f738356c0418d2f690a314185a11fafe20249599e9e2771034418146e26a425a1bcf9da8fb478fd2f3994ad4aca7e9f08a459960f333eeebd64d6f6f43f0c676eb4b1bd68562cc2061c14360d2cad6c341538267b63258df2eb293f2a509c91625735046e5c11eb822ff2dc67d90ad2bd07c8ef18f5297636f8c17b9fd6393214210207aab183df350555c2c63064c0399253708aa637001fe8316be0cd91a7db685e33fc973eba23af446d24f472b24e5a905a70dba6ac731a0acc5db067b322bb7874a3df1472bb3318bdfd44d62b31f09b1053f3ef0cc0dbd505a321f07d636def6bb59011c5800fab2ac069c40b6dc5940ec8e21f0fdc8fac759ca8fe22586e6d4f975592736d83a02c110837f82ac10109cba4c5a46c397627cdf7605fa93a56ec1ba6c840324f8d9a8859a000d92750160ffb3802955f2f38e7774005d9961b8b6d52ef80ec925910826d165a2437034b38268c965b05c1e6daf879fe4bfa93cd9f0c05a8c18c00812133b52c7613fc599ec7fdc210c0f2957f19b4d6138a2496e852ff25aa460314bb81bcc473187e47527aaea1b41be94e345205a81e444381007f5839446c32d0d80e631e7a787156891b8bc0a6497c897679c1b56ee40616fe08a942f3244a6e1ce09c27b8768df57715d9f0fd02b4076c4d8d5502b674aeceea43786e03bd2980e09090292c1f256e0f53dfb42471c93ca5705695683bdcb57ce65f2548214e854203bbd17f67056af2b8ac78d0768793c53a541869baa30e94c1261bc7ff292a8763cc1ddd385f74505b4bf16a3748540a7dfb1f99545855b49bc926b8b6df56b16ebac9b1c70a8ad26f26b81673059d73e781ba4df93eb211706d7e158b384c5570b8f942ea030c465214eaf3a8748e246f59a80a2c6fdaf63249cdfa3aba944584aa0a42c2d40c67b7e52c82f52a695da4ed534aad6695e4115b4e80cc00ace798178e0591c9c41db18dca67c6e35288626cff21f357228010fdc35a94f7ee6cb822f510d85d948fc006983ae34467f200fc1cc2fcb19142d41086335460440e9a35041cac6bf09d53baed841c5f69323f35ec054820633f1fdda41fa802db21a5e0d2b1ba1180b9f555ce06aae1d3a2a756ac2168d647387d35e211c372f50543e6aadcae49ec3dad59ce979f5f39b35e689b7a13a83eb8b2c6a9e08afc1bd06d434f4cbfc26f3af220bf2bdcc9b784f7d8ad994d5e0a771811e41613133de66cf96646243b25f40a9026cc6937d59a9105261c033c948a3f94712659de4a1544089ca9f900c6dcc6c5ddd38e5828339b0483a5a60fb46e7e09c6a90ef3a133d45fb5d82dba8773c2117a030d4bca1554d05da9b8f5e1671d809e6977c72586ccf000c7108f7f55eae8c5b3b626faea6534037e7ab956b47920f458d3e1256c48abe7899f7136d0901c01aff0331ad1c7027591ee7b1b441f2c4e148f62f836bb9a092b0327954eafce0900275772d011fca4105c2b84a3c8321d2fdd9d8bf21c2c465f1dac959a9f8d2f942670b2deeb555ec83eb3a74f1ccff3b76f09961bc03216b32a4bb3ac8caaddadd3f13d4d556c528d532a4e6c04cce386f3f7c019defe813ae3697557bac6451fae93db102a4b3093d141d07f17747464c0cd959782f31142293e72a84fda47f89a6e3ff14c81c8447489ab29f252b12617439ab466337e81ed3f4b04ebf0b5a11aa6ce4cced076f781e1cc4c263b5496160174beb2e05ae8e2c3e9e28428902221dbe2d174fe9f65367b6b6d78f9a72e4932c60b23481d29d6554902a9c5d9b606ddd71c4a5fdcce8591a12037a51a2c5834184c5c0d782ae459764b6ca755b472af8dfffde7e2559febb9601b5ef951ab0fb237794aac28f16403d6a3e469402f3e07c9938997354f5b55860ffdeef9a438cca205fae3aea09e6d733dbbb6c813b5b058abb56db6768ec135176aa6356003503153d17a15fc3a96e8cc54831a04b3ff3ee0d63fedbaab25727a44fae79ead5122a00275ff50b74f65a0b2af6d9062eb7f18955c4a7256360f4bcbb78c6d7375ef8bd1682d33958a1a098e6d54e40786132e5950015261c209a2def1cc7683e9608b4932b360c4e44354c0fb804f2222958f7db3a779c9109811afc3947dc28716b881edd9fb06424e85ed714c2ae539107255049509a9f2aa88f837af4205e920ea3fbc2301e3f1d3b20ab072ec25b2afd108092104c93dcf828f1b0c155f8501ab78bc2f0432d3b78e632b30971e58b291199402594477e792878f4254c797bfc92585b3098428e959a0d0b83e5569f77c998e7296b82a1b874d3be12327c91654b1ac86c2408a524058f09b90f472dbb0efab1754a5fda91abedb66a85a35d3654a1a9ae9bc14e4385daee5723f487fa2006069fd9b1bd9c954569a0943087d5c021fc4ef3a372a3f7df34d399a5dfddaa62a6554520433721fe47e14f05226da0ad55a8c05c076f9d1a28b4335151cbd7e44bd8611ea48aedfc33861b25efe46c28074caace7864c8018658643919a1abcf12a135c90f0a0486c50411b212a79303a1510e76cf10575e1599a1ba5d1ce29cfcba68fa106990a815f2ee5d3a634c743a1eb494f9bca641a8928f01d6f9e1f73396acad2cc19668ac7e1c8e00af6b28db21362e597d8cafacf7e8444ce86e7ca8666afc8a7e7ecbc22b311c239108c4c9348dbf96870a6224c51b8beecfa5b2f894badbf8329fba9ca8a6f67f53c70ee62e63c8b8403dc32058f4f8177821d9155de350806ed2efebb4a4f002121ae70be5309dba016a59beb1b7cb5f22f082df5283428337178bebf8d4c1708d45efe82acead7b4410a821dca93d99c2d58e18c39af3418c58fdce8333255e142178d2a0c9b48ed86392952ef348be6edae7dd2a3de999cd7f4e059eb068c8ac26a6b96b537fc6ddd82a4f621a154cb5dac85a5e5b8737a1d9ccddcc021cb978261f41e99fa886d7082a152a3fec008c1c568b5e6f1167379aa493a4eedd95f237dd4655412fbdcf97e272c06776c1e0a6dcc416bd39ab7fe04c49cd6544ed39a119b003b23100249aacb40e81e8ca11bb221a3020b01be13e7dfb71b040a7211c2a33ea036ad3ba1022d5dd2271f8780a564072141b13e602892e24b798160d462e6246019c096894eb3343c5985620952794aea9147d4ae302e93238a0161e8976c1b4726f1f7410972d0fb9958851881e9462d4342ddddbf06b8032dd6da9db51fd7caf37046fa27ce1ce3ee2b675b34fc5452fb843711bd38b64c043a0158e48311d8a1dc1cfd2443108faec1c6fc1518596765952457d61e17ef51e7b7442e54b4be66affbdf8721c32cc17ed38f794709210df2789b403ad91a6236382237b4ec126fadab4442eda70413baff178abac6a37b02bf88e3ab76623a027866eede827a20b7a860f843e48960fab2ffb17e77cf3f3820644c98786999cbac367693b3e0ee50894f3df5f872d19f50c96ba4c21f165aed6987875e66b35eb6f6f1b964aea139edf0c3a3124b90978dd6a37460c20d5d2b48a7c48635f8d80a1a012fb71a7fdb527456fb9c2a5dd7dc56c0cd15ceaefd74f402ca8cdd451ac7eedbc70cb5ee3c3612c5f231e3e5aeb1d73d50f921941bdb12679ab2f5d5c37dc9d4b441bb733b7be5d08623934df1ed0519e2de97f4d842aff68445edac99e825c77f1494576347b5271b0b449b50bf4be2562eb20d1711d1d4c4e180f99c3693de6d6bd30746de09860e27bf300fabdca836594270494771da9bdcbe8694d1eeb136b5e488f8cfeac2f272475e530fa43744ff43b295ca95aa05fb52c1612c0bde325785cd4948cfcc3947aee6b36ce8855f1ca34a1b0db8e4d16f409c1b5db58e0b50bb7cac1411abfbc90ed5e958800b2ea2c02f7fa382020afc4cd1292c40c59040796c13602333761314504f37e96c9277fafe2fde60b14aee76260b08002e4305d07ab0559d04412319206b802d5ccd20395c40c2f1e6f9b4b2919610633ecba8a3d0d69f0586e153494fc48828fec3dcec0fea770010fd638b249d0ada780c46288910bade0bf9a3ddf8d216e09b208cef15ecede08181e1e78058846a64adbf75d1b49791ce3f6b04ca5093cc69bcce8fbe3104d5a868a47f466a76368faa1941dffb875dfbd4b204aa49a2ece945b64cd4b859cc36a5d99c7aaedba10a6da992699691af8318421b0ba8271110b0835ccc84e54dcb4f3c94145c0848ce7d60108257133f1a8516f03d4cf59e4f6eb3172240cf072dbdc5bba7c2d1932116fa628cce0ad0c0a62f4e133c445a4012a905dccf23a0e744d4ab986e60ab272de57439c42759afdcc92ee80f128614df0d927f114d9250df34eb4bc385aabb4128be5a3e4cd591a7368b3bd471d4eeeddd0d35bf2358bde422f7638364e5ca314529e56590660863b7668479e649f03dde49e8f1b7b386ae081a274f8fd68f1d642ba45f38f38a8a3935b05c4d7357aafd13ec68d0aa1fdf494bd089688ac9af3bfef2e573179ba511162169f7badcf55a49b8b7dd200ab3f89a276fb95c5ffbc36ee755312187788046c6c9fde95850b14db205c01d128c1a99d69d4c30751eb5eae4864ab59552274c4463a3efa9a12fb7e73515e640a1620f44fea1a64f632a4e1a1c584f7461108fa98b529ba4a9cf5f3c812f8fded36dc6166ecf3226069a6b512e7bd9e08eeb2ee722f0099a23173117b66cc4596580c8139c852601d51fb281562c05f29ff9ce8c05e3ccef0d4418520761a5836b79a9749c59557e704954eeb0282ad9c1130dc2c4dea071354a6deaaf4b4ce54820eb2e76ce44393a398d2ddec646aa12cda8749efa5a40959cdde2eb66c07e0c608082e1b10e7b4b326213cf1bafca22a9111c0bc6d3a508464fa12b7da7cdcd545915be3899d0293b9007342467ccea04dd378e12c8844ebd8b695d95a94993f5b46b785160cf9b4e4c096594a5e3b8e873d0cfd39bc6c0450f781a5311e69eb147bbd12c856c8ade0d2851eb29f0f3ea10b6f7c040250bc2997b6d145611e0cc096b0dda413386e26878d33cb1e0354fb0346f029bcca415686944163d912bc256729fa0f2d748f6c27f383da3e6f0a30329bdefc9168981c8617670f23f0e5634813587aa82721cf1eb100937e79661597fafe6ef3a74910573a03594a0d7e9eb53ad474a98a48c488de1d70f224851688f49486ba2bf33aa14fe3f17f41392dbcdfa55cebdaa07967bc9062448b310c5a161e7aeda517b139be1b777941e5fe7a1e14be3e1fa18302f117e17ac5b13254681dd1862804d49f8670b3062e94c43728859f3f286f4e2e42e7965594ff4f6211d9fa21a0f138869a140e536fbf8d012d60e45c49ccd5cb7cf2e611aa0a670b4e0c4bbaa423305601414415455fe5a0b22b5ae9c3c14f9039c7809dc66a28bc5f26461eaa4796c1cf79ea7ed0e94e7e52a642db77734ef34984f894092ef7c5c2c598404743d962858b8beb3bfa289e56e6107c165a853f49f7634c1995fcd69c2395d6aa6fc4c57d106c5fb9b0d12eba4a22c09bc9b8237a07a5a0cd951947fdac37a4cc6e9a835292a6d489ae91a6ed0756dc2f8db297f144c97591cc8d70da84878dc4bc05794368c6d6c29b2055d5b54cbf7dd28a22942e9480110866664fb30343ceaba86357c26449f12ef38fb18620170003ac7e1809386f296d8b0482cad98c98aa56e98978b32ef4f5e7001bc304675594861a1183c71637a4f12efadd85267ab192197510bb86d49211e9475fb1b85edbf2ca886196f274edf29e9f1ce1a5df5e237905aeaa49e96810a8abf2ba5ae90cec73d8b82dfca35a7bfafedb2c736752390278318c26ef19ee870f7c26c704ec30251668e448496e53218416a22df41a2d5f7114a3b39f4ee4cdfaf8896f96cfcb396971fb20a0a5c5c0e57c3a8386f69b186394c4e5feb4447303293d09fa493be3c3f14802557869de543a7882f9a140c00aa63702edc20290d44a61281e5fbe2afaf4f646b51d79122d81ca2549599fb0b812f5ed5f297e9245b8b7883d24161a5c74e9f3bd04043d1b72d652a75335d191acbb2635ba4a521f8195f15f7ea7c80f73214bd45767129ddbcf0acffeca859f1e405848a0ca4995e9424a717323f1118e091e39d7efd1861238e9474e60fd292e3b77fe58b655f76ba12507de5c2132cafdc038677d8b15d8d97ccfd4ab07c0cb074c2ea195143b173ae002bba737ab11d9f1c597fb0f839ab66d5ab838c2d53d2ad89bf06bcbc15fea8a71c2cddc4a186e752b75a3674e388a564bde04f0816aa37d091957ac627117268b1b5870fc0b30ca90a648ed7f42cf8e8acca112c55cdd6e640c61f4e5141ea793e5d0fa0d0f6eaab5514c43c5080b2be12c1ed7b98f7a8536d8d812a97b3b53cf45349aca811bf7cc7db283e3d3cec71a42372cc3d6c223f56df84d60bccc8159164ae134c447a348f3a73ba95a2a960613e3284ec3dc8ac0408f3fbb906534339e913bd43626f10a0065605d2f667ef8f70a44fb3bcf590f0d08c3bd3b72178077b0502ddb0a06ddad3c3331eb59cbd7318ba6032b7d3fe87a60c53580e46490f6b3c971db0613922a03776fb39c2590f14fe988f4b58f8ac5711b574749095968ac24a9da6c3abb1ce8f3aada2493b3f3244f44ce9f4f94b9e1a104601056052aa028f1f3f80f0d096b74921ed8f4903bdf9bcd9dbc4ac555397939a9249f731544d9ce9647c42a540528095b0a16146e3f86c66e9a1f45f71e56402d811b610b116c16ad23631890eaae2bae501dbe5e3a9759caeb29b0201d5164053b7ec5f1d325efb9a6fffa9033e3c93e137d5a0a07f22b4d537051024beabc820c656ac45054fd0603541171459a776981881cd4bb65e725eca4bb6b2ac1134375c05c3423609b82c552cb4c3bee7109c7bb7deba1cba16fa0013a83206ab53407f13019be2224ad19486cc1f4f44da4ee7ea266be4d2f660f22e7ae2884eaf530c9e774562de72a796ae180b6bd0b585731b118a9320868139d2d119a5129b27bd0ac187f347079941c721846ec7a3e81f6a8e6828fb7b38d5aac2cb7c11cf263b035588f630bf4c0fe3a533176e7749050c2a63ccc62dda3810cbdbf059460f935640aa46fd53dc748ad0d8fadc81ac280d3aaa8f59c3c8a993fa18595e4e8929b29cb802b3c28fd3ce822a901e5917c1e391820105fcc315f341fc40766e4fe3a6de6340339f65f61ab219c638ccd38f3eb3d65c7013e8d08fed518a78cbb737996cadeb5ef288b2c257575d5676fdb010404ed1615672f32c705d6846224229f282c77e8a1545b0ecf9d5a8915698a332df5c50b4093068a4a34325bf66bd58c0919c88b61687299289872216201cf4702b40f6871877c13ce0bb8c909a6781bfdabd56f1604a4bf569ec6d4637942d046e66c0d3aaf0a89630ba00404f7225c121f54bf760205685d7864363cb8ea034891dc7c16ecf12acaf0ad9f81d9665b9023c68f4c400d3b7e4ab73b4fdbeab2618ea3b96eaa03bc56590ed868d784a88809a6aa18ec76b6f2170b8db4c0c5b09b1f22239ed0e8c035403fa0c89a20d4ef46c9e56b96eea83080ec9cb8853ac965d19ad170f8c37d78409041fe6a484e12278a6a54632caae72121d3b7a248ce52d684021c74ac44940c0deac1272dd50a805ce61730f670762380c078cff1f0fa0735306c8b50d9ebf8f65f5584d3e7096000f0fa4738ebc710bd4fe313f9134447bbf34ec052767cd9d62cf4d6475e74eacf59d616548284f7309b934c6457600354cb12e0b2779e527a38f22f503d920301d5a4ad78ca881a8bc8c3ad3c3d5325e80df0d5bec9e8d6c2413f64ba77b2e77cbf73ff90396a47d9099c988bbf5077fac8d783b74b768dbc8ef76e5b53e90123e351982b7065fb37263d0cebbf16a11b6fc1b87a05f87aa1ad8c3d39dcb26da8c8852ecd5983904eb164885b73fb9447191f71353424f51eb0ec8d67d98d303c8c7f5e26708c96c9cc19bfe8a4305e8bfb5464737331154b18858b9fad5fd350f816afb1103bc3a3b38e43374f679b8a20676335cff8fc4fb19dccf8fa479376d60b21d4b0511239223ff397f6f9cdc90244f758131c80197d72de5f516adef6ce36ba74ba5fa71a4abb4d3fffea74b6ca83fb0a36e6096faf053c6e7e6c290aa1baa271062b8afe6c0997fad6c38dba1bb87eb80d20ba7e39f383acfc0aaa74b404908244eced4ef9fd90a2d9553fe9d9e3625c13c1cd41e7bb7c05d400357e891438ab305fbf63ee36b0f777b29d04d875d5b434362ad224649cf17c3ce0ab3e452e01dbe6449d930e00d4006cbfddc767bac3c111625af4d400fe80c40968bfba1052e03d1e1be15caf58453a97e677a47d9884a228940961d53b81dc77030a396249618f5afac1fec111e2dd138522e184117d59bb1ed93e198c9017ec4c29ec3b4c5bf096e1cc2877d023a1538cf9746e9e42917ffc4e89a1306697d4d998dc2e4d53adfd466941920e6ee016755044eb897075c8aa18f24f5b4b7d080be06a6242086e79d17548f0056994192ce0c650e08ed63c9ac414a8c5fac611bd5039fc6e259746f1ae8c15034a3e3b97092d31d229d47141b2a1d5ae28109366a50f2e99ab5c6e995ce7091e46f73c11a15276670b3141d6f853657bd1f2ba5a90821d2796f26e52289097401ba9fd0b576c951ebe046150b7ca800bbd7801e2ec08a7f1b8a924e14901c53c83e17605747cd2fd55e407d4573da0583bda9bb7d436abcb8850605b68806817fda40709774b198279055301e5d98878b054b2417a26141b949128f380343ba4d1daa4e8365cffbd67e16b31c388de36cb950084c62f0108dd065132bfe6c5d6a5f4e908a0c1c5fadaec151b26215b503415e5e26672606603cca3026032a5667e76d3242a34f6cad004bd529deb288a639ce687b296a957e5457244cc1fec03e28f9802401ff4583ba8db6c77558a3613c9af058aa96aaa567656a7d04285b8940165581da79db9c8c0899189a7ba1a5c3223c73508463f48f804b49a7b37d876f0f2dce6e4433dbc5d4a161ece82e81c50877862a6cf555032884a4a18699c8c5687b6bee12202c351afc8f5fe9ae9717bb0867d6977691f01f74a5e02b1fb3af949d9b583caaffc6adabc0a558297b2636bf291644a1d048d02064004042afc0f7559b82c5da69acdda464496d86902982f93e46cb8ce838d76904b5aa163391031a099aa115fb08efc34df527b8e098fb412847fc21db350c8385453b6271bb7780aaffef2ac8cbacbd50a0bfab08122a4c09e24c0ce72e84f1707f8a73291807acabe94d5cf4364be9cdedc05fd858f6e7c0acdcbd9e302a0c3fed2a3732d6f1214abff34ec662614850f4f62a2bcc8425bbdcd630abe27d6d28ee733b67a980ccd683888bef1d910487a846c0f3f5eddcc2cbe9e926b0f6d8f52bc9f0e8d65ddc61517759970f28a2c7bbfb9ccf564275f83d66484924b695065270b12f00fd4d74a7bd3b0e6ca0240d73033816fda09f8687996f19215019982d4e202eee2645917eccc1d741f75e62bed956e1f6e65db8efc7222d0f248e2d064610076f6067ff07d8e6ea6cc450878a6032804b25445b99c9b6add9ace5ae2ee59785c45ca9020b1889bc6bd06a349e0a282452675189181718ed3e511d76fb9b11177b7ca1be2757de44e9ccc71f7b7bce1a66e16fe65776de32e03ec4f8d0a0e83cba611ce8bc5091e112157c1327c302c3617282586a82d709fcb846c6dd56fdb1066f8c4694454038dd04d3215966c5bc7d53482470aa868bf4999ec623586b38b7383c814b5d0eb06046851943b27ff80b03760c11646c4cbc259aeb997e403cc0d3c736ffedb58432d408e6d3e4adf158972be0dc8d374ad80f9d0677430886a1ee8001e0b7f0b380d713a6880f481c6b413fb254ad37c5be7701d8cc3d2623c1d0d892e962db36d4104790795b2ef7cef04de1700b63ae3c97462b5e11f504433ca8da5a81e4287caf14848b53cac98b5cd0249a1936441cd517ea62afe9dfbed7668527d779b1d2f42c08cf7b134b45e99d073d2b9f35f140ce1323c58af15d32588508cd81a535c52583fde722b78459e943e011c963ca5cfa56fd13826a8cccf31b7c6982bda74730a1d751002315593ed9e4c57333d4e8add10ba56f33d4ab55e2d4cdfb3583d8d6f028f46ab9140927e71aaa61fe66a8ed14420e45c911e832e60ada91488d35d1551bcc94d93d244ca1154bff0704cb1fa2eee43dd844c7f153ec8a64d1758d2583d27f187b3d6fbe0063a2342a9dc1a8105cd7696825ae251e88141c066df100cd25ab7b49398f0fc867c8d31badc960187599a439cfb5d5649cae72371ee1826c0fd3b23183bc728637c31783d8148b8103a4382d3589f091be8427a39088015f7920051d0c944004ce3106c8a6c181297409049ae16d793748dfd771438e8c7dbee63961d1f2e648973ad3d9e66109d8546dbe4228ae2b147bbed2bf2720403317992bd2f336ac75451e4f300ee27340e3b9c7e05fb33d9edade87f923fa1c449c1ee15b144384c77bdf2cb82f7c454650e2771ad4ddf5893fce4cf7f6ebee01b973d8aa4bf06500a646c97caa6ed17299f8652fef80b1ac762335433703a7dd4d158f145f4211f3056b6bded9cf937d6a2132dbb23b6b01975ed9a869ec6b0398a83df80051c5f443f3d7a6dc99748cfcc4eb8a07fc6d2262fb2cc84831ce312e8a51be9f171f05423a678319b05d85bd8bb5723b248e76a565720f3891f87334f9b98d866512377a0c4814d9f3e3e476170b9519bf86c688e12da032a5f1f706f5fd0b7a20448679727c8073d9884c83bbbd88ca7c5a4d52c6c772528c728208ad62adbf229813c5d4cdde92aefbff8baf0deb064e2b8dd599aca974d678655656019a6420866c49c0ddb527b43eac98f3bb509a0d010660fc4a591fd10fe129127da4b9d8036b186c9b9739f6836e3e64048ccc5dbfe7af766ef6b65ecce2d6ae9f5e076dff9a6157bd9fecb52bee42eaf5a51ed0b4b227537ab0db9b708e22237c418e0335c5001e5568259cfc110aae1b19acff55ae9379ca6d1c84fee79c0a261e5e031d29a137c3d8c06d868404f54fc0c160d540af90f75fca0f8951eacd1acff19e9b134fd2979a3c0dbbf307607147cbbfb71e1ee6914afa3d4f1212b6efd1c06a642fa26f72d1a9174fd848b0f21114d0c1ac030d8944524f5fe7e60524e1361d9f0ed3b169c217315eaf937908708bcdae190bf4205cf2e8bd9bc7e41974a68455746027fc550421417c50bea3a418115cb1aa5e8eee070f36ec735ee2213aa712f94a365c15d6e14c6308e0a3da310cd9c68bd8ab0557f06acbc0d192b1365a1c0570910624b54ef59395af53b4a51b4d454654a3ebbbd6acc6de4b9c1772ab93ea38f06f27b51af15c14e232bb509c38a40e9ba6886aaeeff1ebef2f86e4f37498a2784365fe5a4300b4860094520cd2db5a0699e64546064930da29262eab05e411ba8d018b23c22093dd210e6bd0e9ab5e8c349ed0149df6f127538ae06334a70cdabcbbe27458a1cf665c6e242459086da73925062236f6a8087df022e08d65b327ec83f6a210eb7ffa71bec4fabc040f0d28764a2d07afa10e1b02bfa419e247013605ba4bf4a29078806daabd024bd32bef35d22e8236d0243d75be5845d1283a1187653c238adeeabeb7ec7a9b17e58d49f6c878400354d4b407a83a841eeab1a29bbab25345c71cc62597505639a62177fbd63250d14e4e2a2132a44494a9bb5d05044a6d03e52a5e7d567625850a037e2700c4f3ae13d31e92d67ebd9004ad782038929b3cffff2082bb58cdc161bc79e6988479a8e73fce48a2321e577c18f54e5abe012fe28c9512ce3515c310e547b8e259791d74d3292727e7cd2373873e86d2696e8a214e753e11eb64fc9f6e8fc0d5362a593ab5058d080e07f2d393a42c9aa648e097bf1644ff789d7e0b8fb4ef79ca6f237f7cf693b503edd15bf1d6ac5e85c2e0ef644c1cab0cc341f300b38eb4810fc6e48dd58d23e3b255b3c3cdb3703ddebe19aae5796ea03a24135b96497b38679795a8e5614ee552a781de29b77cb65d7348e048913d5b9d92052baf05d6e26bba4e2674ee1721b83be5baf63d59b0e84ef4602ea8214d1822009f729527c22d402c80bbb9120cdeba216fd9c1390f06bee746c7abefdd74a6a564cc6bbb261bc7961ada4d1cdf7cb45cd6955c1f9c522a7018e6a651fc193955d451a49eef794289bb8ca54a26642ebf16488092a54999a1e866997628d7ae5d79f0222d7bbf727b5acb4db125c074d0138adebb9fcc1e53518a3de989f42801ac5ce29bf88b9d50e6a0280d02dd753168afd6589a49cf5a468dac63cb83e53a27469684b2dbc3c189af3591f9e4db5144318d9822dbeabf5f5d00b3cc42aa7509151b8ee323ea288ff54a2be6b58ba97234b810d36d90d1d2286ffc79bba8bf605153bb3c15768e8a3b0d77e5eb90770ee046890051f23c4f33e0b43fa2e72455c3777bd950151ead8e4017f81f9532a0b8d8c1059431c8813cae7c284b170f214b070b30b2f423cd884ec197e309e5f0ed352c781a323df0a6de68c8c71490e9323b02b318ac9ba61915204ef4f0239f1dec68730a7752d0203b28b3d03a6575f574b1ed3fb0cda517aebb57348a71601888f9280b5ac6dd5dcf0c2a0494a94aede69f51a5166e6d3db2a70c6e218f6be9c54ca6bfa4b4b3faf329bb8f718f6b2792cc1aae0fe3748dea4973fec949b2d15e5de15c8c5fd939cb8eacbe91d853514e9654f4e7f5c053eb11bc2586adc376608ee0d539e3991f1192be7cd09811a78a514d18284aa7737eb4c595fff08bf70e2e19b0d8d631d20c442eb5db81c5bdc034f55cf4fbd43436d2c8e45f2df201a6c1e6ada8efa5530dafdef48a223fa51171a58fdbff5dc4553fc28ff490b37601ddba33d05f8fc9a6b335824a363c6a93ec3f867231301af935d1c43842e2bccc19326900dc84a4434e80f82a4d2a0c804b98b9d90d8e2da34c8383228c67c7e6a95b6e075419325650dcb48cbe5d322d4923cbfcc6e949c9057916d3adad76b406116f1294700548a225506084185816eea6cf656cac7e8b6a411763dc50d1417a384e98f795f6cd3edc7c65ac2421cf232aa43dd5c28f9d1d76d2726eb71a5c3a5d73c3bde557a70704c45ff910cc6703ea71f67b5b3054324e079584438e31f5c54c9b8ddefccbfcf6b4ef4e30cbf35a89ce355b6284eb464cbd76b181ef3fc69defb10d3418da718ef54148c429278063f2c0d27900f614f43002e7ee8877612a3cd66aff0b6a7befbda59432a524658d079807200829071283bdd447ff0ec6e60face7bf20119f28e9dfc13066761d8042fc6486eb0a37f3a0c2c1af488d0ef9b8a952dbead69f566efd69c56c527fb2a08d77ebcf56697e71ebdce2d6a945498a5b27945b6713dbb74cad55b5039b8a39b1d6af34493ed6d74fc126f030e153fc5c404360803631a702ad18202a0a91f3e57c399f77914564b57d6153f5d6fa46d0af5fd32891f7957534971da1cb1e28ddb6176dad99e82d358aeb726ca3b62eeeb44cfd51105604f53246a9d02ee04cdda9cfbab5b266b8b41cea925b53a41b8f4099ca40d83455579b1b84019ca99f2aed68990ab78850200af2409b1c3dbcaab1d65a2b8e675ac1b4c314b30367eabfccc0a6224f4dad70ebd79a82af28f56b4d451844a0aeb3cefa77d68f30d800b4893c70a67efd201cf0bc2abbf8b54ce524ec55561777b62a36e5ddfaf57d34ca08cd7ead0f43a3e4d7dfd128fffa1adda4e626d8f5a5a93e0d7c8ad5c4aa8b55d5d5341a3c006db8d6971a3665a67530da77305a674308e29d00f72da227817cee27207adb91c05ff422b097be4855d328ae83615107c31dbf10fba2e7ee07d7f29cd662b2da33635cbf457b510783bd7cd1731dccf630d8bb3ff7fcdb6336b0ead287807cd163a61ff2455de5bad8d332f59b8b2f4058ade38f1a56b1c099fa9989c76881ad81bdfa58b701f66aadf25788e153fcfa1e9ff8ebc398da75c0066d3988d2a59b589ae08552ca8fa66a921c4d7e35eacd5289c4b287c160b20cf35a86d297cfb2a7af781d1c5da4f0030a56a070040a3ff80f871528248183091c597000218527fe87ef01052aaaa4808214986882c2141c3da099724e89420f96c6853e3350626806477866a0021c26b02e4b7814581bc68f6d09028e30ac8645ab881f1c4e2c76a14f114e1881c98d2014d102318ae0e1055663020a4d8e60c4ce30a018e20731ecb605163cc031c412170e2fac76a1cf92289a2c79228514587aa1cf129e252d560f1595e2e4ac66d44862a1a10bffa1b7bbfb084208a194f2c55da4b4724a29a57429a5acee3b2d4f9d25f22a07e16aab99066bbbe36476c3205cd52aa22dd376b784dded2da58b9452c297bf5e7ae4a240524a29dd9d2b7dd8552ae594d12b9f2084104629e527691ce08aaed6ce882477f70d0849975eea6ef9524a29a5f476f7197cd4104228a5f476f717fcc5dd45da6738e37e8324638cb25ba8bb7bbbbb8b2a876dd956356dabd9d6188427ffeeae22da32adbb7bbbbbcb36fd8d31babbbb3b8422a59cc15fbabbbdbb63babbbb6180aeee96524a29a5bbbfe04c72e8ee5276777b77c774f428eb5f08a1494a192f8cf105f61cd21015a08573a35b4a986e5fd9a87d42b7cb5992b2c6a441bbdb5d6259367366e4b8272b0963f751b641b8aadddda5fe6ee952eef4bb9015825136085b5c24eaeecd575cb51b84da0b75b90734c2487506951342295b3564c94fe8dbdd2424babbbbf209420853b27561dc34936cb54ccb581d48960f20090da6a494524a299b6df409de5e82700559a34e1a544ab929f149dfea004b492925b6424e2561dc2da5949dbdbc94b2835fd98b524a693b25a594bd59ae45246ae1646f104aab834d09af2f3a98d95c01ba4618a9cea09b920b2184d294a2a9214b7e42cb4d09cd85b5660f3b0835134dcbc0cf4c9b948ec20d181b27a080430c91c66d2ff0257eebb44eb7cee865f472e4e747e7e747e74767f4327a39f2a363472fdca689523001c0ebac7dfbce27fba317dbc1231bc76d3f9a88db7e7e7e74ba75b24a658c8dc1992cc31ecb1eeba0a442a9549d6e1d2a54747e7e7e747e74ba75ba757e747e74462fa397233f3f3aa397d1cb911f9dd1cbe8e5c88fcee865f472e44767f4327a39f2a3d3add3add3add3ade3d8e865d6d1cbac47eafcc174462fa3971fcb2f38412bad9556e933d3b88d56d28834ba89ddcd8df4491ad12a7d9246485c4a9f5fa5d2bf1b5a699dd2bf4aa7f4ef86565abf1b5a69258da674d20849a553fa77431abdd0ca6d5a267dbab8b4bc7410ceb8b8d82e35e4b67c7cd2a8a573241bc76d9f9671dbe752fafc2a95fedddc6815a3b25239a3369d83927a51312f6e6ea8ac4ee59c53522faa7b71237dd22a7d7e2ea5cfaf52e9df0dadb47e373737b4d2faddd04aeb77237d9246b44a9fa4111297d2e757a9f4ef86565a49a3299d344252e994feddd04a2b6934a59346482a9dd2bf1b5a69258da674d20849a553fa77432bada4d1944e1a21a9744aff6e6e6e6e6ea89346a49123a1feddd04a2b6934a59346954ee9df8d0b47a0051a261d93ee8d49a7b38ab2164cbab671a216ebf23222cda051a374820d181c9b7dc10eca32d443710a7b0c240490a993d2ae76d9b0612326870d1f413bdfa7daf9543cad562b68272868e7537d9f2acaf701e001e03139bad2204ccecf87862213162b264769686808eeece4c891438500d4e895aa555fe7a860fbc5252828c8c767d3beefebe9f11d11f744a5d279a2d249c19403be9898633825ccdae6b3693e97bf5b445ccf268b7c65f4ec3cd9d979a2d251a974b20c0d05c09b310508c82365746a3232b133134bc1dfa4525c320218f9f4f40480eb41df8bd0264aef89d1fa4d22b73c8bb4b18567912a1b5c0fef7ce8090f8f8c4c15c0cc003a28688705950f0d499c1c66262cd60a333609efcc0ca045272767002c888ce0b0405364b5a221804bd5507066beec69942c4294993fc990579abb53f5996aa5c2a89496affa5f40d4c401cacc9fd87c412fa67cf129255b7756e193c6efb59baa965b7d21fe5b57bbfead1bc2438359721a55abadf46f35b9c42970663e363f9bf3aba9528eb029bd2d1e3aa30793410d95bb8428d9233f590589c3a9b584c3ad4fb7a0403408daf4a54aa056e8172948966c613d8da24b6813f9511e59c515eb555ef68a75b962b507e2b4e756dac3a71405a29811f99a2c385353944597401485427b288bf650166589615394b2f894922cdae2534a3e419950277ce2afa54b7be04c4dd19e281271222e52b9950251200a448134dac92009c41e907ca2bbfad53b29d432558e82b0f4e73b2685d87bc9d7c48c60403c7bb53ed0ad4035545a185e6b4c0e88f2d132f53fd58266a58d70ed5bbf7378b815875ab300ce47a3b80986726bfd6eadaf59e17259b12edac7f04988c6423c74eb0be1135761afbee6c278268133150e6954ab4dd4af58e58136dcad0f5f70a6fe0e765d179f2aac82a5f029fbca2d80bb5ac72e38539f5d4248006d34ad6e6d822de3eedd0444cf3dd79120d364fdaad5f8d23e058726a7398133f51f006df88a7e088fee60344deb7ef48b3a21a2ef17c2bd8bb8f99aa669a2a9bdbf48fbc6beb3e7e843c05ff49ae987bfa87bfde8e73a16e2177bf527bf3493cb8557c3b4860d8850882771225441d8abf50587cbd1ae5cf9377dcba6e477a9fc52295cfa548a04923d7c4ab9f4e1537f9488258e01675cf2638fd67c29401bbef383c0d028f5e00c1236055d3ef8440370e9d37a01195ee013fd1d30f009ab948b700f7086c6730500daf0a5f437db28f99471a4d08f46a12efad5f0095eb1dd3c536e3ffd5c544aa55fdda92cfad18f7e4c6c8a7e3534845cce5d9f410c64852c03493a3b13bcd68a9d9fb239342aaf2a5d039f6aa77d35dd13826c73add6a69ac70703bd126c8a73aaa906f6868634d618a697db452c70a67ffae4c1a5c53839fefd4156417a06f87ac23c56e2eb7bc557fce217bfaf5141e20787e217593c156854d734a1a3681fe9d2aa48581778f2a6409b29854ff4db7f850b9f7c515cdfe7f1e96b54e411a90cdd0bf00973b694b907f064b5cc0df2d28730fef5e1d5a8a9ea58fa5d1be05fbbd490ebab4ecdd5eaa6e68a9588e6aa51737e73f5cd15ed522508380f5137875aa6ff876c4abebc96524a29e512be2ee04c3f35bd5cc851a1b247f2aca03f2579be19421a632a1aad2b57e2eb15bfd8821ae5bfbdee9c4f9b501f30bac2a81414ca9d953641974c315c9ae88a16a138748543576ca2aa39c45e7cc1192454358766960d673332b3549f1a45fda12bbaa2aa39278d1691972017e7e16902ca4c8ec7e7a75c6ef7401b9756c29d6da5bfb8b3b5b8b3ade819abccd7ab4ddf5df36831b029fb8a559a49b7f834bf597ce22210e0ccfc8f53a04d0301ea8854882084f8722c54a20e1fc3934085e7d53cad66b137e74fff97a0c9c44865a581a04d5077941e6a2c5da55f0dd4418e83ecdad540fdb5ab5d0dd4400dd440edea8f3d6f577fedeacf4914e676d23ca7f840a906ba2c28a26b08dd900f4b2c2b2e7ffda08d076db8460246ca0e06029a265f48f65af7431382bdd6c5a114276936d5179529ec55a0fa65f1c68b552b7086bff6b0d34ff1b87f0f9fbce35a6dfda00c9b6a0f0f7b4f2a8ffcca539ff44cae87579edac3b2eb167bdcacea73b902551f3e71407887bd4bc4cb8d2f68239fbf9334115047ece28927bc9707672215e95dfd6a08d51d2490150e08dae4880f94021a38b7657715f65ae8c55ecfd8518b694508da6cb76316d08653a1f59aafae75cad7ed170d1c145050411bfe1e3853864dd5da1b8cbb2ded70c00d12ecbfed51025908ef9cb2bbbbbb4bb7a7742734629624ac1c9d26234a793572791999e857643efd28b502da5c016da450203ebdfc7c3a8506512af4359f7192b098b49ae4e8ecf08a524ae995128de7e5e82461f10a67d6dbe44a93193bd851c7aa38c42b1d172c63d48c0175c4213292c04f6a300c1ba2fc84320eaf28fdee9cdf952b34c610bad30817e92355d897f7e7934b7fed82362d777e5bd157b494069adf414d854f2d3fbf5f5d45d5a8193f9f8df014fdfc39e773113ee1d0f8f95a84d0a65b0a2833bbabf133b89f0433be067fcac24060c6d7f81f33baaff1ddfd20cdb9914c71a865e6d730f156c30479cc300931e2c78ca7d10999d1c154f6a29f4fe223d0862bd7c35ab1a387af8db8bb3b3e62027243bdda6326204f12b22f9dc721295c4c6ef2510c03cecc1f995c2e4d185047c4820431e0e89f8c4c3262893aa40e9085f9f30477feb4417f2fa6fee0cc74e99a87bdf9a9fe449fb9159b5df826d1632291c845afcdcd8aba96ecb5c83dc000377bd1d3e7deb91e5c96752f4222de90b458b142801f7c8a3fdf833639ee7c1a081170e7d7397f07974a3fa74f122a5d4491328589934864860ac8e0c11075a29158240b962a9ee7b56b051a8f3dafa58806635224d79d75562bee7cd904a2e47cd98236a23ba514774a2877ca265aee943aeccdc984bdd9627d7d2b24598d8a3ce6cb1635c91d99237362924824fac428a00d8c4cb2ce08367f0646c99fffc2d7cc9fef41ce3261150deb52a5295907e1ec2094a95daad63a23eb4e16c925b5d0f8351a48c3365e8cb03035e472d7027b4c2c8420b872056a8d721e2db4606384838d1fb11b55f2e0eecd03f4e07bf3a6e4f9a3a8a31208219438f3760721843142a98233ed2dc77cb011e1eede44407777778fedee2e65c38e3c02393202ec329e52c9daa8ea25d8c85cb8943add55a44e64ed00556179d7dd192b08964e1162c9baa453c6a6a2c7db8ba6f81f495608dbf26c8895a7f52a02cf0a9e973de1c952c023448b9192f5960987fcf832cac601a58a7d5a5afd24f6628c5b7d00dfee6e1b2c1c5704f4b22e5fb6df803147b029b9135119938c0546c6ea8e4c45fce1b24d2cf400072a1eddc1fce8c91bd76ab78881e208202892bc2ecc8f7ef903450c543cfa87f030c28dff81a823def81e8dcf08aa01c6162a1e90eb614337a109971444450a06818a1decc52a420e06164e8440c4144c9cd800c70c6ccb853e4e9864e144e7c6090a7068a1c4124a344cd06674d9dd5ca2feeeef3d4beeeedddd34ee2e2784dd10e607e5419faf12da0921010fd832f0575aec6e686fd0288cee60de708607bfc04d503531a89c70bbbbbb3b084b04b10229404438e1d162dc9642662db0a9f7dbee8e85cbe5e78680107eb2c0c245173808c208b7bf85ee6e958d5054921851aac0326484d7111dc60f537477d7e802bbed20f1a978c4f7a212ad515541c99520c2802a38429c800160f07089255f5092c1cd914b2afd853e3e18a1d961480e2768ad6c3005055830a90287e0174fa02c09c2810fc018028c22533c64e20a1454b820079592a022089195485890be064c030ca24042900f389c0087fec227e31f7ee0018c5719485c542cd12f1da68c01c51346907165065e38b1f0a788ece4b3b7d861082c7618021052486922b0a8097cecb0f00b6ac2698a13229a1861c7ca0fba0b2e9204922a81a092c40b2adb2551564b7450224a1742c00195245840970c396289244c9080051026f8e1228913b4b04724b89c5c02c15c8c78481046f0f0426284942b5c3084204836c23e57dcfc800b1940c111daa2090f2a330b5e0364bc9ec82204248220450735a1a236616b65245868f28493900c29ae218e00c5ca0d8f109a30219997307c1de105173260c242c2154168c282162316fe34e9017bc630acab10562b3bc843d6d84d40c8420588a083650a1f2499c112405002a9073665b9099a6922b1178f38811358c8a8010dc228a2a7dc405e2572802c9f248090041537653f8abb0f5d3792c30d0db2900208238cf40f8650e3babb3bf763a1e56ebec2dd9d5960a18afe217c052c7d401b29a53c4205603cb9a2ca22c8071f3d824dd5aed0a67907070f095003113f3f0c60a58980931fb8e841c90fab1568214416f3ae27e0900f434be4e0a5a3e30350112e0953441aef22374711543db8e921c9122b78780fae3bbd3e0409091e458331b545099b62e1fab35092800663522dc298c42073593a9a8dcf725cc7b54e4c92459cd5cdb8c54e988783b80aa3e0163dfc6487a3b08b81980af7ec2479805fee3597d26c45cf9e1b07c3712a224764b999dfec230e3cb223b0dceca1cececd54990a0920b28873b3e762f3d0cd3e6b1edc6c323f6b75d34cf4b555cb641b6b184cff90db5dea0a9be2d6cecd3e3eb7fa33d1679a0986fb2197eb52918db097310e7bd9bbac92d5f31075bcea8c89b007afe47a70dcabd8cb9ea4848d5ac0eca39665d91640fcf267594099ec8170b32e6ef6358c9b7d86e566af75a9146e06bb28650614d973e69f65cf3c580f9f349f8fa3441df066affdf69ac6711ab741ae3feb3ad0aa162034e979313ee112e7b08c7c51575b464a1b4bb098c6ac31db28c3ee7801061ffef27fc0f8431b56b82d725b8c0feb128b7de4b6982432a922648487a6759565b12e1593dca8137772a0052c84e2050e142f5657fe0b8c8a3c20142a3b5742d900199390d82716890f7bb0d440d4065846fe0e96915f5db03ea5285fece9b6a2478a5addbb943da2e7eab8d0c788d5d5c1a6aaa5a1f1bce7ae31d5c0999e9b1376e353b709655ad4409b78bb9bdbbb695208e84db483f521832632c1bb8313992a7ba297bf03860eb2c775cede2683a4293d56ad163b6d4addec940f6f9683bd9c8fb5f83479a24677f4a8989999995905275276cb26a4d854e94b5e5d4a29da81fa4f7a834ff4fd4b73be53e9d3a794fe03d7f66f67e61fa2c11808eb1536552ad5d85b8d6807ebf149c25be213d7d2cb6e07b75c28465072211743cb1dd260cce8ad8d4f01f78f1189622cc3a6fac67597ab09cb7f833d1a178521c6e71e7c1481363d401dbc02237c03842b4a2fb282a843f670b30217103912e7c675f7a7269a76bd4c10d556b4ebe3b7eb69d7412df3a3023ed873bf21771c4b0dba2e12f996041b5fe39a8c742cbca9c7225723af264d2d17723e88c0b62de34b8033fed2e47277401bfafe310bb45902d4c14476b8ee40e29d2e8d10893a241090057f97415c3735109c7157d71f7bfe32e4b58c370fff68a18dbfd7a80ab840d48532ded27aeda4330eafd8f377a01ab443c5b972e50ab65af11057451aa757bdea557ffcf180f18b40415746e9f1f97a64cfaa87bfcf07dac828721075d4fa848707888a382b68339968b596b08eec0891e3c32af67c1fce87f3e17c381f0e6761cfc7a3c8c193db3c2b38d3cd434b8c25af23414200f9e052f1107b2f4352c61e2158fe54af561507c3696eceab0f50a62587c103dae0e434abbbf545717df18b2e76b107c49e4781365338155107fdb6ddc327ef7e8287a7496b09eb7677370e77d76a6da994e200dc5424c25e47f129e00c1591856e9f1ec68133ed034f129a2c791d091262a562af5fb2d8d4e6de38ee6282158c853f76f1107f71276f7167abe6ccb0396793566b4e6ecd39a598f38333b3359d70cb0ab79cf0c7dfc71f0462207ccce9b9084d31a3e7ce8a6593a74b039a3f8fcc9dd9e4ce2537003d53f6d46cca2f02de7500f6fc406ba50fbf524ae9c35b6b1696bfd66ca21d6cc9cbe86359cd9ed2c7b24a318ad54a13b3698f91d8c330ac7ef6a95a79603dcb32d10eb6e455acb297fdf615c3b60cd3302dcb600cd67580e609cbdd7d060eac7777373b19fe9918dec8e4dd8527ee2f5b2e69646141241c0ad2a8c862ed780db4f1e6621777d80bd2a83a34df2dd6c59d9c1ca7dd955a86eb11737a3ac1fac862d27ac2a79ef86598a9729db1238db55a3b592de33d1805d674636b5e9a5daaa412c29e072109616de58bcdce65978aab9ba201065dff56640d613fe772076be00c15cb9faa2e910f7876a46c677797dc524a29a594ef52be94524a296f60fda54bcf8b6850fb011422e85c98e56ab4bac02822396cbfc3f3d85e052796eb31956c38d9967dc6f5e08e94eb1169d4342d723db0af26786b85a9f56bf6d534c3064c34b00c65d87efa55eb60304cc4c1006fed60ead7fed917e07ad0ee077bde26f7f7c127e86307d3dfd1b5966ab46caba9a9e1b11bb8a9eeeecdf3c8a3e28d4d1fb9285ac2a6ac076933f009de1858acc6851d3bd88b2eb87f199dd7a8b21674655282ec79676262b78a8595ff36547052ba011d4e6fd9d21d07426f5a80ad815d007fcc41e396ce2f4d36c446b90d2a5d19379691953df9339e587fcddde3c69eacec49fff8ed31c6969dbb8f9cb0fceeeeee52d4c019efae420316fa30e1bad087891e9a0b7d98c0b95a0bb5ddc1ea51d3ba51088032feee3ea306b6bd183d57ca83412bad49f096d8ab1d1cf558faf3629faa358a75f6eac367ec2b1616eb207b35db0eb6742b7bdad7ec53376ecd3ef5b76618d6b116b7e6876f44839a0facb317611800a91c72a129c26f7f6a1a722334a522cf8db0bbf908e7d8532ac10541e8d8982358540b345bad43f40e181a55034d73df2d32954cb665ba87ec615f63966559d6f66299571a875c3afd77b4f4ee8e5f618f0368da924ad6e5bdc69a6ccb78f7a22e6edb6b730b7263ea0606c03bbbed2bd7daad42cb729b699a38532a7ecd1eeee02157cb6ab5d1c29f194b22da7b3425082124e9606d4c7f3961ed640ffa97cef931a63b720c80974aae47646e2663474ec965b921087bf231ccc5650994912d5deab56982f187773a94ef5c8f968f4be0a95fbe7caaa26002ec0e96d97efb9e8d884d41212d8884db026ee86a10c29e84ab2ec59fc1cb2213107953910524de20afd3b4d0a81a646b816300bc94bb1f72db943255155ad4b1d7fa7774168362a783ed74b0fe9a53f1b979110465b8901b18573e4b0a210d7bb2863d296b825aa49962eb097b7f99bd1814833a28764141b38370a6bbd8622f3e614f46155ab6c6ed875c0c356e74d2a381f8666a164b1b9161bbbbbb03c2d6b8d06709a0ebef2eb470dd9da56d250410e04299ea224db0e746ceb5f8caa1a1f1bc0f7ac2a6604f90cf123e57be03f8028c823ca85cf934352ab4ec3ba3462fdff28913f0f2a9155c3e45ba297b65ea061556a3461d6c99972fb9946ccbc8954d55dea971a3b14b19618c31aef0971d3aa1c11877f70eb83455f69899ff7ae73d285fa803c80dd5a1169f4d374420f161608cd786116cea69e2cf5fa1053ed95082cb3fe7c77832d026fbf933d006fbf9357c62930df10e513d717d967072e797ecd3c0e7ce8fa1997f834f28dcf97075278f29bafc40ecad1d4c0ca2cb2fbafc295c18ece1ed000cd6352001971fc88e5b3967af0bae814f740a892a0df3ad089b82421127fbb8d5906559f614429899da44678c1833ecb0a71fa5acd873c79199233316dfb12c7b2df3cc33cf9cf498c9868e5c8f28c48a42426a0812a9c4d70d3048063eb116b31b66f81142086117a3297bae2e61071942860c533490628c94d6c0a72cfe74eaa6e88a5280d88b1d35d1306760cfa50c0bef297e8481e6e253a9a6086c2c55e0b31466970b173e95532a155ba584e56649d1dc9a2e72f9532e3491183be9fac107a8234216a2f46f68336b5c6a6a950f9f5234e0f049ce9cba693b9e8506511ee3e37da3471063c5f2a7dc9a547062fb21978111194d2043e84776e0856b075e7cd73f466154e4e13b7082c8f5cf5f9b0c349674a2f04e0c932af63caaaefb53d30d41d8f306c8dbdf9d1028b441159c5858e572120dc6fc604f63933fb39b2c7b3075032764f977749b68d8e4ed6e13e570a38d91a52d0046512245bb308a922f8ea1e530410e1da816e37b2bd3604b0b8661a0628fc9fe5819cac88f22b8fdb132f4fa63cd328aa4d22e625d8aafa45a4691cc39e79419b8edb30caf51ac1aeb035c7e89033c15007a8c802eae7a76c0f3b1c737d80c82a75192e7e3d35ced009e660a78781a95790165f8598ccb3f57dd9faab5c2cc95ca64f8bbea686b702e06cbdb5cc58e73c5938bc16f9c371055671097bfd223754863b58fd8082302e60a853b578d2a95ac9dff2d385cfeccd5a2ca5cdc1176ae23341893d256d0c69f7ecd3ed629c3027a0c5fee342aebe1019e32177b9c8901a14cd6d3a80c287bb187053c6560402f036a94ac02f6e032d06d69a1ff49579499ad2fac360af2c85e7c923c19e73958e71103a2602a4bc2739b7bcf1e3e88d46e5ebac5a046c82256008e8bbde00c17c16a730a8410ba8416bae4e1c2a189a8140c1b2b7ac9d0d000000023160000180c0a864482812408c238dfe40314000d719c4664522c1a0883410ee32808c220640c30840002806106d0ccd4b0246e0d20652ba8f095c1d1a3ec35fc89e1759822a8b81ad8903a06f03b78734c089949820bdbd4deefacb93cb3da812aefe34c918a670ec0a46f9cf48545754dd2eaaec0fb4b17a00d0099ec8aa7af300b6758e93f868ebf541ba6ae9c661ded331dad80c4d80e50d23cda86ff3982c21fff96d1156d0b8823fbf7d89e5892c66089668cb1467ba5ebbcf9cafed965745d4da7e6dcbaaa4f4bf9adee8f73692161f0ccc7c4fd1efc0525060b7c2eb423dd38ce969411786a8fd6b0e470ecb9467c6d6ff63fcdde623196ef75dee4525c94fe27ceac182c3ffa17142e3d0779754a65157bf236c9cd5115af12bdcb7d95bdcdcb298ccf3cf0637d9e6357f5887176284ab6a4aac15ad1c2ac389fb30d97215231a145c21485e5ff41de83116d2b6cf39b1c76aee4dbb887ef610308a9ed76c70bda1f9008c8ed931e0b5b9c75cd26e123c35c6483b85e30d21b35e4ab875f91ef1ab923dfcba2ca28883df317e3833fdb4ebf877fa973b22718ea047da7ad73451d7e26ca78a152b3476d9f527f863dd669b458ca942cca94aece4212c377b051bebd183ae52ec3cfcc1d586e88c8218d4357a07405cf1909a500b1ea20835c3e1a6d49e51e984019f12809566990a2c9e6073fd7066fa4401111e80927887f857142a9fc9d8ae14a05401c67ee1ce4da9267f9d416c5fcb6950b600ef928e83ed3213ed3de9eb32410a73c31c635ba56b95518f5a4b4a6a2fdea973009c1c6fa8664a18d394c3357f58fcd8d693938f20f96688e8c5e421b8dd2cf15d879e918f390f8eaa4def9670139a9b0d0225c53b7973cc4fbea0d859c5629eb1c1e9de71831fab0b85d4d9b9cb60ed30323f4197981442a1eaa8a478cf6316a300edd917840c740830d21115360d557664f873c11850917a70dc455d267e8efe75aa00693d08f2853ccfdbb8353d503dc74b715ac46ece0eddb9c131a09c65ac3cf5728ab5d42047988c499bd9d7852f20d23c6f5b2bf7cbc26b26b43f9cdadde78fde7955b73c720b3afb1a6eede153726f25973baaff72aa7c4aa3047c1ec553294105f25ce489707555ab535d5ac9f8bf8bb9cceb950395358a70d30a2d374ca3212a787117ebc13b8b2330a3a51c8ec16c1e9670b18f6a84bcde71dcb4bf3db7eeac791d5f095be30ac6885a9052bc81cae397811fca7ba03b4047ff0741024424e3efa18230e626614d8cd07c8b68841a30f28f5e415d1fe265d96bc31b2a6860fe148d52efa7623e2255d2809dda28f801389cd1d626dc7803fb270279045fa24c70b7a3cde8a93a25be5b48fbe3251e96bd31196595c286e753157d023b2468d648656c454fc144dcbe8bf6e53da7b3e835d03b5ca568bdbda3702bc15c0b11d7ca3b189c51a4cd80bb505091070bb57800272b38d7b0d2073b0502aa62f3595643a0f3e6d3b753fd16d4aae3dcfa18554f9a9f8600170619b49bc27586bc5f1145aad4dceb6806a233488e94033b81ee5fd27f2db754bac394c32aac4eac06941337aa9667b63070adc674a931b6217bfff1033a0bc01982860640c547a4d360ad0f061025d07f79cf4563f0a8ced79547cb0e43701b3679e80fa5f077414713b710934fc2f8b3092de4a74df27d20676fd43b83060ce6d386b4629932544d209c8db3b7202012b89fbe9336cb02d1d696b9e3b3dc837cbea921d04ab7f72ad06ce152b0b826cabf8f25d9d1c0da2e3a367f169dcf86eccd057c6079bfd131df694509e6faf895287be9d1f3d574400acad06997b02bbb6148174236fc861568da06eb32bd5c6cad4e57624a3764a3d224557b1210e4a7db9cfb6c9f8bd8e8c95faefc67fbdb2bf557ad0b3e87633e11df661d7ed5ee28e3262ce1f754afe4f23659e6090403322a23b6d56da16b151d92f9755bc5d8cc85a011cdb30404a3ce2f9e0bb84a279d5ef3bb215ddf038a6b7d90e13a375c29953d2adefde4c2c967147a1559651de09b9ac0f34a5e284c999219ea1b7fe1793a56b05e4d2064472b787bdaf0580a0cf525dec59dae74a70632dcbc9bc65aaa582a402a2c72e45a6941bb236cc58138c184a9ccffae354e468893faa15ccc1f56159f743419c9794c229b799e64f5b1b4e7aa0353b3b273a3794f2dd0bd254838bc735650957568a64e6dedda5cac4fef9fc8ead274cb022d57303644be6aa8d3b85082733446334f6afe903c853df2e365bc3f83a20ab51b0bb50eb93af286e85d6e9a23bb5560d6ab4b31b3e75efdd9e31d80ede9299ec00c7085368a54e85760f64d901175814124640bdd2f20f88b97f60319307202d1735696ddb0f0b432a9ed22837d86b015a9e318413c68af13ff3c37d72c776a0511eab2a5a6a4e869163800ff3475f5f32945be249c5a1b88478d288448b403c2afd9274627a233443c54fca1f9c98b1c11c1199c69c72b407d87f691610d821ddd3b694b5a9968e2d72851fc959abbe7a820903f61c92b9bbf3ec051a1d0ddee799b26f9f9491d09c06aee1c0cdf1ea2a537463faaaa647184660b21d344b55b05043d2fa8ea53374b28aafc977d4688653c8351afaf8d66073b228496fceba61d5519d3271035af63a8958a8862a060ad323a6000f170d853ddfa127feb039d1f55b904728d7fdb31b5ec0514db3ed3d76ad780d761349eee99019c43f799045b54622d3ff798532547eab0e2acea29ddca09748b7ac6861d1a37539894071157275a229cd64d0cf0312d1900d0e7b9e73230c56a6354876579489f38095870d73f815e9a16349c0206883f6ac6b3c746755e6fb7f1d85952ceb559d2a1bbe4020c6f157c771eccfae293802c6202b62d24a19cf192721c46e21ee6783c4d565f242681627f8b7fe1e0fee8755918e9b0c72ca77f8b03f4d69831ef535d30ac5025912e885591ac5e68e0a67dd053f72fce759b99428cbe144a62e55d8b794d098c32cb54254001152c0ce10855dcdec7a4770dd32971efc35971d7bd4d8bc63ad4d79026c737b31011cfd5577b78241779b3f01418a4770c36befd3766f5acc217ff8b9adb0d5e9e01e8bd3cc2979a7036da02f6ba29e8512e4f802f82c04de0e4ca85b362324ad88228972fc8c015d796b9a89cef0e2743800605008bb3fc0cd186bf317b0dc1c31b2c20d2d1a04991b84fafe12b38cf84dd11998485686d457184a4430221886aaca718a3a5ffcd37ee18eed5b053348481ba1bed21800916a4450f8a80aebaa202056f5ec4d44a91b80270367425b91afb47d20fa37f3aa79f4087104c62a4f67917ed7a20b230402e9ba1d30c13bf968fcea4b9519692b0c8a2bc7e3faad8309380e031f4748c31a0e61ed2c3e4975517da771fe309a43c819f6681bafc0ec012940b8ee472b0eae2b8f88f9d39189912d749c31958636a9f4e9a45fede6aaf039090355a31e8a305b6055afcba3e755a5592d929648a969d6aa79d193ac16dc7c47bfd802b334525d254fbf4da5373a3656f6e5e1213de3deccc115bbf7fdf575d93e78f87c0d9dfe4288c76b7b21446103f203e638bb28926518716968647484edd651b97ab6a35a5724619d7f9b8530677c469f1c373adc2643f9e02d2ff74b2aaba5c7a8ac62d70a08a824ca0f376417d75720fad6f12f037e15c7f09ba1d923f5866f6afc1108adcf89e66adb75c589b35359d3e4c7262dab1681c8ae7d468dcf694b730ce99c1df7334e121471a2c5fd8f098d42ef3f3752b8e170f4c9daa82dd9d2cb22e7e4de0ecc064c69c3a5e752ec2c57c9baf2c036bcaea7e53aa6fd80e98dbc54103249c9c8823def52fb767f328ec083d58dff86c22521cdff813585fa2db70323105fb1e48a04e307bc9a8865ca514058146ba4c7e9ab4586c48899b3bb23415a347496f223f211ed47140632f25b2a0fdd9f1bd7c2c5b4c71a4baad1e5fafa4592271e21e30bb2860b2a3cf8546754ca0eda754ad08d2cdbcb55526a513907b04f582840f0d5e73cfa6f08faafa958470489c507711144acfa6651229ae8d4610a57cb6a3419de5d2bc52daa20fa08f42d87a86edf1961c83715f755b76085c75a1f159bf239d5be7b771ceaa8f8a6544a7ae65dd97adb34483c1c7380160af42853789557641960355edbca298161caa082bd9ca4b541e1cfbbf08db73c1c28cff51308f0c9ba56025494adafb008fb78e9b959cf639a06db03a8c83c8cd6bfbaf02809153929608b10fe128fab9586ff31c24be0c62cd84f5555cf2645856fdd5990ecd7fe63e63101922354ff844880d6385cc103cc3aed05d3c74c8f0e9c5515d4988904915f454de2cda5420a71ee8bd2d09da5534677f6be4fda7064ccfc101a7194970c9b3d55459e579e3415324909ab1b073e4a6206ef3809b795b4bb6672c6778c6491250e858e1c3410191a029a413c6f3a16093e0fd0296bedeeec4a720bd85d8ec6cda8d0c2b0d01d598b4d9679a175d0cb6415fcae4b20a760759b222f3699b43256c4e9b4e4592bd040605b8b2e3d3d957836674b7a63f5322aeac72014e6ab7eee11abca7feeb12b85f0ab0090cff285b5c0cd56d107b54982532193bd7d98c8afa3414ec222bb06d97d06b4d8e0699e46816dd802224ac4cef9e6920d3878f864d4f96c1d0ee2f7c8a814ee0919df363e493326e252006ae46c7561d1e43174b8a01df804e25e46ae4d4c9fc166ec854c652d0d7ef322572335e3cebc781fad0a9595b8fb970a35c5c1a3c79bcdf0e1fc1460ced2bb6a0283b19110be25070931a42fb6bd2c5e3ad43ca2024dfac5e4c24907d9b367c97787e73a6719ff52dd49b33f9c41bef8c4a67944de9419def43cac50c0447894d6af78b13c75a5c92f73b37562f4fc28b449769760489c231429103ca75d5af67560d0753dabce4669c9561a3c2e5737debc072e361610fbe000a5906a9e046047356cd8725433497991e037d52e41ffe103a8c970bc83083c261f35ee18482765402ca377d1da19d5c7f2b28014f6f8937ae59e3b14d09037b3774a22c706ac7fd993f784821f6a1ba202b925894baeccff7f22b31440d8cbd6aa2c734cd698483d94c583ae608bac5b50823d669574ac90a39ae346b674d3257e090c41b82f1d0f23fb8161f48807b4f2de6173d28d6241dacb47e2ef2622b707a1070fc80cb0d40703dc407096dc79d5e24803814b7643988a2536dc4af370cad372e45ab5292a50a791a1f0211ef29dabd3b411ce2e1ad8baafa17a2545d18aa46c615a3bcb2929d532b9f151897672fdb5a47d4bc83654963760c58ea5827ac6b64455ee07bb7ec15804cd0116d4bd04344b51c957be825a0e526de6d3cc2c33b41555c561b3f6d9c718356b747055a1051f8a6b8ddad6cc17841be88733fa3348fb19c944d14b37aa3fd4248dcd720cca2396822862fcf411092e6aa16329f40996054ce04009142eb6fb9c0fa2167e08ac99c19a0fa661ac1479ea020833f252508769c12fc08db31359863b831c8aac352a83c094d43938aec054a342e3d9fa8beed2799946178f06e1c631e84bcb24b136adaca8752ff1b70a8ba4cc89eb527194f13635091da168b4503359818999f2ed386e797ce48d723b0ffda9983cd5457aa7eba6919da211eeee64a2feb60fd1c9eb7903d198a47f62b8498d7c84836efe3d25a4262a8be342899088a6109c99f43394e383b84f242ebe09199ea861132177cb0fe5f70636b510cc25250542885399226d4662ee6d7010b274327772b3982702faadb8e60e1ab13c25b886948f851ddb35244f51e6eefc03fb6d62310e149747b504d8ecfa3e219edde48e140ede814e884f2fc0cb450265d28260b30b06088c4be5441891172d2455e04be6146643d1067f49d5760046ffb0f762fe10e6d7e04a82c0b0d2cafe0db6684ede95e849ef0aab1b9fec73f45cd5465785cc3ff6065c69efc2aca537ff6ad495a24e6495509b30d2268f0f136d5418c4edd6cd5ec19ad702b660729684cdb81097b6733c17a6df4073261b134e38436113d6979e738462f825e7172e4fbabb9403992321812a2e270e45a3c2f01e27d7227f039ccb18f745512fec8417f2c4fc48f44679b607a0e66ac8e5b766f7dea92f44546d42f63af7bce65080d2f4eaaa33a7fc8d73eceaa502ef4c44a61f2384f1225c909e7310436e1ffe06962ec2d23564db89bda2254b548b74fba279b0ea02f4e1a6a7059881669c19ffadb4b8881229271d3e41bea1741941203745a384821df442b0516902403c444a4422bf5d4aa23c4e69af363f21bcb9c1c5ede8d8e73477168871968239259369150b47b2e851db6d10d84a75488bb7047f9ea54663ac65a0ee8fa9a130da26f2de11b60c70bdfe5055fc992388120d3f45b4d4d6b0d9611c03d788339e24063ce2e669dba48c4df430941f3f05e47928c43d2dc95e231e05d28b54062f510759089a58c2fc387a87d56a9933b2a03e5d2efa18acc3271b65c41fe7fbfcc696a3d8dac67bfd6d5146d81fdaeb48e28b81a596a28d7dce43935448c1f1fcc9dde4f730b267dab1e8148b25681bef54f67dff7757be4976079cacaca5edfb6a7a897fbf8e4d6ca7a792c590d382cb75db213c4f1393c50a1b1b62da169d7367403a2d226347ef987b9ecd209d66e9603d1605591ed0bfa291651735034cdbc331d7cda059197a254edf47e8c4be922c5fb853194a47a73369714b66f82dc8ea536eef849256ae37314b8d21702c122dc61e00db0c32cf9e9e09af12dde2605254fda86fd079a060a57521f8de54ac21d479407ffd4eca1709118c998b0b98a5d993b87f4941325582c33bd4c72efa2b7bc07a885d2c3c60260f5b514a22f012e0093eb8dca067ccc9ee6250865633d931d7cbf8b3057913e0e76f546296924c6138df0c70fce37c376f60ec7d7781c04d1ee4c5bdba76b6d40968052ac3ffd0fd655db8567c93331ec89a659a01b35768773b1c5a99930a0ba3995209ac944c4869d60d82da85127de3fed53efa5002c0927bc6e24c4e2c61268312068af8c50f8c29f0a1d6693768a0ca9c1f8986faf23aa601b7c180773890809931206e5686f3a12a0d3182910413ccf2c7451e4b256a5880b9c7505bcce3ddaf079a80df2125d8f6887a1ee429e20de3d09c51aa992a00ca9adb5f611715652d732dba67b481d701b1850f13d3306e8114f8f4acff9734a25a4efd41340741570c02e39ff50f3979a92b40f3749611dd54f507cbcb5922c5af087d96780a6679da15f8ac0abbfe115706d6614bbc9d49d45099c4a6936b4427ef1369e6f841284be4c3653811a4a5d2c48a36e0168f40951834a1c240c3a09dcf0a039ef5be46c0d2a48710e7ed404f0c60fd9d59248491b2fb9341c4205f5244bcdff7abc80c3d5172974594b0ac8ba341b90b02fd4b524f433f5b18f7e76612fcd4d82d0294aaa36e4ebefdee6396f65b2062169a6c9240b7aa7df59d2796c9e21624e4301428aba44829cb4dd67a424af9c4f5784ae265ba79466a4c8fab508cb978251dc373effc3a79ef4a64f65a54ad7ba9ee4884277b0fb8863db415e135c54602d2bcc4593406e0c147dd565bfe74835893d652295fa1f301be604a2f3543a27aa479a1641ea699cb65d31b5c66eb32bb89ace7373591da38fa8e07e5a4d48b548b2df97bf2bc8e0f0bf397182f14386c59b28400ed3b431a465cd673880e3dc87db17d4fd4962b3e1433bb86ce212ce1b644e2a96e5c13aa0ba8f826343d0cb7f2eb1b5e71c63dbe9ab027412e31e2b8c61be798b200df993a31c4707ccac01cef07aad7febc0ed3c459c4df5178d9604f06b764204e6797483539454179977400c6871c1e19ca01ac643ef2d99c5851898c428a47e6122c95ebc4c2ed0c847b56f4991039cecdbe7435f0c3ebddcbe1e8a410c4b6d9574cf4c3f4731cdf706f3350414d5066c86ff082328c77263200e4213c1264a5bdb9d397dc4a002f8f1c562c7a18cc925818241f0e0a09f848a8ff537f1522807ac66e50b1e0a2d5666ae9220ee07d61c5e40fd30265222ee5bce4a14d54d564ad4edcb2304be909cba1db202c4c1b2ef876e70289f8b0c4567257b1567340ea7e2039e5e81c17f3876c2b98c99fd46201a54ac678c2fbf133c329d9eb91bea6317ce87e384c83b3663b712eaace87cbd2c10f169772ba49a024078785c9b1773ce67fd86243e91b619329b6e0da966a8304fec5c77787c22e5cd4401c5beec740f0e9da8a7ef17aa2844602801f52c7498d77cc8f234a8b5390ae0475b7c75baa882c08e1dbbb78edefcaae029bdc69409c8cf52f00c3842b2052c7b7903e8888e83ce8120d11fe6236a232acb9f2f860085a8aa647a3301fadbdec035d47382a919c293630020227abf2df75cd38f02a0541dd341136277b269bbf70718cbfa6e2a827db3bc6bc9ac3c310249401a8d0667b4578bc4a98db2a7bcf890c1536805e2aaf8787eb77bba45c15b6df3fb8c08fb439bca3657f8cab7cf182061cad8f8d89a502d7d43a7c53d2b5625dd6a8782ed85e3e31544507223f658d6c334c5df62c5369c38577b39616fd93ad17184714abc2616e3497e7a459041a2a747075ad01f508a2d18f480a363f07fc7eb3d76362720b271ea70db8d95b767e6fdf0a28dce69ceffdae8d41ecbc050e68ca2900e14a42b466bef941c8b1304bf709b12fedcae1c0fd311375bf00942f24aba9b4706d2bfa263f1fe1beffdfb53503afffb6a1258fc9137c412efa112a037692cc39ec1fd0f48f5978265a547309c0aef7e55c1a44047da451e9b27d4b521be3ce2c0ce575bf243e589412b19308d587f59dfdc700eb0a76ddb2d029a0820a4cbbdf31f71d952166fd575c0973a953bbd216e00428474fb960d6312bf6f2a8946e6ca823cc3eca31fb3d161f16cedb512136e9e43e5ae8c9883f396b5f8b10445ab628617e5f5b1aa23af1f5fdcc4bbb842773e3e469b3e26fd461a8e51a44218e93b1408ec4b1d14a0ab88df9c73db1b66b2ce4e0b4372d423d59316760e5d880230b099dffa45151a5b411e6608eec9aec038b07341ca67f5da6590a73971591aa25ecdf9f93d896fd3d56ee88b8fb9797c1b4cd3c772bfc4d8e148b9dfe25c30b950ac2837c652003348941dfa312fdc2453b68d129159cc7979cd8420e3b562dc14e28314bb9ae28e62003eea1892968ed2401b211d427decad48f00e72e8078844816869330e8c5b3306702aa16bde6e2baab80709ec2b8d2d45f97c2b8b2b815e7635fd5412ebf760f6e958585789da424b2e5339ed6956c62c7b7c582d7e0115f76c930d54ec9c1992c2e0a6605b79ffadfc85fe101beccdffcadac593de44889aeeec0f38edeb8d1838649820e6b481ea5d17c8394ffd78d2cb217f1ac8143b1877f379b0217d6c491473b35347fc8e9e1fcd7ad5e86d63f796083e99cea36bb88ba878e8fdb1d6b7a626474c356ef545d43c378b416fd4d0a7452de79fd90628219465b9597644da8c5d3212219c35bcef42d3bec974aa51e5da9d01ececb742dce019e41be78180334fbb63f2cbd729aebd67488ebbef95ef121bec1aa3ec76c21e23a053e10f3599e2ab4ce8360e31500dfe2c4f114099e902ab55fc81c990025a7f8cb98ac12b821e028c1abaf024d440e1021069d901017b9aea09dc2da159fb1aa1035f597a81bd313d201cea5443bdf38731a1e5de2681325c8de6681d93bd6ae01f751f5a45eae76ec6ce6bbcc33af52a634115ee4ed244b46c958120e09067172e18e708a95d48c433cf3f5afd09964b1fd770208226358c8d80d2e96cea0acf142879197361030e120d57b7195c0dcffe4591ba5cf09a914fc8e0b59c92540e7bfebd7bf8e3945bd34f9f038264314dd0e7402a1e1720788653b1dba7cbbaafcd96f0ce966ebb5b85937ca758fb28cb1cd2086d3c1cfddc1228816a5224e440ca53c680a9ca1b33a432f66ef7dda282c7baa678d3d44301912925eb57835eb3037da630898bcdfc5afffbcc32576cea87868dbf787ba335f4be2f21ffcc3dfba8608c9e22fc1c71c70846039322f54f09ec622e5f5d895020075d7ec04881c2af15b1059fa9604aa45a1a0cc48ff6576ce1099fcbcba394b722283f490c5967f092964ce1ad28d06a2a2436116d50bd25b4192eac568cbf21968f1a90a7c385bf353d5f5a63b4eb9c77a0f071c08dc4bf8f1ffebf77b3e83c442de1ac9422d71dfa5359e9f39b259540dbae871ff152f53b0a882d3465f40cc8fa94ca5a9bcf71784ffc4ec276806cb9c44027fa05a180900c682aecea3369ee27df1f5c5febb0c02ffb7dbfbeed825cb85c040e41bad7d92d53be038083df7270feefe14eec98118c615142b07f661c8255ae7531d0ebcc6ea172abdd41cbddf4c950739c2d7f959cb1d8cd6c8cb948051460b6de3fd2c4bc786827d6531654b1987fcb1449704cf954a739ee193e043616f472e657c789298d1441388114db6506f80132d80bccdde6b636249be29ea2b36e0b1119dfb3bc842f8e1e213ace37ac2fbf00b31fc097f9ef832716357de6759ee919886cf3bc2e70f15936e18c4c917b26fbc1d66cab8f7aaba25058542fabd1c278f404bf2c698da31d9958e626855c3b68ccb4dea9c958714fb3ff859939034ffa4f8711e4d1c02152beb49e2c98fd1187ca96bce8e1ff00229969670ea2b831087c26414e7405b43b9e4741d5f88ce12a62e41f89aa96d1a33d6194db75f3875e9416e336f2c657bc464999f39e545de247f7a055a783bfb525e3c90b4f4bf8577151ed49f3322f52228b109dc271ad865e3efbc8a83c438367f07092e545be64b62ad9e1f234c8a98ca5c48af69787955302f0d2222d4c367d9a03c746dc602244a3fc51d3366089cc8760b8539885ed1380fd7cb1a35f39ba010bf00ccf4e097e0eeca98e6313712826d2b1696777d0141b4842fe3567d3e5ac61b526b64d2073a5a866850bc1ab5903c1f839de92c88535ffc987bfeee7f2f964f5f41a1ee83ddd7a9d8dc85db6224863d412007d38fa151b3282b2a443595685a6dd4b9cf85b5268231f8c40ceedb048591267f26c138db016f55ee8adc00153f0889aa5b7dedbcdd4a928b4309b9d82b7c5cc75ae1282fbef4c1e505bd43bdaafa98086fddf49904a66bf47b44d711ec3436eaa75a738571ec703e561bed207580857451e77ee96ac895fc5bd317af37f44e54f7688ee5cc0533c9d3e57bd4b849f7c83b432d81382e7b505551e37df678f81a077f7aa17117880ec70fbc4318e6e83e0fd1bcc8e252d0142f2f6331907190c25c6e220e03c02fbb42cd1cd245d5b55b6db46d351eca715bcc81790e4f76cc246ae6529d45518a42d1d7854edbb12303db3100fb716f0487dbd7b6c443c9e8eb2054b7fab6d88fb091f1fe914445b83f158216704ab45d8012ab205c71f6c954684a6264da54e36edf8a657a60d956f084e04eb6ad89e2c036ae899a72afbde7e0ccc35ae97f128d2d0ba4f23ccc022092a28f0f1e1320491c5ac40adc1a7492c5d42c3a5c892b86b3740ffd90aaf56b944b9f11d5bb175b5c904450f08c3ee3f4967ebe65952c0cbdc4b62dd6a33b2396d70549abad1ea38d886b04e6430fef4b55fc780ced22afdff5a20ca6b48301ad063c622418c873fd0e0e3d497cf9a3c837ae3c20da7d3a1bea9cb4f4814c04c17ebe3611b1b9b4a6c2d6b77c260f0887385975e7e498a378930b4e2e1a8c94280313b5d88824c824d061be8232928f89575a16d9bf9f779fa7ab166caa198fa60184bfb26d761dfaccd3956d93ad36e5d659825080ab037faf16239e6886bc010f6b08831aa24076457a4123d703b5a4f70029e1d8c6ba21d0909287632ad2224c5d6be4bd2c8abd82d2b7a1fe0c37e00bca21e7c0d17ba0ac0e2a9d3471157fef448d4200809e0da8fdbed84f5f2df474abc8f728c0ce9cb576e6f9afe79abc3d63636e85bc696ac80c69579a55254d6a9d69f04b4b9d59b63e3aa7a308cfdbc2a481a6a390a5e93e9f83a83ba2da9a9c384ed5b9e818a123a2577344da43bf2640f4708f5cd3e0b7c90de4500371e714faaec4cc1f48bb97a2336eb06c0322f6798dce6a7d4d44ebb7d751015939941004c64562d30b8d26e11011462900a6b15cc4b0ac7cbc9cd2208a5a090bbadc09116040dd5a7ad3a000374f877f93e941c92d45b811d6d3cc853e4eeeb4bfad8c505a56c1f1e3f139e97f8c3b3dd5d9c241a45bdb4f9ff8a8347057b448d91a50e578c3e6a09f7f51c1b293aa2320dcb27b0716610eef4aa9afde72d4b3863329a0258db7416464548ae610187aa7adeafeb0d6b4a3e729cddae85f711e0d49dead3534af8330bc06b05c7b860729929454b5233ca20e0e2b1d4d239f7f5ed28ea2bbdeea7333d68dd9275c412b47a1adbc1ce3c88869997eacd0ac0e39af05ba834b4195515e93ce39343834e6a276bad33c814f8ddf0509a494bb37f549484260551274e0da5d50b11051c4afc6825884d5873a8b2dfdf4c51031ed60b5650d0fd0d7a1ee3b77fcd4538f6e3adc06b44b3a261dbe168f5cda18a05c2f27bfe154ad6c2eb39c54516a04ce8883b2e27d0810e165377d20257e8dc66ef566fec8b6b4d4a1718ddc7258451ebbf72a746751bb203a49a3e41ed1ff26cb009f80527f9efc4a29a9817615f942c44db5382c77210e7fbf3ae142acf039ed526470ef1b0907b63d3ed99b654c8b0baea0227cf37f5c42583d1cd9e404364401dc232d6ebfe3b9e8a114c8a60e987d38160ecdfe016ef27b94ed22c115414f413fa85a6bd8ba936080d121403ee49041db9182c62f32f618ed2c77ce71a8fb379ca1e9e4ec588cc6cecbc92f0f7b0d71d271c644a03b0d9af3279446b395dbd6a799af1f0b6d06ef3793c5d60945f45102558b2609b16edb5eaf42a2080126a10dbae659ded65aade0bc91c7dbbce66f45497add1182a5a60f4de12a8ece47e04521450e6e55aa63a33409bea80ce7272eeec43d01f9ceb9c80f607681fca02c4c2d9419fc171cfc855896b7acad0514f7c4f040d501197c48f497739526c0143792ed75562fe1055f5c22c9c07050874027b93316c494d046415d07d9cd94b8b0d8844901ac1f3aee811f0246568573b5b70031b57d92580841753d32abf0eb3467d282b40fd34ebc55188fc7e69a59e8bbd13162be4161e16445911b7641158725609bccf87786ae9a8a9166ab28778e3f5196246918d176377da8ad1c91f22dd6eebd12544df480c6c47b042c1ad433decdce55d34def568e3b3576466e619a9182db456c69156d042a0c53d9809e253a42409677fd159db82964d8254d77c7cb6348d51f7b99098f723d249483e4289d6785247d698a6038c5b9b93e8ce4ef534a62282625c65a69cb0425477f85913b0525f5075180829c4c014a8fdfb2fc097aa5a24aca2975c187d39a56682f27302cfbfaaba9fdd875c42962e4b4621703d2565ddbc455598e044eda4eabbfd90e2594764a455f5bbf1c6b958deeb85752dd6934a43e6d9de862d6195823c776b155db5ee9c7a5430b0825fc0cc4fa1181fcdbc5f9c270bd3b5a1fb9eb2ef01935ecac9bf48cac4fe01b173ea6719f3c1fc5761416c9f656cd184a5ec09676b3f302bcd138f410656b0674fe990b79076401e327ddd4909aa1aba2f50d0d28fe1b2a30ca16a38eed70fb9294351c38582ac2635ad29b1e8f4c7eb7cc5678444c2dc2c55660bbeb96f064a1947d90a18b24189acf21627fdfce475cb1f43456fd19e9e908dde5d9438ed5d38c2168e44773eb631d4a738410fbe40640a218b66368887899d1e26117c554c0a933ee21c2690593bfd1aa4f4ed7030d6e93ca312f6caa574da68aba9195a8a98b20825f05cfb5205c46775b2e7f4a2226f5a3cd1395f69b4ddd2c5b2f35ca2c7f3ce559608a9fa20d7698cdc48608617514443f643a7eaa4e071961dd715a85688666de804845af008ad30fbae730614a0e1935834a364d355b3dc87933e07c230f532d824a87547f10613819f20b23119698f3c618d07105cb64fe816db521937e3688d5ab3d066a11d58a3e4e8ba2a0a763fe4f1fc54fb9097e67f0cb0667a49b421fab2c4906c598374047603a67e490c01f87b872b4de8ccedc64286b702b9ba19dc6079c500357c0e6170feb6bfbc41d018337e2888084180391d422a0a339e3bd211d0c5ea54f054b7a2c034093880db8ccfd2e91b7bb4c4efd1ae63266bf32fb861a680d9e8beca82e18cd582a94a20fc0b9bd9e512ba34a16dee067b6ae468d6199ded0710dfe3a296eab2f4a755bee54fcc4631bd58c6d56a85e0ddb6ec404c68cea2059363ea8ab005e27dc3039ef00b0805a3656a92a41554b61a3dd6ee9aac27da34fb15d226534798fa2788912133772dea2744182cefa9ce4b125a712e1f7d747302b0a8c38667baca4037515be7a017ce2ed7bae2a817e8edcd8b877d934591d0f9fa98104b13836578ca73c0fdf60a127e7890cbdf98698ce7b9a086beeb5a6648de039aa0f41d5b4452ee0090e64f6b5b173a8f881a08c401287fef2d7aca09e8cf8a7df34ef6502bf656d89433216230eef1c7565c9e4a262137da708e61b715742d2f119611ba380edc00a22bc7066cb33af0d8ec1490ac8080048d55c2e604360c71c263d275df1f21116a23aed8071c099bc3e6a6294ccebae9141e7a4ffb9ea23e1434a506d4178532d5b9dc04316304468d321166a7f397a8363b0762684754996dca5e24a674b53812c4f0fb82902ba80d47ce940c2e82dea29bc11c56bfa58d47c47b4b64f100d7aa0830f413e0cd0786ffc648caf890f715f765601f465eac8224c978906569ee4b8c8fe059f99a4703561fd8504656029c9b04b7560a87cf7f6639501823cd3b2e6b284824790f121b8f781774095a4c00284e6752a9ee1c8853a28fc8994f58632a752ae322bbb8f6bb60918bd164cb81d643c6dad07d7ece59d631dd9355924129cf908bf60ff88000ca0f2628b83a9551845659752c755d93c9680824bef67e10a9c079930d14c283ad300fa3850301ca9906fb044156b1b06cadd6d5fe2e66d9fdd626f6b140881fb833c69eab35cf74e20c1a5915d03502661e03494b6485822ddc0bfc74518ab112385cee134edd81c601989a3b8c90b81668c91dff3d1c9508ef20faa91beae119b7d4d9cb192b601b9caffa1cd9aded04a15e28c75f28726b3812b87bcdf0235d5945c0c4753076c0c6b0f0f623838cbeea1328da4ee76ce2fa38b3764de771abb85bfc2fc32fafe8d116e20c5320f057b56487e198b957a071d4419e15771abca83b084f15cbe1c06462a3299720ecdd741085fda62872549905483a053746c2cc1b52a4636401321548cd1c6ae6989ffb6ab3448de565c8e0d7d4418d9d678223a57544404150f647604d315afc537cb652ef4ba6218a5166e053256087f1f7a33f696bff797252e8d9dbec7aaeb4a37b74547f19af46468f9da2cce5ef362e22715a48d4015f56c55dc0207edcc202f05bfa4eb67b44d9261d1b64fdbf929079d004ca05538bd612c0eeef0541404983b05f6460a48eab81240eda3ee2e1ba1cf29efcf5d55963265463cd9b47dd1002cfee2d99246ed3d2dec7b86770ba9ca427a912c27dbba26452b988103c22f0e2d314c16ea6425cfd53b3e7d89325362a7651cff2d8292c471360178b152d8165ba7bfa93360c5d35094e13c30e8c753a6ab51179ad65cf97197465f352ca94762e39fccb628246c193d6b079f1005abbb3880e8f5588548957e8435c71f98b5ef892ba70e02cbc1578ce60028e93c702bdece314a4bb2d00dd47f33adf62f655580ad1c0c4a2621f483cbcec34916b65f32bd0f63c7ff4c5465263b1711c90ab079c49fd6d24dad528e7caaf2465703ef74d43b1856e0aa4b80f57de504fcf05ebb8f38822141bf5eaa51cfbf73a2bb961126b96c2f9a5c1d8823449206487c5879ac517931e2c14121bc937d7b94d5fbbe7008e524f44a027cc60cdaf23b20f28d2440d2c37ea045bacc1517df436910ddcf459fc19c0cbd723640f801e43dd975cf31e35487f81e56716e64745588b2e0a71b3b57ce73c8204db206fdde0085d2db6eb3b02525e339583d759ca1298b74836169146eb0fd431319fdcb6eb8a93e060d41e20e43646640fc87078c760d07483cb050e72f881347611d258842679d853968443563b287c0ac8d86c69f715f229106e2acbbb4f61bb976282a7427b7caae2ffd17376df9c1069a48332e567b3211ebb6135bdb62f4beb2791a393bea981495de42f15c7dcd7e4d5b086094b309a8e361071579203bbaf3e8c369d90257ddea5b14bcd94e45d25bc5fce32d85092a4ae9364db839b96f468b0a5af0d6b95609faacb6899f6c5f2b0ff85934ccda97df4081b52728752a8c3069824329fadbb4abb91202c9db14c1c2c0211fda81f5c4d2345137c916b8e451585042d691a87efd2bcab98629e6b949d57f236a1b3f764a07384abc3f3b072807e15097a88a8da10291f9dd038d71e271f1253903d2a4045c997d94cea1e8f12ae653d21e6c78766c31fc6330e201b862b770e6d1afde718a8a32fd0652c2f5adcdfc342182bb619ea4a1305598e7598f2cacc46b169ef11ac117823659c1be87a0c3aa247723095ec3b10c102fdae4f31935a41b377b4b5d8211100cd2bc642c344e7b2ac362f830c6750c31311ae881495ce01892f6a1624f5c229b569e2f064b128eb31cb2368ef882719cef2c19fb87358bfe9dcad12a2b6aa5eb13e1a1b0b4aec3b13c6ac262198dc149585c413dc0604deda8a6f94f5e2a7c8c66fb9230dfeceaf3977042967525e0a08297fe10a74ee31f5d71c5704a911413d4ce30dcbf37d2e243263138154a75c073f1b1130b9ccf69df01e42c1808227079c58881173362f32616ef14954af8e8c5fb97fd951060757f285b2f3b21706424e70223a05f3cac17e6005b085c551ee8b17e9c3dbaa13820598fdff838504740957f0f67414cc52a82115caaa67025725a8884f0ac47e116dc0319057a23b4c58c1a72ab36681236872d57ebe0fbf6b3847e95fdba19a4036e7a03ca284a5f85089065e7c772be2799913ea03daeba46969b6867ef30e9359fd1fe490c55aa85c207b89d29ae752b9aa2ef23c6c648d0eaebba5e63823c9dc44783f30e74ba05c41d8880ecd8cc178685099c86aac1c564da8e970cd6f7e6fa8789b7d60c4bb05bbd439c151ba3851b93800f4520f24e61bc603f22967acf87b766b45b845ca6d5ce57ca6eeeab3c9854a3b3217e6e8ea543755073e5eeaf0687fd2fdd6323f8f86b917244d57842440cfc7974c3aca6aa7d2cc30d89fc972a08a2396b67d1a1458f884b0c44447ab2051723e43bec218ebceac017138dc9345db1a438764e2a5e48fa72daed1d9a08ba7da1060887c247df3bcfa79437df3a6754731ea91fde4b4586c794bc3b850005ccee128ebb55646119f85514e412e21331dac4e49ce01ccd8107c03ae23873c9990f45c8e1a0904bc73bbc4db00f16f618adfb4505e56dc8f004576de3679223a8dc56ddfc90513b3de9bf6af15d39d71c8ac9a816b30e44e9c92e6a7cf250348621285f7c5a45a264f39860006bfaa83a307606c61a88228c0ec08431c5f67491d41b1e3a25c67e2413a0888b10f3566dfad936b0e1761649d83c3cba6ba298c24416bcaada522c4340c37e543ce2a33a550872aa884e294767c6be3b494ef207f4f3f57e3e40d05854965ac3f2916a03d34074fb5524a9f5b18c30b29f83c23f2ea70f83b151560913dc9c2b465713df9c3d4d5a8239de421cdedd139f9a0c05906422965e6eecbb5f39a0d0b2b19503ee70c7a2ae871a65c4c1c4b90bf7fa50616792fde022add6b017b15590db154a95d19a5a4590e30589ff58008c5ed1cf3c808d4adcb530ca1f5c9f74fb68ad80cac278cd82c420e765b4280643ac79519b274ce820a33ee2bccc6ea73dc4fd1d27818372811d4affe988843a83636d0e87bc9a9c9fce4e8faf22d2b16e2c44fbc72d0bea2028aafa2dc42e98048e11d0e61150f6fa5c7b6a82a28023a649d98afbe07f3cd450bf96f36760b5f04ec9335a024428aa0d35fef0718d8778ba49093791693b70f4f76ab270cca840fd8b44d1bdbe97a35cab0a7591228320a0dea03c73af32551415b14e8c70c8ac82628d4543731358c9a312ffef468fecc320d10921fdf8176a96dcb4629dabbbe4ada5011312613fc43fe19d590adf31933996b9aa1b18516a93b5552cc983c7260529fee8c31784f867d4e65027e61c09e8fc53c4cc0ad0c26187509362f8103aad6026f6cdd2b9f01a13136b0b8cdac42b243325094aa54c15e4484a3aac3d00325352fdfba8e8c9220af078a5fce64f4fa089227414b63c6ff85dbfa7419885e05fdf171e1d3fffb2bb2994bc48a9784c48f7ff8e04878fe15699bdb533e71a7d88868c29f3746ec6bec332214aae3c00b1fc834952f2bc2279804f9d2889ad62637750e70f96e73a2984318bc1edbee232d79e486528f1725e856739c62a070ba8e233ae3091bb8c1df875467b3917357cc90623adb944ef11ef14e436468dfa6ed9cd19a2ed406d25817737b903ace3b96d2e5f5ae3eba278071778adfb356470cfd6faf449846b8037b1de1dfbf4d1b0e6d18623e0aff60a913656172d7f642a6ba01dfdd95e206c5157c24b49e854d0d9e6b2623e3f672272fa0c036e26ca8128e29db3593734ba0fbca696f5e58b01ffe6011305eb77d832d6a22cecc5a295c871886dcc959a666c69ee6e5bba4aa06ce81a7da3e6d14ca013afa751204769e2f71d86f3ff413b899aaa3e5427bf3397abd089b6f7eecec97a0bab972de67be00c5755469472fc8f9a2a092dab91a18c9e48058aab28c65277354878e8301c239701a910f59f1c119f085c2290dcc9c4e5ddc612e29c10a8e64a40aaaf0f7bec649e3a4fad6c9fdf7b069fbb9a6e46f5ad08be6ca39afe14430d1ac2d0c8b802317393cb257905bebce626579cd5fc7b9157d82df76af9fa88e4a81ba4d89253904dc435857884d6951cf47a21a5ff7c112a3edb03f7a5c9029752b8f6bdb859ebe1a44e595b6047a272ed43f49e938a70d8040741c0ab437b239193000778c46308604d533604964962848d91e16f0a26e5703d83ae5c273118273ceb46433fd34a86901b05b74c66373f47fe4c1bee67466b636bae057cfed1a7226b5ea3eac776c22fe49a97028fa2a21648d937715d9a02a063912e4bc8e92930e65cba0911239e2f3e4ff332cec00cbcb263b780c385d5bffbb3d82fa639f973d298f101dfbbbfabcac658e8b58ceba5d8c1c95645ec8490119229bbf2d032327c7809a0a27bf86dceb0255a866f09487fbaec9e80e048327103e09aea1bf67efecd9bad8188b96a0f9a3ecf7f8c9b5978712e6e1d32dc2c62907c3c68231a2bf433a0d9672df068e44c1406328cb70ec72c3c803b5683e59470101233cfa8f018c478677c3eb630d96f8f28e755b45a43b365e07735908094794fa41a7fbdd906995f4a7acff0268f649154cb022db18ca61602afdcac61575a91a8ed5c05604fc3a81864fd3c2353198108461d5ce0a6f483fe7a108b073765927e55d6989ad85b5089dc8952a6eec862c60f3c5d57a07d1c90521c4f85213e467b2ca24b0be271272a3c02f7b326948e157525e8d2b091f93a6d7b2123af043803620e674e395020e0399ca3c11d48e5808f5ba78c9e0308eecc4b7e32e26694c3438c9e191cd6e4279e27a04ac4f1d4858977a27470920b7070aa10e04726320d83b0de33626c9cfe6236a9588fb1694489d44be59e462191320c1a832e95e58a07366e616ed532daa6f40c16bdc5ccb0545d177dc7f2c9778bbc9988aa1f38feef58f6a9addfb15584b7a33b1a60f1daf68dfb80af1a595d3af92f8fa28ae954234b87283f536708ef2a42b5fce5ef8d4312119cc5cb27d91f19cef2b11dbe26a198fa8aa79d3c6f25f1c73ab606dbb5607868d3d9ec1b04079cc8705a2549faa790ab4d7406a84b85e29a9ccd6f91cb65a8f4d57c0312ee134dc301eff04099d45d431e195a5e59acb4984c0ccb82436625b6dc014e934ea473065f9e695b0e71256feeb5087d5638cf6b720f01becb7ba1792bd168c7012bdce04c68c3e83cae1f27790e5075fa9151dc2f3e81f2b5bc294e4dcbd5ce596c31bd8833472c9c9c6d556ac5906489779873bd317da0c298e01904d6c574925520fc3af2ea884784ebbc93735b54de8b69528389dcf4449df745ba93a1ce857ed46437b6a67a528cca0ca1d35755ba92c9b8c6443bd21aa6f4755f0e7ee4d33fb58d27960fe1eaed169ed4ff514047ee8699b3b39350945a2acd2f97d77ce8a14128f1b9875c09cf9104f7e129dedbe526a24da632c0dd47e3ece01a5f430b51c116612d6ff0569d8c8af1308c5c52353d9bb34e94e838494897e6d7dfbd3ff6d6f9f88facebf7894dc68afa11f247563ff789a190e641cd62f2968f5364ed0b898e3808b33a53306664c742f30844a4cdb7cbd9c46b4979060dcc94b090e2b3c8b4c45bf1cc20f93e23eaa1eeef8744f32f777a3d3fe8ac5c4e1766a474c5afec55bab39888fae0923b67791082621fe0fa61378db13a36365c3fceb4b15a9d17d4bacdc84273d084a2ec220f5f33c8cee0501b07399e1ea5732af6504363903dcffa6c598b66d478ce68559c6a525438fb825214b9cf53a42c1e0b2c7ef1280b2e9d082a7901ef67db7a88cf588af0d4c64b1e1c48a38c58ae82288f848e192e98029489923418e060a555ec3352c80133b5d3e9d69905fa6795e07ecdf2c5094a6e6c5e6c66974749ca9a0c6c4cb958b86bf8559e9b47b466040ca06d190b43e1344c3d65715864aab2410a8a7eb2e1706ffca217fc212bd870c8c1f5f10d1a78540f5a44c8ded5f6f9ff4e504b6ae13498bcf799a936fcb18a87cb78aedab8be2ce0de587fa89b2c9786216f6703d8f87c789499feca24eb4fe35194aff016919bbca91552d206b2d30d7d8b9f1df6c320a00eed4409025a7f9a5d8b805d549d583c91d56c21bc548f6361ce9d9a2069f5776c0420ee9146e305bb7b3a9c06de17e80fd16103140bee39a5e9a58128885b5b7e3ebf21d76f3e994544c886c97ef0123bc23e8d443f83fc6c61fc122aee40858ee44e75905029c602472e8122331709ebe539188f49e3ef28a32ca55853db68091fca0b672bca2c3c17c9842e278e9d272854ba12eef4427f50ecd36cb9b4acf1dae5713a1b784a249537c0b71dc1ec997ccb687c6d59002692a52cb3650ced79abbe250747c3bb3c4acbf4ec4767957da2266180c3d9786dc421ae403718e7fcf7568a014e74f16bcaf53d7cb5bdfe17b13d7060fcb72373512a17ce30a1d92e21823f89ef07f00a6c6e9283a813cfd9c3c9560eda0224d896af8102591295a39a86c06944c22f89eeedf78f5e391e03729786824a9e3ae1e19e4e1b08ef386a0d0e743a7f0bbe87092d2fff14d4f1896ad09248bd81ca662fdea35fe02f4c1c81de27ccf816cd39438bb60bcda3a0039411767d7f5484ef9445d9db7ebd186cb862a1e5ed34af359441488829ded939a058e5bbb52425d77ba6987a85a7a96898432ad063082d8e5da5ac79ec83fd84dea919ee396fa0258354f9b3e90c477e312e0b10f7baa0bacc21590caa0da65a54f8a269e43c48470d9e9c6b9989669abf32737ec12999005be003b59295dce0cb0694337fac5f49e0166717b8104360ce2a1d8bd8c8c630a134645a4586b5db2b80d34dc2bdb7d71ed6703b0bd8bec089c3a23d77c3ae5f72d35811880154362f0245386a08f2eb8fa320ea34303b21863e073ca46ab0c4390ad1b8d2a24bb335755da0cfb5c9ea121812294bdb0f675c6c295a815474f351d2e1ee7f1e441417c266e2dd918326fefe8acbec9034242c9bdc2ae202ad788dd964c51450395c06b63197b0d6be6590505883d397bc3692be83fac80edf09f94bb97933afc6ce5cabfa7df65f58f907dc42ad61f80235a540c3718b3544dbbf885365944569dce3163d546d72bffa681d04e55571c2f8c44450972b8e80315ad1f171cfd15708a5cd97c90d73803294916b1e28f43d442bad894708d1f075546fb631d599a3fc5d452344c38dcecef7873e24b4666966a6ef5d976134d7808f3582f0fb4eaa1d1522fb4b680a62df8b737d480e93cb8b1c36074502654b7d6a3ba55aa2358c60163a6e39d0cc32e89ae3404c1ba96bf759b4948cb31a7397fc3f7950f1552f63d154d406f10bc255b9f87bb97895a88c592fd71ee3c404340d2299c368a08c4d1275ab3ad05d6c4373bd470a5a725325ac483112e7d7d0c5b8862f92fa853dce53f32052c289b65da16722202a36e40c7a4bf69806244ec53d2da92d4d0904911eb8adf4494ce5674bfeec0193bcd18ddc7c6e175d73d3ff6060487ff2024b139ad5440fa1aaf3f85f9683dbc919167f2bfc1c67b31dce02ec2cf34d96276e8fadd9f01cbb02619b88c9fd031b68e43ea0fa3e09fb9848bbd9816ef59fc4c8ce76138038e43fec617bb3be6a08ba6ca0133ecb925b261ee4a3436aa813d609516424e5552c97344896bfceafe2f2765a574149c7ef5c456ca61e9eebd16998a4b23b513992aa21744503aa5fa3b8a7950d0165090549b3042421360895574268f595ab610dc6084b04240989340b3351b4da016155122c3cd0a3880a456bc4d48ab487d6ed9d870e23e8693e55ef22efeb9262af8849b58a7cae11d31da18807abc557d663b5be41d33d9b531a77015619af976ac41f3c8ccc596302acd36322bb683a2981f11cbf9a3a974d48958232277ac4340b136e3541b4929899564bf5d7e306df5efb2891c404f1fc18741234d850c970ceaf951d54dcd0781815b4fb79392416fc95937060b335f14472dbb8b825661bd417cb39f9b2afb12880dbb9da948c28bda2f2e8834562a2b7ff929854b3e12afedcf71d747b222d32a49899b74b2a0ebbb96d997481abde8b30a7a8e9958cd1feb90b809e86818065b7e68739af4c04506f3df8d18917f8818eb685b3b0411e9c84d936ed0cb5246ce37b58aab013dcc1323c8ee00d328238c8a4f1532b58efc734319ed39cd0aa451c3880923069e55d5259d640327a76edc72404e2ef91dc52242cdbcc523c1a091bf4b3d9ff51b94aaffe5c1ea75c7d83540d9569b751c4ddd292ce774c2ffddc9776f47ca734d2f77ed1622a90d0cc54200a1adfd4bdc12f99a2f5f9c9c1219c9acc745fa26538fbe75cc95d215180731c4c5a5d2e26c2df3ef15681ed8c985dba20a59b9c4aa1a9ea6e655751733f39b42a68f742152bc3302f92f82ed83545ce923d50e07427e811a2578ad51ac4d3c5d6a1c2aeff88f2d7d82997e1570f68fcaa6e282dd204ca8d48362027cf4d2aea62ef07848b26488318a33ad295c4417d19140588211ed372c4c779c450f47991f4f20209a6e02350d20f4b5d7bb7d8d87b07f9ab2f4f58faa2f5491c6a9417cb64930d99807f67d605bea332910e5d2b08569540169d68ec47d6a4a6a17d41d23210bd4efae5bc0b02b731a59765e1c60cd3765b582353731892ad175815592f3ec72edf1eec97d447c6b8ee4c4b9403d146b1ce2efd8437e9d3c598dea18e8dd02c5f69814fe830d24a0463609684ec4ff6856e9dd41719f2a6c6509cbf4b6822cceaceb2a004ea9f625c2f812ca851dd04ccd5a3be818dd47a0337b8075c90606aac27d7a3591ea282fd6ba95dd9275365f229fd9ac5fa8ff4e5fcd610a1df63597aa2207dea09dcdf36e6f00b9db54b3f6822417fd08b5d4504acf6893766d8c56e65f1caf5baea3e1893bee37ae56dd58b8a248a6e409ed18764664c5b50c67f3c342e91f21b1e12a90b5241c46757ea40ea6782c72fc76666032a9b48074f021bcb1d952c416a5d71347d83b3c88499ac4138308b36f29a4c5d8334e19fc06471a2267d02b788f88f24fa4b91b87b4626397ea46ac3d2ba84a2af57eadd592c431f4c63860bc161640150c94b1f108cb2eea5f9888fd463a22381ba9e736b641e23988a37ea6c89d45620cd3b5d7424d0ebc91f54c91c633815f694d99214adc0016f4ecf3e2517a8f8e55bb3dd13118641fe9f0ddc361c566c40ec8d4285e5e6866f3271c506a0e0966c9ea68a4280c78241b05487d6f21c5ffa2ad8391dab1f6933ccc21293f425210e991bae1df5ed7b7dbcd6e7934484f57111bcd28cf47d9f2d4483f6c384984fc23936c63576bd9ad8b80bb22a1213f375db55a711a3dacce3d5905c8c913880aebd3874e7d12a97b80c98a5fbad154c66c710e5f4d9bd6aa8f1e0d6baf2218e2cd1b1de061ceb55eadbfbafdff4d3d448f03743ac758a19f4326fc01db927d0f5466341334b8e2ccc6e92247a1290a85f847c6733bad9f46e15251a61ac25f9196074b057e4e53494f9bf463a3f8b07d18fa46c549a31359d8a3334ff4d13a63636193a2a96c714c1650b06709ccb24bec60793f9123b4ab24c4ab6fa996585c0e590e13c5bcba5f795af6383f6052dadc189f0a4b52cfd13c5453190166a0b6989cb39fb2fba247f71e9a09d5443be3083291ad594fd6fc17e0449e6880b35d8fe6784f1ef09a1b4577214666765c2a20df96932a48ae0f91d8fb23afddc64f9afdfc89172628e5deb8cffb7a0fa38da90ba1211d59185924317a9703b5b9fae55734ec3ea43978028fc3797033909178c46dc2b515aba7ed58b5e59ad53807df8943b2b95a269af958861ab6d286235a2348c41eb61bff222c9ebd37096cf98cc3c8528daea9948b32a94e04f74344a2f1b9940b8bb80cdea62bbc2acafff32c10f623b411a8396cd8bb800b02a141e9423103a0bd373d93dc1f44c4105890f84794da95afd2101a1b24aa550a31ffdcdd75febace2f52f1672b35b2fb724973fda309edfd4b1945c11c1401091e41f300a9f1d7fff98806e41dc98dfd9e3ab119205594e4d8faf7a28df80bc2825c457130144c750d24ba1e4f469206d2d17eab72e54d23b7937ae878464b0ba798b9429e71202c7fad4974eb83c7e2af034607113859320bc90cc50c617e35d2fa57461cd160e2935c86b9c520c9fa490e6b0d1e675f360522ab9cf2a1eeb26c4dcbcf5b8acf42e8c2ab8bf54afba878bdfd5881807a75f8845a89f97edea749d752e051ba7d2b1341425f1cf58c6857087f89acf6936a63d064983ce453417c39c5cea6ae6f7da0d39684d8f1a86fc44ffbfa9c210b27dda65208df4babdeb77169033d45a7222b1f4c3a9d5a6725cc0235ddd7bdf625028dc70667aace42d1bbb54689d19765d3ab39ac00a5fcbfb82769d250e88263c6a0b3b66a2bba751c662ed88e9a9a6c98dfaa27b7b23bcbc09dad93d5a918f88bd01d6aa32e934a1c727f4eb9dfa20cdee13aac7fa240fd1e7e6cfd56bd5f254d95400d453389622743db2d2a5a287d669534bada5b5c550e13d1176a6f30fd16ae69c56a562c5f9c39139f812d92451b0bf87d02aa874ed0ae1a6bc1ce80be0342bc811d3c0a916a19d933a4940e6b7a46fe1172b290a9fce3e92298a1a1db7736f7f457df5946f76cbd59e97687c1d5af4bfd2ca6f2dc1f345ffe580722996f966d952a9be8a4b5b1437125cb2cafcca5e05d19f4edcc05568bb82f46a453ac84ebcdce660706cec272e703626b202a30086c2ffa6809e5b00405b45701fff53629eca174b3d00142cc6091bcabad4a721192ea0ba541a7fd71063ba5da5bcdf9cfa78a939f3ae419e6554d715ca8dd9654d153ab460953213abd44e48505a36de95a0deeaa0746e8fc7103cc8150e018ade3e2affff0844e8158d0dcb6fa0a7301e06b3e945e599d2420d3b0148f253edc0018dbb641f04c145eb5439ab2a6acba7f5ce45f0f812b8fdd2ddd2cc5bf2466eb17ce1a36db634dfd201d2dd66a648033edd9ad2c3f0b8d8e149f89e4c3c4f0fc62ecf711b1ebec2f6804a3693a6ad850e00274b7bcf484a7a7f1e5c32bd44cabc666201bf57aa571666179e0a3736cecb2e59de55393ac62531ca7098f008404f01a20f6ca5997563647455fc1afc0ae5819aefddcdf4b02a92765331757c6ba074c3c286fa50530ed85dd0cd1cf16f0bdce8f8e00d8e76f151f0d2f009deac13dc0cbf06852850dc474d55bcc1615844119d5345b55c72577ac3168b00f48f1db94f0f3420a38adf95fe3e09ddad9986c3ef8477eb3855a55077831b3a6c05aa4bfb0523f20755607f5aca9a39bf0bb8a23839b77b0d99fc0731dfee7610a854ff4a22f8349506696f103ac4c5ad3b88222d93fd4ab0e8665e2aa46b8632a7a06e1d10a40f761770b3a3833739bc064ed71550dd077b713cbc9903a0db50b9359b037217bc9163b37c0bbc34f9056e76b01edf8a289d9fc01b1cede3a36061660a7bebd82c9f0a093d23a0e72f11fcbf84f2ff957a4fce84d7b298ccb7511fdf0c3f535534542af5cb4e3e4ef38130bf8057d2ecd26b734925ec6da35000dc0b52a9e859381a27318f18f388bf37067a173df29fc1892be4c990a49ec892bd3b537ea90097966e54ec09b21aa40212c2c7e6f179c14c5ac0c5e992ee6e43c40975e40b4e198da4776b647b57f2dc2463d636cafe5d5be5501b9bf3ff985fcaf0852f61d7c621a0afb5fd602973db1ebd8d645e74766a3b7e2b2b13ab7412d54e74cad977dacbe4f43238b88f17f472721796540a3ecce0af53a91c37264d45ad3d1476d51b52a6c2c44064b446b62f25efd63b159525e59b53e88b1c97b299f58dbb0fc432ee427b6a869b4a7d79988d2f4c445845239df8bce1070d8d05b900d94491d7bf3f3b6ab03c55b1abd8a1853cf1971f6bd23c79e999dc21b0ea602e44850e640cbba4932a38622ebb03e83e7428619598b7deb2daa8a89be0591ba3bc9db29eec7029db59d3f83d421dd43d330839f3e206dcc155427416fa079632f7dd27e852779941c899835b512d746a07ef8462d385c68c4ad017ac5fdb933d2e649f351abf67c3d619839fb8db963f1994d25f05a26d4543e9fd3a1b4e78f0e4de56fc7450d4e60a886c270ae5f7d3db6ae04327675be0bf06c3e7de11581dd252ea9ebead051e71746d1b3f5b7034f39e01aa587eed70016ee00a801b70d50935aebdd8a400faf09c2aaa26f2ae9bb293d781272d683a608d47c62e2ead6af169e7b9a602fe87067faa72db1b05a25b631aa5b3b12a64a8eeaf29c308ba2ab54b82b242fac25afb1821dee1acc989c0a4fc924a02f1ffca94f52bb99e64f520b717b9bbe4d28b588897b5e1e40183a017c077ea04c757a140f8d183822e0dc595a4bd6e81bf5e05882b5ff6850ee2a6bcf6f3a581abfa8a484e69cc7afbfdaa04b194975c38c65b70794181dfd5aa30ba6707c13c49c6aa36508cad563c9efa2ac153e99cacb52bed62a3db2d230825a9a5c9fd28db5ef082c6a9585040466143cbcfda992e570e6b6b3213d713b0814613d5770d4922cb8533d1b9c487798df312749cce6e440f0e54b1232f28655086f920f393374a12a546e14e648a7e3ad764a17ef4c147ffbf5ee60dd1730dbbe2a3048a5bbf7a68b886fa2fb3853c49305dfb2632044e45e4267b11072020698ff3935a16681f17cf5ccfe97a9b743162c5feb9bb229e6569fb1a92ea1f5765548e9b4b89237be48205e50a284923ad84ef94190bdac2fbcd69d0a0bc923f3fad3940d69e0947737286e23820202b8ab05dc7ca4934fa3e023ab02204de222c2a231cf7ae0c52920624a96033cb99cb55f9ada9d92c5ea31edae468fc2b722fa15b2e5cbc2ce342f50a7a70e5f7bb8c678e4d8332024b3c32a15b577d8578ad03150b9fc0c99628daa7c095afae2162e943646929a4743d1cced4066f6835ff23d85d3166b1846f0a6e461e8127fcefb676108766887aab02c4ccd882d5c6254b23b6928008e2ec9d1f81668ad8b09ee424c300ca075040214aa60d1f975a03a7fcbc0fc99944a505433895f23e88574bc06d34300d5f3fe7187cdf637a3b535d2568c5da32700a88175d8b7f2dcfe637239154680646e293feb5db7049184bf68112f2d891bff1ab8f79ee0f17c922501badc4ddd49aba38ea29c2daee186ecc06a73c4d26db02344e039a84b6865d301416710ec9796e67a89fa396782ec6d1fa3cdae7d1f6bc79703b52cd69fcb291967d173c35392f8775c4932f1d64d62cb6708fcf41fcb900a1d7079478108be53afc56330691d0d1894f36d0ef3efa59d35d51b4b2dd448894524a198d0851080a082252fc29e18c5144304aa887837e8a4b88a90881206212d5bc9fb68c64080b71421f75f5b252be7cc1817a76998aa55e90f08e85e462788576d51863b78c9ae024b84b5076cdefc3e4d8bfbbc59357ea904a96d2e374fe4221100882362c3739b3e0b0b8f6890857b3b95361db749debb6c4a1ebfb3f1abb05932ba7d393c81bd2bfcbb73c87fab9194a65a1a054f3855b2914aff413b565baa2aeb46cdff41495b59be8d24bbf34093e516bdc7721c126aa0af75b485048bd719f8504672058a3652e4e103c52572e5a57432a4159ad71ff658b3048bf614e6844e7a1082acdfdd0476541945a1a95663f8e4f8db98f82f2a3a37e2eabe4a39a62177575dfa502466d5663eea750dc128fd4d515b44ea4aeee8b42aa7987f45b2ff533852e49a14952e84c7622439c4c86e8358184b0104797a2eca5093f4199c7bdba7d4e02a9d7827c8274fb2b25164214033c929f0d1b210054b061e3c60dd0065b1b7abb2b8d4caaf35294e988ff8204d47322774fad61aae1956806ead496890bd36ddff6adc4394a949a94d444578866a81f1b37582cbc710f0bb4d1119f05eac832bdbe0c70972c282570700b8481b06dbb2c13ed6e215496698a6a9a6ab805ba4433dc02f5602e6a4b5483babae19628c52b30bd2cd3cf9541659940d7a9d24f535f296bfd86e559e2a2f2e4a2198b0bf5835bfb66516409872ca12597782373d0819ba628dd74da65953a504dd0855ba21675f50302d145bfef126935e63e488a3211d4835b6291baaac14c94e29628a4aea0883b3f97252e51cdfb57b47191a4a78b47fa05e19f7e86b25004a18f4ae3be890c53bcba5f22c3180e7f84e80db7c2170e61ac17257017264c5c6c97e561237e00c1373fa2e09b27519c3c61729d38e91775a6d07e3f855e1690d42bd5026dbc3285cea450d02695022285a680c85d4e01e18d40186ee57b82314c8254d898f47ad759dbbbae9e6b0da943fa1089c565029c1af3835b26199ef5fbe7899b8148dfbf8bee78a7b991e9fb0b287b016dc0212ad0268582b2149a42595ce60c14503881c5c51203da803188e06788e3eaf7c3d765e1fc08d110c8659d3c70da3528ab34b59ba92f047ab254e158ed1e566e06947c39f07c4dfe2129a7b035a49c4041417dc1e59c8340440e82308220dc8420c6450aee45696902ffba48ad80c91296f400094ba618b2048a16db9219fc58c282254208f132043e0aa34508bebd00724b25e12324a92614f981ef26504b6c31d8c29684b60d41821165b381a0c7e6431425605c16c7450872ceb945a684c9164aac5042fb6184ba42c9109a122556a024055828c1818283509af0951b1259609193c59127b2e0e1c942c89bff6266a1c3930510287f04f7bc4821818f94f8e0811452a0c000821230008209522c00c20f66e641e2e45f78b080d2bf5e7980e0817ebe8ccace6dc2e807114678c1143d6e508af8008a1246261768a002248c647103286e6a7412ba7e6eca359a874c3779239e266a3a6882d64ffeafd1ce6887e79c73d6dfa3cb0c549adbad0dd7bc37f0b866066ab8e6fdafe69c6bd0ba9491e25caf69830edb6b88826b1c41ee9b956707affe9755517d89a745b75d74307ae74cf0418105133d44b62062ab818228823ca149e1811eb798283c554049a180810d4d0109750746c47e6a68a2a8a9cf2d0bb5abf0ba0299acc79021af0fbc8137f006dec01b78bbf7de5a036fdc7ebdb7d65aa1c881b7107e7abdd65c73ada587c578734282fd516b504eec7c84e3d187203e1fddf72879e8d1c39354f41972d7755dd7755dd7755c596b8daecb39e79c73e672ce39e79cb9aeebbaaeeb3add755dd7755d97bbaeebbaaeeb9e870e775dd7755dd7658ee4776577119fdd6f537e787dfbf7455fffab5b93e7973f606bc20f6d6620953e907e871e6a48ff71200cfa8da4fca8f2e0d76b82e5f9d2f58fe0733faabc4af9e60896e635adc601f4677e0be0aea301d2cf402a7dd88187309e50c2c517509810460de97bf450432a7b8c3e2c4b1c40afbf0b9138d8306adabbf24547f42392075be3430da30687a54654fa207d0f1e7af4e0e527552aba7d12d983879827869004145c1c39a2a726fc1e74aef0c0125c50440b3ac0831a1289f4025cd61a432a7fe0b8e5a354d363071fa59a1e3c90c2300cc3300c476118866118fe07666ac2b2c7068a383104134130c209d29ad1af7c0f1e7a5ce04624481727b8010b9450133e0fa4b287e86f6e6e70666a48ef036e82ab06c7eca2b85c3538a61ad2fba0f2e372b96a70bc1ad2dfdcf8e0e2e3d590de07176ca61ad2dff850c398b95c1f306b48ff81991a52d923fc951f4190c256041122f0d4dc1f912b24af2bdb43ce8d0e6e8e30124508b59a3b8413558c20084292f8a8394d5de58a96a00dc119f2bae0f77925ad498fc5c901afa65784d71cdee196ad0991df83825c33f43807c6a1232bc93d8b410fdafcb2422c50c82bc26be73e07f672c876075f7d6102fde99587895b95a2571e2660dd82369e0ff8cd39e75a6bae357b1e13ae5e796ce063ff8ea0571e99ad7f15b4f17af8b5f62de84b41997879d6072b8f97fe71159c9282b1a9d794514a4a0ac93fe5b9a8d630ccfa2bb949153285445d937c31614819d2068e6b5aef096e7b1ecb171b5a4f0736e79c6df0ddefb9f75a7c7bbe165b7c6fb5768acf4be25dc16bc846b15178984c1b250a7effb44feadfb2076b2d91af7e597c40e0f943bf5005b25f86d740db86efbd1fbfddfbbf6ff3fddff7d90cdae472ccb9e4f706b43f33be3f83217004c107c7ec7df67ebff7a25d47d7bc5db6a4e83f4bd321294af9d3eb96669fd81f95d76f9f5c5656798b9ef64990cbc225ef3e4cda6e6f4eb48d0d72cdef73604e863e07562173c83d8534bb1a5ef84ccef3dea5794d0deed2a241f8697f5e08edbc627f3ffe8a4b9d15f0735c0e04962308f4a095726565eb9feddfe10520acffc324ea9ada944203defd69aac1bce62e9f06d6a2f534c16deb0b35b42cba4b348ab6a87d8be6bb51c0df02b140427a5bf4a222273eef073c94a53937c1f1e78c1f0401e7463b7efddea99aed9d8e8ba097a581bc2e0b96b36397955ed678fff7ce6579b22197c57359dea66d231bc9658db944cd3a8ae79a246a086ae79af83b122543a5a08eae933272b8eda76a76a252d485543773f49a13508089496165ce90118306ab35f3a25aa1a46101470b64005cc8d16bb2e63c50e8dba0cca79a75ac9a5d96eef8553c68c7afa25d96a9e357f9a8a2dc164d4d65e4b22a4f14381da35458d8191116f453f5f91089413f554f543aa352d4ce65e11f02c4f888ae4d828bafbea4fcb85adfbbbd5cb1c5f6d46b95a1027e7aaf6edfbb32e860bb282d4b0fd6ad2848e7e2848e2a8d8bbb01d9b40ffc550751ab5641aff5ac3c1d7765a85663f0115a4b053787ac69315ac0ef2825e17057080c1659a5c95f8d84c322048c4ec2f94a16598dc1cf5d1de3e72e8ec36b1cc928ad3425d04f8dc1e449d3340d06337c3ad6dfd2e2ba3204bb5ce99d9c33b99bd4717582414542b08e6f0a1545faa992034ba1c2e4aa31415654725662b4805f54ff2c0843aa97688dc11f23097e9a92cc78b1a4e5ed8a254c493a3e59525bce78bd18e1f7cf94ade34fd92acda8256dd9b18fbf44edf7b3bc75fce5cf2e6f2a173fbd8e576a1d7faacff0d145befa9261be2ec70b69c718f348f1ea1863de7176cd3a4c0a5bef388cbfe8f892b59ab67cb926d6f1fe71cb2b7905f94599c0ffd2c54909261c0380917961061af02fa0664f061ac38bdd2f7739cfca00829f1a064bf54c460f7e6a184d1bb92ccce5a43b323ce2fb4658d3df5069be3eeaaf4c32add2943a7e9d9970958b9f5cd7b85069829f2f3d95a645ef689cae87b46c53f43075cebd79dbf432849f2fddd46db63f53696ebfffc2dd5bcfe4d681c73dc04fd334b91f19af3462bf3f81faa4f3a8b51e85fba98d2070a5804583141f51942087d7c1ebf6c9fbf6ce60569a53d72f9303b7405adff2ab82ef0741ff95230e9523e6f487be1af04a7b1f19226b63ed19ebf734fcf77d8a4c68e633fff19fe626eb48c3fed2c32b1a42e7cc83bc5206afeaabdcab5fd0324381a0b4efa37d1faa25f5a30b687fa53fb198ba2ea6338ee2eb9adf78a285b01809566b0401853924888242ec9ead04848148dc9a808c807e9356e42382854084382031e79a222c8485b01016a62c5fcbd7b212964699993d0ec52b1cbc729d6e371d3869515730595a6426a4ae7696487244d6ef0b164bf10a8cf1580b19e69048241710a9d3d2f2c2ab103682be51e974e4543b15a1cd64e20b26c6c4244e3430166b496b0c0caf46b61acd8b93910ea2e12f24be64b1ef1bd3effb4a1017829d66a010977522b295882a00d1c614446b496b8df1556e1f5193130f0802f105dab09c7b238491d20f44ea9064f80a8b808538a108443ea22f766d57b17bb60f38048882b09eed03c64872dc4943225a44f82ad2ef8722381199c95217527c89b02fb8a882317501913a2e2e20da888e3835667c8d3f461fd5bc3fc24e444eb393ec34a4df3f89b3ea23cac4b48514632211e2eb8b9075898d631ac2be128c8140692ccc39228cc1f6298a9cc6be07913a2854f9e4ffeed93f808de9fe62fb887c445ec06025092a516bdc2749f005558524ea8dfb2309a678250367202dd602d1c421e28e18a473b1089188ca42886369549aefc7d7e8fa8111fdb24622aa39766044471fb65a8db93fa6b8755a52575ff4f423757559a722222f4e464e3f63dac5986a31a635f125c2ae99134b65331a5e9d68b1d847b3d1686108fafd96948d10001fedfb4eb431155fb44dab3544307088da0a810051dc0a717a7c7a7a897398482412d50006b3f1d1be3284bd700b4451f155bb2cd1ad8aca123511f9e0d6f681e116881602515b5bc9ee095f61112b221f1f910f882682d144b05204838daf1136a2a71f51931188e876596310db07b74e608c383b8cb103dbe7d453634eb4d3ec944449ad5fdc3a15a9ab224e3cfdfe894835efdf938f929316b4d3927e5fa41521125169884688303126a6a24c9ce195f86ab969718de9988ee9988ee998b6fc18d37e7f4cc79d5136ee8ce9988e3ba31263aa44eef2a804fafa40df07cab597b8be45d204227548659813c2742c16644cc1d8988e69088b85b0302726befa7d3116135fa211224ccc89b5a4f4b0727528c1a889eb7a180803734058bf6f433874413d211caa5fb197f6faa1186ed5b11ad1eb8788a82cd33561b875fafaa157a5117d254147200032d2eb838a54d60da05aa5e15f1f44ab34e1d7ea53515f5fcf706bfcdaf25527515b3943c93fd7bc4068970b8c5e3f77515bda85b27c7d0dc3add4d795af3e4adcf89224476a4bbf5afa89baba7f665aaf9f89d496969d7948af9f855496a65db3566952b2acd2e8afbad66f5ef0854eb3e780830e5ee74a5f7f06b74c0fa281c4afbbeb44d2a809eec12cd6616181a2b5b6250971aef981363a2c208b8b44b96a8d217775c96bc9141711848148986ea626a81f5418a21a88d2dabe81b0b8abef416f4d35d1ccc485e986436eb441e2166d1532d54dd81369e58b09585cb8e5a125d22c812a2aa08d0eeab44fb5d260528756429e7add1bf73d337b9c4bfcc12bd1a7477c227691a4ae44b3184c489a445de5741554b35684480c86835729291494a5488e22596eb8457d2412c94b6dd3ee1fa9834201a1040e5e81682c2e178bfd5ac0fe917bf4f510b981571f591a0b71d0578d096144d4d57dd026ffa77a588a3224ae476b0c8a57a3da4cc6cb531cd2bf245c8977c882324ef35e2edb05b40971bf474d706e97a01e2e042271438501ea49a1e4a3b506892ce1e0127485253884a83c653a0805726f843821ce0f3f595c28f4b2f287368f7dffa08dfdb74f823a72cf9814b9b8bce9b24cb76b9a9a54f3be687603042a0b05256fdb16c2be812e500784812978035da00c447349a1d7546142e8b1882cb99adc84a428999ec660214e885ec1c320ca3d7282a7489dd48752a09e10b74baebd761abf02ece35c7237daa66ddaa66db987bbe9f8ed65e9ac9f5c96e65cdccd6579383f3c232e2be7b2469bd36b722030dd28d84319077ac16bf7ba0f67a14cc6f3df7cea92bb15bd2f5d684f7ba10deaad41adf73662bfae89a26a46801ee881db886b5e12dc1b4575540d09aa078bcbd233ad7f03d940f6ab33a14c2fff1d957a1c28a72922e02b9fe2839fa5d8bd3704a14c25840ab5714d5c2b03d05a841deb7804dc7edec17534e01a279730bbc64f545a6952422a21d187ae6a8a8e3f8fa4e03b4219064d53ebe87ad638350695c184a8ac5ad1fb3826db4d70af949981cc0a796ecf074c735083bcd411c1b01cc1af5d87f46dd007daa0947204953aa32f0d214b3b6429c83549de08d536a55495826eab31f84bb1d90e5838bbac133afe90e7b6ca50a69a6d5435d359ab985c567773a27a7259dd4f94979bcb1a73b64106ca84d39c266db824dfe886ed3467bd63d4aa0ba881f6f202e4b2c65cc271cd991772c860013fb5cd9471043f55332e034efad19fa19edba81c1150e280287e0f35f6b9cf0ea4724400e94d6f2a39307ad2d79ad15b70c7080162c96f25ef19913eddfec7711dff715dd9cece10fee3ea3a6b43da26c313e160118a5ba357cd78ba15cd5efc8a66b46e5fdb6c221cbcb22f964468b72fa264276ad66740a578a5843321f5d53afff8403e512871a3f3dde865dd570cba679d4f3ec3adfadd7b2f3704c5a3b98c5548543da9ac44edcc88d496b6d54e08b595ebea7e938efffb4c54d7c58e043f51294a268255f05335d361560ae848f55ceaf0c07d59a201465ff1ca82363252ae9fe33c7963f00007187dd5585badb5bea894f302de35cdaf200574985d87d9f39792a2e2a936bc29f7c56b2d9943bea08e1ebacee8732932a29ae1d6a8a4a9a8d83d3ac277a0521cda409b92c93531560da142553ab514a54a553bb7c57317fd7ef6a934f9ef97622693fffd19dc1a7de923febda75f824adf86037e6a5bf97359311d7f19e5b654466efa25fd0edc1a952a9ebbc23fea0197a1ce3a5922b50daff0e8491f136b390fd4ce5d0d21519acc252a3dcdced2d6f1d5d7ec2a1ed54c45134936ce3f93898504da7839ae0ce1ab7c8e7b411d292f7afe211d5c46daddbbb9a51176b08230bcc59787a9dfab9a5dd334034e7ea2f0891007e10e422a62a1527a592974fca59ddb527dd7aa662223d7b4b670441277bdaceea5c64368a5114129f8a99a699c7eaa66232bf8667259a3000670cdfddab659a529755a57d56898c1ebdf688bb0a834a025ba1559166b6b12e2d6b1e75846482ac8721a4fe388fa50bbe216575331c6da36c3aa99adc53369349ec99a0b6a65954e520839eb24ade48252ec96189f3a765fb014a9b2037e6e14955ed618425f74909798e15369ee9b5aa14cb57b29f6eaa7a983d92bcf90b66fc9ed16971d32c2eddf7b2f396697ffc81da282db1fe5af55f06c5fe47875f3d7ba7dcd411b6e5ff60b68c35f472e3df04d5aa5d13544440da2fac8200c1d4eef4e97d3d4b9f6d133c903dfb44d33b966680a6e9feb9b595e548a4a513bd7ecb744a545386e898f3d5eaa78ca8dde8bdab92db154d1ee9091aa87a7f318f0d193fe0cf5747bc3add2e3d73613598ae156a9c4abcb5ac9e155db56a0706f446a195e95231e8036aa598dc1ffad7cae89574f463c8851fa5cb37c724dfc556076868ee077bf2565c8006df67fa609daec5f7d279ca09aa9662a9e14686c1919d026e5bfafd7078de020a757235244e92af46ae40647e837f60dd026456f4ed5a3aaa9681f685b500717e98fd3bad39dd65f17fabeaffbbe50a74272cd1ed58cfcc1adde20d0f3f406819eca6f10e889b8ca732a292c1668f3d50fb42ba803b4575801b4f9be9eba0563b860141cf43a4e8340afe374e8bd8ed3a2170fad435fab05da74ffa96c0bea08bd8c23785a0011ec9af64541c81f4859a5d9d9b4c39602c2d0f55dea1db8a57dd495be0fdef7ae7e1079baf4b3f69c9e908eff23cb53a7215087d973e9e3dce8066d442c8881037c72250f9d76efbd0de6e774373ab242080a6e9ff4e28f30a47aeea3d75f3146a5189562de6f05f3986732da866d24148d340af7e52e879aa16aa8192a45a5a81d940cc583a2a1765043503214cf3569a834f42f02ef8378e81bb150c38763d7cb32778c6afcdc6828c39ec7b203d5f7fb432a20f855a80a071dcf2a4da8ab665515456d953eb5f4f1409b4b727510f892049f8e4548b8066abdfb941ff75eee7236aa9a8d2355b56b62d50c54cdb08a87a642a2ea0149158fcac835552a24aa1e151904cf3c745afa943f9be4e4984b9f7b962cecd10e38efc1ad9186d18f08288df74b6ffad2d79a51c97b461a483ffa51b9c388801107c65beab0fce8c51f7dad2195f59627b775fb2289329128161295de1b585413f574fb2212b951728cc192a30cd6d56fb95ffd763e053f37bad1fd42a59e673295626f9aa598698f74c06fe5be5e96a8d7cbe2444644b56e4548ba35c24296d27b03bfa9143bc0ad29c5bce0229828e7b2f487b26dc46da950bcc2286e893948c7391dbfb6917e54a2642002465fd2b65369482767240f8a5ba5d85de1c7fcaad052cc00ba462c512313aeffdc68ed1155c14f6dbb8ff3630edde86ff46e58948ef1e7f413350445c99654166a89caa4b2503ba8740b3edeebe1a89f5b8021d567e46ef6faa71fb86ae6ca656f895f4725256a4b2cf70baff093780dfaa82c3dd1f19f409b3da282f78460338fd6edd7baed09c0ae3d1d2fe0a2d7c4badc418ac066d2cc1a6e914a31266acf328eeb24d2a4795f1f19e1e7463789346bb1507659b59af9f1874ce452ac635d9a341df0ee4fd56ce79a18bd2c1c027e6e74a33a5afa0c9f233c1ec71e365dcbb5f03caf6302c694a93497ab71dc0c34b87e2cc0c90e9f1f7b93f54bc60095a6fb6a2a42c4fc1ab5253303af9d95480f4ff4fb33d46ab5cc955f63c8ce00cf93a934b7ef21386c7830d8e49735f3525bb57e5dd91b44d70194c1ebb93c67d8d906f66e3c0414c6e4384e731a87b5dcefca915e35ab79f2e899ef9ebd9c778edd78e0636faccbc26a58dc169e05b1436c0cdb59c73aa3b6171023befda1afbf49af9a3837ff67646404b063065b7158b7bcfde850830d3eda04215b8846ab6111a29da19e90911092217a0e3697668d095dc1cfd02c340bf1d0e0900ddbccd98c4c97a92b3b53571677669fe93860c0864ccf250e3b7cc76102cff9effc4408074ac8e5c3049bd8c42636abcc016a8d8957a217e880e62b3c2f7b9ef674e6b6cdf64195c6d6017750c8021d2883a540bfb900b9e78a6fc529dee7b85e2e3dd005fa3561604c10888b2dd136ae2d8c0565e07e80755dde7b73ce45f09591b151030f1ca49891995a0f1352ecb24e8f945ed6499291829076424afa190aa29f3241f45acad8e121b4cf481e7e92601d3f0946ca412b8db74933ac84285ab2ce99cb9c2ecdef60ea0c466b6cc2983041c0981c6352a41fcf342ead0472c96dc793b0aa3497cb1ca7399d5729a480313ec1b24e6be678408de14e605655a430a6a9bb75dd0d3c5e393ad89b09581c8b763a83adfda78d0ed34ad12a5f55c805dc15be012c65c614f0b3d6301640bf8ff1cdab2bfb20b2d270432e390668d8618619408f9f861790697333ce49928545545b2bccb0a080c3b81d0bb038406c983da9e1c7ba74e672982f1899c171cb1c7885abc993001e7ed69ed939b38004c8e059809bc17171e49c6770cce0807120f0b8cc719ad3d9f3383799fe4d5366664600df13ee651e803c2e739ce6740679e58b4ed76d5cc54bcd3ae7ac5fd0a11170dd5d9cb5ce9a8a6c49dcafb5176fdb83cd15a7d8b2d6989c71ffc173a609b3c3061b3f3c3295566b150b0c5c966b077bf32bac50a3c66a55710c7585cd910baec365ddcf4240614c8ee334a7bdbaf23a0e18e8f7deee9ff3dfb88adcddaee33aee5a30062fdb6c54a5b93a6bad73e6405f1f5569b4364d180d734d1d50f9c25d41e159862baa316104ba7d8cf30a8dfb231eddc680b7691feb8b2d4ee13e97a7084602dd9af65a54a5b999db027dc93ae7ac37fe1c3e5cff69da6ada37c11872016c0cd9e5b29546dea1dfc79fb5abeb32075d63ecdf93877eb3056ed7250ed8be59a24a0faf701d650d04af86e338cd699006afc62b6b5dd5d8dba1bc8d3af1d59717ae69abc1061eb52837589705d2f1737a478c868ac567ad57f10aff4e013f2b0de352a77bfc03284d5c411b2fe912ec1334ac0c2a0f4fadd7af2b9f05475570ef3baf1c6148f5ae5d35a6d3ef7d9a04bdd779dd5790f79a4c758d5ed6a97152bd2b358a6df7dd7ddcbd462fcb2b61c8dfd9aeb49f039f79894c02418b7cf7eb4b1dd57f8d7d28b30f3e99fc19d723befa32fa00c73807e0ab2fa31b9e5f675df3d59aef2a7fad01ffea03d7b906c2d716e107ee95078b9f6eba6612be9ab30e18c05765f76a735005b75f5d35c6e21eb0a56164c5c88a9115232b46568cac185931b26264c5c80a11091109110911091109521252925113396c1a638c31c61ac735f5abf4cf8240a215b4c7438fbadcec4818cb711cc75d7e4d8d390e5f72cfaec9734d8d31d67a764dad675acfd47214df37e2814d7acdbad36b7cf66bb514f8eacb5923eddc635cebe79c73ce39679c31ce18e33a42f5af0cc54a8f77d5cb99047b0a4cdab93f374c906baac02451571c4c2cc5879f293485a6b84fbd702bf4dca7b84fe5dcd6f7dca7825c562ac835c954ce4dbdc8547acd9d6b72dfd2fb77537abd2c9c52b9650a9631f75fe5ca9fd2e79a5df0d2a77cc2cd80e5f7646672649f54e7f259794c1cb76adea4c6d1285ee50fe5239d8b752b3e4047527a3a17c3ad15db5d71cff1155be742b1cefdd7fde0a37326262bb61f3af71d49ce6a0c974299a4d06b721fa3053ca350ab31dcc748829744c8f4943ea0f294494244e738999e1ac3e53f67c03a37035669469dfb19b14a933bf733b89ff1e4b246d0572628d42a4da9730fba3030b2ce717fff848975ee0a725669bce7729aea35d29424be2fe5073f5f7a4a0878ad2b7b71d65ce78142df065354b6ada2501422a179a66b86a0b5365cf11cb062bae608cc398f484fbc28249124de6ebe2ec49258e264209392a964d24ea4f4c0c46262b94511d330ef9b82e5c472ba15b9c1bcd3781af1cd93dbedd6733bc297cc60ef3da2b47879266b5251515149b58cc26871697151d9e245c97f48465ad4b4ccf42e1f03c160f2430b24d974cd959595952771f20809b9492412892cb7787d45ca5d2a954aa5cadb4db0b0b0b0a85ebe188ce338bec488651b0e2163868c195bacd4669ecc9bb15d5c5c5c669833cf5c99ab25643056db7271c256a954aa13504061c7881123060a4e6c19a4c5a41093421164450822bbc55c5e0a3452a011d3020c0f5482860c0d990c44a6864c8deec56b00a006006e68a783444e0107800a00f854c84060fca6820d1554d0af2637dc13d33569d0a041c3860d2dbc1bbb468d1a356edcb83df1401efb0969cdb45a20da1612eaccac3033d32b4f135a5f81668515f692cd8f785acc9a40c1028586051a4bd6afa0ce35c6898f1314989ce0784d7e3e235ccf0b1670b0c0821638b8571e2d6e32901f29c1d1020e1c4560f2f5cad3040631ee49365914dc5e672248010eb98516401b5d636a4c1190f473f338e9c16c0b262123324e8638d9393580579e2d66ddeb95678b4a5369aa29009b0516586021000110957061b7d0420b2db8e002c90439b60b2eb8007201e7f01cc02bcf1619543dd3352b8d14626050386165ce90492980ebab2f678c4fc7d703c17defd59ae346dcf6401ef89ed51de777779cbef9e65247cc99bbdcbd57670fcc2497d18d2a6087d5598336609ed5a8a40c7638412ad5cc08000000b315000020140a06448201899ea58198dc0314000d74925074569849e44990e3288a428818400c21ca18024000684668c641004d45f237f4d674b779a477583b0691b499f681152a71519ce4f8e4b85b2e6a4743248b01adf5638698b39b6626e50aaf0e092c6c970dbd63109436d4f959881282f0ee6105a5b1bcbe41da753aaafd201e64195d2ccd483ea98529e25ca32edf87cb427480bd8efe55008a6f80ed8851c314a38aaec8b647d7076eef45dfc2f12aa59fb169373fe820fa612999167658e3a63b8e9c1303e6e7b7eec16443811b4378431c3494123f1320a87195dde569f2896bd3b04af380953731aeb41c6e63ffe6941fde280131581244f01722474a052d0bfcc4b22d5e8b0f7fec8a33f0db84c8a83646b4aa37da8a5cd3103e724f96512d00c45e20601d1b6aebfd5546e99987b2d88705a39d967d48bd8b5ff24dc5c0ef2ee322f680d9a64cf88f9c8c80e10aff397924b661f8711f1478d9f7173a9b3d0b78102c47ed2f6d202d54f9941ad4eec06960ea6f002be2f51cb14554be43dafc902e55cb6b2853707b9206d680016214aec191fa77c41f14db707afe17882ce89a09f3288c991090a6926099243ec50786aca515fb26518b2320e5228114c575b28ef9267f5862b92ba9a0c472a384cf0d84c96ee256a076b45f2f338691d04371264153e39209fb880c36a340a9ecdb831f702d65532aa655ba91e3212762478738b29e767b6dde970b084d6cf46b87945b8a171f687436a0fdcc6e4073b75a734870d974eb72d9005438e6a424a25f0fda0292f8782056499284791a78392b4c5561db6ef489360b94ceb29820d2bf87c4a2d2c557c71c810b23ee1fc9b37085eab5787330a40c71a126efba5492cc55ebe58918b0ea2535d50399a273582939f353408f258058378038933104051504b2002ba6d6411c562fe7e45130b9bed7c09611a1f1e0e81980d577ed6ef49d0c3431be5d382e7581df5c000c5c083dd74bb113de3a7eb62c0ee14e9e7d82517be26a3442d9049ad6b827a4b9a753554d25ee647743b02f914b3da1443adef98274ef47ec2d4970fb5e8fe2f616697b3fd2cc5e64740383683e593bdcb3976cfd259adb9509dfb4196f64d137b26d06ce80ce801ef20c1a43d0201c8d3103baa6dc50d2c71ab742a1c29d4f5f2203dc6b2f202a1c9a8c801077762b3a397f569910a94ea644fc260ad825c0ddc1eaded84d6205cbf645c7251c46b613fd132f1739b8f9d48ef70461aa03fd3e59d5a806b5d648ecebe997f428a0fc1c1fcecb636b0c05449140575963dd1d244f200555c0165cb69acb94dffcadb7cb6071699eeedb73a521a7c65a641f7836875d3a2ba9f43ecab5d053e690d1c3cdb2e5394895184b02d0a0f8e98416dfe6160ca1f462b4a102b44f5a648b3468ed860f2b982e4df3b79da81ca450c2368105d4aaa896c2994f06c6ac67e23c3094af15154341600d502736403da23bbae80e822880c1f626f193391651dcc5ff41c79a4fb94e1981166b7075ccbae73512ff558cc57d028d24945e76497fba0651d9225c1385c62e6033dad6ae7dc995d57978daa4e9091498811accb4fce4d8a3596783eca7ef52e1daf0133e212277d49dedbee304f65878229b011ad5e3afab3f4562c38049d353e84713f7dfc1ba0f882de3812c76036a24fa7e31116f9949b008c328baea9e8fba20c57658210ad66d53c03e8032044bfcf114bc321d248fa19916bca2ef6bc85f10baae0871e132753422d5d1cb109a2f2bb99a991c403d3ecc5892b9cad4852ccd324744612363fe3d1f44594befa9539a6a1ff3b888dcd65a6d3a2bdf5c6c57cb4fb64f1ef407635e398db879d23a34a7e0e4107ac43fb639a8f60b5303bfe58c1808931f3075c0985e23d51edc4e477ecfae08ab6ca591139c0be92fa2d54ed669a820b0700bd1db345b0fda74e47747541261ba62c4d84b519f18717c76051b10511a2be2d7e81b977f116cb9c78163a82df4c76f3a8cb8de50491baed2a6d540c22888424619987ffc51141c6cd423ee0eeaf60cead497d794a6f024998ff0cf8a4668205d8c134e305dde30a9e7c4c3e2931b3da4c1200ae2d0c15e137852e64393f927f5c8f62854822529c9630948f135a3043ac89dff58711a4686017abd872b453a36413ce23b3791730523d3f485a145f9a18ef1503df17b24f0c9e4d90af09df35dede149e0bc07df610cc378fc2efe23deb18f69bb77e0f03ec2b83c5779c2674185b95d138f296a7b7c0c2feef33e170449885773414c1a2c82d938177be1a324b94b46f73a2e99ae15fe20189ffc7ff8a7b63b7a42f94eb4248e44e6f4bc90184be45b992107fc61428848120a9cc8a80595e67c15eade9b1f36d0d8f72eeb4f00a9704114b346c5b030f90701bc519d1334f09ce48b0f411d22aae237a31038b8943ea8b6f656c86c4f765856e350c0e75b7345066a9f25cbbada174478a60b1b5469120a992fb6bc1d0670e7d3bf84c480ab7ce0e95080fa07f7db966230a512d87927d09e1ed29c39aa5985e1101eacf7dfa095d4a6dd126b1cc899e63c5f348ec5b2436ccbc0c009d3f9e0922d57342436ca2756e3be64cf8705e4ba4825f3ab2164d69b191988650e4bb078502fddb6be526eff1df04e356cb70799e9a9e32ea662257e9954ff92a183b689bfc9a3f440338d45049ef47da4e7451318abc01c48a16f0313a26042a4fc52f87b60f3ab57864cf0be7ec4bee0e3edbe425e7c9a2f2e1e7ae92dea4202575287df96bff5e854faea9c59ef0b16bf103e82f98593c65ce38d8e1de1574218f0d54bdd6b90cd82b55c9d2462f84bc2553717815d9aa27342f79c07a0e39518013bd24c4ee6d0f2988d2f7b7800f9e79cddf04bd85d7050a0ce599ca76c41898967f12347c3971180cc38ee69037636e6571e6d38ce1018e0a887019adcb69c75959b5942e8085a6fcc2b6e4c4f24747596309fab55ddf270aba4b705102ea3ce02ae3bff4bf1ba9421ebe75f91d1e617823adde607613be14531a2f7950fb19579e6c1d02431850ef4800b53916c6353b456c604f652a2bd8a61675559821e1ba54c223ebb80bb3a2cfd74f000c286b2462a73563506fa6561c0c3fca19503039a5b21d46a14748f2b4693f3258a0023b7da4845e314416b26a5ce6c9352aa3aeef62eff1f32905c564ea943f2005e9e5d21554a5c3f275cdea10e5494653dcd590c411673ed0ec04f99cce31dcaa38e1170f0a4b46f75302573c795447bd53de29a37a6e8231b6b64cc9f455e0fec5ea05db01fb5039db09286d35c2b425acd06a78fd2536ad421fb9ca79b1623604d208ea5408e766448b7ab4c650d15457adc54ff811436a01e44313da42bd72216897bbc0ace300c0286382f536816b3a41d839aa84c0565bfcb50e298ed88c5656359b2e3fbba2b447618558bf678de86620c7a89016758210c34e89c11034965004bb544ee911d40ce71d61dd82e5f42046e48ee8c18271ebd11b05ab4a563dc45230a9afc8d4f8c8c68c634d999b26397fe95db1eff5e3de9ccb656a85b2d7410324d66361dd6c40a933ba5ce40ac30dad4447ba1d573b6a7d7af4223695624d732cc7aacc4493487fce4511143cf8ae56cab2bc3342eaec230c3aefa4f1739e9045d9afe891c8c428076d6ed6a198e2d05f705128dcc602579e602c7f4646364e9fdf2dda4d82b9b2797e09e164bbbbd296f1b4626e4bd3b5dd48163ca309a908e0c703638bc241f9f3a32dcb61a5452696b0bb6858fc85290268bc6d7888ad71cfc17c2ba8f58f3db2e15c9db28927742f95f24e7485018b2dabc18f0a252d60a6df770711933cb9b319a216bc8d02dc68aed526f22e928032408b75ce4594df6acc4f59b0532a92a1507ed568dc9a82a069586cecdd950d194699d62a64e2d4b2fbadc5644a2b7901e8ac57a8207c1fbb6e10cc1c2a038978b7f5390fd2d66af54a136f290e605a92c0394b94bb6458dabe88d574e7f47ce01fa0936b62dfa600f84fcb6b79bcd5362252c610a18868a8900f846711054115e6780079bbb78a7e59ac70103798c3f8cdc58ab2623822a5a89997afd130eb3297aec3e02107cff6aa0defc74889524418d3cc1c4f965db33b16c616f0877a20feb8821b1c2e717be7fc74cd3bd166cbda09640297ea224b4efa24670b319135f4c264779000c958bf2df634fbb264810b843db0b0f5d993b8d45aee47c2e9ad34b17a59adb8320c664d3602e2a082993b3d84221e609fff0950610d6459b2a5d0656ee14bde3a58498728ce2dc20a1d34d75bd75b96737b9776300656fbe95d66112bab9697c490417a4c3234242a7d452802def9f0fd664447094aaa935f79e89b2791bf10ed6402baf146e968725e16b585833ff3ee7f92f68f482d53686f7acdc1e405187e00d12f21c19c91ee542084620e82a17c7d41ac31c0060159ab9ae4b577022b4f30227f36658a12c7b5fc779a38f30de425bbb26877446e1deae07b753610f57fe58eaa5e2211ccfad7770fc9d67e35a3f4777ce0f7a6e51570fda94b19d23cf5954016d0bbc05d801b44a017a2f228e6d9c047a2e51c7377626e8142a2fc638f51f34c781e969420c2257153b1570ed80b63824b09ec4d279102858bd56f3ffd111706a9b91fa2b0b07f02f0e37586112fbe47d35c8e68651b7be526a8164742b467d11def594c3b1ebad65e38b55025db90894f0d7e4ef1570910228c8772ca0a8ed5ed9b4a29ca28510d78fcf1751445f6b6ad9e8ba1c0ede7db1c7145c890dd2c420e66917ada17fa953856c308bba1b732fe8813da0d4716f9e1bae3aae8d158d95137212869af7f324e94a8ea93d69355a2663e8310fab0caa9dcda1c77731cee80c8b1235477de491beb850e49de4ab06208fadf7b0f8ccbe8187c63c61fc48b29194029e6c7ea972b397642ae88897314a1dfba4a1e901321d3689ece08960d870502683c32011c215cee909e263cc2125611a07ed50aa9d357e1446c120e895263c461ebe28d11870fe3f156b30300c299d7ea214719735222be949b8c233af2d14fb3340b244cea806e9c5beba133df42ca7ef587335b2005771b85026628bd499262c1abfb482f59f5005ef5bea154cf98160051b4566f2069be72684d9c9dedab219dabb704e4e69d47e4c308e2fbcaf48651656adebd3b447998ba624c01fa4349b6ca141b14440020f399d6f83d474485e96c18be6cac725374a534539d8bcb6f68d95df306ae9ab39d38b4990b91bc0d7f6c3dcb828421921e2218a15756cee8233803e5ede3c571894842ce979f3424e3d5bfc33dae7617e4e40302d24b3632fabb84dff62d4532e533c87873009e87d44ec75fafb2c4a76c2a280a75553f11bbdb42742a253302572b4c31ba65f3511474e280d63f7bc08d599f6e713f771e790967488c1998356d8bc9095b980e092d8aae020e2ab147e7f57163895561cecdf1506098e5402629a2c089fdf950af6c3c96d0f27050de279f67b3b4acc63798d493b485c321e4909c6215c263260598719dce18d2e766dbb942e334cf212e0049c5dd970fc487947a638a7bf39c055f4340cc9e8b603e841e9961682944ba26d2118df315970544ff3e277602d383d30a0a4f303c009c9877fd3a27139656b5258d7bf1e31a9656686110b002d44a0ddcc75400300b15d7397cc541029ed2004471e184dc66f01628eb8a24c3b909601e781549b3109f443773e6d4f9844491488ab110b82855c9e450200719efa05ffada5c47be8b32c5cdac1980ffbe1fecd811ebd4d69e2c8d8060da5cb8649a45e634b176f97ed1081e1673996231d87004b991c8362ffb6a7db95da8dc7b626e3acdec8222d92625b141ce2b0eba7d8bbf232a3e598fd29903f57ff57f8c93f2dfc88a1da5d8f81250b58b28e05cb58638d359658606d5845c42cb063083ca429fb8d4ffa1ec77215721a167a85871e81314c5af30387481580eade3efd08bc18d01ff355e909c07f23ac0ee962e13ac86348a7918cdfe2150b70046f244bbbc32a1c0c4ce7906bcc5986a2c1384bfc980cd442881426c0fb7f87141085c0636be2318263a2bcfbb10578fb03ea369cb19c9ad379fd014ab39ce3c47a8a3855f3d970cf5a82d07e95aceb5a8e85185c595f6da70aecc10b738797edd39d867d483e665ec5fa2a71eefea558f429f5f6ff5372219a72bd2953af7add9386e9ee7536bca752e16b95dd7fdb8e0a0133ded54b47c965c88e4c18204d875a13116bc70185bdafdcf2b3b9498d92c4f8b24f19ae980fd655a033c0e8bdb4c7c6f14472b806e84c5bd6a003ddb95943d0670b17b07adafcfd8203a43d2dcc77eef4652259a4acd7ae0904958cd6439ac90ce0a3cd36d286bdd1cd4f238ce020ff32f0175458e884c30402f60f80aa9910fcb2796cda51a1ff18995141eab871cfb12b86110090ffabb7d853026fad827888dc9e1b6f5e45bf07f88f3b1a6130607c7d60a991c35990c53c4e16ab74ba8751c08bfc355edca9178131e8eb6c1f1b76d45cd61d08904929b8807c9e5d353df92130fd7d2514da5b7970511d1be8b60d098aa10a0b33d804d3b27e6fdc52959e26f4cdbd62f43342b304448a1518e398e677a0511d408d59c1220145aa30a6083eef48ad8a04584b63cf4bae50f03f529f818d9695ee0f3945f6d52c27a5fce2bc8eabc78277e2597707e37ddb4e8c6fbd26673a72c85ca6217190cfbf924c807a7e3f270bdccc41420116eb67d348c85d9965a2a1c8fce6ebda96dcabe48eb630c1d941265f77100489ea8d415323bf78a1a923bba243c965fdda907ee1fbe978742ca380854d0d4c96e0be6ab9bb2b65f748524d26d8bdb7ea98f860ef9ef1d608233898af7004c164ba43865db47d6fdab31621bb48204649841050b34400d9de154d8ca83e023896fd7fa2f0a0c433f9acdf6280cc72cab8106e93b87a14ce1ab744260f90190db2106731855614701ea3c7168342fd0638936d70cfb8f67e72f67a091b8da47143df929e08a2260a3ba4bc9c4a1cc1cbdc498d69de77254909cce41219841379e78f7e2d30cbc21744d0cf7d257e5ebc95988c88fdc539c5d1ac24f16dfc477a2726344793340252e05dc8045c884a0f70c0041a4dd1921c00324384dc6c1f539203c36a6b2a0bd595239fb791c94807401b89646c7547c2d2ba36e99a1d17a4e0a0455141e77b041991471f4266d6abe8b7fb6dbbbb866165469bd56bd3ae358ec71273d3bab8113fa2627151d28b85bf5b484b98cc3fae651646345525a9c3a165ca63bb4351cb3e2750320dbedee971b6a13ace50f9c816bdac2c42d87a70a1fdbe8ba2fb37eb088936d0e01310fd352ebb7c17f10372e196b8d5c4268fa52d8818b4923b72a9f88b627a6fa4240031c93fdc314a4d6e2e4d38e0a518773fdaa0d4a411e9c0ed4ca97a0c1de009d9fca920085aa2811a3c606b7a47d9e1043776fb139d7ca08b20939d26706c8abac48911beb4ee136be89e98fc1646cfab8c815399ad5371b6910861b72bbf3d95f7ab24e47d885c1396234c53c55ba083a81a997054da4484929b62f32f12a9a5bc1b786d380e2d4bb4e1140eed9c4559411959ee6a3ce724c6776eddbd46154ad41036886e8ad19f503b85a69cf23f080016f93356f88b741e82034a21a798427fd8a87dd8d36f8d100eaa438d2ab05015c43b2e4ea015d78a4d5c48a59c3265c819a97b1923d74eff97322b1bf14c6b05c14a08f31f134567577fa6c88cb53a3c433f5ccf5d5aa703e10513fb44353640c37bdde9fa79d1a8020c811da411de2df16a3dcdd3736b3ff1f9ba5e4961b248bf71400bf9a91f187d6ea24f72604b2369afeb05b3af13adb02705e7afcdfa6fee38a102f5f5a2266ecaa4b9d80317ed1bb95ae8f47b539ea3a54144fc815bc68d49ea232641dc7650c24a2f93508bc48e9ccc5750d24a307ad694bcbd8992e5e4de97cc4eeef6ad5d020e051aab1f4cf268507ece609aa1035cb58a71c823193ed9010a1c86b6168f6c06f173d4d34fd9ca1f8608808b394578cdc3a256557c580bd7fcaf40c41b84c5a211f047e2c09110e6158af96b273acc6674656417dbbde1f4c79ef68e38a2ae7b184789b33f04da185b2802f1324b0bbe3eb16ee2c8d213953545d157c2773ffa75712cc16d0c9185002c14781f23609c8d2a27955c1e6536a7b1bf84054bd4a21d1c1d4127e109c81408add52892f5c7d57e6c9773564d30026202433fd762279c3e6c7ce47a618fe1cb47385300b65a1a75ab0963aa07c8ccc681c9f614efd2bf0858bdaee7858bfed316cc736b713f87b7f7008ab04850ac3b7275a3f79189abd4f1b9ba2a9d238e179f870ef03240ff893760b04d18fa4a420748e32046ec71a03bc4239c0b0c966c51d664e7834dcdce539014f7d0741e41c2d3e73bd69ce2132e01c0a949d6e1157bc0f5128013cbec60e1b6d9d171bdfca5a732b6918fb04768be422a83056847379cdf67e79c803b7f280f556709ff34ab5f4c7067a9771712523a8b1a14338ce1c00fd58f4ee25e568aa16ca9ccf58ad0944c53769c7c73a3aee6c0a1c29b7b303d8e652f5edbea40bb0ec74cf21751d73e66176ab959377983499d671a61107b6aec173be87e9a670d58e6db86b61d9f2841518748ce7e254b3019a4fae53b4eef04d9270cf127daad677482ac71a6cf974d9bd9497fe202dd7ed8480f93323b1812f942116171e80b76baa16bf4d009e1e1b8d6d8b7f47f98def075a3a24b476dbd01725b2c1a27420aad62612e2004266224fa73714acb038b1290f77724a14a0ca2c2a11c5ef556a413a484086ff5cb398d081e2e35224f0fc7b277d6a2e144ecd66b61031ae6d34f2bb63a0967ab89e89c590f36505b8d9873e1bd3066a869a5fb3016f0128f5385b238f019deda700d00268a161b38a021c8f7e33326566d485306128475c0cd40458e650807f01ad57615629bc7102139c302ee12e666981139cc646d37e363ff326b6eb4f22e5467ab1cf6af522aab6d5c0820bee3f33854d2d9ca47499b14bbc3aba5d61683e91281f585119ca0d120f082adec3bb625084b5eae7ea77c30973635043735a3871b04cba42951c44250b2d7d997f7efbc0127ac35a24439216de76d4cbdc09ea7cec9bceed29996c71e834f26eefb9c71e163e7853a3b1eb0bdf3f900f6f3c67f4e6e3561c6b4a95f32b7484f5ee02f0c4009bf53b132a599d0c59edad9d58c9978f37967cc3efda69846ae86f6beb459a5e55b8fcf262a86205243e10a838eecfb7d267c67c21964d640eadc0ed7fcff69dee506b0712dfc49f1b2228ca8da3d47b270e159c03fcd395bbfa6a0c98395825241f79fd53b5409e55866ac886ef5ebad40a9f56255d7093782ae92a7282ccb0742b911b9b0281c69a8b7c1ea1ea1c8437f1599c64992e42598911a7c7a2c45199cb8f065bc6de856ad963235172f4ea06c0a396a953a9ccab31fa07b8bb66fb8c9167f5818b41a2fe2eb2c66bf25e0d9f1d88670b713e7eb890c19034b3832edd9331fbd31ab26d46c04a43912516e3857785ffc053d1642109282c98d273e0e0cd2fdf0d7bcfb14b107fd2a2e23f521564a183e0904458a90efb9496f29537447ad51e677ae9a6bfe415e0046d8936da33477383530e8869d27974c560b70137ab304d51d8540e37ad0d54e9b66e21bdd5d054d267b12b56448883b63c4314248c945f86c4e98f2388f3740be1c33160deea59c59783bd01b7604965ea85a89ff121a1d0864a51c300ae7d7904abed21662d6dc0e82f1fb73b63fe1ad752052b9f356254ca360a0df11211617527d645a5c2982725dfda7e37fafd609c39488aeb100f292c5a91421dab3af5249c4cad932b831218cd999390f418df42e42fe13581816a9c87fabfd8db4d1f5b40c27c0d190fa67562557d43a6bb7a0006ce61b94b330c376b08b6298daec07c93dfbaa6ce4271011c8169399f905e3481d14a686500aa3d7f7d4905e3d2848bcf7d1b044ae79d8a35670fedf19552f760b29e00d49d17124dac6f898188a12ec4181ce849b27e3fe6c7c2a1991a902f46c294886d4ded80e1843d59ac312d1296cbc40b0c1fd2736547f2ee224d8ce40452d13f3bed42e25f845680c32413e6543039066b00dc5d044cec66588282f33394dde2342f086c653353d72d3a346476cba0a534681937c713f33c847e449efb60f0dd3b564187c223e8b1d59f04c514177485c11a62f1849488081010ea332312ca7813b60346f98e9fc53e90f89d4a60a605cc318969c930ddcedad297edb2ed2fc1054251bddf40e75aa6aced7110d69367fd2e378e4ff30b8879e8dd06e98cc6684703d5fc300dfd96bf67e0a66dc2a6ea22560b0e595cd5ae117d0d431ab2041eb7ae14d105b2455e0d8a1f3c06b4d96ab90ff84fd6b2e14e68a716564660fc278de1bb53e29026e9420d891a421eb7f21e4d3c86f6859c991ed9db012b297ec9344a7e8f3b0f6a30f53b17f2bf7192737e94ce492e17e5249ddc717e25df06e4e187111677f7d515a39b54bfd163f511c5d525316ce3e8b0a65b7a0f85909a853768d8c57bfb9d81f82114f319d988a68960961064247155414666dd0011290a98c185e09bdc74763995b5a22e9807e2420569b82520382c676798412e819cbf001cb68d96fd0a80ce7be682ceab669134d5687f23499c027323b1de5ff05e6026024d726424d8ba39b7387c6bc0e5a0430f94f6148040ed2e5a387ca8020ab6d1f2cb525ce1f17200b99e9707511b6fb9d93c0ec8686694cd544e9de53701bca65aa9c03e9ebc22853de7c56dc32f1befe1bba01fe83ae7a265100548c4da3cbfd84bdeb6e4f1a1223cd37325612ed4575dd299864841376fc00389fc6dcc625f276d33d531ac0462d8953a5ee9633aca1df73f61be89779f3ea286193aaa2a2f45f8ea320e0300e5106aa2343ed5d5f90125080760e5b261187e100f435250be8c6ad25462dbf58fa3a3782c57066aefd6388695c4bbf88db7e2c5772912037156cca2c7769da005d4d23d8a05cb121aceec87a705a7d87506266a880e2bbe39173d3bb2ebcd0490dc28f39fa4d6e5e147b177af174b0b7e7df31fe941dcfcefc336aa2bd7cbc51f2819cf4e60abf9f850a8cfea60c7e49091c15ff0c2842a7abe8acc150aa12751b957ab3585602813f6bbec11245aad8a47f5897316d3004c6fdfe3ac689d220e8f46d536b6072c33dc56fe3ce6e009b3b64bf08c71d48f191e8559b61fc8e308873f377d6c24a1582fc6c2866b073e51eb6fa02cdfe2959fd98af0a06635264da82ab07db987932f1384b3061f74b67cca7551eb9944a6d1ef8d35cef13763c28dcd7547aeeb78e6c2386e2093de9dfa5c0ca41772dd9b4a011b74d44d463149a8bee34007cf500a9f2bfd1aa040f2a11a999887c34ad9829824f29a8b3dc09112215f7d8777c91d8dada0bd0eff107561f82260d0afaa7e99503cb7ee31c9c6958f145c64d3770c650810d765a20f4fa788b6e00d7d1d364151535b2fae02a6f816fad99f4fe3af15a554c9b1d124daa6f7f3d1a0201deb1303e1866423943c4a5043458474ffa778d7fbf4da2528737bd23c67dcdf6c54a54eecbac8b8dd1304b74d16c2cf9640ad15261d5bae7056b2ea931fd716acf1efe94929c02f4fd2a2ab93040117da256f4d32985a07a31328adefc383267205d85460f3b63f3906f9703b79cf604eaeb6b4cb6a450a58fe25569eaad1fcbeb371749b7e5d7a1b200e38b0dfa769261a040aee5ebdf4d8c9621a4424f146d21fd408dbed4c6b75c698bc568ff0c2cbab2c36894dde47f29fa6c74a632223115a93144dd4566aec330ac421a544e488ed3ceb4ea6d4631f36207d05118ff3c3773d757ba90550c511386cf89f2b2d73b83032c0ce314e1cfddbd743cf325252da681f7d4d695c5309ef56b5109d32b1b2078c5e19e5084821850b824b44da426917a8d0564c04149501afd47a32f049ddee62ea4789e90774ed2c49047c147d805997e0e01fa224b13bf683c369d3ebfce966a5ae53bc2cd27900f39a736734a0506880660b36fbd788e2240efda1116080caa09d88159abd68e7a08362571086c1016bd547843f8feec085961d7d1666ee7a67842a4d10f9e6d259e2de3fe4a97ad8dcdedfacf482e682fb80d26b3a5479844a8f6d3d804ee01fbd3c5ca988b184873b7ee3e1ffde24b34744f721693c6f92776af46010cde4d423fa8714b7b5be8f2cf8c24c06b80c1912cf4b02a78100ad4e6089b064f57521da2a4fd5d36515de5d4d12e0d61cfb8c509eccf5081c38230ee8746e086529689c4c3c5aba6155de42489356592001d21fe9fd80449656f6162e9e9d8d5503bc298a51dce4677f731004ca9c7827f0c7aad57406daa1d3959d1f0ba12b08eb757b909d2de289f6885ea9da8f484e782eec7f177bf0676f4c5b62b693a98738a38db79a8b996dad707c79935f0b69fd6b8392a4ed761ce3c5a9e488da83b4d4193b03474807c05d7b1d40999ecbe968d254f30181a1190d4f47d3e1688c7a15cde2af29b055ca8c018e38c1b46109cdc914006ea85e819a9940f3292e59b094ba70889d86f82a3494a35b0d36946a8fe50a9d19390e05736d20bdf78e03931676bf167661fd334dcdd768c6d3d389eaea29a6c0c9ad7e3b22d814244c9be1da04c76f6b734d5801854c866608d565c27b532fe235324948ba665d7581a63ae4c74edbe239a4c299668634eb6f9b0debcfa1740364d05b8b6dfbbfb3ad59f90164a6c4e25d1079e218be9a8d90f4f975e11a40231ad31f0a84193adf9a586624ede8fde2f82930a034ef9bf78e5302465132301587cc224a1c933ba1fb15e3e06e64d354b80083a5aec0df16677cb308aed3ecb4127c8fbe2bbb75b6d74bc80595c843b44ef0cb97c1fbbe2021c2e0abcbbf6387bc26204f06f0b54b5f366da6894476a326899fb2f054fdb7322ae7acccc9f98519bd0ee26383a26494f72bd4c3a9c29df189fcbf22e970e0ff452e23eb14fd572066fc21d78306a6d7791ff970ff3439012ecb68a8172e4259929826a70aea7f481f67821cace8ac89d24bc674dfcb0eda7bb6719f65255199012b2a0fa261b43e6092aa89df42f50fd8719f80d65f8bf2d44fb9d255c0d675a8bb559a3e00fc239f6dfa1ae13fdd90254aeecd439a47f160c5f3ce4967f909769996f0a2f605642b3ceabbe8d4b5c35b304588cde22d8315e5a6c25513d55fc7badf020e44620c11885955597b75b322b38099ed792c45ad7a800974c83478639ed74817a829a6b3e3cbd93efb3369414890c21a2cfdd138d233c5c3c86819ac4946c183411815c800750012aa8975f21637f80c5ca9820c9031dbef41018ebe665d94989022d5dfc4cbb48cc5304a37b3d0346c2206a6923713a9b5861090ec766004b062763117437282185909c46607920d650369b2c6ea4a60176b84195b3b466b48ac0c0954a27aadfa43141ee41a623fbf7973fa7abc3fd39aeb0da67e375b560ad173a81c549642c38b60feca4f5af5a22d2c0c052d957b26a9114d603ac1d72949f16e22b5a7e50b1fa8f41b5e3335ff344a7ca275fe532bf69c59cc7088259dfc3c70b84447a1820631a44acec47c17475ca1d3e4f66c5040bcf20116ec46d6be440599ff79e595459c025144d068d7e99a99498eca2b3cb0fe1ebbd680441e38b012c9107c2a0a4f0986db80ca43dc29169cbf6ea652067996e0fb18a593e72fd946a31b5a96d6e13cbb289e9b0363e06d2787136a20934898bf9794754014809172f12c3b188849dcf440b2c71b86c74aa9b6cf422be1f4b2c5959e701861d0e0152384f8469cc383c767a27aeabf820251249ac1dee2bd776c4e76fc5c9f52d33e557b2a4d2014d75b0970c737e309cadb5328f2cdec42756402f26ea47e9442074bb7d1e68d1dc0130939bd5553ff3dd19d6a891795fd0ab5b450ec39c3f2e73e6c3598ce56aa5a70046b8f76313ceedae0f41c1138eb5d0b2262e84078465e65299098ad4572406314dd45d2398c0b1320fda86f30b05adebc45607328145457364660a6a9907a12789480a8e0d9904e5faa5f489be67d18493ad1993be93621cebebc13b5f1d1647ee2d276de5521e6a7ec6f51c645558e5d5b30cec18cc57a321c0ea8c4cf64295eac0bd343625cf27e48626ab847c61ef6fed9341490f20a6ebda6db61b0bdc57600b9a0292bdd4a116ecc1bce08c1a4f104a21f072ef00d17606449a2095d2c45a157573acd79ca63d812ef1eee0a1f946bb511cbd042c5bee9de85f765186dde72d07766f78d3d34f050597d1f0fd7bd1266d8212778f48ab5cc12f1db670f083d33d90b989fed56e9c7c90950d5f44b5439c0eae9729be93e96ba3158dc50d9b4165c13778c497defc7303d0168018ab4e5fcab976cf19b94395c3f782181ca596adf6c9224a71cd085102231fc997ad06d3a5a4cea30063baf0d2a62dad5ba7cfe73adced2d2c90155a18924c3b1092eac582421a705f7261d6834cbdd97932f04fa78d390a43053f33e41d56c1dbe387396300b368f428cc59a3e0c8b0ef87f992b537ad644c422e55c24f8dbd6ff740c2e15c655917d74b04bc85c0a83c56c6fb06fe208a445510beb4bdad52a40963b3d590be07a4c9485e4e5844c59ee5bbd09d326fe29dcad0d0e0ed05aee42da68e5092f3ee3ad436950a929bef4539bc8f5bf1610f7ce38d95d2b1a93a2cfff75a330a852922087345bbf615ab986a51688a6406addc0ed5f03c980b63a4afdb9357e08dc8eeb1696747a1148f779669adc202828e278703436bace20337e90717c110d4b61136ecf94c9717cb333ff5ece9ee08c37ac3c50278baccf622d7927ace33704064acc5fc66bc9c5fba9f35bc137306b46a63de0d28dd95e11f2d96956d492c39bad242644418775c16352869ca5f80bc2745694d6242af24c5cb9d038db97b310bca45cc20185d0242496d4c48565ea456203078a4fc0ec64e64a3ec548ab1de996825a0438f2129b59135e5c5186c1f002bdf6fa6d9f1363962552075e0abd7ee4fc5a587a83b4364dff816f0fe143b649a1d7df5605320ced0dc6b3d19347dfe18d7f0199835fece7d9c86cfbfb5f7b4b9c4016821f5d2aa24085c001ae0e8ab2d9f30e61c746ec71cea7027c16b12ee449d26ac6e52f310331d58f0a5ca36f0227f99089db0b30531a33373d4e6c405c26f75770fa29e1d321ba8638c98c5987e4626b8588ad13e5ef8e2e31bde34682c0aa34c2be8b60a15c3cca23db2154e73e5399c80621ba192b8ca80917044b094641cf43ca5f737664ff36f0189ba654eb00a8529418297bf49d361f9434c6131a5298a0fe5db4b67295400a56307315487f2b39f0f33b405c39012668c39ef7f6e9a43fa59cb280e4b866332adf087d14ae9b5773800d170c3eaa01f3d35e32f408aab31b58525d349eb0c0e8f4c97b62cc1d5932412d098e6947b452fff9ded6a1a56a0111ffa4812fff117d6d4ba210af2b773ddd26e721a61153c3de58082c1e00002844b749bb652a3a624bbdf4718a93395b7a6265190a110a8f4b7a8c1dae729e4a35b9587ddaab465b107d2338f780a8f7192e09c5e69289e0450653c24faa6617461fa75fc73fb1558be986fbd0a636128c85953b957bd8d9296300e0eb954ee36e72ed60ee1e43f8e6dd6963cfc8f6e32a616928489138758ed0f9611c0eb98a88e84285176331b4ab0e99989b42be257b1d19f2a4801a1e641cb795f29b421b8e9d081fa56c4bd3efae4b13ab0f1bea7b85a8d425a3ca95663a5ad7a52f37ab0af765e9a5093f55d3e019ffdfff0180f0d2818150f74399b2a2efd7b6432f5a4614646f380d689fddbf60ef914e0b44a6f7d7d528be244536e6b6d17d3bc87e8ae5119a203ed875021b7e7fca0ddeb01a52cd6e4a246907eb598d3232712e2211d77565d393dd469693ae8b7f6a5cf325a7deff5298f38b2c191b47ef5fc6351aef20a742f13dae7e8f7ab937eff480a1381f4d4554cbca35f4614b707c2e3310b5979ec03d0405bec3a295ed7bd8cf016e6946312a74bb253e8b47085470e24061ee27ac9f43b74c44a5303609fcd2b6be03dd0ba2b70752654016958df71bc344af3f31b803d40b7236c4526b5255b86c72a60572ad80a5f6998173c021f0e7333d66216929bcc0c246969ada4955aad321a31304acb11a81455d777aef47c514a0beaf061e24dc2ed94048794ec3c5a9bec9b8d6fe76ad78ae24044fd6fac84acd796ccf710a7abd956aca4cbd7a24a22151e914ecba2162dcb5b8d3442528ce94d4d5c7e1e89b67b1d546be1c74a0fc06a0c04498c8b67505d2aab21342c84a5cfe936224aa71a1bd51ea284257ce1104672ad584a17040e90263ce628c2a5376ce45d18f729576314cabb534494466fa2df5c7210bc707c703c22c78932b3f8340151f88ff9c028b7f67fd904f680d17f55c70868609a758e3fef4d07c93c2fbd112ce0fd5e4cd596ce464f610480d4f73cec00cdeb8fcc5c4ccf204c27118462473de3e85b89505cbf5d08a72c620935cfe7453399f75c45821b99b64d7acf9cb9ca4ffb3fc10fd88032937badde58d4218027658913aab49d79bc65f864f94a0977b0a34943bb36f432053b4825cc65df4a97545efeba569052a495ff2a4d4538d40bc56a9f0704c7b80c67dfa52b94a62cff5bd1d29d8695b21030f1f9fee98d8c4b5b93e1e42bd52630c80ec87f9f40729ba5cee27814e3b6075ff5d654f0b93f3767ee4bf6654ad529735bed904190bfc5e97d3f2652414763024a3cc136e92764a1589dc1ccde22c5975e0e5b20b8b740cf6853b806565d12b9520ffacb859c06e4426d1ded073e95561727c46d960131f4206cd75a2814725afcda1825fa61b144d181ea9f8d43c9de5ea121c8098dac626e061b9eb62be86260e5213dd172b35ac829855b59eb9b5dcf3025a1219f58b24e2035ea7f61d64014ac2536720fe90f9d98f9246ae4703bc97ce21b830df9e5cd0289ec126f4942a710c2c3072b19e29842a7dc60ed08436a6d33580c0f68c4e33e48ece2c354cb2a0134b7d685c8a24bbdf2e4422713b72b537073085a6fa7c7b7d0f872e894a3cf3b60fd61ff0be38d3b58bde1f55f3b7d9964db85c0a3e95c286f6899dbf88920deaf9d0a90093f566f923d19f0b58c815275dcd7a284b8f6f7784414025b548d726d4b3f05a67f9c09dd1c66d24331cbe8d738101287b9272622346f96956073d08c5df87696b16029fd93ece548de6c72b3fe295f429959568967b1f2225937b818cc20e8253ef9b405468cbfd23f25109a37db9663176fd03ffde17bbb80bbd5e2262949a7ecfdd308fab406673c2a52006d3d60e50cb72f4d0e5e46eb517d538f00b11e123edd34d181d4f44fe262734d021511dbc677522b0dea7bbd1b42878c62a3fdd17034b2d03d5a98ac1f68501ce9bcc81b470a8f6ba0abe137fdc5af29aa3f486510027896ab21baea3ac6134a4585d611d5c2b8372c42e697a1939a88eeeb494bf0690c592e90c234625e8ed72194739753792523d795be7e4733a08a7363c8d08ae7bf2d146a47828802e2dc769d9b07dd34d951456d1527cd241b865a2d400c1035c840f3d74259e5c6915c6fdd9fa6c9e6e1ccad9464a36fff0e6a5605a58b3b7660263c94e35b75e78f8af24422bbe3048bb13cf2a1a2a6bbecc4c1a7a8a8941b9c8720dce78deec0ac38556f1d5fab83f3b1a1a242f584255e23ee4c67c9a93ef0c1aba6cc596088c8e43e5414df768357c7367df5ffa3088d4a328a1011ded1246cbae7ad6894c8088393d09f942370566d2cc41563b65fa25114e40ea51442fffe473e89353c489a25a7d8a34a79c81799a7067652363b504177e7e54b62fac3e822fbf0ad35bddf71084a22e2be13a54eaa80f05acc97a9ff5d35e6a5c793603d4bd04aa5472127dcce509dcb9f9bf463cd91c1d4807fe9e5e989aedf7046c2381e028592474c51598cf149ee8eabba40b05a4316f8605fc8511c4d74eb645abdb918fc1b2aa54953a3d1251c0627a264815d4a82631e46c3bf66e074d84250ac5f1bd7fc6968b09692043ef573c1847f8c16f8d441e06b4aada16cd4a5b792ad3dc18c337dbfebe6b0c6e0bb64aa0f4b843aaf515638700d876b50b803f0be13036622a982a5e2001565f08359c2ee6215bccdb79f620e47b409c778cc1147fede915eb8842acf6545278938023b6006720b57f0802f9a504fd35819cfacde61c00a9ff2b718b5149f6f65434f0d4693474c42b528c49b5fc6552394070b6c858274e3a25010e109ab43b4a26dd22b70d6adff72344f5d55a9c3e73da594ad135f1d4edaa6a50fd5ef21d4f4a5c68c2cbf4b3bff5655087916f7783aae35a82c3bab2af7c8521f5ddcf412ba18852bb729a1356ca98dedb4bcb0fe71c805977cafba89e5da7e86b6dab5c1bdf68411ef17167cf3a719871402e4dc8f8f3444da7d746c66d3f6c3622f3dad72eb0d0b98f3cc090c54d00de6cdf2889680c940d841bfa21e4a8cc3a45efd3e6940206afba56456fd0216e63131efa281f7845d331b507d1ccb5a5701eb803afc545027b4d95c1f6564fc2b56e58b95a5904829ba1090bef28ecaf62eb3536a79d2b9e998b50cd7874020afec42203541518e969c61cad4c4c8665a25dc4bb4968edeb6512df8dcb85a15d1c4f9441c9d64514ac82102721f4cdaebf567a2fc7e37dddc628bb7334ea65e9f4cf792279aeaf6096d3b22385c5838e5f0ed219d85b1be6f4eef2fa959a75d2d4be9ae92400f8cc8c62b114ab36213429e02a0f1d07f181ac88de9b76f7011f16d0a9d8caf43574324239fe4491d86299faa1fb848e19ceae83dccf71fe7c3c6b7e5b0c3d4370f45049faf9403a8fa2aaef4402658e4bec62bbbaeb3e1b06392e67d9eea08dcbae4e9f64ad31197db66116c0bec7a595b288a9324db450825bbd12b684603a24117822d05afa2fbc39eb3382d58ee0c7452c43da3040da42269400758be391baf90861d3370a845c4730d8ae270f8e3bff94d60fecd961b75bb13e27097a59a082a958338d4c0792f5b93007c4d4f92400f0e83780731c983ec89bc0a4926346119e59e5f485fb4f7d567df0a63185f863501dd2a0b3be51a06a6321514ce4e7b682efeea68ce1a7dc27738deb3b2d8b90c7d567c824c21dd1bd9eeb2bbc528cbfb6b69546cbe93a14a7aa35fb4de91bac81c2ba3b92828aed16d1232220487c7c2ea1aa953a4fe469d6f3030ed17d1895f39ecc3f092390e43fbae83b43a7a5e1ab86a1ae2278d6091858e9bc754c9cc8dea319048a02adddc9345f2fda6a58a58ef64b78d2c7e24af3b791a9e2dcc8158c3c2dcb7e686ec73900e58d3ee95d2e34a30086d95be0f5eb4841809cf55689c096b31d6f4061c7ea13eec72706b332def3a47154f815198a2e0ba1e480de02839c343e4b79f7308b8d8681d86d7ef443772690bd7e9e7032b672e701a1b77a1f1c012814a8d4005f75dd937bafa0a26985eee3d3db041c22d2b8a0a436534f0f4c2c093c97e9f135850b66495e19c20bb8759c98236eddb2919099e9878419de9fc54a7b9907ebe81c0689007bf4ca459d1aa172628cbd32a1f1fed75f3506e979f0d45459595d379a2881819746a2336489d4bbfdbbd9ae03e1b18e10761c6052a2a56e284d304ba824b9892ddc021871b8776b841850381692935a850e5a10aec46f1f9dec850a14f02bfbf0aaec46dd4e6baad848215c2b2e15d83ca3898fcfa339e4cb37036b13e969cc012052b2ba1107e66cd596914515343b53b74a8d5de08f637b71178111c1b7e65aa17ebc5af6ef1271debb0c87454c91ecebb182fe33aa1530e56408c11fa37f5580f0c0b75952d7be916699d9d01185ed9ac7f36078d64f4d1eea2ce8e1878a8fc4ee5cd4eb702b92f7e860bd8f52760e116cbf6d9b568091c5b8c2e9602f266effc628b96dc3ab2dfeda7f6c326089c468f040853c3aa0f13d83d11a3d4e75053dbb152071515b9a283532158f64f4c652f374969e4436a4794ed8552865ad94dfa775352e2319e4b46d1d1e81fa9e14019ba50846d43b8922420e08c988aef30a081808e97ba41c6cc0c964ec048819f5eb37ed4d6b8994af54d514fa30294a14a039ad000b14e338d1014f6d873e91f060efa87016c9033a5f87cab3f3f9aa1cc57292ab995187a317454173fa1f9b9744fbfd2a40bb3e63947e791f2d51df44f1e0c00015080e3132a7d4791d1511fedf7f2936868398bce67b9bedd0228fa2ca34c116cc7bbe7552aa1b24240c8eae1cc2d9f85a7f27b7ef7ae9b316914326167e00cd18879021c8ea9dc0a6f8ae67b572377612a494e45075dc35865f069c24e8059be9a5c13e9af7c611b896847c1f03e819f413cf03272bcf79003473b6c0976f02a59e70a29140375967e9cdec2794f75874f2c006f9668cc93d864985b46262d1bc2d6b17002072c042e695c64ae6c2e58e8063368cbc3c20d313067b92986b83ab227e3d9068e3ae848e12a29b8eb248be304a5694fd2957f2837be2a28a6768ca68a8bd3ea9cd6d10b6bb0cbecf4d5d84a45aa3bbc956bb2ed23fef062a0b81fecdc27ed88e0437e8e6c73b4f295a700ef81251c9252640f06950500d43170be503554c960815499545217fcb7194a4bf8e4323df60e4cba08aea9d00034a2b5fa48c6ad1126ab0fb56eec15be0d1dce35c5b015887de28fcc32078044abcdc2fb231d6103761d5e58c9045b9a161865842cd0c54704d8743b7a4c9d90a02e696ffba520d016aa113d2ace435f7b380e5a25595b6800b7cee72a68bce49b9da8efeb729e36ec92e9e51397950a54100df63699bd805fe6decbf377acb324f3122d65e2af427509c93191d2b512779123fcba49d46f00873274375c66360419d7c5dd213ce0a6a714b8acb725784f78e1cae96efc77a520d0482042a6166b48bbeb59bd1b56bca418d8da9d0e8909f948b26ac966743eeba951325a4c24b8fa46425cf6432cb4bd3a9713503d5a19971225c1fdf99b2b7de7c96b2b84f1363005e394d0e14d61eaacb6592f128cff9413fbc0b979da2701b44400f2f95f32b815ec22b738a759113d5de81b40d3d055f00eea14f9f8f956291863907a10a4c9c722f03ac62d0ae340a5bf2e45a1a31ab193c5fd4c29c8d34215b2f8380506f698c905d9cd088204674443303b0610509a5d0ef6ae3fcfb051aab067a499a56f9652dd57cadbc336aa1a604f9bce98a11684e67f96c680418aa58cee1c35f226fdff9f4b2519481df1a0f004d363b3183ff34216c800bb432dc179cdec2a5df6c515fbdef0913a918360b40fd0830e4645e2735e912e2d5907a9b72086cc24e44d56fd4bfdb0354f22d954f4c7c287c08db5719ffb7c40bccfe553f8c0014489fce2a8624a4c569713765cb07480516d85eb4eb72f3663e85b533feff82b131503e092ee821220f7da0ba49d7564d45c265452193766df6032c1b6032dfb40a2b525951148f52950d02b3b4841102aa3c1acddfa889c1a8c91211a20892331c5ba92124691382bc62033c56148a88ac42e35a9ed48b738a760b664a79361e1984b0a2f53964dfc967bec26582f1c9b21fdb3efb5d3985971cc75d9520d005013c27586f2a6bf9281242f278a3eec18077c871f94db9b98588a60bdde584f475d110ceaf88687646cd71c25891184dbecbeb7601e9d9dcd03e020fc1aa61d1b85b5fa359b4bf1e925ea6ad73633d8c07a99c21674921a76c36d76c083fc961e704eb31431a425802dc9403a9d895117c4d2e0cd147b69e2c0a99a9a6e0248f07342ece195264261c33432cfe5a8127cfc091fdae626946d9d8f1cee116957638f4338148cf66e4372d8e157495405b6e0bca98a4d41df697f15c298daba333df5c23655197c7733ea9ea84145def363c79f9a7bc67ebe10de92a354f44b8de685271093a2dbb5e252928e0e16e4850198eb0a3553098d6de4fe1da9fa499f3eb0239416bf1e4f80e12a5fafa55380434d98444c62797bf7a444fa45948d666c3614328eab7f97f8fa9442a241db98e80318938341cb2a3c01a772c611d4ce35c167df9845871da8bff67cd3993824d44195b778e68476f621f3df3b2a9cbe7ceedde9da6cc1230d9dcf70660288434c153264dc6617562a8036515e3dcfa6e7b555162f91bf39b7f08eb1895eaebf96303ba5ffbeb0806f57ffb7f8f80afdb51a29e3d7afc61cf28ca3cc916ed3bdaa65eddc1350e71d5605571aac8560f51cecac153be656e214b95da89b1fa663e26f71d049d17a7a86d3bed7c85acbc34826f4d5a17bd54d90eb8d6e54d029518fe6772412130ac4e96e59ec8c45f95e26579602668fd0ca4c047cdddfa79f1129979e19910b698811f2165cb7636702ed1179cdb3f16feb0def9f245f20ba7c2ff3a51f4b7f4ee9232c10d37bbc46afd53d3862784ae5d68aa873491d35d2800a1d73d4419f619868e4961f92a6a699c125520f372bd0cca00f6966c6066b5e2763ded434a4730d2a8f76bf5900799af3f39e13c230d950e38eca3b01200f43ec84717daf35d432039860fd8971640e114191f1f4ae6edb292f65db8fab53dde48846b3cbe80fa77775e5957547eec46dc43b177f783a4e46ee98dd831a85f2b0a03ca209de8b1226168b7c4380db22ca4494f2444154dd7bd8c9e47345006642a686d40cb5f837c0eff347a8d2fe9f249119083a9c4e962531b15b3c951f5689902cb1b85f6a5dcf93c1a540ec5f00054c142216ffdd1236590249a0601ee2c0e2aee3724f14b268f0028d8523f04c727d2a8f84194d5b06ee3185d798892672b922d94952ff0ded5dea8a185d8f1b25a3e7ecc0502a5fe20afcf161009f37256f3df64762592685b123c4ab7b84b0ae271477d14922d11d5e326d62d9ba8ffdd0fae16c34696ea3dcf7b8f1daf01f606a6c2c88ae4a9979ce89826d669587d390db0e90c8cafb0990862493fb8eb54fa263e65f81836147140e73a77b231bac3756d8dd829d5a3059e94d4843108e1582717a6f12a618470ea7101dc686c0341e984b3bc7893d51fa9875b68c22760bb7c9db138ce43d00cc369e0bc571c6eb18872d3e211aefddf6c043770fd6c8b0aae0f65425e61e7115fba984c9d845167addc3642addb1450085984d4a31662d672b0bf66f5354dc3011ae6907e180ee36a31981255d6ec592249ec84a4586672ce94613fb9907eb26219881754ad51c23ce5932f1afd3a5c3c84b5e89a05cb5439fcdc1ae48cb957bd3c9bd5f85e06a6d5d1123ed20a3df4db57c45cd07f1af013aef87fb2bb958208b171648a2ac8fb2183b6b62cd3fb9e0dd3134d82df2df65e5fd3ab7cc77e881cb9df712062b3e5b1be243fa1147b1fbe1ced2df8aeae8979b2339cb0d70a0562c1c043db1d055b39ae475be5098aaabfe80997278844cad0a231aa6f3dab49f928f1d4d0a16988eeca011595c59a0ced3e1423b7450a38f9db997f296743c8d1b5def11d1613288b223255905068ecafed7aa00a1af062eba874a8348dadb9d32b06b43b4586eb64ef5e058ce6620eb6a17ddde60a76ea607380d543baaddc44311d6c7c80b963fa2aacfd614108f445b40d0c02b029734290db470341611566293d400f85eb8166f548cbb1dfbeaef88c068d324c15ab82bb7295cab13b024b041c2add193f8bfe61715d5f23002cde023760f080008376ca7de31ffefb8d8b6c1cf653d381248747215b9d3570051ccc3e674417ca20b486e2692f1ed70c9890d13480729c14570fe440de35219f699e594c051c7a11d625ab3c9b7e98e8818f58022fb61b15240ceba819ca65d2690c7c2bcebc003393a398bdc59396ef9a75cd5c1b121b4b4796de6b9e46a6f91d8b858d89aaec65dcaf3114bef330ce8c19846ad572026002a7f0dd36deec271f99709e8d1dcbf4b3040db181352469cc48d5c5d44894ac45a0296682e1dd030281c8d8e7412c4a6fde2db46699f7ff035cbd6c58a2d942b97fa1a0f257058d5fe71cf7bc4819e9cbdda692bad2c515b9f48fa3385464cd7ce0151157ba8e0a7e1ff44cfe15e5d8bc1eeb81edd7bebc598465a6bf690c1c0a31c4290afec3a9e09b0bcf87c99e44c6bece0d42bc05a381d72b9b2561f679f77e0c0ba6961d3de1649756b09b94f37e6c772e9ab8736ba41f01a8e7ecd8905c5fff0ceb7e59f3b01ccea3e426900eda33fcff4b02b4f076be4738f1b2211dec03e28c330f5e2d086f174fa01644902d20ba840a6b12aff28e1b1dca4d2d38946699026cefe8f1ece0536c450605d683e8a01bb1fbf74e066ec795f2a1c6661532b126d5b6403836c74cf35cff57d0ef9f02fe89aef94124892bd3fa0e9d87940b483b221b7c92ed2dde8595a1f93087ae7dc8419b5c440acbd4d8b45e3060010c8160c2d18064d1a5a91ae82a97486f35aedcb14fb5d89b1d9ca994909fe19ddb11644f4fcd8e47953fe6b00c35e8d99eb5b1dae21e7fe2f60349bf04d6beb6fc96770a064850411ea670470271ee2105641f14680b0caae2ece2f046ee682dcc9d63b62350b0ccdad4e7e86d0d7594894c56f5719e379ce28e644045633ccb4ba7dce6e2a6c9312e84a878b01efe2c5f6a9aeaf740fe32550a17912945b01703099d463aaa541d1e700a7a2e5c8d42a839637cc212123eef5421eff5406522135315499996991f49829aca33a1f517f6f5d33e42ec0d88a4cef113a1053fbc07a64035a6b28dd49e6aee4a5c110e68cd5b1c2ba565279fa6360130050cf8ceef7c8cea388bdc3b09a5ca20faed41997acc20ee9b8afaef603f4546f6bb672b9da21aef65d587a9cb5c3ad29703fd10e23ba9bac206ad0791b4529e5a5c975eaeac8635f3096f14f5db3687729bba2a97b28d5915a43ff3297c2fdbc13f276d7f76a1ed087608dfa547fbd73f66cdf59b0a0c969b01755fc548fe04b6a8915bb0c01175813df53bd3a13718577734dc23e0448c0a48c7aa0f9d8270c8375fa4e9e1603299fdbd43bc770517210ea6d13379415fcc439cfede53417d3eb2cd83842de20d02e6d3b1b61a7970e578e8d9eb31e43e92fbe28c43f9339616cc69af8c6065689aae160d713c93928cd09bb5606ae4234dc20cc64c64f576d240850e24749b262dedde3ad3b5295c31021da15c22d5dd293a3570ff6a4768a9ec808b6c932776e7ecec236bc0057b0ef0811f828acd8122eccec051e9638d6f562d408dd885effae47b873c2b0424ba616bb52b59244399892e05824ec2adfad668f52bd84c4976d30ff522997c22d3a28d5cb5cd1d6fb6c3c08a659ec20cf76a7e2cb5dc29c3a499626cc7668b119f739c1617425025336ff2dd64905e645b2e9c3e47ca3a3d864138700cbb272e8c3099d296181726c66b7c53638485b9c189dc469f3945acfa0e4d370c8abb4a99fea7c732d76084c89216b92719cac7092e7f6d2e0f9237cab4d0c88647a4a175bdbca639a23910dd628579fd0f985d8cb7bdc378438141c51b9116f2614b45a9d5a333f646dfa57b86405f3b352613d3fe30c87ef85a0abecad88ae8b2eb00aaf61f40fe6fc9acce73f155ddbe5a9e8f80414e5b70d1b2a17e834094d9edc6758d2d3bdad6b0c60794d4f9fae44d16e0b13e667faf0eaaa65894fd0ba53109f4182549c641049a1d7bae5ecad04bf57493bbfbdd00e4b33e46fc45b5e0a538a536ff4854779a29f168279f6f25fa8c666a0acd1a4e0a28f654719340f0b06375c2666c7df29e773baf0ae3e5977b45b071fa512b68838e83f8c0980bd7e12315bd11c8d27a5a31f506ffece67a6c82268dd1aa86c32d2fd581c492326605fb898a71711395910ba65c015e91a7bc3deea6ca4c05505d984eae5095893a170ee46358debbf06634bce0eeb479199df6ff9fff7d983d706cf4f8a47d53d8cb454912edd4b681215263fcab0394c73bc579563761222463155feb3e421cd4919752c24aafc5c0178b3d7d5c85cdf02eaddf1625d3010baa20e855c06a510f80a6463fb24c967cae0c76295a2d2ab246d0c7b8b5be492fee4785666b7daca9b81bc52f531d78677725ccb0f2010c6dde6e19da7e71a929082fecdfadc835873bb6bf5c3a10e4d4164efbdb7dc52ca24a50cda05de051c063deed8d93a1f260f1f3b25268e7d5414fa3e586380368b07ed4f9a4c4713c7de919c399abbacf756553b9ac33a9bbbece7ac6db46d3b9cbb8e2c2885ae0f4ea92debeeeeeede755dee7297bbae1b4d46a6db8c14daed9b8cdc74ab3a366bb226a36d6768289876ce39e79c13354eaf35c60bfdab1d748d154ddf3d00ce4f11a157b3b6a4847ac60a2da3517a25caa63120515450f47c102608fdee62815e0df1b76fc719ec106f86fbf9edb8f2b1f8ad8f2ddceedd1b5befadd70e8fbb68cc69adb76aab15f70170de9033f4f7f451059b6aff391354d29c114c1e74ec503071eafb36f5d040db840435d56688ea8c11123341ee12f74c159a34d54c3587cdcc986a33333c13e4304c7b781493870926ac2b62ba6eb4878f5d8de68cdfeb8503070d1aab958c0c2d85b43f390324dbe4cf19a05d9f9a9e90409b884653adb66a4c4eebdac24f6bab2bb51d49dd955b85c7cec85d479a9c31d5bad25403a598c165259eec8b15d4d66aabfdec673f6bad1d7968968e7658976082d0645d5a85e18ff8e11389c1b4e030705c99f41389d1af4b93476dc15df46158a30d346912599a48cf48a143d6bb8b06b9922e76d0d764822836858625367d1faa3a79d3ca32c09caed507a16189e99a7b8a2964ca04d1ae5f1ca8b68ad4a5da4a095172e26e3347daef93be678ffbb57ee6f971d3d5c70f09e48fc00680f6f79865e389f6ee7d5cc7494f419ed81284b4f8b21c06d4aeef301ba33770de90398752a16cb2e7819e97bdcf60ee7297bb9cf38fb44804e89126aa3431c5899913323a6fe4bc795fbd28a7204f14d5d6ac15d9de48beeae844d17622caa64f8bd09992940a34498180d012a080de990654cc1cfa643ec940cf2226aa6c321f55d9f4c97c33da92b7803624822a6a42c926f351134736fd6c4556aa3ab3c8c8cba65be60429a51bac5aa7305b24ad1bb451d360763185fca06f107c9e9a71d079f4becba2456a2b5709bf7cab3add3873458a08ddfd8c15da737eb14b77f320d0ddf603bcc70f7ade48ca50db9e69e7a39acea212100b1e13c717fc3d160cdd6de63c9d635120017a164d9951ba69d114d9a63446e9671a010a761eeb7b90feb0c36700a5ed7024ebd3fdc2fd8fe57977db3e522b6a8b3a8cd24085b648815235e88c1bf3516dd18f81429344e8ccb9982864a0c840690148eb6fafee95ce6a65763ffaa831ad22c81d511b250ada73e28e34119a084d73ed42f1cddec070b3551fb8f7de4b5bc248d1121cd09e942f3466a1bc3d8ba4e4a0080423bef068c018637c0407401a3017d8c8081a7cc83aa454b1f59e45529ac0369c328da2ea6ad7d18e56f72f89eebaaec35dd7e10e7739e36be7076eb5d65a291330e3cceefed626dfdcfad3551fdf7b6fbdf88e36875a6d54286dadb5d6ba7bb5f606fdc423e9c2fe5defb5eed616f1d562ecf866dbeb5eeedcf1686dadb5669dfaa4dd825fcf5c5b1a1760fe03f0a86bcbdd059a54a96c3ec76b4775c75c5bf3c61d04d4bfd606ccb2c5d65e7b31cb477561ef30d0b9a882db99737de2505a270e7d9f814e9c5be9c4d674c74989582b165b8c3bdcd94cff6619f0c519c0d7bb00ee3a8b475203dbfed89cede541fe9f38ffe15294a525b2cabed4223d2817249088b24577d124cde5bc44a9336c31bef8da0f7f9676f7def7dcdd6bf3b5b9ebba71def791ced6c5d8e2773c4a00578cbb3b7e5fcee1da7baf9d3757f97bcb5f3f6880d079e2d0bf4366c4ba714e17ad310b037badc516dfb0a6a9cc890ee203efa0ea581e8b81ac98e9a2ffb1367d87c0ae97e6d3ae5677568ab88412aa2f871c1d9a3c2a3dba1d5d39c2295971c5f6a0329839fef34587a6804e6892de6895a1d0d2d0258b4dd5a9dded3adce1eb0e2b02be0d1f9b7304efa79e3cbe9fa0c8a2d3853f64c5400008dddf789a38f8343f9276778e502fb0e9d36eb4207935b02908da549dbaef0dbaeaccaaabcefc80aa558d7ceaebfa9aaecaf32348d5b979b6eacf5a6d9b8c61536a3b8b032240faf3e6d27bedb5b44e4a85c0a3aebb1e312fbed75e8b5b3930c6e3161affdb1cf666f17410a4432b877ef0419374365352f31ae8f01d11033f63a6272951ccd3ff69e203fee97fbef781f998f1c7e7f430e30f3d1a7f7ea8d1d167f41d8114e64db55bb170c721ddd7d590fcf4f3e368c0c48b0e68404031d3c77c131ffdde7bde9bdec77b53ccf8e38db50cf29eac32af06b94c6949a6b4848962b0f00c2bf529d525f04997a1fe7f9af878afdf93092016f3a6f1a7898fe951e30fea4dafc79f263efa4de30f6aac46473f5566b481c662c6d3cfd8e9c94a741a57f889c4f0ed670c665c614c848ddc65b5e8195b0da131ef69ccfbd3eb6fe2636ab26201e64fef03f3277f9891c807e6f5f8e330a313b992d28c7d4f7ad0379644c46600c795cf87ff8dab21e2872f8e3f4d5642be37c08c7da3ff10bca483161290c0080828e646b21a037f0361f89ef8e1cf988d22f48c4df72337f22838ace08927ae0001c5660c1c67d8c008e48d2b214f3a0a74008ad8f6746293ae8489302a8cdc76ef80b67fa92dcff9526db9b32ccd5dfe9f3dda16b7ddce2c90bbdc0ea167ec8b518f21626b2ae975c6aa7ba9cd8ddb3bded029a5994ae7e59858dfd1636d3cde717a403bb1dff75d91cedf66b0f53736daad084403646be39f9f4ad58d64f71e88df7b107f4016b06f36fe7a3d56aea1bb8ff177f82b1eb5457938d0b604388c360d14466048a1a44a9659851525d00a17b21c2a5a2c41a5cb8bca143bc69e45546c9bfc575705a84fa0e9eb30d7cab2b5d28aa3153579d42edbcc9b990395b591d9ba3ffdad9eadfb1edab17bf990dd3171ec9cd3babbbb75777cbff53ee77cc01dc970eb10b3e69c1d189a7eed4293768bf806d57d4e95a6eeee292dd6babbeb52d3afd74e9a47b06920d137c370eef603a8aead1a7a13a7e62f56bfda04ace9efa2698efb9c3a70f69c9e635b8a63bbdfc0ae6ecee9445d5a4439cf399da80b0844eef6f3c2137be64fd1a6e9dbf84251a9c6cd26e79cd3babbd3b0ee2110211073cef994524a4320466bc2d6dd5d8736359c6aebcb192e639373ce9965623e40f5cc9f36a8d59c359b7477a78911a29c5c55ae3a73ce594333b392529342ed396dc2efa2e7d77040d35dc3017d8964ba68fa3694e182dd657ecb19324e3f43bf85195962cf7c77774b33cd3be79c2fc345bc41ee9936bb37bc09514e6ad800a1e572bfed89e306cac9c511a29cdc0c5c992ed6e608756d2765a48370326bab03a7e6e870777fb97b8ed8333f2c82babf740f29664a8aaeeefed994f0a9c0e431f72cfa768437f90a8d85cb6e2160de4b1d20e21e9b89534dac0f268e03aacb1f05ce1b3971f368bb603a429b94e83ee3234c6f986e71a72c924ea93a5482a8adeacc9cb5a6d1b9b3a90b0e9b73fa4c1e75c7c32bb0ec39b984aaaf427c2a80802a6277c7a30b2dd056937ad7908260d8aa04f584d600de07534968921629025a3c7640d77b04264e71cabeb4c8e8afd0f54711e8fa7446679645672bd0f48fd4d6fd99ed1ec42c3a9b5436a3b2aad37d47c11dbbe6b8b1096b157b6ac8a2453270245fafd677363aa3b6db5240d5b9ef000a54d88c7dd9f785d41f41eeb76e36fd4865a6b1a3494cd77d26f685625f2af6a5365b05ca151402ca0a72bb87feadca94ff1dfbdd75bf9cb4acd9ddddbdc87d95eac8e8febdf712b140df9fd5286b550bb4ac957c195af0fbf96290a446d44ddd63d6fd693471eedfd7be3717632fcb75b526ce7dfbeec20b0ef8a9b01913e2736be58cbfe5300664d1ca8117ad6e74016787a0b5d65aeb4d6d5d8bbf7abf8ac79bfb42aacebdeff365c350613376eb5fcbc274ddbff7bdbbf12864e2dc6f010502e36b6ee917b96333aaf95683d496fd99c354982e6bed93947683fd03b429c2e689b63fb7fd59ce5aab541f83c376a8bdf9a83a64e6711bce6bf3ed61b64f6ad7b6368f48c8d74ed5b1ffda61adb5498093daa0671115d9b6ff20ea89a69452eadb8ee4cf8ed39e37d869763bee78d5d638d3f67ff8a83a33063a50daee5f5bfe4e18b160e972c06a9546699d934392182ced00071f324aa33c2c9bd46fadc0691c3a64c1840996e8e24b962f6258ca1113608c313ee2e4868b45670489c89e208a0eff51cc222a76ce942540dc14a229b5ec82f9d93e805af9327bdcbae777341a7bbaa9d61ec01c1d3ca9244dabe3f8e0f1a2fd736c0e5b553cee0a62c5ae55ea8a8b6edd1c7c63c70be68327bbf6fc9c244c88be400229cb134474a0073d2460490f5ad04390ed8a2d78e0441059ec7b551a7543ce983f2fcea43fef0decea5af36b9e0da0d76b67e786068db4d9ef283a4e1e2c1026fcff1993870c59cc07ab191a598c99af4893a9d491aa43c200942a22ab3ad4c3cefefe8ac0f8c10ad828f9d95258683205e42ffb9d8fa3bd74d66696719aa16140166d36ce59c30608adee059b4c01ad9cd010caae2c1565cdfb39c28ff5f2fc3839e10c5baa0670deec6004587256e4a28096fa4f3bdb14d601d1221ac8b4de945e1c6d93ad4d8168f0c49e5e278c11da955eb5daee567164d791d4ce0a6b2bdbf0a5880aa34db36711153825b81cd9367b2ab1a5dc20cc4a88f744623edbf8c1afabdfadba6fb90bfff8fbf8a37a22b1df71177e22b16e948001664cff6452659fdcb9b119bbddb7e02edc8d1230c08c09197f7eb80b1389fdf74462f5bd11087cefebd80402b1d51c5709a8ffbd8f7ff8f3c3f1a7c91c7d6aacbe3f11bc52a17b5a4521e0b812f2fdcac7fbc6186561c6bc2e8f6e44571b10d0ae586e4e80b6c792c15dd8674dac3c7c3136d2212bddf213251d96a3ee688908f0d19110dc328c8d2d9e620b8c315e210b90c334c65364d918a3f0a84aaacdb83205144153d85453104961b449fda112336fb086b4dba087156fd0867e3778436b7d835d884514ec0627f8596b3d8badb5d62db6d65e6badb536e7b0d6dae90230034b2c306676772752539ab73d9d050616955860e81b840ec26f38eb642da1a9a52c302c6b495377f7da0171e3b62b7e2f3f055a3ac06c7dd511525bac1c7ef1153ac88f9cb3a784c355d13e6aabbef7e1705870123a45856edda0e9a77055c75ff45155a4e9832275f07680a903ce20834b4e342ed68d21d75eebf6c4a2192db6af0a6b3d2cfc3185ab295c0e04733dd18033006fee1da9fc85dafa4060725c0e772b4ae1dc15c30466ab7e0a078299a5dd95979c683e0be48dbde9ba3f8114ce61a799caa5943660026f30ce53c19b8dc1137b3c0687a5aee0be3ba6705de06eb8a25860bb5c036da352e52ff758ff7c061aa5ef05dd3df4241bda50f4248e93dc2ca2298b09a6f5f277ede38c9b942a66a93abaf658d7a77b63aefd02883b8cd8e3299b0e343dcd700183dfa8edfad92f06c3f946362f0c6da35299b2c924a66c5e15da66a2c9c1844668fb3a95b289480e7a8a0a7d2a21dc16cca9291aa5b2f91b0d024dbf869f08029db3d62ad5bf97caed68e5f81b958d4ed96aaaa8c284dcd8a46ce078036be4bc81352132d5b5fb7bfd6f06d640142ab7a96851b99db2cdf2a6e30c560c52396bad527d6da1f0ed946de2885750d5da50ecb193e545ea48a7c26dc1da789b916d2adb363ad2e45e8849ecb1421c962aaa64ca368f7c4cd9583bd0f4c9946d7b5fee70bdd6a9e7a108c4ff3e78a3968a32bfc6f62abf5a0c510d394a69d1dc556fa2d0e4cd926b69db78a251b94dde9b0d0697f304e545e7108d39b5da8a8942e7d476fd1a25688d2d89c9c3fe7db246093f598345f7644d15f9c99a28bc276b9ad8957ece23a97537d2f0483e854deaba236963d391fcb68d4d5e1a0b850fb5553db5c6b62b0d202334fd7c83264e8e0d89a12e20def3c6a9fba45680ae50ea93fa17cfae64c69c41eea6080edb90f0b2ad4f07e38b5a8d748b05a63abf3012032341543cd00418b1eac5aeb5d65a6b9146a5408733c021bbde324657c7abd62592ecfa5ac9aeaf52621745b1c5ae4f65aaa850d0b0ab942454af2bc6984aaea31246128c24c92541905d810ede3921028c316a627cc36d8c317eab2fc6f8c6656325318caf1477cf222b465f918a366104144146287d90115f3e78a2657210d23340f870c40b6458d1327b161d010513475ce9c0115c58b1b96beea992b16711125254d9b2c90fc20443556726e14394994409b6f83b0bdd7bbffa56761cf244ac1d7f88c860d4c20b3f8c94e6913dfdf7768421e7d2ca7aac951d7f087d709c017cfae30c24becdd8e977c4ef4fe38f6afc69893b99283ff89e8afe8c7d1f38ced0c407e6c19fe1f41fcc833f63e44e02c40f61582bbbb2e35ce18f65fa982712ab944846861a7f68194454ca68500c0b13612316498352e5ccab9e482c4659c41fc452a41d9919516185204a2c17fbca9243eb8185756befbd1863ff4e4cc17a1f188a26187d8a9141a56662a85eaf0f645857e216950319333e890ed9b3c6eb4e6b9b1251db8883c6cd8c468b9b1a331a2d6ad898d168610384198d1620b4bcd084a1bad27221b96ee0e8018e6bbdc31967a118589449adbc41b7ba353972e0b06837c0d1a1a423a704392f252f0018014008464210610797a7ed18816675acdf995f96d8638de8c076bcec90e085041e3d7250438b1e256451a3073b46304100d7ad97995f9b850e4c003cd7ad97995f9b05093c1be70e63715dd75cc346fcf2e8b163a6ebd6cbccafcd8287c7ee98bd8e677eb1cd62c77a103b218c137cb8e511721e21cb23d48382100a6e4f10f21384ec094229fcb0585e5c722c0e8514560062fd7af1a070565b2aa820f6f80ad6fa955126b5658da8b0421025968b7d65c90112a40619001d000126ca08015e228450c20f275bb8c384615c2844b8a43c2acbb2949144870ce370ae3cc2398c9625c6951857625c897125c695653883e105250ac49063522b4b26b5b2fc91a13c2a99d4ca124a599665e964c2c25989049430a874a26d44b5b274a18523213f8ccaa39249ad2c7566488022530b67e1ec1454629c937016ce68344210a184009cca12e330aec6a41c026351ee90c04367f48623134683a8128ca3326a4359d292da5096e10ce3caa3f24938ab31c138da839e60088c45599618e764c7f5c163cbd16aa1b4b651a96efe55315f38a3610e9486b3274a65ad2ccb12e3988441e12c9c695ba8240c0a67e551c9a45696e12c0c0a69e551592b6959ceca70562bf374520e3161e1ac887076b29540027bedb5d75e6b67560b24947ec802dd29a54872487248724872ee5cf0204bd2976bb1c54343f88abd7287acbd5fecbd82830ecc64322d3df460ed4562af6c69498b9c962fd77281c45e2dd77281c45e2d185f8b65f66ab9960b24f66ab9f65a8cc45eace50b0fec901d1a721fb243766828490b167bb94062afccda8bc45ed94c4b163dc864b2571837283458dd5a8b31c6d6fbc05034c1e8538c0c2a351343455363a33a7922adcb895076159dec3a652cd41895e56c42194974c8646090f52c1c74648d37461a2e1a37ad9b1a5040a8c962d4b06123e7aefa40af6afd6bcf9d3dbba032b1cbe5acb54af52f9b91656143a481e01282068de6fa46ec375b8f02b5d5138327cb9269b0eac60d1c2c9a0ac70eda7b9196e34f1e4d32612238aa666c92cae80eae2d96b5a597e0e84822432693a18fe8c8f920e765f302400861f8f3b7b05e70215c98b8ec3090d582101144d8a19ab163049d191d584a07b01d12a0c8d4449abb52b95ab763ca1c90c04388189a481369325968344210a184009c9eb8ed18210026e8276e3a624ff730136028d5e9bc176932a74ae9cc6eb1c3d31d75504c57fdaeca84759d155dae93e9d13d41732a95c93adcae54d6e59e20bb9b09a10962cf7d135ee73eaa4797032fbd452a9de12e477bd01b260e13a7db82ca64b2088047889046fb82e7b5af914d52195012a009c6f64ad8d9f111e484978ffcf211aa5437ff39b6d8027b50c8a08aca42169d798f10fa5b704414ecf63102348c0db3a4e9833e7a4215422a134b9126d2ba1069f426fe508ab414c49efb43e7e29f97e8ce6437a4f0e3b542de69111d61d199bb2a95fd168751994cc70c0b88a3c20a75052014489024bbca280e73d210ec2ad26e08f202c02be6e6d51e34903103e903241ba415520d120d920a2906d28c6721a9906220cd20a59050483248ac1149062906e984a4916090461a4830482624112944a27183142281481fd24d0da40fc943aa6103c943b201021208ad104c3da9e12e5bcf95d6551aaeb4eae1bc52494a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4addd0430f3df0e0075add5edc65ef0343d104a34f3132a8d44c0c154dcdca0647035ad5d0a862a43e9031c386766fb899144a26e634e357349f9d348ca9bef8ac1a3ac3393104316ba499e53eaf1b69a86a709bfe38dbf52ba5e5198de9d5441452db13b168faa47733b3678dd4b5a9229fc32e7eea0058a2af77839adac44d1c7ff75a9778e1c5b4afaa42c59015a129bae0c106422f770f8aa795d680bb8e8669eeb48bbd77895d62c4ec41d3aa040f3cf0c0030f3c0c0d0d0d0d0d4dfb378f3bb08ab327a3b410e00e0ce4b5f168535ba1d0f77abdb61d6f44215f02de0051addbd06d1d02f42177f7a16a021cb87f2018b239eeed62dddd77189ab89a15b2425ea928ed405b2b343fafb39dcde9d6f6b2d0e761215add6128ed4fdf473b6b9d94a8744dba042d642302000000029316000020100a0704e2902049b33059740714800b638436766442988683912086511404410c8310468c318418e30c324534550172c2fd4a2ca22a0e21502697386856d96c8e98174866b2c61a8b23d7afdf69d01f888788813b8cea6df0c2f3caf42055ca66e61a85fdcac03e4c0c81ca13ca2ff5d0dc811c723ac5a5c51753922699e8b76fd88c65901d099598256ad52db85ba062029bdc616f31581b2ae08a63f316a3e6e0bf5779e677188d450d27c7f834b8d1deb67b6ce969dd49349238337c2bb66860cebe099d000d36255ecc0bb10de39e5f2cf5fa974a22c4b86519c0a10b770e37c5ca610eb9bc43d358f1ea605ffa545f891f645b9ebe1cd26dede932215996876b8364593dbc0c7276fa48ae0afad053705b9f747fb3aedc6c52799aaa4dad93a98d9e277c172cd6caf720a14e1343713b33da7a28bc6ba25e7fe5e7bcbe0532b7b358ada9d0cc40beea7a57c35141a83a1e1ab540b5b8a52d67b9143af3d3ef2ca0ad753085e5c5129923b3d87c61a35034ba79d225ce3e0a7dd3d17748745421487567528f018dd83418335a068441686fd07377dd783942d95f06c283d236daebe08153261f915a1a30c827dc25aad18cda610bef52d5fdba0b2fdd6b50f3becf53358e945e3b9476bac8044e6f1258028575b2cb400c745a6c02d05f307e59f8488ef72157cc97c1dbc18e8784fceb784dd99042ffaa5f5ed6ad70b58e3a18abcb379c543c1e1612baa5ea803192d603154c3395674a60dee44000b9a899e66190e44127e398e52ac4e51737bf425071b4725c9fd4127662f30b530a199cf36046d82a99836f078b5e2578f9d09eaca5a566c80002beb6d2013c4c0404325ed97f6d48f5fe55e85902dfcbda25001b245f81aa566aae124052ad8e8a3fb80d5b8667f464124850e2f62011179c59778de3d9d3ad74998141a4661ed9e3c296946a3800421fa94176444c2f1ed04f4fa0c3171e78845f649ef47a124dda2b5adf6ee126793e1a88215c1582d1081795404523906e00cf50eb8579612cec06e69e08a3819a8c30e2ca1d2a4961013be0d77b15b14de9690adb577ae2607fc6c5af402f206731a9d46f773a7948c28b7918ccb3f5ed3d6140809dd197b3d8362686b2dde4014acf9cb0bb4bdbdc0471485815fa1c4778801933c2c190f0bfc8b87bdd61d941c21fee9e52924743aa2fe177cf50ac49e7a43fa186499928c27504875efffbb9e9497912ec9de58d3a45826df2f9eac392c9fb627d549217738d807d65607f9cd8839f51ff753711fb46f9260e2d8cdb1a164725f0b9b45fc23378d84555b9f6236630b03c3b913da6b425fc52f387e96a89813f2060ef0704ff63ea675cff48881db12608302ffe12fe61bed740ad6bae300c0e4d91108fa648073bbdcf41947936c241d8ad92c1047fb80e6fb3c416e5556425dc141e4ef72b7d43ccdeddeee89df47ab0e049c5b3dac60c33cf4d1b9a8ae104d2198a3f6538ad7454c2d5f3d17f59ec4597f26da2e80df6e4277ef7adafd543711fe51011f24cffbb77ef32b2502cb771668daa23bf75f9e9b31db12ee50ddc7828535d3bca4758c269742c20ccc88d77033f705e86bd8f8173d268fefa286835e1837b50578b6bc40780cf20ddf299bc3ce4394f90242fbf81cbb27c37090c6bb85a30ca43d37da6cf3c7c0f612b1ebf7799b88c6233d97b53dc22ca07d76eccb350a157d8a41d35bd7ff9d08c006515ec3060d83856809fb7575786b44f541c355f0705b69bb1bd3778efc8798b32e616b408de588b8b22a4f79e5517485b727851a0bcf7e88f1a8b3f4f221ad0097b8c51edc0aa5b1933cf34b563043f4109e1cdf0ad7f9ec1b0897e4f0ba5570151f3a7e381e289cd1ed316357b55a5287240e075834634552f0100790cc49f7228f5f58da4e431803c8934fdb5ab3e8d81254f03563301baaa015979dc0a2813cb5b809bda6d8ef0f365612c26f3a63ea97a6449cea192afb1149abfb395e4fac0aa61655c518a016b942a14fb055b41e3ab5d1dae3ad0cb04e49206a3583b8bcb041a621e309c97d357639b139b8891047e52e58c79bb01868017720b6977891831f6e3eb719b134394c9d650ea5fe72a7d5375360325a052364d8491abc85a11c782e94ed804ce620dd0104a1da15542d2c06a08fe2b8c4ac3af0c3d4c516ed9104b861263285178834963604a59b7c07b81f7c8566480a17d8dd18479280132d2be7a90636324f61415db7fb716c66fe533436df83218bb96984e4099e1c792867e9a685c106f04fe3a7752d70a0baa37e309fd248a289375b3915b2b14f2d5b22c9d8c9db460e3c9454eac7e5882d8723939f84657b3693776c27dd57c655fe63c63e9ef01212268e8c93d9d60d7f093b153737984bae72e57dd80ca5e2ae3d7dda231dc6688846fa6c6f83b6106e0e1c515b3951ce99c3484ad0fc728a1a905a40607c9626cca705eca1fe7ceda15c10b8064efa32f3ba0e8c23210ba65898010e48a87dedbd4ff69864c184b1a91c82dcc3007fe82890005ca72e6fb4412edee020171e8fce8fc9a5c81ee5f0413e4f03e79399cb35ee6ffcb5962306e8285e6d871df80db262e82448fc9066d221ddb961bce4b310c15ced45cdcdf248eafe89d5a690ae17eab52a3829edb0071ec611204c1a89fea42960a29b73fb1ce3acd06fd81f9a4ef6510c16d83e2e22c14aab904b9fdc6fb32d54d32d371fe28f45631037095ffd9549c4f0b040ed3d7f265eb7c9a2480b6f6fa1b5315f0789331e0026d4b09f4ede64e1b57325068b862d01b9a982a3cf95924f58cde02534d0bd0ecaaaecf6cf4cbf9ebb09899c910ba4d4411bb0f0a895893aa0f46554626e5470a0c0131df94e921756011dc0a6e2c10c3b9237e23006334e84a018d4c8f346a04817975d80d4401feac7f704315703c9b071ad2fa6d01762b002c91e56b355d383b20e8fd65612e0015248d408360ed078f97e3d392d53d8356050231a4469080bc8f4ca11fd4ef41372c862976b7d1a5f829d29c8ae12debc6cc8931abd388eb04213e020e749fffe476e4f936e79394da8322aabbce7a51448dd789aca23f3626c3eb96fb5b1c8cdd74fa60d7fd30a6745b5904c99fe1d77ee60bf28dd881495f38657693fbd748ec47d25fd797db092d30c00ac234a0bdcd60f97c5575848ac7766eafab6b1ba5a47c826361f547c1d07c12df8ed49fd4a4cf7482ca34f7e0ab0424f3bec931d1dae1ac18043877a595a52ca61d883278bdf008df6b9c74b8efaade3c7e298ed2f4cb4fc3b8baadc34ecf7096fba9f59e4e124fe84d33993d428bdb7d621667784886b20d9c41fe9e59af818a5ce70363a7dc6e2f19440e15ae428490a8b4981e411cb0d50cd0e872fd76eae34a886cd8ad2276d480b8d3b062a3f3aa75ed3e57ff19ad4cdae7ce0394076f9ad41201e039da056c1384e91cb6e8fa482db720cf99f59492774e3087393cc269aaa17fc6b711d12bae0a78265f96ec31c249ca4492b46728a7738fe072f94dfac5b6782eb87503ae6e03d77a38774013dac1f2734ebc7020fe13101a69581240154411542d46f09d770825e9171b577f3221cf427fed8c93d03fde7e7339de08f20385649354f9b38ed40226d2964c9cf57650c6902fc59806ad5ca2b04bd5ea0814e8e2c61353edf6bc05d7293802f243dad2b6a51bafcf471212a4ba9954323ad21721a4d070e547a6489e5ea1ef5b493bf4f83c61240c2d2b318d0c9ac20b4d58ff8e67022c70f480681fce29cee73d5cd56e34e1814dc712b6ec5cc5c9b8eb55de842e649b422141b71405ef701396e3a53d566e5f9be722140c99375e2b1cdabcb6cb7d346864b3a2b6421edde3af40e72eec4b99c914b56798d5eade2def73c0903b6d656227e446f30db76ce1cf2fa834a499fef24619c31b26fc479bed871031cd5326804d6fa07982120f983a20a17bc717804fb3f6487a44bb0ab886fd729736f6a2a3d835baeed0ec047be5a5f6fd8754cd8f8535643cd44c8fcd349a63c75ae51bb222a0fcc574260feae6985f46a79f0be1c2f9980b75bbdd42845ff82e45382e4031dea96aff3c1adbf65a0e882725e68efe619a516340eae949b3b682acc7099d85a18565c4c6bd809417e03e657f10cedf3d8f4233a8d294d72ff230bb277a814c7a2555fabd7abdfadd3a9aba9a7a9bba3b05cfe4cf41af55575faf5f5757bfb55e57e2f125d269afd7d4efacd3d4a929397ef6124d9dcd3a5dbd9a92c1372ed1d5dbacd32831fce117688883d3e938d028054804e28866725f5a01096c6e6d0f7d2f2b22909a98828ec13813690d9d325c3630e6a50eb3897bf1eda42817c5f535f251f673134a6bb19201918a64299e2513ca7d70a5d5fc993accc3073a90a777dacc8d0f5a771a9bf6bc691c53ab995eddf46aa6563fb9f211a3ce34327d1c08e3d8bad2d8d43159a9b4991b67964abb09e1d3581e31ed32e8e67c8f43a2e868a92ba45125eafc3a92d1c1edacaa8e3451543e045cca7d3f5df7f1769c4ef771bf1ce7e171dc2ee7717c108efdaf5ffc6fa2deaed073fdd8d60cd92bd15655bfc4a7edb737b5bcbe86988ad171a0ed057ae293177297741fb579594885b178a489092abd2401f0eb309b7ee7dac966def803c96997532201811940bc5066ea153524e788fd72554b989c9799391a0b06f485dda831cbe0334b6f5cd728420b6d7224eedfe16fc4c9fca62468babd54c338f2e7c546ca6c13a038fb2f2314644ad4583fa14eeb5f996826ca5e92db270d6647ffbe9cf5e8d972171c387750d7eb91ab38f93f33efad0930a280d563b24fbc5c4ef8fb84db36c0a56d593c748141ea46b0104ddb1be19b7c2e61e9064dcf0f762e921fb2d2e94c9a37146bca8d35db2e805ac23b9bd5c226299962e8db4f06a0bfe98666327d6e7606398698c6b83522b2693bb9a0b176813e045cbccf87520d2b06fc856542a8b033885f0106188b4e120687712dd2e3339f89fe0b5df5cafff6a1740a3a6bc1eef86acf8cb3549047cb3dceb0af58d218e164ccc4decab26dd1e8fdc05a1cd61f7163d7884a0afba5893130bc7ff3d112c2f0dc088925c5bf67c526a3949b462900fa378da5c1e683fdc6a14bec75c16b63fc3e414b422fbea838fe4412694b40a0f1ae45722e3af6862ece817d9f8d72227825eef38361f7cefbe42e88b6146fc942414f749dff87d15184bf2e1d10288e927595f201b466d5b809a9ca30f65665e8c492b34b48a35110677da953bd5080de42d9cb797230a9703652b86b9f6cd91cf21fe4c9f4ac9f6e3ba795e8ed92962019a2686cac10025ecc39049fd859daa272e3081a2c8bfdc53955c4a481e8f6d31a9e4f171c1a0ba8746fa726c10f4cfa486090fc2c4624806d8d40dde88416fd4a63ba744c0c4eab6cdc449b134718607f71b9312cb2350010364027999a3f3a0508553df011ce7c602a4d240c709b588dee672c57957ae47e845df6eca16ee5229b0de341f481ee486dadfa278e276dc5c964218b88f238091f6b9b2c46f84dc649b31dbd7a7a5c6e5d497e8b34dc93e0da313ef403f9f60bc945e83ebab20faf1abae3c095a3e70fb44f561f3f086a6121b9b297b0758f0392bba9de4f7cb39a3d2cad76eb07adce12779eb108c2402cb641815a2e1430eddb435d40ecc66a191c1b289f2e78b90310132e5c011695dba319bdc58d5954ccbc6a2a3f5cc788c583d19cc3a051cb8b725293bb00ce73412a29d0b459658670856f98e6e9e3705e517cb624e9c0208baef6a76281dbff4684333adeaef4408506bfa23f3a8ce5d4105dbb06d1297aa54a1c7efb6b78dd2c09497d4bb6a5498dc3f460ade6c2afc8f97065305e000802f6365746b8a7ff36da968889b7dcc36130143311da74a3e322d88c1c9938653338cf64a97f38f5760b00e1f63bb6020535c28f45a6214ba71542473a528d4fc0e8deecc208311bfd761d8f7caececfa497b85bbe5c07cfa674392f2eb1d90d45031dc9831fbd601a510cc908a7178bfe66dbacef88d0ba0bfef21b535174c5bdc8348dd6385a30b28b4aa61f214fd160900bd2045235206ecbbb85f7cec17a67f2205a5fd4bcb16e01f780b440e367785e4bc3a8773432aa2922d0d0a1fc0829283da41626dc289b67d6009816d5004cb33a76554ec946401855de4ebe458a16c2ab8acf42f4fe01c9de09b5cecf14ee2c9e83b90632ad4cea7d2c254fccf361239969c107e231252c9b1d1e05dc4d245e21d174bd9789d61b5cf4d62dfcf1ad977913bdcf598236b1650488ef24ad320e3ab7a515d70bdcf9fd2b6e28c352457fa60ef7073592473d1e38ad529921d8cfb7db116e2024d9d8cefd0ce6d66bc309fa72e255fdc23a539c83f44817aec1c03012eed2eed6cc0ca236949423b12552a1034639c7e8b2c3a535e2cfd6656bc611c0ae710b3522bad97f57ed5766a4649c7f0804e784cf85d1f2a298543c4a0db8a7fd08efe90d800b44a08831a8d3b371fd7b830285774d0f05afd86371ad0b220d397d284d6ce68d03527d1f24729f10207eac1094b806a7064fd28b6ec21d664500d800b29936c7f7a121caa28736d6a4c17f55e51d07a3617bc55f46ffc68cf202c74330b6004c647e22ad5448692492a81637688ce0d317f8f24674277e75969e7f330555624e06483faf711177d2a958ab62366909f6a579f5112e293c1743d2c957dc237f970fedf47fcdc7109b28450ccbd2ed52ed359c04cd87c2c022b8b01b07084156a2f35ca4965bed5fca6ef9aca36edb824aae5df3e1995cddf5ba5511311e82380f22ac727b0655c222a5290e0295531d2b481f85a3737bd976d3692ecb95fdc915de0147b36369208d7296786f340f0dd2abdceb57746fa2779e2dbe43a9f697bbc05c8705ffc0bce225dd1f5dd680b149738954a802b2c52ad7c48d5eee78854dc75ff9fb3c9340ba78680599e1d722731dc5e810ff7ff01bff97dc5dfd8fbe272e3ba8b63604848ac1dd0607169b30562c709192c23f275ecf40274baea715cc46c7ffcb6c1b32cc229be49515d07580f5b3391b898b6dc0cecd0533a6cb56eab9a37963c7c2e896775d2c6c0cb59c35a70b9c12827ace57c6ee381f7a3db819eb6763e6a7de3ef39749b870ad34af5b81edcfae5e47933db36cbb71925951825e7f3d49a082b19a04122eca3f6eb60450d08a161bd399f09d06ad8649a8dee8d14717ebcbb95f00c889ca0d8b70789072d9cd02cb9f8323db09a5a14abdf3ca0cf190edcfec75718831e213872326a3b4bebc010ad414bd61d5e3ad9afbc9d209fd605414a3b80f42d0eb666a8698c29816423f9437d5bb7a5f935305a95b3dde7378584eac78b9b30acb6d64a58d0d1e84ab44de4b883ab89da0c212fc326881e39970a04f19a3e354d610ddc08e0223b7d9fbd359d6336f00263295a9b60aeb401f20e1ecc79aaabc2c48a180b5bf223f31af9d2d4544cb04bb216f5c927c2361cefc97376f33ba9d5d41a0c8b4310d88ab4497323057d02ac96dd50009eee678f183536b7cad1467d927d2916e91f55d58cef959c0bcbcfe8557d5bbaf4da5b71d3061b98c9da641079d802a2160e6ea94503b8c75e0af28ba718ba802c91a33829919d63aa43244a9c241570da74595da1aff440a713b0b6beda2093304822b1a10f83a432b831a9934a9f94ab33ee5b6cb8524e9477a41796b15274cfe6d72bcd40108652a96b36cc72dc8b71f3a6e3f58693b456c7a20fe72273a40f1c3800e535fd399c739435b82dcfa673c08b978886810a887594e8fd5eafc232375d3292fa06b0b52df20d5047dee9cbbe27b19a9a8a81fad8924e53f212b15d9b72341ce662296f8f9b6515c7ad2f964ad7869910c4e0eb30f7c1568d2ab9a93833e95b8e9dd5db9e4d923de1a6d3019c40fcfdb3a65601c65a7514e4b46c4695a943a5f02bb4c36f9e550fbd18fec5803113bc958a6e3e8ec38dc3353dc94171d2822976025ebfed87ea0b5abe3b0afd45b00791df9ae3f1111de0e3ccb056e101d371b6d5fe1f2dc34df157ae6b979e072fc19ab9113dc17ea68faf0e27989b459cbfd098f225aab7b1f1b1665913490235d82fbff49923f6a360df8a8f92955dc610044e2ad33f1aac81ef83e384afc74a3c1da906fb548a0ada5a5aca40e4fe33c69ffc1578e34049b56282879a23bace25093fb38043614fbc85049c9abcae992fd944331153b9de53ea8ae6694acae6623cb9911a25d63cc23e5ece4f59b23c900c1c4c010120bad416b02b5674e4c75626b6be603afa138233a089c206fb654869c2ed9663dd90953d69261ec865a6ca025143576cdd018e8a06bbb15172ccd9aa94cb9ffab993ac462a6a2e276ae384ca2c4f1a0385cb8249de3dad629b6c326912f4fe21d2b517ea938d230504d3a10c8437873822bbf20ef9df0c75b0b57fe566c4a6ca1d6c39caa71f950b8e5467a575c9d87a2f619ceec2a5e84e708bef9f624268939b9a5d371bd48723b57fb31d668d93ca9f9b624edd3d9c4d0302b8d8ffd043ac95b23463e26c46dff0c607e8145d4ad31818d54d55171ae65eb2bda9f486ae42737b91408d4dac37ce566e664a22d6cd017bf5dcf41add106e08995f203ba94be6ed5c2b9ecb7dc25937474cc0fa388c28d0b2ad44574341168c42a53d1602a4f2d58e7dfb1689810d244d662af66ae06da52de3f12415cb74f900034b2c0f3afcbec728fe3d879c4cc8cdcf5605d5c157ab0fece8f5818b6989540dbe67f0ab934b1077c0b2bbf2f448f3aab217df6a7453bf8a54e956585597d55679b84298202f35442afa9c73c97ea76f0792c653e8a2b33942c7720a1cb7572757f85bbea2b7662ca1216a40480f6c795ef4f41be473af3893e97fb84a7f950ac999b0f2ebfa0a575663efe48256627d1d44f48c9f194e2f8345d40ba32f1c9062f4d422c04d6b0482aeb10881142cbc35c4430a4644296ba257c0d25ef3f1356f10367581113c7023bd66a1a6effcd396ca4514687c9fb88ac5ec136e3af67d3cb1f6c9d525fe373bf268e3587a7a6b9cc670c7a30e2bce60c5425802f4b6da4e29c663b4eb4bd32b28e505e090d14961a23f894c611b73a03bf6003c1efbed0fa1cd564cb0346330bbdd0a9b5aad5ded5d3766a7ffa870dad0ef9531e265f5141fca4d85fd418e537812b68ae8a6ab8d19faed6c81073a90645efeca52a4ad9fa6f8d9de1e8364f1ce429fd755f53aa46ab705f9b833d3bd0df88a78f635141e4d2c9254e1c129af94b7b6cc1b3579e65cf702dded87a756e7ab24f41749bf9a31833822e9b5151a4d7c4a5990d206abed2603b29a8d663cfee114a18f323fcc8c806d8360b3830a550e1165dfc627f835326467c8c957bb1f4c028fb5b22c276bb203016924a9290d35f82089826174e61ab7c19c8ad02a9b1b55bd8e0b8fabd3c6c64e7741174d9e886a910958574240ab0f7a61ccd088411f267243c09054c5d5fc7f619152ee210a1fc4e7a901d119a19f41883629692260e1b23d238f1e23173e1df89596ed1ea665c0030593db114c64afc936e9bd6e420eff78b8e5a4554640d508014f09c08d2b44862f4577904388c0a8dc2671eb4a1351052562a43ddd5abce40ccd62c9323d34f0dbf82b311b08f1ed3338685e868d6321cf0de1b0d9324f81c0cb65bd2eed7699d659a04eb140a08eac62d7d7a6ac2239e85f3ac764755f89deb9816b35755d8e688c8dea57607e452684df4006c559cda29dc0b63596fd19384b4efaa8b93172092e55a752f1c897612385ae335dd502e398a4e48b7088f660611c7f55ba3079c860357d566d29b382d673b900c560e049f4ead38d0c9af20b80081225a84c25b1ff9ac689861d52347e896547e2dc45f9d6a01c87763c2ae187ec8773c326aa6df6236be004bb425577b5e50d30d7f116bca8a7c6395b190cdc86a7769f84e4398eeffbaa4093f96163da6be71a7e8614ef4eab7430ed6cc7acfca808007a55cb626297896ba982fe358ab5fed468ce141293c0a32020abaa0f755bdf522235072b18a23ed3b0280517f566d4e6df4a8bfea51a051c59c78a9936c4d9dc68af8432a8ebaf732e0901544dd90d4fa45e8c2a4f2373d01a6163a69fa77210e10992d178ac1a5ecea303ef4e9a483131080725f8af31f4314bf81f0da48322c7ae332d6f62d6b63ac1e0deb71283cc28ed8082b9a5e09516cf577eb55f05142cd684427f7eb902e8461a41708f50733085d3ce72d75964b3669fddc57a8d233a36187630cb1c30bbfb48fb047d64f5102505b723e4ef78ebd8cc22ac82f580330edfc213f70bd6ddfa1e4b1c6b426c100aec1b4e6cd547bf3eda6628255f2eca1e446c5adbd32e20f19b05f0b617167c03f5645b31c2a00935517583159a5a5d213449a61456f949785974095d1d83a7301ca1da6fce46b8606d80119726cb5c14c237d7e22dcafdb286783a7dc63eec0fe25edcc201c8b59a16fc382afcbfe393bac11b0a944f8a11d5f399bfb2a9717d557016b2a8ea8401faceec0dd332b0aa30c60f6902e34b5fcef9dd348a9a825db14512fe4808a2f71fbc087b268ba4ce017061519b8be5860616816e89d05ba6a269b2c6b067f6ab1c3056e62bbee6e530544076c7b8d37470a238792b419e726c9d730585f4d819d86ed5691c3a31938d0ef90db2daa712ffd302b5b804d4dbc1e7f1d83fd9bdd05b25d067013163a87e8fd2cdd3c646fa813b8831b9550e074cd4b20d23bd99e516461fedaf0f7fd10f62ffab9df5cc3bdf615e87747b59a4eaabe555884e202d660a24ddfde20694ca78624274c429b4cee802306153f2189f6d1c66ec4f98bfc4751feb3641dd676e90362343b62749b5f726d5de1710dbb9088212171e5b2c0e84d4b54c7a4196d660eb6052c20046ad5a79af2a1c86d0b28aef33f018a057e7c04d5e9cfa0738998360a3e9f8231686c10e517cf6ba70dc749515a80e50b7260420648f8417eecd2e727ec72bbfa909d604917a044294933afa6db7dcf41740b75db5f78e23fb34af849f9bdaea7f94104945b09fbb62f788424c379b0e5c8054b9e2e78b801ac0287910f5d88c138a20d933df97a986486450c6d96154bcda77652e47395223fcee7248cda8cabe0edfc8c6e7232eb47b9c0953261378f31d37ccc569df1439f18fb045b464c09b873b0b772479d167306c97e3009e3e643fee1075cba6ac8b01289429e93aa5c15e961d59eac8118d3800beffb0a3d49f660450591d59244d0d3aa5578b4320098357378b3236ce2e1828766829a3940692af4f9eee666b9d7ca5015529ef3b064ad91ee892af915921b37b84c0dc853e06bb1065377a15ccdbac22b59d1c558d33b29adac69698a139bb51b88ce075672fc6d5718ef12b940e3751e006aaec91c709a5353333f09711fb995730394152f5f6b4d52c14a737ffc1461ef934d47b172dd557ca395dcec760887e51cc4f15533d75c3df69ad6fa26d6253104276e5e9e9e4032291e9b0ef608a257b70f773a5e3eaa4b66e45e92b9ae9c64495c93c36ea59192fabab56ea3d7961e7831316aa1bf31aa5aeadabb39f62396ba7e734aacab30cd9a29cdd08e043da6944186682b996cfd32223b8d51b1a02e1513dfb063a76460af6008f81ab9c69fdf75d9b6bac5baa8b9b55af95ac4d09d4827564dd7c38fa5ffa0077890bfc287fe74c15df09d2aeeed07649a67f6d313d45efbfe3e72ac44b49c591bcfe22373bacd474a1655dca47cb0c6f234ead603cf22ad8ef5ee99cfb7089dd0dc1d00c4746def1fdcf0c7e184ab8eb45633aee61a4554094b89c2180d90ac84d774f041d7aa57e3c5efaf295574233ac853d941e77a363a2f2274138e4c16cace41c05b92932984eabd8241f18fe3207b89e7fe3816c2cab3a2b0dd1fecb8ce7ed971f57598ce3ef58971d82fd821966f4fded78c5a60528e543d996639d73a320ff5ada00626b8a1df6da27186819f1691285d5e80b45e8b792adc8539d8452d7c6ad22b38d9e140120186859e6bd0bba8f2e1a37c87cb7d584cad5da5ebec68e53cab166af7565a0a57cb20bd97357ec58d7c4e351a6350cc01cb7719701f7f7f17a207cb7442bd9b76378288a7e5b067420b2ead8ab3d0619e213cb19dbba36ecf56126037a76d6cba0ad13fc0bd0dd7ea3f5ce5ddeca2a0d9d381f823b2aa9b1045d84d20f5dd40f905e2f2096e764b075087c516dbb186772fb9fcf0ccbdfca5fd4e6e32221e107ed7acdd660fe839fb10398077b96a9f2001b640d0b2589a940698c906e5aea7b1cb2b013e566cb2040f860a8e2680705dbc57c09f45dfb7f4978015c2199d6dcf00914b719fb6562e50dd017dbc72f2ad60c10baead4e32e3d201d983423b2977da75043e42badd4861cd3538f4e1918e82f37ecbd54f5a257f0f5695b159af6ed29fbfee520657d891e2b606cdf6c28ba879024f88ca9c5f0582a355a0a055bc5069c7a6f4aeb105c8e81b9708da2dcf047ed1177b40b2b2724e97df609e7d34877ebc6fae22a2e60708167a025ab00a8afcfc49ba4a6e416f670487c40e5209a5f7e659d1e2bb6fa097701a7aa82c92fc17eb2729a6009d115b53d1e2c1e4dcd61ce5276359d7039cf81bd8b4e16429c5a434e380f9ff19685753f211bda77f15c58a0b0f7dba575740530e0b1b9ac7adbd5cf8231b75d76dadc40469a4bd155aac33d3014dd565790e11f04ac79c1e3eb07bb5462cf11dd2cae49e82f11ce07e676d8cc725f2a98ca554b294de72cab5db53c88b1e8e8c57daeb5401abfe04b33ccab9702735e7c3a38e43db884fc13766973d673e69dc124ad41625644bae61aa8e3b7869e5069b628cb5a815601192bc3b57ea72f3b4c928df4edcff98f65a178a747d2a024fe1c5019776f9b2ad8ec41ca9aaafafdd5e56323541a1ffc6566c77f1698bb4be2be4dbefba154a6b534a39301b7980c0ee3b3b4a341c133cb1c774da5f54b3b9f15f59ec29bb437ff5b2cadbe47851be63fffdd7a332a5d3b9371be0f37cfd277a90b9f3399f2702f7c73b414e5ee85f4975e55e31b2eb1fb57fda46f521bbcc6936a3119cf9ad954e8d19c9b5be5670617820769ef73ca8bd4e89b4a29cf45bfdbb124e3a13001a23d6a73d29e81150e7e5c80069fd9115d8a282ea026da0d2112f11b6dc50c5c1d100b539afeb0d087422d19034a24fd06ecc9a02112522ac625cd204b81b5f02b01c679a3e31d94480ba66ae1e6c9cc2789ca04ad234729266dda3572e04f0c45f08c0751b60e5c5e14032e9e9a44ebbd695fae3321c8c08cad87aebbcadcdc2fe7b6d2fccbde760598c8c2c140e9a2a8d75d082a4940921c3fc3a7bc2d144a3e18cfff00e76f47068d91e41da436f656691c4a001392b09a22297641d7ae50a34abc334b477577f767e4690b6ae1b1037ef0305580d5959f4068aaa88fb32f962b220509a94ef172d54ded6f2da42cb756659b44ad5ccd45b751570e53122f74be2dffcfb7dd90aa29af2bd518865221b8321afcec2404d027d0cf85b84bf51dc3af8ba74c34b92d8dc107ca537b18523708ffddba1a7c7552df3a785241b8089397ae4fb161fc6bf333edb936f3efcc961e17c83fac7a88e016b2df03a3387c799f7f18de5377087786a8f1c05a9267393c42b5f9708a8b9e02762dc6eddc9b8740ad3121fa5509144d6894e4fba500e01b0dd16f424a88ac7fab34e7fa91f7a8e578b3c735542e4cc22820102b5dce51419c8051420a57cf887c174c3af2705119a9708cd9cd2aa805e5c913e239b121f4abd5c618e626ec275814ad149155359107f482d5c358f879c9cde29e7bada823cdb1057d76bd8cef07e572fdfc2ec255450bc18b3205c0169cbfdcf067dcf33e9c13e9aa31de92beaef3b1ffd1b77e03bb8339713a6e3be94f78d54e8f17291867d70df95869e10ad9b35ffef2a80031548aebf898d2aa855a44c18fad105e1ab697c287013f08324cae8a5cf948657468cc70d69a802e7f386b78b804c6410b3afc277824471a0a95d6ec8a8bf412184bb3e70d30334cd11081acd55e6f9c26dbb9c8daf6925a919c0cc704529c94fe0d75a51a662c854ee0e4e8ae9846861972ea0582180b14ec207b0c457feb1280014cd9f445eca13ce27aa113d6a3c9400409b50ee1ed3bd035cab3afb48f29fda9eee826bc8a35a3df38165e47e0eb5a8db050fa383ab3017ce50a1b933e4e8f58c16d36d61b75d4a5ad71ab171ee204b2cd211cdbacc90e899bbef76679a3916c02b2c3a934722722e9a76da05679bf3711ccd795cc2d954941e904c03feb6879dac997d6504aeb8a2419ba12318a554ade3827187c4df2c93e0b98e2434663e280578df60cb0dab8c850d7982ad8539724a241e6ba2cefe6cb610d6d62fc34011757cb64607c8c553f7205d1858e698515fe61a68a015e2fbe1420ecbd69e158d7ad21c67dac2279c7edc08f1e8978fd55398a1860d6d506b8111c10f61f95ba990ba22107a120c6dc7910fbf329b0543edf897c5e75004378aff88dd3ac81090f1f4dbe90a595d3d08e5f39d14d389a66fe02136af2470da733c9db154061966081c33de6e40d721c2a49e6ac4d57963b8d9255c3c82c81d3b66f08f2cf388947b8c381bfcc3624441bc525d6ae07a6035f5d59bd862697d382e4cec7a355d6ac26075c50eadb7587ae8cbb383b47f17a1a1b1e9782dd9682fa8dbb12c6af00bfcbfc91add166d9a6d14d0587442d5cfb1eb3a734c883b692d87d8645cbc03b071c5e36f957394758d1a78b81caf1171f169ede81bf21f931abea8d4abf490682a29bcbbe79ece730b8c5d933dd909af9068c3f52f7c1d74581af4f0897282f9ac0220640f06d0937045ff81acba10df1e7cb62b236e1336d6a50181e2112585fbf5475d9f5a0107031ccf4807cb7da007c41e6206a567fb3584031f31b76b0ac010228391006ea262e5ceafb1bd7e88f0e0b537b0aa55c952721a1d9bfed8b8ab19541a202b098b4654dce3d740ee29bdf893ed9d14a0641d19fc0d4569e1a321f9b392711a7f49e1bc6dc14f3eb72d8a0e494c839d0bc77244ebc19d70d9211d5ee621cac7b7968e2a7ad3bc67cbe1e1369597bafd3ae5651d99018a7b6cb84bfa72aed0123297975b2981aa1751aae92f6d4d5c210fd0eb98472ccc639aa5c464541efe2de4b503aebbeb7555fd2a84c2038f3bfe9a8bdd2ecfc1b338b6cfdc5aa8f2482b5e6262158ff5ac45dc839dddf36e76629bd7861e6080b0cdd1475933120dadc3d631563d158c05118f45d620d57ac34ab50d7261c8a11b7f720538a62470e0a4effc499bc095ddd3337c6a81f40365aeb4a2a98fbe3afd85387c8cd82afbee13067c4ab01b372ddf50cb4b8e87eef54f54dddf49376d0522c3ec93d6b90b59f667d71c365b79e89ed486e5f6fbf69e14cc467783055532dec9b173d69d59e7b41fb138336141b54f12db7cced2899c1784d6db97f67c0d18053c7a73ed7813c49b73388cf541ce6ff3058c4d67db5ed2647d0649b704886422d0105eb395e6c93bb84211000ef369f87754ffde307fee2c1392464ed84eb129494f78c8391e49508d7c89ebe9323ba630cb605478bb51c6657f99fbfd0e2f27add890d6ab858d229c0f39971371bdd3ec7dd505cb1858ad4d358f1154108233f7ee3ddbc2368d49da0ee4a77c142bed81e26310eb5de37bae23b16f4da3c336da0bd2d0118c10599cff46571014f887bb92b6d8d7d3891e94cf1e951fd7d44b45f8dff0ba1ce302abc28fb837933a3894296b01ddd1c61afea2fa38c903256d9fd2f4595ba9856243260fb622a9c0ea6940d115577616a0dc7876338caeefce9022705888292c7af70bd98dea6e0dad8a3a61f81ff471eb0614e340b97a0acfb05bf49f311344fac69c2477bb60760622b42025af8fc471c2e26050b106ea038d2708f393edd6c0c90fa6eb7c2166d00d9e527420e3a520a77f0e470087991d6065148c4ebf1b5ad9bf143f3ce470b28279548e504fb5be24fa4e00c5d803215047f83e53c300d0418ff0b51060fc4a9f038f93222b87447b12794cb98599e82c28e13aa959a961c7fbe2906699486890cf372be42a49de1b5203681fa2415151ab5ca3ef7f64ba94d2e847081cb232f1219055830f261ae55e57be6bdb283a5bd96c55400a84278927dc1f495f9957214b4e00841710e08712a4ba5a04109c7267e3f9c2aa77eb3de04fa7d510a008c882d95e54a57aa3da30d2ebf2aad3ce57405dc9164f3583f2db3d656788e9ee05345f99642a035db23a7d4d3bf6402baa2ea387f6a97f85d23dc72d0bc0971c4879ce2586c133c5e5ba373b302f56d44452e79eb4f7f4bc92bd3d741752786896bad114349412b72709da1d81361e43f1ea1baa1872214daa6ec7b5f87a5d8b2fd76ab5e5f35911ccb1ae7375075e0d0e8a3fbf34f667766427cbccd16c4ccd3a9c4b3773daedcc5ea8ca29325552304e23b706ca1a5866cadcd222eb042a54c09e2e43ebcb99af6b81625dc36b440eb1eb79cf84334322c52a44f52c6c3e3497dcac649c84001ae2da56bcb1be261257745dfd80e5f431e86bc92b58accc5a8c4e0c82b3044fea12535808bd798ba77377966614b1d65907b39d0a7b395c099425c1e842bdce3c8fcb5a2241136fdaf523d8b76c552d37185b4a60359d5184220a0d9b9f9c872532fc9e98bc7719f905c00bcca46e4d469a1b2aa04411bf6db32874a3a1a94aad6992add1d4ca85c72af36df9facf825d22209446583d977a30e07a5ad6824dbc9be6f7d66f89dfb4342efc8fd319123c9028c48248184faace8f9fd7ab4b6b1eef9dd32358b33b5e007260fd55b47c5323c207f64ea0588675d512563f7da5ce604325420ac3326c66c542d66336b5a296ab844c3d8cd0a918394e3f7f4d4a50be2514b3cd63d222982286c2b4a88e10136339fb08c72f867a9ca7c157a74ddb2282bed47e0dee18d8fd3048d0d856597bd19344c3e442a8c5d19e9a304b8a3a334f332a12c249a19521dfd3b017c84addcf77b9ec3c892659a404603df85dc3b91dbcb7483b24508c7eba2b2b92840757a2c7734d6a03d2b84f026f79f71e9f0c989147b0531319f842b46e860675067fa9b355ddda5baab43e992d0028d1ebbab48e58490ea7a6e59ad33f851be3b7e99d118b9d3ceece970f83bf9e66e4a5170e5b2870dace34b9bd07e1e7fcaaecd5af3098f00e5571e52c0d717c15c1e821942c7810b4a9d55a2c0a432f184b2a4701daa09e1ba069e4d9509ed5c83f713ca6d46975a0506cf05a90a2f46480e369edeb50abec4de23d6827cfefc72d37efdb688c67731e0c68561cc6d50727967086f48a1a00fe092a095a417b1b3299e76d7e49b26cd3f43cf42a23278c5487b708daa77a36ae36390a5e0af6d50b8b048b289723c24fdd4644609a4b4a7f9851568daa49656b0c641a0f7f11808c7626004e6928711a36f7ef5a8ff9efad5fa4a909cc4b345e82ecb01e9f5429bc935c6d4ca5cf3047530c454a5c9fa63dd636327325fcc4344a89db7c37f27d70adbe82eabcbcf365df45579cf95033c74fd094d3e631c85adced52cc375f6803264f8926939bc4bf8158275126346a63bc736869047447b6a91512be7263676b8474a120396268746789fe53158aa59a31c329818fdef31514513319694b5758e20005103bff8340d0365c3a6a1c5055b3839f365eb1129b8d0fe498676776cc0d6f3d8f9fbc43ab6f7092caf5142641f2f6b5d347549f482a8154cae9a9054ef98f9020a4373b6bed121bba388523a5690e28847c1ca709f090ad97594d9a2519b311b7a0cc6572486bebb71a79fdc1d42fd569b0ed7bd96253425ffa4f126cc4068f173c068c685f4cfd56b533d26a75ee1e60e408432c67591615c9775efa22ee12f5e9f1d80583a3c36bb66baecd1c515271bb70fca33c305a64c3d5a6c031ab7cd10ba448b3e88fde44d15722dd71d698444c36f8e81fe46a110b7da2c0be1631242db247a2c2243112222b161d21887e84a33116ee8a0952f96157fa847eb906c5855a870a9d4e832ab472039b4d079ad5a3c1d549895108a5f77699a42760ed680ce9eb61c730c08298c99764fa8b88823f84442634eef1d519f83d4b94ed78ab54c6353ce963a6c7a20ff8ed5fa0ecf620c4950c92fe89861e9877f63ed468567fe4fc79a64f47b36e6d891dd5a11a289d89fe805176a8c1a82c1622f60ca36aa08bf1322e95b92ee61fd3eb49c18a57706ee454c35ba28dc972148b16c454a6d3cd5950d5574ade5350657bbfd991bbcab31b310c5d1a0fcecbb768fdfa621a2cc074d4fe22c55b1c6b26c379efa74997ab986f8381f271a72474aea2b9fee5d356b71cbc98c62137ca0c5ded0b682dc017cd67c41b6478964dcf4803d0c55d0e412305809eaf4f1ca26847c7a452e482437f5193ad7d19f167777c955a4445e57ae3f1fead41657d639074a912c7449042b9fd68e94a29c0be37a8bb1de7ce13d59391cf7573b56cd819db1f504638027bf092a971721373f6e6e60271a2ff4feb7f7d50fc9275397af31a81215b3cf79321b277f99f93db4161429ff1953909c1dc8004b10a920110513703827545060cba8e3e97db8db87f12230b910bfc2ae39f7447ebdcdf8a2ee0b0eda1f847be7205ada5026846b140be8aeb914d3c47fba1ea6423388da1dff81144a983f0db8bf87c55dbacf84530cd4509c22eeb268525ea3882989a5356860673950254b0dfbdbc08c0a1e702396779e95b11c226eead67c92621a66ff7c7189ad03bf75901ba2528f0881ae900fcb8d37ab47f6fe06e3be9c43587236c2d642de14d99805f1c4e569064d242c96c5d370327c1c3e029270fc1e3d3e49e8cb7cda29939195e8c8b15709955c00094c1f04b129c0951a5ca975ac5d1aad0c9030d955e190cdfdbd970095d18c319c7d5ca35136aeb2a701e37e40b8166a3706f421e49b91f1781e7b8f1509934932ce72a8febc61f2107874eb55712b340628001cc7db577b820a91307bdc87c09d61f747c1ee8b28fe151ab1691eb414fe807505e721fc9fa21ba51ebf9f50ba9a55f7c6122038b8763745ad156414270304db2e4a35f95d13b0ac93517b4c3e2217022e8c65a54d9da44e4a91d2d2f0a72c54422983e8284a155ce0d182f7384a6ca28801382e484eeb344632c4a63abdea380961a65f4d2992f202b65704f368163d758804514993b96c3dfc9955e353d02b594e376887b1fe104b60547a5fa2799753312b6fb9d555eac772064df1a2b7a31e681f31dbaf05fa903fe3dd112e62e9fec93684a9368139cee6997f593f9c154a5c12b02373e6e301b2b3e56d4cda24b756c3de3402a9ca979b1493eae1733b570ee6cbf07a48f693a345c67314d05f6f39c40a703dcf14b866dee443f2f3aad0219aec4cac2b2372be619b69beb6a00ac1020804420ce8f9a63585eea40275b555f29e5af47d7a8101e6aac1184f050eb157a1430f75733113c7b3d4c5760206200c408b7174aef0e4c049278e8951bdcab8a15fe4953999c349caaf1eab00b04eb2afe96f0ee46d84b0eddc6f38d90f3c8ad2f20516f40ed784632be4470ebf753201bc293b22b1467160862ee3f11cf0b850fcf0f9152ebdf1fff8334a27d228888851364da3057819b62e0fec8969f9f63f85ccdbf2134811147fb0366114619b3ca98b1cfc191f4e185de21cd0794dcd6fe5d90f8c101a3e1d6134db68a4916616d4206ec77d4a1a3ccc761d0bf2aac83ae6694c29210b75df37b6f6b37442408db26b8d36a30556bb4d99d50469bdde0fe3a844857dbd8ac60ec8ab18d7b5a6c2a37e9d67c84fe4c7b0225aa3f3616692a25b1486f44a6d29a42229c3a385274e31ad92671f1b92f24b3c4bdd7189c2c518dac36df16e32976c3a77e4130c239edd18575a1c01fc5ce5a82c3027f00b8e77f03187b3821c51ead59cbe6957c44324a7548c17113f03d0223d16a822ca414f1b1ba2a9514091bf4de602a254b214fa30689e0dbd7b7b5ac0412cf7a2e42496b3474f8acf211a2046c10450593f1b0d7586d5644453f9257d7120d20c289c64d7d5d2496af930b7b8b4901d8a852d668f165d10c9b95fc566804e2561705e21551a5283f1faf73a6b08da582eaf656b9b3a27960ed392b1db68c173c8f002088f9a755556b467134e62481e45c695b56a1163c03c0fbf88c2b49e929e06368e4554b625e06b38146a4491a890e5fb374ec361ba93a1b15e3101ab7d336180779cb69c793c7eb58af40c062076b0b6e3500e98bf11d9a939ef8cb77503a7b61fbb57321976fbbee949e50c5952362650cf52ca246c193f7f8ccdfbc9e476014bd4321ff786d9d0b28bfd134c84f33607cb1510b668ff0c04d09350c0dbf21f3fd01c2d01df0b12ca6f74a8124c87c7bf20b53b06a146d7d2acc9ec88cfaab5711f4505c33cc80df76a58589f7f9849c8f723d116dee6d7d673f56fd559d5b76a448818c923612f77100a9b2071cf2b932b489aa00a28a227b61a0aee92b226f83940294036ee587bfa125885a1b51526418e26d32a2ed43a69a04054d0384f4616982a17470ab94415f6a509760fa613e4eb00987ffa1dead20f60b4a12984c68d369634a80ad2a3223ae9e86576c29e2477749256c1962ea15d024fdcca34acab32881cbe85daa7a129af5065942caa2b822c4075c2f2e3fe1f6e5ebee3b6bce6c57bdb521a4aae0f819c44277152de237f16d27d9753d80aa584e385ef3094752ba7a0e43456613aa18dd3552d9c56b386b789945c31de01341ea68f320d2281b4e8dda74d524431de4ec8dbf3dec38850b027ec596f8d4f926e357f5cd892326e522a902b2ece9c04ab6d21f06aaa38c8dc2df04f1bad9eaff4f137a826b96520c436cd49e6910312542afe80c29e696a58edc8988783cb6e6aaa168845b14b19de07e8363125c97a8abdca943b7ad546d7dddf387e8a7e89d00b1cd35ac97ce9c7c4777f139c1e4a18a1423b14838b892a96ddc2d8ba254aa9c16dee5eecd0e0ba8e820dbf1b80f0f5f3c868fefb5699ae49507097fdc97ace03293adfc5731343f4a680d8c3891de6b30e8eff323463a64fbbae26a0b18e1d63151b68f5c918703b26e9430f3ea5b6b26b8339106468829c81caaa7d4c7ef00662de87a958acb8de5c600a1bc43cb52e3b9429fbdc01f9a03584c7bce957902f564172571407b36c19a5a8ba5f379cdf2b8620f3eed6b2e37d862809438206c6dea62b8d06a9631ec638f90a8e0bac7ea7b6be05a9106873ae975f028f4f501ba3b90c5fa6e703140d668ca30d7acae65f6d61b90f719745b2f2f96e5bab340705d7a86acb9b0b93e5ca3fbab80419c992dc6ae784aa197fdc2119cfbc4570ce58520777628391c5012b68f053d24514d3bcd353590f90f00b07c12a71e7a8484412502fe806505449a6461459cb57c0c65737f17326aa1351f9d2dc79cc47d20e2ded2044f5616d85f72254ea3ad85a3afc346a610eeb3379c81b1174f923680a90da52be45a28a21bf87caf3695281716007d55f90115a894f623c210294ffc581e1a9f121f0ab62504d68f466c7e513b2509fe197163ee3b1e8037e0ed6a4592801fa928058502aa96cdbe8cb3bb49635c3593b8547092b7eea8d721cc21c770425f0bcc7b6d58d0fd7928c1e12156b045eca58d6454390002a8c81d3d51478e3d536202765785fb51b0a63f4a09bb6ccea31075471dd941fac98e750b3f0d745a4ecaed30680b364d0b85d2a38961bda81c879f132b3007aa1ef54a0bf24866512feac7076dffee45fe6cffd9b6079dc40e16645edd49f4d7aa3046fb97282b3aa7aa27d26b812fbf7b0894da7552ef0b7c5ddbf3c4f2ef4e6ff061aaff61b5873afe5b90829aa085d3f8a05fc351e8363a1c3d8b72e28b2ff4510d425c68972f33e0795a96ac208e2b7b688fe493c877e4208c66f83e117e152da6a5450a5ee5d704b84ab1a2c022c6b76e0b99d90011d55ba11daef8019da1a7ddc3bc4e6e87a9a6c5a60f66642e3263d383e13d5e4f259908fee96f164693d10089c55523f834a7dacfc69280b4daee4b4182603d3b81aeb62ad4a3452fd6ee6c11378ae2fb0b9184e31eb3b779ce4191ea6fbce50f2ebb7a83820e20a64d0b18063eade90642f9e518729c59b44a4c992482b644cbe7cf1833c462970dedffe40bf09225da904810a08b62f0f7fa422397f8a4faeea94d1cab261feb2cbba3479fc5dbac7d491fa7c6f87c64e73ba37818179d9ecf67f26b2a11d2f9ee8a831b33b2b1c514decd1dd84f4921f61c271c79aa319d62005be196c11e3e73d0114dda515208253c4bfd2b5a5224056bc62cb8792bf684f3d606a15018a851d1fd1abab9b5bb0bf03b8ffbb4260ec103b6f9a6c0d3c8ea3c45e47cc42ce0a095b34aa4a9a49d9c53667b8a00311e2adaa00e90000d40307df35ce2af54da7db0a2a587036d719c34df906c4d24ee88410a43ca074bf50cf90e27323093a7e3e9ed5e0cd7ece9f203082c0c53b52bdde8ae3a44bbebadec56d1eaf9584dca8c8db71012f8a98af2b1021d7c83ae05025d8d9340a8531919b31086c48ad4347f751c7beb82dd25027631188327384aa4d9bf81d53373a649b38c5facfd80392f9977f72f924611781f59bb00f0885beb756b158197a23c92007de7ed39e8557d1ecf49dd4d14b0ddc94e5bca66b86320bfba52932b9fe1ae755ce892378730d30d07315ba2392bc4e895b0611f589743ef50fd4ab1445cf9aa79ea728d0f1cc8ad3d3634c21a61b05fc0b86ec5fc14be31bb66c17f35d1367a5f62ef307645bb407b6483c9f35c300d8b485b24a5ceacbd73202884f9205d6a6511b1ae94ce2da64e1011a8b8dff57d35422c6b317272c40aefb414212ec0aa525051f6131eb443be03b9c3faa0d3c2026f413b307a9d56c035abca7e8d683d3ef29c76d39dd69b46a768a748a75a3b8f62bf99038683115c08a43c95317ca20976c3b403c2c26a621cec62a82e9c4c22262e715b6969bece155b1efb0e60fa7913c3c30ec57220b3758e0ce5b400862126317c25bf72dc9a520ea97610d9bb0818190d657c2ecdf5ffe10e0e642f4e92b73d781769864f381b0bf551199436997af111bfc52be47b542b9e1af05ff9a81349c705d419b49d255cb08b9bc14ea21c9397c2c593ba02c4db2e619c78efb828f6f9b2504d1f7bf6c19d66dc3f5c2e159c4b0fe14e1462b728dfc7dcaf355eea0c3acf8dcea7b51ef2116f8d893e9e302bd1651cdecf2550d3a9e5f5fbcb9aa0413877e817e671f05123008ccd680bf681fb03c15a7261e935ff1922d6479139d06bfcbc8e8400fef123760c0f6cab874c634d382b3854f103cd2d9c3fdcd6ed5662540f944cf92b11408be17e161356ff97fad0b0d072a310ac3301859428a686fa60feeb13c6126f7b4962b51f7b2090917f7b9b723c9046aad2ab907a2f9430762f7353ce3fe41a5348199cc65e0cbd4b8a011f3ab0d8a75d475359b60e82f4b2ec1f1db37f0055124a144eaa9feb3bb839674dd0043bad5dd8133c98b3309bdb396dafa7cce84982be34aad977dc24763522d78812c650c77a8096aba59b813baf8b3dfbaaf5315207c2b3babbf6f39cfb404a087d846b972cd8b2903b6d0f5d925e0be91a082ffab11f960a16b38c794f9001619b4f50f7430bdab5ad81e108d5de970279be24a02858582b17ea00ce0c1631bf121864b5a4a6b1c6a7072af5db140805ba08918a832b4cf530560d1d96fb20e24c35f3acd99a502d11e34b16222fc011e03818e69b3df611ae3ee6657d528d2ffc006aee6a7bef91524ec03e033b61f6a10271eb84d9a4e1c3d06319c40345a528e64444a251720cb68a18cf2fb9e7afebc20c2b5e5e271fbeb8d8e1f1d23e5d6b1830e0bd8414e5d89603f62a8d30066573d07ef38f235e89b110b8b24f048939385979c671b1f68708b6b68913b6a0e7b13811dda9ad33cd893fdc78f2daf96e3999bcf726774a58ad8a4b13b1d1811439dea2a45a1ddb73bb686156109905a81cdadfe62a9e50f8cb2713eba56b2a43e5b1441f24d0843e41a65483ad23e417288af689e2518f440f207184ff6210c97a9f0177cd34bc7715e9f6fab838ba4a086b911bf9e6ac38f5e91682442e1fde277b6d04c57700defbc94723c7acf8e94391aa621f279b64fd94fb21f7cfacc767aa8cb618e764321cf7497be9b37f72b1831904f4ef032a2273a35a20da15a903dabbe387d562b8beac141333e58d876ad49078a78feedf2bc8bce27c058301981390cf18a372cf0aa0583f00a046c5b113c0a170b076a052a1ef83922ca5fe299bebda12f08d8cd24a8b108bf6de7bcbbda59449ca6f0afa09f909b5ba153c70eb6a3b5dad89e9148b59a9e710dab7f3c89ece9ab7046d4d6842a1200521b77808e3a7eb2e7904633d7505ac0e42183b3a44a4342122b4671322b95dce2644707b3621f2b34bbb9dc80e8820a191a200410803053d8cd8e991ef9e36238c6c0a13ae4461c4a28438a16497a21348f66ce284ceb7671327687b367122b64bdb84159a80b2298a0503895ae7ac73c6105e2f3a7f8e0aa041f40cc3babf3a87c760dd4f5dfab02707ecbeaf3a00ddd997ac64e9438e0cebbec6ef257988b6258f7453d3d806123975a7a24911284d8a00edd9a488932deed9a4c8cf9e4d8af4ecd2362932830deed9a4c8914db18fd20e6b8e66a34274c708375fba0e690aaef025950823b8bf78bb71d5a9e82d7aa2d4c65fcb16bf4e5cd15b043d9145fbdbf24b62caa0fe561c3ddea3952c5219ddce60529104cdc29910415dc20a0da38455e5e9cf0f4bbab4e79c298d9e3edd99332c4f9f0acd9995a7f42b6dcee4a75f737346f4f47629d8fe1ebd62fb635fb2fd3f22b63f588d9052623b6987ae0f26104c9082ce09f40a4fc90f4484234d0ac315cdf26158c515cdf2a35ef9f0963469d4f96fe7e10f0c454f54d1f62910ead314ecfaf48a5ddf97ecfa95885dbf1a61d7b74aecfa35ded55f6d1fecfaaa6d825d5fafbc8a4e7d5f764ed8f555740bf8a5a764d7ff44158d0aeb8f34e955f449fc120761d7d7a63d7ef925b1eb87f8f51ce91b4d77a60caadd3665d017e94a9b32e8abe89a9b326849cb49c5a64994348b4d1fd3f774a7cbba844dffeab7df88864308e74f1836227c368dbd74992d507f96f5ddc9a69b06d9931ced4fcd016b8368cfd2beea00e0b6240fd19e3fabd831bb9c53b6a638d90b309f8e3c9e4611f6c8bea74f137c10ea090baba63d4092030be9123d3958e834c8d5a009d73252c0aa5e41a1568385578a1c58e82dc145102cf4c4aa9d0851fcc0c2af0645108183d12762708385601584606128564d77c044102c14c5aa7de88e48220856b50f33ac408921988a58f50048c0450c1666d1f50c9ac1aaa640b42a6cb0308b55d39e223458c822ba5e0501ab7a3a51842584e8124a088251253bf8818524b16a6a83190e1696c4aa5d053598c1681744f4c0429413414a100e16b6a862b070e574ae6811584499b2030b53b4064d703ca9154e086ce284c460a18bd3e9e2d38428b0aa1d0547b8800b1b2c5439142b7471c309f12846c066142362b0aa553158f8c2e97c6155ec1bc10843b0aae9135338b1b3030b575de848e107563f8a11b04aaeb27f9844758009a4daf463b0b06a991844f9410ce6c384c2065cd860d30b5092aceb891302ab9a2e718221dc6014ca100d16be10abf64210840716bee720091c1bc5a181a64038192217a30456495274ad9a0256f5ca4f096e301ffc044982602d88558731c4aa7d984f34a9edf8b0120256c9e905284518302d901a060606060606fcb0f70203030304e61a080c08f5c13d2c72ebbdd7af833bf4dedbdd7befbdf7de7befed94dc077beeb5b63953daf73eae2f0b4e286c1b7f385b395b67b78638ab35c369cd681b4b71166ec5364b8a6ce34471167e285b68e3ef71dfac2067e197c971edfa583919241bbf4c6d631610485bb6a01c2ba4899f202d5bc5ac987db264cd6cbe0fa7d52013b93cfdb860991cd5503522e39f7bfa343164df5dc2802b4f3f3bc85dee4d4a979c3d7d6c50367e189ef8cbc260c059d92e658c90762993d343874af51366b54a478ac5f31316ae82983e3503fcc860938167e31c197a367e1cb93963daf80f509b3373e31c191fcc978d2c260db539033a61052004a962e3e923c4c65fca2861db10524226c0507dd9c0116009d365238800390204d5571773d9b062b2f0970400dad88301d7bad9c0d5974c8e8d2077c180b361c574c170845026a7be5a3cb5d5ea71d611a6aba583c9fa3e9d7c5f26a7b64435c8a54cce8459994c8ecc8e030097dbf83d1db4f1b7788474309fb47abc081b3f0086367e9e9c5d92ad9e4dd636fe106605acdcc67354000f74b3868236fe281b1320b7442677367e56cd922a1d9df7dd4f98c7eaf961fffe84d9bf24ab23593bb585af2d4f3f2bb95ddea01ccec27f132375033afd585879c241d133d4c5ec0f1bff2c6f1429ab5dde200f4d3fd764f34893adb6f0d5a6a0dac2569b72a79deffbb43ee99c8c84ae4f3c27243567b1b07c7d50872723559f744e3b27232394e8f4233afdb470ceefba1564c3d94c3fad5c6de1b7a4e9a70607bfd4ca260592108c5de472fae46cfc612ba865ab2f1a6ab5853f8b1f523174af48ea6823539b76b491d909afb863e48e36323a5de779187f1f08e68432f8d8c8f013ca6013c571545111e988461b991d1d233248646a9367cac8466cf278c36e999d15911484bcf22ba38d4c6d86dc0c40cec22ca38d0c1267e10d94a915e40b8036191e67c9d4e68824b280e07fdff77d9f8c920bb046a34c8fe94392681a6d6496380bffa74b6f1a6d6494380b7feffb234b066c999ab370a964329d4ea38d4c2b575faa1cd692ad5ccb7bdb0202f348d498c3330d914b999c95530bea4f40a796969311eac28e8f4e0bea6403f7c45d36c8c67fba9d70b5854f3f4ac8e5f491d9a92dfc57cbf0d416feb0525ae78a4af9810dd2507317908d3fb4221d6da0a1565f3630e853bb630dac6d43e804793a21b4f193339256dbf8b14c0e0d357795d3099c0ddc9ca11bb76c30e064727ab069e009491a789c856336484309daf647d6380d46dc55c9ef7368d0a181c75d93b5f187d357c2d30988a53a9135f83e853eb22d06099da4c4c83901b4f19f70f56561f84ffa8626487060ce94a1e32e1bdb7117c9088fbb5490c8d4dc357afc324adce55224e0c659ba9451b2f1977429d3b3f1937469b26dfc235d9a721b3f8b2e4d421b3f95d1256a8fba875dd1256a67ddc36e912e4d46362677380bbf4988a79e7c72f5a4e32f0cc31fd2e68c69a8660adaf8cb9311a15dde2015b234dd72dbc4c3b3cbd3cfea565f7fca71d74949b6d5d784615cce6d5cae8270b78d7f362e0db96ce3136de332ec61119253af7a7f316894924b999c8d4f4d4eb79313999c50d4373b7c9848b5c47ca4c0b941f5f47383724277e842c137cac6578aa84ac1d8f3edc6787c8cf1e3788ce7ebb89ffa39eab0af226549c007e26149462da323b3436dc2efcbf9f40540db91d4d7381e4512d457e846c13239323acec29fd23273bcb941b5853f2b21fb9f7edc358174cbe62c0c9e7e367e15087e7ffac17f6a82ff74c37f1ac28f92e13f39296138016d7c0adaf824b4f149cac6b88d1ffc1c069cbbca960d8627f86bd9dc55cae47c323958266742616371034c01e7b6bb37cdf2b45f82b51db056c19daecbd913df9cbf3ab7ddfded48db35c2849edd5d255ddeddedd91d15ca75618c0958ecf236d9dd638fd6ba0795740f4ed925b804f4a9fbd2ac6d62f0f683bdf6da6bafb5348b05cd082123848c103242a8d62db200852748b9b6b39d8e4e0764812e12245b6c51abd5786a3c3c75869a6a8db0d58a196aa4d4ec2c6c98ad32e8581974aa0c3a3668a85587065bb78edd3a75ebd8d45081ac7082ddc2083bb3d6083bbb810301b46a458541460d2666b3d91f01c36c369bd1727670684ba0311cda4c071cdaac0a55a0cd68334f0b1cda8c46842734a3cdec86d95b3b5abd9d8dc2867501b331c5060dd5d610a935446c0d119b1a88d450ad0d22d506116b83c80d1c1626dee33e4d76fd54cb11b2ffcd0ed18be1b346cfd85bfe76bc11a9fc287e2803ff735b6ddd6a2be742ae82bda7d6a195dc75962becd418aa63abc181a2a1667328765bf972e2666e064da195096341d5179dd11ef535361f75127b6b68cebab67afaf157b4f8242d7a16adf25da9542a7d772265a35f79afb39dde56dfc068ab7e78bbbf5f9ae2071e5973bf9cb6eebdbfdd7b7eff9650f555535bd5e69a4749ac9933e3aea83fbd0e147922555807c6a7d711fe8904bf07130996f084759a3422555685bc2b1c3b76f071cbc56a6c1948e7a20a56dfa27a79a7808f587d8d3f31b65a0fa5e5ecf07cb61f1fb55577d02137c79b5492cea6b40f95cbcae67e484597d5ab7ed4aa544af5a95fa5542fd23dbc7ccb67dd43921c2fdff23dfca7eeabbe95caa525e52d644c8ac40740c0fc993f6156922d267194f38787ea236f56aaefe58139f4913ebef0b3e187eefae1ac9afa962f6be8969bd54af575f4de750f1c26ec922a7f1d2f3ef53a5cbee5717d69f2bfb79a87e32afea0342dbcfe1c2dbcfe6f819cb565c91cfa49f2c7cb6bf0b5cafe8b4ffd8b56f9ab2c99e3c5a754395cbee55dbee5433aaafc75a4fec5eb687997fb0b78917a173d431b438cb6539be5f0f4f818aac5501490cf4542a8fde1ae9a71ce28d4d7a0dc0e530895511f53efdf1aaafc1cab40e1846132ad48a4d50e1dea0bfc989dfc33680a8d58f228a6eeb8e4dfac24b1dd8edae27156fd2e5cf9f14f5a7c162dfa915679d393def4a0268521e9c33785a4fcdf7b2ba40cf5a79725b92f0302c380c8b0f065b31858f8406418e8d9556c288ed21d3908793f14c7a9c74c275210b4ebdf507f684c45a1dc9bdd77745461b0013b38603e613261c7c4ddef2ea901ba3d962e72f7dd8dc944ba0943f06bdcf5a35e36fad37b9a070ba9b22f928d489565790d00d976468d1e006dd50727254029c3ae3f6901ca994bc64c19f5c318d5024c3ffa1da46f793ade9476d0d868e6a51fe9953f699637e9f0491afc3266e5519f63e551a55f798fccc1f227f2c7e859c237bd8ef04d640f49728c1efc1e3c12d9c308fcb959b4caca8400c92f93895e367ef8329597890fea90011ad3a1ae2d91fe76e05680742eb2c14e11b28805b914e16cfb4567d3ff5d8a70ee9a2253114aba9f984e0cb16d17d9dca5aaa16efaa29f2af211dd3615f1e028602729e989fca2a04d45b8971d213021a2c99e48d893c91034d6eae7c7d89412d9bf8e3fe98de25afe444da41df54573413b9ca411732326e97234f51732bc2c60c24a1f52f145a6fa17aa1ff58b07021b1f0720b091fc0104f623498e173fbeea73fc60c11028416023f9e3070b864089c15ef4c061c24aa42cf52dbffab92263b28a8ca9e5194a6400f4458bd056fdcac202825b03b4c65d08f9fb8f870a7cf1313f2326c692944506f9e3e16f9f0549fe7e8e3dfc2da901ba6f0c3938abc6947c770fcbd245fefe9b42473b7a8fa3be5cc8596fea6b45ceda0a3f09bc72f9b265973467ceb4ccd9a238d855896d57fa6a1e4ee230613219ea532f3b7dcbe33061a50fad98c303e68b8715a06460caa89fa764dfaa5ffd8e17fff273bc71c171d134e745d3156d865ff6f22e3d54aa7ff117dfa8fed353b580d5ab5ec7ea55640f4972b8bcea7b7859bd0ed5bf207b7021e75f3db7a7ba51f9b9c75f699557e9f1533a7f8b163d4ab3fc49af3c498b6fd2a3f75af484a1f4849df48499f64d8994c984883f7a998ce565f9555eb6f232d18f36074d7734ad51db48d35bae30163d612bb031a77444d661474e2601f93c2711f11373ca807699270542f207306c5a8b1848aa0b780063077a8b168a686992e74f2f0c2d89d278cc942497a8ff477d0cac4aa3d6175f90593470bcb20fa1ed3ea0f808dafe3e6afb02de0df7ec505b9624511a7aab48d49efe24f13e326bcb0699beffd46207b29298ace5b927a5428bec64fb948104afb9097298b8797d203da8aafb3d6a767d207b8e365475491bb605ead739839d2ff75eeddb279db25d973e04d9fe934e3aabcab53f79d0297bd2ed5a557f6e0bccaf93b453b6fb9c32701155f797d278104a43afada61b64faf84becf9e5c6cbc6248f979b370f2ab431cd8dd555ba2b121370bf0775e9bbfe073ea6a37dac67d873b4e17ee97bbc31c3c6248f1976a5d6ab55d1806f0e741b93ef911d69c3252d893fda15a1864fbb6f35aa80317bf4650c9b65b268cc0ac3db795f48da31013f76891f072048d4826c618227920c410930ac755903fefc234d774dc57a6e92460565fa2a61386a5b431fa2067f862059fe4039cb49190b570a4c6411b4bb57d9d0fd7d51fd2f01dd7f259db2f194fd910ae81e6bd1f6ea0dd1b6240fd106e2518a03da767bc597ed30569d00a8b8815ff854fccdc31fe882d81a5900b8b7a7d27a44904603a4d517067768b0768c159616662331a3aa8651926b381a6d6e2555910d49e2ce8e9e8d36375b5b123136bdc0010e7ab60b6a458496946a857279617a29d9d7b49c4b7396bb4012dc217b5a5c692e02d06be04713ffee5c2566ed22e9e9401a38e422d9f4f28821485b58819163d0cef360c41c5125a3ba15d2a3482b8fc2a4ecd11d0260fc66e8bb6a8bfa664bf43a1db2441a6d16c6c000602fbfb50170a10a40ccfe02699746ab229779e697166367a4405a1656684fccba608c67b1694c0dc18b64831abf000386edefab9fdcc3ee558ebb6438a1bdb05dc75fd85d2e6c37b27db56f8e0fc00940adbf88904bbba70044b40244f1f104294f988207272dd07d4dc025add39c5c9f07cf936e7f7fea4ec21bb37e587ad0ae37e6a60f64d3727e9ddf4d20fb921d154047690e72a217f9ca398bd29ccf2797a22c12a9d0d702a1fb39501af0adcd6e4ae7d0149ab91c04280d4896f442c07a0ed42120b4adae5145dcfd6332c605d9ffa77a248e7a1fdfabc3b410b8b7dab67d81c7d3097551baa179ebb8e8b8e8a274421d17dd10cff6340574c03be470249734b633505f371337873aa18e8bea3a872a8517eef5c4f35eb90bdcd92b09af272fdc2b09afdcd5b9393d53c69015e4f2f64c7a67e5ad4dfdc2bd92505ddf21a0ad6ae14328d00e45b719a5b95f2b90f54a1e2a1da2a3435c4a67960e418186ecaa7f658de472dab2b74431fb1094866e6beb2d0739f5bdb794c6bee7594bce996dd7915de7d67a90cdd99e2639cb2d0d677d2cc879d650d63f6abe72575d53bb85fdc9d9a1883e7629a134187f6973c45ae98dfe509b77f8521bd88e2ab136b039eeaaffb3afae4163b4a93bd4d7bcce22a9ae4941de01574b96a85de2b0acdb2bcf16b581cdd9558b76a7e3c2884799ce9af6765f7ad02ee9771d59f27037b501dc94eca800e677e30defbb4a6be751dc457ffe35b2b1a63165d0fa596badcf69adb5411da5a17b46d973bca475d6ec41f5b1f86378f021dbee9207ef7af7e7244bd2253fb2a4dd680338ff8e37bcaff5ed0028cd103bda4c9f8d358d189c756b7c49e49b8af19c13cf18e600280dddd6569d63d0c4cc898f136e3e403edf4e8dc75d24ab4b3adb752681d2d05d6b98db73ac6446f9ed8e8052ea01a803c480085c603144912c540186c4a72683309358566238a142a6c6f4d93e9b5cc189ed506001070b339022440a11b67f0c8d23b6fb648109db7dbaa8c1f6cfb721365004c3154ab0ebab4831a70f62982fc4b03d88b5fd71a66d7fd45015dbffb1d0d9fe2c22b65b8108db7fa45123054ea0800452ac0087053087012d07eeee5e16be91d4d8f5c39f2ad056d8882bba26b898624f31c51b6d7c1405158a00b3fdbb112421df79a38210bbbe153d11050ae47601e054a1e2eeee360a0e761de1327dd21653f6cc76541026a5734e2a3292f1dd22365ffeb7d2d16f125036ff097b9ea7050ecea5795ae41c61711cd11d21419d5d2d72800227a17090e028c159e2ad89d2a28a22b488284548f1d6dc25ce3e5a6471c40f0e236e8ec23101a2273c010bae88bd302102172b6451e7c51272c8f3c4154b3471c50f70704510565272b7a7cf15391b206a4c84e4a6508489902725b0face6be79c77de17603c8a55b707a4e3513b72f2a8d66226e8d417406d7af19db5de492b9dddca74d6fd89c4efbd8f474a9b4821dbb3be1c45c93286d27a5fdb951ba45862dfd2969f9c63bfd6da5d5b3d2788ec7b1763dba74183bfbe18e9c9b6372300d98c00b48f20c42e6b6cdbd17900df549c5d37278929cdb7e7cb9c35f70d7653d25bac0ead5bb9410aec2edbc5f6485f421eed692bc215fbd26837249c13c8d3270b297bfa6401659761cea6ffc29e3e59d8c29d4d5f55dfeefaaafa1386bfc428d6fce968605ccebd1c17335f98e766beae0df3501e67619edaca0d522871d6e441e22cfab846621e67d167a122971198b2ed8760dbf79f98a7bec05b6dd1a7377dc3144a9c35774a28fbcf7d7fee7b7dbc652bc59c2c718fc5d5175662b6e8cf2087834d9f898dcbe184308f631e27f4419cbb449b7e1873d7dc94b640087ce2aee92384db94478495a0d0a6e0d0a6e06d535809e6367d5b9d07a746eb196223f253e48684eb6cfab4f42a367d4a6f0f367d5a7a50367d8a8fe02314095d42799a388961979407080a8df2825d52299b2ab14b976d140bc50241cc73a33d1e14777942de9027e409794378e609e11c1efab7073470d0f8e9725dd0b5d9aecc5d77766797766777e7ce6ead0a1f62304ceea8ad1ae409c3bf436dd19f40334807fe8f54dd7c73bcc1a46a3a0b088c67d357422e1d57e3a92dfaf7a6e3ae9dfac2b5ea3ca8fc28164feef9c13cd786c49c71af9554d99f56fbf85164ced4c7c00526900d9754753ff79d403bd5d18f592273c69f02ed23373f88a64ce92206c3642c89bf0f130896c4bf921667368436c4891124613b2d47c771dca5a23b469c451ff3609e4d6bb8f3c2493867fd8d53c5ae64994372ce230cc56c0f8a71d7dcc15d94f40cec30674e35f79869851c4488ed22d85ec52c6716db6f4c02ccd7cfd6fc2ab6ff9c4eb3639cd0147096ff9c4d44b4099a3f0f582cd92e739b0f164798420c764975b65f3b8132c9f26c3fb2cb1adb27490177cd7fcdb07dfa60e3b03267ec6f8c31ae2d18f599a7f1474ed2f31e7bb6e4a1ee5a4b4cc33b08e74acc5eed1d6d68d4c016060bb5ea481e0ae3bf21da78cae83c0f7f3622131572896fb86c711c6d52478051b2545249c84e96abcfa3cd5ca12b574575806efbfb76b264c09e7305a20d9e3274f982375d054f19f3cb0a6c4a8255989462209bee9a0c2809b8d8947c229c30e68442ae7b62304321fb68c384a267778fc36ca9be95b3ea875fd834cae98332f564c75334c1391dfcceae33ca59d5da7f5be33628ffef9a5b86f2574b96b94e18f51211ca92f4b80f333d104feb0b25a2c6b716978ba1316df367de6eadb5d6ee3dd0cba9175db78834ea55740b08b63cf828b0e5a63e3d65d4bf9aa402a84f4d1a86b7ea87f8ff512def3d8ffbfef6be6314aae5e7e84d4d621e97b4dd76ed6d9990d30b31bde779dd26b168c4dc6c8e790e4621b1accc55163905e83bfec1a1e27d60288e2adec571c371f31b46f845fafa2189e5f3d3b187ff68c432ca58e7d14f98bb7af4e001efbcc5d7477e9fad96c0044a5667493ab0e4a7a3caf17737230e600ee4ede40dcec2dfcdfb6161c95f47959337dfe33061df8fb42c7c9044cac417ad7cb5223b1a597b03a5f1d9ae0bf89ee593f8ff58c9813f933f4424bef15e657c317cf0bb0183a2ca178e1eccbbc1615d1cc14e76518dab548d0f7518b1984e3b9467c2c44e071dea6bc26a680cd1b0e0750a80d6512e2d1f5211a593ac5c3ed4abd58befb26a2165a737bd0ad7382c242d8d24b99bf1c00c7d7d600ed1984334bc1aef481f1e266f5c56dfd19833f8ebcbd0a081bdb79e7dec1e0d7751c059f5256473eee2b27a1fbbdf515faa4fbd7dfca18b7ef9957ef12addf2298d0a129b33de467d25b25da81058fc97cf21fecb47e608ff05f903f5a1f82b1dbe4a4f98068094fef432d29b9e87eaa6857cf1e7ce71d22a6fd2e39774067fa457e62e8df484ddc8565ec642817014ad882ad9661310cf555a60c593ca48841aabfde12efbf276e24c2f7ac2acb5d692b892d35616d9cae717b54c7cd18f7492ee9258f4af68fc59cb80c8b0d27b2fd2406458cb8b7a16032bbdb52f5ee55ff4f8a747bd3efd8b468922eac53f89a8f7ef05297379d3abc0132aac28d4c9abd653867dd7284dd296fdd0eb97e4cd09f5f704c3b62e84e43ff8350e7ea713aa92ab777999ea4daf0120bbfbb0454f988bce6fd2a25f699657a5f4e83dd58d8acaf821155d8ea0de437d8b9e65d8e94b5a06440cecf4b30c4399507ad6d68da9a427ccb26a6b45e3a82dfb59cfda12ed5b5b02823dc4b12e2e5fb26894dedffe0e1dea4b7ccb6243cb620aadb5957cd428c9fd6ea4abfdeefbfceef2299717756a1c533fbecb9862d1aafb2c3f61a156dd0f5fa47b4892a3e547df83ea4bafa27b68f9d17f5fe33e8e2e37bbb55eebadd55a6badb5d65a5bafb5d65a6b2d6a0a213b4d896effda1fedbb58bb63cab0cf2283ecd5eb7b9dbfbbb8a4c651fc1aafbac747aaf0eb407de9759c7ef45d4aabeaa71e08cc45ab2af9b5bef8a00a043f5b84675b6b51429688b5b626837d2bf2835d521cf0ab4576b6fd18ec78c3e5738cef42fe48f2fd8afca12255f5515ffaf13f3287f829f2470ba9c2e402505f7a552573a0c8d29f7ef4aa1ca71ffd899c2ffe3591aa5b2255f77ebecff232597e99ca8b2a3a03b5653fb3e851dba1908ab63602e2798ee5f2ade29f1598ad51531fa4af01d056cdf1631baa31fff19b078de8507dd5d850cc7b76dc78cfed8652bcc7eb877af6b0fce1498b3fd2e15b8dc384c9569ef46952066238047fa50b1848fe00c2c3c91bd9294875b34292c81bff0f5503d6405b1447a1a037fa03daaa6f3bef28fdb16f49a415efc3c19451bf06f71cd0567defb15f7acf7d5b037d511ed0160fe814b4559f369932a49832ea536ff7b03715970b82d1997d7be4f4561f9961d8e9a73b3942fa923eb9219156de8e2a8fbc01c1ef57f48d96b190f2e39de9cfcd898e5c88c2483299ca8ba1290a54a9a7a4a170a1e92a474a5fe327eda6211d1456227f0081d121edb4daaa3cac6c9a22fb120f73873728287bbbbc41612e08ec62dc0973ce124551e4f1ba9ff5be6559c2d0cce7f613a589bb4a9167bcb94b5424fb937290cb3077dbfe62933943eb4b7c7f518a49333a610a60a8be4472b4d5967f48962f8e180025007629f2a8609b6d88922398851c024d19fe653823c18f38db8138440f4422c42386300b6fdbc599494a2ec3dcf65f62f3d9fee11646824222520891d8564c1716d345c319a04224dbc3a0ed415e69983365e894e18e3834dae8681b6db5c228c93768d39110e8b98839afbbbbbbbbfbc52218e4faa1bbd3d1c61de3aecbb1b91ff171dcf890e5b8c17140a2f8a22f450ee02dfefc298a74ada2288aa2e80f5e71ce8c2a2a9a357e4e167dd9c572fb278e39435542402959de1d7444743f4c5710d375bbd84f37bfbb1e13fe5ae17f7320799b305ddfbbb0f8b9298efc3fac65de5d7c0fdf718ca318823a3b4b6c3e3920d1c31f84e69c373b623839e410a20ee5de1871229339e9ba229e14e1a48928488c8c38c426127230fc2a0ccbb5e5ab0e2594298571ffb77f507de1a7e40b9695e3070c4230ef314e94cd040747072769d4568c901b0d5d8ded67ee0667390e2d72397fae0ff2cdd9db4dd7e5088158c8f633aae6861569fafc0b76dc545f19ec2b833933b7925dbeb598521a1d2939dab4e07299adabe69cefbdb42135263336278dd119add1251487cae88e539d8fc668f87ddff77d3f9f6a31fcf44f19fe1806b9a4318b82ed1e041532693a1dead91df54563b5e594065301f8489698c43adb69ac62eae335b2e9975e5f5f5b355e7fce504be9a4b56b80fbb883c6f687698cc640f0cb9932747696d8ba9d500517e37fea187f47e99c9452ea2cb2c47f7f77d7de6ba242ee30a6189c227737e762ef3f5c53d2b3e486292e6255d65e77777777777ba9d3e96e434d42022aa6d427560c99a30332194b72df8724f4a9aae508f93e7d55f74076479674535a276b09cb5933b8ed183b871760f8156361d622af502bc6e68c6fa794524ac5184b159952b204a56cff300b53864b9933599834e30ec45809da7420c662e39229c37f1c7fc8d126c6dec6048662fb5f2a6e0f14b9fc9eebb2ff5d776dce7803228a98c7a811a319aa814313441365fb7f5455c3b8ebfb8b7ce919303df54592336a303d3851a050f74d83aba42847038546480454c5952379466dce8c9474924543a30741dcb84576d768e8e502a22167e5584fae16a0648ebdd8764de5ecfae2e7069336a35612a2142bcd7685e981e999ad1b7c901750ecfa3822bb3ecd116870336a0f8ec01109bcaad248352a8d46e4dc2228ce0a02b508e8558ab190b112a62755ab2d3791a91a481a8123d268f473b3984aa0092c81e0cf6d7affd28885049aa02cd9fe54c859db248af262db9fa81224832fca39cb06244540f5c5b64543222939e62e304614241adaf54bd16dd75284dbb53e0d13d30582b63933daf5534ad85ee354ec2a72727936f877a7be66d4c0d412e05f21a62b557b907c1024c15bdb336af5458383e971d612d305a3831934b8fa8aa971960ea6cbc664f97b578aed90d6c7f636675cea83b63dbd0fb2c1ff5e904bf06eaaa2303d304b606c30413051fc35819083f131a249aae6647b85e981c9c140d94e1ffc6aaa96ea7197bba64d297157c5c212a95a6ac90f0cc6f5697031722e04c1f4c0f414208612303d336a650c6e9622697035b329c34b10b7fd6970337a06101b80ac0034b84c83a3a8166230b4185b4081225485a21c91cb19b59a6dc60d46482e67d46638715709e270ee2a69704f3e253deea23eeeaa336eee5289607aa81601695190b3fc6b207197ea6190b63f8d7f0d9e39136eff9ad99c396d676def7116bd4b7658453ade089f92214c12a2dc4a95fa16d4e9fd4d51e4920677e4697073a6b5333e4c0f8c2cb2cad3e0ea2bc62cc60c0606b9a4c1cdb697fec507b9ab04c55d2fde9f46c85da6f7a7197297caf473bfbc3f8d1477b9c464eec271970bc903dd363477fdfbd7185243c75daad2cfedf2feaf672c31e9194af48c1e67f9bfd0336a253dc345cff08965d4b7bce87db429e9b95d4e339474bf72247f34b8efa3c1d13c71d7646204d0f6a7c9b9eb65fbd798d518e2af29858d06c85d9309cdb67d060d8e66e8875dd688754c8e4862973570b6e7afd2193dee2aefcde6aeb214fb71570933a336c3451aec92b483cca8c12cf1578c1c4c8fbb4aef3172a41841db617a6a60ed121923e79925466ebbea575fcea86dd5d3d12695577ea5639ee8985c4ac700e998201d0345c708e15aa6c865aab65fe45e707366fef77d9f9acd19d3cbaeb584130d9562de36917786a394fea84496191cdafe32d2385c991262fbb3685c997709d39323d2a5a802d3b3fdbf32552bbd5dcea86d7f910677812b0212e5be2f411c78776a8bfe1562b2280ea86f4d5f25ceea59e2f3435fd3e0687051c45e5c4647abb5ce3a67eaccd54cc5af7e1ffe70a55ea91ef74d75f7ed31dca5c45f5f4ce63fdc71a59ee8cde98d735e9ab33e8b71ad18e3a7fadbd35d38ac6e5d8576e38d71ca70daf27717b693dbf5915c7dd4d7f84ef57456472e60facf188fa136372d50641c77e1f7efab3747c7eab27634151c542f57db91a5b8ebdf7b6ffd7a5b96c8f567b5b6de6a1def4a53304a729d2109a81466f6177108bcf71ef4dcd22085596d09ecfd88703b229d57499948f6447cbfebc087f12705221f16434c43a256fbb492160970f665010924e8ad4f2d1690c0dd15c21a34669ed6637096bfc7d8db7d59e41758acdbdd22328cffceb32b9487ebd4c1d3d64c8c3fec89c0c375888cf7641204151bc724081f172e32b8279320729099042183673d0c160eda5008b2684f2641ec2891f39e4c82a0b182983d8cdc2e3f068839e77477d2ddab57afb5d6eab5563bdddde79c334791e9572a2ab960cee95e175e6f5491edbbf6eda5e0b262c4f0c2131a97556bad3cd04d81a0b02437bcfefc162972c9daf52e719765b1585d774fb0438182b6ef800225312730c1490c084687840461971e739f39cef6d2a9929eed305428c14591118400c8c90c76497facd825bd6ddfb79a0e5ab88abbbb046e5294c00841b8a2083aa8ed92e6fcd0c42ea9916dab2d1a535f4076206382125494c0c70945c0ac0c46b0cb690b3117410891c49212902006308fc1f6cf4fb6fbdb26bb5cedd52e616cfb8316dbdac759675b2632296cfb6f836d1f8f3696c6850dbe37da801bf583fd7ddf8d365f0d160c120545a696def0c3106f4d5a5f28f2f6436ce3c7efaed23eea5725de1f5241c806a31453ca240428d89e8df7b1ddb9cd6d412eec5b81c8a5df72a8582c16025b2c06a36f35ae2fcf798ea7a4048d1dc3125d90e9fbcd83dc555f14e63b422a3a617d8a8a9103c6aa09cb270a35279d9a56d1fdb654166acaa8bfc2835cde5a37c7969fcbe32ef7502814c6ee5d5b118476fdb9386edc1563d7f721cb51a750c5e1ae492775776a8ae2841222d3205f5bb57e2bfb47cfbceb4391cbf973714f708884bc1e9ce9bcd1b032a099a7105490032c4a60c52dc82cc911389516320810bb3e0a4701756289c22486825ddf9445a082122d0961ca0f767d920f72175418c2f61f61ba138bc586c839a2e2a8f4ac5576412d999a19400000004315002028140c078482d160982469b0990f14000c729c507c561c8983491203290a42c818648c21c4008091919111920600e3758b202a1e72c41db98935736a6ab3042b74b50864388f23b89f1cef87130ab440f987866fc0b81c16a5a7b15f9827464fe9397232f79a89aba806d058cb464e689f2d6a5c1afa8779fcf659668d6e8c11302245d84c1f7ca6055dda1f1253094126ea5d382b01b6acec852040193c054fd35d735f8d04f3701059b12ad698eb7bdc6ce190b639d1305506caf29770f3302e33f0271fcd4ad636ea9ad74f5f04fc0347585d7061798fcb488da1e9319297521b02d8a5471614e62bdc8470e6652b38cd95d28d0404ec0f6acf8588f1805560be229a670f67fa56b9b001a47a4909f6451b580acadbc5c21ff9066cac40338e7b209eaa51d81eef17d5aacc85ba7ae517685d148bc0592b645cfb3c63f5a8d12cc34d2ef8d9563d9980efd8ba0d422d5eba585fe643ab56346d51d85eeb5110726d904f6784043a10fdebee40d7ffe9a474d342df80aee9009b6659489cbf888df8a3dcb024991f2c824afc4b90b1d20d9ef977668f74c9a895e11ecb94a22f4ba13d2e27160eed64aa480c6c4a108af29a3ee69af3929cee885db8c380f05ce6cdf66a177ef195750a9158fc7b004d33d295f6511afa93eb2eb82a299eb14bf646e826562998fe70c9bf49c8ac2721de92391a27bdc1fc2dc5cfa90dc257ca1f047f6a99b1bfc5c8cea8886364d470cd0b8ed95b3ff93ceaaf09b25c91f115a2f3d780378ee16ff985bb273ff6c3cdc6ae663f7b3b380d9669bc3db5505cd0d7680308eddd52355cd00f799f9cfcc8966f4b3b232833cabf90a35060f76c59eb190b6bf652eb8a42b6c6cd1b29bc340e015557e4b0b5fcf784a010b427bf274f72b0dc296937c0a78a8b6c5ae41ebab2cdcc75b30be81e7e8d475109addeea09abedc93572652bc2f594f6f0588005a656ff451623b88ba977b3ba91d11d3ba3e95585c967a472d7d761f3b2ef711801223812eaee67c49353c15de4788f4514b30a5a00261b38a08eae8332b99ba0d73fb2994b564dacfe9d7be4123f45128cf216c3e1f0a6a32c0dec15dfac6d15750fc3d664da333bcf6b7e30583c288357a387be2857ab9f38b615bf76966d2cf073f457ece1eeb495ae2cbdd9c8c5177f6051789489a45f1d8990462189c1f7097e358318afd18cc4c1bdf506df3a7909a1d7051f93afba7a147651061f0ae9bc0c43dd61ae2adb73fa9e748f207b13ae924318af2ef83111e50d47870baf8e3948d995e843ecc8dbe19553444240b2d03f0f551d4ecd2bef8821cccd29a41f06daaf61fd69ba6c9c17efb695e95da7121e988e92dfbfa2081e4ff1155359e6c723064d90ee50a1469cdf2258362c554c3310829b9e18c1e6beb5a362f339069b1995e7125909f5b252cc2e26c1e7529e68cd134cbc9945178e19a75f654b6ca873bc05c9e20ff029c7e781c60d70ecfd386484b0d5f8659a5051b38a5a5483ff29bd09732d51cd19a4a830e8b6dfb60aa497532bffb9f5ae606b6a4f6292e6e5fa708f17ca35958072feede7fc7c0b5218673de0f83a8dcc294359b0dd9f63485085230deb8178f265fdcc57bd33746d2a863a15a14922cf1605a2283f412000f11f959cbd7c09373d8fb83afe02dc04b92b7c404c1225f42629606dec67de6b88720626ed139a2d72cb2554edf94fc2e38b348b8cdf0b53cc244440686c934ce12a56e82abee2ecaa45f5a66dd86f7c184e12c42026397644b80d5c9573083f8f29e26bf4bc0ae056d9b4c99a4ff36daed93b3b60061444f1a71c9080f4b1d28dee88aff081eb07998ad813b3234a38b52b371182043ddaba1a7c106cd61e5c8c71e6f7e73dfadef3a3d249a9a0d14001bd45b43d08638d65078da8e003f40f3d452db2a67574ee27794e75342b75b9bd5daf3bbc3522cedc10b6ca9a87c952cbadd9b046973c99913c0297cb90fac76439971ef00c116549668beae4db26367afd70d6a291b2b48f0fc06a998ec1111eeceb6d4cfda1a1cd165a3eb186dcac270f387238bfa720301d7682dc95b28f13304239ab055321323bdc54e940b117475bdc702605093b0c645c1881c0769c2631238a51b1a0a82a2faeac7272b981ae62ddd824dd76ce61a97551717e797e6c72b7e70048905b22ceee1229db752d05ce167002416a544f9e8100a1d42422428f3041558c6cfea05225007ca35248491f678df18fc0fa48200933dd817c692970cd6710bb6c22e18dde8844d43188211f4aa455d24577b2b9112ca0e74dc1be4636eb3bedb62337c3d4ad232916b9ae8e7a905b371fc61c89159e876a4f883754305e0cbb5c6280d35c1f350d9f82eea7e61452f0bcaa2988934237967b20835e1e06c47368a749e5b2134f348bbdb50e16e739eda7c0fa6882ded8dba7d4ed4150dd442b2734c52de149d344c86cd59a709a53ceaf008c4e9ac6624f9992f559b4001fbec11c0aeccb3f128cf9166d3b011c275d814d4601aea0f3ed156cdb638bdc9cabc3f61105bc1d2b98159778b6fd2747002a8f775f1048b1724c8149cfff1a1c6838d440194643932795aa1595bbf75bd56c8b63226e4ec92e64438ea0a07139d3893ef3e380312b33010d58f0894b3163032560c7d368b5a94209d0771bc00c6267389626ae4b54a313048c7ca42a6df5e86c652f09e11f6c7645201f4f9e1b38745238d8ddad3f9d9e7f4da780aadb41e9d72ad87fc7b889bc202243af4fb062de12b0946c0e2e05d286973f0f0a3ff4d4e1c12419c01b61037ab3234142a3fd27f7563fd2821151d7781757237838849b6265f2d513dbe6bfa5da50e7ee425bd3ca76c6dc7ccd6f9e6424b6206c3452cbafaeb4e53623e56f41613e1e3d107530348360cb45c9d48d13dabfc20ce3ee6653f1ed13f431c762a55c2b83130d7a92b67c9c8a2f163c04f937dd395cdde4daee943b2ebfe73cc4a6fb1066fc0b1b3e2fab42f58d2a58ba76deb620914fb2ab97c7efb215bc7fef6ba91b3e80661b2216a98baa786e99db0c562d4c865f84cd717819f21345435fff68e45039671dac4017da97dde48a8ce6cc56fbaab4ac9105bd7f7942fdbad9145d5efa2005f5e6eebbf674827054b788c55618638b1774ca16963d7178723b1bf98db2063e3797861fe081da9ad39c9e668d48e589efaf373ad5534b57e276e400ba3f4c37492900d20f0fc1a930bf387b728ab24b0131e3c0f5e0a525501382dc874a91d20c4172656bb5eb6cf86b3d3c8e402f5367156b522b48d852c3183e1e8a187d1687561bd1bb6e2db17f2dcedc13abfa6ab8fd17d385fa1e47a22e365e879a3946649b731c4415b8b7f37ae47947c8f27440c7fab87e99e02ab8cd06ef4c44dd70f62d52590d7e3527071ed162a48b04cb670787e1248f4d1bf93a1a050ad9d8a65c837e2cae5e2155d4a21610dde28e8ecd9ab6e8d4e71a185b5fc6a23b7661ea4b7d8047da4d54d7e12830eb27ce6df137cc76593963fe41979d2b0458bab5b83f051c6931006a33553d2fdd8570f3d1130165fdce89daee85df92c0ca858f1eb49c18ada93564206ea584b5dfd2572eaf48b6ff0ffdd73a0811f7162940d5111f0cacac09433af95496841cf4dece0b5b98419e4479f523be02128a5ea908898b79b608b6db3f0e1d87edb4959dc5dc898dc5282037a1ced9084a88f0ceaa39705964ea34a9598a69024f28a6e5088e1a1c347150d81910150933f85eb92f4170fc727a7d04b4553564f4edfd62b7c678859e978e02c37e56f7444be10b998f579167f743b44f203c6e32af55f3802c664b42dce381d2528ed306dd6b3cbf903a289c6dc99a5f918bfc4e097bc220f017c94ceb1059fcde4a26f19814e25a6080b740e4d741bb2ddb6d504cc434ce454117299cbdfd809e830b4f45be70d28c15b3844218c11568e9a286542ae7907c72cd6ebe684e5f5b968968279f4e1f2092ad8ce69136c162cf872cd3766dd968f952940f9ffbb8071907892abcb8c4c8fcda91de1f8744d9f9b444f856b8acd6797b23e1737ee54a6a2b38e6f11e468fd68ac82643ff0380976861327b70f58690094630009b76b3b52343800e13245c1601d6d525812e99c988ebe5d98654e91da79a6aee3e2e61ab83770c0acc3b3395f6f028eef91f4268b88b8b9b9abe30fa1ce680949a152f174552ca2c1a1534b5768d82f96c0d8d13cfe1de833cf0406f3856f04fe42f6a0600ac606f0a344a8150e97ea69272035cf84e4447a675196edea64d30506a5e4e50c913e0bbe6017b9fe34eb4db393cda67c276d7dbd0c229de47fb74807d1a73170bd442d94a42a58b5a8640723fa13a692a834a1cc88670e03b6014020d8eca83e48daa326ed16e5b7b2537d12c8ab287bf8096ca7ed7c405825371c4254b1e3b222b893dd1697223686863514cf99b047a58631a828ac94445c3928de4e23a81354d1533a11971676a9deabb636e4c6e145f93fad9a9f721ae4238a3074226d5c8159069e2c36d7edda427f8db01e3837c65f382145a42b8f8b956ef80d85af735e448081344a457d088f9f6dacbe97790ab25ceb10339020dde167dc1db66e27b5d43461d47c478601e2d105a86a6d126d351ed2f55e2981e39d16c5e55ae5893f3cf6e85aa93b88a907daea89470a10790af9764b482ef4d407b318aa0affb9536fc4e2ad0c7204710d96e2586cab8d10a2a50876b8dbc446e46ca85dfdfd7064aaf2a4c5b02c6d17d1265ab083336bc4db4e8c3d8c927c4b2c1708a09031ffcd677ef6922a885a971b61c3b3d549c017e6aaf8d02b7c651a9125338c267ab709f41f7ce236b581b5cd84be08db75e53543e7967a4485bfeee1886de3372f83573b0b6dbb0f40c57ff1d0c60b068b98875c7555a072dbd5ef46d402a2cd207de09639b88a0f0c0a5ebb70db2d076b0e1a9136e5b1e39cf7ddce79eb966e515b2681d0ee2bf8543cc7c7caadcacf96d415ab06d56fd86e20ceab0df146b5ba2d6a277ea2b25b2cb563bfb15257e196baf948c82ae1cf18417c8c6350838ab3dc84d05507b8e7813467ae10b7b07cb4be47d8f61aec70f68c254dbba40881eeb69805a493bcbde2ae322a8ccff8246f31425688a427473d4993ca6eeaf1b24b2f04f8caf72d452b9c2890bd0f61d33fa15929b21286e9b01d4c1a2afd2476b2d372f35a669bc0fc637f9e8be2415ab4fd59ec2e55a8bdd05979da7aabbb9b392139d7d1b090591142ef5c6eaca30c4a985434f8bb6c8e12079e802dc0e09f1c7f837c2fcde8a726d54053e13aac9ed357479f9616085aa58b4468197a7df1acdd7d359b18f1a98a08d1fdcd1ba30afb0cd92fe0e0e78717f96f1b0a26774c673ca7bb46f45c812c6f8bc485613332fe73dfb2bf272ec562b9e8087e7400fcbad266cfb7e90a141044f3848480928d18d52d6a87bed42ae852105d468711408689eae4ee4d7599c573188b17b50eecbe8a4346de7b1051a1b4493c0b958df40ff3928b86b491ae4a089f1e5b0cda2fe9844c190ee8cf9c3c36676f9f96a8cd3e97b0314582818cc80e8a03c2fa4d2d45bb8445454f1a787a6bca6a2669d289a3db793c20ceb5ad8bfd6c4b9414eb3007aff56c89dcf1956e3cd07c1aec35622e113065c5cb323585bdc02c5a9be18b79d73534eb8f9e26b4a8680fafeda0e09ed5691cd3273d56556377b8d697937e4518b2a09ede5457b04f058f01e6b07933a645ff93f1ad69c71fe82e495577882d222d573d5cc10630b066b40e7cda386a9685ceaaad60c5d8e2b206d976d3ec0c55e5bb921f4cca4ac5cdae0d5a94b1d7c2eca063f81f397bc552a2de1d1c7ddeee31fa085330321afbc68675e08fe8be2a5bb4dcfb708ff10f21947280e21b39692d01b72139c20980742318e2280a7a452e99697f8609f4a450b774d468c9541d3919eb1baa92d9d6de813b9df42517ab8981b7bcfe9608a2fba0fdfaff9c41f1b20e99be0d61de69bd21786b13ec22e0cdbc98982b584a6c33292adfe62350a8ed44775d9d92a14fe354c804b455e2afd506cacb44be78162c8c7d8da41908520d33b32a6a8d6e887e8698da069a3a9b3d42f0b9f510cd648a37187df8b7463a6c5bd91726cc744d149ee95823f3169355ff9530e87a8e988937488f44a3e2e53ee13729b6954afc3dd72b595f7fe4277dd6c301ee873fd2462d3b848433a26dc70e28fbbeaba6b44a6a350002b747924ff3e1f2d51c508c378b2509a3e9cde6561740b17e368b4aecef8dd09d5184cc63821d690700a6b85a03eb28f4c6013ff92f3156ee2ab71b2451d9b4231ab4d01f4df7df5fb4e3f83117a80793d120c58548464a2fae93b5370c78e772700eff7c27b5d5fe4d2c28ed0348e7fd1ec44787f78dc811bc6dd8351073e1e9691dfaf502f391bd8835fac95d4a91ba8cfbe73b8bc93e12cf7b6ea3751bf45d8613a26c3f6fc403cd5d2d9ee54505232f7267b1a00e9c93442f8b31cd15c14ce232d805bf743c7fafc722efe841339dd3bdb409de5a335380b8ed0b7dd30e1cb3439f055c1919b8025cf9a2ecd444821ea3592747403ed15b23e57b47185d6af28ae4683b32203e5f0670bff56091ba01975b91a757cd27f291f77552f6c8e6650e9ab76f2d30811a3632db0341da1422968ff103a8815d65012ad4ca3a37f0b64b8f6cb651e9e269e4b6f626dd8d817199c4e2bce4bdad160cb8b885b4cb286ddd95f57b2ad4b0d41638c4142640e7bb08482739d4852f8d00885e3b0b5b5bfce10aae1ea4deea25d626df82c8165f5deb3429dd484217ab8e453eaf13056c307b6fc4d11ac4d316b2c5d6b0b5c8b812ffd00712c0a3929f3a0a45db5f97710cbe403dfe16a5c9235b68bfd336791c50110fb3b42f7fdf98b3d8e58f7cb11dbb78456fd7e3e581b27cc140cacfe6a14edc03363a6470ce89e3b464e0b438bd98c92a52a15c54237ec4d457bce3a931b16f51356f14e9cc8bcc7aef7fc477a1cb68b8afa260378194773867dffa719a685085b839bccdfeef89962ca4a95868424a8a014b0582837491b93180c39886cca990992a6a4c0703c5a6577bc3f2a4951a73a93c8a5f18948b30243fa94fa4b5721e9192307ea7232f07e27024abe363a7ec8bad0993e80158d5c1a04ca15481122482534ca7937e3a964a5520984b3492c9dd946d9d2b1df096c05160721394da1528c8960f8e1b43d6857da62dc88fa8566dab87847d19526595725f3b2e0809a75e099a624338d5656b43e4dbb21767b9d1402367c060de9c882824fab390cb1e7abc118485f20406edf04080e48655234e61b2b5b98d5153b175cb63ae781b0c7f8c1c1aeb2c95c8181d8df860d5c5f78a58974423d6a904354e6f8fc82d28c061c17ac6083ba1385cd0384e14c6a8969ccbf1552ab3856b253e4c00f017610c554c03c104b6c9d3534eca49a0724a6035af34448dfac8721913e3018cd2d3b5630541c898773229884de3a89428327d50b73a54b81d49f084a0a4b0f26b71832d4a7874feef0a48b3572f93412674732101dada9c07550a87b9886b1b8adf2dbae83603408d99c7cd841d74122fc5e0ac84195dbe60b101a6449fd05881ba2d7adfc9dc7f9160c38c3029e8d69dc46a59312d0b91dd119093e80bf259b286ea442804f758791036e126172d03eb2f027c1b85ba419c0d3c82e5953832d870e6f1be630893108a82dba19227429a7d91581369ad699f227b9c6b18645821edd9799d7b5c1bd05ca15cf22b77962316d2e8afe4c00bad0f2c0e9734fe3f93baf4b074363ea37e81d6221912a81ca0c13d299610cfaa1af5bb6ba2e06314991bfb55798a50c4759a2b7f5956f75962dcf2fe6e854eb2b1a66f465fc5a03c374cf48b2514fa195c8ed37168b51d8b4a15616d6854c5c4cc70633955a1c21f6a665e42a26015cd5a12cae32241a84fb3ce4f6c9ba99446f90847fe213148b605dab1787175ef81d645f872e6523272a4a1a3fbfdc543b847f2788b5f5a734f2883a0d3dccb385040d3a0e8f69b43c48fc9d82d22bbb07c516310cc5332cf614f0439a4c48311866a37df6c565da45cf53e49a11ca1ca2990e5b34317988949ffe74fc6be1a2f14b1095071bafd37fbbbed6a2576a70015944bb314934a66745c4b3342d7af552dfd2223b056110225a00eb2e6d0e2dee84677748df189263ee71cef0cc67f05b1698104f9e79c03d92e92490725d04f38cc535195e9ce6eab8c72e2142f191f5a320c62fc9e8b8ff78e13aa463c4fe8f75a37aa01baa3dcb22b177cfce03c4e74990e01b544198f44974c4d6c4e149bd50b370520dc7a04d45f004d1343c7ca6ded5bfd2daf41ed62483ad23b18d385e630460b1de898c2ed7b18e3f90e8449296152b6298e706a8088752e5ad1d980ad326e6be2cdbad110505589c49d5d4451a9f4b76873bfb153c3044fbf2d5b21d11676ec1b57e7ed2d604cd98fe4f550fcc13369e13600074613f06f7fc33869f54bd2558162c151b1413dee90153a1400edf283fdfdb29503270f870a78ab6fdea4a5b68cb72a23828734c169f5a7f5d10dbe42ce246291125bf5b28b2ac51d6fbd2facab446e9ea542a81add497958790b044efc71838d24a207e202ef09a877432bb8eac20945fa325105be1ae97b637ed9dae97f436655a0c1f37113be9b0eed2854a0b437b6143cdeb4ef225861d015288d7edf685c89bd39b1c2fe3365d3e31e7b8c6ee0a425d3536127c09832d9e1f591ac9cc2e710c24519a0b3748948eb007d3a2766bb08281aedb60481bd5d68e1ad2bcaa68f06db274b638c988635d94e46ddf5f60e4f161826ee422adced021b1ea7495d978349ced9fa4f01ee3d040b06746c135e015c7b7828b9c711c32f642273b9e4b9ebd4ca3071d4f40d142ff925035794d6d29392299848770b58a71baf0048319c55bb8ca6eb03effd3c2569423322eb03fa68747c6d7b0ea3828b3d93869987158865ac9a220fb9ab7ed0f30583b654c5e505e8d3932e7c617004001bfe4cd3eaa4cb47eee0fed0a520a04eeb9193e8a6277212b68ed541b707682469b2cd5ed95afd7307ef165631b2efcf5c74a28122021b79b000e799736c0e58e68516d22aa9ca980f92e788efd822f2342410f163f4016a2453820df3737a6fbdbcc59b12e1199b1aa8ee0affe1365670b518c3b99972bcf63b4c810c0653fc02a39fde8182d7219cb323a14428afb22d88a35f6edfd879e6b0be47cb57f11f683a3be987cd86cc633ebca576e047e4c85127ff4c209521cf14c7ff9526bd4cf3532d440f657b58b1a3a2a23f0326724e7936f2d30eb2da1684b1a26f479e8081a75ed35eb1a3273364d31d20fe70ef6a627a9669891d3deafa9201610921eea3bc853a64064054fc969d6f6038c54a760f4d6b94932791f4eaa136ce3716f64de56d62242ae1a19238a6ade88bded3da87c68edb04bcc69d8ab20cb6fa85d1da95707f6f3ba7df8c3724bb6b85c90243df8080bb65a583e20026ca70d2801f2d3baf07073d78265f5f9fb9dd8bdd0adacc337d00274a26a13a2ef2145d9f1a80f4b6f40adcb55d422fb0d2faf001bea550c4901a482516700c7f58e11be55fe14d0b739c2d6cc6cee2bed74a0ab59bf05b61d0ae6bd835e8728db26cb0ff3734f37adccd8e4308816a61c28f3f9a298c8c7b3b9447aca707b280527b9bb58f7c220bf8cd30429767bff57c1698b10051549576909ffedc719f2ed4473d241c1900b0abca7652783a14d5521c602ab5b8f7d64ca2a279e62017a54d45c10845d9b2c40641d606b6f512e7a9bd2dc73cf948cd911564c5b1f404b81f779869f655af84a5935e3e221bb3a88c2ec3c8c5c3c460e6d2ca66d5df081641946e700fb66684a61475554b21db9895667465eaefbe315174d8a5ac3f8f54f0731d7e10ea433bdd0735a75f6723ca8259228c6d75dc637a181db9e4789b768c67f3e5309fcc9f9023188f97602d88a4874a2d09a4b2b894e7e42c7c52cc5f11fd22a14c04662eb6ed34bcf30a456ce82694fa62fdd45d108d509ef2c9fdce020c4d2d0bb1f56b71da11d867a0f43743d0002364726ebef05fcbb689f3d20a1eddc05653d017946fbccdf7f8c93d5929100a6d9fad6a8ed4414f826a3e3822092da74e6c1f8c5e0feeead6d626cc9b840d38fc6a7500b59f871a67d3460f9aace0c8df595d644159d91c7b4a03eaac5066f46e3bfacfcff0c44a196dfad3c70df2784e4f04eae3b8e151b1d98d3f28a9c01ac7d73dc355e4e41648bb032468699dff73296609c2604ff1e1159768dfabcf8e2c6395711340ad4a205dfd20a7e93de7fbc95542dff58b00b1b0e8079b83ba32843c69a266deba3600393fbf908c16c93fb5c56d3fb93d944b0629e8401074130be0549141d508403cf1580c4ac0295ab642c4405a0c871ecd2c8c3415cf2a3931dfe42e68db793187b05e7c5a23d045d9259cbc4684da1516c7c782725b6e4f9819022a1ea664a7af0e8ec56b5db3698cf03bd8c27af509a9fc63c591c33f7c848da54f5a1f0304001739c1756e5d62457a611e0e8350092b002ee7d940e665d905b5e12bee09bd8892fbad8c90c6bc1df9ae58887b9da4367f363af8a0ce588077184a7d9b6e41f8eff9ab4c9085451986aeb208ee607c778391c26d07768f92ea6b47d3e0b67b3665a0b54b0c1548dcf72cdc930cb44e5519bfbe217e8d360b0a68ce38b6c0f1819036d6ce664ce4b8468db54e6969033574496d8923a5e8b58c4efc44fb17e768e0e800a7432a16289e7826481f07e58fb59ceb75fc13c8285d331a90440b6fc7e362400226cec93b0a413a4350a85cc5509e9b5d009593aca6ecba5a1565a7b9f7c2c1e49c112e43cd73d20dc29c0795b0dadd3946bd61f64eb615a0b18dd1b1b297b73c3e485cb6fa2f62c3b6c3028b3f62a387e1b4e6304e678aac2d696e5a956b72d4199836cd0ae72030ea55016d4b884ee0ec1575ac349b409ec8718e5a98a02f3715f9f9f35b296e3c392f310f99823aa162200e331b7a4790e8d3fbc0c06a7692f9492919c037452f9ba98466e657c7baec16a474539d2a142f65f01cdab84691590420c1f4c2131702a35a660de8d6682899f9dc43868747041386b5c8c94674a964b77a0180c73fa68bdaa0092f316f1ad5c8587f80f56e4c70042453b0a1dc86f84459c9a78b30f588a8aacbbd42b1ae2174490d17d16138ed8348708bdaab59c82407a07b8624943279d95fe56529478eb58831863d52ae4be8b912a6b6e88da10fbe20ccb270fc7f5a4ebc5bb0692289d5af9c1528a533d1d940c6f148332152880eea6a038770af014272438ae9dc67bbb0ef289f2fb428aeafb45560d2c589f2d6a8428ca679fb42c735f739f786a048704e55b28e875db37c8b7295c4b033e5c105013230b5e85cea8e4998858e910a5263c6684e01ea0409159de118a2547eee4497e72461524fea81f6c966ef79983944d56f24e612884c646922ccc80c6a5e0df96e4b5b89f9e2e52657e2dc6a8e20683623875452177374b776f444c69a2acc5e4d30e371b99d621ae0c391044b260c9ccc500fbb25961999b83e66c0a3b9b389a1b117a33a1f550a4c5dbedd81f1df607b4d37e19dbcc40328a004df00164e436a8414bf15d1b6b55ab0a65a8461984ab553442a7cf1ca383699b07bb8463ad55d55b1f015a3bc5486be8d69278b243f4d04c80c0886d24841a4adf0ed670ae56f9ec22b0fce7935c5c5d8754dbd764ad12c08815569406f055d35fdefa33d2efdfc7b726c9af0192eb51ece1f6875282f436ed546cfa1b721f4e801c83b474ed7da24e260abfe1910e9df79fb67503f3ede6a404fa946ab5b1449ce5fab81d9c554ae85eeb7c4d1983c365822b79ab41bac6630b005053773801362cc7a8d64fe8e6a77dc1ebc1fcc70bf7878ea2974d84bd2a2fc07f855230b8f026a6726269b45f0475d3b21d0b2774dd4214b611d81ab08f0d88cb80bb68e99cae2cdc4e0d4e803810ca9d4b7826261c56497821d2566f8aca3f45885c7584c7d1d2a0854ca59994332cda981854cbfef4e8b316c506ef70e59aa591418f0b7cca38bd5e083746271f242dd8bec361bb898886582b19b21150fb22dd176cb1385184a5f01c3bdc291caca8814074e201b29b81335b57c4ea9d4bf06ab9001a71967d549cd03018627daab51f4cf776ef496c2f26732dcad6636f61eac10b37474521cb76fe1e8fc9d2f08577620df9570e3755907206f9476c7bf503a4c1898ffb2865e9d400375b108ee297fa6e47ac7205a27cf379dc002c20a1f6ba6a6374cedcf0825ae6fc3a3b369a1ca5b79e35a67a2e628a44fe00978b80280c44f813237851ead1dad0c064f21fa415437475fb84a27f6ea2d67dc4a1f635f3938a6561916c3148da8ecea4db9d4a4c86168f065f35ac9eb9666850059b316849440314a5f64b8eb80cf3b03f7b700a446e61d831964da97ccf90934e4bb268280070ddd708e9164f336cacd291a5ccd8b313984516a062ea0fd7533b63fbcc4539fe2b00670c159703e0b6b49e6d636bc3c2232046249359c158e934fdf9e3212a8ecd153cc991d98392dda2be7a5ef6803618a5c3409bf49de7eb1e3681c5fa31af3e24f90702ee330c8b01b2d7596df8f6d51c325c8e0851a24795b0af5feb5eee7b5d6ce4a32256bc79b04b597b9a23d5ea75953d29c20baf956ada9bccc3ff12f4d0f3de0f35a13f8e4817dda1dbd1077eb5ba4721148d4caa915f4fa1d6625f4f03d6b79638b59d6c66701de5b830210536590ebd5b586d1232e230dc12d458a4dcb690770e20c38506c2e2bc59ab2fb47446b8cc270466da69fd841b6029fa3866f0a99c4bbc20fd7c2a2c4504da5e23aeb0b63db5689593396da905736732204e6ef0bee161a3a4193302b3b43e2bb6f8ee43af0100051db7737092dbec401652a074da90c3297e6d29f26ed26312203bbeb1489ce99eab575fffc6aa45fe99d3cd23d7a6f3549ac17c7be5d914f091aca4447f5d0f144d74991d922e20c2be1b62f20437eae0867bce25897c38e1a785c66a21ebd62fc1c852bf5d3d8718f45e721db50b6dfe96838720e8bf0b168a9057dea970b858ff54e0b06dbdcdcb810bd08d4bee46594dbcfc2fc0da9dfacf0cdb51bf9b9e85d3b59c3eadb9689ed89811b295a79f3bca10192c7c78fa4cd06f536a41a059bc300bac32e7d38cce47f57a20b719cb3620f768b49138b8c39e52b14864aff7800235e010d411acf5838745e4bfc14051a3b62da5676f4baf24dc8967051e35963aa1a201a8e7d0a2d518cee27f918089aaa7c6a070185167a6b64348952cf8e581b444df81ccb5ec1c67f82ecd1429955b918bc2991d381e007f35188aefc306aacb2bc186a75e7385eef542ce8238ccf80604384634ab267a526a3ec892ba3c08da3819228909d45b21afd218f98ad369085d4c64e3de7d0e2e32a053aa2f94d847ad65aa51058ec3bceaa23b75b8717363f9609071e7acf45c48e93cba727bfe1fd2f76297c402fd094e7efd06f7c4e2b1432dda5b44ff93f7f84a28afcbcb6e08849348515064507317aa17bc95bf8cf452e13264e792e652aff02df3b593e0ee90113d8ade15e5fd383fa212cf3420ac15827d4a974c2f215ed38b83610c957b8ac24abffa47b0832e0f0d73dbf5ce5b919a7ea3068c54f88847a238455dc0bb3fe4cd312a4eb71951c03274e269263c7bfbd9ae346a555524a4dc60d52aff7f6dad4f452614c6eab787f25adb4f7ea2060404021dc21d4f73f1c653372d0f2a0288b396f9a5d679a13852c49ee9047ac70c8e36c751321d8984291293b684501eb06f2b8afac4ebb6c96158bad625efa71beb772606d25cbba0f26e7e89b25c1e89b7ef4487c7af9ae8a25c7cc78fce350735d9200b154d4c1be93dbd3e364ed8fa3cb07b41197543f346ec925a2e493b222da7eebf9ed786acc1a8ae4356d09fa6bcc0b24d258b6520881a2112b92bc150ea0cb777238b68d2b662b9946a69b4a4978d28cb892305e4aad590112572225d68e6bad87dca0ae91e3f53978fc62d9fb773549dcd808352930509aea00db9afbbf84c86972588ae2214481435152443e5ca24e73e9b4a1d5e3bd82b94d05d6ffaa64585517bfb257c6a915d8d5225496e561f74edd69d6cf0b006d74c21dc4953e34ead6eaa6f29050ef26884a58541b2e751929eae219cc43658e6cb36403267104b4a8179f5f2b889830b71891b213cf4ba957e8c80020c03e7094e15e31297b0f83eb3f77980c2b4803141f16929ffc0f22dcf63202189ff3cc94262c6466be6ad7a190f7fd646ecd51745d9ba33f44ececde0910b9bde7f1eb1dda25050ec64cd0befa6ffd71f4cfc06d4865c15015f693c2c52148b89d99c281632d91935727bc35aa94d05c08b645bc07f0e6a1179b050249212acc15ddd01b1417cfc45a9583f7a948ee6e08a8ab31ef7eddf72d9ec6567da69315f7922eeba98807c01b7a3f69dd2610cce35f2470894031ec2b5ae9c53aec2e4e9ec1217ed5c4e125f615c2e466c31fb4044f120c8f215d519924e6070abf6b88ece52fd93dbe33a148acbdbaf459860942c0a51047530c2aced2f492ae83ff38bfb49fc6512e292527d18dec7ea382baa3774a43a09c1fe0dc702db66c1b87254350049d6340533187958a42cda72366636329411a0747e29936ef2c93fe60b6bf81095872c0d8e1d277cd1949a45e58f95e6c72e58ad5fe9cecd87d0aacce0dda99a075629a808d63a5e252ee12e385d06b1ada0ac4b9115410e5e9ad1774f252502f7da091ee5e12b94903d9a9c7c2bb22fb31af832056bbd4e91525e1d607de21551515e254b01f11b5415b911092b52de0c3bc11f6cf72726de85d3708f81e24f332c3dd65646cf97a5571b1d5ef7814aa3c3588c924054f80331e3027095a19007c68e0b11a8e87b363a05ce5a8d7169b5f62e749fda115662bbfcd3b2d579309ad984ba0026630458e5685e9f523e30d3ce4b12f015293d08ee4ae6e49ea0854ffa80a8ba632520920336a09c6eed6e9691267e81b270f74112353e441f34b229e457486ddbd2907666c8c966880414f3a3a4adda0f0686d6a0143e16fd1a343d2f81270a381bf700893835838715c83dc97f116c68448086c3efa8aee42c2d6376aa43571b0417863140ae12d09ea3147a3476b79bcfd5e785cc87181adf00425a83a92bb2abe5fd087043c7f3452f72798e06118044dfbb8636e61c42564a3cfd1ad860ff00a0dabc24d24b5f1aa4c52579aa9d43fc83c5a0bbf1e53c346dadf2727b821774609f939315b0d4f55c9f44f10b20d50470fa6a73f8d55f3fe60425eb12d2ad34480296554ff78284b01850a3ef4a404993874e98792cc1cc1b361b5052b5ffd69c255805259be4e4ce3f620d0c69e10d76b310fb8e626b854afa8d90477c500bc5456c34da7e1b182a5edecd892bc1a8b9bb972687f450d459e3b234b9ec12c636bc4dae4d1eea6b88bcf2b72751ddd79c4c0993bfde2c7363421b477673e0d44008e6091bd311784a94c0df7397b9416de42e9057544f788b3d4df875b233c97c009c26cd5bbf482f519f00a4245fcb06dda9624eb2387ad06cb9b1bdcf944a457bd78c0c662e1115e1af68df9dcffd0e55a65ff68ba1bdc5dd3b4b9f960078162027a351034fdb23d103fa8cfa5278af4132a26d7419c4f13e2761590792ea1c2b15c4dd1efc2861af06846f46f80e0a2ac58b7236eb5117baedb8a1a1ed6de97e99c2a4674911e01fbb1629f0000b4c7cddb2c127880f9b6b6116e31a901b9bf676b36387e4eeab3be72c338455113327b255b744ecd2524273b02a3108dc62131fcb0917b3a2e0558ff1a91f502e8ebd630a19a14690e64639285d9873c0a2105208b65ad312bb4fa8ed8075d0aa91b6a6af9cef8a62026950ecc8173e1f49f7338ad52d6156672a83efe6bb74f13f6c34763668af4998b60278bd958f973832401005f364183948922185a954959088bdfa2b3ba250e1c3acc1b4024208baecb3c45147205370620daa5ba562ba24334a522920e7f929e54c02ea9ff4268bc8ed355f306cf45f223b0ddd30031fd9ee6b5be1c89952ecb0956380167c001f95ad5ce9373c00a4d8c315639515f329ae8382456a448c7f43bc095a8a87b34f628e9f2fd56af823b8df01d6f01ef64843121fd090b11057d76ab194d90e82bdeea95c2f60d292e4a208724332052c69edee0a2d20214317b06b35e930c97df8898b395f6b0785227a01b7b68043e417805abe12c11ede8ea688703a3b9882da994ca942f357768ce878cea2d103210ea2c8b128911432f971ad08db67991e403cbdb29098f0a3b62f92154882fcc3bf8f3e461d7e99e94073508cc4891c097b5a9455fb2082ed105483f54e122fd5234b420917c7e17c1d71a8b8bfc0aca7e1bee7168bac38e060ab14a4278c986316993c8cd2f7fec82135c028bb95d8abb6dbe6b607a4bca18a1d0fb733198944d4943443fa9cd83364aaf752c8331b7924dd3194d14f73872193e334b6c3f000c498e9b34f10f2d46270192191b5220a42ba68ff18027716ad64be27d808879decfca0794f66aae7689b5b4afa7d1249ee0affd6afb05cce505ff80081dc4357ac80ac1290b5fb784d74da73fc6e23a8916475a67e723a6c479b93cc04d669723dd4d28c2257b59c9a5a650101c985a033ef7b701741b61628b266438a173fa079041a203618e85520a8bb9d68b708bcc57f7027d54f47162dc28f7f676e095180a8efc2fab2ae7b26d1ef24a4bfdd561f2e3d0c28f1098ddb36dc613c1b3f8812d2043fe8e2f0498c8efd42d56699e485f132609a11c3b85fcabfbfc097a44835f173d6ff4b0eefe9eed3034f47a21722c87f267bff8531498de390145539e11711386bd81557e4acd9c3fada595c1420d14e9062c541239822bc05d22d6baa6fe5c03418a62dcc354ca992fb53ac3327e3487049953cfe5590075c319ebb0030ed1eaf7c6a70055b0d00425b8ddae47fe9f3a005ae30d32c8ca003a22d86690d2f401eda42668edb66c6f0e5455cd445c8400989a0fffa73993d4b546a480ab056bfd18599f1075b1f45e2d076dd44c1c3b8b9dc5ab285d69d1f3413961961f8d3f42d667b9177f30978faee6adaf53fcbea3d56568afdd97c4774cb3c4c1d5fbaa03afa84e4240b201ed527aa44cfc2b5aa57957ed404010410823915d05f739171a6c8be15659463918e2a840b5e2727c323d828185c4cd99e6600f4d435c274baf1d9c283fa4057cfdc849f0602189d07124868d816f11530b5f20f50bf08bc8ddccba14316876d1ae88f07e9dea45a8adad5e3b274d6ee0fdccb19af46ac882e621f14953e6f4e49161bf929128cf47964a157c4b1e50d676a908405856c2e78089beee565e42ff186220361c16f7533344e10886a514728b6baa1aaca50331a13229fbde87e5cbdb1098bd40ee1cf665919ac35ddb53d892b62ebed7e45b008c7332ab40ec37eec0998c1d078d344f84f5afcf1db5b7c3b0c8566c7e9a06c02f3fcc4ec018c849943bd4f6976bf463014f4b0a1101e5d9cd3f112158ca3315f1d115df69c97cd4588a06848538588c770a57be6eac7a79804dd2b415e8838b46be8aa42ec487a07161b0da100ca43122c6f6f06cc6e8c4c3714e98937ab90d43d0e2f402011d8948a067bc3b6030fc106481fe43857695e994b170e9e0c603d26b84afd81a71659cd279eb5bdacae0a506a426b31725f874398086867008bec47dba3cae298528248665869d6bd2e7fd6cde3596b9df4166f6f211e097f5b7c335c65cc53c58540b39488bf8b699d4f4d0815f40d70a0c9494f053c3d7f4165fd79901be0b090ee3c177a3fc355a900d837fda6a4e70702f10085bec0f53b4037811166c4831b90af93a1f9c256f04062fc78a06c80f7217300f6467df19c3ea9ee99852958e05180414a5f7b7478d017cc1374878ca1981ac8f0faeb19f5e75780d4303f2e93a32858c5385a23d577639ce39c42ccfe2a846ec048cea73252a12a2f80156b58d2f7e3af6131af816fe68d348ba680133df2983829006a313bc6307201d06819f77700e9de18a00b21082a751267f9a19bbfd67eecbdd31c6c926fabd1871b0eae7f684cb0b137dee6086c7a0d1399ed94f6c7084f5a1468057f9f82da858ec042bc3ff1a8c8efeb028bff81673cc1196c17158cadd03061c2b6992d48618c29fb9bffc318f83795e10664e5ebd96ab7cd0851840780b016648b59a09302ed8be1915f64d19370f002d1c8edb3792c7a4e0a52c857806073ed4a812762bb86a6c8982f4dd21a873d0abfb5f024d0bc53162f8fd779c40584e9c0291be95b50493b82751cb7c087f4811ffdc69415c8c7a91a6b4bef9413280a56f55660c142d89c9b3f118d46ff6a711754927c2aaaf059122e3c2a622998d825d66d24d64de0d634c1edec6db7e49a56b505eab9155a45ba18a6ea1d33f28c8340514d1138e2c40fe87f063716559b4ac0604acb3665b9a88ec3f52407a26a3d917fe507951d098df843496005aa0f43c1604098db357868cc190398d41b413c1fcdf27fff1895f4f7f32004c0b2b1ece9f6802d73a0c02fee2227f8b6476282419e59cb7d74611b95761ed76ab9e286b7abd2b8f794558a7c49acb9b014640cd7d3ecf7ccc8d580f37659b18d2c978a86f468c6aec042be808f1a749d2ade374e373d05c27b3ddbd332f6216e7c40e72f327147e4a48d4605ca40e987bf26486946cb87ff25266cff9547b8b2bbd4774431a0aa1f24725cb5baf1e62ee03879bd60370dbc9d8b6da8e1055b7c462dc62e06eb03bd74ed76fdd18a8daf085bb4d50cc2b0b0a0a52fe069f7720a86552a426778cfe750256fcdf016a329bd314a6d19451c5f1e320ac19e2feb8c89b09ed988edfa9808cb7e497cbf7d81c2101d387691a705e374ee8bfdaa03076072b07f1759d46038c1d9469bae46d51cd0510517dd0a977267f0c2ca162a899b0bcee1c229043906fd91de1de815ad1fa893c49295c4d2f4c27b581353d1920bebb4c673b1c752822071353d121e59e52ca65521cbd1b7daff218a8b39171b62baf930be198c27942449a25061be331f664610a4526d7baede5edd22d71c029b64379971e910af8305c20018df70cfa52a8250d605c1a87a728ecb5ac9e55642a90a63558024e4c9b9ea673fa3e3a046885a1fcd57950d72774a83a969b41c88d5d7b72b1d8558f2fafa3df90e414689a1cb4270e695d5fd30ebb049aa9061804010dc350863cab0f5240c0d351bdfd366299f4137ca44ea34b3ca6e012c4d424fe878db42da11e5ab507124a691f2624139668ae6602ee1d638a6b464a0a30d6023695e5ba5c203b6cbb98007229fb81bc8ea2d25563fc1e5f642d03bf4590d7bc099a1789ecc35851f308f933805d953c230b8dcd397a60950c27ebc319a7c56456580e51094ba12b1b08bdb708aed04b76e88b4b938e4b9a306b75d054a038d210754fe68c9a57679d2d33cdc62476fb654b067f71539d21406014cc69b799a2f97fa7c9bf9d58261286b356ea18e89a53b591a69b1ce27816f9108978ccc8901f5a23409580216f053a360492dfd4cc4567f7002f9ea26c72b6a33710232bf47c26314ccfea09f8ab1943ac0df70e1ca2202d9e854fc08bf0a993c38006f662a75a27f77248b6f70fd85ba4a2104ae0208b10542a94a586006ea86a154a0a141a315bf97fddb0223c2b5b507ba6f24d25ca2e8bdf824ea4d0f0f6ae51285b56a5731f11011539a824dcc24105f5c162744b5dbb6e5431f95aaf08174f9d02b1e9eefd513051f327d332821917324ceeddfd88a8e30b9cbd199a3a6d6619652d924b7c363c9dce01544452c85e2b1a137d0b802ce6c24d951c8808c892f04f26578d1cb182b741da8158270c803c44a5ee6995282813074e331c73dc7f59e118f55488cff258ed32e57eae0ed8cc82b0b8d8e6fa3a9bdba8669c0386cbdf4d51d3d9b6b6ee85b4d526e2cd8fa2acacdea13e1ffad1f5095e087af9a4f7c98a4e6d5d8efe4d15bb03023c3bdfa654ae25a7706dd8c554d1ebd85a5999a6745e766853886b239ba044895d0fbba9dad3a02524d5622d107599ec912abc3bef9ac278297b995a86216fa409d52eef9c9a2d8c9e9f91166f0091c00ecdfc53aa88264a0bdbea56bf5bdde72d4ea60384227a0d0f05e09a3807bb1d83d30e14c960effcd8e0ecd9722bed40c9976ddb7bf78cfc6f0c7cd32d503c2760b735e7178d3d5db8ad4eded23ebc892d9f9c95252bd809f9ad4fcb14e2b41d627270b69362fe8d4ac4e9add5c72210e25b6a03302b1490ad1b40cb4786acbde23ce079973f142dd1043adcceb18d84b5d290d1fb2caa8ac02ecce824a6e9b0b94c6ec950cdc68aae56b712131585e41f3bdb27b5136984c1c32aa2a3bb3a75012d2cf6dcde95e636fabc6423875349eae95b43a2090e31cd0f9f2e9cf7e700901e4597cc2336758fc0fbe2f4aef7e3ad0e790dccb8a94174f1391945603068a16a2558bb76e42e06b6f9104e06a3256ce6c13b44a2c34471f0cbe9e2ffb85a15d672864aff6ed8e6710391a8134369993281b9b7cdeeac43f23a54efb71a4449403716b2f26e69a9b4810173248071250b5131b56ce47cd41caaa3d50096fc5046d0785275906172b546b05747d0efabbcaa85c3db784c9908ea9215fc39f98b0ccd6e4c389436b70259f35ba155567457cef71478d65dc05db08485253967d62cc1f10e0c5aaf6d0982421fe6925d73a07dd474b476609d9fb63b9f6871ce092c7b04f0f6c013acd9e891874e5425b08e78beb0f12726c25217f6de1e0515c1874b1ba636b61b737f62fdc50a782470b0249147ffbf3a732291798c614cd3e47812c60501d6c8fbab24c07153d8c4ed5aef3e9f2a4f7379d2ff03b69fd1672f99a74ce00ca196b066113d07002ac43fc38c715080f8ff8b0c850a0ad5817be4c42c3d0e69668889bc5c1bf8ae2d1c377db27bf92f85e522ea64b1c26c3029de5bd1b063b7de6ed4a49035daeb1e2af8577eca4132658cc979d1a037e3cdbaae8596d417743d1ee1aa5f9569f01a460b55e895e2377a082be5eb89a14f4f96e70ee5e85f34643cafd7b42a683ec97e4c4254d59f0af8b52583a87866fc946559c4957eba08ee7ebe2ec51a560162c43d76ed2ece053d59246762e0041dfde9ce67a87fabae2cd95c4d414f4c91717bab4830c99c212c76ae2b9a801904b858b89657b086f5bce94d19d6dc673924fc1fa694cc4df2cd34e6b1fcd718d3c12a067b90f7f8181b6b3bc7a80821d7d7431f34d65d36a372ae3760c66401ef32a98a6803baa31195f72fe508d0426655c051784d3b456d2bfaa441352236436381b9d030b44a7e32b162174e93c743199e461e306af6610d9c7e4367b4f375281d14586df7c38f650fe8de4ea46b1048c99932075bca4e326b8c49645213582e732d01cfa4cbbaf571c32b1bf87a01419aa76053d5bf4502fd3994301beb2aef693459e55c8320a903276917818261a7ce47cdb9f6289e227c63d765b653f6c0487f42078c8bd800d065d8fa18e45dda633621019446ffe2763361f21df7f32ac205f9217066e8b5d60ace189c856787255fb064fe4c970ca03bd25be57053623c70a318ec92659f2fd29a0a0b43d3d4e591a4ea0578a2f5b95d2b9b962714240efdf0160fb97126a275dd020a4b804be0603551edcee12e8d110d013d3918e9530c58032b418ee513c11eff44bf93a883771ed4471825e9b43b34964d6cd25a5a196cb26fbbcd278b0758e573a4f96ea4480eeba59f9196e0a1ba3623fd5e4d745ad921ce291610572851a4495774e3c47923f9c06ebcb6d30046688260178540c75d5d3c884f5c753762fbfeab89d0ac1a5f1515344f23b347dfe65f969d46525b4a0fdaebdd9a0a22bc6e3a944155344f44eec16153e9a68ddcc312152a79a593aec6cdcfa42bc47ec93b05666f6a6a1be4c305cac67d0348caeb39c4ceefc01f5d08407c3c590724afa34418c6e97350e4ccd9ddb43ab41462ad8f59de0a671385b74590b816cdb27123142108f5f78ee98e3134b24118906f6b6e9837bae4a475f9f371463891c04d9837e4ff3ac8def19d6df74c00f2cb355a40df3b4da5348bea0edd68778e3c22c88757b416666f46647cdbfe7d4921ce356921aa1b19800259f3ec9f98c9830deaf665b317786eaddbcf12789e1e8768142013ef96b9cf590fc741700df791b97b5bf4462135e357a16d3992dd178bf8e1bb355961abbab0016062f78f489768559c234b2bcc563e8243b8d3d1ad4bf6e38b72ad23aefac0e49d4a6f38f8c45a2ecb0ad41c02beb385c27528766011f056e085ad01beeb776888ce964fd3101368a90d214be9ab65d0f9b92ec14f7998f1c9a7a945fc2c1a35ae33517be9cf11dbfd2674adba737e4b2f8eace698e26aaff596ea3899d8744b5f975982f38c4d5d0a6f352b9a19ed03a832691d006673402fb83879f707d9aec0025f304f04c90bbda1390f216db332e8fbc7db4bc24c77d73b73627f402245ca3e26536d02d4d623f815efc30965d96a8dca08eba91fcda7165e0e5d63342602293a38420dc45f8a6ef6a430adcc1ecc2ef7554c357d7038269372a44a4e97450b582c9e55dd9bb2820faee78f88db6ef92fd34b6f0110533d3708c075b1ac105c041f73c657c04c95a85809c8fa35d294ba28e656c7b30b55d60582df88bd1361cc42b93444908880a43048627d9cef367a64495693e099f0ea443608b2ededc8cbb695c3f9f23de8a5ec1d1f86281e16bc212495c72e1f0c83e17fa7f55d40f6056ef27bf95c4ec0401dfbef19264c9b686d859d0b07167735344b915e9e0da6b2e69288914007309344f173f4a0922a5478a2c505e5a65bd7cf984d9baf16f84f050be745450f509750a62ca22c683a23f7bb5cc7d2958a81c1a7a8c61aa30dbf6c8a94248c3f44230af700974191944dcd2a526c7dba97780871b5e750748eed0bd6bfd6351e21a2bb7418cc7411b0ddefb78a03c9ebed3855c447c91428974e2a103fd103597c771fa9ec39187068e9d97eab44ab98a3eee8c3c30f03ed7722b848580243643e3b063c4bf80b911c5db2722010cf8a8fb25cb575065f89d5aeaad453da78a6e4647dee83e23624cf0ee45700d016fb51a14d99305c42d3cfb92178ea53b8f2f52e1ebb0276dc0f1242a9a1a2024ddb391419777f94efa7cc75a371c241a3aea706991da73f6e9fc1ef0a872011ae12b643c49fd50f8f241cc9f37fa8a2931d10e86573a1e6d8e341fd64578b254cd1c15ecc26bb1a7df93d1b8377b1fc21a783241f5a004ff6280f93f666496a47eec1712c27747640614c8d04a8e77fae348cfa33f1153216dec503588d13f33ccb2c500dd1f8701f68099915a7f3345002f7ca53e3dd2fe01d4d1d68e24b7b2b044182242dbc51424c8a0b0acee71e1546840937e92b998324ba946caf6c1d076f16037d5835c42e7e43cd87f3deb7cab181000b3abda286899148977bd577a71e0251d27b6a905bf2e2ff6897e66b103b8af3aaa079803afa6153e61afcc61e73ae8d11f6f213db1ed2e118e49abe5868a67964e131f2fecc05c91c61261f70b0eaaebe90395953cabdb468a71652d310e68751abfcdd72c5fc4da6ffaafe5922a7f219d6f493ef251a9b09a6ee9912ac686565523853e542c48b9f833697c97497b7874f825de324f98213c1c2a0c80211d11dbdaa31cfaf4eb65ea78698103c9d99cb6df81e1892acfc44962800286f11073096108d4b46300328677ae324996464387fb270641f56f5ff91f4877276c0bc3bdd580c50a05985821f50d1d2d94df76d5598770ca269817088fcc4b5540538e0bcae23e26ed8e109ef6f529561b98de7503ba01daaf4dea755bcc46a6e1d71a78ec757955bf7fd3c2f108a5bfa486624d4811375be59977c2170d93c1f712fd1211ae6a7804d9a8a1a0108662060bb104cb6480e161518ef10fdcbf7a58dc1265a5c32f242587314145c5fdbf02d9d00d3126b8646f671d055d051f486757071a7cf0d7aa6c6e4e870b2778f97437215f97c182067bbe96646e2488da641e8150d896cc339cc4fa09dae5f113207969dded914689de0bcf9ab796e4a00befc21390d328888bf7b5116cac6fd08faa171126870d1964ebf2e9d2acd04d3cee8a070fe0581952b23e98d491ea7d7a48df8700d6aa5936a06f87f4c448281884b40b0b434dadce673cc8814a82657053b510972489b66cc9b65cae5c939e1271a5cd2c5529a090260e3e31b59106c406d541d347c36583d570d6dd449ede9fecf5c29bc579a6a8c047b92a216302047672484167522987d0032582060e0da1069a868bfecfda1023aabdbe91ad72132f29122a9a890124d9f3899c9cebca95755857e9764448e979f43de555952bd1712cc04108bc59356af1d43a731912045ed63cd355ba8e5917c78d3055de7f766181f08c6973d440288176e87b5257b0c560ac25962bdd40248863d6558e0d98cd624988aff9123148586dcc9a25e63fe3a05ea750177720afda58e0a7144bf4dc401fe6796cf268e95f070db5d48e6463d2f3d310e4ef8317949112768c65a43ee85684349f4284023fd2e31176afd9369c647676a78392cc3e32121188700450693f024f2c8f74d1ab23ec5bbe1c34fb1652c7a465d2420c8cb9fe838f2bfc4279082c411970854ee0e5ccfd6e78863f3e47ebeeb0bb12e9f4a00881a28fd33533d1d958c279ba339d227adaa40d798577526b92445b368bd5471745b14e13cbeed7e7642486c145ae0942e193905d63bf94141480c843588bc5e633c6b6841fc1354375395e1d6839d11c4e7a4823184a2bc3fb82fcdbc9516ae9c282f3e8473755151a475dc92cd3312f204947cd2eb8cde95c466e5856848934709ba9e30871fce6d782857e0a216a4eaf4b37719700222aea041e7aec4addfc99df3205aa9198832715fae4f84844df42c094820cb756d59afef235b95e641a22235b7c6cab7ce6171a6d5117a9ac308166eed3fd62722d54d96c34a62cececbf5abfcd2ec15e6d8a348b441f304b1c7ebb772fb794bc5b0820d32255349b33ce158734e02556aa3679b433c70411393a7e913346a50296f6832c74eb657c0521b860f89906114c5f36d5983ef70f900d9802d41a3a08c1df354f79636bff8c737eb5f0cbf3435a18e4405a54b30f6a4d604f9f5cb02dc31813dbd6e61e9374b4b8d1f5e2713563db4e83f166907d4745bcfaad845df906daf491b8695903f669a35e14b4c04acf36ea9ebbb7dad0ebc96d97f6a9e6d7aa68a8837c6f8365a42f25ad8d9b804266e342a82d809ca0042aa5fbb02f579b333890b754d1c46f0f1fb2e7592516afde79ecf3c0f20ab539f5e7c702162766863890209c36bd1e57ea9b2e72face499d785189d613338f2d3067f3ac8a5126b8ec7665bb7349c31b1b6b68f9cd0787fe7d5f7e295df8c7a945ce511a52fff156696bc01244150c8c18370a123cf977c3f38b497a9559fb12fd7e662240091bea39bbf33afcf87c4db4b99d98aa487fa3ac835309ff9116a8a9dfe6f781ec80c36cc5033bf2fca1174e43383a2b15c14b4dad40cbcb3c59bd09a6c5c14f0fb83db55bc176c2c27adf5a5ee5c1472278da43f635acec0ba4771fc3d1eb2c4be97a30fba3a8f64e2d7b70306ab2a63726c4efcaaae97af574f4750ae0b4ed33238926a124c10a2a0a88d9fc2e5c5c2c4aa93c4020bf181199edd2fe823991da472f27dae2f72151cf9c7dbf43910b37230806dc841e741f407566353bf875d82b14034824e8c1c15a45403e1a9c401ffd515287e0cfe1c8728a6e9da34b18a7c6109ace3ee0e4211c93523ac121b83edfd4e5c1f0586a00fac7e7d06221787053c1ef0ba0939b4f4f4078e08a5fbd06e33431bb96b0b6c6db3fcad6a7934be97aed1202550fb6fc014c4b1c355415306256c06d9cec3c623dd6fd41d7f55e68e67456a6ef48e195736ac51bbb852b4ef47bd734735e48f00fc8e1dc334e066460256597f2dada9ddfa82580c8a643d1b31beb2d3ad8df94bf79922755d18949fa633ae36b273c4a5984974df21977823dfd4cdede96bd125551dc7ed9ef674edbb75f9367e98405b344bc55d9442d68364ca925d66881e5c7f1a350aca2a487cbf8818c4e1071a82da83f1139fd1b5c5aa66b208a51f9c672c8eab0d94399a8b0c6e98957bd3ef5003b1d11c238c0800d4ca2916806053f2be3d20c686858263c122bc22bc886374c029406888c08ea58a6355e064fce599c95d5576d854b43c521a30f17bf0e6f0f01a95daf32c4f0fbcc9d1539f52cbc4cbd03e3a0376729de415755bfe54afd7ed2fc0a8cee3062465045f88d5fcea9ab96bdbad46108f8619ee92ba58a7490624a83931df7759a529740c00481d4850098185e6dfb8aaf2cfcdf21d04d8497ca029c11cc76e5e464f7f46f2023b78467170232410569885fdcc0950cc1371aae27b5e464097ccc9d677db051ddbc829f962ff39898030169d3fdeb38120a0b6c3ab540dde04d5aaba10e147f2f6c76ba2b717251043bef2d680974e3dddb287de49356c0f46411baef662d7d98ee361ac41221a5caa7c3f0ebe787263267f38500eeeb78b7f79f2668912a501f1db8c633a6ece19b2ca35b97f39655733a988dc9c050b1487f8942374d647ee81d56618b3aa048599b17232fdaf2655a91c3c9f32bd7525aa25dbb0077ff07eb47f645905306885e0e05a91b14709ce5b2cd4a880582bcb92896df1401446662714e98c1be2871c818e1e85453c1881e003111d4fb62d66bd0bc9601cc19382a74bd568536fc4a127131740bcee58042a9603de6282d6b0cccda7f5bb9090e81dd842faf2afd6a1f16663f57d9d18f676bc43f751bf4a1985a178664f86dac90d10e2d43cffd0873481e89abbf5c8e49fdb503092c1c0f27c4cd3e08d48fa6dc91c26d3a3994315f86e9c02573fa072397daa1d77d9d6dd689fc994c0e5373da8156191f97994cb6a17e67c4fcdbcf3587b79754a0914031547ecfda050b8925532bf14e1d5ad0e954de067ce7046251246f2225be55c7335f32dd0b43441edb1ee405d615abb14690fb5a76e395b6497c09b27a2ef04d44f432fa4806fa8b2e1d36584f0b92c6047123b9b056728e5a9b4e8b6a65dc4c512c261a963c760a549c02a0b4f36b587d0501b714dea7073402343ded9db5d4f32d86c659ea781170dfadbcc1440bd4d0d6f967558485b9062e0221a9afc828c794bafc8c362d5110f299a1e2cf986634f53b91da1b3897739ca2793f8b5b1a80bc1fc171e96900b5863acb9a10eb473cd89e8c4f0b77575f5a3c77f718ef3e8d8fe18a10349a41f7532898f5409d76f113b445f0cf9ea51cb66113ec9903e6a3229cba27f31fc8708db75a81b723ba5ed6ba27e78d7614dabbc4a839e4145e3978efdc018a796039092d587b2f60d68237516a493a4b6972441d4e2bc0a607521cb1d56cf6c104807f4c0c4040e2cb4bc0fbbd57496cd798a4ec77eb83947f2ce49f573f6af2f9469f16595afc7b84f70080d12a7cfcf5ecffa7d5165c342c90057dbe75c01cb8c831590526c9145dc4769afc5fcd61193722c5dfc89761cc07642f199088201c6da7aceac1a2987eeab2e5ca9d2b0e1ff6bc10098715ca9f3d776bcf4c9b5e1345736f65da0f17bb1d9c1cdde974f38f857fecd476e3d614074ca8a44160e63a6ff24464a3e6ee854a24fb2b03a7b16ae667856b04d55179d0da9758e0c370723854d8fb1e568fa0e2ef72f4b10e2134b7988bbfcb27a55857df25e3a605461e5eb2fd4245fbc6fc422d4a63346a03777e296f4134dc6c756170fc218dec5270e31bdac6e310fa3038d40347bbce9852da406ed6d88c7d514324b0854d47272b2984086a3db454a512be7ccf87111378372c257447d8965bf1597380de5300c41b569467cc21b019ebf34f0655c2e0e67146d8d6d0318ef4b2820f1e41c6ae1e1d5c852b724882deb5bac8f1c9c0779ad78d72aeb6341dda394392b330d20871a29aafee6e7b1aa85b1b9367d23f2e9414c41b2d848865d18a2bd5101611fb55a6b834047516a16cf978055a2e62c641ef023845dfc6afeb3ed72ceda20b64d2e79388b53b0d572478b84bceb1ef21860a13c7e190a5758302faee5e50684d5085187c90518489a91fc49b273efa58954f853638a6e92dc3b7be46ef93245a07dcefb0fa78f0008748ddce928d4b3a67b22c2f50e937683b02e48e99f7e122c04f2ce36b0d4ab1f9d205ab8de9bf664c9a75ca33992b541793cabeb7f44a1a0b4966d0e6c2de08ae4deb872e2869050d26f418082daa0bbbf0428082e46e4b6a9a0fc4ae89e9d6c812fcb8401833719c3e2b54bc0f2f02422c76d5d3e3477320fdc657d61498a46516ccd28e394a946acf7961e8aafb20a3832b2cb4938010413809105b135c2d668f998f564cd5d05fb7cea89391c298a6470810b5a174dae137fe4361880b883ccb21bc56fe771e84eb9bb06c9264e31286b89457bc21e3855b76bf177ebf5e26b8f7925c14f6a801570e3bf1956afdea2da4452fd05c399888354e2885eba554dcbf484390d447d7c532d3e71c200a5e1a2a915d48b0b0dd2855049c39ca15576c3b948cf78382cb0bfb053ee08eccf4dd8d12db3edaf317ebb34d673775d7f343079374e0ff7b7b73697443f13964c6b0215cbb2eb6fb1d0beb492817e3b81558cf6e0a4a1e0e0940e69e293d6f4b586d4fde8a7ec74cbf40a9c1473da8bbb610eea6f530837d939f06c3b087bb7db3e023d97142c3c360e3e7403869f9746c26f096a48046beff5310a29dc49ffb84b128241ca4902340d6698938d6098806d745344198379ba07780e5c1ab93e3f5df5ad05603c6a24f43f160ea687f1143afd44d3dc845870f40851dc8a25f2b1f8c80947c6922010dc7f4cb5ec074c9457b0b923b83210e1d879d56b11bf234f76cab29fbc426b3e6fc30cca5c91335802ec60ba620686e1e0abe574736f097bf4ed7d24a6fba444da1a124107720e1c995298932e572dbf50167d743e30b9636835e1862c85ce675be7296e407c76216f11c0be8c2c2e05fc51ac84f2b746174fa0bc8fc569fd114436cbe968f166f19176dca8a86ec8e214d976753fbaeea39f7c0578732e89e5ede113dab4b13cae5e675e1f98d32a68e8b80ed41c14a29e19adb0f3f63ffabb1973f238bd04453aaff69577180c9fc57a4eee89de0f4c51e45d3a7b273e35700f51a9ff605c98038fd58105ddc6af511354f6aa5050c28dddf28dc375ddb86a13901b03525ae22212bec2638986db8236de27ea66a1ca3c9ffbc2945e2083e4e05db08e38c27a79fa010372caebb76441ca49bf80e6252f9e00e9f895fc2f144f019dff9fd4fa6f128556f4afb7f35c989a2d9ad48e3b12e0c6931d761e7f8a6e8c4e1683ce6d8e5712a695ee64977cf7814ade927c3671b25da2174b3f366e875632be45ec179fc10110e574732ea1144e3f65ec1ad9f76d2b0afc6489e0c00e9c635544e8dedaa019e6dd03abf2a9f51c13d506b728e1005c54e23122f54af9d8014862f5d6c84772172a2262261c381a60036f926988c9c9199322c53cd61ab950bc67dc480ba836ee5e35b06411e98240cdf64e76ad5d52d394a3f5ca8e80a5e4df017bac917a1ca774398c3fd8072296ee09b27c6fb8ea0bdbc11af36634d987550482c5c75db8ddc6733e47f05981781a14dfe092da5343f18505a5c9d1dc52f5e6fb8e849d490acf0c0f558d1f389c0373531e0862602bcf189901b0fbd442db496f5066ea8b8a953bc09cc2acb512eebeb6d12792c1f62e189156d08a433ff82f43411ea6a93338c19026396c7d0190bbe15f149449d18718f003af32f35370c6e0028b5794d9d108cd4d70ee861864b175aa905955e39638400bd66ddf442945ac0ee05321c1fe4dc4446e343f70f6e882e950b6817414caf2d5a61aabe16288dd3331b60ccf15f62a7682b6008d2777ce3f0b5113c6fd517939beb2c5f5dcfe3beb3165923618927738773e05503f263da54890f626f29c79fd8d6f69fe8b05d29162d06bca5f17b2dee6d1aa16037995e0a8387b48b1d9cbc272905c102f78db8bcd46fba6c505c1a80f7df0e65cc6147babe222bbcd9d51ee5e9760f407bfedbce9b1ed4b2fc0d5003df49da2d3883eac91f76b34c95f767017e6322f094bdd524d0c0e5789f379c7856c1c0c8c80623b91b43cddc6c2df2c0dd4a2d323a625904e8bfa5290e997f67524c9ee40e612d08ec9ed1303e9dbe612b6d46e2ee6c8fdcac3b312d0aec9db507ba73525c8990f1d7021332bd6b3934c14321bd1b72e602bcf098ebfabcb50e43a33d6cdede4ceb89116f3894ec4d4ab8de58f483a8164dfb7d9d6c5e4dd17738daa138fde5917177568f0ec532fe4ce2e44ab51609874813d88cbbec72149d2168dcc1bbc90823eb7cb4c4785a73f100592a8dd3350b20c6e5bff04c657ff982545cadad14a26316d8184fbec64dd11f798455dcb5164dbfc013334d6c0ddc107cfa068edc5f79539d88f7c196a552a550ba660788f9ec57fe14f82a5ff02a2fade5ad368cf1aa0576d2081a593cb10a80c234cbe5603859b7978ae458fdd1c255f6514bc6b2ff7c002486efe42044ece791aa1ad2bd52748b03ba86f28258305e11a903c923d591a7f1273a5afbcf371e72cffb38501d6968ec494c76dcae7484786933e02e0b38dd81b785c9a985012af52c0560b914e3eb9bb718c009f4e8093714815b04bf451061443321646fb9b794526e99a40c08081e081708283c5ff3355f5d87bd6b695a359af60182d316fae2423c0875719a0f99b449732139cc65524580edef2ec451f3d268caf15b1749a4276150860dc51a2247a3bbcf1e8bf140d31b8fe1d214e226a72e8d1fb4b3dd65be43932c0eba007ccfe717b10915da05a00b3c0fca32e06141431f3e7f01c9f2093300be279c347a72190de7ca4d5f112d4e215e69dab6af86f04d270b1f8ad0159481270dec416e1b0ee11298f4f3fd4834053e184e5bcbf61bcd617ee3b149932a97c9141b9d3912e541e4a442a23c0a97adaca8a8f8a4511af599cc079a9a3a9827ffa75e28bef7a229fff7e28a0e66cac1ff421186e77328a23eef85e201b63857df85e200b63857d308533685b05dfb409b06f05139802774d416276d83210c1f5c464f7e237283f698c35c7643d161930a79f21757886c9f45b6bfcb668ec300dfffd21c655de6329781a50ae327999911237cf9cb5ffeb2135ab42df7c3d5b32ff4cbd5cb19e7fc7d39eb9864262d1397c9cc24c7a487896cfb9bd498c44c8498bc4c6e485a242d921649eba5bd4a274729e528891aacb5d6d24cd2922a6fb9c96bac0713b5442e37bd7404ec9e2149cd0e6d91a445d20ac08f00dc10d9fea1adf463fb976038fcc0c18744619854d56cb3bd8aed8f5293aaf9263eb6bfc9cb64874cd5953cf9cf1d6caf47c894a8454f1509929657057d228516452d1c7648d4470687965465d4e70738d4ec4f122633a9eafe8386163ba4ca7b500e9396e7830a93aaf95e19562b514b5423551546a61441a26a0ea4a9aeeaaa0926ad7b5bf28a66fcf303891225216a7d9210ddd020928072e017cd38aada902651121c8fcd89a29b48d27ae9ce31ca14ad16a25b8b964c11626e12131ba2cc8268b1ae4cfc8a7dbfaeba30857b5ca22d3285e3429e0fb64b2acae079301e8e1f928aba9229dec1648abf090e38d838aa9ab4b6bf89c9bd302c19936ce4070bd9d7fa665fced7a3e68b7d42bed777b3fda5bda3cbbce31d41ea52e518e34af204084653de3b28b6fd8e3cb6ffe7ffb9a46a24e7786fb0fd436cd0e2d7aab17a0343494fb6c67ea8352a39703e75895d971b03f9023771c71abb638ddd11df7c32dfccc772d3d7628d2d256ec8933f0e53cccd71c7af0502d938aa7edfbd2c641e17082023b5a46c39ca4933520ea90749468a9184905ea41bdad23692cd5a9b8d8e5e14d6e894c8810b8b785b5454ee78db9ea77f1f6b4133e8f931a8b5dfbd2d91c0baf608e6779f2d2d82b3518cb5269154dca0394a3f86969ebe49aafcb10d472516a127792258442516de973c112c996e9f9be4094d6a4955b8fd493522de9ef7802f8c412fdb359928f8026d385422f9d17ba51f445f12d62879d167921238c3e207d2933c29046758e02779d2979458fc60f2256f12822d7a2285608c9efc41193d390b1c5ac0594abe2404494210e6a24570a4c5517864046fde0f8137e869aae451a1f7ef4019232f1d35128a13c4122a7d4500955280b797df2b2939cbc84853a4711c19c7919134122a813469a4a93ce671f44a4a48ac8dd4b236f9c3daac6bfe884145b6545f973e2dfb604988f98136ed7d2309c82b0cc124763bef1defeb75f77a5e77492d94977d6d7f92ebbe8fde9fd4c351b3ae46258ea50817902ca2c7d5da9cc5da688a84b126d95c905ad444726dc7a39f5bc728acf1021651486add92dca4962580cc1211f297c930695bec685dd6c6bed8969db13decca5aa9724a7900b77d29495368ebe2a92c5536e48babc26f632ccc76fb92431955d9a2948db6a89233123225cbf8c9c150236999655b58dbda50b43788d831af328ca3aa18b678dad3dfdeb0a3cd61632c8eed5d685be8c9336bfbc7c8cc92aafb241e7ac716738eed17a82cde9c45b86db12ddd9e9ead1ccd79080e33ab95666998c6d1321a46bbf48d9ed135dc89edc446d327357a42853c9962fb4914dbeb09907d12abb31fdb7f14338249157ded118fd18e1ca79554ddf7cf631e479af268f4e48f692eafbaeacca37934cfe6ddbc2b2847294729a5943bb19dd8b8b07e0c3fb1d193634d02c0164f6cfef9b4fdde7b2fa594524a29c7716ad09ccbc4131bc8033eb1d1d428c7f6b7ed68a13cc63d7add60fb0b31f74aa6ccd21557b04ff0d9f3473132556f8c585235bfd5ca91232606070ebd1a9d418b75b6e278b87b8675bcf9c54dbe0af3e826bdca2b8ab1d6249269db6646348eb2bfd22bbdd22b8c57302c99191c664653188173ea1cad9c9da53be7042cc6321e7c4f40a6cc37808a297b5f060dc0c3c7a33f201d028d8c46df287bdd6884af1d8d46539e705c96b55a6bb54844eabacef3bc9cbf6fcef9a0c7436a211291340824d22323229168341a91909094949490482413939bd4393939119d8c9c9c9c9c844e4e4eb277d2e17b727262eb09474f7c0ea0560bcab8b89bd39b2ea41622520b11087a3c1e11a98588d44244128d8c88449fd168e4198d46a351e5a88fa634a9f65e8c3b3de77b3b7bbec8135b88e67c7065071d408fe7f3d1201d44245028343222128d462424df2c9590481f297b1d8944229148539edc8b31ee3a93e77939e7ef23d9d173ce39e7fc7ca8cf8ec39d0034e9d339abd0ae23d9d1397f2018e35f9d2ee67b79829e39f59c7382a69fcc681a84ad558b3e7ced4807821ecfe7f3d15a8340211d64acf0e05b8e8c8844a2d16884b1e7f3cd9f932b9d404ad9b669ad4119209fd42312b13f7ace0902cd506864442402658c46a00c2799170402658448369a64a3455f1e7d246ad094869f9b26c94917340da5ad1c2d11f9c4120472401a466c200c848131d0e6a81d1007ac6d7ff006a4813aa00c94de62b5756981ddd85499ca9a737a0b4dd51aaeb5f9b5566b34a51d7663135346e794d3ade70395a46bba465b9cab307f3eb0f419e1a2a9efcbd1840ccceb1b6d9e9b27146d9129bb7d2d9f8ba3c05bc4daecede2b837ae8d8f28b4b66fbce1ff8d52f5c911037af1c3f111793c1e8f67f42af345a542ba983fbf50633488f9a23a41baa0a94ae3a797f9a2c6481773be4c060539a4a62261b3e9f70769f9b948469cc8722bbbf22ce7e41eb926c7b290fcca37ce4dd05a6b2dcbfe94924469de215315264f2da9922abbc272144076fe917d6c4f79180a2d05a90b2f06cfab9d61fb7bdc18646a2cde13c1d285a2c661bea1f89e8d9e6a744aeaf148461d7a61857931e9855e8ce5281967c0678aedff999dac5c7bd36173c26c5a252868ee452fb69d880dbbdcdafefaa56d1c5573cef79ec83e48608cb387b327052daa6c1d262a2551f5a513d8012f6ca62452e5ec63d455519199b1a953708d735cbd6e605cb3356d266bd24cdb61dbe10747a92280547d5cd6a05746eb7315ced14de274992b99e22efc396e96a3ac8ca3ea388e302c19177ec265415012b4586760e0f7b7b6e27be9a9be5a60106330073007ec01cab63f5803c64021e00bbcd9feb8a5bd968b5481eeb55ab885334887e6403a4edb1f744995e52c7882d20ce1782df76adc73857648d4875a52353f00a19a4d80ed0f9a49d57db986edaf5b52d5bd0701571a0f8044551d9508b50d6b10ef8e20ecaf34558725827db1b641bc3b5a640a680a226cbda30dfbeed8370479adee8598fe5eeb4afb5d096c855e211b475db005b6c056d7b16466685ac83e979ae7679880453344107374f1d466787e96405aa67868098da29389ed439ab0a940021249c4e612ea8c698250ac4ec001388ab3088fb442a2e188fba24cc3f628c5d7e3f1783c9ef7807488e90956398b6ff6bec7b872977aec537cbbc7d9fbb68aac79dec15a6dc6e7e3819171d38c8d4c81ddd0726ad6a5c5e39f13b0183d98a0c6042040d39109c15a6b93499b74e53830f5994c94454cb4ac2d1f305138c4f1b745dcda60c515b7913acb8254f99e5a905d9028ee1d0c45bcf14c7251d00ee3da98a64c267737e5c02688435c066daa9c7d939996390a0771d485c162749dcc8ca5799e8d107a95950f04b1830e329903c309a984484621929111f448c5d9fef539fc16a6357f606ff4e0be7d1a5295278ccf17b7ed694528142b188a501b0d8562c5d9f35dcebedfc115e0797f047842b1f660cf7715a9028944a1587fece9381e8ab5b5e7571c478d84d24d3ac667193da5a15028140a918c4846d762afcb9f87342bacde388c918acac84868042a551999325f7f3ca50a932937a51acb912935370db1a34cb12f76656baccbf618715006d6da0edb0e8f28a1adb5d676b8c3b6d2b89725337eb0aecbb33ccbb3590fef3a52adaec9e2468bf9e6bae55bbe65d1ba6668caaeec6ac67e33df4cd7ddef4a419076cd3137651c2e68d3066b60acabbe7561ecb2ae3caba08cd216f3ed465396873cf9fb68f96181acb6685ddb6f56c64d725bd78b7926a9d3b0d6722ccb4a2648d0628ed518cdb26c03dfd8fee158e59b4c71c11c75e3285c7bec29e22d639f62cf63cdd0b46a5c1facf30f0c5652cacaaa1961ea8d46c5b7869c50092d2029a5297c71e5ac5d5d1900d1b981c28cef1c40372018900bd402d98058201ad2eb4d4bd3c6765b449ebc46f7f971a9067eafc5c54d9f17cf8e9b3e2d3e9cc4f40efdb8e8d86a9e1ccfcc2364fbe705d63638643b98030a0169321aa624bd125e42832f6e02632b3769104c8b3a160371a31c3aa66302f80f8d1365dc44820983fe2d3e687c98013893494f9ac22fdaa21e4faca0453cd293b7e8c94d2615157165f483776dff77398a091cab3d7500a9681c2d731410f40c77585911c1163dd21468d4a31e41a31ef5081af5081af5081a75cd02b66c024667eb180c4c4eb8651330b01cd812b0651339b0d93a4653201807ade615349a02bdf8c91f06cf5004c968100de943038d2d1f195d8416c199147ac880331c0cd9e08ca640e30cc6053361ecd72d992062db1997348e9fb00d75cc0a6ded101913b03dc4489ed0a0950862fd307d68e2089c2d9b38e2658ba02d9b38a26683469ad2b1d878dd6da881c8946feb984c711868119cc54023cb4d3ab6fd59dc9739bb091c086902072d8de3301eaf2d8246180f97ed0f7af1d46491b023e88064b63f4e0b0aabc9529292e5fbbe1a2d8258a01668b43a7608677324c771b6c6952ccd06d9fe336e721a4aa92d8146d00b68f5e98064404338ae4a5a7393f809d9feb9e526ff6ab68357e818fd6e4653208c9ffc65683435db1f082b82c733d08641dc19350ab030c1106ef2b78920d6f61a4f43dec097184d7d3abe13dbfee08ba63edbeb1342db9f0bbf348c15dbfe2db2d69eb98046ae25048da071fbdf1568048d94da640590b13c874d039379394eab078bd5834b0f3122448810f1f719ef2010b2428bceba994143da66cc1edc63205fd02b384b3a4bc69c4583f88baf463741c05133ecc159b6c65195c572560fa4949decf4a724c409e615fe7542807b08bcbdcfb9d6ea53db5280f70c69ae7ad32f5653bd49551199c29e0fbffed425e6131736999028eb8444d50bbbd50a5e49ee6b29f5dcaf45e4c9df138ad6c6f607c32f14ed0dd2b638485bc4d574c32693e775375ef305abe9dcd06c66436278b258ee5f27274e5695617fb2ae7467f98cb7b60a3dcd97540560fbcf1ba9026df79e34defc441f7c69aefb0bb2a13be0274ffde0a718f9c202d2051252850199e2effe201b1abf3859a08c01b8a44eb725c84397b70f41786a06710bc8d4f471236f76d841071d0c60000108608b52365faf29636971b258d22535598316e7eb66be982559fac14da0162dced78ba6b4b61c58019923c3b79c2e66a869ca0253e0388c9807b3b912b3a5b9492a313b739410477973ceefd3b6cf16623199df5c82e078cd777ce639566a97395934855958c47eefbd31a91ac0bed371ec4fd16fb6bfcbdce4b189e3b712e40b0a86c91282e6b88dc3fce531378154cd8fc914ff13c8941791274f39108f499884798c010c30994a25131310c86f32c5e79c99ac193373ec983c262b3613128bc5eeb57d4080e52c936517cf83b6879bbc4649b27472835d48e345e7d0beaceb095a54f141721c37ed5631d1b12bb9841259e0706091b03b90a89b3fdb243a7cbbec791db681ddc42c2cbbe48cafed7268a6450fe6d160de8da3841802ef0fe3386ace84b897e3d91c755f88213c5990dd79433c9dedefdddebbd15e2cf4606ef260f5e69c73d65eb6dfa754df53ebebd2fc0aca98f7fb94e4f6d40f63fcde835f411920f7a117eb0b7f8611fafde590cc4cabc6d5e3d5e2ddec68ad85b12fb6656d2ccbd26090520c7e18e4829edf18b498a9b0fd3314dbb93d658acb9ba3c41c1362c680a0428642aa648a7df114985f784648d5cd01c4375bc12bb39ce39672129926fb9819f30c5edd5618752d8ecfeeb0396ccc17da7126e790aa2efbc83cf28eeec318630c82618d17b07c3f8eded7611896cc0c0d188594d2931e0d8ef3c0cf033f2868faf845292bc29f060b5a40844459cf9b466cff0efb90af63ea75b71b8d9c6d6037ab6ec7002e94d1518ef242b941814171a1b4506c50582834db9f4a9bce2e33db68aaca64d926b3d59bed4fd39a61b9c9e73753282f7e721165a4b945a6c8a4caabacca505e5070c8d415c0f6475949d5a42863898da66e8832a2a08c25b6129491a64aa69027ff92da0eb69750b1bde4454f5e622b7995d8b67fb6855fd0146544b921535986324ad524e5c8349418190a0e2ecc346e022370370d516a504637b564caa88517998d2a146105296264305fa0d9fe55d6e2b2f39889c8937f2ef2dab01bd96543196ddb1f658ca1a0c4f634800b846265ed0c18cc390af2806360165068d1b6b4388a7ba73368ea7bfc5bc6a029903e8e2153fc6dbdb80b2bcf2d8e8c7dc15897bdb133b6c65bad28f53ccff3bc8fe713ce44bb3242a69e9e5ece22e60c66cb7cb1030c606c7f87f1540c7af27c8454759666bb95c9194b95b7e8d431fc69238a7369eeaf947748174490295e937fa821dbd8728f5a6e795e28da18d64ca6715467633c9687dd6173644f685776e59f3d9ee7799ef79ee77f0715138cd5ea7b7ff02b61983b6303bbc9b20f8eae93c964f4e422a329124946921293eebdd7e28fe1244b025b44b63f18854c819f2944aa425331050988fe41037d5c29b67fa80d5abcb25babfbcebaae6dfbcb68f8cae849091d72394afc68bb870d06458033008d90291539c2d1ea854f0c12653fda7c11c474e12f65341ac944a6ee7d91b6cef8235dcb510ffefb9229feb23adb9f4653a00d79f2bf41c361db600cd872c356a7c30346c1a34553a00bc80f1f1b6c812da08d1c03e2006f6c7fff7cc4ee2a41a6f87795205f7435b8b27aabb72b932939ec5eb2cbe8a61619d8025bf28b602b7b1ee7877431bfd5831c21419878b97e90f34dac45f65115d6da0edb0e3fa12597bd0e67afc3d65a6b3bdc615b59321726e7942b2b52d69032255a6a2c2f903f5c44602cf7e593e40ef8e51601b0e59b48182366c10d184d2c38acb172637981080a2c3714f902fc451477e9d96e2ac917df74e199a1aed1b7b6b54cf16d02448b2bd60d724e297138914813894a69b1219086952eb070b8a325c771b564b2cdb49ac0d1aab0267000e1ea740adcda3699696bad90a5001c95c31e02023bc8213256e974f9cf2f535c7c8ee37e659f369d35c42b5893e8ca4b95afc470565656aec85200a2e6585c0e33c8a49932f33571668b9b524a2a31a63080824524d5903a3a7ad0b0bcc002b9028bcd2153345a6ce7483e348f1d5bc61780692a86c4124b2cb1c4f903323267b6fc45f98519235df88b928a08b074a04579a329c9f2012ed4ee772fe808dab728691b007f78fb3274d8f0f35311e68eeef064b51cc551166bb26a85817d31a0bdbeeffbbeeffbbeefde5b83a5cafebd1c9df47b7d546cffef877cc1a4ca6effa688623b90ed47c08f3b99ba3b5a5debb6648affc7054d8323e41de73442a26e205114bc33b58584fdec49cfa9a7cefddb2530f78d814c0143ab9563efbd63eb8577f0f0f1e3b65ead188ec3c0afedafd7bd16d7191a5a12f0adf86241735e87afd7e16beb0a86f5aaa9d99a8d45a3b31a32ca5c97ee76a3e13269d0949438e47d39eabe650d60bbbc3bf6cd21ef0d796d74d6daaeebba4eef68af72474f1ab46c922d9bb8f1b239f00473db97dfef5e9433d1e6ec92ad599b9b721c255a7be3396cb7383ae8305d581fdba525834cad74ef6fc72055df4f61b758b13d0ddb47a9b23599e243a66e8c3cf9db2a6c4d02913f18c00093a9543231b1a3add9cb9229ee1f0002b4010d87f11cc817380642d81a7691297eed0dede8a6900ecdbd68c7eb2ba3af648d9029fe40d094b5b20c56d6aca4d9dab8bbf95d285a22dbdf768ec23888d4680ab4dd1bd7461130b4353bd63e2f478c68717860d7755de7d1c184dafeb59aa3fcbf0c7a24abeca29c6cb3367bbb33b7c6ee5c9dbbba34b7e5be783c1e8fc7e31e924cf1847668d917e425c3beb6ab85db8521b3ed59d8fe570aa99aff8d4b5c2940815fbc4cd8fe72a2ee8bf7092f6c6dba5842cdc7f6bf4a4815e8e7cdb1af1158dbe64c17fee2d5c1f6bf39902acfdf98db83ed1f841a6c5fadac8e547ddedfaa41bed0ef6fd92055e0536bb343e60b39128a60281c32555e4c40a5933823d14844225d6b3d76ac81a188770de44310b2ef33876ff7d34553d6464f39f3c5944d17fe20f88539a56982f962be4c176e6d362341c0f8be8c9729eeeeb1580fd6d2a2b044d7755feebe0cd3f7f37f567f3ca0fe78c0aeebbaeecb5feeb0e75d578f97cd973bbf56cc608cb387b337a3a54ce174e4bff6bdec610cc3ebe6cfd0b46ab010c59c2c99199a3bc45aeb92e737f222e94dd37bac47423645f212c6e845d2cd7692cd768cb5269148fe4526d39431bc081068a43f9eaeeb7467ade5f2f7596bb9ecfdbda49638b7bd80b38c7ea4c4e28711921f7922584225163f845e147a225844254ff225252f123d495432fad149f719e907813ebafb749d1ee98fa71b8d44a2fc41af98f7b4a1fa231e1dc92323a1919191d0883732121a19190959ab1d005898b1d676d87658095aca142aaa98e10edbbae2ad9737ec5c41f306096bb1bcc064b3e30d2d5dd775f9eb3a4a697ea9927d4a2e97aa17c850c540ebd2c0d97a3b1c8bf5e079588a524b8b8f8219628dd9b3a5ebbe8c311dd181025bbbee76b806eb9ee05cb8197372bb84721fe73164cad63a7ac69cb25693d993a3b5da8c5a615a6c781e0d0ffc3cf063424bce5e90fe782c203dcff33cf0033fafcb19a625535c6eeaf162d1d3fc0fd70008b3da9c73561a15df8a2f0f4d5f54a151c45a6ba5945285d6d095cfbee2bef27d0c5f890186351ae00263f13c112cd7ae7870d87e80fd797d3e3db4046584a0d0fe9ed29c69d5ba45398b80694f16141ad3d30b71bbaf3265027a72154893bff759059e3cf91b4153ce4d57c6c90eb410dcfcf64ccd1618e3b37ce1a4f1d34442a6c448172c9912ce19111b74e80c5ab2ec9cd373cfca65b3dd666a76583a2b1adb625faecd26efbdf786bca02f8b76578ea23ba48fe11f983b52755fdc1ad868369aedbecc5849769a21c08b4153f9060e4cf398c7d15665f4e4195f50d2ea4d4653b5489661d9b55d1d9e98221f8bc3deb036bc4f586d37f22855f84939b6ce312f661c9f7befbd1f9badfb60cf0c4d0bd4b1f5a0ae68c19355c10ab24a516bde17b6db5aaca5141c6d8bed3acee67a6df62abe9db5b5fb6ed775f6f36e386ed8f840f0fb56302c999921bc5ef3f57a590b6256a6cd80f8c00823820ebcd4a4ce0c88500e2d7a37589e652be427f21299083909f9959dc84cacd80c84ccca4764236c86414e22ebd8b9883c83ed368affff9fda6cb521b319109966869399eb3b87dc23bb783b99956bf298616eadd66a0d0dda7efee135db903eb6e71e39099a63f28d5a93b2de68cabfe25a23ed195e9917ef0ec42b83eda16877b627142d1bb68767d82eda30ccc008328821554121526c28a2609db04fd4d4578fb0656d6ac5b89329af8877f36ede4db2dc7c70c19b82f86dc95aafb5796b8c4e7c7115446a63d0e2eb51bf380cd0bbbd77f36ed7d2c0340d76a894e25bb91017b4586d76b63fccee48951be48bb985873dec658a4f21d565bc2d339c17c3fe0ee93ace03761e507a421f5a94b4c9d11569c5a53cd3867ce1bd2abb385f529eb01b7da5b9bddc815d873fd0fbbeeffbbceffb62b8c733dfe646056765b5caa0d7c1b06466685a1e1911ace65083549a0aabaf8a535bd2ba575695a93230d3823cd8626555d6b695c5ba17862523a2c1f7a9a87c1fcff7f130418bb6e57bb1c65a741c7555a68aca0cc53ac59e2a9c9bbaaf54631463ad29e9f7178af5f5f17c42cf9755c02f7b1d4d8dab4767b38415c6586299bd12b8fdc3b2ed4fc3185d7811053346204b20515ca692c6c0d72bcdddd9e01c524a4f06f1b4077e1ef8f940cb14eef10356542f1c2051f689ed997effde772b2b2b397b1d9699b181dd546c6382cbb22ccbcec482581a987d591cdbb23d6af5baea752349680d4c22ba0a49c55ea1a95a8bc06c6cf73aafab36cbaa36cbaa357f1000f101ac8954516bb5406501828579d81d74cee979618d17b0746f5996d5b93c31dc2dde96196e9458cd9c8e14c673a810bfd117afb98e7599d5686ada665235009a548de4dc6c1c2df4d9cfcf60d02d5fe37db7732f77e76ddeba699bb7a9739b3b6e722aa47bfa62a8c55162e865f6f2bd64f1eef319f07ca10bbe07bf074316ddeb2782c505e0b3d880e7f5fff079d0775df84326c2c74fc987169acaef1f9eb9e0f3d9f7997a3e1b69c8253486c4b9136ad969b1b1981c2823cfcea31db5d3e6288e4a4bd5e0332466b2998ecbcd3ecc86388c5c9b6d7f9ff9ecda1c5a5d223ad7448882c57294e3180e8269b00c7e611cdcc23d3a87d1144c3b4c13d1443411ad710efe21537e6d21d2143a8aed3020241f211dfdd5e60c7e61163d2d018b0e5be2c6997027fc099932396cbe8080c9612687e98b869c9b068962834459215322982e3c766d1a2453bec35bda5b5a7b2be7ca68ea16b141db376a36cc721866d19407b35a8eea5ec707ffd8fe380766e119ec03f3c03b30ebda885c1bbe816ddc221ead3d1e0499e23f43aa401aa9ca41902f3a5c6b0266d5302b48be89e5d061f8fbbc09023d88006632ddc462399885591f4f09ecf3910c388ee3569c32409efc7fc47c65f3608b7265ced20e32c5e5c95f04806c02488e8333c42b4fd02b56d0b456cecef24ca5c94a7394af64ea901cdb6261aaadeed44aa3e14aa3511a0aa2456fc751a5ec8354e1f79f43ac1b2a4d5669b24a932976c7dbc92ddecd4d54ae98d0920a4d7945b20deaddbc5ba5895256ab70ce7267d89eacd6644aad82bb218c9a6cb1d25a69d8b3e9388aab55d06ad6462d52896cff4af36e5e11ef9671e41bd986fdbe5c6995866f5ec1b03288c3169b31d9cd5d82e0ccdadc99b39993dd290542ce28e63e206633a942e5708673feb9d7543235a70b04774ce716854c01414f6eaba236a7a0992e204c1a4a9cd30ef1e986ed530ddb5768196242be36e8ee73d6ef1f022036c0010f48d4fdc8b0fd573e61499766d0d49c6940a22610d901899a3833b6b232f3198bc9a275a8640cf807b9756846000000b315000020100c870322a160405416a5b50714000d6e804a64543e1b88a35192c3380a43c618c40800c6000018209129ad0244c28338cd58698393effe591d967f640e121aae91d78a86dff55ef5974638076546ae99bd1de72826466c5cf3b2cd858240eac77e99ba23f809f9c4c37253eb1e3f5255291c22459d5e2790fce19786127a04dc2f1e398387747ca9ad0c333f4cdbc863cd62c4af09729acdbe5c9684997e6085dd5293103431a97d8d36596b48775cbfbd0024ef2b990fe6127608fc7a47a6a2e7958a9886aba0a93a961f26f834a935a00473a074bc8b4cf0bf575547b6544f03973abb172a6a6b7763bc59bb30d5679c3a5c12fa3a9b71706b1c3db9f8ecd247d666dd08b66f1b9ef45118b83126304cca9c4b8a5afea51cfad57265eae6f7b98e34383bf384cfc1f111bc7994b7d830635cbdeccaaadcd4bf2f57b0e8e8644579387634568c0810e7282c001c82b1f8939161ff7be9fb0e779ff089ed9b69ed0879fcf023a0d42b1e73ee98c2ae3c4840c34a297f53d63b4512e69ff1110d2e972b68ac53af758f919b46b697afffa9805615a11db1dac4c195995d090142167851ce8ae134ff5d9992289cfe048b47675fdcda41f4a53478ada3723bb67ed024232ac7b75e44515820e54826583ea898729a42b01b8de9180787d5661765491ce73e9441156391dc63ae4964393e1809eb137f28adc5be5c5e66ed36092c4480fe1db1160d2bffc7f87527263ce7c5983d545aa02d5031f5bca6c2b7724438225c9ff51ce76f0a15dc290044f64ca2fa65530630ced4374be44eadb5c23e25562302365d532ea814915281d9f4951b3259d58b627a6d8b7c01619b6c9e064af0b49321dc3eea364f9bd862430be7a998c933b541be230e5590b3ade4d51603b2cfc262d04cbc4fb6913109e7695de1691923416ed03252f1f4d461cb0f2fa5b1d3ed99691beeb66e2f4d483d4d06ed69f62a38afb3cd287a3e4dfaf3746b54ee09ffcc9f6fa855075bad0b3dec92193ba55a47052543e25322adce374ff108e0d38581091222f94384712d551be4a81660256550c62f04be7ce4b60f94b06821f946769e71c7114370ddc28fa463cc70f9ac14d8621abdee8b779760200d14b16dfd84e2e132d4baec5f1b6e73ebfe74b3e0e76e3e089e68b1ecd62a56765758c1b9199924fd8c60a415123a6defe7d67d7de7df257b6d5edfd06d2b3b61e28f7a0d1e476ae2a43df1a63f87148776e71469b42bd3e8d98813ec8b37f93a2e3d6f9f45411f2cd17962dec2794384132cf3164439213b4ad9841b85e084256ff6f4ecf184a26242ad6a3283e85b89c1c4c70e9a7398d982515e8ec9a71a8011ac2edd33a57a3f784f1cb29c6f429f4e5edac8e1daf9ee6f5c26949629b5801d7c0013340bcf9de7785ed153eeb40996a8789d21bb89306b31d7169af6e62c95f237a1ac5734aae697d054314d0c72bd330c5c7d05282f03d059d0be5d6d1cb4b15aba4b9fb3c5205db3cb378baf02817da588c3e1e25c71519ea7e8e6d07b82979666faf3f22ba57e027a64247e1fcd84f91a1d53c5a659e35babbc4e4cff8670e7563e33c1478ab0457b56e501d7c3992ab6e386533bf1bc0e59260a5c764b36d29ecbe7b29515ccd99ad75b74113cc7ed72110fd1f46098a9d416701443a06103847d4668c060fe13a94097b36874bde38114b655f8b3dafc7880f2ace606136441b5d7483693bcf83c7a6e72e30f9bdc9cf543aac886b8588d3d1bff84899c74c56c30b6e4c34fb6b89543feb1f28e3cc038e401cf72f8792889a36c98f53b3b10cf64567d477f4bf23cfad51090aba5e6ac1ce6965faa5e925f18a3a62895d01bc3a7c1522c9651a1920e88aa87ba0ca88acca4f280cf3e9ade16202a412d52b2bee06207f7244b64aee6edb78f5f63904d355b82fb3e430cc752335db88ff5d7962ab6ad9eb14682f37193e16154df2107eb8877281fc36dfe68a9ecd99c067c9f61af26790edad1aad164966a13a448b44b7de97830ba068eb1e831315fc438a2f07d03ea402706657cbf2071f551feb65fa2f05b906540feac2102dca6a89153fa522d947b77a9616b23478adaa059eb54bb3660a191564b3d4bfa214d716a3c257a2b9499061efcdff070549cd6cf1e94802d5c91b70ecaf38587c2f124bb7ffe0a2263339e17714260ff3894808a3360fb52870c43ea82e311678f8e912dc8d5091e13cca87484fa46b2ac40d009c18ee91b8422cb08041d316b6e4c708e3e0aa1576d4d28102175654ef3f00698f508981986ee5a74c0cc43df95e0779407035793e875133065e52324c435636481077680b0d98ff94573ff8c9197194beeb052c355588ea0c08a8eb0787a87ab5ea4c7e5cb975f501c2116dc559f09160e9bfe488c75dad4770d9e72f09e82ea6c118c0612a11e92c30931a877d2192e9c8962b5a868e397dceb4de90d73974f5b442bc3465b0944556ffe2761e6e6dfc44540e56421fedda3e3ca6b3a2f0c9abb3f361878cdfd6e16dcc265bd0f08b2967f755f902c0e5566e1c3ea43626a25d9bab8d94c553db44aff4130c0b860800a402781e127a1cb5ae11526c9b6a437ea045d254a3471c0140975d02503cbc888e94415ec5a8001ba078acf7f22b5287d4e01728cddd500a3ac7412d1d51587ed7f477c6b60bf9a3fe0f0ece99646b74359976bd9f0593a0c0e8680e6275fc45c51c198459228742627b2fd6d37a0225bd945f6a486a753ba29bcdd2b29f9aa4a07108a021dd43d41d1c04b14b144f042b733022d460c4a2ff53d46b1815fc1f82a2bf8d129a64337da57aa06262f35f3c2fdf6246b636ef53170c32569541c892a6d8207b05d6372bd453eaa9ac508dd64d6dab0b9ed584e244582be809c58bf11b77c1b3aa628828c821a9b22851273c92817e130061dc8c75af7a03901f766417632cecd091f54476c7a9d36fcbe6b7ef0f78a589b7036f36d1f1520624bc226662162cf34a3bb070b42861693d08b36d440941f002811cbb5bf5a1d1ed1b9788612a78e5784288a56108cc1d47af444ecf219166b17f221b8436c60e0346eb0ebeaf0cbbea7f3683c229e86d8937b4332b6021584bcc4bbe81547d53226cc7350665570059b1d646ac75c96875b7b892f3bdb82f85efa3b3e4452230c58979adb6b46a5cebd9d4cdb785b79a8e36e3d8df6df6bfc3554ab23a64bd9a9f145ae7d8dce35643bd4d6cb790087571de77930fd84667af185c7d21be08951b49f32b9e9497624ae7b1ee30e564a796b2a8d3719baff61f0a925c26703113e3d040b9789b0afd3699f8f8886959c8fe933fa58db0584d5cd6e5c609da723ab8ef60fc3c206caba6cc39dd4439b6b1a0d502846a470607c1c594098f8f3cd22a25397d92ed29e2dbd350915e4715656995697cf00dbd76d8c4d8d2d53eac08c794231cba59db7b557eb5c2f55b72fa4b7af60555ff8747befe42015deb612288bb1f2ddbe52fd421c52da26ecd7acb11c7cfcc2e17b5be18d9905584b6a5220e0820a1b24e1b655a988bf1a48233b4473d906b2446b3ef110413f52dcf5b902283e51fc178b47a87c0a36527492dac0d221844bb366349df1e4abc8909bf891784db3d688f16b5f87c17adf666723c2211b2c262876fa191232374dde5a13ef26ee7d6698fb75796d8f1e548d172c2ec7340434e278651beef17b511985f28daef089cd11affc449d2f3aa54e04b6cec53305c4b18eecd2f34788aeb6eb0f202fe2b6b7eb3b8df236a6f73b4a778f2871606bbe58152e204be1f1e7f5579034fb933a6d2e1380d2ee5f533e13452f4a8375ffa985573219c95646ebe4fd2fdd7a51801aebd790c696249466d83c2a1137a0798ab300708ec013f4844b4e00890bf5dd54f7e1c4a21216d08a3fc9bc564adae431127a056c7564cae523c752608ddc1e7ca1a4a000322b37e84a82a7679f3de268832ef50af19344fa5917cd64e53739083883954adf65c29af9eeb5294b80264ae8c4866ae3cdeaa62eea4292699aca48e7fc8ca277c96de99662bbba36f572ce2e496b67db7854e14bae3fee71856f8a2fd0034d26692a46891726d8206bc7bafa14e6a91e19403b0043f82d998651d24725f24a71a3206cbdea3e7d92dba00bdc5a10901194417c91958ee376d78ed693e9720f557d26fc12d820618ac1b1d5cb90b05743c1c7cb196d9d58c31013d1d499ab078dbb0c4e1993bb382be4dd300277c090250f2b38d0e65e0f3fd26608d55b51034088401b985282b095e3e6564f4cd31a013d5a1968a46b8d11f28251550926a8ca76c4a52c7420027c9b6a5c9a93484d2e6ac6c9d742f20ef3d74d39bdb1c00be9c4e26818049be35536065ba241c445685505d1c862c8e27f447f8881ced525a46da43365674ee30837396a36de4e79f23134c13544d3c3aef586c34bfd937c0e4986b2557cd164243b547e86f4483f17b895aea7f3c117cef6f536ac7ff4d374116cbdf9f9d1674b54afb297d623d8a8c5e9a67c62e10a3770d0acbfdd71239e78b6b3503c021c34ef4945ef1845fb14da7ef3a82402a6f9c26652165a7422070252d6b420e8969afc491f452bd19ffd2f13cbb5593c227aac6f47aa7c87f6effa5acd18873cff974474c60bf3483463fd847def0cff8404669c03e2c3d7ff53d41a23f6f45a66246414101a9211a4e8cca0c10599ee0ec37a5dd0730c6c6f9b2c406d1a1928b623e88d100f67d13ca3ec84165ad2b3652612e0a799b31f82de248530e35c6cbba0534d191a3e3ae82ac47a82765e48412741b14824e5b7811c6c658d550710a0e2bbc3061121fdbb34d619c6f87729d704035c4942381fb4c380a856cd14a601a7fa948f9b5a54f33c61c015536844bcc25431004ac7b3d0761ef207810150fb8e5ceff88f7a94e4651484e22b6905ca842f05e292f868981840412519918283b304423c788cb8dc27d7bf30128e08f8051409fa8507e974463c134b9ff85661484be44455187ea632d1a72a02ae6672daa93523a90c491deb57cbf806b8c5a4df806ca64d64b34831a9bd214d873a3c6ac009fd31e85ff062087db1bca9867fe752baa2d79757d31a5a77126f5d34ffd95208668241b721887b1fc622a2f0bc90645f7a50c9b22e3368cf662ce8ae18343f18c0574ff3133203da6ffe60896ea1733e6156c5d9500f7bfd7102d3162adf9b8361a129adc4ca037ad045e446748032cfb791c6d097f33599da2faecf09bc3b723b95fe02a7e19724d72f78e929ecbd300db8c1603ad6a0ee143a8f454838697825c9877d430b850a2681e783af50a435aec06893ba96441facdc388adb43351408eb19d0a51b128d8fdca4cc1cd61de3e00800fdcd09b746c1fcb0765134c4d4aa8f77f890e0cae327c5e43ab1baa80a3eced5e75cf3a60055925fff78aef7503897f57248bce38a3473b00b81ea4615dbf2ef1d8961e748c1460b1876885e23fef95040fd42b301a089630758257bb5c5bdddf5da4a2b68fd280c5dd17d26734807d95e35f4a508447a83811c149bd2aa6e8418889875d94360f133d8bdee58bcf77af15d543baf15576c524d387f798b64e1b5205cd9d0bb26c0bc3301be9c4c2e44d7fbac4ae3e42bba41c5f729e1d5e388fcef2501a66ac8878dd21360316d94c9843688c96cad499ea16c6560424cdabe3f082b2d6e0171597a2e3cdafc245776894054d644092b0f667c1d3e24f8aca00dce8b4c7257260d6dd3c49ec99ebc1bf15354913c5e8ad29591ae6d3c886f1a4b7e026274c501166f7f51b276f6e72c49ecb467e5dc366fa722039de2272c6f3b1f054573455496a8e78f294171d24bc42f0232e0ba47c0930a36e5b6a2f33f2c2b91e551e70ff04d457d5e7e3776c1f425e7cf4c01c2e79afe0660bbce7d156b6a4d342012d599404ab1fd1b5d38c9f1518385854b81ccd3435461273936df3500be3590a775eb1731344e21d90d0ffecd194342e2e92a36689941d30b8d938912b319e0e389c9c671e8d1c89d3e5004e6172455363f01a747a2112a26ed80612d8fcefe509a4d3eadfeb64554eb1608ddcfd5104a8df38d8ea8737d20d76505e5fd4fca923f5bb8f48dea5033cbdfa68503dd495b29541550e619d62187c2b00e51e26aca06e1c7cc8ffa6293c574caa4cf733c9a0b8f305f41feb3c238d3fae4713499401fc6a4bfd91ca41dc33878fc4b2819d70dcb4b4b44ec4580417ec8ddf724f9e8dfdea65dc89065794ca4f2f60c249f354b77bce96867451bd8b443c40e65527f4625108879313fb57540ed04cba855f8e682c439c527d416183dda2de0d223ac16508a29d58f228e936ba2390a358bf0c8431ec6228f70133614b042db7a980524bb32b44938a614d6c1f25df281f429c865d806c856fd86219e3337169801f438ec8604353485cc84dc291b6945b3b52ccb4c2ba5d86be9c03c1bd7f8c705b4bcd7ca36ba8d9fb8e7221e7f4187fc63fcd4cc33c95f9959e70359642280ff53101df41234cc5989e24638e392fc521eec0b531fb3cc1ac4689619bf19aa4e5a74e9b1d4d2917b31c10cfad644a615a57cf1f90be158f5ef1cc1498a6441f00b7b35d82dd73e112411e55d680ce0672bd29afc7d37898326c95e5837c9e471ee073852296fca2bef97c0d7d473ee4b0edfc2483a6e00ca733795f43008f373612f5ac12d4cd7e07e8782c1b03a993ef8e4e7e41f574f49ff87d9768b4cf7a7c7fb372136c416022b3ccaec0bb081d4bc8a37309a1c5911a85193e0e4b2f37e4e84f8bd8f5f3ef827e9aa8e3e7fac167f5cc5bfb878d2858f281a81feb45f42b5fa1ea2d4abea40391359ea0871abcc398d6419b7df1690fbf3973f9ec617b626ddcaf8233fd41480fb2a00b77962d50063b82a0081dcd2599a56b1e84312344d814793547f86f149fcd88e9558004275ae22d58a8086fbc4b22bd05bec06a6ac31683e5d0635e76312159bdf1fa50961b89cb21fdad53494671acc962bde8232e923828863fbb738fc7eb815755483a5418dbe6b0453d1baed1b4f788b196b378525710be67d63d9a199c3499d864e2edc47205335d179f79d3a2e2de4cec4bf3b935e95dc441f12dec531d3965207838e1a31ef2e2375dc677712ea969777e0cd13646c1eb0b4b27b9be7314f0ca44848b70ffa591a86103d024e2a265c91f52ab91996ca8eeb976343505defa53de920751ac8a7860033609046d6474eedfa9b28544ccde783642a2e83b462debd4852716be32e51200ce98eb450aea0033d1ce0e4b2ff404df2629e9b939618be46c5044db3be85525754591c47b3450f2dea4e8585cd20c11b2aa67a56e1501dc70efd75c3f2f474ff730783405aceb94d528f8ad99d8a264956d29eff53cdd7ad67d3b88ae9357d0231974bfa0b49fb11db8b27d3ca5ee5b1309aea1ba953973a75824bdfba1caf0fe9988a692ab0de77203190deb68198205c5b567259869e8fa45c5966b77083b38a8cee5aff48b3beb2d7d77023e5492a25e82b6744351521ed076ed549efb04856e4a390caa29ccf2b054a0c92301f77e2d646ddcad76ab2c60195712f9f4ac0173ccfad8050545d2218f4a4c0fd9d9c9197f7dc6c53a2311c58db49af573785c8a31ba5670afde1507f62421e2ec50854a920541e695b65158877303c23b0992dd06d6eabfedf15b020096f99f94caff0cf158fff9dfca9b494fa64a2691585aaa9730fda13da4fff2aa58442c54bb123d33ce641c89bc5e497df5176eb6f008f4ce8e16d3866ad837675fdbb82e28df03880af389f80671379af10e747e66f257be3fbcb86929d1f763eac21d5198f621e93cb06c3d0fa3bf6bc7da5e332f111ea320431fa7cd05dbdec79eb41d3d6d0f593381080ce203bb92dc08d75b4ec13930070b615ffadaec779d6f215454fafbb35c2f2bd61be9a71bf4bbc1edf1491008ac68bc6366313a44afab823f62cfc4c211fdc7e3b4cc559b17eb6f5c6aebca388c1e540d961034cf67bab3f32a8b241cb12c45b021b54f9c93ea6b6b702afc1d5479eb05472a1cf85281ae2f32a5f5664061eff8e0104b70295db75c02197d0e84c298f7de4659f7770908ae3684f9f1c267ddeae453aed25475ceb621fe9f3539350d6494f8365b4a3077fe09153126bafedfd2d3222ab0e4f20039323028f0b83a78470d77ea3f8c4efc8ab6cbe316fda3148a29772958b2ad786065d2c5bbb51e6e3ba48b885b36f9ec9480671b108783d5fa6708c0bcf45028b49052767cc9cac53f61eb335cddd23ab7dbd2923b5487044c530deca9d420d7631ef360cd2fbf495bf105517efc01fd6a3f756312a50c080672eb16f781a8b0cad685674038e6fea90a42203e66849d17e60f2e69b5c50ce0aa26fc0efd00ed519106bbb19760b1d9a821a461f41f15933f25f8dc4ff9ef48870bd78c15320aff6f5b6f6419537b183a7534a396ca7b75bf014cf9e9ff932d279fccc8f10cde89a89440cd425239f06972c8da4548430a330110be5164d386268cb98cf928fc7747c63af9a9287888d4c6b210d914d6f051cccf3567ecb613d4c364576f8984d9dc92327e2863addc59ebc0e96074830ec5f5f57cde3b8491eba89ad30f98c5ac97ae76ad9f04c14d56a87f8aa6c60c0f8306e655402025188948d25b4aee5793ed5f6f8b179b6ab5c5837cd7188a69a1704a6866cff105eae9f5d5ce77d21f2c58dabca4440f374fc9d1e94f2bb204afee2eba09a8c5bd4ea8f506139132accdf768090c00a8eb7ac3a984a92ae6cebc65d6796744240031312a4e4034a695b876af2d142bfa410ce6f6554cc7e65364d4e2224c64bbc3b78ce672add79546625efa5c1c4d2d8de6e3164d533c215e66b26262fd7465322745c12825ffbdc79c0e3303e72baf2b1365cc47cc9ef946fdb0bd3e199a390346daf01658ebbd3da2fd1e7c18dfd73ad2a20eaee2b6cf5f28502ecc90ee06dd2cd2a405fb71e9185eeaa6adabbf3681bc3958912920762ed18e5f1bfcd9c007895b4a09e1895d57e01109e54a6050170419da530b9b54aec5908dc3f61ce8e275babf0a06b83a5d6baf0bca2fd74343b5921ea61bcf4527781ca4024d3806d46160eba7cc51a8440e1b1d65aec3d0525ac9c7adb651932a14f00e5ee7af2a0b4f1e01988a4db1f3d3ecc78d0ff6a2d0bee6c79907cc5d466183a64701fa5bec105038116b85d756df849cfdaa4f4a54fee70caab6c0fdb70129a113297a8e01502ec25ee7ea23c592b8d5fb3dc9e4327276b9700496a64d9230dc5844a5ab1eb4f6838b496a5185648a25ba7c243006214096906254e72a4707827ba253b1dcd783f04f5f60fc583c82e02235ab84ebc19e55dbf2de7d8c1d555332a26c13e297233496fb353d0cc3c98ca6fd5b46857d227e2e150dd5b61771e4dfcb14afd43073fa2a009dda0d68eb21ec2b2082f4fa061ea6a83673a34788840cc6ac7f5589d29c8d7c9eb14a3d4aaa54056f85051c2fb7c40aa48c028e2594580a175a93b37f55ae8d55b28a90b0a791c6f103b34cf704e293da6a6377e10975bcbf433e8860eff5a2b730ba9bdf23f3286a5296ed119b8cb2b837bc9de2455857a895eed2e4e12481c2456232b09026b2324f089b04434ea2a1ea278f75ffdb970353c8b35ac8e4311032c50229f74105526f88d00892e633d2ce3fac4f8fd27f0f69ede5b9dc7458ae678c9b8ce647421aa09d88703bebc31ca836402c96b8ead9c24429140851f739f99b572a0bc5a0177f91f4106b7e6dbd85125955cf2dd1600e76a798c3743fdcae1970059e8ec742478495981d961002b8108d230509d847acd0742e03253873f4345b0861b943bd86749a194620ac86ffed42ba5d978eda8705a810c003b4c7bb9a80418c11ae3b9bff96028aa1898cdb8738998dffa450d69f49aee02ea70bca3e7a6be8b77b48ab8c2523ca88d991a14a728337d12bd39468bc1890d765003e705d41bbb260594f5d960005fff9b2c5128e7c7922a52bf569a66573d2b6d228a955e52f09c279af68327137aff33b88f13ea02faf77a1c0eff65d4c612fde828c65d941b066e3844b8ed5bf270d5312e33da911f4c8a1cbb35bf30e19a6f1c5b6af4b0a2645529d0aebc336217fa6fc1b8c9a7a651d44de67fe2f3b377f4b5e036f0bf13e64104375680ba7bb10fa75185d89c6a4522baaad700314d98f8bc3425c235dee57f9d475fca2681218b7477c8601bee1af0c1c47da8342aa03ae7a80fa463c8d9a472f36e7253231e88b0c4396cf6bc3ca1f07836fffb9a786ea3409f23a12cf1804d5e0673883c89c37ddd2f678090c7e9f16300011a9724a0c49da9e5787f0e3d8ac44940d6178237d96e678b15b3503e2bf781e1eccac302a740181d577acb427263fada9e8584048a57c667f380a890de2d6740c0b9095cbc9f6b1b68f9176f460042c7fd1351f6e5aa8c224632345cd2015f85d7b3378ae5c9ad7c6a86eacdcc3fc6a7add483ddd089fa7d836bc503191947a6ded76aa231403bd0a8a57ce7ec838e0bec635d01584c6756e94d78b346b51ace557c51455e93c16a0284b279dd2a19b26432ad92d15a652a8084fdef7a32d0de0b896499059850ef42bdc0e8b4719b9626853440912555a447021dee440e4dcea3028a2963d9ae4fc1aef74d04e0368850933717662bad4496e3ff58a715503a036214b5312a0bfbb45c974c954d679fbb68109068ddfcc74d3fc044e895f098c930d786caddfd4c3fba14573705c0dc9f7c2870a82c675c6d068499a4e9441311dbf15abf32fbb560c9cbacf1defdd0c38353719c01d4f65d12f804a72968067fb468349c9351eb358d87625b5ba7098fd3ad530187abd1ec60c064a9b8b54b051d0ac169e212a9a724e7e266a549ac6d80a4c148c756748291275117e49f8fd0551216bc6496b52020c708515012877b6e024a57a9f8945ebe8f3b50caffab79e2c7148d194f8fbba48803d0be0400a0ff604c75828b6951a729b2a6bee7057c68286648014aa705ba6fa3e8ce6a3c9e742383dc556b9404db31221a9494809e35b68e3c0ad67e55f00eba32ee2c2ca3668714406a0b8e3be11b51163e2c7b0d26b68f48fb89fb0b9f413a49f72bf9e07353559ee24921a20790a217bda8e1cba6eb4a884c532efb8f2adf1d9ddad6a01d8ba09628405adafd4fcfa897e342b8dd74b78e839712b39627be40aad215bbbce44d534456eff61db09435f41874b27d14ae0ac466776c6b7e91332a3a2c544aee55f982b337cbe68cab922a032d34143f0aeb56b96c20729049cbd27d2fca1528be365ea0e377f35b785327944a963a6ef9cdec86f32ff74dddca333564b6cc9c4099ec416b1d05780aebb0529a3b0dd531c5e7e94c302989f7ff11e465098307d3bda1d53f8018a74da8353a2d83fb9b70cca531fe38d9d24af474e0f9485ae83178d58854a008ed4534b2b2e82f136fd03c04eb71516ccd79529b1570344104ef557b55991ba656df93bc6db82d5556554d1a6865a327557fd551177a8ba6233657a8db1b841ac492fa269981a7f303d1dfd14635cfdd459e3eadf60a6c0c180e35829a89115aaca833b6540f855cbab605cc6b604acd599c810ce7fc821f8689c88957fab375409f2065c0d6488f21e5bf65641a627164f3f2e9d49741874c7af04ea7f2cf81b27d488fc2c6f2f5ae659245dc9a177d7b83072fe0c5c4606631c520675d92494a58b079458322666d81b2fb453afdb01852442d0740ce5a29f96a9e2a62d8b7263e7f3425e4ec5d2cf37832988127c11695d0b23b298f68df50e94f2676249796623c44ae3935b5ac8e9b5dd1f9b8c51787c40821ecf05f04afa545fe512149f2485c4414ae9191178fc94c5546becf82a14cc43637470c5b691be8006149a688b5ba19823bed4dbd178d61b1320fc9e02828eb2245b0a041278a930065aabd575de1610277d706ce573f68f292542d09a2d8050405064bb9da819e95d78b3e79cb584728192ccb274637104b7385baab6b6127763b0362fd51eccfcdc10b2a32c5369043f7323dba0c8c896158b8d749cd5b5eb8bb2c7be77c50471c790e256630b49945f0b339de9cdad1849c0b6a3988f7985dc5d534505895cd922f01592b4a94b0959bf5f6b418c48ae6f7df9c15ebd1e774dddbc62149568d5b8b4f3b9fa46282971c5c2da559c23ff1aa8fb5561c7cceaf97aa92a4140c6808a152347f0ff3cf9b7ecdee0d66bfb1327386431ea081e971d19c2d69af95b268cf3e4c180e058a1263fb8c1b646cb972892e007fa177b4ac95ca1576a2cf6f171a8a2e4d26d8de43090e5c302d8b82797466040b923be3e25224c52d9d798f0180293bf1e84fb0cb539e032967bd47b0da82e4661d0acbb25ce019717d43931ece3340765556e1c42b6c66f4b7af47fd018e38240074778943d43c113eab231615556531c886d658609408cb979ecf3ce5d3efed53bc598c4fa5307706e6be2affcd3c31cbc68eee1ae547ab75602606ac748d56107ff5fc629a4d5bc1ff8d6cad0386406e06d1c2f5519ff43dc47abebd2c2c6ba86b2ec26d3c2bb0fad90c81c3664e661cca8d89687b79ec05495e6db6f7c211244a246e0590270cbe019d141568f8fae227f2898fb6569cffd72e296a276dd26b8069fcc8c0c13b6f9a7b585158f9204e48d24faee2c84fd889bd2924445768b299402a0dd7a7d77a6c9bf6c8ffa3891b484ca950e8abec849b59cbbe05c7eebf48e0eb037d1b29c58a501ae5b6357dfe00aae2252419c2833881749f5b872d9350d461a4cca256efa63d362e9e83fada688532f0f46f7eaa42500bf6b6f0e44dd137d5e7df349bcbe3d9212c156bcc806f0901baab86f19405bac358bcb256c32d2c6857ab8bbe8223c3eab0b8cb2972250e0a36ed1f4dea4fd7a4acefd17c97518bbd18ef09670bf6d37ccea654391791640b4eddd0096722b621c966b916b0b9264042c1e0eedeff0815266f1f19bee3a808c463de1155b811d6457a1acf5b616f358141e68a5d1b004651a644b291481049ebbe66e3fcc9662d38cb622777e5a9ff9d08c5da97c096927bf7ded065af300cfcf9a65e2af3f181273ae682d72c4cbfe9bab093dc00f3c237055149148e79474f9d78a26a862742686d59c91955ce726f391a649acaa1f040cac2b73ccb6651e1461a28a2954b358903c463cf407ea97790c4bbb9c85dde276b54ebb9992985f0f1ca0dac08096e313bf765834ce993c94cb3303b3811d9ee758d9e948022f2a5ba8f9135acd2e8d81642af337b0c2cdc8a2d248aca10b22dec90a9a1db79cf033bf67092ceee8864d1f25dbf569cba550ee0b2670bf64d4c8d32231cf815f727daeefdbc5dd64587b47dbc6c51a3c517119c8e3043fd59b56fc2226b751afc6e0135a74ed227e8db7a60189c7c8120872484ab6e281d25d90c227d2cbc4d077a2d55aa6077d8a530c0fc9f8fef413469833ce002931a06e31a39c993825ddbad8e27956b423da208e9790913971d0ac1463bd890a3cd79e21655a638b6c2716abee84784d4262c5420eb92847a5d691451a6f0d615fedfeffd03d91bdb482181867f08842b347f8c59b061a7a8828bab157c8ed2d5069301484a9bb0e4b597707ae582f45e539c5291233fbf5b6af038f9004f677df96776b0ac4e3b49e8532b9e381696b147e0505c92c14710e2c9c7b8c05e03ad2fc5602a149c33b81bdef9cc9ed1ffbaa8e82fb356f4879c444cb8a7a1543cc8c1c21ac6f408f7f1e6f48b8c716970c21abe4c0ea9eb6d37c6538896b13a4789469c0e111bf20cb29aae64b8477bd61084133894dfa0ad979bc0f90d639ee8798c74e104758d4c2271e9b08b7503847a3d7846e6d34c0d7c8bc7fd3ca407bda5db87a70830ddbb7d8bef66119c63f046cc25818a040a2a2ffff49e7323ff33ca52f1d7aeba158e49108e105bc921acad37ae235ca2104f2651d9a67d8b81650b6b456c2112e99ab38c70a0b2cb703e311342888ce21aa97ba02591b0ce81c81f733e70883fafa236f41776260264e88d4ec72259832a73ec36b6e412b183465d4db618af418e2ce93fdc3d36f0a62758f4657332434f58f4e229b319a00e5fec7dad46e71e75d601ca4efddb659a7e3c5738e730906fa4369c30fff61050a06a3899c9c1b64d8d045cc7883955c46d3562a95dad410028db5ebe7dc739b7354614d97eb104e437bbde623addc071fbf8879cd689a73723277e1134eb46577084dc56e6887bc67e191dcc639ba1c8b6de9d7f5a08d17c4287067482933e75316648817190a7ae730b1bb8541fd6639e9a2e708cb54e87d78f3426fa9cd98f7109c1f8708950129572e4993a72bba79388174b2ece1275640a33e892a6e182d8e77be3daff03dc476d334542a820ee550327171d4c3f369e26403caf98c103a549b4225128d304c5f1d2c7b773c5ef1bd2eac4b1cbebbd0b5e6f97f49b154e61aaf575f84ef63219cd668f0dc18be688272421f6881859559db4db3e83938f11c8fb321051393d17dbd0b7b4e6bf31c0f9223c0bb154404a5dc4f010a1fbe35ab3b925b5c303ea11ff9aee8db6f550baf0efece811f9a9bba530f601e409037af2a380bd6e30ca8d581d3cb7df5b02c7309fddd6a113cbf0699351fc616a3c3144aecab2f6551e5aeb18f4d008c271f23cd27c8afd919adda98824892806c6a714792191d083c121e23cfee917fc2b4dd84e50bb8541b076dd3d6415d05b7c31ff85b841ea6e31536b5fefec6a36d9315185a1a03b8a0eca798d08b5df6ba9aca37502e4b1e87768a284aa56120065669f7f7c0867d4027ed9c87b66e8afd8183eb71a669caa103d369b77bc9989de669a8e0b54516677f8f255d3f817589628e28ce21edae0a25f311b11e41da0dca98d0755546943416e12ed992214ba291ccae3df36e011db25404ec37f45cee071d7c9643d14a176379b1fe31d1b9accab10ec0c555b9c45943c44e95925050b7b77e571c54f96dd89aed7fbfa1e6ee958d6502fd9d820e8ef960d4cad74716cac785c1e7b45780845c065052c45589475b81084426919104757ffad3a2392d086127e171c5ecbac7c3e348ea1bb9d108a310a7c83e2df7d4ae421d66504574be33ebd26c06e4a34ff41ff4de48e58cf824497d6e824417ca3613eb60fc3a8b4fa5a0b2ab3a1517686dc166ebbcfb9ab461ff03aa2ec960687a084a48e75cae9a6044f28ea070bfcb61f8249106737c147fc4efe5442f0f9c80452468b60bfbf04be263bc8311c6e350774cc5ca4c88d981d18d4064fc09b17aaa03b57b7731ec7dd6a5052584eda59ea59e6fc2573119ea04bd3a94d16fbeb1fc924a573e432ff84a96cc80c3ad0aad3dd6a53c2f8e8f34322ac2eb090566216f641432075b5df230329a8c4769b216a69001867f5931897abf78d19fbe8b8849c17b3645faf5761ffe3b841a5ab23ee002c04965423e8c2bf28d60202f014099910560f7135c3202bdb1fa091ba7729c3a3189fb20a5908142dafcc2c92cf5782b3fb10600d1da11f3071489119bbfcf9b262b8003da840efa69712f6fa9a2921ef2532854a244de86e869297e59cd1778da67dfc601b0e7524753f4274a15b70b5376abf96a27e68703a7a39133b035e8cc212134fa1177979f815a9b0329bdc5ac548aefc28cc3bd2ede93edbf6147e00111d6cbabce781c5f486d207c20032fc0273e54fbc2d553fa29a2f4d05e63a8e31232808ed18ba086ad02a501f6b4901747fff09abf5bb74cdb34dff7571294d8f2d147d22f656773bb696e9611e1b6fe808171111bb609165a699b33f2fe86145637b5fbad367864bb338eb77deb1f6b94a19b58e71480502c8281705d69b4601a2d9d61841d9b3b610297fbf292ef21c5ae0ed6c90bb1b6b8bfd60aac495c308ad2d04f4cd29e41a764ada98237381bce5c17fd2da22bc84d31ea861ff49204d50adc4bb70136bec5ba4b89de0f4db03c6d6168bec9008447f492ad0c6e271f6f8a84de624e1862c9a398184ef826be4337d93a163622f0a94bc96215c7db2d07c247dcbd6bdf0f7044a0becfbf856bf253c476019f4f4b4f4090f5796c5172ee209ddc624e5e2af5c1fc4cff4c837e4cad6449b6c270377760a0df4d742be9a45cf02a094b923a2876b7bf0c725e0fa9bc2cdfb504206a14d6d5574558a8625bb29791f7ecf4796051a0fa441129efcd60c8d203030282df1eba4f4eb2de2c36bf48b1670ca2208a846ad16ecb4448cdf01de9dccda13891204dfe495926405793113640fd5e6dd2def4febb6d14c6d7e33ad05c19543bd494651b0186707c18c43b7398bb5fece8bdfb9278c7f0b8a95799d8f60c83246fb85fb7ee869ca5e2db62ef4d59025fd14aea387612629dfe9001a827d135d82b18583a3912d81644d54323fca75985a3809f63fa2732c3b90ac59a5be61bcb08f78cc2c3a1a7ff06c6cc568d29bebcd13036c2652832ecfacacec434cee8c26e76a20fc3820b2cbb90124e11ff2c4e7b2cce2b0189bd522716d7f6ee31948c276951587eb4712de0835bd97eacc0b86523b7c4632a5704f167133327f74fd7e8e5f8740b5f7f478bbbf650358a03ef9ce1d02fba6f440a68796710d0e123e3e13705d2951d4f57ebb5329597a10b877bc189e6101de972cbcf4c1017b94860a5a3d56dd88eb454c31292dd75663550ae664d4ed083700a89db1f32b79f2ebad722edf937338d39b42d6894e72be82c3b093423202fd7a43c9057401567799a4b3583ee5650db3854acce8795d33aed8012ab67739badaf0627be9e02e9fb8f1c3421adb400649b585e3b91a5b423ec5ca44350d34c9b6c2182bda976eef6ca7661ed12fd1992b84cedea470360e61e1e2f506a5944346698e9517c77f29435955e995cb3064905db10d40ce867d44ee7cd302e3bc1b282107cb5c8c9e5c7a5cd9e248f3a2ae03ec16fb03c2d33cd3d0c4a4910f1485f351098f523e6335ae03e59d089d90386000fa2775e78c12040af3c3d20a8fe8ac5f455ed3d06a56df8693af848852ff08a2c1789359cd1419f4040b2bb5e623166629896f02f9dd8c3649e41e4bd04e9317fbb054817039a56d9b90a47d0da571b06074cbfe1ae3c004318a5d06e696b48d3816e4621196fb1382529c955b98bfb5e113df452055a502803bf43423d60bdabdb7982d4f6f370f203d28d468f47b0aeefa0ca4ee82a6f75038821012c413473291dfedd7f6289b2c957dc484d4bae147a873649c8a1043a85170396b64ab83ffcdda733da82ae9e6af4ee3c7e737ce61e3ff181c14912cf655fe8003483991433522a8c03f91a59c04f591497dcc4cc26710a60e99331d56857e9e2765f0a6f31b372bc779a7d6fd0a6170e3e99c06b5003103d45317402ede425bbcda89409dd40641e00ab7930e4e2840e3bb0ed051c17a94139e2c70a9a5fbb8cd018b740302161c4cb58bef807918f20310cf8fae73750a05b52a41c6ccabcd2219e69ea65855591e2d5c534b090c8ba8c49dc89b0dcd7e8970d65c3340fc278d957bd9cf99b6b86059259dfc05a5528a7185dbcbf8231f1ff02346a782301f8d970664394ff08c6f42bc45fc0c399f52e1f6a3cc3de404210b155c2e3b204ce73cdcd63dc3c8a1eb19100a9c331b965cc1efd56b5ea05a33245eba2bc826ca86abe0afad578f6a6f15991362fc4910b5b537ca8cd58ba92af8970c9d0c209f0e923acbffd7145e6fab3ed7b145ac73328637dcd8a921b583b89ddca72245d53ca863e830264c2ca7b8cd2de64aeb0049d9886b9bf5aa0591b2577ce24b2df26179a6ad9997725c94399f1638f8a77af85715bf1ab2391b19c1b2d4f1fb3881534a4c866275a9f02797b55394572c02b3e6f0c700bc9387aaf8ac47bcbcc6968cf919546d0562e15ded546558dc209950e5c4170914792b564eb9fdacdea8f2c210becb476e365d5b2aaa3465d9a395618ca4634f8f15a133ba78ba544942405f798c11995e9bc8e876766619d663d1789709f0eb8a9024f932fa77b57ee5a0cbc3820b7b0a2be4a5bda709c7b10f90683fad7a13b06d468a129dd2d06cf408d89f7add213cf3ec052f5bdcc992f1e00d5bf33feb59bdd834216e757c17a9d7d6879936b8744616a3b2c4db6aba54f69758131e472acb7c3c46dcceecf00d56caff800668c17633db7df8b1d4afdbac049bf3dade79f750e76acdad179bce4089b25d9f281edb4a64b99b77ca1ea7e7c4f367c8dd09141b77b6ab81d3ea7d8dac810907310196cb34d3d1758c8f666600f9511bfd08dc3537cc6151b141177e2ab3b254e1ed8f247b685c650d7e1d646735184d4b610a47f96e574fd8a761e74adfc28a15af52763b74160da84c3aa2b422c4dce4128fa378115ac662144eca1088394e164de93f75552ec11cb23077b3954a937243ec1552535ccae9f88b6c3a3d7f544f953d4d550e3be8252ef036952855469b2a0b1edf644b49222dc4222e1088d05bfcf20bcdb9a40825d889371a0432a01d96b2f89d358b1214a7aa0c9988aa7faa5b9312dfd24e38d751a4646a5282f197149820d3552f0bd3c30706dad2b073dcd738e2ead9525303986b775e5cb4adc434eac19b72b1789e07ddf241e5ec94de3bd5011db7700b7b765937835bdddc368470a09a15f6e8f77a12b278389fd16f58ba73f1b08fbe5222ab4a70b17b2dcd0fddffcd67886f92e06dfd62ca902e7fd6119f0e77b3ac3449052a1f6dc690084a3fcebe25b77af99cadd9de6c03695c36a6d5ace641faa2b26016e0ea3ed305aec20b0cca1e022588a41ea3f0c5969a3674d7dae4d70960ecc701322e643542ba35057535372b5fb3463e0ba229702b55d88c6c5a052eb62bee9a1b1f6af2ac30b049720411d0a4b6ca5fa09825e58fd66654bc28bd3bc7ab3303030acd3ad7e230b34ccf149a24f2bbf409896b84d38cc276025d827897c8eb50cde2a07f02bedde995f81f857bfac4e439f2fa0657cad1dbe4a4af17f24364f8cf9cb8cfe664f2242cb3f2648763fae3e62eed2ed0256f0bd2070ccecce8c2117b1988b0a54a9bb4d86568858b14b990cc768cc0f4b86479285abd7b0cb4f3152fb417751bd2a77ee3eca1d55892b0051e064a67755adbf5f5f7e2cd88de063619c8c3d7a16566a85560e380aeb15e20437b331710de08b25aef74f2e3802ce2c1fb23642b8e3730a98fa46d58c19f35cf07dd67e1b1c10a289407a7c11ca036bb65813eca27e6f89884ea0da62f409564ebe8a6b5c5b3f7c6c0320b962b9d5a8e0d4ddc56efb979202ac792c763183614b9ace2793d0eed25bcee0e927e93cb89956d9ec9f4d544e958893a523ae8f4b747c5945b91186f36e6dfa89ae7f806b515ae4c5ae3fad55bb21a601236d126701b8715bfe0635e23a399d4d194011a65897b8f8422a099514e13bec7364b958ba06c8b15abe9e250ce0b21433756890dba156908343d033fa136ee190a163b436cc9703c691b11927bc1749b3344c4acd1adaf7b423b5482eef64a5bcc97675a92d90bd891de87853e773e295827c273c06e012d0a80d97d71b752e5b170b09be51a370d5db5d89c4938ce1d8fff1c979a4bc037d0d42b86c0c6b305a7649b43b562ed66f166d767850a088293fd804df47a735e514a369260313f7ee00235ff8ea394a91be96c09d72900412d10c0f7e6595814c81623a3d0e76a76023879ec3cd8d468a0298409250f6b066a02927e2146f7a77ec8f39c06f45cc0a7f3f99a61176c93c4e84dd2e8d58367e8157db114631e39a4eeb7891ee23011fa987bca823c6a01b7d937878af909c6ff5139512d09fe42d3c21d1e51949688692101ee4df866a8829b881c846027c536fe4c060345222243d0820451fb6e6a2984bd2f6fa0de083b66824e0a8985c40f9091266b617bab6e07c27a09a1c4147396c9676d0bd21500c8635b200f18d8c1b1e88c1d383ae6901c671af3bef937a3a00b05a89a1502db5bc4c1cf1cea17b9f5b64387f9a8a3ae8a78a99f0da4cbee79434c00789977e6da599acadae7cb8ddc50d3aae8a55f98bab748f1ea23d7f5d64425fb30d30585c7e40216092ad92b205c396337b8669d3025b2a85c06a7365718a01604c74cdbb9dc56f9c5526051840027b1743c33b38bed5a427cde5fb8e898c1f7929d12b9efc1d341298ab35d998197ff4654e6ea7de01d5e5146c9e74ff113c776d5939b2981d4a6080780abd31cabcffd0dd93e0e17737e6f58276d0188a7a3ef075d1789a3ae08b9bc1d10751ff19e5baa9c3b11d580538f99b87507e4087b12ad5def4133dec4b3ee85e9e61a2a4f55b0dd87195077a284ec617101470b887ec825b51d060391c64521304150021220d0208059acea101fad2dda188abf18205e46375d7561d2384ad239049dd25dff4332382366df1620198f1acf61ae7e91cf01655350a0ae27808bc5f9a70d4e025cee8a1a84b8c5c52f685dc61cceaae889b9eadcab3ed984c3ff3885d58e675aa2aa89b390a415f28d80aec6383f8e3baa397a450be55c8b183544216e870a4c0b66c417e346dbf99fa3877c8ae71e3d58bb8cfcfb90af97e11b1a1f831524c1bc32b474e6c6ee748fb1bddcc4f9e1ab0c354c21cf1adfbb0a75044850b545bbef942e8f5180ae0c17588daf09f9c54aa9fa55ab2b8600055117ec8741444e08afca9a541d19152de4fc1b2c3f64b40b3118724152861dfcbb71683402b388f360bb935a860a021630514fd95fba47588ef6f3c3c8711fe8968362193c5f2a75e76c1d63fdf625d2fb3624e00b67ddf9a5184d9501393fbf22f8528d359326e89fd6079a0935fe2937a7266d9952cc426e3cb3961be42b36208682f84f34235166c39e50c82c476f65425437b88c4a1171e9f47764de28e9dd84745d4fc75d5eda811434aaf36e926c3aee5679d58af09d8fd78314a9310671330f2c1ea52b9f2df761e6438d61ada02ecad1ada455c4973c57ec04060e93e4083dd04002d09c53cb3fb9de55ff360479a8434cfbbc26427654a3e57e9e85f6b6dd1fcfb50fbbf95edd6f670706ce18097221b0048975b3463790a2c07eff27b24188c8da125d3a1931559950a5d63c14647dcee043a4f475c94e36d45e60d851166d4e15ee64f13508dd6bec62eefb62da78e5dfb78408cb7076f3546a0d7056a0f2a268755cf35dc3481d8e66555a4708803e7692977d3e19cf41db6edff485afcc23c7046401a802f437fe5fd8ef53616c651ccbfcac29b0ef8b64328f3537201e882a5bdeff5ffc8a2340a421956dd5030f6cc3114e299fe789cadd85a56baff185f9581e106e3353da30bc4a273f1b4c58e066b453b9777525e815e154cc5d3711cb22aa90d79ab4ceb4fc10c71cb723459040e1117e87971bbb4bc0b2057911cad8abe8889b68e1e9e93e1835fc2fd89a343cf05a26aafbefdea52f143958c9ca929a491db3d5a161c73a4f76a128fe98752b93c0855e94b61eba3aea94b2a9d25445601bcd8a83cbaf6fc913233aafd7bb80d94d00c1958c48018b66a85303f4d83bb17dce5a0c3f86b5be390d77dc621b136638b8566397485333f568f49bf29f851a67814b079ccd26bab565969aa6b2c742541406d308e2eed0580660705ed53232541a08f1824c31880caa88a8a2221b0a9ecc05fd52b1bcac05ecfe157b7ec9db1fbaf67096c66d47b4ac121b2f63c0245aef55cadc8a5811c04f5a9ad0e3ea98d9c8e87f2e6e91335b7643b4e04fe3b7d80d0df83fb6fadcf6387df9b3d5e5acadfcdfadba8ee0ad229f257f8126df2a0e60e38f47897ee6e8b55d0bae76cd91288df14ae1b877981c58908ba3dbbe77a963fc9ca629ba81c8f45524f7d597e09aece8f5bf4016be766576cdf50665c9b1af74abe246d38a7d2182476dfc7972ab50b06296f0015113fd35c3aca7fd9565e5e76bcebdaf1921bf1b8e3ddf3534a61ab46386ecf72d3b0816637ac010206e4d92843d0bf52c8725afa7ae3047b7e42a91424e25b9d52db7a3d4cd73e841949eaed6abe886da14601c12ca63763b385fc15e14b0361897cab831578e73be2ad9f6da43323f211cbdfefe4ef33cb4bd69737811c9fdf7136864de70be029683f4b8ad62d0426c2fc69b932e83227a8dd477bfe063d42820972e4a565576f3324d2be1119670458124e88a07b19df4e9ed04130f81ecf7593bffa4c5c7d00325c8bda710cb554b4081040a2ee8817ffa94f93f89e9a3511a48d654a9abc5c7d7bd60fa9b7bf16e6add11618abca062c29d8c3edc21af10c607ada659b4ea3e1a3361c220c4b8fe2b1b382877bde62db14c09fa17962dcf2593b444c704271cc7c18c46e4f332b382ffc11ee370d9c2cc07ac32ce765a3bb9b7e5ec281a25e7d6508ca4259255502570f262f95c0c9cc83c6b63a3967f89a3fa0b8dcc72e4d90c0f3216a712633f5ad3b0ab47376db5acc5e2ba612fb0925fb0ea7835ba257414538e64f67ecc4e113d8d9f4f3922ead2d7bef1e69642f801fd6cf8464463d6628a4c537be9985e8eb9d47ac8d38fa9e15f779e69f60be8ccbed97bf0778a6c6648adf087cd62f93a7b792999b573ef4622c97d33d2185c86d70ea7913156725e99a2f29d8c445cd34b468c60fa768a4f5cc0cb93d9cbee54cb976753b895b8db3be400f2c74360ad857a0225a86fe7780f5a4a531647f1b14840b63229a8d557ec51ad88754dc2db3a56de18b6cc7c2a8b8a30868b4e12bad67dd3ff36a68a6a73a72057244b670b73793548abbcee02c6f680a975692fb96bfde7b5097ec57f7a55fb45feb7f73afd6598b2bde1c97f3f0764edb4d559309bece42facbde9ae8f3e1ce7810bf87f6f42980de8f8ee240216f626ff06917cb6346091f18ee6e65e58055bf22eb481882262c5aeb8aa558d4ac014f2d798b7f4942d1d80b628394fa02b9aa8b4a8823206b0b96eaa1fbf648e4a854ea8261e0d13fd88cdbb8447517178163d4eb3a878e03639f76b64d7d0c91007528285d99234fbe01909c309716357a8c4ecb7dbd7abb3062e48404204572fbdb4b1605762c77b3d91549361138d9ae0104e82ed8f18fb7d11bcf5e65561a52d6be161e52d66e4126af90b8b8e4afa5b9a88f7ee7330f661f2fbaf6a9c8cd6356cd9d23909e358f95961d6b1e4df8dea0fba2c2fa1cda38132af5649be79d626cda65fc3659ae665b188983c60314a222348e4958e552e6840052b0a50c9aa1c3739ba269f5ed94c4384af43a1cbe1d6010996238a0bd50714fcd6c5d05c165184755a52d002b6862f8eda088b2eb4cebdd5ec9c36a53efa12af3c955cb6baea91730ac368d66090644962666a292dd3eabfa62b504343253cd30858b8753267f17a734bfbcfcea7055e9b443d92860cfc29d6339b048fceb6b10eaddc3e0c752b38d5f91cf49f04166e375de07d267c17625ccc2f84042843a8719972eb3017eeabd7a897ae1f0bd1b4324c5f32ea9956bed80cc5199be5ded8a1c45ca7b43de5b53b96370b087f0162b3af12dab1681049107ef6a617d85c215e46af2db2da3e1bbf9e576ed48be4642088b617ba9b78475536f5e874df1a23b789d18b99ab715ff2ac6f12f4dca6fd8c74c604bfc9de35db14865452e2b2693b85acdb2f6e27712b63210cccc4af89500a19543a64bd90e2559d2823d4b1c7753563c9c3e83b71245e105d736655f8adb0f722462a28c323544215d2f14e6d86ebe362fb3cd7699bd4c67cccdf2f38d10448e90e47297227a0a7cc0d7f5020a5f4a345236f248e290cbab77548a7e812d967d8c5d0750315ed2abd84b88ebbcec9654d70b48a35e5773e075ff689fd58d973cc143772e68aa4b472daffc0d178a49492fd49c5f2f4726f18ac49d9c8c0d8a0da908c28d3a356c659a6ac3c5f5e119f244b9dacfb86430418114484a4136a6dff2a8dc0cde3e0871b531bbc647c9fddfd3824832f34d18ec5c888d9ac49ea5eb3295a1e45063c18205230e47013ed8bbc7f0ddb7794ded10b8ad5d88ad0eab61cfeeb854b2c25a4b8862457fded58de78c0873d8cc6ccc09494c346d3670454eed8a68fe36e15d6118a48a3b7a9ddc95cac4ba7c94f4006c52d01c07e6bdd28f75f5daf085158f3b7b634136821e545e1e17e0b8952a68b6277696d7739c279b5937def6d71f43221c3b542348af3f753bd0e68d1f9f9143663aec33ed12ebe42833cbf1c9302d958b0e5335410555cd2b2993bba6a14265fabba40bef42e911209bef4737559ecf56ad21ee61c465903e921b38ae60b407b111cf448487f710b1eb8f5cfca670fa29716db1ccd05a30f2c50dde13a0dcbcbf212f58815c6e4e2b80308abd1c6c1f2725d555140df8a7c55f29a6f213d76f1bb8fcfdafab9eff2feaaec1aceac9cd4147ff20b701aeab54686af40b3822abd2b5c3ceb9a6e0752a1947198ad1da43f9842d8283c46833c7cd6b65668b39648a36b2640a8512e232f3dc81646119c22c6cd4bfbac4f340e62acb10ff0778e7aca57c030d70cf6fbe6d7ca04bcb16c813a4e7fc082e7a548f99092049d2e90602dca3d32a9e8dd1c5f4494c362290b0e0fd5c8e566c2b716917619d95c2c8457906d451a1a9964acab25bee4928749ceab103ad46f135a6d252344f132dded693eb002348745f84b05ec19e83d339a2099dcac302eae487d0248075e53acf6a1dcc30b4520c3060d96feb7e5a5499011935e7a3347db9bd075003c93258830df2ba3d3573025c45e5b5157827096af78aa5054c2c686c80f2dfc5b93a3097d674eb407271687aedd15357af786204c0c887892044691124afac8ef70eeb96a083b32106318ca189c42d3d28afaaa832be768eea68efc1c547066cf581b015d6f22d9c782178881d54c7085825acb6b6a73bfe8d5fc0746f89ea494bb802a0908a8fd0792120ef80ff636a42e8ba0a46816508d4e9dd339128c185a248a425c9e3c4c15026e6dcdc837f089ced4a0960b3cd87344b0e77d0704ce7b09f70fb640676374e5052820040ecf08fe498b96c09b01cbe9078580adfdc29bd09eb87a6b1b022480d75c5ac6370f99c9197f9e325f010d82e080415ad4f2f5cf1b952adb2680594df56615c355ad333a5e00fa3355869370526dd75122aa57a2c861f7abea783b35a078336b640e821e0164c12879e96286bb7ea6f97e53e4913d15ad67ef6631d9d3320569206753bdb20d276f8351cdd07ad5973c298216be156f188f381186b8402a545ee9a435699d309a3369024657f73109a146c4affc0774652ec384e775859478d751d375f1fca058dc8a61f427956a92c0a8fc159c85c7c0bd81c65557051b6142957f5860e36a084b0dfdbbe6dad6197df55ad55cc13bd581cec6f0dd9ef4daf735db05883ed7a399e914140fa41f2b1b8492203016d2ae281f1d97a510a5d46f618d5ecef9dd42e2953d3e3cd3199c1459adb2f214166c418e98b71a83c928ec0a7300a39efe5f9a9bb46a780da8d8a561aa7030ac449a6ff05f18d92c8da063d771760ca7776b0a15b2da2b31841fa9a6d35fb9a5fdc7e725bf9e2cca55d133632bb8d660e8e0748ee67245015a1843bf8cf711f3a52cb194189c4eb6ce760659f3e1c996e0119d3a9a30b74076cc19ba9afa13650d100f766da004752f2a9b76afa2b6e2e6e0ee23cad84bf7cac57ec1eb3a84db84b8d185d3cbd76779a85b7a4249082845a86f345966ee52d6814d91ddb8daa1fae5ba1b457854faaaa349868c097903f8a7f4efea3bdd66600e47031f17c1c7a868cbd20bc0ad9698f4f39165b148e3206eb445afdd6ad09c52eca39acb4e18671483402090d9eb4efd50041e74136ace3660f40a2e6feadfc62a10becc8c29c52af402386a10d5a0e06da445e698d0c4ba557d1225855b9cdf120b5164bc00937eff52b07116adf097e95b4b21cdbf426219870bb16a422cbec04395b0fe68360495745765699d7329661e852c6dad342589cd54d0eb807f6a450f2c31dc6f2c8a081552317dbfa0e32a8e24d0d3b0c1c0d158be389d7ac7cd51d365648fce65cb3f69487871da128288ea794eab5d87aeb3db4610c242114b5532ea2b15abbd63aa1d4db36a2fccd8dee5679f705aeccd89da0dc953421c85ae9231cc69d51f317b0d9c4c56055d6904e64cf1ad1c7164cbe5933c32916914b0188e2ffa0b8934e3d89758b15ce977bfe2572db97bee8b446d6e8fd45960235f267b8eb83e3f0ce68579908bf48f8e0b2ea86f1f49f9e8bbd6795e617042dd301f663ddb3b68c505e49606250b4adbc1a68a0a18391a940164cbc28102b539472bcf1102831df4689dee5809981d911a307e848ca58d07d599b15d03fd4d37d2275e2bb0dcb2373d5ea8a817a24b58a93f1e99161933a24bd96a9b2a9caa7d554bcd9a7899c4af38a03eae509f55bfc4cdaaa7bc1425c6bcf19d7f6700e491146c6a0a12270afcd43d5ff02f56ef09274a37a7eaf9ed00256802d8d62d7e2b6964c6c3dfe5bf3999c111b3f7a460a5a808b93ed6d656061250344647eb05d76b40e0758e2c40cdafdec86a9ef8c8aae2c510b7cf44eb9ba0e5850507ac9b8e924d29c65d0d7b97f1092f026d095da01604bfe27d2aaddcada7e36cf16943225f5f0ec35085c5d9a9502dd8b5e76e356dae14208c895889595ddb9a46030ca60c69a612194ec31a966e5421dfedecc228fe79971e7a787f9342dd28207b88c6137c03ecd3c2fbcea50cef43519bdc9ffa8fc4d79e4a839630234480710d87b50100d22597416e4e4828a18102b9f65b8caf13452ddce41c508bf13399ceb70c870229784935190df1b34163aebde26f0fd51bd9710676fb9f92f238a55d8a982bea674d2713961e1ee86672226febb68f0e4f1ead2fef3f5c236732dbec6aeeeeafd9e1e04490cb8e9c66617d388d52550fd95a24368a35b7cf254d65b9126c1cbd4ace8dd14476717b30459c636904f632bafbc70fb61e1af774be88223b13664cafbf07092d8ff0c8f6422338c6bb4db7402bf5d0aae9b7539d6065c7c7e86789f072148936432d187315080e0a3a6cccc5265792e793c188246ffc24ff23928b5c2036676220d1e426dfc1a0d2ea0d380e8497a34fd3afb6388377dcd33035ed4890ffa8a5b650514779a2a6f3b5938cd6c38d84b36b49d6922ee696882b520298b78b21e526af06921691613dafc203375511cff347bb7add3ac84d36a8842572a41ec41c8c25241fcc870e288e504ded9ab969c4643525f0e96d8b5dd7d7d8d637ab8c046927ce4a1e1eca7525fbd0ec52cd2aad96400e8e6b979ce53d184615e0d6f4d41faa4115b11e6bb35dc01b3df3e765a6c6d2d11e0ee25e34d2947b15e23325494cd86e2cc6349b781b3e870b928dc5988c041b0528f10de04f8bed58303bed17b2ce25953807486cdcc54e691defe45337408b45080b3e1c1fff00e749926989326a1868fdcefb64f7c34385a545b1e77cf06b4a199e71dc35919a7640b2c32c1b2c35c96bee60977e02c3e141a27340731369018e5f1bb10c9836f2317f92ff410c48201c195e9cb13fd4070e6ec56ea3bfd86600fc5b3e4b2c23a513e4c0955b78c6432bca7e8ec8d8518b9bc52f71cedca7a3001c3cada8895e61a2be2aad5098106a3b20da0d246ac47034e1a7980f862f28bddd21d5d572f45adba2a798cffd7ca5b0320bfd32af6d130f17a8d1b14b762ec95b38213de2c5efc088058b17de610bb4a7fc9c9003ad1a156110e7fb174f1d64b41779fa55141ebf245b4597f58ca6dc187baf035f05b1c2fefcf7469d09f6ed94010005d8bc01bb7e5188c1d7527fdfc3f4fbeb1577cfd7b305b7e70a8d9e68820b9378492b5d54cffb949acdf37d261af60f1d2604c175f99b6158d2bba594632a49fb3be159e45c5db318235a793b364bb8b5497b77a4e159fd9c6acaf9c33ce472f22dbedf0ffc83c059680abaf77ca1475012d621c58cde5c78fc0948d54f3217c9cf79ae8b57070e8ffd6c4bd69d912403a6fcf046a90c4a33ddf959b7ef88154171bb3e354a37badfdb88aa1a35d5cb31e2d0f7fb6d257533b631841de10ccb074381f354745fcc2c12579356bf16fd73de21c15467ae4781e4099c0aa2616d75ffd202271c42ee9a975cc8f4a3c9d0c912af7ee9e42f33ac1621b137a136cd12a3a2e71eaba276d9a07a0f3525bc505cc0a63edfff263f9c49c729bb6e9e82304f30e86c9ebbbb00995bd49547135f49991a721aae77bfbfdff834506673ff28367fccfe4278c8a50f7b19b9a2d1952c35baba20cc523da5270296230c27d1fbdd0a5beb1e77ab0c689d55f82763c844f937aeea3e336bba5d48d428b293bc48a1c41bb013c1116e17bf82396f040d05e418921e48c5abd2caf5ec2e471050bda1d0c14b656902b16038a7a680a7267be8aca8d2ca45fd17e5b14ff2284e4900dd770b8d404cc6464a4d15b22724f835ba6af02512b51341f31a25785f2c0587b8d4d5550ac7dc55d4ec3c15d5fa0fe360effb262cf1b487c5d1f96a523f837e4473ad309939b335fae54de8e979c7b1169151b3a830f21e14b3a7aa44171b6be3c1ebf9160fc1e8db3ee9857e5f20b610d6bec5a5df3efb642bbbe02199ea1f432075d856621f0ca1f8a613401279963cd46a5a7968e44e2b42b78e881603b938013270b789ad74d44a277e3b36dbc340336c6f581512a41cfd1196d5b1b896fa6cb27ea30b819d076d7c6f934c67d94d67be6357eaa55020b728d52752650b7a809f2dec77d4ca1223bc60bb5172e34ab566d1a03679aca4b8ea3039877a3e03eeb5eccbab4164e6d4d00cb04cb90c1f66d03b916358d297fcf6153c6be26a75852bda5372487f86775a5b159020110f53273a4a0ff5a0abd2dc8e122699292846f6e965fc5028302029a56da8f24c03aa473f84706b48485aab74d9394aaaa4b865d374fa159cb4ac22a4e57a757d0d023cfa001394c54cdfb8ea80144ea60e999abd097407484ed201799e1a00048cf6ca18fd534ec02239c4d58223b30c46398cb9b8a2a64716ac034fd626da882a15b8dffac7cffff0c22415762297a8d858308e85af1bb57cda415c56839ca3d1abc0a69d39bd8d1cda230f8381454392592005e47c0bc0afe278290c7fedca1ae7c68e139096bf69cf5d70bd3f392ab21676e2206793f7a700075cdb023ad961615c309a15a903692cd16a9a53e663bc734f48f3ca8d11207b23f26d75ae4c6df1d7a841cb2524025bc40a375bab50bb66f503306d1556c1180319dc94eb0086c963c3c347120e149137fdf04dc7f3aae03f9009215bcabda59472cb2465f205e505190622cc0bc691378934d4c2ef9d869df03b0d31d50acb891fe1770ab4b69984d2c5e8a2c6c510d3e5bb0b1b4c19efa2e5a245e322cc0be665edbb68c5608456851fa2221415b0a3153e0f548c4115be025430af7abb3ef3302f9817c6dd65b56aa613b41a701cc7cd6c68fd3f7f4eeb6447beab90fe6cad075c9c331b1be0662d362a6601320a88c14cd898183066f4339bd9e86ac69c9716eebddbddb67befbd35df2e667b3b21d36525ec6e6cc06b17bd9b9bd0e2f0e68eb76ddb70def0dd2cbef6a3dbb518bfd0247793d39a1ce54af34457ab6eadddbc1bb6de7aeb15110e0801b08470203c540fae86c0c52cc65095487984bfade0b873386b20d7fe2b2e7763ce4b35d35a4f3d799fa8ae83baee2f84939be0ffb66dff1dc8eacf1e79f0614ce033bc21f194394d1bd7dc5a3c310d2d113eb8e176608db8e974c7b9ce8c2b5d5d876feebaaeebba10a80b81621c642fabb67c8b8c02134c998b4365e08e236f1cb5e5a90c8d1aabe6180e0e1a79d66a791be17bf78cd1a8e1a819735e3a5747416b9df96577185e374a2765d164dbb66d1305e139fc3e5fd3a5095c7471137e7771633d1c6ceaf6999f7423a70bab05c3d533f3bc1b394fcff33c8f14041e7b85df41ddebe21def48a59ab9dd64fbf5c0ac9dee98b39c22d7759057ba40e64479fd47e3e8f5abaaa70eea2ca17855ac9b20421a376acbd730e39b9944f0f9a0ee37d070baa468cb276159429f4b646fdf0081bc0dba8890d3054475c971dce4266c868722c10bbac7f8d3e676497f1078f0fb8b30bf28124df07b0d776fa18a0915a1c3ebbbf4a18e2272d8ddd301ea2112ed39843aa8bf47a21f0e5edf5d07efd321f481be98928b31610c8dfded140906776f9e9956109eb02e44eb9c909890f356b79a73ced9f3c1454ba33d09926dd654534a6f06612ee38ed339630de2b4d619a439ad3507ca39e70cea405cc660ab66b401f1600da1dafa0e2c24b0b81a0efe4760ee5a8edbbacc5d8bafc55de6b85a0d07eb0a56148a7dfb6ddbc46eedddc27479234aec2479dd8b7772c6e1b5d6ffe79cf37fc17c1a846f83f0291576883151bf02ba053a45f8148a1b5cd3e53b4a11f07dfc899e66d41612ef33e49efc0f55c2c3c1ccaaa14f1c71efdbbe11e7dd77edbebce415ec149633e73846bf7da6661e3e0086b99368df6eff230fd28fc21e8c3d486306854d1a0f28d8410425a051156c0de8992edf6119c36ac61c8e84176edbb67960b67ce758b2f0daaab5d735c30c3332c8c4ec80e3329c0fdaedde568cb6e31acdfcffffff0fc28c728bd9c8c5e805128c69dac497d0e64bbf7deecfe2b8cb040db661b19ac703c991bdf7569231c63c36e79cf26ddb38876d9f799ab1334f606d814d14385128a31edcdbe104dcb00ddbb0d208d8444d315152a0329b0a2b09490fc84226be192204777a09dfe02161bf89bd49044548de24052ae37bf5f214d3e5b19210cf1ebc992eb22176c257827595e4bc48d886398002331e3025304ddb84e527c20763407cb361229e37e10ddbb00de3b81c122d94c4b6fd7fedb694811bf5abb17d312f327e80d9f27df432655bdf425b9a610d1ada12388e76cb53ca6c696756f6834f2190461802122413db9c9903d1b9dca948c28b91cbe8af68b81255f89df3f09ac8072ff94ff8bdd23949387c8acb1d8af639c3ea2595bb0823e4332a64e14cb178c2c54e27fcde9576d7a5aed7127f4d975ce2482040e44784df397f42070af3c4b99119a322fcae4b34454b4176cfa5554eed4f751f529a2bf1558994035f9168e77ad737efbe910ce9973f3e721fbf79d17a51f326dcc15858582cf78514f0fb75f7d67a2fb8523e08e34a660fca587acc53a864594d140db18458422c567091cb42b237cd2220a147f89d3fa132b77fe73ccf654cf80f95d1bd60f5a43f0e648e303e86607c8471d9187e5f29df44f9ec4d3c5c5955f2a68d86b9b4a56ae98619d69c59569f6259d51397c95632162e6391d5d39c93cb26977d5ca76110eecbd1432af71e5461b59f38825599acd631a42f46ce4355331b3758351fe8808a86369f703666cc4449c2c5397bfba4033728555d41b13085f0ab98560863ea69ca30a3fdcc66369ab0332b53029b917b0ebaf70e045faadd99a7395b6ef7b04d52b9dced2786c25d22e5e0edee799ea87d42da74e1f1a0cb2b7dcac26c2ce59548baef2f876da2051ea91eaa155245d8ee434ad3bd696cefd35af6820a38852d79e91e32898fcd7a70aff66ab3b48f2cb8b68f4d436568f8283a25949c077fee9566b146b1fad9322681a924a4284566cb77232d255076c2ef281b85dc377bb557b5529658f621bf480a22545996b396e9d9ea4d532be1d1b5ed4397fa27fc9e2f0ebdc11ee114df7befb513e5652638ad4e9400c295b0aca7ddbfc5ea684da3791e7c2dc3fd8e32cd7ab0f56279bdeba4db439dc4bdf68abf4bee0eea3ae81efa7474bd881cba4febef8ede773ff1de84af5da4ec4df335cf9fe62bb1304a65b9eb5233d13251bbb2ce91e571a270ce44d123a6cc6e221b65b2fd438474c9ee17447751bb6449e6e9aa56b6876597b4ac4f1e5244e552b9542e996bd43df3a459b5e5b7cc7de2de31ea19ab9e74cf5759987565acf2399337d91d3db27ada33273e4bb4cc3544bb260a2b61a408def7de7bbb6ebf6c071e004f25a6914f9441eb9cb7ed48aafc2b32d833ec6e9fd4aeaab6d46eabf6432a10fb846b65423002c9915ceeee8fd9f21d481632e4b6fad6fd454393cd564f4395f0d0dafba025fdc93cc4bf11094659f423754e2610efe37980ba48af5069ba64faf000fac40ff34bec634d7bb711eb47517018a1380ac1880a6125e1b9e34e4665dcc7b94cc6d58c39b48d85ccb251f9c85bcd39e7bcbdbcbd553d6d6f454949f0176d8686ddbf036f630393034ee64f9f79f557e74abac794f1830f204ca889d1ac66d649f8b5e95203a2c70e6d69b41e2b203fb89c73ceddde5478a9542b578e8f1b1e2311568d55a93a6e643bce769c135dbed8721d672fb69cb55be66ece397343840051a9f04b438134eedadebaa6bad944783c69e1ac3a1e20084ecd63af6cc2ddea3411fd64ab746df7eebeb4aba4c991cf07ad4c1381f3ee31b133f504824c6833253a383851543bd13550d78ad0e19170e03dd475a01ea87b24da53ba0f248ad2731075944e3b0a4a4ff972781da5e7e09ff7e580613402a64af14fd47d48bd2d7f46a599bab07a12d5134aef36749db47b4a9f295189b43f120e1ca5eb20ea299f0e501775944f47113980bae8bbaf50e71f0e9f804fc00c5ed9bd9e0d1a54d2215d863ae6035edbfa0b010df59cdaebc1570f6ebab5ca149a095cd4319ed7446d188a29e3d140d7eeeba56bdde7d1741a89ecd3b107f717c4eba28edd9b1d970442dfb19ef44e923bc6ee18bb634cd762f7b577cc9376d596c7bacb9fb881ec1dfb47adfb6adab512f978130724fcbe776cd5feb181d83db4aec576746ca2b45ea27b741259c7cdfe56fab584e27c753d7b66126e47d7746def6f218dfa475c1873e63a67dd65dd09a1a29466bbd5ef35a6642293d5f01961486c5e35e4911b22b6d5b21d673bce868bb7ffb843ae900ca4429173d65dd61d8c8b73f6bd0336eeb55bb6dbb5db9da9b89c951979c957f9a333bbb2cbe4c22e920d04419c07c1bb8589e2029581e2881874d48453618a11139a684d17141f2e5e32e72f69adf568b7db2d7249ceb7ef92300c9102674c8936f6f44548698f3151b8d3befdc9528a4b16a6f360ce76bb39f4be2ef9e06d5d32e70895a1fdbfd7ed9297a432ec2bc67b789646c2de74e44df592ad6ac750044392b496666506eab16ddcd6dcd63713c0000d0a54609a2c17e3f0b5f8086b6dc636631ff08ae30a5bada596d65eabaeb56a4e729d6be8955fd5ee5a6be62427310087b473e10ec54cbfd0ebc15808c83459d28e7608134422fc2e6e3be16ffdc220fc5ec789bafd88f0bbed721efc0e8909be1190d032b830d846f011b477391d12d50832306235dd3b46082b1019d4b11b09edf66db1d0ebf6d744d9adda5a7bbf97a6f5d22c18e29533e776bb39e79c75a7bb5d3b0a10b84855e2cd59d571a6cafd6ef4d2551078be76bbf7b6ea29e6b6ec76637c32c7d58c3977093d6388d3091818181818181818181818184bb52888adb5d66aedb6618ba9b5d65a51100ef3caa220d8878b2e5a3078de24ce2494b3378931a8623c707d043090c090853f755430606f0a2a2b2a2b2a2a2a4434cdd3c1c8dda7bacfd0f5d97531a9eee330f28b175f10bc061a109851c383e10202107e9f3334e665d6d85e4f3689ed91a9642fd5b50d98a933e69c3bd6da99ab9a7787eac705a2dedcd1b46a760fc771938b51d18670f1ae4ea32e66094fc49c708214b70710a31fe10359c57039a666cc795d57fe9991e4abfcd199e5c898c0909064599665599638f375ed5e15b8487b05c175e918f51c2bf021d5a2b3e82d587a8b79f294982f653d3d4b67c1d2c3e3d0f0dcdabd65296215edede65581dfeb62c0edbad3db75d7d386aa3b392ae5d0e1441536a91199c3c24577f1e56891bd097cca05cb8b1625afd5a2933eaf45ea7a8b4eea2f4aa41c00d05f74007cdef8e223759df4792f58f7e1f02917ddc5e7b93e8f7c81c788f5a6ce2b535629aa141fd72bbdb29e46addaf2ca51cb2b47ad11e7a3960a38e9b9caaf878b1e4a1f410e53fa77afac2717fdbbf7f32695bed2e79b563e917ea18bd29652296d172d7a4a890439445129edd2a746643da5a82a574911a5a86a8aaa86768a0ac545a76110175f8e1e522d3eae6cc970cb89ea64e866aa685422c12b882152bc54aa4ad193992076eda8b36029cd14f5f0375bc0b8cec642966449962449be58585890008095b017594f2c3a94858545c952d6d388244bb2244b92245f2c2c2c48f20e60967d507952ebf5210ce1b44774ecccfed8d89d31de846bcf2f84dc7de1f6d9ab1376f0040c58a91e6810228515a4782814fa72d01a68a189540f2c2e48f119c24e4665eeb73bd93633c383df2b95390002a60b7d91828bf6f53c6c30ae52619b20f382cac81dd445eb04fb040cd3eee20ba1d7f90b2a53002ae33b2fc08b0e0ab34bd23d418514e1f7de59a10054a6e3a1323a2bba280cd0c9ecab93bd58256248ec12254230db9364e7d5c9ba249dacf3e996743d21ce43f6655f39c4a269d5808ab8f7ce3be96a45e94b9db32304811376bdebb7bfbce078f0bf7fea05ada921da6de721508976aedbadd4f5ead9704b0de82a950ac7834fa92a04848bb3d6e927764e8493dcf5a02bfc9e79c77d7abbcf69ba32b577b4739d976c09002105c516d42b8939c45d892b890108f1276e38deb4a148c0754c99fb912087b57fcf3151b5571c4eaf01738a907e41407de66d5c8b31a8b66ddbddee0ccb7b28820fcb5bbed7621e587be3bdd096b87f0f81004216313de60e371ea4a6edc17a638757c5187bc0a756518ce8d6f60fec80f2e26207e9abf6a42c6fd0b458dc0f9e12f6ae3b04da215011b5d809706cca82d57e544f74eb765781199bb1df1a07eb877961735e18c2898476cbfbe4ca26cf95fe68b5ba4e57b78e4b5a3d3af7755b3f7899c4ab13fe44cdad05de75fa267a6306f3148369ba54a6062ac3053389f0c728b899bd1a2ed2d5aac5c4a4324b4c9407c513a113e1731b28beb9c3f2fd7185982eb766c816706a36b4166c058bedac62321e9f1d586c494f12586d818135c4bccc2460b05d33e6bc745668fc07a2ffffffffffff2993d5a89133e7a31108bebc4451a33484c2ea76618d7afa140b04790e2aa4c7c80fa91eee1136299ca3f65091eae10029dc59940564d62f12fe0f1112ae6a063e011ded79a79ede4cd49c289b0122e1531606a6cb94b1c094f14170f15bb023dffab19e701f851f6cf4ab7aca1f89e28f44bf9c9ab5a58abc2346efe1d314701b35aae0222d298c2e9927aa048595949694969465040f8205e0eab47f0ca0ddd61269eb7404167fa4cd09efe1df746ac3f6816004b60ef3f23733d89839c529abf12652032c9da1451068c2c686222dbf454b26ff4f3885c1645bfd96b53429549484e88067d8bd332010e133e7bcf3d6b85cbef8ced07218e6c197db73e7ac0db66a6f72b5b54513380de774a121d7c03619899cf39c74ce496b6c9df3b6c13cf8c22fc0819cb73b2fe52f251399ac460e0fca38dec4787060362f24ae9c71cc19e46ddd7119b46ddd71a214f05c5b70d7b207374b65c94f2379b0bed647545486b6e4f6cd4fe4335b64a667b35a33b240ded6dd0be8b3348f6637cd6a9aed6896a3d9ac91681d0d9b76b423796fc691d42cb1bd7a5267d3b8f6cdde74f21048771e0f8174e7691f5aa52d15ede01b8b27df5df534531335c3da7390a0e83c0f4a11bb13fe10ac131e0e9ff2fa9c2190062dcf39c43968340ad7e26bf1e674e63c8ecbdbebf6de9db7bbbd77e7711cc771209047e405071482069df3eac25f28905c968dcac7d533bb75facb99b4042eead5fbd0ac3755fbf3a7dd399f29838589ca3d78d8275be7abefed34d76305e4071059773b167a596be71ce96ac3176128663c9ad4b3efb59071bb8dee0dbdae129060cc7d3826f2a6bcc130432a6406b447379dd0c7919a292a03a232a01af183083f065d7c16883efae49bd30a2b84ff51297c0bfe872aa8781eea04aa848f2681f32fe12807094ce0c995f8bb816fc7a51b7ee0e259cee0500e856c5e201df0f1ce7be9a573ce3c7f6606d7712c9828859fd2fda90ac783b9b6905cff9e73ce20b9e3a0c43a6e07ffa80ac78339566a78c9afc5988f7a06d2dc8787cfe4c40079fd3b38430d345e60264a0c11f8f5077d443e9a976c0f89b4e6a519864a33d4200dca79134de929293637382e22a4e8bb1caeba3c6aa034e194dfb08573ba6c321f4c8f5e0f875c5b362fc8ed229d80c615638cf1fc0ca23c509491188a10d65ec6a2b0c4138ab084b0761115fe12e02b540927a80c6b9f79fa024e598d2aabb29f3299ac06c65c75e4d2a7c1382b1a5cc3813b0e771c29093834c7dbd61d8731c6b8e33a0edf9c5b35237e0cc5b85ab1481d1a978f9b9c96cd6a9571c64478ad19676cb71821e69cf76ed5de7befbd20ef823c22b8484371d42af263a78bf4c8eb84bb95133e06684cc0065b0dad14de56ed566dec65de160d5ebf187ba38d2b480c56ad55a57cd3afb4566c547e56582bab951a95da0a8ff07b9db57639a21d9fa8f84c955285c99b6cf85d853651f5767145a5e224fcdea9942f95f2550ad5a6cb7795b29e4256841f92f1e05fc9c590cc7e5d4e48d6912a2aa54aa952aa941f83859d90f3eb35536bce59a320c1c5598ab98495f7ce57ea01330bb8e15533e6743e1dcd5a1a36639bb1112eda725402a15cb2a38cd1e86863ab35c290d8bc6ac82337446eab853371afe12f32a4f642fe7fcc96e738fead2738d6c2ab805e41bbf0acff61449b34898941a2aa3dce3197866ca381b044ce39efdce9ac77eef4dedad3debd9dd7413980bab7bbee3a6c0df25a50b1f5fe6ab65bce1b0f0c36a366cce1beb38268463ef92a7f7472feff338da679d01d689c8eacdd369f1169ea798161a250464eb84ff84bf809e5878b4fd69fdaa46681cad849a3bd89f480dbb77efb2c32c989dabed5d3eb277e92d1ce1b7912e74de2cbbb3e0bb509edc9e952a41ca2a79584b5f324fdc171fdcd83f926fc3e01bbe57ced7643e0e4fb0ed3e5fb93f9c89b3049921c57338a66a026381a8f19138e86b7bd1a93d2084ec189a259c7623b0610010490314d56a6a5825ca7d1713150cd39412090888344fc085c9c37af21f880881908311a417710ae6eb84035afc0c2147e8881ee6e4ccc9c53773b86f6339bd93882850bafdef4a40ea6f1816f700e6e611b2e6f96dbae6cc83c5d5bc39e1246422094621ee177cc7af0f1ca946f14e15f1e2aa389d56be66f4f0dc289a2fd06f31211fe8fe9f2b78579a8cc9d793cab7af2462bcc59fcc3eedfb10b26aac3e30cc22f274ae3d574c1b8075ed912af6c895732c80082a5528b16a212d3abe496b3076b3499323907b255b6992e4c6c79677736b34ba68c2a669756e2952da70c038159addf356fca78c8c62c2c0403c17865cbbbc33ab13e1dc7711c870344e78548c78109aff04a8fd3c5e686858b8511d70e817608c4030cd0a040056619bb326071977559ae2144a218118b15118b951b9e42516c260abf485710510e6e6cd7690da511f9107591aa4054a389ca158f99ee35c8c8e0a1bc1eea200e059509c544223a321f44f944229148c46285c5d757fab598cbddd65e08c4fbcc77d1919898181414111f3d9daec43e5838ae7d850b63180c06c318634ce610818bba1c59b0b22ccbc7e3e3f1f1f8787c3c3e1ef1bdaa7a370b635cfac088cc818de338da3b8ee30863b1c20b64b67c2fa21acb51bc6385591e52bf82c0454dbe96f894a63b1e09458b83832f7783e3ca19df6f09098136818b57d56779034d43417941595141595149828b5d4c3379d3a673744cc33412fa8897d6d144348eb6d142e81f9aa5575aa5475dd3d576c7d339d1ed4c148877b1942e7656a4744d1e05a5530203429c9aa894ec9a8cad643300000000331600001808068442a16050341caceb900f14000e62785062523a1c89a3c13047610c84418c31ca186010008420406088a66c03d6ffd7ae16ab37ffc335f98e0b5642d2f738caed22a0bc783ca8b5335ff8f7a9afd6ec0b8fd4e91d63d0d9be1e9a323419ef4e3dcd95510a7faf87914c11470a611ffb06d6c6c81a6465ad44e61d573b06cfaade495bfe6f40d19be29ba962f9cc70d0fbb84e27446beda2f6e6aaa4bb9c176dbd325699958e8a3a210fd860c3dd3637528b1e8d865881b18b613b211153bf1bb73118519e8d25eb389da645f6f89d58e5a1173f7ee867a7a91d1ad9fbedab51fd3b2aa815e69b93eb856ac80891c9cded0e49fc623daab269bf34afa7411d7573c85345372ba4106e9e598fc4a76c0b48773ece975f9d8da31034f6dcb1e4f17bbc2a17afcbef5a80c5d1a5f385a14cb71114153115ae6df32f13525baf42be8a5bfde6fd6645986319306cbe4a6557ef929aa98314b1178171eef8f0e05b540eb8e881b7e4318101356da771ec6bcbc336c8a5b30f9a40da7b01079affb78053b42c3f036c5d19661b9fe2564a5c7b0a2050da0ffa2e1de5cd6e6cf36eea3f321278b0e945f36f2bec877fcf51778b7af1571c1b718d4f3bae0735dbecf4b7e28005c99c2edc497eaa9b07ceed62edf6bc29f635d70b0a1ff55e6bbec85e859b802f73a5924bd275298ee7ac6acc034960960d642e87ee21924e2e88cb643e168bde8225935881f31897fb245c1e47a6ad9f72c9eac9b7e6f53c1da24e459e2c21fbe70b5da100eca43b2821485424314abee5b161f00bbee2b9a39d35ba76059ecc669424949b672f2213e9d9bb46a304a29ef03adb4561f6772eac50692bf5e0809260ec84e95d280c7294f41f7bc68a5fece9a58f284914d1b3ea83d7111d15060539cd4dff194aee0e7b155e261679c108728490834a3a302bdc868d2189b964122e18b5030f73a1282ccb1c5714d28bdc4b51c3be04160041aa1f934d755018cf0c1eb0f06904db52a90d258392537313a3cccf459e72ce2125133f845725f2568786364d01a93b726bdd8ae290b735549aaf62ff8b91923481aa484d8e9488c6edae472a7eaf2ed245b413db2beffc60563b967d08cd0e2b64dc328ac27a2056f45c72cc366230a06e477f96ef63e727f699fdb4129bea3bbe04eb82f9d10da432092b22652e796237474c2bcf54931d9354d0c40b897a0eba0c61c02348825e2a107eb3c661a66d935aa64e4542a445e4211ec890d0e071154f659ee1fbb0361c3a2493202bed0a20ef05a78459351bc0be2eee55d1182a39c31b9f7268559610b694b3f71ccdd1fb5084fb36a41b7287a92a897a297a100242db8b1a7c1fba9939fa10626a9852093cecc187c6d11b94c1165f60144ca9ed51c59e7eef7520f38151b39be954b4232978d4c888fdc86294dea7ffce7844e363a22cc8dd3cc2cc6f7b87d7744414a48e365e52e127076a1ea9fe6106e85fcae118113b1fb79c1a3b45ce1d209073ac2f17ba04aa44a81558ae69f7a2416297326d532b1a19555eb00cf8463795dc8c23f125eee67db4ee1c21d80da46795708eefb929a8aff245cb693974d3314ff29cc078138f2d4654982e89f23a62b9a9c8bd7bbe971bc659c98950e4a89c252085abac54cfb69b9f9f88228ee294f172e6708385e116a66e9fc529f9b18931fde303e2d179d406fb3b81123892494788c18852eb87c6bd0ff6a132fbe9c4f7a8f51aec513db795a5d348a192e60c78d4b91cb745b939d639d0683b6f7ff656c91c6ad61a0a38a47778e2977014b88722505ac10aac96e1d1b343a0e2410300ae0db755a007328474884d4acf1ff0f202b3f0c78e2b084336b92c04ab94b18e2dce06269c2061e5e070de4428d8d131f4874a1ce25cb19801de0785f1082247b2c0745ffa7a61aba8723c59bc5e2529d9494b8628f9876d5a496c33e9e96a738880f6198c01c21ec8d0aa9e04d774ce55b801f6123baa7301562d524ec63b27bb9861b303b50db2b745313e78e262692d3a0ee65830dfe93b575b1f4c941a77a65fea14a51633ca37a1dcf7ce6bc3aa14de1f1e633e112b092bcb12b7806271792157022758bd383724e88cf4911e13377b9cc90965a3053c1f1b53baab8d197d531094dd4ee6b2bb4d593e103e576d51bc85edd4ad1803638220667fc988aacfe784714980698a9da44ea3381c5091f9864009ab6064b3b2505af6c7d8467414932866d6d0dd2335e5a68124abf7212062f4888481bfe479826108882da40c653acdb0cec3fa9c82ee0c616ee6d5c5fcf57ef1205cf2de2d0cd1ec67b4def165755928759aa2eddcf39c01860aa08199c9e78f410762e9acfddd4b2cac425c7ce8c26881e4e9f6af739455a92b148429d0b50cb6c17941660fc199f14cb75758b7264b90846cc5114079db10c88a617d06c6768219d71a22ffc7c27647a6df0d59c4822a9f32027eef64d200714f63112139e664ea0bdd011532157c766889029ce1e6f8e2b6c21d1493721a6e2b2868540045e48ae030fdfe66c6094bee92028b608d7eccbc3e6e65c0f9e38dc589c3c59191830834ee0ba4cba0e54143fcd3261c26c4b9d0990da635d8a9b7ab6ce2e315509380154ab395619ac514822e39767fe047498ac5603ccd6965015880c8a4f50816a96aae68e43d672ab8600b44ef8ca71b67fe1b9d2c2c0e941b4b59ba6d520c93e2003313c2528bae39ed3d589f2507fd7f1b27f81fe5c5986054993dde1b6ba8acc0ac0ff19561ab6ae276de03727b9b2035328168e9bbfd0b0dfb02f7d64445ca905ba1648d6d20979a465a7dd85b8d55077d312aa8652eb5eb1cfd5b8ac490c4fc737e370f5cbca72d2d350d8ba790f1dde5cac3167dc8dc420d5b2b0621c126e11d978c143262ef4a9508742838943033b9f56c7ba68c2a19d9a02d56eaf7921ea2a50e34e0e3295372c978638cde13112a1c08897fdd71bc5aab83fcebd1c9e4d47697fcc8082350424ca64b789c1336442234370c335d9751285c614a6c894ce768d350d68720c4261a4d6370d3da85896af4cc8ec34dadb6b41b229654e22283a1e450f55f5abd56e083814e693bff0117c0a0cd289057396ed021eacb17ffa6a9cd76dae7a3842c23b35f18dc1853add828f78a42d72045d1faf4e1dcf0c9b2e40da877c277baf0929442775b36c343baa6ce821bf1aa62329539b6070ec81824872b8b2896db16ec22f7cfc2744a0d5b6b66a49f7eff7454051da7905e65d48ce88c251050844798f36d58ff9bdc81fe62ec1e10a07dd5e17d87e2388e0e0a5632cbe3863f111cdd86a3ed3e4cdedf1d0f387c0a2a778b58bd454f4ff385046f8d2c50e4c9f5998167a4ba17d23ef328024660b75723da253b0d50b9cc8f41a3ec0f27084b46cb24ec14b0e1fbfccc75321262c84d309b01a303170f92356bfda59946992408971e755e741730b33cb2960209e48401b4d1cc95fcf558ca0b81e72339995aae0e1b02f32a91127027b4d17c2a135a8549044685f6d67c1bd3eed385eae1c65ce02f125942445ed3797258fe0bb0da29ee94ef0adba22f8340f6e00ec8cdfc48e8615122240bd00a8a24cbc978d63624105b81dd21d75876bdc0fb4354d09b9053badf4794a161c9a713eadc371ca232da6e96048e27e3bc8a8023dd6a866c465ee436b4d825b31c46c793dbd4701e59192cafce631fbac3a5cd61c4131198a138911e466affc48d19c531ddb2c9cac37dfc2f1f3d8cf4a0d561cbb5e2227d573c06239225b0da1a24d52e5701b926463cca7fc818c0555775e6a8e2e4a78cc1efc2dd4cea8a8ff32fb4f5360de9452083acc915981462b1d9ca18d42688d40c98b178c2a3525735832fb3cec453589874ef032973abd64091e0bdd4dfc8d869cf9ca3bc64b54280336fe2f6d21220980c29569102730aeff2225a30299804ffe34fbaceee1e204e807e77d6c38481491735ccfd268e81ea1b61dbbc4bd6fccda131a0c6ceb224a1a26f6a641d8aa17b01048bf8370519be6e021a54c9f34a2ae595591a0b619c9dab3f64aeba0e688555338ac924759012b61f00f94ae682bc9d9a2d1bdde1d55932448019bef4896f5fd3c210b1276233d1bd580a53ba07f8dfca1026ef06a96c9da20eb195e4c15dd78b8d9b93db1cd78490ad03ccd9d64cd526a858bf559a1a9d31ffb04145ab42b97447d11694ca4887a4fabb3313c2d9f36e3c3220c4ff36aa0277ddf766256f90cdff2686db40e1055f7f797e8bc7dbdce8e66cf781badadc3327c510378a0c3b6a83a6734cf3c2cab0fa26928b2cf336282b847c42a2820a3d7e2525eeaab947c9369dd69c7d6efb675183ac6717565392f74532e0d503f891362185006ec278007285804d48c6bc3682c8f2f869c072180a82792e13abb6429f96ac90af1de4dbc404e1c875e30ca7dc1ac1a5682e18a0877e0e0dbf5863fea31d226a0844a3cf9abf513c24996b42029640d0ac6c289932d168415b79585f078b0ea63420b78c4dc8e1d3f873d5fdf7cfa49e1fc96a7875049b7f0405b9798cfdfa1f12677bd784ec9c23c2309f174674da3e190819188603a48a76eae01346172c714946725d61e19c0cbdf544598ab93a3cbebcb84111f79fbe62dd065475fb6bc2c628fbeedef8fd714a38a2417b1545187e131d5b42e642dd0a7c4a388d72c1146e367932689e86aee750cf45217c256638e194135fb5374120309746c1a6b5120e7bd0634ed5272de40fdc73c2a5faa101b46e3c2579677f41292d397e9ae0df52e2a1aff2381fa1ecb781016fb2b03585916241820e24de56cb52ed21a2bb164347c1cdcdecb2509aa2d37403674586daf45b1ba3f6abac8cbc55fb092bfe23b8b3e471759dad260963faf23bea4b3701bf57632762ec47e892de7b84b927578b58d128245f6515d9f8c86d61d54755890802c23f13cf1ef75addd4ca46986ca1ced9723374928f18731293a26f2b53e1c11fa1eec2528b1f254b0e8a639b44d6af3d12be0e1e0f4ec2e594ec34526b59326065b386bb639579b819f4381aeed3f0ed93565df1b6bf4fab33d3e1ad471e7c0678397a9f341d32040bd133b958acd0b2393693091a9712a453d3434eed24d7359b6136891add8338cb83fb3085ed324b25f109e83f5022cefd32a254282291fd06604537e2dfbf79085aa5370bc0aa319ac280c0f4d288e0a4b75a5561b3383b70fd7826b125c078462aa8b32d9b100e555170be122333e7869938056c36dee3d889f4435569089c1d3d473be55a5c078f56c35c88c414ec92f45bd6995df98d1e1905dcbf5000eae3623e8e6aba9057c684dd11b716f1cb7ffa01de04b48794545b613c2d8020f8a4a8f699e73810d26da4135115b84f2a2e438453257ac99bec00d97da1985248da0fa7948e4251df67479aa6fd7c903fd6e0df16686258b6d340a41eacb22b6bf58254550c67251d9819c28ca7e6946800506d8af5a3abe19ea205614d2ee56f65d39e63e8984ee36c327f084ef467074ef433e7d8d05206452ad1424f9cf5efb3cc768b429a6b519596e604bfa52a4aea17926822de1d310c5dda93f6ccbb2d7268cd1e64322c1c7ebd1ded38dbcbb6e83b2619cdb7c460573fb52c5c4b3afdb0ec2d92d62ceefda9aa00e9fa04f10009fbabb72472f3f7130a1b2926caf6fb64d75bbf6da19232fca0f1a40af3173d4705c7978be41d720b12e1030b2b6ee5d7989ac11239d9d7cd496bf74c47f2ebdbf8555f9224db8954328620074191e4743e62f549e8be2f7f7a7dba09a007ef81cdea24781d69a5b9668c34c105a2a27891b13f26fb118597d28401d370a0a1249c89f03b79f3aba47f352b12ac5584ac14900d9491d8a55b94b81bf1bec02ebe595c0dc6a4384d28321e23d35fcd7ff6f6f3f2d56620588bf9ef13d44647add66b276e9db33fbdad0df179701cbffde15f05b494381375f7577b21969dfe5461a16d12c7616b02021747fe57cb06fc9da36dad8aa2bb276c3620ebf41a1118777b79528b1c32d8e368c7be830dae914f05da1b0f1932070af372a77d4991316d4ca77d60aa13940af4f718a60abb045d2794f3f87e3504ae919c76c09a60eecd8931ed4cc35f6bccc69b21c27e9a6d498e89d4038625a1bd7001aa9d092d359b81f89debea234e1bbf1298275e26fd2ad21e11da7284971b2ff5c01a0d852e030efc9b0981cfe9c0698e9f420447c99a6a2aa0e5e8ab39a820f72740f078547ac0202242ae8b39d74fe4c0407c4e3f168e4e69d7649324ac91cbddcb66a001b8e0a9269b1231b651d4e5e16fdd64136cca297493c268aa7e1982cd8d9a6c18d56f4375c6d7af08921ca5e8b926dbfc55d8734d3633a3822e0356a1c9bb265b79df35ac286ca7cabde89816856e4a751785197153106214f08d2d0217ce37e783986da0e263fbd51ca3031f36d202aba6a021bd265b700b2a55942d53521daa9aea50cc106e0f126a01b68e6a0ced42368bca56d4f5642e72efeb9b27dd6c67acd3b17ad5a34018a6acd3fd006475ba979ed4e4486c4b7aab981008c0e00810d17242496804a8a91059c3246bb34ac4bc3ef5b0acf666844bb96aea5c7e05a6b0b0b23165a8d49d320f6ab57ce50e95097c231ef246b2e59774ebbed1402f692cbf9a61e5d77a955fa9319921043e68a6fd169ffc62087d74935fab00c9932aa418cfe8add2fb4eb6372b2ed86b7d0a0e87d01437709af7965c2a8bded27e2b28f1ab6ffb057312fd105b704bc4fbc3956675ecc945cf0ef741e5cbd1ca494b63fb74a50d493ecc85b509841d37a239cf0c2936c5664f03aaae5c47da3b48c434e10d093c95e4a94782a6a4c614d448144be958f53a1a42e8da8859c7de824b3d8b3e668d11a1bd3392fd86aea64be0eadb8542bc3a52bbeb29d05c1cf60ea2710c9a7d9e6912a73931b8b3164148c4259282102c49e06688820cf9a8830f04de5e5ab61f8632ce33912ae765425859058fab168e96953c92a20356473a3239195874efc5c14ad45a871fde5cd8629ca8d18286e121fd79cd3e0e1c0b25122037024aea309f84d4ec85b4d9cd0c5c919750c0afd87fa29c10c21b60a14c0c6819380878bf8a20ca4c1415a40228a47f092bd110801f31d0c619d2a376a084dac02cf499192e437c29d39fcde476c65dd12ea93fbffff3831b9de16448598bb79e39cca616ea0dc0a6c4845f511c8eb479584310c5e1683f1c38b687749bb23bf872e3f10f6aa16968e89ffa8d996e349b50b40d86c6d590bc2707268621284a75a303522774301849c5e478d909af1af35c8b22232511b928a2f525bb17252246980e90d48792d73fc33d3ceec708bda71d7ca97956392dc99d93be17b1bd8bc87f785b1cb09d15566b0277e6015591a590314d74268afc72f2f1aa2b690a095084a04965b31c5648e21754f525f1b61c2662e1afc0db010e0ef8a57487663e99d86a6b11305cb78c3b78db6376e1582f93ba08f198f455f2808f33969be18ecbd7b45e1528d4753fa514b066d84e8fa0d83cbfe573e3eb4909dd004af78364fb5e66b379bb2a673745b7e076a67f06280370323da170f4a3dbb90c43f3763297914fe22426b8303dccb0ec9ff9d87f6ee17898e5e0e263478f44111bbf78bc7c65a2dc5743c5143214f4e3fbe04e5ee37233eb75b68cf6edf973e1cf26f9c2d28e65ddc8b41dcd3c2d8ece8d8536fa1b8650aeeb881138b96d5f8036db160c3c87a7a352931aa88b13c85399cc8c03ba15291affad2d79120a6b9b9d18fad2fb0e87b06c62268a22b1f34bf9139650512dee86507d08dc3f1593d9aa1008a11d9c1a79a84ebf98c38a8e67444f1d14999a32eb58a3657fa629955dc0bd57806e1b78b1c3b9592790631372cf9a41c63e4702a7dbb40a59ee48a0522164187179165e3122d68d5d8595b10029f67dc5839dfe15e5b93de27af68d46b14266b35ad6b8658cab832d6dea5efce7fd8a3e878336089c31f46712abc0cc5399702b3c10722ee3706a91e92a23322da436e9ccd0af60be08b3eefbdaf50ab2de3085104c5f0253bf18c75721d3c473131b64489f5d2e6a435310fe877c5e278f6b6cefa3ef195f17c3262fa10731ef8f6d5d85d66229210b7e3e39b708b4173ebde148c1d2c6d263e9604c5c1a05a25e0f5bd6b455285fa8c70dcee4079057a15c64aa803461508d255ffd97397700958347818ce07bbf277e8aa0bd32f24245ecd394a6333006698c66e25e40f86ef4e0569114efc0a5107283891b90a667decf2eb935c2b91390513b2a0ed242c34b0ab075e43b750207c957a7d11509ed0139679b6f452a4ec16debc94a228863d184a83f966918b9bcd395f51426c110a1523f37646e33305ed25a812fb8a9a20d145f86f5fff720336e0207803ca61345b94ed282f324dd27610698493d816050c10163721e269f842d107b794636e806799a6e8a9c78980a7768fed54a145f6e9256c691ac114d2c45ab3dbbf30ddee9741821abe6ae6a0d906f305939645698fdad4783fc390035953c818595524b6a4ed19ee2897b1338467508bcb6b81a0468262bb698571c06d1a104da77726515d977504c86c875001cca6f8cb394c82ac1480b03879f591881ab8ea65849662791f9122e0ea626825a8696de4a594ac72b940da366c3bc5488630fd56234faa15d6ce57f13756a6987a63a98e342d5bde3bfbe845eff28bfed58f3528b235c7732026f7aa7b5c717f3e25b98064182866bff501f4d5796b0f2f235a73713d822a3c2048947b010d30f7d2aa40dc57c4cd06d1a8cea90d694a1bec5d0fca3ee54cd78a5c992b03e5370c02c8fc32e99a4f7ae108c58c65a09976b2231062ab9b9c7d45a336aaf69889b96c15e9e6620deaa2b5a08555b58b3862f8eab2464ed822e3832c88e2893740642d6114149adfbbba1d5cfe535a4f05ce1253534f33a74f81f50faa9d130b30441c2e232d7186690a465aa22d50e05e8519c73a7cfc8ae4e362b259176cb6d7a3cf133fb2bd7c5649570c772c7b0b3ae6ce3a8c97097b635dc8f03e5fafba5352c7a6ae0754a86c62404f188eba2a2034b3791e40843be988995f9345978f3b4c44b2f10e11e028baedcf66053272a2f02496c1546446c6156f9d8871a39efd5c2a81fa487f70917ad51b4c659ef7dea315554a809ab6a4e3d0957636cd57496fea8dc1dd144482a60700720a422f6f516f2e190e256c3d7fe4194c302ef29823f2139cb623e70ff84a2c0bb0e4b904cee1c247c43c154a439427070932cb1a91dfd11e3490c570cc7237bb39fd6ca870a3ddb93f559255d84e459eb5f6f40bee22f62ebebe8388d2be3939946785e6d571103b8f2ae243d6ae707e814f1db3f9769e5095a7c328421cf541262e73bb61a061bcf9b2521ac558eab97065d18dcc2c0ccddccb8135fea5fb730e5e1b76db2c8bfa6a72b9e62c5e0897aac33acda84e48220fbf71bc0b53dd0a1c55a7b49f66c5cb9e1b0427eb09e6efb48d77ab2cec0044bcfbcbd11089fae49c9d4bb1d9f25852d3216fd3f26e437fef0ed9365e3adde23c3390f0ca44419dd7b6ff1c0a4f94edc8f889a85cc1d7240e882313ef6fc0b3ef29c1449900c41362e5ea25a01e19a461ff69142b4c72de7e4084653548f2aaad7b8f56b0908c6ff67948735cc7c077b3b8ce6358b48e1fd0416aab6bc59b3d01efb4bd5ad3f661eac3846a5afac1e750f1c96a44ecf480952d92734f274cc80306dc3a36e6c76c5b3af57727a7206a17c1a82697414bfde08eb95b0ed07eaaf73eaa22b631952b6b68cfd655c781bfc287c001dbded128f53845ee34a6c95091efc529160195f8745caff43e857ded195e5b5d3174007a5832baf0e9c328a0a519af13c0c00da3cf86c4727b5eab420d9d3d481f61d5cc09365f2456362370825f98cfe315179ec6fc4796a2464703982fed6d124bb080aa03350a3e24c5145f437c532b14abe12115001dd4bd9d4ceec20c1707850d4025acb6980c1a9a53803db4fbcae13e13927a2e2902090aed8e620c1cc748313e8b23e718ac555f2be3dd86c4036334c8efe73e8c0b79ecfd5ff15621bf7a7294ffbfa981ca76a11df5d781c6b102f8a8c33f16a922d700361e4334314d880dc8e742ee68c7a8ef16c4bc222fc0ce2fb0e8ab2f444a84a483314049565ae4797fe2457bb11c483313e4ac5f72dae8873c5876e2e8059479d910c70261720cc09a44a9b7ffbfc55ec010c4785e3b67080f280f997fd66dd30a9afd6294c262b7d6a10b95eb2a3343e062b3eb1b8b7760be4294472b2168ad49138c0723568a4ac2e823a08d082d9d741725864091a7319088604ab0de0ce78672579eb583a1a59cb487ea045067b5431ffd804bb7e4cc85541330a22ac634e528a0fd2fd14ac623ff528999b794688904c738e504efe2291e0ef349b64aa6d0ca28110883a91bc6ea7af310bd65be49cce4aa96d8c42c0cc1050f2470ed08927794151e744d860effd2ebae0812c8e5cbd3ef5500aaea402fd68607b4ea4f0fe68309b69ef7a66b75b190801b50c823867e7c389d17656a593066bfe083269e0978f4352dfe8b7f6fb2b3c250d9008d901cd14c3181e88af87e9cf776189b81078bc157e878242977ed4b84402d21736a4715622516d988e28f820d392aa07c129907e2f1090673d0a25f5d744fe85868ea0fddbe6c2a5686bce6f4c19dc30d90dfb2ec9e3a038a1c6deef61cd22a2f655b8773d187a4b5121af14035a00489df081ce7d1a3aae029714e95a5b1d9bc44ec7bd45e211f75a58ce0566f49961d4fce0427fa6b180de23608a8bedfc89a167bf50632bfd6a5186ac4fd551cdb074c8722722d776772f840ab88bf9a9be982791123ae753227100de4bb6682b5beb2427ec43aa7d1ad9ed7ba8e6d8acbfca9a73e3fd890fd33099e2ba9cea5bf679d2fe186213cd7a82d091ebb4eb0d3ffaa50a122027015c1481553a93a7e3015029c8123d389b814f614dcc1e7b8b5737ad746e82b2e156943b69052c54c607cc8e15092287a13dd5325a994ed88beb61eb71aa2168e3882c6d7521ad3adb2d906636e38ad1e22733b1362eab4e72c2898a3d0231f5731befd0697645e6bbd275782fbb0b1d81c9aefa01efb4367ae5c1d1b39fd65f106b47d3d6d4879ea90026d17aebda2613722f3fecc0185910103d5c4d79653bba188263937d615c0b508c0eca66dc1f354a9f3536403a875f1b9856823a73bef3197dcd4028f697a88f7bc31bdb84dc74165a2b4555c4d2feec549d73c1bd342c4664042bcad06842a86db9f895bb71ac95be506e4b0c9b990a900f5c5e9f0c4c03cdcc46ed755bcf691fe9c806bc420fb97380c4509d3ecece013e641e50dfb82251853ffcafaa9bb38e3497aaef6963e3aa4704bc65c12b6e2c955910c72d56698e8d0bf3f7b769c21f1689ce832f85963321b12383efd5c8b4b8a93f1cbd8fb7347a859a80ac27abdf05a710a4abeadf0b2ebfa2cfa3b27b55163678f4126eddee808d689792fecbde5164d48f1dcfb2ad736ad861338689b0bae2b2e0c1e5d1031606da77246f0753334177667de63aec199e86483883a1934d5d835925b8f11dc1015b657bf490838e78da163c4060ba62a3c5b21fdc4440edfaef56c905aabdf4a862e22f83df5bd8c050849df6db0c41dc88eff9ee4231ece26f6ff1adbb08a4197289b56203bf2ca30a8fbf38d01d9b5b70435f331844268c8754a388545f93dd1121c9e1efa245bdac4db358c22b9413c90de54b694990f2f23786a6d03042521c3ccc147fa3be6059c7ada049728a14cec7832fa1cfa4ec0780e9900a4aa782a4a07ec54f451377ae037711df04f8ba1905be09eeed2fc1583bb297011f458c5884f5e62dc92408f39c123eb27937de760c31aee60d7602cccecedc0b1c85f84c92e6211fcb45c97b61564c553252e7315eae820887b7e4f18c418a90e2599a0a180f26a13725a05a431e6976589bb09a9f32eca189a366a2a9266a1be686a3c0c386fdd59872e86904fbdb6004176152d2090b6fd49ca44467b28299805966358ad803432809c26ce0d1d4be382ae89ceb4f0ea58d82fc695f2e12a72397b5df37aba50adcc5f901c43fa8ecfd5652e934c02ebd338ac997a6d09664bed7b815c77ce96a342edbc33b0749ef8aac338de890e0dbc3e6d2b7134bfe1b0de9cbba6401a31a3faa612903a5c41f05ce0c300d48ec835dae8a564a5561821ffc56a4e1f56adb7ce9f8f38aff59463fc4989052181148507038726ccf382a8d9bf41e0bd332d7d7c325324f2c06776aad7872988c7db0de5d69ee3ad5a4a90a3ee6ad7a43c7534a73c93a7711b1ed1bd61b5a36a75a6d1fce5a7c1c90d9cd327b336b786cff0c61bddf146b234660db956699ced5f258cb60b7088d34af66610e9daca67e51083c91385f8b1d977065cb7b557f24d05a2859f665e23c25493aa19dee0f5f35f1a9011fae21808b116ddc15145ff1e6b5b7b70d1a19ca149b8c975009fab77e51704a32106cae0782d335188b61d1be98e73cdde16d87db1d819d745cf2cd8b0b2e3268f5aaf4ea2c7438df2a2ff25d93d2257f0960f96b2eeb96ddab1a06c52eacc907a8c5ff29134981b4fca4c1ac851b44d2df0e0bb7ccf390b531020ede3f3bc550d2a80f1b12d407ddce18879b50e950bf14695ffb322e3e3abad72d67613e52deefee0ce025516422ef8f50075182c72b4aa99115f86e1702a5ee42e15298e24849fb0d88bf9b7453f408135610bf200906c3200ad24282a19046253a2d0132d4cae1ca53d9953868cd79f87d07dff9cf3216c17de5c8b1c2f892d1e96b95bb0f7e7dc12709f9957590a5fa6f03dfc47db37744e98914854b1c6ef01132e601bf1d04d6f4d56f8e4360845d3f27424bbb7e75c4d46beada36e0d2b56facd436f0660d5ea6b523f1a0176cac9dcb2f8139ca77fe0031696466a6358d2950591da9dab21a2fee4cc38efa4c4570cd9cfdf4603161d3178cbd07d1e29822d5cf7f89f4902a598350e6e66c0d027d1a2c6c9db9292f827afa1d846adf6fa08f637ab1b70842bc265a4d4b894793e1f0ac7469648bad456fbb631974ce13931e4d08a19d69923a46082d54edd3d8d2455c2f7190d6bd96971f9c412c46153a0d7412b1f35760d4eaf480721e732a408f722b048f07c6b14399141f3492a516e5452d402b66955c8ea827400872dd168ed00a561b82e1fd6491e3558e948063e94f13ab65235db110da197c9a9a6a9ec271fdb8126ebdbe36041bbee664f411425d1b047524d697bc7c970795fa2e2ba8efe5043f77addb1856b2e4621c178696ff4e736ee8aa87592a0747a55cfe574388737d7100a589030391b4d08aa03fb419084bdb50601186cafa924e8ae958dd4b61aaa481a7f73d911c72a481d255d0ba1e1469a6c844f4403c5f7518095522d2ed72b8c3fdc55bc24b907b4da5a87fad5bfe18ab49fcfe362984194124c45cbb68a00bc8d6aae4225d8345865be100a91791b2087e54de7474b7238a83e36781c671a917dd91c81134760475f3c533ae4adeefc20dbf8ed9a54a80048ef2b930c0a634be2f4a81b8cb2e3a0db3b733c9978248f5c16d226039ff9e903a49cff01c4276f8c65589d085a6031b69e30a9144e9c0d8206dc548cb691726fc65deb726574cece81dfd58c30c8bae9d51b178fd164845d583aebf1f12bbab64297a32112ede275df69b78f91687a9ef3299604cf2b3a01a365cb4bcd74193dcfed438cf488d9b90491c33bcd60077126f1f6a5c3b05715baad7f07a1a774bead622251c08f17ee4701926e14227a1d07f25956d2f979934099b2926155d7efb7ce3f0a9ea0e5b386a8dfbb9f7b8407db6d6e8628f3eb135789d3bb375485df72b3e041ae70ae1ee84bee0a721b79466ec4e75d5d640f65d0638d7a144c9e52d6e0d595ce7f8ddf8f84ff15ecf38d9ecb08a1a53038b54cded2b4be81c889bc8bdd930a032a1abe95ee82fe239975376ac7543131978c6ab4e9e81571a876395338234ec4674b482f586162a5be8ad00f92d3f8cd71bd14c51e2a8aa9d177296f19f30c7f0a760a2bb722ee80b3fc8513a5596111a0f0ca389ce53b25ac1a9acb3b572d3fbb70838b5dc9cd87dbb3853072d208ce5700a9a743f673b0812fcb046ccd50f6432cb4d9d04804bddff1f8e9d7e2c9ad43eaec1205c0d685395fb810302a1eb2ed129fd0792b63a4ca97220f8993c05e6a06aa2846790635640fc1b5aa187b14bd382c4d91d64173c5b647089393be9b1e213fb4a020ccbbc2f7c050295c75f82de0896306b4ee33c1a9f1659507580a53580aed1fcbeb8939b80eb8b195008b4791111c65eb6ad0834ad139c8e034dd64c04c43ad81ce94eb80e27f57551bdef62d50a936c9aca2ec720887221c28eede9b268f039a5a319fa68725dc04486d85f90571923883a935fec4a711d703206d50ed76d6e6caf25d1dbacdaee8b1045971e66184227aeb0d197473a44b437779479798a201568606b520f513463a43356eb43a81e52b82c2bb7f7688b529047de4806aba87342e21be9edc5b73c64f7f5eae95da8ee315047010de3993152a55e377f920474656ab0b7180e4a2443f6a65b656ea8882f4ea77f0472b32db3264589e434b791aa99cd5f5e4780a0fe8fbbb24feed7d42e7ba49a1bf6d1e94cde8308826a9031b82d2be9135206125afb85d44b2100954050d9028c1285da359ea4d53ab43490a0121159ddd3d4d3940d632524a6fbf3956620f237f2448532a4018ca370b3f40aa816e10844ce5913f80d155a08c18080d6324086df0903e0784046dd4334980fae58276919ae2b6906250a4f9d07e312531a14d0abb572f4342d6edd418c3e82856c077fa981e7abee2df0301dfd4cd931196ebc68a69ace35d34f5fa0a969a5ca0d36c5449a240aa04c4f99a0ab00e321149f596a18b7df80323a33cbd97112d73f9b9d5960498f96fbd92d648179db6976937287917ac1138585de8c0ff8024269f51ecdec1202c4b93b100eaed543796617b83cc5d6619e0d552c2f2cfcf348fa3c2ea0c547c6f3be2e08d2dfe29fa335e6d2eb9622469c268660a6af17c0cd338b14c37a6ba3de0365f4ac13608b7d22ca4a937e1939e7ed5289d87766a9c6f48e910f0a7dde22a81cd19fe70cc7b8335f87d2ed98a74eee575119fc937d00b1c3056980dbbc26efb4ffff10930121e9d4e006607e92d9ea8cf82aa4edf3184e35be645e7c29dfb28885caa404daabb38c8ecddd26c61544c34944188f63066120cd01c70ad3b3170f0bc0079ecf6a615b0efe0fbd2c1098a4b2a8a3d88930bd5cd395c525fffe069dfc1722e3e7f63b92b8205f47cac3fd6ff5762b8caa3dfc7a6251fcc8e36aa9747d040ef2df0cb44b8dd96ca77d2e4eb071e2c653161de2c5684cab72d156bec59aaa1c315516d2e41c1832eb21067d129a5fb1cab3cbb951f05d0b2b7877315a799a2ccbd3742c5267e1a0b14057b5a2a7ff8a84f06679f08ffe70f91604f2a0272312572ccbf4e5ecc06e5ed4243962ed6a37ef0987bf0a59021156faa06464085a213f2f3e1fe0fc418257419918154b0a047e31b8bfe8f09cf61f2cc8bd9c143ce82430779963bde423dab1fbab10a9dfc05c0747ae671832bb96626c194e4c632acbcb2bd476dad822c55a02285c0006752675c0acfa6821bb3b208ea29073a60c975a9a9c1994eda4b0009938157184aee24205c3789f90d2ad9b306a08948d260a81469478a182cb184d426a4f0ffb6819e1bfbf71b88bdf049b423739411049e23b4ef9f4030c0a2a139e61121270b9671d1c56765fb74c94f300f91556429c640c1f29af0c363e7a309db79e272a3c6f14c75151c5c02adee39d2aa70cc03ce7ad746fb3a5bd00a86d7a0b7ae8122a542550ee006a2c776a0dad40f8d8eb8acaf285762319012604a61a26ec0321d1362634b3374a31adc5163676a0e85cbe91d8af663a68dfc7b0352dad2244f9f5837e4b27ee6a9764ab94228d9090b1003f837c012559edb9d8316ef4a6b5cdf9c230d43f2d057ff2e4c49336a6b026d8bf5b16f794751d30bcca622cbe6ee90b541afaa6c680ede7b63a068621162c6b6c22bcb16087a3801d4320428a6c917d79a92fb1eedeaca9345a1abd63c5d2101eb87c27c5019ddc57508108da3458c8bd748464b81a90ebe5c0023a0c085645aea88262a50c7520350ff9b1d8ccc442d814a4dce6fdd9458ac56ec5297762b76b6c58daa2cb427b8c0b79e5b696242cbac36f7c07c77419df26f83fb5c114374946d7797fc95c3cc1baa8ba0906819b8e538f32764f6032ba09261929d029d3d2763ae9f68c83edd50ccf0c4cca830ff2137b0b53c4280c16e7d98f48cc4d1ce9c2cd996a9fd3be7e262075fb5f021cbc8db4ba342134de8fe5028980b5075ac4958195bf95236e3124eeea9ab7738e93f2d68a6aebaeba78b943b1594f9d6f357f1683d32c0ddb0f51680bf5240638cd728f589db4ff0ca314219fb00509917d37075a3e076b7d133c03399839351c1c1c75a8840521c5fc04ee62281882304e0d58c88b7c205dd817abac678825bd7fdd62a3a2684532695ddbe8a5344802d308f344ed5e090c09de5c3930a6cd1cd014f8cc4ee78e9dd23fbe9d11ac2d49c7aeb1a758f38e8e0ebe1844d79abb73c03e876a2d31a2eef1a62c9c2779028a21a7178d2a85fa3623429187534dda35fd89630ee559d1f2bf8b5bde64a23292c65c3b53794582d6394b8342f93fd88934600456a127ce2ce2efd8b6fda8568059343c4e0ad60173a5617196130b89741a0f50311a6dc158e1915bf60e213d24deeec95572ac72b9317e7c12ec01e30a8b9969b2cc5c2491e314b42e5ce3783dce7792a0e1e875b9cd5398d00e44a0c7611e7c25c49bdb5c54665a1793c9d2365ef9e547c503a38347eb59647a7bcfbe8d55af84a38e065cb90d82be2899cdac68c752e2f859efe17afde6c7c20cff6884cb62f08a63cdffc1fd61043444f0fe70a7c00287e638b9327463869dcce083b66384365acb621831ead9753759895241deae9f67948df50082ee02097d4aeb7a1eb790178e2cf98fc33a6c8bba1a9acd16a63155b219d8a6a7c11d613879fded8e73d4d29d80035b91f9503ce17702d9cd77ba1abfef941684abdce170bcf50e545a8c1e325de55e98b15d946f53602c72087a4dc6ccc187ae0afa97c9f4e8d370cfbbdd4bee0402b4a05e2308228a5d2446f24c5a4a7a1699ebc09a2ef8d26ace1f87db139b00311b7c98e3347f3f7f17db0ff64f01f79cb0df4cbc48a69c19802678d0fea7af7a292a1284d2792b8a6032630dfb0c163608398f8267d39dd2824d23449c930089ca939cc2083db71b21f3fb1f33341a6d3583452b91b9e92a08d9acdcd3e996704b2a5f2a1271c05d64de7ceb78fb57ac061732b488095564ca64490fafc2bcaf68e2f49296ca3d1abde1061ea7112ad1cbfc4535e6f69d162735d7358b8745a9d0e5dd666491396184fe85cc4998f1cd903c4156a8dac0d19dc9c30ae8e9d429a61b1d1b4ce1364ffbc8786a672af24d80b72ed363d23782dcd0a6ae6987b32ade920ca976947437ced29caa7c6f0d63d74bc39d801348e221d3951229fc56c79069aacddd370e8738eb17607cb6f03cc474b49c0ab7079837e81c329e44b41865eaecf21a6eae9b261cf15aa0572c4f2683bc0fa0212d2979e8b9acee9ef22d6dcebdc3a09e78d82becda90418eaa707069b726256e164fba4a4a4b48d30c81f3953efa0ecbf7fd81dafc5094cecfd1aef8aa922fbb6a16c896fd15a1ee3bc0e31209036fc9c36e1bd2891e75001a76b4022d3bccf8c4b4c4523fa1d1f133022ed60d4ca37102ad848dceea9d5634c2353e4e3eb19aff13c2d63fd93579708030c0fa2922d08a03026328d4c559c1041a44cb334a3490a8f32b4474a129ab30b987cced8bfd32319e258012baede06234ac8bf5a206e9efff4372990133acff1940942da26eddbe4591696b3c3dce18df8d50ec0f5b4d35f96067cc225aaef84c49fb443b6b9067d390bb6f7d8275eddbc6092ac93983276c8f328a55530c14e371de6ba72cbde4cbcbfde35a07950f8fcd770ba4d805e4d3127a63ec193114668cb0c91c1bc5bec72c1860b34255780c66415627f4ae980c3784c8d13dc54bd6e2b2b76a1ce84d3132301b676af4275b3246ccd43895e8215fa756e1640a4aa3970cc54d404e391df4c0df7a1007cde18d5f9abbfd9a3aecb307e408317fee1f90d507f2151464ee3371717305e90fbfabc9b3a764c527a80d0c2435306a5916fa070dce34d9931bb27aa78888a2c2823ee59451909dc8b7e4305b8b2b78ec705667b07a3a9a7a2b136ce41b7e8354b74af61be25c4300a1854aad0e2163f603d1d8ed81d3ce7c277b6db832d236224868fb0fe670013bdf62b23b331bc2bc7731ce0aaa4454e3c9eafee87ff8a98add86913ea16080e37b98262fee06e91c8065830224ac0e9c4985c49060f1fa87a1653c34e52436c09ea54560534611a2e61339dec82b410543cd2ca386d0f5705164aafddcf765e2912c0bbbea40cd27e2e76331387d1fe7fa2c73961ca5b7bc70d4cae4c43de7429d5fd19f4751c875967fcc26a078e69a0f5f21a64a67993e0166b3ec9a9f7989edb7c2974a21536c6903301481bad1b032efc7b786da4aa21cd678796a3676bc92f5e4404bc43ff73b40cae8f278cc5d6c849688b67c6488a6910398df11aa80083b46c4587ab977b2ee8299d170529f5cd253af904267b5539383c35551d88e06e0123d335a691f1baa6d53641ac5868b665d38d230eb39f89d40abf306a07bbe2ec74346f817458106cf8e593c0cd3a9d1e6d7a681e67a6b74faccbb749de2e4b3ea439bf0d67a7252fc79ee9c7b6b1d6b91dd438bec690b2ec9b7e879274cc0c585478d18938bb48569296e62cbc55ab7b7e4c961e68a869ba62a0da38d6ac2843c40be15d0475f17233e44fac319a7832a16de387d8efcc548cf07a704012b826ac2dbddc43108666de60f935b5836f9dce1d118a3f52322c4ec111578db5f8319d671a1297b607f10176f16f9d2e7655d6e217aa83b401ce4a1e2206b38124f1c4686d3f9e07693c054aa79644cbfc3283e516b2faea1e56e4e10d7d57aebf0768af421959d7664066a9ebab0f1b89fbf0ed4b0bc8e8565ccab056df84b9332747d5ab2a1c62fc467d3473f0a52da451b64f2385bb66199e2a8dc00280fd4c7cb956d9ff36facbe374ab76812691054d268a0e12813d3676f5ccb2217c49592654951a1631433492fe4064350d2425022a949bb5ce5f97ced883ce63e46185329fcc886d9c85da35bd0792558487095211e3ff4e1b4a0b3bc05501dc9bbe4114a4480a457da012ef69fcfc381473f56a50d0f9589644eacce6352a0c3d3edf3400f0a1129aed098a2a66078451f7cfda869abfa72f4800196a75a8a8cbd5b5b270b008d1840d5f5bd152dc92432f2892d3840cf134e8bbe64b819d6c3dee11423ff68a05506d707b215176d8ce8cf1c6920e4837f7a814ab523703e3510b37089eaa764b443e769d58dfb9e92fa27314f492fb6328b1b5de241c531906c64410e75031f304744bf7bb75e91f782bc00f11edbc22dd06cea927e11da89770eb7e98c6a65b5726b2c7c50902336d8675e65e4ac2613a3d5924b102601e3e32a9d24b8c4ea00e6f46eceb50fef3d204d253f35a3c5d9a40e854c8f4c3ea7bbabb9d388f397acf26ece5243627a4315d9019b35832528591bf2b29f5f4dd250785d52da6059e64e127590fd68739104c5cc227e065abc3b09f3c26071516fe64d81d8d78ea9e5844b2b2e1df198062be120ed26ba39506bcb406b4103855a0e483bda8ae858123e6eb76cea6213cf6f2b2de49b24cf32cb5f4452dc79eaa48c2874192927d52cedabc2a54f373187cb35cc3d8960d289a7c4afea636edd9dfa904138e522d7fc3e490b3406f8074b9f85b455404462712704d7bc1ccc678bba1bab425612663ba4060441703863e5c6841dfb8ea653b76c4fb73b20778e726f9f7293cc1bd27a7e216e7fc03b2779050952331a99377f42b163e1fdc44fff845d62ecd47f2c39130f4bfdb72cebd948b05c168817de28fa8fe46165df1166522c8007a6ad72a95c6e8be6f619118f4c6b874d0ee3d1c006930da934697f11c6f3c9accb00fec80511eb5038a0507c0e954cb2f53d3b1d9cc9d42b7896e8b194a765d1a3d7bd67fd637dc49c50c860379dd322d750e409eadb82470664062faef63fd993f2c3cc948b1951b81e39b8e4e6cfcff8ef6bb0c0a24087f749f118bf0a83033893a10a7c348f819e684db23f43085800a7bb2181f18555e26b2bfc65993f55f69afc457a87a4bc9f9cfca85b37e0800b0b33983798b5c9410c0b44f6eb720a86695e0bc7e035ecba9347646b05b67dbd8559e9b90d0d0b04fc047d4d2f81af9dc0852b1d0ec1e9fa1106f932fb40f3535c9126432561ce5a134280aeb01ef7eb7ce7e300cc6cb7f4681ff6a425495100b4d989ca2a5350df1bf78256d571925ec7fdbd31a5a9279b2e7604ab5625091b5c72d2f7116d54d81f9ef5a6ab67ea891b39478f086eee6af5a0fa51d5688ad1063d739c149817bba1eb5af3ec6d541040366df555d16d9a1191c9689adef50f7dd6ed61eb5c5320946386d8ec43d2f4211a63f60950ac544f86a140bdaea384b6bb0a84729548ecec2b30ba2b7c1e58a6e69985373f3403b13586099a61c361409d0c8973b2e77f0ac3432d29f93b40db701d5a418a3fd4e5139f1ddc5bac72c3286a1e491b14702035433535bddde623ecdc0bcbcc095e82d43c6d1f4f4fabd71f31f3f57af7a0ed40c2c26b8de036f402c89c353989266aa44693dd9f3ac1e55febe405ba1eea7d7e66b9891aba3baa93e7e86b49295deca8c35f7e2ae21e50cf345ef322b08ec098b98a8e3de2d56f35bda8e61dadcdecdd70067105becd685cbb94658f302c12cb43278718952d245aa6226073c9a189889b6ddc7c372baedb298f08f3f3c25365986be05bd66fedab19f6ffb004c62c61258f08c2a6d7540646456db177aa05f1eabc68becf1a250ddce8f0d9f7614226e32e6a8b345248279f407b6f29f6a014744bdebee09a0a340464110569c36730abe1b7d7ffe2320424b1b8fa3a5e1521ba3effa008ba0a119ec007678357dd40e11531c7d55e78899be66fe1e1c7e0c37a30e7e6b100cfc70aef722617a82a29afe5aa03425565119df9e59f01c8b7fca39511cb10cc739a01a0d9776cd2612511c88e7d61267e8c71cd9276fd1a546102f1322c7cfa75501f9b0d46982ff1b6a3414f40725474cd8cc89498d049ea6f4e4b11f1ec62fa27eceb79d0ab9464bb0fc46c0660ddf3c19299aaf4039aa5c7d56780de3c411ee765c0168aa00ee2f5f92049038e0d93a7c53bf69e3f248bbe0982c61fec927041ec71597cde3a6d1dc9dc97b860e5f28e0f1ad8a233ea2329030e81b7f8d0f74299c80bab7730dc262b54ebb3c7e775adf3b4e27eeea6353f2f2c9a9e70f57f734d66689376f6baf040ee407d3024053409ce2abb827e798076251d1d72eda8f781653e9b5be618296c5b7ca6aacb38c50b11bed0fb891ae8476f7f8e96ea12376d9ff0ad6b03a381176b2b5bbce7898475551dedac931fc3ff63ceec567ec6c500ed80fe4b9214cef61fa9ce431c46b6c1fa77b7cb39d68732f0ea59faa5b3b210dd1cb6a05129fd07639a8f45440b029b056aafeb5f6abf75a9dd0820c7b169a55b63959d028763d699a6e9d8bbf3641374c1099972548bd7bc4960a32b1db6b154aaea0cc9638fc9e779a94a35583e14495814c3aeaa6cfd72f233fea7904ece4f6e4aba4ee3029f546b08ff05dafe4db7c774a3f844a28e61ef34d2370ea18b5752812e2fec2bba8303687cace6e240e27713f7b1e118185c66f384f7a3f7468a42e580d394bb9972747db4c4a85da690c06d1e39eaee043ba1dc0bf8d5505c9ed3ab08fd998f2ae06814973075785f9c371aededa3c12905f7a1adf2732f3c947e766f7b4e3e8d71a771d5a3bd20a228b2a3f5e03fbc48764e97b15895bbbbb9e6859ae8ec3e25297b78d9ac2d9a5a5bb97cab8dbad7321937e78834b71ff597b8e62f383140681ae4999e401d7383fe3778df708396352d2ceb22a52e5b3849ee42d55ed8cf3c4cf341a20a169978f3286b1720e94f6dff9109756791dca1407e1b95c37a26c2c14ce302e4f2b3139cb1513929be336a559e4efc0eb06e8bac991b71968d4c8f8ec5966e3153544ff1c8197a7e9a0ab5278e914840568feb8ec56c2790e106266c7da87f4bda31a71e6d9e04e3da051e1e55cf5e368fe770255ab976d44e65d27a2c8f65073d1bb36513bf237e587a47e330519c77c93caa360f33577cfd48e8e28c740b9ac445038bd4de8678a10eaea4f3ccab707373b494ca675af299b6f08d7cc40f1974c4084aa050eea4241e150a43535c30cb342bca1dcda02b43f85a79b35d2117f149843cb1b0ddd809c9684e0750a77a67a647a3350c018ebbc06f2b097880b2b446b0491790c562ec6800f91de0bcee536221dddc422f97979d16c78e0b230f0c117ad74b365689053a6a65505d791ded8cf0333c159b81397cedd457e5da7a707e1592a44341ecc8e2a990a9fc5b5bd7aeb3e79a139920290a7cbf2d25ce11697a72ce3dafb4c5e8a3775cd99e9052d856351f3d843ef5d0380b9acecfc6ff92a54ca7b19fe9252eacec2671ce376e4761a4ec5e58827cba4786df963da71434fd37ddc0778768ec1595341053eaab3e1fab9864b6b211458e7130e181f0406fe8c6e12257a0ca09c3c31f507860852b5d10f81f85e622d26a9bfeaa54b52551c1ac4d9a4dcf4b63b7f6285b7be91a22082f045ef9ddbdc155091c29564dfea111fc4c5cfe81cf3a027365e5ffe85ae8f92e7de1270ffbd4088abf1314c74c2abb0a2affd4b25cb3aa0652c74cd05c622c4bab665888087907f68b0a99850a36062dbee98a831730a8553f85f5790a91d12998569f5eae4f9f019082cdde3e6d7b0266ebc798a6e7df5b86100a9582a9f1f87b1352a870ab9516c87a89f96aba42b17a7a88b4a826250c4506d51f4383aaeea101bcc4bc3f8d916ea3b066c7ec61128d928c148d58ffb028722bbdaf854a7d5cbb4474a8a62cb4b851ccc274c04157864c0cbdb8437eb78049b13eaf6dfacdd816d4090ca618d921386af3534feabe97e1a6466a02b998028b63c50eb322c166055e748503accc11338109793197305ba5481f03fc9a52ac4aae8dd0a195691e23880ae992cff1dc1e4cbaee1004bbaea5c8a81f21d1054f9115b4c4806d81ec1a548d5f375314288753c35e50da67b855154b970c1038fb297a9d8ddb7b6c04a580a2b3adaf912b8aff9868dc360303f8585ad4bcda78b31235801148bb46ade5bc96a8d746346840801635e1c1c6484872c581a98b43988bd4ff475318dcf9a6c306bf8c789e6e1a3bf55e965f4960b57fb7306a211705baa7ca3c0124161ad2942bcd6d4fdd8a8f1608096cb80d3a378e5814fc4e40d59fb87358d99ffbe01271042a0b0d8a41d543c8ac7aaa846e7bbdc74b4d77014339e033eb64bfad28b5cbff2d8e32057e9d687e7b83a4fb151278bf87c97ea0eb72891d324849e43a8cb78eaf31a92c77a649d534795a6948e2f357e2c4a11e90192497d206421a2c75a9a7fc20e282344da39a7d4c0da392d95e394b89a0052bbc136bf86531658d78464da3f695d13d329e298c0d2b4db22983f7b1bf3d41eddd089e8e45ecf282344f708b6ea5b9298d1fd2c1f907e71c9817a1278f2a4d83bc2bdc388c91bb64d0baa1bcb2d44c34e82d743ed2dda345489f366f340f71e7aa61e0831907e9cb65ab303432f79c4815a413de97f63a3d31870d0df3a4827b47ab5a0690a2f901a858d57fac65ce3eaa314b6fcbb83e4ee8d88c00dd7eabd77e233e66a330c3daad1537b7974b4e780e208e3778e1ded45bb1871aab49c7e4d5bf3ed2afeb72e51fc732fe81503795c5f99d4ca65cba80dcd7586f90f32735f1f10887e2a3f6d5b2020dc26c8d293f6a8f01188912392cbf6a8816109ac3e75b467a9314052bb6e28a678e519a96370e2bb215725e5652319780b128c21c8111e9ca0e4119700d63c948cd3a05c119c64c0114ff03ea3457a25a3092324a8b0134ae13e1fb72561459a6accf8ae8f1105e11b721075c95808ee17528429008046fa1812fe0ce18617c993a2ee67a87c7345e630c16308697956e7cc491e900f29ada44fed62ffaadb5269288904d441289ecee1d0d0a3d09e10a9bead2d67530a9948ed11f0ceaa4bf54d6dfb76ddbf4d7b332795fcfcac8de6666beb76fba63d31d7b4bed2dff444d265df2366a644557db6664d373ab4dbf6ddbd6b3ea59adaa0f900f91910d6fb30274d0e265a5001db4f000060535db2dd18ed2efb42bc7e9af473bce845802777baca6c359aa1d7719ee547fa7cd6ddbed396d56439df229758b3ad519e7c7c0dce6d376ee18d59d6a5b0b236c11f86cedf56a7a3bfdb4fc2e6fbfdb6b8d18857aaa551de7a9ba6be7b6add3bfdfb84db59b394ef79cf6cdbf9a27bfd33c58f37a4e9bee39ed8c710a150373429d4edbb95feeb4719c76bf9d3b6d57e36cce1a11130bc9b676cecb5ef2be9e5d3299aec9fb4edc6947d761ed329fa64e7f399bea4dfaeb396997d3b843cc719ddebcafc76453faf2deb6edf532a6d2653cbb795ffef5ce6b21ee92a679386e9b6ed25fcf69739db6bd7ada4b5fd63d278de3ae71dbabf7f5ecfacd2381289ff3beb839ee1aa7914094edfe7a4e5fcf091f47668f80919e0d6f332c83091db4e839ed1662194ce830839a521077e29fbc0fc93e954e4f6929733aeb0fc9a6fae3be1d67defb9c5ffae52a9ff34e3cf891e67c8825e043697e29cb15d69fcfc687270fee2d1e1e7b9f8f840cc8b04808caa6d7e0d8f430f5d2dbf9f1c09cbeea4fe650a2a05ddac49c764f9dea0f75285754c3f0e4dfea5930c473686cee31616c7aed3bf7140be15ef51782bc5b5041995540e0c65a753a4fe9f8278d5fa2c799d5c3bfde579a40f7d3277ebee5d120a623d9a5478c423ed5aad355a7e37325d5490381f7a7fbd3091f7b1f12fa957e0189bbfbea4d9a842632be90ee58f3743f699e9873c791252f09dd9c4e4277a7694c9078ee11efc46828a393ccadbd9ed35f4a53944e3237cc2bcccdbfd9e33c2a5739736097e6865808dd14850fff4b32378cfe96584dc33eb2532173534ed3244f32f3e7b32337a5f8945e1341e56a36b9cfae05ee641b3f7bd9b9897d64bfa55369435fba953d74bcf45bf2bebceb04ba97b667933475f55d3d7dd5e7be791a3e8edcaec3536de7a12f7dd3f4a5534df549e7ec7163cd93fdee64f73893cb87bf28601b3ff3f221ce8721c6261916e520c5becf25cd79d5fb90a8be1dca1e3a5eaff2a0a439e9cf6e8ebb0e0f6796bc16e28679f53ed42fac797290b89381c464af5ee91dcc4d5ce9f5a5d7671acad5e9f8311e4f4953b93ac157bd9df34c87f1bae34c93f7a1b4bdde778f2fc414805b75faf6d331f79297bd0fc9ce3f79dcebb9d79bf0378f87a33bff28bd2b7970675f12da791f937d55dc79eaf3394d025156edd4e773cf9aca553dd650aeb84d7f4cf63dd40ee3ce3e9f7d7576fa0df98e7c48363cb4d2065e8b5a34fefcfc8400c94e3237de41edf81869f2a156ebb2744e7b599526511f7ab0e1445207f9fa0448afe0ec5189264dbccd71841176ec42347b7066409af834768c41d8f1f1403b725ed2b8f69721d52e301b13c955fc8ea10c238439687ee1e69c538321c41bdc4f05aa3f3bca53a26fbef04938241b120d29c3903f93e6079640230cf1fa9934f1f6b3a9efd7cf8ebff445b4e3efa6040c3be217768c55d01002da86605d3fb387b645d2c487014446101a3b4636768c55763cda5ff643f403b5a7d68ee42a5e87930c4fbd09e7f6f99cfbb98034a41d2da2c842dc449047006ac8f09f45a445273e74ce39a9e74686fff28e70d3b8c4858fd267df49b5fa43e529d0feeacf8e3f186a8e0cffd51f4ae98face1c2c319b8279487704eaf8d0c1f6f9057fe723a57054cdfdc4c9aa8834ffbbbb991dbc43a9c2a05ecf62ac09c2631581dc3a5e17d36c53a79d7182bd6e9525bac1ae48f6e5317f9b33aa7cda980c02daf03b7d43edb72c911ebc48deda9b1283168b36d1e47cacfebc8b8abfe46b0a986aa9d6cc72df537820d290dee8f38477d8c52d6cf3927a594ead45d5f6badb5621d6b4bcfb22ccbb2763d25a24448483a05837c9ad7a97a6aa9553bf3f23a53d71fedb371a40f8d9712576054ab88d4a8c5942772ea7d72326a9d661eb44112246d187d707e6a37f29753f3a9554d0ab2460507f983463713670531e80651aa00f2217f46f638499a7848638c29d041d472642e8adca920c37751f20e976635f35444323869a8a7b2f7c9819a56fdb0ae2a32afaa88ccbe24d24aebf5115bbd23b3eb2d4fb593daf5a98d2379b0577bcbfb92c88d69d54eb5ba05b979acc3221c9052dbf260110e3f1b496a6769452aef7ac94feb754ef929cf33eb65c913151d1caa229ed4c5914d91c1c8ca289de040c86270393237361bb20db42e3dc8de507d2103e58b19468eb7ae5b9752e632727cce564f6ad7ea04bcfea8944eae6c0925474a287bd00853c6c55eb58a48bd5eb5ec965611b16e2d9f1c28032b19910c9e900114488390ad3684fc595b5454c415a07cb244504cd124b5238dfca568004a0d5da1e1e7e80a0d53ac5c791274054a179f09c00bf9bb3664650bd10d70ac0ad046fe56f927890a1448402451b30020e4af06fbc1c1cb3dc2418e1b13bee4ef66c76bd7033269e23b39f207ada091c50a328660984759ae48c962050c8610e941ce3c2347264d7c1645fe60970e4c249326fe69e40f7aa94955e812589440891bf9835fd438e24aaa420d2a44550ca9c1a58a34befc3449ca5ffce16125882f80a0c491bf080406104604c60f05634ab56283a02fb604458941f428088cfdc91cd810922247fea250152b20da7eaac041cb4caa620933b8a12a9800aa228a0a86a89c91bf3854146586a8080a1dbae2091c74c51757c6a872c41bf98b55c290392ae2614b52110f6a2015e92045110f44103511896492440a22c922a2e2e40929027085fb9162fe5841e528490a1c560411b4e55552472b3b5e8956a2513c22237fd1287ab9f283263b3e26491b981d2f855248910d1fc081b46304929f0c9252768cf174cad8858cd845da448b884a035c5167adb1c63967aa099eb0d65aeb4ccd14bc200f1176d74587fca5523a409b4a456808299b62919f73ce69cd4a67a59615452833c292e1a4c1b022664dba1a0069dc9725a5ac434852638d379e847d721f61d7c46c10131cd275ddd8582ce5bfd77a5dd775d92d5df8b2af47efbb3a76c8f190a802d52994bf9b1b13e08d94211b84d015c0dd72a95c2bf789abe556b94d402b91a83a717faacc1ef70639b19f6448b333da48bb338225409d7591ab2b64e50a5da1392d2eec0f768461f1287681318cf82526c926110983f791eaefd84d07431017d062b9a34797f518643192086fa611188f4eb847474719667feed1159415cb42423ad2241e993d208c1b84237324ec981d2d21ccb38634124be86a828d2f3549ae2c2943969014992200c7d6a45b3f50019186200feb077b745942479690ad7204153f6843502841849095464d7af2420d8286b12624a40545119282b2b2b93184619462dac5b4eb255bab5e31c85ffc99bfb1b22d734e6b5a37b3f46a95b3552e3591bfabe56a912bccde2a570b0b518bb48933c80aa217b3d5ca6e66d92aadccb26a26a404113feca02a414454a1020a256c161445480afec2020c8b715e167b9131ab629366d76a580c5f92f975b720d5f24d9a07e65b8fb6376d676d4bddd36f3127d445a1e6d4baa9a1b0cfd97198a69d4b623a9536a89b6efaa52a93e99d76eae83b9d92ab9277333dca2b9d67be7b49cf779fbac326ad711b87619cb6936c5ac2999d95c160d92b6ddde93bed301e4f67c2dfbcd2515ece9edc25ef3be92bfbb2ee5a673abee99a573af5b62fc9e66ef24820ca9b76ecf1603ddace3e263be3360c35ef5ba1034968115c8ae8428b45702982cb8e9731d2d40288747ff810cd530a4b93cb3e442a4efff021f2218247f028a396e6f9cce90f1e71c799390eedee9c478ff3f175e8e0674c67c647794e1f2278e443048fa60f110c323c4ac1207f3df0081e31096282e443b4e1a195d1524613f048464b194c6c5961df5fee94f3cc0adb462badb4d27a32d53ad333d3338342a5626050cfc7b8442bf78a8574bf9fd974a31bdde846b74e43badde47df8f4fb99bd2fe7bc02973d15c618e31576fed5df0abb7ec32753cfcce99be639fdf6ccccec53a9b4c5c0a050a88ccadb763754deeeb6c2e676ec7ada55dbdf0c94ab1f94d20e08f70dcb545a42e9d38c69a667a66726afb06738ee74e2ea7742fdc4715cc984fae69d8ef2764ea6154c25dd33b342cf4ccf8c4f940d9f58e1260d1d18cddca4a1032c5038dcd296bf6f3c279dfac3e78e3331ee4ca652b7e19c655f920aa966b2a61814b439ad093f3bf62ac63f4d9a1deb2f04df2de8d8f8721ad34ffc5c3af799795f56677764e3b9659e6a3bf7ccda2f6f9cffa5b66ad340e0e6f0919d610b4766de97bdcb74925a4ba5739ae7744cbd2fd349ea2e697ac2a7187a0c83326926133665189b32fc8ba1b5d0528bb1877df3be237bb3ddd49f0f84f666cf2c81bc9d4b9d83f07438b3d6290f421afa0ce3438cf108230000002288b063874aa543878c4c2a1513030383429d4e2653a9d4753973dcb661ac69f76619b629b667a773be4ecfffea9e2f1d42eb64d29fb5e7b76b4fda79f48336f93893725e0b71678cf1e1f5be237b624d3fbdfb7c2ba6f8d3fb8e9040946f927abd2475d324d56768439c233b2138b2935008cc31c71c324240b22f47b75a856cd5bb34e773f9100bd970128a21b5d06a266873ced7a8fe5e85dce36f55ab38bd73357ec9fbae29e3d23312fceca9badf674ed5e91d8df596bd2fbf944dc79ac7f44ef368f792d09d93d06dca5a8e8139a14ea7edb4ddedb4dd4edba5d3f9d2bd3a6f7abb10eef7bad79bf4a497f1a8a4e128ed72f5bebc91eced5066ab1bcedcbc2f3b7df34c3f793b260de50a6fe73aef43b2f1abd7bdd4795f86bd6ff370e7ed601d773d57390f0fd9f0081218998fb467dbd7a35d8873cfa69bccddaba765dbd4be9ed3c974611f9829e6744b8731bdfbcd5ec5df5ebb4f2c847bf7ec7da79df32fa5dfeabb4d77dd044adf1e4b34dfa2f4f756ad06c9be51efeb4121bf76a7bf9d87bfe1cedb20fea1bdebd9d13a249beb7ed1d2b38985944e354fe99be6b9a7efbc9ed357d234ee5c0d298ce9a4bfb84d2653a6b9336dd807d66d987623dee93c8c72f547d69f4ff568ad9283f4d9bbcfb347eab9569310fc14c6b00bef60197cc59dc7a33d7bb7d59297737e7d2a25b3feb6c3979ef238ceeb39edee58fbec3a6fe3e0dee95e3ac4d533e9af077a3adcf38ea679d9314fd3dbb34eee9add76875827734c6acfe96aec11e8a914254f425c38f37b7f754cfdd1631fdc69c6cd99e96f63efeba940d9ac182b6dcf9b45a1f4a9b3f6d3a7fe4cd9e9b3e3dfcccbb2d2bcf4990822be33bbdab94f9ae1d7d9dd852f28e04fade23e9f9d7a2a15a75350e467cfbf99f7b930adacd3da33cda36515e8a35ae30c553a7d76326d25bd65dbcdac8cbb956dfa5bb277260a37e3329b33766dce8e5d8ebb3a727ec43ff48735ce827677ec71a79ed6e51414993e6b8d5dcd833dc37476b199659f94e2530f9fb6b0ddba9a673e7bc4415cf8b2bb77faeba9403e98de530f3f7b9cdcd8fb367d655f7611f84cef73c14b4191273d3ecec4be1e7bec7d4c5250e4afe763b2b343cd07c38e33b10f89971124b9f065c3db3cf7ce8c5274a502cd284556ec781f54e45ec0f63019cc32ec59ea59cc33d4b3532683c9a05027cd633f9f82c9322c068561319f8f41a1accf84f1be2ab5d0cff9d47c8c857dd8791973114e310aa94f6de98e4ffda98e854c1d637a774d5efdbddeb6957ea976bded269d38078edcbcefb43715a77f987ebfe5e3ebe42ccb32d7c18ed2b4a9c9e81deca863a83ba9c99b877802a7738738727e7b9df330f3a920d8bb578cc2867ae7a9e6b377a5926aea1fa897f4d7b34b9aa665ea656daa00701d1d97319926ea2600e81d1d97b90ed465327a11d0ee53c99ed741e94c7f3dbb9b150389d8290612f7e99df7d1639a8426f29c58c8e953f39cce691e98cf97bc8f9e36980923824e3277eaf4537f3b3455c5c41df38fc99ebfd7bbf36ef3c6ccd339efa63f3a2f9573dacf53fd25997b4e22f2c484643bbb84a97fa68d7a87429d4a9b98a36ea58dcc51d7a40dcc51cfb084d351bf57d3280fe3f9a9bf9e8d7faf56ddab76ba73d7e934e773cf5de79ebbcff638cf831dd67188633e371dbf5ab5138238c73e7dea4c7f3fb57693e6c99d1d476ad101f412f579192fa551d4ebe0014c9fa68dd2df29c6a372653a8ca7c995e9272f431ea6534a7faf4335843c34843c7c36c6d7d934d43e7bbe3bf5bef998d2218e31bd4b6dd3b992de81f93c8ce926adda397d5e04539b7ed259b5933faf63fad427b932d91d9c79ad16b1108b1dc341b09d1d66ded5c99e3f31eaa2f44ef6fc2c63cc651e76abb5e348ea6dc79918767b29e77da7cd1d4a9bed1d97371d61846f237850d2607dfaf58bfacc348f3d86d9633f502a7cd58ee9dd754c9df6c1efae83df75389bb2632fceb1212e956829d33bf8f4f876185f045867c8a3d35fcfc5d7876ae7ba536fbbde77d23da7ad13e7d83e38ade2ae53d210f2281d6b087998eec31d5f873bbecfa6fb729ec92be55355d63bdce9390de58a6aaddaa1e72e024e67c8e39eea0c79604eab76b6d3eb6c58d31f938d1d9eea9e938fa598b6d6eb31e2a34e3a4590de96cbfd7a9f917d7f6dfe571bad557f46b6fa8d7bdc4ca7ec54daeabb5a2bc7ad38985a310c2a1573fa7bb7eda87a9855bdfaeb59dd6fdbb66df7f5f7f574bbda767aebd5087dd5aad2ebb5739eaaf4eedcb67d6f25adbd7b77ed9b91cdd5bb6d9a275fd33ca86fc7919cee59edac296a7bc43b288de937fda534a530a753dd7e378fdbeaa6d5ad9ed6ca6db46ef5b4d65a6b35799f916d42fdcba71f5c8dbdc956024396104e74f082285eb0903842891886ce885fb608028d25a604d1052867eaa00738d8df6bea19359fa163d026506678e10235c901a80c0c08402778c3e80470c430c6d096a12d2a098e0883882744a4000756681b160d5931f444957b64d7df468b52ec9867310c420827c491503fc1116df800c830e79c73ce392777845c41ae8a5cc15318dc1823dc734e19f7ac357a71436913bd146a8e755d5a09931c4bc34943e7949933b82ce8401674588831859a1329a5147a50de421ed3935a09939ca8e1a499524a4129bd02094984c5a2a91d72562d6f1a638c96f73db10f59ad47a594b2c6e983cb524ae965adb5f6f2be69bdc53eec7549cd421c69299db3022591e5a3fca8b630ca5a449cd95c4a9b7bce393569f3e51dad6f0aab47f7c43e628c71462f4a2d11e9a2944e3aaf5b3cb10a89948428727c8d3546293ba8d4d66addd6d77ab82dab56ab561e8a34d5885456b960828a9c10b247452f90022315399184a4365fdeb2e54f72c7db94567ab82ba5946a242b74d041072952a440a83dc9d4aab56aa161d75a6ba5da5a6b6a012912d90ccb42828522578eb496b41eadaa772c6512657422b38324ba208496452febda0c5f4c3bc47066efbdd7db9906b67dc434b8809b9a1a2c4776ce19259dd56a8708f03419ad26d7d4cc7b8a9d66bf12c618e976358d2da0a686ca49b33a610af6c83462286f86d17da3830938379ab575095aff51086badb55a2e1ffdcc8673ce3977540fcaa4b68536f386a449e93c9dd45e36d3ea8c9f811990f9ff4070c8131802e464942d0da48b5c6990f98b26e1681541e79cb55ab43ac95020a5527d23a5bed24f092d03424b4e3aa9a5cdd8592fcb66e7ee17b0610136c7f5c89ca67275b369acddc86002ce8d091ece4d1cd9c255bda5748bef871f7cd0a489298cb8c841cd62c5942c6b6859e6a8214b0e4a63f890038c0f50d800ba41961eb02c42f480640a42147b5116c44d6b9c8fd6552d4d6dad54f26062b652a91e0657d694d7efb49087756c5b24884546c8c1b455022ad1b016270239f555cd8db59346083a212e32428ea521a4c9567260af47fdd5cbce6a59d34648e50eb05f979439ea0fbb757b1d041b3bf5be9b4d79b0cfe78a77f0ce754ccf9debf3caf1b9984439b15c0b616ad2705c8cc810dacc7f32c61919e3bc5cc1e823a5ecc185333060f5776a95d24cbb2c9dd6b10c07c19edd560cb3b49d564e41e6683a75039db5feba2e1d6115252e778b6587df306073380d6d096c84ab6a822d8bd866372fc20e0412efe49823f705a909a2a561a553ca4cd21764a1c16659015016636829b0b2f881bd020e19c0207a03cb0d7400258a264859166ee47080296958244c460683d596da4a4e9a2b564b18de6f866c5a7f63e99b9b239bd2d5ece143035fe4efc646e26820c8c9ce54cace23150548b2c000053b201114c404c5411643e02c9a684116376459489901aaf163032a8670a30c28a61003cb179bc5cf0d53b6f06001e005598b0f5738f1c14a12d4b21b16f9f0c4946300550c2186175cb0a1c40f39561c588850588aa018e9005301162eae111a2a40c550050cc8e0228320316e80654ac512040d3e44cc6089278080638a2ba28461340786050887ff079822c5cd07ad5c99e2449d628485491396700d007a1dbc3141f660927f7e7e5e98aff3d63ca4968473cacf5a35b387d573c89c9a26d120209149a171d94ee0443d819111aec18a9acf741b164d91617fafc1686054f3190ac6189719327cf5999f7e8119f9f0c4a84a7d02c6fe2ec445bfe8418e316e3802055b3871c3141c98f0c18a132092a00cc1839c69f499bbc6fe5e63fdd0830ee6849f3a4a2d238453c6d9c4674f2a3fa5256dd0d089c32d3dba2f0725dda4869047951edd3e35c6254a5c1861bdf1e43e81c5b559f350e9f94c2652462e96cfbe30c250393b7bcc43f948a9a638c80f9fafdbd6eba7273deb36080e02826dfd1292378f55e5961eccf1b1984819e730c27aa386a4141cb3a2c6b461d114217945cd0556c04697285ad0240e39640d56502c78b0c6b8cc9021c31e90b847c4b041193d0c6911522267da4088ab46dbb0a8871d5c4027cfd4390251684540ca77c3a21e6cd0f677a2790df9640419f2b56191143474f0240958e9161b92c8f5146ae1a488093852cf27127481c50dc818830d2138a15db08882f550434ee553ce4eb235673e3dd95fde3487cc064b830dd9c6d8244b065c77f21c78cd1e4269436fd56ba33de26dc397d24a69a514b392c6cb7265adb55a851deea927f681e91b4c35dd92e3219436d7fef2ecef757ddfd7758500c9ce6e3766ed2f4c7f482ecf524da58d2657d72fada2877b7e05a058da1bae8c92d21833894d4b35cb823ce0a494ded2f456cbaa17b5139359ac1966ef16ab94125b22628c90523b69e2cc8efa1963d4288c931291e40508724491618b1f6c109b54c0035388c1e5871abab061092f54907286005c71849417ae78128610b40b1520264616423120c3881fb441b9a88086941ddc30c58735ac70d952018d8827b8606963871cbca8c18e204881c30d6ac0831aa6d040837475ba9258186129e1a496619ffcd55bd57f9fa9af61502427fb0a2c3fc89c805234450beba668174941c22aeae1047bfe246db43d9faa990752dab0480a0ffbdab0680a16fb7b4d1b1908e38c278038aaf2060e5ca8f0861b2ef832842ab83042ca510f690cb10614353411832d54c8e1270b1b8040c31a66cc40b59028e0e203a436a8e0e2848838665081369468028e2f6004c9e08b960ab810148414429882872f4db2b4b046500f86a862040ebcc8428503a480448d2fae7c89430c242d5854807338d9122506416801079191126eb46028a9054ac481058b0acc1e1401a38925e628220d2f39b84205e8250c379618421c36986307b448081b90e0e1cb0fe27042d40413a221880082110f5ec470c50535354e3001855af1d9a3e78b116de4a0872c57e45053d3c4cc019458060872e04116379041143940c10314f845872b6780620920886cf0658d358e805dccb0bfd48e3fc470024b0e7280e1060d6815220862074140f1421449fcec20a154405291507470011047ec800551a061e413639472021b6b4c11c710a6c41005a542850b732c7c86159036527a32cad873ab088389a42c40a471643444d0507c62c31241354d5c01a307202d3e6872b4e309950b6393ebf6973ba4e7b1bf62d0c48e3beea2185cd959a64d90abb86335d497b49959ed902babe54af3c21e8b720beac19c5b3d2573072b30ca61727fe40f0d43394c4c40c10d5890534f3d25304b0e1378454ed548a8e27d76bc338a0cbce43039801b380441713841500e939a1750308395521281ce38ca61229372a06400b41bf401167254c9a1de9d41cef4e2a6749ed2d56ad24415ac3a3fe7e7fc6a356922a722627f5d057b6d7a799f0d55f5d655530455eb643ad996318e4b7fb9682dd5745a4be9752485514e2a836e84aa1d4a75e49e744626f7e6d3eeb4d27f2e246d55ab5dcdb56a4ddb348c4f59fbcd274cbbfa2c64d33abdb3d1ece5735bcdda2d8d7bd5aaa7da3ad5a6775c48722169d3eeca95d359f39472d0ce3d3548cb30266c3269266dd34cdadd345aab9755a00a4573dc23a7bf4d6f25aeca3e7dc3278fd35f0dda19a842912ba19df5d753836ed5ea21ae75cbdef69c6bd5b6e79e1aa4554df3b6a44dab415b4f0d1a41970d4780e442920d5a00d5201bb49061e619b49bbc2fc93675cf9fefcee92fc99efadb5e3acee4b8774fc915a749ee99cb9e6da77ad3dcd7a3691785a152f774ee976edbcdb4edb45399ced35dbb496befb467ded799368de34a5f92dd3d6214b84fad327d9e7ef354a66bffecee54260d046e153e4f76d37176d333d3352f9e9d34f2d90fd45e569d58502b6570b870e69341bb4e6bafebb2183614852c8661d9b558f40269643c638d2d8fb2136425f1a804d847fda59a5693615c029b58c34140202d224dc33eeab51a698c316669631f7190ebf619f661f5177f4c9da9858431de387a44d4014b13618c372d777308168f8e4cf808b02111d1be68a003a21622a3214062d29196e88068c651b44446d101d10cd924c34164c4492b5dee75d8c77c97ba09226b19fb98cf58476e7a9b991d1ec6a348140fe0d918841793e40a0db98a6c481a19cd904de2913e03f288445e32162f988c994a1d43d07a59d6621a86657902767a1b31cc8c20ec176a5986d9cbaa5c56903652a655afcb5e3b69e6b33cc17e7e5ed6ce69377004960034b1398fcd89659856e293e3d5cc0943832c277dc1e61893f6e5e0113c8cb7f139c6a776cc1ef127be86a80a4bc315c336b1a39568b4c414fb8b4731c63076bc518932f6cd8e611f19a684d0c6b00f6b055116fbba95001f568ffd69bb3e6057a21992d022533abbcc2e6600a68d097b1e71c69e4850b1670b74d8b30540d8f335b028891b8ee061cf39c338234ad2bed18a91ad98b804416f7aac0b31549bde6e61840b683635cd20cfc4c34f2b628a6d804d6f8b4063d35bd807cd330254dac8a7e42fbf92d796524ad951c9f143a095b94f9bce14203ad9df024c8057b4ec0f6e0963534ad928c0fe201c22ec2f36d93446a154c0d85f3c220b1ae10b9b9edee6d457454238d9f4373840860ca1824d6fe488159bbe034866b0e94bc0822f7eba0041091ac206211da4181aa28d2a55b010512922e2079b5aa9c14ace32d852fefcfcfc04514a6996df9c7e08a594c29c4902151db6a4118371e186d45a9e04aa0193e2e5e200c5f620940161c3d5c311a6c40c160f568a7d5d57ddd7755da736e8aa010d56906e908094278a805043051298e2258615f010b4430d12e021a909268638356a2abc2265c8dd0e6c646bc40e1ae4cc04005690392b461842d66880836c1243842a79dbb068873446704186d9b068873960904f1b16f1b0022684260ddc94da25b49c11b361110f6a2c619485c21e4d9c3ce77adc50833d0a40e5a9a77939ea212c7dcd9d55ca21692deb9a506e435838469656e2936364d268e9d136ad4b58ba442e4182887ca69764af9b9a11832e6b5ad6651d47da9435e59571916393ebd69b60cf8c580fc9a4a15e525da49c3509d31dd43b491aeb9727a4f2bdde959a94d7a5975c9fd7e797584b45630d8942f10920385148258f5552ab52a0bf5e64ce5f1a5a3248b952f1430e6009d5dad6758c2d2b465b3d08401ed6b12cd3f0e186e44b0a3267d3d663767f9043f896257411b1ad230ae536c405c4bab4129f1c9c49937947b0a32c1f85e25743276c0b02dbb2563527c012e2b60e015842b512259684756156b366248df51a7982bc653d4e695f883fb084a8435682ecc9cd70acec66d258433a3069ac5b982cf207bf2891369f2d81b4891f615b1600b66559d9fa080018aa305cebf75ac6964b56d5cb0de57d628c41f05e6bcedf287fab264fc84e437f79823c963d4e29ad98595b8363a4226d597520294a9ae55ac027a72665a1813de00a96b0ed28034b908154409819e4af668f3bc4e8c60bc90b523c4746e4d098c016546c2c2591e1907baf2aa2a32447865045a98c548076b7e387c0318e0a206d6051105f76e44cd8d10a348a36f19c1669436fd8f12cece44d3f876cc79173ebf190c855fcbc8ebd8975dba41ee20ac09c7a1cc969f1563796e619b935353ea746ee487346ff38a31d4f331f2ab1a17b7f37ebf28c72764dd3aa14ba0efb92fc4eabb477d84b2f615aa569c7c8d0b02e7ad11129de9b359c56db49730ff1101c59da21675f8204117afb259c56695f42b1ab344d643ba622526f5fb56ac8b6a98ae86a7feb82d0be08bdad5f829d6a153c3dcc295297d81f12bede8b61401ef7d5fba4b9a7f7a81d722ce190b35fecf651fe78ab4973bf7970d268faabd9f71a91333873354f4ca2725c38f3554a29a5358a3c06af0a3d28b3b19db1ee514a29a594424217a594526bb512263997168a32ca58d3b8f091524ae1a4796243017b54a14ac445152c3b0e51115fa3481bf9f8d1ec78ccc21252de8e325fb7a30521847456a1d9038334f01e8c431589a201e7bf6efe337df584f96f08ed963784c4b05f8ae5b15bdef4806ccebcf59a38b9c9991ac8e660f166f7224340b5f86476605a3a57d8d44a7c723e696e70260d85d922f7481b7afa0e481b95459f9a534af925988a058b051ff5432ce6c19cabd25bf457a5d691e44c4f65e9215facb7922bfa1944e5f5037aebf7d78b64b7f412ebd92fbd040922d6b32fc9510db9aeab8a5841e28e8f92888c71cf4b3cc43ec6214da684716ef3f254f3d7b117b16ef5126d7d09f6eb30a77240ae689e3414bb6e2c3b6968078ed82429291093ae105fd800ec01e111584295d963deb22ccbd22ceb9af52f12c978914d8f790cda4d8f013f46ab6a8c5655ad4a41bbe944b45a7d72ea7553758d19d93a9c34d79149637dd08b11192f32fee9d1872a054d331d7f89ea7a4c114c63b4e9f32a22a6cf9bb49d18c39eeabab07f35fbb76d08b3e161ec511337c4d7744dabb04bcab0efd4ac2777e65d5b621faa21d8f489ef956822f826ad641e3ff3ecb6715f48b0a7c28ee92130076543bea47561d7be98779dbb760c70d7b4ca5ebb4f0e0636d3b513315dd34a90b057d2dd74ab8994f24bf789d8470882c46daf02ccd17ef9b830cfda9876596c88c9543a8ec45444e8354d645e8569550a31d75e24e6da979c1ef322f83087d130e7f2eabe9aa762210441e2beae02cc81390b3eb00f81b96ac8e92a55915b18cfc88c54bc5845aeacdb98e3e348cd535da7c3bc8876945e82ba7618ed4b607e3accc1282d06e69483359369d2925e32afc17d599af56c59c79d750e685b9665a952c0d79058428fb5ea2aa27dc9bca655974ec99575eba733f2edfe609714604e13fafc63c98c446fa71919e6a886d4ab8858bff2fa8d5ab44eafab5e7703f0d83f1923b004994d8f6d6aad56e293939a34d49a1e10095383fcc12ed2269eea900123c7294fa39c3dc02c5d87e60c5cc9cf0a65cf3927016098f7f37a8c2f20c016b28e33af2f35802dbf2a14ad1db5c708c396b71eab1231462f220c5f5402f29855a85a1aeba03d8f21d52b282b9ae6b29cdd0c675996116ded8a1cb7a6e19bb9b8698cd1b87fc8470bb332eb5aaf4f608f3cabd5802d6fa1acec3c7b542b5836230752ac63b77db532ad95c18cebd56aee0be421b38e28cf7f595293c9052169cb5338c4458ba5a6e68ab53536d70bb275fa8199cd33af69f6f45fcfccb59e8d41be0eb7ac74c3d9835a212dc41d35d51f98d955ff9033dc3532dcf3baa4999527f27529e4d21fc8acc468c50865c348639458b66855101629269434a7bcec6f87bc54d775236deaae37e1caae04d8b58a50b5644165efd8dfcdaeb45ac10208750bd262a4824aeb2f6bd202a4a4cd577369f32d60d7571e9ccad8df8e5d77b0bf1dfbb3bb565ae56b7d4d01963b1948eb9c734ecbaa5ef8c460861942a88208a12d309011a43ba8246c986a8316226533000080008315002020100a878462b1683cccd234167e14800d7f9a46724e97cb834114a3288a410a114308318018038680cccc147100baa10f89f234fc6b5e17a5c9d3c451df25d19cb17c44a0c8cb2c3d7d608799a59e7acab7870af1cc7434c6449f2a908c8df6332ada62789ef5b619dd533746527f3a9a66793680790ca0ef8a2cd8ead99d4d607979d594c105870be9b6ac540b182229e02428adb26aa49ae0b59ea6bef23a3cea1d88c8fa13cfa321923250dad80b55596d7ee2f131aaf965cbb775a10d2dbf74f2915f96b9fc0aee1af51cee483a5303423ce675cc962c3f160e410635688c5182613be506f85df042c4504ea256021a5689453c96758ddb22e3dd142adfbc6cbbe5cca4dc0de5faaf6b290135159b848743fd97c4ef269a1be299b731a8acb93a8d68e7231ed4040255e08a66708c0d4d914063261f1d47e4bef09630d2b5bfcb3efd8934b56368107d22551f097dbe117de3575bba0b89b978c6ef0728994f08fc3782676922bc81e930d96db3b7d939833146de0a868773ecd286c7d2f164ab97ad7c2a1f88bab8a9da8414fe286016cd4f7df83305154c1ed6c8aa3ff182d33e844e1ee250b072ce09ed2cd51ca2af1585e140d2b88d5c98f5a0b8f68dfa8e33206e811b0e4d63f6be97ea585a07b5203448c214161fa46419caec7d73b829b8f478f4fe26234fcfa8e18a6c068fe5455574070cb2a506f106ac9e74112361038b01d6934e45bc7692e7f3ac3392c18de252250123043493b236bd35548913de19645e49b0c9bfb6643a2af7a2bda0507600e12224c808a0e4ce26e0a35e4e98b813e67b028dfe09efb4ae1eed3be03dfc16557c9d81458fd65209134f498b114ab1c1cf74e230b48edd91d64bcd128317243f91f09803f80b19134181a3afc75f14f6f85cc24dd243918e8a032cbe2787c323669bd830c64f345449b82c43a20b098e32aed6fe3cebdfbf9c6048e82d418db3227a3a1084dc83853a61160c491db40d24e50f9012214eb1898aa00c9456a98d95b1196a9e42b044bc464a53942e63e475644ee4b69755df71aab1093106c2c75915f7d614de2ba9867bbffaa3aa09dd358e81b6cb21bb42098de697b91dcc70470784a7535d3db838c0a67258ed8c90b40cfcf244ca004f5ad94376c418c69c7c33e11716890706c0388bd96ad5fcb3711389d6f9a6411f6bb884d45cc1ef4b0ad820e43d1e63ba60fede857e36e56b74af5a2259145cd899e92bfdf4a83d16e405d2c423c5b801d4f98933b96fef0fd05246df76ebe86e84b2663ee20292d459e94a33a681756040e8f81fbc47d2f50625e973ca4073aac978850f1b0e7b753dd3f9e2d32c9a0374d9a7a6e9038f99e307e6ad2a1af24b43ad477d1060d35607c2df4f68f9b4e79638c53d9b6b2b1887a2a631893396d69f4d023da4ad6b6f65f9f0bc6a28ce64e2f4da45e665264db3ec271e816457bfe18fa474af9ce288dc57ee2629cbc81c20de99fc41cb6be0ec3757febc28a6c6bc86a0aad57e2d7ffe357f4419aa6ff2b89e94f42d8f9718cd6949954c655ae649031c77153659d46929d8c1c3ed669109c2c9f4eb7f9803662a5f9470540576f6825a4057576c4fb243faf23a3ba8b8b814bb7ef650751a6e5b22605dc13880812c301c2b827ecc25c39f5571e5b2a44903381bbd6cfeffaf346a3e94dd0b83a647f8407ad623d9f38421fe3e4e0a9465a3afe9cc8c956ee0984816b09019b435953349fd33a3733a85706fcdc70905af3563b7bbe521412738f16e246c2db9ce912d20e833668819930ad0288508c3bb4356dd4d4214738c5b0ce79beb1c17af41d8c1093fc7bdad304374fdfc2355e9d28c7761432ee0ca28855bc7c1530182be5366997e2805c85e3a3959b2cf3f8f24c2efa0c7f5ea9256e2e562bd82400a720a3907e648de4e10a08f874919b7404b992278b506f6d30471cf957b4b5785a2c4295d043fc31b8da15bd54ac8cb7b11cded52dc1d55fcaaaab62c6b4dd16f979b88c87e4985bdf4d76e17390f48be7ee908672403832a3ea4ec95feb3ab51e32cd29ea8d56ed575cbe7f0d017d65a61f4e7d782346e0afdcd15fbebb5eb800bfa54e8994c5a68ce1b2ee415076738327c5fd5399fd96f5ecd460844899e09c2b32355b1d17ac9d6b7f5a44f9bf66b8e6482d6dc5f2f475641a9f4e3e91c633b6e984d6e96972a6be95c13adbadd88e6b5e1be2589430b3b08bde858a73981f97a59d7a471bf0ea75ab9d787fdf4be40c1a2d03e92673b3714f92cbd6605f1ea806374576bc64fd6424aa336184c93016be13463bb3e13bc725b5aeb7983f56ee8fe7ade29a7835e27756027d3d59d6a2104f3e92facaaa07a279522edbd2a910b0404d18d5359271da6ccc904e1d04fca8719b612bc089bd74acec490526183931d9451c18153150805fce57134425c76b240f1e094b1f1c90fd2311eaf8dd9606759a1f70392e06726231b0d530ed595fcf50b01a9224132221101662846709b411f18a7d62df648e666b3028c79519f5b62d034472677b7f91a2c45a73bf09e52e74dcaee675476c18479a369ff4a719156001ecc412634df24c622d55ed9f9f53e9ccb64da069e8178ec42a3a7c016a05b346b67fad6501c4440494db64c8cb71bdae65681ef1cebecec61998f6d31738a5cb63780e92167034d59d1c77137a7471765583f60a6d0133dfcba8016a500264ccfe6c5dc4d762d57db135fa4c501a667da8ed5c0fa0f2b2d943aee22b28afc10542890031a7d31a6a491d12af99869295a794850e4c91929169bfbb8919ad04d4dcbec7608a0f195311256dfaebb6f72447e8e51e445b31769dadd1090fb5a65fb1015f41f9e141de21c592155757bf440522d514c478a1afcdf11536dd0d9b9dabeec3c1d4dd04e9e7b96add719f0d8e138f577b1e3ed77ec8e9c8532893991b9aff5179ea75e0ef39aa2d3ab814e094e65829135527151d5686e7451c8febb286485e46a87345c88bcf98d8e5d738026ea98d43fe8c69fa40d185cc450b6cc44f7f588247c8fce4e501015d7dcbab1436c417e18f8ee1f8c282f249e910cf23ee7d1772f9f878a9e43755cda6573e21fe4280c837dae7f1f2ef9acf86ffedfca1e930e3e812161ab51efcb68ab22b70b93a8fe57bb01e67e88da5db79d68267f8c191c138b9300991c07b5df7a6551dc8644812577a2d32ba1c79eb04c131b840a020cb840dcd1488f2a6eb2f1b088859591630397f5753017f4c5776eae9f07b26c1a60e6ae278f71750de18308de9f357dbf8b1ac31f67a818a793b3579078cc2b4bd531639c7f854897e50a86c16e408b0781753d0827c3b05493cc70698212bffe5b29e3484d89b24d025bbb937b2de8fc04477ac85debf6e549e0a0c59fad351c55ef75c7e8ef8525c3f5a99e339eae6a1a27c2b3a18f2c2b7f206a7308db1d7b79fda1198a4b79b4e53c0761cbc2aa73884880c1948cc5360520f72d1f525d36fa615691703ffbc82f5acc9a4545a7cbb55989e9dc6fedbb091cfa73d163481cf6bb1b5714e40b49a18cbeca296a605d894914daab45056de0133a5ae3acdec821077b5a315d8244188c3740205664da121ba3a57089a6e2fb4a9e8797fe62f0b10555f0e92c94c4df68db6d11c49540e2cc55e38ac3fa8a222814742475e0ee78ac9cb56b88d689645a4665e286cb44a29c62203ff7a107ce94134ebd51670f49d677d3ae8e3a5ae161117739948cb455a81a07c3c08d113781b889720dc2305db37e3515b9157d418770f29722f8da68dd694826493319614431a789f3771d0e67c28cfb99e98e5cd3c22198c07bdd00f4d48c8039de33c4e587efccabdd4f11bdcbe3ce98c18706b3d98ef29c2895e2d18eda2435752ef889c9fa00411379ec80f36b0a84d5566e92b5c719d46b439860d4a00a517e2c5713449fcb9187e2e5988c812dbb95d5257ba3c5f7152ec5e31585858c4e82d2f944e3a60218bc1be25fb82a83fda22ca2b74c40257064b5bd3d3f9d5609f61c4f69224fabf0fcfd83d2fe5ae3ac661eb1443ea50923e907798be478a7d552868cb35ffa9626919526ea5bee411b4aa610067beaa2ee0e97a3abfcf98ef5a1062d5fc38325bae39d536f19585941eeb55a313a8d8b0dab2f0ed18502876bfe4f26c216e87187dd53a9e4b668c8f7451d7a0c888c8e19de94d171e59443fc54cd21aab3b4e73fc39c60ad97ca3878688d802ffdaf97d3980c8099fa30604bdd4e5acbeb9ae680a30358da257bdb7b9bcd7ddcf7582909dd39579982d4196f8e0fd0967a70c14cd17f7df4f3c56c5d5d2b33369a70c92717eb5c9dee9a2d69d9c111b570524e02ec3f7aa2963f28b23ea7d6a9dfcb6a0e69652ffc3aa0d44ffc3e75ee0cb789dab890d408b357075c16fdd2b1e266d6194b5b9bed9d4c565a2edcf2ce01baf6911aadd9be3cd3ccd9c91be662ad93c0f29e720152dd10a7bc8908082da46f0cb2f401d804d74a554e344f4eb9204a9fd0fe7adc5322678fd81382d03cfcb3d0f6453ee884ee1fa040c8d99c48b0653bad479a21b83bb73febc341948647dd2ff125b3bf92ba031e77d8b2213be1950831951b31c0192d8ae225031cfdcc51be359afb56760f2002b578e1c248233521671daecf26472aa679aecabdeb92c614b88b9b6fb6914bb63c4d45a5f9abc5067d5ce8e78a100f0d7b25642b3aeb46b70291ca2fd86e116227d936e7e60d4ef9be70e88504dfdf20135012a9f72a602f025733adc1628a402a7d4cbc08435742f816df2446dc2568aa7b4c51f36f83f59a68849d93b561aa35ac799a406e369d66baba66229e64cf532a75100c7101715c7496281b16613d16747b02c6831df5a90914e3a1747dbb382872a664997c59f0af3bcd6da080cf701bee5aff628d82ff5b8cdc492cac0d7b35a9007fa8e8bfd01a093b8f561b89499785463be683c8690013a0e3683d8f0c8106bd3219bc16dbb56110e12ed49204c6c9b4d6a4f903a6620262820ff0a44a19c5a6eb7164fa339789fc0d7e17bee90af46fd2b9d9f5f78b638cb32d48b84ae4a592708702a9e2b101c18cceab236cb8b24537f6a143a7b1730b12950a59d70258e8ed240874d5b24e2ba398960eed43ee3c9137e78c9c9fad7f8fd6b4880d0871eb438483add505bb54556833bf5b34d9ae5e5651c6acfabe32578801e85572ac07d73e276bbe12a5672e04a211b082159133b2e4851a0164d652ed47b5d7dd37250c9c26601bc852bcbdf66a2241990f68936434293787d6966f066ed58bd300b9206e8a94e8751fcb42091e3c7c4b3d56447d91ba3420e1d2a576ce5afc21f35efe49dcd8540a76d7c3a5f681ac59b7162f85c17fd0571a979ef6a0281beda6f97dcf164315c9d17426b774746c3fe649e451cf63a10c80ca498b662362a9e653f1a116e117a016fcdd49461f6f63836f9dab79c1e389aef4591a1602e8c7eebe3ef1a08e149d9ce9ec0d8778a3b1e59d368ec55482d29491b44e6d4323266e1cb52cad584a0871e0d432d63afe5a911880f8128e6bde5a8f1fa5e229baafc1a76c5948f695aa504cb834595eef0a67d34eb63f84cdc0b25975093eea163e6d0096987087881b28c6a1524727d8da006bfdb80eac56153126af5e8a7b0f3028482fcd8bf424b40cbc25d21abb7baaeda9f096600e0d2af33da52bd11697888022a01fb4e996c19b79e6f4a7db0ef74b4ce5345c0f9068daf348339c6460676a023a28cb6c9d925ff27318f6279d982f7fdeca049b8c9f3104c31a01d97edcaf3634e889955f8b1327acde3ffa3ecde6092da700955a29bb02a774cb95dc6458b30d6f0d42056cee3e1e7d538f74f71785850aa743ba80208b5483f1c8d0c09f5408b7d942dd811ac955f4efe8e265006d3e25035b0ed2020374e2b87d75ba017f7e249a19cb8dc3c320e9aaecb542e204b8a737419e685ed23598ed6bdec54bb64c2d5250038911abaee28cc296102eaa6d99f8c1899dea8c62f390318fdbfbbc8bca098b2176a02e505b6e5fb4bf789d660e7d7338425a560558f3b587c667216d3c82da68517813c25e6e7401024f9341e330071c2bef1b786d89f3546e8f7edb5019526a2617b78450eb41169b95ae1b4631df0fa59f8d1967680d059e1b15f82fb8afbe0d43d540771c6caf7eefa9a6f0222a39994e93f3ae1a8a752a8b01fd81d596a3267ed0cb33d9271abf3e73418f3dfd3d9f28b8f6334591f4af71ada3a5cce1da2d40c23b962b7887010bad51c5bbfc487dbacab6cb560203a1e68e9a63c744a8d951f19d501d7f628d93950c1039ff94cfd5e315e5e34bdc480bbe57509f9c81d4c61173cf017cca0193ebc224a06f901da69c62b78fdae4d7338a861d001fe99f24a6b186a609c93bcebca152521cc612c0ef0434f5c40424ce3a0517c2835d623451e833197471f10a115cd694d01b37054c909334252ed5bf9461639675dcf674badbcc30a0cd84b4bc0d8818ff0b569b67eb22c8bb6306e3d52136a35d3329f6eb5aae07d0381d2352d841b7d7966f2b8c816304ae3112f0fe6c792f2036385bee83a671ba3e93be28f8a8bc3a7e4ebbe46fb38a790634b665bb6e21d30fefd168bba28bd13b7dd5a1063fff4ef95f3eeb7954a05b8064891d2a860daf372af810288c5fca9ed96a4757aaeb66fa12955c0a963fc58125297c860f286241f5a90e8cc670b20b1408fdb3f12331212c9756edc9fe0680c069dd9dc9da1966fd7541b8d8445ce2a35c308589646d0733e9902e07055db53c0c9de5db050198ede41bac7e650e345ee18698ccc226d986373cc666aab86be4380e2a77319d85a4e30b4ad4ee898a4433296caecee931e834a7201b20b3a650f8bfe02c02839dec9ad281a822ed32fedeaf81896296f74677322235221d8741dbfbbb15ed9f420add80f0738566df5f708a7c6094e80dd01b6337a6313ae69892c7813ec46e7c24a7c8ef6a9c0000fb7609e750d8d17f0112a58d2c5fd01e82c59e10eb06d9520ca4a088c9f38ec2a511424318bbc51f88531c423bbc9589c87f19af3d899a03e8bed3b8f3ce2793463cc01225cbbbbbe3b762332590e0fd6aa2c6e31305a5e62a2df54454efadfe7ffa2f18f43be34106a581c0ec1cd78ca22e999d779400d466876d2b87df013b61c872247b3017002d94b05d64ed35962b20dca08ae15dd169644a73894b3bfa26b8c1b2f97574bbec781f6671a49ac8ddc7a0a993082beec2a5f831e2b3f6397a26e39c509e472bf46932efb1991266566b11d9f4b414cabaf13a92ed2ebd3512edee9041bc8d0abc31b3d12627221d6bb65b36bc04116f652703607918686f1619edbf340abc6eb63522d31ad3a8caebbdf65c3444fff43433af0790e347e61e3f9d7a1235f132fe16288831838e7cdeceb3e11e4a643a08d9f0826476dece4eec88e405b5c572e62a4fe71f20345329f68c3b69df219c09fe9b9e0f8e2ef25140609b8ddbc705ec73980c1893bf4f23281dac59c6c946039b9ca0a8df98d3a677e245721e49752d3c2b30ce751387d129422e2b7b64c7a322572b8c4681a0bcf6f7b63908a4a684c4666c79d619ffb3221269a4c39727d451db5d7893bdfe21ec87b78714120542f5313f83a208db0a15af1ac72906da8b21cd57c4319f5480290afa1c691be8acf4504a6f2004240cb84fdb34f4ffc7d5343ed4024fe5185a46c91e4d855ecc5d6164e300df803801c3ecc1de082b1d1bfedd88c20b03b8feec7dcc4b1ad45dc04bbc4847f8e553e14838962d1784712c1103cb6c39048a9acaadcbca4cb827044fd6b741287345059d4b2c9648220a149934ef5ee6dc4b270fd4e3afe38692dbf746eddcf11de113985553e49a0f822170ab0721eb837a22f27a967670cdc4a1858b9fba479e2fde65d8c99a08b9ac10aa55b2f049b08ed04135763ebc42bf05600b384144e91cd9f6df2107d1eec0d225f5d057a32ce8b1bca17920514bc4d6bc3f2eae663c0c5f5a985aa6b6a418ba35132c5e38908aee032a17e88dcb86b542238bbaab05e0a6849bccc7dd55a5bf1043f1733e7a0cd748572e466f55700313256d8ead1e2f0005edf23fe8bb317a21827e93fb239db4516184733bd59d89e549d2ac2a1e128134410fa0f4702d0bf81fad35082e4ca17aaa7bd917207b34ab781922496307f8857adab99d853a803b17f68c0c10ea837df5326d53f409553d52a39f5fa23287adc33419064a20758573024a74ffaf53bb22e07245dcd1f9986248e9a08c5ea70fe010b80ef82422bc618c59dbb389cf20682f54042fae6d4f8419c98f3a1f027db364ebfe3acaa0f3e443c8a1798623ba81a7264cf75f446d3cf53c007f7deff9821d02bd170ad99bdf0c0d57bbf00ce2634329fbaf65b17261a023289c6766d416e54a80a1e9ab40334b7d49ecf145a9c30910451ec23374ddc535c3fc64561bf69df0af5e70dc9cb67e5bb9b921d1426ff5f6ff7d0bc09b1989b9a795a375f3dc294f6c54c8fd57e313148813984f2079d9e53e362b9ca3c7095a5ee88c3eb39a70e7ecd4b3110d73e7e91acec5c4eeac72c670005f49a0c160c75322706c5b333c3ff8b92eecde823e9630ee7b3f119349eed0804b6f5551e5635d2bb7925a2b69e6d3205ea78e938fabe18ab049343bb4fd5fefc44c97657930e9af5b4bdcc866fccae9ef023e6759ef60970a715d0a3bfd81717a08ad449c2ee50760f7a207392b77ba5820736db7753918eeeb0d19172f200828148ee5d1a8590f8a26818f30d5c4b887e4ce9c47bfa4eccc9bd4dd5abca8df0629ba8bd9c5596b9abf48faa756dc93497740bc44b69189502267d5f5740e65432fe08dc157715748195bec0c489fc2469a5bf9aef2d5773da10143ec415fa5f69e7c249362b05243e673f503bd326f342b8d01138b7bb22097498f32c30f54c9a00bc5aaf06a8819cada25d89c234c40721818d3418ea52f96fe0f14ea1ca0289a06fcf64c1e9b92c96c25cb7bbe566a4c3680784fc0171f78cb2d8a08ebeec7848126bd703d12c39f640869cc59d4c83921225ad82535258305a5bc5061d49f51211a1cbbd2efe672b429bcce77d1f77b0cfc5087a6db6084e11d62c82c82fbc930157213313a1bda33d46bd6b1a6d99061201d6771a699f7fb3ae22938cb3fdcfc64514b3e17befa08b850de0c740dc700de22947bfef13082fea51ba28919ec0b8c7d0669055314d31090a88c629e1b4e6c7d8602e1fb8ef45156f95f336501c678a46de46e060da278a9b983926cdc0ab12ea0f72e20588dbdc628789b195053d6bc24e2a90c57fd39e838c4f35d142dda8d1292a02b0a453362582aad149d9cac255770e523df659eeaf54896f7b4a3754ca87827374bd86c1f17b737b6491e9f7e60e9bb31e204b75d586558df494a4d51dbb45af0030fd2ee3039f5b6ca66873e3327cc21a2afd9f387c6b1437240b271c8a25dcaab290f39135cecb69dd2e0a9a3f65f260c51cfe96319824b8660adde710c6026387d1f0d226c10be636c3fad946bba98c4aefe753867620403b4917001f2b4fff0cc478d0b4e74341e5562ba6d2651a47de90c20030a537c50c45f0ee6772a933d045e5f7d10d7ca659ac42b38dc4dbca9b771289d553a54809bfbefc9b53a60f52fc110b463b419d1641d841261950f21ee187a63bed2ce7a40c493df2d7fe73c0407fef5e3e895a720de098c59db6e14d97a53d5942178367122e5a43146c84c583d5db8500355142918fbf706790d0a390b61ced3a3b70a3b70157ca76859ac27cfa5f6cd8758df7e6cf2ac4e1b7d988316666f35b0c26bd0d48dd93ea34a490b9df2c513ba4bce3912a0b70b3405c65ad1d97b03ffc342c338b30a06b232cf28eb80763ac3d6a64c2b75bd34a72987e84c37166b125e5f1787351bc7dcbe010c350a47400763ae0699ae1a31e07fe1cc236a9c806eabf4636a827bc53838b43b9495d9a1ad3eb841c20ff3fb056445e09952e2b66473dc7a6e854b630104e9fac4bf7785b22767bc04c7655a31ef823f72b70922a9e7262f7be319364c9b3a02f06f030c88297147509b0eda19a46ceacc3c9b35085bb96156a1c9952d4e2514dab284e25d5961bc09b65ce9dbf2289bd8233aeb46b31e4aca5ce65eed72ee68fdbbf1d655495f1a55c4ee202a8695c9855d0e27d24c7e1818275b5acdae30f2df7af23dcc4f239162cc669ca2c965c1d0f7768f267aa2d592eb21e54687fb19f9fc3d9a6a4c36a5511970db2f161076ac62ba455412a833d21157022baaa0f8351df4d2d01e5705e4e76ad257706d81f0b4502f9bfc992c06382e668e7e6aa27b048982d670be175addbe1782c177b40e4af3c58e6667c5c58e16285c45612aba37a4042f3d8b8f1ba1051f00563f02b304dfd56688cdcf34d19575c25ca50adb356fb6850e8bff8636a3170aa44ac45ac5f095e1f3cf8795066be38439a53521096393efe778133d6c76e8b7891214f279a1f2fd38ee48cb7669181ed1a837c6799dfb948074a196c6856752eedace7a5082edbcf986c56dd2582917ee9f5e134e89d165a75a416c3abd22fc2b75378dfa0e0415d4357c1467dd3df66e2aa18ae4871eaab77fc6518062764375f6a3de93429ce59e290c04fb9339ba3d5bbefe308aec5d737f4d7e8820d0275f4f87c53852d5fbde31a811ca7dac1094638858ef1db2689a651e8444363e2dc8fd223a5b109d355a9cc0581259aebac593b6a5451966db142e277b325e2fc2d0f5777ba9afe387854d58e933ab755bb8b96cd5393705d31ce4232e057d41af5ab42c1b2cd2b5c378a2e63caeea392659ddf1460035f99b08d1b47db0746288cff65365c1a13f7ebff2ee1fef8efd87617d462aad06750495879b438ced6e0203976fa3479c077e60b3b7d74083d9cae65170eca3c84bb8a1f319e63a1fe4905fea6b96a9623e4f89634561c722d8fd47f51370b27b18883eff8a19ce352cdcf71c40f8eda60a2c19329f979646fcacba542a06d7cbbedb405aadc429bf4a62af4ccb2f3094aff87bf6870c2a0ace4ef18e3d1a94ff8045bebb8c9861a0a02c8f1313e75262e43eb1e0d336224423217fc3e8cfa08d9220550beeb7f05ffe2bf185982b87f63cd68ef79850e532ba7f67cdeff6e3be5e8aae67756602a58053e1e7322432323bce8076a62fb452bbd68f0f850aadc113e3aab1d2ec558ace5816f5b3ec2901b58fbc1b6f68090a997e8904f827d51fdfc12c5bd824ea82f19bf0e89fc5a6135dea9ceb07cb6e8c3b2d8dbdbda8d138b22f78ace24dd0450d8dc75049800b3303a57e51594eeb56a03b9673b801900e92ceb687a28fcc7eb1e06b35ac3a379e8e7aa9316cb3e3e86af37a433fd7a452d7a1597be7b3679112251e87d2c0547ee35e8340060d1863db24c827dc12b9697f5b99ab9d4d376cb81bb81c624427f1183e3cf2cd919f317b96e6e4114c67bd6a0636de5fd13b680482deca185e0c38cb331117a17dcf64f544a3251aec125db3ccd3f177d16411f959ef7915142f5247c6efd0d41cb5b4117943f0e0cae1d03e27ce11ec707c085cc67d05669c5d04f5273129127f27a544182a67a4f5c1f9cf9290a62d111c8cce70384bd663309888930d25c9bd1c466b8e3c91e718c242e752aaf3878aea6cfc1796cf824445dc72a8bff5ea916fe0831a7dc259da74e48b4f0a7b937146268d073efff88c16146941fe22578a3871ea3b2c8b0eff00e86f1c4347eb5bd20868d3c11d7620137027cab297ec0cbfbdc98ba8f811028c276a3628478062fea0c49cc8c18b2e925af06fc0a4c40f84b67917eb408896e96ba9b43990ca6ce1ac3a55839f44acd19b1da284d6c9d749a819d13746fbb5cb33f9b195936df5d345f9c90509956065740eb8facc7da0c13bfe7738a6ae9e59b24995d4b66b8800b1b04af99f3e1511696913ec92db68247a9a9d07b08082dc2fffdb6c18dff5288f0861b779873be24d7d5544f80ebbb2d155a987aa2378d7cb56a6c549e4bb2d080ccf84384f78ddb9baa083eade9eaa1681602aebb86adc56c46e5887fb0344705efe81a081849f3cc411e68091b1febb184d88b37cb2ad9bdd88a2b0317da26924ad1076b031f7b4a3d87b161aabb02879a7d3876fe748589fd106780d9e05c016125c64cbba498c20fc5a5373ed7e8982a3c251e8077498d10ed37391bf07c245f03aea32a2e3e162e013b8ef1f4c245d1e0cf941e16290912d9c8d3237aeba240b2d130ed4483e374ad5bbe064c405754052a9f0b4127f90277c921f672a22105cd040e6898844a39cde1c36af82541620a5bc77c83910cc58a2ea08d1840ee81d5539b2045e0d13615bc11e28406398609828de186f05969a40a32dcadf37310295a1e74cb1636bc0861b64cf9a119052243b689bcfcb424432f049d63d79ffd1b831ce697e02658a0e73b749c76ee72e92eba0bb38fdac61e90f0f4336ecf48fdbfe3f48eec508a67ad2634c9fa290ff39c2a01332c67891d33e7d7b211f6546c66e5c55cd0a659a409c73bb189fa366d9b19e637993e3aad5f1ec60bddc014266a06b2a9706038ab2b783c24b62a71480f7c516d1985e2d9d5fce36d9422ca70c0fb3342f866800b0e7a23e38ae6fabc7b74d162892746716ea9120add7e5a9c007411b98dde59080f280b3c71a0fb8cb95f3fcccc23ee30c9bfcdc3c80e8117cf86616ac22018725a07f18c56424d62866a26acc634219990f541e06b9984b5c3f78ddc93c049d27f48b0d8abe36f205c06a16265433a34a6e9ea1efe10d525c59b9518ec93b66d91c942b9441f65c11cdbdf01e45c66e6a43fb335c8d43f1b4a6f050984e100a160718526a8ab08d16482d922c03f9834f1f0762d3f8e42b466287c32d1ba7f9f97b950c4ce4a41a35ee76c14ac5f5fac2330528f17a06497d382be709b625206d52e1ee46062e5ac6bcd5945c8e37458f85ddd5900ce05459cd26ef123e636fc30b98003732c78e54b4b70b5bde2e37da60d7a2ad8c6a78313b0dc7d54e3f984eb0a17d606e6dae93b71a7bf15a50bb447243e919e07d5f28a699b638af4b0e4befc415aeb4a4a1fd3e4439529c17aeca55fd01729a574906825f43ef1561ee75f5723b212a82fc156379ead7c8b23e9ba56fde58a8b9e0179f1deedb53e107b400a23372f3339a1e5e4c7db6c27a5f00f1b39e677849a50ecd1cf326eba083f7972a58021abdeb2153d02e90d542fa09a996beb1b4bb98b8f3171d96df9db69826ed6c8ccf4256f5ebc8da0470ce598591f6d482d2a418d5aa1555aefe0990acd46412ef97b95edf8f14f56549e36f6780250ffd051ac7333dafcedc2a5db1891b053649236e8fb0fa13c90d44ecaf0c62682698f164ba57508d699343cbc24537448479ffcecabb91eb1b05c05d050bf06097b930686a5284a38e2d3c772d8ad7a95b250a9e7e919207c131b91ca953b185d687d18be38a8854dc27c3fe4763c18588a10bf5f6fb82aa586903a02471d3288305435c5e99980336be60e1f08b1c782e05a52d974424394a61a57c6ac658613ccdf96289125d427796e946e76a3a60c04843505506b6bf3968b84e89a332d165341b35947f3e0a7117aef753ca6ddd0e62f7602830391090399fabf03ccd6f5671ad2c2bcc983f35b118172ef4fd4d98cbff0119adaf668d209c5dac3e1e8dcf794cc114007db77e25da9a017f2457a1262f0c626f51d85aec750c99aed78b9c301eb8ad7ff9e7541b8746c20d5db2cb202556162fcce788fc6fa5a12d3f024f7a6f05b2a47ecb5844e0bd9e664dc70b67e1897aabe20f80c82b775f8a9e95d6d11ada40de925157b2f8733e0ba0f5c2658d268f30a378457048d87652cc48b6e486a34842cec3d3c332423d590d80d77289289c1e3c15a373a1f78df9553eaa0348237766b63158577474a0f9542a46a26ce3ce0f5a804a1c0b2c4261c11ff269e7a409280052492891159207c181034df0a8a943a177c6ddc2544144549ea7850e843e772b964cfddb250074e758f22c4d75390159bfac4f8ba4c7d55e676695254d31a46828c2bb132fef170cdd7930028a9afb3a3ff217b568517934be07353a72cfb526507fa5af8bbc92e41edec4aeb0dcb4b6c71ed7e02e398d11d13ddf001d495559df8bb5b9d241919e99bfc2a8a84df365687e57e86a91b279effa58909d078b1ad39a7c2007edb6e7de588d2851833b0045450522262fba1c4136ead1e4003c804eaf83b5634bfe5876cf39601e3b589c31b62f43a8c73b885f1003a565db70f964c6c995595692aebe3d0e7c8c8ba440826591a81909babf5952951c9bdaaa14deb0aca46715008220261dba444098767fbfb6d09b013c246c87b32ead89154e20b6241407b935435d57fb29eb505e975d31b6b6d384cc5213f55b251c3a34d4e88fae10892ae0130d3603c4125d280738cac91a26e09bf104b45f39859e63a601a9d5140ac09c6737b06461b3459ab6f23f39dc6668502d52bcf66135b192b60cdec205effa64acf7197b86062c0e8bbd10c8b1ee0f0e5a6a46e5161f5ca19beb0d260a72c2bdb4308ddbf589e1b5524ed5536a53275a6c9ea96dac9541f19ac4b79497a1758dee785849370f8edd20708987c1c18290de6e422e7cf950e3571ca7c0a4f2003ff575bf5274b6db289eb899e0170c5e39f4eaa27b277b204db6d59be3eed714b8a4822183382a194ca848f1d9aaa2a66f1e6a2baebd8e531e42737413ca557a4b0ef425ab66d0d2ead68a3a85af603735089da07991f486d4d6bb085923a81fb39e34306265d4b0fdff9e375515899bd2065404147f5a36d319342d9a4daa4fd7827ed54ea42475590185a4722c0f7cebfaffb0efe54d9f3e3c01fc073775f5195f0dc47e2935c8fa977cba749f17cd751cd86dda7b387a4c165ab8285aed3ce548e2bf2b40a192e5000a48208664d85484b267c584cac4a6dcfa94e4e1b9826dc06a921ec02da33605e36731405effc5d17f88ea0d210036b8294fe5cb38ea755bebb9076564aa0f3953081b657131465940dd4a4c7f9b839a1320aeffe2f627ee7fe1f697eee04f4a1e7430e68185ffe0304ba1fa6c01e9c52ea9acbeb9b232bfd56ab0a85b475558d4130bade0eb15afd45fe67c1963628d8dc439f9adc4ce060460693b7eed2814ede30a27377132ed8f0eaccdfcad24a0e57d42203712220ce0ff5625b3545f9beac14ea84047e6a9556ff62911e140d9fd7c4076304d520bf67e5cacb2ee949227b471682cd720ecb1942d4ad9d2e7995247e976bee3b0bdee6420ac06b7515857036c3e10abab036d847a14833674966858fac509db2c2546cefdac3be0062a2bca3dbc8206e8b0a464b7901533aece2fce0ad7c5492052871d18faa58bbeba258e408cc50bc4b39439c4768b4ba63221308eaad5283667594a479c8a049a43cc4216a61ee29aa0644c5bc282f5b456a472266743e70f2e517083b924ba831ae531811075282a277aaeed9a45b787392a3a1c2be45ce5cab6eb8aa5e8acf59c548f77700ce44ac77189cbc2ec9512b3a4ae0bb6733ccc0603be0425d02d46a33e4c626d30a1a0170a8dd83724bb0f167d829011d5e3bb129bcc814b17932104333d42423100429b3e51d0fe50baaec32e8b1931674f2ed175009728d92b9a11ba56e106312e51e0c344d905d5c41a8492361e723596bdb82a926a825802a60e3abcf51436de615b8fd8a20b8a80ab875e7ab71255c324564265c490dc1a6989d6609510ae445ac587b14ca8d430819544ad63d070c5c472b37d806b8e662d67af9ab4165606f5dbd8953a91468af5225918fb11b71546e63af3c1b8701f0f56b34ee342761dff8ece80763ef4e90db75f3598af7f841f310beee8701daf4ba02d5302022b8e7b0b3bb70e46877a410c67817a2593b0b9e2407b7f23ba253fae7f8f8e0b04dca5edc05eb04198e4d306a9f3fdaf2c0c7c6c2105023cc88cc063c20f6eade482469de186fe868a74034aaf5b23c149de51d491f7373d977251c0033a37e047aedaf323ff8a3b8599ec0a073e4cbcccad00c874c055feb0025c3af28d7d6cf232b9d023b6eb5a97275044182b5f75e058ff7e33226f21b878e14a545bdc42167d6faca889a55186e01afde367c8e83c7061ba90c00b249c71ecfba41a1a16c40e06ce61acc5c084949ae13a7b0defd521184479d76a3b194d52e8a35bc2d00e41fe448ac7e25dde549ebfa8fc88d3b0db25e0a775dd17fe4f4e311aab0e7af5df89ab1cbdec5f020c141fe1c1e8cd16e049a102228ebbb6f0841ba2611bf1c50d9e1ec830bdc5b5434bf0c95d46aa384d1482a33b5627f545aa0a64087d3dbb8465c6d3822c2868214fead9377da792244c5eb52b35adad7c2c5a8c290243f4dabff30b8d1c605c65dfc5421221c92a0ce1ca9a75319589202ed8834a4bcd004e3d2e81bf7c7a2d818d2df2d2e90e0b4f402c467a29d0218138ef452650471e49f1ece81345cff73f861155511712c6b3c38bed72d280d4c132d21fb6a085f8459069f1b71737769b0e8621e9948fc44c9237c0dce1cd39e026d3c7616462e1391e98348dffa8d495a5327fda63d7af3ce2e4fa3401a2b5d4a876b45d01e63e1afe0f5deb7df7279edc44916ce23b6a08e1e9b2e9a4ba346a95b98c2783aa895f0bd000c3bcdecce2fe253f5b75521c4ca8004f97ed65e8a25a875c0d1de041fb788b6fc5913b2977cac4871c2508150527bffa05f7ee9a918908c7c33a3ebefe144452afc53ad6de8c1667c0f6b3346ef6f1b3c16ba51d41c8db63c49a6b84f3a2ee3cc7221c3ec272c879d33a9ef8085c780c4ee91f327dadc6657f5a16b78c0b30c00cf180405b000eceb9cba2d7543f209ffc601fe3903c68c7596a7b165949b7dbe2404f498e109df2a14c86dd96a70832972dc2c26912eb9abac982be7b7146981d3a7312aee89639c28ac85074c3bd365d38cc7ad0919a1833242c3a5281cbc1854ace95a9fd10d770dffd2051c3d2f42747b9d785ff36ec4fde35c177f793014f83cfb0cf64e4e76b6b503859662a1ae2a73aad78ad25ba28e534968109204e919c82dcb06f571ba06d208b3a7c4249a141b384c624c555ebc5b12ce977dc7e6502094a3a42558745f92f1f83811be8b0ad367c1ae8597d1b2ba8e236645c03bb36ffc1a537c7c63cff8874a78c7ebd45a9973367e8b1502c8422c7aa910cf020c51e18c1de097dbbb2b2e4cbf41199b6c296050b9afff3b2181c80c2eac266f8e83159969300d06d81dba66d768b77c209d4ba5f94bb212f464a62f3b9760bcdf8edf8b181a42c4a3e1c1859c2cd7320fc5409bed82b05de6545666e2f5ecbd342eac51e817f12b2bb15b6095e7cd4634d0d5d2ae1eb0a718a5ef93d904c840dcc06c63022bccb316c7521dc0738060ac9ad4005350675b4b847fbfca04cd858fc5870ed55018531e0d1e11083f8af0f492700d52b8c82ea48a04bfd9c5a114a6d20d71746023e36661cf378b35a9477db120dd795e034ff758ef59e10eee4413480b4852ded13b6450770c56177532136991b6acd7e016c8e8d8c901386a041f365136d3a27241effd8124250482d0f21b6027c6d2f3d27f0295da937d6720504e1c84ca996a134e15140c0d84d26e8c4a33a35355565e7962b5678d6540a95524b2d019e44f50223bd508216d9691411dea74561dc4f0352120b6c64adb94ade106d009beb6a02473a6bb9d5267f6da2765de9705c3dc4aa5befdb335de8b22d00f08518d504180f236cfc04446617954e9d703652950f31b61e0796ad71cab9dd4346d5b873920caabbfcc0527839711743417b4a2f8ff801daebfc72c0f87a18032267d834d1aced639640689090665c41bf8d9a2c6cb9811a9971f89c56253ccddb30e46d42908ac36984974411485412cc07225d694522271e57373a261a4afd1f6288ed4efb2b205f7218d646e59c22ceab5cefa0bfb6e5b8c07d6f7cbedce33d621b1d75ae5c818c4cb43a6c0e200650098b4ffbb3c190a67c8a04ed8d4256b3e708aac7d548947c82b6794ecdc882a5df3f98495433ed3087944531bc30db6028b5c7927a55828d77af0bfaac203529da40b34dcca31dc63ccb8a132a26c108219ccaf0d18a613d9ef9d42100c4c4eac75e194301c40b9f632fc8677f9f043e5d0c74efd97187ced91555a9f595d8c9183c7e2033d7208e8f3076897dc8a8550caa46c536406025c0ea65035911b6e4d838139c2c46a6cd0ea461bdd6d90b613c1a82803c7a4cdf528feeaceac9d81ac8dc43693e0a98f11268b9b63c2a2827992299775ae711c44b912c01731e65bb4d3c4e12e6bea33b2c6e372bdef81d1994289333760495896f9441e523a2234d4beb452a233a9a6469be6bb5dd04351e62badc458a8ea068f098d2c77d7464cf7110dc5a4eaa498b53bfc6a6a0ea3ef6a44399d038a67b62ec8c43eb312cf57083885868514864b0a16fa4b73962dd5c425c5d70d49e566112a43b389a40432085d9ec3fbe2fe5d31ad3202680dec1ab2ee037ee24fa4e5a5236b2cdba4ca3e4f2baefbc30ba2c087bfeec6f3582d06d415d8d02b7b121d4bec1571ba3441dbae5af46b677598ae9ba5bcfabf1f2b4cff50e738841a22df87234ca7e5ad39392d755f4e68c6bf189fbf49a334ae42b05085e481fec6a08425aeb0933ee018bfe8832267d7d7928805130bf62dfc9bc1fb2f8abef44f612a76e7ac471e5de269ab60740f084f387a613f62faeacc22e4ad32d84a618b312df535053978d2179376f0bd8bdf73e59b47a543e6f68904f7db3185fcc7279deced1baa1f062e2b160d6a87d02332eff6dffb126a88c817152c06809ea21e61f9475f3568e1a63c19e3e33eb19b01ce8ddfae1c9bf6290f470c94886379f3a054fbe32d8a34696023442c296635f80c25d7079d6e46729442814ac583bcd35cd1fc676dba2e549b36cba2934f9ffd3cf826a2d47f4a373f9834d015e16d5e1f0f82d584f5d179b824d32ce2805dd28c14a1dc4f30dd5ae9572b1a8ce1d56b84e4b61940ff2fb8eacfa8956ce0e3598027926b6a404d52aead6c7e6c337bed17147aa449f8cbdb73419a50c3d52950c1aac806408920a41c83f3e4048d8592dab55241cbedf84c6140a1dc294c251f4af27599b40616467ae53f7a62fbe98eb94664fd07a4f3e463d1c9091e5c77aa4f3daebe083d1bfb3b922fbd45e0f30d3ff311773cbd3f35b381effee7e50e871ddb58545892bbf85da86308087f4cbe3ad860a7331312bd57326a51077caf02d1cc99c45163044fb4954b5e53219c1a25335bb0f320f0f1e60aba97b54cd03a830394fd5b38d6e81dc74df76fe8d39ce0033ac9189fabf9e8376dce56640194d25c51786276a8d3b12a7412614c5172195462117a0d8a1b499857c7fed8ceb0c6b7012c32c4dab304847c93ab5076327b473d05d9a60eb27ac8a7c0b917dda33975795ff2e1ff7bbd97ae9475d4f016b770d7a173206d139cb49398eec138448377a8e445e4664ca8f32f6c6927712ec3a65c85292f7561dd5f3c63a13724b6e9bfe5d48ea882f481909a3b0de246a9c6735e153f9be32efc0f1bb2360ab6e42fbd48f975a90939092977915a03b6521a647263aba1f897a8d30d08ce3256308bc2afea2da4c56b328f68b2cec2214566e27b81e0fdc8520d3232d3093fb980b5fd0f2e48aa0fca16e8a64078b95000f44164aad4c9a8b15b2f7838fc5f61290d436ceaae8d542e1d1ccad379308fd32c6f5f8fdba95c5d008e3ce3469a8115008f2694743fc2edd4995d4f09b3b081436c4c731147117518129202b5c549ea1eaf644bc3bb877af9a92d9616d9374a6103743c61735d605a759329d908ad1951142466287d9310421921d8ab1d1aa01f0177b3368839c7144f3c6b62ac15d66a44ad326c15fa17626f613ee6ea2fe43ee48e867c89d04fd87dc91d4cf90bb49fa0f7727a99f217726f51bee6ea2fe43ee48e867c89d1e040ae5ebef3b985c97efc400cc902ceba6f6cb68f5ea844b39d6509e3dbe1db89f9c1bf18a8409f40fdf835201d6e83d9d597623badaf91b703e0bf836d81135654907ab033d0d40199267114b19552c1d5b46f74f8138d911f0cd012e3680a24888d6d5d95d62f2c89ad7d5f8f9e779d2c1c827704fa4deed7ececc923f090766a9acfc91b3b27135fbd53f6b9006a0fbb2274007a8ec5f0218f19a48c8c1488970ced82a78fb1de04792fff8694c22d13179e101d09f7b30dc36e2960f348de7f24cbf2bc4fc30ca11a2db6b661a232c14b59e668abff48a352f927cc66fdf80017244939e0dfe6e0a57239bbda070aaa813d41e88e252173832227335aa5d1f6b23c86df53414e002a430a826c937186bd06fec0223348ff9894d6985e7ef7e6c41c9870528b157ca6fca6ab5bc61546b179ceffbff1bf049968358f3fc46081076b21448a5f0b629834228bb772bbf1b17b3cea1af80221a292020eb95052f084843ef4b97866a9e035f6eafff628d2932ba995ee27c86cb15234423125ecfcc22eff4f7679cc1f968fc6b8c06aeb42079681a5ac95fc9e7fe2dd676296159f397b14ba3f4b53bc1f8d750163d29917f019428ae1d594f00cecdddc880128023a08fb92443754b290ee31bc056044d65fea024eed10bb068b629a34bfa4e05ecbcb2023ed8e66173f3e58952aeb30270b9b520f959526b49350d07b9e569dc6955f5724e0822f641b618f5c734f2046bdb1c24fc20a179f16b7bca08f9d6a88695dde85a8582cce250efe84566e300ee565fd19aeefbfc1966b4b28e805eb5b6daeda8c8e45730cf467a14d105895e66ac82cc5aeb8ad7d4cd58aea136aa360f9bd8270821354b40bc874647074b61fbe6e312d8e11a05f53353eed06eb87e46a95197272316195c3a7fb632f972c00a58a90f9916873c2ce17c94f3019a8e4a0ad699cc8414a5ee82c7073c43c124bda31bfead21b13b85bb8ff97caa3872f9b5d660fadfcf7c9b68b1070c163ec9c9d52907e0112225c99c6ba7900ab1a4dba39c4d5ee52487c9f7b3e75f96241f7b57480ebbec503aae70a1dbe677686064ec626bf09573b1adf6e34c921743a0d89734bdeccbde53b689e047a56af676b1f51091d0164c0c2617e10ed26603ba34e682edbaa4fddf5292f8a2237987a1bd58068a3f866792abaf6f866ab5a3b4d1c1ba301283e9c90df8062d1b5ad70f1a3f9418e1ce1323d49e67372745d1dc5714e68dcd5919213cab3d8671646013a496042311860c4f5267d2bbddd69fc5d4190dc5ac968beaec7367202391a30bdff4c07d0804a2a60e210ef4d63af5e566d6115e5e73bbe86f6cc6d21e558a397b4ecaae195385409f299aa987654b6588daf9933cb234db3ae27a7735a6dc0b819dd1c455d218eee3eae75d86abcd5a565a3fca51f5262920759573e5605385a3a4d04b74e6135945c89a765c3a8462dcd43d6307dbf393a1c8269c358b9f3ab67a814f62121d79d6244bd58d1bee0c0ceac0151966c5e02fe84752dbb94486ccc50b35e0bba3aa121b18a542106706a5a45e1e1bbb4757a0f22c63df3aebe585e70a00d846265ec3294a870c03a23763ded81e1fc06c94479fae00b652af2e50ef0d685fda3f2788f873d0788e589146cd27bed58de0827db8d156544cfaa8844c149a83e487f3b3eed1eea7979e75dec0f8e53cc8d53383cfaa74f831cd24bd8f770ed24923c65f6fecdbdc72c3983dd34027c707f94b59439fa4641e44629da7a32604eb1f7da94ed05a2b4cdf11d0fe27f190daddc0b5a2831514ec8a6b6717f2214f7b1a060c4025a20babd889f2f2c39bf54462cc1a3a648f5594f487f82848182ece367a5bef7c04b867a6b36cefbd68dcd14c79561cfacf5a48c60f20ca5789f3216c39a61354c0b86cbecec77035e05dd0f321189b9f1742d6cfbfb2ffa66ed60364a4867bf03d1f05301ae327f5dd0011d3f24ec049dbf6f985d768b6b5d68f1068e0dd1294483e75719134a740dc89722bfe3a2cf2a13de7ef20382e647acf5f023b8216f527e854ad3f8ae45f5f1cc22b6ffaa8a5ac0c90007ebe46420a174e2b939ee6aa973450938ee916e072c1626ee10bb744ed4e9704259365364ab2bbcf92904871c4bff61a056b9a11cec45d48b0f5000ec455c5511489333d88bc596ded7baf5a5d4db13258b52b771c5f06830781b8b5cad33df090fa4dc1ac014038ffbaba5a2966ba562cc333aa8c80cf64de1185f9f4dc896ecf55a885bb9edd27d30bfa129dbab9c7f74079f323763b06e64a2372ef02af356ac2bab7060d8acff0b3df2fddb3d380fa50035f387ce18f0d85249b5756f9f4c30fd0045b59a9eb0eb6d802f0d1a504f6a13c6ff638089de3c605c53cca9441254a1f10ea2f9e3f14a3c1db6d8942248af5fa3a6823fa4833fc140594de92786d7e3cae926a9786cbae74e797ff144c45b18d73ed19a0f6dc8646b17ac6663be6d0190897e32dbb7a71af5fa467f9cea8313524cbee9ab927ca6fb082fa53695935cb4a17e95458677fbe3e7416d7c9ad09dd2d8cecc31934f2d8e0e217b9f35d12a943562dc1fa4994697f8653f36930cf126d818d89cbf29c7a5983bf5114e4ad9903cf38ae7c9ed5048b2abda7c46d72b4813b16a438725bf267f22b014896fb2c867bdd8817ceaefe92e4749cf9b87bef6033774b1bd3308ce252c1fdaf201d3c5875f758145a4f428e604d25b705823053863d1a1f90edd84d14c4f946a0a75cb858bd760be0c72f27162584afd48f7ac3548a42c62dda68918a9cc1fc6e9ffd0edc20c198a10e6f61aeae8276f09af04c6167ee4233f4a024a2cc2e7306b8a0c159436458a6c21877cd59cc9a81694d7830ab6c2a5f5fb15d14b455444d168048fb22a0863bb81dff9fe49f12d8525aa09b80231a789b9de5857e70e59da58b11dcf34a2ab68ccc8046b4ee5b73945b1a5282c419b9f51ad5ab9943f78d0553042e8eaae3a40fe1202dd4f585946ad25458b003e0c5b9535d191db4201153e9b71cbb70784a57568e76dc533be5e8a5ca267959df29490fa13b740037e3986e5922948f8b627589ef9a986bd3984fb9c2b64441910aa015b72f6655ed66213d242b2bd1c80f30802ff6cc68ca9c2fcb2647e95c326eb5d6aaad52da84f56fa309a570c804501ad160081a324c28efac0314bab57f4f1cab86be57d3ee272176749bd93442f690774463f2869cddd49c5127edc586460829ede0accce6db8959ea084cf589bf60ca16c2bb25b6b016f78b1851a95a965c710f048cb8f29bf6c8a0baf7aa46da2300c34384caae4d21176326acce6cac8fd8e82135556966616620154ba261d3806328393e764f40f17585a01965fc2d939260e1f084541382f57ee5ee0c5379fc8d09763008158e5c1ef5fa2dba09f19f0ef82a77cde3d654ebea2bde7d936adbcab0182f2d4b3922ed03312e7665dbdc481e96f72fea856690c6776d8a99da687d15f24194ab9ccf47ef173ad4580e368061e2e8f559186816bef0537e5a9fa891c27201751fc1fcaa69f2317f776da4701faa6b57eb24ab7f8ba9b61a4361039d990fd07d4cb7e3f3d8ee1cee0ed32efb85cca6018bcf288ddfb8eb7fcc074db2b70d9d6d2ccc707f3c7f380d7581a5358fc344fe1971498f3348787cef15e12d80ee9d75a3d763d6ff39c487ac6034d2460aecaf406219f5a38e01b5d8d522bad0693181dd21b4237aa0a9120a58b23764bc05baea09a81bb1438b4a48e335a51b3a3c7a471c7e266cb0d353a5fc7746795db908466f775f5dd49e18b9f7d81767859117451857a81ffa812021a1c6d80e04aa007d9102432f5cda60fa9ae4a41cc32731f862e63525a36818e658638f0fb0d79454d8066975b07b8a6ceb81b8327b438fb5e1c9377ad1fc6318c5093f216ecc92c2458dae3eb41151cb888652edea2da719181ebdf23a99b424ed36ead26f493ed61f3a283d1ab79c126732a301979486956a391a6e47a789eaef9c275b50fa369888ee881cb10697dd6349d837a7a58bc98596731aafce171e78d9c0680c6764eb8e2b3bd96c009a7d0cc1a9f81b9d15c86d8b66b391ab84e8bd93995caa0eda5e00defe3847cbb08382154dc6026f24121589c4b541d7845f78826b2dc2350089cd84aea4286ceb04ff472bfd8b72e366d2eb6d7d5083c2a25cd235de42fd7dad31b815872c8290ecc1366b2f94912bce9a8247e243da8f41d042183b5760aeee24be520b7436a78d11ee03390ea7a49911aa46ca4f60a1f805e6a2807914cf6a3842865c7933538a079423acfd5a40733024d4d539b07ff1e71e37ef6a5f2a4d2280db48295962a72cfc9205bcf4535f91657726a2445895055581a670c4044709bea6800bd9a671aa6119f10a36a0df70d918040dd2664244a146032b198e6152c39dc1527090bef695974e8276a5a052c5bd08521463b51865a70f8dae742951535777a6894586af3382cd65911c3b923cc00a2b64166af76ac8f9d08549cf35d5ba8fd8ed4982b8d8b48a34023792a4b55692445a95429312da3327bce1fd2cfb47ccd4491176642cba7da7388b36c98c0d650f1a78b7db26b880031a9dd6bc7972447c0aa7e1b87ef0190630548b4474c479ac86ec0123b17f09c4dd6fd9cd99d151a2ae29b9df7994dbbef9203a1cd1d0832101d929f532351e4bf1ff69faee9cc2844dbee1f965f3c5bb6a2ad2eec21a5841d64f85e70095ab535f90987e365e22a15598162244d9ad1828bde2ebe9057f0a5ec982a153d4237f5b56c3734a12848c22653f292466f567e9bbe3012630fefbd1948c63998c5567178c30314ce75e2c8b8aa204fe754eb6184a6abd6b52056f12350fc010c4f7f94ac6f329bb3ac20a764020d353ba05c1574354b097baded4a9704f01cb78a1bbfcdc9aeb76f6106a5ce095d376756e33cc9dafe7c2036cd2fcd90535d41c62fd0c4c2f7987e32d012602bc2c9c582e334c41a036ddbe948499aa142b8927414395e07e26f9f298919d550b8e40c4f482eb7766533d988d401dd6b07cebe50e99752148bff3abac8d01d76ad2245f2386adcbaa5e628ff7fd02522b89dbaf6ec300c5c239cc21c5e060c2726bcf677586047f0b3820e0b7db7a5854cf40ca5487cdff625d8418984d754180fa09f22b1a2bb238dc765a93ee4145ab884d33ea5e972f5bc6377ac6975111109ae09194ee857d5936fe4410ab5ba479537d1334a3d457b6c711e4d797cd83646ce826bbb60efabcd8a9ef965c86edd9848ab3e5731717c6cfbe17212a7f234737a3acf0f0b19a8e7c82c886341c30915a5f2e6d1a5ca0259f9c051e451a7f2e9e93c7327a70744fdd27d1c7f062b481a66ab6a0e1217084fbed28b3cbbda567a2253a9a6c89838eeaedf7105f6660e5838470225c1ec0dbc9f73a02df2b9eed172d75f28dc7212cba58b5cd4bf02d5b35a6ec4e520eaf42c4ebdb114ca31a7f973434021ec966334285a4097b31f2678faf87ec91fb0dcd79af7b3fc9154dc750e7004969434d875c3a8d639b01f26001cca378b46d7f206f7c1bac9f4006513c958d2902a54123badcd85a8bcb96dcabf63372f64f4b01686940f58ef10521b5fa5b3be111dd0d44b3037fa5661ac35becf38d260502ade33aa6c1cc7760941e1747004603514addc22c028355a29b87e1a38ca7f384062d750933562471008890f0a2b2c60037453fc8d65bb993fc16f1515c932b9fe3c48ba2460e02f5ccb523fa223e6d8dd14df214f8d793a77648d12a339a403fc2b9a9f286e78b9a32c840aa1d220179f2e539852b0e96061fb701def37220d66b5c2c7eccd31936106b3d8a95748785a03007d4249c5d8a2b5cd5432f4d4146090f3273b3bfa1b73ab871138a277800f51f8e85af69518980eafd6119309387a150915664bdfeb6802d7994388653fdbaa0725ba869c84a10785705bebe9eddfe41cf8118d8691b488d6d80550784b5babe66adcb5734efcb41755e12d3af1fbe46958c7e09e686f9b54a728f0044e39e6da4ef1d7e91af8b5632d3ecaca005e0a1a942b4f7355c3ab2afea6aee26dc7dcf42ec01aa87bde2283fe029aaacc9315ee5b622bf92d46c4c8f3adcf36b3cb09348710ad4dff0211dbef4ac2dc1e61fa376afdfd9db335b602deace9682be4e36a54daddaef542223690e6cdf244ec40345457788487a0b4285b2092bbd3e30b8d1d24ede41c184e6fc5572118d4481e3c94d3612515f1d896584f3de4e47c2c8faadb43d43c6ca63948654c32cdb3ad8e24e097219a91a728df6b55ad0162f5d285f226128775942c4e128b26dec4441c7b91bfd4051912d5f0bbd0a2b7507fae295e3c5cb4fdfff498e87bbb5679e0982788ddbdbab384c0d529fa475ebb49a604340c0aea894614b65ae8f89e38539b2a801bc0fb652723b59320a5aeae58e9ae92f9df5533ca3570f7d620c530644e5958e54e809f89bda6fb76924846736b635b550832580c754ec40636f0752954a9891f8d7db22f47f9e80d27b12ad177a8ffc83cc3188d0fabb0d86684560d6785102371285278a5d440308389c9c6e9d3ebad3970f51d6958be4f5d570af8e9de9198ad5094bbe9a2fd24aedf7e5f8105ac344c76d4765185044832dce2ca93577a8e0dff031ded8686b8e8a753a074c3b0c9c991fdea404057a578f0187997c3d0ca3bac8caacb6991d0b6c0f8d7fa4d557b633b0be189b35c3715677644a61e796646d34e8065268cf19f2c9a5a11f1deb67b535769c40c7b3cdf5408c48626ff935eb1519b4bead4e94570657338878d7aa722c11353f70f3b762e04d8ac03914af092e3f534af8df7f74e4700861500757356071dd7b8ecb952e88b940e46d8151f45a5c36d195a8b6001166187949415c5f264cadbdeea00f8bbd6a3e4a5e7d15742a340c4d16bbc9999be2ef35e16a5be18b82c924ac7a46b936ec7df6f7a5385284bbe8605562be462b0f575ef88606312229d0fb8efa10c560162903a98f4a03b985a0e726cb83a1a072382a0b01316d6e9a8361825443b9e90e2c83c266773f147fb434d43f54fa862f62d3720219969040ecc49a9b1545200e04c66c202f905918fbd0234e009643cebca92f98f5504ccdb47423559ed87d9871fcc050a79cbe3d958a94f52b491098ec9532c9f859735e4f3d3a783e6525927d5625ee47f2686bf640527f47159e7074a0dc0784d5fe8c87f3ad0c3989615eb43b497f01a0dfb2c82de1cbdd5f34e342d87d60666038395d04d4bc4e690152bb5105a8da52c44d02d8ae4f855ccfb0f562b53d8a821607aeb34a47df6bac1b09ca19715cbee8f2ea0b6d917070af41c0db339235866a4a6ca28b7becdb454a4982acf09aef94ec077b708d80ed22624082cac36aaa1d6877850ddab16894a98e41aab58b8d2219d2d99312039e2385e3e28a7469729579d72a0a035e1a6f7e451761050671880e3544d754bc58451585f2cdd206b815e944665a43db5983204dd16831650d6d39a2131a7eab227a5caf6df3907e44655f58a3db168ed4be6e15a2c1d5c3bc32b233c82434b188f8a47f6469de0c62d5d111fbbc802fae181e571f803dc816da3c2ad6bfc2af34dcf8825cdb0aab0583c154ff58c722e10a380577dfa0ae22792f46ac1dfd975fe2e77ebbe7c0e768b8f0e9a75327d9924d1735a3da6ab683b908e64636ba74048e183c5c4f0ee73986e2d48d540c6513aca02f9aed9582a9616906ef7a3a14b42c9d89165a614506ab65d92122e3066bbf50b5cca158ea80b989a0464a40ba6a148c60252a9dcaf5ee0f60e208ae83cfe74f8151c746c4c642e63d23864fbe94828e89d5585bcea4f437ca08b4a087d3d9679f100206270d80f77e142f4c1426a1f264c8918cc4636f21dc3c012d84d59855079446828cf2e23b0bbd7cf8c718cbe8e135cf302a78664d8e20b881a01980df1209417897de716ecaf387d42889af1e6744584573c374c955779bb871e9b131295eaa6e6356e774fe1c5c5161d082a046dca1194dfd30d662efaceb4c4e782609bf29b9e47cef4bf39f9f18c59dbe86a1622fd135ada457cbfdf4780aba1cb402191adf675f221577fe7e8f5b1b3efe54efd1a0f4c0b104bd214c1f34b6e11b42e982630d7a4b983e68ecc33741e90dc71ef426a61b3476f0ada174712c5555cdb27f2fb8bff61ce0a41ee7b73897d86def16161289681d973d1118106020ee11ca0723dc063da22f7b76b2080de807f34480619fa0ed581e77c53c6280f842c303fdcf8bd6e3c74cc624944bb7974c1d4d2c2de2888289b7b6dbefc265040d176896014ac54ebb2ca4956322c044d99f35ef130cc34613582708c061ad5187aed7a82b2057d806f69bd5df396462b98e4fa0bad8537e7be92c3a37341fd82a1f2c4d12090571d8723ba8f68050c498026477ee2849c4e7894f01779fb9f687436bbb5f15eab1b6282e920a2256c9a7083a1d45882ef5da5e1dc5194635cebd5869cb5ffd2706e18e033291656d1f4a79a97bc0227abab1472692acfdeb5d4926eab4dc810a0fe112019a72a4d817f161153017da23f7e13aa357d24facfce5ba354dd4012548a8bf8efb0d74f64884bdb24da3fb476437eb6e5c6da08e849124bd58958b84eedd05213f3b7a75b267974b87a4abab6e0be67233b13f5b02a2a959eb4902187f079f770f92a17337f857f1b7256e2c47becea686b1095db95b72f6d3054488a1563c4af7ccb86d414bb70b4d31758bfbc1d5d1edcf8367e8d72d7e5b3ca56c39cdf5edfedca0c34a3bbb1e8428e1c4fb8fd85dad95bbdf8c996002cd6fb895f6eb48f52bd1104b94dad48fc1fbd60c618f1da180b725a1dfe710043ecdcc46baf3dfa7d73ce7192172b016fdec8101635aa91237d4aa1bd6b2cd74b8dcb75aea19faef3f42d0411a72700cda56b828ceb6af8ddd2542049d65725907baa0ea70826835add125e864ef087bcc3023e60391db909f1d193a9a189f809adb27bb3b15e425e512d43220479cfa3b5885b78e2fd149439f89edd42db20c6bb54bde0100d66a82890e071841638281c39505513f8bac30fea393d2ac23e32b181ce2403ec3f16800e742ab3a11170a713ce451960a8c5ed409f3ae43e3e6edaebbde49ea2f2ed6ed9b6bc9d260c033ee14c0b85d430eddaea42db0daf8e876c506bc66aaaf5e59d11eeb87195fb62a7e68e5c8fc632d656201031d9f140ea361c2e11e6c1f86192000b1030e0f717651b8ed9a9c21fb23183505d765ff2952424bb9a0779d9172e848bcfba559f8c06ef14e38943241e6dd99c0a89fbf07e39058ea56b55a7d1aae72f724822cfc0e3a5f6795aa08c9ea8dba33f1916e3fd891a36355c659d01c8ec839b1e51ef75873919501f748f291cfa02ddf76b04dea4e2069380bc2eb68193ae22104b36ed3afbdb85362bd02ad21483b25a1f0e01eb744cdf481a1580ea7da32b556d8485f186b1dbacabab8f2ea65221e140b2484788bf2a96456ce9df5c4c174b906a5b0df801f20d5682b3592f1c971bd17a171de9aae25e31be92ac1bad2214947366d89b2c4f81c90749aa8b0fda87f735a8fbed918c7f1b96c631d1916682ebf86a478742428195c24a51d85372156b137608093db3e5d7a447da4ce4a3dda8976527aef943c045ea2e3b0382454d831f90ae864ff92e8b45bed8fe4cf159a5a36cc88ed1892d8d68c2dd96c552c1f6de06be8802d9b7dfe69bf5283530158d7f635e129eb4a02026b2171784934e46e015b8a09e52cb16766357b024d85382165b3bf4edffb1378b7f14bde3b141fd1c477392c3cc8da3d257167a1bf6cb3cb9cf257bf6b48cb2b60447cd46cca0d225b91d6b4f5b68a940e4a1ef7394a8c760bf2fa31641b94a70ee22921d1a7135b60153270a69b1175761a677c4ea563353e311d2d806e0ee50d5f734a8f03a2a553cfa9b15ba1dcfc6dc2ee4d9035802fb5974a67a10d8cb286b3b30c4f2b289d9dd5593a12d72103440f726ea186f3df08b11f493d83487acdd254654e93a75d2d4bc1a405bb9258edc574a1604558865e19e11098bfe2830ca768a5218cb942caa64257cd00177e812ad38e82c78f7808a441fba3d25ce2178cdca2a6cea161bf60ee009af673b5f2a44caea16f40784755f45273ade457a199577567d47b611812efcb1e0c097c41e5b89839782a845b2e3344c66374da87b62ae671f6722873a4b26254903e56ba86f925e6fce9da05671976a09b3f10641a3e5154c698bad0ee462a1191bd3a263a8802b07c481798f30f025eedd26b33a64abd0e3081d3909bc5fd4deb15a044ae985a1a8f9419f380ee23e71fa230102de25bf25c57a615252520e7cad843be453d71652e4c85c0fa56e600f70b2ae4f3257d99c1a47e67f9321ae704d6ed2aa0990569ad1c071640574da4ed630103a3ad3205f7bb34b6e53e18575e5830c52ac220fabf3be5792c25212c89511f7fd9638ef1fd4cd23fc2ff6c7deaf0be02edae1f3d6d02182300989aaa1fff2b59df019842c55754f61bcef0e8f468f34f5629f948b6c179d31bdcb8c4334aa51d84cee1f683a272cd760a1cd43e00c0528774291739eb87e55d0966995116e119273465bd7be3e79b766c1eb3c52e299e9b35f2416dc758dbcf62f31504fa7668dcd5309b29639f3a453da778966a2430e426c906a0250b4a094a41c1c20747080972c1cbdc72185b68ce74dd5e586e7f179b2f85e9536647ca35ae96b2d8008bb19c709db6998b2b6326d5857d65f72f036b923ab0fcd004a930026bb1e7e5f701f2ed295969864238943cd00e5f7a2238422d8403ef2fdd36c060344f043e3fbe336c0cb26ed78cc21e7f8576e7a6241616fa9401ce22cdeca27843cd9575248e408b052937f9eab33f8349c316397f6140ec607711a3091261e13fc5af6ca9ffc8ba5ac23426fa53d6e34c9f6818c6b2bb71016bb891677fe73b2f1b0168171c8ed50c4c7b41b6d1cff5161c1fd6efb7f76b5c7020400c5edaad3722ab30aa4f61a572827142e7ab15820b9a71567c7e0ad21daa2bbd532d1a7b882b0c131cc662b8cf868881a7dd6e9e3b4fa0407f83087c22fc4997ea3080150b5ffb7e762049e5797f2d3ea52f32de8b8c76b5316631616eaa421bf596c49b7a363627ef80fe46dfe2ba51fcc84c6ed66e7833d6ba761bb017299768216745a4b60936da821f0c7fd8366ef52ca672a7416a99dd1836935ab2e8d25de1a795cd7e324a71da4a60f611526bba1c1f0c9499341fd030d0e03735425e342093a6c62318038d123235427d11653b2813bc73c2a8c4ad9a0fde969041858f72814847e639342930f0a89c6a19b5745f6058a52e9a277e8115f7d4df53c73fd264743c2bd04bbe82c98044bba1de408398f6ea7c08eb17b5eb30f85cc3bddf24d39ee840866b63faf9578f9fe1ef24d689f146289c7753a1c0260703785d6d6bbc59e642aa3f0f8eb81f7a2f7da25f4e30ef3a1eaf3eb86d8df04ec99915c41da85a1856cbef0e3293c88e65009b1d14473efa09d4a318e418034af4c55e5a50d815a503c51db83d42ba5da4ffbec1a971d05a2098ec8073f205c4463230fb0db4299697f010b25a8fa93ebe6a731606807e13d1efc8cabe2cee50b53fe94038f499cdd0a3978ba0df066280df1249c8de7b6f29a54c292519dd05be05e0053cc4262a38536b9b21de830ea55f3733aae04c29e52597885486982a382a433895219c8a1073d7b99f1816036fa049f42a437c583e7fe383f560114d1008e542d9dddddd14d04c4949494999014fd5516d069eaa91b82931d8be5260a385922aaef75a50456eafb0001083b99f07e38b07630bef3d185c783735cfd160c28beaa86822499da13a2a96d8a2ce9b10ccaa87ead443eddfec73722d3d7c6a5c4b75a30713a6250d60a67daea8fd311bb23dd47e95eed7bec61180c97c35f43d73957d6701bb6939e810362f2c52976ec9f207a3a464a6b9389d256d3b7c738a326a2e4e6749bbedf08d3f1821b38bd359d2b6031fb38bd359d2e6cf7596c46284e6a2c3ccecc262c4dc676666e79c9218331e94d5e59919f5c669c769c769c769c769c769c769c759c13c13251483be80d38ed38ed38ed38ed38ed38e93128a2152a12f78e3b4e3b4e3b4e3b4e3b4e38866acd0a02fe0b4e3b4e3b4e3b4e3b0d0b0415ff0c669c769c769c7b1f114a71da7bdc2c9a8374e7b85435fc07921012e70ffc0dc47a2bbbbbbbbbb542a954aa552a9542a954aa552a9542a954aa552a9542a954aa552a9542a95bc4072c4723776b79e420895df4f53448fb179e3d6fddc6fa27b10945354f3524e8250476ab1a3c5e5d7d5bc974e55992e2653547e6cf330993e67f34ed307c441547e14128fb86b7aec665a23a9fca123301c068ce685213d2b3fa8babf75a956a43ada35a6d6216d49a6e63b3164b443a9c237bc844dbc046f9cb3f3a4060969cb3935d169534de3e09a9a9a9a1a6ea2e364279a4c2693c9545353535353634d945068e7490d929b6d734e4d74b66ddbb68d44229148a4d631f18dc96432f112d312f079b7a94d6d6a539b40a118a2946d73b6898e936ddbb68d44229148a4d6d9d1d17952c34898f4b66ddbb68d44229148a4d6699dd6691d9d1832665c2895246d6e76c99a826cdbb66ddb46229148a4cd3935d1e96ddbb66d23914824124965e5a2717d060a62b9275de33b5be3d8b66ddbda666f76499b9677dbb66da3315de4cb9673bad909321afd8b443bd2c9ec77da9bb8437de7f98efb4efb8e8d4b25c98481c9e49bc6c17f1ad5afcc2f2ec79d9eaca8366ffec64f12e381d5c752c4c923e59c22d1ff68e44e9c03ab0e015ab02c3ec1c064767ff31af1e10412fce0a40b2054218b033c28d4f7d3299145f7c03900aaa73a2a9498c117163b0358b30bd3fdbeb3c107d7d00dc3a3e50e58cee5d8d7fad9db3923bc1ab09cd311dbb9fd767db1937b6a6ff71eed8e90e525dadf97324b278ff83dc77459a4f6cb6bb6f39327e373105e904a0e58cea7f6a318aa0b742c228f30bef7e45153123e08ffc9ec4534720fe9a7c09a5d98fd3674fbe09173553c6fd7dd576b51ba6e0704ab9db6d5bdf7febafb27a300c5fbdd9df7c6cac0e2a82c014a85612e1500fefb6b65d820cc9cc46486ebe89018d529cdab6de3dc39e7bea98847fdddedce6da152ad4f6bccfc422b03e4d1323f6691484a48e5acfccdfc4ea5f64319258d317a74c7efe38391c2f7e07b4afa06eecf5dc617f9f9d5c5ca08dfa5444a86017cf3450c087cea657f942d7f34f508e17b7ef5152f8216d86862c21b1b535022055f8412247802881a257a90c2a49e8cc00a34a898708b1a55ccd8842e90c0850a5a50a30713c507349090820b266a0c61564878e1021a3b366001136c606303d263b21633a3809867b7fcd4ee6dd7ddd86531734531b38cd5b5500d3e66f6f6d1efee4ebbfdbd97b93b2f737777f332a77860a082dce8ce39473587001b55a63b7b77f75d0adfbbbb76cdbb9bdd29be7d9d692fb2d7a226458428a38c123e2fc9089fe74419257c5e92113ecfd9811046096584cf73a28cd257c69c28a384cf4b32c2e739cf6194cf61c9df739823e3f39c28a32c9564cc89324af8bc24237c9ed3ff8364e676eac6c6c6669bbcf7832dddaa227c5685e332c2d7553c481d81c813295bbaf556b532c2f8b125d5d277775d7615523655b574ab8af059158ecb085f5781c5bc9791b2ae966e55f045abc27910be58854bf8ba8aaaa55b157661d785c5f85f8d6355382ebb0aab2faca55b5584cf0a42eafbf74fd609818778d547359aea2ef00acb72943a0558ee9d3a2f753c7693c0bb163131b7babf8a7ae92204db626a31642b0d12e01cd18a10d654d9838b10d7c28f6d3149bddccbbddccb4bb2ac8d59e09a1d916814030d1f5b36d5565f8db5a7617d221ed127e6d6c7e2c2395e5c3497cb6dda5391fa308fbc214bc31e198958aa598d6ae5522beda5565c53e54af1c2840b0d462f98bbb297fa30b53d8da4e4d1f4a22ef8fcdca1aad82aeb506d4e7eac92985ab5b9444935184b98523ad722290c4c263b74baed17a61a987a306da61ad366b2c2d4019a6a603299b628a60643cd66aa31ad6ca39b19d024c50c500f3a545b1253831bdc1c015caa8d46dd1eaa8da52e9561722da4a9d19061aa34742ac3addae026c334bab9a1c56059d412736be51b9d3b4780a54095b1307580a72ad3c4d4aad3e95467a85b4551e56b209ce75297aee8b89627a606c38d4e85e1a6b2d4ea54df0fd9aaade8547e7ac5b0d3c5cd6e4c7989147927e656bf91b349b0988aae90eea7a89309d3ee523bd336881a5ce4df8037d547eb10e264d94921464c253286c964e19164b995badbbfabdfdf8a8aae65faf95bfa8f152032ce4977f168995acee2bdbcb8b88c46522492b2b1bd20f499fa1ece852199452a6e9678c170061c71d7ed3fe75ccb567b60a0421896ef85253987ccfbd6668c3c519f3b197f9fa2bab61ba4570a315e8626e217659affbeec86cb617d95b255ca0d1e715d2c2612a9bcb1cd4ecedebc130f446aacda06eaf2102ba49a91fa249490aae87b2e478a01cc50df6b38eafb94ff3cf656ca6b5fdf8cfa5e03d5f71a55dfafd321faf74234856a3660bc44a1325e4465d00f8d419dc3e1c1a8366ba416d54435f2b0812a79d82aa966a4aee321d40914ae7eb0de474739e7a4a4da5b3aab4b759cc4e59c73104208ddb7745d586e9da31afcf8bbae9dfbe8ff5ac4cb8585ceb97ddfbbbb8fce5c40bcf7de7b0e1f7c0fbef581db7c5f627436442229e93ff768ff3e5fef6511bc20ee3de7dc730efa09dcddfdaabbbb8314c07787104218a1433ac4eba35738e7dc8c20d6bdbb7b7eb098fd1a8b680996a4debdf5645754bbc79711c648e55583d92f8520b26287c3e17a0877174d3ab9e0dc7bfe9e7bcfdf73f439103eddb9bb3be7dcdd331f8ce48b6805cfddbd5f3f7cef457fef02a67fb03a70f48da4cb0bedf7de6bd992d2c0eaeff0c1ead48ae9627777776bf0fde37734121d9db96a47611385119be6a880628bca9486ab0544954654d9c8ee10ebd77aee877ba632eef9e153cff1d0337e5dbfef189db9b4bfeaf5fcee2f3ab3d9ca8fbdf62beaa15319f77efd775f547e05a945514d6e8dd80fe61cf3a2daf594e5ae2bd3f8aff7eb5deb78ebe3ff3d5bc7a40df9379ba1a9b2996b5ad9cc55292ae3ded5755486df3d9569d2f3fb9675659ad7cbb1f74bbb280d577f6ae6aa32d6bb4ab522d5d266bdde5d1faf97fb63997cdf0ad35526c34391eaef2a956992ced054d68cf0d0332d835975c5e90f7ef73f445573cfeff6c69ac2c2803c99a7797f81addcae3aff102a437ce62efb100fbabb3bbbbbfbe7727777be86983c41eefefd9e3f738a0c2cc796e584982c1ba02284b5a56a5b96374060f680fb2c6fb33774ce86e732ca7d0c2e2359515675599807fb78e6073451b29450e80a5915150ac9180a85d6a978d87ad2ee0fc628e58ecab929ac1dd785611ecfe71312cd898292120ac1801123060d8fdccb7057a8ce79d1ed1f18a57bcb398aaa2acbbd15125dd7f47c44313314039aef41389292a2aaca39e79c7318e61ede98bd0215ac60aac0a9a0602a992a44cc8b1d888a89a9248f2c0bc33c9ecfc73910080565c6a4b80b8bf1fc3099d967ef7adc87b7d72fba1f9ea20942c1623e9f6b82b018a6cccccc1c7359cc444cedba769f991f1217a379b10ffc3cef0feff480eaa732d5225097ee30e2e34a580cb73f185bdab40caa5be25adc57565f8ec97675ba16cf27c78ad920942b05eb7633a3ba2c9906e3e22c1482016361ec37a08a52421f18312e2cacb9eb3a8818076b8f564879dbc354dbef9fa1953adff127f85b9f1c1f8e83cbe883880d3ce21859ea66a1d92487d6f14d7cd880c383efdece3090177b10b2fcffff57c145ca97ea8849c308bea889b975e30e1eedac0e8ba16134ea6be98e2366884727235c5c3c1c982fbb2e417ad0c01575a3569926aa6e9fd2f75896e0428bbacf372acb125c3061c4230e4c4d5621474cad3727424841d42148c952fa16a5c8deeba0de5ddb2cc438fa1d836cb0e20a149da12da0eccc950edddff2e8110bf87d55f88d050c2a7c20fcef1f95d9e7af43b07c30912275a987170c95c1443135b7830ea22a433d111aac470d3c7a9207111ebd8a068727a1c3154881b8c38147fccd52ab0c879eee747a779a35700e8aa228aaa9a62b409c6ed6df54d3415465fa3773e1113f0df25ac79ca3dfa5c4d4664d1502ebb57d9a3357e41ba94e34a933aaa3c2899d951ff2b1c7a886bd7c23d5c276f07faf837fb564b6dbbb8bbdd58f619487ab4e663d5cc530aaf5705566c675f07f31905e6dc14ccb86ac6b814fe32f93d97f7f839a3a85123bd52dc562dec539ba5d7b60f8cae25b9566c4aa32ae17e7d036d003d7d45dd977cfc3d6aa5ad9d72ae5d1b5a56ba12eccb5ec43d15e1b39608301968d03f0bba43f246f60190776dd4020507dab91de3da2fa41882710e18e881f50555052754088e70efbb1cf95ec748188de7d0863165ff426e203330a0ec65a76f7a52ee3a15909cb39e780e450640737c4df65fe261e2d93ca2cd7e47ef7f75e76ecbabfc7b2bbbb0b618c514a8aaaaa252e795d18160316a345f7f7dcdd9d6a3dbac1a3bddcddddbddd5ff676af4f5f7d4de999168394d5a93681da94e63302eb1ddd8b6368275dcb3e8ecafde2bb2a55cc1e3b5c53b7dbfbfb034775cf0a8f579d36b34768af77c0da75cedd39e71cd576616039e79c734e52c037980ab797171717917c54f6fcf9732c263e5c5f9f35353534f0f3c5175f6ccf802504fb5febbea9af359219df3629af351029af3508ea825eeb23336ec4cbb235766569ac8dfd5f199a844f35296d504dd29835289d91d5f8194fb32347b0fcca7be00f70048d6f137f6f34608581c964f994af5183e5254b0d16fa66d448d25bf71295cc2b8dcccda0b5cd0a0bc9af95ae2c99732d336a50c7a395cc55ae35b2240d0219b406e29ab195065d61a12ea03446cf8c956cc6ab64aec64a3b6b9bba33421f2383513fe5456f3d2c4614daeab0508a947352a2acb7aca7c83a27832aa799f2d587f8a6ee5b9fb293a16c196849d9ac2aa7f9f918d9a7aa9ce6fc1899a7aa9ce67ee8650d51ad0235f43132acc2d80f513e613128fdeeaae052b5de9c0e09d35a6badb5deaeaaf5c642a85a6f33bd8c041313749b6a23c1a4041be8c6025bdd8731947059e8e0876a7359e8c003d5e622e5b5bc4972584baabb547ec50258e2c12cfa90b816f9327bef33cffbb79bdd06db506dac7aadfaa51ad65585c2623c54521e0a5ba6867caeeaadeab2b6565686bd1c7279de7aeaab6c08cdac580c65613650d72283b65b65f63cceb5acc46262c78cbf43bbfc1eaaec04239e85267e4a86cdb4511dd5e8798da5f68dda6dc57f8f653760606259d4a4bedb6b15231f3e7f1c551e55e68bbb099b67da8eea28afe14859cdeb5e75866a887ecaa33c88b2b623dbfa2f25d5fce56ba2f932e7d77b58a9edf7197507d71f20245314b10384648a927b4e134e6a7fff3bd430709a4766ccf66f067fdf61be37a717d48626207b735a52db616de2c26ecbec9322ca9f87a2211eed432a2f21a6ab4d9f066a2c529dca1a906abfb5cea93ec093ea2e249e1c01f6fde3154e477cd238fc3d16a1ba472854973694d2a99adb9136b349e3e88fe749ed8f4f607c5a101521a60622d5fe5c8147fdd9712d3dbf3efad191f1112dc1626a32b6da75e9ea700efefe8f161f279c636d908290039a4b8b2433d71182bc176f873ab7a0f11e95f5f27af892e4d01e10f5c9d1a7b81c0270a3feb64423064200effbfdabacedfb3e8665f0a9bfb29967aacfed60be87ef64a076d5d5fc29d9580c4dd71f0b851451f870f54121051455caea30f9304c73c917352346d4f72ed3a40c8c2c51030e0fa82f100a8162c2ff28e91ab13790aecd0c8fdafb89b48e9184d345a2ffd1c845c8cc0e34fec6e84f7ebbfc96fe5e9daefc8032902e0087ead4078fdaab4704a22653029ca35f9c0d9c6301fc007ed98b7e88f9fafd53e34f1b5cc09f7b22169f8cf9bfefcb094662b3a7eb09e4c03ee88f54d07b86c4c4bfdeb23cefbc8da8284f5ce1092daadb9ae9a8c0411035e5f9dd563f6f7932d0877ad011e4578098ef178502d907bd85fd487910d53c293462318e7da8663e4c0dd08aaf12e47989c57864ca07267ec462a284ef6a64eaa23daec7bec7ac9e9869f13f1a0dd7948720aacd5450a8070ffb454d79e75a34ec237603ca0794c978e88cae3a06643f7e4ae679989ed94c6825521ed7630e4208210c6532fcd83706e4ba641713be0c7fca6bfc28dfa0f73c7c944f01655f617f3e9eecabe7410fb11bde7bde7de6b9daf38e47120ad3f34d2596f18780f063efc11ef416289b6f392c26e5419996427938d7f279e75a3c0f42c9e683f6024dbaf2e3f3d77bfef2d078d12c0bedc3cf5e425cb5dfbd5d85e1f744c05bb53eee8753b4aaa82ae6568a7a18ee2cc6d6a672ab2e8b1e31eac61e30e29a7a0b194588b790524a29aa548c31ca2d9438f7c54df530d31e920a7faad476237e23b58d98aa7ccd0812b55f25035fd4a61ae4c1dc7a6d0544adc9a07c48513795ba42f6a05125a54e10de4cd12ed5e4576f398f10767d7f5fd4f1e85d376c571e1d7cd9b1faf854456fd848519092d4297920f8f835453aaeaa89dd2b930f3f46195d3af8fc7386bcaaaaf8f0a5942b65c5ce0367bd6772771d13eebe5afc1e2b5951d5acaa8d102e101b75e166b1b89f21989d11bdbc2ca009bfe8407bd9c13bc5e66c3bececbc8f9c1c8fd992f6a671d010e1d1d41cbf8f16659712e69cd105ee1186d8a3c3189d00a13716acbe30f901c977a02cf350ed0155522d3e7462db735955b7b4a86eab0a52a5745654ccf9620bfe0dce111d0ccfbee89493aa3237920070c0526ff14bf81be4e10a48f592a26eaa51dedd71b455c76a542fe7524eaa2dda906a37aa7c4085bf12888d1adf799545aab5af887eef1b245373db15842dc618df488dee326edbb609a1bea24e2819d7e49b695785ce4910b6f6766f47a2b285a9ed66053fc138f8a790564c211cc1d43aacdf96738a44a691897f9364616e51b5dd5c10b6bef142fe36678b88d458c5483598cdad5d451e21e7117b55bd3f3b6d51a5a47c29e50629f564343120f0657c2a6f702dba7d78f11bec3a11d51a2c6abc274c00b080c1104401c0020658f80073646e0d929a0b8bad699287746ce0114c0d2fdaccb3a9918ab935c230d6c3c1b0a5e4c6b2a99e58364faa27413e0934e8a0be57a75a4bf693a0003f80b544e340c1a584a9b9ad7a4284263b30db36b2965437ae853f09539324d810685985ffd2dd0fb7d92e346475b3212bc4b59ca47c4376d7860f3b51d45e3a93d5b6e1c30e14b543709aa48785e55ca6f56909236795926ad54b261e42f8707e8dce49bda4a4e890ad9aa83625618410be574885f0e8d1c9a3194ec70ce3e8ef17328386e30adddddd310ee4404e492a70a76a4929bfb34953bd4875a75acc2414f27a5c4cf89ae8abcc64fa5ddb7ae9b0acec06e3e0af963e17f3ba81bdb0dc0dcddaa9fb8c833425e1468f6a13788f6a3b541652f955b40ce854a65afbd8c1d4a0121e1159e1d1157e111baa1c1f9e2493d2e0d6fb6be2fd4d42fef6de3caa088f36871c78b49a75aa4e95ca34e745b57860e9d47d151f36d4259b638b70a3e5bde111e4e74c67dca9f65cfdd95d9995734a32f96ff048f67565d6a9f773681d960e0fdc16e17238b7dfd4ca712d3f982c6fdcd86ac7b5ec5f57cc7d0d6e6cedd89ceae2a0e4c6884502e126d9239ad3c9617d1d0728e68abf91ea56f8e658c139bc83f068658f2421adcddef06817c0a12578b4afd2dbce8ff9bd325de13752d9b456d4e57f1eada96a2b37565e2ee05566dfeef7287bcccceedfe3e7a8cc7ba7970ce60ae1d1ce00c1d2fdd36584233b348e7e229c433a8bb32a3fbe9565d40edbdc2a5f733b95666b6a7aebd6ec91de81a63752953fc62375039fc3a8342e598c18aa1901000200b315400020100c088542a148948591aaf71e14800b7588406e5c3e9807b32489611c06316390318410420080088c8ccc900101ecc02562137ae00aa73c7103a00a5467cd4da7eb64ca3bede0adf3e1b58cb66f55d9a1b9d00710c69421c0ab99ce89f00d55c099e4f696a18ce0380e7e7a38587b2b55d120bd6865cc968e3cc4584f5a424bb58e4588392d5f3906be32e8fab3a6a9b4f868083e3ce9aa944d32c42b78fa526ae0be3326d629bf8dfac14fa580050ab8033c07fda6fd5474056bc64bb0ed79607e7323499d62dc0204766d7ed20930e8e73a40f99bd81278a1f3b934f43a68be3d313e8710e27839f6f5c57beb83c1f46129af0e31a6486f5cdcfdc86bd50c25089a6d3ded862d37cdb9c35e7d215ee4891656a30cdcc596f156f2194a309365e1963c4dbd7a79893a3b050349b00e3dafff629eaf5208a92940addafb4d17c40d5b1c13b82772fec1ed198863d2815d0b9618a43708ff23c2e98a4105d98061b24819c0f8ecd2847c43c221f1faabd98169aa0dc176f9ad460c84ab08e4b7ae35bb484d67030054a333b29848b45624f6c38bfd046ad8dd3135fc04780ea6c855dff682f4cc3b8b283c933a49196f44850c25e178bebd0f2ec387c338942e6456a6c89ffddcfe11ccb1dcc175f553a2c37573c90e22290941b08ae8399080d6cf6c9168e8d7864ff93766eb47b23adfa8d60950c0748539c664d29da68d4692628ccb65f60d05db7fdcca77836fd0f75622e58fe837704738dc5ecdc55caae58d120eff9ae172b50ebabd4d60ada6a809cfd8c1d878937a4131e52a3489642bdefb272a3ecae270e01817605be5f39a5e4b09c114f19c9c61b73dc9c6aed456f55ae191d84cf1395a37bb66655f92f4f14707690b9cbd9e9530f74a2361180e480e45dd1632f4616166b2a250f2344d254eeea81cb1cfdd5f27606a2bb4b1df3e062bf1ee0a5bf34f1b56c30d322b0b21d9f48442428962c26216394345d936fe851f27200f12025cda125ad467ea3fdd7f449980054003a0d645df662149e096f12916ebfecb6154be8cc26d0bfae1fe6cc7b95bd0eea4835181ad646842e593dc3c3b61f00939cecc840b0b248590e38a08c6944350b484362bfe66e7cc18c197e50ff157412c6f8ac3d52ce2337eaf2ba087acf4868ff2873f6cb8498babe7ddb6442add86e269e4063bb81ccdbd92a74b2ab26f32522e3b8cb50f9bed254900e5f6aab6aa71a2a1431042698799e3ce0502292be5f76555a4c97c74e6bb37ea20f2b0f070fc2f9cf13425255ed877821a83890397cf839783bbf0042c2ba49b64b36644a71727a3227a4dacc2ab2e21aedeb02b3afc2c2a24e7a28a71ddeb470e4a09e8d8d95ea510897107c9d56163b16074d6640efdbc1c57aae2f70c70f858d1cd1839e37766c58fbe92fd0810dd794829fdb26002af37a585217c92c04860b68b0458ec1ff5699f0d381d22fa6c49c888fe6b9603547683775bfaee1aa0fd812dbfdf732cf8671c4a4d2a98feda940bd0ebd635bb43bd829d421873edfe883669b804c8115ac524fdab58749df327cef7db71b0a1acdce90a5ac67957395fe8b27f42f09312c6063ff2ed0c2334ddcb5f04d85c0708fd9e08340ed2ccbdc4a5b25ff48b8799e34c07bbf04c0b2ed3fddde5c722ffcf8e525b583fc9502fe249472b65a142c7cfc5ec130a18cc5229f8e34c440dbc9e341ab4e11cb40e5c62c42a625bb18e05987ecff8124715199683a908aaa6c158bd77cc6fc618dc00464911b5e6645cd03bfdaa41a2f370982367a88596f1b7faa919176149f891b57b3de5f8965c886446c29202911c01b391b041acb8750a8ab97dc82ba518aca3981d0dd5e60c270675d4f77b3c28bc1637ac8d49a5e818c0eb5e2028982642cb5255d4d831fba44184d43dd1a19c2d52e619280d510b412a0f68c141759ed2ba590378a309b0829de9a8881b99fa7e351ae2359ee82517071844b4614b4ea5bea04c0df7a1740113ed021384322c524bfa25f202b47a99b59ce81a6d4ef3e04ee71d4eda7cf7153dcd3fe9d76cc42395a545f65595a919561377fb9c8a5ab342da16ceea4fae99da635ad76a7dd3276ef1c76bc57efacdb9f67364cdc6b4a898568c572bd760ed2b0171b1af8a09b2ce9aa9cca8d93125c958f5ba7cab572c9810a6b483a0214a41a83ddb5396ee60208d3ba7376b506bab9160e9b02d6b72e62ab99fc7324a167ca4d620ea5c7166ff8e5707190f07350884a5f335b6b048b13993b516395833ed832e18c46de0c87ce0682ac582591afb5396c2c13ffeaad83d3fc06fb6ab55783754f1dbab42c3fa43bf9c63055f258a17e6eaa0909d2714e6d64c30b8066e8c4b9ff66f44d19cf54a41f1719915b8c5fd1b2dc6bad0c420ae9b4bc9dbe5e29ea19d710ebed9b6cdd058ff41252542c6e76c23b037e021c7dac1b4025544feef064130a818fbd3d9d9e18962df020fcd20481d06e88dbd916b7093ee13ab453dfa20f49023640384f5d6c76ab3ebff07671d928be101f1d82be47a8d91f7b713d6bb74f7e30f7e9a850030b3ca1d14f896f470c465c0565311e6210ac8aa76614fbfbf455b9bc8d1ed3ed24118675ad4b871d5e7ba30827be70754adfacf3fc3faa41fb9624082d3ce3364eb650e1fdf1d2af71f5c971c38f329baa0cadfaedcaee7d92bfc755612dfc0e093f5d662ee80ed95d1a57467afb6e3d27265d37845ae8aed8fc63d907a72f6f4277af06cf29149d9dc690ebeb23499e184494f732521a7ad6d146b91729593ececadb717aaa00fc7a7ac9a50df92b2087695334397c8b0ea88a69bc6f47ddee2889ef4c8943e76b2809fd1401e4dd87a640cddd8cb0f8ee675b21c97b5386038b79d53ad1b21a0db85f4c90df75e883805e566dd0230b9ace0feb5f5b2679a10701410359ac97519bb13fe01b3cf056cbb9d73fa1d703235ce3de7b46486c074ab49b17e3844536eaefd4d196a888d07c66120c989b7ac981f65a7dc2f26929c3e428c918e92d7d023b6d713cf9df1aa40bf91f8941294007014abc944b4b420d93e9ff1e82bf34efc58a438e52aa0e6e0364d925e8373bdba4c044898bf49b854b6cfd820138f7c35b3e5a99136a9521e954cc59b5184d11740b78b0a19ceb25de891e0605be27612113a5db6a80c177d8b0389fb70d3153f1763640c6eb107e04a10619d43349fbf7ece42d3adfa7d3622118630fa30db9642acb7115d3cc64fab7639be5db92c6050a788ec048720947d570035c8cff3b19473106c136ac09f4070877486248002c7cfcd022e154c4386bc604cb32974f74e6f35a25c7ee66bc2a64a5637f73b3e7484f881abfce9897284661577f6e4f8c262a70510382838c3dca3458ff4761f776499d23f3e577fb256d7b3e37b4661d88bfcf7a1872863dbb630fb1c4ef0fa63fd5dbfbc60d4ae93a0cca8bcd796b429a056766140bd324be8ea8b22b25f858e01d2c4a2d5584a37f595bc746ad777231be2e1c26f280f4a06c0c7041ca538ed959e7ea06aa8fe67eb9ce588c2bc987dcd530ca348ce00114a77a870ee7314bc7b9921b8d396e688be69c0838d6695998b0af4a4d4388fe04c58b2368ea39ed4aad47793514381625a07e678d1f938f3401c3de4474ebf8742059d247b9ceb13c616bce8685e1d91e773354a4d9b8ae0127c44bdad813af92035830287fa27e41810d62227eeaf17b51410f0b881c7909eebd8c73d1788dc234c3ddd0ef46d55baa72fe0c88b146ed01062e6b16cb737cdbe8c6c84d008e0686698ea2be0660dc99d3db8a48f8fa657833db16a3e10d649418ea04b44160869a5209faacf014a68c22fe52c05964b16185166529463afdde998a2a53ca89edbb84051b711d9013984e56bc3d4ced3065b0ccad6337f1ec1262c2e7f4fe1fc22bef5fe718aa38d4ca672dd01e0c340562721bd0aab60260a451b8e80f01814a1e5c8327f412dc984f2408bdb360e49ec2fee956bfc6e16541ca7cf31d5cb4478675c54721bca0a0d42635886a4b112feb2ccd69ccb7646a2528d59ac543670ed0a04cc65faa16edcb199692b409dc8341d15361502aac036acaf443c620800505abd86a5487193f8e869444a5d9e3b549623558e7fab91ab18778afd79da1124480952299a2979a5c7f211f93b383f78798a7a6814b12719d8f44814d01c3924886b7e707e092200605d608569624c6939021c5e72190c9de7faa173588aa6a5dac0a38fd72f4a9d70dc003a42c9b66cc509786635670e0283420fc7bb2670c888bf467e113231ea8992e51dcc4d02d8ac58c0190631bdf45e2c7b90832d4fe26626786ee16a62af4b603c79067d813914dd8b81b5d55fe13cbb454882acab894085afa31dbf3fae0d5ebdf01c6a8e472e86184e5e8108391abf7f168f0f60aa40b719717e682c3c730aa4ef636808d54462350187b96a402f25602a442ccb6aab2cb03ddadafe5ccd7aca9aacbe551c8a24a2bbb5f5fcbaee2a8644e85fa0b7222d117cef5702ffb687b28633e9428be32aeee1caba6dc3c5b84e767fa5fc7f5ed7d245910ec4e1f4e9388c647055b288d122a3da8f7ff6a787649d0783770198be05be26fd0a6927f9f6fde2272b8aaa3d439bff9a191e777617de38d61623fd0d656e311ced655fa3c74c46da2bea12f20bf3831fae325f15a44dee59ffcbe3b723e0a6b2f09631b78fdaf1e9d86e4ace8734892afd4347fffd5218dc11cea009c6aed8fdbeae7a35755cf4ee13f1709650f3260a8245be2156db2f900efcd7b993292a0278b617a2c68c01a94a5852cec6b6b4e0c34c8d9fcb96fecaeb933b355673768b8db64ed7f5070cb654755266d9bb6fef9803c333ea9d4fb81fb42ba398a3a51a3890c2c48fce1f881f67c2117f993af76b4b2ad1105d4eaf39eaa92f1c12c79e0c1d12001e72b18a8dff185636514f5cdb9e815fbdd880b1c0f5192a1d65958469ed9a71602761b9ffb55a0f1e2d516c8c9c62cf82bab2fe0d478afdbb25bacf0bc208700ad0f5065f26e94618f4ce1b03c1e0bb6118591afff99b8de57b0a42dfbba7bbc8912f7c3311f15b5a50230348e92c0e1d028aa30e25c4a35d93baa0a3a4ee3857b7303eeb6c02882e3ee0fa0f5ccad7e0e2aac38198de7eca47b5741e578fc86801b9e8eb05e70d626992cceb79215be1e6672ebc6efbb53d37e9408120c824e50711cfbfc15ae0e91b9989b7f884aef5e1769383f6e67c06d8f5ea84738c0a3f36f2680313fca0a8311bbb048ef884ee417494e3b546efe30c0286494ed8b5d4c14a881e6600a3235c5d6c9485fb8e280a16fe710ddabad6096b43c3064b141cb8f64e40bd036196c27e1e6673e943f84da832ec601eefbaba8bb66b25aad22f41b1a834a27a0c82311f814504558511d48b9ad4ee70c296e091161c9d09fc177a75f3a7350d70690a7d17d95241328779e1198261a1199a34939558457bfba8caa2bc8631e1801468df229de11147b41ebcdb2921ec34372efd857d319eb7c4aba086ea98d46028ae460c5b6c8e5cfda471b8d352c089fe546a2e85d12b57e22c58e33a6ea6e61849cb3f82c6c91bcdc965bdfb5b1ff7e5ed3f5b07403163d10e8c03876e94755cb4c9472b27b4a0f611fdb5dd7c20e3c0ed0f285919728ab02fb68ad3eb7db454b897412957cc2ecede7cb35daec49bed8ca272608c9fd0c102a15c803bf909fc3e3e50828e73c1d3bf9ac9b0f6e889210434f279115c45720c00c1b424634f80e2f2f41db23b7a67d13cdcca8d073bd353efa612a9480588f6f03439172770737cff03a1e726cb32a62563e2e91f69bf0f8d550574390bb708e6ff3135c25baf44e7289e09ec954e3b0d750f3531064cccea243f9036976983f27347e80e44780f9421f6d69a5267d90397837c6e011c023def795e93798041d50f9b3b9c58f097dace323a92a08c6ea45d6a7e465750110056f85ee15915b7e938d879a6f0b00e28ad1de887ef72b10530b0d6259d2f06a95ec633aea9439385c51dae195d6112558c91769196875c700a65066a83f5e8a0dc800661b64ae0150e357d72ba9edcd9cfe802d3e385a209490d36f77fa45d21922475b1e1fb348fad0dee24998aa1e6a248980675d7d7428fc98c686b672926a751085b24aa0c44e46334b708d074237a1487568ca9822006dbf61d12884a4805e103f6781eac94c68784e6e4d125b02802e056aed55581d2cf58a264f5a4c4fe849b36301a2485dfe9386854afce4f037a4746bbfd12272ac8a01eeddce31cb3830748155dcb2cfe87ca0b01b86ec189e7452152e1b73b404ddfa21c150ba3531b412f1b74cb16c1c10e1a6e0d9c06c910d90dfb3bb7ccc6f4aceca2235e80557fad85bc619c985914a39d20122036ec28e6e7fcd6bd48733668ed96ecb19f040debf87c6050c591b43c426383afcf6a4b006afdc7922fe0b80f7fa50bfed6edafe9488c809e8aad8a34d0e8609bac246acb1b8e2a34af35dbc6fad598f968e584aad4296c6c1f3e6fcb7494e1c8f252eabf20f765c3aa7f0adf328768249714ca6b6a0c4767a48543d9c6b8491f088eefea43d4134c26cd6c03cfac3e22f242dd5676401182d703e25e31411e0216b9bae4a0cdbf3eb48a824f3f2a759b2e43f7293d647651488fef6e545d74d8290b6d7ead49726be493fbe138a5021b2f9dbc225ff9d585ba12555b8ee19f4c06599adb91d61fa995d7a1c8abb0849a8ea8b60aab1962ef673c86595d37dc8390131639e982d06b700259eaf65d91c4f8c8587d90dedeca54e1755942a6cae8a567ba605e2407ad06e5b59a23d7766d6a3b25b2701dfaeb775d57ff4c554a1708d76dbb906fc04414e424b9170951e7146e5423933e62eb89e84561680c9f6142deb504180af499791ddb5a7ee6ca1915413934f2a8b1eed42443af266bf670fe681344c1331857a88d5944c38af7faa42236c62aff0772a0c131c94592c4ef86f6977834ab78311c6e2bd6c67ac5a1ab5cf84b002d49678faeb605e32f1269462d58f7f6b5f92a86507b151801c463e71a9e508f17108e7c654c55c8ac754be86a784a0c25650ac492be48a23d860062d4c1f2a25291f342834c6f5808df8a3e8f46fdf5e629682d09b97c7d3724d08e8fb2c8dfab39c441dc611016e33970f1ac9b09ccf180ba1047d4d30fd4610105fe77700f5f980085ec584d810269ee3d06fce7f81095ef26622b7ef65d0961fd1ff998639365a09a2595862e69a2fb1b62374e662619f5092dcd02abc83d1dcbb86d0f0f99a0853261bb3b7baf435016f146f7e07bf9a3f35d605b409cf2cf711e2f6a1096fd5a0dab2b72e74fc1d5afce511b35c98c2c8da9a12970977e6d4a8e7d8fc5f22a691b89306e130ee1c2e517804909244d675c7acd4abe02f781d5eaaa9fa9c729b82e061bd513b04b806bbdcac1bbc856d39e205499502f7bf28d7977310a9a4c9aeab286dab83db8771e324d38b705e656d0ca04c51187731c3e590dad3eb95af4699076994575c9b4bd175c76b12738b47a66c9cdb4c3f9a66ac7ea721edfaed5bdfdd4df474e36d006c6ce3d4367b3098d9a2240829845a6a9aa54ec8f64cbc59891df66269da409faacc52b02f626da69bf1ec4e344b644428b9400e972e6e85806c3130a61208dfa5095540be8888c6f3fc4b892c4594386413b410e59383ebd173d543a2e98db82bc2ce4f2acf610aad507f7c6f92b0dd2313e342bbad8dfb71b3a4827d892ff740eacbae81f1ad01535d1ccddaf960bf6d1488a3ec18ad22b45f9fe8327212e024eed4207fa0f5cea64718fb191070598f562dc060085db967740cb0d5a26d4bd6ea370a243c974ea22ea6439dea0465141e3f05688f0e048a5b6059787fc11465553c4151720745901fd11fbf4f7599e952c2a2b73a7cffd119b3a0c283c00365d58b1c56d147b2482de5124f3f4d9152fe60da4c7aed7ad0e516bb3d65e176182a69b51da12694e9c4f6d4b16b26bdf0d56ba67f92f9760835230b862901d22bc1df129c9d10ee48978bab8c64bb5791458240b9ac5e830fc74d476d6ef98c8b9cd5f02a1aed497e7b53743ad97b73fce323b7aa4f592a3dd49767e9234fa39bbb676a80ac2257e7439c3f21eb0104e84fed2d563b6b391bce9c513a185860a6101f9d4afd2d3a8ae1bca79ebcbc0486d3673f11f369e403b1e8bb324ae41213a5350cfebc844273a1102f7a3e7161563d53f6153df035af3e47603cc759d8bd167f4823bf63a8c7aac14f82d5838f2454afb29b6ca2459e07afd1581d247397b6b00f0eb339c1499a131c87df070e78887b7a72f35f1889def40b1d1fc861c84294f5a9420b49bf659654979c86aa97332845fdf3e83da8053e5645ebe328da9f0bb5922f1b382171297ccac865c8c20fd9a220ba5a78f1e43235f6b277a47f4b0f6045b88079e5e28626ad716231e204566755ca46716582a61f0bdf9115b0a318d9e6d762f372ee2f5cdb23829740376a5417bcd22c01d3258dee163bf3702fe75fc42e27878f48a6d477fbb0f3fb64c249e4aaee9f317eed6655089fff965b842bb499b230008ef56bd62f1b2b31a0873a15ed3c1e04be31ee0c14e6227ed3b1facc0b4c2bc0317698623c75cc46acf457aed3a3400b840776460d346ffc47ea07a45e0a6b3ec49062187da726d29566ccfbf518d0894a0b3cdd99c0064b6b5aca8b2942f71fe9b87d56024f0ed1df1d73ff348b86f768dadd6de4991bd07768239d48cf4145d46fc29071553d47b2433a961d776e123d6a8b344560d7c695c1fb1bb79195a1611052c7910b1e1fc3ed10cb2728ae5199ae1a04452cab1d6af8e76b1a6cf960d842875712f33cdeb76a18ba594228e2701ad64930315437d1543e1a5701a00a6679060f3578cb567d6aa6154990348887d6ebe608a62435e82132253ce6e1e196c9b59e2612a4884415bc5d3157a96c97ad30636a89894382a7d64d1cd5ea171c4359987f3713552f49245ce5ca16e042fa50fc7db6a4e81c34f060a5e5afe8e12103b6a503f8a3a2dfb14b647ed829e16d51c14146c3782af4dbe19ac58b21b02a875d054e6b9db184657f02de52e2c00e08185690705e5c4649accb9e228001d690b22ddb4019cc65b851b509e58ed3c22ae2e34937e720e055b899bf2673f80cd10b699b785d3db75d0207cc30e244d557ae17afb29a5646f12568f73c57d2702453016262a2616b861e4aa26e5be516d99b51e41cd9e0e5d83a0d2b78fb44379b150b6d608e5f0b7b1f1aca11075170bb68aa22cebcadf9b654ec11df20e710ccd1b4340f1221045be055ab3aca9d4b54a6e11a5f6e0409a922d036c673dfba7b5e428e8af1dddfc475ded69dc133a83ef96e5d018f9f5eef16747f2a08fa81fdb088cd109fce616d09efa8182a1527436fecfdf58b932f7e2a10f7bfaa59c29c438c35af956d08e9e1b4b12cab0d959aea008f314c2f4a59ba2622b5eb43a33bd4855c14271e1274bbea44cff9e0ad0038ec2f28ecf48c083a5e94b33f21f6878192c94dc740271a8aeeaae9e86990b47906d3131076d90ff9334f02e6f6da8434f17d207de58ba14b0857eabbc31baf1a7550df646aaa780790317bd0237b16ed14ef774d0846a8031ce18cfd6fdf3126732be6d61fc53c0f4b521923a4a9ca5685cc17252c4fd35afb73ee41533fe41888bedd8e81262e7a85ca87862f5084271813f91359d005e35a86c68f4f61191e3e999cfe70932c638d74c0c2d0d27f5ce6e80f6ae455c6f96ef29d070ab22aa5c6a39cbf80a8441ab8b649d3a20045e3e1f4c0d998aa0c2f5e4430bd6212a34b19737987529e3557613a666d2300f2ccfb872030a178635b69d146bb5081298e2d273d99c726137d31ccd1104505cae38e14112432e937ae2efa8c962a6d8d28ceb61b931dd143283729509e61c8698fa63c86da10f6f72d3b065286004b9f8db5c57e4d9a3395931e91fbed26143934e5dac0730fb4379e47cec2424603fc7fe23d68d3770c1ed214ad192580059c875e143ca3bd9f53e26a42e4c2cd389424ab12ada83b25196c80c4e1e41a5f72744df4921e8de9e264df9e2fcf04ba7205d24e1d73af5d11f67d86ce86d865c8a70a2824656222b438a303e3c117ceac86e985080d45b46c4939ee6b8bbb4e21400d5299731c1f3020cce55dded194e7c3d086b0820d1819e4f501c561538de13c28052a95527caf8a5feeea7dd3f9a721c4b1d2cb5f8cad46d110b4ccf2b74d69c0a5dc18cd54802c102f921b65fc1efb1478988b26bc300abc69324dc87d148f6c842d46b3eb3e866a9f102188b74cf140219eb8b4db4021e5a5188cf272e30fccc2037a0237737f3bb23941a2255b1d1ce2b46e50539c284bb2906fb47786a4a9496946febfee6dd5dc8f77a1a004f4394891dc74e591361cfaddc17eb9b7a2a37d6ee62d530754887e902535510f5d24cc518b15ef6e47ed4942b3d6add868ab5954f5ac892a22147f0005b87c50690ab03138c718474ede6567d12a983a00ad0a56fad72c78481c80fa1a95030e398bfb8ee05881a4708e6549c21cf2ec96c50916f46faaa7a3c9e20a0c2d9a9e84dca4a8697fbc10ddef46899385ec65e22ba408c28b86d7b514c58ee833a233e53b84f305b44a8dbf737546295b27dd93fcf92ab8fe276c0f3a18a345625e11e0e1aa142a7fa86742c245aba0663025c9f18658fa179263400d4987a3a347f6a7a0c20aa94aa2f620e5c6075adfd2cadfff74f5e4c9bdffe66c81c4842d8af93c2242aceb1fa93c5f9a760af24222eaf32e05825ca12764df9cc87fc5ed12e2e1f08630e4b4c182bee26041be70a8fe0f7d4018086b9e257c6ca9dd9bfac67932400afe2f83dccbea5cf45b5578909b3fa15c82acedfcd0dfc647799b10974c68db6846c0613e7e15b4bc81af719da52b2e2c46913b3a608781b75bfa4a3c5dd1885e773ff1c5c32daf3fcfe52fd2fc415ef7a13b7b5529e726674389a874e768d43afff369887ca1bd144156b9a7f85f8c3b0e032ee42ef3fac80d7552d373243637651ed555708971bacebd5289947e789c0be0dfdc3ef9332052259a028eea9febb3d11ef5a0c19fd179771f57d700e1b9e820ce5494f86a298c2d1555034bc5337e8e5ee468b756f6032e6f8223b8f2eddcc2ecdca926320df4217baa8393eab2101fdff69102ea0324d01f245cc1b5327ac58c4592aa2c0dcc2dadc2220a5c9d25f5a21e8b182221cbdc05446496940a85d48ef7de27159dbfd08c454904d6fe510876b307ab976561e628b0266242690312101e197d9b3c079529b8d005ff072d8bf86ef063c3fafdbcc2c9f5f1466789a1031fa2b45716b5ba788f242718f5f37d5541b0b00b51bf0b1d84450a3b45d996a90ef923c6b430548a60a2a19d3f7b811e9bb830e4a2db4cc73b73f8626b4ca8d9a7fcd3386a87475df5cfed805185a56cdb7cb0b19cb56de9aaaada4e737016d8ade766ec04ea83f9d60644f9d0423cea0433c7415b1ec893241e80326c0f54fb87349b0b434e23d5b38ab4a40f61883c5b3a553bf4a2d2ad68739c31e0483aa1d15f13934b45cad20e050d7682879ec28062d82b58c8fad8f05fd11147685de03ab36b633ba7d12a6931aea847b6200010d890832a6b9804795a686b7e5035192c9f3b6adc68895b835b8f34448da50f143bdbb2e3500072a6240e386599ff8eac15165c9a179f5d91dc1dc1e90721a0c0d5603735489bbb2508709535291f56a378a40ad3195906fc7d29d667c610cc80629f1c95981c393fe8e496aa34b2151b66913e5ef0b165041790590c18dc704e926c4553c50bd90f378cef8613d4056f264139db532f1c71cc2f89a755a9c71eb0de71d26386fc6be746d2f65f14553fd8491f0791e0e26c1f0c714d3331b645ec4140e3c2b7a102517ccc26ea2562f11514d0d1a26c9cba23fbf870949b67a298f8c4e66bbd8c09c755fd110410b5fb303adc2f567ca28f4df631be02279ff6d42c1f88d7954cbe57067c180f7817ea2cb2c60b269b52bebba8ab5cf83e7a022786e09710af82f2ccf197ca86fe84df0301f307e1f9df56c193a91a6e5199d2df61d61dc652cff078690112b4c9e7f51bf03785b3247f60d429eee5e710c51b6100096881e30684a0546bd45673f7425387ac67086205e73af388f4f85843bb1363ccac34188b20cb8e7495cbf626d575325c6879efe5086063d68ce29b5f85d0a9b744a511e7497a24fcada529371bbd1307336877586582e7a064f01613fb4e56d66eda2e8d55d4691fa163dc3d8f286915ebd0bddb238897c84a2aefe602b11660b46369fd408cff16f8025f62e33ffbe02a1d7bab423821d443bce4c83da3e9699936a1271a86724828fa670a0a8e763c825a6011bc7bfba3a05c26fc4553be6912e524bc7b7aacf6d47dcebfc0fbc31b806c1c16035fd1a85eaac051455a1d47bcef7ae1cdfd7e9ec9d8340124c603a527e4ab8a7d96ad982ed8ca4076759acbac57497a73a220ba78cb68a5079f03d9dc9aee0d9ab333dba3b5548688d24fc2f1d476c83dda66bc640e6a50e71dfe7588d62412531e3d905550da321c2eb7702a019778866015857528915b8b6a682e9bfb1a0b5c8c4c9f96fe4f7ffc3eafe718590e3fe82b0fee058f0cfb3bb2606bd919f05b5aacb754a591504f8471919d6e6dc84a22539dc89fc5bc706fccfbddbbb2de5ee39f7a766ef363287874d58e993332fe20338e3b29197e03d5e0129bb78f6e5ddf4ad08d6ea83fd222fe793c94ecdcd6b377da70850995b92d97efc631620c1803150e08ca1e3203d8b3afc1c18a4d959a95216e9cf3725800188dda5ba9826768a6041dda8e45893801411a091485a39252082acfe2ec344f4aa86b619877e75463150c52a2c06d609037dc0286a3da74bc30cb2ea4311a2217f19770771f5260d9a4a4aea03775ce3810432b7ce032a3205ca902d7ba11012a15abe70089cd3dc8e60ef0a3a087e41ab1f1747151616998955fdef5aa940b0e847d7621819b01a6e8fd338b45676fe15d593d3f533dead3df18ab91b162663cd2061542837a5ff8595428aaac4ed804a92b2f4a926590f4b144f3d01ef54e3c6b7fb95c806a843b6f2401f0ce3362ed040b9ac5ba23355bc5ef745480d6158942e5ca3c6997f97695eb37aa6c6c0a7cf743a64c1809a5cf49a3ca9693ad903f1c59f41965a171319232e26938b9881ab0de9972d8965860b5fb6d3b24b7964dc751f2c07b85876ccdbe316814e2eb8124870994c2d70a2f9c602f06c098d2e86bc6a555e336c2d2645bfc72d3862e3dad1748d1043418552a24cf685841e1f99a149b121cbe4627c27800a921840163e606d68802174b31aeaf2598cf302a1ac007e42591583ca3a52670054097ce20b9e6cc7865c789d6498dceb80b786fe5a25b4215572557cfea369cb276854fa20f47ee8bf566d8653f07d6c9b3d2891db9ec155c6135886865e580a34f5881ff6a19c5875f8cf3418fc2775639060b5472bd3c1f07d923a83e396407229c3d561948dba2c3e94a0b7f0c14885bebad52e7c10151474a4e2d0b157906ca1c4d2108c8f76ad9002b876a8c1ee3fffb0b902daaa4ab68357fcbcd1c840b4c67403a78d07f400171b548411da2e8e36bb23c93c06066089b214c3aa3e5797d9545c0036b8a6293c1c5fa29934bc661b692f8c6353a1e524835e87a4e2d834015bd24e62a7e50a5c05d14693873dc1f890c361287876f6bc936561c2e29b192c956f3d72af1d32d6d38504df1a2dbb3391b59f23500b2603c869cec10b74e50276caf948e3c3666201e8f4ce29be5807b86754c76e6674ef284ddcd1a393a402284fd3f8e844d4bd2af7f64ab899cf1c2ab7b58df854abf849dc2ec118b8ada1859bc5a5a0e28d636b83eb8f5a7cf46af5b74139b269189f3200e029605fc7071153cd88c7b20463e96ca1efe2480fbf0375a8595ad604dde6413de5077d37470b8e969c327a5759132681f12890e158a8bfdbffd42bc2d2a637d36b20083b9aef43a8d9acf5ce8f78dcdebdd07483428af52d9cfe90027ca6948ecde4f2ca4dae4b8bcc5c52032f59e2cba58c24403a4437ca57865098ab7c9a064ed831ce7e4c5ac33b5131ddaab44e3d8e6715f23a6d601c8db17164deb8a7d9e809f8216caf139f7aabc5facc6b08f2d568b44f84d5f1d1130699b37de5397d493823ddc1c8b7550d27fabf3a480e42f4a625098148d973c9b6bbcf350274b10188c396563e0caaf3c5eba6d44b0a892120f679b88400b923de027a77f9f7372b758a5cc309d8fd5e58909f49b8d2870cfb93d358a71f12c96a48427a6fe8c085e64d04b6d207fd54b7413c039075a8bb7dd78fa9b8c3312e0fe7158d29229761e58a103061eec6df5e07c7f1a25d3c7815bd0ad4e14746b201e60a02ed656bce9433b49f0eb7a0c18edad64213f5d12b9fe5b580417707a637b2a806dd2161f4d77b3db2d7ae9f6df970a8fd8a78dd84fa9afb0f312c65dc95ef0eac7e526156998c4f1ef4f4f6625ba38fe0dd6a603c63f07cff632cb6a29f693a741c19d969c76984d0a2120d0097e4817bf3230eef13b300dff81db9f23a78c41e52f97cab4506ec4be38d2a47130a2163b4639b716c836926c84d6588e5110d0b28a597c784480a0f5e0f946f647fe2cf1d250412675202e13b01f0f813a6a23cde528ed50133290a99b81601078c0d1d454e6f560b5c95344d4ec95be51b60547e184c84de36d08bef6d63ef31a18a579b0be45e5fbc524fcfa6130dd173c218d9b59e8f097e1dbdd81efe5741dbfdc2329b3d78e2798cad84c07be3199c89b06e04c6ec27b79d979f5ffcff3e3eaa5790de05f71351b3402a7fb01462cc1616515339a7b1a61b6c4b79dd14dedbba4f8d16bd08ffeb732d3c0d3eebade3f5d25afba43710379991906d391a910b598dd0fb8ae545a64804565ca02e2473fce61089c6baf1ed5b1ffe70b2fc270d9cd7d37fd38939e6c351e48102bfab3b395d141ef5a63c8587b4b979d8ce4bbd06ca0a81575bbf5a52b7f0cc3f105bbaa84c25671e0fd43e50456a1b3991e2eeda12bbe7e746487f6d32616558f0d892b344687a5db3d600dd1b8050b3c5aba9b28b9c6ebb5656e9004bc0cd9dee81f56b14559102d62fce0c7f25fd6e41df05996c465ec00f4e4eed35beec27e3e8a1a18f218621db9b08c6fbd7933d1986e1cb97e1c50a98327b90d08fbdd1afc7cec764a34ec866121a08483bd178af11c747c37348e61d1f6d8502b4fbf8280fac00e72c2211b6067b8c5fad3dbee8eb73d66fdeb30b8ad9388e787a842cd903019b25bc406a382ff1b86424a845ce438e66d77f37a0be80021a1c22b2ffae60ba80f106381f057ceea72b7b058ffab2c05169144d9594f04c2f0ad6cb1b9f5ef463d37fa88be00f21ac1926b67d4014a6111a0561008ebf4dc8e7767c159dfd7c4fc6bc0971e85eba605d362ab21585adf24b462c4917f689bedf4954ceb05bb858174d5295597e0bad44c879a2e706a080fe0fb2c25fce7af2d5efcb0216f103fd4d71911b1ac10babc1774c7b4d326e5dc8ef3e8722d4a8856956f407cd283cb8c2b4c590310eef4e01901e4723e97e623c6d84ca00760a002f9b3c08406ce566cabb7fd602e1fb091ab75718ddece22481f8b9680483b61a1a518d89d5dad2be51add4c979c0be31d93d3370612bb959a1a081e95e06ee263c86cfaddbf8a38d4ce989c64132e588e953b240f2c455920a5aa1406a1851dec42402dbaaf7b45ea3b3c954ef018c6f1fe54e580cef31d6e9f93f72b4b00918ea688d9cc93f6bd42f70ecbbb49663917d411779a07b71034202a113372ba8cb4d2c0b80a94569a3fad08fc6dbeecb17ed7a8201eae762ab83d9b7ebe7895f4f40137f80af8f00af3ad61eb4ac277e2002bcecb30eeda5abb0444400ed6317d552e0fec61a82205b6353f01a2b71c8ed4b6bd8ace186ed97c745173afcaea1f27657b28e894b89e73b6b67337efc61e54d0e9d9a3cce46166b35453a704c9fa55bee46d0e0dc2b571709a98a7ba6000c80e62b5281b78391b2082e37e3905d82b06c026f72c25e8d9874731bb301b2dff60310b29401dcfb81012a9e30c233f1943814b90cf5fc50adbe4f7f3e36b49f0eed79d105728008ace0d2a700a4a06a7e0ced6d8d12c3899b2e25485bfac89062b5e0c034bb76814915c53a3f5c9dc17221e5566ab047d512374e34f47ff6640d07921940126f0d68fa0549b59ea8d3641f7f1ecba06fa9ac0d920b1e76e175e50f8e5f4486f28a35fb1d91303df43bb045cfe1ce5d6377478769b5b01adaea042e1c2e54804196c418794f0767453cc0aceb4b63538c1da1754a82cfa015d73b99ddb256254a518fada7223499950f244c718200ccd6fc1d23c396b0c975f7bd6fa975df9759a9c02cdaae39eb3b9d1d5e40e0227a8cd2272e1541abb871f5d50f906ba9a48dfee2641b08d3b0f244212255d0bc6e137b911874ce28f27fa4c17c3b851112701b7f32522078ed4471dc27e92f35601d677b89fa4ea8e9c06f5193e1830c4c0ffb43a83511268ec3f2be51717a9e0e383c93a824fcb63091fc92f0601c4af6a3239fe7b30152988a86befb0b909ec173da97bdb6a8cf27e212dccf80c7415190513ea7a00da4d7aa575222badbcd2bdb199612c24b351b78be7492a4bcef17f84ba5be83a94373bc2f59f865e390039268fed1e0ba0c50d65bf3ace85b005202906da79c2aeac29022c8ec2f935e054892a6a91d2acf39c0bed8f476af8f87bfa674af517b345dd7b8ecfe727048867e944f68f5c9fa8443a850f93ca079eac0ddf13df11382a368a3fa5fb2da4486cef15f16f045fc0cd9c22984a33103ce56fbea729efc6679eeb7e85bc9dc25f48de58ff24057b319ffa2db6efb930da5e28582edb3a771e99df66325cbe90fd00bd5ca12789cfc1d8e8c400ebf2b2af74879960347f46791a72490acca44ad119af99a47bc4b02ae86a878de0bf036b17a69936ed77a47ba4aa5ddec477fff46da332041ff1d02a315b368db90bab1c235a4bf513d562d0f1627d318f4ab3c62f808da58a558840376ede86df34aedff1fd081ff980556b71c14edac6e5bca560978e5ae16d9bc7ce7042336356aa71b824c5ee2ca106b9868abb1b9e3f39b9e796ec05a27a3ad377ee04942cd64a2abdf7b8e33b5cfccb2419833c6290c6df3bf2452aa4e426c87e9bc11e389ddec676bf1c98d26679eea2ace7d3c74dd33cc7fb36e81579d9563e2262d7e14d4cc60818d564eda381521e55dc70981cc8d7a5b981c6385d2dd5c59869658984d368f4095befe6088f489b5a7a82b4002ce750a507fe758353e958680e5975c901434509b813c336774bd220740196f7a65ba5bc759397b1871c6f547286968915eb90e2ddba3d0ec6519305b942e4e16bd925eb8a2398d8f00b5d602a5bfec6d2a1b50303092263e23fbe3f0d2c0ad9c39426239f60ca27610e9b0aca2460ef842ee72f4371e96f7574a338d54bbede4b8bcb97f2b9cd737b0a4b39bf2197fe4e897c4a80a4aa9d814074ce3d419a2620fbce2c8810166011d1264523fd4b618630e60fc4d84b96f5071816f17316596dbbd949615cfbb0c142d4bc32b4525dcf62d632b62e044b492a77e7c5541e22593d5ce7154361c5602488a519ed15fd700eb3e8ed0156878774bd27530095fc98e46b226e1778a2f28aaf430cc149a44bbf374bed30bae81d7e0bf349403aafe58c22008ce067e4b2714d10f95027662e9b1932fc972dea43e5142e64d5d2b94b034a919645a18c4d0348369c3efe7086a76866d227cd7382ccadc08aa9f5d86a251296d92a4241a2812f011c919c9497094e42f960c0dba5cf0f6817f37d88afe9cd6e7aa350b3cf9b3a099cefe88d37434d875cfa87c2ec86f4fe145b0c9a470a5ff735a4ec865f2b580f178f51dfd054d430b680aa11f9c5a11dacaa07ef971c114f42dad8e9639348f70a88994d4fa2507847ffea030088cab89e6d8f5f31835ec40b781b84d61a819a846cb641791328abc980dd5d4fcb9f687cb0df91a9e3b01819164694f40ea02f6cb023989b6de30cfc9c63cbacc4dae4f5ad4ef289a6c8632736c0b3a82c49ab87eb6129b47654311bb06161b3fe53c12d679b07811f98a7d984e7fba0f20f8bced8d5d964f4aa804e6f43f7a8f29b33520f55cf3fba1a61751303adfade4ef51917d701d7070f65a90beca38be32393beb90ce71f0cda466603d601f0d143e1eacc8770705cc4b84b4134713e6b1d48174871a9ad384b9a0ac0fc52d0361bd19a3ac3b1453534eedcd26b974d1bbcba94ecc5b1d0051619ec5e4d62b325aec532d18ccb22e689acf21852c12898c45ff306cd91881f5b3fd56cb9db26df7f872f890e4c928eb5077a0bd0469e339f50578dcd1b771118369dce3efad948eb4174d93b2d3f603a3016aeb3cff69a0152beec80260cde047b3bc522c6dffb4583ea3fbbb9cc42f859db67fea8d7a0dcc4b7f83d21de6dc4c322a7e276ba7eda8eb6053eb37a974dabec406191bf0a8612d8c8e10a6dbf7ea929d1e5d10b0d356fb9ff5a68aa9a901a75fbd467cdf2640496d81da8c6b2d0196b8f20156deafdb2238b0702b1285d91a062ff7577c61e717fbb3e04ff72ee3517cf22bb4dd9238b3f09364e7323576b7270ca4cc10bd40352778b9adea81d4be041f8ffecba5d3cbbcc85593baa98eb2306cd81d1e30a6b7d8f5898e3aed429debb3d6f90118b8d758af58db3b2affb08d0dcd01541f3601527e1c8539e66256a74de71c408f764e83903ae001733fd935116867252bccb39e7dd1d2ce8dc0d9ea51f209dc560ffa70dd2a6653dc1c54372838f292da3f1651b635faa9d467527323b7b7e0de097ba02a6ad8982af8495c11407f03a58d5f4a5eddc88ea798f736ceb17d3d5de4fdaddacbc13fad717ccd5da1935a6f99441d24ef38c73c3d12fdf45c871cf6c68f8532101f3ac77419ea3e004226bcde5ff05604606dc7c1cd81c2a8392bd055f60aecde4fb6134b678b0b08a10a36099f4a03d50e5e243e8b07ad409f439d571e287b67b94183c8d105df7acf18766849e021bedd89382255fa2541f67b636db517ec05bdd1d1a47af627f4d4622fb18adfc88cbbc835557253663542f295e006788e0db77c7e95888fc07d9c58f63da098f70029c8085fb7c02b118568af9f5c69c9e96e1d66044a7c31627ead3796621c8e9555f4725eed13c924ed17196c43b5232078e5b4808f15c9dc78d13051671f70e6d88350ee015550ba93ff7648f2efc36ef500160920bf009b12655f6051a5061645a1f8ae4d7e6915177ea4d143e452c3d3d485889707a0a86452be417a5fe447f4f404b0b4248ec2912738df13b5d52a452d0801a88cd3d3c0c309f836dc22edc2145289ba31055d6fc2ee8324fcc4864c45ebfa3fde42484d665501533db52fc48bfcd5b3ccbb424fae030e2c12e73ba1803de8be5b1a9cb9bdd6f8de2a4f937432e6b45942530e8ebb84073b4392b90e5c1429d75640259e7aaa9d3bdbac5bc419a050ca72d9d0e05ae4826966c535f76208c2153c70db828037ccf720f756a2a76fd40fe68c7f55a45b03cd4e128261e60bf6f7203521e5a651d937d215a275d7de733975934024800be91d05cc4f3313593c2db3e33149774118e0cecd8ee7fd0c432b9c2ab76849e56d7729f3b63d5ae384284225eb03e6da906b53c605004a97e983a28c781718b35b4ca9a53577a92cc0d2bb42601196b76ee4ffe45a16c7724964d0700410af9d8f838b2c0ad2cb52190586cf1619cf5855047903bbd519ea985b855bfa8dcce444f71c8e6fa24764010202b9c5cf3432457d1475cf124af8f635c10be4152ccf9171af2463da00816e0ee261a1ef2f511b8955f39b808f8a9eabe60e9164a12045949a8e865dc8a8fadb40542ef685dc10126450c9702009195c42eaa43434f78356d7a61f91cc6f9e53b8d45e2c3a77a9b58b067aa69018486ed0f9dede21ad221a342b1c64969fc67124d600bbcffe8c8a1b66b113ddd173ec9444d3cb11ea85793c435d7daf3acdbf135f34d51bed882814c29a538f82ed5ffff063834007eb045f231c83a2543e1d2c70e23924d5c234126891c959e1335b53ba80cba50afbff22d2ff0c628333bdb15729f23daf6793b2bfa8011542fc4da4a2944ff5bd6b12762ad2a3c9b998a0f628cb4c595e387c2c06291daf15eab5eca9403479218664d74b2d78099b79dc329d0e32cd76396404f238c235501113dba1eec009ff4bc5914e2b06e65e6d6c306442b1ea8849522e70e0f4ed0151b8524614eb0cb3b3ade4bc5f7a8fa1184aecde17752ce97e9955f206e2f30628298edf8f69b692e8054c14b34d2e759365e0e058c6e51d96716e3edf9b6c3b295bf203d4e1a9e01cd9a7dffc119bb02a21400a082fef9ac72b2fb129549e043113594ee5353c0149c10008854018f13cec1ad25f0d5e5e3a1082c93a916dc827cc42f165c45ad6745b072d9b255b06e1da63df4ad2867e59609315b9321857a97d2bd2b25d80326f356022c6b81291c65b26688fc0206b3ab43145c4db7c3bb210028d2904a0a1b9f90fd8b086987d91cce4c6ef7ee04183b66cce213ff575512dc47fc3a571b56f531fe95753221359dc1b580bb83368fa40002a2b3559b54cf9e5fd36e3d0f9affd99afb21b8d9236b4dd6e47f6ab2781837697ee4023fd7e8be6fcb788b02338cfeffbc2ce914e263239a1224704ec4b46293905a748cc3f21057f83d95dccfe908e0a4cc06398854b2c5f0a1fa478b5b3d7c05b6d7ba4235eff7313f38a37970a6c65917ce82ecdef423d29fb88e90ba660cfe056d42d38666a057131d4109ce1eff00c3442329a9018f73125cc21d5a9370aa8d7852a075215a7da371569e1430d18df42e8efa755df7db1822dc19cc369210eda084e0ea6a0cc8bc1e4350ab5feeb0cc751e797f874544e6d09c17ca8ab2e15b241ceefdf7599a1760c9f26bfaf399cef1b902495eb8ccfe1929b5019170f165720410d6834d369ccd3455e746ffe74a2e6b2cf229c161f3663241ecb90bfda2d904ec43ccbf6e91519ac463d4bef157b0020a42470168ef99f77762906bc41c7c6778cd2279f442a1b7315516eaac5082b5afa6b567ddc50ba53427f815dba12db643851058d617dd649d6391294ad822a7be7606620289426f412edcc6c9eb928afd4d8f2c175bf9cde8fd6c9d0c504c29e39c6d087d95c81bb46917a35169d3505d129f6c0f4d94474418678718bc7c1b49209f3b93ed18a6a7237ae7cae6f74a298dc8c8b605160ba0e6f5bd394279a7e8b533c87a6954cc8c7f58d2e2a93bb71f3697da289cae46e3cebcc5de222b00f2a56aa0cf4da44388342b4718acfd1582913f9dcbed08a62b86b3cbacc6e3131e8875ad2bfb8c5e3605ac984f95c9f684535b91b9778c8342d66a94b6c18fbda44b84141bc71c5cdd15899893881a9350c67dfc6297eac067a99a94970a953231a7a7c88a234ccafabdb42d4c1e7aea07d553f844e20754e577822a66cccf396df93c41fd39eb53c3e2e952521480c95e955ca234160d00f94007a179a113d816e899e4083a267a0bfa17c15fa333410ba197a10ba191a0c3d60a77f72818a7d72838a3db9b88afd1bfdaae8267450f4273456f496a2cfcc05127be6aa12fb77fb2af4676828f468b6ffe50215734547d57d80bac373bf53ec4d327761b3296ff68be2e6040fc8e781c63d9d19585787dee711adef8c345f793ff163b38d32942d8256f13202601c65488e39235ab8feea708c13ff18bda5fb3e3fc1e2e3cbfd9c096767de664b644a2270a40c47d8b9490c4568837cd7cfa388509e1ac2ea149a005dd4cd1ddc194f0c1675129eb9d8f9d2226c08f8a50511261139688a5310fb353938a5d8e0adbed8c484747848d15b0a3ea48399b0908c4e6cb1879c5664c0eef81db240db17235b4b7e09c8c7fbbaa6383d4a681938662df7eeffa29eb6b7224c7bbc8ffbb1261da07840d269a91ab5e7f9b9f753d0822d8c7fb1a4c0b5af30495eadcf246fc800ca1b81855560f12ab078a9a9acb53f6598ad25e13080fee638a5600da006a081af0b0834bf6d11dbf4350ba8d6e99562a104dc9243e0ab16fea1343d9fa48ae0d90800b7f1188a4c08a46090402db3cd3b70fe897e38d83fdfd1080ff26cbe83607a610d6a31a229c638d1585520a68c059a19ed84f573f39f371a8379e2ee6e1666682025000c2aceb5f5bfa0962129c8f4010ec16b873457620989d23002cfab59fc1cac70c6c905631fc748704cd8b6ff92f542155833dbc039475d42b3da8333b3bf1d70e1e10c90cdf5b7ddebe099514ac28746de433d19cd61a9b4fe7a1bd2b1fe5598f1f7b5a200b82b3009374503a13f21dac07b8ae6c139a26a4fa62013796c9fed56e9283a1022596efd983bd0da47ec525d42d7dbefbca03479dec2e1730e9fddea9a4f6f5eba5ca4b42df521b51f0c3354cd7e889864cf1a5b0ed9b1567b421d0b7c06edc4bc6ac116cce0fcd68448dbcbc5648fe3ee95999635534543d2fc67993df8c0f0ca3c2df43d998c9f72989f9fc453169e5ccbf37f53e4a011acb13290a68c039a09b042458c08311100daf8185da0c386e935d88789ac5ce8bb3ba0b0ca4ea7886494d618c14bbc4e2c5513b95f51878fe0e49586a11f60b9bb013bf5014c67c87a652fead9be89279997faec80adfafb1e0aab13236b474ece92a8245084c3084a1e32999041f3121b7e50fd80b3b93a56ca472b3f7bd8a2866b375ba58663175d0adbe549e6f5c27aaae24488890e2b0263c218a0bd29b7e0b767f7d229d5e7ef64ed5a4d1c52a123ee138af40553d92dbd2d5270c37d0faecc0dbc29f59a1f483fb38f2be97e22e4f9928fb0e264a116b4550d6f7e6e9f7cebffa921ddac839d9979d52a643401636e8a98ae178f63c1c1c116ef0cb615b73775fdcca99211cd757fc312ad5b5dc6d29e988bc71f4e6ccf6fe0a6184f50c848c37a7c9e7ace20c16d03bb9319fc7690885a0b2d1d8323d815568611a4bd79a35354b850f5e0590fec429aa305a6465ba059e9bb46321b05b207a806f1e94d48b6f2d6b868f2f06f9e7601cd750fa225d954b9983c8df417dd9f795bcb6d03c5133a5797331a021e6892c6e462a972ec420a6420442d55ee0c8349c17b0b531607e5e734eb968b591bf21d0e43a41f9c54d1960a73629cacd636f89ea2837c667664622c0f36d22a023294ead2ea31281d901910e1dbfb04530b586324a944da76cbc37c4fb53f65dea70508bb7b29e8527df04f3cb35a48a45a8c7c706407ae1b2591c1a4182a2a07dd43672841c4864fe6204684858a78eded04581d46dc1a6baa43bcfcbff78e1dba680eee92e6e5d23b04cc4964d792675f700ce2f44d30d8226e638112fc3187cf725da723687bd5187f124642f02462b09f2ca4ff3c5024aaa2f16cdc998a4c58347f991b06ecc7cc4587c73abdda61e88c6bd14622b5c302c7f3bd1de205ac7488f2497ad16a22dfb448f04a82c2579aa970112f5437d7bfc0ed5ba9e278d962b1a6f61edcd260302a538a1b8e72a9395cbf476ee5a84e040b7db16ea98ae60b6bcaef9620d5f085f48c3975efd6de58fef1796193f96f47ff3efdfe38bcacc7140ac7ccb689ef329b0896d19fe3e2d3bcfd530b8228582626a8d240ed9eeb43e880727be9163286da3520193a5af63de148023d2817b34d9b012bf5ecf8b69982250fd4986f955a255f9112be105943227fc3be5f69826be1651c20dcd5ef5f4140a14b8346d22d26af6edf882fcc5336e32572544cc5716720f90a67f7dd1ad50c34a09c1b88cb31d0d77202ca84285fa72440e58413dc7cf61fd7638416863c30549a171aa2b9dca94dd88563abb430140d5427854fb91e6d8848292097a071b4afdb33bffa17563e5860b9ba3e37ccfb91756f964e04474fb7ae48fc27b8c889ae5808a415db7a631b7a5c62b876830f4d15e618f45c092c5c30a3ee46056433f12144a5c39eb346c4b64905a1d0d491d4d491cb8aa45878f08d65561851d3eb4d2ced0eb39a007b8d3375ab7adf47c1868560a9d44137463c29df81784e1567a22e0ef09cd25c2c1451098717364be39fdc60a3124a8778fd700105d578a0b6bace3a2a61dc3986e8303a22841a8191a6f261d8d8f53a9a75286aef24a6bbc851ea8624f6ba320e54dc024087097ceda58577d6e6ad3fff03992d4f1099ba9af27843e2a055b90bc1976740e9c42ff17312d522e1c48121ba2315a8151aaf1c0e723ed68461c021efc403095e91a66b424e25780e817b9f81424f8447bed092775117dc7a9d616006000742431e645d7f95fd65e24103956d8f9f932c552d7977afb90b596c477709a3ed124727785bad0b0cea5966518ee1d3ade9eee8e8a463a540258c29d32147a603c2923485ce3e9689b3fb358fa9d980484955952602e96269bcbb8bebdf126fd33ef027eb0ed9f0a0076d4cd5df110b228bf9f1e9f4c0521507ea3db8c0bc224f885b68d889cd2d1a0d0c9db89aa29b697845f422ca287479808a91f76d281f19d3b851bfba0bae218566b1cd145173228b35cd0d31718a1d6e1e56d037da563870c97c24b9231bc1e8b896864a5efb9d6e05ca11e3782b58ed79b8df1910cc350382cce51b7f946818521348a807c42d1bffa4cd8f5f75081d3aa5cb57a9dcfa295cbd0855cfd65189e50d343d1bfb092dd5df2ff4ebcddec8143ca5386cf83f46b18b25450c49c81db0b634dc07ba003de5d6d022489ab6a24cb8ff81c5cca886885db569863b6208207b3ffbc16a96ea3a50d84f003e09be5c28ae60d632b2691ab0f8c59a3a2c7a609afbc7dc261afca8b6f12d94274def3b3f3347218517d818c68197c4770758f4b3924bb8c5904526606c23af07eb0ce3d170a380966659abad4834b3deb72f26c6812c8d60339597160544ccd5f3183bf6489eec28abfbf23bdc2792cda4c0bc05767c00286039d33a3e1f03a17472368f3c202134eb07b59c4c5f414baa704106f797760d2581314ffd26f1c7dda8525c0339d240632b07cac804df4d3edd3ffd0f6ab85025f39697abdbcaf94cc577bb383ec5b6c43c527e762f22017d14120f14a714326b10b48dc03c34797aa70e8bf84fcf62f91232f202b4f23d374b3f710b0c378929d562a8ecc5433e55ff3a0d22f4e07ad1269b643d29659b734b4737bc52ee626faa574a130ae0521b0dcfe1e48d5df97772723ff57ce240318a0fb8ec695a32819410f53603cd5a6e348c021d81e3161958fb31e4c54268f87051c9c9c19871c917bd8348ea0e8ea41981c56ffebc8730f141ba1bd56c778aa5880737c83b0792f48e238635ce160c04df56151bd5e4f27a641c11d0b37ffa422e3c789cf2ff56eed24e13f579f91fba2ea7fe6a2ac79154daade768714de98050cfe87d5e0214f417a83edb1927e8e1964a575ec1273705595e66119ee5e92bd217bfd8cb21e2751131f25680f5d03d5a23a89000bed80db91bee64711e92c53414452cb89bfa026cc44d4df3f82491bdba5cc762ed3da1e4ea10a75c2328fc138abb6115a2b3a6135cdc287e14357eebe6c71114ca69cd1e3180ebd67fbc92c9bfb7f2a7d69e34d969bb768c2e889bcee403e48623607e4deb24c907de231a2f9df6e01f6b1138fd8d2b8d755b1f23ee0a4376e37b98c093624e3992ebc9528007b2396680c09c537e245a4086d58a8d85d05f46607ab00add5ff859eca2e4004a3f94f12097248065bdc3fcf5216a93f160b3edcbfe0206a15522d59512f3e2b1d7e2d632d7023256cfae88d7b46d7b55b2ac5bd3dcf4788bb6e015bafdc5fd03c6886dd859468adccda38afa03b04a09fdcb11ce882163a99a66e491979f0033a1a0f8009767af81b8bab5f703901fb7077a2671d36daaacb5d4f8251387c5ac5676545d1bfdbfdbbfe94b136c4e88c34f7f71970ab3161d4354fb67eff85c452f08a9e9c73f88ce46aa3b1ead4ad09993416ebd9773b5ac42893b62dfffd1250b49afb189c482a1a7bfe84d7f4694342b687eebe1f9895144416a303716881645e1fc2620f53e2518a2600ac111c3ab7eedd12438eae424e850ff186bb0a8196c849eb5a526e923a310e5713b202e448ad20f4ba64ae1c12d168e8e52b1de92e1e6d35e6526f96f9f88c040c4c73f04564b57702c986bd394ddb6e718eb980bc78c891be607b93ae07b2dcf1842d5714628d6615b698509dabff82cd9a6e69e4dc2f26a893619593f6df3ee2aa4a2f203488b6e8242d7edbbd3cb171f2f3a9c2a8d852d7c5b16d4c88fd430771b2357850ca30c913360f5ab887fa24b1736fe7c2b61a219a97cd11eeacf57ee61d30db956870131f2e03186547417f9eafd69f51c88e882240183aff28838e318c46157dd0b9e4cc7ec07f359e3ff36a33ea3a3964326b357ffc39cb3a5c80b4465d93938dd2cb0f61d045045c025bc00f5e089522da5835b513887631167ebaa50f826c93b3c9b1a51da2c2123adc24d8d39a2419d0b18b2026e8c7f6d47ae809b1a73a4aefaa4ad60a41efa20380eac6c8be0566d39c56ceb4d652471ffb13386919b9b75a94ce190ab436528bc018148aaf2e09683f831343e7ef4bf1fbb22bba019a60e2e469fb6df50531a0d39d1a01a34abcd42a23391a606274ba88b88e2e9b76575113187971530c51a5418b1424716f0406f05b01538b17db599c9ab43ca155b13eb6049ef61aeafdcef6db6fc2d805e81f58cb0c9c655dd2839222e8949b9f175e08c9cc0f76fac92a146173e75b831f58ef5e0e664848a6174b9f90c9b85cb0ff5ab8db549beede657421485cd4a4a0a85822ac45ad5f185536be9c3a94121346b3eaff78aa62091b242754de579a805ca4a5e4d9c212d4e2294916e68c50130e7d00976b8b04ecf3256ff03ace4c5603e06e9da2ac1349d629764822a09c932a14440fa3af8b57207ce57221adcb52eb137fdd84793216ea582c45cf4080d812e74a3a0986c7bc9acd1d7344f08b52fe28b4a01cd8d9da4e154c864406c6fa9587a26e7f4b9ceb82fca064ac807112b0422a278f66db9ba44c4c13a9c3630f07b1f411dea5817f5001d0880b26f2ff33f911d04de8b3a200a18701a5079ffa56481abdd943d3071e54b2397c88176836f8f8460d60aa8f25c87dd4214f7039aec26985a20d03a4e075517ab8d3043898c5e74ec103e3ff36a3b3098ff4d9851f5bece81d227038fac7a38b3b5b90000dc121a75df84127104b15c875146c4832e1d4e160863b446c258ec75173f792575f493ca6f7b77db724b295392326d0a3409ef08755699434374c690cc201a044d119a42484a93090a1308854e8603c070a36186a40320e0c66e88f1820b08f8a1b5d65aab035898400bdecf7791a46024498b4729a400fad84f418504d05a779c251289427c803c4354f854007decab90802494d66b395b53d808aed45dc751a976fc27a1b55628a89824491205acd09e021400faf82b80aeb0005afd72b6da5a93c0f365ddb6c8125521aaad6aa93d382453bcd4ade245f5de2c81c769cb402df6dff0028f0e74bb92f781a6197c42d1a46a6ad850d9dcb8c1c19193e357a18e1d1ff0e8c1f201c2f7010f09a48788edf8204e1d7edea0d281946664f91290ae69933db20c235d56c44e14f1c93751750d98cccfd80b92eec558a5fa17c54e1a3bc9a6099d4f6469c96124d90a205da62bb294ff05b8a2a2935af682e62203f249777d76cee0acf6114e984ce22c0a9eaf8f9d1d2288f049d9a32353d5cebb0bfcee6507ae58d0d1018978e6421786c032e8c070b33a4eab8e0e0002f08d20160a215d2d9b46f8dc1481bd00aceee7ee3f77c02338fba53b200abe338200de79469c1d469cd50fae4018b203f671590268e570f719e3f118ab95e372f17c2b2139c8e90da0e746e847cf8d20413e21dff785338684ebfc10224408014850899ee7d952c7d11f201080041b0ec2f541822c6176279b5569e7a6042dbbcef90089d011583b3b6209250cc92f07b4ab934c3082e427090b920a550f0640cef24369eba44efa218aa28d472c663f4b99254f5bf6dbe26457741443c20ac54a108bc562319b188fff0f328dd712409f12c013269d4baccf2d0144c14b78a10a5000134ede8387092698e04304e3a8785c1f49c4044ea488890811225d9123060069cb649d64b34d5bd713ca8c11b159a893669019a565427452386324b8754e813283cc28f38aad8a0d8ac524a01f1839f249d933637fb1151f1cf92e36c0376f2019a074c2091d122428dcd88d3144140e50855243313fc027dd7f7a08f89c22000108f849a116355119b91b705f5f28258be3b89b3999d8e3e707f4b9ff53779efb71a665ce6af0933d2b8a73b0a58ea3b5c74de153e1f329c566053cc02334531554502101493a015f02401ffa0948f229a065b671c6a6908d09845a94d2e2b4cd20338a0472a5281309618bf1e8e1452b24790e82322da658803fbb87685830f0f4a41775d37f49e656abb1856e354e1e327c97e45ec950f30d1f3081d0e756a3ac8d3464bad33fe6528cab90ace5fc588370fc58a154890318a491fb53dd3a7973316aaf6bb7eddec2886eaefb76c740873c4ea13925cfa12a25efe6e28836757fcec50cda6bb04d4221e8db33dd6367396a1a2d4b1ebb06e6f463db1a29778fe92420182d298f1e947bf49894dc3e45e6445dac208f5e94dbb3d4fce8b32db99d8bd3dce6450d79f49b277999dc2365020b8a59c92315ca9d87aae4a6572851eea74d675eec208ff428956f7ea4b4dcb40bce8f148c531bcf174fa0e4b0822066607b75993cd2a42f9ac89549ee9c70bc5f3cc9389e766b47c6f137a00f0e55b7c6eb8551c6c1f91ba00fcecddb803e3737bc80e51baf027d6e4c228200ca366f03f4b1517191555f03f45195b28daf017d6c0820d7e802875ce353a04f8d9c5cf334a04f4d8af6829c7a14e8934a659a3f813e343e328a1644463d067d50a79f017d4eb88c8cdf04fa605994671e047d667e6413174c64d37fa08fa9d5403ee097bfefef0df267148311e4eff3bcef401f6f8b5cda2205b9d475cf813e1d0cf23dcaf783298292107a71dc57d087b35c60b5d62218a8c087ba7b0be52539b32605b331c6345f7006832934b9ffd4ddd90719401193f2a50645e820cb1247a0b8f46b3e9e307002c6400b1a98308622c33ef4cbbe25bb164b647f998518d9ff037ddc05595ce1d3dd9a2a972a7a456ae92209303aa8cd6008297240851724efe22231c0a398e7f4a159053995dd0b43089cdc7f412cb2c0a126f77334483772bf055b50c12cc4a3a0118eb2e47e0a6eb1038b1078810552ee77af7693c7ef0545e47eda462f4823776bc1c51758fc61e402297237be37530feebd3b215851450840382348c78a2d78f051a3fdb0228c282c2f3710ac28f3440453f331db81871e628058332174e031064c9c9560870f6810eb316382871d299597201e332c4d748cf1c1ac053c8465c876cc683dacc2c074ccc880fd18b6705603207204adb47cc0490e12d16b79c2030ea45b0e2d23d801c706cbd152a5879b1a0e2d2b8072e38c221c2d5834b10123bbd142cb414506ec86962f4f6c1cd918694123a846112f45aa1b74a82902c6060f3aa452aaaf5f23ca139a30866a92e80155835baa054e049d6e319a166889612418aa055e42305303a2530bd008c254060cef000524433653440e5f1935930972f0cc90814de4500ac3f64db143378323ef8a2d3adc2f42a52bb880c28921d45d61c6132b66e85e5126875a240c8ddb82430eb448cd6e09f222b65add32821dbac8ed886ea9f2647661912fb32d5138c12a1974899570c337ce972964624ca105870d53d0b07c01620a1a90608aa421f005c2410377b08fe2494e962372f45024050e11609b2c8d8ab4c8712b32e3a5c0a62c8db0d840064bd0103847964658a4bc152c2bc8e3bf008b1659b078c9b10406b334c232e6478053355c8171b234a2e2071c55a8582247188cb334a2a22806541cdda82043092a763084511fc8918267449073064e9520070b30ea891c5e70b785097cb7c83992418e14b8e4250c4ccdb852450df2f853f097a5511538b8218b0d59ec12f4051546497c11451e7fa723c108381c419b10e5f958a57a0093395f082e3369f6c3a00b438a943ea97fa527bc94346e128c1040b2c806a715d70a9e409f7b0a1ea9cf85a3bf053ef046f980d7d452af4fb99498449132d5d1b07f29bbd36aad0d5276767676a6a494562a9c49650244a9fdee55365ccbf27f5c3b12cbd0ac8e617afb9147d8861320908b7e47ee481f2fed9c62f7ae4056cb952fe4fa08983807ec2fa4f2fc98a0d56c3fddf7deeeeebb33bf2370bf37bde3e54269ebb464543ffec8d2260bac7220591a85016414450c287b335fb7925ab0fddc21cea234dc71d6f4a1695032497914d3c8230f0ef2286737c8a3a48dc96860800c2b4851965842288dd7b4417e7202296cd0e549920ca8bc4e595c61fb410c9a172a5e1df8418a1c90a901d0131c5ef387b86b09131044c1841969a4f1c414af15c6fc0074a4a50c1164bce6b7e0ae0bfc30451a48559ec0c189d77c18dce537c092c30eb2b8408889d7f4a662a898244f74d16207464e8c31469431b52c74008418b01a40406f2fa0c00c3e70a484182db280426b20c9342181110d0a31585c11a2da5a435c650ce8199302118931a2882aba3062c78a184550a8ec80091939d0000723242a280c8cbec0628444825ccad208298603e3b245092b88d07204450a420a5996464f24651e591a45c125db7fe126fbca40e9c52fc8395f95abbb872d84495a9c48602d80f9140a1e67963cb39caeccb2844e6e8b5f8b68e0fef76af2651113245fc9a21b8a8e7ca8ef7f73b3825da102b5386df63a6b3e7696b3b8e0bfdd6e0d34a5cc200d345d046052f4ea9f41f205412f79a3827c3191ce9a37373ffe2ac897872bf853f130f78f308334d08bd40c2c5f2c20be0401f492af25398431abcdb0101a27ac85fc0bcdee389ca5f55a8ea32bce6768d16f9a78261e5e90200c0134e14842abc69fc231041b8f25ed7190af3c23498e61231479d408c79d106a5a29a19f99e4acfb437a22b578e7cdd6e2bda97cefa74e5f7b30ce0a89e1dea178cc5d58f6f4c8dcf74df6d4c8dc93cc711cf77865c4597d6b917b1ab6ad45eeb91f67b5cd1d7ce9269b1a4e3deac779ab79f9e25ebaeb86d2fc0aa7af093d80fa132afc7116f7a7701e398b7b0fa442e92c1cde09d29f48f3e794996b20268b7beee20662e2138aa651600a475597a089c81c0d0f5408275bcb49b039abb95a8bdc77d8b416b9471981b9f7e6099fc2190bb9e7fe95d0cc12a50e074ac113d636c9e32cce94bdfeb8ef20242d723ff373037d4d98ec699bd489b913d96aa4d944b63a8c14b9e764110fcfce8e28feab5053b89e5dc664f9ec306dbb21e2b8afdfafcad2679e52c74be6de8b019c79d3908e80744d98b7207be873ffe32ec9b1f2288fc4b41952877bd3aac34820dc83abb6491deebf5523b5c8fd8439f75cdf9cc53d3794392a45649547c91ceb8630558723768e730273fd5dba55e3de042348e40e2eb400aaeb13144fee185d267dac9cf19071b97134da99b382f0984ad130b067574a8ac8fa3e3ddb826b2d8269b18243e05126cd50c4ae9470a0b3129a3ba9537b966bf5afdfb376993bf1e48e1125cbdd7b5b8abaf7271d91bbc0efdebbf720d953d375b57b70f5e32c77d262e7410e6b119504a64febde7b028f0ebb7990bb4cdfa964f7331cbd88eb482c9147772277f8d663ba0c100beebaa17f6ac15d3734c90cc67f0a69303d7e1ac09ff925af8e3ecdcbd7ccea868637299c50bf027e9ad003338f1f15e2900567c997e79fe5fac8651f39387fda789901df03333ed39b4856f7920567753f539b365e30f8a6bf6f53c3f867fe5efa71e07cfc1e308dd7e7867e12fca677f0868629e0077f8599308639e94f95cdd8c530bdc9bd0ebb0eeb21d983c4edf0a97b6875bf431ac0507456f7dd6db17b997e6ec02ff0bdeb6a90aceebb9a0aa2a89e3459c9177dc9d02d195a2c022475baf796c0487e1c8ac78898aceefd47fc7312315d1e649ac1a79fb1998289024cc37196e024f2c061085d6bba4c2109799cb51f87398b76dd53941178945b86244a5653386f33e9769de72854969ec364758fc1c03360609392e94ea44ef774e53b489dee67cd5dcec36475df3911b9fb0ec779cbdd4b772072f71e8ed396bbc760e09a1c03553233073a5319e22c2a3cceea7a88756beca11eea56129f9f1be80beca44eed1c2675baef3ce6acee3b77e24da4d87d57248b7878767644f17fd672f70da6d02f0f9ad2b1d0adae89d4e968e830a2ee9174abbffb9f247247175a0025a3ad029353e5cb19389ac035683872e0824701068bcaf8d2448e2cbea0208717b894a5d197299fe50b9437c117980ef8860638cec0388e7248806b3cf150e01b591a7911c241c238b234f27243147c638b02631a0e19e06f0b0a6a584a5043c10d6a2310aae18043033139c4601b5ee48802d718e1d0f0e9ca53c1780a951944119ac10e4718ef0047104e85c1d1034e6d210446559183258a9c22c0b0720230aa84018611385de02f4b2330448003033082c080c920c6839492babbbb7fe01e848b3589d37e90b4289f524a4dd0e1ee4edddddddddda95f4a57ee94525a69adb55213de524aa9a434fc7196a465ea4e3d07e734071fe1eebe537174eeee52de784e6fcc6c6103aa4c22a5366624ade16e1384bb5321eed4ddab3b3db9bb4b49290d8dbbd3ebeed4dddd5dbabbbbbb3b75a7eeee7ebb25e58c0d777777779fd9628bbb1f818fc047e0f9d6dd7d02ee93de94dca5ecdc714c4a6f0e75f71ceeee4eed7b5d19a126d050a4eeeeeebdc3dde90e9fee7495e574771ea615ac50010f29a5fc1c180b1b2b23ad22cb518291f8db21a50eaa9af28d94526a3f09ca703492a50d123c2f579462777fee4e13504a29f59ac346ca1c29dd717c14874a79236f502aa58dfbf591524abf9d16e5bbdbc0354e744aaf9959a2c0f451a5261c21676196343ee79c7336f53967db0481a7dd4129a5b27dbaa36abe13a51fb6f1cd6c4129a53654b09b289512bc316fb7a494f2a9d32aa5a4725249c122354b6bed47a9941ea5b384a3cbf9a4bc39bedbe2f45086cef22d409b93d27e525659ddfda33a3e7c02ea3b593aa51fad734e7a29a51f4c1b2a97ebc1a3c7911a2ced2d29d8a284e5a80e49e029031dc8f9a83e7676886069e9411774904107864e8aa00674748258597cea24cb86029ddda13c04c162b5725c42b3fee8b9112488909eb3a711aef383b3b472f676f4077884824000126c3808d547a597b3542e674760edec58ae52cbdd1fa2287a0f1070951a312795d9b367cf9e22e0f1f55aae2475bc0d64ff594227756a8903b9fa74b68417aa000530e1e49ca5f57256c8723e447cce2a4ea488c92f572f67290fdcbd1c0f3cd40fcc3040e984133a241e12147cce1b5f44140ec0513f80a59ca595b3f7de1b52cb899ca5f5729608cb95ba5ba5587bd83c2127adb45ece56a9f47276462bad97b3552abd9c9dd59ffe7304672bad1cc7892c9d1ee28e08b6d65a6bad3d64358c74d9244e56c44e14f1c9db262a9ba4a4aec662b11a45d658b5d505d526b9ab565b6db5d5565b6db5f54a05e2030400d424db586305905656069e6fad7581b555b44b5811a8574b69b5dcff83da6879cced56862655264040d5c90fb0c22a0c003be89600d0199d512ef4881ea9ba3569e52e750283d1a07e2054e8071a44abd0213a744526838288280b2da22308a0d62a8474595bad1056006efb6eb91f002015af95866a653c090020a52d17adb5d65a7da85ee4b3dcafe3442be7e2477ed485e6b97868adb5d61a7399cb78727cca005cc885aa0c0da087d2954bf1588b22f09e201fc57128411e1444c88d903b718709b9d16508d0499de44c1cc8094002b5f56608242060db6c63fa460209a08f7d124a18529b4b1fd90471d5565b6fed1202d8341a985aad8421363a4b17156df901f6cc1b92a9577b395b6bf5f00748845e01412683a2899a2867d0877b15c0044bbd5aee5a6badadb5569b4d9ae24348a84a0fd91e88d70bf4e10a60824fa55e2d77adb5d6569bbb6aad434811aa44c4643299acc6a23414d1c30eeaa096d2b18e553af3aa990039e98699801ae373bb95494a22426bad15ccacd5906c458c605aafe56c9d5be66c729947475d68b42246666c92c8525464e488090a22222346401fee8d1c3901895b6b2f676dadd5d65a69adb556eedaa419a45ecbd96aab0fd5561b9419a446b9526ba561f5615e91c94ea0b5d6b1d37bd7e3b37fe0bd5704339216ddfd4f356f0a41f10b6feaaf5c61ea62b2834dc3b0ef795fa6d65afb4dab618a0f756bbeb539b27df73ecbd96b3b697f48df60c1d67d7697162dad33bd912518d8665a87e18e4d6bf02685faf457a84f4326309e17f838dc579391ed8b91ed7bc9f657a06f0a99344d8a601f87fb02c3ee42b2c2489625635f72e1a882a591adfd991233c110484b7396cdd2b3b08b5ab46f51409d1537c8e0d4e9e7cf90668fa1fb19d64802cb8cf31e4ea9ba75fafedf71fa06c7e45186cea7067d4c8f42a150a84779fd9d56338f97e42943cd33a19d404053aa5b32b7b5f282e1b7caf7a5ce0d39bb7a6195e7fbf457f5a1311838ccb2cef69133cf5075c3e3979b0beee6e786f9aa7f837dd54763e6687ae5f9218a3bb2c766fa23f0744bd5224dfdf07f773199affaf47d25b6283fd3ce27a983c517678eba0c2f47465581478a5f1ec38c610e40f2f0e013b6f1d42cb359d4227d5412781e59e15d4e488b1cf7813e5efd2ae853ad955287fbd2e56069c43033f72357e30a0c9b41b20727df9f501e77e920d808f0f8e58bc2c1054f8039d8bda5eeaaf084cd2177dd9faa22e9a570c2a4ce7d1b2fd8c24adf95ee77e184b578b18c7341966ecd769c55335d22532470545ea7143a85a44c8074d9508666d1afa16c160d29052275a0fc008660478a10c5a1df4445060614111e670cc8946e8d1f9b52e69003913d3fb586b407150c2a5c349b33c352ec029f93d2a27d70156ba75356cbf6c73b6dd97e0e787e5f116d3decf794b69d77956cdf5738dfa295b9e02ed3db8741fa9b5673e62cfbd349bb2652b364dedb2c42848c30c20fecad3a4673570f396b8b6cb594a945b63a8a14ed5b59248b787876764407c38692ed43f9b9a15f18a402f6805de8d6678b81c9b26f2fb61898ae1672967d2b6d7fc371e2c003ec16f39809c1146bd9d94fc79c657fe264db43f6cc9506665642b38d4aead88fcd264e6c4e9cefdaf781197739e72b392275fca792d98318e6a781c79bea1d64ff1db2a7fa8dba23def048b3ff11088e327dd364011e7b0809296db20b2fc0d02defe9f7bcdd49da783fa477b448a5bc2fbf456a7bce396b902e1176c609d42bf1932e1baeaed236567da55926903af447474202a10f82a08ff56805c06faa5c984542b9569b453d8b6abec1748be66983a83ffd0c2383a0420e5c47c954a0822973d7f432a734378f2617dc6ade2617d34b0d7c70d5df200d0d083e87aa09511c2a9cb55943d998616a3c453dada91152b1f1a79f3629c4468d8d1f4aad7080fc5e8c4bf49b06b4810a658b334f7d9a91e973ddaccd23ee4bab18661e7732c5e1ccccd377400bdd9a095f34853b4698e611c7bb749c251b74dec6cc5b0f7569892199df32a5ff7d69c5c23c423581674dd6adbed2ad51da8864cfec2c5a0b188e8d25d32f1cdb892f07f8880517dc6543de5b0a4bdf2b1b44ce42428a5586868686bec352b82375680fe1643ad4fdd7620f35d150f7c8f229a51f70a16865b9abacae64fa43dc8f3dd44bc82a4c64dab2c9ad58d9ae62e080d8df2175fabbd5b7d8a3ca26f7ffd3d3d15c42d32a2982b2f71ee8e1f8bc55f64aef7d2775996ed1af2e247bbaf7de837edcf144af746309dc5ffab99a493fb8936e797873a474d32f9764ef86486725d97b07aaefbdc3dabbefbde7795e0ab7e87d8806f6a8fcc860fbdeb737927bdfde0e9bf7a3f57e7aef9ef7ee799f3d8f882080bcc7f1fe5141f68b9e1dc99e30d36f2edde2fe3ead60ba657320d963ddd5d1bf1cd7b31fa898be5b3101bb2f75a5f7fe7b6fd6740d2e39f8e919771a734a3add66a71b02dad4b3a6f5ccae9ad6b5b6ad7a2645a0ff751699bed75b64faa5e6a2b5481618077fc0edb5eb170a969e7e9716bd52cf702bd1a694fa946e0d790dd295a459ed45ba66ad87eca151467f429b8c983098892630150c4ee9dc557afab294a493348bb664f595603295485074696f0adc5dba69dd1a25974c2badb7f451cf9abe5f67d1da0ca9f99a3567519ad4a14f6ddda5bb90227dcab34369d36a5d731655d13a4b6a9bb516297d941128a033ba39d45dd4458d45b23a55ee76b27b9158e677f7bba74ebad53d85d2ad21d943898a648f8edc3d0dbb2e729745eeb4d0d2eaaebeb9ba2dbdfb22a9d3fd0d163c3a51cf2bcdea1e8adc755f0abbaeab9ec5e13018b8c6f77df23927920196953b7d0d2dd8ab60112aa7ff5aec5e1651327bc03df81fb0ff31c1df83dfe3705f4c70f817131cf00b7c93068a749122b7c58e870cd3ee7be5472d767f5a39cd59dde395134911ba9f712cb97bd34aca008c6e94bb07adc8dd7f2b7742b2ba9fcea5c5ee3bcb13dcb32e027fe8229954c5653ed4fd888772f75d943b2f889cd57d07d462f71eced062f7a313e5eecb5df729dc5ef3fe5060670dcfba357e5bba6553cda51b4c237dd87ec9b64cb6d6afb468894297b568ed7f64f0f8c98a68803265d22dfaee45ba54cea2c99e1e99bed764cf0e5ac30e191743dfb6edf75419dc011efb96696a90ac2e2cd1840e74a3025cf333a7de893e1aa2a7f9bef7da49b75041b287e6f414ffccf7131904871cb899c669f090124a0cc55a94d222ed9f398bbe6321dbb180f9cc5ddd44b2e8539ad38f7d5ad17c83a8f7e6c7239f62d863b946184a0f870de3a1ea273208076eb6f1f4db4943b1115251fdcc779014a27afa35549f5a61a7c91ecf14049d46933dd3699e34a9a40e9d422edd9d0675a2b87bee69fb40ff362c7b1e7d96e98afb2e530ab95b8fa92e64fbdd9cf5244ef651c3c01d9d45c8124804cc1d4e21a943ff260adc30a7d16e95c2300aabc1046ed0071e32fcd3e340981254491d4a69c33215fa719ab3e837931629cc815aa4a94cdf81f209f7698b94524aa958caf6559225e5d734403438603070cd0483ebd72eba58f55988b4904844ceaa3ea5c5fa43ba2607ec432ed462adff91c1475dc3f78cde9512488392cef7158f3c57313490c6926778a54ecdf397f89c27a17c855abc50f4bddfb2fb5dc3946e0d75959974bf81644f4dbeb74c8bf7febccfc22af544df3bef4d3960022edc114668f176cda77e943416eedf7bef1791ef774d0894efa7c2d9e4a392fa213d93dc3565aaef3d119c29bd7497d00c6791d4b9ef2d8193ba956ab14cb71ca672d70326ebfec5a61f55a71f45d48f3b343ff2e407ccfba90f79f459b621571283ebd386c11ad6b0ef6deaed3b16d9a251a448e4ae54e8b7f155a670fc0186311bf7d68437fb85f47341db2e563d2ddfac5093f26a561eb0a1e66b3c0d35c29b1aa1076ad050f335420cfed484777e35ab252f09fafc9ce0e6fa2de5b76cf1d01c9a43736886a42423d7c32555f7978bd9b71797c211ab5e25da9bc7fc964481288c06d198ec99415240597e17816d3121fb3e64df65f69dc84d4d738498bd196badb5f7de8b461554ce48e5f9dc1d6365082fcfb7773e9e36dc4a797ec541154336d03b1f5bc1e5cbf33d8905a63cbfefc5d87bb56af1ce39a9e8a29639bf2f8899b32115351caf925b0e8208024a901369bca60dd9c351953b1c7f47b750f94e530b3c9cc7f1e4a494d2d9d46950a6efc91eeaa1212b3e87845de65dc8166d224598bb4aa1d7de3e775ffe9081f77e187b2ad54d183c36ad83700e9b41b8d06b13480eb2c786fe45ead00f294cead09218ecdf34c959f4efc558a5faa4d96c369bcd66b17b5595e7525b79eec5aabf62e690f0e83559cd764ba24014267b644b5ef4bdc85df405f4a2ef47f413e3f98b33888747c213a44effe823f711109016a2972c8d907f8cdf171e91a5d01af18255dc1579ba678001950596799437ea030ceef2171199676478147fa4b3c6478900dff873ce71dc75ee4be18d87255aa5489d5abf5bd504512b0a084c77847e98dc90b649d5622582b990362cdd307dff3ca42b7696ccbf4c19840358a440ca36596291e228072965f97206913af6c7c6138875577757d859f668867978b254b94b74964dc15f5df8780bdb4f5aaa01e6c26f0baeaf6a71ca9fee87b4e5acb39c355f82a52270373503a99dd8ffe6501e55398c61869159c9ec812d5ad10485b9d1158839b3e6c1288c2cd73ceaa8756bcc9911756bbc379b2bdd721d744b1ad980b2bf0e30a38e313650647faf8227d874d4dc255ffedefd86b49719a106a314bb0923281c738e8254a8af9c99b36e6ab87fd451138364cf7cff1b35ee6344dc4a07cd596270dc6c8ac69c990e20a99333cb9939cb75d4747891ae4ef64c1d64b2eb1093fd471d61b277a18eab52e9a88535283524945d7c12d3511bca2e06499d2af0a8a3967d6523ab39b35ae9e7cc72b6e41ce524e560d2ae2a94c30509a6a3960326c79673cb299343cbfe954e1db5225bb7461b990e303a90e6aa3fa748f6ccec8fc38f64b2a77bc49bb757c63a918f25fb8fd4892c6bfe5db6657f69c59c81ad818becfe58649f734ec999461ab2921cb9dbc08cc1864d63312942331ba02964d8ae10156d19b2dd90c6d8108491358ac8100262c758c331b07cf9376ad08cd4f1f799fd6b1559b76a7037ff7aa55bd2480c2ed96bcd22460e32583446cc2b51f6d935d6ad71a64a711ee4b14ec97e83c7153c237bfaab119edc21e77bbdf2a48e7f2781f8749f23140808082877d849d12748573e32f78a03cd358882d79e6eea6fff7189cfcc32d37066ffb4c0b1826305c70a8e151c2b385670acd8a0a0221c8e151c2b19c70a9e2faf3723b30489d070b440b667a484aa117386637d92fbe5d71a64ab0a55a0b9aac9f4e92a06223eeeee1d6dfaccafd1041e4db5dc3f57375df0d87d8f265aee57327b30a4e7a5d23d950bd2ae8bdc5fe7ac2035d53a5aa864f6a03bba49e2afd2cf4c251ca33be2bebf06c91e8bc3bfba5b9fc896c9d6627f9bcc1829962377d1dc8b314d776433998185494ceeee56232b516badb5873cce1409d1fcab54183b8d981490ec11d28891fd299aa37b31a639721f2aa54fe2af1225aab02a001a8edd915c5da9333f258481f044809212c4e996e9ec2ca4cb8466d1377509c3c50bbd21c3fe93ba001eb9ab3e15c2e32c5a9429750fc73e3a7297f474a35738cefb2b4ee4509426d02c8ee3b83199dbf12d72e384f9aa6d30ee39aff11b32987b1976970c2e7dfdf17e9bac89852b25ede688b5bf2483aa1b2e59d0c79b73ce69ed6a49f6aff45d62a1452e3c92cab2c57973ee5ea798c34103d38a671c870d34d3b009f30e9ab00663e33a8ee3be6fb7061a23e676bbdd6e37dadb6c76dff13bbae5a62366c029d8b6970ae62aa66b7faddfabae7d645446422fea6652a733c263cfc020e5fab2d3d2bd4f9d2f4125271491b9d6ef2f1ad8a3de146c1f8381bb0bfefdd26a3ae8e399c21b23329bbe88cca65f927b357e6e21bb694557df4b105c2dc9be92a1e62f7cc00472bf5734e45bffaeb82d7256dddbef164599aea611157d8e95a955cd14f55055f0fc0912a91fb6512961ad4a05b8c85780ea5aabd35a6badb5d65a6bad95565bb97a6badb5d65a6badb5d65a6bfd4a69fd5bb95adfd6ea4d81bb4bd71b25f04fadb5d65a6b9da17eadf56bfd5abfd65a6badb5d65a6badb5d65a6b450169d1b2d934fe79fe852a2fbc97a6ac60fa23cd7f9b566a2fbdb4a3253a6bde9782beef82c0bf41a6e782acaa62224c220f5a08dff56294d249e9dfd7a5d3f6c9d6ecd2c9d6e4e1d9d911e99d77d6e4118db68c073f6123423e4f282f449f41ce9a41b267d2a40e9427b235bb90a23fcf8f3bee2d7400fce2cd3ef2e4034c7c0a81c78fd1b904237b0cb28b3c503b219c785a74d29ce5535af4a1b085fc3d1944eb9681cd25e1d13e65d40915de64f05d669cc914e9e6ee9a42b7642bfef9dc1c63b2e873df851e188e6f0a477126149a791c4ea131a6ab6524bc291c5b5f38e60ce1e08c9c3c4a1a6d862d49eba1e930071abaa859439d9e8ed02e1a9a45658f7d2ab3081132c20838d7691b923a4de40006c85623216955750a5153f00c9d2cd0f620b03d209e887e679935142d524ae4b1805fbee8c4337f0a5938bd69fad8d4f0293c999ec90db307af139cfe8517a8c0e6eb8626a2827b88d6dcb5436dcc1a7d7a7187b4e94741da45cea28f7a301c49f868d39af76889769496a046e491da09216ccd9104f0a70a157b68d672ec4c293da66f2d52a943ffb46a272416232b726b912c5b0fbc64faf46752e70cece1148a813a60ffee955844aea40e9df9a50e7d22518ab5527f4a805330f7f7e2c8f75dc6ddbfdcbdf7fe5ce1b46802dc3b909dd46564cf7c158e3c7612de215fff40beefcdd59c92c571f7729fe440b22727df7726382dae544d78b5c6d24b1d285f8fbb96b60d3b28bcb7afd75d0e9452475461bee8537c1fec01cf58033590b33a49ea045dd9ea3252bcad2623c5fb976747bc49aa69b3c9fba3e5e92467dddb7d77d1bff7beb88312ea56e0c91d52ceccfccc8f63a7b5c3096506a657a8740c196c72d229220100004000e315000030100c088562a12c0f933cd36a0f14800d769e4a6a5899ccc35110e420649021861800000080004360866a4a1b00a52bfc0ae355071c08c03c4842e2fd3f6fd982c04150d95de1f8e592df0ffad3948cdc69483c300d979698a56e6ee7fd1107f4ab03ae709fdaaca246dcaa45287290b536f41b64b9fe91f076e9f7017e4badbc7dc9bc0d5cb1d8ed1740eeca15b96624ecf8c11b3275662fef299a218efda80d821fea72b34ce201a446428803cc01e39361ba00912cdbe168e48c4ec4210fb4d6109a2c3dd699aa0af569f6d33258106e5b8fe042ca4bd3c008cba0876942d63129c14c15a9f8bec41de2ab4e60c8d9a41c4faa4de03ac58e546486fe57fc4b815ecc408e1d6887c2769326cbf8b85880ce599e25c247046c6c6a91be89b99bc87468b2e6d711223583fc43975c6117c1de222245720a3ffd695cf0841110a2ab2a41732de6a1fa995529ea8991f821c598ef9530c36a8f569aa0fc335b38362806259c5adcd4220da58ecd53d6c03f804b9792faa896bef1e9cbae2dc021bdfe668260c16a7ea63a362c4e8821570eaf7aaf3967810092e9e185ae3b2c9eb2b9c0ddb918a8405b569870a9d361b73990f892e3b93369e3b5744569977342db9737f1437fa82b8d89423861d0459e5f2ce19cc56848fd0561f58560c39233be6ed4dc1b37ddd1fde5d072c4da4b5baee039395658ad53897ab31e9b7bc70147332647bbb9794610261e5ff68666ba77c0e0269da6d3698f4d7d35d128d5e395b11629a087e624ae0c59d8ca085b40f6b83c6cbc6f41ce27715925508a840e23051b1e95aa584a9442cedaa3b0b597e115c3b2f73384a2e4ee24bf08afb748da54e98cc551933bc478049a5edc4af108ba4f6540ee8d460f1cdcb28c589c65c4a6419e57d2452e2bb93dee17344ddf4f1358574109a18622c98ee2f52d0acf85e3ea0efbc291128f20267647228d3e55d8b56e9307afa7f81680a49e61b3880dd0c8702b129fa099feee548590a78dc21289f75e5fc3b47902ef21c158f222cbcb19e12f302e0ae071d0390e80da9247261fbea3a78ac31268228cdeeadb9e482b68467e8853c8a4b3ac57eb3893533fb2574dfd3d4f8ae8dd07a0abafa946ddcfa45bd2f2f567605974b016d0a9556d2aa75e3f96cdbf663ca8e9532e59d09ad11bfb849df3f73cb6b7ef8a86d3b0824b4ab9ca19c6c1a7fa9e1de2f16ad8d415baddac043b224d38f2f0a715f2ef24172d499770d3ef6a8dc46be9d5638ae2a3909d4da40d09d8621d54ebdb46cf1bda1049041064fba4a184c6cc0af35071d32a88f5c94e7086ea1bcbabf740d22dc3d9799df2d0b6ffb32cf590d32d3c1d6a5312e05b5d9468000ea6a3553d49b3ca5dabc46c55e87a33432d8b150f94b904083eb8e90275aeaa350edd53e28635cc9ae6522c26eac8c00b82e1784af10f64cf36f9b1ecaeaf842100b81aae3b4c88438792e2136ab014db3e8b602de6be58ca1e795ff1faed8b887933300b34f0d729bd6e550382dbf729367a8619751ff5f92b3b45b3823b832097d4d9ac015e92db6295550041b080c90be8f2bea6a85f6abc13190e217352be390d4b5ba4260fa9b54734ea9964830e75b3aca1ffae2b297563b208307a04c5a94222dc60403c233662bd721929ed55134524de9825b6c36789f5f227c4ebcf3cb51fde524f3100a9006967db472915ffd8f01172369450b021695557dcc019ec36a5bd51a840c0d492db2b9f692a6eb3a6d522ac79bf5b0cd34af1ee05f5f86df80405bdd93a05b39d951ea5272a8015e2a235020ec004783e8b4549d72f902b410db6eaf4eea3942d15aa6c88aece9bf956019f32b386a56faf7d5ec203443cbd9a41d89d0e1f6af9f2b7b64b020caddc610cf03c68d4ee91b7e10517cda527129660e3931fa9321283abd32998409c4a54420db8c2f9ae9893b46f85ccdbc459f7b0e4d5d187fad310f30544bfde6c33fd9c829340041e9d2da287296f65eb39128208e6625aac81ada5d8255721eaaff717e8d28f63068469cf0b37180dd1b593093b5f80458e010f46a5cd7c204a10c7b06e10b33029f5ef462b5fd2162e3a3cfd4b2990a140fd443795183f90b16e89773efdb29d4817a841c848e553ab9f69c3d2a070b88b32068978301cc3f3cff577520a20c056d028d096689d2fa84d51c46a8636f9bc5959805c490a0f4b997159796c7f0a1b6f9a4bd1ad9b0b54813eb2d1071cf7d8221ffcac029c4e0398e003e821229b82aaa31719e6b20e114c5bc470470fc7f7ff03441320578b8103f50f0c208d1f52fbb26de78c395318e0a40039ec86cc89ff71b2a20e3f47a91bc92d08f9431afe628c43ed108eeff4e31aa5373e9ade4416cd86784a71cad902bf02c8fa86abd810183aae3a420b690342588d4aed63dd244cb97177b173891e1c23fc009fd5f8ffd979ce770e79c43360f0eccdc1a69cce084fab330c5f1ffab9b614dd36a91356484dadb3acf1bae74f09761a5de6711c5ca43ec219c58f0268056559a298a607091ed5108243163ff5cf95d6902996e64b173bb0d1aca8fa5869f60eda80f2d8945630473975d9eeb960261d543097c0ed2f3bd5e9b363e4487f8a4d4bfb889e349cfcd72019cae1be4721cbde682e2be2ec73b5f6530bcb2a84ecd26ab0b36b3175bd3bd4e441a0321fb3429b7a6d868978f0f439134a5f551566cd6ee0e885d9b331aa0d2bc4a95a78f9ef2a233e3644d80cdfe6633f1e4c45bb5b18f505225c4328f3959674ae87aba2c94cc963d2f69c40ee9ee1265ecf5114652a18eb4731540eeaa2133712c1a0112532d52c4f10f42491c6182c20c68bbe7642cdae63c56f2b9a8326235d353dd7c363c18c2dae6f048837eb107f471098aae0e1b8fa41d95ef64a82bbc4a9a1828f1df2bad12c606c6acbf76b0940fec98e309b74b866b662f07d0a0e203a4a97b4d9ca16fc492e52a4c67a415d6d07b2a09dcfca4279983be60d9186ba2890d8080974732bd52e5f909283c254e7c88033d9a351b238ac7c1b00b85696920c5513fc7112806df0623b53fcfe5e77a717119b34f51cca28b15e03a62d14bd5e9aecd2f16efb912f119905f23f57ccac73815e3015bd678d750460ef461cc647bd7c9141890ab81ed6ef1a6dbd20db4b6d8b09762a73b3d7bc3c13189881b700942589cdd083642d233873abe8602de47d379206380c0703b81e715787f3798e102466503c7d083c976059360b04d864cd9543caa0f7d44a97a95bc5ad95543c005d1104d5357b725b6aa3688b00b532b75faefbe8c60f15510aa570f078a50d0598081f7df01e11a0eaac89860295836e31d82c21159edbb60d0c95de6bf34d1ac53d2fba50b5bc845bde77120eff0698aef6503ebf1014c936d5af8cb0c29a151cb33ca8956bf77e59f0567748a2c42fc9aed9902ad2d2c04b672ae9d0ce90ad17dd10c8bae5ea07988a5faed64f4fb61d5af633fc070ec65c01b2572d11b27f4168b9fd6b22c0a4c83802d0c84b62033b419069840721f1a7da5fa8220d3c94540733be6be6426ef15d43ee69487632d9880bac970dda8e85dfba7f1b358dfa0bb5a23c2cc71b2a3347868d8f49b7cbed6ea8b5a8f0517003514b6ab1b8ffd4432db23584e83fb8122a287175acc4413c97f5a812e4500bf3e555a5625f5e05518b834ab4a98d1d10b2fd3948d9f6638ac429d9fb6819413612cd35b9fb8b15d3c14a3bc0ef835e17f0ae142d5232e4a85cb6dbe21f539dfb40d85a9980f75f0cf13a240aa67a2124e329ca6abeee694a51dc1324f3ea04739b82040c7ea6293bfef85d0bd9cc198127d399720d9be02f491837cf34c29f5d721d29e98ee48a50dbdae0cd81d7a7b3904f2671735b5d408b2b7871dfd7e162796e8e1c37c1933a28d4475be4362e0d01f6c20f5380d50edebd1a792c852aa7883514b41813ae6768fd1efe3fd86fe4cdc2351710302abf7131e47df2c382e00412e8c60b3cf2f50ba13adb862eff581a5b2fcb10b7f6beb5715c53dc9fddf352d2f3f12792bb97341fd324894c71808350c0ef0f44c0b732e788c7b2eb98e7dcc9778cd2df7e3ba06fbc2fd7de7790366118a2789c607b300c99169111d0816a2629e5655914add96420c04c412fc45a9df983b60a8ac93770fd9036d62f0ca9dc0ed7db11dffdfca6b9bfb5538612fcec6f4143cd5a0d814c3f5fc81abc551ca5119bc432d38622201270e1b438f4754bad179e4b53afca5388c7dd60b5934358ae0107636a6b544c7ef83f9cdddeb512020b0bd646b96f413fc7e0e9cb0604b93e2d0be3a8c6186cbe6be23d1553554100d52f96464828ce8a05de011b2b663e58603be0920d89ba98c4c90b9b596b571fb4d159ca828595bac85d163aaf53cbec5cca8b35ef8a40efb658d0cb5c621fe5f2fd9d14fac52699415744212aa2a0b27900c3a0c179dcfcd1c1532166629c85c3c81798bdc92173e8a1210365e55a3892f9636e34cd103d157efb8a0ef5a2b7f2f6a71dc78c6297000c877f391406241cdb133bcb28b24dce2fc943655b80233ea6c2feb54517dc5a011c720c47df296e538a699705e045f2167f06ce6a722859058264f65924409bb213a24681dc52893c4f55393ebc1799d0bea605000c1f33cf000223cf8f06c8057ccc81ffe388f7f58e68ab96b8d915c61fb7ed638612dda35c597a9119f4833124c97392cbeacdfbeffd241b2568fe2f055da0fac6902f829d37b75c2a6083b7dd4414b74c5deee1bbd2e145199da48023573aa3254956cf28b0037e5c761c7ec35201d7382f559c38e6977e291f27dd04712f4f7789a4a199442b44c6250839eb6112fb8226c10ff9adfe828badc9d6a0f75aa688a5e32d80ba869fd4f8073d3e89459d6d129165090d5251c7f610fec597786b6b38dcb4f44e238983e922a4fc9bb5ee2ca70a205bdcdddd6a691f4399d40d263e5479503840f7d7b0255794c2e612ee9fe76910ce4936157dbabcd6440220c0f138a6237d2c300e6243690fbb573c8bb331b8fe10cecd448993653a4760248b2b5642e388c0df70aec192c7fb893f89a3d2fdb4f73af2e2b1ba38660bd8cd1b5cff4103b4061a262e407ef5c6865673a5eb05dd2791c1560a8ceb02c8398b75b6884460bed17ff4d35edd9e3ffd756f5960c4caaf8b6da984e7db487d9d1544ed560a75d81eae0ff2e7bef25c0305c98dca2f3904c4271f555e1585c28e937b9899c93ff9c4a9d5a5b882982ec7015e35ccf07f1c5d27ecf172f53e8d6479dc76a97ca73d036627854fa1f558c5c455acb99d7500d99e86f757f89c0bb0db5ca9e59128c63be3d464d5c51023453b3ad2f7da8d508f8143a6285d09633ac105836d2dac1c4df8625ddc9a01738bbb8e376cef29901c0102c59587bff8ebe467262480e12ef9d8f5b3ec22ebc5351663c07d1434a950bbaf439d246390d87b18d4764e3f68328cf1301e024005ca9511d6a39cb3bb44ce87a4f066b67432259d0b423fb1fa4eb4f8103130acd928857fef6587d7be5d3495c5be9f511764dc0ee05e3609802aadab439596dca91a9714d867c5db9cd249c5bb6108091809212bde8d5189cdbd6e33711358608b6b6d9edb06c93add419d8e8500d2b06eec9a7452af6832c9110c0935d2a097ab6e540abb2a3f2526be0089173c57ef19ac6061941aed50e0b344e4fd8a5e02a63f3ffa466913b46b0da0c9dfcafee80deee0b0706f9a64046f136f6ae8ead5e461770a330a31ac027f8c7e0e470d41e95598ec3a60390eb30d5ded207b59286318150b3fceb6808d0dd96e2b59ed92b441d3d5a19d198ebbacf4c5883a44c498c6cc752cbf47b6f0186ad466ae45fe0ecfa1b5a5a2205b2808c1d248c512a4b7ed91f188e0e6984e43e70189821041b4f986c13cf1236cc0175052bde824649e51e35eba04761a6437ddfc649d805a1fd82c019ea32dce89b29cebe4493ff100a89933608f723fede9821e05e39ce3962519fa07db26659f4faba6c5d5b46954b092c80775d690fe87a8f12469dd26d2e890cbf589b8fb4b4f63ac1ac61979fd9245a66173d038b834c708949a82480459b41e2994f6c972eefd80df54524c8c56fe2bff9cbfe49b9e949ac717d8fe9db55dbd1d074be059ddea17a9c9bcdbaf3bf237eb0f6e4205eb0c6f276e0d6554ba116a2fd207f0cc1120a1657573b7832899aaba2ff60c309c9a187ff41f27039b9af101168277c9b04278a79472e4658b228af00330870aa5180ee21f6d9cc2740ea76efb7178ae7fcc12ac0a935eaf1675d5c8d51eb7ca5518d6702d3e06a9084928f33e0d4b8be3146db3e6e84e9771a87d159442bd4baa60aec273bb16b6052cb9301840a2af72c32257d21a83ef7b0c710878640ea055dd541ce024e560bace0b6d0e4bc42c96340db2f1054b729b7d8caa7af40240956cf027ab9ef928b8641274111a7959ecd82654560c6c738ec677b4e266d658c1fa7dbc0a9546065214e53f23251b3e52b5288f11a4e33007233d9d39c0323ac3ec7046f7ee1716646e1344f468729b474bc009a94e675858e9d2fc16ac605261dad752eaea4910be660d080401c0d31f134b0361958afff753b27213fb586a86959fdac5462b0924117eda2437c34d9ca363d9676333f93ee66ec272b25eabf078c0f49c551960d46886c108662621eef82bf83b2cd15cf804fb6ede030cfeb59cce9b79d77cc0cd8abf545ede19a21f4623ef712c489339d60b556a5cbb3279c6de0b6448090c4820f02cda870d90b9b83bd7e56eea806c62e754db5cb3886c5c649f0748fd786d2a6b770cec71535960f4a5a0379b62332650a239d14cbf2b8342fdaf7707cda71aa432a72d6a95c931a5694b7570a62043b25c42bc607258b453fa02e2ad939575e2fdccd68f75337f602522d93833c224dc20f7c418c9827a98601befe02ae0ba3d30d2d62e2136c295854df7d59c377a5c6df367fdf2e7309597495f7e8385ac065cac7ec6504a6e950734e0982be3ddb76e7d3c987387704bc8cbb712192c4f6fe39d910d4b6812e200fc56128eddb777a137c3a789ff67009a8fa7a29b48d09e1ac4e0d54829f3665e43fd5cb8adff3471777d11ea4a8daa142166093701aec84b53630956a139c2cdd6c8d749b0db9ad58639b47a3cd512b871f4f731cb33d3f5f20b0751964a1ad33d05ecdd61bae4b3a4e0d0f9343a3723cdf1201b74f9821376dec3451429ed4ea6f71d3866f71042154fd818cb12f87b9a375661a1446eb33a87eb805be5557530fd5a2ac7b449905feb02ab44f6f8295ff85e8b091aa6b9bff99ecc284efbd7c404d66f504f7a140d7581806e866c59288bd6649c3672356026c94d0b2ead4eca5d35ee8ce7eddc5193cd43b359150089ec11da1f82d373ee9c987d6ce2381bdddce6910792c4c6e1edf5832d147a06d956f59d3face9a98d27657e508624cbd37813d7c07c4f2a0f90df3ab570062c05f414a981787efba6b973c62f0623dc493be0de5e8780b01ed76ca99506a21cea933f65a9ff5a86cf7a7d04c6a395710dc25b1d91df6179c2e6f84b4ef1ea49b81f387d26ea3be84dc433e0116461aa73fe25557ef495bc4026805f744e0dbe35b8b39048744fd1445f58e3df835dff2d47163fd6e963cd50ee73933986387329f9a83abafd0cdf66d4a40f65bc73675c0a8c1b68d5ce251885423b19740443a1dab4ff18d9081d63f40f7699124b42bbac703db99dd0deae645a009bb7f3deecb6448ca2b1df80e4b2b988d10f944a99221edc9f7adc481d2346052834e21d373f612a0258ac4cbb27198354dbbb0057251cc0751ceda4be21209d67b8caf22d1f181c71af882877ad4dbb0a927033df36e1cbbf1c9c1cacc0c2067abe79df1bf4ca98712f5bd36e090ee8d58534597996cadf4558a5d47b28a6149444c7f62917a755a4504d9eebfe1b144e71d95b08baecd65cafecae7fb041f6ad236ecb50e90c6465ae1ad11958eec3e832218c2fedf9940b4ad3d2a91787051858ed07bef8cefed98e9e3186f2ee28804d3cc1e17c1aa059227fa7a5595b6b39a212f51e05823fd8eb913b774be448bc1cfe660db6641140948fee413fce040c9a3659308ee50e250b76592e48c2173c7345173923985b5b691cd419d2890e28fd3bae34f17a35d902aed7416078fe988ca6dcb17dba28033a03494d9477a1117225c4d5f13852e4ced69f4e4f7989ac8301319f412e3becf85fbc666e65c882f6865e75e0e8fc4e0642c806159f37f05b206e8a156801f8aa0aef7e3264dfcb1111f9195c8a0e02a54e9c2237feecd9c9bfa5a38a8869fe03c4e61bf1120d5c76923b67f6cd212bf8072f8f6023377bc351505a41ce2f6838af168c3b24b0b2267cc0144069c00559934eeb4f162e05ef4d103d6961684e8e98cdf2b98dccaba7880be8c48f817640e2f5b937039c3cd7235e5bf319a57bcb362b07965a633b57d6be522665b47c4835cb2f74eacc4a9530dee024bd09649ad6468655dfee60780b7ba2703b1ab3a3a9aa02d16845b8bc390fb5ba1fec9754283d8477d5286d793daa00c72234856b10936c3b0a439416fa6afd94c4c88e466f1d60d3250c82b1f408deb93e833c3355847ae850d675c877fb4c4355aa027546cdc2e731a767e8d30cbe039286de58d6ba35fc1cd30e49d9e158961b34d678c5929e0a28354a71ad751f815ef2e1c75ee8e3b9aee5e66c8de1f85581789dc1a8b71180e8a4bc51e00a7838f445d13035958b8bde06e04b90432a05b638c64702b0b05b0d0492492de4b9e1ae3a506b7d5df2834e79eb337f15d041138e6c4f2743de43f48116ccd4105e738781658a40996183a581a50220c8514b05bc96a9216bf94e01c068084c3a8d71523724a789f516afeeac78e3496cd548a7e6c09576058a5eda5078647e4e3c1795631a64ad3ac8131a5eed70eafe9922cd782af7bcce3e24cc1c5289a0984cc189db655a313939156e00362802e84827e8b9ce6a04dd3841cc54e7e812670a8f7229cd4a52b2e02ba83eef1659f6e23392c7954ca743006f824f38ecda34cebbc4b88931ea2e9fca5ed5aa35fdcab5642904cb9d6c1fe442b438f492ce0c2339b1858742f6d0ea8072f1153e482d95756c5161b865cb751090d2e6961a739cb669425292b36944f2c07bb54334878aefa5b04da4dfac1ac5f5fe2e0fdc8ccf29db445faadec65c1dca39a9e4048e837c387201b73b9c570548c5cbef378f91c60b221cc441c7f840908fb0e870c6d30e8fc559e4a2371ee46f091e594cb9175da78f8fc99c0197092206be0ed56fdf175062d9a118674035298eae9905847935c161c4b42c11a44749c311f07037fe8f8ea6bd8a7626604719ea8371153f5b923d46fadc7285b433a3eb3d32eccad6041cec7490e684f102cfa797fb7fa9ba1136d3a20f3caed1fc0c0b7e2e95cca9b24ed518a64c42963dd9cde47daf7080b94ea5db0f16138855a675db0391a8cc6a078e8597cfb7421c78ebae845b3eabdcf33a5aec0f75c19271527e005845aeba3a42e5b53c2cd94d190b48deb9a396f81a293e899c91cbe7920817a2c5a2e87106cded6c718eb3a6b1cf7c96c7bbea6eed50fdd12627bc99c1ee6bcf2e9e70c0ec5aa3323b217816b4b67fbbff5cbe1f803082c71f764aa44b45dd01db33847a1070484b326593a53fc4ef4fe267e8b348b25cd0c96ce943ec46574a988271692577cce9fa9704bcd17bf7ec8c20b07308fb9847e581cecc437489817f7b87dfc6afb87fea244c206133e9120e0f951a7bdb7b8e5e700bc9c1bf9e01ce2113772739108d089db15dfd8f252f39eeddd50ebc94b243992563a16ebc4677a833cb733ad43534c1b7356553d9bcd5fe519fedeacdf8fd68a06e6a790a2cb0ab81231d066f20609fd9fe755b54a68bfcc355933d83e910c69f4b6108844d287a0ee3b47b3b4a64470f3c4bc64874c7671472e1a18ffe9563d135f3db9ad708e7195f6c81bcc50621e01c44f310e21689aa3168afb349e6e4d58128a23dfc86e8d4c45854268818be651c85c0ad9608be965f65dfe1521a471d740d43b0cfcec86e7009ed047cb6a4e8fc937a5fa15d4a46ad6d53d274bb3d944a121eda95734d4045513361dfe82819aa21aeec79dd34331ecd5cc80c34ac8b31c14338f9464f539c5d29ef545d5f4341bc0800a80ea4cc5f340bab19d9fa16901f140de7b8aab587da944e428e7718658e886387008606c63477d36e95370a8a8d7e6190763f290aaba94f47caa4e5aa83e5e9b5da84232ab11a92b7429e386c30a304f71ce66a89ba8131061b826f687f292093a78dc128d40bfdca2e7da179d6084a56794251492b194cde427c4548cf20ec8118ae8ad863f8a0bc0e76099c23121d47771ba66e06580345bf144d08163327230386b9b913270220c01cb5c3fd08e95d0e9de564940bba0be7c1d1e6318e6dc088b9fe7285ebd8dbc8c9e8cbf58a9e4165fab59c5ac30cf5e637091930acf1103e173e911117d037ac52c1d3895eec6b5f44f87ad855a14a2d384b1036a72a98e34b63379cebb9585776cdbe8c22801b80a0d3e6b1dac9e30532bc2f294ee80e709368e55d269b96044244a50ee9e597e6e46bfe6b92ce7bf2a827b54c64553a5a1dfb00756859ab8be975969e8940d2a65abdb0eed843b9d4e6cf3ebc7c3a4c78283618f367137e15e69e1c8ef10ec6b3ed0a86c487e8ecf026b1470d2b7a72c6171d969aba18f94969873f59f63caf3f77a7fd05e2cf6c91fe4ca590e4da9855182371e63d709429c07601944eaf645132f62d9212184543b03a1c2a01526ad9a63f81a4a712e4c7815a47d003ed4524d28f6ded2baa7ca4fb179dd1dffb1e9a0574e3d0bb9aecdd713a0bd4e2d75b7508d2bcdeca5d32850a0b531f29c21afab9c7105eabf3b3b4392962eb7312fce4e7ba7e36584da3907e5ef296f7038a055108625f2c4dfc0f538b9559599a968615a794f74497b3d27defc87d71bed7afc55a1bbf28edc24dbf48d81dfbebda4d893831e5727f421b92dcff287f7ef7f8d54b301853c0d1c07e8c981799538286341546571d73951359988ea21abc15578df307514fc4523e5cd15c736079f652a7df9a57b8208a793dc8699e7e993fb15fb7f492dd7f763c6ecf7dc71ec8b490be011eb8e32bb66c2c29883f5cd492cfc3b51451690db76be1e4cff3dc8c0afeada78559d1fd8d5afb689ad0ba290e7e1598f521c0e079090955328bbbfdb8b3e4526b806ff7af71e47d5c6492005218591fe160842740d856b79688c4903047da39ee51bb70935a8a73a91d780e097444d0fd993bb580488e07cbfc24fa705bd7ab21554147a040fc5f8f2c4476e5950cd41af368b9274eea04d57149f5c3de4cacda7a841460a0230a4bb4c97855baddc0a06058fa4d5b1a8af64056910b62851d16b14fd6a98326e434ef7074e62ea301e1af5f7faf6dd5b6e100cbedefbb435bb39e41cf7894fd0740de3c5e67a94b827df00e47d83c522fe6b86f9ba22969ad974c0316ba5eefa2ad354ce6a66ffb3e5e955093570daf21ef0f7a778cd6f0365746405534b99374834ad7b9efaf1ec5173eecced9d594371a5746027b08e9a794a34cf3c80bc753905f495446dad60345545c7e14d9ac12a5e25b6810dd5949021bb41da961251d3bb6d8e5775105c73b646d2cc294e4530cb98f26a3d32a6b4a596987a31336a208b0105dbda625d8c1fb33fc58c195fb0ded6aedf0d40b04c068c348a625b8695f70326cbc6519ffa0570c6dfc10c3ebbbc774f865190ee32d2c75c829ae87c2ff9b87441c2ec21c28d95d3bfa4bbd57830755a3c81c5735b0c8328752e48cadabd2912b6c3b1a7700021e5a2fe5ef1b581814c01c58cb15267c8a7b7ebf66acb0a3458329889181ad9339d32699dabd8599255e030040c02dbf0fa3e55680551d331682d15fd90220969b0962f996f397776b753b85be03bb461f35462e13bd3ab4d2dcc828e5144b1465a31db1de0a9063799c24658e2eaa97200d9a3c9354f4073c58b812bddace8fa4f8084ff9b711c93888f8c09be6e80f477bf8806dc9a8a2604c865ed73c72b46a87f49875eb2e8a59517d5fe2e3ac22ff6dd71907b14241e8234dd85ffa403c719b2b475fc4c1ac1026cec67ede7da4da2f59208e168be5332d8ea6b8e5decbd1badfd7db125adab2c1144b25b3dea12072b4a620d2c0de18137aea2f47a3773530a787fae25e777c373707969c92a140ecf90e6c19464c392c6cde8460d9f51bcef88b2de509b49d6b1d4e77efac54ff445f97922a77ae5d02d7fd817ec9dc85df3f186f23aeafec1450bd1eb945f311fd48138beb0b567bcbee282cd01503132a28b4018defef2d35e1df021805fd044162072bc0d4c8ff025b7116948578de5400602edc5bbb42e3624237991589abb84fe82d3dd1ce16b1578e0804ca9af87496b0990c70fb8276cfd4fbcc1948a9d06f61aa56772a6320555beaea9d5b0d36049ae3f505aaa0075a816120655ba81349cca4e0ae011ebc2c2607050b780efdb2d79937f30ac9855dd9b198cd9fd7b5e12dd1d3caa3f00dda80f86a628046a20fb40dbaff538f87281c2df02d242a2687c2f0baafd8210a2559d476acbb2950270d456ff147ba38caa43f552ac5f790ff2dafaa08fc2021de3de38af3122f66f2c8cc086addd71aa461863dc574cf8a89bfc8d692d8f4ab27778311d5a018d27b1792cc26f5f3aafe4bfa8636349e872b9c9a349e07610fcc3d088e60078d17982bdb1ba398d372e5a4a3f1793663bbe9299a700e904da34696f9948695cebe78a6da0985e5d709d97c6adf6001effbb9d2a8a2ebf6591887afac2a9fcfc4a84ffcb2bf2c8b66dfe1f4177a02ffd6632765af503eb897ae4d12787885b41ef94277c1e2b7a8315a556257f3a74a4e109a078a429c306dc83e763156c9f2b5bf7d2ef848898a2f5a50c7b6a1dd476dc8a46c0e9f48ddf4d80b28c8194a174f58623f94e092f185763c3e7dcec7f2679ddbec964e9aea558c591748d1ec00540d09e269b85d6aa36d323e32c3a46f047589373b102d4cd78a01c0361799fe3e0ec051a58fa7ce386224da25037f38a9d99753840754e29b4975b38474c1570e7b2fed984fb3d6b81bef4e90a616aac20fddc746ba452dfd379e8c9cce141a9539e55ca6c47b4e995a13494716c0c2b817f258bf23626e18965645abab432148e305ca34406acfda7320cc5d192fefb5a547fa492c4b04e15789bd5e8432939ab3b1842f1b96681ea8a10b40b2ecf6353eb4f0a3b5835dfef670a73ad46a65ceaa6e8246e48814507b58bfc41fce6393e6ecd0fb5dfd2083376cc7bdcc4b5c45a0234690ffb5e71322cba6ebc8611ec15af7f3f7eb0dc9c5e180d379f107c31d05835ea1c4338c404a8c407bce2b526d015c3d2c0569f3b0ede542d49a74acecdf2ee05018f1b75f014993f0917a7b7577dd17cdcc83b98d4c99f03f4e1c4c848416935df0ee9046a74d7f2e95d2ae4f62754ece0651ea2925bc5ec008e124cd16eb21dfc061b9d15fd06e77163d18abddaafc2c7af154bbd4df10be6a6139c1b12349287ab66001cb39c9c502a41cc903d0164588b89fb53d88626f4d7ff748029a6c3f72b3af12ba5e05ad6c2ec3865eb42da966887ad2ca0c0e0cee63696159e6a6e99d84863932d48edf1960566959be0b14915c8cbef075bd427e7ce6ebbf9ee060081ac327f80ebb403039fd9ebfd2ba27d54a3047dfb5b83c4f54f3a3f330387ecb536e7db6f5e8cce9aa3af8e288fbb7cec215cbc05774f1597ea6b76ed08355f5676305904022f4d5ce4cc45f0390c413714757257baea325829b51041b349b101ecc9b615c8ce5cbe864df5fd4ec5c50ef10cac34f92eabbc1e227854e11486f19730f3d02dffbe1e7c6d1c0c8a4b6230e2efe03f6bd2aa8c925c6fb5595aff341960fce379b546882275c2210d53f2faac91e794f857f9489ca644c8227815c4d6194a1a4440740608d5b754dcbb82a82918e07d0243d8ff05e3c2020a1a4c03492f4b8f770bb8cd4311d7a0803f449391c1c608bd977ffec4d3dbe4012d7ec9d45b0e790d377c3d698da676137d206c5469dbf29f14cc3d22a0c9887f1383edc716c4c488f917ee8f5e02050f10c3fba63d961f7954bb47b3574cba08b93c471c9a8ba6c963410e341c8bd34b5689f38cadc174cbd51a78376848c3d4ac0e465f234172a9d607d8837c82b77c5248189b1d47a6e214c00a3d5a6a7432d14c05b4d2c9d6c27b8c8e32eb474660bdd3e54656ea08076409f52110105097075ade3e1a03dbf54b026947fceb9fa29c70931d3933b0c06cde335897e413644ebda78b85fb0d1d2b173c440198de487e05b6b1900d842b0dff04f878713556392da5db50757766f1179b3c52c3ec5f57c4620303871f48b258fd04796feb6979c2abd0b25ebb0854c24991b090fed836b0721da7eba9fb9eb47880eeca3e0de456eb180d7f645a8f826c50fbcff9b9af36556802ce11c24d49cd5bd0743d077147aa115d60b0f30a7396fd437fe85804b0b6292f89a0fb27e13b295007dc523dc052684983d99c836259533991fd44532cf5ce62e6e3fdb4094275ddde2fef0a3f332bba670022203af6307327b8ddd9f2058b0dee2638fa83d70b8189c7a2f4aae49b1d2af4697edf996f6b248b673c1d7dab6f31aabb2d455aac52fbe7589f62c1c7bd86258da1d59a774dc42396f0a1267e0e1e3add7221b22b9bbc5beae020da2634078a8dee030d98c79f04f0c36a2274f7bd551d05547bd54a4b5946eea1f8eb3a03c464e3a64b02f22ba83e3c49a196585da5b7a1e93cc5ef40a416ab5ac1511cbd1898819438346c92d9bf1acc49d8cf7c97cd72d7f3e00eba34459291c4151daea98a4bb7631c1d5cc5ef28283f788793cc14bc433c6789204c5dd7ccccd777682fa9573563fb2c60d49b45ed5e83bdd9598af15761bff4d2a68918cefeacdb02a023ff87502a524762152a50811f0f25a485d90eb13b967cc82315aeb855f33d71a6832d370c4f985c1ea30fc0a907caead3e85a4c5ec28e5df35e00b498fe8922f151540985da429f4c0f102bb838b08b44493b547a5dbe0a730a2836e675bf38c2d6ebe2105fcc2579fd8e58c9bd1e75d26af8c8678f39edc68733e23a81823df44c5a918f36aff7689a56984d0f93b45ab36b8505c7a6a0c0d606760dbc2490d1ff864877b09943c76d6472e9ac0e8c82dc32a46a208c040d9ad110062a051f3d65043103cae2d13dd813340cf768c7ac952400dcd88182905947cc64be1612c6d674bc6d012d86fc8ca891aa0e5007f378391fba8cde6b65573bc489f47db4389776027a8b413800fd9c4039671834cc5120c1277b9d16a4fe2c71aa0b100c1da7e665173d555803b390f9124bf63548503e83b47217152b8674d39edf46199a7b12425c249eac3a005c0bc9f94c9f3ca807fdb7991710f4f0a83362200bb978a174147e8f47d23a12d7fc0772f88a939141b49f31580a1026038ecb280c0f4973e04ab4eb4533820c4ee778c404f040a98b4cf77260f4df4f0c51179168a2366d411421066cc4e2838724afb8862b6d37ce9297a9975f725ee565e36fc2886ecee78e6b4397f7891d42f34769f87e015a960ba2916bb17f684685d6c88ffb65f509ab7098d5191c60158c574d7224a7e217a514e444cb5362393f8b080f3a7c468b752e688c008bbc37e68e3e010aade8ce8636ddbc91b91068cbe38f4422b9d751bcd4ddbe28aa3a45fb72b0f029e223c766504ac8bb825c14596d758f62aeb2b9389d8d8dc5e11844f07f330f338a1c0d596e03a84ed28fe1078defeb511ac680fd4fd08d4882d809b2045fcdfe7e4ddc03b50026edda6515a96c10dc5670b01f9b05b7ccde935277a9fcea4bdc8f8e76282e20e71fc444eadc24bafdc5e039970624e6dd6e077ca9ff5995ee17040718e017dff744d231b025a5723af1aecf2b1dcc2fb46282f9c213883a895ae508c733cb08f67f4737c9d02f1d14d53dc6211937d26ffca1b2bb5d5cf8b5cb9228afad203f746ee8576ac298059bee5d6707e8b3e9999101ea49dcd3e2a113d49d49125884f0c52b39d00ee2dd994fabed2a18562ccdde7474747f1beb66c975abe903d19306eb598caa7a262d66bd151a606b37aa708da5458e469c6f39643732e87ae2302087edbb751073819454ccbd05f186474d81542ff8c2395d90f1d4a440b08a1c2991a40d11fb7b983e045fb07997642f868b2cb7f6085b5fd18ff130bafd8e984afd1cdc67b29952a43dedae21873151ce98104fb386909cdbedc1413c103bef74db6dba90205f24877e9a6c2fce0ba84dd403b10d48662f887f080a06179aff63c1d46a2f79d9fbb759bd9701660cede427f772abebd749d02cc0cc2a78143f638551f7d98dd3698c8b0c3b072a3f88e1e4dfd4d5faa9969fe583cd40ab85df62781f53c7571535a1a66cc3148235615e7d786153c58124dbf62fee05a235974f660fdb4fade1e2ff356371ee7a78dd5fba508e7a6548d14081d86a9bb0f80914973655f430897e5ae28b076f13722e507d5ca4ddd5f41676f7fb897066ee10a655f3350e3cec1e9cd22f84ca4ea046e113527e42aeda1e68a6c02a2a12cc8e8b52142a6678f4a61d6109f29031a6a5e3451f8a8b0b27bbde4a46d308ed23c51d3b389ec7706d6044958d64366c69082dcd35114d79f6ffc495f0411e152b790a1a145964af4fa5e390aeba2c129185981d9b42f4ff10283cfbcce81feb8127ef5e1e7b83c6adce51fa15de670581fe038ae01d241386c15adfbf9a9e23a1ca8ba69735426761328ff3207974122eadeace310c355fc7baf994188035db1b6cc42e83c475506b6be892d73683957007ade48150c070f717191c9399756f8554055e698ee273f0859fdd971cd5c58bdb5e36b4aafeb589ac6dbab54cebfbb7a0d9b5de110e106ab8711e04ba8e12ea0f30f5860c0fc870fa0d75f8ba7480808c45e0d0ccbf769e503a48cb628510062de7b50c7a94e0b7049e0c3d2b96f78f2310a91302ed3346e02108db90b4822a5f7f0426f7fc41b6fef1eb8cfa3800090059bb987dc3bffdb05791503fe65f00b3b8d2d27d5bea88021698ace612313d3c0d5f8f4e48db89405838fbdc1e61d922f3bb62e01bf92aff38184b1687f15119b17c930854d0292097066edc168d270038f4b5015335c88a40cc3a3fbb1d6bf9671090789f3f838a450ad6474c70611face23555baa4f97563dc87594f1934a15718e98dda6978bf2b0dab28e24844e19a92426e1562e3214c0f3d265e645c5d289b065f0e3f4b0048f520fb7537abb8c6e7093299cf6186071ab966d5b5914437d921a91e3de28d648f535607d71d35972cc5f17b2e332a0eb54a1acd74d128cc110e777731d851ae8ed510334a8872237a11fd685873dd54c2d9c762204520ca07a82bcfc328d15ed52a33714bd49378fe68baf1c4f79b1e89fa7820c7e1c265dca61b051033149e29a578033bd5c6f27f266d640e4c488fa5ef9a21f894425091596e9a0afc0c36bed2c0af624404174d5151b39fb388e0ced719b0100e9aabd76a62e8231070993090f05448deeb84d80d75396d3b9265faf34c3404d91fab1e635108afb34c26da36ab78920228b7210db3d0bd0c055a76b78299e3f4ea0f1147d77318242146015feeb140c3f0beb2e7064e24eb823b19c0ec07cd16643e2c9848e837c3e33baf5483fe21e0631427a526c10ef097eeea51bf073416329797167f2a038ae0c7c56e505f02112af0e8dac1ae39ab5313a07ab221354c0837beec0a7bc0eda80cb1f738bc56eaa4a9085434ca9a1ac633fe3d197109f48c675ffc4bb67d33212e8ff8c462affdc3d99fc1d9662bbc24d28797473104fa43f8fb8538dbabb19bb34f186db8674fe8d5e22f3d294f86111d379a359c40d617556f65834160f29cfb40034c0dcd67e51f903c4ae9268271a4811c608010734aeb2e838b4f87c4b47fa3205cf42078ef44e7e04ce0d765a1382ebfb7ce70b7dbc180821493c702a8fb269661f389c5da3bde6baa388f54729629fa38bc1f34428dd602a8fb9ee0229d12e260648e3b2324db39634d63f166cfb0aab70c90da0a52efa04584fdf91514e7dfe02b3a3247ceafabb7fcee81dfa19747184f5906d7303ee1676dd510b86f2aaa2299c79a71a065be96e7f83ce47964279f7d6acbe6b75278e4a57f675e7047d4d963c6926012e903717bd96150d4249a05d4c53daa4b3b35aed190cd68e80fd175f89c2956bcbf5d9a3d0d48695d44f8f438257d499d2d9517fb3e114a50e0f1b1c263887e841db585afa5e54505fd047484606a88c29dfecb126d45070e9a7830e2e7f90197b3e6b699e976e84cef068f44a111c097e4d39b9f46f452f3d8a55c80745ec5a03bfdb920669b706b9045abcae5cfedfa6091a8a2ef943391aeedb7343d2edd6f06f11d7ed145f0cc8edd7846b746a4494219b44660301371a76aba6ad51e4ca4499f8153d0346c94ee00717a4e467c49ecf02ccb12db5aee73329ea5980d759906c64a5dd9f71f98859a34a42547914e0fd271954f69a87fd0f34396d69fd12190da93d4c7226f3cdb1f54713bdd76a729458857cc79d406c1aa37264b5908617ea451005203d844471cc8d616d66a01d5d15bb5bd2b34c3de855f2dd86764b2a50c863bb9e479a18b709b5c264fb0288b1fb75fce50750f908d245eb03687197612fefc44294b2808ea53e55856379d87d48342662db5a495127c0172d061f4d863647038d4247e8240d2ede8b76924639d505ab1effda2a6fcf35e79d2f17dc947e0c5b83dcec1a03a4d09ba41e6de9938dc03666c827c486b3cdf610718a503c3c69de30b6f904491565c4a153dfbd37416414032592bfb8cf72b03ab5c7fd6703beecfc71f8280e3f8c9e95e501cac31b44392021d1086a14a94c783ced48eeacf8ed4ce5b9dc059b6748169b6f44dbb042e4bfa31b384101fc460b30a83d8004dd8bac54902e27b101ad317b160ae080ac44b8159ba00c326335634f5dadede2b8a542e2ff455802a79001b083fdff75ce93481f4052eebf9de38bfa35390406312d8bae1059de42e86e811d70b9057039c863ddf722d7878115261ee19a7e724259064e25827602c9b60e48c831ee388eaf7b34a33b843309bca779a292454b1157c0414074ee8e0fe6b6b11deec05c0afe9c6c8e72f8c85c72061d7e9a5927c0c7e3e569e59ed3ae0a00a6887a9f321b03ec2baf15e0d33c8cf9766cb13c15151fc791e533a7414b2cdd36f7b340878a7f8139a49cdee5c1e87f626a10636aebba67dc8452207ed9a800136654f26b0417153cfcff0bc60e70cefb9b7e74c3917f01f9ed08efc26e1a1e65ac5cdf404f7428532121ae5923a9b3015d5c685810cf90fffd1c89e7a66820078ce0d036434e87df3436331cb431352c614a9b470d92873b27cf837f6e7404b1d7502566f59eac97098d125f06c7120b20b2a3321e06f8917b345cf9e93f2d943e5db40eac70ce08dab437df7fad2eacc99b8af4c1a4c6c17ded64f599d368f984637c54de441266d4ee799bbefc2c9abcc35c61e6f1ea60281768364a9d4775efc569cfc2ec840f6e688e5ad495811fb183f1b98c1fb8e8c49a6db6ed20e5c5a7bd9a8832e04b0233c924c92c9edc045adb7e9abd4d6e681dd4316ec234f2fd4a721d586e65d1ef5033a73197cc672493d60c71a335915b089c239c5b81f591cd1488dad9bca900bcdbc0ac80e55d08b618c0af0f99481d7865ed24d94f3b22e06438694c5dd82a8b6533bc7df41092702922c1cbb04db9f21b429ae98cf9b924410e0d39bf89052efaa3e703770fd3d179fdcc6884f576a15ee943512abefcbf110b01f86052e2c02c36b3d7d779df238199365fc8b94ed6eef4264817fc2dbd53c7364c17353572934b1966c3198d321ce308d8ef149b6abfc2c3c709df57900f4239d944c8fa1254aea0d916278099609c309eb640a8ddefb3435aea3cfe317b1d5c1da517f40974793017b2a3cf301a746e2344fe4db9941d83e191b05dcce3161b5b1775fa7fc5a78f50ac526243ea070bb4cfc1b4702188ff9c6fea30caf76a895be0a8de1c6eba260e98d5db451ab882ba4c2556259d7154b5410d7debea227040269ccd162c22b51682887f71ae6d6cdc6441b3cb1e89958a87489b3749bb540faecf753dbfb2c13460df39924deb439789747d5b9d2e1f46c35fdd92017751721f5e2fb2e0770ca5ebd0525d4722f9888329fa5d5cebda5e85953943063a1921fb05e0ee35fd1e735caae937045c801bbaba05a11a0de8f9903b72322567994427e59540b61c520117dd3012a06fe7b9212484136948527c2bbe587e4ba2e496687af85fbbd04dd63e513c0ef4677af26750f58d2b112bd1b7b8c05104313aea0d8dc01d87221473b9a97727777103af59607d2b162c6ea29d9759e7f60d0fb70cdaa787de324a0e46371fc583c7a5e9633c7688fd785cb2149d74b965170595f29bcf5db083fd6e504b4ee57ea0ba0bf336a82dd0c9f8c08ab446a9d1ea1377d35503206e657915b88e1ad3dfec0845a55c2faa520804f4477d6ffbe52bd37ad8499624e19076703ee6844cc9d09b16f2e3d68a5d584449a7d94ab2e232b397571cde83ca032f017d976692549c16366c99604c77904de8af4b0f20430bf31481f0d17216a090f0b5480f7e885e887a283ef8102692fa2a90a9916dc3b3a29e2c8e502b5b7d7c13799569d0c1a8194d5ff6e9e5864ad385915fe2da5ee46714006b34a22a9b833eb494793219e3f19371df2ca35c33ed77d4eefde1539c596340f6b3be7fb41c15ee4052a7b7d6b297a4a418cb0cce557b6f11de1cd578c7482e3241504e60adf1bd4c197188feffc64250c7577c58d760eb12caac0468646d0cbf0bd6a14e6ca47c839cb65d13987c419d5442609ad7fb076a00661cd291e863b669c76f05e9b96813af911c1936bbbeb79b69d0c121aaaadf6081883c1e6ec7df9fb7f66ff0b09e923f10c14a9ba3dda62927c718f3fa0162f66cf9469e9805135f2f2777dacfe331d852c4584e6227db841fecd19fa5f751260096659f2deeda435d961b8a24a90a0a809fdfe5e311ad277a0ff85a41cb6c30087088cab3651c0532fac3b976ec9cecf3ed2ba57c3bea23fe58873cc43396f3c348fa8f32b7070eba3697e0ec777ef0c5e20cb17361fc865d2746252f2cb1892ef90691d7a172c516b3c0b6e27b8729b03366b75dd818e50ed7105aff7f06ec13d9c17a72412cf7f06f32198f6522fc1bef69a66b6021df9a42a59253b8b13b3cfb9f0bd0edf438ba7ff280fd154790652ed64c0fbd29ccac1c21c76dcd5cefd11690c3c8f31fe3cff5ada3d48a51fb7d4d58b630941c92cee564b6e3135f23926a3f14bb0f85cda60f612a3939d1818c1fa28a279c7ca4cb5ebdfbb4ffe85b0940c70e71caefa5900f6fa2bcccfe1b95566f7ac8da85c9ced9abddcedf93667eb9d5d42a0bffab88d3e3c64d0e6c4523744083810f8fef2473a4e7a70784994a137c5851f667a2fe9f53e09d7b5740f8def97105ede83b662cd1623bc6cfdc2991e9bbeeef6a342adba27e9cc8eaf841035a10a3465a450696a48e02cad4c9192808f8852f5e99cfae23cfe0b87b948cce611f9ef57587e80c0c23a30ef5cc36271a4b12645a408cfaf9b1fca1c3c266e68fad27eed897b1bb33b0c5c1af441d53caf86e0f738c2d8cf019cb4527c614a68f9c9d91654711cae70d698ab00cbdc2a40f986f53504fbcf8608409b1c18d1ede25622b39dbe389515d67ea887c6eff91b1bfc3be7d9bbb356ee6ea311d78d04bfc8bdf52f0e9203c4844d67563fc50002d251bd7aacc38798c498a1338b1fe4b4ae747440f6c5a0f8c25380fee02a886dc938fa3a847db6364fa0ea4667d14d67af27e3d8de8671343f5d37c564c9acfe6c2fbe9de7f250c8a7b86139f4c7fdd064e71258af8947438755858cd1da4c9938846de12abf8073a21153f8fc6874b731dd9e3d67cbcddf622edc701ece5c6d80784ca94c2712938d1c369839a1f53f2f10a1a89b388b50a73c6b3006c28cc8a1284836581cdd4c482ffe0e41292a66b199d7aba0348e9398db5fd0f0fda528e234f8b644ba0f1770aeda6586af18f6f3c2dc829b3f092938b67f884bfc40d9e3941c26c235adf4e3db32a2a16a53b50003f27c88798e51c8a813bd56eb2bf53ef0ef4e2b3d6a6c980e72674f21d0bdf477f302d38cd22840e24c6e18d0c98cc6a710c8cc2a633a7b59a90bd893a073ea1b87bf15830e1e384749b25679f3ce10e0f9ab26010404a8df627f4db4205dbc7edd13620740e93e700f20975447a18b1454428311383ed5cd4eb6fdb520b08b842e2c419d786a2a92136eba3081763795cee17d4a5746406de0c599266c50455c71bbc3878b3399119a68f65c00f4a3f00b3c149c9c6111972e88123fa56d54ced86cdf807a5525e46f2178fda42d813b48161bfb40e499cd429fe502add5f80511aab5ff998e0a242a1a476014bab4805e337c3146397d366dc2a82206163d44061443f2e8b2cf125029e0454e58aa28b4c9018617409688acefdd067b7312c36a2755ab0b75828d9f692017c722c8d2cdc2bb313d68a4e4a9b03212d82f74f85169300749c63028f0f29bceeff7a542a90a272fbb5fe1f091f70b88aefbdfe8304a47c18b8fe40b25cb549f3c4b84871e521a2fa2cd5b2e026d70c474a1f3dd288c4ceda3022130e10c6c79f6f6f671ce6dd47e8c21c8d1d166919307bc63977a0c672f73f52df0527d9c079a9486cf295ad2a44527e321ecc03e9d4cd3f4ea1970e12fe18fed685358124512fdf5165bd3c5cc0e3e6373a49e299fb1a4e604c100e981a19428bd4e117966214b60d5ef0340de153e69c6b135e512f19c5565458a0dee4d1d4cebd55e8721c7020071c8c63d784f06abd5ee6ef12d0e9e89ce07cb732f954c41b53b8e829de4eff77ee45134103a2fd7a2dfb42c1a2e533e25c093e9abcc1d6c6204dc6e059614c0ea6cffe8e718acbe9c1e937751df9fcdb7b7865653c377a8bd604dbd336054636bef8e5af6e03a70e6c4d8577c084c8a6123fd88c75cc013301366e430e8892c5f86edea7b7a38da7a3dbe12b38952fd54652c940e5dc38d7eaabc4e6e621bf78bf72bf8eed930d0ba08bc613eef4a1bada0c4100fe64ea4b1197f0fefe4a10928b0ebbd1f846922d9da780383bb0dacb1c228d8fd722de3a63a51ad69a69c93f26832f4502981a3c53f58cb3bd77240d73c2324a3e6357b17c198cad87bab4c9879c8e8ff3774d706dc003c7df622522c60ebe14e077ee41c34027f2d907ab9899cf5451cf98e9a92a71aa649da2c0711b3a2117d77982e51284ed203358308ae2c0825e77916290eff356c84ba308dc48fd395e06d39f4382b70e3577f7330816e14a9966545ff4d8eb0e91373f0451c509a068e4070aeb92eeca09a7fb508d8ba284d396400e18f5d76719b3e455ba8c6b4d8880baff76b08e782df31e179ad65b283d89796bcec24aec2d4264f4092a85b3e3b990e8b6b807c9e66faf050f1d21d45908a6dd38ef9a6f0bf875404adf35d09429ef82bf7e118eaae455cdf97fa88870c4dbcfe8c8880fe0707e0a5b0283bd3e5071b6b0428dc854ac7c8f24432ba2e8aa6e8c2489b7428d7c682e44b858ed3ed53bf796c16a8c974e793eeb6f75441eb1a8b171d7bf97b09afa00e0d48a0fa76a9b9c63c287cb3ef58f0036f4922bbe019683ed3c610f013a5f6ef60533f422184053652ba13478373993ff65fa4aca60625267642ad658084a7aa2c6e0972aab8af7055e9681738c624666617f60db09cef296e390bd0ceb6bb10ce24ac1dc5a1728aa2a9dc9e77513618fdbddbe623d80356947d7f4c76c67ec0905e9aede5538014a8f704c23981b5562f6c9e80b1c5cef57c097a46039c19327bc77c93cc494e6eb936fbb21ec8f4c400368294ca5d5e01c25b7c62775b4943e5861c1539e1dfc4cce1e860f4f936023bee9eb77bc921bbef14dd92811dc93de775a4d2c46ce90667db3c758a296f754a8ef31e3a56496b0d53f3970ee25e482c1f53a1af8c1b45184d9f7dcaa70ead4afeae48a3fdac81192d6f927d4818d13a17ae8693af4c3640f082446b9e16d7f9287223ca562ab430b8533102f2479dab407524501f32cdba74c7c0f68c61a4db77c2dd87e52363bc66864ebefc5d6ab824d67bb68e2b0064e9e7c54405bc2eca8c3d1ef714691c17fddb493e6ed744d8dc69d9676566f22b087c9c5f5274435115357509f7cb6afe05f901491e15c5c2b829fa2281a6aed613f8778c94964632e15eeef1a37f2b704432946cdf3fde9521143ba9159f237d8471e644471a313ccbbfb12eae2d304ffcbe73d21976aef9b81869e8a2a4eccbfcb0495c08a40d4aa5800276252a1d4fc45555aa8f5d2c4fa7558d5aba3aab0629aa584b00d56c907dc1aae336b70d3f72175de393c5cfa92c431c30b01a1303186d23d359ce414c36eedb037a6409d778c29228b66eae808d10a797157611dab50af4b2dab47ab4b917436fce3d5eb408ba4b15469b39a74b108d6cd05a201713140a9d31b143df3836c3f07ceedd69b7b4023224f6fa327a15059ebdda5deeda5600254bbe9a5ad29365748e3b82ec2a35d1f43af408940a361907f0575b640b3e36a8215a12e71a692f31d191d8459e31679c6227a7ed2b66a00f58a100437d436661b280f137adc99ee5d57747627bd7e5630fcc4652525a57343ce543c077e08db61c931ff18e5f41f4c0acba9eaf119d1380324376fa2e71a121e75fe456004ee9580eab093d0d35550ffd9080929055654721f9f56a26eb8137549d6d8ad1ce97349be734f74bd342b3fa362554e5e874d83ee0b536ac989e267fa0f68716a962279c9edfa37778815763530601eadac2b7f06f4b7c0d2b681c39bbe4c91af0fea4f7a31a50927cc8c2fed0c24064e1b1db581b851c6c1461368738d032ea654e29ced460d4c2b831b15184be0b33351143ef0a5b6587f264fd44bf577ea4825a9fe8cbdfcf562b2c43135aa084329ea720d21b8da30dab28474d7b473418a60d5f0a5bb8690ca76d01ba6fd01e0d1f0e30ec298e76b0719f2a8d07d9498591f07d22dceb31f7f3190b03ef1182155cc8d83f8360bac32e9e1ae9f2dd52f75dfe41e8301804ddec2216a35578eed29c9c0b927f0edf5b647a63ab775e01a151e9edf14185a1d96fb74ac8d0c2d8031f6c13138087ed194159ecdac3cfe0a3aa8e4346dc4a396283f0401bd8017b5654d7c365bf701cfb03ec77691beb2b089b50afc2430d07ad18ab7516f415d24e00c61b5d99d4f83a9282afdb90caefc48f07d2908149eb31177dbd7b86bd99d0d7ff52e4ea8df5f3e0b1b34e2752787acc6edfb8d0c97b0ebe5f1ddd0733bb0d6056769901435ec1f1c0896201ad9c03094ac2f5335b814427764c05fd679595eee07bb6cc84fd732eadcf9ef091d28fafe1e26227ae22048b01dcd406c0235140237064e130b6d657ad083673801d81bd506a525069dfa59e6587183d92822821c0e5e2344808a53be34eb17dd31d05ef80750ca6ea47790033514874732fb76076eb799df4305d7914460e2993b082510ecb7ea4c1a08b2a2f5ac3bf6d0a226e0d203cfa1f4aa54d96d9920a972c6557fae0f3b0f5a25284d49db82a08b7082af9768b34283e899ae6c77ab6134bbcc9ed6de6f5029b03f2c2e4833cce8685812fa07d9417aaa7f8ca8dea12096827492d3786f60aa0c560110db958bed3a3227d8e5261201a7e21c3c757f376e9008851372108a2562f5e4e735546b58dfa7463d2492c32d1b025b56b9f16a85d96efe5a9adf5397d7ba3295020401fd79d17d97d4aee5a215cd56dd87f877b3ae4312be155dabdd2d885b5a03d4c83a23056398e1142796eb32bbfdf83f3907f6093ca4d916656a2bd6c30db1bbb68e525be582468c490aa05b0677340952fad1e32001f3c89f8ee0a559de7ec2d7ed84c1df48186f19ac6862797203f562cf05438802b4d6c039f1e68263c727e4b51ce7c581f0c6f39362e6f580e022568fd0d4604930bd2ba0110da9b63831c63b9ddb4ed4f103405d218f36e50e73dc42459143c0538fcd625907eae5a16c698c8ceaad09b49231c0242cd64f823b5b2a10f012b9106c3c2495b10315afe9ec54df939b2c9714372b3a13a8bbfe5384cc9d7c0f0d6977a408e290d1a00f3d1b25f723d2a7f5804477e959d03cd4ceaf536bcf4bd1be892ce7dd2c99cfe6d44bdd18aa09a5fd04898a89f58f14faaddf8e7c4a57d54998fea27f9fd34f51cf641ee226fc892795f1cf1c4b3705e91db17fb9282cf12a1c79401a50bd21a7afe3532be80119a6ffe9b3740f472972969836e811c8f62f8eb21884e12965528bd611b0437d02b614103e360b82d9cab46ccea08327b035c1c777ffc15c9a00d61eaea7831283742f907ac5364b6091c6e0f7f3b436f7c40d9c9444dbd82e4ffa0a62906cfe132acd30dec5fc59b2bf17474ee6e33ee3b3c8322b53c1aede611c98e458f24c0171fbc3677208e4230d81533ae6667be5c277e1a6224a64bfdae64ad9967baa81bc75ac8eab99c667547a288c727d5838ba85c1d70afc4f5370f59c009eacf6ddaa79981e57a97ecd98665a38019c065d54101ebdd3ac5983c3855863c37d962f29db13748b2ab83c61007af56881e784c397d21b04a4660ddaafe8aaa0ba5bbc924362efd94cd8f63b0e0660a2f3c121ee131efdf2d0535d809c1aa3820ab0a1273c68da6de38c346557d2cb11f8f73f1d5eb701f46e6518e0e9538c89f166f36eca21f827d044bde8c22ebd3c080ca6aeaa9dd57d07703f36e01dbac76897b0ef5049834a5abb7205f63a36e028f9a19500b5ad0ca1a35d80cbe873a9965615529053973e15e13ec56c172fe57ceb5da71ed459dd01a4ace6c40ae99a824b5d5098ce207d8c8893436fa3cfc0f712c2aa42a9eeabf373d3a7fa4e0773d41e6db1a3b1f0f98df490302a46c54988e8ea402aeaecd049a0021e01398e027620321acdd1cdc044d8e5551124fca4d71604e777d247d1d01d12980ca84993d689d0d554dbc4bdf26652c989c1c5da1af17dc70aa68b09b4648493c8eac4ace1f1fd6b5a51091c7dd265b5d118a8da19b86d5d55daf92f1c235736a9e5f8914b0ec6072a6e7e05027b220143c6968b1607fe7e9740d71a51e513f69c5254cb1f0044117705856e42c75423cd5e814b504b8ef46bd7d2a406081cf23a3b06918366aed92310210305670649693dbd3a9682ca2e40f26b77eb718673d92fea1093650b733f93da8ce4283af72d33ea56744bcbea60d11c311876417b0ef56e717f7445ab57166b9d8198865a8a459d58deacb26b35690da39b4aabd5d9441bccad4933833936d839c251301820ddcf02d44855779dd992c28a9514d1dea1a9946d3771fbfdf395623bcb4a6f4fe0ca8390dd1e9c91d6e7d6746c33ff7d59006b861511142d922f5f1c9abd9a106344e47e73bfe626d2da14c8741c1fac06d394eca297c72c48f21fb0cee319b1a0c4446790f9bb78a0ab59f0c22fc973e90b84bc9ea0c5095ef3387455511bb47c66f1d570ce12970e1b4849d04d7430dbe25c6d79dc59b2bd63e9cba0cb6c489e9af450cce5d0b432453a404fbcd6dc65483d58b4620c323020fe3a821ce2650927b5b6e20c2a2aafccc35bc9c70af75758fef44316fca58478a80d03ced20671e75bf7c8884b39d0edcf09060be19ba59dbabb8564aa685d216c39a05de58dac23cc28e4346f9e9e040701e8786d108cea77e06fcdb08b3ad798895404be66f115217e22c711bc6e7b27598da40c9c65e438fda1ef578af854ac61a8f8eefbbcc7591c821010298f9d87d9c7583bd8d3f8d994e0403bf688c1d65bded64059c60f91558d84e7e97d90749c9eb386eae605d8ff36952bb0ea883f712c9085c5567027f060311857640c74283e332c6e8d3ff85bb14f95e4bc12b3c84ffc1707599b4e24a646a30f3a4e7f38ef34abc7dedfd4f3def6df8bfd9078bca138c7119a82d29db078cebdf9bab3885b5931a09bde445b2953027db98e177ca336b1d9413a37cb44d7582490fee544040beb909ea39ab6b6e13b734975a901a6988fb3c80a27b5ced598584649aae9c889696f0db1293bbb4fa3bfd41bed2eb159a2e2baa103667439a7cf4e6ed0c2e6db5ff06379b8b526e99a771dbd6b42c7dba2e48c8f3b8738d7588e7d9dac2b3eb75b2687785fcf75558e738d46ddc6f1297933565bb067570b0c8671831b5acab52dc1150738681358a9e85c260fe9b78e130ac13f8c9564577fc81b9c66a35e53fa6dd1d8dff4b47327950d390af8a09c1cd6b89144ea67b4d21ac8f576d0c357c4d8383c5fdc32b5fbc1af03979012bc6806b4c01c84727c261dc0997d1ed825fc350d3d0121d9b29e06e5fb2e7c98f6dfa9d7af09c8884c088160e31cf1e8a2cf1372c75d3c8944e31370076292ba0186304a7cdcf8ebd1ce0db9a7fb0a9ca4f3991d7a7c949996e8cfa5260722fe2b2168e2b7839dd219deab839ffb24f97cff5fc3ce566862529376d784630243d4264be771f25b7c6f138e7e60e9d77e9d5ea6c6de3b56cccbf7a9540b366ade53dee86a7c03bc7ee41a35480d88ecddb5e2f29cbe173dec0214a34fed76157839b7b120f149be3c1e240b41818bc0ba9d82f153ed8fa0366d92848a7709fdd47bd02cac48ffcee3f790b4ea1b84edd73e85446748a03d9f0c9653ae5df24dab83c306699e401976c539b871a215b8e2be99ee252782f0cc406a9880d0ed2f7503412e15ec76439d997c61a7ca365613cfc9353635ee5f03f1ef83b48cf7bdaa8ebf3358c5f8a26f9f6d16471f7407ec88df5da0dc6d4dd0894dbdcab8e328ae6a35c63b89bd8c468439ea6a1729bf4d333a665b5798ec7a822b7ac5b477dc52320f163e819442813dfafd70b4c7a22995d8a157ccef7ee962a562b453f1cb51e8d023b81442959876ad6d693a127e84d32ed73cf6cd95981d5d65b00bde120a3de408bd16a00b187639c525bd607c57f54b2928583f86955a059116997730c83276624fc8940469b0d50631f0c8553dd8ef6ae4e7862ce250b7cfd29c5f2e77a7bdd922b1a95518ef38b5abbace6027b19651886147fdfa22edb16946456c7bc5f0ce972e978aa11d452f59c8d0a3797169b92c4dd2896d2f32ef62842b5a85f1ae442fab91218eb4d265caddd2bc4ec146a6a06b2ed811f27231ddb56d3a24a6d35692f6bd5d5cf7ad4d1282b1731b2574cb0bcbd161c8938ddd0ac69a16af0c7196a8d8c56fe4ff683afa87d6e749e326804f20030ac4e8573ea0d2704f7959d3e19f123965404c30593b1cc8505ff18063920a3b191c600eca286e85f1b5277067d20417b8a7213fc32243a6d934c8282e95dc20ee254d478ca11d0327589d60f84bd6c104b018d67be947a8aa6beabca0bac1ddb3a8d9f5f018798c93a2edf7e44ef8805107be6e72406540eb3b88efc2caa534a0a9ba8994ebf0daab5948583a0f17c1fb91c861031da061c799ab6fd9ffc5910bf9c48880f87982c284eab7f019b70e81b8be7a6fbe851a22a37ad7d679e36350cc1a26ca28fb3e5d5965c6e7464ef495f608fe3b3863150fab9f432c6c4f8f6c171ae161945e18f6bc4c0f6290263e87f5e7ba533e1788329ad786caabb2e2e94763da0bf61b6dcf11023476171cd4bc17d67aba0d43270aa79e2166289dd78943a242e351bfc5a663e1f629131f2f9d4b30cabaacfe7d3a745cbd85d7341d2cfe3efc370a4a3b0aa6a4a7ed4a0ecae9f5047d6d626cf6c091914dda3b05a408758c654161e0ac562c2bfcd35cdf127467e5913fc64d318425e098777fdbab400161fd2fb9b993432d6b1ec0622ee703694e5128ce0d17f8105e549c7c12ab00b0742fc289bcbb87dc3745a3cd02f7bc840b9bbff1618d5a5a341d57f1cd541ed9d092cdc7779a9ef6a8f76674110808b8fee5cf6ffcf6ff13a2bb700d8e43c10d872e020717ebb24179d1fad4a0e414344cbedd59a4ec38dbae1c1d3efe851695a818455f8819d53d250418ce94b6bee8c10444f586131a76f94018c8292d456aab5c8d03e90398de1a4e373c778d3599c3e083205881c2977b3c55807cbcf4aec2d9b556b63df0431b047af3e8250e41a4a38470dae56e304b408ec0b2f39a4c4bde4dba1b43bfee86000ea8160b04031e12c9ef871484b7264c47bff06bc0f8950b64b2f78885297133df0db98023d10a590c894359ba4d2a35ee6f6f4b52cd7722a2eb79661000b99e925bae7a530792be15a7d156dccbc8b61717fe387062676aeeac0186d14cdcc874d6784bb7bf35910e22b4c3e35e47c2c5e985cc0efe99bd68dffe515d8c287f1b79ba2c561ea37909b75e0a2c177fa31f730ccbf138f44b0f7c64f25812092300aaba5a136f26707c927b3f0e665f278b0d009146b7b08e2ac2a6f911b7d2b88bb74c5260faa55217f91eceeae6447519d57706e07bc47c1890ab9981709380362251214b6cb532f7919722b9e60e3890b7c0d8b05835c842b357b25a0b1ca55ee0cfacdc49b0dab64fafc792a693f3bb31eb8b889bf640593cd55902f2b0bc9dbe08f1e3a4b4d933dc9ed2565b5337b600b833b99b0c45d10bd3c6c9ebc4e5ae9d9ebc7aaab62a73d13cd8ebdd229d56aed99fc1879e5d5078eb7233eca87595f3135c68e7aaebfa26107ca4c1a2330b83a71e7d9b95b7843066829fe0bfaf4033c0d614f7777199831090a6071e8db4532f33fb3074c3ddbccdf2465345b449639ba43608818e3a1b4a46cfd2147b1c4da9327cdc563d70f6714d84b14bcdd119fb20c953feeca2716895901e502b6e1c3cd9b6178be049f08747857444495a53e790cfd8410d9cf690102024a03d2c784f5e5e517164c4a8848d0b2f4982770937ece3d0efc3a0bf7acbcac1cc70bc2ad0c03b03d2cb7c501a719584100aa9b24dc03da0145eb76dd4422d0212ef2ecd6bcc8770dda5954960b1276adf0d3a26c1d7bc3f7c1d8d6a05843ebcdf9b6f30e8eadeafa2d7280ab0970a4754fb09000b0c81c120fce087ec88a1dce137b769e4df5588e074212bb372e1a83af89e21caa72a1cfa3d61e7a2135d542aa8d4aacbe07dca3b0114eea270f2d3396c8ca7f91aba1499ab4dfa9577a09d79b9067dc8e089ba4b4312c37ab0eac6687889d8b94a70ef3ddf40d6a9e986b3cdf9688a5971bdeb8b08080ab87c7207ef46b44162d5cddc9f7f389b68dd5580a7c7fa75aee9bad66ab515a4bb6b58ba032f98c155b8cd1064e7e1215dedd29322966da2d90bf98be7a06c9ce6ad593a1cd2bc2829d0c5b2d469bdb2c63881c043a0c840f575c59ca1a64e0fcd6a77f798192471b03b101240628a1200550dcb148981ff337d871924d019215761a742e3cdcf204f8ca5e4654fe68f754ad9ed8eeeef9a81d971a7d8a87af00da91a64388bd3e4ff8e223b8bd445121e4d9da23439baa9ea4294e08b942eff676d6f2b31c91f67d3e6d9aca85055013f4b2b1341326840f2251396511322ffeac542b0f2db43a1e2740db5073dad65d2ffa649685cf93b4dc19d38080ba43d4a2ab75cad74cb469e0f61cc878c77f9400a119fb158eb298bb2876c560bbaab2195ef5a235fd5faf03091b75629193d16556c66e2c3a4241654ee39be5db4f87836558fe50242bb644768dcf8299d91eed188ff3ecf631fa0c28d68ac90c87b07532d4f7f75b2801b5fdea9f3204df3bdd98d5a62f543c5cf616168ac5d31e9404296f7f6c122a463619a19c1b20735bae2c78352b57ce17c7543b61f61a1c102603be3f7b2a6e82aefb9326288035b8ee075af3c7d588ed3ece43154bb70d1ab822d1a2013ed730be416a3ea03b71ce29b5fbf58688b7686c44ff78480b7694bd1b3308cf5f2e53856d8012bbcd08e217fb499fc0c0698be195b50ac71ccb313cc1d502743ed5fa37f51b1c790238eae19cedba209f466023ad179625b30cc59261d2bad05368361dab818c517f402d2f3c930b7af0b2f80a17d3aa3b425900765b82365a4f8aa22ae5206e9a788560a3fdcdcafafc3c06f4ebd99245999c79374d2731ce888f712ac933ed656a491bdf796524a29a54c01e305c005df0594527a29a593673e6d633a9f8af8c1991315b25cf486e441366cda8ec09db56cdc663f07266d6bb9a8d0d5d931361e6487709b7d3bc7ab1bb343d87bb42d9de950dae53ff6af6871f01ffb74e2113bf4e4daf673b2ed7f5604b9afce87a8a65051cdf096706dc89bd5d52e906d3fa7b3c7dcd5b1ad5dba3affb10fce6027a5d33ecf9c57778d8e66d0ceae9a42d6eb2645e56ed3b6d4426d3b7577dbfea4390c61064d273604a5c22be0ce7a813a2a64a9e8cd041e64b7beaf2f0c3cdad5cb07f68d79592e4b86ca7a5932f66b1ad599aeb21c5b65a95051edb46fdf4b5e543adfeecbcb6bc987ec0e435cc8968123b566091046bc422f9dafece565e6ebee9aa6508a1dd8d4579cabbb475729ec831994cb610862e00ed4d124478593b661560c970f795121efabadd57eed5a835e4c0778500c2fcb7811a37a598ed96790b7ad0466549633c37fea6391025bbed5428692f62d01ff9940995d3f27fa9870da3ad8faa96f65cce840ea52ec2c30a5c1c2c6a491d794b49e1c5edd47051480ffd4ffc940ca39e7bcc9299ed820b52d65dbcd7f84005065c800361b904dbecd2600a00e32c89ee55b5987b432a0fbe4be2d2ad464bed3360d1b94e10e1b9ce1144950a1d9200d65952860b65789e2b4a7c823c727c00eda3a8a09ac0d5ee997e678806efc35245d1bb4e17c13e65863521e98ed0fe41276186483399ce2881436e88552e4b1ef55a638e1b1ff8553fcb0b6fd19ba2cc74ef94ffd28b22d45af3285cbb6a254d589fd82899dcb41be6506239b1d3144e7f73ee7c41bf3a1f9d5bd6c960fd9af56cbfe70219b6507a831bb566b43d60cba4e5bad3fbb2c67192d4129fa16bb65c7462fc70a2269bb973563bf6c988d63b9a6f420573350df730ee6f5dbca4fbcea3ed2f26d7bdcfe22adeb6d35fd36fd1ffefbd86458600a556025000dacb26e9033e7425a4f0ebd7a0067100f8c6bdbdff61f9143fbbe8f3f33da6758ba61e780bced33a80ad896626d83d2684bd1c40667c8b4a568c106abcd2980ffd4cfdb8abe658617b6144f6410cc7fea9720a26d0fb40257a0691d0b88abbd2374c2abbe0675ccce39971510635b4e9bcf0c9243ecea64e704b06b5805037d04bb41985fdfd69f5fbffe08768f5328a56676ad31a55c536b9d21584011382f783db95a12e446172d2328c18d94a41e84d05a6284658b0844745e666e40d101ab086b8bfb90a60710465bbab06ed8a08106223ea0646141081f6c809470856a0a15246fa2986c29b13aad2d33097483c68b4b0e2276d8a1082d5ac0ec586fa4f6072a128cafee9edddddddddddddddd7fbebbbb4b6d55b5ab0fbf2aa373ee9a8ae24e7bf5e974ea506badb5567c3b10779a7e08b66da70f6b75eded09b35a9d529a75d538ca62ae50e9fdecfe757477ac6bf7de5bed64c240aa9829a8ae3e17d8f18af8b3055e051f05604fc8234391736256d326dcddddb350c6945212341a89122376744ce8daec440e0a194fd80352f055e059901f8b77b417541f9a62aa90ee186060cbf169f32f910348f1d7d8f6e2ecd9bed682a87d6028cb99699d11246825764cd448c89e320a9e1e0a2ab0e0c5f1029f142a30b0d90dde00100001d87e6c3995baa8b1ed6331675d8c40f49fbe7f1f9a140b81ef379a809d4517d2303450b69452a09cb86dbd72c45ead70a6decb9d536c9fede17c666797d8388f2e8212768329e8063108f3dce0cd66cba1a3535b89aa9d77cb36858cf217615d1d7d6fb7273ace86c106a98a0dd6141bb4e1bd608378dc601637e87d166c10ac608321051b94f56c3087678333141bd42736a853dbe008131b24b1b3415a58c5123b8b4534bcd1faadc48325681bdc21b14113233658d3d9e009bd4114b30df2e46cb047b6410a2a003768c1b7c1f73628e60d8e788317dc0dfad40da6a01b5431378841e881370ce8946eb3e5d4b1fa8f7d6c9f5aa2eb64f6257c82e2ae803aa50823d4fda4e3a980c4d997383b1e8538fb9adefc79e86cd39fed2712d831d39b6b7902a77d1f94936abe30659654c01c69982440161f92235de33ff7ef833694af3ffc4f72ddcf59eb5a8dea8b0ad3ac1163ce281b5fa633ea9166cdc670a459b5f8880f7dfe28a539d4b41068b499e7e1cfde1a4ed922a4945eec01683bc0e28c2983ca96a4339492295c02e5a4b55a5c29978c991a10c4a2b74119622c628cb1483798432cce5d450d56acc03767f6e5e011537b71a6de2863b492218396d9b3bd11ef037d6839d4b4106820187ab45a8f974399082de85b99b5b6d27baddc549c8165c8b025bb63ce096b538e7b855bb5e6e4c85ad8cf91855388058b695bb3c10bd92ccd6c0681ce22063d82c483b51a899016561fda3e4287462b11fad0fc6b0ef50e09590c1068b4113a25be844c8416f5b3d3a04fd3a74c6f4ebebf11b21694849485393217764726428beff19b086d9f3faf767f76ad483728438be516c50dc417d33659c4a0a59dd26bcdb1a3dc39321375066d7fb016fa0c92dd10944d815ef6f20f3e9b613c5e8cbf3ab0e99d7eb33f43b0e99d6eb33fefb624d8f4e67ca47af9881c5204d26baf3573bf28957cf995b3d62eeb97a66165307416c195c1c8b3c2a8db5a23749cd71a914cf80c76da530251ddce0e95a37b71dbf4a74e54e85a51240fba5bd3366f9a6b45852e17bd6dcda0fb356d5e3ce89e71dbfcc99546863d7fbedf607021bca3b78997acecb9db6177b9a810e5e261b8f6ac7ed6a65b337775be5f54885e4abf6610c55433c8f74de342f8be799957473bf1ce62963d39bd55e933c7c5cefc13a8b01326e39f346d57babb57ebb58e3997b252a4edd433a6fe95cef049e6e8ce6fade193bbd3dd763ad20f0c14e991952876f88fbf3f8be96267fb96d373aed4c4b6e3dc9a36ff6c8f80f6e9b495524a29a5f268a73ed524a594524a2ddd795d2925d3cea618534a919aeaa7a1d75e0e6ad43164a23876aca462b2d2ac6b606226761dadd7b45933f33693808c6c36ce8bd5c0f4ce6a2ad19d975c925f43f4ce9e24d449ef153760b1b3da294da1dbb414e42e81b486e7c475eb6e07bf278b4165302cc6584eab9b66e66d7e5797999dd3136ce7b48e334e2f143af0ddb97647842735b7e8910fd5973f6f9842df653303043647990b139b8e366cdaacd84d9265759556dc2420db9e54d68226c1618f109da34e364c47dff956e66267e7b11334785dce9c9dede2e22c4dcc4841a573d4893acda02453e846cddbbc50df0e6ad7f6b5d5936a01cc33c85d5b59e79cd3070a4a6863c2a6d5c6ed5857a880704081113b418dce2d9d4e67024e7ead07ec59c0cef978c940834d77ceb75c404bec9c1780d2a44da5926cda94be1fed8c26874d5fd7d09860d3ff34559bbe2d0d9c4d1f286ccba6bf82859aa64dff05934d5f060c9b7e071ee4b0e97fa086cda64f43caa62f822fba066c5336569b8a09d9542ccda63f652d28d4761fb255082123845c033b80c8c043520d43c0e4e031c4a69f01a5b456939452231c5a5d740cb16b6187a316c7a6417ad8f43358b1c114aa38fa3284e6671772dc9c5f4cc85af434c11ead49b8346b0d6993263fab239f55ae3ae9106ead9a564308bd86b331b39e28dd13a57361a87b8484a09c3e6d64b41c7d5642d602850e7a8e0dd0d9cfb9552da454948a5a51219e19393f3f679c5404af989b5e3b83b326e65eee4291e77e0d1ce532a259f496bdfcf58c769cec3ba0b7fc21fd6f246a32e37b59feef1b8956d091c836d22c9be3be689e77fc60daf2d3a0379a15a487117b8a5227f2ecd039b9e399417f3e1d2917bde5e799f13dfdef471d748e66ed6cc36e12e83e3d3b5d1f74f9410d1cf8f789bef7be062e57b3323c9167fec733efcff0fefefc3b123599e38cfbdf48f4f4469fc829b5a3f61f9ac73ccebfd4717e810d5dc79c74dad4ca92fead3131a0fb541946f8b3f438fe433f8b2ca89e364a3f8b95c506f45fd0209a423c1c706ddae5f47548699bfa535df5b0bb83e3411e4c9bbd3a0cb8cd5a19548806f560067d3031e04120d0f8008499cea4934e3aa907fcc74e3a0208260e6b41030790042a4016900cb50f7940c7854418c36a73cc491bdbd231e7426cab698860daec7b3a8bd6be87d1184104d249461101c924b9934b3289d401ad60319d6870759dc0b0f0851394527a29bd01634aa0464c385cd1828298314e8e854c9b4fcc0b3f7c74f1afb73a1ed973cff2c6ccc6ef5f7b00429284578414c1a16b9aa635aeab881827149a8031e130d0c636cb199d0f1cf40595a32936a98702c4d43cb169e2412a87992c202a7c595274496f7b9f7f2a595e121530de03dd2cbff342c7a56949a8681c6810a26b9aa6b50d269aa4b5fe22ecf551d43c848ede9cc5ac5892f096dbf5250917b163a67c78570d2303d2bf381ed1b7d61fbf62ac8566630c866be3efc1185f5b6b7d1f814c001249296064a68cc04993021a220a4313274a38123c8b8517640f615c6c4b2f3c6cc8c24d51c650020ea45dbcaec670535c800b38b0761103859ba202d0104d24aa1f7024c8326fd4c8100419299cebb0848d176e8acea506076622822c39e140af0b9026bbef06252a38100ca9e8696ea06117ee827c45e140594845e934a604859ba28765e1c09c908a928513dce8705394494470e04c3675c5b08423810145bcbebc082da08900f9a07693850a3745bfe2c2813a3e806de1a6e86ab61881a1f2859be210160e241152513e61caf2859ba2e4510407d298d28495b8fad2466a07aba80a146e8aa20f38d0840d287885e1a6b8002a1c580ba9e85686388dc9243680e87053e4c10107a208a938954c51dae1a6e85a9870204f48455966f7c216111cd8b3b56445aa051c48011329a70a422a7a97283aa8705314ca81032d08a948f43786ec7024781521ba4069000f1c09288ea8385b0813e44bac061c288654a441a42859e1a6e86ebc70e0f8b4e5eb82908ad3879a1d47b829ca5d130ef409a9487f8af3870a39763850850a0c841ca9a1c24d11031670244c89991ee0b9d65aabe73fee0159c4761f9df6e5e1b401ed586f761b0752d36e480a2aa0229fe7d2a5e73eb69b17d16a2780e8ee9b159c5e69fd4010fc467cadd504e3d10f87a6357b5982d38634235d6bf67ce8becd811f826118829f87af957080f4bf8fede643f6bf3157208ae3f17f3fe5d736f3bd9f6e75f4b4b9f74e6945a1622ae7fd377e3f65303c1530e839652dbe31e78db3ce771f7a8356fabdbfd72cc35cb4868bd6f7b7b216129c61252145e7f47eb076c287ec5714b9efc151c594fe3efff714a4e098fb3ccf7fe8a34993668dd8ec7bf0fb3e279af52ffe5a67ce4f5136caae69fbe6cfc4a2d9eb5a67ef7af673cec6d957d1ceeadffb33f933d1a56eda3ea99b1f1d89a6eddb60dabe5a3598b6efeff8bd98b6effb72d0e81cd0fee6d797543e543583bc51823d28d9e8f0afbdf6da6ba9a52fe728bffce7fb9c36dafbf9b97aa008f5fbaefd3d188a326adabeaf61f9be7e0f7e8f828dfe5e7ed9ff28100733e8fbef67cca0effb0e7c48eeef6592dcc9ef3398428efb9e6806f9fec6ef5fcca05c53b3bf31e72668f3b53fefbfcf697fdff7eedfe75cccfe3e69b4bf2abffe4b7eddffb2d6e3f79ffb7c230853234183864d1bd0e71515a7df74045160d1f741f9579cbd7f7fc59cf76fbca38c02e18904dfc235b1f7b558a45fe736e664e8771d91a8064eff157335b60c3deaa722ae62ae04ba5d9f059d80e3b47d2ddea881c3a28ccb4196c5a05fafa848ed0bb65f4db1d9341c7346d1a5f3e7a4d1b956d53973ee57d9910f25cda06f9455728d0e1f63f9b9591f4b1775df5152f94ffe1c31fdfdfdfc55d6e2826f4511e4ec2847ccc9a83dc28722d1b4e5af61d1740451a4d13929a9eab4ff395b7e5a8f8f0fc99ddf0233c8777e0f3ec8cfc10cf202ecfcb519946b79cc25c00d15fe9c5f6ce74c75db998a55fe44e95b52651936b372f75a6d3bdb3cc1dd6b1d73eeeeb5d6a8127d686aadadee4380c21443a81415e8d5829e9dfbe4e0c8f5482392ca3ab5bc8effccd07fa876ae07ab0d948e0f49b9b3be3a9a4ba00f7df72217f2c610a6e7ee8e2de54f6faef89cbd70e4801aaafbc07fe8e784e9dc0a0ea650a62fa8ad85894d1bb56336ecfb6ca3e0c8c1bc3a2af48dd4a3ff22cc86511be6747d5477e75163a5adf90c33139b8569f935bb534a297d7277a772c87faaa5694adb94c40681862ad4a933a64ebde6eeb3365a7ea884bad327da5e0f3927a6968db5d65a6b2dc8145291495aed9592ca0d40748cde3cdb241f46c2b463915215969574c4a48ac81b2cc0d975d1214477e589540a62395a58beb4cec0406baa9f7d9a449ae6cd8924c9fa7de2581d6f7b9fffaaf4e52a01618cb194d5bc79967521b565ad97654d51a09e484511abb24eb05250721e588e8c9a762401001493cb4385222c97124fa09e483da132400d24b0ab1a56e0e2c50528a929399c59e1799ee7756d9937bfa1cb0c98988bae3877c53e005496162e618ae001c6b610264ee5d23d3979126eb8b2064b8e9040e9ca61aa8aeaa4e82a3dbe364739bcfb63449795f58a38d2e562b39ce218f18adef63eff3e6e8fa2a41c5288602294d6587c31c61863ad1a741b63245dd334ad7ddcd0598c31c6ae75e5b431ceb6880f1b048ea08a28fdd811840b2c4861023311468bf3957ff8e0b9b266e70d71ba352d1b5e362b59a5209689889f967e603739bee049846bdedceb2b2c069131dd510ca69da661c98c744dd3b4c6a2e5471590a31c00c86087940957b6a2bcf1d2242a86a6ad1dbf4246e9de7b85e0901fd0c62a93b13233da22337adbfbfc2369e13759158916f1eea5030f1e55647c0023248a89d5911230a02c55cd74e89aa669d71863fc40158ad5bc79d6960b285cb5b7f1b6f7f9c7506ce48052b3d65a1c57f3e638b6641c37e81a97f66214668cd501858f060f40440909020b0727a61f5b0ff2f0bca61d61de629e2092e6cd959a92444d55e117415c617cc4cd67f47d41d2e4214bf3e64e160243a06a7188446525fd35859f5a5a4b25b8aadcc802431a2c489609122663430f5dd334ad3f1c3b9604d1b48b12a40a9215942cd961a8284b5d647a107372b3640b36c18b0998690c906f19cb5e0d4e474e7252961aa0bc2f49497caef42055770042f686c9dbdee73f0731a10c4859237c94f190b4ccf0198c31fe116563fc98d25f6ea8670162ea4b4a7a2283c011aeac43d7344d6b9aa4bfda00aab55a6bad8d529a376fca4974546dea5f4455d980260ecbc3f322c0444816141baeac6081da216d28fdbdf75ea4174854f3e6de67e918bb57e2e4302a41c4e4e6c997383c56c87a822a01894aa8ed59aa6ef0c104efca95af231ec4785765867c1fce7295f5e3862c584c3c174e5034efbd3b8cd060481ddd7baf8e1b812c2b1b665ae802e6c8aae08293aa05ca4910cf53e2b583c3f37ef8508483871f3eb471c12a79c20134e181ea9bda638cb115a7797328ebc28a540d63bc83078f0b045f85271409a18b3c6f099b22385c523a9d6e870557e238716d16335bb7c106295467a288140162938401a213064953c5218728426ac8bb1b330c8155250b1a1b73499634454c6e8c2352f8da7befbd5f9e57e3684c51952a306db40cb148b8423657c25c08acd1656103b653c4a4470f5654a6603172440b143360ba88ae06e788de3c67248c31f661410562ace810e60211657c30c2c215901e1d13beeacdfa6295030c3283a4f45c0d679ff6d65a5b24356f4e95ad74d6bcf98e51b4356ff5cdbd5e2f307594020e343eb674715a62d484e4de7b3bc02a226a86252e70caa4a0e5498913bef6de7befbdf7de1b6669df7baf0f329ee7795ed2bcb952539228173ca62ed02db22f907cc504302624402ab03871d92e2e37e9fb84bea0c1c14b13912629203d79524adf7763f7638c19145ab0a2b328d41d9856a0a0c694ad1a8cb470f9a1288626aca41d2892c4218143d7344deb163f880db1438fad2728262555592cc797a738cb179c242d48407c18630c638a8bde3c475953e4186bb9b06463121b177d6351bcb256942f1d0f648d54282f290b90e6b1c68512deec8081ca064b44c9148a4525c7dbdee7bf015345762b8831b911c60e1183af5c0dc1c3f36a349d99ba1186499a333a964ee0e16a51b2b51bc3d7de7befbd75df7bef8d81c48bde7c7b5ed69284892dfa228fe64ea7d3fd90aee55575b459cc6cb5ac948446f6e55896a625e99aa669adbf96a065457cd9071411a67352121297c517638c31c6185b0cdc9861e90a140f3ff0c06121523b3cef8521d600c1a5858620c0f81b2d558b0a5c74e8b79382990d4135440521883821081962a0e25eb26240c1c31262c9c8bd684d4129c95154f5a6c7152c562ad796229e25773a9d0e497a160b619ed523090bd7552642c9427901855edbb576b8c24a60e05825314794fc016fc2ac0d1d4ef28164e6e56adb7baf99e6799ee735cd9b27c9517aaa56f557b62d401b023d6e9837dfb915f712b12fcd42248b1579f7c5e97bc37defbd421577efbdf7e66a731f7e8062c5c8045858900177ed09fb6a5961e9291b994e3a9d0e4896bbed5a4dbb0f88e190d28586861e7078c6d9f882e978dbfbfcd7e09134e6684988274084cd1c642e182294309e5a47660862978c0185e9743a1f25c6b65fe1c235b659cc6c7b049778a864cc9a696ae810d5400008080043170000200c08060442499285699ad8f414800a569c4c664c3a9dc602a13092a32008a22086611884611004180380634a59a42600471c1dfb6c713b4833f5afd5912d46e3ecb860aa1994b4fe701c9d03d9fbf7d0f1aaf73a3721fc2c5a6dc720f353cadc10a689976f5ed4584f67f911df245bbb1c05828bf6b97e6bc5963b97596571e304aec4c9294da166ea9ee60bef8b7885ee827b15cbb93555268b85b72e1caa921e1edf676c29e119f616a3a1945edb7f5081f2ff974522aee0ab99a9d4d8c9f8ffa94b3c3f7e4c659042abdb51ca1d874290c96ab8c40ba6e2a6f0dd14dc06f2a5c50768f9cc9ffdf0c3c7bac5e93fe3725863a2eb7818d9274e005abd0b3ce1fea8afa200bfc00b31f07805e5f1e29a5c9fbe48a9ebb33cde5fbfd058007437b277aa99f06f481137cdecb6d262fdeb5ca9bbd0d67d76276825bf8b9ec1d81f0f70afb52233375b43f2186e50c74d044f4713b362cfd90700ef57e9298e5fcb0424b4bce990869c108893ea9a5159aa918ce4d0c091d2638fa6510c2de739e139f2b8cf70edeae09aecb9cf6cc3fea8a95de1877dd7c0ae4c59ac0628a53e811745dab7ce274101630fddeb4243adbb33ec0615c86396f65c293b94a2097613c4370161030c82534a4832c1285aa61a0f40317e0172ff07f5a117304965e4be0af44fad6e4174ec5878ceff6a91040acc32965da42149ebf0f5313bb7917ccd6b24d21070a83e993859a63226cde89d2c864a7f3046d2720c90a727133b04a8df2ac9855bd09d9af0b249645e7d4c44f1348df61b9976fc94098e2a60f98d70920c8c156ae7b7256b57b0d6be0e274557fdf9f4b6aa6005c05140e3f55f8a9f2fd34b13c4194cbbed49effa94a341c8ea83fa3835cb5e300a73530847414b118af9efeb1c7336990a035b7b752980012ccd1aaf4beefc9a9e66e51d7133005dabbc6ade25152400b98a547afc7bb23c905f095733484bd4c57fa2dcf5823984656bb92e3ab95489cd9ae7020e0aaab0213833eb1fcac026d2bde04bca15fe2ddd0e450020a6f4e7c515356504cf82adad16c46aa31bd4f2819b73749ec6c8c186189311fac0059878d5a883375820c044fabd2b1e8ad871927bf9009e956522b221115aee7128d3e4f271288e88851882528bc26689f4bfd973ee0ad85a415adc9f73eba60d7a32cf1177111bd8ac9a2cb12f4445f5aa6f0c131bb5259697b83ee38ec5f0587f430690d31b5577e036006882a0be1a8e2292d57a0f49a3ca8a4021ba4027d3b02d15645a8bf3d243fffd3aafa720ad4daef9edc0e21ddb0c746b687d2c27247c4b320eb311b2362c2efdd6a0a9086eeda9cbf093ac9a0586100213b39a8cd0b65c8abfd67c7c7bcc6011388f79955701dfc4431b7d1204947646795663e0ec270d2a094d2e19475d1b700b99323e1562f2c2b566f60ef85a605a99e32c26001925f3db3005801bc1ca13bfe31f67c725f9bf1eb25c3ac32660d77e1a51f2d5aea622c85def1cb7884876c33e2d1ebd98340c78b497af6b745c11741c6bf22cf1f73cf54f82985f10dc632b04b82d4d105ecf2590749c93beed9ae70473847c6c029c5969e2a2406c801091198ea62bc83fa7b3965980c1c6a0e11c76cd9922d3d9bd663012cd07847a6a89df6c71eeb3a06969eaa3844991878e208493693a522013a0db8284db2c5a3162025d6282275e4d071d33c92b4f482d0328f977c60c36090abcfa438d9556580e9e20a969688f49937ca30200487425996c1d22983e8923c8281649b92a306f7eac156a3e8db56be50d88706693103f07bbb90e84f3734fcb23406b13d4a9acc9110c2c584ba11f57e28f8d327916c537021f7430176235a7e9b6a56485c1609f0904b09744be1f67a15340a10f292f81fd156ca054f0a371cbc5d195f4121fb4aff0d867b9be71a0940b5e3c29155986869060fdaa46e163a52c8ec056d391d5624539b13d3a56beb599dd0be33e3abf164d0899cee373113b3ca03df7b7c0aef5c1976ad5175295db9d98ee1cc3343e6822d75f2d147279eeec2c9dfab351bb605d559a89e7bac37c541ce31ab1486bfdaf7607ba3cc7a74a54420319fa5e858b9c651b435dd7da2aa9ad273e6932fa9cb5c88c0335a6fdd432d45fa67bb875d152de836e3cd9fef83b0fcf5b9e3e080c25d0b6de72661d65ca3dcc8abf3597480bc84d4171f3c076dfe23abc3ae6bea51e9e2b5940a742de4b2e9122dc20df62b789a6ef5508c9353d5a82e33321c50bba337eb3a73188087e10ee0422a21c48ad2c7a623f3860131d0d82b75bb830e43bb37e9b8f33656600f510e4bf143cad6e5ed720467ec96b655358571a6bb800f6f7badc895193673270a93f00bbbcb5c5574eec031f3508bc6b7e03138ea2c061485b00f82e349c50eee18440538d0c534cc4ca6e9fc91582f22b8515d15b9994a0837c26459419411948273e4fb51a158db2ea04146a02f9c2c6ea54ae5897c0d25982f51ab6d00cb020fabe82d5b2f51ebcfbbbcf84822c21b6667d23023cad66afd36e830301dfb206b937b24823709d87af0fe19b9a2e1d34760a964bf8f30e474de9c5863b16ae96ac9f65cf589dd229d11daef39593458838e99a8c51fe6fd31b23ed088a02254ac8098bf12b3fca11d670598d854a6a5cd80d7bfccd057c4eca37df63c3cb463f56d3fb012f8be9c21097857d8fb525b7284545f5a7ad7c2119a9e34c2f008617ef482529816a16bafc1da9460cb4da84329846ba2bdf8f2c0d7ff55e78b5ba1a4f55b76b3a2feef87a9b62e1071be1e45358c3f66f9208b5ee537471fad28a9e72af61cb688ae5e86a95e7e6be2dcd7d00017c3c90527c1ded244b242ef72c173dfef41b115583369148cf9f467263408e41c8f505c2d9a0a034afabc25cecb577b4b727530f966e492106194608934af22e163a4509d2882f95db647115d1ee9d6ae62622d788861ee3389d8421afe16aba249cf323d53e26bdbfd87200e726fcdcc72848af3599c5c148f52639a3e07ca7ffb773be20225f873e5e5ab18652fbc04a8dc5ac6df0fbca395d3b89ed6c1f7ed42406d7b8d757768070aeb0708f81b6ee49006170b6893aa4a2e6838feea2ec529f319ec69068220902affc8e31179219acca0a4ce326881fd36dc71f36e34ed53915cf41e8045dba11feb100027e1b240ff972dce3bebeae0fec5ef2ff9cc686a26be631987fe4b1eb4c0bcda74dc532386b3758a9441b0e482a6b35f825f74e33c9bec95a55a0d6acfa32cff7690c1e5f566b8a21169c2dd7e59f7e1baf7c0ce5bf5204340a66402c880dc90d061c4c270088995a3017a0b17c815cfe6ff1a14039200260cdd8ff2afe40dbffbc5fe441235c826499862c074407e47b2ddf50743db9cbbf64bb6fa9f1f70eb420be43edc7d2bb884131db127ea1c510109d5253eff6ed53034733e79173ec89bf1a89a4884f4541e8a93b22c5351eb1f1ce6aacf46c8f4a22d7135e5169e035b092363e8f244fa552319b0c7493d919b8f691ec95c845030fe9de2bdb27225f293f85ee0a48294ec539648c0a907e3990f81ed1391f9d97753d7039c82901c5a8fc16d9203da4003d0f181210c0b23a2bbb71b588a804e9f3b37ec4969c7dcd7aafc4e88105ce08dfd9f0deab5cf27f9ba06685dda5144928e15c7e40b085bf72706f737db9f45b7335d325f3daea1196895a82bee3786e72d8f6ceaac63d2e7f734c352502293e897e245edcd49b6711eca07befa78cb3fb51c95b4f1bd184ed88b67d00a71a04f7f49a053402e408e6da6e0a47a39c8344d210e877fbb60ca7ae7da440c2e5c45dbf488f32a782499d42acab4f53778200952009ba20b3447793eca761277ed1b316a67d6a802a2096e0ff7d3cd9f2f07855485f4d79f42f55ab5a56547600dbf8ba237e10f003d0518e5c2ac37e08969bd5f68ba78d65c941dae5bf034c54637a9be30661204d1dfc7cc2305c6519cbd63b5ce23b97b865fb9f599f717262fe23534e17985bc19ee1e2cb9a447327a8af3a59eeab73a773e99d14445d89ebfd7d631873d38cb457e42e8581a864626c2d62028b0f8925b8124a9a36e9502228abd2255924cabb8e0b84c9d6500fef1a8009fe341560e11c6c89527f3d44aeb1a5ff3e9f53a2c67afaba56f597555146e28eca44cb6145ed1695efb7e65a4d410710b728ebb5099114a5ea2d41b5a870c745842e09ee9ba773c164a43faf39b6aafce8cb9a17ca262d60c98afbbf2c12990848a28a0f731ad86538f40468b96e33322945e33e4b14b86e7bdb902cc1eedc9f13d1d81fdaae501849a15d880bf2099f4923f768fca0bdcd498a53e49fa7fdf8eed6ab71f917af3e53d53f4c445baa1b2d2dc9d1b3e68646302b2743a619f62a4601d3ebf94830b3e8af599cef76709afdde78662d228e79005feda6d4533e5344c113db28c8b9097dc79f9dd0711209465952ba5d08167ca43a6825b19d002facd977455e918aacdba2c610554d44b11f7deef5d46405749dfa014b9991b162942b0476410c3d671fb73b597bcdd6a1d9ecf2e23e7db095a7761bab791656f24b78190f002500acf835e652ab38ee9636a6bbbb2b67970c524bebd167e3ba26bdb6aa6991c8d15e73e8ab78813fcec3d3feadbfbec6a9c76533f55a0b970147298061f896529e2bc39461af8b5035c5f55c37decd4715d6f8040ea3610cf6effbc9cb5fedc8e77f05c5c39ee0d7205d4ee382ce4154f1d6ed03eb9e0a4ba12469444ef299a066a5c33d50a750c88b4c89f16a20b179eb5d558baf1156dc875b3221d1f27d6d3efcf290b391e5763920a40afc78fc019dd0c701421479c6f9ece52288a0e64769ad6290bd25cdb1744f47beb7302b346dd71fc1732e45bd31333492ecb5619b0f0a3009409941fb6ee63280f90b26e217cd10c74e155d2a9c4d70bc6ee86e5888cb8daa1156189e3cd405198c76a8ea2c443cd056d7b25144509fa84d04ffd2664c1704708c78cb0220ed7893f49cb6e12c081646ef33caa0c42f9460837a97c3c71d783262e951c7fb9416ce875b08e0c4faac0188952dca0a87626deb84b104d3206e77cff636a980910dd7b6cd6ba3698837d6812e74a4d3333fe7c9f46f4528cbe6161cadbe90d528ebcd21f197f2bb4bf9cb380adb9ad6d030cdce4efc15413cbd4718c133118b6ab67e85ffa0ded70073cc340cbd88002cb1e37a9a9283ad829a9666ef0c08ec7644bd0b80e14b08d5e4ae40d3bc6ff43b0c425c647f3876ed15eed1cb8699c6fc40c1001fe296bd5c8390ac2556ce7da5213dabcf3be6e70ebb8ebc29b09bfef9c0e40388d397745af58f5cab4ff0b6337dacc6a9b2d7997395976349cca6c2e167a362977da96e13429595ddebb87e4ebda71a971714ef888eb75fa5c991840430438851440fb103da1236fe9f892da0be624e4be6ba09210c2afd29adc1221bc5ef78790e1f9f6cdae868792894029c5eb326f20b33f6c4ea14259e76156bdeb1238de0ff5d67d9606a14fdc73a4cf90240331b02164470f770990a2fd84f58c50bc1de0b5410ab1c16a50d4e9bf9b114dc86ee09483c27f60983cb9249e5e1821db420cfdf28622a934afd29cd768ab9b99432ce22ab5f508bed267014026009f1764f02413ac3b8c743bd4b61a6f5c0bee3386791c9eeb3a0de7554bea7ca1fe4f48623557c32adb297e8dd724d8a5f77a4d6f1d79093adefa4065702137d27fe780a44e6f788b76a84744827b516d13f3d3d4144e82ea4323c8ffd44ddcba278c4e940d5d089e1ab74cde3e090aa8168f4b171d40ba76543a70071cf27cdc2fb6a38928709ccd477f5efa7b745aa8c27862f881889f0dea65926695666e6eed4de0c032c31bcc3bc9c16556a69da796a421af91a0c89e18d7bb272d7feba646a367fd8dd26e27240a38bc2edfddc76d750b9f397304706fb54dd7753a327d56590b77e203061e412764f61f0bfa1ea056f9d8982ba8fd12962f4df05333bbcd94df9eff502b422a29eeeb7ef2657652d168860d19debdc75fb6834102eea0aad801a9a2d2242d1c84b7ead563eb271cb0cb17ff5131c117c1f779c23ebc257c7307350e30bb02c04219521e0a110b25f371bab309803dfcf651ca459ce5e0ed053631e26b3c2890857a594f6fd1813670032ce09d380d72b6a0bbcb923879f9886f360fbd1225fab8e74052974bfe5f72e32e4eee0bc1c2d128548b2f5e91698c87f082ae3d7c7ce462cdce8ede566db87bf3642efc4b3d1444bc9ab50ec9f0d8b7fe3cb04f16bce0eeb437f94fcc49279ec5d2edac2ca803eb2de7ac370982654afb83002302d6c17bdf31e3b46b9f951baa8671efab1eb5d7c4b5cbd788602444f9c8b92fed06794c301c155a2a558cfe875eb992e90091d63a253f1637ee9b01531da027eedb23ed237d9641d5fca6a827f06c30c9fa2f77880dfbd536722da87001ff8fd8198c625911af8639532acf93936d204bff3fb5d07bf1320f347a3a077ebf67efa4aa6e835fb03ada2967b33581f80a0b008f628b5fbfb3b08b18fa1c89fc4f54ca84f184130dac132f7a9243f6f68fd1b9891f4cff0c38bf7d49466d64785cb5e8271194be27a69dbbd06ca1224a8096b831257c66dddf05a9ab7618f993e4d7112f98d578d5e28e7f4d7c00438499c9c41dff52ef98f4c2439cb183532b762fcd3d930ab44e8c03e42868456b7bf6d27264f62f1c9ecd28821dfc8baf3803ef1c30748c1964a6cbaa5b20211052018500b0af182f3ebe2ff9e7ca3d0623ebd287bd07d8bc86ef4ec4d5a18c882e8875a3489e50b244f29829e926a2d628529e19e5fa212145e73d302c1664d180a4c5222ddf7e2ab6acd6f455056ccf0c6b62f106449c52cd099ae1ba4f889320e23380c637d9a1b955e1300d598d00db29f7531736c29c338314fcb1eb4f5651085c93b94c212e2addbc071b6386fd362008bae80e27fb32f22c9055d4472ab30d2f0c98f683420c5c1d3bd2b184557afe27b85ef0c4daf65c50b1efb7141b69bc6110c062893ceb7a512e10e3aade9752a4b5285577c1d70f7a1983ba5f31ea3b2e38ef47c0c3be1bfeec445a8c16b1a88ea66f7ca4ed98710b3783850e8541e1dbae144273e210c2da46201684a97288db1320c757c72d6d13d1d811c08f40bb5f12174cda92b9235c877c37b82c50f2ea75dba91a1c305f5f32b3b379c0a831c23d5d0cc0789b5674c2dae67130a0e554cf7c9c54c66688df795307c641d0cda102ea0b33a22d32301773c8a9d909852f563355cf27384e588e253413a102ee405418f681ac4ca363e38cb151f7380c2366fdb6b19435f597a05034be190011139c83aea17264b1a41f70063c6a04578194750ddc3421f7eb1548262ca314d936f1b90f8d5592d2e026d190d676cf50371be4c072c29bf6f24a5a106e881f6043623c3e8327f8e2c5d1d1071fb72e0c39ad3ee39714cd0dfac749e11d17f2749240b1d3ec8fbe279c85272d8f2241e34d753b0dd0a0d363d0b5616d0283ea49ea7f2ca8b62400b2f1bbe6567bd86dcc9c4b17c21241440c68a3caa501c724aba2be35f5939a7ab66eb7234a0449e6802d6e7993d1d7b306182834a8592a3c401c84c6a417c3483f9d74ca465b3fd79c14ebb0b9d78d3f4b80a9325676c6389e879d7e4ec789b99d4d7dc113c9168392af8653b197e0449f09b888e576252573f290d7653174c18ec16fe05a0b4832575b7af6d688b732d84cb74f19583705a8721991eccfe636be928f4dabfdb6ade4578cdbb44f5bdb37b1c493d2629c6678d85c0e7ea7be1dec89d43ba622bbfb12e613711e990d7928f2586175f8d9ad81032cc3d72e1b9b3a97b6328b4500cfbeb105a2a1f13610da26de3bb1c52481f8a85666ffff0efc7a2a40ecdd75ecba1bf409d7323c9ca9e4a5cf565f644166aa224fa7b79032842e4928c840710abbca10f04b21723c6f4f84583b55651f73ad29af38f252bc2bc148426d6988d05e4b8526d196e9db1b9d0ebcfcf175df45d35c6c0fbdd8c58c028faeeef6fd6921bba1b49705a7a2a3e86177dcfaa963f8750cc05798317e21915a9171814706f71b88d8f79c06be8a2a318eb9ac2520f8ba084b90b8646a81f972d0f9f343b7d9c5a1fcd1ecd0059b8abef65f7931b9101400386d970150382002621f1300b88061678613ba7b6ada24781ceb6fd1c52373adc14d184b8243b4568e50c1decb24c74adc328ee4e0bf7dbcad5bca7cca540d942248f19b07e0f19abbdd1ed7f265e62e6e370b1237df4d6dbf9fc08fd1e80ee232b9913857014e0af865b144c971e976c3935a2ab54a27431023e140bbc83f8b7af9c2c793c9c8a49d9a69b4d03e720773a982f3d5932c1535fafa08ffc3c8b600e13c7fd746c52af1c201bd4fc76843fca4e14a4fe632945c34c8ea93586e2c94401a36835ccf9228c6966dc10d7eba05a1fca8dc3c76e879ce872592dc1837427a712a897705d3fcd7712281b3de6474e0901b11eed200993179105274e16dd26e47408df914378966090540cdaa55011b1b325ecdad300ffdccc10133404cb6e6fa4ba775f637e770407bc605220466f29357004931bde4dbba14ccc19344da0ef9a6e41604d2ca250e7445ee9ab723ba9715554e814aa9bae8c7a8448eb971830c780638321358f44aaa47e43d13989c2703434380f65f195e33fd3971e60f75ebd3ee19eca82d964d2c314c3977ffff2f791008744da08cfac2404e189a9fdb9269f7e5ca3ffe09cf7cd6271924b5abe546e4b0e47a0c5b5783b2e022e742cb0c2ff15b0d7474659f65b83183e90e8b50e47d5a1051870ca683ac8180a69ded554e82640546c8c0d277ce3dbe3f9ec75d6fa9c81a7a351d4ad01729cba9188065ee802b434bd22620af82932cb9ce691f9e516a7469d5afb8aff9b18492c5307c366c227be8805ea79dfd6ed2bb36470393d7aa4d575e42a6ae51b335516c4fe49c9199b0cf5806b9bcf0a395260fe6058f174b4f5030b4a163ad93d37db4f66f025dc1ce87d4580623cb2d38cc44ecf51c52951e61a3f363806e9f64ae7530475e0682f0de2668df18d67b99b37b60f9189a2a8c32412ff818d579ff39d2a96226d27b7fb2f278502c6e37f5c953d25a8ca0152569f9d3980c9d2ed9cac4a45bb5d3ae7a09137c935cd019ade00ae40068b9e03dcc948c02d9dbb02ae4bc37635cfe2437bfcfca3ef19c2ce402f7c4bc0553121c10d3a64e1c931cce76c749590b6650e6f4f706271a336cac87b96ebf08956ff8c98a40d32dbf180eedd41d0ec2ab91acc2bf3a6f6f761ce8f3fa4f219a198331f37cb537c070c91039b90cf31dd5f1b6d6d726ea87745ee650396f76883391d9e137ee4c89a501f1fd6d169b66d9a4814ed181ca9aa0ce67d5faa749bcef29b26b8f615327813645d22b8391113d34d7e02246afea88d7f17662855fbdca68d15d747761792437cac5aad9b02681d996541f317320595a956fdaa94150dbf71a24e88b7d2a2d032fd85f48f62c60a9af59689cb7acbaea4ff51ea32d1330aaec27b832fa668a57314bfbfcc257f54d36c5feb55d0f516799c6b0629d519198e67e83b4546ccbb9409516d54d5d9cda8900a621862372a9bef74ff711b5c58728b472a0dba9876a8cc1360b485a0801fc2b6935b3f9574c47131124fc74a9c403676306506019b3b662db263fab7236291a74ea5ecae1fd74443544e01c3521bef682baf139dfeae781ca00fdc0a945b29109209ed8a2eb4c5a014dcc457f4144bb3eafd71c634b0b5bb985649871ab937df4a172ca8bfc4b6cc2306c96f9241273218cdb1d16266b124174cd7f455de18624ae6ecac7b731d3b099cbac5241ab9ab1caa528151679c5a65f921089ead80e797e2a93eda25875968bcbe3e61c95a2c62ab6b6ca01e026d8ded065411f7b18dee1a3ae23f414621e34dcec2464d239747ecdb6777e7c702e2d33609f29033668c11b290d9f1cf93dea21508304d437e2590428b9dafd2a5c823c4de1512113426268d4da7d7a10bdeb4bd78f442dd8801902d74e56da915464c9578a41bf2e2e84c9329cdc3d8e03e018f22d160a5fa71d4d12b8b20238d8cd8509324e0bf996b1cc1866eed5b82f1c1debade42a4137ffd240410dedf0c15b2327cd39b7780f345f27656ed99967bcd2512e6acae9bd88678d87bfdd821240fdec5ae8678ec86cfb1bfae72947fae7f9b9829a2e2de6e183c1fe253acdffec941f3a1507beab1426789e7d11f7ec08f0d2bf33fbeb1acd461d14901eebc06c161fbfb90c282d923e85c89d9a05d5b5e3802472d5d3239444c378d0ec22f49257906b5cacef6a5c0b3ef0890e0727986da17d0b21b955dc07c92367c30b62da2b345840fe3d9a63a1efc3e861d1a8483ba6ae2152f6fcf313d6310f7f8cc33e27bc62408abd3cdd7c4efa03f0e4c24f7c38e9a2478ec83e8a2e6d05c0b934ab160f6c45d03c59deac03f94d99666311ffc848fd0f9cabdb2c31c86997f7fa6abf7b8a3fce27aa72bf9a57e95988fbb4d19d0154baa372d54f6565ba5375fd001845cfedc5fee5bf68dd4ca9bcd6f2fc20e53a242b2437834e9ac64ed72c40dca23e62ad36a02f10b64497e3d9c5596d1bd4188d365a75e26e88bf07ddb7496e759a99b3c01d1aaedbbc4d0787e2aae2c0e6356e6616796f9b63319cc5c29d66242f9a4ff4a75861be0878e84e6f2303d8742ddf15be0828f4e03aa0a838c5c621c6efb1b88514b8b92c017e2dd6506648af637ebc2c3c23cff827bf1a4ef8fb02cd0852f3a12311134add6a01750c27592e6183c00826251bf7effaa800a1cdd54838f8ca0039fe09dd108fc9ef60f83f2d5caba096c425371e5765b0d0495b872f5ae0ba4edbfbe4bba3ae8b6fffb1dbcf222e0b17b06941ce99657c72c0dcc75fcfb459ec391211a9002e36fed0807ba160a9595d98c940432f50de4da88ad4abaf6af3bf2bbf530e761a5b52e618db167a0f06a16e76cf07a06b349e35391e9f8a179fe31e8b97b72b58b1cfa6dc7558440ea558b2f070e1a7928a4d852e389b9f2522c7be971393c2e4a8440a5d0c793f84ec048b496c23ac5527480208616626292058196f5cadc124491319965caef163012fdd9e4315dde12a0bfa7fc9969005bb635520efd5bb469e54d92d60b3f7eac6c98bcc98c9e7d47a9f69dcca8e2cd5bf067c4ed8e53b65ed813d13718c16100c6459c26eb4c9ef58a44729c27645a9e24417a162f69efec1b2dc85363fae22803c72bebeaaeff4f8fc8c2d2667c16108cd886ffd89d23d9f0b37ad9bd16eb63867a76f5f374ab37743abf043dd594341637029e59df7d452344df405cc66d64b0b8f70e7d956da00c73952419171d0ac2aa94c986cdb102fa910a9aa7a0a9ab8266f07b0cf0737879dea738e1a74caaf3c0e5a0020a3b6318924f4e0929846cd9e93a01a933bef3bfefa196e3db2bb2a14a8e5f5d2b672680e4d561637b00d6b3e154c3675df146fbb2238f05744bf11a3fd6a8ee134810538be47d1a6b2adc598c4e7b42cf5a723ba92c0522dac961a5e1065972c967bc4c338538297e648b468584f023220c5ae89b819432588b07ac6fb925397c8bc29a627ca3618363e63c09aed2de3b78c9739eeb10b4e1b65c8ab3b4822beee0831318742afc358254cab720f6db7301644a68951ed39fde288b4e333a7c5533c6d31b8496d4bc06bef6c823560f8436d88fe1a404d719939c30d8cf3f3d82bacad5cfe05e5777cf07b6e1655607e01d747693ea2e0b6fa8e954636c976d5a86d0d8199fc48ad6cbbb92b22ff4b0d7f9a4eac471d5500cedace429c7c8f445601eb6f3803c97de6bef0e005e78793a0a2f5b1bcf347cac45a7ff0f582c75a5ebb5bedf53bb7aa8f0b99f9788ce011192b66ad55fc7be25820d6e4201f306005bd15c1abad68abf5faba4d030ed77faea8946be0f9d2663537f634e224519d543038d8c4e1a19f5279ac5a855aa7900452726107567d37155810954cf89da0f15070517e4d5654b3121d73795383d5054d7111b0bf7b7c3c3657821924011c391225bb39e59f5399161fbbfa68abf1bb5e1a0f605fa759171ebecbfa9be20addf42be75c1ee4ebfc5091da8fcc5c3a9acad05538cd13dfb380b521b869a215b47d269cb70c88870d02e460ec43b84cce70d5da74157c892a26baa0cc93a7a16bc4369f915c9e5bf5d6cf5d5c8bca9b41e3235853428547d4431331f4e4726e88efd8aeec2cf1d29a01b2a4132ca9756c858c84ef7bbfb3b382a5f96b1b5666ba0d04b54ae1b643644feeb883c6d2cce846c7e5966f52e39821b4858e368185256bc9fa864a4b03bf69edfe671008487010343996a6172ab7452eb0fd0f7cd543b0ab90ffec8b3126702759192608a6cfde1b629a41805ef0324f59ff38197d2f062f3aca7a433debb979d3fc314d8870aa16b57cf0676b32b5842502cf7c85d76611a32feb0ada1f4bbdb8392c78865d00c9dae9dcd2840468b2a450059a18411982292ac907a5eeb7a2116b05cb0ac18c5cfac2b94f503b2e482dc3bb502fb4272260e2d6e56c6040f747efe7aa01b87c69784948d64edd178617e50d9383725c3c14b5ea01f7265e2e2c8c49bb4dac227ed2a13e3fe0402b511e5b0fd6e29283073f264179939f0dd0ae1fb0caa3c732b80e574fd29e4c0afb87902a959ef45a5bccde426698263a6414252595dfc42585cb484673515e0301b5669c1f5b2744a1808a26209463bd4a0f523f37c29dadc121e4c610f88d47df364332ef386a261da7ceed7e06371423b25a17ea97f3d181162edbdcc66524167f05d7f7eb802f56d64852e773e5ed39bff1b684e18f3763b076b8c51503890f2a535695921075032e87a02c6ca42d6b1784d8a3e11ad8373f3bf01dae7b6892874c757cd2ac5932e8578946032fe0215a4b0fc54b5bba54ee33038b9d26901771812088cc44c168103b69164dcdd3c112726259192846b07867ccb87a432f873c63b82b725071b5eaa1228c9e9652dd5a63eb8beab10f5b1f53d6ed52d89de3b7901fbf5077f992a0adbc17bf149a70ea4879c87e592293b46b02bf0724db3deea840938d62eef3dc696390688c114a83fa48188446fa7800e480560d1347fee5d654bd0f9265028fc8c4a8d3300f73ede70ef57b5f72b481479be1848f3808e50f3f68087c8cadf4660f1cb3326a23c1543e7f466b4fe4ef467667671b10567cf52d7c760ca904dc629eac28a3a4c8ce84e4a0e010696eeb5c1522e6413fabfca2634916ad2298c0146ece20e896a4cf6af137fd595bf8c40d9738c17cf05c85d41c6401930a895bdb7b1bf52327a4372be7274fb217916ed76b6ecd4e3e6acc9e1763de4a86663d09e428614aae7383fdef23e9e26cd22f05385e2546e5e4b57cb3149f46fda81e73c17017e297ddf96c6ec447402ab1e109bbe5f73fc4b88e11cb81c7a9f68f2267ad9417dc1d9be687d11268b91d939cceb2cc55266336ab17fd905664f90ee5057d437602035c721fbdab6ebc094384903ee4aa959ecd80b6525504d9420d8883f199f9c9b62bdba451219817634774ca2c284a1e29884cb5d8a237c8a680c8c6795ae7a9f10cb10281e68e54ed9892ecffd0788714ea12a5d2f546bb8fe3fe8a83a80b5a345c5a3ab6317820527f94750c94baa135ec458ab58c242a71b31a24eb13e5ab0ae2094d117204127cb8f8945bfb498d6a234b2c6344298fd3c72db72559158b1b6d963b248539ec0bf0bcbc3ed296239c1651335e70b33357a43e28c1bc54580e3c3f8a746c229c2c9a00b8ac574f52b6aef015d7eb8154b1daade382d3a8de8c4e8aa5d14224177122e80332d24a4c81f4bc382e10ff697a46a44d99b5b64360939ddbf2ca120c9b782fe030a24e54cc7335ef069e61b558b79e02f0891b72932d60dee2a171a08d1a2e45c1435c5a8ebf2121fea39265c0717e460d049e28c9aa992524c002242340d56fad69428afe3dfda5943bcb870225ea958600fddd3125f0faad281f81e0024169b53f6bfb955ab203fc14993cf274ea0a97afb5f4f7f6f5d4f5c7e8fd1dca09b81112d334625770e42a82c98a3e6bfea9624a14d740cf0797102b4c8800a94867b5211918fc54c3da4052049ba62d5fcfa484ca35e1723203073d4ecfc375e77a5eb42059e84f3b1235532888f83cb32c2102f8096e958c90b7495032fa349700ab65d1f6aa37701c5cb71a909bf9425f9a5c65d71b0ef82ac4c94dd42af1f7bac407ee4c98ee527838185e817dcb9485a6fa6faf5f1d60ff37998dda26ef6733b0129efee9ba0750067d3193ea38bf2168e437e7b0445fb6785ed3686196002273948e9ff380d806fc09f8047ae011a3d0a05b6019ce9617f28f2913de3956d5fb7f5823b463e9e6172323b38dcfaf7ba2816296adbba8fbca152b19ef5f9d354c24bc5a85a6813a371890619a224d65dfd849965d2a4056ba028644a021cd043502db2cb01876c1cdfd1873a110b2c51c03ec6470160cc390225f545e63252ad2393623646520593dcd54c0d4264430528e0052599e79a25d4b3a57f7c365992f7b55ac6cf65e94ff90d47caf8f6889db5ee643d466b6deef53f2db025151c9e11709cb55d847d762d1b38a573851ae2b799f72d99b9607724dfa74ec817b8324fd0da436c397758a27aa855304716dd524397d0047297e47118b86e371242a5200291b08f931b34d75587edee7b6c5589b1867e130eb11b1b5f9ed6b73691fd4a74c823a262dfc23d75087f65f1a9470409b742ddf52019617d19488de98a5c4e40e4e3a1b50f33a73f5eeb473e8e1c61c04deb7f1801e012ec1781ec2f475f49ca830956adfb2de0bed1d309a3ab1acdbbab0adf5baf5037390894dea3f9f115768da7ff461906f342e912c90843e8ddc64f9a560c06cc8a5cef53c96832bab865de6d88092f2b676d0f14979b586882b12a0837fbea286b507394ab28106340fc23ac4109dec96402954e708f64d015cc5af19cf334857e62a459e1e96a99aa3cff924efc56674fccc3fd7accbee5fd4ea7421b6b8f646b1824823131a9f9caffd39a97d4062828ee5cb20d042844310c4434664cbae92d9385f548d8277132ebc1d00d20c65b30e1bd4b47734a24d8ea2057298db0d65cb36153d7ccfd713b75e73f986097932426731a3bc89b24a8b1bcaff214e2f202e431f243cdab43a07eb69163ca3d8bfe77b583cb931034b456adabb7c48f21bf6875de86a250aa6bc6619c56b3887ce24dee72a5e4615174bd271fa1f8fa3f46d02f8e4479227712a48d16b3c9607345f1613f74bf8d68272c2d432bc554401755e36d354e5caa4de4baced335bee1e48523a2dd904d4327b69a00f8829379f741c3628d855c5c26880a7c9ac1625830cef88506dbf9f9ad696539740503e66868ad783326bdd4b00364639e160d2eb996af184d565c2f54bd767db5ef0b8ab229fea668f9eb816f1d016e5b4086ebc8e4617a49ed0a5eed57906394eef4657d47f78546f4f909187c2d09b6bd15ce89ef05c83f00bd4dd3e8743fecf1f04383809153bb9133c06db4d593fe43b143ffeb3d2941da839e7cfd8851ad7b929c2bda63d3807e6d40077b9fd914adce4a0e3537e7eb37287b32d20f4141f2f83cac54d3fe37a06f9b7d6601c79cdfe9f53d6dbd234b7f5a1f3f4dd50773acf7d4da674c195fab9b441db9fb99d8715c3481268dfb84128e0c5fde2bc51cf3cef82a0c45a95c72f848be81691ec7d028fe432acef4d4ea773ebf67c2553b83d787501da04c21b4222e9c4588e3ffbf572dfc7b178af2508fba62d32642a2468328058e55cd64106a6083da52cee1d56905d1f236c0ea1b040474b1391ea2ecc8d8f2fd813505e7e5a6d27b425f4c4cae0d5eeb073172a24bf10fa6e0b3fb3e19370bed5a4c4c3c75ff0cceb158795186cc52ca24b6c8dbe18687a043eef33bdb85dc8f1cc526b1e712da88e074a02dad9b871632200e8eb5477d851ff657ac6949cfd26fcc7737e739f1be159f81772a1ee4e86e749a72d772ebac49c1919362dbbb860ecdf5ffd57dc62f9e22cab3a26f197f60f4631c8f51168a717b6c243c637af2eefe56975b1cb4027587e9eca645e415c773e5fac0f05685e009b1f4fe88dcd8a5a7f846ff7484b2fef85e022f3cb8e630606e238d4947760f1e78cc9747d081144d0e9ec89f62843b1874ab6e8031f08f379d5b96db45373c0e920da382fdf06d1aee668336e17534104736584428b97532b16adfd63ecb34b2e8d55ba39a6438a0cf26a7e6f84f341b98dba88670ed1c1f8b1abc8b611150429c385300cdf6e5441c3684dc6697855aa1520a519cac596a198bb9b9229a3cbc5945c88f587f381b0ef93702e4d4c6421398ac655a703461527358f1714e2fff1410929683d89391bb12c664a310f20ac2d336935b5e9821f1a9c3d02a2b3dfed295207a78da4c7e4801806d2feefc2e468e58615c6accc039bf199f5bddafb48f36d85a1f191911681a67e935267dde6b440c431c15568aad2e42a2fe44ca1acbb3c39618e286824596ae1f48c99471472663df7b3ed4e2376adb46a510f1b134090d05b9c4bec0f9a2f2cfd0b75a8c014d1ccdc30970a03b0290a3527ca6e682df96c5c194dcc8a40024858ec67389be72fa58128d413493cf9823c18f8b6b943579da2dc30e0c82ba5ad830403a05720ca98afc9718caa0d737052af561488a85ac590f88c5890d15de7daa45f88b744ba4ccb540cd699c799ff3f7d18cc625bc699d76600d3cc1f69f73e6f7624434ef07246c42d6e93367f60fd0c87acc0fb62020ed31fab165854eb1df1261a6a91b9f68f4b358417401d390a0d4ca4e147427ad9d49f4d2486256ba45bb2ea9d2999951096c425202a49c64ad6c6aa5d3f0a5d1d3404ae942d8892bdb3628d56385fcbcb18e457d94ffafd26cfb0f3161a0341a46398d5e77e06d5acd30a44c74a431f822cf304cf2f9e2e51ce6b38292fa96fc82abfd223779772d9d9d13d3ccd7a883342d038fe3fcc7326d67894143b9a06d0760e9ede01eae9afa71a863b742229a01750cdb602108775009a0d29e31af6e337b7e06b983fec99caf0ef258e5246695c4a2acc98f0cea2cc4c9b6a701dbad47075cd8672d98081edb24be31123edf4b5ab40b9814c2351aef153bb49b742e7a764cc0235c545a1e0e40477bad985aee064e10a5b60a8c02c64972df61a1343826e4034ae24e810a8a944c6941fc5f98ca2b819c191aacc13dfecb8ebe3e9f096972191d3ce4f5acb422386e7839fbef79ad23642be4eb28dd15754171391d83e3c2ff15247de8418b17c910bedd399c5c0adf99261385d78818ac721ced57543791fcd466b2b99443d84f76cdbd8bcfc45ec1f82440aa4739eacd847a4f8faf4e3eed530dc1d86797fd31acc0eff874b76d5ac2aea0ce51b06c021881e36a9ac388dd76ff7132976fba26e57044817a2b42a0f917e5398dc0fb1c695ed729cd2b4b476401c83b2bf0b3feb774a01928cf74339f7c9ae65c08bfb679978b4f9b9c0be5d734c765f16992ebb2bcdae6fbae501c83a201e083d6fcd6400ffa180041fa216a6b34b7ac6e48fd93d77848caa88217e14d93bccbf0d736f7223c69927319fedae65f84276d722e845fdbdc8be1a749dee5f06b9b7b21fcb616855e323b4829c4f900af399e0c26a4ecddf14c7bb8150f49fcb6bfd7a91e8f3d51406e6e250e2834e5760b6267fb7d5175e988bedee3833c1a2083271337a1dd263b403aace7f2705b0b583ec00959c5b5e9b30170c7e64de8d3c01b5017fbd83e0cc61ca2e18687dbc96219d2fe3f451ca290f6631d7438caa5b407c244a256e0592173d99e840877218bb1b7534904b041df26e7a9095b970cf5b5380998c451eba1da8dcedd4f63f24e0fedd884a5357351009789200cdb52132b1118419424d8a4aa1657ac8b18b4650af6907fa6084ca92ddfe7e15a0074dc9d5d5b3272c14b8f42748c7704cd07fbc142438aac554c311764f1e4bce270892e31a9206a60318c358d2d28b800ad1418b8f9835df8a2e6cb181568e5e2227c08e42221b5f0da11cd771a47a79bf1e3fa0af163a2541f73cf1dc42a2d69db33b2657f37c0abfa5deed7c3339ea2aa6478a41340aa839c668ec0ff9385a33e97705b077dd847a4c681175531433ad6d2a8ce2d210514bb31e2fa510098611c2a25a733d2222a388833d8179ca81cadaf03958918c36471f7c9ab51de33c7fa9f89bac4deb64c0b5aa261b8623d5c9296fe1b517466aef4b8b600ea0d5df1b7d0648b89aeceeaedf015b679b0543d20288f794261d48c4801b7d2aef6ca49e654d46d65020205544e193b82d401c52fd4d74e974ba51aca57c6bee1d634a4f6f98971f55d39a2f147a3a1ae982aa931316ab40793f7f06fa49466738fff0ead92764fe9af5cb0c7df0a058a760a4fa364da08afd09326c31bb66f1a647fc497284eb5f9635e5fa1ecb3162e1f5d938623baffa77d709200204b2d1f09ab92a229324287cf541cfc7629989df02879574c002e6448caae00716803a765d564c4489c8968093962087bbce5d2effbcdb46ca81c0b29dab2e149dbb9b2aae4526bb0d8d08015ec85a70df005f88e6dfac1718190b2a7982649f4d290f1fe6e3f24aa1f982991499a61372538c62b354afa181e2401c3309ee4c74a7418b06a0f9cab433af2d78585b2d77a670c1359b83959de82c054ab8b7bcda019a49788667256b24ebe139b5031b3181ad996b4175b9ba9b173654025a117ebbfa10dae93bbef49b7678492c7307237c644f97638c3fb2c7cce41c5f11cc806c1bdfe033431226a2b02ec0f014aaccc2658808c65753ee887794ca694e8423f9cfbd4c4ece32e98109d849767c208f57f7a20b2a36a27aaabb7ddde7efbbf5bca2de516bbdd8cb2a6522314aaa3e295ceb100fca62b420ec5ff127c3b8a0c0f72a1bff79649eeedbf0351025b025a026f6268e5ffff9fd781e8ca396eadfb7bef4d14aab6945834be0622f2df6ddbb6d53d6d5176461884a907199617f6c3fcf803dfe083fb8f6fae32e7d9ecb4a21f56a8a6011b36ae54a4483ae3134edc6afec0b6b38b4ec20b50cb55d4193c61e2b922808cb297cbc11471385c3085294995584498120cd4562b51d4c4e25eebb4de75705d01c3fb69e50e442f0cb9df9e4935d132a6c90e273e58453eba7afae8db4b18c41d9f7119e7575ac877a9b5843becca06eb040703882bd1f31423a2c4b4b35fffff7fcb8e6a4b838e1a5a8edcff7f991412e66a4bdbb6d73aad772dc76ef1ff0753e27153c4d6f0fa8f10aeb6746f99cfb88cf393deae4247d5961e09317121a759e7320fa2a044386760a1e8888478bb98ff7f1bdc6a4bdb9b931b971658064b0f04efb34940c3071c9878c2460a1fc6148814b034a958b105335d7591e05992a8c0841cd630ab08a786cb9009e0566dfdc1546d6993eae99afc80baee2fa938731c5e103c59d213970719e1cbd26b9dd6fb8ff6bb6aa1a2d4b259fa709e67ee30b29e999e9b9e1d18b11753b688ae73907716bee530eabd68cac06112eab96e07284a515e721017940e5a62e318600070062526af99dbafffffffffffdfa486e7ba2f67e011cdf5b48551cfbf9deb3e957be1e7466ff8d9e19dd66b9dd63b8d98dca6bdd6697defd86b55fede9459ccb5700103059100ca6151435bc128bc69adb5a681546da992d9a432a1f1dc3709801cd11419a97cc410ab8eedb2ea88f7beadcc8a9b48acd73aadf79d372722fc8f5ba068b760e432cd675cc679ac87ab7c03a087d7691fb772fa729c0601084b52e59197306e83395a6bfd83516da99058346af821f78dcb6262219625bb45e1d034d3b0936a4b9d26b0d58ccbe27516ee0d423899558e730acc8ce45c9725967363bb5eebb4de87acebea1c52d5b92131df2c0c8b43e3103954b63a5e78bbbdb78f02e514d15496964d09adb474a4d911b31122c0a30a6aa5a39903e5548a18c6d81c60d4c2c0f3feff350002755d9479ff60e8a68eddbd2c807205a18e63f31cb45980e38172ea80e2702369dc61f0b0fcea529ac12569f5b071956630fda40618316505e3d4a1e10cf18bc90de335286629bf303969a4a59fa0560dbb65fcb5b296f78efb4d8750913ab12179681e9ad18dd4ec5e0f16f8ff1f958472b4f1f5933ad2cd2870486184ce0d0f0b1c9d19379528ecb48fbb5419c8ca393ee332cef76e010d76307dad7327d422de17e587cc2302dffc684664176ed148cc69bf7e4db5dad236e40554c71607282b142b4d2f58f2c27b5261c0e0bcaf91e40e93cb663ee332cef70ec26b715789dcf052b644dc2aa3e8fd7befbd37ce8ab473dd991e0be2098311f2977967595ee54baed73aadf7949c0d01cfff9f6abcb1501c0e8703538d25e9d208d869f3abd26b9dd67b8d950dd58a0e6937e4a255fc18418a6ddc5c2fa4a6f96b041a4b44950b6417120a9ed110d251cb4bef3d01a843f3c73414b6a4581a71926355b2c1a56778efbd7f38af0cc115756f7c7cc6659cb32c8ca4faff0f3210343397e0e2645e35873a2d645614574b4e6f5f8ffce81ffda37ffa6e2375f95c7867657a6a7213e5b2650e2e24e6332ee31cba6514b5d73e2999709284fce1a69a343ddb17215250848f19a2108589625e3e4098402c7e9a39421f36da6e59cb1f37bdba2097693ee3329ef2bdf78e4ff413ae092b2149e3622328086a14032a0bb04107af8210b64a00b942c842404f3d27c3744974a4aae1332ee39c050099f8847f280fe7f602219aa4891d3d3b4b1a06f149b224aea0f27efcbe5daafcbeac1c350231874ffc349491733a20083cec114154bd40f142e72bc7c615aeb153ec8cad621c5cec6d356a715f9594a815e2ed9ea61b904c71c3df1cacc94874478eb66e86b8c4f65cb709a861565bdaca328b02de7befdf7efdffff41764afe4150c10bc22b925163a85de8707aa94ba9898924415560ea9184d4cce05b0c875a846c5286e804d525732f452715882a96154bf9cc011085322fcb12ec9764787c3a179cbc9e1636408bffffbfff7f15e06a4b5b20b90f5690a0534f9ca593098720ff6339834df3d9beae0865772a4f5165ffff9137aa2ddd713520835cf7b142923940dc0631a3d39ff9c9be8c2b452a1c0ee782a158922a9dcca20757a78bc57bd6f33beb60aceac6c0d691d6608b897b50e00b8785881d2eae5e340b2517c5850dcb6a82a30964249dc155e07569467eccb573f658128452cf6a524ee96321b7c205ab434ce67d6560ad55d47a11d3e22135215844763ed72d89a67084b5e3464a57d30fc0fa1076a9b2ccfecbeb9b4bbf5e8c50d95281830905cf75776b34b9f5de7bc76ef1ff3f7e934a45aa2d35c4a1ff0627ba65e11b002cc41694f725f1efcbee6eba75f71a43a8da5262d1883489a1b48a12b66ddbb6ad08461c1bad1db20f9d5ef25d585ae510beebb3867059c307d62aecd7ffffff52b26a4be77686dfcc4ca4767a6d1606f386aeb6b4dda95573d54cd54dd54e55d0ff3fbc329766184c4275cb90f47c42b920953f3d29563415bc8135edabbbfe5a3511d52770fa044f9f00ea1330b51d9f7119e7efd3d97394c9c2a9c9332bd60bb1da5d500699d1bbbdf70e2a1015ea20236222a088242cbf9a101b24fde606613578b158a761474c9ac731b9d5f10a6cacf9ff1f6cb53ef28ec023cc5178247e4d456baddf57abb429ca8e47012f214a2947ebcb35f331fbfbf5a74e3a27d9fd7fde6e65f9e5782bfd786b0b6dfeffd61c7c8b423752d4474f0652d44d4a4b8a8ace1488109f184827514957caa99c9e3143078debea5cfe432f40b964ea581c5469c034531c5451f6878aef30c378ab2d6dd3a76156530b0e0b292e2d234b242ac34e589816942c337c24391706d86b9dd6bbafcf3a0c9ff83d3d071f789c163a58125cbc9073c1a66749509cfe0dffff8338555b6a8583cb2488976ad512198990444a2226519376d4d2b66ddbb63e239296e6d76f5ab8795c3c2f58a759f62be8ebf875f4c5f4e5844107d8371597c532ab8c225234c3d46e12e7c41c617657f7be28ef7efb6de3d016582006385da240275891a59c7064ac8e1f9c3c3e3271972ab3f2fbee1db33a56703a51e6d5512ac913fec7b7904ecbed7aa8306d8a52b5a5cc26150729cfdaabac41d6e8babaa7e26b6097ee16d78db7036956cfcb0a072e65b127cac87523dda004f2ff7f8524d76fba86e3ec5c77fb1eb8f7de39af92bd5b3dcf3f075fbc0ac0f4ff1f9e2919455f7aadd33abca2b957a8ae070b9bda990a9a3a4e1d4d314d3941591d459458f88ccb388759c050d0e9028cf2a8640d1fc7840018131a380411c37024ce03c59d00140005096c7c8468880c1d30201285432231200c120980a0301800048202819010000a8d87624a567700de405ed00989eb67c6d2ea2842ab21b96e279de6e208fbd681e1491b1283f0a0e78ab5d7a4c142d37e4db17b50a9c8cd5d317fe94d8173835d8cac71ebd41b70e04658a392565e7a102cc4446ea152db9990e95825fe96b29a6ad34bde4e88d8fa6d943759375627ab07da67dbf585ce37a1d7edb396aef40a9d2090df600f722dbd2b9d3c6106d3bd020956a7469e2284d7994a5e6f7754e97c825405a236fa176542470057311b4554a3c8bb54b502eaa7ec14e64fa651302abfa8d5f9c9806252e6bd7034ed440b78c6fa816ea728c64c6858c95b266973402da9790df6960a440a1267d30e0f0d69f3cb0eda3832ec8129586818e6fe9dbafb1028382f46b37867ad8439e1fc911f546fa111ad4ab2be679c2426bcf77ff43f2fd0ac0242659361b53584f84720796d46b3e78ad8391fca101eec8823f983651ec9cd39c3b5b046b31e1a53afe985ad46646521545f49af9e196a65bc02007b0eadf8942b6107e5184d64efee89f3316a3505d7c7a679bdc0ec180d9d5a239aa9feaa5c2c946c5f4095d797cef48d412942655cbc2fc0228c4e3e35ae699875e37dee2fb9149dc007c2eea6db15e2603f5de371622ab9c86a1dc24f4879f09e3da16eed8c73aea34d7e6e23e672d7ed34cd1b8d493412a9a2f5e35d8891372c8ef3c14bf81a19513daaf3b73e18af59268c9da82bdf4e57894c28805947ceb54bccc61ad638e1a51b1898db1886e603d95b9061e2fce17050dd53ad6b07d482e3f06f487ee343c3ce2792ade3f5420cf72e5e32c2812aaec9fad357021667fc2ba3f19abcff02b52dc6eff12a83594e9b225b42796f0d644c8c6164953b5bee5e68c6fdd635cb5ff862f088729455d66410db812eaf0c994a5d6e999369835e57570c849c291179b9169c1a011830e0a45e5bf4664ba8524706097ad018633550bb77c030f3f17db693af4ea69af7d2831c90b9fc3c10188f183f7e53eea659d84d2bd2583bca602d5c8a5e43605f4014ec0934bacaa3746746fe38ac3ea214719d123f5f01e73a1d95780a1405409fbca8fc57b7adb082f0e4cd89d0c165e2d2df49b8f1586a79a23ca051695fc4db68b4746aaaacbdc0d94aabcf512d2e677b552583290e05c0c31cfde3a0506164ba69e70da224966d66892a5aac313bbdd880c46773dbbf128a88d8d69cea105ec38ee965779d16cd0f14fcf6ce0a3e38d4f2934a95e86bb04b874a510cf4bd43ee227f1c4f42b17d2312ee0d15369c4f1ba9852ca6e1b2e1b77e39c0d70dce3d78daddd218d0217c302dfc7da58b159464dddc9065519dfcf15530205202b649201dc270d7119189c3f84dfe6199b8fea0b92b480887dbcd063f90a71ec460f84e173cc83f78283ba7c1a073ac7528f1363e822a2d508c07ca7be4971be715acc5517aa3408c72e3c8e8e64afe242537ac53a00edb96672e70c43a92321504557c2f1900bc3d8faad334b5c3611c2d473f0301b6910b95c1046f9444e02d02f4346ccfa8e480a5c5779c88d016696649f2ec4b059b8aa954b550208ead3381cedf55d7ddfb7dad484ab59885039df3dc19a9107f96f8a668fbcda7d5c15d8355462df6e8f49a3ecf45c5bec972e8d22864269fd82b2e8dea1a90c4c147c89f3452169ff150f43d2eca540bc19c3251266ce9ec86ed488cf6b072d52a4d84b576df849abf702476c373ac30bb0d5070677f76a410836ea9ee5586eedb817f4d3682909571163027fdeadff328fa0f760696841e2d3c84c01d84c2e45da7b341f4fa8f4505134b56355f93543535b48075310f07517854327058d7cd2a330670aeb0abeb9075ebb8c6df4043175ef473f25e6de0e17a2165d68694a950f37482b4bfe1d9f579dae009548e1e743e2a42ab96c790a8e5a01731c5a36bbc1a0f667639d90e724e0d08eab5d4dd1fc8c904295f49ebafc4a2d61471e7304166498bb072bad3d098e0f67cad1d0a11a8b465f7d89d4a86d9682214ea24c9d65cb6cf07b1d07a8a76e50adc6267099f7a99a82b25971f580c0f8d90fe6551b36dcc12b2f57b87586e6603dc2444e2ed99073de25df5683db10ac4cda2d04aa6a6fe91248df88e39a2208a6fa4ceac4c6243ea9fbfd004256a163b7d026d31d52846ae7a2e60a0a813bb214e909b3b6ce75279a6827f63e2830f64e92bf0d9663f947938058984dab5968baec7e58e0c2e724590892c92073aaf3eb135b2670e9aed3225da1847118957075f019587a5daa7eb40db8f09abd790c7e6f4aba1566aa97b167c4794232d4603bc0087a284a939adca2ebd56fb6fc0742d64950402b6907f031170ecfe8b4b086e4e5a65e17fe9a084dd29a809f247f654efba224772f4cd3f40efc0f2fd53ef2157189ae46d9b146168972e82218a5a373fc5e353c6102792ab690c597478b338a6da6c5a3142aba27304a8eee7a88fa327289596ff4bba9c2fd6dee19e6206880701e526ebc988b470daec9070907a1b59ac7d41831a82378cd3f120e339ac9e03c1819e46379f9158ef2cde50b9ed414ccae55ea11f1c5fd3950fd4fefd359c3f20013610d407e8974ec7d354d40cc446c28be25b7d7d63e380aec27014379316d6919869457fa88c5c21102d5939e9b02aa1c5d9aa07d61135d8184179e954b83b08121d23341e06202a78ec7e07528bafe260660a130f5f14d1cbf948865c91fc80b228ebc9a8899146dcd28efa643a2a19400707307f048a579158978d167a5b60490c29c96acbcd0e9393f6c82bc9a47ab906d7687836ec1a93c8bc89c03ad453bd7250fa1bc6428425286318a71468458e67302e7cadad0d6e75768f96d4653af59a5d685d65a28fa9f3ab7bed20786b1561527193d640f9026ed086525c480fa0d2948ea25250dd9963634df8a58a30d02de3284da6ecaf42c41fa29da42a3f9ff74430c10e5a5fd2d6543f17a6dc9cfa37f59769b6305c0d3e80a104796a57b44e30088da86bba2328cd44346d96aad6f5fb5f54f00240858cc354da859c5c60505c1baf465111b210db46f8160919d4729f1320bd4abb99a6166f02348fbc2765e9c7e5063c24d5ba0fa9b88e14a6610160ac5fd80031abf52f7d9dd2d050814d203be5dd22704b0c979610790518c95e2ff2e938d60f2dc24b9c007e8b61c150d24305735a5119ca8835540ca7b0b81d072aa9fa87a3e8e86232148c6d351e12874d5297d4aca2b86fc5e1622381c99d8d7c17b3269430f89137356dfa78dc4edf7e95bab567feca12b7c21818bb922dfa954e45e3351908b7267e28a176076666eacdb4111fff32b4b75bc39f8cc8f844175e2601b27840edde16d95c129a577af48bcbc5bbed7aba8813f49375e04329438a494d177d906e88c51fdec94bd1b411c53c75e68eec171f4c5dba501f7adb7e0d111ae7ca3da1309162cf3c8915a80050f889b6522035aa0d1faed71ca81bffad9d6509423520b49e7afc1851e9eba3e981f0c167f9f7465ec56fafe2c25bd985a8e033eaad744527f4598ad10a8362689ba2f385ac4d9e88057f5d3d75bfc69a39ef828415b8f1e835f66365da1d8fa64c9c6df9f5fa5ad8be17578315a4d45b7120d1550c9e62ab3f894e8e50640f07b526467042bf278707bdf39de444ab42934e81eb857edd12fc3b8868c9ef17a807992754909607a55718f9c0fcf793c9de6bb83cf905fa08af2004cdbced7e22f3296b17b397e75871feccea1b87d5095e3171f4b1f44fb568e285449cb3fbacb8b64b1699fd9534a6e9c0820083003c104fdd2c2d0022f49dc05a9a2f7ac447aca443265a9fd3f5559a5334e7d7b5d5eab4c2aaa3de249d57c281f5d9a3a5afaf24946e29571a648851ab34eca33ea4ccf49a790fa2ae7bcf9f88c2e1c674d8a9323541e9e68ed664c8fec4bcc673e85b52ddfb2df1d52eee651098bcab94a20c163a99ec71f67aae087503703f9c81ac857b353945dac4d1fa4f63d9a2450b939df0bfacb130941dad04ad328ebc68dd60afbb6ea85e125b1b761ceb4842891c0bfbf611bd5639709035e7c9565f671c45126cf36f74503d1033373dd70065c3cdc1c542c8d47f750fefa195dd0c471206224787518af8a2bcee6e7015b9b766cae3918627d1b40b040ca33fc360c08b3eb13b630f8d5a21501c1f04f437c43e6de73b7ac6d2044ffb94a2548a447dfe5fa96242bd1860f587b1c6dc02777c1c0885aff8851517fd8add58031c6b118d09f727f1538d7439988fa326854f18ad1b9a0411366c929d00ac22db05230b2d5baf3d7a3887ddad0746a500411889e8269255170915d84c6a8fa60314a038d36bcee7e20bb5e75554943b1b44588143cfeadea2a7dbb775284d28337bf2c0a02c1b2c863f4152eb405d308fe5d6bee1633379ac593bba0696b4e7c2e9a23cdf9caea5a5035d6d0192520ca0be81bcf8e4797b7e68bc78579419010838c79f83160eed060f5c38813c42f03f67df79ed1a3605db3431ddf50149fbbb808bb068f03b6d779f2aba9893d644b5dc1c1fd986a55c7387bdcb779d770742daf41a1083bbce9f93d6f2c13366b6997b16579f995dcdbe0cd7ecc5e90a7696bf1a163d237aafb239d7cab188b554ecd043ef7a3c1644fc5a384a85b620943430f3545b6c383dc35d836bf65b03c5fc1608aea4341be432ae44753c3dbc13c26ff2cfb434332477329fac79c74ccd6ec43f94a74fa76b2ec068728ecf80c2e856aad44397402289cf55fed0108c1bf2d41e574d9e762e2c681a409ffa38edb4bec7d4944463468b7aea323979953419e862791762cd89550b69b437fe55a4496708a56ea8abeb532dea2d7a53ef642f05b1ea2f05c879da9a36c64c100cf1103b3abba288c9cdb5fd30617c24775665980df9212312044f4002ebbb534ecdf2aaffb83ab2d054a2fa378f951702247a9b8e3fb177dcebd0f505a4556efe08e347ca64ac818fc802ffada1a416caf2b5954690a93069c75c67b1831d61589acbba8b61f445a3ac4490b683450508a14f1390ef7512d45d12415df945f54d75790add3e5166776281487447b4f8789e90744009e04e0dd983eb9bac1f32a0dfced3f31401765babe40b54c5fac0489f4167a99534d76034a32946c99f5c00372a5828c790ebe928003e866de2e6d15b2db6873f08d2bb32d2d2e33e88a52c2c8c304d7b2110a4647d711e66202a573242942f4e2eb741f9f5490f8b54c7b7a14a8b0ed57b4e8fa0c65b5f5b3c883df1caae254729cf72d27a0eb865750c8386a5a06569088d2343445b37f112e0b25cb7e0424282faedaa3240c9dca238fab23de9835879ceea31c208e967f4a37f301a78ef5a10ccb86d4288971d2fd39b7a6e5f14139a6817d327871955edc1156501b725ebb42a0f6d5f4644fa77335254c7408dffe03ab0bf7fb4e04518c04b626c112ff0cf0674b52892781ac9d8f827cb912bed12ce0d52c330f60f40cef7ac170b6c4f5a52e447c3a74662b05fc89d8e2f54f7e981d6abe54370ca33352a6118047200966b6864b45ed559e2bd720e9cbfb4a44eedd1e02540ef99d7d495f1ef46e66ef40a3b79c6a2ee433eb3aeb74463ab1c336806a2a2a497ee348417f83bc22d33b22e6b97978daae38d50e8c0fd65a0c35df22a58e60541d2444669f59ae7d9dcd2cb17c5e3bab78d68a8848ac1e462ab02697125687db058f756b64c54e9dee53feb45f8d0d27d09e5cb34de81c83f4b3477dc7bb8d2e05d1fab5ac7e12f917acd7abbc46465742a14c128a89295db240f335b4b5039bd28e9644ecbc58e848c310f84cd51bf98a1945b73e8f2d2b2b78b5e791886aeb968bd238bad4422f87c7e6ccdbf58ccaf715e134325c6791165d56b1b0e1323fa38438a44ed4274c4c783a2f844750ee81e88484e7e590f23c9c43824a390919d765ce929488d10692f1c98d88c88d088967f6c499d2947934f20bdb2316158054213949a07c1f1ff10b698193ec488f1e98312ff00ced33bbaba8c25c01d9574e03d94b4e04fa5b4f9ee67cba7abc0e484acc87422846ec0f2ed25acc0bf6f9157d874ce6e0039758bae889a6b8126eb0222eedffb2ac1c44d6815ce313ffe5c1b7df752927bebf167547e88fbbacc0b1de8dd7a38364e334a88285674f032ac23b9a1e1d518d8a234f50688d97fa4ed31856bcf0834c04f375103a0da95b00e607555a93b43561b4c98988c6adb5bff4ae8bf9e11862ee3705378afd36ae39817ac16e215ffd4d23d4af8f65e053d30abf6db3f55cb36c70364a3b1ee89a679fd9bd83bcaee02b256fcb0296f67f325d1127f104ff1756f45720a8fd3ce982961721503ce8cfa6c3cec9614d5ad1eea3fc0248e3ed972cf46786a2ba31cb12f4cc0c4c03d121b56c4ccd3480628093de0c251903331d7a2a51e4a37eb025a28e75a877aca661604a9ddf4daf63880938d56e40e1718ba216e1e509dd36255fd663081541d303ae64bb8af5b3fa55305fb6f82ae3f282b7b255db14fd4caffb2c6f8a73c368d9d8aa7de6f115abe4a72b4ec0641e0cc91cd22a5fc78556502bf34218e64c3658ca7041a2bebdc3d5de810d10d510f9d5b1214931668b05946098c63e8625b93683dc116a6131f2b8053792b565390db09c7dc4519402ea9ebc139c24205276d547e1982eee1a68a3718e20816c97025046500c2d373f68f2c4e40f8ee73f60cb6e995067f3611f436544e379e766b41ae90b283d1d182c8cb4bcede5d0f3005b6deea57fd58ba99d39e91b58ac83a1385a2877ff4498f1e7a66cd2dc753569c39d4e3adf4832efbb682bb52101a91787a2ad043b8f4d48412fabf75dc01908e892356f059dd887cd0c74d871958d69fb08730afb4f5742ea9eba479bee060a35ec23d1d329fcb50f220eb081d356700a83fd43a4e9a5098ebb7d931b77e27086cb5ef340a4030eacb9ca5b2cc82dc1a8fcf926c76cfe12937f4ee6561381499bf3e8cd9d82635bc80990975c027ab36a4934b76a31ea6f5bcb7c353aaa16f926722bc84508747718fc13be86ac70f08d8978d78d7bb5662e4815768fab6252b58f49333a28491d79caf2ba06c61b0648be6dfa8125cad15312b07cfcdc6119f55e86305024c4f402abf3a43202baef2442c947eda790638f7c384b4283ed70ec2d6849c71a57b9c25918b92d0b48770a3fb0a73fa4e8cc49620452010ca25ff21a29a09af4ad2b9c7cb1f9ccf40f12354d6d448714a304b0c4b09c5e4fe68a06d58d7d393fae229fb3226481922b4da99c065579711a844b948dcb160d002bf46dae8cdfa7d151916077f15878976dee762bc0638593b1dfc5644762e94fbb19a3ea240db4e94683e020b92591e8c3c09fbd9a253ac2823f539d98a342b43f184ea54896093693f326649d6cf48c07242186b16c27037f2df293f10304d0fcd626b726b8014485af3963df57f835ffa67c6e18d32412502cafb9dd55adc1e51807b349cd9bee8506dea226f43aeae6082241283478e47de6711080e640c6f217cf2dc7a1f96c9551c5e36bfd22da871a6d14dd3f0593b0b62ef40507f51b3791b193460eb2bf64bec73074f63c2dc1cbc37addf8394841e423fb8667cf9447b3638d1d41dba9483808249a398ee10c88a9461289c915c2846db8e6210d684ddb50509910a176e8e147687246cdaf0a53182c5a8094533b20a5abf0d5c62034ba84190b15a01f90c463258ee7870882776e3de26394ee7814ef3560668bca09063cfbfb7a2d57dd408a7395f084b0ab744ed4c9158edb31148839895f0a331b67d855c5bfe55ce27067c3fb1b3865764063faa2707b8e59fa5b26647ce9cc7674912218ed076541178e9296b2c5bc56b0e6b8ba41176d13de9b1e7718428e9819dc18a510c89346407615f7e0ec00b6430dda91decea95af344217229c123976b51f018bc5ae032f6f30fe0560167f4df234504880f834b6ec90712363b4496c0024b3ef66787f5883e9e84d89e70ffae75b72fc204dd6426e0d796b91ac5051e6bc6587c96fe88c3e342ab3c5d1ee0620cc3cd403b9eb5ccafe8e6829160565fd8bcc5f38c21a4c9df3bcd5786576332f6dca7250a428f61f7be908c270ed347dcc21f78769535c7acb8698c411eab7325d41046be9e3568601d2fb19ec6a0c4e120c4d4c0681b86e403d0cd8fc125a834c70bbe93b82a111dff334abe3803fe894108d82dfb96dab6992315dfb8327b8255af3c0234e0d0d8b52db062c9e1c588c8aacb4bf6d432bf07abda2f503b0174c82a7761b4c92694b2e52bb072193845a491152eee9ceced0c0970e097bd61e4c6e7a5b3c4dedce93950f5214b97aa471c9fc9c3f0b0f455aa2a35d033aa90503b2921c09358f21821a42edf7ac6909c7403c94a77c0c6d68fc2e168e4301e265ab1efdd1117c92b5f847645d7c5c5307ba178024140273e9a52cdd35cd4618693324775665cea6fc6023401213d484c409a2dc1d30044ccf34e5a98e5feac85c3b3471e33ea4f28830bdb5d358fabaca478d4163b13d40fe8933b8ca62b5cdfe6000e2bcb22d6df44151ad2c78e6523d7a45426cf5df0780649b5f1d669f4a5df830876d604d042b9b1707eb5904ac47045e82cbc27b2a18ed2554461f779df813e5010f616bee010b0db2f31f224ddc8fc0f14c8c0a015f6dd007a11a79be93ea5129da8910ac624451ad5875cf912d41c2ecd5d71e80c4f1f8174c4f01ead1d02e57608eb2eaca40188c6674dde8c189c9b5f649d9a064266acee0de5cc835f6fda7e3f10a733d70060b8f77e049e4e26f42330f5f729334b8cd992ac929d8285ad38ea68612c71794281feed3cdde22bbf79652cabde59601eb02e402ca022ac8f8629f404f0d878f263bbf2d67a0dcb62021757006f951bc01f5428f212c5944944fa6b23d93b7dbed289b4a17a3c084fc99daf3b49ffd0be9d29dd80f3ab4b564527140fc420fe79cf756adb53693946b7889a9e929859929de3aed1ea42d95854907f1a48a45d9cbeab4ad41b877ef03547279c44053909414a4765a882dfc8e5e45b6b8f78e43d1af77e2185a01d5a31e36c6c2589602e04e1530484dc21cbd5c6b71393f32ccd98c1176fe02d2a0cb525e7565a0b213765c87ea41fee01d1d6b5191325604ba513304a87b3beab813a43585ba1bfd3ced67ff1be81c825bee0c85b931c28f4f0f2f3a0b0b595e2c8039e25dd738099d864e44a7a293b10b69adb5d66580700e6827f9104e4319750fd75aeb1f64ae61ab649652c5cf92b71a059abe0c4540a3e69b73cef98e5c9aa23b44bed683132c0fd21e013dcc44946b3878824918db4ba200bb98bead15be2e5cccb7130609c491e1c713724b91d2d1ebd9495d3f703f783f80db4b968f5e772c8e47fe6cef04e5e8bc309b97adbce69b73ce399732a1c9e5fc07092ec7bf73540a894fce6cc242d1a45505b6c37bdacffe4f9e094f280a4e92452a589d2a4cf1d97befadcb35ec230aa6127409d3b4584375c3b76a34ca968a285d381ed0488594a48db37791910d4c7cbfdd0a3dca37e5d3e311a1dbe1eb80809b15949e959298ab28ac63084894984b1297259673ce77fc542e487e45e773ceb9ee2ad73056d76251e8b6628fc4777e80ec9fa51d22ba4632d7709672458de50a1bb7bdf7de3d810593ac326cdd7c7a1d1c20d55f678cce24b1bcfe84c7f3a911b2b0cdc65818cb9e3c25600ab574a581c270cdeb913373c45c3167cc217356b92492d7aef7dd7906e8e5731413a276a105dc538e2b30424e5882d8180b63d95e4e039f90004439496a1e4541f5f7b49fbdda0313c202ad1dd7121f19e2912b4cc82fab4c07427078e4a5e9042b41be08318d7eb2f41dc4be61ca6a0710ff847befcd4bae9d03550d7cdacffe81df6e23e6b27ce9deadc68c4292d4033ba18e6d3bdf5c9b4170b98679fa4410604c29f7b49ffd033ded670fd4818531543aac9c80a4844148969016940b71b81af9f494682cc8883133258b0b45a6313ba11aa92a9efea9563dbef5de7bef2bc35cc3c4a23155710599a63584b670a530c6084f8a182c530060a9b274fa20da3bc773bb6f3917a2bddb7bef0ddc38a8ce2b2182bcdd4ee619f210798a3cc65c0124088daf0d3e3698cb500814141c54ca00d9128188170f506694592186449cd350c1a2f2d05918cb64888db130963d795a6bfd03e61a36fa25b1bfa5d88fe97f4db4df538bb3dbec46815768191f52153488986bb868445aad084aa629be28d110807a0793a07941bc1b1336a6388db0b542074fc21c09614b46fe7828af434fd74de4de7b6fe130d730b168445a7114c224e729093aa8f7de7be73ded67df81661ed55a6b9e30d7f090476479c5d867c98caf953dca47563ffa50fed8180b63d9b507f532d4f0b49ffd7f617b9c73ee33409201037890c9e5b0611caad22f1c4b90d23a75c1de854ffbd97fe769ded37ef6efc339e73d2e245eb113ee1f06c426bb2d2a2aab0fc01051e2a1416908c55893ecb51ba0889a06a74f18ea5ec38e73ce777cebbdf7de7befbdf77188e8ee9d54820943316cd9c1f36ea5bb5122a12b2b9aa7a7a727fd6c8c85b12c50d14e4e25ab925749aca456720b7b1972e4c92a2325a58c0b3f001c1df5a23037dd7fd68397badecf765c1a47526badc72c730ddf743ea214300491543502aee2728985e848085f7049296e88d02eb3302e1bf9274d67f0b8c59023c9d0132c5e92f4a81ffb6715360e312101811c0e483213a5868f1a545c5a42920431953e1b8c670d779e8df34d32bd14c7c65818cb5ae5c8d9014468d74b724276391661ead2f7872646e30249567e600509ea7222c245ca0827d2521207a6a2820a6f8bd8180b63591db9e906640295e6f178ac085dadeefb95a4986bd888b43a9124b9693f7d07e4d4f9e69c735ea42ad7f015963e5144eb7f5415887d94c7efbd37d732d7f0adebd828cdefefab4ce9a5511c54d2fdfb7afd4275d7a9aca319f3ae15cf7edbe8e02a4570b75787c690fcfbcff588c5341364187664b9bdee676092c81c5cbc24a8e5ead37c01b48e9147e0e3328f505fc11979043e76b9b96671d9c3b5993e1d5c42996fc34b8d9e7fd692ac6294c5370b904fd7d4ea900e8f51bcac25d7868d68f118c5c4b5e1aa984922bb267a76e020460793c4f94bd786bbbe755d3cc58395b1dcd4355f0903475c48d0f32c55145cf3d97cbbf1a2ff03c12012127efbe9007a849aefeb084602a6f9acf9dfb6467e8ce02a058848d040d4a14fcf5854bbf4882cc36263fb631ee1b68f16aa3c8f482c2bb82f171f91471e1988693e7b8110a4293c7e49576ae8a52de66ed9ab35eadb9e55d3547d1433373fad021722da74ab3110da54dfb6b70cab5afdada4fb777d6cf6d94ed5dfaa0ccf3a7f2d45d9cf1a164c8c5e99966bd217a06b9bf6c1322dc5e56452929bcd0e458dccb897930d37bfbeca0e98356ef8a804e8e6ef3a3d935c6cc5cd47a72c377dbd5ff8acd140ff2bd3cc145a865f63045e277ee55a4e5f3fa64991be32adbb26cc354d94cb9a41098b33ad6635c5e40852ac0abeabf9f4b344bed906c4cebb662430ca78f5aee7561159e564caa7733a639777dd4d8c0c4d1e255a6e6fb6c189e15d3bb00a95652af441d113a67755b770a460f5aeeb91222f29a61b8d50d5cd8ab106d19b6d1c58beab06285b49272e27ba77ada1b29123da9045a9a8839508a9acc6b4c063a6e3a501fb01c33286e8335bf8f5d0bdd906078953962ec137db6015aae8a8514763885e1d1a24ac10e55efd3a34485c81d1f2a24f037ff911258accab4303b6c2ab7568c0b4bca88c06ecc77bca7a6ec0fc179043ba77f5f0012f97b4846fb60171e4a5819a6894ad416a4a51a7b8178e033570033550558f74be79aa39e71c8cf0ace11e46d97b74ef09bff229b0c3147bbedd50e8cfc8434d1e8aa28fa228aaa54a30ba285adcedd634218a3c1c82583d068d75d6da9cf26d381e97b1f65d746a98c13755756a33a3a8e6726d22509a9b0690737edda4cd4c24e6114d266e41e0d8f3b51ea2a8d6362fae39df4d1c6a94c7aca518f268d41a4af9b8368cc5b7d64d2f10336d935f37f5b48687a206a0a7251e4ed01004e5b49bdc9a8b8f479f8b31c678ef5775bbd5d7fbf1062f57033527d37c4e56caf039194dd3343d4f143d7bcf20c3b9d65599ed35cd89f3d7ef1df7c7af41874980a229e734329c65b698bb7bfa2bb751f1fe736f592cd3d8d6f6b6d6362593a15926eb4a58f3b39a53178ec79b6be3e2a3d4968ba2e8dea7aceb8ca25c86660950f33c914260a54a3a7e26c26471c14d8bd3e2058c1825724adcb43738376ddbde80621881e2d530eba9684c2ab7baa63432558943a6a64ec408e862513fe9a29ed2c51e74cb80f802468c3e6b5f9da5e19430018bc15ebd78c3af793312e26ebae090a989e7338d3266e87c98ddda57676938254cc062371cecd56f37deed85040edbd301f4c5491d1d8c1719dc7c40a318322e10b6a8c005b23d6b4955bf88819343ad15cf72d6b455d755cd2c5ae09448d39ade332ebac8236c3d031339285ec898a1c3a2457fb13091d33bac9b406122a72fc9a66f298fb0993722d0241a169fa64ca360aaeaf2089b6985337938d36828eedfde9478b1234ed377ee2419f4ff51cc9e96d3a2021722da58160b03d17b26b28f62f6b49c1615b810d1b230117bf6ec06c1ce68b3fc678a3818828cb1d28693eb6a12cd90c1417e93cc251d93f802460c8c83953414f76f6f4abc5819335e1bc53274b0d22c7ec1ed9abebaae6a5e53959645f44c5ba1fefaaa4c8015bb3028f67b64dc6d6b5d5bbfe0a6c569f102468c1239aa7e95e0379d77f506e7c6c6b6ed2d3d120267adaea9baae2a1e13340ad7548dda72d757f57f08e1a2c35e13ebaf81faebdbd47f695507b57e1a8a3b98efcdd6f068c47253550775528e22a8246dddf7cccd80008a069318000005000c8371200bb32c09553d1400072b8688bc8470a030168843c1b0400c0604836130280c00026050208a83180aa439ae92bd6ea36dfea7ca910ad69099128a9eea697280d3369cc7d579791f71ef55d0c6b560827f971dd2462687598d7298dea9323796e3e83c9814d46edc8ec3e4929af372adf00565c893047b1cc78596fea4576a8352b68c51da07d49b481bc0a7a78b99be6f301cd1c4f6d05bfb62718ac0fd4d9666091befe28d53e58708686b5c710508fcafb438b3dd3eb3da8646a8a4b0cbb14e2167680eaa6b92c6ee086c210ba929fc25b238a188b74aa3cd7d19353b09be55bd2146fa56a7e07e4de14ae54522265e6d27bbc1f28916c5ff4e2d911dabdea70697b8b14b75a9be4b465a37ce12532d0d64362d408338227cff42a274c17d24e205827426c2e94eb5319d411cd3c96db116ea00cbaafc56cddee200404266af65472fedecb59dbd981dbd0c3b7a69a7d776d8def494b0777ffe17806c62448f9f02e7289daab67c9273c4a19c8187600ea86cf0b53633a08506d30df202739bf169c70e4b23995116517cbf6b8933e1b2b4f3981bfd8be85ecd6961e7fbfdcd6cfc4db4a59e290d3b1c6e9ccecb684b572de819f8bef3bc6177b423d15d1c4fe8f07dc803d111419af74d097d2d39e82dbf2a6f5880fabd490844e38b53e89e6a0bdb0fbda8dfa315410012441ebbd25bd4c4d1c0541318382ac92c0f9f84ce51afe6bb69d556b619499acd6fe0d17a963ba4b79a616826caf4a2a1a8b64a1d505decfe8bcc0e44cd44e160f9021529161835052c84a5f4c50d750ae49ffd3dadd073284c1ce93816c968a22896b6a35dbc97d5886027f094d60563eb3633461fb2bdd44ffbd2b0ccf0f411848342de1675c124996ae65be0fe0e6d0a94ae10a02469b847de205f5c18a9cc665ea142e8cc01e78430241778d75faec6b8d2941655729e604a8169515c8855dac1c4f5e5832d0c3b1ad886ab3627429dffeaf5b2b2e36ffcfeaa955daa0b74357db697328e3950bbb577d986d693984f71d684d7a817af0968bf59ebc963dad1d2158460a0736798caad6c96fc93a75cf1b3b7527f3c4f8bb9ca02298ead92f848c350ffdc0344a30795d87dad3bd37aa52808c33fe24a391f73df55278e13c43f87d31054e8e69b705f62a57d488009e649a85f1f08e5034c1909fbcac256049d1000e9ecf7e31250e5bfa38eb4fe6f4e2cd204a1598736d2e2c084d4bd30a9538710ffb0f4a738e8fc687c63a144572803ead2b35725a1706112fc63287900199431f616941579dc3cbfc8cd8d9bce4522c4e741654cd11d89756ecee993009e840746541d2850c95eff7e3f417a3ea90ae79ad4eece06240256d40a108d3039fae799f06d9ce2d1852dc00f5312124e92b88b70ac125813e3e5b237c2d7880ae63431ad99338cdb3de9ce2a90fd02847238cb20d1d489a5b7a73f87425649b89b9e62cdea00fa47c4fe6fb1409b166a676b63926e8933959fde0f50f34b96ea0166dcab78faac84431960a24840a53e0f34a4e0e81534678924ae950fa8b0899eaea000b74364c79e95adc32a94da6c00206a663759f718189939bf2e15697ce4170783c03b58c413e7406f1d807d07dd3ddd2d0f8e027d0f01368d64f78122c9436ff86603bb0fb4a396d3f581dab3ef93883005e6e1ffc422049bad0da16e043a9ac6aad6d717afe8e991d05b0d21daeeca8f844b620747399d53127b1729a47ce41b7eb782755b15ab1b8032da95656093e11a0830dd3109e91b04f856b52f7b1e17d1bc4c67da521c3ad3f123c043a453e068d2e606273252a0cbd024074823e03e6bbab4ab43e343074061121c0e2cba1202b4e668b02d7fe4ff37335ed10592f9ae63e2ff51656a8f83a8350644ef8d19f1e465f05fd8ba6ff7fd4b2adf512f8d26af41034873bc4d91e2bfb17f29409508ef2f30b94268b67f87056bd54311f62286bd1695f12582e27ebf3dd7a7e40af98e830b0bb3f8febf834c6f4c84371f9b9cf323cb116ea539b96f34f6433ab8c3c18615eb303548cc521683f3df056c5a43ad2ce89e0caedd2c751193937ec4fb7501d3d7aa0b24da444dd76002240eb309d9166c36169fa042ab484b0810d88a283ac198838136eecf79e7ea0818568681d84925387f90cc25a0f3393aeddba0fa7909ed160fbd551f1fdbbd1dd2ab6cd7a8c0858c3747d171e812f770288d3e88b9a6da15eb0eb5cf73e702b4c923c885b8a5359d2ee0b256fc40d32e62ba02274262d88d0dd152269ab6fada873155aaade5e68b401cb8ad7284e7976bcaf2ad49d7f458847db902048b7cc20ef64c24b3d23cf829238685422231213752d263865aaea29c6359e219c11ef58bf34fefde3ee0c69ef6e6fd7bcc800bfba5d85ee3b4d5cafb8db7cb61aa7c3cc89e54db1b15df298e671c0b2289b3ecb0dfc8820c2936385247bfc543321f5ad5f588e1335fa9dafac46e618ee905108440ef77a344cd0518d991428761e8047a0174054b190a14595dbc660137a7eee5c20c786b6b8be85796f6e700020f5470641a6e9eb1040557a38d41053449696911e23c7a1bd5f6c689358f9141a5af0dd5879c0198950a8a7e8cf22c516e40a17ea6775966643d36558a6dd9b7d15b52195e09bd8a2e6db57c39dc01ed84963d478bf30a430132cb734fc617df2ff3c91f2edb705f124ce80beae5872043c2f112223cbc0b1fc82159fecfe51c1d09254e8bf6973d814e3ad05f00e274267c9d6cf404c46ca534c090c2a07720249523523beae83dd4f2e0a37e380d1a54fd37591a0f76267e638e9de983781b7e5a9994fe316f48cdd2d4170e053fa14b5642b2422ee997f1061b87028abaef048465a9b33dee6ce35e2af4495e568dbd72f253b6b9959983a7b0dfe3759f0a3fb8617e679ce3b2fefdebb901e7f8f3835182e8928245a83a5be341c4985c1ff21546b5315752fc036dcf2871cae8b483aa0efb1927796e3ac3a9fb95e5165401a554231db328bddc73c7a29e3ebac09e75e33e55bd1184a45f304ec842cf26c8855432656976e945f29fe52d7ea20638305be88ac2fb8a2d87e06e6cca74c32eeac50382a63ed5e844bb0cb08f6b15a76703abb0c6e3a06eaab7641596f0ce291e68069f01ef1cec81a19243c61f338c6a6e59759594464adfbdba88a27477a7f6c38b92c2c5fa149602280be7ce294aee9f95869af4b80ea09bedd5a51b5628dc9da948cdc56be659ada762513d5c6c5d1bcf67cd60ca9ea045a05f35a51cf1da3068e9612e40b7e6d1e9363b3a636bef7fea125caf4117705594a31321fc0f34df1732520028c3f6818abfc1633b37e35066d857dc1c526d5e98def9ed33422dda035f41d860882fd607c90985897f5013118ce6f3c491e127c195b7911aff3a35c78add701e3a809172939e15a544c35bdb51def1b1b0c6955a85e562560812193f015085607088145614a74a60e062613223c503e6cd70319e03578ca5cfc7eab195373441302f5462846b31d85049d7195c0119d07b165e7cf027df9c04a8fec6c656272d224620c539fd9b77152390ef09e3fd4b6bef748abe67583de884d5d54127ec0406a5b4b49caf4284b27eb721e62abf3e90898bf832e72142cd42cd0c97ca221f25e4a8278d48e00c3658d209954095f4ade710aac907ccf3d6490c7a58ab5a1a1554db744f6e245ff69e15a5c5a35982b69581cad2bbc59207e963d293ee52fe72792509780052f21724b717d51fda47bfb998ef5e87d60c9dd9a74a7b14388d6a0389f8570a017afb0e0e6866147077ebdbad190b52808ecbf1dd6830eaeabce7cdeaf8b66de7f403846f288f10e0dbb29d10cdf07941274e796c6ea6b4cd82d8e5f10b2b0cc084b79ad8c549ee5b8b1f2150784244d1b421f0d185295997ca64abd0c56eb092e6c14f446618e43a1cce6dcc02172dc34747a9a80602d1606b9e79594be42c19c82315673232467fa971093c27bbe8a8995e64efbb177b028c216daccdb5c6cad7bf77ce24c561bf5aaa92a1fb47fdce82a6d03940cbfab6b3739f6ae19542b0ce43622cc94e0da1c885fb9359d02686fbe4ff3f1a74c1472506855efbb623a854a9d23d255a634c381137cb37d2a454f3a07d490b20f0abfdb7437c0eb5a919c839c02330a099fe87d8e4b490ef595976a50ff7c4392e199804558393b401adfcbfa95c60198e43d45583de4624c5afb208d9dc4caa993644057a582faca0810228f5699d0817e0ed035212ae30e56df041c7501a939ba9e94ba9719886e4c53c910a4e31eeb0504495f304001e9c3130a280a824998545bd67dadf41d189a70bfbc92934c04a362892769374b2ec06cdb56808cc88bc8507efa1a5d80573052ee230ae820f67e2ed66884f0dda1fa52954439aab931d47aab90cc423090c2d0cd531ee105881a20fa5007e33490d31d70a0e41c78a70d810876682265602c98ac7fe45ca2c04376e455bca3a44f1b1530cea4d700987153a75a8ac183adebe9b04e3a645f7c684aedd2a8690f708efac70ac00ed16e70a2a2ee4d9397e5971aaff3c91a0f9d7cb8a2a5fb60a901b652b64e98d5351f75f58416d3b60b942650333ba221625de755064eea799772e0346e26c2612c66eecabd5100da898327305aee267e4099165d8fccd4d882967be7f3a2f44450b4a3f9af1a18c1651bb10d44ed7d3097b3fb47e8a0efadf4dc3bd97963a8c2e939259800220a08adeda6a0d2f59d474f6705c4461badebbace76bbbbb00669f136f42d3acfac5264251759381f4cfe1fc70373cc3396eefe11b596cb6874c4d5938d032425546c0226958dc299f978b5146e633da1f73456cb62ac3eb1c2eb95bbeaec5c898d072680851711896d1190496e3fcef6015902672ec665d10703df6cb190c62affc8d01be4893200cb52174a5372bd428102119dba72bf454b1282b6b5261daadaaaed2bbe902a003c537d87779ed255ac50019f78c3a708815ad2a22e522a57e00bd53d342ba7c1f8db7a091ae2962bc3e12027725dc64af9e0306c2809078f6c961c6b13e0022125c9f0edb1842ec020da06592ec229641b925cf3e183282f2a583e6466ead46047480d3121b4e556e907235ba0c08c14b32c87acb81f601de6b17ffd223c2e2167e0a8f5970443d4e63e384f9f919c2ed2d6ba640de1e11b6f8b1d7548ada3a541e87211197c2a4913665903c10fc191669341a3c74bb57cb74f6223828912b52c439ce175432170e1f25e5ad4c02fc27eb06b5f8860422d942f8927e70f348601d7b6565264cf2453d992c00911c10910f8ea424cf6025ec0ddfc6dd6129f7cccf667f625d7b103574742df314de24bbd176d88ab25097d6112ff2893123726b4f7d3705672f965335dc0a998d6de4687a4d2f9a15fab9b1152a238b15e8f7c91cb2b0a653cc503ac778394a461933efb3019413416b3ad57bf601872b9ea80a75b3b9e7d6cb683fea97c481b0a5c6856cf5d651296b1117e30a5b81f73804febf3ba50f147419f01493bc66745e1b0c13e0b933d2607c6fdf80cf546028144dc07bd8dffd495972b0d076d800116c5344cdf920033430785d038b1a936abee2c681635c7f1a3e8463beca640a60a4f57f96a4852fa2ad1e4df432598627674724fb36ebbbf6d798c3eeca8f711ba4fffd779ab5adb5b4c59e7a3663a67ffe4142c3faa071a6d161e20282203b7d9a285f70928b36df9e8f054a97e84ef0779431af3f2342adade2f59f78aa5ee4967515d96e7d1a8d54aadb6958b47f3bb7aeba2418f06541652ea3eeea60bf58cbba46197aa75b77599a3760104e5cf2d34703fe2b1e2b146622b1f3ed6f98e6416c9a16de0bf47f31c58fa9898393b69753bf2f33dcfdd52c2c0ae0f33562f6f8f4292b2f399248201fb9926dc4e25773a12d89e3157d3319efd10d2267cfc344f6bf2ca0b50c8b18939fb33ede20528245fd18bf9c0265d1d153e471e926355bfe4cc8e23c8f070d0e5da37800f71bb1ddbbe842f6816814c72968a07cf3eec1d037284bd766b94b7f85362c8b66004e5463253616526a8e24b5295218818a409c51d0b16c8436c3eb0a26201829ee3f82769088ecd249910220230d6e60042a81d18a7c4a361041d02badccf7c833868205e2d9ee7daaa00d33b3c66d10ee16370f83f946c60bc25ed75963e512670722843bdb3d82004c92823612e533fc882f015842ba8cdb0cb07fdbd1980642fff1a3dd19419fb0206d1ee3f3bf47bcb22706388499e00a17945cc6e4271615a61d5e130fcb446dcace0bc752c9ea64f28bded7f91e2729f9d0f89aba1c5371d5c0261f3ec6c62fde30c2ba20f27d68d4879337fa5cefdca18a0685e228a55e07ad153f82ca7e92b1a344df1c659951bcb88ae909cfa5e21ecf8e7980476ead867ee60b0547d45569bb68f2088c3adaeb66b44dbca690e90194c6cc988d01ad172f2188e753b40025677a504f0c83ad83010e4bc18c4cc15086f66bcb37d7eb96abe5e9fb785e8c855e41d1c2ec0874129efee5d65f475c63a75915287682ee3c9d5c11164f4a261f7a6b96218e3524fbf8c1aec9b88a71fc0a248f58986a7b9dcf7d563bb1dc1481e26a0bd4521e8005f7ed60a89b1ccc7e7381b87d6c761a09edbaa83bef7fba5765428cdd57ee67a4b0016f71eb9c063a905350b615fdbe913234142c72bbbd2e6eca704d9e88b7a49963d8deec571e2697a888d48b0e34740b7b7bc139dec2828f201952497cea9ec2944a9861ab523e9019cd0dd10c7f8d22142c9a6937a2e660327cccd627bbb7f5b0051f6877ab24e6d0f1f8e34814b2c2ee70b1c86865f6010da6f2331d72b2cda7ba515c5f67be1f01cb26da7ab21dbc10607571271df67f4be584e1629e13dfc1f790dc4414e06830f272314ffdb5f02f58b510702945ea858faeed48b60f547c2074a001be5864adee422bbb17a9c6c12beb80191e1f77b4cb002cbf3f81598b7eac088917e9e6fc74b9a019b35db889831e6d8bd08c5320626ee97d31b4be69a3b5d6bbed6582b0cca977b565408d02ac90322979e4904d8654924aeb91e3e56ab2e8e454eb77d26ec31479d78d5f906f415eae7278dd8acb5fd42c9aa8138ecf01ed168ab33c0e2abaeb37ae10b6226a2ed78c8ac0a6a85eaeccc0eb26e8c4212afcf5698a13798745f6b63f4ca3f015287fe88f813032244205582f327b86eea2def4fdca92d5a4b9893736413b4a82b72e61434eb8013c5af8098a66ab01fad2f5e285929c889d9480d9fff47aade0e8ff891e41480c08db4a95d0eb8a98a569582182009cd4415cd39bcbff694c71e990866142a655a443804a78f2bb66188ccc5f7ac6f397b5be82b125c0aa0a3fccb278bfb8619cf8067f5e1c8f72552f09026a3a0a995ba7b619afe16694479f2357ad5a3ee0f455b74be85244999b39ab9c89bbbc0f10af3b6b971d0bd29b053a5b413ca3a5d6408c39c628eafecb5068e71dc4bd7760157673797d467b00160714fe14dc98193affef14efef4391dfd256b9d608ccb2e7e5528746aaf9effdc9a0ff1f3fbc777ec313afdcfae993d7203cceb1f218479364b3ef76599c78bfbae2e0f4e9639988b11f09e44a9a90023848473015eda18f8b8bb3daee50bcce9f85042c4286dddc57450ede9a7d47045735f20ed5221e4e5b81ec10317e1133b91c6ce8c504a06e3eae32906021c4ed4372632c2382211c89cd1d2f8cf611e2ddb823d3be645a76ee0a26c3b3d9203572bf18fb14f8fbee520fae971a96fec166944e0625135e6ffb2841dc981258df4e1281f317e1342193505f4cb5239331841ddf3109920094197047602004abc9c68a3316893b0208be9cb99735761c3077aec546e54f1aa9702aa2bec89bdabad420472cae32e42210c2f63ee28089e6298b07414cda6cdb0c9d3f95349b7392cf41dc1574427b17efa6658f65f1a9a0d8a5dabae09a70c0f6cc174487c08262600b4935cebe5c38b8baf61453a6a0cdd4ae758bc7bb7b0d0aaff77cc7a297b7d11d2afa99dc8c3ee894e8ebe3b75d6579562668a4814a0a78e5c500137e2f6f2a9022db569d5afb669d5e5a6fb9916bf5a05322f74242e599e9b762bed43ca4eba8caf4b167614fb80553cc4dc4552a1c15c1e77daecff408bda84134f81b0282b83a422e7b3722c94d59f2a49fc81c1ce82f78ade449a06c81621d38c011fd6dcabe15b84bc997ad83807254c3b842b5ef23506c19c4170a3e0d271cd67ec76f661152e33c7544d22d09260c77f1d2e47804129bc7e81a93a0580370dbd86ae4a3ab1a11ee888b0075981185eeff98e9c109d563ec86ecb23400841b1b882a6241401e6bc57d205c296f76555311170da33d320f6108059174820b5cd40dfd7c0dcd9fbea16a1fe18f5e1a709af34bdba5153149351c0c4bc290f322ca868b053a71ce5824cb3587879db50adcf4bc3d54468f938a986fbebe598d7a286d989bac9eac87768f508888ab9a76a49fd0f742ac9f54b7502a058a436f68d6d31c7fac65b49b8b16c5680990e0698647bb3d3ef363de5a84a212af04b05d8a639d196a033ec2e3353e0c965bf3dd93254c78f8488138777cf337603ef60dd8acd5884f87426bbfa765fd7365bbc48f49014d073bae018722352545f561ad1b12b6b96c66aea0e13cdd5fa5f5ac0d47b10e52fb63e85f4788250d2c6a2215c8cf59f29d5391072b1dee6585c65e5bdcaa5aa86cc1202bc0b7d8f02ba7f505aed67c77cd079a7ede91ea5e5aeb45a69f6111285c3d8886e238ba03b509686ec44c71d2c035a3da9999acc6a34f8cac2cdea9a72e22ce0d5329bd2c545a1a52821730bfea50bd060d3ce5dcf607f9f222778b8600dd900af418678feb2c9d123b68ca810154c68ad56960c4ad44c4eea430eada43361952c82f1f399206a4754e512383190abc704f2955e19baab069ddc18859d73955014dd4fcb4bdbca35c04dea7a7baf092cc8ff9035db4bce7e40c1b05d336e319e661e95ef9a8d10ff408692d31a6bff0e22a14858f8d68fb13006028abc6e3e8cf4f7521d1a05546ca480347453c5115e121cf4649507bac901ea237ae8952c1469e5dd91a37f560f382e2f365fb3c8d8b886df7a13db768deec34938196da69bfc4c52c493478236766352b7af3677006a70e465d902139a42d23155c664de962c13a17bc3ed4195b60517a0c71763ac9750b386d71a8229f6e3b40f6831087db5605d78f2f829dfe3a140afbb5067bc035303a9f5e4ef139f36f097034e9895d1d964277070950533ddc265d1ac0fabafb6aa9542eee8602b9034e09f013343d0445786a146fe073be3f710de9ce819fd4a0c8b48d1fa147753b833cae663106563424bab2afe4d4260a689a059de14b3b39940a12868c136e1c1247c15b78700ac1159506932d4049d103dd1d7a9e832a61fca8f98bfc28b9a9471c85e6bb16f2dbb3ae01287e7be53146eb4854662a0e1a181259666318692353c212ae73c86168e05b81bc56ed86859c4f39b0fee0272dc9f5aa895250fd6c12bfe6244f57c33379e8868274a1d767d64ad456fcd5a1d860b637c6c5ecb484a596509ae8683740f45a9d630da16602d40e270dd5f09527b355c7659b10a11c0cb4130a17ebba69e1a9e561fb44a1348c559449e00bf9247e994a671dad93b4a4d4fb49f8af22ed463e34676796fae72827bfa2925f8bcbd855d0c35e17f1ceaa6ee693adabe523147c9785d7b3fd09b4015c7fdd4dff6f268e05226f4924c8205d69a4cae112c20253048cb34b04fccdbdd2a074a7542c304505b4e5937be5d596e595d81638aeda4ddc55af7be50184c6a473f49379581959e2ab16864bb75d7d3db01f7139293b9ce9053118b9b76355e4322358e10fcaf68617b025f949b587f656a314b05d19161b27ba7d59bea4cd9061eb796035e9f6e68dd5fe8d1a56d541f19ec6dabf015622202867eb10245eefe4d4dfbafad193566cff07dca12aaafec0531642904bcc03e5e0046bdf293b9db6132735f02ac515161c212790a9994dfba5669e4525859de2243486480915cf42cd353150274a4e5434f6a3840ecd1e53aa0dd7e949623d44ef49264b91ab510221c9f2f5733593944406e28c2bf322595e39af025454ba417291bd53d557750be8db5fc1559cc8b4a9524204b185707f0ef93013efa38d3c6e0a78a95c03838e4e93696ec2adc56eb97f1014470448d81a7f1a5c4b0d8b81e35f406290a8b59fc3ed093990dbad45ae638781d110ebf47b23de83a026bf4303c8283ee75b88478b66ee04a44cbde13cf06089cdc6983a7c1bf8b7922846cb03f03c94bcbaa427275b4097279abbc5434a96b2e24f0913964e95e323db6b872f471b736331f6e0e6d72502a8ffdbd45df689c8a4ff9e1ab47ce8a01115730a06a8296f7abe38eb34ed2e0282d9896a5d97098dffd7c8f6dccbfa4181ceb482a62252fd40c8e65155943d63d6a10701ee98a54dd76b076a5208b5c7f777078771b2d53cfa97da15c376146ea4d01c8f637b091e2f5c938188328a8ab7a0316a6a20318f292fe0f9c16d0f1ccf29f4d1e4acd23b2962ecc6f2cbf77264a356b64a13fd4945e58dc6d3662f628d5ce6aaa3846c7eb52c331b581e5e9736bb8b264471e7640839f95b411a772a3df226e4f6b4ff4a90f7d018df138b961305491574ae1ccdbd830bdce15d73366251e9d7aa3e1f49358adec034c16cee19e4ebad5716c234c233f5be7d6142ab2f87f74cf4e268299cba865dc60b682b2d51acaac2564e8c5701430b0d9966326ae61bb282829d9c25bf7332b0d432855b9abb9d65810c6f715932ebc91aeb51f76a540f6ef6891244a3fae460b7af2856d3cd832e6009a8738522782580df41acec7703aaacc28b5b20103a9b3689b8cf54ebc9c335d70e2eaa0d5511c8f7b67830ce31d5f6535f0997ab2e17f451cc542a63bd0e09fedc9480066a0184458517e2044214133295e56be268b5c4c0988f15572acfd743f118b1a559420811a195dddd3bd508aa088c08353d39ac3db24836a956ddfce788a28fb546f54bada2e27725f6f2f1d9416b54b5cd1dfab34645faddae5fa2eacc1a511c3a75d42dc65a55a72c942a55bba83697d6b1635a5bab55b5aa56d5aa5a05e61d34b5d6c4ac128bd6c8c1c517d360189824d8da0be38ae1c11503c3ff310d7f8580011160586cb91b9be11ac1da6b6d0f18c32c5672c1b4a6c130f662181fb0d2b518b09fbdf8fb5e7e5c62c182055f0b232187857980d1e4e8ac2e161a6c2fc68205df991a3b609ea9363c1bdd8d5cc2b4365b0d0e13f0c55213334176310f316c2f86e10f0617db8bf1adc262a3c9e1336f369bcd66b3f6add454d681592fa671b9762771661470758757a833d9f5305ec2d8e28e852c509a8b7fc5a1af71d0301afe0a21849b18b1d78d0830441061860cc7e119ae114600470881ee8b3136cf226a42a0aa038ec1603cb8605a733fdeb85eba5e2e3e6dd3b6642be2366d3c80532bd1d0336956995534a8bbcc28453b3d5b3e2573a787480c81562f7e34c01c0db2fe87d48179981903d3fa3e50cf2ae05759ab10fc88f07891122f3d445b2e8c841c16d6008c264767759d68727272747678ee4c4a4a8a2a9a3bf499f4f4d86c5051b6dbb95c3475cc2172129744848ceaf8b431e9993ae6107c9c5bb4c82a227a666aec80333b3c1f8f0dcf4677e3462ea1041cdccd66b3d5e030015fa79a9809b28b351083c966e0cde50405c2ae14418fa8f67b6a0e1f7a137331993bf42bc771401cb77bdea8584452a5730822a40e7d5965bb34397ce6cd66b3d96c361a1a188d140cb5b144ad25d1cae1abc116d3e808e90929e6e4d2c56a52093127386738e7d49cab3959734281c39c7a4e2f36a0eaad6fbd0e815afa592190163bebd659bf0a81587db50a9f6c40430fc359eb20f8bdfdb83cf52f8bfe7d9ee7754f4f40e95d9773e69e6ae043e7388cf185a2df6bad7d72a2865affa1ad09f290a542c0c560616247a7ef7542f45a3f8740f593e2062eea29ca08c768d9c10d9568220538c22668607b6a82034f33c0f244031078c104155239ca1502d1a456cc0e1a86042c9b5b29b06145a5b17420fc614512ab06482055d26a07337c532195e7043ec9808bee33ca3f7840e5692087199476b0c08f2e4e3e5069c28054d20ab03c6d898a22df2e9fa2a8d1f040bf643ca1b3cd264a77b71a1664b141bbba7c72c114312af44c974f2e00420e3ac6066c88d02b1f42a0c12a4fb71a0ce8b0cba7db125f831b979a1f6e56d4c840eb2e9f6e5f625b7486124546169ae583cd0cba25448d14dac2a046078d9190a185eea03e043a3bf14a682b45cd94b6389841735d3e59d1410d34d8e59315aa1568dce593952f41505441f1c31314542e8c2e9fae0cd16d974f504ce9a3ee5d3e79d3a42d93b6aba5c961f667983426d87d22fc34fa3f4e2e67613e7e22274c9613c9e7dec97cfc4e982a27e2b813cc67b6e89747c50b07424495e0881c9880026abe94ff16f8bebee7795ef5ba9f735a99f34b2ba50e19c057f2f6a70ecb83cc9dfbf7b9f4995c48eadce7bae851420529aab327b4fb46ea1124499430f92165998af7f30e2af3fefe4f0a3e3e29de5f6d49052d7c1bbe94f25e1624cefd7943a0908641a4ce7d2d033d2565a5b5d3aec6279d4b9f1f6edb4149a3610f195d2a39926423498011f9a55f0848f1fe85622275605398f360d672133fe247fc02fc02db164acd299e23b01ce831b4d1a6d08602cf91ac5f36e91376fbd35667e0f728292599ca72ca72504a3c073a1c42cec2a48a63933ef35f4ce82ca1956ec3a43acb394c6aeaf673d6faf57a9183ca7516660a6e1c74e641ead81fbda93477ec7f53c70372cf3f66e9935f7e0d79e818e8517291d18b2a2d730f0b5d9f86b63a53e2a0ea6cda2a8e7daa1e0e4aec799e97a839a84af3f884e1e0453167ad5fafffccc73fa2f52b64496184952b2fa815c78e7a3956d65e2b0c7fec1efcef0bbf0fffeb42a030fc3cafc525f56ea8387958ef25f73cafeb3afd79acd5117a3e058ba0f983fdf80e015a3e7961d4e5d3172f9d842e9fbe38f50c46f5eff2c90b5bff2c58c37be9e6de0e40f6fb7700b2d38e9b4070fa9db0cc9fd24eff010a189ff4fe43432058863fe8c380390cff7d8ec3300f12fb7db15f2eb57c4f5e50e9ad2e9fbc88d2394edad925cce20db32f1f6639fb536bc8837efeb9474b7fc23891c3b8173b7ecb25d705891d7379f94fb93ba0619822efbd38731c4841282a93faf2969dd2db95e9b4c5d55da1d27e1de7cdd5c779db50b4c551673bb4c82b9f162e776e815222a1860aaa366fd672f846ecf7ef9813eb1c06383e9da613152f9f372ac632b0c3d54110ef980e821bc6e10de3780c3508b5cee1ad3b18a3831edeaf0e62fc20f6fec378831dc41ba683e0867ddfe30dfbded53bbcbd0e82fb7bbcb9dd43c53b4349cb60b1549d4d259c45ca6613549dada6fabd38ea366d544481944d22a478ff2add6c94864904fe8bef8ae39ca8e7eee857deea8a86abfce0b797c2f7bacdf10efb0c816666a0650f7ff51fc428fcd5cfda9c809c4d2366ed8b18913ed3ca01e46c1a91e74d2a06fd4e24c279933af78ba8787f853fc4f876ff525d8c1f6f222ade79a3b22b542643f585ce6248538b54bf2fb95c2f50fd7ee6f0955ca6d18432a3e03d9fa8a8c8df8832597cf425156fa48ea414a094524a29a5391407dd712371e453ca5fc6133a6bd24355d500436a5a18564e289afed437d0f56dcd566bebc33096562606aaee000ad2f78a035f8b7474a1dc2857875ef7fc7b74a150d95402824e4aef124d1cb64452a577822e2efa28b7d468d0b3368f6ceca8eb96e9de5befadf72af5fbf48554bff5de4b61f4de692475eccf5bc3e06b869296c1f6f165a4e2d0206549f01146b2b60152b43f6228dd5a23964903a42c02566ad69844c0dadbc36a42eae1ac51d1ce4e7bfe0974399b14983744718089898159db316bb3866bb7a967d6a691cc2c82ce682694a6dbd4612a51a932917a76a4a0e5418d9b5823b8457752259cf64d89a65a2f9dafd84b2dda4e396728a262ec02393729d8409762673169235b747edb237d5ac8216704e801d40eb2482b4546681cddbe4815e75e1915758f7864545111996e7f1ebd9a12a083a31e2f55b386ef8863c7fcd8957a4a626acb402501057503277c4d0b426ef8929c7be4d4c484d8c47ee4f0255a88007ad8f0255ce7a3cdc7843c6b2fe1fa920b3543b811d3e863a4f133f8929c33a326068b9543838f393f832fd14368c4f80883fbf13184dcbc00f8922c24068c8f0989c5584262ac3762fac1c725213f63c88d908f3164c6cd1b31c1e063ec61b03ec6d7f0255c5f6a41c647ee4b4372f2901eae971962c34799afe14bc0ce2d60c46463c4e4838f4b43be470b397c5c3a7ada90a7c197e86e0123a61c1a6fc4e4e2a3cdbb64f858f332ff537900a510005aff01000a27ecd0e1b345f81c3b84efd933d93661d208f038b6085fc20ee16f6c1b3c7b87d208f035b608afb343f89c4d028d8dd3a4d208c08d98449ea5a85847e0990a2ad69fb145e04b2dfccd0ea1059ef986fdde34ff7be665ecd7db6cd8d76c9a8fed19d8879be6c13df3df7ebdb7613cdf280dcf57f60ccf4e3c6ba162fda23df444b6d00fd9432f640b3dd11ee239680bf11c5571eac76cafc7d8d8890920e1a5c3d8dcd3510d4ed06576bd61024e5774d7c619b04285831e53b987d93c9b8be17bef49ef6cd783f6cfbbb65bcbf52bbbc73d8981ebdc8e617e612d1734b9cf362acb372abb929db2960c4565e0d7cf5b721495adbe7ee64265acaf9fa5ea54af5febb20f21c5faddc62c90d88a14eb7f1b1f21c5fae0c659a4583fdc380929d65f6dcc8414ebb3369e8114ab4d7e5b766fcbde6d190a702190fd56d8f85671ea0f6063201b43559cfa413696aa38f559d8780a5751b1b2b06dad460bb22512b728906a34209bd206b0256d858d6b50a2c9102808b6b9aaf44b28157e68d096341710a248e9564603fa2d1fb153afd82613e3890f0ac4824fdeec265ddf042e9ffc4991cc2927940a37a9a507879883a3cf8f5171f2a07ba48f91bc6ea712c9ebb1a43ce876798fc8c11756875930326858f7abf77e76dfb765cf5bda9d73bea25bdfa3c5e3be12da5b998ff96908b47a4bc51687e54c45bd67ff747e90ce2c2df3f1fbf6fcd6962f31c65540e9f24b974f5448f59c41993f24afdec22150ce79cbcf2fe77361506ebdfca1dfb7f60d81705f7cf185173dff6d75cf91bc7aebbf1fb8e75f81fbe28b2fbe74c997623e871278d198bcef421edeb75e863f70f782bc6ffd0314f0a473610f98f7f92597ff75606bcbd71be67dc7a3c561dedf9e5f7adfc1bcd54f6e61b611cccff03418ce949fa6f52c1665b558ac47f2fa02a9cba72024f174f9e4c55467cd607e3cf282b57e056bf1a04bc3eff3666d58fed9f3c36c58e63f54c6082d66fd7118cb52b183b15adfb71b307bc8c5a8a48ff991805dff97392c3feb3587651e747bfecc412acadf30a8e82f833a7bf931c6e30b747d8f3f4665acff3e29d67f0f6aadbf87ec9ac35a0f83fefc3a7fabdb23d85b7a8fb977e1cb70f54359fb495fed0f8ab9f37df7537f28b8f1e7ed1955baee6dee32e7304857469440a4e3057586f4b9f3866ea70df6a907f4087e379dadb5a07d2b85764207f1418fb28a4913a5d7eb17a864afd0aed86b17a5b55a1b02d94aefbc925b8d31748c451ff38ca939f93cf2418fb6e7095231e7f778a6627e1c642675cfdaa4628af4c19f9ff6207d64cf2385d2338dd27306bd1f67979ebbcbbff43985caa3fb2f2eddd45204ad4281b86f952c27e59337a3de415e99ffeaf927d45b790dd173ce398725d0e34c9a20903326152753990ed267fe4b08cd943393599b47337a9ee9f9e7149bb3075ef6cf561a0af1f46761434165c922ade4c8218a7bcfccb45af9bb93d4c934d480ced2ea97be7519c29339b91ba0faa5d4de67c20bad32819cd1da8c7e9f365deac42b8bb6521ba2dfafdbd2a6c929150f80353aa5dfa753a86ca44a7d532ab4898a4ab52a2dce59eb170b3405a2e9bb69209a28ad512a773a61af0de71654e64f277e90330a0595258bb492238728ee3d33d3a2971ed15aa8015aeb41eadccfd2a707a9a31e2177eedf298552b90f04156fd3bd0fb3a4ef7d6929f580306b341dc73cbec1061a408cf1c37cd1ad2f5fb4d68f5b8f297e2a054a1abc97b27b2927973da34ea0432034b54d9bcc3ae4e3cbb56585d9b4d65f1f0b6e9a7291a232ac33c8f510889a60737d4a51244a6d98524ca929c53f4ef79ee9784a4da94937ed610d7a9c5c3ae6c29a85d4c1df0198a51945655ca62d67ad6d78d630aecd98982f32675d6162608c4849aa29298a3d30738ff4a1344aeae0cfd1c9191454962cd24a8e1ca2b8f7cc4cab953bae183fc5d84a5b9f80144649e61812da9b818d12373842460e6e300411371041ec49d374f974031a6474d17a8b9a240d5ab1c31432a44c2103124ce12483298288d140cb74f934050e2b9882862a22a6b6b08192144ca4c0ca91142690010412d4604b0e36567ad8417f5d3e4981c39314519ea4c88013525fc840aa4a8a4aaae60587e79c416ab59546ca5aabee81c3a27dd51816c695c1f5bab85aabb43119a6abb6a5bf7a2d0b5c85368570656bb51564596badbdf7de04d84f4a2965ad55ca4eca18970c8c18af191a2b613a2af06996b6b6d66aeb586badd3565a6dbd2f6a635418564a995b6fad55ca186ed65aabb5d6c26469efb5b5d65aeb4d4ccee05eedd55aad4642cfcf99c5e10f5c8136d44820818405b3adb56a243e962765d7aab556cbc5d85aab46c25e7b6b95b11546b560adb7d65a6dad55d35aef9db54a296ba5a94145776d772d87f306659db5248da25f132e51a89a1a1ec24d2b46de3accb6a1c2014aa5863a51a79b17d541043a852a51251166c4a051a8386304285414abed6e6769ad26ba70707042a0ee69c4dcda4da03ac5668a060935503112708e4e8d9dd6b7bafb6af15a55abea975a45655ea1229d37fd819b16274a6b9497ea05fcb6d42d4935a9ca4e5555945a65eed0aa2896060d1a39356c805f0f0d7a01bfca5a85750bf8d9ea96a42a494955a2d02a5a55a34c9b4da706abc6c66aecac749849539466deb171a3d6a8280ed7249badda2acea555b656d52a5bab495347dd22aa26d96c944ea1d8661424241e1be084326d586a6755091d121c47a69424c1918b9860c4041957ab554441a064337cb3a42023fcb9a9e0433acd7a2eee000e9b9027d65657104feaac4fd46b33369a9576b5a3d90b2a5caf1742781c06bdce1a1d4d8f725d5399e78541f93d8cc320fce3e4611fe38c45c73d7e3b4e1edf9297cf28558f46a9d3ff26ada087247db2cb49fa749555449fcf1a42caaaf59056532c9bf4b9ef59e9f4c7950efafc90e67b36c8d9459ade0d7d7a3bf4f9439f770252e64991fef4fa7ceeca2267accc8476a24b29ba64c91bcb8905c58a624531bbccf59cb36785e2efbb48f49341a76cdb22d5d9cc161287fe04926850aa36d0240571c49ae23ac767aaa40efd981eb8aa9c333b5075ca67945c543ab3ebe19337578cf84153cfd1a5113fb8f528166889eba692dbef532034175fa2a2032fe8d60b5d27de14387a1a4734b3d05f717ee4fef198d4c5c3165a4a29a19aaed0b2494a293d20a5acf726d97fa9239f7316db6b2d37a70c0cbc0a81a68ea17a7d56174dbf42f5f9b94b3dedd39f96523a47db44adf8a41c5937e972c2b5d63ab26c9eadc75ca1ebbc4795f390ba2b085dbfda7d6b52c74ad1d65a4b29f049798f5c41dc5a6bad7452b124f1b592d2b7750acba66b6c6e6dcecfeb3247b7d4a4cffdf9148a4b1004c1a736e9537fcc330ea91ed9a79ced0bd7e485674e69cc9d4b1a73a7d40a073ab5a15324a963fb422569ae6e5287be4c171e524de790ea0cec92047a51eaf44b68d4290da1d83a45ba75fad47290d659656521c9e072cba938f3a55472bce26987f8a4ecb3cf266aaaaaf84246942aac9001a50aa94b4301292c5fac076b2de5b1d64eb90423a234fa94467913271298d426715d958602d38baf7ed0cb8ac45a1890b83ac72da9f02d2930b8ba8e8f489074efed38bb37bbdda30b86fb5fa5e1e5a37d0c03f7b31f012177b4f75d0b4abfffa3e33d541cda429ec81ef26405972ebbecdfece9e1a1624ff7230f0e2a52fa437e8642f385fc1c7aa197319fefb7127af64eea7cffcd3028bff744bb09d10b7dd06e12f443ff854f3323055a49ed5e6cdbb4f03f14db3c251dbe77a96cf446c5ef1e4709f93f59d1a587cf9f8b2a7da6cb272ea0baf717bc51970b90aeafdedbf757fb7211fa27b4a10d231a7a17de05de64e89fd0be896d365da7d717be167917a8f876d02f742fe34665e115fef5ebacc9a4bdc061ab97b4173e53b1fe0b5bc6023564a9a2f9af3ec67f39048ac1df15aaf0a4f397e10a371ffe0f8db167c76150f89cc382c2e7cf390c37fc72a162fd6818c455d163547c096d1891d0bff02ff02642ff84e6824175b542185f3dde525d548471ce83761e1ad52e3ac8a72e3ae01b8eaab349eb3293514df80a207a7decc457213e82529798825467978a2a2c2a7a175e8643887c919fe11016de859fe190205f84dfaa8a53df858d6b15a74e79576391bd847632f445ef44e889fcad530a4a4751b17afb3e6c8810212f69451b3664c89097b48f0387c2cbc5c3b61b1a55c71bd5ebffd48f036f54fdcb2583340cc317a272d6550cb5affe72a1b290d7bf515466f3f5439b0df37e76ef5bd8308f631a8e4271eabbbad0f88647fc012d8377ab6da54eecbf70684b9ad096b4cd63df3719c00fe14d88bcd00bd9432fc321f39bacf043bcc9d0d70af04e867e0aed5a01de09111624ad002f4320dc5b16e81379217bfe904d7f288606cceebdfe300c3f535152d98a7f4e54ac5a3af7e0a7c556d161bccc635b9d09d5d4d4d4fc931545f4ee3152f8f5f51a75ffdcffdf86efedd92595ad3c6fb5e279255b714f48d284fc0c87509a10de440234a10fb7b72f14bd5b58b83421fe53712a6c0a4db14dfa7cbd7b0c84a340ba10080e8906f0b02134e8e94b1a0e895678d890f9422fc49d10fd7c49fba977684b1a91b1eba31c71fa58b3c74e668f38bf6598ddb5475d80dd64d280fcc72da9f05f0689b6a40575bce75bbb6595d0ee3d98bf21900be47eebed4ec2bdfd6c8ba13de6476ceb3d541099224445d014215c8ab8212e5436ea4065e396a8222c45246948e8edd72522292a1b97823e89cac6a5217f7986a2a212958d4b42def21c65e3f1f57111405f1fdf5208c0d7c7fcebe3fdf5f17f7d2ce3ebe3292a1bc5eff1f571172a1b47781f545436fa7c9ef24265638ecf5da85845fbfaf84baffd1801e0c883d221ddafcf45a1b2f1392a5436cebee7eb68c2cb9a705429c1864211277c7deeb6e3eb7357747c7dce69f5f5392de1d7e7a0c0afcf6da1b2f1c54d51d968e36f7cdd799eafcf51d5f8fa9c179dafcf5551d9e8fafadc172a1b738dca46185f3f1b51d9988fa86c84bdcdd7cf50a86ca4f99aaf9f91a86c9cf9d8d7cf51a86c7c3d152a1b49f89caf9f81a0b211e7697cfddc4465a3083fe3ebe72a543686f0374d2c8d005fdfc7eeb1fb27c3183e3ee931ff9b1fe0eff60cf0e05e15e063db662fe15cf8bd9fc8fe1c444422cf03888f97c86af311e89f488e8ff1259a88185b190189bc8c03ec226ec494c7d5fb8c90021fff7700648cc097685de4f3464ccfc71138203e06e07d88e4c844c411fe89fcf391bf0c222fe38d9802c0c72522ef539483c88b453e39de8869043efea7c0f928e303f0db48d12a17c540ef79d1e64bc022be978a3e666455f4a01171843762f2f8c89fc7e5e37ea0ef762754c218fb1ebe240badde888926d4f9d8fd15f2ae8d10ed574225f4d57b2f747cf4fe0abd354037c48d98c69e97f12579b4791c387e0060adec71f0257ae88d982e1f7bdef225dcb53f8f832fc9343ee2c84200e8f92b742f1fc1b742d7be11d30f1f97841e00433884be04be44e328e1fe8f7d007cf70228e363cff7219b3c248bad86bc21af7b23a61e3e2e0dbdec059ba18fbdd0237b23a6151fbda7817cecbe7fb8c3206ec434f61875fe065f92836cde88098513f818aec01b413a7cf4f136413a27d8fcaa48c8c7d58341ff152024e2464c230a234fbeb1838fe0873abeef061f6f7c0d9e376202f9a883ebf135f892ec838f3572d00e1d0f0681e017047e6fc4d4838f4b41bf83a846d0eb10d5d07923261d7c047fc7f73a3e2c82c29f407423139d40b4e263ec43a255f8464c28f07189e84f287283e8798adce07923261b3eae1e053e861f4de4d0c520875a6b51cc30e70c6e98d3bbc00d2608f1add3cc1b6f62cb70e34fe811a4a202bdd0b7e12619d682d0d42fd7ef05ecd316557ad8e5d3164b4f7491c30e6ed0e1061e50fa50f03d0cfca4413e958f9be84ceb053c9d795ff74c576f17a138b588fec8d32907730e7ae4e9b5b35d77bb6b654837dd6312ba8174fb45515195663ead9df2625f86db2d0943a756b7badd2303ba8ee9f5e7519404d42f5235a14c7951ea6c377c5f18638c2fbe574e4d7ac48684caf26c925f6ab30a68829c2fe6479ed0e011206e482273994a17df7be57c65f1e2a95473d63d2f45245e40263d932039d271a1c1a9a63995ec6cea330817d36c928d33082abb1f44d63a499228febf8e28c1b1a0aad0f393820f2acb16df231587ce7cc4a2441e52694eca9bbfebba2e772f770c32cfa3398f66eda85f2654a4f49b50f0fb3698430e3b2f8a761de9a949a54759b544ead07791408ff368945acca3b9a4dbb1d78d14f3fba02f16f5fbd130a876eee751c8419e8bf49bf744a222bd1c0a7d024e2f03534a2ba7e530596953be932b39ac7216ece327b24e2c9df6ef9c734e7b61d2eefb44973761929ce83ee64dee37794293586259ef4bbee8abe2c849b32f2d975095561a50f025b7716cf41c5dbe0f593da82a89f32371260f79eb31189974f6e0e93124199374fab35b6aed8cd1449536457da9515f7aad950aa41fbc76611c729164a45fdaa5f505b47ec9e8f2698ba3feeaf2a98a8a867995a65091d63ae794f35edcdd2899e69b7491eeede674b5cc8e5b5a39bd405cd8911294258194321d30c6b5be72cd1547dffcb552ea1ee87d580f6aad557c69dd43ad55722bd80faea84b2ae60ae4596bd53ed45aab94574a7b6bad1573f395c7273d37618e9382a5608e9382a5608e9382a5608cb96b6deebc8fcb1ccefdefb3f46ac115e47256e294c070c5e5acc429ad585cce4a9c124b63d64ab7ee2a94360461625c32b953ca1cf8859f4ce7e58eab326977c48814932454b4daeca3e2d09fa220f6e2efe1e1c11873d7525d67f8a5e4308ecd4cbaf047fe642d032f2caa6670420b2f3615d002072ad0820b951631f880164ac8e0420b2c1998fd792cd0d55aab0d5556600864271410b4e8741ef1d490a5d65aabb7fb08028106597ce9f4bb2b2a8c3ec6bc3461a5054659246591031b2cc001171dec6002287ae0850d515fab073d7e9de11a9468f3e707a9b3a7cf5a8d368a7d7c2f1ce8f42d8d396207bd7e7d9a3f206207a8664a29a5f2053f4851c1e40310566044a35f3aa5309d524a29a55b6237bdbe1c73b080a2d7267aa512a207343cf5200a219e7cb045af5fc32d5824f5faf5a9d3ff931faac0814b0e5774e8810b5aeda25729adefb25adafc41a76f5744bc68950d5039bd806a6a063360f10414aada155540c1022a8a3ceaced13c6533c595256caa74accba72b543528b72344f08315c040bfba7c3a62895815475451938123ba4802064850bc76974f5880609a33533a73753ad07494407ffc309ef41c42ce588f6d7ad26ccacf44168b5fac33169f4797cb8a7324f33ef4fee3f6e43c5bd2c02d69af8f83dcce38dcf3a8cea6d8bdcdf36d968cb1c57e37b88d264ddac00fce12f0676a027ecda0ef54d43cca1c1715a1b3b9da9f8c9138f8c10d9338f8e70ea1739b46af5b86d93da9833fcf1dfc9fb411823481fb1c8a833f9a4345cc7134497a3ec779268d153dcea328dca3e01d4da423d247569cfa1faceb8e261295cd747c85ce641254d88a2ae2389b3ac6f825ee3297452ac338ac50b70b74fd31eb26cf0acf7cc5d4f4c8faa80fc723f74bd7ca43651247776225c759fcd5bd94ff5adbf5f3b0a40f169befef260dd37aeff1f6fec31f66b1581eeb5b5e4b8af72ccdda7abb90d02f2adeef46497b8f7f9c50f07e918af7c30fe8d57b7f04c9d7c5d6f1b75aacff58fc07cd7a182ab2f808f6d6687b8b8f31afffa13304b295d0d2c7f5d3f534fcc13de62eee8710e87b560af45399d74d59571dc6a3cffe43c13dce0e7ee0ffd4ef827877add66be9237b8bebd67e8d40b77ed4bd25adf4091f7f320cc2df7ad686015b16ccb3382c88f5def770f13166c4ff80d959af6b6bb3feb5fafeebe49c751572706f4fc3f017e9dc86611ea4a8cb4fbbe80c09c5b97febccd2303f42c5cbd3af9e9e9197a41e42972ff801959e5b20a099a2614002d68781fbc961e0fe52259dfb8aedd8753ee60a83fdfbbcceb9333ae9f5e5dc19232083943af549af3f763d3fe6fee356af5930cd79d0aec3d73d3332857924158b92435f87acad821620289e3aa60ed9c11e86e1cbcd9574c8c3672dc1bcddb055ddb015e7d1bfc9b296c567af2ba017d75494303ad0e07f307cf5df86b17e76d67f1bc67275a1bfd0065d1ffc51f7186a0cf58b2fbafd3ecb3aeb4ab64ea0412e3b3bf2c02fb9fc5e127a941daff62737f153fcb01ff361964b9aed32515e4b853cf8e40dedb22e71f3e5bb6237a95ea429f42c7f85cdbf7d520965e98cd2e47f34e471bb05b1ad53fa987fbe9db7c9222541822e6f49f4d0c7aee33e1d20672e7944fad8f49c4e5f89f4997ccca9a1d31b0b743ac6be497da840c56f81407f9f414024496cd0f9b95d548406fc717ed1dc46ba9f1dff995f848ad48891d14851119e3a6652877ede78eecc9f61d8c4cd3a7dda43651864e7cefcccf1dce9f2a5dfe8f2a98b537e1f54a441a86cf22054443277e81f9105e124d09e7704c9d4213bfd514997bb4302f6ef3f6f2f85ffed5781cec20f77118a436df75167b68ba2919af076ce1f8d921677ac303f052a9b1c3481e67ecc3d3f3f3d3d477e7e7e7a7e6639cb6c2167ceac2b9060146857922463922347b86b593cb090eebd5f9fe64f8a765db121aa4b27babcb2011488935fa12db5b61e759d940a4d3cb0a18f720a890755fa28bd40d94ac516e8711ec9db7c2ace2bf4f8485a7cf266a418638ee3400eeb3cefcb9734f943b897efe40e999f3f7327f227875dce632aa145ccda3c6292848a98f3a21a2448c5a90f8343ab46a1c7dc6f95562bbe982ba8a575ce0f9f68a874ec986a7a5422443402000000c315000020100e88044271388e645108d17b14000f7c9040705419cac24912c4208a821432c6180200000818205343334312042af0a1262a12fb6497af725470e5d9185a1eb61a02e46a01e8cfa01fb0e90d0470ef7f7336fdcbcb7f24aa596e3950070100d3f5d70685865e660afe0109cbd5eb10885366611685226fbc3b1ca0224fb9a6ab2f850dbd3c8d1a57d786fe525b750118379c008f87f05499eccf1b40318da3a8410a2494836b708875e2c3e65a88a51c6c801f61f21f68a1d35dcbee2f0a80a1a7070e994bc5c128d776026d670609a29e13a37ffd1320f89c0706ff57c8431e53199490cc204d0b00eee3cabcf304c84ca0b32fd1f484db498c42b1454f5da3fbd0ffeb64337769f14eee1aa25940db0892ae49a9c63c0b47cca6964ba9c723b30153aad247e6103c400b702f58eedec60b3eb72f3b0bc96ed017d2cec7748fa043c376a477eb495349c5a6b256f2140f2a14ca447b48bdc2d73cb24a449ace270575d984d201b14e5bb45594e50b3fadc144ef42f4c9288c89de6393700a5355d49532dceedf92cb7203f515ce89ff321852e8e0ea7e91fad10f0a729d38f929ee1c0b8c160c112fec9bb9fd3ca8cf35d3a76880166731852f5313e406aed98b2b0f82c05afc585b5cdf408e8e2a1a87239e1714787fd4d6c7a42da8ac5bee122d6583d30e7f04bfaf8e8a023fe3c62a85bf8be9698ffee5946349ad90cc180ce43be28b7a6dd4604c2fcd2aa05b3d9a8cacc3a7d4a8310479f970c8a42c7d9581ce6a44129bbf5c9d9b520cb23e13ca346c61f470becf842b5f80304930d889fbabf8b139cb0be8c7c1913188d002c1223c75ea1c9cfacd6df3c035ab9cf1abdb8c15dcf79a9e546674314c0175a957f2571848754de8808d5f646946d38627b9750d08423f29e198ac6a56271d205db33d72c7fbd151b9c73260d4081b2850d89f853cda0bf22ce065f242d92dadd97adbe7dcba6e22b54b8f41f9f8326e2cdcc5a92fbef6df11bca25061d4cad102c704b43094d707f93c6c4f6c7391046e286e15870a19d1eb2c900d00e23e426024051f00af9a104a20e5d79f9760b728cd1d5385d0fb0c49146a2beb114b736b9e27b0996da5c090d91cfb7b37db361b424033757afda4df4788b801e33f512111aa3c7a3af1cac5daaef5dcc3857448a4b58c9e1ee502a7c17e4b8100fb427e2206603c9c391f8e6974358bb3301ce58b21046c3922b7233719afe85789a778a4610bae94476585320b15877192fb33db606b429600b0583f5215f53b4b4bc85919df3784964e2fe6f113fa5ca94068fc17b30a5d95c2d4a5764acc29c87a4a0847fdc59783a5fd08d0a06ff3b523143c733144d094ed92046f76a900db2ea04b3ed9d086648d6b1ab092232eac0cd6c8d3365c1127486cf73af4d2c645209dac4d37e377c26ec0a2f5ad16fc0e22aa92c87d519f96d59b905d17992f57533284367aa5b50d6439b9e91c4302beb447a4f529b1045b506478edd5afc9d3f0e63385348ed1a75a302c8a07bd8e6447eceadc5556b7b3bbb9cb4d6190d0ad4a913b3dcb1121dc12cca1efb41a2a1417af324f38d7ff78cd1855e4403af4f9641e004d2b285a3e4e38daeda64a1398e202c02a9ae4565a6ae2c37d7ab82b85aa80e9443a05c8f77147cf29fdf53020124d7071c0848cabe11a27340a2d57391f48b6c6d578a0092d1ab99b74530ea8901911dec678b7c4f850d02120dc5efbf18fde33fe8e7ecf1e90875ff365a70a6a332aafe9c252a761e169734f0cb94b14a4d57b7b70240aa212b8e91c51d0497b3e9d3ba0ca199267641d8a20412c9a8d63948e82a2c45d9eef02a2121a02be591f310fc9c5f2d5bc88251c9da0c175b7a25637fa26b29d1ec7375cc64c5167aeb05746fb54262be22db84fe2c17fd4ed58772ad7147cd763965b62253ec014484462f26b931f7513d1e0b5d14d0c1263e0c8093e96747a679b585dec64fdb72b8445c2fa40e9776ceca693c8e9e37bb6b38da6f775ff1d4d92643038ebb675c86578aa4d1c9006ff215a53fd5571ccd2a1792bf0c5a501546f4be6d325002c56780dbb0309ff47e09daefc730ef66cac1f36b1bbf6a86fa739a42d4f5c3cf344c0cf22631e0c8a020b76bdade0c2c92ab895a179e69f1920fb063105503a1f2f5dc1c705ae424127426201ca259ccc8d7fdc68b1807e0afe31a9b1806ec207b0d1887cb1e280e7a5a86f8a5b3cb42f9fc8bd925314c7b37c9f84f79b1adfc739fd5bdc09ab66c3ac1509c9a45f7778b8991935fb2a3501da98e63ea665e6df0fbe27f72339e63ed254a72602aeac252c9cbe5c03e5a69e43ce0d7f1e8af5a5ad7c4a374c9a7643fb1f97aa354a67cd199554a0e45b187668830ad869f3cf8e212ecab0c611dc91af265a256783593e0b7cfb0879de8e8ccb28e3c7c1d7ec90a00423a1ef1a5d6347e2d67cf5cc96cd34f805a2c7152ad168fe8bf316d0e05062cbd45592689e1da1b52b491fdf1a13d57a3e197990b5efe6dfcb560437e5b3542cab7e902f523f7857650cf4c6b0e16b60199f4384974541ce9daf1327ce8b088af9c16f53d9ecf3646b219c3c0cb17b8ebe00fadbdbb4e986fb28fa3fc599c8fddf4268f132aa4f7d64e11a3b41e98256f2039edb65374b4ecc0f7221307c6a853ea143d3ca020a610258b39bd3dfb92a631f80bd00ca6e663a26d771c35895f40b4659c4823aeba29377cfa763fbc1d7019daaf8b93f79486a87a6c59d9d3a5b80d8fff58e25618fdc36f00895e341e0f89fc7e839dafe60d739c7affa6014a085b3fffb04f4b8da0f5b20267f5142b5ae2f0c92ad584e006a101b60c146046f96ed79e961f0106a04514f00612597ee300bf2430e0e0868fa8687eb6bdc47ec9e2f3f5a8f518042b1f7e7bbba7f6c949cfa100e49355bccc868fe71c0f1e80307cd81dd56f157315fe6e8b9f52a9e41f833612221cbf8f17c6fadda3261e5d07cbc01fb312c771eef811bbea7048a518fee7bfde6f2cfbd1e5761ccf4faaf392cb4fbe0ed17319707d933a6e4966b3081493ade0c822ce9a1f22cd92b45572eafb74abde7d1c7d232a549e483599c75410b9afdc431a0e95b2741499c1df2f7e1a4cbabd07081f9e1706951b9eab497d37c8d4c52bb31e4e739bc5bac084cc4a0c242b917527dca4409f8799a51bf2d7528e237cfbd327bb12a8a73bcf10594c78b0f01a296668cc3b0a7b932e3bac945e91e524a0b65c6e7152c58d4ad9e7453e85728175bf6e3928adb79f4abf69e00d9f95f04ac3e999dcb961217e7e844b5b08cd4eb298d511811dd0f10378f80d8c17e72109744121fb5705370238c38dc918a60fa0c4b68bb8e680b4b867823b74b486ba3939ba663f00bbc2508be3dd2cb348205a2f38bdc28b5ab24917f7fc3095add02775d302dda9c1dfa15336d1c7f4cb4f7c9d8b88cb85ab9a4684787cede17d926da7b7ac16aa6b2e813fff233c6781570a49ff02b09af111dc97bf5a1bcc69f1ac7a522ed21a76448632f93ef1e27001062b77b800f765837ee371bfeb1cd70548777e9c283ad5d5b5c5bc28eb1bdd60681b79daceef3a5c3f5b6db8da49592ebee77b3a0891e2b0e5e3e66b53e73e3e88b6aa38a12deabc7393a24363cbe00e54e9afa90232614c2a2257312d2ecee41f140b4d66c3a72f91228c10efa08c3826fc6b9e873ff6ea9316cc00cbd808320fabc51215a4ca59e735abbaac028e3e3609c9a2262ff92b4997dcd103327c90d0f9309f3fac783dfbe3eee0dbca1c3886b088bca75694cdd597be69b98f9011237a8594914ca47a37387de65906f12335dbbcc322feb14163a3d7acbd0d58e7684b71557345f3ef8a03d3ef249e57b35ecb2edfb1070e956441bb3b01c4940d2a9aa5c3fca80471ce3dc50f9e2735cabeef1901038484b0c9281781406f81e65f7037962691ee7038568da1bb98f83ed7528119da91b0502c83b1393d1af165a00604720807b446f8062488e4b6f3c7abdb498d7fb9f9f3daf9a71afab09e4f9f25ea81de07fbb5a77f0ebb92cef59eb6e709a3af46738bc8637b78fc75cac372f3883425781b3e77cca1ff4d567a503c5c1c4b7a5e98a41fb92b8719892b403e4f9731fd67e3c83b34bf5f0858e8695b36caf243f09242a86d64662f738c4e0aa1cb5ea38734f12946df7e6ef2b86f3a2c8365c4c09aad3ed5e1d54f6f51c8a15d6fa342d723141d62a699f83d2729942b092ae7c18af13dba40ab382079f8c5c8f5fbc993550a8725abae055a8bd07e3b29f7f031d21dba2ba45e8e07411048ef11d64cb9ff7ade4d0cd5f630f689140ddb79267bd741dbd2f244d15cfb6b0afb476a830ead6d46a7957cc0c2f11c50f159ba9d147ee84d149af63133e8ea1ce84ce9e5661c6a3f7637a862db7125207662cd23721fcdf3e58677cb0c5120acfaac3012129fc404ed82b002370751ece72941dbee95e298e95e007a5bfacc2cac6e3dfe91880e22a7646b08c38bef8142763eb6719135c9b5d2ced50b83ef05a7d30c7744dc140cadb6a3b82c26717399498a061c60ff96580209b76a7ee1b4da6efe801f3800d31668c9ebb37a9ba76e63bdc17f632cefaf8263566e7dc98498fd1ee674df485c72647bf963d60322ec9bf34c994e608f8032b1176f3770c26696f772d56be28a74b1e30106832f5b3438477a1496ee1a7f066b35a2c03d6e63a4c475ca494412a8a95faffcfddc6084b7ddb16e820027c337a2dd3825c40deb43f2668cd69930eca1718dc92efcf9fda1791def389dd3029973351e92de808ba514d6a9094f349a6ac2a970514c676fb3084d491cc45bb95a6e1a0c15264142476883204f6d3b9456a30a386e2e9c68f321f50357ce54cfd9aa8a30689ed4296cbda1efc44b1237455af5b6f32c3a12094eb06d9e2cfb97a0518529e89b769570f7224add5194cf0cce3ab66a3f11692e9ba593ab7488c8c7a3710f746734202ebd86250f58a42192d2d30067451eaba90f7503801c784fe6e3f07a6d5e6eb58130cca2182e77a65a41be8681c2c9f09d17e9114e820c75b74b022bf536c30552b3cb79298da81e27b194398b46f4bd9aef3bcee77e7cca7d044f417216174bf42b0e47a5aa92b48902e6e9d5c8ae2a85919568e28e104f66aea1d3e0e0440222ca651432866e033ebea0e1af90bf128c97cf045ff57ae7f8192c0189978c561d452091a0f111480688c311ec2dfa2d790ec3ed0bd0b3fce2f2c93d96a963255ed54313d37f486f7bf6be3e84382f157981610e07e827048863d028788178baf150b4182593117d7986a7db0f222805aaa775932805c8cfbe685802776053ffcfad892a6f157a84a7a5d9d87da08f8a81d351e523c9acc996441c1d708dc218cd5d944e0b05c5d77ae0d790f66e51556c8ce2141ea6a1d11c0eeb29efe4b7ce1aa4f238ece789f473c7ea424f4428bc9f1946f6524485543cc4d645d3452374151c87513f21235c63bef1c3d6f3764bffac6c3ba045a5ad5824ff69a478d6067896d9ce8c2ccf096c376ba99f374f48a5c5016c85afbb239baed006c00b478b8afcf1a376e7bb1da20320577e9b5d94305ea10be9c124196c66c964aae95ce51d343d0e6c20036b03a939f161ff70d5561901acf81578a3bde143ce9223c0785b5046a3233647e2cc45fac8d7684ec9fe2cc4a3fab0dd5efce575c77e56c47bcc142f9e45bad683364dce83a110595f68d1605a4fd594e3764d85489c360603f1e91c2ab0222561671a8550620ff9504e8cfa813abbb1088260a4f83c55bdccb191431424b21c146f18e5e81672080474ae987adc2f485d16bf4de53d10ec00ad3a5f7c52d9370d6d8b23fbbc3c0f43505d42c470a27e37f6476e60687dac9a3f7eef53fa086f172d76734c79bc305fec14a55d09167a25873c676582d24c906d741e2f04c02557646b4f31dc54d8d9924d0991638d890800323d3ee5f2fb5dbf1aea94e340f07584e0f9ca50753f95312771f8a07a23c4ef26f807e42f90d78bf47bc2f30f4e49f17873deee999698f77ad48cbc2a5d313d12c6580cfdb71bd04573d9c0d6bced810e28024d7f60b3635194aee7a77f94a5805393039da139009c8c5e3b409bce5e4e94f86ee76b3eb557af54e5eb60507e01d78baecf2f902fc6a2b71e0bed3b064de28fb1efd30d6ae1f3b0fb84f18302d74ccb4f1855fa1667f501ed04d049cfbd4862850e082addd7ae2423418aafaee42ab30c07f089e70a332fea6a9ee94af330b079177c115f199cd6ad32c1c85c08c9607a00093def4f521d31ec69a9093be5a37291b1a4a98962c12042603a1a713c2475ab2202ca0009f69f3d16a1319f3e58c77fb98656de0fc9c2e18ff5d327e97212d756a2405944a87f93907048d18f15db062f1131a1a69fbcfa65ec23a909dadd0fecf619b0bb018f3318371da8f8e202366e8b67ec70faae942690f0119ddd241d670f57a7040b91ea1b86653d03106905d91e247d9673b60dc95d497c29ab74659880105891dec3fee5e9cbdbd209d5f81c89e7522a14d6a16c2b4e3a91f0d01999832b7924969d91ae46957d7eda25cb0da11644b45b0b09df5c0be7f3ddc474c2a7b120f7ddf94dec093fa87ce23ffa45c7b5a9391b511223f0573572828ee9d388559ddece78d7c6a96a991fe9f5be165b3df9942fd79936965b57fdbafa2ce65e16bec33d4781ea7a69ba7105b6f45eddc23778cc2567a167dddd1921027712835e74d09199be85a3a96cc0d7029a31f6fc6f7828a3e5d8496eea512c6fdec2da5b755d371ad76508e19165c36ac0b82c3d550acf9b4825b7c4bfd784964d4e1e2f3a908e087b4366accba11eb8baa916554b1e862c389da88a2f353645d0f99a7a149f2ee7b24af2137740fbc81a8a2dfb9f9b87a2a135f4bc6a9f74a9200b7a3a5350cfdd8f584b5b2a0c1c0243fbc45e9a092b0dc985876633374ac368a0137b50053d859c5fa5c6b7540e87056647d580c798bbbae7ea07821b453c694e82729d133bbb7b0da9da5a0b679950cbdf8431c4e162a55c7f3a45f7ea3b58a1d639b3826d11796ac41d7c83584f25fdcaa2af933c4cb00aab2e682b74c6fd8d5ce914416740442aecaf09184d1db1f10a1715c849a52ad08c1f4be9e0dda5529c66c01211c5f7bc1c9cc3776974f1b81a2901bd4f6bf94ed2ca17e0103d1ed5610185b40b5f49ceddc569e0af6736fa550f6b643b6be79a78e208a309aa34072a1056dbde9393c2ae3adda0899e78e983bb3ee7694b15c404ca77adfde709daa5f0e5dd0e003cfc9dca1229c72cbb11647d1f9c84abc77625a32951143a27e28a796f1489df776dbc8bf23dd8544d9a320f4d2dd62ac6e9df6568476371e85a7e55345ca0371e187172afd1c091a71325ae72ff9e0f2d87417b86f637d423cb1004be6016bf860babdf3990648c04914d0842ff7c6eac7c2b7338d30734225cda8852f20f58e03cae39b982e98255082e75ba3312341d41360ef56b92413f792b164d3a1770622934a26c8e1723e98045a5e0f0cc2ccc41d5c9d69693d126a823f54beea87db18273cc2819774522a4dc150852c6b855eb5212cae530d0999c18a5131925c2f54426f1bcf60baa99a4e93d020cc55921e2651ced4f7b3fb783492cd25f2ca47ab199288cfc17d7131367d64ba03023f13e978cec380ff087eaade0279538d91afc5a7acbc0eb57c08e135d4d66a9f32da24353c5443f7a5b2b3d32be6db96f053e34014cde144a71aa4d5b02b20bfcf14a409151fb89a21d953633582c1c617f09393f5a6b22a60c64b360b28fdd78997fdee6355e841ee518ec9245efb6715b8070596982ae0a6ac1650607a00b12a20af58027e2b993e4b12801b13aa6151d4251e2772cb3ba0445c1709282221ff01bcc93a47fff2fbd25c00b04e210bc2965f5864a146a757ed91bf28f21e06affc3a03c60e276ac3a79da44efb1ec94cf5e52bf6202707d46220dcebb816401366abe92ebdbb21048ccfcd210f4f073e3c6e189fe521a1fe4f5e13a3e0696df30ff6ab01324aa58a7072026d3662cb5615ed732b9225b18dbabe52fdd2a3ccd880ba97b51b53b1049eadbf93e186a5ec19f7a77dac125f31d6f6f975384c38159babd998ad81e183f3bf0e4327f0f670244e0534bed9cc049b93d5e9345e8389fa87b488c00ceee5b994007cf0374e5a1206a8ecc6aab0c677c69ce3d9420838e06ba74b536e90df4a6b4cf3a74c2844bb6707b1a46595e89d9913d1a8b1591777d5939a944c9d35a51e116e4dc652578ea5613a3d56c1b8b5ca58dfdadb64ac92bac91043004f73875668c111a69b7e13ba16ca79437cecc280ce663e23549b5a373dda7633a84afbc94483ac5b632a1fd7bbfad81a7a824ce57a2c5f930d28dd5d128a3eba35a510e0ba16cf3cf6681820e761a9eda484b4b0cd68b295a399b4b23ef593cd710ce363410915e8e1d908b8004221b2b941248bc4709ee0f9a84357ccb022906aa64e32b1b274ab53a61661ad0d706ea2b329b06641ff4d7c2a59075cb081e6bfd79b146039039f9166d981c8cd160cbb00ee0a9c6bc79be670dce06a4a90bfe2cc70b88a3ec73b44d30d5029a17755503c0ad221a1ba10d1803c89da4ee8a354b94dcd0cd0c7a80630a9dbd61e96bb7b0bee217cf62482b9384657f6f35de5bb848f5c985cdff94eaf285bf638e148c2991ee2b07af2305a580b15c816a7f6c42a85085243ba2ef503315581bdf4ac195957c09bd27a1b0a52abaf61ec4d77d4a2428056377927be78ad1ad9df219d340df2d6cdf8cea2f6bc210fbd108fe5a0eae6ae7e0c8014dc146faf5fc8acb102b96fe0a29386ff3030f5e4b747db4f70ac6f6da779e5142048ec227f67310e7cf661c5ce1800dc76d6f9d8274ba787fd6920f68bba706b24afd754ba5e784c759d4a2c8c90e85a5866901e4d050ae6c66e91004f635be94a7c650b7fcca6f47e2fa2726608f7c52398ab47a9cf06ace126a2475e81ebf9ce0f3d2a780878813d34b2f0494c33802a529871451ffa55ad4229cdab7b06b8655b73e2fe873b6026fd3310892e7583c4a3dbe5f9c61810234bca70fa6d0cb809b99eae5074d828a0726cce2675d47e081b6ed59effbac43abe735f224175ff9da91fae73dfe946cdfef4a459802b744d8a20dc3b04fa3fa98feed179cef58c83050ddd1bbfcbecf4e6aa28b2cb8a944592296b2dfd7d490d6d28a2c311eded8b64de57438c06abffaa9ae48f767e9dce942a9579e844bd51adae441788199934f887f9fd646233111f12d529f842f4540b9244ea4fb09559d845e05c3dcc8f9c69e81c792218ddda7acde6f47a549522175f8f5c444caa4a6cc68edb40fc362a34a508bd42c1671bba8f76a74a78e7a751a6d93239ad9c0a8db1be7f766d99c6e028e8cf9ec99bcb725a520649d7f87b32a125343af25502d1a2790b0379e78f624c9f2815a0af17f5cbc19043da0e0686140f116da8a74ae23ade2f5544a5ddcca893ba0c8fe7d94cb083128c68962fef707d609f158c5e5f0d1cba3442c5c31cdd489799d43f4507458d3e8d8d9d25044d229dae1648b7e24e133ee729aa2233bc13e53a17b4b416572c4a269f188fb0186cfb629446bdcd1bb4d5c25e92bb833c2f535e3eabc82bb54c3ffc8d7918f501b984004582df1594ce3a7d8944cfd320803d0ef5626110a06fa9d0c0d412ed24926f82a60025da1b2443682396253780f86a6efccb8c8d6260d3d0a937c6841f69d94e401ee68ca2f600b8e3833c86c0ec5407ccda19b8ec0080155a95d1680295ca47dd0f225ffa62c21cedf87c44222a2c387a03960f85e11e41d3ed5973757c5787c3f61f82ec9a79aae6d2d9b41911d569fd6ecc2caea79709585cf44b9a67263c067babcaa18e40bb3f909667ef3ad96e4e3a5bfc295ddba11eaf0e6cd7e067cf63c62a846fb12a95fe6e5521553f24ade8860bc1646358ccc345405c10a83f28420e7641694e752fb2924d9b4fcb16ef3447a740e462c39e17ede09d381b9accaf9ac192f3296da86a1db7fad4139dd41d8d97522c1ac328ef1f88e9e18555a8838adff08d89e8681c1e54fbc750c0e950a0a1724be114d7834c31047399ea5f2e5b306ce720ed6ba2be4eeb393e4fc7facb2558c317ed25c4d7f68e121927bdc2c723192875d416be4b373734fd463a122e3d32d1d4c3f6498bb2003f2a28c5ee4d9799ab1782c56bd81eed589c89a7f03d002613c8a9f50d7412434d08c200ebdaf5df1059786e493c281d0d9c9197949cd29d7d12d1daeec160ed3c171fed5b92acb586ea06955bb666ca7aa0f4178d7607b7a61f557e567efa5fbe04d933bb8fe7ea1e62b4a3f79a32faced7026b0477b818084af97ba082d94bd867f407efc0838887e5fbe78df84f440d79175187dd8eb6f759abdb633a4d0f4a91229914fc3c4ed16fac1cf2244f43e5e91aabfb78e69fc56c865c91cf2ac2e0a3dc6fdcd10b464b87b2d772aa5308df4b94d07bb50aadba8fe8b7fc78b2dcfc537334d1846eae0e6f6e39a987da076bc145012b7942812fadde6d509848b8387d0b0ccdbdb594c3f0ed122f6c61e86272679df6d6f7c25ffe4799f158e1cde0c862996235cc338f40ecf0be683373321705679c846bc4a2a875da499f8c9ca57f4afb89d5a89343aabb4805d24c72e510453f2f7ed3ffd64468d03b83ecafcbee0298fce55215ca0fc1eb01d3c754613c8b06541e49dbb18e6aa15fa98b215284278c5be07b753f266c1670bef8a47b464ad0a6e3cb14e12d96652213976802a852b0ec2ae7cbe3950a12e03907503e3d732e4834c5e13044dc4f309891a919f94ff825085b03f57358d423a6ff7325cdf1360aa60186baf2abb0c14e3bd57f875d16b50dad1adba30fd40a8293873ce29ecc7450d28e5634b935745ea59421389c0966ea21e8ad401cf03a48ce76c429faacb1b0f1b1b6a3edce9d9783951510d0037fec728f6d4a667cc8aa8db31bb6fc2e747f2d6e2a95b513c4fa86b0789eb830fb7ff30d54681e5cb04e694eace024e18d69e31b0d1872bcad68f8b41d387c3644a9dd8c5de433521bdf40739f591a895513d1e2c9447d1165e28c62afedc414b206bc12eb635fa7f0a8148d4fa1d06be64ab88f4b06b7ce0abec27738d30dfea8682002548584dcdad8869a4400f053249de6e844054e3c9f914b115bf2831bae4a44c09f87ed9d492e561f0aca33a15c4d629a0fa41e4616ee5724d1d0061e06b3ee3afd025574ffd11bd7b1307221d0c2409d12a3751b4abb41bd6bf8196b6e5c9f42c80055b7737b0b7de2a74b660af66fe592fcf01cb322ca6fefb0511d280e7e3d6347a44caa3c334a849b822bbfbb60ce6aa328fac02daba5a2dc0fb284095115549bf468e8769b570bdf0d43ddffc3ddbb05d2cf24b0a1d5b5765aa4525444e672e17c64d616bd9d8efae34bd407a405247ca2501492bc53b84058b875d9074b76870318ff936e4953764b738ed4554e16ec35aea1fe09880fd8100e2f824743ce8d86208142e06355a3fcc2e0f4479d7d936aecc8394aeac5864cb88650b2f5ba1041bef504182ea96594a792a8582e04248934bbd16082716ac9d039689e39574886e87f4744addfaf0ad3046a880828a46e42ebd7829568243b88ac75ae70c10d39815551aed74ef3350d62171deefc0d4367ca33173a9976cb7ef15647c8b023106847d8cbf8f645790bedeff1cbe6617b4ec0c0a2bbc736a35773a176193e306daf09e78603567a4ee5c319fe87123e8aee5346b31838677022437e50c48813968f416d52404aaad52b81e0e2afcdb811face271db0a2bb18d821a191e95d20b418c8a4221860947f399377ebe2c2f4e6c316fa2dc503b61c2f382421bd273356cc4523803a0c29e7976de3b0d5bc18a25f727b2f88a89de19494c11cb1dd241d343b64ca338816ee7fe8a8700077a8db4b6cdc4c01e6fd3353a3c470cb9865c11da74928b1a06184b4d2da8d8be651278e22a8b369eaf5e1d38bc9fef45d16dd324a8a58d52cb466d8c55802427bc003540478e727939ef0fce2e3a25bcdd06849919929385b50e558b41f5d2bc73d9f0ec3c692e4edb1bc5d382858d242f5258cd676ebbb36d801796dca8d36b75de0c0b661076adddc075f9c9468878daaa9574dbfc838a401ac7f6e618ddf03323745e68ec73343eef68e90bdfedfd2b06a2f105f0ed9d9306f1f2ab9389f9e29eacae056a7246a099a6f71b9e30bf4108727644bb44a8315e019dfd8570f92614157a6a03ebea0d649380d94678cdf2192089822b26c3d09446747d3f262b3d4e65892df2ce1d01525de31639d7db0ee221029c120b47e36d3d10ec4a99d5b17f3e543cce4acb54090740d0a8d5d79bc4cd5b49f853c4727dc4a734e466d4764d88e68a347b4b5695136505ae40b20124bfe8910b5394aa66b6482f86fd2ee3fe2f7b19aab8d5a58549a1c6162d8910729c3ab8a0f3018ba061831af82484709e0f932234718239842a085325fbdf14a0a80bdf749ee8a34ffb06696362b5ad1feeb378f2d84f3f6e1ffd8685e2073846c639d333c9fca1ff91ccf84ca0614b0afea1558d214e07296c2a2325ec91ae3b2e0fad4af9733900206104c022fc78d989404fac17c54fc2b5d36947e29038f6e511a4aaa7a2c0356e3a6008fec8a561f4297596f712fb54ac94b7a216bb956086cb9731f87d23efcbd40ca1e04fa6a637fc550a4910d1e2fb1fb218a332425812cb3c8a5515b3418770a04473cc1dc16c38df2bc94e7f2e78ba8017983db6db417142a48c7c27c0a5f82ac34a5190e69a76af47e0d54dfaf46ef7a71d144219e14255551b3552e0b83b310ae59877f2a8fc1348a9ddf165ddf2063b726a8b9a73299e400db166cf32e2d2e12a7a57973f2addef80b5d3225ea0a75b26e5b103353d54505a881a312a264d0cc36f4d8eb6d0c90ba8a91cc7e335748db4450d350a46f2544cad33078c45c73934b5a6973d6307b239e6fd36cb7d9c55846a5ff2051d79bf3922dfb26c44a43a4105b3aed619a6fcbad0c84d65c806d0be5ed7bb90d29d0458e026cf25d0e08b6205584fca0db106b50ea4015fa811240ef7d3778c7c5f3b3f7074405e258827554ae388558060b0f92590bcf6cacd693fab6a382dcf085f7b19d52694af26506a64d63e9bf815bb4a07198a9b8a3944d2a2307d4dc8e425699216d99355376982fdc1e316ebbaf422d8baa359d0bb775d56d5f520e8241dae140176972b28486e041f708ca0cdb0aaa3405125b8374b62e5d073152d63e73e82f014de5825cb2e618ac4051e662a0dbd5cc5bce702c3105593337bd4d13671a54f194349560552c85655adc34b9261b7ea3052b63100c0773b738fa42e8a9a61e9ac4db9b4e187c081fdd949ae1834f62d54cfadceac2df2aa70476bf095c907c4e7175f8d65d1513a96a428db70c4097dfa950941b9d3a338d423ee07fba031842b9cae426926b5562d72221ea0ec30da23f08ee83fe45a686b8ada3e0ced43dfe0901d2d16be082d0327226c8bc09febe9551f98ec7d091a06584484dcca2b8c44ad78b53d25d9c11d8f8e2e6c802942aee57c16de3e42c47ab24f4883a26ec214bc35f44fb32e570f4f706151303c3dc51b45433854d82db5a382c2dde05afab9db33182b0d84c342dc2ea9798427d34ef24f4228d79b2e1f3a2abbb81efe530bd934f562f118c842166d9bc9bb5acfa2998c30369f3a0ab07a29d40f3d059b6b863ab70b61cef7cd98dca1523d79ddc4ee6aaab302de008908ab0f42aad165ea81cfb43f7aba00850dbd8b2d1899ac310dbcd070d2181996f64a3b321183f95b2c862befe5e6aaf96f401f5b4835e30196a93522bc9dbb9aa084d4bf782d5f26648d6ffce53983599fa61394b24f06869a92777b08200a966f249243c23adc70104f26f6d54b3d364871185ab181a12e6fd43082ad0d89e24d790f7b417199d71695b310aaa7a13e67c7382415f93c17f5bc4c081f49dfb3a022fa52f233470105ef91aaae4007d2d65c42c79ccc79279c51411a8cc24934e9563bb6032a68401791299c9d8334581e5a1d1df0520e0301dd7bce819379249ee60b05604b9b20552af0271d4461c03ef46c6216b69ae9ef8aacaa009d2065ebc96397527947c1b9d8293ad4c35b22a78d552f8f7be200c04069e81761609cdcec4b03179795ab372d6aec0189887cf0100b17159e689dda9416ecaeb2d145fbeb125068c2024ce15ec9917a7ed88e4eaf89f021b4e42287e92d45d00ab3b166249396f8220e75c75473f1884ef818e6e9dba02303212e6daeacd5e459392aada4939d51345761e6827868b8ba1453c4c2e0cd593417ade4113195bb575dcae6363f2f1633086f64cfa498a86c21ef571a440322d319ab4805189cdb532071c601d9fbfc8e9ba86f4a1c9efad2f81a411f09e4a3e48548bc43c789d9e009c6b28998a1027ec5c4717843066c9afe18bebbe20b232af6a655eca1d984ead217d94f9884f03563eaaac2367ef80cbfe033b3a72eeb2737b2ea84d9f7560899c49e0ef18ac9c210c7851e08ffa175ee49d111d0c41670a32e169352989ee7f74c995db970206a09baf746bc3e495d5579da31bff7bc4fe27b61bd7ad08966cee6827b717a0a35f63efa3a7ea0e99053cc253d50d359160973ef869569eb8d68259539981242f401386c08908f997fe78e63ef0c69ef69d3c9a923a4886680d8d7947a7432d88ce4c6a6dc06012e9604d02853ee8670ccb4a84c901521693f5ac5db38c1b2843270862499e632b6f6b1cecdd5860a27d6cdb882522dcbc227d9510b27206b26fe12755077e58a102ef47a1e1d0aece2a0f5e6cb8c8042225aaa2435c84fe9800bbfb73bbcf15a412f5c36ad1d6d17a0206c7fdef589a4a0acb953f4b2d5eaf3a14fe03713ca4903f544cf0864a4dfb938b855511199769795a28a91038374938589bc13f575b4e41184dafc6ea97a817641a778017039485e8194410abb1d07bc4e61175d0628234520abcbd4389139653ce8bf12a91b674261915c62d504d1de5a2511d42cf7c17271ed6cc5e50854fbabdfba8739f3632eb6c0502081eb4634bc0930967c682472162139bdb324cda906ee086ecce1bd2cbfc6be0b424657b73df3c9c301c83ba747be15c46b2154faf06ec3c90f2dea7959266dc5adbb17942ea1131010178318d6dd53a6cacf531eb9139c5042178b289a3100c0e6f89a80e456ea0975fa4caa36d4ecfb353f9c7fe355a844001a253325f40f2dac2fd5715951a235d482f32673e913e4ac3dd4d34885bc8d87f1ca74d9f605aafbddfe1063826f04c72b6a36677844d6f3c9a8474e178bf5f79259d412690c0a602343ecff9408a1a6c9274042418d17960a81639db93bd6ecd7843d69029ac2091ce5510759e2ce83c7b1a665295979d77b1b4732eaef89c4a4d233cf61c7c554c533dca53acb0f8b7b478c95beffc8c93ebeadc708cb686fd807cfe1cc1b1ff0260bc38c0ac00b8fa80ef391881a6d50bf5e3c684bc754282a4bac192043930fc782461a6731e1baace6564b4bf0909b577bed704ae8453c1c64ac63d3e0f0de8a901b14743ec432961340c9d35139d070c422822ed48e776e4bf418a191fcb9cbc7043b6e5407cb9623ec3cd4a02e4562025917aca22f219662c7d78a40290495149e2435f02133a4f211117fd3ff554e60875f4866bca6471e38479d4117fec0eaca34c40b587d8b6c4937c468d2a10003aaa2db1bc86d87652725bf98260f6c2ab31c3ff6d7cf3ce6e60170ef6c2f30c313ca5155c3cdfaceb62833f65bf3a62fc251b0e69bb2d0e92ce127f57afe8195eaf185a46272667d37a78ca73bfa69992c2e06e83b15e5a528866fc35882f3f4e1a8f0e3b2e7e54c51e6f5a9d6b882965efb648c1ee9967f1c66067ab5348c6f0ec98d4a147b29df04583710ae1848b58bd56c260cc1303b5da88373c3835ad7182babf503b3be2c8a86e97d385d667e6d3e154eebb740e2d27c37d338f36bf09f305bbfca1d0fa7f07458d1ce2d8ed5063402cbeb6197c55b694fc6b41133720cd7f978f71602a15b426cc091e2cd38a8e22c594c4390e0e5cd3bc16a6d55ed3f0741b5e0e21f09232b8a4615386df5f8eb0f6c7fc731f30d030c12c8fcac26cbf65b30a5762a5456549a98104be0a8dc511c6f98bbd93e9e3b2a40463256c842ed6e513d274d9616b1ec080a8a75881bce47376f4545bc796bc96e725e4556879756f63c31ce887b4e7c76b5ef692c01621e84fbfa8dd95e4f7c5938eef0097db918e030a533752e49383e10c1d2a3591a7dbcdbbce0afbbf26ffaa31ed0b326712f241297b45167792c8dc980965733c70e83fa02c744d03c0a9eacb955bbe6cf33e850e3c952db95c2ba44bb439570513f583f72139816f4ff8d07e3023b1fd229143424bae8073501e44ab983f5c916d1307a77b11fba9415a1a6bf15580cea121fb56cfdcb8acdb357dddf8631f8d7ebda3201a25ebfc1a56d8301482107412d970abb769d3e8f2eadbbd071f0eff081fa1127facb4a54dc68a28abcc2288560d009e386f8447b4ad1089955d44f3e0ea70358cf008b2d2a5b343e180dc960bbe7e497f889724c5b82e10013d5726b42abd8cc2557acad595c1bdf690b87717d0359dd85665f04217c5139b8f71dfd69bec10cb9ac86d8e297231103f4c4f4e31f312a1e0de815113fbae4746a5b25c6c305eac3b4870b91b07c15a86acb15a30d2cac563a2c1c1f54dca6e884de1eed927de68268a779b58bc3cf18b8a66dba5c69ec384f9ea7a566b5623c30e812e6cd75a2c8cb0c37def8590420d90179650c1448b4f4067c9fd7406906ac49277f59fc88e02e2f28f184bdc0cf83fca18b451153bb8d0b0697999f6b7e180b301234dc16d9c2041310974bf44c0b81ff0881ce8d2aecf5ce0134230557ce5e69833e6ae261bdbeab32aa21fe7f61be62c19fd5f9df7ef41a2eb5f3c28201f8ed72ed22f1122565139d85d187993b2f478ce7b37cedf046aaa2fe84c9167801036ee541527663b3f1a44d711b62c99e9922e339798914f68e5e9266e78d5c6bf1dc0c73309e771fcc8b4ab0097d772ad99a2ac6d6fcd7903bee0c3a3ffaf95bf95bbb29bd49afcc95e2a4477e67835e25ee1866b4f012e93e7db4637c409b7399cc60a70a9be1408de5c79ef17c45d4d587fc3b8c397b1bf03d717e0e0dbc72bccd98f3201b891079abceb4cd0d37d27255b96eb4360b277213ae554cddd84ed855e826d5fa473d467ddfaf5921a951fb18f9b300aff7ee24f9c8bf561269b9c119406db8ee7a6e3d874aed39480e156d150c50651599b27af1a89807708df0cc55393606b5884936899c2f7354112c721bf5e664d6ed43c8568cc6baa0dacb9bbb1e8349e199c56f5b805fd363ca17c1f90b8f23dc4c11973f419f02569769cd73c36bbd8a1c709e6c92a36328cd869ec8aa3d7d17f4e0a5d75bf44fc55d72e85559a67af37734a7a03178aa662c61d19e061646d4f4af7a9537db0f45af900618e7511bafb8805d5eb6095757f27e0bc3d9b3889bb2f73ef3116eba3e6408a9866dcabcfd783147a4b64909ef7f4c9998c5eb7e127fadb0fa331cee479351addd90e74039aa0c2c7aa3f1380a0e0dbdb73f4044af13673602a50b8e76b6792f559178499d6062aa63f40cb053a5b0c377bb9752c8a6db3725086dc8492a316d70279a5ace0ca9ab8c972a252a2e3fabb4110a797a823107bd7ca284ac354379da4ebaf5fa85f74712f1a4aa1a4271deb4bd3ead701e3e5bb3fdabc469d25fcc6cfcacb85023979f490713d3e4d9b34e1bcf0e18fb493ac33dae0f626873e844387f39697d8274a06d51374a39cf9c7967fce7cbcee76f7b272cdfe6c53c976a2aa7568c5d9dfe726ede8a8ee0cd2254e89da1b45f00136a79ce7bcb5ef0c023688bfb442e37c52cbd9177630cee6dcd12a596209a2d3b38c11861fc18d142c57fe191fffc2b8b8f5def62951d4192ab1be53545389f98accf8c7732cdfe6e55b11326964b403932e8b90732afad8217650bcc352cfb1110db635a1f4d1c6adeabef6df71cdfe18b60dd4cbf8c0784fe58d9ba7e78344fef5eaad4a3f4f935018db5e047ee1feacc56ff9d50fcf041a847735c321986ef2113bfa4596ba5e566bdf283ee55e2da2a013818b39f43cd13cae068de677c559502f96274bcd889c0692624d027500b3e8633a978263d78d5fecff8119354ec82c2d84369c3ae8351764b90edcea004e7bd7867ca1fded9a6a9377b50e6fad89726982fc75e5834caf8818cd6e6c6493b3fd61b27e142b326e0ac54cbf0a472f20147da4e24f1485390db21a622b871f62f1903f030aaccc320543a7c0d0a5542376dcd771ede090c433de52a0856871c0de7d438d6b636dc83bc4ca7d100709bf7655b7d48b47594912ada7bf1f755940f22f1ef6f362a7eab8576493b66afd276ad53d84c09b0cde0826caaf1663fea860ef437dec0b996f35c138799d3ce8f63851b1a97c5f4f978036ec0ac3fd15d15beebab8d7b5dcb975071650dda8d4db24756730dc4f1f52a13f5ce343e679dd835669153a28f60ad6eac20acab01062f4d210b12ba2cfe668822410d2c7fda5db8bfd707861bd9c389cd0df047cece78f6564bf671d59e978469465dab77a54a7c76e2d3509cb012571992192c0dfcb8b001906e14f21bcc60c9be6356801e6a7933afea78e24b0efed309a14047a5c80d656359f5a00d6faa0f33b29244ead69da8f09f0b4f323b697262d545dad86d6029965e8a47a8b617e7341d253566f12d6c304edc28a06310dcb6a4e75c37f3f05d94937bf318c46bfd833d0029408d323f431c73535f6f54e1ec50d0d88c1e61ddd5ca4f4c751faf21122ab0d9c81fc0e4c095fa8763371ce40fef52bcda44a77cfde35c0fdc8a42dc600e918b425385872e76b5e28bb7ff09c41a50abbe3fd4ef858c908779998f144e0ccaebbcc6644df1dae4803ae099a072d1928a481713a7a21c639924311e4a551376c11fc956152f0645df25d0530507959c6702a6cdf912c2f75f22ff80954f22cba126169eb5e216bfcca861008bb6673af8e7288c7605602799e8d7b08f8aa6a0f9bebf9ed8243ae268b0a599500116b98855f52b197f6abf6b097c59deffca4b5c64f0b7b99f77da971977dd54b8e8c348c658300e448af9799107a59a85a62d4df27ee98cd9b3da879d9e9d52d9ac878d2c3f2d2029226be0e03668f73a64f970e73fbc4f82e8b4474084d53abc53896e4bae2c0d68a8301f2b2b708bfdbc2a2eb9b2505e94c32c7e156cf0beb36a3089d7a840914411defeeda756d992980e9ae22f4f78d1e293d55f693acbcc04401775bb18293c36bbdcfac32582c5f8f814c349dc9d0bfcc9d4b88778179ffabba0cbb78429da2622d5683c75789d283692d27e9665bf103d12013545534bf891802290d74830aa2c95bf01651ad0f38e9be58a8e242d33049c1349e8fbf182a4b9e421581f841b3186ee876519f793c54155bb76c953418f3232e5af5cd7494d1ad3f4cb15808962040d0c5abae4c1009771319cb9b4cb406f62ac5024d21d83d5892d3abc59f723597825e258786d780c68a17eb66a3321fa78c0a36cde90597ae16281bc9b48568b6b5bb80c050ef91a7037c473a10b80a4249571734e2bc001650531baed096ea2d77bf865da08966886e8274a8d80b0cc9f5053a96e5490d6801d5178c9ce6c78b325d78caefd81b4974c1b056425eaa9ef3f01101a4897c361273a6eb11510a705eb7022e8f802f252fb0592d61e160b524782f5889d06753a582514b5eb38235615d508fc3ad09f4cd00e0bc3524736c37de3e8da10c8433452ad5f075e798893a772910f16f09968f64a093f66af05bac0d48bb908103937e77285214ecb054e9a26346f508bb155a154179c7a9435b998b48fb5803862ea2408f9ee3a333ea480c2e048c81eca8fecc9a3fc5e4334b202aa47b92962fdb5d3dc6ca24e9762328625e03298c296094a5bf37532480899f4ef3f6a719a52b23fff63896e991bf9989a82d757e51d03f0f77e1703076266c20d23307a71e33a8b0c32ae9c92316696f23f1c4b645281c6292c3600f917090297200053b953d3eec61d3bfeb30be9839004bd2ae6aadaea1d0cd18496722a027569fbfd522f2907c67bf8f4178b8326786aa10b40b3c2bf5268eec1be1688866a5395b894c9c835dae04659df393d4325c1653a7a578da667a3215654e894b7f9759b887a9c2e6f3d76531a5864672a52db0db479420bb298f09253ef8306d3ecd30319a4d3c5d24d55de273f03db52989332b09e619725c24288f483b4777a1977cf0724142a30a13b75615459287ecf730a4f6c2623be90b8bb5e9f7581d036adcea44213a2280bc7f34e813cc7e72770330169a34d62fb8ea1c8801dab4becd4ceb9344ebbe58d251189978fba25f291d802721c36011daa43786fde60bec710858b648f581e8d7c198a74e8d5b500112fce097baebc3d47da770f2a9525654732648132989ffae00bba14ca680d80462322527582e8370d8102e3b935f2806f20d5bee2b01527f00a92715bd2e838107e82c39d0b1379f270bf2a8446e105568c057bb940ac40d3c51b8249b58dfc181af2904e1f86c9d6e40b56f09f9dd22398853b13c52924aeb90f4919c723b7f0afb603de6ae98114ce1bda8b7e77954c9e690b02245617040ccb6821bf7dd55d2039d417f20b4eedb62d738ecafb4db07e264b73760066aa4c3adc342db3dcaf669d5a8eabb58ef3c83cd7894124cd16d64a63971f8a405f4db88bc089eb747611d2d1ca03f5170a8b617b81f81050ea6a45a20c79f331c0f9006b240ff055ec03d748fe44ee3a81603e38defb130a9ab0d60306b7f5a8782b36d74356c4f1e42fdbcfb367664d42481602b1fd42eb5582e213495080306c1910c1df6d32168a6fe694ead6602c33121ed34defcf4cd94347dae995a52d5fbd031b02c7aec9245b09e458250558b1e240b060a3e4731f3f0850183557d96f5ced26ceb3797d82f836e40893d86dd55e90e375fe39e0943e6991b92377c276e83d36cb7eb9042992536f43302516e74602901bf0c16a5a501e5d90ea53eb3b21ee9f9e93c5d6ec6383ec174eaca569fe2b1d216d169035ed3ea0dc4bb59ef967fb1cb200fd09fff5cac9f45bcdd6c8d39099fb7b8111d4a4007854d1b45e3c41b3b4eca661c49e517dd13f392feb4512b29bc1df0dc250f07feef190ab8c0c3824a67ebb5a78c562962493e3c48a40be441a2a3ec17b7d4d8f08fea55627773be1da0b9e34c8712d5a35d1765a58cd259656c05befbf992346f623b66bb326f00be1b466fe148cf8f3a6978dea56ff6d6d7ff5ddd7c57be8389b3132ccc6cfe3f109b590316fda33b43fcba26c0658a892b5a92a813949d25e03b260527712e822912fac50aa42508edfd83a707724012db8f7013608c6030a10082aa61354a4134316c28aa36c2ab361ef33932a2d0e9540e5c1b600c3a1cd07acb9205dcd234a59fbeb95244ac2a9e1484b29f6ec6a73d0f633ad79c718fe19ef6f7a560c974077374dc7390a969eee2facb4b70570007d6a9d351adb56dc775a40d88713fe72590d596c9f4c9b72d7754d5151b872bde656c6a24142e75344fd7c7f1aea87284fa562a717f64ba04cd3fa5ea25388bac8f2df2bdd5cbd7506214ac3b2a56804f53e7d4103e0b3382cdf06cb2276f409b0533626d3488f09ab09029029b53a27c5e42a4de7dd1ff5e299fa1878fed0914458707b28cf264a05f0948a9d420f47f5b85a40dc0ff220e10681129362006483d06ff8b01477102e71458e90f59de2f05e284afd530f8b6a0f1af60e40b376d0b86267c100e3603acd14753fae27e23a6f49013aa891b46a3234598622a7b139d5f8b3f29c9c37412e60a5039b102c0e0c157e15b35c15a08dbfbd82b9a9fa60ed06b7307cc969e1acdb921cddbc3db63a222393f045cca2a84a8e36febf9b35a398b51d340f31611c888e9e765ecee18a1e853434b07653aeaed55e40fa456068ea8b49060c58e54e5543ecac54e8af74dcb33d3976215765d0df36839c31d8ad4d377d3c13e2ffad2329f4ef56103b0570004ad665a5f05063b6f321997d8366ee7a15357785a2c83d832cad27b02ef0554967144e87a21e7de1dad60015b2634335fdf05eaade6d54e4c1abcc61f822a200d912192bf313c08b0ade96881aa1ede7a0d9d8a2c211fada0f5047cd44a3a4f6299f38ff4a67065e814d0cd64ecdbf359811f313656fac8d099852da807912ecd0838fd880d1560e7472b08b1ac00e73f6b7bab80f3b77b03a39b0b1a23c25e1023241f74e8893341940c4d2eff73eab6e9c90b708ea9f5af34c3b21f7a01a7230c2e4bb7d52aed1bfae71b2a483a79c15927293e4749cf2df92fc093176016c34d195ea8c9cda6b48d5896dd0b1415b80be3ee74bf1760fe9da5dc7b5f3df394b2d46a2396660e64ca1564706fdf352212090c6440d6884c5bf82a0184378e564d997dd46ce6beca59e2ab58c7ff3536ed0d7ec980ecd034d5d608da6470ceb1f3210381214b853bd5ae82d6eec4693faf7f6ba543d5347f8d253fc05ed01c8a36347c8a4a429e5227af9ac29b5d174138aa3f549df6d481199cbe9d6d44271fddec54f0ba9212aaec097069b6c3a6e4242319dc2c0e68af46415ce59dd77820dda8d309d25229fdf8d621fc5c9a8855bf77dd9279e1393c9d0e91a0180ce14cb2ac55263d7be4a7ce25673a614d2af4216e820ad64245f18324296ce249b624f7a7b0135559044fcf11acaca15e8d22c216b76f1c25a57dc5e2155b8e3daf54bc9500a796e1b1d7874501526e18ac3379cefd73cb0042489b930e4abfad460006feb435e1c7a60e0ab2e31746d82a8625a4fbf3509370657c243757f0ccd75dea4ad70f0bedd9dc29a103fa04bdf98d8bde41734db5233f4158c0b13d19a6ee733430c1794f84d3ca494b3334350af3d0520d695a5b6b480fc91ebbcb772e3d8accbf95caee91fe43d9ce0ca5f2c6ad101bfa6b77e74e88442ba533f4091ac1ad3d90ade0f34f7f5f16a3d6a4f850a21f285d93e2a8a6291fb5be4fb3f5c81c5718e5ba1f0dd3410fcd5099658f972fd0507b0545a15b32fb424c8d80264971775916d0aa5bda2d1a5280fad9b136307ffe31a154f99fad9bbbb54826c18387f863fcc2fb0e750efa63b692d4c5b5d52d8042249cd1b58fdaecfa80bf9aca9ce369f0c3053a0c7e6421967cbaa9319260f5196d0e7de4a95773474dab2e34606ea33343732c4a2e1680a5092ed2d058b5a84049f4183c712f23b9c1314419496d5fcecf33acc208efae126661d1a6f9841543705d6c529cee12f241cb629edb46512cd1da837000b9a3eb2b85dd9a1210da140db2181331b46edb48ccdcebf2abafcf416a6ad367ad59c1dd77cfd79717d3bbcc76890b1d2c6c6dbc746a15a1b07cefd007df485b78a8379158153329824d2f46fb44e9f181e4f7eea45551f84d3f5646c368ab781441a760436c7b289cd66c9ad0c70514f1a83710ee6313abb3cea2243741b2dbb29e58ee2e76d97fa5a5d7569eff6566dc240e675a1aea46811ff8f6a8bfb1eff7a8d7db994f0007e3daeb97434dfabf2620453936e7724178d05f2cad4ef92207b31dbab866ddcd3698c067d19f1e19ae8cd62b8bf0583cea436b2f01b4889594ab56b8deb9e4941de64ed534c03621e9a5986a10c6cbb5b3ed2ee6958b50ca21d2a9d8ff34cb439cb8f044805f9af98bf9e3a585e970f3f63e05c45a81025ecb06173932ab8283ecf090ec0a7da51eab7fa34dc856dd4851c2b963ab94387da396fa569964448c7229132c403a5d1a472e6ea64b479bed90aee8a1f01ccd4e84444508133406c3c8133e59d80b2ed17872528a915b0f2f5d1d474504db6c3fada3c2dff9b4888e861e05433be1a596cff975bdda27e35feeb05c0d126ea17a2a817a89c7a6141f25cd6bc3e1a4d69d6e85d19fc680c81a38569f9b3b73bddd200796de29163b1410767030185d7220a9d983e600b6f9743902a0e82a12f3f3cd202639e6f4e1ca2ed1c6c911fa6375997ea1b7c3095c0344554ad1c1856ab05719ab31149ccf02903a4f307236533500fe4bcc6ed1f7d214e7dc55f5203cd797be0086ac0ec52897e130374e3e95f150932821397d9b33ffa88c14cba14a05f858bc720421ded0b9a9e2ea2b9a1651accd584927b3446d2597d9d8a15ff89f0aaf8d92940298510f67e23a554a90b4fc2557e54d40888a19191a5fc1842c83961519928ad0aa78544ce320be04c0d85381c4474079cb25ce8582db1e8641c5245468d8e9f5dc228c5505a733e62fe38c8d452a3c4a9170029ea1b330fe3a8a9f8ef1af63c337c824f350362a921b6506607acb2a1b5b26324ee902e64314caa45f3062895a0c6e20a3699da1f1a9445e9743bf4de04dbe060469ca413cfe6300c22117fc6308be7c142833a9fd0124585d6f694fbdaed1d6c7aef5219445e5d01c618a55d2b6286be5ff575faa1b3440fe895f08825d488d1e55722fff0324c95dced0742b9568a88d30abe72df6d88c90632f9019ee198355439eb924e3ccfce2b0097a763461d2940062259a21677ebe475778909d25b7b35617d574b3f56859bedc9d7f2a60e33db4830ef299f8e6344b45b1d9d5f1d6b01092b7c6ec0aa283e04a229f0c924c108f6af39cc06692b3d34998fd56084adc06c380a2f34e095c859380af8e3164a4c807d0706f6d9cb23b77ffc102aa0abbda9e444b65aae5f29fb376899039b26c33c9b1f2d0d1a633da13a84a880e90c89ecac063f74e51e613fac99059375a3b4eded1740b02b8bfa9ed6941be0cbadfca50c6e0d99ab1051dcf403a0598ccea88ae2794ef67b457fb48a6fa89660441e00aa1505c7efd2ff80df18aae74fdb2377b7cc87774549e5da6a0b7097fe9914a31786f7ecf649c859058b4f9a7863d7161afe3d3b6394ef26d4b0f6c42a9c77b7363ef5750f8ddb92e3f4fc41f05d0c7a81591a1761cb72ad728f23d474bf44bfe942c43c785860261dcd453c2f26048b13f42ef2e4dd6232336128b983e74f90227a85a8e652f8840bdfd4e792e477e78ea0aac726cb7a91bad58c8f9477884c4c7dec9396f1982930db3dc1e8f2d50338edb077eab93ca31616957af57a547e6a56c23f4ed4449fdfc6e901873bf33ed17f3136fd51a13ff953749d1884545afc8b7cb142565b9506e245184bae1ef0a07b147348baa8b02f54a04cc137475d19ac00049ce257aa973e4f4e32171641218f152e765890695a3e9f1f4a05edc8f7e44f3941182bef20259e963153852975c131a751d3af1cc0cadb8716521a1871d82509978b3a19dba4906af799b219fd08ad474fea0406e2b9a70eb99f5eb10eb9255d264c86a3a8406c9aa044c409bf3ba4f334094571b9328f28bdcfcb147982b99499a7acbbd687e63c2d5f98bc61bc948375bcc00761c775728266360533aa15a7e9cfb68638b7c67cc312546db731441f4143bb0acb57db8d84aa113813c0f9061e8d78b852658ecee864d8c84ed06604cdc54d322afb80c308982837edaa98e6af499702842d55b30d815c0e5a03b0d77574189e444a3b7795167062c9c507d586868b41daaf41ece6a5bb2fc1bf9a66d3a21911c2d3764413ef12b75fb1e16a5f057eaa097fa1f6dfeb87f9e1431ab1b011f1da09bd85d0dc544efa354172e42ddd193ef53e8581ccd59607808414a74993406f65619e73ad17e643ad89779cedb54ccea1e9be596b20ee73c1728bc86bb3610b60868ee311177d5237559544455cec268011de4729d331ca02d39c949ebbf98a916ee931dd50d855f56874592736d862be473ee746bd15073a205591a9a684fc3a6ee823d856905800f485690fa3db7268e3480afde1802203523b6f98e5ae3d701a8ef1d3695c357ba7e4486cb6ceafbd6f30090e19697a3a45faa5f4f6a749c8650d53a17aec20e0aeb99279a195de641db3add20fc269bc6704866d11e2c390f006267da30c68e92c3ad1167c8174a47e20b97dca223058a434068059486054f2d598e9b784a9199d749a007f0542377966e3a0aa2f15fd1aa55274bb557ffd5465d27353ab084c587bbf8380eb4305b464269c09729e3f183a55fb945ac2fc752ad3d3272e787871803f51077545c335eea836113c04237a8823dae686ad5dc00b25a893184ea182b4a34b25d1248ff39af3a7dc05f625d0f6f13c5ffd1b50d3ece36bb849abfe4b02660c24c113c85746c21fb572b8f35f5ec28400ab7263ad36946abd93463e63986c23b8e66954a32aabba2a9dc7cd64a66b6da270e2a6a4bbdf9c05fee0a5222e0460f3af0c2279d2d8e7ccca5592a2de4cee24e9f829e5663e7c8071c2b81ebe43119e3cc183e7706e4a34a89da94d188dab4f343c16966a136e135193561bd92cebc24cf842a341c26ed3d3f1c9096240013baf2eba5293703c30d8b8ae8a48fd5cd1a2e38bc079317590d9e7f91408ba4e4bc7fa246a4509746ceb92c17cd46a334878200ef59d002b060325980d72f50e4d8c5dd0cd7d20665b6a6621de1f860ad1da66945058fd4af003fef6460c3ad853592c9b4718aae85e1e37a6da1270be8422f4806cda9fd6cf952a6e3e0ed7729293a43ee2a5c0fae6979024a30aaf25264d63addf98a946acea00437148a3cdca987ea174e991e399bc44dccc42db96ca1250194409feb36d1e62ab073f90770fd12a4b404529b9c9c62e3ae93166efb58ef996a394e513b000c0b1e9e84573b7c6493127bba0901b7a0a4a1a0f22d69e5db30f649b5e71ed9a28a5d2bdf085ef966dd588d1f7448d5d3c14d0cf9514a4cd0abcc348f5e68391be931fde05ed2dd905d0c3b66ad8dc6449a8621bb8c30fc86abc242807036f92ad3f151a2041654650dbfed54d3f885ffc4457c670de4f601995d6d6c8294285199a9705474af554529a7cfa9880695f9e7b7ed28ee32999be085443f1f22a757e2228f1ebea1d889ad2f4c3f619d362ae34c7e138d73654ebbb0244b606ee0f033b29892e887486c5acf0b354fafd6d91942a58ab93a421ac2dd6a12af4786fe9551a34b86da1f22ac942e7ae6dcedcc109388d03b4b6f8124686c04a1b4ff8775ae87988e5ce156bedf88c8414648be2a29123a612eb0367ad4df40455110eac384d04057b0a27cfdf30e9bc6328e5624d185c2abbc018efd732b069f00779291a4f68963a8d0c048b697352cc01049d1b16be2e242987199ae9039de480a2f12939ea69afd8cc247b42ec63e42bc5c0d4acad54d34c842a11c972072f1317594e72d3434d0efe2357b0242d6d92e0e5abe5ff29a337e4d8141ce8c992424392f909fca97fae8d5fc92644ef2eb6d0f048502faceed615e300e429b0e29475929dc458bac5a66863f1f0237dfa460ed2c2b5d8f30e220b8b174993652acb67253b20623b8d1ac1d4b173a6680542008c2c050081cb4a186f24725968eaa82f1f61a9ab06948d07d97c14842dadeddf6de5bca94a40cc905db052306f9737e66055cf3015c2479103332c0cc5001469b007e6e4072b432fb1263f560c49e5e44b1a22442458b2916fdd752c5e40a2670cd4f29a5af718791d268330fec5bfb52704bd35d4f9317375c1ec949d816c9486020825f0c812f9017b6a10c5ce8e9f104c3e8018f543074588caa5902835778e097a6bb1d5090c02f78b0a8e98e474c0648b04bd31d4f12f907eb6c8335dde5b8418f9aee7ae8d03be3d82fffff5ff37ff59ecdfed5caffffff57ef7df5deffffffd7284b9cd08eebe1a8c0f112be97f0bdfcffff57effdffff57183be7131b312effffd5b443fcffff7f752fffff5ff37fb5f1f2e18fcbffffd7fc5f675efeffffab0ff1ffffffd5b9fcffff7ff5ef7d7dafffffff5f3d02f5bdbc2e7c9d0960e811e0a855985c3c7a2882c90b8f3cc20617785e3efc6d396d0c433ea717b0a7c81790e7c5c6da40e9745e6e52c0f0dcbcb0cceb6483cc4276a13100901d181aa8ff2e1fcf85261c3e5ee5017b57b7ca6303766dc0a03eddad5e6633eb33c287c25181244b121c287b4960bb7c603f80a24fa3151c70f4c9cb0c19a3292ccc80ba1502f96eb1716d61fd218622f4b579a1f9abc5791e61392470fdd9b5df5a5f56bb8c9fc72773ad1a18f30e69f80f929e6b59b39756665f3b14237d1d0eb4f050b35f9e31420aedcb3754703d918176b30a2d28b248d16cfe644afeca94b89529a9996615beae606c31b9a038169ad8670c7065cac1d39745405680d17578947c9869ae525427ac676d538a73a51462fcb39cc193d2a82ea03a945aa2efb33eb6487f198ce5ecb31a9f55f049f7584d7a5b9eef855f2d6dedddf6321760b679567545ca1e85aac91d917e39c7b1649fa6797c2bb1f6e783a4257df6fde9369bedc311b4e158cb1a2195616b29cac4bcffc4f92ffcce9a00317ff99ba0343e7ff99da01fc6c502860ef386a1f79ffacbae18486fc2cc8a3d9d85598c51ca41985b2c74f8b1308f2c328c3d065914adf85e7e0df37f08598b65085e5e097475047392d297984568f1810d63dade742086355717610d897de65e33ecb3b154ae6c57381d5a3d18f7297c2cfc1b9e53fbdff56631a5517309312fa12af11030a5030ae546caeaf3ee803ecdf80f438cad50406f3efb7c8e21fdb9ca52a0d1813d6f1ba47e1ad556b6615f915414569a0231e64a634d81188344cb0906c10122780efd6aca988d85317a4551146bb2de168706c18f92637d28630af86f5e27fc9bfa65fa378f06e860e3a0f400347f372280b5cb7608581914431f16b41d2ae41d37c0cc927db21d21d01b022fed57466907557ba6b45a46a06acf31179f6d4c05fa7424c50ea7a82c2f5042bb61f3cddff77ddff7e59e19b44fa6020e235a748c491204498e2bb47befbdf7e69e19b42bdb61654a5ce6e265119869cf2a8038dc4b216c2e7dfcb2baf74049bff9af18c48007bc61b3cf6f8365deec0bb8f9332c8394460d7a53f3786f094c961903cbb4e457adf518cdd6a97bbe4d29b8334bfcff0dfaffff9452ea84d4f6ffff711892345aa39021e6424c69a4b9d1eefe2fa33816c7d7fa63eab38cd2980dafe9771efdb54a6aaaaa07c573826a62525a62d2af43f2d9d3ec79cc6910dc3f8795c8679452d9b53424255dd81cca50b01ac401c62a91cffe5ee94d7343a208e8e0a6056bbc314d37ed853200e8728ecba88c4ff6590c41a032be56d3635fafdb25211439fd34273de327348de5a04abb975529a34b53285060d1b09ab18e80372ccf96b4e71a28434eda758551d1387587d6f8cd670a0b71fdecf7dd3a53019b9af7e0abafe3c4f1e003fb27d89861c5136c50de0c07880002ed39ed9d6063c607335c42d8dddddd4f16171790f1d6e8ffffff7fb5f9f0c256716b75556675d53ac9a8f37abcf8be9a9d81a7699e59e2ea6e7ccd0b5fff93583f406e409ee7ff9ff5a3e8ffdfa7e869acd5c6092570823cc50982c5466980fadaa88c19262a193e0092f03baf06065cf3b5bdd76f6d1c5757a118f262851febe40b0c24d83505420c11a39820ec6b0a84182c9ad414083152fcc7071d6f8a37d2a7b4529a6bf8fe9f6485ea89177c16a789d0dbe674dab75592d1db2eadc0ee90c2f2782bffa95ad53fe9ea5250f4fe23edfb75da061c4c9e78b0c1c013e5c911b4fd660ebd9fa77dbfd307fe052a21cff3404ea4dd6a7fcde4f5a4b657d57026348aae4efb22edd988561994032a322aef46d1bb3e5131e2ae49daeb927626ed3abf60b4e70dd004dc5d71da6b7ad72d4b3ebd2157454b9668f749df252778be80eb509abb9b25b8677c732544e5606514054918249a4fa13de378a0020bde5769c6865dcc80b75582b7b5d235c77235c784e06d79bae6991e785b9cae79c6076f7ba46b1e75e0fda7ae79cc81b7ade99a5f3cf0feded75c5ef91e787042ff517833aea2efcd36b37b73cde5414a11fd5990e82f6bdc1922302b4bcd312c78fb895bb89ab1185c76c1bb5ae97a73a10b08bcc4c30f4ffa66eb392df4bdb97b54b342cd3543b8c511b8851157697fa0efcdd8733ae8016889f1752ced5eaaf755d251daf41ca5d70dbf84f04b09af00835744f98ca9af4e6ea4369b0510f37caa2cb0c08d4dee03d7a4d3fd504d87c3d99148e6f699e165492949f1be2225291e0f642901c3610b302cb29ee0b058e48284e3e802aee975c823a526728512d764d50a5fc052f82459e4849aac7e5f9cc624b9058f2cc07bdced8034cdaf9ae76c162c903c67b3c8b130c2d57769cb42f71a33529b3df2f457b7d6d2d21d0cfe78aaecde7c4665f8bdb21b2ad0e8dff8c8f32123cd12bc432870cd940c857718e6077e5d2171385850f5029248612ec0e80b8ff63112888b0a7cb6d9fe48ddbdd6fa4febc7286d7451ea02236c371a9d42082872342a1a8d1928b903dea1866db939b1b14042f31755008f094a398569c19f8e926adc7103eb0ab803caeb4829143669f5f4007fc8ece80202b951224fd4c723468401dcb1c50ee9087b8a589e245c475a345b3af3ffffefee4ee9ffd731310024e1eb82eaeefe5f799274cdb3b0ea9d7610bcc9e81d8cae80d0ada5ff45fa2da551b30dffc7f0f08cae7b1bff1fc794bf7fad4e8c95f736366c8ab07d4100dd5d0feb43cf87393886d1d7fd587badb5bb1d25dafe8e5118c4486df667ea7aa4a91975a5a9f905a9a7a9191544db1ba551a51cf73752e06d6f2ec5d2ad56abd572d070be3aa5d769f970e5879bf93a6ed69a2eef756abe4f6fc2df3cd9deebb0aaa408b3937a9d7ad66ab42a6696bd2d57f62a856b36e175ece992b5649b9eba5652b66b4dd7517673b826abd493babd8e0cef47548d56b3c5555acd9fedcb7d4a36774f6b525962d23ed9be365def6ddb9bae17f7b27d6b2edbd6cabc58468a3f7b6db536e32adada232cdad640b3d6caf6e74072aab184134470112440420e2557ec802bd5b1b21906ae03de333eb8418093a602014e9acdbecb51a4e9aee6a40ba0e9ae96d3b0cfef544b97c06c031b23a114c173603f5fc7e8b57c80385af57a682f4768f1416d8cfe72049a90765033cce7cc01e5682f74fa2b4720ff4b4d83e508b8ea51243d666bb5267a68b11c0186aeb290caa899bc695639c258a76a7aac1946184d9623b87495d5b104bf5b5adbb223ab258a9fab6cb5beb54fa05d9aca7606f0f56ae963b055eb3731529b2d56023c1979522104fddccccfe7dedeb0814ee74267af9001e070b118ee5769a046ead1cced03b1dcf078230f30d432e319e1f508c500605c3918ab885487ea8c998eb1d9dfc09071c4ef3b0108ca58238933bbc9310df2cbf657d1fe5234eb346726cbcb48a98ed8c24694c19ee8589659a631c24c754a593dcdd14527bff13f455efddce7744b560ed1728189f58cf45a24e1c2620c8798fc1c359f0895f17242697cee739f7b2354a79ee1d3a0ff06ed673d574ce1970c76b5ca1739b25ee22b045fdf7dd9d7bfbceab42e0ed0552821d3227b9209211342b645b645f644294d61a4fec28229e9334a1ff00f0800a5b556233228ec25fd7affff9621546dcb10be52ffd6be61cb105e56a98ccff7af577a652e42b8d19f6f62147cd1f8acca348eaf5e34d25ceb7fad31190f531a96caf02355535bf34854b33bae44489447c23f8de528f0ff94470295f19656ff166d829f661753f8b30c08fc9986b4b766161550b8062890e0ca3676c2dfb8e732569b647478d3261d6a3a7a89e5abffe3501949f8c90b6880d2b059bb0015376c420951388791da904f25a4406530c198a65aac33cd1236c81399f33256594b692c043eb3945a7abfeffba815c1534a22c1b059e821a635d9719ea84310e0e9c9d4629e54c64cd0db1b36d0e95c2cb157c800703122333e3e10cb0dcf09ded803865a66bc303c5b2806c06c8109339baa14aae35667ad52b59c7efecd4c1138b39b1cd3e085fcc879667231413f6d40f385cc20cc4a75aa496f3c83995533f6d482577ba03a5ef5ae261097e7a958fc0a882f9af93906972d99d9335d6062bd303d130913046966fcc4ee04367330c1d34f0f4375aab97d0aedcf43bbb984a98286a60b17211b8600edf009c39027b25842442126086dada2180e11865a44d648822139b2c450e405b1d6da0fb439a01dc398d39b9b4596be1f735bf51bf98de7cf8927a621837c5a89308c851487300ca956b8500300e3053e2f7052221bf9584de99d71a046773abbdfb555edf5575043ad89ba8ff9afa0e262375bedd66eedd630a03fd7cfca5835d7b52499f4372c2128a678634c6520094127466ab3c7ea63a533ab025df3df27595b70cd7e5f34406a6bfd16683f3bda777badadb1d6d532c698e09a3f3f0d0db85afbffaf2209f55cb51197dd50e16d2fa864d0f4420a0613d996c10a30a6c85430d82383293a32f081599aee7658f978d184c5a8ccc3e0957cc32f28353cdc3a0283062cf3a3c90ba79a23484d773ebd9f5145979c19a203b860e241ac88016658284038ee08e00574335e99d999a8586c4966110123b6e58557ea5e16a1627401594334b6a062bd74a82b92c035bbcbbc66c8284cff414d773e5b6a171bce982098690fdc34c52234254b6f879d245f68429a666c358e1ca0fca8cdc043844412b42fd797fd3565572909bcaf92670f72e86532a3c36532f364c6680669262947ef99a5ab3473c369cf3339ed59e6c933dd323ded5b466acb9c54cc0bb51c74508810c3046dcb58f9d07ba6a63def19db0cd00d92c9728364b4c834c9f0b4cb3869bf2ddd98b467ba658eb4cbe8b4631925edf9754ed1fb65a57dcbd4b68c8dc5142754744f48edae685be6268393c9c9181941650413af9e94077abfa6a45e4e522f28ab9769f56ab2b279a6fb75d3be5fb8fdca25b96281d2d58e1c9a3ca1edd75190de2f9df6fd527a2de9f0daa1c38b87d5ab6600bd5f3ce69459c5c34f3cdce3e59ad01b1f69df188cde58a92908264ca298212a88b63190deb849fbc63cec645bc02fd816b0107cc3b802e88d8b2c0ef3581c063a3a8fac3cbb943cd3ed32b56f57d376f15600c40d5047dc74539aa06dd7d3cf76e9ed9aa27231a172dde03a72e9b46f57d2e92afad348bbcb666baedb76f13cd3ddea69257ab7a4b48381cad1c4bcb2048eb65b670fbd5b56daf376e9ede2a1d2a242a54acb6c35dde8dddaf1925a4bad23eda59467bacb53fb2ead76abd6b473950416a6225298a0ed96cd47efd60d57a43def56ae65e4a434c2099872a7bde4954f654ffb2ea396caa5255df32e99b4e7b23683dea54dfb2e77f9822251a07c9e8c1802036d97399bdea54e07a4ed32e905295e98828c9aaad24e5e7d8ee43df5b4671257b5c9a34dea4c98e2e4850627b6082d41dba4120fbd49537bde6413b97b1fb285f7217f5c913c2490f64d123dd038f54063d5a8a47d8f2692de639305a05822e68724228240a1ed91d7a3f7d8d361d1f61845352aa11a691889c6a2d148fb88748eb573b43545f9663d69cf74b37a364ad49468ea892248146db3a476e8cd3aa95857595851b2b0a4b0905849ac25ed9bc5e44f2c1c2b57c59e67ba4529ed5b3cb1e82d5a35c1638715232493882ab4cdaaf1e8cdb269dfac1b8b4807b18b0ee2102293b8139db48b50a6a8b445b326deb67824221579a24898102a8c9ad21e561d854d4721efe80977b443537bc8e44161900785425557218ff610c8c19e83527e3b63d01b54daa039c587eec70f51568ac6d036d8b4e37983504f80459e008d8040201158a41d34b2faacacc09a950f7a7fbc29bdbfa72f082938d49084071145d0f6d7d3b1bff3a5f75765c4a78311df93cfe843fa92b47f4b55aa77cfafe6fbbb7d44566e966ae56ab94b97e9eeb45727bff15d9d92f6b5b56845a86a11266c4f4abb9d3ab24e47164ac99a4d4abe03a3a6bb1698d0309fe5b2ac41cb5204b62c6b88a04ea1cbf20195d6b0321a1807489a1618266aba6b610c4959ac12bc988c31aaaa0c92fa6272fa4f9f68cfbf146619ab08ac8cd25c6b942495e1f9631bc074b78295de567b94ae347b2e414d772c74d1b0abe98e052434cc67e010638c263059b1062dc420024c0c2248c0a004172a304c00710194133190c0aee9eef644c6b73096da889aee6e51ec8c9a7ebb1e56bb1e411a10d9eb14540b836c3e2fa3f4d220c4e8b0790abfddcdca8de9ad3e77f2284da7aa9c8783e4494b384c383b4db3e76a95eb9870d5731e07ea3991179d9e2332b94ebddd7637a71bd42daa4e699aab59cd5a548d90cc249a35e0555715c804cff9325476a24c1f68ba41b681d5786ef45cabf3fccd5ea524265329090443d16429259199927924499224cbd69faeffa8977dbddeebeb8e4446b96d714418bf888cb46799dc0cce125d511463db3631c5a0c2db9e33344c2a2c6f4593f6cc82096661b0f70abb35f4d05e7bef7bbda30a52c58a7d79b467163ef33284aa6fac85adc2c06280c17bc560455983454b3b0fea29aae7525e61b1163af2cb102a5963fb1ad19a5b53f35e6bc2960b08682a73e95a6badb5c6ae18829f8d41e522779e589fe7379e67d5799ee779bf3083300cc33034dd64999f189e67d5799ee7699a4ca6699a66288e250c18e4c764b4288aa228428537b024ffac3acf93759ea2693299a6695eb274bd6666f469b2582c168b6542886121f967d5499e7f9ea7c96492e69ba639f67a51bd5eafd78b412543b30286410c1c28ed34fa4a0ccff33c4f93c9344df3b3377bbbdd7abda85eafd7ebe974493a9d4ea76341c6a0c2300c6a5e640d70707070706ece841eed9db477bbdd6e37f3669aa6699eb556190a568721c6ee39d273cef359ce3018c6ce7be51de2bcf1e7fc56c77add1cbe39d7cdb56eae64f54ecf11abf226f3a6a9b1d940343d277459b365cdd29abfc106a19bf66689cabcc9cf9ba6c6668307ebd9f39c2faaec7d8fd5137be147ea6a4ee73963924ea7d3659ee7f0b8ce254951b6696864bba6c6c66603bdef06fada44c1febd7821b64acddb00500c3d3e3ce0809aa8ed74ece0e3cbb36c93f3d137c46b4872753b3e59ac98a29f21b65ac3ced10f86611a8cc33ccb3639db320eebcb832008eee459b6c95906a1223cc2d80e7011c24d5124498ec9a783508f0c35e9d6e30a21f9c83986611a8c876cf7b6c4866f621b02002f8a143d2ef86043936fa932016689861e8c4071ca4108870e2152404bbc00b1c0080e3c6c80f4805887fe743b4856b019e73ee13c9c5a49d28412ef05636ac0c189cc288b12ab188a107345a92706223622df0d2bd4effb6c391b4adc30c4d5144142a67c4d7ea4e0916342f41d01f1c88179966d729e659b9cf32cdbe41d84a48608d04304470b2f60f181942b8244e94bfa8182c7901a64a4bf9d247f9d0841013911fb030f2a27461ca181059f0d403cb61c4f0cbfc4866f326408c4f964618103a44748ccd010af21c9d5ed0cdd98080dd9a9281c710aa104084989f7e97c7c2192a3bd16dc6e48a85ce9314403e8a3c7100e1b8240e1e1618673c7cf0cb9a00f7bf420c6071262aa7cc8a2e42709fbb3842d140a73f5234a101c6c481ed5a30267e783a2f8b83c42be8850949f6f0886611a4cf1ce47901d74542d4a7638979092434fee4ba2848f2161c66171b14877c728e8c88e960fc98fc923a4ee2046688c113e74099a72042817548f8080785c2041446e9e659b9cc19f230ff265e7082d59b0984a9f91a01a88ee67cbcd18f2a18a101a78d082830c40490f644568849a15241e588e5c1d2932c48194f0b06211c1304c8371d014a9dbf9efe60314a3fc902dcfb24d7e7a299f2142766018a6c118480fce0fc5d22076d031e413a9288633f817246407b56221e833faf1b15373399cb73351b4e1503266a9881f9618d97c10d9050dd9328ee5428b807a3f310c712236518c91e4cb55940b3f00d1f40d19c2f9f8dd09f180867c1e186ac14ed0962748a0bedc0f53ce46cbd1ee268390cdd3ad9ef3c05614c04c024b699021996d6860184cc1af77a81dd378d680e6808002984910ba8d76cf7b56834536600274e6d9495256ab602173154ac3cd586d1a6392758530a49424b3286656256bad51c95dcf9118093e9b00e560042ac3f327012ac3630fa01acca0acc515d3da806993d2709c19396813095278af3c9406a5203e81de80322aa5537eaefadea84e2b5f5d988aa8842c992d6aa988488010001401d316000020100a89c401491044811a95f20314800b5d844c625632980683c16018864114454118c230100208008600828c6312b50a02c3349451836eed19893a2c0be67858668b6b0c5f1594df6f88ff8c45d493c890f8557907fb9705a4ded3a59ff0b6f9977825033c90d419d3720d800860b8cc7a31a1484e1d1847ea5fb7a74a686e280d1b7ffba561248a6f1eb11a6bfc5551808b72dce55e18b63f55c089f4baaa3c78fa8859b44ef946f9bd34223524c05d6c0b72d5c1a11e5a06f848b9523823663d346c848581e9b4ddfb517a07937f3701cccc666dd260a06a8bddec4e19984620a3ebdf612df6a828020b3adc2f55694dda412843316c413c2ced5adcb7b1e068610b159b03a4911b8daf1cf41fe3fdc1369e972471b849ac1754da72800939dfdd6efce3bc9f2fb25082bd3fe916a8a3759ba9b4e9c972df5c3e08a2632315704be1db82b1bb6da7323e9976a0e9c946503f88aa46c1adf709c0ef76994b010b8f2194b835c9e25662076990d21db1cdca5d707f1990236c9f41a7f9c1e6a58258733dfe9b8126e998a376802683fa206142187278dc7d725eca7745042e4f7d216814ff0754dab25853aabccbe8d335e54ffe8cb8f1bbfacfd1ae8cd0c530724b4c70b56c0d67d7a47425915f428b6e3de9381b6305e0bff575a3d8988bad53a0810b3b437e85d736ba11c9ef2ec2932dd0313fa51aabc7dfa2e66d88159a1f93befe55df7202d8acbb974847220a211d6605a65f2121d6e47c2c2a58ad09f630e66f349e2e3586deadf86c5fe51fc06128fd888ca856672e7a4f22cb4cbdabca13757b3317bd7f3540cc526fda71cbf726ada207538749bded6bfddcdb48afeff3d173698dac96b2606ab5b03e3310d7067d35d2973f63e7e3ca1d208e0456718e089a876f2e9bd93cc98a69f8c10e0a07455ddb1fb39573cf853a074f08989b1ba3a824c8a63fbf7dd2b3a393ddaad47b10d9ebbc7e8613e169d515ac5bc7102e1dd80d3c959e13e782962a43980d1a0c6db6f12fb4cccf11dabf9252096f00b0e8fdfaf9fbb26e36f3a5f8bbb416e01b6044d2fbeb7993de2d998275ac5634e30646480223d8d3d234d66be97e1a4fdc2647070367cd1b7af9b8d42e66db4ef227648bfecc33ed8e97bf84109f6d2d951bd1a862e3d77b77d8487280240557e417b3cf7de75ebc3285b73916a81c59a09c645017f91c974601cadd72d0fd33ca0adaf1d0404b660f1e2299f7f8d83fccfa5e7279284e39a77ea93ed65bbf453137284f5039d425949f55372a8853d2344e6ac2368191411237360cd06fb5f82c82ae7ecfd0f30135c5daa5b046f18ee9a4e35dc4844622d179769e043b9564cb8cc86107fedcc269d50ce377869cf8692236606481b3e81dd37fe5cbea577dcc04478a4120db2796e6bda1cd71b47a84bdb677b1985e6695950d4ae0d8551afe1a6c782f93637d8f48c6b5faabf9837561f25a6d6453ecdf9b522cef3fbc309334861a74bbcac24406322903840a71b25e90f6f41d65f4c92db3f98e8cb26cc73efd29c1074dbaa26351396d8dd3ef6d15d511c18e2fa6acb64fb3464378989e7360baab0e05cb725c5a8aa884989f9b77c46bccb696d68f133930982f389db3e0a398af22a591867d57b2714d22366e362c2b480247b7573139e8a3b6f1de8b7d92379ea58f2df234468190b5fed1ebbd5903cccf8813687a45be4e77f8a8d718917aec3563d7ffacffad61e35a5b3d4a74806520eb74f944a86ad73bc99c14a21a816aec6cf32119c1223ca6b6695c1a8003d6140653d290b4a0a2745392309b3024d856f9e39b91d0aa7818daaa37ab0e0d0efddbefc93916ef8f0f56d760430e8908405a84018aabb47d9cb6b6314a52db766ddcc2ff868e554d4415f5a8eb81eed2693d650f677784eaaec5120297e7da09ec50180cfb0769fde758585a93a8d91b749316b75b0fe111fb07eb7dd11673fe20932b5fdad80f0323253c0d9b3949bb7f4b3854b9c90fc4a5299da5de610c7a5817d0658c703319134648a6e984d6602a22f9e85c67cc0f8dfd70efc32a32f166d9931d1904372c9b4e59b3e9539f216e1fcd9f046a1dc7bb756d5b1f48343018f3dbce7fe81816189b9075860110640dc1a7ed4b7d62b0201e75484069fe5103b1d5a1986ac0c4d0bfc2b912397428b195a40aeabc763ea9796075430f8472d54a94c6e914302b1970930a049599f353c3cc234142c4934721d4931638268d81d31e1b8e1c0222bf23bcfd31890731a3d6e552512c479d20f2bd758870ff4fd54360075d0876b00e23219ff1ce5a17eff26fe1ff1a31afadfdb1890720b321c5c9f721854861d85f2a9a0b04934341e2ae0ddd0c2c51b558e777768e77675938f69acf9f3985a426641e2e6104f6aeeec06b23a0d488029290c8dee37b2e990703898edfdd18b07aa2f4540f91823d0f24ce08761266af9bc8194dae972b1402c3e49aeb9390f8b2e7e2261bea498c68b9ad4ca6fe44c1930edbb5c571a3657e7171b9ca4c106197dc3129971c8f511ea43755de583cf940b00ad2cb1185804a0ae4f8154ea9bc0d413552da3498fb3667889e00039bbeeeaae183673bd7e80b246917063a863877b0f0edfbc31e6cb864177a0df5470a16924d00454bc2d6f9306ac2e74c3f992df552bafaf274852d24d64ee48299dffda6fecdfaa3d71ffb69eb2d52e3a58c4b19a95b3884ae520ecdd66cb0ffdf14d7c1f0954c714daacf8924e6e9b05e54cade511208b8787b474a3fb7bf55b3e15b65c808d14fbb6a6a16bbc340aa0cd9006ec3648cfb4292e1883f0a365a28b5eec649b94294159e15c54e82d32622556d01bbd5748496aa8a69da9284bc531a9d8351ce9c9d3e139e3f03b39727c8f91bf9db71e9dfbc6e41484f6c7ea175ccfe5866baca90fdb8dd79e133629fe07bbc87d685cc882dc73e76f40705abab07a0f991c39fbe938907fb691f367737c0571daafbb420fde3aa1e7037b34ba0e72b8662ed310582f42d273fe9934ec0200454fce6b877037d9d069400caa7616963d0926974742ec9b712e644af78b9cd85a7414b408db8a2d13319ec84a8beff9619d583f169ed3efc42fb30d0b8db6a6a5cab12af6c8a071490e6a5578dafc694b2f45e46bbd5ab0321b3cee45ded1a7031a1b4cdbc40e5e28abe5bde571c2cb6b7d04a28541d4f9855a9a0da51863ea72f79cf658f71bd93e1632bd4d15fa20c336255cc0a0fda5c2e82a5f942bee49637f47db4ece5ae91d05be1e85e32e4acf4e061015a382a59105264b0e307468b4c73b04fc1d2a6b9352b1318ab29b729d6d33bab916bba856afe115deefd268b875d1370999f816b58d576929da87b9cab937e00b93908bb9cee3e1ced4db407ed2951f2c7a0bd5f810beec2dded5d32d08c3b153290a24bcd491f18f4dae0de3dc96b182e91c8ef95c878fd69ba3383fe6620120ac97d50f1a51974df1da7c08855cf2d702568a68192b9e44db79394e96941ede9e9d5db0233d92e8998d8f86bda81c8a2f7513a87858c21e8f45ec4701ecbbbb8609d6887fef61b767b3f06cd6e5f60858b6024aca375c5be28b7d30b5cdd5a8946f7f57d0b9154a4d55f1a39a534546bfdb71e4bad7ef75337a637d5e8d5c8aa006c5da21c77526f07a21c8c4da21dd2856eaf6088b51a66eb35e47dcd7e736e1e5420d263637faf60758d5354b01f58b2beae672ab88b82d35135dc7f49a9330ad7d68d5cb7ee3b0eb41b7b5e3203fc8d7d93133fde2ecf50fddbfa3b90da05f3ea817bab36bc619dc1df2422ba775037c1c01162ec5e0a304b024f81afc636ee565e54ae6cf476c06c5b67958279fa883b7b3aaa191ff6c7e648efbee047a07da19987fc0218bfd4b8fc096b4f30f2831ff7b60e9cac3b3cb1eae726eb94607737ad6a22a503cddb492f37c5b4ce468450d54ba638d5d96b0bb876265604b9aa56db0bac9a5a016ec6a987d4e13799519c80696468a2b988464a3d2c1adf1a6cf0d355dd5594a85a5d0116a3aec6a130e79efd8880ea8b3d10dc0d3728ae61d5acac778103fc3f3faa7afc6704d83cb33bb46c1b99b2312c3512adb87a8673feb6bb73f275c99c90dd6676d0ab50ca50167f75fb10a33880e21a72f26e67eee3699f77bb3fe0c7c4e59ed97abc5d9e1b32f670bf59ae38a3eff3ca130cd387a4a590be7d08a437d6f1c55bfe244f5e3904cd30cd665e1609751bc828ae1d194c27e01977ff911034f891247892acbdd8c1646fd0f5c3b252a8e55197cd5d62d1234dd7bb07f128974132a035b7be232a057e37cdc328bb0b42678dffd06caf39ce6e3cbd4497c523409022a18419b76e198ec05c141ec1327aac3f8cd42b160fcc3c49cffead9bca4ac6b68cbb8690740696826fad374ebc151d03fc002178ada4b2e9bdc2d007e9e5c253f65e253f36ab40ac4d0e55d348bde6cdcd7d5d4e2d7be34a94a4087ea6833866a4b452fab2dc93313ea1e6528077249dbb6ca58677daf25cb4bf41ddaceaba23d00f34f62e9f723efe9dca1bc1f181e2c75a2677f555d787d4228a275b3ff2e1a675f42b6f51aa24e207b8bd2199b06c1b8ebd99b925caa3ee2e3a2414af979e338e3ab92f06ba2e2fe01133800a3a05fdd211fc6da35b1cfdf80224eac36b8053febb6e911faa31832e18f4566e8d09f79e1b0e1a7a105f5b82cf7b38eef9cc749a2d03cd2244fb8199433677cb26887985996872fa37e551a4b9cbc06f578e3bce64d858945d1b47b8b7837e652c251d96f77bd9a0a5d837d3783349d4457c34c98b150dfa0dc47ca5d478cf6e073a3c434a71169fcae4dc4ac3d8afa55956e4782908676da3611e10a821c99a52cef53c025a9b66c22661c837208e542178151cbc008d064402cbb960592d40424bc96d88bd55c4415cbc7599840d641afa1c187cf96c2a6fb1b0e34ae5536eb5137b0baee31aafe4025c381c57313b183c235ca0d3daae5d9bf1f4befc4944ec0023c22d9f95bbf46dc974449aec58ae0ccae9b44f25b201a1436cd0b9e8a85c602d812a77c31b88df89f1a71fd3a51d865271971180b785c846e68f7c63560981f6223bd9b8b9cd8831a018c2dec1b8400c21b47ea7de2d19a034cd3de485605a43ac28b2835016cec8daaf5214bad23e37e0d1080ac29519bf2f5d0e317f30ddce5b42340cd29dbd622c941ac4d83c4ad2be64ee121275039c4955a3eda6aa1070aceeae8cf46877f02daf1c4975d03d997bc1d8120cb62e24e1220558344a7a9b90637f3f85f60164eec076af1f1afec1f1130a604085b183494b360d8fff1a6e47629eb10c4128eb4a79c3bf65f414744132a2c76a77f1fb7771b5f3c2a4153ed3bb7efe656b30f16d96924e5a8809c01d6e7d08e6a0631b90f5b05db0396a3e692bf73724bd6618d0bbfe746bcdc93af2e99c096a5f0ec421d232c4bd9571740cf4d0cc162e6463f42e6d03483ce9be436c05ededa23a7513708c93b68b148bf3a1e635ce7115f29676821dc0631a16c8c8ce84d4d7f852520f2a6862e770c67479235ffee4fba5c354e214cf59579cd32433fc56fc389494ac9ad718d9ca0db83cbc05e28e17292bc4dde4f5cf9bfd42e9d055e2aefb8b0a4a1cf5d183c351b2459ca3a06e0bf3f25351bcc1bc1f5f442bc43f63bbb5d81bdac9c8caf0abb54368dabdd84b53ba85079a54ad7a0c98557de5373813366ab1750f2a378c5c4a99e567d983eebca9febd6db1f4295fa461d6a014787bdf00a6ca26e9209116d02e0b9a1f9407be395c99256e889baf53b16faab17714037aeffbb430fcf7303c764e74c8399b2dfb9dc34608b41b8b01bd17b4f82b271a5602c3b830795911e1967d95823f80443fd1ccbab2168e0282094231cf0f7694bcdc36cd6e00aca1058bacc5b84b349a7017ada20747e4e06874c95db3d845bb6bd25c60cd250e6f383c4a98f08fdb7d5ac5de0aa8543fe1cef0a407bd776ee77446117b182977912f71466184238d75c1a6d0817e5f3f94d53886f425f13167e8974a6b7177d53fb94b016e51d49bf4a3977ff86679fefaaea41b99d78d91039f011fc82e2893cb19e975ca1091bf0aec590ace7ebe1d6435c240fec16196ce27cd860122642d301ff71e1a1857e0d4f70238431800f20621a590bd371e67186f58085ac4e59e92d2de84613c92dc4a2fe0f1e42b7f009c0af7257cf473e89045f41b1748c7022e348623e9d601b233061d9525554497141fcc9284abf168a87473248f01f0d2ef9f0739cd6aafa1b10d507158a27e5336f48c74ff1e73a88b64309183f51804cbfd0bb0b823d0cb42cd9d8b1cc2bdec81d437d33816300f166c5876d7918021af476ed90e4f27be6cecf3e932daecb3398ed3c341a4aee0b708e6524434a183e9be830abf3f4564b8a3a1a4e1f7ffc46f6b2ec78379d8dceb0f60005fd16a6c3b6483a5d0d467ccedd9ee112c327d93f99a29481cbd0aa52d1a124553a674536d03aacb317f249310ce2f524b4a32a73d744bc924aca3d30eca62486647acb9e32cb87cd136033abc5783b1c8565de29138d9d31659b4d4ff04659253df11c02b35a29c777b92631f499047b682889695a5f4dad02f38410295e33277382cb81f33faac2a73511daff6ad10e48ba8ebc309040db14d26b68b9a3d917cae1fc9a7f859c244b85f080d38cd47f7212642cd3dba4ad0095ea732c6df95a9ecee978b5b0e922382da9879c13630b8d0982adef16a817a843ac495798a7c1061c5c84b6f367c443072ebab0927b106580b33cc9e6495baf19e9fef816d519677822c060a344a004f02de2c686ee489261a03a8c47a06508772eeb2ae81a1121c8b5322f998856214e9d929cfeb30ff274e5ba1bf898ee91064fb877cfc594655f024f2390cba73f2374bdc4012d602344e1faa4331364ee28a7940dc457807656ca857c54937faa295e3545a855952685e28622670d23fa16fc3f4706e813c9d6a06072b987747acecf7fe634f6a5ec0b1ec80d2f8838ed829e50f1ca2cc60fea0fd0611d4b114b349cf0ece5b13937babd0ca4650d3e40ed8cd30978c97e3942d2340708b4a55da0890f0fe13c0aff5f1a995e8f497d665642cdc9e85f34872037dabcb3448866f44730f22bc9537ede030168eac0ce04893a56976e21c0f6487c3d7a3816437ce8356a982274ef2375fd53e6320026bc25c31846af9607b7b80a270844052021f760c559f6a8e903f434ce3e91ff72eb1e61d7e88de92df508c7f31a23bb8eecb6cafc91e8428c7f756f6c63b39f3a9ce24c5055c5e16f50e3ef20c9c3a9b9eae6fea2de4277c87bdd67610dce0be9deb6241b86095a1320d9995788b42f11d94d5b5c81b2dbf10cd95e5e5c4d7b0dbf18698b32d9b91ba99165335b7385a2b690755fa9bb691d9d2aa359fabcb995226e49c1b51a2b9adfbb40ae12efd03ccfebaeebeb7eb9f9487cf2487ac07d382b0757d16d884140e4358fee3acf53255bb46ef06c46ca01ed9312e21d08fbeb3fe6cbc7d875fb0ebe05baed8f22ae1d5b5e9ce1d71bf0d244cdd296748412ebb2fa9150afa88a6267ae24419458c21bdc76f101002ac8e5bd61e65167c127e5e383e081258ab3f9a2cd8fe60d976f521834458286091977ece2c0fb0e9039f14373452b0ef9b0a6ae03a80f92cbab288638911c88ec2a4aef02c2bad8d93b536e057443c021ad89b54b83b208b54736c4590865de512ea07a0360648aff8f6a0c691185a7615aa424491edd2674e16d44f2d4154856050bcb158454b01edafa4f6a9aacb9ceb6d7fa15abb349040e6d3b653cd943ac2ea8146a3407d8079374769c07a0814a32aa731ce5051f7b53fc16a17a269c932f840d6b6803212a24d270dea4cb7e501fd6bf0adbc17d646166d81cb04840121b25f4d4f4b142eda5575e0131a4057a13e562f0938e832fd3d90fcc3c1b2a4c5f3812666ab85d6b751d011ad2aa9b8a3c19736b2fee7895bd28392c1e0dfea492238632f95dcaef865fa94fb6de90a6e28378dbd35fb6392b2f4b0c4c8f712f8d9fee6eb8e9e62803532b1e3657876216431085c1c770d8bcea4947c250e174b3c79a3d301581148ca0028a2d144030b02af612f8a948645af8f3f33fa84a839dbbc6e6952627a6acaf2cbcbd343830c798de567defb8cf3bcfe1687e25c6ab1dba06d02c135fb39707138e9082ea4a3bed42b619f431a3c312fdcef512308c80ed94046efa73dce90af5a30284e8f1a668c6bd1329e8fcbf61127802835301da9013aa17ea777626793455f7d528b10d83e892666960cfec3e52117ff6e892e1e325a45b0bf8b4c7e367131f1e72f6bb826d48158c97c7b8bdce70de0820df2908a9aeb66b71c2c6dd37e060806a4dadb02359df8d319c6dfe8a47cc8bf6b9702868508b038de50c3c881c495debb094b18d446975b5b7089fbe310b6df3bc1f099bc7ec360a97a5ebc089a33585dd333c6f86046252963cfc043c60aaa023d366ed5c26095f71c522cea1b646c8014638c4d443dd59f22c0859b0ca66b6af1a7e01086982b9156a709c5d4141d39bcef8c2baa08b5cd8fbb8bf3ea145166f5ebc0ed6c63b94d49ff12d4c2aa1c5a6861b185a91a9567a29c41efa848545d342ddd1311f7088d8517a101c3d678cb71424f295640682b8eb7fab4e265380ba978d1994506343d0c8df009555020d696a650ebaa3997259aec868bb467bc18ac68562cd3e1ba17effc0f99a2e38347b146717a8946b531f0ff7411df150eaccf319a882aa7ebc1b917224e1f885b7cf893c6aba45c5df2074463dc198361ba36ea0e1c0606dd8144cd3b239dac36a16e299397d65358468bcb1b8d190c20f31a3ca3d3aa87f07a7ea601c06026583a3dee90a23146b5aa7efcc64b0b93785622a2081be6ab7ad7518ab4dcfbfe7e772707ece05eef02ba2f748ec4cc25a60ab303b9c3699deae6112376bd445ab132c9338e77ddb3baf0ccdbd11266f6e3fa889460da0245f288b6208b1ced27d0ebe8f9ccb404b9e41f0ef85388af9661527ded158123eee172b1c034193637c9e0547e0c6e73bcfe211a152ac9a76f292e946478210357b5a0ebf3f588020b7e1ddaae81bc93986d05fd1520b226ff944a524a3cca7656e2b24467e30e3ead0f51c0c764810eef92ae9e8c3ed2b54e2bee7d1d10d2dfb70a4d365c13937b0cadfe8a5660fd1caaec8f1eacac84e3097a6946a70d8cb806cccf2cc02de675751c95d16559db5997067d38ddcf0f26ccdc94a0ce74bfc681851b0a58841cb3f423d4858012465181845174d6276e6fa0adf3daefc7d2e93ed65620601099950737781ede99cb9d6d3f6925c330899cdaed24a358c981888839ffd85075d85f438e3eb0bf77a942cc98600084d8f03fb2660806df93afedc70fc3e4bab353529b166bf06c349c64d8df73b07639145058f383b4e9af80e039fd98b45bfc10ca52d47cca199723d82e5ca213f67fabbd00e94a0e4023cdae5a604d41dfcb20419d6b8ede07cc78ad9b6ceffd6001c57687221c9ea0c2d6dbe574c050348ee2fa1b36c49cbee166725eddb28087b3a39a34c5eefc1ae2416b1f8a12c4c846edc68302f605a643ec9f379b502b74577ef678be40b64f37c61e31037a8196294301e296550d6210513ba3708081e58e7bd2f6d2c0a2599b587f4f3aed2bc7e1ec3f6efb2e9fdf1e4b79a7b8eff7078c6d5fcbd161d608424193ab81e7a9208c796253da1aa3acb23c958137de601f012d08b476f5d0cbbfda95dfcfb94afd0b0bff6d0ebcc851796794fa851f47b5a850ea2b4e0afca738de0d1acfa650a5a3807b49e5f986e18972b4a8fdada576c2b90089e770e5ab5e1d68a89ab2480f59439acff4465fc7a358eb69284cf242a78a381c329cb3abae41bd6afc49dbf7c91db1e2dbc05ea94fc020e900516c4da7c51186680b82171eda79d57a8f0a9a4bc0a59bf5d3671a6cdd5c3118cd16346aaf11ff11c61605ecbd09e77047f61f2322ed3b8d4993f0cd28d7d3cf56bb9603170b3494b9406da9fa72c444126941dfd9b7a6b0afbb9c59c1d78344414f303d1b431854f302e8036723a223e7c6088e42b08e20ea7da89d364d102546aaf73103d95d536496f1b0b1a89198c508df6e3d32cbec08fc18de0192a55bdf9bf25c2d24e5970caee1571bc5ab6154b2afc591516556aac0de50ab9b1a8f4720297b3703451f71460106b4b3da4924b34fc1d4cc40a2d24984c914656e98dffe3b7a0a13e6a8e1dcdc1ce65ef850dae700814bdb788a66d0ab7b4ce9a6be0092135811704c50dd13b03231a11e3cf1b1ebf042f04f1178c3bf5106b4f752e92c803003b76d70aa1e3ff24155ccd4e69cffbf60392ad0069ac24002328022297553ad70fc6d1e7174fe5b1692230fe9eb7bf3acc5e5197ee97ba871865871d2ad97f4e2283b1eee01d614fe4d0fad60e091d4472a55d7face026d5c84ece16e8a692af620a106211e90a1c28dc847b4409cdbb13eb199cf5a5a6b66c9537205f233dedf91ec6d39cbac1a34f4c2dbdad5b9231b61524eb77c48ccf3ab34fdf5b4356be85927cdde0fd21a1fe574165436accead951c5c3d67bfea7865a00dfd5c05205e3b2752a9ec1caca7a2fc7b0578017edddd99d0ae7fc93f0f574eadc280b03f947884960877f24a966835d158518aa1357cbd74c1b2c6a0a5835545389f9b02bc99d9a8cc9e512ac7fd9c670c92d0cb899420582780f78dd2733e61b438d5f264bd1acce4598886664dd798febec45e472be096c55a1e7bfa3b037ef08e5a0f4f99594ff67dca5f2718533f39c12259f2e97c45e511ce7ae502502ce1bf82daf5b46d9b8af8f9240b9b3fd7e603294cfc5d6e35837bd079bf76a2fef6f879d32747ab00bf81e43c3c674c06095a3aab91f4200d963f6526f04d578fed69b28613c51336bea5aea9595ea108dbff09733051be31951c2f401c2c048ddb8a910c785eec9f9bc57b230e820df2ec6d875c734a290155516490148fa1511af34ae78671239375f2b5603e1f1b0ab513449fc508fdf7927e109477b00c29be176c5750030c9c02d808798235089450b3ddbcd67ac10acd4f0aa9cd26a2fe6f6e4b046aeb4b16e16d4639b1149f76e8e731f7968b478ae316c052fa2e5b896d5edbbd379b8c19d5db874ddb9c36912568c2d8bf60df30b459837613f42e91ace8262f1c59488bfd002ec0abd92d5a14eda2ca33e23a7d333197108c8fecd12244a7a0c8dfe5369e6b4bdc302e33e14c14b4b7b9be4724ed1d234abd90d99850f118d2ca5deb162d294894ae1be46ee74792b05fd77583ad1a4630b29b8dbd20770deac3f634fe78b9b3ec28cdbec6bc1e82a0c911191514e4d84425516efe4ae3d1002454aa68b867874431ab5da682ab9071ec80c192af3dd4b3bf1747981c580ed8af72332ffbe8e2e9970bbdccee2863a70286d2e441511528fa90b2431d6f533e38d772d8bd1a71bdb9146f1f0fa75f607d5f145db23c2793fc83d54c14e99f757eaaa3297442ef8ce5b35934b73bfd2e0b84e5a161fa02778faa5de0db8ab5f530471c100dcd644682ecd81aeee818e571fc5871e27e26eef1c06617210c8eb2d6b760ae2d3dd5ac7ee40636644502e5674af9f498fd7abc512b866bed73951d696e27f135055ae184dabbfe0f9d46f407fb96a26123bfb88270e697dd4f5427a5e7de61841303faac5f8e008bec7c59120116695ebc775eb2fc3de294ca07d5c258076f4da7e03d42ff5da78cf9331728b15401803a755e3d3beeda1ba555687ff57f9303a9203bcabc6a4c0319b9b0707c23bfed342be61f6504a9baf18c684fcd320f651692ca8e5e82da2ac440c5360ea006c241764049bd6f940f120676fab899dab95d3db1ad4872bc5a8a88b0f4c08deca8e948ebe8428bd3f439d3991d862e6d15c5c0f2636a3a429afe8745b1e0ddb4a19bcf3b3df1bdf2c29bc65e95e39a4c4d50d13407f4434b269ec6ffbeff459632814004e9ac72ff18fe3b3ccbd28ce8e7dd3a9e7afa0ffb7690ac865b3a800311bb1689f6110465862546b6c77f1ac87a54a70bc3f9476947780c7220b34e0ae15a3aa9d708083a99537ffb813704b567f6be9004b6c6e9cec88284873c070f61995b15a4faece932332df44d59f752ad9dd794787e29cacc82fc4fa9227820c4dd2297033a9e65d905462afbc62fdb03dbd3cf455fd8a529e7c5e8d425e825326d2f33e292211f2aab073f30563c36110c220e8144cf3f257cb05e214ffb45d383ce157ffd234782ca849a02446060a3e76860a35f0f14aedf904ae766aaa17d1891e47e8f20a9d199e789ad29a2e3e8edc83fbbbd3ea0b3a55ecfbcf86000fcd69627dfeaaa6f17d718adb8ed3754945df32ba3d83abcaa3d400b01a3c5ee143d905b1700b90661e98486fcc1a8f1115336252274fe7ed262532028aaae0eb7f87519f0756606401a329bdf46b384dbd5f0b1425970e13743795d1bea76bb8ac7724cf86af8000515c2f335cd968a6f94ba7e5127de38b11cfc4851b02e66c38f284d7ef58ca91ab6cd9e3c86498cf812d721cc0c358eea004c698289687b8926f22e2c9f8f9c7f941a8be3b467508080e9cff1246e8c749bcb94cf5c70be4db212f0b6c1772bc6ce85ad852a4fff6a9fb6b87c04b6bb1eb614a6fa749fdc6a3731016a87adf4f0f75089be8e940e6ef65f01bd71d0a5cdd26ea15880d8abea6abdc29c8769d5b5d9bc021f650f2047c517ea7ad68cddd16500cbf70b03887f71e1eed2eb696b9d80b63456b03ceac39ca1d2a2211f5e10fa9c6f71ee249846c0ddf143a000d200969b7aac24704bbf8d1fe110651b36bf2be1fba00ef84a38fe7706fc37a551798501f66ef1d32e8075d26812097b10339935452c3d3caaa7e159a30ad6b331cc8dbe0f230aba7821d2f1a12c1883f0e180e464065bff9cb2b07ee1df3271c23b01be5347efaf8af1e1ad5821503e6862ec4f48c987ce73278cc7629a4639f5736a52a20c2816a0efe84a3787735b0021decb2e2eedb35d1c017f124c04f949cc8eedd75bce3155e5102beb9ff50ced2586da5c6caee0a25b138f9a76b98ecd9700c419269824874fe2e7661ed3c173bcfd5bc9fa70da3c190c059af66db5994e2d47bade08aae4ac0dfa84c72fdb9b61a3b2be1d648bf112e60fc53ab0c7086f5f97ae0ceec8516bcdfac4b39b35d9c3ec7b005f7c311f287177e568749124f8f47a1f504800799d8538fc36637d6f556a6680b4b52b2a4e744258e9e79f0c0a1d84c46a1c42589cccbc82dd155851553523f19ff497bca5b717b5647084055e6eb9b880cad296d02fea2a3b0e99ae3a6cd71314c0862e146f4172c4480c11cddf607e82347d61aa54503ffff41e5d5614173169a2e773c13a3068e43fc45479a26d7f73339283b884e0aca4553118e88242b647f1150d8733ca4f95648bab6b357387baa900c88ad9fae01244f5556192c46479ada8f994e21760baf47f9f6265e5c3d23439c894e49dc793104c0afcfc2977d12cf81fde6cc6358ff411180412d2a40cd4fe35142088234085cfc5feaace2569f5777d4b83b1eea210d9b1a27206f631b9852b01e6d7d1bf7f5ce3e321e62e8d7e12e67cc7a4f4fd26b5bd123a127d793c1170e0d93daafb31886563609ecbff42be8660c0fd079b7f60b3fe1a5162a1c5f95a16a7abbe3c2a396895d17f3e2e45548bef714eb22ffd071092b86b87c2b6cf21aafcfa87f7e28ab2907b0bf9eec7f7eaf928828f5e95ad01ba6e3ef0c87a72a0877d3853614b1688b3ddabcefcdf804fe36b6fc4fa2852b1617757b1e8cfdd7ddccc5f5986fda111cacc3e6a8099038fa5a1800274bafa6b358b8c7aa52f2804d01d57fa9f9bdaac7f257aee3ae6d7727d7ad0f23429e628793ad9bb241c56fba7d4de7c9a70cdc026aa4b0fabbdfd1f8f61a5c149b7ab84f47b6da0e22656310c794194b16ea2270bc29c43f6f6e8827cca280115d0e9ce58c9acb3fdba48131602e01a1e762ba84a93dd501bb8b94d49d23e9374199d1c9e5511c6a4b699ecb3bc2a33a2a461df05d1c7dd6134bb6e8586fde4f0c935ef3284fc09f8eb72e0cda9e6597b16f76fd79d8ff7fa8d8f5f9ac37dcd9d36f472f0e78a2092bdd4390cb4bc899759e771a14c3b64aeceefbddba821d3b946449a9bbc120b0e1281d01661088eda44275ddf72a352977fb2594f694d14f63ba0579dd0ea660a37055b605b8f572514c04c8b343c5f3555ff7becd765e0a97a7bd988aec35ae819d78d837a1dfd539bbd3464008d733241d790d4a1783418d1d9e30021f15cc458fa462216bc34357920a0b2bdbbfbf6399b1e6454456a54a38b7a358db0841726e9a4be5bd0f60e70b6fd54fc6c44f00e02bb129fd01e9f30915a87f673d898b620f82ecbe264291e1751dc4feb18d16570d75ce734fa6832972f4230650dd837f7932d5a525151d024fa69341f4449a833b34cc59859d813eaf9019fdd0c632700bc050fa0f32d18ead7fecb65419fa4d0aa5fd5fcb02ca3e03a8fb544424a47cfb387eb2ccd9ec4a1d1ddf752039159e8ba2521864720f839509534103d0107a02c9880f4408e74ae529a500f4b905e10d21192876703fa024a484fe2484bd77290eee15e9a9f76f5c6860073174d63bce2e1108cb697d462c9a0c522055dc97f47f5e4b7d533ac8cae6842376e51b4bf118200eecfec1f7eedeb372d47f8f9814db777128009c21df2a2b4a57654cf3471b47c764bf4b162ed192da70cd27fb9b9227002e8cbf93b47b23a2c73fa1e9c9ff4523a318ed0a5f76e6df6a4298b1f89c93a5ac87e4ec86b32dfbceac35ea8eb5e2654e10d45c17902c22265346b4a901a5154262e38849de34ef88b1dea14ba3adcbe8c3619c27f36e07803083633f962c49ce178f75aae8267c2b6c53d61f7ff6d924ef98e2b4b4538cbd01a04c29497e42ef47beae549cee07830eadd29a16dc715ae1657713651cf102036f85f958128f326c5dcc7ab05c3259e71a2450f256740cdb6a9ce46ed2042fb80af0cabd346d735503d964c334cb470b52de8c070be69b9cf6edad648d93ad80be56a4dba8ebc921a6de7bcf6995b88a9a981c34273a05a5cd36f2c64e5c1f1ec2261d206f963ed2bc66d41071ccfd926e72c2b19c22c6c46594799989450ad0669372e68b3f064c882e850ff648df8758fac28f4ea1ca47edb8a26ded8816e6d373ef03d40e788d5d021e5a23d88f997acde13553a57d49509db31783cf0ae1e42f74ce54dd47ed1d56cfa38a49192e10a04b1d4a3874ea0a491b3e1c6be3908ee70f8aff7cb0595451d13bf962c1953c8ab7633381696627aa7a92fa4d67abd95765a918f3145fca80b3b5b04b961cbd37efe7af2800d866d7d0d1930811cf3f1b8f26cd4dc56f420698346f4a1fb98a150cf9aa52aab16cb2c6ed240193a9ef7f0c571594034dcba31cf4c05655192a9ab4d44b89a14efc7edd8a870fbb4855e8ed2d1629910070267d61ec89193449fcf02dcceb4e912b40570d4d327b6008027938e9209875a68da2efe0237a6891b3ecd6419461b0bfa215685d4ccdf6fea3795ec0975c53d299ec402bbcb14adfdb5848152e8569529cddaf1cad0a1afd70939dc93de95e1a5d451131641e04994bb26a77385879a0d25b57e3b1f7d4183f8dc201a66de3b2d9635432c194d0f1d9b1012282699bfa3bc26b48abd93b943fdf04dbb7d031571544bc23b6c299de3b621f1394ed6559b9928bd4c71f487e54c498b292661db85e0fd6b4c344d5ab6a74ca19b220f8936100e7ded218e8d316c8b05b406d7c0f07520a98cb1bfec224a4a60415178af614f871dcbf970b733f5119da9f938c79b222325a807c50f0f5e510b956708b1e9fa6ae1fc1676565d4696934a5f2569186f7caeded7d0a365217ab151da9b051e741521af2f9267404ea1013e7885885c4d41b7e12369cbde1246e195cbbe4c539ab30baf81dd7ff841e161276c74f50079718ce31a5de22dea7cc469455b68ecf21fb61c8a64dedeeb3ce482158906c3aed038e5ac52d27732f87516ecb92fdba4ca50fe34bca92c3c7d2c37657142d8d769b56f4b96eb2b0ff4f5a55667d8d7ec4ee6c58f8f6a50aa1f0f902c97ee139b7ad89ca5ab9223d703f8bfc38624e960111c21790e8482eb80c2b5af83984d88ed4aa9b46dc543e7300ced0b7fa9273ab27f131f1ddcd5e5d8b6dd73f6bb6e86e1e02d489269d8a24d3ec8136c10e1066406492153ecb7d3502026076f7b975a78d7c2b42828e335c6cc4593dfdb4217dafd2da92cbeae1d5dc8e5008adb3e50c057409f6bc7167fd2519833456a9e1c09f63129aa942ea4b90150a39eccd7b2256cfc0e4de6bd5196c8f8a2ab1cf9a17728fb1f91549e8018cd8854581585c5c65da845c415136e421610ae191136ef0b15e083dc386e8e0bb11971c1fc4553efc74102a1c2670e6ac2203838e19d2c1a7d3f92ffc89892fa81194a863496a694a6997cd1ada9ba7434bfd5cba489d106a1f05a792cb62319052c35d371ad0df4242883cc63a0ee8b34c0e2b750ee1ab014876dffa13614e532cbc209f099000011e6e1291e643fef1675581c250929d27283d3db3b08f2d092d892127fe50b5c78e4c5b2a9d6d2b5bf98aedc2ca445e00384bc405a1636516f0caad3282ae6ab2512584c3716922b33171cfca4d311bae8ac541417c8543e763035fb025ea7f1e09017153c7281b76f7860d6c3098bf0e91c31ac6ae71e6cc6d8c0ae7761d70eb5300c44e824b8f53528ede13a0977afa46e3fbe9e266ca021848426038a88b0aef4063538d2c93148b2307f235fbdf3fefde9c2391ad011c9563762072310231a53370803c57db8b382c5669003d74b2d3f4253c9f4620806a605b240094601fa15eccab436de080509ac49a66b93934210fe8860d1aaae26f11996036b60dcac96cd81868835eccbc441cf1b39247be80caac0195bd88b33cedbb21faf470f2583a4ed6e2e599f3d41d99760511baf5eb6507c032bd4be82c73e8ea5011a03fba0638e20951837c720a894b6e38c9cab2ab11dfc96c1660172b9833a9171e5193fdc9698945add84aaa2b94b45a7ca0fc32d1b15eb2273f550abe842e8a682a82f1685dd3ad83796dd48569c60d21895bfdf25aea3d94b35647c8989946bff3b9c714de2a08c51ec614bc0e403b32287e4bd9723ef220797c65f89a72b80e81ff2f23b0fef9459d028491183d20b51019a284d0a2c5ca1c2e96662b9abdb53a694d96f21f40b64805620dd0a3c1d4ba28eac1dcf79e896eb13f005f21330306f432d119e19b28c23843fe6ae5d38448413509907e2ad7ffcefa83d7c59afd1b381d7cdc12033c3d3abc2b3b7588a914a2c600c7c670b81a0478f6c70780a9b24b2a440f190ec339229686d7723a332649df8445867a8c9c053b93427519c23b3ee59577d89fd3936741c9fe17b16c6966b6a9f8b7cd0bfa45a7456c133d3695fb44ffff849251533a074c3e18e617ac96434a1835c2d89a0c1657f4f101ac8292ab8d685b888725d74edd28317d2741481b99dc5c96014b69576f5076fdcd09f59e4a9cfc65c36f84a56d67b1c8c669b7778a65d3672c8a938440b419a6c80b8dcc28e3ab680b1449772f9053afa8a45915c11b448438404616a732c6decb44876f998e0a545ed2d3a230e380e9a9750a8467579e8134837080302a39e42adc4b22c1d7250b49a6cf3197c2dc27f784e89833e1a061109c2be853fec61a9ea214d6988f01ef3a9c3b061fa6079124d2088aa594f7f74fe96b52b16314c05df81340e255d5e21cc744ac3b524a0462539eb165d654b25856a70150a13cc352e8d06876c282a0fc95ebc540b768848d873a72e2a4702959f4e98e60e4ae4ba29f68fd1b0f5562024d7defa62363a021b7448eed2ef3ba910195724d94287660d1cd5485769a306858822ee2e65ee113892b94d0276fa14c78437bfd83f8e9d6b04b78f43072bbbf1ba580baab5d61ff1ef6eec34d965143db33e4e61799ae14ff62e31d112f1af049ea052d68929fe45d9fc5c946a0f312bc4de0944f320df28fa1da159b11927caa309f7fc56a57a08cc1389d8818ca0629f5af383520e5a238b0a08de933f63165fa391f54f4448686897a108fcd34ef1688abaa0c9d4f7887f04b3ae90ea0ba1a70bb6e655175a01c3c828dac93ec44370ed58ed9ee752a337369bcb8217eaf7868ef28c1ce2f415202073fe884e91df8a434273d7799fe918d2be2962c553b314ac76755f3276149af7183f22e77a8b0f15ae2bf6938ac3a2fa50e46bdb6e3f00328e9e350f236986f3f4c379384f3ede6ef0f5e3cf23f811e1ce61e1606b430bfc278446cab0cc019a44cc200ea7b6d825d76e5895bc03f0b8c1f404cf7b2d81d7c5b94fab15c9885438f1fbe8da1a014ca9436a35bf0b125341091344a073f95ab1d03f0ea5959f7042c6fdb8258e72ee6bea0718eea2d4b07f9125d63f538160a40e036c98bc3fce2e634d618a91c72a2e29fd396a68523072f9fba981084a56aa8ceff89ee9460ad91d3e5bbd1195531aa1d09911294bf6785a1a22163c1fe010eaaf698a7280b2fe3734d90d08aac92e3cc6736f23e13d7433329385779974126afd50d77332c57dd0e127724591fba8108fe1e2eb007d786c300c73c910aac5f3ee3b8ac5201f2cad85c170aa0563be0c7f5a7793fd585566f452bd0932d71cdd3c66647e9308f1bafb37e7596bf71f7693765a97142038c28f29ebb43f70c6a50385652ff077bb4b8b79248b0e5b979519a302b8f13578af2993106b0a3c2184e9b031fcd260fb9feeca493d0392e40ea43b9d7fab565b5f70c7f0265047afee665a6cf156efab6e4a617cee1ac4ca2861cfe0e429fd5bbca2ebd7f257562f4ffa4ea7fbf1a742d841c49ec69ede027d4491a9172dc9a35a45e02b29bf4db6f54a15be922526d58bad60b43823cdb2ca941743f3dceefd8efad45db2185a9607c7c8ec30fd0ff01674a07a33db9590b14279643a93275aec577f62f68b2623a1fed0c5b889b54642473edae81ce8c848dc646b5b640845e3020014c53af686a6927b2bcc7e64dce5eccf1bc26f328e8c7f011577a2716ddd15a573bcc30cd3fc811cf4ba67db42d65a49b8cfd5b1e55d5f4740c6f1b44e7f89ac2a9e372f4a90a70e2119ca58b4fd7847fd0a00f208cfa3e8e558070753ef994ccd66e4543929d84c2b576334931d67b46cdcf6bccb8f51a50e4f7378e2c5dcd9ba4f764de30e56dfe0ceb63d8854857a305d8970d15d7bb3c747ea8b5e6d5364a67e246d1b06104ab71902a8826be1923b69c0955ee7ab3318fbd27d79411a8024370bb5e47bc013103d82f041ff2fe7e62da841a0bccbf71cc6ab908f99fe522e43d490b75828b52171daadfad2dd2d47e56831bbc31e43daac0cf9f0869f82ec622ea88f8bc8b575a339eac1ba88af31d40291f490d5265de4066cbfd7ff08951d5d84e8052d2c05a029f4828955b2b94836ad2ba1c45c6412fad544f76b0d64882e1b0a23bdc760fb50e4b25a825c04422daf50ccefb8084f248cf7c2178169ade76a9f9cef60bf31e4b97b4e2653552480a62a104f310f88e67be202629de2720b01db14d8e2224206212f39f642cd0e82621ff6101127cff4e2f71004efb011495b636056538d9b31e5006f0f78adf7c09b1fbf73c7fbca016b8710894ddaaa03816ca2618a7079864c0b8e0b403cd9645cb4b3494c6a9ebd8656189fc02b839fc5aed3820a77646e004daf33bdd80d932beef0d7cba15da04ea6e1bba5021724ab02172f58810bfc5b810b9957e0828b97ad64b1742216e1b018859b567f16b8106388f844be62ed6603d70f62e6b6de263940393d4c12a7cdceec9bde0f036cb353502ea6ecd4f18eb5b617076a52caa203dae432166ad4934e75c551b558c01c8c6be6122a4a6786f15d8389266f9883c5b93e05ba9d371ada481e03524746dce5a273f7a613944afd8e00cc5aa9fb35dca909d2e69c893bbb7a3522f98cf264a3c0081cbf298a15429f7d755c7a05c5ec34cc2e60931643fbdf50690ba3f6893dbd64403d09ace2999eec30ecfdb8ab433f131e637d6561500421034b09a79ca9731b811405fa2852f293f2400a015e0ed6b53a203df6e6b4b9d396217b4e57f9d02b0846aa8e43f09c56e0cc2f0f5cdd05c29f5a24fead758c961015ade012d87c0f7707aa5887a7e5a89e7b563a22f8adfbbac353c61f95278a7bc0323e910114a3027aba795a5e4096594d07a163515486d4818ec1b4abb0d5ca6c2ba051306e1f9a7b446f0b9cedd3bde0123a620336ca0f6c9c0170e5f8f39d3dbb6c4780bd98009a413244175800dbfac60534ac10471b7be90c876bd1269a6c7befbdb79452ca24a50cea05910537053f4d5e7ea04075a7d3e98442fdc47439643e9f191d3441223d1031221253d1cdcccccca850416489b0654b18112516a81a542b38d024a1e9549e0c954ae5b1401a4f8613497a01c03b62657252a3192100a82d61384c21806ec7005e84d8a49410c08315a09ba3122a3d38d50e4b563bd3d59094d4853041c3243ac28df0e16606775a6b95104283b556488d6dadad752e11a282226e902203215078002064a9478b212d1a6892180264cb253d5818a1236ca2061008397e08126eac1822a50615366ccce4d02173038e181d7a6060d0e3059623f5d34487cb0f14b5d65a6b0fba6e09fb9122478e930f4b506ba5071d2a463974ac061391256e7c44947e7835f8e870e0c125d9b1bd7c6847d8909decc03818e1060e53f81877e41885041995f88c301b46257692a8778402363e0100210a30b4ff0528fa861e3792a8370cd9e2df282188941b72cc1b7a5021ebc486b5d6da2436ec20dbc0031aaaddf1830d417818d284ee81e68c5ea0611a0a1d64d409027483eca3c427a89b7352ea13f331aab55a0b640996618c73f689e203846ddb382e482bc84e1764d49e30d231d03e3c347c5bc27c7c70fc08c096df690f63d03e77ed7357523a69cb37c14edf016cf9ab3d3d164c475758dad09f75ce8ebaa8d9326646d5c0f6300b71dcbdb5863bd46548dbbf36d9fe1669d70ba4c4458130c618638c31c6f8047bbb5af3bd57944f58dab67555e3bada755df57c4ca6eec864ea6a57419595bab2e274ae9838ade2b156569458ba0a9e5686b63f77f25827aa643b05dafe9c8b8743815ee8cb4bf5f912454989ea2829cd8e8c90624646afe93381c6d9337b664b3e519ac9249984c209d3c39146db41f184ed6f4fd8f5fedcb78612c4dab679acd9799be7399d9ed771def799be4e6f269595159695eeb4b1a05a5a5c5abad4cbf6f2e274beb8bcc0c0c4c0743233dbcc8cd3391333a342c50a15dd831b083a9d6056d1d0b468d1551000abba5a399dabb07b0fa7822c3cd6dc5f4195c762d1d178acb9c5d9826bd1c2e96c91bf9819bbd2e42f26ef1b8a2fecfb379c2f253500120a8408734e4a8148f1c9517d786415c2c95808f4dd39260a3af512f600ca00ea4294494101285017f24fb02dcac8a8b698812cd9e2093a37293d8077a2feea556f95a8a103a9c6105cfdbaa2c90e4190868044521131ac0e1daa0ea2f155efe1576bad8e1a4d3210288030b1c5bfd16ce028cd3ba834c01140ac5031231303f3927269419d585654eed20d0e5fe268e8f974952a3a9a3f9a544d669a23a809cebdb2aca868d3e775dca6657c6d750a43f292306490ae4dd024afa931783a296532e42d38a2e95921f110119ae2871a45178663e7470f291d17920ea620a2093b9708d88f17c07ef8f88123c995c0bd116fe44dca6aaf3e5914d13ee89ea31bb8055a89c6a16709dde52003fd835ea27fd42062812ed23ad0e20ba17b0461867f558e628b7fe32ea83c58506badb5faa023db8006cc638707120e1e3db8c1e3c98d5a6b652144b3b881ee31ea2471b784f500daa27eed09e9d53d94b9eae0d0dceb0e1c19093d97d8b841d890d9bd1ed1a05396c788ed32bb9d0ee339c2dd4f29163ae898be3c886c1f337052e52fe491a7fc5db81082bcabfd9e7adda76602380d94db82727b15da49c5f0fe03b5d003a54400f6aecabe9905a035e2023675316be81f60e24c5904f640fe7ff166674fc60577de40fc1e68231503497eceba8753b706da29ad7f96cb9d90f7817a735b674d3b8355dacc6f67191c9572d2fad9ed446b64b667adf4ea87ff6d8c0ddcb683deeec0ec351a286b8c4cb36fbabd7ef7b7ed81da6be67720b72b3882bc4d19ffdc37747065c7b28b9394ea38cf8e9d429d72c837d82541f01c19c173844f94e429c2e6f1c109c5d384a669dac6e5c042702ca2cc9959603f1f2eb601ceb0cc21693dd829ba9a3c9e608c73e661846dceedb7ae7370bef4648fd68e77b3c77871702ca4a0f54e4f4ad9b303eb2105ee295202448b683e13ec39da29588fd2d640eee101ac87897c5a6badd6fad0e9898231c639f7247d3db3f301f3a32e078f071f42f898901feac423656f09eb29b235a025cc47918f156c7d4249183278c4231e4391c6f038f317741c9ab96645b3d7ec6836675172765aafd6fca31c6bcd26b725bbad27b3357d46d91c92b96445b227ae992b8a6be6b8e60e0af9a58f52b19c9616ed43ed6f9e20e7ba340e9c0821e90814484f72d04eb4f84568a019d01290127d8e9b1d65a2eb5b193502ae2242fb4ec1bd86754e202427fda78dc178a0be7d4fc544df5711a1ebd3e7a694726a29f81693993114c65f6aea94b3fdbefc84f9f9732661c4fc949130667eaaf8997fea8debbccf14b4b75701ba4c05587f063ce924c8ec19b0be0c887251318a59e9b1fd65c0fa31604b0f18efc51527db3f06acefb2e2e4e5fb1730f5302c4952a67fe146976c632d3be5d202ce99b4998f02e94bdacc3f81de42a9bc6865d862d2c6575e9c5b8eb45119a1456e64c1dcc8b2028a35890a286e4cc49a44944cc459644f23889406ceb3e76fa0e84f546b63dc688a4918991bdd9e642697039be3b2974b4e369b60cb766aa5acfe84cba4cd7c994dc1987d3b0ac2ec979dda2e9ba3a1d4725831b39fb7f5de03ab2b02f55b98533a8fd997e173499b2d2786daa61c550eb4783ac5240c0fb43033bbb2616630a3b4c9d9226adc38d022cc6cdc2b4618943ff7a71c09c33e6a77a0f4df40b126f1d74011a6c8f6cfa79858936c71cb41d915b3da92b171cee8ab25ba6c068a4efa892650716df54fa4b182dbb45c3ff104afa24d9f673f110560caa5057562b99f9882f057a898918981c19f08038b9053cdaf4755c6678ccc298cfb8bd7d4cc8e217585d285dab2ba6e8c9394934fa594524ad90d0a293440050bc09098a8ae93ee729d7352eaa4dea0904203548021c94e7aacb503d5da0c70e008859bbc012d5f3a5a5bfc0c7400031c48ca9dde3425a31ac0096f0414f3d64977192c41ea04057dc9a44e2009524f663229098e404608739491a008a0705c8db4a1cf79acce9b2f3b700514dba294a96a7e2561c080a2c080049a6d5f02a73aca7455250b26467420b5111eb8bbfb3092b48d44a18d4c4103a09d27403d408072580284a402c900a80787810e12ed456ddf7be9795ab57557b0db1ea8235f48b4e7a60e928a1f49cd21d875daf434cea774ff720e85bab0520f637e6bb266fe965760a6b63d10d440a12eccdbc1296de6ffddae9433f40e9c35be398dd364d63e1186bb3d1005afe164473f11867d9febee0d5dcdefe691fd44b06fc8edbf49b8945fe57ba514d3f8684c97d4a1f9321b610233128319d9c1c88fb611c6c8a7610b978e99315ffe0cc318e68c0144cf694b98911b5be29795c6072d6aed96d2b7f7d200a12cb8eb83809c6091620643b4c8565a2e5cea48fc53db5e43aefc459741ba704919521aa1f884159cd9b6876dc964b4f358a87ddff668512b9359d90e75e9c2b6ac8cd6902e300e99435de01dbada71ff9cb54ea51ec3703bd48595415a9f2e835c4d4a690be3fcadedef7fc10ee3f078e44ae9a1a492f4865b9b7f2a24ada26232994ca69cdfcafc854a12adf1672227692829a55f6d7faa22a32b7f16516823be978481df5ddc78eafb7749f485a45eabf3faa2d7b35dca2ba5a0d08dc670e8392ec356b540cfbf2ae8afb4740d36f851a40639cca0c7054556002bf2dada95a32a5215a98a5445aa225591aa4855a42a5215a98a544ab40cf764b45af6f55229512999cd5e2f95123aef0f17db273a8e2cb3bdf2da2ab3d5d25266baf9b67c950b62d48597f1cd2f6c1aa3abf91569b270328bca49dd9fb2249d7308479fa3200e67d22e013f9d6464b43eed6ac2a926157466a899219b64d4a97a813ed5e9e14899b5cf3e8e8715cab49d5377afe149a39bd220b40b75536ec3b450e25eddab7b75afaea27908457478111ed5b6285d6bedbdb9481147c2fee8714cc2919e5284861d384987e490387ce69c53c29c071eb62da58d140245c8d29096bb7bad4378e85896789f11dfd6846908107437c1214850192265e5da60f9729cb81b4e5bc27e7480fdc0c0e507960af75740955044ddf06d0a3f503481a27575a0689a89a851a411db2c58ec76948f9f3e0becf8b5d0b6640dfe16504a8c3fd3ecd02e5d86a35c27cad560057ffde9e9d851da1cd2b6e48beead4f02e6872e8440effbf6458b63cb37b564a6960b2dcc29ee1b989fe36ad76d2dd1478e7b1943cbdf7519dc32f49dce8787cae69c4e3b0cce6c2b6be8e7fcf7c5ad55eb579e4dbf574b2549452665d249279da6d6a66f6a997a4c3ed4457dfa92c63c67a5a5d11c8371577c447b499bfa34445adc7c44dbfaaa0dc56f885d7d76fd2369535f05d374f3318d3d9837d4e7f4ba5ad115b4ecfe4e59dbf66dfbe6b1a646bdea2b78c5bb3e95d65a6b27cd5f7d4af369ab98a0c56ecf1dc3969e0cbbe50c4b9f3e95362c336c583d968af6d97a790bb3f5587ac60c6738a5cdf5582614b246bd066c9c4757c0f7cbde0a54f3aaf4eacdcda6de04b4cf17d042c9c2b2d65aabc7aa1f818abd1758dbaecfdaf6145a2998a58d6762cd97af859ac7e2f686ef96e5c6b22116c1f670caf6629cac59cb67c92d437b63cf4f8ce167b430bdef7e06eeb79f5e8c04bcef7e052ff4d9f257e0c267dd5d9f75e7f55a9853fc394a433929ddd9dd77aeb5d69ddf5a6bedce7fefbd177bacbbf373b8b320c618638c777e151164b2d92c5411414f079c367e6ecbdfbd21fe1c7226edf30c2db439c49991f102ceccc63f7371789f8217c4b95376956f77eee6a454ca557066abe02f6c8eaca1d97362effea2cd2a3417f59c1d9c5489efbfe59680e9c2633debdbe7b0d61e832dc090a3813206bebf8135e69418db73f75efcb580b74f5980f915bc7b03b5771dea93a310ca91c2c5848901d25d166db1765e6a89932fe46ca1a43d5f4f39b433e423a57419ce29f2a58792536826242454c4e690253824646d702a1fd43bbdfaec98735277e1a15aabbd47afdc618c71d67490e9d084ebb66ddb384e071d66413b571302a77a82253b4fbecc19b42428c99c93521da204c1a413310c15a167c9ce1344600214316cd2b69ec3071cae53faa4b5b5d6d2d024c38288080171c2277d9913aa239cb851a98ec8d9d1e969e5ece8d89c698deccbba6c9155625d947baee5d30334b67c7a5a4746f775676e396badbd168fa07499c4135b6e419bca2c9fbea891bc2fbd47912d7f8eee84c9e69e6ad5ca2eb633cd266d75db9ccecdcaac87d3f2e9b940776cf9f4b464e5ee6c1c0252e21a878046dc755dd7755dd7dd9b2fd2a6afddd83dba467445595807e7dcd98d7295ee8c85f2c6212025ae710868ec388ee3382b62ccfddc1ccee306a464d3e75c1dd057bfcfe9fc46cdc3e9923a5917eb9a74485d8c9338266bad5ce52438374ec2321cc34d30129643405949768d434054d474726a0d3397679ecea6ffe5987294ac94672cd4d69e93da8bba16d38e36d58ce88a6aafae73d94638991b7726bff8d493519b0bb545dc7cb69eedb4b536d926db649b6c936db24e7b790dfdbab552fb7f6b6d2dbdb55e9b832fd4287567333c9b567b69afacbdb497f6e266cb6736ce8666ae59d12c168bc562139c3038d7d9cc5f60ad53a9ffd56acf6b5d961bb7fcd271a76d9ec73ce6318f63cc6c06ad4c166a678c33c6b8e23ce6d15f743a959a79f48bb5a7f0ccd75eeda1a8532bed95e79c8e63b1582c26b3e546cd0a4a79e79c33e358c6b1996fd8eb76bdde0edb2d7bbd99735bb98cfd5a4e2693c964a88e73c92464415b6b26417b51a3598f3cba93d4cb04e7e640c9cd3d77983d166a7badb5569f77eb625dac8b7d5dcceb625d287ee85d6cd3dff2e775e166da5a15d38cfff33a1c6e7e6fe7f986d8cb336cad775bb621cee3a63fb91bbee41e737fb9d0865ad8b198428b9ccbc5b9b40df11830242d9a1f9a1f9a1f9a1f9a1f9a1f9a1f9a1f9a1fd76abbb57588178a2556e7dfbfff85e2dcdfeb4d65dbb66dfbdef340b9849efbfbfa5da7a2efbba993fe8173bbcb169996e786d47e865ec76d2b9ea882e80fb86b7bc0fe7d0bded7a47d49fb92f6355f5c615f5315418b7a9b6d8ab4ede75f1935abc74d9f459bc27b6d53ce6e0ab55631a1e73659d004ce7d67b93b6d6dbef679afed4695e5b267fe3bab234d0f5adcc6210963daf7ec77d6fe665fdbc66dc5155bfb0ee440518b796ba16822123523d3c4407364a252f1a05695aa09c72191a0c025620256897c4d01fbe268c46aadef218c072540301e7a603ce8d088c598429c58cce572b954482829d188599775b1b47ecff35e7b1c8580b6b94f81fafc0db643d2dededf148a316c93f734623462d64523a682625dd625b2605d20988960a411a34b2a688275d125152cd957d29126ec30c30e3aee112486b4a9091fe80be5083a521c017284e8c80f47823832c491228884202a828809221f100d81480aa22947768ed870848748c8861321d9a13710bde0871a44406c513fd290520d1f52c20da29c1651cb46251a897ebc38571a5202510e516bce20a59425d8f245bd7d82323a3931f64f8461db0f80f55a984d60c2941d82fa73a740e7ac41ddebb77ef6af8a7d41793f7b3801d82b60f64a4a232d6abfd7b77dba6d285660d730c76ca9a216881d82f6d14349434345434843b56e296d94b8322d4407e921a11aaf1a3af259ca257690c413b11e7a10820c62d41fecfa3a881d42475bd42f44941fe81cc51029845a3628098e19044ba2ea93694b58500fb6a8df8d2c0c7410da220111d235d07828077a077a053a68e75f15c4435bb256ce3427a59e33a55402390c1757eb9b23d98b5dcecf7352ea5eab755cf3c6558e733a39abdd0d73b9ab98cb9de66d9fe66d9f9ecf993aeda97c2b2c9585c5e964e954563c9648812438a95214a599d1911152cce8c8e835a9d24c26d5271838814ef1041668a787377252a75eedbd4ee7edaabd177739e3ace170dce6e1705de7e178ddf7799fc9e4e1a8a8b4782c169794c742752f2d2b9d8a8703b278acb9358b8773ea50f51d942da89616a7b325dbe99fe801b05ace8262ad75bb751c974d631b7e0d638c378c2bc618632de3fa1ab5b586b97acb05129b4abbe3dae29f6fa9b6042bc37624dfc199fd45f19a6ff6cdbe99b31459c2a6f59b790d651967b34dbfc588b6bca88bdb0285b624d11626680b5228b6c0a46cfa2c2c2c51a80bbf16d7ad811b8cd6d0ed88aee8b6c1e88ac6a40dfd6f66caa12e44fbdfec53faa27c52622c977dc33cbb40b4bc7636ed618b72894ddfb644ae852738b3b796bff85edfabf57ddfebde17bfd735020d36fd5e7365c6f2ea69695117cef26279b1bc585e2c2f16162396a38c2be83bd266b66c0f698cae5aec0daebe5459fb72be9c2efd3bba12fbf46f0816accb34ee5049514da15a822a089c4986a2756debe1dc5db445ab82a2ef37406eefa747a9e7eeded75aab075a6badf5eebdf75eef39dc75a04a496f8fb5962cbfbc35db789cc5e628de1cdc852a257d9f72de6bcff2bacfbbe35ed33e6f2d7f0c7b46f7dab3bacd25a58d16d3bdf731dac7b0bdf0852ec499d95c286a38333b87629df46737b52038d5929eef4b4b4e97967c892e2df9d2125d5af2a5a525bab4e44b4b4b4b7469c99796969696e8d2d212751acad8d3c37959439c994d43cc0214576dcb5fb8fc7cd1e608e79c93db3697d7d0570de44af3b72e2957f75a9105ebda4a6817b005945e73f4744559dc90ab09a06ec81afa262564cd7dd37d930c15746668f919502ecfd949bd4a14eaa50b18e32d608c8731126879975fa1e55ddedf254401120f5770f954888297777914a4bee56388f102a25aa72368fbe216bbdb1f15b630a7a076240c67792957545e4a7bc3822d9468ef4d4d4c327fe1d2e997d285495c6d31bb730245948fb862079b0ea884ae3517a9543402000034007316000020140e898462491084619cc9d80714000a65763e665c349b0885b124ca61180652902186184310008600830c8d0d19100079122883d1cc168113c1f2811d0aba3ca64d0a05d64e12bc6b1ff05d48a12af4ac3770637c94ca5f409c4f7e1e0d0f4ddab2f34ab934ece8daaf123991633243107a24e8d5103283d70615934a050d19ef7f1456024007870fee05c32abf4c92b30efa65baa3f7d24d78d0c483914c5b05a20d9d6bea3034b3309a0a96635c228dc522f7d097db05aa2d41349c30efa2cf27306c4655fd445ab220278c44ac44f0960f3b1b8a0e4ab6047129b00a227897aea47b25ad63b0281c16039ecf01cc8e42be403be0b075b31b580486ac8e2c2b272458067f7e56dbd5bfa08b236cbaf8c0c978d085580085b7477884c1fb9979ed8496e092d0b5ab60076b8a3f80a0b4ec30203d9c104f1d83d4bc1491b5ab0d905f289600f4c0a108e8e4fd18514720a7ef2941175c31729ff5f3673205b62bff41b7fe66fbb040818ab0045415067c14a09497146ead9a9d7849389db470ebe777402946760ecfe34840d134b5ac10e90ac4a1cf20e14677afec6061ea76787220737f2d2a1881e10e8837292153746a354fca49b421b9580410c0fbff8acc5f1103c1be9040f0abfb0dc3efea84fe523c8c918081de5e384f2701cde25c2b8039e50b04ac2070800961bf8ad5e9af83193adb5f20187a08de04153316b2284e6c250df28542a35debb0ffa248fca4f3a4d66f563049679fc18f2fd590c6558bfcbffb9ad38fb41e08513515126931a87ed5e7b640fc9e87735efb0bed388ca7de9540ba26fd47fb58bf5cef9916e9bc5f83bb9950c555943db92feb1230901e542f96bbcafc452377d25cdc74181b5e283e447a432826794932db45f564bed49319c1b8701d7a4b951925c50cb180466353dd4b0e25cbcac861b8f1fa211cbb74bd4b6f81021dc1d783b5a1dd16a1da081e1d076c6bd38a547a35acd5d5d62d35ada5ab01b60a5f53c6824e4175f874c0184076b5394823f5316b0513a887785e3058c2bf02f570d836c779ef01fe4aa1c2c24f43db54dc66580b817a30c2c78737ae310a8496a66a5e9093a5257d6644531d2009212beda2a83d162f073805eaa16ddfe404b555bacf83f50f02f540c989912fce49da0497e9c63abd26414263e4e7ed15c615a281188f41e77622fbb342cf5ca509d4c3adb7714025118dd138e711a887c22b4cfe4e8f9a3e0cde7ee17e21c7eabfc065458f280aba249c0cf030f7aeb598941d8a2818a9b7b883e71512d317724c869f5b74bb54564b402313cdc8d1b509d4435f6f82d98ecdd5a422e5c479c2640880b294832e9138c9ffcf1ee532e2b0d86abbf77b6cbb632f7dead12f500ff355cbf49f99d6e1ac2c902b730509da54c13abcb605c335f5e0169cf273175bba17dc51421b52c3b8e10ceece527dd74ce6a4a0dfeef91e9db57bdf8a2aeeff2bafdc62f20533b51c9eb33c14b9f8695454413ef514cac1554e2602fa16f3abc4c74532a39327815db9370f0d513ec6c532ef994edb55a5e8d0c2c4acefc8dcb7d7271ba47d3c53dc3c7336a51cc1e93aef2997947826008920af80f375720f866621fc1a338365ef22b2bd8b57c132f6643ca2efa64caf4d228970f63f676ad533fb5575e475f35e41a5bd1402c4704a31b2acdd84b52b31a2d9b3209c656f5fac7724f5b53c4fb0a35bccf531be0907fe882df53c6ed401e2d5e9a9b0e6b2c58390f0a04b98a18b5891abb35aa9bd3a2f7ac60a71abd6013baf52505c200819855daad35b7ecdab02fb46b64e725395ef9d56eed1592e89620e314206036957a6476891aa004de53f4dae8ac4439c4dab7526057fc06fd594717d41d466426c7ae9282a8423c1dc4952ebc34acce79383c34476ad2ae8d632aa931d013cb5db4b8268850d834b629c5dfd508adc129374c33067c150efa1548eb94924d89178b2ab223ddee67d66ea12301e9fda1e8adbab9b7dc09aa50d9d1c95588bd464725d7e38c2e0d07e6459456b1f88973d6c04b416def7d58386547f77d45d2e6591ba34a27297ce5daefcd09db7f32e62eb30ad39ed0ff53bd4a0ee1fed6c6e6008263c0be1effd0eb8da475190a07c3fe7412ce87c5b8882fbc8678442e5e22d5fcadbe6804177c0c1a3744d230489bb69e194d10f8633c3a50ad2b9a728da893bf5b701442a877f8ad459bf82e0d8916d4d0b3f781739052362412be06a040bc00cd7991e815e5a96394cae9553a65df7986a1615a4b371d92b508419b2bc8ae4e0f61dd5d34e775dc7289ae5ddd781236423593df887a7dbf9c685bcbacd6ebca822dda49db834d5a3b2d902a58750c4eb4a87533bbe9c85ff01303782d44d8f1976bcdddd406f9c71bc6218b833828058a7dfeaf96bbffd0b986c8012107603c0d53e070c1885c98b6520d5df0ffbd707bd324a3f6ab01131aa856eeb80b14be36518d9f0736578c0d1ac2c6809370c14948f056f4a865fcd75947aaa0fdc4b7c6bcbd258bf081f3ace41898e1a36ac532385498315033b7a01e6a951ed754b7296192e4abfc1ba81f4aa669c20c419326ea19130798c46183e98178ec57e1240c2afcbab2024dfc60ab52bae68e3f131b4996b8928606ad8091045cbbcc3e059e135dc704c3daf1631014825476071aa5dbde1dd4c267857ae112e5a8888095c26b3736d242963e4e082ab91e3a9c387730b4df08cbebddb0ef9f8acb00f77348d2217dd0caba0fa5ab7acfd6fd39674e26fb526550e55616beef0df75c6902a98ea6c9541ef3f9857002492e8a5ec61b1a286bc2914329cb0b97c3f219ea885271378fca8217f4eac9ee0587092560e3dd30b4f8abab175671a6e5c52d22a5eba90b92f2f77d1f00107c15a7ca57a8c344268c76346c8c27388637eb5d4f5a7f28401b38c29d3dddafa5efe603b2e7fc1ad38c6e866f185c485546f1489b0b0b5036cb47777b37e9bf0a3f068b21bfa12c4c4a1a6905370241f7538afe58ba19f406160bfbb81709d66270158c9c11cbec9b85494dd155a911ce0438a3200b614f49162ffbe1f6233f97557a0e1ec6e2470ae2c668719aad0505971501327a4603a7a09d14c379f8f28eab0b9b83731390b6e8fce4ffb3370da806e03704635b4ce59dcb9a89da783547609773e8c404f783f8e6da54b7be422176e2cbbb6f9341eaa2374262dd5d9fdf7c7a771a81be0fa1fcf409edbcc0774e4a8b3d8a0cbd6e6549c58d772c7c759db953e6b00206c6484b2bea2b4a2a10b73a8dcc8f7527588d5ef6f8d62d823dc5cd69e42fedaee4f843d4329374dafe114ba4969959ba8dc6b9e4cba00d15dd071c8aff4cb451da339720e07d10dcb4630b355a8400d97bd95706486b763684829d6d79ca2acb8e50dd8b5eea4e58f08eaa33105d29df31ce0523b10b0ad7cf619f034e16460daf0a140c93cb9cb64edf7880786651b1edbd96f628eb9d9a482d3bd5b5fa010e2d8819e965b8a5b5cc0523cbdd8d8d8b0e04a5a2ae7efcc97c685df1610276c6ddc9e81407f4743dd0b3936206ba1fc9050f1afc2a28b2515aceba4059840c8a5496f615fe0a63d4a9a4ca4e92cf7e36552b61e43e6dce4d68fb4f5f840adaaa8c644d281fbabd42df6b76629d56ae6f6f0b773032dc63cbbc625dd47c8086afbd45d9c981cc9ce4da22570ecbd9354b973ead1177a8d5a391015aa3837c78285b0afd583250ff1c5922ed42996f90ec6b2cc7233a16596bcd65a6600c81cc3c88558eb3b3a4527f060593439408316a4ceeef0a8eaa7db6468f33f7bc9b4987b38fa6cd560fd200b4f68a1f2334130a888690e7ae32e663f7ee6277bf1922c65a1546a6d9d331b0501edd13f4ce7c1f751d500b91f69c10cc4f96cc89d5a549b4d2ac8e17bec99a622aa2e73db4f623627224d89b79b1f57fc55e81953c888d6789a9cd6d10ca4737f56bdecd1628ae6b381105878d125a5003e936efda6141376b4636df0694a97b03850bf31579d74d86c6662d8990eab7172da27da981af067533a4023d0e9c8e8b106cc7d7795aa8c8b3f0f1b018ce429cc23745439a62950ef55dce8c078b8ad1f074f0c346cd529abe44cf2a7630c8c4711c48ab8699a21266882cd5f88b6dcd1287e49d3966619235ddc084b9a0114d49148b31575eb76ba175b4cd37b78728d3aa501e182e202313aa96ea2399abc95bde7b5578a9bdc8b7db2309021b50dbd8ac099303849af2fae2df8b2e4f7d0a6f886ae88e8015042fa31221d4a5108b02bf6b565987234b608222907292c1bc241bf36265046e0f246406eb3e153eb0c732e0a0545ff58d11f14a5145470eeb8f89ae67127696308ebc183120a2670afa8e839a1bf6f2d24306038917acbc8fd26b720810121b11b84f66d921b26c44f6056afb02ffc2f0c732f52801627709f56269e1c7b574976bbcaaf026012d8e2217d2124a14a6640df3fec18d91b782dfff85d862cef10c1ec478a60f9fae3e1aed6537ad67014743342369f229ef68fef76e9360c8c08e7585f9cdcc0e90570b828f4023d66d7492667408052a06ade0ca2b732745004b3511406f22d57410a478ed89b92c1eb1ca388e0d514236328b1dcc75aa4aa0657805b413c21d31a10d4cf7e42d785dbe26112bcac0b6cc641257a5f89041ee6c705a62ad9cd122f859768b77574a31cc4b106aefba3993777af58e41f1af8d0787741b82f4d90f1c691a2970bb6c1c21c446fb4d5f741a769ce116ca4c0cba72dab87a70e2cb3dc8f21c064b3f06c5a059a0e4281aeef37ab607e351e3116e42bbbbc0ca783e860dc740e54b7b62c8db156f1b54d9f92d85a6d0b4e8c7d1669ef9bc0d8a0c82da2b969a113d6c2cc32394b9772b6bba986c43382a8244823a5dfac2dd2a5f0bba1f7273214b33c1f145120da2cac0677c395401bc4a4eb3ef225ce624d61f3cc679e497a55b96aef78ecaa1688632ed599e06b5845ae786c05bbaa61ec164c75d438a59538fd74d5ca5fd057b1b2cb00632584a569e14da59df4c2ded0e968e5b95bb4746916a359b99dcc815a981081fade4aa9729b97474bee941c18c34f153a4b889d5e3080900f02dc63d511e4cb1f4f16f74d7a5a61d03f8caf48903ff8fde1b21239f4f24c797ef421961f505c2ffa0fd6094cb9837dcc474fb568c68d118cc845303009229858702f5c9d2f88881d40f8e130c070ddf47a485195c1cfb786c115bfef6da4742d22267386cada57f0226904c184886ff7d6b0db32f4f4567ff4dc9d29e34e256bc8733236f473f391ff8e3d7b7adbbf24b07407dc7f88727f20719e0fd909faa08fe829f0e9c68a98943a3e3bc3f3a2310f0aa4ea08f9c92ac406d71a5cc57b35d7fc3c6894ed34f791fe0bdfe8d8dc4b67f92903aea9956548bae2ec8045262dfb1514ff59e9467a2d14d389b01491bedc1230f10adc801efc6f836122f501f30d7751c588ffe6c063358206436792d92e3b1cb478441a743cfc0d9aea891de00c341d0a8cf1efb47568e1b03688aa8b78c480169f27fafd940f655da01d0ceaf4436308209a2b6bff9f19686d5324e274c64ab8462916a0b26396b322d57e9b1853874ebafb85c5229bdad85a7d5efd92b8eb441a39cc8ea3c35341c501890cf349a93e8014aa5bbc4d130a7531cc5fdc922a175e6861b765bf77a59e5a638d97f0bdf1dffe14a5c68c18b1f01ab27dd66ae405acbf2d08b345ab58bdb23a61fc66120b0efe3156b297d04e9f4f940468db25a8d3f9dce088e6a22740e32050ea0598ac12ac074f0db0f7d34709fb85a58791b4dd682d9ab38e1e4cba52e60e9d2057892e0995f08bc3504281c5435daf794bfcf0102040de620c1ed220aea8272644f977080438bc8cf1fee272ec5d3c63fd19242cf5d3eaef2d921846a0518c870490b6802e6bdd8a665dc34b5e4601e54fb8d859084dd04b2a85db284aec0695847ddd321ebed3aa5017641b721c908653a138f6f82585b984faff85b04cea61c340ae632d0bb6bafdc5f3d9f5200fc0b10810e496c46c41b1f3e36331426b3727151a91ed440755d320b46aadd203aac70d82bb7853f0f9ce5d8cc04b93bc70e3b9683bffd35662f63ab6f9bf6be45c1852e68e5d14828d9b135ec3c293768e80f3dc0cd7b04cf91d00d0eb313436cc17dd84ab513fb84bb471da971dd8d725f93eb26a7188be1601f0b47348f2e55da74cfb87a4223d11e8ae3685faf39dfc82f318e4719e7a25ae9f1317fcceb6da6794daa5bcf58070349207c7a9b0dc09c06814a7fa1db962a00b344b8e287d0880c8a953b472bdb2f354126348c31674f20ed0d29a5c9a194c0c10f7eff17964132016fc23619ee2743736d029b72cd116241bf6fb16323e00e2c84a2ac8a5d4815de67040c587d3031183cb046ecb554341c65004889545184a1cbceedf3b00e9c312948b518e640658553a05e9afb3029de76aea2ff1104782c6d47667876a4a1fb053f8f4424b8960f7c332424eb52f724d849c00c88bc9350c817ac0298246ebc44511033e62b3e15b6a1d862dc7365bb4e08af6d7b82f0154b09e9f48326a7b880edce4c12937174fffcf3d880ea80ad6c8b51d25896831fc830e347bbebda15f1cb2195f24d2ae8487c7f65516228c0842f8774e43ebca5f8300e0d111c701e140198191eba88414b8fec58470180b1a3a06a7af406807657d2b0c8b4c0a86c58652e930d1015830688993fe6835d669475008961faeb1fdaa477f70a285d6c2d20dcc571c7823a240cd4bd0a0a0ad9c57c480be56bcc0e7304ec08d37c28a0723bd3d5dfec6b81105261f68d2ca7690867303b091a92cef1a9989109f5466e5dea227e5cc68b5787d31cf9708caf9f1f27793359ca58cd2de18a61c39b9224ebece540b7a91d1883308f5160f66031a6a9595c0176c5bc27a445584fc0f87015e1b8c43ec87aefc1f30e7dc9b4a64b63782e48b241c4bef5598bc21c448095ef6a95e6c921c3da4c3a28c1dd452d5feeb48d284dd8456b183de0ad9238bd55af2fa3424618bd2591a41dde6d1c7449fb215ceb41221d73fe423ecef61805692599d77624c98ffe1a9ac13b16f3251702995126ec46ef907817816e22a1d855cfca565acc3e6b42a925edab29328a34903fb36c26d5bbb8b509825dcad9fea6916993dca15bda8145c4cb94a9d98c7ca0e04ac4377ac31d86835a74b50465ded0835e8bd595128fc0571b0d88a562bb99e8f0cc6f5279d4aa205e54595c73050ddaf29000385b24e646e06e8b95828b3fb8ed201ff164295e32f0b71a66d0454964632fa324092c6120544a5817aaa194a2fbe9328a0287131d6d1d4a5e77f527865264f87067b8b9e7af83e69bdd078c321d21d262a22893e46f1d403f0e8f47c136d9c68ba2d24844e74443a65580e82634e5aa435012a9959488c06d08d6b7d2104ff6ae41d8b58513eff46c5dfad314389bd6b1db9132b48ce2dfb43001d9d227c236d541f567066d21b8b049b91660cb83691bf76f79845e5d092742e92a902a79136bc87419e505e2e0d167d26a05ef4f4f7081c0b68730774a6ba758ea0212ecfb90c597797ea63b5abefb489fe9f12289f44d7bd50872304485099b352ee1edf1d5016d7867fd4e4ef5116f41825404908706b8ba63e121ad3379e1c4ad648295d6eba316f16ed7689943f052436dbeea661af23768b2052ecd042a2d3dd52fc2279fbbb883905f580262f882e714785e3ab174e8bd0c03266ecad24fc8bf881f4717f77968041426b349ab739e2e18ea09e74c666d26257468bc931ea000160d35578539558e62745356ab6ed4b9d41157fc1cfcc07ea72542940b528e5c93cbd38722ebf1a2d1e797828b49f75b04da903a9fa0a6ac01c9a4dd699bd71a418e55d1de86baede78741928155fd52a0e69b4d9bc904419531e56ce2038d60f145da63a80cde2fd222bbe8ba80193316f5d06b976466408ee4c5c4bfb7cbbcd59f0e1a15088dc29453b16754369c558f55a84e30c159c1221d3a5aa79db93c74535ba301bd666177b3db92a62d148e7049499dec56279497e4f81d9f3e0ca72f84e3c6294ee258e86e6b6009eac09050148310af583b26e1a2a3f8b2a276bbb0448359e4df1c2eee57e8348fe09bc33780ee0003291c6c45a7b68a941763a1acf014d00523ef4c76fc9d970327782fab25c81e9e1db91922721da59f7c23bb841fff8b96684391f5c43cdef3675f359151ddc2b633a74fce09b58ab78ada28d0ff216d8a0a76ee9ea7d84e9b177612a52dc79a82131b5619e712b54bc6fa8f7018c8b232ad9194cf3799a8350ad5e6a9bfdc2fa4e17656dc2d697bc631de0021afb9626c764aee77eea14ccfc53669200dc1b1b478a0e5df9b62be09999635db2d464cd8a6c661e697cb3a920973ae7e146f295a27e31863021f3ff140d961a7d3d2c7c2e27808f70c85002c39bdbfe91b385d9abd43550fb221fa9b75f87dce7931c35dc2a9f49c66d42050a2bb3ed324644ab9dcb7f48420223c4197260e7c0dc1b8c1f3ca92d001dc0e3f41463a6ed1ed62ded950bd6a65b1dc72ddc46a7696378bc7572346bc7797b13970993982d27af32fd9bf613a9cb5ddb644990f678ac0d58ec6d7504f435deb96da8f75419681753baa5fc238f8a91f1dc402688ba687b2f890e890a00e1e8e9a2c02f30409ca3090b1e9ea2d0b46a1c07f4d6183b24b62b6edba7b6c0e93806f8e689782260eeb31d803864f566905a5a1d2c64b6ec6811a00ccafbc5aa328c8a367125a237dcff751b9dee74a7e50b2cf183e617d8c77525d3d9817abcda5a38ee8101f04406bc7a67ef792b8541ad5d7405d12398a697c25e34ae591a5924b6f19061bcde1adef1e4ac04d6ac0b3d509cdefed8c72bad082422ce72a78417be58a9bdebb28d77711bd9a1c652a9d3d98b5085b4afe8b20e0754aa85d6a4042a83fa1cd27e2547d2d337b28d8038856ef60c83395b2b96e0fc9a9d39265de270b2ce592259855e49e3fbde7d46f6c87963b836181079aa6d9a2e8c0e9ff36e691c71090fb6e3dbd9874ac00c1bf89c19b7c0d6c0143550452d9debf4c30dd9220cbfe41fdb15b1de5eabb9b5f43e4155dd9931020128d2bceffb47ad6d600e0771f858878266709c24cf858b346e5c33c3d59b27d5b66c9d2cda994ca408be239b9726a08208c177b24b49651325aeb87d279690d8abc4c79325a37c1d095216ecf9855f971e8e60a0b5097d2ce80300cfd8b5e08550f45434ad86c42a702e423b30a511508c14200df59fffd042f0cab565379af6d62a45ad8d754533c3aa82fb83d654aa17a653c34fe576cb1252ef4d9a2ba2facb5064d8adbebc8d53f60b33b52e25d89616d270d78b76b7ac7a3f58bd8e85b7d43286c13021199431cb613871d10381820511f59ef8b888ca3ef58ea4ae203daf52f2017caace1a57e2a7f358cee6ad03d96fe4641952db775a8216c4ac5d10abba8650ec0316c7a273ef73fb1fe0e069eef434a8f0d3b9163dd35d88437d48ac32b0e1c161c663c2e297ec1890f8ef1f863263ddf73db0c13b4a79d3bcf59fb7efc97b5a1d9cff03fd7dfb822f71b07095a20a8fb762c3108f0743e982dc01248b99de12dd2b31ff3b9d14f6c8e8b3ae5222ab3bb27b80c306a8eaf506c6c14cf11fd4e8a7ccb1e017f3a62802d543b0e379758559381feb7e1f4b6ad9c13350a958f2fa62115e1a1c50393c308bf8f7e1c32c7b28681dff98cd3f2941dffb802b2e6081265bc99cfa8664a1ec89e615725b00f5175f2d38b036c48be76ae4c4c2692d216b839b3e30c3a3236f337030c3146cfa9f6df2208f3bfd7c50f34d2d80e53a35e373bdf112df7565f1cd84097f167c00bce68faed596259d94acf968f6d8e117afb3257416d3cfb004f1dcccdd19300431c94e2ced40d52cd72a88ba71595690f8e38a64bcb919ddd7ef9e1eacd3663f4bbecc9a63b51fed30f61235556a24360917c72e05dea403347e15654d875eeb2cc3c188259efe51e302fe17b981a1a8f53f62bd386ef01ff3e190594289ef279b1b27926bb4eb6d87e001d39adb5899196e5b242354035cc69ef7b44234d767e354ce87c85e5763bc4eeff354848231221fa3b735b2f3422d1ce59dddc4cd007aa416964bcdd29c2360702d1f295d4bb4294d61b99650f0e551e7521ba4677e19e916ac1de401b7ce1af09b490428a5c0977fb406d06e0d05282aeb64b12f6ba94318e2c23eaebdb0c5547084b4a3f9c672d0b135904b08960c8594eefb3335d425545ebe24e5194108a97ba7d248cbc1ceea856a687e66c5ded328c201925a78343b1f1a2b6745772fc66c14e6b64dc309d1f5f49b394202c65e39e04e5cdd45655cf4c577090cb8fe7985233eebeda51e36807bfe44ad14dbe1f147eb5997bf7b61a74589916f76ab193ad689345b8f73922da6f9108249d4b096431f1adf635619f8107b30a5d40cbafa9e6770c24e3d08407b8867c5c063e58816bbbfbfff9dba50a8c6b4a44c7303dcd8836b3dc7ec020f4ec0b3f5b58d2e159be854f3c2c80e6a651e92b2b9dfb2b6ebeaa29270d6a0978e6aa20c4ebbc4cb62c05e36080718229c3ad4b8031edf41d20da4a29a6e94d8a4a1ce0817c4f1d153a003886400fb1f07ee2d486849399e0bfb707920d6138066d68ec85a25b9d6d4544e33d87ba223ce194b955061c2bf17d44b1e7523e9d12fa123d6643af406ad6446a6aae1fdb72b02d7cb9ec9f66ae23cdb36c7ed9a043080e2941336acf7a4fe0de267fd09ef80b26792e58702f4b28052cfc877e4b943634a169f7332efe433da934b10019f21a6a54f3420093fb80fc1620d87e75ef654e0285d8d6ceea5b032fde76b93a9e0e32afdc18e48669f7057241c40c3d625752a2f111a13ef67eac8d78bb8f6840dcd49d7950a24a9f78dc11ac5b514f0539cd72fd045ac6c0303aff8b2cdb74592a8440e457c6852cae90d3cef7e119523233b4f6d27a8d76522294b38536946b72c895752231125e2fedff8aa578e8fd10df527fb45e68db5f1983818621cc9c244b4514bb40d5ca2d40826766632b1874d6e83929109f6b3a10452ed9280b112121c667a840259cfa2755af1218b39acadd63a2d7cc8662e502668cbb3ed42a06b2a269ad0108c7cefd415299b944e94f1d403db3431e11a89b08324738c6043dec604e0af294a652264bf88905b4909c6d941afb17df8cb799f11573ca743beeda8963f2ebad8fde45f967dc61fa334f8c71faadb8346c9d2a5819c45e0c51a1edb4e1e1422e7262c138504afe0bdf27c9a3866989bd38858c933d8989c81585b78beee04ce064f8b1b82bfc0d930da5f93acf3ebed80195b7af40493827232f6216beaaa7e31090fc0988134308611198c317024bd5cb07a53180cb0612a2b020bcb656a198a2b3b6f8bd27d76baddc49a24177660f7ba899dc878a08351bb7bc114a397cc50b6e8468197193312655c82e20137720e8ece66a5a1ed48eea02f22e5814ed74b5ec3a9578cade144e309fc48be7f8a60270d5818e9b4f793952c3d89df0c3967741b8dd4ec2dad1c71a41dd16f097ac6bdece69e40471ccc2738c1866ca8eaba74d8fd46e9dd7141682dc382df739528f2e2c3386d9f25643731a206a07e91e3281682c41a77175e8788fb831fa7cc5bcc8fe258b36c91dc3b9ec85a376ae0a93a0d4181dce148b6b63a184f6046153e451b711718b1cdbd37c2b805ba97a463dc023cf8151a7f818e66e87ee515d7c3679662dc3ae37e781b6bee97a3befe2026bd1336d3460e36bd72f240874493c747929358bfd5baad29b43da9e75aa30453e286b2d31cc136f01e4b5cb68d525cd053a14f8ad7ed56848521fe9bb6f5a1af8035f5a1a1d21beefec1cf797352355620d6faf64fa3babe1fcc09251b6a4404e2791ed9f09501fc10b56dd6e61c78c42d165f81be4861296bf36d2379438ae3f7a6645ffd1013df0a9abab41011b26ead993527e31e352a1d3ae018d2dca24505b508f407f35f5eae3f58c9ca3b08d235dc4229863bc94d57e1ea0719cb293da61cabe3d71878b2a21425ee18ffeb9aaacb918951188a754cd5549f636886c449948931b7e9d66870244906460ebde6a9ba8ca8a029119a0a0bbd2d9ec6452345a75eb70be1de31d0b5377c7286254770883eb54c0b8e3f48c4574806c9cdd370564822206282995f51923b39ca6a62a553782fbf8284e07c6e582c4da358f5e9c07da6405b9946a6f294d537c3fd9b5889a18a48a44f3e173974c25184d5e5114944dbf64819f178cb644c2239acc17f5c4fbb15c28a0e3090016974da97eb6a87ad26d4a63c52b8ade782d667b15c8fa288274deea9b9f6287f3dee429ee5a45e2a694456727c2148b508add1b68639bb477428193c9672b290084354d305b91a5953af8c4b9a5e4f74907869505274db9bb80e4440d1a2d032a3c33b060d1016ed2264791a5bc8417d7ac2c36a6956b25934911c4c9a1d0576d8f841805a41478b1652d326501190479b3cdbecaf35d7f19a3620feecd378a6caff1dc7bef0383fd543afe095e857d6f097bacfad6d0e874048a1c448ab9e9c551e44281e70e5e02baa2a81f0bd4245c700eb04325c2769db68c6218ead59611c927deea7988a0c51adc8cd4543dfa08b107da372c13ebc17ad535d9c8942ef0f47515467c69a1bbc229bffbbfacfaa62ed61659374fcdb2949b7f791dc39ebbe45916885bdaffc4e4ac9984643e589ba06cf9e26d39aa5f457b9cc5bc1c081b6ce8ecbb4785311c59d2b17c80cf04d5ca93d0781810e79b24c2499951f309353b091b4c6478486654a1df52e83e6283f1fe0014c42c8bb12e8a517f82d71d7fe3e977135f5bb9010e0fd831be2036924a2894d8c8fd2f05d8008d2619a27fa1ee738cf7c999cdfb8e3d26ff4232fdced97d73023038ca9f711363048a19d7a73d4e279dbbc7fca890ffd3f38abf0ea827e2ecc158f552ef80f83ec116d74432975a2de61746e93fdf0ff6703128eaf10964aded6ce293320142b342da80c43e0ffc25505ebf6ec17562aa0ce83773649b4a0d0856dcc6742a8d5ca11db971b7a6f16ff0c56ddfb6b276bbca3974c7cd54b019ed3449c42cc0a894ac40a5ef01263c6d35cf92545664d6cc33c5479a42a62c1a67ce1819850cfcf10c7fcd049372f62c15274c1b5cb700d2756b1664541b40b839fab1725152165eab9de38dbf0a6421eb95f87f48f4034f8c7fe444d9c42536e1873b40d68dab43858e5cba2c02cf34db63a77a04b92415475af6e60822539e59a9308ad31b64b689b2c2465f1bdf1cdc49a25e9f09df815f436a5263f3b27cdfd43ecfb5daa1ce2d58a890fea8ecb0a03f4a4d75e003a8e29877f3e3d02a743d6d78241534da51c481f98355288517a1e35495753b0d59201431cf300a626467c3ebdc5e7eb657cbeffc7e7f38f7cbe921fc77f10f84e04c476a390de029854d186ea137fddb46e5e89f43bf80dede165a9be999463c78d7aa6a924956c9b18b46ae387177030eccfa5ca9fcc299ed834f180b92c246f03864b932f15cdfc54a27110e41baa7e092f82dea80d3d3e24f561bcc2bae3cc2538220c89489ce0e94783749d30c95276ec3d34620087ad15dae4211137ccef9d3b935a8f6ac3833c1b0564fd1481047813faf2d932389f2d54c0a8461c8a69457bc499aaff45657cd802f196ef8376d7a400655f341b81e92aa8b44316e4c1987721eefd259028c812de0146216012adfdecd697e260865445de6732cd147bfe372f9e313a1ae9bd938d28af7d1071a3d543fff29eac9a57d8bd999d6d6573fc765a03279692a2f00ee68cdb84d26a177c204325e5dff61f5c46615ca99e01dc6e406ce9be3ea1fb2dc11c758499edd4b8cd7324363c7e98a37c8a17408b9f01749f04d24424d658f2d96fe4de3f2ea91df980ea0642060b939002572aa0a5caff89198db8eee6567d5169f6aae46db10395fca5fef067345ae7028c64c8f515cd621f251bd6ca9c27228f82f42b7cff42495269cf20b426445a9005b1483ae66ce14bfe0e61528e905cfa15d1e4548701d96e1829aafa52f886864aaba6dd1311ad59a52192f2c73bbed903af12647f85173ce0829aec12d035617daa256df4b9217f62c1afc038560c53679a01516923c6e5e9e3d2de372a43186876f1460c937236c6e171b4775de3ad5397f73fdc42fbd2e08ccae92f0bcc7356baa1074a8e27e18c03cdfa8d79460397cc8bbbb1da93f21662a91d8f810f6a69877c88bf3fc6fd5a73d73687eb585463e970bb9ed25bf06e53cb2fc81b3a981a27db3b005216b77671ee702819d0d7c80bf2bcb4989868a80b746cb274b0213ce7d33955f13419aca05be1adfd05df12e84a792bcd5f6c38476030f9c2c0384ea5a49f17ace0d3c3a8b69a88f7a44f1aeaf72050957d3542379ed589c90eabf897820f60ae46c66ada9c79828f1be9dd25fc41c4db9a04a0a562fbbdecb2f15ba7bff9c0c80b1a4f9f7c8ddc2edc670a93065c45ad9b8a78a2dc2d9939e995c9a1a2165ac733c4605d55acf9eba2937ca2cb0722c3eb3cda3b5d3302db3fe015895112b273d95d98e01fc09f96b8be8e4de60e830a02d352baef6fd9b9262dbc6e63fa3e22fd376d1d9622b59e0615e6833454c417f4c4627bea9663544df69b8562e818052dc66742d8a93d18ed436cf86d46f6fe234e88fde268dcd86121add067a6cbb6f6d691442b329fa69e0cc4d4b6090a57dfca59f3437d9cea51824f38e3c628beb2634d69b8b13814ddc0b77f00a344cdda0c93492dce092dc1b7d5bd5859a37d13a9865bfd83506f9a1efbfe7813c4f036baab5a4942c124e6788855e70022556e13b71c5dec3ef2c3f7525b4ade310f952467ab18e8ae43a1769a3543c384f05846eafde047f411f4d70764d8c99c2b44ad8a83ed622a704932e18c1f862ac56e8b445e74547e545b6f8f041582a01ef1edd8b2fe708bd4250309d0c04a85745b91e15c6e6b388e759b84f252cdfe3224579d38b7013178a712ac1eb1c89f54757cc429477d93f59a5e2136b75900b0a5d2a327edadab4385985d7d7efa2fac34dd6d2236e501edd8c74a6f2d816adbadf48b2b2a94dc7d3072613dd8a4c379c834fb6f1f9fe9882e79440eb34c89967b238dd81f3bb2a9f57e6427e243498ad78191d9843e559a0e9e373b949f09ce10a43e99cea442099a853e4d4496133545cd596d527e580b74ab352f60301e330dd5150a1b74f6d5e2cc736d4544ce6a160dedbf18c2dcdaf54695f14ecb3edca5ff9f19929d6278b90d2c3471a3a5baa80e72bf8aea2022c53a578da60df5355b00989a52ecc18ce246c203561c561e5a969f7e35e809a403713deb9a9cd25b6cf6892eccc4d662645ef96d6c3935aa063afa3d11675bba0db21d82166dac8e62e38b3cd8c4ca45a9eab41e58c367f5a1c1568473db72a66071c2d30a82092802c509bc4cba46cb2b2b26f0ef23d6e043e0e61e5e2b33ddad4bdef5d12308fae346ac7013cf17ad5dcc5dd563959bb73b37e88019f2b9a260e1baa4611bd3d8af1616edbc2988697c6a94866da33af0fea44b2591b50c0b5df42fa3d9c2b603423b37e62572135c16b3011724003cb7ebf70e6abb7f7a654f71096754b7ddbf15e60e1c9df406808e9b652787466edf5270b5a7d67205040a89fb4abd567d8fe1f04c36b00c6dba9a9fc430f2051c177f0eaa558c732ce8f8b7b4a81bc6508ccc6ec324fa29356fe4cfed07ed2b2569c9bc7f98141013d1a89f01d0136065de8f1a6a6ceb53a102a4bc8841239c70d7de4fa1d1a6ed2395d821fbc0bd39db7e1f155c2fed0a364403728e2c46750c404cf019fb418f6944c7bbcab90c38c7227202fb13cf87bd1a78acf019c09ed7de0a2da3579f1f735073e938aed5164ee202656c191679a7f37d205f594869d84989b2ffeb0791143f56c3b358df2d904eef892fc10ba63204ac63e44ab241b3bdd4163a3ddd5e9f24e24c7ad0170a2e490bfe6a4f6a80adc00115ee0f0d7bd7156e5a2562e32c7ebdd40d77a6ac133464949076e74793c4b8e6d7f7f151e02746e87b12554cc032d1eb4025826db91044070a13fb2e2f33cad45581383e4bd2bc423126ab28ed9126958dc5fda4940d5541bf506f0328ae9a0991822d0d20148ddecb7ded3f165a858c94461975469760bb5db6f7ddae16dea70ccb5532cb64583d604a2511ecf193ca669f3d22dfb859a81b171ee78e80c24db39e3d7967b3d4ffe8d1dfb1e84feeac7fe43c86bd0498ae05210bb39dd3bcf5b9c821c2864ea6532849b5b2ad47c46b0d693d9fc0302fbb7795d02e61421cd8ebdead1004c7b2841ab9fcad826e3527f1cb505ef44a81547eda38a94f1e0e78d848130e1bcca3d7ef8742be65a06e80eeeb659903a209906e1c5ab3389a95eade620f34a516f799ebb0a717c6db0b118a55585f4a1eed1fbead2d5221b1f425619ec048570fe02131211a678d37eb674148ce566244dbc389698754e50970f78a41a000bacfc536e6b6877a132546675e6c38f61f5d74d346b39d709efe48da4f9ed32d9d4618e6332fab4914c90896caf1628a4fdbcbb8cd47e04d8be9eb157495f319e6df1903602edc0cdadaaede08af2a61c65a6a5174c32d56c3d193e7d4868bd3f3608804d22a928c0fcfa9e9d98bafd8e7255ea942f033426c2e1575cf36d8ce57e922cf14fc95fd57e6997ed6b682a81c22347b02ab131592944a075510a09dae20e53fb59d8592add93b656642bf1552219fb22af19e363dd8e4516d5bab8942bac7c3e1459ba8a170d674a4830a8cb2a04342e144b244680a1177e6f49cd61f84d2a44a3e61766cf09ceddcf94ffee655779096935f290ccde5727ab4dcc36f38aa09317231cb1b86be47aca77c2fd7a647236bb5875f2461eae9daab5513e646d9737d985d696becafc86bda5d7d4272b33eb0b209d0c00b36bbdb87aedd92bc230d8da6ecb29d438913542b950f4dd7c1a0b499e98309405e62ecd7ae02268f6a5ec5cdd9e6fe19a9a1fcd9ae7f2ec1095dfbaf86f15378392ff084758a7e50a6273ea6d9228c82309e9b76d2235fda40f58c32dd3c47f057880931ecdd0c4d202758ff1fc2413ca5cb78ce0f5cc06cec8872fa605dcb04e3eb46197f7965d0072e016ee1378f20f3e366da74e21550378d132b197a822fd8d49d40392540db25e9749969b20076072149f3b95d97811b708606e7d838ad8a3db3653465fc8ac672fdd5ca403f3c9add82ba6d6b017aec5538ddd464e744e06baa3b63a6538c532fc74247368ed59d14d904643019f6a58ffa22366d151e61e57619cd70325505adba968124c1f71a00e44d17eb529f4033f085415c6c9f344b2e15d7958aba575d69f00103edf68bd8ac7b9f402e007981a730f016a04f3fcea6a615d5047dd089554acb70e3a233303378f400d68da91373c0f52d33e70171192c00cc8a0eec790183db6405b75f5cf32d5ef079c902ab2cad3a507618e8233a8462dc5b87ae66083bb50e0e7f87d8d0c9e8d58325c3f6c3dbfb2f4b1251ed801cac0e1a434a5bffe345a01ca8a90b1f54a6d25eb0147373437749cca8d942bbd0f265d4f51fc44378b13e999304647e4decb4319e38ac6cfc9c36f7f7a5847c284e6ec556486ef3caec93ed1bef6654c1e4b187bce26a17e55ac136b709442660bcd52ae6ef767acd66610de1d5b2b151c24b6ebf4512b99abf49a2bf244eca89db10e80f89c1d5c9db04c153c25432bf99a09f4ac88509b729da83a4b58735360d5565440bd09c32b136333596cc09da36b0bb72618e4a04826647643da3eef72e8b8053c07880a2e8169a5091b2641681fc35a87c4d49f052f81bd6a42ab92878b5e142048415cc6f2fd05f257617736e4db4078978657ed3887c92c854276e0de80f897975fe467d9c7a812ab94f5b27aa06ccbdb375aa92fbb475509d7bb3779c6a2e35f7c1d671d56029e72cf5549dcdcbd92242d4041c5bf995c4bc8dec1ad80d6eb15cc6b4ec34a7efa2f78d8a73b1e27a52ff22af9cd7e6f919a67f2df63238e91664faba8be786fd9d9b4ead36163778d550b346235fdf296c63af2bf673aaa910ad0551ee4f374f596a2876e85684ab0d5bb3db47287a848c23d91fc0f34252878e9948e5a6d054149cfa0e96dc2c33fadc0f6f55604ba2591aa79cd4d61eb1f1cf58e559592e5454d41a80d3f0726a9eece4ae0dd4db6d6ec8926de7004ba1a85a449c348c55803eb5cc43f52af94fccde6cc069f56bbb7b4c26795c47f2c5091d96698ab9e2aaf1932c47f39f9398136fddb179c3926e55b8a44ca472b676c639c2bb4e6b2ac5d98ac40a3d840002acfb0b206387ca1ed10b3d40c87667870040296383aa6e8110932140cc727f29b2a2e9636aae781f88d8871e509f0552cf8babfccdb11f8220e067542509e4aa3c914982057f9f358d516b60ad442152469cf007b5b763c6df1eeb0bec24ba215dbee21179a9094a39433d7f524eaf89932772a9ad30eecee03283e63a2cf63da91ee409fb5b9a3a3f189d13ad8c4a892be08f979f20308d1071693ce1de8ce6c338cd91384bea30c80ce7d2fa8edac974e1059248b424482cb508ab36505643ee31bc102f2a7b625b8ec07c0d9c9230a1b2e006ab15b9c66c179eada7779384b56198428457227c74cad6e804e26b1ce193bc6ed68346025fd4ab99ef00584fd865f580c55b94304c4a34775e0b4573a0f0b60a03fbf7226bfc358d4e38db73ba58319bfa011e7525f2f821107ce8551f0f1d36f47f9000f30f49502f8df888c059eecebd80b7dc0be8867b006ec03e8f7ef3ee93a6a39e4b618f78cc4ec4993f4fc669c8d349775dc6746bdbef86a71f8b0eeb62350f2fc41a89a428ebae8baf010b506b2b432905d2ec1b7c9076f37674c565845bcee05cf208129228982ff26edd2804b41b5201132cf3943dacc1530d21df85de4b4bc6a1c95f83ad21e1a210505381a86c63252a70c5659b0116e70e46bfd9ec0d73986c5a3eb911283d8741823cc68e30387bd3510f931d52ce4208c7954075ec953ba09d772809a427d5e6415fd3a6df1a6814540918ac7ab8383bf9e1233f5ac00257c7817d548d53c041223e73dd24de9a5fa902508d7698cac321c1831adb3e5568caf5fe997dfb299c74804b9a3837150068cf232d6aa2393a8ccef88750f76d187fc8fb96bf9eb990b98949c50af03f8c030243afbd50052efc8f0c9a33fd5071c31345d268696561775224453d041e14793b5501cf18aa9d9eaa596e276dc5900d70b4e69a2e069f1797583f81a96238937e3187641602a50c29aed0d831dfa25838ca6551c32f5e00b379cd03296ab27c59c0568eb35ae596a09a5df82e8da7c019b3127aeb6585fb19d6599777072b6ed0870e22597b80be5fc8c6659b53821d120847a17a916e98ee4ada24067919d30f4675ccf1e20eb7ae7a7ce8bea5e8819b584ef504f87512163849391ea146c19f4c4a8f1a12cc865937d67608492d597e32b6d7422ff77a8d1a07c3ead294ae0f1eb13d4cd24e80163cb0cc914acd25c601260625981690ed07e46d01f130447fddaeebcf4a092c4ba8f051407d9f334fb9ceeecd52e2ef9cab00c868e2da5dcf855208f213f60a259909b83b29e1502b8874d0def0f42292465119e40d45dab18f86de583311f559631c299320bb85c8cad47357893d913aca57ca7782eac5da0d1e0019214ef1797205132b885211c94c94c324af325f66c2dd679d28a68358bbaa974fbb6726b54f019527089e71e15464e3a3f5fc23ba201a01fc0a03b725e5e0a12046db51af0e8d2acaa03fd07386e808f8ae7217ce332589d1ca7018d2f499a91fff4fd49740f4d2920998dd73468ed29826a0d628741960187ae858e56b5888d53480d7c8dd7f2ddff61602aeed014544c495863ea52b472cf80f29b1171e4df383a04ba8e3d3d531607738eb9f93adbebc380401b4a94cee025fb43babbab4e06271b0e87da621c21e186dfbead9372455586c2bba8c0f25742a5769ff95feb042f84fa82f2e27e4fec9c2a22467d72d2b348e6fc1f429dd3e5219a7ad6edd520b2db76a458bad5a6fb1f556dcaa675b6e5eb2ecaf0f373f101a250ca55ea54a7b432bfd6a17e47faa18b40b7552de0aa158ed9ea909b9ba3782f5838d456e5190ad2125bf8b88202bbf02c677ac84f7b7b73facb58a33511403bdc2bd60b3cb1c3a66770bdf598b8be592cea7aaf9793645cbadb56aade5165b6ba1e556ad68d95acbadb68efb56439f4267e7902c861584d4345d957fbd3c931d7f416757052c34a79f5ab9e1e2d6f1dbfe6da1f0f4b8b41781046d308c899f601664f4de887579cfeb2ce43737c73a16c85962c18644d16345d18aaf32a11dc0d2530a571a1f51ca4567f97fbf0c3b90587544293c938830b36832c86d3bc6f89bf2be71d524d3368a4ad006b0ce08766ec25851759dde5b21e9a69b70682fa9bb203ea9f2553aa77a60da9b2210b51136a3cecadef40ac066d0a4b8d9425b6f2e47bc495bb77ff0e3abb2f19e079853208e311fb7ed9004afdcd47bfc1b683a69bb4da6c03c56da75972c1f729a1ecb6cbc2ab25f1747d64c05386136c26e4d8bec2dcf76ada7f5ba385e4edce23c9dbcb39c11e46a6d4ab02c834b7a3d566ea9063e2995b0af924e67f8fcf2bcd5fa4eea6e8d27772a9d06771796bf7121ce932cc958852f5e74f90ee28baa08608be28b90f81bbc997a1c9906c3ea87750c6934d7faf58c0cec4120f4c1c664104e9dd496d41c4ff572f709eecb3a0101436e88ac8debc10483b83ac0ecfe35ca9776c0c83c5d8ba36bcf3daa61981ead577dd47d27b4dc3d94be8a700096c787587453e67429cbfdf79ae5c77fe888d61708f0a0a31411982263b30029732d071caa8b6f12dc8e8db264530acc9eb95a32341e15e7fb1ebf73165f2e33dad7545d2edce1f9344a0b1b4377b7d75cc908307384df542bf661f9ffa3428d556bce07cffe68290332314907d718f913d1cc250131b72842e943725e40a613a78fc8af63bb9867260136e12c5d0649f14dbaf618d9ca18107502f7cb41195960bd6d18854a50500970acb473131d3a5af04334978725e3fcc9e286a5d43de660870a21de8a2747ec65ad911b417c274a63376b535c51788bd77e38d1724b121304f8ec06ead6f86c64298970309f237b4682ff3bba507c0e8986821d5fa20111d75b2da69816043500a4ec94fa365bf55a33ddba2411c61fd15623c97fd3ffcf4c13e91b0ddee61ea1e208f66378e8ff2d0c85f7549caf3d1420bb388b884cb48bba61827306e52dfcb4887bcce15e08e7f863f8f332e9ed58295712fd2d8763f015a6270450f51d5576ba3226b4219aeb8cdc45fa56739a0c67cfed2dc194689e6839faf773bead594feab4d8edda0cd70493e7fca424dd6c5506e5c6a1e97e4b48390989cbeeb63d7122860b380c7b482e8f03e35905fff0feace9e22e7051451581afa4f31d094339ac6dd7aff5515fc8db3c970c0d070e861bc34cb60769034c72503a4d730c8103b0c7840582e926da86d23d71fb8b1c5d3b73432fbd5c3967ee673e8094f62ad854c691ed30ea9003198d6095b9430a363939b5ebd45b1533620de9d0a9f38e67d5b671921d24c5ef0f118eefefa5bf6735c8329b4f283f96f2b6067b32dadc64524da82eb080a166eaa8cb7439ea207b3ea6a01d98b44f179cd7c75f5d1cbd50903bc0f44e2c9d9f64dd78ea4c7cb0010de26bde9eae3e7b4d48812afcbc35760caeca3a4b348710113d2fa6cff90883ec82ad8a0a68c2f365593213fba0d9880e6e603ac9c93292f5342a6d2e8ae9dbd219ad916235b9c265fff424f88ed6a417361eac25153160e8db3647db285fe141344735f005eeba12050fb87ec0d39ac8c5b0cfa451db483d977319cb0c14a5f9d1a0b193d36f16dfad9704d225f23ae4f879d1a43817457811f7b09b4e9a25967c9b3bdec9a4af3450e1c7e40757a07b00eb46fd1ec38b3a710dc8b47dbfdbcfc150d57752dcf3b7051b1e5cbc2a69d096bfb7ae4a4c87aa656e854690b39f265c51d0f51249753b311810d00f59425a9a4c7dca77796ac713dc816df98368d4f259310a85bda719595baea8ab70a3f0d45adf6f7761a0ed19d9d614e51d473f12e998c95193faa035d9bbd62a101524c478b304b2ed8c92f0dd7d5dbb02733462a4c85fe73cecb269581c17947e996a9ca06a2859558a354a8d5ee7f5d0a2e0939eb6e0705e64c90301dc57040e24c4ff0d581050e76c739b4e17df07c77d7d078e9d16f17b98d61d28a2ca35a72beea0b734daed3ebdd9a9cf8e04ee9a688d1b3df4c3d41e762a6e2f1afaa599d383570d366e3fc40b7a99efc8224dbf1a9009b25e5a5ab2a594524a19540d6d0d6e0e4e7b8461e25bdce59bcea5a0bd854198ce7bfdfbf5f9c333b9e771ee3de726883dcf83e9f845f7c39c728bbf678a786fbc373f7764f486546aaa287b8f42f12b39fb36f70ecd9f09e57c9be5d3c704558739ad4a979717977205d3c19cc074b0273027d57ba6ea5c99604f60ba0b7b027382e9604fb2a7624d699cfd9835a55da294c6d9ff79ac29d81398cec64a15d614ec098c26961618399813eb0a16163096b0a6604f74e5f836bafdd74587bfecb940bdbc28a55d32516b59fe3a234ac964c9a1fbe5b4897273769476395719e5b9ceac64a2543251e896792d3767bf8b4efc2dbe77ae32f2b9ceace5c52e3a74b3a6a0d0fd354b285953e816a7bc12d0fde1ca9ab229628a1355a088020a74fda4a4604eb027505154acecb7b1525ef90f5c813e7aab30110515af984725a70f8d964c4258287fde7fdfdfc5c53b7f0879e76762fcdf87f1b7437b66f97de2cdad57ee5eb4ffab7f1dbddad5e2a5affe3b6d9828f70e158b10ea8f674ca17f05fa02bd5546700515f158d38232e97bce511a2bb9f53454726b3fcd95dcead9099a2ab905054d546ee1df364094e3db00b1ffaeca245c72ab5804ba8e4d33a45418fc35a68919b99bb3c35f657432a8689cfd2fe6d538a4f86b99448ca99bb3695c72e8fe1a2cca9546abcc754616743f69ae32aca0fb47731597a0fbc5281957d6193fa0fbc525f963223a41b7380494293b07ed174525e7f59898ae93dee59ef9195363133679962bf2572bf2572bf2572bf257258957ab8d921e093e69ae2f272bcc5fcaf2952bffc5a47c71294bf25f56ff5296bf23bb942fff42f25f5f5c5cbeb5ddfff2302fdfc2bc1ae7e55c5b92ef5c99a3c9e55e4d5e4d5e4d5e4db68785098a83406f95295aeefa9b2449d2db66520e9d2437f8de477670dda837924fbafc6aef15b97f875e91dfe624d5dfd5cb6a45becbea5dc8fda252fd6abbac5c48af3c5796e9cb15f93b7cef5526399aa30b221a9e6b7ff059f93fefe4bbce04adb55e71923ff96ab222c9578efc171372a522c9d5bf98ac9c14d12a72f5ab73a57279d5ea57ab736db7eb4a2e97cbd1e472af26af26af26af263a0fca08a8a029a0b7ca088640c5d59da1b5d649abf79bbf77729ef9e73d7adfd3d848f15e831f8e6388c7108f211ec3f177e8d15c6150c6579949e2df711cc3578daf0abfcd4534bae68026913fc41f7f47a6b161a21c4f5548ee98d6f149733ccfeff3077b8277c2f33b576f469f1d4aec1aa6833981418139810d017332bf1eeec4f03c5726cf833d99299130beee5ad45a9f5ed75d77ddf5f7edec79f95f394fffc639e7df5ac83b8b6814ef294f680f7aab84a08a2959bc2957a6ec3c6f6db7f7ddb461a2a4b191b28aaaefbf26e573c5603b8aa2289e6bab3ac1ef4f92a3b80acf76a3e0e9cd941f1329d4833971cd614e20cc69f55eef7661e881a0863d813d813d91da4ad0a1e2d6df66149bf8eaacb5d666521125fc8b68349f77a36d5ef1d9eaaf02f5416f15104085208a104841454de60f01141405f456010116a4507e4c8e66f9f95cbd07c573157fe5927239cf91e75095ea5cc7732d5736524aef6c37ea8de06bd3464a299e349e43bdfe2b535278d2d8305182a0deaf357f7d7a2e88bfb58ecc5d47fe7ebe9f4bf17e83bff7fdde61544498132a86abbf5feffc7be7dfe62418b9f78f17d1e2e3fcfcdb6cae1985f19debaebbeebdc38001c37e18bf23635314fa1ef39d0cccdf9792ef549beff6b93fc3743027fb330c0abab6593493c2cf01dd1746ce3011bfb8c28610619c49e28730604f6836eb078c9375ae1915614e68dfcf8958b9ccf31f58bfcf50fcf057ec42d84f56f8dff3177f7cd5cffc0b1ffb613a98130cdbdff7de6b9b579813fa0df5df67d27e181ff6cf45ccccb778f12efbf97f3d0ff54fda3f46b47fa97b31a31af7b97e1e155414391aee2d9adbdc3b84b1236f9813b4bff7dcdc2c937c1a537cfc9ef9fd0b7334759e7961ba7cc34317e7fac99ceb1773c29c6bd9e27c39d71997b3d4a238f21ce79d73bcfa4c0e75544abb4addfacd8452620e5d25ed73ffc0ab93e5bdf8fc75fabfaf1ccfb5d4a1ba84caf5e72f9a3b547cfee09326cfdd1cf193c61f232afea002214a28543fec0986890f3e4c975b17e6847ee6f5f6defbbd7ec29ee01dfec5d0601744904247f4e5a3401005bd81de2a4d4c5569220abd416f95269cd026aca0228affa543c515577d7fee945be1f7e743f0270e8547e1b91e9ae0878f3dfe8316f14966fcaf1cfefcfd0efdb5993493c6cf01c5e6aad16f955fe4f764cf2b9757130ccbdf93c81fbfc72f3f5cce35a3e3bf9c6b46c97fe9d0fe18e75f71c718e73389fcf1fb6b74ede7bab1c7a42407fcad38a0fdbf737d0d81aedeb739297f0e683799d06fdda8f721fef07c394157af8846578c923fd68ce69517e68ce2ffbe737de950efefa75dfabfffbeef57efd3dff7e5c72e308cfdc9c7663f59e387ef8541f01f7ce0ef3ff0f7f0bf7f31c1b0fe5fee3652ca36a37d6df34b87862539f4f2fd4c7a09fb4bf885e18bea3b574c7ebfae84f8be3e46a122c93b3a9a172549b36f94343bdaf3fa62827edfc921fce07b2ed87bd00c5f9b2d7e9b30af5cbef1568cf2f263f02c28e78f31f8abcb9505cd9804c95f5f4d30ccfbf25c5d575c52683fd776d3d83051aeed0e1f277d8861f8dea3e1c7a40f7cb2c01fdffb7e450894afa6b27cef6d14ffea57d7159446bef7e2c3982dccf15c9dabeb0a8a3f893c57ec913f461493af2273eb6a0ae5ff6a8261f85c5926f4fbf1c57fe572eba2e27752487ce9d0d0bc1c05cd8b76144c82f6150128df2828a2dff96a8277bcd3fc609e62b488351c30b1de576bfdf4b4f7d69c73ae7befbd6bec799e5793022da575396a6a0a3fe99a14945afcf83e316fba39fac4fa6a8df914a97752f9a98a9426a89aaa78a0021adf75f724a0190941d4ec9084140c1421a5082949f42b528040a538910281242ce18225ae486962da9d402a0328d8a1033a3c1d6189231c518a2e30c11551ca882598e0c01223582205bd054a00015562084a1c41092c96d86189dc120cf89fb1c4138d031e8c31c63a9c22ac22bca20cb1981197bcc8e486c74a283ae9d0ac45bc55f70909510709cff3d3381906a62cb9d6d8d34c2c19c2079fe87befc393bfb8d249fbf5633d14a2fc4530d47b46fbf7df3fd4b9d6fcf333f5be7f489fdd876d8a7cbce450efff799e287a9ee7f5ff6aa494eb875eb9354a94df63d58bbf3a6d76a5ea8442bd176fbe8cb599f34a6bad32f7de7bf59c73ce57bdf7defbea456f5499354d94e38356f2137f9a9a8a8af27ebd52ab96f254674d13e5f71ef96228ae5efca195ea3f5475ae2c4abe78b27c7ca8f81f2a9e2b8b86cf845e5225fe90eadc79cfa43a59aa5f3d4b7c267475b2aa93470c4a9ebd09f55e3cb39555eff6efd07d556205a569f149fe194e9cf7ce58c5a8bd77bec0bdd9da29bbba4ee3eca77ca3cb2e10898b737174fa29b77a947e81dbea1cd82ff22717077e7f8fb21f478fa25d3aa771f647c92d8dc4e6bf00ef5c35da4f0dc47581bf571eba791419677f14514c314515555cb1f73ef5c9afd4eccab547c9e56a42a0ffce58358a5fbc49a898c71a24caf523f9ebcd398f8ae23a5def5d9b3d2acaf33c4f9bdff77ddaacf1c05dbf1a0fdcf543a7a6a2a2b00eebae94d4ca835eb0c603a48f4f9bf859219b5d897f4837e5489647cc95dcda6f258af543bf6f9fd94a888598ff0eed20190606f7c71806467b68d737e7e67c687f1e5832881f3e911882e707f29a292528cd21fefb41d2071735278746b4bfb82acb12f8e8af3f7f1b7fd7f34ecc63a0b5d65a6badb5d62cadf15facb5d69ee7791ecbfba4fef9bdfef97bce5aefbd4dce39efbdf7ee799ee77956ac4c4d4545d52c316a1e31319ea7bd310871b766f2cda77f983f1a27f7c8acdb72e1de883fda35a371f073feeb6aeca1730fed7a8d93bfc78feb4261c5bbaa8887e295877a49572a05e1949ea922434103cdf8b71983ae5c3c93f4ffa3fa5c85f6f3a95b042b8c70c5119090042d4a580213b068c2169e45930e3b2460090f3df890fb41010b60c2809b9385f0d99bdc9cfc42f8ec40dc1c3e353535c59dc838f9ab7c50cc549169e42bb2967cc3013084cca7388fa90f07170b114e6e9073810a72a0c3150be01b83e0cab7c405960882123ebc311ffa9a26000325a040cf95099df14419365da0f173268736c92fa9bad138fb6f340e46552fe6d12383a854e4ab48d5efc89b3c874254f5a371f6dfee795fe736bb12e692e487c92079f5e4afc8df91fbeafc6ece470aedcf1b4172bf7773f6df9bf3bdf88d61280ec1e49bfb2339748373b8c773cc3743f7def07b73ff924364480eed7d73449024c11fc92038a148ca508e771cc771c4f953914f861787a16af5e5796fcefe15f91825cf1587aa4ef23f941ccf242d722b3c2b88deff5104eb933785a1111d98426f9523acd4406f9523a4c2150cca272f9ce18232e6e902795f8ad9333908963121cbc7daff47f6de8b4157566e4e085ef043cf95eb80661fb9095dfbb35cf0fefbef4cfadefb8bae2c17be071f3c933c960fd44373ce53bd09e2cd57ebab84134a3481aa59092594c0006f42cbff6074aea123d1e480174838c087992824228084110e408204489c00892790c80112424082093b1f7641ec22b0dbed50b0abc1ce073b2624914b0202493c452009100491440b929822092c94f84189274a04f1a2069d08d709225ca0a5092b1ce0440d22e00acf9ac134aca77922d6d3d03c0b06eb61641898bf2e7ed5684ccc11a58c8fc17222b7d62bc58262b1a272ebc56f2968a45ca06476b935fe7e192932503253722bfc7d450a746be9cf7aa6a0dc4f960c34cf7a229a67c9789a9388e659cf3a95c4789a9329a89fabeb8a7ef935e60a8dd4cdd92d7ebd5a647632524c19a87cb33f3465a6e49bad319025323ec68b364cca3d009a3fe107c07a18381c4114e3613c0e324e56ff139ee64ff88c438c139ee659fd243ae1a461113deb619c20089afd2f396aad7f95d9f1dc9a1f7c32bc68488243f2cd064f19167737673fcb14f502cab547117717084abb58bf3ddd9571f1ba8be2d61e2944e66a7050f65f7b941bb4803a8faf4d2634ab40f10a78b36abd01cd34e6ea5d98ab4665ce1e853fa131e6ca7f803165766bf962ae3452a0fb5dbe5cbe3157666fca374df9662fc937fb9bb838fb830842082188c8f9bc1728716fd2aebdc79c168e65762c285024557faf4bbca271f6e72857b4ea5cbf4f6719579ae8270b6a49b95e2d489434e5724b6726acfcfdb509630384cd0f25cdb3f6af48f9667fcb3259501a673f8d79350e2b0add4f23659380fdabcc0edd2f5ec9ad1c85546e65c9ad5c456e4d895a340cdfaff9fcce9bef87f156f5119565d70dda778ad59964f2e740bc33744e4f9726ff7d315d4cf1924361ff8db340ef5028b6782297f36a1cd513bd9c5ca77154e3487e2785c8b22c3f9b353828cdf5062ddb5ccdd55f12ff369950bc1a5f65ae2e2ae828fe6882b47dae375841f77b1ec9775194f9fbd0af054c0bf3858952af3b34cf8dbd3ca5402d4794e28fbf8a3926a52eb79cac769c0953107e51fc9129c8c3a2677eafcd8e3f3cd75512abddcdc9e0b98a3ab1495c22e64426f9e68657b4eb6a9ca7ce55e7effb7e15f1677226949faf26a358eec0ccabd8e8caf552592f95f552c158dbe46c7c28c7ecd954a0dc2ef0c327023f3c951ce1bd122225e0c9146443019b1d4a183b0c00a9c70b3d80dc28d0ac7972eb732b6774c6df5c1b68f632478298c129fea452c2bd404dda057e0699a02b38b572a7ff9e29e85472c47d259f4b8a280ccf1b74f111e5f7a04a8b76dda0fcab25aaa7702ab7ae00b5805828013f9dab6a2b41f574733238054e8157805a402cf24d06a7d00c964fdb02227f8c73d65aefbd37e79cf3de7bef5d4aca46025252566c24e0020ca87fa8f3d73fc435f7606023848d103642d8086123848d103642d8086123848d103642d844c0c6c96602364364189b1fcafe5ea6f1ba548b2c1768b7f8012f6205d59b5a64b9397a0585ea35b47273f4f39c8e422f007c805f54c088e60fa1565121540815428550df4e8b76f19cc6c1afd33939d1ec6a3650aa6a8a287ff0e229ea05113f8029a350fce2e9e6e0100ac53b34419aa7fd01299b2038b70902a683e9604e3aeb6e8a38ebdeb5ee5ae3ab55fbbbe9bd36b3eefa5ff83929a4ff72fe39f7ce79e77de45c777def3631d79a6bddb5dee7bdf876a81df889abd5f771fc63b532f3efd575e5d58404c1578de35786abd5eac599affc56ab57eed564c59fa0a84c1ea50927f37373755d71e29142a0598edf4b9749a1ef1b9b942f5d4fc107650a9407bd553e20050551708ffc21a21863f207ec09dfa157bedb917d88ebf763a87afc34d5b99227ec0939c44921cca39ca0a27f2df3c39c843ef3db186f069430274c5e2c9f78c4500c54144fa10dc5751ac743f57b2f662c86413c2acc7ac96a889f302721193727ffe5516c50ae32a4647c1dad89a2c4b7a37746c65388fa3b50864d48e5969725ac2284ba40f8330cd0bc0234f3a71d8fee99e11553d8ece815211651c2a928ca704abbc226aec880c1cc0a4aa0055dcb1b3ee5895f80ab6e108dcd11e57efd6153b824cc854cc0281728ff7aaf6c2d1b0bdec497e4d68783f2eb9cc35799e7da6eb19be087a6f8993c57b00830cacde13cf7997c49bee1ef81e6d6e29143380b5414c5f07bf099d0dcfbd612ea9a70f1770c054c077bf2f940bc33f0f8f7310e9641b97fbd41797efae7c791ff7bfe798320a8dbf7e61c3491434df456819a0215f178fbcdd1384acd0dca75856afd25cce51e0eca511ccd357cfe3db8238b2613dacf7c458641836de502c9809a12e584d3146511ba49a465980ee60473426154603a241df711883c97f3df954e9bfdb3b9b3de599379f71c7ae79a5bd17c6ffe9befad7f9bfa59f95fbaaccd570eefbd8b7868fe8dafceada9ddd45d5d57d0b5dde8c73fce75d7dfcf8b77f6cecf5fb99cbf3b2175022750318fd98583d0bcb3f9d2690fd54cf8732b7fbef1f05e4244effd3b23eec7f8e646e35ca2ce77ce7f4354ebd7e79500d65aebef3dcda33f4febad794d13b6d69aefd75bf3efbdefbd27fabc10e4dce324d177fe78e7cf9745c9f9de9d9ff7e6e0f776b0bbeb6e02c5fb3d4f67a71820959b9363682727cf09a704942b7ff2bc5d135bb66cd9b265cb962d5bb66cd9b265cb962d5bb66cd9b265cb962d5bb66cd9b265cb962d5bb66cd9421384104210d1317eaebb40b96ef2cfff8917efaceae6f8e2f3103ef89964c930bef84427d189f5cefb1bd29a975eefdcfb6de2a04bd630a1cc21d4cdb15952ae3c0a9b253973a69eb90bc49bc51a0e98c0043230410dd01922c49b6b76e052353328571868f6d0fc18669bbb07a57e7c5e9b0d943c4f3183030860315a6305b622632bb0d6d80aac37b6026b8eadc0ba632bb0d656606d05d656606d05b6a2c68aa9a91a2bbe2cb475fe1af04096f080b3f2303ed7691c91c7bd3737a20cf7e2904236bbb21c397966b24608e578b2787494ff28eef1bbd65af31f553fbe388ee3388a7f55e373b3a31c2ab7303a8abd8be7688acf773abcfac33b2d7e163f141f14ff13dfcb1d25c5f15cf78b2787ca37f8c53377813c73b7f21f780ebf3649dc9ba0f301162c58b060c182050b162c58b060c182050b162c58b060c182050b162c58b060c182050b162c58b0883f8e3c68ce959749e2ef95dff1ea707f8bfd2b5cee87a1c5efb3243fe6f7b9c2fc582589cf45d1eca2f82ef6b728c5219c05ba5ffc17c82f5f7373e52ff257a9f8bb98eb0d5954bf4f56f9fbc5e726abfcf139ab3c7988ff2e3f8a7b14c91727f2c53389fcf24c72f1fb4599b3d5688be72f9e6bccb94ffe2dced51e4755f99df4b16158553fbe78ee7cb3b63874d287866154ed9dcbd2a6017baf3764110a5fa471e1b1dfa52cbf3ccb972f4dfe62babc4aa57a1795d3e6e6dee2efe7e63ac34dd5f3d234825197f7f68be28b3764415ffee5344b73c5a8cbabf8f8dc54bd8b5996664655e6ba3a69dc6967a9a1a2dcfbb9a9121f7c95b9e64045293a85e61214ceca0d59b45600153e40b19356001554ec563588b2b2dbedac48e9dd6e777795124451e5bbdffd76c01ffe14347c992a253002d5ffa24ffd9cfcb1592c9e3552ab1a299b060c51822156ab526ab7db5ba846aadc7b550226bb5d7983959d959d951aa9ddae464ab5a5e60735596a82500304fee313891f3e0f78e7fc658ccb8df1efbbbfffd03e79eee4398cb3de9cf3ee8123376b7850e6d73c08f70f7d99e427cbc7f7fc873e7eb2be079fc59f09054ff63b799c3727eb1733292454230599372954238546f7de526c7473cea5e0e8eebdf7fe799ee779520c79e8ae91a2ccafa5a4a6a6a428b18f4f3cd7a4a113d07e02ba776b99831a1d443da12aa0b70a0996a0e2eaf2c77b7f7b7b68ff1cd0ccdfd3fdb7c9bf0b71eee1cc44cef8a2e38be369ae7c278ea6cbab9e87f257af49960c2eaf7a2297f0554f549e3a11ef9df9a77bb93db2c74547af3fffd1c7caffd6e0a00ccf15fcfc5a1c023ffc1d9ac677f977e87365aaf80fa8fe1c365398350fc43db4aad981de9b73ce7befddf33ccffbbeeffbbe9a1d8064cd0e4afc57dfe7bf33cea48fcef7d63b676f6ae78477dee1bf742fdd05f7f63e97cbe55e4c5eb9571328519e425de884f233772577259763a2fb767a87f7238139e51b0ff5604ef9c6f33013fc14f1ce6773853941f777d813bcb3a740f9e7300b1a4ae51b7eeef4a34c7a3fe64c97a90665be28bff9e6e342380df194d32e952ed702d18a0ea142a8a710ea29847a724108154e09a3422772ab875572ab8b57ae44f1cabd9abc7246440977518c087731788af204258a113b2950e1aea605207fe962f014e5094a14237652a05cf0f404258a113b2950af262f27215494a7904a9427283b2342a870ca5308f56af274828f69ce5c2ef7f46a128679f46187eafd5c8a87cf19f4c513a62cab8c2fe23193f81ccd9a274af1fb4a4d5e149b17ad794199043eff1d596ce972ebe6561f427cca2df17bfd6214318a68c42786fd7361a3e0f93b74c7678845bed1926fc4262d2116b829b7565c5305e4f8ec353028bdbfa1969a17949853e155b8150e05cf2dfc1a5d31bac29ee01d7c0e81f6afa1bc55a0a008b538e5d61a6ae154aaa0fa7995ecc241fa432c72eb0454df2a504c564e05d5ab98c33b2bcc49119d4516334c2bbbe2a7c11e952beec4299e378e991cc7f177e4574ea57afe959f7ebe5a9d364c741a57fd2802559d9ea99b684dbeca24cf95e9d5647ce5f44bc73dbdc751c348f1176b5a5026e132b7beffb7be747b84f93eee3404da7f47c6e8eb237d88a83e5dcc1594c6c13c62a0dfaba46e8e508d104afc6bb8ab4111280e7778b75a018a4f11cb6a05687f6de218e82587b0d405fabebf67da30515e2c287eb08bd80c3bdea19d3ba1df7328277fca3732d0ef65a0fdbfbe8a0a775ac9c9f9f3efbdf7ce4f1829328f4778b1a64a99e43d477b1e31e983a3de7758a2d079800c34855f8f18460b68e2bae4b8cbd0430eeb29e8081271200a5f8f1e7a2fc816c0193b06d0050c0c1b1a99143e155c0862a343f8e9783ea48fcb07106fdc1e0d07d22d70dc28fc0e0ff4c2bdc35dd83f3b30676993cbf0805f4cbf8460335f2803ba74602106d1c677b367ec197d034d29a8760b5c051e039cb161ac6ae8137668d2d9c19a88ced99a23e03c80034660ab21d1012b513b24360045014c3820619388a8b12107b0a18601cc200021405e08400fa01f9f1b9b1a00fc4e010ab22042155856d05173d2bcf09e5c5045031990416805a0136246b13b3105044744d100940b10f1340101dca0b0a32381081009c9028b2b8c6a20c2104850647369001033223a60a11725089d0bb4c19522a200bd5a2e60c4f0f360b03ec0840daaec470c01f0c14388024d7ef0e145ea860890e8c006986898c1d59a81d930b062841974e468815e4fa20710286181270e5800022a40010a00f123061d301446cc04bd84ac654ffd1072968d254bc1a5f00d720d320dc0198c506418e427f2949c84462227ed15cfc032be13380cf245769163308c4b0bfe925d70b95559e46106bf2f7b1ecf1b6b8cfb25579aa547d0b419d0b45fe8293cf68ea043998126ce47cfe6063a6c226a6c1723140e740534ed17409910c64c029a4002ec1a740cb1ede3c7e3fbe9a186cd84bc054d1f54138c0d3a802e3d012bc61d34f12c9af8484383a6b13d47d004cea8b207e33bdc492e467c01811d3693a695b932758ecbce37e392c50e5c85efc7c3a1571ac707a549c35063a787dd88262d769a4d43aca1f11e378d900757c12340a7e9615f479811069c01653c02e826ecd069f46e074ea5a966dd4a5f5473c2061a57dd65639da359d84046173d7b34782c2f061ea3c25dd47c8f5aebac3dfd693084b1b52700ef65052474f1ba87b5b76dec9d8dbf179aa503288373a04965840e2e7db3be1676d83bd8e12cfa9bc5162c36b802032b2ba0823b1212844e2868851c2e5b8d0843d841a15c7d5e016af81143162f8022063280e07182c08e08eca0064fa880041f4042033b3a364f702d10eced0845988a620650a0c0034c391cc0861a06f02386211e3262b89099120226243a90030e4527c0b0d564a876a083224a4d596c4902126c28800b19971aa820052520c10798480288263f141d800034fc88c1c7132f48810b44e0d40307377842052820c108320065013c24a008533598010946304589254daacc87900b3945c5143b58010a420002294504c100555674001b0a40830f2118108e0bf9c40b5630010904b144951d20003e7808c18054e4be544cf1c40b5890821080404a124534a0c9120304c0470e1890cb460d9c17977db3a0620a1db0600529404108409044110d08a2090396f0a0c80036acb0a38305135e7061a5ca010c1d93050c80061e0b30600149901c0166a1b7e4267026e4257c1cd81bc845640de09e5c43f3601d3147aba05f46468681591e8d7e8167b60b2c03b67879d1e55e8daa92a4195f88304217d0fbba977be75ce34b1396a0967b2f7bd3516946695b9bdd967654992d36abe14eb8177b60957e4b900225f8a4049770fee65f95cdd8daecd9d9b7b38725b9a5b71429f6e9ec411d205009d2b877c81fd5662ad291c7f91c38fe26078eafcd8e54a30f8bf22bc2bd439e88edd9d9b7498c0ca0a3a353001f3d3a0dcfbd1c767214eebd326ef9d12e7bd3a9ddd4b64d97766ead0ab7fc703e98daac6555d97f6bab3dabda648f73a3c66e381b5b7a48f0a4aeaca6b6e9b3a51725aba9a5d7c453f248ed514da53d11dbffcd46e496b6ecab47b5f486e4bdc0de746e4831255569478dcd68ec057788712f88807b559696125171b7f6de7d7e3b7d8a8b73efbdb9f7a270622aeeabc6ebf8db0d174be1f5fa79b95eadd78d978d97cfabe755e3c5f37afdfcfcb87e5a3f377e6cfcf8fcf4fcd4f8e1f979b97e5c2e57cb75c365c3e5e3ea71d570f1b85ead9f96abd56add68d968f9b47a5a355a3cadd78d9f1bae1bad1b376ed8b8e173a3e7468d1b3c375e367e6cb86cb46cdcb061c3868f8d1e1b356cf0d878f9fcf8b87c5a3e377c6cf8f8f8f4f8d4f0e1f179f5fcf4b87a5a3d377a6cf4f8f4f4f4d4e8e1e979d5f8a9e1aad1aa71a3868d1a3e357a6ad4a8c153e3c5f3c3e3e269f1dce0b1c1e3c3d3c35383878707098f7aef65dd9247b9ec4d470957db699588a8375bcc00050869dc8437383c0e8f807f1a218d1001ffff7fefb5b9f7d6dc7b678c5cf6407cc7104e53721516f7de17b7dc3d1832e481421a43863c504b44a5fd8743705aa4a3d9edbf25a2d26e863c904ca5cd52226c9a23470e935591626daa0480b3dc4718f1345040e1dbf4656a526c564b9796dc0bb4d372a3f7d9598b33fa67672a52dbe260b8d96e37a123b6dbcd16b461dcaba3b3f3bdd7bba56682958bf338707c8d9b576bb618867ccd366b977e3871ef3da1eead1971efede9ded6c9bd3c36dc7bf5fd7bef45ba17890da5eea189eebd3694bac7bda7117bef1572cb4c057bd3319ad1da9bcd28bdf7c6dcdbe2de3be3deedb2f5bd2a8e961af921b79bd090afa55fb3fd109c9ba5f476a48603026a6938560d32e4652a8d96c6eebde5bd7775ef55ddf1de2be221eebd02b825b652e22ab9e6defb40acac86b3193d11dbb738dbdbda22f6a6c3a36343a7460eabb6498c767c7a7e62eacb48f67af5b46231b5468e922da66384436a6747496e2d3b3b526f3bb6a35b1adbb9a932da0c67b4a32ad990763e078ebff786f7fb7e626e899b6e3ba32db13fa44d87c8dcf256b9f7bedc1213dd4b4b8dd894d4dbbd97bc9763a007f75e7ccbcb837baf8b5be216f75e985bde2ceecd814495d5663795adcdd89b8ecca6b413538de03c3bbbf99a4a7b1caf1abd8c86b321b18f73ef05efcdb27befcc2d2f14f6a6d32a11c9f766bbddd4afa52f536b375cabdebe669bb5695b539554da92d2ecdb597a6bffa8366bdb54e96623f269eef75e18b7bc33f75e975b5e1bf7de23361a919b6ac4f649da592c5d4a63ec4d27a61a293a92de766237762766a3d1d29d24b7f46634a3dd7bb9def7de3c566122dea8a626f4eaf10927722eb724b7cf1e6c9a48e2bf733eaf0be2cd6611cd69df921d74c89ff7bd401a7b60efbdf9638c93f02a84cf224a56fc0160eabf9518c9cf5bfdfcfbefd05c7325016042bff7ce6d26f1b38812143c933aff7dea353ff6cca44fc9de5aebadf7de5bebc7ff831721de35fffa3df8d92ca22f3f716b247f7fbecd223368523e5b8df6bf68781651d203a31f3e8b2841bd33697ffefefab57993ee5fa60f6711883650dfb5f9808d1238c43be392667e11e32012871cf27f6753fe3d8e0f7ae1fe9034f392fde3631307f07106c96df6b04290fed05c92c341fa7b582168ef279f488fa249921f8a9fc341e192f145f02f29c30d02c7271f9b38848fc113872388c2c78f83f8b93449160fef93bc530349f2f7530349f4af80969f7983447389f8b90f0aff339790dfc307858fc9b3e95c82430efac3b3492fc97d10f99aaca1d44f9a38e4a05f3c9bf493329044407238287cd0cce1207085a0f07338487c319be463737c4d0ab164d84f7e0dfac7ffcc25200d4c41e489c31144e2e3c7217c1307510c4db03f0eb241a22c72b340fb99a48124f9359064ff739225c3fefc441a080964ff2581e8ffde84f86997122539e4d79f03fefd4a8e20f2bebf9225b90fe2dfc3071d41043eff1cbe0fff9e4a7af8207e2ac9a17f78e63e483f78e6f09db90fc2cfdf3b73e8f8f9a9ff7e0e1dd7441b107cda1594cd1e700f7b49ee88222ba0f87bd8e711455640f5e72218d3207e9f077b72613ad813981377c2e45154f8141694f8f21d86bad2faf41429a2ae0558b08008e88a3f08829feff7ef5f4c9abc74a0c98dc026cfa4503f77bed97c976ff4d7aca0cc8f3594be7ff77fae2bda85ffe67bdee7cf99448937b7f42e7b6c1c60a3b301c206089b04e83eff8ece3dfe719023e19c932f92e68f8d037e702001af96ef6af1ae967eb53c2d79406944dfed96b8e88cc82d150edebfbec364df7db7ceecbe43b3d493eecb65169b0794ab8b4ec6a9873daee0af9ffc5c65a0ba7e05bbe844a953c669091299a8510130523f3b3c6fa5fd3829313a8423dfe47ebb138cf64ba53bb955f4d0aeeffbbeef07c76e5f25a019887cae6c9e94eb4a0a34c687d2f8beeffbaa5001142a3881155554206595751f08835bb87c7e202fbf5e2b65b9962dbe9798181ec363788c39eacab5d4953b3397badccab453564241751905d5bad4e99e722ba3facb1d1e195066291454b1b3470ac59ca36e77738bbfda55ea97dc7350bafcfa4d69170ee238e6e43c8649bc42d47239be5a254ee972cb1b6d9a942e2f6644117f6658962fe726c111bb982dccd25ccb75e6d17eae5c9c128ae13cf3cc31d7dfc91fdeafb47ca3dfe68717e6d538dc46bed1dc46877215a7a6722bbffeb1e98adcd2322e1973b9a5cb2d5687c1fb357fccd93fdfade23f34f32f64f0cc8b9f79a2173f33f32f5efc8b53c98b52873a5da0ac5d2fc6f1ef8a5c3d39f3e26762a038c50c11f3945b2ebe1301137581f2772da5ae74925b31afbf742a8540b516a750adf9bfe0274b86997ff14433ffe25472047f252f7e869f44343ff333a79299a739734cfe55140226eae668f15771aa8c314b27a5d310f9268f2e347e61b2f2cf982c19f249f4e2699e88f533cffa99f75e9833a614ef5d5c644cfe97748989898931d7fcdebf742634bf0c20df68cf3b6de02f66cc3b553a95ba28caf54ef12f677efdd0722dd172062d75f92cf3ceb8b8fc7aa75e62fee55b982b13dae23d52a8c58bba08ce62ed660d0e4afe2e9ef7313131264c0ccccb7b2fbf43b778717139bf95e756aa1f9e4c1d4c0950fde0a7b577ee9bf356f1df913b5f471d93652cb9f997f030feea79205f85c311dfe330feea3bf9aaef7f574f34feea24225f755e16c3d82ca0e451f4064551acc141197efeef2bf7832613fa79fbfb26c79d7fb3a4742d6dc9068828192b3b671a17ebef972c73cc3834435e8cb912c3471917286fbd5a5ca05ca05ca05ca05ca0c42b32315762aec4441123159325a68a98a9182dfa6ab954647651680f2526856e4317fddefb9b93733791767d888c133254d0fd1e29944fd9d849a1f245f15c459a2ce020a97befe7c0f10f34e4a836abcd5225f536e45b365d7a35564b8dc86a692ca6ca6c2c282001413d502aa80f57478f0f8ebda92cee26536f6aed88eda7a706aeade16c4ae90e17e4eef5a10795add996583588526c0032da0f590d6589da9a7abbe15848c2ded41991596b8b41a60a51d5a3b4157234834176b3c5d4202acd687654c3f178416d6d4a6a90db4d28e98710118bca541e4a6aeba39dd1c082dad67cace0dd24ed8c366b71371d506c7ae469b434f63a90866ea9632645faf46b3325b59dbd4a3baacdd847cb1c52f75e1db6c519f5dc328705eebdb69aacc70757e6507394578746538fb0e9d3a8a94666477f549b3d11dbbf4e121a0d47e4d556a52d29d962b299ec59f589d8827040b9b822b31a4e496d6754c0906ecf0c35b4c60c6d4d554a922e15a96caad2d42047d4184aa01d0882a14e1223100443f57176d81c968dd96439b559aab4639be9e8b0319b6c6707885d6a5ba41b03b435d5885a8057918840100cdb9a6a44480850d0bd37865bbeaeb8f7eab4ac7a748463bf453a9a29bdba94a44d55a496868ad4d65425dcd12d7d15a955656a4d5d5a4a919e4d91be669bb1accafe113586d70f2acd16842d8aa5291bebf1c1b14a6a3bfbf1e12ac9d09b7a83aade78dc541ccbfa5069b620ec527a44087b23e20144496d7dd05223b6dbd2124a5363b59405a2761624536f335c1135483b636d4b6a0b49684b4b38214852b5c519cd6e6d8bc220539362365a4d00ac92dafa50694629912a8405d5c84c8da941643555c86dd6821a9bdd8010a9b16aad9dd17053891405b5ead12d6d8b64ea111b8d96eac0a1aa448a5e98b5341c0c311bada8a5833d4a693cd25b8b4488464363ec0c0655e56154b3b1a91ae4a7a706ee06939bc4766b59b5859a7a83edc64335327b81559792a82c9b16b52acba23672d07feebd416e69a3bcf7aa375c9baa447e085bc31519491a22536946694d7dd5e85b16a7f4b25a3abbe5245193aeab868e0d1d9e9c231b0d77ef6d4b9f2cb71a7c94f4e8f8d4d0e1c9a91db1dd8c90d814c967003d6ee9f3828d48cd47cba62fccda59cdc70d335a5a9bf1104a425b5a4255364502420404f4820e99bab434bbb52c90129b1ec121a5c694dbc6d4dbcd16fbd65663ff89ccd42524eab3b35791881e36a4e8662b1a225391d8596d46e483d89b0edbce946a4a5755b209516bb618888e6ab35b2b2448d112ab2aa5351680808cf4f8e074dc54206cd14d5d42922add68696b6b8b90a44a3a702049956233b636bbb548d422954d8d74f4f8e070dc54204852a59a8d488907766bb6197b5367b8f7ce64aa919bcaaa4154f5c623c6ce948080d89a9a646b8180585c9bb642d4582da5a5413622351f496eb63695d5521868e94d5dfa414b956eb618d82429105625802d0636490a44558914b149d225964d692cb06c4a8be950218b21b129520da72acdda1aeea6a3d21973b4dc210f34e4dbf4d5366d9770b79b8d05f6a6434b7768295099737574745068551a8d36556f47dfda62781df669694ac3c56869ec91dad9913faacd64351c104d35a2d28a80d89b0e129b22ed20b1291210507bb32d2de1d8225529bd11a1f1c2bdedcd86c4becdd602a9ec4d35a2debee6e3de4b12dd52852cec4d4756535b24eacb016ea90292abb6ac5a2bbaa9edac48c9762352145397d89d986a44051b5208020eabde6cb1da2c4562618654f381c4a63d74e8b8f5c0414bdb9aed86d9cd86a4a348260408489ddddaa225d688ec961ea91db1b570c42ae9f8c1e188a9330001c554234040b2962d5a62d33695b569515b53d9b44d5b90a56a0f59aa22c5d0a3a8a8c70767c4b65484245542e18ba1870d23404045ad4d9626d16c4b699bb650b3cd6690a92d3b636f2a90195c584a6150d51b51108d86e3618be1681664b311dd54a4f6074b9ba5adda824c1592f4a36849298624491a536545b7a2225509c7aab725db4dd6e38393d16c48ac7a436a8b64357589c5b129ad550357d4b2b719119acd66d4b233246a114b4b6b4733b6c5fd686bea6c6916536f3a7078a84b4ab1013c8d189262365a50daa6b2b455958a54a59a8f9b2aaba9ec8cdd3daacd6846332140404a3124b5d9d1ecf603004af001004d1877ef1d724b0090b7b6a6ee2ca54aaa0e1c997a249bdd8cd0a721f391de5220373862ea0c6cac6886d3e3837b1a3d3eb81bf586195b244362d31e4040b254452a8a15512a2aa224bb4196d2cc72d9db03cc23bf837b89d86c3720aacc16535b686b2a6b8422c5da54899dc1d0da6cb2540d92e4d6d68468a92c5583b4369a1059aa22a1b6a19a6da6065165e9ed684900b254ed112b024311a516d41b6642549c8a930129d6a64becac859a8f25a55b0f96556f47424b4ab71ef7de17ae0b01b897a6d66a29120b4b4ab71e6c91daa62d5b9424a5a93720a0a2d686c42ea535216a9bb6428e6ab3a3946555188480811651cc60050bfc808a1544b1018e02c474a6cf03a18b079e08e2437043ae198109183cf400aa66c5c30b42983ab2e70113902225c78a9927332f9841112de410032205e4d041bff7f210a219a52d4e49e8e602c0c5bde92d6330b949d4a4225a1ab371e06620466943a7864e8d1c9502d8898baf9ce09627c0dc24b514894d55224466b24f5f35922221c56648479e46929b4d49557a5b5b9bc9521b4da6b631dcad656bb6183bd3499f880d89c57d12a397a9af1ad5d2d8bd2cdc7bf78e1772919bd4b6e9a76d2a7b36497a8496be4c656748edcb6ae923b129d2ab325b2d1da2e268e90c404032b576e4872a3baacd906269ecd55bfa2a0df7dea07b2fbae3ee9862099764b3d158bb7b1f4895d962afd28c52a458aade6ab897a90f549be14072ef855971af11eebd04b825ebaf4c9ddd5a578f0e4f8e912c479ddd5aa0974c35fa24b254bdd1d27bafcebdf7862213b8f712b9250dd2bdec4da74895d96ab35bbbc3aa4666ed4c69765bdaf171a9448c8c5c3b357a521e974fcc86ccc7c7c60f8feaca51dbf4d6b2463876876d71b6a4988a14db69674798878e4c6ddb9992922d86519da4586a64bbbd6af4b534f66d8ad47ecad6d25bfb3575c9f6b6189a80c22d5fec5a9bedf6ea517ab3b5ac12cc5bbe6897b4bcd871ef45a1c6aa36d9cb5215e9db9a7ae3f7b670cb992ad89bce4e91daa6b2192d35a2d3aaecac9dd1d2da4d6d91a84f4bdb9aaa54b3dd66466a424aca1926f72aa92d9b84cd59da6177eebd30dc72c6c6bdd764d35b0ae46baa7aa4558d5e6553f516abcd3e09ad8dcd6e2dfbb6f65999aad6fea61a29e16a9f14b3d18cbe364b91629f24a5a941eebd3faed60d1b3ef7de9bc3fcc2bdb7e8962e8adaf4686624d5463cd93374285a56f639723cce4d4da5e9c46eec027cb8f716e0963158eeadf13944682afb39723c928e7a2453d99b8e2ab3d57654f5d61aedb035dbac8da9349a2db6d332528918bd7a541b3c2d1f998db487a727c693a632998ba7461a4b7f5e3d2ed5c7868be7b5136b59dc6d8700443e584081a02c3c8e47229ba56dda827a940251712aae48d19292aca85569b474a988c5d1704ab858daa62d1ccd88d46c2c1ce0de9be396313b2e6bbba937fc516d968456b3bd2c55696f6b9f6d6746dfd6d4596c4684088e7d99da129921b117d370ef95dd12268abde9b4b17449c916f3c989a9325b2c27493bbba54bf7ded62d619aee95a9451ec6e373809eafa548edb3ac4a4b524b9f55956e298bb3cd8ca83720485459cdc78fb686b3c58a8edc542336594dbda96d0d6763413d4a81c8541657d4221dcd541a68294e36333293d566454852a512dc7b6bb8650b14d066b81b3a3d393622b5598e4a4b63ac4cad1dcd5816a94d81dc7b7368a8503b9ad152f58619dbe26c49d21756b877aa69c8f594bcbbefce81aff78465dc057b7785b90c56e1af67bbae76b26378f9fbf8d6185f1759e7e68b65d82be0ebc1f85d75ce6d649d7b60ece18cb1ee37649cb197658260dcb17733267574eefd267cbc73de3abc31ce213e42c6e0e57867ad62bc668cf32780ccca38f79d711032c63d6319b00b8c75fe4ec0b5a7c23218c77c1a4f0067dc33c65917e1bc43d0461eb18e0ff3193a07f672de35749833c659b53002760d91870692efbe190378eb9bcd33d6973f00f300df7ccbb2bcf8e28d331e02fe720a18679eb3c6d807efe00f8f39e7dc59c028e4bc33e6d13ae28bcf06932f34190298e71778638d6f06923fc4fbe659bf3f0433405ff304f8ee4841d6b8e3ed61126ba79c3f208d7f34ce797f1ec11bcc31f678760d193c3887fdcb1863ec610c8473c681ee18cc5b1bc167c661ac73302866fc7938efc831728c7c82befae215ee396372977ae7173967dcf12682c11958e41973ac72618c3166651f9e08666cf48d5ec632e00f639df1c63df009f9956164317b99638d33ce62f636d65c63ecc21adf60108f1863188e9143ede16fe38c3110c65d26c3e09d31dff89545ac730cac75ce3b6ffcca19d3e41083f8db19630c844fc8a1a7f1fe36c6d8f57826850f875681638d41bc67300802890560c5c000d838e79e3d1597313c620f8c33ce18e39cebdda55b03139e22c010ee1380882c5608604e51050d290f3a200029a42e9179832b840818a842d2276e1022a64c208869fb210311eb1490d4c68e17888861841e290c9e1711333baf54c5019714e40c9719e29614b809ad215950a0f55baece1026c4c8191225d390ca808dc6f3a4a0c2130d22c818f2a38c77f1729f5a18e00ee141dcdf09b857df7befbd37051df75e1acad514f6a693b6a9aca82f096b5ad0e4811eb8555fcb03f50923910e319cdf4d0fbf9f3daef01e7bd13ea249edb2af2420024d5d953d70d3204ff8e9405338c328db34543a641b2c2e808d3b0e1334e578a1059704e41dee177092d0e4831d52b0a203e6402e3276e890378dce59c2a60eaec20c9a7a97016449cc2a88073da4830f4d2f401a469811e6061e314b1f1b22a109470b0e0d6940e9819ae449fb07263a7c5bd54fc02b1f1db058004c81064b3e2d10506591ef70f15edb05b500bb1d5af09b904768d36dd82978af1d9a206268870d002153f22c21632f28c089261147440209207b567806181ae6bd68e9107aaf1e7e2aedf231a44f087920a129f47c9042be1e2c211e21d8631422c3d144938b4da31576a016640f03a1e6a8546db396454c3285d0c8884000010000b3140020301810090583a168384d1529a80f14800a98a04e62461888d224c97114424612600c1000000002202023230e089f67623713793497e2bbe53982023967b82d36261b1da63305dde7cd7072c48d67a1397d5568d4d74c70cc5ce9a5d25f2325e5d4a6908dffd9dd6c3df8fd09b9ed28e0dbbcf929787ad5070e1957204ab6783f41a70e507991959e26bb8a162df61deae7f3e00eccb943a36784177553a66e5eb54e2c9a00731c1cb4d8684e86eb5001c5f86662ed2ddce41addb4804ee3a098086d716b6e2b6f8fa0d69d63f12571ff36e5b13dfdb2236db4fece97fe5de3e7de00cb7c090568237012c2d34b005d766e1f07f806d858012e9799024b4a857535ca4a1deb8441207d1ee7a53e16862fec7a2c13af0a3f3cd8a7d84d45346efff1f14968a2ec73f7be0412acd27d9ca86455e07f5731012e0de3219e241eb53530cca6aa3872fcf476b4e589e1620a9634afd557c0a399464ac79efae1be9b8c4013299615e2f5bd5588e93c605d9b7e398cd8c32730dc608f0a44cf17b34b2aff17922d1b2e0980cac09af8eb807735a9e01d5231da3c9c9d2ade280e2b1ad6c524b50d4620e9afcba56e241f22b7ddf94a3f01e36c98f69cf3b983e108e3ad8e0c7c4cffe9c196e844d69974706b607f83f40acc0d750a69f2d10a6fc9252c7c15a25742c15101fc2c02b4cd7aef2a18ad5917fc4ac83ca33ef502dee79972fe1bf3f4945b4da44f63f9816b406092f5db67ae9d4da30e0d5acb0312a647cfcf2eed910149a383d0a76b2e0da2145f137714a7934ad100b6e3b97e948b7dc1cea6ce2e178b42df0f326f3b5c51bfca512e9079bdd2e863e850b993b651f76a42cf9f51e853a46ea7d3676ef326d349b49fcc2626330724afcd664d9434fcdcaf946bae21f308167561f88859043f0c46d94f4a50eda988fcb8eed1d2050a64934dfaca3d658b9f175f29fdaa42d89abfd80cb3349d37758d3d20a6ceb0878b9c361a2648906b65f9f1ed59f8e0d30e5f78a68a3d7da27274476d013c2c24612b82d9158b925a2fd05e83160984bb8813a6cb3dfbe9a65b01150d8b152aaaea4615de18167837be30aef95e0b6f19781a21cc3920f4e358b72a9bf8c0df07fe00e345bc89fc7f8f624569e5fd2b139dee0c34e72a511923d409639738ffcb62ede80a1bd9be8eed857d5c5441d2b114303334b154f2de15fc2408f22ee1e24ea1e89e33eba61705aedf0dbcb485fad42dd2d9bc055a27d38322bf4511fe3d1ca67344eddc0866328adb65b7efcc9a459f90a32f5fda84f6886c827c55a470d99508436f59d0474422b9e307a6286665be82506567b1f311d475d03da1e3dd504b5057d618f9fd44e15b0ea1aae5267a138b1ae7885b5a37680438c6621ee7eba949897c41a016a811f9f8c14557b4adca69f2f1b30ec6db1b9103e38dcc4cf64b2cd5526133ed57285565e1ad78d746fbcc12ad5577c21f039bf11f21e21505bece1ada2f1470dfdbb8682938064599f1a13c4cfaf6dff3b3cb228bd9b9b58f625d7912de7a4286443b155c5dabb6d898560f13fe335c6963bda8415940b03a1ab924cf55ac8c342a80e000272494e412a63664bcfc03812143751e4c54ccf8ee961baa8cf1ed364d721a480b9deea05cdfca84f59f1c32143df9db10ac288363f2e2f443d9c2305057b8d3281016ecaeedccdda433574ea104046543bf7775b568950d051bdb80d431c3e64277a0b5f9ae0e8066f12003a6881dbb51c58f6903714c9453e3aaa94deb4f8e348ab5e98f06549ace03e4c9051278fb51f5d09c6d494eca12d5817b7d7dfd7af376c7506243418f1f4d77b3481d959a9f6ef4c6acded51d4f816fe6b185c9ed280a0d6527ac1a589ee71c25fd014ff4f0ce5ecdbd83a17d08c90364095a8df7bc6184fe671fdc3c428486f4f86a1f4400c2cf2f9cd52b35357a8fbe758d1bc0416ce4d08baabaf29ec470d4be8c447f73500a61038014247ccb7c005889ab510afccb561144dc550003564e3753ea63f994cdb35b43540933563444bf436d1b13b7e7db599a60af4b9909cc6af76d819fefa31c3f939b58777b27d10d89d8ae6d9bee458da733dc1d8f52179a33fff9e67152e9b7c175d906bafde3887cc2bd3fcd5df140f0d598ac4896cef31d53cb4f59e6eb719b2df121dd5fea8ffe2d74f00b750c5badb6097e0f4bae37fe44e33771637a44c573580ee20058dbffd3fe30f810b34f0c591e71ede887f25d3712fd8f814b974df515857fdc2ed11e9799740b647d99c0fc2257607d00279104679c5d2940d74a7143740a7cf0013e27bc7c8848de6f9d30f359157ea4e553646fbbc9d96c5d3fd375d9907644b686b19b3dcffae4a59f930ec014dbca0f087e57d64fa615cc6ec1a34bb3b9c74a56f9be050c4e517762206496a7bddbe8ac1be9fc65552698a837f624506bfd33f35178fc0093b72ff0b87c24bfc5e7d077af4ea258acd31d525cd929b540af8de1f2bf8ad676e40db13f4a245de320ea43528afe59e77f0f1ba55e2ebb1165a51f6ef9872ace60fbcdf62ed02fa1efaff5c19f50eabd41e9afebdadc773086bd2f45fdf7c83ebbbcca792b79965fd3b17370dc3d9137996fa67e2148edf53981ebb1ea8caa27e69b7e62c2fa2bbaa5eb6c8a319fca6fd5a732788289c9b095e13f7ec7fcbdf48f1e380a9afcf2c49dd8ba51ae004e2c17b2bcc1376ae85d67aa755b7475d309f35832a6dfabacc5943ae4fab8714147f62aa608f4571ae3e600c7cf7d5f1bde63457cfcae04964b8717022766485b285c38c47fcc73ac5138b645e3f6cb1ce5a61a8ddf5b31b2f40f000d391a30bb0f523e45ec3a63a3434ed1b3759dd13743340bbdfc901d30a23f9473b43c0bc637c786ed01ab94d237e2be7d2dff39e39dc8987dae28788bd936003882041ee80e346f1a14ceebcc7185d51109ec9f5768792ecb87c3797942e0b0e9e7cbff891e325dfcf7061e61567342b4132439ccd8797e71c09dbdd1f3fbfd97f63975ee7ccc77eb993cc7de3101b37b329f0ff8fedf592fbfbe97618b3f38fda1317f650f3c18926f8a119e580d284e2027a2a32d7bc4be226e8b30df087cdf00ffa31d8cc35a8ffa9d03c5edbf9f90fb0f3a5f8cb7f465a4551f3e9c6e58086f7c4fd4f223e537d3dc75c510dca8732cfbd8eadd566bc2c4f98da58c984722fd9fe5ccb30a75010ed7c3c0fb12778030098c8c1c7bceec1f27bcc6fa124cee6b006917ad546464352cc3f23fbc1b8715b8640cb4f31adcfba1f6f55b96c35b851c4690d236e637c7ea35e26cbf63da7da5c4f8aec2e6fb2a5f0005667b0e90800462e2617c4a68bae2b08eefb94452795a24dcf779b863f7994b06bbbd931c85311e04c4190664413fb0b63ac01e4b4f3d395071d057ffac75f8d6044086477f760cc5f59f6e233d247cd4d1497316c71cf52b6de16f2857d6aa91999d4323c490eadd734a8bf7c089357ef5d905ff4bc9ab9004de340ca40f2787b1b7f4e61d73d861e033788c6197c2fad2419ddac0fce72bd4e4562a88010aed5c7a681f772159207d94910972e7fdbd7fcf09eafea49e0f25947eee94074488ad2a19703f58b4e5eff9eeb249130195cf7b84223ffebd207253bfa01ea975df8ac9579a7e98d939c1a274f7c816ccf56474eccf063a24c3e678ba80b8e47a42c6ea6033601de0963651668dd7e03a9c66634f97c165ff4b60e1ba32b875d9577a0328a515b179df36dae947ffa6c5e86ae54a9ba6d3cc86d0a46c44164a71df3a7b4fcf31832e5e5677a3a9bbd6d2128955635559ac92ef0432de07909d84152c5a334fa298a0a1fac95e29d66d80ca185dbe3a39336dceade3f0822f9765be4b05f8e7533af613fb99f99c486d6c577c417d6952c44ca8de6976d110ca72564ca71aeccc1e09037781edb3b32abb1044e7e399796f37ec5f8520b2da364b81bec6f42dd426824afa0b382156d91a7720e1b94d96aa7b19fc9c1604f7a6b84df7504483900227ef7d39f4b7fd93ab1f7e6c28cb719dcc0d1192e3ac662bcb5a8babd0f8e9373dd7fbe702f72355c6e22947c4d9873a235d76f08c593ee9571eecd1b693f7cffe00b9359151bb0100a73608d3451e798f81b0db652bfa866b8c2c00596971c1d12fd511cdab99ee50f3c8ba0f471d11e9aa3ab8fd430cf68e83fc6754cc748240227a55f657b359f91b4f759ebe05334e23d26148f42158bdefe3e5673fbbc71550b011c8c519cb611fc2799b4033bea2e65491bfa8a04191e9905adbc8eaa8ee70b3f1d310196627767bc942d05af95b35551c510a489cfcc3fa8a1360cc5da1107136dbf1013c7dfbf24c91d0763f92e05c21aa2101d4a9d8f141d0e9db2d1e0e4c88c6cad6a2c30b4ea00504341b89c5174dbebfa49b53a56913e5a90557fcdda4180cc8469c4c461198799e2c76ef00b4b7c8c3f4982644f92ffd18b97ab3db30e7cc2b3723602bf3b6b7b162170132c5e64011432725dbe9332f24ffad91c3bde7d874bfe00a752defcbe47d620c0c54dd2cd5407094ddc74a302923b57aa5112c084d1c750c45dfb3472f08cb1af00e8a23c70db48abfc037a25499fb482ee7ec1428e652628df4281d8ef171f248ea68b63a6334aae62ca1f7d97aa6350b65e98b8f84c517bfb042e96a235f3c5fab344821ca654eef1f368d6d66fded23ea8f4bc344911bf883fab6123b78a567b4dc6ccc79646c8e58e0b0b5130bb79632605869e9261726a9c860f99016d9d96fc680281676b9e3e2000892fb05882d91fd1526e2b41cee437be61929712a268459ee04bcba6e5f8906dcb92aeebb3c3799475dd81642305db095074c70dd3873007df8c27f28cf069216897111584c90522680d1fd006a484a920de2bd4ef97b4ea2e4f1c2d58cbcef1c5890318eccdeb2e501b544365fa31b3b79d0f7fa6c6f86648f3a31b6ec39a5dafb77f4bd49440496aa5a532384919feef8fe7213aa7e0aa20f65ad9aee3005cdb07e9ab268cf82b5b1ef07a0a412696fd69e6bbd313be5abb1dab9e2c05f8f001c43afb6b40146753ffbb1bf0d897d43214610e281a70773abf7c82e7dfb04e28891f1148734d68a727c712f23bb20d4467d8204d727343fc0bb1ad905baa862ced9cc859cdfa90f5bf867ea3c179e073829d274af32a924a694ad81db3d4a6d91bce6731a0ec21eabace1cf29da2cbce612b4d7bc65ed73ac17409a52be14c841770395928678496688a96a436cc885db3eaaefded83a2fe60730bdcf298240c87972ef8589128a66c36bae2db6220039372cb72ae4ba033a62745aa57cfa1093c4cacb244748fae23bfd16538c3583999d9b7dbbade3312a29d50709f5bb4c649c3493a63ae46a61fba9ad6e15cd6d42ea84fc034a16a166742a2f46b949ea0474601ae7fd1f828881680760060868e2e74f4bf50816e855091a1e2781fd3ff2dca576c33a0488c22698ac505f26e9044600b39123640cf6981315c442488cdb76adab1fa83961cffcb31bbd56b63ecfd2384d87dc2ed52fe602d1f96916c6ee2bb7ac4d589eec5f39ccec9596c31b99bc4709982887397cf23b5459721fc088db5b0a52363605984afbf681eca7de5d6673ef0e00b320bfcf422f2a79d84271bfe5e20e1f46518d90e39b872f0adc2377e24dd1648600368cd37c19d280e6925d9bf151b0160043d79214dfd2272c160dfd653028cfa6c9c54abf8e5aa5c6d2bbd1b6ee03c0cf3a12a3aa871c43a4dd291b83c8ead8de9045af787efcb58c16d7b6f89e6d468bfe8537655174a55540e589c5c00d2ca6b21134dce02687d3625b118d1e7680156eb33d19b1c756f147d050b54acbbf1a8996e3c3b8838c16e49aad2ac00d39dec46e9d8778fb4460d5832fc83b0fad8680330039d529fd6a7039d6d0b082b9b98ad55ae095de3b020677f2b9190e05b87920a9c94eaa5701c6dc2d3c00f23f73607d851164a39759efec9832516af27d30bb11a8deb0cef654ab0d9b9fb8434f8a20e69598d5a30aa0a41b2fc5abc68830673a498931c1fb2ed638a110e05b5e08218409dc71546c9129be81ada190f10dac09a75bff27657109209ad395add87501977d384b26322403efc9b7b472ba28ac8889a7123fdd670478007fda1b799eeb846f50a7bb07d953d33e9227a2fb411165c5beb98f0946b4b7f57c4f3eb23ae443c44e74eaaddc71ef7250b3e9319af58831491c164444b06b5aa0d5cc660a128d7caf66f68cf8f0f90de4c978c9769bf912df6a67d5ef61d806faa8109978af05edf62a6bac948f6293bcccce0ebdc6cd77a378334d15950765d5f8abf94529c16f72583b2f4bf4dc9535ecaa325e66c276a5f3a0d67e36d07eeac2b8b828ce20e8bc5d48cca36e1b0a96f69979881bdf166f9ff7ea6ea7583439a25d2ed368fa87336aec13f105afad55e49b94d0f5c66809edd92f5a6c97271008bdaff2a2c167711a8d336624f0ac24b49fd9b62f5a67cdae07849601dfcaee4d2f92183756f466e7cc3315ebd4fd43b7268a287a17c3f9e05e1f08a66b71b471b4880e24572a614337f6d72a991b6a27973f5c93a8407bf5f7e8d98329ccef83d31bdbefa3dcb0274ef713d9b4a8c4acd3cc0efb10b13a1b973d9b06b8208da3058b6bcee1ed9c9a301851ed89549fa9be6fd5369ef9ae5d0ad7dde4a0e52d858729ce27654b4a8e60897d1e2a36b819ad686359e87191f396fec83e6d484a26e293b5440422c92501c9b81102eb597455489739859288ac44b09f6b3f2f0d6d9b0fcc5a50eaf8d5945c9f44f8ba2dd5d1fd0d50c1c44c42a8b01482d9e2bec8d216b3a94a3c4a7dfa6b85c812257c6c249795c4e0ef4edd92e4579bdbac217bcd2c20791295c83e04de561cfbc0b9c6a6e637b0f66a9b11e5b684b3d19acda4998ae2603a93aeca1a1af599743a09f56fa472ccda8bfe663ef37fa27a8e38a8b89cea9b95a8c921b1533fd92cb2922c876f31eb4f53b51a3f3445e0b83111e804c477943fac87466450b4b2fa10b1ec6ca19f8f341cde15419bcc7c2372bd45ccbbd113a1c2de53af8da8293dd59bc8c40cbb73717fa287fc703675751c6ebe5e63e2c254a58259d49db489c678a5a00d60d4c0323e14067b0197f79972af604a0784407de0326e13a390b785b7e7d6cf38f8e2248613c4f099c46aecb6976f1376d0d75c5621a0866ac1f7ae0f0d93904dae64a120203434515c45b9b097f26e220a98cd056dff90c612a196d83dc8ebcd915c555a3d479fa9e3e1583891e6983b0b8b12bc42dc3df7e6c99db5cc13571e9d601252e960af11799f35b54c44995043408a55e894e5d926b6d0f46a5a60d03b7a94f91509e20d37575ca0a0e9f34e7e9c9caea5b93d493ed3c44c97b9d8fef67df1acc8e0a01c8baf1c48745aed1a22868d43d68385c5af250c39a9cbe0e903c60df2764205691da0019fff90cf04fc210bbe20371fcb5b93f1dbc6b4b59802192a32871ca766d904fa57aec1506e41495b4b9108c8f181d414d5cffd53066062ba32b56e6bd5913e20effe0a135d59d2f95f10d6defbc38fbf1ebe89ee6d0a4954f2a40d1761dc2f7b9dab75335427eb98cbf065d17130a32b5f2e05fbdf51a40075c98b19898970fd5087e4689ff1c000327d14a8d503ff6fdf08d70f6b71f7f28b1da49d611b45815d21e608bfb3fc23e28d5676ee36ef016637636077a17f243e6555d5be70eed64b116c9c9842b840217a4a13e9d31c93a6ad66cc7f524ce93ee0bb6d458e0c31ce8462fad25b3816f2e32df3c5b60c7c2fadeb13c061c170e90e5526a4e62d2729961074b905c4738b35eee92bd54381dd52ab3f152a49f81c02d83eda7a85ec9f0597735522dab9836c6b03eeb9c058f0fa3123718b7a57948429b00bad4caebd9d4c9a808e5f0ef69e35f6f73752986d75ca86920f687a71f28e943b7242f7deafdf269582ef9edacc2af96a4a980914a20653089962c95d4cbdad20263819601c27cef7f2f11b0187889640bd24a5a5e142c93d6f83b56ad39ae245444741f12550a692cc3c15f1ca29dfa87c92abfd9270ebc39849b652a0cfe6d21450406f231f93bd4ca3c280714525e567b0ec8ef94d2fc6e146165748ac93b7c670d4e4696ebf12f88dd5033034a45fead4fa90a809cf706aeb832deb13ea75e0e66e5f00cd68ffcd8615dc65f368dfa7cf6d033601facbe05998a0a0079c65427f8ed5310c614cb5cca792c2de153de21e42ee0a6f0d88865d703dcb9e1679b739288ae8cfd9db91a4e64d5d6af8426fb2d1651c01496821e8ee45008a30f8285c77ce46bc1b77679802471fc4eb08c5a04e09892b453ace9e313a60346ad9bd9d11f64ac4fc5911be7dd824ba15156074106f39721fc218b6aca5430168b96ef586b85dde09ffb8fc42c4d2ccac6358c5b74a03f62beb894bdf1a7413d836069b1ba7a3b089e140d2067a508a6059ed9123e9959f793f8a0ff5d3131348533897e1856930049c2de0f77adb1ef883aa94b16b20b83ca7407969a56a45e0c09cd84c18d083831f29b097b324d761fe0efb97390e56fe16919cb9d2403c77db0bfd288ebe980ab5ca87c0612138aa6b72d1b9f0b52228df4e7f13ffed56dc8b09a3956550405c4e93ab9967e76c10fd4a155fec028c678e7379597d793eddcdd4061e8cd9adb2e2281c304ca39b0ab9377f00756ef9f03bff354e3d2ef82b7481a749cdac486bad5f0e77a48c84a7b54fbe5102ca62b311667195a10216009f1587499c4b57e5f15b8d061d9e7aa8387b5b2ef87fb03184247231b03f946f1a0cfdf7020b52762ca540f63790cf1727b9d1bf33a2c4d78e2c6e550d6c250bd81c96a1c9c634d66836164cba4c1d6173608fb02a0a2540a65c77bf7969a850505bc8c5abf32be531e28b73d083393e2b3ab0ae7d660a202dfb84f034bd741830fc07a9deffae2de51a78b2990cfc6a63e9dbfc9d5c2799592d06e3fa8cb440c21ba7c6f7e852b47e4b6fa70734d2b694a50ef07e71d5b0b48b9a8e91cdc561f9268b6651cb8bd650363072e3c5e2448ada57d0a44f1702a94fcb2217477404512009f88e18de86d0471d92a264b9dab16bd4e55e83ce309d68c3f6054fc87927e44d71daadcf466728c3a43e964570028ac655c894c49083af87b0fd82ce2e2bd384627cc2977d4908799047f3b5a424308086db1a635edaa695554644645740f71b4f6cc492d1ea7f91793311d4de3ae32dea9d58b8f426c42ba25ebab5c20a097fa4fed09a548838c471f3a33ecf52790f6506ce11d7249c0ce0829ada4fe50abec9118d13e3c38d650456201f01997f788ab21782b9f4455b068157300039a31f05ab1ab44f0133a1686fbdeb0d051a22aa609baa06bc4ab0b18cc0a50fa3e2e7621d999cc87fb0feed2dad488f033aefc281e243faf6805d505f24c4d809830f2891041d49ad2c9859688ece82358a08b3ef534de6b3c42409d3774aaec4ca59d72cff007fc0a8960fd4202f5da8157905cda899608cd75cbeb2e19dd523509502f6a6df388b60b6db0ca90bb83c8ad4cdf75fed1556d9645f143689d16ccf186955a505e853f811e27f715bdf2019f2063fe0a2d4ccd98ef8e2626f27c70b4d661ff822721a545716807e5ca6fb333b699880b58a7373111d3116b7c3d80b349b85593129946bcbe7452766847ee56b6291eaec397895ad4f0444616bfa6e117cc83a615c420b4ecb3864240ce55e12d9c0bb6a59976a18a6f6f7140a26bcd9b2941b9e4555897bd2122b78705e9c45cd076cb29053e1aca9d477064f9dac7a1e28bbff3b620acea153f9f4bb976ed980978d121c0e7f0d710db18eb44e932efd262c5e5fc5fa668767adc8650a135e144b67aca90e4a04c64e2658cf424463d1631020c29682c87b59efdddb370f17fa83b121caabf8f0c597f94521878ec4623429c9a61fce1cbaacddd438220a611b893045885671191b5cccf2b677ad81ff618c1e5449d50d9cd8af9510aa4c7340660f38abf8a02704fc7560561a8a0fd76627003fd2b235dbde039f97f754ffb0134011b7272ec865fc6df38986a4db5b692e2e2ef0b1e70611860011e038e15978ec5e241dbe22dce3e93ee336b3ce1f4ec1a590244045c3e5381badd604908f30849168a8cf4008abce53488020c4141c85c46c6ac5b9c91bcebcf50ae215db5ef9f80de8d5aa04bd51fc3dd35f440f512afd2b50fa5131ef5e1edaa7a76f3b764395ef47e0c4330b7b4e899a9b381ca0110acdb0125ae8cde968b0e176e353877e0f142e8779bbdcab087f3e6eb27d9458c2f6d8d786fba402654761c2586c7e481c01d121a204c02e3cee234e416ccf8802100d69e2d820f86d46569a1c665ee238afb91ddb6a20cbb7b14ae9e3ec5c484e0aba9ecd86b7ec57ba4d09931f9090c895f14fdd3b2e086c003a028a68458a6d45740f7f698adbc04b15c91b319849aa99edef9f50a708b33814a9357b75989d73d878f5c9748f077b265cc9f01a1b2b21345b80d371ad6092e0b2e49d86ddc4a1e18c97e0e1c4f03a77b30caf4d69db0f4b1df8303cb91fc7154a790ce9b736e662b5219fc629a48daaa19bd8e90f5ab24dab83bf34879956489a8fbf0c2b363a1ed067a568568a7be63f4807cd3a0444085d3dd013fcaa009df2f999ac65d78932e6c3282458821bdb8b22f76311a558bcaf1a381d3eb2e3f32df8fd567c815e3738cffd39d00a3db30d204e2c6a44c1a3ac82554eaf00e8f76c90738fc180d43b9fc67d0d81cf9030227dc1aa68e1b31f03529d84223a6e2162a8d1230927227d1293cfe37bafaec6dabd8976a373a10fc5d6cf2f13499c7c1b84c0d062183e794efc89915ee5e4094139e6e6eed89e4d5a0e0f02238ac6d46bb82200e07058214896228ce347f80fbd28fd6769e978f0fcc5bff1e6de217044c71f3ee2c5a9e7b8f1b3c86df9ff7db776ce1e084a0de0a2e1cc85a2e3a4e871a9b402949929ad3252480dea5f7356f23d1e69d62376f505bf72ad0b9f128eeca04b4ff299c66a9805af2bf459e590f949ecf30c607eb0b56f5f8355b0ed2dd78a2b70b2eb645d386d912494593219fe041f0ab44164ef4b817d829ca3c2bd3c1e9d98626b6c7bbae80171a059a0cc5d27a5caa03ec92e4bdbb4016da37de6e0fe9412bb5c65a79cc4b9184719b398884f12236ffe684e0fb5529b4b28f1b3548bccbcd972512e1cbc994779280094b45630e99eeb16ebf6b41c252a6835e885a7085fae636c1e561b0c2df3a24f78faf72c41a9a704c818682aefc44bb32f8d76e09f4cc9d5ee8aaffdf038b229c448cbee708385c7eaf06f32b8946742c769ae101132859571dcb36124022432a7842d6408f1ce53171dc581a86489f1da53b7c91e85d8e9b1ef82ab73f7c39f43a2330ed8634a3b8a6c51045858bf44d42098c0284cd6079c0490ed0bdb5cb234a0b650e46ce65b3c001310c10b7d47128743658872aaa1d1b22224592d4f955019b4445d990dd7416932a294a1145db1b6d449955eec199285bd4fd390b8d176b74e70370b75d5019e2671c1e6ffcd4d76243f3ea77a30d274cb9dca8cbdc7cbd05b09830c2c2b1b4952f631031b96c923bf2703b9499cd0fdc53672ba4074b3ea05927175d8b32d3531af104a5c710be576bc45ba8e6b3fdee0af0ca4904a7983dc867ff44c7036e275b2a615fd6e6ba39de373099d39a6cc9dc11d3797e8668e8c19ecde16bc412ff8b587e31dcbb8c052fa9461e64b352161cc6a0a71b7293be6588f30f6ab5f897270e16b30a6e8c9e592b34fff5de04fdd189de205b79adf8bfa0de063402c1aca10c2a472a9b78c59cdc85b7c1cc1ac88184fcf7b54c3eeba8ad0fa59478d686923c8b90d9a9cdfa31abf3e3cd89e4a552a68a9bb01d5ce7a34e113fa9a2371415d6b0b7201ddc08ecb7f982f8eb401e6b161d1891ab0858c1c81e56304d0520a14749e9453578fd586ca6eb9d75b6f6809f632bd51674fe164c07e1864b3ab4ce0ab8af15e4901b7ae852594087ea80d47892a2edb69f0b6be67adadc6ba444b604ad2bc346b8cdfa08ba7dfb0040923d6378b36b4849b4a8e0fd6bdc619849c16b4d44c9aec4d48766229870f6deeead2a9cc20359df2bde5d78ca7e5d981febbf118e85cc2946294dee9b59110256dd6dc204a16c8effb850798a78328a514884e153f4253b322c319e791754a567fd0db297b0939808d0c66c1b23565a4611657590b31d9e44a65aac0837cec4d13393eb9961e8327dbe821d5a9a631321303cb71a4d1e3fba03c2294a0ca5d2e2dcc9675605a2ac9057651aa29500002af747943e13b91a05ae4ba886e32945e894e4b669d4b0be80d366c3b7a6c1a8515fb693fcf35ac8af1da31ac626062a71b4e4761f1abb1e1546fb0396a8ee298289ca16006dd7eb9e719c285284cf6447ca5936881ad8c4038a9b7b8162d7d1083d85265ed4b0bb907e9c9898f0f1200366407ab2833f4b0e7f1ad993119c3b11134b5549f0aa4437315c3e8f806c1334e8aec4fca2238de660d07582442f67f8f022f9c87edf94b66feffef9e140934c6c907471e73c2542e2d643bf0ac06e3e714884640dc2ab278a111ff26502d56026a32989bbbb463db82878d6e0be58a8a83f1144f86c00c1850db820b7f654c79e82417b3552884153d733e8811f9c86222c03cc6b9e3b8e08a950ee76595add7ecc83941b9b91e07b4e4d57e0c333bbec30cd1779878ccf4921fbfdd63adb25d0c516016b561f87e934bd63708c2e7d09c7bf01157a24f6d335d458e2ae61f250f62e4ae3917ea17606b67b470571393cd0364e875b8f04aaef5c0e63bdc7dae6195bc26dbbf9e5762c6fd684b572f4deed37b208eb856b266e66aa4a37dd6d4ef875fe14e2291776be110241778b41619a6b821b137ec3897bc5e5288c0836ebf6ff8370c394598d3e4745881780a475b9dbf6604b98cd9851dfde27ccb3c9cfc6e6b758f0f65e56ac345d5152d8245d80c798489bca97d0df00674e3375eef38871b1b61dfdbd2feeab3b863c7fb894a8b8a4290461a1e44f35337c6ef47680a7b48cb5cc925c6a7d25da3a17fbef69caa35b7b8e1f7b1a2e6dab1a32422ab401c9886f5f6db7b5bfe87aeb9c0a5da46a5599cf1e3daed0a047ce32babe31c84b1745c65e1f36689e31b4276b8fcbe6ded5d3d468d04e33a3b4dc3db9e19af1362f6ebe64251e16dff8d10d7dd4233f6ba6020bbfa2e44d267bf929162ed3ba75f4fc55bca820dfba054abca50c4b3f7a7118d24cf9b7b5a5559a153027cd4b0cfddf80c4b624055c7193d5c0035fae1311d458d181131f088d73fd5d9a096d91e08045914256fe0e015682ebed0cdc788edc01eda3498c03994db3f86b29ed51a6a854159209c52b413644e588a646d9976702dad852f65cd528ab97dafb0373e23efa5476f8b43f48330125adfbbeb57e200f0ad92d60b7fc0679d2484792cf3000422bb60ddc191ab3723f5efc1538a78f8594317faa5ff01332466f2f240df05c31f48f93928a42343f9c9d05b07b671e94a0e627a6989393f0f8538eb4210647480e53ab9dd30e9f4256feda5e8f1265cb5ce1fb87ed589f8f9a33bb48dc415de1efed63f5f6d9764c4294b7fc4ede543ca365cbec4216c000c1612d1a403d538de3a7d5b5ef50e6465355576b82300c9e5eee2228a0314711884246b31658fa9ccfbd6a97f9f673f4e07f36b6fcdb885fbe90f71fe06bb08e7e1f09b42fb730efad4a90830132b7336f2a811f76259b6bda2b8258e90b19a4b63876c176bb618bdc37228413563feed32d15f62e720ceb15e75cd780b83766e96b4726390b7fde561a6c82da78029dafc383c06b005743cdd5c8f47740b14454386d1b81c30d3f7363f75f81f3d704218e0546764b2a50f01882e91f517830cad89dd332dc90f78bc7ef1473d9778c88b7bfb8be7e14e473da6c489b2fd4562cb11182098bb2eab4f802bda198ab654e05a0c9d521a49274ebaadfa6f972a7bb63fcb0b8482e50e5e2b4f2e0206f0563556f9262db6db07dbb0bab38e53cbf32ad450a2d1b5497378e6266cd3282396504e8e109ad80e8230a4216a58bb08f394904011234ac00dbf2256f7ed4f8ac13a33f598d45527b31a35d4c1505b3db5d66054436d75ebd5c0a4965a75d5a9b31e06756aabb5a69e7aa873751db78b071ea21bba9d57bcfe3d7078a93309b450fbd50d77602cd9ac6349b34846deb26884eaeeda2d03b0080e1ed5be202aa40c27dee90f17abe2ec44e6b482a947a9f5a2ec7de69825c426ff65cd1968602465ee123199f833c07f581ace0647716297106adc4370f2a175f80ecd3541e3fdf2601bfe78805e678b5b389595e0f731d788ea8bcd37b9082d6acfc5822402c862ba82ea3eeeab71301711ca7901084604f23bee5d7d85f04c8989e2c13b56f83526a1d5f292e36d36260308a7bc0e6f60ce3e241830920532452ad4aaac28b4b57d4139113dfeec896bd5c9ff388ea7919ac8306ab1f16cbdd18b70ba66266d41b3b5e9215e151bc289ba58b26d7c314a89dee5b82ea54459f243f441f7c31333e95dccfab9433b9a79b5daf1c69e9ee0f3710686ffc23986245738f496295f13d242e741ae018655f737751d972452e5fff0b138315a67cad699ec1d4ede93ffca677ba94604681bff8c0dd9f619a50bc4c17b21095c2d065b55db596b85fc882418e7d45a6ecb8f62e79f32c0b52a19a7575e43906ea58f75ec09586cd9a0773ae3461d603df909cf68cc0ba00f8c80fc46306aee38c9aa172a9358a39e33908584622bd55d02e6cfa42c1da0ce858151e0459197c58120d035afb31ee261384e4762a509b2d2342751bc8c776b822e282417c1a197a017a990376dbe85b7fe39d54edf6ed4bfefdc88d1af486287a13a17573608df439c4e729d791b094121696e37705f84467ea0b8dddba294a9311789a8313957865474c58da724b54968a7748094e96575ea2aba9267a031882a44aa4e57127a5502e38f40d1fbb12d3632b5a10612c0bb64179b8a9bdd4fa2dcb35e8648cccfa1b571edbb49d211e229217e994ae0c1c1eb032f93bb40964dce7e4e8eac17bce16bde35d82d56771543079d998186f517903e3ff50ee09fbc8988c1964d06140c380f204e601b652cfdb23aac457dbb1821da4da23a943f554e2702f18efb254ed05833e042cf00b72cfcd84afb802d6faf4e7592f58b44f0507836874b8eb36fd390e1f44bb6edfd62c16e2feaa2df05381e5da4f20b16f989233e8545b7ea25f42bcc061bb516d18339d696e9fdb61a6cb8feef4a65abf61c040a19f7231bb687224f0fd4f710847bd6c482e31511f9dae75593fb039becb302107bc25242e4c365b6e03e6ebe766c6ee47cbaa52be56fab996b67a6ce1a26eaa9a38eb97aead65187995a35d6a9510b33b56ad552632d75ccd454b7562d75d4b9ae6b81d35ae50af32ac7ddcb1732d9c4a942e2db9b184e69f306de9f1958c048ccf7f4b797d2c339282b9249d05301c761365d2b1803c42240de45aa106791f609b4f754a497c95bed88804c62ab9dd6b5493d566acc6e1a17b63568001c0df5f9317ec06a13ff8b365d286b13c3492ff05636bde693bb17ae1d6eba50b0492ceb7e3489d44666dc3efd8ad5ab9b25d737d7f8f187e593eba3265285d02a8ee7c53ef1dd6ad31f1d3c3dbd7734f91087b30262aac017bc99e0ccf4fe66692427eeeb1d824a9739046f6932ea29a2eb33948faa8f602b4d1542cf853a9f94e7de090ffeed80e37ffc0b4887bde44c8419c818ca5df07dca2cf05d6cd15393a2371105cc08d41961da82fa0382d225b949265a937e25d639aa85ee31bda734b40601849e6fc924d24482f097740b594ba28be010572bad4254d5c0310d74a16fd3c0055c2087d75bfe9ab0c78babfe7cd2dc64cb5212f2445e05e17c1fdc3e2f1568bc5af6c73f075c423a70c66347c4ec12977e8c0422c93761d57e0bdce3a44fa270b54dae1062b904c2c200bcbd040402ea80ee49d8a855c8fad85ccfa55a85b88e132707028fe620860655c1ca07275fed18f749b89f0b7c7eec19ff83d126729bc246c64cc268257cb01e12a58870d16baea59208ec039e7ba18d574095d73a0e483033dfef4dab90a6b0a60c85aa17c81fabf50bcf7121b7b93746bd014164e78cc061b58f4bd602d0969b82df435d8307217136c737ab1f436454ec13ddfa09875811b854172e411706a3343a91ca506a6ba18bdefc5877ef0a3f6bf0d1f80ead8c053f3b521d2c69242642d955cb2d3dfe604f9538bbfc97c636d3ffd5152b2df9a3ec832841453a46874182d13858d820ad760a569d2450b1f58ecac9575ba3b3b6452ab8092bf47990aec48e09a5aa49651835419b1a620a5172e157605788921036b1cca5020d66bfbf4591aacbd9988af9d4203180ff1a84469e58f37f0a4d2422852841661e6b65a1a19e4abd5c95c05bfadf53fa8aeaf594d67fb2a51e9a73b697ee78fb90a791c5d183da584f45ce0121a6ea201545c7f7070e1e14a187bf1fc561dfec25a64fbcefe10a30a78c89d04f8de0f089871ab0a750a25da5346c2546c489a67d8d57cdea4787ce33cc53e05fb30381a48929dd2372776d3e4a4f1df14ae17800a310605bf446c89b14c5e0f99bc7767d22f42e39f2c1a5938b916bc36e8c10fb44062c05ad452c44ac754ca471917149c5e2e33ea17906cd197a3eff32357a1c0400b2701ed42722801fa26b3bb0c13928eb4bb58cf74b4a0b23025e95bada488f55f0660199e750f35abcc7967e3a4675978e1110fd44cbaefca081be00a1944196138add8daf76afb8de2c4ef7759f46be08430e3af3e9eac7d08ed1ca248c65a9d2f6fdd5ebf4cd21c30ab08d18bbee3aad5cb2898a3df3a2b2ff3a51d4305674f2078605afc2fba60b78d70d9e6d980c10e302292a081782f41651d693dc13e97fe4231016183d9cc1d84d1fea6fdc4801b29075d8295ac89e074ad94b5b7a753005fa4775315c9264a7d0815129fbc1927035e9c4e1fe29370e1faec226f7defe52fdb1d07a276c180e26be09f793c1e4d311a6a28e23c89faf72a1184e87e83b1b371f255d7a20ff913d1d13c078b55d59d0eda540c9fcd545852a6e508315f48e14bc4cc517164efc235cd23ee69fb08df006a6f794fd08c81d628d4f285d986a22a6eca459ebf0a8e6293a58c0fbadbf943efe7b6548621f2db20f0548876899efbea5e29ac807e611ed72e5f8170f80a80ac8cf3d2e9bb5616a887b4cb67663224bc2d532d3986c75a6273a5d0ec65e8345e89fdaee968cc21ca6f04e7d225e180ca4682869363f5a2f82039ed3828df5b09a82e3dd7060c3464179877c69cfce187d82b5b87ac04ac6de361dc64a5f619cbbe92799149ca251a42ad89a86172e26024ccacf948a83976823f65562cc237d6ccc51493e8c83a9f60ecce53be2dd3bdeea1e4a85efdddce0f30484f4c1772fd82a33a8911ac63de7f8a5310b8a0f96fdf84ed21078493beed8b38251bef3ead477053fbef8e1af3d2d46b6d0f0052723183d0d4721b1a5d76288b67a7cd077a29c052c554d788b8ca00cde60da3c31fc97b5a045b04d16ca2e6ee0b34191c7bcca79c2cbd477077ffe768eb6b2fb0e63682eb1cf8130d9a03d86adfb04ed894d57aa0eb207d3fe7404c86e20762a567aeba8ae8b8a9f78d07dd4e9e7e4384e88e230a85a4488038e67833d4c6de207635e10fdd3ea88f988e2cc84266bf94c85153578169366673aa56879361febca13dcadf36db372e0a711567c9c61d99bae0a39e4190cec2617e2e7e14065e9720a4191b212d15b8da02d0ea4d0cb966c0a0cf9fd11d787e44306c8ef6ad0b62a4f9a1f4992294cdf7e75c998699ad6745e1b9a84e0447374634937fa2b890ec80091998958dbcc2eca7583b0ce0c04017171d32189eb66caddd47f98ad4dfb423071ba74d6b77f3b64d7faad54fb2dda5afe80aeee092e38517cb9a326b5023f417b35a3de27873ff5cb1cd0b52c2dd60d493f1ac68f0f0b4384519891369bad00656aca293574fc178a60d1d182dabb7886aa20f96752b53fa4f69a3362c24f0091d864a8956128cf8b641373631b6008ab0cd648e858cbb390742f296d71b2089d462bc201a769f9f8d0531e9c9f21fafad055d317b671cbcb385914b8f975e8069376ccf233f047f631550007795bed80a866a0e3da34e719d056d499557339e981448a84d8a280d080b6355c09d8808c6a42c89096df446d38785e64013866c8c926ecfe6780bf800ce39605721a28132c29739d6fbc5108c221643a624a3f6740508127d0437ac20797393dff5274699d8320fc513846fb53417bd10b0424178998520fca4f7c7d59914f850e107d9d2324d4f0ec7066ba8e43af8ae63b339bbd0d3ccef8c89e9bd59f4cd7b12758c1dc1725f398540e994c8381ea0576813e084d4e7363b70f753dc9c544719d1d7a0916b4f27d248c89aa1ee828344c423f30df879c9569ee79972f6604085caced40aa23f9acc9189cedc2bb66011a30b602efd032525e75d4cbe5e2e3054c1499b3ec5cadad6c12ac846245a39bf112e9a3aa46e677b5e49aab45ef5c691295c98ef74285560ec1a28aa34cfc4ed0f6944beea6211bccc83118cc6be9d047e5d0bcc548e277942abaf4e5ed28c1079bf99cc13d049c544131f5b64a235c189badadfe3cf16f5e3e9d1ab3ea022c0af8f522500aa1057eacfb341d19700916e159360b4e8f9a1a234b0d529a3f2f5f229090cbaa6599ae7cd03c12f8a379d96b342ce46b3de455a0f9fcaf48be7515da41c63b9776c377129b858c2091ba44909a3775efad42fafadbe597a967c8faf161ac7942abd6cf1dc063abd6b99b39cf226f6363326904cf1d173d53ec866ce3c9dc6cfd416b5bf9043e10eaa3910bec3ce1391126bf60438654764946412541f0ca5c9c0ab9b0de6b38d2a494b0e86eefbecad423c56a65b2b2c4432adbdb8aaf0bfacc662d2717ed0df817cea22d01ea8a2ecf013ebf947cc9a5fcbf3af9ee4cd56e55c0bf7232cd13f3d38a1d096c4d2ee95cb078201fb99c51fc3a34c5648a442af7914c0495204f7f84a79196324354ceb20ef8a89c5c14431a51c2b92fb7c5e5d36e5c5904e6bf6349faf8e6de015251b1cbbfa15e804d2d4ccfdc7f3db71ebcbc372fde9f3a7404c8c85e4e452e1492f67de9ab8ad133518b0106dc9ea55b15dce75cb434521600cd4758b978e00c3fa52bed77c8ee558d02baa88f032ad19a03701becb37ba099fd1e5f0db2b025dd4977d24e58f19286a1b984913166e12266d74418b14ace04e45408d13b6603ba246721e3550b1f88996c1674659b67d77a70678e69d754a3a541412dbb43fcfa811f99e4962dfc348f34c6637c5cbc94d2921642d0512da29a68f45b1021b8763eb21c62e2a8de492b0cfb72d8740abfc1a820419235e70f7387a50893e5e82c955f343a9a6776e2c0c9d5279975debce474fbf3b6e7ec333cdb68f78cb2f82855e1ed03d6691aae6a869b84e5b3c47f4cc1d7852874a9c35003fa26e660c24e26a6be5bd88d06fcaf0cbf24bc9d0aaa2771c5956473e197e8a26825573982d28400485cd749ac13e87d6d7c7c150e16c0a51690f71bad11c37cbf4e744b28f143916521e2c2400d85ef6a3cd71a6680ecbdc5efc0144d4918b14cf562424273152134924bc39994b7b1e14a7eec91176233cba523b1854d64a86bcd3e8cd522d132b630a031212400e62b21e69f022b71b91cc50d1bc411c550fc5f6b6c877c246afffcdcb9f8a57f785186b2ef6f8451ff812cf40e1d682e389794e1f08f09aba9d65471c6e9881c42f4295cb030c58257865b5a61eec91f535831d11f53b2898aa3d0e58dea0fb8c1bc91c49c847020ba4e693a866ad28b2ecc66ad42370e37e0e3a2022916c9c948c54a60b9fbbf52956e35be0aabb155d2b4481763cc871dc79195818924fdcd0edfe5927a65968d327d8057d13c8ab3733309361e943a3dd7d21fb061655163886126a9c39a26e69cf231be6d5c713d51b5a56e191e65bcc5d0a8719c470b6b8298a4e4bd540c0d683811b1fd9a2a71b39509ff6ff14e0c89786e699c0011230c72e7aaee2dd550456b5d5db276ab391199c6b6c5eabf2fa5f0a8597290582ffc0cfb2a786dd001aba2bc200f2942f0dfbe7d0b371071f1f1afad2233bdae5c1023ddc5b59e4dc50cfb071b54ccdcdc27f7a2c557bfc67d82a3a128bcc0918fa265007ebaa17a13fdaeb903ed2c5ec23e164084da3a7ee30b7302c71b689c1f08ec622007d1ad486873648340910d8ddd83becd6f17aec1d411675ab60aaaa3b2ace0e216d088a42bc91af4ca92a419ceef6aa1b58e2fd4ef18c7c63b8c7c44bbdb60e02d0e85a58ce3686147fccb71560b69f4f875662eba1f992e753298c54f3267695e17e748c8e085dc6d4da6efe5b96e79251e22718af46b86c62533acfbdb7c7f1e084736f1a4e1e096aec034e741b612a51c971cbf8b251834daae753bd6d6e6c4f6015ec00b1ce4cdf6d7fb38160fcd53dfbcf8dd23834f4f6e95b5f84d4f02c9aa1ac6763bde1ffee2044d48182f163202f52de1070bc1154ab882b440dd2d8f4bd0e2eeecd029b185e0b574626563ae65a48b79814b9b1e3a80ba54ec70f7964dbe6a68f5b675735d622caace0dbb5e996b43478ddd36924f20516dc79f1b456b7a0e90e7ca906cae562fc551db637b8a16cfa7826d1548e2148281eaa3f2b97f1d423e1c585dfc8b143f1f9f9d6c2b3a60d37c986f42149946485114c2684435bdaaf1daa416a5002229c4b84f9a0aba95d44d0bbdd9dfd919ddf5093247a38b6c340d6ae5cb03080cf80c003a3e8a88ecb8c5c3262868f51043e4961098aba130298c5d38bf6aea977177fe3bc4879f171bb0a0205163577020a2f177921e912f5bb705227ca7796d2013695489514024e8e3a17385944e5552dad58cf41a87430f9d3e4bab595272610afaa9e53ecc8f52c13a64c77e66d29def0c15493bf269b7443554f6834479573e63df576ab22e1da7b50e14142151e05d083e357bdf808355d0fd2cca1fb69ab3b33ae34272f337c430134e305a0172e755dd08c0068ee629cb65ec1531312ce8ae7e66f6a8b0bd4ebd86f4c65ac8e2638eedb1d68a16835b572c77940a2378db4c13f667f079cc513c285ef4205d129e6f252afc705831a4851f2739265894a732cf7f4099c91a1e8bcdbe05a69a3c47d6251e6da7857ab71c625091f108f13f2cbdea78395358773084700c0b609267ef38d655cbb9c461c85b6ca4c4091b71b60ce8681493c0c059908ab49002c68cc138d4701c7eb1ee812e45b11499653cb08b85b5eb1fe26f0575114eb18a26c4feb8068053a184af94bee83adcc1e352f14f8d246435dc86e8448f6ec20205a7bfb1a9930f7fee86c8dddf09bb0ed911411cdb9cf6d6999dd4a2bf34420f60125315203cc8d886dc5bf591e544c7a40b59fe4e7f92dcf98cd35925a2c1599d8b1eb891f64f5736868d9cd9996ca4de46959231a5240c1c502bce94ef9983bd7f33efc2305e129e9a40dcbafc0b44f210abecf9f224688df093c2777a80b6c2e8d442affcb85f6df018648ba7e68d1ba662104d10895b9a5257d28f80598e2e6e2ad90f06915fa1937f8d77954655b0b7a213a259f061ee6a0c1b890d76d17c1df4a21129f435e83e08ec0c7d923f0d4babb6da391161f41c689882ae8abda020442e98cbaa64767afdec92c6b0d133be8729c4cb1285604d1dd65d25dc20e3ae0b331e00e11f0036cbd776c19aebe3db783d8abb06e3967fda441e5dd59e02557279b9f519ae30310d5161215c507392bb599e68b847ed19b67f62918b49f7b271d12c45cdb0302e80064709c49684e412756f86cdafeb48cc206fd8930720682d96671fd76e14f202294c5685a26a5832db7c93ee709407a089027541d5f545c2fe594cd4901ec66fc1f5597a2373c971d15637facc7d21b249c687be922ea5589ce2312581d41330243ea651e3314b1c269375858dce37de6db3c256a05371ba6044d12179f726d183973a1177deb1379d1a1131b53755d37bdf95c801d2c8e260807eddaae79832ac043335ad2025b0303a5fb3ae0a7fc99d1f00f2e7292dbb7d81f18c754919edf9d93a92f11f80825183d06186dc423729c2a8c9d029bfa8c0b2c3d4579ecc0eac43f207a34338aed0a60dc933aaabb172777f046ca7ac306be940106166f083c96b76f5e3b6711098f7378f1ba19217f90d90fba10031b6a9eb69ab12b98fc2a711dd0985328dbc5a9b813c688f128a365e8d661a7c7e8bd76503f21a606cb3355ccea6dd31ee78f7f763564968c50e4f52b4c094a58dceb5e66878e75e4fefac98fcabe191b4dadef6b55d966045b4bd90219ba83bf5d0a21a555a02ccb0ec77221152da1b8d72f5946ad74f8188cb49733910ad2692c24a67d1535d9926c18ce2c1b0ac03655f908123a64c309b9a8cd1539442772da3eb5ec54c6818f4b82a2028c19ffa5177aeb7bd9825369ba985d80b0e5674d062d32c25e7ea795cd298924d92c69bba40a4ef995df1541f1f9f33471e696fb14c82bf890accecb59c9962dfc83874e37b360cbf0f63aaa9db693bb3d02132c7180a45964b7f2600e55e649257c0d1e6ccc58d647840b6cd9ac8728faee957e756c35ab17b1caedef86fc0a096bf662d1d6317c0986fbbd120eeadff740a04a442ec795c29c4e3af9a713d4fe21d69b017eb9efc6cfec15b07f5b213163a5968087205fd3bd78d4fda38441aca9cf0d404ca8118f1fd5836a8185f2e1d2290c3635729093748b9f8678a27211c187c6f07a738840b6b781a97d35f98e08eb6c639c90d4b6cb614b1675e8cc07522a4235f26eefca5a26ad58f1c9b3320fa9fde3d738912244160f6eaab2735e8d80cbe5e831f4202eac4dca05a78327e0c2e9476d22e79525b9f4323f2455ff5c7a9fd44e917257397a168e0a1f125a1bf954daab5b2da8b5eeb2ddd1026f073d57874942766df53c565d4869f3bfec9a244d86346289d84f85cf57f28e46697fd39c765a36d197055b8100ba965aaaa2746dc1863feddaac34596e5aa150bcc66f3e1668daf689e21d9c5650f17917a07631fda4de5358966ed90168c4499e8ae8289b52407c4a4b0188381b9ac49b94d8ca0892689e6bc701cc7001de8d70d56c6d083bd81c681e1d4644072790abf79e39e14196bda893569f22bd5fdbac9fdfa5d0b7b9dbce91f5bac4f69d78466dc9261c94e427d1991864a0b5a5105bab1087ec50356c3dcc54a5af6d97e41f159bd468219f9e813e6c407f5ddc543db6792f2c8391d8dcffc6f2324621273f759d8b5e80420eb18f8380b497fd78f71e0fc8b93162ffc892d8ab404818dd2b20f1188a998c3e2eff2d8afd500313de03d90a08fa3fc4ff26f5c6fd1e5c4165ff32e56ba0ec2ac4740ea78ee69194303d2948543ce5182ed442ce9c7c5bf39c90313c326f719c117c2a9f394c2ac0aa20b08643321f599489b99f3ec7b9c862bcf2c99ab569b47fd4e2b2e730cdefd83d66d86a866407da707aa40e6bcd6d8862c59d9caf5053769cd6eb7ffa27d8c07dcb916ba871ea877f9d615d987dba7ba5bd17e7fbe7062b08a430872d2d378c8c18228aec1ef4f6708e0538a82dd2a2cbe6bc90a500412e2d6dedb8a825a26834355c6dd6e72ce7602b54412f8c16d3a2ad197bde9790300039e7084afc78653733b5c838b844ea2193fb79b1ebbcef9b5c9d879d3fd9b245385c4a5c20c15602883c04adcb06f911b2478b19e0dd3089190d61131dafdc1707cb00d49740d427a62dc00f9ef9bd6ef37af3e6077be80e2e8f2ba40e087a9d7cc6c4eacbac22374d58c9e7c081944b65f9813f6d30a4bc90305e676c0b8347a2d2f3ae1557ad13afac18c5c00572cce9e070cabeb5907291a37882209f701337f2992006991550bdc730e65641893bb29d606136cf431727a8f13abc84fed9c0d77331fb203fdb12cb437290c24c830cc28116662aeec98910d53e23f6213dc813a4470d96296a56a2a94e5ee5cdb916d133307375ff1a3ea28e3b243bd518e252b5fbbc76ed65cbeaade086ccfc2902f298e7d77ef6dcbd50c2cd20558481b16ff879e0e37fd896f7df6d0e132b433478635db323f166ac224e432a6846a785daa59cd8f5c6b42533c71338267ae1a107a6449e7e28984e132de773b2d569da5fd5b1158e331b34c8a5579d18c8bed0d664ec5108a002ff8fcba71301663fca6d81b98c4d015e3ba17c9cd80b54e6cfccb51286c581a4d86ad9c3651b532a5a3abd2e20a7a4553f0cc0a21ea866fa76363bc02e630dc06be8a8ca3e5886445f7933d2769790bac88db6a10983ce096314e48fb0204cde030adabcabccc9961637c93942c1aa62d4f4c1d27a6707e2f11dd88481aeaac29d055ed8b57ae9abba08bbc269b703a0b79910b085ae6bf6283d079bd013e2b283b4207d8b5bffb9118c2c93ff6c350b6e9e111b49cb7350cb07bd2fef4ad2c449c04a5734c73d3c370368c2b4ae0e89680eded5191877670333063260a040d2f2af3444b8082e2131343eba108f590164c19b7de9c11d4992419e6afb785851f49fa424f23a8ca98285b27bef961e2a8ccace4be7dc00ef279ce8ac8db28db8e889b9ef3d67131754f437b829b8068dda1be47efbf48ae0d3a2886fbd70af764a70d0f2923a0f1ae213b84ad29bc912f8a4639bb854e525e43550d3f85e7a112d547ed5339821d441f3573b1e56ce8777f27a37d0865cea01466cdcc582302dfcc280ec306b5d69970a8ed8cf46e44c1fc19caeebd0d070159237f8f53d328a851722f1d45b65900bea1b4e34e0b4182c1bc87634bbd8846d87ec9ff95183b5a0d49bc6c814e51cfc26b5257589bf422d9988362b88438c1e07fbeff3ea98d06ab04e1a776c4142668b106272e57d39cded24872335936d04cb708a10ef4b18a8b48c6c66c81309688e3d4345f6db685c7c17a127299e56c1ed1962e950c74569d73dceb47ac9d5c7ae18a3dc68429f7aa95a0333bd256ebe51da845a7ff444218f18ec9c5f7c8205b021ac1dfe67679d360490dd35a69634b6ae608ccd2cbe4ebe0a1d7c6787f62c2d3879eac59c8178a226fbac919232789746fc145c9a7bc3a65f33901c1620361afcbfd2a9c0b94266290fd9ad65387d07c53f55a611f9bfda39d7bf6ee57d7bfe8ff8d38a5063910c1bb8278b06f1d94f38d6f655fc38c9f190afd057c70a1fb1fb75730e61e64f2f98b01f4bd2bcfcfbd0644d40d8d92d454e0fcf3b928f5549bdf61ebdea0bcde831cd46943987fa4e0baba79f9bf57096d6d60f4410ee2403e228d3e45a4f02915e587a4e063f2a77cb873c1d6ad6a883ad05bb0d14b93af05677a8a57b4d2d27f84b98bceead841325233ebd7f19b21107141c403be7dc595d84e3e23dd7131d20e951c9072b2bdedb07a94850ce6f6bf6f4f7249a99ba9cef6d14f66c1b54666a028ebe57e8278309c9cdb8beba43ce16bac3f989413af5c899d1ccf434c40cfcc87df120a9367bf62dc9779dc82616114612180cbeecff2519d12371f19c24c21b0b3e6e74ef331e55b486f655f641bcf9b993951221cdbab01af9e95355252bb78dcd2b5d9e910add88a9e1cb183b3947230e7de8af4fabd39c97aa9e64c963b582129cd3c34ae04d07536581f567f3031a9f0189c039f604a6eaae398032ec2cad6bbbf97c9d77748ba8f6cc0e672c60d5492e44ac7e518c592d114bd51a240ef901c9ce595824ad0c2f0103a607078dc1a113e9b77c3ab9ad6dc4682344322cecf4e79b1e4642e4f4126247748a0a340f56e540d4a864a118a279002e3a1c30d7cfac23178a0cf4a23cdd748b7c7e4ac4e23bfc75c58fdb0b665847686638a7df4be1103d25423770817d387ba01aeb35123c606110df988fd09b203216ca430073d054a946bc9aeac1edf448d39b557ade501aa313d7bee8d21fb54add20f96494174b06bbb2048bb9e97797c8e2135ce89a713823423d500b9e4dc796bccd725a7a387c5c19ee585c8c9e1324f85e2c983041c7613a1d955c5e0b054dce21267c8d34078b2740ddc2d9100c92f2cb0479f42cc7ce6c12978ef63556ba7997f3e371abeb7f6b1e0d8fb53a5eae758baa250e4241fdf1b6365f7e1471e7a5c5fe70259152f7a209edacf58ce840ce7e7dcd09b36e6c4cd7cbc84c1980f5789643096b50c043f24a4df7fcd161ad0ce1714bc2240f066c0ec0ef556de623bb9b136615851c9ba33499c6efae755674d74e78b8d59715e74551ce45925db73d38916b116b3926a78a2e121fb44cdc5bd8423823c413b99e25bffbde78d9d06b5d19c9aa4c576b8bbdf73b41fb4c03c7467391b1cce7f014cc73dc4684f796176cb3f3160eaaa8c1917f42af057a42cd0e8831807b84e594d6745c226add56976d3b2bfdfdea5efbbccb8e266376b76be430fafde4d69844eceae99d7f4c97272f9e59061d23e7f67374fadfab38f847b76ecb23f335c4f8b67b728460798f5e1f9483d00e2c42410ca0c9bb9cbcac6262a1a84a8bdd123ab5c581d5f4ed509b57bec6fb8b6b8add5cd631cd016ba76dbd27b7fb4e5d2b6a5caeb213207f0fd5e6382fe5dfbb0ebefb39b195c9d76d38f9c47bfea43302e28b8d459c81ce05cff306d97938653671c506a90c19f2ab440965a8ff39ca30350f2a4a376d9477d1f3e662a9e14ec918d17e373286466a6e23a613ac5bce4ac62e4349d80356733b1e60ed5ffbab6e75172cd190a02029834a7e6b9e64e72b2928756985b73e26023e92da74c4e04e90a2ac774db3d22079f586b89ce9c8be07d3463a2754962c0d0f733111ac3ab1411cf0b30cb55a2637736d4a5a9a44b32139a358e00286ec22a69d5ec06843e9cb332903b20b9b52d8335548e5e0dd8d3f64674534db0ad6b466cc8788516cc631a4ae0245b3405662e63602e0b4bb24f7e8217e6c0d924f99f2fba905e78e128b7e3a3cb8993f93c411fdce0c765202d5a56cbc7ef1ea3b9e4b724c537f95ffcacbf44cf8926c0b18aed805d009b922e1dc7db956481a245a44fbbcd9cd3a678134dfafe677e3dde024ef90c34ae863dfc4ec56ceb560be330a6d068edb2f62fd926ea78d282774fc9ab190442c7b8cbbebf7eb85c39b68705c0261ee4b808620327ebfa854fea9537e1edfc989db2e4e8083610241083ea0ca0969e2843750c67ea9124b2ee9061a833fb9da81360685de870914a9e645f4bc4dc2c41303624b486d87ea24de4440efd4a9435a0f30434391b03cf20044826948a78bb25024560d25b00b98c0761d90a6f1046eefa03308e08040032accc778336248b2e752f440a8d291584f660e62b5aebcaf258db2e722663102c80998b167094ecb7ce0aed3e583a33752dd66a6d870262866a6a95fc99ecbda3268d2d11bf3ba255f9c94879e7d6a1a9f126f5192460802003af9d3a41b4778177e4052e8a6627debfc0e7a7d99108c1c0ef8481f5b866a7ce26e052085f4195dbb1ac9e425c31bb2e9983f9a6df8967844a44bcc8b3d5eac4e03ab89ab49638c97d103a6dc076eaefe0c9e8a49283676c83084f6172247b1755a6a43004585e2aaf627eb7700c2ec2cbbb63b0e4b366888389e391e398cba2106bd23071cc56d0835bed3f0ce0747d26584f9c1a652dedf594aa9b0e650a3d8638e186fd65ff16c534d539798e2d14a1ff75e3a0f20190401918c4c09e5df0d48a630c0d859768d26d4aaaaaf6668ca728295d980faf58da76cf27b30203a74df8cff3f1900a99c0b0ce516591d247a2639112f0c0557e0a1c455d95140aeda31c93bc79de9692c1ca409e8d931965701e56ae3c5416a9b224f57c39bcdd3fae71f6c7590c747448d61897557d2dc634acc249d95492f5292a5b02c57d83a807b4a46ca670faca8e9b29a4da116f4239245adaacc429a6541883b45d28f8578232933e8d885acf49b7b3cf228301594b998c3d7b7de19ddc5d0c6dcae961bc86ba75eae2d135fd53eeab36268644b60d293134a3420fed541bb63ac414bc24720848fb692fa80c5fff3f4a511959ecff92762a8f2582355bc82871f1211de99114bec99262cc2a7bfba298c2fa0a70291c2bb6f74bcec2c54fd55ffea77695c10177d7e3a4c2f8efa2707971cc67d8bd89c33c337c3633d9cdcecc957f705f4a27e8ccb3b0c824840280f4cea1d51a6f4e88c85be4b9e6452611ceeb930ef476f1bc5ef6dfe6b5a4c914f3f965ebd385d9a82791bc559c3a533f191fe7588c34b635554f57c814c3a1582622539bf82b3d055147caadceb6fe1fa1002a445944196fc72c08c7901803d72f91675e4720e631207767687cc114be9b2c1a9bf59a18afdc0971f3c659126f4bb31dda0f5a01494454bf912c352b24f2586e26ce767cd2019945edb161cf0e0f98206e258d3021b0fb7a8d3a2d1acacee835735efb57084d1f1fc8757f4b369dda12fe9ba900c10a08ae48c10a08a008018509a4882129244061022c244831022812582182c4e2d4d90db1a749c42511d3cee5e9206c074783e0a5523a9f0f62bbdd50386a6c7fddfc0955e9534a7461ce924f1377e3809bf2edb7fe13ca5953413e238ff3ae4eccdc5ddf9485184ccd7fed4c13e375ef423e259444f7bf8b2829c0d343b09dd863bc3f55ed70d2b2facf055cb682867c40afa178d0a06c886a3c0c2d6b2134b8f0fcfd7b420825c795adc8a4692e41fbdf62155a2e6ff95c7be14f14fc48c08c0bc50920226555c135b53454e5c32eafb1b80b0744db47bc0ea63c4bb3a3b907fbe6331bcc283ed12a5bcfd624a3ac1cd6dbd4ad686570febafb83e7956f40160f6dea1c1e67923c3f4f8c3d764d269a466295e2e57ab1bbbb06c05bf609d18a07c15567efa7a15daeb15d8b8af1f8d082287489a8e90486f4875be19a6574ca696a4714a95659ea847bfdf5a8cde4349c4d33d031a07c94968cc66d958992c3f298189ed6c05beb65622c2f2ec840c26b0931d20f545aa2ef3214c6de1456e3a58f8beb712358090834284e111731af09aaccb367008629eae4d1d8da697600884772704f72c436f05eda10759e58f1243e09d4e22c6b22d3ab3de2eb79a97a530aa4e489883bf580229effc6409987120c0f8887fb97b7b1558187a6d40204375e9623c6ff34b360d7cf92993c6ace11677a42b0959599bdac811c30b653e9802724bcd99204f40a2fbd7320ebd8d981a74ab5b551a3d65965fac80e72d543988f213d398e0ec3f7e11728ec806cbd806bca068cb2eb988f6d1508b5852d2921d2eadc4db6d310b75fc1a19779d6d9f444c79f0c8dba696b0a39baec5b26eb12e2209c371174864cf3a78b594caa93128081e94e578da6e52c41bbba03e37a8aa060009076bac55eb5b4951f2ff636f8b769f263fc3b75840ce1934ecf70500e108acd0225836f04768cbe24e974c19fa7d33590590e4e17b85816c8e6f892e95ad1e987a0e2d8198401d4120de8781b1d100636000e942667621ab26ca271290cdba7f71c743d04d9f44f291f24911230986164d3b929ba76d1f73bb2bf78687c8a9211091b5a3d2592b8457aa109b0d5749f9990041be0933021b0df2ee98ce9ce53b17aa05c8f42062fdccae108ea638132625a4d67f9e448a29672a4908f22400c4dfed8170a848c7372417ae1bc335417bdc701fecb348af464e70c38a190bf43d77c05f3d10473021a0a9418b192db8d879b4fb87b35769b9098184084a296ad7c82cbf6ff547a5db6b62ca47c6e9f4207dc2a05cbbf3f2d2c80f06aec4f4dd036b530af44a27be5b60f1d95587f37aad1f38945f5b61fbaaad87f6e54a3eb1b8bea561fba2a31d831dd123641ff37b62a370ae815c30711c721daff272673d0ab4be724453ba71fa404daf9dace0f931a1cf9045ad877c8531040cd381dac76f33cd5b18fccb3b6ac35244df293f11ee7f9ba9a6029098b41e2e8b965b35b2ac396724726d44892dd64e5d2162319007ff1ecc1af1e38b326ff81ffd876b3a98f0188f8e99166fccafb2405200c4c0c210c5d97f1fbe44f3aff522cb338e7d5529bf9a831d32a82a0f56a1c85696fc5da9f6c87f0645d2ba967315ed9a1f946d90e69891161f9fdc48842496be1fb14cb288e11fd678d624431220c7e063fb36244312231624c628070550d8e72558c083f96f45b7d12df4fa2f5e87229939893147cb80ae5aa18d10ab3babb8336492187498a2cba5bf02cdd31f8184b2dc280a28c29a208832fe7c4aba954d582a0f55ef83ebd57c24c1c80b5cff75a96b9deabb6be364071fdc4a44a5ff931fefcca8f67b5b0d7e8e5c758beee674c65b9d2d727c9ffdeab76c8fbb08529fefa3120795f7369c1f23d4e5d9be5f759ef87044431048a2c50882905297dc0061c1a98e18931cd796e878aa0e152adf737f46967f9411f61250bd01c29cda1812f5425149cd8c3e4c41add754ec36881852c2bd710110d2c23a22bee4529897777277434f40a8a61d56a0509bd808c565b8a8e5e5c56429d0f59d1c416f33f2a638e5d56a94ac5441335a5154a28dc4965d1bf959a8beb3e26fac3b4d8a218bd9fe436cfcf5e4ab39486fd69ddd357b59d57eaf573a6d7ffca4a5d3afea4fb2d0f2538fffb8b711197576e54bd6ca1ddfdb58909236ced2ea9d05d4aa1bb839450e82e05a0bb7442c984384c1798a3913c097bbd383cdf3afe3e296122063fb3c0cfac229a29f2e65ad04a9c5f8f96582048b71881072cc1e58423598ab49506e8411384c687013994fef8c18d369a7335e7cf5fb16806f53ce9ba6e86e595ce515de755ae389b27381e0dc75c43bdeb5c7e7646fbeab286fe30b7797eea419a8b6a5288c34f63a008d29a0463d6a6866be2393a1d92ccddb5d99356ae88c2a2f8c9d4db6c41ef3e1c5d9dc76cc6958a5fe8393af37ef85856e1bcb3a989d9bf81e2ee068a9dce796d0c536ef462164b98cdf848353efe2c4bd0e7f7b3fbb3fc329b1df530ff2b3f4bd97f3f1dcb5928859c7b9cedd07f30598f2878bfc80ecd7a34d6ec2d8a7ddfb243afd7eb3586dfb4607ea954b85a8a55aa218ca0311551c655fe0310455020862290e84e92c43ff9d8a591b8aae59493542dbf72ed53f28a32d7fe25af287f262fcd444417a1bc34b759fa570adecf3fe783547e3f5816e17f2bf5683492b9250395567e5cf891a4ebf1fdf9749cb21ee5faadd5106874f71059ba63960811224570971f2244881479cdafe2f802bd1a7e7d9f677d2c040bdc08bb1f7aae925e99847f5cdf277fc629df4856e9ac5f34de1765f83cffafc4ce8d557a8c3aea653263c74b32bd96ded025161dd3f9f5b14bcff27e97a32376feb38ccad2a35f28023947b31509897e4f732e661dfc59f6f94f735cdffbeb195bd0b174d475eca0bdb13affeff7ad9cc3572639cd5624ff2cd6c3764673fcb3eca818cbb99815fae1e236bb7336df2733f518751ccf58aca146de4cf183347bccfe2c3b77a90cdda6c39dcf47d53ce1c9f19c47921f6c7c2ccee1f031c64f65955a59b5e37dd106f78c3fcb8feb9274734a49c3553ee8e3f749118b9e6456d1c6dc0e1dfd153f2aadccfaadf9f7f347ff83c97af41f8ce6fb499595ed10d0984330e8da9957e51b615965ca2a76683e8c5e0fc3c416cd66c1489ecd5265f4ef27d956b643f985b21dc2ff566615ad956c87f05165815eed35eb633056c0c0e0285765fc1300afcfb602e1c555423f5c661ee8d59c8c219d61270de0e9b6d51570c41c5e2de504f46a4e7460373a39de74d2f339f2779e6742c989f5e8dceca4523f3cc0f44368fac1c90f35dd75ee394ef2ae4b5522e76c3e8bded7de9930a9710ce2bff2f37eba83c922064a143187cf83b2fa944fa25926d1fbf385e5f7c91796332f4bd8ebbd6b63b34c694e18c06a578d73ca113fadd91bfe15c3d7f751a45c1fccded7f077be57455bab7c8d357b431f884a301edce081890494a9d25d001f0c90809ad20b4a30e8520a4a5c94ba40c00e4152c080ee66b509012274d7710f01f470002e4d6408d00e70e0cb6511bcc10e33310c9043dba08424890a44e9ee239c74770f0a50c0f5c95448007fbf56ea5272fc05af52ec374e2589d7ff784c3a1cd1a5559756257497363da8d8408a0db050812a1468d2dd61bac17451b71601a060ca8184ff60300a039af2efce1311079c93f452a970887158c184c38643dbb8ca51fe8afdad71d1ec4f887b44efb5601aae300da5acd26b6759945f08d21b4a42dd30c8da34cee4df8cafa8f1d11d43fbd46ce39fb6be9ede4c33d3411a34d9f872f7338d597bc31776e56fa9a64a955481561531c40b6495fac043c986bff3a3332fc994f5683c5c107ec6489efdb0c76236b4aeca5a7d4864879ecb8fffcaf191fcda9857c518a6339773f971aed6739ca9a388102142a44895fed7c6be8a8f8fe463be74facfb2749bfd33bd345f8560c25e384ce505dae28aee29babbc80e6dba47e0cbe577825f36df3aa69eb1fc8814a9d6e230b47756eb19cbff3c4beaa3fcee2711795d7549853e6c6042824b6861430bdd611d9f28630fd4dd2fe0e00204c29e571f60871c70b04074cb8cc194190e78f0f1507a2fdad7124fc94acddd7dc7901b1c0e27e57dd2f74910bb0092d15dc369139843f77d4c6d777f69d3a786094cf5143faff657ce2af1e566de958f87d0be7670a443f5824251f1a1e236b5496b72ecb3a8547926a3469728c73e8bbb7bf58283d7267dbd6cfe0bc993373b0dc408a3832a78a0e213fbef353fdb4102a84cf1265eff7bbde667856edc2748094c544cffb4d5c71c824f7368400f3437ccc67478f4c96fdda229efab542a95bc413c3c3c3c3c3c3c3b3b3b3b3b3b3b3b3b3b3a3a3a3a3a3a3a3a3a3a3939393939393939393938383838383838383838373937393739373937393739373937393739373951a2448912254a942851a2f4f4f4f4f4f4f4f4f4f4408102050a142850a04081f2e4c993274f9e3c79f2e4090f0f0f0f0f0f0f0f0fcfcecececececececece8e8e8e8e8e8e8e8e8e8e4e4e4e4e4e4e4e4e4e4e0e0e0e0e0e0e0e0ececdcdcdcdcdcdcdcdcd0d4e942851a2448912254a94283d3d3d3d3d3d3d3d3d3d50a0408102050a142850a03c79f2e4c993274f9e3c79c2c3c3c3c3c3c3c3c3c3b3b3b3b3b3b3b3b3b3b3a3a3a3a3a3a3a3a3a3a393939393939393939393838383838383838383738313a507ca139e1d9d1c1ca14fe66b4190d5dda8ee1ada440032f2be138fdeaf2f1bbf4a048a20ad548866bfaf528fe667affcfc0793b37e580bca6d64219a2c302ab24378ac52c8dad1dd7574371d41d5d223a34c419ae5fe28b3d8a1ee9ea3bbe5e86e32124f2f28e8c7fa945540f71f7c411157ebe11c8af2a3324956d1ffca87e55945c714bf688357eaaefa37d81bcb22ccad8c30c7f3b333afd6effc2cff7afe307f3af14fc7f42b4d86d8eb3f0c8f55826eadebfe283fffe48a0622ba3b8eee564177c3d1261ac237de66afd47f96afad62a531cfb6fe549aad48f5c886663f774ec67d8de3ff983f68b18f32749b7dccf4a33059597fc52cc62af5efa3b4f959ce2c4a98cff2a530975ea56339036dc6a2c7519f2f1f263f6e62298ea963fc77ce2aa3f893a20defd95614b8d1dd6d7cb5430fda56779fa0bbd9e8ee354ce0fa124403abf5020a0222fa190a7a1911191905bd82b21c011109bdb8ac8454aafa48d6f59f38ad508f0ff89995f1cb2890cc7e93f595ca6ad08f16216c6ababbe5f87dc9892326f0e546d80b63197a3296a2628a5c65a520bd1ea6d341b13efe4993ec0d1dc49286ed1559a5f95ad8ca4539abbd1fa14a38635a0baa4077237184acd269bd077aa34f6669a5bb8d28a25be2e9fdad32da9aff6587e7c9ce1993f5e1e81a1f8bcde1783d952a4767b256935a2d7f71b61fcef66bed3c115b435e6128552a7945f9c222ae8fabf55e21f6e807138b54aa28383c3c39171bc1d0ab237b9f86b14a5d5dd1f32ccdeb8a2651a09e1c9ca3f9356a650812457874ab54af10cb300391eeb04d4540f87299c27a72705ef87ef8fdac270747246283e8a7bb251081eeefde20cf7edf8aa885a11eda0126a13c846ce396ac528ca9507743000c8b872c7c64b9d29f05087cb95996a193318701537f52cf5834729ceb83b2c73ecb32f4ef5ba954dd2ddc202824e980880e80e86ea23661b1028b0e8b8b2f393a2ea547ecc2b279c29373654890d7153157c474d76e1660ba72d3b9521bbee6d768cca3f9c159a6573ab962a4bb47987f087ece32062762e88901855c1fff2d1233b63b492a95cf0ccb2b323ccaef67a5d9f959ebbdc43b9b55be40b1ce2b69a15893604d82393a62d007ad230225a05b30fb559941a0c765beac9fa557edcf64a9542bc0daf4b3c30b3f2574370da175e5fa4941f872b9f6af0ff1d39b49286a575d3aa3390d926d0431bacbd6de6efac3ced83cf0d94698f259cc744bc5e16e0028a3db5595662b169afdbe9f9677ad159a9cb940f9aef97fe7fcd94408da4200c11602c8727d9fb43070c47ead3f282bf749dad73c56b95f24da9113ede8363b379f4ad0a318fcccc28f244121e7baae26859cbb7496b1a380584e6739e36ef4542a57d7728e3a873d1aa3de87d8abd31e1fd529abd8fb34542a24abcc7af41408dba17ac52af313ed96249ae59368966c87bccaca7608c993b0ef933fdb9127ddfde2674309aa541b0864ba7b7c24d567f9b5181b08f25a2745415b90309b911a74588f32f5e817d68296f466a427685259f47dd26709ad8b02db0722e87ed0b65e325ac35f9772e33e2e656e1f5ce96efcc190de8a8cd1f767732b62ea16e75fafd4a3329b6523a20668af15fc65ba558eb10cbb1b490bbd0db1621b72b721ae6d4808db1023aff768d27d8c2f87f126c48c10383621676c42aa6857bd6a125f54a6f3efcf2349d7260409e3f9ca9582f58ab04fa29f7c85ff482f9a9ce5184dce72486718949f5ff9f195ff799f9c334fb4b952f0951f6f41bc70104488090f26da84879836e101469bf040a34d789869d30b82b4e90545daf40215ba7b84108c14314d61469ba620d3a629f668131545da44850a6da282499ba850b5890aa0365181a54d547419e2c1c9c81e3b7ddae3a74f7b1cf5698f2e7dda43d6dd48908c00c2b6248fde9604d25bcd91de6a52e8ad86a7b71a2cbdd574bdd580201cd9909051a24d6436d026325cb4894c1a6d22a382369129d3263279b4890c1f6d92e38336c9e16d9223a74d72fcb4490e579be4f0bafbc807206c320ce94d86117a938185de64c0e94d8629bdc9d0ea4d86ae37196e6f3228a037198a28128210103a2872ba83883eddb1449fee80a24f775cd1a73bc6e8d31d29e8d31d66fa74471e7dbac38f3e9909d2273347fa6426007d3293a44f6694f4c9cc4d9fcca8fa6426863e99e16242228484378adaf4c60c6d7ae3d5a637be36bd91002444402812421121dd46b6235f6f476ee8ed48027a3b1281de8e54a0b7234df476444c6f473cd0db9110f4766404bd1d71a3b72374f476c406bd2109d21b9223bd2109a1372426f486c47b4382ea0d094f08a7cd84c4c807438ca8a14d46886d326287361901449b8c10a24d4628d126239c68931162badb4808276c518cf416a584dea22ce92d8aaab7285b7a8b6243779f4c38726488112444b60f361308221441b26d9e18bd796cf4e6d1d19b77a6b709426f3300bd4d25bd4d9ddee6aab73980de2697dea6acb7697b9b0ae86d42a0b799446f338adee616bdcd347a9b6ef436e7e86dd2a0b7e7a0b73fd2db9bd0db33e9eda3f4f6acde5ef6f6b8b777406fbf446f0f456fdf81defe8bdefe8cdebe8ddede05bdfd99de62427a8b997a8badd05b0cd55b8c4a777750c48891234540e8e0f4810d6d0293d426300868131820da042689368181a24d603ad0263060b4094c09da04864c9bc0b8a04d606ad0a630346d0a83a44d615268531816da1446d5a63059da14c6d5a630af29fdba010add2640ce0052c7f7498f0c40a2e8ffd8cbe6172061ba7bbefe6380e4d00d4877e5061014ba1b9020af337a74f71938bafbbd6aeb98334a74371e1fe9b30f7d1fe95adacb74e673357e9de9697cc64d6786f4f885a1fc038feec67fa8d159befe18f387137f84e9ee3fc2fec34be3a7cd81923f44e86e0a66fc343fce74f77c65fb61931f54f831816e6ecc21188b89307c3f3f68ab4a0c2bf529aba4310234ce1041c98c253e7081a90f115099e293825850a1e257f46a363548f6852967833d079b97a3708d921c1c856bc6477a8db0d78be3e04baedf9a577a9802adac702ad5b79ceb3a8f59bc72eeabbdef02b23f5ca8ec6795222dffe8d9d6efa319fb5f79e47f9f86258de6454246579c0b9d93550a5aaf529f9e633a3f49629f554afb4d98f55ba9cc30eb58d264c67626afc7acbb748b3f994709a26495a22ea6f763d2f3e39fd19947ef833f0bef2cdf4b41978e29fdfca5ebba3c685b1d9ed7d22acb39ec7856eb75e59cdb5c2dbdbfc5b9a73763eab3de0fc7af267de9ba2efe6edd568f519a7c8f594f7db9be688347f363779573a157eb3dc6ef7d1ffd120444f4a352bdbeef695dbe743fada7eaba7c1f457d3265658e3f89ca56cecda75f184a7fd8b4787e4f6328c72eb1f4bcb21ccb2a0dc3a2b1cafc4c6174666f91cc126895edd027ce9f79ad6c87ecd0ac4772745d77a98cee1219dda531ba4b21e82e81a0244677298cee1218dda531dda52fba4b5e7497ba286d51f24077298bee1216a50e94aae82e51d15d9aa2bb24a6bb2445778903dda50d7497a2e82e41d15d7aa2bba4815213dda50c749730b0c475410ecdc92a9d2e28ea1996af2e66da6833aeee4e22800ebff2cbbe4f7a34664ac0b9a30eafc6c31d52a44270dec1a53f09b35f0c40f80dd31d225c0e670996a940991df25fafda1f6b05b35a5ab084127ca954aff96ab4208f24e3fda4f74a3df487d13051c4b9578ba96867a68e92575cf9b5569c7b90e6fad82545ba9676bfbeccbd3eb633cfaf6867700e6331cb2bc350ba38ed0d9d09932b695fc5393c2dbd1f3a28004cf3cb9c0239a78103acb25421c68e0ff47bd5da11841d353b5c8d73fd6a43d01e491b0a3c20076903f3bf3a78e8d0a2268538ec995691b3998e72544d4dcc36f19dcff2bbd61f7bfdd0bae60f613b345629342f518c288b44f8e9b599d5ba5f6944d90ec9aabd5b1ea42e9acd62ad6b4b4d0acdbf3677219728b5c8c82c81569385e4d92c5a7a84e8a18f58417777c9007184e98ee33b288e23dcf8484dbceb1e49e2ee556d77e57f9ee3fc32cf2cf7f1ca4a617246a35d8b3d878fe47dd27c8fe2f191f092873dc6bee5da49670f7359a51e056db5def8517ff1ba9c730ec7acbd45e36399787c2c766848c91b41ba3bdb4b63240513e8f9f3671563f3fb2badf7eaaf4c25106281920daa20811311684c508308125de386125deac38d1d7c3918e85d9c02bddafd17e8d5da98d924da3872823c4e20c5099c50728229affcf865a788e52b7bb2fe176b98ba6dae35542aaf0cbd5a283a3a38148fd8c40650f784d91bb22182898d0fba1b851d5f0ee7584d52a9708ed535a8690d9557eb4edcab685454735d39fbb9c9c9d1a149a3c9aafdac128c0950e86e262e7003c5b01b28c61d16a5f730bf32744cbde895b2b14a5f24c0407e2ca318e7f592e64f045f58bee69825bc4a1620327e37a1cc18a4797ca4f1915e2fbb6238823c46f0c60872709202bd1aedda17e8d54c686c818614ae7a85b57f599b1d852fe7610a3af130054d6738815fc4983a99799f3dcbeba14b997f5f26a337ff153f89e2fab19f2ecf28ea2eddfec386b04bf628ac85abfcadfbdfacf2cab7b0f885576c198d62952b99550b02baf2bf1f59a5d87e3f397ccf5bd50f89683f1482f7cabb68f2ce59a65baaa5acef933949a0c74588195c329659262bd77e28cb7dfa85ff5672ed8780f087e0bdf293defb494421e871a99f05e3f0085ffbc124a640f7ff0be975c9a4ffde28f646393a47d635e5077a5c3e265bf8317ecfdea210f4b8205d09decf724b08de2b332cafd0ec10c6e36399e3fd24eb610a74ad95697ff2b72605aa967e325bd727b304c22ff3aa4ca2d99395f5d3feccbfe1a7fda1fdd06a94dfcfa34981022975e92ed1d05d9a81a64a0ebae0f0e7ff7eb2846460494ac8164e56eda579ae3fcb0fda96731826e29957e5ad22240c0d63f3b128a48b0a1c9c3a981d181184083d82d0c0a6e68569120e0209721424280894d296211e6419abf42cda99a95beca88cc5017497b474978e4aaeee52ab341485490c54378cf64349849147a55fa5fe30bf9ff45a98c220a244022fa5d504c4b823553f8ac55976299fa43757eb3050bc9e6331749b2b7dcdfa1efe595ae2f307a318dbd0c7af62f04aff240b93723eeba71daa02f4f4ba7c56a952c140f1fe34807e54c62cf62e8b60f7b14f5af2b4710c1036cbfb999664280d7d9143a9a8bb443434851745ed755107eb4a175e17417aa8bb278b0b1dba7b5631f6d70917266c9187ab4611a652dd9ff2ba32bed4ca234997f7dac28aee9601681c4c8b20b89755af3296bcf28a520b026831a5dbabe2cd8eca987eb9f695c70367bacbf66b756e3fec2128337e90ba304da2d3e52c0df1c051cb2b4a0f8020cb02882c4c2d2c98e89e7959824e74929c78170b8105162d5c714437075eae0002bd9a04c10e98e0fbe4cfb4b1caaab6cae80dd19ef64356bcc00a1bacb8d2fe49162c7da03400d62771a6b22b3ff79654e9b987127cc592e8f87d96743e08521f7f96bdeb7c8b73d21fb49ecdce7de96a5248a50a47bd41804c777ff1e228d4a4dec5cbcf32950e012bba2150838077739e0c913cf9b9c4a19cdd2f72ce867b8ed6f816c68da6b30ba344c39684a985a9e16c6e587b5a03a6cc186e0333e3aa9d98d27cb4f93e59e39566c1c07025185373b107b8c1e5077cb13d60d6ddf67accdaea1285256dfe7d400958a4983a60ccdb2c69a693ca706e0e987577eaefe600d3587fe6da8070a337207ce0e6e7bf61e702e2a6fb3e16e7bbb606b88083ad7c7cbe4ffef88c2dc7d25d53a6801e9729355bc507fbf864fcd3c7c7a6660ae871a9d92a3f68f9610887478984570cb881012b30a0880f56f830830f443d9ce9818ceee6983c683193ffc66f6249fb9149b69509a69f185b713f2568abf7b36c9f7676881bbf4f5eebe327c360b7e2e6a33e29f4c3a587560f29f47064015c3487bfce53dccf98bdb3fc7d36d7821620bb9ba8b7059c1640b329404c734ff3f1f36cf6ce539cd00f171feb95b2bf8ec5fbb26a3fcfd28807301b0f2e6c0920334a211fbdef6e197a43c00d106003042881802bcd3d9633ef8aa1ffc73c95e2b2a433996843d1510700e300f500ddb643203bb060db81871d380388c000073080ab0067badbd55b019c284002b602dc703eca5095e2fe6332ac9fe27274fc615dcd57aeea3a4f7135385cb2dbd8705c0daa26874be70ff3efa35b9cc3aa2e25ab1eb3a1f4b0fc3e899a0f7ea61feb3a4cfddf0a27f4c3455e8bfd939e0e596c3a24a14312dd9dea4d87dbdd5a7ad301856eae3a4ae8874bd7798acbd61aa9bace539c4df89ecc72561393b8f5590bfb17a63ef7e9057d6c7a4447f58835531e364af06629da07696e53979b367589b5a98b03dad4a589367519a34d5dc8b4c90b095e7adad4a583ee7e7282099d04004d9a30b1a959a2e405175a602189afd04d23044d1012e8a68940370d04c2e0e0020e2578e0c31030dd340fe8a67140370d10db0d6b6c379041f343370d037c3072bb24021fba5aca61fa85a0ecbaf958c23c0445988fb6e55c17d28cefd399149b262ec5997813ff8fbdaaa5b8c6a97848f32bff27c526a4b9c6fba4f7a2e29eff73e2c4ffda2aa3a88cc5db759d73d44798a36c429a6b3c357e577e14a4d8a557f1a672b5b7eb5ce26aa92ca4d9a5f4ff58d78d9d5ffa33cb4248b37f52cc9726b1e09f459bbb4f76997e22e8ff315f795219cfa24dfa40771fd1dd493c6c4961bbcace68495c927e50af2a3db10e49b5e0cbddcfa19cf285639ba84454416c5781f6c6e48c96cfe8ee1e23ffe416b2095fce894a95ef27d5913d2ca67374300f3d8457f872d57a2a15e8d5ae19574cb7ab66a5488e0ac5165e793494a880b0465766002410951ea745506aa153502a75ab154a5a2bd76f85d4956732d156013fb3dea32c22dc32cadf6ae1ef5b55246a0aa018dd1cc64b6216fbf7c99ffb45dcf749af2685383cdd43eaaa49216ed6c7f7b1e8d2714833fe2439c3dcf858b8f191ae751658a0efa82aaf8dd1b073dd6439f899e52be7ea879fbdee97be579fcecff23e28d6a7592923e7d6671e458d554e56b543d90ecd073fb3f0f749b065ad2b94b4d67fb27569368bb5ae49abccbf34ac05014d3bcb2f94eb675c5976c81acd1a942b15925902d5a450b6432fa10d360446cb95825784fdc5df47913cfb613a7e3509be5eeffd6b146138a4f935ca309434fc02a9fcbc5c29885f7fc317ce8f5733a4d1a61960d0261a9c5859410909514c5c4e6de262d3262eb64d5c9e68139732dac485066d9ac18436cdd0d3a61988da3443529b669022080a08e0870a4b9460259bd258ea9a4b6f0420d2dd3d38dc4d2a5b7bb72f3e740d5f5018425303921724f0e55a43442cd7cfd0d1005e5c5642f4dab07949a13bc9bc2e7c391e0e87bb49a5b62e0be802e3f05fffd07ad7e696f7492f24e9bd1624f95be6cf4a3dfc46b952a1af75b30cdfa81ecd8c6d968c45a0f9343b6b100d2fcc80811984704d0a499fd5a450ad49210ea419bfc7beda4c674d9231971efb1e03b9ea2bfd1cb439db2aced9fb3750bfa2a54972f6b05182f8bdbf2eda916b5920bfb60609baf450f4faa15521617abdd26c966eb1db793fe969f68acf7ffd15bdc795765ea587627299c4589e84c82888061f5a5d71b951906b1564148307557157eb48c839e7aa75500e3927ffc67c56946c7d3ed69573588e5fb55d87453c5e7973b5de4f8a65d57ed2bbcef1e358ccfe94f7c12ace75f893a29dc1bbae731ddc7d7ca6c82c811c35552a47f94c51a962dfb7a68074d60aa5d0cb241577771cdcffa321683d5bbbae0bf2169cfb4250d6deab24d1ecc99f32e3cc399681063238d1dddc9225ae9af485c2b1bf7e6d752c67f76f48d559a678cc7452d1068a2b8be6fa322db24ae503e12f0b17ddaad76b8888d5320ad2f20a8a616544e46abd5e2a5790515190ee8d2805ddf8bf3046747f7ef6ca7d11e35ca950ae542894b4d657fa4df940b952a1bf4593057e6685d4057e66e54a85402abf1feb9a8f8f26eb7ea54d96278766996e11f26296e5cfd7dff0e7ebfbe42bcb946e2c69a1bdf59164fe095225c894203d4e926c583a1a187a04d04d13250a0d952952545168a03ce9a6e169a2c444a549544b81682cbdb1e0e8f92b1b83a32a753bd4835b594987d20a343b5daa8175b35da901506abbd275572a65d27115bf4a71b98fd72478e5c9159b2b226c31b0e12a9baf8d01278610ace0d1ed2a57b9eaf57904dd43bd59e1a11b7f92fa4c196167581121080e0e56100426f11c72f0f94ec5c773c8c16d6aecfd1b5e9872ff37c64119ddfda537200b7c4b6ec049e2d3e4d44344f363f47d140bed87a6fd69fd7cff5069055591a38b7a785a2dae662409febcd62bf51a8d65d1c2a47363be1fda1b3a0b3d3c18b3e0c92ffceb3d3cad96cfcf935b1283738f64932ac536e34bc51b7ac63f3f5be3e13f92db2ce41c87677525eedc2cf49f757f6dac669b1a7ffc492bce75b4ceb98cede70fabd87a348fd1ce06a552b96a3afcf773cc82985639f31e7459a5f893fe4be5998c7e8e65f5a77b3463fa7dab2931fb492e6d5c7f6bdca3a1cd2e33a69f773eae291df8f26fb50f5a4c633625f36c6bcd5671ee6fa03855a94b2db608539ae7997533f899aa825c4443ce61e7eea342e7baaee59c8dcc72daec78090e2558e31c0ea5102a8be1276d2aadc9d63920d6959fe851f97d622c943f533d2887bc0f5b2cebc2f37f287bd69529ae76c8dea7c1caf7c99f0e2e14aebb25cdce0c94188b6ef3b443aeadc707a7c7490f0a5b0f929e211b9440a0988152064a0bba43eb362fd4b813b779c1512fb82ab48e7ac16bdc5528ec5fba6c50ae80724477bbcaa6a6fb090b90ae94c9f015ca9f4debbd68351afbfb42ba125452820d342fb8f07dd2cbd882af2c5f342d548af4ba368f57528fc6be3eec93b94ada2751190bf83f961fc9a31997d428a131294d121a5fe171a5af1aaef7a0acdd2511d0a850caf103f46add342974d3a050c5ee124ea60900ed95690ddd3427f41f26d0944043c208746c397974778e33999f0da54773b3e5d8a6018008219c36130d129b1a7cb9da0ba7c6551e0dad47433bad10feb792bff5489ecd92afbdf2bf9fa02b56d149dda03b95b3a548e89c24b779564baf8ddd0fc58c6596369674d39c604311a0e79c2b3c9b0831418349b831d169d4fc3bebb7706ab3f1c3260dd0ab39ea0be87151a95c5df0ed6c2af51a97a0c42216956ab290aea5e51f729f94e3c0c42b445c25e382bceb06e093c2a0734c9864d13a13267e6dcce7635c93429f2df84923eb2aa2114273448b6d8991ae8ff1bf4eb029b182735592f9559430e12a25a3928a6b52488f35b617d6e86ee9d77ae98ced05256658ceb0bd3039d896ed05176470a10e20960b39896e2ef4747373c88c138cd956d0a3bfdaa1f955465bd95a239a34da580862636187eeeeba6940a0f98086486f2c4cd958b8a1f18046080ba676951191915190274992644b228224662411b32571a2672f941357cd77e2a8d7968407a742854a77a90034bd25094a72d3aeea2ed5cda9d83c039b03d1dd957a3547da9ccbe6425e63f3faa4ab72ed51ae5a61896e49c37fcd29b1a49f7c8953ba5af04d851eece4451b7ebebc4f1a4333c68b0ebc604b14344f341edddc63fb795ecb18bfe789f8c55ce59532f7d0da2d448a70f8f3fc7a96568814e1b0cc72baa45d09cebcfab01af34f8ed2a6c441a968ca082f480109427497f4a041a51f95b1a0d20cba4b32e8ee2079246d279cb19d3044f7d39baf8d79fef4e69a149aad1a942578ad15d6cb6468071c4944adfc387febd682c6c782e767af608ce4652cb3bc572511c6f2c3489ecd1223c2f24a8ce8f3689ec55856a9a20a982a5ebab9ae8a32e9ab1519ddbd42c10c18c410e0048391eee630f77d02b07212408e4f0b82f059f98440a50f2a719ca888e96e0d0dd12a769e1abf599fded883b27e8efd37658f29664cb9537ea4b8408a17526652a41424523c5059d1376667959d8f307969aeff7f6d3ea94e51bc8872459457140f4e3d25e831408f0d141340e100141fa0003de9e3c919ddcdc56c2a635be452329d4832cfbf5984d1f1c3fe77fc669523cc75455bed937f7284470f9e0f788ce5aaae5e11f6a2d9efb319ab343af1c0c0edecb0c344e78f93ce057468d0f1b6c2fddf59e5fc9c03cb31410c9c2970bae0707974634c479b2ba5e37743c38d9193404e4ea03839718013282727cd7131c74b26cd7e1f0a771d77e246e088a4b44851917aa58aa0b0407928119a80716a324413dbc44a13cf9d93f9d586ff37d859a6d92b4bd9c7df5f0b14e455d678771f14c59b3b9b9de59966693f98cd9da71e87d413275ec2f28c4570ac327f2b26484c54367bd86471b2a9c1e60af7528a5c857f5a218ce577aa2973aa09c1a946889a2b35a6e6bafa37d86b674b92382df9d2dd47fab48448091f642821a2bb679e685d8f24a5ac387c52a2e4853e4e2fa8717a414cf7e985009c5c70c1077d72818c0b4bb8405d48d2c21939b35decca25b5127debd4020f2d44690185e626ed4e2c6c39b1b042123492fc9024764a729424c8c963e0489cfcca0a3538adf0447f9f84b3271d533ac25c3529486dd879a5d9076dbed643d133c6b1f08a61d29de56b69dee1bf22ae4155be30f59912542d960fcafac2147f12a4decf4fba5ed77ea84298eeee930a590501a830a4b93cc256a714c858a510a6b9f15ba530aba24da126579b51df7742a10cadd9160a447c969ff4f083288428388797c810b4a700a8c1e153009ee89acf1f9f9aadf27dd29b6179254a9f4ea0e174c20e9993096a98309af0c2c9040f4ab0e25442772a21a804212464d114d53d1633166b10ede87f978876ac47ced9740f4ad48ad6fe8b7d52c6f693ffa2cca5579a0c5bdddd419f484022a1841150308210a71180648ac300e80200e009003074b5d363d4678e1a61df27c21622d8e09ab1de10c20a4218e214c2d7dcc4ddad47270d9cbc53924d055b10a78dcac974a69bc3f7b1acd2751eb392fb6abb90ce46f971297c3205f1714202c5098944a2c48d233f9c8efc1124a7232710c49c40f0a1ebac749ee264e7a99baec8392c4329ca280c9498769eb27996af1876288e56ca840997b1fd983071550c43ac21a3d5166eac5d31f41308424e46ca3819d9c148cde98333ddcde5d1a606d32c6d6658f381014e1f2cf92000a72264cc2ac75aed5f5df77dd2eb4e45724e44627022c20511312722349c88f834d77df26f17b31efbaafde4eb25dd8538e99f9c61399bcdb0bca252b96658ce6cacb26cacd2d769889850fe5d9d86ecd0dded0de9ba1b853e0de9e9eeae44434c1eac4e1e10e1270fb8cc3c0802ca9310322721617e9e840079a93aa947c5d6a90333a70ea4e0babff6a70be27e7c2c3ee363191fc9e7b14cf15ecbce13f1a7f54e1d70a72065bafbc7ce539031a720439c82e490e24e418a9c38e0e2c441adbbafe87930115b6b74fdb73813264c9870d23f2c270e60c814fc479242270e4af8d689468d6e2e943f73bc04063ec62bd86f39d1c04e3447279a29ddddabcaaed5751eb3dd4fe72d6fe23f35449da7c64c6b3fde420bdc4feb39ed6bd063392bf2c118637983542ad7fdef7b6cf3fd57ae93be72ed2b686f8cf6f5da53abd17d6a3192864fdd9dba860b848fee40bc08a4c6e12c5781a0ba0fc4c80dc674372747587783909b37f01b00e2864c5640c63417d20c880fddcd0132833996344060709de1a387ce647126cc99a2ee96a3cd673cf5071fddfd871a7f38d12dbd87fdb1c3fda3eb6e4ed2feb8f9a3577e9021e44798f6236c3f7a84fc1842fba13ed6f0acccf1f7adfa80a20f2e5ce7bfeae3a65d7c94e1643436e56cc58798eee6f8f0a1393eb874371fdecd01b1f6e0e3fb567b8ce9ce4baadd838866ed71a5bbb9af362fd9a304ce06656ca0840d6acd511bc030c26c60ea1a94e16a9045770d66dd5c0d7aba399b1a9f8f690d4cdda3ad7a90e9d6238c1eb3fc343d4cdddc5f0b8e55521a64d1ddb53408d3dd1c8b066177d3e0a6bbdb69606a6efeac3f9b811bae1938d13d83d99533e8e1647506260a93411e2d1988b1433228eaaf264119d4743707c4e2a3b93cc8e8fba1e7c73f7910813d8f8e93558a252d0fef8fc6c08dee1880e9ee9eee23b39c3ea822289fc9c2de6bc13e36e74a856496f35a2be067ea333e92cf64b97c7c7ca6f8f4882d2295cae58343ea42f9b01ce59a12230a290e69f651a95c2f95cae5f3fa3ed319cdc7352566274ba57299c9c38c1a668830a3831925664ccd75b03b4228d3461930ca7c65885ad0470b9e68410d2d80a1dba6fec735f1f1916a62d625c5622c6929298f3b4f4919bf1aa3d3822955fe160b8e60c10e2c80b120880529b00000769461870f76c86007143b4cdd9df43a4f751c15073b4fa9feda486fe29e3771d0c3d5b25cd5cd1bce63b68e21ea20aa83053a6c40c7982a661156633f3ba3613a4a98638c39c239beccd1811c61c871013992e45042068f59ce4baaa571e357edc762d2bbceb1aa43c2644032362b58630547c4b1471c248803873852710851810a5440850abeeeae732cca686c94e0fd24eb18836faba3baae1e7170e49182a30738aac0819af91b42bc71f48691147491021ebaede7558b023a50c001140481022b28a0e2c61d6e44c08dae25cde6ab1d6b3c533ba3390aa3326d038e36aa68a3d6c66c633bc19913dcb0a102368060a3870d13e72fb799f455d339a6b95250f589d7bb6e5c238735b2ace126988109ae3001122660994004aea37d75da57f9d9a6c6667b4798ab3edba15925ea96608912e012542981cb68ac92800a12742450410d39d418d35c37d2beaac1a551260d2cd2a0401a4169843002322378c0088ab611981ecf3cd939777fc9cf5cd9fb1a60d6bb2b7e3457d151e0679afa1bb6d038001a5bd058e18c3dcef8e20c26ce103ac388d7d9fcca95d2beaec059bed66d76ebe54a854440452064c61e66a0c00c1eccc029838e32882863a80c131962907144a6f7bd5e31b3b8f772a678090afc59c6f26fecaf634b63706e4a195e7b6d2cf6a98c1fe6d2f15ff193499f7a23326ec8a019438de6ba6aeb156398028da1658c202178230461bae75cad407003105c018219089c80e0041004f9801b8d6d4a4af7810f1c11830b3192c4a012061e61d811d45b184a704ee493aeea42e7c67c65989a97cec63002b0815107185f808100306a603401631b338689be2bce064bafc6a5a454f76799fe2759a1313b638a7c41822f10f005973b5ff61f4da237aca2a7bc58c38b0978519ba38b26baa8a18b255c04b27101022e94e8eefcad5184b9aabb3f8a196359e4298e8bde228e2d80d862478b3db4e0428b0868a1450b0e3cf0010f844f04c35aee2b577912958ddf8ab3c98f3d466b1c779dcf0f250d77ddb531afb25654162fc882892c7668f95894c1620358cc8045962b6a70851b15ca155b07c674a0031df8a1032b2bfcb0228beee63a507ec64b1efc283865e7295511d775dcf8852e63d68a2755dca00a36aa20a20a5715a6f959ceba1587f1129b7dfca8004385162a50db1466a618639b0288295a537420268f6a65d2c78ff652c1f295e1084349c7a1a46131338811224518522421054c0a231cf8830319e0000fdd753ec25c66393b4f7163953657dad5ff3826dea453c94f04af8d79f2ca98f562d6fd6779e380120e6c1bf8a30e2edf2b5dd5e190e6ce531c0e69de40ddc09640a280220a22a280018a33449f745b7d52c754de2e46bbf06df2e31acfdf82e20505ea09173c81c413f5891834d0c7a60138341005d7e56f3dfea4aac328cae2521a00d2c0113a9cc8c2891b9c28eae6301e65f89a345749f354e7ff491c8a8e978ce2d6c4184d70a009209a906d4db890813532c044068ac8c04f0648e8eece06a786a87315d7cdef1c670a068d8f343e52e729cef11255a7baf23fc74bc0cfb4f314779760ea635d713fcb4430bfd6bb8ebbd67d260bfc4c7daa8f8da37c6aa678afe5abd667b21ce5289f1c1df14ed667eae333e5c331fbccfa1ef6f171d4fc7293336b3feb971c9dcd02372052a97c7a44d0e3829ff0e45c6159e08905842c9105e8d12c419b4559972852a2054a484089295fbc384a89139228d39d34ab4c62892428abb7243c7fa24dbd1656e39972b9d65505dea8c0022a70d35c16adcf6b1d355d66ea28293724c040c207247a8ef0a4a33e11bf6c8ab09ce727da237e38c21e7182111fe8fee205556d284a9b51571ae142776f45c0d1cd15d144113d1471632b92cc1d92cce394451421d35fbc649102435000060ecb19058c1031a6bf7841c9d0bb78e16c3ad0e332ebb7bacf315b5325feb742840288e0d2b4af44b830013dbabf784175f1d2da26f0c30476305d7199563b9b0d71660826be78f18cade7a82e5e388c45c7a1cdd887f819628a102c10420242fc04914710477cf1e2933aaa7e52bd9f6465fe49b14a21e7462cdafbb22aa7cd3ee5df1aae5209fa741b8282786d415cf12e5eb85c25e0870498904051739d8da326ab4b9233714ae9be4ffe74b38a2e812d023388c0115fbca08058a82e5eac9d72b6da12019eee0eab06a804f248f7a116328468460000000000031100204024180dc72362e178d26e011400015fb06cae529e0bc43cca29640c31c41000000000200020902106004b093cc84a4d5305c4eb7f5bf2761535e8d142836ed9241c418f1022738aeee60b399142a60806fef7d45aa6fa74880e72a4dfd5981eee60e1f679eb765b8811e367899f57c798c1265921fa3b00e369afe61a3b1a4e7bc49a1373601c8824a4a140c1a5a5e67e22a64f6240550f933d83796496623c29e71224986b68ede731d149e60b8706de8ade46f0cf418899d3312ab01d380ddc7baa431598ca46729aa93d3e421e6b9cdefa65bd9bf05e1b6f8535e96924f73050d8bc49d28551af05c87d2e7462a15f117b53d99aed6b469c54b7f30641d62deda01ff2078c2ca384af8a03eab29c71a981ef090dd627e14ee6ec633f8fd2c27e34329aef33fd4e20063169ec8b1d3e0e5a97b0d8b16eb5728972b33e8e67d45c7197232c9bde9b05011cc649651690249e6fdf2847a3af53de1d955aaff3103b1c6723995a99fc51f47cefb36f7fffa9f7bd67e82e55f5a459f2298f5f1f3455d17327f74d3895fe88ea24b47158d5e7feb918778f6f93353599499ebb038adb55069f7677642d9a24ca462df1a275209883fde0c87012b2a4603785ec1feebdd4de9f46e04c0dcb04ec90c97140ca89edb27f514d5c69b65dbc233a1780623848a81ed775b89d938bf0db2384d9f246c60243b06122518f2c3912674a1e29b9e0e5f671f5e4e5462ba476c0bdb09c93786d935178b44621969e07733ad6b8cd29d373dcc6c5be4b0157dd88ebf9ac22ff54e77ece4f05a9bfc7327db8b84f9d92fd1e40a01e72143d7f039c3c13ab4fe255ffa052295d4aabeb15247e23f0a4e318e95eb99d26cb4fb67d46aee1e0bf512f539840eace4b992bdc76e5c7dd1dc9ab1954d7e35e6e814200090d87c92928e46cdcc56f4cb16c010a276852714196dd9a31bea9b5c88a85a4fc9fd3637abe78b581261189d31c8c19ad650109dc804f0c4676867d2cae003edaf0d95e1eeed007b29d9c7d9e6d48d55515f31b2aa752ab1e8d518bb04cbf06a44ac3ba9ac7266d59b3286fed795dc3e303a3d84e1d2ec56ce2ea8a3ddadfcec68e670f6efd0fff715b8e9d4dcae6dcc2b5241b6728c50b2289ae59597b49090c1e72485a94249eed9a466ef121f06c24fdb5f60d258bc61d5d72b1eb208dce3f221d8fc421cff1511ec84c7cfe345f9b69f4d67c9669c4c583e289ac15ed56e7c7516f5cf9f9dad9e05d1895c3199bf3e37459aae5fc98a7868a363f8b2f185ca078b5b0b4106063cd7cb35ba6d8196802d95ba09ec91e542034d0eef765cbfc55aa178b1df31f7a67a0f4702a342f698b5ff7785cf438ce952542f20818389b2aa71562b3731ac5f22527887dca6962373239e9d14025959303e1cdecc79cf6bce7c9d02664df0259a30d7d7c6ed07c2f33bbaacc64eb654458c8082ffdab92a08c609025b5dc0f22e4df647e5a06027c396c8e3d9ccab65bc27a132998f0692fdadddffeb1df14e21e7161a49292545bc5fbdb9e6b19155ed9117a67710e9757ec07d703efeb3b1f57a541570a33e8a88b1a7550848d50a6384f0d22a910a9ed918fa50d9946df651a1befcef0daad831b66e560262e10bb33cebc3d2eb30ff746907231d6667f1252dc9e420c7a1ba16bb45556d9b01b4477614e3972064fb113aa4303693471d6faf5a0bea858fdcfe641419433670487a792c6e1d24da4be4703370c6eaa0109456c15c1f2fcc3a058a3147d6338b54ab48a0a60747f37f4577308dd83030466ddc48a66d45bea01ab06a70105f026448a64e7800dabde3ef0402ff3e9dae8032a851c2ef3f3c06ad4e3447196a6220bdeb0755841939b6002c4dbcab7091293247bd067a911d8a1947d4833b3dd1624e19d065227e9a11a3021aac8153839dd53ddb672307b9e989aaaf8c6cf59ce98f829464e9b64ffb41a4812570ba365d942fa5b0ae29b7a90d4419cf2360e50ef81b3bdeedaabe922578d42eaba2f5b8365d0fcea4ace17ee40ffe41ae4699707397ddda1800f6ae2e8a5b71b3a40516bedea0928c71d2dd8e588e92b7f665c7e0a52a903558275768d0065ac7ad781133d09e1309edd6102fa3b9d36a7bbca884fcaa36eef511de5120e48cce5de66dbf7269e99e94b24a1701f5bae359acedfe8e85b7dbaaa87e0308a138fe7c54a9e0cc9dd4f0b9e996b5b2f38277e72439f44bce86819897a26996858b1ae23ef34287a05c5aa838a8422d1f1ada4ac668d0c81dd2922857fc62637e3493c14f6e6ff638654d0f0e03b74128b392c7c699eb354670601bcae08cb52cb643481e38ebeab200e2c7c7d00c8f2df2f6773a5c84610777bb74e42f23fb6f4269593828a9d69516ada90cb1b84496ac305a42f40c3f5cf122ec9d87f8b64d4d903ac0cd2310bfe0ad392e68efbcf74cfcb4fa6ad5777ce7caf927bb2d5103f0629befaff56e9dc41641fdf3f254b73f8805bb907edc7608045930089da7e4fedbcb555fdffbb061434d1689d59fa9119fb373b30384d0c11dfba2c7e2691d1d6f8297c9e00b3027045447e4ec6cb3c512f29661c8be26af53053682a60d2104e3ffa631e8143e8462a3811ddd3934b432761c4ab04fc3cadf0f1f8ee0a437583f013065f0b107a7c77d07d1abd278335071e7eeb790e06fd239f5f8d357ec6f41a91214e07316767a1af8b1c7dafa15917f52330e1e0edb2c8cb75e5e611c7b84e367c9715114e53de4d6aa61bf7d7ef66bc7f83622fc9aea305e1f281646c8d0b4f452b20fcd85222ee7ea34ebf7a1912c78c0b701c2ee818363b59e94a351b2ab67840f735ab6db715dd5b7448bbc5e568be25195e6d05ae1060fc95b63e7aa3417ccd3e2edd6ef0a307f6d083861e986267ca2eec8a7750a530f91b01a0a3ea91bb87b0c6a10872b44a10b5d7b3100582e6d534a20aa14648850bb48a8e8c2ac299ea3f50c56f413ab266ca6a140e92339f0acb5bd77b0863c16bf065f7f3cf85f139b7322b0d9401b33fccddf50bc7193011c2b2e0b09a7cfd496b86ea9a6df066f6707e945d5811667f28cd8eedef2fcdd8fbb0e67aa0ff6190e019769fcd745c0dccd5b402dade0e0644e509076f49084034dbea0d1c7fb18600cc4d755b566ccc10f4e888b6c99b20e2e3ef0447b087c0b2894c2cb74953e8ea0798c11f50e0e22a2e325a7ac5e1776ee261384547f31665efd2306b638e847ec78499bca069d32e6aa633031efa6942f1425f6f5464080682a0051f374784525d5679aaf73c5260e1fbf2f8892e9d884c0530a0c3ebade73e4912d7066a4fa1269e05d3145218b8beece749f0a114a78d122d60ecad11922c62a01d7e73e9310f30c27b13472c217474870a43d5271bcfb89a8a279b665e643c3e781b415471337627fbe5206ac49c9b154e60bb7e1d50644d769216d8386d0fb55865bb127dc9b20bb7db9bfbdda6be7dc4d1f077e6e46fffe3cd62df49f2e38807c65bcf7b8d0798f2afb0edcc1bf9e98f17548f3f125ef329fb69e169ceb99ed6e60789846c8b6bd1a6a9e374fab3db8375a01c3f8a4b489fafeb615faf4e9ce918f71cac85481126d6f3a10ba773dd4d89231264fc3b093d317cbe1a2a929fbeab87c8d977088244e6e491e8a469a1f4d0e3a37a8dbf7e0711189552b264b3d771f518f896c1e1b256691b2989a654550a28131d7b2040fb5583ec939775252569ce152b625327a4d71934cf91fdb6c0e203725df98fae79a29c1933d3f5487cfdedb8ffa04de3168c220efe529f68421ebebd29ada2c1f6b0ae8d08e48fe60f1cf285aedbf3d0b2d0215a563af5ce19d16eb1d11e82d6802fc854d146bedb3d209bbeb81ee62fe53e51f7839d005504e6c8f5441a4d0eccdfbad86f46765d8003d863095c5ecebfd71c86cde0b996da39c071808141c6e00aedcb6569e01f64f6902808c2c216a594db3778a82e58e95ea9900bdd46da1920c2ed027ca536a2f101dec65870cdafa3ace67429716af6b9c9712306bd7b44d033846c96946c8dd138f7d6402f2466dc66c5868e432b28cfb291a1f75d4604dc89f40c3e12d8e2ce5e4b86b52334ef12fc03b076d015543371b37573142fa102a8e21e445d9a2eb1a7c03c3bd9e3dd739ed769d8aaf41b425aca53e1688874ecd474516fa801e0611170e3930389cb88ce60fd0a85f8094b7a10f943f87417d150a3ff123d8c18d0f5a0c08888183f5c286729e7b4e6c33d1fa617c2e3967b7698989c744a6e19ad78ce4c4d91041389809e90e82fd5d491c91965768b54f9fe5101e9f9c52addacb2473e072cd937cb07c9b7c7ca6ea1bdd187f0a031eab9b119db98ce09d6f873ac32f3fcd101f2360b67544ff7fa4e11b07f3be27f4891feb0af038a88bb9f75d47b2523587d48a3097439f5358fb40a33c57590fb7464a92216e40b8e287b94530b5b0cac06743590f9f6c0a3c841dbe747da2ce27498656a5cd1ac0d4cadc9a9a5296c66ff5b56c592bfcd4cbb2fe54792fc131380fab8398d1ad73415e65f8ffb826fe0b07b18c8e305c8500feac0ec3186c92faa3e12c3d36692b59fd1390f1f5522c2131d25770e9d736d1c359b906e7161f06d8cf25562ef4950508a278ab07298c410e86bb2a8855a645b26e7d938b0f3f008aab8a3a58ce5911a24a150209b527daa1f55c3456587399a3f8f4b3f46bd07883c1538c0c3e4c664bbe897b836563e13d7f0dd3f2a92cda270b56663b8370c30fec0adc98009ee5675d38b148a0123956ec007082c4e5f9f8d4325a9ab433bdc49e5d6db32ed30b6156e24001d8d3f7256b571f530386a1a83717dc6e08a571eea97d6ef0972ec477b0d5872b082724ddab3252230cb6f4f225ad63a62e78f8a15429aa4f46df0e8bbc8df04c9033b36d2e55c36e418ca75b65dcc3c5c534f6d4fcb0f52369e1eb265401915e509ca583c7b20873d1c3831c858d4e7d689f9cf357f5b4ddeb6008f4a973a23766d259677652a9c7b773c99b46f52a2ca2281baa0c3f87209f9c6ddbea8fdc20f76c4517dac3cf313fb66eaf5e59f74920ce840588d0cafd22a154955876071290b20e8d0beaac7e898563295204f8bed979a3b756b7749574328aab9068b057aad6878fb076b51ffb9675a7649e93b02552d32d1028517128923e367b6e50dbd9335904ce9a4756700b2f89bc8c6684f5083684446f4e8a16432165ee831f9aae129dc4506cc7dbb922ae552cde870b849fd2617298002a8968b7ac267b199e8d78a1db64defb581a3056fe7360ce32215bd3e8c5b908e79cf53cd06af2f0cc30be6bb147655922799d1135cfefb81accca01acf41e0fdb9436fd0597a7ee5e86d4d40a7c1dc914bac0da0b5c51e8cdb1b90287a2aec8e8ffcb7336aeae6443c818ba6558a2ef6c57acad5d5247cfd9edf23ffa54bc69f99a7093594e85a521305e28174e438716c6729e24328909f500d41f4988f60ec23d22f5da93ed2552dcd26893e6900c57377cd965b2276c62c132ec3b4999c2206c17a80805c1c9617bfdd98208abcd2b0e1ca5776cef532e87c66252dcd789950cd1f12d3ddc4cc51e57e3a96fb139b3d4fd9fb7385a94309182937bf2eca2b31dcfc0e6a1314678f1045bc6ffe050dbea06809ca84b04fa0f758702280fccdd165f44de9304edcdf8173253688ec695fa42f844223ed500580cb490243093729d75c5fa6ec330b7d966cd1a78f1df3ec1c4f481e72371b079021dff544f771a66df32b63cce95676139dda6a32f87a96832535663fd20566ad7eeecb646fd9d36ef75e0280e2defca5fd7d0fc79252646b4782642c18fff7d0935f96d39d2dd1283078cde019f4d996426c82d580edc62c21618380c8a2c0cd3138cfea3d869a1702dddc2cb6fc88465bd0c4a659bfb1589a1d8f0efd92e937aab34a9de170c5a36be78f22ee1fafd09a974ddd8c71475749bbd1b8a9a406a463c45b19a4cfdcd9c49663ae7ca5c113f0fe49359eed863dcd5afe10c0bdf7f8ef87637ea43815cbfa4272b7604a488827556c2bf1f644accd1c21d19269e088c1e41f0e3377ebec0ea3f0b8deab4bce9e8d174acce76f56ecd0f7c742b0a3fe8c134b2e38d4c98985ec2fc7404f83403e73fe1526b46be24f2dc28bc948779c4f61557b98e4dba195dc732906d04a3e43bb98c266f81d890fba3a7c13e692b1ec410e397c5a15b38b089ba49dcb6831370d00db2d8dd64cd10ae20b09ba017f07f19acbecea3a0faab5e8727c43d626a522c6651fdb546481968b7dd05c8b55b437a749f39e186edf5db98b2503e22e8fe25bc03d11ecb07061a51b652f41840821345e73cc4745c133e7e2647d7d43bf3da9d8dd0a50fb74df9353e573566b880625d515e1b54f8b6b52b588eb59638f2f3158431ba4d5a46b51dbbd8199f53a5946a902a17297af803d050be3512f273f6eeefcbc8f52228c52ad8c2dccc9835e3d8fcedcfba1292e05259cca1e7f7918fedbad2d178f7a470a26be5b429e024833917bf451a7f2f572c4bb8ddd7e9020ce16562563836e887486fa753cdb00f53843e534f38ebb55ffc36f4e7ecedf44de69deec85b265994ae9a687ed38273f79f919e880f007fa1ec01c2dcb29da457151f6d0c5873514202a49486455bce9727793a833a53fa8805dc18cbf8dbb57f9e7ad6971b82e593d7d42e7c074a67c170b14491e2c499c7539906f36d1c080ca2714b404c7e0725f578c0adff004885e76635b83686f1c9d1ac5388caef07ea917a4357a5ed832d009120611b7052002bb367f6350eefce6fe36ad9c99f75d4d485721c9206054d45a61080915d577b9d5d73f91a9f12af2a98106a9abe813cc714892abdcbc659197cc23f8fcb33b5ec18252d2d58850114dd39111e33f220ccb82cd0e4439ff41787e4e4ae31846a3a75ba76639330a0d688d7403ae995e3ed18914492ae654f1a0fb8b0cd25388a3a5c877e3b35ef8d52ace82f8463edaa202c054b3557da1c86324ccd35765a855bd50596351ac3d1ac50f332e4c7a144e4c402a31ad27cdcfa183489914b5c2b4dbdcb056a222ecc08d38765bc22619007e4b44332be469b0c39b5c1b88474e42d69cee538d35ebb1c55227553c5e1ef6dcc75bde097bfdb84051be94c1e01f33686e53a4cd43b7c03510cba28d86274316b023695e5b18428656f1ec9da82a0d2209b0210610426a83b30ab85cf79401e717ad99e80b051305f8cc8dbd3b2cf8350283b8c872fc2eafac94ef05809b2050a07e15036aca3fab318773859d0cbe0f5ecbcbf789494f33b4fbf59164f81a55aac9acda674df8b5e71c4f18c823acda94838cac02e387929165a70661e1bca068cdd52e98039b678b0031d581c4c73d94b2e869126b77c8b8603755df79f697c36b76978e7f9a8070a543fdafef17b7fdecabd5fec046447213e0a14d2ad8678c750ae3dcd30f3f96ea8cf7e46fcefef7f6e5dab75038326c01dd0dc792f56b2ffbf9a267796820de3c5817964e2b16c267c4b94ff5be2d8e93b0188a8058b7ed60d3cec0233d80ea20b76a12ae9f3feedd49e834ea0028ad477fe8e4829b6f9cdc802401aa26e6d591a5e4b199ba2e8f00cccac08836721afc722a7852d12752f784989d3f3c8265667f845a3a7f14ababab043949a13e0196a55c9f25876bdce66be91bcf4842a33fc084bb24f2d939dca004021652f6da963d7a125138ff6bfbc2608087e82b15891d3de6389a7b812e13573ee23327b3a56d3197483e4d5ab72cb6d5d3040bf34c68c1871923b596540460e58c41a869dc52dbdca252a4a44a295e5ad6a2996cdc41c0ba0b1e04c870767173c53a8033e49bc33239e4ffd9250ae43560b7118c1d7dc1a246e2a5b9bb72d6a8eef501e46d68153c7282f4a7e11d66505a8314de7d38418fefb9a3f432af722019c3fe5c6f20565100e287546ec0fb290f3da4d038bc179a58f74f233585d26305e79dbf0b912042c5be2f899dd171486e7095dc6f35e12520d36b3204889235bd1bb7f6f899fc554da76c80f7670b256270b6eed34b9e9163ccdd1e2c263e7a80d5612094e885f70cc67a16b2a4fbb63f15849ea79ddf48690d4117d27458136f4df68b647813cede0ffe00a303d4e68d94c2170baa1c6d0e1fb4ac204b3f2238e3cc7899902440a99bfe95ec0852918c4f21f94d1f5d40351c2195500ffdbf54717de0cde06ac26dbe84a3e037724e32f65d4820e7ccecbe830fa87885358704fd00a740007222f4876cdd4f8ce8999fc9e5ed5b3f5c8046f688ae127e3679d27eddfbae1fc1b9c191c17473bf94d75e23e091cfd89fc80ed1d9893548a2da97401021ed10d80f813a418140c905e82bd0f37fd364047741151b0b6d1443c8e6d145895e6b3d51ccbfe98f97e20a67ffadc44c9870e55fe9d50b6afce10dc52932c8a17345de65a312c5edafb15541c6bfeae19feaa62e6f074a7acf2d37c374f0b87cd7859a03e0f08cc57591c732acb3e5214853ccee98ac0d8f4ebb9eaef5d2cae862e2c5813a25e73f63567b1007b7b2d321901c91113b51d333ef692092d7c22748dc9f827788fda69d5751a5ebfa68e0588d940a7b447b5701c6c8a48f903e2f14fb1d4873ee1c02cdc27adb4ae913f27998e25c22e04d39210aba1e8d5694a5eff159c9d5348a62e4b10106fc0ed188bb4aaba01c5591a7dc15c6d98cec77b80e1bed1786747d60715627793f9e0a80de2e505dd0b000b2cd451c1594ae8f6182d82caa0234aa1f0c66737dfa25b2016b7df91057b045f69180ce393a670cf20897d5e5d9dc014b700dfa7bdf07a344e2cef9d6867818afd7aa636b413545c8339f31ca5d19fe6b2e8ecc0145b4a5444fd77dd564f963f4f1e0f45c088fa6473dfdeba653447b22c577cee686e5d4df8297754d65795b1fb14b5f4b1000a80bce936502aabb1ffb5ebdad814e028e8d8461668e0fb96aec5d3336d280f099da47dc7c29a4b9c371cc401da8c23d5462ffd1e3cdb224a6d45c9381dca8082b7751eba1c503eb1621baa739cbc779852d9d73b5b9be7aff4a11e95038231b1f29ef81a3499ff5160a1e49c23fb88e1f8f5a89184d9a087c0c5ebab5e252e6daee2a57bc660d739740cb7b755a80993cf3ba056e85f1e608b697a55a9fd0370f9ed6eb7759266a2dbef56148e9ae5f262797492a126ec613cb2a922cb20dc3e383539fbb140751aec327ebaed3a670f4344b5002371c3f108b0df75ac2cff5a1f3a84eb04f9d1ee7393eee23c9e7c2fd5914a657c19f0e55c87c81bca5f0e492328af84da73400aa2e331188509d75035ee8279d15ab5b3085241b8397151d8186e8d78a6a35c2068c5966cb14b2227fe7d3230382c77373067d8a7b9722b96daaaa8bdfec74086da764ed14e3cca927d49cea740740ce2be1d8272d9df328e54852b2fa739a8ea0043989fee207f9d137581422b9cc0dd94d0c6b42227e0919e6177e47720c9dffe6bb5f449daec1f1083d10e79efb2b76f97c558b3a2a949d7c988155bbd81c6e95d7ad0c0a58dabf18d551ddad942884b482f98c443b97ca976f236afd03a1bed1231daceafc9c4255ba20a0fcec057da803c8dce48f89d4e70c474786774c413bda8092c8659d45ff613e07417de6449076e5cbae3f7f17ddc4be5a64d7017592f915905da6d858addc4ea27660f5afeb33b57958a05384dcb52200c787caf2981f52d0ab2b5b014b9e73a0d635fe467c02d8b88af43d2636cb40c59de05be1026dfd97f8b180b4bd2cf7f3246daaf68fbf8725ca605c6b55e1b4ff4de7b08b34b3773fdbc40e36893d7dfc43dfa9033a3f26981365d1a2806f7365b4867d83208b16d2e8aecaf6251b9c988a31fc09e8f93970ce909c4dae8bc1bff691a7b9656e73d42fa270731d562c3189560ed8b3f5a07a47ca3c5421d60425960265b92514d530264bd9be60cf0df55a69aab6b7112c93b9885e8fca6f08b9806fe324c8e30615d4ed7908d0d369394ff0757f23f49742e6a8c80f8cbc12eac380eb7b539925ff830d0d59a384e0de84ba346f4f5bf6533f8bbd4a57a2124cd03d3a5e22cbf8f0943521d25f106f72ed826a1a21e6e7eda46cae5e3d0851e08bfdf92e50afb9b038a8577f87345211c1d9fb6c5b32760569489e1a09856263aad81f4e2ebd97394c8fc4c498c7eab877378e5438c02216e3c845e76617bf54df33d854265347ddb643766f6323e5a7bb38693c2d9ac0aa9aded9be4cbcf5e7637af211675236ff646528f3ff45df438f643a5d4fcea14a050807e92b3ef8188e0e282445b851eaf69cc4ab98ab0befb0252451b330792ab2fde9f726f2401e0fb9fd20fb4bec345b5abb5f0571830eed1b5f9cd8a9130d73e50550fc2d62e1f17067db0ca54eab3f957614989561b8b6f93f87476ee9f2b4bd70b0856f45f0f30c3e2bcb0dd9ef1ffdec2633c20a47e1c7ebdfbc8e07f74f8f7f44e9b050aee642ac2fc24ca85cb5f3aba58d3f8641226cbc2e65ae12ccb070644b6b9ca6be7d9ac6eb523ec37d4dc78191b146a76a51a7808138851a3189eb07baee639a8a817feee3651db51d4cc472963bf4db6a4eb4689c056f9e348a7612d2cfa1a8a04f33faa962849992e868874c65c07eed2ef4075820ea47bee9850c9f2c134aff4e22adfc0c62617f684ef9b2ac74fe8d61f8e75215f13ba7ab5d6a8d6014f255f259a048faec9408654a0c65dc9ab8fce48f5c9ddfbccc3713ec270e63f5a0079f0e9bd65a6ede7f9caf20e42ff65ffe2fc77e47b17f173492331f44302829f31e827db0aec189db8d2973c6eb532b4d3833595f0561a761641aba4f08ae477b71ca447e7cd7d7a58c1e4429760034f96fbc2199af32cb1a8cf9f8bba627c27844c74bddcc58366cb23fd906746172b2bfcf164f39c384593364d5455500ba1841550c05b7e922133f2e1c22ea80bb9b7a579337c74f6d08104b247bab82f74598f0551aff0b831f7f0c67cfc2c0e812428e92b5585d67db0ecb6166c79966d7fc1fdb780577f70cb127b4b2deccdc37e3246bcbf3d893caaa52c260b13c12428971b7dd452311ae10a5fc403814750759008a9d263244c9f5f403b09ca1e840596ace9c59206161f1eb65c0936b877ec56bee6c6d107aef566fdbd2d877cb07b2db269d9d0abc45332569b9a558c00fa18bfe8b8ca1ff4579c5c88ee5c929feb0b4e734fe3d7b93227f39584ef4733632d734687ec043281ed0fa4a96a895b7125e7a08f834f271e25e8fe4e824551dacfdd1a9785af97518d320ccbacb5fff125428bbda03a1f6a17d2729c1fab6939a490e458cda6202028e1dfdcfb827bc3da93506e59163aa09a4d675687852a14704f915e90b76dfbb7993e6ed0e4b391d624808b6c6e273d896e78155989c20dbc20e03e2255a58cb3995091009e02664e410f6ef4c85620018482881b1239416752d1c16e9572c701c7cbdafde0154b37d6edc268c875df382efeeba240f0ebf0b9a3d6990ed3a2efda2ee67d465b35fa7016117cdeb0eed18d73f466f3db6efcc2cdaa79c4f3c7c48099d563430e091c490d4c26827faa3496f5755cfaf54d546191753aa8baf91129e95eb36f555ffa285fe633a57845bcbcae9211a5a61308860a9a0d86a5a8e8cc209e84a546e79c8c163c47431aad5429e229c827393f99699e3eb74e36be71cc24e1b38cd65ed5a1a5d1e7f65979145cf766debb384fd2beeceb35af998d340ba4a6f70a6c60870b78c930be382830ec09866ed442a880c586d3b2926619db208fa07b30ab32622d8b2dd402952b8b58c15c9c568b938ecc65751d3cc947bfa97706c1742ac5a01d5f8af7237b2e143aea861a3ea4cfe042c6777b40eea3658556d241d4aa1bd5e1ebce6c11dedbf58691ab32abb330ab0cba88d322c6c7da346b4dba9ba9caade8cc4c02bd43f08ba89f65128841d8bb8ea19b04fd919e56706d0d746797cc9e78e035b0e0b98ed44f0fa92d979b0bd2944c76119cbf2b013d57513cf55917bdd6729ccce4bf899c36d4a8eb2dfd63f94dd00bd70c271b6d666a0b34fbcc901df0bbae4b45b5cb237d9ebcf370c2b30df3f1ac9f85ca78e1cfd9297b6bf889c5066c0c3d57e00149a97d742c7bac261bd32712cc66137889f963ec70a318c1f8a41c3a64797fe598cc0eec5ebd2246de12add8e20149324c030a14611ce8dfc395e60d8b8f978974d04d81e7e0b5d50d1bfdeae3c2fff0e650b0de3ebe4dfa912c26f5a326949abcd318e6a80d4060e5188c6abbe57f0d6752bcac0af44c03d255c57ec726ca0b1068d61bc2eb3f819c6bba78ed8adce5a99b4095fd263ac26dc727c2c2227c94c4ed3e3bd532eeb617fb747bf7d64356fbcd29ce1aec243a36a27f89f206fdda20e0932e5f2526c08fe50120a6741db5c266dd03e53a58157960368d2fb9584c4590aa8635e02a784b18e6c8cd6f4be3d0a809ba9577e213c6111e3f8550c7d569439fe4d8cd8ca2ffa3948ccca0c9b19e5311b78b4dc6a46a8a9c9edb3744c0f08ae23d4f5941753809e1c3d5b6fdc03cf4a50dac4f953fc55718ead7c59055234ce67014ea2cc5ba158d6c4e6ad451f2f4c5271c36011caf04bd030fde81a11ae53116a9a426ea0191677cb282a1834ca9dd22e32a28bf04ef2bc6b584aab1db55a039d2adecda25a718b10fde7f744ac856e56eaa3eaf465fd88e71a9f41c26f35ac32ece64fcb239653e01b945bc1e5b0fa6ca0c53cfe686b606a010f92a4ea65872bbaef2a47cf9b794895e31f91489bb3124ad69383b66491e60a33abe19a92d9378c7f3d688748e848bf728efdd18effd42ae41dfcffc59f98c66c759e208975658ba49137c238948576154d8968db1402e160331cc765576eb8f6dd5784833970e069fb452966dcdb7aad3b98e5f8c730be8a2311e807534ed0d508987addea7d8b51d6e1329bd7976896f2eee1c54722db8bfc635a9f07a637d40cc81185cd25fa695a08462ef55429e08ad21f033a638eacbab7b77edb2a177c0d746576c40e22f41cfe0cfe4fdcc9f4021b06c340767cd4abd882fc9d26d6e895e431ffd5987906a7342eed68359d4175cc6536b1f2864e3e131be49f50e8dd3107b9a65703960b5579bd1eff61671bbb0e72380dda9dfe18874f1d20d119d70ec570deb3879575f7bbdca6bda3d85534c964b95f94aa7e638778d1b9132883725921a1584790c8a621ea98dfd7a73f5fc21d1df52e07968f9a3db703264a3b778d537855cca1533738416478768b679403b2e80b9c6669c6a962392392ede68b7d49bef2bb2b9c8552ca55d5ef9f8f3482fc0e54746d0efef18f4ad7e05df6798e886e239bc657c16ecd848e11caa4eb799bd35d3dea8d68a3cdb8de17ff805765b366b9c67617978c6f9f9c53441c3643c48fd5f081524f04945587eb57c2ae6ae17aee1e1ef213ffc8349a383f421989b04e4bcffca87e62b18839cff6342b5df1c486aded58253130d9355851755e1059420db76c0d24c89ede19757b27d0e4abd1bb9902ad9d4605479029bd25e7fc55edd3280e8596cd8f3164e1376fdeaf6f4bb1766f87b502ff58856b13d2ae0a3a384c899183f611b82a81d3f48439ae02087d1eaed1657c6b595287419280ad87a4231e144709deb39b5b2bee1f163f6c7cc72202e076cee2dfd958b2c5f4b52a00161e3b802ff48064176a0cafa1e1cc247b01ec6d753635a45373314380e5689265b02653a2d0e131c209d6bb124a06e64fd0dc8aabba4292259c4bff87c2efd6c051e29cb963de012d449f563adfbdd7bdd534f5a64668e95455aabf7094a0646bfa27e6f4d8f28616dfc04a38166cdb302b74ac1331beb73a0340e4492577e638f5b883b1f1f5dd6b98a5ca56c1bb92ea93a5fab08ac82b8679d83aebc2e6e2136730a51bd3dddec7877be936637c74b182656e5879db81d96eddace4f06b47f01b416a2e7d8d813105fb1afcd8b595e312d67237c9ea874cafab63fb07ec4b226d2ca460be0ff2cf25cdf63b4fc1b66d6c16b7122305f51dea1d8324851a925127d0253c4ec89ff4c999d7533df9cbf4135e45ed3386ca73fcb95617dea49851e26ccf1a549d9f81b13209ba45a6e6f6f0b2deb6cd47e6499469bf47eeb7dc7d61dcddafc9e13e61aab0f20c8fd870f0f658809c5a4ee49b24b81c3d4d6120fde71449a80551b18fa6cfc5a3375b6420848a9f1f049912ef215f48afaa97944a9a4e2cbb84e41f58d406b783e6d4907f33f10528412d768d8885e89bca05adede6a422aa2e08291f4500ac5158044c5c57a1ea9d8bf323249a58523c17105accad3ebdde949b4b89c19f3f7df7733e333e94bc161793fa44aa2289b60d1a3ff98d9886f7d1536417bb528463cb55de19a23946ef0c7f8994d54a38c7509fc9a7695102c59e52ff1bd86ec4ac3b1702ee1f935b38d2dc7d0a1db53594be9b5372da8b5a137d8af4cd369babaf6a638b277c3dde0331cdb7934ce96b9f1ca1a8302a024826512c726bf4a8e73b926e1bc855460b7754c47387c3a2a467f896b47301e80b743d1bbb5beb38de7c823f45db3aeeb7e1c379973985464814b52ab4b3a8775b24f3596d7dee7085d586ce267cdf985410733bb7a356ce34b069e6535e08d04ca696e01cfcb3b86d33a7f70fc8d548592448fac239ea83ce4de6fea04fa23d8d38ba98cfe366a1ae3fe7f200322d719653a8e7d4dddd6938e1ce4a66402febcd03dcba10c48c423f82d4ec9a2c737962e5be2bef7a0899715005652fcdcf529aea8bbf5238b9ee4e1c53556507f0643a1a9f01c3d510ee215d3518c302eee940e5e1a0ef351efca9e9c4439836c954e3b723b36859062249e66d64e96ed8ed316b64d3aef3f4e2d934ad114e680ea1d1091815d5673ad3e23d0f3781b4f69a7cf56438c2e9f93a29d01844689884729021300b8883604a2d97860779c6f125443d11a55f1a6bff9ce73baef69481f08f66398dcf41cea1c2d2aec7402d490f71af427d15862738c95bd8c9edde36d3301d54f33419e44fdfa9301c54e23f846f5d5a94d03814e12d1c74d1a85b61844bddf28c60986a87e3eb0775e288025665e30d952e8b100e1c3b3e54ef1c6acf20955b861fa5baedb3582d80c488636e309e6dbe95f334da443d83bc8d42c610a733f91a3cf1784f090b44155c39656f1d15039f74cf8c1e257b6dd89884baffc563c7fce8ae7df4b315885f3adb92d5af4eacf336ba275420824e26462e6af57d8c55698e9f1ea0492e4f5852025fa69fbb9011bd652f2554fd0d5801188303b9c4919f98701e8d99342226f9f1993d78202719546810a2ca87e3a4e7f57f88ac4371bc22e270b6df3b99f57abfddcd028125548410e9260e5a3e33d12c21b0184a65953bf4de6befa0a039bdb1a078bc0036c547558af6420a79e57530643cf70638cfdc5c36f6f7a5ac33da473b6c8f66aea5f2fdde353b1e7a95104e07ecdf35d1a66b96ca53e7f050c3e187684a03d2f754b29c07f6ded5ad9451f81c41d32fde6c9e01e5c51363ced97157cd58ddf92578bdc8d43f214e6e7fbaa1bccd579730b39ab7db66b1baae902935ceae1e60940efaae2855caf0d446d70d75a58ae803019af90dc0839a1ba6f4cf75d0d8adb1e1fdca4121fd5789e75c2f4d1133374d3a24c202b11d6666b4d2f089c6a24fe9585a8db899691b68c7cafcfb7171c402840d548ac42d14ab9d26c6533266a17035ef9d41d356bd678d1174af5e66c9985fd895a3cdf89d52b063c95b2218bc50a8db47f557ce13f70188c7241e15eecabedeef31e500c217d51c0636d87909dd34e79afd171ed44d462592ba106510c2dd79d3cdba83878872418d77ae930da0ff42df47f5a1cce59d454b4129161de201d292d09181fd18be010de18bd09e97da1cef6480480d1d6343db36e86fea147fe6013c2b5d5ce2a2afb8c3c5316386785999cb51fb95797e7c4bd83b92ce9d42750dedb10b3eb2b07207578ff15aeb6fd1f6c51b15cf22a5409a221b2194ce103198ece25b8ccd2113b4f16fdbd9fd9a06c14920f89fc624b78c6348ba8f2ea5e50c5d106e56719ebb6061c4b8696bd94698c15e902f7520e7000d279acf2e8ed93dc4062217fd0e0e4f512114c7efea979bd35edd61613ccca0e205961fed996403cc319e0e294f8126fa61181093aa4c208f58493cc2a42f88eff72a880a62cb903600ac6744be7fae2b726e03ee8c5beac5397c4de1d9dec5fa4f22e25e8574029c56cbb2083f7937d458b9515fe2e39bae91acab8283e12ff09c6a42d4300ccdecd679c575f35e4fa35ee5b5765e8a2f6dc71af8ccdda356dfc6fb73fa558308f4452fb3f916f7dde063e119c76a30f492eeb3ffe81aa6a622e26bbff866443089cd4302ea76872a67779a1135eb1d91c206c5b51e987d1d528ea2a70cacbea4423edd65847c80c69bbabd3f61c8af1028bb518e2cdacdd4bca54817b86936be09d91e5fa4013387a77e308ad339c88936c6487caed3c5f830738386be792fca62586ea2cd7d65feaf67d5b787e19010840945fad40498bcdb6cd44f7180648ef7c521de73f87fde30a6a36a5659a982ead4dd91cfd70d419723cf9d2878e4f9e7b649dd97c15ccbc4895f3e49ceead1b52761d417ab73712bcdafeea2bbe1fa5c446a7d2599b003ca57d374b337771c9c5bb0f66e518b6b9c7cc673475d2b72626cf4cefc3b325bfc725d0df99345852b890e47840828b5dbdfd14aabeb1c52b3c15715b85eab49c92c8e07f96a4d2766916af152c3cc3d669cc4cacc09bc57dc189c1a19d12e381d9845fea123268cea73ab62bdf6ceabb51284ac84ef41a315b8797767f3dc588a640e0eb5527a75a11fda51fd32c38747e945203c873f8de57086cfc327bbe99bc4fa015c7ce3e3ab0530932b93238be7c75b1e77a3319cc85908e47172ed69148f52423346f10c4c2ccce90504b9c6927c3622ae608da329f51aa3ea540b464c74258945f6d6ccce628c77594f7e44ff07498e29d8fd54bd86f77af9093531f85462c6ea6f04027ea985ae1ae0db02327a1f0bf0e0f16d6e456d3bef5270f6ff0390253dc7fb4530764761c1751358c14f85fd322b6194aa67fd12ab2068d8efaa8d0ee458e5f7772f365c88f78e4926601318947096449250350e224c402af2cba5854c692dae3b93a7dc80f887e1e5169a3882c5e5daaa8e05d092c601627cc349bd10f6e4e617e221cf5e2026544b962d821b69c47d139f75a65e1af89f309d52a8a3b0ff2e39a25247bc6566dd2589d3b9669003c2aaae9041ea7f19a1bb92cd42c1e3d1c753806c0bc2e367bcf13108629a4412352f1fd2a28e5e6191de0d14f19f5729f8496ab67d9b066cb69b782818cbadebd60aca3a26440d17f35631bb581ff272053965e4148dfc6e15811bae26584272a755cca23bba1377a20bd35ae07de440c46351f55fe06818668a30059bed40d20ea2aec936bfea950a1de2fdbfbee5d1bd8ec833f97621abbb890761a65361da83de09efcf14bb07ea352ce18ffe4b50323d61e08758c7863ad6ef00bdc71c91d63c6bafd99f921538beac9662332d3cc7e766b3c470b1d31980027a115b8ee4ab0930fb73da71d75ad9d9918a83e2ccd35c0a9f7600878277af59c5e52ba80852c80f2d920fde46f412ea4ff3dfb0cc6e8a5008a7dd5dc4124e2731aa06030436f16d7fe7abf6c3f6fac57ebc7297f96c3251f9810fbd94ae7674d551ee5018afc32f53d7b4314d376eec62d6d49323c20c2a4391c8ffbd02d9879130402d70d51e0aca0a3a086f929a265a89e8b091929505057c8664cb755e4da926839cc2149c6dbb6d412bed24cabc72f9371f632b6eb26653442df3808db19811b2d60003121460ffa0412c878c03d40f21135ae46027e5bc889fe537de8d5b5332d8a40535e8ce16a8d59e839da2ddba1f888803141676b86a0c899702c087d7b5a7b28dd3e2a5d4f98da5eba1a64854ead33ef745aede5cbab6a45f7aced600f44d0a80044d949932d9af53432e54ba33e66db11aed9be41ff1d7dfd9db4dcb79531a845c6635666f1f740a837f2876f07d098f413420a87e6788fa97046e8507620bdafd534e0e345ddc95a92c0b2b01a717930292f3e1ba1eb9e2576f0157919fb1706d781db2205b3c059e9888e799c81224c5526e31cd2885d6c25866c76d0c5a3f9bfdc1e7f78169ea15f38928d37415c26970253676de8eb33ebb62dc44336680392d1078daeff8c85ff0537f9ed7f4edeb8e8ed8d70c447ef5477c643e79bae8407d1fe45585827888b67064c2a74dc40359a35c40c7c660d97def845cf0c122316c3aad26aa13f912066cbab369c865430d4db8ebb23af30ef8ba1287aa881899cbb13e040731b22f3ff3a27850680641e2d96bb9ccc4bc5dc5ec6e08255c1becb6025d81158d4c487df3827dd28a4c18033a5acc42ebecdc8c35c157edf9d8e040b932cf563fef43425f9816e7702deaff1703382d869e554f67d6a0eb6eba17dcd2d630ae60a7599a0e8f86855873753f0e9289a812098559fe08b69db10361f3704b8e3c5f2cf21a7042d98cb04fb71b56bd465382cd840cc72ea1752ce37d16773ae340a1ee8e5503eec633c5dfbe98521b84cd32a10af8ad0c486505fb5db3028e77eb5033e26ab1d35c6b3902055d5bd5908921464f37ff61d0431f97742cdf8e584e58fd9c6a0f05368d26eae4f5c21a638e5119ababac981c42ebb675e71914d591b150a4583a7f90595faa0f9ee1f1570c0b855cf008df821a3bfadc328a10e986ac68c9d7d99bac9b23f09c9338bfb042cbf503c6568128b7ceb4e1a41c7a6427830eed07787a58c5f9bd5031ce205d44c3fe0e0f3ed1551cc0bec648cf10a6cc25644817e98aec4a5f37a965ad58d40a35ebeb38119e4b08705b42160c00cc6e8ecb0051e8d81d2c8d8897aa09f3101a17553bd4637007b000d78947fe94043b2e81c994bef07a4d9d302325fcbd34fd1a9e64eba91b4a630dd6e4272f3a8f792d3b8a3953fee9b000b38565d7d5b33ef523c0d8f2dbdda9c368af819adf2601149d33d48c1690e754b85cea41ae8c33b410a769d7c5d98d75d2a7d75280f6ad2bbba5a5b8f8bc0335ef0c6da524feaeba26b18fc453b71e6e0d1851391d7cbcb0a4736dd55246ff8a52cc8fc0a4b022b4982c945d5133a461e600d82b98bb8565383335befd078cdcff6aac0f4ebbda71057c3a1dd43e05d134b5ea3f82dbc479d5a10d2bb2b37510d26cbd20f73b6484640ee14bce97ba92ea02e570195506d9b34604319d23cc1224dfb0964af155b03ff750cfe834b4aa84c164b6d36939c2f37f1b32d0f845ac420ce20e9869fbeb900c9f9fb65fd5d8b68f6d0a8fd9d6d4f675603a8be170a4d0ed12889597467f5e346aae25165d002b55b55b5c7ab0e44c9bdd1fd699556c10daab12b046ae74934193f1eddfd39257a1449a131108f8bf41e0a0c587795cb2c170a59d9618501f2168e395a7ef093138dc510c6ef7b73fd6e61a2bf70025b02dbc24b5ae857cc696d6469edaeb9f026e84bf73677053437240992bfc21d238c29178c10232f7e87352c553ee38e46a419cfcce0f5f2a9a08f0096f2c54678f6e4a074f6bc3ddb44e6e58f9bfa2e4ededcdce47b6be8d397dbc52886d73ddb17c67226f269d41e961929b2cca200afcd29ff3b0dba1233e931288513685e2ecf0bb71be333cd876a877ed2b65be0780a5d54117d1838a566a223adc7f76c53caa9877021e67d9be47f14824464ee76ff43e7082033abf0f81c917cd529df8c4c16863d64b194006aab7d1a0360771dd4b7d02a5ac177af6d2fadbea4d80cb6742bb5d7ccd887c0f41733b74fd2140fef0f8c563e238fb2cc01ce663a45764c83dfe658f4761c2ea535e714b2ef00c86a97227ca07a73bd5a802987ede6d9b96ab761ee4d71b312d87b0a8323ce8935bd9538424484b0c685cb254220f21a44705a969ae557bffd1b65ce5db52774c376acdebcd7e2f8e17884c1d63a55b74e39488d5b2a4321395c70dc514544b3834fd141b06793179f2d54834b52d4ee16a65f8dc5d9dba3fb4c83f9efed1320e5f44192bd6e74b261cb6f7c735c0e3ecf0be617b399196013e37e204d73a20721d768ea39004968b32cfbcc2448fad48595181767e7644d04629b61a16ca7026ff06e15b18279f83c5fd8ef5f49cbe75ea62d65331faac9c58cb9c615d3e3fc491bbecb9770371e4f61d19861efa900b73fd25883841724c0e9d6294bebfb8d94621b8f5db3cd36c2f3ece89cf7ca5063226756fb52c637fcbec0e63ca19a21821459dfe073096e6fec5ccf130243a67a7dc2226f8ccf5989c25f18f1216e06654db6648ef0719436a81864270a7ee3e3487ca03a5e0a1845c17af7831d6de86858931e870a470a7fecc48d3e456694dfd09466012c52c448d139b5d54a67c61cb8f84242e8362d921122862b0da21d0e0fe12f5e0f76976f57d52ef32a2b3806fe196aac320d5b2f3310be299f6d20b68a98dff84e4e1d70358b0031d5311520693fed02e7820c014fa39bd3a40a3b3f4d55d306114f7310293502fcf72020700d54f6aecfd23108016a4146268febc3ba88aef8ae2fc8cc7116cb0df1b29febe787c3acd1480f9d14e14409f37bdc1254d3c61044eb57d2c5be7a607bd561a07cda5bc21e06f358c9046c375ae85694a9249a45dc4dc4c82d7a3eee044f9c1c78b90e375b98a22a9ef20717f826b5f78183e92ed252c243306f8afb5fe72dc1db2f3b284e52cf54d496a4ff4f3f5297c95851896fcc3ff7b003cb0a3a449c036275c2b9cad78877655e8a8a600b15b30e0185c4c1897b51fadc0577d2ba0ea4aa976f50853062c226e614c747cb5da4b414b88e32488b6be38638305721050a0fe4ce5672952f65eb960b4b5f190e510609d6acfe3e6091b5db150edfdb2085392d6b152a83e4cf0e8e44a957deb483c7544b6c682dd6330e6ad03731c717406291776982d900dab8596a3738244ca5f84e54c06bc6dedaf02e2decd0fd74c5beac14d3c751e0e7c87558fb72a6ff3b7aa9bcc27f69670b0b623524119eb718c527b205cf59f7f32fb0e4fea969ee7a6dde04c7964bcce49ad23c74fc546d5216f2ba9ddcf483e9f734f09c27f3c4bf07b3042397420366fcef0981246c71c1edf6f7096db51fa8529e95a337cf4d3e1ef4e1cdfef0f8ebbeac37042a4a296cf2eecbf01c3ae85ad66481f98ada53c8fc8832be6329357665faeb2e0f5a45d28f8c4f93c3d548afb1b0b2d855fb3a2f3e6759b36c41c6382880117f00f7be7efe00c06bc6d15984f972ed8641c8e7414b8266626c476d92a6b22962a71f4d200279b21f37246dbcde03d3b4810853cc765dafa6b28356cf06e4a144210397e6a3ec1fee9bc6e8c187f577c7e9e0ad1fad93bfd53e31f75ceb8dc77c33a5f6e86401fc0e5adf636bf64c84430b3a13446e39d8440b451c75c9dfa007b12c6eecf0e1e3f2c084e9c6a009b073506684c7be61b1245b2e48fa00fe21889652076d6112043455f8cd3e4b6d953496ec3e256d91f737baf2aff3f936c7b20e4a22a4f0a01be6239b48a5d813257a705ba97a2cadeea8683803c0f2b7d36c015a702cba604c83ec89147ba4521a78395ffd98b48631af434626b3b53cd15c7fc382085549825e822f8c45b39dc08d438792725e0e05edc1d1c910b73ca5ed49d8ec0eb7cdc3ec6b8b2b36778548d4afb59d7036b8ebd0e4e753c918d4ccd24987cee44a0a4cd55433765d11aaecb409bb74f56542fb18181e3488073889740b875628608d45984a511935d849e2be742fbb2abec5c104fe3ebbbbfe650b2a02ba1cbe950a69da179fa32265c6a3d5d8181a3d719c4a56291573576660de44237a2ce71acd743d9a7115fa836edb65c8735244433d816cff91105b3c709dc283f28d36ef32030528666d6a023df1c21d696cd0b1eaa27ca62b12b0c58c00b156d859e83ff73c2fec03f6e86c28922a385432d8e43c1a90e8e213f7ec58a51f02b000edff34864931aca89b663c759830bc6925d4b4b97fec86cd88815b917caa727acbec2b27781ccd67ed02c40f2168f15d3c6920690e0800bd04222b0158a7751c133d659908ba588bb76ea7c891864be83581c941e0a48d03546fd0fa30ce4376057ac090a0ff922aa354df387847b4780db24229a3a5e2030de986ad2624ce2e12a2b10021e10e5111787d852bb9a0d869443c32e4f04534131df816be1f372040ebe3515c26ce6aaf5beaabd7eb754c2eb8e949b0c00633462db451699e365bc5f78d41e80becace37d89ea68c347c7ec7fb1c3462f6927259c569b16322f963b5713ab846df642f18bc09c327b4704debcfd770e7c8de20a972242d8c4723ea5ce8ba2a22d7c75fbeea8ddf922a602accaa02c1efc16ee26f7c697d3291d51e4044eca9e33c2dbe58b405c07eec0cc792a09ff70dd3e9be5c4a647267da50c11a062941a0313b48489a9e8c5a370124ca1f8809ccd020f30366f8c0c2fd34b61a76c9e73850edc236212280f50e2d83c8836180a5c5b1486d269e41cb6cd9994a029013d41d174c1e845b143daf516e19819951617d6c2158ac9f02c06330077371e11c105d6ac4d0d70986319407529c751562404d0a96329f54e40caf3828e835782a3d0abfdda192f4c034620703b0061da52547ee55c8d92805a4246e4414886824c5542c5ce4e4085ee4a63dd552207c0e08ed08c53dc011c8fd528968453c08f7764308bb3a4674d07c1fbfded93443e8f6f437d609842970e85870dc29dcef3d86535f97a807eb4061e3a9b04c0c58a27c002d87c00e0bffd42d5d1cbbae1de7f30382794d96df6cdfef0c7cf367e214be0ae9f91b4555d0033926c5d16c38021fbf78777440773251007f38e65f33eed6a4b989214c177f0f5a3753fcfb8271af3a26b8e3336c959101844ebf9e93e2cb64594767fd009820d6b4ad3137f8d345fa17f76952fc7cd2dc6345b9328132747bd8c22bdd9f94208f9e87bc7c8ba3b6070f871dda3fc1377f9cc73bdafa01ce36ddef82d5d8fd450048f85ea4d67b332c0817857c9a42a1452f50c4bfdaae5f28741f7dbc2a86afa45decd5fdddb00cb6eb8f2ba112eb8dad23905b3b7a6eb09cbca5bbdf5787af74c7eb8135f4b5f4ccdd1c1f16e65c2d8213fa41c23522b12fba916d245ede2485a6f663426f39d0bb05ce89effbecc1550aa03c634150bc8ccf467717518fa6d0895f04f1ada8e14eff58900ae76bf727b341f2e570ea9243f04688f9e542d52e51bfabb51eac7c1a3349bd0b133aa242e30d76fc075d04f38cc32210412adda87fa5777217d3c708cef973d034ddf406e4a1c87f36c60a1dbf97cfbfdac593865fdd76d550292b040d527872b40e609cf42d12e7b0d3305b8234a9a1c85848b81ff97e8bc0c365bdbcf98a5c451b6c5c7c7a9a6f2b5c2f92c0d4bb630ee50be669a04b3fa499d0dd15c798641639b17ba4ea90992415ee71381fcb3b0a0211d2125b244366d459d963af1b4125a3a3289a6484eb6088525943cc524cd75c50e47b1e0079dbc37c62ae18f868201d5393fe3cf5d2b80a17337a4b86a47ee14c3b7adfab9bfe3599d5c83c4125116737ae8447962410fbbf986290525589ede667cfce59d5c04003bbd378c01246fc41cb139649ad0b21f72f4483d6bbc0070c05a0b4c6e47d3fcef7f25e38b472c32d633ad16c48574960e1873ded5f56df13bddbfc0dfd94e8fdf1a37863028eae2c4716dd6a06ae7072cfabcf11ee94d0ab55a12ff1b451e93a3887ef8fb75f934a06ea15ef00531ba3d642576521836ef85f3a86762fe1e8eda103bc488145bba7e0efae376790a22cd4489391d546c06c3b44513aa97a390e1abb624860572e72f284676ee478cd52b0679063b8a0de77f84c32110e66ba915e227e80a99c6bd4e01f7f83c93aef7133087aaf86f6a7d9164e59502d836f4eefc62f9b7283d2e071cdedecf9087580f521682f17a7bce844c0daced391b92f33ba7508169fdf3db0ac8200c9d7be72c9925888260e2890bbdd3e6008501f5850f28020cf2f13ca7ba0b12512baa4bc400941aca070c90214a640e82d1256f3cc7abeb6aa87a1630cfebff9390f655a6aa408b376abe96fbf63e03f287b74620ccbdf6a0b0c164f790fc307c7af488949aad0d51095f27ecb85d96223d8c0885b16060dfa8aebd7e553f0a5da20b2d423d5833b277422b5b1b37d300e9bf43019d66d5a362b4e9a1ac8578089281a0634d52816f2807ece223dc4548d851c2ed251fe8ea93315b0e79b0b2f738a01bc8c112ec24dd5e82a78dee13e3de273571d361df70cbf9e9bae30a5e56164bee36a76225b235235a5357aaa840727c621f39f2bb9bdafa799ac707224e91cf8aa1344e335388038cf6436b856d74cbccba69f1e6e6e270e36156a051c9e5c5285fcf76ff0240b7eddba9dc993087579c363cf762902cd165800129687413c3412223e6ebf27f4ed9cce709cdc65e87680be5ca7db498a3d2735c5406dcc466f18e61dbd269949932203908985ab8b1923fa5652197c49e63ae7fa75ee23106bc479c23014466c7625b036d3621083661a6b0ebc6a9c4e0ff4939a534642ab03a4f45931057de1c8a0b7c80c1bcf4f5c60c1c5c4faf2c076717623dfa9e104d7365b202ad05e04570ed2d5c6011e5b617f723607830ae0e173f6a04f2ae3b063a6e22d3787632ca659a9de8494c57c533ad572a9faeb395ea0322c46c55e039807d4dccac349cee6f0042a793fa5ad5145541c3f2550e4793db2366108655a0707dd1bb4a95720acf28470f3a4e8b389f8206039f297e3583ea3cfadb3c4c8ece3c151fb60ca05236377682b7c12153849612adf9cee155899073083d1507d5f6f444b247e2718a5eb072d51ce4221bbd88aad13e2fc735ae85fc9d3b95ad2cadebea20a1be42767405a134b7bafed124eb912fdfa283359c2f292c7e20d9217f2543503ddf88188bb3f54144c4ebc1d4668cfb96e512af10cc8dbab11f075059435c0847732bec5c37ce4d3df5d91417892c34d4888d68257c247dc761e454223302a805fc16a6192059ed4a3741678a90d9de2cca785d6a94e7ef2fc0a5169439312c130f8737559453e5f9bb1ef8934240758d9a7d824d81aff770d00e80b75b4a6cc1d1349330ca8e8eeed591475cae7b528eea0eafca5a5d8142f4ff5b49e2f02cb5b97b1153b2e7e994f5699c7236ff7d74c87cc2ee990ff91cbc6ef6e5ff8601f640e9191634cf7cfc34900dd1f326b710e6fb05c80e81089718dc4672bf6db5a615e705247d2d14d2bff19711b28a2ca61359cba62911f8a75547fc95f2ef0596f0516b5425bd364c616ef5c022e845f5722cadd93160901c77c1066ea2f163aa537ad7d52aceaa89ce4610cf533aa0f0aa7becd9fdad6994f75a23d9dee921737da9a5ff6bf907b3d44f956cb015661ac3a3cb1b3d34d00772c434ceb7fa8e0ec64f67669f3fc0154b3d1bbcb513d696c03f05e7fa30fe1d5d8a98d0e18f269ccc43809dbd3d462bb16f5f63963ddd8ca970ddbc533908a2cdaef42795e97d8e3d949bc67971a022edd7a742c292791419de353da1dc0fb3a46ee0538126b4ea82730c9b858a36a81ab858bbecba76ea9bfcddc6fef940f5d8b37c1416c8b49fa84dc009d3c94c35a7a420fabe6da89bb0a1745af9fd3194ae65e394f3c4afd4754e6947603d134e3604b8fd693eeba6b727e46ae7f071fcb4a839164fa7bcdaff20166fdc9809ba870a40c0ac8a101cbd83b04b554de2149714d2ecf9d64a9c4dd7e0d6ce3be3875551548042c286edc9ef3eb6ba0a7bac6c08bf7cd52ebd9ebfa9e72a333026b081321846bd292ec471e56e8effd7773b553cc78423ccf543da2b19032c341a73091024d9e50964da077827f45cb17cd58b7079980f1abbd193eeb28e5f3920375730df98320b315c33326b0e68f4d8aa2bb0a1963a0f0d2aac42301a862fb0cbcc07749e698323b4ffec5b4cf688c3345ec74a81d4ef81fc8d7f26e762fd1fc73968636b50fe28c8e2ba22e042e921204ba9e4c26e7718f99fa55bcc37ea5459e09fbfc08e80f6435c63e743dd46a3f26747ef68c232efb00d71efa8a787aa42dc1ad21b08b445dee75e46472fd127d0fbeafa4c1f64a2b5c889e73b0b7ad43cb1d114c3841b2b44e60eebbb586f5552c4dd8ab043a7f9419379ef7a7dd4a4982dce79b38da5a9e9d64152ccb83e2391cd8e349106be97849a03e16587d84471fad128156bd9c27d1951e3acf14cb595cafe654236d97e6262374dae523f48c95a3c48c53f902fe616618c1c121273e49b9662d97afa23ca2d4caebcc5beef74f41d2bc9db5baad601248473b453bcd1cd3dd9f4c457b7a106aac8787a3beb80807574b4766faeda986502874469f9e669a40afe1764a77de64f0de5a4d6c9cab10c5965226a47f79a0aedff1f9a6c839664d85e3359833de2500b443c921e18143162a9af2d2079abfec5e6bd6db1ecd8ac49fae1e2749511f70b68e999797c5da87e63971e4219f319b8ddf96029c7f25caf6946d96b90b72f28be5711ce13228cda7fb1a8af486d3127ba1eaa9ad7be8026be0f76dc24d856f21388f73221e7565eb757a7be29db50273c0b0790fe015f41bf967f6f3e5784b6a161c96af1dc817fb31e7a875d8fba2e2bfc617bdb5c9ccf124c6a73bd87429de4de58f470f6a8789049f03abf0cc882524fcfcf6d497024c8cea894bda0f7106a4b16b26ea5f7b367c77e647aff23ee66e7e88f64e2dfe42072acfdb3e869932601bd7647f92e7d30b8338d38f9f8f8000dcf09de07eb60ff4f6446baed4d92edaa858c8cfd0f7bb18736c6fbce6742fdaffa04bfe816b38fa7b91cdd3fb4ee392f8ecb978f812e0908a7720296218322f87a193f7eb45f5adefe1d91648dea2cc0f41ba9be15bfed6730a6b0de39653bb3fdcc5a51559fdde955f5cbe4a5b410f22fd0b723f0abb604580b93fcff5a176bfa23b2354dae5433353f93df8899d1df2bdf8ead0dce347f01697dd7993a7620d5d99f681c1021f572aa6d201b28f51a5db9addbc3261b75157b11028a0a4eba2eb39ea1e4ee66beb202382fc273f08a9c036d213342ce9cc7e4cb6e45b180518abd7bb648da8136dcaa32cc385f01ab19738aefc2e650810fe85ccfb96718394c2ba6b477620d09481793a72d0a25cdfd7d7a221b445a3df37a16231fa28a53496d8199209173b704ac435a95cbea8fbd8af137ad44fe97cb2dcc64f53102e779aa55dc50c31c5e137ea1b143fc69668fdb0cff5f58df2898590a63255625c35a0087e77cafa4b985fa57cc1ecb31a28efc4cecec891887daef5b87030ca2b98bcde30f1033be0b742f0c5dbce5aed555f96f7f73e588ff99e0687e0011ad4e19ff03995e1de0fdf5d6a8125b72f3725e23b0d74d0791e6577f170e2b766fc0b1c21af2cef24496afdb6161693a0beec234c167e387b413039496bd6ca4eb639249b388b8dc1e9643b2528269a5a72dab96789183642b85021331f8ca2e5dbea8a0408403ff21867010f2adc5861dd3748d9ec6b0dc12c936637cb76467c88b3096320bdee1103127e62c174d2b3e278e64add0b224a57f282b710ad5cb3751b12d97a0fd63fd2e946c3b0283033f667ce58dbcba251dc09d852b779ec11982f65623ec2c292f94e1215467a0ec5a9ce43a47856f87f4687f7ece0fda833fe9675bbe0aaf6d29c27154cad730e65d143f04a094b1b8a49857ab476f47c21bec2665e97b6ae1b3705840358c561c5d957ffadb25178b7ca445bb8908fedb571bb7a68b3cba8bbaaf6dd296ab97a8d360f1e488c3370594dab8cf44bf140253479265da518c2fa3edb68226ff00ecc47e0b09f8f9a4f3c9114f81842dede81b35713b0e4017d5e25aa78f3877dbccca97e7dc782cf5461a6501af7d642dcd80e5a137bccab2cf856c2806dbf92843c9802a34787c40750c17e3c0ad566d762684208abeeae429ac1798bb7ddccc58625508410e32d52996d9077193dca99f971314557d83048080bd8985b8451f872efd90520d47dd51065457881e464b5e46aa38d66158d29d6330609fd809504800ae3a6e2758d37ee91bda0e5c4392b39c8df97b0103db71bb6736301a3f99cd7ca0fa80eee1ab45518096da39488b3d6effc8cde55e1c1283dd602397ca8c47c6363c1025f62439b48e528399101f3919114331a44cba1f2d28994d5e938bb33b1a0c7c7af51aee39db374fc813bf125c5eb28e449c3c1a7ba69e8791055151f067327ae98dc9ee619ecce4ee0e61937564061dd3d828ef233c31206ebfe627145d717a14040e46527de106bc0d1aba04f652b4bdcd0815b2813bd0a4bec65c37c0fe95877a140b5377c606fd1c01ed1944785879e4b52d4a0cbc0fc2f94ddef750636eb4d95c56db9723c2091196dd4c729777c15bf2cf3b210846972f351539dc58c79b69e0828b6c87a742824be34025ae6fc3991a5daf4b50c5faceb4685711cf1a837de51e290ed08ecf77bedf9926ae14b223b95958cb597dbf6b3952dff1c5bbfd1e38daf13cd28e28e049f241de18fd01dfb919a4e603109e0c1e50418e02ceea386d0976e946043432edda3d961433027a9f4e6fcf64e42c99bea8e6b8b8757f23652f2a28a74ddf0d38ae285a9eb9af738cc153397af6db375dbc5de685a81eceec17e63233d24f62c2f025ee421e7351076170eedeb199579597d652030980f1b63bca8fe3c7b6d4e04584e9789868cb0734e41ada04709c661f02e26fa07c3a6d18d4ac4a567faddc60cc2d036f31e4d8f78f18267cb472c48d1181adbb12c21e9da08e41090cdf1abe5c6f1aed92149e72bdf2a961f0af983506cf8796a48b44a3924b65904cc8a43394b0cbab42490eedebbd22675d04c4cdf028ef6ddbfddf2085a573b9e92d82c017fa2eb5f2961b647a41b25fb572a2eae99fd2c686465bfb2078e5f04ca7349623153df895962242981e5a4f63fa4311f4448b71be1f14f1a43dfe415a4c704228915d2c647a6556ca80fb0154e2e34ae1bef641fbe7d426e2ebb9543c5edab5234f9453fc92ed4a5cd058215095b0f8813e1d49c00d262e9e76defc4fca94891e165c3737b96b0db224891b3d4e859253885506084bc35b98a6bca59ea3b979ebd575c436df440f628e03df713c5034877f389c55963e9ae60edb2b0a887abb4462f65fc4db6820dbd681657b48d0d521731d95c212dbe32c2a6b8a2e9a0220dacd3c2a901b3375d55f729a78a3194d8e9fc5273975f86937043e14cc629e8b92aad274811d7daf87674627f8b6212186e564099c9b798b9c45bfe5a4190baa3c9fc5dfae9124fc6d55f79e17b47a8a5c256da4d40508683394174c9ef8b85571c92e4fcdf5efe38e8a4ce45cdfa2a39746e195a8073225d89a893bba3e86801d9b1b7d8eea626862081e3c868fa0e6a1001d6c9e58fc3669aeda4b3b6c289f6ef590d69fc29bdf7ffa3dd2688fc4b78caa091709c22fc487d8d98fec64df00e1207581f946398c5a020fa28b001056a050b247014811847ce93a201caecb3e96c803901106bb3fdd2a44b71b33e330f1bf82217b2fdb7fcbfc0700270e4aca008aaa3371801207ca0812b04f9a2b901b67d336355e8a5d65a46799daac8d3fe497e769a8d2c12f81efe3b29c30cb9cad73c85172f45f90f925aed04521483a62382bccc1f002ad2bfd407ebe08107bd661e86fa7e609b011c82878607b1d345f98b213d2898149442ad76a14923370f9b946a24c0ff67203b03def18f0b19069227d0a2eb31a173eb5fc5b2b868fd536d2648fc525e9fbe660d287ab3de9782ab7e3cd3a517735bdd99bed287a733724192eef29af00ad8e8382ec99f8e8bd03f364d71f9322525249bc810d646871315c1fe9522826749d77d3f220252394fd86eee78da263a74f368be03ceb2efd63bd38e40d137c4eb8b2ab7b161e494777fa6f5d38b79f244232722fa616aa1a57b6f6765a93d93d21e63219c3028b013e6958c5b2356d53992b62f0ef84d9e978142623b4df6b5d3960671e2ed05f564645b77c75bfca019c7debe6e918caab8e8d5c7ba622b8c6d659071199dd9dc553adeeb44294508514315a2448278ab20c48235469110153f3f18ebb5a57a5d655d452917ee4f0d66c0e154da88799361dc8f2ed0c2ec67f0166b8b2928214b946a7b109b375519f4b568c1309a3089aff17c13a46540eb38e77ab1b0c23496308744f1331560fe7de1030975b47f7841a94ee1e45fc5fd3a0ba6c6f4f5accbff57e11d7cfeff5cc0f66a37be75cf5888919233dbf8598f269801d99ec10669359a8500bf750def74387287855f58049b7cdf492fa772abff48041d21d04886ce1ec52d3629b10cd13d3835e85d5238ea16079b67990f1f9b45601f46a28b1bf4af6b6e816fa4bb34d254dc3f50efc0ca1a44a80815ba3613e91d7861f674d19e36cdea646e7eeed5a81b608ae5d9d00bb4a86519e218ba78914ab1d1264a8d8aa0732ec014c64c2b2e690d1ddeb1f84f0d99b6914165dfd5ed421367a588cf0d9b86a59b16cf39e63df9b081a1ceac0c4f0b2247b7483baf33e33a7afc802122219578b02041524cfcbae4b51b835d43f8c74ff1522f67aa5dded3a2b16e01987c4d13d40a7eb4fd893eca59b199b7d07f447e4a35b830a57afc50fd7070ae389b5ab17e5f85510d4250ac7c1fe9cf9cc717c47da41f33ff8319c5ea74d6a4995f05109f7d36972803ff052986a5758cf69626adfde776ee5b7cd408e148f198696f452fc84324f0d422c077f2d3a8270e384a6392b584dd331a679a00d826e84739ce1c23341bbd81deeb131182002856db86a713d56cc3d2dccda0b1681a9efa70e4c5ec8c4e6be8a3e2ca5c9b1758540c1461dbca7546d4571eca2ac1ca6bf9472ad376bc1028302d3ca8502592291b7e56471a46562f6313057ac5d88cb1c3143c373e89dabbe99297f0d5c83fc72c0226a97b0abec6f606b872b150d9c72d92e10cdd1c32e132c02d73c9e131d3999da88ef1b5b60b3a52a04ddee9ef624ba1114538a4b62d68f47099951033089a8444fcdc762a44851428bd4cb4ed0ed53378ded9965073f6cd3041263642e6352591b8240511d69f7b36912d25f97d8383f05881284ee7ec3f0ce56736800eab9ba1f7a6734b8bc9947eaee0279784be1cf9a0dbdab2f4a1bb3ae3317c74cf2983cdd1b317d4828ca93bd8e8a1e98a942f49c7910438df933720e9146f217022ccd238f7ac41e65779f6d4b943aee613b1c80f220194d622e03f201d71cb63b19de0c3ffdbd8ea5b32d24b80b88a93f871982fc4d793c35211d69191367f46184d48693b4be13eda1704a9232acddf70e1fd2847722b6f70358517d27d544a6ec6c59a8bc1ba2bad7d9b99287de6adfe51dc98171be2ce880efd5a2b6b98e36ff2d29c07b22bdafe4df303557a00f233f7e52170cba83a9dafb95f8438b6f66b3140fab3e4fef3c7ab7c49c9cfafca28dd675d7f6796042196981b0d3dad98a512c8d6e2c7b212dc98276389719c1ce6110917f82fe1d9bf9d8dbcc0b6984f1a19d64d4e7b6fe48fa04925335bbf093e97e046e77bbd3546584a336f99ff870246f77c1965b893fd166d55c874a9746e46f78f6f4b42f67b10fabaa4979962bef8f42936ace06687df3a69272ca14b528023b422960cf3a4eda3fc9c0ad0ab33fa99c06730f1a67dc59d8f27ef70c1dc7fe4eb8b1db08df75c639f767d592b83db4c74fdec1b5471d225ba76d1a304c8a89aec907a260ad77ca16b7675600eb4397b1e624fca070b8f4c9d314f0013be2349c27e9b6421e3982dbc5a3a616f1a5b492fd91193ffe421ba935044ff007a67c7bc37521c7c9ee6c5f1fd48aa08ae892ab8287c93429f2453587f22e99eea19df7663eee8bd8990a08f1b33c320e3988f0c7dc6424f7e44b68cc8a726312492bfd3e5e03b5bb2eb7961ea698dc04e2ade31e54ddf344e7c1708a79fe8ca087f261b30875b60ddc398187c18649a21c00f9d8be02c041068080272411fdbace58b7f7f147e05c62f52af80171be1177b8e5a23f685e5b9e60b63a51dfc7aa3e9568ac02ea959e5f437b8b7f1cb63c0b8b16bc93c6b599ae576a2db1e52c043fc59002e20d665de33f46cb87b76c526a9d1f2940480b747b681a7ff0038fb3f1ee75a41e868eaddfa3a7edb4a7ab0ed22afc714e156cb083620742d2639bc911ff6949943bf7b33334e82d89daedd1c4733ddd97bc527f8c435d451fa9161e5cdf0f6d0e2f55fc5a63e1fee85d17a42b3fc4601f0e333a3fd4e6644a9f080e103fd4c5cbbc7f98a366d3a37afe724fb051f0b4974e63ed46667e8d18756c566dcf059201e575a103119dbce2c0827e64df1c4af4d98d0e63627ec4afcb3c455555d93d499237ebd228ab37fd66afba9eaec7950b9f8e2aac030107edfc0dd58bb02151034002d611f5441beb63c856d00433358781cabdf0cf02820adcb3974c01da78a9abe558fba05d1bafa70ca80c9ddb9894636a48503ac4ba48f03f4902ba1a3d290d8233e8f0b2c1b0d0053cb8b6642d59d05abb41f291f67e5958c6698ab2a9b34247f3441be1b3af925d8e43cf8eb960c656f2151c5aeb30c0f0f8bb56b40c3d9d6987568600c7406a28bb5c33a27e463011ba7a121bea49b6f82658cd41f257cc5ba4f3a2868d577419e560c824c34f817f9dfcab906a2378b2f22824e349fb3d76efb369b92838afd315783621b339af912725e710ed73f8701c0f4fef18846a5bde34a883d87424e38f7d8173b2007bb3a3e05170e39306d70283cf1d1c4816e76a1b4739ab466dcdde55a3c162ef658024fc6de82aae6632b9113981f5f16d370c759ba3c258de418bb18dfb82a92d1592bf50c9e8f1c5c1e9b1a6ffd7493ec8c564c9730a364c1b95d2041646872d576a6c438cf9b3f16e3b6fcf9f9b535fa84549e5ad14b4f1727e5e728491d3a014142dd6e0bb5806f27616fc4a149348654debae9d66d1f929f8001c2e3ac1f2e4876ff39a27a6073eabd7ea3f12959cd1513aa655deb76e30349df57c04e0e31beb41e5db6bc5b9e2ddc1c7a88944555f4d1b2182ef6f01764d62deed553ce1daa2a2081e0e403c270b08e5ec2f751461301c6ef902dc287db06b5bfcfdcd11422fd28037f06f6abcb95eb57439264f90350d1a3c5bfc7ce087a5a463e9c7b4c06e76443806f6e4eea81764813a2575712a06d9400ab9cf9c40fcd38680c2e2708d3099dab4f38dc02ef92f3bafd7399e81cd37f312d0fea5e2cbb8c7b372c19ff832179f7e4e82cb1809315183557f6416bdd00c260446d0788e3a476e6c9f3fa0987ed7f422db88dd641129c7ab3d346bdd1e6578e3bd2c6919e3f8ea8ee9804fe7498ddb2c219604c6f84423bf44414845f6e3291e7ec07a9bce420b2c599b6581ee478781e05999ade154fba600b09ac56ac58f02bf557b031d96c80399e385fe4a20faf1097bdf11ddda2af2a03c05c79da881967638b86fa726db9d45c6de52641fb23af8f5e8e03835307569120aab6ec20dbc0502b4e888dfe82bb1603760d3abdac1b880c87401274b2ea3d07ba9d5d1090a6518190e6ff8268ea6544f6170268e712b76be086a1cac3781765b699a37609e7c38764af313678c6336a9b679c1f9e30b47d55464698901663e5dbc8c07e748d785c9eff94ce2f7ce41822af2b543637bb7b8852a09a10df03e72a6fe051fcf92328d2885fffe27158014b8f61a3b445a2ae11fa6af93afae05314cbf1c0bc8eb3bd417a7c5ed4ac6318ef9f6f6db0e0d2efff4cb1e6bc47b4a501eb2b6b589f264bd7a29c21fdb937a01d4631f00e6d26f83506df79101eea636a766fd2e689b3a86b53a6744cb6d3548f827a9096189a4e18a9a6603d4dcf4f5912f8681425f4952b15a44eb6465936a1aa539bd90039177f41b7b62a94f0c527a3a5663916a125aff21c812a29c5dddcce1baa05b52fb5d0b74127fd54887dc3c91eb99401a248f085bd2dcd226ab5f633835213cb880a092ca9011ad362d0c33e6fd3f62a138f3cc10ccd2bbec89113d52313c4135fcab39e7cfd805ae0cd8336cd0ee669cba85c71e9b2dcf4cedac9ae8464e4f79210d197be61c2b0f8596cf98e74ef57468fba320143937844f529f59f29530600ce8abaaee23c945ac486c22a72b2879609763ebc2fd183ac8b442c0c3416cb7d3727a87acc68581814abf771f1407e3e80a03bdea9731375d93bc0b08f00f0f248819b3e9003fb800ff09cf6e7644f6f70c026109d7e2b77cb0dcaf43b4c25f32284ba817a5b96d8e96368675ab3d37184bdc828036de67572f43ba3dac6be6234405ee27d5983ea5df0ced3f0b36bdd90de3202284bfe879ad04e3acab738a7c117af7a50ee130fe31238937f46277014c03f9352797850bc86147c91861b40e7b3d42050b45a1157445835273092b532b8edf49e14af2f6bb0e8b376cbdd4ba684c38dc7248334c1c028145f4068c2aafdf632ef2bf3c224fe06937cb40d7b472d221576636b707aa4ff33f718f7e7c4a1f8c26d685728274cdd483be3d3700df2f3150db086823d7206d153abd7ffd269a8ce7ddd397ec9894d64f98f9a6b287be30eabda0f0cd57dfba01690ddf63c4b77da309f9137611870c870c1105cb5be92b595e4987cc3c7201be160a38070e7fb6afba4484585916e6219a33b06d6adf4b2febbd1b9388e30c638f9531598b522d649b724182bd1eb27f49a3a8ab14cfe923a6ee2862180ca0b9366bb52b4bcd27b64b26410e117e07e60d8ecc9a3c4f9d614a3995a3cda077aa8e89dd00bbd85db9a116ae9cf94bfd769d5e99773c342780cfe6fbee3e51a02cf846406e5c7f60363b7716d3cae2549614a22429e2f1762d8111a913a2494b4bd677c1f102e731b9874d8599366d61f5c819e4a5e03063ab1f0b1fa092068e70d9a5317e6f6485dd15649af64f0d8ddd2f0f0a3db95819e2fe341d487885aea735d97b70070c30250399a4925b80cc090dcb3ee5b9e636a8ab27379f99be53efccaa30dc9164a34e154ed936c44ccb3611284a817dc49239c0d56a794e3d0165b374f274445235c388a479ffe75c722a8971e549e136152ab59174d8c3ecc6a95ddc6e23c5a2683f2a0f170831da296761f2845aa480dd0b23b7115c8eafe73f5d6d3e321f491214b20942d5a6288bc03f5d850948a6bf6b2b526c3dd792dc6594d2bbd8d7780aa55e18ff40f1dcd7ed92473b126bd38b91a44ad27bcfff583395cc402013467c0d168f04b5d8e54c94cd4532b432f56f61489a71c6e7220ff0a2bd588be016f26fecaa769dbdddd02ef666170a348b4fea3bccd29e06393e8dfa8b79abb881b0e59a4c7c99c8764b0fec8b1031146306257b81deeed0e1e04380631c7fba3532bd4a2c5d081156ae6d9e0e433e27f6b08284af9aec7b435fd5d28f661c7bdb52fc8ed1bf5b5af878272a0bcddd14344fea5a766a79268e5de0eabf7777491ab62503f9edd3d1d1a06b0df0dc3cc5ba2bc4a71ebb8ff8121961dd3288db10c418ac463f1cac558cee93d4ea8ed74a5de4d7a58850df6db02b08e1be68f9b6dfe0be2b8bb37a659c223a7d43097c2b79d959469c2951931dc036964fe797824f41878b98873e41af884171efcf9ee08b7fc7a201b4f8c2e836372b0b7de1ceef1eb19ed65c9d9b44e6a07ac4fd532971a1b0a9f2cf6adcc84f7ea3a61e3ff87daf6bf4818c1d080371a579e953dbd79246ed20d18f16b911c7b64764d77894dd7528cedbe0a7daf22fe57d001fe7faf93cec17c35370ecd51c026a822f6a9f70d3538b4e37225b3b2cc092db2b515a357d433f69f7998f967cd13152af1338028c6d6eddaf6b0f864894c50f8b734e7fade6710e37bcf16082a389fde6d4053ff1f32bca773f9e920f883bfd8c5eb9dcbcb6780fb1762ff699c2bee2094e2c12b349e2f796ec954e76eaee1de567b318c98146ffe4ee55361a80371448e16cdb355737cbc78786d97b2a6294e5070baf9f9610b2e739f02de75de943d34920072deec09ee430fe6dc8f388ab8fad05bcee1e97684c1a1ff9808b775e5b03fdef5c851ef0e4e397f81a7ae7cfb5b122e78a68f211fbf7ae3513f7bab37fb226cb4a66403932f2a72f874551f325a94625a495fa46bdcac13e0c3b96a616f6ea7dc33ba8a6acd5a3f9ba804c01a2155a88d30d104fafa35b6f5c520c5836e9b8d33bb6b90276ff734eb8bbc0b09cafe70b17f1c5aa6122c86ca5112139ca4280b49fe74e4ab47ca8b84cc6eb2d37172cd3a6a0ff40bdc34ad073e941d8f3e6a94688cc9d78cd6fc7a78e2056f5515bce46eeb1cf12d33b68285e304361156785f98175133b6fb61711d758504936157d07d96330e532e9efc2bf060de61a074b88f71c5a70ce3e9ba5d50f91d8de77ead800f95f99e0f5864fa73ff7b9b549652c01d4e4b9a618095d5043929be7c5c5e15629096e7f171fc69a1e25ad75b0077ade8a30092817ceae90b1270160b6bdaaddd45d263a020a7c3fb3035da5d757f5245788ab8f02776352e9d152e4beddf5e5915a2383326ee658d026cf55544cecee60ad87fbdf649a75d873948409d41e8720cf4d7dd8e7c5c508e86195c4635c867a8febc37c87558148f9af3d4a30d3367c617e0d67b0c8ae075829d086f9ef19eabf57ee27f5e7a7fc7a182953d851861cd933f19caaefb56d25f556c582bec3328d489b8e24b4cac0471d5e700bc49fc7dcc869d0df631f2415e4d45339c5530a6c3eb0385eaccf67c82c67c2c333a8b41f1a9c6839b4b1b9da52375971d7f1d6b3a6b518511b27e88e04ef208a3e58fc0d8bb9f6a414e6fb2bb83da90f55c3749f446f9781cfba4313a2e505d565cdf023f64e8ff285fb18cb4cbe4bc1d709671b5ad58d15380616d7fb02695d1992efdcb4f5c5a4ec7685e5ac20a994761b392bad8834450f6886dba6c97ada29ff627407812e8fa54496c559a69c259bd64bcf4da29420b643587b67c30bb15dc1f77dc95fcabbc01fea8b525b23954217710b8cc97ee6e09c4e4a542626ad31278fec81bfbdf6d7e18ceb2fd24bdddbcf92fdd6ce7b3b06480ef51c0b790f8f7bcca1baab27dbb630c0dcc407d328538dbfb4f752b5ecb642e67bd587d81b92df18dcdb0d20b927f134ee419fe5cff8e53a098d9ac17ab23a0de9b68b81ecab0f7dc40837d72411cdea15d8a7d0f97a239f19a3150ff5eb751b3d34804b29d71387f6a7d6233b32686187245b7c6286709956279d386807f39c0a3c792081957a4e1030d8a284c5c91860f3428a23071451a3ed0a088c2c41569f84083220a1357a4e1030d8a284c5c91860f3428a23071451a7ebcf10a4e2c71c41dcc18c78b3f5c5ca1c38d1e258668f1068d3c6cbc88c2041434f2b0f1220a1350d0c8c3c68b284c4041230f1b2fa23001058d3c6cbc88c2041434f2b0f1220a1350d0c8c3c68b284c4041230f1b2fa23001058d3c6cbc88c2041434f2b0f1220a1350d0c8c3c68b284c40c10e834b5d2d5fc2cdcd36c6b42dcca639b6a7aff9b7c651b555d414dd9184ea043b1411e2082fb491c61f6e6811c5135668238f375ca822892bdcd0471a2facd044146ff8a18d145738a18a34fe70438b289eb0421b79bce14215495ce1863ed278618526a278c30f6da4b8c20955a4f1871b5a44f18415dac8e30d17aa48e20a77c27a69d2083f68ac076b9c891afc32e32f581d86091f23406441e38d1ee0aad100697bf743d40c5aaa128535d29f4c54dfd7e8e56517a1911e29bb291342bd872b3a8a9280ce131df26410a6aa3c00fd23a0bd9686404fe455bf80b19fc189c27604f477531943ff4ef06b64a1da79b98c3d29b5afbd8cfba4a83fdf4e947c95e19ab40c751080adcf441b9eb28c0217eb4cc4fbe602f0c65fca92149cee96e75a58b95587f06b74165442f9ac4d315cfbdf6c61c7e598daa6dbe0eccb8999c45d5da912b33593b0892e984bc1fd3ed4d8e8c51bd7c985c25dd679fa0e5fa7e77aa2654b5f073c925aa35e5f65621148132b3d0a165dd9323a88d6bf9884289d634cb126d9a8b6d5f32f9877b146d49cf3f26b694b3a82b7d05d9bd3a882ba60cbb34cfa010900ee46a4be3f5bc074a816a092561b6e7b9cd3df0299e552c95b08cd9bfd4dff88190dbe4b839d709ab37ae3d985e0f32606dc3db2f507c73e77fa68640085ba4c0f01e4463183560abd9349419a4dadc8f80e6a7298231afa6ee07919f10a40293c97ddfbc382198270120cd1936e167c70771b12ade1312f546fe6ad2e65eac1455c77882fb82f186f92d09d3f583fe0349cd68d46203b8c267453c2faf5365b597a84f3cac759ce73af4b0d915eb8ec364f9357f72bf113cde8341ae1f78e689f39798e3293dae07ca993539c1b59a2b277fefce4e9a3aa7d6d50904764584c5387b06bca49e46a18a66319969698ddb94b7d40549388c38311c9d3a3e43b64cf23620ea9a31cc5841aeb3ba64df8a405861c9cbbd64a6d24a6d750b77a0188fadb81eb8deabd0713a7eb8d0844605ba07f817b9fd1cfbf0360a0aaac6129af08af6cc4e7942e8bcae849d7cb28f47f502652216fad42699feb53d5a8fb45ced9e21666afd154a3d7752aa46e0e27aaa36fcf69f44d9b4d256fba9289cd564b520fb966d55a18d8b0b25bf88d3c5c72b3fa52bfe8feb74cb82e7c2521230c66c3ef36291544aa758cfaa34953079fecfebfda3ffe77d4b941aed9a2b089101d83f80cdb7f71587965f21fe3784858abc72d8097f90226875aa657590b3eaa3c1539fa8a599ff0eeea66876c42fe315df53e31d13e36d4de56ff86c8901340ebbf171f0cb8922ce1d11750017e92f6efcedebe3a1be14aa70cca437994f50eacfd71de50dc21d1ed1775f8e3b638e09c4de4fa89c417659cc6f70fed7b2baa4464880ad19aa2d252eb517bad1879eeafc980d48d46d3dea00c1475659f7f31c0a41b6e12c15c7e7dc73d69231c742b89e14d96af67b1b2a79840c5fec05b7e4ae53e58946cf0a10381b542b3b3b1e2ccdb989132cd55683fd586f577e67d9b97bd53d0dbd0952ce69177d6f36649cd67e752acfc904f6be5ca2a73b87d97af61bd6c78a164d2c4231c3c59a26c2113b64b1d043969b3c555e786a2714f360fa163176261c34c8c05c2678f936565124ca583568913c8c3a1b37a4b6825be468b2e5798fe63ac337d20933140254d6002c2811e9123803c348e41607189bdf4758b0b2e22bc2a4f5fd09bcb34a502e3fcf193ac123f1b957badbfe88c171294037beeec91ecf489cc96a7d7a1c412e95adcd965a05da47d37ecb2bed66dffac99ede7b0a5a07003fb002e021c3804aeedc4b00e441098459336401606060606060aa13fcf61bc32e134f553e603b56d6d66a95964baade4caee7b7418cf42ca274ae15805307399dc5cd93b4b315d089e3df47241a7ffff77d512680d270d3ff28498ac1f79425b48d248e64ad287a62a9a5bb0aca66119d1c870967349c2d962878c9352efbf96f2ea156bc799e5a50a1648c312c4080bcb0b11160ec8e31d1acdb00f4db5b924e17c40878826c4e1446003ccd9800620908108b0408181085c80021680c0e6890ae8a0c005262081279e90804c0498f3a1cb094da3f9040438cff57b4223281ed01870007332d08096992ae7431c0e2b79ae67ea8b9c01359cc8ceb57d0e67d4e431b0006e6f02399a4c4c46145879ae370a68e6f42b991fca8901793aa2d9d924e0020880774433810330e73b1c4e1579649e304093295381023067fa7062409e9898e90301026c06700101b0e584680301e8d13401c0ce0fe9c0c14365f4311b4861111428cd5927cc014d9c5193dfa134a0050c40a112272f33412a188882139422804a031bd2e89182026506550645063506250615060506f505e505d505c505b505a5059505850575056505e586aa82a2829a8292828a826a4339413541b1a198a096a094a092a0d6504850475046506a106108692480454225a0d94f3983003932d00395030381c891812732b08049e46049420e1618e460194329a550625aa0943a192307060aa0948a018da608c4118524518a176d2895d2821c17f06208392cc0881416a4ac80a382142855d344bd6ca860c9510127e47802e6784225870484fcb04342528e08e488400fa544764837f8b8199d3e3ed89296961491ea99197ac9e1000554114ae96226470380a81c0ce081a806d4c3becc7469998a848b1f79409e0bfa78b6f87c7ad8f7a1548a8c7d2c3e9f1e4aa57c444aa52801d15ca5524e603d4946b58752291e90e7be15a2944af9d13a0ac63c562aa5c755aa59cd0c857a88944aa9541d79110dc9910045b41632b5891dc2b4f80f9d7534b980863c280b50169f0f4d900f9da3c9c57e26218f02cf11a552e62834cd4c215016329ef9995e44ff412617394d2f4aa5503133432f2ffacc201ffba199b668223ff3814c2e4aea446404ea3f748e682617224aea1c1d1149a55292f48001c251293e4ca0944a2981522aa54747343b292468f2a32c944a19410a1529493e1f1a17a552b810a520014d1ea552b6d022258b7f99ee4b8a8f2361b840054a2902a81c04e822070164945238540e0274548a1111289552040ba5525cae50475eea2f69668778da4b0941ca90d5356f45552a45c81c4dab544a15356f85fd783a3f52828c427346a914693d3523cf6786683e45944a01f2d5336921ba221464249a4f64d4a30868765e3e345d61877840592895f223f44a3ca0e90aa5527cc8cfac1e50a7fecb47e48979229fe9a91e4b1382075213a211cd0fbdd4f8502aa58752129a82d4f8b0a01f897e0b23539deab485522954804029191af9a1a9239a3f409ea98e3c3e441f7a218ca49130240d8943f290381288a4a5a5978844dd6c494b4bb3252d2dbd842d9962baa021a2e982864c017a229026344d017a222f335d9acc2be668da293c1c9067869e0e696999406f6526904824b21fcf165348515f0b10cdb525780c4bd046a159a4c64e3e46a1396387d4d8c9c714533493a25916231168fab1e10169a480cd3490a6e695b447633dcd68a6c8818302d633696124241a5d17998ae4c7a8899c219a1e3344d3a30768f2882aa0540a0526a054ca134aa54820254704944a8180130f502ac5010d502a85014a299594052825aa01f5c8a1dac0e28652ea24872203f57c60720420707008a5d4c9247ca0c4471a6edc600f4aa9142e668c2c410e0bd8042494522a6b102109457260a10cae943a29f208186ca10019e8810c94522720b8c108b028430640c88252ea640c445460470887144b504aa110912010c4181b1883124aa9140690d18645ec008d2cbc412905801ee4e08d9338b468820aa5144a202461860a30b10340b8524ac5073001e041070d27e08352ea240eb4c540821a74a10725aa792b54cc904359a552722865a70236a163850f532965084d2829a441a93ef86125133468d18452eaa4109810c4ccc4b4682d38a2903402fd91e9e3e39941a4d104bae2071249643793e8d36323896060ecd7cc4cd1775e364da64cf5c84c508dad53241a792693d13451298ae9f1c0e64a8e39f7984ca1988d4886668b8d0423a281014dd1d789c9683359d09d3a1db043423f43474342313173b339225391d8e9631298500aa5092a654a9129402671c50f245114b9e2079222285ca020c07e17a2c9c403298090841e941403f2cc7c3ca28d8482491492945253ad48e2899548bc11892e2834945291184542044aa99548b0ac4402012b90f8c113a8a0d45879441e4820b5984cf0c0c649017a00b12b8dc0b1c2083056180185525267feadd848452697d1df2ec800420d6a10274a0d4840610d4aa912a8153ea880a6fb403aa22984106f10a2116f509c1542c480109e4d0b21344008012835a2999c502b831083524a14925a5a04a18815410042106968598152aae6ad8809f5b04229b5a294a81541304014926a5e49072cf0a0491492020195529bd1dcd4bc9240a828a5763c4dcd2bd1a1529aa0d40a20c400c4095600b1031017500a3479381d58f1031b56fc50861f9aa89a57a292e20714c5647646d7250b511640642a9219998ae4c8911f1b1e47a4084d413e9ff9e3337fb4b40cc07a262d5a5a5a5a38a0b7d6d3e17866266746246a1e32c5147566a6c7f4d2d2c2b211cdcd0cd1f490628668e60834997ca64c4562a71fb4665e315dd090e9823c1c1ecda610fddfd0e411bd92ea19813c56fc124f8c4c6d62259029d812998aa4a5a59758191a10a70b19eb8634dcd044f5700394dca0949236239a3674a10d6228a55468a2338a9736e8982b6c68031bd2504aadb0c1056c5812882624f2d0e943376b68845292677259431a4aa209ad810a251aadc10925d957c3153e9e0e934d0f35443518600a6930c14a1a90a441493c8e782c688a36303f776e6060ec7b602634e8000d2e6888c019de38c31a671043492f33d5191adbe30c1b38c300cc100533d498610365788392be33ead49f01d13c0fd00e1d9b8f99329e8e6876ca8003253599321634d195321060850c4c20434729a96632097d8cfdcd68f69036224f8ca7230a8946a309a463f3d633863e8c01086310a2241890e70a989929049a36bf64fee7818881116258430c4894924430309b69049a7cfc80f9d01d54c72f999d1d53872486b5094324940a4d3a36d6c3b1a08986a10c150618a5800cd984810aa5442f617880da80c0f08652223080c10d30a00186264a94051838ea993ce80b8d50138f2fb080046ae50b17f0421d9492607e636ba6cc2481bc0086179e179c50eac78866ea00a84a458c74418d2e7456baa002e3919199a6cc688eb8a0038f5ae142145bc803f7d848a0c93312cd1b7a26d367d343ead43923da02932d944029f56a450b6f2805c3440b67ac6881052b5a78805230d368633fd3a8533d9d983993052c64210859200223cdd10402c3e441d36464661a89369e1016b680852a6081060b2c5750c315c670852faee072050a5821134a29098b4d0b8c24a281d944317d642a126966cac0c0b4c04c1fd29481811185a650e847738a21561043a21ed106d4c30a3392158a58c10a4e28a5944c6eb421b9b1e2869d3edc70a248151aa1a42ad461faa8c213ec8b68387688870a6f485470433499ac50a1a3946441930a0f5053e882524a7d56a640869a021647a4200929084149a01acae3ff6e60a6b043663ca39168aa9c8e680a91a9483aa2d991c292421476d80ffd12cfe7edcb44410c1505181b05a844d3f3991b26ef12051728f4c10714dc508ac9bbfc5fce14524c214593c907678a29ded27c3e34c399461cd11390b4d108a5148ca80d15c088be8dd746069c90871618980d1435af0466c786870e988d13de09185869421cfeef86039b4d88c6da1e2b6c4c820d44b02105a5a060c3b2c1030a181111db432925865a61c26785090258421b6076ec586bf10e1d3a1ac986477b6436a20d6c5aa050129a986c441ed1280a29667a96ccc02c218c25185902039840f14c5aa0906038164624648a9729b4d8f0b0420a2580a18417252c40d1242110d2153f908c402f335dd1d2f2c264022581034990c01a605883c91a3ed66824fc01096c200109127e4830a31771361b2573d4d2a26323e9d8d0c8f0268a1d303b9882b0d0b181818181a9a17f6d0cc81303f21ca1115d5047e8718422343147d82849b4e343938c8e4d0d681aa10c1b8fc86261843494149a36fd62842246d8484528c44a11d298403d8a00a3a4cf5750119ce8a1861b4ad1cd6803200f6cd468b2a206154a7d98fc5d51c30922486132e1b1995ca6480312692c218d1da401930601843005214c42d011044c7ca268922409169fcfdc7060c3c3a3040b2c36120cc36c6a3e211e59040106c10140a804108800842e80f08464375180a60d8f1890e707a21fc81f60c00780f0c1193ea04229f523c986039b243ab090fe33977868ba3032e311d1443137437ae0040fa6c08324f040090f1e0f02800615d08841a3a1c1811dec61074bd8c1921d5c400769d0c11374307550801c6c22076de4e073b08133dea014149b3bfdf57c36a291a7258a1f316f5ab0e8c0904d14d28e2331d3470716303a36a3d0df49039bcf9c666a689536473aa3896e78f00061b189428a02346571c4634173a363e31179866c463b746c44517842134c10110c0f984d8b04c381e14d14d763e79c420ad0779884a60d0fce193ad4194ee0c00d25ed004d1e100e6070f08452d28e69740338dcc08b999a91e86f204429c98c4658fa9687c78c36a41df6ea30a30c3360cc28831265aca1a6cf8866e2b129a389928a2855437b94a1431d21a30fd28e90c823b3094df7081965bc4787888c193284281f643cc0a3a40336a8832766c9a6870dd2504a82b1c18c82b101154a493030a21abc51833228c9d3a9818f1a8c60fe872e87c9836ae0040dda504a493c60447336912b34f828698c338c311ac3023340c30cd49881680675062b32c0820caa0c0c20461a144d68a463f34b3c9b69b4d9a163d60d0fd1ec6c3e1f0e68fe679a24a98e7ec383470d68d6d0990fcd78946c66886e78ec80d980fe958838ffa17323868b181788c11e6260460c48a0a4d0c443e4f90f058189014a185008a30461c4309e08438142349dfaf17c3cdf192d99bf858ecde2cf67fedfc9c48271061849c0f00183444818f8c88c3a92b469a1996a3210e3041acd128c60c2c00d18d040492f5860616453437f485f290cda178590449d116892d930194f93285e66f280f962f485902f0cf0023794827951161b0b00912f3d7e4823452410988dc833459e39442412c5cccffd0fdd17086132454bcb8b144d261f1cd1acaf850b4ae082014cc10b8f170b9060603677c8e679d887f9ce0834373c5e36924886a6863c75f3f94c2558c06c5ab0c54a0b10c082386c2c680ab160c4821d2b784329a9e63ba397563082156c54a00615b440053a528089149021056bd01f3b7eec8079d1f4d1d232676aa847e4e9bce8d8483534459e3b44daa1630303b3691981e668339a409f59e38111d1144c2998220505504adac13ab0d844217146d364e4f3594141cc0a0a84d444a2e6073556d43cd1840c4dca9060288d88637fc234435164fe4814e311c1ec108d26509d1e11cd34dad04c35348acf674e90f4a129d580264bf3a2998dfd234d609a40268550aa0c4cd060d2844991256fa8256948a2d99996ccac2c29a2d4121d4ad1bc41c306a594045aa171c0e810a3348c9a8c88280966878e9799441c91471a6dbe33a2d9c0c0ac88b620a2c18a480a991fbdac844c1082d7481771e8628d2e46d0058b9a20310d623a636253004065983262c8b47c06f1c9820e3ea08f90cf0494bc21f3a3d0743d4a9e3841203cb00323adc47821468c98224aa90a9af5c6e1fe60fa41fc10be7e0260ec083447a1694666c85318eb02db01c16ca26891d9706003aa57a8b762800682a6a19464ef047ac933dba0d448b432210c0b604c00c31e1071fe43975387c985b3860232c4852386c481a97925f63909504a12d5bc92cd3492f1bc15268082094860021d25f04309d650a2a7a317896a5ec94a092c40823790800d127041029411b0318215ac8cc00a25e910590fa7e69558d16323895e09c8b3d93112e9d8d47c36a169b3e333473a800cd93c1dd5bff7434c1e643fc411b991448c243049742895840bebe1c06cb848a3c70a1748242e7470a194928e20a98392824242032454483523d1648224015b9441a92dc4e8b105922d12a0b47063870e2dcad0a288524a6551892c8e908588c9df074d51dccf8ba2004d20d1069445162f6d7859432969e5c5e58868762a8d6823fa2c36927d110d68ae1c7143d54ca1d112cfe7081a4a3ad239b2568e38a18cd4611a414329c90812a5404696521268c588134a29490475504aa98d08bc58e219899684685a5a5eec90969617eb298286222a90608a14008b252b5840e102079734e6157990ae98572c267385c80e88fc20b2002bb460c55ba180101c220467483c42208010a80c69c2102e86e8504a59d0ec6c6024212f42282084031b9909d2b181a20a19841241d45809c24510968f58915b905dc88d92a2780f9599926c46a26966a381cd878a6c3c00337598f8b8626e3a95466623ba93911520330022c50f41acfc08c3e7c70224514bcb4f29c1c0d44ca30d10092606e411493b5a5a5e746c9a4c4f6fed7a7010d23fb64bbd4e8e70dee68e7367e461d29ce3670a391184a4cc369cf3ffb1cb56e48e73206464b690bd565eeecdf92020e433eaa637a597724378ff20a3b3d8a275eb5606dde32b4efc2067fce8d6b783975ae62f9ef4413ebb6b1f27337f773e88c9c4b173fa48d2e8632489e5a50a0ecb0fd642922489dae73e38e183e4e891d2e9ba31ee76eb876844d3a772607f26283443c351324d1f6f96972a5844c0f2838508cb0b1196b807d9bf784e46ab7d74dea807e938be775b2f771bd7a21d6716eb342c329e8e485ac2429d8665b524277990eeb9fb966d7cb3365090e6133cc8bafad1d775316bf5417607f9e885d39bf575cdffdd0e927a5c3c5fbbb5e875e69c9f787152075999417aa18dd33d76b3759c41ffe1d45f12d9417649c20972428718db6206bdb5061bbff6e7e082d4215b9741b7d6aadfa9f3c77b422f9f59272292c4f2a3e6ade888a6901f2ccff5c4e4e595cc8f0f49927c00b9c239962284933948d6757a9d3d217bdbe06c434ee420dd7a476ff3f3dfa6efc641ceea9effec576bf5081f1c24a396f9d64aeb648e55fa0649e98b7445eb1ebfe7d65a619cb8415e5ff4b5c7d031576b7b21d2832e49384b4eda20db8cad7f35dafed5cb5cc7f951e0610ebd9ddf617636c8c5d6edbbdcd042d7e87b4fe8a5e93859838c94def80ffadb4be3ad1f510cf568aea01a516b3951037cf0bd86afb1836fb116b9c576b77e65cc4c297bafa541b6bef3a98d6f5d7ff3d5b72e7131b5ee928423c5091a6475ededb69f718d6df90c72326c2dc2efbf7da3d38e33eb2e4ecc20a77363d4dfb3d6bac52e5bc14919e4b767f0bd377aaf6590c9201f745e77b6e7eeeaa5750c92bd729dd1bddf37793531489f4c6d74acd67ff6e3890b4ec22021e51a9d9b0fadd75b1b052760908f6f73bcb6459eb13a157d412e1a9d8b96455bd98bd17a41b67b08d9639d8f638b5d90cd5dd9b2ed192de39f1d67ae39e18274eb51cadc73d31febfa3ace2c05275b906bf2a3d3fa727addaab4e3bc5893132d48389bb79d956765f35edb71e69e4eb220fd369c73c1e56dc59eb6e38c0539e7db58df7bde1a593fd7a2932b48c79a75cb6b356abb8ea6c90ab29d2ba3931f5bb3d9ee8e33643724b38f6fb5e9f8759ca3cc4915a4af3819bfe59c6b73ef182ac876ddb6daac45b60e998ade094ea620af6d6a5f37e630dee8ea874453c759c98914a4a3cebedd5dd0b9fbb63bceddb8313397249cd04914e48cb132cf7e6f59f7ce4241d248fddd6823d34b6bab4f90ec6074fce2738d52365b1baf99f1748ef3ce3a9b3b01fabdadae05bd1775f19b209b9b73ef459eed7975c706730d3a6bab3973fc60847ddbf9b28cb649ddad183bfe5c0b912411cb0b114962ffe28409b25f5b48d76de8f0d7ea8eb33bb6fab14b12cee7640972bae8cf0bb2cb1d6778851325c80ae15a9351cbff1d7b769c471fc384f800d2114d2192442da7239a9d1f2c3f5884b0fc6039c2f2428445fa784fe84592a4299c244136ed5fede67c2c42381f4b11232c3e587eb0f460294284c52d7649c2a1395943c6e5b545e6d6b18670d28e73939119d2100e274890df569c31b66eb7f6f4d971fe0f8d38cc9f090a61f133352f8ddf891c4e8e20d97291b56b67cd55d7abe31c03f2884234f5431cfe182be713d182e5078b152c3f584634574852e89584a6ccdbc94592de4e204992a4c5fd760235c78cf2831323480aebacb76bbd6f75645d0469e7b3d6b1ca3fdbb17d6ac8c5ead79fab17ac11c64604692f9bd6396763ed8e9487201f8c94f2b3f3d26e783d0de97dbf4e67fb6e841cbbe30cf2707e3459088bc5d66d3d6ecdb5860d1b5b147665bff47ea416da20c8d9dc2e3f6bb13afbd6aec8831320c8d837de4b2bf438f936ef384f17244990c3ad5d92704e7470f203195b746fb953389d7d1a7122cb4b152c9254dfde372249a32a49955333f284e64c5b3438f1817cbb28b3df9a37ae6c6b0fe4e4d51ae4db68fcdbcff1a0f93d66e7d690db7bed71639f91f9f3cbd869eb38c30e8d66b6384143425e1d2db4b5c2fe8ed30834e407cb8bcc140a527fe68824bd307649c23961e3640712de4523b765ebb566d64f74205df57eeea6dd1a437b7310996baf2de7625c8b316cccd95b5cf36f37f6fb904fce90d6c5382347d8166def210ee4dfc8dcf87d7cbedeb5edb924e194e0e40694beebda9aff9cd5fb9a19b09b3ec65e5b6e5ba57c528684ec9b56e8fcadc6c8d60919b231767e7135c8bed17fed9dd840b2dfc8d8b5cb96b3ff8ee7490df841f606239b2ec27a3bceedf98c8c879dd04046c86cbd062d74beee84d0d3e485849ec944a44d703286a4cdfd0dfb19beb7d8cb42024d204992a1013d97241c7a3203c91ceb75b94156dd5b2eba76220339176dedce77d39fadc5f1440ce960abf5b50a9da73bbb1d67260f62a13f121a1d61f6d048c4e2490c64b75b477bd5c69a3665190ee83fce353353756c1d0dcb0b0b75342cb1ff240cc9aeb2f9bd96bb46bd46f7e3040c69bd2933fd660dd97f6c2a4e6020dfbebb9a32d8d3c5585d9e7c21295b18e973ff4d19a3cdc7c90ba453d66c17ff826e31d73acea310279eb8403a5fafffc1c6a87db71ff41f4e3b20275ec8b7a6fbaab3c54bef9d8d096981a4ced275ad7b3fdfabce678705921f7decae8deddacde81de7c7a1916805d2d98e8cd278bbc5c77c3bce9ee6a802d9cdba75f773b91a6fd38ef3e759ce0cc5386ef610a4404eea204fcbdef573573934122d8902f9e2ac5caf63ec5ffcca9f69a2426ae45d0d67e34927adeffa5d13e9ad46e72e6bfbb6d9638d89fccbeaf3e81efeb3ffcb9c5c221b6d6f3d686d6b0a63affecf0ccdc8491ac9fa41eef6cb99abddae6824ed2f372fe5065f8cf363c799c338af45b2d57eb131d7feba6baf779ced9c615248526eadbd5b1fd9ac5ebde3dc41ba901032ca9cc58ffc9e3fef388b26dbd88546a23723afebe64c9fc6b938b6cd629210c60a699df71fbc2fdeb50548366bef72ad42b6d4deb664e4fa66e357fee6fb66cf8f643fe37b71cd587db979b75022a38dd731daedf55cfc99a1183b679a433f8a2399cbe00922bdabbec3c758a3ff3aceb099863392b9b00a4fcf67b72a74ff33d6be1de7f668382f0acd99c6323420e6d259eef9653f5d7bd63eff8eb30b3d0834248b18e920730e3a4767bb33ebfe3343f3b2ae6cdcdaabebdba22e32b51d67fb79cf754798e148e632295eb23b1bd2b72ae5f6fc388d439d2af332cf452be9b4cd8db57eb16b5dac879d452449147af85c927062aaa4ebdfeb59db82fc7d1de3f7a1a93695b523d74ad9a5eb5e38a1283a97241c2493c5be4de1a3fdec7b65dd5c9270268c9cb77eadb42d7b5f8c8e46f600c75dfe3ae76cabddc1898509a48d7e6ff5b6566bd659d871e688209740da79ddb27cdd574be75b1de79af961ec4820ff466b7fc55bbdc2756fc7d9f11881ac8bbeb3b13eaff16d27610bfbce089bb79fae2b17b2df5666fa7f6d7bacf68c8c875124b2a363962e6eeb6cdbb52d646476e3f4fb60d7766f1ba2857cb33aa7d6b676273b5b35f33323f24c1734a47a40b38824b94b12cecd42365cebb6162d3357abd7189047495c2f92af7dfab13dbbff9429e3d74724f3f456abf31bfb1b6bf68c4806977bcedfdb366dff94a4cfe7eb7a2e49385c8840be7eefda6cf628658c7dc7d97a383f53337296972a586a403d24a906345f1e7349c2914564b345bd61ed76f860b38eb31bc95c0d60211f5ccf9c3dfa8c3e6a5fb3450217d97841c668bbcb556e7c9bd8211f039a4624e96340332449a29989c3ee928463af80bebac1f53a3a8e0d1946c6bca66bec4606d9ed6763c739f4a3213f24c9be6766aa922492a4d08f3c418cb0f4e2d068e6440d22b2596e949bfbbdddffdd71fe0a9ae2571016a0200f8a66a6162b64a4155ae6ec8b6bad05ffbe117f3134f4ad1bc95c361302f9ddde735b2f630b5ad61d670c0ca9bcda5db5adeb58b594798890b8fad9bbe6f77fe3ea38332baa80cc9f9bed0e79b5f5607308824c6fabb2fdd78dbef8338a40b6eb145ebf96d99bb3b4e36ca72340287b6cb2db9a36c3ca6ded64e4c7f5e7f9ea6d7f962b5b467cc8eaccfe2c8cb5196cdc1de7cf8c8c87633f343b22e83d7cbdca7d9fe37a6fa4b0fb850a19a77b4effba635fefad8ec8f98120b2d9627f84b5fd649527992934c37d640a79993bf7f8587b36461a3bce3353c8f2fa80a4ab32ebbd5a377bd9731d9f468ca590ecd8cdb8d8bd78a37bef383f68fa544ef58ce648d4cc1e9093dd55d85e37da3f9d3bce3253e83649aabf84e585088bcc140a22493e2429ba24e1a0a045c6c92e6d6ef3398cacb58e33f411bf3e66eb9ab1ade6fdace3922449cc85463333d02d77ab2d171b328efd166392cc92cf4792d65e87b6576c5adb6486028f882634dd181afa403e33329e763234203692b94c5c4ea7b1b647465bec4ad7bd5324f224f5efd8cf9d9bdf3be6a46333425f8daee8d68bb7e3cc61fc1ed75f32a449ea5eb3efea2f1b29dfd871e634bf91cc658fc94c132726c4e138d1d221d369e9a3ee689d2f769c47214805cbeb5673bbbec6bf6cd1da71e6385cf2418ecf9ba30c5e68d7ed3843f60ec858afe367bfcc3d99c78e33932914c32d496eb71c5ed7dc5757d9eb388746a22864bf7596c24899b3af671de791cc8d59f090adb2a3add616a3f3e9b7e36c419333596ee78203f23547d7d7eb342edacd759c3b229a194e68ba9cd783e507cb0bcb0b1196fa5a30994622bb7349c22102857cae32bbfd5a635ea3731de7d0ec544e6990143a766dbdfbd1c15ad120ab6dee083fb6e55d193c836cecedf4b6e5de3308971964c7c5b1ad48275d91322f03e48ecc9e2f66d65a7408dd7a8cdd466f7eedda8264906f5e5ae92f6ae3f36a2f49afd14819835c8dab5be8a8f5e7d8a1182474ec3e3a6153e668bc2c0ccddc7b31f81adec7d6e1a5bd268460906e2dd8fc1a64dfef5ef805799deb79edfcb726e3d8ab7941c60539dee791cdf76acf2ec8fbec9a8db35ae69ad5c605e9dd6afb823d79f9b4bf05f9288cdf17b2f876797b2d48db266c0efedf7ecc3666c17db16befc1d66df9e3d6b83e6799ed6bdf2fdbbc6241dad766bd6c6737ea7feb152473d3ed4ff7ef45e81ab382ac96d67a23b3492785cd53dc900fd2a71f3fbabb4b12ce94520549ffd9becadf11527ef63319a1825ccc4d6eb063ab70b275a09429c8cafac6ebaefbd9db738d06295290d4d1c9dc5c1552bed72394414a14a475facfb66b9bb7e9b13f2950900ec6c8209d0e4ec7263b7c829ccebc9832a53c579d5408296d48a7ec5ab66eb208dd8b35ba13645d6f2db4f55d9b347a8465a43441b286f4b1667e775eea8e0de98c1da3ee2e64963aa717e4b806294c90b636a45eaf6d06dbedb8041959bbd59dd95fb42b3f25c869d77b3db93bb68fd425417e6b375256a98df52dca6bf8f3d5cc3d326c112e87ab17acacf1746ccd67612341be777f1965c8f3d93193a4ee33528e205b8dcf9141dbb5e75c168c1423485ae372dc984f665f3f9b520449ef7f3bb3ba6e6d6d5e35a4c3ba68fd56db9aec412782e4ca1f5f9bf3f99df3dd21c8c7de471af93aa4f799a621dfbb3be163ce416e3fa710a4753aefbbf53acbe26b2f08ecde8bd11d5c8ff9b53bd89c7ea55e6f7ba79602417263a6d62163b4b2d9d69991f203f962cfe7265cedabbb6fb5f3817c343a56ed7a577b20e785de1ef36f0b36ebcd03e9627318ebf772ec359d68c809ed3bf64fbd3d3fb603e9a675d775de161d63d77420ef6c75c2e5f86ffd383907f12de871bdd70e32a47ddf7d91becb1e73ef0c495b64ed1abbe6a8abcc1c4bc1816c7432f6ac83b031fb6e536e20dd3fdb9eaf5f17df55e622c50cd9f8565edee037f8cbb19432628b8d9bafe69c63cc1a3a072b8dd751366bbb2dc6994286bcb59b63fe8bb9e618753fc3e1b824e1482936904ea7ffa2d4c5dbb3727fae0b414a0d64b48b36af2fc2d6718e993e2c850692d90779dad98badc7ed3acef66326224452c660ee0fb26b2b7ae4e80b3ee6ac27b3a3969f36ff989889c8cce4224931d3c7b1941948a6efb5763c5dab919d9d418a0ce4ba15ded6e8ff7a77f5730ed7a48821a18bb3d6e8f056daaadb8ef3874686bd1061f9d05c21499d9127342549f4f978a88813fa19497249c209a5c440def9a0b7db77adfad559c7f9b1bc5481c4a584213b3684175276dcbebe088674d15eebd4b9fffafe5fe8d54881819ccfddc8965dd39d6bb45f48caf04ebeefae1a27ff4b79819c8b2e6691f5830e69ab4d468a0be47bb0d6bf0c699cd636853748f14232c820b37b1fa32e49381d944dc836bbfdbdb33c9ff76590736203144d48ae8f1b755fed3bd866776226a437d8b3ade8e2fabf5f3bce50d4fc1a132c325f1e975bacc5151bb3c60fb2cbec8a773657173bce924892502e21a9bb914e5ad964d339fa5eb484e477df8dcfab2164f85f09c91ab43cddbaff766b636fc8c87d17f36759338dcf9490dfecaee6eaff24a47b963ecad67cdfaed1270969db9dfd73bfd970dd180979ed37d7d442c614d2cb90f0b63ac6e6ed203fefe61ab4d6467ffb1de36aeb1192c2d9de74d54268e3726ed02509a70b1447c8b8983f7bdad8ed499d3f9e02a51192ba9dd5e3e3172f6b334a92c4e12af2c8b4f718219d3268e35f7b2f6c8dd545487eac753b6f9659369d2b42bef6d5f6645ed5369e2f1192cd661f63fcf4bdb5672f445824e921425676567bb9edf5dc3a070f21dbbf7fc6188c17c26b6bd4018a21e4b313c6e7f15ed7b81d8a6a66114992240e4356039442c8e57045e7f65b5d94b6450809dddd4f9eb4d2679dd58ef3c803f270388f480f1f5810a9e2715e109441c878fb715dfdda51b7d1fe4ccd0b84038a2064b476bde6607c8eff286b6c4009849caee9ed6b9bfd45a77b2343244992a416f270984fd480028815ddf3e58cb9c8fdda7aebdd4869bb4febbbcbea6247f983f4fb7e56775e5dbcf1d98e7368e28c3ea631647e902f5eafff6abc91aee608631f64a51ca7b38ebea6fd6ef241d2d978ce7ef83e42eeba07d9d6537ef66aa43d29ed217a90b0be8bd559fbef8f17e6413e785fa4ee7d32b76e737890ddcdd8d1f6188dd6fabd83ec7facb1e69ab2c5b59b1de46aaef321eceb2a9cb4eb202d5c5cd9cf4be9c358e920b9d5f6ae515b1d4ec77c0e30b26bbcb841d7a28baedd6cf7fdd9e91e738f9543802207d9e873b5996bcfe7a4ef0c250ef24df8ea3f8e76d93bfbe1205bc78f71cdd56cd1bbea1be48bcecdd87cf78d5138dd20db7b4dab4feafcd6dab18181d20659997b0c6bdb3ba97b2f4e23d010fb45c84061838cf5e16a6adfe3d5ef9a19286b90b7c1e8f5758cd471acee676a5ed4202ba42cbae80d5e6a1b52c76990d6d2b7ea5b6f46fae0ba6c08286890f5fdbdd86cbee55ccfb0d0544492ce20db74cc39f7b6afbd8cc1c65afc403183acb49f2d8cefd9be313a5c6590cff1b3b7bd8f8ca1c3d123835cebc2b678f1635a595dee8d41726bb73cdf3bc6af7de32592d478096b4c401183e405ddcec573ad67f3ce114a1824f3b70d238ceb417b2d0383747e6f9bad78bb755cbcdc2509c7a27c41c2db5cece675416bdfaaf6f39e2092c461d1ab19351150bc20d94e58eb64fbcc51e898244952cd6831a766d44740e98274b6d9693fcf069d73970bf2fd75f63bce151f9b75a26c41b2d5cfb6f7e8f7f367a70509b927756f2e4ecaef19250b727dcf9fb77dc6c5902ba4020a1624fbfb9a747deb37fd5a9617222ccc1c6e0d05942b485ebe9e8bff957953487db9816205d960642cb2391f63ebaa243173d8b380e286a46d19c3da93cd65aded2a48763821658bb5adece3eb38337e549096c6bae8fdd7b12ff33905396b5b7eb99f4e9fedbd45285290ccaeeadeb4cbadbbae7317961f92d49648123387db928edc049428c8faf3bec38e6e41a72b42415a57ef7ab052b766bbf8160701e509b2d9652183b659182ff5da865cd42d06996bb6383a779d20dfad86df8eb57de7da04b9da4d08fb6d331b324e385d77b3491ba3fc4c90ac4e1b5d2fb816f49ebf84179bdba13be7cc357ecdb15d70317d97b266eb3e455182a4d6b29b1edf5f9eb739020125097255473d4ea7cdee5b3817af215f5cdeae75d02ba4f0b2a8060a12e45cacb265ff2dfafcabb30f508e205d63ee5217e7827cfdb124b91ea018415e372dadcdfadef5586345908bb15b71397d57392e5743badbc9ae279bd01b32874204b9acf5a7ccbe6a9d6dacbd4019826c0e276d35faaa73b28d6948ae0bfeaaf5cef6d5b185201b3fcbf5eb73f0d2493f08b2ddf53a7a741c19af07027cd01b8b8cc5d5cb19b218e98d35aee82cbdcc8bc21f48d87345487bbad616b32849920439fc646a139803141fc866ae2bdbfb5c7597b9ee382ff117222c222d9c81a0f440429f153ec7bb2863b641141e486f9eef5af4d5de51eab84041433238b9f99c0f5ac66ea53b90f1798df0e3ff85ddd65174d0627774081bbbe55c6cf6d8b37c6fb7f5b531e88d59819203193bbe561fb2e83f21db09c4f8ede4d220ca19d23dfb90b5d73e5fa36d4e23b7b8070a0e24e59fcc3a8fd331b618eb784d68049223d0ac530bd833538671506ec09219f22d8feb9b5a77ede9e58e3fa68c864592409367441dcd626c049432a4a3d3729b37ba8636b22a449220b39343a09021292fda4ed9bdc78cb226e448102b587eb008691c05141b48eab336effe7ead2d8f3590fccf3ec28ecc9adfe51d6796972a5866a61010499a9942b6c70b1196185d804203e98f7da40dc6e7fce9729431e4fcfaefbd9e5f5f6437a2cc40c6d93e3e56e18d96315765c01e14316475d59dff57cb7cf1accd3f283190b09d7bfb189bfefd36a7cba9098d20cb4b152c5210961f2c43e615923433657ac900250cb97e42a673bee89284c3021430e45d8eba8594199ded623b224992049b39ac071418c8fbcd9fb7d80ce1b7b3ccc040f942bee7d7d3b947eb3ff86ac799c3996238b05f80f202d96baeea1c5d76faeaca1f1108c505f2d9e4e52c7dd710c2b71de7d92c0c142f64336f93616df3b5a597759c39b1bf38d9845c76fe5dd6d108d937dbd59d134dc84979b1bbd66d65313a9809f9b5bd2edad7fddbd7dae2d598903ddd8470dab75e6dfd65874892489258821861892e349ab98464d7deda5a5badced91e5a42d65eb645ead739fbee7f6ba1d1cc4925642fb6e66568dbaab0fa7d435ef8dc3fb42f3eb86a5b4ac84a9bb6770abf4d7e5f27216be4b6d8e30899abcfab2464bf355d7c0b19840c5e1a0919995b0a693ba7966fa390908d7eb7ebb771a417fe23e4c7866e3517595dd07d3a42b2caf5525b619b8d90d74ef7d5baf8ea72ae272364b5d551eada83edb3ab2f423a363d3a3a2955848c94bd5dbb48dda18b9e08e9f0fb19af66eff5ca0e11925d0b2b65f79da5d5c64348c6cc62ec1badc7399b1942ba59ffd26adb7bcc9b7721e4e535d7857de7bccb5542487fcd3d2e3703765ddbd352cfbd9c214182485273d60e7054815e57a9d7d8ae2f2ac8fbecc7161bd2762fbf29480b637396f9d1eb9c3566714841d2e52d76a3f3fa9b90b28e732b82230a92f2bdf6f18c96cedbbafa101c50909752e8d69a73b9e63cc227c80997aff6eaa48edf7baedb90d6f9d177ebd72f6f8bdd091236377b35cbacb5cc51d77176dc04e9d5bd77abff75cfefb0e31c021c6cc8e6d5bdff4166fbf6d18e731482830932d3e4048e2558908709888603f2c43c55000e25f08bfefea6fdc6d45fc7f9459fe78426cecc94617623c09104872fb6c51ebddbe38e91df75bb1c3a86fe8b5f345f5c43c6d67adae9eabc6bb1879f8fc70a49428264b05147ab7f6bce2873c7395a81e308d27fd9461d8b6cb169efebb8c46104d9af3ee7cdbdae57e02882bc975db76ab4d6d235bf311638d490ce965977e3bc31be9bed514204f9987b554a19afea6cbda221486ff7ed75bb1f2773d869c849699cb5ce6717218b2d04b9a25bef5d27ffb76527e402471064ed6ebf8f1985acb5fb0b0e20c8d86c73afc966afc870be1fc8b61e6b9fd4353b1fb3db6c021c3e90b5d278a3bdf636e735f7e4e1cc885c0fe4b5d0c277ad6d961d6b93079223b4ecbd7b6edb37753464bdf4c2689ba3b55cab15e1d8816cd3cef8eeaf182fbba5387420e9f55a7fd55a6b6cd0298e1cc8badc6b73510a6f53eb0c04c719b25e4ae37a16dae51cf38b66440f070ea4abed39aeb0eb8a165207210d6c4670dc405e77b0216b103a7baf5333646dfc7ed5d6fa351abbcb90fc60a55f7b5efff9621538c870cd7964ddd8b5f3b81833efdb97bdc5efed391c3690f7b5a5af19cef64bf9fdcc54458c3f088e1a4857233ffae6659ef641e7b06b010e1a48c8ab72fb638f3aaccdc790d7defaea7293b266d9332f70cc40fa65dbd65f66d9bef9fe882449d2879cc3fe050e1948efe5a085af32f8b5290e3164656c5156e16cd04d475d0ca463eddcdf7dee2a6bb7b181230c399f8decbfb5e5fc5e6b38c090cb9d597b909f2d43f83090977e64d89752c89637fd42b6b3bfec9b5dcb3dd7e60be46d3ba17fd3e538b2d570b840d29ef5c21b9fb7afb361cd5be12ec0e185bcf632b7cb5d073f320825691acdd484eafbd0172a9b90f332640bb6fbd662ffea99b490a40f71f843539551d184b4eea29d93e15ab0276d9990efe05cedd9399973cc8d09795bf35db12973d61d7d97889063e3c6bc9fc3069dad35d76c66d53e66efb3e696908db54bfbd5ebe66ad3d6cf1149e2b068347d4410062a9590f6da181df515d9ff6cf10d597fb6f6ef356c46d96294906ec217dba4f0abad96b9492ce898c1e81e37477676feeed87de6c9ac4b42d2079d1f84b6cdc5ecb5922449921439ccecee04954848e86f457e0ed256e1b70609f96e84cbcd66b71d738e3e423a5c8fdd666dd7ff4659c511d05d6cdd1a3be366d618b76fd4d56861658c5f3742ce3563b3f1e983eeff5d4648b6feae6336ba46b9b65f84ecfeba228cffee397d56921421bda757d7f8b2d56ef9cd429224492511727265faeba16dd5bd7e1de7251ecb8044d81c1b22e4b3ee55babeeffcd5361e423a56ff31a6eedd3dd36808b9e2570a1d743b0b21fd1db7fa6e3f5bcd3512c21debc762c3c62ef6acb435e73cdb46689d0721db45e894bd8b6e19ed2908e97abdd8ce608b0cd97d13a80442be76d6badb5176f656db69a10208f91ca4d5ceb83a2edaac87260e28f4cea1872e2a7fe8181dfb8bcd6b797b1c5b83b3d91aab7d66af4c680a224932a1e97a68343303153f48c7edadba7bd19fc2d754fa20a38babc2051bdf45df6d153e48f7cbc1b6dcba70b26fbf07f9dc837d237cbf4e299c7a90ce3147da9cf955c983bcd1b2b62033b34f8faf8207c9f755b7f65dab0cdbaa77900ceb65cbadbbf781fc4ccd0b743bc8f7d83baf0bf2656c7e1d24bb565785f7eb65eefaa383ec053bbad66c74f445dae6e020b3b6627c0c32079d2d176d5dd475a3973264f6769c8b783e3347422391192a7290b59bae7effd132f4fb71906df5b7ca989baeab850e07e9b05258fbabbb6b395e8ee5a50a167f836ceb7a646eaecb9be9abb841bac9dead153a5c96b5d86d90adb9daa8ebe7d6779bb1331a4d1536785cabc6ea3c52da7176a8b206e9abda17db85b746b6d03ba359a4754673a6d58cbaa9a841fa64f555d766a5feb3276766cab8109534487bdd6cac7e7476ad42d871665c1382100d92edba0ee9a28d32b8e8ec3807314285ca19243b3b199caccd5727fb93a43154cc2023ebbf0edab97c39ff2803953248f7cb2cbed8da63f6602583ec8feebefd5e7736dbe018245bfcb4b9c9dddc7ccbb11421c2126754c4201942760e9da3f15506390cb2d6eb166b8bc66e90c50606c9d74ee69abec617b649bf205b333a5764daf4ad376e4a54bc20afbffb4be1bc31c2afec042a5d90d6d2091d5f3b79d558e1679aa8137d66643c1f152ec8c86a9d6eb139f9d2afb0e32cf240167d3c239a0fa86c41425b5b75ce4256d969752dc81b615b5c59f3d5d3dbcb82848e1b43a7ce5f73db1a0b9259871e978514ce55d715e49ad5b9bff5d1b9b5efad20bd79bbe86bcda6ef3dbb21df2f7e2ed2c9f3b18d4ba50a10727baebbe36bdc96af6e786f9bb4c1becbdba3825bcf9b5bfff8e2146443cafdec5ed8be61431529c8c790e35bcc5e7595f98540250a72367daf354ef8a0b5ed1c0af2173fdb1ccff62efceb4f90ae7283bd1a9dacef7aab0d692dafbeab5f575bbfa313daeae8966bf1b963ae35c8cebae5627dcb586bf6b99b2021f5d7de62dcdaa2743ae7300b54d8f0e51dbdc57e6b41b6185bed167dd63ab665ce3dea5498202fe4e78eb3dbed4f6b9720db62b77d3b757fe76d3d0279a6228f9919474509d25e766db5b7f576b95a559220295337eb5badaed8b6790d59ede3e9dcd7e2a6cf409e0ee751e01145d0f45141829cde2e842e3a4fd6f7baca11a4730c5f6b2c366861abd108b2b13fcbf8ffadd80e571164edff17d963e57be7e3e6031535e4edc78f3d84af5badbfe20f548820db62f3b145e9bbda189c2a4390304e7b69acaf3a3b19d63464a48b39f3db5a431b5dab0841ae8fb39d7bd54527ac3708f25e66e75f56a12fb6fe802027bb17464b1f7dfa685c3f90afa375cacd97bd6bc5f781bced8f218bef71b4f05b0f585baff97a8db93973915e6b9fc17bfda1733c90ef5ca34eed7b7c56bbd190eeb275cddfa5af59575782ca0e64ecc7ee5346efd7677f3d50d181bced23f4cb9c756eda6e8b611a2a3990efde9acccb327bd88e55ce90eed59e2c5e165f8becaf8203f9d8bf638e3ddaf13eb32a3790bfd8b3edcde8f64e7aa78a1992556723f3cab875b7c52a65c8e516b635a357e69eb577027154c8906ddd6c303a8eb4aee94ec50692aee5cfddfd9acebeca2a35903c273be78e369c767d54a181bcb7316fb6cbdad7ae479531a25bdc16739199c7c8e06ac88c36b75eacbc7e4216556620a79d0c6fe3052f636d592e5464b020838f35e8e28b11b2e8ab39beceae8373b2c65c6b2a6248eba89bd03a6b17bdfd680ca45776ae36e7eb9885d5a98421ebc7c85ae566b1fd7d300c153024848ebd185d5c96be4aada40203b95af407e1f2f74a995da399010d1185687eb824e1d4a87cd11ee4f55883d15773872c2e6ea2f20249ebff3bead6ddd81e8d2a2e9070dafad6e3691bfc67a98a17f22ee8ff58a3d03a086f370b523621a9bf055d77cff5968d6c149a455690a209592d63ebd86cb5d7a32e3a270529999097c1d9adae1999bd90be48248a9890b0de066f9df19f9db132ee21a45c42dad6fa5efeb76cbbbe299690b7d9756743c613365742daff65278cfc8db668f90d0969bf5b2774763573b7a55042d6dbdebd0f3e7abb2ecbacd92464752e7af509ef6cd4e9654c12d23d748b5f5dee0c1b3a9748c8b59ce13b37ad3376db8584f4ca9a7d961da4cdced1474876695ccdb5ca95c6f6a223645bef9eed5ef4f8bc7923e4adf0c57add7165e69332424eeace1a4e7a2fc3f8386511d2ddf75a758fae5ffb154190a208b9666535fefd189b459b9208b9a86358eb6daedb617b44c8e7677a2985af56f69a4d3944eb08d98bce7d3107df63d8f445bbb8d2ebb1b6eb264c3184e4d7ba3a56178bd43ef742c8c69aab7d1de3eadede284992d44b602f6999da841142d6e7d65babb2dbdcd2f6ee83904cd75d74adb598eda637668e8e80264f0b42c2c87639a78ef9e5e62cf2202510b269d3192d57f88fefb3e84793480c520021a7b50c59f5c56f9fceef38ffa886723a229a9938a29919d160e123e50fd21ba5f735f728eb7e97fa41ce38a1a5f521bf685ff33e48379fbbf5d6f5d12e1a5f0a1fe48495fff25b7f99ba56f7207bc2ca6ed3e59ec256a11ea46d3ae1b2fde88d1dafe741b6b390ab8d5e9b3ed68d07b9f851d6bc36abdcd5ae3bb4f8b8ade55a63d89c2fd6e8f3f61e7c94e1e26aed2027acddb6dfdedaff3da5d4ea2027b3ef6ef7620cd2c5970eb2ced833d2861ead75bbe6202fad8ffd753bab8bcf5a39c8ca62846fe17cbb3cc21907f9e87cee4dea6dbaeaa083838c0d328eeefaac8ed6d7de20b9d785cf6f9d0ebefa981b24d3e77eede0f50a2fd33648af5f178db6c1ca06d9f1c59e71fdfbeacd710d10aee7fe60e4e7eedaa3cbded5eebb5ce7a46a90f3f5cf48e784f4d9f51cc4414a9c28a8647206777910a32006010000c3648c08148311002028201c8d862322b178346cf300140003528c428c503c160924b2589283388a822806420c20c018638c21464106c70a02440da2a4f70b9e19cef7efb60051e3f3f1d3662c78862bb247f1cdf2e14d18f7dab2172ec655d1e0546dc723454d0d56b1014950080ff3fc6fe122ed4db9000adc2d28e33c176df1f800b3a663d4623dde81271dc1cf73986bd7dd0a5c88b507008728168277e40a49a8caba000b083a310e11f66faf48ebe15576ad18e68adcdf6fc521bd59eb16391659714c0b1e8ce20ec86315af63392550619f817636be187a460c22ac8898a8164f0b8693a65b7f083472d15137197239e7f91780ff8f6d1448d9aa45aa55605a4d0c238848a75321bac4ae2d8a70dc66c14d7a7ecc930af8b1d4d4f309a2caba4849f629dea1aae7c4722ffdc1ec2bba014855b50b2de54a44d45e4596c8cbb69cc2805c0db3e2b9ee974233789a557ca6dbb99dd08842948c15d09f53fd9f88d68af596d347ba730facead91e94304e0b51aac95309179c4fc470a963ed41798b677b0f217e3800959d8e830df4eb02b82ce4889ef4d4b4d856ee86056ea1ae9de56864d7b8678cfef6ff33038a8ad12be36ae0eef4cf0b717c68017aa0574e7a86b3d6db0f5b48f14fc177018684bdb501a6027b6c83727c9885fb51ec26972ea9d5070a6bc6d91a4770c78bbad0615fc6f20670dbbb857902296c4b54dcfb16cb04a3aa8615a7b76b53004e309cc641da72e9274d5737e428553005282e07c8b242bdfd32bc306a25b1871e3408965985f59eb1154e43e6e2d07a538117434d482d55cc8c698c5787059d3182dc70110b817ef06e1ed247cf576076fd2a0d41d9087ae36db1bb9ca81dc2141f4efab115285507ac492e84da308e0e56b044814a50739f5ada4df24693fb0b5c0e0967c142ce97f49c7bea535b004855a57ca86a0cf28ee230f3c299db1d582c816198a61a04b56b66c04ca1b4a40d54e13664bb54dc333282e84289758c06ef2730b1ae25713abd0d0dea044eabf5eeaa973b0eff034e289e38809c00e1d0e2967056fafd2e64df599fcc7efcb8411fa25b681951878c0f8244153dc0ab3b4c3ad24c3f06f728468c319c8dca50bbc5c1dbb792eb1362e73d9d92ef15167e9baf03145cccfc547d4e529b24fa8b7ce604f4119b6b75e70712a76835d7ce9b292b6a87ab2242955efda7e97b37fbef8c0a9e3e2d6865bfe3d4a7fbc18f5a18e24bfe85bb7fbfe23efd08981f58f85ce06985c90d2768cceb1c3b17a6ca583f9017322d3f47b06701d913d074a61b2273f7f49d9e8e2e037d986640212fa368b452e869a2226491f97c76ed03e934f47f19ec3a2c12b493bab067b95d530469e52eda4dfb47640dbbbe735349d5344da30e684e52008f9708ce852ae98732e632f4a71a88ce6ff5120d9b04ad59a286c05166277f7f651f5456a847c839d40c94980668e9b821e33f980d61104fee8e7a747b30b441fb543891f36a90dce8318e62572f7ad0e0e235e584f5142db2655e16871fd0fb4d9991a398be36cab405db739439ee7aa9812a7db9ddfae7a8651552ea346b89b0ca14216099f7fc92ff9252a16f9a0153183c3570b4eadcde1a1c63dbf85e34be3bffadf6be1d5249280be54d3213e972e04745cc5086ac348a52d08f558f50c3e3c16a71c4e04ca914cc6133833c62cce318b879cf248f67a69d799cea7e58283f205c492e05317172d2904273c4155d348f071409d1bf87155922156e47decd440e33a0f7e99761556739490838f971ead6c4c18ce5564f899eca59801a0b5b35f7fce0384bd55b18b9fe544163f67eca15594b5ea5f66e0da2fcacd3c0c5c8b2b9d87de31065bd760701f790dc0440086483455d40563046157bb339950a43acb842a080a556e526082f48d293219039be76af9f5eb9e62dcde8d2bafc08b64d7d60a724e9d4d4523e210e3d98aeaa56a6c5ede45b91bce1d180165965f02e4a7584442412f6edbc7c4a22c71a444427a5ca306e3566f6887b4bda23aefec0474f8fb727ecfa74bed2676e162b8743cb1be3f8e0fa42f73d8fb430fce5e84a669efba3cff2f5764b8125be20340f617a5435517c11daca4080a5ec79c6b5e65db0c53263e3ae9d1d8b88141f988b924ae121b4772069b872ff29f79d65eed8d55892e800895a28a1b06177129d999151b82a8e898a8dba7df3d107b835d27b554737c23e3e147ca1649de9da16a89be1bad97dfca96178e2a336d0367b49140a80d2d1eb6187e3881120f70926e0c84485d759fe1a070d22717ab1fa4d7a7363fadb9998e8753c50e46ada312394bdd61b28dc6947e66acb6dcbe48df974a0503e9503d77e0d6c7f23255c7c2b0a5ac99cdf63a24d571b5b4ddae718fa4733dea5902483e94b0ba0c6d9bc434c76dd5720858686a7ada734cd7e6c1ba1b0424c3c922af253784e6c5f447156f0c71d867aa83f6e21d27e016b365c9552955d814daa90949f0d797aa5a4f655b94d27e361e87cbc4998ebd2b58304034e8a4007306aa08fa086195d3eb558f0e7f2915ff4c27814bce4f510259f163be87eee91261416069c4954f82c2bd30e06508d112abac51ce20fe299a835a119fb99165d79c6b23ada15e9d3523dc50326143f82a3d753c659ca947cd939010ac28cf1c9d75e1b53876ae9ec5eeb30aaf33e19b1b46f0bc754ea08f1fe8709a7eb8db860215f5962d138c58ed30ab3133993cb0447ca32590eb4b822345abddaf4fed20b3b81b402c31476e32b1df7b9874833428d5ee220dcd1b060ef4d74ca3abf2c4440a82720ab41fce6121522bef622914245fc48721881eab526179a673d210d87e4da64955d6b0032a6b2c9a42e04d80d204aa8e267ac5a4187c977344357c6ac375b8d43dad2891a316a8e58f38e04d2a19ff12b3e03cf5ab0209dd331a4e9af084a512713618b7168d0c3385590bebb4f0a68ed3e9dce61f30cbbf902f1b1ca2278cf3c19105c8dd76e54b58a1e1ee2df7f659bc2fadb5fd4069b4260a19ced4bbcf55e4496f4e2403f77d159452d1b056e49c91a10d1b777b996dc9f565581a40ecc1c9a9225ed0cf2380e0acda1f345c24ca9fbf6442e547ad2d9bb7d603fcbdb91947ff674bac7080e703d38cc871632896db340235628395141e84e41539cd42e05dfe2615505fbde921873447199790fa524e13dae15b221e5d2e37b8cf74545993ace22f5844410547f5f226817850fdb99e87584202c608090308bc03af70a87bfbab9812e8108925d0920984db94585436bcf706c257acb8129e30dbd93ed37a841a161c1734608e77cb246d8e6ad6ff4325072a47653458197423f76f164de23cdc219103ad638dbbfc549807bb2675ee4149343563e4a26c2a5b9334678c966e4cbaa161e5594e0d754715471dd1b968a63e66ecd7d4934806b6adddb48e642b320a8c3ef74b39597cb67af5dde7cbdd7c2a1257afd32efb64208d5570984fe3c09fb0bc442f788a6b028070dbdf0a39196559f489d31caa33422a9d93983dd7c4d506a34b682e7600239fcb2ac71eb19ea314591e98f2f5492dcbf0e801b884a84039165fbd11e8c4538b4af077000dfddee4b4bbbead33892fa00c3d8294aca8b1d440c2ae8febf9acc16c66b16233e4ecdca51a9f6e68ebd2285cfd9cb7c99a1ce181622ae66356d361510e6e7c1a145cf70d4417df93e813274c49f22a92a4de887cb60be898ee033fc684111f772bb12535f5b2418833ac7712d6e13fe2c9b3adeb837e84dc1c947e4e53a398b21ec311e2850a1ad062e239ca8a3ae48c127963e5287aab37eecb504541764c75a87ad6fad3cb5f13a2798434b47ebcec7bd833acb0a39d0f420f1115ce15597ea7cbd033e41ff7b7b246fc54efe5108dfd51af856361119dc4d016a4fb2ea410d6bf9997895129ca081a958db024c87abf78d37ac69e1014c82aa2fd37e7ca7eff82251b5738bec2dcf9dc56ff01f19ce4521d2be3e9e522808ab7168eac51b8d2af44b33dc3433ca08ac274e1e27b8072c3cde2b4fb711676fc9c6388089c0be2f51407d4fa31bdf0a5604f0404eb5e911e41eaf0fa40f6a2f34f350d47993d6d2e8797ca3326556fb7937a7f042765940dc915997acb011268ef0ae2c111d28c17d31dadf4d9b46f9f0645d3365875e625b344930a64a03e16dd8e4b30094c6e4c3066a98c677a0f0838bc4832ac64c1c97221463fd4821825a0a1b5208a1423b1e6ea20220056c57894f15726d081616570e9325fbaf469438180b1a05d2777255872c2a10dd4f6a4dc7db2738d922174e89c342090e32f5e5f6e01371d5a5d401b5d2c2f7ea9cce8c305fc95acf1db2a715071822c1127ee1590d116a0b12fa9834d5401bedad8e9202bf37a91c5dea915576df161066d7da54352a9c98c15c5e4f582831006b4fdc1e1a053a9d4dbd4cb98a29e3aafd289cfaa3ad9246c937336cfc65eb874b9a990fdf368d5b6768573c0462b402f26182511ad5998178ba565803d955b5e86edaa9c52eda435359c8f40ec4ca89ac556b33e2f61557824e5d252f5501465b311822720b42103c8a06c2e20eb9887a13c610c954242777532577dffc023f10c5aaae0f5deb7c1388dae8661a53a4eb6562f684b1d6852c87feead9508fce5ebe158a5372542e18d92843be413bdea91de77e86b64b361da5b2998126ce81ddeced2d52ff23e834b09ac9392a6f3658531f096899b50759ea8da00c847551e7854313bdc54939decfbd45eebb26fdfa6fb9c2243cae5c4fcac2a9dc10b934d4e6f2895a57f83164a83f860268f09331c8ef89d1d3033add4219c3e519c623aaa27079924173217f7c143e82a030c496184fd416f6ef50738abf01b82b610a2f4748c67346c3fbe945fe07a48e0c4443314bfea4a8eb7ca63528f8b80bf33e8306e684aca529e6c1c12ae0895052bc908ca827ab2caf4a456f0ff3fb37250dd5576e761b13452da459dba44d00e3c9be4ae16eee81f45c4b45d8cde64fb66e6792d0501d2cad35bed328a9b1268791b5c2c1103586144821639fd03568b6b5a1559017a69c717362782b06e776a7805fd6b73ce8a91e78d76bd63e9f7d348ca795779ec32137a10070694f38def13ec0a55e8acdac266a8b3de044c1647d9869bc17746f12408a8441e096aa68993616be7591a793fbd9c62ce0b9289ed26120f3c112984192d7ad2364d8afef08ee9b415321b99ba0cf683bc873d7c00325bcfabbaec060f72435eda68570a4212b1f4005ec82f6df63511b7920d763dfc42d87bea017dcfa66e903a7c97fcb30d0833f9f98a5d3e38cb72899d685620c7e6c02784b661c10830fe5ba48ec9f49253d8cf694db93f14db4ea69ea92d66b1b7de714ef1959b6cd6d6246b73ab16202e386dfa94103e5f8356842b426b2dccd4062ada9f085d173a3f16b007211ba266d6eb0d1e605dd5e4a7e3256363abcb25967027083f0ea1cb4a3e20b59db4108ee760f44d8b84f16a74537f555453628ef977cf9f0362538421338e0d29eff1dcafd850d0364bb748b7a422397e826eddd386e45499f868072f305fad8969ac9cd2a446ab3e6312467c93b8c363625266485290cca1de49bb9c5ae61e19f5e295c253518b451a6c347337822624915f77fc21d08097f949281391bd1b3fef19b7119c15fdd0efc1ec132a4f76ec7a1618f6fa0f70efc62bd99261e450ee772e43049977dc1462d3065e1c6025ffd48a1d70eede0913faade1a253b789921026979f0340aa19c92517979c28a48d248705d683714396f7862e093f61291c4079da26985fab4310ed9c91d4c41d21410e976b86c5cafa74e050a1750ab76ef46d3098d810853d994c4dcef638acdd5e275cab405a30b73a1b80c841e9806f0aaa3cd9d0ee813e548ede3c946659f9f089c104dbde37a788d2a750622fcd4d0409d5e564494bc23f626e17699729d7c89180a22a0195d79253411b4b250241d2f60c36cee476f169acdae264a3d257ef2bb6d59557ec5ada9d62e4993aad6e0b9a6745838dc5e81640b1131e889603909ecb1f9908c42bcc44ae356325ffe6d34b2864ca60165565646e3bc804cb5225e139d718cbe08e819310b99ab331752bdd801ab1534e2565b060741d468efd75fb1d7422bbe3eb27192a6506090a54a20f3f72cd93024dbd29851e4168a5c5e1e0dff01086c634ed494159c5aa852cb74340723d43f206614a44108430aee7bbd0e6deb09ac913d2e8328c74a69c123f7fbbad8291297606cc6dac980dd7aa5f42349607ea62bd0d0d9eaa96d148cfb7ee6f2f5ba29d52d28d9d7674c7d4056f578a8962aff774330cfcd52269a6ce17756e610bc8b17b099666bb6e1affd0f2a1b5b2c15069e6d26b20c2dac326bec8b65e51d073090e0008cb991304b67dd879d5ede77716ac5b69b8df4bbbf3b939f51214218b36be3bd2ff396a706805f7091230367f6d4dfb1375baa69bc05efb580776e4aab243a4d8729ed3d688f96df24fb1e09329c6e42ed4811d8f9e474f1088833172e758627cb9990c05498e86a20067f389795d04c963a14badb5b55c3ff86c6b1536c18c79e6591c20ab37dd30454b9c6a4b94f79ec6343f4aa6a9dcb79aef52cece01e2155d1a1a34ff55e45f6c50c634c8d12d193c4301d1be4510d0268561edbb549712da9645d12600a620d32a392590602d8c9fec027a864665475d5c867d080d5e2afda3bbd33d542777c808390d476672545f2cd18005e75338b70925d9a0497f55ddae19471f97ce4bb68b0ab7dbfd66806150eb70d47e1f46453cf0024d9a6d54e74105fad01e1b45f0a02b441e3b9b10cfcad4b05178bd5ece31e5ee566211c17f287d9d072211e3699696dc36b3cd8655730f1cb43461c9ee7c9d7e66a52e2d71ea8e26e285bea9a19aa116f6c94a1267a8a7164d04123fb9344590e5b421746341eba46d142060f37d7a2b0d97f5ad3f202c866ee0813bf5dbc1e87c68ed88265f2f380f267ee5211b55309c6c8329279a6d9e6d8ceaba21bb4a7997c3151bad855bfafc0b0814f65b98569628acecde3c2c72d2aadb7c31acc8b51e6096ceb05fbebc446400c0b5710fe2d3d3acb916070f8e9c07eeca57177eea0a2d4cdc59f78c2ffb7c4781ba4275681c101bd44f72ad8f77757f50c31097880ae3baa78827654dd2d90b704d400a0f21593a5e2e7233237aca0f7a8554f935812ad8f791d3a998b1263a90bd605c783a05ac46925871d708e8a348cb438bb15330cd6acb17f62ba1aaa8a2dead927e3822a1218c55b8c34598ec4da94b27555f39aa60d3ca4c9a6016731a94304d078ad5ce2f3a5779f7d119eb64284b06eb3fe05de564244ee2176ed24e24e9af8a54d99d665fe56edfe3c86ddc281d012abbeadd32c1b233320c314aa418684b41e8a0f4d58dd4be22e8d40a9c6a2860a4158e30f0982fc981b43bee101973262c837bcf66e0a7913bcd6971eefaceb07f7ad39fe66310182a1a9d46639c801642b9c2e85ef7694baafc0572de63086d49754ba939aea5fc7a2be5368e59152505fe25ff262b41b7e314b7b9b618493e35b9b73da3b22e1af2f2700c8927d25c837ed818a71454fd19f7dcfb5b00db3bd53850f34125507926cf70076413ad12cae56766b4bbb4f6502bd430dbaf74421b56ea631807fea2c0b2911f353b03de506d32f10288b24f8dd888a0a2a9885dbdfc6533d7fa3471aa3e2424614792e01d01224153551c035c87cdb09ac3a8d4e14eaa83c264712f8cadb022d0770c62df7300a24957ffef3c044ba735d72e114f4d2bead037fa33d168371ebc38204c97c341334413244ab3f0616ec8a20eb74677c5d1ccac6ea9a2fe2bb6b1c504451a4ba127429b74eea73528708420bc9866f72aa8c816d83cc482694def5cfcdfc301659f4735a3197907e5bf554e3e470adf1f721c6474a94fad09b9915f326cc6bac5cc2ea9b9621d7250757c6cf6c738050c9e4c2bd26993db7ef61e4cfe9defec0826ae444a600f051b67eaeae0cdd399a9b6ad36f67ecb1a0c6f3475324b9ac4d3419ffa9a94d8b01db0ec465f06b23f64ea4fe90ed80025067767394690a61d39b9f6d7f21d15dec51f6af3fb7af387a0b0dbf7be627c89238a0dc6d626c918bcf544e4a8e3b473be16d99ed2cdb03688c141ba5c3831adb5164f21b83695b7cf01049417c0865da4ae2c6ada4dc2290525a7edf957b8ae74a7139b5986cf6b574c5bf6e707c1451d15e53d8b7b45d35064fc8f0dcd2680bc2ec407b411f66bbe2e798be7786dae3e42ad13bb71eaebb933aaf76aebabe8adce8f314ff14aeb9ecb935cffa36afd3368f8c3f39ae0614e782ba7e651701f00b1b52c9a1c3b4d648612ad9b9be67668c4a5c747b2e6042962c7ae64ff571df58af5bcbf067b7f60ad4b32c70dbd3b1a960c48d6e6fcd975e65083f236bb8797488220a0d05a73dce40612898f42b69312c3128a08874a1469ab29d86c3c7fc2e2440e30cd8df7293fc457e14a05a8065325a3d08b9531285e8270ba8f2de788060f9720c610eb70318801c643c9f30be040a5fe29cf85871fc8e6a799cafe47aeb6a9a79015cef1692d2014c3ca12938b1e68299aafba391fd35c0b9eb0454373c577fef572aded0077804dda415bf9d5e0c0b3c27c0ba790fc3f879f562292f6d1227a3bcf70b1a2150fbec3ba090cc721984869d14cb4c65e2438d5573313f9cd866e6870bbaeb8229f2c39603791a8ba29afe707930f35e584972d16a312ae56dc771f2bf6302451bcb798f6708aa599fd7302b19667e3b1e3fa35d5753a99c53d6791c1e361cd2968c61a2d22fc8dca0b72aa88b9dc43b1375bfb006bd663998f70315e00abb9db9c076549835d913de06b0b9abd8f17baaad842c4931b56acdde6c6bd3e1c2e0118c25805a1d08db4a4b4cbf31d5f6097351a86894ad2401faa0f67cafd4ff2a4c9fce4b741f0ff73890dffa5a9440c16ad8a505976f31c14413c39a970167c16be2fc7171c0997eebeecd7c3c51208af77f052620c6e6c1b1301071202434e3b1467e6f843fd3c6048b2ff69c4ed9891c7f03c3bab6b35ca79738f3738c10265a334d54f41f753708c782161591f0b7d2215bf368421e2499c584f9b4f957685a25d6a77fd4e796e06dacad9ae857b523eac25a6840cc6c85feb319fe05550c6a88ad6b62acb13577cf3951766395e9d41a2ba8b582298060644a4e7ff06ebf05bbbae67fc73e7aa47c501c72567637c034ebf1a96bbc52261b5c74f8e69558d0f7fa9d1dfcdc4f0790dd8d3238799993e0f83db8bca0403b4a99ee4d2c4b19170c236d3f7e75b61a15b2e8d4157c9a3b241e1e9d7e365c761b017d0a57a781e938eeeec2559e42a60032eaca1a815627316f50ab7a7a83d1831a590998fa6141621a539fa9905f43cdcfce23ed8e6b5bc7a50de95bf2336b45510f2278543a6f4a4fabd133d7c2004b56ca802eb8664f431896f743596995c6679afe967b180162ee2c9f708c43d6e71412a36dcba3efb3230100cd10a5c6e88049472fcc72c0ba10dd0e54b00b4e2e975244571f71c5e9f3d3e8405a8024da8003f360a7440049e3f32046260fb654e26e5d6ca0d83674216bc970b9440033342588fa0216b5806e3f89001b165a29c3a4403be20c4f34c4afdda8a633b38ba9fff54dcbd6ec40a24e6ae73b695c8b8563c200727a6221c0b9c79c22153618937204c0c0df438f77e34bb2802a28dc58e13d0891f5475e32a102394ff3137db84b451daf0e6b197bf59da9e9c32244808b60b350b04f7b2aacbc86c7d7aeddb60baf17014c72404b930eec8e36614432abde32b3080e7f5297e6145eb5507d413911cd8b705f03998550c4a1c8b0882421839efb634e70f17ab2988fee722c4806466a645026c6471d302e13809b1c0a989951ad0ccbc1e048870cca08f88e03c13332b0c60f4c39b42347ac542ee73d48237938ce0538592ff3b55ce6c59dbb46738b0885a3b32422839b7fd0ebebc1ef60ead57e2f271d8a37d461fce56996743823fe8fe2e59db0ce0714e1bec3fa1daa79e54a70b4ae30452d76f171034e81c75030e0fb72a3393b24925c6008f0fb31cf2e083d3c20497e2a9aba88649d0f3e77b04cb347029d69a2ccc039358e9c0ca709826e7c8863a3d8cf6a681c18e4ee332c37d2c17751fe4616acab0177d3f9adaebb07fc00531f88763a869f75fdc141bf5ffde925c3491735a69878e9dfb6bef3d8a709ecc0efa4ab4c2e859f206d21eb14ae895f15422ae67f8aaff64d303bcae891dd8f0287fdd024f1697719bec613726b25d351fb0107315c5bb2998fda07684184e2eea9b36d7e5f4ca0af643219cb0b413bd5603cf9b1819a902b9fb14b4adfb02ebf4f08f04cb91864243ccc8be22953ab36b9f549fada160fa19b14f6887da4a63bf6478d323746216d07e800f920e0157af8aa82d432df0226eefd4757fbe962175b2cb9ba1124a2a96f8a5c0835da510993dd5e18c48e6972447328435ec1d9f538c765168ad0b1b802c53a43c62015d19b4917513297686e9840b6244d4e6adce9da3dce657843076d13749eb0ba95dcf741d73808b481bc59f8188693ac282f3f51e09c47d998ec5eb3dee2deabc3905583739afaf381f1d8b001da100e6e784a9ac343ad0e31b7875428813040d67e6aaad1f9e94979c2a1e265a0687f26f62766dbd8b1c77911ae3541fba8344b179e13d7fb9b04667c553fe261fc15281df8f7e2eb18cfd1f8113763e1e317713f50719a09b913d14a02fd9317dbe3b1827e0eb452b008899434f40f88b285ad670c8869b710a839650e3800bcb8319c63345fb0858a343883c01ffd7fd734927cf0c1bacda046c09d0130edf7f3ce3d96a3aa77b0b9b5e494e9b9710f1f6e21ce68a44b28f141ecfa41135c7e329e224032f2c6beb239552e430ee5c7a827ac33675504767466a3d9e76d5930f8244fa235c350bc358b975bad63a4ed0792f5a6f7d2e2db29bd2a4de31317c9d77e460c8e478cae9b9ab9350c0ef61f31e4066eac43a3c6866c004c3cf8d6caeea5696e265a63296d5a43007a46403b0d35f55643674de797f1cd799572796c4c786a136423d576d23b049495965abd92cf85c0b46fda352a08cd90a92f9b045add70cc530b8e487ab8abc21e12f3a9d05eb3b35491e57599f7564bc91035cc05b27a7eb4edf7e3186ef6539783d70ec862e267b1a919199e0beb3e993a0576f827af38498ea3aaebef7cbfce376253274d5082c60daffa0c9187df960598712271e14c6f8e2058b34e8e1646e4ad020b969beba0637d3bce46c6f616182ae6469acbe652eabdee536baadef846afe7b8ad1bb4b342ce9b8e1128772987ae31fefaca05e176921fd1f59dd25d6ba5ee3dbc42b484fe46c82600f7057ef79a0a5ac3b7818ca2f1cb2e6789211c3473bf37e0b9f2a3d73ffd306d05fd815a2f336b2d7d1f26ba7e12dab9e42f5804c35a9623ee5f34fcf7f02c9eba6fe7687f861b1ef667d6f279d15c20217c28048f623418ec671d31725019e423ded0c65f00a46190d46a78b854b2c7e643c279ba103340baa1fd9ea7144736981cca418b0ce75d18fb9fdb2ed673b47fdba5f3046425c72dcc9566f3e4c1ebbc2efa31a6d0c7a53ef8dae60122040e9788386d92af3fb45e13587edfb6420afe61d731dab902bcbeb94b7dedfd3c6e750d74afaf3c28a083338cc802de384ee69662756ec9d84b41a48c9643db85d39650793c5f3334297b6a99be301d30e1c5b40cad2d37fa50c396936e9ce0498b9018a8968d91ab02e82a27d51b3e793b6a7080fcc3e115e21423478e85d073ceac69d03e20086685820d664672b5604dc8bdb89750b42b34acc1a2228bccd66f0951963dc6608da410eeaebe4cd284fb8571b80220f4edea0d802dcd7311acfc4642a5301c58f499aa63a2452cbb473e7cc45ed925d8548c8b209ca0a5118d882d1d2ff869219c328010d6d411dd6c2ceaabc5c52d921a182e6d88133553505c7323430f9360e67a88a8e2234a9dfd1485dacc11c93b6842b009edc8ba1a2118e7ceb90d0a58b2b895b3bb05a25ff10d75ab6e5cac9bac2ec3c25108fc4736afbf691753d89a5f07148758b63e0893ee44cec42c31d5573e5b6c59337b7156c177e097d5cefcfa2cd2f020ce2942f6915df1ae7b76f283ebc22380dacaca756cf912045971f9a61d1385029c21a8254fb144fdfbb55d531f6d7cfcd18fda9de87fde75daf8a7a60d9b1c68418747e5159d65498175f700a82f90c3eb4d62fa98e48f55404d0b48c623c14abd2cff6ef83283b8ba1a144b1abc67282c9c01c5b90eaabad75604db4259ffc9b232c78416b6a0d8f040753a9156e394ef2783b0bb72c3f7d94189bbc80523075a9e0361d216937759d9c84225886a799c6bc3a729da1adfee9f0417eac0b2e5ef51584d0d2effd3fbb67e0723df4e9df4e01f8ab6827b14d74ce3a18df160c82279ec4d1cf9c7c545b9e8d5d41974002a6613874a993d7154ab4fa20ba5f7417ed07f893997de7d68a535f31aecd3827d38d696b396b522e549e5cce3ef21571e6a577806c7716891ae67587e503fbd208618b74ea9ad4c02fd576ade122c0c5f5179c36f551be0a69d92dd7b871b0cea6b5833063714f3980a6c03c3b58566fc2b2a7e2c3ea6339fbb7f0e3a70424065deb08fbab6fa112abcfcbaeca2758b60a000279f1d9a32faeaa78b2305d697d3472794e6b5471aed1f3f142c960c35b8dbf2c175470a98601d3aaa039a4576f7cc3e687c3f747f181747027b7c7daaecad8e92b8571a1348a482a9d134c5d99b93d3f27cfb0e71af5fba6dec46a40089a6e62cf9c62ca60bf971afc5dbe16b0c1c55b34c4ba80e891ae4ecabfeec0b8b2ec9806aff9367ef2d1230a802d932de1b226cbfc2d9b223410242b11ac21c98281a9bfa7c6de9affca34cba2ece2627f16c6a25e8b2669a43112b3f616e5ed808683dcdb127b2618f59fac7098399c922566fff2090759c661cc6d2821f893b19050bfbc6e1268c7606ecf27d26b6ac360993ffe201f889d5abb7f7ce0b0c8a2068a2c6b20022d9850f2afb5a085a58905f54ed56e8ef080160c213afc1f876eb3fe062e9ca8ee3f8dd77fe5fae55cf4b7c6533d43fea6ca65039fdfa37e06986f7eaed27750973e8c1771323dfa4d3228bb6ef3bf40a1d759e15d2d97b5095a91f59b8fa6525bed74d351614e7b1e99b91baf96bb4bcc4f70d7ea2804b47d6f46e64c0f771c56291a933be2f20c39a748b6cf25de9cc40bbcb5e4bd3f6636d2f54e851ea683e0c9b3806840fb75508c824eaaf84ab92fbbbf10beb380bbd3444f069e9477e5806ec8173a4e335d5f39c7a685f1374da4639df4b730f5960eb8b75ec672fc655f4a83df7cd73efeb31cfbe4e3d14f31a0d01f2a131760650ad4c377b3d3793d1c2e58700fd586f20cfbfa79c55daaf226a74814623cbb89616f016783922018b4c84d46a0383188beb93c54bd5248115e2e20f9d0f4b246280913cadccb1ef1b407e5578a62dea353a1bede2f0d9f8d019f73d78f502e3c9fe17d60271b355592c6184d0ca2bbb2d542e1de9f1caba01b540953a265b30f8d50e240a6ff45a5924bcd124e073b3f3b640f9923dc32c45f3df20c90307c3616e1bc51783d792528b10a60eb63f0f4251b41086866e339322d4ad4318692442664d4aa83a9340030125ec929950fd9319da3200184d36af9ec09831363198a8f8cadd7c92a0d8310a4dc19914f93a96f494819fa7c01a742166b2acc09b3906ba856356359f11c0da74b51cb91d59b7d80aa12dbc01fc127c667d8bff39d066f3195f99249bfbef58a7b6b1f13b1c5bdf51e535521966b0140e73a366a865a2595dc2a9b14fd26da7b4e69d2cae2485dc66d35929093d03bf4e1518f2608801a6cdc8df96a07b06d7b4c8b6e8e88a38116ffda8018f1683c5c70d4386532d1688fdbd4d9775cad4bf2ec1b88d5b4b5e4dd498b17bdf432c1711456b019ba299c5a70a8655f34771f18fa8e432b5a311bb4abaec1ac1e8e2b4130a9ac14a0a99b755fb9115156fa6ae89e018a5f6d73472c16b5b734a2763ae4be6b897b0a688e91db047bb7e65dbfb91cdecf9bb4b0becdc66d3da65eb7beb4f3ec4fc2083a78e724b3f9640c96daf0c4625c2ecec763f40e8e41965fd883184ace9de3b38aaf95e0bd51f22b8621562f17bfd6d3582e92cb1badde3e04a29fff5e0a7d9b95771360d32b7fe465d6dee34c7ba7b8eaaa51737e0044ca231d2ad9989ffbd60a1b7c2c6e11a07e9b44f4bbf9fd10ffe54f26b877ba76b6e522d355e89bf85b4a40a2e5c786abbd67ea98d7a17ad5b0751408ce2fe9ac0d33f35820ef15eff1284fd49b0fbe7e4e0e15408ca6e29d099087b1a5894697297a6d16ae813d182705c4e404a44faf52a0e82ad55f126f5f00d295cc8ffe894687bd47ef9c56001ee52c195c9f1439c63028feb624630dd958ad807b73bfee03d50fe0c2f1579ec85d42793305bc0f1f9d5008af230145c58743b95cbd8a2dbed372111cf21a353ef1e753806c6510f7968402a36122b41a81b70a6b56c44d85f2f27b30e8f09953ba66c045ca6da07ef71b9b5c7de3f3f9a6ee712d14809c690b8191e52801fc343c2e3576671c203a87e9f57e88f61721b7edba8fe5a3da8b054095d964954339da9a8bfa16c8d5ccb6865c0e6d22b66827f02a591030a8cddd164f4cd67fba8680cae2f4675613327378eff0a984d01373ef0d692866be074edafe48dfaa72ef23007fa0bdff04659cef1ed6f373c1129c527e528bd352e60cde7961b09b5471b2ef91c8c593e49e63b3ba13fd5839f814f655845fca7de51dd1b87db8a8cc5ac526cab904a4436ec35e4c815113a575b2f008092844cbc93dc1a6e4fbc3a6de47151cac5605567280e4f8aa5f317b639cd165abb1418e68cd1d9879d4aefce65a4523c963c5727795f3a9332fb658ba2c6a9f273ce2733b24eccfdf8267944a8cf5d7d21567ae1735a0a78733f0e5f85f24fcb71849ecd0186f9a71e006b5d6d256610bd0bd0fc1c1e4714130e29c7e6b3b49a328cf511773b224edd436a6106df077799acfa4eab59db91eee4020609726b33b2010932b199b9b6fa3d25fd84642eb28acf1714f1b9df633e6e5d8fafb2407421832453eba4f02420eb563e1eb0352164217c699b3281b807e2cc1f6426fb07a41c537a73693f5c6e1ff34122a8728c5f362a14ea3d907a431191d6b4617ecef46ef183e0e18d67b1fb466051bb3d77175e0842bf5f2f2693b0b58c0aaf62868246380d984a54f03176912aa8f2f80d2188d7d7fbba4c2f0f18a749661ee84ce12c980d21de88b5d02d27320d542d662875f3ac5e18c01e3a2884a9db8d77d1d33d1eb00117aa898b6fc2b5f3091e4dbde06160be29e9b8e0f5ad70f216b35163da855d23879d60ddd8e670b2eddcb736662e6bdf94e54b914c69ff4928536e5ecb037fd65a43eb28516dc43fa3b819d2dfce58f422b74c983ed1abe969465c8f88b2961b97dd4b0f3d2244c518ed961ad43c62c3c44496faa1151f35d9c80961165b10b8cbd57c32a0a75b4816a244cb416be126151a5fd363b900791612f18396f53b0acad1588a5fee610cd8f390fe190ecac63d2a1c28c03d5c443405c9bb6eb1c303e637054e819eb605a44737dccd8951265b3a6f731aba5d4c47286fb99104d8334823034684d66d5c826393391b53748e70f761c8093e7721d59d398bf454da97d616e7921b384dabec6189b95980fec7b62c7c0234c0cc6f70bec41c5da955f9415112751d10aee7584dcef68218070c2dc5ee191f986842679dcdfee9cb2ef9f0eccf1be3ef6008d4bc1bf72b670a1605a39bd7c6a0adc8e922707d2f9478c67fec03998e567ac6151a9a617e165adb74c8214876ffa47316e7ebd059280c80aecd07f2bf754a8db7e71844d319d6a263849923b788618f4e116b19e169c6fc221b34714d0c7aa27048a555242e9a8afbfb05e68ed0f9215495468645cad197497d1001c41502e3a5c28995f2a47d06d0e28b3b28460ef01382e13f3b8ce5aeba01ffe56264a7d4d5e8bce3f41bf2da1fa66c10b9469f98648248a0842cd5f91451a94873511479de6b82ea95502c20ced1362a2f49fc3cde8b66f832f87ea52e63b9a5cdeb028537a4feae13f0c2b6a357ecb098883fe574651f49cb3f1ffdfa1ba82a6cfc5eb57828f5440eb55677d5ea28ccec6522fcbb27b819604855860303cadfe41dcb59148e73120a539f7daad6a261cdb4ed5e3626f49bdde102824dabda94ba184b226260941ad45981cd5140ebdbe0116bf16b1e0052020a28938c7063d3626407164b6b960f6a350e70ebd6efa0451e76046732c2527a674e1ba1763f3de8bbc2e0d04dfbf1253cc79c8f5d6dff0c8c51a6bbfd5f53010e7ef8f09034206dcd94663ed9bbd8685c33c6438af44948a325076a97f347d1323da01cf6bafdb3a171107eddc370e31799daf3e45421d66d385fed31665db2a4f6b9f5be4f12e7bdb8d5ec04e2b546bef45d177bfcf069db01162a3487af95a45b395988b107289b65232cf3713d7139dc2117a2a76e09dfd87de394cb501d4926b349721ea771436fcf532df287b02cb9ad7b2f5cc4d4420ff89e67bbba692c9e14ecceabbd6e36ed6f7ee60133af7422ce5583c85f933b09a1cb0f35cdc70966c2f7ad6137c00c68fe207173bfdc896193ad4f410528ee004f630192d664a658febbf3beec57b6d21e9ab31ba9149b76395397b3801e9d02a58774acb6a7ede35873181a220f2f071d6374811de26b52b50d5a2225c6ddca70fc78a1d40f97131488746f99a00c6cc21f599f30c699b7c051ef3d38a6d833f38e3179ba6c1626b7802cb8111c3385c2574c20d9937c53d18fc1956d693ace7c0aff8e2230f166b97f353c0a18b1c721bc01927f2e44a69f532db3255c3189defc4f059232cdd4ef73daf1a13e164c98dbd9b4457cfea8d605e881ed2c9b5b2e7495e711c41109f5a039a9e813d72b4dc519a2830d31c8817c0a695cccd42d513b5e7b94118bfc6f28683ff0f362d77507800c3cf89bf9e0aaf33f48b923ecc2502c30ef4275c17de9b43bf23c6c627ceadcc95bdfa583f999641cdf3e2f22d4eca9d6e591ea89bc1091961d2215468513bd9ae35349c8a71f6a6a562e202e87f21846c92c6b159a1341e34e79d15f3004f0a13a1d5cd3d603146c561ef1862088912ced3513ff5abac5ac360ed2b18472ee48935f881c9b32a158545326138219bdac2cbe442ce775b82b61aa484a350c707dd81215c99ca6977dd8e0de7238eade6122b556ef22cb352c5dbb3f7761a12ba303b50958ee058dbe4662192f2a1e51d7e21e22fbd76462587d675ff62127b47102867b5f6527cd0e1b06e7ac9dc6320e3f4f51c591e2e7b08197450b97ca55f18b4552dcfa29bba9e37f9ef79a113370f02de97258e90aee61d0b8b283401e483aa69b4bca20f3a6ae3d6d881de3cb628cfdab8f56eedae474c73286860a6444307ec41d9c91395b552970048d1108eb8829f2136c044e44419c0811abafb6cfad431825294ed3dd3123b9189627e3f5dab29bd85e49dc7089d9f6b1d8c1750df71b9a717720c83acde99de25422cb76b2c518edc3ed15e5bec8b5c7cc8a8060cc32967330fcd08bd9a7e2e086ab49d1a15b64fa93647903910fc4bcdc2821c5b0be9de26baf4996aa377cbcea4b140275ea8d2d63093ec4f224e8c85982cd66dc3b2624b67df5366fb535b1886d15b7e9e01f7f15029d41e19c8dab409b4dcc1bb7961775c3a15d8ff93bbea34ae36c70161208c440ec98483729597a62cf7ed48eb439012d06e1323542c1db53c5c39873d9402624390dfd82063b158e7b070e09629b8bd028e5f2d2cfbdf906524e1b11b22af095596b355f5e748c00a30193bd94555b6cfcfe1bfc1fb358babbd3e31a548d728901169bad75720ad94960eb7b331c17c000979a5886f3ff010052c5ed8c97af1f525251280ddf640ea55228cb43f69cc6590a4539e17e28705e13cdb8ae3dbaaccb1e27ed09aecbe95078acc45d451fac87359241d10a0445179acb2c3410a659c39cfbd6f64ae40dde9f1759da7e1f853c57add373ea33199b75c2436aa18685bc0b4b7367367bc85ca684757d258440b6a9d65df143cf2dc988fa97bb83f550f459f1bf36c4f897ebe579f50d200c3284c30643cd8a92c2e89accbcaf662e70f92dbd275416ba556ed664887973cf3c7ca5fff184b88005941c92a4b6bc6904ea63020e9f2e695a369284e2d0389fc30d7017f8b2b5def77507948d14e99a352cc6ba24e811344cea3153643e8e088db3524eb9659897c02597f3c32e1da0c5b4ce3e05d051b73bdb1123284e2755fd35ddd3df46888bda925aa55a2a3c63beca96474b1ead63a24fcf2cd836817c0e2eb2ba86e51f8159698272cd19144171c41f5da0bb486f32fc26eb27e8dcdff6686427b4f9aca9a318387c05bca2d27ab113a2068a3ddb04c50e8989b9610a2b8878a5100cfe29014480e2cbe7cec1dd63029095f02fdb8efb0a7bad5caa328ab3256b436505d47bdfa6e0a478ce115c7b7d71eddb4dbf1e7361a29395c45e1db3123481cc3598ae45f9786aac7406b5876a904e5e0df244c5640cc684cd141f90f86b4b7fd88c844061c98e19c6e6208cd273f831fd2b6e56c3e36fe09c32f26355c202fb403d99f7ed04e7e425c1d28321b72a78f90e3fdafad4c1d670ca678f4ad2f402cc1ad8b73e60dd6f39078aae4eb5be1a32d4747306afee451b702b3b3c0a85b9b62c3b59aa712b2353710073f733f664cc043539aea642dff09311d420371ff7f21474e9c185ebd6890288586c9f8b6c4bbabeb9b2172f1eeaa1a08c376581e91e4ba5502fddb51463982f4299eba7c4d2c1aa27cc3cfd77b9046b248f2cf8c9c6a400c67cafac30bb33fd965dd0e7dafa084bc28b4827edca10e3aa93fb09bb434e4afaf7b4e088b62c7cf27ffe96eb54905eed6a6b6b82ce7008e486f67fb1afe96e2a93253ca966345b2aac7ec06225a58dd55b725a0f137b499aadddb1ed5d477817ace0339c5105c890e7090c13bde6c8736c763755ee37aa3fdcd3f8bd9f4a12c847cf3cf64f642c0b1579ce65f916a0f492aef7147178514b1f51252d7fbe6ed27bd1556ebb80a6aff955469f8ae3b4bfe3727e45ac9d7515e641a654c82c06d64ad134674ef5c8753c75b0f6540f7ec45e57dbba8b31b7e170dd5e4070979197418568bf7f2d739f6266df30932a52281646f2bef538c7c8e005cc5eb5d6ac7ab0d2be3224d8e98f99ea412e167050824e0e4dbed100bee8939e30ded7110e3d83b1f46a51847cddfa0b40345563d1c1f981d6b73828d7ea50e914277307f04ca3cab7573a8981c6247d093dade60c70b7be5f381ce13dfc2274e8669d1011f3cc904166ede3a07b81b3d11d3b84d4fe264e3998b69a33cf628c1b1aa6b63960c5cbe78f0b5bbf780919b8f8959098e43b93e8e5f25f8e824fa1337190fcece7ab9dfe9528d4d386d81d02dd61fba81acaefbee496992bf42d23449fac7f473b2089f24b007ad0231790370cbf4310bfbb497f3c78326cf9e7ace0676b20dbd6023d67039f87406859bbfac0ada3b71c4e0300e6ce6158769a5e29844feb6e1b7c964baee78e6a04ff741cde18e1b1333cbc2280883d0ce76cc4cbf6b7be6786584ea276fba65637dd87bdecf52b28c2cdd094c3967dd058e735d83ea9cf88f57748fbb96b7596eff1fb6b2f83b22be7593afa62bb9fb9dfd1deae3043c04af2e25ec92dd67141d7d0ddebe5fa1facd9653293cd9f769df986f4fe2af37442aa6f042ddc79875818db7d36263507a66670e6eaf8a0a53387723dd105ffbb7a82e90cb9185e64628ee9e9f75b1eb12effd7c58a4687ea44fb93b6a2a27a0ea6dd9f266975fc7d0b061cbd33e256029aec33b91cfdc1d5b8fc29c4b2db5a5c936c307004fa21a97243a694334184e941c800b6ea17d1a84d550d0067ed81880475c58e331ee0b721c1fb22f26aae9727e805799efe98e672829fdf1e522e93ddcab80275de3dd3c95ae7b9cb8d70a003731b0dc0c0c08b64fdfde45e79cc71c17f35032cf9f4c30fc4189b7b2b2eeeeab61754001e66ea8fcfc96ad713e87bd5395fc615d3a543801625d02ef015a5d491d9717e8774ba094a80713b30711ab99f2c274bd584dd5a1958cde853c12f482e9c9a358e5bded3824203d4ab3bfcbbd42d986da56593c79608c4381f32f747d06e50baf0d8a576b5b54cb62eb5da00cacfc901b43443616cb745b3124b31689393c2ca8ef112abe5f4efc2fec92cf9d558ed467747c06a999f104a3c75279048e5da1678849cdefa3f3e07a0b2bc38c5016da47c06f4965e376019425558196ef4f103a4522613ce787be1aaa589c6909e26ba4b73a3f2648c6a8fefbd237bfc488c3a979e830d41f4ba892230639a1f57dee183e5b22f93cd5b48d81ac8d7a702918020efca0fce7953367b291f25e6e2001965f4b067d30a6824907f71ba86f51d8aa19571155a0f32a79449db9fd63398a7ff39522555e52555e014a0088e3be54858b534127c6f6ac415bf16b0aba31ae0eb66756451e63173a70d49b31fc4a7158d92da82cd3e1dabd5720a852da492a500371d4885bae4c38d1ebd26baa843f17395584c837b4111035283ebbd668b3cbeaebe64abc96e68b901a0e15866728b9df4ea8b27bd58462faaaa9bc3f50448ddf7fc9e00a5b88087e40c03a1cbe6c256e4bfb2c5d58451f3fcc14f25955b4f43dbd6bdeefe24b333b4c13fd5b1baaef3b644d4fe879dcd817c736d44cd118c384e3a2719ce9f3cf32eceaebf47ed2bad8ebe17401bb85c2e602c6cba5ff40aab8e821b0078f35649cc413de28dd8f9452d26c7318f08ab61df171374d4a376e8d011d846259d7dcdf63d285a52704d90022574364b02a3d202ab81ea58652fed4a890f8f440810208451ab45c260667c8de6c47c222378a7bd71addeeb38e7d6c58e6a5f2b387089d25f2c96b6d9c9df34dc514be6e02c6e7be6d30a18d92f16f92e30047beae18f4e9a50e81de1c5b6def6927dcdec0e82463e348ee4bf43ef1adc8bcd3cbc60622eda6bdec5b72874b169c78678ce710388aa7209f8e740b4541c7c686ba36f6f9dfee90ee4ff655c172b7e41ae8161b0a6d82ddc3a315d2620782a8d7ee0869656c3b77dd20c5a0e1b24bd97d4e8d5f3d5fedab3e101f2e8aa0180af33262a611ae149de1f689f4705c696cf7cf9ba55c08e350ddd084daa3b17b0bfb1892eb72a930dd5a9e2edd12bd1d15a53cd2877aed93c8f95db55e7a326f8d421750cf50535a4ecc9bb178b2903a4f432df0645faf1eecd771b025f1e994ddae1ccf3ddc29211d64c44620c8fad9a0326fb7e0f2bdd5bee20bab8fb8688e1e9f03a22c884a1eab9c91ac1c1bd30ae1d1fcdc9a273945aff44b800a659b9a5e2fa260aa494d1943a95b79bd787de3b43d88e8be51664baaafc6ccb626d70d1c1d8c662ebac8568dfe6fe7bea79f63bd3562e43aefcd46b2dff4bfd0fc561a7c2cd5faeb4130adc88f3ae14e2c2d2b2db868d73e07c83c0e37c8e3c96c4df06cb783ea0279a8838addab349ea567463917fc42442718a5114016a0f20374c7073ea601185774b2b91518e980097df2c2505c0535314a44097ef8da693148ccf291c7934068b515019b7f0a532503703c49913eb18de65c03af04f6f4362429bae49c4405cc44474c8a3e80cf2d5feca40eff94998a7dbbc7a61c11f8c9c99ce35dfb9b061351e8c368ffdc429abdcf42c0d0ff2d17f89f00d89533a4a937768ff5cf0597d45340906f3d035006d285c1e310dcb6c1c913288a1c480defb0797aa9e556ceee40c2064cd830d64ad9d43744d5889f17efea0db53c35afd17a45c1e9c667ec9a53f51218b3f3ae3d29d8a2865d98aedc6c98826099acfd4866c256d7408d8ec013acbdf798c4d5ecc168ec61bde6349d00f54ca9c38ea00e20e1e7562becba1f31e5daac8748480c21448ef49fb05487a0c069b06e6da7e3de571d58d8cbacf5843cae7487c8b3545a44128b90e1c39f1db1b890ac87f68e9d8509d9418a96741071ce39a751f207d6ccd52fc47ba05936a6d99c2da1ffa952427cd769d48d370aca701717351bc43f2cd6335b7ea16351411c3c3067f2b2b5cf55397ea79c2408b58809e1cc35f882f7181030e3e91e26197aba87dc1b3b44e2f180a91c4448be1e672ffee2382974e870ef2149a144fa30fdf57985c0f5c530183fde8b11275062f23c7096ed6acb1b1ae7800fe2facbb6dd2faef0038f85c07b06ce1ad53fcfcc8b3b9b02d1f623cd5d8fd59bfef11925b5a7d583764df5cfc309bbe9311a482ea9622707ddbc8947d5fcffec64f512ad425369e211dde0c185ec18d19974ddb9ca25522a491626304324d5f056d6ee95c248d4a886ff009b94d501cdc17848b05afcc2220f4ca7395f38e015a224482676d9d24e4665bcd138dede9320874016945f1d27f31b13e1a651d72625a47a6a9a1fcc7e4a995a1d92b51064f3920511ef9ed4f9bf3b90e9a9c4c23c48b59eb27b9f99ddbde7eff7a1b94ea782b05266eef06b9ac4962141b4f4f0b78c73fdba402e7e31df0063a02f0d42de87d0d601ffafac396a1a82a25732828084f43a12b16c18502f372c3652347028929c6afd9c2d186ff7383ee2fd60cf32db3c6dc7f35c46952636200075667a23e6ca78bf903c7fb9493e97aa07e14df9484fc369a72c9f148577e12d959c2a9e746b8aad966fcdb4f7a3317cb4ea13e4f4c9f5518b168e290bc7e19faa845463ecd44ace77f54db4168dd5423aa4f9a7465008454570c0601830e09b46d5a82e769e31cdd18a56189edfcefa87ef18c2985f17acf7379d11fafc497c0346ece405e068cbc726d606ff0c8c00cb030719871c1f3f35e8e4544833a949d63473132e71774b6dad1b5d91adfa56ae5f811bbb3355aec277c42bb7a1b800b17bf7f6c951b6f62b92db5c532b651674ee05f60a8179cb2dea37efad57b0b21d296882715d3847bf7411d65500d0e23b518a780c19494b9a0ebf71c3c1e6af998ccd32878f760ce5434e798e92179e28ea325bc1cc207ef8d42633eff953574df9885679c8c0ae31b52fece07617d159ac662ec3c715881f6706a520ec713fa93f7795ecf999ff5e63a8e1ccd9c5fb7e39f1a52cf5bb8da6b7d01b817e91c94681a63d7b38a660c6d69d8e8ef3f9f54afe3c60a2f1ba9e148aa5f168867a2dfbf1aca7ace9df57e470233595737d87277ca7d532d14624426455bebb241a2d755f46a79b0f2a2d81899177a2249ac2d7ea10313e27e72b91d47776381abbffc4c9590baa048152cba48d52b6155b621a305207e92e358938058e5d87aa517695d57402f0b937fcbac352a92e0473b55e0efbb57f707646240f1112695eca023cefe620bb76a1d70cb707731fb1b1e4eaccdf81a5eaa0959751e696bd3b37e324c01265fde017afad64c9bc42f7eb77e99407b535bbaf21c21cff8d038b43955c0b7fabed275ccbf33ac4738299449d9c1a881540110ab7d2e817f980cc4efdf22fb5d2281d864bfdff83014bf70c69b914ac39b5bf2affeef5c06f0cc2087a451383cc70883dcbc21f1188e901e87f6b7e6df232475c3e46110ca1b0c7d3175e7e8200d81c1dd507f1d97feaa2418e5570316a517266e9a10bccd0e32b7a83e998614ee2fa4bb477a90ee28587ddabc465c5372ec6addd79fd816bcfe533d035257046315d97a3debd0484cf0afe33b30e03fb1ab19c2c557301ec29992eb003319849b044f27952d5f9b4e7c3a9382d3b94e197f235fac6401cacba9f7cc6bb44a8ea533bba70318ee55cebee9a84ea67eb15117fd77e604bc1623e7b97246ac4433573bc14246ce9ea9b83d3eba7c142d6cfaa7e67a2cdcbd15e0b83c0d410d7e8bc8f369c071846128b5c4fcc7c7399b2e3101bfbde2f4b4f89de7585abde094f28291c80da70ba7fdf8de7611374b30dd714622f6fffb88bd11a163b9bbb924e4d5dd214239c43ee627939f762a22557a6d370b4428cfac06f86fecc0c91666a90bcba0bc6ed31e649790140bb3b69841e2f9752cae101d453e7ed5900d1eae47c473e8579b312da783ef40c621c6d5155abc04854c7d4be7fe450c01aedb1ddd27326f6ad4abfc0587f67e921004bf56d2b219a6ad06ff7ee80eb6234237fa6522726da7ef2df432ffe6989cdf663a25b09caea80482bf61674b81570237c9f4968d70607002990cdc3bc6225eb10d60d692998cc945196afff6322c81f9d8f6bc57cde676160e152c3bd8e603fcb7b2dc3d34224f04248fab139e99bd3065f76f795c25f245d8e484c7ae349eff55b270236c26277cf26db07700d0e00ddf03d8612c62f79462e40490fdb373e5684c96ad75753c2728916f4bf6b9e2de5a5b0a420a3a519c497f5bd0f6638ac0e0dd41ffac81bb5c61bdcafac49767695e87cb6c1e489d66ef64903827124ab30d41f0e36e5e04ec1bcfc0e7f538a4dd4696997afd3fc64e5cc7ee254bdcade7cf5f1f0909654678b18a027faf9f5268ffc1016f4353f12cae18b988c571e819bff3b0ffeff638a46a651765d12a1426dffdd97c07fac6cf286179e2297564159de4d619937c44ad2fb38fd80c5a58e882e8920413f4b02d07c2cb92ebe768b53a774991664fcec2c4a77b82edfeca914061ae2237dd23e8c67b5c2081dfd6659714fe8e8a322d5c1c0ccb7a290b6f10e15eeef431c54abe20289e9ea10715f55c9d2c2b14340ffda887f3c8020347ebc7c412b973b8dcbc439fdcb6accd3cf159690f79a5af551782454165b8359a015fc3e5703b430743157634b64e7be00a47a89178f265b26663c31857af0ae37f0197b61a0b3a707bbacfcf56c2aa038c8bfe9b676dc8a0c7f42fcc442adf1ac5b07fbd76579ae0424d96e6fe0242d470502be1a607b35b984e7aece20df618f4dc639eff295b5e50e57f186b288d67e8622f42935c44522e8535ff01b681ec61cc1d88dbf6d6a777acfe862e9fc433db47f0933afa88378a3ff940ee1afd9e82e4473c3a3824e1a0d59c7a71ef9109b32a4b9c5fa8dd81d6f6e150a940ed23e9f09c30010bcd3de813b845e1af6cbc368d5fbcf08aeee1185f781d94fa0bf017247e069177603e512f468770655af75ab52b37ca4572f969457099fbb0c99cb4055fc862547988889409a0946b1d27ef50c0b006985dfc431c419a93978c66a9bf60373983b9580506b79df86240f6d9c00d4e7af162d52845a09b1260206bde72314db6583b7bc0458697191f872e921c7def7a786d3013bd0df28321b2f69b0b103abf4280e5d50c3023c59fd823722090423b4e8e56759eb463dbd2fb22ef63ee72cbbdecac5d60774ca81b6e899606b793786286e56731499dfa77123bdb7cdcd1022e3bc06092b9d8aa9f75e601883efa8ffeb008cab7574fc67d5c801b31ee5702203e07b51b932fd94cc4dce77cca260dbd316565215233c5cb87ead4969a8a45b62b26e7472f63fcd43439e8ee5dc8a5877d6fb17900cc6377543b178c557a276ec704c90d2a423ccbf0c95759cd0d6d218ee2887f6b87cd6b82077a1bac195b9cfaa8b320edf045a91a62907fd97c8024b1a1846bf880074dff74108ba97b17878437aad6e0067eebe94a32bab9a12d0addac2bed6403abad03189c8e9d7c177c2b6a8eb8566772f78339edbc86e4fc14da607032cff78fccc4ae6b04a9623282308a6c8806f75c5053f0b8979d27ae1d0cf58efa6dcf4699410e8d9c9112ee45db32afddded1e1a6d914a73a649ae877351771535f55e1ee0a9d58eec55bae8044f07e96850f9b8eedcaecc936f55944c1acc6e33eb87961eee5df903c82ed92b5bb32bbb9b5a0e32cb76b729b716c5b84b9c516b64f1cbf7ddfee68dc7b2c28f8d7d19f0ef31081b92b92752eca9b44463d83b89fe7efe8eb6c76b8f07107f082a925f5123847e2fe9b5b8d88a3263dfbd8b34e0a55308ddc228e696acc68afdcfec64d790032ad8fea50a11eac48827c5528a89e82ca2d56087b03bbc1af6b785cb185f6ca60a39951c89509ab0157218a3f0991e8f1e1cc60ad0fa993091b476c8a4368de8369e58a5320a541a2828f7995eccf1cc492e5c65faef49f56d18b845a649b235c114bdf9e887974f59320a39a13540e8b5b0a0a572ce8f986125233e0dc81bc990a2396b4f56b32adbdfc530bb036cf3b013a643f89625d5a96436c731f13f74c9646a095271ce4c498a9452b865f0e46c7e92a1bd0641e190f7140ec27369c20f5f5cfa35f1a0ebc000ffc60443a5aa57caa8cac4bb4203ef1b4d33500f4086dd75e2083cc3ca2f75f5d879643c6340af8c0d2c02418205e87d5d0caadbb35e62208d900e360c943a6c2eef282a5b91f9b61fa1756f9463ec5d7df8642da513d9b046c37fdf16b1a685709215c8c13dec98170fdf851b782b7b44e61e968ebe1e8bffe77321a237d80826b6e28374b2764f78ef3b945bd21e6b9bdfb66fe508a3415800d2874115c817d0ef3ffe74991c7e9aa8ba0c879e27a0d01aea5f2bc59935de65b5bb9bd6b8bdf9c7c9d7adbc222945ade05d6fddff032546551a5f5b7f9cbf469566d0573dcf34557df86cec77d499f7b5a6b6a03963aeeb2742f07312da237d55d0f721c466e1fc4b4aa85877e2edeb528b24b61ae54fc13c54d60f5fb8bbc81de0eb0cbcc6b0f45ea4455fd5096478e7c8d8c288f12ec2bca1379baac813320dcc126a9eb9f115d40fc75c106cda56aff3cdfcfdc90668b66a1b8441c1529681ad4ce7487889a9bd3414fe4e4a138350c598fa47f480f473113472c1e6179c85c866ab8ebe4782bd379e8df9f2b975d423461efb0b17cff805ac84916ccd1ce87f34e4cae2ada5a057a82338d463078c891f64a5335f48698d526adea70c63ba454ebc6a279092e3333ed47c01af9e8d873399b80af16f2fde3b3e9bbb6863c12d0371dcd0d0c890e7da3fce8f111b227fae0bd095913a5ce3f25df18faf014cc9266be79865c8ff61f3cef47179a6d0ebbfd1e413f4842ba01079c24a9e89f22e33aa3581edb379e27f6137baa635ddd67ed61488f7ddd4daf6c011c5f62118c9afd46a2d3765b3adf0b8096a9e5d99168a4d18d036fb55227fae97069a9c691d24c641b4a63cd668b3f698ee0a4caccd46b6bc2a9de3a26d7da7d9ea3b9f12c1f9db3e7d755a6bb6f26c1608caf78b1176a05e7c1a63e55c431c507f141daddf14ae79141cd90c91e5139ce748d13f3fc35de6bff8e7ee4f7952854e865d32d688b5c7449b1e7daf056761db3ca96860ea19f7fcec534e78a39d1997535972de97e1812bd8c9472ef820f2216733f64f7e29be6e9c797727cc04a5f6371d92eb46901b62eb756d6be9bacc72ca540a309ff7b134c7c0be1e6c4af32cdac3632729dca5d07462d40d30ef5d70c97a2723c2493028ef484860c3560f0547230333333333333333333d36c6a6eb81c6d37c99545847b53f1a132536e4a2a55e2d3b9d386bf481bfe22fbb7ddec731a04e90ba60cc00c4984d1ec7144512ea743ffa83bc47a1a51700f21b98799b0791e461426b5e31c7c904514d3448d7daa5aa6e428a21c342c57773ed67d2711e5f4a0d2a3cc7e9cee20a21051cd55ebd63d6be71005eff0234f1d7c64751d4394cc3ffcdac47ed77821ca23493a46c9b6a23a21ca1e9864cb8d49fd7c10c5701f45b876928e1941143b7ef02073596ade8128a7bdb348e21fb6654094c3d29c9366f30f65f7e938c7c1478f6afaa1905f5a5422a6b90ce943c97f73fe40c2d5da840f654fe69ad371545991df4321e87fe60f227a28069bd0b8fed14b7b9f8742ccfa72eb1b5725f77828a5a4ab0ee26f78aefe0ec590657b7307f770d3dba13493a17b26b1e2a4af43714fbd537de9871c870e058919bf6eeb3994dafae358f26dade6e550f83856b266cf49cd8f4329bc7e7278b2e6928743e9ed4534dde630c9bfa12021fd9fb1774339cad4c455547ac6db507c0ff197f716d7391b0ae6c9d63269ec59660d85c96c665dfa31075b0dc5e49ff193aceb764e4351620e3ab80dfd60c38e8692fb5fdc6609922bfb190a16e593e1f383bfd6cd50daea204e3c2ecf5a2f4339daf0a95b09d5137532147220539af63b52437c0ce513897b92471743214f566a0e0fa929f43094ef443642f7a26c733014d5f374359af544cdbf500a8f63bfc8185c22732f9423f268895e9a644e174ad6f16154e4aab90f17cab1f5c7183c3de6fa6ca114be5e1e8c86d3f6182d1442c86778d7594d1d9385729c0357fbcc394afb0d164a9ef122bbe557287dc72719c6af73b431562875989931f5b7468e3455285fae4a7e8ede3b27860ae5db2bf338dafecb1033855247d2e01171ce4b34522868be8e7b3b62d0f4992894343f6fbc9dbb4ccf40a1183c4476fca48feccc13ca91fe2e25670f2397714231c78e39398cf3419c4c138aaaef2f1ef8760e25c38462860d3d9ac13743be84424c47bf74f8d5f9e35042a13e861c43bb459ef49184728449fe943112cad1c38a4919723b478f500e25ccbbc79063276a8472e7b8d2cb25dd4b528472d8abe181aa67448e08858e3ac8f598d47a6d08a5f5c06d752507f5a94308c524639a1ed5d5be7504a198838e63e6f0c3f3b83a805058d320271f678d9af383a2c585048dd391a5c70785d20d9f91ee41395a49b9ba0e2bcbe541b954b2078d0c9be3558b1d143bbbc715fed61da35ae8a0e86d113ba7aefd38548b1c1462c65fbfb7d597a816382846f0f03918d591345b8b1b14dcdc423f468d3196ad850dca39baba6efb241d86ad450dca151d556e5adffe6a2d68507c9f78e629f3eb573d8bb2c8c96a8fe5e4a85a160549f9e8c3bfdcb053c7a258d6eba1a45d94861a16e550621e721e668f3eaf28ffe6942cd53c5d1a57143cdcf06114cfe8f4684521ab07adaa7152869a1585f55d7309999e245e45218a7dcc6fcf70ebb22a8a72b6deb13b1d049753512875d75e8fcb3c321915250f226f089153ee977c8ac2bff984ed8e4d5178e9f8b6113984fcb814e5b6f7f03e68e4468f4951b69ee898f9d1c5453c8af2abb9484489dadb114559e7f43b0edc3fe50f45b1b3739c2b826dfb0e8a8286a0e93d08f39bfa27ca7947e3c6ccac270aa2e1e33c51d783c9b19d2854079a714a2cd4d3cb89420e956ddbb0efa1de4d14524d79b81e8b87215e4d144b52460c49de4c94254fa45f5bbbf3208b89835b7cdc74e025ca41ee309fd7fd5c9d254ad1816b44e4b8ef5925ca517aa4b1bba67b19250af22bf9d77eabfcda4994c7f63c73aad8c8d74aa26459fb219ebe2bae8d4439d88d78a692eb632d240abe11d2c38fdaa183f611059933effd5024f2ee88b2c781a49330e95cf5461437536aeea435b9378c28e86a687b1c5446dc2ca23ce1411e8fe2d73c0e4514ec36797e8ccc33e144948366bee5871073be882869c8d31d73daba871ea224aa2fba1d4b4ea31aa2949b23424d0ee2c664210a75f1615de29f7e2421ca29e6390892a34d6d0ea2601d4ce7c72107fa114194e338fbe4489a636318888287dfdf9373de9ca102a2b491fb1ee7a3c817ea1f0afbdad962dd618c9efaa190e2d3a9591e7964691f4a561de610a6a6ee26e543394c7273b8d57a7ef65018ffbcdd1f5bcee3e8a1e8d991ab4f43c78e9387827708fd295f44b3070f8510a96a543cc81d8a214e4bf89bf830ea6987927cb41a3e54f19836598782984d98707ff7fd9174288739487e9d4731b923e7504e9eac5dc4964321e968981a49377dc6a13c92b7c3daec2952040e258fcf52b2e647ceee0d25adfaa0a67cece3e686626e482a6dd35a6e651bcaadb29d3737fa934a3694fb43d209d72a9ef23594c3cc1faaca739b6fd450baacd30d59437c3fd250f4fcb9a349aff38e030dc597ae3799fc7b1f3e43c953c60871e632af6b86a2567fdc1cc7d1f34aca50de4d1d5f8fd1fe236428649188d4fe64a21d1943c1ab3fa7fd2d698f2262287a74f4f499e3fc38270c858f8ef020f36028bbc669e84f552dff0ba5fc3839ce1ce385b2baac24f7badf0fd385625b249fec12731e860ba508297164f6ffce630b45cbf99c9f9bf07116b550ca5cd65b2f711f52cc42399fb487fbe183cd12b1504c1d27fb103f885213bc42d1c343e89c09a371442b14d2e33ba4e679202356a11c87e704e97866a38854285a59f8c739eaf7693885f277b68efd8197840ca5508aec9511531885f24f0e39fadf1c470d2114ca7973f4b17dca84e8794279a4465ebe93eeee8462459b5fc7f9dad326947368f9aa5e1d7f920965f97615890e92de2fa17431efed9b99437b2514d35fa6cecee1666e9250fe507395d00fe6c320a194217b7dd81172708f23143cc63831b91aa174b9d1ca62223c368b502cf1dc7f298f08a5d07c61291dcb72724328a66ff6d81dbb5489370021943d45f8ab77f06184378020142cd5ac345fe6b5bb0100a1b09f29226f4e8ff719c00f8af996621f82a4c467003e2884e8a1c7bcf192dfd8007a50acf0a859b9edcd616c003c2847cf089247dfc46a1bc00e0a5599ebb3464c9bb20d4007e5706bd345f4eb07131b400eca692a33e72ecf66a20d0007e58df4b0537b42ecd0067083620e395ada6e75b09f0dc006e5aa8f3bf2edf87acf065083d25ada567a3c19d5b301d0a050e53937722a8fded92c4a96513fb9837efecd64518ec2235b787f7b98b25894279a4695fcef51cb60515c7df5c9da817749f68a82ec9aa8bca5df785c51ea3f0f45ef5e7cf76a45f9d5a3334dffd368172b8a99367c301fae551453bf27d4e67844df5245399799857d30bf6b2b15a53b4f1f457dfb785aa8289b4fa79cb03bde91758ac29fa708766b3b6952a628e6f8dbe3e31c79ccb14a51b498ef2026794eaa1529caa15855a40fdae3d46a146515d18ece218731ad124539f0283f316b6d8a5485a2b4de61e319246e46058a72b8fee94b4eaa24aa4f14b76f3dfccbafd5c713c58fd6103ce9cd69be13a5159309eb784e14724e57771d62b26fa2301d67329afe4588268a3b9d52ff7ef3789e89d207dd59653ca67e0d268a311ee6f19a0b0f3f2e51f2b7e9dc816f52dd1265310b1397541d845d89b275840d0ddbf0e552a2941fddc4bd6ac87712c515b38f5a73b8ee114914e36d865d9e969d9128d85766be76b2fe0e1245f938eec34f0edbf388721cc1d37b7c5a0d3ba2984ad3f6356b44396d7fdbd78c285ae4c03a9c0f1f8544025844b1ece3cb666a6d894711c5ff384d6ef45509994d4431c3a3c8ca0eabdc534414ffe3703e994ce86c92000e51ec510d6ae9c1cdff638882c74aff648e2f4439ffef47d16cb631c70980108c695b4a8c90626432db6a34fa4c3f96539d0ca2f869b37cd863d6317544a0035fb0400082286e7ca0fac977f5ce134020ca39f238fa98a30b55f3b01c080010856899e4a259baac7201fca1982d82da5d64e785afe58762c8f371bee3f41ab1838c3e943d7ef851c6d59475980fa58f0e8bac0f3bd66cc9f650888edacc39c89c6e4a3d1464d326d718593a72270f058bf52c6f8d9273bb7828648f1219d1bec376fc1d0a5665fa9a77ef5673ac1d8aff39a40dd57c4909d5a178abea7651d3a118f2111de9781c55633987d2977cb471f3c3944e90722845b6c4ec13d66f2b3cc87128deb4c71cd5f6519e3d1863948170288412fba8b5c483952880375c9b3bcea56fde36461928b80d08c00d7c5c5b842b8bd0d4da18f38a3ca32102684339e79c34eff5cc56522c2f2eb00013a0e0040d70c101c820a327e06220c0860d1b25003614253f4701f987c27af2709d2cefc5c30fa50c4dee31ddcf6fab3e9473189f99ec4c3dcbb4051f8a3998f7384fa567ef7f0fe51c65cc61cc933dbbc57a28fc64a7db6cb94d855be4a1187d32db8732d31d613e620b3c14f2cbadea7a2a73b7ef50700db13ac733fa786b8772a4a95a23c7ed5d626e5187d268d428c944bbe3965bd0a1e021848d0fbd3387424d8ee3b84ce57adecba1e0516aff9d6d42be3c0ee5d71ce6d3c912d6240387a24608393e0e1de24ff78662d6976eabdf88a3714341c395cc77dc59776b43e935ad65b5254245c5aad8820de590446462f489eb195f4321648fb5d5860851226a284d94cf25e7712431c53414eb36468dcdb6404339af94f586b2cf9afd19cae1296a34b684281b33943d9d5a555ac94c865b94a1743fa1f512fd83d6ab045b90a13caa395ed1ccbecef4184adfa7a93f7ee924411643d1839acf16d97379370c65bddde8d9de63a52179b6004339fa5af3a06c3e3cf52f14435f87f412eb3cc8f142a137c711536e4fcce9b145174aa393939947635f625b70a11ce7cb103e62d88f740b258ff5e34c269ecf63af8592e638656dbccc4ea7c94229f263a6f6523d2e1b0be5f6fa2b9dda9b8ceb150a2e36bd3b9f5229122b9473e326ed94940829ac42d937fc6cee4c591f795428f54832ef48f5f29c2994e3ccfac8d4b633ceb48514caa93639ba9973b54c060ac4f882b68842d9a303d94d3d7edac930da041378172302fb2e4618785b40a13415d7e1bcd3eede7cc34c182e2003b77842e123e62fb777f5255b388151b1c8c8329349933226848c7a9a42c1164d289566fee861def1386daa38b76042f9c38f3996d0d418428880093cc00b0554c00b5286d8620965978a4a8898d4325fe1417a87b173e0b659b35b28a1e8a6390e2dd443e658dc2209e51cac84ddd41ddce46a0b249456d26de4f90b0fa34dd07634d8e208c5a8f61fc97af2482118658cd128c00a630b2314ae4389cc1eaf35e4fc2d8a50ceb15b0f3cea77faeb8616196590d12628126c4184c27df4eb92e4e7ee7914dcb1c5100ae121de47c91fbef94334bf02365b08a1187eb222e43a67f54f60cec790800db60842a1b3667cdd53f0663e032928266830ca40c1094cd516402898dc8eb58d7c8a30193f28e6483a775278630b1f14bccd2fb35cea3baaa9c4d8a20745910e365a8ec6ee98048c2d7850d8e8c1e7bff32ad573636cb18352b876c7fe61f89e1c7243eb8b32b6d04161af63c6f49258eb4e0c0b44c0860dacda2207c5ff1c76982d254bfa67b0050eca759bac3fd3d548e76c71838298ca6b4b68c94cf1163628468cf410bd6f5183727785aded798e51e32d68904b494610f78eb950b9b28f24b3fd5317e9318b627b07752793ab738a298bd2cfb706cf3ecfd9cb860dfec18c5814d4b2c3245233b3160bc440800d1bb0a8e378ac32ef75d840c12b0ab719de83bdf8c8dd7445613c46644f7a462b0a2b6faa6fb62621115614ddc307abee711c27dbab287ce0d16373bb3d54ac8a729ab0954ab3f1ce4152b1c9a490b052261dc27d6ccc9bf6d3e35051b60e195a33b91b5aa7df04658821c618163841ff18659011810e7c818219a728ed77646e1dfda76607334c51d45ceb81e488f8724f186694a2b8be39f4a0b63149966790a22039d336e36a1c8f232d4751f438b732685c45510ef2965a1d2222263714250ff3d6c7955c196f81329e0c27cc0045397a583f659ff93a0a3f51bcc8f039a86a88fd314f14edb6dc73940c0db9ef44b935d6d5addaadc71927d88a999052b2c887c7b76887e2b1e68ff64d147eec3b3e08112e398e2654ad8a99d81eebf16df2f2fb61e59b199928777c51ad5982788ed30d2d177c09bef02713e384d100264c1442d393a6a45fb5c42e614ceeb0cc8ec91115c1325c7ef81cf7857e382d5188397efcc8c8a944c167e33e280fac3fce295152df48a23ae38c4914734e9e9ea371d755fa620c315012c56ad9089b324ee7a8138952aec741c8933aba6a98ca4230031285f8d197ad86e6a6b39e8c4714a277c895fd1ec457f18696234a12b2686ccb749b9c51cbcb27a2684a7c0623ca9aa4438d1f8b840dc94594c36f0eaa1ea6bc247b1551f418929f4924a6570d27a214b2fa81e57ebbde7943ebc9d09e8188524ab2cc9c1b3aa77ce48b198728ceaece6f764a8fbbded0aa324459c7f43fcc476197ff0dad2b10cc2844f1bdce63ab74ec3ffa8656162198b58822e125661e61be254adc3ff4204b841983285ed5f607cd4ed7cf7183198228e5799f878ba64788dbb061c3860d1b848319812866f08c1327a4b39304108516530de5d9e3df8337b4be18a3df04a610e04551bd61c61f36bd8f6e2f31ce45c40f4c673b9518a36dc31b5a4f861826305aa40fe5b79b1051cf7e4ae37c28e47029ddbed933e2227b20b94449089134a544dbc35abbe330630a0d9db11e8a1d1b32c99e8d69a91c98918742c450269a425d32473cfcd5918aebd67687b323ba8504eb4c09d559b99ebdd3d677d4c9d80c3b14ae63048f6d9b4256ab43d1c6d5afe3b9d2d8331d4aab1dda3d0e52e7fcec8c391455472752bddec676861c94d02a1d2e9f122376d9ae4dda34dfd05201195f5c1c0a9f6442f2e00389917f389463cae67b54232f9ddfd07a43314bdc9ca3b283d53cbba19024cfdff9ab6fc841da50f038e5f584381e72123114f4092e0333d8500abbb4dbd4bad61c6b28ade424d6efd9b1c3a386428e534de327526acf23cc4843b9ace38732e14143713e881223c3730755a9000228e813540961c6198ae937b89a9867d83c11c10c3394c4e57d474a5279fc366ccc284349e2677798591142386790a110e26d48ded6910ef10dad309a051fc6176388f145ddd518d088b7b2aaaef852b1b2ec58fec3c88fed380c8ba1a8d1a53f3ad17ebd1a6db5c25008a22317a9c3d758f1aa8c16fc21600618ca71387162b286dcf776c6170ae1b9eb73c6ffffca5e28d9c76a19c774dd33da85728ae0666a1d7eaf8798195ce0cc6423479ca984d421318f78f8f26da3d611e38c2d143d87491b23cec545e686960bc628a34a6b23d0812f0a30430b852bf78f9023edac91bea1e5617c190d28366c1820037733b250e89c83901c277e18db344167c01031030ba5f9587e743d07def9c2ca8b0b2ca06031e30ac5f00fc28497fcb36ba300052ab04261b3a493de6029e1c36e687de1618071ccc030a30ac5df88ab1da4888c69a6422927673f88f53fe54ea11c7744879447191fa9195228a8e9c6f01fc207727e14ca33fb1e35e581482b28c1e6236640a11c9dc7be7f47fbf39e2794ff25d54b66ae9c8a6e68ada0045f9c7e137c81e500628198e1849247edb989c49b507a5d9fb5f0f98afb6e68fd08fc8918339850ae37d58dd38a10575b4261b24faa95f459d57443eb8b2f7e0463fc09ca4a30430965cffa3ec9a21f9e7824a1983262fcb8f6c608c01823cf0c2414a773501da66c34a4f308e59af1a036a7c26313f49741c6172530810a0e525e5c60010818411860f0cf304239478a95cec1e75da608659d78af2991e38f93264239d94afef073f89d1f3c8462ca0fed8d5408c5e85b9a35c7991941287ee8a8d2377f9fc7f41795aa84194028dedc6a4eee1dfe4ae88696095a0529f82faa5a05292825307f0301f483724e3b1955b783d065faa0f02bf13de7f9d859562079460fcaf6bb9b355f27e3470086d30c1e14ee6cf2ec65eb8790e9318a0d1b3dc6dbb001c68c1d943a3b630e99e338fcd05e30430785e8712764af091e491883193928dda4e9fcd0ecedebcb0874e00b0fccc041c1834ab9d68c5fb50c0036987183b2872a9f273a9060ee8130986183f2bace768b87e620476530a306336850ba881cf9c6c7cea2e01ad92cd5fa43ba9445d15522ab4a0c1d5387d12216852c31dd22beb9631216c5cd3c1e27b9e99499e315c54c11e284ce397498d515a5aaf88fdaf71dcf865ab4a274aa13de93cb848e5618b4604521976ac4a01eaabd2357519e0e2746b9655dc7122d5451b2d89c83782669918a72ac39353d95993cc21148828a427ea8779def3ad4dc4e418e98646259a91221b15a643e824b6daa97a085290adf9d4e53c4d9adf55a94a2fc21b377ae64cec8f36b418a92c6f63053a665b41845f1efdf83dabde5e76f045a880251338fd8a21226458ee337e69498c0f2055a84a26c256a3e16390c76ef171f0618c709c4305661880146960bca00838c035a8082f808592389879774e4ebe547cecf91ab5a7ca2943d25d57592655422c3868d0874e00b1568e1893a264fbb939e5bde4e10434f6f0cd609b4e0c4f6299abbb792d28aa1c52632d59649a2222ed3e5f2314343ea7dcd6cb76ba1896287b3d71ee65c6694d8002d32510c9ab6f7db7446631e13e50ecd7ac52bd375ce9728bcd8479b35a325caa3f9c344fb20249d498b4a14acea53ea367b6c871285b049272547f1a8fb4994e3fe98ae3186c66824518c9b7153e68e73b88e138972bcafa13e869ea0f78144d12af23b68d1dc613e8f282695d1f20427bd97f51c6fb6fafc390b43021890801708f002015e5ce001e40f350e51fa1c6d62c43cf933f34da86188d2e6149b3f46ff89e4284431d87f10bfee39257610a2986722fa871d34aeef419453840fd1fe39a8970a05514e99a53dac6cbd570727a146200a6a9e1e6d13b2c7fc160935005154edbc3a714c53677fef0e35fe504ccd27137b77dbfe5938d4f0435123c6f3e06190b4a1461f8a9b32b2511fd799c47881800b3c400d35f85088f2e261f9f65e20c00b1380d165d41ecae6efb93468cc88eeeba1ac23a711dee11e3ecc43e1b575e39465aee49c146ae0a1f4398eba2672d9ef9466a8718782c4cc87a162837d60ded03a3fc6175587b8861a76287b98f5cbaac315f5ca0b047881002f10e0850d1b78861a7528af849ffc8ae438884b87d28a47f8758c8e5aea1c4a327fb17fe6cba11c9c759c4e79a651f338143ff0d8f3412af73a0c1ccae136ab9a66f2c8acdf504e2b33af1a9a66abfc410d37947b6a53e26d4a3b76db50928cbf3569747d36c286f249c40c9bf9484ab3867268d6c8fafd213e5d822e037b50430da510793d9199fcac7d1aca3f2b7b9f2c533e8e4443c9c34f6eb2fadf0f256728bfc4e0d1529ded223443a9dac169a7d77850a30ca5c8c99ab0b23976da6428fd884c0eaa3ed7c7c817ba841a6328061dd118315649cceb8e50430cc69be0b1c7d7a6c250eae99839c29fb79a0e06629f89dc95bd58ff8582c4fd31ab8d6f611d5e2825c7b09ad3ba7b74c138f521547cf8980b750e365d7abcd1322d50630ba52b8fe37c481d9bfa06468fe15a287e8792a2b9f3cc639c85c27de46215d1a31d9f19a106168a6d3e5a1792c3bced71854279474ec9412487ff850bc6288322a028e813848144a861855246bd0f726cf6331aaf42a9373df2de8f1f468e59a106150a7976f951e5a9dbeb53286a78daa8c9dd83688cdf163404bc4080176148c00b0478e16180e1002f10e00502bc70c13bc00b047831c6df20a319e00502bcd845419fe00bffaa2185927c77f021fb3ed9f551287fb49bbe43f397351d0aa59d9d90b1f2e309a7fa1cc77d993c9c50ce1cad3e733caed975138a6935d6e46b7eb45a33a1202f6316317fe6bcf312ca3985cdc57e9cf7e35809c5d412268a7cfee0f126a170331ef6f3a64828dddd86e98df15b62c8110a5975f5a1fe87d2b6118aaed9b1a6bd0d1f26b108658f422ad2798ea773234271367dd0a95f7ac71f42f125abc884a8f3a4114239c8c6ac0e37f5071ad508423970f73fcd71e0a259a7ab1a402879fcee7b9c659a63f0078556b9ef2499aae18372dc68ce133a65ef2428502f2ef0002f4e603640ecd4e84139af4c8be768a3071112851a3c288ec6c96934be837267cca669f65935291d94356fce1e72327486899d502307a5087bfa35672e119238289874dee4da7965fe4da1c60d4a5a1e27ced7741c44866da0860d4a571db39e7bdcc9892450a306e520711b52a75777de5a841a3428c688ee4156be7c1c7d16e578aea9e338f20d9eb33b021ab228be795a7fcadf4f537971810510a3118bd2d49cdc64576f6895a15e5c600165d8b042801754de042850c105bc98c003bc8045b966c7c56bd289fd1f46960d1b870d1bf68aa2fbda46ce797645c145638a3c29619b3406081aad284726d6414aee099eedb23ed0604551628ef9231d750eee59453173988e3a45a3b98e65b4e0bfe025d0504539b8baf11c65977e60af1e68a4a2a82e3a731e93eda64af3400315e540cce39a9e9d65cc9da29c269cea8725e181862930d9fc68377ae471f485185e30a0518ad2f544c941d8777f24b9a128b83046008605a24083147d487f1ee7c8346b5e37b46e98327a0c147c218693229b018d51942a5e3bc2c92b8a72dc69a5bb29dddb330230c8403bd00845f1f36d8ad84d5e1d6880a21c44f32c9fe44d4da29f28668fd34b2d637acc1a0d4f1442ceef1231443b519a90a37643d5474e9d1345cfb1738ee3a89e038d4d1473fe14961e3992ff38a2a18972a8a9224662ae3b7b3351da0c216669deac97ea0dad2fc428230c30ceb81213c5df989b3f4b76fc9dc3860d1b36acc8a04b94b46a6265ad7c43cb50d06368c0128518fce4d6aea3578738814625cadefdf21f798edd5037810625cae532b949cd56d43c93286ef4f587692389629ff467ea8d6603543ba011894208293cae3589891af2e2020ff0a205621cc0860dff1640a2bc9e9b3a6f5eb87ca812683ce23888f193f7a43aa2a01e3ef030b337a6480d8146230a1b666b37721c3945e757c088a2ef7856c6c5c67b0c7181c6220a39becfd829e7db2a29d050443965071f6ce7186ff16f68651108d04844e136746d4644fc720f12041a8828e674b11ac4cd32d57e88b2ebe7e42ea9ddd05a43c310a5192f0f22ba737ac46f6891f145ae8046210a31878ff058bec3c99b30548065d02044f1523ba4e35e35437d43cb05078c32c408e30bb331680ca2281242bfe45f0f6d911b5a5f88e15b5e5c6001240c1a8228f6e5768ee0d20dad4014a79345c7c9ca2003c7b02cd00044d93445fc94f30d2d23c3860dc3028d3f14a3467a73cea7922e1f4118606c1768f8a1ac1aba7122635668a7821ca30c14d0e843e9cb3f064f1a253e7af6f890b506cf8e1832931b5a648c32507034f650f64c97a2ed1e4bff74433540430fe51cd48efe869c32cc6420a19187628428b7f1d09531e71768e0a1105e3cfcb06c4de2d7641c34ee503a8fb3e7687535376188618762d6602f96b9547f03b41568d4a1f0916dd2faa8792a73171c5f988581018e030d3a94dbda03ff49ed1b5a43630ea5cc4164afb6520fb90181861c8a2ab91257836c544b8c130618c48b0b2cc00b03f880461c8ad5d3b29d03150ee5306fb2cdcb3cab8521c68621011b36c828811862dc40028d3710634ff2ce1ca223cf0426680424951668b8a1fce95327bd2f8f11761bcaf9273a7cde830d45cd9c340d496247fc6b28261f2da9907defb81acab18b076715da6b214943b13393741c860f0d859c6e68b8efb813be33101b1227ea1e2d29d5aa3ca6e3283e4c9abca134cc508e65ed364712d12843d1b443fb106ae6b62634c850109118c43b73dc1d3d34c6508e39a8f77b3fef8e430ca51a8b1c078b84a1d4d7e1be1b3d7d42d5031a6028c69ac858d3f29a3ffc42393f420ac99a77f3280734bc50fe55c938cd2e611a5d288a072bc17d5b3232cd8552865dc5c726e9d3b1db011a5b287a7c1e62cfbe67dd1c985a6025fc6cecb250eef7ec92f35774cee12c1528076860a1fc9d437bf8c8e369f25ca114b61e964689b5b6150aa2193bd098d77d6155a11ce9749abf1f0dfed11734a850d28e1eb91539ece4dc140abeefdb2529bd3677001a52287e78f4dfb599e7355a008d2814a379a70e3f25e60d8d188006140a7a1131c47b4cd5e63ea1bc5bf211390e6a1e3e27147c77734cfbf864c2d684720739e2f7b4dadc739850cee1586f079a3f7b7e9650fafd398dfc1b653e8e124a9ae3d44c9a3e4928bf69548d5b726ee7414239e99a6ce6e0b3473c4728e68f27e3641af3ea8d50cc41a73648520f91a308a54ae9e416b661354c8482a6b7f93c9137843c8462d27b3bcdd1be1d7c211452c7c8dc9833c7d33e08a5c80d5134aa6b4ed103a19c6e2b1ef9897dd47f500ee6a61fc609d1f6f04131fe53238790e379d77b50d08fa1033dd930893a0f0a9d4e5e3c254e75e83b287c1cbac4fd5487fd3a28985dcbc7d6b0e37d0e8ababa29592e5a913138287bb679fb30bd31c2e60645bf96a8a79b37e6cbd0b04139f86968e67876be73d0a841517672f37f3be7fc418306e58e2071facb743c3c8be2aea71db3b9655134ef1cfb89f6e8c78e45a923f1546afdeb2e362c0ec7cde5038f7945a93f360913219cd8ec8a72b835ef9ab8b135db8a9254568d8478e6a7322b4a3ffb9ae1a3cce6ce2aca79c722b5e4248bbc2a8a1e857df0336f2a0ab1b2c565d3454579c3a38f3727cfb1fd7a8a528c89d76f87ff9ad514e5388e1b23b27baee32845612667a7635576e8418a7294e0162185c494758ea27013f73ff648cbcb4c5194f32339e930c95094d7f34b87aa217310495094e389fc1d65bd8738e6270a39717243dc90931ec413a57fd14dd1e167cd59d289c43da44f848470a22c9a7dbb9a45f6d3b889f2c4788f6ddedddc464d94ef67325a46cffe2266a2e021b4e5a5b44a8821264a9a44e4367e9c3d115ea2741ecf844c85962869761c39aa68cdef57a21c64f4cf078b92fba044e1ae523b4ca923f224cad11173e049d55a424e12a5fbabcfe998931ab9489443e34e7210c3f47c40a29c23f9fe4b0e7b4431679f0631093b363147144ab5ec32781a510e6fd9718e3e37e930a29c437c0fb3461651d00e7aa2d9d88721528a28e698f65f27db686a958862c81ec4e48107220a79bbb44524de437d8862368f9aa9e30c51de98f6cb2348648d9102b62844d13f904cfffc4dfbd01684288668f370fdcf41e8390eb56a639ba611e8c01732d84210a5eacffcc993a671f90251fc38b23c373787aa0c106984b6046b9768cf1692b4cc3f8e83039b284c36491f874e2e1d74347104b13e134549a71d7bc88689525c66de6a26f7b08315842e2e514815631d355e47d9cdb5a10b4b9483fda4a93acb6e33ce862e2a51ba7eb7ea901f94285587f7d0e38469e862128573efb2f53fd3da90240a6ea6a9171d79790c3fd04524caf5a1a9e1496d2486c0d00524cac96de2778e3d22bdc40b5d3ca29c3b7af930379daf992ea313400600c8d085238ae5ff415d2ca53df81b510839043f59db30a2e43152aecc886ace8e451493a5676ef538e4fd684514e39f7cce9cc23bcf89285d646d330fb76223882885bdba871dfef9667c8882cc7ef4bb2fa131c5862859479b7c721c5988725c591f1fa6c4aa4d12a21cfa43dbda6f8328de7fd4301daf5ae788200af1b5b37baa8f942c06a29c436d9f91ef370f03a2ecbe39bb3ece5f9dbc3f14b7e5bd222684d6ed87427d6bd85849fa61b53e14a4eb56fd460a8010bae04321e549a6c9ebf469740f05499f1ff6471ff5e6d1851e0abd31ff98844cee5c322abac843f15fccad935f782844f0588b0eebf4d420c0860d1b366e056380d11340c0710205d8b041a5e8e20ee5e8fd52368796e9eb638792065789f1e3e88c76755187c2768e7ba3319b1b63baa04321a6a8f7e878bb9843217aaa482e1dbab5585dc8a1d4e1a19c989d5978ab5dc4a16c501770286eb987f68f8c2f58f061548da0c368082421ba7803795424adc498d76e286a871f62c760d11aff36143ecce1fc6d74ffbc391bca693ec8192261db53afa19cd3fd7c6a784779550d450d3b199348d250deebecc06ff3467e201a4a9f34e694072bb5d1339423a996f69de4b5493343413d244e4a99ca500e63ab4b18dd8cb10d19ca9a3347699fcb741e3e8672cca123eb1c5bf5c388a19c33db7aa4e8084339b3db36fa6b301436471abedfa2b3ed5f287b68d939bc93bd50c8214c6bfeec314ec65dd075ff62b2783821174aa99ab5e3badc822962a4c38fa331a95a28659a4ca5db7b4a0e9285f255d7f6f9d46478d60516ca13f7e315c6e8c20a85b5d08917f3a1a18b2a14f7c1c6b439248f0ae410e97d750a85cfede1adf53eee183743175228f427b90fb7a5b43ba250eef073b6ef687d5bf250e83a25781cebedff84e38fcc277e1ce6a64e386cb325a7d9040fcb26942c36c723a71126d3cc04f683659def48f41c59822bbd21dfc945ab84438fc97a2aa27b104ac2bfd5daf9038f3979474239a60f5fb374e47154720443b6588d1adf6346602a5bdc67638ea4638a50ac0cf2316796c72d1a118a5efaff9ad3c7949b1a42f725f91b33ea070ba16497ae913ece25375119ba0842517ab2947af05196dd40d83e73d0f6f96a3ae4f841f9e31cfa83920e2587491f7c1fe849a7499922377485d0450fca61a7eef6341375aed1a10b1e944a4259e7207e6a67cc0e8afe935b3de6101cbad0812a9d246afcfe103a9e83427547f591a448f5fbc101ee79f5fbb30721f4bf41a1fef40315c9eff83ebab0c17963744c88e4ce6e17aac711425febd95dd0a0a092a38ff7d78899b3b3586cd445726451560f1e6feaf4518488c6e29eebd6f4e83ed86e6051cc3aa221226aa476c92b0a1f43c7a33fb0ed30eb8a3f871c8dcea64dd5722bbc702b0f1ef2e7509515a5ccc8fa1c7b27f9385b85711f7393e5ee795451b68bd5ff707318a265dec0452a4c8d1c878dca0afd282a1ea9da9bcc9c22138b0f74d5d4a57343ebcb006301e68037c141082e4c717866b3c152a26fac52f8d2b91ebfb121e4b8a1c5a428caef9bc72182ce848f5194c3f051d3594896cfb628ca915e44bad75a99c9a1e032b64fd984ac11a2a0288711cddbce2b4e42f813e5aeeee439637dbe2c3dd1476af4fc1c3eb69a3b510ce1ab634db0ec60279c28a64a0776daa13eda4d14b284471f868ce123829a284f7f660df9f3de3dce44c1b535a64c97fa108389a2daa7c9b1ad511aac4b14c2b463bbceb12769c485250ed732ce548992c47bdefd538f03ef28a1bc07ede1878edb9f44614c738ba8e71cbe749228761ccf85688cd0fd238184a65b6c8c94c86b9a86986b16ee21879a63820e038cf3c51a43a29872f2e626b6efd16556955428e8137c416de0e21185a8d6f318bc3ea6268e28475c4ae7499146943c8ceefe0e255ca58611a4d0be4eeaff594421f787a8ce1d62ce2ba2bc1fc4ec419de71cf713512c515373d9f4f4104494639578521d3fa87ae61065d71c4fe43a0e325287218a2ac93c6895bf901c2e44c9e3dcd1be35a4ad9310a5df2e9d10b5bb1f64104ec8f3f87ad5d611b810c471549ae137211788527d04eb7febb439612b4094ec6387ff9f733b66ea0fc51c1ec34b65c881e64ce5062efc50cc13592dfea551aa5b4170d18782b706f510e5716add17f0451d1db8e04339e6cf71078f50d7667f512d2823f9c0c51ecaf1ffe394d936d691d643b13d9a66f97bca8e340f45d3f650114befaf030fc5bdd80bd1ed099e2a4e0217772886ea1c0766dbd933fa5cd8a1ec1d6c346fca915911c0451d0a66df7b95994387625c4feff16b8608d348818b3994477dd33fde905cf76427702187626aa6869043c9aa31270ee51c67c779fe9169580f877284999eb4d23561e26f28e4b8e2b93dee77ec0f3714463fae62bfd37f1cdc8662d8a879ba573f492b1b4cc9fd14b39f24c305ef803514acfc3f5ea37c7262d450fc385c86b8217af0aab848835962c4ff1c648c8672dc1fc72ab31eade4bc09438c08bc09438c306a0f5c9ca1d89e1225668d8f23586a86b2eb4cda99d89a31836528b947a9079a6b7316990cc5bfd0fc25b9d6abf9188af1f19757fb770eeb134339e618fcbdeda322d261284afb473f396623f904864278145ff3b8ffae922f14dc63e9b58bdbd891e6c20b65eda8c3b0f9e3a8f4f8093cc00b31cae82b3070d18582e76464bd88fa4ba45c28e750571f4287e7d14f82c0c5168aa799d424c7e221fb69a1b8795e63daf3e0220be5c82607e9ace3f8b7d5175f8618615421c00b03e010b8c042c922d56a88ecf17de4af50eeb03a6543cc29ceb35628871f69dce8791929b31d705185a28a7d640d0bc91d422a14f3c318d446bd6a6b9b4251b2c24d42dceaf6490ae53eef183c8e5fa7ae230a05f5bbf530ee840ca1864231ec841892ace2e209054fa969254f08ea93b61c70e184d2f594d668e647e7d001174d285c69a7cb5af3a831b342e08209c5ccb08f3f48fd786d0c042e965088292dd33449dc3bf147a055c62f80b950427147722469537f0e639c84727c125367fb206b914442517e73a8137396b03971718442ebea948788e13f3e4628f707f33af910a77753846207132a9ecc53fa3e88504c13db6d09de933bf3808b219472539348ca1c49b20b6fc085104a192d7d2e6972508fbb61c2e8310e1a701184f20739d2cdae3da541e5020885d78928d5e122c9a61f14e6a523c9904232e38ecb850f4adb2737124a22dbe6700cb8e8416144fd83ae0ec77f3e7850ce1ed33cb3f62ab18b51c6171ae06207c5dc5b699bc6e37fe675012e7450120f356a72eed9fc7095c0741916182301f9012e7250ee99d395fffca943a32a5ce0003b7509113c288c36010a9ac0c50dcab5966b191f4e75f488800b1b143acc614886bfd5ed1c37b44c6082be51060ade5bc0450d0a6962cc1b7122b47c9a0b1a14438ecb4432f665d0c82cca4147a36ba73d0cb1d59045596de36d9e1bf1400c4ca0462c0a1d3bc7be0ed12f393947500316e43e6df1483e53578d5714824d78a0db217fa4f78616d11aaea0d443ff4dbb8e1bba8c831aad287ec7883e93436d345107355851922ccff49c2bbbaec62a0a223944b4c4bf862a4ad21966efd7a537c335525108d26213322e19728af545a1a234b9a221dd8cda5ee7043dc60bc038011865a04002366c7c81891aa728a55f798e99bcbb29b3851aa6285adfdf7526fdd06e3b4b438d52145b3ace8f4bcd53749a9c45a0035f74a006298a59b4a25eab4362d88ca2d47136d69b77948fb7612316354451f07f4ffb7a7f539f138ae269fabab1fac8d23a40518ae4c1a564bc43f1b84f143c44bbee09517165bf021a60e589c279af84cee7965d45801a9d2807b39ef05976ade773a2202a92ed3fda9b2827ff124d95b98626b050af9f2c21234b32510ef13de3c3a3efc31f13c590830e7764643b8afd1285f70e6432a37e869cb64431e74da9b92341a7939528cd4ef4f0e769f1b39b000c151c616ca20625ca91d4c68efdb64e9173432bbdb8c002522b021df8428c1a9328ee4ff9f96584d1232076811a922884099f97daa621c7ed17653c193f8619056a44a2f0f944efc30ea2a9e0e8036a40a2e03ba332771e3d79d00dad2fbc7f8c74408d4794c3189183aa7a5851a9961a8e28aea68d1fcb90265f65216a34a2d471d2630e7360ff1979718107d46044c12652d6e4c8fcb299c0c1f8220c31d4868d0bbc09bc01596311e52023a60f377fdcd04a4514337958d9816ecefe9a88721c075125d95da406224a8b99a8b4ad050392401c0c0643a150280c08a52faf0063140000000c1610c782c1589ce96add011480033e3a2a3c32321e2018121818160e8843a1400010088801413018100685c2807030481107a1f601f86d3a39e541463532ba8bb6a3e72641b0b98152acd00c66a24ec6016502ffed1c54180fde1f235ab140a8038b2651468200682213de4fcbcb5f63641b6600d3ca95a3e77d333578f26375471941e2a1e678d5ba52b6b51f181e914b478459643fb716e4d4f115a9548ff0364186934461a84b1485184bb6b8ecadf5543f838ca1ab96b84a87237bf3d37cc603cf0715fd999d22eac809f6b6a9e8e43d91704fb4131de66650fd9cf6749493366c4424c1fb0e35892ba70666cfc1a0f7a0dc903259fb81c7528e8ef59feb0361bf613f1cff41fad998fd13aad74a39ea5b9af503c75bcc04d78fd157fd7e37bfbafd86fc072afd8ab4a86c46e3932a848604495123044047c87c5044e238dc756c3655d29a2a7dc7135f827a0380ca81a41dff3e205e9c2198353576184658db8c9128f831885ee14f027a20240d37dd36f74ccfa3a0af0782da824e308b740cbd2c3312327c8ee2b68ceccc343aeedfd751447d480a8a03c6de2eafcaa55561a00b5f60da87227a5128106e4509bafed3d43512f91566e0945465fa1659c5350fd6af3afdf966b42ae08b3c996427c02f0f93c8f3ea01a779f633d33ce39cca40d0f9206bc597a28d06e1da0231f2f3074ce8f7d705727cdf5a9e683756d9d4efb026129a2ce71ced86ef5dae1d2b0d6a6419451fca26f3b12cb318cbf359b91617c4aa1107236b2338a1d1b884d5dc7e309aef0845a43cc56867e5442fae65a467d2acc82b0341a429f4519a84b49b5a0762e846a3b9086f4bcb3c62f6483b547e6a3747a3a7258efc8616577e2b341e4d9559f78c02a33ef490d2b89da5119093fbf340aa257e815a2c8c6f04f3320997c53ac79c3873bed680d6ca8d26eac309b9bde90eb220dc287e5229946dc98cc734542220adf727605f7c2d84a3682037e9a61f95b592e70418aa383ea3abd233204810c0fca045a3a22394c05eb247871b8a4c2b893c606d001788db49ef13e41f693d2a76134bc6bf6401e1700852024a0bad0b157733c8aa48088cc7278ec6407fe9a30b463abdb2483dc19f0ea29f875b8889c7fe1387c918580dcb6ebac5dcbb7f0d182df61a8eaa628dbb860c224eb52a541ac70629ab9457b9b3794db823a7ca306f3760555023eaf1b49ce1e25419586dac85b21a35dc21b0119a7895b95ff08251c1315e6a50b1935f6f0d876ae2982ade5750357eb0926a2e795415f442f9b09c2047e8ea883381200906ef5a42f5497075af2b27e2c0b03c2ec6b75280779686753fa75fa56b217464d79303263a6254858141f37f82f512dbb4db1ecc22ee6aad3aed825a14e897299e44c31fc966a0033cfbfd6d6d2572a0125343a504c5218b0c1c50a7867ac0f402d9002665d4c0490185099501ace9f8483a4fe4a4fece067047341a120fd14911088026f725465e0d43ca46d42580337e61e01a0fe05614906d4b49910f99018e5815fc064c0fd94e377e7855a283f75ccda980368c1a2350c52170b4f806d4481aeddc29b4a4135acbca545356beb43bcfe29e997c7943a1adc30a771392393d1905784252e97399b954e003cb360e83da444406bac3a9ee7d6253dab3d84e78cfb67d436061af2682a0113416c4331024c84c706541ea0ef830d0b4be55a15cdbadf852b01d1222f16dbf38dee789da0121ce3586b0d3215891b35b6c40dd29d7322e2b1b66febc70763aa15191b01c9de0ce519218cef8be3e0fec0100a946d9f75d39a086cc063b1783002897bc63a04455c7d65ae990a8594628b0321e2d705285dd0e254c922bd5a4f171921d1dc0eec6c99013df6306954d7deed7e3d44f330ec50f66ea067bdf0ee02945797d520f4fb7f902d38346e4e1fc43eb082b80a0fbe44c86906902940a9c55c2af033cabd8bc9369e7315387c5548700e4392ed0acd57b1f02ed8abd0a39c1730d05295ebef3521397d6abe825dcfb1a805e03e7f43bd0df299783cb96a77f4c5fa3445604c26ed50f734993120e706776ebe7268c70388bd62d7bb45111f4ec2f6d9abea4bfa6cba17962490177c84099635744987ee7022dd9f27cd90a1ade456498fab077ac5955b843bd0e9a3c35ed9a261f824ebf2b3d1674ef2ca4a9fb6dde781593ee922390c06a8de314111e7c9941561b1c14f88b3a3f172cb20d1e216caa69f7d3069ca80d0e2e9f249ec1882e7488d26666b7b0a5b1bf367bd7719322d09ccc7e5197435f529881ccb1b95eeedac8caf717893aebcae798244f674af95fabd7acab288f826828ca4fdccfdf81dd06ab89d7c9d0a6aaa138edd415632929e9e572142daa6f5794465905707552dd8fcb3fca1d344219ea7f6567d19185b59cada36644c75ad2598a1faa04153b9528744bd8bcc101d520ad8d38362b1f2f9e85ecdb191c1790de4607794a21dd48192aef75374c4a479bd48a31d567361a8fae3e1181cd9a0b3a3c955b67054ed2546f38da3b493e477ba40fe04cc2efd1d90e034989ceda213f63ebe2308960a35a02630d62e40138f3edd04152b7c33538f711d357ef1795c5d8e1b0111c90c2ff8759670618ac1aa8857bb2b94c2e6bbdacbed4c74eac5d35c2f0110f0300d75cb9dc95b0ed7b44e3f122b0e182d99b547fd5c35bc9a36dfe6125fef1a76d11e0deb7198e4837d19af565b1e62e9d6a44ecb0d6f154b9fb21b2b728966901cbaa67f9981458e0e5ae33801b63cd77074e7c1d7f990fd23b576262cc81214baff5a2587d20502f196bddbcec3bdc5a46efdd273cc20fbb5cecdb52f20162d7cc0449ec8f1c181c7c2239cda307b3ed448f2e0613ef3b3f5ef33059c8289f6887c14e79124ce9f9c4a6c98180f72adbab6d94a6e18ba6c2a40d19dcd7a5ebf2f49d33d618faaf6157d58287820d31f2501cb2d7e54e514e7f765caaad17404f8d57a58d851adddb059a7cb62797c699ebd1875b1d3eb492b9bd4c9df74e3049d8bad4e23dc037114ef932295144639c041457a7fb9a65e040f4f60e3caed3ddccd5bfb2f9f6cbb8aa7ed25e7f2a2c450968906ff0e66a091bb5a64749ac41802683d0db0534ea3cba515b3aa930a198f41086b9b3ceb52bba5b8e8d561727a2392e4ed03556952d402a9ba0a13286145336936a7b346b31a14ac0c7ac128eb717e3a184269f5a624c16863b17578a8faadbf9753d8239f3f8c6d032e4ed35658872a76457f217ef04dfb0f20fd017eef35e144925bc643cb34a767fea10d0adfc881a76a75ca04a671330dfeeee46a52152479bad4cff43656e9b1c41691c156b5a0f04d0b28cd7561f3a12935beece4b27025d2fcb793b64f1919f32e3185188a16fdfb891d8461e1e204bf6d1a61c32c661de261ea1eab7451c96a16c062e30ec75a328a5ed5e67c07f1ad67bb3e85995b0f2660d9756f7ef379aa4b2cd9ac6330e3bd2d23b67afaccfd57aee00fc88c2a2482c6845825f622254c653896ccc95d1dd6be3f26608b5c102b12d10796814445b9bc04f5ac005b83c92a8db2c29495ce91b3e67bfd2f310db34fd2292a2b95d8b1373a9f66232228a7d444cb23cbb2040c1fb257a5bf902dc8f5ef2b8ebcd9479e5ab4cb3764da496800728a48f729ddbfc422278e956b9ef48dc8abbc80121289d17c855be4045b20e4570aac1af7ab69439e4992343514836b60b5704cb130027afc566b845f606cb2b01e075d85992958cfc847c4bf5f5009340f78a2d1bd9d7212320f5c697c81385a1c22ca2a8903abbd9a8e7698f2c5e95a794c85a8199ee2fb8bc928e20c22d4ff52159a82c1aa5807882771bae0e2f8eb74be11bcc91a28414ce751cfe9f74c7ac08e353d7a2d3c749eee2a3c50e092861948d79172f63379c91e0374f98ab0e1d8e9232bd6c59c67bc39638d19260f805470c1c2687aecb2f245b20d95282d6f7b7d7b5bcc6da001c068f0988e8cd3720becc2693913d24d03eaedea678fc289a8deea1732ad75c954a52f5020407f89dc97892de1bc759dbaf0788e064aaa9c2c881dec8811f1a91fc827a644f3328cf079afc75828e7ea7e49127c7f01829685504d1cd9b674e93986ab176fe3a7272875470f011c04d862e7832d0455082465c1a2557587b7794b256734c7445ed8db6d76d5fb27267a3a8b9bb15113fa7f872e9fe10f3231d7f6844b287c77ebefdfdfc912bcd10e424e048cf0c6cf629a9cc772427e86889819274bf9c69ceb5eb19d1f7468635fefbf6e186b464e0735fba197ff0c322d0461a34ed883e6e5a227c7e75c45581b919478619f293124535ceceddc23de2dab2fbf85ed1f14822c7cab98a3378743e83e3789e46f19e57699451c62eb59eb47d2c04250cc802608ac050e52ec11578f557c0fc53d348e10af0dd68b290f0cb64ede247f7c3dc21352f93a59c7f13fccd7f544f324120635292d8d14508b7f1acef5fdee63f0507b77f26527b82639f9282f03557006045526d625e182838683c36b4ac9ca88839638367bc9e90bb99061309772909faa4aee4b33183d8bbd23fe3feedb0f4b393384c0353fabdc66569ff90256186e51566ba66f0d58e47f70669bb987aea0d9fb19ded6ce64e962543304ddd647886d8706732ceee3d1deed0ef410b8cb5b209a892af292201eced2542b5da18edb83fe75422eb69ff7a3b6a92ed16c6762a4d894c171f383c9e397d53ba496cb2e260a7cbe8d838681af09079c28bf9d97c5bc01429e62d11727e249bd6a36ae57ea46cd1f1922c387103c66f0a7dd41112e8d04591be7915840991f6e56b68128aa286f0df50e256eedced61347adc552597b48314a9e17eb5fed4a36a20288d2e85a69f4c7ba6ec056025f8abaf0f43b1d2eced9fdc1535da63c428c43bb89b8932e85e37f4c2c27681286bf1e77cbf1a23f35c6a99278e15a76f4a628e0e52c4845a7084f9b532e7abba9300be8dc8c03da18ff48bd385102ec84995ba34f00505933433e84f47a42979e34fa052ce0fd2213f09c9c8070bc47c70d0ade0ba8f5f6646152514167a8e2dd9887e4ad8299879510c0d59904cb57861bb8281e54ee8a780fc429dfd1898db919e8cc1d35ac6233806bf993c9df8fc5f9aab4f677e21166786ada5772ccd9bce9a97e04f2c164a7c8d41e8b341bc75b6fcedcb973186cd2f17e1bf9a841f4e4d24281b655a89829b7c9f878ae7c00faf0698a12346bf5fd04bef85b30fc24084edc1981c9dc3e8b022cc6bd965309a9ebc9d54ebb4a7b8378dafcb732185a820990bb101cb077d11f6b5631b0f75917c3e4d9f3a54bab5286b7e4c30b922852d1147f3da02040dd914769786f732aef158ecf45c0a3973bfcc04441320bab5532232410925364811cf297357f530b3d65ba0e9c4aa246822741b371d9409100d998f02906b2ab5a6ff97d559886bd1beb22332009e0cccae749454b48dad3ea96bf80bf096cd13122b7a4268377bd4cfae8a88e395d2ce6226d883c99e93e69fe717fc2cbb7b8cf09213926055e2282f5191981e684fbb3c9ad896f99eb26e2b3b7d39352d8c453e485f57aedfff4fb506e5507c5571332c5c16e21ec3cc42cc8d23a5b80488e72c3207b5a52ee4eeb3eb92e6e2caa4ad3d52937341f4153ae7b22f643129501a204da658b90b87b88e948743cc3eb1ab39e1309b18b3a3744cc15731eb1d6cbc787b3c08b88d1ad38db1303e30a4b72d6dfbc1c035cfc0c65bc43c417e89c67efc18be5c311e535cfa45718e7d856a9799cbe03234d18cb7948916515f246a4139a0424ddf24112e6710e5ce73b9e0f7a85e6ae255e172b281b53397e8f02e51343fd4c4494ae956c55a8d1217c0dd99b4a57312000de1b78aabf8fdcd2cb92692e65b592c3fbb6bacf4cb3dac99b96cde6c669894f583b511367e756f1d243c640c74cb084b4bdf48873ef15d768b9ef967c17a0a1ab569b98fa7a64ae0b403de70fcded52c1709e95dd6a392186bbaed36372fb5cca17316a614b12364b2b40d3c5c1d6c66886dcde43648eb4dd00f5713603fdabb04a30412c0b45d986f4100843c024406229640b8005b25a4bb1ad3bc005e757fd231c25b7cdc792ebe9ec3a6847ed74aabdff365684e274d7489cbf527d5735e3e0766437a0c72806e9c5c2ed79e116c813b8bc8c534e4a2ae68518221ecec0169b8f7c811d0f5f85b97a507cd5a2acde2664dfc2e43569d8fce6b60a7bb96a74b57b36af6992f306bea15b9c4795940bc7a8cc7db436050c709d4bf5459748fa0bf93096bd03815dcce3ed350c410b975f2c9436d8230dc7b0ef1f4dc7270015e233d6bd843c0e6dd957712e1da53a1695569c2300f00b5490f89a3fc855910ddf25281b071488260f2af2be39d796c78f68b99149d142f75e39bf9a3fc2c26620e9521d7f21b6247bd613ae492c951b929d350e141424c59bf8fab7969bfd66c78b411cf17a381001ff894194a0e8262063d46be7726420c73bedd6ed41ab4b27264c1230bb45b8c46c0cfd897202cda8418598a1dd45543e518c439c5e034148a620eafeb34f3c6105429bc8ae1b077d5c7d72dab263004160add9a30be16a2d1e207cf5efe2753040c6b392fc77986f9fb556bd7c06a2e315cd47242268f5b285c9d1852da0666c5a5d1aafc5989384eba7ca39a66ca2d1a4186a486a44a019321703e4acaa4e00f655c11c92c8452bbaad432d93ad06de3dfc4e801486c673ae8f1b94102b51c3673e69c62e1bb71c9e86bf624bb0fc47c60c0109f87447436040ebaaf65357b0845074e0927f075a439bfb8e5f3d773260c7e150dd654f931a64b27d4808e571196d439903621cbdd9f0b2de9739a2d5b6db129f324f7b8209f3a52110d1b73fe3b41059b1c82548318ebdbbc2d30687f4268a1ae0cb5fc8b6119ad23050fb3d4f22b8b30d892947dd320a291e63016238d596f1c97aa3668a35f3037504a5e44ac7609f55376967158e6defc7ac5280a088414068c55cc990096550c8c8b8483a2938582712c4118e1cd5c87de7e0ca21d75108c2f34de51802eb32f3e29ab45c3d861b6bcb9ad48dba344038b172b92a36266efcabe7a4dce9b9ce9383e342b6c88d68e60f1fb320e0a9ae4a73255ce6f7606140937016a8d158aa8612127120f59db5e9c13ab7f539d813a69039a1f469acf3586cc957a59b822d227882cdeb2c664bc9d4c2e62be5126878b318bf6854669301a4521557c87400f9322092172e53984f06e9c92f5a024460f93a64b82ae0182d692c7f7c216f1d01e78a8e8f9ce7a6c474c5309ce44ffca052b672b535746ed3297cd5131f77f72c81b335afbe6042e78d65194d8a963bdcaee9306ea4feb470a5d5715782173955da3bd3d89248d558b8a85349425ea1a423d0a2c8855fe91e90d5679f1c7c2a1d59345491398277530d8c3023d5bd8c3023d5bb887857ab7400f2e400f0c23defb0a1045753b36304a24d2a6a176db7e361a756d749eb43a50c75be5b2151dd937c6a2461283eec830862dab501e4111b282f76b8186891f73f3b6601d900e9a0517c88cd0e6e7b5548df7591e19f256788cd4c15855fc81793b8aabc3112891061121d6be96e3787fe9d122b703838f414a6988aae75d1adf120326a3d1e5c1bac90419969fb395ad2012a4b89d2020174d908ed95ab72a5ed29cf4e56099ef59bbf31c5a89185cfdd7a5bff4044c8ac62356af448b88eee05538220e3b756734c2ccb3b05a1da6f889c14fe9d898c8e2faf35fc10259f156ab4935418a774ebe7b435aaf3bac8c2b12abaaad8d0cc8469e7af7196e2773e36656f034041af41ac00131cd3ab1aeb6dd7d5c8bebe9bc04b8ddc0ef65f2e64e14e350571867c78c00fae8b7de4d6e4c47bada5036a0e2f9891885da83e33dc7fcae03fff49ed5c0fe65dfadfc6c437f1bcd28a6f83ba85929847adb8833dcf1f26ab1cdcd3e37849481b9c43bceaff837a6f1ddf95aa4d98e29905f61bfc8e6863e5b1d936cdcaff4d1e4c8180258714116d28f54e304761a154f58231229a98171cd5836f169130161a2c31796fb4a22069986a4b3328d9ea17513aa23efecdc37d43847fb99fc1f08fe56c208739306835589fb88fbd8c109c5e7d88b15ae881b1c569ae6ca0215209ca228a161b20cec5dbaeaeb2e72a11ce530411f9f6e1fa69248d0bc9fe369ee7b27d471f367624a31e2255befd68c2b4bd4e437ee7dfd9a51a302df6ec9c5dd4da00ecda15a5f947074f24a4044158fecca5879f87e31b49bfc4630e808a0cb0926ffe518d35cca95e1b8e5f35f316d5fa286870788364de120e0b2862c72b0f226e77b8ed7d8dd4a7ab7fb89ee9bdc57306db6ba4ffa324ac40f6040c801ed7b2bafee2adadc02dd872bdc120c9284288260c8c60cd89d8e0d2ee4b5d07255dcbc4a0c024ffb010bc535f1f951bd8b5576aa54101dda999053a7cb14bb48f7d2783cd5dcea665e9a55f03dc3f4ea79974138cb399b8c9cbb72ce53aa1f2ae13c14bf2963925539abc4b763592fa2a066280e8710d74faedfdb4ac561a6dd4b16c0accd6c4c749860adc9eb2ac599779195bc7632074dfd2c69093b2d4419ae8fc92b388d0b19a8b0a6c6e007c5494f72019b0a8401d78ab384b2217ab0ff7da50a6b12e1fdd3ee5c52bc3237407bd115209a8915f3f2b9de48c5507121cfc29879302a2bf891dd83e678fda8004cecdc1eeb520bfd6a0e875094f90a2f4ed2c21e041448ee88b72a39b4bc00a92d3cbb38bcfddbbdabe03cf79affb1d4205655c2ff585d0487afdb68bbe254251380b153531c6d4651b66d792ec0cbeb42a3628e32a7529e190eaee817a82a218d2aa50a9952915d3a700b29302be2851096b0a7e14f86d46b83b241d45cef5f20fc310561bc63a63652606ed94e7e96452c403369a89170ee48cd6bb2ad9242e2b9c88f7483b4204a8f44962230df1a03bc4e74f9ce3458c244847ac2c15205be09240d96785d49398d065e1e418115b7e5ad7f4dc8bfc9b509e17ce760c08188180e777e0e8087d0152d6ea4078873da5f6810f1d848a65757d206294ea0118f0555503fba8b5775587214bfef929c30f2e5e5443603965c014954af90c350a5d7135f9dc659b83fd2f934a364d7b0d4317dac008267e659c47c28bd4b5365ad5ba21267e5feee4e415462927cf43c1f41b14b5a8b9023b6b6ab5669b7dfe8884cd1f7abdd36edcca9331482ebe249a5ccb72620713ec61105890174926fd172ac78e2101f5ba363806157c95dedeae13419d1d415e579b5b49f64e82304de60f5caf1d7407b001555630666874885d5fa73185b5550555c0bbb3fbb5c32253ac99535a4387ad76378180942780e83667484a4a0b154624b8675da9e147f7c6e209f14c7a6e7135326d11956e1cd2a133fc92543406be65063a595c8ab2dd6dab3dba99439d97b8e94f95f3491763519004dc977194aaa057bb7c8ca03004b4dba80fcee1f4603b8d085ad5368d69a3cdbed209dc47b18b34227e1a7a2daf72c2d501fd6f26156078c2e99edef7fd4d3a7bae88ddf86b6366760b8d09ab13f8255f0995ca54db47c45aecc435632574a4a6268132c7ed795880c789585768c2ef0b1c44598ad5fd276db1113719c392c3c733c54a03fc25c184352a14eb01739ce2bfa04e6176890f0755c5214352859a062a715b85025deba8e8fbce8acbee0eca2199b34897553cca3bb8e557d3eb1e7e19562d0482a06b16414c7ac1134f1561c39223a8baee0362580d381df23fc45d30b0cdcb22037ecc2c8dc48c01c72cd30c27f6501f215fc3ce212033d4b0fb9d19f0a7608592804a97d72a71024b49c307dbea98b7009930ced10dc0d6102904c570e5e268302facdf9da44ca4cb7f49e13fae80d0bb4efbe32eac21cf5420fba06b6b3908b04341bf3dd7a4671f16a6d5abc78a3157c5cf525f8c2493697818b1424d10d404e750720d55cbb5878bc914e98fd863f7f66626b868e550e4a8f153e34f6ff7e5f45530c0b24b773c2694592386c97d8cd7907885205061770f4b8132b10e028c2855772be81458242353a58dd9d123ba9dfaa44b594bc9389a8d6b2b4094f515add11e59ad06d1929e42ae2b6995f66b90c2866444d15de69c0a1b1de24afccc0a6b48277207d5c232999ea5d6e9bdeda802b6e8a3985929259e6acd30d3d22eb51d5c7a223be78d88a4279d5a47d4db54880ab680fb3c42d69a57c2d33e7dbd4424c51e9a6466520501e08dbd28add8e3a1dc941d7bef90c3ef51e971cd91c84666a8212ca6d9027855bdc31726447940bf65899a5d0be6394b5a0b06029b1236a00064c63587d8622d22482fc5b319758ae6ef73d9820152d320eb753cfe41442bcbaf0ca76d3e434bee90386a6f91ac733c460236c934eb91d2b716689815cd7b26e0bbcd3b52c2cfb7599565ab8961dcbde8cbdf20a6699d8f042afc5ac5bc0682c50ae998c68b533d43922198e7b694e05a58d9740fc68a8cd0b5e870647fc3ac62428c2d14e2c3ac0ea2a548ff1919da897189a25bd5570860b7acb57ebd86f6605f9ebae7ea767f9a6966d454f5e6e9db19b0ac9451dcdabb46f66145ec2f3c9be6ff777467c57cd4a7798ff42e7fc365ee6b18c82005a10871694bb0551bc7b4a931892200d1596d585bfc5aa094f805d2cd4982ed68a5909481be2d38aea844f0031d04f44756945627241d42d8c88f1d53fcf73b93ea75a8d4e29a9581e3818d63b200118bca383a648ecb4adfc30877220b31317ed54afb01fe0b1bccfd1ec4ac5842118473bc678a3ff504f2ee4a74aa772a5ee586796a5c4b336bad19b5c64372a2e4ea025740859f06f219abfd2237c5fe36996f244263605f09aa3739b2fead81fcfa3dcce91beb56b7718c7321a8a084c370a5ed047ef005e909919963caa899f0aba268b5a01559ecb41f4b11c98db3e6bcb11ae9adfc7ab1c9d237c58777f38fb53cd62c4450a6cab6570ad8c79bec9fa0bceeb3f0997319d1a344039511216417427fa42102f13eebf92da4a9bf1e1025acde293bafef770497c91392cbcc070486fd899097e0e04a1f219c65b426456feacd33ed4010ecdfc839afbe40f400cc4a791a8d4d9b2c453b1d0ed143e2f7a8895fa68120d1d29434cc2258e9604ae062f37190b43e36db16840e83afb9df06aec4c261f2bc39f9cb64930368db9968a43fe1ea7a729047e8fd8a8789ddfa586d3a8336cee6b69e314fa4e925a4159c0524612ad3d65c1822cc3fcf7b1cd3f9100aaa66b5d6523360d3e3ee7ddd4bad148ef5ee9f4cc9b322657982be58e5a5000d23bb64356edc1574558814349509a0e22cdf352c810255d4519e62b0d758362081695665eefee64228408e72b6312443312079ef5ba8432decd329553759bd07cc529a5eae6481b2c20f69fb3b665fdeaec2bc36a7400508ee6889ca9cb1726cad9f82594eb5913a78eb768e72aa5dfe998886bcc8c520d8bd8a88bf0d8d20c25dc5a733ace52d5505afdf676318716cd44459bb0ef3a70b061bc46cdeb79bd01e0d9866f0b39281b5cbcad795d94514f5ca228c948f70db02bfe9c67b81b95f240a8825c51b5df42a2d36d223ba3f9eafed274a536f49d024e54443d0b3640b0a6d0013c0c3c0c3c0c3c0c3c8cdfda7db3334b424a724b0ecf352e2371f45c4a49a62453ea01e7d8dfc65d23f6139dd87750d105120b4d0b3b0b979f58dc9432a23434714c62ea793f3739a491895390b376496e92826cee6860e2a0929ee79a762929c9d9e280c6258e7f2aaf9b99f989ad29cb6147c312c7682bf236c99c32b312072b2989419b98d24eec2971363fb1cbf4f5bdc8486312278b414933ee61f2844912e712c37cbe2889c4f146bffe49d950332f240e26ae4663f8082d571f713eb1945c89160d471cde04e9252f591adb984623dcd4e55e9aa667c431c68492bbaef4d87c110769d59b478813451cab7466840593449cc643a5709659ee2242c4415474eb89365e7ff621b858bf979ae4d81027cd948491637b5fa22bc4498610c2a452ca849bac123408718ef1ba744998123d4c833899586a6c5cb4823866af959b462daf7c204eda366ce92d1310c7f4d7ba5779e2768f79a0f187538ca14ac64942658a314fa0e187d389d1944cc2af82b07c1f8e6b26e575b58a679bc28763860aa129477b38596bfadde87de2f689c13ca0a187835e74cf19b50c17f23c1c4f0cf69fa5b615b6e3e12077835cb2cd1d8e7f59bf7362e869cded7036e9368d8a4993682ed5e12435b364f0f65f9d133a1cb4e952e2f958dee77012453643d706c9e16c7179c3791c879318ad2e6fd01bb4b586c349beed9fc9fd460fbde118449d92dacab42425bbe1f45bd29affbf88d56c1b4ee2bbeec93fa37f31ca86a39d98477e943a21d3b986b3d86a75a6b9a8e160a3fd44ec2a6938496ef516636349e6a3e168725eae5f49f90fcf7092f7cdd39643d85a678653eadca6d8e695e4caca70d4a0c56be42a329c4ed0fc975df6319ce44c4a2835cda2254562382949933ed5379d29bb1cd008c341ee9c64725a1e0c27e99f7382924a4c17fe2f1c6c83aefeeede0ba710427ec591ab0e3fe9c2612eef588ae11566e5c2e90479f94e3e4972db942d9ccdb73ef3c347f4bf32c8d0c2299560925ea8f1b752928553599718424923c46966031a58386df48faf245738e6d7ecdb125182f4da0ac760322b76255872135385e3570972b25e655e0b8ea851e1389671e4da9794dbf5b21b616820d30734a660383a40430a27d91d19639bbd9b5665018d289ca412dd922cbaef4db95038870ca5e468067172deecf1830c1a4f388e127facffa432193c16030d271cf62a64ee6c968a7ad28463ceb649b265ba0ff531e1fc1a3349c24bc7efaae440e211060e1c377019a481c6124ee276fa2f2a5352df2be1b8499d7fdfea08697b120e4ace2446a833932c9320e1a831e9aa135350ba24f511ce257d26d164c83eb1c44638e5e649b316939e49e1221c2dcc4932c42d98184e229cafe54491196ade34398463fe36cb266713c2e97236def2e95b511284b387f8d094a374a70a8483d0d46725c88911df0f0e3e9724953ba3e183d309ea3bfdc47c559a62e006183b98d18bbc34c59d686ef1e218b27ef3a2b1c410c1b801c60d66ece23442647c89b1f717e21066e8e2585a752fe6d5b8a736337271aa133bdd52b198470517e7b50a5a830c3d262d734498718b53d0173c33c5d509d1dbe2287ff94dce74e7dea3f7400ba3065d02bb1a748fc22158418e0fcca885f2b33a3a67333976f040333d98418b73bbd58976bf5a424fb338e5107929a7a5ae2596c5712b777f668d17e3f4589c64cc26dd246b499292e43a7a8481b0389c3ea9c49ce65fd6e82b4eea4ed7e5a9f8889a9d8f19ae388ca83357bde07341dd8ac3e912f584f293e52565c70c569cae42c90e0bf67f5959c549ce944a926933236aaa388c7cb14d82b852a6a6e2ac15b337bc7f8a9d507130c16393f8cbab1cfd290eeb15bd8412839292f403678a534a16c32e979284df121be8782ec57943739aeaa928f73d294ef1e545b7b5bae41c85b12fc98bf93413c5e14a5ccbbf74cbb47e284e42086b9337285d721e3974043340c1fa499374c95675750eee199f38c8f42deb660f1e3b74886086278ca752ac2495954cea44698390e1f7199c386df586d2e8a58493db91199bb82b8612c4590a8b6b2251b521c4a82d1307f950213575d3659838dab95e36cd277659b9c43188d7fd7dd11035269638698dfba2bf412e2e5f89c37d493fd394dc24497044cdc7ba6006254eb3bf974eb62b59d2a86c1247ad0d9e3198269d412389937cb92e9bbe93fc4a1889c3b5a674217a29ea0924cea15164967ec9be6df8889394344c9756e8d3e43be2fc268467be0d6ac4d92f337626691d23ce1a73c53b938b385ac6bd8d15fd5afd55c42543a9c5aa3549c46983cf6faed589e984117114bfb7112bf1d486cc214ee944bee532dd0a726488938ac9d4d2955988e3fa98ee55ddc6dfde83470edfa1438c1d3a9010873729175e94580671be132a2374f6eeb762411ccf94c50813be84f92810c74b62570c3ad46b6e538e1d3ef223c7cd00c4d9b469aeb4db8ea8d5a07b1433c18c3f1cbf922484f01f3dcbc0dd07fae198b29968fe1b9fe9ef0dcce8c3514ef49eaa1294d49234a296a306bee36ad025305782197c388aaa60b28c3ec1b265c61ece2952bc7545ce46fc33f47012524bc593dd16efe433f2701293be9d86ae2c1bf5197838a705ddfb3f1a4de5b747ce3830e30e871d1573995ff74e663e00831976389ae6de3d79a2da359f518773891ad7e46a5e9ea6eb6e84a1816fff40961f33e870329d79e49cb4952a26cd98c35183f44c616230d1c2b5a3cc90c329a824f2f64ed2d6a3b21e3c7eecf6f01f3a300333e270cdd8b7b670389912574388cd1a66bce1dcefdb59394ed2e3a53d61861bce176cdfb3726511178da855d98c369c2c7f946a57362defd970cebeb4f944680d8663861a4e326ab615eb509683e13a7a84813687196938c9a541c5cd5a29ab190d27e525e6fbc7a4f605679ce118e4555349f9554bccce30c349098bd14dad9fe612ce2843e95ab4284177f74f06e3ad578468d124fba1638c20cc188369b32a975b0c8b8a8173dfcd07560733c270aa929bfeede563c2196038891e4de65d172f5a72c617ce27a950a559e385e3574939494ed6d3c38c2e9cb2426c08f37ecf1b6770e1a0514e50497783aa351951cb513c31630be78c31a937ff6644ad52f70823ed28e3bd0437c0b801c68d1eee19b0195a38584ce2e51325c9b0d5ccc8c249b869851f1d9a195838254b622e9afc47d4c6e0d103a51c37e81186084a8003c75916665ce1784209e659629edc57ba47191d8219563878e5c93ef91b1d5667156654e16852927f62ab269a34e2c0910685195470a38c16214fe9499a423a546e2a8dffad91023af3af5850d69b3e2bcc8882617eb38896fbda2843a1df20fab5549c493561c613acd2703188a5149a5953a8de69b6962588194e3849929f8ca741dd2309339a70f82f25f8a85132e1a8ad279cb293da5ab7259cc5c4944eafd204a1d2cebfc47d5ff624092769f46dd2994ecdc68c84c325e937c54b594908a1231cf496983fb615ae1b34c2c1c49d5f0d2ff1e4ae453828b14c4fc3888970cc12afdfcdd4284d0fe1943a4ab42427936b2684a35dd8b13bd3a5ad0ec2498c3a352a5c09ff6006100e8d29fb6ab696e0a31fac1eb2f19a61860f2a4986e56ed40c05e8c549c985d7ea2b7b5126bc389d987459ecb4d899510176713a3156aaf04bf927bdba38c6ccc8865993a6f4a963a406397ef8d8a1c32e51010870d4a000b938f569baebad5efec87171f0be8c9e5d792c8bd22dce2347a9b3bc0b6dc26a8b830891fd55b2415fb702d4e228226b4e53d25af7cd0a0a400b3ced62524af212cd32dbe307195228c02c4edb6f29289da5a465e934060590c5262c66a8646eb39758a8ab23b533bb8776444d4d0f0a000bc3c1a300af3829e9b5620c931e1b972b0c0713a100ad28002b8e2987c566523ddb1eade2b4716d4d2e2e89ddb12a4ef1e226399ba3e4089531c61ea100a93866d70a977f458e3231a8389a50533954b632cdc929ce973bb64c9062ed5f39a100a638b7bb68c915e36a4aca48978408e2247f5bc5e6eb1d3a60d0a3471203c60e0edc00c33d033cc2b801c60d1f1670cf009610ac2087009410128853484d7296b4101773e41942007112b3dc9c85df60716232e40f87d731ddae3f77ba8446d472e428a50c217e38a694dc2ff76817f3b410d287832ab952e4e94deb22b6e3c3d9b5bd534b4596b43ac71e0e72662ddbfc2f88103d1c73ce4c729bab9246cfc36984f6bff892848793be7c714426794734bdf687903b1c94fdf6695c7ac68d1d4ed9a1beef8230a40e079992f0a75dfbf575a943081db6202c36aeb6b8a63715217338756508575306090f319085c8e16cf2fc6430b9c4768590389cf5cc524aa325e56317110287935ca34de593c3b2c738a266831ee3876bc0072242de703c61f51b5c93d01fb78709c01b42dc7092d56d2c653e493c31d68683166917fe64f7d831b94184b0e16ca3f6e29da0adb91d00cc10b286d3fa9c8ceecdcdf6550944881ace275c4c5a4d7e3d258f1f068c1b1cc081a3478b5146084400061837788491af0849c349badd11fbd39524137d313c4b081a0c070a39c3a95d2e2cf8260bd973f8701f3e72240ef80fef91fcf01c56a4106286938cf7a5c41c27ee3df621a40cc7ecfc8edd8b3bf94c0ee0c08103478e588490e118fc44ad8ec6bd30a5319c629de8a2f6f5ffee440c07b129fb82b818bf360ac3d98431ad1bd54f545843c070f6ffcd3b69c5f594d0178ea3e5449384fb5971f9bc70ce603a43cc25bb70ca50e29b98294e5bfd215c38a8db9482923516b285a3c5d25a954aaafc6f8521440b0721cb84fccf88e675b370caa0c4495a5a26aa5823f04208164e55569684d332f7357121e40ac7d42688d8dfd60ac768a94b8c6ab40a274ff72f59dde493926495e00618378a043746f0811b629031860e63215438a6e68cd9215f52844ce19cfd269a65b84011228583ca21644afea6c22a33a26696810b89c28540e1b0592658653ae924429e7090717467bf690b1b5b10e284732949df429c24138434e1b82a9a4a7a0b9dd9472b8430e1b849845566bc24f534860859c2495295f425e9f4c4a8b7e4184294707ecb4aaaefdd6a991292849324b37d5a3619241c568445519996239cb2ce850affde17428c70b6602364bad8b020a40827f9db4c924ada5421840827a1c4ca262d49c28413154286700a27871a1b6d4adbe9236abc234408214138d70927a364654d551523040807bd7137282b9919c2726f08f9c179e6c5c48a59c94e0a317910e283533e53e7e3276df9264dce01a417e7cf7f0d2adaab415b9217a72a251f328a7a2f2905db00b28b93ccacbc2ba784c9751c407471f612fd33a924a1de3a482e0e7a3f9a549e982cc606828bb36c9fc88fd8b09c1709406e7196d1385719d4d9670c882d8e6be5a9765a07a9c5296f854da29a7d93201d51cbc123951980d022310899e2040fe935cee21c4abeb86f72eb5b09fe304b1e20b2384932a878446f84a10131c468306e84f181911f3a5200128b93a8311b4cca098b639f893f66c13b1ff60690579c45ac64a94a21636d8c2b8e9ac34dd5494997c9122b80b4e2a084baa765bb9c60312b4ec2377f6564688c6f0f026415c7db978d76416cd42f2d7f0051c5b136e8deec88555271944d767625a395829211b56230e86181911f3a52b043070c74f41001af00041527156b64c6744d5aba8fe8097688e02ced28630c1d1c0390539c54e55035c944173b494c7158b5ab91b1f4864a651a404a712c49657ca816cdb6162505bff143e50b130d183c7e0707ba00328ae36b4e8b5352a8cfbb9c0144143a0009c5292cb8c5906695f48907028af389498bd698aaf7892499d51a26698962a91f3e76e828f703104f1477a2a2e5a12bb8236a3f748ca1430c3510dc00230537c2f8c08d528c8174e2e4256d595e1bad0184134755b91835172753af5e00d9c4295cca7a7a6397d476324d9cbd72fbe8c96413403271520d63e2090d260e3298c9aaa3bc33d606728973a6d09542cba8c918648973665e3a517493142aacc4955258b2d8943ae6cd434bfe36f165553e54cef86a004289f365cbdf716f2a9bc429cd5aecdd51aa9298d3c0f146181ad031068f1d371083c708dc33b0e7230320923849f2c49b58b934cf71a043bf001289e3ca5d12db6e47b4c5769cc07f74074020714a59369d25495b4619e5b07cc4d194fa2cd9d64c501a88234e9f392b9e9a3709208d38a5aeb10fa94950529a11c73e498bcc9976110771319d1a97d308208a389dbaaf919333efde8938bdba8b18134c0ad53f214010712cfbaccbf7df2a227488a37ea5de5ce63d635a431c4b54cbba71a62475152c810029c4492e799794521f21ce9a9a4fb8112a437316a369c0a30719641435800ce294562d2cc58908e5b7208e9ba133a2977ec7440371da6b8b333742fccdc6069e769cdd010410a760328556db3517d383c17a00f9c349b09c7117b2b44ae47600f1c3d173a4965d9e3c4a2999e006183870e0c07196438d0f01d287e3f965b4244fc6acc83870a08f1feec347973a80f0e19c21665183b8a0641161a0c3475601640f273f498834a924d92d623d1cde74c55872e96a13d3121c1d40f270de4dd7123345450c207838f67be8f82d490cd3271840ee70d6d9a4a2572e9b30b69501c40ee70d966d2da874fae44f05903a1c2e366a65e5cdfacb8da8e5c82780d0e1e8154cc9a4f5659210871340e67092044bb9d08d8da8d140c71140e470fe362549312396bb4f4b0089c3299e94cb73e9672b1240e0704a5a339d4a92fc1b4e61d46bd7bac363476e38cca971ff525b1356d486f34835414e5f98177db3e13c1bc65daec33493bd8673e5d5a5384956c3e1376bd2d0db27a846d370aa9355b7d35a56e4060d472f55756a41e68c3acf709271a28b491bcd7050139e65cafb329494e1e0a271ef44d1797f92e1a4bccda42acba7db311cbfe48cabf29db6b1a30188184e96e7d5ae73b35be6c370f8caa65b326949ff1d0c271d26b309c24ef469fc0ba7542dfa7aae57fde25e38fc96e8eac68b652675e194d794b4997da3ae252e1cb4c589f15a42c9f8c916ce9b525af432afee4ca285d3bfd9c8b552926c1c65e1f0756dcae384b0709e134aca994992e53b7485c325157ed3b292f8695be198b4e7e4cb262ec8acab70b4dcfe37df91e1aba6c249c8ec8e6bcafe25e9148e3e52d36a848a495251291cb36b53926bd3289c949e55f3711f179942e1682974896661a455de3ce1a06e9485a668bd76a6134e2a65f253e363134e95c45d7ff9ad561a99703c75269c6ecbc91bc4251c4459d0352555ab9d14251c93f80e55b97ca7c59284c3aaa6a0728957d738124ec9bafacced231ccd4b1052b3093ab3c508678d233c46f684915b114e3267cc8f2ab55c2923c2a95438d96eb3408670d2fb53fa4ba6a494aa8c01228493ec6c3bd19a830148104e3a476c63ec53265534a20d0284a38990ad416ec818def4838376b90deacfa4ec1381f8e0a46c55833c396f4e6869f4e2b866b71beb6450371e0d5e1c3ff4f66a7d75ee24dda0471829a0b18b2c9c5965aa7bacb6a9c566404317870f214d9d4ca67efc948ba3a6da2fd512c6c5f94b8cac5cf919748c346e71d0a3d48c8d88aa1e255b9c4bd693ac2451b97227b538d90922a3496baa2f515a9c82094a94bfb057fe178d591cbbed629dfa8a6b5a16c7e033aa4ee566aa6a62719e93fa2c73f86e8f098b93587b1aafe3bc55c5571c6dfeb269cc6ae9bb42c31567df686eb56efed79a561cc5ba439332bbfceab2e2941feab4c59fd9bc8aade234dac48af797bc638252a0a18aa3a9b1d798e4e465a9a4e2e4e773e25f0926dc8c8a837e91d14564e8f5499ee2acf9a21a2a8eb7756f8a9352e96a5a3d830aaa2fc531d3bbee9536bbe41529cea1e69a54adc995ee8ee29ce92d73a15772f5258a8312134753a8249b7472a138d6d8b949e99294428b40713eef2b99d64433d1449f3897feb656d9ef2b95d5010d4f1c6453fafea89243df6c041a9d38a5b025a951b17f42c938712e614aafc8743293a83771ccbeba09a9e6edabc87912e74aab623d324a29314be2f49ba792f5fba9d27124ce967262d21b935082742171da1d4be2eb9aba5bf611e77d6b97396d5ad3461d71d89a9197c433d327d4469ce43025a86bb6d6b01b461cc5e413ec4b83594a6216710a9644f88d65147150f1daf256626e93c9441cac2437f13443fbc524228ec1525f10b1ec8ad1fa18448d439ce4b2af5c552936c91067d1f551393119370b71ee102a9f4979d2ff9884385bc888cc2afddb3d0ee2202f575dac25b1510ae2e0e255a2ae64184d2981385cbecc68e13b56d400c429732c5e6cd396b9b1d6f8c3793ca4c5ad94b2cafb236a39f28cfdb0819715d4f0c3b943b78ffa7635fa70ee3929689162a142cfa3c7b5a0061f8e27c336ec98ead7ba20a8b187631284e54969c34e09170fd4d0c369db4e124d95ce64328b066ae4e178e9d428d962497a4e6944ade0e1a45d4e8abe1da63f7bb11a7738accdc6132f95cb34281135ec70d66c799358d91a753885ffbfb2ca1153d1840ee75f8b17b61a459fca8e329e6d50630ee7924bd8aa144c72388c9ed871b741edf72c83470d6ac4e118cdc26a1a5dc2e12493e472925552eadb1d3ac678c34197e9cd08559933ff6e38c5b8da9755cf67d335a2b6a3471928078fa434a8d18693c52e6562dc68a2b565439d39b332b2526b384951297d983e37d5ac1a8ec1b64b34316f92ad13428d349cdf2dad8932351acea5d93793b0164d9ee1a4ff37d4697eeb9d6e869398aa35dafa5acc8c1951cbc12371106a94e1945f6d94523bfdb241644057988de638078fa43fa83186f30925aafa92789eb9440c27fd5695e4a93a499b65442d078f1486ceaa3559dc7032a8c0908fc85841563458e30bc718da9d73e1bc440d79e160f1cd92e59f6c92d4236a5d38c86c93f5d4496a35642e9cbd92924a4d670955d5885a0e1e297b50630b67ddaf3c7a37a9b44d1951d3410d2d1ce3854bf1f963164e27a5afdc5c57b7760e6a60e1a02e9f50d22d778593768bc95e7194d49d8e647c50c30a07619b67c7ba1b51cb4186f720a37050a30a47d3b651132e448593852c4989269bc249f64a347529164a2e49e1b431059d9f73b7d6658ea14614ceaf6175bebaf4c68fa0705059d31a5434a9b2e8c450e30927fdd5e5be49cce65772c2c937f454aa7f089371130efa37428be8bb2499cb84c385fc56bc5439ceca259c74fba594f2a478a156c2d1c4726f893125e15c2c359270d02674c3f4e4cca2922ea88184939b7f2559724e4f291de164a743c6d126e5306a18e124be79dd8b10b727adab428d229c524d4c47e992d67f27c2d14444a970c1c4f593b11a4338d89c1e9b2bf100193d46a9218463a9adb2350d67b5e11a4148ec5ab12bcd2540386cc56ff9af669297fec1c1eb368414939fe1dc1a3e38650e9984cc6ad937687a71cc7015194446ba8cc68be3aca8c99c73f2c478ede25256a2bb7bd797ba38e90aea4dbf94942ff6b938c64bd16252169a6f755c9c749b50f25527b740d3c2523c0b6d9f235b9c2fdd8965a2788813bb166793e5b4fd69ada512438b73aa8f96bb70334d29b338c93521d79915277593450ebe88c541a85829546a3a2127068bc3d58f0aba9b4df6b45e918812ea62860ca57d7345257c6d2593fb3209ca56a4f67475c887669a15e8924ae782b2789372abe0b32dc8e8134f945561c5984c351ba6928ab734495d4a2a2b11159524a5ca1593a4ea1455dd9694265a668d294e426bf5dd52558a539a3f7fb564fff73a299075763d323a8a649e5071fe4b5414c54992c28fd8de84e2a0a1534f6a95676c0914e736252a68d77cd247f489a39b8951975eb24c903d718a5196a24b2cbd7fb29d380933b7ebdf52b696e5c4f182126e35bde4d7db4d1cc4e43596c628a91ad5c417974c9538eadfcac449f89c6c396f76f127260e6e7258d5e9f112a7ef0d1d1b2ffaf3522c71301551736a2cf867a51227a9da323a739bbe3c4a64da624ac7c618fb491c752ea39dd85dddd02471b098c72bb65b086b8b0b5f4402a573b3cd0789746cc59c4d23db233fe298ebf26405cd2d6a57471cf544153de1ecce47e50a5f34c214a7d154d7653c694664e26c64b42f16718c593746eee9aed35f11a78a37d24f584961e54fc449ae8bbc2c3e22dead2db5551de2282e27962ce233d47b439cf4a4d69cfebea54fbc1087f99c911bf93ee226c4f9c3f624715256690771aa3b3d57d3a197a28238daca58de132fe6aa1488c3893f5994204d554c9200e25cf5df3da296362bc91f6e3d2fa5de27ae2ce487f349b2963e312b9949faa0ae9598f6663e1ce498a07ab9234509427bd04ac98c17849be0ebe114fc04dd1a6f4d4911e5e1a0824a524f9ccd1356c1c3c9e337c8935bdfe178fa15542ead14b5b5039b2bd6af4e9694bdafc331578b899f4950b62b7f41878352e26d53933c879398b09bb9733bb6633914e6f409224b1451e37034d13d37b668e170aa72132c35ba6ff852bf84954cf25609b9e16849ca19279914dda1b6e1244c9d6cbd49f3051bce9b16f4db74ec7857c5b0f0c51a4e4affea884bf15ad7fe420d673f1d993339a59468d270c5d12498a445ec97341a4e82878f1825ac9b6cc9331c2eb9888b41bcc80fa1190c61e95edfbb416538cbaa785c2c0b194e6b314993b7b4f9a6319cb2626b8effba7dcd9bf085180c6d498edc8d26a5240cc70b2156dc525e4f76603888c67ca9499029c9da7de1f2dd93ab3754b495bd7032499338512fe5d1b375e1342a96b75ccd5c3809e15e32eea6b233d942627b267a2869e1207696ed628ae1fe962d193d46f9220b0791f1f22b98e82577341083870fefa169b1700ead69196d2dc9d9e80aa74c1be553d72f0595f263878e31ac70364b2273cda9fed574154a2563668450a1c231bc4628f95d392b86a670b0b496417ba752386ed21fa14ac62c6aad11b51c62f40f1e5b852fa2f0cfdf5b1295d79437f8020ac74c514c767d450ca4232923790ffdc1174f385838edfe118b79591951dbd1a30cc429f8c2095fae6dd3156dc27959c39e1c21365e3321794f869d91abe32ea1de1c26e6bf9f14957036e997b48b52a1996512ae2c25f7cdd98504334c5013db44b9bd18bb1186062e006df8e2086fbe4c934992ae67f7889a11d898efad2ca593f5f61e89a71c3b3af1c154f8a208274d6a829a8dbd6517044651f00511cef95f4aeeb194a16733a28666021c5f0ce1bc2af36bd2f6236a4987183c7cece0014617be10c271e35b123749503d2abd2f82704a82bebebb4d621e19b72b39be00c2f9945712fed54cbbf7236a37e8f1835ff0c50f4e258e12bff05b329e94e165cc80055ff8e05c61f44952e63451213482013284f4e278bd6b166a46d789bb0143082f4e31cdeefce98a6550efe214cfc47449c9b8112286e842d750cb4eb39439b3773dd4fd6fa8890e1f3b7424244272713a93afa1617c5c1cb34f0a172cc6c42bbd272bb738882e93e42825ca51d783c70f135ce0870d4ed9e224a35988e550a24df4b53809db9a36349992d6a4a010420b1e3ac08840c82c1c10228b584820041615f20a31c468305cd10a0884b0e20121abe0f13b72e820830121aa4840482a50718a901053f4304048297af88e1af8f8f1212840082972e820c3029eece0a18090512c2044143e6ee03268404828749061811e2e831e3c52d08010502487010c3a8c08847cc287277c3020a4130808e1448e04846cc2c70142349180904c848460c246c825be08b10401422ae1c375fca81142891c3ac8b040f728c3023642267192f3f449a5ae6652b6e4700d8448e29ce157b157424817f5b709227138c1eddc04d9909e494d08818499444b05a5df0c79c42928515a5b2cf44c923be2a439964f851d8534e2b4692d9a4f967872e58c38be661d37e9a4a994c4459c3ddb2f5664869bd11471cc75628497102156de449c2d66895e0b15f3531d2304111772880b3184e128049bc475d150b29de4885a08215239393d4a4ed54e46d43250821b7b2a0819c4416c5a5bbc38997e8c388c9da871599b378ecc0e361671cc64a249375af389ce28e21445da9daf8929cb96d0602311c7104b254533316d2ad1da40c479f48d12251adb38c4499cb678a2643ef1eb2bc586214ef2651121e245c58f4921ce3b96c4d45f4c09360871eccd67996166846c4503360671bcb0d911fda92283cc86208e962788106bed18360271ded4d061299f302966c4b0010846d8f8c3e1ae3685504b0736fc700c32a87f496ef7e1a0b5dd64c9371f0eef5ea53f5efd43a6d70636f6704aeac5046de9f461430f474bb2b75cc89e8763ec934606252831bd573d6ce0618b765afd95541eabcc1cc1c61d8e414fe69d89f2954c9a7318156cd8e114bd66ac4da62418e8f091c3f260a30ee751b24a92a6b2873e250e1c5fb04187737de974958da284ebce60630ea7aed392df24664ce5700ae17fe2a799ecfa31661c4eaa4992f642fe6a3ed9061c50392b6fdc282a2c031e3c46c4483aee0461e30da7bc76a61b0e4a7ec92445cb9a62fe236a660c36da700c71f9c345058c911f3a5220861816b801c68d1b60dcf86103ff71b02c6db0e1a05d94fefa4b82acc86cace1bc2bfaada4bee660430da75793c2d6e8be932ffe061b6938a96821faaa44532e97b1c1061a4e42e4d644681fa1b5bac1c6194e97e3677596d6a04b7062b06186c3c9ae6962a89db20c2ac341882ccdedffbab153186c90e1e4262c54f20afb4c63056c8ce1146477652879e33fbf180e62416bdca5d91b6987e1a0a5672efa520996c460387c965bd2a1c4ed49ef178e15e7d6dc4f975c4dbd70bedcb0be219ac208958d2e9c6c376f6e91f976e5c285e39ccc0b55252897932d9cfb4325ab4cc94d685e0bc7643ff657c2cfc2495daa2429f977f2081f0b07bb186cbd466c25bd5fe1242d84d66d3eb1c2413688d1d2ae4b219454e124b5da9aa8a1840ac716b92e76f2c3db640ae7ce946294116b92c2c952e3c7943ef597465138c8396d628d1a0ae78cfbef0ff5134eca4a5d52a26925df76c2498e0df72b41998e8e9b703afd264ebc8a19e363269c941493e34adf8ee6770907d5247d6788a897bd4a386fc9258637bf8aa2d9249c4ff8d47491e14767160907592293d0131ee1709adda3fd442b25b746385eb8f46df395b52ec2415c9297c4e2466511114e9954464bf2af7b1ac2595d7ded5d2fb9c74238ee5b3a559a47f4448370b0d8f5515fcae49c4038956e9d96d899b13ffdc1495025d637bba63caf0d1f9cccbcc226d1ecc539c734c689ba3711f2e294c4a44c459129cd5d767152c25a6a9697a42c4517870d8ba92fc86fd1cee4e29846d6dba48a312931838b83f9a5097397ebfd32b738697606edb72783db698bb37db8e5a573dd18cb5a9cff24b74ab2093d494b5a9c6b735b8ce9620997348b53ceaa46313954d819657138493a69779fb94e0c63710efdd9142d85b03805d1ec1d2a2353f45f7110cd62624f3583dab8e2b061b6a413d38ac399e5f9a6aab86461c5a92b7b9d7649a7eb2bab38f9f7655092d2a9e26cb1fb3ebf74a938ee28db1437e6f6660e1507934eb444469b6ded4e71d02a3a7231dbe44d628a63bca4497ba388cf6ba538fe6b98785dcd925a23c549e62f51d3368a63d6e952b1ffd27d2f8ad3853b15beb2f7c892509cec459d247d56a0386cb8dbe833ad749616f9c4b9c432e9ae37f8efd8229e386b4cff4d7e72892e428c8348274ee76f7ea94aef5728e5f0d1653e2c50da20c2895309a595b4a2a56f4639600232ca488e0132ca489e74132771cc4c543579a2a58906114d9cc63609215e34c693fd1944327152b13108a1e1ffeb3f260e5ef94a5692cf041d3233885ce22896c5b3e4e6d13c6f8f8343c412e72c157bfd130f4304229538267191a9f7e8e1a7042c4289499c543c292c2209c3110391488840e2441e71161fdfd465ca54d88afbc023e28863e5ba88a705cd273870300f441a7130b1d346d52875b308238e9574e38fcc380f327c780fdd80c8220efadce4d092414f7c8031802b8828e2246dae50620c26e5104a228938679fcb4932f4799738a2c6271041c4d94ecac6294934d49a50193e700422873888bf32f1aaaa1aad8fa85d08440c71d81857a9647dd7a8231d3c7e14e254fa6b2ce9498893f7d7ae8885d256ea0f880ce23866db5f493a11c4d137b4892d7fa1fbe2409c92d25a313aeb4ba60788538c3bf6793a664ea9f60f0731339b318da87e2b89f8e1984f972c1ec2ee83e1e0c389ece1647f297bb8864d440fc7b372cb241afa1a6f913c1cadeed384d91ce284d188daf3c831e2a337802a8287f3b98931954d9bec93bdc3492a5d72a53ca49f9df440c40ea7fbd7ce2cb1ea707ad7f495c424d992b0a1c349d95e36f537933775581099835136a3566a05d79896c238c6a0811862c8e168e9d2be9bbf011f37700fc4e1949d9552aed6cd90aba982081c0e6e29e54a3abbb69a7ec3593ec6b2896174c3513d44c7975e4bcb8a481bce99df62ced718af8a89b0e12408eb16d57b5ac3b162dedd3a29ac8663da4925941edd1b53af0591341c356979eca59c2af193418fc1131041c3b164daedb7653e419a233e7a037b64f4181d1039c349db645072e84ba5af34a26686f3895768b5e9de3291a1a30628528683b88ed025efaa81ef702b531021c331595752490c71b3de160a22633898e09afc3f93c60922623896bc66c1ac92c270d253825eee250b13180e266f5fe946bb19113741e40b278bc154126374f589122f1c947585fcd9ec9420d285f38dd21fbd244d64a8b8700ca7753299ac41fa7f754810d9c2317ea9be9a50f11144b470d8e82698f8b61c0b276288a143065938f6089949dc0a9555d458389a459dddab1246db39a2a603912b9ce2afea553875eac46d8563bc544a6534b19a665d238854e16ce2ea58ae8a51e1ac96dbe7478e7cec4f0491291c6f6b468653adce3c91c2495d9924ea496a49ce140a41240a470f296795d6dbc3741f50386869f6e656cd39568fa8390c9e702c31336553192689b28938e1e4966e94e46a526e4c36e1a4649b5b5c90266e4c62c2d94c7d36469df8891808224b385f9f94f9749d5896f4818812ce59b9f9cf828673209284c369ead167654ad46518092755ba466345b30df511ce7b996452a5a3ecb26c84a3eb9dac58e262dc707d14e1b027353d344f8d5022c241e993b444ce87ba4c1a511bc3b506224338a8e97b134e8a5db2288908e12826364be6b4a0747961f81009c2f92b2ca68d975485460111209c64ef8cff9cb064527644ad0c911f9caccee204add388dacd40c407a77c23bf24d37c2f4e266bf4b33b99c2cb548317c7fcd1a5279ce977d8bb388d8a8a7b69837e06378c92821aba38a8afb15dd924698f528d5c9c0c6ae0a2478d5bcca0862d4ef228f1532a0521d7e223d6e3071988a8518b53d8df684a30ab8ca225a1062dce662136b2e29aee9db11338ba4183a0ee878e1d3a769491c3d10d7a8cb3317c8c1ab338b66834a9aa6d2784892cce96abfaf554ea9b4c6371b638fe1d4a75c364ab018b538beb6831517fc53149566283ccb2385a75c541a80c7361764d6d50a9d18a831675e1d27465b62449561c83922565fe8be145a85ca8b18ab35acccb5ccc772a34559c7654ca55eedaaf50928a930575cabcb65276555071922df5242989e5250695531cc3dc49e16c839f0c15d730c5f9a4594679ddd83fb2b292851aa5386b8c7ca93f19a2f48651508314a73799776b6575dab4511c537be88fa6cdb6297e75a8218ad3269942653b31e692261d6a84e22c1aa6164bd2fea21b501c77d34952a9b6fc1aed11b51a9f38f87de55c8a3b32cb7b861a9e38e8adf8d6fb6c861a9d38eb9624eb9f60d51b4f9c38a5b497442ce9b6b6a04d9cbf7d4c8aa9356b6734711c9fd760e278795c3e13c7a094709dc124499fe531716e3fa99494943c3fd65fe2e0ab6be94556895a274b9c529998b86adf9f49528963ed8efd498bdb6e25943849d269038d6aa8849085325924120883a15020068370c4b90063130820182c2a0cc622e18038d3b73d1480035030284c38341c242012161889c4035120180a0402824028100605c2c02028440ec5909ed303fcb3fde05fb915d990e90c854c6d3639e84c3e53604bad21586865d61b0ac94842f207c8a5d85fcc8db819e4cc40c8c57574fb27442ae4f040f11ab540490cb1eb0e21691e7c24cddb1820dd678333a0012468fd1a9e45c9b217a1b5ab5da525d3f6f48b6b8d49ea58fc92244aaf973df999e661e09fb23942227075e8081cfebc502622ce6d6b5f034b8fa70e7b6a7a940b7fd2f96d3e77f4307c7a0ff4f7295fc2b129a9dac89b8533acbabff895e1d6b0fd085b2ca05568fce9a956524b2b9ee47db431fc6263c03cc733a4449463d9bd45c75bbdc441150df471896b59d672c6f980a03f38214cb679137c4e72e053937f0820dc9bbcede520d8d379e8b32a73d008321780877d01c9ba950acd41c6593b0c30271acb6a87723d982c42e7ab614d3532370f461776ceca258a90b43789a90680766a7fb93e99e64c636a3e57ca75e356979f118f0ecb96194ab49f840dca1bbffa4ae641aefe95bb2804a4242705844c6f5aaee6c54bdafe88627b162c42e31656066b80d2d10193f5a0636abb8aae096ac1fbea2404bd12efe1682b3e62aecb2e4c4ad157bf654c8b02d9622c9f6271df21c70edde6855f033d3131de0b08dde11b48ab6ca10ed03b51a601b4936ff0cae6f612fc0ac47f0362f8dc2fca7b97b8f5847abf66d996cc0feabc5f33a673dace3d89be5645cd2a119656f3dc9a366693c31b2d5a8dfc7e7d23a335b08121fbe5315f7304cc986887f3cba500c360a7201d71377559a084fe21f22de555a6b752944bc0c011f6318a977e445c4cc268bec3885d463e505525fbb2be1fc7b491487044a902882fb5dc6a9d42c4e7323924c33cf33b605b62a410534122390a268ffc6d3fe82aa79bab3d227798d74d5878bde0dba2bd651c095ef6231e6137b6758ab7b727eb99959c3c62bca8c7a1606049360dabf9e6209b1cf5455c8d29f004ae8a29f08458eecdc6a7936e731584305f5824c737bf9ed992453259cd5781b23eeaec98aa1a45a412cc66881c912fb2d50c91ad9147725599aeb7a03dda3ae054a028ba3db769203bdc3bcd3cb1024e5c1f93aaea0eaceefc7c25be8ad38d4770c59853afb0ee89973805d511b406cbfd007083da70a9e6d9fd2cb3980d9bf9d4ca7e41dbfd526de18989d3c0d3756b5418a681f985d46bd9051a3bfd4b649a7ddd213d9f1e41409f06cc2f80c246562345f5075058036603d63749fd1128f0a448497d16b0b2e4d8bcb778dd615abc72bcb040830b061658e5cc6c03f7618554bc2c65a4a5e0edc24ca69751c97a5014d63328e0b5fb9e67ab0da8faa5335585c80a49b0079ec6b1274b286e4eab0af77cd008b80d6e83e2b54794549dfca7222006de33b45f11ab79bf92fe5b5e04bf64174378261035e89f7355cf7b338e805371705c69efe89e4b1254528234663c315b34fa32a46e972c0625921299ad8c4acb1596d5e1b47eabfbd76432a0146dcb8b037c322528249476401255344d63459e22ea4153242cec96751ac7780491a5ebeb5e1fe194c898b5c4ca7a9a9736b858ba3775d51a58751be1ae19e379174514e622af2cdeb98865724280a897c48ba2ce50cf6e4a54930cc2d78ca8fb3ccdf09ebc1b025500be596860d0e124a5cab2235e7a5ce95a9762ffbc2da9265f0637efa11269625feb7a1948741949d4a15b6cf5523bede8e8616dcda18d25d1c72c37800dbc26420ad56fd23b3ec01f7052e21bad9d5361a158451d072aa5e7f8846aa631404ab4c92d65d051d1226690e3a3bc463d20ac21e80bcd2e4a5193ac513ea3f101f95e2296240fd362a79e0b7b9eb280358b913d59b04cf60d7990f2cbd04672d39308ec2cf4029637936cc2518c63c90d3f9801474416be20c38ca22416a205aa484d790e2af39ce392937a065ccbc74187384e55723a16f515be7a7fbd33fbc2d25c1d98da906f191291be8b48621571dad05fd5d00459e03c24c84762f10a4a4d882f5c3e1eaf735f1cfff786abebf8e436e1e6dfc77883db337006478756ad203dc1d0e2b95905eda40ed447237d2e08d30d44a014119dd24a804b2264fbc073749601905682280d636a0a9e753bf45cb3cefce43d52cc3fc6751317f897773588a24e7e573ccc573d4e44ca3188e617351ce3dcb4660c7504e88249cb87b25dfb22ee8f96d4e12653a8d329973ae0dc402d9d2600a7a40ed2b8bb1034aee8c3d96d6f3c622d462da7193c8716a3da915fe97b159f8d420701780ab0157d0bad98b605e472d649001a439932e1e3576fdd20b4c586a4b75e441d4285644344bd047c9a406b1e91a402bf6c624a2f99fea1eb94684071a07c887246496d08af41c6cbe299c43e94a4059cfc2fbec46e37ba68d773937d4bc6fb66c23b5eb1f73d65b93915d78f9c61352acb45d5a9475838bbd8c5b7f909fb3d7571bcc5844e7664791f4b6145c718be32b22cfd87efe01f6b217889f05e63e59072084cfddb7809a2e0dbf32afe4100cd071948e2c1637a40bcbffbdc3b1c5ca033dda5d600891ae6808f157b41efcf3bcbfc0d5c86008fcaf515ec118d52a31625837e51e0927591a584898580cf31c4f2e4f4a1ff710a2a14af5015582e8e34eb84e260598d3419a2aeae8335b854a2d516db15b03d88481087b2efe3ffe064df949875bf53a50662dbe693d49cf21b1038d3cca9e6b0a964a5abadb2be84a2d41ec2eba2dba8872ce69ef13e8eebca34f26aeb4099e6da891d1ec35e905f853973afe7b4d83c903a1e21f4db2c3e454a8f248bfa9aaaf917eb8a930c3838d33aaaf9a356e50d4e9c3a6650750791cfa646effc29a8ad6fb840e8170f6550ca38350aaf950d1e073f55cec2f8a05e5c6e6caeea1e0fd763b3c69f60f0296e61ec82deb0bcd87ed2e243fce21859eff9a32e99fc0b76e032a1771b3ad09297c73d6a05d3ca8b7e104bd6c201a7e9415221889a07b3d3f438ff9178e0acdc091e5c8fb63a170c657c260a1edf76651555416b0369451dd20c522b7ad2e065834dceaa39ef49d8c319ef3178c70fb0e0d8c3cb2422aea5a2037279c4526f568f809558068339402402904621140054286e246f7e6c7388b56ac8a1a957762915934586dcd80163c7c1079778cbb795bd84cf949cc0dace8ae12079955a8daba162f2c353df3c7be4fb80be1f9655b4ce977c761a79175c35b9f2a8774f353865b180584c9625eb3011c9f47249232f9071bee772047240862ddd8a153c049c3918dbeeafb275081ac1cae0d0f3ce1b3cce8e49b48c7cb4b218cf57be23dba4dcbbb944f0089517357dd114efe5635043a2a881a13199729ab000c9ab6add337571eba2aa5ba72edbba5c7521ea164e97aa2e99baf874abaa8b5317f7ea66dba3695d69d6c5a34b3674f1bc8349edff48395dea38ca31044ce530f1fe527b406dcf9dc3fb2d12ef4d5de2daa5cf5b5a77ebb3f5e2ab98bf84484cd082088ec599b30366a4c0b4b2a3bc7d585f81e52b0760c55bdb230c925aa33dc8c129fb5d73eaf6b7b6b887008c0af527f0984f408e0536e7b15e94250b98a179084fad1b8536b9c71fd1469403821860c7d93c3e309ef87e28013b1339caa526587916231756d87d3329db624bab9216c27648e1b748eeced10621ddd0df1a741345270f7e2c46f05f0239a2253297d2f95a450777f0dd543eeab1471f85c5b923ac048eb7bad835b3d8e4daa6d9b8d130ad0d51b58cc6ef34d3172d12d080abb87ee0f5333fadf43e0a64a591438326eff881b26bba8aa7ee76fd4123b271863e5921c2b7f44e443d2cecc54f88428b0dad1d6d36c50d7db2c2ebcde6c24e17b355c642753a934105a9c75cfb5ee12efb083a2643610b8b383f874a059fded699c7909b86880a82f631b6b3b1b6d9992c89c91bfc1d8c3567ac1c9d712116523ea1219f2534fe85b33aa523b30045ef0705d897fa3fa7e3adb0472e2155aa230ab8238b1afd59c08201e18ccc46760ab8d814f67b5820a617a2c2ca981220b07d8785bad44961963dcaa58eb38054c40634d7f806a88fb006dbef94cab85f15f7d0bd63b6193cec6f1d853a6af5889e10165c058565339580d1fd9c668d71e041a264b27a05ac2a92fff669a255a1837006691784a3214d1141311c92262c77ef7953145e57baf98bb378e0eacbd48f8bec435198b307e736c771d110e0573eebce11d6874272b4d19128267ad95bc40025952e33c46a844287771f99eae04c613d538a62037806bcb94089dbd74cad9d1a76dbfca9427467ab22def00990d798c6f566fe9f74f42276ec2a5d6ba3fc0b5719fd83aa97d13790a1153cb000dd003405da2690e15dd8440cafc27b500713be0e1249409404320f0d4cb66fa0826f53c6ba3e2904324947600876019707f86deba972459237dd92830432cbe4ffdcc3c9e6a029700dd160a0ab4050ac9208f74d0180f5de0904219a4fab8c30f438c5d1bd5757428f3e4e4f00339cdda29beebf458401503b6fdac5c00f928e3c9ba9d1c60f16db8032ff282d21df7fae488bfffdd893788a3570bc57a3549b1a4becac015523480d6a1acd6de06285cf1a6e5fa7ce11344a2940e092031a25d5d52883a686b6061701daebe3e0eb61626994cc3d14783b2d66cc191988a252cedfa66c67fabf2543508d03d121402480259aae947bccc33d1c7b8ddeac8fcc06d52b349aa75a0bb5a76505df16b4130f4089592a4f86a767032f6065be94cf86b85157753585447aa469f49cc1953674cb811d237a771885c113e0196aad3094990aee46a2830611358500e264ac3cf50c35247f68d26cc1d422336cd2f4f627a5f92b25374073f07140230da5aad1092ca917fae079cfd0d50091cc017733f9bb16ad7473847d1a6af5b7e765da30ebb27dda269236781854cd406f0364374f370c5ccbf8ba033d841e879a8114fea902924b07dacc4e960dcc6c941875a319be324032373fc9d1845d3ff618b6dc96060f7e3ab43a1f106450ad05dbc557c8504b9e21ee69fbf4852a15030044f87f6ef90e0f133b6838686e2a89625f7a0d3376b6ce8d9cff3e260b635d88650121623bfc732219fd253f7a7a92430726c9b47785f283e790eda8817f80e35d2e6b4d3104f33cdea8dc595e7952e39d65aca8d58a2adc84aae3d5353b3195cd508c70ab5866d0dd1a6abc931230a19ef526a9a2bcedd7cec070471ae96f6b9b637002fe442042d03f5fdaafbdb3051d4269e02e63b921d91721590e2ae0c33e4cb6c46d7a101aae9f580b6b26b5d5c89d2d9fb55353c6bafef38264b6c76533599d22598b997803af9f9ec8589673adf533d36cd8c1c0085df39def9f8a540f748cdbb39b8c2ae2fddb296e4b7b012c0119e3c82dddec1ce279c690d7a3b1ccd9af136896672e2c817df61f2783c841ffa73ff10767ea642f801e676e9b27b72389e63154933b87eaaa0ee35f17f74ebce7f1a3fbf978a6108478459fbaa4c0790e08ae791efacd77f91c169e2e3d0ce87cb3b360f012cef74adf32226df9d5b6257cd7c601df06912cd5bfaffd36746e2376d80e2a36c285c046435d77a70abdfdc2e934ba1040e098ee64debebb35941bee3a154e9ac23f48aa28aa48959d920a779d8c28cbeeda52228ea789becc28ecbe9971508d0f44a4214ba3f0ba255003603e70883ee40096044a8771be677c1f408f7fc34205ba3bbe9545c9597a8b67c1ac4cd84063a80fb165f28e5a706144b4ba5e762366c5731e27c6b3ddc49123340c7220ea6ac679e64d72d669888af729ec6394fa202855335b8966b7f391106924d800016ff9d1084a09b14c7323479959eed6acf5445b5824ce2b3e047b0b67bc5dbb6c722e700ac7e5ed2eeabd40c61b989068ddfbb87e499bb4c3699f5039b82c89466e49b58dd879d388bc92f41e231eee416a4df634dd05843606ccbabec96dc538293ae6f25539376ca64a4641acc93715bdc00717055f85824aba56aa551d50d2c54a9b7a2a61072f9a22189849f1d04543699ce782a294340ca6f87fb027d19fa48c8def2cbef297d8b4b44542b2ce433c28eeb8b9283d82aca9a30cb95c91d47b7762ea88a94b7377eb0639b8122350bc51f23fd6eb664ab68390f946c7a999479ea388cf1af6473da4ace638f240d35b192810c4c5a0e4e218a1129cd7380033a926672a7d674a9afb662b8f10db9fe42248ef4b09757671a1c6f089b4b3e7b7537ce440417419f939f57e429cd66312787f20404a4904dc3a73a22899c138375de426d97160eee8bea49608f69117a726d4ac5ecb712b83f119b110fdb3a66532f7a490849856e9c6746db4f61a7a71197a0b38ff8d78cb6162d0ebcbb4815e1d0f7e1313c0e1deef67de598db894563312c5c9dd616f29cd665df604eb3279596432455c03e61600795c82d8d9e5a00915384097dde15f20023ffebe9cb980bcb10bc72f207d85717afb04a238c480c0c9026291d2d43a3ccd6705f82d236ec327107ec2a87d06dc7e6f0e939f6955064dbbc53662a01b3ef286aba5a98152a4888c1fa2236c3a56aaa4ac314019c249c7e87024c39687e3759142a665d0e3701c1a15dc435049939f12652a204ed041459039d33b2c5841934b65acc451f6a0f6cb8c87e06b0804eb76952b10aca1d4dc8ce6990987645f386ae5ad683f00f64927d4103c712c6542435fb9512e2c918361e651e97aa2d6c108ed4aa25920a681c8b4dd149856c2496159316463962667045900bafa21039c184451d363e2a74a957d39b067ec42ce5406433edea60b3cc190e6046411ec7d9fcb5a92c9c8748ea87ab8ab92088946cebe03d1301bb8f8c0967a60d853669772ef2dc281998690f543fe4d800fc8c19593d06b9242157d41a424f964055dd15c391f871beaae121493b9a5888b61739daa6bc5ecba227123246d5f368172597cce72b526ca9769e0753e35da3ad8e48fb2eb274144d7df8d1cfb003a4fa7523262789f9aa88eba74668875d2d9b99487d28c6979e980b6a4d87c95471553f85501a8278de71f8192db85f00241246e34ed69939ff15310f98a5381c5e60b2061126218fe7d8ac08d593ef0545689cc97d17e4751bbd99cd2486d4a923bdfc70e019bc9740f41b51ed21e3a184e416b10d1160ab7f188e5ef59ef646a84e5b67dd87a89787cb0c7761410dccc08cccaaa7205cabaa07500c8c2ba9678d080089dfbfd360828012958a6001dd0e591ca44cc0698589532d1b1baf9d4f8918a48faa45a122705b75ab6a008cfac6a3e7da3c2cc2a56076d61a40eae50b8a22692f5fb69c25465ade76827611354c00977d0f941e40d7d985b6749aa402a5ac198c4037fcfe0e54f96ef2fdba1e8f14abac1f8e68349ad1d909a61d72c9bd1b9cc09ebd301201f952799d3a506e071c25f6f246b921180b172c0fd40f5129eef1ded59d4dd62fe7aae54960701fd33d72edd39f5ed604884cdd1386e190e1076352afcf5ae627c4f52a7b545f50ca404e47d82947f76717e4dfe6af60769ff1d09ac518e6247658403117c58f544ec8031fb0b3a08574b01f38982045154b802f2f81a495d1708d906cb53237c7700a1c4931d35046608a5fa80e532ca618478ab68a708ba8debc763f9ec69164d4a12b96d9b952f4be541c960bb1a874bf738cd8f433977785e9f758e1094894a5352ea32a0dc274291b1e56053290a51adc9db529242542baa62608a8d6d988b95a5bd8f0af7f3a7e983f572076b93c2d4c3b1707c9a2e14686b49fd1f2511038df269c585b8ea38d8b25fb435529bf775cd61c072507520dd03b6344675ce38ae69d3efb39216c43808bf6efaef6ae08e4b58f2bc2988217a837f2621b008accc145709788527ce055621d23e0fd9272d09953b3f4d488dbc86e9ae91c55c0ee01e2da904510ada9cdf00ea507893544fd2b93185653544e4ae38b5ba43a12d29b8c145c3149daff54abe87c25937bb384992222d4019a220a8338b80421240501e0a5f318fbbb728d2281745078ac3f56914c8a797d9b06c09e95dc63050bd4f52d5a61988cb45e76f73c5cb0c833f51a55c5b84897a65ccc1a667507df53b320472dfd3be17168b6599bbe7d1de90193a490811949d6060f13d666ed09adcb8bae4109e6e36b024002e77204105da85397a98560aa71c78619df08634ce982c23fdd6682ef97c20256c83e371a1ab6b3bb92f1181bfb65630e10808810bf4f064480f231aeac752aa87704686134699c6f22e19450a05687df431d970b35d36987d4e4622455f560747e2507d2fc3095c1c123c0125b8655206078a719e82d6143121b737eaf897c702f075e99ce7647fb01e4e1b413548b1c09bc923b09ed305faedec0f2e4c950d8be87900b0de453fb723ddc0427814ce7e5ff1ff60a1127154f01f252527fe1b21c3b47c23230b61861b1657d0484a09f57ee03d8e69246f98d587e02d99ea52b3e432eca13a9ff0b09ae1d66ba4d38a9e8736628a201bc4d9cec3250939fe4908353e01f283fed7ff6450abd24af4d500e1c606a9dceb95c0eb530ae79cc2322e0e9148f2a4204005903e66659a33cbd839d040fbb15babe49e5dc8e705372a29c6b49bbd2323c9ac258a6cdfed2c520e61577791788d71a2102cdac66296076625f41e9e13ed8831b4aec4aa6128a396ee55b951239952e0cc51f6eaf987575cc92f93b06b125a8afae0327cff19a8ccadcb7991e3bf0194b379723aa7bb4516026971e4fc840843c691905294a41360200a8428a9441c69d0c6b9232e4e8053dd40d0867635dc770fd922f6a82827b259f8b42b889765e786823e59f20e7477dca51c572e2703d4701a38d5a75c4cd40208e7e4e03fff3c2b609545141a84111c363d8c526a0765c9f7ebc11b4e2d0e4f822e667ed2353821db9739ebf3a978d9dbbbcfb0de9b8bb85cb44024351f08274338783f93b2833e575aa0b33c63f93dc6d2a30432e03d772c1915d89b567080994e28b3d3c24463a42344951a6bc320cf38c2ba080e6b69bb294ab0def48f4a7a69111099802922e82aa27896b667671625e6a11cefb73dbc2b4f7a5d31cc7ebe0da60eb4d00e568674d41c7be70b65b034eb9d4212830aef623ee48a91fb290ff44a195f9f573221c52de620282981205fa54acd1a1a0c393c0a96bedd57567017d94deb93152c19afccd645e33390a8a3714125c36ad49cb64439a1a2f601bbecc5d9f2f3df167ebc79c4d27615440953d05dd0e1a2a1924884924e18a6c98aa50f69596caf6fea21920145be58adcda58daff27d392f562fe1f04d58eba216385dce20aa1850f6412d27b1abeceab241d54236cc7b3ea3d1c40ec43b4a813bcc8c92812cf295028aead996958a959e311bcee8c425bb4fb2dcbce58c9b1c28184dbb0821b699e680adf1b0310618a162eee1b59275dc7188a7fd48f30047eaa05c625ce6ae2c6102b12dd71f68cc3f76d751d1705efdbd39a6e659298ddfaa1d6fdb1055a66a307119aaf1e321c75f80dd7d78b10a660275f73fc6040244f56b2547cdeaa22346a634adb7e3b3898903857e1143c78f3e543b8a35de70a4ef7ea473b25a2653ee9d5be2bfe628dcb5ce52f1078baf223d8dfb92780de9f516bf216259551459266fd9cfddce6eef0209d5f999bf34414045fb3b8a0c367adbff0595a46a19b5262b479d48605effff4cc4b391f2f0e53c39bdc837e3c396b136175ddaf5c441d88117c716f2c08e6cce5a94c9153a930badcc7074cce2e8db95011c4752a2438d99f9e3afe9ac8d97e9ff58120e7050fa2e19429fabe7a2eef4aae1d75110ea21a0c8657dd30a0cdc1d9e25e31bc5b35e5de6347409b8131cacd7e0e828b3089b650d222e59c3a1dd36a76827ca36450494888a0203abd104f5a62dd2028152fc857d6ff459a48ef84e2cf1a045da416955b4cb0c802130ca41210c62f0bd851e18280c6145b77a1184a8a8ca362b7fb8a9100547120d7b37cfc70a9c315d70a56cc6f859b28230814c2043844de83e5b38115edcb9c95ec2fea4cf0df88d4349bc1ea1b5b80f9581e3094a9cc214b6e9d1f9e8d32362ec796dd8aee1d66231bcf0e8204313624c27225095be05f0f55238b1255e63828474cfaede3c38fc4bce2a3978d5faa94adf8bb388fabb3ca4502a4057aa58993248e5fe1e2ab3b0985798f76208d41005392338cb4a5822475b60226187779125af8ff5ceea4162589a455824721c0520914802b1db03326747f12944c1c15e12e6669da067a9bb3631a46decc245c44823321176485a8428999c3fa1f45b71845b0425826ae45cc1fa8e3298e41d0b9a14a266f8e52c3fd8849d5a802bb014d00955092405720220a11e157abe0f9dc0aaa0843044e02e6023d42fa0a5856da6f6fc36840e023642f01f8e45e6627b0de193f051a09db0eb01cd29b6757eadddadf840912d41fc14f2694027d9c75c70e6b29f2d1cc899924e097ab422386a158000b01d9c36fcabc11aa489badcdea9625df3f27f999d50523f6a30457c64130de2b9b4c205341d78d83ffc0d5e862f11d2c8e2cf4abe0565dce793f1acf8e2979795af0b9e6688f70e5294751ab7a8135103180d03c436dd3d3748db6bd3a9b28ca41a2a9351c30847557f925c41894e1e30e308d6596dd07aad92e664b135c85b10a092517388174b18d93b5b321492f79c49ac4e5137a386de350ceb3451838d1006b26cd2d5c9f8b62ae3d1840cecddc9db6afe65f843df9025408247b7aad603a8c91280478b3dca920b110a33005019e2ca674f4f84d35a693f67aadb270e7ffaa49e4828cfc95ac35bef42d40ac3558c87aaee0039728e85e65a1cbeb362d7579ac0b309820323015d67798103471a301909d8166126f5d8b0c8b1c6b06d3b0004eb2620d3126bbbb288996d347573a94b3bb342d2e914b7cd25276a2e26a50b16bb583e230ec35ca4ba25cdae923c9dd0654248a92811926876ba1d885a87b5d297e9c1d7c878e7327a4f377a18b46ea4b4c32e025033a2c8487cc6dc0f097f642a465264f4ce77dcc1a13c43bfccf8d92e4cbdc858196430adcc8ad7d65a2549db022d5560f3559c227a15977625dc610eb1eaa984ede63fd13d045a59e75269580780c282325eeb5c15055810146456fe12292748118e0154e8779f1a0834e41e361130c2742bf1964323741acde202a0c06ff54e121e96f2f4bb15a1b6a8d3249212e0487d4816a0632bb7a570a9ae65d1ed0bb5e6896aca84445a0a20d15929404f50cc84ca9407c95932f098893a2a34143989534f81428977388819805ef017fa5e62ac48944981258ca915c49defc24c8768e5eae501d2d5782e8172995bb8d5653edcd0d6d1cf60ba4c006130feac5292e7236d69b61dd68de0776f6cfa0e7488138e270e66742e0549ef50388d38feab386ca96b0a265d62999f7a9e43ea7d1222dd162db9858207e1809f610774448060989563fad04a0b10b184b054a4a555c6c258203e96e53823bcca574da09bc56a11b5449751921fb1a521fc6b36a9421669976dc461b4bed1cc4423cb7613253c9e29aa5c7a64405c89e8c5762539d3174297b5324c2a831d6d1a358b02443ba3d8a275a26b3b3dd170d9616d3afdd68a8d2bf9ab32d8eafca099fe493204c32a83f9c44845c0100168912745286c0511027a940ee692df9473d76c450bc3de12bbf3c833e272289e7a0ab552b17a2d6c40a3a8368c7c5f8ca58242a7652b3f874a899a98d70cf1434982762c09c90e3ebe1de6056ea6e45a4353a4a434aecae2c9579c3c4803953ae4a5acc2a7085a5210232f0d3d511114366656c246b37a90c9b85dc6e7905272095d29769536ff99c7deaecb2adc4bd3122cdd2bb9d224221fc68d64350895cd0c5f0eea5d10a76c0e8257a077d656ed577cd64bc1e4b31b0bb831a647bad1c5be294f415c9fc56dc29594998235733e35d56e53a1b27572dfdfb7bb4270a32d89f75c721dd572f471414f047799e25eb3eb56a2cf5f112865cce57c7439ee6d4834b5fcd667dd8e5bd8871f9230cf876fe999845269696550d25ce5f9a53f5265088f01abb2967c33ae4736609673dc31f03835f7ebe83d1faf0a3d78400b7450214f846c7590e35712067b9a9479b05472b2b6dc63f3aa00225f9a772399d50c51254cf5dda54575b28306ce431d79ed70ac5addec386a70ca204a1b7c08b76b35167c716bf7da45bab520ea2fc684e4c8154482745b2c9ece650255763dc2d1d86db03a00236543ce9fc2964d26b8e9443f389c23405ea74e5a2156820f2f41d698d4bfdc39e82e2bb5075080b7cade99a75142b61f003f9bc02784faedd63042d51ff24b691c0d5206ed422f3a4918cc562b96b9f12b6a279d9c5141adf85d3cd941988c5aedc74d1c6786682ec7f8cb01fe36b5894c5ae03707267f20c0db9444ddabc297c0ac6a56c614d5005833254470a7869920108c49260ef314b95ec9ba1ced05d6335727398f85397e4007ba67e8c099f16e23d2634c1c7d2b5abc0e2bd16e932011d1fb5345147503ede590569e1c132c1e4c2b3d636897ed3ebb93ca54e8db08246603c31d273ed2bb90299bbbc3a4f081c60c8633456eab3e9b607abee5e4552b3d98b992674d39020cec3122fa3eab04df0e3217726e2d1ed075c893843824447202a28ffed809897f2f5eeb90429717a3584a76a00ec3697f43c1808fa547b2b8105b6135a82b562c819ca93b08c368fce0fa0c2ec54ee6174325d43df8e241dc48fe04a4e780303e27eb11553429110ca5556a6b4a3c7ca83b2a075f05d2fb45e1c10d7adbe0b9ce7671da5f29d473a3e160c01dcad54f71201cf1c7fc78a247722dea65d786d947472b9fe6b8587b7062de8f8857468549a1d7cf998013fc0f700c0e7c2cf0023a691a47f1eb501a27dc4060ee4f58da27cbf4115e01a408e0c0ffdc3fd08b9b767e81d376bf3cc9d26fd069aeab9a2da5775d85f7cd045d11e37b56c3b4f41b0f11a00f8d196997c2919b7d6ceee06a5c18e76994393180681e1a2db85d850afd6c1ef976431287a545afa2375d1cdf8d07fdb7aecf339c15086ff8691473983b125d2c84fd77e93a60be4f90a6577849f321467dd4275ab317924feec822d3268e7918ae58c410913ca64cb23bec3dc4dd277b231f7ef38689adf3d2c10016e09fbd0b68bff00733a4514e87c1ae154c1f6ae0fe35ba82f3301b7fb42aab967cdf6b2b524c1c90cf60e014906901342bec4e72f7660324fc305571c2a2fd23ba1f914adfcac8186b0817faca2aa5bc1f396e577841d08a5ca775d0aea640a77de9aa8e00b951747a45cf29edc3a09e32fae9ef5d8affe8046eba353b3332f48c20d8622ed18b6a4910d043ae1c33773436e75c6cba48322a8adcd29bc6a20a374f4159d9706ac133850a70beb434c4cf17a5ebd19665c2d40fda212d42b0d8bf6b15a6c4ce8bbe05f51ecf6689e1986e9a8970b4cda5660062025b01a581c0126c107220a78de642c55527429893dad01c31bef9aa2c1011439f235b7f410f6a84a0be0d3f071364dd5f6c818898cb1ce42e9a1718ac4bc895ec27a247b8c1d037b76c0742c126f45287184e71a8f4b45572f614c84efeee1bddc038d129182d770491b24e087e1f91bf933fac43996d8c5805a613dd451c220b87384dbe615abfb2c697bced58ce9a86fd9ba6a27701e2207addfaf49743280204da36b282ba6156980274d41a6230fcf800876f3db1e6e42ab06260d92b9983c58b2a6a3485483e00d8b6434b5a4faca3722a4deb5604d2c36040efcd19288bb80513e642218405da47d0f880e4813841804012603562ac64df3c45837d0ba7ec1832542d41f39aadcdf9034174ab27762638557e7905ff54e2b8c00b16a0b9c985b60a011b449ea25001a61fbe1d3d45fc2b4cdf4384a19dde61f721c481027ec7c4fa0b3160b25472ff000000000000000000046370df7e93105baf4813110e36252525d96e263ec8cc5e6ccdb6259d0e3e9d19bf20e90bff0b420ca5cbafde1d4f92982ba9602a8760daf1f3e4f02aa860f24b8516afdb6bab9c8289a75d9762554cc1599cbedce213eaa6520a362489793a4d8e762385147cccabcc1d7a1c0d7d14dce5d042ae9cfa971fa2e073149a1d4393a5a943c18d85eab837344ba6808213abae38216fe9a89fe07ee2e5903b5bf62e3dc1f644771072f8962ab89de0734d7d68ed793159cb09d6034b2fdad15e63ed2618fdfbd0153c695a5c134c0a3147c93d875b926782f7cc9d9327ec3a3c30c1486d894b7f48e19b4bb029452c6974dda03196e044226e5fd27a3f4d259890fa7274d89aa36e29c1e74eea41ca97122c3a09deaf42720965c9722709367d3fdec544828b993a079ef2a74f1b2498343169b65efdc8da2338936ca9233815bd48964356314b1ba1c7714a31542246f0bf95d1b5de52aa882e824b1e63baf193d0eb2b82eb387c435b697647223811f598e31fd19603117cf07812f3e3e475cd21b8fb0f1d274f8ed16308feee2387a4ec1e954270516a92c4a810820f731a0dae0f82abedb1cc7ead398e1404275125f87d8dc7a90c04235afb2963ce9fa20404535692e3ac1f9d5afc037fde9e35e2463bebfcc0adc715cb73ecb99d3eb0a963d3f29827bece075672e8e8d3b9072e73f81dd671eca1a4d403fb9f62ce13dc2d6b9479f83c7d2358f2e0816bfbe8771b3ea13beec07414711d4fedc044fdb3b6b0646a963af09af62cb96ebae8b174e0dad63f7a5ca92c45e7c0674844de7f88e9a71c58b74baf606b9b2b8871e0d6e2e670cb21644f100e8cc7514821f737f01944524eb7a71c7edcc059b4a8e6f6b481ffa8537a65dccbc961031f296977d68df6c95f03ebee295da6cba981ef298f34fb274e0ebf34306696fad3c4deca1f87064eaa2d7890c9638b39ee0c5ce6ccd0e1ebc731749c19b8d033ffc97721d9e6cac0e43c16c77defedd623031fab793869699289e4c6c0c6943c342b72626073cee8b6aeea38e8c3c054ea9e9c9e8e2ef460e02dd98414524537a7bfc0068fbaca33ec746b2fb0214786f2c8569b2c5de0eaf2e6c9b1c4b16db9c0e6b7f484f886ca6f0b4c9acc789d43aa18322d702185a97f6bb2ba290b7c5ce95e9b65e351322c7093bd230d39885d810b614937c72b46cb5b81bd16b3a9bc5781f73859a2e546c9be53818f2746bd983c1caf7c0adcfa9696a64cd2da2105c683444f1d34d2831c51602b6f640b968602d323551e68a60d19f3043ecca9c310d5d99346cb096cec71e9ec673581ff1c7b85609b12751613f8a06bfdd364b50b622d814b7b4bdd7a5eddb152029b3be4efcdded17227094c9494bcf63912d8641a52e4d0bee3cd8fc0a69cf08cca5ef51f46e04eb23424d3f00a1e45e0f3e728a6d289c07e943d86ac94afd36608bc84e42972d4fb1ca708810fd7bc12553343cf20b093f3fa6ff47a4b0884ffdf743ae5fc80eb8a7a59cc3b8eb6a301f880b71ca6ce2eeaffaa512ff81c1d776765d1f310e2051ff7e50b493cbb98a10b464d4342e6c8fdd4e782fdde1ad590596b37b860379996ba78a5d4985b3049630ead3c8a2db80b79371a254fceb5169c697a2c92435ae02c78efd6c9d17f103e9e2c78f70c6953a8cc7190c582cdff49eadda15dbe080e4c0b56033360c18620d963ab174b41ef57b03927f3bd9ca4ff1e734329a905c6cc156c55478de539da7bc86d61462bd860b6fbff515670a61efee48fad55f06925f65a14cbb020c1c20c55f09ddc3d456a4e2af86cd1abf42fe9c20c54b059bdd582479bdab11098710a36d35a8648c5362b1f30c3147ceb4f9ada95ca0b3f04334ac10739ec63d0efd2dbea033348c19e48508df62f5775146cca963b7a742c7ba744c15e9a46e6e42031a4f486d259604628b8af5e4ba79f4b2de46680821b4dc13d3bc7d1558813667c8217cd15628a2126695160862738df10a39b86dcdf4de90497a6bb2ab9449c6034d57b4e37f90da54dc18c4d18e57b21b222e7861219a789cb047b317e0e1dc5147c52850956a432e4477868a7df0d25f4c08c4b70abbfee361d4f08f5df5022c312dc7d7488fb95bafbe60da5a24af09342588f27f592d00a66508257c914d4bc364d7af424d894c8ba09b963f2cc4a828fb077498dda49a98d04af3ef991866f8eec15127cdcd53d82cdb1c2831c0fb225441dc15555879c36fcdc6f049bee3ccf2a454cc9638ce0cb7763688bd47d478be08269f41cb784e63854115b7b8b748798bb6b4a9cf26b8fa637aae306ef2fa8c11356136624820bd6eb714ed162c8d31500dc300311fcb75fccb14990900ebba13446192ff819cc80060739c38c43705f6f9ad2a3a3d01f6f08b603fd0cfa1ea5c398a3106cae4f1d8adf8b754c1382d58f982ffb843c557b107c47312415095a1ffb46105c87751d07c9624e936b20f88b94e3ad8fe300c1badec7815ec721fc627f6037e670b53d781cfe931f986ce9ad92c82de51b9dd107ce33ef87dcad7faa61ea60061ff828ad62679a9c57a27403dec18c3d30e6f127cdd13d6378f450ccd3360fa71fc28c3cf0b6933b8e7c73747b7130030f5c7a54c922645f91dc67dc81f7acefd0993d240633ecc0855ccf9c25adc3cc56995107bee394b4b1d355851ce5cca0036f2b3a39838aee757203628871cc600e468978b559df2dddf73490c13fe0f80f501515cc9003d7713c65eae9c3b2f3184055c693d1811971e0bb3d2b228d67fc28724309073328e305450cc000b11b33e0c0e69852634a12227e79dec05ac7fb1a6ad4add2ed0636071e46d210fbca1da50dec84f947d00fb2818d597c2f6392d6c048b290b73fc8c8219a1af8eef8b79a37c52e8f66a481519d5cf9236d0e62796e289512cc40839639476b3fee68396e30e30cfc7f143b9a8c3c29c79a19666024f5d5e3205207590c018e604619b88891e9c65a634c77cf20036b6e1a34baeba487df8c31b01f37847cd3ce10838981309811862ecc00c3169d93e6bf26e60d252235ccf8022f39faa58df956c7bdc0bee65069213a4e1e7aba5066ac7ecf53361778cfa194ae44d97bb4d90293db3f7f90f51f479ea28573bc989d267dc8e156b2c07a1cb5c4ab52bf0815b7726a677848f70abcb6b7e6ba8edc535eadc075f2d4da0fbad93e5641dffc4093c7c14fa402bb7e49345dce1418c9955d5277fe384e9f14f88e1d9bb44b150557439a140a664081b18fd22159129fc079ea3421a5a871f2e3042ef8975f0a510d9591194de052ba97d2958ace60021fd3c6f4bd694a5263dc208306312044465982e10c25cc4802b71963efbe5a688efd8f400b66208133b798bc25d847607310b929ff83724dee0da592c00c2310da43ee798eeb39c8985184fd2576e67cb9e0b801910b8e103c49c00c2230495b3fc4b052cbf50c814b9f0e5f2a7746c96184c08b7be59090bea36f4a10d8e8172564fab032c7a140e06adc7c3d57f207dcfdbea9f774ff87551e61860fd82469bab683fed8e3da0b26880721e7a05f2f39ce0bae2eb548468e79457c177c1cdcc47e4f3d3334ba60cfa3bc1ab96f3ce71427082017fca69cccfb8d229157120401e082b59d4aa97a39b7e0627d98e2648df51de56dc15b4a3efff8f18bc6bc167c547e4ae9f503cd69d3820ded1b3dabe628e70fce82fb4a2ac93b7b14da9f2cf8cf22d67a1d4da3b3fd810062c1fb78fe20b349070b2e42b64e25192e11be82bd9c5294b290f23b775cc14ab4a6fff1fb5ac1bddbe4c6cd9d156c2a73dd8b49dc8368ad8253f5eaf8b5c12644c44c00aae04d2a841c9a5aac07024805df493c9967fb1cf999a8603b2d734ec15b4a13bb26e42049b098821f0d6e21ba2b3be59482a9172db38f3cf47fac0f04400ac6ce3bc4f1e439b23e2d07021805db356d9ea38fcab3a645c18f6faafa8f261b0820146cc4d3241ee5b02e84d00a144c49e42887f0c0836c767d82cbff8165e9304a35280b08c013ace7cbdb88f9a3645b192a98010c543083188c51c6a7a0c82c5d009d6025c74a1529e528965538c167abc47cbd34a138086013eca847213dfe701080269894fb73070fb399e0268f68471d295d0e4c98002e416208c012ec7a90215da784d8966a83002ac15ece2e091d66da135b009460f3a94e90bed36c394e5e6004638c400093e0d346879b9ec70dfd32ae8c0024c1c6af08d9f26a7f8840009160234ed478392144d28f4282c934a96c9d293fec1fc1c741e26592b8bf2e410784200c077cc0012e28830c1aacc019f00f017f52af108023b894f5438ae5901ef1d208ce5a276fa5048db9bf0fbedf490a1500860fd84a39e4affeb6b6f4e905db9a43a954f3f082ad5d750f2c638c31f55df01e079a36dba40b3ecae1a78e75baa38e5c30ed1b2219dbb6266b70c159b88510dcce934ef6166c47cd39bcace9c34faa2d98cc71c7d051d73ca7b316ecc4aca91a9a2ed887b46027f5e430c6eff02a78b3e03287cc151d86081d8468c8826d8fc493073147afd8890537fea15b94ec1bcd745830112b273543fa0a36c7fa1bad7b2febd8345cc19ee565aef87b1596d756f0f541c8123f2c68facf0ace2a357ad86f5f1b7f5c05133ac61433d05005bb295e8e60a7b7a9752af8492675ede6916746a8e07284270b11346e69088d5370a939b8588a6f1e7352766898825bed09b93999a84bc8a0818fb1d5344ac1bae730a6e87b19830629f8fddeb78f8c9999e90fd01805e31ee5204aca2c7f0c698882cbfad4f57149c8aeed42c1849ad0538b1dc7131550f0314fb37ff4654a018015687c82cdedce9b1aeb402f58a0e1097e3f5cfb9f8a549ff41b4a63946162f03328df82363598c1d718687482c9fa28b4472e6a2327d8ead0937550d1b69b0a028d4df0414e1ba1e33d6f283d818626d89bfc912162a86482edeaf0d861c70ed3a22f80810a1c2081301c10c6053040031375ed491437c92fc184741c7894a886e6571ca061092e52f3f965f7a7b1a49914685482bfcf2429f7c7d714685082df0e4a55825bd6033426c1bdc71ce425296f28a5e0052aa0315a100317a8c008004aa02109563f4233a4e04682951ee9ec5972ec5ca132041a90e0d26e945d871a935afc114c8f65d647d1fb729d8ee0f55325cd39881ac1c77c7fa98e634f738f1b4a465724a0c1085e3cb7bc4573241adb19c0608c42008d4570a51e69ae8fedc30ab512682882b3dc610829da27826b0db30d1632c58f7a0ea3031508430c31b04003117cde8a9da1dc3c2f723b1a87e036969ec7bec91de6704370df52962b357ea5595e4054340ac149088b794c2f74749c109c564ea929ea791ccc63105cd0a950a6111a3a2e083ed3955587ec696f2d10ac65fa7bd4dc552e2940f0917b3dc596fec0faa7fc96a9631ed564d340c30f7c08e95eacf2e747fff4810971738a78eab9a3c6f0819b8ec53b078fcc32e5ae40630f4ce5b44cc9e1a1f3327ae04282f87be45144c87179e02fd43f07ab5481061e584939c4d4f83bba1f5981c61d58090997aceba142e8143b7011c98358879f42791849d0a8039763e4eba9a7d7ca381db86076f934accc2bca39707ae911b12a8fa02107bea3a4177375c4051a71602b85def3abf65cd963040d3830399214f3a3b3dfc047d6aa0e16573ca7981bb85037ad9e383a9ea34b048d36b0d191b6f35675ceefdb8003aa081a6c60534a0f558f9151081a6be043fff49d5163bba71c6a60ec638ca5810ff9c972e41c64c8c92a41d04003f71d7de8adebe4641242d038031369effd245be78e4a3a3370e9f34f4bc851206894810b0d5172903f27227a32709d3cfc9ee0711cbb8d63e0aaefd22efdf3030d31707f11c9ba3e870a2cf033c880fd814618f86c1fd77d7a8ddabbe9810618388f13b284cc41d6d6040f34bec0c6f78ebf3f1d739c1e59a0e105462562d0168d9efa4a078451c60b5460013ad0e802976b931b22753f083a7281d71c6bc71fc7b499b2a3e240630bbcd5ede5455bcbd9ad16b8a82f9d9bf2e7bc8fe040230baca5bbc8fb96cbee3d37d0c002ffddf519b463dae8ff0a57dc0ed1c2232d56e07a42355a5eb09b0c4b15f838565bd1e07160eff7b6810615f8d83de1252999027fd92dd4475aa4555d030d2930f173749dec1e561525a18146149868179d1cf14ef2268fe640030a4c7e9c5557dd5278ee9c81c613f8e49ebac3f441ced35771027b41828d64f6b1f3550c349ac05ae81ceb64d8c71c7a1708030d2630395965f1fe3eda8ef3028d25b03b9ab3c7d5fcacada34043097cf411f432789015638707ca302d80801862bce0cb28c3b4e0d04802e3d12bad86da8a791f3828430580a081043652c5d7cc99c390f912430c1c94a1023cd03802377e3972b38d516d3302eba1a318c273f67cc91781b5fa96accf715cb73a11f8b571f588cecf761d43e0a29f4e07a996257e84c07be0fdff1bd563fa08029ba277d22c16f37dd440603c96d0d3fd2ad19c1fb07597f5274325ed4ec3074c6994c70ca5e9051f6a9ac75e7e2e1e04c370800bbe8c09dce10b5e705143caceddb9eba2d9056b211d4535778f27d7051f63a835174cced1ad564278ce61c105b7259993dab3b760ed3ea8d8f9f9879cb505af3147c15a30fe7f79620af338cc2e2df8fbb4f3c8983c0e8dce82c929ada7477f360f4359f01f3d3a5b08dbfc10c682cb3313bff50f21f383c516d2e5c8b51cafe06e2a5a86ce925cdc7305bf97f63cdc9ed0742bb818ddc373f1d528bab18295e8d0e187d329665fabe026071e72de73b5181255301e858eafea3c52c1ae7706b5ac57314d1a157cce1e6f5aae7979879e820f3cc7518a5ae96f7b5a1c7c610a4e23a9599e4eb0f294820f838bd6646fa9a79c147c6c93424d779b46cb310a265ee5f45f3956144ce5a78fd3ce0d05173aee77f97ad6b8495030b5a956d15f73906dfb0413ffaa6d237f1ce7c87fe10936b6c58e18d3a4134c7ac4ea15bd39c1c450eeb6e2ef179be032628e6356ab9aa0fe7e3f7a1c72647c91896f27471d52321c10430c31c420e3085f60a2f4f8dfd973d091c2179760f34ff434e9225f5882ffcbe0ef6f13257c51094e274348bb8e2e2265a4055f5082b5fc3925cdc9241dd9f4c524b80ed6e1e4a02a92e032ddb23f47ea305850055f44821be98e427690a865794830b919835bf2d69ddc3f822b4b393b76ec1dc167e7dcd21cc999fa46b03173e5e8418598a3723082e91cafdd320fbe9163115cb21cea56f49c1b2cab0826e4f3942ff3da78a02682cd651d4c53e44afe8808b6ca4c9387123b04e3b17658aafa3885b40cc1c7cc0829b45ff0a013189041e80f15b4800c3cc01785e0a3f4ce347d1b73bc1382cb2d4fa331453da6ce20b80ea23f66573d8de60b82f5482594c594b60e1308f603ad8afe51fa4110104ce8a01e85d04cf6a1f2076ef7e3e8ee3c46f128e9072eef46f7c0ddc3cb8ffac0c5081a214a5aebb37ce0b234a4742947bed8c37da1872ff2c06aba6ffae8abcbe3e418442cf8020f8c4f5ecc71fcd47ea532686081174060bfb8036b1f47eed891cc33331340267c6107ae7224b1cb336491f0451df878c5e3a92431e5075fd0813defed583b42bffa44a48967458a8b2fe6c0e6ee642d31338b4a565545444444446535f14c85f0851cb8df5649a9b3a5836ff28b38b02f9dbd5fafd7d68703db5171624bc7bf21be810dc1dfa2ed468a6f6ee0a38e7437aa473d5d6de05daa35c7219a9a5a6ce026bb3d5748759da635709da30821ac420e6f3a6ae06f424a79bb59734f4e1a78bd8b9756220799f26860b7f5c3d114ad39e567604a2c640be2d152889b818be25ee31632b88729036771723ce9b5103d0a19383bcba1246d7a9bca18f830c6ebc8d1affb5831f01e591d74c68899cb30b06983f5b4f948f0110c6ccc1bcc3df6cadab9ff029b5cf42bf6876731e4bdc0d98ae618f32fbded029bc646344876aee55c6023c498fb2ced0712df0213b2e438f6e03a95365a60275d43538cf61e6a1698b452d915f3051d110b5c9e1cb24bfe10b1b42b306d3976cc1b722b7099b7aa77a3794bc4abc0ed6f8e57c7538151dd0ea2633947f353e02c789c7c6dc1bd7c29b09ff2d8c7f13da5cf11052e5f64c971fc010536c6e812d29656c71358cb243da9c427f576029f922a62214731e634810916b1ec3cf460021f5f42646aba0436bb4d8eaac7228712b8bde492979db6444c02771e4fb35fb6ad1443025f1ed55f8ebe6b5b4760ecd2f253b53c8e268711d8e8d8d378daab857c119810f5d13cce93d77222705b151d9a495dd487c07648a93df2fa384e0e21b0a1cd0e02bf1727b7c7162070aad3515beeca55fd80cdb8f53aed173ee053a6cb5cb1272fb2bde0437fba1c5fb556649b175cec3513dbac77c124f5fe280d213bae5a17ec7444dbbfd8f5489d0b6e4bfd3f050f51f76370c1bf67b8dae6dc82a98b24390e7a752fb7059f42dc831cfe69d3a3165cecae9354936f3a4d0bbe36777e94762b2f330bae634eaa21455295909105973c32d29e85d94f4c2c98dc9e1c4775f5907358b05b3eb1a7a30f7378bf82ddb5f4d8394ecb61bb829f8c5696bb3678c6b4828b90e37db81556b09edc935be6ad5cd155f015e37d94392daae066bdc404369ee0021b4e287448a89c1251a2755495b1dc31fecf185f060d62e002181c28061b4de072794cc9bdc3e2c79f1b4a6983094c88b9c394a3d42559646163097caa34d92d47da719d1b0b1b4a603c0eadfecb9724f0fb9a7d39aa70cbd2ca0612b824f5415c1f09a1c63e021f52d40e543c9cca5d0f17368cc0e5a012a4d5b42d864711f89bf441274446fa58379408ec7a640e18d82d6c0c81bfcc1ed279316d2f86182978810ac270401864d8c2861058ed0c217348aed5096c04818bc1de36fb6eb69ae80f3680c006fbd318123f9aaae7077c64aebeb776d98d6fc3075cbbbfe6f07d3dc58ae9059f2b86eb94a4bc602f772febffb80b268596ec28847c518f2ef89cbf4df4349248b072c1abe455665fcad131840b6e354b6a4e2e7e16f15bb07b51ee22e56187d9b605631f335c3a900e2b2db5e02a640d8b13a20aa8418b3ffe7966c18ea4e6405c6279c4b42c78f7a8edc3aa634ad3c5824d953ed9c69c64591158f06d9be249dba66ba8c62bf8c8b5b25727c6155c5caf3c29872934456d051bd3936af28929f99bace0377d9021620c39cc8ed558051fef7e5ff9e5fa49d40161100c84e18030c805c2704018c4026138200c5281301c1006d9430d5570ffeed1bd749a1e4bdf504a05379e2ea45e6d8f2b846e2879a2062ad8582a398eff9782e4e886528d53b07193f5c5e8b76717baa13430051f478c1af61ea68ce942458d5230b1a2c38fbc2a7fea6a908289103763a8a45b992432ca50816619458d51701beee9697fde715c51b0d933e9ee583089135c50d408051b8389774e53279a1a0656133540c17dce2c4b8d94ab43a599a8f109bea3cdafc896c5724c0794612e40060370605af01bb0440d4f70e751b49798fab24d8e6627d8ac1e43c813aaf3e300190cc840c143d4e00417fd3ba88f2ddd2823052ff80a941a9b28316a6882fdc8f2c5bff330b4d41a99e0a67537771ce858a881092e95d8e5b0b28698347943894c0a352ec1d46647e5a1e696e072e36d5c4be50da55209c624bec4f5f8410e2d093528c16fdecbdb10bc1b4a93e0cc7bd2e5ae9cf99704b7ea512c63f2b8e9b38d0497ae93fdf8f9c71a9290603aa456ba1191d8315948a8f108de62f0d698e358d555c10c62503ea89105dd18826578941b4a8de053f61cef886e9c4e0b5af0648c81031a3423785d4b265e21b4523d460c68008319a4a06a116cdf98a4103ac49ceda08622588fe021493bf286d21830704b0417f9fad15254886073734a8a915cb266c10183161c106a1c82b3ab0889f2ce285adf50ba32041ff73e56cd607bf79542304962aaa62eeb0f5d23d420043ff93fe559d08e320383198c8183ae16c060063808ce24e63052d2da9e985bc6b7e07d05c178f8e7babd1f44b21e0826c4747bf943ed30ffe3885003107ccc9c18f25c3c75d4831a7f60b3ae3ee438523fdcce0d2517a8c0d8a10217c0a00c437e603bd3fbbabe52ca1c7d43c9ae50a30f5ce794b2cf834d6ec9583ef0b1a3727091ceca7fb9a1944fa8b1076ed56ff2d2e38c1d74500f7c4eb79c53e40e72fbb262428d3cb01fa5497845cd7156aa6ae081fde8317310347743690c18f81db8ce51cfb81ee4dd98dd501a830c156c0d3bf095e6df41eff2febb1b4a64103a5b841a7560436bb4595c4dc990a203d3efa1c70f2bbd624bf6851a73e023f56439da29c50ed25ea821075622ffa7ee3257879e38f071276acbfc730a518503fb17530e25920e704018653420f406763d0e733bbacaf1476c0b35dcc09b5977dc1de4c89bd20da53670b6fd71de1c3347be1a12d46003fb51aaefca49b3811a6be06b243286e4ba8fc1afa1062e87ff41534388532108851a69609258e420f3a97b649e26d4400363c1c3cfe1497d64963f035f1d96a7df38a237793370d12c7328fa52997d978117eb4f97ca9182743419f8c820995b3a66ddd18c813731f53d49193170d92d4b26f14e2fc112066e7fb26bc851eb3dc782815defd58b4ab9adfefc0237eaa17a9e2647fbbdc0571e8fdb253ffac8a30b5c4eae261dc7c92da5b9c0455a8dfd51accc926a0b9c8798235bc22af6aa053e3a0f92c5ec965d22ca0217bcfd424decdba039a10616d8eda053e57852e520735c813b49b97356678ec8991b64180984d1810a8821c61849871a56605dd368d61c2cac51054e3a95e78f37256f4f161994a84105d62b3744e5541ed8f81108c3016140c0013b05be430f11a1366a45bba5c04e0e7b3aac8e7bf3e651a8c2f33e8e5ea1c045bc1cc7d173d41223fd04f623861c9ad27202df99632fb54c7a49cc267096ed4378909edcc3d87e0d480e3598c07db08eb672a5ded0713596c08203062de800d4500213d3a526c6addc50320aa3031100c1ff11438c1a49e02c5dce71e0afa139a6379460f08231aa4a0d245c96a3a6c761991994412e3082310c50e308bc86afdddb471bef9425d430021f471a2c6dbb799ace29029be1e739d64b9dca1f22f0b1a43c144987c09d69cc6331e5c98a8e10f82e8f24a706d38b3e08ac4e9654d9a15aca3610d8fed32c8da75993f91f30595ee22966bdac8cd7f00113725b99e7b8da3da7174c5b471eff5e36b3d0c10b26794509d1b4a76369175c65da8bae90fefc2b37b9e0c633e4586c93e4f471c1ee4607b99537784cf7166c56648ee320affea56a0b3ecc414efcbacfa2762db816f1dcb1b36fbc4ad2824dfe511c17cd6c5bc15930214da268a46e09a92cd8dcde7ce5d1a284d4c582d75ae90e1e794adf010bc634f98bf8792c9eda2bb8881052a3460a0c57f0414fe3dfc6cb6e293204305ac146d48d07fa153058c19e7734a162049fa89655f0b5163d22ab5405dfc1273c57d705462ab80a0faa7932dbfba79600062a18e938ed871bb92c76fc29b834f992fb96746df6300563397eaa55f12805eb81657aba0b91c1d2a460cf2ae45d4ef038d2370a3e3c891b37c71c42494c147c0e2749ec5cd17aa450f0d939479d1f42a06043d3d8d9d4762425d14ff039ac90d7d367d3247982f768d327adde0e3ef14e30b5717a4452cab62c9c60e3ef7fb43f7aba9ddd049fabb375eee86322a526f8f8f32f42b398092e73457f895a4132476182e9b053ea146a5d8289af1ba5c3cefbd4174bb09ede2f845c31727c6725384d8fcb538a581e3d5282d3c81343d7470b7dd924f89a1c684841752a3c24c16ad7dee46de4eb084582efd471d4dbae8f1d4182b51e0901e3112446e5018623981edbbe9cde413dcce50dc06804d7f6913c65fbde473e23d8d8a697a7438f45b062a79d62e6e8d773ad08467cdfc35add93ba35115cddf98687db8281083e72d9c79f3e128c43b01d47973779c2c3b4794330fd71e5383cdc8e3d8e2e04dbd16dce41a67775c91382fdbd98badd3774faf82098982ef6498eccc9122308cea64cfa329b7f90974070a31edd2a254d1e270404df1d9a29d93430fec0f5c616d71c727e8e3330fcc09d6e88f6e4ae5396f7810dbaa9af8310bd223df8c0b7e458d874925053b9a1f4021598327e0660ec814d0f5a39423a891600861e18dd4bbe7123d5aeff3c305ee29179877e34e9c6037b1e7b948387664e46c0b80313390a4f71246b0776d2c358299d11f2ae75e0dfb378468e3ad150d2810d0fa2e668de1cf8f3208867c8fc561901430eec45851c78f889031f7675cedc6ecd963e70604caa52ef428ed637e70dac6ffa1cadeafe4479dcc0c49822bf8f6f44efdd06d6fb6d3f160f36f0d1e7903eda6bd3cb7a0d6cec98eba1b55fe2460d4cecdfe9307d5093b14d031fada52153670f3d93686023c7d1e34535cb693c03f7f6bd9dad3ab2c8998189e641074619f8f81ea656cbeade412a043806186460fabdd57ea2671badc01803bfd1a7c4fc73dcd0316650460c080c66906088810d1edac7993b8af2fc5906c0088381a1f604607ca11bff4f2194a93400c30b5d60528588f8c71d648871e3c289813000630b8c6632b7e82e185a28168091859b0118587801185738a52da8984a749924538fccee26460ca1424e91008615b8c99f357d9c22b3728501605481c438021854e0abbbb752e8f81962ce14d85193be1c1ebf3bf4a5c0757ff42629ef47da61a2c0a4ecd4f17b103ce48f02054e3b0617cbf102e3097cc762dada9d72471fef0426e59f546d6bcf314d13f838d773664c60229ee7e40e5f2d6a57810dcc2600c61298ac4be3c9f3c4df1f0c25302e390e738e7673b23cb5004612b8241d7ae0c9a348605c2d791c5ced7fd53f02971ab2e598584afc14237051153442f4acf60e2f02abf67120a931c729912957008308dce68fe3de0d4dd7be72018c21f055bf51fbd155d20e4a40802104b6434549cb92536fccc10802df7953c6a09b0308f6eb66338f42f903de72b47a62836073b2febe781dd68582e05390c89763cef7ef02c105ed38c72871f5a31820b8dca2924f2aa528da1ff8dce9db41a71492333f9c2e0593a4397d603487ea460f63d09d0ffc5f568a740c1e52b5076e7d637b054b0f5cab699d455ef3c0fff779f01c925908513cf091458f1afdb903d37f9fd3d573fe1cc70e7c0ebf63c7f9af03eb9bdde7913c7df0e9c0a86436bb3c3ae9e373e0c49374981f7dafe572e02ba59a1c72448ec38f3870621bb2bf0e073e5ea49f776d0e62dec04b7a6787ccd107ede106c623fef9e6c4f8ead1066e837fdc7f9dee410e36b0dab591a5f6b57eaf818f228668c72e313f450d5cdeff4a8be419bb34309a21ee45c793975a34f0b14d7d4ebd1bb2da33f0317e0e53ca93e868cdc08ee61c6f927755a96560d3bf3b8a7b1fe5a564e092e78fc394628af6730c6cc7f9aa3785ea78a7189812fd28a5eb5092ca30b061932fa45fca1c0703bf962b72c5feca397e810f435f8dd8e805ce2d74554551a910bbc07810d10fbf24e87ec9056ea3c7ff2fb7052ecdfe73e8cffbb86981edfd0fa3721c7143cb029fa3ce919249d0945258e0c6d3b348ce61dc4a5d8197bc132f657a2c9dacc0a7eb3389163c658cb20a9cfbd4644f1c0f36492a30492ce57037e5503153e03c543bf82b052ee767d6bc5d6d46a14ee39b7de981029bf7d2fd47fe098c5fc7da69bdbe7177021fb3e3b8ae52a5b2de045e3c8e2ba60d13b8c81d47a631e97f97c0849468e9a343097cdeec99636692c05afe4c2d4bc1022081bf0c2ad1999b3e2c588023f0932d2a7987943c65b1004620dc8394325d5b04eec7f6a2f344e03dff9b7bf687971d021773a81963fd441285c0977560f69a726d14042ed86fb0dca14f0b044ec326c43a5847447fc0a7501fd9ea967a9402f880c9e157112cff52b4177c54fcde2cbb9558f282b12a158dff9382bbe03a3d481f724e175c84851c62f472c147bd16a4cc92e7c0c3053b693de4f1289aa2760b7eda3f4e53d59662660bb64ce266fae530f5aa051b8377b449bf532c8b166cbe7854c1727de669165c5aab0e21757a782159f09eaf34a94e98552816fcc70bda99c3942d42080bf66a6f638a7ff539045fc16b65ed38aafa784582aee0d65eaa2fc5cc20116c0577e7e679b27e381182ace0738e589fb4b30ace3bb22cf1fa62c8bd2af8380e3ab458c8d2da53c1c6d7ed28799cb6428e0a26e8e5ac11cddac4e3147c78971b661da6e03a94587b9183fc38a5603c6809f1f385144cc7ee5929a68c821d9d249973f471f3150593c1ef2e5f4377e886820be12d28d8a8e3e9715ca123aa9f60efd2443ada9c424e7a828f93aa7dfed8092643a8cbfc5873e59013ec48e4283fcc951fc34d3052bb316b7bc48f424d70ea15ed73f4d498bd4c70a19364cb90539cec30c1fb54bc1cc790af357609c65677bfcf35278d9d25b8f01c64d6e822b5da5582fdb8626ecd5795923a4a20c9d6fc833cdd24f8f20939a6525f4fd149828f4bc783cafeb50f7291e034a34e6615fd387320c1a9a7a81c2b7ae0d779041321fa974c2bed3d1cc1edd54799b9a3117c18a35d247fae440e46309d2f739c73d89b3b16c149e7ec211545b07ea51da40d21789b08f6453b47b446043b21636fc7610e414cde95bf1a43b039cc25a93efa95650ac1dd74a839b014bcf642087e5c5af36e0e4ba73208a62af3e5384ddb478a20f82a3d4d679625424a20b8d431ab532ae5ff0b08fe23654d195375d2fd0367a925a634bdb935ea072edde71c7e4c1e249a7d606af523a7d8b1a2997c603c468f791bfd72977be0ad5483af957a60bc34a57a550fc4cf03a379bd37b35cdd82786037686ebbb2123bf10e6ca9744d8bc59446b403d39d4ea5d5ab03b7d1227fb2774d0f3a702153eaea184952720e8c9dafea5dcce4c0c4f61c9264e3c0767c7a2167eae54038f01a29c450163569546f6072dc1d7f7db4e4c70d4cddd4469deec5b40deca5bbe74817a3e5880d5cd250125912633689ad81e9de6829efb857871a98ae9c69d35d2bba69e045356ddc5c6a2e7934309ed473fc62a926e9676075744434a47c361d6660d3b34d3ba79a98ee3270da1173bd84bee864602a99a98694bdd43206265245aa25a5889d18984ee983848e52c894090397463d59927c75e90206a6f256ddf8fb052e5864bdc0f48876debca1834c17f88f7cc3d3947b642617b8c91042e8cac99fe41698e81bcc2ed846fbd002d757517c5d5a43c52cb09bbf22425a2b4288055eaa4d7f2a7f32dbaec0447e0f6c93b9477959a1f0345215b8f7ce8eb4d73dde890a7ce09e1b9da39a021bd5fdbd77d19e839414d88f3f9a8958a58f211505dec30f69c173a0c078e86d133ffcbdfb3c8173d3880ef59f983e4e60d36a8acc21a7095c72ebe83d5aa3ea6702978246be91aef0f597c0df8478e8214bd4f595c06f57a53c9aa24cfc24302d314858cc0bd97b24703988695b9d276bce7104aec3a2aa648dc0c6cd0f215dc74cd751043eeeea38979d25d31081d35497d26fc463b487c087648b88f614ff324260f2583cd7ca418020b09d3fa19d3bf4c6420020b07124e7fb4731067d09f0033e969cc27a34be472e017cc05ffadb47befa385e7bc17b65a7fc0e7e1ea3bc606c6248a943e90d95ee82b7d01a4143db063b75c15ddcd0fdd9c2db82b9e0538b550e3dd2f788b8603fece89edd5a72fcdd828bd289a57d3992fcd982f1d8a343a7091ee5d58291fc122fed3ee575440b269b95e66e8d939da259f09a35a26f8fc6c88a64c17adf7ed6e8fff14a28165cf69f87155cdced030b3e3755c2b2e7159cb8557a7b4a65d371051772581dc7f4b9fe7f2bd8ea1c996bbd5e2e9f15dc7ff6ab607f7b93e9864696bc2ad8f48fc183ec11557b2ab81789d5573974aa382ad8aff6f455f7f13dc729d8abf330c433514d394cc127778f3d664bfb93a314dc7bea4bd2f1a4602565f6c6318bc1a347c196048f1f5958a44b8b82cffc496269219fd5a16023e78cca29d8861a14ec7887e3e1e96651f309d6a3c7d6287a828d1e639b4b0ebf9ce904939fedbe597a62c47082bf7bb3fcbfb516b309be3645f75234c1771cf94359a499b499e0d24b3afa1f13ac7d4cf9f1a997e0ae376e4f260f54534bb0e92a59094e738e7c2292e5b19460a723dbb68ec81b9d049363092d0ba224f8d441524b1f16093687b667453cd3fb20c1458f8fe0ef265e6cb7ac12cd116ccab86649ccf76a045b2ffa31248b1dd48ce03d43c899838e39de22b8eacd91df9dda56041f58584445bfd02c117ca56c77f51ecc24426c208255bfef899acccce2c5c621b871df4d6e1d593f87f5c08621b8d0d93bbeffb2c997d2818d42709df3a5f871b6ad98b1fb810d42b0ef597573070f3ca47b105cdc9073d0992fb7871a41f45e1dc3235d2f105c084931dbaed546bf00c18dc45cd9b1849c5a2a7fe0e39452e8bedacf76ae0d3ff0b9a232bc36c7f187ba0fec6877248f434a2b666df08153f7b0e3eb45dba54f07f6d0978e6f0e82e7fcea81ff8f2faae7bcafeef50636f2c08418bfcd73b87125ef36f0a0bbdea7a9abdedb8007d8b803636ad143b6903506a9edc09b4e760d76d571c89a3a309e13343c4dde182ba503d7593a7bb493755142a8d2c61cf89c935d78669ed871b41c98f81d33ff85b60b4fb9a1348629a305ef486cc4a1da061cf81c071e87ee59dec0c7ffb03daeccda7003173aaf3ceb6aa30d4cca5779a9f7d2fd48850736d88036d68036d4e0eec609c99ca543bba1fe8789010770f01450ba4dd848830d34d41958b18eb610f4e37de430035b27adde967b228bc446195837efb0fe754d447b316c90810f724ffa527f6c126c8c81f716354fbe1127d81003933fa5a47d1fe4f829250c7cc8902da92347fb1f30701b747bfa43626e56bb041b5f60a3e4e68e1f6f0ef3dc0bfc4f4b7ea9575536bac064ae9cdd827ab4de41aa6c70818d1e564a77e9a38d1d5265630b6c59aa7674316d6841c961be59e042a744defdcb96dec102d7e579ec2d5dda7ecf15b80a6e2a5a1a4b35e956301b55e082c468952b6d06cf49950d2a70dee953d33e07c9828d2970d6ebf1e307f95a1f471e6c4881b1507ef93e654e694f36d8880263693446a7e4aa95bb63030a7ce5cb6d8b8aa8b4adc5e2b1481c1087c30151200c06ba331fd3140800182c268d8502411427a2b03e14800351221c3a242620201a12141a0e0e140e8502815028140c04c1c0201810080683a1a08bac52c60f693771eb0f7c761f762dd2ba4e513bbb8529e25ae5eecb45fed7f3854cf14f117b026c4be28ca599a5dc1dc0c0013ad5d11cdb6701a58d773b5c5c9ea737e85837754f4c9cc607e8b00e73ef2ff53ccfd5b6f2190dfbad99da6277613d41820a29bd227d2f8e7a9fd7f5ac4c4b6fe9a519f9475677a107eea48a018d6968e3615f8f1279d529bab95c24a712b61bc39382ca81e23d4fe4995293df6f1af514e9ef453933c61350c08535841b479fea59538be9f88dfe42cd856bac8e943f75f5a18a35759d22f3caabc5eaa0e5889ed0d59cfede5ea2f33a97ddd22dd94895d89bccf4795744747ceeeb6c0e3d8be8f82cc56a6303a93c429a625e18f6944e6d8c9c961b8d61d38a6097bc392aff695d315f329f4e1673f4e8cff4066fe8b9cec668892d99aad6fb99f68b482404aaed9b7c9c6c58c9b0c302f62418d46044c7f34b7b64715279bd207f62f4947296f1c05cbb5a82117ebf7d0af7bd4e4775ab7373c8c77d4e7775d57c66b3b29c17adb5a7ec1dba871cf69c05dfca0d03656f2a350dfefbbe29207c3d5b4ac48fd4b768b4ce45eb467ec8c8f97b7de4f36c3c8883887c7b55ed147b9a4c940d27a82a3f587dcea736cc726eae8521e7fffc1cdd61b108ac6b31bea17de473756bd8ee3d0dc999ee69fd13d66a4321625ded250da36fbf3916c2dfc1851ff0bdcff2b16633d31990e56cb2a9343906c394da1bed23d2a60be2d0aa3b7db21338fc833eeb5b7c3de62136cdd2fb62e9fbf08353abdddfc19ddfa019bd9518cc63e6c3ecafcc895dc6e1efe955da6b9d209886eaa99ce73e6c3799ed7df86c347e78d6dd0313dc8c04b579d96179124ff98043b0a7c719b9580937ddb1fab0bcf097cdc836609996c7a40d2a454f3b81a95b24c602b2eacd72f41c38b1bac783799cb66a4d4d178904276a1154d81cdab24ec495c4d88fa1d89e018e89678946ab7e802514cee592a7d1c47c1840f8a223dadf85a1a5a65d511921bc10aa7b5342c4e9353c15f621013f21233cbcbfcd95931f2ef531855eeaed730965257c52b380d3e508df63daf70dde5e7e89b80ef1a857c8a9170e62b8feaaa3309e43bd6fc075377c0bb2fc40dcc3f1a8fcef7fa761e76098300c6a2c4a6bced9a087d0ee931d3791eb89edad1cff5f5a84de0eec40e78ed02412e6dd2cc1111aa84be12f80346e2414d264542e117da0400fe81c090157c30bf9b06674e97b619d6205143cc30fcbab63f0775f18ec8eb7a71508b313e352506dd041bf3de7de8bdbe8b2bbe9076589b021e3dadfd1955a2c2c84875a6173227724d2515e36183e61b793499a70e46044e4c29e76248166d80603e9c48ad0d5027f1135a128685351a2550d1670051400d24ec54b00dcf22e7d86fc904011a4fd2c0a20d41dca1c129edbc3948878bba4b95834d83d5ebb2e08afee5913f69ed843b1e568b4e12891241eca75e2538d8413021705383a13bd6bdb265a8d5b80b0c90dee0e7045722b08ae45b7b4c8edf2a0e914c3f9b434bad1f5a2e047c06f0a7608aab15e73a925abb7d70e36ecf8cc0af9f67a43b7163d7ff0d6cfce8318c61a0896df32dcac802808ff16711600c936ac483070fc0f2ba4cc241694520081a4b81102a0d02b301b3a04522ce02708f9e8cc4732a00f58db0dd94092fe0b49a20d443b860f9afedeba6cdbe4036bf296fa20990c509777a830b34b25ef19fb6f045ab4b5a482027d953fd7dacea712d40ce35d531ad051abf55504607a37672b0500bb2fd91c93d32d7b635538dc0e7f14765583c467463b937992cf1a9def480dbbe6b4a3815ea8398c9c10e42bbb34103db7748cc554a8ef470ad2be2631a73b345f2e7ae651c8ed519da1a2546edc3f130a57fca122b037e50a6442805a3bd7d6086ca64197ced77140e90076504cebaea691b06a960d0d30251329f5a226eb850500a27c5c2580652e6619de2d4093ea3fd4f9e8e27147244503a14131a27224440589fe40fb588c8cd0a05421070afcca09aa2e901cd139cb4bd06633e045d6956957d79d9233ba1201ef8a368e4d2c5966f3c8d5901a1a04d1caf751189aee788709a732c7648c9e50725fbff751e60dad3b752548b0d33bff5f33520c151bc11b8d5804448c768aab198c1fcf68c5f6743d05776433d23418edb2c56877d3902a4e530c56401dddc8837fe9f130b0157d92a1dfaade9bbfd29ba2b036455e78db6fcb45a41abea30f10f323b5241e75b0f34e6ff68b52624eedde8dd5be4fe18ca28e2944eb38c1c4ffe07d5e29c9bf018e8f22eebc7c5fb6374f85770c846a4d3c0f1616b0fd1decb28f0941ee9212be3d83d499c6106952ed67c8185b42558c1fcacb98fd7bd6d5986399dba68dedac2d4a71ecb70c3e8752b7ee14f71b7832766f86bdd42d7a7fbe6efa5444faf4042c9361ef512d8126924bf9322171b484ded19e5274cdda5807a7aae0fc51d364eb529711368734bd947558ec9418ea579be4184895d030936144fe93697e774b777ac81a701f75e6ba471777d31bff7e1b84f228784d3a9dce208b022f4f329359397ac93203a16b69376b1d988d11ce5091aeb66ada142141234fd93661b5a2178f6646dddde07a46af10649844b097e5865cd5dab2fc680b5df777fb486848b38b2670e242daf32420e91f6c1a6388159e4952a2dcc41f46a19c950e281124fb3952df1a4add9e09af345001a00b9c31c1725ff1f844964100d5c292e2f43d1966263276b9d20b0bcb15949739b4170b7a55aad1cefd38aad681f8bd50402247fcc88ad3ab52440872c236b87140ea3857e28be36dc85b9302168d219b4f45321aab5aeab7955b9fa812511e9925a74f291586a8d25ae0b44cd7765ec1e87848a06377b02f0116392f326604e8a95cba36391552c1658d02d4d9874da46e6093c71a0fc3a3f4d4098fbe167ead54b576253b08845d2483f0a824eac4a8a02a880249ab082708b51dc7927a0de308ad21500c355a12980f6c9c062e1c508320ab7038d5ff7a19619c61ed9946942c6b42419533682462b2f3decd3796039c960728c85aae134e65af3d61ed10839a4fe822366266b105d4a085adcac859ed144b8be8cb86b1ba230f34b0fcf7dd4a8c8391a7f5776891fcb2e2486f0fdc6bef6b48462aef285678700ad4598c9883cd7aa9c5ad8552750a39f39f502917b169b42430a5ace7431b952c9e410d941eaece4a17ee213848b9355ad57afe593abc9c4fea348ac2d10ea7452009a5343a13c184c6dc102f1ea8511dc4125a089066937b4d6cef512da9d512f417fd38cf422675110c519c04dd2d6adf3080cb87e3989f6ca5ce9ba80116064a404bbdc3b68007d2ab1c2d9f7ff25cf3da98bf4cdee10cf02ebba3de4482509bda1154c601a1fd1ed79da392d1c93bd0af2749dd0eab8ded4d7005dc739c4e344e17b2cbda28094d1d5f26963472d032a2d9c9a646bb03952105b70e133dbd996b5d48d3ba79443c87cc5321a3480c92a49a7103160b690a50383c5124f8aaa8306b7cca237446fe3d7fafc559bc611572b1c38d5c0b4d0b6874693610e8519129f9bec37afdd856cf7872cd194ff3c345062319c22012e637d636454fb58f2f04f63585d4990884a559808e2c0f5327e4962130343b0c2b7b7588af0c16a9a057830a350aa19605d52a10bfc5f8fd12c98cee5006f041588caf1e8acaa74f924fcd2fe85bafbf1cd2d912c4c0bffabdfbf0ffa004c8093803a0ccdf7e0058fe8ba6a96a36c9d2029f7050cdc54ce84fe8a90ca3fdbdecbd375eafd4639cfb59ffb9beef6334805e1a4800fe15208284a75f29284ffa60a872d69a3e9cc0c148b996588899c58a102498c5ee8f3ab1244ea954acf69fac11560d4deddf871b029641e65be06250b95c724740d090642f332b866295b4f530b34c9b9f210295cc63b76445246e6c2232b0494e86eacc71c7ba78880431320c706c799915c3672154c3bb8eb665e03271f942f669f798d126d70397303ab331d3348afb4ef945add708b5648af7057a34e79e9048dd9d7646c31888717b69c1c06120cdc5c2d893de72735811d06470bb213d45b471600b7c28f0deeb4d1c68fc0f6bfc7c84de4a847269a41a4108081b4f86e3bcf01f2c90a196cf9d097c4d256b120aab11252f5bb84291685c9a1882f5eb30cabbd39c052790ea557b9ece5a21a977d1754d9e2a75ca58a88caf638dbe44cd635694b1212bc845c8d4bd0a13b59812a1e2446dd31fd498a9c82a7aa40cd59d0b37fe93e30e48c177e0eecd984d57f24e8a6825000ec43a744f25a0dbf4c99d6cc28ec58f502cea64b45e1815699f012e48b6022326ee5e59a178a65c0f6fb7349f022f0267d64e4565189e701bf369328efa001de136981a9c7a8c9adc2a6b5a24f03955364c732ec8d4f96de735c91ae66e1d42d09bc69d994bc84fc84f3ab7a24a04af28c31b51ff0c245bbb693a552a404b504ba025b865a885b05d80f606aa490f892f371fc9ce5ef7aae04c42c531cc85607065ee93e1b6e04fbbe91af5e353f4137c71b6824c3e5d5bc4aaf2c42679a28c0a1127c49775268de8d06073f3462898606f53dd46bdda814ce06dff56d209d9babebbfa682902103ec403b7b3a67eda646593954db636b6c566a6f6b6d99b35193d3a7e7bd414578a0f9ebf6380ffc6c75134265d07d9eddf9f0715012ded40ef389323e21ba89409c5054188d963d9274eed6aa843aa89ab93c70b0fb5c1aafbcb9acdffd5c00624c0636449084677d14e9a4f9fe077ac608e377bdcd09ee77fb4695fef5f262f0f5a739d8b1186505968df2a709ac8b6fe6f9648ebb912d3148dce2df166fcbcff5fb8906b6e55e76c16440fa2dc46ba4b07dcbdf053671181b14b2867730ded89352f6762d2131897373e5c1d2d7bd17311540319179def5269eff093968da077ae2b3ed8ca8caae1e7cae7a7f2deaa2b4e71e61b6414d3a69fab1318c0e66e87b2f12a57ba9218f72be4682939e883f6eba3c084b8927078b24775ec1c439e8003c8f2f345592a2112d355234281e3f4f1102311f0f72a88dbfc3cfdec5049b074607b95bcf1567d1bb1d6d366dcc96ab88e4319e1cefcc0d01f2b4e3437a1c18a62b17e8417ef1750d1327d132a97f2f4906a535b9024e0cfa1ca426357ba51c2fe7e2b98a37f44ccd907720877eef03ae6d17464e110991647f5bb9a6fec32f3bb62625b6bf4055ffe483885ec0f27fdecc1c423b2c98104a42020be21e269c80b01bc1a42e7fe51cd9155ec1990923da1083112d481a5c15083853c152603bbca66fd55e490038d8431f95b27d32913c2b14b2b97091d4e121a224d4056954a8b4fd7ce060786c19d864bc5374de2b0d95518b3b636353b3e7a81c91efa6b3ab0ec149d7f63805ceae2aad12b7da114b59736fca562438d149c648548d7f152625388ee3231a8c2ba1e607efcf044f41813d5c35238ac945594250fed10506be73716612c949c3961355029f1925adf7b612e55e41f091b1d148560c96896e67adaa1a63abf2ea2ac871a4213b23680ed1242990214562a717b9a0db90af49430775dd16bf014d87e72d2164933db038a8e5fae4c038cb34e2bd2896624a1d5d14a93fb4b8584764579f9a855d8c619904aab0857e3b01d906eb6e4a3a1d9c4c384e162cb4eedc9af57205978ce37df4ae5ae90ab408c2c4b87dff06e99e1711baecc5cb3076237b71e4adcd93e7e59100328b45e873c3a8e6f55728f6d1d22e3c87837dcf5c0c7516361ad67492b9ca8a1a08a4e2e810755a849ffbdf9d46dda6c50ae75635490e1167b043c323ece0a7d8caa7fc0903178ef9eb52bb89bee3db2042d1f62807131cdc9841f78280d50f542b382378ba84fd4b9f5cc3891c6d64aa86dc0c953d65402a32858facb6645f2fb6a7ebfbed22063544059636fa1bf80896031a21a7f81598c22964620823af91f0b090b7312a0555f96441199481bdc5847c30d57991a8e12230923c0c89b9b0e7b1ed11fedfc66e435a98e921c4381de0dd271e98e6413feb35ad233651db414678078d3f895ef03bc76a8e9955a588cc3b0596befeaf8d07620f9335c122477eda59962649a91354d21069a1b657bdce1a05587550d0bcea2bda8b4c3a3460b0daa9b92793800606031cdb544a267292f1f2143a5b47f2039febd2f004b36a08c382f438c14f4891d475c768174785d0402c9380e2d4a25708aa57c0f859a040e6a56f8007daacada936749dda53ca450157d142d6934763b6d98a48375820cbd0ddabc250ac69923a8c9c32de27a2fc292db36a5fd46f0bcc3d5e81fbd1214b864a4e0625de6ea405f8c83e49060575cbbb98c71430691cd0317a6682a1dcab873bdb8c60dadfc3393b0702365b6f62ad2c68081870974b858d42c4a70d933682e154c02110253837f7ed03c6ecdb0f98ef169aa09cbb0fde0a6622013bbce2498ec9f57641406a16322c49a6e3488d42c6aa3380d44482353d1833ccc271ad9c5001c64cb186f4689fc49b648b63ba67c834811081088109827a7a3dcd6a963c3fdfa11f30c459ec1a368c0f022373af45e496a279d20e2708b2988ec00cd3feeaa7015376c553193e329a329beab58c5391797066842eb1cf7c66175c94840a22210bb04fe043d40bdb0cf98ac77428bd8ee27c1940ce19d0e95c7804bfdcc66dd845408cca814390920d50cc832aae55947429feda4863a740343275d70ff280a5b14fe2276eb0027763441275266fceac95c0a8d50204a992690fa476a817de7042f07a559465ce92370944fd4af0119f1f19c4facd912b97c04dc282f3163b66cb872cadcfb04b4d074a9268294e7f251911e8a52fec35dc6c214eeb28645b01a917965eb92ea72378c11570fc94b17d1c6cbf2f73a3a9343d96760cc3e6b1a51250512d84f6705a38366c852b7d745c3dc8d0f7724997d2c91b40a0103d6509501ad6d01527087dab45ddf12090e9db0b0e8848e9396601947a40bbf8422b2280a5babf82922655129eeb7fc370f432400e801a9e8f2bc172549b9423dee89cfa8610f4d230888a122a91b3ae9d0ac1994e761358ec4ff8e0dcde94c36ec9acf3328e580435c58c1bdd2e1021dc771a86ddabff4447c30f7e5b9c11f129f2a5b767302c4b50ede857929d40a6f2441ca29e37205b19293660411e6e6b6867e9221792fcafad3cc23a5e50c66f177e66e5f69d8dcf2cd006ba2b4b670366b9c70eb6372e3ad8e255fb017d18ce5a8bed9feaf199318daa919a41fcfbdd94350b29ecade1ec2d9b28158f5068bb513b692c0daf74a2c40d4f8ed8d913ec4e8e69723718ca38fb624851a9c516ab8bf26916f54efa9bb55b8dc77842985fa18f7a8c9b9ec1e92f1963a8e2bcc67cfa2fadc6b874d519981714c42383e87b7cb806c7cd8c1a94ac9a21d327822caabf8c3e281160e14b9e71e4cb82af363fda44241d806d7437a3235f6c6e5f8b4042ce9a7b34b7e4f344dbadaec390d9ffe5af9a9ca96709ac331c1a326ad5af87a12af109f4c73b278e99bcc4a823808fadbd8e0a67836f6fb02430327fd5ea3446e70812044aaae5546ffcf18fdf76067304016ef91f7dd871a1a08d2fed01cdae33b282149dc73ee21d34eeda0ade565985dc774ca80df218fb9c323dceaf4c2fb248e1973d06b115ba80b181465eedde309e8aae127b7820bfa082ac6fdf13de1bd44bf05e5a6a5f4a0772a781b375282f4612724f498795d7aa8dea15eedbe4b420f95f4018feee98aae3d3c7b07cde0fb0da1608511edf4ebc8aaf337ea5f9b4b1be6178814e3d471ec253b416bf5c71c155c1b391b26d4d8df35fea25bb7f300e926b1bdf1238e0a976faa3dc4234af696ac104e6980026220171a72994c05ed54bf1a38cf5d6befda0b9d0d750499877ec99ed607a52f89dcda1938a7da65eb506a2b31e5fe3adaa7c247ce11ac93c46fdaf464fc6a8e03db77594bf609fdd3266420da26402a00f1d89a42495c03c0592f1b5d1d61cdc76910287abf9e1f22d0db65adb5a922dab45972aa763df2b50907f39b94194021c9c0deb811bf99f91e48a0aeb9bc424dc22dc4ed1855d24931a936b04d8006554fa9971e957e1edddc8f90708e4684813756aaefa33575150db8761c2a2d9e76192f853eed6951afd4f11b9db4183fb7f402300926a3a6d6e8466496150805b3ccb7d6a9c0e908daa0bd9b0c0043382f8248e694a19461b8cbf9d59a773e193e8d8f32e470820ede8c5ae5b32e604d2bdd294e6d62f6f374740ee7e31abdc508255a46453f6358a90afe9a1221eef95d0c6c15d612837eea073748919fa67c271a04bd921306b93744cdfe2dfde40912e20a995ec1da3581d28085e6f4c7c3a9943741177812fca5ac282c3f624e481436d7950f5f86e709d6633c01c65f55f422ac533f179ba7bcbde3eeed755a7f9f9c97502d288f0591d57eadda9954434379a9138836e15bdae9f2df166b600521300209fa207501e38047763572d1deb63522ebf7eb98e2fb99050d0ff40a17428f77886481f2d32922e6c69023180ed1c173780155dceeaf14ce84f9001a2403ae8150c084ffa01557cbe9e3635834e08280001fd01bb042ece2114c7b8df6a9399f568a15de84ad603382a90c8cdf3bd1c292920116b1b8581428c4a8ed4b8b759b88f5c1a5e00904421ae8f7580323d03a760a70f5671198cebe093a12560e57e36e0315515cc3ad4db450fb2b90a13ea5c3eb8ec4f2f49d881f21ff7348b88460857483550813ece04aafeb2d04d930293c08ac2eb05753112a209832b6f7259bbc2eb7cc53097eee0a6b825ae3a1f8480f1d24055e8125a887a5202a77cc8dfc73181a6c82ae4024c007deb050284af037e2f9023eea874c0a2b20b548dd88d803f82ea83e8a10b7648208fc795ef066ec0b02405e306fe2aac418aa6f091885a7392a010776081d20879ea00440088426fe206102bc4a10e500fb9580115f4c0fe33ff044c1ce0462081adc04ae7004ccea14dd57e2c4bf016f8422f04fd241056fc292501583510e4f7a8f1d7d5fc409b9028e8823e426b67f76024f8bfc7f21980fd201384c0e7b824890087c012ef52bb8b6aa5cc4334b70da1a040d9306ef4169880c061dfe9aa0ee4d1f0e80c8e64fe5f157385eb7c82f72a57f2ac15452f463831c0204d7004ee0f412be070030768523613ec0375c7a545f85a3e20aab037304ebbd1b5b2d4c88508f0cb9e98fa4d016eba2cc82f840365889f1c2b9e00e42042e78834c52b14012d8075366a9c049b006cae6d21c5d5620c68b224b4d479423fdda86203db8146866f60049759ce9c0bc153c7d2e33e4a4fa688cbc4e286bc68eaf57b0d567896af7438c1b8aded1849a348e479c1689507c341cfe2511ca051a237b91279dec54c67dae6347ef1d679818cb39118060bc98d541826eb2a7e48aac198f09d3e2936fde877a9b15efe1da2e41748eb2b2684ae8579ced6395a899f05c3cc7ab048f103c6bc52747feb00d06e43a99a03f8bd47a3d7d3a5a9f610979429ff4715a9f5bd52cb8118a731301ba2ad4662a91dd485beecbbaeb9d44d29beb1c497837447a7d981032d6326ac9dd6cdc4450b31757f7b878b03ed2273464032bbf5e425dc5e6f8ca9f731f5bafee3ebf31dcc1ad4ae867a4b7eafbc39eb72f6638fdf9c3516dca752f42706d21076f75e561ed79e8f83cd9217a8bd36514b6e3f34bb35f9926ca2106c59092cdbdab7dd65e43be26c14984edb8501045df750f700902b872ae4f46949f15aab521d1d861e8d185912ed1ca720c84779d8c521fdee6c3de7c48bdf938907b6efb643d12141640e8c147370aa1171fada71f377e6b10e5e977ecd1dc9d3bb6d3a9cfa0744497de57ca5b043ab8da683634e1142cf5b6fed2e9c4066e277e129824181509532e1ed12ba48a51580d59db4107ca4f4cb2eea965f9ee38ffa3a8c6c039b0727feeb97c05d3618eab14b73ecba0f25053b7148483a880405912c0366af146fe2e642c2d8fac883d2570890c2213912b119a682188955778690e838820668898e87d89ea27314e8e1a770a508cea39f347c6abd5a2429685be5e0088d1605a8811d43ae663568011081f27f78dade4f31a4990292416ea18c83ee5276f58f243efc3dbafb33246ac316cbb3a6c0736e8098fed1ed4143d84cf192cf9e35d0c46417cc6713e998e176208777aa4814d6678209a1193e92f7b9683b5141f1b8462c2b1a3240880540ba94e4f845e0c601e3559371b370b1c382613171e3d6ff9e90b58c63e0bd98d21c8b493a9347c8446e9b588d849239f5b3116aa2054932ca153ef8bd07ef19e610c12ce8e4af538aee9dfa7fcfc5b527fc6fc199949a35f5ff818eb70b0bfda904eebbafc963ce0dc461f0392cd68e908ea1248861929c36b55e5cd7ddf08ae6975c132d15149deb13c95d5f2362b3bc6b3e4d89e132799bf7b5e588c6b45e64f2daf01d3e08bee2c72b54635ff122bfce32f2ee82b7d03e449a909f97c953b9eaf5ede9cf1cf7c811e010ff1f3a8b659c2ff47b8e14a1da72710fc6b9fee2ac918a88ed2760a254963f5f24881552f0ff4a93cef25ca312ee50db3b06d9e151e2887ab7f2adad5a4e0d24a2dcb9e7ed32ed8e52d361b0b3730151225deb29a049951171828a2880643684ceb96daf1d9553d1c286109c907b9d1b0bb9b9754a29f1495949cb41239b53018ecc168c7b1e2cf0db1b1b13e8fe6658a65d7dad03d52112bec9b0280ad7e624b9f6339e88599da5240d84bd0a74cdde824f74c8a8d8111a5f6a69b0699949016e88bc1ec2e5fa753ff3c44d7da185071c0e3e1ddb02cc410bb5952129fc390d844d9a631787a22bdd2f96d4858feae911e213a0241efa29070020d6f48813a74b671f6f16d17bb255a1d9ad0da7b539bedb28182d741d1e00eb03620c23d8a97f202e81941cd394c397c295eb4873caa16080ff160d3904e1a301a8bbbd6004c599bbc88b24ec33e24487b2493294196ba7c30a52d2590df5560a590d61d49dde8bd6d46daabcc9df6349cee79a0586b01cf6e124628dc570081d03dfa8ba543081d7fe8422208d56840c1504401caa2ecbf2552880e65158771ee3e632573526870a597c1c665865c11755cb61c08901f4b23383e42624152bd171e7ff41ed7fc7686dadf7f3e5581cc6343e939e409c9eec06b64229c9f566750ea0e84d5bc43273439c71b60f519585645ff2956d548c797388b4fce850d80eccb5872674a41d14b73b70d5304fffdf1d87e51906baf9c2099f09542bd9e7813af7f1d179f9ee78acf27437656814e9888ac7121f945245e0e01b32188364a2c4474649888b7f17424fda91410543c0830a0f7f8717b6f9d05ce493df29d96b2a0df4cd4fb078e8fe5144ee53796e23e67b61b4ad91c432e17347f30abd7b18ef2b82aff8d6e83d93ddffbddc5db210f4cad1a529bd1b58e9c2e942daac23fb0c9c543f4447d40ec939b2bcf6c6d81be864912a48a5adf7aab529a4bece41b419becc040bdecb6afbc6d9b49973ba9a74b17c76b018558027e2e84b10a3440b2a4d001ffffffffffffffbf4ebd655bdbb5cd3203da97526e69011492984b29c994524aea17e608218d106cfbc2f6b31bbc04330ad90a850a9aa913ce652d1955314d16214e7873295a75e89b0ba14df8a7a4249432419af004bb2073ac9d4c33ca84ffe225a2359a4a3984092fca499babc4d09c4a2ee187bbe79439c4949558c297912966372be17a77753e0be79f32947074ca65c9ac840af7241c214bfe4defc9362c09c7d2c42c25fb4878325909234b90f04449d1d6848b1b3d3fc20b3209224b562e96ec08d7cc34644c677f1d37c235b93dac8bd889f965845bc2781242447d70cb22bc777feda0a38a70dd3f663231f8bfa989f0433e965ad6f0d929229ccd5497b493877074884eb23ca6a8e519c253825ab414657ea715c2ab110d0b57c266aa1221bcd41de4c3c4ad579506e1e6d774316d1284f35e9224a609f5244c8170b4a6d0594b8070edef73498207994f7ff05b94d81827730cd50f7ed812ddcc9347114f1ffa94bb930c3a091a830f7e0a95e63d59cab424688c3df43147b7943d7a7036dd9470f62699d6e4c12f5f9393a8223a28f1e09760620e7626aedddfc13755bfb299243171dbc13599494e66413609aa835722f3952455be74990e9e24fcc6953057979d83b3496a7abf4d5e522b074f5d859edbfa33370edec9e1b249651bf47070fb64273bbde16f7c8327b8492699aab8c15f3fe1e4f9ab0d5ebe8de2b3f229a4c9064fba2e2999983b0829aec12b557fba04e52969a8064ff2183589258489280d9e798c6e4aa4978a1d1a3ca1447bd26b31a6ebcee055e5b4d983d9ac6d66f0a28938d9c4142a83dbdb236a7d36cc58880cdee953728c2234064f96fe9483f2123c460c5e4e954cd9785c304f189c4b972f9885b42f0f187ccd2948cd64d2c4a0e40b9e9cffb593d41c2ded057f8332150bd973ca2e78969596e73d973a9f0b9e4e299b50c1df827fc27470bfec6e522df8b32925995d67c151c265e7fc3316fc8cd9bc640cab70ba82df29b7d6bb67a58c159c8dd92adb08ad4a962a3832a81813b6ddb3880a5e4a8292846cc779760a7e0eeba4477aecb2540a7eca966e3165143c55e1777229a1e00715d7498ca67349e7139c515e962d78c868824e70ece3e234668bb162131c8fddbe9a66c3db638223469cdaaa35c9547796e046134d76910bd24d76d2f0f2e9ad12ad29c113a299c4aa609da19d24389fe173c5122b9a641d24f8a7c36bc57497e49c7404ffc772650fea2f83690c2338fa2a89366a4529256314c12d496888cc6818ae5d30b1a414240c57e6be748e3941a8c1f0c4543a3e338949c5030cdf4a2841a9365525fa85efb1eb4c83cacc24bef0356906ddafae79d30bb724f9cbc25829994c78e16b5f88c987b85777e1e8cf4e1f224d50daebc2ab4ed27a9998498572e15beacc953165499ec685a331b7874b2774e5dcc2f35c39297daf2dfcb48f31cdd6c24b19eaa364cbd27469e1db7b0e2a484bd2e667e128f9b88ea954d62eb2704da62409bfc4422d25366a4e85859f5cc62aa5f9156e6ae5d195dbec4eae706389316a92b173feb215be9885880b9e148315ae95da2093ec156307133156e1b6f76950ff9d5dba440c5560a5e45c2a5ccd15834c5d366264092a7c4dda7395a0738c6bc9291c25c518643e33dfde14ae9aec2393d8d9424da570acba52fa0b6e279848e1770e756a55e44b7a46e186becb1beb52949a88c293c436dd1674c52026a1f0733af97afc34df0714ce5a07ab14a3a689e6136e6629dbd0bc6d9af1841f54badc21ed4ef87177f2c65449cb0973c24f52948d6f36e17c5736b12f65b58c35e179a7a86e82b05333e1a8c77c90a1196407139e74de3978d6eca5da4bb89d338ad4a8a50425967035a5f9f63541e5be125e5be64ba984094a4a29671a25a8bb4cc299b9a492ee7c2927497876820ee2445a345b23e1fddf5dbb6d063541c23917df5a4b3aa6271fe1793ee5b33d2ab64347784a86ef0d67c1abd4084fb68c2f1965c43f6abed286b6084798694f7248119e1c93ba3f71b3a192084f6cd26ebfbe4184a72b47ad987308c7629aec6792aaa4254338769a19b2a4f9a510be7aba1eb751254d84f0d2834ca26c4a39e507e1f7a88e66c24810fe49e263a5cde3994281f094a48250da6349383980703d9558635f2a68fefcc1f512356b7312934c397ef073a59c3be59c66eca40f8e6be8ec2dd97262c2076f3685109e354927c9ecc1ebecd0fa908d59367a70448652795dd4dbcf831b16f3a551e3c1af784da9cc4464eee08789dbf69578f4de0e6eb6646e26a65f8c3a38a6d6265a2c0bb2ed17830e7ea5a98fd9ad366bfd62ccc1b34c2928c1945225c32f861caa7c29944ca21c0747e96ead36f10da18583a772eca4a4a437b8966bd6832ee1834e718363ca332bc6943638f25146c64d52ba2d6cf0748d9c201a624ad53538aa2e25fb3bd5e08aea92fb6419f39a064f6706a1bd349c8d8806bfd73cd7b87ccad2197c13623bb9e62ff5318323837bcae8af0c6e0a256325f92783df266decb7caf1e78dc1d3a3e77a63b68f1d138357952aaa2d56416c1f06b79208334bedc1e0da064b3176fbcc67ff05dfba36556352d288ebbde099f429a9bf183c675217bc9cda4a92432e78e3e127ca4b8991a52d78f9744e7d92ac900dd282db416a725192054fb4f0a144c9c1826b711a73ff27db3c57f024cbe53985cc0a9e2ca2a29bbc65094aaae0acaaa57747934b9750c119cfb3e9c65328a99982676d1acb45d7c592143c4912a1442dad29fa1f053ff797892e792878c1eedf92ecf594c34f705468cf615927f8397b4e1532de5ddb2678720639499bfc965398e0774ea2ac76094a46cb12dc4e5f7239a534a22a69f8196e54eebc2ac11f3567929804b153ab1849f094ec71e9528e4168550c2478399f8eb96b333d45c53882f329a59829ff099352318ce028b9356538955489528c22f8bed95e164d6a50e6303cd173d06292123a9d290c4f635013cddce3c50c86339a949c994db6c912186e275d2a7b3899dbe47ee16af24f51daf9c20b67d14ae5d43d5aeb85274c3061654e3da579e16b4a194ab4945b2ebbf0aac4dea8f5f619d5851b4e8e954e562d815cf8a7d2880ded69de4f2c015cf826a7923f73e8168ea65149c97da90f1f5bf8f29e3dfb492dfc7462284b62c96535a185b3a5f47a2c99851766729fbcb93d648c2c3c69724c5e426c508262e1561016e4bbe5f305165e78699d8f1093a2ff0a2f86ba9c63ada90eb9c2cfa08488d7dd0a47a70be9612bac70cbd4c5f6d32abcd7ac12930ea56aa3aa70947a7cf9e5646e662adc4a1b9d2425a8f0d4682a29fd770aeff3988d7b8550da99c24d42b6560595c259f70ea7f348f50b29dcba92c48c16e351f829f666a70a1334662c0a4f305162327571283c71153c27e1ccad4ca0f0b46c66bb3ce227973ed1673bcd9441e3093736945213a34e38b275aa624a4d7f8813fe8cc98775499f6268136e2865f2b78a34e19bbc59664b27a13e27139e785fcc667a4dde8309e78499fa311984303197f093d69ed395419ba8b184a7dc2d9a8b327993a6128e8b6c4c25bf554a794af81ec4af67e8684a924978490861d274cab1e19684ff96e96fe548f856b263569324412e0d0937f72541c767f7af1ff195981446cd8e7094ae249c5fbc126884574989a91a7412f36557028c70ebec83952acb4e979540f2c75451849fe9315c90616412a46604fac6201fc2f734aa4d8e495fd2e21ac2cd59548cb1f94ba64b0be128157d534b9884f02a36a3c5668ce12f3808ff3297a64fc2d5c74e108e0c4a4c499c52fe1ebb403827bdc807a9314038327f4a685bf6074fa7cd14bde9dafac40fde6813fcd4f57d70d5469c2449ca3e25990fce7b769d9694e46055cd00640f6eecb56462ac44b992a407c7635a134c45797073ca96941219840764ec641bcd4e74074ffd8ac574da9bb972ece09df8d59dac491d3c59aad478d02a6a64123af8612edbbb0425da5a660e7ea866f43ed1eccb7f39b826a594b22de5e3e0774e6b8f6ea1c9a20f072fc87f50c289312699fb0d8e8ab94b53c7da0d9ecce3a3949828ea326df0bcebfb533eefa0ff65839b6257578965ba73d7e0c9dded5183e31996efb22c69703df7860dd75e524c1534b8bd6a3f4a5bcc90969ec1519b4f0c972976cb976670c4c56eafd3b00c8eba583906cfe1e97b32782183c86c9faf82cc8ec1dfa86de25a46655c4e0c9e567509156a3b8c4a183c79fd4343068373f2f9cbc8d240bee05df4d818e35d97d602f1829b3d35abf29d1cdb49902e14acda6a6444d45be32d798f4aff188370c18b9916d4c4f419c4a57bc005902d70a5ce54bedf44455f00d102972984eeecb4ab0dcab1c3055700c982eb76628bfe12362de6981c6490f1c98c1c5501102c7852c78507798fdab071054f9d12e26ef36cd967a0b1031d3ac8b8b143c78d1efc0e2bfc9f438334bf2c8ea4074a666ae5032055f06a438651e2540e2364260042054f9237f668a68a6af5c1b17643478fb3a443c70e1578e048003205afc49483492728c97d0c714108508e1d2e501029788212bc4dfe2a49b8d3a60d902878d9b13d4851bf6216c2b166860e1d3dcc18410281829b041953986c213e53480390273897b4da289951ed31c5099e546e8134a18030a1a401b2844d9034ac24e98ca19992b8ce6c478f33ea00a20447b5dab3db647e024812dcac50eaec52121024b826a9d81cddba52c936470072044f69d5e0f2be22a6e4418ce078bce731d93363e98314c1cd1821deb4a4c3f04e0625c774b17d08c393821653626aed2cf1110cd773ce9d4cc78a10d91fe29d599515e203185ea813726616369d2c4ac2c72ffc933c49d945d7dbc5ce175ea9646e9793a4c2d332c2472fbc6c4174060f9daa9eed237cf0c22f51dd27766576e1dabce6243ba7e60a7a5db86292ccc154a658d6f823176e0cafbed9b7a9eac2b8f043fd05e57de92d9cf18b8f1a4aae1915e1c316cec88a3de6315b0b3f4d129364626d52f8a085dfd7f561b39b86cf69168eec51525292b6c79f46168e67534273ee8d353f167e67d216252aa77cb28685dfe2dd693e557ba9f02bfc998fa136a497ceb2ddade0c3159e9463b6f28f492d876d0b1fadf04d658931560a4ac57358e1fd28d9c46493abf03644e73575f2a71e57157e6bd87ccd784eb29b0abfb2cf656730e1b15250e1f927a154954cd3ca487c80a77044db4eb3c969aacf8438803f7c98c2db9cb1a2ad9af29847a5f0749dbd6cf9068d4187148e38ffec5e2a69666b1715f1310a3ffdb6758a5a27c9413902c4831c3d5e070805366c84b820042cb061c3860d162010e0e8912306643cfa400ee34314de56e774375525b557189161100b0e171fa1f0ab74c718ecc48e2dbd0d1ba0f0a492cbb0ec58be1efd847fd144f66635514ace74b0830325e0f122b833f340d50e8483c7abc0042188021adc10c0293e3ce1bd8675fa203b7c9a0ff6e1a3139e687ffac4ee5c7a5ce4c30727bcb4f0d14ffee826fc3731d9dd434d7852f986a8992a138e380bad3f9382096f6d7d4cb6eb745362838f4bb8fe553d9fb297927c04870f4b782a284d9b212c95acc14ab8692634a72ccb991df441093f6a34138eb54978d1ea447f366582cc8d6306e261a6840f49b8196a4e9d2445114a1254c7c3860d497c44c20f2f76bac23e37d00ebec75d0b121930e20312defa26f570317c4e613dc23bcda13e9979cd28318ef04f7d93b2bb4cd2e824eaf164dcd0d1e3060a3e1ae1678d26f5c5497d6a1d843c58d023c7413b3cc0821d243ac8e8800e17f0c02d7c30c2f1d0edaa2527a93cb4086fb68275584c49640c29c295d53e113b4f223ce1a430517b3ce33f46849f498caaa828d17b3bdba183073b9019668c20c4033b74e0e8810607cad0b1030466e400012c3e0ee18f4a4a7d3e7b4ee55a031f867046a792c3a9e814155121fcec1ead644ac933460f211c1b390b7eb21e84f79d2e092b23355a6705e19c64d278cefaad0fe34720dc3ceb318c7af558f50108d77492948a4952f5f39a3ff8d92f17e353f40925f583e39943589b0c1be5c33e7cf0c16d4b1dbd4e4a0debcac71edc92c4a87ce8c119e99abbb2736c868f3cb831aaf6670ee517333c860f3cf8b18493655af3f9a6e70e9e9429cf78a960191ff4860f3b38a3e92cf5ff7a096e0ac3471d3cf5d755dd314247190a1f747083922bd7683a392e5b7b898f39b8be5a659eb2a652bb85c4871cbca0954b69860e3e2756b6838f38f86141a7cbb1c2c834baa3a38cd279f880835f32879d503993428a3ef87843c1b2b3e6d25cb2697cb8c14f9b2fdf694f0de1a30ddeba9f98b7f213222638d6d8e0ca5892bf2fad6f92f226848f3538b2e131bb7d85ca68aac1cf50afb1de744a1afce0a5347cf6cef02dd1e02741893d3255ea2d6fcfe06a12d7577217aea46a06e7547ab7ab3229da7567f828831b8370ffcc61c1c10719fc7f91df4a49306144e7051f6370c62429a8bf9283e764f91083179aae9498b29669e1c247189cef2487f4d19a938efd07183c4f1e4b264bf132968371f8f8c287175cefd4ec6e0da6550eb8e1a30b9cb418272e38ea2dbcf2956492e67a0b9e6675bf242bac054fc99be24688daf759b2e0a59424f94bca549b073fb0e0092227fb7cd07f5cc14b3a093b7df7224de93eace0657977aabb4f4a663faae0a6e497bee76bf39d0e203ea8e0ba2813ae930a16de3f1e3ea6e067253179104a8dd0e1a40c1f52f05693eea0927b7638930090e1230a7e124a3aababd31a3ea0e08f8e4950a93d5449fb9fe089afd9f01ee44795886af8708297b46bcae4a2d7347c34c1199334df876d18e526267851a4e6924cda2cc1cfa153ce5a56417fe7d3f0ed735f76a694d2824509aec9b2aa129fe4f7124c82bfd173bc9c1494ecd943829b4a26d1d446578f123b829f5cfb4cce18c14d51353d6ab24b9fae3b317c14215957cfd1e4a0d23a7aec618c61f8d79acd544ef2765d1843189eab9b4962c8f8a44c29186eee93fc5db47d6f1a18aef6b88997d459a7a15f3822fc2e0977196ed3892fbc4afab6c6af62ded3bdf0ed64cd9e6154e62ef1c29199b34d8c7225279b77e169a99049ca319f42b3baf0ca8216916977d25632178e8cf6ff397887ab18c4859fc65c4b63da6ee1a75cc1bf3ea69613ab0cc402335210e201b38573339ad32afcdcdc7486316ae1473fe12da9fbf9ab092ddc14a1bcbf676dd326b1c218b3f0ccebb2879eef9853c3853164e1c9336fb6b10493c4fe6251a6b459f3c8060b37c9d5264db43a1edce84116c678853ff225c9418f27b1de76852383b074aa495a775863b4c2ef94426953a28415be6576d3a92fe7fbba57e1fcc69c3d46735b8caa2abcf2ba20c59494100f84e4302347421f98c318a970fc4b8cee2c17156e0af1bf13eab5bf621b366ed81ac63885d73998f06ec289a6968c610a3f8427a541c7602a87394629dc382997545e496390c26f194d16b49cf8f56514feff95e5bae06b92b8e007a8046388a28bdd3116c6b3b44eee33eed48f565b7f804a30863142e19f7f78c969adc600859b3a93a6c8de123ee9136ede3a9d2d494f954f9e702b5dd2ee2525a9d65fde20743079143208d7bc664eb6f12c2934c4830707b4478820bc241a52b3d2a970312924108e5853255b9b88af753a0801842bdb569a95e1b72af607573ce5ac4566d60f4108e903229b103e14930efe623a5b65101142f670217af046ed4bfcfde6380fae9f70632aa36892ee5e081e2ee40eb89adc659a8ecf983c7532b93c1c6b1962072f7410cd1a3dc70621757045093f29f58df84c2f840e6ee93225beaa846c97819039b841cc6387d614775b9283e7fdb1c47b13073fe8a4ae9d55a632cb70703c89362a991c0a7983db62f549b67f0a9d5337785292848e17150bcf671b3cf541491354de32f98f0df9fc474d529235683fade152f944c6104ac757480d85d7c9b9e4f24d2a2b869034b8d95b2667acaac8592168d8b292ba95a5d7ca6a6227badc8832adb5d96629849cc155add2544f9331055d88193ca1a5ccd365cbb9b7331e2165f072f41cc38bd081410819dccaaa26dea43c064fbb6913a36752ed139e1122064759a6de58f299a76f43c2e05da6ec260f42c0e088e8f0532ac542bee09cb0d52aaa15ab6ca4215e303c68eda0426751e2d81f8474217bcd639704c71a32810ffe048c06085810e286102e1cd755d6a97121227ee2ee2c14b285668327cd9a162d781617935f095a5469cddeb01d2159f0d4e4d8fc29b7b66f88633f040baec69769cfe104f353052157707390354a1eb1b9b7dc8e1e676020c40a6623072155f0c3eebc52da890a7e7609cb67494db40c9a827397fc93a9d50c6a355270e304f1d5274933db7714fcbff093c28d160afeb8e78b7556266b2a4f70940cba35492ad8a993e2042f877b8ef38e1f2b65131c33416de62b77fa2699e067a6cd256ce7aafa7109de565c2e95849786331f63d75cc792699b125c932f971cfbdfc4d61592043fa975d159b935cff748f0ca2e5cf4ab20af261572044f1294e8963f4c428ce0274b3f49f44aaac269438ae08928f5281aedf2a5576318ae299d820eedb030fce021a47889f5bed9e31ac170e4337f12d4f698ce39a506309c73f7d3fc15c524d4f88527c8e0294a8ad0da3d1e146af8221d835a12c497985783357ae16fe512343d798aa95583179e58963309176376e1c5562531a627d97febd5a0862e8e13934c1a935afcb9f042a3896ad255ceee142edc4ea33953a74a11678d5b38dff26a5faaac610bd4d252d53cc6523ebe374929949c6d3ded1ab570c3c8eed3b1e7844c0d4ea1062d3ca9d15a4349f206dd658d5938a624e92d9af4b11ab2704eec6cb484881aa51ab170649bb8943c5f98a49260e15772ed93b47798bba4573863154b9556932bbc24956ce752526c38532bfc7cd299c99a84f6a4c40ad734a891ebd09bdeb40ae7e2db7365af0d995785b31ee33dc4b69ab053e18ce7f6b97ca5aa2e0815cea893abfb4cc807119dc22ff93ef7669329fc1c7397f624052b53520a7f54ca1a27a6a706293c19a3ab9f761ed3f2d41885a7740ee5e15ab49fa786281c193c574a3108efced4088517a3fd491b99eddaad018af2e7203376ed27fc8d226318b5fa32a527fcb693a4d0e17527bcf2fc229360c209bf242d6ae9275594ba093705eb92c474a5de649af083d8f632a994269d3299703526d9efa231891613a9f956369d82bec6257c19a1b93c98df75f66b58c2f5eb1c224bf4876abf46253c95440bca934f094f95e7d3d698fb363a09c7be93e8fca731d32809379d4cf25dcc45a20e9dda3d4dea21e169cca8a8f03cc2111393a798fc7365ba1de19ca7cf5482fd67efba117ee73221c6ce92682746389f744aed5db2b7a88bf093d860490a4a9570a222dc54229b7e6249878c13e16dc93ab13144bb578c082fcfc77d921683aae8107e8e133c542d9ab8134378995e72d0496558490be1e852d26494bb95a0238457ab3177855857ea06e16679eb7bd904e16d50cb59b172095f6d205c53965aeb3f80c0e7939c248bf9836f7762cc24d39431fbc13b25b37cdeb4f421e57f62e1839772694fa3376992abb2072f43ac9f9f1c353c470f8e7b2ee93f4919c476340f8e1aede459d4a92e59c5835f6249a89693b47cab77702d78fea4c4143bf81b5e9b654cf28c8bd6c1ab7abff9381b659bd2c1eb542fca34837a14cdc153cf92e54b64cc3629074fd2317cd05faf99c4320e6e8cb4ac3f1d38b8296d3b3da98ff6e70d7e494274f5c9bbc1db204aac147c94acba0d8e18d3a933792a2b61367892ce29f8895057425d83b7224e9368a11a1c55e7a2d4ba3478f2894dea3e06254e0cd1e06fbfe958159ec113b495aaea246706cffdac6c947c19bc4ad34eaa6458fafec8e069b32498649e9450d21b83ffa56e179e93925c3b31f8395beaa06310174d1406573b780795b764d3ad81c115352526a95436576b5f70546b589149b5fb52cc0bfe59b68fcd5092d6a02e6c822e496df411173c314e35a75611a2926cc193d3adc499242995365af0c48ef92cf839b7fac9b294b1bfaa81052f5d4cc9546318c75a8e336c7301b6a8710547c64411954ffb75f975b3a861054f94a7f74b22c4b1d606031e3d921939cef81bbb8053d4a882bf1ed38926a54d810119093a860a80440d2a787974cb6c545b11969f829b71b24d366d1fbd53ac420d29382a664a26e524cd53d328f84135cba938eb8a4d0205df359c4a9935f304578430355127f59cdd56a8e104bf929c6d9427ab09bee934234657123e1e66420d2678c9724aef27d59ce85766a1c612bcb70f9d4f32318da5a620a1461a8fb8f67c2895378538d636063594e0cd6b8d099e3ac69c1a4970649204316e33e2d81a4870d475081d63eb1a47f054f455b86d92e43219c1134e565dd0a31a45f036b5d34a5e0f2b771a86a366ccb744cdd5410609c3cfdeb85ce2130cbf5492564b101f6078176335a7b9f42ffc5297d926dfa619d5f185efb5694e79280f0d26bdf03b668b6d397607f131bcf037e8fb8e4136bb7073a89cff4be7a03b47175e9c45f1de2498a532177edeb0a135658d0b3fc368ebe499bd85a745aaa5c5a5a5ad8b2d1cd5996d32f7c90aa3ac85a39efb2dafe834b19316aea651525a979d7432b370d409cb7565f2f5f6b2d867f409c2843b167e34613d97ca1883c51016bafc976726e92b9cd336a16e35bc24a132de8c0402882bbca03fa724e6f094a40ba202482bfc543a989884509926a78c0920ac784dd9cdc917c82a3cb198045f93257231d33a5880a8a2aa9439f9d779123ba9382bcf5dcca620372abc284a926278ebade0f7297c4ff2765e9a63b978a67074f0527a46e9ecac1a8eb552b8499019cb394eac7c6a258090c2919a934af2d9aea6d31f808c42cf529220bba445e19c50cb12735072d2aa79c0033f304307395af08394630782c1091460089050b8266809af29568fc98f63cd860db4338080c20d774a7fa853326f7caa00f289f5c47622198413209b607e2ec890a24fb461a36f478f3304800a104dfc692b9306158eb53274ec48366c9041c67b200b29403251b6e94c3741e32a83897ed6e6f35fb9c95fc274a59498ee4c92f2692d913693e6e4645d9f5209ad2fb99a0e3a96ec9c2fcbf13b5c0008104a9c4f48ef52f94b290f90495c96b3267d722294dc0a40247158caca97d96d8938b1a38538a951048984df9e1a640a52030209e7ab2ea9ac8658007984339629be42a6d15ab205c411ce89164e9ae9d4f0556a845f16d3090b1931c23769fdf55bf6156db308ef3af3a56c49d252a65684f76325e61c3e9d08c7f2a64a7acd92c8204684d77f3526671f1428b3809505f0eac698c01866a3141b1681a4070f34761420003f301638880100e8c1030d1610200048078f860ecc78321020001e3b12700200000000000040031c903c181080360080070f63830002f81e7f6c142000dfe38f8e1d360e0080014020013bd00e92efc1e3c60d070020000f3800e6e8b103070f3200d103f1f883a7b35cda54a1254941ea074f76b0f8d9e83d26667df08210dda333a5b78cf0c18bbb3ba9e424d9270fe3582b65a03274640f88073aca2803957180113d608e1e3cc871f2f08333f080397a1c1d65a071e3460246eee0ff5c29250899c3b17c86c6591968c70d1ee438374e8e049dc1a3ad871939908719397aec4064e438a30c1dc90a46ec80376e2060a40e6794919481ca30c0081d30470f3270f0f81b37123032077d4e58ae0e79e5e06ccc966eb3d6913878b29da04987abc820038d54e62370703b5b8926e7134db4a037781e266cae5c991137f82656bac7a49949187ba40dfea6888ea5a249c86e47d8802cb7bcc14bd2c81a8e5a23ae327047d4e02555f297bab524530c1a3c6c03236948d014ad53e3743682066fbb2f79d0a0ef64f8f5032367f0525ceebe4ed9cb548f636d2f306206ef55c3e23a2ea6fe348fc2c3032365f0b235437848cb4c2ae9841132944e7b3e694aaabf6a640c411811038e84c16ce81801038e7c0147bcc06c46ba80235c68d3e53b2cb5ddd59855a6ec4a82ac93c4890ec71adac1bbe08c912d782ff7266282aa05cf7a849674266ebd732359f0c4746ad0a7a247ac8605ff4657261393365c5d2357f05cfc820a3a4647acd0d5d869bda554d1b2adb24997be3ed748155cb1fe7a732f51c151d154614912b5644a6d8491297c9d3d44c9999d4fa4c09dd858c77c5a9c9dba944e6a240aae9647cd3146050a8e52a7f306dbeebf1c3ec193cb1c3dbd5a57ca718233eaacb53bc42fd5db044705cbd94c32d99b3f650242e5ec9f434339b2046fee248deea6bbc1481abe5d7d7609db297c14e130a204cf746534fd75d66b9f91243826c5e612ba0499c7d711243826dc9755b83872042fbf9aba4a52beec9f1b3182e7d6eaabb9c5926807478ae049721af5be1e2c839a458681c2c860f8ee276d4d8a689b8ac0f8857f99b67bbdf201324375b0039d006f07ea91c3178da5abaf9b8bfbac54963d6374b5a42f498af4c2ef7c16d761ae1e6de585ff9bc3ffc489fea9c3bb703c98ca77a5492c10d185f7a2f557a6745c524a72e1c6972c4f92d4ff1b1a2e1cb1a426e749a56eb1b6f03d861293d128b23a5b0b63ab57543b51a48523ccc6848e258df8ed66e19aece1572dd876c84c16d596b859ccd59d875ac86aac0f3317b3665c9f51468222b1705318a193dda5d461926c1081c589bcc273f1e0171e6acb6458c415d78a1361c5ad025521920abf3a8926e9d2a2c2f9326131575092880f9de2444c514ae1891ec5b49494e5d16344486136467122a2f0dca4f9594b9d434dec1222a170eeda63d558470414b956675d5da98b55dcc58ecd944294f040e4137e6837ad14cae4094f8e9afed7a429d209ef73526ac4278f08277c0daa4426b56a726e130144426413ce68b4f429d4ff29318926bcffa825894958d29e2a2299f0d53d26e5625a4c38dba33ecbbd0625d60ed423c7a52172093757ac7faf882de1af7528d9fb531d2295f04e1263ccb499bfb3654a38ea7fb3f5077712cea8c7a80da619b37f24e1c628316dd53466cdfd8e924422e1e5cf1af449efab588220a198669273346123f2087fd4eabc334511174d8ef0c263ee7c625552926b9146784273bf7f0a97968497117e1ea1c4093626a9fa908d165984a222fc79d14a7e29633a2713e19c1232b52631846dd2df21c24f231e9fe7447ab6cbdd219cada4ea4dbf7a6708ef4b8ed99238b710ce79ce575a25c3a8247f4708dfdc04bb3341733708dfe45ce1bf32a396ecde8908c279f3981593e8196d0a84a773c858c272a628a0c18d158800c26cc840e40f5f5d7a0aa33378227ef02a690e1dd3db81481fbcb0399f7c9d63dbd927c2074fe6a0739a5ce9e63e06f7e0c6e8a54b32ff51440f66e344f2e089a6e65cdaca3f2e8c638d470e3d3c38a3477a75bf8f2a4f9ec81d3cfdd7bd72ae881dfc55cd49a78b8cef31c113a983e396ec73e5e0be5d693c113a58b6766a39e334e6bd535082ce492c3207b75249f27627084f66de89c8c1df10dbe43e423488c4c1334925d1d2213e9f5b441138b8c13c2c7f524a30cbf937b832dae3b73fe90f1d22e38c3272f06017718327a894fa4dc8b5e38c2381481bf0d0b2682f372e1b1fe7c640840d9e49ba4663ae18f3d1640d9e8e661f43079d1abc12176c5465280dcea5b510ea27a6f2b9d1e0da98baa4677426a5b367f04db0f69c3d9beca44d3378a54ac7dc5c922acc2852063f9d8a91ae41e54e840cde6fd0d817f6a9fe9268888ca194e7e647dca6c5802261f0c3fa4f7f776a44c0e0da6b124df0e0f9821f84ff28ed1e2c27f18a78c1fffc314931e3f29c94d205376d28595c94bc696352840b6dbcc875857d67d85968225bf03e0923c63e5c98f24a440bce69c624e98f75b97354240bde5c677efb64b162c2388860c1cfa4d29625133c2ce65cc11b1d3de4ae7e2b78a9566387f6dc4949b10a5eda7a964a57279e3a112af89ac4565b26494e5a4e44a6e09fdc08db7cf29d8814fc1c63a6a376e9f858120547f9d69694363d1128b87e974b8e0b13b4fa2e66883cc1f1e097c5fab36b947837ec7870224e7054d2ca36ab8ccbcc399126785abe6f35fcf4faaa66e428c18930c1fbdc1fd7596d3c9125787139c7aaf0c15d3da682481a8e925d42f75889abcfa8031125f8e997bb44395bf90f169124f8a7cadd2e954604096ed7e6afd4ec27854a8a1cc133612a626db3c9304a96206204b7840a139476f12ba51529825faadd3d43936ca3510c1986274bde60dad714228c0c86d90086d9c01b84fcc26cec20c41766c38c905ef871c1b39a9a92bb537a8d7208e18517976427e194a0c2ac786408d9856361a207cd18ef563a3084e8c297f99c73c838132ade40482ecc062edcaecb8a3b215ea283ce8d63c697a16347e2b35bf855258ab79b106fd374b185b75d97aaefcdc4905a78fd665f9ece3708ad68e1e7ce96549b204d45ed67e1e5faa8d96252c951ab0e84c82224165e79b6a9d431f66c92c2c24b258931fea285f50dee2b9cedad5ca592f8b7fb425ce176e53bb53f93ec3b15d20a4e561373acb63c261c8bacf0c3924a259fc5ecb0cc2afcbf58e5eadaabc28f9e93f2183e93688553e1052d4265f42851e1a9bf7d095b5f1f4df7146a65134484923453f89e325c9f7621a5f04c5d5b7c168d145c2a8fafe066c20a198527a63abb8d4ee6561d46278488c2b55c41869728cd3a49a17054ac650e93724c1a43a0f063844713f2999459cc2736694dd46d5838c4139e86133227f1944e38d2653429b73984137e30952b99124c4999cb904d3817ec52eb5dd49d52856802f1b220a79666ecd3e6347a674ad7ee92d33a24138ede4a25d3c3c7e5394330e169cb49dcbc09254e8ca6117209bf4dfe31c1336b644b2010422ae155fee8aa6a62fae8f80619680725fc607723b5efa44d2dedc8914c032193f0bf62c9e6717d1e2b8f634d0737ccc881a3478e1e4842334b692cbbc96a5b5ab9a79989cf7539e57a98a16347ba71d046c2114ff2ffa84eeadec8811c0881846bd1a3bae6ec0b61bad39047f855ff224598609bfae4f164dce891838c33788438c26b8d4fdebea2be01010b42421ae146abadca781393a91fc2084f3b9a3ce22e54abe82cc291725f9b42e7ef4214e16f2879ab11a5e562851792086e4e74cf10b2c7b176e3073b7a98f18620c2ebfe98d76e2d0625ad9043783ac6128d696f88213ca56e93d41c5eb17336a4106e8bdc86932f2e688410c2038b41a824ae6582d25820188a43027128100a2cdc1e00031408001834268d0482e17014a6d2f6011480044d2212362e2420261416141a1818180c0642a16028140683826150180c0a0442a1f0759c237b013bd977dee17e4116ba8898ceee02846ec6cfb5912d1c5793b6e8b2e934af00b9d57830d9b6bc2eee70fa4906a4170f9321dc06fc002dee56d2c3c83b83c481b5fdc4ddb1bd978205f1357a0a6e3695266b7b4ae15595c79955ab534bd1f800b81046f8b726249377978efed9e71478c071abfedb9de803c542d383f7f74cee3c3de4d65506971860aff08484f3254eee1fa4c751ca2b4ba48dd8d02c0cade7905209e9546419c6193fa3a944bb6bc0a47e3871ed4f12229561893b939ce6eb22d141093556b3fe772625f249934a0e6cdc8300b84d96f86323305118c1c0b7f4a13145523dd1b9340ad03e9e593c0d8a3c9fc7c7900f9dbe79d689374de94fcb529678d5c7235b16c40920dbc075b5142448f630004e8806fc62b0e4a90764a13c9d4fdc60356c5ff0444957eea424332eb56faaf8518cba5f4e4eb06f13a0c88ac47ebcf7df3d2713d73721b92883205cc62545c4303ee26b5e89f74a5a664f1e98e390a9e92ddd04438ef4abb557aceeab9968fad88dc0484dcdec6ba6a0c0f71cf8db5424bfaff1c078211f88b812f5a5446cf68a2f01b6245a2141bb01b4b1fe1a15582527620c2d366cb3683bbc3bb4cd4a4b5c8a737eab65b9c26fc13183737aab25f7c04f4863b5c499262ae488aff9d7f2d21acdb27e23869fc5fa627068f293e81b5b1c022a163efe7d558c65fb727fadc93ece3024312239907f0790224cc51d3ccee47a463793cde24c9e111e1df5e4b25bc4cf0b73ebe08101da595e5d5454f8178c8fd92f6be94a19247484f39f3835c03009d7e6c98b97c64aeb3d8472d0b75d632f4b6ae6901943e89dba02879e7f732f33710412ffb045ff8342ba51c5492570e259fe60cb8b7a0ea3750eb8a89fb09e574a8a9b7ce4c762530e42c5ce9e1a25a774d4e681a9d413c4de1e8941f49706380a372c342849008e39ec05a517cac6ea61daa47b45c0e2e326b0eefeab565e263bb5f6b776e21eea2fc793eef39a7dd3d80ad4b3d5eb8573a852d0e129088de7c08809c9c04304a72394961a99474f08e525a211c748aa3608d3c0d965217a2536c25dac75d50e0d016fb150971b050246442579cedffd17dded06467ebabe5a4d8306fd21a82bc9f50a6f5a44c4dc7341d3f0cad7917ea9ad1f101feca68b96c27b4314118aa5c1c0bcbeb0aa24563a44d368af25d106bb06c91f917c477be39016d95e1be895fbc8c8e4bc636bd0bc58abad37c4d27384523b4f5b43c7c59277987567caf9c34d28bbe60f60772b23954ae29ca4ca57c8bf9ee29a9a752d1191bbcb297bbcf3becd7ffa320efa6b8b4ba1ecf196ec087bbc11b1d3d2c6ad78af8e69b5b356cac400f15aca9c35a06661e47aaed0e72c90141301602f45fe1144dea918863b057e1518dc0e15b2a06922c522f6af434d081662a09786eab66909a0c04449ccb3d08460a693de38a725fdc7c82ea3c6aa07fcd397fbc3c32301dd0d74897f462e97e8ae808e3ba888b6f1c6a3a1c8db5a6f4ec4de343bc08c24585a7da30597d70717adb705767e6abb507890d6aee044138275183941b6eab1373a9bc6323b3d428c95e6121318bf63e9c1c49c7b432cd623012f4ad77a867cb5cc4b20a5da4cde299dc93194dbaa0101e5c239e0f3265ac74c8395d641710be3fdc4dbae8e84ee64e34861aa52a0eb4e3cd6a6098c8b9ad61b41a15d799564ec809ad5d337fc522cf78a7e4feab2c6a102c1d11a029a60341a274984a0118b4e7278d3f2becc0e6faf3284e13a2c24e9522a19ac521532eec5f5c9aa2006555079764b874b50f1bfe5401ad542ada8d82d026bd3010054995b09b1f2d727a78b59e1351f23ae9e50d694f103c50bb1fd8bb59375a854e601d4b35b6720399c29b7cc4253d5cdd2aae9878376724cad20b7d886410e81665ac80bb22c82ef182358a4b066c4086bf30253fcba87526e0453d908b85a3302b12706bafce02a963f09701268c195bb70dd9afc2dbe0b4d17ff0ed1c1d6ee35413d26bd45b3ae3446e85ed8a7d55b16596433231491e6fbc8b83daf55599359c8cd76dbe5cdec4a0c20990c16df8112b9a813f310e21d525567e82a134693ac5ce24f3dda1e15cd59d3c0e0632d5b82df283cad60af80786f2a3b65ffe04b6a0818ef667524f444ca5b0b6b8916248708483a38c09ecbc322eda60d6326bdad9372e2b7d6aa2b9e0ebfdbb2b5ca90e340d201693ce3bb9a0507c7daa96821a655afeab3a0a00513acb424b3828bc20983a40fa2c84d96664c2f9fb8f94de1a2810f0e35a56b5b724a80e8df9b5c38b0f27c7bd6f0f5972e6f7b3a4179ca444422b6e25b8941bdddc951ccf51fa1d242d494e375204f77d50c65cc44d4e7a00c5dadc0dc428e561d7733e2f8737ecb1ab864aff07e55ca80c7c44cebfb1548b440bcc6004cdbb8308d9b17d41305c5a569f1ebab1d6dc96e2778a7b1e0562f88deeac8688fc66953f759526850853a2995d96b825739bd374bc3a36a1901462ebb9f4e5c417a3d2dbf410f8ecc8eb5aa2966aa2f09ea153b1a0675b5ec822813bcb3ce5a4abfe0c5262bc3eb3c481afa3efad45699651ba2614ec77fd7bef6dd0d0944f8599e9df295b5f9e27c2f10113c8b71213f78bb8e37e02ab1138580a4088f2a208f63de936a65f9ffdccc4c466acff12ee716a10690113ecfe226770effa95677ad257e9b6e6bb4e69cc961133a6d5f06b368998468b4b5e8f446801e8944210589c020a5b25899a078abe3d364f970a1bd868b416fe2d02ef91d58ba3b509265c39e2e23b68c539c34ba8aa5423ecb1424f68307036f9bd8bee3e6262400cec4f40c918013702a76fac06294ec0e0107dd41fdba4c36a87a2d18cdf196b914604bb694e94e486a65d673c34b75b9176da71047b3426c1bd9979ea9029a25360aff8e89208ab2e29ac5dd74e4d2f499eb5d0ca45e2c7400352877e6bc57cbf89a9a314716bdbd23543afff4f45faaa5d5f2c27595248d05d3feb8b10b6462a192886321074b49b67e58e0fa29972e4b225a95627f0bacf65014058c9d4a8e21711f975e2887da63da874df70ea8595262d96d8630908e2432f60d8c621d6af8cdbb28a91e282a422886d3e4a7085af0ede094131a85f59168a26828ea08d8d4be7e39d9ef84d1545d8810da19a9a26e06384432ed0c6c7c322f39a33e5fb49342c5ee679283d99bf41ec9de908d665d29f87c9a93a0f7a8fb90f10d19c9c44ed978f07b50f49154ca0c2a85ba6ce2f31cbe26f2454db300cbc99a18b3831c0c3e2506f62b3bad0afbba0de61591b38e1fd9dab642ab632c222a130ecb33b543ae9405a8f5e570da7338b9dff40a29321afff8ff74966115216104e80eae833cc9bb31173d13ac1108f9cf125af7929362685f39974017a90a3708bc19035c2bc657b779e06f33895035c2e211f3b77f15a88a0be7752105ef2415ec95ae429fb3ccd6c448fceea02f833cf6ed5084550a026bc2acfdb907fe20335fd2e23d1b771171a4e4ae723d4c10be06d8c45c0759a0f2f05f72669aa668d83f56fc380737629dfd47c76782230e9a130810a45397e34506bfafc59f7d1c9e153ad615aada186eb50198cc2f9ced546674c34f853228181db2f1f804c61db4ce547cabc9367b1e1fce6c940df630c2fbf7958deea405dfa1b1448b93c419b4c315043c183462f651034c68488b6300d46aee8a57902bccd09f124144712f1a3ea11714b70b9b0a8321b21349c00427d4f9be67279c05c6446a6016c05db2129012c6a319d1b87c82b597d2777a25d4ebaf546e2d883a3663b367e89a8ae3fe5435b4615a466438e7d126aeb268494d480093e7e05fd7bb71da26c7c51556dceed88cb8cbe150480bfb107351bf6b3e3e71b5222b2108c7b41c936032097d73ee4aee705cea528290e617b3c3af14d6fe647a264eac3c089bc8846d70199d455cb20dc57247861236a324f0323659e36e48587df280d4297c80ea9a04a26be252034c26b7a5de16e25aa9a2124b6b738c69822fd8953ebf84869810f9c4b2dcfd1e492c51d5ffc4928d51c273114013f840f43b3057f6bb6a7323f42a455e89299992a54676d980de6051d57b2b0f8ff00f05981488107e40aa43209ac5ae69a39571572098dfb1ff8a86b3372dc762350d75a1500a7023b29841deb2411b9db3a2a7c3c84d52f92bb2a5023b42b7e9b76e3f85fd2b18493ad4b8d8b1a8f78d09cd170c67b8b6ec88abe92ef0393883673d8e98b3fc3569fad858606bb930667d69dc99f07ae93fbb005403046f4c825713b9cbf047709d5167b8caa4a2703e22a8057202326c40955a5b9a6afded762814cd7a541a6dd7ac46a95ea0d2bc04d2dd68e3b774579c8d764745512b699b84e747f9c0a283675e38b4f52f100b6872729b2822ed3cca21d807dd8a2d6052a6ac10f3402a04f8014b57caf353214a7ff9c5c9444bb60b59acba61176d167a40e4eed5776b5064b85841bf0a4bec4c40765d457f284a770ba36b55f37e518937f3e23c048b333859000734dba9776698356a7ad5d65aa2747d04fd505ccdf0b26501389aa59b77adfc9b5cf41c22828df7c1dfb61d26f61a7721f973f10a5bfcabaa775f391bf82cfd1c2ec21aaa3f98d0a58e1e887f6f2378697c8387c9393d821e2b2d06cd7987a6830c88a052219f98cc0851cc27a02c827aa777045629d1e19babc7e1c9ec6ecbb401ccf41b7783560e7b5be467160dff8a2a2d2a9e55118a8e5c92d357e896d5df3e1991f6ab01e68292fca17680dd090cd544ac3e1777b56bb7422a534538897441fb5e3e65134e60c19dae28a98a12291a2dd0e91e0336c567f036bd321b677dc35677756c834f68504966646df6349871e4fdadefff4e1f059952cb80abde39c5482950c1652fcf0ad78f306d48740a78108f659c045274877e984375585ce4c95fe1c7a0a4141b9e4348ba88f162045f96ad7c8acf339bca55ad03dd517d569b14cb042d7b8ba7482acf6ac51f478d46b341df9ab0053ab78a74817956ef8a741feec35ae07c470776d57a4ab1e836f399450a53d549d1e65b298560793fea1443183501d75582d45c90a3181569c857194c42b2495a6e1fd611b0feba2e768b6d0ab1495ec8f39c4ca42904209e44a07d40dfee04ad448db4006c5b94faee13553d185df5221bf82e3fbd89013e9038ba7b2c960390a76d935e0fd46a87530f574e4ed01eb24f6b804adf3d541901ae74af3514a3de6422a0a848b8045655f6d33156a0aa7f0bff95eab9cf17ad56201290a5862fb86c6092a1a3cb4598d934575bcd7a0c11d82f7b9f3c18808ddd07a8bd29aae596cc74eafef37b198d087b6ed00113f50c006094d87661f6b6ff4194f9a365c21460dcfd1955471d0b64486274eee10964d6fadf11d104ff16db068ee5983e7110a042f23b2853814b7ef0b83b52cb6f997c9cd4374cf7474e5441d0c8f750a55b1b21107582a6ad0a2762309bebc882151882d367d85d17265e3038d9eeaba7776c4079028e3367b27ed7ebfd62bc35e62e040259ed89fdc3c087f963d6e29b3c57d80ee2a3e2722ac938fe8c6c77cdcd6bd116e17d728e87083963c5731ae91de7d128de4ec9b751d1466c02a867ac4e9c914ad04d0d01be9a1103ab9c00261c052356e81eb97f42301064502c50b48bf4ac32cc2861d18f13e09b00889a0e44f9258a072e950bd380b88782840a8b5234d5ccd4e74dfce72948ef0501fe347001154880cb7abb9ecffeac24a90c4da9f87eba5ddbbf3e7de77ad1e98f74fc9978fa4da072004a86d5d03440901e392dc235a6208ea12bfc559d1915a9cfa07c1a2e4d4815046a67144b9e6bf20fac496d9a44d6e981546d3614a956d686790d6d1c53e1dd4d12df2ee2638f6dc65b983b39f731136e949d43b0662fc9106e2b9e28e1c92461102aaab8a68c4e8dddfb83599803537636fb88830f8afe7ac070e72f6091e6ceff24958ed68d14baebe77d772b4e783f49212c67f36cfc8a139336b3b4c7476b8e70cfeca9ee8918c639d2052163a9229ce971711bf3356a9a840b689a9cfbeddf399298d16fd286594d0ea38fdfe8623382450aeb05fdc87604be970b9263527cd870e4f949c1be6513162095d4549b561e32b2a023d745f04530a6de46849d3cace3f69b724ca2100e317f8029fcebf088484a2804911317762d52f50365f0d5e61183133081ca0833e5ba8ed4602bb843bd494c30887e7823aa10730a6b877bf4b1b34bb9bf29daff39765befaa78443d45406a44775c87cedbd653c835b55852df95ea33d2f1317b730424680cb5b82bb4856fd92fb04535ef835d81a2237a28b6b1969e00129ae1bf76278ba58dce33e4a06ea7428d422154b09475764716ad5c402bcc75c049a437ad5d907b5c99dc0d74fa428acbadb1125cfa78368f115ca76bd7c278da14dac10c55baa4bd94ea7b610335c17d5cf2ed9559021ea9f13adb900ca43a5b9863fd330a8d2f74b1e0dbcd1c9b1c22ef9cdd585c8e6b5562a95d5927c009c7d25945189284f06ae58ef2ebc1728f5e718833b24621b65a26b9d3e0f415cd78ade3a558c40641539d592f9c7fb81de672fab05ae47311e68c70487ef352f654e43be87ca9a508440b5d29c64b299236b6b874c53b6db50792f5b150a65ec599e4365bed0143ae4def1d7ab94aad2392e4b3197c3b88b714cfc16fef25d356337dbfc68cceaf48e0d09b8c4286c88594aee5e26ed40f33dd9cba7142d60c422538bc279bd6ed595293a339742bc31fc02cf25a3e7cfe24b6d3ff5d8c061a81487508b8f8df7bae153ba355395a3b675d992eedfce65a48de3b931d655f4bb0c2d47d2565be9c83db159fcf9b595f5dc25d32129d35bc11b8e02735e8ee8f83281b9bb2b924d98203cec4ad496904a0e7722b0476b3d2380f99b7e9874934468fd023443842cf053fc1952218a4c7d187a29ff1828c3087cabb4db22ee549cffac7b9e715490e5b3f80a5acb32ee4439a8d4e027294134c1aeed4270f764b4295079e645ec1cca1845230a5091f360dceb35376de3788e2e95401342effbec69eb685cca9bbaf0694fdb13061c007edd14b9c8b9b88704a1b9afa41b7eca47e5ad7535437439e64890f4b32289abba684584800440c420271dd92111f89cb2dad53df522229e18b422455fcb6535f1de17d77b65b1bc5c2faea194595a9a702103cf0c2503dd967a47f20d557e98813fc5dfe8736dccf65bb032408a30cbe42958457b8039541c7f8ac0aa9648620ba29c8214b30552f3f70b695105b4f0031f0d8ace482118813f259213d212010dc99f7bf2cc0fe01cc9a244cdb7eb281032a045b74b1e2624a3396345a9422389a5ad30597e2a3bda8dc92eec34aa43d6b4d5b6482f7c6f0a39199eb5085dbd0878f6cb7048b682a5de6a72477b7d246cb1e65ed04d9c32c1616cf01b5b0b4901c5c896901aa5822f16e0d8e93c9168375e62ca529a1732ef82391a09d75c547180004fa200564b4a9e094dd976eace41e6f574a39c70530c8231c898b41ea8f721655529b162793a4f6e300262bceb9c43324bc80d814c8cad726ee023ebf282517f02f32c8289edc49511ae1858b7ef84abb214ba4c3e3ba79cc482228267324c9a052b2d503406737b58aa8724b4b90761c883b89591b31a83af023b580f75466cfc349e929a820e24229c599c829ded27302d5040a365e15985fbe35eca6a22204843b7ae9971eb3b431a715f4b8f13cf610dc5443258692277c082d5528917cd7c2225edc2958a442eb0ac94f803e53ecdec10595411ffd0939e066b66d34b2893efd03924eca4de8e1df2b586f7488588e7cde4f748033a2694fea20ed04d292a8b4e6b0edd3aabe03951a22104a0b0c2566b6b895ce710895983dd98949f890881f96dba48f1ed934e63ac7ea2296183913c9d911499df76cf218d731bdb530e16ed5fedc8fc7f3a1a75c47a39aac3a3bdcc5d14a2e2679fa63142f3da2aa2338817870ce50adfea935b9a455a7b5d94ca34165e2a72f58a3d42c62e3b46483ea64e2b9071aafb555f8800bc24cfc5e4b986a3b787e57287e4e59959c2fdd1811a8eb0413b60fe1d912d557125ce67a978eaa1ae2434923947f61310989f1f8bc94aae4448bbbf7272e3f256e7fd8fc65431bd70731c5a8a0368aa57332b2f879c7f227b2919f97492f999d2710464a2db5244cce58fb6ac499410178073052b7ba596a71afaaf0d1909a2c21150f7c274be256bab3ade5c3cb05eda2cd9f5072d0c0ee7948c9d17dfe8ad36b34d42435e081e03981fdc1fc4ce29d705e09725212cf2ad30b764dd982fd34d433cb622076bcbe52a5c133ff443867a3a2fe82e5bbb6b3a68777091b3376e8749228602abb599a230df5e0989c377981dbb1614292354322b0fe185178add5a62b84134ad0f009fab6d435b868128c5d0402e5e8e27dddf6e720e9b422005d962dd36951f29eb987b1314e0244cf6ecb48abfd6e690378768215adfa5414e10c99787c04daf0fb683f823009594148391b63f4c67f38d269f14dabd278bec22a024ca3964b6ef5d81b51eb029d8ffcf5f954f47e25eab680aac43e2d10f5db67706bcb6b056a95cf629d17306c4a866beae02d90d01214308ca8fd28e4d44f6e379893846a214f0fde2822896550da03fa1269073a0cfbba498c3f2983cebaab9e20d4b23d505078d306fc458eed3bacea0cf7024e49f0e892a37526076c0b3a1e348d8e05a3eb047c4b572a7d2e423382f09d7331f60ddfaf9292c564b9aaccc469ce3afa3d392382437e40f143a23803607498fcf4ee0d2ce630b19d4ebf15a7a594f45048f5274816cbeba0aba043429c155a9bc254f08bac7547a8c4cfa013b369301df73972649c68c2328bc4e72e77a326aef8e6a69ce74f8855a49f47571309220e73b81d5c44987671851745987ff08fc0ea4bbdb81047aa6a2da8cd07315b49f3699d35669546495f3b2cbdf79a7b28003cbc206121ffe29e92a8e6bb992602b586aaaafdae64fdd8c183b4759a58d4a4672c6268e2d72e4964c2ddc1432fe12f4895bba04e36806487e61edfb8a97d4a10edb253622fbf973ffe86917a181dac9d73a863e711cb98482b50f5996f758e4e308e9abc990d31bbe47eeef37814b2f22a062b0f0c1c05aeae7b93f271db21af9dae3877a1a7e1d45711d825fb8b913e7ecb3177b816ba701fdc8235f978fadd1424269ecb45b0f8bcb7eddcf6cc42ce9f61c687f86986ddc343271968cd317a39f4e6361cc10afbec1ae21cd50fd750133c28a9830389c5da090ce8dc9a00bc85c80080914ee0a1713186aeb3e2280a56c2d32d198919a546d972c2ff1d74fe60e04f852d10066bb63c1381f71784907de66fe37c40411c350e24fb2551c5a2e1dafc0fd81e360b50fcc74b1134e1f5f2a938daa8edb0a0bbd142bbdf9a1f56bba8162385333754d645c0df20fde083ac91ea5583126b8bb39811863b34a32ef2a8f14298a91beecba28d28c377f35b1164544685deac936f413ea2ff9af459102b6fe4dc82c4c39d78a9f45782e8983cf6ac7d0ba7590ad84bc744b05d60132a25a4908a1097d992505f0740a4ba25ee446759e59bbb5dc5aa4bd4d962dc39c3d6070969ea98954eade9ce6347babfdb2cc4ef5d6b865a21571bc95ec7a124ff6637adf5d972b2c387434cc8a30ed1d06266a63b00adb108c49e4f15769057246978bbec8ba3b0ffedb31ec4b6b10eea7997ead82044869e9daf4a49ee622c69e727d42b4f50a8d45d7585145a6555aef25f041b5ba902009495d5f1fd9ab73aace59cecb0f8aff17cec0f0ea0a661718db36a6ca9318dc6a36ea364d7c7694a211c2517fb77a56662c6d3509d12685892be99dbf4213d89051b16800ba2d77d9ca35ef2fd69083ec50fd67509e495b36c47fc290acb486b402ffe38ccbee1304bf41c4651aceff14ebd27945d217b08d122843221370aad45e813a11284c80c8103839d066a2502e7ddcfba03661df67fedb6ec95052bd6110658d838d00d1feef8c5e35fe90b29f64b095e921f90b735ca773009802b09a98385cf1f36d7a982f278ef2e2ac5632f66f8724425e35da70c8eaea5702ceaf8c5bea8f2d6a387d54b41e951bd3c195ab704ce8b32061dc74fe038f16f7b52c7e77534a50aa6e96b2a18a0f3bc7e5f58c9c1453633923b30949d9fb76426464399c16339431a34f6ba1a2e051be4b8a9c9a510a4500eb780a0fd53b832b852f212c5a4202ed285d58793c140854a701826a0946d360b8c4027ad1ea5f098d18a8158cf3238c95eb3fdd9fdaf268a833c99e4aa874df4637b71930715a5d907fc60550b2500f9d9130e4573ad0d74c03cb728c1127652ccc04f620388e5b4faef09620a8191264ae54ce118d7b55d8411f512952215c1834cc85be92078aa6af80ddeca1365cc4935ea8169707b0923c2fc3d7994b374059724336b68fceae3077d31177461b80f03f5bc859dc016033b8b8acd8fc9c8366b9d809cf5c027fcf55df4d55c480e0b0f4708c56ff81d61665c419c67e6f68e6cc009298a7c01163a75e2651f1bfc738f49a38d9d0cd2143166116234e6b95fc64d2763ec27dd9dcff4a7cf6ca7c69444b5eacaa8184d5b831cb51d66ceb4eb5487ff48c63b214773bc73910dc21778a655423b902a4e6a06a3cbbaebbf9cd5c64c56498bf0e7e4bb6d037c2a23d3aac0158d1e6b935e5e6d093964d2326229cbed1423d0c3895aa397185c0af1084ef20aafcb8a14156456873e95e9cd473bea75d7ead48bdc22737206de55c21cb810d56867a3c5613e6665997565b895b2b145011569e3bf54e83e467badd9495e8c76e2684a9a3550b80215ea17cd84af86bd9606c865aafc7ea78444c4fca11edb9317eebed2775f320d4425d494e59775c517e262563f53d7da8b4c4e72d79da700b763d64ccfd2c4e6596950465b0de69c794b2fbe49ec06cbfa96cbec4bb18c4485f0adf6e1a54262dac6e87591ebca7c53e058a16251fc2fdc20b3213783893599b4be1a8951a622f1555e6c9cfaeddcd5fddcf41ddedbdddb5a25768386a5e6117d93620a91285e8e98d4584d9e44e1feaaee09f022fa67b7063a717fd840d6047d71babbbf99317776825a63a562ebc0e0a222d2e19aa06b1ffc8f49541f872b5a42eaa3acbac9d7232e55aab8864d4bdacc0624b80b668a14d2a3035846ee2a8d4879b3c15a21351e935cfd739db6d9a43b5fc49be476c54b0833fba957e0c56ed93032edba7f91494989f6bc1da10889e8099268c7e9288ff2f03b336635a2f6bb6519d887d14f4530975fda8f5f5960008bcd9179115cfb5750ebf9e95ac76f786496178c87f01367e836950c9f2a53df2984c13d0cff610faf6345cebf43da94547984ef988cc0a7ccbbf1bcce22969525218a53cd08bf5cec0b74effa801752e303f5ee68cbff6a2bb1c4b98592fdf0af5e9d2012f84a96dde7505fe3c55dfe655959c6f5b0a050bba29e43e3442a76dd22640b2a0d88aa4b3873039b029fc1e1148411d2137878bf8604", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x1002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d6318141ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9657ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x1002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d6318141ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9657ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0x5e8a19e3cd1b7c148b33880c479c02814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x682a59d51ab9e48a8c8cc418ff9708d24e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x7c215a8bceb5e4dcd92f78e36a5fd0ff4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x000064a7b3b6e00d0000000000000000", + "0xcd5c1f6df63bc97f4a8ce37f14a50ca74e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb363fc5191ef4dec4f7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66": "0x7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3c21badc8f9053b1f1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965": "0x1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3ca2c608870c60a0ccaa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814": "0xcaa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d823137badc90c9202d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534": "0x02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950039f7057bdcc4bc16175726180caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814": "0xcaa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19503b5fa0e23c4a4cae617572618002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534": "0x02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19508d1b0ce8b7d45af961757261807ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66": "0x7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950e6240f6cb493659d61757261801ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965": "0x1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x1002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d6318141ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9657ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x1002d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce53402d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d6318141ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9651ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f9657ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b667ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x03000000", + "0xe8d49389c2e23e152fdd6364daadd2cc4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json deleted file mode 100644 index 064a2dfc0db..00000000000 --- a/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "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-rococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json new file mode 120000 index 00000000000..fca916ab550 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/asset-hub-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json deleted file mode 100644 index b364139b87e..00000000000 --- a/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "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/chain-specs/asset-hub-wococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json new file mode 120000 index 00000000000..30a63a9fc78 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/asset-hub-wococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 8c8091aaec3..636488cbfe2 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -796,39 +796,107 @@ fn asset_hub_rococo_like_local_config( ) } -pub fn asset_hub_rococo_config() -> AssetHubRococoChainSpec { +pub fn asset_hub_rococo_genesis_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) + let para_id = 1000; + AssetHubRococoChainSpec::from_genesis( + // Name + "Rococo Asset Hub", + // ID + "asset-hub-rococo", + ChainType::Live, + move || { + asset_hub_rococo_genesis( + // initial collators. + vec![ + // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG + ( + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") + .into(), + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") + .unchecked_into(), + ), + // G28iWEybndgGRbhfx83t7Q42YhMPByHpyqWDUgeyoGF94ri + ( + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") + .into(), + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") + .unchecked_into(), + ), + // G839e2eMiq7UXbConsY6DS1XDAYG2XnQxAmLuRLGGQ3Px9c + ( + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") + .into(), + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") + .unchecked_into(), + ), + // GLao4ukFUW6qhexuZowdFrKa2NLCfnEjZMftSXXfvGv1vvt + ( + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") + .into(), + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") + .unchecked_into(), + ), + ], + Vec::new(), + para_id.into(), + ) + }, + Vec::new(), + None, + None, + None, + Some(properties), + Extensions { relay_chain: "rococo".into(), para_id }, + ) } -pub fn asset_hub_wococo_config() -> AssetHubWococoChainSpec { +pub fn asset_hub_wococo_genesis_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( + let para_id = 1000; + AssetHubWococoChainSpec::from_genesis( // Name - name, + "Wococo Asset Hub", // ID - chain_id, + "asset-hub-wococo", ChainType::Live, move || { asset_hub_rococo_genesis( // initial collators. vec![ - // TODO: add invulnerables? from Rockmine? + // 5C8RGkS8t5K93fB2hkgKbvSYs5iG6AknJMuQmbBDeazon9Lj + ( + hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") + .into(), + hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") + .unchecked_into(), + ), + // 5GePeDZQeBagXH7kH5QPKnQKi39Z5hoYFB5FmUtEvc4yxKej + ( + hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") + .into(), + hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") + .unchecked_into(), + ), + // 5CfnTTb9NMJDNKDntA83mHKoedZ7wjDC8ypLCTDd4NwUx3zv + ( + hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") + .into(), + hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") + .unchecked_into(), + ), + // 5EqheiwiG22gvGpN7cvrbeaQzhg7rzsYYVkYK4yj5vRrTQRQ + ( + hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") + .into(), + hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") + .unchecked_into(), + ), ], Vec::new(), para_id.into(), @@ -839,7 +907,7 @@ fn asset_hub_rococo_like_config( None, None, Some(properties), - Extensions { relay_chain: "rococo".into(), para_id }, + Extensions { relay_chain: "wococo".into(), para_id }, ) } diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 52aa1c8bd57..870e45e1d55 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -176,8 +176,8 @@ fn load_spec(id: &str) -> std::result::Result, String> { "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-genesis" => + Box::new(chain_spec::asset_hubs::asset_hub_rococo_genesis_config()), "asset-hub-rococo" => Box::new(chain_spec::asset_hubs::AssetHubRococoChainSpec::from_json_bytes( &include_bytes!("../chain-specs/asset-hub-rococo.json")[..], @@ -189,7 +189,8 @@ fn load_spec(id: &str) -> std::result::Result, String> { "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-genesis" => + Box::new(chain_spec::asset_hubs::asset_hub_wococo_genesis_config()), "asset-hub-wococo" => Box::new(chain_spec::asset_hubs::AssetHubWococoChainSpec::from_json_bytes( &include_bytes!("../chain-specs/asset-hub-wococo.json")[..], diff --git a/cumulus/scripts/bridges_common.sh b/cumulus/scripts/bridges_common.sh new file mode 100755 index 00000000000..8d64c5ede52 --- /dev/null +++ b/cumulus/scripts/bridges_common.sh @@ -0,0 +1,305 @@ +#!/bin/bash + +function ensure_binaries() { + if [[ ! -f ~/local_bridge_testing/bin/polkadot ]]; then + echo " Required polkadot binary '~/local_bridge_testing/bin/polkadot' does not exist!" + echo " You need to build it and copy to this location!" + echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" + exit 1 + fi + if [[ ! -f ~/local_bridge_testing/bin/polkadot-parachain ]]; then + echo " Required polkadot-parachain binary '~/local_bridge_testing/bin/polkadot-parachain' does not exist!" + echo " You need to build it and copy to this location!" + echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" + exit 1 + fi +} + +function ensure_relayer() { + if [[ ! -f ~/local_bridge_testing/bin/substrate-relay ]]; then + echo " Required substrate-relay binary '~/local_bridge_testing/bin/substrate-relay' does not exist!" + echo " You need to build it and copy to this location!" + echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" + exit 1 + fi +} + +function ensure_polkadot_js_api() { + if ! which polkadot-js-api &> /dev/null; then + echo '' + echo 'Required command `polkadot-js-api` not in PATH, please, install, e.g.:' + echo "npm install -g @polkadot/api-cli@beta" + echo " or" + echo "yarn global add @polkadot/api-cli" + echo '' + exit 1 + fi + if ! which jq &> /dev/null; then + echo '' + echo 'Required command `jq` not in PATH, please, install, e.g.:' + echo "apt install -y jq" + echo '' + exit 1 + fi + generate_hex_encoded_call_data "check" "--" + local retVal=$? + if [ $retVal -ne 0 ]; then + echo "" + echo "" + echo "-------------------" + echo "Installing (nodejs) sub module: $(dirname "$0")/generate_hex_encoded_call" + pushd $(dirname "$0")/generate_hex_encoded_call + npm install + popd + fi +} + +function generate_hex_encoded_call_data() { + local type=$1 + local endpoint=$2 + local output=$3 + shift + shift + shift + echo "Input params: $@" + + node $(dirname "$0")/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" + local retVal=$? + + if [ $type != "check" ]; then + local hex_encoded_data=$(cat $output) + echo "Generated hex-encoded bytes to file '$output': $hex_encoded_data" + fi + + return $retVal +} + +function transfer_balance() { + local runtime_para_endpoint=$1 + local seed=$2 + local target_account=$3 + local amount=$4 + echo " calling transfer_balance:" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" + echo " seed: ${seed}" + echo " target_account: ${target_account}" + echo " amount: ${amount}" + echo "--------------------------------------------------" + + polkadot-js-api \ + --ws "${runtime_para_endpoint}" \ + --seed "${seed?}" \ + tx.balances.transferAllowDeath \ + "${target_account}" \ + "${amount}" +} + +function send_governance_transact() { + local relay_url=$1 + local relay_chain_seed=$2 + local para_id=$3 + local hex_encoded_data=$4 + local require_weight_at_most_ref_time=$5 + local require_weight_at_most_proof_size=$6 + echo " calling send_governance_transact:" + echo " relay_url: ${relay_url}" + echo " relay_chain_seed: ${relay_chain_seed}" + echo " para_id: ${para_id}" + echo " hex_encoded_data: ${hex_encoded_data}" + echo " require_weight_at_most_ref_time: ${require_weight_at_most_ref_time}" + echo " require_weight_at_most_proof_size: ${require_weight_at_most_proof_size}" + echo " params:" + + local dest=$(jq --null-input \ + --arg para_id "$para_id" \ + '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $para_id } } } }') + + local message=$(jq --null-input \ + --argjson hex_encoded_data $hex_encoded_data \ + --arg require_weight_at_most_ref_time "$require_weight_at_most_ref_time" \ + --arg require_weight_at_most_proof_size "$require_weight_at_most_proof_size" \ + ' + { + "V3": [ + { + "UnpaidExecution": { + "weight_limit": "Unlimited" + } + }, + { + "Transact": { + "origin_kind": "Superuser", + "require_weight_at_most": { + "ref_time": $require_weight_at_most_ref_time, + "proof_size": $require_weight_at_most_proof_size, + }, + "call": { + "encoded": $hex_encoded_data + } + } + } + ] + } + ') + + echo "" + echo " dest:" + echo "${dest}" + echo "" + echo " message:" + echo "${message}" + echo "" + echo "--------------------------------------------------" + + polkadot-js-api \ + --ws "${relay_url?}" \ + --seed "${relay_chain_seed?}" \ + --sudo \ + tx.xcmPallet.send \ + "${dest}" \ + "${message}" +} + +function open_hrmp_channels() { + local relay_url=$1 + local relay_chain_seed=$2 + 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 " 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:" + 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 set_storage() { + local relay_url=$1 + local relay_chain_seed=$2 + local runtime_para_id=$3 + local runtime_para_endpoint=$4 + 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 " items: ${items}" + echo " params:" + + # 1. generate data for Transact (System::set_storage) + local tmp_output_file=$(mktemp) + 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 force_create_foreign_asset() { + local relay_url=$1 + local relay_chain_seed=$2 + local runtime_para_id=$3 + local runtime_para_endpoint=$4 + 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 " 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 "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 +} + +function limited_reserve_transfer_assets() { + local url=$1 + local seed=$2 + 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 " 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.polkadotXcm.limitedReserveTransferAssets \ + "${destination}" \ + "${beneficiary}" \ + "${assets}" \ + "${fee_asset_item}" \ + "${weight_limit}" +} + +function claim_rewards() { + local runtime_para_endpoint=$1 + local seed=$2 + 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 " 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 "${runtime_para_endpoint}" \ + --seed "${seed?}" \ + tx.bridgeRelayers.claimRewards \ + "${rewards_account_params}" +} \ No newline at end of file diff --git a/cumulus/scripts/bridges_rococo_wococo.sh b/cumulus/scripts/bridges_rococo_wococo.sh index 4bfe9b32a83..4211a37226d 100755 --- a/cumulus/scripts/bridges_rococo_wococo.sh +++ b/cumulus/scripts/bridges_rococo_wococo.sh @@ -1,5 +1,8 @@ #!/bin/bash +# import common functions +source "$(dirname "$0")"/bridges_common.sh + # Expected sovereign accounts. # # Generated by: @@ -125,310 +128,6 @@ ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_BridgedChain="5EHn LANE_ID="00000001" -function ensure_binaries() { - if [[ ! -f ~/local_bridge_testing/bin/polkadot ]]; then - echo " Required polkadot binary '~/local_bridge_testing/bin/polkadot' does not exist!" - echo " You need to build it and copy to this location!" - echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" - exit 1 - fi - if [[ ! -f ~/local_bridge_testing/bin/polkadot-parachain ]]; then - echo " Required polkadot-parachain binary '~/local_bridge_testing/bin/polkadot-parachain' does not exist!" - echo " You need to build it and copy to this location!" - echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" - exit 1 - fi -} - -function ensure_relayer() { - if [[ ! -f ~/local_bridge_testing/bin/substrate-relay ]]; then - echo " Required substrate-relay binary '~/local_bridge_testing/bin/substrate-relay' does not exist!" - echo " You need to build it and copy to this location!" - echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" - exit 1 - fi -} - -function ensure_polkadot_js_api() { - if ! which polkadot-js-api &> /dev/null; then - echo '' - echo 'Required command `polkadot-js-api` not in PATH, please, install, e.g.:' - echo "npm install -g @polkadot/api-cli@beta" - echo " or" - echo "yarn global add @polkadot/api-cli" - echo '' - exit 1 - fi - if ! which jq &> /dev/null; then - echo '' - echo 'Required command `jq` not in PATH, please, install, e.g.:' - echo "apt install -y jq" - echo '' - exit 1 - fi - generate_hex_encoded_call_data "check" "--" - local retVal=$? - if [ $retVal -ne 0 ]; then - echo "" - echo "" - echo "-------------------" - echo "Installing (nodejs) sub module: $(dirname "$0")/generate_hex_encoded_call" - pushd $(dirname "$0")/generate_hex_encoded_call - npm install - popd - fi -} - -function generate_hex_encoded_call_data() { - local type=$1 - local endpoint=$2 - local output=$3 - shift - shift - shift - echo "Input params: $@" - - node $(dirname "$0")/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" - local retVal=$? - - if [ $type != "check" ]; then - local hex_encoded_data=$(cat $output) - echo "Generated hex-encoded bytes to file '$output': $hex_encoded_data" - fi - - return $retVal -} - -function transfer_balance() { - local runtime_para_endpoint=$1 - local seed=$2 - local target_account=$3 - local amount=$4 - echo " calling transfer_balance:" - echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " seed: ${seed}" - echo " target_account: ${target_account}" - echo " amount: ${amount}" - echo "--------------------------------------------------" - - polkadot-js-api \ - --ws "${runtime_para_endpoint}" \ - --seed "${seed?}" \ - tx.balances.transferAllowDeath \ - "${target_account}" \ - "${amount}" -} - -function send_governance_transact() { - local relay_url=$1 - local relay_chain_seed=$2 - local para_id=$3 - local hex_encoded_data=$4 - local require_weight_at_most_ref_time=$5 - local require_weight_at_most_proof_size=$6 - echo " calling send_governance_transact:" - echo " relay_url: ${relay_url}" - echo " relay_chain_seed: ${relay_chain_seed}" - echo " para_id: ${para_id}" - echo " hex_encoded_data: ${hex_encoded_data}" - echo " require_weight_at_most_ref_time: ${require_weight_at_most_ref_time}" - echo " require_weight_at_most_proof_size: ${require_weight_at_most_proof_size}" - echo " params:" - - local dest=$(jq --null-input \ - --arg para_id "$para_id" \ - '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $para_id } } } }') - - local message=$(jq --null-input \ - --argjson hex_encoded_data $hex_encoded_data \ - --arg require_weight_at_most_ref_time "$require_weight_at_most_ref_time" \ - --arg require_weight_at_most_proof_size "$require_weight_at_most_proof_size" \ - ' - { - "V3": [ - { - "UnpaidExecution": { - "weight_limit": "Unlimited" - } - }, - { - "Transact": { - "origin_kind": "Superuser", - "require_weight_at_most": { - "ref_time": $require_weight_at_most_ref_time, - "proof_size": $require_weight_at_most_proof_size, - }, - "call": { - "encoded": $hex_encoded_data - } - } - } - ] - } - ') - - echo "" - echo " dest:" - echo "${dest}" - echo "" - echo " message:" - echo "${message}" - echo "" - echo "--------------------------------------------------" - - polkadot-js-api \ - --ws "${relay_url?}" \ - --seed "${relay_chain_seed?}" \ - --sudo \ - tx.xcmPallet.send \ - "${dest}" \ - "${message}" -} - -function open_hrmp_channels() { - local relay_url=$1 - local relay_chain_seed=$2 - 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 " 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:" - 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 set_storage() { - local relay_url=$1 - local relay_chain_seed=$2 - local runtime_para_id=$3 - local runtime_para_endpoint=$4 - 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 " items: ${items}" - echo " params:" - - # 1. generate data for Transact (System::set_storage) - local tmp_output_file=$(mktemp) - 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 force_create_foreign_asset() { - local relay_url=$1 - local relay_chain_seed=$2 - local runtime_para_id=$3 - local runtime_para_endpoint=$4 - 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 " 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 "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 -} - -function limited_reserve_transfer_assets() { - local url=$1 - local seed=$2 - 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 " 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.polkadotXcm.limitedReserveTransferAssets \ - "${destination}" \ - "${beneficiary}" \ - "${assets}" \ - "${fee_asset_item}" \ - "${weight_limit}" -} - -function claim_rewards() { - local runtime_para_endpoint=$1 - local seed=$2 - 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 " 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 "${runtime_para_endpoint}" \ - --seed "${seed?}" \ - tx.bridgeRelayers.claimRewards \ - "${rewards_account_params}" -} - function init_ro_wo() { ensure_relayer -- GitLab From a46183c706e300b1993f28278a273153010d2b0c Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Sat, 21 Oct 2023 04:01:14 -0500 Subject: [PATCH 343/633] Vstaging statement distribution omnibus (#1436) in-progress PR adding new tests and solving bugs --------- Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Co-authored-by: eskimor Co-authored-by: eskimor Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- polkadot/node/core/backing/src/lib.rs | 8 +- .../core/prospective-parachains/src/lib.rs | 8 + .../src/collator_side/mod.rs | 95 ++++---- .../src/collator_side/validators_buffer.rs | 2 +- .../node/network/gossip-support/src/lib.rs | 44 +++- .../network/statement-distribution/src/lib.rs | 1 + .../src/v2/candidates.rs | 8 +- .../statement-distribution/src/v2/cluster.rs | 7 + .../statement-distribution/src/v2/grid.rs | 69 ++++++ .../statement-distribution/src/v2/mod.rs | 197 ++++++++++++----- .../statement-distribution/src/v2/requests.rs | 29 ++- .../src/v2/statement_store.rs | 92 +++++++- .../src/v2/tests/grid.rs | 19 +- .../src/v2/tests/requests.rs | 202 ++++++++++++++++++ 14 files changed, 654 insertions(+), 127 deletions(-) diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 97efb3ba808..27b5972d982 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -1574,7 +1574,7 @@ async fn post_import_statement_actions( ctx: &mut Context, rp_state: &mut PerRelayParentState, summary: Option<&TableSummary>, -) -> Result<(), Error> { +) { if let Some(attested) = summary.as_ref().and_then(|s| { rp_state.table.attested_candidate( &s.candidate, @@ -1630,8 +1630,6 @@ async fn post_import_statement_actions( } issue_new_misbehaviors(ctx, rp_state.parent, &mut rp_state.table); - - Ok(()) } /// Check if there have happened any new misbehaviors and issue necessary messages. @@ -1674,7 +1672,7 @@ async fn sign_import_and_distribute_statement( let smsg = StatementDistributionMessage::Share(rp_state.parent, signed_statement.clone()); ctx.send_unbounded_message(smsg); - post_import_statement_actions(ctx, rp_state, summary.as_ref()).await?; + post_import_statement_actions(ctx, rp_state, summary.as_ref()).await; Ok(Some(signed_statement)) } else { @@ -1800,7 +1798,7 @@ async fn maybe_validate_and_import( } let summary = res?; - post_import_statement_actions(ctx, rp_state, summary.as_ref()).await?; + post_import_statement_actions(ctx, rp_state, summary.as_ref()).await; if let Some(summary) = summary { // import_statement already takes care of communicating with the diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index fcca0dd0b53..dabcfb80e02 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -290,6 +290,14 @@ async fn handle_active_leaves_update( ) .expect("ancestors are provided in reverse order and correctly; qed"); + gum::debug!( + target: LOG_TARGET, + relay_parent = ?hash, + min_relay_parent = scope.earliest_relay_parent().number, + para_id = ?para, + "Creating fragment tree" + ); + let tree = FragmentTree::populate(scope, &*candidate_storage); fragment_trees.insert(para, tree); 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 304cabbaac8..e4b95f24d5a 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -93,13 +93,18 @@ const COST_APPARENT_FLOOD: Rep = /// For considerations on this value, see: https://github.com/paritytech/polkadot/issues/4386 const MAX_UNSHARED_UPLOAD_TIME: Duration = Duration::from_millis(150); -/// Ensure that collator issues a connection request at least once every this many seconds. -/// Usually it's done when advertising new collation. However, if the core stays occupied or -/// it's not our turn to produce a candidate, it's important to disconnect from previous -/// peers. +/// Ensure that collator updates its connection requests to validators +/// this long after the most recent leaf. +/// +/// The timeout is designed for substreams to be properly closed if they need to be +/// reopened shortly after the next leaf. +/// +/// Collators also update their connection requests on every new collation. +/// This timeout is mostly about removing stale connections while avoiding races +/// with new collations which may want to reactivate them. /// /// Validators are obtained from [`ValidatorGroupsBuffer::validators_to_connect`]. -const RECONNECT_TIMEOUT: Duration = Duration::from_secs(12); +const RECONNECT_AFTER_LEAF_TIMEOUT: Duration = Duration::from_secs(4); /// Future that when resolved indicates that we should update reserved peer-set /// of validators we want to be connected to. @@ -108,6 +113,13 @@ const RECONNECT_TIMEOUT: Duration = Duration::from_secs(12); /// connected. type ReconnectTimeout = Fuse; +#[derive(Debug)] +enum ShouldAdvertiseTo { + Yes, + NotAuthority, + AlreadyAdvertised, +} + /// Info about validators we are currently connected to. /// /// It keeps track to which validators we advertised our collation. @@ -129,10 +141,10 @@ impl ValidatorGroup { candidate_hash: &CandidateHash, peer_ids: &HashMap>, peer: &PeerId, - ) -> bool { + ) -> ShouldAdvertiseTo { let authority_ids = match peer_ids.get(peer) { Some(authority_ids) => authority_ids, - None => return false, + None => return ShouldAdvertiseTo::NotAuthority, }; for id in authority_ids { @@ -151,11 +163,13 @@ impl ValidatorGroup { .get(candidate_hash) .map_or(true, |advertised| !advertised[validator_index]) { - return true + return ShouldAdvertiseTo::Yes + } else { + return ShouldAdvertiseTo::AlreadyAdvertised } } - false + ShouldAdvertiseTo::NotAuthority } /// Should be called after we advertised our collation to the given `peer` to keep track of it. @@ -255,8 +269,8 @@ struct State { /// Tracks which validators we want to stay connected to. validator_groups_buf: ValidatorGroupsBuffer, - /// Timeout-future that enforces collator to update the peer-set at least once - /// every [`RECONNECT_TIMEOUT`] seconds. + /// Timeout-future which is reset after every leaf to [`RECONNECT_AFTER_LEAF_TIMEOUT`] seconds. + /// When it fires, we update our reserved peers. reconnect_timeout: ReconnectTimeout, /// Metrics. @@ -443,7 +457,7 @@ async fn distribute_collation( } // Update a set of connected validators if necessary. - state.reconnect_timeout = connect_to_validators(ctx, &state.validator_groups_buf).await; + connect_to_validators(ctx, &state.validator_groups_buf).await; if let Some(result_sender) = result_sender { state.collation_result_senders.insert(candidate_hash, result_sender); @@ -619,15 +633,12 @@ async fn declare( /// Updates a set of connected validators based on their advertisement-bits /// in a validators buffer. -/// -/// Should be called again once a returned future resolves. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn connect_to_validators( ctx: &mut Context, validator_groups_buf: &ValidatorGroupsBuffer, -) -> ReconnectTimeout { +) { let validator_ids = validator_groups_buf.validators_to_connect(); - let is_disconnect = validator_ids.is_empty(); // ignore address resolution failure // will reissue a new request on new collation @@ -638,14 +649,6 @@ async fn connect_to_validators( failed, }) .await; - - if is_disconnect { - gum::trace!(target: LOG_TARGET, "Disconnecting from all peers"); - // Never resolves. - Fuse::terminated() - } else { - futures_timer::Delay::new(RECONNECT_TIMEOUT).fuse() - } } /// Advertise collation to the given `peer`. @@ -685,22 +688,29 @@ async fn advertise_collation( .validator_group .should_advertise_to(candidate_hash, peer_ids, &peer); - if !should_advertise { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - peer_id = %peer, - "Not advertising collation since validator is not interested", - ); - continue + match should_advertise { + ShouldAdvertiseTo::Yes => {}, + ShouldAdvertiseTo::NotAuthority | ShouldAdvertiseTo::AlreadyAdvertised => { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?candidate_hash, + peer_id = %peer, + reason = ?should_advertise, + "Not advertising collation" + ); + continue + }, } gum::debug!( target: LOG_TARGET, ?relay_parent, + ?candidate_hash, peer_id = %peer, "Advertising collation.", ); + collation.status.advance_to_advertised(); let collation_message = match protocol_version { @@ -1149,7 +1159,7 @@ async fn handle_network_msg( PeerConnected(peer_id, observed_role, protocol_version, maybe_authority) => { // If it is possible that a disconnected validator would attempt a reconnect // it should be handled here. - gum::trace!(target: LOG_TARGET, ?peer_id, ?observed_role, "Peer connected"); + gum::trace!(target: LOG_TARGET, ?peer_id, ?observed_role, ?maybe_authority, "Peer connected"); let version = match protocol_version.try_into() { Ok(version) => version, @@ -1200,7 +1210,11 @@ async fn handle_network_msg( }, UpdatedAuthorityIds(peer_id, authority_ids) => { gum::trace!(target: LOG_TARGET, ?peer_id, ?authority_ids, "Updated authority ids"); - state.peer_ids.insert(peer_id, authority_ids); + if let Some(version) = state.peer_data.get(&peer_id).map(|d| d.version) { + if state.peer_ids.insert(peer_id, authority_ids).is_none() { + declare(ctx, state, &peer_id, version).await; + } + } }, NewGossipTopology { .. } => { // impossible! @@ -1369,7 +1383,11 @@ async fn run_inner( "Failed to process message" )?; }, - FromOrchestra::Signal(ActiveLeaves(_update)) => {} + FromOrchestra::Signal(ActiveLeaves(update)) => { + if update.activated.is_some() { + *reconnect_timeout = futures_timer::Delay::new(RECONNECT_AFTER_LEAF_TIMEOUT).fuse(); + } + } FromOrchestra::Signal(BlockFinalized(..)) => {} FromOrchestra::Signal(Conclude) => return Ok(()), }, @@ -1390,7 +1408,7 @@ async fn run_inner( // The request it still alive, it should be kept in a waiting queue. } else { for authority_id in state.peer_ids.get(&peer_id).into_iter().flatten() { - // Timeout not hit, this peer is no longer interested in this relay parent. + // This peer has received the candidate. Not interested anymore. state.validator_groups_buf.reset_validator_interest(candidate_hash, authority_id); } waiting.waiting_peers.remove(&(peer_id, candidate_hash)); @@ -1446,12 +1464,11 @@ async fn run_inner( } } _ = reconnect_timeout => { - state.reconnect_timeout = - connect_to_validators(&mut ctx, &state.validator_groups_buf).await; + connect_to_validators(&mut ctx, &state.validator_groups_buf).await; gum::trace!( target: LOG_TARGET, - timeout = ?RECONNECT_TIMEOUT, + timeout = ?RECONNECT_AFTER_LEAF_TIMEOUT, "Peer-set updated due to a timeout" ); }, diff --git a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs index cfa76270384..5b88efc99d8 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -133,7 +133,7 @@ impl ValidatorGroupsBuffer { } } - /// Note that a validator is no longer interested in a given relay parent. + /// Note that a validator is no longer interested in a given candidate. pub fn reset_validator_interest( &mut self, candidate_hash: CandidateHash, diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 4fa23507e86..2b2b2d0933e 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -104,7 +104,7 @@ pub struct GossipSupport { /// By `PeerId`. /// /// Needed for efficient handling of disconnect events. - connected_authorities_by_peer_id: HashMap>, + connected_peers: HashMap>, /// Authority discovery service. authority_discovery: AD, @@ -130,7 +130,7 @@ where failure_start: None, resolved_authorities: HashMap::new(), connected_authorities: HashMap::new(), - connected_authorities_by_peer_id: HashMap::new(), + connected_peers: HashMap::new(), authority_discovery, metrics, } @@ -407,19 +407,42 @@ where } } - for (peer_id, auths) in authority_ids { - if self.connected_authorities_by_peer_id.get(&peer_id) != Some(&auths) { + // peer was authority and now isn't + for (peer_id, current) in self.connected_peers.iter_mut() { + // empty -> nonempty is handled in the next loop + if !current.is_empty() && !authority_ids.contains_key(peer_id) { + sender + .send_message(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id: *peer_id, + authority_ids: HashSet::new(), + }) + .await; + + for a in current.drain() { + self.connected_authorities.remove(&a); + } + } + } + + // peer has new authority set. + for (peer_id, new) in authority_ids { + // If the peer is connected _and_ the authority IDs have changed. + if let Some(prev) = self.connected_peers.get(&peer_id).filter(|x| x != &&new) { sender .send_message(NetworkBridgeRxMessage::UpdatedAuthorityIds { peer_id, - authority_ids: auths.clone(), + authority_ids: new.clone(), }) .await; - auths.iter().for_each(|a| { + prev.iter().for_each(|a| { + self.connected_authorities.remove(a); + }); + new.iter().for_each(|a| { self.connected_authorities.insert(a.clone(), peer_id); }); - self.connected_authorities_by_peer_id.insert(peer_id, auths); + + self.connected_peers.insert(peer_id, new); } } } @@ -431,12 +454,13 @@ where authority_ids.iter().for_each(|a| { self.connected_authorities.insert(a.clone(), peer_id); }); - self.connected_authorities_by_peer_id.insert(peer_id, authority_ids); + self.connected_peers.insert(peer_id, authority_ids); + } else { + self.connected_peers.insert(peer_id, HashSet::new()); } }, NetworkBridgeEvent::PeerDisconnected(peer_id) => { - if let Some(authority_ids) = self.connected_authorities_by_peer_id.remove(&peer_id) - { + if let Some(authority_ids) = self.connected_peers.remove(&peer_id) { authority_ids.into_iter().for_each(|a| { self.connected_authorities.remove(&a); }); diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index eead7df5224..259c8f6a360 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -320,6 +320,7 @@ impl StatementDistributionSubsystem { let mode = prospective_parachains_mode(ctx.sender(), activated.hash).await?; if let ProspectiveParachainsMode::Enabled { .. } = mode { v2::handle_active_leaves_update(ctx, state, activated, mode).await?; + v2::handle_deactivate_leaves(state, &deactivated); } else if let ProspectiveParachainsMode::Disabled = mode { for deactivated in &deactivated { crate::legacy_v1::handle_deactivate_leaf(legacy_v1_state, *deactivated); diff --git a/polkadot/node/network/statement-distribution/src/v2/candidates.rs b/polkadot/node/network/statement-distribution/src/v2/candidates.rs index e660df5da17..ad56ad4a236 100644 --- a/polkadot/node/network/statement-distribution/src/v2/candidates.rs +++ b/polkadot/node/network/statement-distribution/src/v2/candidates.rs @@ -353,7 +353,13 @@ impl Candidates { ); c.has_claims() }, - }) + }); + + gum::trace!( + target: crate::LOG_TARGET, + "Candidates remaining after cleanup: {}", + self.candidates.len(), + ); } } diff --git a/polkadot/node/network/statement-distribution/src/v2/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/cluster.rs index 8adb8353ca9..619114de967 100644 --- a/polkadot/node/network/statement-distribution/src/v2/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/cluster.rs @@ -331,6 +331,13 @@ impl ClusterTracker { self.validator_seconded(validator, candidate_hash) } + /// Whether a validator can request a candidate from us. + pub fn can_request(&self, target: ValidatorIndex, candidate_hash: CandidateHash) -> bool { + self.validators.contains(&target) && + self.we_sent_seconded(target, candidate_hash) && + !self.they_sent_seconded(target, candidate_hash) + } + /// Returns a Vec of pending statements to be sent to a particular validator /// index. `Seconded` statements are sorted to the front of the vector. /// diff --git a/polkadot/node/network/statement-distribution/src/v2/grid.rs b/polkadot/node/network/statement-distribution/src/v2/grid.rs index 3d53ff6d321..19bad34c44f 100644 --- a/polkadot/node/network/statement-distribution/src/v2/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/grid.rs @@ -2245,4 +2245,73 @@ mod tests { ); assert_eq!(tracker.all_pending_statements_for(counterparty), vec![]); } + + #[test] + fn session_grid_topology_consistent() { + let n_validators = 300; + let group_size = 5; + + let validator_indices = + (0..n_validators).map(|i| ValidatorIndex(i as u32)).collect::>(); + let groups = validator_indices.chunks(group_size).map(|x| x.to_vec()).collect::>(); + + let topology = SessionGridTopology::new( + (0..n_validators).collect::>(), + (0..n_validators) + .map(|i| TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(i as u32), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }) + .collect(), + ); + + let computed_topologies = validator_indices + .iter() + .cloned() + .map(|v| build_session_topology(groups.iter(), &topology, Some(v))) + .collect::>(); + + let pairwise_check_topologies = |i, j| { + let v_i = ValidatorIndex(i); + let v_j = ValidatorIndex(j); + + for group in (0..groups.len()).map(|i| GroupIndex(i as u32)) { + let g_i = computed_topologies[i as usize].group_views.get(&group).unwrap(); + let g_j = computed_topologies[j as usize].group_views.get(&group).unwrap(); + + if g_i.sending.contains(&v_j) { + assert!( + g_j.receiving.contains(&v_i), + "{:?}: {:?}, sending but not receiving", + group, + &(i, j) + ); + } + + if g_j.sending.contains(&v_i) { + assert!( + g_i.receiving.contains(&v_j), + "{:?}: {:?}, sending but not receiving", + group, + &(j, i) + ); + } + + if g_i.receiving.contains(&v_j) { + assert!(g_j.sending.contains(&v_i), "{:?}, receiving but not sending", &(i, j)); + } + + if g_j.receiving.contains(&v_i) { + assert!(g_i.sending.contains(&v_j), "{:?}, receiving but not sending", &(j, i)); + } + } + }; + + for i in 0..n_validators { + for j in (i + 1)..n_validators { + pairwise_check_topologies(i as u32, j as u32); + } + } + } } diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index e11d66c41a0..95104732df0 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -100,6 +100,8 @@ const COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE: Rep = Rep::CostMinor("Unexpected Manifest, missing knowlege for relay parent"); const COST_UNEXPECTED_MANIFEST_DISALLOWED: Rep = Rep::CostMinor("Unexpected Manifest, Peer Disallowed"); +const COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN: Rep = + Rep::CostMinor("Unexpected Manifest, Peer Unknown"); const COST_CONFLICTING_MANIFEST: Rep = Rep::CostMajor("Manifest conflicts with previous"); const COST_INSUFFICIENT_MANIFEST: Rep = Rep::CostMajor("Manifest statements insufficient to back candidate"); @@ -185,11 +187,18 @@ impl PerSessionState { } } - fn supply_topology(&mut self, topology: &SessionGridTopology) { + fn supply_topology( + &mut self, + topology: &SessionGridTopology, + local_index: Option, + ) { + // Note: we use the local index rather than the `self.local_validator` as the + // former may be `Some` when the latter is `None`, due to the set of nodes in + // discovery being a superset of the active validators for consensus. let grid_view = grid::build_session_topology( self.session_info.validator_groups.iter(), topology, - self.local_validator, + local_index, ); self.grid_view = Some(grid_view); @@ -334,7 +343,7 @@ pub(crate) async fn handle_network_update( true }, Entry::Occupied(e) => { - gum::trace!( + gum::debug!( target: LOG_TARGET, authority_id = ?a, existing_peer = ?e.get(), @@ -366,9 +375,10 @@ pub(crate) async fn handle_network_update( NetworkBridgeEvent::NewGossipTopology(topology) => { let new_session_index = topology.session; let new_topology = topology.topology; + let local_index = topology.local_index; if let Some(per_session) = state.per_session.get_mut(&new_session_index) { - per_session.supply_topology(&new_topology); + per_session.supply_topology(&new_topology, local_index); } // TODO [https://github.com/paritytech/polkadot/issues/6194] @@ -409,6 +419,12 @@ pub(crate) async fn handle_network_update( "Updated `AuthorityDiscoveryId`s" ); + // defensive: ensure peers are actually connected + let peer_state = match state.peers.get_mut(&peer_id) { + None => return, + Some(p) => p, + }; + // Remove the authority IDs which were previously mapped to the peer // but aren't part of the new set. state.authorities.retain(|a, p| p != &peer_id || authority_ids.contains(a)); @@ -418,9 +434,7 @@ pub(crate) async fn handle_network_update( state.authorities.insert(a, peer_id); } - if let Some(peer_state) = state.peers.get_mut(&peer_id) { - peer_state.discovery_ids = Some(authority_ids); - } + peer_state.discovery_ids = Some(authority_ids); }, } } @@ -542,6 +556,13 @@ pub(crate) async fn handle_active_leaves_update( ); } + gum::debug!( + target: LOG_TARGET, + "Activated leaves. Now tracking {} relay-parents across {} sessions", + state.per_relay_parent.len(), + state.per_session.len(), + ); + // Reconcile all peers' views with the active leaf and any relay parents // it implies. If they learned about the block before we did, this reconciliation will give // non-empty results and we should send them messages concerning all activated relay-parents. @@ -599,25 +620,18 @@ fn find_local_validator_state( pub(crate) fn handle_deactivate_leaves(state: &mut State, leaves: &[Hash]) { // deactivate the leaf in the implicit view. for leaf in leaves { - state.implicit_view.deactivate_leaf(*leaf); - } - - let relay_parents = state.implicit_view.all_allowed_relay_parents().collect::>(); - - // fast exit for no-op. - if relay_parents.len() == state.per_relay_parent.len() { - return - } - - // clean up per-relay-parent data based on everything removed. - state.per_relay_parent.retain(|r, _| relay_parents.contains(r)); - - // Clean up all requests - for leaf in leaves { - state.request_manager.remove_by_relay_parent(*leaf); + let pruned = state.implicit_view.deactivate_leaf(*leaf); + for pruned_rp in pruned { + // clean up per-relay-parent data based on everything removed. + state.per_relay_parent.remove(&pruned_rp); + // clean up requests related to this relay parent. + state.request_manager.remove_by_relay_parent(*leaf); + } } - state.candidates.on_deactivate_leaves(&leaves, |h| relay_parents.contains(h)); + state + .candidates + .on_deactivate_leaves(&leaves, |h| state.per_relay_parent.contains_key(h)); // clean up sessions based on everything remaining. let sessions: HashSet<_> = state.per_relay_parent.values().map(|r| r.session).collect(); @@ -1734,6 +1748,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, + local_validator = ?local_validator.index, n_peers = manifest_peers.len(), "Sending manifest to peers" ); @@ -1749,6 +1764,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, + local_validator = ?local_validator.index, n_peers = ack_peers.len(), "Sending acknowledgement to peers" ); @@ -1974,8 +1990,13 @@ async fn handle_incoming_manifest_common<'a, Context>( let sender_index = match sender_index { None => { - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_MANIFEST_DISALLOWED) - .await; + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN, + ) + .await; return None }, Some(s) => s, @@ -2029,6 +2050,17 @@ async fn handle_incoming_manifest_common<'a, Context>( return None } + if acknowledge { + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + from = ?sender_index, + local_index = ?local_validator.index, + ?manifest_kind, + "immediate ack, known candidate" + ); + } + Some(ManifestImportSuccess { relay_parent_state, per_session, acknowledge, sender_index }) } @@ -2558,6 +2590,13 @@ pub(crate) async fn handle_response( let &requests::CandidateIdentifier { relay_parent, candidate_hash, group_index } = response.candidate_identifier(); + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + peer = ?response.requested_peer(), + "Received response", + ); + let post_confirmation = { let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { None => return, @@ -2596,12 +2635,29 @@ pub(crate) async fn handle_response( let (candidate, pvd, statements) = match res.request_status { requests::CandidateRequestStatus::Outdated => return, - requests::CandidateRequestStatus::Incomplete => return, + requests::CandidateRequestStatus::Incomplete => { + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + "Response incomplete. Retrying" + ); + + return + }, requests::CandidateRequestStatus::Complete { candidate, persisted_validation_data, statements, - } => (candidate, persisted_validation_data, statements), + } => { + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + n_statements = statements.len(), + "Successfully received candidate" + ); + + (candidate, persisted_validation_data, statements) + }, }; for statement in statements { @@ -2673,6 +2729,13 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { let ResponderMessage { request, sent_feedback } = message; let AttestedCandidateRequest { candidate_hash, ref mask } = &request.payload; + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + peer = ?request.peer, + "Received request" + ); + // Signal to the responder that we started processing this request. let _ = sent_feedback.send(()); @@ -2681,12 +2744,12 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { Some(c) => c, }; - let relay_parent_state = match state.per_relay_parent.get(&confirmed.relay_parent()) { + let relay_parent_state = match state.per_relay_parent.get_mut(&confirmed.relay_parent()) { None => return, Some(s) => s, }; - let local_validator = match relay_parent_state.local_validator.as_ref() { + let local_validator = match relay_parent_state.local_validator.as_mut() { None => return, Some(s) => s, }; @@ -2718,28 +2781,39 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { return } - // check peer is allowed to request the candidate (i.e. we've sent them a manifest) - { - let mut can_request = false; - for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { + // check peer is allowed to request the candidate (i.e. they're in the cluster or we've sent + // them a manifest) + let (validator_id, is_cluster) = { + let mut validator_id = None; + let mut is_cluster = false; + for v in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { per_session.authority_lookup.get(a) }) { - if local_validator.grid_tracker.can_request(validator_id, *candidate_hash) { - can_request = true; + if local_validator.cluster_tracker.can_request(v, *candidate_hash) { + validator_id = Some(v); + is_cluster = true; + break + } + + if local_validator.grid_tracker.can_request(v, *candidate_hash) { + validator_id = Some(v); break } } - if !can_request { - let _ = request.send_outgoing_response(OutgoingResponse { - result: Err(()), - reputation_changes: vec![COST_UNEXPECTED_REQUEST], - sent_feedback: None, - }); + match validator_id { + Some(v) => (v, is_cluster), + None => { + let _ = request.send_outgoing_response(OutgoingResponse { + result: Err(()), + reputation_changes: vec![COST_UNEXPECTED_REQUEST], + sent_feedback: None, + }); - return + return + }, } - } + }; // Transform mask with 'OR' semantics into one with 'AND' semantics for the API used // below. @@ -2748,19 +2822,34 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { validated_in_group: !mask.validated_in_group.clone(), }; + let statements: Vec<_> = relay_parent_state + .statement_store + .group_statements(&per_session.groups, confirmed.group_index(), *candidate_hash, &and_mask) + .map(|s| s.as_unchecked().clone()) + .collect(); + + // Update bookkeeping about which statements peers have received. + for statement in &statements { + if is_cluster { + local_validator.cluster_tracker.note_sent( + validator_id, + statement.unchecked_validator_index(), + statement.unchecked_payload().clone(), + ); + } else { + local_validator.grid_tracker.sent_or_received_direct_statement( + &per_session.groups, + statement.unchecked_validator_index(), + validator_id, + statement.unchecked_payload(), + ); + } + } + let response = AttestedCandidateResponse { candidate_receipt: (&**confirmed.candidate_receipt()).clone(), persisted_validation_data: confirmed.persisted_validation_data().clone(), - statements: relay_parent_state - .statement_store - .group_statements( - &per_session.groups, - confirmed.group_index(), - *candidate_hash, - &and_mask, - ) - .map(|s| s.as_unchecked().clone()) - .collect(), + statements, }; let _ = request.send_response(response); diff --git a/polkadot/node/network/statement-distribution/src/v2/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs index f13496024fc..8507a4b8276 100644 --- a/polkadot/node/network/statement-distribution/src/v2/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -265,6 +265,12 @@ impl RequestManager { HEntry::Vacant(_) => (), } } + + gum::debug!( + target: LOG_TARGET, + "Requests remaining after cleanup: {}", + self.by_priority.len(), + ); } /// Returns true if there are pending requests that are dispatchable. @@ -355,6 +361,13 @@ impl RequestManager { Some(t) => t, }; + gum::debug!( + target: crate::LOG_TARGET, + candidate_hash = ?id.candidate_hash, + peer = ?target, + "Issuing candidate request" + ); + let (request, response_fut) = OutgoingRequest::new( RequestRecipient::Peer(target), AttestedCandidateRequest { @@ -498,6 +511,11 @@ impl UnhandledResponse { &self.response.identifier } + /// Get the peer we made the request to. + pub fn requested_peer(&self) -> &PeerId { + &self.response.requested_peer + } + /// Validate the response. If the response is valid, this will yield the /// candidate, the [`PersistedValidationData`] of the candidate, and requested /// checked statements. @@ -582,12 +600,19 @@ impl UnhandledResponse { request_status: CandidateRequestStatus::Incomplete, } }, - Err(RequestError::NetworkError(_) | RequestError::Canceled(_)) => + Err(e @ RequestError::NetworkError(_) | e @ RequestError::Canceled(_)) => { + gum::trace!( + target: LOG_TARGET, + err = ?e, + peer = ?requested_peer, + "Request error" + ); return ResponseValidationOutput { requested_peer, reputation_changes: vec![], request_status: CandidateRequestStatus::Incomplete, - }, + } + }, Ok(response) => response, }; diff --git a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs index 74db431eda1..96d976e22cd 100644 --- a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs @@ -212,6 +212,7 @@ impl StatementStore { } /// Get an iterator over all statements marked as being unknown by the backing subsystem. + /// This provides `Seconded` statements prior to `Valid` statements. pub fn fresh_statements_for_backing<'a>( &'a self, validators: &'a [ValidatorIndex], @@ -220,14 +221,15 @@ impl StatementStore { let s_st = CompactStatement::Seconded(candidate_hash); let v_st = CompactStatement::Valid(candidate_hash); - validators - .iter() - .flat_map(move |v| { - let a = self.known_statements.get(&(*v, s_st.clone())); - let b = self.known_statements.get(&(*v, v_st.clone())); + let fresh_seconded = + validators.iter().map(move |v| self.known_statements.get(&(*v, s_st.clone()))); - a.into_iter().chain(b) - }) + let fresh_valid = + validators.iter().map(move |v| self.known_statements.get(&(*v, v_st.clone()))); + + fresh_seconded + .chain(fresh_valid) + .flatten() .filter(|stored| !stored.known_by_backing) .map(|stored| &stored.statement) } @@ -250,6 +252,7 @@ impl StatementStore { } /// Error indicating that the validator was unknown. +#[derive(Debug)] pub struct ValidatorUnknown; type Fingerprint = (ValidatorIndex, CompactStatement); @@ -281,3 +284,78 @@ impl GroupStatements { self.valid.set(within_group_index, true); } } + +#[cfg(test)] +mod tests { + use super::*; + + use polkadot_primitives::v6::{Hash, SigningContext, ValidatorPair}; + use sp_application_crypto::Pair as PairT; + + #[test] + fn always_provides_fresh_statements_in_order() { + let validator_a = ValidatorIndex(1); + let validator_b = ValidatorIndex(2); + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let valid_statement = CompactStatement::Valid(candidate_hash); + let seconded_statement = CompactStatement::Seconded(candidate_hash); + let signing_context = + SigningContext { parent_hash: Hash::repeat_byte(0), session_index: 1 }; + + let groups = Groups::new(vec![vec![validator_a, validator_b]].into(), 2); + + let mut store = StatementStore::new(&groups); + + // import a Valid statement from A and a Seconded statement from B. + let signed_valid_by_a = { + let payload = valid_statement.signing_payload(&signing_context); + let pair = ValidatorPair::generate().0; + let signature = pair.sign(&payload[..]); + + SignedStatement::new( + valid_statement.clone(), + validator_a, + signature, + &signing_context, + &pair.public(), + ) + .unwrap() + }; + store.insert(&groups, signed_valid_by_a, StatementOrigin::Remote).unwrap(); + + let signed_seconded_by_b = { + let payload = seconded_statement.signing_payload(&signing_context); + let pair = ValidatorPair::generate().0; + let signature = pair.sign(&payload[..]); + + SignedStatement::new( + seconded_statement.clone(), + validator_b, + signature, + &signing_context, + &pair.public(), + ) + .unwrap() + }; + store.insert(&groups, signed_seconded_by_b, StatementOrigin::Remote).unwrap(); + + // Regardless of the order statements are requested, + // we will get them in the order [B, A] because seconded statements must be first. + let vals = &[validator_a, validator_b]; + let statements = + store.fresh_statements_for_backing(vals, candidate_hash).collect::>(); + + assert_eq!(statements.len(), 2); + assert_eq!(statements[0].payload(), &seconded_statement); + assert_eq!(statements[1].payload(), &valid_statement); + + let vals = &[validator_b, validator_a]; + let statements = + store.fresh_statements_for_backing(vals, candidate_hash).collect::>(); + + assert_eq!(statements.len(), 2); + assert_eq!(statements[0].payload(), &seconded_statement); + assert_eq!(statements[1].payload(), &valid_statement); + } +} diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index a0af9579823..5b1dabfc8a0 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -1797,6 +1797,7 @@ fn grid_statements_imported_to_backing() { #[test] fn advertisements_rejected_from_incorrect_peers() { + sp_tracing::try_init_simple(); let validator_count = 6; let group_size = 3; let config = TestConfig { @@ -1831,12 +1832,12 @@ fn advertisements_rejected_from_incorrect_peers() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); - let target_group_validators = state.group_validators(other_group, true); - let v_a = other_group_validators[0]; - let v_b = other_group_validators[1]; - let v_c = target_group_validators[0]; - let v_d = target_group_validators[1]; + let target_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(other_group, true); + let v_a = target_group_validators[0]; + let v_b = target_group_validators[1]; + let v_c = other_group_validators[0]; + let v_d = other_group_validators[1]; // peer A is in group, has relay parent in view. // peer B is in group, has no relay parent in view. @@ -1911,10 +1912,11 @@ fn advertisements_rejected_from_incorrect_peers() { ) .await; + // Message not expected from peers of our own group. assert_matches!( overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) - if p == peer_a && r == COST_UNEXPECTED_MANIFEST_DISALLOWED.into() => { } + if p == peer_a && r == COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN.into() => { } ); } @@ -1927,10 +1929,11 @@ fn advertisements_rejected_from_incorrect_peers() { ) .await; + // Message not expected from peers of our own group. assert_matches!( overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) - if p == peer_b && r == COST_UNEXPECTED_MANIFEST_DISALLOWED.into() => { } + if p == peer_b && r == COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN.into() => { } ); } diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs index 0734b75c971..4734d7a0f96 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs @@ -1306,6 +1306,208 @@ fn local_node_sanity_checks_incoming_requests() { }); } +#[test] +fn local_node_checks_that_peer_can_request_before_responding() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + + test_harness(config, |mut state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // Peers A and B are in group and have relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + let peer_b_index = other_group_validators[1]; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_b.clone(), view![relay_parent]).await; + + // Finish setup + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let mask = StatementFilter::blank(state.config.group_size); + + // Confirm candidate. + let signed = state.sign_statement( + local_validator.validator_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ); + let full_signed = signed + .clone() + .convert_to_superpayload(StatementWithPVD::Seconded(candidate.clone(), pvd.clone())) + .unwrap(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, full_signed), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone(), peer_b.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), local_validator.validator_index); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + // Local node should respond to requests from peers in the same group + // which appear to not have already seen the candidate + { + // Peer requests candidate and local responds + let response = state + .send_request( + peer_a, + request_v2::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask: mask.clone(), + }, + ) + .await + .await; + + let expected_statements = vec![signed.into_unchecked()]; + assert_matches!(response, full_response => { + // Response is the same for vstaging. + 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); + assert_eq!(persisted_validation_data, pvd); + assert_eq!(statements, expected_statements); + }); + } + + // Local node should reject requests if the requester appears to know + // the candidate (has sent them a Seconded statement) + { + let statement = state + .sign_statement( + peer_b_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + let response = state + .send_request( + peer_b, + request_v2::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask: mask.clone(), + }, + ) + .await + .await; + + // Peer already knows about this candidate. Should reject. + assert_matches!( + response, + RawOutgoingResponse { + result, + reputation_changes, + sent_feedback + } => { + assert_matches!(result, Err(())); + assert_eq!(reputation_changes, vec![COST_UNEXPECTED_REQUEST.into()]); + assert_matches!(sent_feedback, None); + } + ); + + // Handling leftover statement distribution message + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), peer_b_index); + } + ); + } + + overseer + }); +} + #[test] fn local_node_respects_statement_mask() { let validator_count = 6; -- GitLab From e00ae1ea73b8d619e18e34289a4861146cf1b21a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Oct 2023 00:21:27 +0200 Subject: [PATCH 344/633] Bump aes-gcm from 0.10.2 to 0.10.3 (#1893) Bumps [aes-gcm](https://github.com/RustCrypto/AEADs) from 0.10.2 to 0.10.3.
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=aes-gcm&package-manager=cargo&previous-version=0.10.2&new-version=0.10.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/paritytech/polkadot-sdk/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0267a0c1e55..1ea3eb38d0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead 0.5.2", "aes 0.8.3", @@ -17420,7 +17420,7 @@ dependencies = [ name = "sp-statement-store" version = "4.0.0-dev" dependencies = [ - "aes-gcm 0.10.2", + "aes-gcm 0.10.3", "curve25519-dalek 4.0.0", "ed25519-dalek", "hkdf", @@ -19962,7 +19962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a00f4242f2db33307347bd5be53263c52a0331c96c14292118c9a6bb48d267" dependencies = [ "aes 0.6.0", - "aes-gcm 0.10.2", + "aes-gcm 0.10.3", "async-trait", "bincode", "block-modes", -- GitLab From e2b21d00c7856961ab3b692b2e2798747af1e819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 22 Oct 2023 10:44:34 +0200 Subject: [PATCH 345/633] sc-executor: Increase maximum instance count (#1856) Changes the maximum instances count for `wasmtime` to `64`. It also allows to only pass in maximum `32` for `--max-runtime-instances` as `256` was way too big. With `64` instances in total and `32` that can be configured in maximum, there should be enough space to accommodate for extra instances that are may required to be allocated adhoc. --------- Co-authored-by: Koute --- Cargo.lock | 1 + .../client/cli/src/params/runtime_params.rs | 6 +- substrate/client/executor/wasmtime/Cargo.toml | 1 + .../executor/wasmtime/src/instance_wrapper.rs | 17 ++++- .../client/executor/wasmtime/src/runtime.rs | 64 ++++++++++++++++++- 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ea3eb38d0c..ae88e4c2c99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15172,6 +15172,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", + "parking_lot 0.12.1", "paste", "rustix 0.36.15", "sc-allocator", diff --git a/substrate/client/cli/src/params/runtime_params.rs b/substrate/client/cli/src/params/runtime_params.rs index 79035fc7d4c..07009a96ee6 100644 --- a/substrate/client/cli/src/params/runtime_params.rs +++ b/substrate/client/cli/src/params/runtime_params.rs @@ -22,7 +22,7 @@ use std::str::FromStr; /// Parameters used to config runtime. #[derive(Debug, Clone, Args)] pub struct RuntimeParams { - /// The size of the instances cache for each runtime. The values higher than 256 are illegal. + /// The size of the instances cache for each runtime. The values higher than 32 are illegal. #[arg(long, default_value_t = 8, value_parser = parse_max_runtime_instances)] pub max_runtime_instances: usize, @@ -35,8 +35,8 @@ fn parse_max_runtime_instances(s: &str) -> Result { let max_runtime_instances = usize::from_str(s) .map_err(|_err| format!("Illegal `--max-runtime-instances` value: {s}"))?; - if max_runtime_instances > 256 { - Err(format!("Illegal `--max-runtime-instances` value: {max_runtime_instances} is more than the allowed maximum of `256` ")) + if max_runtime_instances > 32 { + Err(format!("Illegal `--max-runtime-instances` value: {max_runtime_instances} is more than the allowed maximum of `32` ")) } else { Ok(max_runtime_instances) } diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index fee1afc9666..261d52c0ede 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = "0.4.17" cfg-if = "1.0" libc = "0.2.121" +parking_lot = "0.12.1" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! diff --git a/substrate/client/executor/wasmtime/src/instance_wrapper.rs b/substrate/client/executor/wasmtime/src/instance_wrapper.rs index acc799061c2..8852532adbc 100644 --- a/substrate/client/executor/wasmtime/src/instance_wrapper.rs +++ b/substrate/client/executor/wasmtime/src/instance_wrapper.rs @@ -19,7 +19,9 @@ //! Defines data and logic needed for interaction with an WebAssembly instance of a substrate //! runtime module. -use crate::runtime::{Store, StoreData}; +use std::sync::Arc; + +use crate::runtime::{InstanceCounter, ReleaseInstanceHandle, Store, StoreData}; use sc_executor_common::{ error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}, wasm_runtime::InvokeMethod, @@ -154,10 +156,19 @@ impl sc_allocator::Memory for MemoryWrapper<'_, C> { pub struct InstanceWrapper { instance: Instance, store: Store, + // NOTE: We want to decrement the instance counter *after* the store has been dropped + // to avoid a potential race condition, so this field must always be kept + // as the last field in the struct! + _release_instance_handle: ReleaseInstanceHandle, } impl InstanceWrapper { - pub(crate) fn new(engine: &Engine, instance_pre: &InstancePre) -> Result { + pub(crate) fn new( + engine: &Engine, + instance_pre: &InstancePre, + instance_counter: Arc, + ) -> Result { + let _release_instance_handle = instance_counter.acquire_instance(); let mut store = Store::new(engine, Default::default()); let instance = instance_pre.instantiate(&mut store).map_err(|error| { WasmError::Other(format!( @@ -172,7 +183,7 @@ impl InstanceWrapper { store.data_mut().memory = Some(memory); store.data_mut().table = table; - Ok(InstanceWrapper { instance, store }) + Ok(InstanceWrapper { instance, store, _release_instance_handle }) } /// Resolves a substrate entrypoint by the given name. diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index ae78137959b..ac88663f4e7 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -24,6 +24,7 @@ use crate::{ util::{self, replace_strategy_if_broken}, }; +use parking_lot::Mutex; use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ error::{Error, Result, WasmError}, @@ -42,6 +43,8 @@ use std::{ }; use wasmtime::{AsContext, Engine, Memory, Table}; +const MAX_INSTANCE_COUNT: u32 = 64; + #[derive(Default)] pub(crate) struct StoreData { /// This will only be set when we call into the runtime. @@ -73,11 +76,59 @@ enum Strategy { struct InstanceCreator { engine: Engine, instance_pre: Arc>, + instance_counter: Arc, } impl InstanceCreator { fn instantiate(&mut self) -> Result { - InstanceWrapper::new(&self.engine, &self.instance_pre) + InstanceWrapper::new(&self.engine, &self.instance_pre, self.instance_counter.clone()) + } +} + +/// A handle for releasing an instance acquired by [`InstanceCounter::acquire_instance`]. +pub(crate) struct ReleaseInstanceHandle { + counter: Arc, +} + +impl Drop for ReleaseInstanceHandle { + fn drop(&mut self) { + { + let mut counter = self.counter.counter.lock(); + *counter = counter.saturating_sub(1); + } + + self.counter.wait_for_instance.notify_one(); + } +} + +/// Keeps track on the number of parallel instances. +/// +/// The runtime cache keeps track on the number of parallel instances. The maximum number in the +/// cache is less than what we have configured as [`MAX_INSTANCE_COUNT`] for wasmtime. However, the +/// cache will create on demand instances if required. This instance counter will ensure that we are +/// blocking when we are trying to create too many instances. +#[derive(Default)] +pub(crate) struct InstanceCounter { + counter: Mutex, + wait_for_instance: parking_lot::Condvar, +} + +impl InstanceCounter { + /// Acquire an instance. + /// + /// Blocks if there is no free instance available. + /// + /// The returned [`ReleaseInstanceHandle`] should be dropped when the instance isn't used + /// anymore. + pub fn acquire_instance(self: Arc) -> ReleaseInstanceHandle { + let mut counter = self.counter.lock(); + + while *counter >= MAX_INSTANCE_COUNT { + self.wait_for_instance.wait(&mut counter); + } + *counter += 1; + + ReleaseInstanceHandle { counter: self.clone() } } } @@ -87,6 +138,7 @@ pub struct WasmtimeRuntime { engine: Engine, instance_pre: Arc>, instantiation_strategy: InternalInstantiationStrategy, + instance_counter: Arc, } impl WasmModule for WasmtimeRuntime { @@ -95,6 +147,7 @@ impl WasmModule for WasmtimeRuntime { InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator { engine: self.engine.clone(), instance_pre: self.instance_pre.clone(), + instance_counter: self.instance_counter.clone(), }), }; @@ -277,7 +330,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Mon, 23 Oct 2023 17:54:06 +0800 Subject: [PATCH 346/633] wasm-builder: manually set CARGO_TARGET_DIR (#1951) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✄ ----------------------------------------------------------------------------- Thank you for your Pull Request! 🙏 Please make sure it follows the contribution guidelines outlined in [this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md) and fill out the sections below. Once you're ready to submit your PR for review, please delete this section and leave only the text under the "Description" heading. # Description *Please include a summary of the changes and the related issue. Please also include relevant motivation and context, including:* - What does this PR do? make 'substrate-wasm-builder' manually set 'CARGO_TARGET_DIR' to '$project_dir/target' while building instead of unset 'CARGO_TARGET_DIR'; - Why are these changes needed? If you using this in the `build.rs` with following content in your `~/.cargo/config.toml': [build] target-dir = "target" the build process will stuck because of dead lock -- two `cargo build` on same target directory in the same time. There is already an attempt to avoid such dead lock by unset the `CARGO_TARGET_DIR`, but for users with config above in his build enviroment (like me), this workaround won't work. - How were these changes implemented and what do they affect? Instead of unset 'CARGO_TARGET_DIR', we set 'CARGO_TARGET_DIR' to '$project/target/', which is already assumed to be true by rest of the code. *Use [Github semantic linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) to address any open issues this PR relates to or closes.* Fixes # (issue number, *if applicable*) Closes # (issue number, *if applicable*) # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` 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) You can remove the "Checklist" section once all have been checked. Thank you for your contribution! ✄ ----------------------------------------------------------------------------- I have built my project with this fix, there's still some warnings with `build.target-dir` set but the building process won't hang. I haven't found related issue in this repo. But I did find one issue [here](https://github.com/substrate-developer-hub/substrate-node-template/issues/116). --- substrate/utils/wasm-builder/src/prerequisites.rs | 7 ++++--- substrate/utils/wasm-builder/src/wasm_project.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/substrate/utils/wasm-builder/src/prerequisites.rs b/substrate/utils/wasm-builder/src/prerequisites.rs index f5a985ab92b..8e81e6774fa 100644 --- a/substrate/utils/wasm-builder/src/prerequisites.rs +++ b/substrate/utils/wasm-builder/src/prerequisites.rs @@ -143,9 +143,10 @@ fn check_wasm_toolchain_installed( run_cmd.current_dir(&temp); run_cmd.args(&["run", "--manifest-path", &manifest_path]); - // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock - build_cmd.env_remove("CARGO_TARGET_DIR"); - run_cmd.env_remove("CARGO_TARGET_DIR"); + // manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock + let target_dir = temp.path().join("target").display().to_string(); + build_cmd.env("CARGO_TARGET_DIR", &target_dir); + run_cmd.env("CARGO_TARGET_DIR", &target_dir); // Make sure the host's flags aren't used here, e.g. if an alternative linker is specified // in the RUSTFLAGS then the check we do here will break unless we clear these. diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 849af853c6d..da6fab863df 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -670,10 +670,10 @@ fn build_project( .args(&["rustc", "--target=wasm32-unknown-unknown"]) .arg(format!("--manifest-path={}", manifest_path.display())) .env("RUSTFLAGS", rustflags) - // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir + // Manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir // exclusive). The runner project is created in `CARGO_TARGET_DIR` and executing it will // create a sub target directory inside of `CARGO_TARGET_DIR`. - .env_remove("CARGO_TARGET_DIR") + .env("CARGO_TARGET_DIR", &project.join("target").display().to_string()) // As we are being called inside a build-script, this env variable is set. However, we set // our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this // env variable. -- GitLab From f678b61c39377ac413cd85e9028d95545a597f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 23 Oct 2023 12:07:16 +0200 Subject: [PATCH 347/633] paras-scheduler: Fix migration to V1 (#1969) The migration was missing to migrate `AvailabilityCores`. If this isn't migrated, all parachains in the availability phase would stall until the next session is started. This pull request fixes this by migrating this data. Besides that it is doing some cosmetics. --- polkadot/runtime/parachains/src/assigner.rs | 3 +- .../parachains/src/assigner_parachains.rs | 4 +- polkadot/runtime/parachains/src/scheduler.rs | 16 +-- .../parachains/src/scheduler/migration.rs | 111 ++++++++++++------ 4 files changed, 84 insertions(+), 50 deletions(-) diff --git a/polkadot/runtime/parachains/src/assigner.rs b/polkadot/runtime/parachains/src/assigner.rs index b21e857a471..9e408df61dc 100644 --- a/polkadot/runtime/parachains/src/assigner.rs +++ b/polkadot/runtime/parachains/src/assigner.rs @@ -53,7 +53,8 @@ impl Pallet { fn is_bulk_core(core_idx: &CoreIndex) -> bool { let parachain_cores = as AssignmentProvider>>::session_core_count(); - (0..parachain_cores).contains(&core_idx.0) + + core_idx.0 < parachain_cores } } diff --git a/polkadot/runtime/parachains/src/assigner_parachains.rs b/polkadot/runtime/parachains/src/assigner_parachains.rs index d605d866051..866e8290052 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains.rs @@ -39,7 +39,7 @@ pub mod pallet { impl AssignmentProvider> for Pallet { fn session_core_count() -> u32 { - >::parachains().len() as u32 + paras::Parachains::::decode_len().unwrap_or(0) as u32 } fn pop_assignment_for_core( @@ -62,7 +62,7 @@ impl AssignmentProvider> for Pallet { max_availability_timeouts: 0, // The next assignment already goes to the same [`ParaId`], this can be any number // that's high enough to clear the time it takes to clear backing/availability. - ttl: BlockNumberFor::::from(10u32), + ttl: 10u32.into(), } } } diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 60b2a925460..af48019124d 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -605,14 +605,10 @@ impl Pallet { /// Moves all elements in the claimqueue forward. fn move_claimqueue_forward() { let mut cq = ClaimQueue::::get(); - for (_, core_queue) in cq.iter_mut() { + for core_queue in cq.values_mut() { // First pop the finished claims from the front. - match core_queue.front() { - None => {}, - Some(None) => { - core_queue.pop_front(); - }, - Some(_) => {}, + if let Some(None) = core_queue.front() { + core_queue.pop_front(); } } @@ -628,9 +624,10 @@ impl Pallet { // This can only happen on new sessions at which we move all assignments back to the // provider. Hence, there's nothing we need to do here. - if ValidatorGroups::::get().is_empty() { + if ValidatorGroups::::decode_len().map_or(true, |l| l == 0) { return } + let n_lookahead = Self::claimqueue_lookahead(); let n_session_cores = T::AssignmentProvider::session_core_count(); let cq = ClaimQueue::::get(); @@ -686,8 +683,7 @@ impl Pallet { fn add_to_claimqueue(core_idx: CoreIndex, pe: ParasEntry>) { ClaimQueue::::mutate(|la| { - let la_deque = la.entry(core_idx).or_insert_with(|| VecDeque::new()); - la_deque.push_back(Some(pe)); + la.entry(core_idx).or_default().push_back(Some(pe)); }); } diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index c1ce95b10e3..bb9a647e955 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -25,36 +25,45 @@ use frame_support::{ mod v0 { use super::*; - use primitives::CollatorId; + use primitives::{CollatorId, Id}; + #[storage_alias] pub(super) type Scheduled = StorageValue, Vec, ValueQuery>; - #[derive(Encode, Decode)] - pub struct QueuedParathread { - claim: primitives::ParathreadEntry, - core_offset: u32, - } + #[derive(Clone, Encode, Decode)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub struct ParathreadClaim(pub Id, pub CollatorId); - #[derive(Encode, Decode, Default)] - pub struct ParathreadClaimQueue { - queue: Vec, - next_core_offset: u32, + #[derive(Clone, Encode, Decode)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub struct ParathreadEntry { + /// The claim. + pub claim: ParathreadClaim, + /// Number of retries. + pub retries: u32, } - // Only here to facilitate the migration. - impl ParathreadClaimQueue { - pub fn len(self) -> usize { - self.queue.len() - } + /// What is occupying a specific availability core. + #[derive(Clone, Encode, Decode)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub enum CoreOccupied { + /// A parathread. + Parathread(ParathreadEntry), + /// A parachain. + Parachain, } + /// The actual type isn't important, as we only delete the key in the state. #[storage_alias] - pub(super) type ParathreadQueue = - StorageValue, ParathreadClaimQueue, ValueQuery>; + pub(crate) type AvailabilityCores = + StorageValue, Vec>, ValueQuery>; + /// The actual type isn't important, as we only delete the key in the state. #[storage_alias] - pub(super) type ParathreadClaimIndex = - StorageValue, Vec, ValueQuery>; + pub(super) type ParathreadQueue = StorageValue, (), ValueQuery>; + + #[storage_alias] + pub(super) type ParathreadClaimIndex = StorageValue, (), ValueQuery>; /// The assignment type. #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] @@ -108,30 +117,36 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::DispatchError> { - log::trace!( + let n: u32 = v0::Scheduled::::get().len() as u32 + + v0::AvailabilityCores::::get().iter().filter(|c| c.is_some()).count() as u32; + + log::info!( target: crate::scheduler::LOG_TARGET, - "Scheduled before migration: {}", - v0::Scheduled::::get().len() + "Number of scheduled and waiting for availability before: {n}", ); - let bytes = u32::to_be_bytes(v0::Scheduled::::get().len() as u32); - - Ok(bytes.to_vec()) + Ok(n.encode()) } #[cfg(feature = "try-runtime")] fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { - log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); + log::info!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); ensure!( - v0::Scheduled::::get().len() == 0, + v0::Scheduled::::get().is_empty(), "Scheduled should be empty after the migration" ); - let sched_len = u32::from_be_bytes(state.try_into().unwrap()); + let expected_len = u32::decode(&mut &state[..]).unwrap(); + let availability_cores_waiting = super::AvailabilityCores::::get() + .iter() + .filter(|c| !matches!(c, CoreOccupied::Free)) + .count(); + ensure!( - Pallet::::claimqueue_len() as u32 == sched_len, - "Scheduled completely moved to ClaimQueue after migration" + Pallet::::claimqueue_len() as u32 + availability_cores_waiting as u32 == + expected_len, + "ClaimQueue and AvailabilityCores should have the correct length", ); Ok(()) @@ -142,11 +157,8 @@ pub mod v1 { pub fn migrate_to_v1() -> Weight { let mut weight: Weight = Weight::zero(); - let pq = v0::ParathreadQueue::::take(); - let pq_len = pq.len() as u64; - - let pci = v0::ParathreadClaimIndex::::take(); - let pci_len = pci.len() as u64; + v0::ParathreadQueue::::kill(); + v0::ParathreadClaimIndex::::kill(); let now = >::block_number(); let scheduled = v0::Scheduled::::take(); @@ -158,10 +170,35 @@ pub fn migrate_to_v1() -> Weight { Pallet::::add_to_claimqueue(core_idx, pe); } + let parachains = paras::Pallet::::parachains(); + let availability_cores = v0::AvailabilityCores::::take(); + let mut new_availability_cores = Vec::new(); + + for (core_index, core) in availability_cores.into_iter().enumerate() { + let new_core = if let Some(core) = core { + match core { + v0::CoreOccupied::Parachain => CoreOccupied::Paras(ParasEntry::new( + Assignment::new(parachains[core_index]), + now, + )), + v0::CoreOccupied::Parathread(entry) => + CoreOccupied::Paras(ParasEntry::new(Assignment::new(entry.claim.0), now)), + } + } else { + CoreOccupied::Free + }; + + new_availability_cores.push(new_core); + } + + super::AvailabilityCores::::set(new_availability_cores); + // 2x as once for Scheduled and once for Claimqueue weight = weight.saturating_add(T::DbWeight::get().reads_writes(2 * sched_len, 2 * sched_len)); - weight = weight.saturating_add(T::DbWeight::get().reads_writes(pq_len, pq_len)); - weight = weight.saturating_add(T::DbWeight::get().reads_writes(pci_len, pci_len)); + // reading parachains + availability_cores, writing AvailabilityCores + weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); + // 2x kill + weight = weight.saturating_add(T::DbWeight::get().writes(2)); weight } -- GitLab From c284a9312a546b59450496c0c85b2b445afa89e0 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 23 Oct 2023 12:22:42 +0200 Subject: [PATCH 348/633] Remove `(rococo/westend)-runtime` deps from testnet AssetHubs (#1979) ## Problem This PR addresses the issue with testnet AssetHub builds, which was discovered during the execution of `bot bench`. https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4038738 ``` Compiling asset-hub-rococo-runtime-wasm v1.0.0 (/builds/parity/mirrors/polkadot-sdk/target/production/wbuild/asset-hub-rococo-runtime) warning: Linking globals named 'Core_version': symbol multiply defined! error: failed to load bitcode of module "rococo_runtime-8799ee884447805a.rococo_runtime.0bc572b8-cgu.0.rcgu.o": warning: `asset-hub-rococo-runtime-wasm` (lib) generated 1 warning error: could not compile `asset-hub-rococo-runtime-wasm` (lib) due to previous error; 1 warning emitted ``` https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4038739 ``` Compiling asset-hub-westend-runtime-wasm v1.0.0 (/builds/parity/mirrors/polkadot-sdk/target/production/wbuild/asset-hub-westend-runtime) warning: Linking globals named 'Core_version': symbol multiply defined! error: failed to load bitcode of module "westend_runtime-86d7844430f97d5c.westend_runtime.b7678d03-cgu.0.rcgu.o": warning: `asset-hub-westend-runtime-wasm` (lib) generated 1 warning error: could not compile `asset-hub-westend-runtime-wasm` (lib) due to previous error; 1 warning emitted ``` ## Solution - Removed dependencies on `rococo-runtime` and `westend-runtime` introduced by [this PR](https://github.com/paritytech/polkadot-sdk/pull/1234/files#diff-a86375df98e04ca3cce1ea35c40257a222e2d5087f5f528ff33307678b78dc2dR534-R550). - Replaced `::index()` with `rococo_runtime_constants::TREASURY_PALLET_ID`. - Added `check_treasury_pallet_id` to the relay runtimes to ensure that the constant is aligned with the pallet id. - Added "Rococo Treasury" to the waived locations (that will not be charged fees in the executor) for `BridgeHubRococo` (to be aligned with AssetHubs). ## References [Full element discussion here](https://matrix.to/#/!JUeaZUiYbdrvzvtwSL:parity.io/$2PnjYMsWRjR7M3oOfGuRI0XkjdoqJLtRcAPVcDLuLVg?via=parity.io&via=web3.foundation). --------- Co-authored-by: command-bot <> --- Cargo.lock | 2 - .../assets/asset-hub-rococo/Cargo.toml | 4 -- .../assets/asset-hub-rococo/src/xcm_config.rs | 3 +- .../assets/asset-hub-westend/Cargo.toml | 4 -- .../asset-hub-westend/src/xcm_config.rs | 3 +- .../src/weights/pallet_bridge_relayers.rs | 46 +++++++------- .../bridge-hub-rococo/src/xcm_config.rs | 24 +++++-- polkadot/runtime/rococo/constants/src/lib.rs | 3 + polkadot/runtime/rococo/src/lib.rs | 59 +---------------- polkadot/runtime/rococo/src/tests.rs | 63 +++++++++++++++++++ polkadot/runtime/westend/constants/src/lib.rs | 3 + polkadot/runtime/westend/src/tests.rs | 8 +++ 12 files changed, 122 insertions(+), 100 deletions(-) create mode 100644 polkadot/runtime/rococo/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index ae88e4c2c99..5dcca22dd05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,7 +874,6 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "primitive-types", - "rococo-runtime", "rococo-runtime-constants", "scale-info", "smallvec", @@ -1000,7 +999,6 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", - "westend-runtime", "westend-runtime-constants", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 6d20ccc905f..b1ec66f40bf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -55,7 +55,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 -rococo-runtime = { path = "../../../../../polkadot/runtime/rococo", default-features = false } 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 } @@ -131,7 +130,6 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", - "rococo-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -167,7 +165,6 @@ try-runtime = [ "pallet-xcm/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", - "rococo-runtime/try-runtime", "sp-runtime/try-runtime", ] std = [ @@ -221,7 +218,6 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "rococo-runtime-constants/std", - "rococo-runtime/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index d25f336f1af..48babbd49c5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -40,7 +40,6 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime::Treasury as RococoTreasury; use rococo_runtime_constants::system_parachain::SystemParachains; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; @@ -532,7 +531,7 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = >; parameter_types! { - pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(::index() as u8)).into(); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } pub struct RelayTreasury; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 294f7d8413d..7a523f8bfb6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -60,7 +60,6 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} -westend-runtime = { path = "../../../../../polkadot/runtime/westend", 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} @@ -117,7 +116,6 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "westend-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", ] @@ -151,7 +149,6 @@ try-runtime = [ "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", - "westend-runtime/try-runtime", ] std = [ "assets-common/std", @@ -213,7 +210,6 @@ std = [ "sp-version/std", "substrate-wasm-builder", "westend-runtime-constants/std", - "westend-runtime/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", 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 1306b00e2f0..f14b410327c 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 @@ -41,7 +41,6 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; -use westend_runtime::Treasury as WestendTreasury; use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ @@ -506,7 +505,7 @@ match_types! { } parameter_types! { - pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(::index() as u8)).into(); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); } pub struct RelayTreasury; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index a934a1be582..0ae6e5eff2a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! 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-10-23, 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-t2sp1qqs-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 -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_bridge_relayers -// --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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_relayers +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,8 +56,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `207` // Estimated: `3593` - // Minimum execution time: 54_291_000 picoseconds. - Weight::from_parts(55_145_000, 0) + // Minimum execution time: 46_239_000 picoseconds. + Weight::from_parts(47_442_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -74,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `61` // Estimated: `4714` - // Minimum execution time: 28_143_000 picoseconds. - Weight::from_parts(28_920_000, 0) + // Minimum execution time: 23_977_000 picoseconds. + Weight::from_parts(24_837_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -88,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `160` // Estimated: `4714` - // Minimum execution time: 30_329_000 picoseconds. - Weight::from_parts(30_646_000, 0) + // Minimum execution time: 25_798_000 picoseconds. + Weight::from_parts(26_495_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -104,8 +102,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `263` // Estimated: `4714` - // Minimum execution time: 29_704_000 picoseconds. - Weight::from_parts(30_269_000, 0) + // Minimum execution time: 27_382_000 picoseconds. + Weight::from_parts(27_936_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -116,8 +114,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `6` // Estimated: `3538` - // Minimum execution time: 2_793_000 picoseconds. - Weight::from_parts(2_999_000, 0) + // Minimum execution time: 2_944_000 picoseconds. + Weight::from_parts(3_093_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 0f6dfb13684..14de497cb99 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 @@ -231,6 +231,23 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +parameter_types! { + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); +} + +pub struct RelayTreasury; +impl Contains for RelayTreasury { + fn contains(location: &MultiLocation) -> bool { + let relay_treasury_location = RelayTreasuryLocation::get(); + *location == relay_treasury_location + } +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); + /// 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; @@ -262,12 +279,7 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount< - Self, - RelayOrOtherSystemParachains, - AccountId, - TreasuryAccount, - >; + type FeeManager = XcmFeesToAccount; type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 19225c68151..84594cffcf3 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -120,6 +120,9 @@ pub mod system_parachain { } } +/// Rococo Treasury pallet instance. +pub const TREASURY_PALLET_ID: u8 = 18; + #[cfg(test)] mod tests { use super::{ diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index f4264ea3533..1e8e3ed01e0 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -119,6 +119,9 @@ use governance::{ TreasurySpender, }; +#[cfg(test)] +mod tests; + mod validator_manager; impl_runtime_weights!(rococo_runtime_constants); @@ -2204,62 +2207,6 @@ sp_api::impl_runtime_apis! { } } -#[cfg(test)] -mod tests { - use std::collections::HashSet; - - use super::*; - use frame_support::traits::WhitelistedStorageKeys; - use sp_core::hexdisplay::HexDisplay; - - #[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 encoding_tests { - use super::*; - - #[test] - fn nis_hold_reason_encoding_is_correct() { - assert_eq!(RuntimeHoldReason::Nis(pallet_nis::HoldReason::NftReceipt).encode(), [38, 0]); - } -} - #[cfg(all(test, feature = "try-runtime"))] mod remote_tests { use super::*; diff --git a/polkadot/runtime/rococo/src/tests.rs b/polkadot/runtime/rococo/src/tests.rs new file mode 100644 index 00000000000..464a8c4f545 --- /dev/null +++ b/polkadot/runtime/rococo/src/tests.rs @@ -0,0 +1,63 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Tests for the Rococo Runtime Configuration + +use crate::*; +use std::collections::HashSet; + +use frame_support::traits::WhitelistedStorageKeys; +use sp_core::hexdisplay::HexDisplay; + +#[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")); +} + +#[test] +fn check_treasury_pallet_id() { + assert_eq!( + ::index() as u8, + rococo_runtime_constants::TREASURY_PALLET_ID + ); +} + +mod encoding_tests { + use super::*; + + #[test] + fn nis_hold_reason_encoding_is_correct() { + assert_eq!(RuntimeHoldReason::Nis(pallet_nis::HoldReason::NftReceipt).encode(), [38, 0]); + } +} diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index 4851303b589..a06b3ba602a 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -114,6 +114,9 @@ pub mod system_parachain { } } +/// Westend Treasury pallet instance. +pub const TREASURY_PALLET_ID: u8 = 37; + /// XCM protocol related constants. pub mod xcm { /// Pluralistic bodies existing within the consensus. diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 78062662fee..9f996316059 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -91,3 +91,11 @@ fn check_whitelist() { // XcmPallet SafeXcmVersion assert!(whitelist.contains("1405f2411d0af5a7ff397e7c9dc68d196323ae84c43568be0d1394d5d0d522c4")); } + +#[test] +fn check_treasury_pallet_id() { + assert_eq!( + ::index() as u8, + westend_runtime_constants::TREASURY_PALLET_ID + ); +} -- GitLab From e0620fd9c01d3a5b65f06c8c8b0a101617a24877 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 23 Oct 2023 13:41:20 +0200 Subject: [PATCH 349/633] [testnet] BridgeHubRococo nits (#1972) This PR does not introduce any functional changes to the existing code, it merely addresses several minor refactors: - Moving bridging pallets to separate files. - Improving the readability and naming of weight files for bridging pallets and bridging pallet instances. The reason for this refactor is to facilitate easier plugin integration for the upcoming bridge between Rococo and Westend. --------- Co-authored-by: command-bot <> --- .../chain-bridge-hub-rococo/src/lib.rs | 7 +- .../chain-bridge-hub-wococo/src/lib.rs | 7 +- .../bridge-hub-rococo/src/tests/example.rs | 2 +- .../emulated/common/src/constants.rs | 18 +- .../assets/asset-hub-rococo/src/lib.rs | 4 +- .../assets/asset-hub-rococo/src/xcm_config.rs | 16 +- .../assets/asset-hub-rococo/tests/tests.rs | 4 +- .../parachains/runtimes/bridge-hubs/README.md | 6 +- .../src/bridge_common_config.rs | 105 ++++++++ .../src/bridge_hub_rococo_config.rs | 73 ++++- .../src/bridge_hub_wococo_config.rs | 72 ++++- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 254 ++++-------------- .../bridge-hub-rococo/src/weights/mod.rs | 34 ++- ... pallet_bridge_grandpa_rococo_finality.rs} | 38 ++- ... pallet_bridge_grandpa_wococo_finality.rs} | 38 ++- ...allet_bridge_messages_rococo_to_wococo.rs} | 104 +++---- ...allet_bridge_messages_wococo_to_rococo.rs} | 104 +++---- ...pallet_bridge_parachains_within_rococo.rs} | 42 ++- ...pallet_bridge_parachains_within_wococo.rs} | 38 ++- .../bridge-hub-rococo/src/xcm_config.rs | 11 +- .../bridge-hub-rococo/tests/tests.rs | 33 +-- .../src/chain_spec/bridge_hubs.rs | 18 +- 22 files changed, 547 insertions(+), 481 deletions(-) create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_grandpa_bridge_rococo_grandpa.rs => pallet_bridge_grandpa_rococo_finality.rs} (80%) rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_grandpa_bridge_wococo_grandpa.rs => pallet_bridge_grandpa_wococo_finality.rs} (81%) rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance.rs => pallet_bridge_messages_rococo_to_wococo.rs} (81%) rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs => pallet_bridge_messages_wococo_to_rococo.rs} (81%) rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs => pallet_bridge_parachains_within_rococo.rs} (85%) rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/{pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs => pallet_bridge_parachains_within_wococo.rs} (88%) diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index 6da5cd3818f..ed3ef440c83 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -68,14 +68,15 @@ pub type Address = MultiAddress; pub const BRIDGE_HUB_ROCOCO_PARACHAIN_ID: u32 = 1013; /// Name of the With-BridgeHubRococo messages pallet instance that is deployed at bridged chains. -pub const WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; +pub const WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME: &str = + "BridgeWococoToRococoMessages"; /// Name of the With-BridgeHubRococo bridge-relayers pallet instance that is deployed at bridged /// 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; +/// Pallet index of `BridgeRococoToWococoMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_ROCOCO_TO_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 0c771736804..1e147d367d0 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -62,14 +62,15 @@ impl Parachain for BridgeHubWococo { pub const BRIDGE_HUB_WOCOCO_PARACHAIN_ID: u32 = 1014; /// Name of the With-BridgeHubWococo messages pallet instance that is deployed at bridged chains. -pub const WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; +pub const WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME: &str = + "BridgeRococoToWococoMessages"; /// Name of the With-BridgeHubWococo bridge-relayers pallet instance that is deployed at bridged /// 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; +/// Pallet index of `BridgeWococoToRococoMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_WOCOCO_TO_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/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index f24e13bb71b..fd34299ce1d 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -64,7 +64,7 @@ fn example() { outcome: Outcome::Complete(_), .. }) => {}, - RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { + RuntimeEvent::BridgeRococoToWococoMessages(pallet_bridge_messages::Event::MessageAccepted { lane_id: LaneId([0, 0, 0, 1]), nonce: 1, }) => {}, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 592269e9aa3..93abae753b9 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -669,14 +669,16 @@ pub mod bridge_hub_rococo { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, + bridge_wococo_to_rococo_messages: + bridge_hub_rococo_runtime::BridgeWococoToRococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_to_wococo_messages: + bridge_hub_rococo_runtime::BridgeRococoToWococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, ..Default::default() }; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index a0eef7e43a4..20b59368a5b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -838,7 +838,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_wococo::WococoNetwork; - type Bridges = xcm_config::bridging::to_wococo::NetworkExportTable; + type Bridges = xcm_config::bridging::NetworkExportTable; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; @@ -869,7 +869,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; - type Bridges = xcm_config::bridging::to_rococo::NetworkExportTable; + type Bridges = xcm_config::bridging::NetworkExportTable; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 48babbd49c5..ae4a275d43a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -763,8 +763,16 @@ pub mod bridging { pub XcmBridgeHubRouterFeeAssetId: AssetId = TokenLocation::get().into(); /// Price per byte - can be adjusted via governance `set_storage` call. pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + + pub BridgeTable: sp_std::vec::Vec = + sp_std::vec::Vec::new().into_iter() + .chain(to_wococo::BridgeTable::get()) + .chain(to_rococo::BridgeTable::get()) + .collect(); } + pub type NetworkExportTable = xcm_builder::NetworkExportTable; + pub mod to_wococo { use super::*; @@ -773,7 +781,7 @@ pub mod bridging { 1, X2( Parachain(SiblingBridgeHubParaId::get()), - PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX) + PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_INDEX) ) ); @@ -824,8 +832,6 @@ pub mod bridging { } } - 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 = @@ -864,7 +870,7 @@ pub mod bridging { 1, X2( Parachain(SiblingBridgeHubParaId::get()), - PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX) + PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX) ) ); @@ -915,8 +921,6 @@ pub mod bridging { } } - 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 = diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 7f48d576288..a763382f905 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -704,7 +704,7 @@ mod asset_hub_rococo_tests { (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)), + X1(PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_INDEX)), GlobalConsensus(Wococo), X1(Parachain(1000)) ) @@ -909,7 +909,7 @@ mod asset_hub_wococo_tests { (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)), + X1(PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX)), GlobalConsensus(Rococo), X1(Parachain(1000)) ) diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index 9acdfd6d053..ef1f837a7e1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -172,10 +172,10 @@ cd - 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 + - BridgeHubRococo (see `bridgeRococoToWococoMessages.MessageAccepted`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + - BridgeHubWococo (see `bridgeWococoToRococoMessages.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 + - BridgeHubRocococ (see `bridgeRococoToWococoMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer ### Claim relayer's rewards on BridgeHubRococo and BridgeHubWococo diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs new file mode 100644 index 00000000000..a1fded8470c --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -0,0 +1,105 @@ +// 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 . + +//! Bridge definitions that can be used by multiple BridgeHub flavors. +//! All configurations here should be dedicated to a single chain; in other words, we don't need two +//! chains for a single pallet configuration. +//! +//! For example, the messaging pallet needs to know the sending and receiving chains, but the +//! GRANDPA tracking pallet only needs to be aware of one chain. + +use super::{weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent}; +use bp_parachains::SingleParaStoredHeaderDataBuilder; +use frame_support::{parameter_types, traits::ConstU32}; + +parameter_types! { + pub const RelayChainHeadersToKeep: u32 = 1024; + pub const ParachainHeadsToKeep: u32 = 64; + + pub const RococoBridgeParachainPalletName: &'static str = "Paras"; + pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; + pub const WococoBridgeParachainPalletName: &'static str = "Paras"; + pub const MaxWococoParaHeadDataSize: u32 = bp_wococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; + + pub storage RequiredStakeForStakeAndSlash: Balance = 1_000_000; + pub const RelayerStakeLease: u32 = 8; + pub const RelayerStakeReserveId: [u8; 8] = *b"brdgrlrs"; + + pub storage DeliveryRewardInBalance: u64 = 1_000_000; +} + +/// Add GRANDPA bridge pallet to track Wococo relay chain. +pub type BridgeGrandpaWococoInstance = pallet_bridge_grandpa::Instance1; +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_wococo::Wococo; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = RelayChainHeadersToKeep; + type WeightInfo = weights::pallet_bridge_grandpa_wococo_finality::WeightInfo; +} + +/// 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; + type WeightInfo = weights::pallet_bridge_parachains_within_wococo::WeightInfo; + type BridgesGrandpaPalletInstance = BridgeGrandpaWococoInstance; + type ParasPalletName = WococoBridgeParachainPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ParachainHeadsToKeep; + type MaxParaHeadDataSize = MaxWococoParaHeadDataSize; +} + +/// Add GRANDPA bridge pallet to track Rococo relay chain. +pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance2; +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_rococo::Rococo; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = RelayChainHeadersToKeep; + type WeightInfo = weights::pallet_bridge_grandpa_rococo_finality::WeightInfo; +} + +/// 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; + type WeightInfo = weights::pallet_bridge_parachains_within_rococo::WeightInfo; + type BridgesGrandpaPalletInstance = BridgeGrandpaRococoInstance; + type ParasPalletName = RococoBridgeParachainPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ParachainHeadsToKeep; + type MaxParaHeadDataSize = MaxRococoParaHeadDataSize; +} + +/// Allows collect and claim rewards for relayers +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = + bp_relayers::PayRewardFromAccount, AccountId>; + type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< + AccountId, + BlockNumber, + Balances, + RelayerStakeReserveId, + RequiredStakeForStakeAndSlash, + RelayerStakeLease, + >; + type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; +} 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 73eb27e9216..a02d8ad88e7 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 @@ -14,25 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Bridge definitions that are used on Rococo to bridge with Wococo. +//! Bridge definitions used on BridgeHub with the Rococo flavor. use crate::{ - BridgeParachainWococoInstance, BridgeWococoMessages, ParachainInfo, Runtime, - WithBridgeHubWococoMessagesInstance, XcmRouter, + bridge_common_config::{BridgeParachainWococoInstance, DeliveryRewardInBalance}, + weights, AccountId, BridgeRococoToWococoMessages, ParachainInfo, Runtime, RuntimeEvent, + RuntimeOrigin, XcmRouter, }; use bp_messages::LaneId; use bridge_runtime_common::{ messages, messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, + target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, }, - messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, + messages_xcm_extension::{ + SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, + XcmBlobMessageDispatch, + }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, RefundableParachain, }, }; + use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; use sp_runtime::RuntimeDebug; @@ -48,7 +54,7 @@ parameter_types! { pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubWococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; - pub BridgeWococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub BridgeRococoToWococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); 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]; @@ -97,7 +103,7 @@ pub type ToWococoBridgeHubMessagesDeliveryProof = pub type OnBridgeHubRococoBlobDispatcher = BridgeBlobDispatcher< XcmRouter, BridgeHubRococoUniversalLocation, - BridgeWococoMessagesPalletInstance, + BridgeRococoToWococoMessagesPalletInstance, >; /// Export XCM messages to be relayed to the other side @@ -125,7 +131,7 @@ pub type OnMessagesDelivered = XcmBlobHaulerAdapterWococo XCM messages +pub type WithBridgeHubWococoMessagesInstance = pallet_bridge_messages::Instance1; +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_messages_rococo_to_wococo::WeightInfo; + type BridgedChainId = BridgeHubWococoChainId; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWococo; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = ToBridgeHubWococoMaximalOutboundPayloadSize; + type OutboundPayload = XcmAsPlainPayload; + + type InboundPayload = XcmAsPlainPayload; + type InboundRelayer = AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = ToBridgeHubWococoMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithBridgeHubWococoMessagesInstance, + DeliveryRewardInBalance, + >; + + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = XcmBlobMessageDispatch< + OnBridgeHubRococoBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + AssetHubRococoParaId, + Runtime, + >, + >; + type OnMessagesDelivered = OnMessagesDelivered; +} + #[cfg(test)] mod tests { use super::*; - use crate::BridgeGrandpaWococoInstance; + use crate::bridge_common_config::BridgeGrandpaWococoInstance; use bridge_runtime_common::{ assert_complete_bridge_types, integrity::{ @@ -251,10 +294,10 @@ mod tests { }, pallet_names: AssertBridgePalletNames { with_this_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME, with_bridged_chain_grandpa_pallet_name: bp_wococo::WITH_WOCOCO_GRANDPA_PALLET_NAME, with_bridged_chain_messages_pallet_name: - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME, }, }); @@ -265,8 +308,10 @@ mod tests { >(FEE_BOOST_PER_MESSAGE); assert_eq!( - BridgeWococoMessagesPalletInstance::get(), - X1(PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX)) + BridgeRococoToWococoMessagesPalletInstance::get(), + X1(PalletInstance( + bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_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 fcd9a6229ff..d09ee24976d 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 @@ -14,20 +14,25 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Bridge definitions that are used on Wococo to bridge with Rococo. +//! Bridge definitions used on BridgeHub with the Wococo flavor. use crate::{ - BridgeParachainRococoInstance, BridgeRococoMessages, ParachainInfo, Runtime, - WithBridgeHubRococoMessagesInstance, XcmRouter, + bridge_common_config::{BridgeParachainRococoInstance, DeliveryRewardInBalance}, + weights, AccountId, BridgeWococoToRococoMessages, ParachainInfo, Runtime, RuntimeEvent, + RuntimeOrigin, XcmRouter, }; use bp_messages::LaneId; use bridge_runtime_common::{ messages, messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, + target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, }, - messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, + messages_xcm_extension::{ + SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, + XcmBlobMessageDispatch, + }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, RefundableParachain, @@ -49,7 +54,7 @@ parameter_types! { bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pub BridgeHubWococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Wococo), Parachain(ParachainInfo::parachain_id().into())); - pub BridgeRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub BridgeWococoToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO]; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value @@ -97,7 +102,7 @@ pub type ToRococoBridgeHubMessagesDeliveryProof = pub type OnBridgeHubWococoBlobDispatcher = BridgeBlobDispatcher< XcmRouter, BridgeHubWococoUniversalLocation, - BridgeRococoMessagesPalletInstance, + BridgeWococoToRococoMessagesPalletInstance, >; /// Export XCM messages to be relayed to the other side @@ -125,7 +130,7 @@ pub type OnMessagesDelivered = XcmBlobHaulerAdapterRococo XCM messages +pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance2; +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_messages_wococo_to_rococo::WeightInfo; + type BridgedChainId = BridgeHubRococoChainId; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = ToBridgeHubRococoMaximalOutboundPayloadSize; + type OutboundPayload = XcmAsPlainPayload; + + type InboundPayload = XcmAsPlainPayload; + type InboundRelayer = AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = ToBridgeHubRococoMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithBridgeHubRococoMessagesInstance, + DeliveryRewardInBalance, + >; + + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = XcmBlobMessageDispatch< + OnBridgeHubWococoBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + AssetHubWococoParaId, + Runtime, + >, + >; + type OnMessagesDelivered = OnMessagesDelivered; +} + #[cfg(test)] mod tests { use super::*; - use crate::BridgeGrandpaRococoInstance; + use crate::bridge_common_config::BridgeGrandpaRococoInstance; use bridge_runtime_common::{ assert_complete_bridge_types, integrity::{ @@ -251,10 +293,10 @@ mod tests { }, pallet_names: AssertBridgePalletNames { with_this_chain_messages_pallet_name: - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME, with_bridged_chain_grandpa_pallet_name: bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME, with_bridged_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME, }, }); @@ -265,8 +307,10 @@ mod tests { >(FEE_BOOST_PER_MESSAGE); assert_eq!( - BridgeRococoMessagesPalletInstance::get(), - X1(PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX)) + BridgeWococoToRococoMessagesPalletInstance::get(), + X1(PalletInstance( + bp_bridge_hub_wococo::WITH_BRIDGE_WOCOCO_TO_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 6b6d84649d7..5973801d37c 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 @@ -30,6 +30,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +pub mod bridge_common_config; pub mod bridge_hub_rococo_config; pub mod bridge_hub_wococo_config; mod weights; @@ -68,7 +69,6 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; -use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_runtime::HeaderId; #[cfg(any(feature = "std", test))] @@ -80,19 +80,8 @@ use xcm::latest::prelude::*; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use crate::{ - bridge_hub_rococo_config::{ - BridgeRefundBridgeHubWococoMessages, OnBridgeHubRococoBlobDispatcher, - WithBridgeHubWococoMessageBridge, - }, - bridge_hub_wococo_config::{ - BridgeRefundBridgeHubRococoMessages, OnBridgeHubWococoBlobDispatcher, - WithBridgeHubRococoMessageBridge, - }, - xcm_config::XcmRouter, -}; -use bridge_runtime_common::{ - messages::{source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter}, - messages_xcm_extension::{XcmAsPlainPayload, XcmBlobMessageDispatch}, + bridge_hub_rococo_config::BridgeRefundBridgeHubWococoMessages, + bridge_hub_wococo_config::BridgeRefundBridgeHubRococoMessages, xcm_config::XcmRouter, }; use parachains_common::{ impls::DealWithFees, @@ -468,167 +457,6 @@ impl pallet_utility::Config for Runtime { type WeightInfo = weights::pallet_utility::WeightInfo; } -// Add bridge pallets (GPA) - -/// Add GRANDPA bridge pallet to track Wococo relay chain on Rococo BridgeHub -pub type BridgeGrandpaWococoInstance = pallet_bridge_grandpa::Instance1; -impl pallet_bridge_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BridgedChain = bp_wococo::Wococo; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; - type HeadersToKeep = RelayChainHeadersToKeep; - type WeightInfo = weights::pallet_bridge_grandpa_bridge_wococo_grandpa::WeightInfo; -} - -/// Add GRANDPA bridge pallet to track Rococo relay chain on Wococo BridgeHub -pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance2; -impl pallet_bridge_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BridgedChain = bp_rococo::Rococo; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; - type HeadersToKeep = RelayChainHeadersToKeep; - type WeightInfo = weights::pallet_bridge_grandpa_bridge_rococo_grandpa::WeightInfo; -} - -parameter_types! { - pub const RelayChainHeadersToKeep: u32 = 1024; - pub const ParachainHeadsToKeep: u32 = 64; - pub const RelayerStakeLease: u32 = 8; - - pub const RococoBridgeParachainPalletName: &'static str = "Paras"; - pub const WococoBridgeParachainPalletName: &'static str = "Paras"; - pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; - pub const MaxWococoParaHeadDataSize: u32 = bp_wococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; - - pub storage DeliveryRewardInBalance: u64 = 1_000_000; - pub storage RequiredStakeForStakeAndSlash: Balance = 1_000_000; - - pub const RelayerStakeReserveId: [u8; 8] = *b"brdgrlrs"; -} - -/// 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; - type WeightInfo = weights::pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance::WeightInfo; - type BridgesGrandpaPalletInstance = BridgeGrandpaWococoInstance; - type ParasPalletName = WococoBridgeParachainPalletName; - type ParaStoredHeaderDataBuilder = - SingleParaStoredHeaderDataBuilder; - type HeadsToKeep = ParachainHeadsToKeep; - type MaxParaHeadDataSize = MaxWococoParaHeadDataSize; -} - -/// 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; - type WeightInfo = weights::pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance::WeightInfo; - type BridgesGrandpaPalletInstance = BridgeGrandpaRococoInstance; - type ParasPalletName = RococoBridgeParachainPalletName; - type ParaStoredHeaderDataBuilder = - SingleParaStoredHeaderDataBuilder; - type HeadsToKeep = ParachainHeadsToKeep; - type MaxParaHeadDataSize = MaxRococoParaHeadDataSize; -} - -/// Add XCM messages support for BridgeHubRococo to support Rococo->Wococo XCM messages -pub type WithBridgeHubWococoMessagesInstance = pallet_bridge_messages::Instance1; -impl pallet_bridge_messages::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance::WeightInfo; - type BridgedChainId = bridge_hub_rococo_config::BridgeHubWococoChainId; - type ActiveOutboundLanes = bridge_hub_rococo_config::ActiveOutboundLanesToBridgeHubWococo; - type MaxUnrewardedRelayerEntriesAtInboundLane = - bridge_hub_rococo_config::MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = - bridge_hub_rococo_config::MaxUnconfirmedMessagesAtInboundLane; - - type MaximalOutboundPayloadSize = - bridge_hub_rococo_config::ToBridgeHubWococoMaximalOutboundPayloadSize; - type OutboundPayload = XcmAsPlainPayload; - - type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; - type DeliveryPayments = (); - - type TargetHeaderChain = TargetHeaderChainAdapter; - type LaneMessageVerifier = bridge_hub_rococo_config::ToBridgeHubWococoMessageVerifier; - type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< - Runtime, - WithBridgeHubWococoMessagesInstance, - DeliveryRewardInBalance, - >; - - type SourceHeaderChain = SourceHeaderChainAdapter; - 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 -pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance2; -impl pallet_bridge_messages::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance::WeightInfo; - type BridgedChainId = bridge_hub_wococo_config::BridgeHubRococoChainId; - type ActiveOutboundLanes = bridge_hub_wococo_config::ActiveOutboundLanesToBridgeHubRococo; - type MaxUnrewardedRelayerEntriesAtInboundLane = - bridge_hub_wococo_config::MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = - bridge_hub_wococo_config::MaxUnconfirmedMessagesAtInboundLane; - - type MaximalOutboundPayloadSize = - bridge_hub_wococo_config::ToBridgeHubRococoMaximalOutboundPayloadSize; - type OutboundPayload = XcmAsPlainPayload; - - type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; - type DeliveryPayments = (); - - type TargetHeaderChain = TargetHeaderChainAdapter; - type LaneMessageVerifier = bridge_hub_wococo_config::ToBridgeHubRococoMessageVerifier; - type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< - Runtime, - WithBridgeHubRococoMessagesInstance, - DeliveryRewardInBalance, - >; - - type SourceHeaderChain = SourceHeaderChainAdapter; - 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 -impl pallet_bridge_relayers::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Reward = Balance; - type PaymentProcedure = - bp_relayers::PayRewardFromAccount, AccountId>; - type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< - AccountId, - BlockNumber, - Balances, - RelayerStakeReserveId, - RequiredStakeForStakeAndSlash, - RelayerStakeLease, - >; - type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -669,12 +497,12 @@ construct_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, + BridgeRococoToWococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 46, // 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, + BridgeWococoToRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 45, BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 47, } @@ -687,7 +515,7 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { // Parachains BridgeRococoParachain, BridgeWococoParachain, // Messages - BridgeRococoMessages, BridgeWococoMessages + BridgeWococoToRococoMessages, BridgeRococoToWococoMessages } #[cfg(feature = "runtime-benchmarks")] @@ -711,13 +539,13 @@ mod benches { [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] // Bridge pallets at Rococo - [pallet_bridge_grandpa, BridgeWococoGrandpa] - [pallet_bridge_parachains, BridgeParachainsBench::] - [pallet_bridge_messages, BridgeMessagesBench::] + [pallet_bridge_grandpa, WococoFinality] + [pallet_bridge_parachains, WithinWococo] + [pallet_bridge_messages, RococoToWococo] // Bridge pallets at Wococo - [pallet_bridge_grandpa, BridgeRococoGrandpa] - [pallet_bridge_parachains, BridgeParachainsBench::] - [pallet_bridge_messages, BridgeMessagesBench::] + [pallet_bridge_grandpa, RococoFinality] + [pallet_bridge_parachains, WithinRococo] + [pallet_bridge_messages, WococoToRococo] // Bridge relayer pallets [pallet_bridge_relayers, BridgeRelayersBench::] ); @@ -904,7 +732,7 @@ impl_runtime_apis! { } } - // This exposed by BridgeHubRococo + // This is exposed by BridgeHubRococo impl bp_bridge_hub_wococo::FromBridgeHubWococoInboundLaneApi for Runtime { fn message_details( lane: bp_messages::LaneId, @@ -912,12 +740,12 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< Runtime, - WithBridgeHubWococoMessagesInstance, + bridge_hub_rococo_config::WithBridgeHubWococoMessagesInstance, >(lane, messages) } } - // This exposed by BridgeHubRococo + // This is exposed by BridgeHubRococo impl bp_bridge_hub_wococo::ToBridgeHubWococoOutboundLaneApi for Runtime { fn message_details( lane: bp_messages::LaneId, @@ -926,7 +754,7 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, - WithBridgeHubWococoMessagesInstance, + bridge_hub_rococo_config::WithBridgeHubWococoMessagesInstance, >(lane, begin, end) } } @@ -939,7 +767,7 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< Runtime, - WithBridgeHubRococoMessagesInstance, + bridge_hub_wococo_config::WithBridgeHubRococoMessagesInstance, >(lane, messages) } } @@ -953,7 +781,7 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, - WithBridgeHubRococoMessagesInstance, + bridge_hub_wococo_config::WithBridgeHubRococoMessagesInstance, >(lane, begin, end) } } @@ -994,9 +822,14 @@ impl_runtime_apis! { type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; - use pallet_bridge_parachains::benchmarking::Pallet as BridgeParachainsBench; - use pallet_bridge_messages::benchmarking::Pallet as BridgeMessagesBench; use pallet_bridge_relayers::benchmarking::Pallet as BridgeRelayersBench; + // Change weight file names. + type WococoFinality = BridgeWococoGrandpa; + type RococoFinality = BridgeRococoGrandpa; + type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; + type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; + type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1131,6 +964,13 @@ impl_runtime_apis! { type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; + type WococoFinality = BridgeWococoGrandpa; + type RococoFinality = BridgeRococoGrandpa; + type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; + type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; + type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_parachain, prepare_message_proof_from_parachain, @@ -1138,14 +978,13 @@ impl_runtime_apis! { }; use pallet_bridge_messages::benchmarking::{ Config as BridgeMessagesConfig, - Pallet as BridgeMessagesBench, MessageDeliveryProofParams, MessageProofParams, }; - impl BridgeMessagesConfig for Runtime { + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); + let bench_lane_id = >::bench_lane_id(); let bridged_chain_id = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, @@ -1165,7 +1004,7 @@ impl_runtime_apis! { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, - BridgeGrandpaWococoInstance, + bridge_common_config::BridgeGrandpaWococoInstance, bridge_hub_rococo_config::WithBridgeHubWococoMessageBridge, >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Rococo), Parachain(42)))) } @@ -1175,7 +1014,7 @@ impl_runtime_apis! { ) -> bridge_hub_rococo_config::ToWococoBridgeHubMessagesDeliveryProof { prepare_message_delivery_proof_from_parachain::< Runtime, - BridgeGrandpaWococoInstance, + bridge_common_config::BridgeGrandpaWococoInstance, bridge_hub_rococo_config::WithBridgeHubWococoMessageBridge, >(params) } @@ -1186,9 +1025,9 @@ impl_runtime_apis! { } } - impl BridgeMessagesConfig for Runtime { + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); + let bench_lane_id = >::bench_lane_id(); let bridged_chain_id = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, @@ -1208,7 +1047,7 @@ impl_runtime_apis! { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, - BridgeGrandpaRococoInstance, + bridge_common_config::BridgeGrandpaRococoInstance, bridge_hub_wococo_config::WithBridgeHubRococoMessageBridge, >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Wococo), Parachain(42)))) } @@ -1218,7 +1057,7 @@ impl_runtime_apis! { ) -> bridge_hub_wococo_config::ToRococoBridgeHubMessagesDeliveryProof { prepare_message_delivery_proof_from_parachain::< Runtime, - BridgeGrandpaRococoInstance, + bridge_common_config::BridgeGrandpaRococoInstance, bridge_hub_wococo_config::WithBridgeHubRococoMessageBridge, >(params) } @@ -1230,16 +1069,13 @@ impl_runtime_apis! { } use bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof; - use pallet_bridge_parachains::benchmarking::{ - Config as BridgeParachainsConfig, - Pallet as BridgeParachainsBench, - }; + use pallet_bridge_parachains::benchmarking::Config as BridgeParachainsConfig; use pallet_bridge_relayers::benchmarking::{ Pallet as BridgeRelayersBench, Config as BridgeRelayersConfig, }; - impl BridgeParachainsConfig for Runtime { + impl BridgeParachainsConfig for Runtime { fn parachains() -> Vec { use bp_runtime::Parachain; vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_wococo::BridgeHubWococo::PARACHAIN_ID)] @@ -1255,7 +1091,7 @@ impl_runtime_apis! { bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { - prepare_parachain_heads_proof::( + prepare_parachain_heads_proof::( parachains, parachain_head_size, proof_size, @@ -1263,7 +1099,7 @@ impl_runtime_apis! { } } - impl BridgeParachainsConfig for Runtime { + impl BridgeParachainsConfig for Runtime { fn parachains() -> Vec { use bp_runtime::Parachain; vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_rococo::BridgeHubRococo::PARACHAIN_ID)] @@ -1279,7 +1115,7 @@ impl_runtime_apis! { bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { - prepare_parachain_heads_proof::( + prepare_parachain_heads_proof::( parachains, parachain_head_size, proof_size, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 54c7c03fb60..c41900097a1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -22,12 +22,12 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_balances; -pub mod pallet_bridge_grandpa_bridge_rococo_grandpa; -pub mod pallet_bridge_grandpa_bridge_wococo_grandpa; -pub mod pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance; -pub mod pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance; -pub mod pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance; -pub mod pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance; +pub mod pallet_bridge_grandpa_rococo_finality; +pub mod pallet_bridge_grandpa_wococo_finality; +pub mod pallet_bridge_messages_rococo_to_wococo; +pub mod pallet_bridge_messages_wococo_to_rococo; +pub mod pallet_bridge_parachains_within_rococo; +pub mod pallet_bridge_parachains_within_wococo; pub mod pallet_bridge_relayers; pub mod pallet_collator_selection; pub mod pallet_multisig; @@ -50,13 +50,16 @@ use frame_support::weights::Weight; // import trait from dependency module use ::pallet_bridge_relayers::WeightInfoExt as _; -impl pallet_bridge_messages::WeightInfoExt for pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance::WeightInfo { +impl pallet_bridge_messages::WeightInfoExt + for pallet_bridge_messages_wococo_to_rococo::WeightInfo +{ fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE } fn receive_messages_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime() + pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( + ) } fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { @@ -64,13 +67,16 @@ impl pallet_bridge_messages::WeightInfoExt for pallet_bridge_messages_bridge_mes } } -impl pallet_bridge_messages::WeightInfoExt for pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_wococo_messages_instance::WeightInfo { +impl pallet_bridge_messages::WeightInfoExt + for pallet_bridge_messages_rococo_to_wococo::WeightInfo +{ fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE } fn receive_messages_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime() + pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( + ) } fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { @@ -78,13 +84,17 @@ impl pallet_bridge_messages::WeightInfoExt for pallet_bridge_messages_bridge_mes } } -impl pallet_bridge_parachains::WeightInfoExt for pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance::WeightInfo { +impl pallet_bridge_parachains::WeightInfoExt + for pallet_bridge_parachains_within_rococo::WeightInfo +{ fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE } } -impl pallet_bridge_parachains::WeightInfoExt for pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance::WeightInfo { +impl pallet_bridge_parachains::WeightInfoExt + for pallet_bridge_parachains_within_wococo::WeightInfo +{ fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs similarity index 80% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs index f646ddc3a38..e6d7cf53dc9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_bridge_rococo_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! 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-10-22, 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-t2sp1qqs-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 -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_bridge_grandpa -// --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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_grandpa +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -70,13 +68,13 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_grandpa::WeightInfo for WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) @@ -60,16 +60,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `404` + // Measured: `504` // Estimated: `52645` - // Minimum execution time: 43_991_000 picoseconds. - Weight::from_parts(45_465_000, 0) + // Minimum execution time: 42_043_000 picoseconds. + Weight::from_parts(43_557_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) @@ -78,16 +80,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `404` + // Measured: `504` // Estimated: `52645` - // Minimum execution time: 54_906_000 picoseconds. - Weight::from_parts(56_412_000, 0) + // Minimum execution time: 53_080_000 picoseconds. + Weight::from_parts(55_107_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) @@ -96,44 +100,48 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `404` + // Measured: `504` // Estimated: `52645` - // Minimum execution time: 48_906_000 picoseconds. - Weight::from_parts(51_665_000, 0) + // Minimum execution time: 47_757_000 picoseconds. + Weight::from_parts(49_024_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `372` + // Measured: `472` // Estimated: `52645` - // Minimum execution time: 42_784_000 picoseconds. - Weight::from_parts(44_788_000, 0) + // Minimum execution time: 41_434_000 picoseconds. + Weight::from_parts(42_468_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `372` + // Measured: `472` // Estimated: `52645` - // Minimum execution time: 75_805_000 picoseconds. - Weight::from_parts(77_731_000, 0) + // Minimum execution time: 76_285_000 picoseconds. + Weight::from_parts(77_717_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) @@ -150,8 +158,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `376` // Estimated: `3841` - // Minimum execution time: 32_012_000 picoseconds. - Weight::from_parts(32_653_000, 0) + // Minimum execution time: 31_296_000 picoseconds. + Weight::from_parts(32_147_000, 0) .saturating_add(Weight::from_parts(0, 3841)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -170,8 +178,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `376` // Estimated: `3841` - // Minimum execution time: 31_851_000 picoseconds. - Weight::from_parts(33_017_000, 0) + // Minimum execution time: 31_114_000 picoseconds. + Weight::from_parts(31_937_000, 0) .saturating_add(Weight::from_parts(0, 3841)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -190,20 +198,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `376` // Estimated: `6086` - // Minimum execution time: 34_818_000 picoseconds. - Weight::from_parts(35_728_000, 0) + // Minimum execution time: 33_620_000 picoseconds. + Weight::from_parts(34_604_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -212,8 +224,6 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// 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`) /// The range of component `i` is `[128, 2048]`. @@ -222,12 +232,12 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `672` // Estimated: `52645` - // Minimum execution time: 172_737_000 picoseconds. - Weight::from_parts(175_172_000, 0) + // Minimum execution time: 63_809_000 picoseconds. + Weight::from_parts(65_441_614, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 3_669 - .saturating_add(Weight::from_parts(1_013_545, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Standard Error: 61 + .saturating_add(Weight::from_parts(6_729, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs similarity index 81% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs index 7c25ae337ad..12015b962fe 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_bridge_messages_bench_runtime_with_bridge_hub_rococo_messages_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! 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-10-22, 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-t2sp1qqs-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 -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_bridge_messages -// --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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_messages +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,6 +50,8 @@ pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -60,16 +60,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `467` // Estimated: `52645` - // Minimum execution time: 43_473_000 picoseconds. - Weight::from_parts(44_789_000, 0) + // Minimum execution time: 41_613_000 picoseconds. + Weight::from_parts(42_942_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -78,16 +80,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `467` // Estimated: `52645` - // Minimum execution time: 53_826_000 picoseconds. - Weight::from_parts(61_945_000, 0) + // Minimum execution time: 52_657_000 picoseconds. + Weight::from_parts(54_020_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -96,44 +100,48 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `467` // Estimated: `52645` - // Minimum execution time: 48_194_000 picoseconds. - Weight::from_parts(50_311_000, 0) + // Minimum execution time: 47_484_000 picoseconds. + Weight::from_parts(48_318_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `435` // Estimated: `52645` - // Minimum execution time: 40_783_000 picoseconds. - Weight::from_parts(43_019_000, 0) + // Minimum execution time: 40_860_000 picoseconds. + Weight::from_parts(41_720_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `435` // Estimated: `52645` - // Minimum execution time: 74_259_000 picoseconds. - Weight::from_parts(76_009_000, 0) + // Minimum execution time: 75_743_000 picoseconds. + Weight::from_parts(76_862_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -150,8 +158,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `339` // Estimated: `3804` - // Minimum execution time: 31_323_000 picoseconds. - Weight::from_parts(32_282_000, 0) + // Minimum execution time: 30_195_000 picoseconds. + Weight::from_parts(31_047_000, 0) .saturating_add(Weight::from_parts(0, 3804)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -170,8 +178,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `339` // Estimated: `3804` - // Minimum execution time: 31_725_000 picoseconds. - Weight::from_parts(32_250_000, 0) + // Minimum execution time: 30_410_000 picoseconds. + Weight::from_parts(31_057_000, 0) .saturating_add(Weight::from_parts(0, 3804)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -190,20 +198,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `339` // Estimated: `6086` - // Minimum execution time: 34_244_000 picoseconds. - Weight::from_parts(35_033_000, 0) + // Minimum execution time: 33_096_000 picoseconds. + Weight::from_parts(33_710_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -212,8 +224,6 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// 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`) /// The range of component `i` is `[128, 2048]`. @@ -222,12 +232,12 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `635` // Estimated: `52645` - // Minimum execution time: 172_521_000 picoseconds. - Weight::from_parts(173_742_000, 0) + // Minimum execution time: 63_158_000 picoseconds. + Weight::from_parts(63_769_302, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 3_678 - .saturating_add(Weight::from_parts(1_012_559, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Standard Error: 35 + .saturating_add(Weight::from_parts(6_896, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs similarity index 85% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs index 147e8447ee8..1a125f4cd0e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_rococo_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! 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-10-22, 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-t2sp1qqs-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 -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_bridge_parachains -// --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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_parachains +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,15 +60,13 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { + fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `294` // Estimated: `2543` - // Minimum execution time: 33_519_000 picoseconds. - Weight::from_parts(34_527_779, 0) + // Minimum execution time: 31_409_000 picoseconds. + Weight::from_parts(32_561_631, 0) .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 45_887 - .saturating_add(Weight::from_parts(120_010, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -88,8 +84,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `294` // Estimated: `2543` - // Minimum execution time: 35_140_000 picoseconds. - Weight::from_parts(35_801_000, 0) + // Minimum execution time: 32_828_000 picoseconds. + Weight::from_parts(33_681_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -108,8 +104,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `294` // Estimated: `2543` - // Minimum execution time: 67_110_000 picoseconds. - Weight::from_parts(67_951_000, 0) + // Minimum execution time: 65_531_000 picoseconds. + Weight::from_parts(66_418_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs similarity index 88% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs index 432f9f9969d..02c350a0408 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_bridge_parachains_bench_runtime_bridge_parachain_wococo_instance.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! 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-10-22, 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-t2sp1qqs-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 -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_bridge_parachains -// --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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_parachains +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,8 +64,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `367` // Estimated: `2543` - // Minimum execution time: 34_968_000 picoseconds. - Weight::from_parts(36_202_569, 0) + // Minimum execution time: 32_627_000 picoseconds. + Weight::from_parts(33_806_957, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -86,8 +84,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `367` // Estimated: `2543` - // Minimum execution time: 36_607_000 picoseconds. - Weight::from_parts(37_304_000, 0) + // Minimum execution time: 34_360_000 picoseconds. + Weight::from_parts(35_212_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -106,8 +104,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `367` // Estimated: `2543` - // Minimum execution time: 68_548_000 picoseconds. - Weight::from_parts(69_402_000, 0) + // Minimum execution time: 66_678_000 picoseconds. + Weight::from_parts(67_571_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) 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 14de497cb99..703acfa4417 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 @@ -15,12 +15,15 @@ // along with Cumulus. If not, see . use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, BridgeGrandpaRococoInstance, - BridgeGrandpaWococoInstance, DeliveryRewardInBalance, FeeAssetId, ParachainInfo, - ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, - RuntimeEvent, RuntimeFlavor, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, + TransactionByteFee, WeightToFee, XcmpQueue, }; use crate::{ + bridge_common_config::{ + BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, + RequiredStakeForStakeAndSlash, + }, bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, bridge_hub_wococo_config::ToBridgeHubRococoHaulBlobExporter, }; 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 dcde07dc287..0109e4de4a9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -18,11 +18,11 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_hub_rococo_config, bridge_hub_wococo_config, + bridge_common_config, bridge_hub_rococo_config, bridge_hub_wococo_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, DeliveryRewardInBalance, - Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, - Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, + UncheckedExtrinsic, }; use codec::{Decode, Encode}; use frame_support::parameter_types; @@ -95,12 +95,13 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeWococoMessages(event)) => Some(event), + Ok(RuntimeEvent::BridgeRococoToWococoMessages(event)) => Some(event), _ => None, } }), @@ -299,12 +300,14 @@ mod bridge_hub_rococo_tests { mod bridge_hub_wococo_tests { use super::*; - use bridge_hub_rococo_runtime::{ - xcm_config, AllPalletsWithoutSystem, BridgeGrandpaRococoInstance, - BridgeParachainRococoInstance, RuntimeFlavor, WithBridgeHubRococoMessagesInstance, + use bridge_common_config::{ + BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, DeliveryRewardInBalance, + RequiredStakeForStakeAndSlash, }; + use bridge_hub_rococo_runtime::{xcm_config, AllPalletsWithoutSystem, RuntimeFlavor}; use bridge_hub_wococo_config::{ - WithBridgeHubRococoMessageBridge, DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + WithBridgeHubRococoMessageBridge, WithBridgeHubRococoMessagesInstance, + DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, }; use frame_support::assert_ok; @@ -416,7 +419,7 @@ mod bridge_hub_wococo_tests { SIBLING_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeRococoMessages(event)) => Some(event), + Ok(RuntimeEvent::BridgeWococoToRococoMessages(event)) => Some(event), _ => None, } }), diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 5de4a49f827..ca5583fe2e5 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -315,14 +315,16 @@ pub mod rococo { owner: bridges_pallet_owner.clone(), ..Default::default() }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() - }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { - owner: bridges_pallet_owner, - ..Default::default() - }, + bridge_wococo_to_rococo_messages: + bridge_hub_rococo_runtime::BridgeWococoToRococoMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_rococo_to_wococo_messages: + bridge_hub_rococo_runtime::BridgeRococoToWococoMessagesConfig { + owner: bridges_pallet_owner, + ..Default::default() + }, } } } -- GitLab From 95052437800dec7934f6804a77053e4552fc28e5 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:52:25 +0200 Subject: [PATCH 350/633] Re-enable Identity on Westend and Rococo (#1901) Reverts https://github.com/paritytech/polkadot-sdk/pull/1476 The `lock_pallet` / `unlock_pallet` additions in https://github.com/paritytech/polkadot-sdk/pull/1814 will result in less downtime for users than using runtime upgrades. --- polkadot/runtime/rococo/src/lib.rs | 19 ++++--------------- polkadot/runtime/westend/src/lib.rs | 15 ++------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 1e8e3ed01e0..3d6edc0ac1b 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -67,9 +67,9 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EverythingBut, - InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, - ProcessMessageError, StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, EitherOf, EitherOfDiverse, Everything, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, + StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -156,24 +156,13 @@ 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 = EverythingBut; + type BaseCallFilter = Everything; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type DbWeight = RocksDbWeight; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index a7ddfc52ce6..3d4db3cdd76 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, + fungible::HoldConsideration, ConstU32, EitherOf, EitherOfDiverse, Everything, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, }, @@ -160,24 +160,13 @@ 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 = EverythingBut; + type BaseCallFilter = Everything; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; -- GitLab From 5ca909cc09ca039d0fa4d61b02efb7ab85828c7c Mon Sep 17 00:00:00 2001 From: ordian Date: Mon, 23 Oct 2023 16:22:37 +0200 Subject: [PATCH 351/633] polkadot: eradicate `LeafStatus` (#1565) Fixes #768. --- Cargo.lock | 3 -- .../relay-chain-minimal-node/Cargo.toml | 1 - .../src/collator_overseer.rs | 4 +-- .../node/core/bitfield-signing/src/lib.rs | 14 ++------- polkadot/node/core/provisioner/src/lib.rs | 12 ++----- .../src/requester/mod.rs | 5 ++- polkadot/node/overseer/Cargo.toml | 1 - polkadot/node/overseer/src/dummy.rs | 3 -- polkadot/node/overseer/src/lib.rs | 31 ++++++------------- polkadot/node/service/Cargo.toml | 1 - polkadot/node/service/src/overseer.rs | 4 --- .../node/subsystem-test-helpers/src/mock.rs | 3 +- polkadot/node/subsystem-types/src/lib.rs | 31 ------------------- polkadot/node/subsystem/src/lib.rs | 2 +- .../src/types/overseer-protocol.md | 12 +------ 15 files changed, 21 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dcca22dd05..90fda2d0ecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3892,7 +3892,6 @@ dependencies = [ "sc-service", "sc-tracing", "sc-utils", - "schnellru", "sp-api", "sp-consensus", "sp-consensus-babe", @@ -12527,7 +12526,6 @@ dependencies = [ "polkadot-primitives-test-helpers", "prioritized-metered-channel", "sc-client-api", - "schnellru", "sp-api", "sp-core", "tikv-jemalloc-ctl", @@ -12914,7 +12912,6 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", - "schnellru", "serde", "serde_json", "serial_test", diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 51889865944..f132b1a7653 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -37,7 +37,6 @@ cumulus-relay-chain-rpc-interface = { path = "../relay-chain-rpc-interface" } cumulus-primitives-core = { path = "../../primitives/core" } array-bytes = "6.1" -schnellru = "0.2.1" tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" 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 49332cc350f..216ca0d3965 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -15,7 +15,6 @@ // along with Polkadot. If not, see . use futures::{select, StreamExt}; -use schnellru::{ByLength, LruMap}; use std::sync::Arc; use polkadot_availability_recovery::AvailabilityRecoverySubsystem; @@ -36,7 +35,7 @@ use polkadot_node_network_protocol::{ use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics}; use polkadot_overseer::{ BlockInfo, DummySubsystem, Handle, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, - UnpinHandle, KNOWN_LEAVES_CACHE_SIZE, + UnpinHandle, }; use polkadot_primitives::CollatorPair; @@ -156,7 +155,6 @@ fn build_overseer( .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_client) - .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .metrics(Metrics::register(registry)?) .spawner(spawner); diff --git a/polkadot/node/core/bitfield-signing/src/lib.rs b/polkadot/node/core/bitfield-signing/src/lib.rs index f29e827e109..0fc0bb3d278 100644 --- a/polkadot/node/core/bitfield-signing/src/lib.rs +++ b/polkadot/node/core/bitfield-signing/src/lib.rs @@ -32,8 +32,8 @@ use polkadot_node_subsystem::{ messages::{ AvailabilityStoreMessage, BitfieldDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, }, - overseer, ActivatedLeaf, FromOrchestra, LeafStatus, OverseerSignal, PerLeafSpan, - SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, + overseer, ActivatedLeaf, FromOrchestra, OverseerSignal, PerLeafSpan, SpawnedSubsystem, + SubsystemError, SubsystemResult, SubsystemSender, }; use polkadot_node_subsystem_util::{self as util, Validator}; use polkadot_primitives::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex}; @@ -257,16 +257,6 @@ async fn handle_active_leaves_update( where Sender: overseer::BitfieldSigningSenderTrait, { - if let LeafStatus::Stale = leaf.status { - gum::debug!( - target: LOG_TARGET, - relay_parent = ?leaf.hash, - block_number = ?leaf.number, - "Skip bitfield signing for stale leaf" - ); - return Ok(()) - } - let span = PerLeafSpan::new(leaf.span, "bitfield-signing"); let span_delay = span.child("delay"); let wait_until = Instant::now() + SPAWNED_TASK_DELAY; diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index f81e5550b15..8893bdc6549 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -31,8 +31,8 @@ use polkadot_node_subsystem::{ CandidateBackingMessage, ChainApiMessage, ProspectiveParachainsMessage, ProvisionableData, ProvisionerInherentData, ProvisionerMessage, RuntimeApiMessage, RuntimeApiRequest, }, - overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, - PerLeafSpan, RuntimeApiError, SpawnedSubsystem, SubsystemError, + overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, + RuntimeApiError, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ request_availability_cores, request_persisted_validation_data, @@ -421,13 +421,7 @@ async fn send_inherent_data( "Selected disputes" ); - // Only include bitfields on fresh leaves. On chain reversions, we want to make sure that - // there will be at least one block, which cannot get disputed, so the chain can make progress. - let bitfields = match leaf.status { - LeafStatus::Fresh => - select_availability_bitfields(&availability_cores, bitfields, &leaf.hash), - LeafStatus::Stale => Vec::new(), - }; + let bitfields = select_availability_bitfields(&availability_cores, bitfields, &leaf.hash); gum::trace!( target: LOG_TARGET, diff --git a/polkadot/node/network/availability-distribution/src/requester/mod.rs b/polkadot/node/network/availability-distribution/src/requester/mod.rs index 446988f7cc0..97e80d696e7 100644 --- a/polkadot/node/network/availability-distribution/src/requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/mod.rs @@ -35,7 +35,7 @@ use futures::{ use polkadot_node_subsystem::{ jaeger, messages::{ChainApiMessage, RuntimeApiMessage}, - overseer, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, + overseer, ActivatedLeaf, ActiveLeavesUpdate, }; use polkadot_node_subsystem_util::runtime::{get_occupied_cores, RuntimeInfo}; use polkadot_primitives::{CandidateHash, Hash, OccupiedCore, SessionIndex}; @@ -105,8 +105,7 @@ impl Requester { ) -> Result<()> { gum::trace!(target: LOG_TARGET, ?update, "Update fetching heads"); let ActiveLeavesUpdate { activated, deactivated } = update; - // Stale leaves happen after a reversion - we don't want to re-run availability there. - if let Some(leaf) = activated.filter(|leaf| leaf.status == LeafStatus::Fresh) { + if let Some(leaf) = activated { let span = spans .get(&leaf.hash) .map(|span| span.child("update-fetching-heads")) diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 5d41407ef83..376ebe0375b 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -18,7 +18,6 @@ polkadot-node-metrics = { path = "../metrics" } polkadot-primitives = { path = "../../primitives" } orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } gum = { package = "tracing-gum", path = "../gum" } -schnellru = "0.2.1" sp-core = { path = "../../../substrate/primitives/core" } async-trait = "0.1.57" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } diff --git a/polkadot/node/overseer/src/dummy.rs b/polkadot/node/overseer/src/dummy.rs index fea96e5dbab..fc5f0070773 100644 --- a/polkadot/node/overseer/src/dummy.rs +++ b/polkadot/node/overseer/src/dummy.rs @@ -17,11 +17,9 @@ use crate::{ prometheus::Registry, HeadSupportsParachains, InitializedOverseerBuilder, MetricsTrait, Overseer, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnGlue, - KNOWN_LEAVES_CACHE_SIZE, }; use orchestra::{FromOrchestra, SpawnedSubsystem, Subsystem, SubsystemContext}; use polkadot_node_subsystem_types::{errors::SubsystemError, messages::*}; -use schnellru::{ByLength, LruMap}; // Generated dummy messages use crate::messages::*; @@ -193,7 +191,6 @@ where .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) - .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .spawner(SpawnGlue(spawner)) .metrics(metrics) .supports_parachains(supports_parachains); diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 673569ab946..6802426d3c7 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -70,7 +70,6 @@ use std::{ }; use futures::{channel::oneshot, future::BoxFuture, select, Future, FutureExt, StreamExt}; -use schnellru::LruMap; use client::{BlockImportNotification, BlockchainEvents, FinalityNotification}; use polkadot_primitives::{Block, BlockNumber, Hash}; @@ -88,8 +87,8 @@ use polkadot_node_subsystem_types::messages::{ pub use polkadot_node_subsystem_types::{ errors::{SubsystemError, SubsystemResult}, - jaeger, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, OverseerSignal, - RuntimeApiSubsystemClient, UnpinHandle, + jaeger, ActivatedLeaf, ActiveLeavesUpdate, OverseerSignal, RuntimeApiSubsystemClient, + UnpinHandle, }; pub mod metrics; @@ -112,10 +111,6 @@ pub use orchestra::{ SubsystemSender, TimeoutExt, ToOrchestra, TrySendError, }; -/// Store 2 days worth of blocks, not accounting for forks, -/// in the LRU cache. Assumes a 6-second block time. -pub const KNOWN_LEAVES_CACHE_SIZE: u32 = 2 * 24 * 3600 / 6; - #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] mod memory_stats; #[cfg(test)] @@ -283,6 +278,11 @@ impl From> for BlockInfo { /// as the substrate framework or user interaction. pub enum Event { /// A new block was imported. + /// + /// This event is not sent if the block was already known + /// and we reorged to it e.g. due to a reversion. + /// + /// Also, these events are not sent during a major sync. BlockImported(BlockInfo), /// A block was finalized with i.e. babe or another consensus algorithm. BlockFinalized(BlockInfo), @@ -641,9 +641,6 @@ pub struct Overseer { /// An implementation for checking whether a header supports parachain consensus. pub supports_parachains: SupportsParachains, - /// An LRU cache for keeping track of relay-chain heads that have already been seen. - pub known_leaves: LruMap, - /// Various Prometheus metrics. pub metrics: OverseerMetrics, } @@ -802,10 +799,9 @@ where }; let mut update = match self.on_head_activated(&block.hash, Some(block.parent_hash)).await { - Some((span, status)) => ActiveLeavesUpdate::start_work(ActivatedLeaf { + Some(span) => ActiveLeavesUpdate::start_work(ActivatedLeaf { hash: block.hash, number: block.number, - status, unpin_handle: block.unpin_handle, span, }), @@ -864,7 +860,7 @@ where &mut self, hash: &Hash, parent_hash: Option, - ) -> Option<(Arc, LeafStatus)> { + ) -> Option> { if !self.supports_parachains.head_supports_parachains(hash).await { return None } @@ -891,14 +887,7 @@ where let span = Arc::new(span); self.span_per_active_leaf.insert(*hash, span.clone()); - let status = if self.known_leaves.get(hash).is_some() { - LeafStatus::Stale - } else { - self.known_leaves.insert(*hash, ()); - LeafStatus::Fresh - }; - - Some((span, status)) + Some(span) } fn on_head_deactivated(&mut self, hash: &Hash) { diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index ba5976fdcee..899a95dd3a7 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -86,7 +86,6 @@ parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } async-trait = "0.1.57" -schnellru = "0.2.1" log = "0.4.17" is_executable = "1.0.1" diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 7d1add11824..fd618863eea 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -40,7 +40,6 @@ use polkadot_overseer::{ metrics::Metrics as OverseerMetrics, InitializedOverseerBuilder, MetricsTrait, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, }; -use schnellru::{ByLength, LruMap}; use polkadot_primitives::runtime_api::ParachainHost; use sc_authority_discovery::Service as AuthorityDiscoveryService; @@ -342,7 +341,6 @@ where .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_api_client) - .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .metrics(metrics) .spawner(spawner); @@ -380,8 +378,6 @@ pub trait OverseerGen { // as consequence make this rather annoying to implement and use. } -use polkadot_overseer::KNOWN_LEAVES_CACHE_SIZE; - /// The regular set of subsystems. pub struct RealOverseerGen; diff --git a/polkadot/node/subsystem-test-helpers/src/mock.rs b/polkadot/node/subsystem-test-helpers/src/mock.rs index 35d74e27c9c..522bc3c2cc4 100644 --- a/polkadot/node/subsystem-test-helpers/src/mock.rs +++ b/polkadot/node/subsystem-test-helpers/src/mock.rs @@ -16,7 +16,7 @@ use std::sync::Arc; -use polkadot_node_subsystem::{jaeger, ActivatedLeaf, LeafStatus}; +use polkadot_node_subsystem::{jaeger, ActivatedLeaf}; use sc_client_api::UnpinHandle; use sc_keystore::LocalKeystore; use sc_utils::mpsc::tracing_unbounded; @@ -55,7 +55,6 @@ pub fn new_leaf(hash: Hash, number: BlockNumber) -> ActivatedLeaf { ActivatedLeaf { hash, number, - status: LeafStatus::Fresh, unpin_handle: dummy_unpin_handle(hash), span: Arc::new(jaeger::Span::Disabled), } diff --git a/polkadot/node/subsystem-types/src/lib.rs b/polkadot/node/subsystem-types/src/lib.rs index 02651ace1e5..e3d6e4decf2 100644 --- a/polkadot/node/subsystem-types/src/lib.rs +++ b/polkadot/node/subsystem-types/src/lib.rs @@ -51,35 +51,6 @@ pub use polkadot_node_jaeger as jaeger; /// If there are greater than this number of slots, then we fall back to a heap vector. const ACTIVE_LEAVES_SMALLVEC_CAPACITY: usize = 8; -/// The status of an activated leaf. -#[derive(Clone, Debug, PartialEq)] -pub enum LeafStatus { - /// A leaf is fresh when it's the first time the leaf has been encountered. - /// Most leaves should be fresh. - Fresh, - /// A leaf is stale when it's encountered for a subsequent time. This will happen - /// when the chain is reverted or the fork-choice rule abandons some chain. - Stale, -} - -impl LeafStatus { - /// Returns a `bool` indicating fresh status. - pub fn is_fresh(&self) -> bool { - match *self { - LeafStatus::Fresh => true, - LeafStatus::Stale => false, - } - } - - /// Returns a `bool` indicating stale status. - pub fn is_stale(&self) -> bool { - match *self { - LeafStatus::Fresh => false, - LeafStatus::Stale => true, - } - } -} - /// Activated leaf. #[derive(Debug, Clone)] pub struct ActivatedLeaf { @@ -87,8 +58,6 @@ pub struct ActivatedLeaf { pub hash: Hash, /// The block number. pub number: BlockNumber, - /// The status of the leaf. - pub status: LeafStatus, /// A handle to unpin the block on drop. pub unpin_handle: UnpinHandle, /// An associated [`jaeger::Span`]. diff --git a/polkadot/node/subsystem/src/lib.rs b/polkadot/node/subsystem/src/lib.rs index df379f2d97b..8b407c75a0c 100644 --- a/polkadot/node/subsystem/src/lib.rs +++ b/polkadot/node/subsystem/src/lib.rs @@ -28,7 +28,7 @@ pub use polkadot_overseer::{self as overseer, *}; pub use polkadot_node_subsystem_types::{ errors::{self, *}, - ActivatedLeaf, LeafStatus, + ActivatedLeaf, }; /// Re-export of all messages type, including the wrapper type. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index fababbff354..54cdc2edd12 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -32,18 +32,8 @@ Indicates a change in active leaves. Activated leaves should have jobs, whereas winding-down of work based on those leaves. ```rust -enum LeafStatus { - // A leaf is fresh when it's the first time the leaf has been encountered. - // Most leaves should be fresh. - Fresh, - // A leaf is stale when it's encountered for a subsequent time. This will - // happen when the chain is reverted or the fork-choice rule abandons some - // chain. - Stale, -} - struct ActiveLeavesUpdate { - activated: [(Hash, Number, LeafStatus)], // in practice, these should probably be a SmallVec + activated: [(Hash, Number)], deactivated: [Hash], } ``` -- GitLab From 676bacd7299826fb0ea88055d2108f3c6a734291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 23 Oct 2023 17:06:04 +0200 Subject: [PATCH 352/633] Always schedule at least one job onto a core (#1990) Even if the host configuration is returning `0` for the `lookahead`, we should schedule at least one job on a core if the core exists. --- polkadot/runtime/parachains/src/scheduler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index af48019124d..f3333d5cf85 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -627,8 +627,8 @@ impl Pallet { if ValidatorGroups::::decode_len().map_or(true, |l| l == 0) { return } - - let n_lookahead = Self::claimqueue_lookahead(); + // If there exists a core, ensure we schedule at least one job onto it. + let n_lookahead = Self::claimqueue_lookahead().max(1); let n_session_cores = T::AssignmentProvider::session_core_count(); let cq = ClaimQueue::::get(); let ttl = >::config().on_demand_ttl; -- GitLab From d0fd2660031b92a3896db3ea47e65f6f8af9a9ae Mon Sep 17 00:00:00 2001 From: Muharem Date: Mon, 23 Oct 2023 19:14:52 +0200 Subject: [PATCH 353/633] Resolve Credit to Account impls of `OnUnbalanced` trait (#1876) Implements the `OnUnbalanced` trait to resolve received credits to the specified account. Credits that fail to resolve are dropped. ### Motivation Throughout the codebase, several types implement the trait with the same behavior. While some currently utilize older currency trait, a migration to the new fungible/s is anticipated for all. Examples: [1](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/cumulus/parachains/common/src/impls.rs#L37), [2](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/polkadot/runtime/common/src/impls.rs#L36), [3](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/substrate/bin/node/runtime/src/impls.rs#L40), [4](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/substrate/bin/node/runtime/src/lib.rs#L1969), [5](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/substrate/frame/broker/src/mock.rs#L198), [6](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/substrate/frame/society/src/lib.rs#L2031), [7](https://github.com/paritytech/polkadot-sdk/blob/1b34571c0c423115813034783ddf524aac257bf5/substrate/frame/treasury/src/lib.rs#L1118) --- .../support/src/traits/tokens/imbalance.rs | 2 +- .../traits/tokens/imbalance/on_unbalanced.rs | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/imbalance.rs b/substrate/frame/support/src/traits/tokens/imbalance.rs index e487b812234..9dd8531324d 100644 --- a/substrate/frame/support/src/traits/tokens/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/imbalance.rs @@ -25,7 +25,7 @@ use sp_std::ops::Div; mod on_unbalanced; mod signed_imbalance; mod split_two_ways; -pub use on_unbalanced::OnUnbalanced; +pub use on_unbalanced::{OnUnbalanced, ResolveAssetTo, ResolveTo}; pub use signed_imbalance::SignedImbalance; pub use split_two_ways::SplitTwoWays; diff --git a/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs b/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs index 27bfe46e181..ecb8de8841f 100644 --- a/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs +++ b/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs @@ -17,7 +17,9 @@ //! Trait for handling imbalances. -use crate::traits::misc::TryDrop; +use frame_support::traits::{fungible, fungibles, misc::TryDrop}; +use sp_core::TypedGet; +use sp_std::marker::PhantomData; /// Handler for when some currency "account" decreased in balance for /// some reason. @@ -53,3 +55,29 @@ pub trait OnUnbalanced { } impl OnUnbalanced for () {} + +/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`]. +/// +/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for +/// address `A` does not exist and the existential deposit requirement is not met. +pub struct ResolveTo(PhantomData<(A, F)>); +impl> OnUnbalanced> + for ResolveTo +{ + fn on_nonzero_unbalanced(credit: fungible::Credit) { + let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c)); + } +} + +/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`]. +/// +/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for +/// address `A` does not exist and the existential deposit requirement is not met. +pub struct ResolveAssetTo(PhantomData<(A, F)>); +impl> OnUnbalanced> + for ResolveAssetTo +{ + fn on_nonzero_unbalanced(credit: fungibles::Credit) { + let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c)); + } +} -- GitLab From 39c04fdd9622792ba8478b1c1c300417943a034b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 23 Oct 2023 21:52:30 -0600 Subject: [PATCH 354/633] Update wasm-opt to 0.116 (#1995) Just keeping wasm-opt up to date. I don't see anything in the [binaryen changelog](https://github.com/WebAssembly/binaryen/blob/main/CHANGELOG.md) that should affect substrate. This release includes dwarf passes that were accidentally omitted from previous versions of the wasm-opt crate. I suspect this will not affect substrate as their omission hasn't been noticed until recently. --- Cargo.lock | 12 ++++++------ substrate/utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90fda2d0ecc..a8d679c6ce8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19522,9 +19522,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.114.1" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7" +checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" dependencies = [ "anyhow", "libc", @@ -19538,9 +19538,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.114.1" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d04e240598162810fad3b2e96fa0dec6dba1eb65a03f3bd99a9248ab8b56caa" +checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" dependencies = [ "anyhow", "cxx", @@ -19550,9 +19550,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.114.1" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efd2aaca519d64098c4faefc8b7433a97ed511caf4c9e516384eb6aef1ff4f9" +checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" dependencies = [ "anyhow", "cc", diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 73586ebe614..2550122ad4b 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -22,5 +22,5 @@ toml = "0.7.3" walkdir = "2.3.2" sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } filetime = "0.2.16" -wasm-opt = "0.114" +wasm-opt = "0.116" parity-wasm = "0.45" -- GitLab From a5a2432d22d199e595a776d39233663dce858125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 24 Oct 2023 11:55:46 +0200 Subject: [PATCH 355/633] `CheckWeight`: Add more logging (#1996) This adds more logging to `CheckWeight` to get a better understanding why a transaction exhausts resources. --- substrate/frame/support/src/dispatch.rs | 2 +- .../system/src/extensions/check_weight.rs | 64 ++++++++++++++++--- substrate/primitives/weights/src/weight_v2.rs | 5 +- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 75e94827fea..e6a090ebcae 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -390,7 +390,7 @@ impl GetDispatchInfo } /// A struct holding value for each `DispatchClass`. -#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct PerDispatchClass { /// Value for `Normal` extrinsics. normal: T, diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 1030c8daf7b..70d1e756332 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{limits::BlockWeights, Config, Pallet}; +use crate::{limits::BlockWeights, Config, Pallet, LOG_TARGET}; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, PostDispatchInfo}, @@ -50,8 +50,16 @@ where ) -> Result<(), TransactionValidityError> { let max = T::BlockWeights::get().get(info.class).max_extrinsic; match max { - Some(max) if info.weight.any_gt(max) => - Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if info.weight.any_gt(max) => { + log::debug!( + target: LOG_TARGET, + "Extrinsic {} is greater than the max extrinsic {}", + info.weight, + max, + ); + + Err(InvalidTransaction::ExhaustsResources.into()) + }, _ => Ok(()), } } @@ -79,6 +87,13 @@ where let added_len = len as u32; let next_len = current_len.saturating_add(added_len); if next_len > *length_limit.max.get(info.class) { + log::debug!( + target: LOG_TARGET, + "Exceeded block length limit: {} > {}", + next_len, + length_limit.max.get(info.class), + ); + Err(InvalidTransaction::ExhaustsResources.into()) } else { Ok(next_len) @@ -137,17 +152,28 @@ where if limit_per_class.max_total.is_none() && limit_per_class.reserved.is_none() { all_weight.accrue(extrinsic_weight, info.class) } else { - all_weight - .checked_accrue(extrinsic_weight, info.class) - .map_err(|_| InvalidTransaction::ExhaustsResources)?; + all_weight.checked_accrue(extrinsic_weight, info.class).map_err(|_| { + log::debug!( + target: LOG_TARGET, + "All weight checked add overflow.", + ); + + InvalidTransaction::ExhaustsResources + })?; } let per_class = *all_weight.get(info.class); // Check if we don't exceed per-class allowance match limit_per_class.max_total { - Some(max) if per_class.any_gt(max) => - return Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if per_class.any_gt(max) => { + log::debug!( + target: LOG_TARGET, + "Exceeded the per-class allowance.", + ); + + return Err(InvalidTransaction::ExhaustsResources.into()) + }, // There is no `max_total` limit (`None`), // or we are below the limit. _ => {}, @@ -158,8 +184,14 @@ where if all_weight.total().any_gt(maximum_weight.max_block) { match limit_per_class.reserved { // We are over the limit in reserved pool. - Some(reserved) if per_class.any_gt(reserved) => - return Err(InvalidTransaction::ExhaustsResources.into()), + Some(reserved) if per_class.any_gt(reserved) => { + log::debug!( + target: LOG_TARGET, + "Total block weight is exceeded.", + ); + + return Err(InvalidTransaction::ExhaustsResources.into()) + }, // There is either no limit in reserved pool (`None`), // or we are below the limit. _ => {}, @@ -233,6 +265,18 @@ where }) } + log::trace!( + target: LOG_TARGET, + "Used block weight: {:?}", + crate::BlockWeight::::get(), + ); + + log::trace!( + target: LOG_TARGET, + "Used block length: {:?}", + Pallet::::all_extrinsics_len(), + ); + Ok(()) } } diff --git a/substrate/primitives/weights/src/weight_v2.rs b/substrate/primitives/weights/src/weight_v2.rs index 3946cfe42c8..d692aaff8f5 100644 --- a/substrate/primitives/weights/src/weight_v2.rs +++ b/substrate/primitives/weights/src/weight_v2.rs @@ -18,13 +18,10 @@ use codec::{Decode, Encode, MaxEncodedLen}; use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; use sp_arithmetic::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; -use sp_debug_derive::RuntimeDebug; use super::*; -#[derive( - Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, -)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Weight { #[codec(compact)] -- GitLab From 35eb133baab93d3f2f179df216b2cc175d7dcaf2 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:01:04 +0100 Subject: [PATCH 356/633] Ensure correct variant count in `Runtime[Hold/Freeze]Reason` (#1900) closes https://github.com/paritytech/polkadot-sdk/issues/1882 ## Breaking Changes This PR introduces a new item to `pallet_balances::Config`: ```diff trait Config { ++ type RuntimeFreezeReasons; } ``` This value is only used to check it against `type MaxFreeze`. A similar check has been added for `MaxHolds` against `RuntimeHoldReasons`, which is already given to `pallet_balances`. In all contexts, you should pass the real `RuntimeFreezeReasons` generated by `construct_runtime` to `type RuntimeFreezeReasons`. Passing `()` would also work, but it would imply that the runtime uses no freezes at all. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- bridges/bin/runtime-common/src/mock.rs | 1 + bridges/modules/messages/src/mock.rs | 1 + bridges/modules/relayers/src/mock.rs | 1 + .../pallets/collator-selection/src/mock.rs | 1 + cumulus/pallets/xcmp-queue/src/mock.rs | 1 + cumulus/parachain-template/runtime/src/lib.rs | 1 + cumulus/parachains/common/src/impls.rs | 1 + .../assets/asset-hub-kusama/src/lib.rs | 1 + .../assets/asset-hub-polkadot/src/lib.rs | 1 + .../assets/asset-hub-rococo/src/lib.rs | 1 + .../assets/asset-hub-westend/src/lib.rs | 1 + .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 1 + .../bridge-hub-polkadot/src/lib.rs | 1 + .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 1 + .../collectives-polkadot/src/lib.rs | 1 + .../contracts/contracts-rococo/src/lib.rs | 1 + .../runtimes/testing/penpal/src/lib.rs | 1 + .../testing/rococo-parachain/src/lib.rs | 1 + cumulus/test/runtime/src/lib.rs | 1 + .../runtime/common/src/assigned_slots/mod.rs | 1 + polkadot/runtime/common/src/auctions.rs | 1 + polkadot/runtime/common/src/claims.rs | 1 + polkadot/runtime/common/src/crowdloan/mod.rs | 1 + polkadot/runtime/common/src/impls.rs | 1 + .../runtime/common/src/integration_tests.rs | 1 + .../runtime/common/src/paras_registrar/mod.rs | 1 + polkadot/runtime/common/src/purchase.rs | 1 + polkadot/runtime/common/src/slots/mod.rs | 1 + polkadot/runtime/parachains/src/mock.rs | 1 + polkadot/runtime/rococo/src/lib.rs | 8 ++++--- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + polkadot/xcm/pallet-xcm/src/mock.rs | 1 + .../xcm/xcm-builder/src/tests/pay/mock.rs | 1 + polkadot/xcm/xcm-builder/tests/mock/mod.rs | 1 + .../xcm-simulator/example/src/parachain.rs | 1 + .../xcm-simulator/example/src/relay_chain.rs | 1 + .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 1 + .../xcm-simulator/fuzzer/src/relay_chain.rs | 1 + .../bin/node-template/runtime/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 5 ++-- substrate/frame/alliance/src/mock.rs | 1 + substrate/frame/asset-conversion/src/mock.rs | 1 + substrate/frame/asset-rate/src/mock.rs | 1 + substrate/frame/assets/src/mock.rs | 1 + substrate/frame/atomic-swap/src/tests.rs | 1 + substrate/frame/babe/src/mock.rs | 1 + substrate/frame/balances/src/lib.rs | 23 +++++++++++++++++-- substrate/frame/balances/src/tests/mod.rs | 9 ++++++-- substrate/frame/beefy/src/mock.rs | 1 + substrate/frame/bounties/src/tests.rs | 1 + substrate/frame/child-bounties/src/tests.rs | 1 + substrate/frame/contracts/src/tests.rs | 1 + .../frame/conviction-voting/src/tests.rs | 1 + substrate/frame/democracy/src/tests.rs | 1 + .../election-provider-multi-phase/src/mock.rs | 1 + .../test-staking-e2e/src/mock.rs | 1 + substrate/frame/elections-phragmen/src/lib.rs | 1 + substrate/frame/examples/basic/src/tests.rs | 1 + .../frame/examples/dev-mode/src/tests.rs | 1 + .../frame/examples/kitchensink/src/tests.rs | 1 + substrate/frame/executive/src/lib.rs | 1 + substrate/frame/fast-unstake/src/mock.rs | 1 + substrate/frame/grandpa/src/mock.rs | 1 + substrate/frame/identity/src/tests.rs | 1 + substrate/frame/indices/src/mock.rs | 1 + substrate/frame/lottery/src/mock.rs | 1 + .../frame/nft-fractionalization/src/mock.rs | 1 + substrate/frame/nfts/src/mock.rs | 1 + substrate/frame/nicks/src/lib.rs | 1 + substrate/frame/nis/src/mock.rs | 2 ++ .../nomination-pools/benchmarking/src/mock.rs | 1 + substrate/frame/nomination-pools/src/mock.rs | 1 + .../nomination-pools/test-staking/src/mock.rs | 1 + .../frame/offences/benchmarking/src/mock.rs | 1 + substrate/frame/preimage/src/mock.rs | 1 + substrate/frame/recovery/src/mock.rs | 1 + substrate/frame/referenda/src/mock.rs | 1 + substrate/frame/root-offences/src/mock.rs | 1 + substrate/frame/safe-mode/src/mock.rs | 1 + substrate/frame/scored-pool/src/mock.rs | 1 + .../frame/session/benchmarking/src/mock.rs | 1 + substrate/frame/society/src/mock.rs | 1 + substrate/frame/staking/src/mock.rs | 1 + .../frame/state-trie-migration/src/lib.rs | 1 + substrate/frame/statement/src/mock.rs | 1 + .../construct_runtime/expand/freeze_reason.rs | 5 ++++ .../construct_runtime/expand/hold_reason.rs | 5 ++++ substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/misc.rs | 12 ++++++++++ substrate/frame/tips/src/tests.rs | 1 + .../asset-conversion-tx-payment/src/mock.rs | 1 + .../asset-tx-payment/src/mock.rs | 1 + .../frame/transaction-payment/src/mock.rs | 1 + .../frame/transaction-storage/src/mock.rs | 1 + substrate/frame/treasury/src/tests.rs | 1 + substrate/frame/tx-pause/src/mock.rs | 1 + substrate/frame/uniques/src/mock.rs | 1 + substrate/frame/utility/src/tests.rs | 1 + substrate/frame/vesting/src/mock.rs | 1 + substrate/frame/whitelist/src/mock.rs | 1 + substrate/test-utils/runtime/src/lib.rs | 1 + 102 files changed, 154 insertions(+), 10 deletions(-) diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 45ef790d744..67ae974668e 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -190,6 +190,7 @@ impl pallet_balances::Config for TestRuntime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs index aebb7eafa78..e98f9e1f5de 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/mock.rs @@ -130,6 +130,7 @@ impl pallet_balances::Config for TestRuntime { type MaxReserves = (); type ReserveIdentifier = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 4713ec91658..d19d47eec5c 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -98,6 +98,7 @@ impl pallet_balances::Config for TestRuntime { type MaxReserves = ConstU32<1>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index 44d531c971e..46143674bb3 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -92,6 +92,7 @@ impl pallet_balances::Config for Test { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index bc0710e3465..8f567aac2f6 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -98,6 +98,7 @@ impl pallet_balances::Config for Test { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index b6bf8419ec4..bfb3e74be9c 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -353,6 +353,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 107cd5c6873..81d78baba54 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -192,6 +192,7 @@ mod tests { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; 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 5c51a3a5232..bc17fcada23 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -225,6 +225,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); // We allow each account to have holds on it from: // - `NftFractionalization`: 1 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 b58d094deec..7033e1c2dca 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -235,6 +235,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 20b59368a5b..f57cfda1428 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -231,6 +231,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); // We allow each account to have holds on it from: // - `NftFractionalization`: 1 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 a7dc3a84777..c090536b3da 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -203,6 +203,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); // We allow each account to have holds on it from: // - `NftFractionalization`: 1 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 190987b1cfe..9fdf8380bc3 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 @@ -249,6 +249,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; 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 dc23135f05d..6ce1df99295 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 @@ -249,6 +249,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; 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 5973801d37c..326acc812a2 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 @@ -305,6 +305,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index cec4152bcc3..edfbfa851fe 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -215,6 +215,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 1ea3eaa2e47..71733d48e81 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -219,6 +219,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 86389425eb5..522cbf1face 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -399,6 +399,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index dcea349f3a0..0523f0ad978 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -248,6 +248,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index ccf624c0ffa..e9b242ac638 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -250,6 +250,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index cc8ec339c11..cb2e5083b0a 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -720,6 +720,7 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index e35303912fa..267413eb1ba 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -747,6 +747,7 @@ mod tests { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 0c736a63284..548adc6fbd5 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -780,6 +780,7 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 5a293914592..f67fc12a67f 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -941,6 +941,7 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 590593745ed..e50ffb634b3 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -274,6 +274,7 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index f14db68267d..d5a32775fd4 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -181,6 +181,7 @@ impl pallet_balances::Config for Test { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 8b8c6d89d01..2d33cf28993 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -792,6 +792,7 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 58ca19d0288..bc95483dd7e 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -552,6 +552,7 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/common/src/slots/mod.rs b/polkadot/runtime/common/src/slots/mod.rs index a3efd5bfa30..01f6365b791 100644 --- a/polkadot/runtime/common/src/slots/mod.rs +++ b/polkadot/runtime/common/src/slots/mod.rs @@ -570,6 +570,7 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<1>; type MaxFreezes = ConstU32<1>; diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index ded7de08e4f..9df54bf29d3 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -135,6 +135,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 3d6edc0ac1b..cc12920ff82 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -297,7 +297,8 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = RuntimeHoldReason; - type MaxHolds = ConstU32<1>; + type RuntimeFreezeReason = RuntimeFreezeReason; + type MaxHolds = ConstU32<2>; } parameter_types! { @@ -1084,9 +1085,10 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = weights::pallet_balances_nis_counterpart_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type MaxHolds = ConstU32<2>; + type MaxFreezes = ConstU32<1>; } parameter_types! { diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 99fd2198400..888477366d4 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -229,6 +229,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 3d4db3cdd76..d166c8a3326 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -292,6 +292,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; type MaxHolds = ConstU32<1>; diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index a85fe0fa2af..afa956c3cda 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -274,6 +274,7 @@ impl pallet_balances::Config for Test { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 5b6fa3ee5a0..e51bd952177 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -75,6 +75,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 19ced591951..5fcba5e2f54 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -119,6 +119,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index bc7cba31382..fa9d3300619 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -106,6 +106,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 4e9195a8454..0fba4cb270d 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -92,6 +92,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 95f875eca06..f9ad0252285 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -95,6 +95,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index a29ead9e6c3..756cf4803b1 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -91,6 +91,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; diff --git a/substrate/bin/node-template/runtime/src/lib.rs b/substrate/bin/node-template/runtime/src/lib.rs index 4653b49bf2c..62c24081cbe 100644 --- a/substrate/bin/node-template/runtime/src/lib.rs +++ b/substrate/bin/node-template/runtime/src/lib.rs @@ -251,6 +251,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 2070e3f12d0..36ad4d985cf 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -512,6 +512,8 @@ parameter_types! { } impl pallet_balances::Config for Runtime { + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxLocks = MaxLocks; type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; @@ -523,8 +525,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; - type RuntimeHoldReason = RuntimeHoldReason; - type MaxHolds = ConstU32<2>; + type MaxHolds = ConstU32<5>; } parameter_types! { diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 82dbbe9c0bb..eac8411699e 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -69,6 +69,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 3a19f39e7ca..4eee701f193 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -87,6 +87,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/asset-rate/src/mock.rs b/substrate/frame/asset-rate/src/mock.rs index 5fe0d4240af..9ca0f0f3cc3 100644 --- a/substrate/frame/asset-rate/src/mock.rs +++ b/substrate/frame/asset-rate/src/mock.rs @@ -73,6 +73,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = (); type MaxFreezes = (); diff --git a/substrate/frame/assets/src/mock.rs b/substrate/frame/assets/src/mock.rs index 32ad02da904..2c2203bcdad 100644 --- a/substrate/frame/assets/src/mock.rs +++ b/substrate/frame/assets/src/mock.rs @@ -83,6 +83,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type FreezeIdentifier = (); type MaxHolds = (); type MaxFreezes = (); diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index e20e1df564c..92eb9a04458 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -77,6 +77,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index a3f755902b5..e0b23afaf66 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -125,6 +125,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index c294779a0e0..c6a2252df61 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -207,7 +207,7 @@ pub mod pallet { use super::*; use frame_support::{ pallet_prelude::*, - traits::{fungible::Credit, tokens::Precision}, + traits::{fungible::Credit, tokens::Precision, VariantCount}, }; use frame_system::pallet_prelude::*; @@ -229,6 +229,8 @@ pub mod pallet { type RuntimeEvent = (); #[inject_runtime_type] type RuntimeHoldReason = (); + #[inject_runtime_type] + type RuntimeFreezeReason = (); type Balance = u64; type ExistentialDeposit = ConstU64<1>; @@ -256,7 +258,11 @@ pub mod pallet { /// The overarching hold reason. #[pallet::no_default_bounds] - type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Copy; + type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Copy + VariantCount; + + /// The overarching freeze reason. + #[pallet::no_default_bounds] + type RuntimeFreezeReason: VariantCount; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -544,6 +550,19 @@ pub mod pallet { !>::ExistentialDeposit::get().is_zero(), "The existential deposit must be greater than zero!" ); + + assert!( + T::MaxHolds::get() >= ::VARIANT_COUNT, + "MaxHolds should be greater than or equal to the number of hold reasons: {} < {}", + T::MaxHolds::get(), + ::VARIANT_COUNT + ); + + assert!( + T::MaxFreezes::get() >= ::VARIANT_COUNT, + "MaxFreezes should be greater than or equal to the number of freeze reasons: {} < {}", + T::MaxFreezes::get(), ::VARIANT_COUNT, + ); } } diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index a0a3085c54f..dd3e5b7a85a 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -27,7 +27,7 @@ use frame_support::{ parameter_types, traits::{ fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, - StorageMapShim, StoredMap, WhitelistedStorageKeys, + StorageMapShim, StoredMap, VariantCount, WhitelistedStorageKeys, }, weights::{IdentityFee, Weight}, }; @@ -70,6 +70,10 @@ pub enum TestId { Baz, } +impl VariantCount for TestId { + const VARIANT_COUNT: u32 = 3; +} + frame_support::construct_runtime!( pub struct Test { @@ -132,9 +136,10 @@ impl Config for Test { type ReserveIdentifier = TestId; type WeightInfo = (); type RuntimeHoldReason = TestId; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = TestId; type MaxFreezes = ConstU32<2>; - type MaxHolds = ConstU32<2>; + type MaxHolds = ConstU32<3>; } #[derive(Clone)] diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 9480fd0406d..8618fdab19a 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -135,6 +135,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); type FreezeIdentifier = (); type MaxFreezes = (); diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 4083b05b629..233e41b474c 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -98,6 +98,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 1fa3d944f3d..46f8fa65dd3 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -101,6 +101,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 0fea2b15595..3cc5e7cf4a1 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -370,6 +370,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; } diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index 656112deebf..850b98b218b 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -90,6 +90,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index ebccf32e342..07a0ef5c3d5 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -140,6 +140,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index d4659eba566..92144351e8f 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -253,6 +253,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } 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 2e3cb15f9a4..9195945f6ca 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 @@ -114,6 +114,7 @@ impl pallet_balances::Config for Runtime { type MaxHolds = ConstU32<1>; type MaxFreezes = traits::ConstU32<1>; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type WeightInfo = (); } diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 93f9fc2b6d2..e4c56e68f9a 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -1360,6 +1360,7 @@ mod tests { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index addf219dc3c..c7b5b9e9a84 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -84,6 +84,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/examples/dev-mode/src/tests.rs b/substrate/frame/examples/dev-mode/src/tests.rs index ba98f5174ce..c7722bc0524 100644 --- a/substrate/frame/examples/dev-mode/src/tests.rs +++ b/substrate/frame/examples/dev-mode/src/tests.rs @@ -78,6 +78,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = (); } diff --git a/substrate/frame/examples/kitchensink/src/tests.rs b/substrate/frame/examples/kitchensink/src/tests.rs index abded83e482..3b88f68d1c3 100644 --- a/substrate/frame/examples/kitchensink/src/tests.rs +++ b/substrate/frame/examples/kitchensink/src/tests.rs @@ -56,6 +56,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 1d9afdfa60a..a4b12c6d31d 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -904,6 +904,7 @@ mod tests { type FreezeIdentifier = (); type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = ConstU32<1>; } diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index cf274c784f9..6b866224ab9 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -76,6 +76,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index fd4d737dc49..79e3069d01d 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -141,6 +141,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 1532980574c..6bfd15b4aae 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -83,6 +83,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/indices/src/mock.rs b/substrate/frame/indices/src/mock.rs index d63081e0b73..7dc6730d34e 100644 --- a/substrate/frame/indices/src/mock.rs +++ b/substrate/frame/indices/src/mock.rs @@ -74,6 +74,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/lottery/src/mock.rs b/substrate/frame/lottery/src/mock.rs index aefb6a1cce2..e50ec3441b2 100644 --- a/substrate/frame/lottery/src/mock.rs +++ b/substrate/frame/lottery/src/mock.rs @@ -86,6 +86,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index c690f0e580e..987c65a8954 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -86,6 +86,7 @@ impl pallet_balances::Config for Test { type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; type FreezeIdentifier = (); type MaxFreezes = (); diff --git a/substrate/frame/nfts/src/mock.rs b/substrate/frame/nfts/src/mock.rs index f091a53f8d7..248522aafff 100644 --- a/substrate/frame/nfts/src/mock.rs +++ b/substrate/frame/nfts/src/mock.rs @@ -85,6 +85,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nicks/src/lib.rs b/substrate/frame/nicks/src/lib.rs index 0a68f7d7142..ad30c628adf 100644 --- a/substrate/frame/nicks/src/lib.rs +++ b/substrate/frame/nicks/src/lib.rs @@ -313,6 +313,7 @@ mod tests { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nis/src/mock.rs b/substrate/frame/nis/src/mock.rs index 76fdf5f3f06..30f7ef95f33 100644 --- a/substrate/frame/nis/src/mock.rs +++ b/substrate/frame/nis/src/mock.rs @@ -89,6 +89,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; } @@ -109,6 +110,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 1e6a5c24999..3cbaed23835 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -77,6 +77,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index d806ba071bd..d683994c28d 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -247,6 +247,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index 54f578f861e..c36dc70cb46 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -88,6 +88,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index 88f418dd3e2..c877f955fba 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -79,6 +79,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs index 2e7051a99a4..0f966312d9e 100644 --- a/substrate/frame/preimage/src/mock.rs +++ b/substrate/frame/preimage/src/mock.rs @@ -82,6 +82,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = ConstU32<2>; } diff --git a/substrate/frame/recovery/src/mock.rs b/substrate/frame/recovery/src/mock.rs index 2f2bd866a71..bc81d07bec2 100644 --- a/substrate/frame/recovery/src/mock.rs +++ b/substrate/frame/recovery/src/mock.rs @@ -84,6 +84,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index dce91f7dbfd..345accbe268 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -116,6 +116,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 2d2a5476149..59ab539fcf6 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -123,6 +123,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/safe-mode/src/mock.rs b/substrate/frame/safe-mode/src/mock.rs index 635ee0cfedc..10afe5bd4b5 100644 --- a/substrate/frame/safe-mode/src/mock.rs +++ b/substrate/frame/safe-mode/src/mock.rs @@ -79,6 +79,7 @@ impl pallet_balances::Config for Test { type MaxReserves = ConstU32<10>; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxHolds = ConstU32<10>; type MaxFreezes = ConstU32<0>; diff --git a/substrate/frame/scored-pool/src/mock.rs b/substrate/frame/scored-pool/src/mock.rs index 591c910488b..32a66c0cdc5 100644 --- a/substrate/frame/scored-pool/src/mock.rs +++ b/substrate/frame/scored-pool/src/mock.rs @@ -90,6 +90,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 24a821ac87a..d3da12ef9a8 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -84,6 +84,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/society/src/mock.rs b/substrate/frame/society/src/mock.rs index a318c2e794b..0bee08236f7 100644 --- a/substrate/frame/society/src/mock.rs +++ b/substrate/frame/society/src/mock.rs @@ -97,6 +97,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 26d05d3a8c8..c694ce004dd 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -162,6 +162,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index 3e69b219bb5..ac3996459cd 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -1126,6 +1126,7 @@ mod mock { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/statement/src/mock.rs b/substrate/frame/statement/src/mock.rs index 79d2aa7d891..10a74e100df 100644 --- a/substrate/frame/statement/src/mock.rs +++ b/substrate/frame/statement/src/mock.rs @@ -86,6 +86,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = (); } 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 18790850d6b..55696cc6c6e 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 @@ -46,6 +46,7 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) )); } } + let freeze_reason_variants_count = freeze_reason_variants.len() as u32; quote! { /// A reason for placing a freeze on funds. @@ -59,6 +60,10 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) #( #freeze_reason_variants )* } + impl #scrate::traits::VariantCount for RuntimeFreezeReason { + const VARIANT_COUNT: u32 = #freeze_reason_variants_count; + } + #( #conversion_fns )* } } 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 1bb7462133c..3856c4a2bb9 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 @@ -46,6 +46,7 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) - )); } } + let hold_reason_variants_count = hold_reason_variants.len() as u32; quote! { /// A reason for placing a hold on funds. @@ -59,6 +60,10 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) - #( #hold_reason_variants )* } + impl #scrate::traits::VariantCount for RuntimeHoldReason { + const VARIANT_COUNT: u32 = #hold_reason_variants_count; + } + #( #conversion_fns )* } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 1532d67facd..75c43d8cc50 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -61,7 +61,7 @@ pub use misc::{ DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, - TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, + TryCollect, TryDrop, TypedGet, UnixTime, VariantCount, WrapperKeepOpaque, WrapperOpaque, }; #[allow(deprecated)] pub use misc::{PreimageProvider, PreimageRecipient}; diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index eb704de4353..45a3bba9b3a 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -36,6 +36,18 @@ pub const DEFENSIVE_OP_PUBLIC_ERROR: &str = "a defensive failure has been trigge #[doc(hidden)] pub const DEFENSIVE_OP_INTERNAL_ERROR: &str = "Defensive failure has been triggered!"; +/// Trait to get the number of variants in any enum. +/// +/// NOTE: can be removed once is stable. +pub trait VariantCount { + /// Get the number of variants. + const VARIANT_COUNT: u32; +} + +impl VariantCount for () { + const VARIANT_COUNT: u32 = 0; +} + /// Generic function to mark an execution path as ONLY defensive. /// /// Similar to mark a match arm or `if/else` branch as `unreachable!`. diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 8fe111afc26..189623b520e 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -95,6 +95,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index bfbe8b4178c..76c78fb4222 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -121,6 +121,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs index b8d7b523ca2..5fa8a4ab27d 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -113,6 +113,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 97253be4630..419989bef12 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -108,6 +108,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/transaction-storage/src/mock.rs b/substrate/frame/transaction-storage/src/mock.rs index 243e26b5590..947c81c12ac 100644 --- a/substrate/frame/transaction-storage/src/mock.rs +++ b/substrate/frame/transaction-storage/src/mock.rs @@ -81,6 +81,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index 1748189723e..522ecf6b18f 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -92,6 +92,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 60c5fc1eced..66218c8c015 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -78,6 +78,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type FreezeIdentifier = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; } diff --git a/substrate/frame/uniques/src/mock.rs b/substrate/frame/uniques/src/mock.rs index 5c44a7ed7a5..1f62c3c4e93 100644 --- a/substrate/frame/uniques/src/mock.rs +++ b/substrate/frame/uniques/src/mock.rs @@ -80,6 +80,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 183853c4e8a..cbd495a5c15 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -183,6 +183,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index fe1779475a6..13d6d5ba57a 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -78,6 +78,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } parameter_types! { diff --git a/substrate/frame/whitelist/src/mock.rs b/substrate/frame/whitelist/src/mock.rs index e6ddbf02bb2..4e70a503c28 100644 --- a/substrate/frame/whitelist/src/mock.rs +++ b/substrate/frame/whitelist/src/mock.rs @@ -83,6 +83,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxHolds = (); } diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 687790f2ffa..845ef2c4456 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -396,6 +396,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; } -- GitLab From 91851951856b8effe627fb1d151fe336a51eef2d Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:47:11 +0200 Subject: [PATCH 357/633] Make `IdentityInfo` generic in `pallet-identity` (#1661) Fixes #179 # Description This PR makes the structure containing identity information used in `pallet-identity` generic through the pallet `Config`. Additionally, the old structure is now available in a separate module called `simple` (pending rename) and is compatible with the new interface. Another change in this PR is that while the `additional` field in `IdentityInfo` stays for backwards compatibility reasons, the associated costs are stil present in the pallet through the `additional` function in the `IdentityInformationProvider` interface. This function is marked as deprecated as it is only a temporary solution to the backwards compatibility problem we had. In short, we could have removed the additional fields in the struct and done a migration, but we chose to wait and do it off-chain through the genesis of the system parachain. After we move the identity pallet to the parachain, additional fields will be migrated into the existing fields and the `additional` key-value store will be removed. Until that happens, this interface will provide the necessary information to properly account for the associated costs. Additionally, this PR fixes an unrelated issue; the `IdentityField` enum used to represent the fields as bitflags couldn't store more than 8 fields, even though it was marked as `#[repr(u64)]`. This was because of the `derive` implementation of `TypeInfo`, which assumed `u8` semantics. The custom implementation of this trait in https://github.com/paritytech/polkadot-sdk/commit/0105cc0396b7a53d0b290f48b1225847f6d17321 fixes the issue. --------- Signed-off-by: georgepisaltu Co-authored-by: Sam Johnson Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- polkadot/runtime/rococo/src/lib.rs | 2 + polkadot/runtime/westend/src/lib.rs | 2 + substrate/bin/node/runtime/src/lib.rs | 2 + substrate/frame/alliance/src/lib.rs | 2 +- substrate/frame/alliance/src/mock.rs | 3 +- substrate/frame/identity/src/benchmarking.rs | 60 ++--- substrate/frame/identity/src/lib.rs | 163 ++++++-------- substrate/frame/identity/src/simple.rs | 185 +++++++++++++++ substrate/frame/identity/src/tests.rs | 55 ++++- substrate/frame/identity/src/types.rs | 224 +++++++------------ 10 files changed, 404 insertions(+), 294 deletions(-) create mode 100644 substrate/frame/identity/src/simple.rs diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index cc12920ff82..e6ad061ce06 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -76,6 +76,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; +use pallet_identity::simple::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; @@ -610,6 +611,7 @@ impl pallet_identity::Config for Runtime { type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type MaxAdditionalFields = MaxAdditionalFields; + type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; type ForceOrigin = EitherOf, GeneralAdmin>; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d166c8a3326..9ee4f3cf23e 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -40,6 +40,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; +use pallet_identity::simple::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; @@ -876,6 +877,7 @@ impl pallet_identity::Config for Runtime { type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type MaxAdditionalFields = MaxAdditionalFields; + type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type ForceOrigin = EitherOf, GeneralAdmin>; type RegistrarOrigin = EitherOf, GeneralAdmin>; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 36ad4d985cf..f4c8a5940a3 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -60,6 +60,7 @@ use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; +use pallet_identity::simple::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; @@ -1474,6 +1475,7 @@ impl pallet_identity::Config for Runtime { type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type MaxAdditionalFields = MaxAdditionalFields; + type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; type ForceOrigin = EnsureRootOrHalfCouncil; diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index 627399f805b..f3ff03780f5 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -112,7 +112,7 @@ use frame_support::{ }, weights::Weight, }; -use pallet_identity::IdentityField; +use pallet_identity::simple::IdentityField; use scale_info::TypeInfo; pub use pallet::*; diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index eac8411699e..a5970bc7af6 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -31,7 +31,7 @@ pub use frame_support::{ BoundedVec, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use pallet_identity::{Data, IdentityInfo, Judgement}; +use pallet_identity::{simple::IdentityInfo, Data, Judgement}; pub use crate as pallet_alliance; @@ -121,6 +121,7 @@ impl pallet_identity::Config for Test { type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type MaxAdditionalFields = MaxAdditionalFields; + type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = (); type RegistrarOrigin = EnsureOneOrRoot; diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 059de204bbf..16ce4d8246e 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -22,6 +22,7 @@ use super::*; use crate::Pallet as Identity; +use enumflags2::BitFlag; use frame_benchmarking::{ account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, }; @@ -48,14 +49,9 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, registrar_lookup)?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; - let fields = - IdentityFields( - IdentityField::Display | - IdentityField::Legal | IdentityField::Web | - IdentityField::Riot | IdentityField::Email | - IdentityField::PgpFingerprint | - IdentityField::Image | IdentityField::Twitter, - ); + let fields = IdentityFields( + ::IdentityField::all(), + ); Identity::::set_fields(RawOrigin::Signed(registrar.clone()).into(), i, fields)?; } @@ -81,7 +77,7 @@ fn create_sub_accounts( // Set identity so `set_subs` does not fail. if IdentityOf::::get(who).is_none() { let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); - let info = create_identity_info::(1); + let info = T::IdentityInformation::create_identity_info(1); Identity::::set_identity(who_origin.into(), Box::new(info))?; } @@ -102,24 +98,6 @@ fn add_sub_accounts( Ok(subs) } -// This creates an `IdentityInfo` object with `num_fields` extra fields. -// All data is pre-populated with some arbitrary bytes. -fn create_identity_info(num_fields: u32) -> IdentityInfo { - let data = Data::Raw(vec![0; 32].try_into().unwrap()); - - IdentityInfo { - additional: vec![(data.clone(), data.clone()); num_fields as usize].try_into().unwrap(), - display: data.clone(), - legal: data.clone(), - web: data.clone(), - riot: data.clone(), - email: data.clone(), - pgp_fingerprint: Some([0; 20]), - image: data.clone(), - twitter: data, - } -} - #[benchmarks] mod benchmarks { use super::*; @@ -153,7 +131,7 @@ mod benchmarks { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Add an initial identity - let initial_info = create_identity_info::(1); + let initial_info = T::IdentityInformation::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 @@ -174,7 +152,10 @@ mod benchmarks { } #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), Box::new(create_identity_info::(x))); + _( + RawOrigin::Signed(caller.clone()), + Box::new(T::IdentityInformation::create_identity_info(x)), + ); assert_last_event::(Event::::IdentitySet { who: caller }.into()); Ok(()) @@ -235,7 +216,7 @@ mod benchmarks { let _ = add_sub_accounts::(&caller, s)?; // Create their main identity with x additional fields - let info = create_identity_info::(x); + let info = T::IdentityInformation::create_identity_info(x); Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve @@ -275,7 +256,7 @@ mod benchmarks { add_registrars::(r)?; // Create their main identity with x additional fields - let info = create_identity_info::(x); + let info = T::IdentityInformation::create_identity_info(x); let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info))?; @@ -302,7 +283,7 @@ mod benchmarks { add_registrars::(r)?; // Create their main identity with x additional fields - let info = create_identity_info::(x); + let info = T::IdentityInformation::create_identity_info(x); let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info))?; @@ -386,14 +367,9 @@ mod benchmarks { .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 fields = IdentityFields( + ::IdentityField::all(), + ); let registrars = Registrars::::get(); ensure!( @@ -431,7 +407,7 @@ mod benchmarks { add_registrars::(r)?; - let info = create_identity_info::(x); + let info = T::IdentityInformation::create_identity_info(x); let info_hash = T::Hashing::hash_of(&info); Identity::::set_identity(user_origin.clone(), Box::new(info))?; @@ -464,7 +440,7 @@ mod benchmarks { let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); - let info = create_identity_info::(x); + let info = T::IdentityInformation::create_identity_info(x); Identity::::set_identity(target_origin.clone(), Box::new(info.clone()))?; let _ = add_sub_accounts::(&target, s)?; diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index f192ee2b461..a341cc6bb9b 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -73,6 +73,7 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod simple; #[cfg(test)] mod tests; mod types; @@ -85,7 +86,7 @@ pub use weights::WeightInfo; pub use pallet::*; pub use types::{ - Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo, + Data, IdentityFields, IdentityInformationProvider, Judgement, RegistrarIndex, RegistrarInfo, Registration, }; @@ -133,6 +134,9 @@ pub mod pallet { #[pallet::constant] type MaxAdditionalFields: Get; + /// Structure holding information about an identity. + type IdentityInformation: IdentityInformationProvider; + /// Maxmimum number of registrars allowed in the system. Needed to bound the complexity /// of, e.g., updating judgements. #[pallet::constant] @@ -163,7 +167,7 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - Registration, T::MaxRegistrars, T::MaxAdditionalFields>, + Registration, T::MaxRegistrars, T::IdentityInformation>, OptionQuery, >; @@ -197,7 +201,16 @@ pub mod pallet { #[pallet::getter(fn registrars)] pub(super) type Registrars = StorageValue< _, - BoundedVec, T::AccountId>>, T::MaxRegistrars>, + BoundedVec< + Option< + RegistrarInfo< + BalanceOf, + T::AccountId, + ::IdentityField, + >, + >, + T::MaxRegistrars, + >, ValueQuery, >; @@ -277,9 +290,6 @@ pub mod pallet { /// - `account`: the account of the registrar. /// /// Emits `RegistrarAdded` if successful. - /// - /// ## Complexity - /// - `O(R)` where `R` registrar-count (governance-bounded and code-bounded). #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))] pub fn add_registrar( @@ -317,22 +327,18 @@ pub mod pallet { /// - `info`: The identity information. /// /// Emits `IdentitySet` if successful. - /// - /// ## Complexity - /// - `O(X + X' + R)` - /// - where `X` additional-field-count (deposit-bounded and code-bounded) - /// - where `R` judgements-count (registrar-count-bounded) #[pallet::call_index(1)] - #[pallet::weight( T::WeightInfo::set_identity( - T::MaxRegistrars::get(), // R - T::MaxAdditionalFields::get(), // X + #[pallet::weight(T::WeightInfo::set_identity( + T::MaxRegistrars::get(), + T::MaxAdditionalFields::get(), ))] pub fn set_identity( origin: OriginFor, - info: Box>, + info: Box, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let extra_fields = info.additional.len() as u32; + #[allow(deprecated)] + let extra_fields = info.additional() as u32; ensure!(extra_fields <= T::MaxAdditionalFields::get(), Error::::TooManyFields); let fd = >::from(extra_fields) * T::FieldDeposit::get(); @@ -364,11 +370,7 @@ pub mod pallet { >::insert(&sender, id); Self::deposit_event(Event::IdentitySet { who: sender }); - Ok(Some(T::WeightInfo::set_identity( - judgements as u32, // R - extra_fields, // X - )) - .into()) + Ok(Some(T::WeightInfo::set_identity(judgements as u32, extra_fields)).into()) } /// Set the sub-accounts of the sender. @@ -380,11 +382,6 @@ pub mod pallet { /// identity. /// /// - `subs`: The identity's (new) sub-accounts. - /// - /// ## Complexity - /// - `O(P + S)` - /// - where `P` old-subs-count (hard- and deposit-bounded). - /// - where `S` subs-count (hard- and deposit-bounded). // TODO: This whole extrinsic screams "not optimized". For example we could // filter any overlap between new and old subs, and avoid reading/writing // to those values... We could also ideally avoid needing to write to @@ -392,8 +389,8 @@ pub mod pallet { // is a large overestimate due to the fact that it could potentially write // to 2 x T::MaxSubAccounts::get(). #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) // P: Assume max sub accounts removed. - .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) // S: Assume all subs are new. + #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) + .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) )] pub fn set_subs( origin: OriginFor, @@ -453,17 +450,11 @@ pub mod pallet { /// identity. /// /// Emits `IdentityCleared` if successful. - /// - /// ## Complexity - /// - `O(R + S + X)` - /// - where `R` registrar-count (governance-bounded). - /// - where `S` subs-count (hard- and deposit-bounded). - /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::clear_identity( - T::MaxRegistrars::get(), // R - T::MaxSubAccounts::get(), // S - T::MaxAdditionalFields::get(), // X + T::MaxRegistrars::get(), + T::MaxSubAccounts::get(), + T::MaxAdditionalFields::get(), ))] pub fn clear_identity(origin: OriginFor) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; @@ -480,10 +471,11 @@ pub mod pallet { Self::deposit_event(Event::IdentityCleared { who: sender, deposit }); + #[allow(deprecated)] Ok(Some(T::WeightInfo::clear_identity( - id.judgements.len() as u32, // R - sub_ids.len() as u32, // S - id.info.additional.len() as u32, // X + id.judgements.len() as u32, + sub_ids.len() as u32, + id.info.additional() as u32, )) .into()) } @@ -504,15 +496,10 @@ pub mod pallet { /// ``` /// /// Emits `JudgementRequested` if successful. - /// - /// ## Complexity - /// - `O(R + X)`. - /// - where `R` registrar-count (governance-bounded). - /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::request_judgement( - T::MaxRegistrars::get(), // R - T::MaxAdditionalFields::get(), // X + T::MaxRegistrars::get(), + T::MaxAdditionalFields::get(), ))] pub fn request_judgement( origin: OriginFor, @@ -543,7 +530,8 @@ pub mod pallet { T::Currency::reserve(&sender, registrar.fee)?; let judgements = id.judgements.len(); - let extra_fields = id.info.additional.len(); + #[allow(deprecated)] + let extra_fields = id.info.additional(); >::insert(&sender, id); Self::deposit_event(Event::JudgementRequested { @@ -565,15 +553,10 @@ pub mod pallet { /// - `reg_index`: The index of the registrar whose judgement is no longer requested. /// /// Emits `JudgementUnrequested` if successful. - /// - /// ## Complexity - /// - `O(R + X)`. - /// - where `R` registrar-count (governance-bounded). - /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::cancel_request( - T::MaxRegistrars::get(), // R - T::MaxAdditionalFields::get(), // X + T::MaxRegistrars::get(), + T::MaxAdditionalFields::get(), ))] pub fn cancel_request( origin: OriginFor, @@ -595,7 +578,8 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, fee); debug_assert!(err_amount.is_zero()); let judgements = id.judgements.len(); - let extra_fields = id.info.additional.len(); + #[allow(deprecated)] + let extra_fields = id.info.additional(); >::insert(&sender, id); Self::deposit_event(Event::JudgementUnrequested { @@ -613,12 +597,8 @@ pub mod pallet { /// /// - `index`: the index of the registrar whose fee is to be set. /// - `fee`: the new fee. - /// - /// ## Complexity - /// - `O(R)`. - /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] // R + #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] pub fn set_fee( origin: OriginFor, #[pallet::compact] index: RegistrarIndex, @@ -640,7 +620,7 @@ pub mod pallet { .ok_or_else(|| DispatchError::from(Error::::InvalidIndex))?; Ok(rs.len()) })?; - Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) // R + Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) } /// Change the account associated with a registrar. @@ -650,12 +630,8 @@ pub mod pallet { /// /// - `index`: the index of the registrar whose fee is to be set. /// - `new`: the new account ID. - /// - /// ## Complexity - /// - `O(R)`. - /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] // R + #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] pub fn set_account_id( origin: OriginFor, #[pallet::compact] index: RegistrarIndex, @@ -678,7 +654,7 @@ pub mod pallet { .ok_or_else(|| DispatchError::from(Error::::InvalidIndex))?; Ok(rs.len()) })?; - Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) // R + Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) } /// Set the field information for a registrar. @@ -688,16 +664,14 @@ pub mod pallet { /// /// - `index`: the index of the registrar whose fee is to be set. /// - `fields`: the fields that the registrar concerns themselves with. - /// - /// ## Complexity - /// - `O(R)`. - /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(8)] - #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] // R + #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] pub fn set_fields( origin: OriginFor, #[pallet::compact] index: RegistrarIndex, - fields: IdentityFields, + fields: IdentityFields< + ::IdentityField, + >, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -715,10 +689,7 @@ pub mod pallet { .ok_or_else(|| DispatchError::from(Error::::InvalidIndex))?; Ok(rs.len()) })?; - Ok(Some(T::WeightInfo::set_fields( - registrars as u32, // R - )) - .into()) + Ok(Some(T::WeightInfo::set_fields(registrars as u32)).into()) } /// Provide a judgement for an account's identity. @@ -730,18 +701,14 @@ pub mod pallet { /// - `target`: the account whose identity the judgement is upon. This must be an account /// with a registered identity. /// - `judgement`: the judgement of the registrar of index `reg_index` about `target`. - /// - `identity`: The hash of the [`IdentityInfo`] for that the judgement is provided. + /// - `identity`: The hash of the [`IdentityInformationProvider`] for that the judgement is + /// provided. /// /// Emits `JudgementGiven` if successful. - /// - /// ## Complexity - /// - `O(R + X)`. - /// - where `R` registrar-count (governance-bounded). - /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::provide_judgement( - T::MaxRegistrars::get(), // R - T::MaxAdditionalFields::get(), // X + T::MaxRegistrars::get(), + T::MaxAdditionalFields::get(), ))] pub fn provide_judgement( origin: OriginFor, @@ -785,7 +752,8 @@ pub mod pallet { } let judgements = id.judgements.len(); - let extra_fields = id.info.additional.len(); + #[allow(deprecated)] + let extra_fields = id.info.additional(); >::insert(&target, id); Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); @@ -805,17 +773,11 @@ pub mod pallet { /// with a registered identity. /// /// Emits `IdentityKilled` if successful. - /// - /// ## Complexity - /// - `O(R + S + X)` - /// - where `R` registrar-count (governance-bounded). - /// - where `S` subs-count (hard- and deposit-bounded). - /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::kill_identity( - T::MaxRegistrars::get(), // R - T::MaxSubAccounts::get(), // S - T::MaxAdditionalFields::get(), // X + T::MaxRegistrars::get(), + T::MaxSubAccounts::get(), + T::MaxAdditionalFields::get(), ))] pub fn kill_identity( origin: OriginFor, @@ -837,10 +799,11 @@ pub mod pallet { Self::deposit_event(Event::IdentityKilled { who: target, deposit }); + #[allow(deprecated)] Ok(Some(T::WeightInfo::kill_identity( - id.judgements.len() as u32, // R - sub_ids.len() as u32, // S - id.info.additional.len() as u32, // X + id.judgements.len() as u32, + sub_ids.len() as u32, + id.info.additional() as u32, )) .into()) } @@ -975,6 +938,6 @@ impl Pallet { /// Check if the account has corresponding identity information by the identity field. pub fn has_identity(who: &T::AccountId, fields: u64) -> bool { IdentityOf::::get(who) - .map_or(false, |registration| (registration.info.fields().0.bits() & fields) == fields) + .map_or(false, |registration| (registration.info.has_identity(fields))) } } diff --git a/substrate/frame/identity/src/simple.rs b/substrate/frame/identity/src/simple.rs new file mode 100644 index 00000000000..db5ecf3b1c9 --- /dev/null +++ b/substrate/frame/identity/src/simple.rs @@ -0,0 +1,185 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode, MaxEncodedLen}; +use enumflags2::{bitflags, BitFlags}; +use frame_support::{traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use scale_info::{build::Variants, Path, Type, TypeInfo}; +use sp_runtime::{BoundedVec, RuntimeDebug}; +use sp_std::prelude::*; + +use crate::types::{Data, IdentityFields, IdentityInformationProvider, U64BitFlag}; + +/// The fields that we use to identify the owner of an account with. Each corresponds to a field +/// in the `IdentityInfo` struct. +#[bitflags] +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub enum IdentityField { + Display, + Legal, + Web, + Riot, + Email, + PgpFingerprint, + Image, + Twitter, +} + +impl TypeInfo for IdentityField { + type Identity = Self; + + fn type_info() -> scale_info::Type { + Type::builder().path(Path::new("IdentityField", module_path!())).variant( + Variants::new() + .variant("Display", |v| v.index(0)) + .variant("Legal", |v| v.index(1)) + .variant("Web", |v| v.index(2)) + .variant("Riot", |v| v.index(3)) + .variant("Email", |v| v.index(4)) + .variant("PgpFingerprint", |v| v.index(5)) + .variant("Image", |v| v.index(6)) + .variant("Twitter", |v| v.index(7)), + ) + } +} + +impl U64BitFlag for IdentityField {} + +/// Information concerning the identity of the controller of an account. +/// +/// NOTE: This should be stored at the end of the storage item to facilitate the addition of extra +/// fields in a backwards compatible way through a specialized `Decode` impl. +#[derive( + CloneNoBound, + Encode, + Decode, + EqNoBound, + MaxEncodedLen, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[codec(mel_bound())] +#[cfg_attr(test, derive(frame_support::DefaultNoBound))] +#[scale_info(skip_type_params(FieldLimit))] +pub struct IdentityInfo> { + /// Additional fields of the identity that are not catered for with the struct's explicit + /// fields. + pub additional: BoundedVec<(Data, Data), FieldLimit>, + + /// A reasonable display name for the controller of the account. This should be whatever it is + /// that it is typically known as and should not be confusable with other entities, given + /// reasonable context. + /// + /// Stored as UTF-8. + pub display: Data, + + /// The full legal name in the local jurisdiction of the entity. This might be a bit + /// long-winded. + /// + /// Stored as UTF-8. + pub legal: Data, + + /// A representative website held by the controller of the account. + /// + /// NOTE: `https://` is automatically prepended. + /// + /// Stored as UTF-8. + pub web: Data, + + /// The Riot/Matrix handle held by the controller of the account. + /// + /// Stored as UTF-8. + pub riot: Data, + + /// The email address of the controller of the account. + /// + /// Stored as UTF-8. + pub email: Data, + + /// The PGP/GPG public key of the controller of the account. + pub pgp_fingerprint: Option<[u8; 20]>, + + /// A graphic image representing the controller of the account. Should be a company, + /// organization or project logo or a headshot in the case of a human. + pub image: Data, + + /// The Twitter identity. The leading `@` character may be elided. + pub twitter: Data, +} + +impl + 'static> IdentityInformationProvider for IdentityInfo { + type IdentityField = IdentityField; + + fn has_identity(&self, fields: u64) -> bool { + self.fields().0.bits() & fields == fields + } + + fn additional(&self) -> usize { + self.additional.len() + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_identity_info(num_fields: u32) -> Self { + let data = Data::Raw(vec![0; 32].try_into().unwrap()); + + IdentityInfo { + additional: vec![(data.clone(), data.clone()); num_fields as usize].try_into().unwrap(), + display: data.clone(), + legal: data.clone(), + web: data.clone(), + riot: data.clone(), + email: data.clone(), + pgp_fingerprint: Some([0; 20]), + image: data.clone(), + twitter: data, + } + } +} + +impl> IdentityInfo { + #[allow(unused)] + pub(crate) fn fields(&self) -> IdentityFields { + let mut res = >::empty(); + if !self.display.is_none() { + res.insert(IdentityField::Display); + } + if !self.legal.is_none() { + res.insert(IdentityField::Legal); + } + if !self.web.is_none() { + res.insert(IdentityField::Web); + } + if !self.riot.is_none() { + res.insert(IdentityField::Riot); + } + if !self.email.is_none() { + res.insert(IdentityField::Email); + } + if self.pgp_fingerprint.is_some() { + res.insert(IdentityField::PgpFingerprint); + } + if !self.image.is_none() { + res.insert(IdentityField::Image); + } + if !self.twitter.is_none() { + res.insert(IdentityField::Twitter); + } + IdentityFields(res) + } +} diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 6bfd15b4aae..f0980e9c7cc 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -18,7 +18,10 @@ // Tests for Identity Pallet use super::*; -use crate as pallet_identity; +use crate::{ + self as pallet_identity, + simple::{IdentityField as SimpleIdentityField, IdentityInfo}, +}; use codec::{Decode, Encode}; use frame_support::{ @@ -107,6 +110,7 @@ impl pallet_identity::Config for Test { type SubAccountDeposit = ConstU64<10>; type MaxSubAccounts = ConstU32<2>; type MaxAdditionalFields = MaxAdditionalFields; + type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type RegistrarOrigin = EnsureOneOrRoot; type ForceOrigin = EnsureTwoOrRoot; @@ -139,6 +143,43 @@ fn twenty() -> IdentityInfo { } } +#[test] +fn identity_fields_repr_works() { + // `SimpleIdentityField` sanity checks. + assert_eq!(SimpleIdentityField::Display as u64, 1 << 0); + assert_eq!(SimpleIdentityField::Legal as u64, 1 << 1); + assert_eq!(SimpleIdentityField::Web as u64, 1 << 2); + assert_eq!(SimpleIdentityField::Riot as u64, 1 << 3); + assert_eq!(SimpleIdentityField::Email as u64, 1 << 4); + assert_eq!(SimpleIdentityField::PgpFingerprint as u64, 1 << 5); + assert_eq!(SimpleIdentityField::Image as u64, 1 << 6); + assert_eq!(SimpleIdentityField::Twitter as u64, 1 << 7); + + let fields = IdentityFields( + SimpleIdentityField::Legal | + SimpleIdentityField::Web | + SimpleIdentityField::Riot | + SimpleIdentityField::PgpFingerprint | + SimpleIdentityField::Twitter, + ); + + assert!(!fields.0.contains(SimpleIdentityField::Display)); + assert!(fields.0.contains(SimpleIdentityField::Legal)); + assert!(fields.0.contains(SimpleIdentityField::Web)); + assert!(fields.0.contains(SimpleIdentityField::Riot)); + assert!(!fields.0.contains(SimpleIdentityField::Email)); + assert!(fields.0.contains(SimpleIdentityField::PgpFingerprint)); + assert!(!fields.0.contains(SimpleIdentityField::Image)); + assert!(fields.0.contains(SimpleIdentityField::Twitter)); + + // The `IdentityFields` inner `BitFlags::bits` is used for `Encode`/`Decode`, so we ensure that + // the `u64` representation matches what we expect during encode/decode operations. + assert_eq!( + fields.0.bits(), + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_10101110 + ); +} + #[test] fn editing_subaccounts_should_work() { new_test_ext().execute_with(|| { @@ -233,7 +274,7 @@ fn adding_registrar_should_work() { new_test_ext().execute_with(|| { assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); - let fields = IdentityFields(IdentityField::Display | IdentityField::Legal); + let fields = IdentityFields(SimpleIdentityField::Display | SimpleIdentityField::Legal); assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields)); assert_eq!( Identity::registrars(), @@ -608,15 +649,17 @@ fn setting_account_id_should_work() { fn test_has_identity() { new_test_ext().execute_with(|| { assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); - assert!(Identity::has_identity(&10, IdentityField::Display as u64)); - assert!(Identity::has_identity(&10, IdentityField::Legal as u64)); + assert!(Identity::has_identity(&10, SimpleIdentityField::Display as u64)); + assert!(Identity::has_identity(&10, SimpleIdentityField::Legal as u64)); assert!(Identity::has_identity( &10, - IdentityField::Display as u64 | IdentityField::Legal as u64 + SimpleIdentityField::Display as u64 | SimpleIdentityField::Legal as u64 )); assert!(!Identity::has_identity( &10, - IdentityField::Display as u64 | IdentityField::Legal as u64 | IdentityField::Web as u64 + SimpleIdentityField::Display as u64 | + SimpleIdentityField::Legal as u64 | + SimpleIdentityField::Web as u64 )); }); } diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index 1837b30b027..7055f6d80cf 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -17,7 +17,7 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; -use enumflags2::{bitflags, BitFlags}; +use enumflags2::{BitFlag, BitFlags, _internal::RawBitFlags}; use frame_support::{ traits::{ConstU32, Get}, BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -29,6 +29,11 @@ use scale_info::{ use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::{fmt::Debug, iter::once, ops::Add, prelude::*}; +/// An identifier for a single name registrar/identity verification service. +pub type RegistrarIndex = u32; + +pub trait U64BitFlag: BitFlag + RawBitFlags {} + /// Either underlying data blob if it is at most 32 bytes, or a hash of it. If the data is greater /// than 32-bytes then it will be truncated when encoding. /// @@ -180,9 +185,6 @@ impl Default for Data { } } -/// An identifier for a single name registrar/identity verification service. -pub type RegistrarIndex = u32; - /// An attestation of a registrar over how accurate some `IdentityInfo` is in describing an account. /// /// NOTE: Registrars may pay little attention to some fields. Registrars may want to make clear @@ -228,143 +230,31 @@ impl` that implements `Codec`. -#[derive(Clone, Copy, PartialEq, Default, RuntimeDebug)] -pub struct IdentityFields(pub BitFlags); - -impl MaxEncodedLen for IdentityFields { - fn max_encoded_len() -> usize { - u64::max_encoded_len() - } -} - -impl Eq for IdentityFields {} -impl Encode for IdentityFields { - fn using_encoded R>(&self, f: F) -> R { - self.0.bits().using_encoded(f) - } -} -impl Decode for IdentityFields { - fn decode(input: &mut I) -> sp_std::result::Result { - let field = u64::decode(input)?; - Ok(Self(>::from_bits(field as u64).map_err(|_| "invalid value")?)) - } -} -impl TypeInfo for IdentityFields { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("BitFlags", module_path!())) - .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) - .composite(Fields::unnamed().field(|f| f.ty::().type_name("IdentityField"))) - } -} - /// Information concerning the identity of the controller of an account. -/// -/// NOTE: This should be stored at the end of the storage item to facilitate the addition of extra -/// fields in a backwards compatible way through a specialized `Decode` impl. -#[derive( - CloneNoBound, Encode, Decode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, -)] -#[codec(mel_bound())] -#[cfg_attr(test, derive(frame_support::DefaultNoBound))] -#[scale_info(skip_type_params(FieldLimit))] -pub struct IdentityInfo> { - /// Additional fields of the identity that are not catered for with the struct's explicit - /// fields. - pub additional: BoundedVec<(Data, Data), FieldLimit>, - - /// A reasonable display name for the controller of the account. This should be whatever it is - /// that it is typically known as and should not be confusable with other entities, given - /// reasonable context. - /// - /// Stored as UTF-8. - pub display: Data, - - /// The full legal name in the local jurisdiction of the entity. This might be a bit - /// long-winded. - /// - /// Stored as UTF-8. - pub legal: Data, - - /// A representative website held by the controller of the account. - /// - /// NOTE: `https://` is automatically prepended. - /// - /// Stored as UTF-8. - pub web: Data, - - /// The Riot/Matrix handle held by the controller of the account. - /// - /// Stored as UTF-8. - pub riot: Data, - - /// The email address of the controller of the account. - /// - /// Stored as UTF-8. - pub email: Data, - - /// The PGP/GPG public key of the controller of the account. - pub pgp_fingerprint: Option<[u8; 20]>, - - /// A graphic image representing the controller of the account. Should be a company, - /// organization or project logo or a headshot in the case of a human. - pub image: Data, - - /// The Twitter identity. The leading `@` character may be elided. - pub twitter: Data, -} - -impl> IdentityInfo { - pub(crate) fn fields(&self) -> IdentityFields { - let mut res = >::empty(); - if !self.display.is_none() { - res.insert(IdentityField::Display); - } - if !self.legal.is_none() { - res.insert(IdentityField::Legal); - } - if !self.web.is_none() { - res.insert(IdentityField::Web); - } - if !self.riot.is_none() { - res.insert(IdentityField::Riot); - } - if !self.email.is_none() { - res.insert(IdentityField::Email); - } - if self.pgp_fingerprint.is_some() { - res.insert(IdentityField::PgpFingerprint); - } - if !self.image.is_none() { - res.insert(IdentityField::Image); - } - if !self.twitter.is_none() { - res.insert(IdentityField::Twitter); - } - IdentityFields(res) +pub trait IdentityInformationProvider: + Encode + Decode + MaxEncodedLen + Clone + Debug + Eq + PartialEq + TypeInfo +{ + /// Type capable of representing all of the fields present in the identity information as bit + /// flags in `u64` format. + type IdentityField: Clone + Debug + Eq + PartialEq + TypeInfo + U64BitFlag; + + /// Check if an identity registered information for some given `fields`. + fn has_identity(&self, fields: u64) -> bool; + + /// Interface for providing the number of additional fields this identity information provider + /// holds, used to charge for additional storage and weight. This interface is present for + /// backwards compatibility reasons only and will be removed as soon as the reference identity + /// provider removes additional fields. + #[deprecated] + fn additional(&self) -> usize { + 0 } + + #[cfg(feature = "runtime-benchmarks")] + fn create_identity_info(num_fields: u32) -> Self; } -/// Information concerning the identity of the controller of an account. +/// Information on an identity along with judgements from registrars. /// /// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a /// backwards compatible way through a specialized `Decode` impl. @@ -376,7 +266,7 @@ impl> IdentityInfo { pub struct Registration< Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq, MaxJudgements: Get, - MaxAdditionalFields: Get, + IdentityInfo: IdentityInformationProvider, > { /// Judgements from the registrars on this identity. Stored ordered by `RegistrarIndex`. There /// may be only a single judgement from each registrar. @@ -386,14 +276,14 @@ pub struct Registration< pub deposit: Balance, /// Information on the identity. - pub info: IdentityInfo, + pub info: IdentityInfo, } impl< Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add, MaxJudgements: Get, - MaxAdditionalFields: Get, - > Registration + IdentityInfo: IdentityInformationProvider, + > Registration { pub(crate) fn total_deposit(&self) -> Balance { self.deposit + @@ -407,8 +297,8 @@ impl< impl< Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq, MaxJudgements: Get, - MaxAdditionalFields: Get, - > Decode for Registration + IdentityInfo: IdentityInformationProvider, + > Decode for Registration { fn decode(input: &mut I) -> sp_std::result::Result { let (judgements, deposit, info) = Decode::decode(&mut AppendZerosInput::new(input))?; @@ -421,6 +311,7 @@ impl< pub struct RegistrarInfo< Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq, + IdField: Clone + Debug + Eq + PartialEq + TypeInfo + U64BitFlag, > { /// The account of the registrar. pub account: AccountId, @@ -430,7 +321,52 @@ pub struct RegistrarInfo< /// Relevant fields for this registrar. Registrar judgements are limited to attestations on /// these fields. - pub fields: IdentityFields, + pub fields: IdentityFields, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Clone, Copy, PartialEq, RuntimeDebug)] +pub struct IdentityFields(pub BitFlags); + +impl Default for IdentityFields { + fn default() -> Self { + Self(Default::default()) + } +} + +impl MaxEncodedLen for IdentityFields +where + IdentityFields: Encode, +{ + fn max_encoded_len() -> usize { + u64::max_encoded_len() + } +} + +impl Eq for IdentityFields {} +impl Encode for IdentityFields { + fn using_encoded R>(&self, f: F) -> R { + let bits: u64 = self.0.bits(); + bits.using_encoded(f) + } +} +impl Decode for IdentityFields { + fn decode(input: &mut I) -> sp_std::result::Result { + let field = u64::decode(input)?; + Ok(Self(>::from_bits(field).map_err(|_| "invalid value")?)) + } +} +impl TypeInfo + for IdentityFields +{ + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("BitFlags", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) + .composite(Fields::unnamed().field(|f| f.ty::().type_name("IdentityField"))) + } } #[cfg(test)] -- GitLab From 017f8d80b2667ece95f5353e0386beac5afedf72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:50:46 +0100 Subject: [PATCH 358/633] polkadot: enable tikv-jemallocator/unprefixed_malloc_on_supported_platforms (#2002) This is indirectly enabled by rocksdb crate, better to make it explicit (https://github.com/tikv/rust-rocksdb/blob/2096b9a161f93e437f7adee49e68cd1570aea42f/librocksdb_sys/Cargo.toml#L35-L38). --- polkadot/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 6e82cb69f6e..8540f65d70c 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -23,7 +23,7 @@ default-run = "polkadot" [dependencies] color-eyre = { version = "0.6.1", default-features = false } -tikv-jemallocator = { version = "0.5.0", optional = true } +tikv-jemallocator = { version = "0.5.0", optional = true, features = [ "unprefixed_malloc_on_supported_platforms" ] } # Crates in our workspace, defined as dependencies so we can pass them feature flags. polkadot-cli = { path = "cli", features = [ "westend-native", "rococo-native" ] } @@ -36,7 +36,7 @@ polkadot-node-core-pvf-common = { path = "node/core/pvf/common" } polkadot-node-core-pvf-execute-worker = { path = "node/core/pvf/execute-worker" } [target.'cfg(target_os = "linux")'.dependencies] -tikv-jemallocator = "0.5.0" +tikv-jemallocator = { version = "0.5.0", features = [ "unprefixed_malloc_on_supported_platforms" ] } [dev-dependencies] assert_cmd = "2.0.4" -- GitLab From 8cba5b90f28f14b5faca618e25fbe9da526db096 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:25:47 +0200 Subject: [PATCH 359/633] Bump actions/setup-node from 3.8.1 to 4.0.0 (#1997) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.8.1 to 4.0.0.
Release notes

Sourced from actions/setup-node's releases.

v4.0.0

What's Changed

In scope of this release we changed version of node runtime for action from node16 to node20 and updated dependencies in actions/setup-node#866

Besides, release contains such changes as:

New Contributors

Full Changelog: https://github.com/actions/setup-node/compare/v3...v4.0.0

v3.8.2

What's Changed

Full Changelog: https://github.com/actions/setup-node/compare/v3...v3.8.2

Commits
  • 8f152de Update actions/checkout for documentation and yaml (#876)
  • 23755b5 upgrade actions/checkout to v4 (#868)
  • 54534a2 Change node version for action to node20 (#866)
  • 1a4442c Update toolkit cache and core (#875)
  • 6e9e448 Merge pull request #872 from akv-platform/add-notice-about-binaries-not-being...
  • e52912e Update tests
  • ac16ae4 Update message to use waning instead of info
  • 5a8d911 Update build
  • 9e956a5 Add notice about binaries not being updated yet
  • 7da2a7e Bump @​babel/traverse from 7.15.4 to 7.23.2 (#870)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=3.8.1&new-version=4.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check-licenses.yml | 2 +- .github/workflows/check-markdown.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index e8def665bd0..50dd10a6d3c 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-node@v3.8.1 + - uses: actions/setup-node@v4.0.0 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index 991fdd171ce..05b5d898d67 100644 --- a/.github/workflows/check-markdown.yml +++ b/.github/workflows/check-markdown.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-node@v3.8.1 + - uses: actions/setup-node@v4.0.0 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" -- GitLab From e39253c022bfed42ba241113c7c9b545b554f098 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 24 Oct 2023 16:22:15 +0200 Subject: [PATCH 360/633] PVF: Add worker check during tests and benches (#1771) --- Cargo.lock | 5 +- polkadot/cli/src/command.rs | 2 +- polkadot/node/core/pvf/Cargo.toml | 13 +- .../benches/host_prepare_rococo_runtime.rs | 130 ++++++++++++++++++ polkadot/node/core/pvf/bin/puppet_worker.rs | 17 --- polkadot/node/core/pvf/common/Cargo.toml | 1 - .../node/core/pvf/common/src/worker/mod.rs | 12 +- polkadot/node/core/pvf/src/artifacts.rs | 1 + polkadot/node/core/pvf/src/host.rs | 10 +- polkadot/node/core/pvf/src/lib.rs | 13 ++ polkadot/node/core/pvf/src/testing.rs | 58 +++++++- polkadot/node/core/pvf/src/worker_intf.rs | 1 + polkadot/node/core/pvf/tests/it/main.rs | 36 ++--- .../node/core/pvf/tests/it/worker_common.rs | 22 ++- polkadot/node/service/Cargo.toml | 8 +- polkadot/node/service/src/workers.rs | 61 ++++---- polkadot/src/bin/execute-worker.rs | 1 + polkadot/src/bin/prepare-worker.rs | 1 + .../utils/build-script-utils/src/version.rs | 6 +- 19 files changed, 285 insertions(+), 113 deletions(-) create mode 100644 polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs delete mode 100644 polkadot/node/core/pvf/bin/puppet_worker.rs diff --git a/Cargo.lock b/Cargo.lock index a8d679c6ce8..d1a1b1877a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12184,9 +12184,11 @@ dependencies = [ "always-assert", "assert_matches", "cfg-if", + "criterion 0.4.0", "futures", "futures-timer", "hex-literal", + "is_executable", "libc", "parity-scale-codec", "pin-project", @@ -12200,11 +12202,11 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "rand 0.8.5", + "rococo-runtime", "slotmap", "sp-core", "sp-maybe-compressed-blob", "sp-wasm-interface", - "substrate-build-script-utils", "tempfile", "test-parachain-adder", "test-parachain-halt", @@ -12912,6 +12914,7 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", + "schnellru", "serde", "serde_json", "serial_test", diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 3da6e54b812..2dcf5e0e8d7 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -50,7 +50,7 @@ impl SubstrateCli for Cli { fn impl_version() -> String { let commit_hash = env!("SUBSTRATE_CLI_COMMIT_HASH"); - format!("{NODE_VERSION}-{commit_hash}") + format!("{}-{commit_hash}", NODE_VERSION) } fn description() -> String { diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 27f4df117e5..bfd70c6fbd4 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -12,6 +12,7 @@ cfg-if = "1.0" futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } +is_executable = "1.0.1" libc = "0.2.139" pin-project = "1.0.9" rand = "0.8.5" @@ -34,19 +35,23 @@ sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-comp polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker", optional = true } polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = true } -[build-dependencies] -substrate-build-script-utils = { path = "../../../../substrate/utils/build-script-utils" } - [dev-dependencies] assert_matches = "1.4.0" +criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support", "async_tokio"] } hex-literal = "0.4.1" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } -# For the puppet worker, depend on ourselves with the test-utils feature. +# For benches and integration tests, depend on ourselves with the test-utils +# feature. polkadot-node-core-pvf = { path = ".", features = ["test-utils"] } +rococo-runtime = { path = "../../../runtime/rococo" } adder = { package = "test-parachain-adder", path = "../../../parachain/test-parachains/adder" } halt = { package = "test-parachain-halt", path = "../../../parachain/test-parachains/halt" } +[[bench]] +name = "host_prepare_rococo_runtime" +harness = false + [features] ci-only-tests = [] jemalloc-allocator = [ "polkadot-node-core-pvf-common/jemalloc-allocator" ] diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs new file mode 100644 index 00000000000..3069fa2b194 --- /dev/null +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -0,0 +1,130 @@ +// 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 . + +//! Benchmarks for preparation through the host. We use a real PVF to get realistic results. + +use criterion::{criterion_group, criterion_main, BatchSize, Criterion, SamplingMode}; +use parity_scale_codec::Encode; +use polkadot_node_core_pvf::{ + start, testing, Config, Metrics, PrepareError, PrepareJobKind, PrepareStats, PvfPrepData, + ValidationError, ValidationHost, +}; +use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; +use polkadot_primitives::ExecutorParams; +use rococo_runtime::WASM_BINARY; +use std::time::Duration; +use tokio::{runtime::Handle, sync::Mutex}; + +const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); +const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); + +struct TestHost { + host: Mutex, +} + +impl TestHost { + fn new_with_config(handle: &Handle, f: F) -> Self + where + F: FnOnce(&mut Config), + { + let (prepare_worker_path, execute_worker_path) = testing::get_and_check_worker_paths(); + + let cache_dir = tempfile::tempdir().unwrap(); + let mut config = Config::new( + cache_dir.path().to_owned(), + None, + prepare_worker_path, + execute_worker_path, + ); + f(&mut config); + let (host, task) = start(config, Metrics::default()); + let _ = handle.spawn(task); + Self { 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() + } +} + +fn host_prepare_rococo_runtime(c: &mut Criterion) { + polkadot_node_core_pvf_common::sp_tracing::try_init_simple(); + + let rt = tokio::runtime::Runtime::new().unwrap(); + + let blob = WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"); + let pvf = match sp_maybe_compressed_blob::decompress(&blob, 64 * 1024 * 1024) { + Ok(code) => PvfPrepData::from_code( + code.into_owned(), + ExecutorParams::default(), + Duration::from_secs(360), + PrepareJobKind::Compilation, + ), + Err(e) => { + panic!("Cannot decompress blob: {:?}", e); + }, + }; + + let mut group = c.benchmark_group("prepare rococo"); + group.sampling_mode(SamplingMode::Flat); + group.sample_size(20); + group.measurement_time(Duration::from_secs(240)); + group.bench_function("host: prepare Rococo runtime", |b| { + b.to_async(&rt).iter_batched( + || { + ( + TestHost::new_with_config(rt.handle(), |cfg| { + cfg.prepare_workers_hard_max_num = 1; + }), + pvf.clone().code(), + ) + }, + |(host, pvf_code)| async move { + // `PvfPrepData` is designed to be cheap to clone, so cloning shouldn't affect the + // benchmark accuracy. + let _stats = host.precheck_pvf(&pvf_code, Default::default()).await.unwrap(); + }, + BatchSize::SmallInput, + ) + }); + group.finish(); +} + +criterion_group!(prepare, host_prepare_rococo_runtime); +criterion_main!(prepare); diff --git a/polkadot/node/core/pvf/bin/puppet_worker.rs b/polkadot/node/core/pvf/bin/puppet_worker.rs deleted file mode 100644 index 7f93519d845..00000000000 --- a/polkadot/node/core/pvf/bin/puppet_worker.rs +++ /dev/null @@ -1,17 +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 . - -polkadot_node_core_pvf::decl_puppet_worker_main!(); diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 4bdacca72f4..5fe2c6b6845 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -37,6 +37,5 @@ tempfile = "3.3.0" [features] # This feature is used to export test code to other crates without putting it in the production build. -# Also used for building the puppet worker. test-utils = [] jemalloc-allocator = [] diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index d0bd5b6bd7c..e7b996ccdc3 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -35,9 +35,14 @@ use tokio::{io, runtime::Runtime}; /// spawning the desired worker. #[macro_export] macro_rules! decl_worker_main { - ($expected_command:expr, $entrypoint:expr, $worker_version:expr $(,)*) => { + ($expected_command:expr, $entrypoint:expr, $worker_version:expr, $worker_version_hash:expr $(,)*) => { + fn get_full_version() -> String { + format!("{}-{}", $worker_version, $worker_version_hash) + } + fn print_help(expected_command: &str) { println!("{} {}", expected_command, $worker_version); + println!("commit: {}", $worker_version_hash); println!(); println!("PVF worker that is called by polkadot."); } @@ -67,6 +72,11 @@ macro_rules! decl_worker_main { println!("{}", $worker_version); return }, + // Useful for debugging. --version is used for version checks. + "--full-version" => { + println!("{}", get_full_version()); + return + }, "--check-can-enable-landlock" => { #[cfg(target_os = "linux")] diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index d7b15ece7b2..dd83f76494e 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -141,6 +141,7 @@ impl ArtifactPathId { } } +#[derive(Debug)] pub enum ArtifactState { /// The artifact is ready to be used by the executor. /// diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 81695829122..6c9606bb2f3 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -446,7 +446,8 @@ async fn handle_to_host( /// This tries to prepare the PVF by compiling the WASM blob within a timeout set in /// `PvfPrepData`. /// -/// If the prepare job failed previously, we may retry it under certain conditions. +/// We don't retry artifacts that previously failed preparation. We don't expect multiple +/// pre-checking requests. async fn handle_precheck_pvf( artifacts: &mut Artifacts, prepare_queue: &mut mpsc::Sender, @@ -464,8 +465,7 @@ async fn handle_precheck_pvf( ArtifactState::Preparing { waiting_for_response, num_failures: _ } => waiting_for_response.push(result_sender), ArtifactState::FailedToProcess { error, .. } => { - // Do not retry failed preparation if another pre-check request comes in. We do not - // retry pre-checking, anyway. + // Do not retry an artifact that previously failed preparation. let _ = result_sender.send(PrepareResult::Err(error.clone())); }, } @@ -764,7 +764,7 @@ async fn handle_prepare_done( let last_time_failed = SystemTime::now(); let num_failures = *num_failures + 1; - gum::warn!( + gum::error!( target: LOG_TARGET, ?artifact_id, time_failed = ?last_time_failed, @@ -846,7 +846,7 @@ async fn sweeper_task(mut sweeper_rx: mpsc::Receiver) { gum::trace!( target: LOG_TARGET, ?result, - "Sweeping the artifact file {}", + "Sweeped the artifact file {}", condemned.display(), ); }, diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index e3c6da9c4c6..27630af40c2 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -116,5 +116,18 @@ pub use polkadot_node_core_pvf_common::{ SecurityStatus, }; +use std::{path::Path, process::Command}; + /// The log target for this crate. pub const LOG_TARGET: &str = "parachain::pvf"; + +/// Utility to get the version of a worker, used for version checks. +/// +/// The worker's existence at the given path must be checked separately. +pub fn get_worker_version(worker_path: &Path) -> std::io::Result { + let worker_version = Command::new(worker_path).args(["--version"]).output()?.stdout; + Ok(std::str::from_utf8(&worker_version) + .expect("version is printed as a string; qed") + .trim() + .to_string()) +} diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index ca69ef9e4d0..31bcfe7fadb 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -15,13 +15,20 @@ // along with Polkadot. If not, see . //! Various things for testing other crates. -//! -//! N.B. This is not guarded with some feature flag. Overexposing items here may affect the final -//! artifact even for production builds. -pub use crate::worker_intf::{spawn_with_program_path, SpawnErr}; +pub use crate::{ + host::{EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}, + worker_intf::{spawn_with_program_path, SpawnErr}, +}; +use crate::get_worker_version; +use is_executable::IsExecutable; +use polkadot_node_primitives::NODE_VERSION; use polkadot_primitives::ExecutorParams; +use std::{ + path::PathBuf, + sync::{Mutex, OnceLock}, +}; /// A function that emulates the stitches together behaviors of the preparation and the execution /// worker in a single synchronous function. @@ -47,3 +54,46 @@ pub fn validate_candidate( Ok(result) } + +/// Retrieves the worker paths, checks that they exist and does a version check. +/// +/// NOTE: This should only be called in dev code (tests, benchmarks) as it relies on the relative +/// paths of the built workers. +pub fn get_and_check_worker_paths() -> (PathBuf, PathBuf) { + // Only needs to be called once for the current process. + static WORKER_PATHS: OnceLock> = OnceLock::new(); + let mutex = WORKER_PATHS.get_or_init(|| { + let mut workers_path = std::env::current_exe().unwrap(); + workers_path.pop(); + workers_path.pop(); + let mut prepare_worker_path = workers_path.clone(); + prepare_worker_path.push(PREPARE_BINARY_NAME); + let mut execute_worker_path = workers_path.clone(); + execute_worker_path.push(EXECUTE_BINARY_NAME); + + // Check that the workers are valid. + if !prepare_worker_path.is_executable() || !execute_worker_path.is_executable() { + panic!("ERROR: Workers do not exist or are not executable. Workers directory: {:?}", workers_path); + } + + let worker_version = + get_worker_version(&prepare_worker_path).expect("checked for worker existence"); + if worker_version != NODE_VERSION { + panic!("ERROR: Prepare worker version {worker_version} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}"); + } + let worker_version = + get_worker_version(&execute_worker_path).expect("checked for worker existence"); + if worker_version != NODE_VERSION { + panic!("ERROR: Execute worker version {worker_version} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}"); + } + + // We don't want to check against the commit hash because we'd have to always rebuild + // the calling crate on every commit. + eprintln!("WARNING: Workers match the node version, but may have changed in recent commits. Please rebuild them if anything funny happens. Workers path: {workers_path:?}"); + + Mutex::new((prepare_worker_path, execute_worker_path)) + }); + + let guard = mutex.lock().unwrap(); + (guard.0.clone(), guard.1.clone()) +} diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index bd85d84055c..e9382b66bf7 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -283,6 +283,7 @@ impl WorkerHandle { if let Ok(value) = std::env::var("RUST_LOG") { command.env("RUST_LOG", value); } + let mut child = command .args(extra_args) .arg("--socket-path") diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index f699b5840d8..cdf8d6eb82d 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -18,8 +18,9 @@ use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ - start, Config, InvalidCandidate, Metrics, PrepareError, PrepareJobKind, PrepareStats, - PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, + start, testing::get_and_check_worker_paths, 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; @@ -50,13 +51,8 @@ impl TestHost { where F: FnOnce(&mut Config), { - let mut workers_path = std::env::current_exe().unwrap(); - workers_path.pop(); - workers_path.pop(); - let mut prepare_worker_path = workers_path.clone(); - prepare_worker_path.push("polkadot-prepare-worker"); - let mut execute_worker_path = workers_path.clone(); - execute_worker_path.push("polkadot-execute-worker"); + let (prepare_worker_path, execute_worker_path) = get_and_check_worker_paths(); + let cache_dir = tempfile::tempdir().unwrap(); let mut config = Config::new( cache_dir.path().to_owned(), @@ -296,25 +292,9 @@ async fn deleting_prepared_artifact_does_not_dispute() { let host = TestHost::new(); let cache_dir = host.cache_dir.path(); - let result = host - .validate_candidate( - halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, - Default::default(), - ) - .await; - - match result { - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) => {}, - r => panic!("{:?}", r), - } + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); - // Delete the prepared artifact. + // Manually delete the prepared artifact from disk. The in-memory artifacts table won't change. { // Get the artifact path (asserting it exists). let mut cache_dir: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); @@ -329,7 +309,7 @@ async fn deleting_prepared_artifact_does_not_dispute() { std::fs::remove_file(artifact_path.path()).unwrap(); } - // Try to validate again, artifact should get recreated. + // Try to validate, artifact should get recreated. let result = host .validate_candidate( halt::wasm_binary_unwrap(), diff --git a/polkadot/node/core/pvf/tests/it/worker_common.rs b/polkadot/node/core/pvf/tests/it/worker_common.rs index 5379d29556c..df64980dc80 100644 --- a/polkadot/node/core/pvf/tests/it/worker_common.rs +++ b/polkadot/node/core/pvf/tests/it/worker_common.rs @@ -15,27 +15,21 @@ // along with Polkadot. If not, see . use polkadot_node_core_pvf::{ - testing::{spawn_with_program_path, SpawnErr}, + testing::{get_and_check_worker_paths, 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(); - worker_path.pop(); - worker_path.pop(); - worker_path.push(name); - worker_path -} - // Test spawning a program that immediately exits with a failure code. #[tokio::test] async fn spawn_immediate_exit() { + let (prepare_worker_path, _) = get_and_check_worker_paths(); + // There's no explicit `exit` subcommand in the worker; it will panic on an unknown // subcommand anyway let result = spawn_with_program_path( "integration-test", - worker_path("polkadot-prepare-worker"), + prepare_worker_path, &env::temp_dir(), &["exit"], Duration::from_secs(2), @@ -47,9 +41,11 @@ async fn spawn_immediate_exit() { #[tokio::test] async fn spawn_timeout() { + let (_, execute_worker_path) = get_and_check_worker_paths(); + let result = spawn_with_program_path( "integration-test", - worker_path("polkadot-execute-worker"), + execute_worker_path, &env::temp_dir(), &["test-sleep"], Duration::from_secs(2), @@ -61,9 +57,11 @@ async fn spawn_timeout() { #[tokio::test] async fn should_connect() { + let (prepare_worker_path, _) = get_and_check_worker_paths(); + let _ = spawn_with_program_path( "integration-test", - worker_path("polkadot-prepare-worker"), + prepare_worker_path, &env::temp_dir(), &["prepare-worker"], Duration::from_secs(2), diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 899a95dd3a7..3429f4e0a3a 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -74,9 +74,13 @@ frame-benchmarking-cli = { path = "../../../substrate/utils/frame/benchmarking-c frame-benchmarking = { path = "../../../substrate/frame/benchmarking" } # External Crates +async-trait = "0.1.57" futures = "0.3.21" hex-literal = "0.4.1" +is_executable = "1.0.1" gum = { package = "tracing-gum", path = "../gum" } +log = "0.4.17" +schnellru = "0.2.1" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" thiserror = "1.0.48" @@ -85,10 +89,6 @@ kvdb-rocksdb = { version = "0.19.0", optional = true } parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } -async-trait = "0.1.57" -log = "0.4.17" -is_executable = "1.0.1" - # Polkadot polkadot-core-primitives = { path = "../../core-primitives" } polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" } diff --git a/polkadot/node/service/src/workers.rs b/polkadot/node/service/src/workers.rs index 5f7cc1c2ed4..b35bb8302fd 100644 --- a/polkadot/node/service/src/workers.rs +++ b/polkadot/node/service/src/workers.rs @@ -18,7 +18,7 @@ use super::Error; use is_executable::IsExecutable; -use std::{path::PathBuf, process::Command}; +use std::path::PathBuf; #[cfg(test)] use std::sync::{Mutex, OnceLock}; @@ -75,11 +75,7 @@ pub fn determine_workers_paths( // Do the version check. if let Some(node_version) = node_version { - let worker_version = Command::new(&prep_worker_path).args(["--version"]).output()?.stdout; - let worker_version = std::str::from_utf8(&worker_version) - .expect("version is printed as a string; qed") - .trim() - .to_string(); + let worker_version = polkadot_node_core_pvf::get_worker_version(&prep_worker_path)?; if worker_version != node_version { return Err(Error::WorkerBinaryVersionMismatch { worker_version, @@ -87,11 +83,8 @@ pub fn determine_workers_paths( worker_path: prep_worker_path, }) } - let worker_version = Command::new(&exec_worker_path).args(["--version"]).output()?.stdout; - let worker_version = std::str::from_utf8(&worker_version) - .expect("version is printed as a string; qed") - .trim() - .to_string(); + + let worker_version = polkadot_node_core_pvf::get_worker_version(&exec_worker_path)?; if worker_version != node_version { return Err(Error::WorkerBinaryVersionMismatch { worker_version, @@ -215,11 +208,11 @@ mod tests { use serial_test::serial; use std::{env::temp_dir, fs, os::unix::fs::PermissionsExt, path::Path}; - const NODE_VERSION: &'static str = "v0.1.2"; + const TEST_NODE_VERSION: &'static str = "v0.1.2"; /// Write a dummy executable to the path which satisfies the version check. fn write_worker_exe(path: impl AsRef) -> Result<(), Box> { - let program = get_program(NODE_VERSION); + let program = get_program(TEST_NODE_VERSION); fs::write(&path, program)?; Ok(fs::set_permissions(&path, fs::Permissions::from_mode(0o744))?) } @@ -287,7 +280,7 @@ echo {} // Try with provided workers path that has missing binaries. assert_matches!( - determine_workers_paths(Some(given_workers_path.clone()), None, Some(NODE_VERSION.into())), + determine_workers_paths(Some(given_workers_path.clone()), None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: Some(p1), current_exe_path: p2, workers_names: None }) if p1 == given_workers_path && p2 == exe_path ); @@ -299,7 +292,7 @@ echo {} write_worker_exe(&execute_worker_path)?; fs::set_permissions(&execute_worker_path, fs::Permissions::from_mode(0o644))?; assert_matches!( - determine_workers_paths(Some(given_workers_path.clone()), None, Some(NODE_VERSION.into())), + determine_workers_paths(Some(given_workers_path.clone()), None, Some(TEST_NODE_VERSION.into())), Err(Error::InvalidWorkerBinaries { prep_worker_path: p1, exec_worker_path: p2 }) if p1 == prepare_worker_path && p2 == execute_worker_path ); @@ -307,15 +300,15 @@ echo {} fs::set_permissions(&prepare_worker_path, fs::Permissions::from_mode(0o744))?; fs::set_permissions(&execute_worker_path, fs::Permissions::from_mode(0o744))?; assert_matches!( - determine_workers_paths(Some(given_workers_path), None, Some(NODE_VERSION.into())), + determine_workers_paths(Some(given_workers_path), None, Some(TEST_NODE_VERSION.into())), Ok((p1, p2)) if p1 == prepare_worker_path && p2 == execute_worker_path ); // Try with valid provided workers path that is a binary file. - let given_workers_path = tempdir.join("usr/local/bin/puppet-worker"); + let given_workers_path = tempdir.join("usr/local/bin/test-worker"); write_worker_exe(&given_workers_path)?; assert_matches!( - determine_workers_paths(Some(given_workers_path.clone()), None, Some(NODE_VERSION.into())), + determine_workers_paths(Some(given_workers_path.clone()), None, Some(TEST_NODE_VERSION.into())), Ok((p1, p2)) if p1 == given_workers_path && p2 == given_workers_path ); @@ -330,7 +323,7 @@ echo {} with_temp_dir_structure(|tempdir, exe_path| { // Try with both binaries missing. assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: None, current_exe_path: p, workers_names: None }) if p == exe_path ); @@ -338,7 +331,7 @@ echo {} let prepare_worker_path = tempdir.join("usr/bin/polkadot-prepare-worker"); write_worker_exe(&prepare_worker_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: None, current_exe_path: p, workers_names: None }) if p == exe_path ); @@ -347,7 +340,7 @@ echo {} let execute_worker_path = tempdir.join("usr/bin/polkadot-execute-worker"); write_worker_exe(&execute_worker_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: None, current_exe_path: p, workers_names: None }) if p == exe_path ); @@ -356,7 +349,7 @@ echo {} let prepare_worker_path = tempdir.join("usr/lib/polkadot/polkadot-prepare-worker"); write_worker_exe(&prepare_worker_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: None, current_exe_path: p, workers_names: None }) if p == exe_path ); @@ -365,7 +358,7 @@ echo {} let execute_worker_path = tempdir.join("usr/lib/polkadot/polkadot-execute-worker"); write_worker_exe(execute_worker_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Err(Error::MissingWorkerBinaries { given_workers_path: None, current_exe_path: p, workers_names: None }) if p == exe_path ); @@ -440,8 +433,8 @@ echo {} write_worker_exe_invalid_version(&prepare_worker_bin_path, bad_version)?; write_worker_exe(&execute_worker_bin_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), - Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == NODE_VERSION && p == prepare_worker_bin_path + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), + Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == TEST_NODE_VERSION && p == prepare_worker_bin_path ); // Workers at lib location return bad version. @@ -452,8 +445,8 @@ echo {} write_worker_exe(&prepare_worker_lib_path)?; write_worker_exe_invalid_version(&execute_worker_lib_path, bad_version)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), - Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == NODE_VERSION && p == execute_worker_lib_path + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), + Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == TEST_NODE_VERSION && p == execute_worker_lib_path ); // Workers at provided workers location return bad version. @@ -463,16 +456,16 @@ echo {} write_worker_exe_invalid_version(&prepare_worker_path, bad_version)?; write_worker_exe_invalid_version(&execute_worker_path, bad_version)?; assert_matches!( - determine_workers_paths(Some(given_workers_path), None, Some(NODE_VERSION.into())), - Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == NODE_VERSION && p == prepare_worker_path + determine_workers_paths(Some(given_workers_path), None, Some(TEST_NODE_VERSION.into())), + Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == TEST_NODE_VERSION && p == prepare_worker_path ); // Given worker binary returns bad version. - let given_workers_path = tempdir.join("usr/local/bin/puppet-worker"); + let given_workers_path = tempdir.join("usr/local/bin/test-worker"); write_worker_exe_invalid_version(&given_workers_path, bad_version)?; assert_matches!( - determine_workers_paths(Some(given_workers_path.clone()), None, Some(NODE_VERSION.into())), - Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == NODE_VERSION && p == given_workers_path + determine_workers_paths(Some(given_workers_path.clone()), None, Some(TEST_NODE_VERSION.into())), + Err(Error::WorkerBinaryVersionMismatch { worker_version: v1, node_version: v2, worker_path: p }) if v1 == bad_version && v2 == TEST_NODE_VERSION && p == given_workers_path ); Ok(()) @@ -492,7 +485,7 @@ echo {} write_worker_exe(&execute_worker_bin_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Ok((p1, p2)) if p1 == prepare_worker_bin_path && p2 == execute_worker_bin_path ); @@ -509,7 +502,7 @@ echo {} write_worker_exe(&execute_worker_lib_path)?; assert_matches!( - determine_workers_paths(None, None, Some(NODE_VERSION.into())), + determine_workers_paths(None, None, Some(TEST_NODE_VERSION.into())), Ok((p1, p2)) if p1 == prepare_worker_lib_path && p2 == execute_worker_lib_path ); diff --git a/polkadot/src/bin/execute-worker.rs b/polkadot/src/bin/execute-worker.rs index 1deb3658098..c39a5a3c89d 100644 --- a/polkadot/src/bin/execute-worker.rs +++ b/polkadot/src/bin/execute-worker.rs @@ -20,4 +20,5 @@ polkadot_node_core_pvf_common::decl_worker_main!( "execute-worker", polkadot_node_core_pvf_execute_worker::worker_entrypoint, polkadot_cli::NODE_VERSION, + env!("SUBSTRATE_CLI_COMMIT_HASH"), ); diff --git a/polkadot/src/bin/prepare-worker.rs b/polkadot/src/bin/prepare-worker.rs index d731f8a30d0..3b42991f18b 100644 --- a/polkadot/src/bin/prepare-worker.rs +++ b/polkadot/src/bin/prepare-worker.rs @@ -20,4 +20,5 @@ polkadot_node_core_pvf_common::decl_worker_main!( "prepare-worker", polkadot_node_core_pvf_prepare_worker::worker_entrypoint, polkadot_cli::NODE_VERSION, + env!("SUBSTRATE_CLI_COMMIT_HASH"), ); diff --git a/substrate/utils/build-script-utils/src/version.rs b/substrate/utils/build-script-utils/src/version.rs index 309c6d71d77..f6a9ff9554a 100644 --- a/substrate/utils/build-script-utils/src/version.rs +++ b/substrate/utils/build-script-utils/src/version.rs @@ -31,7 +31,11 @@ pub fn generate_cargo_keys() { Cow::from(sha) }, Ok(o) => { - println!("cargo:warning=Git command failed with status: {}", o.status); + let stderr = String::from_utf8_lossy(&o.stderr).trim().to_owned(); + println!( + "cargo:warning=Git command failed with status '{}' with message: '{}'", + o.status, stderr, + ); Cow::from("unknown") }, Err(err) => { -- GitLab From 0284e21f556fc6a4b40795e86d76e939a34b96d1 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Tue, 24 Oct 2023 18:23:21 +0300 Subject: [PATCH 361/633] Refactor candidates test in paras_inherent (#2004) Splits the test in multiple cases. --- .../parachains/src/paras_inherent/tests.rs | 74 +++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index 7c70fcea194..4fc60792e34 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -1205,9 +1205,17 @@ mod sanitizers { } } - #[test] - fn candidates() { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + mod candidates { + use super::*; + + // Backed candidates and scheduled parachains used for `sanitize_backed_candidates` testing + struct TestData { + backed_candidates: Vec, + scheduled_paras: BTreeMap, + } + + // Generate test data for the candidates test + fn get_test_data() -> TestData { const RELAY_PARENT_NUM: u32 = 3; let header = default_header(); @@ -1233,9 +1241,6 @@ mod sanitizers { .unwrap(); } - let has_concluded_invalid = - |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - let scheduled = (0_usize..2) .into_iter() .map(|idx| (ParaId::from(1_u32 + idx as u32), CoreIndex::from(idx as u32))) @@ -1278,29 +1283,54 @@ mod sanitizers { }) .collect::>(); - // happy path - assert_eq!( - sanitize_backed_candidates::( - backed_candidates.clone(), - has_concluded_invalid, - &scheduled - ), - backed_candidates - ); + TestData { backed_candidates, scheduled_paras: scheduled } + } - // nothing is scheduled, so no paraids match, thus all backed candidates are skipped - { + #[test] + fn happy_path() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let TestData { backed_candidates, scheduled_paras: scheduled } = get_test_data(); + + let has_concluded_invalid = + |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; + + assert_eq!( + sanitize_backed_candidates::( + backed_candidates.clone(), + has_concluded_invalid, + &scheduled + ), + backed_candidates + ); + + {} + }); + } + + // nothing is scheduled, so no paraids match, thus all backed candidates are skipped + #[test] + fn nothing_scheduled() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let TestData { backed_candidates, scheduled_paras: _ } = get_test_data(); let scheduled = &BTreeMap::new(); + let has_concluded_invalid = + |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; + assert!(sanitize_backed_candidates::( backed_candidates.clone(), has_concluded_invalid, &scheduled ) .is_empty()); - } + }); + } + + // candidates that have concluded as invalid are filtered out + #[test] + fn invalid_are_filtered_out() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let TestData { backed_candidates, scheduled_paras: scheduled } = get_test_data(); - // candidates that have concluded as invalid are filtered out - { // mark every second one as concluded invalid let set = { let mut set = std::collections::HashSet::new(); @@ -1322,7 +1352,7 @@ mod sanitizers { .len(), backed_candidates.len() / 2 ); - } - }); + }); + } } } -- GitLab From 12130a76ac2b955f8ca68a53299cfddf3ff9dbae Mon Sep 17 00:00:00 2001 From: eskimor Date: Tue, 24 Oct 2023 17:51:01 +0200 Subject: [PATCH 362/633] Remove obsolete comment. (#2008) it is indeed correct. Co-authored-by: eskimor --- polkadot/runtime/parachains/src/scheduler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index f3333d5cf85..b81b68b5745 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -352,7 +352,6 @@ impl Pallet { None }, Ok((pos_in_claimqueue, pe)) => { - // is this correct? availability_cores[core_idx.0 as usize] = CoreOccupied::Paras(pe); Some((*core_idx, pos_in_claimqueue)) -- GitLab From 4a44356773d27221c4ac9e48786d07dc72104a48 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 24 Oct 2023 17:59:38 +0200 Subject: [PATCH 363/633] Improve features dev-ex (#1831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a config file that allows to run `zepter` without any arguments in the workspace to address all issues. A secondary workflow for the CI is provided as `zepter run check`. Both the formatting and linting are now in one check for efficiancy. The latest version also detects some more things that `featalign` was already showing. Error message [in the CI](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/3916205) now looks like this: ```pre ... crate 'test-parachains' (/Users/vados/Documents/work/polkadot-sdk/polkadot/parachain/test-parachains/Cargo.toml) feature 'std' must propagate to: parity-scale-codec Found 55 issues (run with --fix to fix). Error: Command 'lint propagate-feature' failed with exit code 1 Polkadot-SDK uses the Zepter CLI to detect abnormalities in the feature configuration. It looks like one more more checks failed; please check the console output. You can try to automatically address them by running `zepter`. Otherwise please ask directly in the Merge Request, GitHub Discussions or on Matrix Chat, thank you. For more information, see: - https://github.com/paritytech/polkadot-sdk/issues/1831 - https://github.com/ggwpez/zepter ``` TODO: - [x] Check that CI fails correctly --------- Signed-off-by: Oliver Tale-Yazdi --- .config/zepter.yaml | 45 +++++++++++++++++++ .gitlab/pipeline/check.yml | 19 ++------ .../chain-polkadot-bulletin/Cargo.toml | 1 + bridges/primitives/relayers/Cargo.toml | 2 + cumulus/pallets/parachain-system/Cargo.toml | 1 + cumulus/pallets/xcmp-queue/Cargo.toml | 1 + cumulus/parachains/common/Cargo.toml | 3 ++ .../assets/asset-hub-kusama/Cargo.toml | 1 + .../assets/asset-hub-rococo/Cargo.toml | 1 + .../assets/asset-hub-westend/Cargo.toml | 1 + .../runtimes/assets/common/Cargo.toml | 1 + .../runtimes/assets/test-utils/Cargo.toml | 1 + .../parachains/runtimes/test-utils/Cargo.toml | 1 + cumulus/primitives/timestamp/Cargo.toml | 1 + cumulus/primitives/utility/Cargo.toml | 1 + docs/STYLE_GUIDE.md | 2 +- polkadot/parachain/test-parachains/Cargo.toml | 2 +- .../test-parachains/adder/Cargo.toml | 2 +- .../test-parachains/undying/Cargo.toml | 8 +++- polkadot/runtime/parachains/Cargo.toml | 2 + polkadot/xcm/Cargo.toml | 1 + polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 2 + polkadot/xcm/pallet-xcm/Cargo.toml | 1 + polkadot/xcm/xcm-executor/Cargo.toml | 1 + substrate/bin/node/runtime/Cargo.toml | 1 + substrate/frame/asset-conversion/Cargo.toml | 1 + substrate/frame/democracy/Cargo.toml | 1 + substrate/frame/glutton/Cargo.toml | 1 + substrate/frame/identity/Cargo.toml | 1 + substrate/frame/message-queue/Cargo.toml | 1 + substrate/frame/multisig/Cargo.toml | 1 + substrate/frame/nfts/Cargo.toml | 1 + .../nomination-pools/benchmarking/Cargo.toml | 2 + substrate/frame/referenda/Cargo.toml | 1 + substrate/frame/society/Cargo.toml | 1 + substrate/frame/statement/Cargo.toml | 1 + substrate/frame/support/Cargo.toml | 1 + .../primitives/api/proc-macro/Cargo.toml | 2 +- .../primitives/consensus/beefy/Cargo.toml | 1 + substrate/primitives/core/Cargo.toml | 2 + substrate/primitives/io/Cargo.toml | 3 +- .../merkle-mountain-range/Cargo.toml | 1 + .../runtime-interface/test-wasm/Cargo.toml | 1 + .../primitives/statement-store/Cargo.toml | 2 + .../primitives/wasm-interface/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 + 46 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 .config/zepter.yaml diff --git a/.config/zepter.yaml b/.config/zepter.yaml new file mode 100644 index 00000000000..2bdc106b2da --- /dev/null +++ b/.config/zepter.yaml @@ -0,0 +1,45 @@ +version: + format: 1 + # Minimum version of the binary that is expected to work. This is just for printing a nice error + # message when someone tries to use an older version. + binary: 0.13.2 + +# The examples in this file assume crate `A` to have a dependency on crate `B`. +workflows: + check: + - [ + 'lint', + # Check that `A` activates the features of `B`. + 'propagate-feature', + # These are the features to check: + '--features=try-runtime,runtime-benchmarks,std', + # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. + '--left-side-feature-missing=ignore', + # Enabling this feature somehow pulls in two versions of `sp-runtime-interface` and makes it impossible to build that crate with `cargo b -p sp-runtime-interface`. We therefore disable it for now. + '--ignore-missing-propagate=sp-core/std:bandersnatch_vrfs/std', + # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. + '--left-side-outside-workspace=ignore', + # Some features imply that they activate a specific dependency as non-optional. Otherwise the default behaviour with a `?` is used. + '--feature-enables-dep=try-runtime:frame-try-runtime,runtime-benchmarks:frame-benchmarking', + # Actually modify the files and not just report the issues: + '--offline', + '--locked', + '--show-path', + '--quiet', + ] + # Format the features into canonical format: + - ['format', 'features', '--offline', '--locked', '--quiet'] + # Same as `check`, but with the `--fix` flag. + default: + - [ $check.0, '--fix' ] + - [ $check.1, '--fix' ] + +# Will be displayed when any workflow fails: +help: + text: | + Polkadot-SDK uses the Zepter CLI to detect abnormalities in the feature configuration. + It looks like one more more checks failed; please check the console output. You can try to automatically address them by running `zepter`. + Otherwise please ask directly in the Merge Request, GitHub Discussions or on Matrix Chat, thank you. + links: + - "https://github.com/paritytech/polkadot-sdk/issues/1831" + - "https://github.com/ggwpez/zepter" diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 5a304d8bc4e..bf2e7341b8b 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -21,16 +21,6 @@ check-try-runtime: # experimental code may rely on try-runtime and vice-versa - time cargo check --locked --all --features try-runtime,experimental -cargo-fmt-manifest: - stage: check - extends: - - .docker-env - - .common-refs - script: - - 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 - # FIXME .cargo-deny-licenses: stage: check @@ -91,17 +81,14 @@ job-starter: script: - echo ok -test-rust-feature-propagation: +check-rust-feature-propagation: stage: check extends: - .kubernetes-env - .test-pr-refs script: - - cargo install --locked --version 0.11.1 -q -f zepter && zepter --version - - echo "👉 Hello developer! If you see this CI check failing then it means that one of the crates is missing a feature for one of its dependencies. The output below tells you which feature needs to be added for which dependency to which crate. You can do this by modifying the Cargo.toml file. For more context see the MR where this check was introduced https://github.com/paritytech/substrate/pull/14660" - - zepter lint propagate-feature --feature try-runtime --left-side-feature-missing=ignore --workspace --feature-enables-dep="try-runtime:frame-try-runtime" --locked - - zepter lint propagate-feature --feature runtime-benchmarks --left-side-feature-missing=ignore --workspace --feature-enables-dep="runtime-benchmarks:frame-benchmarking" --locked - - zepter lint propagate-feature --feature std --left-side-feature-missing=ignore --workspace --locked + - cargo install --locked --version 0.13.2 -q -f zepter && zepter --version + - zepter run check # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 .check-runtime-migration: diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml index d748f5aa933..9cc79bef1a6 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -35,6 +35,7 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-api/std", "sp-runtime/std", "sp-std/std", diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 93ad0789263..ffed2debbe6 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -30,7 +30,9 @@ default = [ "std" ] std = [ "bp-messages/std", "bp-runtime/std", + "codec/std", "frame-support/std", + "scale-info/std", "sp-runtime/std", "sp-std/std", ] diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 1b367f94e33..d48604d5025 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -55,6 +55,7 @@ cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } [features] default = [ "std" ] std = [ + "bytes/std", "codec/std", "cumulus-pallet-parachain-system-proc-macro/std", "cumulus-primitives-core/std", diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 358a0bec8bb..b923c16cb1b 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -57,6 +57,7 @@ std = [ "log/std", "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", + "rand_chacha/std", "scale-info/std", "sp-core/std", "sp-io/std", diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 3393a7a46c1..92c7cb6ef12 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -52,11 +52,13 @@ substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } [features] default = [ "std" ] std = [ + "codec/std", "cumulus-primitives-core/std", "cumulus-primitives-utility/std", "frame-support/std", "frame-system/std", "log/std", + "num-traits/std", "pallet-asset-tx-payment/std", "pallet-assets/std", "pallet-authorship/std", @@ -66,6 +68,7 @@ std = [ "polkadot-core-primitives/std", "polkadot-primitives/std", "rococo-runtime-constants/std", + "scale-info/std", "sp-consensus-aura/std", "sp-core/std", "sp-io/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index dc401e3d8cd..ede9c6af35a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -203,6 +203,7 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", + "primitive-types/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index b1ec66f40bf..ea5b5fa0554 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -217,6 +217,7 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", + "primitive-types/std", "rococo-runtime-constants/std", "scale-info/std", "sp-api/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 7a523f8bfb6..5e3807f2785 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -194,6 +194,7 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", + "primitive-types/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 56171c7212e..770acc93c71 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -43,6 +43,7 @@ std = [ "pallet-asset-tx-payment/std", "pallet-xcm/std", "parachains-common/std", + "scale-info/std", "sp-api/std", "sp-runtime/std", "sp-std/std", diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index d8b5ca5c8e5..86cc72e2dd3 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -53,6 +53,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" default = [ "std" ] std = [ "assets-common/std", + "codec/std", "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 1ecbb212a0e..c455807fd8f 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -49,6 +49,7 @@ substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } default = [ "std" ] std = [ "assets-common/std", + "codec/std", "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index 6b0d3d4a4dc..aed51a44912 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -20,6 +20,7 @@ cumulus-primitives-core = { path = "../core", default-features = false } [features] default = [ "std" ] std = [ + "codec/std", "cumulus-primitives-core/std", "sp-inherents/std", "sp-std/std", diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 691a4599b2c..d50f93d89b7 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -31,6 +31,7 @@ std = [ "codec/std", "cumulus-primitives-core/std", "frame-support/std", + "log/std", "pallet-xcm-benchmarks/std", "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", diff --git a/docs/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md index a9ac4a5910b..1ae9bc5003f 100644 --- a/docs/STYLE_GUIDE.md +++ b/docs/STYLE_GUIDE.md @@ -152,7 +152,7 @@ let mut target_path = > **TLDR** > You can use the CLI tool [Zepter](https://crates.io/crates/zepter) to -> format the files: `zepter format features` +> format the files: `zepter format features --fix` (or `zepter f f -f`). Rust `Cargo.toml` files need to respect certain formatting rules. All entries need to be alphabetically sorted. This makes it easier to read them and insert diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index a30be9c678a..3252d1f83cd 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -19,4 +19,4 @@ sp-core = { path = "../../../substrate/primitives/core" } [features] default = [ "std" ] -std = [ "adder/std", "halt/std" ] +std = [ "adder/std", "halt/std", "parity-scale-codec/std" ] diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index f22b5ccfdcc..1a47328b28e 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -23,4 +23,4 @@ substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } [features] default = [ "std" ] -std = [ "parachain/std", "sp-io/std", "sp-std/std" ] +std = [ "parachain/std", "parity-scale-codec/std", "sp-io/std", "sp-std/std" ] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 8690da5a4bd..273eef4b63a 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -24,4 +24,10 @@ substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } [features] default = [ "std" ] -std = [ "parachain/std", "sp-io/std", "sp-std/std" ] +std = [ + "log/std", + "parachain/std", + "parity-scale-codec/std", + "sp-io/std", + "sp-std/std", +] diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index a3950083373..e49c00459de 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -88,6 +88,8 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-runtime-metrics/std", "primitives/std", + "rand/std", + "rand_chacha/std", "rustc-hex/std", "scale-info/std", "serde/std", diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 92024e69c1b..60c27f7fcfc 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -29,6 +29,7 @@ wasm-api = [] std = [ "bounded-collections/std", "environmental/std", + "log/std", "parity-scale-codec/std", "scale-info/std", "serde/std", diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index fb4f389b212..88df81a3dad 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -41,6 +41,8 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "log/std", + "scale-info/std", "sp-io/std", "sp-runtime/std", "sp-std/std", diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index e471e8cf269..da472fbe6db 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -38,6 +38,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "serde", "sp-core/std", diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 902f55901d6..9f0caa80617 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -29,6 +29,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", ] std = [ + "environmental/std", "frame-benchmarking/std", "frame-support/std", "log/std", diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index bf6c540774c..a9d685523f6 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -228,6 +228,7 @@ std = [ "pallet-utility/std", "pallet-vesting/std", "pallet-whitelist/std", + "primitive-types/std", "scale-info/std", "sp-api/std", "sp-authority-discovery/std", diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 0fd2d6c19f8..de898d4ccde 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -39,6 +39,7 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-balances/std", + "primitive-types/std", "scale-info/std", "sp-api/std", "sp-arithmetic/std", diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index c1477745848..870bfaa9b89 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -39,6 +39,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "pallet-preimage/std", "pallet-scheduler/std", diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 3f47191cf0a..368fcab65cc 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -36,6 +36,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "scale-info/std", "sp-core/std", diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index cc2b50cdbd3..309c0aab550 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -31,6 +31,7 @@ sp-core = { path = "../../primitives/core" } default = [ "std" ] std = [ "codec/std", + "enumflags2/std", "frame-benchmarking?/std", "frame-support/std", "frame-system/std", diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 831259597ea..48304cd882c 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -37,6 +37,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-arithmetic/std", "sp-core/std", diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index b0fc189974b..a2ee608c33c 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -35,6 +35,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "scale-info/std", "sp-io/std", diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 3ad8707b9a3..2a3b2921c75 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -33,6 +33,7 @@ sp-keystore = { path = "../../primitives/keystore" } default = [ "std" ] std = [ "codec/std", + "enumflags2/std", "frame-benchmarking?/std", "frame-support/std", "frame-system/std", diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index e4720f25fcd..e8b18666815 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -43,6 +43,7 @@ sp-io = { path = "../../../primitives/io" } default = [ "std" ] std = [ + "codec/std", "frame-benchmarking/std", "frame-election-provider-support/std", "frame-support/std", @@ -52,6 +53,7 @@ std = [ "pallet-nomination-pools/std", "pallet-staking/std", "pallet-timestamp/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime-interface/std", diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 9146bef79ce..4f53e2bc002 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -42,6 +42,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "pallet-preimage/std", "pallet-scheduler/std", diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index fa13bc3bc8d..654447e6893 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -40,6 +40,7 @@ std = [ "frame-support-test/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "rand_chacha/std", "scale-info/std", diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index ffb469051d1..a5c8cf5b8de 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -33,6 +33,7 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "scale-info/std", "sp-api/std", diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 3eb453d9b2e..5caf993bb35 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -66,6 +66,7 @@ std = [ "log/std", "scale-info/std", "serde/std", + "serde_json/std", "sp-api/std", "sp-arithmetic/std", "sp-core/std", diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 25c87b5d0a4..d60b9f1bb4e 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -30,6 +30,6 @@ assert_matches = "1.3.0" [features] # Required for the doc tests default = [ "std" ] -std = [] +std = [ "blake2/std" ] no-metadata-docs = [] frame-metadata = [] diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index cfc98f19bcc..5ff0a2ebc70 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -42,6 +42,7 @@ std = [ "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", + "strum/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 7929833a2e2..1b6b10eeeed 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -116,7 +116,9 @@ std = [ "thiserror", "tiny-bip39", "tracing", + "w3f-bls?/std", "zeroize/alloc", + "zeroize/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index ab9d26ec26f..445104b736e 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -44,8 +44,9 @@ std = [ "bytes/std", "codec/std", "ed25519-dalek", + "ed25519-dalek?/std", "libsecp256k1", - "log", + "log/std", "secp256k1", "sp-core/std", "sp-externalities/std", diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 166c1895445..5216765825f 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -33,6 +33,7 @@ std = [ "codec/std", "log/std", "mmr-lib/std", + "scale-info/std", "serde/std", "sp-api/std", "sp-core/std", diff --git a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml index de0d6f9a13e..7729f89fa39 100644 --- a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml @@ -25,6 +25,7 @@ substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true [features] default = [ "std" ] std = [ + "bytes/std", "sp-core/std", "sp-io/std", "sp-runtime-interface/std", diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 75bbf421ada..658229cef22 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -37,10 +37,12 @@ rand = { version = "0.8.5", features = ["small_rng"], optional = true } default = [ "std" ] std = [ "aes-gcm", + "aes-gcm?/std", "codec/std", "curve25519-dalek", "ed25519-dalek", "hkdf", + "hkdf?/std", "rand", "scale-info/std", "sha2", diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 92f884e3fd2..c7413fec43c 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -23,5 +23,5 @@ sp-std = { path = "../std", default-features = false} [features] default = [ "std" ] -std = [ "codec/std", "log", "sp-std/std", "wasmtime" ] +std = [ "codec/std", "log/std", "sp-std/std", "wasmtime" ] wasmtime = [ "anyhow", "dep:wasmtime" ] diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index dc0a6076a29..84b214a0b9c 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -81,6 +81,8 @@ std = [ "sc-executor/std", "sc-service", "scale-info/std", + "serde/std", + "serde_json/std", "sp-api/std", "sp-application-crypto/std", "sp-block-builder/std", -- GitLab From 8a79fb22dbe8796579d28d06077341cec4ae67d0 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:44:48 +0200 Subject: [PATCH 364/633] [ci] Run check-rust-feature-propagation in pr and master (#2012) Need to run this job in master to make it `Required` --- .gitlab/pipeline/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index bf2e7341b8b..cd26003d88c 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -85,7 +85,7 @@ check-rust-feature-propagation: stage: check extends: - .kubernetes-env - - .test-pr-refs + - .common-refs script: - cargo install --locked --version 0.13.2 -q -f zepter && zepter --version - zepter run check -- GitLab From fbd57771185ffe1f928d420f8942b0d39febd7bc Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:37:34 +0000 Subject: [PATCH 365/633] Application Crypto and BEEFY Support for paired (ECDSA,BLS) crypto (#1815) Next step in process of making BEEFY being able to generate both ECDSA and BLS signature after #1705. It allows BEEFY to use a pair of ECDSA and BLS key as a AuthorityId. --------- Co-authored-by: Davide Galassi Co-authored-by: Robert Hambrock --- substrate/client/keystore/src/local.rs | 27 +++++++- .../application-crypto/src/ecdsa_bls377.rs | 57 ++++++++++++++++ .../primitives/application-crypto/src/lib.rs | 2 + .../primitives/consensus/beefy/src/lib.rs | 66 +++++++++++++++++-- substrate/primitives/core/src/bls.rs | 2 +- substrate/primitives/core/src/lib.rs | 2 + .../primitives/core/src/paired_crypto.rs | 20 +++--- substrate/primitives/core/src/testing.rs | 2 + substrate/primitives/io/src/lib.rs | 21 +++++- substrate/primitives/keystore/src/lib.rs | 65 +++++++++++++++++- substrate/primitives/keystore/src/testing.rs | 26 +++++++- 11 files changed, 273 insertions(+), 17 deletions(-) create mode 100644 substrate/primitives/application-crypto/src/ecdsa_bls377.rs diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index c77f023e0f0..8089dbba035 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; } use crate::{Error, Result}; @@ -366,6 +366,31 @@ impl Keystore for LocalKeystore { ) -> std::result::Result, TraitError> { self.sign::(key_type, public, msg) } + + fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + /// Generate a new pair of paired-keys compatible with the '(ecdsa,bls377)' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } + + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } + } } diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs new file mode 100644 index 00000000000..70940587ced --- /dev/null +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -0,0 +1,57 @@ +// 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. + +//! ECDSA and BLS12-377 paired crypto applications. + +use crate::{KeyTypeId, RuntimePublic}; + +pub use sp_core::paired_crypto::ecdsa_bls377::*; + +mod app { + crate::app_crypto!(super, sp_core::testing::ECDSA_BLS377); +} + +#[cfg(feature = "full_crypto")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + /// Dummy implementation. Returns an empty vector. + fn all(_key_type: KeyTypeId) -> Vec { + Vec::new() + } + + fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { + sp_io::crypto::ecdsa_bls377_generate(key_type, seed) + } + + /// Dummy implementation. Returns `None`. + fn sign>(&self, _key_type: KeyTypeId, _msg: &M) -> Option { + None + } + + /// Dummy implementation. Returns `false`. + fn verify>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + false + } + + fn to_raw_vec(&self) -> Vec { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 5384220bc9c..686b486f335 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -50,6 +50,8 @@ pub mod bls377; #[cfg(feature = "bls-experimental")] pub mod bls381; pub mod ecdsa; +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls377; pub mod ed25519; pub mod sr25519; mod traits; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index c69e26bf574..5bdf8ce010a 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -74,10 +74,11 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { /// Your code should use the above types as concrete types for all crypto related /// functionality. pub mod ecdsa_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; - app_crypto!(ecdsa, BEEFY_KEY_TYPE); + + app_crypto!(ecdsa, KEY_TYPE); /// Identity of a BEEFY authority using ECDSA as its crypto. pub type AuthorityId = Public; @@ -115,10 +116,11 @@ pub mod ecdsa_crypto { #[cfg(feature = "bls-experimental")] pub mod bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, bls377}; use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; - app_crypto!(bls377, BEEFY_KEY_TYPE); + + app_crypto!(bls377, KEY_TYPE); /// Identity of a BEEFY authority using BLS as its crypto. pub type AuthorityId = Public; @@ -140,6 +142,46 @@ pub mod bls_crypto { } } } + +/// BEEFY cryptographic types for (ECDSA,BLS) crypto pair +/// +/// This module basically introduces four crypto types: +/// - `ecdsa_bls_crypto::Pair` +/// - `ecdsa_bls_crypto::Public` +/// - `ecdsa_bls_crypto::Signature` +/// - `ecdsa_bls_crypto::AuthorityId` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls_crypto { + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use sp_application_crypto::{app_crypto, ecdsa_bls377}; + use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; + + app_crypto!(ecdsa_bls377, KEY_TYPE); + + /// Identity of a BEEFY authority using (ECDSA,BLS) as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using (ECDSA,BLS) as its crypto. + pub type AuthoritySignature = Signature; + + impl BeefyAuthorityId for AuthorityId + where + ::Output: Into<[u8; 32]>, + { + fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { + // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // a choice of hash to field function. + // We are directly calling into the library to avoid introducing new host call. + // and because BeefyAuthorityId::verify is being called in the runtime so we don't have + + EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + } + } +} + /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; @@ -458,4 +500,20 @@ mod tests { let (other_pair, _) = bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); } + + #[test] + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls_beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = ecdsa_bls_crypto::Pair::generate(); + + let signature: ecdsa_bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); + + // Other public key doesn't work + let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); + assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); + } } diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 8ce6eb166f8..e519ba1806c 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -134,7 +134,7 @@ impl Eq for Public {} impl PartialOrd for Public { fn partial_cmp(&self, other: &Self) -> Option { - self.inner.partial_cmp(&other.inner) + Some(self.cmp(other)) } } diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 75b84c89ae6..ec0641c5466 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -75,6 +75,8 @@ pub mod uint; #[cfg(feature = "bls-experimental")] pub use bls::{bls377, bls381}; +#[cfg(feature = "bls-experimental")] +pub use paired_crypto::ecdsa_bls377; pub use self::{ hash::{convert_hash, H160, H256, H512}, diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 355fc690779..a97b657e757 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -33,12 +33,12 @@ 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_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] -pub mod ecdsa_n_bls377 { +pub mod ecdsa_bls377 { use crate::{bls377, crypto::CryptoTypeId, ecdsa}; /// An identifier used to match public keys against BLS12-377 keys @@ -49,12 +49,12 @@ pub mod ecdsa_n_bls377 { const SIGNATURE_LEN: usize = ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; - /// (ECDSA, BLS12-377) key-pair pair. + /// (ECDSA,BLS12-377) key-pair pair. #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; - /// (ECDSA, BLS12-377) public key pair. + /// (ECDSA,BLS12-377) public key pair. pub type Public = super::Public; - /// (ECDSA, BLS12-377) signature pair. + /// (ECDSA,BLS12-377) signature pair. pub type Signature = super::Signature; impl super::CryptoType for Public { @@ -151,6 +151,10 @@ impl PassByInner for Public PassBy for Public { + type PassBy = pass_by::Inner; +} + #[cfg(feature = "full_crypto")] impl< LeftPair: PairT, @@ -244,7 +248,7 @@ pub trait SignatureBound: ByteArray {} impl SignatureBound for T {} /// A pair of signatures of different types -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] pub struct Signature([u8; LEFT_PLUS_RIGHT_LEN]); #[cfg(feature = "full_crypto")] @@ -447,12 +451,12 @@ where } } -// Test set exercising the (ECDSA, BLS12-377) implementation +// 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 ecdsa_bls377::{Pair, Signature}; use crate::{bls377, ecdsa}; #[test] diff --git a/substrate/primitives/core/src/testing.rs b/substrate/primitives/core/src/testing.rs index 25f5f9012c9..947dcc387fc 100644 --- a/substrate/primitives/core/src/testing.rs +++ b/substrate/primitives/core/src/testing.rs @@ -31,6 +31,8 @@ pub const BANDERSNATCH: KeyTypeId = KeyTypeId(*b"band"); pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); /// Key type for generic BLS12-381 key. pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); +/// Key type for (ECDSA,BLS12-377) key pair +pub const ECDSA_BLS377: KeyTypeId = KeyTypeId(*b"ecb7"); /// Macro for exporting functions from wasm in with the expected signature for using it with the /// wasm executor. This is useful for tests where you need to call a function in wasm. diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index ec098a155c9..c4182d6ab3a 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -106,7 +106,7 @@ use sp_core::{ }; #[cfg(feature = "bls-experimental")] -use sp_core::bls377; +use sp_core::{bls377, ecdsa_bls377}; #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1207,6 +1207,25 @@ pub trait Crypto { .expect("`bls377_generate` failed") } + /// Generate an `(ecdsa,bls12-377)` key for the given key type using an optional `seed` and + /// store it in the keystore. + /// + /// The `seed` needs to be a valid utf8. + /// + /// Returns the public key. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate( + &mut self, + id: KeyTypeId, + seed: Option>, + ) -> ecdsa_bls377::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + self.extension::() + .expect("No `keystore` associated for the current context!") + .ecdsa_bls377_generate_new(id, seed) + .expect("`ecdsa_bls377_generate` failed") + } + /// Generate a `bandersnatch` key pair for the given key type using an optional /// `seed` and store it in the keystore. /// diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 035af7099a6..e415080779c 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -23,7 +23,7 @@ pub mod testing; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -270,6 +270,10 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls377_public_keys(&self, id: KeyTypeId) -> Vec; + /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec; + /// Generate a new bls381 key pair for the given key type and an optional seed. /// /// Returns an `bls381::Public` key of the generated key pair or an `Err` if @@ -292,6 +296,17 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result; + /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. + /// + /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result; + /// Generate a bls381 signature for a given message. /// /// Receives [`KeyTypeId`] and a [`bls381::Public`] key to be able to map @@ -324,6 +339,22 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; + /// Generate a (ecdsa,bls377) signature pair for a given message. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -349,6 +380,7 @@ pub trait Keystore: Send + Sync { /// - bandersnatch /// - bls381 /// - bls377 + /// - (ecdsa,bls377) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -398,6 +430,13 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let public = ecdsa_bls377::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) + }, + _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -560,6 +599,11 @@ impl Keystore for Arc { (**self).bls377_public_keys(id) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec { + (**self).ecdsa_bls377_public_keys(id) + } + #[cfg(feature = "bls-experimental")] fn bls381_generate_new( &self, @@ -578,6 +622,15 @@ impl Keystore for Arc { (**self).bls377_generate_new(key_type, seed) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + (**self).ecdsa_bls377_generate_new(key_type, seed) + } + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, @@ -598,6 +651,16 @@ impl Keystore for Arc { (**self).bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls377_sign(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index efa35fd24bf..7f5dfd9faa7 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -322,6 +322,30 @@ impl Keystore for MemoryKeystore { self.sign::(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + self.generate_new::(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + self.sign::(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() -- GitLab From 2e11ae89dc13e55c3162b9e7d7af6a1fe531df62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 25 Oct 2023 00:30:48 +0200 Subject: [PATCH 366/633] basic-authorship: Improve time recording and logging (#2010) --- .../basic-authorship/src/basic_authorship.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 57c2996ab40..4db2de61cb4 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -334,7 +334,7 @@ where deadline: time::Instant, block_size_limit: Option, ) -> Result, sp_blockchain::Error> { - let propose_with_timer = time::Instant::now(); + let block_timer = time::Instant::now(); let mut block_builder = self.client.new_block_at(self.parent_hash, inherent_digests, PR::ENABLED)?; @@ -343,7 +343,6 @@ where // TODO call `after_inherents` and check if we should apply extrinsincs here // - let block_timer = time::Instant::now(); let end_reason = self.apply_extrinsics(&mut block_builder, deadline, block_size_limit).await?; let (block, storage_changes, proof) = block_builder.build()?.into_inner(); @@ -352,7 +351,7 @@ where let proof = PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?; - self.print_summary(&block, end_reason, block_took, propose_with_timer.elapsed()); + self.print_summary(&block, end_reason, block_took, block_timer.elapsed()); Ok(Proposal { block, proof, storage_changes }) } @@ -443,6 +442,11 @@ where let pending_tx = if let Some(pending_tx) = pending_iterator.next() { pending_tx } else { + debug!( + target: LOG_TARGET, + "No more transactions, proceeding with proposing." + ); + break EndProposingReason::NoMoreTransactions }; @@ -539,19 +543,24 @@ where } /// Prints a summary and does telemetry + metrics. + /// + /// - `block`: The block that was build. + /// - `end_reason`: Why did we stop producing the block? + /// - `block_took`: How long did it took to produce the actual block? + /// - `propose_took`: How long did the entire proposing took? fn print_summary( &self, block: &Block, end_reason: EndProposingReason, block_took: time::Duration, - propose_with_took: time::Duration, + propose_took: time::Duration, ) { let extrinsics = block.extrinsics(); self.metrics.report(|metrics| { metrics.number_of_transactions.set(extrinsics.len() as u64); metrics.block_constructed.observe(block_took.as_secs_f64()); metrics.report_end_proposing_reason(end_reason); - metrics.create_block_proposal_time.observe(propose_with_took.as_secs_f64()); + metrics.create_block_proposal_time.observe(propose_took.as_secs_f64()); }); let extrinsics_summary = if extrinsics.is_empty() { -- GitLab From ff3a3bca449a3cae910d2dc8c7ed3658938c6478 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 25 Oct 2023 11:02:13 +1100 Subject: [PATCH 367/633] Small optimisation to `--profile dev` wasm builds (#1851) `wasm-builder` was adjusted to default to building wasm blobs in `release` mode even when cargo is in `debug` because `debug` wasm is too slow. A side effect of this was `.compact` and `.compact.compressed` getting built when the dev is running build in `debug`, adding ~5s to the build time of every wasm runtime. I think it's reasonable to assume if the dev is running `debug` build they want to optimise speed and do not care about the size of the wasm binary. Compacting a blob has negligible impact on its actual performance. In this PR, I adjusted the behavior of the wasm builder so it does not produce `.compact` or `.compact.compressed` wasm when the user is running in `debug`. The builder will continue to produce the bloaty wasm in release mode unless it is overriden with an env var. As suggested by @koute in review, also refactored the `maybe_compact_wasm_and_copy_blobs` into multiple funuctions, and renamed things to better support RISC-V in the future. --- There is no `T-runtime` label so @KiChjang told me to put `T1-FRAME` :) --------- Co-authored-by: Koute --- substrate/utils/wasm-builder/src/builder.rs | 4 +- .../utils/wasm-builder/src/wasm_project.rs | 305 +++++++++++------- 2 files changed, 190 insertions(+), 119 deletions(-) diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index e0a30644b23..9c1655d8562 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -273,9 +273,9 @@ fn build_project( ); let (wasm_binary, wasm_binary_bloaty) = if let Some(wasm_binary) = wasm_binary { - (wasm_binary.wasm_binary_path_escaped(), bloaty.wasm_binary_bloaty_path_escaped()) + (wasm_binary.wasm_binary_path_escaped(), bloaty.bloaty_path_escaped()) } else { - (bloaty.wasm_binary_bloaty_path_escaped(), bloaty.wasm_binary_bloaty_path_escaped()) + (bloaty.bloaty_path_escaped(), bloaty.bloaty_path_escaped()) }; crate::write_file_if_changed( diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index da6fab863df..c41e0935d75 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -48,13 +48,13 @@ fn colorize_info_message(message: &str) -> String { pub struct WasmBinaryBloaty(PathBuf); impl WasmBinaryBloaty { - /// Returns the escaped path to the bloaty wasm binary. - pub fn wasm_binary_bloaty_path_escaped(&self) -> String { + /// Returns the escaped path to the bloaty binary. + pub fn bloaty_path_escaped(&self) -> String { self.0.display().to_string().escape_default().to_string() } - /// Returns the path to the wasm binary. - pub fn wasm_binary_bloaty_path(&self) -> &Path { + /// Returns the path to the binary. + pub fn bloaty_path(&self) -> &Path { &self.0 } } @@ -110,78 +110,112 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { /// /// # Returns /// -/// The path to the compact WASM binary and the bloaty WASM binary. +/// The path to the compact runtime binary and the bloaty runtime binary. pub(crate) fn create_and_compile( project_cargo_toml: &Path, default_rustflags: &str, cargo_cmd: CargoCommandVersioned, features_to_enable: Vec, - wasm_binary_name: Option, + bloaty_blob_out_name_override: Option, check_for_runtime_version_section: bool, ) -> (Option, WasmBinaryBloaty) { - let wasm_workspace_root = get_wasm_workspace_root(); - let wasm_workspace = wasm_workspace_root.join("wbuild"); + let runtime_workspace_root = get_wasm_workspace_root(); + let runtime_workspace = runtime_workspace_root.join("wbuild"); let crate_metadata = crate_metadata(project_cargo_toml); let project = create_project( project_cargo_toml, - &wasm_workspace, + &runtime_workspace, &crate_metadata, crate_metadata.workspace_root.as_ref(), features_to_enable, ); - let profile = build_project(&project, default_rustflags, cargo_cmd); - let (wasm_binary, wasm_binary_compressed, bloaty) = - compact_wasm_file(&project, profile, project_cargo_toml, wasm_binary_name); + let build_config = BuildConfiguration::detect(&project); + + // Build the bloaty runtime blob + build_bloaty_blob(&build_config.blob_build_profile, &project, default_rustflags, cargo_cmd); + + // Get the name of the bloaty runtime blob. + let bloaty_blob_default_name = get_blob_name(project_cargo_toml); + let bloaty_blob_out_name = + bloaty_blob_out_name_override.unwrap_or_else(|| bloaty_blob_default_name.clone()); + + let bloaty_blob_binary = copy_bloaty_blob( + &project, + &build_config.blob_build_profile, + &bloaty_blob_default_name, + &bloaty_blob_out_name, + ); + + // Try to compact and compress the bloaty blob, if the *outer* profile wants it. + // + // This is because, by default the inner profile will be set to `Release` even when the outer + // profile is `Debug`, because the blob built in `Debug` profile is too slow for normal + // development activities. + let (compact_blob_path, compact_compressed_blob_path) = + if build_config.outer_build_profile.wants_compact() { + let compact_blob_path = compact_wasm( + &project, + &build_config.blob_build_profile, + project_cargo_toml, + &bloaty_blob_out_name, + ); + let compact_compressed_blob_path = compact_blob_path + .as_ref() + .and_then(|p| try_compress_blob(&p.0, &bloaty_blob_out_name)); + (compact_blob_path, compact_compressed_blob_path) + } else { + (None, None) + }; if check_for_runtime_version_section { - ensure_runtime_version_wasm_section_exists(bloaty.wasm_binary_bloaty_path()); + ensure_runtime_version_wasm_section_exists(bloaty_blob_binary.bloaty_path()); } - wasm_binary + compact_blob_path .as_ref() - .map(|wasm_binary| copy_wasm_to_target_directory(project_cargo_toml, wasm_binary)); + .map(|wasm_binary| copy_blob_to_target_directory(project_cargo_toml, wasm_binary)); - wasm_binary_compressed.as_ref().map(|wasm_binary_compressed| { - copy_wasm_to_target_directory(project_cargo_toml, wasm_binary_compressed) + compact_compressed_blob_path.as_ref().map(|wasm_binary_compressed| { + copy_blob_to_target_directory(project_cargo_toml, wasm_binary_compressed) }); - let final_wasm_binary = wasm_binary_compressed.or(wasm_binary); + let final_blob_binary = compact_compressed_blob_path.or(compact_blob_path); generate_rerun_if_changed_instructions( project_cargo_toml, &project, - &wasm_workspace, - final_wasm_binary.as_ref(), - &bloaty, + &runtime_workspace, + final_blob_binary.as_ref(), + &bloaty_blob_binary, ); - if let Err(err) = adjust_mtime(&bloaty, final_wasm_binary.as_ref()) { - build_helper::warning!("Error while adjusting the mtime of the wasm binaries: {}", err) + if let Err(err) = adjust_mtime(&bloaty_blob_binary, final_blob_binary.as_ref()) { + build_helper::warning!("Error while adjusting the mtime of the blob binaries: {}", err) } - (final_wasm_binary, bloaty) + (final_blob_binary, bloaty_blob_binary) } -/// Ensures that the `runtime_version` wasm section exists in the given wasm file. +/// Ensures that the `runtime_version` section exists in the given blob. /// /// If the section can not be found, it will print an error and exit the builder. -fn ensure_runtime_version_wasm_section_exists(wasm: &Path) { - let wasm_blob = fs::read(wasm).expect("`{wasm}` was just written and should exist; qed"); +fn ensure_runtime_version_wasm_section_exists(blob_path: &Path) { + let blob = fs::read(blob_path).expect("`{blob_path}` was just written and should exist; qed"); - let module: Module = match deserialize_buffer(&wasm_blob) { + let module: Module = match deserialize_buffer(&blob) { Ok(m) => m, Err(e) => { - println!("Failed to deserialize `{}`: {e:?}", wasm.display()); + println!("Failed to deserialize `{}`: {e:?}", blob_path.display()); process::exit(1); }, }; if !module.custom_sections().any(|cs| cs.name() == "runtime_version") { println!( - "Couldn't find the `runtime_version` wasm section. \ + "Couldn't find the `runtime_version` section. \ Please ensure that you are using the `sp_version::runtime_version` attribute macro!" ); process::exit(1); @@ -208,7 +242,7 @@ fn adjust_mtime( let metadata = fs::metadata(invoked_timestamp)?; let mtime = filetime::FileTime::from_last_modification_time(&metadata); - filetime::set_file_mtime(bloaty_wasm.wasm_binary_bloaty_path(), mtime)?; + filetime::set_file_mtime(bloaty_wasm.bloaty_path(), mtime)?; if let Some(binary) = compressed_or_compact_wasm.as_ref() { filetime::set_file_mtime(binary.wasm_binary_path(), mtime)?; } @@ -279,8 +313,8 @@ fn get_crate_name(cargo_manifest: &Path) -> String { .expect("Package name exists; qed") } -/// Returns the name for the wasm binary. -fn get_wasm_binary_name(cargo_manifest: &Path) -> String { +/// Returns the name for the blob binary. +fn get_blob_name(cargo_manifest: &Path) -> String { get_crate_name(cargo_manifest).replace('-', "_") } @@ -501,7 +535,7 @@ fn create_project( ) -> PathBuf { let crate_name = get_crate_name(project_cargo_toml); let crate_path = project_cargo_toml.parent().expect("Parent path exists; qed"); - let wasm_binary = get_wasm_binary_name(project_cargo_toml); + let wasm_binary = get_blob_name(project_cargo_toml); let wasm_project_folder = wasm_workspace.join(&crate_name); fs::create_dir_all(wasm_project_folder.join("src")) @@ -539,8 +573,8 @@ fn create_project( wasm_project_folder } -/// The cargo profile that is used to build the wasm project. -#[derive(Debug, EnumIter)] +/// A rustc profile. +#[derive(Clone, Debug, EnumIter)] enum Profile { /// The `--profile dev` profile. Debug, @@ -551,17 +585,63 @@ enum Profile { } impl Profile { - /// Create a profile by detecting which profile is used for the main build. + /// The name of the profile as supplied to the cargo `--profile` cli option. + fn name(&self) -> &'static str { + match self { + Self::Debug => "dev", + Self::Release => "release", + Self::Production => "production", + } + } + + /// The sub directory within `target` where cargo places the build output. + /// + /// # Note + /// + /// Usually this is the same as [`Self::name`] with the exception of the debug + /// profile which is called `dev`. + fn directory(&self) -> &'static str { + match self { + Self::Debug => "debug", + _ => self.name(), + } + } + + /// Whether the resulting binary should be compacted and compressed. + fn wants_compact(&self) -> bool { + !matches!(self, Self::Debug) + } +} + +/// The build configuration for this build. +#[derive(Debug)] +struct BuildConfiguration { + /// The profile that is used to build the outer project. + pub outer_build_profile: Profile, + /// The profile to use to build the runtime blob. + pub blob_build_profile: Profile, +} + +impl BuildConfiguration { + /// Create a [`BuildConfiguration`] by detecting which profile is used for the main build and + /// checking any env var overrides. /// /// We cannot easily determine the profile that is used by the main cargo invocation /// because the `PROFILE` environment variable won't contain any custom profiles like /// "production". It would only contain the builtin profile where the custom profile /// inherits from. This is why we inspect the build path to learn which profile is used. /// + /// When not overriden by a env variable we always default to building wasm with the `Release` + /// profile even when the main build uses the debug build. This is because wasm built with the + /// `Debug` profile is too slow for normal development activities and almost never intended. + /// + /// When cargo is building in `--profile dev`, user likely intends to compile fast, so we don't + /// bother producing compact or compressed blobs. + /// /// # Note /// /// Can be overriden by setting [`crate::WASM_BUILD_TYPE_ENV`]. - fn detect(wasm_project: &Path) -> Profile { + fn detect(wasm_project: &Path) -> Self { let (name, overriden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { (name, true) } else { @@ -585,7 +665,8 @@ impl Profile { .to_string(); (name, false) }; - match (Profile::iter().find(|p| p.directory() == name), overriden) { + let outer_build_profile = Profile::iter().find(|p| p.directory() == name); + let blob_build_profile = match (outer_build_profile.clone(), overriden) { // When not overriden by a env variable we default to using the `Release` profile // for the wasm build even when the main build uses the debug build. This // is because the `Debug` profile is too slow for normal development activities. @@ -615,35 +696,12 @@ impl Profile { ); process::exit(1); }, + }; + BuildConfiguration { + outer_build_profile: outer_build_profile.unwrap_or(Profile::Release), + blob_build_profile, } } - - /// The name of the profile as supplied to the cargo `--profile` cli option. - fn name(&self) -> &'static str { - match self { - Self::Debug => "dev", - Self::Release => "release", - Self::Production => "production", - } - } - - /// The sub directory within `target` where cargo places the build output. - /// - /// # Note - /// - /// Usually this is the same as [`Self::name`] with the exception of the debug - /// profile which is called `dev`. - fn directory(&self) -> &'static str { - match self { - Self::Debug => "debug", - _ => self.name(), - } - } - - /// Whether the resulting binary should be compacted and compressed. - fn wants_compact(&self) -> bool { - !matches!(self, Self::Debug) - } } /// Check environment whether we should build without network @@ -651,12 +709,13 @@ fn offline_build() -> bool { env::var(OFFLINE).map_or(false, |v| v == "true") } -/// Build the project to create the WASM binary. -fn build_project( +/// Build the project and create the bloaty runtime blob. +fn build_bloaty_blob( + blob_build_profile: &Profile, project: &Path, default_rustflags: &str, cargo_cmd: CargoCommandVersioned, -) -> Profile { +) { let manifest_path = project.join("Cargo.toml"); let mut build_cmd = cargo_cmd.command(); @@ -685,9 +744,8 @@ fn build_project( build_cmd.arg("--color=always"); } - let profile = Profile::detect(project); build_cmd.arg("--profile"); - build_cmd.arg(profile.name()); + build_cmd.arg(blob_build_profile.name()); if offline_build() { build_cmd.arg("--offline"); @@ -697,69 +755,82 @@ fn build_project( println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); - match build_cmd.status().map(|s| s.success()) { - Ok(true) => profile, - // Use `process.exit(1)` to have a clean error output. - _ => process::exit(1), + // Use `process::exit(1)` to have a clean error output. + if build_cmd.status().map(|s| s.success()).is_err() { + process::exit(1); } } -/// Compact the WASM binary using `wasm-gc` and compress it using zstd. -fn compact_wasm_file( +fn compact_wasm( project: &Path, - profile: Profile, + inner_profile: &Profile, cargo_manifest: &Path, - out_name: Option, -) -> (Option, Option, WasmBinaryBloaty) { - let default_out_name = get_wasm_binary_name(cargo_manifest); - let out_name = out_name.unwrap_or_else(|| default_out_name.clone()); + out_name: &str, +) -> Option { + let default_out_name = get_blob_name(cargo_manifest); let in_path = project .join("target/wasm32-unknown-unknown") - .join(profile.directory()) + .join(inner_profile.directory()) .join(format!("{}.wasm", default_out_name)); - let (wasm_compact_path, wasm_compact_compressed_path) = if profile.wants_compact() { - let wasm_compact_path = project.join(format!("{}.compact.wasm", out_name,)); - wasm_opt::OptimizationOptions::new_opt_level_0() - .mvp_features_only() - .debug_info(true) - .add_pass(wasm_opt::Pass::StripDwarf) - .run(&in_path, &wasm_compact_path) - .expect("Failed to compact generated WASM binary."); - - let wasm_compact_compressed_path = - project.join(format!("{}.compact.compressed.wasm", out_name)); - if compress_wasm(&wasm_compact_path, &wasm_compact_compressed_path) { - (Some(WasmBinary(wasm_compact_path)), Some(WasmBinary(wasm_compact_compressed_path))) - } else { - (Some(WasmBinary(wasm_compact_path)), None) - } - } else { - (None, None) - }; + let wasm_compact_path = project.join(format!("{}.compact.wasm", out_name)); + let start = std::time::Instant::now(); + wasm_opt::OptimizationOptions::new_opt_level_0() + .mvp_features_only() + .debug_info(true) + .add_pass(wasm_opt::Pass::StripDwarf) + .run(&in_path, &wasm_compact_path) + .expect("Failed to compact generated WASM binary."); + println!( + "{} {}", + colorize_info_message("Compacted wasm in"), + colorize_info_message(format!("{:?}", start.elapsed()).as_str()) + ); + Some(WasmBinary(wasm_compact_path)) +} + +fn copy_bloaty_blob( + project: &Path, + inner_profile: &Profile, + in_name: &str, + out_name: &str, +) -> WasmBinaryBloaty { + let in_path = project + .join("target/wasm32-unknown-unknown") + .join(inner_profile.directory()) + .join(format!("{}.wasm", in_name)); let bloaty_path = project.join(format!("{}.wasm", out_name)); fs::copy(in_path, &bloaty_path).expect("Copying the bloaty file to the project dir."); - - (wasm_compact_path, wasm_compact_compressed_path, WasmBinaryBloaty(bloaty_path)) + WasmBinaryBloaty(bloaty_path) } -fn compress_wasm(wasm_binary_path: &Path, compressed_binary_out_path: &Path) -> bool { +fn try_compress_blob(compact_blob_path: &Path, out_name: &str) -> Option { use sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT; - let data = fs::read(wasm_binary_path).expect("Failed to read WASM binary"); + let project = compact_blob_path.parent().expect("blob path should have a parent directory"); + let compact_compressed_blob_path = + project.join(format!("{}.compact.compressed.wasm", out_name)); + + let start = std::time::Instant::now(); + let data = fs::read(compact_blob_path).expect("Failed to read WASM binary"); if let Some(compressed) = sp_maybe_compressed_blob::compress(&data, CODE_BLOB_BOMB_LIMIT) { - fs::write(compressed_binary_out_path, &compressed[..]) + fs::write(&compact_compressed_blob_path, &compressed[..]) .expect("Failed to write WASM binary"); - true + println!( + "{} {}", + colorize_info_message("Compressed blob in"), + colorize_info_message(format!("{:?}", start.elapsed()).as_str()) + ); + Some(WasmBinary(compact_compressed_blob_path)) } else { build_helper::warning!( - "Writing uncompressed wasm. Exceeded maximum size {}", + "Writing uncompressed blob. Exceeded maximum size {}", CODE_BLOB_BOMB_LIMIT, ); - - false + println!("{}", colorize_info_message("Skipping blob compression")); + None } } @@ -869,7 +940,7 @@ fn generate_rerun_if_changed_instructions( packages.iter().for_each(package_rerun_if_changed); compressed_or_compact_wasm.map(|w| rerun_if_changed(w.wasm_binary_path())); - rerun_if_changed(bloaty_wasm.wasm_binary_bloaty_path()); + rerun_if_changed(bloaty_wasm.bloaty_path()); // Register our env variables println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); @@ -902,9 +973,9 @@ fn package_rerun_if_changed(package: &DeduplicatePackage) { .for_each(rerun_if_changed); } -/// Copy the WASM binary to the target directory set in `WASM_TARGET_DIRECTORY` environment +/// Copy the blob binary to the target directory set in `WASM_TARGET_DIRECTORY` environment /// variable. If the variable is not set, this is a no-op. -fn copy_wasm_to_target_directory(cargo_manifest: &Path, wasm_binary: &WasmBinary) { +fn copy_blob_to_target_directory(cargo_manifest: &Path, blob_binary: &WasmBinary) { let target_dir = match env::var(crate::WASM_TARGET_DIRECTORY) { Ok(path) => PathBuf::from(path), Err(_) => return, @@ -923,8 +994,8 @@ fn copy_wasm_to_target_directory(cargo_manifest: &Path, wasm_binary: &WasmBinary fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`."); fs::copy( - wasm_binary.wasm_binary_path(), - target_dir.join(format!("{}.wasm", get_wasm_binary_name(cargo_manifest))), + blob_binary.wasm_binary_path(), + target_dir.join(format!("{}.wasm", get_blob_name(cargo_manifest))), ) - .expect("Copies WASM binary to `WASM_TARGET_DIRECTORY`."); + .expect("Copies blob binary to `WASM_TARGET_DIRECTORY`."); } -- GitLab From 3148063a6f7389331e3ff9e3d7b7281950b0f790 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Wed, 25 Oct 2023 09:47:54 +0200 Subject: [PATCH 368/633] Contracts: Add benchmarks to include files (#2022) Project that includes pallet-contracts via crates.io will fail to run ```bash cargo check --features=runtime-benchmarks ``` without the currently not included benchmarks files --- substrate/frame/contracts/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 1b0d9529295..d80577f9d44 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for WASM contracts" readme = "README.md" -include = ["src/**/*", "build.rs", "README.md", "CHANGELOG.md"] +include = ["src/**/*", "benchmarks/**", "build.rs", "README.md", "CHANGELOG.md"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -- GitLab From b7a8532db14ef665d69c05019340896fbb42b88d Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 25 Oct 2023 21:59:40 +1300 Subject: [PATCH 369/633] publish pallet-root-testing (#2017) so we can use it in our tests --- substrate/frame/root-testing/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index bb19d90466e..7837289cec5 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -8,7 +8,6 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME root testing pallet" readme = "README.md" -publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -- GitLab From c86b633695299ed27053940d5ea5c5a2392964b3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 25 Oct 2023 14:46:49 +0200 Subject: [PATCH 370/633] Sort the benchmarks before listing them (#2026) Signed-off-by: Oliver Tale-Yazdi --- .../utils/frame/benchmarking-cli/src/pallet/command.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 84da3aaa02c..99f77866f8d 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -748,13 +748,17 @@ impl CliConfiguration for PalletCmd { /// List the benchmarks available in the runtime, in a CSV friendly format. fn list_benchmark( - benchmarks_to_run: Vec<( + mut benchmarks_to_run: Vec<( Vec, Vec, Vec<(BenchmarkParameter, u32, u32)>, Vec<(String, String)>, )>, ) { + // Sort and de-dub by pallet and function name. + benchmarks_to_run.sort_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa).cmp(&(pb, sb))); + benchmarks_to_run.dedup_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa) == (pb, sb)); + println!("pallet, benchmark"); for (pallet, extrinsic, _, _) in benchmarks_to_run { println!("{}, {}", String::from_utf8_lossy(&pallet), String::from_utf8_lossy(&extrinsic)); -- GitLab From f6560c2b7226ea756ade18df42018c3eaf3be2e0 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 25 Oct 2023 17:35:15 +0200 Subject: [PATCH 371/633] [testnet] Align testnet system parachain runtimes using `RelayTreasuryLocation` and `SystemParachains` in the same way (#2023) This PR addresses several issues: - simplify referencing `RelayTreasuryLocation` without needing additional `RelayTreasury` struct - fix for referencing `SystemParachains` from parachain with `parents: 1` instead of `parents: 0` - removed hard-coded constants and fix tests for `asset-hub-rococo` which was merged to master after https://github.com/paritytech/polkadot-sdk/pull/1726 --------- Co-authored-by: command-bot <> --- .../src/tests/reserve_transfer.rs | 10 +- .../assets/asset-hub-rococo/src/tests/send.rs | 5 +- .../asset-hub-rococo/src/tests/teleport.rs | 8 +- .../assets/asset-hub-rococo/src/lib.rs | 8 +- .../asset-hub-rococo/src/weights/xcm/mod.rs | 18 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 131 ++++++++++-------- .../assets/asset-hub-rococo/src/xcm_config.rs | 33 +++-- .../asset-hub-westend/src/xcm_config.rs | 34 ++--- .../assets/test-utils/src/test_cases.rs | 5 +- .../test-utils/src/test_cases_over_bridge.rs | 17 ++- .../bridge-hub-rococo/src/xcm_config.rs | 38 +++-- .../contracts-rococo/src/xcm_config.rs | 40 ++++-- 12 files changed, 195 insertions(+), 152 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index fb25607c635..ee5f0727a1e 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -39,7 +39,7 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { AssetHubRococo::assert_dmp_queue_incomplete( - Some(Weight::from_parts(1_000_000_000, 0)), + Some(Weight::from_parts(57_185_000, 3504)), Some(Error::UntrustedReserveLocation), ); } @@ -52,8 +52,8 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 630_092_000, - 6_196, + 864_610_000, + 8_799, ))); assert_expected_events!( @@ -77,8 +77,8 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, + 864_610_000, + 8799, ))); assert_expected_events!( 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 index b8ec370e3f8..195afcd34c7 100644 --- 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 @@ -83,7 +83,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593))); + AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts( + 15_594_564_000, + 562_893, + ))); assert_expected_events!( AssetHubRococo, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 4b2ea0e160c..0d2ca685247 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -68,7 +68,7 @@ fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Rococo::assert_ump_queue_processed( false, Some(AssetHubRococo::para_id()), - Some(Weight::from_parts(148_433_000, 3_593)), + Some(Weight::from_parts(157_718_000, 3_593)), ); } @@ -76,8 +76,8 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 534_872_000, - 7_133, + 720_053_000, + 7_203, ))); AssetHubRococo::assert_parachain_system_ump_sent(); @@ -97,7 +97,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { fn para_dest_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(157_718_000, 3593))); assert_expected_events!( AssetHubRococo, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index f57cfda1428..1ce504d6704 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1381,7 +1381,13 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(UNITS), id: Concrete(TokenLocation::get()) }, )); pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; - pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; + // AssetHubRococo trusts AssetHubWococo as reserve for WOCs + pub TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some( + ( + xcm_config::bridging::to_wococo::AssetHubWococo::get(), + MultiAsset::from((xcm_config::bridging::to_wococo::WocLocation::get(), 1000000000000 as u128)) + ) + ); } impl pallet_xcm_benchmarks::fungible::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs index 22c2f2450b2..2fbbd61654b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { 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()) @@ -125,12 +117,8 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { fn report_error(_query_response_info: &QueryResponseInfo) -> Weight { XcmGeneric::::report_error() } - 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-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 9d95048c0ac..926d7aeb9e1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,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-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-ayothjw6-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 +// 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 +// --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-rococo-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/assets/asset-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: 26_104_000 picoseconds. - Weight::from_parts(26_722_000, 3593) + // Minimum execution time: 20_408_000 picoseconds. + Weight::from_parts(21_066_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,15 +65,19 @@ 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: 42_449_000 picoseconds. + Weight::from_parts(43_065_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: `System::Account` (r:2 w:2) + // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -88,49 +90,58 @@ 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` - // 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)) + // Measured: `246` + // Estimated: `8799` + // Minimum execution time: 85_637_000 picoseconds. + Weight::from_parts(86_550_000, 8799) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: `Benchmark::Override` (r:0 w:0) - // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + // 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`) 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) + // Measured: `39` + // Estimated: `3504` + // Minimum execution time: 7_006_000 picoseconds. + Weight::from_parts(7_185_000, 3504) + .saturating_add(T::DbWeight::get().reads(2)) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 185_307_000 picoseconds. + Weight::from_parts(189_716_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } 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) + // Minimum execution time: 2_934_000 picoseconds. + Weight::from_parts(3_078_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,15 +149,19 @@ 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: 18_701_000 picoseconds. + Weight::from_parts(19_221_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:1 w:1) + // Storage: `System::Account` (r:2 w:2) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -159,32 +174,38 @@ 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) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `145` + // Estimated: `6196` + // Minimum execution time: 57_182_000 picoseconds. + Weight::from_parts(58_877_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 45_073_000 picoseconds. + Weight::from_parts(45_927_000, 3610) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index ae4a275d43a..222e96d59d1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -40,7 +40,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain::SystemParachains; +use rococo_runtime_constants::system_parachain; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ @@ -76,6 +76,7 @@ parameter_types! { pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. @@ -497,10 +498,11 @@ pub type Barrier = TrailingSetTopicAsId< // 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. + // Parent, its pluralities (i.e. governance bodies), relay treasury pallet and + // BridgeHub get free execution. AllowExplicitUnpaidExecutionFrom<( ParentOrParentsPlurality, + Equals, Equals, )>, // Subscriptions for version tracking are OK. @@ -530,22 +532,25 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = ForeignAssetsInstance, >; -parameter_types! { - pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); -} - -pub struct RelayTreasury; -impl Contains for RelayTreasury { - fn contains(location: &MultiLocation) -> bool { - let relay_treasury_location = RelayTreasuryLocation::get(); - *location == relay_treasury_location - } +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::BRIDGE_HUB_ID | + system_parachain::CONTRACTS_ID | + system_parachain::ENCOINTER_ID + )), + } + }; } /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// 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 f14b410327c..fe0fd613d22 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 @@ -26,7 +26,7 @@ use assets_common::{ }; use frame_support::{ match_types, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess}, + traits::{ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; @@ -74,6 +74,7 @@ parameter_types! { PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -157,7 +158,7 @@ pub type ForeignFungiblesTransactor = FungiblesAdapter< CheckingAccount, >; -/// `AssetId/Balance` converter for `PoolAssets` +/// `AssetId`/`Balance` converter for `PoolAssets`. pub type PoolAssetsConvertedConcreteId = assets_common::PoolAssetsConvertedConcreteId; @@ -236,9 +237,6 @@ 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 @@ -466,9 +464,12 @@ pub type Barrier = TrailingSetTopicAsId< // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, - // Parent, its pluralities (i.e. governance bodies) and treasury pallet get - // free execution. - AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, TreasuryPallet)>, + // Parent, its pluralities (i.e. governance bodies), relay treasury pallet and + // BridgeHub get free execution. + AllowExplicitUnpaidExecutionFrom<( + ParentOrParentsPlurality, + Equals, + )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), @@ -504,22 +505,11 @@ match_types! { }; } -parameter_types! { - pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); -} - -pub struct RelayTreasury; -impl Contains for RelayTreasury { - fn contains(location: &MultiLocation) -> bool { - let relay_treasury_location = RelayTreasuryLocation::get(); - *location == relay_treasury_location - } -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// @@ -550,6 +540,8 @@ impl xcm_executor::Config for XcmConfig { >; 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, 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 b0616acb1a4..5fb34e7a571 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -93,6 +93,7 @@ pub fn teleports_for_native_asset_works< .with_session_keys(collator_session_keys.session_keys()) .with_safe_xcm_version(XCM_VERSION) .with_para_id(runtime_para_id.into()) + .with_tracing() .build() .execute_with(|| { let mut alice = [0u8; 32]; @@ -111,7 +112,7 @@ pub fn teleports_for_native_asset_works< let native_asset_id = MultiLocation::parent(); let buy_execution_fee_amount_eta = - WeightToFee::weight_to_fee(&Weight::from_parts(90_000_000_000, 0)); + WeightToFee::weight_to_fee(&Weight::from_parts(90_000_000_000, 1024)); let native_asset_amount_unit = existential_deposit; let native_asset_amount_received = native_asset_amount_unit * 10.into() + buy_execution_fee_amount_eta.into(); @@ -128,7 +129,7 @@ pub fn teleports_for_native_asset_works< id: Concrete(native_asset_id), fun: Fungible(buy_execution_fee_amount_eta), }, - weight_limit: Limited(Weight::from_parts(303531000, 65536)), + weight_limit: Limited(Weight::from_parts(3035310000, 65536)), }, DepositAsset { assets: Wild(AllCounted(1)), diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 9852453d283..8cc5f81f497 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -182,6 +182,14 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< weight_limit, )); + // check pallet_xcm attempted + RuntimeHelper::::assert_pallet_xcm_event_outcome( + &unwrap_pallet_xcm_event, + |outcome| { + assert_ok!(outcome.ensure_complete()); + }, + ); + // 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!( @@ -196,15 +204,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< 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() 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 703acfa4417..2456a7ee63a 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 @@ -29,7 +29,7 @@ use crate::{ }; use frame_support::{ match_types, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, + traits::{ConstU32, Contains, Equals, Everything, Nothing}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; @@ -40,7 +40,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain::SystemParachains; +use rococo_runtime_constants::system_parachain; use sp_core::Get; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; @@ -67,6 +67,7 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. @@ -222,8 +223,12 @@ pub type Barrier = TrailingSetTopicAsId< // 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 relay treasury pallet + // get free execution. + AllowExplicitUnpaidExecutionFrom<( + ParentOrParentsPlurality, + Equals, + )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), @@ -234,22 +239,25 @@ pub type Barrier = TrailingSetTopicAsId< >, >; -parameter_types! { - pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); -} - -pub struct RelayTreasury; -impl Contains for RelayTreasury { - fn contains(location: &MultiLocation) -> bool { - let relay_treasury_location = RelayTreasuryLocation::get(); - *location == relay_treasury_location - } +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::BRIDGE_HUB_ID | + system_parachain::CONTRACTS_ID | + system_parachain::ENCOINTER_ID + )), + } + }; } /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = (RelayOrOtherSystemParachains, RelayTreasury); +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - NativeToken with the parent Relay Chain and sibling parachains. 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 71a789e3e25..6ff60b958fe 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -20,7 +20,7 @@ use super::{ use crate::common::rococo::currency::CENTS; use frame_support::{ match_types, parameter_types, - traits::{ConstU32, EitherOfDiverse, Everything, Nothing}, + traits::{ConstU32, EitherOfDiverse, Equals, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -31,7 +31,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain::SystemParachains; +use rococo_runtime_constants::system_parachain; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ @@ -52,6 +52,7 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const ExecutiveBody: BodyId = BodyId::Executive; pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } /// We allow root and the Relay Chain council to execute privileged collator selection operations. @@ -140,8 +141,12 @@ pub type Barrier = TrailingSetTopicAsId< // 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 relay treasury pallet + // get free execution. + AllowExplicitUnpaidExecutionFrom<( + ParentOrParentsPlurality, + Equals, + )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), @@ -152,6 +157,26 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::BRIDGE_HUB_ID | + system_parachain::CONTRACTS_ID | + system_parachain::ENCOINTER_ID + )), + } + }; +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); + pub type TrustedTeleporter = ConcreteAssetFromSystem; pub struct XcmConfig; @@ -174,12 +199,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = ConstU32<8>; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = XcmFeesToAccount< - Self, - RelayOrOtherSystemParachains, - AccountId, - TreasuryAccount, - >; + type FeeManager = XcmFeesToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; -- GitLab From bdf186870dc4a7d74d59cad338baf8478d0715b4 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Wed, 25 Oct 2023 16:32:18 -0400 Subject: [PATCH 372/633] `polkadot-parachain-primitives` should not depend on `frame-support`. (#1897) This PR does not make any functional changes to the code. Rather, it restructures the dependency graph. Before this PR, the crate `polkadot-parachain-primitives` depended directly on the crate `frame-support`. This is wrong in principal because a parachain does not necessarily have anything to do with frame. This dependency was only for the `Weight` type which was just a re-export from `sp-weights` anyway. So this PR changes the dependency to be directly on the much lighter `sp-weights`. --------- Co-authored-by: Joshy Orndorff Co-authored-by: command-bot <> --- Cargo.lock | 10 +++++----- polkadot/parachain/Cargo.toml | 9 +++------ polkadot/parachain/src/primitives.rs | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1a1b1877a9..7208b77e109 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12625,7 +12625,6 @@ version = "1.0.0" dependencies = [ "bounded-collections", "derive_more", - "frame-support", "parity-scale-codec", "polkadot-core-primitives", "scale-info", @@ -12633,6 +12632,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-std", + "sp-weights", ] [[package]] @@ -13440,9 +13440,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -13639,9 +13639,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" +checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" dependencies = [ "bytes", "rand 0.8.5", diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 681bee3c327..27aa117a87f 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -15,7 +15,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-core = { path = "../../substrate/primitives/core", default-features = false, features = ["serde"] } -frame-support = { path = "../../substrate/frame/support", default-features = false } +sp-weights = { path = "../../substrate/primitives/weights", default-features = false } polkadot-core-primitives = { path = "../core-primitives", default-features = false } derive_more = "0.99.11" bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } @@ -28,7 +28,6 @@ default = [ "std" ] wasm-api = [] std = [ "bounded-collections/std", - "frame-support/std", "parity-scale-codec/std", "polkadot-core-primitives/std", "scale-info/std", @@ -36,8 +35,6 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-std/std", + "sp-weights/std", ] -runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] +runtime-benchmarks = [ "sp-runtime/runtime-benchmarks" ] diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index 3247e841422..dc89ae7868e 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -20,12 +20,12 @@ use sp_std::vec::Vec; use bounded_collections::{BoundedVec, ConstU32}; -use frame_support::weights::Weight; use parity_scale_codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_core::{bytes, RuntimeDebug, TypeId}; use sp_runtime::traits::Hash as _; +use sp_weights::Weight; use polkadot_core_primitives::{Hash, OutboundHrmpMessage}; -- GitLab From 0bcebac4fc69f6bef5da7d94615916bbde294967 Mon Sep 17 00:00:00 2001 From: Dastan <88332432+dastansam@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:52:12 +0600 Subject: [PATCH 373/633] Expose collection attributes from `Inspect` trait (#1914) # Description - What does this PR do? While working with `pallet_nfts` through `nonfungibles_v2` traits `Inspect, Mutate`, I found out that once you have set the collection attribute with `::set_collection_attribute()`, it's not possible to read it with `::collection_attribute()` since they use different `namespace` values. When setting the attribute, `AttributeNamespace::Pallet` is used, while `AttributeNamespace::CollectionOwner` is used when reading. more context: https://github.com/freeverseio/laos/issues/7#issuecomment-1766137370 This PR makes `item` an optional parameter in `Inspect::system_attribute()`, to be able to read collection attributes. - Why are these changes needed? To be able to read collection level attributes when reading attributes of the collection. It will be possible to read collection attributes by passing `None` for `item` - How were these changes implemented and what do they affect? `NftsApi` is also affected and `NftsApi::system_attribute()` now accepts optional `item` parameter. ## Breaking change Because of the change in the `NftsApi::system_attribute()` method's `item` param, parachains who integrated the `NftsApi` need to update their API code and frontend integrations accordingly. AssetHubs are unaffected since the NftsApi wasn't released on those parachains yet. --- .../assets/asset-hub-westend/src/lib.rs | 4 +- substrate/bin/node/runtime/src/lib.rs | 4 +- substrate/frame/nfts/runtime-api/src/lib.rs | 2 +- substrate/frame/nfts/src/impl_nonfungibles.rs | 8 +- substrate/frame/nfts/src/tests.rs | 82 ++++++++++++++++++- .../src/traits/tokens/nonfungible_v2.rs | 4 +- .../src/traits/tokens/nonfungibles_v2.rs | 13 +-- 7 files changed, 101 insertions(+), 16 deletions(-) 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 c090536b3da..30d38422242 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1081,10 +1081,10 @@ impl_runtime_apis! { fn system_attribute( collection: u32, - item: u32, + item: Option, key: Vec, ) -> Option> { - >::system_attribute(&collection, &item, &key) + >::system_attribute(&collection, item.as_ref(), &key) } fn collection_attribute(collection: u32, key: Vec) -> Option> { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f4c8a5940a3..a2d100e1f8b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2630,10 +2630,10 @@ impl_runtime_apis! { fn system_attribute( collection: u32, - item: u32, + item: Option, key: Vec, ) -> Option> { - >::system_attribute(&collection, &item, &key) + >::system_attribute(&collection, item.as_ref(), &key) } fn collection_attribute(collection: u32, key: Vec) -> Option> { diff --git a/substrate/frame/nfts/runtime-api/src/lib.rs b/substrate/frame/nfts/runtime-api/src/lib.rs index cf2d444b42f..77535c64069 100644 --- a/substrate/frame/nfts/runtime-api/src/lib.rs +++ b/substrate/frame/nfts/runtime-api/src/lib.rs @@ -48,7 +48,7 @@ sp_api::decl_runtime_apis! { fn system_attribute( collection: CollectionId, - item: ItemId, + item: Option, key: Vec, ) -> Option>; diff --git a/substrate/frame/nfts/src/impl_nonfungibles.rs b/substrate/frame/nfts/src/impl_nonfungibles.rs index 4a6b70eb997..ee7f42cfc68 100644 --- a/substrate/frame/nfts/src/impl_nonfungibles.rs +++ b/substrate/frame/nfts/src/impl_nonfungibles.rs @@ -79,17 +79,19 @@ impl, I: 'static> Inspect<::AccountId> for Palle Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) } - /// Returns the system attribute value of `item` of `collection` corresponding to `key`. + /// Returns the system attribute value of `item` of `collection` corresponding to `key` if + /// `item` is `Some`. Otherwise, returns the system attribute value of `collection` + /// corresponding to `key`. /// /// By default this is `None`; no attributes are defined. fn system_attribute( collection: &Self::CollectionId, - item: &Self::ItemId, + item: Option<&Self::ItemId>, key: &[u8], ) -> Option> { let namespace = AttributeNamespace::Pallet; let key = BoundedSlice::<_, _>::try_from(key).ok()?; - Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) + Attribute::::get((collection, item, namespace, key)).map(|a| a.0.into()) } /// Returns the attribute value of `item` of `collection` corresponding to `key`. diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index a82fcca0151..aeebf51b7c7 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -22,7 +22,7 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, traits::{ - tokens::nonfungibles_v2::{Create, Destroy, Mutate}, + tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, }, }; @@ -982,6 +982,86 @@ fn set_collection_owner_attributes_should_work() { }); } +#[test] +fn set_collection_system_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + + let collection_id = 0; + let attribute_key = [0u8]; + let attribute_value = [0u8]; + + assert_ok!(, ItemConfig>>::set_collection_attribute( + &collection_id, + &attribute_key, + &attribute_value + )); + + assert_eq!(attributes(0), vec![(None, AttributeNamespace::Pallet, bvec![0], bvec![0])]); + + assert_eq!( + >>::system_attribute( + &collection_id, + None, + &attribute_key + ), + Some(attribute_value.to_vec()) + ); + + // test typed system attribute + let typed_attribute_key = [0u8; 32]; + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] + struct TypedAttributeValue(u32); + let typed_attribute_value = TypedAttributeValue(42); + + assert_ok!( + , ItemConfig>>::set_typed_collection_attribute( + &collection_id, + &typed_attribute_key, + &typed_attribute_value + ) + ); + + assert_eq!( + >>::typed_system_attribute( + &collection_id, + None, + &typed_attribute_key + ), + Some(typed_attribute_value) + ); + + // check storage + assert_eq!( + attributes(collection_id), + [ + (None, AttributeNamespace::Pallet, bvec![0], bvec![0]), + ( + None, + AttributeNamespace::Pallet, + bvec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + ], + bvec![42, 0, 0, 0] + ) + ] + ); + + assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 0)); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), collection_id, w)); + assert_eq!(attributes(collection_id), vec![]); + }) +} + #[test] fn set_item_owner_attributes_should_work() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs b/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs index 788a4d25e81..05f76e2859d 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -226,7 +226,7 @@ impl< >::custom_attribute(account, &A::get(), item, key) } fn system_attribute(item: &Self::ItemId, key: &[u8]) -> Option> { - >::system_attribute(&A::get(), item, key) + >::system_attribute(&A::get(), Some(item), key) } fn typed_attribute(item: &Self::ItemId, key: &K) -> Option { >::typed_attribute(&A::get(), item, key) @@ -244,7 +244,7 @@ impl< ) } fn typed_system_attribute(item: &Self::ItemId, key: &K) -> Option { - >::typed_system_attribute(&A::get(), item, key) + >::typed_system_attribute(&A::get(), Some(item), key) } fn can_transfer(item: &Self::ItemId) -> bool { >::can_transfer(&A::get(), item) diff --git a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs index 868afbdf7ee..c0209b6d512 100644 --- a/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -75,12 +75,14 @@ pub trait Inspect { None } - /// Returns the system attribute value of `item` of `collection` corresponding to `key`. + /// Returns the system attribute value of `item` of `collection` corresponding to `key` if + /// `item` is `Some`. Otherwise, returns the system attribute value of `collection` + /// corresponding to `key`. /// /// By default this is `None`; no attributes are defined. fn system_attribute( _collection: &Self::CollectionId, - _item: &Self::ItemId, + _item: Option<&Self::ItemId>, _key: &[u8], ) -> Option> { None @@ -113,13 +115,14 @@ pub trait Inspect { .and_then(|v| V::decode(&mut &v[..]).ok()) } - /// Returns the strongly-typed system attribute value of `item` of `collection` corresponding to - /// `key`. + /// Returns the strongly-typed system attribute value of `item` corresponding to `key` if + /// `item` is `Some`. Otherwise, returns the strongly-typed system attribute value of + /// `collection` corresponding to `key`. /// /// By default this just attempts to use `system_attribute`. fn typed_system_attribute( collection: &Self::CollectionId, - item: &Self::ItemId, + item: Option<&Self::ItemId>, key: &K, ) -> Option { key.using_encoded(|d| Self::system_attribute(collection, item, d)) -- GitLab From 21d36b7b4229c4d5225944f197918cde23fda4ea Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 26 Oct 2023 15:36:05 +0200 Subject: [PATCH 374/633] Removed TODO from test-case for hard-coded delivery fee estimation (#2042) Co-authored-by: Adrian Catangiu --- .../assets/asset-hub-rococo/tests/tests.rs | 38 +-- .../runtimes/assets/test-utils/src/lib.rs | 44 ++++ .../test-utils/src/test_cases_over_bridge.rs | 222 ++++++++++-------- 3 files changed, 164 insertions(+), 140 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index a763382f905..b93315cc39d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -683,6 +683,7 @@ mod asset_hub_rococo_tests { bridging_to_asset_hub_wococo, WeightLimit::Unlimited, Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + Some(xcm_config::TreasuryAccount::get().unwrap()), ) } @@ -717,29 +718,11 @@ mod asset_hub_rococo_tests { 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 }, @@ -888,6 +871,7 @@ mod asset_hub_wococo_tests { with_wococo_flavor_bridging_to_asset_hub_rococo, WeightLimit::Unlimited, Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + Some(xcm_config::TreasuryAccount::get().unwrap()), ) } @@ -922,29 +906,11 @@ mod asset_hub_wococo_tests { 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 }, diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index e0f05fa7b0a..471b1f09b56 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -19,4 +19,48 @@ pub mod test_cases; pub mod test_cases_over_bridge; pub mod xcm_helpers; + +use frame_support::traits::ProcessMessageError; pub use parachains_runtimes_test_utils::*; +use std::fmt::Debug; + +use xcm::latest::prelude::*; +use xcm_builder::{CreateMatcher, MatchXcm}; + +/// Helper function to verify `xcm` contains all relevant instructions expected on destination +/// chain as part of a reserve-asset-transfer. +pub(crate) fn assert_matches_reserve_asset_deposited_instructions( + xcm: &mut Xcm, + expected_reserve_assets_deposited: &MultiAssets, + expected_beneficiary: &MultiLocation, +) { + let _ = xcm + .0 + .matcher() + .skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..))) + .expect("no instruction ReserveAssetDeposited?") + .match_next_inst(|instr| match instr { + ReserveAssetDeposited(reserve_assets) => { + assert_eq!(reserve_assets, expected_reserve_assets_deposited); + 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 { assets: _, beneficiary } if beneficiary == expected_beneficiary => + Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction DepositAsset"); +} diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 8cc5f81f497..6c8ac8c6452 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -16,13 +16,12 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets transferred //! over a bridge. +use crate::assert_matches_reserve_asset_deposited_instructions; use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ assert_ok, - traits::{ - fungible::Mutate, Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError, - }, + traits::{Currency, Get, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError}, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::{AccountId, Balance}; @@ -30,10 +29,13 @@ use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper, ValidatorIdOf, XcmReceivedFrom, }; -use sp_runtime::traits::StaticLookup; +use sp_runtime::{traits::StaticLookup, Saturating}; use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_builder::{CreateMatcher, MatchXcm}; -use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_executor::{ + traits::{ConvertLocation, TransactAsset}, + XcmExecutor, +}; pub struct TestBridgingConfig { pub bridged_network: NetworkId, @@ -61,6 +63,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< prepare_configuration: fn() -> TestBridgingConfig, weight_limit: WeightLimit, maybe_paid_export_message: Option, + delivery_fees_account: Option>, ) where Runtime: frame_system::Config + pallet_balances::Config @@ -151,6 +154,11 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< existential_deposit ); + let delivery_fees_account_balance_before = delivery_fees_account + .as_ref() + .map(|dfa| >::free_balance(dfa)) + .unwrap_or(0.into()); + // local native asset (pallet_balances) let asset_to_transfer = MultiAsset { fun: Fungible(balance_to_transfer.into()), @@ -166,22 +174,76 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< }), }; - // Make sure sender has enough funds for paying delivery fees - // TODO: Get this fee via weighing the corresponding message - let delivery_fees = 1324039894; - >::mint_into(&alice_account, delivery_fees.into()) + let assets_to_transfer = MultiAssets::from(asset_to_transfer); + let mut expected_assets = assets_to_transfer.clone(); + let context = XcmConfig::UniversalLocation::get(); + expected_assets + .reanchor(&target_location_from_different_consensus, context) .unwrap(); + let expected_beneficiary = target_destination_account; + + // Make sure sender has enough funds for paying delivery fees + let handling_delivery_fees = { + // Probable XCM with `ReserveAssetDeposited`. + let mut expected_reserve_asset_deposited_message = Xcm(vec![ + ReserveAssetDeposited(MultiAssets::from(expected_assets.clone())), + ClearOrigin, + BuyExecution { + fees: MultiAsset { + id: Concrete(Default::default()), + fun: Fungible(balance_to_transfer), + }, + weight_limit: Unlimited, + }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary }, + 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_reserve_asset_deposited_instructions( + &mut expected_reserve_asset_deposited_message, + &expected_assets, + &expected_beneficiary, + ); + + // Call `SendXcm::validate` to get delivery fees. + let (_, delivery_fees): (_, MultiAssets) = XcmConfig::XcmSender::validate( + &mut Some(target_location_from_different_consensus), + &mut Some(expected_reserve_asset_deposited_message), + ) + .expect("validate passes"); + // Drip delivery fee to Alice account. + let mut delivery_fees_added = false; + for delivery_fee in delivery_fees.inner() { + assert_ok!(::deposit_asset( + &delivery_fee, + &MultiLocation { + parents: 0, + interior: X1(AccountId32 { + network: None, + id: alice_account.clone().into(), + }), + }, + None, + )); + delivery_fees_added = true; + } + delivery_fees_added + }; + // 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))), + Box::new(VersionedMultiAssets::from(assets_to_transfer)), 0, weight_limit, )); + // check events // check pallet_xcm attempted RuntimeHelper::::assert_pallet_xcm_event_outcome( &unwrap_pallet_xcm_event, @@ -190,20 +252,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< }, ); - // 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 that xcm was sent let xcm_sent_message_hash = >::events() .into_iter() @@ -219,7 +267,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< local_bridge_hub_para_id.into(), ) .unwrap(); - assert_eq!( xcm_sent_message_hash, Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256)) @@ -268,12 +315,41 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< .split_global() .expect("split works"); assert_eq!(destination, &target_location_junctions_without_global_consensus); - assert_matches_pallet_xcm_reserve_transfer_assets_instructions(inner_xcm); + assert_matches_reserve_asset_deposited_instructions( + inner_xcm, + &expected_assets, + &expected_beneficiary, + ); Ok(()) }, _ => Err(ProcessMessageError::BadFormat), }) .expect("contains ExportMessage"); + + // check alice account decreased by balance_to_transfer + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance + .saturating_sub(existential_deposit) + .saturating_sub(balance_to_transfer.into()) + ); + + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.into() + ); + + // check dedicated account increased by delivery fees (if configured) + if handling_delivery_fees { + if let Some(delivery_fees_account) = delivery_fees_account { + let delivery_fees_account_balance_after = + >::free_balance(&delivery_fees_account); + assert!( + delivery_fees_account_balance_after > delivery_fees_account_balance_before + ); + } + } }) } @@ -405,15 +481,21 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< 0.into() ); + let expected_assets = MultiAssets::from(vec![MultiAsset { + id: Concrete(foreign_asset_id_multilocation), + fun: Fungible(transfered_foreign_asset_id_amount), + }]); + let expected_beneficiary = MultiLocation { + parents: 0, + interior: X1(AccountId32 { network: None, id: target_account.clone().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), - }])), + ReserveAssetDeposited(expected_assets.clone()), ClearOrigin, BuyExecution { fees: MultiAsset { @@ -422,22 +504,17 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< }, weight_limit: Unlimited, }, - DepositAsset { - assets: Wild(AllCounted(1)), - beneficiary: MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: None, - id: target_account.clone().into(), - }), - }, - }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary }, 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()); + assert_matches_reserve_asset_deposited_instructions( + &mut xcm.clone(), + &expected_assets, + &expected_beneficiary, + ); let hash = xcm.using_encoded(sp_io::hashing::blake2_256); @@ -498,55 +575,15 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< }) } -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 @@ -572,10 +609,6 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< <::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() @@ -584,25 +617,6 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< .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(); -- GitLab From 1b08bdd2dd3f1c2fe623c6cc7df45714e6256362 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Thu, 26 Oct 2023 22:00:51 +0300 Subject: [PATCH 375/633] cumulus: fix test runtimes panic (#2039) the min slot duration should be 0 only if the `experimental` feature is enabled. otherwise, the runtime will panic on a division by 0. --- .../parachains/runtimes/glutton/glutton-kusama/src/lib.rs | 5 ++++- cumulus/parachains/runtimes/starters/seedling/src/lib.rs | 3 +++ cumulus/parachains/runtimes/starters/shell/src/lib.rs | 3 +++ substrate/frame/aura/src/lib.rs | 5 +++-- substrate/frame/babe/src/lib.rs | 5 +++-- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index f5d52239e54..7f4f88fc055 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -224,7 +224,10 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; + #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; + #[cfg(not(feature = "experimental"))] + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -355,7 +358,7 @@ impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION) + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) } fn authorities() -> Vec { diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index c2bcaf8a126..9efbf563123 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -216,7 +216,10 @@ impl pallet_aura::Config for Runtime { impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; + #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; + #[cfg(not(feature = "experimental"))] + type MinimumPeriod = ConstU64<{ parachains_common::SLOT_DURATION / 2 }>; type WeightInfo = (); } diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 4aad553e6a3..18c1fcbb4ba 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -219,7 +219,10 @@ impl pallet_aura::Config for Runtime { impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; + #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; + #[cfg(not(feature = "experimental"))] + type MinimumPeriod = ConstU64<{ parachains_common::SLOT_DURATION / 2 }>; type WeightInfo = (); } diff --git a/substrate/frame/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index b314a3601e1..3017120e4e6 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -408,8 +408,9 @@ impl OnTimestampSet for Pallet { let timestamp_slot = moment / slot_duration; let timestamp_slot = Slot::from(timestamp_slot.saturated_into::()); - assert!( - CurrentSlot::::get() == timestamp_slot, + assert_eq!( + CurrentSlot::::get(), + timestamp_slot, "Timestamp slot must match `CurrentSlot`" ); } diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 4b99cd51796..57e1dbb6b53 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -900,8 +900,9 @@ impl OnTimestampSet for Pallet { let timestamp_slot = moment / slot_duration; let timestamp_slot = Slot::from(timestamp_slot.saturated_into::()); - assert!( - CurrentSlot::::get() == timestamp_slot, + assert_eq!( + CurrentSlot::::get(), + timestamp_slot, "Timestamp slot must match `CurrentSlot`" ); } -- GitLab From 42707bc98b4d0921087c8abbff7ca115cf7e4a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 26 Oct 2023 21:53:15 +0200 Subject: [PATCH 376/633] sp-version: Improve the docs (#2027) Co-authored-by: ordian --- substrate/primitives/version/src/lib.rs | 47 +++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/substrate/primitives/version/src/lib.rs b/substrate/primitives/version/src/lib.rs index bd8408bb4a4..13f4520f6e6 100644 --- a/substrate/primitives/version/src/lib.rs +++ b/substrate/primitives/version/src/lib.rs @@ -175,17 +175,24 @@ pub struct RuntimeVersion { /// will not attempt to author blocks unless this is equal to its native runtime. pub authoring_version: u32, - /// Version of the runtime specification. A full-node will not attempt to use its native - /// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, - /// `spec_version` and `authoring_version` are the same between Wasm and native. + /// Version of the runtime specification. + /// + /// A full-node will not attempt to use its native runtime in substitute for the on-chain + /// Wasm runtime unless all of `spec_name`, `spec_version` and `authoring_version` are the same + /// between Wasm and native. + /// + /// This number should never decrease. pub spec_version: u32, - /// Version of the implementation of the specification. Nodes are free to ignore this; it - /// serves only as an indication that the code is different; as long as the other two versions - /// are the same then while the actual code may be different, it is nonetheless required to - /// do the same thing. - /// Non-consensus-breaking optimizations are about the only changes that could be made which - /// would result in only the `impl_version` changing. + /// Version of the implementation of the specification. + /// + /// Nodes are free to ignore this; it serves only as an indication that the code is different; + /// as long as the other two versions are the same then while the actual code may be different, + /// it is nonetheless required to do the same thing. Non-consensus-breaking optimizations are + /// about the only changes that could be made which would result in only the `impl_version` + /// changing. + /// + /// This number can be reverted to `0` after a [`spec_version`](Self::spec_version) bump. pub impl_version: u32, /// List of supported API "features" along with their versions. @@ -198,15 +205,25 @@ pub struct RuntimeVersion { )] pub apis: ApisVec, - /// All existing dispatches are fully compatible when this number doesn't change. If this - /// number changes, then `spec_version` must change, also. + /// All existing calls (dispatchables) are fully compatible when this number doesn't change. If + /// this number changes, then [`spec_version`](Self::spec_version) must change, also. /// - /// This number must change when an existing dispatchable (module ID, dispatch ID) is changed, + /// This number must change when an existing call (pallet index, call index) is changed, /// either through an alteration in its user-level semantics, a parameter - /// added/removed/changed, a dispatchable being removed, a module being removed, or a - /// dispatchable/module changing its index. + /// added/removed, a parameter type changed, or a call/pallet changing its index. An alteration + /// of the user level semantics is for example when the call was before `transfer` and now is + /// `transfer_all`, the semantics of the call changed completely. + /// + /// Removing a pallet or a call doesn't require a *bump* as long as no pallet or call is put at + /// the same index. Removing doesn't require a bump as the chain will reject a transaction + /// referencing this removed call/pallet while decoding and thus, the user isn't at risk to + /// execute any unknown call. FRAME runtime devs have control over the index of a call/pallet + /// to prevent that an index gets reused. + /// + /// Adding a new pallet or call also doesn't require a *bump* as long as they also don't reuse + /// any previously used index. /// - /// It need *not* change when a new module is added or when a dispatchable is added. + /// This number should never decrease. pub transaction_version: u32, /// Version of the state implementation used by this runtime. -- GitLab From 86228fa45e4c64642f7210cf44c40cc84ae17537 Mon Sep 17 00:00:00 2001 From: yjh Date: Fri, 27 Oct 2023 03:55:49 +0800 Subject: [PATCH 377/633] add `authorities_len` for aura (#2040) --- substrate/frame/aura/src/lib.rs | 7 ++++++- substrate/frame/aura/src/tests.rs | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/substrate/frame/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index 3017120e4e6..f7506db05d1 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -230,6 +230,11 @@ impl Pallet { } } + /// Return current authorities length. + pub fn authorities_len() -> usize { + Authorities::::decode_len().unwrap_or(0) + } + /// Get the current slot from the pre-runtime digests. fn current_slot_from_digests() -> Option { let digest = frame_system::Pallet::::digest(); @@ -363,7 +368,7 @@ impl FindAuthor for Pallet { for (id, mut data) in digests.into_iter() { if id == AURA_ENGINE_ID { let slot = Slot::decode(&mut data).ok()?; - let author_index = *slot % Self::authorities().len() as u64; + let author_index = *slot % Self::authorities_len() as u64; return Some(author_index as u32) } } diff --git a/substrate/frame/aura/src/tests.rs b/substrate/frame/aura/src/tests.rs index d3ce877d3e6..b3a5e144fad 100644 --- a/substrate/frame/aura/src/tests.rs +++ b/substrate/frame/aura/src/tests.rs @@ -29,7 +29,8 @@ use sp_runtime::{Digest, DigestItem}; fn initial_values() { build_ext_and_execute_test(vec![0, 1, 2, 3], || { assert_eq!(Aura::current_slot(), 0u64); - assert_eq!(Aura::authorities().len(), 4); + assert_eq!(Aura::authorities().len(), Aura::authorities_len()); + assert_eq!(Aura::authorities_len(), 4); }); } -- GitLab From 6ca5789db85bd22b1ab18b6bfede6b56c305dd53 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 27 Oct 2023 04:54:56 -0400 Subject: [PATCH 378/633] upgrade docify to 0.2.5 (#2052) Updates `docify` to 0.2.5, which fixes some indentation bugs and adds the new `#[docify::export_content]` attribute which can be used like regular `#[docify::export]` but will only export the _underlying contents_ of the item it is attached to, if applicable (otherwise it just behaves exactly like `#[docify::export]`). Release notes here: https://github.com/sam0x17/docify/releases/tag/v0.2.5 cc @kianenigma --- Cargo.lock | 8 ++++---- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7208b77e109..0facc7e18cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4538,18 +4538,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee528c501ddd15d5181997e9518e59024844eac44fd1e40cb20ddb2a8562fa" +checksum = "80bf86c286159ed2d70e9ff5c4de69b793ab8632c8a1d276d44bbff36f052f64" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca01728ab2679c464242eca99f94e2ce0514b52ac9ad950e2ed03fca991231c" +checksum = "2b5ac3bdcdc56f2317e51884a90bd6f595febd6d029cdb75174162107072a8a3" dependencies = [ "common-path", "derive-syn-parse", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 5f8f31c192b..f6b8335b311 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.4" +docify = "0.2.5" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 832369e5b58..ad502f03d18 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.4" +docify = "0.2.5" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index f0e439081e9..194201b715c 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.4" +docify = "0.2.5" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index d307cc87854..6f8f5973885 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.4" +docify = "0.2.5" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 25f10448d92..5663dc0dea8 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.4" +docify = "0.2.5" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 5caf993bb35..e6edaf22f10 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -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.4" +docify = "0.2.5" static_assertions = "1.1.0" aquamarine = { version = "0.3.2" } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index f0b4d0ce65b..a4d0ec08762 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.4" +docify = "0.2.5" [dev-dependencies] sp-core = { path = "../../primitives/core" } -- GitLab From 43415ef58c143b985e09015cd000dbd65f6d3997 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Fri, 27 Oct 2023 11:38:16 +0200 Subject: [PATCH 379/633] feat: FRAME umbrella crate. (#1337) ### Original PR https://github.com/paritytech/substrate/pull/14137 This PR brings in the first version of the "_`frame` umbrella crate_". This crate is intended to serve two purposes: 1. documentation 2. easier development with frame. Ideally, we want most users to be able to build a frame-based pallet and runtime using just `frame` (plus `scale-codec` and `scale-info`). The crate is not finalized and is not yet intended for external use. Therefore, the version is set to `0.0.1-dev`, this PR is `silent`, and the entire crate is hidden behind the `experimental` flag. The main intention in merging it early on is to be able to iterate on it in the rest of [`developer-hub`](https://github.com/paritytech/polkadot-sdk-docs/) efforts. The public API of the `frame` crate is at the moment as follows: ``` pub mod frame pub use frame::log pub use frame::pallet pub mod frame::arithmetic pub use frame::arithmetic::<> pub use frame::arithmetic::<> pub mod frame::deps pub use frame::deps::codec pub use frame::deps::frame_executive pub use frame::deps::frame_support pub use frame::deps::frame_system pub use frame::deps::scale_info pub use frame::deps::sp_api pub use frame::deps::sp_arithmetic pub use frame::deps::sp_block_builder pub use frame::deps::sp_consensus_aura pub use frame::deps::sp_consensus_grandpa pub use frame::deps::sp_core pub use frame::deps::sp_inherents pub use frame::deps::sp_io pub use frame::deps::sp_offchain pub use frame::deps::sp_runtime pub use frame::deps::sp_std pub use frame::deps::sp_version pub mod frame::derive pub use frame::derive::CloneNoBound pub use frame::derive::Debug pub use frame::derive::Debug pub use frame::derive::DebugNoBound pub use frame::derive::Decode pub use frame::derive::Decode pub use frame::derive::DefaultNoBound pub use frame::derive::Encode pub use frame::derive::Encode pub use frame::derive::EqNoBound pub use frame::derive::PartialEqNoBound pub use frame::derive::RuntimeDebug pub use frame::derive::RuntimeDebugNoBound pub use frame::derive::TypeInfo pub use frame::derive::TypeInfo pub mod frame::prelude pub use frame::prelude::<> pub use frame::prelude::<> pub use frame::prelude::<> pub use frame::prelude::CloneNoBound pub use frame::prelude::Debug pub use frame::prelude::Debug pub use frame::prelude::DebugNoBound pub use frame::prelude::Decode pub use frame::prelude::Decode pub use frame::prelude::DefaultNoBound pub use frame::prelude::Encode pub use frame::prelude::Encode pub use frame::prelude::EqNoBound pub use frame::prelude::PartialEqNoBound pub use frame::prelude::RuntimeDebug pub use frame::prelude::RuntimeDebugNoBound pub use frame::prelude::TypeInfo pub use frame::prelude::TypeInfo pub use frame::prelude::frame_system pub mod frame::primitives pub use frame::primitives::BlakeTwo256 pub use frame::primitives::H160 pub use frame::primitives::H256 pub use frame::primitives::H512 pub use frame::primitives::Hash pub use frame::primitives::Keccak256 pub use frame::primitives::U256 pub use frame::primitives::U512 pub mod frame::runtime pub mod frame::runtime::apis pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::<> pub use frame::runtime::apis::ApplyExtrinsicResult pub use frame::runtime::apis::CheckInherentsResult pub use frame::runtime::apis::InherentData pub use frame::runtime::apis::OpaqueMetadata pub use frame::runtime::apis::impl_runtime_apis pub use frame::runtime::apis::sp_api pub mod frame::runtime::prelude pub use frame::runtime::prelude::<> pub use frame::runtime::prelude::ConstBool pub use frame::runtime::prelude::ConstI128 pub use frame::runtime::prelude::ConstI16 pub use frame::runtime::prelude::ConstI32 pub use frame::runtime::prelude::ConstI64 pub use frame::runtime::prelude::ConstI8 pub use frame::runtime::prelude::ConstU128 pub use frame::runtime::prelude::ConstU16 pub use frame::runtime::prelude::ConstU32 pub use frame::runtime::prelude::ConstU64 pub use frame::runtime::prelude::ConstU8 pub use frame::runtime::prelude::NativeVersion pub use frame::runtime::prelude::RuntimeVersion pub use frame::runtime::prelude::construct_runtime pub use frame::runtime::prelude::create_runtime_str pub use frame::runtime::prelude::derive_impl pub use frame::runtime::prelude::frame_support pub use frame::runtime::prelude::ord_parameter_types pub use frame::runtime::prelude::parameter_types pub use frame::runtime::prelude::runtime_version pub mod frame::runtime::testing_prelude pub use frame::runtime::testing_prelude::BuildStorage pub use frame::runtime::testing_prelude::Storage pub mod frame::runtime::types_common pub type frame::runtime::types_common::AccountId = <::Signer as sp_runtime::traits::IdentifyAccount>::AccountId pub type frame::runtime::types_common::BlockNumber = u32 pub type frame::runtime::types_common::BlockOf = sp_runtime::generic::block::Block, sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic, ::RuntimeCall, frame::runtime::types_common::Signature, Extra>> pub type frame::runtime::types_common::OpaqueBlock = sp_runtime::generic::block::Block, sp_runtime::OpaqueExtrinsic> pub type frame::runtime::types_common::Signature = sp_runtime::MultiSignature pub type frame::runtime::types_common::SystemSignedExtensionsOf = (frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, frame_system::extensions::check_spec_version::CheckSpecVersion, frame_system::extensions::check_tx_version::CheckTxVersion, frame_system::extensions::check_genesis::CheckGenesis, frame_system::extensions::check_mortality::CheckMortality, frame_system::extensions::check_nonce::CheckNonce, frame_system::extensions::check_weight::CheckWeight) pub mod frame::testing_prelude pub use frame::testing_prelude::<> pub use frame::testing_prelude::<> pub use frame::testing_prelude::BuildStorage pub use frame::testing_prelude::ConstBool pub use frame::testing_prelude::ConstI128 pub use frame::testing_prelude::ConstI16 pub use frame::testing_prelude::ConstI32 pub use frame::testing_prelude::ConstI64 pub use frame::testing_prelude::ConstI8 pub use frame::testing_prelude::ConstU128 pub use frame::testing_prelude::ConstU16 pub use frame::testing_prelude::ConstU32 pub use frame::testing_prelude::ConstU64 pub use frame::testing_prelude::ConstU8 pub use frame::testing_prelude::NativeVersion pub use frame::testing_prelude::RuntimeVersion pub use frame::testing_prelude::Storage pub use frame::testing_prelude::TestState pub use frame::testing_prelude::assert_err pub use frame::testing_prelude::assert_err_ignore_postinfo pub use frame::testing_prelude::assert_error_encoded_size pub use frame::testing_prelude::assert_noop pub use frame::testing_prelude::assert_ok pub use frame::testing_prelude::assert_storage_noop pub use frame::testing_prelude::construct_runtime pub use frame::testing_prelude::create_runtime_str pub use frame::testing_prelude::derive_impl pub use frame::testing_prelude::frame_support pub use frame::testing_prelude::frame_system pub use frame::testing_prelude::if_std pub use frame::testing_prelude::ord_parameter_types pub use frame::testing_prelude::parameter_types pub use frame::testing_prelude::runtime_version pub use frame::testing_prelude::storage_alias pub mod frame::traits pub use frame::traits::<> pub use frame::traits::<> ``` --- The road to full stabilization is - [ ] https://github.com/paritytech/polkadot-sdk/issues/127 - [ ] have a more intentional version bump, as opposed to the current bi weekly force-major-bump - [ ] revise the internal API of `frame`, especially what goes into the `prelude`s. - [ ] migrate all internal pallets and runtime to use `frame` --------- Co-authored-by: kianenigma Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Francisco Aguirre --- Cargo.lock | 128 ++++++- Cargo.toml | 4 +- docs/mermaid/substrate_client_runtime.mmd | 10 + docs/mermaid/substrate_simple.mmd | 8 + docs/mermaid/substrate_with_frame.mmd | 20 + substrate/Cargo.toml | 2 +- substrate/bin/minimal/node/Cargo.toml | 56 +++ substrate/bin/minimal/node/build.rs | 23 ++ substrate/bin/minimal/node/src/chain_spec.rs | 66 ++++ substrate/bin/minimal/node/src/cli.rs | 81 ++++ substrate/bin/minimal/node/src/command.rs | 126 +++++++ .../frame => bin/minimal/node}/src/lib.rs | 8 +- substrate/bin/minimal/node/src/main.rs | 30 ++ substrate/bin/minimal/node/src/rpc.rs | 66 ++++ substrate/bin/minimal/node/src/service.rs | 254 +++++++++++++ substrate/bin/minimal/runtime/Cargo.toml | 36 ++ substrate/bin/minimal/runtime/build.rs | 27 ++ substrate/bin/minimal/runtime/src/lib.rs | 231 ++++++++++++ .../client/consensus/manual-seal/src/lib.rs | 2 +- substrate/frame/Cargo.toml | 91 +++++ substrate/frame/examples/Cargo.toml | 8 +- .../frame/examples/frame-crate/Cargo.toml | 24 ++ .../frame/examples/frame-crate/src/lib.rs | 66 ++++ substrate/frame/examples/src/lib.rs | 3 + substrate/frame/src/lib.rs | 347 ++++++++++++++++++ substrate/frame/sudo/src/lib.rs | 24 +- substrate/frame/sudo/src/mock.rs | 4 +- substrate/frame/support/src/lib.rs | 4 + .../support/test/stg_frame_crate/Cargo.toml | 2 +- .../test/stg_frame_crate/frame/Cargo.toml | 20 - ...event_type_invalid_bound_no_frame_crate.rs | 45 +++ ...t_type_invalid_bound_no_frame_crate.stderr | 5 + substrate/frame/system/Cargo.toml | 1 + substrate/frame/system/src/lib.rs | 54 +++ substrate/frame/timestamp/src/lib.rs | 27 +- .../frame/transaction-payment/src/lib.rs | 47 ++- .../primitives/api/proc-macro/src/utils.rs | 28 +- substrate/primitives/core/src/crypto.rs | 3 +- substrate/primitives/keyring/src/ed25519.rs | 12 + substrate/primitives/keyring/src/lib.rs | 5 +- substrate/primitives/keyring/src/sr25519.rs | 12 + .../src/generic/unchecked_extrinsic.rs | 8 +- substrate/primitives/runtime/src/lib.rs | 2 +- substrate/primitives/runtime/src/traits.rs | 4 +- substrate/primitives/session/src/lib.rs | 22 +- .../primitives/session/src/runtime_api.rs | 38 ++ substrate/primitives/weights/src/lib.rs | 18 + substrate/src/lib.rs | 109 ++---- 48 files changed, 2019 insertions(+), 192 deletions(-) create mode 100644 docs/mermaid/substrate_client_runtime.mmd create mode 100644 docs/mermaid/substrate_simple.mmd create mode 100644 docs/mermaid/substrate_with_frame.mmd create mode 100644 substrate/bin/minimal/node/Cargo.toml create mode 100644 substrate/bin/minimal/node/build.rs create mode 100644 substrate/bin/minimal/node/src/chain_spec.rs create mode 100644 substrate/bin/minimal/node/src/cli.rs create mode 100644 substrate/bin/minimal/node/src/command.rs rename substrate/{frame/support/test/stg_frame_crate/frame => bin/minimal/node}/src/lib.rs (90%) create mode 100644 substrate/bin/minimal/node/src/main.rs create mode 100644 substrate/bin/minimal/node/src/rpc.rs create mode 100644 substrate/bin/minimal/node/src/service.rs create mode 100644 substrate/bin/minimal/runtime/Cargo.toml create mode 100644 substrate/bin/minimal/runtime/build.rs create mode 100644 substrate/bin/minimal/runtime/src/lib.rs create mode 100644 substrate/frame/Cargo.toml create mode 100644 substrate/frame/examples/frame-crate/Cargo.toml create mode 100644 substrate/frame/examples/frame-crate/src/lib.rs create mode 100644 substrate/frame/src/lib.rs delete mode 100644 substrate/frame/support/test/stg_frame_crate/frame/Cargo.toml create mode 100644 substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr create mode 100644 substrate/primitives/session/src/runtime_api.rs diff --git a/Cargo.lock b/Cargo.lock index 0facc7e18cf..6c65b139253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -591,7 +591,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -2434,14 +2434,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", + "time 0.1.45", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -5192,10 +5193,32 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame" -version = "0.1.0" +version = "0.0.1-dev" dependencies = [ + "docify", + "frame-executive", "frame-support", "frame-system", + "frame-system-rpc-runtime-api", + "log", + "pallet-examples", + "parity-scale-codec", + "scale-info", + "simple-mermaid", + "sp-api", + "sp-arithmetic", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", ] [[package]] @@ -7933,6 +7956,55 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minimal-node" +version = "4.0.0-dev" +dependencies = [ + "clap 4.4.6", + "frame", + "futures", + "futures-timer", + "jsonrpsee", + "minimal-runtime", + "sc-basic-authorship", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-consensus-manual-seal", + "sc-executor", + "sc-network", + "sc-offchain", + "sc-rpc-api", + "sc-service", + "sc-telemetry", + "sc-transaction-pool", + "sc-transaction-pool-api", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-io", + "sp-keyring", + "sp-runtime", + "sp-timestamp", + "substrate-build-script-utils", + "substrate-frame-rpc-system", +] + +[[package]] +name = "minimal-runtime" +version = "0.1.0" +dependencies = [ + "frame", + "pallet-balances", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "parity-scale-codec", + "scale-info", + "substrate-wasm-builder", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -9695,6 +9767,15 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-example-frame-crate" +version = "0.0.1" +dependencies = [ + "frame", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-example-kitchensink" version = "4.0.0-dev" @@ -9751,6 +9832,7 @@ dependencies = [ "pallet-default-config-example", "pallet-dev-mode", "pallet-example-basic", + "pallet-example-frame-crate", "pallet-example-kitchensink", "pallet-example-offchain-worker", "pallet-example-split", @@ -13796,7 +13878,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring 0.16.20", - "time", + "time 0.3.27", "x509-parser 0.13.2", "yasna", ] @@ -13809,7 +13891,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring 0.16.20", - "time", + "time 0.3.27", "yasna", ] @@ -16497,6 +16579,11 @@ dependencies = [ "wide", ] +[[package]] +name = "simple-mermaid" +version = "0.1.0" +source = "git+https://github.com/kianenigma/simple-mermaid.git?rev=e48b187bcfd5cc75111acd9d241f1bd36604344b#e48b187bcfd5cc75111acd9d241f1bd36604344b" + [[package]] name = "siphasher" version = "0.3.11" @@ -17843,7 +17930,6 @@ dependencies = [ name = "substrate" version = "1.0.0" dependencies = [ - "aquamarine", "chain-spec-builder", "frame-support", "sc-cli", @@ -17854,6 +17940,7 @@ dependencies = [ "sc-consensus-manual-seal", "sc-consensus-pow", "sc-service", + "simple-mermaid", "sp-runtime", "subkey", ] @@ -18570,6 +18657,17 @@ dependencies = [ "tikv-jemalloc-sys", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.27" @@ -19422,6 +19520,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -19924,7 +20028,7 @@ dependencies = [ "sha2 0.10.7", "stun", "thiserror", - "time", + "time 0.3.27", "tokio", "turn", "url", @@ -20539,7 +20643,7 @@ dependencies = [ "ring 0.16.20", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -20557,7 +20661,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -20727,7 +20831,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time", + "time 0.3.27", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c98fe6d1a3a..66271139dfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,6 +179,8 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", + "substrate/bin/minimal/node", + "substrate/bin/minimal/runtime", "substrate", "substrate/bin/node-template/node", "substrate/bin/node-template/pallets/template", @@ -251,6 +253,7 @@ members = [ "substrate/client/transaction-pool", "substrate/client/transaction-pool/api", "substrate/client/utils", + "substrate/frame", "substrate/frame/alliance", "substrate/frame/asset-conversion", "substrate/frame/asset-rate", @@ -350,7 +353,6 @@ 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", diff --git a/docs/mermaid/substrate_client_runtime.mmd b/docs/mermaid/substrate_client_runtime.mmd new file mode 100644 index 00000000000..23c3f849224 --- /dev/null +++ b/docs/mermaid/substrate_client_runtime.mmd @@ -0,0 +1,10 @@ +graph TB +subgraph Substrate + direction LR + subgraph Client + end + subgraph Runtime + end + Client --runtime-api--> Runtime + Runtime --host-functions--> Client +end diff --git a/docs/mermaid/substrate_simple.mmd b/docs/mermaid/substrate_simple.mmd new file mode 100644 index 00000000000..475d8be5ef8 --- /dev/null +++ b/docs/mermaid/substrate_simple.mmd @@ -0,0 +1,8 @@ +graph TB +subgraph Substrate + direction LR + subgraph Client + end + subgraph Runtime + end +end diff --git a/docs/mermaid/substrate_with_frame.mmd b/docs/mermaid/substrate_with_frame.mmd new file mode 100644 index 00000000000..12d072a3360 --- /dev/null +++ b/docs/mermaid/substrate_with_frame.mmd @@ -0,0 +1,20 @@ +graph TB +subgraph Substrate + direction LR + subgraph Client + Database + Networking + Consensus + end + subgraph Runtime + subgraph FRAME + direction LR + Governance + Currency + Staking + Identity + end + end + Client --runtime-api--> Runtime + Runtime --host-functions--> Client +end diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index d77f02c6060..9e2e0b1a6ee 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -10,7 +10,7 @@ version = "1.0.0" # The dependencies are only needed for docs. [dependencies] -aquamarine = "0.3.2" +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } subkey = { path = "bin/utils/subkey" } chain-spec-builder = { path = "bin/utils/chain-spec-builder" } diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml new file mode 100644 index 00000000000..11ce98eec0d --- /dev/null +++ b/substrate/bin/minimal/node/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "minimal-node" +version = "4.0.0-dev" +description = "A fresh FRAME-based Substrate node, ready for hacking." +authors = ["Substrate DevHub "] +homepage = "https://substrate.io/" +edition = "2021" +license = "MIT-0" +publish = false +repository = "https://github.com/substrate-developer-hub/substrate-node-template/" +build = "build.rs" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[[bin]] +name = "minimal-node" + +[dependencies] +clap = { version = "4.0.9", features = ["derive"] } +futures = { version = "0.3.21", features = ["thread-pool"] } +futures-timer = "3.0.1" +jsonrpsee = { version = "0.16.2", features = ["server"] } + +sc-cli = { path = "../../../client/cli" } +sc-executor = { path = "../../../client/executor" } +sc-network = { path = "../../../client/network" } +sc-service = { path = "../../../client/service" } +sc-telemetry = { path = "../../../client/telemetry" } +sc-transaction-pool = { path = "../../../client/transaction-pool" } +sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } +sc-consensus = { path = "../../../client/consensus/common" } +sc-consensus-manual-seal = { path = "../../../client/consensus/manual-seal" } +sc-rpc-api = { path = "../../../client/rpc-api" } +sc-basic-authorship = { path = "../../../client/basic-authorship" } +sc-offchain = { path = "../../../client/offchain" } +sc-client-api = { path = "../../../client/api" } + +sp-timestamp = { path = "../../../primitives/timestamp" } +sp-keyring = { path = "../../../primitives/keyring" } +sp-api = { path = "../../../primitives/api" } +sp-blockchain = { path = "../../../primitives/blockchain" } +sp-block-builder = { path = "../../../primitives/block-builder" } +sp-io = { path = "../../../primitives/io" } +sp-runtime = { path = "../../../primitives/runtime" } + +substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } + +frame = { path = "../../../frame", features = ["runtime", "experimental"] } +runtime = { package = "minimal-runtime", path = "../runtime" } + +[build-dependencies] +substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build-script-utils" } + +[features] +default = [] diff --git a/substrate/bin/minimal/node/build.rs b/substrate/bin/minimal/node/build.rs new file mode 100644 index 00000000000..fa7686e0109 --- /dev/null +++ b/substrate/bin/minimal/node/build.rs @@ -0,0 +1,23 @@ +// 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 substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + rerun_if_git_head_changed(); +} diff --git a/substrate/bin/minimal/node/src/chain_spec.rs b/substrate/bin/minimal/node/src/chain_spec.rs new file mode 100644 index 00000000000..91fa9ef4520 --- /dev/null +++ b/substrate/bin/minimal/node/src/chain_spec.rs @@ -0,0 +1,66 @@ +// 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 runtime::{BalancesConfig, RuntimeGenesisConfig, SudoConfig, SystemConfig, WASM_BINARY}; +use sc_service::{ChainType, Properties}; +use sp_keyring::AccountKeyring; + +/// This is a specialization of the general Substrate ChainSpec type. +pub type ChainSpec = sc_service::GenericChainSpec; + +fn props() -> Properties { + let mut properties = Properties::new(); + properties.insert("tokenDecimals".to_string(), 0.into()); + properties.insert("tokenSymbol".to_string(), "MINI".into()); + properties +} + +pub fn development_config() -> Result { + let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + Ok(ChainSpec::from_genesis( + "Development", + "dev", + ChainType::Development, + move || testnet_genesis(wasm_binary), + vec![], + None, + None, + None, + Some(props()), + None, + )) +} + +/// Configure initial storage state for FRAME pallets. +fn testnet_genesis(wasm_binary: &[u8]) -> RuntimeGenesisConfig { + use frame::traits::Get; + use runtime::interface::{Balance, MinimumBalance}; + let endowment = >::get().max(1) * 1000; + let balances = AccountKeyring::iter() + .map(|a| (a.to_account_id(), endowment)) + .collect::>(); + RuntimeGenesisConfig { + system: SystemConfig { + // Add Wasm runtime to storage. + code: wasm_binary.to_vec(), + _config: Default::default(), + }, + balances: BalancesConfig { balances }, + sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) }, + ..Default::default() + } +} diff --git a/substrate/bin/minimal/node/src/cli.rs b/substrate/bin/minimal/node/src/cli.rs new file mode 100644 index 00000000000..e464fa7d6ca --- /dev/null +++ b/substrate/bin/minimal/node/src/cli.rs @@ -0,0 +1,81 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_cli::RunCmd; + +#[derive(Debug, Clone)] +pub enum Consensus { + ManualSeal(u64), + InstantSeal, +} + +impl std::str::FromStr for Consensus { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(if s == "instant-seal" { + Consensus::InstantSeal + } else if let Some(block_time) = s.strip_prefix("manual-seal-") { + Consensus::ManualSeal(block_time.parse().map_err(|_| "invalid block time")?) + } else { + return Err("incorrect consensus identifier".into()) + }) + } +} + +#[derive(Debug, clap::Parser)] +pub struct Cli { + #[command(subcommand)] + pub subcommand: Option, + + #[clap(long, default_value = "manual-seal-3000")] + pub consensus: Consensus, + + #[clap(flatten)] + pub run: RunCmd, +} + +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + /// Key management cli utilities + #[command(subcommand)] + Key(sc_cli::KeySubcommand), + + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Remove the whole chain. + PurgeChain(sc_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// Db meta columns information. + ChainInfo(sc_cli::ChainInfoCmd), +} diff --git a/substrate/bin/minimal/node/src/command.rs b/substrate/bin/minimal/node/src/command.rs new file mode 100644 index 00000000000..a985370c2d8 --- /dev/null +++ b/substrate/bin/minimal/node/src/command.rs @@ -0,0 +1,126 @@ +// 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::{ + chain_spec, + cli::{Cli, Subcommand}, + service, +}; +use sc_cli::SubstrateCli; +use sc_service::PartialComponents; + +#[cfg(feature = "try-runtime")] +use try_runtime_cli::block_building_info::timestamp_with_aura_info; + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Substrate Node".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + env!("CARGO_PKG_DESCRIPTION").into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "support.anonymous.an".into() + } + + fn copyright_start_year() -> i32 { + 2017 + } + + fn load_spec(&self, id: &str) -> Result, String> { + Ok(match id { + "dev" => Box::new(chain_spec::development_config()?), + path => + Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), + }) + } +} + +/// Parse and run command line arguments +pub fn run() -> sc_cli::Result<()> { + let cli = Cli::from_args(); + + match &cli.subcommand { + Some(Subcommand::Key(cmd)) => cmd.run(&cli), + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + }, + Some(Subcommand::CheckBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, .. } = + service::new_partial(&config)?; + 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, .. } = service::new_partial(&config)?; + 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, .. } = service::new_partial(&config)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, .. } = + service::new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.database)) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, backend, .. } = + service::new_partial(&config)?; + Ok((cmd.run(client, backend, None), task_manager)) + }) + }, + Some(Subcommand::ChainInfo(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run::(&config)) + }, + None => { + let runner = cli.create_runner(&cli.run)?; + runner.run_node_until_exit(|config| async move { + service::new_full(config, cli.consensus).map_err(sc_cli::Error::Service) + }) + }, + } +} diff --git a/substrate/frame/support/test/stg_frame_crate/frame/src/lib.rs b/substrate/bin/minimal/node/src/lib.rs similarity index 90% rename from substrate/frame/support/test/stg_frame_crate/frame/src/lib.rs rename to substrate/bin/minimal/node/src/lib.rs index dba99f1bbe7..c2065def736 100644 --- a/substrate/frame/support/test/stg_frame_crate/frame/src/lib.rs +++ b/substrate/bin/minimal/node/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod deps { - pub use frame_support; - pub use frame_system; -} +pub mod chain_spec; +pub(crate) mod cli; +pub mod rpc; +pub mod service; diff --git a/substrate/bin/minimal/node/src/main.rs b/substrate/bin/minimal/node/src/main.rs new file mode 100644 index 00000000000..900651fd1fd --- /dev/null +++ b/substrate/bin/minimal/node/src/main.rs @@ -0,0 +1,30 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Substrate Node Template CLI library. +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; +mod rpc; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/substrate/bin/minimal/node/src/rpc.rs b/substrate/bin/minimal/node/src/rpc.rs new file mode 100644 index 00000000000..d0c417a93d7 --- /dev/null +++ b/substrate/bin/minimal/node/src/rpc.rs @@ -0,0 +1,66 @@ +// 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 collection of node-specific RPC methods. +//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer +//! used by Substrate nodes. This file extends those RPC definitions with +//! capabilities that are specific to this project's runtime configuration. + +#![warn(missing_docs)] + +use jsonrpsee::RpcModule; +use runtime::interface::{AccountId, Nonce, OpaqueBlock}; +use sc_transaction_pool_api::TransactionPool; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use std::sync::Arc; +use substrate_frame_rpc_system::{System, SystemApiServer}; + +pub use sc_rpc_api::DenyUnsafe; + +/// Full client dependencies. +pub struct FullDeps { + /// The client instance to use. + pub client: Arc, + /// Transaction pool instance. + pub pool: Arc

, + /// Whether to deny unsafe calls + pub deny_unsafe: DenyUnsafe, +} + +/// Instantiate all full RPC extensions. +pub fn create_full( + deps: FullDeps, +) -> Result, Box> +where + C: Send + + Sync + + 'static + + sp_api::ProvideRuntimeApi + + HeaderBackend + + HeaderMetadata + + 'static, + C::Api: sp_block_builder::BlockBuilder, + C::Api: substrate_frame_rpc_system::AccountNonceApi, + P: TransactionPool + 'static, +{ + let mut module = RpcModule::new(()); + let FullDeps { client, pool, deny_unsafe } = deps; + + module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + + Ok(module) +} diff --git a/substrate/bin/minimal/node/src/service.rs b/substrate/bin/minimal/node/src/service.rs new file mode 100644 index 00000000000..b6369c44dda --- /dev/null +++ b/substrate/bin/minimal/node/src/service.rs @@ -0,0 +1,254 @@ +// 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 futures::FutureExt; +use runtime::{self, interface::OpaqueBlock as Block, RuntimeApi}; +use sc_client_api::backend::Backend; +use sc_executor::WasmExecutor; +use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryWorker}; +use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use std::sync::Arc; + +use crate::cli::Consensus; + +#[cfg(feature = "runtime-benchmarks")] +type HostFunctions = + (sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions); + +#[cfg(not(feature = "runtime-benchmarks"))] +type HostFunctions = sp_io::SubstrateHostFunctions; + +pub(crate) type FullClient = + sc_service::TFullClient>; +type FullBackend = sc_service::TFullBackend; +type FullSelectChain = sc_consensus::LongestChain; + +pub fn new_partial( + config: &Configuration, +) -> Result< + sc_service::PartialComponents< + FullClient, + FullBackend, + FullSelectChain, + sc_consensus::DefaultImportQueue, + sc_transaction_pool::FullPool, + Option, + >, + ServiceError, +> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let executor = sc_service::new_wasm_executor(&config); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + )?; + let client = Arc::new(client); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let select_chain = sc_consensus::LongestChain::new(backend.clone()); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let import_queue = sc_consensus_manual_seal::import_queue( + Box::new(client.clone()), + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ); + + Ok(sc_service::PartialComponents { + client, + backend, + task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (telemetry), + }) +} + +/// Builds a new service for a full client. +pub fn new_full(config: Configuration, consensus: Consensus) -> Result { + let sc_service::PartialComponents { + client, + backend, + mut task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: mut telemetry, + } = new_partial(&config)?; + + let net_config = sc_network::config::FullNetworkConfiguration::new(&config.network); + + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: &config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + net_config, + block_announce_validator_builder: None, + warp_sync_params: None, + block_relay: None, + })?; + + if config.offchain_worker.enabled { + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-worker", + sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { + runtime_api_provider: client.clone(), + is_validator: config.role.is_authority(), + keystore: Some(keystore_container.keystore()), + offchain_db: backend.offchain_storage(), + transaction_pool: Some(OffchainTransactionPoolFactory::new( + transaction_pool.clone(), + )), + network_provider: network.clone(), + enable_http_requests: true, + custom_extensions: |_| vec![], + }) + .run(client.clone(), task_manager.spawn_handle()) + .boxed(), + ); + } + + let rpc_extensions_builder = { + let client = client.clone(); + let pool = transaction_pool.clone(); + + Box::new(move |deny_unsafe, _| { + let deps = + crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; + crate::rpc::create_full(deps).map_err(Into::into) + }) + }; + + let prometheus_registry = config.prometheus_registry().cloned(); + + let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { + network, + client: client.clone(), + keystore: keystore_container.keystore(), + task_manager: &mut task_manager, + transaction_pool: transaction_pool.clone(), + rpc_builder: rpc_extensions_builder, + backend, + system_rpc_tx, + tx_handler_controller, + sync_service, + config, + telemetry: telemetry.as_mut(), + })?; + + let proposer = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ); + + match consensus { + Consensus::InstantSeal => { + let params = sc_consensus_manual_seal::InstantSealParams { + block_import: client.clone(), + env: proposer, + client, + pool: transaction_pool, + select_chain, + consensus_data_provider: None, + create_inherent_data_providers: move |_, ()| async move { + Ok(sp_timestamp::InherentDataProvider::from_system_time()) + }, + }; + + let authorship_future = sc_consensus_manual_seal::run_instant_seal(params); + + task_manager.spawn_essential_handle().spawn_blocking( + "instant-seal", + None, + authorship_future, + ); + }, + Consensus::ManualSeal(block_time) => { + let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); + task_manager.spawn_handle().spawn("block_authoring", None, async move { + loop { + futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await; + sink.try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock { + create_empty: true, + finalize: true, + parent_hash: None, + sender: None, + }) + .unwrap(); + } + }); + + let params = sc_consensus_manual_seal::ManualSealParams { + block_import: client.clone(), + env: proposer, + client, + pool: transaction_pool, + select_chain, + commands_stream: Box::pin(commands_stream), + consensus_data_provider: None, + create_inherent_data_providers: move |_, ()| async move { + Ok(sp_timestamp::InherentDataProvider::from_system_time()) + }, + }; + let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); + + task_manager.spawn_essential_handle().spawn_blocking( + "manual-seal", + None, + authorship_future, + ); + }, + } + + network_starter.start_network(); + Ok(task_manager) +} diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml new file mode 100644 index 00000000000..1f9b49da7bc --- /dev/null +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "minimal-runtime" +version = "0.1.0" +edition = "2021" + +[dependencies] +parity-scale-codec = { version = "3.0.0", default-features = false } +scale-info = { version = "2.6.0", default-features = false } + +# this is a frame-based runtime, thus importing `frame` with runtime feature enabled. +frame = { path = "../../../frame", default-features = false, features = ["runtime", "experimental"] } + +# pallets that we want to use +pallet-balances = { path = "../../../frame/balances", default-features = false } +pallet-sudo = { path = "../../../frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } + + +[build-dependencies] +substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } + +[features] +default = [ "std" ] +std = [ + "frame/std", + "pallet-balances/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "parity-scale-codec/std", + "scale-info/std", + "substrate-wasm-builder", +] diff --git a/substrate/bin/minimal/runtime/build.rs b/substrate/bin/minimal/runtime/build.rs new file mode 100644 index 00000000000..b7676a70dfe --- /dev/null +++ b/substrate/bin/minimal/runtime/build.rs @@ -0,0 +1,27 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +fn main() { + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } +} diff --git a/substrate/bin/minimal/runtime/src/lib.rs b/substrate/bin/minimal/runtime/src/lib.rs new file mode 100644 index 00000000000..6c59592554c --- /dev/null +++ b/substrate/bin/minimal/runtime/src/lib.rs @@ -0,0 +1,231 @@ +// 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)] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use frame::{ + deps::frame_support::weights::{FixedFee, NoFee}, + prelude::*, + runtime::{ + apis::{ + self, impl_runtime_apis, ApplyExtrinsicResult, CheckInherentsResult, OpaqueMetadata, + }, + prelude::*, + }, +}; + +#[runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("minimal-runtime"), + impl_name: create_runtime_str!("minimal-runtime"), + authoring_version: 1, + spec_version: 0, + impl_version: 1, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +/// 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() } +} + +type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); + +construct_runtime!( + pub struct Runtime { + System: frame_system, + Timestamp: pallet_timestamp, + + Balances: pallet_balances, + Sudo: pallet_sudo, + TransactionPayment: pallet_transaction_payment, + } +); + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; +} + +#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type Version = Version; + type BlockHashCount = ConstU32<1024>; + type AccountData = pallet_balances::AccountData<::Balance>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type AccountStore = System; +} + +#[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig as pallet_sudo::DefaultConfig)] +impl pallet_sudo::Config for Runtime {} + +#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig as pallet_timestamp::DefaultConfig)] +impl pallet_timestamp::Config for Runtime {} + +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type WeightToFee = NoFee<::Balance>; + type LengthToFee = FixedFee<1, ::Balance>; +} + +type Block = frame::runtime::types_common::BlockOf; +type Header = HeaderFor; + +type RuntimeExecutive = + Executive, Runtime, AllPalletsWithSystem>; + +use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; + +impl_runtime_apis! { + impl apis::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + RuntimeExecutive::execute_block(block) + } + + fn initialize_block(header: &Header) { + RuntimeExecutive::initialize_block(header) + } + } + impl apis::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> Vec { + Runtime::metadata_versions() + } + } + + impl apis::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ExtrinsicFor) -> ApplyExtrinsicResult { + RuntimeExecutive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> HeaderFor { + RuntimeExecutive::finalize_block() + } + + fn inherent_extrinsics(data: InherentData) -> Vec> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: InherentData, + ) -> CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl apis::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ExtrinsicFor, + block_hash: ::Hash, + ) -> TransactionValidity { + RuntimeExecutive::validate_transaction(source, tx, block_hash) + } + } + + impl apis::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &HeaderFor) { + RuntimeExecutive::offchain_worker(header) + } + } + + impl apis::SessionKeys for Runtime { + fn generate_session_keys(_seed: Option>) -> Vec { + Default::default() + } + + fn decode_session_keys( + _encoded: Vec, + ) -> Option, apis::KeyTypeId)>> { + Default::default() + } + } + + impl apis::AccountNonceApi for Runtime { + fn account_nonce(account: interface::AccountId) -> interface::Nonce { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + interface::Balance, + > for Runtime { + fn query_info(uxt: ExtrinsicFor, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details(uxt: ExtrinsicFor, len: u32) -> FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> interface::Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> interface::Balance { + TransactionPayment::length_to_fee(length) + } + } +} + +/// Some re-exports that the node side code needs to know. Some are useful in this context as well. +/// +/// Other types should preferably be private. +// TODO: this should be standardized in some way, see: +// https://github.com/paritytech/substrate/issues/10579#issuecomment-1600537558 +pub mod interface { + use super::Runtime; + use frame::deps::frame_system; + + pub type Block = super::Block; + pub use frame::runtime::types_common::OpaqueBlock; + pub type AccountId = ::AccountId; + pub type Nonce = ::Nonce; + pub type Hash = ::Hash; + pub type Balance = ::Balance; + pub type MinimumBalance = ::ExistentialDeposit; +} diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index 41cd5f3127e..e3608f6716c 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -236,7 +236,7 @@ pub async fn run_instant_seal( // instant-seal creates blocks as soon as transactions are imported // into the transaction pool. let commands_stream = pool.import_notification_stream().map(|_| EngineCommand::SealNewBlock { - create_empty: false, + create_empty: true, finalize: false, parent_hash: None, sender: None, diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml new file mode 100644 index 00000000000..f7b35aba358 --- /dev/null +++ b/substrate/frame/Cargo.toml @@ -0,0 +1,91 @@ +[package] +name = "frame" +version = "0.0.1-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "paritytech.github.io" +repository.workspace = true +description = "The single package to get you started with building frame pallets and runtimes" + +[package.metadata.docs.rs] +# enable `experimental` feature for docs +features = ["experimental"] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# external deps +parity-scale-codec = { version = "3.2.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.6.0", default-features = false, features = ["derive"] } + +# primitive deps, used for developing FRAME pallets. +sp-runtime = { default-features = false, path = "../primitives/runtime" } +sp-std = { default-features = false, path = "../primitives/std" } +sp-io = { default-features = false, path = "../primitives/io" } +sp-core = { default-features = false, path = "../primitives/core" } +sp-arithmetic = { default-features = false, path = "../primitives/arithmetic" } + +# frame deps, for developing FRAME pallets. +frame-support = { default-features = false, path = "support" } +frame-system = { default-features = false, path = "system" } + +# primitive types used for developing FRAME runtimes. +sp-version = { default-features = false, path = "../primitives/version", optional = true } +sp-api = { default-features = false, path = "../primitives/api", optional = true } +sp-block-builder = { default-features = false, path = "../primitives/block-builder", optional = true } +sp-transaction-pool = { default-features = false, path = "../primitives/transaction-pool", optional = true } +sp-offchain = { default-features = false, path = "../primitives/offchain", optional = true } +sp-session = { default-features = false, path = "../primitives/session", optional = true } +sp-consensus-aura = { default-features = false, path = "../primitives/consensus/aura", optional = true } +sp-consensus-grandpa = { default-features = false, path = "../primitives/consensus/grandpa", optional = true } +sp-inherents = { default-features = false, path = "../primitives/inherents", optional = true } + +frame-executive = { default-features = false, path = "../frame/executive", optional = true } +frame-system-rpc-runtime-api = { default-features = false, path = "../frame/system/rpc/runtime-api", optional = true } + +docify = "0.2.0" +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } +log = { version = "0.4.20", default-features = false } + +[dev-dependencies] +pallet-examples = { path = "./examples" } + +[features] +default = [ "runtime", "std" ] +experimental = [ "frame-support/experimental", "frame-system/experimental" ] +runtime = [ + "frame-executive", + "frame-system-rpc-runtime-api", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-inherents", + "sp-offchain", + "sp-session", + "sp-transaction-pool", + "sp-version", +] +std = [ + "frame-executive?/std", + "frame-support/std", + "frame-system-rpc-runtime-api?/std", + "frame-system/std", + "log/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-api?/std", + "sp-arithmetic/std", + "sp-block-builder?/std", + "sp-consensus-aura?/std", + "sp-consensus-grandpa?/std", + "sp-core/std", + "sp-inherents?/std", + "sp-io/std", + "sp-offchain?/std", + "sp-runtime/std", + "sp-session?/std", + "sp-std/std", + "sp-transaction-pool?/std", + "sp-version?/std", +] diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 9c47d744211..98c4e51889b 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -12,11 +12,12 @@ description = "The single package with examples of various types of FRAME pallet targets = ["x86_64-unknown-linux-gnu"] [dependencies] -pallet-example-basic = { path = "basic", default-features = false} pallet-default-config-example = { path = "default-config", default-features = false} -pallet-example-offchain-worker = { path = "offchain-worker", default-features = false} -pallet-example-kitchensink = { path = "kitchensink", default-features = false} pallet-dev-mode = { path = "dev-mode", default-features = false} +pallet-example-basic = { path = "basic", default-features = false} +pallet-example-frame-crate = { path = "frame-crate", default-features = false } +pallet-example-kitchensink = { path = "kitchensink", default-features = false} +pallet-example-offchain-worker = { path = "offchain-worker", default-features = false} pallet-example-split = { path = "split", default-features = false} [features] @@ -25,6 +26,7 @@ std = [ "pallet-default-config-example/std", "pallet-dev-mode/std", "pallet-example-basic/std", + "pallet-example-frame-crate/std", "pallet-example-kitchensink/std", "pallet-example-offchain-worker/std", "pallet-example-split/std", diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml new file mode 100644 index 00000000000..d525008e525 --- /dev/null +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pallet-example-frame-crate" +version = "0.0.1" +authors = ["Parity Technologies "] +edition = "2021" +license = "MIT-0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME example pallet with umbrella crate" +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 } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +frame = { path = "../..", default-features = false, features = ["runtime", "experimental"] } + + +[features] +default = [ "std" ] +std = [ "codec/std", "frame/std", "scale-info/std" ] diff --git a/substrate/frame/examples/frame-crate/src/lib.rs b/substrate/frame/examples/frame-crate/src/lib.rs new file mode 100644 index 00000000000..0fea2c22cf5 --- /dev/null +++ b/substrate/frame/examples/frame-crate/src/lib.rs @@ -0,0 +1,66 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame::prelude::*; + +#[frame::pallet(dev_mode)] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: IsType<::RuntimeEvent> + From>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + pub enum Event {} + + #[pallet::storage] + pub type Value = StorageValue; + + #[pallet::call] + impl Pallet { + pub fn some_dispatchable(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use crate::pallet as my_pallet; + use frame::testing_prelude::*; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + MyPallet: my_pallet, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl my_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + } +} diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index a7084fc6ef9..8d65639f835 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -40,4 +40,7 @@ //! - [`pallet_example_split`]: A simple example of a FRAME pallet demonstrating the ability to //! split sections across multiple files. //! +//! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be +//! built using only the `frame` umbrella crate. +//! //! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs new file mode 100644 index 00000000000..1a8350405a8 --- /dev/null +++ b/substrate/frame/src/lib.rs @@ -0,0 +1,347 @@ +// 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. + +//! > Made for [![polkadot]](https://polkadot.network) +//! +//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white +//! +//! # FRAME +//! +//! ```no_compile +//! ______ ______ ________ ___ __ __ ______ +//! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ +//! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ +//! \:\/___/\\:(_) ) )_\::(_) \ \\:. \ \\:\/___/\ +//! \:::._\/ \: __ `\ \\:: __ \ \\:.\-/\ \ \\::___\/_ +//! \:\ \ \ \ `\ \ \\:.\ \ \ \\. \ \ \ \\:\____/\ +//! \_\/ \_\/ \_\/ \__\/\__\/ \__\/ \__\/ \_____\/ +//! ``` +//! +//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's +//! > State Transition Function (Runtime) Framework. +//! +//! ## Warning: Experimental +//! +//! This crate and all of its content is experimental, and should not yet be used in production. +//! +//! ## Getting Started +//! +//! TODO: link to `developer_hub::polkadot_sdk::frame`. The `developer_hub` hasn't been published +//! yet, this can be updated once it is linkable. + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "experimental")] + +/// Exports the main pallet macro. This can wrap a `mod pallet` and will transform it into +/// being a pallet, eg `#[frame::pallet] mod pallet { .. }`. +/// +/// Note that this is not part of the prelude, in order to make it such that the common way to +/// define a macro is `#[frame::pallet] mod pallet { .. }`, followed by `#[pallet::foo]`, +/// `#[pallet::bar]` inside the mod. +pub use frame_support::pallet; + +/// The logging library of the runtime. Can normally be the classic `log` crate. +pub use log; + +/// The main prelude of FRAME. +/// +/// This prelude should almost always be the first line of code in any pallet or runtime. +/// +/// ``` +/// use frame::prelude::*; +/// +/// // rest of your pallet.. +/// mod pallet {} +/// ``` +pub mod prelude { + /// `frame_system`'s parent crate, which is mandatory in all pallets build with this crate. + /// + /// Conveniently, the keyword `frame_system` is in scope as one uses `use + /// frame::prelude::*` + #[doc(inline)] + pub use frame_system; + + /// Pallet prelude of `frame-support`. + /// + /// Note: this needs to revised once `frame-support` evolves. + // `frame-support` will be break down https://github.com/paritytech/polkadot-sdk/issues/127 and its reexports will + // most likely change. These wildcard reexportings can be optimized once `frame-support` has + // changed. + #[doc(no_inline)] + pub use frame_support::pallet_prelude::*; + + /// Pallet prelude of `frame-system`. + #[doc(no_inline)] + pub use frame_system::pallet_prelude::*; + + /// All of the std alternative types. + #[doc(no_inline)] + pub use sp_std::prelude::*; + + /// All FRAME-relevant derive macros. + #[doc(no_inline)] + pub use super::derive::*; +} + +/// The main testing prelude of FRAME. +/// +/// A test setup typically starts with: +/// +/// ``` +/// use frame::testing_prelude::*; +/// // rest of your test setup. +/// ``` +#[cfg(feature = "std")] +pub mod testing_prelude { + pub use super::prelude::*; + /// Testing includes building a runtime, so we bring in all preludes related to runtimes as + /// well. + pub use super::runtime::testing_prelude::*; + + /// Other helper macros from `frame_support` that help with asserting in tests. + pub use frame_support::{ + assert_err, assert_err_ignore_postinfo, assert_error_encoded_size, assert_noop, assert_ok, + assert_storage_noop, storage_alias, + }; + + pub use frame_system::{self, mocking::*}; + pub use sp_io::TestExternalities as TestState; + pub use sp_std::if_std; +} + +/// All of the types and tools needed to build FRAME-based runtimes. +#[cfg(any(feature = "runtime", feature = "std"))] +pub mod runtime { + /// The main prelude of `FRAME` for building runtimes. + /// + /// A runtime typically starts with: + /// + /// ``` + /// use frame::{prelude::*, runtime::prelude::*}; + /// ``` + pub mod prelude { + /// All of the types related to the FRAME runtime executive. + pub use frame_executive::*; + + /// Macro to amalgamate the runtime into `struct Runtime`. + pub use frame_support::construct_runtime; + + /// Macro to easily derive the `Config` trait of various pallet for `Runtime`. + pub use frame_support::derive_impl; + + /// Macros to easily impl traits such as `Get` for types. + // TODO: using linking in the Get in the line above triggers an ICE :/ + pub use frame_support::{ord_parameter_types, parameter_types}; + + /// Const types that can easily be used in conjuncture with `Get`. + pub use frame_support::traits::{ + ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, + ConstU32, ConstU64, ConstU8, + }; + + /// Types to define your runtime version. + pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; + + #[cfg(feature = "std")] + pub use sp_version::NativeVersion; + } + + /// Types and traits for runtimes that implement runtime APIs. + /// + /// A testing runtime should not need this. + /// + /// A non-testing runtime should have this enabled, as such: + /// + /// ``` + /// use frame::runtime::{prelude::*, apis::{*,}}; + /// ``` + // TODO: This is because of wildcard imports, and it should be not needed once we can avoid + // that. Imports like that are needed because we seem to need some unknown types in the macro + // expansion. See `sp_session::runtime_api::*;` as one example. All runtime api decls should be + // moved to file similarly. + #[allow(ambiguous_glob_reexports)] + pub mod apis { + // Types often used in the runtime APIs. + pub use sp_core::OpaqueMetadata; + pub use sp_inherents::{CheckInherentsResult, InherentData}; + pub use sp_runtime::ApplyExtrinsicResult; + + /// Macro to implement runtime APIs. + pub use sp_api::impl_runtime_apis; + + pub use frame_system_rpc_runtime_api::*; + pub use sp_api::{self, *}; + pub use sp_block_builder::*; + pub use sp_consensus_aura::*; + pub use sp_consensus_grandpa::*; + pub use sp_offchain::*; + pub use sp_session::runtime_api::*; + pub use sp_transaction_pool::runtime_api::*; + } + + /// A set of opinionated types aliases commonly used in runtimes. + /// + /// This is one set of opinionated types. They are compatible with one another, but are not + /// guaranteed to work if you start tweaking a portion. + /// + /// Some note-worthy opinions in this prelude: + /// + /// - `u32` block number. + /// - [`sp_runtime::MultiAddress`] and [`sp_runtime::MultiSignature`] are used as the account id + /// and signature types. This implies that this prelude can possibly used with an + /// "account-index" system (eg `pallet-indices`). And, in any case, it should be paired with + /// `AccountIdLookup` in [`frame_system::Config::Lookup`]. + pub mod types_common { + use frame_system::Config as SysConfig; + use sp_runtime::{generic, traits, OpaqueExtrinsic}; + + /// A signature type compatible capably of handling multiple crypto-schemes. + pub type Signature = sp_runtime::MultiSignature; + + /// The corresponding account-id type of [`Signature`]. + pub type AccountId = + <::Signer as traits::IdentifyAccount>::AccountId; + + /// The block-number type, which should be fed into [`frame_system::Config`]. + pub type BlockNumber = u32; + + /// TODO: Ideally we want the hashing type to be equal to SysConfig::Hashing? + type HeaderInner = generic::Header; + + // NOTE: `AccountIndex` is provided for future compatibility, if you want to introduce + // something like `pallet-indices`. + type ExtrinsicInner = generic::UncheckedExtrinsic< + sp_runtime::MultiAddress, + ::RuntimeCall, + Signature, + Extra, + >; + + /// The block type, which should be fed into [`frame_system::Config`]. + /// + /// Should be parameterized with `T: frame_system::Config` and a tuple of `SignedExtension`. + /// When in doubt, use [`SystemSignedExtensionsOf`]. + // Note that this cannot be dependent on `T` for block-number because it would lead to a + // circular dependency (self-referential generics). + pub type BlockOf = generic::Block>; + + /// The opaque block type. This is the same [`BlockOf`], but it has + /// [`sp_runtime::OpaqueExtrinsic`] as its final extrinsic type. + /// + /// This should be provided to the client side as the extrinsic type. + pub type OpaqueBlock = generic::Block; + + /// Default set of signed extensions exposed from the `frame_system`. + /// + /// crucially, this does NOT contain any tx-payment extension. + pub type SystemSignedExtensionsOf = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + ); + } + + /// The main prelude of FRAME for building runtimes, and in the context of testing. + /// + /// counter part of `runtime::prelude`. + #[cfg(feature = "std")] + pub mod testing_prelude { + pub use super::prelude::*; + pub use sp_core::storage::Storage; + pub use sp_runtime::BuildStorage; + } +} + +/// All traits often used in FRAME pallets. +/// +/// Note that types implementing these traits can also be found in this module. +// TODO: `Hash` and `Bounded` are defined multiple times; should be fixed once these two crates are +// cleaned up. +#[allow(ambiguous_glob_reexports)] +pub mod traits { + pub use frame_support::traits::*; + pub use sp_runtime::traits::*; +} + +/// The arithmetic types used for safe math. +pub mod arithmetic { + pub use sp_arithmetic::{traits::*, *}; +} + +/// Low level primitive types used in FRAME pallets. +pub mod primitives { + pub use sp_core::{H160, H256, H512, U256, U512}; + pub use sp_runtime::traits::{BlakeTwo256, Hash, Keccak256}; +} + +/// All derive macros used in frame. +/// +/// This is already part of the [`prelude`]. +pub mod derive { + pub use frame_support::{ + CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, + RuntimeDebugNoBound, + }; + pub use parity_scale_codec::{Decode, Encode}; + pub use scale_info::TypeInfo; + pub use sp_runtime::RuntimeDebug; + pub use sp_std::fmt::Debug; +} + +/// Access to all of the dependencies of this crate. In case the re-exports are not enough, this +/// module can be used. +/// +/// Any time one uses this module to access a dependency, you can have a moment to think about +/// whether this item could have been placed in any of the other modules and preludes in this crate. +/// In most cases, hopefully the answer is yes. +pub mod deps { + // TODO: It would be great to somehow instruct RA to prefer *not* suggesting auto-imports from + // these. For example, we prefer `frame::derive::CloneNoBound` rather than + // `frame::deps::frame_support::CloneNoBound`. + pub use frame_support; + pub use frame_system; + + pub use sp_arithmetic; + pub use sp_core; + pub use sp_io; + pub use sp_runtime; + pub use sp_std; + + pub use parity_scale_codec as codec; + pub use scale_info; + + #[cfg(feature = "runtime")] + pub use frame_executive; + #[cfg(feature = "runtime")] + pub use sp_api; + #[cfg(feature = "runtime")] + pub use sp_block_builder; + #[cfg(feature = "runtime")] + pub use sp_consensus_aura; + #[cfg(feature = "runtime")] + pub use sp_consensus_grandpa; + #[cfg(feature = "runtime")] + pub use sp_inherents; + #[cfg(feature = "runtime")] + pub use sp_offchain; + #[cfg(feature = "runtime")] + pub use sp_version; +} diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index fb29c0da42a..36de44d9d72 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -148,12 +148,34 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - #[pallet::config] + /// Default preludes for [`Config`]. + pub mod config_preludes { + use super::*; + use frame_support::derive_impl; + + /// Default prelude sensible to be used in a testing environment. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + type WeightInfo = (); + #[inject_runtime_type] + type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeCall = (); + } + } + #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// The overarching event type. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A sudo-able call. + #[pallet::no_default_bounds] type RuntimeCall: Parameter + UnfilteredDispatchable + GetDispatchInfo; diff --git a/substrate/frame/sudo/src/mock.rs b/substrate/frame/sudo/src/mock.rs index 9e78e474f4e..427bda6d99e 100644 --- a/substrate/frame/sudo/src/mock.rs +++ b/substrate/frame/sudo/src/mock.rs @@ -19,8 +19,8 @@ use super::*; use crate as sudo; -use frame_support::traits::{ConstU32, ConstU64, Contains}; -use sp_core::H256; +use frame_support::traits::{ConstU32, Contains}; +use sp_core::{ConstU64, H256}; use sp_io; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index f54252ff9d6..1c696bbb84a 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -802,16 +802,20 @@ pub mod testing_prelude { /// Prelude to be used alongside pallet macro, for ease of use. pub mod pallet_prelude { pub use crate::{ + defensive, defensive_assert, dispatch::{DispatchClass, DispatchResult, DispatchResultWithPostInfo, Parameter, Pays}, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, storage, storage::{ + bounded_btree_map::BoundedBTreeMap, + bounded_btree_set::BoundedBTreeSet, bounded_vec::BoundedVec, types::{ CountedStorageMap, CountedStorageNMap, Key as NMapKey, OptionQuery, ResultQuery, StorageDoubleMap, StorageMap, StorageNMap, StorageValue, ValueQuery, }, + weak_bounded_vec::WeakBoundedVec, StorageList, }, traits::{ diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 64c6147dd1f..0f9617c0368 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame = { path = "frame", default-features = false} +frame = { path = "../../..", default-features = false, features = ["runtime", "experimental"]} scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [features] diff --git a/substrate/frame/support/test/stg_frame_crate/frame/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/frame/Cargo.toml deleted file mode 100644 index d99ac2d2d46..00000000000 --- a/substrate/frame/support/test/stg_frame_crate/frame/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "frame" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -publish = false -homepage = "https://substrate.io" -repository.workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -frame-system = { path = "../../../../system", default-features = false} -frame-support = { path = "../../..", default-features = false} - -[features] -default = [ "std" ] -std = [ "frame-support/std", "frame-system/std" ] diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs new file mode 100644 index 00000000000..573ceb6dfab --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs @@ -0,0 +1,45 @@ +// 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::deps::frame_system::pallet_prelude::BlockNumberFor; + use frame_support::pallet_prelude::{Hooks, IsType}; + + #[pallet::config] + pub trait Config: frame::deps::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/event_type_invalid_bound_no_frame_crate.stderr b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr new file mode 100644 index 00000000000..0f805c972e4 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr @@ -0,0 +1,5 @@ +error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` + --> tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs:26:3 + | +26 | type RuntimeEvent: IsType<::RuntimeEvent> + | ^^^^ diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 908d8092eef..f7733e312c3 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -52,6 +52,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "sp-runtime/try-runtime" ] +experimental = [] [[bench]] name = "bench" diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 897d3bd7ce9..eca20f5a0a9 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -244,6 +244,53 @@ pub mod pallet { type BlockHashCount = frame_support::traits::ConstU64<10>; type OnSetCode = (); } + + /// Default configurations of this pallet in a solo-chain environment. + /// + /// ## Considerations: + /// + /// By default, this type makes the following choices: + /// + /// * Use a normal 32 byte account id, with a [`DefaultConfig::Lookup`] that implies no + /// 'account-indexing' pallet is being used. + /// * Given that we don't know anything about the existence of a currency system in scope, + /// an [`DefaultConfig::AccountData`] is chosen that has no addition data. Overwrite this + /// if you use `pallet-balances` or similar. + /// * Make sure to overwrite [`DefaultConfig::Version`]. + /// * 2s block time, and a default 5mb block size is used. + #[cfg(feature = "experimental")] + pub struct SolochainDefaultConfig; + + #[cfg(feature = "experimental")] + #[frame_support::register_default_impl(SolochainDefaultConfig)] + impl DefaultConfig for SolochainDefaultConfig { + type Nonce = u32; + type Hash = sp_core::hash::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = sp_runtime::AccountId32; + type Lookup = sp_runtime::traits::AccountIdLookup; + type MaxConsumers = frame_support::traits::ConstU32<128>; + type AccountData = crate::AccountInfo; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type Version = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + #[inject_runtime_type] + type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeOrigin = (); + #[inject_runtime_type] + type RuntimeCall = (); + #[inject_runtime_type] + type PalletInfo = (); + type BaseCallFilter = frame_support::traits::Everything; + type BlockHashCount = frame_support::traits::ConstU32<256>; + type OnSetCode = (); + } } /// System configuration trait. Implemented by runtime. @@ -1817,4 +1864,11 @@ pub mod pallet_prelude { /// Type alias for the `BlockNumber` associated type of system config. pub type BlockNumberFor = as sp_runtime::traits::Header>::Number; + + /// Type alias for the `Extrinsic` associated type of system config. + pub type ExtrinsicFor = + <::Block as sp_runtime::traits::Block>::Extrinsic; + + /// Type alias for the `RuntimeCall` associated type of system config. + pub type RuntimeCallFor = ::RuntimeCall; } diff --git a/substrate/frame/timestamp/src/lib.rs b/substrate/frame/timestamp/src/lib.rs index ad055bab004..a62ac6d633d 100644 --- a/substrate/frame/timestamp/src/lib.rs +++ b/substrate/frame/timestamp/src/lib.rs @@ -31,7 +31,7 @@ //! //! See the [`pallet`] module for more information about the interfaces this pallet exposes, //! including its configuration trait, dispatchables, storage items, events and errors. -//! +//! //! ## Overview //! //! The Timestamp pallet is designed to create a consensus-based time source. This helps ensure that @@ -144,12 +144,33 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{derive_impl, pallet_prelude::*}; use frame_system::pallet_prelude::*; - #[pallet::config] + /// Default preludes for [`Config`]. + pub mod config_preludes { + use super::*; + + /// Default prelude sensible to be used in a testing environment. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = frame_support::traits::ConstU64<1>; + type WeightInfo = (); + } + } + + /// The pallet configuration trait + #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// Type used for expressing a timestamp. + #[pallet::no_default_bounds] type Moment: Parameter + Default + AtLeast32Bit diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 8160d72ad89..efadfd60bdd 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -319,9 +319,29 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); - #[pallet::config] + pub mod config_preludes { + use super::*; + use frame_support::derive_impl; + + /// Default prelude sensible to be used in a testing environment. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = (); + } + } + + #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// The overarching event type. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Handler for withdrawing, refunding and depositing the transaction fee. @@ -330,12 +350,24 @@ pub mod pallet { /// adjusted, depending on the used resources by the transaction. If the /// transaction weight is lower than expected, parts of the transaction fee /// might be refunded. In the end the fees can be deposited. + #[pallet::no_default] type OnChargeTransaction: OnChargeTransaction; - /// A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their + /// Convert a weight value into a deductible fee based on the currency type. + #[pallet::no_default] + type WeightToFee: WeightToFee>; + + /// Convert a length value into a deductible fee based on the currency type. + #[pallet::no_default] + type LengthToFee: WeightToFee>; + + /// Update the multiplier of the next block, based on the previous block's weight. + type FeeMultiplierUpdate: MultiplierUpdate; + + /// A fee multiplier for `Operational` extrinsics to compute "virtual tip" to boost their /// `priority` /// - /// This value is multipled by the `final_fee` to obtain a "virtual tip" that is later + /// This value is multiplied by the `final_fee` to obtain a "virtual tip" that is later /// added to a tip component in regular `priority` calculations. /// It means that a `Normal` transaction can front-run a similarly-sized `Operational` /// extrinsic (with no tip), by including a tip value greater than the virtual tip. @@ -355,15 +387,6 @@ pub mod pallet { /// transactions. #[pallet::constant] type OperationalFeeMultiplier: Get; - - /// Convert a weight value into a deductible fee based on the currency type. - type WeightToFee: WeightToFee>; - - /// Convert a length value into a deductible fee based on the currency type. - type LengthToFee: WeightToFee>; - - /// Update the multiplier of the next block, based on the previous block's weight. - type FeeMultiplierUpdate: MultiplierUpdate; } #[pallet::type_value] diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index c9389154bbf..e261b162b5a 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -15,21 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::common::API_VERSION_ATTRIBUTE; +use inflector::Inflector; use proc_macro2::{Span, TokenStream}; - +use proc_macro_crate::{crate_name, FoundCrate}; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse_quote, spanned::Spanned, token::And, Attribute, Error, FnArg, GenericArgument, Ident, ImplItem, ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, }; -use quote::{format_ident, quote}; - -use proc_macro_crate::{crate_name, FoundCrate}; - -use crate::common::API_VERSION_ATTRIBUTE; - -use inflector::Inflector; - /// Generates the access to the `sc_client` crate. pub fn generate_crate_access() -> TokenStream { match crate_name("sp-api") { @@ -38,10 +33,15 @@ pub fn generate_crate_access() -> TokenStream { let renamed_name = Ident::new(&renamed_name, Span::call_site()); quote!(#renamed_name) }, - Err(e) => { - let err = Error::new(Span::call_site(), e).to_compile_error(); - quote!( #err ) - }, + Err(e) => + if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + let path = format!("{}::deps::{}", name, "sp_api"); + let path = syn::parse_str::(&path).expect("is a valid path; qed"); + quote!( #path ) + } else { + let err = Error::new(Span::call_site(), e).to_compile_error(); + quote!( #err ) + }, } } @@ -261,8 +261,6 @@ pub fn versioned_trait_name(trait_ident: &Ident, version: u64) -> Ident { /// Extract the documentation from the provided attributes. #[cfg(feature = "frame-metadata")] pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { - use quote::ToTokens; - attrs .iter() .filter_map(|attr| { diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index ccb61c12f32..f7e2c56ca9a 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -942,8 +942,7 @@ pub trait Pair: CryptoType + Sized { /// - the path may be followed by `///`, in which case everything after the `///` is treated /// as a password. /// - If `s` begins with a `/` character it is prefixed with the Substrate public `DEV_PHRASE` - /// and - /// interpreted as above. + /// and interpreted as above. /// /// In this case they are interpreted as HDKD junctions; purely numeric items are interpreted as /// integers, non-numeric items as strings. Junctions prefixed with `/` are interpreted as soft diff --git a/substrate/primitives/keyring/src/ed25519.rs b/substrate/primitives/keyring/src/ed25519.rs index c3ad86409e9..3060bfb1ad9 100644 --- a/substrate/primitives/keyring/src/ed25519.rs +++ b/substrate/primitives/keyring/src/ed25519.rs @@ -35,6 +35,12 @@ pub enum Keyring { Dave, Eve, Ferdie, + AliceStash, + BobStash, + CharlieStash, + DaveStash, + EveStash, + FerdieStash, One, Two, } @@ -104,6 +110,12 @@ impl From for &'static str { Keyring::Dave => "Dave", Keyring::Eve => "Eve", Keyring::Ferdie => "Ferdie", + Keyring::AliceStash => "Alice//stash", + Keyring::BobStash => "Bob//stash", + Keyring::CharlieStash => "Charlie//stash", + Keyring::DaveStash => "Dave//stash", + Keyring::EveStash => "Eve//stash", + Keyring::FerdieStash => "Ferdie//stash", Keyring::One => "One", Keyring::Two => "Two", } diff --git a/substrate/primitives/keyring/src/lib.rs b/substrate/primitives/keyring/src/lib.rs index 1db18f7edbd..ee7fd56ba11 100644 --- a/substrate/primitives/keyring/src/lib.rs +++ b/substrate/primitives/keyring/src/lib.rs @@ -27,9 +27,8 @@ pub mod ed25519; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; -/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`, -/// since it tends to be used for accounts (although it may also be used -/// by authorities). +/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`, since it tends to be +/// used for accounts (although it may also be used by authorities). pub use sr25519::Keyring as AccountKeyring; #[cfg(feature = "bandersnatch-experimental")] diff --git a/substrate/primitives/keyring/src/sr25519.rs b/substrate/primitives/keyring/src/sr25519.rs index c738cfdc59d..914a66b4d83 100644 --- a/substrate/primitives/keyring/src/sr25519.rs +++ b/substrate/primitives/keyring/src/sr25519.rs @@ -35,6 +35,12 @@ pub enum Keyring { Dave, Eve, Ferdie, + AliceStash, + BobStash, + CharlieStash, + DaveStash, + EveStash, + FerdieStash, One, Two, } @@ -114,6 +120,12 @@ impl From for &'static str { Keyring::Dave => "Dave", Keyring::Eve => "Eve", Keyring::Ferdie => "Ferdie", + Keyring::AliceStash => "Alice//stash", + Keyring::BobStash => "Bob//stash", + Keyring::CharlieStash => "Charlie//stash", + Keyring::DaveStash => "Dave//stash", + Keyring::EveStash => "Eve//stash", + Keyring::FerdieStash => "Ferdie//stash", Keyring::One => "One", Keyring::Two => "Two", } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 0b1cd2b5429..1cdc0b8e405 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -134,16 +134,16 @@ impl Checkable - for UncheckedExtrinsic +impl Checkable + for UncheckedExtrinsic where - Address: Member + MaybeDisplay, + LookupSource: Member + MaybeDisplay, Call: Encode + Member, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, Extra: SignedExtension, AccountId: Member + MaybeDisplay, - Lookup: traits::Lookup, + Lookup: traits::Lookup, { type Checked = CheckedExtrinsic; diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index dd861ad05de..0e1d4c31fd7 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -466,7 +466,7 @@ impl Verify for MultiSignature { } /// Signature verify that can work with any known signature types.. -#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct AnySignature(H512); diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 17dc7ce50ea..ec79f43cabd 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -226,7 +226,7 @@ pub trait StaticLookup { } /// A lookup implementation returning the input value. -#[derive(Default)] +#[derive(Default, Clone, Copy, PartialEq, Eq)] pub struct IdentityLookup(PhantomData); impl StaticLookup for IdentityLookup { type Source = T; @@ -1666,8 +1666,6 @@ impl SignedExtension for Tuple { } } -/// Only for bare bone testing when you don't care about signed extensions at all. -#[cfg(feature = "std")] impl SignedExtension for () { type AccountId = u64; type AdditionalSigned = (); diff --git a/substrate/primitives/session/src/lib.rs b/substrate/primitives/session/src/lib.rs index 45395e9766f..9933495fd60 100644 --- a/substrate/primitives/session/src/lib.rs +++ b/substrate/primitives/session/src/lib.rs @@ -26,28 +26,12 @@ use sp_api::ProvideRuntimeApi; #[cfg(feature = "std")] use sp_runtime::traits::Block as BlockT; -use sp_core::{crypto::KeyTypeId, RuntimeDebug}; +use sp_core::RuntimeDebug; use sp_staking::SessionIndex; use sp_std::vec::Vec; -sp_api::decl_runtime_apis! { - /// Session keys runtime api. - pub trait SessionKeys { - /// Generate a set of session keys with optionally using the given seed. - /// The keys should be stored within the keystore exposed via runtime - /// externalities. - /// - /// The seed needs to be a valid `utf8` string. - /// - /// Returns the concatenated SCALE encoded public keys. - fn generate_session_keys(seed: Option>) -> Vec; - - /// Decode the given public session keys. - /// - /// Returns the list of public raw public keys + key type. - fn decode_session_keys(encoded: Vec) -> Option, KeyTypeId)>>; - } -} +pub mod runtime_api; +pub use runtime_api::*; /// Number of validators in a given session. pub type ValidatorCount = u32; diff --git a/substrate/primitives/session/src/runtime_api.rs b/substrate/primitives/session/src/runtime_api.rs new file mode 100644 index 00000000000..5e508cd3dbd --- /dev/null +++ b/substrate/primitives/session/src/runtime_api.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. + +pub use sp_core::crypto::KeyTypeId; +use sp_std::prelude::*; + +sp_api::decl_runtime_apis! { + /// Session keys runtime api. + pub trait SessionKeys { + /// Generate a set of session keys with optionally using the given seed. + /// The keys should be stored within the keystore exposed via runtime + /// externalities. + /// + /// The seed needs to be a valid `utf8` string. + /// + /// Returns the concatenated SCALE encoded public keys. + fn generate_session_keys(seed: Option>) -> Vec; + + /// Decode the given public session keys. + /// + /// Returns the list of public raw public keys + key type. + fn decode_session_keys(encoded: Vec) -> Option, sp_core::crypto::KeyTypeId)>>; + } +} diff --git a/substrate/primitives/weights/src/lib.rs b/substrate/primitives/weights/src/lib.rs index 36cf864dd53..ececb622fa0 100644 --- a/substrate/primitives/weights/src/lib.rs +++ b/substrate/primitives/weights/src/lib.rs @@ -248,7 +248,25 @@ where } } +/// Implementor of [`WeightToFee`] such that it maps any unit of weight to a fixed fee. +pub struct FixedFee(sp_std::marker::PhantomData); + +impl WeightToFee for FixedFee +where + T: BaseArithmetic + From + Copy + Unsigned, +{ + type Balance = T; + + fn weight_to_fee(_: &Weight) -> Self::Balance { + F.into() + } +} + +/// An implementation of [`WeightToFee`] that collects no fee. +pub type NoFee = FixedFee<0, T>; + /// Implementor of [`WeightToFee`] that uses a constant multiplier. +/// /// # Example /// /// ``` diff --git a/substrate/src/lib.rs b/substrate/src/lib.rs index 409515ea505..be9eef9952f 100644 --- a/substrate/src/lib.rs +++ b/substrate/src/lib.rs @@ -55,9 +55,22 @@ //! is merely a matter of the Wasm blob being changed in the chain state, which is, in principle, //! same as updating an account's balance. //! -//! To learn more about the substrate architecture using some visuals, see [`substrate_diagram`]. +//! ### Architecture //! -//! `FRAME`, Substrate's default runtime development library takes the above even further by +//! Therefore, Substrate can be visualized as follows: +#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_simple.mmd")] +//! +//! The client and the runtime of course need to communicate. This is done through two concepts: +//! +//! 1. Host functions: a way for the (Wasm) runtime to talk to the client. All host functions are +//! defined in [`sp-io`]. For example, [`sp-io::storage`] are the set of host functions that +//! allow the runtime to read and write data to the on-chain state. +//! 2. Runtime APIs: a way for the client to talk to the Wasm runtime. Runtime APIs are defined +//! using macros and utilities in [`sp-api`]. For example, [`sp-api::Core`] is the most basic +//! runtime API that any blockchain must implement in order to be able to (re) execute blocks. +#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_client_runtime.mmd")] +//! +//! [`FRAME`], Substrate's default runtime development library takes the above even further by //! embracing a declarative programming model whereby correctness is enhanced and the system is //! highly configurable through parameterization. //! @@ -68,8 +81,8 @@ //! ## How to Get Stared //! //! Most developers want to leave the client side code as-is, and focus on the runtime. To do so, -//! look into the [`frame_support`] crate, which is the entry point crate into runtime development -//! with FRAME. +//! look into the [`frame`] crate, which is the entry point crate into runtime development with +//! FRAME. //! //! > Side note, it is entirely possible to craft a substrate-based runtime without FRAME, an //! > example of which can be found [here](https://github.com/JoshOrndorff/frameless-node-template). @@ -79,8 +92,8 @@ //! * **Templates**: A number of substrate-based templates exist and they can be used for various //! purposes, with zero to little additional code needed. All of these templates contain runtimes //! that are highly configurable and are likely suitable for basic needs. -//! * `FRAME`: If need, one can customize that runtime even further, by using `FRAME` and developing -//! custom modules. +//! * [`FRAME`]: If need, one can customize that runtime even further, by using `FRAME` and +//! developing custom modules. //! * **Core**: To the contrary, some developers may want to customize the client side software to //! achieve novel goals such as a new consensus engine, or a new database backend. While //! Substrate's main configurability is in the runtime, the client is also highly generic and can @@ -100,10 +113,9 @@ //! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These //! are the traits that glue the client and runtime together, but are not opinionated about what //! framework is using for building the runtime. Notable examples are [`sp-api`] and [`sp-io`], -//! which form the communication bridge between the client and runtime, as explained in -//! [`substrate_diagram`]. +//! which form the communication bridge between the client and runtime. //! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related -//! to FRAME. See [`frame_support`] for more information. +//! to FRAME. See [`frame`] for more information. //! //! ### Wasm Build //! @@ -157,8 +169,9 @@ //! 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/polkadot-sdk/tree/master/cumulus), the -//! library on top of Substrate, empowering any substrate-based chain to be a Polkadot parachain. +//! 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? //! @@ -199,6 +212,7 @@ //! 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 +//! [`FRAME`]: ../frame/index.html //! [`sp-io`]: ../sp_io/index.html //! [`sp-api`]: ../sp_api/index.html //! [`sp-api`]: ../sp_api/index.html @@ -222,76 +236,3 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] - -#[cfg_attr(doc, aquamarine::aquamarine)] -/// In this module, we explore substrate at a more depth. First, let's establish substrate being -/// divided into a client and runtime. -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// end -/// subgraph Runtime -/// end -/// end -/// ``` -/// -/// The client and the runtime of course need to communicate. This is done through two concepts: -/// -/// 1. Host functions: a way for the (Wasm) runtime to talk to the client. All host functions are -/// defined in [`sp-io`]. For example, [`sp-io::storage`] are the set of host functions that -/// allow the runtime to read and write data to the on-chain state. -/// 2. Runtime APIs: a way for the client to talk to the Wasm runtime. Runtime APIs are defined -/// using macros and utilities in [`sp-api`]. For example, [`sp-api::Core`] is the most basic -/// runtime API that any blockchain must implement in order to be able to (re) execute blocks. -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// end -/// subgraph Runtime -/// end -/// Client --runtime-api--> Runtime -/// Runtime --host-functions--> Client -/// end -/// ``` -/// -/// Finally, let's expand the diagram a bit further and look at the internals of each component: -/// -/// ```mermaid -/// graph TB -/// subgraph Substrate -/// direction LR -/// subgraph Client -/// Database -/// Networking -/// Consensus -/// end -/// subgraph Runtime -/// subgraph FRAME -/// direction LR -/// Governance -/// Currency -/// Staking -/// Identity -/// end -/// end -/// Client --runtime-api--> Runtime -/// Runtime --host-functions--> Client -/// end -/// ``` -/// -/// As noted the runtime contains all of the application specific logic of the blockchain. This is -/// usually written with `FRAME`. The client, on the other hand, contains reusable and generic -/// components that are not specific to one single blockchain, such as networking, database, and the -/// consensus engine. -/// -/// [`sp-io`]: ../../sp_io/index.html -/// [`sp-api`]: ../../sp_api/index.html -/// [`sp-io::storage`]: ../../sp_io/storage/index.html -/// [`sp-api::Core`]: ../../sp_api/trait.Core.html -pub mod substrate_diagram {} -- GitLab From 3069b0af398e5a0374802c31201637e97f4a530a Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:50:30 +0300 Subject: [PATCH 380/633] make polkadot die graciously (#2056) While investigating some db migrations that make the node startup fail, I noticed that the node wasn't exiting and that the log file were growing exponentially, until my whole system was freezing and that makes it really hard to actually find why it was failing in the first place. E.g: ``` ls -lh /tmp/zombie-01a04c2a2c0265d85f6440cf01c0f44a_-51319-uyggzuD4wEpV/bob.log 32,6G oct 27 11:16 /tmp/zombie-01a04c2a2c0265d85f6440cf01c0f44a_-51319-uyggzuD4wEpV/bob.log ``` This was happening because the following errors were being printed continously without the subsystem main loop exiting: From dispute-coordinator: ``` WARN tokio-runtime-worker parachain::dispute-coordinator: error=Subsystem(Generated(Context("Signal channel is terminated and empty."))) ``` From availability recovery: ``` Erasure task channel closed. Node shutting down ? ``` Signed-off-by: Alexandru Gheorghe --- polkadot/node/core/dispute-coordinator/src/lib.rs | 3 ++- polkadot/node/network/availability-recovery/src/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index 3f0fd401314..e96fee81240 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -27,6 +27,7 @@ use std::sync::Arc; +use error::FatalError; use futures::FutureExt; use gum::CandidateHash; @@ -431,7 +432,7 @@ impl DisputeCoordinatorSubsystem { #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)] async fn wait_for_first_leaf(ctx: &mut Context) -> Result> { loop { - match ctx.recv().await? { + match ctx.recv().await.map_err(FatalError::SubsystemReceive)? { FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(None), FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { if let Some(activated) = update.activated { diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index e2146981da9..9acc48ea92e 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -822,6 +822,7 @@ async fn erasure_task_thread( target: LOG_TARGET, "Erasure task channel closed. Node shutting down ?", ); + break }, } } -- GitLab From 9643a3adf8c2d2bf2a8e496e06702013d547cd55 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 27 Oct 2023 15:58:55 +0200 Subject: [PATCH 381/633] Enable "cargo run --bin substrate-node" (#1927) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 66271139dfd..2c63aabf935 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -456,7 +456,7 @@ members = [ "substrate/utils/prometheus", "substrate/utils/wasm-builder", ] -default-members = [ "polkadot" ] +default-members = [ "polkadot", "substrate/bin/node/cli" ] [profile.release] # Polkadot runtime requires unwinding. -- GitLab From bea8baed691496816ac50794855cc0e9a5b5cd79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 27 Oct 2023 20:35:59 +0200 Subject: [PATCH 382/633] level-monitor: Fix issue with warp syncing (#2053) When warp syncing a node we import a header of the parachain around the tip of the chain. This header is currently not imported as finalized block (should be fixed at some point as well), the parent headers are not yet present (still being synced) and thus, we run into a panic. Even if there is a case where a leaf could not be found in the database, this probably means that the db is broken and it will fail somewhere elese. --- .../consensus/common/src/level_monitor.rs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/cumulus/client/consensus/common/src/level_monitor.rs b/cumulus/client/consensus/common/src/level_monitor.rs index 5f115ec2c4a..270e3f57ae5 100644 --- a/cumulus/client/consensus/common/src/level_monitor.rs +++ b/cumulus/client/consensus/common/src/level_monitor.rs @@ -98,7 +98,6 @@ where /// /// Level limits are not enforced during this phase. fn restore(&mut self) { - const ERR_MSG: &str = "route from finalized to leaf should be available; qed"; let info = self.backend.blockchain().info(); log::debug!( @@ -112,7 +111,14 @@ where self.import_counter = info.finalized_number; for leaf in self.backend.blockchain().leaves().unwrap_or_default() { - let mut meta = self.backend.blockchain().header_metadata(leaf).expect(ERR_MSG); + let Ok(mut meta) = self.backend.blockchain().header_metadata(leaf) else { + log::debug!( + target: LOG_TARGET, + "Could not fetch header metadata for leaf: {leaf:?}", + ); + + continue + }; self.import_counter = self.import_counter.max(meta.number); @@ -123,7 +129,19 @@ where if meta.number <= self.lowest_level { break } - meta = self.backend.blockchain().header_metadata(meta.parent).expect(ERR_MSG); + + meta = match self.backend.blockchain().header_metadata(meta.parent) { + Ok(m) => m, + Err(_) => { + // This can happen after we have warp synced a node. + log::debug!( + target: LOG_TARGET, + "Could not fetch header metadata for parent: {:?}", + meta.parent, + ); + break + }, + } } } -- GitLab From f46f5a90f688b213faa502780a45a1598f32703b Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 27 Oct 2023 15:43:51 -0400 Subject: [PATCH 383/633] upgrade to docify 0.2.6 (#2069) Updates `docify` to 0.2.6, which fixes a bug that was preventing nesting `#[docify::export]` within sub-items of items that already have `#[docify::export]` attached to them from working properly. Release notes here: https://github.com/sam0x17/docify/releases/tag/v0.2.6 cc @ggwpez @kianenigma --- Cargo.lock | 8 ++++---- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c65b139253..60790128506 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4539,18 +4539,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bf86c286159ed2d70e9ff5c4de69b793ab8632c8a1d276d44bbff36f052f64" +checksum = "4235e9b248e2ba4b92007fe9c646f3adf0ffde16dc74713eacc92b8bc58d8d2f" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5ac3bdcdc56f2317e51884a90bd6f595febd6d029cdb75174162107072a8a3" +checksum = "47020e12d7c7505670d1363dd53d6c23724f71a90a3ae32ff8eba40de8404626" dependencies = [ "common-path", "derive-syn-parse", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index f6b8335b311..05b86f6c723 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.5" +docify = "0.2.6" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index ad502f03d18..2aa2e918f3e 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.5" +docify = "0.2.6" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 194201b715c..4bc3dd6a3c7 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.5" +docify = "0.2.6" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 6f8f5973885..6aa81baf7ac 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.5" +docify = "0.2.6" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 5663dc0dea8..ef507a95316 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.5" +docify = "0.2.6" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index e6edaf22f10..82942c3a4f1 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -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.5" +docify = "0.2.6" static_assertions = "1.1.0" aquamarine = { version = "0.3.2" } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index a4d0ec08762..e23ded725d8 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.5" +docify = "0.2.6" [dev-dependencies] sp-core = { path = "../../primitives/core" } -- GitLab From a70617124b4c0c730016a210e2b8b343c829d784 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Sat, 28 Oct 2023 10:23:19 +1100 Subject: [PATCH 384/633] Automatically build and attach production and dev runtimes to GH releases (#2054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/paritytech/release-engineering/issues/6 Adds a new Github Workflow which on a new release being created, builds and attaches all runtimes managed in this repository in two flavours: - `dev-debug-build`: Built with the `try-runtime` feature and has logging enabled - `on-chain-release`: Built with the regular old `on-chain-release` feature The new Github Workflow could be extended in the future by the @paritytech/release-engineering team to fully automate the release process if they choose to, similar to how it is fully automated in the Fellowship repo (https://github.com/polkadot-fellows/runtimes/blob/main/.github/workflows/release.yml). The `on-chain-release` did not exist for parachains, so I added it. --- Tested on my fork: - https://github.com/liamaharon/polkadot-sdk/actions/runs/6663773523 - https://github.com/liamaharon/polkadot-sdk/releases/tag/test-6 --------- Co-authored-by: Chevdor Co-authored-by: Dónal Murray --- .../build-and-attach-release-runtimes.yml | 69 +++++++++++++++++++ .../assets/asset-hub-rococo/Cargo.toml | 5 ++ .../assets/asset-hub-westend/Cargo.toml | 5 ++ .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 5 ++ .../contracts/contracts-rococo/Cargo.toml | 5 ++ .../glutton/glutton-kusama/Cargo.toml | 5 ++ polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- 8 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build-and-attach-release-runtimes.yml diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml new file mode 100644 index 00000000000..297f7a1665b --- /dev/null +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -0,0 +1,69 @@ +name: Build and Attach Runtimes to Releases/RC + +on: + release: + types: + - created + +env: + PROFILE: production + +jobs: + build_and_upload: + strategy: + matrix: + runtime: + - { name: westend, package: westend-runtime, path: polkadot/runtime/westend } + - { name: rococo, package: rococo-runtime, path: polkadot/runtime/rococo } + - { name: asset-hub-rococo, package: asset-hub-rococo-runtime, path: cumulus/parachains/runtimes/assets/asset-hub-rococo } + - { name: asset-hub-westend, package: asset-hub-westend-runtime, path: cumulus/parachains/runtimes/assets/asset-hub-westend } + - { name: bridge-hub-rococo, package: bridge-hub-rococo-runtime, path: cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo } + - { name: contracts-rococo, package: contracts-rococo-runtime, path: cumulus/parachains/runtimes/contracts/contracts-rococo } + build_config: + # Release build has logging disabled and no dev features + - { type: on-chain-release, opts: --features on-chain-release-build } + # Debug build has logging enabled and developer features + - { type: dev-debug-build, opts: --features try-runtime } + + runs-on: ubuntu-22.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build ${{ matrix.runtime.name }} ${{ matrix.build_config.type }} + id: srtool_build + uses: chevdor/srtool-actions@v0.8.0 + env: + BUILD_OPTS: ${{ matrix.build_config.opts }} + with: + chain: ${{ matrix.runtime.name }} + package: ${{ matrix.runtime.package }} + runtime_dir: ${{ matrix.runtime.path }} + profile: ${{ env.PROFILE }} + + - name: Build Summary + run: | + echo "${{ steps.srtool_build.outputs.json }}" | jq . > ${{ matrix.runtime.name }}-srtool-digest.json + cat ${{ matrix.runtime.name }}-srtool-digest.json + echo "Runtime location: ${{ steps.srtool_build.outputs.wasm }}" + + - name: Set up paths and runtime names + id: setup + run: | + RUNTIME_BLOB_NAME=$(echo ${{ matrix.runtime.package }} | sed 's/-/_/g').compact.compressed.wasm + PREFIX=${{ matrix.build_config.type == 'dev-debug-build' && 'DEV_DEBUG_BUILD__' || '' }} + + echo "RUNTIME_BLOB_NAME=$RUNTIME_BLOB_NAME" >> $GITHUB_ENV + echo "ASSET_PATH=./${{ matrix.runtime.path }}/target/srtool/${{ env.PROFILE }}/wbuild/${{ matrix.runtime.package }}/$RUNTIME_BLOB_NAME" >> $GITHUB_ENV + echo "ASSET_NAME=$PREFIX$RUNTIME_BLOB_NAME" >> $GITHUB_ENV + + - name: Upload Runtime to Release + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.ASSET_PATH }} + asset_name: ${{ env.ASSET_NAME }} + asset_content_type: application/octet-stream + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index ea5b5fa0554..ebf811e5463 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -240,3 +240,8 @@ std = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 5e3807f2785..7c7a0731459 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -217,3 +217,8 @@ std = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 5befb21c891..8c4e1612780 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -233,3 +233,8 @@ try-runtime = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index a020b66baae..0eb2428f358 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -192,3 +192,8 @@ try-runtime = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index e8abc61311c..f5362e4d6b2 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -125,3 +125,8 @@ try-runtime = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6d0dee3e434..243f4337cae 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -314,7 +314,7 @@ 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 +# A feature that should be enabled when the runtime should be built 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/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index a4f1bfb007e..cb1118cf92f 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -338,7 +338,7 @@ 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 +# A feature that should be enabled when the runtime should be built 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" ] -- GitLab From 8ce16ee6ff190912995dc6c8da85b741eaada395 Mon Sep 17 00:00:00 2001 From: Vadim Smirnov Date: Sun, 29 Oct 2023 20:20:40 +0800 Subject: [PATCH 385/633] fix(frame-benchmarking-cli): Pass heap_pages param to WasmExecutor (#2075) In https://github.com/paritytech/substrate/pull/13740 the use of the `heap-pages` param inside the `frame-benchmarking-cli` has been removed. This results in running out of memory and this PR fixes the heap allocation strategy for benchmarks wasm executor. --- .../utils/frame/benchmarking-cli/src/pallet/command.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 99f77866f8d..5c76ca68e85 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -25,7 +25,7 @@ use frame_support::traits::StorageInfo; use linked_hash_map::LinkedHashMap; use sc_cli::{execution_method_from_cli, CliConfiguration, Result, SharedParams}; use sc_client_db::BenchmarkingState; -use sc_executor::WasmExecutor; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sc_service::Configuration; use serde::Serialize; use sp_core::{ @@ -219,12 +219,20 @@ impl PalletCmd { let method = execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy); + let heap_pages = + self.heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |p| HeapAllocStrategy::Static { + extra_pages: p as _, + }); + let executor = WasmExecutor::<( sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions, ExtraHostFunctions, )>::builder() .with_execution_method(method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) .with_max_runtime_instances(2) .with_runtime_cache_size(2) .build(); -- GitLab From 7035034710ecb9c6a786284e5f771364c520598d Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sun, 29 Oct 2023 18:25:33 +0100 Subject: [PATCH 386/633] Improve Client CLI help readability (#2073) Currently the CLI `-h/--help` commad output is almost unreadable as (for some commands) it: - doesn't provide a short brief of what the command does. - doesn't separate the options description in smaller paragraphs. - doesn't use a smart wrap strategy for lines longer than the number of columns in the terminal. Follow some pics taken with a 100 cols wide term ## Short help (./node -h) ### Before ![20231028-174531-grim](https://github.com/paritytech/polkadot-sdk/assets/8143589/11b62c3c-dcd5-43f4-ac58-f1b299e3f4b9) ### After ![20231028-175041-grim](https://github.com/paritytech/polkadot-sdk/assets/8143589/dc08f6fd-b287-40fb-8b33-71a185922104) ## Long help (./node --help) ### Before ![20231028-175257-grim](https://github.com/paritytech/polkadot-sdk/assets/8143589/9ebdc0ae-54ee-4760-b873-a7e813523cb6) ### After ![20231028-175155-grim](https://github.com/paritytech/polkadot-sdk/assets/8143589/69cbe5cb-eb2f-46a5-8ebf-76c0cf8c4bad) --------- Co-authored-by: command-bot <> --- Cargo.lock | 11 +++ polkadot/cli/src/cli.rs | 33 +++++---- substrate/client/cli/Cargo.toml | 2 +- substrate/client/cli/src/commands/run_cmd.rs | 69 ++++++++++++------- .../client/cli/src/params/import_params.rs | 19 +++-- .../client/cli/src/params/keystore_params.rs | 5 +- .../client/cli/src/params/network_params.rs | 47 +++++++++---- .../client/cli/src/params/node_key_params.rs | 42 ++++++----- .../cli/src/params/offchain_worker_params.rs | 8 +-- .../cli/src/params/prometheus_params.rs | 2 + .../client/cli/src/params/pruning_params.rs | 2 + .../client/cli/src/params/runtime_params.rs | 4 +- .../client/cli/src/params/shared_params.rs | 27 ++++++-- .../client/cli/src/params/telemetry_params.rs | 3 + .../cli/src/params/transaction_pool_params.rs | 4 +- substrate/client/storage-monitor/src/lib.rs | 9 ++- 16 files changed, 190 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60790128506..1183f9204a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2572,6 +2572,7 @@ dependencies = [ "anstyle", "clap_lex 0.5.1", "strsim", + "terminal_size", ] [[package]] @@ -18425,6 +18426,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix 0.38.8", + "windows-sys 0.48.0", +] + [[package]] name = "termtree" version = "0.4.1" diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index bc060c21fba..e20e35c9103 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -84,29 +84,29 @@ pub struct RunCmd { /// Setup a GRANDPA scheduled voting pause. /// - /// This parameter takes two values, namely a block number and a delay (in - /// blocks). After the given block number is finalized the GRANDPA voter - /// will temporarily stop voting for new blocks until the given delay has - /// elapsed (i.e. until a block at height `pause_block + delay` is imported). + /// This parameter takes two values, namely a block number and a delay (in blocks). + /// + /// After the given block number is finalized the GRANDPA voter will temporarily + /// stop voting for new blocks until the given delay has elapsed (i.e. until a + /// block at height `pause_block + delay` is imported). #[arg(long = "grandpa-pause", num_args = 2)] pub grandpa_pause: Vec, - /// Disable the BEEFY gadget - /// (currently enabled by default on Rococo, Wococo and Versi). + /// Disable the BEEFY gadget. + /// + /// Currently enabled by default on 'Rococo', 'Wococo' and 'Versi'. #[arg(long)] pub no_beefy: bool, - /// Add the destination address to the jaeger agent. + /// Add the destination address to the 'Jaeger' agent. /// - /// Must be valid socket address, of format `IP:Port` - /// commonly `127.0.0.1:6831`. + /// Must be valid socket address, of format `IP:Port` (commonly `127.0.0.1:6831`). #[arg(long)] pub jaeger_agent: Option, /// Add the destination address to the `pyroscope` agent. /// - /// Must be valid socket address, of format `IP:Port` - /// commonly `127.0.0.1:4040`. + /// Must be valid socket address, of format `IP:Port` (commonly `127.0.0.1:4040`). #[arg(long)] pub pyroscope_server: Option, @@ -126,10 +126,13 @@ pub struct RunCmd { #[arg(long)] pub overseer_channel_capacity_override: Option, - /// Path to the directory where auxiliary worker binaries reside. If not specified, the main - /// binary's directory is searched first, then `/usr/lib/polkadot` is searched. TESTING ONLY: - /// if the path points to an executable rather then directory, that executable is used both as - /// preparation and execution worker. + /// Path to the directory where auxiliary worker binaries reside. + /// + /// If not specified, the main binary's directory is searched first, then + /// `/usr/lib/polkadot` is searched. + /// + /// TESTING ONLY: if the path points to an executable rather then directory, + /// that executable is used both as preparation and execution worker. #[arg(long, value_name = "PATH")] pub workers_path: Option, diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 98928700328..dc53ed54d96 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.6", features = ["derive", "string"] } +clap = { version = "4.4.6", features = ["derive", "string", "wrap_help"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index 5dda488b133..bc62dc3324e 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -40,35 +40,38 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; #[derive(Debug, Clone, Parser)] pub struct RunCmd { /// Enable validator mode. + /// /// The node will be started with the authority role and actively /// participate in any consensus task that it can (e.g. depending on /// availability of local keys). #[arg(long)] pub validator: bool, - /// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA + /// Disable GRANDPA. + /// + /// Disables voter when running in validator mode, otherwise disable the GRANDPA /// observer. #[arg(long)] pub no_grandpa: bool, - /// Listen to all RPC interfaces. - /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC - /// proxy server to filter out dangerous methods. More details: + /// Listen to all RPC interfaces (default: local). + /// + /// Not all RPC methods are safe to be exposed publicly. + /// + /// Use an RPC proxy server to filter out dangerous methods. More details: /// . + /// /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. #[arg(long)] pub rpc_external: bool, /// Listen to all RPC interfaces. + /// /// Same as `--rpc-external`. #[arg(long)] pub unsafe_rpc_external: bool, /// RPC methods to expose. - /// - `unsafe`: Exposes every RPC method. - /// - `safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. - /// - `auto`: Acts as `safe` if RPC is served externally, e.g. when `--rpc--external` is - /// passed, otherwise acts as `unsafe`. #[arg( long, value_name = "METHOD SET", @@ -79,15 +82,15 @@ pub struct RunCmd { )] pub rpc_methods: RpcMethods, - /// Set the the maximum RPC request payload size for both HTTP and WS in megabytes. + /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. #[arg(long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB)] pub rpc_max_request_size: u32, - /// Set the the maximum RPC response payload size for both HTTP and WS in megabytes. + /// Set the maximum RPC response payload size for both HTTP and WS in megabytes. #[arg(long, default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB)] pub rpc_max_response_size: u32, - /// Set the the maximum concurrent subscriptions per connection. + /// Set the maximum concurrent subscriptions per connection. #[arg(long, default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN)] pub rpc_max_subscriptions_per_connection: u32, @@ -99,15 +102,17 @@ pub struct RunCmd { #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS)] pub rpc_max_connections: u32, - /// Specify browser Origins allowed to access the HTTP & WS RPC servers. - /// A comma-separated list of origins (protocol://domain or special `null` + /// Specify browser *origins* allowed to access the HTTP and WS RPC servers. + /// + /// A comma-separated list of origins (`protocol://domain` or special `null` /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in - /// --dev mode the default is to allow all origins. + /// `--dev` mode the default is to allow all origins. #[arg(long, value_name = "ORIGINS", value_parser = parse_cors)] pub rpc_cors: Option, /// The human-readable name for this node. + /// /// It's used as network node name. #[arg(long, value_name = "NAME")] pub name: Option, @@ -148,36 +153,51 @@ pub struct RunCmd { #[clap(flatten)] pub keystore_params: KeystoreParams, - /// Shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore. + /// Shortcut for `--name Alice --validator`. + /// + /// Session keys for `Alice` are added to keystore. #[arg(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub alice: bool, - /// Shortcut for `--name Bob --validator` with session keys for `Bob` added to keystore. + /// Shortcut for `--name Bob --validator`. + /// + /// Session keys for `Bob` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub bob: bool, - /// Shortcut for `--name Charlie --validator` with session keys for `Charlie` added to - /// keystore. + /// Shortcut for `--name Charlie --validator`. + /// + /// Session keys for `Charlie` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] pub charlie: bool, - /// Shortcut for `--name Dave --validator` with session keys for `Dave` added to keystore. + /// Shortcut for `--name Dave --validator`. + /// + /// Session keys for `Dave` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] pub dave: bool, - /// Shortcut for `--name Eve --validator` with session keys for `Eve` added to keystore. + /// Shortcut for `--name Eve --validator`. + /// + /// Session keys for `Eve` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] pub eve: bool, - /// Shortcut for `--name Ferdie --validator` with session keys for `Ferdie` added to keystore. + /// Shortcut for `--name Ferdie --validator`. + /// + /// Session keys for `Ferdie` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] pub ferdie: bool, - /// Shortcut for `--name One --validator` with session keys for `One` added to keystore. + /// Shortcut for `--name One --validator`. + /// + /// Session keys for `One` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] pub one: bool, - /// Shortcut for `--name Two --validator` with session keys for `Two` added to keystore. + /// Shortcut for `--name Two --validator`. + /// + /// Session keys for `Two` are added to keystore. #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] pub two: bool, @@ -186,10 +206,13 @@ pub struct RunCmd { pub force_authoring: bool, /// Run a temporary node. + /// /// A temporary directory will be created to store the configuration and will be deleted /// at the end of the process. + /// /// Note: the directory is random per process execution. This directory is used as base path /// which includes: database, node key and keystore. + /// /// When `--dev` is given and no explicit `--base-path`, this option is implied. #[arg(long, conflicts_with = "base_path")] pub tmp: bool, diff --git a/substrate/client/cli/src/params/import_params.rs b/substrate/client/cli/src/params/import_params.rs index bfa54a35058..add7cb4f850 100644 --- a/substrate/client/cli/src/params/import_params.rs +++ b/substrate/client/cli/src/params/import_params.rs @@ -48,6 +48,7 @@ pub struct ImportParams { pub wasm_method: WasmExecutionMethod, /// The WASM instantiation method to use. + /// /// Only has an effect when `wasm-execution` is set to `compiled`. /// The copy-on-write strategies are only supported on Linux. /// If the copy-on-write variant of a strategy is unsupported @@ -65,6 +66,7 @@ pub struct ImportParams { pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Specify the path where local WASM runtimes are stored. + /// /// These runtimes will override on-chain runtimes when the version matches. #[arg(long, value_name = "PATH")] pub wasm_runtime_overrides: Option, @@ -74,12 +76,12 @@ pub struct ImportParams { pub execution_strategies: ExecutionStrategiesParams, /// Specify the state cache size. + /// /// Providing `0` will disable the cache. #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, - /// DEPRECATED - /// Switch to `--trie-cache-size`. + /// DEPRECATED: switch to `--trie-cache-size`. #[arg(long)] state_cache_size: Option, } @@ -115,26 +117,23 @@ impl ImportParams { /// Execution strategies parameters. #[derive(Debug, Clone, Args)] pub struct ExecutionStrategiesParams { - /// The means of execution used when calling into the runtime for importing blocks as - /// part of an initial sync. + /// Runtime execution strategy for importing blocks during initial sync. #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_syncing: Option, - /// The means of execution used when calling into the runtime for general block import - /// (including locally authored blocks). + /// Runtime execution strategy for general block import (including locally authored blocks). #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_import_block: Option, - /// The means of execution used when calling into the runtime while constructing blocks. + /// Runtime execution strategy for constructing blocks. #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_block_construction: Option, - /// The means of execution used when calling into the runtime while using an off-chain worker. + /// Runtime execution strategy for offchain workers. #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_offchain_worker: Option, - /// The means of execution used when calling into the runtime while not syncing, importing or - /// constructing blocks. + /// Runtime execution strategy when not syncing, importing or constructing blocks. #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_other: Option, diff --git a/substrate/client/cli/src/params/keystore_params.rs b/substrate/client/cli/src/params/keystore_params.rs index 87210c3390c..5a5d0f94999 100644 --- a/substrate/client/cli/src/params/keystore_params.rs +++ b/substrate/client/cli/src/params/keystore_params.rs @@ -39,8 +39,9 @@ pub struct KeystoreParams { #[arg(long, conflicts_with_all = &["password", "password_filename"])] pub password_interactive: bool, - /// Password used by the keystore. This allows appending an extra user-defined secret to the - /// seed. + /// Password used by the keystore. + /// + /// This allows appending an extra user-defined secret to the seed. #[arg( long, value_parser = secret_string_from_str, diff --git a/substrate/client/cli/src/params/network_params.rs b/substrate/client/cli/src/params/network_params.rs index 84db218cc51..12f19df2a68 100644 --- a/substrate/client/cli/src/params/network_params.rs +++ b/substrate/client/cli/src/params/network_params.rs @@ -42,6 +42,7 @@ pub struct NetworkParams { pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. + /// /// Also disables automatic peer discovery. /// TCP connections might still be established with non-reserved nodes. /// In particular, if you are a validator your node might still connect to other @@ -50,7 +51,8 @@ pub struct NetworkParams { #[arg(long)] pub reserved_only: bool, - /// The public address that other nodes will use to connect to it. + /// Public address that other nodes will use to connect to this node. + /// /// This can be used if there's a proxy in front of this node. #[arg(long, value_name = "PUBLIC_ADDR", num_args = 1..)] pub public_addr: Vec, @@ -67,20 +69,28 @@ pub struct NetworkParams { #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])] pub port: Option, - /// Always forbid connecting to private IPv4/IPv6 addresses (as specified in - /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with - /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in - /// their chain specifications. + /// Always forbid connecting to private IPv4/IPv6 addresses. + /// + /// The option doesn't apply to addresses passed with `--reserved-nodes` or + /// `--bootnodes`. Enabled by default for chains marked as "live" in their chain + /// specifications. + /// + /// Address allocation for private networks is specified by + /// [RFC1918](https://tools.ietf.org/html/rfc1918)). #[arg(long, alias = "no-private-ipv4", conflicts_with_all = &["allow_private_ip"])] pub no_private_ip: bool, - /// Always accept connecting to private IPv4/IPv6 addresses (as specified in - /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Enabled by default for chains marked as - /// "local" in their chain specifications, or when `--dev` is passed. + /// Always accept connecting to private IPv4/IPv6 addresses. + /// + /// Enabled by default for chains marked as "local" in their chain specifications, + /// or when `--dev` is passed. + /// + /// Address allocation for private networks is specified by + /// [RFC1918](https://tools.ietf.org/html/rfc1918)). #[arg(long, alias = "allow-private-ipv4", conflicts_with_all = &["no_private_ip"])] pub allow_private_ip: bool, - /// Specify the number of outgoing connections we're trying to maintain. + /// Number of outgoing connections we're trying to maintain. #[arg(long, value_name = "COUNT", default_value_t = 8)] pub out_peers: u32, @@ -92,15 +102,17 @@ pub struct NetworkParams { #[arg(long, value_name = "COUNT", default_value_t = 100)] pub in_peers_light: u32, - /// Disable mDNS discovery. + /// Disable mDNS discovery (default: true). + /// /// By default, the network will use mDNS to discover other nodes on the /// local network. This disables it. Automatically implied when using --dev. #[arg(long)] pub no_mdns: bool, /// Maximum number of peers from which to ask for the same blocks in parallel. - /// This allows downloading announced blocks from multiple peers. Decrease to save - /// traffic and risk increased latency. + /// + /// This allows downloading announced blocks from multiple peers. + /// Decrease to save traffic and risk increased latency. #[arg(long, value_name = "COUNT", default_value_t = 5)] pub max_parallel_downloads: u32, @@ -109,19 +121,24 @@ pub struct NetworkParams { pub node_key_params: NodeKeyParams, /// Enable peer discovery on local networks. + /// /// By default this option is `true` for `--dev` or when the chain type is /// `Local`/`Development` and false otherwise. #[arg(long)] pub discover_local: bool, - /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in - /// the presence of potentially adversarial nodes. + /// Require iterative Kademlia DHT queries to use disjoint paths. + /// + /// Disjoint paths increase resiliency in the presence of potentially adversarial nodes. + /// /// See the S/Kademlia paper for more information on the high level design as well as its /// security improvements. #[arg(long)] pub kademlia_disjoint_query_paths: bool, - /// Kademlia replication factor determines to how many closest peers a record is replicated to. + /// Kademlia replication factor. + /// + /// Determines to how many closest peers a record is replicated to. /// /// Discovery mechanism requires successful replication to all /// `kademlia_replication_factor` peers to consider record successfully put. diff --git a/substrate/client/cli/src/params/node_key_params.rs b/substrate/client/cli/src/params/node_key_params.rs index 8c5579eaec4..53f19f58e1f 100644 --- a/substrate/client/cli/src/params/node_key_params.rs +++ b/substrate/client/cli/src/params/node_key_params.rs @@ -32,39 +32,49 @@ const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; /// used for libp2p networking. #[derive(Debug, Clone, Args)] pub struct NodeKeyParams { - /// The secret key to use for libp2p networking. + /// Secret key to use for p2p networking. + /// /// The value is a string that is parsed according to the choice of /// `--node-key-type` as follows: - /// `ed25519`: - /// The value is parsed as a hex-encoded Ed25519 32 byte secret key, - /// i.e. 64 hex characters. + /// + /// - `ed25519`: the value is parsed as a hex-encoded Ed25519 32 byte secret key (64 hex + /// chars) + /// /// The value of this option takes precedence over `--node-key-file`. + /// /// WARNING: Secrets provided as command-line arguments are easily exposed. /// Use of this option should be limited to development and testing. To use /// an externally managed secret key, use `--node-key-file` instead. #[arg(long, value_name = "KEY")] pub node_key: Option, - /// The type of secret key to use for libp2p networking. + /// Crypto primitive to use for p2p networking. + /// /// The secret key of the node is obtained as follows: - /// * If the `--node-key` option is given, the value is parsed as a secret key according to - /// the type. See the documentation for `--node-key`. - /// * If the `--node-key-file` option is given, the secret key is read from the specified - /// file. See the documentation for `--node-key-file`. - /// * Otherwise, the secret key is read from a file with a predetermined, type-specific name - /// from the chain-specific network config directory inside the base directory specified by - /// `--base-dir`. If this file does not exist, it is created with a newly generated secret - /// key of the chosen type. + /// + /// - If the `--node-key` option is given, the value is parsed as a secret key according to the + /// type. See the documentation for `--node-key`. + /// + /// - If the `--node-key-file` option is given, the secret key is read from the specified file. + /// See the documentation for `--node-key-file`. + /// + /// - Otherwise, the secret key is read from a file with a predetermined, type-specific name + /// from the chain-specific network config directory inside the base directory specified by + /// `--base-dir`. If this file does not exist, it is created with a newly generated secret + /// key of the chosen type. + /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. #[arg(long, value_name = "TYPE", value_enum, ignore_case = true, default_value_t = NodeKeyType::Ed25519)] pub node_key_type: NodeKeyType, - /// The file from which to read the node's secret key to use for libp2p networking. + /// File from which to read the node's secret key to use for p2p networking. + /// /// The contents of the file are parsed according to the choice of `--node-key-type` /// as follows: - /// `ed25519`: - /// The file must contain an unencoded 32 byte or hex encoded Ed25519 secret key. + /// + /// - `ed25519`: the file must contain an unencoded 32 byte or hex encoded Ed25519 secret key. + /// /// If the file does not exist, it is created with a newly generated secret key of /// the chosen type. #[arg(long, value_name = "FILE")] diff --git a/substrate/client/cli/src/params/offchain_worker_params.rs b/substrate/client/cli/src/params/offchain_worker_params.rs index d1fedab4cb2..3583d85c00a 100644 --- a/substrate/client/cli/src/params/offchain_worker_params.rs +++ b/substrate/client/cli/src/params/offchain_worker_params.rs @@ -32,8 +32,7 @@ use crate::{error, OffchainWorkerEnabled}; /// Offchain worker related parameters. #[derive(Debug, Clone, Args)] pub struct OffchainWorkerParams { - /// Should execute offchain workers on every block. - /// By default it's only enabled for nodes that are authoring new blocks. + /// Execute offchain workers on every block. #[arg( long = "offchain-worker", value_name = "ENABLED", @@ -43,8 +42,9 @@ pub struct OffchainWorkerParams { )] pub enabled: OffchainWorkerEnabled, - /// Enable Offchain Indexing API, which allows block import to write to Offchain DB. - /// Enables a runtime to write directly to a offchain workers DB during block import. + /// Enable offchain indexing API. + /// + /// Allows the runtime to write directly to offchain workers DB during block import. #[arg(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING", default_value_t = false, action = ArgAction::Set)] pub indexing_enabled: bool, } diff --git a/substrate/client/cli/src/params/prometheus_params.rs b/substrate/client/cli/src/params/prometheus_params.rs index 4d234ea33c2..69199ad5b26 100644 --- a/substrate/client/cli/src/params/prometheus_params.rs +++ b/substrate/client/cli/src/params/prometheus_params.rs @@ -27,10 +27,12 @@ pub struct PrometheusParams { #[arg(long, value_name = "PORT")] pub prometheus_port: Option, /// Expose Prometheus exporter on all interfaces. + /// /// Default is local. #[arg(long)] pub prometheus_external: bool, /// Do not expose a Prometheus exporter endpoint. + /// /// Prometheus metric endpoint is enabled by default. #[arg(long)] pub no_prometheus: bool, diff --git a/substrate/client/cli/src/params/pruning_params.rs b/substrate/client/cli/src/params/pruning_params.rs index 1b5bf247d94..25b17b53289 100644 --- a/substrate/client/cli/src/params/pruning_params.rs +++ b/substrate/client/cli/src/params/pruning_params.rs @@ -24,6 +24,7 @@ use sc_service::{BlocksPruning, PruningMode}; #[derive(Debug, Clone, Args)] pub struct PruningParams { /// Specify the state pruning mode. + /// /// This mode specifies when the block's state (ie, storage) /// should be pruned (ie, removed) from the database. /// This setting can only be set on the first creation of the database. Every subsequent run @@ -38,6 +39,7 @@ pub struct PruningParams { pub state_pruning: Option, /// Specify the blocks pruning mode. + /// /// This mode specifies when the block's body (including justifications) /// should be pruned (ie, removed) from the database. /// Possible values: diff --git a/substrate/client/cli/src/params/runtime_params.rs b/substrate/client/cli/src/params/runtime_params.rs index 07009a96ee6..a130d808418 100644 --- a/substrate/client/cli/src/params/runtime_params.rs +++ b/substrate/client/cli/src/params/runtime_params.rs @@ -22,7 +22,9 @@ use std::str::FromStr; /// Parameters used to config runtime. #[derive(Debug, Clone, Args)] pub struct RuntimeParams { - /// The size of the instances cache for each runtime. The values higher than 32 are illegal. + /// The size of the instances cache for each runtime [max: 32]. + /// + /// Values higher than 32 are illegal. #[arg(long, default_value_t = 8, value_parser = parse_max_runtime_instances)] pub max_runtime_instances: usize, diff --git a/substrate/client/cli/src/params/shared_params.rs b/substrate/client/cli/src/params/shared_params.rs index 3d20ca504a6..6419e15c62a 100644 --- a/substrate/client/cli/src/params/shared_params.rs +++ b/substrate/client/cli/src/params/shared_params.rs @@ -25,12 +25,14 @@ use std::path::PathBuf; #[derive(Debug, Clone, Args)] pub struct SharedParams { /// Specify the chain specification. - /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to a file - /// with the chainspec (such as one exported by the `build-spec` subcommand). + /// + /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to + /// a file with the chainspec (such as one exported by the `build-spec` subcommand). #[arg(long, value_name = "CHAIN_SPEC")] pub chain: Option, /// Specify the development chain. + /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. #[arg(long, conflicts_with_all = &["chain"])] @@ -40,14 +42,23 @@ pub struct SharedParams { #[arg(long, short = 'd', value_name = "PATH")] pub base_path: Option, - /// Sets a custom logging filter. Syntax is `=`, e.g. -lsync=debug. - /// Log levels (least to most verbose) are error, warn, info, debug, and trace. + /// Sets a custom logging filter (syntax: `=`). + /// + /// Log levels (least to most verbose) are `error`, `warn`, `info`, `debug`, and `trace`. + /// /// By default, all targets log `info`. The global log level can be set with `-l`. + /// + /// Multiple `=` entries can be specified and separated by a comma. + /// + /// *Example*: `--log error,sync=debug,grandpa=warn`. + /// Sets Global log level to `error`, sets `sync` target to debug and grandpa target to `warn`. #[arg(short = 'l', long, value_name = "LOG_PATTERN", num_args = 1..)] pub log: Vec, /// Enable detailed log output. - /// This includes displaying the log target, log level and thread name. + /// + /// Includes displaying the log target, log level and thread name. + /// /// This is automatically enabled when something is logged with any higher level than `info`. #[arg(long)] pub detailed_log_output: bool, @@ -57,14 +68,18 @@ pub struct SharedParams { pub disable_log_color: bool, /// Enable feature to dynamically update and reload the log filter. + /// /// Be aware that enabling this feature can lead to a performance decrease up to factor six or /// more. Depending on the global logging level the performance decrease changes. + /// /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this /// option not being set. #[arg(long)] pub enable_log_reloading: bool, - /// Sets a custom profiling filter. Syntax is the same as for logging: `=`. + /// Sets a custom profiling filter. + /// + /// Syntax is the same as for logging (`--log`). #[arg(long, value_name = "TARGETS")] pub tracing_targets: Option, diff --git a/substrate/client/cli/src/params/telemetry_params.rs b/substrate/client/cli/src/params/telemetry_params.rs index 67f44107141..3b3d91e6b04 100644 --- a/substrate/client/cli/src/params/telemetry_params.rs +++ b/substrate/client/cli/src/params/telemetry_params.rs @@ -22,14 +22,17 @@ use clap::Args; #[derive(Debug, Clone, Args)] pub struct TelemetryParams { /// Disable connecting to the Substrate telemetry server. + /// /// Telemetry is on by default on global chains. #[arg(long)] pub no_telemetry: bool, /// The URL of the telemetry server to connect to. + /// /// This flag can be passed multiple times as a means to specify multiple /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. + /// /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. #[arg(long = "telemetry-url", value_name = "URL VERBOSITY", value_parser = parse_telemetry_endpoints)] pub telemetry_endpoints: Vec<(String, u8)>, diff --git a/substrate/client/cli/src/params/transaction_pool_params.rs b/substrate/client/cli/src/params/transaction_pool_params.rs index b2bf0b9b364..48b2e5b1572 100644 --- a/substrate/client/cli/src/params/transaction_pool_params.rs +++ b/substrate/client/cli/src/params/transaction_pool_params.rs @@ -30,7 +30,9 @@ pub struct TransactionPoolParams { #[arg(long, value_name = "COUNT", default_value_t = 20480)] pub pool_kbytes: usize, - /// How long a transaction is banned for, if it is considered invalid. Defaults to 1800s. + /// How long a transaction is banned for. + /// + /// If it is considered invalid. Defaults to 1800s. #[arg(long, value_name = "SECONDS")] pub tx_ban_seconds: Option, } diff --git a/substrate/client/storage-monitor/src/lib.rs b/substrate/client/storage-monitor/src/lib.rs index 655b940e8be..b88b66d2d60 100644 --- a/substrate/client/storage-monitor/src/lib.rs +++ b/substrate/client/storage-monitor/src/lib.rs @@ -42,9 +42,12 @@ pub enum Error { /// Parameters used to create the storage monitor. #[derive(Default, Debug, Clone, Args)] pub struct StorageMonitorParams { - /// Required available space on database storage. If available space for DB storage drops below - /// the given threshold, node will be gracefully terminated. If `0` is given monitoring will be - /// disabled. + /// Required available space on database storage. + /// + /// If available space for DB storage drops below the given threshold, node will + /// be gracefully terminated. + /// + /// If `0` is given monitoring will be disabled. #[arg(long = "db-storage-threshold", value_name = "MiB", default_value_t = 1024)] pub threshold: u64, -- GitLab From d715caa63a9dbb1b491ea3cd0a909208424abbab Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Mon, 30 Oct 2023 19:43:32 +1100 Subject: [PATCH 387/633] Improve `try-state` developer experience & fix bug (#2019) Making some devex improvements as I audit our chains adherence to try-state invariants, in preparation for automated try-state checks and alerting. Note to reviewer: while you're here, if you have time would be great to get your eyes on https://github.com/paritytech/polkadot-sdk/pull/1297 also since it touches a similar file and I'd like to avoid merge conflicts :P ## Devex Improvements - Changes the log level of logs informing the user that try-state checks are being run for a pallet from debug to info - Improves how errors are communicated - Errors are logged when they are encountered, rather than after everything has been executed - Exact pallet the error originated from is included with the error log - Clearly see all errors and how many there are, rather than only one - Closes #136 ### Example of new logs Screenshot 2023-10-25 at 15 44 44 ### Same but with old logs (run with RUST_LOG=debug) Notice only informed of one of the errors, and it's unclear which pallet it originated Screenshot 2023-10-25 at 15 39 01 ## Bug fix When dry-running migrations and `checks.try_state()` is `true`, only run `try_state` checks after migrations have been executed. Otherwise, `try_state` checks that expect state to be in at a HIGHER storage version than is on-chain could incorrectly fail. --------- Co-authored-by: command-bot <> --- substrate/frame/executive/src/lib.rs | 15 ++------ .../procedural/src/pallet/expand/hooks.rs | 36 +++++++++++-------- .../frame/support/src/traits/try_runtime.rs | 24 +++++++++++-- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index a4b12c6d31d..1ca9629fd42 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -349,23 +349,12 @@ where Ok(frame_system::Pallet::::block_weight().total()) } - /// Execute all `OnRuntimeUpgrade` of this runtime, including the pre and post migration checks. + /// Execute all `OnRuntimeUpgrade` of this runtime. /// - /// Runs the try-state code both before and after the migration function if `checks` is set to - /// `true`. Also, if set to `true`, it runs the `pre_upgrade` and `post_upgrade` hooks. + /// The `checks` param determines whether to execute `pre/post_upgrade` and `try_state` hooks. pub fn try_runtime_upgrade( checks: frame_try_runtime::UpgradeCheckSelect, ) -> Result { - if checks.try_state() { - let _guard = frame_support::StorageNoopGuard::default(); - , - >>::try_state( - frame_system::Pallet::::block_number(), - frame_try_runtime::TryStateSelect::All, - )?; - } - let weight = <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( checks.pre_and_post(), diff --git a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs index 2825756f270..aaad4dd2be0 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs @@ -58,19 +58,6 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } }; - let log_try_state = quote::quote! { - let pallet_name = < - ::PalletInfo - as - #frame_support::traits::PalletInfo - >::name::().expect("No name found for the pallet! This usually means that the pallet wasn't added to `construct_runtime!`."); - #frame_support::__private::log::debug!( - target: #frame_support::LOG_TARGET, - "🩺 try-state pallet {:?}", - pallet_name, - ); - }; - let hooks_impl = if def.hooks.is_none() { let frame_system = &def.frame_system; quote::quote! { @@ -271,12 +258,31 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { n: #frame_system::pallet_prelude::BlockNumberFor::, _s: #frame_support::traits::TryStateSelect ) -> Result<(), #frame_support::sp_runtime::TryRuntimeError> { - #log_try_state + let pallet_name = < + ::PalletInfo + as + #frame_support::traits::PalletInfo + >::name::().expect("No name found for the pallet! This usually means that the pallet wasn't added to `construct_runtime!`."); + + #frame_support::__private::log::info!( + target: #frame_support::LOG_TARGET, + "🩺 Running {:?} try-state checks", + pallet_name, + ); < Self as #frame_support::traits::Hooks< #frame_system::pallet_prelude::BlockNumberFor:: > - >::try_state(n) + >::try_state(n).map_err(|err| { + #frame_support::__private::log::error!( + target: #frame_support::LOG_TARGET, + "❌ {:?} try_state checks failed: {:?}", + pallet_name, + err + ); + + err + }) } } ) diff --git a/substrate/frame/support/src/traits/try_runtime.rs b/substrate/frame/support/src/traits/try_runtime.rs index 31aebeeb4d9..e7a1fe109fc 100644 --- a/substrate/frame/support/src/traits/try_runtime.rs +++ b/substrate/frame/support/src/traits/try_runtime.rs @@ -144,9 +144,27 @@ impl TryState Ok(()), Select::All => { - let mut result = Ok(()); - for_tuples!( #( result = result.and(Tuple::try_state(n.clone(), targets.clone())); )* ); - result + let mut error_count = 0; + for_tuples!(#( + if let Err(_) = Tuple::try_state(n.clone(), targets.clone()) { + error_count += 1; + } + )*); + + if error_count > 0 { + log::error!( + target: "try-runtime", + "{} pallets exited with errors while executing try_state checks.", + error_count + ); + + return Err( + "Detected errors while executing try_state checks. See logs for more info." + .into(), + ) + } + + Ok(()) }, Select::RoundRobin(len) => { let functions: &[fn(BlockNumber, Select) -> Result<(), TryRuntimeError>] = -- GitLab From 0aeab381380107a6462fea240181f6e2a78f21b8 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Mon, 30 Oct 2023 19:48:30 +1100 Subject: [PATCH 388/633] Stop `Balances` pallet erroneously double incrementing and decrementing consumers (#1976) Closes https://github.com/paritytech/polkadot-sdk/issues/1970 Follow up issue to tackle, once the erroneous double incrementing/decrementing has stopped: https://github.com/paritytech/polkadot-sdk/issues/2037 --- substrate/frame/balances/src/lib.rs | 27 ++++--------------- .../balances/src/tests/currency_tests.rs | 24 ++++++++++++++++- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index c6a2252df61..d518f933df8 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -935,8 +935,8 @@ pub mod pallet { if did_provide && !does_provide { // This could reap the account so must go last. frame_system::Pallet::::dec_providers(who).map_err(|r| { + // best-effort revert consumer change. if did_consume && !does_consume { - // best-effort revert consumer change. let _ = frame_system::Pallet::::inc_consumers(who).defensive(); } if !did_consume && does_consume { @@ -1006,8 +1006,8 @@ pub mod pallet { let freezes = Freezes::::get(who); let mut prev_frozen = Zero::zero(); let mut after_frozen = Zero::zero(); - // TODO: Revisit this assumption. We no manipulate consumer/provider refs. // No way this can fail since we do not alter the existential balances. + // TODO: Revisit this assumption. let res = Self::mutate_account(who, |b| { prev_frozen = b.frozen; b.frozen = Zero::zero(); @@ -1024,26 +1024,9 @@ pub mod pallet { debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed"); } - let existed = Locks::::contains_key(who); - if locks.is_empty() { - Locks::::remove(who); - if existed { - // TODO: use Locks::::hashed_key - // https://github.com/paritytech/substrate/issues/4969 - system::Pallet::::dec_consumers(who); - } - } else { - Locks::::insert(who, bounded_locks); - if !existed && system::Pallet::::inc_consumers_without_limit(who).is_err() { - // No providers for the locks. This is impossible under normal circumstances - // since the funds that are under the lock will themselves be stored in the - // account and therefore will need a reference. - log::warn!( - target: LOG_TARGET, - "Warning: Attempt to introduce lock consumer reference, yet no providers. \ - This is unexpected but should be safe." - ); - } + match locks.is_empty() { + true => Locks::::remove(who), + false => Locks::::insert(who, bounded_locks), } if prev_frozen > after_frozen { diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 2449638788d..200df9ae743 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -144,7 +144,9 @@ fn lock_removal_should_work() { .monied(true) .build_and_execute_with(|| { Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); Balances::remove_lock(ID_1, &1); + assert_eq!(System::consumers(&1), 0); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -156,7 +158,9 @@ fn lock_replacement_should_work() { .monied(true) .build_and_execute_with(|| { Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -168,7 +172,9 @@ fn double_locking_should_work() { .monied(true) .build_and_execute_with(|| { Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); Balances::set_lock(ID_2, &1, 5, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -179,8 +185,11 @@ fn combination_locking_should_work() { .existential_deposit(1) .monied(true) .build_and_execute_with(|| { + assert_eq!(System::consumers(&1), 0); Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::empty()); + assert_eq!(System::consumers(&1), 0); Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 0); assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); }); } @@ -192,16 +201,19 @@ fn lock_value_extension_should_work() { .monied(true) .build_and_execute_with(|| { Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), TokenError::Frozen ); Balances::extend_lock(ID_1, &1, 2, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); assert_noop!( >::transfer(&1, &2, 6, AllowDeath), TokenError::Frozen ); Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 1); assert_noop!( >::transfer(&1, &2, 3, AllowDeath), TokenError::Frozen @@ -1324,9 +1336,14 @@ fn freezing_and_locking_should_work() { .existential_deposit(1) .monied(true) .build_and_execute_with(|| { + // Consumer is shared between freezing and locking. + assert_eq!(System::consumers(&1), 0); assert_ok!(>::set_freeze(&TestId::Foo, &1, 4)); + assert_eq!(System::consumers(&1), 1); Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); - assert_eq!(System::consumers(&1), 2); + assert_eq!(System::consumers(&1), 1); + + // Frozen and locked balances update correctly. assert_eq!(Balances::account(&1).frozen, 5); assert_ok!(>::set_freeze(&TestId::Foo, &1, 6)); assert_eq!(Balances::account(&1).frozen, 6); @@ -1336,8 +1353,13 @@ fn freezing_and_locking_should_work() { assert_eq!(Balances::account(&1).frozen, 4); Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); assert_eq!(Balances::account(&1).frozen, 5); + + // Locks update correctly. Balances::remove_lock(ID_1, &1); assert_eq!(Balances::account(&1).frozen, 4); assert_eq!(System::consumers(&1), 1); + assert_ok!(>::set_freeze(&TestId::Foo, &1, 0)); + assert_eq!(Balances::account(&1).frozen, 0); + assert_eq!(System::consumers(&1), 0); }); } -- GitLab From ad5163ba93a7e142fd6fb2b9ed975bff9c29c479 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Mon, 30 Oct 2023 21:55:05 +1100 Subject: [PATCH 389/633] contracts migration: remove unnecessary panics (#2079) Runtime migration CI is currently failing (https://gitlab.parity.io/parity/mirrors/polkadot-sdk/builds/4122083) for the contracts testnet due to unnecessary panicing in a `pre_upgrade` hook. Soon idempotency will be enforced https://github.com/paritytech/try-runtime-cli/issues/42, in the mean time we need to manually fix these issues as they arise. --- also removes backticks from the string in `echo`, which caused a 'command not found' error in ci output --- .gitlab/pipeline/check.yml | 2 +- substrate/frame/contracts/src/migration.rs | 37 +++++++++++----------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index cd26003d88c..ce3a6155792 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -107,7 +107,7 @@ check-rust-feature-propagation: echo "---------- Building ${PACKAGE} runtime ----------" time cargo build --release --locked -p "$PACKAGE" --features try-runtime - echo "---------- Executing `on-runtime-upgrade` for ${NETWORK} ----------" + echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" time ./try-runtime \ --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ on-runtime-upgrade --checks=pre-and-post ${EXTRA_ARGS} live --uri ${URI} diff --git a/substrate/frame/contracts/src/migration.rs b/substrate/frame/contracts/src/migration.rs index 27146207312..1873ef2765b 100644 --- a/substrate/frame/contracts/src/migration.rs +++ b/substrate/frame/contracts/src/migration.rs @@ -263,14 +263,14 @@ impl Migration { impl OnRuntimeUpgrade for Migration { fn on_runtime_upgrade() -> Weight { let name = >::name(); - let latest_version = >::current_storage_version(); - let storage_version = >::on_chain_storage_version(); + let current_version = >::current_storage_version(); + let on_chain_version = >::on_chain_storage_version(); - if storage_version == latest_version { + if on_chain_version == current_version { log::warn!( target: LOG_TARGET, "{name}: No Migration performed storage_version = latest_version = {:?}", - &storage_version + &on_chain_version ); return T::WeightInfo::on_runtime_upgrade_noop() } @@ -281,7 +281,7 @@ impl OnRuntimeUpgrade for Migration OnRuntimeUpgrade for Migration::set(Some(cursor)); #[cfg(feature = "try-runtime")] @@ -308,24 +308,25 @@ impl OnRuntimeUpgrade for Migration>::on_chain_storage_version(); - let target_version = >::current_storage_version(); + let on_chain_version = >::on_chain_storage_version(); + let current_version = >::current_storage_version(); - ensure!( - storage_version != target_version, - "No upgrade: Please remove this migration from your runtime upgrade configuration." - ); + if on_chain_version == current_version { + log::warn!( + target: LOG_TARGET, + "No upgrade: Please remove this migration from your Migrations tuple" + ) + } log::debug!( target: LOG_TARGET, "Requested migration of {} from {:?}(on-chain storage version) to {:?}(current storage version)", - >::name(), storage_version, target_version + >::name(), on_chain_version, current_version ); - ensure!( - T::Migrations::is_upgrade_supported(storage_version, target_version), - "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)" - ); + if !T::Migrations::is_upgrade_supported(on_chain_version, current_version) { + log::warn!(target: LOG_TARGET, "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)") + } Ok(Default::default()) } -- GitLab From 30f3ad2eefce06fc3a1a063b57af22e9d75bb903 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 30 Oct 2023 15:15:36 +0200 Subject: [PATCH 390/633] Refactor transaction storage pallet to use fungible traits (#1800) Partial https://github.com/paritytech/polkadot-sdk/issues/226 `frame/transaction-storage`: replace `Currency` with `fungible::*` traits --------- Signed-off-by: Adrian Catangiu Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> --- substrate/bin/node/runtime/src/lib.rs | 3 +- .../transaction-storage/src/benchmarking.rs | 16 +++--- .../frame/transaction-storage/src/lib.rs | 40 +++++++++----- .../frame/transaction-storage/src/mock.rs | 52 +++++-------------- .../frame/transaction-storage/src/tests.rs | 3 +- 5 files changed, 54 insertions(+), 60 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a2d100e1f8b..f3c24897632 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -526,7 +526,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; - type MaxHolds = ConstU32<5>; + type MaxHolds = ConstU32<6>; } parameter_types! { @@ -1833,6 +1833,7 @@ impl pallet_nfts::Config for Runtime { impl pallet_transaction_storage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; type RuntimeCall = RuntimeCall; type FeeDestination = (); type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; diff --git a/substrate/frame/transaction-storage/src/benchmarking.rs b/substrate/frame/transaction-storage/src/benchmarking.rs index fdbaeb1f951..8d485d9f3ca 100644 --- a/substrate/frame/transaction-storage/src/benchmarking.rs +++ b/substrate/frame/transaction-storage/src/benchmarking.rs @@ -21,9 +21,9 @@ use super::*; use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; -use frame_support::traits::{Currency, Get, OnFinalize, OnInitialize}; +use frame_support::traits::{Get, OnFinalize, OnInitialize}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, Pallet as System, RawOrigin}; -use sp_runtime::traits::{Bounded, One, Zero}; +use sp_runtime::traits::{Bounded, CheckedDiv, One, Zero}; use sp_std::*; use sp_transaction_storage_proof::TransactionStorageProof; @@ -103,9 +103,6 @@ fn proof() -> Vec { array_bytes::hex2bytes_unchecked(PROOF) } -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - fn assert_last_event(generic_event: ::RuntimeEvent) { let events = System::::events(); let system_event: ::RuntimeEvent = generic_event.into(); @@ -129,7 +126,8 @@ benchmarks! { store { let l in 1 .. T::MaxTransactionSize::get(); let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); + T::Currency::set_balance(&caller, initial_balance); }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) verify { assert!(!BlockTransactions::::get().is_empty()); @@ -138,7 +136,8 @@ benchmarks! { renew { let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); + T::Currency::set_balance(&caller, initial_balance); TransactionStorage::::store( RawOrigin::Signed(caller.clone()).into(), vec![0u8; T::MaxTransactionSize::get() as usize], @@ -152,7 +151,8 @@ benchmarks! { check_proof_max { run_to_block::(1u32.into()); let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); + T::Currency::set_balance(&caller, initial_balance); for _ in 0 .. T::MaxBlockTransactions::get() { TransactionStorage::::store( RawOrigin::Signed(caller.clone()).into(), diff --git a/substrate/frame/transaction-storage/src/lib.rs b/substrate/frame/transaction-storage/src/lib.rs index 753f5ca0c7b..fb8ada0f5f9 100644 --- a/substrate/frame/transaction-storage/src/lib.rs +++ b/substrate/frame/transaction-storage/src/lib.rs @@ -31,7 +31,14 @@ mod tests; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::GetDispatchInfo, - traits::{Currency, OnUnbalanced, ReservableCurrency}, + traits::{ + fungible::{ + hold::Balanced as FnBalanced, Inspect as FnInspect, Mutate as FnMutate, + MutateHold as FnMutateHold, + }, + tokens::fungible::Credit, + OnUnbalanced, + }, }; use sp_runtime::traits::{BlakeTwo256, Dispatchable, Hash, One, Saturating, Zero}; use sp_std::{prelude::*, result}; @@ -42,10 +49,8 @@ use sp_transaction_storage_proof::{ /// A type alias for the balance type from this pallet's point of view. type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; + <::Currency as FnInspect<::AccountId>>::Balance; +pub type CreditOf = Credit<::AccountId, ::Currency>; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -89,6 +94,13 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// A reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The funds are held as deposit for the used storage. + StorageFeeHold, + } + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. @@ -98,10 +110,14 @@ pub mod pallet { + Dispatchable + GetDispatchInfo + From>; - /// The currency trait. - type Currency: ReservableCurrency; + /// The fungible type for this pallet. + type Currency: FnMutate + + FnMutateHold + + FnBalanced; + /// The overarching runtime hold reason. + type RuntimeHoldReason: From; /// Handler for the unbalanced decrease when fees are burned. - type FeeDestination: OnUnbalanced>; + type FeeDestination: OnUnbalanced>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// Maximum number of indexed transactions in the block. @@ -112,8 +128,6 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// Insufficient account balance. - InsufficientFunds, /// Invalid configuration. NotConfigured, /// Renewed extrinsic is not found. @@ -432,8 +446,10 @@ pub mod pallet { let byte_fee = ByteFee::::get().ok_or(Error::::NotConfigured)?; let entry_fee = EntryFee::::get().ok_or(Error::::NotConfigured)?; let fee = byte_fee.saturating_mul(size.into()).saturating_add(entry_fee); - ensure!(T::Currency::can_slash(&sender, fee), Error::::InsufficientFunds); - let (credit, _) = T::Currency::slash(&sender, fee); + T::Currency::hold(&HoldReason::StorageFeeHold.into(), &sender, fee)?; + let (credit, _remainder) = + T::Currency::slash(&HoldReason::StorageFeeHold.into(), &sender, fee); + debug_assert!(_remainder.is_zero()); T::FeeDestination::on_unbalanced(credit); Ok(()) } diff --git a/substrate/frame/transaction-storage/src/mock.rs b/substrate/frame/transaction-storage/src/mock.rs index 947c81c12ac..a8da19a382d 100644 --- a/substrate/frame/transaction-storage/src/mock.rs +++ b/substrate/frame/transaction-storage/src/mock.rs @@ -21,12 +21,11 @@ use crate::{ self as pallet_transaction_storage, TransactionStorageProof, DEFAULT_MAX_BLOCK_TRANSACTIONS, DEFAULT_MAX_TRANSACTION_SIZE, }; -use frame_support::traits::{ConstU16, ConstU32, ConstU64, OnFinalize, OnInitialize}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, +use frame_support::{ + derive_impl, + traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, }; +use sp_runtime::{traits::IdentityLookup, BuildStorage}; pub type Block = frame_system::mocking::MockBlock; @@ -37,58 +36,35 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, TransactionStorage: pallet_transaction_storage::{ - Pallet, Call, Storage, Config, Inherent, Event + Pallet, Call, Storage, Config, Inherent, Event, HoldReason }, } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; + type AccountId = u64; + type BlockHashCount = ConstU64<250>; + type Lookup = IdentityLookup; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for Test { type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = (); - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); - type MaxHolds = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type MaxHolds = ConstU32<128>; } impl pallet_transaction_storage::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; type FeeDestination = (); type WeightInfo = (); type MaxBlockTransactions = ConstU32<{ DEFAULT_MAX_BLOCK_TRANSACTIONS }>; diff --git a/substrate/frame/transaction-storage/src/tests.rs b/substrate/frame/transaction-storage/src/tests.rs index 43dfed81f88..e17b3ca3beb 100644 --- a/substrate/frame/transaction-storage/src/tests.rs +++ b/substrate/frame/transaction-storage/src/tests.rs @@ -21,6 +21,7 @@ use super::{Pallet as TransactionStorage, *}; use crate::mock::*; use frame_support::{assert_noop, assert_ok}; use frame_system::RawOrigin; +use sp_runtime::{DispatchError, TokenError::FundsUnavailable}; use sp_transaction_storage_proof::registration::build_proof; const MAX_DATA_SIZE: u32 = DEFAULT_MAX_TRANSACTION_SIZE; @@ -71,7 +72,7 @@ fn burns_fee() { RawOrigin::Signed(5).into(), vec![0u8; 2000 as usize] ), - Error::::InsufficientFunds, + DispatchError::Token(FundsUnavailable), ); assert_ok!(TransactionStorage::::store( RawOrigin::Signed(caller).into(), -- GitLab From a69da4a85f73e54a21b9cc80526d8222e234311c Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:03:30 +0100 Subject: [PATCH 391/633] Switch from `tiny-bip39` to `bip39` crate (#2084) Switch from: https://crates.io/crates/tiny-bip39 to: https://crates.io/crates/bip39 Required for: https://github.com/paritytech/polkadot-sdk/pull/2044 --- Cargo.lock | 38 ++++--------------- substrate/client/cli/Cargo.toml | 3 +- substrate/client/cli/src/commands/generate.rs | 23 ++++++----- substrate/primitives/core/Cargo.toml | 7 +++- substrate/primitives/core/src/crypto.rs | 16 +++++--- 5 files changed, 38 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1183f9204a2..c95cc70b0da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,6 +1377,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", + "rand 0.7.3", + "rand_core 0.5.1", + "serde", + "unicode-normalization", ] [[package]] @@ -11407,15 +11411,6 @@ dependencies = [ "crypto-mac 0.11.1", ] -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "pbkdf2" version = "0.12.2" @@ -14732,11 +14727,13 @@ name = "sc-cli" version = "0.10.0-dev" dependencies = [ "array-bytes 6.1.0", + "bip39", "chrono", "clap 4.4.6", "fdlimit", "futures", "futures-timer", + "itertools 0.10.5", "libp2p-identity", "log", "names 0.13.0", @@ -14765,7 +14762,6 @@ dependencies = [ "sp-version", "tempfile", "thiserror", - "tiny-bip39", "tokio", ] @@ -17076,6 +17072,7 @@ version = "21.0.0" dependencies = [ "array-bytes 6.1.0", "bandersnatch_vrfs", + "bip39", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -17087,6 +17084,7 @@ dependencies = [ "hash-db", "hash256-std-hasher", "impl-serde", + "itertools 0.10.5", "lazy_static", "libsecp256k1", "log", @@ -17113,7 +17111,6 @@ dependencies = [ "ss58-registry", "substrate-bip39", "thiserror", - "tiny-bip39", "tracing", "w3f-bls", "zeroize", @@ -18707,25 +18704,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.11.0", - "rand 0.8.5", - "rustc-hash", - "sha2 0.10.7", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - [[package]] name = "tiny-keccak" version = "2.0.2" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index dc53ed54d96..5a98b43f43c 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -18,6 +18,7 @@ chrono = "0.4.27" clap = { version = "4.4.6", features = ["derive", "string", "wrap_help"] } fdlimit = "0.2.1" futures = "0.3.21" +itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} log = "0.4.17" names = { version = "0.13.0", default-features = false } @@ -28,7 +29,7 @@ rpassword = "7.0.0" serde = "1.0.188" serde_json = "1.0.107" thiserror = "1.0.48" -tiny-bip39 = "1.0.0" +bip39 = "2.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } sc-client-api = { path = "../api" } sc-client-db = { path = "../db", default-features = false} diff --git a/substrate/client/cli/src/commands/generate.rs b/substrate/client/cli/src/commands/generate.rs index 93b83fcbef5..c465bcc85a4 100644 --- a/substrate/client/cli/src/commands/generate.rs +++ b/substrate/client/cli/src/commands/generate.rs @@ -20,8 +20,9 @@ use crate::{ utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag, }; -use bip39::{Language, Mnemonic, MnemonicType}; +use bip39::Mnemonic; use clap::Parser; +use itertools::Itertools; /// The `generate` command #[derive(Debug, Clone, Parser)] @@ -52,20 +53,22 @@ impl GenerateCmd { /// Run the command pub fn run(&self) -> Result<(), Error> { let words = match self.words { - Some(words) => MnemonicType::for_word_count(words).map_err(|_| { - Error::Input( - "Invalid number of words given for phrase: must be 12/15/18/21/24".into(), - ) - })?, - None => MnemonicType::Words12, - }; - let mnemonic = Mnemonic::new(words, Language::English); + Some(words_count) if [12, 15, 18, 21, 24].contains(&words_count) => Ok(words_count), + Some(_) => Err(Error::Input( + "Invalid number of words given for phrase: must be 12/15/18/21/24".into(), + )), + None => Ok(12), + }?; + let mnemonic = Mnemonic::generate(words) + .map_err(|e| Error::Input(format!("Mnemonic generation failed: {e}").into()))?; let password = self.keystore_params.read_password()?; let output = self.output_scheme.output_type; + let phrase = mnemonic.word_iter().join(" "); + with_crypto_scheme!( self.crypto_scheme.scheme, - print_from_uri(mnemonic.phrase(), password, self.network_scheme.network, output) + print_from_uri(&phrase, password, self.network_scheme.network, output) ); Ok(()) } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 1b6b10eeeed..1e8a353f419 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -25,7 +25,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } -tiny-bip39 = { version = "1.0.0", optional = true } +bip39 = { version = "2.0.0", default-features = false } regex = { version = "1.6.0", optional = true } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } @@ -42,6 +42,7 @@ thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } bitflags = "1.3" paste = "1.0.7" +itertools = { version = "0.10.3", optional = true } # full crypto array-bytes = { version = "6.1", optional = true } @@ -76,6 +77,8 @@ default = [ "std" ] std = [ "array-bytes", "bandersnatch_vrfs/getrandom", + "bip39/rand", + "bip39/std", "blake2/std", "bounded-collections/std", "bs58/std", @@ -88,6 +91,7 @@ std = [ "hash-db/std", "hash256-std-hasher/std", "impl-serde/std", + "itertools", "lazy_static", "libsecp256k1/std", "log/std", @@ -114,7 +118,6 @@ std = [ "ss58-registry/std", "substrate-bip39", "thiserror", - "tiny-bip39", "tracing", "w3f-bls?/std", "zeroize/alloc", diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index f7e2c56ca9a..d369de5a1c0 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -19,9 +19,11 @@ use crate::{ed25519, sr25519}; #[cfg(feature = "std")] -use bip39::{Language, Mnemonic, MnemonicType}; +use bip39::{Language, Mnemonic}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] +use itertools::Itertools; +#[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; #[cfg(feature = "std")] use regex::Regex; @@ -870,9 +872,9 @@ pub trait Pair: CryptoType + Sized { /// the key from the current session. #[cfg(feature = "std")] fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase = mnemonic.phrase(); - let (pair, seed) = Self::from_phrase(phrase, password) + let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed"); + let phrase = mnemonic.word_iter().join(" "); + let (pair, seed) = Self::from_phrase(&phrase, password) .expect("All phrases generated by Mnemonic are valid; qed"); (pair, phrase.to_owned(), seed) } @@ -883,10 +885,12 @@ pub trait Pair: CryptoType + Sized { phrase: &str, password: Option<&str>, ) -> Result<(Self, Self::Seed), SecretStringError> { - let mnemonic = Mnemonic::from_phrase(phrase, Language::English) + let mnemonic = Mnemonic::parse_in(Language::English, phrase) .map_err(|_| SecretStringError::InvalidPhrase)?; + + let (entropy, entropy_len) = mnemonic.to_entropy_array(); let big_seed = - substrate_bip39::seed_from_entropy(mnemonic.entropy(), password.unwrap_or("")) + substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or("")) .map_err(|_| SecretStringError::InvalidSeed)?; let mut seed = Self::Seed::default(); let seed_slice = seed.as_mut(); -- GitLab From 40ff09b8fb6a9f669b9d7da3ef4cd447ec2e1c39 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 31 Oct 2023 00:05:27 +0800 Subject: [PATCH 392/633] pub `keystore_accounts/accounts_from_keys` for offchain Signer (#2051) --- substrate/frame/system/src/offchain.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/system/src/offchain.rs b/substrate/frame/system/src/offchain.rs index dd4ac6782a5..a019cfd666e 100644 --- a/substrate/frame/system/src/offchain.rs +++ b/substrate/frame/system/src/offchain.rs @@ -154,8 +154,8 @@ impl, X> Signer /// all available accounts and the provided accounts /// in `with_filter`. If no accounts are provided, /// use all accounts by default. - fn accounts_from_keys<'a>(&'a self) -> Box> + 'a> { - let keystore_accounts = self.keystore_accounts(); + pub fn accounts_from_keys<'a>(&'a self) -> Box> + 'a> { + let keystore_accounts = Self::keystore_accounts(); match self.accounts { None => Box::new(keystore_accounts), Some(ref keys) => { @@ -175,7 +175,8 @@ impl, X> Signer } } - fn keystore_accounts(&self) -> impl Iterator> { + /// Return all available accounts in keystore. + pub fn keystore_accounts() -> impl Iterator> { C::RuntimeAppPublic::all().into_iter().enumerate().map(|(index, key)| { let generic_public = C::GenericPublic::from(key); let public: T::Public = generic_public.into(); -- GitLab From 2d9426f1cc144a0624ea0329ddc7e567bb47d6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 30 Oct 2023 17:37:10 +0100 Subject: [PATCH 393/633] parachain-system: Send same event & digest as a standalone chain (#2064) This ensures that upgrading a parachain code sends the same event & digest as when using `set_code` on a standalone chain. Close: https://github.com/paritytech/polkadot-sdk/issues/2049 --- cumulus/pallets/parachain-system/src/lib.rs | 9 +-------- cumulus/pallets/parachain-system/src/tests.rs | 12 ++++++++++-- substrate/frame/system/src/lib.rs | 5 ++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 369281ccd8e..84b4cda1534 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -39,7 +39,6 @@ use frame_support::{ dispatch::{DispatchResult, Pays, PostDispatchInfo}, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, - storage, traits::Get, weights::Weight, }; @@ -598,7 +597,7 @@ pub mod pallet { ); let validation_code = >::take(); - Self::put_parachain_code(&validation_code); + frame_system::Pallet::::update_code_in_storage(&validation_code); ::on_validation_code_applied(); Self::deposit_event(Event::ValidationFunctionApplied { relay_chain_block_num: vfp.relay_parent_number, @@ -1399,12 +1398,6 @@ impl Pallet { >::put(true); } - /// Put a new validation function into a particular location where this - /// parachain will execute it on subsequent blocks. - fn put_parachain_code(code: &[u8]) { - storage::unhashed::put_raw(sp_core::storage::well_known_keys::CODE, code); - } - /// The maximum code size permitted, in bytes. /// /// Returns `None` if the relay chain parachain host configuration hasn't been submitted yet. diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 3f5b4f649e3..7db6a966ec9 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -869,7 +869,7 @@ fn hrmp_outbound_respects_used_bandwidth() { } #[test] -fn events() { +fn runtime_upgrade_events() { BlockTests::new() .with_relay_sproof_builder(|_, block_number, builder| { if block_number > 123 { @@ -894,12 +894,20 @@ fn events() { || {}, || { let events = System::events(); + + assert_eq!(events[0].event, RuntimeEvent::System(frame_system::Event::CodeUpdated)); + assert_eq!( - events[0].event, + events[1].event, RuntimeEvent::ParachainSystem(crate::Event::ValidationFunctionApplied { relay_chain_block_num: 1234 }) ); + + assert!(System::digest() + .logs() + .iter() + .any(|d| *d == sp_runtime::generic::DigestItem::RuntimeEnvironmentUpdated)); }, ); } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index eca20f5a0a9..dfdacc9a8eb 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -163,7 +163,7 @@ pub trait SetCode { impl SetCode for () { fn set_code(code: Vec) -> DispatchResult { - >::update_code_in_storage(&code)?; + >::update_code_in_storage(&code); Ok(()) } } @@ -1106,11 +1106,10 @@ impl Pallet { /// Note this function almost never should be used directly. It is exposed /// for `OnSetCode` implementations that defer actual code being written to /// the storage (for instance in case of parachains). - pub fn update_code_in_storage(code: &[u8]) -> DispatchResult { + pub fn update_code_in_storage(code: &[u8]) { storage::unhashed::put_raw(well_known_keys::CODE, code); Self::deposit_log(generic::DigestItem::RuntimeEnvironmentUpdated); Self::deposit_event(Event::CodeUpdated); - Ok(()) } /// Increment the reference counter on an account. -- GitLab From 9faea380dce6db9aabba29cb01328df229764863 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 31 Oct 2023 11:08:08 +0100 Subject: [PATCH 394/633] PVF worker: Add seccomp restrictions (restrict networking) (#2009) --- Cargo.lock | 63 ++- .../node/core/candidate-validation/src/lib.rs | 3 +- polkadot/node/core/pvf/Cargo.toml | 5 + .../benches/host_prepare_rococo_runtime.rs | 18 +- polkadot/node/core/pvf/common/Cargo.toml | 3 +- polkadot/node/core/pvf/common/src/lib.rs | 5 +- .../node/core/pvf/common/src/worker/mod.rs | 57 +- .../core/pvf/common/src/worker/security.rs | 512 ------------------ .../common/src/worker/security/landlock.rs | 325 +++++++++++ .../pvf/common/src/worker/security/mod.rs | 189 +++++++ .../pvf/common/src/worker/security/seccomp.rs | 201 +++++++ .../node/core/pvf/execute-worker/Cargo.toml | 1 - .../node/core/pvf/execute-worker/src/lib.rs | 4 +- .../node/core/pvf/prepare-worker/Cargo.toml | 1 - .../node/core/pvf/prepare-worker/src/lib.rs | 9 +- .../pvf/prepare-worker/src/memory_stats.rs | 2 +- .../node/core/pvf/src/execute/worker_intf.rs | 35 +- polkadot/node/core/pvf/src/host.rs | 126 +---- polkadot/node/core/pvf/src/lib.rs | 1 + .../node/core/pvf/src/prepare/worker_intf.rs | 37 +- polkadot/node/core/pvf/src/security.rs | 312 +++++++++++ polkadot/node/core/pvf/src/worker_intf.rs | 5 +- polkadot/node/core/pvf/tests/it/adder.rs | 17 +- polkadot/node/core/pvf/tests/it/main.rs | 128 ++++- .../src/node/utility/pvf-host-and-workers.md | 13 + .../list-syscalls/execute-worker-syscalls | 9 - .../list-syscalls/prepare-worker-syscalls | 9 - 27 files changed, 1376 insertions(+), 714 deletions(-) delete mode 100644 polkadot/node/core/pvf/common/src/worker/security.rs create mode 100644 polkadot/node/core/pvf/common/src/worker/security/landlock.rs create mode 100644 polkadot/node/core/pvf/common/src/worker/security/mod.rs create mode 100644 polkadot/node/core/pvf/common/src/worker/security/seccomp.rs create mode 100644 polkadot/node/core/pvf/src/security.rs diff --git a/Cargo.lock b/Cargo.lock index c95cc70b0da..c368a957764 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5642,7 +5642,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" dependencies = [ - "rustix 0.38.8", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -6596,7 +6596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.8", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -7049,9 +7049,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libflate" @@ -7635,9 +7635,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lioness" @@ -12279,8 +12279,10 @@ dependencies = [ "polkadot-node-primitives", "polkadot-parachain-primitives", "polkadot-primitives", + "procfs", "rand 0.8.5", "rococo-runtime", + "rusty-fork", "slotmap", "sp-core", "sp-maybe-compressed-blob", @@ -12331,12 +12333,13 @@ dependencies = [ "sc-executor", "sc-executor-common", "sc-executor-wasmtime", + "seccompiler", "sp-core", "sp-externalities", "sp-io", "sp-tracing", "tempfile", - "tokio", + "thiserror", "tracing-gum", ] @@ -12354,7 +12357,6 @@ dependencies = [ "sp-core", "sp-maybe-compressed-blob", "sp-tracing", - "tokio", "tracing-gum", ] @@ -12377,7 +12379,6 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-tracing", "tikv-jemalloc-ctl", - "tokio", "tracing-gum", ] @@ -13525,6 +13526,32 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procfs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +dependencies = [ + "bitflags 2.4.0", + "chrono", + "flate2", + "hex", + "lazy_static", + "procfs-core", + "rustix 0.38.21", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.4.0", + "chrono", + "hex", +] + [[package]] name = "prometheus" version = "0.13.3" @@ -14452,14 +14479,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.5", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -14556,6 +14583,7 @@ dependencies = [ "fnv", "quick-error", "tempfile", + "wait-timeout", ] [[package]] @@ -16182,6 +16210,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "seccompiler" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345a3e4dddf721a478089d4697b83c6c0a8f5bf16086f6c13397e4534eb6e2e5" +dependencies = [ + "libc", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -18410,7 +18447,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.38.8", + "rustix 0.38.21", "windows-sys 0.48.0", ] diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 21a7121d47b..93db7d11cee 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -149,7 +149,8 @@ async fn run( exec_worker_path, ), pvf_metrics, - ); + ) + .await; ctx.spawn_blocking("pvf-validation-host", task.boxed())?; loop { diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index bfd70c6fbd4..430f7cd5e8e 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -39,6 +39,7 @@ polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = tr assert_matches = "1.4.0" criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support", "async_tokio"] } hex-literal = "0.4.1" + polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } # For benches and integration tests, depend on ourselves with the test-utils # feature. @@ -48,6 +49,10 @@ rococo-runtime = { path = "../../../runtime/rococo" } adder = { package = "test-parachain-adder", path = "../../../parachain/test-parachains/adder" } halt = { package = "test-parachain-halt", path = "../../../parachain/test-parachains/halt" } +[target.'cfg(target_os = "linux")'.dev-dependencies] +procfs = "0.16.0" +rusty-fork = "0.3.0" + [[bench]] name = "host_prepare_rococo_runtime" harness = false diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index 3069fa2b194..acd80526262 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -17,18 +17,15 @@ //! Benchmarks for preparation through the host. We use a real PVF to get realistic results. use criterion::{criterion_group, criterion_main, BatchSize, Criterion, SamplingMode}; -use parity_scale_codec::Encode; use polkadot_node_core_pvf::{ start, testing, Config, Metrics, PrepareError, PrepareJobKind, PrepareStats, PvfPrepData, - ValidationError, ValidationHost, + ValidationHost, }; -use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::ExecutorParams; use rococo_runtime::WASM_BINARY; use std::time::Duration; use tokio::{runtime::Handle, sync::Mutex}; -const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); struct TestHost { @@ -36,7 +33,7 @@ struct TestHost { } impl TestHost { - fn new_with_config(handle: &Handle, f: F) -> Self + async fn new_with_config(handle: &Handle, f: F) -> Self where F: FnOnce(&mut Config), { @@ -50,7 +47,7 @@ impl TestHost { execute_worker_path, ); f(&mut config); - let (host, task) = start(config, Metrics::default()); + let (host, task) = start(config, Metrics::default()).await; let _ = handle.spawn(task); Self { host: Mutex::new(host) } } @@ -107,15 +104,18 @@ fn host_prepare_rococo_runtime(c: &mut Criterion) { group.measurement_time(Duration::from_secs(240)); group.bench_function("host: prepare Rococo runtime", |b| { b.to_async(&rt).iter_batched( - || { + || async { ( TestHost::new_with_config(rt.handle(), |cfg| { cfg.prepare_workers_hard_max_num = 1; - }), + }) + .await, pvf.clone().code(), ) }, - |(host, pvf_code)| async move { + |result| async move { + let (host, pvf_code) = result.await; + // `PvfPrepData` is designed to be cheap to clone, so cloning shouldn't affect the // benchmark accuracy. let _stats = host.precheck_pvf(&pvf_code, Default::default()).await.unwrap(); diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 5fe2c6b6845..7dc8d307026 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -12,7 +12,6 @@ cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" -tokio = { version = "1.24.2", features = ["fs", "process", "io-util"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -30,6 +29,8 @@ sp-tracing = { path = "../../../../../substrate/primitives/tracing" } [target.'cfg(target_os = "linux")'.dependencies] landlock = "0.3.0" +seccompiler = "0.4.0" +thiserror = "1.0.31" [dev-dependencies] assert_matches = "1.4.0" diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index 53c287ea970..e2211b97d87 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -32,10 +32,9 @@ pub use sp_tracing; const LOG_TARGET: &str = "parachain::pvf-common"; use std::{ - io::{Read, Write}, + io::{self, Read, Write}, mem, }; -use tokio::io; #[cfg(feature = "test-utils")] pub mod tests { @@ -50,6 +49,8 @@ pub mod tests { pub struct SecurityStatus { /// Whether the landlock features we use are fully available on this system. pub can_enable_landlock: bool, + /// Whether the seccomp features we use are fully available on this system. + pub can_enable_seccomp: bool, // Whether we are able to unshare the user namespace and change the filesystem root. pub can_unshare_user_namespace_and_change_root: bool, } diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index e7b996ccdc3..274a2fc8039 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -23,13 +23,12 @@ use cpu_time::ProcessTime; use futures::never::Never; use std::{ any::Any, - fmt, + fmt, io, os::unix::net::UnixStream, path::PathBuf, sync::mpsc::{Receiver, RecvTimeoutError}, time::Duration, }; -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. @@ -85,6 +84,13 @@ macro_rules! decl_worker_main { let status = -1; std::process::exit(status) }, + "--check-can-enable-seccomp" => { + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + let status = if security::seccomp::check_is_fully_enabled() { 0 } else { -1 }; + #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))] + 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( @@ -129,6 +135,7 @@ macro_rules! decl_worker_main { let mut worker_dir_path = None; let mut node_version = None; let mut can_enable_landlock = false; + let mut can_enable_seccomp = false; let mut can_unshare_user_namespace_and_change_root = false; let mut i = 2; @@ -147,6 +154,7 @@ macro_rules! decl_worker_main { i += 1 }, "--can-enable-landlock" => can_enable_landlock = true, + "--can-enable-seccomp" => can_enable_seccomp = true, "--can-unshare-user-namespace-and-change-root" => can_unshare_user_namespace_and_change_root = true, arg => panic!("Unexpected argument found: {}", arg), @@ -161,6 +169,7 @@ macro_rules! decl_worker_main { let worker_dir_path = std::path::Path::new(worker_dir_path).to_owned(); let security_status = $crate::SecurityStatus { can_enable_landlock, + can_enable_seccomp, can_unshare_user_namespace_and_change_root, }; @@ -198,7 +207,7 @@ impl fmt::Display for WorkerKind { // 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( +pub fn worker_event_loop( worker_kind: WorkerKind, socket_path: PathBuf, #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] mut worker_dir_path: PathBuf, @@ -207,8 +216,7 @@ pub fn worker_event_loop( #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] security_status: &SecurityStatus, mut event_loop: F, ) where - F: FnMut(UnixStream, PathBuf) -> Fut, - Fut: futures::Future>, + F: FnMut(UnixStream, PathBuf) -> io::Result, { let worker_pid = std::process::id(); gum::debug!( @@ -262,7 +270,7 @@ pub fn worker_event_loop( } // Connect to the socket. - let stream = || -> std::io::Result { + let stream = || -> io::Result { let stream = UnixStream::connect(&socket_path)?; let _ = std::fs::remove_file(&socket_path); Ok(stream) @@ -317,6 +325,24 @@ pub fn worker_event_loop( 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. + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + "could not fully enable landlock: {:?}. This should not happen, please report an issue", + landlock_status + ); + } + } + + // TODO: We can enable the seccomp networking blacklist on aarch64 as well, but we need a CI + // job to catch regressions. See . + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + if security_status.can_enable_seccomp { + let seccomp_status = + security::seccomp::enable_for_worker(worker_kind, worker_pid, &worker_dir_path); + if !matches!(seccomp_status, Ok(())) { // We previously were able to enable, so this should never happen. // // TODO: Make this a real error in secure-mode. See: @@ -325,8 +351,8 @@ pub fn worker_event_loop( target: LOG_TARGET, %worker_kind, %worker_pid, - "could not fully enable landlock: {:?}. This should not happen, please report to the Polkadot devs", - landlock_status + "could not fully enable seccomp: {:?}. This should not happen, please report an issue", + seccomp_status ); } } @@ -346,18 +372,11 @@ pub fn worker_event_loop( } // 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(event_loop(stream, worker_dir_path)) + let err = event_loop(stream, worker_dir_path) // It's never `Ok` because it's `Ok(Never)`. .unwrap_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, - // but may be in the future. - rt.shutdown_background(); } /// Provide a consistent message on worker shutdown. @@ -438,7 +457,7 @@ fn kill_parent_node_in_emergency() { /// The motivation for this module is to coordinate worker threads without using async Rust. pub mod thread { use std::{ - panic, + io, panic, sync::{Arc, Condvar, Mutex}, thread, time::Duration, @@ -479,7 +498,7 @@ pub mod thread { f: F, cond: Cond, outcome: WaitOutcome, - ) -> std::io::Result> + ) -> io::Result> where F: FnOnce() -> R, F: Send + 'static + panic::UnwindSafe, @@ -497,7 +516,7 @@ pub mod thread { cond: Cond, outcome: WaitOutcome, stack_size: usize, - ) -> std::io::Result> + ) -> io::Result> where F: FnOnce() -> R, F: Send + 'static + panic::UnwindSafe, diff --git a/polkadot/node/core/pvf/common/src/worker/security.rs b/polkadot/node/core/pvf/common/src/worker/security.rs deleted file mode 100644 index 1b761417744..00000000000 --- a/polkadot/node/core/pvf/common/src/worker/security.rs +++ /dev/null @@ -1,512 +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 . - -//! 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") - } - - // 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(()) -} - -/// 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: -/// -/// > "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 -/// sandboxes as new security layers in addition to the existing system-wide access-controls. This -/// kind of sandbox is expected to help mitigate the security impact of bugs, unexpected or -/// malicious behaviors in applications. Landlock empowers any process, including unprivileged ones, -/// to securely restrict themselves." -/// -/// [landlock]: https://docs.rs/landlock/latest/landlock/index.html -#[cfg(target_os = "linux")] -pub mod landlock { - 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 that would benefit us. - /// - /// # Versions (as of October 2023) - /// - /// - Polkadot reference kernel version: 5.16+ - /// - /// - 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 - /// - /// You may wonder whether we could always use the latest ABI instead of only the ABI supported - /// by the reference kernel version. It seems plausible, since landlock provides a best-effort - /// approach to enabling sandboxing. For example, if the reference version only supported V1 and - /// we were on V2, then landlock would use V2 if it was supported on the current machine, and - /// just fall back to V1 if not. - /// - /// The issue with this is indeterminacy. If half of validators were on V2 and half were on V1, - /// they may have different semantics on some PVFs. So a malicious PVF now has a new attack - /// vector: they can exploit this indeterminism between landlock ABIs! - /// - /// On the other hand we do want validators to be as secure as possible and protect their keys - /// from attackers. And, the risk with indeterminacy is low and there are other indeterminacy - /// vectors anyway. So we will only upgrade to a new ABI if either the reference kernel version - /// supports it or if it introduces some new feature that is beneficial to security. - pub const LANDLOCK_ABI: ABI = ABI::V1; - - #[derive(Debug)] - pub enum TryRestrictError { - InvalidExceptionPath(PathBuf), - RulesetError(RulesetError), - } - - impl From for TryRestrictError { - fn from(err: RulesetError) -> Self { - Self::RulesetError(err) - } - } - - 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 { - 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 (should only be called in a process' main thread) with - /// the following landlock access controls: - /// - /// 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). - 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) - } - - #[cfg(test)] - mod tests { - use super::*; - use std::{fs, io::ErrorKind, thread}; - - #[test] - 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(|| { - // 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(|| { - // 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/node/core/pvf/common/src/worker/security/landlock.rs b/polkadot/node/core/pvf/common/src/worker/security/landlock.rs new file mode 100644 index 00000000000..51500c733b8 --- /dev/null +++ b/polkadot/node/core/pvf/common/src/worker/security/landlock.rs @@ -0,0 +1,325 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! 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 +//! sandboxes as new security layers in addition to the existing system-wide access-controls. This +//! kind of sandbox is expected to help mitigate the security impact of bugs, unexpected or +//! malicious behaviors in applications. Landlock empowers any process, including unprivileged ones, +//! to securely restrict themselves." +//! +//! [landlock]: https://docs.rs/landlock/latest/landlock/index.html + +pub use landlock::RulesetStatus; + +use crate::{ + worker::{stringify_panic_payload, WorkerKind}, + LOG_TARGET, +}; +use landlock::*; +use std::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 that would benefit us. +/// +/// # Versions (as of October 2023) +/// +/// - Polkadot reference kernel version: 5.16+ +/// +/// - 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 +/// +/// You may wonder whether we could always use the latest ABI instead of only the ABI supported +/// by the reference kernel version. It seems plausible, since landlock provides a best-effort +/// approach to enabling sandboxing. For example, if the reference version only supported V1 and +/// we were on V2, then landlock would use V2 if it was supported on the current machine, and +/// just fall back to V1 if not. +/// +/// The issue with this is indeterminacy. If half of validators were on V2 and half were on V1, +/// they may have different semantics on some PVFs. So a malicious PVF now has a new attack +/// vector: they can exploit this indeterminism between landlock ABIs! +/// +/// On the other hand we do want validators to be as secure as possible and protect their keys +/// from attackers. And, the risk with indeterminacy is low and there are other indeterminacy +/// vectors anyway. So we will only upgrade to a new ABI if either the reference kernel version +/// supports it or if it introduces some new feature that is beneficial to security. +pub const LANDLOCK_ABI: ABI = ABI::V1; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Invalid exception path: {0:?}")] + InvalidExceptionPath(PathBuf), + #[error(transparent)] + RulesetError(#[from] RulesetError), + #[error("A panic occurred in try_restrict: {0}")] + Panic(String), +} + +pub type Result = std::result::Result; + +/// 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::trace!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "enabling landlock with exceptions: {:?}", + exceptions, + ); + + 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 { + 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(Error::Panic(stringify_panic_payload(err))), + }; + + matches!(status_from_thread, Ok(RulesetStatus::FullyEnforced)) +} + +/// 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 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). +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(Error::InvalidExceptionPath(fs_path.as_ref().to_owned())) + } + ruleset = ruleset.add_rules(rules)?; + } + let status = ruleset.restrict_self()?; + Ok(status.ruleset) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{fs, io::ErrorKind, thread}; + + #[test] + 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(|| { + // 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(|| { + // 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/node/core/pvf/common/src/worker/security/mod.rs b/polkadot/node/core/pvf/common/src/worker/security/mod.rs new file mode 100644 index 00000000000..9a38ed17277 --- /dev/null +++ b/polkadot/node/core/pvf/common/src/worker/security/mod.rs @@ -0,0 +1,189 @@ +// 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 . + +//! 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. +//! - Restrict networking by blocking socket creation and io_uring. +//! - Remove env vars + +use crate::{worker::WorkerKind, LOG_TARGET}; + +#[cfg(target_os = "linux")] +pub mod landlock; + +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +pub mod seccomp; + +/// 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}; + + // TODO: Remove this once this is stable: https://github.com/rust-lang/rust/issues/105723 + macro_rules! cstr_ptr { + ($e:expr) => { + concat!($e, "\0").as_ptr().cast::() + }; + } + + gum::trace!( + 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_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") + } + + // 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_ptr!("."), cstr_ptr!(".")) < 0 { + return Err("pivot_root") + } + if libc::umount2(cstr_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(()) +} + +/// 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 { + gum::trace!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + "clearing env vars in worker", + ); + + 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 +} diff --git a/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs b/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs new file mode 100644 index 00000000000..5539ad28440 --- /dev/null +++ b/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs @@ -0,0 +1,201 @@ +// 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 . + +//! Functionality for sandboxing workers by restricting their capabilities by blocking certain +//! syscalls with seccomp. +//! +//! For security we block the following: +//! +//! - creation of new sockets - these are unneeded in PVF jobs, and we can safely block them without +//! affecting consensus. +//! +//! - `io_uring` - allows for networking and needs to be blocked. See below for a discussion on the +//! safety of doing this. +//! +//! # Safety of blocking io_uring +//! +//! `io_uring` is just a way of issuing system calls in an async manner, and there is nothing +//! stopping wasmtime from legitimately using it. Fortunately, at the moment it does not. Generally, +//! not many applications use `io_uring` in production yet, because of the numerous kernel CVEs +//! discovered. It's still under a lot of development. Android outright banned `io_uring` for these +//! reasons. +//! +//! Considering `io_uring`'s status discussed above, and that it very likely would get detected +//! either by our [static analysis](https://github.com/paritytech/polkadot-sdk/pull/1663) or by +//! testing, we think it is safe to block it. +//! +//! ## Consensus analysis +//! +//! If execution hits an edge case code path unique to a given machine, it's already taken a +//! non-deterministic branch anyway. After all, we just care that the majority of validators reach +//! the same result and preserve consensus. So worst-case scenario, there's a dispute, and we can +//! always admit fault and refund the wrong validator. On the other hand, if all validators take the +//! code path that results in a seccomp violation, then they would all vote against the current +//! candidate, which is also fine. The violation would get logged (in big scary letters) and +//! hopefully some validator reports it to us. +//! +//! Actually, a worst-worse-case scenario is that 50% of validators vote against, so that there is +//! no consensus. But so many things would have to go wrong for that to happen: +//! +//! 1. An update to `wasmtime` is introduced that uses io_uring (unlikely as io_uring is mainly for +//! IO-heavy applications) +//! +//! 2. The new syscall is not detected by our static analysis +//! +//! 3. It is never triggered in any of our tests +//! +//! 4. It then gets triggered on some super edge case in production on 50% of validators causing a +//! stall (bad but very unlikely) +//! +//! 5. Or, it triggers on only a few validators causing a dispute (more likely but not as bad) +//! +//! Considering how many things would have to go wrong here, we believe it's safe to block +//! `io_uring`. +//! +//! # Action on syscall violations +//! +//! On syscall violations we currently only log, to make sure this works correctly before enforcing. +//! +//! In the future, when a forbidden syscall is attempted we immediately kill the process in order to +//! prevent the attacker from doing anything else. In execution, this will result in voting against +//! the candidate. + +use crate::{ + worker::{stringify_panic_payload, WorkerKind}, + LOG_TARGET, +}; +use seccompiler::*; +use std::{collections::BTreeMap, path::Path}; + +/// The action to take on caught syscalls. +#[cfg(not(test))] +const CAUGHT_ACTION: SeccompAction = SeccompAction::Log; +/// Don't kill the process when testing. +#[cfg(test)] +const CAUGHT_ACTION: SeccompAction = SeccompAction::Errno(libc::EACCES as u32); + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Seccomp(#[from] seccompiler::Error), + #[error(transparent)] + Backend(#[from] seccompiler::BackendError), + #[error("A panic occurred in try_restrict: {0}")] + Panic(String), +} + +pub type Result = std::result::Result; + +/// Try to enable seccomp for the given kind of worker. +pub fn enable_for_worker( + worker_kind: WorkerKind, + worker_pid: u32, + worker_dir_path: &Path, +) -> Result<()> { + gum::trace!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "enabling seccomp", + ); + + try_restrict() +} + +/// Runs a check for seccomp and returns a single bool indicating whether seccomp with our rules is +/// fully enabled on the current Linux environment. +pub fn check_is_fully_enabled() -> bool { + let status_from_thread: Result<()> = match std::thread::spawn(|| try_restrict()).join() { + Ok(Ok(())) => Ok(()), + Ok(Err(err)) => Err(err.into()), + Err(err) => Err(Error::Panic(stringify_panic_payload(err))), + }; + + matches!(status_from_thread, Ok(())) +} + +/// Applies a `seccomp` filter to disable networking for the PVF threads. +pub fn try_restrict() -> Result<()> { + // Build a `seccomp` filter which by default allows all syscalls except those blocked in the + // blacklist. + let mut blacklisted_rules = BTreeMap::default(); + + // Restrict the creation of sockets. + blacklisted_rules.insert(libc::SYS_socketpair, vec![]); + blacklisted_rules.insert(libc::SYS_socket, vec![]); + + // Prevent connecting to sockets for extra safety. + blacklisted_rules.insert(libc::SYS_connect, vec![]); + + // Restrict io_uring. + blacklisted_rules.insert(libc::SYS_io_uring_setup, vec![]); + blacklisted_rules.insert(libc::SYS_io_uring_enter, vec![]); + blacklisted_rules.insert(libc::SYS_io_uring_register, vec![]); + + let filter = SeccompFilter::new( + blacklisted_rules, + // Mismatch action: what to do if not in rule list. + SeccompAction::Allow, + // Match action: what to do if in rule list. + CAUGHT_ACTION, + TargetArch::x86_64, + )?; + + let bpf_prog: BpfProgram = filter.try_into()?; + + // Applies filter (runs seccomp) to the calling thread. + seccompiler::apply_filter(&bpf_prog)?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{io::ErrorKind, net::TcpListener, thread}; + + #[test] + fn sandboxed_thread_cannot_use_sockets() { + // TODO: This would be nice: . + if !check_is_fully_enabled() { + return + } + + let handle = thread::spawn(|| { + // Open a socket, this should succeed before seccomp is applied. + TcpListener::bind("127.0.0.1:0").unwrap(); + + let status = try_restrict(); + if !matches!(status, Ok(())) { + panic!("Ruleset should be enforced since we checked if seccomp is enabled"); + } + + // Try to open a socket after seccomp. + assert!(matches!( + TcpListener::bind("127.0.0.1:0"), + Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) + )); + + // Other syscalls should still work. + unsafe { + assert!(libc::getppid() > 0); + } + }); + + assert!(handle.join().is_ok()); + } +} diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 23678d95696..203bbd0e785 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -11,7 +11,6 @@ cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } rayon = "1.5.1" -tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index af73eb16e68..8872f9bc8dd 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -39,12 +39,12 @@ use polkadot_node_core_pvf_common::{ use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::{executor_params::DEFAULT_NATIVE_STACK_MAX, ExecutorParams}; use std::{ + io, os::unix::net::UnixStream, path::PathBuf, sync::{mpsc::channel, Arc}, time::Duration, }; -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 @@ -138,7 +138,7 @@ pub fn worker_entrypoint( node_version, worker_version, &security_status, - |mut stream, worker_dir_path| async move { + |mut stream, worker_dir_path| { let worker_pid = std::process::id(); let artifact_path = worker_dir::execute_artifact(&worker_dir_path); diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 886209b78c3..eb53ebdc941 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -13,7 +13,6 @@ gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" rayon = "1.5.1" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } -tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index fa5d3656a35..926d9cabe18 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -45,12 +45,12 @@ use polkadot_node_core_pvf_common::{ }; use polkadot_primitives::ExecutorParams; use std::{ + fs, io, os::unix::net::UnixStream, path::PathBuf, sync::{mpsc::channel, Arc}, time::Duration, }; -use tokio::io; /// Contains the bytes for a successfully compiled artifact. pub struct CompiledArtifact(Vec); @@ -131,7 +131,7 @@ pub fn worker_entrypoint( node_version, worker_version, &security_status, - |mut stream, worker_dir_path| async move { + |mut stream, worker_dir_path| { let worker_pid = std::process::id(); let temp_artifact_dest = worker_dir::prepare_tmp_artifact(&worker_dir_path); @@ -229,8 +229,7 @@ pub fn worker_entrypoint( // Stop the memory stats worker and get its observed memory stats. #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] - let memory_tracker_stats = get_memory_tracker_loop_stats(memory_tracker_thread, worker_pid) - .await; + let memory_tracker_stats = get_memory_tracker_loop_stats(memory_tracker_thread, worker_pid); let memory_stats = MemoryStats { #[cfg(any( target_os = "linux", @@ -255,7 +254,7 @@ pub fn worker_entrypoint( "worker: writing artifact to {}", temp_artifact_dest.display(), ); - tokio::fs::write(&temp_artifact_dest, &artifact).await?; + fs::write(&temp_artifact_dest, &artifact)?; Ok(PrepareStats { cpu_time_elapsed, memory_stats }) }, diff --git a/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs b/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs index c70ff56fc84..5f577b0901c 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/memory_stats.rs @@ -122,7 +122,7 @@ pub mod memory_tracker { } /// Helper function to get the stats from the memory tracker. Helps isolate this error handling. - pub async fn get_memory_tracker_loop_stats( + pub fn get_memory_tracker_loop_stats( thread: JoinHandle>, worker_pid: u32, ) -> Option { diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index 783c7c7abbc..61264f7d517 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -18,6 +18,7 @@ use crate::{ artifacts::ArtifactPathId, + security, worker_intf::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, @@ -106,7 +107,7 @@ pub enum Outcome { /// returns the outcome. /// /// NOTE: Not returning the idle worker token in `Outcome` will trigger the child process being -/// killed. +/// killed, if it's still alive. pub async fn start_work( worker: IdleWorker, artifact: ArtifactPathId, @@ -124,7 +125,10 @@ pub async fn start_work( artifact.path.display(), ); + let artifact_path = artifact.path.clone(); with_worker_dir_setup(worker_dir, pid, &artifact.path, |worker_dir| async move { + let audit_log_file = security::AuditLogFile::try_open_and_seek_to_end().await; + if let Err(error) = send_request(&mut stream, &validation_params, execution_timeout).await { gum::warn!( target: LOG_TARGET, @@ -153,9 +157,38 @@ pub async fn start_work( ?error, "failed to recv an execute response", ); + // The worker died. Check if it was due to a seccomp violation. + // + // NOTE: Log, but don't change the outcome. Not all validators may have + // auditing enabled, so we don't want attackers to abuse a non-deterministic + // outcome. + for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { + gum::error!( + target: LOG_TARGET, + worker_pid = %pid, + %syscall, + validation_code_hash = ?artifact.id.code_hash, + ?artifact_path, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + return Outcome::IoErr }, Ok(response) => { + // Check if any syscall violations occurred during the job. For now this is + // only informative, as we are not enforcing the seccomp policy yet. + for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { + gum::error!( + target: LOG_TARGET, + worker_pid = %pid, + %syscall, + validation_code_hash = ?artifact.id.code_hash, + ?artifact_path, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + if let Response::Ok{duration, ..} = response { if duration > execution_timeout { // The job didn't complete within the timeout. diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 6c9606bb2f3..dd0bd858198 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -24,12 +24,12 @@ use crate::{ artifacts::{ArtifactId, ArtifactPathId, ArtifactState, Artifacts}, execute::{self, PendingExecutionRequest}, metrics::Metrics, - prepare, Priority, ValidationError, LOG_TARGET, + prepare, security, Priority, ValidationError, LOG_TARGET, }; use always_assert::never; use futures::{ channel::{mpsc, oneshot}, - Future, FutureExt, SinkExt, StreamExt, + join, Future, FutureExt, SinkExt, StreamExt, }; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, @@ -153,6 +153,7 @@ pub struct Config { pub cache_path: PathBuf, /// The version of the node. `None` can be passed to skip the version check (only for tests). pub node_version: Option, + /// The path to the program that can be used to spawn the prepare workers. pub prepare_worker_program_path: PathBuf, /// The time allotted for a prepare worker to spawn and report to the host. @@ -162,6 +163,7 @@ pub struct Config { pub prepare_workers_soft_max_num: usize, /// The absolute number of workers that can be spawned in the prepare pool. pub prepare_workers_hard_max_num: usize, + /// The path to the program that can be used to spawn the execute workers. pub execute_worker_program_path: PathBuf, /// The time allotted for an execute worker to spawn and report to the host. @@ -181,10 +183,12 @@ impl Config { Self { cache_path, node_version, + prepare_worker_program_path, prepare_worker_spawn_timeout: Duration::from_secs(3), prepare_workers_soft_max_num: 1, prepare_workers_hard_max_num: 1, + execute_worker_program_path, execute_worker_spawn_timeout: Duration::from_secs(3), execute_workers_max_num: 2, @@ -200,15 +204,24 @@ impl Config { /// The future should not return normally but if it does then that indicates an unrecoverable error. /// In that case all pending requests will be canceled, dropping the result senders and new ones /// will be rejected. -pub fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Future) { +pub async 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 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 } + // TODO: add check that syslog is available and that seccomp violations are logged? + let (can_enable_landlock, can_enable_seccomp, can_unshare_user_namespace_and_change_root) = join!( + security::check_landlock(&config.prepare_worker_program_path), + security::check_seccomp(&config.prepare_worker_program_path), + security::check_can_unshare_user_namespace_and_change_root( + &config.prepare_worker_program_path + ) + ); + SecurityStatus { + can_enable_landlock, + can_enable_seccomp, + can_unshare_user_namespace_and_change_root, + } }; let (to_host_tx, to_host_rx) = mpsc::channel(10); @@ -882,105 +895,6 @@ fn pulse_every(interval: std::time::Duration) -> impl futures::Stream .map(|_| ()) } -/// 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, - "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 - } - } -} - -/// 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)] pub(crate) mod tests { use super::*; diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 27630af40c2..102a91dbdad 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -97,6 +97,7 @@ mod host; mod metrics; mod prepare; mod priority; +mod security; mod worker_intf; #[cfg(feature = "test-utils")] diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index b66c3604434..1f6ab0b7655 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -18,6 +18,7 @@ use crate::{ metrics::Metrics, + security, worker_intf::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, @@ -126,7 +127,9 @@ pub async fn start_work( 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 { + let audit_log_file = security::AuditLogFile::try_open_and_seek_to_end().await; + + if let Err(err) = send_request(&mut stream, pvf.clone()).await { gum::warn!( target: LOG_TARGET, worker_pid = %pid, @@ -150,7 +153,19 @@ pub async fn start_work( match result { // Received bytes from worker within the time limit. - Ok(Ok(prepare_result)) => + Ok(Ok(prepare_result)) => { + // Check if any syscall violations occurred during the job. For now this is only + // informative, as we are not enforcing the seccomp policy yet. + for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { + gum::error!( + target: LOG_TARGET, + worker_pid = %pid, + %syscall, + ?pvf, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + handle_response( metrics, IdleWorker { stream, pid, worker_dir }, @@ -160,7 +175,8 @@ pub async fn start_work( artifact_path, preparation_timeout, ) - .await, + .await + }, Ok(Err(err)) => { // Communication error within the time limit. gum::warn!( @@ -169,6 +185,21 @@ pub async fn start_work( "failed to recv a prepare response: {:?}", err, ); + + // The worker died. Check if it was due to a seccomp violation. + // + // NOTE: Log, but don't change the outcome. Not all validators may have auditing + // enabled, so we don't want attackers to abuse a non-deterministic outcome. + for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { + gum::error!( + target: LOG_TARGET, + worker_pid = %pid, + %syscall, + ?pvf, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + Outcome::IoErr(err.to_string()) }, Err(_) => { diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs new file mode 100644 index 00000000000..decd321e415 --- /dev/null +++ b/polkadot/node/core/pvf/src/security.rs @@ -0,0 +1,312 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::LOG_TARGET; +use std::path::Path; +use tokio::{ + fs::{File, OpenOptions}, + io::{AsyncReadExt, AsyncSeekExt, SeekFrom}, +}; + +/// 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. +pub async 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")] { + match tokio::process::Command::new(prepare_worker_program_path) + .arg("--check-can-unshare-user-namespace-and-change-root") + .output() + .await + { + 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, + "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 + } + } +} + +/// 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. +pub async 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 tokio::process::Command::new(prepare_worker_program_path) + .arg("--check-can-enable-landlock") + .status() + .await + { + 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 + } + } +} + +/// Check if seccomp 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. +pub async fn check_seccomp( + #[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 tokio::process::Command::new(prepare_worker_program_path) + .arg("--check-can-enable-seccomp") + .status() + .await + { + Ok(status) if status.success() => true, + Ok(status) => { + gum::warn!( + target: LOG_TARGET, + ?prepare_worker_program_path, + ?status, + "Cannot fully enable seccomp, 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 seccomp, 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 seccomp support for maximum security." + ); + false + } + } +} + +const AUDIT_LOG_PATH: &'static str = "/var/log/audit/audit.log"; +const SYSLOG_PATH: &'static str = "/var/log/syslog"; + +/// System audit log. +pub struct AuditLogFile { + file: File, + path: &'static str, +} + +impl AuditLogFile { + /// Looks for an audit log file on the system and opens it, seeking to the end to skip any + /// events from before this was called. + /// + /// A bit of a verbose name, but it should clue future refactorers not to move calls closer to + /// where the `AuditLogFile` is used. + pub async fn try_open_and_seek_to_end() -> Option { + let mut path = AUDIT_LOG_PATH; + let mut file = match OpenOptions::new().read(true).open(AUDIT_LOG_PATH).await { + Ok(file) => Ok(file), + Err(_) => { + path = SYSLOG_PATH; + OpenOptions::new().read(true).open(SYSLOG_PATH).await + }, + } + .ok()?; + + let _pos = file.seek(SeekFrom::End(0)).await; + + Some(Self { file, path }) + } + + async fn read_new_since_open(mut self) -> String { + let mut buf = String::new(); + let _len = self.file.read_to_string(&mut buf).await; + buf + } +} + +/// Check if a seccomp violation occurred for the given worker. As the syslog may be in a different +/// location, or seccomp auditing may be disabled, this function provides a best-effort attempt +/// only. +/// +/// The `audit_log_file` must have been obtained before the job started. It only allows reading +/// entries that were written since it was obtained, so that we do not consider events from previous +/// processes with the same pid. This can still be racy, but it's unlikely and fine for a +/// best-effort attempt. +pub async fn check_seccomp_violations_for_worker( + audit_log_file: Option, + worker_pid: u32, +) -> Vec { + let audit_event_pid_field = format!("pid={worker_pid}"); + + let audit_log_file = match audit_log_file { + Some(file) => { + gum::debug!( + target: LOG_TARGET, + %worker_pid, + audit_log_path = ?file.path, + "checking audit log for seccomp violations", + ); + file + }, + None => { + gum::warn!( + target: LOG_TARGET, + %worker_pid, + "could not open either {AUDIT_LOG_PATH} or {SYSLOG_PATH} for reading audit logs" + ); + return vec![] + }, + }; + let events = audit_log_file.read_new_since_open().await; + + let mut violations = vec![]; + for event in events.lines() { + if let Some(syscall) = parse_audit_log_for_seccomp_event(event, &audit_event_pid_field) { + violations.push(syscall); + } + } + + violations +} + +fn parse_audit_log_for_seccomp_event(event: &str, audit_event_pid_field: &str) -> Option { + const SECCOMP_AUDIT_EVENT_TYPE: &'static str = "type=1326"; + + // Do a series of simple .contains instead of a regex, because I'm not sure if the fields are + // guaranteed to always be in the same order. + if !event.contains(SECCOMP_AUDIT_EVENT_TYPE) || !event.contains(&audit_event_pid_field) { + return None + } + + // Get the syscall. Let's avoid a dependency on regex just for this. + for field in event.split(" ") { + if let Some(syscall) = field.strip_prefix("syscall=") { + return syscall.parse::().ok() + } + } + + None +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_audit_log_for_seccomp_event() { + let audit_event_pid_field = "pid=2559058"; + + assert_eq!( + parse_audit_log_for_seccomp_event( + r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1326 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559058 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, + audit_event_pid_field + ), + Some(53) + ); + // pid is wrong + assert_eq!( + parse_audit_log_for_seccomp_event( + r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1326 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, + audit_event_pid_field + ), + None + ); + // type is wrong + assert_eq!( + parse_audit_log_for_seccomp_event( + r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1327 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, + audit_event_pid_field + ), + None + ); + // no syscall field + assert_eq!( + parse_audit_log_for_seccomp_event( + r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1327 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e compat=0 ip=0x7f7542c80d5e code=0x80000000"#, + audit_event_pid_field + ), + None + ); + } +} diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index e9382b66bf7..8f9a7de354b 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -245,7 +245,7 @@ pub enum SpawnErr { /// has been terminated. Since the worker is running in another process it is obviously not /// necessary to poll this future to make the worker run, it's only for termination detection. /// -/// This future relies on the fact that a child process's stdout `fd` is closed upon it's +/// This future relies on the fact that a child process's stdout `fd` is closed upon its /// termination. #[pin_project] pub struct WorkerHandle { @@ -270,6 +270,9 @@ impl WorkerHandle { if security_status.can_enable_landlock { args.push("--can-enable-landlock".to_string()); } + if security_status.can_enable_seccomp { + args.push("--can-enable-seccomp".to_string()); + } if security_status.can_unshare_user_namespace_and_change_root { args.push("--can-unshare-user-namespace-and-change-root".to_string()); } diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index 8bdd09db208..e8d8a9a6b63 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -28,7 +28,7 @@ async fn execute_good_block_on_parent() { let block_data = BlockData { state: 0, add: 512 }; - let host = TestHost::new(); + let host = TestHost::new().await; let ret = host .validate_candidate( @@ -56,7 +56,7 @@ async fn execute_good_chain_on_parent() { let mut parent_hash = [0; 32]; let mut last_state = 0; - let host = TestHost::new(); + let host = TestHost::new().await; for (number, add) in (0..10).enumerate() { let parent_head = @@ -98,7 +98,7 @@ async fn execute_bad_block_on_parent() { add: 256, }; - let host = TestHost::new(); + let host = TestHost::new().await; let _err = host .validate_candidate( @@ -117,7 +117,7 @@ async fn execute_bad_block_on_parent() { #[tokio::test] async fn stress_spawn() { - let host = std::sync::Arc::new(TestHost::new()); + let host = std::sync::Arc::new(TestHost::new().await); async fn execute(host: std::sync::Arc) { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; @@ -149,9 +149,12 @@ async fn stress_spawn() { // 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; - })); + let host = std::sync::Arc::new( + TestHost::new_with_config(|cfg| { + cfg.execute_workers_max_num = 1; + }) + .await, + ); async fn execute(host: std::sync::Arc) { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index cdf8d6eb82d..a69a488adb9 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -#[cfg(feature = "ci-only-tests")] use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ @@ -24,6 +23,8 @@ use polkadot_node_core_pvf::{ }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::ExecutorParams; +#[cfg(target_os = "linux")] +use rusty_fork::rusty_fork_test; #[cfg(feature = "ci-only-tests")] use polkadot_primitives::ExecutorParam; @@ -43,11 +44,11 @@ struct TestHost { } impl TestHost { - fn new() -> Self { - Self::new_with_config(|_| ()) + async fn new() -> Self { + Self::new_with_config(|_| ()).await } - fn new_with_config(f: F) -> Self + async fn new_with_config(f: F) -> Self where F: FnOnce(&mut Config), { @@ -61,7 +62,7 @@ impl TestHost { execute_worker_path, ); f(&mut config); - let (host, task) = start(config, Metrics::default()); + let (host, task) = start(config, Metrics::default()).await; let _ = tokio::task::spawn(task); Self { cache_dir, host: Mutex::new(host) } } @@ -127,7 +128,7 @@ impl TestHost { #[tokio::test] async fn terminates_on_timeout() { - let host = TestHost::new(); + let host = TestHost::new().await; let start = std::time::Instant::now(); let result = host @@ -153,11 +154,113 @@ async fn terminates_on_timeout() { assert!(duration < TEST_EXECUTION_TIMEOUT * JOB_TIMEOUT_WALL_CLOCK_FACTOR); } +#[cfg(target_os = "linux")] +fn kill_by_sid_and_name(sid: i32, exe_name: &'static str) { + use procfs::process; + + let all_processes: Vec = process::all_processes() + .expect("Can't read /proc") + .filter_map(|p| match p { + Ok(p) => Some(p), // happy path + Err(e) => match e { + // process vanished during iteration, ignore it + procfs::ProcError::NotFound(_) => None, + x => { + panic!("some unknown error: {}", x); + }, + }, + }) + .collect(); + + for process in all_processes { + if process.stat().unwrap().session == sid && + process.exe().unwrap().to_str().unwrap().contains(exe_name) + { + assert_eq!(unsafe { libc::kill(process.pid(), 9) }, 0); + } + } +} + +// Run these tests in their own processes with rusty-fork. They work by each creating a new session, +// then killing the worker process that matches the session ID and expected worker name. +#[cfg(target_os = "linux")] +rusty_fork_test! { + // What happens when the prepare worker dies in the middle of a job? + #[test] + fn prepare_worker_killed_during_job() { + const PROCESS_NAME: &'static str = "polkadot-prepare-worker"; + + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + let (result, _) = futures::join!( + // Choose a job that would normally take the entire timeout. + host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), + // Run a future that kills the job in the middle of the timeout. + async { + tokio::time::sleep(TEST_PREPARATION_TIMEOUT / 2).await; + kill_by_sid_and_name(sid, PROCESS_NAME); + } + ); + + assert_matches!(result, Err(PrepareError::IoErr(_))); + }) + } + + // What happens when the execute worker dies in the middle of a job? + #[test] + fn execute_worker_killed_during_job() { + const PROCESS_NAME: &'static str = "polkadot-execute-worker"; + + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + // Prepare the artifact ahead of time. + let binary = halt::wasm_binary_unwrap(); + host.precheck_pvf(binary, Default::default()).await.unwrap(); + + let (result, _) = futures::join!( + // Choose an job that would normally take the entire timeout. + host.validate_candidate( + binary, + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ), + // Run a future that kills the job in the middle of the timeout. + async { + tokio::time::sleep(TEST_EXECUTION_TIMEOUT / 2).await; + kill_by_sid_and_name(sid, PROCESS_NAME); + } + ); + + assert_matches!( + result, + Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + ); + }) + } +} + #[cfg(feature = "ci-only-tests")] #[tokio::test] async fn ensure_parallel_execution() { // Run some jobs that do not complete, thus timing out. - let host = TestHost::new(); + let host = TestHost::new().await; let execute_pvf_future_1 = host.validate_candidate( halt::wasm_binary_unwrap(), ValidationParams { @@ -204,7 +307,8 @@ async fn ensure_parallel_execution() { async fn execute_queue_doesnt_stall_if_workers_died() { let host = TestHost::new_with_config(|cfg| { cfg.execute_workers_max_num = 5; - }); + }) + .await; // Here we spawn 8 validation jobs for the `halt` PVF and share those between 5 workers. The // first five jobs should timeout and the workers killed. For the next 3 jobs a new batch of @@ -241,7 +345,8 @@ async fn execute_queue_doesnt_stall_if_workers_died() { async fn execute_queue_doesnt_stall_with_varying_executor_params() { let host = TestHost::new_with_config(|cfg| { cfg.execute_workers_max_num = 2; - }); + }) + .await; let executor_params_1 = ExecutorParams::default(); let executor_params_2 = ExecutorParams::from(&[ExecutorParam::StackLogicalMax(1024)][..]); @@ -289,7 +394,7 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { // Test that deleting a prepared artifact does not lead to a dispute when we try to execute it. #[tokio::test] async fn deleting_prepared_artifact_does_not_dispute() { - let host = TestHost::new(); + let host = TestHost::new().await; let cache_dir = host.cache_dir.path(); let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); @@ -334,7 +439,8 @@ async fn deleting_prepared_artifact_does_not_dispute() { async fn prepare_can_run_serially() { let host = TestHost::new_with_config(|cfg| { cfg.prepare_workers_hard_max_num = 1; - }); + }) + .await; let _stats = host .precheck_pvf(::adder::wasm_binary_unwrap(), Default::default()) 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 6a14a3a013d..0cefeb1f77c 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 @@ -126,6 +126,19 @@ 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. +*Currently this is only supported on Linux.* + + + + + + + + + + + + ### Clearing env vars We clear environment variables before handling untrusted code, because why give diff --git a/polkadot/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls index 05abe9ba736..4a7a6618129 100644 --- a/polkadot/scripts/list-syscalls/execute-worker-syscalls +++ b/polkadot/scripts/list-syscalls/execute-worker-syscalls @@ -24,10 +24,8 @@ 42 (connect) 45 (recvfrom) 46 (sendmsg) -53 (socketpair) 56 (clone) 60 (exit) -61 (wait4) 62 (kill) 72 (fcntl) 79 (getcwd) @@ -52,23 +50,16 @@ 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/prepare-worker-syscalls b/polkadot/scripts/list-syscalls/prepare-worker-syscalls index f1597f20675..cab58e06692 100644 --- a/polkadot/scripts/list-syscalls/prepare-worker-syscalls +++ b/polkadot/scripts/list-syscalls/prepare-worker-syscalls @@ -24,10 +24,8 @@ 42 (connect) 45 (recvfrom) 46 (sendmsg) -53 (socketpair) 56 (clone) 60 (exit) -61 (wait4) 62 (kill) 72 (fcntl) 79 (getcwd) @@ -54,23 +52,16 @@ 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) -- GitLab From 18ad449015e243d148d48688f2492d435fc75522 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Tue, 31 Oct 2023 12:08:32 +0100 Subject: [PATCH 395/633] Contracts migration update (#2091) Restore fix from #2077 --- substrate/frame/contracts/src/migration.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/substrate/frame/contracts/src/migration.rs b/substrate/frame/contracts/src/migration.rs index 1873ef2765b..6d61cb6b1e1 100644 --- a/substrate/frame/contracts/src/migration.rs +++ b/substrate/frame/contracts/src/migration.rs @@ -312,10 +312,7 @@ impl OnRuntimeUpgrade for Migration>::current_storage_version(); if on_chain_version == current_version { - log::warn!( - target: LOG_TARGET, - "No upgrade: Please remove this migration from your Migrations tuple" - ) + return Ok(Default::default()) } log::debug!( @@ -324,9 +321,11 @@ impl OnRuntimeUpgrade for Migration>::name(), on_chain_version, current_version ); - if !T::Migrations::is_upgrade_supported(on_chain_version, current_version) { - log::warn!(target: LOG_TARGET, "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)") - } + ensure!( + T::Migrations::is_upgrade_supported(on_chain_version, current_version), + "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)" + ); + Ok(Default::default()) } -- GitLab From d85c1d9117293ef7215ebdcbf86fbe8eae429b56 Mon Sep 17 00:00:00 2001 From: Rahul Subramaniyam <78006270+rahulksnv@users.noreply.github.com> Date: Tue, 31 Oct 2023 05:11:00 -0700 Subject: [PATCH 396/633] Add test to demonstrate the failure scenario (#1999) The change adds a test to show the failure scenario that caused #1812 to be rolled back (more context: https://github.com/paritytech/polkadot-sdk/issues/493#issuecomment-1772009924) Summary of the scenario: 1. Node has finished downloading up to block 1000 from the peers, from the canonical chain. 2. Peers are undergoing re-org around this time. One of the peers has switched to a non-canonical chain, announces block 1001 from that chain 3. Node downloads 1001 from the peer, and tries to import which would fail (as we don't have the parent block 1000 from the other chain) --------- Co-authored-by: Dmitry Markin --- Cargo.lock | 2 +- substrate/client/network/sync/src/lib.rs | 125 +++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c368a957764..8315bebc683 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18466,7 +18466,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.8", + "rustix 0.38.21", "windows-sys 0.48.0", ] diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 10eaa245051..0c8e8a104e2 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -3364,4 +3364,129 @@ mod test { pending_responses.remove(&peers[1]); assert_eq!(pending_responses.len(), 0); } + + /// The test demonstrates https://github.com/paritytech/polkadot-sdk/issues/2094. + /// TODO: convert it into desired behavior test once the issue is fixed (see inline comments). + /// The issue: we currently rely on block numbers instead of block hash + /// to download blocks from peers. As a result, we can end up with blocks + /// from different forks as shown by the test. + #[test] + #[should_panic] + fn request_across_forks() { + sp_tracing::try_init_simple(); + + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..100).map(|_| build_block(&mut client, None, false)).collect::>(); + + let fork_a_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let mut fork_blocks = blocks[..] + .into_iter() + .inspect(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() + }) + .cloned() + .collect::>(); + for _ in 0..10 { + fork_blocks.push(build_block(&mut client, None, false)); + } + fork_blocks + }; + + let fork_b_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let mut fork_blocks = blocks[..] + .into_iter() + .inspect(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() + }) + .cloned() + .collect::>(); + for _ in 0..10 { + fork_blocks.push(build_block(&mut client, None, true)); + } + fork_blocks + }; + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + // Add the peers, all at the common ancestor 100. + let common_block = blocks.last().unwrap(); + let peer_id1 = PeerId::random(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) + .unwrap(); + let peer_id2 = PeerId::random(); + sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number()) + .unwrap(); + + // Peer 1 announces 107 from fork 1, 100-107 get downloaded. + { + let block = (&fork_a_blocks[106]).clone(); + let peer = peer_id1; + log::trace!(target: LOG_TARGET, "<1> {peer} announces from fork 1"); + send_block_announce(block.header().clone(), peer, &mut sync); + let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 7, &peer); + let mut resp_blocks = fork_a_blocks[100_usize..107_usize].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 7_usize + ),); + assert_eq!(sync.best_queued_number, 107); + assert_eq!(sync.best_queued_hash, block.hash()); + assert!(sync.is_known(&block.header.parent_hash())); + } + + // Peer 2 also announces 107 from fork 1. + { + let prev_best_number = sync.best_queued_number; + let prev_best_hash = sync.best_queued_hash; + let peer = peer_id2; + log::trace!(target: LOG_TARGET, "<2> {peer} announces from fork 1"); + for i in 100..107 { + let block = (&fork_a_blocks[i]).clone(); + send_block_announce(block.header().clone(), peer, &mut sync); + assert!(sync.block_requests().is_empty()); + } + assert_eq!(sync.best_queued_number, prev_best_number); + assert_eq!(sync.best_queued_hash, prev_best_hash); + } + + // Peer 2 undergoes reorg, announces 108 from fork 2, gets downloaded even though we + // don't have the parent from fork 2. + { + let block = (&fork_b_blocks[107]).clone(); + let peer = peer_id2; + log::trace!(target: LOG_TARGET, "<3> {peer} announces from fork 2"); + send_block_announce(block.header().clone(), peer, &mut sync); + // TODO: when the issue is fixed, this test can be changed to test the + // expected behavior instead. The needed changes would be: + // 1. Remove the `#[should_panic]` directive + // 2. These should be changed to check that sync.block_requests().is_empty(), after the + // block is announced. + let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 1, &peer); + let response = create_block_response(vec![block.clone()]); + let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 1_usize + ),); + assert!(sync.is_known(&block.header.parent_hash())); + } + } } -- GitLab From 3ae86ae075ac5eb9b80f89f09bd7f4a63f97c582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 31 Oct 2023 14:07:10 +0100 Subject: [PATCH 397/633] check-each-crate: Do not reference crate to check by name (#2098) This pull request changes how `check-each-crate.py` is working. Instead of passing the name of the crate via `-p`, we now jump into the directory of the crate and call there `cargo check`. This should fix issues like https://github.com/paritytech/polkadot-sdk/issues/2013 where a crate is present twice in the `Cargo.lock`. Besides that it also changes `core/Cargo.toml` to not always pull in bandersnatch. --- .gitlab/check-each-crate.py | 10 +++++++--- substrate/primitives/core/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitlab/check-each-crate.py b/.gitlab/check-each-crate.py index adad4f5bd58..da2eaad36c5 100755 --- a/.gitlab/check-each-crate.py +++ b/.gitlab/check-each-crate.py @@ -19,7 +19,11 @@ output = subprocess.check_output(["cargo", "tree", "--locked", "--workspace", "- crates = [] for line in output.splitlines(): if line != b"": - crates.append(line.decode('utf8').split(" ")[0]) + line = line.decode('utf8').split(" ") + crate_name = line[0] + # The crate path is always the last element in the line. + crate_path = line[len(line) - 1].replace("(", "").replace(")", "") + crates.append((crate_name, crate_path)) # Make the list unique and sorted crates = list(set(crates)) @@ -49,9 +53,9 @@ print(f"Crates per group: {crates_per_group}", file=sys.stderr) for i in range(0, crates_per_group + overflow_crates): crate = crates_per_group * target_group + i - print(f"Checking {crates[crate]}", file=sys.stderr) + print(f"Checking {crates[crate][0]}", file=sys.stderr) - res = subprocess.run(["cargo", "check", "--locked", "-p", crates[crate]]) + res = subprocess.run(["cargo", "check", "--locked"], cwd = crates[crate][1]) if res.returncode != 0: sys.exit(1) diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 1e8a353f419..7f329832efd 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -76,7 +76,7 @@ bench = false default = [ "std" ] std = [ "array-bytes", - "bandersnatch_vrfs/getrandom", + "bandersnatch_vrfs?/getrandom", "bip39/rand", "bip39/std", "blake2/std", -- GitLab From c38aae628b437dd7bd0e2178dc6e73f685b424f4 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 31 Oct 2023 14:59:15 +0100 Subject: [PATCH 398/633] Elliptic curves utilities refactory (#2068) - Usage the new published [arkworks-extensions](https://github.com/paritytech/arkworks-extensions) crates. Hooks are internally defined to jump into the proper host functions. - Conditional compilation of each curve (gated by feature with curve name) - Separation in smaller host functions sets, divided by curve (fits nicely with prev point) --- Cargo.lock | 85 +++++ .../primitives/crypto/ec-utils/Cargo.toml | 63 ++-- .../crypto/ec-utils/src/bls12_377.rs | 205 ++++++++++++ .../crypto/ec-utils/src/bls12_381.rs | 195 ++++++++++++ .../primitives/crypto/ec-utils/src/bw6_761.rs | 186 +++++++++++ .../crypto/ec-utils/src/ed_on_bls12_377.rs | 88 ++++++ .../src/ed_on_bls12_381_bandersnatch.rs | 153 +++++++++ .../primitives/crypto/ec-utils/src/lib.rs | 295 ++---------------- .../primitives/crypto/ec-utils/src/utils.rs | 151 +++++---- 9 files changed, 1059 insertions(+), 362 deletions(-) create mode 100644 substrate/primitives/crypto/ec-utils/src/bls12_377.rs create mode 100644 substrate/primitives/crypto/ec-utils/src/bls12_381.rs create mode 100644 substrate/primitives/crypto/ec-utils/src/bw6_761.rs create mode 100644 substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs create mode 100644 substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs diff --git a/Cargo.lock b/Cargo.lock index 8315bebc683..8cedf9f2c74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,6 +327,18 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-models-ext", + "ark-std", +] + [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -339,6 +351,20 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bls12-381-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-serialize", + "ark-std", +] + [[package]] name = "ark-bw6-761" version = "0.4.0" @@ -351,6 +377,19 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bw6-761-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" +dependencies = [ + "ark-bw6-761", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-std", +] + [[package]] name = "ark-ec" version = "0.4.2" @@ -365,6 +404,7 @@ dependencies = [ "hashbrown 0.13.2", "itertools 0.10.5", "num-traits", + "rayon", "zeroize", ] @@ -380,6 +420,19 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-ed-on-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ff", + "ark-models-ext", + "ark-std", +] + [[package]] name = "ark-ed-on-bls12-381-bandersnatch" version = "0.4.0" @@ -392,6 +445,19 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-models-ext", + "ark-std", +] + [[package]] name = "ark-ff" version = "0.4.2" @@ -435,6 +501,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-models-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -508,6 +587,7 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", + "rayon", ] [[package]] @@ -17179,11 +17259,16 @@ name = "sp-crypto-ec-utils" version = "0.4.0" dependencies = [ "ark-bls12-377", + "ark-bls12-377-ext", "ark-bls12-381", + "ark-bls12-381-ext", "ark-bw6-761", + "ark-bw6-761-ext", "ark-ec", "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", "ark-scale", "sp-runtime-interface", "sp-std", diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index e091385071c..651fc96d7ac 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -12,26 +12,53 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ark-ec = { version = "0.4.2", 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 } -ark-scale = { version = "0.0.11", features = ["hazmat"], default-features = false } -sp-runtime-interface = { path = "../../runtime-interface", default-features = false} -sp-std = { path = "../../std", default-features = false } +ark-ec = { version = "0.4.2", default-features = false, optional = true } +ark-bls12-377-ext = { version = "0.4.1", default-features = false, optional = true } +ark-bls12-377 = { version = "0.4.0", default-features = false, features = ["curve"], optional = true } +ark-bls12-381-ext = { version = "0.4.1", default-features = false, optional = true } +ark-bls12-381 = { version = "0.4.0", default-features = false, features = ["curve"], optional = true } +ark-bw6-761-ext = { version = "0.4.1", default-features = false, optional = true } +ark-bw6-761 = { version = "0.4.0", default-features = false, optional = true } +ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = false, optional = true } +ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false, optional = true } +ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false, optional = true } +ark-ed-on-bls12-377 = { version = "0.4.0", default-features = false, optional = true } +ark-scale = { version = "0.0.11", default-features = false, features = ["hazmat"], optional = true } +sp-runtime-interface = { path = "../../runtime-interface", default-features = false, optional = true } +sp-std = { path = "../../std", default-features = false, optional = true } [features] default = [ "std" ] 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-scale/std", - "sp-runtime-interface/std", - "sp-std/std", + "ark-bls12-377-ext?/std", + "ark-bls12-377?/std", + "ark-bls12-381-ext?/std", + "ark-bls12-381?/std", + "ark-bw6-761-ext?/std", + "ark-bw6-761?/std", + "ark-ec?/parallel", + "ark-ed-on-bls12-377-ext?/std", + "ark-ed-on-bls12-377?/std", + "ark-ed-on-bls12-381-bandersnatch-ext?/std", + "ark-ed-on-bls12-381-bandersnatch?/std", + "ark-scale?/std", + "sp-runtime-interface?/std", + "sp-std?/std", +] +common = [ "ark-ec", "ark-scale", "sp-runtime-interface", "sp-std" ] +bls12-377 = [ "ark-bls12-377", "ark-bls12-377-ext", "common" ] +bls12-381 = [ "ark-bls12-381", "ark-bls12-381-ext", "common" ] +bw6-761 = [ "ark-bw6-761", "ark-bw6-761-ext", "common" ] +ed-on-bls12-377 = [ "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "common" ] +ed-on-bls12-381-bandersnatch = [ + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "common", +] +all-curves = [ + "bls12-377", + "bls12-381", + "bw6-761", + "ed-on-bls12-377", + "ed-on-bls12-381-bandersnatch", ] diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs new file mode 100644 index 00000000000..8f19a2c4a19 --- /dev/null +++ b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs @@ -0,0 +1,205 @@ +// 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. + +//! *BLS12-377* types and host functions. + +use crate::utils; +use ark_bls12_377_ext::CurveHooks; +use ark_ec::{pairing::Pairing, CurveConfig}; +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + +/// First pairing group definitions. +pub mod g1 { + pub use ark_bls12_377_ext::g1::{ + G1_GENERATOR_X, G1_GENERATOR_Y, TE_GENERATOR_X, TE_GENERATOR_Y, + }; + /// Group configuration. + pub type Config = ark_bls12_377_ext::g1::Config; + /// Short Weierstrass form point affine representation. + pub type G1Affine = ark_bls12_377_ext::g1::G1Affine; + /// Short Weierstrass form point projective representation. + pub type G1Projective = ark_bls12_377_ext::g1::G1Projective; + /// Short Weierstrass form point affine representation. + pub type G1SWAffine = ark_bls12_377_ext::g1::G1SWAffine; + /// Short Weierstrass form point projective representation. + pub type G1SWProjective = ark_bls12_377_ext::g1::G1SWProjective; + /// Twisted Edwards form point affine representation. + pub type G1TEAffine = ark_bls12_377_ext::g1::G1TEAffine; + /// Twisted Edwards form point projective representation. + pub type G1TEProjective = ark_bls12_377_ext::g1::G1TEProjective; +} + +/// Second pairing group definitions. +pub mod g2 { + pub use ark_bls12_377_ext::g2::{ + G2_GENERATOR_X, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1, G2_GENERATOR_Y, G2_GENERATOR_Y_C0, + G2_GENERATOR_Y_C1, + }; + /// Group configuration. + pub type Config = ark_bls12_377_ext::g2::Config; + /// Short Weierstrass form point affine representation. + pub type G2Affine = ark_bls12_377_ext::g2::G2Affine; + /// Short Weierstrass form point projective representation. + pub type G2Projective = ark_bls12_377_ext::g2::G2Projective; +} + +pub use self::{ + g1::{Config as G1Config, G1Affine, G1Projective}, + g2::{Config as G2Config, G2Affine, G2Projective}, +}; + +/// Curve hooks jumping into [`host_calls`] host functions. +#[derive(Copy, Clone)] +pub struct HostHooks; + +/// Configuration for *BLS12-377* curve. +pub type Config = ark_bls12_377_ext::Config; + +/// *BLS12-377* definition. +/// +/// A generic *BLS12* model specialized with *BLS12-377* configuration. +pub type Bls12_377 = ark_bls12_377_ext::Bls12_377; + +impl CurveHooks for HostHooks { + fn bls12_377_multi_miller_loop( + g1: impl Iterator::G1Prepared>, + g2: impl Iterator::G2Prepared>, + ) -> Result<::TargetField, ()> { + let g1 = utils::encode(g1.collect::>()); + let g2 = utils::encode(g2.collect::>()); + let res = host_calls::bls12_377_multi_miller_loop(g1, g2).unwrap_or_default(); + utils::decode(res) + } + + fn bls12_377_final_exponentiation( + target: ::TargetField, + ) -> Result<::TargetField, ()> { + let target = utils::encode(target); + let res = host_calls::bls12_377_final_exponentiation(target).unwrap_or_default(); + utils::decode(res) + } + + fn bls12_377_msm_g1( + bases: &[G1Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bls12_377_msm_g1(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_377_msm_g2( + bases: &[G2Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bls12_377_msm_g2(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_377_mul_projective_g1( + base: &G1Projective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bls12_377_mul_projective_g1(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_377_mul_projective_g2( + base: &G2Projective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bls12_377_mul_projective_g2(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } +} + +/// Interfaces for working with *Arkworks* *BLS12-377* elliptic curve 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 "not-validated" +/// and "not-compressed". +#[runtime_interface] +pub trait HostCalls { + /// 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, ()> { + utils::multi_miller_loop::(a, b) + } + + /// Pairing final exponentiation for *BLS12-377.* + /// + /// - Receives encoded: `ArkScale`. + /// - Returns encoded: `ArkScale`. + fn bls12_377_final_exponentiation(f: Vec) -> Result, ()> { + utils::final_exponentiation::(f) + } + + /// Multi scalar multiplication on *G1* for *BLS12-377*. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_377_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Multi scalar multiplication on *G2* for *BLS12-377*. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_377_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Projective multiplication on *G1* for *BLS12-377*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_377_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } + + /// Projective multiplication on *G2* for *BLS12-377*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_377_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } +} diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs new file mode 100644 index 00000000000..99a0289b7ad --- /dev/null +++ b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs @@ -0,0 +1,195 @@ +// 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. + +//! *BLS12-381* types and host functions. + +use crate::utils; +use ark_bls12_381_ext::CurveHooks; +use ark_ec::{pairing::Pairing, CurveConfig}; +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + +/// First pairing group definitions. +pub mod g1 { + pub use ark_bls12_381_ext::g1::{BETA, G1_GENERATOR_X, G1_GENERATOR_Y}; + /// Group configuration. + pub type Config = ark_bls12_381_ext::g1::Config; + /// Short Weierstrass form point affine representation. + pub type G1Affine = ark_bls12_381_ext::g1::G1Affine; + /// Short Weierstrass form point projective representation. + pub type G1Projective = ark_bls12_381_ext::g1::G1Projective; +} + +/// Second pairing group definitions. +pub mod g2 { + pub use ark_bls12_381_ext::g2::{ + G2_GENERATOR_X, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1, G2_GENERATOR_Y, G2_GENERATOR_Y_C0, + G2_GENERATOR_Y_C1, + }; + /// Group configuration. + pub type Config = ark_bls12_381_ext::g2::Config; + /// Short Weierstrass form point affine representation. + pub type G2Affine = ark_bls12_381_ext::g2::G2Affine; + /// Short Weierstrass form point projective representation. + pub type G2Projective = ark_bls12_381_ext::g2::G2Projective; +} + +pub use self::{ + g1::{Config as G1Config, G1Affine, G1Projective}, + g2::{Config as G2Config, G2Affine, G2Projective}, +}; + +/// Curve hooks jumping into [`host_calls`] host functions. +#[derive(Copy, Clone)] +pub struct HostHooks; + +/// Configuration for *BLS12-381* curve. +pub type Config = ark_bls12_381_ext::Config; + +/// *BLS12-381* definition. +/// +/// A generic *BLS12* model specialized with *BLS12-381* configuration. +pub type Bls12_381 = ark_bls12_381_ext::Bls12_381; + +impl CurveHooks for HostHooks { + fn bls12_381_multi_miller_loop( + g1: impl Iterator::G1Prepared>, + g2: impl Iterator::G2Prepared>, + ) -> Result<::TargetField, ()> { + let g1 = utils::encode(g1.collect::>()); + let g2 = utils::encode(g2.collect::>()); + let res = host_calls::bls12_381_multi_miller_loop(g1, g2).unwrap_or_default(); + utils::decode(res) + } + + fn bls12_381_final_exponentiation( + target: ::TargetField, + ) -> Result<::TargetField, ()> { + let target = utils::encode(target); + let res = host_calls::bls12_381_final_exponentiation(target).unwrap_or_default(); + utils::decode(res) + } + + fn bls12_381_msm_g1( + bases: &[G1Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bls12_381_msm_g1(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_381_msm_g2( + bases: &[G2Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bls12_381_msm_g2(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_381_mul_projective_g1( + base: &G1Projective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bls12_381_mul_projective_g1(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bls12_381_mul_projective_g2( + base: &G2Projective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bls12_381_mul_projective_g2(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } +} + +/// Interfaces for working with *Arkworks* *BLS12-381* elliptic curve 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 "not-validated" +/// and "not-compressed". +#[runtime_interface] +pub trait HostCalls { + /// 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, ()> { + utils::multi_miller_loop::(a, b) + } + + /// Pairing final exponentiation for *BLS12-381*. + /// + /// - Receives encoded: `ArkScale<`. + /// - Returns encoded: `ArkScale<` + fn bls12_381_final_exponentiation(f: Vec) -> Result, ()> { + utils::final_exponentiation::(f) + } + + /// Multi scalar multiplication on *G1* for *BLS12-381* + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_381_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Multi scalar multiplication on *G2* for *BLS12-381* + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_381_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Projective multiplication on *G1* for *BLS12-381*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_381_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } + + /// Projective multiplication on *G2* for *BLS12-381* + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bls12_381_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } +} diff --git a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs new file mode 100644 index 00000000000..a68abf6e43e --- /dev/null +++ b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs @@ -0,0 +1,186 @@ +// 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. + +//! *BW6-761* types and host functions. + +use crate::utils; +use ark_bw6_761_ext::CurveHooks; +use ark_ec::{pairing::Pairing, CurveConfig}; +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + +/// First pairing group definitions. +pub mod g1 { + pub use ark_bw6_761_ext::g1::{G1_GENERATOR_X, G1_GENERATOR_Y}; + /// Group configuration. + pub type Config = ark_bw6_761_ext::g1::Config; + /// Short Weierstrass form point affine representation. + pub type G1Affine = ark_bw6_761_ext::g1::G1Affine; + /// Short Weierstrass form point projective representation. + pub type G1Projective = ark_bw6_761_ext::g1::G1Projective; +} + +/// Second pairing group definitions. +pub mod g2 { + pub use ark_bw6_761_ext::g2::{G2_GENERATOR_X, G2_GENERATOR_Y}; + /// Group configuration. + pub type Config = ark_bw6_761_ext::g2::Config; + /// Short Weierstrass form point affine representation. + pub type G2Affine = ark_bw6_761_ext::g2::G2Affine; + /// Short Weierstrass form point projective representation. + pub type G2Projective = ark_bw6_761_ext::g2::G2Projective; +} + +pub use self::{ + g1::{Config as G1Config, G1Affine, G1Projective}, + g2::{Config as G2Config, G2Affine, G2Projective}, +}; + +/// Curve hooks jumping into [`host_calls`] host functions. +#[derive(Copy, Clone)] +pub struct HostHooks; + +/// Configuration for *BW6-361* curve. +pub type Config = ark_bw6_761_ext::Config; + +/// *BW6-361* definition. +/// +/// A generic *BW6* model specialized with *BW6-761* configuration. +pub type BW6_761 = ark_bw6_761_ext::BW6_761; + +impl CurveHooks for HostHooks { + fn bw6_761_multi_miller_loop( + g1: impl Iterator::G1Prepared>, + g2: impl Iterator::G2Prepared>, + ) -> Result<::TargetField, ()> { + let g1 = utils::encode(g1.collect::>()); + let g2 = utils::encode(g2.collect::>()); + let res = host_calls::bw6_761_multi_miller_loop(g1, g2).unwrap_or_default(); + utils::decode(res) + } + + fn bw6_761_final_exponentiation( + target: ::TargetField, + ) -> Result<::TargetField, ()> { + let target = utils::encode(target); + let res = host_calls::bw6_761_final_exponentiation(target).unwrap_or_default(); + utils::decode(res) + } + + fn bw6_761_msm_g1( + bases: &[G1Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bw6_761_msm_g1(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bw6_761_msm_g2( + bases: &[G2Affine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::bw6_761_msm_g2(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bw6_761_mul_projective_g1(base: &G1Projective, scalar: &[u64]) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bw6_761_mul_projective_g1(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn bw6_761_mul_projective_g2(base: &G2Projective, scalar: &[u64]) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::bw6_761_mul_projective_g2(base, scalar).unwrap_or_default(); + utils::decode_proj_sw(res) + } +} + +/// Interfaces for working with *Arkworks* *BW6-761* elliptic curve 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 "not-validated" +/// and "not-compressed". +#[runtime_interface] +pub trait HostCalls { + /// 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, ()> { + utils::multi_miller_loop::(a, b) + } + + /// Pairing final exponentiation for *BW6-761*. + /// + /// - Receives encoded: `ArkScale`. + /// - Returns encoded: `ArkScale`. + fn bw6_761_final_exponentiation(f: Vec) -> Result, ()> { + utils::final_exponentiation::(f) + } + + /// Multi scalar multiplication on *G1* for *BW6-761*. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale`. + /// - Returns encoded: `ArkScaleProjective`. + fn bw6_761_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Multi scalar multiplication on *G2* for *BW6-761*. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bw6_761_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Projective multiplication on *G1* for *BW6-761*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bw6_761_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } + + /// Projective multiplication on *G2* for *BW6-761*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn bw6_761_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } +} 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 new file mode 100644 index 00000000000..a03be41b854 --- /dev/null +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs @@ -0,0 +1,88 @@ +// 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. + +//! *Ed-on-BLS12-377* types and host functions. + +use crate::utils; +use ark_ec::CurveConfig; +use ark_ed_on_bls12_377_ext::CurveHooks; +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + +/// Curve hooks jumping into [`host_calls`] host functions. +#[derive(Copy, Clone)] +pub struct HostHooks; + +/// Group configuration. +pub type EdwardsConfig = ark_ed_on_bls12_377_ext::EdwardsConfig; +/// Twisted Edwards form point affine representation. +pub type EdwardsAffine = ark_ed_on_bls12_377_ext::EdwardsAffine; +/// Twisted Edwards form point projective representation. +pub type EdwardsProjective = ark_ed_on_bls12_377_ext::EdwardsProjective; + +impl CurveHooks for HostHooks { + fn ed_on_bls12_377_msm( + bases: &[EdwardsAffine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = host_calls::ed_on_bls12_377_te_msm(bases, scalars).unwrap_or_default(); + utils::decode_proj_te(res) + } + + fn ed_on_bls12_377_mul_projective( + base: &EdwardsProjective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_te(base); + let scalar = utils::encode(scalar); + let res = host_calls::ed_on_bls12_377_te_mul_projective(base, scalar).unwrap_or_default(); + utils::decode_proj_te(res) + } +} + +/// Interfaces for working with *Arkworks* *Ed-on-BLS12-377* elliptic curve +/// 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 "not-validated" +/// and "not-compressed". +#[runtime_interface] +pub trait HostCalls { + /// Twisted Edwards multi scalar multiplication for *Ed-on-BLS12-377*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_377_te_msm(bases: Vec, scalars: Vec) -> Result, ()> { + utils::msm_te::(bases, scalars) + } + + /// Twisted Edwards projective multiplication for *Ed-on-BLS12-377*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_377_te_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { + utils::mul_projective_te::(base, scalar) + } +} 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 new file mode 100644 index 00000000000..9d63f358765 --- /dev/null +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs @@ -0,0 +1,153 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Elliptic Curves host functions to handle some of the *Arkworks* *Ed-on-BLS12-381-Bandersnatch* +//! computationally expensive operations. + +use crate::utils; +use ark_ec::CurveConfig; +use ark_ed_on_bls12_381_bandersnatch_ext::CurveHooks; +use sp_runtime_interface::runtime_interface; +use sp_std::vec::Vec; + +/// Curve hooks jumping into [`host_calls`] host functions. +#[derive(Copy, Clone)] +pub struct HostHooks; + +/// Group configuration. +pub type BandersnatchConfig = ark_ed_on_bls12_381_bandersnatch_ext::BandersnatchConfig; +/// Group configuration for Twisted Edwards form (equal to [`BandersnatchConfig`]). +pub type EdwardsConfig = ark_ed_on_bls12_381_bandersnatch_ext::EdwardsConfig; +/// Twisted Edwards form point affine representation. +pub type EdwardsAffine = ark_ed_on_bls12_381_bandersnatch_ext::EdwardsAffine; +/// Twisted Edwards form point projective representation. +pub type EdwardsProjective = ark_ed_on_bls12_381_bandersnatch_ext::EdwardsProjective; +/// Group configuration for Short Weierstrass form (equal to [`BandersnatchConfig`]). +pub type SWConfig = ark_ed_on_bls12_381_bandersnatch_ext::SWConfig; +/// Short Weierstrass form point affine representation. +pub type SWAffine = ark_ed_on_bls12_381_bandersnatch_ext::SWAffine; +/// Short Weierstrass form point projective representation. +pub type SWProjective = ark_ed_on_bls12_381_bandersnatch_ext::SWProjective; + +impl CurveHooks for HostHooks { + fn ed_on_bls12_381_bandersnatch_te_msm( + bases: &[EdwardsAffine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = + host_calls::ed_on_bls12_381_bandersnatch_te_msm(bases, scalars).unwrap_or_default(); + utils::decode_proj_te(res) + } + + fn ed_on_bls12_381_bandersnatch_te_mul_projective( + base: &EdwardsProjective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_te(base); + let scalar = utils::encode(scalar); + let res = host_calls::ed_on_bls12_381_bandersnatch_te_mul_projective(base, scalar) + .unwrap_or_default(); + utils::decode_proj_te(res) + } + + fn ed_on_bls12_381_bandersnatch_sw_msm( + bases: &[SWAffine], + scalars: &[::ScalarField], + ) -> Result { + let bases = utils::encode(bases); + let scalars = utils::encode(scalars); + let res = + host_calls::ed_on_bls12_381_bandersnatch_sw_msm(bases, scalars).unwrap_or_default(); + utils::decode_proj_sw(res) + } + + fn ed_on_bls12_381_bandersnatch_sw_mul_projective( + base: &SWProjective, + scalar: &[u64], + ) -> Result { + let base = utils::encode_proj_sw(base); + let scalar = utils::encode(scalar); + let res = host_calls::ed_on_bls12_381_bandersnatch_sw_mul_projective(base, scalar) + .unwrap_or_default(); + utils::decode_proj_sw(res) + } +} + +/// Interfaces for working with *Arkworks* *Ed-on-BLS12-381-Bandersnatch* elliptic curve +/// 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 "not-validated" +/// and "not-compressed". +#[runtime_interface] +pub trait HostCalls { + /// Twisted Edwards multi scalar multiplication for *Ed-on-BLS12-381-Bandersnatch*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_381_bandersnatch_te_msm( + bases: Vec, + scalars: Vec, + ) -> Result, ()> { + utils::msm_te::(bases, scalars) + } + + /// Twisted Edwards projective multiplication for *Ed-on-BLS12-381-Bandersnatch*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_381_bandersnatch_te_mul_projective( + base: Vec, + scalar: Vec, + ) -> Result, ()> { + utils::mul_projective_te::(base, scalar) + } + + /// Short Weierstrass multi scalar multiplication for *Ed-on-BLS12-381-Bandersnatch*. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale>`. + /// - `scalars`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_381_bandersnatch_sw_msm( + bases: Vec, + scalars: Vec, + ) -> Result, ()> { + utils::msm_sw::(bases, scalars) + } + + /// Short Weierstrass projective multiplication for *Ed-on-BLS12-381-Bandersnatch*. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale>`. + /// - Returns encoded: `ArkScaleProjective`. + fn ed_on_bls12_381_bandersnatch_sw_mul_projective( + base: Vec, + scalar: Vec, + ) -> Result, ()> { + utils::mul_projective_sw::(base, scalar) + } +} diff --git a/substrate/primitives/crypto/ec-utils/src/lib.rs b/substrate/primitives/crypto/ec-utils/src/lib.rs index c5cc8507739..e3aea98faa1 100644 --- a/substrate/primitives/crypto/ec-utils/src/lib.rs +++ b/substrate/primitives/crypto/ec-utils/src/lib.rs @@ -15,272 +15,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Elliptic Curves host functions which may be used to handle some of the *Arkworks* -//! computationally expensive operations. +//! Elliptic curves which are mostly compatible with *Arkworks* library +//! mostly useful in non-native contexts. +//! +//! The definitions make use of host functions to offload the non-native +//! computational environment from the some of the most computationally +//! expensive operations by internally leveraging the +//! [arkworks-extensions](https://github.com/paritytech/arkworks-extensions) +//! library. +//! +//! The exported types are organized and named in a way that mirrors the structure +//! of the types in the original Arkworks library. This design choice aims to make +//! it easier for users already familiar with the library to understand and utilize +//! the exported types effectively. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "bls12-377")] +pub mod bls12_377; +#[cfg(feature = "bls12-381")] +pub mod bls12_381; +#[cfg(feature = "bw6-761")] +pub mod bw6_761; +#[cfg(feature = "ed-on-bls12-377")] +pub mod ed_on_bls12_377; +#[cfg(feature = "ed-on-bls12-381-bandersnatch")] +pub mod ed_on_bls12_381_bandersnatch; + +#[cfg(any( + feature = "bls12-377", + feature = "bls12-381", + feature = "bw6-761", + feature = "ed-on-bls12-377", + feature = "ed-on-bls12-381-bandersnatch", +))] mod utils; - -use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; -use utils::*; - -/// 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 { - /// 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, ()> { - multi_miller_loop::(a, b) - } - - /// Pairing final exponentiation for BLS12-377. - /// - /// - Receives encoded: `ArkScale>>`. - /// - Returns encoded: `ArkScale>>`. - fn bls12_377_final_exponentiation(f: Vec) -> Result, ()> { - final_exponentiation::(f) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - msm_sw::(bases, scalars) - } - - /// 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, ()> { - msm_sw::(bases, scalars) - } - - /// 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, ()> { - multi_miller_loop::(a, b) - } - - /// Pairing final exponentiation for BLS12-381. - /// - /// - Receives encoded: `ArkScale>>`. - /// - Returns encoded: `ArkScale>>`. - fn bls12_381_final_exponentiation(f: Vec) -> Result, ()> { - final_exponentiation::(f) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - msm_sw::(bases, scalars) - } - - /// 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, ()> { - msm_sw::(bases, scalars) - } - - /// 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, ()> { - multi_miller_loop::(a, b) - } - - /// Pairing final exponentiation for BW6-761. - /// - /// - Receives encoded: `ArkScale>>`. - /// - Returns encoded: `ArkScale>>`. - fn bw6_761_final_exponentiation(f: Vec) -> Result, ()> { - final_exponentiation::(f) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - msm_sw::(bases, bigints) - } - - /// 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, ()> { - msm_sw::(bases, bigints) - } - - /// 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, ()> { - mul_projective_te::(base, scalar) - } - - /// 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, ()> { - msm_te::(bases, scalars) - } - - /// 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, ()> { - mul_projective_sw::(base, scalar) - } - - /// 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, ()> { - mul_projective_te::(base, scalar) - } - - /// 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, ()> { - msm_sw::(bases, scalars) - } - - /// 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, ()> { - msm_te::(bases, scalars) - } -} diff --git a/substrate/primitives/crypto/ec-utils/src/utils.rs b/substrate/primitives/crypto/ec-utils/src/utils.rs index 063b8fac7ad..d0dd8ed8131 100644 --- a/substrate/primitives/crypto/ec-utils/src/utils.rs +++ b/substrate/primitives/crypto/ec-utils/src/utils.rs @@ -17,109 +17,100 @@ //! Generic executions of the operations for *Arkworks* elliptic curves. +// As not all functions are used by each elliptic curve and some elliptic +// curve may be excluded by the build we resort to `#[allow(unused)]` to +// suppress the expected warning. + use ark_ec::{ - pairing::{MillerLoopOutput, Pairing, PairingOutput}, - short_weierstrass, - short_weierstrass::SWCurveConfig, - twisted_edwards, - twisted_edwards::TECurveConfig, + pairing::{MillerLoopOutput, Pairing}, + short_weierstrass::{Affine as SWAffine, Projective as SWProjective, SWCurveConfig}, + twisted_edwards::{Affine as TEAffine, Projective as TEProjective, TECurveConfig}, CurveConfig, VariableBaseMSM, }; use ark_scale::{ - hazmat::ArkScaleProjective, + ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}, scale::{Decode, Encode}, }; use sp_std::vec::Vec; -// 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 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()) - .map_err(|_| ())?; +// SCALE encoding parameters shared by all the enabled modules +const SCALE_USAGE: u8 = ark_scale::make_usage(Compress::No, Validate::No); +type ArkScale = ark_scale::ArkScale; +type ArkScaleProjective = ark_scale::hazmat::ArkScaleProjective; - let result = Curve::multi_miller_loop(g1.0, g2.0).0; - - let result: ArkScale<::TargetField> = result.into(); - Ok(result.encode()) +#[inline(always)] +pub fn encode(val: T) -> Vec { + ArkScale::from(val).encode() } -pub fn final_exponentiation(target: Vec) -> Result, ()> { - let target = - ::TargetField> as Decode>::decode(&mut target.as_slice()) - .map_err(|_| ())?; - - let result = Curve::final_exponentiation(MillerLoopOutput(target.0)).ok_or(())?; - - let result: ArkScale> = result.into(); - Ok(result.encode()) +#[inline(always)] +pub fn decode(buf: Vec) -> Result { + ArkScale::::decode(&mut &buf[..]).map_err(|_| ()).map(|v| v.0) } -pub fn msm_sw(bases: Vec, scalars: Vec) -> Result, ()> { - let bases = - >> as Decode>::decode(&mut bases.as_slice()) - .map_err(|_| ())?; - let scalars = ::ScalarField>> as Decode>::decode( - &mut scalars.as_slice(), - ) - .map_err(|_| ())?; - - let result = - as VariableBaseMSM>::msm(&bases.0, &scalars.0) - .map_err(|_| ())?; - - let result: ArkScaleProjective> = result.into(); - Ok(result.encode()) +#[inline(always)] +pub fn encode_proj_sw(val: &SWProjective) -> Vec { + ArkScaleProjective::from(val).encode() } -pub fn msm_te(bases: Vec, scalars: Vec) -> Result, ()> { - let bases = - >> as Decode>::decode(&mut bases.as_slice()) - .map_err(|_| ())?; - let scalars = ::ScalarField>> as Decode>::decode( - &mut scalars.as_slice(), - ) - .map_err(|_| ())?; +#[inline(always)] +pub fn decode_proj_sw(buf: Vec) -> Result, ()> { + ArkScaleProjective::decode(&mut &buf[..]).map_err(|_| ()).map(|v| v.0) +} - let result = as VariableBaseMSM>::msm(&bases.0, &scalars.0) - .map_err(|_| ())?; +#[inline(always)] +pub fn encode_proj_te(val: &TEProjective) -> Vec { + ArkScaleProjective::from(val).encode() +} - let result: ArkScaleProjective> = result.into(); - Ok(result.encode()) +#[inline(always)] +pub fn decode_proj_te(buf: Vec) -> Result, ()> { + ArkScaleProjective::decode(&mut &buf[..]).map_err(|_| ()).map(|v| v.0) } -pub fn mul_projective_sw( - base: Vec, - scalar: Vec, -) -> Result, ()> { - let base = > as Decode>::decode( - &mut base.as_slice(), - ) - .map_err(|_| ())?; - let scalar = > as Decode>::decode(&mut scalar.as_slice()).map_err(|_| ())?; +#[allow(unused)] +pub fn multi_miller_loop(g1: Vec, g2: Vec) -> Result, ()> { + let g1 = decode::::G1Affine>>(g1)?; + let g2 = decode::::G2Affine>>(g2)?; + let res = T::multi_miller_loop(g1, g2); + Ok(encode(res.0)) +} - let result = ::mul_projective(&base.0, &scalar.0); +#[allow(unused)] +pub fn final_exponentiation(target: Vec) -> Result, ()> { + let target = decode::<::TargetField>(target)?; + let res = T::final_exponentiation(MillerLoopOutput(target)).ok_or(())?; + Ok(encode(res.0)) +} - let result: ArkScaleProjective> = result.into(); - Ok(result.encode()) +#[allow(unused)] +pub fn msm_sw(bases: Vec, scalars: Vec) -> Result, ()> { + let bases = decode::>>(bases)?; + let scalars = decode::::ScalarField>>(scalars)?; + let res = as VariableBaseMSM>::msm(&bases, &scalars).map_err(|_| ())?; + Ok(encode_proj_sw(&res)) } -pub fn mul_projective_te( - base: Vec, - scalar: Vec, -) -> Result, ()> { - let base = > as Decode>::decode( - &mut base.as_slice(), - ) - .map_err(|_| ())?; - let scalar = > as Decode>::decode(&mut scalar.as_slice()).map_err(|_| ())?; +#[allow(unused)] +pub fn msm_te(bases: Vec, scalars: Vec) -> Result, ()> { + let bases = decode::>>(bases)?; + let scalars = decode::::ScalarField>>(scalars)?; + let res = as VariableBaseMSM>::msm(&bases, &scalars).map_err(|_| ())?; + Ok(encode_proj_te(&res)) +} - let result = ::mul_projective(&base.0, &scalar.0); +#[allow(unused)] +pub fn mul_projective_sw(base: Vec, scalar: Vec) -> Result, ()> { + let base = decode_proj_sw::(base)?; + let scalar = decode::>(scalar)?; + let res = ::mul_projective(&base, &scalar); + Ok(encode_proj_sw(&res)) +} - let result: ArkScaleProjective> = result.into(); - Ok(result.encode()) +#[allow(unused)] +pub fn mul_projective_te(base: Vec, scalar: Vec) -> Result, ()> { + let base = decode_proj_te::(base)?; + let scalar = decode::>(scalar)?; + let res = ::mul_projective(&base, &scalar); + Ok(encode_proj_te(&res)) } -- GitLab From f1bfc08038252caf7f1225f668b4518a6149bb24 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:06:07 +0200 Subject: [PATCH 399/633] xcmp-queue: remove outdated bridging comment (#2095) Removed confusing and outdated `TODO`. --- cumulus/pallets/xcmp-queue/src/bridging.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 0fc3f1f39ea..78ccd4b6269 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -63,13 +63,6 @@ impl, Runtime: crate::Config> 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 -- GitLab From ada1ac3dcdfdf0cac66b0c8b6ecc12de9e8657c5 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 31 Oct 2023 13:33:01 -0300 Subject: [PATCH 400/633] [DNM] bump zombienet version (#2083) This version includes: - Move `spot` usage in CI to 50% - Fix `PodMonitor`, metrics will be relayed to grafana --- .gitlab-ci.yml | 2 +- polkadot/zombienet_tests/functional/0001-parachains-pvf.toml | 3 +-- .../zombienet_tests/functional/0002-parachains-disputes.toml | 1 - .../functional/0004-parachains-garbage-candidate.toml | 1 - polkadot/zombienet_tests/misc/0001-paritydb.toml | 1 - 5 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 069068369ab..835b668de25 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.71" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.75" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/polkadot/zombienet_tests/functional/0001-parachains-pvf.toml b/polkadot/zombienet_tests/functional/0001-parachains-pvf.toml index 9ae4d899e69..53205867fd1 100644 --- a/polkadot/zombienet_tests/functional/0001-parachains-pvf.toml +++ b/polkadot/zombienet_tests/functional/0001-parachains-pvf.toml @@ -4,7 +4,6 @@ timeout = 1000 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" [relaychain.default_resources] limits = { memory = "4G", cpu = "2" } @@ -133,4 +132,4 @@ genesis_state_generator = "undying-collator export-genesis-state --pov-size=1000 [types.Header] number = "u64" parent_hash = "Hash" -post_state = "Hash" \ No newline at end of file +post_state = "Hash" diff --git a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index e6aeb8e245c..c63d3e02170 100644 --- a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml @@ -8,7 +8,6 @@ timeout = 1000 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" default_command = "polkadot" [relaychain.default_resources] diff --git a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml index ef27d7b92f0..94eb6bb5bb1 100644 --- a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml +++ b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml @@ -9,7 +9,6 @@ bootnode = true [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" default_command = "polkadot" [relaychain.default_resources] diff --git a/polkadot/zombienet_tests/misc/0001-paritydb.toml b/polkadot/zombienet_tests/misc/0001-paritydb.toml index 99dc9c66e26..e2130963f0e 100644 --- a/polkadot/zombienet_tests/misc/0001-paritydb.toml +++ b/polkadot/zombienet_tests/misc/0001-paritydb.toml @@ -9,7 +9,6 @@ bootnode = true [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "polkadot build-spec --chain rococo-local" default_command = "polkadot" [relaychain.default_resources] -- GitLab From 64f4b15640f3ee0f2e5d00d8603c8d9771f7ce61 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:40:12 +0200 Subject: [PATCH 401/633] polkadot: parachains: Fix v9 host configuration migration (#2103) We shouldn't override with their default fields that have been added in the previous version(v8), because we are going to lose whatever values have been set. Note, v8 & v9 seems to have landed at the same time on Rococo, probably they will land at the same time on westend and other chains, so functionally doesn't make much difference, but let's have this fixed for people that copy-paste :D, like me. --------- Signed-off-by: Alexandru Gheorghe --- .../parachains/src/configuration/migration/v9.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/polkadot/runtime/parachains/src/configuration/migration/v9.rs b/polkadot/runtime/parachains/src/configuration/migration/v9.rs index 64d71e628f4..e37f0b9b0e3 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v9.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v9.rs @@ -24,7 +24,6 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{SessionIndex, LEGACY_MIN_BACKING_VOTES}; -use sp_runtime::Perbill; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; @@ -145,11 +144,11 @@ pvf_voting_ttl : pre.pvf_voting_ttl, minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, async_backing_params : pre.async_backing_params, executor_params : pre.executor_params, -on_demand_queue_max_size : 10_000u32, -on_demand_base_fee : 10_000_000u128, -on_demand_fee_variability : Perbill::from_percent(3), -on_demand_target_queue_utilization : Perbill::from_percent(25), -on_demand_ttl : 5u32.into(), +on_demand_queue_max_size : pre.on_demand_queue_max_size, +on_demand_base_fee : pre.on_demand_base_fee, +on_demand_fee_variability : pre.on_demand_fee_variability, +on_demand_target_queue_utilization : pre.on_demand_target_queue_utilization, +on_demand_ttl : pre.on_demand_ttl, minimum_backing_votes : LEGACY_MIN_BACKING_VOTES } }; -- GitLab From 6e2f94f81c79665cc573ab738f209780d61e9bf0 Mon Sep 17 00:00:00 2001 From: Adel Arja Date: Tue, 31 Oct 2023 14:35:19 -0300 Subject: [PATCH 402/633] 1953 defensive testing extrinsic (#1998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description The `trigger_defensive` call has been added to the `root-testing` pallet. The idea is to have this pallet running on `Rococo/Westend` and use it to verify if the runtime monitoring works end-to-end. To accomplish this, `trigger_defensive` dispatches an event when it is called. Closes #1953 # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` 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) You can remove the "Checklist" section once all have been checked. Thank you for your contribution! ✄ ----------------------------------------------------------------------------- --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 2 ++ polkadot/runtime/rococo/Cargo.toml | 3 +++ polkadot/runtime/rococo/src/lib.rs | 7 +++++++ polkadot/runtime/westend/Cargo.toml | 3 +++ polkadot/runtime/westend/src/lib.rs | 7 +++++++ substrate/bin/node/runtime/src/lib.rs | 4 +++- substrate/frame/root-testing/src/lib.rs | 24 +++++++++++++++++++--- substrate/frame/support/src/traits/misc.rs | 6 +++--- substrate/frame/utility/src/tests.rs | 6 ++++-- 9 files changed, 53 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cedf9f2c74..a292f0cb1ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14350,6 +14350,7 @@ dependencies = [ "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", + "pallet-root-testing", "pallet-scheduler", "pallet-session", "pallet-society", @@ -20370,6 +20371,7 @@ dependencies = [ "pallet-proxy", "pallet-recovery", "pallet-referenda", + "pallet-root-testing", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 243f4337cae..5b55d3fec50 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -86,6 +86,7 @@ pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = 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 } +pallet-root-testing = { path = "../../../substrate/frame/root-testing", 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 } @@ -161,6 +162,7 @@ std = [ "pallet-ranked-collective/std", "pallet-recovery/std", "pallet-referenda/std", + "pallet-root-testing/std", "pallet-scheduler/std", "pallet-session/std", "pallet-society/std", @@ -290,6 +292,7 @@ try-runtime = [ "pallet-ranked-collective/try-runtime", "pallet-recovery/try-runtime", "pallet-referenda/try-runtime", + "pallet-root-testing/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-society/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index e6ad061ce06..b127eda3ba9 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1230,6 +1230,10 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = weights::pallet_sudo::WeightInfo; } +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + impl pallet_asset_rate::Config for Runtime { type WeightInfo = weights::pallet_asset_rate::WeightInfo; type RuntimeEvent = RuntimeEvent; @@ -1368,6 +1372,9 @@ construct_runtime! { // State trie migration pallet, only temporary. StateTrieMigration: pallet_state_trie_migration = 254, + // Root testing pallet. + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 249, + // Sudo. Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index cb1118cf92f..4148d610591 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -92,6 +92,7 @@ pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = 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 } +pallet-root-testing = { path = "../../../substrate/frame/root-testing", 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 } @@ -177,6 +178,7 @@ std = [ "pallet-proxy/std", "pallet-recovery/std", "pallet-referenda/std", + "pallet-root-testing/std", "pallet-scheduler/std", "pallet-session-benchmarking?/std", "pallet-session/std", @@ -315,6 +317,7 @@ try-runtime = [ "pallet-proxy/try-runtime", "pallet-recovery/try-runtime", "pallet-referenda/try-runtime", + "pallet-root-testing/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-society/try-runtime", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9ee4f3cf23e..b8b2e540e96 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1349,6 +1349,10 @@ impl pallet_nomination_pools::Config for Runtime { type MaxPointsToBalance = MaxPointsToBalance; } +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + 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; @@ -1483,6 +1487,9 @@ construct_runtime! { // Asset rate. AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event} = 101, + + // Root testing pallet. + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 102, } } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f3c24897632..cb8d7f6b1de 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1014,7 +1014,9 @@ impl pallet_remark::Config for Runtime { type RuntimeEvent = RuntimeEvent; } -impl pallet_root_testing::Config for Runtime {} +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; diff --git a/substrate/frame/root-testing/src/lib.rs b/substrate/frame/root-testing/src/lib.rs index bbcda09c306..51fd835409a 100644 --- a/substrate/frame/root-testing/src/lib.rs +++ b/substrate/frame/root-testing/src/lib.rs @@ -24,8 +24,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::dispatch::DispatchResult; -use sp_runtime::Perbill; +use frame_support::{dispatch::DispatchResult, sp_runtime::Perbill}; pub use pallet::*; @@ -36,11 +35,21 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } #[pallet::pallet] pub struct Pallet(_); + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Event dispatched when the trigger_defensive extrinsic is called. + DefensiveTestCall, + } + #[pallet::call] impl Pallet { /// A dispatch that will fill the block weight up to the given ratio. @@ -50,5 +59,14 @@ pub mod pallet { ensure_root(origin)?; Ok(()) } + + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn trigger_defensive(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + frame_support::defensive!("root_testing::trigger_defensive was called."); + Self::deposit_event(Event::DefensiveTestCall); + Ok(()) + } } } diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 45a3bba9b3a..78032cc0a94 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -55,7 +55,7 @@ impl VariantCount for () { macro_rules! defensive { () => { frame_support::__private::log::error!( - target: "runtime", + target: "runtime::defensive", "{}", $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR ); @@ -63,7 +63,7 @@ macro_rules! defensive { }; ($error:expr $(,)?) => { frame_support::__private::log::error!( - target: "runtime", + target: "runtime::defensive", "{}: {:?}", $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR, $error @@ -72,7 +72,7 @@ macro_rules! defensive { }; ($error:expr, $proof:expr $(,)?) => { frame_support::__private::log::error!( - target: "runtime", + target: "runtime::defensive", "{}: {:?}: {:?}", $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR, $error, diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index cbd495a5c15..01e3f5264bf 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -132,7 +132,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Timestamp: pallet_timestamp::{Call, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - RootTesting: pallet_root_testing::{Pallet, Call, Storage}, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event}, Council: pallet_collective::, Utility: utility::{Pallet, Call, Event}, Example: example::{Pallet, Call}, @@ -187,7 +187,9 @@ impl pallet_balances::Config for Test { type MaxHolds = (); } -impl pallet_root_testing::Config for Test {} +impl pallet_root_testing::Config for Test { + type RuntimeEvent = RuntimeEvent; +} impl pallet_timestamp::Config for Test { type Moment = u64; -- GitLab From 495d24d730bb9c2205a5305f383627eabda4a323 Mon Sep 17 00:00:00 2001 From: Lulu Date: Tue, 31 Oct 2023 18:04:31 +0000 Subject: [PATCH 403/633] Add ci check for parity-publish and fix current check issues (#1887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Co-authored-by: Bastian Köcher --- .github/workflows/check-publish.yml | 28 ++ .gitlab/pipeline/build.yml | 2 +- .gitlab/pipeline/test.yml | 4 +- Cargo.lock | 388 +++++++++--------- cumulus/client/cli/Cargo.toml | 1 + cumulus/client/collator/Cargo.toml | 1 + cumulus/client/consensus/aura/Cargo.toml | 1 + cumulus/client/consensus/common/Cargo.toml | 1 + cumulus/client/consensus/proposer/Cargo.toml | 1 + .../client/consensus/relay-chain/Cargo.toml | 1 + cumulus/client/network/Cargo.toml | 1 + cumulus/client/pov-recovery/Cargo.toml | 1 + .../Cargo.toml | 1 + .../client/relay-chain-interface/Cargo.toml | 1 + .../relay-chain-minimal-node/Cargo.toml | 1 + .../relay-chain-rpc-interface/Cargo.toml | 1 + cumulus/client/service/Cargo.toml | 1 + cumulus/pallets/aura-ext/Cargo.toml | 1 + cumulus/pallets/dmp-queue/Cargo.toml | 1 + cumulus/pallets/parachain-system/Cargo.toml | 1 + .../parachain-system/proc-macro/Cargo.toml | 1 + cumulus/pallets/solo-to-para/Cargo.toml | 1 + cumulus/pallets/xcm/Cargo.toml | 1 + cumulus/pallets/xcmp-queue/Cargo.toml | 1 + cumulus/pallets/xcmp-queue/src/bridging.rs | 4 +- cumulus/pallets/xcmp-queue/src/tests.rs | 22 +- cumulus/parachain-template/runtime/Cargo.toml | 2 +- cumulus/parachains/common/Cargo.toml | 3 +- .../pallets/collective-content/Cargo.toml | 1 + .../pallets/parachain-info/Cargo.toml | 3 +- cumulus/parachains/pallets/ping/Cargo.toml | 1 + .../assets/asset-hub-kusama/Cargo.toml | 3 +- .../assets/asset-hub-polkadot/Cargo.toml | 3 +- .../assets/asset-hub-rococo/Cargo.toml | 3 +- .../assets/asset-hub-westend/Cargo.toml | 3 +- .../runtimes/assets/common/Cargo.toml | 1 + .../runtimes/assets/test-utils/Cargo.toml | 3 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 3 +- .../bridge-hub-polkadot/Cargo.toml | 3 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 3 +- .../bridge-hubs/test-utils/Cargo.toml | 3 +- .../collectives-polkadot/Cargo.toml | 3 +- .../contracts/contracts-rococo/Cargo.toml | 3 +- .../glutton/glutton-kusama/Cargo.toml | 3 +- .../runtimes/starters/seedling/Cargo.toml | 3 +- .../runtimes/starters/shell/Cargo.toml | 3 +- .../parachains/runtimes/test-utils/Cargo.toml | 3 +- .../runtimes/testing/penpal/Cargo.toml | 2 +- .../testing/rococo-parachain/Cargo.toml | 4 +- cumulus/polkadot-parachain/Cargo.toml | 1 + cumulus/primitives/aura/Cargo.toml | 1 + cumulus/primitives/core/Cargo.toml | 1 + .../primitives/parachain-inherent/Cargo.toml | 1 + cumulus/primitives/timestamp/Cargo.toml | 1 + cumulus/primitives/utility/Cargo.toml | 1 + cumulus/test/relay-sproof-builder/Cargo.toml | 1 + cumulus/xcm/xcm-emulator/Cargo.toml | 1 + substrate/Cargo.toml | 3 +- substrate/bin/node/cli/Cargo.toml | 8 +- .../bin/node/cli/benches/block_production.rs | 1 + .../bin/node/cli/benches/transaction_pool.rs | 1 + substrate/bin/node/cli/bin/main.rs | 2 + substrate/bin/node/executor/Cargo.toml | 2 +- substrate/bin/node/executor/benches/bench.rs | 1 + substrate/bin/node/executor/tests/common.rs | 1 + substrate/bin/node/inspect/Cargo.toml | 3 +- substrate/bin/node/testing/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 5 +- .../bin/utils/chain-spec-builder/bin/main.rs | 1 + substrate/frame/asset-rate/Cargo.toml | 1 - .../frame/examples/frame-crate/Cargo.toml | 1 - .../procedural/src/pallet/expand/warnings.rs | 8 +- substrate/scripts/ci/deny.toml | 2 +- substrate/test-utils/cli/Cargo.toml | 2 +- substrate/test-utils/cli/src/lib.rs | 2 +- 75 files changed, 334 insertions(+), 250 deletions(-) create mode 100644 .github/workflows/check-publish.yml diff --git a/.github/workflows/check-publish.yml b/.github/workflows/check-publish.yml new file mode 100644 index 00000000000..9ab47dba51b --- /dev/null +++ b/.github/workflows/check-publish.yml @@ -0,0 +1,28 @@ +name: Check publish + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + check-publish: + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + + - name: Rust Cache + uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 # v2.7.1 + with: + cache-on-failure: true + + - name: install parity-publish + run: cargo install parity-publish --profile dev + + - name: parity-publish check + run: parity-publish check --allow-unpublished diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index fefa3739a9f..5c13045706c 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -305,7 +305,7 @@ build-linux-substrate: # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" script: - - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release -p node-cli + - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release -p staging-node-cli - mv $CARGO_TARGET_DIR/release/substrate-node ./artifacts/substrate/substrate - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 7d7007acd8a..4ed3ec19c48 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -352,7 +352,7 @@ quick-benchmarks: WASM_BUILD_NO_COLOR: 1 WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" script: - - time cargo run --locked --release -p node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - time cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 test-frame-examples-compile-to-wasm: # into one job @@ -396,7 +396,7 @@ test-linux-stable-int: script: - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace - time cargo test -p node-cli --release --locked -- --ignored + time cargo test -p staging-node-cli --release --locked -- --ignored # more information about this job can be found here: # https://github.com/paritytech/substrate/pull/6916 diff --git a/Cargo.lock b/Cargo.lock index a292f0cb1ab..f2b9b9ec45d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -774,7 +774,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -797,6 +796,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -844,7 +844,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -866,6 +865,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -947,7 +947,6 @@ dependencies = [ "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub-router", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -970,6 +969,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1052,7 +1052,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -1075,6 +1074,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1102,7 +1102,6 @@ dependencies = [ "pallet-session", "pallet-xcm", "pallet-xcm-bridge-hub-router", - "parachain-info", "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", @@ -1112,6 +1111,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1994,7 +1994,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2017,6 +2016,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2057,7 +2057,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2080,6 +2079,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2160,7 +2160,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2185,6 +2184,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2225,7 +2225,6 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", - "parachain-info", "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", @@ -2234,6 +2233,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "sp-tracing", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2502,20 +2502,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "chain-spec-builder" -version = "2.0.0" -dependencies = [ - "ansi_term", - "clap 4.4.6", - "node-cli", - "rand 0.8.5", - "sc-chain-spec", - "sc-keystore", - "sp-core", - "sp-keystore", -] - [[package]] name = "chrono" version = "0.4.27" @@ -2772,7 +2758,6 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2795,6 +2780,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2983,7 +2969,6 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -3005,6 +2990,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -6011,7 +5997,6 @@ dependencies = [ "pallet-glutton", "pallet-sudo", "pallet-timestamp", - "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", @@ -6028,6 +6013,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -8468,151 +8454,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "node-cli" -version = "3.0.0-dev" -dependencies = [ - "array-bytes 6.1.0", - "assert_cmd", - "clap 4.4.6", - "clap_complete", - "criterion 0.4.0", - "frame-benchmarking-cli", - "frame-system", - "frame-system-rpc-runtime-api", - "futures", - "jsonrpsee", - "kitchensink-runtime", - "log", - "nix 0.26.2", - "node-executor", - "node-inspect", - "node-primitives", - "node-rpc", - "pallet-asset-conversion-tx-payment", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-balances", - "pallet-im-online", - "pallet-timestamp", - "parity-scale-codec", - "platforms", - "rand 0.8.5", - "regex", - "sc-authority-discovery", - "sc-basic-authorship", - "sc-block-builder", - "sc-chain-spec", - "sc-cli", - "sc-client-api", - "sc-client-db", - "sc-consensus", - "sc-consensus-babe", - "sc-consensus-epochs", - "sc-consensus-grandpa", - "sc-consensus-slots", - "sc-executor", - "sc-keystore", - "sc-mixnet", - "sc-network", - "sc-network-common", - "sc-network-statement", - "sc-network-sync", - "sc-offchain", - "sc-rpc", - "sc-service", - "sc-service-test", - "sc-statement-store", - "sc-storage-monitor", - "sc-sync-state-rpc", - "sc-sysinfo", - "sc-telemetry", - "sc-transaction-pool", - "sc-transaction-pool-api", - "serde", - "serde_json", - "soketto", - "sp-api", - "sp-authority-discovery", - "sp-blockchain", - "sp-consensus", - "sp-consensus-babe", - "sp-consensus-grandpa", - "sp-core", - "sp-inherents", - "sp-io", - "sp-keyring", - "sp-keystore", - "sp-mixnet", - "sp-runtime", - "sp-statement-store", - "sp-timestamp", - "sp-tracing", - "sp-transaction-storage-proof", - "substrate-build-script-utils", - "substrate-cli-test-utils", - "substrate-frame-cli", - "substrate-rpc-client", - "tempfile", - "tokio", - "tokio-util", - "try-runtime-cli", - "wait-timeout", -] - -[[package]] -name = "node-executor" -version = "3.0.0-dev" -dependencies = [ - "criterion 0.4.0", - "frame-benchmarking", - "frame-support", - "frame-system", - "futures", - "kitchensink-runtime", - "node-primitives", - "node-testing", - "pallet-balances", - "pallet-contracts", - "pallet-glutton", - "pallet-im-online", - "pallet-root-testing", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-treasury", - "parity-scale-codec", - "sc-executor", - "scale-info", - "sp-application-crypto", - "sp-consensus-babe", - "sp-core", - "sp-externalities", - "sp-keyring", - "sp-keystore", - "sp-runtime", - "sp-state-machine", - "sp-statement-store", - "sp-tracing", - "sp-trie", - "wat", -] - -[[package]] -name = "node-inspect" -version = "0.9.0-dev" -dependencies = [ - "clap 4.4.6", - "parity-scale-codec", - "sc-cli", - "sc-client-api", - "sc-service", - "sp-blockchain", - "sp-core", - "sp-runtime", - "thiserror", -] - [[package]] name = "node-primitives" version = "2.0.0" @@ -8766,7 +8607,6 @@ dependencies = [ "futures", "kitchensink-runtime", "log", - "node-executor", "node-primitives", "pallet-asset-conversion", "pallet-asset-conversion-tx-payment", @@ -8789,6 +8629,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "sp-timestamp", + "staging-node-executor", "substrate-test-client", "tempfile", ] @@ -11135,19 +10976,6 @@ dependencies = [ "staging-xcm-builder", ] -[[package]] -name = "parachain-info" -version = "0.1.0" -dependencies = [ - "cumulus-primitives-core", - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std", -] - [[package]] name = "parachain-template-node" version = "0.1.0" @@ -11237,7 +11065,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-xcm", - "parachain-info", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-common", @@ -11255,6 +11082,7 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -11276,7 +11104,6 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", - "parachain-info", "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", @@ -11288,6 +11115,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "substrate-wasm-builder", @@ -11313,7 +11141,6 @@ dependencies = [ "pallet-collator-selection", "pallet-session", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", @@ -11323,6 +11150,7 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", + "staging-parachain-info", "staging-xcm", "staging-xcm-executor", "substrate-wasm-builder", @@ -11557,7 +11385,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", @@ -11578,6 +11405,7 @@ dependencies = [ "sp-storage", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -14283,7 +14111,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-xcm", - "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", @@ -14301,6 +14128,7 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -16366,7 +16194,6 @@ dependencies = [ "pallet-balances", "pallet-sudo", "pallet-timestamp", - "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", @@ -16382,6 +16209,7 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "substrate-wasm-builder", ] @@ -16614,7 +16442,6 @@ dependencies = [ "frame-try-runtime", "pallet-aura", "pallet-timestamp", - "parachain-info", "parachains-common", "parity-scale-codec", "scale-info", @@ -16630,6 +16457,7 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -17865,6 +17693,178 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "staging-chain-spec-builder" +version = "2.0.0" +dependencies = [ + "ansi_term", + "clap 4.4.6", + "rand 0.8.5", + "sc-chain-spec", + "sc-keystore", + "sp-core", + "sp-keystore", + "staging-node-cli", +] + +[[package]] +name = "staging-node-cli" +version = "3.0.0-dev" +dependencies = [ + "array-bytes 6.1.0", + "assert_cmd", + "clap 4.4.6", + "clap_complete", + "criterion 0.4.0", + "frame-benchmarking-cli", + "frame-system", + "frame-system-rpc-runtime-api", + "futures", + "jsonrpsee", + "kitchensink-runtime", + "log", + "nix 0.26.2", + "node-primitives", + "node-rpc", + "pallet-asset-conversion-tx-payment", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-balances", + "pallet-im-online", + "pallet-timestamp", + "parity-scale-codec", + "platforms", + "rand 0.8.5", + "regex", + "sc-authority-discovery", + "sc-basic-authorship", + "sc-block-builder", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-consensus-babe", + "sc-consensus-epochs", + "sc-consensus-grandpa", + "sc-consensus-slots", + "sc-executor", + "sc-keystore", + "sc-mixnet", + "sc-network", + "sc-network-common", + "sc-network-statement", + "sc-network-sync", + "sc-offchain", + "sc-rpc", + "sc-service", + "sc-service-test", + "sc-statement-store", + "sc-storage-monitor", + "sc-sync-state-rpc", + "sc-sysinfo", + "sc-telemetry", + "sc-transaction-pool", + "sc-transaction-pool-api", + "serde", + "serde_json", + "soketto", + "sp-api", + "sp-authority-discovery", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keyring", + "sp-keystore", + "sp-mixnet", + "sp-runtime", + "sp-statement-store", + "sp-timestamp", + "sp-tracing", + "sp-transaction-storage-proof", + "staging-node-executor", + "staging-node-inspect", + "substrate-build-script-utils", + "substrate-cli-test-utils", + "substrate-frame-cli", + "substrate-rpc-client", + "tempfile", + "tokio", + "tokio-util", + "try-runtime-cli", + "wait-timeout", +] + +[[package]] +name = "staging-node-executor" +version = "3.0.0-dev" +dependencies = [ + "criterion 0.4.0", + "frame-benchmarking", + "frame-support", + "frame-system", + "futures", + "kitchensink-runtime", + "node-primitives", + "node-testing", + "pallet-balances", + "pallet-contracts", + "pallet-glutton", + "pallet-im-online", + "pallet-root-testing", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "parity-scale-codec", + "sc-executor", + "scale-info", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-externalities", + "sp-keyring", + "sp-keystore", + "sp-runtime", + "sp-state-machine", + "sp-statement-store", + "sp-tracing", + "sp-trie", + "wat", +] + +[[package]] +name = "staging-node-inspect" +version = "0.9.0-dev" +dependencies = [ + "clap 4.4.6", + "parity-scale-codec", + "sc-cli", + "sc-client-api", + "sc-service", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "staging-parachain-info" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "staging-xcm" version = "1.0.0" @@ -18051,7 +18051,6 @@ dependencies = [ name = "substrate" version = "1.0.0" dependencies = [ - "chain-spec-builder", "frame-support", "sc-cli", "sc-consensus-aura", @@ -18063,6 +18062,7 @@ dependencies = [ "sc-service", "simple-mermaid", "sp-runtime", + "staging-chain-spec-builder", "subkey", ] @@ -18090,12 +18090,12 @@ dependencies = [ "assert_cmd", "futures", "nix 0.26.2", - "node-cli", "node-primitives", "regex", "sc-cli", "sc-service", "sp-rpc", + "staging-node-cli", "substrate-rpc-client", "tokio", ] diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 5dd18f0c156..5d9752dbb20 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-cli" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] clap = { version = "4.4.6", features = ["derive"] } diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 1d87efa443c..30798f84800 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-collator" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] parking_lot = "0.12.1" diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 8239a498746..f440270c982 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -4,6 +4,7 @@ description = "AURA consensus algorithm for parachains" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 26d7ba1b142..9dfd14b1cf5 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -4,6 +4,7 @@ description = "Cumulus specific common consensus implementations" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index 29720a8f479..4cfba66cec3 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -4,6 +4,7 @@ description = "A Substrate `Proposer` for building parachain blocks" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] anyhow = "1.0" diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index ba077f62403..de280e6e9a8 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -4,6 +4,7 @@ description = "The relay-chain provided consensus algorithm" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index eaaf497ac3e..08956f9f6c6 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true description = "Cumulus-specific networking protocol" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 2ce903fd352..e407b33e0e2 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true description = "Cumulus-specific networking protocol" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index bc8d0d430c7..19c99c5cb72 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 3da7ab0b0e8..803df7d302b 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-interface" version = "0.1.0" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] polkadot-overseer = { path = "../../../polkadot/node/overseer" } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index f132b1a7653..6518e09cbb5 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-minimal-node" version = "0.1.0" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] # polkadot deps diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 0f09377e106..102ce75508d 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index b7c274ceecd..314aebdcb9c 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-service" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] futures = "0.3.28" diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index 78d25f2285e..c9d82ead1eb 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "AURA consensus extension pallet for parachains" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 2f3f660ea15..3d48074d5c5 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-pallet-dmp-queue" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index d48604d5025..76a77651cac 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Base pallet for cumulus-based parachains" +license = "Apache-2.0" [dependencies] bytes = { version = "1.4.0", default-features = false } diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index cb5d9904c7c..6accfa92c57 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Proc macros provided by the parachain-system pallet" +license = "Apache-2.0" [lib] proc-macro = true diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index af419cc37db..e4ef72965c7 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Adds functionality to migrate from a Solo to a Parachain" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 853dd86bb4c..d79e57bceac 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true edition.workspace = true name = "cumulus-pallet-xcm" version = "0.1.0" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index b923c16cb1b..fdb5654d59f 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 78ccd4b6269..9db4b6e74c3 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -55,7 +55,9 @@ impl, Runtime: crate::Config> 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 { + let Some((outbound_state, queued_pages)) = + pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) + else { return false }; // suspended channel => it is congested diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index cf6d947609d..bab7e92ca2d 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -410,9 +410,11 @@ fn verify_fee_factor_increase_and_decrease() { assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); // Sending the message right now is cheap - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 402_000_000); let smaller_xcm = Xcm(vec![ClearOrigin; 30]); @@ -422,19 +424,23 @@ fn verify_fee_factor_increase_and_decrease() { assert_ok!(send_xcm::(destination, xcm.clone())); // Size 520 assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), FixedU128::from_float(1.05)); - for _ in 0..12 { // We finish at size 929 + for _ in 0..12 { + // We finish at size 929 assert_ok!(send_xcm::(destination, smaller_xcm.clone())); } assert!(DeliveryFeeFactor::::get(sibling_para_id) > FixedU128::from_float(1.88)); // Sending the message right now is expensive - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 758_030_955); // Fee factor only decreases in `take_outbound_messages` - for _ in 0..5 { // We take 5 100 byte pages + for _ in 0..5 { + // We take 5 100 byte pages XcmpQueue::take_outbound_messages(1); } assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.72)); diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 2e5bdab1e21..06e818dcdbc 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -71,7 +71,7 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature 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 = "../../parachains/pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../parachains/pallets/parachain-info", default-features = false } [features] default = [ "std" ] diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 92c7cb6ef12..ebb3cdeaa5d 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Logic which is common to all parachain runtimes" +license = "Apache-2.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -40,7 +41,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } -parachain-info = { path = "../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../pallets/parachain-info", default-features = false } [dev-dependencies] pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false} diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index e85112ed8ea..e3f8023f419 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" description = "Managed content" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index c63101bab91..40f1a07c2dd 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -1,8 +1,9 @@ [package] authors.workspace = true edition.workspace = true -name = "parachain-info" +name = "staging-parachain-info" version = "0.1.0" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 3acad9f371d..0ea424e1a2d 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true edition.workspace = true name = "cumulus-ping" version = "0.1.0" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index ede9c6af35a..bde9cce7531 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -4,6 +4,7 @@ version = "0.9.420" authors.workspace = true edition.workspace = true description = "Kusama variant of Asset Hub parachain runtime" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -75,7 +76,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index db400f2977f..4c3651eb8cf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -4,6 +4,7 @@ version = "0.9.420" authors.workspace = true edition.workspace = true description = "Asset Hub Polkadot parachain runtime" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -70,7 +71,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index ebf811e5463..d8a8f224aae 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -4,6 +4,7 @@ version = "0.9.420" authors.workspace = true edition.workspace = true description = "Rococo variant of Asset Hub parachain runtime" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -75,7 +76,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 7c7a0731459..95e46f31243 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -4,6 +4,7 @@ version = "0.9.420" authors.workspace = true edition.workspace = true description = "Westend variant of Asset Hub parachain runtime" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -74,7 +75,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 770acc93c71..a7f2b86a6c8 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Assets common utilities" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 86cc72e2dd3..0bcbe79691c 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Test utils for Asset Hub runtimes." +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -30,7 +31,7 @@ assets-common = { path = "../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 } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } # Polkadot 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 603e74850cc..8572c9ba3d0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Kusama's BridgeHub parachain runtime" +license = "Apache-2.0" [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -68,7 +69,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [dev-dependencies] 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 535a0516997..b9b0f50006e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Polkadot's BridgeHub parachain runtime" +license = "Apache-2.0" [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -68,7 +69,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [dev-dependencies] 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 8c4e1612780..c7e31c80ce4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Rococo's BridgeHub parachain runtime" +license = "Apache-2.0" [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -69,7 +70,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } # Bridges diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 2ad79bb2488..40d7741fb38 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Utils for BridgeHub testing" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -29,7 +30,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-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 73d787caf86..b5f22c828e7 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Polkadot Collectives Parachain Runtime" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -73,7 +74,7 @@ cumulus-primitives-core = { path = "../../../../primitives/core", default-featur 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 } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [build-dependencies] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 0eb2428f358..1ee069d5cc3 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -4,6 +4,7 @@ version = "0.2.0" description = "Parachain testnet runtime for FRAME Contracts pallet." authors.workspace = true edition.workspace = true +license = "Apache-2.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -73,7 +74,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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [features] diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index f5362e4d6b2..6051d029a1d 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" description = "Glutton parachain runtime." authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } @@ -47,7 +48,7 @@ cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = fals 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 } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [build-dependencies] diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 18bee9982d0..65ca58ac8b3 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" description = "Seedling parachain runtime. A starter runtime for solochain to parachain migration." authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } @@ -36,7 +37,7 @@ cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system cumulus-pallet-solo-to-para = { path = "../../../../pallets/solo-to-para", 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 } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [build-dependencies] diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index ef4b62f985d..b9f63133cce 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" description = "A minimal runtime to test Relay Chain consensus." authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } @@ -39,7 +40,7 @@ cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-featu 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-core = { path = "../../../../primitives/core", default-features = false } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [build-dependencies] diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index c455807fd8f..9cc4b604f33 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true description = "Utils for Runtimes testing" +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } @@ -27,7 +28,7 @@ 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 } +parachain-info = {package = "staging-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 } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 13e52f8a3ba..d5db4a02034 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -72,7 +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 } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } [features] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 616d92b6940..4f45b3ea89b 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Simple runtime used by the rococo parachain(s)" -publish = false +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } @@ -54,7 +54,7 @@ cumulus-ping = { path = "../../../pallets/ping", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } parachains-common = { path = "../../../common", default-features = false } -parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 3c2069c81ef..6cacb5d764a 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -5,6 +5,7 @@ authors.workspace = true build = "build.rs" edition.workspace = true description = "Runs a polkadot parachain node which could be a collator." +license = "Apache-2.0" [[bin]] name = "polkadot-parachain" diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 791ec17378a..168c85b2efb 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-primitives-aura" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 3ce7b1da4a6..6c923a700ec 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-primitives-core" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 026d5a61bc8..5a448f65ada 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-primitives-parachain-inherent" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] async-trait = { version = "0.1.73", optional = true } diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index aed51a44912..a0fea51f8db 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true description = "Provides timestamp related functionality for parachains." +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index d50f93d89b7..c159bca5d2a 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-primitives-utility" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index e044b92f7c4..8807e4e2858 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-test-relay-sproof-builder" version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index c77d350bdfe..5d43b48ea32 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -4,6 +4,7 @@ description = "Test kit to emulate XCM program execution." version = "0.1.0" authors.workspace = true edition.workspace = true +license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 9e2e0b1a6ee..47cde0ca70c 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -7,13 +7,14 @@ repository.workspace = true authors.workspace = true edition.workspace = true version = "1.0.0" +publish = false # The dependencies are only needed for docs. [dependencies] simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } subkey = { path = "bin/utils/subkey" } -chain-spec-builder = { path = "bin/utils/chain-spec-builder" } +chain-spec-builder = { package = "staging-chain-spec-builder", path = "bin/utils/chain-spec-builder" } sc-service = { path = "client/service" } sc-cli = { path = "client/cli" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 49dc39099be..34cca4495da 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "node-cli" +name = "staging-node-cli" version = "3.0.0-dev" authors.workspace = true description = "Generic Substrate node implementation in Rust." @@ -101,12 +101,12 @@ pallet-im-online = { path = "../../../frame/im-online", default-features = false kitchensink-runtime = { path = "../runtime" } node-rpc = { path = "../rpc" } node-primitives = { path = "../primitives" } -node-executor = { path = "../executor" } +node-executor = { package = "staging-node-executor", path = "../executor" } # CLI-specific dependencies sc-cli = { path = "../../../client/cli", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} -node-inspect = { path = "../inspect", optional = true} +node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} serde_json = "1.0.107" @@ -139,7 +139,7 @@ substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] clap = { version = "4.4.6", optional = true } clap_complete = { version = "4.0.2", optional = true } -node-inspect = { path = "../inspect", optional = true} +node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} substrate-build-script-utils = { path = "../../../utils/build-script-utils", optional = true} substrate-frame-cli = { path = "../../../utils/frame/frame-utilities-cli", optional = true} diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 246de8f3e92..a22aa365e04 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,6 +39,7 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; +use staging_node_cli as node_cli; use tokio::runtime::Handle; fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 47f89057415..dd6c237d4dd 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -35,6 +35,7 @@ use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, Transacti use sp_core::{crypto::Pair, sr25519}; use sp_keyring::Sr25519Keyring; use sp_runtime::OpaqueExtrinsic; +use staging_node_cli as node_cli; use tokio::runtime::Handle; fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { diff --git a/substrate/bin/node/cli/bin/main.rs b/substrate/bin/node/cli/bin/main.rs index 4b434a3e6da..ccc7d7b6b11 100644 --- a/substrate/bin/node/cli/bin/main.rs +++ b/substrate/bin/node/cli/bin/main.rs @@ -20,6 +20,8 @@ #![warn(missing_docs)] +use staging_node_cli as node_cli; + fn main() -> sc_cli::Result<()> { node_cli::run() } diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml index f73d97eb8cf..5f43b5839e6 100644 --- a/substrate/bin/node/executor/Cargo.toml +++ b/substrate/bin/node/executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "node-executor" +name = "staging-node-executor" version = "3.0.0-dev" authors.workspace = true description = "Substrate node implementation in Rust." diff --git a/substrate/bin/node/executor/benches/bench.rs b/substrate/bin/node/executor/benches/bench.rs index 1c9c002492c..95c8afd5506 100644 --- a/substrate/bin/node/executor/benches/bench.rs +++ b/substrate/bin/node/executor/benches/bench.rs @@ -35,6 +35,7 @@ use sp_core::{ }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; +use staging_node_executor as node_executor; criterion_group!(benches, bench_execute_block); criterion_main!(benches); diff --git a/substrate/bin/node/executor/tests/common.rs b/substrate/bin/node/executor/tests/common.rs index 6ce9ea3a010..5f88ba85adf 100644 --- a/substrate/bin/node/executor/tests/common.rs +++ b/substrate/bin/node/executor/tests/common.rs @@ -42,6 +42,7 @@ use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; use sp_externalities::Externalities; +use staging_node_executor as node_executor; pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 4a92db29185..30cc22b0e8c 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "node-inspect" +name = "staging-node-inspect" version = "0.9.0-dev" authors.workspace = true description = "Substrate node block inspection tool." @@ -7,7 +7,6 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository.workspace = true -publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index f5a39693301..68f80ab6e83 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" log = "0.4.17" tempfile = "3.1.0" frame-system = { path = "../../../frame/system" } -node-executor = { path = "../executor" } +node-executor = { package = "staging-node-executor", path = "../executor" } node-primitives = { path = "../primitives" } kitchensink-runtime = { path = "../runtime" } pallet-asset-conversion = { path = "../../../frame/asset-conversion" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index c7690faf7d0..f25358e52c2 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "chain-spec-builder" +name = "staging-chain-spec-builder" version = "2.0.0" authors.workspace = true edition.workspace = true @@ -7,7 +7,6 @@ build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository.workspace = true -readme = "README.md" publish = false [package.metadata.docs.rs] @@ -24,7 +23,7 @@ crate-type = ["rlib"] ansi_term = "0.12.1" clap = { version = "4.4.6", features = ["derive"] } rand = "0.8" -node-cli = { path = "../../node/cli" } +node-cli = { package = "staging-node-cli", path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } sc-keystore = { path = "../../../client/keystore" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/bin/utils/chain-spec-builder/bin/main.rs b/substrate/bin/utils/chain-spec-builder/bin/main.rs index 53e11abbf62..a002f6dc0e7 100644 --- a/substrate/bin/utils/chain-spec-builder/bin/main.rs +++ b/substrate/bin/utils/chain-spec-builder/bin/main.rs @@ -23,6 +23,7 @@ use clap::Parser; use node_cli::chain_spec; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use sp_core::{crypto::Ss58Codec, sr25519}; +use staging_chain_spec_builder as chain_spec_builder; use std::fs; fn main() -> Result<(), String> { diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 8de62aca5ec..734bc5ef43f 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -7,7 +7,6 @@ homepage = "https://substrate.io" edition.workspace = true license = "Apache-2.0" repository.workspace = true -publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index d525008e525..854ee8b55c8 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -7,7 +7,6 @@ license = "MIT-0" homepage = "https://substrate.io" repository.workspace = true description = "FRAME example pallet with umbrella crate" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index 6ce2097c268..030e3ddaf32 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,9 +33,7 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } - let CallWeightDef::Immediate(w) = &method.weight else { - return - }; + let CallWeightDef::Immediate(w) = &method.weight else { return }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") .old("not check weight witness data") @@ -66,9 +64,7 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } - let syn::Expr::Lit(lit) = weight else { - return - }; + let syn::Expr::Lit(lit) = weight else { return }; let warning = Warning::new_deprecated("ConstantWeight") .index(warnings.len()) diff --git a/substrate/scripts/ci/deny.toml b/substrate/scripts/ci/deny.toml index ca059e384a3..1afb4a4f693 100644 --- a/substrate/scripts/ci/deny.toml +++ b/substrate/scripts/ci/deny.toml @@ -38,7 +38,7 @@ exceptions = [ { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "chain-spec-builder" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "mmr-gadget" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-bench" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-cli" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "staging-node-cli" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-inspect" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-template-release" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-testing" }, diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index 9c4167c9b6e..022db32c34f 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -20,7 +20,7 @@ nix = "0.26.2" regex = "1.7.3" tokio = { version = "1.22.0", features = ["full"] } node-primitives = { path = "../../bin/node/primitives" } -node-cli = { path = "../../bin/node/cli" } +node-cli = { package = "staging-node-cli", path = "../../bin/node/cli" } sc-cli = { path = "../../client/cli" } sc-service = { path = "../../client/service" } futures = "0.3.28" diff --git a/substrate/test-utils/cli/src/lib.rs b/substrate/test-utils/cli/src/lib.rs index 99119a44d2e..d77a89b4dbf 100644 --- a/substrate/test-utils/cli/src/lib.rs +++ b/substrate/test-utils/cli/src/lib.rs @@ -135,7 +135,7 @@ pub fn build_substrate(args: &[&str]) { // Get the root workspace directory from the CARGO_MANIFEST_DIR environment variable let mut cmd = Command::new("cargo"); - cmd.arg("build").arg("-p=node-cli"); + cmd.arg("build").arg("-p=staging-node-cli"); if is_release_build { cmd.arg("--release"); -- GitLab From b53a93a6762324b66a4e67add5fdfc65c9897f07 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 1 Nov 2023 09:15:19 +0100 Subject: [PATCH 404/633] Bump ec-utils version (#2104) --- Cargo.lock | 2 +- substrate/primitives/crypto/ec-utils/Cargo.toml | 2 +- substrate/primitives/crypto/ec-utils/src/lib.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2b9b9ec45d..1f22fccd2c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17085,7 +17085,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" -version = "0.4.0" +version = "0.4.1" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 651fc96d7ac..3c84c17a5c2 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-crypto-ec-utils" -version = "0.4.0" +version = "0.4.1" authors.workspace = true description = "Host functions for common Arkworks elliptic curve operations" edition.workspace = true diff --git a/substrate/primitives/crypto/ec-utils/src/lib.rs b/substrate/primitives/crypto/ec-utils/src/lib.rs index e3aea98faa1..970ad71765a 100644 --- a/substrate/primitives/crypto/ec-utils/src/lib.rs +++ b/substrate/primitives/crypto/ec-utils/src/lib.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Elliptic curves which are mostly compatible with *Arkworks* library -//! mostly useful in non-native contexts. +//! This crate offers elliptic curves types which are compatible with the +//! [Arkworks](https://github.com/arkworks-rs) library functionalities. //! -//! The definitions make use of host functions to offload the non-native -//! computational environment from the some of the most computationally -//! expensive operations by internally leveraging the +//! The implementation has been primarily designed to be used in slow hosted +//! targets (e.g. wasm32) and offloads the most computationally expensive +//! operations to the host by leveraging the //! [arkworks-extensions](https://github.com/paritytech/arkworks-extensions) -//! library. +//! library and Substrate's host functions. //! //! The exported types are organized and named in a way that mirrors the structure //! of the types in the original Arkworks library. This design choice aims to make -- GitLab From 37f3269c4513827cd1473bce49b0401cc285f5bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:50:39 +0100 Subject: [PATCH 405/633] Bump chevdor/srtool-actions from 0.8.0 to 0.9.0 (#2089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [chevdor/srtool-actions](https://github.com/chevdor/srtool-actions) from 0.8.0 to 0.9.0.

Release notes

Sourced from chevdor/srtool-actions's releases.

v0.9.0

What's Changed

Full Changelog: https://github.com/chevdor/srtool-actions/compare/v0.8.0...v0.9.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=chevdor/srtool-actions&package-manager=github_actions&previous-version=0.8.0&new-version=0.9.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-attach-release-runtimes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml index 297f7a1665b..c7cd4b34384 100644 --- a/.github/workflows/build-and-attach-release-runtimes.yml +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -33,7 +33,7 @@ jobs: - name: Build ${{ matrix.runtime.name }} ${{ matrix.build_config.type }} id: srtool_build - uses: chevdor/srtool-actions@v0.8.0 + uses: chevdor/srtool-actions@v0.9.0 env: BUILD_OPTS: ${{ matrix.build_config.opts }} with: -- GitLab From 9ca267328e0cba753aa528615cc19d1f633ed764 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Wed, 1 Nov 2023 12:28:16 +0100 Subject: [PATCH 406/633] upgraded review-bot to 2.2.0 (#2097) This version includes paritytech/review-bot#97 which can assign reviewers. It will be the final step required to replace PRCR. It also moves the secrets to the environment master. --- .github/workflows/review-bot.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index 178193da338..5970989cde0 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -6,12 +6,10 @@ on: types: - completed -permissions: - contents: read - jobs: review-approvals: runs-on: ubuntu-latest + environment: master steps: - name: Extract content of artifact id: number @@ -19,15 +17,16 @@ jobs: with: artifact-name: pr_number - name: Generate token - id: team_token + id: app_token uses: tibdex/github-app-token@v1 with: app_id: ${{ secrets.REVIEW_APP_ID }} private_key: ${{ secrets.REVIEW_APP_KEY }} - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v2.1.0 + uses: paritytech/review-bot@v2.2.0 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - team-token: ${{ steps.team_token.outputs.token }} - checks-token: ${{ steps.team_token.outputs.token }} + repo-token: ${{ steps.app_token.outputs.token }} + team-token: ${{ steps.app_token.outputs.token }} + checks-token: ${{ steps.app_token.outputs.token }} pr-number: ${{ steps.number.outputs.content }} + request-reviewers: true -- GitLab From 1cd6acdff3618a547dc98d9fd0c7984b5db933ef Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 1 Nov 2023 15:10:33 +0200 Subject: [PATCH 407/633] Move syncing code from `sc-network-common` to `sc-network-sync` (#1912) This PR moves syncing-related code from `sc-network-common` to `sc-network-sync`. Unfortunately, some parts are tightly integrated with networking, so they were left in `sc-network-common` for now: 1. `SyncMode` in `common/src/sync.rs` (used in `NetworkConfiguration`). 2. `BlockAnnouncesHandshake`, `BlockRequest`, `BlockResponse`, etc. in `common/src/sync/message.rs` (used in `src/protocol.rs` and `src/protocol/message.rs`). More substantial refactoring is needed to decouple syncing and networking completely, including getting rid of the hardcoded sync protocol. ## Release notes Move syncing-related code from `sc-network-common` to `sc-network-sync`. Delete `ChainSync` trait as it's never used (the only implementation is accessed directly from `SyncingEngine` and exposes a lot of public methods that are not part of the trait). Some new trait(s) for syncing will likely be introduced as part of Sync 2.0 refactoring to represent syncing strategies. --- Cargo.lock | 5 + substrate/client/consensus/grandpa/Cargo.toml | 1 + .../grandpa/src/communication/mod.rs | 2 +- .../grandpa/src/communication/tests.rs | 6 +- .../consensus/grandpa/src/warp_proof.rs | 2 +- substrate/client/informant/Cargo.toml | 1 + substrate/client/informant/src/display.rs | 2 +- substrate/client/informant/src/lib.rs | 2 +- substrate/client/network-gossip/Cargo.toml | 1 + substrate/client/network-gossip/src/bridge.rs | 5 +- substrate/client/network-gossip/src/lib.rs | 2 +- substrate/client/network/common/src/sync.rs | 342 -- .../client/network/common/src/sync/warp.rs | 101 - substrate/client/network/src/config.rs | 14 +- substrate/client/network/src/lib.rs | 9 +- substrate/client/network/statement/Cargo.toml | 1 + substrate/client/network/statement/src/lib.rs | 6 +- .../network/sync/src/block_request_handler.rs | 4 +- .../client/network/sync/src/chain_sync.rs | 2435 ++++++++++++ .../network/sync/src/chain_sync/test.rs | 1085 ++++++ substrate/client/network/sync/src/engine.rs | 49 +- .../client/network/sync/src/extra_requests.rs | 8 +- substrate/client/network/sync/src/lib.rs | 3460 +---------------- substrate/client/network/sync/src/mock.rs | 61 +- .../network/sync/src/pending_responses.rs | 7 +- .../src/request_metrics.rs} | 0 .../network/sync/src/service/chain_sync.rs | 5 +- substrate/client/network/sync/src/state.rs | 6 +- substrate/client/network/sync/src/types.rs | 206 + substrate/client/network/sync/src/warp.rs | 95 +- .../network/sync/src/warp_request_handler.rs | 2 +- substrate/client/network/test/src/lib.rs | 9 +- .../client/network/transactions/Cargo.toml | 1 + .../client/network/transactions/src/lib.rs | 7 +- substrate/client/service/src/metrics.rs | 2 +- 35 files changed, 3903 insertions(+), 4041 deletions(-) delete mode 100644 substrate/client/network/common/src/sync/warp.rs create mode 100644 substrate/client/network/sync/src/chain_sync.rs create mode 100644 substrate/client/network/sync/src/chain_sync/test.rs rename substrate/client/network/{common/src/sync/metrics.rs => sync/src/request_metrics.rs} (100%) create mode 100644 substrate/client/network/sync/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 1f22fccd2c1..0f386c52b38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14995,6 +14995,7 @@ dependencies = [ "sc-network", "sc-network-common", "sc-network-gossip", + "sc-network-sync", "sc-network-test", "sc-telemetry", "sc-transaction-pool-api", @@ -15211,6 +15212,7 @@ dependencies = [ "sc-client-api", "sc-network", "sc-network-common", + "sc-network-sync", "sp-blockchain", "sp-runtime", ] @@ -15363,6 +15365,7 @@ dependencies = [ "quickcheck", "sc-network", "sc-network-common", + "sc-network-sync", "schnellru", "sp-runtime", "substrate-prometheus-endpoint", @@ -15403,6 +15406,7 @@ dependencies = [ "parity-scale-codec", "sc-network", "sc-network-common", + "sc-network-sync", "sp-consensus", "sp-statement-store", "substrate-prometheus-endpoint", @@ -15489,6 +15493,7 @@ dependencies = [ "parity-scale-codec", "sc-network", "sc-network-common", + "sc-network-sync", "sc-utils", "sp-consensus", "sp-runtime", diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 472bdd1c5b8..921b9c539e3 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -37,6 +37,7 @@ sc-consensus = { path = "../common" } sc-network = { path = "../../network" } sc-network-gossip = { path = "../../network-gossip" } sc-network-common = { path = "../../network/common" } +sc-network-sync = { path = "../../network/sync" } sc-telemetry = { path = "../../telemetry" } sc-utils = { path = "../../utils" } sp-api = { path = "../../../primitives/api" } diff --git a/substrate/client/consensus/grandpa/src/communication/mod.rs b/substrate/client/consensus/grandpa/src/communication/mod.rs index c0749858568..6d9e956b41b 100644 --- a/substrate/client/consensus/grandpa/src/communication/mod.rs +++ b/substrate/client/consensus/grandpa/src/communication/mod.rs @@ -59,7 +59,7 @@ use crate::{ use gossip::{ FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage, }; -use sc_network_common::sync::SyncEventStream; +use sc_network_sync::SyncEventStream; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 10c4772fc76..4a869d0f515 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -33,11 +33,9 @@ use sc_network::{ NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT as NotificationSender, PeerId, ReputationChange, }; -use sc_network_common::{ - role::ObservedRole, - sync::{SyncEvent as SyncStreamEvent, SyncEventStream}, -}; +use sc_network_common::role::ObservedRole; use sc_network_gossip::Validator; +use sc_network_sync::{SyncEvent as SyncStreamEvent, SyncEventStream}; use sc_network_test::{Block, Hash}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_consensus_grandpa::AuthorityList; diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index ea8114eafd7..dcd55dcdf3a 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -23,7 +23,7 @@ use crate::{ BlockNumberOps, GrandpaJustification, SharedAuthoritySet, }; use sc_client_api::Backend as ClientBackend; -use sc_network_common::sync::warp::{EncodedProof, VerificationResult, WarpSyncProvider}; +use sc_network_sync::warp::{EncodedProof, VerificationResult, WarpSyncProvider}; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index e077f4e11a5..47e65df3cc1 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -19,6 +19,7 @@ futures-timer = "3.0.1" log = "0.4.17" sc-client-api = { path = "../api" } sc-network-common = { path = "../network/common" } +sc-network-sync = { path = "../network/sync" } sc-network = { path = "../network" } sp-blockchain = { path = "../../primitives/blockchain" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/client/informant/src/display.rs b/substrate/client/informant/src/display.rs index 722cf56d778..64ddb71d572 100644 --- a/substrate/client/informant/src/display.rs +++ b/substrate/client/informant/src/display.rs @@ -21,7 +21,7 @@ use ansi_term::Colour; use log::info; use sc_client_api::ClientInfo; use sc_network::NetworkStatus; -use sc_network_common::sync::{ +use sc_network_sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, SyncState, SyncStatus, }; diff --git a/substrate/client/informant/src/lib.rs b/substrate/client/informant/src/lib.rs index 03f9075055e..b072f8551f9 100644 --- a/substrate/client/informant/src/lib.rs +++ b/substrate/client/informant/src/lib.rs @@ -24,7 +24,7 @@ use futures_timer::Delay; use log::{debug, info, trace}; use sc_client_api::{BlockchainEvents, UsageProvider}; use sc_network::NetworkStatusProvider; -use sc_network_common::sync::SyncStatusProvider; +use sc_network_sync::SyncStatusProvider; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; use std::{collections::VecDeque, fmt::Display, sync::Arc, time::Duration}; diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 73d2d3fa051..95e26a232c1 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -24,6 +24,7 @@ tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-network = { path = "../network" } sc-network-common = { path = "../network/common" } +sc-network-sync = { path = "../network/sync" } sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 6a3790ee2b2..8f7d490757b 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -22,7 +22,7 @@ use crate::{ }; use sc_network::{event::Event, types::ProtocolName, ReputationChange}; -use sc_network_common::sync::SyncEvent; +use sc_network_sync::SyncEvent; use futures::{ channel::mpsc::{channel, Receiver, Sender}, @@ -338,7 +338,8 @@ mod tests { config::MultiaddrWithPeerId, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NotificationSenderError, NotificationSenderT as NotificationSender, }; - use sc_network_common::{role::ObservedRole, sync::SyncEventStream}; + use sc_network_common::role::ObservedRole; + use sc_network_sync::SyncEventStream; use sp_runtime::{ testing::H256, traits::{Block as BlockT, NumberFor}, diff --git a/substrate/client/network-gossip/src/lib.rs b/substrate/client/network-gossip/src/lib.rs index 5b02be5c23f..a77141ec6f6 100644 --- a/substrate/client/network-gossip/src/lib.rs +++ b/substrate/client/network-gossip/src/lib.rs @@ -71,7 +71,7 @@ use libp2p::{multiaddr, PeerId}; use sc_network::{ types::ProtocolName, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, }; -use sc_network_common::sync::SyncEventStream; +use sc_network_sync::SyncEventStream; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::iter; diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index 4ca21221f87..a910740aef6 100644 --- a/substrate/client/network/common/src/sync.rs +++ b/substrate/client/network/common/src/sync.rs @@ -19,150 +19,6 @@ //! Abstract interfaces and data structures related to network sync. pub mod message; -pub mod metrics; -pub mod warp; - -use crate::{role::Roles, types::ReputationChange}; -use futures::Stream; - -use libp2p_identity::PeerId; - -use message::{BlockAnnounce, BlockRequest, BlockResponse}; -use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock}; -use sp_consensus::BlockOrigin; -use sp_runtime::{ - traits::{Block as BlockT, NumberFor}, - Justifications, -}; -use warp::WarpSyncProgress; - -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)] -pub struct PeerInfo { - /// Their best block hash. - pub best_hash: Block::Hash, - /// Their best block number. - pub best_number: NumberFor, -} - -/// Info about a peer's known state (both full and light). -#[derive(Clone, Debug)] -pub struct ExtendedPeerInfo { - /// Roles - pub roles: Roles, - /// Peer best block hash - pub best_hash: B::Hash, - /// Peer best block number - pub best_number: NumberFor, -} - -/// Reported sync state. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum SyncState { - /// Initial sync is complete, keep-up sync is active. - Idle, - /// Actively catching up with the chain. - Downloading { target: BlockNumber }, - /// All blocks are downloaded and are being imported. - Importing { target: BlockNumber }, -} - -impl SyncState { - /// Are we actively catching up with the chain? - pub fn is_major_syncing(&self) -> bool { - !matches!(self, SyncState::Idle) - } -} - -/// Reported state download progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct StateDownloadProgress { - /// Estimated download percentage. - pub percentage: u32, - /// Total state size in bytes downloaded so far. - pub size: u64, -} - -/// Syncing status and statistics. -#[derive(Debug, Clone)] -pub struct SyncStatus { - /// Current global sync state. - pub state: SyncState>, - /// Target sync block number. - pub best_seen_block: Option>, - /// Number of peers participating in syncing. - pub num_peers: u32, - /// Number of peers known to `SyncingEngine` (both full and light). - pub num_connected_peers: u32, - /// Number of blocks queued for import - pub queued_blocks: u32, - /// State sync status in progress, if any. - pub state_sync: Option, - /// Warp sync in progress, if any. - pub warp_sync: Option>, -} - -/// A peer did not behave as expected and should be reported. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BadPeer(pub PeerId, pub ReputationChange); - -impl fmt::Display for BadPeer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1) - } -} - -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(ImportBlocksAction), - /// A new block request needs to be made to the given peer. - Request(PeerId, BlockRequest), - /// Continue processing events. - Continue, -} - -/// Result of [`ChainSync::on_block_justification`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockJustification { - /// The justification needs no further handling. - Nothing, - /// The justification should be imported. - Import { - peer_id: PeerId, - hash: Block::Hash, - number: NumberFor, - justifications: Justifications, - }, -} - -/// Result of `ChainSync::on_state_data`. -#[derive(Debug)] -pub enum OnStateData { - /// The block and state that should be imported. - Import(BlockOrigin, IncomingBlock), - /// A new state request needs to be made to the given peer. - Continue, -} - -/// Block or justification request polled from `ChainSync` -#[derive(Debug)] -pub enum ImportResult { - BlockImport(BlockOrigin, Vec>), - JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), -} /// Sync operation mode. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -197,201 +53,3 @@ impl Default for SyncMode { Self::Full } } -#[derive(Debug)] -pub struct Metrics { - pub queued_blocks: u32, - pub fork_targets: u32, - pub justifications: metrics::Metrics, -} - -#[derive(Debug)] -pub enum PeerRequest { - Block(BlockRequest), - State, - WarpProof, -} - -#[derive(Debug)] -pub enum PeerRequestType { - Block, - State, - WarpProof, -} - -impl PeerRequest { - pub fn get_type(&self) -> PeerRequestType { - match self { - PeerRequest::Block(_) => PeerRequestType::Block, - PeerRequest::State => PeerRequestType::State, - PeerRequest::WarpProof => PeerRequestType::WarpProof, - } - } -} - -/// Wrapper for implementation-specific state request. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueStateRequest(pub Box); - -impl fmt::Debug for OpaqueStateRequest { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueStateRequest").finish() - } -} - -/// Wrapper for implementation-specific state response. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueStateResponse(pub Box); - -impl fmt::Debug for OpaqueStateResponse { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueStateResponse").finish() - } -} - -/// Provides high-level status of syncing. -#[async_trait::async_trait] -pub trait SyncStatusProvider: Send + Sync { - /// Get high-level view of the syncing status. - async fn status(&self) -> Result, ()>; -} - -#[async_trait::async_trait] -impl SyncStatusProvider for Arc -where - T: ?Sized, - T: SyncStatusProvider, - Block: BlockT, -{ - async fn status(&self) -> Result, ()> { - T::status(self).await - } -} - -/// Syncing-related events that other protocols can subscribe to. -pub enum SyncEvent { - /// Peer that the syncing implementation is tracking connected. - PeerConnected(PeerId), - - /// Peer that the syncing implementation was tracking disconnected. - PeerDisconnected(PeerId), -} - -pub trait SyncEventStream: Send + Sync { - /// Subscribe to syncing-related events. - fn event_stream(&self, name: &'static str) -> Pin + Send>>; -} - -impl SyncEventStream for Arc -where - T: ?Sized, - T: SyncEventStream, -{ - fn event_stream(&self, name: &'static str) -> Pin + Send>> { - T::event_stream(self, name) - } -} - -/// Something that represents the syncing strategy to download past and future blocks of the chain. -pub trait ChainSync: Send { - /// Returns the state of the sync of the given peer. - /// - /// Returns `None` if the peer is unknown. - fn peer_info(&self, who: &PeerId) -> Option>; - - /// Returns the current sync status. - fn status(&self) -> SyncStatus; - - /// Number of active forks requests. This includes - /// requests that are pending or could be issued right away. - fn num_sync_requests(&self) -> usize; - - /// Number of downloaded blocks. - fn num_downloaded_blocks(&self) -> usize; - - /// Returns the current number of peers stored within this state machine. - fn num_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, - best_hash: Block::Hash, - best_number: NumberFor, - ) -> Result>, BadPeer>; - - /// Signal that a new best block has been imported. - fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor); - - /// Schedule a justification request for the given block. - fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor); - - /// Clear all pending justification requests. - fn clear_justification_requests(&mut self); - - /// Request syncing for the given block from given set of peers. - fn set_sync_fork_request( - &mut self, - peers: Vec, - hash: &Block::Hash, - number: NumberFor, - ); - - /// Handle a response from the remote to a block request that we made. - /// - /// `request` must be the original request that triggered `response`. - /// or `None` if data comes from the block announcement. - /// - /// 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, - request: Option>, - response: BlockResponse, - ) -> Result, BadPeer>; - - /// 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, - response: BlockResponse, - ) -> Result, BadPeer>; - - /// Call this when a justification has been processed by the import queue, - /// with or without errors. - fn on_justification_import( - &mut self, - hash: Block::Hash, - number: NumberFor, - success: bool, - ); - - /// Notify about finalization of the given block. - fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); - - /// Notify about pre-validated block announcement. - fn on_validated_block_announce( - &mut self, - is_best: bool, - who: PeerId, - announce: &BlockAnnounce, - ); - - /// 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. - #[must_use] - fn peer_disconnected(&mut self, who: &PeerId) -> Option>; - - /// Return some key metrics. - fn metrics(&self) -> Metrics; -} diff --git a/substrate/client/network/common/src/sync/warp.rs b/substrate/client/network/common/src/sync/warp.rs deleted file mode 100644 index f4e39f43851..00000000000 --- a/substrate/client/network/common/src/sync/warp.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use codec::{Decode, Encode}; -pub use sp_consensus_grandpa::{AuthorityList, SetId}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::fmt; - -/// Scale-encoded warp sync proof response. -pub struct EncodedProof(pub Vec); - -/// Warp sync request -#[derive(Encode, Decode, Debug)] -pub struct WarpProofRequest { - /// Start collecting proofs from this block. - pub begin: B::Hash, -} - -/// Proof verification result. -pub enum VerificationResult { - /// Proof is valid, but the target was not reached. - Partial(SetId, AuthorityList, Block::Hash), - /// Target finality is proved. - Complete(SetId, AuthorityList, Block::Header), -} - -/// Warp sync backend. Handles retrieving and verifying warp sync proofs. -pub trait WarpSyncProvider: Send + Sync { - /// Generate proof starting at given block hash. The proof is accumulated until maximum proof - /// size is reached. - fn generate( - &self, - start: Block::Hash, - ) -> Result>; - /// Verify warp proof against current set of authorities. - fn verify( - &self, - proof: &EncodedProof, - set_id: SetId, - authorities: AuthorityList, - ) -> Result, Box>; - /// Get current list of authorities. This is supposed to be genesis authorities when starting - /// sync. - fn current_authorities(&self) -> AuthorityList; -} - -/// Reported warp sync phase. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum WarpSyncPhase { - /// Waiting for peers to connect. - AwaitingPeers { required_peers: usize }, - /// Waiting for target block to be received. - AwaitingTargetBlock, - /// Downloading and verifying grandpa warp proofs. - DownloadingWarpProofs, - /// Downloading target block. - DownloadingTargetBlock, - /// Downloading state data. - DownloadingState, - /// Importing state. - ImportingState, - /// Downloading block history. - DownloadingBlocks(NumberFor), -} - -impl fmt::Display for WarpSyncPhase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::AwaitingPeers { required_peers } => - write!(f, "Waiting for {required_peers} peers to be connected"), - Self::AwaitingTargetBlock => write!(f, "Waiting for target block to be received"), - Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), - Self::DownloadingTargetBlock => write!(f, "Downloading target block"), - Self::DownloadingState => write!(f, "Downloading state"), - Self::ImportingState => write!(f, "Importing state"), - Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), - } - } -} - -/// Reported warp sync progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct WarpSyncProgress { - /// Estimated download percentage. - pub phase: WarpSyncPhase, - /// Total bytes downloaded so far. - pub total_bytes: u64, -} diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index d069c3f458f..124d73a74db 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -30,7 +30,11 @@ pub use crate::{ types::ProtocolName, }; -pub use libp2p::{identity::Keypair, multiaddr, Multiaddr, PeerId}; +pub use libp2p::{ + build_multiaddr, + identity::{self, ed25519, Keypair}, + multiaddr, Multiaddr, PeerId, +}; use crate::peer_store::PeerStoreHandle; use codec::Encode; @@ -39,9 +43,10 @@ use zeroize::Zeroize; pub use sc_network_common::{ role::{Role, Roles}, - sync::{warp::WarpSyncProvider, SyncMode}, + sync::SyncMode, ExHashT, }; + use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::Block as BlockT; @@ -58,11 +63,6 @@ use std::{ str::{self, FromStr}, }; -pub use libp2p::{ - build_multiaddr, - identity::{self, ed25519}, -}; - /// Protocol name prefix, transmitted on the wire for legacy protocol names. /// I.e., `dot` in `/dot/sync/2`. Should be unique for each chain. Always UTF-8. /// Deprecated in favour of genesis hash & fork ID based protocol names. diff --git a/substrate/client/network/src/lib.rs b/substrate/client/network/src/lib.rs index ee307596878..4dc9bdb4cc1 100644 --- a/substrate/client/network/src/lib.rs +++ b/substrate/client/network/src/lib.rs @@ -266,14 +266,7 @@ pub use event::{DhtEvent, Event, SyncEvent}; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use request_responses::{Config, IfDisconnected, RequestFailure}; -pub use sc_network_common::{ - role::ObservedRole, - sync::{ - warp::{WarpSyncPhase, WarpSyncProgress}, - ExtendedPeerInfo, StateDownloadProgress, SyncEventStream, SyncState, SyncStatusProvider, - }, - types::ReputationChange, -}; +pub use sc_network_common::{role::ObservedRole, types::ReputationChange}; pub use service::{ signature::Signature, traits::{ diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index adfb2d6a05f..ef974b4f33f 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -21,6 +21,7 @@ libp2p = "0.51.3" log = "0.4.17" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-network-common = { path = "../common" } +sc-network-sync = { path = "../sync" } sc-network = { path = ".." } sp-consensus = { path = "../../../primitives/consensus/common" } sp-statement-store = { path = "../../../primitives/statement-store" } diff --git a/substrate/client/network/statement/src/lib.rs b/substrate/client/network/statement/src/lib.rs index c5d83b59b26..69d4faa13ef 100644 --- a/substrate/client/network/statement/src/lib.rs +++ b/substrate/client/network/statement/src/lib.rs @@ -39,10 +39,8 @@ use sc_network::{ utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, }; -use sc_network_common::{ - role::ObservedRole, - sync::{SyncEvent, SyncEventStream}, -}; +use sc_network_common::role::ObservedRole; +use sc_network_sync::{SyncEvent, SyncEventStream}; use sp_statement_store::{ Hash, NetworkPriority, Statement, StatementSource, StatementStore, SubmitResult, }; diff --git a/substrate/client/network/sync/src/block_request_handler.rs b/substrate/client/network/sync/src/block_request_handler.rs index c24083f6328..f363dda3a2d 100644 --- a/substrate/client/network/sync/src/block_request_handler.rs +++ b/substrate/client/network/sync/src/block_request_handler.rs @@ -24,7 +24,6 @@ use crate::{ BlockResponse as BlockResponseSchema, BlockResponse, Direction, }, service::network::NetworkServiceHandle, - MAX_BLOCKS_IN_RESPONSE, }; use codec::{Decode, DecodeAll, Encode}; @@ -54,6 +53,9 @@ use std::{ time::Duration, }; +/// Maximum blocks per response. +pub(crate) const MAX_BLOCKS_IN_RESPONSE: usize = 128; + const LOG_TARGET: &str = "sync"; const MAX_BODY_BYTES: usize = 8 * 1024 * 1024; const MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER: usize = 2; diff --git a/substrate/client/network/sync/src/chain_sync.rs b/substrate/client/network/sync/src/chain_sync.rs new file mode 100644 index 00000000000..9cf0080e36a --- /dev/null +++ b/substrate/client/network/sync/src/chain_sync.rs @@ -0,0 +1,2435 @@ +// 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 . + +//! Contains the state of the chain synchronization process +//! +//! At any given point in time, a running node tries as much as possible to be at the head of the +//! chain. This module handles the logic of which blocks to request from remotes, and processing +//! responses. It yields blocks to check and potentially move to the database. +//! +//! # Usage +//! +//! The `ChainSync` struct maintains the state of the block requests. Whenever something happens on +//! the network, or whenever a block has been successfully verified, call the appropriate method in +//! order to update it. + +use crate::{ + blocks::BlockCollection, + extra_requests::ExtraRequests, + schema::v1::StateResponse, + service::network::NetworkServiceHandle, + state::{ImportResult, StateSync}, + types::{ + BadPeer, Metrics, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, SyncMode, SyncState, + SyncStatus, + }, + warp::{ + self, EncodedProof, WarpProofImportResult, WarpProofRequest, WarpSync, WarpSyncConfig, + WarpSyncPhase, WarpSyncProgress, + }, +}; + +use codec::Encode; +use libp2p::PeerId; +use log::{debug, error, info, trace, warn}; + +use sc_client_api::{BlockBackend, ProofProvider}; +use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sc_network::types::ProtocolName; +use sc_network_common::sync::message::{ + BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, +}; +use sp_arithmetic::traits::Saturating; +use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; +use sp_consensus::{BlockOrigin, BlockStatus}; +use sp_runtime::{ + traits::{ + Block as BlockT, CheckedSub, Hash, HashingFor, Header as HeaderT, NumberFor, One, + SaturatedConversion, Zero, + }, + EncodedJustification, Justifications, +}; + +use std::{ + collections::{HashMap, HashSet}, + ops::Range, + sync::Arc, +}; + +#[cfg(test)] +mod test; + +/// Log target for this file. +const LOG_TARGET: &'static str = "sync"; + +/// Maximum blocks to store in the import queue. +const MAX_IMPORTING_BLOCKS: usize = 2048; + +/// Maximum blocks to download ahead of any gap. +const MAX_DOWNLOAD_AHEAD: u32 = 2048; + +/// Maximum blocks to look backwards. The gap is the difference between the highest block and the +/// common block of a node. +const MAX_BLOCKS_TO_LOOK_BACKWARDS: u32 = MAX_DOWNLOAD_AHEAD / 2; + +/// Pick the state to sync as the latest finalized number minus this. +const STATE_SYNC_FINALITY_THRESHOLD: u32 = 8; + +/// We use a heuristic that with a high likelihood, by the time +/// `MAJOR_SYNC_BLOCKS` have been imported we'll be on the same +/// chain as (or at least closer to) the peer so we want to delay +/// the ancestor search to not waste time doing that when we are +/// so far behind. +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; + +mod rep { + use sc_network::ReputationChange as Rep; + /// Reputation change when a peer sent us a message that led to a + /// database read error. + pub const BLOCKCHAIN_READ_ERROR: Rep = Rep::new(-(1 << 16), "DB Error"); + + /// Reputation change when a peer sent us a status message with a different + /// genesis than us. + pub const GENESIS_MISMATCH: Rep = Rep::new(i32::MIN, "Genesis mismatch"); + + /// Reputation change for peers which send us a block with an incomplete header. + pub const INCOMPLETE_HEADER: Rep = Rep::new(-(1 << 20), "Incomplete header"); + + /// Reputation change for peers which send us a block which we fail to verify. + pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed"); + + /// Reputation change for peers which send us a known bad block. + pub const BAD_BLOCK: Rep = Rep::new(-(1 << 29), "Bad block"); + + /// Peer did not provide us with advertised block data. + pub const NO_BLOCK: Rep = Rep::new(-(1 << 29), "No requested block data"); + + /// Reputation change for peers which send us non-requested block data. + pub const NOT_REQUESTED: Rep = Rep::new(-(1 << 29), "Not requested block data"); + + /// Reputation change for peers which send us a block with bad justifications. + pub const BAD_JUSTIFICATION: Rep = Rep::new(-(1 << 16), "Bad justification"); + + /// Reputation change when a peer sent us invlid ancestry result. + pub const UNKNOWN_ANCESTOR: Rep = Rep::new(-(1 << 16), "DB Error"); + + /// Peer response data does not have requested bits. + pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); +} + +enum AllowedRequests { + Some(HashSet), + All, +} + +impl AllowedRequests { + fn add(&mut self, id: &PeerId) { + if let Self::Some(ref mut set) = self { + set.insert(*id); + } + } + + fn take(&mut self) -> Self { + std::mem::take(self) + } + + fn set_all(&mut self) { + *self = Self::All; + } + + fn contains(&self, id: &PeerId) -> bool { + match self { + Self::Some(set) => set.contains(id), + Self::All => true, + } + } + + fn is_empty(&self) -> bool { + match self { + Self::Some(set) => set.is_empty(), + Self::All => false, + } + } + + fn clear(&mut self) { + std::mem::take(self); + } +} + +impl Default for AllowedRequests { + fn default() -> Self { + Self::Some(HashSet::default()) + } +} + +struct GapSync { + blocks: BlockCollection, + best_queued_number: NumberFor, + target: NumberFor, +} + +/// Action that the parent of [`ChainSync`] should perform after reporting imported blocks with +/// [`ChainSync::on_blocks_processed`]. +pub 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 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>, +} + +/// Action that the parent of [`ChainSync`] should perform if we want to import justifications. +pub struct ImportJustificationsAction { + pub peer_id: PeerId, + pub hash: B::Hash, + pub number: NumberFor, + pub justifications: Justifications, +} + +/// Result of [`ChainSync::on_block_data`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockData { + /// The block should be imported. + Import(ImportBlocksAction), + /// A new block request needs to be made to the given peer. + Request(PeerId, BlockRequest), + /// Continue processing events. + Continue, +} + +/// Result of [`ChainSync::on_block_justification`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockJustification { + /// The justification needs no further handling. + Nothing, + /// The justification should be imported. + Import { + peer_id: PeerId, + hash: Block::Hash, + number: NumberFor, + justifications: Justifications, + }, +} + +// Result of [`ChainSync::on_state_data`]. +#[derive(Debug)] +pub enum OnStateData { + /// The block and state that should be imported. + Import(BlockOrigin, IncomingBlock), + /// A new state request needs to be made to the given peer. + Continue, +} + +/// Action that the parent of [`ChainSync`] should perform after reporting block response with +/// [`ChainSync::on_block_response`]. +pub 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. +pub struct ChainSync { + /// Chain client. + client: Arc, + /// The active peers that we are using to sync and their PeerSync status + peers: HashMap>, + /// A `BlockCollection` of blocks that are being downloaded from peers + blocks: BlockCollection, + /// The best block number in our queue of blocks to import + best_queued_number: NumberFor, + /// The best block hash in our queue of blocks to import + best_queued_hash: B::Hash, + /// Current mode (full/light) + mode: SyncMode, + /// Any extra justification requests. + extra_justifications: ExtraRequests, + /// A set of hashes of blocks that are being downloaded or have been + /// downloaded and are queued for import. + queue_blocks: HashSet, + /// Fork sync targets. + fork_targets: HashMap>, + /// A set of peers for which there might be potential block requests + allowed_requests: AllowedRequests, + /// Maximum number of peers to ask the same blocks in parallel. + max_parallel_downloads: u32, + /// Maximum blocks per request. + max_blocks_per_request: u32, + /// Total number of downloaded blocks. + downloaded_blocks: usize, + /// State sync in progress, if any. + state_sync: Option>, + /// Warp sync in progress, if any. + warp_sync: Option>, + /// Warp sync configuration. + /// + /// Will be `None` after `self.warp_sync` is `Some(_)`. + warp_sync_config: Option>, + /// A temporary storage for warp sync target block until warp sync is initialized. + warp_sync_target_block_header: Option, + /// Enable importing existing blocks. This is used used after the state download to + /// catch up to the latest state while re-importing blocks. + import_existing: bool, + /// Gap download process. + gap_sync: Option>, + /// Handle for communicating with `NetworkService` + network_service: NetworkServiceHandle, + /// Protocol name used for block announcements + block_announce_protocol_name: ProtocolName, +} + +/// All the data we have about a Peer that we are trying to sync with +#[derive(Debug, Clone)] +pub(crate) struct PeerSync { + /// Peer id of this peer. + pub peer_id: PeerId, + /// The common number is the block number that is a common point of + /// ancestry for both our chains (as far as we know). + pub common_number: NumberFor, + /// The hash of the best block that we've seen for this peer. + pub best_hash: B::Hash, + /// The number of the best block that we've seen for this peer. + pub best_number: NumberFor, + /// The state of syncing this peer is in for us, generally categories + /// into `Available` or "busy" with something as defined by `PeerSyncState`. + pub state: PeerSyncState, +} + +impl PeerSync { + /// Update the `common_number` iff `new_common > common_number`. + fn update_common_number(&mut self, new_common: NumberFor) { + if self.common_number < new_common { + trace!( + target: LOG_TARGET, + "Updating peer {} common number from={} => to={}.", + self.peer_id, + self.common_number, + new_common, + ); + self.common_number = new_common; + } + } +} + +struct ForkTarget { + number: NumberFor, + parent_hash: Option, + peers: HashSet, +} + +/// The state of syncing between a Peer and ourselves. +/// +/// Generally two categories, "busy" or `Available`. If busy, the enum +/// defines what we are busy with. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub(crate) enum PeerSyncState { + /// Available for sync requests. + Available, + /// Searching for ancestors the Peer has in common with us. + AncestorSearch { start: NumberFor, current: NumberFor, state: AncestorSearchState }, + /// Actively downloading new blocks, starting from the given Number. + DownloadingNew(NumberFor), + /// Downloading a stale block with given Hash. Stale means that it is a + /// block with a number that is lower than our best number. It might be + /// from a fork and not necessarily already imported. + DownloadingStale(B::Hash), + /// Downloading justification for given block hash. + DownloadingJustification(B::Hash), + /// Downloading state. + DownloadingState, + /// Downloading warp proof. + DownloadingWarpProof, + /// Downloading warp sync target block. + DownloadingWarpTargetBlock, + /// Actively downloading block history after warp sync. + DownloadingGap(NumberFor), +} + +impl PeerSyncState { + pub fn is_available(&self) -> bool { + matches!(self, Self::Available) + } +} + +impl ChainSync +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + /// Create a new instance. + pub fn new( + mode: SyncMode, + client: Arc, + block_announce_protocol_name: ProtocolName, + max_parallel_downloads: u32, + max_blocks_per_request: u32, + warp_sync_config: Option>, + network_service: NetworkServiceHandle, + ) -> Result { + let mut sync = Self { + client, + peers: HashMap::new(), + blocks: BlockCollection::new(), + best_queued_hash: Default::default(), + best_queued_number: Zero::zero(), + extra_justifications: ExtraRequests::new("justification"), + mode, + queue_blocks: Default::default(), + fork_targets: Default::default(), + allowed_requests: Default::default(), + max_parallel_downloads, + max_blocks_per_request, + downloaded_blocks: 0, + state_sync: None, + warp_sync: None, + import_existing: false, + gap_sync: None, + network_service, + warp_sync_config, + warp_sync_target_block_header: None, + block_announce_protocol_name, + }; + + sync.reset_sync_start_point()?; + Ok(sync) + } + + /// Get peer's best hash & number. + pub fn peer_info(&self, who: &PeerId) -> Option> { + self.peers + .get(who) + .map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) + } + + /// Returns the current sync status. + pub fn status(&self) -> SyncStatus { + let median_seen = self.median_seen(); + let best_seen_block = + median_seen.and_then(|median| (median > self.best_queued_number).then_some(median)); + let sync_state = if let Some(target) = median_seen { + // A chain is classified as downloading if the provided best block is + // more than `MAJOR_SYNC_BLOCKS` behind the best block or as importing + // if the same can be said about queued blocks. + let best_block = self.client.info().best_number; + if target > best_block && target - best_block > MAJOR_SYNC_BLOCKS.into() { + // If target is not queued, we're downloading, otherwise importing. + if target > self.best_queued_number { + SyncState::Downloading { target } + } else { + SyncState::Importing { target } + } + } else { + SyncState::Idle + } + } else { + SyncState::Idle + }; + + let warp_sync_progress = match (&self.warp_sync, &self.mode, &self.gap_sync) { + (_, _, Some(gap_sync)) => Some(WarpSyncProgress { + phase: WarpSyncPhase::DownloadingBlocks(gap_sync.best_queued_number), + total_bytes: 0, + }), + (None, SyncMode::Warp, _) => Some(WarpSyncProgress { + phase: WarpSyncPhase::AwaitingPeers { + required_peers: MIN_PEERS_TO_START_WARP_SYNC, + }, + total_bytes: 0, + }), + (Some(sync), _, _) => Some(sync.progress()), + _ => None, + }; + + SyncStatus { + state: sync_state, + best_seen_block, + num_peers: self.peers.len() as u32, + num_connected_peers: 0u32, + queued_blocks: self.queue_blocks.len() as u32, + state_sync: self.state_sync.as_ref().map(|s| s.progress()), + warp_sync: warp_sync_progress, + } + } + + /// Get an estimate of the number of parallel sync requests. + pub fn num_sync_requests(&self) -> usize { + self.fork_targets + .values() + .filter(|f| f.number <= self.best_queued_number) + .count() + } + + /// Get the total number of downloaded blocks. + pub fn num_downloaded_blocks(&self) -> usize { + self.downloaded_blocks + } + + /// Get the number of peers known to the syncing state machine. + pub fn num_peers(&self) -> usize { + self.peers.len() + } + + /// Notify syncing state machine that a new sync peer has connected. + #[must_use] + pub fn new_peer( + &mut self, + who: PeerId, + best_hash: B::Hash, + best_number: NumberFor, + ) -> Result>, BadPeer> { + // There is nothing sync can get from the node that has no blockchain data. + match self.block_status(&best_hash) { + Err(e) => { + debug!(target:LOG_TARGET, "Error reading blockchain: {e}"); + Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) + }, + Ok(BlockStatus::KnownBad) => { + info!("💔 New peer with known bad best block {} ({}).", best_hash, best_number); + Err(BadPeer(who, rep::BAD_BLOCK)) + }, + Ok(BlockStatus::Unknown) => { + if best_number.is_zero() { + info!("💔 New peer with unknown genesis hash {} ({}).", best_hash, best_number); + return Err(BadPeer(who, rep::GENESIS_MISMATCH)) + } + + // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have + // enough to do in the import queue that it's not worth kicking off + // an ancestor search, which is what we do in the next match case below. + if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS.into() { + debug!( + target:LOG_TARGET, + "New peer with unknown best hash {} ({}), assuming common block.", + self.best_queued_hash, + self.best_queued_number + ); + self.peers.insert( + who, + PeerSync { + peer_id: who, + common_number: self.best_queued_number, + best_hash, + best_number, + state: PeerSyncState::Available, + }, + ); + return Ok(None) + } + + // If we are at genesis, just start downloading. + let (state, req) = if self.best_queued_number.is_zero() { + debug!( + target:LOG_TARGET, + "New peer with best hash {best_hash} ({best_number}).", + ); + + (PeerSyncState::Available, None) + } else { + let common_best = std::cmp::min(self.best_queued_number, best_number); + + debug!( + target:LOG_TARGET, + "New peer with unknown best hash {} ({}), searching for common ancestor.", + best_hash, + best_number + ); + + ( + PeerSyncState::AncestorSearch { + current: common_best, + start: self.best_queued_number, + state: AncestorSearchState::ExponentialBackoff(One::one()), + }, + Some(ancestry_request::(common_best)), + ) + }; + + self.allowed_requests.add(&who); + self.peers.insert( + who, + PeerSync { + peer_id: who, + common_number: Zero::zero(), + best_hash, + best_number, + state, + }, + ); + + if let SyncMode::Warp = self.mode { + if self.peers.len() >= MIN_PEERS_TO_START_WARP_SYNC && self.warp_sync.is_none() + { + log::debug!(target: LOG_TARGET, "Starting warp state sync."); + + if let Some(config) = self.warp_sync_config.take() { + let mut warp_sync = WarpSync::new(self.client.clone(), config); + if let Some(header) = self.warp_sync_target_block_header.take() { + warp_sync.set_target_block(header); + } + self.warp_sync = Some(warp_sync); + } + } + } + Ok(req) + }, + Ok(BlockStatus::Queued) | + Ok(BlockStatus::InChainWithState) | + Ok(BlockStatus::InChainPruned) => { + debug!( + target: LOG_TARGET, + "New peer with known best hash {best_hash} ({best_number}).", + ); + self.peers.insert( + who, + PeerSync { + peer_id: who, + common_number: std::cmp::min(self.best_queued_number, best_number), + best_hash, + best_number, + state: PeerSyncState::Available, + }, + ); + self.allowed_requests.add(&who); + Ok(None) + }, + } + } + + /// Inform sync about a new best imported block. + pub fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { + self.on_block_queued(best_hash, best_number); + } + + /// Request extra justification. + pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; + self.extra_justifications + .schedule((*hash, number), |base, block| is_descendent_of(&**client, base, block)) + } + + /// Clear extra justification requests. + pub fn clear_justification_requests(&mut self) { + self.extra_justifications.reset(); + } + + /// Configure an explicit fork sync request in case external code has detected that there is a + /// stale fork missing. + /// + /// Note that this function should not be used for recent blocks. + /// Sync should be able to download all the recent forks normally. + /// + /// Passing empty `peers` set effectively removes the sync request. + // The implementation is similar to `on_validated_block_announce` with unknown parent hash. + pub fn set_sync_fork_request( + &mut self, + mut peers: Vec, + hash: &B::Hash, + number: NumberFor, + ) { + if peers.is_empty() { + peers = self + .peers + .iter() + // Only request blocks from peers who are ahead or on a par. + .filter(|(_, peer)| peer.best_number >= number) + .map(|(id, _)| *id) + .collect(); + + debug!( + target: LOG_TARGET, + "Explicit sync request for block {hash:?} with no peers specified. \ + Syncing from these peers {peers:?} instead.", + ); + } else { + debug!( + target: LOG_TARGET, + "Explicit sync request for block {hash:?} with {peers:?}", + ); + } + + if self.is_known(hash) { + debug!(target: LOG_TARGET, "Refusing to sync known hash {hash:?}"); + return + } + + trace!(target: LOG_TARGET, "Downloading requested old fork {hash:?}"); + for peer_id in &peers { + if let Some(peer) = self.peers.get_mut(peer_id) { + if let PeerSyncState::AncestorSearch { .. } = peer.state { + continue + } + + if number > peer.best_number { + peer.best_number = number; + peer.best_hash = *hash; + } + self.allowed_requests.add(peer_id); + } + } + + self.fork_targets + .entry(*hash) + .or_insert_with(|| ForkTarget { number, peers: Default::default(), parent_hash: None }) + .peers + .extend(peers); + } + + /// Submit a block response for processing. + #[must_use] + pub fn on_block_data( + &mut self, + who: &PeerId, + request: Option>, + response: BlockResponse, + ) -> Result, BadPeer> { + self.downloaded_blocks += response.blocks.len(); + let mut gap = false; + let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { + let mut blocks = response.blocks; + if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) { + trace!(target: LOG_TARGET, "Reversing incoming block list"); + blocks.reverse() + } + self.allowed_requests.add(who); + if let Some(request) = request { + match &mut peer.state { + PeerSyncState::DownloadingNew(_) => { + self.blocks.clear_peer_download(who); + peer.state = PeerSyncState::Available; + if let Some(start_block) = + validate_blocks::(&blocks, who, Some(request))? + { + self.blocks.insert(start_block, blocks, *who); + } + self.ready_blocks() + }, + PeerSyncState::DownloadingGap(_) => { + peer.state = PeerSyncState::Available; + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_peer_download(who); + if let Some(start_block) = + validate_blocks::(&blocks, who, Some(request))? + { + gap_sync.blocks.insert(start_block, blocks, *who); + } + gap = true; + let blocks: Vec<_> = gap_sync + .blocks + .ready_blocks(gap_sync.best_queued_number + One::one()) + .into_iter() + .map(|block_data| { + let justifications = + block_data.block.justifications.or_else(|| { + legacy_justification_mapping( + block_data.block.justification, + ) + }); + IncomingBlock { + hash: block_data.block.hash, + header: block_data.block.header, + body: block_data.block.body, + indexed_body: block_data.block.indexed_body, + justifications, + origin: block_data.origin, + allow_missing_state: true, + import_existing: self.import_existing, + skip_execution: true, + state: None, + } + }) + .collect(); + debug!( + target: LOG_TARGET, + "Drained {} gap blocks from {}", + blocks.len(), + gap_sync.best_queued_number, + ); + blocks + } else { + debug!(target: LOG_TARGET, "Unexpected gap block response from {who}"); + return Err(BadPeer(*who, rep::NO_BLOCK)) + } + }, + PeerSyncState::DownloadingStale(_) => { + peer.state = PeerSyncState::Available; + if blocks.is_empty() { + debug!(target: LOG_TARGET, "Empty block response from {who}"); + return Err(BadPeer(*who, rep::NO_BLOCK)) + } + validate_blocks::(&blocks, who, Some(request))?; + blocks + .into_iter() + .map(|b| { + let justifications = b + .justifications + .or_else(|| legacy_justification_mapping(b.justification)); + IncomingBlock { + hash: b.hash, + header: b.header, + body: b.body, + indexed_body: None, + justifications, + origin: Some(*who), + allow_missing_state: true, + import_existing: self.import_existing, + skip_execution: self.skip_execution(), + state: None, + } + }) + .collect() + }, + PeerSyncState::AncestorSearch { current, start, state } => { + let matching_hash = match (blocks.get(0), self.client.hash(*current)) { + (Some(block), Ok(maybe_our_block_hash)) => { + trace!( + target: LOG_TARGET, + "Got ancestry block #{} ({}) from peer {}", + current, + block.hash, + who, + ); + maybe_our_block_hash.filter(|x| x == &block.hash) + }, + (None, _) => { + debug!( + target: LOG_TARGET, + "Invalid response when searching for ancestor from {who}", + ); + return Err(BadPeer(*who, rep::UNKNOWN_ANCESTOR)) + }, + (_, Err(e)) => { + info!( + target: LOG_TARGET, + "❌ Error answering legitimate blockchain query: {e}", + ); + return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR)) + }, + }; + if matching_hash.is_some() { + if *start < self.best_queued_number && + self.best_queued_number <= peer.best_number + { + // We've made progress on this chain since the search was started. + // Opportunistically set common number to updated number + // instead of the one that started the search. + peer.common_number = self.best_queued_number; + } else if peer.common_number < *current { + peer.common_number = *current; + } + } + if matching_hash.is_none() && current.is_zero() { + trace!( + target:LOG_TARGET, + "Ancestry search: genesis mismatch for peer {who}", + ); + return Err(BadPeer(*who, rep::GENESIS_MISMATCH)) + } + if let Some((next_state, next_num)) = + handle_ancestor_search_state(state, *current, matching_hash.is_some()) + { + peer.state = PeerSyncState::AncestorSearch { + current: next_num, + start: *start, + state: next_state, + }; + return Ok(OnBlockData::Request(*who, ancestry_request::(next_num))) + } else { + // Ancestry search is complete. Check if peer is on a stale fork unknown + // to us and add it to sync targets if necessary. + trace!( + target: LOG_TARGET, + "Ancestry search complete. Ours={} ({}), Theirs={} ({}), Common={:?} ({})", + self.best_queued_hash, + self.best_queued_number, + peer.best_hash, + peer.best_number, + matching_hash, + peer.common_number, + ); + if peer.common_number < peer.best_number && + peer.best_number < self.best_queued_number + { + trace!( + target: LOG_TARGET, + "Added fork target {} for {}", + peer.best_hash, + who, + ); + self.fork_targets + .entry(peer.best_hash) + .or_insert_with(|| ForkTarget { + number: peer.best_number, + parent_hash: None, + peers: Default::default(), + }) + .peers + .insert(*who); + } + peer.state = PeerSyncState::Available; + Vec::new() + } + }, + PeerSyncState::DownloadingWarpTargetBlock => { + peer.state = PeerSyncState::Available; + if let Some(warp_sync) = &mut self.warp_sync { + if blocks.len() == 1 { + validate_blocks::(&blocks, who, Some(request))?; + match warp_sync.import_target_block( + blocks.pop().expect("`blocks` len checked above."), + ) { + warp::TargetBlockImportResult::Success => + return Ok(OnBlockData::Continue), + warp::TargetBlockImportResult::BadResponse => + return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), + } + } else if blocks.is_empty() { + debug!(target: LOG_TARGET, "Empty block response from {who}"); + return Err(BadPeer(*who, rep::NO_BLOCK)) + } else { + debug!( + target: LOG_TARGET, + "Too many blocks ({}) in warp target block response from {}", + blocks.len(), + who, + ); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + } + } else { + debug!( + target: LOG_TARGET, + "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", + who, + ); + return Ok(OnBlockData::Continue) + } + }, + PeerSyncState::Available | + PeerSyncState::DownloadingJustification(..) | + PeerSyncState::DownloadingState | + PeerSyncState::DownloadingWarpProof => Vec::new(), + } + } else { + // When request.is_none() this is a block announcement. Just accept blocks. + validate_blocks::(&blocks, who, None)?; + blocks + .into_iter() + .map(|b| { + let justifications = b + .justifications + .or_else(|| legacy_justification_mapping(b.justification)); + IncomingBlock { + hash: b.hash, + header: b.header, + body: b.body, + indexed_body: None, + justifications, + origin: Some(*who), + allow_missing_state: true, + import_existing: false, + skip_execution: true, + state: None, + } + }) + .collect() + } + } else { + // We don't know of this peer, so we also did not request anything from it. + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + }; + + Ok(OnBlockData::Import(self.validate_and_queue_blocks(new_blocks, gap))) + } + + /// Submit a justification response for processing. + #[must_use] + pub fn on_block_justification( + &mut self, + who: PeerId, + response: BlockResponse, + ) -> Result, BadPeer> { + let peer = if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!( + target: LOG_TARGET, + "💔 Called on_block_justification with a peer ID of an unknown peer", + ); + return Ok(OnBlockJustification::Nothing) + }; + + self.allowed_requests.add(&who); + if let PeerSyncState::DownloadingJustification(hash) = peer.state { + peer.state = PeerSyncState::Available; + + // We only request one justification at a time + let justification = if let Some(block) = response.blocks.into_iter().next() { + if hash != block.hash { + warn!( + target: LOG_TARGET, + "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", + who, + hash, + block.hash, + ); + return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) + } + + block + .justifications + .or_else(|| legacy_justification_mapping(block.justification)) + } else { + // we might have asked the peer for a justification on a block that we assumed it + // had but didn't (regardless of whether it had a justification for it or not). + trace!( + target: LOG_TARGET, + "Peer {who:?} provided empty response for justification request {hash:?}", + ); + + None + }; + + if let Some((peer_id, hash, number, justifications)) = + self.extra_justifications.on_response(who, justification) + { + return Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) + } + } + + Ok(OnBlockJustification::Nothing) + } + + /// Report a justification import (successful or not). + pub fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { + let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; + self.extra_justifications + .try_finalize_root((hash, number), finalization_result, true); + self.allowed_requests.set_all(); + } + + /// Notify sync that a block has been finalized. + pub fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; + let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| { + is_descendent_of(&**client, base, block) + }); + + if let SyncMode::LightState { skip_proofs, .. } = &self.mode { + if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { + // Finalized a recent block. + let mut heads: Vec<_> = self.peers.values().map(|peer| peer.best_number).collect(); + heads.sort(); + let median = heads[heads.len() / 2]; + if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { + if let Ok(Some(header)) = self.client.header(*hash) { + log::debug!( + target: LOG_TARGET, + "Starting state sync for #{number} ({hash})", + ); + self.state_sync = Some(StateSync::new( + self.client.clone(), + header, + None, + None, + *skip_proofs, + )); + self.allowed_requests.set_all(); + } + } + } + } + + if let Err(err) = r { + warn!( + target: LOG_TARGET, + "💔 Error cleaning up pending extra justification data requests: {err}", + ); + } + } + + /// Submit a validated block announcement. + pub fn on_validated_block_announce( + &mut self, + is_best: bool, + who: PeerId, + announce: &BlockAnnounce, + ) { + let number = *announce.header.number(); + let hash = announce.header.hash(); + let parent_status = + self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown); + let known_parent = parent_status != BlockStatus::Unknown; + let ancient_parent = parent_status == BlockStatus::InChainPruned; + + let known = self.is_known(&hash); + let peer = if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!(target: LOG_TARGET, "💔 Called `on_validated_block_announce` with a bad peer ID"); + return + }; + + if let PeerSyncState::AncestorSearch { .. } = peer.state { + trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", who); + return + } + + if is_best { + // update their best block + peer.best_number = number; + peer.best_hash = hash; + } + + // If the announced block is the best they have and is not ahead of us, our common number + // is either one further ahead or it's the one they just announced, if we know about it. + if is_best { + if known && self.best_queued_number >= number { + self.update_peer_common_number(&who, number); + } else if announce.header.parent_hash() == &self.best_queued_hash || + known_parent && self.best_queued_number >= number + { + self.update_peer_common_number(&who, number.saturating_sub(One::one())); + } + } + self.allowed_requests.add(&who); + + // known block case + if known || self.is_already_downloading(&hash) { + trace!(target: "sync", "Known block announce from {}: {}", who, hash); + if let Some(target) = self.fork_targets.get_mut(&hash) { + target.peers.insert(who); + } + return + } + + if ancient_parent { + trace!( + target: "sync", + "Ignored ancient block announced from {}: {} {:?}", + who, + hash, + announce.header, + ); + return + } + + if self.status().state == SyncState::Idle { + trace!( + target: "sync", + "Added sync target for block announced from {}: {} {:?}", + who, + hash, + announce.summary(), + ); + self.fork_targets + .entry(hash) + .or_insert_with(|| ForkTarget { + number, + parent_hash: Some(*announce.header.parent_hash()), + peers: Default::default(), + }) + .peers + .insert(who); + } + } + + /// Notify that a sync peer has disconnected. + #[must_use] + pub 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.extra_justifications.peer_disconnected(who); + self.allowed_requests.set_all(); + self.fork_targets.retain(|_, target| { + target.peers.remove(who); + !target.peers.is_empty() + }); + + let blocks = self.ready_blocks(); + + (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) + } + + /// Get prometheus metrics. + pub fn metrics(&self) -> Metrics { + Metrics { + queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), + fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), + justifications: self.extra_justifications.metrics(), + } + } + + /// Returns the median seen block number. + fn median_seen(&self) -> Option> { + let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); + + if best_seens.is_empty() { + None + } else { + let middle = best_seens.len() / 2; + + // Not the "perfect median" when we have an even number of peers. + Some(*best_seens.select_nth_unstable(middle).1) + } + } + + fn required_block_attributes(&self) -> BlockAttributes { + match self.mode { + SyncMode::Full => + BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, + SyncMode::LightState { storage_chain_mode: false, .. } | SyncMode::Warp => + BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, + SyncMode::LightState { storage_chain_mode: true, .. } => + BlockAttributes::HEADER | + BlockAttributes::JUSTIFICATION | + BlockAttributes::INDEXED_BODY, + } + } + + fn skip_execution(&self) -> bool { + match self.mode { + SyncMode::Full => false, + SyncMode::LightState { .. } => true, + SyncMode::Warp => true, + } + } + + fn validate_and_queue_blocks( + &mut self, + mut new_blocks: Vec>, + gap: bool, + ) -> ImportBlocksAction { + let orig_len = new_blocks.len(); + new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); + if new_blocks.len() != orig_len { + debug!( + target: LOG_TARGET, + "Ignoring {} blocks that are already queued", + orig_len - new_blocks.len(), + ); + } + + let origin = if !gap && !self.status().state.is_major_syncing() { + BlockOrigin::NetworkBroadcast + } else { + BlockOrigin::NetworkInitialSync + }; + + if let Some((h, n)) = new_blocks + .last() + .and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) + { + trace!( + target:LOG_TARGET, + "Accepted {} blocks ({:?}) with origin {:?}", + new_blocks.len(), + h, + origin, + ); + self.on_block_queued(h, n) + } + self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); + + ImportBlocksAction { origin, blocks: new_blocks } + } + + fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { + if let Some(peer) = self.peers.get_mut(peer_id) { + peer.update_common_number(new_common); + } + } + + /// Called when a block has been queued for import. + /// + /// Updates our internal state for best queued block and then goes + /// through all peers to update our view of their state as well. + fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor) { + if self.fork_targets.remove(hash).is_some() { + trace!(target: LOG_TARGET, "Completed fork sync {hash:?}"); + } + if let Some(gap_sync) = &mut self.gap_sync { + if number > gap_sync.best_queued_number && number <= gap_sync.target { + gap_sync.best_queued_number = number; + } + } + if number > self.best_queued_number { + self.best_queued_number = number; + self.best_queued_hash = *hash; + // Update common blocks + for (n, peer) in self.peers.iter_mut() { + if let PeerSyncState::AncestorSearch { .. } = peer.state { + // Wait for ancestry search to complete first. + continue + } + let new_common_number = + if peer.best_number >= number { number } else { peer.best_number }; + trace!( + target: LOG_TARGET, + "Updating peer {} info, ours={}, common={}->{}, their best={}", + n, + number, + peer.common_number, + new_common_number, + peer.best_number, + ); + peer.common_number = new_common_number; + } + } + self.allowed_requests.set_all(); + } + + /// 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>> + '_ { + self.blocks.clear(); + if let Err(e) = self.reset_sync_start_point() { + warn!(target: LOG_TARGET, "💔 Unable to restart sync: {e}"); + } + self.allowed_requests.set_all(); + debug!( + target: LOG_TARGET, + "Restarted with {} ({})", + self.best_queued_number, + self.best_queued_hash, + ); + let old_peers = std::mem::take(&mut self.peers); + + 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(peer_id, p); + return None + } + + // handle peers that were in other states. + 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)), + } + }) + } + + /// Find a block to start sync from. If we sync with state, that's the latest block we have + /// state for. + fn reset_sync_start_point(&mut self) -> Result<(), ClientError> { + let info = self.client.info(); + if matches!(self.mode, SyncMode::LightState { .. }) && info.finalized_state.is_some() { + warn!( + target: LOG_TARGET, + "Can't use fast sync mode with a partially synced database. Reverting to full sync mode." + ); + self.mode = SyncMode::Full; + } + if matches!(self.mode, SyncMode::Warp) && info.finalized_state.is_some() { + warn!( + target: LOG_TARGET, + "Can't use warp sync mode with a partially synced database. Reverting to full sync mode." + ); + self.mode = SyncMode::Full; + } + self.import_existing = false; + self.best_queued_hash = info.best_hash; + self.best_queued_number = info.best_number; + + if self.mode == SyncMode::Full && + self.client.block_status(info.best_hash)? != BlockStatus::InChainWithState + { + self.import_existing = true; + // Latest state is missing, start with the last finalized state or genesis instead. + if let Some((hash, number)) = info.finalized_state { + debug!(target: LOG_TARGET, "Starting from finalized state #{number}"); + self.best_queued_hash = hash; + self.best_queued_number = number; + } else { + debug!(target: LOG_TARGET, "Restarting from genesis"); + self.best_queued_hash = Default::default(); + self.best_queued_number = Zero::zero(); + } + } + + if let Some((start, end)) = info.block_gap { + debug!(target: LOG_TARGET, "Starting gap sync #{start} - #{end}"); + self.gap_sync = Some(GapSync { + best_queued_number: start - One::one(), + target: end, + blocks: BlockCollection::new(), + }); + } + trace!( + target: LOG_TARGET, + "Restarted sync at #{} ({:?})", + self.best_queued_number, + self.best_queued_hash, + ); + Ok(()) + } + + /// What is the status of the block corresponding to the given hash? + fn block_status(&self, hash: &B::Hash) -> Result { + if self.queue_blocks.contains(hash) { + return Ok(BlockStatus::Queued) + } + self.client.block_status(*hash) + } + + /// Is the block corresponding to the given hash known? + fn is_known(&self, hash: &B::Hash) -> bool { + self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + } + + /// Is any peer downloading the given hash? + fn is_already_downloading(&self, hash: &B::Hash) -> bool { + self.peers + .iter() + .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) + } + + /// Check if the peer is known to the sync state machine. Used for sanity checks. + 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> { + self.blocks + .ready_blocks(self.best_queued_number + One::one()) + .into_iter() + .map(|block_data| { + let justifications = block_data + .block + .justifications + .or_else(|| legacy_justification_mapping(block_data.block.justification)); + IncomingBlock { + hash: block_data.block.hash, + header: block_data.block.header, + body: block_data.block.body, + indexed_body: block_data.block.indexed_body, + justifications, + origin: block_data.origin, + allow_missing_state: true, + import_existing: self.import_existing, + skip_execution: self.skip_execution(), + state: None, + } + }) + .collect() + } + + /// Set the warp sync target block externally in case we skip warp proofs downloading. + pub fn set_warp_sync_target_block(&mut self, header: B::Header) { + if let Some(ref mut warp_sync) = self.warp_sync { + warp_sync.set_target_block(header); + } else { + self.warp_sync_target_block_header = Some(header); + } + } + + /// Generate block request for downloading of the target block body during warp sync. + fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { + let sync = &self.warp_sync.as_ref()?; + + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) + { + // Only one pending warp target block request is allowed. + return None + } + + if let Some((target_number, request)) = sync.next_target_block_request() { + // Find a random peer that has a block with the target number. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target_number { + trace!(target: LOG_TARGET, "New warp target block request for {id}"); + peer.state = PeerSyncState::DownloadingWarpTargetBlock; + self.allowed_requests.clear(); + return Some((*id, request)) + } + } + } + + None + } + + /// Submit blocks received in a response. + #[must_use] + pub fn on_block_response( + &mut self, + peer_id: PeerId, + request: BlockRequest, + blocks: Vec>, + ) -> OnBlockResponse { + let block_response = BlockResponse:: { id: request.id, blocks }; + + let blocks_range = || match ( + block_response + .blocks + .first() + .and_then(|b| b.header.as_ref().map(|h| h.number())), + block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), + ) { + (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), + (Some(first), Some(_)) => format!(" ({})", first), + _ => Default::default(), + }; + trace!( + target: LOG_TARGET, + "BlockResponse {} from {} with {} blocks {}", + block_response.id, + peer_id, + block_response.blocks.len(), + blocks_range(), + ); + + if request.fields == BlockAttributes::JUSTIFICATION { + match self.on_block_justification(peer_id, block_response) { + 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); + OnBlockResponse::Nothing + }, + } + } else { + match self.on_block_data(&peer_id, Some(request), block_response) { + 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); + OnBlockResponse::Nothing + }, + } + } + } + + /// Submit a state received in a response. + #[must_use] + pub fn on_state_response( + &mut self, + peer_id: PeerId, + response: OpaqueStateResponse, + ) -> Option> { + match self.on_state_data(&peer_id, response) { + Ok(OnStateData::Import(origin, block)) => + Some(ImportBlocksAction { origin, blocks: vec![block] }), + Ok(OnStateData::Continue) => None, + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + None + }, + } + } + + /// Submit a warp proof response received. + pub fn on_warp_sync_response(&mut self, peer_id: PeerId, response: EncodedProof) { + if let Err(BadPeer(id, repu)) = self.on_warp_sync_data(&peer_id, response) { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + } + } + + /// Get justification requests scheduled by sync to be sent out. + pub fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { + let peers = &mut self.peers; + let mut matcher = self.extra_justifications.matcher(); + std::iter::from_fn(move || { + if let Some((peer, request)) = matcher.next(peers) { + peers + .get_mut(&peer) + .expect( + "`Matcher::next` guarantees the `PeerId` comes from the given peers; qed", + ) + .state = PeerSyncState::DownloadingJustification(request.0); + let req = BlockRequest:: { + id: 0, + fields: BlockAttributes::JUSTIFICATION, + from: FromBlock::Hash(request.0), + direction: Direction::Ascending, + max: Some(1), + }; + Some((peer, req)) + } else { + None + } + }) + .collect() + } + + /// Get block requests scheduled by sync to be sent out. + pub fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { + if self.mode == SyncMode::Warp { + return self + .warp_target_block_request() + .map_or_else(|| Vec::new(), |req| Vec::from([req])) + } + + if self.allowed_requests.is_empty() || self.state_sync.is_some() { + return Vec::new() + } + + if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { + trace!(target: LOG_TARGET, "Too many blocks in the queue."); + return Vec::new() + } + let is_major_syncing = self.status().state.is_major_syncing(); + let attrs = self.required_block_attributes(); + let blocks = &mut self.blocks; + let fork_targets = &mut self.fork_targets; + let last_finalized = + std::cmp::min(self.best_queued_number, self.client.info().finalized_number); + let best_queued = self.best_queued_number; + let client = &self.client; + let queue = &self.queue_blocks; + let allowed_requests = self.allowed_requests.take(); + let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; + let max_blocks_per_request = self.max_blocks_per_request; + let gap_sync = &mut self.gap_sync; + self.peers + .iter_mut() + .filter_map(move |(&id, peer)| { + if !peer.state.is_available() || !allowed_requests.contains(&id) { + return None + } + + // If our best queued is more than `MAX_BLOCKS_TO_LOOK_BACKWARDS` blocks away from + // the common number, the peer best number is higher than our best queued and the + // common number is smaller than the last finalized block number, we should do an + // ancestor search to find a better common block. If the queue is full we wait till + // all blocks are imported though. + if best_queued.saturating_sub(peer.common_number) > + MAX_BLOCKS_TO_LOOK_BACKWARDS.into() && + best_queued < peer.best_number && + peer.common_number < last_finalized && + queue.len() <= MAJOR_SYNC_BLOCKS.into() + { + trace!( + target: LOG_TARGET, + "Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.", + id, + peer.common_number, + best_queued, + ); + let current = std::cmp::min(peer.best_number, best_queued); + peer.state = PeerSyncState::AncestorSearch { + current, + start: best_queued, + state: AncestorSearchState::ExponentialBackoff(One::one()), + }; + Some((id, ancestry_request::(current))) + } else if let Some((range, req)) = peer_block_request( + &id, + peer, + blocks, + attrs, + max_parallel, + max_blocks_per_request, + last_finalized, + best_queued, + ) { + peer.state = PeerSyncState::DownloadingNew(range.start); + trace!( + target: LOG_TARGET, + "New block request for {}, (best:{}, common:{}) {:?}", + id, + peer.best_number, + peer.common_number, + req, + ); + Some((id, req)) + } else if let Some((hash, req)) = fork_sync_request( + &id, + fork_targets, + best_queued, + last_finalized, + attrs, + |hash| { + if queue.contains(hash) { + BlockStatus::Queued + } else { + client.block_status(*hash).unwrap_or(BlockStatus::Unknown) + } + }, + max_blocks_per_request, + ) { + trace!(target: LOG_TARGET, "Downloading fork {hash:?} from {id}"); + peer.state = PeerSyncState::DownloadingStale(hash); + Some((id, req)) + } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { + peer_gap_block_request( + &id, + peer, + &mut sync.blocks, + attrs, + sync.target, + sync.best_queued_number, + max_blocks_per_request, + ) + }) { + peer.state = PeerSyncState::DownloadingGap(range.start); + trace!( + target: LOG_TARGET, + "New gap block request for {}, (best:{}, common:{}) {:?}", + id, + peer.best_number, + peer.common_number, + req, + ); + Some((id, req)) + } else { + None + } + }) + .collect() + } + + /// Get a state request scheduled by sync to be sent out (if any). + pub fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { + if self.allowed_requests.is_empty() { + return None + } + if (self.state_sync.is_some() || self.warp_sync.is_some()) && + self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) + { + // Only one pending state request is allowed. + return None + } + if let Some(sync) = &self.state_sync { + if sync.is_complete() { + return None + } + + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.common_number >= sync.target_block_num() { + peer.state = PeerSyncState::DownloadingState; + let request = sync.next_request(); + trace!(target: LOG_TARGET, "New StateRequest for {}: {:?}", id, request); + self.allowed_requests.clear(); + return Some((*id, OpaqueStateRequest(Box::new(request)))) + } + } + } + if let Some(sync) = &self.warp_sync { + if sync.is_complete() { + return None + } + if let (Some(request), Some(target)) = + (sync.next_state_request(), sync.target_block_number()) + { + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target { + trace!(target: LOG_TARGET, "New StateRequest for {id}: {request:?}"); + peer.state = PeerSyncState::DownloadingState; + self.allowed_requests.clear(); + return Some((*id, OpaqueStateRequest(Box::new(request)))) + } + } + } + } + None + } + + /// Get a warp proof request scheduled by sync to be sent out (if any). + pub fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { + if let Some(sync) = &self.warp_sync { + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) + { + // Only one pending state request is allowed. + return None + } + if let Some(request) = sync.next_warp_proof_request() { + let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); + if !targets.is_empty() { + targets.sort(); + let median = targets[targets.len() / 2]; + // Find a random peer that is synced as much as peer majority. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= median { + trace!(target: LOG_TARGET, "New WarpProofRequest for {id}"); + peer.state = PeerSyncState::DownloadingWarpProof; + self.allowed_requests.clear(); + return Some((*id, request)) + } + } + } + } + } + None + } + + fn on_state_data( + &mut self, + who: &PeerId, + response: OpaqueStateResponse, + ) -> Result, BadPeer> { + let response: Box = response.0.downcast().map_err(|_error| { + error!( + target: LOG_TARGET, + "Failed to downcast opaque state response, this is an implementation bug." + ); + + BadPeer(*who, rep::BAD_RESPONSE) + })?; + + if let Some(peer) = self.peers.get_mut(who) { + if let PeerSyncState::DownloadingState = peer.state { + peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); + } + } + let import_result = if let Some(sync) = &mut self.state_sync { + debug!( + target: LOG_TARGET, + "Importing state data from {} with {} keys, {} proof nodes.", + who, + response.entries.len(), + response.proof.len(), + ); + sync.import(*response) + } else if let Some(sync) = &mut self.warp_sync { + debug!( + target: LOG_TARGET, + "Importing state data from {} with {} keys, {} proof nodes.", + who, + response.entries.len(), + response.proof.len(), + ); + sync.import_state(*response) + } else { + debug!(target: LOG_TARGET, "Ignored obsolete state response from {who}"); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + }; + + match import_result { + ImportResult::Import(hash, header, state, body, justifications) => { + let origin = BlockOrigin::NetworkInitialSync; + let block = IncomingBlock { + hash, + header: Some(header), + body, + indexed_body: None, + justifications, + origin: None, + allow_missing_state: true, + import_existing: true, + skip_execution: self.skip_execution(), + state: Some(state), + }; + debug!(target: LOG_TARGET, "State download is complete. Import is queued"); + Ok(OnStateData::Import(origin, block)) + }, + ImportResult::Continue => Ok(OnStateData::Continue), + ImportResult::BadResponse => { + debug!(target: LOG_TARGET, "Bad state data received from {who}"); + Err(BadPeer(*who, rep::BAD_BLOCK)) + }, + } + } + + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { + if let Some(peer) = self.peers.get_mut(who) { + if let PeerSyncState::DownloadingWarpProof = peer.state { + peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); + } + } + let import_result = if let Some(sync) = &mut self.warp_sync { + debug!( + target: LOG_TARGET, + "Importing warp proof data from {}, {} bytes.", + who, + response.0.len(), + ); + sync.import_warp_proof(response) + } else { + debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {who}"); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + }; + + match import_result { + WarpProofImportResult::Success => Ok(()), + WarpProofImportResult::BadResponse => { + debug!(target: LOG_TARGET, "Bad proof data received from {who}"); + Err(BadPeer(*who, rep::BAD_BLOCK)) + }, + } + } + + /// 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. If an error is returned, the pending response + /// from the peer must be dropped. + #[must_use] + pub fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + ) -> Box, BadPeer>>> { + trace!(target: LOG_TARGET, "Imported {imported} of {count}"); + + let mut output = Vec::new(); + + let mut has_error = false; + for (_, hash) in &results { + self.queue_blocks.remove(hash); + self.blocks.clear_queued(hash); + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_queued(hash); + } + } + for (result, hash) in results { + if has_error { + break + } + + has_error |= result.is_err(); + + match result { + Ok(BlockImportStatus::ImportedKnown(number, who)) => + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); + }, + Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { + if aux.clear_justification_requests { + trace!( + target: LOG_TARGET, + "Block imported clears all pending justification requests {number}: {hash:?}", + ); + self.clear_justification_requests(); + } + + if aux.needs_justification { + trace!( + target: LOG_TARGET, + "Block imported but requires justification {number}: {hash:?}", + ); + self.request_justification(&hash, number); + } + + if aux.bad_justification { + if let Some(ref peer) = who { + warn!("💔 Sent block with bad justification to import"); + output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); + } + } + + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); + } + let state_sync_complete = + self.state_sync.as_ref().map_or(false, |s| s.target() == hash); + if state_sync_complete { + info!( + target: LOG_TARGET, + "State sync is complete ({} MiB), restarting block sync.", + self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)), + ); + self.state_sync = None; + self.mode = SyncMode::Full; + output.extend(self.restart()); + } + let warp_sync_complete = self + .warp_sync + .as_ref() + .map_or(false, |s| s.target_block_hash() == Some(hash)); + if warp_sync_complete { + info!( + target: LOG_TARGET, + "Warp sync is complete ({} MiB), restarting block sync.", + self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)), + ); + self.warp_sync = None; + self.mode = SyncMode::Full; + output.extend(self.restart()); + } + let gap_sync_complete = + self.gap_sync.as_ref().map_or(false, |s| s.target == number); + if gap_sync_complete { + info!( + target: LOG_TARGET, + "Block history download is complete." + ); + self.gap_sync = None; + } + }, + Err(BlockImportError::IncompleteHeader(who)) => + if let Some(peer) = who { + warn!( + target: LOG_TARGET, + "💔 Peer sent block with incomplete header to import", + ); + output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); + output.extend(self.restart()); + }, + Err(BlockImportError::VerificationFailed(who, e)) => { + let extra_message = + who.map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); + + warn!( + target: LOG_TARGET, + "💔 Verification failed for block {hash:?}{extra_message}: {e:?}", + ); + + if let Some(peer) = who { + output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); + } + + output.extend(self.restart()); + }, + Err(BlockImportError::BadBlock(who)) => + if let Some(peer) = who { + warn!( + target: LOG_TARGET, + "💔 Block {hash:?} received from peer {peer} has been blacklisted", + ); + output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); + }, + Err(BlockImportError::MissingState) => { + // This may happen if the chain we were requesting upon has been discarded + // in the meantime because other chain has been finalized. + // Don't mark it as bad as it still may be synced if explicitly requested. + trace!(target: LOG_TARGET, "Obsolete block {hash:?}"); + }, + e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { + warn!(target: LOG_TARGET, "💔 Error importing block {hash:?}: {}", e.unwrap_err()); + self.state_sync = None; + self.warp_sync = None; + output.extend(self.restart()); + }, + Err(BlockImportError::Cancelled) => {}, + }; + } + + self.allowed_requests.set_all(); + Box::new(output.into_iter()) + } +} + +// This is purely during a backwards compatible transitionary period and should be removed +// once we can assume all nodes can send and receive multiple Justifications +// The ID tag is hardcoded here to avoid depending on the GRANDPA crate. +// See: https://github.com/paritytech/substrate/issues/8172 +fn legacy_justification_mapping( + justification: Option, +) -> Option { + justification.map(|just| (*b"FRNK", just).into()) +} + +/// Request the ancestry for a block. Sends a request for header and justification for the given +/// block number. Used during ancestry search. +fn ancestry_request(block: NumberFor) -> BlockRequest { + BlockRequest:: { + id: 0, + fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, + from: FromBlock::Number(block), + direction: Direction::Ascending, + max: Some(1), + } +} + +/// The ancestor search state expresses which algorithm, and its stateful parameters, we are using +/// to try to find an ancestor block +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub(crate) enum AncestorSearchState { + /// Use exponential backoff to find an ancestor, then switch to binary search. + /// We keep track of the exponent. + ExponentialBackoff(NumberFor), + /// Using binary search to find the best ancestor. + /// We keep track of left and right bounds. + BinarySearch(NumberFor, NumberFor), +} + +/// This function handles the ancestor search strategy used. The goal is to find a common point +/// that both our chains agree on that is as close to the tip as possible. +/// The way this works is we first have an exponential backoff strategy, where we try to step +/// forward until we find a block hash mismatch. The size of the step doubles each step we take. +/// +/// When we've found a block hash mismatch we then fall back to a binary search between the two +/// last known points to find the common block closest to the tip. +fn handle_ancestor_search_state( + state: &AncestorSearchState, + curr_block_num: NumberFor, + block_hash_match: bool, +) -> Option<(AncestorSearchState, NumberFor)> { + let two = >::one() + >::one(); + match state { + AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => { + let next_distance_to_tip = *next_distance_to_tip; + if block_hash_match && next_distance_to_tip == One::one() { + // We found the ancestor in the first step so there is no need to execute binary + // search. + return None + } + if block_hash_match { + let left = curr_block_num; + let right = left + next_distance_to_tip / two; + let middle = left + (right - left) / two; + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } else { + let next_block_num = + curr_block_num.checked_sub(&next_distance_to_tip).unwrap_or_else(Zero::zero); + let next_distance_to_tip = next_distance_to_tip * two; + Some(( + AncestorSearchState::ExponentialBackoff(next_distance_to_tip), + next_block_num, + )) + } + }, + AncestorSearchState::BinarySearch(mut left, mut right) => { + if left >= curr_block_num { + return None + } + if block_hash_match { + left = curr_block_num; + } else { + right = curr_block_num; + } + assert!(right >= left); + let middle = left + (right - left) / two; + if middle == curr_block_num { + None + } else { + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } + }, + } +} + +/// Get a new block request for the peer if any. +fn peer_block_request( + id: &PeerId, + peer: &PeerSync, + blocks: &mut BlockCollection, + attrs: BlockAttributes, + max_parallel_downloads: u32, + max_blocks_per_request: u32, + finalized: NumberFor, + best_num: NumberFor, +) -> Option<(Range>, BlockRequest)> { + if best_num >= peer.best_number { + // Will be downloaded as alternative fork instead. + return None + } else if peer.common_number < finalized { + trace!( + target: LOG_TARGET, + "Requesting pre-finalized chain from {:?}, common={}, finalized={}, peer best={}, our best={}", + id, peer.common_number, finalized, peer.best_number, best_num, + ); + } + let range = blocks.needed_blocks( + *id, + max_blocks_per_request, + peer.best_number, + peer.common_number, + max_parallel_downloads, + MAX_DOWNLOAD_AHEAD, + )?; + + // The end is not part of the range. + let last = range.end.saturating_sub(One::one()); + + let from = if peer.best_number == last { + FromBlock::Hash(peer.best_hash) + } else { + FromBlock::Number(last) + }; + + let request = BlockRequest:: { + id: 0, + fields: attrs, + from, + direction: Direction::Descending, + max: Some((range.end - range.start).saturated_into::()), + }; + + Some((range, request)) +} + +/// Get a new block request for the peer if any. +fn peer_gap_block_request( + id: &PeerId, + peer: &PeerSync, + blocks: &mut BlockCollection, + attrs: BlockAttributes, + target: NumberFor, + common_number: NumberFor, + max_blocks_per_request: u32, +) -> Option<(Range>, BlockRequest)> { + let range = blocks.needed_blocks( + *id, + max_blocks_per_request, + std::cmp::min(peer.best_number, target), + common_number, + 1, + MAX_DOWNLOAD_AHEAD, + )?; + + // The end is not part of the range. + let last = range.end.saturating_sub(One::one()); + let from = FromBlock::Number(last); + + let request = BlockRequest:: { + id: 0, + fields: attrs, + from, + direction: Direction::Descending, + max: Some((range.end - range.start).saturated_into::()), + }; + Some((range, request)) +} + +/// Get pending fork sync targets for a peer. +fn fork_sync_request( + id: &PeerId, + targets: &mut HashMap>, + best_num: NumberFor, + finalized: NumberFor, + attributes: BlockAttributes, + check_block: impl Fn(&B::Hash) -> BlockStatus, + max_blocks_per_request: u32, +) -> Option<(B::Hash, BlockRequest)> { + targets.retain(|hash, r| { + if r.number <= finalized { + trace!( + target: LOG_TARGET, + "Removed expired fork sync request {:?} (#{})", + hash, + r.number, + ); + return false + } + if check_block(hash) != BlockStatus::Unknown { + trace!( + target: LOG_TARGET, + "Removed obsolete fork sync request {:?} (#{})", + hash, + r.number, + ); + return false + } + true + }); + for (hash, r) in targets { + if !r.peers.contains(&id) { + continue + } + // Download the fork only if it is behind or not too far ahead our tip of the chain + // Otherwise it should be downloaded in full sync mode. + if r.number <= best_num || + (r.number - best_num).saturated_into::() < max_blocks_per_request as u32 + { + let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block); + let count = if parent_status == BlockStatus::Unknown { + (r.number - finalized).saturated_into::() // up to the last finalized block + } else { + // request only single block + 1 + }; + trace!( + target: LOG_TARGET, + "Downloading requested fork {hash:?} from {id}, {count} blocks", + ); + return Some(( + *hash, + BlockRequest:: { + id: 0, + fields: attributes, + from: FromBlock::Hash(*hash), + direction: Direction::Descending, + max: Some(count), + }, + )) + } else { + trace!(target: LOG_TARGET, "Fork too far in the future: {:?} (#{})", hash, r.number); + } + } + None +} + +/// Returns `true` if the given `block` is a descendent of `base`. +fn is_descendent_of( + client: &T, + base: &Block::Hash, + block: &Block::Hash, +) -> sp_blockchain::Result +where + Block: BlockT, + T: HeaderMetadata + ?Sized, +{ + if base == block { + return Ok(false) + } + + let ancestor = sp_blockchain::lowest_common_ancestor(client, *block, *base)?; + + Ok(ancestor.hash == *base) +} + +/// Validate that the given `blocks` are correct. +/// Returns the number of the first block in the sequence. +/// +/// It is expected that `blocks` are in ascending order. +fn validate_blocks( + blocks: &Vec>, + who: &PeerId, + request: Option>, +) -> Result>, BadPeer> { + if let Some(request) = request { + if Some(blocks.len() as _) > request.max { + debug!( + target: LOG_TARGET, + "Received more blocks than requested from {}. Expected in maximum {:?}, got {}.", + who, + request.max, + blocks.len(), + ); + + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + } + + let block_header = + if request.direction == Direction::Descending { blocks.last() } else { blocks.first() } + .and_then(|b| b.header.as_ref()); + + let expected_block = block_header.as_ref().map_or(false, |h| match request.from { + FromBlock::Hash(hash) => h.hash() == hash, + FromBlock::Number(n) => h.number() == &n, + }); + + if !expected_block { + debug!( + target: LOG_TARGET, + "Received block that was not requested. Requested {:?}, got {:?}.", + request.from, + block_header, + ); + + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + } + + if request.fields.contains(BlockAttributes::HEADER) && + blocks.iter().any(|b| b.header.is_none()) + { + trace!( + target: LOG_TARGET, + "Missing requested header for a block in response from {who}.", + ); + + return Err(BadPeer(*who, rep::BAD_RESPONSE)) + } + + if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none()) + { + trace!( + target: LOG_TARGET, + "Missing requested body for a block in response from {who}.", + ); + + return Err(BadPeer(*who, rep::BAD_RESPONSE)) + } + } + + for b in blocks { + if let Some(header) = &b.header { + let hash = header.hash(); + if hash != b.hash { + debug!( + target:LOG_TARGET, + "Bad header received from {}. Expected hash {:?}, got {:?}", + who, + b.hash, + hash, + ); + return Err(BadPeer(*who, rep::BAD_BLOCK)) + } + } + if let (Some(header), Some(body)) = (&b.header, &b.body) { + let expected = *header.extrinsics_root(); + let got = HashingFor::::ordered_trie_root( + body.iter().map(Encode::encode).collect(), + sp_runtime::StateVersion::V0, + ); + if expected != got { + debug!( + target:LOG_TARGET, + "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", + b.hash, + who, + expected, + got, + ); + return Err(BadPeer(*who, rep::BAD_BLOCK)) + } + } + } + + Ok(blocks.first().and_then(|b| b.header.as_ref()).map(|h| *h.number())) +} diff --git a/substrate/client/network/sync/src/chain_sync/test.rs b/substrate/client/network/sync/src/chain_sync/test.rs new file mode 100644 index 00000000000..6f9fea1b161 --- /dev/null +++ b/substrate/client/network/sync/src/chain_sync/test.rs @@ -0,0 +1,1085 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Tests of [`ChainSync`]. + +use super::*; +use crate::service::network::NetworkServiceProvider; +use futures::executor::block_on; +use sc_block_builder::BlockBuilderProvider; +use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; +use sp_blockchain::HeaderBackend; +use substrate_test_runtime_client::{ + runtime::{Block, Hash, Header}, + BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, + TestClientBuilder, TestClientBuilderExt, +}; + +#[test] +fn processes_empty_response_on_justification_request_for_unknown_block() { + // if we ask for a justification for a given block to a peer that doesn't know that block + // (different from not having a justification), the peer will reply with an empty response. + // internally we should process the response as the justification not being available. + + let client = Arc::new(TestClientBuilder::new().build()); + let peer_id = PeerId::random(); + + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let (a1_hash, a1_number) = { + let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + (a1.hash(), *a1.header.number()) + }; + + // add a new peer with the same best block + sync.new_peer(peer_id, a1_hash, a1_number).unwrap(); + + // and request a justification for the block + sync.request_justification(&a1_hash, a1_number); + + // the justification request should be scheduled to that peer + assert!(sync + .justification_requests() + .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); + + // there's one in-flight extra request to the expected peer + assert!(sync.extra_justifications.active_requests().any(|(who, (hash, number))| { + *who == peer_id && *hash == a1_hash && *number == a1_number + })); + + // if the peer replies with an empty response (i.e. it doesn't know the block), + // the active request should be cleared. + assert_eq!( + sync.on_block_justification(peer_id, BlockResponse:: { id: 0, blocks: vec![] }), + Ok(OnBlockJustification::Nothing), + ); + + // there should be no in-flight requests + assert_eq!(sync.extra_justifications.active_requests().count(), 0); + + // and the request should now be pending again, waiting for reschedule + assert!(sync + .extra_justifications + .pending_requests() + .any(|(hash, number)| { *hash == a1_hash && *number == a1_number })); +} + +#[test] +fn restart_doesnt_affect_peers_downloading_finality_data() { + let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let peer_id2 = PeerId::random(); + let peer_id3 = PeerId::random(); + + let mut new_blocks = |n| { + for _ in 0..n { + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + } + + let info = client.info(); + (info.best_hash, info.best_number) + }; + + let (b1_hash, b1_number) = new_blocks(50); + + // add 2 peers at blocks that we don't have locally + sync.new_peer(peer_id1, Hash::random(), 42).unwrap(); + sync.new_peer(peer_id2, Hash::random(), 10).unwrap(); + + // we wil send block requests to these peers + // for these blocks we don't know about + assert!(sync + .block_requests() + .into_iter() + .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); + + // add a new peer at a known block + sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); + + // we request a justification for a block we have locally + sync.request_justification(&b1_hash, b1_number); + + // the justification request should be scheduled to the + // new peer which is at the given block + assert!(sync.justification_requests().iter().any(|(p, r)| { + *p == peer_id3 && + r.fields == BlockAttributes::JUSTIFICATION && + r.from == FromBlock::Hash(b1_hash) + })); + + assert_eq!( + sync.peers.get(&peer_id3).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + + // we restart the sync state + 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(|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!( + sync.peers.get(&peer_id3).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + + // Set common block to something that we don't have (e.g. failed import) + sync.peers.get_mut(&peer_id3).unwrap().common_number = 100; + let _ = sync.restart().count(); + assert_eq!(sync.peers.get(&peer_id3).unwrap().common_number, 50); +} + +/// Send a block annoucnement for the given `header`. +fn send_block_announce(header: Header, peer_id: PeerId, sync: &mut ChainSync) { + let announce = BlockAnnounce { + header: header.clone(), + state: Some(BlockState::Best), + data: Some(Vec::new()), + }; + + sync.on_validated_block_announce(true, peer_id, &announce); +} + +/// Create a block response from the given `blocks`. +fn create_block_response(blocks: Vec) -> BlockResponse { + BlockResponse:: { + id: 0, + blocks: blocks + .into_iter() + .map(|b| BlockData:: { + hash: b.hash(), + header: Some(b.header().clone()), + body: Some(b.deconstruct().1), + indexed_body: None, + receipt: None, + message_queue: None, + justification: None, + justifications: None, + }) + .collect(), + } +} + +/// Get a block request from `sync` and check that is matches the expected request. +fn get_block_request( + sync: &mut ChainSync, + from: FromBlock, + max: u32, + peer: &PeerId, +) -> BlockRequest { + let requests = sync.block_requests(); + + log::trace!(target: LOG_TARGET, "Requests: {requests:?}"); + + assert_eq!(1, requests.len()); + assert_eq!(*peer, requests[0].0); + + let request = requests[0].1.clone(); + + assert_eq!(from, request.from); + assert_eq!(Some(max), request.max); + request +} + +/// Build and import a new best block. +fn build_block(client: &mut Arc, at: Option, fork: bool) -> Block { + let at = at.unwrap_or_else(|| client.info().best_hash); + + let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); + + if fork { + block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); + } + + let block = block_builder.build().unwrap().block; + + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + block +} + +/// This test is a regression test as observed on a real network. +/// +/// The node is connected to multiple peers. Both of these peers are having a best block (1) +/// that is below our best block (3). Now peer 2 announces a fork of block 3 that we will +/// request from peer 2. After importing the fork, peer 2 and then peer 1 will announce block 4. +/// But as peer 1 in our view is still at block 1, we will request block 2 (which we already +/// have) from it. In the meanwhile peer 2 sends us block 4 and 3 and we send another request +/// for block 2 to peer 2. Peer 1 answers with block 2 and then peer 2. This will need to +/// succeed, as we have requested block 2 from both peers. +#[test] +fn do_not_report_peer_on_block_response_for_block_request() { + sp_tracing::try_init_simple(); + + let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let peer_id2 = PeerId::random(); + + let mut client2 = client.clone(); + let mut build_block_at = |at, import| { + let mut block_builder = client2.new_block_at(at, Default::default(), false).unwrap(); + // Make sure we generate a different block as fork + block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); + + let block = block_builder.build().unwrap().block; + + if import { + block_on(client2.import(BlockOrigin::Own, block.clone())).unwrap(); + } + + block + }; + + let block1 = build_block(&mut client, None, false); + let block2 = build_block(&mut client, None, false); + let block3 = build_block(&mut client, None, false); + let block3_fork = build_block_at(block2.hash(), false); + + // Add two peers which are on block 1. + sync.new_peer(peer_id1, block1.hash(), 1).unwrap(); + sync.new_peer(peer_id2, block1.hash(), 1).unwrap(); + + // Tell sync that our best block is 3. + sync.update_chain_info(&block3.hash(), 3); + + // There should be no requests. + assert!(sync.block_requests().is_empty()); + + // Let peer2 announce a fork of block 3 + send_block_announce(block3_fork.header().clone(), peer_id2, &mut sync); + + // Import and tell sync that we now have the fork. + block_on(client.import(BlockOrigin::Own, block3_fork.clone())).unwrap(); + sync.update_chain_info(&block3_fork.hash(), 3); + + let block4 = build_block_at(block3_fork.hash(), false); + + // Let peer2 announce block 4 and check that sync wants to get the block. + send_block_announce(block4.header().clone(), peer_id2, &mut sync); + + let request = get_block_request(&mut sync, FromBlock::Hash(block4.hash()), 2, &peer_id2); + + // Peer1 announces the same block, but as the common block is still `1`, sync will request + // block 2 again. + send_block_announce(block4.header().clone(), peer_id1, &mut sync); + + let request2 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id1); + + let response = create_block_response(vec![block4.clone(), block3_fork.clone()]); + let res = sync.on_block_data(&peer_id2, Some(request), response).unwrap(); + + // 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) + ); + + let request3 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id2); + + let response = create_block_response(vec![block2.clone()]); + let res = sync.on_block_data(&peer_id1, Some(request2), response).unwrap(); + assert!(matches!( + res, + 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) + ); +} + +fn unwrap_from_block_number(from: FromBlock) -> u64 { + if let FromBlock::Number(from) = from { + from + } else { + panic!("Expected a number!"); + } +} + +/// A regression test for a behavior we have seen on a live network. +/// +/// The scenario is that the node is doing a full resync and is connected to some node that is +/// doing a major sync as well. This other node that is doing a major sync will finish before +/// our node and send a block announcement message, but we don't have seen any block +/// announcement from this node in its sync process. Meaning our common number didn't change. It +/// is now expected that we start an ancestor search to find the common number. +#[test] +fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { + sp_tracing::try_init_simple(); + + let blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + (0..MAX_DOWNLOAD_AHEAD * 2) + .map(|_| build_block(&mut client, None, false)) + .collect::>() + }; + + let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let info = client.info(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let peer_id2 = PeerId::random(); + + let best_block = blocks.last().unwrap().clone(); + let max_blocks_to_request = sync.max_blocks_per_request; + // Connect the node we will sync from + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) + .unwrap(); + sync.new_peer(peer_id2, info.best_hash, 0).unwrap(); + + let mut best_block_num = 0; + while best_block_num < MAX_DOWNLOAD_AHEAD { + let request = get_block_request( + &mut sync, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, + &peer_id1, + ); + + let from = unwrap_from_block_number(request.from.clone()); + + let mut resp_blocks = blocks[best_block_num as usize..from as usize].to_vec(); + resp_blocks.reverse(); + + let response = create_block_response(resp_blocks.clone()); + + let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize + ),); + + best_block_num += max_blocks_to_request as u32; + + let _ = sync.on_blocks_processed( + max_blocks_to_request as usize, + max_blocks_to_request as usize, + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id1), + )), + b.hash(), + ) + }) + .collect(), + ); + + resp_blocks + .into_iter() + .rev() + .for_each(|b| block_on(client.import_as_final(BlockOrigin::Own, b)).unwrap()); + } + + // "Wait" for the queue to clear + sync.queue_blocks.clear(); + + // Let peer2 announce that it finished syncing + send_block_announce(best_block.header().clone(), peer_id2, &mut sync); + + let (peer1_req, peer2_req) = + sync.block_requests().into_iter().fold((None, None), |res, req| { + if req.0 == peer_id1 { + (Some(req.1), res.1) + } else if req.0 == peer_id2 { + (res.0, Some(req.1)) + } else { + panic!("Unexpected req: {:?}", req) + } + }); + + // We should now do an ancestor search to find the correct common block. + let peer2_req = peer2_req.unwrap(); + assert_eq!(Some(1), peer2_req.max); + assert_eq!(FromBlock::Number(best_block_num as u64), peer2_req.from); + + let response = create_block_response(vec![blocks[(best_block_num - 1) as usize].clone()]); + let res = sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() + ),); + + let peer1_from = unwrap_from_block_number(peer1_req.unwrap().from); + + // As we are on the same chain, we should directly continue with requesting blocks from + // peer 2 as well. + get_block_request( + &mut sync, + FromBlock::Number(peer1_from + max_blocks_to_request as u64), + max_blocks_to_request as u32, + &peer_id2, + ); +} + +/// A test that ensures that we can sync a huge fork. +/// +/// The following scenario: +/// A peer connects to us and we both have the common block 512. The last finalized is 2048. +/// Our best block is 4096. The peer send us a block announcement with 4097 from a fork. +/// +/// We will first do an ancestor search to find the common block. After that we start to sync +/// the fork and finish it ;) +#[test] +fn can_sync_huge_fork() { + sp_tracing::try_init_simple(); + + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) + .map(|_| build_block(&mut client, None, false)) + .collect::>(); + + let fork_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let fork_blocks = blocks[..MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2] + .into_iter() + .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) + .cloned() + .collect::>(); + + fork_blocks + .into_iter() + .chain( + (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 2 + 1) + .map(|_| build_block(&mut client, None, true)), + ) + .collect::>() + }; + + let info = client.info(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); + let just = (*b"TEST", Vec::new()); + client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); + sync.update_chain_info(&info.best_hash, info.best_number); + + let peer_id1 = PeerId::random(); + + let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); + // Connect the node we will sync from + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) + .unwrap(); + + send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); + + let mut request = + get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); + + // Do the ancestor search + loop { + let block = &fork_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_id1, Some(request), response).unwrap(); + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { + // We found the ancenstor + break + }; + + log::trace!(target: LOG_TARGET, "Request: {request:?}"); + } + + // Now request and import the fork. + let mut best_block_num = *finalized_block.header().number() as u32; + let max_blocks_to_request = sync.max_blocks_per_request; + while best_block_num < *fork_blocks.last().unwrap().header().number() as u32 - 1 { + let request = get_block_request( + &mut sync, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, + &peer_id1, + ); + + let from = unwrap_from_block_number(request.from.clone()); + + let mut resp_blocks = fork_blocks[best_block_num as usize..from as usize].to_vec(); + resp_blocks.reverse(); + + let response = create_block_response(resp_blocks.clone()); + + let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + assert!(matches!( + res, + 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; + + let _ = sync.on_blocks_processed( + max_blocks_to_request as usize, + max_blocks_to_request as usize, + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id1), + )), + b.hash(), + ) + }) + .collect(), + ); + + resp_blocks + .into_iter() + .rev() + .for_each(|b| block_on(client.import(BlockOrigin::Own, b)).unwrap()); + } + + // Request the tip + get_block_request(&mut sync, FromBlock::Hash(fork_blocks.last().unwrap().hash()), 1, &peer_id1); +} + +#[test] +fn syncs_fork_without_duplicate_requests() { + sp_tracing::try_init_simple(); + + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) + .map(|_| build_block(&mut client, None, false)) + .collect::>(); + + let fork_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let fork_blocks = blocks[..MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2] + .into_iter() + .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) + .cloned() + .collect::>(); + + fork_blocks + .into_iter() + .chain( + (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 2 + 1) + .map(|_| build_block(&mut client, None, true)), + ) + .collect::>() + }; + + let info = client.info(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); + let just = (*b"TEST", Vec::new()); + client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); + sync.update_chain_info(&info.best_hash, info.best_number); + + let peer_id1 = PeerId::random(); + + let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); + // Connect the node we will sync from + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) + .unwrap(); + + send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); + + let mut request = + get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); + + // Do the ancestor search + loop { + let block = &fork_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_id1, Some(request), response).unwrap(); + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { + // We found the ancenstor + break + }; + + log::trace!(target: LOG_TARGET, "Request: {request:?}"); + } + + // Now request and import the fork. + let mut best_block_num = *finalized_block.header().number() as u32; + let max_blocks_to_request = sync.max_blocks_per_request; + + let mut request = get_block_request( + &mut sync, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, + &peer_id1, + ); + let last_block_num = *fork_blocks.last().unwrap().header().number() as u32 - 1; + while best_block_num < last_block_num { + let from = unwrap_from_block_number(request.from.clone()); + + let mut resp_blocks = fork_blocks[best_block_num as usize..from as usize].to_vec(); + resp_blocks.reverse(); + + let response = create_block_response(resp_blocks.clone()); + + let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize + ),); + + best_block_num += max_blocks_to_request as u32; + + if best_block_num < last_block_num { + // make sure we're not getting a duplicate request in the time before the blocks are + // processed + request = get_block_request( + &mut sync, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, + &peer_id1, + ); + } + + let mut notify_imported: Vec<_> = resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id1), + )), + b.hash(), + ) + }) + .collect(); + + // The import queue may send notifications in batches of varying size. So we simulate + // this here by splitting the batch into 2 notifications. + let max_blocks_to_request = sync.max_blocks_per_request; + let second_batch = notify_imported.split_off(notify_imported.len() / 2); + let _ = sync.on_blocks_processed( + max_blocks_to_request as usize, + max_blocks_to_request as usize, + notify_imported, + ); + + let _ = sync.on_blocks_processed( + max_blocks_to_request as usize, + max_blocks_to_request as usize, + second_batch, + ); + + resp_blocks + .into_iter() + .rev() + .for_each(|b| block_on(client.import(BlockOrigin::Own, b)).unwrap()); + } + + // Request the tip + get_block_request(&mut sync, FromBlock::Hash(fork_blocks.last().unwrap().hash()), 1, &peer_id1); +} + +#[test] +fn removes_target_fork_on_disconnect() { + sp_tracing::try_init_simple(); + 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( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let common_block = blocks[1].clone(); + // Connect the node we will sync from + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) + .unwrap(); + + // Create a "new" header and announce it + let mut header = blocks[0].header().clone(); + header.number = 4; + send_block_announce(header, peer_id1, &mut sync); + assert!(sync.fork_targets.len() == 1); + + 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 (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut client2 = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..4).map(|_| build_block(&mut client2, None, false)).collect::>(); + + let empty_client = Arc::new(TestClientBuilder::new().build()); + + let mut sync = ChainSync::new( + SyncMode::Full, + empty_client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let best_block = blocks[3].clone(); + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) + .unwrap(); + + sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; + sync.peers.get_mut(&peer_id1).unwrap().common_number = 0; + + // Request all missing blocks and respond only with some. + let request = get_block_request(&mut sync, FromBlock::Hash(best_block.hash()), 4, &peer_id1); + let response = + create_block_response(vec![blocks[3].clone(), blocks[2].clone(), blocks[1].clone()]); + sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + assert_eq!(sync.best_queued_number, 0); + + // Request should only contain the missing block. + let request = get_block_request(&mut sync, FromBlock::Number(1), 1, &peer_id1); + let response = create_block_response(vec![blocks[0].clone()]); + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + assert_eq!(sync.best_queued_number, 4); +} +#[test] +fn ancestor_search_repeat() { + let state = AncestorSearchState::::BinarySearch(1, 3); + assert!(handle_ancestor_search_state(&state, 2, true).is_none()); +} + +#[test] +fn sync_restart_removes_block_but_not_justification_requests() { + let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + let peers = vec![PeerId::random(), PeerId::random()]; + + let mut new_blocks = |n| { + for _ in 0..n { + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + } + + let info = client.info(); + (info.best_hash, info.best_number) + }; + + let (b1_hash, b1_number) = new_blocks(50); + + // 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() { + // "send" request + pending_responses.insert(peer); + } + + // add a new peer at a known block + sync.new_peer(peers[1], b1_hash, b1_number).unwrap(); + + // we request a justification for a block we have locally + sync.request_justification(&b1_hash, b1_number); + + // the justification request should be scheduled to the + // new peer which is at the given block + let mut requests = sync.justification_requests(); + assert_eq!(requests.len(), 1); + let (peer, _request) = requests.remove(0); + // "send" request + assert!(pending_responses.insert(peer)); + + assert!(!std::matches!( + sync.peers.get(&peers[0]).unwrap().state, + PeerSyncState::DownloadingJustification(_), + )); + assert_eq!( + sync.peers.get(&peers[1]).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + 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!(pending_responses.len(), 1); + assert!(pending_responses.contains(&peers[1])); + assert_eq!( + sync.peers.get(&peers[1]).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + let _ = sync.peer_disconnected(&peers[1]); + pending_responses.remove(&peers[1]); + assert_eq!(pending_responses.len(), 0); +} + +/// The test demonstrates https://github.com/paritytech/polkadot-sdk/issues/2094. +/// TODO: convert it into desired behavior test once the issue is fixed (see inline comments). +/// The issue: we currently rely on block numbers instead of block hash +/// to download blocks from peers. As a result, we can end up with blocks +/// from different forks as shown by the test. +#[test] +#[should_panic] +fn request_across_forks() { + sp_tracing::try_init_simple(); + + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..100).map(|_| build_block(&mut client, None, false)).collect::>(); + + let fork_a_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let mut fork_blocks = blocks[..] + .into_iter() + .inspect(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() + }) + .cloned() + .collect::>(); + for _ in 0..10 { + fork_blocks.push(build_block(&mut client, None, false)); + } + fork_blocks + }; + + let fork_b_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let mut fork_blocks = blocks[..] + .into_iter() + .inspect(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() + }) + .cloned() + .collect::>(); + for _ in 0..10 { + fork_blocks.push(build_block(&mut client, None, true)); + } + fork_blocks + }; + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 5, + 64, + None, + chain_sync_network_handle, + ) + .unwrap(); + + // Add the peers, all at the common ancestor 100. + let common_block = blocks.last().unwrap(); + let peer_id1 = PeerId::random(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) + .unwrap(); + let peer_id2 = PeerId::random(); + sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number()) + .unwrap(); + + // Peer 1 announces 107 from fork 1, 100-107 get downloaded. + { + let block = (&fork_a_blocks[106]).clone(); + let peer = peer_id1; + log::trace!(target: LOG_TARGET, "<1> {peer} announces from fork 1"); + send_block_announce(block.header().clone(), peer, &mut sync); + let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 7, &peer); + let mut resp_blocks = fork_a_blocks[100_usize..107_usize].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 7_usize + ),); + assert_eq!(sync.best_queued_number, 107); + assert_eq!(sync.best_queued_hash, block.hash()); + assert!(sync.is_known(&block.header.parent_hash())); + } + + // Peer 2 also announces 107 from fork 1. + { + let prev_best_number = sync.best_queued_number; + let prev_best_hash = sync.best_queued_hash; + let peer = peer_id2; + log::trace!(target: LOG_TARGET, "<2> {peer} announces from fork 1"); + for i in 100..107 { + let block = (&fork_a_blocks[i]).clone(); + send_block_announce(block.header().clone(), peer, &mut sync); + assert!(sync.block_requests().is_empty()); + } + assert_eq!(sync.best_queued_number, prev_best_number); + assert_eq!(sync.best_queued_hash, prev_best_hash); + } + + // Peer 2 undergoes reorg, announces 108 from fork 2, gets downloaded even though we + // don't have the parent from fork 2. + { + let block = (&fork_b_blocks[107]).clone(); + let peer = peer_id2; + log::trace!(target: LOG_TARGET, "<3> {peer} announces from fork 2"); + send_block_announce(block.header().clone(), peer, &mut sync); + // TODO: when the issue is fixed, this test can be changed to test the + // expected behavior instead. The needed changes would be: + // 1. Remove the `#[should_panic]` directive + // 2. These should be changed to check that sync.block_requests().is_empty(), after the + // block is announced. + let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 1, &peer); + let response = create_block_response(vec![block.clone()]); + let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 1_usize + ),); + assert!(sync.is_known(&block.header.parent_hash())); + } +} diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 1a383cdde47..0f689742bc5 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -24,12 +24,21 @@ use crate::{ BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, }, block_relay_protocol::{BlockDownloader, BlockResponseError}, + block_request_handler::MAX_BLOCKS_IN_RESPONSE, + chain_sync::{ + BlockRequestAction, ChainSync, ImportBlocksAction, ImportJustificationsAction, + OnBlockResponse, + }, pending_responses::{PendingResponses, ResponseEvent}, schema::v1::{StateRequest, StateResponse}, - service::{self, chain_sync::ToServiceCommand}, - warp::WarpSyncParams, - BlockRequestAction, ChainSync, ClientError, ImportBlocksAction, ImportJustificationsAction, - OnBlockResponse, SyncingService, + service::{ + self, + chain_sync::{SyncingService, ToServiceCommand}, + }, + types::{ + BadPeer, ExtendedPeerInfo, OpaqueStateRequest, OpaqueStateResponse, PeerRequest, SyncEvent, + }, + warp::{EncodedProof, WarpProofRequest, WarpSyncParams}, }; use codec::{Decode, Encode}; @@ -61,15 +70,10 @@ use sc_network::{ }; use sc_network_common::{ role::Roles, - sync::{ - message::{BlockAnnounce, BlockAnnouncesHandshake, BlockRequest, BlockState}, - warp::{EncodedProof, WarpProofRequest}, - BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, OpaqueStateRequest, - OpaqueStateResponse, PeerRequest, SyncEvent, - }, + sync::message::{BlockAnnounce, BlockAnnouncesHandshake, BlockRequest, BlockState}, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_blockchain::HeaderMetadata; +use sp_blockchain::{Error as ClientError, HeaderMetadata}; use sp_consensus::block_validation::BlockAnnounceValidator; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; @@ -363,18 +367,17 @@ where ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = net_config.network_config.sync_mode; let max_parallel_downloads = net_config.network_config.max_parallel_downloads; - let max_blocks_per_request = if net_config.network_config.max_blocks_per_request > - crate::MAX_BLOCKS_IN_RESPONSE as u32 - { - log::info!( - target: LOG_TARGET, - "clamping maximum blocks per request to {}", - crate::MAX_BLOCKS_IN_RESPONSE, - ); - crate::MAX_BLOCKS_IN_RESPONSE as u32 - } else { - net_config.network_config.max_blocks_per_request - }; + let max_blocks_per_request = + if net_config.network_config.max_blocks_per_request > MAX_BLOCKS_IN_RESPONSE as u32 { + log::info!( + target: LOG_TARGET, + "clamping maximum blocks per request to {}", + MAX_BLOCKS_IN_RESPONSE, + ); + MAX_BLOCKS_IN_RESPONSE as u32 + } else { + net_config.network_config.max_blocks_per_request + }; let cache_capacity = (net_config.network_config.default_peers_set.in_peers + net_config.network_config.default_peers_set.out_peers) .max(1); diff --git a/substrate/client/network/sync/src/extra_requests.rs b/substrate/client/network/sync/src/extra_requests.rs index 09e6bdb5739..8edd1a772e2 100644 --- a/substrate/client/network/sync/src/extra_requests.rs +++ b/substrate/client/network/sync/src/extra_requests.rs @@ -16,11 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{PeerSync, PeerSyncState}; +use crate::{ + chain_sync::{PeerSync, PeerSyncState}, + request_metrics::Metrics, +}; use fork_tree::ForkTree; use libp2p::PeerId; use log::{debug, trace, warn}; -use sc_network_common::sync::metrics::Metrics; use sp_blockchain::Error as ClientError; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use std::{ @@ -343,7 +345,7 @@ impl<'a, B: BlockT> Matcher<'a, B> { #[cfg(test)] mod tests { use super::*; - use crate::PeerSync; + use crate::chain_sync::PeerSync; use quickcheck::{Arbitrary, Gen, QuickCheck}; use sp_blockchain::Error as ClientError; use sp_test_primitives::{Block, BlockNumber, Hash}; diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 0c8e8a104e2..c42b0601e65 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -16,67 +16,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Contains the state of the chain synchronization process -//! -//! At any given point in time, a running node tries as much as possible to be at the head of the -//! chain. This module handles the logic of which blocks to request from remotes, and processing -//! responses. It yields blocks to check and potentially move to the database. -//! -//! # Usage -//! -//! The `ChainSync` struct maintains the state of the block requests. Whenever something happens on -//! the network, or whenever a block has been successfully verified, call the appropriate method in -//! order to update it. - -use crate::{ - blocks::BlockCollection, - schema::v1::StateResponse, - state::StateSync, - warp::{WarpProofImportResult, WarpSync, WarpSyncConfig}, -}; - -use codec::Encode; -use extra_requests::ExtraRequests; -use libp2p::PeerId; -use log::{debug, error, info, trace, warn}; - -use sc_client_api::{BlockBackend, ProofProvider}; -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}; -use sp_consensus::{BlockOrigin, BlockStatus}; -use sp_runtime::{ - traits::{ - Block as BlockT, CheckedSub, Hash, HashingFor, Header as HeaderT, NumberFor, One, - SaturatedConversion, Zero, - }, - EncodedJustification, Justifications, -}; - -use std::{ - collections::{HashMap, HashSet}, - ops::Range, - sync::Arc, -}; +//! Blockchain syncing implementation in Substrate. pub use service::chain_sync::SyncingService; +pub use types::{SyncEvent, SyncEventStream, SyncState, SyncStatus, SyncStatusProvider}; mod block_announce_validator; +mod chain_sync; mod extra_requests; mod futures_stream; mod pending_responses; +mod request_metrics; mod schema; +mod types; pub mod block_relay_protocol; pub mod block_request_handler; @@ -88,3405 +40,3 @@ pub mod state; pub mod state_request_handler; pub mod warp; pub mod warp_request_handler; - -/// Log target for this file. -const LOG_TARGET: &'static str = "sync"; - -/// Maximum blocks to store in the import queue. -const MAX_IMPORTING_BLOCKS: usize = 2048; - -/// Maximum blocks to download ahead of any gap. -const MAX_DOWNLOAD_AHEAD: u32 = 2048; - -/// Maximum blocks to look backwards. The gap is the difference between the highest block and the -/// common block of a node. -const MAX_BLOCKS_TO_LOOK_BACKWARDS: u32 = MAX_DOWNLOAD_AHEAD / 2; - -/// Pick the state to sync as the latest finalized number minus this. -const STATE_SYNC_FINALITY_THRESHOLD: u32 = 8; - -/// We use a heuristic that with a high likelihood, by the time -/// `MAJOR_SYNC_BLOCKS` have been imported we'll be on the same -/// chain as (or at least closer to) the peer so we want to delay -/// the ancestor search to not waste time doing that when we are -/// so far behind. -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 blocks per response. -pub(crate) const MAX_BLOCKS_IN_RESPONSE: usize = 128; - -mod rep { - use sc_network::ReputationChange as Rep; - /// Reputation change when a peer sent us a message that led to a - /// database read error. - pub const BLOCKCHAIN_READ_ERROR: Rep = Rep::new(-(1 << 16), "DB Error"); - - /// Reputation change when a peer sent us a status message with a different - /// genesis than us. - pub const GENESIS_MISMATCH: Rep = Rep::new(i32::MIN, "Genesis mismatch"); - - /// Reputation change for peers which send us a block with an incomplete header. - pub const INCOMPLETE_HEADER: Rep = Rep::new(-(1 << 20), "Incomplete header"); - - /// Reputation change for peers which send us a block which we fail to verify. - pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed"); - - /// Reputation change for peers which send us a known bad block. - pub const BAD_BLOCK: Rep = Rep::new(-(1 << 29), "Bad block"); - - /// Peer did not provide us with advertised block data. - pub const NO_BLOCK: Rep = Rep::new(-(1 << 29), "No requested block data"); - - /// Reputation change for peers which send us non-requested block data. - pub const NOT_REQUESTED: Rep = Rep::new(-(1 << 29), "Not requested block data"); - - /// Reputation change for peers which send us a block with bad justifications. - pub const BAD_JUSTIFICATION: Rep = Rep::new(-(1 << 16), "Bad justification"); - - /// Reputation change when a peer sent us invlid ancestry result. - pub const UNKNOWN_ANCESTOR: Rep = Rep::new(-(1 << 16), "DB Error"); - - /// Peer response data does not have requested bits. - pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); -} - -enum AllowedRequests { - Some(HashSet), - All, -} - -impl AllowedRequests { - fn add(&mut self, id: &PeerId) { - if let Self::Some(ref mut set) = self { - set.insert(*id); - } - } - - fn take(&mut self) -> Self { - std::mem::take(self) - } - - fn set_all(&mut self) { - *self = Self::All; - } - - fn contains(&self, id: &PeerId) -> bool { - match self { - Self::Some(set) => set.contains(id), - Self::All => true, - } - } - - fn is_empty(&self) -> bool { - match self { - Self::Some(set) => set.is_empty(), - Self::All => false, - } - } - - fn clear(&mut self) { - std::mem::take(self); - } -} - -impl Default for AllowedRequests { - fn default() -> Self { - Self::Some(HashSet::default()) - } -} - -struct GapSync { - blocks: BlockCollection, - best_queued_number: NumberFor, - target: NumberFor, -} - -/// 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. -pub struct ChainSync { - /// Chain client. - client: Arc, - /// The active peers that we are using to sync and their PeerSync status - peers: HashMap>, - /// A `BlockCollection` of blocks that are being downloaded from peers - blocks: BlockCollection, - /// The best block number in our queue of blocks to import - best_queued_number: NumberFor, - /// The best block hash in our queue of blocks to import - best_queued_hash: B::Hash, - /// Current mode (full/light) - mode: SyncMode, - /// Any extra justification requests. - extra_justifications: ExtraRequests, - /// A set of hashes of blocks that are being downloaded or have been - /// downloaded and are queued for import. - queue_blocks: HashSet, - /// Fork sync targets. - fork_targets: HashMap>, - /// A set of peers for which there might be potential block requests - allowed_requests: AllowedRequests, - /// Maximum number of peers to ask the same blocks in parallel. - max_parallel_downloads: u32, - /// Maximum blocks per request. - max_blocks_per_request: u32, - /// Total number of downloaded blocks. - downloaded_blocks: usize, - /// State sync in progress, if any. - state_sync: Option>, - /// Warp sync in progress, if any. - warp_sync: Option>, - /// Warp sync configuration. - /// - /// Will be `None` after `self.warp_sync` is `Some(_)`. - warp_sync_config: Option>, - /// A temporary storage for warp sync target block until warp sync is initialized. - warp_sync_target_block_header: Option, - /// Enable importing existing blocks. This is used used after the state download to - /// catch up to the latest state while re-importing blocks. - import_existing: bool, - /// Gap download process. - gap_sync: Option>, - /// Handle for communicating with `NetworkService` - network_service: service::network::NetworkServiceHandle, - /// Protocol name used for block announcements - block_announce_protocol_name: ProtocolName, -} - -/// All the data we have about a Peer that we are trying to sync with -#[derive(Debug, Clone)] -pub struct PeerSync { - /// Peer id of this peer. - pub peer_id: PeerId, - /// The common number is the block number that is a common point of - /// ancestry for both our chains (as far as we know). - pub common_number: NumberFor, - /// The hash of the best block that we've seen for this peer. - pub best_hash: B::Hash, - /// The number of the best block that we've seen for this peer. - pub best_number: NumberFor, - /// The state of syncing this peer is in for us, generally categories - /// into `Available` or "busy" with something as defined by `PeerSyncState`. - pub state: PeerSyncState, -} - -impl PeerSync { - /// Update the `common_number` iff `new_common > common_number`. - fn update_common_number(&mut self, new_common: NumberFor) { - if self.common_number < new_common { - trace!( - target: LOG_TARGET, - "Updating peer {} common number from={} => to={}.", - self.peer_id, - self.common_number, - new_common, - ); - self.common_number = new_common; - } - } -} - -struct ForkTarget { - number: NumberFor, - parent_hash: Option, - peers: HashSet, -} - -/// The state of syncing between a Peer and ourselves. -/// -/// Generally two categories, "busy" or `Available`. If busy, the enum -/// defines what we are busy with. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum PeerSyncState { - /// Available for sync requests. - Available, - /// Searching for ancestors the Peer has in common with us. - AncestorSearch { start: NumberFor, current: NumberFor, state: AncestorSearchState }, - /// Actively downloading new blocks, starting from the given Number. - DownloadingNew(NumberFor), - /// Downloading a stale block with given Hash. Stale means that it is a - /// block with a number that is lower than our best number. It might be - /// from a fork and not necessarily already imported. - DownloadingStale(B::Hash), - /// Downloading justification for given block hash. - DownloadingJustification(B::Hash), - /// Downloading state. - DownloadingState, - /// Downloading warp proof. - DownloadingWarpProof, - /// Downloading warp sync target block. - DownloadingWarpTargetBlock, - /// Actively downloading block history after warp sync. - DownloadingGap(NumberFor), -} - -impl PeerSyncState { - pub fn is_available(&self) -> bool { - matches!(self, Self::Available) - } -} - -impl ChainSyncT for ChainSync -where - B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, -{ - fn peer_info(&self, who: &PeerId) -> Option> { - self.peers - .get(who) - .map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) - } - - /// Returns the current sync status. - fn status(&self) -> SyncStatus { - let median_seen = self.median_seen(); - let best_seen_block = - median_seen.and_then(|median| (median > self.best_queued_number).then_some(median)); - let sync_state = if let Some(target) = median_seen { - // A chain is classified as downloading if the provided best block is - // more than `MAJOR_SYNC_BLOCKS` behind the best block or as importing - // if the same can be said about queued blocks. - let best_block = self.client.info().best_number; - if target > best_block && target - best_block > MAJOR_SYNC_BLOCKS.into() { - // If target is not queued, we're downloading, otherwise importing. - if target > self.best_queued_number { - SyncState::Downloading { target } - } else { - SyncState::Importing { target } - } - } else { - SyncState::Idle - } - } else { - SyncState::Idle - }; - - let warp_sync_progress = match (&self.warp_sync, &self.mode, &self.gap_sync) { - (_, _, Some(gap_sync)) => Some(WarpSyncProgress { - phase: WarpSyncPhase::DownloadingBlocks(gap_sync.best_queued_number), - total_bytes: 0, - }), - (None, SyncMode::Warp, _) => Some(WarpSyncProgress { - phase: WarpSyncPhase::AwaitingPeers { - required_peers: MIN_PEERS_TO_START_WARP_SYNC, - }, - total_bytes: 0, - }), - (Some(sync), _, _) => Some(sync.progress()), - _ => None, - }; - - SyncStatus { - state: sync_state, - best_seen_block, - num_peers: self.peers.len() as u32, - num_connected_peers: 0u32, - queued_blocks: self.queue_blocks.len() as u32, - state_sync: self.state_sync.as_ref().map(|s| s.progress()), - warp_sync: warp_sync_progress, - } - } - - fn num_sync_requests(&self) -> usize { - self.fork_targets - .values() - .filter(|f| f.number <= self.best_queued_number) - .count() - } - - fn num_downloaded_blocks(&self) -> usize { - self.downloaded_blocks - } - - fn num_peers(&self) -> usize { - self.peers.len() - } - - #[must_use] - fn new_peer( - &mut self, - who: PeerId, - best_hash: B::Hash, - best_number: NumberFor, - ) -> Result>, BadPeer> { - // There is nothing sync can get from the node that has no blockchain data. - match self.block_status(&best_hash) { - Err(e) => { - debug!(target:LOG_TARGET, "Error reading blockchain: {e}"); - Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) - }, - Ok(BlockStatus::KnownBad) => { - info!("💔 New peer with known bad best block {} ({}).", best_hash, best_number); - Err(BadPeer(who, rep::BAD_BLOCK)) - }, - Ok(BlockStatus::Unknown) => { - if best_number.is_zero() { - info!("💔 New peer with unknown genesis hash {} ({}).", best_hash, best_number); - return Err(BadPeer(who, rep::GENESIS_MISMATCH)) - } - - // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have - // enough to do in the import queue that it's not worth kicking off - // an ancestor search, which is what we do in the next match case below. - if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS.into() { - debug!( - target:LOG_TARGET, - "New peer with unknown best hash {} ({}), assuming common block.", - self.best_queued_hash, - self.best_queued_number - ); - self.peers.insert( - who, - PeerSync { - peer_id: who, - common_number: self.best_queued_number, - best_hash, - best_number, - state: PeerSyncState::Available, - }, - ); - return Ok(None) - } - - // If we are at genesis, just start downloading. - let (state, req) = if self.best_queued_number.is_zero() { - debug!( - target:LOG_TARGET, - "New peer with best hash {best_hash} ({best_number}).", - ); - - (PeerSyncState::Available, None) - } else { - let common_best = std::cmp::min(self.best_queued_number, best_number); - - debug!( - target:LOG_TARGET, - "New peer with unknown best hash {} ({}), searching for common ancestor.", - best_hash, - best_number - ); - - ( - PeerSyncState::AncestorSearch { - current: common_best, - start: self.best_queued_number, - state: AncestorSearchState::ExponentialBackoff(One::one()), - }, - Some(ancestry_request::(common_best)), - ) - }; - - self.allowed_requests.add(&who); - self.peers.insert( - who, - PeerSync { - peer_id: who, - common_number: Zero::zero(), - best_hash, - best_number, - state, - }, - ); - - if let SyncMode::Warp = self.mode { - if self.peers.len() >= MIN_PEERS_TO_START_WARP_SYNC && self.warp_sync.is_none() - { - log::debug!(target: LOG_TARGET, "Starting warp state sync."); - - if let Some(config) = self.warp_sync_config.take() { - let mut warp_sync = WarpSync::new(self.client.clone(), config); - if let Some(header) = self.warp_sync_target_block_header.take() { - warp_sync.set_target_block(header); - } - self.warp_sync = Some(warp_sync); - } - } - } - Ok(req) - }, - Ok(BlockStatus::Queued) | - Ok(BlockStatus::InChainWithState) | - Ok(BlockStatus::InChainPruned) => { - debug!( - target: LOG_TARGET, - "New peer with known best hash {best_hash} ({best_number}).", - ); - self.peers.insert( - who, - PeerSync { - peer_id: who, - common_number: std::cmp::min(self.best_queued_number, best_number), - best_hash, - best_number, - state: PeerSyncState::Available, - }, - ); - self.allowed_requests.add(&who); - Ok(None) - }, - } - } - - fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { - self.on_block_queued(best_hash, best_number); - } - - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - let client = &self.client; - self.extra_justifications - .schedule((*hash, number), |base, block| is_descendent_of(&**client, base, block)) - } - - fn clear_justification_requests(&mut self) { - self.extra_justifications.reset(); - } - - // The implementation is similar to `on_validated_block_announce` with unknown parent hash. - fn set_sync_fork_request( - &mut self, - mut peers: Vec, - hash: &B::Hash, - number: NumberFor, - ) { - if peers.is_empty() { - peers = self - .peers - .iter() - // Only request blocks from peers who are ahead or on a par. - .filter(|(_, peer)| peer.best_number >= number) - .map(|(id, _)| *id) - .collect(); - - debug!( - target: LOG_TARGET, - "Explicit sync request for block {hash:?} with no peers specified. \ - Syncing from these peers {peers:?} instead.", - ); - } else { - debug!( - target: LOG_TARGET, - "Explicit sync request for block {hash:?} with {peers:?}", - ); - } - - if self.is_known(hash) { - debug!(target: LOG_TARGET, "Refusing to sync known hash {hash:?}"); - return - } - - trace!(target: LOG_TARGET, "Downloading requested old fork {hash:?}"); - for peer_id in &peers { - if let Some(peer) = self.peers.get_mut(peer_id) { - if let PeerSyncState::AncestorSearch { .. } = peer.state { - continue - } - - if number > peer.best_number { - peer.best_number = number; - peer.best_hash = *hash; - } - self.allowed_requests.add(peer_id); - } - } - - self.fork_targets - .entry(*hash) - .or_insert_with(|| ForkTarget { number, peers: Default::default(), parent_hash: None }) - .peers - .extend(peers); - } - - #[must_use] - fn on_block_data( - &mut self, - who: &PeerId, - request: Option>, - response: BlockResponse, - ) -> Result, BadPeer> { - self.downloaded_blocks += response.blocks.len(); - let mut gap = false; - let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { - let mut blocks = response.blocks; - if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) { - trace!(target: LOG_TARGET, "Reversing incoming block list"); - blocks.reverse() - } - self.allowed_requests.add(who); - if let Some(request) = request { - match &mut peer.state { - PeerSyncState::DownloadingNew(_) => { - self.blocks.clear_peer_download(who); - peer.state = PeerSyncState::Available; - if let Some(start_block) = - validate_blocks::(&blocks, who, Some(request))? - { - self.blocks.insert(start_block, blocks, *who); - } - self.ready_blocks() - }, - PeerSyncState::DownloadingGap(_) => { - peer.state = PeerSyncState::Available; - if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_peer_download(who); - if let Some(start_block) = - validate_blocks::(&blocks, who, Some(request))? - { - gap_sync.blocks.insert(start_block, blocks, *who); - } - gap = true; - let blocks: Vec<_> = gap_sync - .blocks - .ready_blocks(gap_sync.best_queued_number + One::one()) - .into_iter() - .map(|block_data| { - let justifications = - block_data.block.justifications.or_else(|| { - legacy_justification_mapping( - block_data.block.justification, - ) - }); - IncomingBlock { - hash: block_data.block.hash, - header: block_data.block.header, - body: block_data.block.body, - indexed_body: block_data.block.indexed_body, - justifications, - origin: block_data.origin, - allow_missing_state: true, - import_existing: self.import_existing, - skip_execution: true, - state: None, - } - }) - .collect(); - debug!( - target: LOG_TARGET, - "Drained {} gap blocks from {}", - blocks.len(), - gap_sync.best_queued_number, - ); - blocks - } else { - debug!(target: LOG_TARGET, "Unexpected gap block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) - } - }, - PeerSyncState::DownloadingStale(_) => { - peer.state = PeerSyncState::Available; - if blocks.is_empty() { - debug!(target: LOG_TARGET, "Empty block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) - } - validate_blocks::(&blocks, who, Some(request))?; - blocks - .into_iter() - .map(|b| { - let justifications = b - .justifications - .or_else(|| legacy_justification_mapping(b.justification)); - IncomingBlock { - hash: b.hash, - header: b.header, - body: b.body, - indexed_body: None, - justifications, - origin: Some(*who), - allow_missing_state: true, - import_existing: self.import_existing, - skip_execution: self.skip_execution(), - state: None, - } - }) - .collect() - }, - PeerSyncState::AncestorSearch { current, start, state } => { - let matching_hash = match (blocks.get(0), self.client.hash(*current)) { - (Some(block), Ok(maybe_our_block_hash)) => { - trace!( - target: LOG_TARGET, - "Got ancestry block #{} ({}) from peer {}", - current, - block.hash, - who, - ); - maybe_our_block_hash.filter(|x| x == &block.hash) - }, - (None, _) => { - debug!( - target: LOG_TARGET, - "Invalid response when searching for ancestor from {who}", - ); - return Err(BadPeer(*who, rep::UNKNOWN_ANCESTOR)) - }, - (_, Err(e)) => { - info!( - target: LOG_TARGET, - "❌ Error answering legitimate blockchain query: {e}", - ); - return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR)) - }, - }; - if matching_hash.is_some() { - if *start < self.best_queued_number && - self.best_queued_number <= peer.best_number - { - // We've made progress on this chain since the search was started. - // Opportunistically set common number to updated number - // instead of the one that started the search. - peer.common_number = self.best_queued_number; - } else if peer.common_number < *current { - peer.common_number = *current; - } - } - if matching_hash.is_none() && current.is_zero() { - trace!( - target:LOG_TARGET, - "Ancestry search: genesis mismatch for peer {who}", - ); - return Err(BadPeer(*who, rep::GENESIS_MISMATCH)) - } - if let Some((next_state, next_num)) = - handle_ancestor_search_state(state, *current, matching_hash.is_some()) - { - peer.state = PeerSyncState::AncestorSearch { - current: next_num, - start: *start, - state: next_state, - }; - return Ok(OnBlockData::Request(*who, ancestry_request::(next_num))) - } else { - // Ancestry search is complete. Check if peer is on a stale fork unknown - // to us and add it to sync targets if necessary. - trace!( - target: LOG_TARGET, - "Ancestry search complete. Ours={} ({}), Theirs={} ({}), Common={:?} ({})", - self.best_queued_hash, - self.best_queued_number, - peer.best_hash, - peer.best_number, - matching_hash, - peer.common_number, - ); - if peer.common_number < peer.best_number && - peer.best_number < self.best_queued_number - { - trace!( - target: LOG_TARGET, - "Added fork target {} for {}", - peer.best_hash, - who, - ); - self.fork_targets - .entry(peer.best_hash) - .or_insert_with(|| ForkTarget { - number: peer.best_number, - parent_hash: None, - peers: Default::default(), - }) - .peers - .insert(*who); - } - peer.state = PeerSyncState::Available; - Vec::new() - } - }, - PeerSyncState::DownloadingWarpTargetBlock => { - peer.state = PeerSyncState::Available; - if let Some(warp_sync) = &mut self.warp_sync { - if blocks.len() == 1 { - validate_blocks::(&blocks, who, Some(request))?; - match warp_sync.import_target_block( - blocks.pop().expect("`blocks` len checked above."), - ) { - warp::TargetBlockImportResult::Success => - return Ok(OnBlockData::Continue), - warp::TargetBlockImportResult::BadResponse => - return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), - } - } else if blocks.is_empty() { - debug!(target: LOG_TARGET, "Empty block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) - } else { - debug!( - target: LOG_TARGET, - "Too many blocks ({}) in warp target block response from {}", - blocks.len(), - who, - ); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - } - } else { - debug!( - target: LOG_TARGET, - "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", - who, - ); - return Ok(OnBlockData::Continue) - } - }, - PeerSyncState::Available | - PeerSyncState::DownloadingJustification(..) | - PeerSyncState::DownloadingState | - PeerSyncState::DownloadingWarpProof => Vec::new(), - } - } else { - // When request.is_none() this is a block announcement. Just accept blocks. - validate_blocks::(&blocks, who, None)?; - blocks - .into_iter() - .map(|b| { - let justifications = b - .justifications - .or_else(|| legacy_justification_mapping(b.justification)); - IncomingBlock { - hash: b.hash, - header: b.header, - body: b.body, - indexed_body: None, - justifications, - origin: Some(*who), - allow_missing_state: true, - import_existing: false, - skip_execution: true, - state: None, - } - }) - .collect() - } - } else { - // We don't know of this peer, so we also did not request anything from it. - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - }; - - Ok(OnBlockData::Import(self.validate_and_queue_blocks(new_blocks, gap))) - } - - #[must_use] - fn on_block_justification( - &mut self, - who: PeerId, - response: BlockResponse, - ) -> Result, BadPeer> { - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!( - target: LOG_TARGET, - "💔 Called on_block_justification with a peer ID of an unknown peer", - ); - return Ok(OnBlockJustification::Nothing) - }; - - self.allowed_requests.add(&who); - if let PeerSyncState::DownloadingJustification(hash) = peer.state { - peer.state = PeerSyncState::Available; - - // We only request one justification at a time - let justification = if let Some(block) = response.blocks.into_iter().next() { - if hash != block.hash { - warn!( - target: LOG_TARGET, - "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", - who, - hash, - block.hash, - ); - return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) - } - - block - .justifications - .or_else(|| legacy_justification_mapping(block.justification)) - } else { - // we might have asked the peer for a justification on a block that we assumed it - // had but didn't (regardless of whether it had a justification for it or not). - trace!( - target: LOG_TARGET, - "Peer {who:?} provided empty response for justification request {hash:?}", - ); - - None - }; - - if let Some((peer_id, hash, number, justifications)) = - self.extra_justifications.on_response(who, justification) - { - return Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) - } - } - - Ok(OnBlockJustification::Nothing) - } - - fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { - let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; - self.extra_justifications - .try_finalize_root((hash, number), finalization_result, true); - self.allowed_requests.set_all(); - } - - fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { - let client = &self.client; - let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| { - is_descendent_of(&**client, base, block) - }); - - if let SyncMode::LightState { skip_proofs, .. } = &self.mode { - if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { - // Finalized a recent block. - let mut heads: Vec<_> = self.peers.values().map(|peer| peer.best_number).collect(); - heads.sort(); - let median = heads[heads.len() / 2]; - if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { - if let Ok(Some(header)) = self.client.header(*hash) { - log::debug!( - target: LOG_TARGET, - "Starting state sync for #{number} ({hash})", - ); - self.state_sync = Some(StateSync::new( - self.client.clone(), - header, - None, - None, - *skip_proofs, - )); - self.allowed_requests.set_all(); - } - } - } - } - - if let Err(err) = r { - warn!( - target: LOG_TARGET, - "💔 Error cleaning up pending extra justification data requests: {err}", - ); - } - } - - fn on_validated_block_announce( - &mut self, - is_best: bool, - who: PeerId, - announce: &BlockAnnounce, - ) { - let number = *announce.header.number(); - let hash = announce.header.hash(); - let parent_status = - self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown); - let known_parent = parent_status != BlockStatus::Unknown; - let ancient_parent = parent_status == BlockStatus::InChainPruned; - - let known = self.is_known(&hash); - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!(target: LOG_TARGET, "💔 Called `on_validated_block_announce` with a bad peer ID"); - return - }; - - if let PeerSyncState::AncestorSearch { .. } = peer.state { - trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", who); - return - } - - if is_best { - // update their best block - peer.best_number = number; - peer.best_hash = hash; - } - - // If the announced block is the best they have and is not ahead of us, our common number - // is either one further ahead or it's the one they just announced, if we know about it. - if is_best { - if known && self.best_queued_number >= number { - self.update_peer_common_number(&who, number); - } else if announce.header.parent_hash() == &self.best_queued_hash || - known_parent && self.best_queued_number >= number - { - self.update_peer_common_number(&who, number.saturating_sub(One::one())); - } - } - self.allowed_requests.add(&who); - - // known block case - if known || self.is_already_downloading(&hash) { - trace!(target: "sync", "Known block announce from {}: {}", who, hash); - if let Some(target) = self.fork_targets.get_mut(&hash) { - target.peers.insert(who); - } - return - } - - if ancient_parent { - trace!( - target: "sync", - "Ignored ancient block announced from {}: {} {:?}", - who, - hash, - announce.header, - ); - return - } - - if self.status().state == SyncState::Idle { - trace!( - target: "sync", - "Added sync target for block announced from {}: {} {:?}", - who, - hash, - announce.summary(), - ); - self.fork_targets - .entry(hash) - .or_insert_with(|| ForkTarget { - number, - parent_hash: Some(*announce.header.parent_hash()), - peers: Default::default(), - }) - .peers - .insert(who); - } - } - - #[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.extra_justifications.peer_disconnected(who); - self.allowed_requests.set_all(); - self.fork_targets.retain(|_, target| { - target.peers.remove(who); - !target.peers.is_empty() - }); - - let blocks = self.ready_blocks(); - - (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) - } - - fn metrics(&self) -> Metrics { - Metrics { - queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), - fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), - justifications: self.extra_justifications.metrics(), - } - } -} - -impl ChainSync -where - Self: ChainSyncT, - B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, -{ - /// Create a new instance. - pub fn new( - mode: SyncMode, - client: Arc, - block_announce_protocol_name: ProtocolName, - max_parallel_downloads: u32, - max_blocks_per_request: u32, - warp_sync_config: Option>, - network_service: service::network::NetworkServiceHandle, - ) -> Result { - let mut sync = Self { - client, - peers: HashMap::new(), - blocks: BlockCollection::new(), - best_queued_hash: Default::default(), - best_queued_number: Zero::zero(), - extra_justifications: ExtraRequests::new("justification"), - mode, - queue_blocks: Default::default(), - fork_targets: Default::default(), - allowed_requests: Default::default(), - max_parallel_downloads, - max_blocks_per_request, - downloaded_blocks: 0, - state_sync: None, - warp_sync: None, - import_existing: false, - gap_sync: None, - network_service, - warp_sync_config, - warp_sync_target_block_header: None, - block_announce_protocol_name, - }; - - sync.reset_sync_start_point()?; - Ok(sync) - } - - /// Returns the median seen block number. - fn median_seen(&self) -> Option> { - let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); - - if best_seens.is_empty() { - None - } else { - let middle = best_seens.len() / 2; - - // Not the "perfect median" when we have an even number of peers. - Some(*best_seens.select_nth_unstable(middle).1) - } - } - - fn required_block_attributes(&self) -> BlockAttributes { - match self.mode { - SyncMode::Full => - BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, - SyncMode::LightState { storage_chain_mode: false, .. } | SyncMode::Warp => - BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, - SyncMode::LightState { storage_chain_mode: true, .. } => - BlockAttributes::HEADER | - BlockAttributes::JUSTIFICATION | - BlockAttributes::INDEXED_BODY, - } - } - - fn skip_execution(&self) -> bool { - match self.mode { - SyncMode::Full => false, - SyncMode::LightState { .. } => true, - SyncMode::Warp => true, - } - } - - fn validate_and_queue_blocks( - &mut self, - mut new_blocks: Vec>, - gap: bool, - ) -> ImportBlocksAction { - let orig_len = new_blocks.len(); - new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); - if new_blocks.len() != orig_len { - debug!( - target: LOG_TARGET, - "Ignoring {} blocks that are already queued", - orig_len - new_blocks.len(), - ); - } - - let origin = if !gap && !self.status().state.is_major_syncing() { - BlockOrigin::NetworkBroadcast - } else { - BlockOrigin::NetworkInitialSync - }; - - if let Some((h, n)) = new_blocks - .last() - .and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) - { - trace!( - target:LOG_TARGET, - "Accepted {} blocks ({:?}) with origin {:?}", - new_blocks.len(), - h, - origin, - ); - self.on_block_queued(h, n) - } - self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); - - ImportBlocksAction { origin, blocks: new_blocks } - } - - fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { - if let Some(peer) = self.peers.get_mut(peer_id) { - peer.update_common_number(new_common); - } - } - - /// Called when a block has been queued for import. - /// - /// Updates our internal state for best queued block and then goes - /// through all peers to update our view of their state as well. - fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor) { - if self.fork_targets.remove(hash).is_some() { - trace!(target: LOG_TARGET, "Completed fork sync {hash:?}"); - } - if let Some(gap_sync) = &mut self.gap_sync { - if number > gap_sync.best_queued_number && number <= gap_sync.target { - gap_sync.best_queued_number = number; - } - } - if number > self.best_queued_number { - self.best_queued_number = number; - self.best_queued_hash = *hash; - // Update common blocks - for (n, peer) in self.peers.iter_mut() { - if let PeerSyncState::AncestorSearch { .. } = peer.state { - // Wait for ancestry search to complete first. - continue - } - let new_common_number = - if peer.best_number >= number { number } else { peer.best_number }; - trace!( - target: LOG_TARGET, - "Updating peer {} info, ours={}, common={}->{}, their best={}", - n, - number, - peer.common_number, - new_common_number, - peer.best_number, - ); - peer.common_number = new_common_number; - } - } - self.allowed_requests.set_all(); - } - - /// 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>> + '_ { - self.blocks.clear(); - if let Err(e) = self.reset_sync_start_point() { - warn!(target: LOG_TARGET, "💔 Unable to restart sync: {e}"); - } - self.allowed_requests.set_all(); - debug!( - target: LOG_TARGET, - "Restarted with {} ({})", - self.best_queued_number, - self.best_queued_hash, - ); - let old_peers = std::mem::take(&mut self.peers); - - 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(peer_id, p); - return None - } - - // handle peers that were in other states. - 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)), - } - }) - } - - /// Find a block to start sync from. If we sync with state, that's the latest block we have - /// state for. - fn reset_sync_start_point(&mut self) -> Result<(), ClientError> { - let info = self.client.info(); - if matches!(self.mode, SyncMode::LightState { .. }) && info.finalized_state.is_some() { - warn!( - target: LOG_TARGET, - "Can't use fast sync mode with a partially synced database. Reverting to full sync mode." - ); - self.mode = SyncMode::Full; - } - if matches!(self.mode, SyncMode::Warp) && info.finalized_state.is_some() { - warn!( - target: LOG_TARGET, - "Can't use warp sync mode with a partially synced database. Reverting to full sync mode." - ); - self.mode = SyncMode::Full; - } - self.import_existing = false; - self.best_queued_hash = info.best_hash; - self.best_queued_number = info.best_number; - - if self.mode == SyncMode::Full && - self.client.block_status(info.best_hash)? != BlockStatus::InChainWithState - { - self.import_existing = true; - // Latest state is missing, start with the last finalized state or genesis instead. - if let Some((hash, number)) = info.finalized_state { - debug!(target: LOG_TARGET, "Starting from finalized state #{number}"); - self.best_queued_hash = hash; - self.best_queued_number = number; - } else { - debug!(target: LOG_TARGET, "Restarting from genesis"); - self.best_queued_hash = Default::default(); - self.best_queued_number = Zero::zero(); - } - } - - if let Some((start, end)) = info.block_gap { - debug!(target: LOG_TARGET, "Starting gap sync #{start} - #{end}"); - self.gap_sync = Some(GapSync { - best_queued_number: start - One::one(), - target: end, - blocks: BlockCollection::new(), - }); - } - trace!( - target: LOG_TARGET, - "Restarted sync at #{} ({:?})", - self.best_queued_number, - self.best_queued_hash, - ); - Ok(()) - } - - /// What is the status of the block corresponding to the given hash? - fn block_status(&self, hash: &B::Hash) -> Result { - if self.queue_blocks.contains(hash) { - return Ok(BlockStatus::Queued) - } - self.client.block_status(*hash) - } - - /// Is the block corresponding to the given hash known? - fn is_known(&self, hash: &B::Hash) -> bool { - self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) - } - - /// Is any peer downloading the given hash? - fn is_already_downloading(&self, hash: &B::Hash) -> bool { - self.peers - .iter() - .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> { - self.blocks - .ready_blocks(self.best_queued_number + One::one()) - .into_iter() - .map(|block_data| { - let justifications = block_data - .block - .justifications - .or_else(|| legacy_justification_mapping(block_data.block.justification)); - IncomingBlock { - hash: block_data.block.hash, - header: block_data.block.header, - body: block_data.block.body, - indexed_body: block_data.block.indexed_body, - justifications, - origin: block_data.origin, - allow_missing_state: true, - import_existing: self.import_existing, - skip_execution: self.skip_execution(), - state: None, - } - }) - .collect() - } - - /// Set warp sync target block externally in case we skip warp proof downloading. - pub fn set_warp_sync_target_block(&mut self, header: B::Header) { - if let Some(ref mut warp_sync) = self.warp_sync { - warp_sync.set_target_block(header); - } else { - self.warp_sync_target_block_header = Some(header); - } - } - - /// Generate block request for downloading of the target block body during warp sync. - fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { - let sync = &self.warp_sync.as_ref()?; - - if self.allowed_requests.is_empty() || - sync.is_complete() || - self.peers - .iter() - .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) - { - // Only one pending warp target block request is allowed. - return None - } - - if let Some((target_number, request)) = sync.next_target_block_request() { - // Find a random peer that has a block with the target number. - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= target_number { - trace!(target: LOG_TARGET, "New warp target block request for {id}"); - peer.state = PeerSyncState::DownloadingWarpTargetBlock; - self.allowed_requests.clear(); - return Some((*id, request)) - } - } - } - - None - } - - /// Process blocks received in a response. - #[must_use] - pub(crate) fn on_block_response( - &mut self, - peer_id: PeerId, - request: BlockRequest, - blocks: Vec>, - ) -> OnBlockResponse { - let block_response = BlockResponse:: { id: request.id, blocks }; - - let blocks_range = || match ( - block_response - .blocks - .first() - .and_then(|b| b.header.as_ref().map(|h| h.number())), - block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), - ) { - (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), - (Some(first), Some(_)) => format!(" ({})", first), - _ => Default::default(), - }; - trace!( - target: LOG_TARGET, - "BlockResponse {} from {} with {} blocks {}", - block_response.id, - peer_id, - block_response.blocks.len(), - blocks_range(), - ); - - if request.fields == BlockAttributes::JUSTIFICATION { - match self.on_block_justification(peer_id, block_response) { - 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); - OnBlockResponse::Nothing - }, - } - } else { - match self.on_block_data(&peer_id, Some(request), block_response) { - 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); - OnBlockResponse::Nothing - }, - } - } - } - - /// Process state received in a response. - #[must_use] - pub fn on_state_response( - &mut self, - peer_id: PeerId, - response: OpaqueStateResponse, - ) -> Option> { - match self.on_state_data(&peer_id, response) { - Ok(OnStateData::Import(origin, block)) => - Some(ImportBlocksAction { origin, blocks: vec![block] }), - Ok(OnStateData::Continue) => None, - Err(BadPeer(id, repu)) => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(id, repu); - None - }, - } - } - - pub fn on_warp_sync_response(&mut self, peer_id: PeerId, response: EncodedProof) { - if let Err(BadPeer(id, repu)) = self.on_warp_sync_data(&peer_id, response) { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(id, repu); - } - } - - fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { - let peers = &mut self.peers; - let mut matcher = self.extra_justifications.matcher(); - std::iter::from_fn(move || { - if let Some((peer, request)) = matcher.next(peers) { - peers - .get_mut(&peer) - .expect( - "`Matcher::next` guarantees the `PeerId` comes from the given peers; qed", - ) - .state = PeerSyncState::DownloadingJustification(request.0); - let req = BlockRequest:: { - id: 0, - fields: BlockAttributes::JUSTIFICATION, - from: FromBlock::Hash(request.0), - direction: Direction::Ascending, - max: Some(1), - }; - Some((peer, req)) - } else { - None - } - }) - .collect() - } - - fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { - if self.mode == SyncMode::Warp { - return self - .warp_target_block_request() - .map_or_else(|| Vec::new(), |req| Vec::from([req])) - } - - if self.allowed_requests.is_empty() || self.state_sync.is_some() { - return Vec::new() - } - - if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { - trace!(target: LOG_TARGET, "Too many blocks in the queue."); - return Vec::new() - } - let is_major_syncing = self.status().state.is_major_syncing(); - let attrs = self.required_block_attributes(); - let blocks = &mut self.blocks; - let fork_targets = &mut self.fork_targets; - let last_finalized = - std::cmp::min(self.best_queued_number, self.client.info().finalized_number); - let best_queued = self.best_queued_number; - let client = &self.client; - let queue = &self.queue_blocks; - let allowed_requests = self.allowed_requests.take(); - let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; - let max_blocks_per_request = self.max_blocks_per_request; - let gap_sync = &mut self.gap_sync; - self.peers - .iter_mut() - .filter_map(move |(&id, peer)| { - if !peer.state.is_available() || !allowed_requests.contains(&id) { - return None - } - - // If our best queued is more than `MAX_BLOCKS_TO_LOOK_BACKWARDS` blocks away from - // the common number, the peer best number is higher than our best queued and the - // common number is smaller than the last finalized block number, we should do an - // ancestor search to find a better common block. If the queue is full we wait till - // all blocks are imported though. - if best_queued.saturating_sub(peer.common_number) > - MAX_BLOCKS_TO_LOOK_BACKWARDS.into() && - best_queued < peer.best_number && - peer.common_number < last_finalized && - queue.len() <= MAJOR_SYNC_BLOCKS.into() - { - trace!( - target: LOG_TARGET, - "Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.", - id, - peer.common_number, - best_queued, - ); - let current = std::cmp::min(peer.best_number, best_queued); - peer.state = PeerSyncState::AncestorSearch { - current, - start: best_queued, - state: AncestorSearchState::ExponentialBackoff(One::one()), - }; - Some((id, ancestry_request::(current))) - } else if let Some((range, req)) = peer_block_request( - &id, - peer, - blocks, - attrs, - max_parallel, - max_blocks_per_request, - last_finalized, - best_queued, - ) { - peer.state = PeerSyncState::DownloadingNew(range.start); - trace!( - target: LOG_TARGET, - "New block request for {}, (best:{}, common:{}) {:?}", - id, - peer.best_number, - peer.common_number, - req, - ); - Some((id, req)) - } else if let Some((hash, req)) = fork_sync_request( - &id, - fork_targets, - best_queued, - last_finalized, - attrs, - |hash| { - if queue.contains(hash) { - BlockStatus::Queued - } else { - client.block_status(*hash).unwrap_or(BlockStatus::Unknown) - } - }, - max_blocks_per_request, - ) { - trace!(target: LOG_TARGET, "Downloading fork {hash:?} from {id}"); - peer.state = PeerSyncState::DownloadingStale(hash); - Some((id, req)) - } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { - peer_gap_block_request( - &id, - peer, - &mut sync.blocks, - attrs, - sync.target, - sync.best_queued_number, - max_blocks_per_request, - ) - }) { - peer.state = PeerSyncState::DownloadingGap(range.start); - trace!( - target: LOG_TARGET, - "New gap block request for {}, (best:{}, common:{}) {:?}", - id, - peer.best_number, - peer.common_number, - req, - ); - Some((id, req)) - } else { - None - } - }) - .collect() - } - - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { - if self.allowed_requests.is_empty() { - return None - } - if (self.state_sync.is_some() || self.warp_sync.is_some()) && - self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) - { - // Only one pending state request is allowed. - return None - } - if let Some(sync) = &self.state_sync { - if sync.is_complete() { - return None - } - - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.common_number >= sync.target_block_num() { - peer.state = PeerSyncState::DownloadingState; - let request = sync.next_request(); - trace!(target: LOG_TARGET, "New StateRequest for {}: {:?}", id, request); - self.allowed_requests.clear(); - return Some((*id, OpaqueStateRequest(Box::new(request)))) - } - } - } - if let Some(sync) = &self.warp_sync { - if sync.is_complete() { - return None - } - if let (Some(request), Some(target)) = - (sync.next_state_request(), sync.target_block_number()) - { - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= target { - trace!(target: LOG_TARGET, "New StateRequest for {id}: {request:?}"); - peer.state = PeerSyncState::DownloadingState; - self.allowed_requests.clear(); - return Some((*id, OpaqueStateRequest(Box::new(request)))) - } - } - } - } - None - } - - fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { - if let Some(sync) = &self.warp_sync { - if self.allowed_requests.is_empty() || - sync.is_complete() || - self.peers - .iter() - .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) - { - // Only one pending state request is allowed. - return None - } - if let Some(request) = sync.next_warp_proof_request() { - let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); - if !targets.is_empty() { - targets.sort(); - let median = targets[targets.len() / 2]; - // Find a random peer that is synced as much as peer majority. - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= median { - trace!(target: LOG_TARGET, "New WarpProofRequest for {id}"); - peer.state = PeerSyncState::DownloadingWarpProof; - self.allowed_requests.clear(); - return Some((*id, request)) - } - } - } - } - } - None - } - - fn on_state_data( - &mut self, - who: &PeerId, - response: OpaqueStateResponse, - ) -> Result, BadPeer> { - let response: Box = response.0.downcast().map_err(|_error| { - error!( - target: LOG_TARGET, - "Failed to downcast opaque state response, this is an implementation bug." - ); - - BadPeer(*who, rep::BAD_RESPONSE) - })?; - - if let Some(peer) = self.peers.get_mut(who) { - if let PeerSyncState::DownloadingState = peer.state { - peer.state = PeerSyncState::Available; - self.allowed_requests.set_all(); - } - } - let import_result = if let Some(sync) = &mut self.state_sync { - debug!( - target: LOG_TARGET, - "Importing state data from {} with {} keys, {} proof nodes.", - who, - response.entries.len(), - response.proof.len(), - ); - sync.import(*response) - } else if let Some(sync) = &mut self.warp_sync { - debug!( - target: LOG_TARGET, - "Importing state data from {} with {} keys, {} proof nodes.", - who, - response.entries.len(), - response.proof.len(), - ); - sync.import_state(*response) - } else { - debug!(target: LOG_TARGET, "Ignored obsolete state response from {who}"); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - }; - - match import_result { - state::ImportResult::Import(hash, header, state, body, justifications) => { - let origin = BlockOrigin::NetworkInitialSync; - let block = IncomingBlock { - hash, - header: Some(header), - body, - indexed_body: None, - justifications, - origin: None, - allow_missing_state: true, - import_existing: true, - skip_execution: self.skip_execution(), - state: Some(state), - }; - debug!(target: LOG_TARGET, "State download is complete. Import is queued"); - Ok(OnStateData::Import(origin, block)) - }, - state::ImportResult::Continue => Ok(OnStateData::Continue), - state::ImportResult::BadResponse => { - debug!(target: LOG_TARGET, "Bad state data received from {who}"); - Err(BadPeer(*who, rep::BAD_BLOCK)) - }, - } - } - - fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { - if let Some(peer) = self.peers.get_mut(who) { - if let PeerSyncState::DownloadingWarpProof = peer.state { - peer.state = PeerSyncState::Available; - self.allowed_requests.set_all(); - } - } - let import_result = if let Some(sync) = &mut self.warp_sync { - debug!( - target: LOG_TARGET, - "Importing warp proof data from {}, {} bytes.", - who, - response.0.len(), - ); - sync.import_warp_proof(response) - } else { - debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {who}"); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - }; - - match import_result { - WarpProofImportResult::Success => Ok(()), - WarpProofImportResult::BadResponse => { - debug!(target: LOG_TARGET, "Bad proof data received from {who}"); - Err(BadPeer(*who, rep::BAD_BLOCK)) - }, - } - } - - /// 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. 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>>> { - trace!(target: LOG_TARGET, "Imported {imported} of {count}"); - - let mut output = Vec::new(); - - let mut has_error = false; - for (_, hash) in &results { - self.queue_blocks.remove(hash); - self.blocks.clear_queued(hash); - if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_queued(hash); - } - } - for (result, hash) in results { - if has_error { - break - } - - has_error |= result.is_err(); - - match result { - Ok(BlockImportStatus::ImportedKnown(number, who)) => - if let Some(peer) = who { - self.update_peer_common_number(&peer, number); - }, - Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { - if aux.clear_justification_requests { - trace!( - target: LOG_TARGET, - "Block imported clears all pending justification requests {number}: {hash:?}", - ); - self.clear_justification_requests(); - } - - if aux.needs_justification { - trace!( - target: LOG_TARGET, - "Block imported but requires justification {number}: {hash:?}", - ); - self.request_justification(&hash, number); - } - - if aux.bad_justification { - if let Some(ref peer) = who { - warn!("💔 Sent block with bad justification to import"); - output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); - } - } - - if let Some(peer) = who { - self.update_peer_common_number(&peer, number); - } - let state_sync_complete = - self.state_sync.as_ref().map_or(false, |s| s.target() == hash); - if state_sync_complete { - info!( - target: LOG_TARGET, - "State sync is complete ({} MiB), restarting block sync.", - self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)), - ); - self.state_sync = None; - self.mode = SyncMode::Full; - output.extend(self.restart()); - } - let warp_sync_complete = self - .warp_sync - .as_ref() - .map_or(false, |s| s.target_block_hash() == Some(hash)); - if warp_sync_complete { - info!( - target: LOG_TARGET, - "Warp sync is complete ({} MiB), restarting block sync.", - self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)), - ); - self.warp_sync = None; - self.mode = SyncMode::Full; - output.extend(self.restart()); - } - let gap_sync_complete = - self.gap_sync.as_ref().map_or(false, |s| s.target == number); - if gap_sync_complete { - info!( - target: LOG_TARGET, - "Block history download is complete." - ); - self.gap_sync = None; - } - }, - Err(BlockImportError::IncompleteHeader(who)) => - if let Some(peer) = who { - warn!( - target: LOG_TARGET, - "💔 Peer sent block with incomplete header to import", - ); - output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); - output.extend(self.restart()); - }, - Err(BlockImportError::VerificationFailed(who, e)) => { - let extra_message = - who.map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); - - warn!( - target: LOG_TARGET, - "💔 Verification failed for block {hash:?}{extra_message}: {e:?}", - ); - - if let Some(peer) = who { - output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); - } - - output.extend(self.restart()); - }, - Err(BlockImportError::BadBlock(who)) => - if let Some(peer) = who { - warn!( - target: LOG_TARGET, - "💔 Block {hash:?} received from peer {peer} has been blacklisted", - ); - output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); - }, - Err(BlockImportError::MissingState) => { - // This may happen if the chain we were requesting upon has been discarded - // in the meantime because other chain has been finalized. - // Don't mark it as bad as it still may be synced if explicitly requested. - trace!(target: LOG_TARGET, "Obsolete block {hash:?}"); - }, - e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { - warn!(target: LOG_TARGET, "💔 Error importing block {hash:?}: {}", e.unwrap_err()); - self.state_sync = None; - self.warp_sync = None; - output.extend(self.restart()); - }, - Err(BlockImportError::Cancelled) => {}, - }; - } - - self.allowed_requests.set_all(); - Box::new(output.into_iter()) - } -} - -// This is purely during a backwards compatible transitionary period and should be removed -// once we can assume all nodes can send and receive multiple Justifications -// The ID tag is hardcoded here to avoid depending on the GRANDPA crate. -// See: https://github.com/paritytech/substrate/issues/8172 -fn legacy_justification_mapping( - justification: Option, -) -> Option { - justification.map(|just| (*b"FRNK", just).into()) -} - -/// Request the ancestry for a block. Sends a request for header and justification for the given -/// block number. Used during ancestry search. -fn ancestry_request(block: NumberFor) -> BlockRequest { - BlockRequest:: { - id: 0, - fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, - from: FromBlock::Number(block), - direction: Direction::Ascending, - max: Some(1), - } -} - -/// The ancestor search state expresses which algorithm, and its stateful parameters, we are using -/// to try to find an ancestor block -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum AncestorSearchState { - /// Use exponential backoff to find an ancestor, then switch to binary search. - /// We keep track of the exponent. - ExponentialBackoff(NumberFor), - /// Using binary search to find the best ancestor. - /// We keep track of left and right bounds. - BinarySearch(NumberFor, NumberFor), -} - -/// This function handles the ancestor search strategy used. The goal is to find a common point -/// that both our chains agree on that is as close to the tip as possible. -/// The way this works is we first have an exponential backoff strategy, where we try to step -/// forward until we find a block hash mismatch. The size of the step doubles each step we take. -/// -/// When we've found a block hash mismatch we then fall back to a binary search between the two -/// last known points to find the common block closest to the tip. -fn handle_ancestor_search_state( - state: &AncestorSearchState, - curr_block_num: NumberFor, - block_hash_match: bool, -) -> Option<(AncestorSearchState, NumberFor)> { - let two = >::one() + >::one(); - match state { - AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => { - let next_distance_to_tip = *next_distance_to_tip; - if block_hash_match && next_distance_to_tip == One::one() { - // We found the ancestor in the first step so there is no need to execute binary - // search. - return None - } - if block_hash_match { - let left = curr_block_num; - let right = left + next_distance_to_tip / two; - let middle = left + (right - left) / two; - Some((AncestorSearchState::BinarySearch(left, right), middle)) - } else { - let next_block_num = - curr_block_num.checked_sub(&next_distance_to_tip).unwrap_or_else(Zero::zero); - let next_distance_to_tip = next_distance_to_tip * two; - Some(( - AncestorSearchState::ExponentialBackoff(next_distance_to_tip), - next_block_num, - )) - } - }, - AncestorSearchState::BinarySearch(mut left, mut right) => { - if left >= curr_block_num { - return None - } - if block_hash_match { - left = curr_block_num; - } else { - right = curr_block_num; - } - assert!(right >= left); - let middle = left + (right - left) / two; - if middle == curr_block_num { - None - } else { - Some((AncestorSearchState::BinarySearch(left, right), middle)) - } - }, - } -} - -/// Get a new block request for the peer if any. -fn peer_block_request( - id: &PeerId, - peer: &PeerSync, - blocks: &mut BlockCollection, - attrs: BlockAttributes, - max_parallel_downloads: u32, - max_blocks_per_request: u32, - finalized: NumberFor, - best_num: NumberFor, -) -> Option<(Range>, BlockRequest)> { - if best_num >= peer.best_number { - // Will be downloaded as alternative fork instead. - return None - } else if peer.common_number < finalized { - trace!( - target: LOG_TARGET, - "Requesting pre-finalized chain from {:?}, common={}, finalized={}, peer best={}, our best={}", - id, peer.common_number, finalized, peer.best_number, best_num, - ); - } - let range = blocks.needed_blocks( - *id, - max_blocks_per_request, - peer.best_number, - peer.common_number, - max_parallel_downloads, - MAX_DOWNLOAD_AHEAD, - )?; - - // The end is not part of the range. - let last = range.end.saturating_sub(One::one()); - - let from = if peer.best_number == last { - FromBlock::Hash(peer.best_hash) - } else { - FromBlock::Number(last) - }; - - let request = BlockRequest:: { - id: 0, - fields: attrs, - from, - direction: Direction::Descending, - max: Some((range.end - range.start).saturated_into::()), - }; - - Some((range, request)) -} - -/// Get a new block request for the peer if any. -fn peer_gap_block_request( - id: &PeerId, - peer: &PeerSync, - blocks: &mut BlockCollection, - attrs: BlockAttributes, - target: NumberFor, - common_number: NumberFor, - max_blocks_per_request: u32, -) -> Option<(Range>, BlockRequest)> { - let range = blocks.needed_blocks( - *id, - max_blocks_per_request, - std::cmp::min(peer.best_number, target), - common_number, - 1, - MAX_DOWNLOAD_AHEAD, - )?; - - // The end is not part of the range. - let last = range.end.saturating_sub(One::one()); - let from = FromBlock::Number(last); - - let request = BlockRequest:: { - id: 0, - fields: attrs, - from, - direction: Direction::Descending, - max: Some((range.end - range.start).saturated_into::()), - }; - Some((range, request)) -} - -/// Get pending fork sync targets for a peer. -fn fork_sync_request( - id: &PeerId, - targets: &mut HashMap>, - best_num: NumberFor, - finalized: NumberFor, - attributes: BlockAttributes, - check_block: impl Fn(&B::Hash) -> BlockStatus, - max_blocks_per_request: u32, -) -> Option<(B::Hash, BlockRequest)> { - targets.retain(|hash, r| { - if r.number <= finalized { - trace!( - target: LOG_TARGET, - "Removed expired fork sync request {:?} (#{})", - hash, - r.number, - ); - return false - } - if check_block(hash) != BlockStatus::Unknown { - trace!( - target: LOG_TARGET, - "Removed obsolete fork sync request {:?} (#{})", - hash, - r.number, - ); - return false - } - true - }); - for (hash, r) in targets { - if !r.peers.contains(&id) { - continue - } - // Download the fork only if it is behind or not too far ahead our tip of the chain - // Otherwise it should be downloaded in full sync mode. - if r.number <= best_num || - (r.number - best_num).saturated_into::() < max_blocks_per_request as u32 - { - let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block); - let count = if parent_status == BlockStatus::Unknown { - (r.number - finalized).saturated_into::() // up to the last finalized block - } else { - // request only single block - 1 - }; - trace!( - target: LOG_TARGET, - "Downloading requested fork {hash:?} from {id}, {count} blocks", - ); - return Some(( - *hash, - BlockRequest:: { - id: 0, - fields: attributes, - from: FromBlock::Hash(*hash), - direction: Direction::Descending, - max: Some(count), - }, - )) - } else { - trace!(target: LOG_TARGET, "Fork too far in the future: {:?} (#{})", hash, r.number); - } - } - None -} - -/// Returns `true` if the given `block` is a descendent of `base`. -fn is_descendent_of( - client: &T, - base: &Block::Hash, - block: &Block::Hash, -) -> sp_blockchain::Result -where - Block: BlockT, - T: HeaderMetadata + ?Sized, -{ - if base == block { - return Ok(false) - } - - let ancestor = sp_blockchain::lowest_common_ancestor(client, *block, *base)?; - - Ok(ancestor.hash == *base) -} - -/// Validate that the given `blocks` are correct. -/// Returns the number of the first block in the sequence. -/// -/// It is expected that `blocks` are in ascending order. -fn validate_blocks( - blocks: &Vec>, - who: &PeerId, - request: Option>, -) -> Result>, BadPeer> { - if let Some(request) = request { - if Some(blocks.len() as _) > request.max { - debug!( - target: LOG_TARGET, - "Received more blocks than requested from {}. Expected in maximum {:?}, got {}.", - who, - request.max, - blocks.len(), - ); - - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - } - - let block_header = - if request.direction == Direction::Descending { blocks.last() } else { blocks.first() } - .and_then(|b| b.header.as_ref()); - - let expected_block = block_header.as_ref().map_or(false, |h| match request.from { - FromBlock::Hash(hash) => h.hash() == hash, - FromBlock::Number(n) => h.number() == &n, - }); - - if !expected_block { - debug!( - target: LOG_TARGET, - "Received block that was not requested. Requested {:?}, got {:?}.", - request.from, - block_header, - ); - - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - } - - if request.fields.contains(BlockAttributes::HEADER) && - blocks.iter().any(|b| b.header.is_none()) - { - trace!( - target: LOG_TARGET, - "Missing requested header for a block in response from {who}.", - ); - - return Err(BadPeer(*who, rep::BAD_RESPONSE)) - } - - if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none()) - { - trace!( - target: LOG_TARGET, - "Missing requested body for a block in response from {who}.", - ); - - return Err(BadPeer(*who, rep::BAD_RESPONSE)) - } - } - - for b in blocks { - if let Some(header) = &b.header { - let hash = header.hash(); - if hash != b.hash { - debug!( - target:LOG_TARGET, - "Bad header received from {}. Expected hash {:?}, got {:?}", - who, - b.hash, - hash, - ); - return Err(BadPeer(*who, rep::BAD_BLOCK)) - } - } - if let (Some(header), Some(body)) = (&b.header, &b.body) { - let expected = *header.extrinsics_root(); - let got = HashingFor::::ordered_trie_root( - body.iter().map(Encode::encode).collect(), - sp_runtime::StateVersion::V0, - ); - if expected != got { - debug!( - target:LOG_TARGET, - "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", - b.hash, - who, - expected, - got, - ); - return Err(BadPeer(*who, rep::BAD_BLOCK)) - } - } - } - - Ok(blocks.first().and_then(|b| b.header.as_ref()).map(|h| *h.number())) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::service::network::NetworkServiceProvider; - use futures::executor::block_on; - use sc_block_builder::BlockBuilderProvider; - use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; - use sp_blockchain::HeaderBackend; - use substrate_test_runtime_client::{ - runtime::{Block, Hash, Header}, - BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, - TestClientBuilder, TestClientBuilderExt, - }; - - #[test] - fn processes_empty_response_on_justification_request_for_unknown_block() { - // if we ask for a justification for a given block to a peer that doesn't know that block - // (different from not having a justification), the peer will reply with an empty response. - // internally we should process the response as the justification not being available. - - let client = Arc::new(TestClientBuilder::new().build()); - let peer_id = PeerId::random(); - - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let (a1_hash, a1_number) = { - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; - (a1.hash(), *a1.header.number()) - }; - - // add a new peer with the same best block - sync.new_peer(peer_id, a1_hash, a1_number).unwrap(); - - // and request a justification for the block - sync.request_justification(&a1_hash, a1_number); - - // the justification request should be scheduled to that peer - assert!(sync - .justification_requests() - .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); - - // there's one in-flight extra request to the expected peer - assert!(sync.extra_justifications.active_requests().any(|(who, (hash, number))| { - *who == peer_id && *hash == a1_hash && *number == a1_number - })); - - // if the peer replies with an empty response (i.e. it doesn't know the block), - // the active request should be cleared. - assert_eq!( - sync.on_block_justification(peer_id, BlockResponse:: { id: 0, blocks: vec![] }), - Ok(OnBlockJustification::Nothing), - ); - - // there should be no in-flight requests - assert_eq!(sync.extra_justifications.active_requests().count(), 0); - - // and the request should now be pending again, waiting for reschedule - assert!(sync - .extra_justifications - .pending_requests() - .any(|(hash, number)| { *hash == a1_hash && *number == a1_number })); - } - - #[test] - fn restart_doesnt_affect_peers_downloading_finality_data() { - let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let peer_id2 = PeerId::random(); - let peer_id3 = PeerId::random(); - - let mut new_blocks = |n| { - for _ in 0..n { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - } - - let info = client.info(); - (info.best_hash, info.best_number) - }; - - let (b1_hash, b1_number) = new_blocks(50); - - // add 2 peers at blocks that we don't have locally - sync.new_peer(peer_id1, Hash::random(), 42).unwrap(); - sync.new_peer(peer_id2, Hash::random(), 10).unwrap(); - - // we wil send block requests to these peers - // for these blocks we don't know about - assert!(sync - .block_requests() - .into_iter() - .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); - - // add a new peer at a known block - sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); - - // we request a justification for a block we have locally - sync.request_justification(&b1_hash, b1_number); - - // the justification request should be scheduled to the - // new peer which is at the given block - assert!(sync.justification_requests().iter().any(|(p, r)| { - *p == peer_id3 && - r.fields == BlockAttributes::JUSTIFICATION && - r.from == FromBlock::Hash(b1_hash) - })); - - assert_eq!( - sync.peers.get(&peer_id3).unwrap().state, - PeerSyncState::DownloadingJustification(b1_hash), - ); - - // we restart the sync state - 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(|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!( - sync.peers.get(&peer_id3).unwrap().state, - PeerSyncState::DownloadingJustification(b1_hash), - ); - - // Set common block to something that we don't have (e.g. failed import) - sync.peers.get_mut(&peer_id3).unwrap().common_number = 100; - let _ = sync.restart().count(); - assert_eq!(sync.peers.get(&peer_id3).unwrap().common_number, 50); - } - - /// Send a block annoucnement for the given `header`. - fn send_block_announce( - header: Header, - peer_id: PeerId, - sync: &mut ChainSync, - ) { - let announce = BlockAnnounce { - header: header.clone(), - state: Some(BlockState::Best), - data: Some(Vec::new()), - }; - - sync.on_validated_block_announce(true, peer_id, &announce); - } - - /// Create a block response from the given `blocks`. - fn create_block_response(blocks: Vec) -> BlockResponse { - BlockResponse:: { - id: 0, - blocks: blocks - .into_iter() - .map(|b| BlockData:: { - hash: b.hash(), - header: Some(b.header().clone()), - body: Some(b.deconstruct().1), - indexed_body: None, - receipt: None, - message_queue: None, - justification: None, - justifications: None, - }) - .collect(), - } - } - - /// Get a block request from `sync` and check that is matches the expected request. - fn get_block_request( - sync: &mut ChainSync, - from: FromBlock, - max: u32, - peer: &PeerId, - ) -> BlockRequest { - let requests = sync.block_requests(); - - log::trace!(target: LOG_TARGET, "Requests: {requests:?}"); - - assert_eq!(1, requests.len()); - assert_eq!(*peer, requests[0].0); - - let request = requests[0].1.clone(); - - assert_eq!(from, request.from); - assert_eq!(Some(max), request.max); - request - } - - /// Build and import a new best block. - fn build_block(client: &mut Arc, at: Option, fork: bool) -> Block { - let at = at.unwrap_or_else(|| client.info().best_hash); - - let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); - - if fork { - block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); - } - - let block = block_builder.build().unwrap().block; - - block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - block - } - - /// This test is a regression test as observed on a real network. - /// - /// The node is connected to multiple peers. Both of these peers are having a best block (1) - /// that is below our best block (3). Now peer 2 announces a fork of block 3 that we will - /// request from peer 2. After importing the fork, peer 2 and then peer 1 will announce block 4. - /// But as peer 1 in our view is still at block 1, we will request block 2 (which we already - /// have) from it. In the meanwhile peer 2 sends us block 4 and 3 and we send another request - /// for block 2 to peer 2. Peer 1 answers with block 2 and then peer 2. This will need to - /// succeed, as we have requested block 2 from both peers. - #[test] - fn do_not_report_peer_on_block_response_for_block_request() { - sp_tracing::try_init_simple(); - - let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let peer_id2 = PeerId::random(); - - let mut client2 = client.clone(); - let mut build_block_at = |at, import| { - let mut block_builder = client2.new_block_at(at, Default::default(), false).unwrap(); - // Make sure we generate a different block as fork - block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); - - let block = block_builder.build().unwrap().block; - - if import { - block_on(client2.import(BlockOrigin::Own, block.clone())).unwrap(); - } - - block - }; - - let block1 = build_block(&mut client, None, false); - let block2 = build_block(&mut client, None, false); - let block3 = build_block(&mut client, None, false); - let block3_fork = build_block_at(block2.hash(), false); - - // Add two peers which are on block 1. - sync.new_peer(peer_id1, block1.hash(), 1).unwrap(); - sync.new_peer(peer_id2, block1.hash(), 1).unwrap(); - - // Tell sync that our best block is 3. - sync.update_chain_info(&block3.hash(), 3); - - // There should be no requests. - assert!(sync.block_requests().is_empty()); - - // Let peer2 announce a fork of block 3 - send_block_announce(block3_fork.header().clone(), peer_id2, &mut sync); - - // Import and tell sync that we now have the fork. - block_on(client.import(BlockOrigin::Own, block3_fork.clone())).unwrap(); - sync.update_chain_info(&block3_fork.hash(), 3); - - let block4 = build_block_at(block3_fork.hash(), false); - - // Let peer2 announce block 4 and check that sync wants to get the block. - send_block_announce(block4.header().clone(), peer_id2, &mut sync); - - let request = get_block_request(&mut sync, FromBlock::Hash(block4.hash()), 2, &peer_id2); - - // Peer1 announces the same block, but as the common block is still `1`, sync will request - // block 2 again. - send_block_announce(block4.header().clone(), peer_id1, &mut sync); - - let request2 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id1); - - let response = create_block_response(vec![block4.clone(), block3_fork.clone()]); - let res = sync.on_block_data(&peer_id2, Some(request), response).unwrap(); - - // 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) - ); - - let request3 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id2); - - let response = create_block_response(vec![block2.clone()]); - let res = sync.on_block_data(&peer_id1, Some(request2), response).unwrap(); - assert!(matches!( - res, - 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) - ); - } - - fn unwrap_from_block_number(from: FromBlock) -> u64 { - if let FromBlock::Number(from) = from { - from - } else { - panic!("Expected a number!"); - } - } - - /// A regression test for a behavior we have seen on a live network. - /// - /// The scenario is that the node is doing a full resync and is connected to some node that is - /// doing a major sync as well. This other node that is doing a major sync will finish before - /// our node and send a block announcement message, but we don't have seen any block - /// announcement from this node in its sync process. Meaning our common number didn't change. It - /// is now expected that we start an ancestor search to find the common number. - #[test] - fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { - sp_tracing::try_init_simple(); - - let blocks = { - let mut client = Arc::new(TestClientBuilder::new().build()); - (0..MAX_DOWNLOAD_AHEAD * 2) - .map(|_| build_block(&mut client, None, false)) - .collect::>() - }; - - let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let info = client.info(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let peer_id2 = PeerId::random(); - - let best_block = blocks.last().unwrap().clone(); - let max_blocks_to_request = sync.max_blocks_per_request; - // Connect the node we will sync from - sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) - .unwrap(); - sync.new_peer(peer_id2, info.best_hash, 0).unwrap(); - - let mut best_block_num = 0; - while best_block_num < MAX_DOWNLOAD_AHEAD { - let request = get_block_request( - &mut sync, - FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), - max_blocks_to_request as u32, - &peer_id1, - ); - - let from = unwrap_from_block_number(request.from.clone()); - - let mut resp_blocks = blocks[best_block_num as usize..from as usize].to_vec(); - resp_blocks.reverse(); - - let response = create_block_response(resp_blocks.clone()); - - let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize - ),); - - best_block_num += max_blocks_to_request as u32; - - let _ = sync.on_blocks_processed( - max_blocks_to_request as usize, - max_blocks_to_request as usize, - resp_blocks - .iter() - .rev() - .map(|b| { - ( - Ok(BlockImportStatus::ImportedUnknown( - *b.header().number(), - Default::default(), - Some(peer_id1), - )), - b.hash(), - ) - }) - .collect(), - ); - - resp_blocks - .into_iter() - .rev() - .for_each(|b| block_on(client.import_as_final(BlockOrigin::Own, b)).unwrap()); - } - - // "Wait" for the queue to clear - sync.queue_blocks.clear(); - - // Let peer2 announce that it finished syncing - send_block_announce(best_block.header().clone(), peer_id2, &mut sync); - - let (peer1_req, peer2_req) = - sync.block_requests().into_iter().fold((None, None), |res, req| { - if req.0 == peer_id1 { - (Some(req.1), res.1) - } else if req.0 == peer_id2 { - (res.0, Some(req.1)) - } else { - panic!("Unexpected req: {:?}", req) - } - }); - - // We should now do an ancestor search to find the correct common block. - let peer2_req = peer2_req.unwrap(); - assert_eq!(Some(1), peer2_req.max); - assert_eq!(FromBlock::Number(best_block_num as u64), peer2_req.from); - - let response = create_block_response(vec![blocks[(best_block_num - 1) as usize].clone()]); - let res = sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() - ),); - - let peer1_from = unwrap_from_block_number(peer1_req.unwrap().from); - - // As we are on the same chain, we should directly continue with requesting blocks from - // peer 2 as well. - get_block_request( - &mut sync, - FromBlock::Number(peer1_from + max_blocks_to_request as u64), - max_blocks_to_request as u32, - &peer_id2, - ); - } - - /// A test that ensures that we can sync a huge fork. - /// - /// The following scenario: - /// A peer connects to us and we both have the common block 512. The last finalized is 2048. - /// Our best block is 4096. The peer send us a block announcement with 4097 from a fork. - /// - /// We will first do an ancestor search to find the common block. After that we start to sync - /// the fork and finish it ;) - #[test] - fn can_sync_huge_fork() { - sp_tracing::try_init_simple(); - - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut client = Arc::new(TestClientBuilder::new().build()); - let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) - .map(|_| build_block(&mut client, None, false)) - .collect::>(); - - let fork_blocks = { - let mut client = Arc::new(TestClientBuilder::new().build()); - let fork_blocks = blocks[..MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2] - .into_iter() - .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) - .cloned() - .collect::>(); - - fork_blocks - .into_iter() - .chain( - (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 2 + 1) - .map(|_| build_block(&mut client, None, true)), - ) - .collect::>() - }; - - let info = client.info(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); - let just = (*b"TEST", Vec::new()); - client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); - sync.update_chain_info(&info.best_hash, info.best_number); - - let peer_id1 = PeerId::random(); - - let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); - // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); - - send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); - - let mut request = - get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); - - // Do the ancestor search - loop { - let block = &fork_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_id1, Some(request), response).unwrap(); - request = if let OnBlockData::Request(_peer, request) = on_block_data { - request - } else { - // We found the ancenstor - break - }; - - log::trace!(target: LOG_TARGET, "Request: {request:?}"); - } - - // Now request and import the fork. - let mut best_block_num = *finalized_block.header().number() as u32; - let max_blocks_to_request = sync.max_blocks_per_request; - while best_block_num < *fork_blocks.last().unwrap().header().number() as u32 - 1 { - let request = get_block_request( - &mut sync, - FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), - max_blocks_to_request as u32, - &peer_id1, - ); - - let from = unwrap_from_block_number(request.from.clone()); - - let mut resp_blocks = fork_blocks[best_block_num as usize..from as usize].to_vec(); - resp_blocks.reverse(); - - let response = create_block_response(resp_blocks.clone()); - - let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - assert!(matches!( - res, - 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; - - let _ = sync.on_blocks_processed( - max_blocks_to_request as usize, - max_blocks_to_request as usize, - resp_blocks - .iter() - .rev() - .map(|b| { - ( - Ok(BlockImportStatus::ImportedUnknown( - *b.header().number(), - Default::default(), - Some(peer_id1), - )), - b.hash(), - ) - }) - .collect(), - ); - - resp_blocks - .into_iter() - .rev() - .for_each(|b| block_on(client.import(BlockOrigin::Own, b)).unwrap()); - } - - // Request the tip - get_block_request( - &mut sync, - FromBlock::Hash(fork_blocks.last().unwrap().hash()), - 1, - &peer_id1, - ); - } - - #[test] - fn syncs_fork_without_duplicate_requests() { - sp_tracing::try_init_simple(); - - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut client = Arc::new(TestClientBuilder::new().build()); - let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) - .map(|_| build_block(&mut client, None, false)) - .collect::>(); - - let fork_blocks = { - let mut client = Arc::new(TestClientBuilder::new().build()); - let fork_blocks = blocks[..MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2] - .into_iter() - .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) - .cloned() - .collect::>(); - - fork_blocks - .into_iter() - .chain( - (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 2 + 1) - .map(|_| build_block(&mut client, None, true)), - ) - .collect::>() - }; - - let info = client.info(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); - let just = (*b"TEST", Vec::new()); - client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); - sync.update_chain_info(&info.best_hash, info.best_number); - - let peer_id1 = PeerId::random(); - - let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); - // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); - - send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); - - let mut request = - get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); - - // Do the ancestor search - loop { - let block = &fork_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_id1, Some(request), response).unwrap(); - request = if let OnBlockData::Request(_peer, request) = on_block_data { - request - } else { - // We found the ancenstor - break - }; - - log::trace!(target: LOG_TARGET, "Request: {request:?}"); - } - - // Now request and import the fork. - let mut best_block_num = *finalized_block.header().number() as u32; - let max_blocks_to_request = sync.max_blocks_per_request; - - let mut request = get_block_request( - &mut sync, - FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), - max_blocks_to_request as u32, - &peer_id1, - ); - let last_block_num = *fork_blocks.last().unwrap().header().number() as u32 - 1; - while best_block_num < last_block_num { - let from = unwrap_from_block_number(request.from.clone()); - - let mut resp_blocks = fork_blocks[best_block_num as usize..from as usize].to_vec(); - resp_blocks.reverse(); - - let response = create_block_response(resp_blocks.clone()); - - let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize - ),); - - best_block_num += max_blocks_to_request as u32; - - if best_block_num < last_block_num { - // make sure we're not getting a duplicate request in the time before the blocks are - // processed - request = get_block_request( - &mut sync, - FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), - max_blocks_to_request as u32, - &peer_id1, - ); - } - - let mut notify_imported: Vec<_> = resp_blocks - .iter() - .rev() - .map(|b| { - ( - Ok(BlockImportStatus::ImportedUnknown( - *b.header().number(), - Default::default(), - Some(peer_id1), - )), - b.hash(), - ) - }) - .collect(); - - // The import queue may send notifications in batches of varying size. So we simulate - // this here by splitting the batch into 2 notifications. - let max_blocks_to_request = sync.max_blocks_per_request; - let second_batch = notify_imported.split_off(notify_imported.len() / 2); - let _ = sync.on_blocks_processed( - max_blocks_to_request as usize, - max_blocks_to_request as usize, - notify_imported, - ); - - let _ = sync.on_blocks_processed( - max_blocks_to_request as usize, - max_blocks_to_request as usize, - second_batch, - ); - - resp_blocks - .into_iter() - .rev() - .for_each(|b| block_on(client.import(BlockOrigin::Own, b)).unwrap()); - } - - // Request the tip - get_block_request( - &mut sync, - FromBlock::Hash(fork_blocks.last().unwrap().hash()), - 1, - &peer_id1, - ); - } - - #[test] - fn removes_target_fork_on_disconnect() { - sp_tracing::try_init_simple(); - 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( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let common_block = blocks[1].clone(); - // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); - - // Create a "new" header and announce it - let mut header = blocks[0].header().clone(); - header.number = 4; - send_block_announce(header, peer_id1, &mut sync); - assert!(sync.fork_targets.len() == 1); - - 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 (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut client2 = Arc::new(TestClientBuilder::new().build()); - let blocks = (0..4).map(|_| build_block(&mut client2, None, false)).collect::>(); - - let empty_client = Arc::new(TestClientBuilder::new().build()); - - let mut sync = ChainSync::new( - SyncMode::Full, - empty_client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let best_block = blocks[3].clone(); - sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) - .unwrap(); - - sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; - sync.peers.get_mut(&peer_id1).unwrap().common_number = 0; - - // Request all missing blocks and respond only with some. - let request = - get_block_request(&mut sync, FromBlock::Hash(best_block.hash()), 4, &peer_id1); - let response = - create_block_response(vec![blocks[3].clone(), blocks[2].clone(), blocks[1].clone()]); - sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); - assert_eq!(sync.best_queued_number, 0); - - // Request should only contain the missing block. - let request = get_block_request(&mut sync, FromBlock::Number(1), 1, &peer_id1); - let response = create_block_response(vec![blocks[0].clone()]); - sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - assert_eq!(sync.best_queued_number, 4); - } - #[test] - fn ancestor_search_repeat() { - let state = AncestorSearchState::::BinarySearch(1, 3); - assert!(handle_ancestor_search_state(&state, 2, true).is_none()); - } - - #[test] - fn sync_restart_removes_block_but_not_justification_requests() { - let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peers = vec![PeerId::random(), PeerId::random()]; - - let mut new_blocks = |n| { - for _ in 0..n { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - } - - let info = client.info(); - (info.best_hash, info.best_number) - }; - - let (b1_hash, b1_number) = new_blocks(50); - - // 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() { - // "send" request - pending_responses.insert(peer); - } - - // add a new peer at a known block - sync.new_peer(peers[1], b1_hash, b1_number).unwrap(); - - // we request a justification for a block we have locally - sync.request_justification(&b1_hash, b1_number); - - // the justification request should be scheduled to the - // new peer which is at the given block - let mut requests = sync.justification_requests(); - assert_eq!(requests.len(), 1); - let (peer, _request) = requests.remove(0); - // "send" request - assert!(pending_responses.insert(peer)); - - assert!(!std::matches!( - sync.peers.get(&peers[0]).unwrap().state, - PeerSyncState::DownloadingJustification(_), - )); - assert_eq!( - sync.peers.get(&peers[1]).unwrap().state, - PeerSyncState::DownloadingJustification(b1_hash), - ); - 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!(pending_responses.len(), 1); - assert!(pending_responses.contains(&peers[1])); - assert_eq!( - sync.peers.get(&peers[1]).unwrap().state, - PeerSyncState::DownloadingJustification(b1_hash), - ); - let _ = sync.peer_disconnected(&peers[1]); - pending_responses.remove(&peers[1]); - assert_eq!(pending_responses.len(), 0); - } - - /// The test demonstrates https://github.com/paritytech/polkadot-sdk/issues/2094. - /// TODO: convert it into desired behavior test once the issue is fixed (see inline comments). - /// The issue: we currently rely on block numbers instead of block hash - /// to download blocks from peers. As a result, we can end up with blocks - /// from different forks as shown by the test. - #[test] - #[should_panic] - fn request_across_forks() { - sp_tracing::try_init_simple(); - - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let mut client = Arc::new(TestClientBuilder::new().build()); - let blocks = (0..100).map(|_| build_block(&mut client, None, false)).collect::>(); - - let fork_a_blocks = { - let mut client = Arc::new(TestClientBuilder::new().build()); - let mut fork_blocks = blocks[..] - .into_iter() - .inspect(|b| { - assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); - block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() - }) - .cloned() - .collect::>(); - for _ in 0..10 { - fork_blocks.push(build_block(&mut client, None, false)); - } - fork_blocks - }; - - let fork_b_blocks = { - let mut client = Arc::new(TestClientBuilder::new().build()); - let mut fork_blocks = blocks[..] - .into_iter() - .inspect(|b| { - assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); - block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap() - }) - .cloned() - .collect::>(); - for _ in 0..10 { - fork_blocks.push(build_block(&mut client, None, true)); - } - fork_blocks - }; - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - // Add the peers, all at the common ancestor 100. - let common_block = blocks.last().unwrap(); - let peer_id1 = PeerId::random(); - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); - let peer_id2 = PeerId::random(); - sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number()) - .unwrap(); - - // Peer 1 announces 107 from fork 1, 100-107 get downloaded. - { - let block = (&fork_a_blocks[106]).clone(); - let peer = peer_id1; - log::trace!(target: LOG_TARGET, "<1> {peer} announces from fork 1"); - send_block_announce(block.header().clone(), peer, &mut sync); - let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 7, &peer); - let mut resp_blocks = fork_a_blocks[100_usize..107_usize].to_vec(); - resp_blocks.reverse(); - let response = create_block_response(resp_blocks.clone()); - let res = sync.on_block_data(&peer, Some(request), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 7_usize - ),); - assert_eq!(sync.best_queued_number, 107); - assert_eq!(sync.best_queued_hash, block.hash()); - assert!(sync.is_known(&block.header.parent_hash())); - } - - // Peer 2 also announces 107 from fork 1. - { - let prev_best_number = sync.best_queued_number; - let prev_best_hash = sync.best_queued_hash; - let peer = peer_id2; - log::trace!(target: LOG_TARGET, "<2> {peer} announces from fork 1"); - for i in 100..107 { - let block = (&fork_a_blocks[i]).clone(); - send_block_announce(block.header().clone(), peer, &mut sync); - assert!(sync.block_requests().is_empty()); - } - assert_eq!(sync.best_queued_number, prev_best_number); - assert_eq!(sync.best_queued_hash, prev_best_hash); - } - - // Peer 2 undergoes reorg, announces 108 from fork 2, gets downloaded even though we - // don't have the parent from fork 2. - { - let block = (&fork_b_blocks[107]).clone(); - let peer = peer_id2; - log::trace!(target: LOG_TARGET, "<3> {peer} announces from fork 2"); - send_block_announce(block.header().clone(), peer, &mut sync); - // TODO: when the issue is fixed, this test can be changed to test the - // expected behavior instead. The needed changes would be: - // 1. Remove the `#[should_panic]` directive - // 2. These should be changed to check that sync.block_requests().is_empty(), after the - // block is announced. - let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 1, &peer); - let response = create_block_response(vec![block.clone()]); - let res = sync.on_block_data(&peer, Some(request), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 1_usize - ),); - assert!(sync.is_known(&block.header.parent_hash())); - } - } -} diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index ed7c647c797..42220096e06 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -23,65 +23,8 @@ use crate::block_relay_protocol::{BlockDownloader as BlockDownloaderT, BlockResp 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, ImportBlocksAction, Metrics, OnBlockData, - OnBlockJustification, PeerInfo, SyncStatus, -}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; - -mockall::mock! { - pub ChainSync {} - - impl ChainSyncT for ChainSync { - fn peer_info(&self, who: &PeerId) -> Option>; - fn status(&self) -> SyncStatus; - fn num_sync_requests(&self) -> usize; - fn num_downloaded_blocks(&self) -> usize; - fn num_peers(&self) -> usize; - fn new_peer( - &mut self, - who: PeerId, - best_hash: Block::Hash, - best_number: NumberFor, - ) -> Result>, BadPeer>; - fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor); - fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor); - fn clear_justification_requests(&mut self); - fn set_sync_fork_request( - &mut self, - peers: Vec, - hash: &Block::Hash, - number: NumberFor, - ); - fn on_block_data( - &mut self, - who: &PeerId, - request: Option>, - response: BlockResponse, - ) -> Result, BadPeer>; - fn on_block_justification( - &mut self, - who: PeerId, - response: BlockResponse, - ) -> Result, BadPeer>; - fn on_justification_import( - &mut self, - hash: Block::Hash, - number: NumberFor, - success: bool, - ); - fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); - fn on_validated_block_announce( - &mut self, - is_best: bool, - who: PeerId, - announce: &BlockAnnounce, - ); - fn peer_disconnected(&mut self, who: &PeerId) -> Option>; - fn metrics(&self) -> Metrics; - } -} +use sc_network_common::sync::message::{BlockData, BlockRequest}; +use sp_runtime::traits::Block as BlockT; mockall::mock! { pub BlockDownloader {} diff --git a/substrate/client/network/sync/src/pending_responses.rs b/substrate/client/network/sync/src/pending_responses.rs index c863267e780..9e2fd5cfd67 100644 --- a/substrate/client/network/sync/src/pending_responses.rs +++ b/substrate/client/network/sync/src/pending_responses.rs @@ -19,6 +19,7 @@ //! [`PendingResponses`] is responsible for keeping track of pending responses and //! polling them. +use crate::types::PeerRequest; use futures::{ channel::oneshot, future::BoxFuture, @@ -28,11 +29,13 @@ use futures::{ 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; +/// Log target for this file. +const LOG_TARGET: &'static str = "sync"; + /// Response result. type ResponseResult = Result, RequestFailure>, oneshot::Canceled>; @@ -74,7 +77,7 @@ impl PendingResponses { .is_some() { error!( - target: crate::LOG_TARGET, + target: LOG_TARGET, "Discarded pending response from peer {peer_id}, request type: {request_type:?}.", ); debug_assert!(false); diff --git a/substrate/client/network/common/src/sync/metrics.rs b/substrate/client/network/sync/src/request_metrics.rs similarity index 100% rename from substrate/client/network/common/src/sync/metrics.rs rename to substrate/client/network/sync/src/request_metrics.rs diff --git a/substrate/client/network/sync/src/service/chain_sync.rs b/substrate/client/network/sync/src/service/chain_sync.rs index f9e0e401fdf..3d11880c511 100644 --- a/substrate/client/network/sync/src/service/chain_sync.rs +++ b/substrate/client/network/sync/src/service/chain_sync.rs @@ -16,14 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::types::{ExtendedPeerInfo, SyncEvent, SyncEventStream, SyncStatus, SyncStatusProvider}; + use futures::{channel::oneshot, Stream}; use libp2p::PeerId; use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link}; use sc_network::{NetworkBlock, NetworkSyncForkRequest}; -use sc_network_common::sync::{ - ExtendedPeerInfo, SyncEvent, SyncEventStream, SyncStatus, SyncStatusProvider, -}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; diff --git a/substrate/client/network/sync/src/state.rs b/substrate/client/network/sync/src/state.rs index 305f0ee6838..5d34613d1c5 100644 --- a/substrate/client/network/sync/src/state.rs +++ b/substrate/client/network/sync/src/state.rs @@ -18,12 +18,14 @@ //! State sync support. -use crate::schema::v1::{StateEntry, StateRequest, StateResponse}; +use crate::{ + schema::v1::{StateEntry, StateRequest, StateResponse}, + types::StateDownloadProgress, +}; use codec::{Decode, Encode}; use log::debug; use sc_client_api::{CompactProof, ProofProvider}; use sc_consensus::ImportedState; -use sc_network_common::sync::StateDownloadProgress; use smallvec::SmallVec; use sp_core::storage::well_known_keys; use sp_runtime::{ diff --git a/substrate/client/network/sync/src/types.rs b/substrate/client/network/sync/src/types.rs new file mode 100644 index 00000000000..5931cf47b28 --- /dev/null +++ b/substrate/client/network/sync/src/types.rs @@ -0,0 +1,206 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Common syncing types. + +use futures::Stream; +use sc_network_common::{role::Roles, types::ReputationChange}; + +use libp2p::PeerId; + +use crate::warp::WarpSyncProgress; +use sc_network_common::sync::message::BlockRequest; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +use std::{any::Any, fmt, fmt::Formatter, pin::Pin, sync::Arc}; + +pub use sc_network_common::sync::SyncMode; + +/// The sync status of a peer we are trying to sync with +#[derive(Debug)] +pub struct PeerInfo { + /// Their best block hash. + pub best_hash: Block::Hash, + /// Their best block number. + pub best_number: NumberFor, +} + +/// Info about a peer's known state (both full and light). +#[derive(Clone, Debug)] +pub struct ExtendedPeerInfo { + /// Roles + pub roles: Roles, + /// Peer best block hash + pub best_hash: B::Hash, + /// Peer best block number + pub best_number: NumberFor, +} + +/// Reported sync state. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum SyncState { + /// Initial sync is complete, keep-up sync is active. + Idle, + /// Actively catching up with the chain. + Downloading { target: BlockNumber }, + /// All blocks are downloaded and are being imported. + Importing { target: BlockNumber }, +} + +impl SyncState { + /// Are we actively catching up with the chain? + pub fn is_major_syncing(&self) -> bool { + !matches!(self, SyncState::Idle) + } +} + +/// Reported state download progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct StateDownloadProgress { + /// Estimated download percentage. + pub percentage: u32, + /// Total state size in bytes downloaded so far. + pub size: u64, +} + +/// Syncing status and statistics. +#[derive(Debug, Clone)] +pub struct SyncStatus { + /// Current global sync state. + pub state: SyncState>, + /// Target sync block number. + pub best_seen_block: Option>, + /// Number of peers participating in syncing. + pub num_peers: u32, + /// Number of peers known to `SyncingEngine` (both full and light). + pub num_connected_peers: u32, + /// Number of blocks queued for import + pub queued_blocks: u32, + /// State sync status in progress, if any. + pub state_sync: Option, + /// Warp sync in progress, if any. + pub warp_sync: Option>, +} + +/// A peer did not behave as expected and should be reported. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BadPeer(pub PeerId, pub ReputationChange); + +impl fmt::Display for BadPeer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1) + } +} + +impl std::error::Error for BadPeer {} + +#[derive(Debug)] +pub struct Metrics { + pub queued_blocks: u32, + pub fork_targets: u32, + pub justifications: crate::request_metrics::Metrics, +} + +#[derive(Debug)] +pub enum PeerRequest { + Block(BlockRequest), + State, + WarpProof, +} + +#[derive(Debug)] +pub enum PeerRequestType { + Block, + State, + WarpProof, +} + +impl PeerRequest { + pub fn get_type(&self) -> PeerRequestType { + match self { + PeerRequest::Block(_) => PeerRequestType::Block, + PeerRequest::State => PeerRequestType::State, + PeerRequest::WarpProof => PeerRequestType::WarpProof, + } + } +} + +/// Wrapper for implementation-specific state request. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueStateRequest(pub Box); + +impl fmt::Debug for OpaqueStateRequest { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueStateRequest").finish() + } +} + +/// Wrapper for implementation-specific state response. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueStateResponse(pub Box); + +impl fmt::Debug for OpaqueStateResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueStateResponse").finish() + } +} + +/// Provides high-level status of syncing. +#[async_trait::async_trait] +pub trait SyncStatusProvider: Send + Sync { + /// Get high-level view of the syncing status. + async fn status(&self) -> Result, ()>; +} + +#[async_trait::async_trait] +impl SyncStatusProvider for Arc +where + T: ?Sized, + T: SyncStatusProvider, + Block: BlockT, +{ + async fn status(&self) -> Result, ()> { + T::status(self).await + } +} + +/// Syncing-related events that other protocols can subscribe to. +pub enum SyncEvent { + /// Peer that the syncing implementation is tracking connected. + PeerConnected(PeerId), + + /// Peer that the syncing implementation was tracking disconnected. + PeerDisconnected(PeerId), +} + +pub trait SyncEventStream: Send + Sync { + /// Subscribe to syncing-related events. + fn event_stream(&self, name: &'static str) -> Pin + Send>>; +} + +impl SyncEventStream for Arc +where + T: ?Sized, + T: SyncEventStream, +{ + fn event_stream(&self, name: &'static str) -> Pin + Send>> { + T::event_stream(self, name) + } +} diff --git a/substrate/client/network/sync/src/warp.rs b/substrate/client/network/sync/src/warp.rs index 74835a6e015..2c0adc856c1 100644 --- a/substrate/client/network/sync/src/warp.rs +++ b/substrate/client/network/sync/src/warp.rs @@ -18,28 +18,107 @@ //! Warp sync support. +pub use sp_consensus_grandpa::{AuthorityList, SetId}; + use crate::{ schema::v1::{StateRequest, StateResponse}, state::{ImportResult, StateSync}, }; +use codec::{Decode, Encode}; use futures::channel::oneshot; use log::error; use sc_client_api::ProofProvider; -use sc_network_common::sync::{ - message::{BlockAttributes, BlockData, BlockRequest, Direction, FromBlock}, - warp::{ - EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, - WarpSyncProvider, - }, +use sc_network_common::sync::message::{ + BlockAttributes, BlockData, BlockRequest, Direction, FromBlock, }; use sp_blockchain::HeaderBackend; -use sp_consensus_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; -use std::sync::Arc; +use std::{fmt, sync::Arc}; /// Log target for this file. const LOG_TARGET: &'static str = "sync"; +/// Scale-encoded warp sync proof response. +pub struct EncodedProof(pub Vec); + +/// Warp sync request +#[derive(Encode, Decode, Debug)] +pub struct WarpProofRequest { + /// Start collecting proofs from this block. + pub begin: B::Hash, +} + +/// Proof verification result. +pub enum VerificationResult { + /// Proof is valid, but the target was not reached. + Partial(SetId, AuthorityList, Block::Hash), + /// Target finality is proved. + Complete(SetId, AuthorityList, Block::Header), +} + +/// Warp sync backend. Handles retrieving and verifying warp sync proofs. +pub trait WarpSyncProvider: Send + Sync { + /// Generate proof starting at given block hash. The proof is accumulated until maximum proof + /// size is reached. + fn generate( + &self, + start: Block::Hash, + ) -> Result>; + /// Verify warp proof against current set of authorities. + fn verify( + &self, + proof: &EncodedProof, + set_id: SetId, + authorities: AuthorityList, + ) -> Result, Box>; + /// Get current list of authorities. This is supposed to be genesis authorities when starting + /// sync. + fn current_authorities(&self) -> AuthorityList; +} + +/// Reported warp sync phase. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum WarpSyncPhase { + /// Waiting for peers to connect. + AwaitingPeers { required_peers: usize }, + /// Waiting for target block to be received. + AwaitingTargetBlock, + /// Downloading and verifying grandpa warp proofs. + DownloadingWarpProofs, + /// Downloading target block. + DownloadingTargetBlock, + /// Downloading state data. + DownloadingState, + /// Importing state. + ImportingState, + /// Downloading block history. + DownloadingBlocks(NumberFor), +} + +impl fmt::Display for WarpSyncPhase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AwaitingPeers { required_peers } => + write!(f, "Waiting for {required_peers} peers to be connected"), + Self::AwaitingTargetBlock => write!(f, "Waiting for target block to be received"), + Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), + Self::DownloadingTargetBlock => write!(f, "Downloading target block"), + Self::DownloadingState => write!(f, "Downloading state"), + Self::ImportingState => write!(f, "Importing state"), + Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), + } + } +} + +/// Reported warp sync progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct WarpSyncProgress { + /// Estimated download percentage. + pub phase: WarpSyncPhase, + /// Total bytes downloaded so far. + pub total_bytes: u64, +} + /// The different types of warp syncing, passed to `build_network`. pub enum WarpSyncParams { /// Standard warp sync for the chain. diff --git a/substrate/client/network/sync/src/warp_request_handler.rs b/substrate/client/network/sync/src/warp_request_handler.rs index 0e502a6dba5..b23f30c50dd 100644 --- a/substrate/client/network/sync/src/warp_request_handler.rs +++ b/substrate/client/network/sync/src/warp_request_handler.rs @@ -20,13 +20,13 @@ use codec::Decode; use futures::{channel::oneshot, stream::StreamExt}; use log::debug; +use crate::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider}; use sc_network::{ config::ProtocolId, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, }; -use sc_network_common::sync::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider}; use sp_runtime::traits::Block as BlockT; use std::{sync::Arc, time::Duration}; diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 11505903e35..ad4201f94a2 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -60,16 +60,15 @@ use sc_network::{ Multiaddr, NetworkBlock, NetworkService, NetworkStateInfo, NetworkSyncForkRequest, NetworkWorker, }; -use sc_network_common::{ - role::Roles, - sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, -}; +use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, service::{chain_sync::SyncingService, network::NetworkServiceProvider}, state_request_handler::StateRequestHandler, - warp::WarpSyncParams, + warp::{ + AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, + }, warp_request_handler, }; use sc_service::client::Client; diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 5e42465974b..2a6aa4b3a40 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4.17" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-network = { path = ".." } sc-network-common = { path = "../common" } +sc-network-sync = { path = "../sync" } sc-utils = { path = "../../utils" } sp-runtime = { path = "../../../primitives/runtime" } sp-consensus = { path = "../../../primitives/consensus/common" } diff --git a/substrate/client/network/transactions/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index b46733d4272..1b97d4b96c9 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -42,11 +42,8 @@ use sc_network::{ utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, }; -use sc_network_common::{ - role::ObservedRole, - sync::{SyncEvent, SyncEventStream}, - ExHashT, -}; +use sc_network_common::{role::ObservedRole, ExHashT}; +use sc_network_sync::{SyncEvent, SyncEventStream}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; diff --git a/substrate/client/service/src/metrics.rs b/substrate/client/service/src/metrics.rs index ece5758be77..a411a83a784 100644 --- a/substrate/client/service/src/metrics.rs +++ b/substrate/client/service/src/metrics.rs @@ -23,7 +23,7 @@ use futures_timer::Delay; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::{ClientInfo, UsageProvider}; use sc_network::{config::Role, NetworkStatus, NetworkStatusProvider}; -use sc_network_common::sync::{SyncStatus, SyncStatusProvider}; +use sc_network_sync::{SyncStatus, SyncStatusProvider}; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus}; use sc_utils::metrics::register_globals; -- GitLab From f50054cffba4df6b25a16dafdbc66d582e419355 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:37:09 +0100 Subject: [PATCH 408/633] [ci] Update rust nightly in ci image (#2115) Run CI using new image with nightly 2023-11-01 cc https://github.com/paritytech/polkadot-sdk/issues/2113 cc https://github.com/paritytech/ci_cd/issues/896 --- .github/workflows/fmt-check.yml | 2 +- .gitlab-ci.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index 55e67f2799b..7ca4413bb05 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -14,7 +14,7 @@ jobs: os: ["ubuntu-latest"] runs-on: ${{ matrix.os }} container: - image: paritytech/ci-unified:bullseye-1.70.0-2023-05-23-v20230706 + image: paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231025 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 835b668de25..6dc7fc1a3cd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,8 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + # CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231025" # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" -- GitLab From 00b85c51dfbc0fecbb8a4dd3635d4c177a6527a6 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Wed, 1 Nov 2023 15:21:44 +0100 Subject: [PATCH 409/633] [NPoS] Paging reward payouts in order to scale rewardable nominators (#1189) helps https://github.com/paritytech/polkadot-sdk/issues/439. closes https://github.com/paritytech/polkadot-sdk/issues/473. PR link in the older substrate repository: https://github.com/paritytech/substrate/pull/13498. # Context Rewards payout is processed today in a single block and limited to `MaxNominatorRewardedPerValidator`. This number is currently 512 on both Kusama and Polkadot. This PR tries to scale the nominators payout to an unlimited count in a multi-block fashion. Exposures are stored in pages, with each page capped to a certain number (`MaxExposurePageSize`). Starting out, this number would be the same as `MaxNominatorRewardedPerValidator`, but eventually, this number can be lowered through new runtime upgrades to limit the rewardeable nominators per dispatched call instruction. The changes in the PR are backward compatible. ## How payouts would work like after this change Staking exposes two calls, 1) the existing `payout_stakers` and 2) `payout_stakers_by_page`. ### payout_stakers This remains backward compatible with no signature change. If for a given era a validator has multiple pages, they can call `payout_stakers` multiple times. The pages are executed in an ascending sequence and the runtime takes care of preventing double claims. ### payout_stakers_by_page Very similar to `payout_stakers` but also accepts an extra param `page_index`. An account can choose to payout rewards only for an explicitly passed `page_index`. **Lets look at an example scenario** Given an active validator on Kusama had 1100 nominators, `MaxExposurePageSize` set to 512 for Era e. In order to pay out rewards to all nominators, the caller would need to call `payout_stakers` 3 times. - `payout_stakers(origin, stash, e)` => will pay the first 512 nominators. - `payout_stakers(origin, stash, e)` => will pay the second set of 512 nominators. - `payout_stakers(origin, stash, e)` => will pay the last set of 76 nominators. ... - `payout_stakers(origin, stash, e)` => calling it the 4th time would return an error `InvalidPage`. The above calls can also be replaced by `payout_stakers_by_page` and passing a `page_index` explicitly. ## Commission note Validator commission is paid out in chunks across all the pages where each commission chunk is proportional to the total stake of the current page. This implies higher the total stake of a page, higher will be the commission. If all the pages of a validator's single era are paid out, the sum of commission paid to the validator across all pages should be equal to what the commission would have been if we had a non-paged exposure. ### Migration Note Strictly speaking, we did not need to bump our storage version since there is no migration of storage in this PR. But it is still useful to mark a storage upgrade for the following reasons: - New storage items are introduced in this PR while some older storage items are deprecated. - For the next `HistoryDepth` eras, the exposure would be incrementally migrated to its corresponding paged storage item. - Runtimes using staking pallet would strictly need to wait at least `HistoryDepth` eras with current upgraded version (14) for the migration to complete. At some era `E` such that `E > era_at_which_V14_gets_into_effect + HistoryDepth`, we will upgrade to version X which will remove the deprecated storage items. In other words, it is a strict requirement that Ex - E14 > `HistoryDepth`, where Ex = Era at which deprecated storages are removed from runtime, E14 = Era at which runtime is upgraded to version 14. - For Polkadot and Kusama, there is a [tracker ticket](https://github.com/paritytech/polkadot-sdk/issues/433) to clean up the deprecated storage items. ### Storage Changes #### Added - ErasStakersOverview - ClaimedRewards - ErasStakersPaged #### Deprecated The following can be cleaned up after 84 eras which is tracked [here](https://github.com/paritytech/polkadot-sdk/issues/433). - ErasStakers. - ErasStakersClipped. - StakingLedger.claimed_rewards, renamed to StakingLedger.legacy_claimed_rewards. ### Config Changes - Renamed MaxNominatorRewardedPerValidator to MaxExposurePageSize. ### TODO - [x] Tracker ticket for cleaning up the old code after 84 eras. - [x] Add companion. - [x] Redo benchmarks before merge. - [x] Add Changelog for pallet_staking. - [x] Pallet should be configurable to enable/disable paged rewards. - [x] Commission payouts are distributed across pages. - [x] Review documentation thoroughly. - [x] Rename `MaxNominatorRewardedPerValidator` -> `MaxExposurePageSize`. - [x] NMap for `ErasStakersPaged`. - [x] Deprecate ErasStakers. - [x] Integrity tests. ### Followup issues [Runtime api for deprecated ErasStakers storage item](https://github.com/paritytech/polkadot-sdk/issues/426) --------- Co-authored-by: Javier Viola Co-authored-by: Ross Bulat Co-authored-by: command-bot <> --- Cargo.lock | 1 + polkadot/runtime/test-runtime/src/lib.rs | 9 +- polkadot/runtime/westend/src/lib.rs | 23 +- .../westend/src/weights/pallet_staking.rs | 1055 ++++----- prdoc/pr_1289.prdoc | 28 + substrate/bin/node/runtime/src/lib.rs | 16 +- substrate/frame/babe/src/mock.rs | 2 +- substrate/frame/babe/src/tests.rs | 8 +- substrate/frame/beefy/src/mock.rs | 2 +- substrate/frame/beefy/src/tests.rs | 12 +- .../test-staking-e2e/src/mock.rs | 5 +- .../frame/fast-unstake/src/benchmarking.rs | 4 +- substrate/frame/fast-unstake/src/lib.rs | 4 - substrate/frame/fast-unstake/src/mock.rs | 4 +- substrate/frame/grandpa/src/mock.rs | 2 +- substrate/frame/grandpa/src/tests.rs | 12 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- substrate/frame/nomination-pools/src/mock.rs | 5 + .../nomination-pools/test-staking/src/mock.rs | 2 +- .../frame/offences/benchmarking/src/mock.rs | 2 +- substrate/frame/root-offences/src/lib.rs | 2 +- substrate/frame/root-offences/src/mock.rs | 2 +- .../frame/session/benchmarking/src/mock.rs | 2 +- substrate/frame/staking/CHANGELOG.md | 27 + substrate/frame/staking/README.md | 16 +- .../frame/staking/runtime-api/Cargo.toml | 5 +- .../frame/staking/runtime-api/src/lib.rs | 6 +- substrate/frame/staking/src/benchmarking.rs | 22 +- substrate/frame/staking/src/ledger.rs | 19 +- substrate/frame/staking/src/lib.rs | 301 ++- substrate/frame/staking/src/migrations.rs | 50 +- substrate/frame/staking/src/mock.rs | 18 +- substrate/frame/staking/src/pallet/impls.rs | 222 +- substrate/frame/staking/src/pallet/mod.rs | 185 +- substrate/frame/staking/src/tests.rs | 1403 ++++++++--- substrate/frame/staking/src/weights.rs | 2051 +++++++++-------- substrate/primitives/staking/src/lib.rs | 133 +- 37 files changed, 3474 insertions(+), 2188 deletions(-) create mode 100644 prdoc/pr_1289.prdoc create mode 100644 substrate/frame/staking/CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 0f386c52b38..fb49533a7f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10619,6 +10619,7 @@ version = "4.0.0-dev" dependencies = [ "parity-scale-codec", "sp-api", + "sp-staking", ] [[package]] diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 888477366d4..596e65eca06 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -192,7 +192,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type KeyOwnerProof = >::Proof; @@ -318,7 +318,8 @@ parameter_types! { // 27 eras in which slashes can be cancelled (a bit less than 7 days). pub storage SlashDeferDuration: sp_staking::EraIndex = 27; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub storage MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxExposurePageSize: u32 = 64; + pub const MaxNominators: u32 = 256; pub storage OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxAuthorities: u32 = 100_000; pub const OnChainMaxWinners: u32 = u32::MAX; @@ -354,7 +355,7 @@ impl pallet_staking::Config for Runtime { type AdminOrigin = frame_system::EnsureNever<()>; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = MaxExposurePageSize; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; @@ -380,7 +381,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type KeyOwnerProof = sp_core::Void; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index b8b2e540e96..9dfc3389d57 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -255,7 +255,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type KeyOwnerProof = >::Proof; @@ -306,7 +306,7 @@ parameter_types! { impl pallet_beefy::Config for Runtime { type BeefyId = BeefyId; type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = BeefyMmrLeaf; type WeightInfo = (); @@ -645,7 +645,11 @@ parameter_types! { // 1 era in which slashes can be cancelled (6 hours). pub const SlashDeferDuration: sp_staking::EraIndex = 1; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxExposurePageSize: u32 = 64; + // Note: this is not really correct as Max Nominators is (MaxExposurePageSize * page_count) but + // this is an unbounded number. We just set it to a reasonably high value, 1 full page + // of nominators. + pub const MaxNominators: u32 = 64; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxNominations: u32 = ::LIMIT as u32; } @@ -665,7 +669,7 @@ impl pallet_staking::Config for Runtime { type AdminOrigin = EnsureRoot; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = MaxExposurePageSize; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = ElectionProviderMultiPhase; @@ -688,8 +692,6 @@ impl pallet_fast_unstake::Config for Runtime { type ControlOrigin = EnsureRoot; type Staking = Staking; type MaxErasToCheckPerBlock = ConstU32<1>; - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; type WeightInfo = weights::pallet_fast_unstake::WeightInfo; } @@ -788,7 +790,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type KeyOwnerProof = >::Proof; @@ -1547,6 +1549,7 @@ pub mod migrations { pub type Unreleased = ( pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, + pallet_staking::migrations::v14::MigrateToV14, assigned_slots::migration::v1::VersionCheckedMigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, @@ -2100,10 +2103,14 @@ sp_api::impl_runtime_apis! { } } - impl pallet_staking_runtime_api::StakingApi for Runtime { + impl pallet_staking_runtime_api::StakingApi for Runtime { fn nominations_quota(balance: Balance) -> u32 { Staking::api_nominations_quota(balance) } + + fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page { + Staking::api_eras_stakers_page_count(era, account) + } } #[cfg(feature = "try-runtime")] diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 099693d26b5..3c4542c6d6f 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_staking` //! //! 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-10-31, 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-yprdrvc7-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_staking // --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_staking +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,746 +48,755 @@ 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) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `894` // Estimated: `4764` - // Minimum execution time: 51_108_000 picoseconds. - Weight::from_parts(52_521_000, 0) + // Minimum execution time: 39_950_000 picoseconds. + Weight::from_parts(41_107_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(3)) .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) + /// 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() -> Weight { // Proof Size summary in bytes: - // Measured: `1959` + // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 96_564_000 picoseconds. - Weight::from_parts(100_133_000, 0) + // Minimum execution time: 83_828_000 picoseconds. + Weight::from_parts(85_733_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) + /// 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: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2166` + // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 97_705_000 picoseconds. - Weight::from_parts(102_055_000, 0) + // Minimum execution time: 89_002_000 picoseconds. + Weight::from_parts(91_556_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) + /// 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:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `981` + // Measured: `1075` // Estimated: `4764` - // Minimum execution time: 45_257_000 picoseconds. - Weight::from_parts(47_309_508, 0) + // Minimum execution time: 40_839_000 picoseconds. + Weight::from_parts(42_122_428, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_343 - .saturating_add(Weight::from_parts(61_484, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Standard Error: 884 + .saturating_add(Weight::from_parts(46_036, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5)) .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) + /// 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::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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::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: `2221 + s * (4 ±0)` + // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 94_800_000 picoseconds. - Weight::from_parts(101_763_223, 0) + // Minimum execution time: 84_244_000 picoseconds. + Weight::from_parts(91_199_964, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 6_481 - .saturating_add(Weight::from_parts(1_450_372, 0).saturating_mul(s.into())) + // Standard Error: 3_381 + .saturating_add(Weight::from_parts(1_327_289, 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) + /// 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: `1343` + // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 57_763_000 picoseconds. - Weight::from_parts(59_394_000, 0) + // Minimum execution time: 49_693_000 picoseconds. + Weight::from_parts(50_814_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) + /// 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: `1248 + k * (569 ±0)` + // Measured: `1243 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 35_501_000 picoseconds. - Weight::from_parts(32_260_525, 0) + // Minimum execution time: 29_140_000 picoseconds. + Weight::from_parts(28_309_627, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 34_554 - .saturating_add(Weight::from_parts(10_625_386, 0).saturating_mul(k.into())) + // Standard Error: 5_780 + .saturating_add(Weight::from_parts(6_509_869, 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) + /// 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: `1839 + n * (102 ±0)` + // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 67_970_000 picoseconds. - Weight::from_parts(65_110_939, 0) + // Minimum execution time: 61_377_000 picoseconds. + Weight::from_parts(58_805_232, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 32_193 - .saturating_add(Weight::from_parts(4_688_614, 0).saturating_mul(n.into())) + // Standard Error: 14_197 + .saturating_add(Weight::from_parts(4_090_197, 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) + /// 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: `1675` + // Measured: `1581` // Estimated: `6248` - // Minimum execution time: 59_515_000 picoseconds. - Weight::from_parts(62_462_000, 0) + // Minimum execution time: 52_736_000 picoseconds. + Weight::from_parts(54_573_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) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, 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::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: `771` + // Measured: `865` // Estimated: `4556` - // Minimum execution time: 13_943_000 picoseconds. - Weight::from_parts(14_384_000, 0) + // Minimum execution time: 16_496_000 picoseconds. + Weight::from_parts(17_045_000, 0) .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .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) + /// 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: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: `870` - // Estimated: `8122` - // Minimum execution time: 21_212_000 picoseconds. - Weight::from_parts(22_061_000, 0) - .saturating_add(Weight::from_parts(0, 8122)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `865` + // Estimated: `4556` + // Minimum execution time: 19_339_000 picoseconds. + Weight::from_parts(20_187_000, 0) + .saturating_add(Weight::from_parts(0, 4556)) + .saturating_add(T::DbWeight::get().reads(2)) .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) + /// 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: 2_977_000 picoseconds. - Weight::from_parts(3_217_000, 0) + // Minimum execution time: 2_340_000 picoseconds. + Weight::from_parts(2_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) + /// 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_152_000 picoseconds. - Weight::from_parts(9_949_000, 0) + // Minimum execution time: 7_483_000 picoseconds. + Weight::from_parts(8_101_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) + /// 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_509_000 picoseconds. - Weight::from_parts(9_838_000, 0) + // Minimum execution time: 7_773_000 picoseconds. + Weight::from_parts(8_610_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) + /// 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_480_000 picoseconds. - Weight::from_parts(9_755_000, 0) + // Minimum execution time: 7_577_000 picoseconds. + Weight::from_parts(7_937_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) + /// Storage: `Staking::Invulnerables` (r:0 w:1) + /// Proof: `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_140_000 picoseconds. - Weight::from_parts(3_438_665, 0) + // Minimum execution time: 2_522_000 picoseconds. + Weight::from_parts(2_735_307, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 93 - .saturating_add(Weight::from_parts(15_688, 0).saturating_mul(v.into())) + // Standard Error: 38 + .saturating_add(Weight::from_parts(10_553, 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) + /// Storage: `Staking::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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: `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: `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::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)` + // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_729_000 picoseconds. - Weight::from_parts(93_633_668, 0) + // Minimum execution time: 82_547_000 picoseconds. + Weight::from_parts(89_373_781, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 6_522 - .saturating_add(Weight::from_parts(1_421_038, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) + // Standard Error: 3_589 + .saturating_add(Weight::from_parts(1_258_878, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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) + /// Storage: `Staking::UnappliedSlashes` (r:1 w:1) + /// Proof: `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: `66606` - // Estimated: `70071` - // Minimum execution time: 135_155_000 picoseconds. - Weight::from_parts(960_317_735, 0) - .saturating_add(Weight::from_parts(0, 70071)) - // Standard Error: 59_264 - .saturating_add(Weight::from_parts(4_884_888, 0).saturating_mul(s.into())) + // Measured: `66639` + // Estimated: `70104` + // Minimum execution time: 134_619_000 picoseconds. + Weight::from_parts(1_194_949_665, 0) + .saturating_add(Weight::from_parts(0, 70104)) + // Standard Error: 76_719 + .saturating_add(Weight::from_parts(6_455_953, 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:65 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:65 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:65 w:65) - /// 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::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:65 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:66 w:66) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:65 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `5773 + n * (151 ±0)` - // Estimated: `8579 + n * (2603 ±0)` - // Minimum execution time: 92_788_000 picoseconds. - Weight::from_parts(129_527_249, 0) - .saturating_add(Weight::from_parts(0, 8579)) - // Standard Error: 73_346 - .saturating_add(Weight::from_parts(33_413_624, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `6895 + n * (156 ±0)` + // Estimated: `9802 + n * (2603 ±0)` + // Minimum execution time: 114_338_000 picoseconds. + Weight::from_parts(138_518_124, 0) + .saturating_add(Weight::from_parts(0, 9802)) + // Standard Error: 53_621 + .saturating_add(Weight::from_parts(25_676_781, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14)) .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(5)) .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:65 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:65 w:65) - /// 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:65 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:65 w:65) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:65 w:65) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:65 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:65 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:65 w:65) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersClipped` (r:1 w:0) + /// Proof: `Staking::ErasStakersClipped` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `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::ErasValidatorReward` (r:1 w:0) + /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:65 w:65) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:65 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:65 w:65) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:65 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8056 + n * (396 ±0)` - // Estimated: `10634 + n * (3774 ±0)` - // Minimum execution time: 118_795_000 picoseconds. - Weight::from_parts(181_663_036, 0) - .saturating_add(Weight::from_parts(0, 10634)) - // Standard Error: 132_894 - .saturating_add(Weight::from_parts(51_369_596, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11)) + // Measured: `8249 + n * (396 ±0)` + // Estimated: `10779 + n * (3774 ±3)` + // Minimum execution time: 132_719_000 picoseconds. + Weight::from_parts(170_505_880, 0) + .saturating_add(Weight::from_parts(0, 10779)) + // Standard Error: 32_527 + .saturating_add(Weight::from_parts(42_453_136, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) .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) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1960 + l * (5 ±0)` + // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 88_870_000 picoseconds. - Weight::from_parts(92_783_195, 0) + // Minimum execution time: 78_438_000 picoseconds. + Weight::from_parts(81_774_734, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 7_412 - .saturating_add(Weight::from_parts(49_785, 0).saturating_mul(l.into())) + // Standard Error: 3_706 + .saturating_add(Weight::from_parts(51_358, 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) + /// 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: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// 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::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: `2221 + s * (4 ±0)` + // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 102_112_000 picoseconds. - Weight::from_parts(103_755_459, 0) + // Minimum execution time: 92_129_000 picoseconds. + Weight::from_parts(94_137_611, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 6_107 - .saturating_add(Weight::from_parts(1_436_139, 0).saturating_mul(s.into())) + // Standard Error: 4_141 + .saturating_add(Weight::from_parts(1_283_823, 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) + /// 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::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: `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::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::ErasValidatorPrefs` (r:0 w:10) + /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:0 w:20) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:0 w:10) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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 ±0) + v * (3566 ±0)` - // Minimum execution time: 547_465_000 picoseconds. - Weight::from_parts(557_541_000, 0) + // Minimum execution time: 527_896_000 picoseconds. + Weight::from_parts(533_325_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_380_806 - .saturating_add(Weight::from_parts(78_379_807, 0).saturating_mul(v.into())) - // Standard Error: 237_234 - .saturating_add(Weight::from_parts(22_772_283, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(185)) + // Standard Error: 2_064_813 + .saturating_add(Weight::from_parts(68_484_503, 0).saturating_mul(v.into())) + // Standard Error: 205_747 + .saturating_add(Weight::from_parts(18_833_735, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(8)) .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) + /// 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::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: `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::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 * (907 ±0) + v * (391 ±0)` + // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 39_710_080_000 picoseconds. - Weight::from_parts(42_191_823_000, 0) + // Minimum execution time: 35_302_472_000 picoseconds. + Weight::from_parts(35_651_169_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 506_609 - .saturating_add(Weight::from_parts(7_688_462, 0).saturating_mul(v.into())) - // Standard Error: 506_609 - .saturating_add(Weight::from_parts(6_303_908, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(180)) + // Standard Error: 412_098 + .saturating_add(Weight::from_parts(5_172_265, 0).saturating_mul(v.into())) + // Standard Error: 412_098 + .saturating_add(Weight::from_parts(4_142_772, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(1)) .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) + /// 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`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `951 + v * (50 ±0)` + // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_603_304_000 picoseconds. - Weight::from_parts(481_860_383, 0) + // Minimum execution time: 2_522_650_000 picoseconds. + Weight::from_parts(97_022_833, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 55_189 - .saturating_add(Weight::from_parts(4_786_173, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Standard Error: 6_751 + .saturating_add(Weight::from_parts(4_990_018, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(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) + /// 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_453_000 picoseconds. - Weight::from_parts(6_857_000, 0) + // Minimum execution time: 3_833_000 picoseconds. + Weight::from_parts(4_108_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) + /// 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_037_000 picoseconds. - Weight::from_parts(6_303_000, 0) + // Minimum execution time: 3_520_000 picoseconds. + Weight::from_parts(3_686_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) + /// 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: `1798` + // Measured: `1704` // Estimated: `6248` - // Minimum execution time: 72_578_000 picoseconds. - Weight::from_parts(74_232_000, 0) + // Minimum execution time: 63_983_000 picoseconds. + Weight::from_parts(66_140_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) + /// 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: `661` + // Measured: `658` // Estimated: `3510` - // Minimum execution time: 13_066_000 picoseconds. - Weight::from_parts(13_421_000, 0) + // Minimum execution time: 11_830_000 picoseconds. + Weight::from_parts(12_210_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) + /// 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_057_000 picoseconds. - Weight::from_parts(3_488_000, 0) + // Minimum execution time: 2_364_000 picoseconds. + Weight::from_parts(2_555_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/prdoc/pr_1289.prdoc b/prdoc/pr_1289.prdoc new file mode 100644 index 00000000000..f3d8801d9d8 --- /dev/null +++ b/prdoc/pr_1289.prdoc @@ -0,0 +1,28 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Supporting paged rewards allowing all nominators to be rewarded + +doc: + - audience: Validator + description: | + We used to clip top `MaxNominatorRewardedPerValidator` nominators by stake that are eligible for staking reward. + This was done to limit computation cost of paying out rewards. This PR introduces paging to reward payouts, + meaning we still clip nominators upto MaxExposurePageSize per page and there could be multiple pages of rewards to + be paid out. Validators get commission pro-rata to the amount of reward that is paid out for the page. + + notes: + - payout_stakers should be called multiple times, once for each page of nominators. + - payout_stakers_by_page can be used to pay out rewards for a specific page. + - Some old non-paged era storage items are deprecated, and can be removed in a future upgrade. + +migrations: + db: [] + + runtime: + - { pallet: "pallet-staking", description: "v14: Migration of era exposure storage items to paged exposures."} + +crates: + - name: pallet-staking + +host_functions: [] \ No newline at end of file diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index cb8d7f6b1de..127faec3562 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -485,7 +485,7 @@ impl pallet_babe::Config for Runtime { type DisabledValidators = Session; type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type KeyOwnerProof = >::Proof; type EquivocationReportSystem = @@ -628,7 +628,7 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const MaxNominators: u32 = 64; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; @@ -663,7 +663,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = ConstU32<256>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -686,8 +686,6 @@ impl pallet_fast_unstake::Config for Runtime { type Currency = Balances; type Staking = Staking; type MaxErasToCheckPerBlock = ConstU32<1>; - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; type WeightInfo = (); } @@ -1453,7 +1451,7 @@ impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type KeyOwnerProof = >::Proof; type EquivocationReportSystem = @@ -2392,10 +2390,14 @@ impl_runtime_apis! { } } - impl pallet_staking_runtime_api::StakingApi for Runtime { + impl pallet_staking_runtime_api::StakingApi for Runtime { fn nominations_quota(balance: Balance) -> u32 { Staking::api_nominations_quota(balance) } + + fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page { + Staking::api_eras_stakers_page_count(era, account) + } } impl sp_consensus_babe::BabeApi for Runtime { diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index e0b23afaf66..0003c6f9f11 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -174,7 +174,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index ec4e6fd9727..e65f1844f88 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -440,7 +440,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -481,7 +481,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Balances::total_balance(&offending_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, offending_validator_id), + Staking::eras_stakers(2, &offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -494,7 +494,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Balances::total_balance(validator), 10_000_000); assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -553,7 +553,7 @@ fn report_equivocation_old_session_works() { assert_eq!(Balances::total_balance(&offending_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, offending_validator_id), + Staking::eras_stakers(3, &offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); }) diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 8618fdab19a..53d523cf724 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -192,7 +192,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index bf1b204e026..bf5ae19510c 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -277,7 +277,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -314,7 +314,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, equivocation_validator_id), + Staking::eras_stakers(2, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -328,7 +328,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -363,7 +363,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -397,7 +397,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, equivocation_validator_id), + Staking::eras_stakers(3, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -411,7 +411,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(3, validator), + Staking::eras_stakers(3, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } 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 9195945f6ca..751ffc07aa5 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 @@ -237,7 +237,6 @@ parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 2; pub const BondingDuration: sp_staking::EraIndex = 28; pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. - pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(40); pub HistoryDepth: u32 = 84; } @@ -269,7 +268,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = (); type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = ConstU32<256>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -809,7 +808,7 @@ pub(crate) fn on_offence_now( pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[OffenceDetails { - offender: (*who, Staking::eras_stakers(active_era(), *who)), + offender: (*who, Staking::eras_stakers(active_era(), who)), reporters: vec![], }], &[Perbill::from_percent(10)], diff --git a/substrate/frame/fast-unstake/src/benchmarking.rs b/substrate/frame/fast-unstake/src/benchmarking.rs index 5ec997e8eaa..851483e3697 100644 --- a/substrate/frame/fast-unstake/src/benchmarking.rs +++ b/substrate/frame/fast-unstake/src/benchmarking.rs @@ -74,9 +74,9 @@ fn setup_staking(v: u32, until: EraIndex) { .collect::>(); for era in 0..=until { - let others = (0..T::MaxBackersPerValidator::get()) + let others = (0..T::Staking::max_exposure_page_size()) .map(|s| { - let who = frame_benchmarking::account::("nominator", era, s); + let who = frame_benchmarking::account::("nominator", era, s.into()); let value = ed; (who, value) }) diff --git a/substrate/frame/fast-unstake/src/lib.rs b/substrate/frame/fast-unstake/src/lib.rs index 2b99ad79a7d..153b6c2c353 100644 --- a/substrate/frame/fast-unstake/src/lib.rs +++ b/substrate/frame/fast-unstake/src/lib.rs @@ -203,10 +203,6 @@ pub mod pallet { /// The weight information of this pallet. type WeightInfo: WeightInfo; - - /// Use only for benchmarking. - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator: Get; } /// The current "head of the queue" being unstaked. diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 6b866224ab9..df133bdfd47 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -134,7 +134,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type HistoryDepth = ConstU32<84>; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; @@ -175,8 +175,6 @@ impl fast_unstake::Config for Runtime { type BatchSize = BatchSize; type WeightInfo = (); type MaxErasToCheckPerBlock = ConstU32<16>; - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = ConstU32<128>; } type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 79e3069d01d..9afcec1c797 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -196,7 +196,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/substrate/frame/grandpa/src/tests.rs b/substrate/frame/grandpa/src/tests.rs index 59d73ee729e..993d72af6d4 100644 --- a/substrate/frame/grandpa/src/tests.rs +++ b/substrate/frame/grandpa/src/tests.rs @@ -333,7 +333,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -371,7 +371,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, equivocation_validator_id), + Staking::eras_stakers(2, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -385,7 +385,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -417,7 +417,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -450,7 +450,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, equivocation_validator_id), + Staking::eras_stakers(3, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -464,7 +464,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(3, validator), + Staking::eras_stakers(3, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 3cbaed23835..9a7f2197a7b 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -110,7 +110,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index d683994c28d..24bea0b87f2 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -202,6 +202,11 @@ impl sp_staking::StakingInterface for StakingMock { fn set_current_era(_era: EraIndex) { unimplemented!("method currently not used in testing") } + + #[cfg(feature = "runtime-benchmarks")] + fn max_exposure_page_size() -> sp_staking::Page { + unimplemented!("method currently not used in testing") + } } impl frame_system::Config for Runtime { diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index c36dc70cb46..0db24e9c244 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -124,7 +124,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index c877f955fba..1a458ec90d5 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -176,7 +176,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/substrate/frame/root-offences/src/lib.rs b/substrate/frame/root-offences/src/lib.rs index a93e7ff8487..e6bb5bb1881 100644 --- a/substrate/frame/root-offences/src/lib.rs +++ b/substrate/frame/root-offences/src/lib.rs @@ -111,7 +111,7 @@ pub mod pallet { .clone() .into_iter() .map(|(o, _)| OffenceDetails:: { - offender: (o.clone(), Staking::::eras_stakers(now, o)), + offender: (o.clone(), Staking::::eras_stakers(now, &o)), reporters: vec![], }) .collect()) diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 59ab539fcf6..82da429e00a 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -179,7 +179,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index d3da12ef9a8..47c337569a0 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -173,7 +173,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/substrate/frame/staking/CHANGELOG.md b/substrate/frame/staking/CHANGELOG.md new file mode 100644 index 00000000000..719aa388755 --- /dev/null +++ b/substrate/frame/staking/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog + +All notable changes and migrations to pallet-staking will be documented in this file. + +The format is loosely based +on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We maintain a +single integer version number for staking pallet to keep track of all storage +migrations. + +## [v14] + +### Added + +- New item `ErasStakersPaged` that keeps up to `MaxExposurePageSize` + individual nominator exposures by era, validator and page. +- New item `ErasStakersOverview` complementary to `ErasStakersPaged` which keeps + state of own and total stake of the validator across pages. +- New item `ClaimedRewards` to support paged rewards payout. + +### Deprecated + +- `ErasStakers` and `ErasStakersClipped` is deprecated, will not be used any longer for the exposures of the new era + post v14 and can be removed after 84 eras once all the exposures are stale. +- Field `claimed_rewards` in item `Ledger` is renamed + to `legacy_claimed_rewards` and can be removed after 84 eras. + +[v14]: https://github.com/paritytech/substrate/pull/13498 diff --git a/substrate/frame/staking/README.md b/substrate/frame/staking/README.md index 387b94b6a68..8c91cfcaa7f 100644 --- a/substrate/frame/staking/README.md +++ b/substrate/frame/staking/README.md @@ -14,6 +14,7 @@ funds are rewarded under normal operation but are held at pain of _slash_ (expro be found not to be discharging its duties properly. ### Terminology + - Staking: The process of locking up funds for some time, placing them at risk of slashing (loss) in order to become a @@ -29,6 +30,7 @@ be found not to be discharging its duties properly. - Slash: The punishment of a staker by reducing its funds. ### Goals + The staking system in Substrate NPoS is designed to make the following possible: @@ -75,7 +77,7 @@ An account can become a validator candidate via the #### Nomination -A **nominator** does not take any _direct_ role in maintaining the network, instead, it votes on a set of validators to +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 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 the @@ -90,10 +92,12 @@ An account can become a nominator via the The **reward and slashing** procedure is the core of the Staking module, attempting to _embrace valid behavior_ while _punishing any misbehavior or lack of availability_. -Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the `payout_stakers` call. Any -account can call `payout_stakers`, which pays the reward to the validator as well as its nominators. Only the -[`Config::MaxNominatorRewardedPerValidator`] biggest stakers can claim their reward. This is to limit the i/o cost to -mutate storage for each nominator's account. +Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the `payout_stakers` call. When a +validator has more than [`Config::MaxExposurePageSize`] nominators, nominators are divided into pages with each call to +`payout_stakers` paying rewards to one page of nominators in a sequential and ascending manner. Any account can also +call `payout_stakers_by_page` to explicitly pay reward for a given page. As evident, this means only the +[`Config::MaxExposurePageSize`] nominators are rewarded per call. This is to limit the i/o cost to mutate storage for +each nominator's account. Slashing can occur at any point in time, once misbehavior is reported. Once slashing is determined, a value is deducted from the balance of the validator and all the nominators who voted for this validator (values are deducted from the @@ -173,11 +177,13 @@ such: ```nocompile staker_payout = yearly_inflation(npos_token_staked / total_tokens) * total_tokens / era_per_year ``` + This payout is used to reward stakers as defined in next section ```nocompile remaining_payout = max_yearly_inflation * total_tokens / era_per_year - staker_payout ``` + The remaining reward is send to the configurable end-point [`T::RewardRemainder`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.RewardRemainder). diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml index 5f49df254ce..746b463b8ce 100644 --- a/substrate/frame/staking/runtime-api/Cargo.toml +++ b/substrate/frame/staking/runtime-api/Cargo.toml @@ -14,8 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -sp-api = { path = "../../../primitives/api", default-features = false} +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } [features] default = [ "std" ] -std = [ "codec/std", "sp-api/std" ] +std = [ "codec/std", "sp-api/std", "sp-staking/std" ] diff --git a/substrate/frame/staking/runtime-api/src/lib.rs b/substrate/frame/staking/runtime-api/src/lib.rs index c669d222ec6..b04c383a077 100644 --- a/substrate/frame/staking/runtime-api/src/lib.rs +++ b/substrate/frame/staking/runtime-api/src/lib.rs @@ -22,11 +22,15 @@ use codec::Codec; sp_api::decl_runtime_apis! { - pub trait StakingApi + pub trait StakingApi where Balance: Codec, + AccountId: Codec, { /// Returns the nominations quota for a nominator with a given balance. fn nominations_quota(balance: Balance) -> u32; + + /// Returns the page count of exposures for a validator in a given era. + fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page; } } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index f94d9bf4b32..05c6bc39709 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -552,10 +552,10 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxExposurePageSize::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxExposurePageSize::get() as u32, true, true, RewardDestination::Controller, @@ -572,7 +572,7 @@ benchmarks! { let balance = T::Currency::free_balance(controller); ensure!(balance.is_zero(), "Controller has balance, but should be dead."); } - }: payout_stakers(RawOrigin::Signed(caller), validator, current_era) + }: payout_stakers_by_page(RawOrigin::Signed(caller), validator, current_era, 0) verify { let balance_after = T::Currency::free_balance(&validator_controller); ensure!( @@ -586,10 +586,10 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxExposurePageSize::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxExposurePageSize::get() as u32, false, true, RewardDestination::Staked, @@ -687,7 +687,6 @@ benchmarks! { let l = StakingLedger::::new( stash.clone(), T::Currency::minimum_balance() - One::one(), - Default::default(), ); Ledger::::insert(&controller, l); @@ -760,7 +759,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let origin = RawOrigin::Signed(caller); let calls: Vec<_> = payout_calls_arg.iter().map(|arg| - Call::::payout_stakers { validator_stash: arg.0.clone(), era: arg.1 }.encode() + Call::::payout_stakers_by_page { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() ).collect(); }: { for call in calls { @@ -984,7 +983,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxExposurePageSize as Get<_>>::get(), false, false, RewardDestination::Staked, @@ -996,10 +995,11 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); let original_free_balance = Balances::free_balance(&validator_stash); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), validator_stash, - current_era + current_era, + 0 )); let new_free_balance = Balances::free_balance(&validator_stash); @@ -1014,7 +1014,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxExposurePageSize as Get<_>>::get(), false, false, RewardDestination::Staked, diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index cf9b4635bf5..84bb4d167dc 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -34,9 +34,8 @@ use frame_support::{ defensive, traits::{LockableCurrency, WithdrawReasons}, - BoundedVec, }; -use sp_staking::{EraIndex, StakingAccount}; +use sp_staking::StakingAccount; use sp_std::prelude::*; use crate::{ @@ -54,7 +53,7 @@ impl StakingLedger { total: Zero::zero(), active: Zero::zero(), unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), controller: Some(stash), } } @@ -66,17 +65,13 @@ impl StakingLedger { /// /// 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 { + pub fn new(stash: T::AccountId, stake: BalanceOf) -> Self { Self { stash: stash.clone(), active: stake, total: stake, unlocking: Default::default(), - claimed_rewards, + legacy_claimed_rewards: Default::default(), // controllers are deprecated and mapped 1-1 to stashes. controller: Some(stash), } @@ -240,8 +235,8 @@ pub struct StakingLedgerInspect { pub total: BalanceOf, #[codec(compact)] pub active: BalanceOf, - pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, - pub claimed_rewards: BoundedVec, + pub unlocking: frame_support::BoundedVec>, T::MaxUnlockingChunks>, + pub legacy_claimed_rewards: frame_support::BoundedVec, } #[cfg(test)] @@ -251,7 +246,7 @@ impl PartialEq> for StakingLedger { self.total == other.total && self.active == other.active && self.unlocking == other.unlocking && - self.claimed_rewards == other.claimed_rewards + self.legacy_claimed_rewards == other.legacy_claimed_rewards } } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 227326763a9..9e4697e845b 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -112,11 +112,15 @@ //! The **reward and slashing** procedure is the core of the Staking pallet, attempting to _embrace //! valid behavior_ while _punishing any misbehavior or lack of availability_. //! -//! Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the -//! `payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the -//! validator as well as its nominators. Only the [`Config::MaxNominatorRewardedPerValidator`] -//! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each -//! nominator's account. +//! Rewards must be claimed for each era before it gets too old by +//! [`HistoryDepth`](`Config::HistoryDepth`) using the `payout_stakers` call. Any account can call +//! `payout_stakers`, which pays the reward to the validator as well as its nominators. Only +//! [`Config::MaxExposurePageSize`] nominator rewards can be claimed in a single call. When the +//! number of nominators exceeds [`Config::MaxExposurePageSize`], then the exposed nominators are +//! stored in multiple pages, with each page containing up to +//! [`Config::MaxExposurePageSize`] nominators. To pay out all nominators, `payout_stakers` must be +//! called once for each available page. Paging exists to limit the i/o cost to mutate storage for +//! each nominator's account. //! //! Slashing can occur at any point in time, once misbehavior is reported. Once slashing is //! determined, a value is deducted from the balance of the validator and all the nominators who @@ -224,13 +228,13 @@ //! The validator can declare an amount, named [`commission`](ValidatorPrefs::commission), that does //! not get shared with the nominators at each reward payout through its [`ValidatorPrefs`]. This //! value gets deducted from the total reward that is paid to the validator and its nominators. The -//! remaining portion is split pro rata among the validator and the top -//! [`Config::MaxNominatorRewardedPerValidator`] nominators that nominated the validator, -//! proportional to the value staked behind the validator (_i.e._ dividing the +//! remaining portion is split pro rata among the validator and the nominators that nominated the +//! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in -//! [`Exposure`]). Note that the pro rata division of rewards uses the total exposure behind the -//! validator, *not* just the exposure of the validator and the top -//! [`Config::MaxNominatorRewardedPerValidator`] nominators. +//! [`Exposure`]). Note that payouts are made in pages with each page capped at +//! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across +//! pages may be unsorted. The total commission is paid out proportionally across pages based on the +//! total stake of the page. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see @@ -303,7 +307,10 @@ mod pallet; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ - traits::{ConstU32, Currency, Defensive, Get, LockIdentifier}, + defensive, defensive_assert, + traits::{ + ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, + }, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -313,11 +320,12 @@ use sp_runtime::{ 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, StakingAccount, + EraIndex, ExposurePage, OnStakingUpdate, Page, PagedExposureMetadata, SessionIndex, + StakingAccount, }; +pub use sp_staking::{Exposure, IndividualExposure, StakerStatus}; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; @@ -457,21 +465,29 @@ pub struct UnlockChunk { pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. pub stash: T::AccountId, + /// The total amount of the stash's balance that we are currently accounting for. /// It's just `active` plus all the `unlocking` balances. #[codec(compact)] pub total: BalanceOf, + /// The total amount of the stash's balance that will be at stake in any forthcoming /// rounds. #[codec(compact)] pub active: BalanceOf, + /// Any balance that is becoming free, which may eventually be transferred out of the stash /// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first /// in, first out queue where the new (higher value) eras get pushed on the back. pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, + /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. - pub claimed_rewards: BoundedVec, + /// + /// This is deprecated as of V14 in favor of `T::ClaimedRewards` and will be removed in future. + /// Refer to issue + pub legacy_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. @@ -507,7 +523,7 @@ impl StakingLedger { total, active: self.active, unlocking, - claimed_rewards: self.claimed_rewards, + legacy_claimed_rewards: self.legacy_claimed_rewards, controller: self.controller, } } @@ -708,32 +724,50 @@ pub struct Nominations { pub suppressed: bool, } -/// The amount of exposure (to slashing) than an individual nominator has. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct IndividualExposure { - /// The stash account of the nominator in question. - pub who: AccountId, - /// Amount of funds exposed. - #[codec(compact)] - pub value: Balance, +/// Facade struct to encapsulate `PagedExposureMetadata` and a single page of `ExposurePage`. +/// +/// This is useful where we need to take into account the validator's own stake and total exposure +/// in consideration, in addition to the individual nominators backing them. +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] +struct PagedExposure { + exposure_metadata: PagedExposureMetadata, + exposure_page: ExposurePage, } -/// A snapshot of the stake backing a single validator in the system. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct Exposure { - /// The total balance backing this validator. - #[codec(compact)] - pub total: Balance, - /// The validator's own stash that is exposed. - #[codec(compact)] - pub own: Balance, - /// The portions of nominators stashes that are exposed. - pub others: Vec>, -} +impl + PagedExposure +{ + /// Create a new instance of `PagedExposure` from legacy clipped exposures. + pub fn from_clipped(exposure: Exposure) -> Self { + Self { + exposure_metadata: PagedExposureMetadata { + total: exposure.total, + own: exposure.own, + nominator_count: exposure.others.len() as u32, + page_count: 1, + }, + exposure_page: ExposurePage { page_total: exposure.total, others: exposure.others }, + } + } -impl Default for Exposure { - fn default() -> Self { - Self { total: Default::default(), own: Default::default(), others: vec![] } + /// Returns total exposure of this validator across pages + pub fn total(&self) -> Balance { + self.exposure_metadata.total + } + + /// Returns total exposure of this validator for the current page + pub fn page_total(&self) -> Balance { + self.exposure_page.page_total + self.exposure_metadata.own + } + + /// Returns validator's own stake that is exposed + pub fn own(&self) -> Balance { + self.exposure_metadata.own + } + + /// Returns the portions of nominators stashes that are exposed in this page. + pub fn others(&self) -> &Vec> { + &self.exposure_page.others } } @@ -985,6 +1019,195 @@ where } } +/// Wrapper struct for Era related information. It is not a pure encapsulation as these storage +/// items can be accessed directly but nevertheless, its recommended to use `EraInfo` where we +/// can and add more functions to it as needed. +pub(crate) struct EraInfo(sp_std::marker::PhantomData); +impl EraInfo { + /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy + /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be + /// removed once `T::HistoryDepth` eras have passed and none of the older non-paged rewards + /// are relevant/claimable. + // Refer tracker issue for cleanup: #13034 + pub(crate) fn is_rewards_claimed_with_legacy_fallback( + era: EraIndex, + ledger: &StakingLedger, + validator: &T::AccountId, + page: Page, + ) -> bool { + ledger.legacy_claimed_rewards.binary_search(&era).is_ok() || + Self::is_rewards_claimed(era, validator, page) + } + + /// Check if the rewards for the given era and page index have been claimed. + /// + /// This is only used for paged rewards. Once older non-paged rewards are no longer + /// relevant, `is_rewards_claimed_with_legacy_fallback` can be removed and this function can + /// be made public. + fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: Page) -> bool { + ClaimedRewards::::get(era, validator).contains(&page) + } + + /// Get exposure for a validator at a given era and page. + /// + /// This builds a paged exposure from `PagedExposureMetadata` and `ExposurePage` of the + /// validator. For older non-paged exposure, it returns the clipped exposure directly. + pub(crate) fn get_paged_exposure( + era: EraIndex, + validator: &T::AccountId, + page: Page, + ) -> Option>> { + let overview = >::get(&era, validator); + + // return clipped exposure if page zero and paged exposure does not exist + // exists for backward compatibility and can be removed as part of #13034 + if overview.is_none() && page == 0 { + return Some(PagedExposure::from_clipped(>::get(era, validator))) + } + + // no exposure for this validator + if overview.is_none() { + return None + } + + let overview = overview.expect("checked above; qed"); + + // validator stake is added only in page zero + let validator_stake = if page == 0 { overview.own } else { Zero::zero() }; + + // since overview is present, paged exposure will always be present except when a + // validator has only own stake and no nominator stake. + let exposure_page = >::get((era, validator, page)).unwrap_or_default(); + + // build the exposure + Some(PagedExposure { + exposure_metadata: PagedExposureMetadata { own: validator_stake, ..overview }, + exposure_page, + }) + } + + /// Get full exposure of the validator at a given era. + pub(crate) fn get_full_exposure( + era: EraIndex, + validator: &T::AccountId, + ) -> Exposure> { + let overview = >::get(&era, validator); + + if overview.is_none() { + return ErasStakers::::get(era, validator) + } + + let overview = overview.expect("checked above; qed"); + + let mut others = Vec::with_capacity(overview.nominator_count as usize); + for page in 0..overview.page_count { + let nominators = >::get((era, validator, page)); + others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default()); + } + + Exposure { total: overview.total, own: overview.own, others } + } + + /// Returns the number of pages of exposure a validator has for the given era. + /// + /// For eras where paged exposure does not exist, this returns 1 to keep backward compatibility. + pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> Page { + >::get(&era, validator) + .map(|overview| { + if overview.page_count == 0 && overview.own > Zero::zero() { + // Even though there are no nominator pages, there is still validator's own + // stake exposed which needs to be paid out in a page. + 1 + } else { + overview.page_count + } + }) + // Always returns 1 page for older non-paged exposure. + // FIXME: Can be cleaned up with issue #13034. + .unwrap_or(1) + } + + /// Returns the next page that can be claimed or `None` if nothing to claim. + pub(crate) fn get_next_claimable_page( + era: EraIndex, + validator: &T::AccountId, + ledger: &StakingLedger, + ) -> Option { + if Self::is_non_paged_exposure(era, validator) { + return match ledger.legacy_claimed_rewards.binary_search(&era) { + // already claimed + Ok(_) => None, + // Non-paged exposure is considered as a single page + Err(_) => Some(0), + } + } + + // Find next claimable page of paged exposure. + let page_count = Self::get_page_count(era, validator); + let all_claimable_pages: Vec = (0..page_count).collect(); + let claimed_pages = ClaimedRewards::::get(era, validator); + + all_claimable_pages.into_iter().find(|p| !claimed_pages.contains(p)) + } + + /// Checks if exposure is paged or not. + fn is_non_paged_exposure(era: EraIndex, validator: &T::AccountId) -> bool { + >::contains_key(&era, validator) + } + + /// Returns validator commission for this era and page. + pub(crate) fn get_validator_commission( + era: EraIndex, + validator_stash: &T::AccountId, + ) -> Perbill { + >::get(&era, validator_stash).commission + } + + /// Creates an entry to track validator reward has been claimed for a given era and page. + /// Noop if already claimed. + pub(crate) fn set_rewards_as_claimed(era: EraIndex, validator: &T::AccountId, page: Page) { + let mut claimed_pages = ClaimedRewards::::get(era, validator); + + // this should never be called if the reward has already been claimed + if claimed_pages.contains(&page) { + defensive!("Trying to set an already claimed reward"); + // nevertheless don't do anything since the page already exist in claimed rewards. + return + } + + // add page to claimed entries + claimed_pages.push(page); + ClaimedRewards::::insert(era, validator, claimed_pages); + } + + /// Store exposure for elected validators at start of an era. + pub(crate) fn set_exposure( + era: EraIndex, + validator: &T::AccountId, + exposure: Exposure>, + ) { + let page_size = T::MaxExposurePageSize::get().defensive_max(1); + + let nominator_count = exposure.others.len(); + // expected page count is the number of nominators divided by the page size, rounded up. + let expected_page_count = + nominator_count.defensive_saturating_add(page_size as usize - 1) / page_size as usize; + + let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); + defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); + + >::insert(era, &validator, &exposure_metadata); + exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { + >::insert((era, &validator, page as Page), &paged_exposure); + }); + } + + /// Store total exposure for all the elected validators in the era. + pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { + >::insert(era, total_stake); + } +} + /// Configurations of the benchmarking of the pallet. pub trait BenchmarkingConfig { /// The maximum number of validators to use. diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 89520028b90..84b00254126 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -14,7 +14,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -//! Storage migrations for the Staking pallet. +//! Storage migrations for the Staking pallet. The changelog for this is maintained at +//! [CHANGELOG.md](https://github.com/paritytech/substrate/blob/master/frame/staking/CHANGELOG.md). use super::*; use frame_election_provider_support::SortedListProvider; @@ -58,6 +59,49 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migration of era exposure storage items to paged exposures. +/// Changelog: [v14.](https://github.com/paritytech/substrate/blob/ankan/paged-rewards-rebased2/frame/staking/CHANGELOG.md#14) +pub mod v14 { + use super::*; + + pub struct MigrateToV14(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV14 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let on_chain = Pallet::::on_chain_storage_version(); + + if current == 14 && on_chain == 13 { + current.put::>(); + + log!(info, "v14 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } else { + log!(warn, "v14 not applied."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 13, + "Required v13 before upgrading to v14." + ); + + Ok(Default::default()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 14, + "v14 not applied" + ); + Ok(()) + } + } +} + pub mod v13 { use super::*; @@ -113,9 +157,9 @@ pub mod v12 { #[storage_alias] type HistoryDepth = StorageValue, u32, ValueQuery>; - /// Clean up `HistoryDepth` from storage. + /// Clean up `T::HistoryDepth` from storage. /// - /// We will be depending on the configurable value of `HistoryDepth` post + /// We will be depending on the configurable value of `T::HistoryDepth` post /// this release. pub struct MigrateToV12(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV12 { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index c694ce004dd..d2afd8f26e2 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,8 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, - OnUnbalanced, OneSessionHandler, + ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, + OneSessionHandler, }, weights::constants::RocksDbWeight, }; @@ -236,6 +236,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static HistoryDepth: u32 = 80; + pub static MaxExposurePageSize: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static MaxWinners: u32 = 100; @@ -304,7 +305,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = MaxExposurePageSize; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; @@ -760,7 +761,7 @@ pub(crate) fn on_offence_now( pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[OffenceDetails { - offender: (*who, Staking::eras_stakers(active_era(), *who)), + offender: (*who, Staking::eras_stakers(active_era(), who)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -778,7 +779,14 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { // reward validators for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era)); + for page in 0..EraInfo::::get_page_count(era, &ledger.stash) { + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + ledger.stash, + era, + page + )); + } } } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index ad2de1d5931..bb16fe56d51 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, OnUnbalanced, - TryCollect, UnixTime, + Currency, Defensive, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, TryCollect, + UnixTime, }, weights::Weight, }; @@ -41,7 +41,7 @@ use sp_runtime::{ use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, Stake, + EraIndex, Page, SessionIndex, Stake, StakingAccount::{self, Controller, Stash}, StakingInterface, }; @@ -49,9 +49,9 @@ use sp_std::prelude::*; use crate::{ election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, - BalanceOf, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, MaxNominationsOf, - MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, - SessionInterface, StakingLedger, ValidatorPrefs, + BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, + MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, + RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, }; use super::pallet::*; @@ -158,12 +158,31 @@ impl Pallet { pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, + ) -> DispatchResultWithPostInfo { + let controller = Self::bonded(&validator_stash).ok_or_else(|| { + Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; + let ledger = >::get(&controller).ok_or(Error::::NotController)?; + let page = EraInfo::::get_next_claimable_page(era, &validator_stash, &ledger) + .ok_or_else(|| { + Error::::AlreadyClaimed + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; + + Self::do_payout_stakers_by_page(validator_stash, era, page) + } + + pub(super) fn do_payout_stakers_by_page( + validator_stash: T::AccountId, + era: EraIndex, + page: Page, ) -> DispatchResultWithPostInfo { // Validate input data let current_era = CurrentEra::::get().ok_or_else(|| { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; + let history_depth = T::HistoryDepth::get(); ensure!( era <= current_era && era >= current_era.saturating_sub(history_depth), @@ -171,8 +190,13 @@ impl Pallet { .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) ); + ensure!( + page < EraInfo::::get_page_count(era, &validator_stash), + Error::::InvalidPage.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + ); + // Note: if era has no reward to be claimed, era may be future. better not to update - // `ledger.claimed_rewards` in this case. + // `ledger.legacy_claimed_rewards` in this case. let era_payout = >::get(&era).ok_or_else(|| { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) @@ -186,31 +210,29 @@ impl Pallet { Err(Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) } })?; - let stash = ledger.stash.clone(); + // clean up older claimed rewards ledger - .claimed_rewards + .legacy_claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); + ledger.clone().update()?; + + let stash = ledger.stash.clone(); - match ledger.claimed_rewards.binary_search(&era) { - Ok(_) => - return Err(Error::::AlreadyClaimed - .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), - Err(pos) => ledger - .claimed_rewards - .try_insert(pos, era) - // Since we retain era entries in `claimed_rewards` only upto - // `HistoryDepth`, following bound is always expected to be - // satisfied. - .defensive_map_err(|_| Error::::BoundNotMet)?, + if EraInfo::::is_rewards_claimed_with_legacy_fallback(era, &ledger, &stash, page) { + return Err(Error::::AlreadyClaimed + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) + } else { + EraInfo::::set_rewards_as_claimed(era, &stash, page); } - let exposure = >::get(&era, &stash); + let exposure = EraInfo::::get_paged_exposure(era, &stash, page).ok_or_else(|| { + Error::::InvalidEraToReward + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; // Input data seems good, no errors allowed after this point - ledger.update()?; - // Get Era reward points. It has TOTAL and INDIVIDUAL // Find the fraction of the era reward that belongs to the validator // Take that fraction of the eras rewards to split to nominator and validator @@ -236,15 +258,17 @@ impl Pallet { // This is how much validator + nominators are entitled to. let validator_total_payout = validator_total_reward_part * era_payout; - let validator_prefs = Self::eras_validator_prefs(&era, &validator_stash); - // Validator first gets a cut off the top. - let validator_commission = validator_prefs.commission; - let validator_commission_payout = validator_commission * validator_total_payout; + let validator_commission = EraInfo::::get_validator_commission(era, &ledger.stash); + // total commission validator takes across all nominator pages + let validator_total_commission_payout = validator_commission * validator_total_payout; - let validator_leftover_payout = validator_total_payout - validator_commission_payout; + let validator_leftover_payout = validator_total_payout - validator_total_commission_payout; // Now let's calculate how this is split to the validator. - let validator_exposure_part = Perbill::from_rational(exposure.own, exposure.total); + let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; + let page_stake_part = Perbill::from_rational(exposure.page_total(), exposure.total()); + // validator commission is paid out in fraction across pages proportional to the page stake. + let validator_commission_payout = page_stake_part * validator_total_commission_payout; Self::deposit_event(Event::::PayoutStarted { era_index: era, @@ -267,8 +291,8 @@ impl Pallet { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. - for nominator in exposure.others.iter() { - let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure.total); + for nominator in exposure.others().iter() { + let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure.total()); let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; @@ -287,7 +311,8 @@ impl Pallet { } T::Reward::on_unbalanced(total_imbalance); - debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); + debug_assert!(nominator_payout_count <= T::MaxExposurePageSize::get()); + Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } @@ -306,6 +331,11 @@ impl Pallet { stash: &T::AccountId, amount: BalanceOf, ) -> Option<(PositiveImbalanceOf, RewardDestination)> { + // noop if amount is zero + if amount.is_zero() { + return None + } + let dest = Self::payee(StakingAccount::Stash(stash.clone())); let maybe_imbalance = match dest { RewardDestination::Controller => Self::bonded(stash) @@ -587,31 +617,24 @@ impl Pallet { >, new_planned_era: EraIndex, ) -> BoundedVec> { - let elected_stashes: BoundedVec<_, MaxWinnersOf> = exposures - .iter() - .cloned() - .map(|(x, _)| x) - .collect::>() - .try_into() - .expect("since we only map through exposures, size of elected_stashes is always same as exposures; qed"); - - // Populate stakers, exposures, and the snapshot of validator prefs. + // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); + let mut elected_stashes = Vec::with_capacity(exposures.len()); + exposures.into_iter().for_each(|(stash, exposure)| { + // build elected stash + elected_stashes.push(stash.clone()); + // accumulate total stake total_stake = total_stake.saturating_add(exposure.total); - >::insert(new_planned_era, &stash, &exposure); - - let mut exposure_clipped = exposure; - let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; - if exposure_clipped.others.len() > clipped_max_len { - exposure_clipped.others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); - exposure_clipped.others.truncate(clipped_max_len); - } - >::insert(&new_planned_era, &stash, exposure_clipped); + // store staker exposure for this era + EraInfo::::set_exposure(new_planned_era, &stash, exposure); }); - // Insert current era staking information - >::insert(&new_planned_era, total_stake); + let elected_stashes: BoundedVec<_, MaxWinnersOf> = elected_stashes + .try_into() + .expect("elected_stashes.len() always equal to exposures.len(); qed"); + + EraInfo::::set_total_stake(new_planned_era, total_stake); // Collect the pref of all winners. for stash in &elected_stashes { @@ -692,12 +715,21 @@ impl Pallet { /// Clear all era information for given era. pub(crate) fn clear_era_information(era_index: EraIndex) { + // FIXME: We can possibly set a reasonable limit since we do this only once per era and + // clean up state across multiple blocks. let mut cursor = >::clear_prefix(era_index, u32::MAX, None); debug_assert!(cursor.maybe_cursor.is_none()); cursor = >::clear_prefix(era_index, u32::MAX, None); debug_assert!(cursor.maybe_cursor.is_none()); cursor = >::clear_prefix(era_index, u32::MAX, None); debug_assert!(cursor.maybe_cursor.is_none()); + cursor = >::clear_prefix(era_index, u32::MAX, None); + debug_assert!(cursor.maybe_cursor.is_none()); + cursor = >::clear_prefix((era_index,), u32::MAX, None); + debug_assert!(cursor.maybe_cursor.is_none()); + cursor = >::clear_prefix(era_index, u32::MAX, None); + debug_assert!(cursor.maybe_cursor.is_none()); + >::remove(era_index); >::remove(era_index); >::remove(era_index); @@ -1036,6 +1068,18 @@ impl Pallet { DispatchClass::Mandatory, ); } + + /// Returns full exposure of a validator for a given era. + /// + /// History note: This used to be a getter for old storage item `ErasStakers` deprecated in v14. + /// Since this function is used in the codebase at various places, we kept it as a custom getter + /// that takes care of getting the full exposure of the validator in a backward compatible way. + pub fn eras_stakers( + era: EraIndex, + account: &T::AccountId, + ) -> Exposure> { + EraInfo::::get_full_exposure(era, account) + } } impl Pallet { @@ -1045,6 +1089,17 @@ impl Pallet { pub fn api_nominations_quota(balance: BalanceOf) -> u32 { T::NominationsQuota::get_quota(balance) } + + pub fn api_eras_stakers( + era: EraIndex, + account: T::AccountId, + ) -> Exposure> { + Self::eras_stakers(era, &account) + } + + pub fn api_eras_stakers_page_count(era: EraIndex, account: T::AccountId) -> Page { + EraInfo::::get_page_count(era, &account) + } } impl ElectionDataProvider for Pallet { @@ -1129,10 +1184,7 @@ impl ElectionDataProvider for Pallet { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); >::insert(voter.clone(), voter.clone()); - >::insert( - voter.clone(), - StakingLedger::::new(voter.clone(), stake, Default::default()), - ); + >::insert(voter.clone(), StakingLedger::::new(voter.clone(), stake)); Self::do_add_nominator(&voter, Nominations { targets, submitted_in: 0, suppressed: false }); } @@ -1141,10 +1193,7 @@ impl ElectionDataProvider for Pallet { fn add_target(target: T::AccountId) { let stake = MinValidatorBond::::get() * 100u32.into(); >::insert(target.clone(), target.clone()); - >::insert( - target.clone(), - StakingLedger::::new(target.clone(), stake, Default::default()), - ); + >::insert(target.clone(), StakingLedger::::new(target.clone(), stake)); Self::do_add_validator( &target, ValidatorPrefs { commission: Perbill::zero(), blocked: false }, @@ -1176,10 +1225,7 @@ impl ElectionDataProvider for Pallet { .and_then(|w| >::try_from(w).ok()) .unwrap_or_else(|| MinNominatorBond::::get() * 100u32.into()); >::insert(v.clone(), v.clone()); - >::insert( - v.clone(), - StakingLedger::::new(v.clone(), stake, Default::default()), - ); + >::insert(v.clone(), StakingLedger::::new(v.clone(), stake)); Self::do_add_validator( &v, ValidatorPrefs { commission: Perbill::zero(), blocked: false }, @@ -1191,10 +1237,7 @@ impl ElectionDataProvider for Pallet { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); >::insert(v.clone(), v.clone()); - >::insert( - v.clone(), - StakingLedger::::new(v.clone(), stake, Default::default()), - ); + >::insert(v.clone(), StakingLedger::::new(v.clone(), stake)); Self::do_add_nominator( &v, Nominations { targets: t, submitted_in: 0, suppressed: false }, @@ -1622,31 +1665,12 @@ impl StakingInterface for Pallet { MinValidatorBond::::get() } - fn desired_validator_count() -> u32 { - ValidatorCount::::get() - } - - fn election_ongoing() -> bool { - T::ElectionProvider::ongoing() - } - - fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { - let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); - Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) - } - fn stash_by_ctrl(controller: &Self::AccountId) -> Result { Self::ledger(Controller(controller.clone())) .map(|l| l.stash) .map_err(|e| e.into()) } - fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { - ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { - validator == *who || exposures.others.iter().any(|i| i.who == *who) - }) - } - fn bonding_duration() -> EraIndex { T::BondingDuration::get() } @@ -1707,6 +1731,24 @@ impl StakingInterface for Pallet { Self::nominate(RawOrigin::Signed(ctrl).into(), targets) } + fn desired_validator_count() -> u32 { + ValidatorCount::::get() + } + + fn election_ongoing() -> bool { + T::ElectionProvider::ongoing() + } + + fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { + let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); + Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) + } + + fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { + ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { + validator == *who || exposures.others.iter().any(|i| i.who == *who) + }) + } fn status( who: &Self::AccountId, ) -> Result, DispatchError> { @@ -1746,12 +1788,16 @@ impl StakingInterface for Pallet { .map(|(who, value)| IndividualExposure { who: who.clone(), value: value.clone() }) .collect::>(); let exposure = Exposure { total: Default::default(), own: Default::default(), others }; - >::insert(¤t_era, &stash, &exposure); + EraInfo::::set_exposure(*current_era, stash, exposure); } fn set_current_era(era: EraIndex) { CurrentEra::::put(era); } + + fn max_exposure_page_size() -> Page { + T::MaxExposurePageSize::get() + } } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index f084299be8e..18ad3e4a6cf 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -24,8 +24,8 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, + Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, + LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, @@ -35,8 +35,9 @@ use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, }; + use sp_staking::{ - EraIndex, SessionIndex, + EraIndex, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, }; use sp_std::prelude::*; @@ -47,9 +48,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, Forcing, MaxNominationsOf, NegativeImbalanceOf, Nominations, - NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, - UnappliedSlash, UnlockChunk, ValidatorPrefs, + EraRewardPoints, Exposure, ExposurePage, Forcing, MaxNominationsOf, NegativeImbalanceOf, + Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, + StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of @@ -61,12 +62,12 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; pub mod pallet { use frame_election_provider_support::ElectionDataProvider; - use crate::BenchmarkingConfig; + use crate::{BenchmarkingConfig, PagedExposureMetadata}; use super::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(13); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(14); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -138,8 +139,8 @@ pub mod pallet { /// Following information is kept for eras in `[current_era - /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, - /// `ErasTotalStake`, `ErasStartSessionIndex`, - /// `StakingLedger.claimed_rewards`. + /// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`, `ErasStakersPaged`, + /// `ErasStakersOverview`. /// /// Must be more than the number of eras delayed by session. /// I.e. active era must always be in history. I.e. `active_era > @@ -149,7 +150,7 @@ pub mod pallet { /// this should be set to same value or greater as in storage. /// /// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec` - /// item `StakingLedger.claimed_rewards`. Setting this value lower than + /// item `StakingLedger.legacy_claimed_rewards`. Setting this value lower than /// the existing value can lead to inconsistencies in the /// `StakingLedger` and will need to be handled properly in a migration. /// The test `reducing_history_depth_abrupt` shows this effect. @@ -202,12 +203,19 @@ pub mod pallet { /// guess. type NextNewSession: EstimateNextNewSession>; - /// The maximum number of nominators rewarded for each validator. + /// The maximum size of each `T::ExposurePage`. + /// + /// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize` + /// nominators. /// - /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can - /// claim their reward. This used to limit the i/o cost for the nominator payout. + /// For older non-paged exposure, a reward payout was restricted to the top + /// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the + /// nominator payout. + /// + /// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to reduce + /// without handling it in a migration. #[pallet::constant] - type MaxNominatorRewardedPerValidator: Get; + type MaxExposurePageSize: Get; /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. @@ -390,7 +398,7 @@ pub mod pallet { #[pallet::getter(fn active_era)] pub type ActiveEra = StorageValue<_, ActiveEraInfo>; - /// The session index at which the era start for the last `HISTORY_DEPTH` eras. + /// The session index at which the era start for the last [`Config::HistoryDepth`] eras. /// /// Note: This tracks the starting session (i.e. session index when era start being active) /// for the eras in `[CurrentEra - HISTORY_DEPTH, CurrentEra]`. @@ -402,10 +410,11 @@ pub mod pallet { /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// Is it removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. + /// + /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. #[pallet::storage] - #[pallet::getter(fn eras_stakers)] #[pallet::unbounded] pub type ErasStakers = StorageDoubleMap< _, @@ -417,17 +426,45 @@ pub mod pallet { ValueQuery, >; + /// Summary of validator exposure at a given era. + /// + /// This contains the total stake in support of the validator and their own stake. In addition, + /// it can also be used to get the number of nominators backing this validator and the number of + /// exposure pages they are divided into. The page count is useful to determine the number of + /// pages of rewards that needs to be claimed. + /// + /// This is keyed first by the era index to allow bulk deletion and then the stash account. + /// Should only be accessed through `EraInfo`. + /// + /// Is it removed after [`Config::HistoryDepth`] eras. + /// If stakers hasn't been set or has been removed then empty overview is returned. + #[pallet::storage] + pub type ErasStakersOverview = StorageDoubleMap< + _, + Twox64Concat, + EraIndex, + Twox64Concat, + T::AccountId, + PagedExposureMetadata>, + OptionQuery, + >; + /// Clipped Exposure of validator at era. /// + /// Note: This is deprecated, should be used as read-only and will be removed in the future. + /// New `Exposure`s are stored in a paged manner in `ErasStakersPaged` instead. + /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the - /// `T::MaxNominatorRewardedPerValidator` biggest stakers. + /// `T::MaxExposurePageSize` biggest stakers. /// (Note: the field `total` and `own` of the exposure remains unchanged). /// This is used to limit the i/o cost for the nominator payout. /// /// This is keyed fist by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// It is removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. + /// + /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. #[pallet::storage] #[pallet::unbounded] #[pallet::getter(fn eras_stakers_clipped)] @@ -441,11 +478,49 @@ pub mod pallet { ValueQuery, >; + /// Paginated exposure of a validator at given era. + /// + /// This is keyed first by the era index to allow bulk deletion, then stash account and finally + /// the page. Should only be accessed through `EraInfo`. + /// + /// This is cleared after [`Config::HistoryDepth`] eras. + #[pallet::storage] + #[pallet::unbounded] + pub type ErasStakersPaged = StorageNMap< + _, + ( + NMapKey, + NMapKey, + NMapKey, + ), + ExposurePage>, + OptionQuery, + >; + + /// History of claimed paged rewards by era and validator. + /// + /// This is keyed by era and validator stash which maps to the set of page indexes which have + /// been claimed. + /// + /// It is removed after [`Config::HistoryDepth`] eras. + #[pallet::storage] + #[pallet::getter(fn claimed_rewards)] + #[pallet::unbounded] + pub type ClaimedRewards = StorageDoubleMap< + _, + Twox64Concat, + EraIndex, + Twox64Concat, + T::AccountId, + Vec, + ValueQuery, + >; + /// Similar to `ErasStakers`, this holds the preferences of validators. /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// Is it removed after [`Config::HistoryDepth`] eras. // If prefs hasn't been set or has been removed then 0 commission is returned. #[pallet::storage] #[pallet::getter(fn eras_validator_prefs)] @@ -459,14 +534,14 @@ pub mod pallet { ValueQuery, >; - /// The total validator era payout for the last `HISTORY_DEPTH` eras. + /// The total validator era payout for the last [`Config::HistoryDepth`] eras. /// /// Eras that haven't finished yet or has been removed doesn't have reward. #[pallet::storage] #[pallet::getter(fn eras_validator_reward)] pub type ErasValidatorReward = StorageMap<_, Twox64Concat, EraIndex, BalanceOf>; - /// Rewards for the last `HISTORY_DEPTH` eras. + /// Rewards for the last [`Config::HistoryDepth`] eras. /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] #[pallet::unbounded] @@ -474,7 +549,7 @@ pub mod pallet { pub type ErasRewardPoints = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; - /// The total amount staked for the last `HISTORY_DEPTH` eras. + /// The total amount staked for the last [`Config::HistoryDepth`] eras. /// If total hasn't been set or has been removed then 0 stake is returned. #[pallet::storage] #[pallet::getter(fn eras_total_stake)] @@ -743,6 +818,8 @@ pub mod pallet { NotSortedAndUnique, /// Rewards for this era have already been claimed for this validator. AlreadyClaimed, + /// No nominators exist on this page. + InvalidPage, /// Incorrect previous history depth input provided. IncorrectHistoryDepth, /// Incorrect number of slashing spans provided. @@ -854,23 +931,10 @@ pub mod pallet { frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; - let current_era = CurrentEra::::get().unwrap_or(0); - let history_depth = T::HistoryDepth::get(); - let last_reward_era = current_era.saturating_sub(history_depth); - 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 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)?, - ); + let ledger = StakingLedger::::new(stash.clone(), value); // You're auto-bonded forever, here. We might improve this by only bonding when // you actually validate/nominate and remove once you unbond __everything__. @@ -1463,21 +1527,21 @@ pub mod pallet { Ok(()) } - /// Pay out all the stakers behind a single validator for a single era. + /// Pay out next page of the stakers behind a validator for the given era. /// - /// - `validator_stash` is the stash account of the validator. Their nominators, up to - /// `T::MaxNominatorRewardedPerValidator`, will also receive their rewards. + /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// ## Complexity - /// - At most O(MaxNominatorRewardedPerValidator). + /// The reward payout could be paged in case there are too many nominators backing the + /// `validator_stash`. This call will payout unpaid pages in an ascending order. To claim a + /// specific page, use `payout_stakers_by_page`.` + /// + /// If all pages are claimed, it returns an error `InvalidPage`. #[pallet::call_index(18)] - #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerValidator::get() - ))] + #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))] pub fn payout_stakers( origin: OriginFor, validator_stash: T::AccountId, @@ -1779,6 +1843,35 @@ pub mod pallet { MinCommission::::put(new); Ok(()) } + + /// Pay out a page of the stakers behind a validator for the given era and page. + /// + /// - `validator_stash` is the stash account of the validator. + /// - `era` may be any era between `[current_era - history_depth; current_era]`. + /// - `page` is the page index of nominators to pay out with value between 0 and + /// `num_nominators / T::MaxExposurePageSize`. + /// + /// The origin of this call must be _Signed_. Any account can call this function, even if + /// it is not one of the stakers. + /// + /// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing + /// them, then the list of nominators is paged, with each page being capped at + /// [`Config::MaxExposurePageSize`.] If a validator has more than one page of nominators, + /// the call needs to be made for each page separately in order for all the nominators + /// backing a validator to receive the reward. The nominators are not sorted across pages + /// and so it should not be assumed the highest staker would be on the topmost page and vice + /// versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are lost. + #[pallet::call_index(26)] + #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))] + pub fn payout_stakers_by_page( + origin: OriginFor, + validator_stash: T::AccountId, + era: EraIndex, + page: Page, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + Self::do_payout_stakers_by_page(validator_stash, era, page) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index cb620f89f12..ee6f67adf14 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -29,6 +29,7 @@ use frame_support::{ pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, }; + use mock::*; use pallet_balances::Error as BalancesError; use sp_runtime::{ @@ -158,7 +159,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Account 21 controls its own stash, which is 200 * balance_factor units @@ -169,7 +170,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Account 1 does not control any stash @@ -192,13 +193,13 @@ fn basic_setup_works() { total: 500, active: 500, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1125, own: 1000, @@ -206,7 +207,7 @@ fn basic_setup_works() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), 21), + Staking::eras_stakers(active_era(), &21), Exposure { total: 1375, own: 1000, @@ -467,7 +468,7 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![], } ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -522,7 +523,7 @@ fn less_than_needed_candidates_works() { // But the exposure is updated in a simple way. No external votes exists. // This is purely self-vote. - assert!(ErasStakers::::iter_prefix_values(active_era()) + assert!(ErasStakersPaged::::iter_prefix_values((active_era(),)) .all(|exposure| exposure.others.is_empty())); }); } @@ -640,9 +641,9 @@ fn nominating_and_rewards_should_work() { assert_eq!(Balances::total_balance(&21), initial_balance_21 + total_payout_0 / 2); initial_balance_21 = Balances::total_balance(&21); - assert_eq!(ErasStakers::::iter_prefix_values(active_era()).count(), 2); + assert_eq!(ErasStakersPaged::::iter_prefix_values((active_era(),)).count(), 2); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 800, own: 1000, @@ -653,7 +654,7 @@ fn nominating_and_rewards_should_work() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), 21), + Staking::eras_stakers(active_era(), &21), Exposure { total: 1000 + 1200, own: 1000, @@ -713,7 +714,7 @@ fn nominators_also_get_slashed_pro_rata() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); let slash_percent = Perbill::from_percent(5); - let initial_exposure = Staking::eras_stakers(active_era(), 11); + let initial_exposure = Staking::eras_stakers(active_era(), &11); // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); @@ -981,7 +982,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 has some free balance assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1), @@ -1006,7 +1007,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 has some free balance assert_eq!(Balances::free_balance(21), 2000); // Confirm account 21 (via controller) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); // Confirm account 21 can transfer at most 1000 assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001), @@ -1025,7 +1026,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 has some free balance assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 11).own, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); @@ -1054,7 +1055,7 @@ fn reward_destination_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1077,10 +1078,13 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![], } ); + // (era 0, page 0) is claimed + assert_eq!(Staking::claimed_rewards(0, &11), vec![0]); + // Change RewardDestination to Stash >::insert(&11, RewardDestination::Stash); @@ -1095,6 +1099,8 @@ fn reward_destination_works() { 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); + // Record this value + let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; // Check that amount at stake is NOT increased assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1103,10 +1109,13 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0, 1], + legacy_claimed_rewards: bounded_vec![], } ); + // (era 1, page 0) is claimed + assert_eq!(Staking::claimed_rewards(1, &11), vec![0]); + // Change RewardDestination to Controller >::insert(&11, RewardDestination::Controller); @@ -1123,7 +1132,7 @@ fn reward_destination_works() { // Check that RewardDestination is 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); + assert_eq!(Balances::free_balance(11), recorded_stash_balance + total_payout_2); // Check that amount at stake is NOT increased assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1132,9 +1141,12 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0, 1, 2], + legacy_claimed_rewards: bounded_vec![], } ); + + // (era 2, page 0) is claimed + assert_eq!(Staking::claimed_rewards(2, &11), vec![0]); }); } @@ -1159,7 +1171,7 @@ fn validator_payment_prefs_work() { // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); - let exposure_1 = Staking::eras_stakers(active_era(), 11); + let exposure_1 = Staking::eras_stakers(active_era(), &11); Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(2); @@ -1192,7 +1204,7 @@ fn bond_extra_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1209,7 +1221,7 @@ fn bond_extra_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1223,7 +1235,7 @@ fn bond_extra_works() { total: 1000000, active: 1000000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); }); @@ -1261,11 +1273,11 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000, own: 1000, others: vec![] } ); @@ -1279,12 +1291,12 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Exposure is a snapshot! only updated after the next era update. assert_ne!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } ); @@ -1300,12 +1312,12 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Exposure is now updated. assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } ); @@ -1318,7 +1330,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1331,7 +1343,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1347,7 +1359,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1363,7 +1375,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 100, active: 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); }) @@ -1466,7 +1478,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1485,7 +1497,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1498,7 +1510,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1511,7 +1523,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1524,7 +1536,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1537,7 +1549,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1552,7 +1564,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1565,7 +1577,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); }) @@ -1592,7 +1604,7 @@ fn rebond_is_fifo() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1607,7 +1619,7 @@ fn rebond_is_fifo() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1625,7 +1637,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1644,7 +1656,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1660,7 +1672,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); }) @@ -1689,7 +1701,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1702,7 +1714,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 200, unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Event emitted should be correct @@ -1717,7 +1729,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Event emitted should be correct, only 800 @@ -1737,15 +1749,15 @@ fn reward_to_stake_works() { // Confirm account 10 and 20 are validators assert!(>::contains_key(&11) && >::contains_key(&21)); - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 2000); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); // Give the man some money. let _ = Balances::make_free_balance_be(&10, 1000); let _ = Balances::make_free_balance_be(&20, 1000); // Bypass logic and change current exposure - ErasStakers::::insert(0, 21, Exposure { total: 69, own: 69, others: vec![] }); + EraInfo::::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); >::insert( &20, StakingLedgerInspect { @@ -1753,7 +1765,7 @@ fn reward_to_stake_works() { total: 69, active: 69, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1766,21 +1778,18 @@ fn reward_to_stake_works() { mock::start_active_era(1); mock::make_all_reward_payment(0); - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 2000); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); let _11_balance = Balances::free_balance(&11); - let _21_balance = Balances::free_balance(&21); - assert_eq!(_11_balance, 1000 + total_payout_0 / 2); - assert_eq!(_21_balance, 2000 + total_payout_0 / 2); // Trigger another new era as the info are frozen before the era start. mock::start_active_era(2); // -- new infos - assert_eq!(Staking::eras_stakers(active_era(), 11).total, _11_balance); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, _21_balance); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000 + total_payout_0 / 2); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000 + total_payout_0 / 2); }); } @@ -1807,7 +1816,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::::new(11, 5, bounded_vec![])); + Ledger::::insert(11, StakingLedger::::new(11, 5)); // reap-able assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); @@ -1901,8 +1910,8 @@ fn wrong_vote_is_moot() { assert_eq_uvec!(validator_controllers(), vec![21, 11]); // our new voter is taken into account - assert!(Staking::eras_stakers(active_era(), 11).others.iter().any(|i| i.who == 61)); - assert!(Staking::eras_stakers(active_era(), 21).others.iter().any(|i| i.who == 61)); + assert!(Staking::eras_stakers(active_era(), &11).others.iter().any(|i| i.who == 61)); + assert!(Staking::eras_stakers(active_era(), &21).others.iter().any(|i| i.who == 61)); }); } @@ -1935,7 +1944,7 @@ fn bond_with_no_staked_value() { active: 0, total: 5, unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -1989,9 +1998,9 @@ fn bond_with_little_staked_value_bounded() { mock::start_active_era(1); mock::make_all_reward_payment(0); - // 2 is elected. + // 1 is elected. assert_eq_uvec!(validator_controllers(), vec![21, 11, 1]); - assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0); + assert_eq!(Staking::eras_stakers(active_era(), &2).total, 0); // Old ones are rewarded. assert_eq_error_rate!( @@ -2009,7 +2018,7 @@ fn bond_with_little_staked_value_bounded() { mock::make_all_reward_payment(1); assert_eq_uvec!(validator_controllers(), vec![21, 11, 1]); - assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0); + assert_eq!(Staking::eras_stakers(active_era(), &2).total, 0); // 2 is now rewarded. assert_eq_error_rate!( @@ -2160,8 +2169,8 @@ fn phragmen_should_not_overflow() { assert_eq_uvec!(validator_controllers(), vec![3, 5]); // We can safely convert back to values within [u64, u128]. - assert!(Staking::eras_stakers(active_era(), 3).total > Votes::max_value() as Balance); - assert!(Staking::eras_stakers(active_era(), 5).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); }) } @@ -2185,10 +2194,9 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); - ErasStakers::::insert(0, 11, &exposure); - ErasStakersClipped::::insert(0, 11, exposure); + EraInfo::::set_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); // Set staker @@ -2198,9 +2206,9 @@ fn reward_validator_slashing_validator_does_not_overflow() { // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::default()).unwrap(); // Override exposure of 11 - ErasStakers::::insert( + EraInfo::::set_exposure( 0, - 11, + &11, Exposure { total: stake, own: 1, @@ -2211,7 +2219,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check slashing on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], @@ -2310,7 +2318,7 @@ fn offence_forces_new_era() { ExtBuilder::default().build_and_execute(|| { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(5)], @@ -2328,7 +2336,7 @@ fn offence_ensures_new_era_without_clobbering() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(5)], @@ -2346,7 +2354,7 @@ fn offence_deselects_validator_even_when_slash_is_zero() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2367,7 +2375,7 @@ fn slashing_performed_according_exposure() { // This test checks that slashing is performed according the exposure (or more precisely, // historical exposure), not the current balance. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Staking::eras_stakers(active_era(), 11).own, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Handle an offence with a historical exposure. on_offence_now( @@ -2393,7 +2401,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2416,7 +2424,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2432,7 +2440,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], // NOTE: A 100% slash here would clean up the account, causing de-registration. @@ -2459,11 +2467,11 @@ fn reporters_receive_their_slice() { // The reporters' reward is calculated from the total exposure. let initial_balance = 1125; - assert_eq!(Staking::eras_stakers(active_era(), 11).total, initial_balance); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1, 2], }], &[Perbill::from_percent(50)], @@ -2486,11 +2494,11 @@ fn subsequent_reports_in_same_span_pay_out_less() { // The reporters' reward is calculated from the total exposure. let initial_balance = 1125; - assert_eq!(Staking::eras_stakers(active_era(), 11).total, initial_balance); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }], &[Perbill::from_percent(20)], @@ -2503,7 +2511,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }], &[Perbill::from_percent(50)], @@ -2525,7 +2533,7 @@ fn invulnerables_are_not_slashed() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(21), 2000); - let exposure = Staking::eras_stakers(active_era(), 21); + let exposure = Staking::eras_stakers(active_era(), &21); let initial_balance = Staking::slashable_balance_of(&21); let nominator_balances: Vec<_> = @@ -2534,11 +2542,11 @@ fn invulnerables_are_not_slashed() { on_offence_now( &[ OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }, OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }, ], @@ -2568,7 +2576,7 @@ fn dont_slash_if_fraction_is_zero() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2589,7 +2597,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(50)], @@ -2601,7 +2609,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(25)], @@ -2612,7 +2620,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(60)], @@ -2634,7 +2642,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2646,7 +2654,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], @@ -2683,12 +2691,15 @@ fn garbage_collection_on_window_pruning() { assert_eq!(Balances::free_balance(11), 1000); let now = active_era(); - let exposure = Staking::eras_stakers(now, 11); + let exposure = Staking::eras_stakers(now, &11); assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( - &[OffenceDetails { offender: (11, Staking::eras_stakers(now, 11)), reporters: vec![] }], + &[OffenceDetails { + offender: (11, Staking::eras_stakers(now, &11)), + reporters: vec![], + }], &[Perbill::from_percent(10)], ); @@ -2723,14 +2734,14 @@ fn slashing_nominators_by_span_max() { assert_eq!(Balances::free_balance(101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); - let exposure_11 = Staking::eras_stakers(active_era(), 11); - let exposure_21 = Staking::eras_stakers(active_era(), 21); + let exposure_11 = Staking::eras_stakers(active_era(), &11); + let exposure_21 = Staking::eras_stakers(active_era(), &21); let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2757,7 +2768,7 @@ fn slashing_nominators_by_span_max() { // second slash: higher era, higher value, same span. on_offence_in_era( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(30)], @@ -2779,7 +2790,7 @@ fn slashing_nominators_by_span_max() { // in-era value, but lower slash value than slash 2. on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(20)], @@ -2814,7 +2825,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2837,7 +2848,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2861,7 +2872,7 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -2869,7 +2880,7 @@ fn deferred_slashes_are_deferred() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2920,7 +2931,7 @@ fn retroactive_deferred_slashes_two_eras_before() { assert_eq!(BondingDuration::get(), 3); mock::start_active_era(1); - let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), &11); mock::start_active_era(3); @@ -2956,7 +2967,7 @@ fn retroactive_deferred_slashes_one_before() { assert_eq!(BondingDuration::get(), 3); mock::start_active_era(1); - let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), &11); // unbond at slash era. mock::start_active_era(2); @@ -3004,12 +3015,12 @@ fn staker_cannot_bail_deferred_slash() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -3028,7 +3039,7 @@ fn staker_cannot_bail_deferred_slash() { active: 0, total: 500, stash: 101, - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], unlocking: bounded_vec![UnlockChunk { era: 4u32, value: 500 }], } ); @@ -3078,7 +3089,7 @@ fn remove_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -3154,7 +3165,7 @@ fn remove_multi_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); on_offence_now( @@ -3164,7 +3175,7 @@ fn remove_multi_deferred() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -3529,8 +3540,9 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { mock::start_active_era(1); Pallet::::reward_by_ids(vec![(11, 1)]); - // Change total issuance in order to modify total payout + // Increase total token issuance to affect the total payout. let _ = Balances::deposit_creating(&999, 1_000_000_000); + // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); assert!(total_payout_1 != total_payout_0); @@ -3538,7 +3550,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { mock::start_active_era(2); Pallet::::reward_by_ids(vec![(11, 1)]); - // Change total issuance in order to modify total payout + // Increase total token issuance to affect the total payout. let _ = Balances::deposit_creating(&999, 1_000_000_000); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); @@ -3555,19 +3567,19 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Last kept is 1: assert!(current_era - HistoryDepth::get() == 1); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0), // Fail: Era out of history Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0)); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0), // Fail: Double claim Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, active_era, 0), // Fail: Era not finished yet Error::::InvalidEraToReward.with_weight(err_weight) ); @@ -3593,7 +3605,7 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); on_offence_now( @@ -3672,9 +3684,10 @@ fn six_session_delay() { } #[test] -fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { +fn test_nominators_over_max_exposure_page_size_are_rewarded() { ExtBuilder::default().build_and_execute(|| { - for i in 0..=<::MaxNominatorRewardedPerValidator as Get<_>>::get() { + // bond one nominator more than the max exposure page size to validator 11. + for i in 0..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; Balances::make_free_balance_be(&stash, balance); @@ -3694,29 +3707,73 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( mock::start_active_era(2); mock::make_all_reward_payment(1); - // Assert only nominators from 1 to Max are rewarded - for i in 0..=<::MaxNominatorRewardedPerValidator as Get<_>>::get() { + // Assert nominators from 1 to Max are rewarded + let mut i: u32 = 0; + while i < MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - if stash == 10_000 { - assert!(Balances::free_balance(&stash) == balance); - } else { - assert!(Balances::free_balance(&stash) > balance); - } + assert!(Balances::free_balance(&stash) > balance); + i += 1; } + + // Assert overflowing nominators from page 1 are also rewarded + let stash = 10_000 + i as AccountId; + assert!(Balances::free_balance(&stash) > (10_000 + i) as Balance); }); } #[test] -fn test_payout_stakers() { - // Test that payout_stakers work in general, including that only the top - // `T::MaxNominatorRewardedPerValidator` nominators are rewarded. +fn test_nominators_are_rewarded_for_all_exposure_page() { + ExtBuilder::default().build_and_execute(|| { + // 3 pages of exposure + let nominator_count = 2 * MaxExposurePageSize::get() + 1; + + for i in 0..nominator_count { + let stash = 10_000 + i as AccountId; + let balance = 10_000 + i as Balance; + Balances::make_free_balance_be(&stash, balance); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(stash), + balance, + RewardDestination::Stash + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(stash), vec![11])); + } + mock::start_active_era(1); + + Pallet::::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + + mock::start_active_era(2); + mock::make_all_reward_payment(1); + + assert_eq!(EraInfo::::get_page_count(1, &11), 3); + + // Assert all nominators are rewarded according to their stake + for i in 0..nominator_count { + // balance of the nominator after the reward payout. + let current_balance = Balances::free_balance(&((10000 + i) as AccountId)); + // balance of the nominator in the previous iteration. + let previous_balance = Balances::free_balance(&((10000 + i - 1) as AccountId)); + // balance before the reward. + let original_balance = 10_000 + i as Balance; + + assert!(current_balance > original_balance); + // since the stake of the nominator is increasing for each iteration, the final balance + // after the reward should also be higher than the previous iteration. + assert!(current_balance > previous_balance); + } + }); +} + +#[test] +fn test_multi_page_payout_stakers_by_page() { + // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1000; // Track the exposure of the validator and all nominators. let mut total_exposure = balance; - // Track the exposure of the validator and the nominators that will get paid out. - let mut payout_exposure = balance; // Create a validator: bond_validator(11, balance); // Default(64) assert_eq!(Validators::::count(), 1); @@ -3725,54 +3782,86 @@ fn test_payout_stakers() { for i in 0..100 { let bond_amount = balance + i as Balance; bond_nominator(1000 + i, bond_amount, vec![11]); + // with multi page reward payout, payout exposure is same as total exposure. total_exposure += bond_amount; - if i >= 36 { - payout_exposure += bond_amount; - }; } - let payout_exposure_part = Perbill::from_rational(payout_exposure, total_exposure); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); + // Since `MaxExposurePageSize = 64`, there are two pages of validator exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); - let actual_paid_out = payout_exposure_part * payout; - mock::start_active_era(2); + // verify the exposures are calculated correctly. + let actual_exposure_0 = EraInfo::::get_paged_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_0.total(), total_exposure); + assert_eq!(actual_exposure_0.own(), 1000); + assert_eq!(actual_exposure_0.others().len(), 64); + let actual_exposure_1 = EraInfo::::get_paged_exposure(1, &11, 1).unwrap(); + assert_eq!(actual_exposure_1.total(), total_exposure); + // own stake is only included once in the first page + assert_eq!(actual_exposure_1.own(), 0); + assert_eq!(actual_exposure_1.others().len(), 100 - 64); + let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); - assert_eq_error_rate!( - Balances::total_issuance(), - pre_payout_total_issuance + actual_paid_out, - 1 - ); - assert!(RewardOnUnbalanceWasCalled::get()); + System::reset_events(); + + let controller_balance_before_p0_payout = Balances::free_balance(&11); + // Payout rewards for first exposure page + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); - // `Rewarded` events are being executed. + // verify `Rewarded` events are being executed assert!(matches!( staking_events_since_last_call().as_slice(), &[ .., - Event::Rewarded { stash: 1037, dest: RewardDestination::Controller, amount: 108 }, - Event::Rewarded { stash: 1036, dest: RewardDestination::Controller, amount: 108 } + Event::Rewarded { stash: 1063, dest: RewardDestination::Controller, amount: 111 }, + Event::Rewarded { stash: 1064, dest: RewardDestination::Controller, amount: 111 }, ] )); + let controller_balance_after_p0_payout = Balances::free_balance(&11); + + // verify rewards have been paid out but still some left + assert!(Balances::total_issuance() > pre_payout_total_issuance); + assert!(Balances::total_issuance() < pre_payout_total_issuance + payout); + + // verify the validator has been rewarded + assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout); + + // Payout the second and last page of nominators + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 1)); + + // verify `Rewarded` events are being executed for the second page. + let events = staking_events_since_last_call(); + assert!(matches!( + events.as_slice(), + &[ + Event::PayoutStarted { era_index: 1, validator_stash: 11 }, + Event::Rewarded { stash: 1065, dest: RewardDestination::Controller, amount: 111 }, + Event::Rewarded { stash: 1066, dest: RewardDestination::Controller, amount: 111 }, + .. + ] + )); + // verify the validator was not rewarded the second time + assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + + // verify all rewards have been paid out + assert_eq_error_rate!(Balances::total_issuance(), pre_payout_total_issuance + payout, 2); + assert!(RewardOnUnbalanceWasCalled::get()); + // Top 64 nominators of validator 11 automatically paid out, including the validator - // Validator payout goes to controller. assert!(Balances::free_balance(&11) > balance); - for i in 36..100 { + for i in 0..100 { assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); } - // The bottom 36 do not - for i in 0..36 { - assert_eq!(Balances::free_balance(&(1000 + i)), balance + i as Balance); - } - // We track rewards in `claimed_rewards` vec + // verify we no longer track rewards in `legacy_claimed_rewards` vec assert_eq!( Staking::ledger(11.into()).unwrap(), StakingLedgerInspect { @@ -3780,30 +3869,207 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![1] + legacy_claimed_rewards: bounded_vec![] } ); + // verify rewards are tracked to prevent double claims + let ledger = Staking::ledger(11.into()); + for page in 0..EraInfo::::get_page_count(1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + ledger.as_ref().unwrap(), + &11, + page + ), + true + ); + } + for i in 3..16 { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); - let actual_paid_out = payout_exposure_part * payout; let pre_payout_total_issuance = Balances::total_issuance(); mock::start_active_era(i); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1)); + mock::make_all_reward_payment(i - 1); assert_eq_error_rate!( Balances::total_issuance(), - pre_payout_total_issuance + actual_paid_out, - 1 + pre_payout_total_issuance + payout, + 2 ); assert!(RewardOnUnbalanceWasCalled::get()); + + // verify we track rewards for each era and page + for page in 0..EraInfo::::get_page_count(i - 1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + i - 1, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + page + ), + true + ); + } + } + + assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); + + let last_era = 99; + let history_depth = HistoryDepth::get(); + let last_reward_era = last_era - 1; + let first_claimable_reward_era = last_era - history_depth; + for i in 16..=last_era { + Staking::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(i); + } + + // verify we clean up history as we go + for era in 0..15 { + assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + } + + // verify only page 0 is marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era, + 0 + )); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era, + 1 + )); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + + // verify only page 0 is marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 0 + )); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 1 + )); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); + + // Out of order claims works. + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 69, 0)); + assert_eq!(Staking::claimed_rewards(69, &11), vec![0]); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 23, 1)); + assert_eq!(Staking::claimed_rewards(23, &11), vec![1]); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 42, 0)); + assert_eq!(Staking::claimed_rewards(42, &11), vec![0]); + }); +} + +#[test] +fn test_multi_page_payout_stakers_backward_compatible() { + // Test that payout_stakers work in general and that it pays the correct amount of reward. + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1000; + // Track the exposure of the validator and all nominators. + let mut total_exposure = balance; + // Create a validator: + bond_validator(11, balance); // Default(64) + assert_eq!(Validators::::count(), 1); + + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); + + // Create nominators, targeting stash of validators + for i in 0..100 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, bond_amount, vec![11]); + // with multi page reward payout, payout exposure is same as total exposure. + total_exposure += bond_amount; } - // We track rewards in `claimed_rewards` vec + mock::start_active_era(1); + Staking::reward_by_ids(vec![(11, 1)]); + + // Since `MaxExposurePageSize = 64`, there are two pages of validator exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(2); + + // verify the exposures are calculated correctly. + let actual_exposure_0 = EraInfo::::get_paged_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_0.total(), total_exposure); + assert_eq!(actual_exposure_0.own(), 1000); + assert_eq!(actual_exposure_0.others().len(), 64); + let actual_exposure_1 = EraInfo::::get_paged_exposure(1, &11, 1).unwrap(); + assert_eq!(actual_exposure_1.total(), total_exposure); + // own stake is only included once in the first page + assert_eq!(actual_exposure_1.own(), 0); + assert_eq!(actual_exposure_1.others().len(), 100 - 64); + + let pre_payout_total_issuance = Balances::total_issuance(); + RewardOnUnbalanceWasCalled::set(false); + + let controller_balance_before_p0_payout = Balances::free_balance(&11); + // Payout rewards for first exposure page + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + // page 0 is claimed + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + let controller_balance_after_p0_payout = Balances::free_balance(&11); + + // verify rewards have been paid out but still some left + assert!(Balances::total_issuance() > pre_payout_total_issuance); + assert!(Balances::total_issuance() < pre_payout_total_issuance + payout); + + // verify the validator has been rewarded + assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout); + + // This should payout the second and last page of nominators + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + + // cannot claim any more pages + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // verify the validator was not rewarded the second time + assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + + // verify all rewards have been paid out + assert_eq_error_rate!(Balances::total_issuance(), pre_payout_total_issuance + payout, 2); + assert!(RewardOnUnbalanceWasCalled::get()); + + // verify all nominators of validator 11 are paid out, including the validator + // Validator payout goes to controller. + assert!(Balances::free_balance(&11) > balance); + for i in 0..100 { + assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); + } + + // verify we no longer track rewards in `legacy_claimed_rewards` vec + let ledger = Staking::ledger(11.into()); assert_eq!( Staking::ledger(11.into()).unwrap(), StakingLedgerInspect { @@ -3811,14 +4077,60 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (1..=14).collect::>().try_into().unwrap() + legacy_claimed_rewards: bounded_vec![] } ); + // verify rewards are tracked to prevent double claims + for page in 0..EraInfo::::get_page_count(1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + ledger.as_ref().unwrap(), + &11, + page + ), + true + ); + } + + for i in 3..16 { + Staking::reward_by_ids(vec![(11, 1)]); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + let pre_payout_total_issuance = Balances::total_issuance(); + + mock::start_active_era(i); + RewardOnUnbalanceWasCalled::set(false); + mock::make_all_reward_payment(i - 1); + assert_eq_error_rate!( + Balances::total_issuance(), + pre_payout_total_issuance + payout, + 2 + ); + assert!(RewardOnUnbalanceWasCalled::get()); + + // verify we track rewards for each era and page + for page in 0..EraInfo::::get_page_count(i - 1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + i - 1, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + page + ), + true + ); + } + } + + assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); + let last_era = 99; let history_depth = HistoryDepth::get(); - let expected_last_reward_era = last_era - 1; - let expected_start_reward_era = last_era - history_depth; + let last_reward_era = last_era - 1; + let first_claimable_reward_era = last_era - history_depth; for i in 16..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. @@ -3826,48 +4138,125 @@ fn test_payout_stakers() { mock::start_active_era(i); } - // We clean it up as history passes + // verify we clean up history as we go + for era in 0..15 { + assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + } + + // verify only page 0 is marked as claimed assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_start_reward_era + first_claimable_reward_era )); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_last_reward_era + first_claimable_reward_era, )); - assert_eq!( - 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] - } + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + + // change order and verify only page 1 is marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 1 + )); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1]); + + // verify page 0 is claimed even when explicit page is not passed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era,)); + + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1, 0]); + + // cannot claim any more pages + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era), + Error::::AlreadyClaimed.with_weight(err_weight) ); + // Create 4 nominator pages + for i in 100..200 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, bond_amount, vec![11]); + } + + let test_era = last_era + 1; + mock::start_active_era(test_era); + + Staking::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(test_era + 1); + // Out of order claims works. - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69)); - 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.into()).unwrap(), - StakingLedgerInspect { - stash: 11, - total: 1000, - active: 1000, - unlocking: Default::default(), - claimed_rewards: bounded_vec![ - expected_start_reward_era, - 23, - 42, - 69, - expected_last_reward_era - ] - } + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2]); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0]); + + // cannot claim page 2 again + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2), + Error::::AlreadyClaimed.with_weight(err_weight) ); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1]); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1, 3]); + }); +} + +#[test] +fn test_page_count_and_size() { + // Test that payout_stakers work in general and that it pays the correct amount of reward. + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1000; + // Track the exposure of the validator and all nominators. + // Create a validator: + bond_validator(11, balance); // Default(64) + assert_eq!(Validators::::count(), 1); + + // Create nominators, targeting stash of validators + for i in 0..100 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, bond_amount, vec![11]); + } + + mock::start_active_era(1); + + // Since max exposure page size is 64, 2 pages of nominators are created. + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + + // first page has 64 nominators + assert_eq!(EraInfo::::get_paged_exposure(1, &11, 0).unwrap().others().len(), 64); + // second page has 36 nominators + assert_eq!(EraInfo::::get_paged_exposure(1, &11, 1).unwrap().others().len(), 36); + + // now lets decrease page size + MaxExposurePageSize::set(32); + mock::start_active_era(2); + // now we expect 4 pages. + assert_eq!(EraInfo::::get_page_count(2, &11), 4); + // first 3 pages have 32 nominators each + assert_eq!(EraInfo::::get_paged_exposure(2, &11, 0).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_paged_exposure(2, &11, 1).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_paged_exposure(2, &11, 2).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_paged_exposure(2, &11, 3).unwrap().others().len(), 4); + + // now lets decrease page size even more + MaxExposurePageSize::set(5); + mock::start_active_era(3); + + // now we expect the max 20 pages (100/5). + assert_eq!(EraInfo::::get_page_count(3, &11), 20); }); } @@ -3897,12 +4286,12 @@ fn payout_stakers_handles_basic_errors() { // Wrong Era, too big assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0), Error::::InvalidEraToReward.with_weight(err_weight) ); // Wrong Staker assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 10, 1, 0), Error::::NotStash.with_weight(err_weight) ); @@ -3922,33 +4311,137 @@ fn payout_stakers_handles_basic_errors() { // to payout era starting from expected_start_reward_era=19 through // expected_last_reward_era=98 (80 total eras), but not 18 or 99. assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era - 1), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era - 1, + 0 + ), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era + 1), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + 1, + 0 + ), Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, - expected_start_reward_era + expected_start_reward_era, + 0 )); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 0 + )); + + // can call page 1 + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, - expected_last_reward_era + expected_last_reward_era, + 1 )); // Can't claim again assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era, + 0 + ), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + assert_noop!( + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 0 + ), Error::::AlreadyClaimed.with_weight(err_weight) ); + assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 1 + ), Error::::AlreadyClaimed.with_weight(err_weight) ); + + // invalid page + assert_noop!( + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 2 + ), + Error::::InvalidPage.with_weight(err_weight) + ); + }); +} + +#[test] +fn test_commission_paid_across_pages() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1; + let commission = 50; + // Create a validator: + bond_validator(11, balance); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(11), + ValidatorPrefs { commission: Perbill::from_percent(commission), blocked: false } + )); + assert_eq!(Validators::::count(), 1); + + // Create nominators, targeting stash of validators + for i in 0..200 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, bond_amount, vec![11]); + } + + mock::start_active_era(1); + Staking::reward_by_ids(vec![(11, 1)]); + + // Since `MaxExposurePageSize = 64`, there are four pages of validator + // exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 4); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(2); + + let initial_balance = Balances::free_balance(&11); + // Payout rewards for first exposure page + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); + + let controller_balance_after_p0_payout = Balances::free_balance(&11); + + // some commission is paid + assert!(initial_balance < controller_balance_after_p0_payout); + + // payout all pages + for i in 1..4 { + let before_balance = Balances::free_balance(&11); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); + let after_balance = Balances::free_balance(&11); + // some commission is paid for every page + assert!(before_balance < after_balance); + } + + assert_eq_error_rate!(Balances::free_balance(&11), initial_balance + payout / 2, 1,); }); } @@ -3957,8 +4450,7 @@ fn payout_stakers_handles_weight_refund() { // Note: this test relies on the assumption that `payout_stakers_alive_staked` is solely used by // `payout_stakers` to calculate the weight of each payout op. ExtBuilder::default().has_stakers(false).build_and_execute(|| { - let max_nom_rewarded = - <::MaxNominatorRewardedPerValidator as Get<_>>::get(); + let max_nom_rewarded = MaxExposurePageSize::get(); // Make sure the configured value is meaningful for our use. assert!(max_nom_rewarded >= 4); let half_max_nom_rewarded = max_nom_rewarded / 2; @@ -3994,7 +4486,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(2); // Collect payouts when there are no nominators - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 1, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4007,7 +4503,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(3); // Collect payouts for an era where the validator did not receive any points. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 2, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4020,7 +4520,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(4); // Collect payouts when the validator has `half_max_nom_rewarded` nominators. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 3, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4043,14 +4547,22 @@ fn payout_stakers_handles_weight_refund() { start_active_era(6); // Collect payouts when the validator had `half_max_nom_rewarded` nominators. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 5, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 5, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); @@ -4060,7 +4572,7 @@ fn payout_stakers_handles_weight_refund() { } #[test] -fn bond_during_era_correctly_populates_claimed_rewards() { +fn bond_during_era_does_not_populate_legacy_claimed_rewards() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { // Era = None bond_validator(9, 1000); @@ -4071,7 +4583,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); mock::start_active_era(5); @@ -4083,13 +4595,12 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (0..5).collect::>().try_into().unwrap(), + legacy_claimed_rewards: bounded_vec![], } ); // make sure only era upto history depth is stored let current_era = 99; - let last_reward_era = 99 - HistoryDepth::get(); mock::start_active_era(current_era); bond_validator(13, 1000); assert_eq!( @@ -4099,10 +4610,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era) - .collect::>() - .try_into() - .unwrap(), + legacy_claimed_rewards: Default::default(), } ); }); @@ -4131,7 +4639,7 @@ fn offences_weight_calculated_correctly() { >, > = (1..10) .map(|i| OffenceDetails { - offender: (i, Staking::eras_stakers(active_era(), i)), + offender: (i, Staking::eras_stakers(active_era(), &i)), reporters: vec![], }) .collect(); @@ -4147,7 +4655,7 @@ fn offences_weight_calculated_correctly() { // On Offence with one offenders, Applied let one_offender = [OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }]; @@ -4204,7 +4712,7 @@ fn payout_creates_controller() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(controller), 11, 1)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Controller is created assert!(Balances::free_balance(controller) > 0); @@ -4232,7 +4740,7 @@ fn payout_to_any_account_works() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful assert!(Balances::free_balance(42) > 0); @@ -4355,7 +4863,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 11 * 1000, active: 11 * 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4369,7 +4877,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 11 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4395,7 +4903,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 11 * 1000, active: 11 * 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4409,7 +4917,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 11 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4436,7 +4944,7 @@ fn do_not_die_when_active_is_ed() { total: 1000 * ed, active: 1000 * ed, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4453,7 +4961,7 @@ fn do_not_die_when_active_is_ed() { total: ed, active: ed, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); }) @@ -5528,7 +6036,7 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { let unlocking = bounded_vec![c(1, 10), c(2, 10)]; // Given - let mut ledger = StakingLedger::::new(123, 20, bounded_vec![]); + let mut ledger = StakingLedger::::new(123, 20); ledger.total = 40; ledger.unlocking = unlocking; @@ -5542,7 +6050,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::::new(123, 10, bounded_vec![]); + let mut ledger = StakingLedger::::new(123, 10); assert_eq!(BondingDuration::get(), 3); // When we slash a ledger with no unlocking chunks @@ -5758,149 +6266,6 @@ fn proportional_ledger_slash_works() { ); } -#[test] -fn pre_bonding_era_cannot_be_claimed() { - // Verifies initial conditions of mock - ExtBuilder::default().nominate(false).build_and_execute(|| { - let history_depth = HistoryDepth::get(); - // jump to some era above history_depth - let mut current_era = history_depth + 10; - let last_reward_era = current_era - 1; - let start_reward_era = current_era - history_depth; - - // put some money in stash=3 and controller=4. - for i in 3..5 { - let _ = Balances::make_free_balance_be(&i, 2000); - } - - mock::start_active_era(current_era); - - // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Controller)); - - let claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(3.into()).unwrap(), - StakingLedgerInspect { - stash: 3, - total: 1500, - active: 1500, - unlocking: Default::default(), - claimed_rewards, - } - ); - - // start next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(3), 3, current_era - 1)); - - // consumed weight for all payout_stakers dispatches that fail - let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); - // cannot claim rewards for an era before bonding occured as it is - // already marked as claimed. - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(3), 3, current_era - 2), - Error::::AlreadyClaimed.with_weight(err_weight) - ); - - // decoding will fail now since Staking Ledger is in corrupt state - HistoryDepth::set(history_depth - 1); - assert!(Staking::ledger(4.into()).is_err()); - - // make sure stakers still cannot claim rewards that they are not meant to - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(3), 3, current_era - 2), - Error::::NotController - ); - - // fix the corrupted state for post conditions check - HistoryDepth::set(history_depth); - }); -} - -#[test] -fn reducing_history_depth_abrupt() { - // Verifies initial conditions of mock - ExtBuilder::default().nominate(false).build_and_execute(|| { - let original_history_depth = HistoryDepth::get(); - let mut current_era = original_history_depth + 10; - let last_reward_era = current_era - 1; - let start_reward_era = current_era - original_history_depth; - - // put some money in (stash, controller)=(3,3),(5,5). - for i in 3..7 { - let _ = Balances::make_free_balance_be(&i, 2000); - } - - // start current era - mock::start_active_era(current_era); - - // add a new candidate for being a staker. account 3 controlled by 3. - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Controller)); - - // all previous era before the bonding action should be marked as - // claimed. - let claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(3.into()).unwrap(), - StakingLedgerInspect { - stash: 3, - total: 1500, - active: 1500, - unlocking: Default::default(), - claimed_rewards, - } - ); - - // next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(3), 3, current_era - 1)); - - // next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // history_depth reduced without migration - let history_depth = original_history_depth - 1; - HistoryDepth::set(history_depth); - // claiming reward does not work anymore - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(3), 3, current_era - 1), - Error::::NotController - ); - - // new stakers can still bond - assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1200, RewardDestination::Controller)); - - // new staking ledgers created will be bounded by the current history depth - let last_reward_era = current_era - 1; - let start_reward_era = current_era - history_depth; - let claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(5.into()).unwrap(), - StakingLedgerInspect { - stash: 5, - total: 1200, - active: 1200, - unlocking: Default::default(), - claimed_rewards, - } - ); - - // fix the corrupted state for post conditions check - HistoryDepth::set(original_history_depth); - }); -} - #[test] fn reducing_max_unlocking_chunks_abrupt() { // Concern is on validators only @@ -6047,6 +6412,282 @@ fn set_min_commission_works_with_admin_origin() { }) } +#[test] +fn can_page_exposure() { + let mut others: Vec> = vec![]; + let mut total_stake: Balance = 0; + // 19 nominators + for i in 1..20 { + let individual_stake: Balance = 100 * i as Balance; + others.push(IndividualExposure { who: i, value: individual_stake }); + total_stake += individual_stake; + } + let own_stake: Balance = 500; + total_stake += own_stake; + assert_eq!(total_stake, 19_500); + // build full exposure set + let exposure: Exposure = + Exposure { total: total_stake, own: own_stake, others }; + + // when + let (exposure_metadata, exposure_page): ( + PagedExposureMetadata, + Vec>, + ) = exposure.clone().into_pages(3); + + // then + // 7 pages of nominators. + assert_eq!(exposure_page.len(), 7); + assert_eq!(exposure_metadata.page_count, 7); + // first page stake = 100 + 200 + 300 + assert!(matches!(exposure_page[0], ExposurePage { page_total: 600, .. })); + // second page stake = 0 + 400 + 500 + 600 + assert!(matches!(exposure_page[1], ExposurePage { page_total: 1500, .. })); + // verify overview has the total + assert_eq!(exposure_metadata.total, 19_500); + // verify total stake is same as in the original exposure. + assert_eq!( + exposure_page.iter().map(|a| a.page_total).reduce(|a, b| a + b).unwrap(), + 19_500 - exposure_metadata.own + ); + // verify own stake is correct + assert_eq!(exposure_metadata.own, 500); + // verify number of nominators are same as in the original exposure. + assert_eq!(exposure_page.iter().map(|a| a.others.len()).reduce(|a, b| a + b).unwrap(), 19); + assert_eq!(exposure_metadata.nominator_count, 19); +} + +#[test] +fn should_retain_era_info_only_upto_history_depth() { + ExtBuilder::default().build_and_execute(|| { + // remove existing exposure + Pallet::::clear_era_information(0); + let validator_stash = 10; + + for era in 0..4 { + ClaimedRewards::::insert(era, &validator_stash, vec![0, 1, 2]); + for page in 0..3 { + ErasStakersPaged::::insert( + (era, &validator_stash, page), + ExposurePage { page_total: 100, others: vec![] }, + ); + } + } + + for i in 0..4 { + // Count of entries remaining in ClaimedRewards = total - cleared_count + assert_eq!(ClaimedRewards::::iter().count(), (4 - i)); + // 1 claimed_rewards entry for each era + assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 1); + // 3 entries (pages) for each era + assert_eq!(ErasStakersPaged::::iter_prefix((i as EraIndex,)).count(), 3); + + // when clear era info + Pallet::::clear_era_information(i as EraIndex); + + // then all era entries are cleared + assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 0); + assert_eq!(ErasStakersPaged::::iter_prefix((i as EraIndex,)).count(), 0); + } + }); +} + +#[test] +fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // Create a validator: + bond_validator(11, 1000); + + // reward validator for next 2 eras + mock::start_active_era(1); + Pallet::::reward_by_ids(vec![(11, 1)]); + mock::start_active_era(2); + Pallet::::reward_by_ids(vec![(11, 1)]); + mock::start_active_era(3); + + //verify rewards are not claimed + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + 0 + ), + false + ); + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 2, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + 0 + ), + false + ); + + // assume reward claim for era 1 was stored in legacy storage + Ledger::::insert( + 11, + StakingLedgerInspect { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + + // verify rewards for era 1 cannot be claimed + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0), + Error::::AlreadyClaimed + .with_weight(::WeightInfo::payout_stakers_alive_staked(0)), + ); + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + 0 + ), + true + ); + + // verify rewards for era 2 can be claimed + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0)); + assert_eq!( + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 2, + Staking::ledger(11.into()).as_ref().unwrap(), + &11, + 0 + ), + true + ); + // but the new claimed rewards for era 2 is not stored in legacy storage + assert_eq!( + Ledger::::get(11).unwrap(), + StakingLedgerInspect { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + // instead it is kept in `ClaimedRewards` + assert_eq!(ClaimedRewards::::get(2, 11), vec![0]); + }); +} + +#[test] +fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // case 1: exposure exist in clipped. + // set page cap to 10 + MaxExposurePageSize::set(10); + bond_validator(11, 1000); + let mut expected_individual_exposures: Vec> = vec![]; + let mut total_exposure: Balance = 0; + // 1st exposure page + for i in 0..10 { + let who = 1000 + i; + let value = 1000 + i as Balance; + bond_nominator(who, value, vec![11]); + expected_individual_exposures.push(IndividualExposure { who, value }); + total_exposure += value; + } + + for i in 10..15 { + let who = 1000 + i; + let value = 1000 + i as Balance; + bond_nominator(who, value, vec![11]); + expected_individual_exposures.push(IndividualExposure { who, value }); + total_exposure += value; + } + + mock::start_active_era(1); + // reward validator for current era + Pallet::::reward_by_ids(vec![(11, 1)]); + + // start new era + mock::start_active_era(2); + // verify exposure for era 1 is stored in paged storage, that each exposure is stored in + // one and only one page, and no exposure is repeated. + let actual_exposure_page_0 = ErasStakersPaged::::get((1, 11, 0)).unwrap(); + let actual_exposure_page_1 = ErasStakersPaged::::get((1, 11, 1)).unwrap(); + expected_individual_exposures.iter().for_each(|exposure| { + assert!( + actual_exposure_page_0.others.contains(exposure) || + actual_exposure_page_1.others.contains(exposure) + ); + }); + assert_eq!( + expected_individual_exposures.len(), + actual_exposure_page_0.others.len() + actual_exposure_page_1.others.len() + ); + // verify `EraInfo` returns page from paged storage + assert_eq!( + EraInfo::::get_paged_exposure(1, &11, 0).unwrap().others(), + &actual_exposure_page_0.others + ); + assert_eq!( + EraInfo::::get_paged_exposure(1, &11, 1).unwrap().others(), + &actual_exposure_page_1.others + ); + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + + // case 2: exposure exist in ErasStakers and ErasStakersClipped (legacy). + // delete paged storage and add exposure to clipped storage + >::remove((1, 11, 0)); + >::remove((1, 11, 1)); + >::remove(1, 11); + + >::insert( + 1, + 11, + Exposure { + total: total_exposure, + own: 1000, + others: expected_individual_exposures.clone(), + }, + ); + let mut clipped_exposure = expected_individual_exposures.clone(); + clipped_exposure.sort_by(|a, b| b.who.cmp(&a.who)); + clipped_exposure.truncate(10); + >::insert( + 1, + 11, + Exposure { total: total_exposure, own: 1000, others: clipped_exposure.clone() }, + ); + + // verify `EraInfo` returns exposure from clipped storage + let actual_exposure_paged = EraInfo::::get_paged_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_paged.others(), &clipped_exposure); + assert_eq!(actual_exposure_paged.own(), 1000); + assert_eq!(actual_exposure_paged.exposure_metadata.page_count, 1); + + let actual_exposure_full = EraInfo::::get_full_exposure(1, &11); + assert_eq!(actual_exposure_full.others, expected_individual_exposures); + assert_eq!(actual_exposure_full.own, 1000); + assert_eq!(actual_exposure_full.total, total_exposure); + + // for pages other than 0, clipped storage returns empty exposure + assert_eq!(EraInfo::::get_paged_exposure(1, &11, 1), None); + // page size is 1 for clipped storage + assert_eq!(EraInfo::::get_page_count(1, &11), 1); + + // payout for page 0 works + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); + // payout for page 1 fails + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 1), + Error::::InvalidPage + .with_weight(::WeightInfo::payout_stakers_alive_staked(0)) + ); + }); +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; @@ -6076,7 +6717,7 @@ mod staking_interface { ExtBuilder::default().build_and_execute(|| { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], @@ -6217,7 +6858,7 @@ mod ledger { assert!(ledger.clone().bond(reward_dest).is_err()); // once bonded, update works as expected. - ledger.claimed_rewards = bounded_vec![1]; + ledger.legacy_claimed_rewards = bounded_vec![1]; assert_ok!(ledger.update()); }) } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index f2c65e677ca..ad6dbccde9f 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/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_staking +//! Autogenerated weights for `pallet_staking` //! //! 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-10-31, 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-yprdrvc7-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_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/staking/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_staking +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/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_staking. +/// Weight functions needed for `pallet_staking`. pub trait WeightInfo { fn bond() -> Weight; fn bond_extra() -> Weight; @@ -84,599 +81,615 @@ pub trait WeightInfo { fn set_min_commission() -> Weight; } -/// Weights for pallet_staking using the Substrate node and recommended hardware. +/// Weights for `pallet_staking` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `927` // Estimated: `4764` - // Minimum execution time: 53_983_000 picoseconds. - Weight::from_parts(55_296_000, 4764) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 42_811_000 picoseconds. + Weight::from_parts(44_465_000, 4764) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w: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: `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() -> Weight { // Proof Size summary in bytes: - // Measured: `2028` + // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 96_590_000 picoseconds. - Weight::from_parts(98_921_000, 8877) + // Minimum execution time: 87_628_000 picoseconds. + Weight::from_parts(90_020_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// 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) + /// 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: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2233` + // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 99_901_000 picoseconds. - Weight::from_parts(102_919_000, 8877) + // Minimum execution time: 91_655_000 picoseconds. + Weight::from_parts(94_146_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// 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::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:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1021` + // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 45_230_000 picoseconds. - Weight::from_parts(47_052_829, 4764) - // Standard Error: 1_044 - .saturating_add(Weight::from_parts(43_887, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Minimum execution time: 42_953_000 picoseconds. + Weight::from_parts(44_648_505, 4764) + // Standard Error: 937 + .saturating_add(Weight::from_parts(51_090, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) + /// 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::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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::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: `2294 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 97_534_000 picoseconds. - Weight::from_parts(104_772_163, 6248) - // Standard Error: 3_674 - .saturating_add(Weight::from_parts(1_470_124, 0).saturating_mul(s.into())) + // Minimum execution time: 89_218_000 picoseconds. + Weight::from_parts(97_761_884, 6248) + // Standard Error: 3_888 + .saturating_add(Weight::from_parts(1_346_441, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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) + /// 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: `1414` + // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 57_467_000 picoseconds. - Weight::from_parts(59_437_000, 4556) + // Minimum execution time: 51_200_000 picoseconds. + Weight::from_parts(53_403_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// 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) + /// 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: `1285 + k * (569 ±0)` + // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 32_857_000 picoseconds. - Weight::from_parts(37_116_967, 4556) - // Standard Error: 9_522 - .saturating_add(Weight::from_parts(8_796_167, 0).saturating_mul(k.into())) + // Minimum execution time: 28_963_000 picoseconds. + Weight::from_parts(29_884_371, 4556) + // Standard Error: 9_063 + .saturating_add(Weight::from_parts(6_532_967, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .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) + /// 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: `1908 + n * (102 ±0)` + // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 69_613_000 picoseconds. - Weight::from_parts(68_079_061, 6248) - // Standard Error: 18_554 - .saturating_add(Weight::from_parts(4_012_761, 0).saturating_mul(n.into())) + // Minimum execution time: 64_644_000 picoseconds. + Weight::from_parts(62_855_016, 6248) + // Standard Error: 17_528 + .saturating_add(Weight::from_parts(3_993_850, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .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) + /// 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: `1748` + // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 60_430_000 picoseconds. - Weight::from_parts(62_702_000, 6248) + // Minimum execution time: 54_505_000 picoseconds. + Weight::from_parts(56_026_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, 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::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: `808` + // Measured: `902` // Estimated: `4556` - // Minimum execution time: 14_276_000 picoseconds. - Weight::from_parts(14_766_000, 4556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 16_639_000 picoseconds. + Weight::from_parts(17_342_000, 4556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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: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: `907` - // Estimated: `8122` - // Minimum execution time: 21_710_000 picoseconds. - Weight::from_parts(22_430_000, 8122) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `902` + // Estimated: `4556` + // Minimum execution time: 20_334_000 picoseconds. + Weight::from_parts(21_067_000, 4556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// 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: 2_970_000 picoseconds. - Weight::from_parts(3_120_000, 0) + // Minimum execution time: 2_680_000 picoseconds. + Weight::from_parts(2_774_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_362_000 picoseconds. - Weight::from_parts(9_785_000, 0) + // Minimum execution time: 8_613_000 picoseconds. + Weight::from_parts(8_922_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_275_000 picoseconds. - Weight::from_parts(9_678_000, 0) + // Minimum execution time: 8_657_000 picoseconds. + Weight::from_parts(9_020_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_414_000 picoseconds. - Weight::from_parts(9_848_000, 0) + // Minimum execution time: 8_600_000 picoseconds. + Weight::from_parts(9_157_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Staking::Invulnerables` (r:0 w:1) + /// Proof: `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_061_000 picoseconds. - Weight::from_parts(3_618_535, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(10_774, 0).saturating_mul(v.into())) + // Minimum execution time: 2_792_000 picoseconds. + Weight::from_parts(3_293_694, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_668, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// Storage: `Staking::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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: `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: `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::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: `2018 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_914_000 picoseconds. - Weight::from_parts(95_688_129, 6248) - // Standard Error: 5_030 - .saturating_add(Weight::from_parts(1_487_249, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 86_537_000 picoseconds. + Weight::from_parts(95_127_637, 6248) + // Standard Error: 3_902 + .saturating_add(Weight::from_parts(1_336_182, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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) + /// Storage: `Staking::UnappliedSlashes` (r:1 w:1) + /// Proof: `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: `66639` - // Estimated: `70104` - // Minimum execution time: 99_269_000 picoseconds. - Weight::from_parts(1_154_264_637, 70104) - // Standard Error: 76_592 - .saturating_add(Weight::from_parts(6_490_888, 0).saturating_mul(s.into())) + // Measured: `66672` + // Estimated: `70137` + // Minimum execution time: 100_777_000 picoseconds. + Weight::from_parts(896_540_406, 70137) + // Standard Error: 57_788 + .saturating_add(Weight::from_parts(4_870_910, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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:257 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:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// 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::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:257 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:258 w:258) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:257 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `20217 + n * (143 ±0)` - // Estimated: `19844 + n * (2603 ±1)` - // Minimum execution time: 91_767_000 picoseconds. - Weight::from_parts(146_781_264, 19844) - // Standard Error: 31_341 - .saturating_add(Weight::from_parts(30_553_008, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `21644 + n * (155 ±0)` + // Estimated: `21412 + n * (2603 ±0)` + // Minimum execution time: 133_129_000 picoseconds. + Weight::from_parts(190_983_630, 21412) + // Standard Error: 17_497 + .saturating_add(Weight::from_parts(24_723_153, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) .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:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:257 w:257) - /// 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:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:257 w:257) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:257 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:257 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:257 w:257) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersClipped` (r:1 w:0) + /// Proof: `Staking::ErasStakersClipped` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `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::ErasValidatorReward` (r:1 w:0) + /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:257 w:257) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:257 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:257 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33190 + n * (377 ±0)` - // Estimated: `30845 + n * (3774 ±0)` - // Minimum execution time: 121_303_000 picoseconds. - Weight::from_parts(151_046_907, 30845) - // Standard Error: 41_899 - .saturating_add(Weight::from_parts(49_837_804, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Measured: `33297 + n * (377 ±0)` + // Estimated: `30944 + n * (3774 ±3)` + // Minimum execution time: 149_773_000 picoseconds. + Weight::from_parts(151_527_124, 30944) + // Standard Error: 24_152 + .saturating_add(Weight::from_parts(46_124_074, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) .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) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2029 + l * (7 ±0)` + // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 90_068_000 picoseconds. - Weight::from_parts(93_137_456, 8877) - // Standard Error: 4_799 - .saturating_add(Weight::from_parts(54_421, 0).saturating_mul(l.into())) + // Minimum execution time: 81_618_000 picoseconds. + Weight::from_parts(85_245_630, 8877) + // Standard Error: 5_049 + .saturating_add(Weight::from_parts(39_811, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// 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) + /// 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: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// 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::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: `2294 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 103_139_000 picoseconds. - Weight::from_parts(107_036_296, 6248) - // Standard Error: 3_935 - .saturating_add(Weight::from_parts(1_465_860, 0).saturating_mul(s.into())) + // Minimum execution time: 95_395_000 picoseconds. + Weight::from_parts(100_459_234, 6248) + // Standard Error: 3_781 + .saturating_add(Weight::from_parts(1_333_607, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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:200 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: 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) + /// 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:200 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::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: `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::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::ErasValidatorPrefs` (r:0 w:10) + /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:0 w:10) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:0 w:10) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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 * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 587_156_000 picoseconds. - Weight::from_parts(590_176_000, 512390) - // Standard Error: 2_008_420 - .saturating_add(Weight::from_parts(64_526_052, 0).saturating_mul(v.into())) - // Standard Error: 200_128 - .saturating_add(Weight::from_parts(18_070_222, 0).saturating_mul(n.into())) + // Minimum execution time: 571_337_000 picoseconds. + Weight::from_parts(578_857_000, 512390) + // Standard Error: 2_090_511 + .saturating_add(Weight::from_parts(68_626_083, 0).saturating_mul(v.into())) + // Standard Error: 208_307 + .saturating_add(Weight::from_parts(18_645_374, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .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:200 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: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// 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:200 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::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: `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::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: `3217 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_399_721_000 picoseconds. - Weight::from_parts(34_605_803_000, 512390) - // Standard Error: 380_106 - .saturating_add(Weight::from_parts(5_426_220, 0).saturating_mul(v.into())) - // Standard Error: 380_106 - .saturating_add(Weight::from_parts(3_318_197, 0).saturating_mul(n.into())) + // Minimum execution time: 34_590_734_000 picoseconds. + Weight::from_parts(35_238_091_000, 512390) + // Standard Error: 427_974 + .saturating_add(Weight::from_parts(5_084_196, 0).saturating_mul(v.into())) + // Standard Error: 427_974 + .saturating_add(Weight::from_parts(4_503_420, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -684,709 +697,725 @@ impl WeightInfo for SubstrateWeight { .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: `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`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `983 + v * (50 ±0)` + // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_392_849_000 picoseconds. - Weight::from_parts(64_373_879, 3510) - // Standard Error: 8_995 - .saturating_add(Weight::from_parts(4_721_536, 0).saturating_mul(v.into())) + // Minimum execution time: 2_509_588_000 picoseconds. + Weight::from_parts(89_050_539, 3510) + // Standard Error: 11_803 + .saturating_add(Weight::from_parts(5_031_416, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) } - /// 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) + /// 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: 7_529_000 picoseconds. - Weight::from_parts(7_970_000, 0) + // Minimum execution time: 5_347_000 picoseconds. + Weight::from_parts(5_562_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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) + /// 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: 7_011_000 picoseconds. - Weight::from_parts(7_317_000, 0) + // Minimum execution time: 4_725_000 picoseconds. + Weight::from_parts(5_075_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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) + /// 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: `1871` + // Measured: `1773` // Estimated: `6248` - // Minimum execution time: 75_982_000 picoseconds. - Weight::from_parts(77_412_000, 6248) + // Minimum execution time: 67_204_000 picoseconds. + Weight::from_parts(69_197_000, 6248) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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::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: `694` + // Measured: `691` // Estimated: `3510` - // Minimum execution time: 13_923_000 picoseconds. - Weight::from_parts(14_356_000, 3510) + // Minimum execution time: 12_497_000 picoseconds. + Weight::from_parts(12_943_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// 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_415_000 picoseconds. - Weight::from_parts(3_679_000, 0) + // Minimum execution time: 3_245_000 picoseconds. + Weight::from_parts(3_352_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `927` // Estimated: `4764` - // Minimum execution time: 53_983_000 picoseconds. - Weight::from_parts(55_296_000, 4764) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 42_811_000 picoseconds. + Weight::from_parts(44_465_000, 4764) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w: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: `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() -> Weight { // Proof Size summary in bytes: - // Measured: `2028` + // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 96_590_000 picoseconds. - Weight::from_parts(98_921_000, 8877) + // Minimum execution time: 87_628_000 picoseconds. + Weight::from_parts(90_020_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// 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) + /// 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: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2233` + // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 99_901_000 picoseconds. - Weight::from_parts(102_919_000, 8877) + // Minimum execution time: 91_655_000 picoseconds. + Weight::from_parts(94_146_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// 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::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:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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 withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1021` + // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 45_230_000 picoseconds. - Weight::from_parts(47_052_829, 4764) - // Standard Error: 1_044 - .saturating_add(Weight::from_parts(43_887, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Minimum execution time: 42_953_000 picoseconds. + Weight::from_parts(44_648_505, 4764) + // Standard Error: 937 + .saturating_add(Weight::from_parts(51_090, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) + /// 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::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `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::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: `2294 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 97_534_000 picoseconds. - Weight::from_parts(104_772_163, 6248) - // Standard Error: 3_674 - .saturating_add(Weight::from_parts(1_470_124, 0).saturating_mul(s.into())) + // Minimum execution time: 89_218_000 picoseconds. + Weight::from_parts(97_761_884, 6248) + // Standard Error: 3_888 + .saturating_add(Weight::from_parts(1_346_441, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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) + /// 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: `1414` + // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 57_467_000 picoseconds. - Weight::from_parts(59_437_000, 4556) + // Minimum execution time: 51_200_000 picoseconds. + Weight::from_parts(53_403_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// 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) + /// 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: `1285 + k * (569 ±0)` + // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 32_857_000 picoseconds. - Weight::from_parts(37_116_967, 4556) - // Standard Error: 9_522 - .saturating_add(Weight::from_parts(8_796_167, 0).saturating_mul(k.into())) + // Minimum execution time: 28_963_000 picoseconds. + Weight::from_parts(29_884_371, 4556) + // Standard Error: 9_063 + .saturating_add(Weight::from_parts(6_532_967, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .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) + /// 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: `1908 + n * (102 ±0)` + // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 69_613_000 picoseconds. - Weight::from_parts(68_079_061, 6248) - // Standard Error: 18_554 - .saturating_add(Weight::from_parts(4_012_761, 0).saturating_mul(n.into())) + // Minimum execution time: 64_644_000 picoseconds. + Weight::from_parts(62_855_016, 6248) + // Standard Error: 17_528 + .saturating_add(Weight::from_parts(3_993_850, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .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) + /// 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: `1748` + // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 60_430_000 picoseconds. - Weight::from_parts(62_702_000, 6248) + // Minimum execution time: 54_505_000 picoseconds. + Weight::from_parts(56_026_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, 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::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: `808` + // Measured: `902` // Estimated: `4556` - // Minimum execution time: 14_276_000 picoseconds. - Weight::from_parts(14_766_000, 4556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 16_639_000 picoseconds. + Weight::from_parts(17_342_000, 4556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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: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: `907` - // Estimated: `8122` - // Minimum execution time: 21_710_000 picoseconds. - Weight::from_parts(22_430_000, 8122) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `902` + // Estimated: `4556` + // Minimum execution time: 20_334_000 picoseconds. + Weight::from_parts(21_067_000, 4556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// 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: 2_970_000 picoseconds. - Weight::from_parts(3_120_000, 0) + // Minimum execution time: 2_680_000 picoseconds. + Weight::from_parts(2_774_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_362_000 picoseconds. - Weight::from_parts(9_785_000, 0) + // Minimum execution time: 8_613_000 picoseconds. + Weight::from_parts(8_922_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_275_000 picoseconds. - Weight::from_parts(9_678_000, 0) + // Minimum execution time: 8_657_000 picoseconds. + Weight::from_parts(9_020_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// 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_414_000 picoseconds. - Weight::from_parts(9_848_000, 0) + // Minimum execution time: 8_600_000 picoseconds. + Weight::from_parts(9_157_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Staking::Invulnerables` (r:0 w:1) + /// Proof: `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_061_000 picoseconds. - Weight::from_parts(3_618_535, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(10_774, 0).saturating_mul(v.into())) + // Minimum execution time: 2_792_000 picoseconds. + Weight::from_parts(3_293_694, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_668, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// Storage: `Staking::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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: `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: `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::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: `2018 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_914_000 picoseconds. - Weight::from_parts(95_688_129, 6248) - // Standard Error: 5_030 - .saturating_add(Weight::from_parts(1_487_249, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 86_537_000 picoseconds. + Weight::from_parts(95_127_637, 6248) + // Standard Error: 3_902 + .saturating_add(Weight::from_parts(1_336_182, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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) + /// Storage: `Staking::UnappliedSlashes` (r:1 w:1) + /// Proof: `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: `66639` - // Estimated: `70104` - // Minimum execution time: 99_269_000 picoseconds. - Weight::from_parts(1_154_264_637, 70104) - // Standard Error: 76_592 - .saturating_add(Weight::from_parts(6_490_888, 0).saturating_mul(s.into())) + // Measured: `66672` + // Estimated: `70137` + // Minimum execution time: 100_777_000 picoseconds. + Weight::from_parts(896_540_406, 70137) + // Standard Error: 57_788 + .saturating_add(Weight::from_parts(4_870_910, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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:257 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:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// 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::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:257 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:258 w:258) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:257 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `20217 + n * (143 ±0)` - // Estimated: `19844 + n * (2603 ±1)` - // Minimum execution time: 91_767_000 picoseconds. - Weight::from_parts(146_781_264, 19844) - // Standard Error: 31_341 - .saturating_add(Weight::from_parts(30_553_008, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `21644 + n * (155 ±0)` + // Estimated: `21412 + n * (2603 ±0)` + // Minimum execution time: 133_129_000 picoseconds. + Weight::from_parts(190_983_630, 21412) + // Standard Error: 17_497 + .saturating_add(Weight::from_parts(24_723_153, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::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:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:257 w:257) - /// 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:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:257 w:257) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:257 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:257 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:257 w:257) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersClipped` (r:1 w:0) + /// Proof: `Staking::ErasStakersClipped` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::ClaimedRewards` (r:1 w:1) + /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `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::ErasValidatorReward` (r:1 w:0) + /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:257 w:257) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:257 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) + /// Proof: `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:257 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33190 + n * (377 ±0)` - // Estimated: `30845 + n * (3774 ±0)` - // Minimum execution time: 121_303_000 picoseconds. - Weight::from_parts(151_046_907, 30845) - // Standard Error: 41_899 - .saturating_add(Weight::from_parts(49_837_804, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Measured: `33297 + n * (377 ±0)` + // Estimated: `30944 + n * (3774 ±3)` + // Minimum execution time: 149_773_000 picoseconds. + Weight::from_parts(151_527_124, 30944) + // Standard Error: 24_152 + .saturating_add(Weight::from_parts(46_124_074, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::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) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, 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`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2029 + l * (7 ±0)` + // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 90_068_000 picoseconds. - Weight::from_parts(93_137_456, 8877) - // Standard Error: 4_799 - .saturating_add(Weight::from_parts(54_421, 0).saturating_mul(l.into())) + // Minimum execution time: 81_618_000 picoseconds. + Weight::from_parts(85_245_630, 8877) + // Standard Error: 5_049 + .saturating_add(Weight::from_parts(39_811, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// 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) + /// 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: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// 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::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: `2294 + s * (4 ±0)` + // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 103_139_000 picoseconds. - Weight::from_parts(107_036_296, 6248) - // Standard Error: 3_935 - .saturating_add(Weight::from_parts(1_465_860, 0).saturating_mul(s.into())) + // Minimum execution time: 95_395_000 picoseconds. + Weight::from_parts(100_459_234, 6248) + // Standard Error: 3_781 + .saturating_add(Weight::from_parts(1_333_607, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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:200 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: 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) + /// 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:200 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::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: `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::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::ErasValidatorPrefs` (r:0 w:10) + /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:0 w:10) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersOverview` (r:0 w:10) + /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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 * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 587_156_000 picoseconds. - Weight::from_parts(590_176_000, 512390) - // Standard Error: 2_008_420 - .saturating_add(Weight::from_parts(64_526_052, 0).saturating_mul(v.into())) - // Standard Error: 200_128 - .saturating_add(Weight::from_parts(18_070_222, 0).saturating_mul(n.into())) + // Minimum execution time: 571_337_000 picoseconds. + Weight::from_parts(578_857_000, 512390) + // Standard Error: 2_090_511 + .saturating_add(Weight::from_parts(68_626_083, 0).saturating_mul(v.into())) + // Standard Error: 208_307 + .saturating_add(Weight::from_parts(18_645_374, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::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:200 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: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// 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:200 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::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: `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::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: `3217 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_399_721_000 picoseconds. - Weight::from_parts(34_605_803_000, 512390) - // Standard Error: 380_106 - .saturating_add(Weight::from_parts(5_426_220, 0).saturating_mul(v.into())) - // Standard Error: 380_106 - .saturating_add(Weight::from_parts(3_318_197, 0).saturating_mul(n.into())) + // Minimum execution time: 34_590_734_000 picoseconds. + Weight::from_parts(35_238_091_000, 512390) + // Standard Error: 427_974 + .saturating_add(Weight::from_parts(5_084_196, 0).saturating_mul(v.into())) + // Standard Error: 427_974 + .saturating_add(Weight::from_parts(4_503_420, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1394,113 +1423,113 @@ impl WeightInfo for () { .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: `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`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `983 + v * (50 ±0)` + // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_392_849_000 picoseconds. - Weight::from_parts(64_373_879, 3510) - // Standard Error: 8_995 - .saturating_add(Weight::from_parts(4_721_536, 0).saturating_mul(v.into())) + // Minimum execution time: 2_509_588_000 picoseconds. + Weight::from_parts(89_050_539, 3510) + // Standard Error: 11_803 + .saturating_add(Weight::from_parts(5_031_416, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) } - /// 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) + /// 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: 7_529_000 picoseconds. - Weight::from_parts(7_970_000, 0) + // Minimum execution time: 5_347_000 picoseconds. + Weight::from_parts(5_562_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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) + /// 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: 7_011_000 picoseconds. - Weight::from_parts(7_317_000, 0) + // Minimum execution time: 4_725_000 picoseconds. + Weight::from_parts(5_075_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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) + /// 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: `1871` + // Measured: `1773` // Estimated: `6248` - // Minimum execution time: 75_982_000 picoseconds. - Weight::from_parts(77_412_000, 6248) + // Minimum execution time: 67_204_000 picoseconds. + Weight::from_parts(69_197_000, 6248) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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::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: `694` + // Measured: `691` // Estimated: `3510` - // Minimum execution time: 13_923_000 picoseconds. - Weight::from_parts(14_356_000, 3510) + // Minimum execution time: 12_497_000 picoseconds. + Weight::from_parts(12_943_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// 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_415_000 picoseconds. - Weight::from_parts(3_679_000, 0) + // Minimum execution time: 3_245_000 picoseconds. + Weight::from_parts(3_352_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index dfc18987d15..c2ac5ae004b 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -21,11 +21,13 @@ //! approaches in general. Definitions related to sessions, slashing, etc go here. use crate::currency_to_vote::CurrencyToVote; -use codec::{FullCodec, MaxEncodedLen}; +use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::RuntimeDebug; -use sp_runtime::{DispatchError, DispatchResult, Saturating}; -use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec::Vec}; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Zero}, + DispatchError, DispatchResult, RuntimeDebug, Saturating, +}; +use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec}; pub mod offence; @@ -37,6 +39,8 @@ pub type SessionIndex = u32; /// Counter for the number of eras that have passed. pub type EraIndex = u32; +/// Type for identifying a page. +pub type Page = 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 @@ -280,6 +284,9 @@ pub trait StakingInterface { } } + #[cfg(feature = "runtime-benchmarks")] + fn max_exposure_page_size() -> Page; + #[cfg(feature = "runtime-benchmarks")] fn add_era_stakers( current_era: &EraIndex, @@ -291,4 +298,122 @@ pub trait StakingInterface { fn set_current_era(era: EraIndex); } +/// The amount of exposure for an era that an individual nominator has (susceptible to slashing). +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct IndividualExposure { + /// The stash account of the nominator in question. + pub who: AccountId, + /// Amount of funds exposed. + #[codec(compact)] + pub value: Balance, +} + +/// A snapshot of the stake backing a single validator in the system. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Exposure { + /// The total balance backing this validator. + #[codec(compact)] + pub total: Balance, + /// The validator's own stash that is exposed. + #[codec(compact)] + pub own: Balance, + /// The portions of nominators stashes that are exposed. + pub others: Vec>, +} + +impl Default for Exposure { + fn default() -> Self { + Self { total: Default::default(), own: Default::default(), others: vec![] } + } +} + +impl< + AccountId: Clone, + Balance: HasCompact + AtLeast32BitUnsigned + Copy + codec::MaxEncodedLen, + > Exposure +{ + /// Splits an `Exposure` into `PagedExposureMetadata` and multiple chunks of + /// `IndividualExposure` with each chunk having maximum of `page_size` elements. + pub fn into_pages( + self, + page_size: Page, + ) -> (PagedExposureMetadata, Vec>) { + let individual_chunks = self.others.chunks(page_size as usize); + let mut exposure_pages: Vec> = + Vec::with_capacity(individual_chunks.len()); + + for chunk in individual_chunks { + let mut page_total: Balance = Zero::zero(); + let mut others: Vec> = + Vec::with_capacity(chunk.len()); + for individual in chunk.iter() { + page_total.saturating_accrue(individual.value); + others.push(IndividualExposure { + who: individual.who.clone(), + value: individual.value, + }) + } + + exposure_pages.push(ExposurePage { page_total, others }); + } + + ( + PagedExposureMetadata { + total: self.total, + own: self.own, + nominator_count: self.others.len() as u32, + page_count: exposure_pages.len() as Page, + }, + exposure_pages, + ) + } +} + +/// A snapshot of the stake backing a single validator in the system. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ExposurePage { + /// The total balance of this chunk/page. + #[codec(compact)] + pub page_total: Balance, + /// The portions of nominators stashes that are exposed. + pub others: Vec>, +} + +impl Default for ExposurePage { + fn default() -> Self { + ExposurePage { page_total: Default::default(), others: vec![] } + } +} + +/// Metadata for Paged Exposure of a validator such as total stake across pages and page count. +/// +/// In combination with the associated `ExposurePage`s, it can be used to reconstruct a full +/// `Exposure` set of a validator. This is useful for cases where we want to query full set of +/// `Exposure` as one page (for backward compatibility). +#[derive( + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Encode, + Decode, + RuntimeDebug, + TypeInfo, + Default, + MaxEncodedLen, +)] +pub struct PagedExposureMetadata { + /// The total balance backing this validator. + #[codec(compact)] + pub total: Balance, + /// The validator's own stash that is exposed. + #[codec(compact)] + pub own: Balance, + /// Number of nominators backing this validator. + pub nominator_count: u32, + /// Number of pages of nominators. + pub page_count: Page, +} + sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); -- GitLab From 2726d5af65d041adbcd3e96986a233e7c8fa07a8 Mon Sep 17 00:00:00 2001 From: jserrat <35823283+Jpserrat@users.noreply.github.com> Date: Wed, 1 Nov 2023 11:58:46 -0300 Subject: [PATCH 410/633] remove gum dependency on jaeger (#2106) Co-authored-by: Marcin S --- Cargo.lock | 12 ------------ .../node/core/pvf/execute-worker/Cargo.toml | 6 ------ .../node/core/pvf/prepare-worker/Cargo.toml | 6 ------ polkadot/node/gum/Cargo.toml | 3 +-- polkadot/node/gum/src/lib.rs | 19 +++++++++++++++++-- 5 files changed, 18 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb49533a7f9..e6d764dcd39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12257,15 +12257,10 @@ name = "polkadot-node-core-pvf-execute-worker" version = "1.0.0" dependencies = [ "cpu-time", - "futures", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-parachain-primitives", "polkadot-primitives", - "rayon", - "sp-core", - "sp-maybe-compressed-blob", - "sp-tracing", "tracing-gum", ] @@ -12274,19 +12269,13 @@ name = "polkadot-node-core-pvf-prepare-worker" version = "1.0.0" dependencies = [ "cfg-if", - "futures", "libc", "parity-scale-codec", "polkadot-node-core-pvf-common", - "polkadot-parachain-primitives", "polkadot-primitives", "rayon", - "sc-executor", "sc-executor-common", "sc-executor-wasmtime", - "sp-io", - "sp-maybe-compressed-blob", - "sp-tracing", "tikv-jemalloc-ctl", "tracing-gum", ] @@ -19103,7 +19092,6 @@ name = "tracing-gum" version = "1.0.0" dependencies = [ "coarsetime", - "polkadot-node-jaeger", "polkadot-primitives", "tracing", "tracing-gum-proc-macro", diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 203bbd0e785..77a9420961c 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -8,9 +8,7 @@ license.workspace = true [dependencies] cpu-time = "1.0.0" -futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } -rayon = "1.5.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -18,9 +16,5 @@ polkadot-node-core-pvf-common = { path = "../common" } polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } -sp-core = { path = "../../../../../substrate/primitives/core" } -sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } -sp-tracing = { path = "../../../../../substrate/primitives/tracing" } - [features] builder = [] diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index eb53ebdc941..e5a08f8a153 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -8,7 +8,6 @@ license.workspace = true [dependencies] cfg-if = "1.0" -futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" rayon = "1.5.1" @@ -17,15 +16,10 @@ tikv-jemalloc-ctl = { version = "0.5.0", optional = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } polkadot-node-core-pvf-common = { path = "../common" } -polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } -sc-executor = { path = "../../../../../substrate/client/executor" } sc-executor-common = { path = "../../../../../substrate/client/executor/common" } sc-executor-wasmtime = { path = "../../../../../substrate/client/executor/wasmtime" } -sp-io = { path = "../../../../../substrate/primitives/io" } -sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } -sp-tracing = { path = "../../../../../substrate/primitives/tracing" } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemalloc-ctl = "0.5.0" diff --git a/polkadot/node/gum/Cargo.toml b/polkadot/node/gum/Cargo.toml index 01ed34f7a73..acee9efd0e0 100644 --- a/polkadot/node/gum/Cargo.toml +++ b/polkadot/node/gum/Cargo.toml @@ -9,6 +9,5 @@ description = "Stick logs together with the TraceID as provided by tempo" [dependencies] coarsetime = "0.1.22" tracing = "0.1.35" -jaeger = { package = "polkadot-node-jaeger" , path = "../jaeger" } -gum-proc-macro = { package = "tracing-gum-proc-macro" , path = "proc-macro" } +gum-proc-macro = { package = "tracing-gum-proc-macro", path = "proc-macro" } polkadot-primitives = { path = "../../primitives", features = ["std"] } diff --git a/polkadot/node/gum/src/lib.rs b/polkadot/node/gum/src/lib.rs index 1cc4d8dec1c..dad5887af22 100644 --- a/polkadot/node/gum/src/lib.rs +++ b/polkadot/node/gum/src/lib.rs @@ -105,8 +105,23 @@ pub use tracing::{enabled, event, Level}; -#[doc(hidden)] -pub use jaeger::hash_to_trace_identifier; +// jaeger dependency + +/// Alias for the 16 byte unique identifier used with jaeger. +pub(crate) type TraceIdentifier = u128; + +/// A helper to convert the hash to the fixed size representation +/// needed for jaeger. +#[inline] +pub fn hash_to_trace_identifier(hash: Hash) -> TraceIdentifier { + let mut buf = [0u8; 16]; + buf.copy_from_slice(&hash.as_ref()[0..16]); + // The slice bytes are copied in reading order, so if interpreted + // in string form by a human, that means lower indices have higher + // values and hence corresponds to BIG endian ordering of the individual + // bytes. + u128::from_be_bytes(buf) as TraceIdentifier +} #[doc(hidden)] pub use polkadot_primitives::{CandidateHash, Hash}; -- GitLab From 8507f45cefe5185712938a0087fbbdf4f0c2cdfc Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 1 Nov 2023 16:06:25 +0100 Subject: [PATCH 411/633] [ci] Revert CI_IMAGE variable (#2120) CI image has been updated in the shared snippet, reverting the variable back. --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6dc7fc1a3cd..835b668de25 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,8 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - # CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] - CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231025" + CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" -- GitLab From dce5a8da66af8d5d2bbe639a2e39cfdd9d712af5 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 1 Nov 2023 17:11:07 +0200 Subject: [PATCH 412/633] Direct XCM `ExportMessage` fees for different bridges to different receiver accounts (#2021) --- .../assets/asset-hub-rococo/src/xcm_config.rs | 9 +- .../assets/asset-hub-rococo/tests/tests.rs | 4 +- .../asset-hub-westend/src/xcm_config.rs | 9 +- .../bridge-hub-rococo/src/xcm_config.rs | 147 ++++++++++++++++-- .../contracts-rococo/src/xcm_config.rs | 9 +- polkadot/runtime/rococo/src/xcm_config.rs | 10 +- polkadot/runtime/westend/src/xcm_config.rs | 9 +- .../src/generic/benchmarking.rs | 2 +- polkadot/xcm/pallet-xcm/src/mock.rs | 8 +- polkadot/xcm/xcm-builder/src/fee_handling.rs | 117 ++++++++++---- polkadot/xcm/xcm-builder/src/lib.rs | 4 +- polkadot/xcm/xcm-builder/src/tests/mock.rs | 3 +- polkadot/xcm/xcm-executor/src/lib.rs | 6 +- .../xcm-executor/src/traits/fee_manager.rs | 9 +- 14 files changed, 275 insertions(+), 71 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 222e96d59d1..83fa31abd7f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -53,7 +53,7 @@ use xcm_builder::{ SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeesToAccount, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -75,7 +75,7 @@ parameter_types! { PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); - pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } @@ -619,7 +619,10 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = (bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index b93315cc39d..18f5f4fc41e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -683,7 +683,7 @@ mod asset_hub_rococo_tests { bridging_to_asset_hub_wococo, WeightLimit::Unlimited, Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), - Some(xcm_config::TreasuryAccount::get().unwrap()), + Some(xcm_config::TreasuryAccount::get()), ) } @@ -871,7 +871,7 @@ mod asset_hub_wococo_tests { with_wococo_flavor_bridging_to_asset_hub_rococo, WeightLimit::Unlimited, Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), - Some(xcm_config::TreasuryAccount::get().unwrap()), + Some(xcm_config::TreasuryAccount::get()), ) } 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 fe0fd613d22..6b5ce904da9 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 @@ -52,7 +52,7 @@ use xcm_builder::{ SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeesToAccount, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -73,7 +73,7 @@ parameter_types! { pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); - pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); } @@ -562,7 +562,10 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; 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 2456a7ee63a..dc6f61d0146 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 @@ -24,9 +24,18 @@ use crate::{ BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, RequiredStakeForStakeAndSlash, }, - bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, - bridge_hub_wococo_config::ToBridgeHubRococoHaulBlobExporter, + bridge_hub_rococo_config::{ + AssetHubRococoParaId, BridgeHubWococoChainId, BridgeHubWococoMessagesLane, + ToBridgeHubWococoHaulBlobExporter, WococoGlobalConsensusNetwork, + }, + bridge_hub_wococo_config::{ + AssetHubWococoParaId, BridgeHubRococoChainId, BridgeHubRococoMessagesLane, + RococoGlobalConsensusNetwork, ToBridgeHubRococoHaulBlobExporter, + }, }; +use bp_messages::LaneId; +use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::ChainId; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Equals, Everything, Nothing}, @@ -43,18 +52,20 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use rococo_runtime_constants::system_parachain; use sp_core::Get; use sp_runtime::traits::AccountIdConversion; +use sp_std::marker::PhantomData; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeesToAccount, + deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, HandleFee, + IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{ - traits::{ExportXcm, WithOriginFilter}, + traits::{ExportXcm, FeeReason, TransactAsset, WithOriginFilter}, XcmExecutor, }; @@ -66,7 +77,7 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; - pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } @@ -290,7 +301,26 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + ( + XcmExportFeeToRelayerRewardAccounts< + Self::AssetTransactor, + WococoGlobalConsensusNetwork, + AssetHubWococoParaId, + BridgeHubWococoChainId, + BridgeHubWococoMessagesLane, + >, + XcmExportFeeToRelayerRewardAccounts< + Self::AssetTransactor, + RococoGlobalConsensusNetwork, + AssetHubRococoParaId, + BridgeHubRococoChainId, + BridgeHubRococoMessagesLane, + >, + XcmFeeToAccount, + ), + >; type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; @@ -401,3 +431,96 @@ impl ExportXcm for BridgeHubRococoOrBridgeHubWococoSwitchExporter { } } } + +/// A `HandleFee` implementation that simply deposits the fees for `ExportMessage` XCM instructions +/// into the accounts that are used for paying the relayer rewards. +/// Burns the fees in case of a failure. +pub struct XcmExportFeeToRelayerRewardAccounts< + AssetTransactor, + DestNetwork, + DestParaId, + DestBridgeHubId, + BridgeLaneId, +>(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgeHubId, BridgeLaneId)>); + +impl< + AssetTransactor: TransactAsset, + DestNetwork: Get, + DestParaId: Get, + DestBridgeHubId: Get, + BridgeLaneId: Get, + > HandleFee + for XcmExportFeeToRelayerRewardAccounts< + AssetTransactor, + DestNetwork, + DestParaId, + DestBridgeHubId, + BridgeLaneId, + > +{ + fn handle_fee( + fee: MultiAssets, + maybe_context: Option<&XcmContext>, + reason: FeeReason, + ) -> MultiAssets { + if matches!(reason, FeeReason::Export { network: bridged_network, destination } + if bridged_network == DestNetwork::get() && + destination == X1(Parachain(DestParaId::get().into()))) + { + // We have 2 relayer rewards accounts: + // - the SA of the source parachain on this BH: this pays the relayers for delivering + // Source para -> Target Para message delivery confirmations + // - the SA of the destination parachain on this BH: this pays the relayers for + // delivering Target para -> Source Para messages + // We split the `ExportMessage` fee between these 2 accounts. + let source_para_account = PayRewardFromAccount::< + pallet_balances::Pallet, + AccountId, + >::rewards_account(RewardsAccountParams::new( + BridgeLaneId::get(), + DestBridgeHubId::get(), + RewardsAccountOwner::ThisChain, + )); + + let dest_para_account = PayRewardFromAccount::< + pallet_balances::Pallet, + AccountId, + >::rewards_account(RewardsAccountParams::new( + BridgeLaneId::get(), + DestBridgeHubId::get(), + RewardsAccountOwner::BridgedChain, + )); + + for asset in fee.into_inner() { + match asset.fun { + Fungible(total_fee) => { + let source_fee = total_fee / 2; + deposit_or_burn_fee::( + MultiAsset { id: asset.id, fun: Fungible(source_fee) }.into(), + maybe_context, + source_para_account.clone(), + ); + + let dest_fee = total_fee - source_fee; + deposit_or_burn_fee::( + MultiAsset { id: asset.id, fun: Fungible(dest_fee) }.into(), + maybe_context, + dest_para_account.clone(), + ); + }, + NonFungible(_) => { + deposit_or_burn_fee::( + asset.into(), + maybe_context, + source_para_account.clone(), + ); + }, + } + } + + return MultiAssets::new() + } + + fee + } +} 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 6ff60b958fe..ebb3de740b9 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -41,7 +41,7 @@ use xcm_builder::{ NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, + WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -51,7 +51,7 @@ parameter_types! { pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const ExecutiveBody: BodyId = BodyId::Executive; - pub TreasuryAccount: Option = Some(TREASURY_PALLET_ID.into_account_truncating()); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } @@ -199,7 +199,10 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = ConstU32<8>; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index fb1653c549e..0814b77414f 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -43,7 +43,8 @@ use xcm_builder::{ DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -53,7 +54,7 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); - pub TreasuryAccount: Option = Some(Treasury::account_id()); + pub TreasuryAccount: AccountId = Treasury::account_id(); } pub type LocationConverter = ( @@ -191,7 +192,10 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + SystemParachains, + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index dd6a29885ad..64e07317fc7 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -44,7 +44,7 @@ use xcm_builder::{ DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeesToAccount, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -54,7 +54,7 @@ parameter_types! { pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get())); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); - pub TreasuryAccount: Option = Some(Treasury::account_id()); + pub TreasuryAccount: AccountId = Treasury::account_id(); /// 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. @@ -185,7 +185,10 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeeManagerFromComponents< + SystemParachains, + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index c6b76e0ffad..4a997666027 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -561,7 +561,7 @@ benchmarks! { let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( &origin, &destination.into(), - FeeReason::Export(network), + FeeReason::Export { network, destination }, ); let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap(); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index afa956c3cda..3b41ad90ec9 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -34,7 +34,7 @@ use xcm_builder::{ AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, + SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -343,11 +343,9 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount< - Self, + type FeeManager = XcmFeeManagerFromComponents< EverythingBut, - AccountId, - XcmFeesTargetAccount, + XcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/polkadot/xcm/xcm-builder/src/fee_handling.rs b/polkadot/xcm/xcm-builder/src/fee_handling.rs index 1386747c977..c158d5d862d 100644 --- a/polkadot/xcm/xcm-builder/src/fee_handling.rs +++ b/polkadot/xcm/xcm-builder/src/fee_handling.rs @@ -19,40 +19,103 @@ use frame_support::traits::{Contains, Get}; use xcm::prelude::*; use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset}; -/// A `FeeManager` implementation that simply deposits the fees handled into a specific on-chain -/// `ReceiverAccount`. -/// -/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets, and also -/// permits specifying `WaivedLocations` for locations that are privileged to not pay for fees. If -/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be -/// logged. -pub struct XcmFeesToAccount( - PhantomData<(XcmConfig, WaivedLocations, AccountId, ReceiverAccount)>, +/// Handles the fees that are taken by certain XCM instructions. +pub trait HandleFee { + /// Do something with the fee which has been paid. Doing nothing here silently burns the + /// fees. + /// + /// Returns any part of the fee that wasn't consumed. + fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason) + -> MultiAssets; +} + +// Default `HandleFee` implementation that just burns the fee. +impl HandleFee for () { + fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) -> MultiAssets { + MultiAssets::new() + } +} + +#[impl_trait_for_tuples::impl_for_tuples(1, 30)] +impl HandleFee for Tuple { + fn handle_fee( + fee: MultiAssets, + context: Option<&XcmContext>, + reason: FeeReason, + ) -> MultiAssets { + let mut unconsumed_fee = fee; + for_tuples!( #( + unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason); + if unconsumed_fee.is_none() { + return unconsumed_fee; + } + )* ); + + unconsumed_fee + } +} + +/// A `FeeManager` implementation that permits the specified `WaivedLocations` to not pay for fees +/// and that uses the provided `HandleFee` implementation otherwise. +pub struct XcmFeeManagerFromComponents( + PhantomData<(WaivedLocations, HandleFee)>, ); -impl< - XcmConfig: xcm_executor::Config, - WaivedLocations: Contains, - AccountId: Clone + Into<[u8; 32]>, - ReceiverAccount: Get>, - > FeeManager for XcmFeesToAccount +impl, FeeHandler: HandleFee> FeeManager + for XcmFeeManagerFromComponents { fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool { let Some(loc) = origin else { return false }; WaivedLocations::contains(loc) } - fn handle_fee(fees: MultiAssets, context: Option<&XcmContext>) { - if let Some(receiver) = ReceiverAccount::get() { - let dest = AccountId32 { network: None, id: receiver.into() }.into(); - for asset in fees.into_inner() { - if let Err(e) = XcmConfig::AssetTransactor::deposit_asset(&asset, &dest, context) { - log::trace!( - target: "xcm::fees", - "`AssetTransactor::deposit_asset` returned error: {:?}, burning fees: {:?}", - e, asset, - ); - } - } + fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason) { + FeeHandler::handle_fee(fee, context, reason); + } +} + +/// Try to deposit the given fee in the specified account. +/// Burns the fee in case of a failure. +pub fn deposit_or_burn_fee>( + fee: MultiAssets, + context: Option<&XcmContext>, + receiver: AccountId, +) { + let dest = AccountId32 { network: None, id: receiver.into() }.into(); + for asset in fee.into_inner() { + if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) { + log::trace!( + target: "xcm::fees", + "`AssetTransactor::deposit_asset` returned error: {:?}. Burning fee: {:?}. \ + They might be burned.", + e, asset, + ); } } } + +/// A `HandleFee` implementation that simply deposits the fees into a specific on-chain +/// `ReceiverAccount`. +/// +/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If +/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be +/// logged and the fee burned. +pub struct XcmFeeToAccount( + PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>, +); + +impl< + AssetTransactor: TransactAsset, + AccountId: Clone + Into<[u8; 32]>, + ReceiverAccount: Get, + > HandleFee for XcmFeeToAccount +{ + fn handle_fee( + fee: MultiAssets, + context: Option<&XcmContext>, + _reason: FeeReason, + ) -> MultiAssets { + deposit_or_burn_fee::(fee, context, ReceiverAccount::get()); + + MultiAssets::new() + } +} diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 34371398cdc..0a74b3f579a 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -68,7 +68,9 @@ mod currency_adapter; pub use currency_adapter::CurrencyAdapter; mod fee_handling; -pub use fee_handling::XcmFeesToAccount; +pub use fee_handling::{ + deposit_or_burn_fee, HandleFee, XcmFeeManagerFromComponents, XcmFeeToAccount, +}; mod fungibles_adapter; pub use fungibles_adapter::{ diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 7a7c8837fc1..543b00e0118 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -526,7 +526,8 @@ impl FeeManager for TestFeeManager { fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool { IS_WAIVED.with(|l| l.borrow().contains(&r)) } - fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {} + + fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {} } #[derive(Clone, Eq, PartialEq, Debug)] diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index e11ec2630e4..e43d7a04899 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -248,7 +248,7 @@ impl ExecuteXcm for XcmExecutor XcmExecutor { destination, xcm, )?; - self.take_fee(fee, FeeReason::Export(network))?; + self.take_fee(fee, FeeReason::Export { network, destination })?; Config::MessageExporter::deliver(ticket)?; Ok(()) }, @@ -962,7 +962,7 @@ impl XcmExecutor { } else { self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into() }; - Config::FeeManager::handle_fee(paid, Some(&self.context)); + Config::FeeManager::handle_fee(paid, Some(&self.context), reason); Ok(()) } diff --git a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs index 2b2f21927f2..d7146457f3b 100644 --- a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs +++ b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs @@ -18,12 +18,12 @@ use xcm::prelude::*; /// Handle stuff to do with taking fees in certain XCM instructions. pub trait FeeManager { - /// Determine if a fee which would normally payable should be waived. + /// Determine if a fee should be waived. fn is_waived(origin: Option<&MultiLocation>, r: FeeReason) -> bool; /// Do something with the fee which has been paid. Doing nothing here silently burns the /// fees. - fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>); + fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, r: FeeReason); } /// Context under which a fee is paid. @@ -42,7 +42,7 @@ pub enum FeeReason { /// When the `QueryPallet` instruction is called. QueryPallet, /// When the `ExportMessage` instruction is called (and includes the network ID). - Export(NetworkId), + Export { network: NetworkId, destination: InteriorMultiLocation }, /// The `charge_fees` API. ChargeFees, /// When the `LockAsset` instruction is called. @@ -55,5 +55,6 @@ impl FeeManager for () { fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool { false } - fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {} + + fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {} } -- GitLab From b2bb8cbcf3cea421de48bebd3e5a3400964fdf7e Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Wed, 1 Nov 2023 16:16:13 +0100 Subject: [PATCH 413/633] review-bot: prevent request review of core-devs (#2121) This will remove `core-devs` from being required reviewers of PRs, --- .github/review-bot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/review-bot.yml b/.github/review-bot.yml index 581e3376260..b053ead37fb 100644 --- a/.github/review-bot.yml +++ b/.github/review-bot.yml @@ -118,3 +118,7 @@ rules: - minApprovals: 1 teams: - ci + +preventReviewRequests: + teams: + - core-devs -- GitLab From b6965af493eaa277bf7983201311362cf62ce5a9 Mon Sep 17 00:00:00 2001 From: Kevin Krone Date: Wed, 1 Nov 2023 16:28:02 +0100 Subject: [PATCH 414/633] Improve FRAME storage docs (#1714) This is a port (and hopefully a small improvement) of @kianenigma's PR from the old Substrate repo: https://github.com/paritytech/substrate/pull/13987. Following #1689 I moved the documentation of all macros relevant to this PR from `frame_support_procedural` to `pallet_macros` while including a hint for RA users. Question: Again with respect to #1689: Is there a good reason why we should *not* enhance paths with links to our current rustdocs? For example, instead of ```rust /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::storage`. ``` we could write ```rust /// **Rust-Analyzer users**: See the documentation of the Rust item in /// [`frame_support::pallet_macros::storage`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.storage.html). ``` This results in a clickable link like this: image I don't really expect the links to become outdated any time soon, but I think this would be a great UX improvement over just having paths. TODOs: - [ ] Add documentation for `constant_name` macro - [x] Add proper documentation for different `QueryKinds`, i.e. `OptionQuery`, `ValueQuery`, `ResultQuery`. One example for each. Custom `OnEmpty` should be moved to `QueryKinds` trait doc page. - [ ] Rework `type_value` docs --------- Co-authored-by: kianenigma --- substrate/frame/bags-list/Cargo.toml | 30 +- substrate/frame/support/procedural/src/lib.rs | 94 ++--- substrate/frame/support/src/lib.rs | 330 +++++++++++++++++- .../support/src/storage/types/counted_map.rs | 60 +++- .../support/src/storage/types/counted_nmap.rs | 47 ++- .../support/src/storage/types/double_map.rs | 95 ++++- .../frame/support/src/storage/types/map.rs | 46 ++- .../frame/support/src/storage/types/mod.rs | 82 ++++- .../frame/support/src/storage/types/nmap.rs | 60 +++- .../frame/support/src/storage/types/value.rs | 33 +- 10 files changed, 741 insertions(+), 136 deletions(-) diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 05b86f6c723..b99726ebf2d 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -13,17 +13,21 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } # primitives -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } # FRAME -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +frame-election-provider-support = { path = "../election-provider-support", default-features = false } # third party log = { version = "0.4.17", default-features = false } @@ -31,11 +35,11 @@ docify = "0.2.6" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking -frame-benchmarking = { path = "../benchmarking", default-features = false , optional = true} -pallet-balances = { path = "../balances", default-features = false , optional = true} -sp-core = { path = "../../primitives/core", default-features = false , optional = true} -sp-io = { path = "../../primitives/io", default-features = false , optional = true} -sp-tracing = { path = "../../primitives/tracing", default-features = false , optional = true} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +pallet-balances = { path = "../balances", default-features = false, optional = true } +sp-core = { path = "../../primitives/core", default-features = false, optional = true } +sp-io = { path = "../../primitives/io", default-features = false, optional = true } +sp-tracing = { path = "../../primitives/tracing", default-features = false, optional = true } [dev-dependencies] sp-core = { path = "../../primitives/core" } @@ -46,7 +50,7 @@ frame-election-provider-support = { path = "../election-provider-support" } frame-benchmarking = { path = "../benchmarking" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 9c551b9f230..68bf3e4874b 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -979,21 +979,26 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` -/// from [`pallet::config`](`macro@config`) into metadata, e.g.: /// -/// ```ignore -/// #[pallet::config] -/// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type Foo: Get; -/// } -/// ``` +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::constant`. #[proc_macro_attribute] pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::constant_name`. +#[proc_macro_attribute] +pub fn constant_name(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// To bypass the `frame_system::Config` supertrait check, use the attribute /// `pallet::disable_frame_system_supertrait_check`, e.g.: /// @@ -1099,6 +1104,16 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::call`. +#[proc_macro_attribute] +pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, /// which explicitly defines the codec index for the dispatchable function in the `Call` enum. /// @@ -1268,60 +1283,11 @@ pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime -/// storage and also set its metadata. This attribute can be used multiple times. /// -/// Item should be defined as: +/// --- /// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; -/// ``` -/// -/// or with unnamed generic: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<_, $some_generics, ...>; -/// ``` -/// -/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be -/// one of `StorageValue`, `StorageMap` or `StorageDoubleMap`. The generic arguments of the -/// storage type can be given in two manners: named and unnamed. For named generic arguments, -/// the name for each argument should match the name defined for it on the storage struct: -/// * `StorageValue` expects `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `StorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `CountedStorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `StorageDoubleMap` expects `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` and optionally -/// `QueryKind` and `OnEmpty`. -/// -/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the -/// macro and other generic must declared as a normal generic type declaration. -/// -/// The `Prefix` generic written by the macro is generated using -/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names -/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: -/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. -/// -/// For the `CountedStorageMap` variant, the `Prefix` also implements -/// `CountedStorageMapInstance`. It also associates a `CounterPrefix`, which is implemented the -/// same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. if runtime names -/// the pallet "MyExample" then the storage `type Foo = CountedStorageaMap<...>` will store -/// its counter at the prefix: `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageMap; -/// ``` -/// -/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ -/// Twox128(b"OtherName")`. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::storage`. #[proc_macro_attribute] pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1424,6 +1390,9 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_config`. #[proc_macro_attribute] @@ -1431,6 +1400,9 @@ pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_build`. #[proc_macro_attribute] diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 1c696bbb84a..4888b8996d1 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2199,11 +2199,10 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros 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, 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, + call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error, + event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, + inherent, no_default, no_default_bounds, origin, pallet_section, storage_prefix, + storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; /// Allows you to define the genesis configuration for the pallet. @@ -2220,7 +2219,7 @@ pub mod pallet_macros { /// /// The fields of the `GenesisConfig` can in turn be populated by the chain-spec. /// - /// ## Example: + /// ## Example /// /// ``` /// #[frame_support::pallet] @@ -2275,6 +2274,230 @@ pub mod pallet_macros { /// } /// ``` pub use frame_support_procedural::genesis_build; + + /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded + /// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) + /// into metadata. + /// + /// ## Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// use frame_support::pallet_prelude::*; + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// #[pallet::config] + /// pub trait Config: frame_system::Config { + /// /// This is like a normal `Get` trait, but it will be added into metadata. + /// #[pallet::constant] + /// type Foo: Get; + /// } + /// } + /// ``` + pub use frame_support_procedural::constant; + + /// Declares a type alias as a storage item. Storage items are pointers to data stored + /// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on + /// the type of the storage. + /// + /// > From the perspective of this pallet, the entire blockchain state is abstracted behind + /// > a key-value api, namely [`sp_io::storage`]. + /// + /// ## Storage Types + /// + /// The following storage types are supported by the `#[storage]` macro. For specific + /// information about each storage type, refer to the documentation of the respective type. + /// + /// * [`StorageValue`](crate::storage::types::StorageValue) + /// * [`StorageMap`](crate::storage::types::StorageMap) + /// * [`CountedStorageMap`](crate::storage::types::CountedStorageMap) + /// * [`StorageDoubleMap`](crate::storage::types::StorageDoubleMap) + /// * [`StorageNMap`](crate::storage::types::StorageNMap) + /// * [`CountedStorageNMap`](crate::storage::types::CountedStorageNMap) + /// + /// ## Storage Type Usage + /// + /// The following details are relevant to all of the aforementioned storage types. + /// Depending on the exact storage type, it may require the following generic parameters: + /// + /// * [`Prefix`](#prefixes) - Used to give the storage item a unique key in the underlying + /// storage. + /// * `Key` - Type of the keys used to store the values, + /// * `Value` - Type of the value being stored, + /// * [`Hasher`](#hashers) - Used to ensure the keys of a map are uniformly distributed, + /// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying + /// storage, + /// * `OnEmpty` - Used to handle missing values when querying the underlying storage, + /// * `MaxValues` - _not currently used_. + /// + /// Each `Key` type requires its own designated `Hasher` declaration, so that + /// [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) needs two of + /// each, and [`StorageNMap`](frame_support::storage::types::StorageNMap) needs `N` such + /// pairs. Since [`StorageValue`](frame_support::storage::types::StorageValue) only stores + /// a single element, no configuration of hashers is needed. + /// + /// ### Syntax + /// + /// Two general syntaxes are supported, as demonstrated below: + /// + /// 1. Named type parameters, e.g., `type Foo = StorageValue`. + /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. + /// + /// In both instances, declaring the generic parameter `` is mandatory. Optionally, it + /// can also be explicitly declared as ``. In the compiled code, `T` will + /// automatically include the trait bound `Config`. + /// + /// Note that in positional syntax, the first generic type parameter must be `_`. + /// + /// #### Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// /// Positional syntax, without bounding `T`. + /// #[pallet::storage] + /// pub type Foo = StorageValue<_, u32>; + /// + /// /// Positional syntax, with bounding `T`. + /// #[pallet::storage] + /// pub type Bar = StorageValue<_, u32>; + /// + /// /// Named syntax. + /// #[pallet::storage] + /// pub type Baz = StorageMap; + /// } + /// ``` + /// + /// ### QueryKind + /// + /// Every storage type mentioned above has a generic type called + /// [`QueryKind`](frame_support::storage::types::QueryKindTrait) that determines its + /// "query" type. This refers to the kind of value returned when querying the storage, for + /// instance, through a `::get()` method. + /// + /// There are three types of queries: + /// + /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. + /// It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is + /// the value type. + /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself + /// if present; otherwise, it returns `Default::default()`. This behavior can be + /// adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty = + /// GetDefault`. + /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, + /// where `V` is the value type. + /// + /// See [`QueryKind`](frame_support::storage::types::QueryKindTrait) for further examples. + /// + /// ### Optimized Appending + /// + /// All storage items — such as + /// [`StorageValue`](frame_support::storage::types::StorageValue), + /// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an + /// `::append()` method optimized for collections. Using this method avoids the + /// inefficiency of decoding and re-encoding entire collections when adding items. For + /// instance, consider the storage declaration `type MyVal = StorageValue<_, Vec, + /// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you + /// directly add bytes to the end in storage without processing the full list. Depending on + /// the storage type, additional key specifications may be needed. + /// + /// #### Example + #[doc = docify::embed!("src/lib.rs", example_storage_value_append)] + /// Similarly, there also exists a `::try_append()` method, which can be used when handling + /// types where an append operation might fail, such as a + /// [`BoundedVec`](frame_support::BoundedVec). + /// + /// #### Example + #[doc = docify::embed!("src/lib.rs", example_storage_value_try_append)] + /// ### Optimized Length Decoding + /// + /// All storage items — such as + /// [`StorageValue`](frame_support::storage::types::StorageValue), + /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — + /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of + /// a collection's length without the necessity of decoding the entire dataset. + /// #### Example + #[doc = docify::embed!("src/lib.rs", example_storage_value_decode_len)] + /// ### Hashers + /// + /// For all storage types, except + /// [`StorageValue`](frame_support::storage::types::StorageValue), a set of hashers needs + /// to be specified. The choice of hashers is crucial, especially in production chains. The + /// purpose of storage hashers in maps is to ensure the keys of a map are + /// uniformly distributed. An unbalanced map/trie can lead to inefficient performance. + /// + /// In general, hashers are categorized as either cryptographically secure or not. The + /// former is slower than the latter. `Blake2` and `Twox` serve as examples of each, + /// respectively. + /// + /// As a rule of thumb: + /// + /// 1. If the map keys are not controlled by end users, or are cryptographically secure by + /// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT + /// required. + /// 2. If the map keys are controllable by the end users, cryptographically secure hashers + /// should be used. + /// + /// For more information, look at the types that implement + /// [`frame_support::StorageHasher`](frame_support::StorageHasher). + /// + /// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to + /// the implementors section of + /// [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher). + /// + /// ### Prefixes + /// + /// Internally, every storage type generates a "prefix". This prefix serves as the initial + /// segment of the key utilized to store values in the on-chain state (i.e., the final key + /// used in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule + /// applies: + /// + /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(STORAGE_PREFIX)`, + /// > where + /// > `pallet_prefix` is the name assigned to the pallet instance in + /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and + /// > `STORAGE_PREFIX` is the name of the `type` aliased to a particular storage type, such + /// > as + /// > `Foo` in `type Foo = StorageValue<..>`. + /// + /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is + /// required. For map types, the prefix is extended with one or more keys defined by the + /// map. + /// + /// #### Example + #[doc = docify::embed!("src/lib.rs", example_storage_value_map_prefixes)] + /// ## Related Macros + /// + /// The following attribute macros can be used in conjunction with the `#[storage]` macro: + /// + /// * [`macro@getter`]: Creates a custom getter function. + /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. + /// * [`macro@unbounded`]: Declares the storage item as unbounded. + /// + /// #### Example + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// /// A kitchen-sink StorageValue, with all possible additional attributes. + /// #[pallet::storage] + /// #[pallet::getter(fn foo)] + /// #[pallet::storage_prefix = "OtherFoo"] + /// #[pallet::unbounded] + /// pub type Foo = StorageValue<_, u32, ValueQuery>; + /// } + /// ``` + pub use frame_support_procedural::storage; } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] @@ -2291,3 +2514,98 @@ sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); // Helper for implementing GenesisBuilder runtime API pub mod genesis_builder_helper; + +#[cfg(test)] +mod test { + // use super::*; + use crate::{ + hash::*, + storage::types::{StorageMap, StorageValue, ValueQuery}, + traits::{ConstU32, StorageInstance}, + BoundedVec, + }; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct Prefix1; + impl StorageInstance for Prefix1 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyVal"; + } + struct Prefix2; + impl StorageInstance for Prefix2 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyMap"; + } + + #[docify::export] + #[test] + pub fn example_storage_value_try_append() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); + assert_eq!(MyVal::get(), vec![42, 43]); + // Try to append a single u32 to BoundedVec stored in `MyVal` + assert_ok!(MyVal::try_append(40)); + assert_eq!(MyVal::get(), vec![42, 43, 40]); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_append() { + type MyVal = StorageValue, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(vec![42, 43]); + assert_eq!(MyVal::get(), vec![42, 43]); + // Append a single u32 to Vec stored in `MyVal` + MyVal::append(40); + assert_eq!(MyVal::get(), vec![42, 43, 40]); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_decode_len() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); + assert_eq!(MyVal::decode_len().unwrap(), 2); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_map_prefixes() { + type MyVal = StorageValue; + type MyMap = StorageMap; + TestExternalities::default().execute_with(|| { + // This example assumes `pallet_prefix` to be "test" + // Get storage key for `MyVal` StorageValue + assert_eq!( + MyVal::hashed_key().to_vec(), + [twox_128(b"test"), twox_128(b"MyVal")].concat() + ); + // Get storage key for `MyMap` StorageMap and `key` = 1 + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"MyMap")); + k.extend(&1u16.blake2_128_concat()); + assert_eq!(MyMap::hashed_key_for(1).to_vec(), k); + }); + } +} diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 50e2c678248..75fbdf2617d 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -35,8 +35,8 @@ use sp_metadata_ir::StorageEntryMetadataIR; use sp_runtime::traits::Saturating; use sp_std::prelude::*; -/// A wrapper around a `StorageMap` and a `StorageValue` to keep track of how many items -/// are in a map, without needing to iterate all the values. +/// A wrapper around a [`StorageMap`] and a [`StorageValue`] (with the value being `u32`) to keep +/// track of how many items are in a map, without needing to iterate all the values. /// /// This storage item has additional storage read and write overhead when manipulating values /// compared to a regular storage map. @@ -47,6 +47,51 @@ use sp_std::prelude::*; /// /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. +/// +/// The total number of items currently stored in the map can be retrieved with the +/// [`CountedStorageMap::count`] method. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Examples +/// +/// Declaring a counted map: +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink CountedStorageMap, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = CountedStorageMap< +/// _, +/// Blake2_128Concat, +/// u32, +/// u32, +/// ValueQuery, +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = CountedStorageMap< +/// Hasher = Blake2_128Concat, +/// Key = u32, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } +/// ``` +/// +/// Using a counted map in action: +#[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)] pub struct CountedStorageMap< Prefix, Hasher, @@ -1173,4 +1218,15 @@ mod test { ] ); } + + #[docify::export] + #[test] + fn test_simple_count_works() { + type FooCountedMap = CountedStorageMap; + TestExternalities::default().execute_with(|| { + FooCountedMap::insert(1, 1); + FooCountedMap::insert(2, 2); + assert_eq!(FooCountedMap::count(), 2); + }); + } } diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 5da31c05922..c2c2197acee 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -33,8 +33,8 @@ use sp_metadata_ir::StorageEntryMetadataIR; use sp_runtime::traits::Saturating; use sp_std::prelude::*; -/// A wrapper around a `StorageNMap` and a `StorageValue` to keep track of how many items -/// are in a map, without needing to iterate over all of the values. +/// A wrapper around a [`StorageNMap`] and a [`StorageValue`] (with the value being `u32`) to keep +/// track of how many items are in a map, without needing to iterate all the values. /// /// This storage item has some additional storage read and write overhead when manipulating values /// compared to a regular storage map. @@ -45,6 +45,49 @@ use sp_std::prelude::*; /// /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink CountedStorageNMap, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = CountedStorageNMap< +/// _, +/// ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// u64, +/// ValueQuery, +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = CountedStorageNMap< +/// Key = ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// Value = u64, +/// QueryKind = ValueQuery, +/// >; +/// } +/// ``` pub struct CountedStorageNMap< Prefix, Key, diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 519ffcbafad..1002222a895 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -31,22 +31,66 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type that allow to store values for `(key1, key2)` couple. Similar to `StorageMap` but allow -/// to iterate and remove value associated to first key. +/// A type representing a *double map* in storage. This structure associates a pair of keys with a +/// value of a specified type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key1)) -/// ++ Hasher2(encode(key2)) +/// A double map with keys `k1` and `k2` can be likened to a +/// [`StorageMap`](frame_support::storage::types::StorageMap) with a key of type `(k1, k2)`. +/// However, a double map offers functions specific to each key, enabling partial iteration and +/// deletion based on one key alone. +/// +/// Also, conceptually, a double map is a special case of a +/// [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Examples +/// +/// ### Kitchen-sink +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink StorageDoubleMap, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageDoubleMap< +/// _, +/// Blake2_128Concat, +/// u8, +/// Twox64Concat, +/// u16, +/// u32, +/// ValueQuery +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = StorageDoubleMap< +/// Hasher1 = Blake2_128Concat, +/// Key1 = u8, +/// Hasher2 = Twox64Concat, +/// Key2 = u16, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } /// ``` /// -/// # Warning +/// ### Partial Iteration & Removal /// -/// If the key1s (or key2s) are not trusted (e.g. can be set by a user), a cryptographic `hasher` -/// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values -/// in storage can be compromised. +/// When `Hasher1` and `Hasher2` implement the +/// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, the first key `k1` +/// can be used to partially iterate over keys and values of the double map, and to delete items. +#[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_operations)] pub struct StorageDoubleMap< Prefix, Hasher1, @@ -742,6 +786,7 @@ mod test { use crate::{hash::*, storage::types::ValueQuery}; use sp_io::{hashing::twox_128, TestExternalities}; use sp_metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR}; + use std::collections::BTreeSet; struct Prefix; impl StorageInstance for Prefix { @@ -972,4 +1017,30 @@ mod test { assert_eq!(A::drain_prefix(4).collect::>(), vec![]); }) } + + #[docify::export] + #[test] + fn example_double_map_partial_operations() { + type FooDoubleMap = + StorageDoubleMap; + + TestExternalities::default().execute_with(|| { + FooDoubleMap::insert(0, 0, 42); + FooDoubleMap::insert(0, 1, 43); + FooDoubleMap::insert(1, 0, 314); + + // should be equal to {0,1} (ordering is random) + let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0).collect(); + assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::>()); + + // should be equal to {42,43} (ordering is random) + let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0).collect(); + assert_eq!(collected_k2_values, [42, 43].iter().copied().collect::>()); + + // Remove items from the map using k1 = 0 + let _ = FooDoubleMap::clear_prefix(0, u32::max_value(), None); + // Values associated with (0, _) should have been removed + assert_eq!(FooDoubleMap::iter_prefix(0).collect::>(), vec![]); + }); + } } diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 7f936a8a35a..81a3dd270d8 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -31,19 +31,45 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type that allow to store value for given key. Allowing to insert/remove/iterate on values. +/// A type representing a *map* in storage. A *storage map* is a mapping of keys to values of a +/// given type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key)) -/// ``` +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example /// -/// # Warning +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink StorageMap, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageMap< +/// _ +/// Blake2_128Concat, +/// u32, +/// u32, +/// ValueQuery +/// >; /// -/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as -/// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised. +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = StorageMap< +/// Hasher = Blake2_128Concat, +/// Key = u32, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } +/// ``` pub struct StorageMap< Prefix, Hasher, diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index c7f2557099b..1d995d93e88 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -43,13 +43,17 @@ pub use value::StorageValue; /// Trait implementing how the storage optional value is converted into the queried type. /// -/// It is implemented by: -/// * `OptionQuery` which converts an optional value to an optional value, used when querying +/// It is implemented most notable by: +/// +/// * [`OptionQuery`] which converts an optional value to an optional value, used when querying /// storage returns an optional value. -/// * `ResultQuery` which converts an optional value to a result value, used when querying storage +/// * [`ResultQuery`] which converts an optional value to a result value, used when querying storage /// returns a result value. -/// * `ValueQuery` which converts an optional value to a value, used when querying storage returns a -/// value. +/// * [`ValueQuery`] which converts an optional value to a value, used when querying storage returns +/// a value. +/// +/// ## Example +#[doc = docify::embed!("src/storage/types/mod.rs", value_query_examples)] pub trait QueryKindTrait { /// Metadata for the storage kind. const METADATA: StorageEntryModifierIR; @@ -65,11 +69,10 @@ pub trait QueryKindTrait { fn from_query_to_optional_value(v: Self::Query) -> Option; } -/// Implement QueryKindTrait with query being `Option` +/// Implements [`QueryKindTrait`] with `Query` type being `Option<_>`. /// -/// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be -/// returned when no value is found. To use another `OnEmpty` implementation, `ValueQuery` can be -/// used instead. +/// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be returned when no +/// value is found. To use another `OnEmpty` implementation, `ValueQuery` can be used instead. pub struct OptionQuery; impl QueryKindTrait for OptionQuery where @@ -89,7 +92,7 @@ where } } -/// Implement QueryKindTrait with query being `Result` +/// Implements [`QueryKindTrait`] with `Query` type being `Result`. pub struct ResultQuery(sp_std::marker::PhantomData); impl QueryKindTrait for ResultQuery where @@ -113,7 +116,7 @@ where } } -/// Implement QueryKindTrait with query being `Value` +/// Implements [`QueryKindTrait`] with `Query` type being `Value`. pub struct ValueQuery; impl QueryKindTrait for ValueQuery where @@ -140,3 +143,60 @@ pub trait StorageEntryMetadataBuilder { /// Build into `entries` the storage metadata entries of a storage given some `docs`. fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); } + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + storage::types::ValueQuery, + traits::{Get, StorageInstance}, + }; + use sp_io::TestExternalities; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + #[docify::export] + #[test] + pub fn value_query_examples() { + /// Custom default impl to be used with `ValueQuery`. + struct UniverseSecret; + impl Get for UniverseSecret { + fn get() -> u32 { + 42 + } + } + + /// Custom default impl to be used with `ResultQuery`. + struct GetDefaultForResult; + impl Get> for GetDefaultForResult { + fn get() -> Result { + Err(()) + } + } + + type A = StorageValue; + type B = StorageValue; + type C = StorageValue, GetDefaultForResult>; + type D = StorageValue; + + TestExternalities::default().execute_with(|| { + // normal value query returns default + assert_eq!(A::get(), 0); + + // option query returns none + assert_eq!(B::get(), None); + + // result query returns error + assert_eq!(C::get(), Err(())); + + // value query with custom onempty returns 42 + assert_eq!(D::get(), 42); + }); + } +} diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index 406fd42eaf7..0723db68900 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -33,24 +33,54 @@ use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_runtime::SaturatedConversion; use sp_std::prelude::*; -/// A type that allow to store values for an arbitrary number of keys in the form of -/// `(Key, Key, ..., Key)`. +/// A type representing an *NMap* in storage. This structure associates an arbitrary number of keys +/// with a value of a specified type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key1)) -/// ++ Hasher2(encode(key2)) -/// ++ ... -/// ++ HasherN(encode(keyN)) -/// ``` +/// For example, [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) is a special +/// case of an *NMap* with N = 2. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. /// -/// # Warning +/// # Example /// -/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` -/// such as `blake2_128_concat` must be used for the key hashers. Otherwise, other values -/// in storage can be compromised. +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink StorageNMap, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageNMap< +/// _, +/// ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// u64, +/// ValueQuery, +/// >; +/// +/// /// Named alternative syntax. +/// #[pallet::storage] +/// pub type Bar = StorageNMap< +/// Key = ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// Value = u64, +/// QueryKind = ValueQuery, +/// >; +/// } +/// ``` pub struct StorageNMap< Prefix, Key, diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 3e1f2fe9551..9fff1774d7b 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -30,11 +30,36 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type that allow to store a value. +/// A type representing a *value* in storage. A *storage value* is a single value of a given type +/// stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink StorageValue, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageValue<_, u32,ValueQuery>; +/// +/// /// Named alternative syntax. +/// #[pallet::storage] +/// pub type Bar = StorageValue< +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } /// ``` pub struct StorageValue( core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, -- GitLab From 9987bbb1d264672d406071fb2e164e4e80117e13 Mon Sep 17 00:00:00 2001 From: jserrat <35823283+Jpserrat@users.noreply.github.com> Date: Wed, 1 Nov 2023 13:11:35 -0300 Subject: [PATCH 415/633] Remove transitional code wrt executor parameters (#2112) --- polkadot/runtime/parachains/src/runtime_api_impl/v7.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs index 35d92f71084..4d0bbc6a896 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs @@ -370,15 +370,7 @@ pub fn get_session_disputes( pub fn session_executor_params( session_index: SessionIndex, ) -> Option { - // This is to bootstrap the storage working around the runtime migration issue: - // https://github.com/paritytech/substrate/issues/9997 - // After the bootstrap is complete (no less than 7 session passed with the runtime) - // this code should be replaced with a pure - // >::session_executor_params(session_index) call. - match >::session_executor_params(session_index) { - Some(ep) => Some(ep), - None => Some(ExecutorParams::default()), - } + >::session_executor_params(session_index) } /// Implementation of `unapplied_slashes` runtime API -- GitLab From 49c0f33baed01c56260beabbbbdb5cf049f7e7c9 Mon Sep 17 00:00:00 2001 From: Daniel Moos Date: Wed, 1 Nov 2023 20:41:28 +0100 Subject: [PATCH 416/633] fix substrate-node-template generation (#2050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description This PR updates the node-template-release generation binary as well as the `node-template-release.sh` file so that we can automatically push updates to the [substrate-node-template repository](https://github.com/substrate-developer-hub/substrate-node-template). I assume this part was not updated after the substrate project has been moved into the polkadot-sdk mono repo. # Adjustments - extend the `node-template-release.sh` to support the substrate child-folder - update the `SUBSTRATE_GIT_URL` - fix the Cargo.toml filter (so that it does not include any non-relevant .toml files) - set the workspace-edition to 2021 # Note In order to auto-generate the artifacts [this line](https://github.com/paritytech/polkadot-sdk/blob/master/.gitlab/pipeline/build.yml#L320C15-L320C15) needs to be included in the build.yml script again. Since I do not have access to the (probably) internal gitlab environment I hope that someone with actual access can introduce that change. I also do not know how the auto-publish feature works so that would be another thing to add later on. --------- Co-authored-by: Bastian Köcher --- substrate/scripts/ci/node-template-release.sh | 6 ++++-- .../scripts/ci/node-template-release/src/main.rs | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/substrate/scripts/ci/node-template-release.sh b/substrate/scripts/ci/node-template-release.sh index 09ef98e0462..bc57b0f538e 100755 --- a/substrate/scripts/ci/node-template-release.sh +++ b/substrate/scripts/ci/node-template-release.sh @@ -3,7 +3,9 @@ set -e export TERM=xterm -PROJECT_ROOT=`git rev-parse --show-toplevel` +SUBSTRATE_FOLDER="/substrate" +GIT_ROOT=`git rev-parse --show-toplevel` +PROJECT_ROOT=${GIT_ROOT}${SUBSTRATE_FOLDER} if [ "$#" -ne 1 ]; then echo "node-template-release.sh path_to_target_archive" @@ -11,6 +13,6 @@ if [ "$#" -ne 1 ]; then fi PATH_TO_ARCHIVE=$1 -cd $PROJECT_ROOT/scripts/ci/node-template-release +cd $PROJECT_ROOT/scripts/ci/node-template-release cargo run $PROJECT_ROOT/bin/node-template $PROJECT_ROOT/$PATH_TO_ARCHIVE diff --git a/substrate/scripts/ci/node-template-release/src/main.rs b/substrate/scripts/ci/node-template-release/src/main.rs index 850535e4045..fc8089f3051 100644 --- a/substrate/scripts/ci/node-template-release/src/main.rs +++ b/substrate/scripts/ci/node-template-release/src/main.rs @@ -32,7 +32,7 @@ use tar; use tempfile; use toml_edit::{self, value, Array, Item, Table}; -const SUBSTRATE_GIT_URL: &str = "https://github.com/paritytech/substrate.git"; +const SUBSTRATE_GIT_URL: &str = "https://github.com/paritytech/polkadot-sdk.git"; type CargoToml = toml_edit::Document; @@ -63,7 +63,7 @@ fn copy_node_template(node_template: &Path, dest_path: &Path) { /// Find all `Cargo.toml` files in the given path. fn find_cargo_tomls(path: &PathBuf) -> Vec { - let path = format!("{}/**/*.toml", path.display()); + let path = format!("{}/**/Cargo.toml", path.display()); let glob = glob::glob(&path).expect("Generates globbing pattern"); @@ -196,7 +196,6 @@ fn update_root_cargo_toml( ) { let mut workspace = Table::new(); workspace.insert("members", value(Array::from_iter(members.iter()))); - let mut workspace_dependencies = Table::new(); deps.values() .flatten() @@ -212,6 +211,10 @@ fn update_root_cargo_toml( workspace_dependencies[name]["rev"] = value(commit_id); }); + let mut package = Table::new(); + package.insert("edition", value("2021")); + workspace.insert("package", Item::Table(package)); + workspace.insert("dependencies", Item::Table(workspace_dependencies)); cargo_toml.insert("workspace", Item::Table(workspace)); @@ -428,9 +431,12 @@ frame-system = { workspace = true } let expected_toml = r#"[workspace] members = ["node", "pallets/template", "runtime"] +[workspace.package] +edition = "2021" + [workspace.dependencies] -frame-system = { version = "4.0.0-dev", default-features = true, git = "https://github.com/paritytech/substrate.git", rev = "commit_id" } -sp-io = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", rev = "commit_id" } +frame-system = { version = "4.0.0-dev", default-features = true, git = "https://github.com/paritytech/polkadot-sdk.git", rev = "commit_id" } +sp-io = { version = "7.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "commit_id" } [profile] -- GitLab From 4f05f9a6865b73221d618e7ec139e97fe71e8d72 Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Thu, 2 Nov 2023 04:20:53 +0800 Subject: [PATCH 417/633] Build workers for testing on demand (#2018) --- polkadot/node/core/pvf/src/testing.rs | 54 +++++++++++++++++++-------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 31bcfe7fadb..169b55d34b5 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -55,13 +55,35 @@ pub fn validate_candidate( Ok(result) } -/// Retrieves the worker paths, checks that they exist and does a version check. +/// Retrieves the worker paths and builds workers as needed. /// /// NOTE: This should only be called in dev code (tests, benchmarks) as it relies on the relative /// paths of the built workers. pub fn get_and_check_worker_paths() -> (PathBuf, PathBuf) { // Only needs to be called once for the current process. static WORKER_PATHS: OnceLock> = OnceLock::new(); + + fn build_workers() { + let build_args = vec![ + "build", + "--package=polkadot", + "--bin=polkadot-prepare-worker", + "--bin=polkadot-execute-worker", + ]; + let exit_status = std::process::Command::new("cargo") + // wasm runtime not needed + .env("SKIP_WASM_BUILD", "1") + .args(build_args) + .stdout(std::process::Stdio::piped()) + .status() + .expect("Failed to run the build program"); + + if !exit_status.success() { + eprintln!("Failed to build workers: {}", exit_status.code().unwrap()); + std::process::exit(1); + } + } + let mutex = WORKER_PATHS.get_or_init(|| { let mut workers_path = std::env::current_exe().unwrap(); workers_path.pop(); @@ -71,25 +93,25 @@ pub fn get_and_check_worker_paths() -> (PathBuf, PathBuf) { let mut execute_worker_path = workers_path.clone(); execute_worker_path.push(EXECUTE_BINARY_NAME); - // Check that the workers are valid. - if !prepare_worker_path.is_executable() || !execute_worker_path.is_executable() { - panic!("ERROR: Workers do not exist or are not executable. Workers directory: {:?}", workers_path); + // explain why a build happens + if !prepare_worker_path.is_executable() { + eprintln!("Prepare worker does not exist or is not executable. Workers directory: {:?}", workers_path); } - - let worker_version = - get_worker_version(&prepare_worker_path).expect("checked for worker existence"); - if worker_version != NODE_VERSION { - panic!("ERROR: Prepare worker version {worker_version} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}"); + if !execute_worker_path.is_executable() { + eprintln!("Execute worker does not exist or is not executable. Workers directory: {:?}", workers_path); + } + if let Ok(ver) = get_worker_version(&prepare_worker_path) { + if ver != NODE_VERSION { + eprintln!("Prepare worker version {ver} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}"); + } } - let worker_version = - get_worker_version(&execute_worker_path).expect("checked for worker existence"); - if worker_version != NODE_VERSION { - panic!("ERROR: Execute worker version {worker_version} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}"); + if let Ok(ver) = get_worker_version(&execute_worker_path) { + if ver != NODE_VERSION { + eprintln!("Execute worker version {ver} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}"); + } } - // We don't want to check against the commit hash because we'd have to always rebuild - // the calling crate on every commit. - eprintln!("WARNING: Workers match the node version, but may have changed in recent commits. Please rebuild them if anything funny happens. Workers path: {workers_path:?}"); + build_workers(); Mutex::new((prepare_worker_path, execute_worker_path)) }); -- GitLab From c66ae375e6a76a1ae3ec93266b818ba70bcd53a7 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 1 Nov 2023 22:11:28 +0100 Subject: [PATCH 418/633] [FRAME] Short-circuit fungible self transfer (#2118) Changes: - Change the fungible(s) logic to treat a self-transfer as No-OP (as long as all pre-checks pass). Note that the self-transfer case will not emit an event since no state was changed. --------- Signed-off-by: Oliver Tale-Yazdi --- bridges/primitives/relayers/src/lib.rs | 2 +- cumulus/primitives/utility/src/lib.rs | 6 +-- .../xcm/xcm-builder/src/fungibles_adapter.rs | 8 +-- .../balances/src/tests/currency_tests.rs | 54 ++++++++++++++++--- substrate/frame/broker/src/test_fungibles.rs | 2 +- substrate/frame/nis/src/lib.rs | 2 +- .../src/traits/tokens/fungible/item_of.rs | 2 +- .../src/traits/tokens/fungible/regular.rs | 12 ++++- .../src/traits/tokens/fungibles/regular.rs | 12 ++++- .../frame/support/src/traits/tokens/pay.rs | 12 +++-- 10 files changed, 89 insertions(+), 23 deletions(-) diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index c529eea536d..c808c437b54 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -115,7 +115,7 @@ where impl PaymentProcedure for PayRewardFromAccount where T: frame_support::traits::fungible::Mutate, - Relayer: Decode + Encode, + Relayer: Decode + Encode + Eq, { type Error = sp_runtime::DispatchError; diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index c4ce6719485..03f827d7ee2 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -102,7 +102,7 @@ struct AssetTraderRefunder { /// Important: Errors if the Trader is being called twice by 2 BuyExecution instructions /// Alternatively we could just return payment in the aforementioned case pub struct TakeFirstAssetTrader< - AccountId, + AccountId: Eq, FeeCharger: ChargeWeightInFungibles, Matcher: MatchesFungibles, ConcreteAssets: fungibles::Mutate + fungibles::Balanced, @@ -112,7 +112,7 @@ pub struct TakeFirstAssetTrader< PhantomData<(AccountId, FeeCharger, Matcher, ConcreteAssets, HandleRefund)>, ); impl< - AccountId, + AccountId: Eq, FeeCharger: ChargeWeightInFungibles, Matcher: MatchesFungibles, ConcreteAssets: fungibles::Mutate + fungibles::Balanced, @@ -241,7 +241,7 @@ impl< } impl< - AccountId, + AccountId: Eq, FeeCharger: ChargeWeightInFungibles, Matcher: MatchesFungibles, ConcreteAssets: fungibles::Mutate + fungibles::Balanced, diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index b2802c90809..63ce608824e 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -34,7 +34,7 @@ impl< Assets: fungibles::Mutate, Matcher: MatchesFungibles, AccountIdConverter: ConvertLocation, - AccountId: Clone, // can't get away without it since Currency is generic over it. + AccountId: Eq + Clone, /* can't get away without it since Currency is generic over it. */ > TransactAsset for FungiblesTransferAdapter { fn internal_transfer_asset( @@ -150,7 +150,7 @@ impl< Assets: fungibles::Mutate, Matcher: MatchesFungibles, AccountIdConverter: ConvertLocation, - AccountId: Clone, // can't get away without it since Currency is generic over it. + AccountId: Eq + Clone, /* can't get away without it since Currency is generic over it. */ CheckAsset: AssetChecking, CheckingAccount: Get, > @@ -185,7 +185,7 @@ impl< Assets: fungibles::Mutate, Matcher: MatchesFungibles, AccountIdConverter: ConvertLocation, - AccountId: Clone, // can't get away without it since Currency is generic over it. + AccountId: Eq + Clone, /* can't get away without it since Currency is generic over it. */ CheckAsset: AssetChecking, CheckingAccount: Get, > TransactAsset @@ -325,7 +325,7 @@ impl< Assets: fungibles::Mutate, Matcher: MatchesFungibles, AccountIdConverter: ConvertLocation, - AccountId: Clone, // can't get away without it since Currency is generic over it. + AccountId: Eq + Clone, /* can't get away without it since Currency is generic over it. */ CheckAsset: AssetChecking, CheckingAccount: Get, > TransactAsset diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 200df9ae743..46a4c4caefc 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -18,14 +18,18 @@ //! Tests regarding the functionality of the `Currency` trait set implementations. use super::*; -use crate::NegativeImbalance; -use frame_support::traits::{ - BalanceStatus::{Free, Reserved}, - Currency, - ExistenceRequirement::{self, AllowDeath, KeepAlive}, - Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, - WithdrawReasons, +use crate::{Event, NegativeImbalance}; +use frame_support::{ + traits::{ + BalanceStatus::{Free, Reserved}, + Currency, + ExistenceRequirement::{self, AllowDeath, KeepAlive}, + Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, + WithdrawReasons, + }, + StorageNoopGuard, }; +use frame_system::Event as SysEvent; const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; @@ -1363,3 +1367,39 @@ fn freezing_and_locking_should_work() { assert_eq!(System::consumers(&1), 0); }); } + +#[test] +fn self_transfer_noop() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + assert_eq!(Balances::total_issuance(), 0); + let _ = Balances::deposit_creating(&1, 100); + + // The account is set up properly: + assert_eq!( + events(), + [ + Event::Deposit { who: 1, amount: 100 }.into(), + SysEvent::NewAccount { account: 1 }.into(), + Event::Endowed { account: 1, free_balance: 100 }.into(), + ] + ); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(Balances::total_issuance(), 100); + + // Transfers to self are No-OPs: + let _g = StorageNoopGuard::new(); + for i in 0..200 { + let r = Balances::transfer_allow_death(Some(1).into(), 1, i); + + if i <= 100 { + assert_ok!(r); + } else { + assert!(r.is_err()); + } + + assert!(events().is_empty()); + assert_eq!(Balances::free_balance(1), 100, "Balance unchanged by self transfer"); + assert_eq!(Balances::total_issuance(), 100, "TI unchanged by self transfers"); + } + }); +} diff --git a/substrate/frame/broker/src/test_fungibles.rs b/substrate/frame/broker/src/test_fungibles.rs index f6ac5a49ded..d18bff14953 100644 --- a/substrate/frame/broker/src/test_fungibles.rs +++ b/substrate/frame/broker/src/test_fungibles.rs @@ -168,7 +168,7 @@ where impl< Instance: Get, - AccountId: Encode, + AccountId: Encode + Eq, AssetId: tokens::AssetId + Copy, MinimumBalance: TypedGet, HoldReason, diff --git a/substrate/frame/nis/src/lib.rs b/substrate/frame/nis/src/lib.rs index decebbd5676..5e547b63e54 100644 --- a/substrate/frame/nis/src/lib.rs +++ b/substrate/frame/nis/src/lib.rs @@ -148,7 +148,7 @@ impl fungible::Unbalanced for NoCounterpart { } fn set_total_issuance(_: Self::Balance) {} } -impl FunMutate for NoCounterpart {} +impl FunMutate for NoCounterpart {} impl Convert for NoCounterpart { fn convert(_: Perquintill) -> u32 { 0 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 a47998eb134..636866ab93c 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -219,7 +219,7 @@ impl< impl< F: fungibles::Mutate, A: Get<>::AssetId>, - AccountId, + AccountId: Eq, > Mutate for ItemOf { fn mint_into(who: &AccountId, amount: Self::Balance) -> Result { diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index fe2a1f2a14a..f2fb5c5f7c2 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -235,7 +235,10 @@ pub trait Unbalanced: Inspect { } /// Trait for providing a basic fungible asset. -pub trait Mutate: Inspect + Unbalanced { +pub trait Mutate: Inspect + Unbalanced +where + AccountId: Eq, +{ /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't /// possible then an `Err` is returned and nothing is changed. fn mint_into(who: &AccountId, amount: Self::Balance) -> Result { @@ -303,6 +306,9 @@ pub trait Mutate: Inspect + Unbalanced { } /// Transfer funds from one account into another. + /// + /// A transfer where the source and destination account are identical is treated as No-OP after + /// checking the preconditions. fn transfer( source: &AccountId, dest: &AccountId, @@ -311,6 +317,10 @@ pub trait Mutate: Inspect + Unbalanced { ) -> Result { let _extra = Self::can_withdraw(source, amount).into_result(preservation != Expendable)?; Self::can_deposit(dest, amount, Extant).into_result()?; + if source == dest { + return Ok(amount) + } + Self::decrease_balance(source, amount, BestEffort, preservation, Polite)?; // This should never fail as we checked `can_deposit` earlier. But we do a best-effort // anyway. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index 7c39acdf424..a2fc4e55095 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -250,7 +250,10 @@ pub trait Unbalanced: Inspect { } /// Trait for providing a basic fungible asset. -pub trait Mutate: Inspect + Unbalanced { +pub trait Mutate: Inspect + Unbalanced +where + AccountId: Eq, +{ /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't /// possible then an `Err` is returned and nothing is changed. fn mint_into( @@ -353,6 +356,9 @@ pub trait Mutate: Inspect + Unbalanced { } /// Transfer funds from one account into another. + /// + /// A transfer where the source and destination account are identical is treated as No-OP after + /// checking the preconditions. fn transfer( asset: Self::AssetId, source: &AccountId, @@ -363,6 +369,10 @@ pub trait Mutate: Inspect + Unbalanced { let _extra = Self::can_withdraw(asset.clone(), source, amount) .into_result(preservation != Expendable)?; Self::can_deposit(asset.clone(), dest, amount, Extant).into_result()?; + if source == dest { + return Ok(amount) + } + Self::decrease_balance(asset.clone(), source, amount, BestEffort, preservation, Polite)?; // This should never fail as we checked `can_deposit` earlier. But we do a best-effort // anyway. diff --git a/substrate/frame/support/src/traits/tokens/pay.rs b/substrate/frame/support/src/traits/tokens/pay.rs index 18af7e5e548..4d1d80b5b50 100644 --- a/substrate/frame/support/src/traits/tokens/pay.rs +++ b/substrate/frame/support/src/traits/tokens/pay.rs @@ -82,8 +82,13 @@ pub enum PaymentStatus { } /// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account. -pub struct PayFromAccount(sp_std::marker::PhantomData<(F, A)>); -impl> Pay for PayFromAccount { +pub struct PayFromAccount(core::marker::PhantomData<(F, A)>); +impl Pay for PayFromAccount +where + A: TypedGet, + F: fungible::Mutate, + A::Type: Eq, +{ type Balance = F::Balance; type Beneficiary = A::Type; type AssetKind = (); @@ -110,11 +115,12 @@ impl> Pay for PayFromAccount { /// 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)>); +pub struct PayAssetFromAccount(core::marker::PhantomData<(F, A)>); impl frame_support::traits::tokens::Pay for PayAssetFromAccount where A: TypedGet, F: fungibles::Mutate + fungibles::Create, + A::Type: Eq, { type Balance = F::Balance; type Beneficiary = A::Type; -- GitLab From 1b1fab0da343cc7dcdbd89cebb021eef731108cb Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 2 Nov 2023 00:39:49 +0100 Subject: [PATCH 419/633] [testnet] Add `AssetHubRococo` <-> `AssetHubWestend` asset bridging support (#1967) ## Summary Asset bridging support for AssetHub**Rococo** <-> AssetHub**Wococo** was added [here](https://github.com/paritytech/polkadot-sdk/pull/1215), so now we aim to bridge AssetHub**Rococo** and AssetHub**Westend**. (And perhaps retire AssetHubWococo and the Wococo chains). ## Solution **bridge-hub-westend-runtime** - added new runtime as a copy of `bridge-hub-rococo-runtime` - added support for bridging to `BridgeHubRococo` - added tests and benchmarks **bridge-hub-rococo-runtime** - added support for bridging to `BridgeHubWestend` - added tests and benchmarks - internal refactoring by splitting bridge configuration per network, e.g., `bridge_to_whatevernetwork_config.rs`. **asset-hub-rococo-runtime** - added support for asset bridging to `AssetHubWestend` (allows to receive only WNDs) - added new xcm router for `Westend` - added tests and benchmarks **asset-hub-westend-runtime** - added support for asset bridging to `AssetHubRococo` (allows to receive only ROCs) - added new xcm router for `Rococo` - added tests and benchmarks ## Deployment All changes will be deployed as a part of https://github.com/paritytech/polkadot-sdk/issues/1988. ## TODO - [x] benchmarks for all pallet instances - [x] integration tests - [x] local run scripts Relates to: https://github.com/paritytech/parity-bridges-common/issues/2602 Relates to: https://github.com/paritytech/polkadot-sdk/issues/1988 --------- Co-authored-by: command-bot <> Co-authored-by: Adrian Catangiu Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 127 +- Cargo.toml | 4 + bridges/modules/relayers/src/lib.rs | 44 +- .../modules/xcm-bridge-hub-router/src/lib.rs | 2 +- .../chain-asset-hub-rococo/src/lib.rs | 7 +- .../chain-asset-hub-westend/Cargo.toml | 26 + .../chain-asset-hub-westend/src/lib.rs | 52 + .../chain-asset-hub-wococo/src/lib.rs | 4 +- .../chain-bridge-hub-rococo/src/lib.rs | 8 +- .../chain-bridge-hub-westend/Cargo.toml | 34 + .../chain-bridge-hub-westend/src/lib.rs | 75 ++ .../chain-bridge-hub-wococo/src/lib.rs | 5 +- .../chain-polkadot-bulletin/Cargo.toml | 4 +- bridges/primitives/chain-rococo/Cargo.toml | 2 +- bridges/primitives/chain-westend/Cargo.toml | 32 + bridges/primitives/chain-westend/src/lib.rs | 79 ++ bridges/primitives/runtime/src/lib.rs | 4 +- bridges/scripts/verify-pallets-build.sh | 1 - bridges/zombienet/README.md | 31 + .../best-finalized-header-at-bridged-chain.js | 25 + bridges/zombienet/helpers/relayer-rewards.js | 28 + .../helpers/wrapped-assets-balance.js | 26 + bridges/zombienet/run-tests.sh | 97 ++ bridges/zombienet/scripts/invoke-script.sh | 5 + bridges/zombienet/scripts/sync-exit.sh | 14 + ...sset-transfer-works-rococo-to-wococo.zndsl | 25 + ...sset-transfer-works-wococo-to-rococo.zndsl | 25 + bridges/zombienet/tests/0001-start-relay.sh | 5 + .../src/tests/reserve_transfer.rs | 6 +- .../src/tests/reserve_transfer.rs | 5 +- .../bridge-hub-rococo/src/tests/example.rs | 2 +- .../emulated/common/src/constants.rs | 18 +- .../assets/asset-hub-rococo/Cargo.toml | 2 + .../assets/asset-hub-rococo/src/lib.rs | 56 +- .../asset-hub-rococo/src/weights/mod.rs | 1 + .../pallet_xcm_bridge_hub_router_to_rococo.rs | 52 +- ...pallet_xcm_bridge_hub_router_to_westend.rs | 130 ++ .../pallet_xcm_bridge_hub_router_to_wococo.rs | 52 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 40 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 216 ++-- .../assets/asset-hub-rococo/src/xcm_config.rs | 174 ++- .../assets/asset-hub-rococo/tests/tests.rs | 347 +++--- .../assets/asset-hub-westend/Cargo.toml | 15 +- .../assets/asset-hub-westend/src/lib.rs | 76 +- .../asset-hub-westend/src/weights/mod.rs | 1 + .../weights/pallet_xcm_bridge_hub_router.rs | 124 ++ .../asset-hub-westend/src/weights/xcm/mod.rs | 2 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 87 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 202 ++-- .../asset-hub-westend/src/xcm_config.rs | 204 +++- .../assets/asset-hub-westend/tests/tests.rs | 235 +++- .../parachains/runtimes/bridge-hubs/README.md | 124 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 + .../src/bridge_common_config.rs | 25 + ...o_config.rs => bridge_to_rococo_config.rs} | 45 +- .../src/bridge_to_westend_config.rs | 322 +++++ ...o_config.rs => bridge_to_wococo_config.rs} | 47 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 281 ++++- .../bridge-hub-rococo/src/weights/mod.rs | 28 + .../src/weights/pallet_bridge_grandpa.rs | 81 -- .../pallet_bridge_grandpa_rococo_finality.rs | 20 +- .../pallet_bridge_grandpa_westend_finality.rs | 83 ++ .../pallet_bridge_grandpa_wococo_finality.rs | 20 +- .../src/weights/pallet_bridge_messages.rs | 231 ---- ...allet_bridge_messages_rococo_to_westend.rs | 245 ++++ ...pallet_bridge_messages_rococo_to_wococo.rs | 144 +-- ...pallet_bridge_messages_wococo_to_rococo.rs | 144 +-- .../src/weights/pallet_bridge_parachains.rs | 113 -- .../pallet_bridge_parachains_within_rococo.rs | 23 +- ...pallet_bridge_parachains_within_westend.rs | 116 ++ .../pallet_bridge_parachains_within_wococo.rs | 27 +- .../src/weights/pallet_bridge_relayers.rs | 24 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 92 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 242 ++-- .../bridge-hub-rococo/src/xcm_config.rs | 107 +- .../bridge-hub-rococo/tests/tests.rs | 163 ++- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 239 ++++ .../bridge-hubs/bridge-hub-westend/build.rs | 26 + .../src/bridge_common_config.rs | 50 + .../src/bridge_to_rococo_config.rs | 347 ++++++ .../bridge-hubs/bridge-hub-westend/src/lib.rs | 1077 +++++++++++++++++ .../src/weights/block_weights.rs | 53 + .../src/weights/cumulus_pallet_xcmp_queue.rs | 77 ++ .../src/weights/extrinsic_weights.rs | 53 + .../src/weights/frame_system.rs | 155 +++ .../bridge-hub-westend/src/weights/mod.rs | 72 ++ .../src/weights/pallet_balances.rs | 153 +++ .../src/weights/pallet_bridge_grandpa.rs | 83 ++ .../src/weights/pallet_bridge_messages.rs | 245 ++++ .../src/weights/pallet_bridge_parachains.rs | 114 ++ .../src/weights/pallet_bridge_relayers.rs | 123 ++ .../src/weights/pallet_collator_selection.rs | 225 ++++ .../src/weights/pallet_multisig.rs | 165 +++ .../src/weights/pallet_session.rs | 81 ++ .../src/weights/pallet_timestamp.rs | 75 ++ .../src/weights/pallet_utility.rs | 102 ++ .../src/weights/pallet_xcm.rs | 289 +++++ .../src/weights/paritydb_weights.rs | 63 + .../src/weights/rocksdb_weights.rs | 63 + .../bridge-hub-westend/src/weights/xcm/mod.rs | 247 ++++ .../xcm/pallet_xcm_benchmarks_fungible.rs | 208 ++++ .../xcm/pallet_xcm_benchmarks_generic.rs | 377 ++++++ .../bridge-hub-westend/src/xcm_config.rs | 329 +++++ .../bridge-hub-westend/tests/tests.rs | 285 +++++ cumulus/polkadot-parachain/Cargo.toml | 3 + .../src/chain_spec/bridge_hubs.rs | 184 ++- cumulus/polkadot-parachain/src/command.rs | 12 +- cumulus/scripts/bridges_rococo_westend.sh | 368 ++++++ cumulus/scripts/bridges_rococo_wococo.sh | 2 + .../bridge_hub_rococo_local_network.toml | 8 +- .../bridge_hub_westend_local_network.toml | 94 ++ .../bridge_hub_wococo_local_network.toml | 8 +- 112 files changed, 10018 insertions(+), 1628 deletions(-) create mode 100644 bridges/primitives/chain-asset-hub-westend/Cargo.toml create mode 100644 bridges/primitives/chain-asset-hub-westend/src/lib.rs create mode 100644 bridges/primitives/chain-bridge-hub-westend/Cargo.toml create mode 100644 bridges/primitives/chain-bridge-hub-westend/src/lib.rs create mode 100644 bridges/primitives/chain-westend/Cargo.toml create mode 100644 bridges/primitives/chain-westend/src/lib.rs create mode 100644 bridges/zombienet/README.md create mode 100644 bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js create mode 100644 bridges/zombienet/helpers/relayer-rewards.js create mode 100644 bridges/zombienet/helpers/wrapped-assets-balance.js create mode 100755 bridges/zombienet/run-tests.sh create mode 100755 bridges/zombienet/scripts/invoke-script.sh create mode 100755 bridges/zombienet/scripts/sync-exit.sh create mode 100644 bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl create mode 100644 bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl create mode 100644 bridges/zombienet/tests/0001-start-relay.sh create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/{bridge_hub_wococo_config.rs => bridge_to_rococo_config.rs} (87%) create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs rename cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/{bridge_hub_rococo_config.rs => bridge_to_wococo_config.rs} (87%) delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/build.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_multisig.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_session.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_timestamp.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs create mode 100755 cumulus/scripts/bridges_rococo_westend.sh create mode 100644 cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml diff --git a/Cargo.lock b/Cargo.lock index e6d764dcd39..dc972af8714 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,6 +905,7 @@ dependencies = [ "asset-test-utils", "assets-common", "bp-asset-hub-rococo", + "bp-asset-hub-westend", "bp-asset-hub-wococo", "bp-bridge-hub-rococo", "bp-bridge-hub-wococo", @@ -1015,6 +1016,9 @@ version = "0.9.420" dependencies = [ "asset-test-utils", "assets-common", + "bp-asset-hub-rococo", + "bp-asset-hub-westend", + "bp-bridge-hub-westend", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -1052,6 +1056,7 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub-router", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -1066,7 +1071,6 @@ dependencies = [ "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io", "sp-offchain", "sp-runtime", "sp-session", @@ -1682,6 +1686,16 @@ dependencies = [ "scale-info", ] +[[package]] +name = "bp-asset-hub-westend" +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" @@ -1745,6 +1759,19 @@ dependencies = [ "sp-std", ] +[[package]] +name = "bp-bridge-hub-westend" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-messages", + "bp-runtime", + "frame-support", + "sp-api", + "sp-runtime", + "sp-std", +] + [[package]] name = "bp-bridge-hub-wococo" version = "0.1.0" @@ -1937,6 +1964,18 @@ dependencies = [ "sp-trie", ] +[[package]] +name = "bp-westend" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "sp-api", + "sp-std", +] + [[package]] name = "bp-wococo" version = "0.1.0" @@ -2114,8 +2153,10 @@ name = "bridge-hub-rococo-runtime" version = "0.1.0" dependencies = [ "bp-asset-hub-rococo", + "bp-asset-hub-westend", "bp-asset-hub-wococo", "bp-bridge-hub-rococo", + "bp-bridge-hub-westend", "bp-bridge-hub-wococo", "bp-header-chain", "bp-messages", @@ -2124,6 +2165,7 @@ dependencies = [ "bp-relayers", "bp-rococo", "bp-runtime", + "bp-westend", "bp-wococo", "bridge-hub-test-utils", "bridge-runtime-common", @@ -2239,6 +2281,88 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "bridge-hub-westend-runtime" +version = "0.1.0" +dependencies = [ + "bp-asset-hub-westend", + "bp-bridge-hub-rococo", + "bp-bridge-hub-westend", + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-polkadot-core", + "bp-relayers", + "bp-rococo", + "bp-runtime", + "bp-westend", + "bridge-hub-test-utils", + "bridge-runtime-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", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal", + "log", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-bridge-relayers", + "pallet-collator-selection", + "pallet-multisig", + "pallet-session", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "pallet-xcm", + "pallet-xcm-benchmarks", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "scale-info", + "serde", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-keyring", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-storage", + "sp-transaction-pool", + "sp-version", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "static_assertions", + "substrate-wasm-builder", + "westend-runtime-constants", +] + [[package]] name = "bridge-runtime-common" version = "0.1.0" @@ -12524,6 +12648,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", + "bridge-hub-westend-runtime", "clap 4.4.6", "collectives-polkadot-runtime", "color-print", diff --git a/Cargo.toml b/Cargo.toml index 2c63aabf935..ccb952cc963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,16 +17,19 @@ members = [ "bridges/primitives/chain-asset-hub-kusama", "bridges/primitives/chain-asset-hub-polkadot", "bridges/primitives/chain-asset-hub-rococo", + "bridges/primitives/chain-asset-hub-westend", "bridges/primitives/chain-asset-hub-wococo", "bridges/primitives/chain-bridge-hub-cumulus", "bridges/primitives/chain-bridge-hub-kusama", "bridges/primitives/chain-bridge-hub-polkadot", "bridges/primitives/chain-bridge-hub-rococo", + "bridges/primitives/chain-bridge-hub-westend", "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-westend", "bridges/primitives/chain-wococo", "bridges/primitives/header-chain", "bridges/primitives/messages", @@ -78,6 +81,7 @@ members = [ "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama", "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot", "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", + "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", "cumulus/parachains/runtimes/bridge-hubs/test-utils", "cumulus/parachains/runtimes/collectives/collectives-polkadot", "cumulus/parachains/runtimes/contracts/contracts-rococo", diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index b9b98ca7e25..ce66c9df48e 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -325,6 +325,12 @@ pub mod pallet { rewards_account_params, new_reward, ); + + Self::deposit_event(Event::::RewardRegistered { + relayer: relayer.clone(), + rewards_account_params, + reward, + }); }, ); } @@ -369,6 +375,15 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// Relayer reward has been registered and may be claimed later. + RewardRegistered { + /// Relayer account that can claim reward. + relayer: T::AccountId, + /// Relayer can claim reward from this account. + rewards_account_params: RewardsAccountParams, + /// Reward amount. + reward: T::Reward, + }, /// Reward has been paid to the relayer. RewardPaid { /// Relayer account that has been rewarded. @@ -455,7 +470,7 @@ mod tests { use super::*; use mock::{RuntimeEvent as TestEvent, *}; - use crate::Event::RewardPaid; + use crate::Event::{RewardPaid, RewardRegistered}; use bp_messages::LaneId; use bp_relayers::RewardsAccountOwner; use frame_support::{ @@ -470,6 +485,33 @@ mod tests { System::::reset_events(); } + #[test] + fn register_relayer_reward_emit_event() { + run_test(|| { + get_ready_for_events(); + + Pallet::::register_relayer_reward( + TEST_REWARDS_ACCOUNT_PARAMS, + ®ULAR_RELAYER, + 100, + ); + + // Check if the `RewardRegistered` event was emitted. + assert_eq!( + System::::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: TestEvent::Relayers(RewardRegistered { + relayer: REGULAR_RELAYER, + rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + reward: 100 + }), + topics: vec![], + }), + ); + }); + } + #[test] fn root_cant_claim_anything() { run_test(|| { diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 5cf94fc83fd..cf51ef82412 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -335,7 +335,7 @@ impl, I: 'static> SendXcm for Pallet { // just use exporter to validate destination and insert instructions to pay message fee // at the sibling/child bridge hub // - // the cost will include both cost of: (1) to-sibling bridg hub delivery (returned by + // the cost will include both cost of: (1) to-sibling bridge hub delivery (returned by // the `Config::ToBridgeHubSender`) and (2) to-bridged bridge hub delivery (returned by // `Self::exporter_for`) ViaBridgeHubExporter::::validate(dest, xcm) diff --git a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs index f1ea1e9c88c..1a08ade2f4f 100644 --- a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs @@ -37,6 +37,9 @@ pub enum Call { /// `ToWococoXcmRouter` bridge pallet. #[codec(index = 43)] ToWococoXcmRouter(XcmBridgeHubRouterCall), + /// `ToWestendXcmRouter` bridge pallet. + #[codec(index = 45)] + ToWestendXcmRouter(XcmBridgeHubRouterCall), } frame_support::parameter_types! { @@ -44,8 +47,8 @@ frame_support::parameter_types! { 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; + /// (initially was calculated by test `BridgeHubRococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubRococoBaseFeeInRocs: u128 = 1624803349; } /// Identifier of AssetHubRococo in the Rococo relay chain. diff --git a/bridges/primitives/chain-asset-hub-westend/Cargo.toml b/bridges/primitives/chain-asset-hub-westend/Cargo.toml new file mode 100644 index 00000000000..c880f159ac1 --- /dev/null +++ b/bridges/primitives/chain-asset-hub-westend/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "bp-asset-hub-westend" +description = "Primitives of AssetHubWestend 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.10.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-westend/src/lib.rs b/bridges/primitives/chain-asset-hub-westend/src/lib.rs new file mode 100644 index 00000000000..2d317e4aee4 --- /dev/null +++ b/bridges/primitives/chain-asset-hub-westend/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 AssetHubWestend 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; + +/// `AssetHubWestend` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `AssetHubWestend` 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 +/// `AssetHubWestend` `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 = 34)] + 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 `BridgeHubWestend`. + /// (initially was calculated by test `BridgeHubWestend::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubWestendBaseFeeInWnds: u128 = 487441010000; +} + +/// Identifier of AssetHubWestend in the Westend relay chain. +pub const ASSET_HUB_WESTEND_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs index 5ce66054d64..809e56934e9 100644 --- a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs @@ -44,8 +44,8 @@ frame_support::parameter_types! { 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; + /// (initially was calculated by test `BridgeHubWococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubWococoBaseFeeInWocs: u128 = 1624803349; } /// Identifier of AssetHubWococo in the Wococo relay chain. diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index ed3ef440c83..039d681951c 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -68,15 +68,17 @@ pub type Address = MultiAddress; pub const BRIDGE_HUB_ROCOCO_PARACHAIN_ID: u32 = 1013; /// Name of the With-BridgeHubRococo messages pallet instance that is deployed at bridged chains. -pub const WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME: &str = - "BridgeWococoToRococoMessages"; +pub const WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; /// Name of the With-BridgeHubRococo bridge-relayers pallet instance that is deployed at bridged /// chains. pub const WITH_BRIDGE_HUB_ROCOCO_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; -/// Pallet index of `BridgeRococoToWococoMessages: pallet_bridge_messages::`. +/// Pallet index of `BridgeWococoMessages: pallet_bridge_messages::`. pub const WITH_BRIDGE_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_INDEX: u8 = 46; +/// Pallet index of `BridgeWestendMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX: u8 = 51; + decl_bridge_finality_runtime_apis!(bridge_hub_rococo); decl_bridge_messages_runtime_apis!(bridge_hub_rococo); diff --git a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml new file mode 100644 index 00000000000..22daf280868 --- /dev/null +++ b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "bp-bridge-hub-westend" +description = "Primitives of BridgeHubWestend parachain runtime." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +# Bridge Dependencies + +bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } + +# Substrate Based Dependencies + +frame-support = { path = "../../../substrate/frame/support", 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-bridge-hub-cumulus/std", + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/bridges/primitives/chain-bridge-hub-westend/src/lib.rs b/bridges/primitives/chain-bridge-hub-westend/src/lib.rs new file mode 100644 index 00000000000..a52e328b687 --- /dev/null +++ b/bridges/primitives/chain-bridge-hub-westend/src/lib.rs @@ -0,0 +1,75 @@ +// 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 BridgeHubWestend runtime setup +//! (AccountId, Headers, Hashes...) + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use bp_bridge_hub_cumulus::*; +use bp_messages::*; +use bp_runtime::{ + decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, Parachain, +}; +use frame_support::dispatch::DispatchClass; +use sp_runtime::RuntimeDebug; + +/// BridgeHubWestend parachain. +#[derive(RuntimeDebug)] +pub struct BridgeHubWestend; + +impl Chain for BridgeHubWestend { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + 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 Parachain for BridgeHubWestend { + const PARACHAIN_ID: u32 = BRIDGE_HUB_WESTEND_PARACHAIN_ID; +} + +/// Identifier of BridgeHubWestend in the Westend relay chain. +pub const BRIDGE_HUB_WESTEND_PARACHAIN_ID: u32 = 1002; + +/// Name of the With-BridgeHubWestend messages pallet instance that is deployed at bridged chains. +pub const WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME: &str = "BridgeWestendMessages"; + +/// Name of the With-BridgeHubWestend bridge-relayers pallet instance that is deployed at bridged +/// chains. +pub const WITH_BRIDGE_HUB_WESTEND_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; + +/// Pallet index of `BridgeRococoMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 44; + +decl_bridge_finality_runtime_apis!(bridge_hub_westend); +decl_bridge_messages_runtime_apis!(bridge_hub_westend); diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs index 1e147d367d0..750a8f7ecb9 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -62,14 +62,13 @@ impl Parachain for BridgeHubWococo { pub const BRIDGE_HUB_WOCOCO_PARACHAIN_ID: u32 = 1014; /// Name of the With-BridgeHubWococo messages pallet instance that is deployed at bridged chains. -pub const WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME: &str = - "BridgeRococoToWococoMessages"; +pub const WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; /// Name of the With-BridgeHubWococo bridge-relayers pallet instance that is deployed at bridged /// chains. pub const WITH_BRIDGE_HUB_WOCOCO_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; -/// Pallet index of `BridgeWococoToRococoMessages: pallet_bridge_messages::`. +/// Pallet index of `BridgeRococoMessages: pallet_bridge_messages::`. pub const WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 45; decl_bridge_finality_runtime_apis!(bridge_hub_wococo); diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml index 9cc79bef1a6..1dd45ba95fd 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -2,8 +2,8 @@ name = "bp-polkadot-bulletin" description = "Primitives of Polkadot Bulletin chain runtime." version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" +authors.workspace = true +edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml index 3c4d3917bc2..469be1dbd33 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -16,9 +16,9 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies +frame-support = { path = "../../../substrate/frame/support", default-features = false } sp-api = { path = "../../../substrate/primitives/api", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } [features] default = [ "std" ] diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml new file mode 100644 index 00000000000..797621bbce2 --- /dev/null +++ b/bridges/primitives/chain-westend/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bp-westend" +description = "Primitives of Westend runtime." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +# Bridge Dependencies + +bp-header-chain = { path = "../header-chain", 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 } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } + +[features] +default = [ "std" ] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", + "sp-std/std", +] diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs new file mode 100644 index 00000000000..45c13d60060 --- /dev/null +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -0,0 +1,79 @@ +// 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 . + +#![cfg_attr(not(feature = "std"), no_std)] +// RuntimeApi generated functions +#![allow(clippy::too_many_arguments)] + +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}; + +/// Westend Chain +pub struct Westend; + +impl Chain for Westend { + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hasher; + type Header = ::Header; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Nonce = ::Nonce; + type Signature = ::Signature; + + fn max_extrinsic_size() -> u32 { + PolkadotLike::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + PolkadotLike::max_extrinsic_weight() + } +} + +impl ChainWithGrandpa for Westend { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_WESTEND_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; +} + +parameter_types! { + pub const SS58Prefix: u8 = 42; +} + +// The SignedExtension used by Westend. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; + +/// Name of the parachains pallet in the Rococo runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + +/// Name of the With-Westend GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_WESTEND_GRANDPA_PALLET_NAME: &str = "BridgeWestendGrandpa"; + +/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Westend +/// parachains. +/// +/// It includes the block number and state root, so it shall be near 40 bytes, but let's have some +/// reserve. +pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128; + +decl_bridge_finality_runtime_apis!(westend, grandpa); diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 7f4a1a030b1..e5277d8db6a 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -23,7 +23,6 @@ use frame_support::{ pallet_prelude::DispatchResult, weights::Weight, PalletError, StorageHasher, StorageValue, }; use frame_system::RawOrigin; -use log; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_core::storage::StorageKey; @@ -98,6 +97,9 @@ pub const BRIDGE_HUB_ROCOCO_CHAIN_ID: ChainId = *b"bhro"; /// BridgeHubWococo chain id. pub const BRIDGE_HUB_WOCOCO_CHAIN_ID: ChainId = *b"bhwo"; +/// BridgeHubWestend chain id. +pub const BRIDGE_HUB_WESTEND_CHAIN_ID: ChainId = *b"bhwd"; + /// BridgeHubKusama chain id. pub const BRIDGE_HUB_KUSAMA_CHAIN_ID: ChainId = *b"bhks"; diff --git a/bridges/scripts/verify-pallets-build.sh b/bridges/scripts/verify-pallets-build.sh index b8ac09e26b8..e797f77d026 100755 --- a/bridges/scripts/verify-pallets-build.sh +++ b/bridges/scripts/verify-pallets-build.sh @@ -74,7 +74,6 @@ rm -rf $BRIDGES_FOLDER/primitives/beefy rm -rf $BRIDGES_FOLDER/primitives/chain-millau rm -rf $BRIDGES_FOLDER/primitives/chain-rialto rm -rf $BRIDGES_FOLDER/primitives/chain-rialto-parachain -rm -rf $BRIDGES_FOLDER/primitives/chain-westend rm -rf $BRIDGES_FOLDER/relays rm -rf $BRIDGES_FOLDER/scripts/add_license.sh rm -rf $BRIDGES_FOLDER/scripts/build-containers.sh diff --git a/bridges/zombienet/README.md b/bridges/zombienet/README.md new file mode 100644 index 00000000000..2da3093f4f0 --- /dev/null +++ b/bridges/zombienet/README.md @@ -0,0 +1,31 @@ +# Bridges Tests for Local Rococo <> Wococo Bridge + +This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both +onchain and offchain bridges code. Due to some +[technical diffuculties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we +are using native zombienet provider, which means that you need to build some binaries locally. + +To start those tests, you need to: + +- download latest [zombienet release](https://github.com/paritytech/zombienet/releases); + +- build Polkadot binary by running `cargo build -p polkadot --release` command in the +[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + +- build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the +[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + +- ensure that you have [`node`](https://nodejs.org/en) installed. Additionally, we'll need globally installed +`polkadot/api-cli` package (use `npm install -g @polkadot/api-cli@beta` to install it); + +- build Substrate relay by running `cargo build -p substrate-relay --release` command in the +[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone. + +- copy fresh `substrate-relay` binary, built in previous point, to the `~/local_bridge_testing/bin/substrate-relay`; + +- change the `POLKADOT_SDK_FOLDER` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables +have correct values) in the `./run-tests.sh`. + +After that, you could run tests with the `./run-tests.sh` command. Hopefully, it'll show the +"All tests have completed successfully" message in the end. Otherwise, it'll print paths to zombienet +process logs, which, in turn, may be used to track locations of all spinned relay and parachain nodes. diff --git a/bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js b/bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js new file mode 100644 index 00000000000..f7e1eefc84b --- /dev/null +++ b/bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js @@ -0,0 +1,25 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const bridgedChainName = args[0]; + const expectedBridgedChainHeaderNumber = Number(args[1]); + const runtimeApiMethod = bridgedChainName + "FinalityApi_best_finalized"; + + while (true) { + const encodedBestFinalizedHeaderId = await api.rpc.state.call(runtimeApiMethod, []); + const bestFinalizedHeaderId = api.createType("Option", encodedBestFinalizedHeaderId); + if (bestFinalizedHeaderId.isSome) { + const bestFinalizedHeaderNumber = Number(bestFinalizedHeaderId.unwrap().toHuman()[0]); + if (bestFinalizedHeaderNumber > expectedBridgedChainHeaderNumber) { + return bestFinalizedHeaderNumber; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 12000)); + } +} + +module.exports = { run } diff --git a/bridges/zombienet/helpers/relayer-rewards.js b/bridges/zombienet/helpers/relayer-rewards.js new file mode 100644 index 00000000000..a5f567db797 --- /dev/null +++ b/bridges/zombienet/helpers/relayer-rewards.js @@ -0,0 +1,28 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const relayerAccountAddress = args[0]; + const laneId = args[1]; + const bridgedChainId = args[2]; + const relayerFundOwner = args[3]; + const expectedRelayerReward = BigInt(args[4]); + while (true) { + const relayerReward = await api.query.bridgeRelayers.relayerRewards( + relayerAccountAddress, + { laneId: laneId, bridgedChainId: bridgedChainId, owner: relayerFundOwner } + ); + if (relayerReward.isSome) { + const relayerRewardBalance = relayerReward.unwrap().toBigInt(); + if (relayerRewardBalance > expectedRelayerReward) { + return relayerRewardBalance; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 12000)); + } +} + +module.exports = { run } diff --git a/bridges/zombienet/helpers/wrapped-assets-balance.js b/bridges/zombienet/helpers/wrapped-assets-balance.js new file mode 100644 index 00000000000..bb3cea8858a --- /dev/null +++ b/bridges/zombienet/helpers/wrapped-assets-balance.js @@ -0,0 +1,26 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const accountAddress = args[0]; + const expectedForeignAssetBalance = BigInt(args[1]); + const bridgedNetworkName = args[2]; + while (true) { + const foreignAssetAccount = await api.query.foreignAssets.account( + { parents: 2, interior: { X1: { GlobalConsensus: bridgedNetworkName } } }, + accountAddress + ); + if (foreignAssetAccount.isSome) { + const foreignAssetAccountBalance = foreignAssetAccount.unwrap().balance.toBigInt(); + if (foreignAssetAccountBalance > expectedForeignAssetBalance) { + return foreignAssetAccountBalance; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 12000)); + } +} + +module.exports = { run } diff --git a/bridges/zombienet/run-tests.sh b/bridges/zombienet/run-tests.sh new file mode 100755 index 00000000000..1fdbc6b8d61 --- /dev/null +++ b/bridges/zombienet/run-tests.sh @@ -0,0 +1,97 @@ +#!/bin/bash +#set -eu +shopt -s nullglob + +trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT + +# assuming that we'll be using native provide && all processes will be executing locally +# (we need absolute paths here, because they're used when scripts are called by zombienet from tmp folders) +export POLKADOT_SDK_FOLDER=`realpath $(dirname "$0")/../..` +export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_FOLDER/bridges/zombienet/tests +export POLKADOT_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot +export POLKADOT_PARACHAIN_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot-parachain +export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=$POLKADOT_PARACHAIN_BINARY_PATH +export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO=$POLKADOT_PARACHAIN_BINARY_PATH +export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux + +# bridge configuration +export LANE_ID="00000001" + +# tests configuration +ALL_TESTS_FOLDER=`mktemp -d` + +function start_coproc() { + local command=$1 + local name=$2 + local coproc_log=`mktemp -p $TEST_FOLDER` + coproc COPROC { + $command >$coproc_log 2>&1 + } + TEST_COPROCS[$COPROC_PID, 0]=$name + TEST_COPROCS[$COPROC_PID, 1]=$coproc_log + echo "Spawned $name coprocess. StdOut + StdErr: $coproc_log" + + return $COPROC_PID +} + +# execute every test from tests folder +TEST_INDEX=1 +while true +do + declare -A TEST_COPROCS + TEST_COPROCS_COUNT=0 + TEST_PREFIX=$(printf "%04d" $TEST_INDEX) + + # it'll be used by the `sync-exit.sh` script + export TEST_FOLDER=`mktemp -d -p $ALL_TESTS_FOLDER` + + # check if there are no more tests + zndsl_files=($BRIDGE_TESTS_FOLDER/$TEST_PREFIX-*.zndsl) + if [ ${#zndsl_files[@]} -eq 0 ]; then + break + fi + + # start relay + if [ -f $BRIDGE_TESTS_FOLDER/$TEST_PREFIX-start-relay.sh ]; then + start_coproc "${BRIDGE_TESTS_FOLDER}/${TEST_PREFIX}-start-relay.sh" "relay" + RELAY_COPROC=$COPROC_PID + ((TEST_COPROCS_COUNT++)) + fi + # start tests + for zndsl_file in "${zndsl_files[@]}"; do + start_coproc "$ZOMBIENET_BINARY_PATH --provider native test $zndsl_file" "$zndsl_file" + echo -n "1">>$TEST_FOLDER/exit-sync + ((TEST_COPROCS_COUNT++)) + done + # wait until all tests are completed + relay_exited=0 + for n in `seq 1 $TEST_COPROCS_COUNT`; do + wait -n -p COPROC_PID + exit_code=$? + coproc_name=${TEST_COPROCS[$COPROC_PID, 0]} + coproc_log=${TEST_COPROCS[$COPROC_PID, 1]} + coproc_stdout=$(cat $coproc_log) + relay_exited=$(expr "${coproc_name}" == "relay") + echo "Process $coproc_name has finished with exit code: $exit_code" + + # if exit code is not zero, exit + if [ $exit_code -ne 0 ]; then + echo "=====================================================================" + echo "=== Shutting down. Log of failed process below ===" + echo "=====================================================================" + echo $coproc_stdout + exit 1 + fi + + # if last test has exited, exit relay too + if [ $n -eq $(($TEST_COPROCS_COUNT - 1)) ] && [ $relay_exited -eq 0 ]; then + kill $RELAY_COPROC + break + fi + done + ((TEST_INDEX++)) +done + +echo "=====================================================================" +echo "=== All tests have completed successfully ===" +echo "=====================================================================" diff --git a/bridges/zombienet/scripts/invoke-script.sh b/bridges/zombienet/scripts/invoke-script.sh new file mode 100755 index 00000000000..cb21d61ab91 --- /dev/null +++ b/bridges/zombienet/scripts/invoke-script.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +pushd $POLKADOT_SDK_FOLDER/cumulus/scripts +./bridges_rococo_wococo.sh $1 +popd diff --git a/bridges/zombienet/scripts/sync-exit.sh b/bridges/zombienet/scripts/sync-exit.sh new file mode 100755 index 00000000000..cc20b098e78 --- /dev/null +++ b/bridges/zombienet/scripts/sync-exit.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# every network adds a char to the file, let's remove ours +truncate -s -1 $TEST_FOLDER/exit-sync + +# when all chars are removed, then our test is done +while true +do + if [ `stat --printf="%s" $TEST_FOLDER/exit-sync` -eq 0 ]; then + exit + fi + sleep 100 +done diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl new file mode 100644 index 00000000000..a1af2625c1c --- /dev/null +++ b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl @@ -0,0 +1,25 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Wococo Asset Hub +Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml +Creds: config + +# step 1: initialize Wococo asset hub +asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-wococo-local" within 120 seconds + +# step 2: initialize Wococo bridge hub +bridge-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-wococo-local" within 120 seconds + +# step 3: relay is started elsewhere - let's wait until with-Rococo GRANPDA pallet is initialized at Wococo +bridge-hub-wococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds + +# step 2: send WOC to Rococo +asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-wococo-local" within 60 seconds + +# step 3: elsewhere Rococo has sent ROC to //Alice - let's wait for it +asset-hub-wococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Rococo" within 600 seconds + +# step 4: check that the relayer //Charlie is rewarded by both our AH and target AH +bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,BridgedChain,0" within 300 seconds +bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,ThisChain,0" within 300 seconds + +# wait until other network test has completed OR exit with an error too +asset-hub-wococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl new file mode 100644 index 00000000000..ad2446d58ce --- /dev/null +++ b/bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl @@ -0,0 +1,25 @@ +Description: User is able to transfer WOC from Wococo Asset Hub to Rococo Asset Hub +Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +Creds: config + +# step 1: initialize Rococo asset hub +asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 120 seconds + +# step 2: initialize Rococo bridge hub +bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 120 seconds + +# step 3: relay is started elsewhere - let's wait until with-Wococo GRANPDA pallet is initialized at Rococo +bridge-hub-rococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Wococo,0" within 400 seconds + +# step 4: send ROC to Wococo +asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds + +# step 5: elsewhere Wococo has sent WOC to //Alice - let's wait for it +asset-hub-rococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Wococo" within 600 seconds + +# step 6: check that the relayer //Charlie is rewarded by both our AH and target AH +bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,BridgedChain,0" within 300 seconds +bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,ThisChain,0" within 300 seconds + +# wait until other network test has completed OR exit with an error too +asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-start-relay.sh b/bridges/zombienet/tests/0001-start-relay.sh new file mode 100644 index 00000000000..fc231fba895 --- /dev/null +++ b/bridges/zombienet/tests/0001-start-relay.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +pushd $POLKADOT_SDK_FOLDER/cumulus/scripts +./bridges_rococo_wococo.sh run-relay +popd diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index ee5f0727a1e..1b6bf995863 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -249,15 +249,15 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { test.set_dispatchable::(relay_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - let delivery_fees = Rococo::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after); } 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 3b48e6529ff..6923cd13126 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 @@ -38,7 +38,10 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { } fn system_para_dest_assertions(_t: RelayToSystemParaTest) { - AssetHubWestend::assert_dmp_queue_error(Error::WeightNotComputable); + AssetHubWestend::assert_dmp_queue_incomplete( + Some(Weight::from_parts(31_352_000, 1489)), + Some(Error::UntrustedReserveLocation), + ); } fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index fd34299ce1d..f24e13bb71b 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -64,7 +64,7 @@ fn example() { outcome: Outcome::Complete(_), .. }) => {}, - RuntimeEvent::BridgeRococoToWococoMessages(pallet_bridge_messages::Event::MessageAccepted { + RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { lane_id: LaneId([0, 0, 0, 1]), nonce: 1, }) => {}, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 93abae753b9..592269e9aa3 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -669,16 +669,14 @@ pub mod bridge_hub_rococo { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, - bridge_wococo_to_rococo_messages: - bridge_hub_rococo_runtime::BridgeWococoToRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_rococo_to_wococo_messages: - bridge_hub_rococo_runtime::BridgeRococoToWococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, + bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, ..Default::default() }; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index d8a8f224aae..766cadb93b0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -83,6 +83,7 @@ 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", 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 } @@ -171,6 +172,7 @@ try-runtime = [ std = [ "assets-common/std", "bp-asset-hub-rococo/std", + "bp-asset-hub-westend/std", "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-wococo/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 1ce504d6704..24c511e1a68 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 10006, + spec_version: 1_003_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -136,7 +136,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 10006, + spec_version: 1_003_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -833,7 +833,7 @@ impl pallet_nfts::Config for Runtime { /// XCM router instance to BridgeHub with bridging capabilities for `Wococo` global /// consensus with dynamic fees and back-pressure. -pub type ToWococoXcmRouterInstance = pallet_assets::Instance1; +pub type ToWococoXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance1; impl pallet_xcm_bridge_hub_router::Config for Runtime { type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_wococo::WeightInfo; @@ -864,7 +864,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime /// XCM router instance to BridgeHub with bridging capabilities for `Rococo` global /// consensus with dynamic fees and back-pressure. -pub type ToRococoXcmRouterInstance = pallet_assets::Instance2; +pub type ToRococoXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance2; impl pallet_xcm_bridge_hub_router::Config for Runtime { type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_rococo::WeightInfo; @@ -893,6 +893,37 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; } +/// XCM router instance to BridgeHub with bridging capabilities for `Westend` global +/// consensus with dynamic fees and back-pressure. +pub type ToWestendXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance3; +impl pallet_xcm_bridge_hub_router::Config for Runtime { + type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_westend::WeightInfo; + + type UniversalLocation = xcm_config::UniversalLocation; + type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; + type Bridges = xcm_config::bridging::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 @@ -931,6 +962,7 @@ construct_runtime!( // Bridge utilities. ToWococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 43, ToRococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 44, + ToWestendXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 45, // The main stage. Assets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, @@ -1006,6 +1038,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToWococo] + [pallet_xcm_bridge_hub_router, ToWestend] [pallet_xcm_bridge_hub_router, ToRococo] // XCM [pallet_xcm, PolkadotXcm] @@ -1263,6 +1296,7 @@ impl_runtime_apis! { type Pool = pallet_assets::Pallet::; type ToWococo = XcmBridgeHubRouterBench; + type ToWestend = XcmBridgeHubRouterBench; type ToRococo = XcmBridgeHubRouterBench; let mut list = Vec::::new(); @@ -1311,6 +1345,19 @@ impl_runtime_apis! { 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 { + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + xcm_config::bridging::SiblingBridgeHubParaId::get().into() + ); + xcm_config::bridging::to_westend::AssetHubWestend::get() + } + } impl XcmBridgeHubRouterConfig for Runtime { fn make_congested() { cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( @@ -1461,6 +1508,7 @@ impl_runtime_apis! { type Pool = pallet_assets::Pallet::; type ToWococo = XcmBridgeHubRouterBench; + type ToWestend = XcmBridgeHubRouterBench; type ToRococo = XcmBridgeHubRouterBench; let whitelist: Vec = vec![ diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index 59f97d2c8e5..4997e589c3c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -34,6 +34,7 @@ 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_westend; pub mod pallet_xcm_bridge_hub_router_to_wococo; pub mod paritydb_weights; pub mod rocksdb_weights; 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 index 3ce9e4e7d31..ff00ace25b8 100644 --- 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 @@ -17,9 +17,9 @@ //! 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: `[]` +//! DATE: 2023-10-26, 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` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -50,34 +50,36 @@ 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: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`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)) + // Measured: `265` + // Estimated: `3730` + // Minimum execution time: 9_084_000 picoseconds. + Weight::from_parts(9_441_000, 0) + .saturating_add(Weight::from_parts(0, 3730)) .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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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)) + // Measured: `202` + // Estimated: `3667` + // Minimum execution time: 5_971_000 picoseconds. + Weight::from_parts(6_260_000, 0) + .saturating_add(Weight::from_parts(0, 3667)) + .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) @@ -85,8 +87,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `117` // Estimated: `1502` - // Minimum execution time: 11_479_000 picoseconds. - Weight::from_parts(11_831_000, 0) + // Minimum execution time: 10_231_000 picoseconds. + Weight::from_parts(10_861_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -99,6 +101,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -109,16 +113,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`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)) + // Measured: `478` + // Estimated: `3943` + // Minimum execution time: 53_966_000 picoseconds. + Weight::from_parts(55_224_000, 0) + .saturating_add(Weight::from_parts(0, 3943)) + .saturating_add(T::DbWeight::get().reads(11)) .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_westend.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs new file mode 100644 index 00000000000..8c344b44f78 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs @@ -0,0 +1,130 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `pallet_xcm_bridge_hub_router` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn on_initialize_when_non_congested() -> Weight { + // Proof Size summary in bytes: + // Measured: `193` + // Estimated: `3658` + // Minimum execution time: 8_528_000 picoseconds. + Weight::from_parts(8_886_000, 0) + .saturating_add(Weight::from_parts(0, 3658)) + .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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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: `183` + // Estimated: `3648` + // Minimum execution time: 5_170_000 picoseconds. + Weight::from_parts(5_433_000, 0) + .saturating_add(Weight::from_parts(0, 3648)) + .saturating_add(T::DbWeight::get().reads(3)) + } + /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `150` + // Estimated: `1502` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_762_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: `ToWestendXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`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: `387` + // Estimated: `3852` + // Minimum execution time: 52_040_000 picoseconds. + Weight::from_parts(53_500_000, 0) + .saturating_add(Weight::from_parts(0, 3852)) + .saturating_add(T::DbWeight::get().reads(11)) + .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 index 1ee0e933715..ca371f1e6ce 100644 --- 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 @@ -17,9 +17,9 @@ //! 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: `[]` +//! DATE: 2023-10-26, 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` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -50,34 +50,36 @@ 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: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`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)) + // Measured: `231` + // Estimated: `3696` + // Minimum execution time: 9_115_000 picoseconds. + Weight::from_parts(9_522_000, 0) + .saturating_add(Weight::from_parts(0, 3696)) .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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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)) + // Measured: `183` + // Estimated: `3648` + // Minimum execution time: 5_207_000 picoseconds. + Weight::from_parts(5_534_000, 0) + .saturating_add(Weight::from_parts(0, 3648)) + .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: `ToWococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToWococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) @@ -85,8 +87,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `83` // Estimated: `1502` - // Minimum execution time: 11_420_000 picoseconds. - Weight::from_parts(11_946_000, 0) + // Minimum execution time: 10_437_000 picoseconds. + Weight::from_parts(10_956_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -99,6 +101,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -109,16 +113,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`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)) + // Measured: `425` + // Estimated: `3890` + // Minimum execution time: 52_176_000 picoseconds. + Weight::from_parts(54_067_000, 0) + .saturating_add(Weight::from_parts(0, 3890)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 926d7aeb9e1..fe5123a427c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ayothjw6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 20_408_000 picoseconds. - Weight::from_parts(21_066_000, 3593) + // Minimum execution time: 20_940_000 picoseconds. + Weight::from_parts(21_453_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_449_000 picoseconds. - Weight::from_parts(43_065_000, 6196) + // Minimum execution time: 44_310_000 picoseconds. + Weight::from_parts(44_948_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -92,8 +92,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 85_637_000 picoseconds. - Weight::from_parts(86_550_000, 8799) + // Minimum execution time: 87_226_000 picoseconds. + Weight::from_parts(89_399_000, 8799) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -105,8 +105,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `39` // Estimated: `3504` - // Minimum execution time: 7_006_000 picoseconds. - Weight::from_parts(7_185_000, 3504) + // Minimum execution time: 7_320_000 picoseconds. + Weight::from_parts(7_453_000, 3504) .saturating_add(T::DbWeight::get().reads(2)) } // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) @@ -131,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 185_307_000 picoseconds. - Weight::from_parts(189_716_000, 6196) + // Minimum execution time: 183_539_000 picoseconds. + Weight::from_parts(190_968_000, 6196) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -140,8 +140,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_934_000 picoseconds. - Weight::from_parts(3_078_000, 0) + // Minimum execution time: 3_068_000 picoseconds. + Weight::from_parts(3_228_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -149,8 +149,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 18_701_000 picoseconds. - Weight::from_parts(19_221_000, 3593) + // Minimum execution time: 18_788_000 picoseconds. + Weight::from_parts(19_240_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -176,8 +176,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 57_182_000 picoseconds. - Weight::from_parts(58_877_000, 6196) + // Minimum execution time: 58_577_000 picoseconds. + Weight::from_parts(59_729_000, 6196) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -203,8 +203,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 45_073_000 picoseconds. - Weight::from_parts(45_927_000, 3610) + // Minimum execution time: 45_804_000 picoseconds. + Weight::from_parts(46_702_000, 3610) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 2c51afde7b3..e2fe122a12d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,28 +17,26 @@ //! 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: `[]` +//! DATE: 2023-10-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 +//! HOSTNAME: `runner-vmdtonbz-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 +// 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 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::generic +// --chain=asset-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,33 +48,39 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 415_688_000 picoseconds. + Weight::from_parts(433_876_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } 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) + // Minimum execution time: 3_209_000 picoseconds. + Weight::from_parts(3_465_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -84,79 +88,85 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 11_582_000 picoseconds. - Weight::from_parts(11_830_000, 3568) + // Minimum execution time: 7_940_000 picoseconds. + Weight::from_parts(8_208_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) + // Minimum execution time: 9_336_000 picoseconds. + Weight::from_parts(9_733_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) + // Minimum execution time: 3_368_000 picoseconds. + Weight::from_parts(3_700_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) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(2_034_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) + // Minimum execution time: 1_870_000 picoseconds. + Weight::from_parts(1_972_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) + // Minimum execution time: 1_890_000 picoseconds. + Weight::from_parts(1_962_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) + // Minimum execution time: 2_660_000 picoseconds. + Weight::from_parts(2_744_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) + // Minimum execution time: 1_845_000 picoseconds. + Weight::from_parts(1_945_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 54_283_000 picoseconds. + Weight::from_parts(54_969_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -164,8 +174,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 16_456_000 picoseconds. - Weight::from_parts(16_846_000, 3625) + // Minimum execution time: 11_850_000 picoseconds. + Weight::from_parts(12_328_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -173,11 +183,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_974_000 picoseconds. - Weight::from_parts(3_108_000, 0) + // Minimum execution time: 1_891_000 picoseconds. + Weight::from_parts(1_950_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -190,11 +202,11 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 29_823_000 picoseconds. - Weight::from_parts(30_776_000, 3574) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 23_644_000 picoseconds. + Weight::from_parts(24_296_000, 3610) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) @@ -203,137 +215,151 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_966_000 picoseconds. - Weight::from_parts(5_157_000, 0) + // Minimum execution time: 3_719_000 picoseconds. + Weight::from_parts(3_896_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) + // Minimum execution time: 125_710_000 picoseconds. + Weight::from_parts(132_434_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) + // Minimum execution time: 11_650_000 picoseconds. + Weight::from_parts(12_277_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) + // Minimum execution time: 1_978_000 picoseconds. + Weight::from_parts(2_070_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) + // Minimum execution time: 1_899_000 picoseconds. + Weight::from_parts(2_002_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) + // Minimum execution time: 2_133_000 picoseconds. + Weight::from_parts(2_194_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 58_644_000 picoseconds. + Weight::from_parts(60_614_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } 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) + // Minimum execution time: 5_185_000 picoseconds. + Weight::from_parts(5_366_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 54_443_000 picoseconds. + Weight::from_parts(55_873_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } 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) + // Minimum execution time: 1_909_000 picoseconds. + Weight::from_parts(2_011_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) + // Minimum execution time: 1_814_000 picoseconds. + Weight::from_parts(1_956_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) + // Minimum execution time: 1_875_000 picoseconds. + Weight::from_parts(2_003_000, 0) } + // 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`) 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)) + // Measured: `39` + // Estimated: `3504` + // Minimum execution time: 7_376_000 picoseconds. + Weight::from_parts(7_620_000, 3504) + .saturating_add(T::DbWeight::get().reads(2)) } 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) + // Minimum execution time: 1_863_000 picoseconds. + Weight::from_parts(1_964_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) + // Minimum execution time: 1_956_000 picoseconds. + Weight::from_parts(2_057_000, 0) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 83fa31abd7f..367c18966e4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -17,8 +17,8 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, - ToRococoXcmRouter, ToWococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, - WeightToFee, XcmpQueue, + ToRococoXcmRouter, ToWestendXcmRouter, ToWococoXcmRouter, TransactionByteFee, + TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, @@ -44,16 +44,16 @@ use rococo_runtime_constants::system_parachain; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, + AccountId32Aliases, 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, - XcmFeeManagerFromComponents, XcmFeeToAccount, + IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -260,10 +260,6 @@ match_types! { 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 @@ -478,6 +474,8 @@ impl Contains for SafeCallFilter { pallet_uniques::Call::buy_item { .. } ) | RuntimeCall::ToWococoXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) | RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) | RuntimeCall::ToRococoXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) @@ -567,11 +565,13 @@ impl xcm_executor::Config for XcmConfig { 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). + // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus + // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being + // held). 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_westend::IsTrustedBridgedReserveLocationForConcreteAsset, bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset, ); type IsTeleporter = TrustedTeleporters; @@ -624,8 +624,11 @@ impl xcm_executor::Config for XcmConfig { XcmFeeToAccount, >; type MessageExporter = (); - type UniversalAliases = - (bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases); + type UniversalAliases = ( + bridging::to_wococo::UniversalAliases, + bridging::to_rococo::UniversalAliases, + bridging::to_westend::UniversalAliases, + ); type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; @@ -653,6 +656,9 @@ pub type XcmRouter = WithUniqueTopic<( // 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 Westend + // GlobalConsensus + ToWestendXcmRouter, // Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo // GlobalConsensus ToRococoXcmRouter, @@ -675,14 +681,7 @@ impl pallet_xcm::Config for Runtime { 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 XcmReserveTransferFilter = Everything; type Weigher = WeightInfoBounds< crate::weights::xcm::AssetHubRococoXcmWeight, RuntimeCall, @@ -775,6 +774,7 @@ pub mod bridging { pub BridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() .chain(to_wococo::BridgeTable::get()) + .chain(to_westend::BridgeTable::get()) .chain(to_rococo::BridgeTable::get()) .collect(); } @@ -819,13 +819,6 @@ pub mod bridging { ) ]; - /// 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![ @@ -852,12 +845,6 @@ pub mod bridging { ), >; - /// Allows to reserve transfer assets to `AssetHubWococo`. - pub type AllowedReserveTransferAssets = LocationWithAssetFilters< - Equals, - AllowedReserveTransferAssetsToAssetHubWococo, - >; - impl Contains for ToWococoXcmRouter { fn contains(call: &RuntimeCall) -> bool { matches!( @@ -870,6 +857,82 @@ pub mod bridging { } } + pub mod to_westend { + use super::*; + + parameter_types! { + pub SiblingBridgeHubWithBridgeHubWestendInstance: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(SiblingBridgeHubParaId::get()), + PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX) + ) + ); + + pub const WestendNetwork: NetworkId = NetworkId::Westend; + pub AssetHubWestend: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(WestendNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID))); + pub WndLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(WestendNetwork::get()))); + + pub WndFromAssetHubWestend: (MultiAssetFilter, MultiLocation) = ( + Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), + AssetHubWestend::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( + WestendNetwork::get(), + Some(sp_std::vec![ + AssetHubWestend::get().interior.split_global().expect("invalid configuration for AssetHubWestend").1, + ]), + SiblingBridgeHub::get(), + // base delivery fee to local `BridgeHub` + Some(( + XcmBridgeHubRouterFeeAssetId::get(), + bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(), + ).into()) + ) + ]; + + /// Universal aliases + pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter( + sp_std::vec![ + (SiblingBridgeHubWithBridgeHubWestendInstance::get(), GlobalConsensus(WestendNetwork::get())) + ] + ); + } + + impl Contains<(MultiLocation, Junction)> for UniversalAliases { + fn contains(alias: &(MultiLocation, Junction)) -> bool { + UniversalAliases::get().contains(alias) + } + } + + /// 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 WND from AssetHubWestend + xcm_builder::Case, + // and nothing else + ), + >; + + impl Contains for ToWestendXcmRouter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) + ) + } + } + } + pub mod to_rococo { use super::*; @@ -908,13 +971,6 @@ pub mod bridging { ) ]; - /// 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![ @@ -941,12 +997,6 @@ pub mod bridging { ), >; - /// Allows to reserve transfer assets to `AssetHubRococo`. - pub type AllowedReserveTransferAssets = LocationWithAssetFilters< - Equals, - AllowedReserveTransferAssetsToAssetHubRococo, - >; - impl Contains for ToRococoXcmRouter { fn contains(call: &RuntimeCall) -> bool { matches!( @@ -967,15 +1017,17 @@ pub mod bridging { 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"); + to_westend::UniversalAliases::get() + .into_iter() + .find_map(|(location, junction)| { + match to_westend::SiblingBridgeHubWithBridgeHubWestendInstance::get() + .eq(&location) + { + true => Some((location, junction)), + false => None, + } + }); + assert!(alias.is_some(), "we expect here BridgeHubRococo to Westend 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 index 18f5f4fc41e..c3d3c4abbbb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -29,14 +29,16 @@ pub use asset_hub_rococo_runtime::{ AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, SessionKeys, System, ToRococoXcmRouterInstance, - ToWococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + ToWestendXcmRouterInstance, ToWococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, +}; +use asset_test_utils::{ + test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, }; -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}, + traits::fungibles::InspectEnumerable, weights::{Weight, WeightToFee as WeightToFeeT}, }; use parachains_common::{ @@ -642,11 +644,43 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p }) ); +fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( + bridging_configuration: fn() -> TestBridgingConfig, +) { + 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_configuration, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + Some(xcm_config::TreasuryAccount::get()), + ) +} + mod asset_hub_rococo_tests { use super::*; - fn bridging_to_asset_hub_wococo() -> asset_test_utils::test_cases_over_bridge::TestBridgingConfig - { + fn bridging_to_asset_hub_wococo() -> TestBridgingConfig { asset_test_utils::test_cases_over_bridge::TestBridgingConfig { bridged_network: bridging::to_wococo::WococoNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), @@ -655,35 +689,26 @@ mod asset_hub_rococo_tests { } } + fn bridging_to_asset_hub_westend() -> TestBridgingConfig { + asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + bridged_network: bridging::to_westend::WestendNetwork::get(), + local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), + local_bridge_hub_location: bridging::SiblingBridgeHub::get(), + bridged_target_location: bridging::to_westend::AssetHubWestend::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, - } - }), + fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_wococo_works() { + limited_reserve_transfer_assets_for_native_asset_over_bridge_works( bridging_to_asset_hub_wococo, - WeightLimit::Unlimited, - Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), - Some(xcm_config::TreasuryAccount::get()), + ) + } + + #[test] + fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_westend_works() { + limited_reserve_transfer_assets_for_native_asset_over_bridge_works( + bridging_to_asset_hub_westend, ) } @@ -713,7 +738,32 @@ mod asset_hub_rococo_tests { } #[test] - fn report_bridge_status_from_xcm_bridge_router_works() { + fn receive_reserve_asset_deposited_wnd_from_asset_hub_westend_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 WNDs + (MultiLocation { parents: 2, interior: X1(GlobalConsensus(Westend)) }, 1000000000000, 1_000_000_000), + bridging_to_asset_hub_westend, + ( + X1(PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)), + GlobalConsensus(Westend), + X1(Parachain(1000)) + ) + ) + } + + #[test] + fn report_bridge_status_from_xcm_bridge_router_for_wococo_works() { asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< Runtime, AllPalletsWithoutSystem, @@ -764,6 +814,58 @@ mod asset_hub_rococo_tests { ) } + #[test] + fn report_bridge_status_from_xcm_bridge_router_for_westend_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToWestendXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_westend, + || { + 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::ToWestendXcmRouter( + 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::ToWestendXcmRouter( + 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 @@ -782,14 +884,43 @@ mod asset_hub_rococo_tests { } ) .encode() - ) + ); + assert_eq!( + RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode(), + bp_asset_hub_rococo::Call::ToWestendXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ); } #[test] - fn check_sane_weight_report_bridge_status() { + fn check_sane_weight_report_bridge_status_for_wococo() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); + } + + #[test] + fn check_sane_weight_report_bridge_status_for_westend() { use pallet_xcm_bridge_hub_router::WeightInfo; let actual = >::WeightInfo::report_bridge_status(); let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); assert!( @@ -804,9 +935,8 @@ mod asset_hub_rococo_tests { 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 { + fn bridging_to_asset_hub_rococo() -> TestBridgingConfig { + TestBridgingConfig { bridged_network: bridging::to_rococo::RococoNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), local_bridge_hub_location: bridging::SiblingBridgeHub::get(), @@ -837,41 +967,15 @@ mod asset_hub_wococo_tests { assert_eq!(flavor, xcm_config::Flavor::get()); } - fn with_wococo_flavor_bridging_to_asset_hub_rococo( - ) -> asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + fn with_wococo_flavor_bridging_to_asset_hub_rococo() -> 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, - } - }), + fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_rococo_works() { + limited_reserve_transfer_assets_for_native_asset_over_bridge_works( with_wococo_flavor_bridging_to_asset_hub_rococo, - WeightLimit::Unlimited, - Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), - Some(xcm_config::TreasuryAccount::get()), ) } @@ -989,113 +1093,6 @@ mod asset_hub_wococo_tests { } } -/// 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::< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 95e46f31243..1a7f019d4f9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -71,7 +71,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 } @@ -79,10 +79,15 @@ parachain-info = { package = "staging-parachain-info", path = "../../../pallets/ 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } + [dev-dependencies] hex-literal = "0.4.1" asset-test-utils = { path = "../test-utils" } -sp-io = { path = "../../../../../substrate/primitives/io" } [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -112,6 +117,7 @@ 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", @@ -146,6 +152,7 @@ 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", @@ -153,6 +160,9 @@ try-runtime = [ ] std = [ "assets-common/std", + "bp-asset-hub-rococo/std", + "bp-asset-hub-westend/std", + "bp-bridge-hub-westend/std", "codec/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", @@ -189,6 +199,7 @@ 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", 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 30d38422242..737b8625881 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -43,7 +43,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, - ConstU64, ConstU8, InstanceFilter, + ConstU64, ConstU8, Equals, InstanceFilter, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -54,6 +54,7 @@ use frame_system::{ }; use pallet_asset_conversion_tx_payment::AssetConversionAdapter; use pallet_nfts::PalletFeatures; +use pallet_xcm::EnsureXcm; pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, @@ -108,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_003_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -794,6 +795,37 @@ impl pallet_nfts::Config for Runtime { type Helper = (); } +/// XCM router instance to BridgeHub with bridging capabilities for `Rococo` global +/// consensus with dynamic fees and back-pressure. +pub type ToRococoXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance1; +impl pallet_xcm_bridge_hub_router::Config for Runtime { + type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; + + type UniversalLocation = xcm_config::UniversalLocation; + type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; + type Bridges = xcm_config::bridging::NetworkExportTable; + + #[cfg(not(feature = "runtime-benchmarks"))] + type BridgeHubOrigin = EnsureXcm>; + #[cfg(feature = "runtime-benchmarks")] + type BridgeHubOrigin = frame_support::traits::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 @@ -825,6 +857,8 @@ construct_runtime!( 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, + // Bridge utilities. + ToRococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -946,6 +980,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_xcm_bridge_hub_router, ToRococo] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -1231,6 +1266,7 @@ impl_runtime_apis! { 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 @@ -1246,6 +1282,8 @@ impl_runtime_apis! { type Foreign = pallet_assets::Pallet::; type Pool = pallet_assets::Pallet::; + type ToRococo = XcmBridgeHubRouterBench; + let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1274,6 +1312,25 @@ impl_runtime_apis! { 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_rococo::AssetHubRococo::get() + } + } + use xcm::latest::prelude::*; use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; use pallet_xcm_benchmarks::asset_instance_from; @@ -1329,7 +1386,13 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(UNITS), id: Concrete(WestendLocation::get()) }, )); pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; - pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; + // AssetHubWestend trusts AssetHubRococo as reserve for ROCs + pub TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some( + ( + xcm_config::bridging::to_rococo::AssetHubRococo::get(), + MultiAsset::from((xcm_config::bridging::to_rococo::RocLocation::get(), 1000000000000 as u128)) + ) + ); } impl pallet_xcm_benchmarks::fungible::Config for Runtime { @@ -1360,7 +1423,10 @@ impl_runtime_apis! { } fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { - Err(BenchmarkError::Skip) + 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> { @@ -1399,6 +1465,8 @@ impl_runtime_apis! { type Foreign = pallet_assets::Pallet::; type Pool = pallet_assets::Pallet::; + type ToRococo = XcmBridgeHubRouterBench; + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 281c013b337..a857dc62062 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -33,6 +33,7 @@ pub mod pallet_timestamp; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; +pub mod pallet_xcm_bridge_hub_router; pub mod paritydb_weights; pub mod rocksdb_weights; pub mod xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs new file mode 100644 index 00000000000..9d0d0cbc655 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.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-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// 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-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_bridge_hub_router`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { + /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`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: `193` + // Estimated: `1678` + // Minimum execution time: 8_157_000 picoseconds. + Weight::from_parts(8_481_000, 0) + .saturating_add(Weight::from_parts(0, 1678)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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: `111` + // Estimated: `1596` + // Minimum execution time: 3_319_000 picoseconds. + Weight::from_parts(3_445_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .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: 10_396_000 picoseconds. + Weight::from_parts(10_914_000, 0) + .saturating_add(Weight::from_parts(0, 1502)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`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: `426` + // Estimated: `3891` + // Minimum execution time: 45_902_000 picoseconds. + Weight::from_parts(46_887_000, 0) + .saturating_add(Weight::from_parts(0, 3891)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} 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 3e47cf077a2..b321f396ea1 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 @@ -209,7 +209,7 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { XcmGeneric::::clear_transact_status() } fn universal_origin(_: &Junction) -> Weight { - Weight::MAX + XcmGeneric::::universal_origin() } fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { Weight::MAX 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 f482064e84e..89b0d97e7c1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 25_407_000 picoseconds. - Weight::from_parts(25_949_000, 3593) + // Minimum execution time: 20_295_000 picoseconds. + Weight::from_parts(21_142_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,15 +65,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 51_335_000 picoseconds. - Weight::from_parts(52_090_000, 6196) + // Minimum execution time: 42_356_000 picoseconds. + Weight::from_parts(43_552_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: `System::Account` (r:2 w:2) + // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -87,48 +89,53 @@ impl WeightInfo { pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `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)) + // Estimated: `8799` + // Minimum execution time: 85_553_000 picoseconds. + Weight::from_parts(87_177_000, 8799) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: `Benchmark::Override` (r:0 w:0) - // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) pub fn reserve_asset_deposited() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) + // Estimated: `1489` + // Minimum execution time: 6_166_000 picoseconds. + Weight::from_parts(6_352_000, 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`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `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)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 184_462_000 picoseconds. + Weight::from_parts(189_593_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_602_000 picoseconds. - Weight::from_parts(3_844_000, 0) + // Minimum execution time: 3_018_000 picoseconds. + Weight::from_parts(3_098_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,15 +143,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_480_000 picoseconds. - Weight::from_parts(26_142_000, 3593) + // Minimum execution time: 18_583_000 picoseconds. + Weight::from_parts(19_057_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:1 w:1) + // Storage: `System::Account` (r:2 w:2) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -158,20 +167,24 @@ impl WeightInfo { pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `145` - // Estimated: `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)) + // Estimated: `6196` + // Minimum execution time: 56_666_000 picoseconds. + Weight::from_parts(58_152_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) @@ -180,9 +193,9 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `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)) + // Minimum execution time: 44_197_000 picoseconds. + Weight::from_parts(45_573_000, 3610) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index e776529eb7f..3b19e61fa21 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,28 +17,26 @@ //! 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: `[]` +//! DATE: 2023-10-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-westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 // 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::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-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::generic +// --chain=asset-hub-westend-dev +// --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)] @@ -52,31 +50,35 @@ pub struct WeightInfo(PhantomData); impl WeightInfo { // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 405_795_000 picoseconds. - Weight::from_parts(421_225_000, 3610) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 415_033_000 picoseconds. + Weight::from_parts(429_573_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_021_000 picoseconds. - Weight::from_parts(4_234_000, 0) + // Minimum execution time: 3_193_000 picoseconds. + Weight::from_parts(3_620_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -84,79 +86,83 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 11_004_000 picoseconds. - Weight::from_parts(11_217_000, 3568) + // Minimum execution time: 8_045_000 picoseconds. + Weight::from_parts(8_402_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: 12_888_000 picoseconds. - Weight::from_parts(13_249_000, 0) + // Minimum execution time: 9_827_000 picoseconds. + Weight::from_parts(10_454_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_504_000 picoseconds. - Weight::from_parts(4_984_000, 0) + // Minimum execution time: 3_330_000 picoseconds. + Weight::from_parts(3_677_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(2_887_000, 0) + // Minimum execution time: 1_947_000 picoseconds. + Weight::from_parts(2_083_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_753_000 picoseconds. - Weight::from_parts(2_844_000, 0) + // Minimum execution time: 1_915_000 picoseconds. + Weight::from_parts(1_993_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_741_000 picoseconds. - Weight::from_parts(2_826_000, 0) + // Minimum execution time: 1_918_000 picoseconds. + Weight::from_parts(2_048_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_417_000 picoseconds. - Weight::from_parts(3_525_000, 0) + // Minimum execution time: 2_683_000 picoseconds. + Weight::from_parts(3_064_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_775_000 picoseconds. - Weight::from_parts(2_853_000, 0) + // Minimum execution time: 1_893_000 picoseconds. + Weight::from_parts(2_159_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 27_035_000 picoseconds. - Weight::from_parts(27_734_000, 3610) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 53_116_000 picoseconds. + Weight::from_parts(54_154_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -164,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 15_728_000 picoseconds. - Weight::from_parts(16_145_000, 3625) + // Minimum execution time: 12_381_000 picoseconds. + Weight::from_parts(12_693_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -173,11 +179,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_630_000 picoseconds. - Weight::from_parts(2_700_000, 0) + // Minimum execution time: 1_933_000 picoseconds. + Weight::from_parts(1_983_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -192,9 +200,9 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 29_996_000 picoseconds. - Weight::from_parts(30_620_000, 3610) - .saturating_add(T::DbWeight::get().reads(6)) + // Minimum execution time: 24_251_000 picoseconds. + Weight::from_parts(24_890_000, 3610) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) @@ -203,127 +211,145 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_629_000 picoseconds. - Weight::from_parts(4_861_000, 0) + // Minimum execution time: 3_850_000 picoseconds. + Weight::from_parts(4_082_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: 135_145_000 picoseconds. - Weight::from_parts(142_115_000, 0) + // Minimum execution time: 112_248_000 picoseconds. + Weight::from_parts(124_454_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_948_000 picoseconds. - Weight::from_parts(12_160_000, 0) + // Minimum execution time: 11_457_000 picoseconds. + Weight::from_parts(12_060_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_718_000 picoseconds. - Weight::from_parts(2_794_000, 0) + // Minimum execution time: 1_959_000 picoseconds. + Weight::from_parts(2_076_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_590_000 picoseconds. - Weight::from_parts(2_674_000, 0) + // Minimum execution time: 1_920_000 picoseconds. + Weight::from_parts(1_994_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_858_000 picoseconds. - Weight::from_parts(2_939_000, 0) + // Minimum execution time: 2_149_000 picoseconds. + Weight::from_parts(2_394_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 30_652_000 picoseconds. - Weight::from_parts(31_552_000, 3610) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 58_011_000 picoseconds. + Weight::from_parts(59_306_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_408_000 picoseconds. - Weight::from_parts(5_597_000, 0) + // Minimum execution time: 5_031_000 picoseconds. + Weight::from_parts(5_243_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 27_144_000 picoseconds. - Weight::from_parts(27_736_000, 3610) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `246` + // Estimated: `6196` + // Minimum execution time: 53_078_000 picoseconds. + Weight::from_parts(54_345_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_696_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 1_936_000 picoseconds. + Weight::from_parts(2_002_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_655_000 picoseconds. - Weight::from_parts(2_720_000, 0) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(1_950_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_599_000 picoseconds. - Weight::from_parts(2_723_000, 0) + // Minimum execution time: 1_882_000 picoseconds. + Weight::from_parts(1_977_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + pub fn universal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 3_912_000 picoseconds. + Weight::from_parts(4_167_000, 1489) + .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_630_000 picoseconds. - Weight::from_parts(2_728_000, 0) + // Minimum execution time: 1_911_000 picoseconds. + Weight::from_parts(1_971_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_797_000 picoseconds. - Weight::from_parts(2_928_000, 0) + // Minimum execution time: 1_990_000 picoseconds. + Weight::from_parts(2_076_000, 0) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 6b5ce904da9..a44c4524656 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 @@ -15,11 +15,10 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, - FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, - XcmpQueue, + FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, + PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ToRococoXcmRouter, + TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; -use crate::ForeignAssets; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, matching::{FromSiblingParachain, IsForeignConcreteAsset}, @@ -47,12 +46,13 @@ use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, 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, - XcmFeeManagerFromComponents, XcmFeeToAccount, + EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, + IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -90,6 +90,9 @@ pub type LocationToAccountId = ( // Foreign chain account alias into local 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. @@ -256,6 +259,14 @@ 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().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) => + return true, + _ => (), + }; + matches!( call, RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | @@ -445,7 +456,9 @@ impl Contains for SafeCallFilter { pallet_uniques::Call::set_accept_ownership { .. } | pallet_uniques::Call::set_collection_max_supply { .. } | pallet_uniques::Call::set_price { .. } | - pallet_uniques::Call::buy_item { .. }, + pallet_uniques::Call::buy_item { .. } + ) | RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) ) } @@ -469,6 +482,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom<( ParentOrParentsPlurality, Equals, + Equals, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, @@ -492,6 +506,15 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; +/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. +pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = + AssetFeeAsExistentialDepositMultiplier< + Runtime, + WeightToFee, + pallet_assets::BalanceToAssetBalance, + ForeignAssetsInstance, + >; + match_types! { pub type SystemParachains: impl Contains = { MultiLocation { @@ -526,10 +549,11 @@ impl xcm_executor::Config for XcmConfig { type XcmSender = XcmRouter; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - // Asset Hub Westend does not recognize a reserve location for any asset. This does not prevent - // 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 = (); + // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus + // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being + // held). Asset Hub may _act_ as a reserve location for WND and assets created + // under `pallet-assets`. Users must use teleport where allowed (e.g. WND with the Relay Chain). + type IsReserve = (bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset,); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -553,6 +577,19 @@ impl xcm_executor::Config for XcmConfig { 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; @@ -567,7 +604,7 @@ impl xcm_executor::Config for XcmConfig { XcmFeeToAccount, >; type MessageExporter = (); - type UniversalAliases = Nothing; + type UniversalAliases = (bridging::to_rococo::UniversalAliases,); type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; @@ -579,13 +616,21 @@ pub type LocalOriginToLocation = SignedToAccountId32; -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( +/// 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 Rococo + // GlobalConsensus + ToRococoXcmRouter, )>; #[cfg(feature = "runtime-benchmarks")] @@ -672,3 +717,124 @@ where 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; + + parameter_types! { + pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_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 = WestendLocation::get().into(); + /// Price per byte - can be adjusted via governance `set_storage` call. + pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + + pub BridgeTable: sp_std::vec::Vec = + sp_std::vec::Vec::new().into_iter() + .chain(to_rococo::BridgeTable::get()) + .collect(); + } + + pub type NetworkExportTable = xcm_builder::NetworkExportTable; + + pub mod to_rococo { + use super::*; + + parameter_types! { + pub SiblingBridgeHubWithBridgeHubRococoInstance: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(SiblingBridgeHubParaId::get()), + PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_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_westend::BridgeHubWestendBaseFeeInWnds::get(), + ).into()) + ) + ]; + + /// 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) + } + } + + /// 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 + ), + >; + + 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_rococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| { + match to_rococo::SiblingBridgeHubWithBridgeHubRococoInstance::get() + .eq(&location) + { + true => Some((location, junction)), + false => None, + } + }); + assert!(alias.is_some(), "we expect here BridgeHubWestend to Rococo mapping at least"); + Some(alias.unwrap()) + } + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 599ff90e254..de87a98fb0b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -19,20 +19,19 @@ use asset_hub_westend_runtime::{ xcm_config::{ - AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - WestendLocation, + self, bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, + ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation, + WestendLocation, XcmConfig, }, - AllPalletsWithoutSystem, MetadataDepositBase, MetadataDepositPerByte, RuntimeCall, - RuntimeEvent, + AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, + ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, + RuntimeCall, RuntimeEvent, SessionKeys, ToRococoXcmRouterInstance, TrustBackedAssetsInstance, + XcmpQueue, }; -pub use asset_hub_westend_runtime::{ - xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig}, - AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System, - TrustBackedAssetsInstance, +use asset_test_utils::{ + test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, }; -use asset_test_utils::{CollatorSessionKeys, ExtBuilder, XcmReceivedFrom}; -use codec::{Decode, DecodeLimit, Encode}; +use codec::{Decode, Encode}; use cumulus_primitives_utility::ChargeWeightInFungibles; use frame_support::{ assert_noop, assert_ok, @@ -42,14 +41,10 @@ use frame_support::{ use parachains_common::{ westend::fee::WeightToFee, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, }; -use sp_io; use sp_runtime::traits::MaybeEquivalence; use std::convert::Into; -use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH}; -use xcm_executor::{ - traits::{Identity, JustTry, WeightTrader}, - XcmExecutor, -}; +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]; @@ -59,14 +54,18 @@ type AssetIdForTrustBackedAssetsConvert = type RuntimeHelper = asset_test_utils::RuntimeHelper; -fn collator_session_keys() -> CollatorSessionKeys { - CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, +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() @@ -253,7 +252,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() { // Set Alice as block author, who will receive fees RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); - // We are going to buy 5e9 weight + // We are going to buy small amount let bought = Weight::from_parts(500_000_000u64, 0); let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap(); @@ -641,28 +640,178 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p }) ); -#[test] -fn plain_receive_teleported_asset_works() { - 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 data = hex_literal::hex!("02100204000100000b00a0724e18090a13000100000b00a0724e180901e20f5e480d010004000101001299557001f55815d3fcb53c74463acb0cf6d14d4639b340982c60877f384609").to_vec(); - let message_id = sp_io::hashing::blake2_256(&data); +fn bridging_to_asset_hub_rococo() -> TestBridgingConfig { + 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(), + } +} - let maybe_msg = VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data.as_ref(), +#[test] +fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_rococo_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_rococo, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + Some(xcm_config::TreasuryAccount::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), + bridging_to_asset_hub_rococo, + ( + X1(PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)), + GlobalConsensus(Rococo), + X1(Parachain(1000)) ) - .map(xcm::v3::Xcm::::try_from).expect("failed").expect("failed"); + ) +} +#[test] +fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToRococoXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_rococo, + || { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_westend::Call::ToRococoXcmRouter( + bp_asset_hub_westend::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_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_westend::Call::ToRococoXcmRouter( + bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: false, + } + ) + .encode() + .into(), + } + ] + .into() + }, + ) +} - let outcome = - XcmExecutor::::execute_xcm(Parent, maybe_msg, message_id, RuntimeHelper::xcm_max_weight(XcmReceivedFrom::Parent)); - assert_eq!(outcome.ensure_complete(), Ok(())); +#[test] +fn test_report_bridge_status_call_compatibility() { + // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding + assert_eq!( + RuntimeCall::ToRococoXcmRouter(pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, }) + .encode(), + bp_asset_hub_westend::Call::ToRococoXcmRouter( + bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ) +} + +#[test] +fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); +} + +#[test] +fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { + asset_test_utils::test_cases::change_storage_constant_by_governance_works::< + 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/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index ef1f837a7e1..9bd6557f350 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -9,6 +9,15 @@ - [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 Rococo <-> Westend bridge](#how-to-test-local-rococo---westend-bridge) + - [Run Rococo/Westend chains with zombienet](#run-rococowestend-chains-with-zombienet) + - [Init bridge and run relayer between BridgeHubRococo and + BridgeHubWestend](#init-bridge-and-run-relayer-between-bridgehubrococo-and-bridgehubwestend) + - [Initialize configuration for transfer asset over bridge + (ROCs/WNDs)](#initialize-configuration-for-transfer-asset-over-bridge-rocswnds) + - [Send messages - transfer asset over bridge (ROCs/WNDs)](#send-messages---transfer-asset-over-bridge-rocswnds) + - [Claim relayer's rewards on BridgeHubRococo and + BridgeHubWestend](#claim-relayers-rewards-on-bridgehubrococo-and-bridgehubwestend) - [How to test local BridgeHubKusama/BridgeHubPolkadot](#how-to-test-local-bridgehubkusamabridgehubpolkadot) # Bridge-hub Parachains @@ -136,9 +145,9 @@ cd **Check parachain headers relaying:** - Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: - **bridgeWococoParachain** - Keys: **parasInfo(None)** + **bridgeWococoParachains** - Keys: **parasInfo(None)** - Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: - **bridgeRococoParachain** - Keys: **parasInfo(None)** + **bridgeRococoParachains** - Keys: **parasInfo(None)** ### Initialize configuration for transfer asset over bridge (ROCs/WOCs) @@ -172,10 +181,10 @@ cd - 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 `bridgeRococoToWococoMessages.MessageAccepted`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer - - BridgeHubWococo (see `bridgeWococoToRococoMessages.MessagesReceived`, `xcmpQueue.XcmpMessageSent`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/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 `bridgeRococoToWococoMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/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 @@ -197,6 +206,111 @@ cd - 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 Rococo <-> Westend bridge + +### Run Rococo/Westend 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 ./cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +``` + +``` +cd + +# Westend + BridgeHubWestend + AssetHub for Westend (mirroring Polkadot) +POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \ +POLKADOT_PARACHAIN_BINARY_PATH=~/local_bridge_testing/bin/polkadot-parachain \ +POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=~/local_bridge_testing/bin/polkadot-parachain-asset-hub \ + ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +``` + +### Init bridge and run relayer between BridgeHubRococo and BridgeHubWestend + +**Accounts of BridgeHub parachains:** +- `Bob` is pallet owner of all bridge pallets + +#### Run with script +``` +cd + +./cumulus/scripts/bridges_rococo_westend.sh run-relay +``` + +**Check relay-chain headers relaying:** +- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: + **bridgeWestendGrandpa** - Keys: **bestFinalized()** +- Westend parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: + **bridgeRococoGrandpa** - Keys: **bestFinalized()** + +**Check parachain headers relaying:** +- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: + **bridgeWestendParachains** - Keys: **parasInfo(None)** +- Westend parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: + **bridgeRococoParachains** - Keys: **parasInfo(None)** + +### Initialize configuration for transfer asset over bridge (ROCs/WNDs) + +This initialization does several things: +- creates `ForeignAssets` for wrappedROCs/wrappedWNDs +- drips SA for AssetHubRococo on AssetHubWestend (and vice versa) which holds reserved assets on source chains +``` +cd + +./cumulus/scripts/bridges_rococo_westend.sh init-asset-hub-rococo-local +./cumulus/scripts/bridges_rococo_westend.sh init-bridge-hub-rococo-local +./cumulus/scripts/bridges_rococo_westend.sh init-asset-hub-westend-local +./cumulus/scripts/bridges_rococo_westend.sh init-bridge-hub-westend-local +``` + +### Send messages - transfer asset over bridge (ROCs/WNDs) + +Do (asset) transfers: +``` +cd + +# ROCs from Rococo's Asset Hub to Westend's. +./cumulus/scripts/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-rococo-local +``` +``` +cd + +# WNDs from Westend's Asset Hub to Rococo's. +./cumulus/scripts/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-westend-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 `bridgeWestendMessages.MessageAccepted`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + - BridgeHubWestend (see `bridgeRococoMessages.MessagesReceived`, `xcmpQueue.XcmpMessageSent`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer + - AssetHubWestend (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer + - BridgeHubRocococ (see `bridgeWestendMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + +### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend + +**Accounts of BridgeHub parachains:** +- `//Charlie` is relayer account on BridgeHubRococo +- `//Charlie` is relayer account on BridgeHubWestend + +``` +cd + +# Claim rewards on BridgeHubWestend: +./cumulus/scripts/bridges_rococo_westend.sh claim-rewards-bridge-hub-rococo-local + +# Claim rewards on BridgeHubWestend: +./cumulus/scripts/bridges_rococo_westend.sh claim-rewards-bridge-hub-westend-local +``` + +- open explorers: (see zombienets) + - BridgeHubRococo (see 2x `bridgeRelayers.RewardPaid`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + - BridgeHubWestend (see 2x `bridgeRelayers.RewardPaid`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer + ## How to test local BridgeHubKusama/BridgeHubPolkadot TODO: see `# !!! READ HERE` above 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 c7e31c80ce4..339544da901 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -75,8 +75,10 @@ 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", 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-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", 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 } bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } @@ -85,6 +87,7 @@ bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", d bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } +bp-westend = { path = "../../../../../bridges/primitives/chain-westend", default-features = false } bp-wococo = { path = "../../../../../bridges/primitives/chain-wococo", default-features = false } pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } @@ -102,8 +105,10 @@ sp-keyring = { path = "../../../../../substrate/primitives/keyring" } default = [ "std" ] std = [ "bp-asset-hub-rococo/std", + "bp-asset-hub-westend/std", "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", + "bp-bridge-hub-westend/std", "bp-bridge-hub-wococo/std", "bp-header-chain/std", "bp-messages/std", @@ -112,6 +117,7 @@ std = [ "bp-relayers/std", "bp-rococo/std", "bp-runtime/std", + "bp-westend/std", "bp-wococo/std", "bridge-runtime-common/std", "codec/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index a1fded8470c..296ec88a856 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -33,6 +33,8 @@ parameter_types! { pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; pub const WococoBridgeParachainPalletName: &'static str = "Paras"; pub const MaxWococoParaHeadDataSize: u32 = bp_wococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; + pub const WestendBridgeParachainPalletName: &'static str = "Paras"; + pub const MaxWestendParaHeadDataSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; pub storage RequiredStakeForStakeAndSlash: Balance = 1_000_000; pub const RelayerStakeLease: u32 = 8; @@ -87,6 +89,29 @@ impl pallet_bridge_parachains::Config for Runtime type MaxParaHeadDataSize = MaxRococoParaHeadDataSize; } +/// Add GRANDPA bridge pallet to track Westend relay chain. +pub type BridgeGrandpaWestendInstance = pallet_bridge_grandpa::Instance3; +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_westend::Westend; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = RelayChainHeadersToKeep; + type WeightInfo = weights::pallet_bridge_grandpa_westend_finality::WeightInfo; +} + +/// Add parachain bridge pallet to track Westend BridgeHub parachain +pub type BridgeParachainWestendInstance = pallet_bridge_parachains::Instance3; +impl pallet_bridge_parachains::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_parachains_within_westend::WeightInfo; + type BridgesGrandpaPalletInstance = BridgeGrandpaWestendInstance; + type ParasPalletName = WestendBridgeParachainPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ParachainHeadsToKeep; + type MaxParaHeadDataSize = MaxWestendParaHeadDataSize; +} + /// Allows collect and claim rewards for relayers impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; 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_to_rococo_config.rs similarity index 87% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_rococo_config.rs index d09ee24976d..35497c84068 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_to_rococo_config.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Bridge definitions used on BridgeHub with the Wococo flavor. +//! Bridge definitions used on BridgeHub with the Wococo flavor for bridging to BridgeHubRococo. use crate::{ bridge_common_config::{BridgeParachainRococoInstance, DeliveryRewardInBalance}, - weights, AccountId, BridgeWococoToRococoMessages, ParachainInfo, Runtime, RuntimeEvent, - RuntimeOrigin, XcmRouter, + weights, AccountId, BridgeRococoMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, + XcmRouter, }; use bp_messages::LaneId; use bridge_runtime_common::{ @@ -54,23 +54,26 @@ parameter_types! { bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pub BridgeHubWococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Wococo), Parachain(ParachainInfo::parachain_id().into())); - pub BridgeWococoToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub BridgeWococoToRococoMessagesPalletInstance: 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 ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO]; + pub const AssetHubWococoToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO; // 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 AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); pub FromAssetHubWococoToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( ParentThen(X1(Parachain(AssetHubWococoParaId::get().into()))).into(), - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, ); pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); } +pub const XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 1]); fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { sp_std::vec![ @@ -99,7 +102,7 @@ pub type ToRococoBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof; /// Dispatches received XCM messages from other bridge -pub type OnBridgeHubWococoBlobDispatcher = BridgeBlobDispatcher< +type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher< XcmRouter, BridgeHubWococoUniversalLocation, BridgeWococoToRococoMessagesPalletInstance, @@ -117,20 +120,19 @@ impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { type MessagesInstance = WithBridgeHubRococoMessagesInstance; type SenderAndLane = FromAssetHubWococoToAssetHubRococoRoute; - type ToSourceChainSender = crate::XcmRouter; + type ToSourceChainSender = XcmRouter; 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; +type OnMessagesDelivered = XcmBlobHaulerAdapter; /// Messaging Bridge configuration for BridgeHubWococo -> BridgeHubRococo pub struct WithBridgeHubRococoMessageBridge; impl MessageBridge for WithBridgeHubRococoMessageBridge { const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME; + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME; type ThisChain = BridgeHubWococo; type BridgedChain = BridgeHubRococo; type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< @@ -171,21 +173,20 @@ impl ThisChainWithMessages for BridgeHubWococo { } /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type BridgeRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< +pub type OnBridgeHubWococoRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain, - RefundableMessagesLane, + RefundableMessagesLane< + WithBridgeHubRococoMessagesInstance, + AssetHubWococoToAssetHubRococoMessagesLane, + >, ActualFeeRefund, PriorityBoostPerMessage, - StrBridgeRefundBridgeHubRococoMessages, + StrOnBridgeHubWococoRefundBridgeHubRococoMessages, >, >; -bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubRococoMessages); - -parameter_types! { - pub const BridgeHubRococoMessagesLane: bp_messages::LaneId = DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO; -} +bp_runtime::generate_static_str_provider!(OnBridgeHubWococoRefundBridgeHubRococoMessages); /// Add XCM messages support for BridgeHubWococo to support Wococo->Rococo XCM messages pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance2; @@ -214,7 +215,7 @@ impl pallet_bridge_messages::Config for Run type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = XcmBlobMessageDispatch< - OnBridgeHubWococoBlobDispatcher, + FromRococoMessageBlobDispatcher, Self::WeightInfo, cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< AssetHubWococoParaId, @@ -293,10 +294,10 @@ mod tests { }, pallet_names: AssertBridgePalletNames { with_this_chain_messages_pallet_name: - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, with_bridged_chain_grandpa_pallet_name: bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME, with_bridged_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, }, }); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs new file mode 100644 index 00000000000..36dcab09dea --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -0,0 +1,322 @@ +// 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 . + +//! Bridge definitions used on BridgeHub with the Rococo flavor for bridging to BridgeHubWestend. + +use crate::{ + bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, + weights, AccountId, BridgeWestendMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, + XcmRouter, +}; +use bp_messages::LaneId; +use bridge_runtime_common::{ + messages, + messages::{ + source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, + target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, + MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, + }, + messages_xcm_extension::{ + SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, + XcmBlobMessageDispatch, + }, + refund_relayer_extension::{ + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, + }, +}; + +use codec::Encode; +use frame_support::{parameter_types, traits::PalletInfoAccess}; +use sp_runtime::RuntimeDebug; +use xcm::{ + latest::prelude::*, + prelude::{InteriorMultiLocation, NetworkId}, +}; +use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; + +parameter_types! { + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + pub const BridgeHubWestendChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID; + pub BridgeRococoToWestendMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub BridgeHubRococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(ParachainInfo::parachain_id().into())); + pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; + pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; + pub const AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; + // 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 AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); + + pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( + ParentThen(X1(Parachain(AssetHubRococoParaId::get().into()))).into(), + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + ); + + pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + + pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); +} +pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); + +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::ToWestendXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested, + } + ) + .encode() + .into(), + } + ] +} + +/// Proof of messages, coming from Westend. +pub type FromWestendBridgeHubMessagesProof = + FromBridgedChainMessagesProof; +/// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages. +pub type ToWestendBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof; + +/// Dispatches received XCM messages from other bridge +type FromWestendMessageBlobDispatcher = BridgeBlobDispatcher< + XcmRouter, + BridgeHubRococoUniversalLocation, + BridgeRococoToWestendMessagesPalletInstance, +>; + +/// Export XCM messages to be relayed to the other side +pub type ToBridgeHubWestendHaulBlobExporter = HaulBlobExporter< + XcmBlobHaulerAdapter, + WestendGlobalConsensusNetwork, + (), +>; +pub struct ToBridgeHubWestendXcmBlobHauler; +impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { + type Runtime = Runtime; + type MessagesInstance = WithBridgeHubWestendMessagesInstance; + type SenderAndLane = FromAssetHubRococoToAssetHubWestendRoute; + + type ToSourceChainSender = XcmRouter; + type CongestedMessage = CongestedMessage; + type UncongestedMessage = UncongestedMessage; +} + +/// On messages delivered callback. +type OnMessagesDeliveredFromWestend = XcmBlobHaulerAdapter; + +/// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWestend +pub struct WithBridgeHubWestendMessageBridge; +impl MessageBridge for WithBridgeHubWestendMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; + type ThisChain = BridgeHubRococo; + type BridgedChain = BridgeHubWestend; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + BridgeParachainWestendInstance, + bp_bridge_hub_westend::BridgeHubWestend, + >; +} + +/// Message verifier for BridgeHubWestend messages sent from BridgeHubRococo +pub type ToBridgeHubWestendMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Maximal outbound payload size of BridgeHubRococo -> BridgeHubWestend messages. +pub type ToBridgeHubWestendMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// BridgeHubWestend chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct BridgeHubWestend; + +impl UnderlyingChainProvider for BridgeHubWestend { + type Chain = bp_bridge_hub_westend::BridgeHubWestend; +} + +impl messages::BridgedChainWithMessages for BridgeHubWestend {} + +/// BridgeHubRococo chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct BridgeHubRococo; + +impl UnderlyingChainProvider for BridgeHubRococo { + type Chain = bp_bridge_hub_rococo::BridgeHubRococo; +} + +impl ThisChainWithMessages for BridgeHubRococo { + type RuntimeOrigin = RuntimeOrigin; +} + +/// Signed extension that refunds relayers that are delivering messages from the Westend parachain. +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< + RefundBridgedParachainMessages< + Runtime, + RefundableParachain< + BridgeParachainWestendInstance, + bp_bridge_hub_westend::BridgeHubWestend, + >, + RefundableMessagesLane< + WithBridgeHubWestendMessagesInstance, + AssetHubRococoToAssetHubWestendMessagesLane, + >, + ActualFeeRefund, + PriorityBoostPerMessage, + StrOnBridgeHubRococoRefundBridgeHubWestendMessages, + >, +>; +bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWestendMessages); + +/// Add XCM messages support for BridgeHubRococo to support Rococo->Westend XCM messages +pub type WithBridgeHubWestendMessagesInstance = pallet_bridge_messages::Instance3; +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_messages_rococo_to_westend::WeightInfo; + type BridgedChainId = BridgeHubWestendChainId; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWestend; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = ToBridgeHubWestendMaximalOutboundPayloadSize; + type OutboundPayload = XcmAsPlainPayload; + + type InboundPayload = XcmAsPlainPayload; + type InboundRelayer = AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = ToBridgeHubWestendMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithBridgeHubWestendMessagesInstance, + DeliveryRewardInBalance, + >; + + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = XcmBlobMessageDispatch< + FromWestendMessageBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + AssetHubRococoParaId, + Runtime, + >, + >; + type OnMessagesDelivered = OnMessagesDeliveredFromWestend; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::bridge_common_config::BridgeGrandpaWestendInstance; + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + 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() { + check_message_lane_weights::< + bp_bridge_hub_rococo::BridgeHubRococo, + Runtime, + WithBridgeHubWestendMessagesInstance, + >( + bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE, + bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + true, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: BridgeGrandpaWestendInstance, + with_bridged_chain_messages_instance: WithBridgeHubWestendMessagesInstance, + bridge: WithBridgeHubWestendMessageBridge, + this_chain: bp_rococo::Rococo, + bridged_chain: bp_westend::Westend, + ); + + assert_complete_bridge_constants::< + Runtime, + BridgeGrandpaWestendInstance, + WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_bridge_hub_rococo::BlockLength::get(), + block_weights: bp_bridge_hub_rococo::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: + bp_westend::WITH_WESTEND_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME, + }, + }); + + bridge_runtime_common::priority_calculator::ensure_priority_boost_is_sane::< + Runtime, + WithBridgeHubWestendMessagesInstance, + PriorityBoostPerMessage, + >(FEE_BOOST_PER_MESSAGE); + + assert_eq!( + BridgeRococoToWestendMessagesPalletInstance::get(), + X1(PalletInstance( + bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX + )) + ); + } +} 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_to_wococo_config.rs similarity index 87% rename from cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs rename to cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_wococo_config.rs index a02d8ad88e7..7780b02632c 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_to_wococo_config.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Bridge definitions used on BridgeHub with the Rococo flavor. +//! Bridge definitions used on BridgeHub with the Rococo flavor for bridging to BridgeHubWococo. use crate::{ bridge_common_config::{BridgeParachainWococoInstance, DeliveryRewardInBalance}, - weights, AccountId, BridgeRococoToWococoMessages, ParachainInfo, Runtime, RuntimeEvent, - RuntimeOrigin, XcmRouter, + weights, AccountId, BridgeWococoMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, + XcmRouter, }; use bp_messages::LaneId; use bridge_runtime_common::{ @@ -54,24 +54,27 @@ parameter_types! { pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubWococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; - pub BridgeRococoToWococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub BridgeRococoToWococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); 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 ActiveOutboundLanesToBridgeHubWococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO]; + pub const AssetHubRococoToAssetHubWococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO; // 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 AssetHubWococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_wococo::ASSET_HUB_WOCOCO_PARACHAIN_ID.into(); pub FromAssetHubRococoToAssetHubWococoRoute: SenderAndLane = SenderAndLane::new( ParentThen(X1(Parachain(AssetHubRococoParaId::get().into()))).into(), - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, ); pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); } +pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO: LaneId = LaneId([0, 0, 0, 1]); fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { sp_std::vec![ @@ -100,7 +103,7 @@ pub type ToWococoBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof; /// Dispatches received XCM messages from other bridge -pub type OnBridgeHubRococoBlobDispatcher = BridgeBlobDispatcher< +type FromWococoMessageBlobDispatcher = BridgeBlobDispatcher< XcmRouter, BridgeHubRococoUniversalLocation, BridgeRococoToWococoMessagesPalletInstance, @@ -118,20 +121,19 @@ impl XcmBlobHauler for ToBridgeHubWococoXcmBlobHauler { type MessagesInstance = WithBridgeHubWococoMessagesInstance; type SenderAndLane = FromAssetHubRococoToAssetHubWococoRoute; - type ToSourceChainSender = crate::XcmRouter; + type ToSourceChainSender = XcmRouter; 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; +type OnMessagesDeliveredFromWococo = XcmBlobHaulerAdapter; /// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWococo pub struct WithBridgeHubWococoMessageBridge; impl MessageBridge for WithBridgeHubWococoMessageBridge { const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME; + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; type ThisChain = BridgeHubRococo; type BridgedChain = BridgeHubWococo; type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< @@ -172,21 +174,20 @@ impl ThisChainWithMessages for BridgeHubRococo { } /// Signed extension that refunds relayers that are delivering messages from the Wococo parachain. -pub type BridgeRefundBridgeHubWococoMessages = RefundSignedExtensionAdapter< +pub type OnBridgeHubRococoRefundBridgeHubWococoMessages = RefundSignedExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain, - RefundableMessagesLane, + RefundableMessagesLane< + WithBridgeHubWococoMessagesInstance, + AssetHubRococoToAssetHubWococoMessagesLane, + >, ActualFeeRefund, PriorityBoostPerMessage, - StrBridgeRefundBridgeHubWococoMessages, + StrOnBridgeHubRococoRefundBridgeHubWococoMessages, >, >; -bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubWococoMessages); - -parameter_types! { - pub const BridgeHubWococoMessagesLane: bp_messages::LaneId = DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO; -} +bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWococoMessages); /// Add XCM messages support for BridgeHubRococo to support Rococo->Wococo XCM messages pub type WithBridgeHubWococoMessagesInstance = pallet_bridge_messages::Instance1; @@ -215,14 +216,14 @@ impl pallet_bridge_messages::Config for Run type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = XcmBlobMessageDispatch< - OnBridgeHubRococoBlobDispatcher, + FromWococoMessageBlobDispatcher, Self::WeightInfo, cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< AssetHubRococoParaId, Runtime, >, >; - type OnMessagesDelivered = OnMessagesDelivered; + type OnMessagesDelivered = OnMessagesDeliveredFromWococo; } #[cfg(test)] @@ -294,10 +295,10 @@ mod tests { }, pallet_names: AssertBridgePalletNames { with_this_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, with_bridged_chain_grandpa_pallet_name: bp_wococo::WITH_WOCOCO_GRANDPA_PALLET_NAME, with_bridged_chain_messages_pallet_name: - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_NAME, + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, }, }); 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 326acc812a2..0743b6e91f9 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 @@ -16,11 +16,15 @@ //! # 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`. +//! This runtime is also used for Bridge Hub Wococo. 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`. +//! +//! This runtime currently supports bridging between: +//! - Rococo <> Wococo +//! - Rococo <> Westend #![cfg_attr(not(feature = "std"), no_std)] // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. @@ -31,8 +35,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod bridge_common_config; -pub mod bridge_hub_rococo_config; -pub mod bridge_hub_wococo_config; +pub mod bridge_to_rococo_config; +pub mod bridge_to_westend_config; +pub mod bridge_to_wococo_config; mod weights; pub mod xcm_config; @@ -67,7 +72,7 @@ use frame_system::{ }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; use bp_runtime::HeaderId; @@ -79,10 +84,6 @@ use xcm::latest::prelude::*; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use crate::{ - bridge_hub_rococo_config::BridgeRefundBridgeHubWococoMessages, - bridge_hub_wococo_config::BridgeRefundBridgeHubRococoMessages, xcm_config::XcmRouter, -}; use parachains_common::{ impls::DealWithFees, rococo::{consensus::*, currency::*, fee::WeightToFee}, @@ -123,7 +124,11 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, - (BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWococoMessages), + ( + bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages, + bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, + bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages, + ), ); /// Unchecked extrinsic type as expected by this runtime. @@ -187,7 +192,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_003_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, @@ -491,19 +496,38 @@ construct_runtime!( Utility: pallet_utility::{Pallet, Call, Event} = 40, Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, - // 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 BridgeHub runtime. + // Rococo, Wococo and Westend BridgeHubs are sharing the runtime, so this runtime has several sets of + // bridge pallets. + // + // BridgeHubRococo uses: + // - BridgeWococoGrandpa + // - BridgeWestendGrandpa + // - BridgeWococoParachains + // - BridgeWestendParachains + // - BridgeWococoMessages + // - BridgeWestendMessages + // - BridgeRelayers + // + // BridgeHubWococo uses: + // - BridgeRococoGrandpa + // - BridgeRococoParachains + // - BridgeRococoMessages + // - BridgeRelayers + + // GRANDPA bridge modules. BridgeWococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 41, - BridgeWococoParachain: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 42, - BridgeRococoToWococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 46, - - // 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, - BridgeWococoToRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 45, + BridgeWestendGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 48, + + // Parachain bridge modules. + BridgeWococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 42, + BridgeRococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 44, + BridgeWestendParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 49, + + // Messaging bridge modules. + BridgeWococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 46, + BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 45, + BridgeWestendMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 51, BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 47, } @@ -512,11 +536,11 @@ construct_runtime!( bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { RuntimeCall, AccountId, // Grandpa - BridgeRococoGrandpa, BridgeWococoGrandpa, + BridgeRococoGrandpa, BridgeWococoGrandpa, BridgeWestendGrandpa, // Parachains - BridgeRococoParachain, BridgeWococoParachain, + BridgeRococoParachains, BridgeWococoParachains, BridgeWestendParachains, // Messages - BridgeWococoToRococoMessages, BridgeRococoToWococoMessages + BridgeRococoMessages, BridgeWococoMessages, BridgeWestendMessages } #[cfg(feature = "runtime-benchmarks")] @@ -539,15 +563,16 @@ mod benches { // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] - // Bridge pallets at Rococo + // Bridge pallets [pallet_bridge_grandpa, WococoFinality] - [pallet_bridge_parachains, WithinWococo] - [pallet_bridge_messages, RococoToWococo] - // Bridge pallets at Wococo + [pallet_bridge_grandpa, WestendFinality] [pallet_bridge_grandpa, RococoFinality] + [pallet_bridge_parachains, WithinWococo] + [pallet_bridge_parachains, WithinWestend] [pallet_bridge_parachains, WithinRococo] + [pallet_bridge_messages, RococoToWococo] + [pallet_bridge_messages, RococoToWestend] [pallet_bridge_messages, WococoToRococo] - // Bridge relayer pallets [pallet_bridge_relayers, BridgeRelayersBench::] ); } @@ -716,10 +741,19 @@ impl_runtime_apis! { } } + impl bp_westend::WestendFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeWestendGrandpa::best_finalized() + } + fn synced_headers_grandpa_info( + ) -> Vec> { + BridgeWestendGrandpa::synced_headers_grandpa_info() + } + } impl bp_bridge_hub_rococo::BridgeHubRococoFinalityApi for Runtime { fn best_finalized() -> Option> { - BridgeRococoParachain::best_parachain_head_id::< + BridgeRococoParachains::best_parachain_head_id::< bp_bridge_hub_rococo::BridgeHubRococo >().unwrap_or(None) } @@ -727,12 +761,20 @@ impl_runtime_apis! { impl bp_bridge_hub_wococo::BridgeHubWococoFinalityApi for Runtime { fn best_finalized() -> Option> { - BridgeWococoParachain::best_parachain_head_id::< + BridgeWococoParachains::best_parachain_head_id::< bp_bridge_hub_wococo::BridgeHubWococo >().unwrap_or(None) } } + impl bp_bridge_hub_westend::BridgeHubWestendFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeWestendParachains::best_parachain_head_id::< + bp_bridge_hub_westend::BridgeHubWestend + >().unwrap_or(None) + } + } + // This is exposed by BridgeHubRococo impl bp_bridge_hub_wococo::FromBridgeHubWococoInboundLaneApi for Runtime { fn message_details( @@ -741,7 +783,7 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< Runtime, - bridge_hub_rococo_config::WithBridgeHubWococoMessagesInstance, + bridge_to_wococo_config::WithBridgeHubWococoMessagesInstance, >(lane, messages) } } @@ -755,26 +797,26 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, - bridge_hub_rococo_config::WithBridgeHubWococoMessagesInstance, + bridge_to_wococo_config::WithBridgeHubWococoMessagesInstance, >(lane, begin, end) } } - // This is exposed by BridgeHubWococo - impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { + // This is exposed by BridgeHubRococo + impl bp_bridge_hub_westend::FromBridgeHubWestendInboundLaneApi for Runtime { fn message_details( lane: bp_messages::LaneId, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< Runtime, - bridge_hub_wococo_config::WithBridgeHubRococoMessagesInstance, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, >(lane, messages) } } - // This is exposed by BridgeHubWococo - impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { + // This is exposed by BridgeHubRococo + impl bp_bridge_hub_westend::ToBridgeHubWestendOutboundLaneApi for Runtime { fn message_details( lane: bp_messages::LaneId, begin: bp_messages::MessageNonce, @@ -782,11 +824,50 @@ impl_runtime_apis! { ) -> Vec { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, - bridge_hub_wococo_config::WithBridgeHubRococoMessagesInstance, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, >(lane, begin, end) } } + // This is exposed by BridgeHubWococo + impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + // use different instance according to flavor + match xcm_config::Flavor::get() { + RuntimeFlavor::Wococo => { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >(lane, messages) + }, + flavor @ _ => unimplemented!("Unsupported `FromBridgeHubRococoInboundLaneApi` for flavor: {:?}", flavor) + } + } + } + + // This is exposed by BridgeHubWococo and BridgeHubWestend + impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + begin: bp_messages::MessageNonce, + end: bp_messages::MessageNonce, + ) -> Vec { + // use different instance according to flavor + match xcm_config::Flavor::get() { + RuntimeFlavor::Wococo => { + bridge_runtime_common::messages_api::outbound_message_details::< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >(lane, begin, end) + }, + flavor @ _ => unimplemented!("Unsupported `ToBridgeHubRococoOutboundLaneApi` for flavor: {:?}", flavor) + } + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -826,11 +907,14 @@ impl_runtime_apis! { use pallet_bridge_relayers::benchmarking::Pallet as BridgeRelayersBench; // Change weight file names. type WococoFinality = BridgeWococoGrandpa; + type WestendFinality = BridgeWestendGrandpa; type RococoFinality = BridgeRococoGrandpa; type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; - type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; - type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; + type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; + type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -966,11 +1050,14 @@ impl_runtime_apis! { type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; type WococoFinality = BridgeWococoGrandpa; + type WestendFinality = BridgeWestendGrandpa; type RococoFinality = BridgeRococoGrandpa; type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; - type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; - type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; + type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; + type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_parachain, @@ -983,9 +1070,9 @@ impl_runtime_apis! { MessageProofParams, }; - impl BridgeMessagesConfig for Runtime { + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); + let bench_lane_id = >::bench_lane_id(); let bridged_chain_id = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, @@ -999,24 +1086,67 @@ impl_runtime_apis! { fn prepare_message_proof( params: MessageProofParams, - ) -> (bridge_hub_rococo_config::FromWococoBridgeHubMessagesProof, Weight) { + ) -> (bridge_to_wococo_config::FromWococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWococoInstance, - bridge_hub_rococo_config::WithBridgeHubWococoMessageBridge, + bridge_to_wococo_config::WithBridgeHubWococoMessageBridge, >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Rococo), Parachain(42)))) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, - ) -> bridge_hub_rococo_config::ToWococoBridgeHubMessagesDeliveryProof { + ) -> bridge_to_wococo_config::ToWococoBridgeHubMessagesDeliveryProof { prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWococoInstance, - bridge_hub_rococo_config::WithBridgeHubWococoMessageBridge, + bridge_to_wococo_config::WithBridgeHubWococoMessageBridge, + >(params) + } + + fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool { + use cumulus_primitives_core::XcmpMessageSource; + !XcmpQueue::take_outbound_messages(usize::MAX).is_empty() + } + } + + impl BridgeMessagesConfig for Runtime { + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { + let bench_lane_id = >::bench_lane_id(); + let bridged_chain_id = bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID; + pallet_bridge_relayers::Pallet::::relayer_reward( + relayer, + bp_relayers::RewardsAccountParams::new( + bench_lane_id, + bridged_chain_id, + bp_relayers::RewardsAccountOwner::BridgedChain + ) + ).is_some() + } + + fn prepare_message_proof( + params: MessageProofParams, + ) -> (bridge_to_westend_config::FromWestendBridgeHubMessagesProof, Weight) { + use cumulus_primitives_core::XcmpMessageSource; + assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + prepare_message_proof_from_parachain::< + Runtime, + bridge_common_config::BridgeGrandpaWestendInstance, + bridge_to_westend_config::WithBridgeHubWestendMessageBridge, + >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Rococo), Parachain(42)))) + } + + fn prepare_message_delivery_proof( + params: MessageDeliveryProofParams, + ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { + prepare_message_delivery_proof_from_parachain::< + Runtime, + bridge_common_config::BridgeGrandpaWestendInstance, + bridge_to_westend_config::WithBridgeHubWestendMessageBridge, >(params) } @@ -1026,9 +1156,9 @@ impl_runtime_apis! { } } - impl BridgeMessagesConfig for Runtime { + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); + let bench_lane_id = >::bench_lane_id(); let bridged_chain_id = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, @@ -1042,24 +1172,24 @@ impl_runtime_apis! { fn prepare_message_proof( params: MessageProofParams, - ) -> (bridge_hub_wococo_config::FromRococoBridgeHubMessagesProof, Weight) { + ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaRococoInstance, - bridge_hub_wococo_config::WithBridgeHubRococoMessageBridge, + bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Wococo), Parachain(42)))) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, - ) -> bridge_hub_wococo_config::ToRococoBridgeHubMessagesDeliveryProof { + ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaRococoInstance, - bridge_hub_wococo_config::WithBridgeHubRococoMessageBridge, + bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, >(params) } @@ -1100,6 +1230,30 @@ impl_runtime_apis! { } } + impl BridgeParachainsConfig for Runtime { + fn parachains() -> Vec { + use bp_runtime::Parachain; + vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_westend::BridgeHubWestend::PARACHAIN_ID)] + } + + fn prepare_parachain_heads_proof( + parachains: &[bp_polkadot_core::parachains::ParaId], + parachain_head_size: u32, + proof_size: bp_runtime::StorageProofSize, + ) -> ( + pallet_bridge_parachains::RelayBlockNumber, + pallet_bridge_parachains::RelayBlockHash, + bp_polkadot_core::parachains::ParaHeadsProof, + Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, + ) { + prepare_parachain_heads_proof::( + parachains, + parachain_head_size, + proof_size, + ) + } + } + impl BridgeParachainsConfig for Runtime { fn parachains() -> Vec { use bp_runtime::Parachain; @@ -1205,11 +1359,13 @@ mod tests { pallet_transaction_payment::ChargeTransactionPayment::from(10), BridgeRejectObsoleteHeadersAndMessages, ( - BridgeRefundBridgeHubRococoMessages::default(), - BridgeRefundBridgeHubWococoMessages::default(), + bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages::default(), + bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), + bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages::default(), ), ); + // for BridgeHubRococo { let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( VERSION.spec_version, @@ -1227,8 +1383,9 @@ mod tests { ) } + // for BridgeHubWococo { - let bhw_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( + let bhw_indirect_payload = bp_bridge_hub_wococo::SignedExtension::from_params( VERSION.spec_version, VERSION.transaction_version, bp_runtime::TransactionEra::Immortal, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index c41900097a1..a657b588c02 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -23,10 +23,13 @@ pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_balances; pub mod pallet_bridge_grandpa_rococo_finality; +pub mod pallet_bridge_grandpa_westend_finality; pub mod pallet_bridge_grandpa_wococo_finality; +pub mod pallet_bridge_messages_rococo_to_westend; pub mod pallet_bridge_messages_rococo_to_wococo; pub mod pallet_bridge_messages_wococo_to_rococo; pub mod pallet_bridge_parachains_within_rococo; +pub mod pallet_bridge_parachains_within_westend; pub mod pallet_bridge_parachains_within_wococo; pub mod pallet_bridge_relayers; pub mod pallet_collator_selection; @@ -84,6 +87,23 @@ impl pallet_bridge_messages::WeightInfoExt } } +impl pallet_bridge_messages::WeightInfoExt + for pallet_bridge_messages_rococo_to_westend::WeightInfo +{ + fn expected_extra_storage_proof_size() -> u32 { + bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE + } + + fn receive_messages_proof_overhead_from_runtime() -> Weight { + pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( + ) + } + + fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { + pallet_bridge_relayers::WeightInfo::::receive_messages_delivery_proof_overhead_from_runtime() + } +} + impl pallet_bridge_parachains::WeightInfoExt for pallet_bridge_parachains_within_rococo::WeightInfo { @@ -92,6 +112,14 @@ impl pallet_bridge_parachains::WeightInfoExt } } +impl pallet_bridge_parachains::WeightInfoExt + for pallet_bridge_parachains_within_westend::WeightInfo +{ + fn expected_extra_storage_proof_size() -> u32 { + bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE + } +} + impl pallet_bridge_parachains::WeightInfoExt for pallet_bridge_parachains_within_wococo::WeightInfo { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs deleted file mode 100644 index 5fbe2da8eaa..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_grandpa` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./artifacts/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_grandpa -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_bridge_grandpa`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_grandpa::WeightInfo for WeightInfo { - /// Storage: BridgeRococoGrandpa PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa BestFinalized (r:1 w:1) - /// Proof: BridgeRococoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa CurrentAuthoritySet (r:1 w:0) - /// Proof: BridgeRococoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(50250), added: 50745, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHashesPointer (r:1 w:1) - /// Proof: BridgeRococoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHashes (r:1 w:1) - /// Proof: BridgeRococoGrandpa ImportedHashes (max_values: Some(1024), max_size: Some(36), added: 1521, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHeaders (r:0 w:2) - /// Proof: BridgeRococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - fn submit_finality_proof(p: u32, v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `231 + p * (60 ±0)` - // Estimated: `51735` - // Minimum execution time: 241_332_000 picoseconds. - Weight::from_parts(69_790_821, 0) - .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 6_013 - .saturating_add(Weight::from_parts(47_580_554, 0).saturating_mul(p.into())) - // Standard Error: 100_298 - .saturating_add(Weight::from_parts(1_213_475, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs index e6d7cf53dc9..b0634ff2ccf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,17 +64,19 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (60 ±0)` + // Measured: `268 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 292_425_000 picoseconds. - Weight::from_parts(294_025_000, 0) + // Minimum execution time: 304_726_000 picoseconds. + Weight::from_parts(16_868_060, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 3_450 - .saturating_add(Weight::from_parts(55_743_036, 0).saturating_mul(p.into())) - // Standard Error: 26_622 - .saturating_add(Weight::from_parts(327_706, 0).saturating_mul(v.into())) + // Standard Error: 2_802 + .saturating_add(Weight::from_parts(55_200_017, 0).saturating_mul(p.into())) + // Standard Error: 46_745 + .saturating_add(Weight::from_parts(2_689_151, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs new file mode 100644 index 00000000000..4ed140b7d17 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs @@ -0,0 +1,83 @@ +// 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_bridge_grandpa` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_grandpa +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_grandpa`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_grandpa::WeightInfo for WeightInfo { + /// Storage: `BridgeWestendGrandpa::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::BestFinalized` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::CurrentAuthoritySet` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHashesPointer` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHashes` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:0 w:2) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + fn submit_finality_proof(p: u32, v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `335 + p * (60 ±0)` + // Estimated: `51735` + // Minimum execution time: 305_905_000 picoseconds. + Weight::from_parts(2_636_863, 0) + .saturating_add(Weight::from_parts(0, 51735)) + // Standard Error: 2_724 + .saturating_add(Weight::from_parts(55_199_477, 0).saturating_mul(p.into())) + // Standard Error: 45_444 + .saturating_add(Weight::from_parts(2_835_596, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs index 7769112027b..05474ed224d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,17 +64,19 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { // Proof Size summary in bytes: - // Measured: `268 + p * (60 ±0)` + // Measured: `302 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 294_211_000 picoseconds. - Weight::from_parts(43_087_768, 0) + // Minimum execution time: 305_146_000 picoseconds. + Weight::from_parts(308_711_000, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 5_610 - .saturating_add(Weight::from_parts(55_863_061, 0).saturating_mul(p.into())) - // Standard Error: 93_579 - .saturating_add(Weight::from_parts(2_409_156, 0).saturating_mul(v.into())) + // Standard Error: 2_651 + .saturating_add(Weight::from_parts(55_082_480, 0).saturating_mul(p.into())) + // Standard Error: 20_462 + .saturating_add(Weight::from_parts(298_367, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs deleted file mode 100644 index ec40615dc13..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_messages` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./artifacts/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_messages -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_bridge_messages`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn receive_single_message_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `52645` - // Minimum execution time: 43_187_000 picoseconds. - Weight::from_parts(43_681_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn receive_two_messages_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `52645` - // Minimum execution time: 54_131_000 picoseconds. - Weight::from_parts(54_813_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `52645` - // Minimum execution time: 48_120_000 picoseconds. - Weight::from_parts(48_733_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `335` - // Estimated: `52645` - // Minimum execution time: 41_028_000 picoseconds. - Weight::from_parts(41_635_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_16_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `335` - // Estimated: `52645` - // Minimum execution time: 68_499_000 picoseconds. - Weight::from_parts(69_263_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn receive_delivery_proof_for_single_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 32_277_000 picoseconds. - Weight::from_parts(32_880_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 32_504_000 picoseconds. - Weight::from_parts(33_085_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `6086` - // Minimum execution time: 34_963_000 picoseconds. - Weight::from_parts(35_473_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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 Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem RelevantMessagingState (r:1 w:0) - /// Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) - /// Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) - /// Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `635` - // Estimated: `52645` - // Minimum execution time: 129_978_000 picoseconds. - Weight::from_parts(98_246_356, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 2_554 - .saturating_add(Weight::from_parts(544_728, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs new file mode 100644 index 00000000000..6513b63474a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -0,0 +1,245 @@ +// 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_bridge_messages` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_messages +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_messages`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_messages::WeightInfo for WeightInfo { + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_single_message_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `643` + // Estimated: `52645` + // Minimum execution time: 41_873_000 picoseconds. + Weight::from_parts(43_434_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_two_messages_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `643` + // Estimated: `52645` + // Minimum execution time: 53_328_000 picoseconds. + Weight::from_parts(54_592_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + // Proof Size summary in bytes: + // Measured: `643` + // Estimated: `52645` + // Minimum execution time: 47_486_000 picoseconds. + Weight::from_parts(48_721_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + fn receive_single_message_proof_1_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `52645` + // Minimum execution time: 41_093_000 picoseconds. + Weight::from_parts(42_050_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + fn receive_single_message_proof_16_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `52645` + // Minimum execution time: 71_947_000 picoseconds. + Weight::from_parts(74_564_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_single_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `482` + // Estimated: `3947` + // Minimum execution time: 31_235_000 picoseconds. + Weight::from_parts(32_051_000, 0) + .saturating_add(Weight::from_parts(0, 3947)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + // Proof Size summary in bytes: + // Measured: `482` + // Estimated: `3947` + // Minimum execution time: 31_320_000 picoseconds. + Weight::from_parts(31_973_000, 0) + .saturating_add(Weight::from_parts(0, 3947)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + // Proof Size summary in bytes: + // Measured: `482` + // Estimated: `6086` + // Minimum execution time: 33_656_000 picoseconds. + Weight::from_parts(34_779_000, 0) + .saturating_add(Weight::from_parts(0, 6086)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `772` + // Estimated: `52645` + // Minimum execution time: 61_671_000 picoseconds. + Weight::from_parts(62_656_321, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 25 + .saturating_add(Weight::from_parts(6_641, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs index 83e9596fb3f..f4f5e85f562 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -48,170 +48,170 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_messages`. pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `609` // Estimated: `52645` - // Minimum execution time: 42_043_000 picoseconds. - Weight::from_parts(43_557_000, 0) + // Minimum execution time: 42_407_000 picoseconds. + Weight::from_parts(43_917_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `609` // Estimated: `52645` - // Minimum execution time: 53_080_000 picoseconds. - Weight::from_parts(55_107_000, 0) + // Minimum execution time: 53_258_000 picoseconds. + Weight::from_parts(55_144_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `609` // Estimated: `52645` - // Minimum execution time: 47_757_000 picoseconds. - Weight::from_parts(49_024_000, 0) + // Minimum execution time: 47_950_000 picoseconds. + Weight::from_parts(49_315_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `472` + // Measured: `577` // Estimated: `52645` - // Minimum execution time: 41_434_000 picoseconds. - Weight::from_parts(42_468_000, 0) + // Minimum execution time: 41_383_000 picoseconds. + Weight::from_parts(42_898_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `472` + // Measured: `577` // Estimated: `52645` - // Minimum execution time: 76_285_000 picoseconds. - Weight::from_parts(77_717_000, 0) + // Minimum execution time: 72_118_000 picoseconds. + Weight::from_parts(74_643_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `376` - // Estimated: `3841` - // Minimum execution time: 31_296_000 picoseconds. - Weight::from_parts(32_147_000, 0) - .saturating_add(Weight::from_parts(0, 3841)) + // Measured: `448` + // Estimated: `3913` + // Minimum execution time: 30_993_000 picoseconds. + Weight::from_parts(31_793_000, 0) + .saturating_add(Weight::from_parts(0, 3913)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `376` - // Estimated: `3841` - // Minimum execution time: 31_114_000 picoseconds. - Weight::from_parts(31_937_000, 0) - .saturating_add(Weight::from_parts(0, 3841)) + // Measured: `448` + // Estimated: `3913` + // Minimum execution time: 30_894_000 picoseconds. + Weight::from_parts(31_925_000, 0) + .saturating_add(Weight::from_parts(0, 3913)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `376` + // Measured: `448` // Estimated: `6086` - // Minimum execution time: 33_620_000 picoseconds. - Weight::from_parts(34_604_000, 0) + // Minimum execution time: 33_804_000 picoseconds. + Weight::from_parts(34_560_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -228,15 +228,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[128, 2048]`. /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `672` + // Measured: `811` // Estimated: `52645` - // Minimum execution time: 63_809_000 picoseconds. - Weight::from_parts(65_441_614, 0) + // Minimum execution time: 62_616_000 picoseconds. + Weight::from_parts(64_073_891, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 61 - .saturating_add(Weight::from_parts(6_729, 0).saturating_mul(i.into())) + // Standard Error: 43 + .saturating_add(Weight::from_parts(6_525, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs index 12015b962fe..596b8dd3cc6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -48,170 +48,170 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_messages`. pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `467` + // Measured: `537` // Estimated: `52645` - // Minimum execution time: 41_613_000 picoseconds. - Weight::from_parts(42_942_000, 0) + // Minimum execution time: 42_086_000 picoseconds. + Weight::from_parts(42_833_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `467` + // Measured: `537` // Estimated: `52645` - // Minimum execution time: 52_657_000 picoseconds. - Weight::from_parts(54_020_000, 0) + // Minimum execution time: 51_927_000 picoseconds. + Weight::from_parts(53_847_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `467` + // Measured: `537` // Estimated: `52645` - // Minimum execution time: 47_484_000 picoseconds. - Weight::from_parts(48_318_000, 0) + // Minimum execution time: 47_218_000 picoseconds. + Weight::from_parts(48_380_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `505` // Estimated: `52645` - // Minimum execution time: 40_860_000 picoseconds. - Weight::from_parts(41_720_000, 0) + // Minimum execution time: 40_585_000 picoseconds. + Weight::from_parts(41_714_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `505` // Estimated: `52645` - // Minimum execution time: 75_743_000 picoseconds. - Weight::from_parts(76_862_000, 0) + // Minimum execution time: 71_197_000 picoseconds. + Weight::from_parts(73_983_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 30_195_000 picoseconds. - Weight::from_parts(31_047_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) + // Measured: `376` + // Estimated: `3841` + // Minimum execution time: 30_823_000 picoseconds. + Weight::from_parts(31_501_000, 0) + .saturating_add(Weight::from_parts(0, 3841)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 30_410_000 picoseconds. - Weight::from_parts(31_057_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) + // Measured: `376` + // Estimated: `3841` + // Minimum execution time: 30_854_000 picoseconds. + Weight::from_parts(31_663_000, 0) + .saturating_add(Weight::from_parts(0, 3841)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `339` + // Measured: `376` // Estimated: `6086` - // Minimum execution time: 33_096_000 picoseconds. - Weight::from_parts(33_710_000, 0) + // Minimum execution time: 33_463_000 picoseconds. + Weight::from_parts(34_290_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -228,15 +228,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[128, 2048]`. /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `635` + // Measured: `739` // Estimated: `52645` - // Minimum execution time: 63_158_000 picoseconds. - Weight::from_parts(63_769_302, 0) + // Minimum execution time: 61_523_000 picoseconds. + Weight::from_parts(62_686_055, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 35 - .saturating_add(Weight::from_parts(6_896, 0).saturating_mul(i.into())) + // Standard Error: 26 + .saturating_add(Weight::from_parts(6_563, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs deleted file mode 100644 index c9f1d7e05d3..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_parachains` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./artifacts/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_parachains -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_bridge_parachains`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 34_759_000 picoseconds. - Weight::from_parts(35_709_034, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - fn submit_parachain_heads_with_1kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 36_005_000 picoseconds. - Weight::from_parts(36_492_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - fn submit_parachain_heads_with_16kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 62_374_000 picoseconds. - Weight::from_parts(62_977_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs index 1a125f4cd0e..81cb0a66b7d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -60,12 +60,13 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `294` + // Measured: `367` // Estimated: `2543` - // Minimum execution time: 31_409_000 picoseconds. - Weight::from_parts(32_561_631, 0) + // Minimum execution time: 31_241_000 picoseconds. + Weight::from_parts(32_488_584, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -82,10 +83,10 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `294` + // Measured: `367` // Estimated: `2543` - // Minimum execution time: 32_828_000 picoseconds. - Weight::from_parts(33_681_000, 0) + // Minimum execution time: 32_962_000 picoseconds. + Weight::from_parts(33_658_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -102,10 +103,10 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `294` + // Measured: `367` // Estimated: `2543` - // Minimum execution time: 65_531_000 picoseconds. - Weight::from_parts(66_418_000, 0) + // Minimum execution time: 62_685_000 picoseconds. + Weight::from_parts(64_589_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs new file mode 100644 index 00000000000..bfe93b4c36a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs @@ -0,0 +1,116 @@ +// 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_bridge_parachains` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_parachains +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_parachains`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_parachains::WeightInfo for WeightInfo { + /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. + fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `468` + // Estimated: `2543` + // Minimum execution time: 31_493_000 picoseconds. + Weight::from_parts(32_511_270, 0) + .saturating_add(Weight::from_parts(0, 2543)) + // Standard Error: 33_650 + .saturating_add(Weight::from_parts(20_764, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + fn submit_parachain_heads_with_1kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `468` + // Estimated: `2543` + // Minimum execution time: 32_976_000 picoseconds. + Weight::from_parts(33_647_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + fn submit_parachain_heads_with_16kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `468` + // Estimated: `2543` + // Minimum execution time: 62_898_000 picoseconds. + Weight::from_parts(64_463_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs index 02c350a0408..416e16c78c4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -60,13 +60,16 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + /// The range of component `p` is `[1, 2]`. + fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `435` // Estimated: `2543` - // Minimum execution time: 32_627_000 picoseconds. - Weight::from_parts(33_806_957, 0) + // Minimum execution time: 31_573_000 picoseconds. + Weight::from_parts(32_739_400, 0) .saturating_add(Weight::from_parts(0, 2543)) + // Standard Error: 49_518 + .saturating_add(Weight::from_parts(5_166, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -82,10 +85,10 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `435` // Estimated: `2543` - // Minimum execution time: 34_360_000 picoseconds. - Weight::from_parts(35_212_000, 0) + // Minimum execution time: 32_780_000 picoseconds. + Weight::from_parts(33_797_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -102,10 +105,10 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `435` // Estimated: `2543` - // Minimum execution time: 66_678_000 picoseconds. - Weight::from_parts(67_571_000, 0) + // Minimum execution time: 62_847_000 picoseconds. + Weight::from_parts(63_991_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index 0ae6e5eff2a..fde670ab927 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-t2sp1qqs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-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: @@ -56,8 +56,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `207` // Estimated: `3593` - // Minimum execution time: 46_239_000 picoseconds. - Weight::from_parts(47_442_000, 0) + // Minimum execution time: 45_338_000 picoseconds. + Weight::from_parts(45_836_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -72,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `61` // Estimated: `4714` - // Minimum execution time: 23_977_000 picoseconds. - Weight::from_parts(24_837_000, 0) + // Minimum execution time: 23_561_000 picoseconds. + Weight::from_parts(24_012_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `160` // Estimated: `4714` - // Minimum execution time: 25_798_000 picoseconds. - Weight::from_parts(26_495_000, 0) + // Minimum execution time: 25_133_000 picoseconds. + Weight::from_parts(25_728_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -102,8 +102,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `263` // Estimated: `4714` - // Minimum execution time: 27_382_000 picoseconds. - Weight::from_parts(27_936_000, 0) + // Minimum execution time: 27_356_000 picoseconds. + Weight::from_parts(27_828_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -114,8 +114,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `6` // Estimated: `3538` - // Minimum execution time: 2_944_000 picoseconds. - Weight::from_parts(3_093_000, 0) + // Minimum execution time: 2_955_000 picoseconds. + Weight::from_parts(3_084_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/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 cd1a673cb53..295abd481d7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 23_601_000 picoseconds. - Weight::from_parts(24_226_000, 3593) + // Minimum execution time: 19_037_000 picoseconds. + Weight::from_parts(19_602_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,15 +65,19 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 51_043_000 picoseconds. - Weight::from_parts(52_326_000, 6196) + // Minimum execution time: 43_115_000 picoseconds. + Weight::from_parts(43_897_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: `System::Account` (r:2 w:2) + // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -86,12 +90,12 @@ 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: `260` - // Estimated: `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)) + // Measured: `294` + // Estimated: `8799` + // Minimum execution time: 90_267_000 picoseconds. + Weight::from_parts(91_460_000, 8799) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(5)) } // Storage: `Benchmark::Override` (r:0 w:0) // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -102,33 +106,39 @@ impl WeightInfo { // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. Weight::from_parts(18_446_744_073_709_551_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `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)) + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 60_477_000 picoseconds. + Weight::from_parts(61_314_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_603_000 picoseconds. - Weight::from_parts(3_721_000, 0) + // Minimum execution time: 2_996_000 picoseconds. + Weight::from_parts(3_107_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,15 +146,19 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 24_265_000 picoseconds. - Weight::from_parts(25_004_000, 3593) + // Minimum execution time: 18_907_000 picoseconds. + Weight::from_parts(19_475_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:1 w:1) + // Storage: `System::Account` (r:2 w:2) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -157,32 +171,38 @@ 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: `159` - // Estimated: `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)) + // Measured: `193` + // Estimated: `6196` + // Minimum execution time: 59_143_000 picoseconds. + Weight::from_parts(60_316_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `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)) + // Measured: `141` + // Estimated: `3606` + // Minimum execution time: 44_459_000 picoseconds. + Weight::from_parts(45_365_000, 3606) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index da3404909f3..7c686190208 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,28 +17,26 @@ //! 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: `[]` +//! DATE: 2023-10-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("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-vmdtonbz-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::generic -// --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_generic.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::generic +// --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)] @@ -50,122 +48,134 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `3572` - // Minimum execution time: 37_350_000 picoseconds. - Weight::from_parts(38_105_000, 3572) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 62_732_000 picoseconds. + Weight::from_parts(64_581_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_042_000 picoseconds. - Weight::from_parts(3_117_000, 0) + // Minimum execution time: 1_987_000 picoseconds. + Weight::from_parts(2_107_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: `69` - // Estimated: `3534` - // Minimum execution time: 11_037_000 picoseconds. - Weight::from_parts(11_465_000, 3534) + // Measured: `103` + // Estimated: `3568` + // Minimum execution time: 8_098_000 picoseconds. + Weight::from_parts(8_564_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: 12_359_000 picoseconds. - Weight::from_parts(12_741_000, 0) + // Minimum execution time: 8_539_000 picoseconds. + Weight::from_parts(9_085_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_165_000 picoseconds. - Weight::from_parts(3_295_000, 0) + // Minimum execution time: 2_205_000 picoseconds. + Weight::from_parts(2_369_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_847_000 picoseconds. - Weight::from_parts(2_893_000, 0) + // Minimum execution time: 1_828_000 picoseconds. + Weight::from_parts(1_994_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_847_000 picoseconds. - Weight::from_parts(2_936_000, 0) + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(1_946_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_856_000 picoseconds. - Weight::from_parts(2_933_000, 0) + // Minimum execution time: 1_842_000 picoseconds. + Weight::from_parts(1_949_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_635_000 picoseconds. - Weight::from_parts(3_710_000, 0) + // Minimum execution time: 2_460_000 picoseconds. + Weight::from_parts(2_593_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_822_000 picoseconds. - Weight::from_parts(2_899_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(2_003_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `3572` - // Minimum execution time: 29_399_000 picoseconds. - Weight::from_parts(30_284_000, 3572) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 56_813_000 picoseconds. + Weight::from_parts(57_728_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } // 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: `126` - // Estimated: `3591` - // Minimum execution time: 16_173_000 picoseconds. - Weight::from_parts(16_576_000, 3591) + // Measured: `160` + // Estimated: `3625` + // Minimum execution time: 11_364_000 picoseconds. + Weight::from_parts(11_872_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -173,11 +183,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_882_000 picoseconds. - Weight::from_parts(3_017_000, 0) + // Minimum execution time: 1_821_000 picoseconds. + Weight::from_parts(1_936_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -190,11 +202,11 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 29_839_000 picoseconds. - Weight::from_parts(30_519_000, 3540) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 23_081_000 picoseconds. + Weight::from_parts(23_512_000, 3574) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) @@ -203,147 +215,163 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_806_000 picoseconds. - Weight::from_parts(5_042_000, 0) + // Minimum execution time: 3_747_000 picoseconds. + Weight::from_parts(4_068_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_407_000 picoseconds. - Weight::from_parts(4_548_000, 0) + // Minimum execution time: 3_045_000 picoseconds. + Weight::from_parts(3_208_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_930_000 picoseconds. - Weight::from_parts(3_042_000, 0) + // Minimum execution time: 1_962_000 picoseconds. + Weight::from_parts(2_284_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_915_000 picoseconds. - Weight::from_parts(3_052_000, 0) + // Minimum execution time: 1_951_000 picoseconds. + Weight::from_parts(2_026_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_823_000 picoseconds. - Weight::from_parts(2_912_000, 0) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(2_084_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_119_000 picoseconds. - Weight::from_parts(3_205_000, 0) + // Minimum execution time: 2_042_000 picoseconds. + Weight::from_parts(2_145_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `3572` - // Minimum execution time: 33_394_000 picoseconds. - Weight::from_parts(34_497_000, 3572) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 61_350_000 picoseconds. + Weight::from_parts(62_440_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_471_000 picoseconds. - Weight::from_parts(5_640_000, 0) + // Minimum execution time: 4_993_000 picoseconds. + Weight::from_parts(5_309_000, 0) } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `3572` - // Minimum execution time: 29_932_000 picoseconds. - Weight::from_parts(30_478_000, 3572) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 57_133_000 picoseconds. + Weight::from_parts(58_100_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_807_000 picoseconds. - Weight::from_parts(2_941_000, 0) + // Minimum execution time: 1_899_000 picoseconds. + Weight::from_parts(2_153_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_785_000 picoseconds. - Weight::from_parts(2_894_000, 0) + // Minimum execution time: 1_880_000 picoseconds. + Weight::from_parts(1_960_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_844_000 picoseconds. - Weight::from_parts(2_943_000, 0) + // Minimum execution time: 1_825_000 picoseconds. + Weight::from_parts(1_960_000, 0) } + // 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: `BridgeWococoMessages::PalletOperatingMode` (r:1 w:0) - // Proof: `BridgeWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - // Storage: `BridgeWococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeWococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + // Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) + // Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) + // Proof: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundMessages` (r:0 w:1) + // Proof: `BridgeRococoToWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `1529` - // Minimum execution time: 28_427_000 picoseconds. - Weight::from_parts(28_755_860, 1529) - // Standard Error: 383 - .saturating_add(Weight::from_parts(393_744, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `139` + // Estimated: `3604` + // Minimum execution time: 28_419_000 picoseconds. + Weight::from_parts(29_387_791, 3604) + // Standard Error: 552 + .saturating_add(Weight::from_parts(316_277, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_781_000 picoseconds. - Weight::from_parts(2_907_000, 0) + // Minimum execution time: 1_903_000 picoseconds. + Weight::from_parts(2_023_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_001_000 picoseconds. - Weight::from_parts(3_117_000, 0) + // Minimum execution time: 1_963_000 picoseconds. + Weight::from_parts(2_143_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index dc6f61d0146..87ae9a8e0fa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -19,19 +19,9 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; -use crate::{ - bridge_common_config::{ - BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, - RequiredStakeForStakeAndSlash, - }, - bridge_hub_rococo_config::{ - AssetHubRococoParaId, BridgeHubWococoChainId, BridgeHubWococoMessagesLane, - ToBridgeHubWococoHaulBlobExporter, WococoGlobalConsensusNetwork, - }, - bridge_hub_wococo_config::{ - AssetHubWococoParaId, BridgeHubRococoChainId, BridgeHubRococoMessagesLane, - RococoGlobalConsensusNetwork, ToBridgeHubRococoHaulBlobExporter, - }, +use crate::bridge_common_config::{ + BridgeGrandpaRococoInstance, BridgeGrandpaWestendInstance, BridgeGrandpaWococoInstance, + DeliveryRewardInBalance, RequiredStakeForStakeAndSlash, }; use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; @@ -65,7 +55,7 @@ use xcm_builder::{ XcmFeeToAccount, }; use xcm_executor::{ - traits::{ExportXcm, FeeReason, TransactAsset, WithOriginFilter}, + traits::{FeeReason, TransactAsset, WithOriginFilter}, XcmExecutor, }; @@ -213,6 +203,10 @@ impl Contains for SafeCallFilter { Runtime, BridgeGrandpaRococoInstance, >::initialize { .. }) | + RuntimeCall::BridgeWestendGrandpa(pallet_bridge_grandpa::Call::< + Runtime, + BridgeGrandpaWestendInstance, + >::initialize { .. }) | RuntimeCall::BridgeWococoGrandpa(pallet_bridge_grandpa::Call::< Runtime, BridgeGrandpaWococoInstance, @@ -306,22 +300,33 @@ impl xcm_executor::Config for XcmConfig { ( XcmExportFeeToRelayerRewardAccounts< Self::AssetTransactor, - WococoGlobalConsensusNetwork, - AssetHubWococoParaId, - BridgeHubWococoChainId, - BridgeHubWococoMessagesLane, + crate::bridge_to_wococo_config::WococoGlobalConsensusNetwork, + crate::bridge_to_wococo_config::AssetHubWococoParaId, + crate::bridge_to_wococo_config::BridgeHubWococoChainId, + crate::bridge_to_wococo_config::AssetHubRococoToAssetHubWococoMessagesLane, >, XcmExportFeeToRelayerRewardAccounts< Self::AssetTransactor, - RococoGlobalConsensusNetwork, - AssetHubRococoParaId, - BridgeHubRococoChainId, - BridgeHubRococoMessagesLane, + crate::bridge_to_westend_config::WestendGlobalConsensusNetwork, + crate::bridge_to_westend_config::AssetHubWestendParaId, + crate::bridge_to_westend_config::BridgeHubWestendChainId, + crate::bridge_to_westend_config::AssetHubRococoToAssetHubWestendMessagesLane, + >, + XcmExportFeeToRelayerRewardAccounts< + Self::AssetTransactor, + crate::bridge_to_rococo_config::RococoGlobalConsensusNetwork, + crate::bridge_to_rococo_config::AssetHubRococoParaId, + crate::bridge_to_rococo_config::BridgeHubRococoChainId, + crate::bridge_to_rococo_config::AssetHubWococoToAssetHubRococoMessagesLane, >, XcmFeeToAccount, ), >; - type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; + type MessageExporter = ( + crate::bridge_to_westend_config::ToBridgeHubWestendHaulBlobExporter, + crate::bridge_to_wococo_config::ToBridgeHubWococoHaulBlobExporter, + crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter, + ); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; @@ -388,50 +393,6 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -/// Hacky switch implementation, because we have just one runtime for Rococo and Wococo BridgeHub, -/// so it means we have just one XcmConfig -pub struct BridgeHubRococoOrBridgeHubWococoSwitchExporter; -impl ExportXcm for BridgeHubRococoOrBridgeHubWococoSwitchExporter { - type Ticket = (NetworkId, (sp_std::prelude::Vec, XcmHash)); - - fn validate( - network: NetworkId, - channel: u32, - universal_source: &mut Option, - destination: &mut Option, - message: &mut Option>, - ) -> SendResult { - match network { - Rococo => ToBridgeHubRococoHaulBlobExporter::validate( - network, - channel, - universal_source, - destination, - message, - ) - .map(|result| ((Rococo, result.0), result.1)), - Wococo => ToBridgeHubWococoHaulBlobExporter::validate( - network, - channel, - universal_source, - destination, - message, - ) - .map(|result| ((Wococo, result.0), result.1)), - _ => unimplemented!("Unsupported network: {:?}", network), - } - } - - fn deliver(ticket: Self::Ticket) -> Result { - let (network, ticket) = ticket; - match network { - Rococo => ToBridgeHubRococoHaulBlobExporter::deliver(ticket), - Wococo => ToBridgeHubWococoHaulBlobExporter::deliver(ticket), - _ => unimplemented!("Unsupported network: {:?}", network), - } - } -} - /// A `HandleFee` implementation that simply deposits the fees for `ExportMessage` XCM instructions /// into the accounts that are used for paying the relayer rewards. /// Burns the fees in case of a failure. @@ -439,22 +400,22 @@ pub struct XcmExportFeeToRelayerRewardAccounts< AssetTransactor, DestNetwork, DestParaId, - DestBridgeHubId, + DestBridgedChainId, BridgeLaneId, ->(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgeHubId, BridgeLaneId)>); +>(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgedChainId, BridgeLaneId)>); impl< AssetTransactor: TransactAsset, DestNetwork: Get, DestParaId: Get, - DestBridgeHubId: Get, + DestBridgedChainId: Get, BridgeLaneId: Get, > HandleFee for XcmExportFeeToRelayerRewardAccounts< AssetTransactor, DestNetwork, DestParaId, - DestBridgeHubId, + DestBridgedChainId, BridgeLaneId, > { @@ -478,7 +439,7 @@ impl< AccountId, >::rewards_account(RewardsAccountParams::new( BridgeLaneId::get(), - DestBridgeHubId::get(), + DestBridgedChainId::get(), RewardsAccountOwner::ThisChain, )); @@ -487,7 +448,7 @@ impl< AccountId, >::rewards_account(RewardsAccountParams::new( BridgeLaneId::get(), - DestBridgeHubId::get(), + DestBridgedChainId::get(), RewardsAccountOwner::BridgedChain, )); 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 0109e4de4a9..b5b1c3778c0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -18,7 +18,8 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_common_config, bridge_hub_rococo_config, bridge_hub_wococo_config, + bridge_common_config, bridge_to_rococo_config, bridge_to_westend_config, + bridge_to_wococo_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, @@ -57,8 +58,9 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), ( - bridge_hub_wococo_config::BridgeRefundBridgeHubRococoMessages::default(), - bridge_hub_rococo_config::BridgeRefundBridgeHubWococoMessages::default(), + bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages::default(), + bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), + bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages::default(), ), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); @@ -96,12 +98,17 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + Box::new(|call| RuntimeCall::BridgeWestendGrandpa(call).encode()), ) } @@ -177,6 +194,7 @@ mod bridge_hub_rococo_tests { #[test] fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { + // for Wococo bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< Runtime, XcmConfig, @@ -187,12 +205,34 @@ mod bridge_hub_rococo_tests { SIBLING_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeRococoToWococoMessages(event)) => Some(event), + Ok(RuntimeEvent::BridgeWococoMessages(event)) => Some(event), _ => None, } }), || ExportMessage { network: Wococo, destination: X1(Parachain(1234)), xcm: Xcm(vec![]) }, - bridge_hub_rococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_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()), + || (), + ); + // for Westend + bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< + Runtime, + XcmConfig, + WithBridgeHubWestendMessagesInstance, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::BridgeWestendMessages(event)) => Some(event), + _ => None, + } + }), + || ExportMessage { network: Westend, destination: X1(Parachain(1234)), xcm: Xcm(vec![]) }, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, 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()), @@ -202,6 +242,7 @@ mod bridge_hub_rococo_tests { #[test] fn message_dispatch_routing_works() { + // from Wococo bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< Runtime, AllPalletsWithoutSystem, @@ -209,7 +250,7 @@ mod bridge_hub_rococo_tests { ParachainSystem, WithBridgeHubWococoMessagesInstance, RelayNetwork, - bridge_hub_rococo_config::WococoGlobalConsensusNetwork, + WococoGlobalConsensusNetwork, >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, @@ -226,13 +267,42 @@ mod bridge_hub_rococo_tests { _ => None, } }), - bridge_hub_rococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, + || (), + ); + // from Westend + bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + WithBridgeHubWococoMessagesInstance, + RelayNetwork, + WestendGlobalConsensusNetwork, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, || (), ) } #[test] fn relayed_incoming_message_works() { + // from Wococo bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< Runtime, AllPalletsWithoutSystem, @@ -248,13 +318,33 @@ mod bridge_hub_rococo_tests { bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Rococo, - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, + || (), + ); + // from Westend + bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + BridgeGrandpaWestendInstance, + BridgeParachainWestendInstance, + WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessageBridge, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Rococo, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, || (), ) } #[test] pub fn complex_relay_extrinsic_works() { + // for Wococo bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< Runtime, AllPalletsWithoutSystem, @@ -269,9 +359,32 @@ mod bridge_hub_rococo_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - bridge_hub_rococo_config::BridgeHubWococoChainId::get(), + BridgeHubWococoChainId::get(), + Rococo, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, + ExistentialDeposit::get(), + executive_init_block, + construct_and_apply_extrinsic, + || (), + ); + // for Westend + bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + BridgeGrandpaWestendInstance, + BridgeParachainWestendInstance, + WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessageBridge, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + BridgeHubWestendChainId::get(), Rococo, - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, ExistentialDeposit::get(), executive_init_block, construct_and_apply_extrinsic, @@ -305,9 +418,9 @@ mod bridge_hub_wococo_tests { RequiredStakeForStakeAndSlash, }; use bridge_hub_rococo_runtime::{xcm_config, AllPalletsWithoutSystem, RuntimeFlavor}; - use bridge_hub_wococo_config::{ - WithBridgeHubRococoMessageBridge, WithBridgeHubRococoMessagesInstance, - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + use bridge_to_rococo_config::{ + BridgeHubRococoChainId, RococoGlobalConsensusNetwork, WithBridgeHubRococoMessageBridge, + WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, }; use frame_support::assert_ok; @@ -419,12 +532,12 @@ mod bridge_hub_wococo_tests { SIBLING_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeWococoToRococoMessages(event)) => Some(event), + Ok(RuntimeEvent::BridgeRococoMessages(event)) => Some(event), _ => None, } }), || ExportMessage { network: Rococo, destination: X1(Parachain(4321)), xcm: Xcm(vec![]) }, - bridge_hub_wococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_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()), @@ -441,7 +554,7 @@ mod bridge_hub_wococo_tests { ParachainSystem, WithBridgeHubRococoMessagesInstance, RelayNetwork, - bridge_hub_wococo_config::RococoGlobalConsensusNetwork, + RococoGlobalConsensusNetwork, >( collator_session_keys(), bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, @@ -458,7 +571,7 @@ mod bridge_hub_wococo_tests { _ => None, } }), - bridge_hub_wococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, set_wococo_flavor, ) } @@ -480,7 +593,7 @@ mod bridge_hub_wococo_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Wococo, - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, set_wococo_flavor, ) } @@ -501,9 +614,9 @@ mod bridge_hub_wococo_tests { bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - bridge_hub_wococo_config::BridgeHubRococoChainId::get(), + BridgeHubRococoChainId::get(), Wococo, - DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, ExistentialDeposit::get(), executive_init_block, construct_and_apply_extrinsic, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml new file mode 100644 index 00000000000..92250a84786 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -0,0 +1,239 @@ +[package] +name = "bridge-hub-westend-runtime" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +description = "Westend's BridgeHub parachain runtime" +license = "Apache-2.0" + +[build-dependencies] +substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +hex-literal = { version = "0.4.1" } +log = { version = "0.4.20", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.188", optional = true, 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-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-session = { path = "../../../../../substrate/frame/session", default-features = false} +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} +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-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} +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} + +# Polkadot +westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } +parachains-common = { path = "../../../common", default-features = false } + +# Bridges +bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } +bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } +bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } +bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } +bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } +bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } +bp-westend = { path = "../../../../../bridges/primitives/chain-westend", default-features = false } +pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } +pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } + +[dev-dependencies] +static_assertions = "1.1" +bridge-hub-test-utils = { path = "../test-utils" } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = ["integrity-test"] } +sp-keyring = { path = "../../../../../substrate/primitives/keyring" } + +[features] +default = [ "std" ] +std = [ + "bp-asset-hub-westend/std", + "bp-bridge-hub-rococo/std", + "bp-bridge-hub-westend/std", + "bp-header-chain/std", + "bp-messages/std", + "bp-parachains/std", + "bp-polkadot-core/std", + "bp-relayers/std", + "bp-rococo/std", + "bp-runtime/std", + "bp-westend/std", + "bridge-runtime-common/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-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", + "pallet-bridge-relayers/std", + "pallet-collator-selection/std", + "pallet-multisig/std", + "pallet-session/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm-benchmarks?/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-core-primitives/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "scale-info/std", + "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", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + "substrate-wasm-builder", + "westend-runtime-constants/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] + +runtime-benchmarks = [ + "bridge-runtime-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-balances/runtime-benchmarks", + "pallet-bridge-grandpa/runtime-benchmarks", + "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", + "pallet-bridge-relayers/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-xcm-benchmarks/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-aura/try-runtime", + "pallet-authorship/try-runtime", + "pallet-balances/try-runtime", + "pallet-bridge-grandpa/try-runtime", + "pallet-bridge-messages/try-runtime", + "pallet-bridge-parachains/try-runtime", + "pallet-bridge-relayers/try-runtime", + "pallet-collator-selection/try-runtime", + "pallet-multisig/try-runtime", + "pallet-session/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/try-runtime", +] + +experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/build.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/build.rs new file mode 100644 index 00000000000..60f8a125129 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs new file mode 100644 index 00000000000..9bae106395a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs @@ -0,0 +1,50 @@ +// 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 . + +//! Bridge definitions that can be used by multiple BridgeHub flavors. +//! All configurations here should be dedicated to a single chain; in other words, we don't need two +//! chains for a single pallet configuration. +//! +//! For example, the messaging pallet needs to know the sending and receiving chains, but the +//! GRANDPA tracking pallet only needs to be aware of one chain. + +use super::{weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent}; +use frame_support::parameter_types; + +parameter_types! { + pub storage RequiredStakeForStakeAndSlash: Balance = 1_000_000; + pub const RelayerStakeLease: u32 = 8; + pub const RelayerStakeReserveId: [u8; 8] = *b"brdgrlrs"; + + pub storage DeliveryRewardInBalance: u64 = 1_000_000; +} + +/// Allows collect and claim rewards for relayers +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = + bp_relayers::PayRewardFromAccount, AccountId>; + type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< + AccountId, + BlockNumber, + Balances, + RelayerStakeReserveId, + RequiredStakeForStakeAndSlash, + RelayerStakeLease, + >; + type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs new file mode 100644 index 00000000000..70ff43c09e3 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -0,0 +1,347 @@ +// 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 . + +//! Bridge definitions used on BridgeHub with the Westend flavor. + +use crate::{ + bridge_common_config::DeliveryRewardInBalance, weights, AccountId, BridgeRococoMessages, + ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, XcmRouter, +}; +use bp_messages::LaneId; +use bp_parachains::SingleParaStoredHeaderDataBuilder; +use bridge_runtime_common::{ + messages, + messages::{ + source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, + target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, + MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, + }, + messages_xcm_extension::{ + SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, + XcmBlobMessageDispatch, + }, + refund_relayer_extension::{ + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, + }, +}; +use codec::Encode; +use frame_support::{ + parameter_types, + traits::{ConstU32, PalletInfoAccess}, +}; +use sp_runtime::RuntimeDebug; +use xcm::{ + latest::prelude::*, + prelude::{InteriorMultiLocation, NetworkId}, +}; +use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; + +parameter_types! { + pub const RelayChainHeadersToKeep: u32 = 1024; + pub const ParachainHeadsToKeep: u32 = 64; + + pub const RococoBridgeParachainPalletName: &'static str = "Paras"; + pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; + + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; + pub BridgeHubWestendUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Westend), Parachain(ParachainInfo::parachain_id().into())); + pub BridgeWestendToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); + pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; + pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; + pub const AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; + // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value + pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; + + pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); + + pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( + ParentThen(X1(Parachain(AssetHubWestendParaId::get().into()))).into(), + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + ); + + pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + + pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); +} +pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); + +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_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_westend::Call::ToRococoXcmRouter( + bp_asset_hub_westend::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 -> Westend Bridge Hub messages. +pub type ToRococoBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof; + +/// Dispatches received XCM messages from other bridge +type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher< + XcmRouter, + BridgeHubWestendUniversalLocation, + BridgeWestendToRococoMessagesPalletInstance, +>; + +/// Export XCM messages to be relayed to the other side +pub type ToBridgeHubRococoHaulBlobExporter = HaulBlobExporter< + XcmBlobHaulerAdapter, + RococoGlobalConsensusNetwork, + (), +>; +pub struct ToBridgeHubRococoXcmBlobHauler; +impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { + type Runtime = Runtime; + type MessagesInstance = WithBridgeHubRococoMessagesInstance; + type SenderAndLane = FromAssetHubWestendToAssetHubRococoRoute; + + type ToSourceChainSender = XcmRouter; + type CongestedMessage = CongestedMessage; + type UncongestedMessage = UncongestedMessage; +} + +/// On messages delivered callback. +type OnMessagesDelivered = XcmBlobHaulerAdapter; + +/// Messaging Bridge configuration for BridgeHubWestend -> BridgeHubRococo +pub struct WithBridgeHubRococoMessageBridge; +impl MessageBridge for WithBridgeHubRococoMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME; + type ThisChain = BridgeHubWestend; + type BridgedChain = BridgeHubRococo; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + BridgeParachainRococoInstance, + bp_bridge_hub_rococo::BridgeHubRococo, + >; +} + +/// Message verifier for BridgeHubRococo messages sent from BridgeHubWestend +type ToBridgeHubRococoMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Maximal outbound payload size of BridgeHubWestend -> BridgeHubRococo messages. +type ToBridgeHubRococoMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// BridgeHubRococo chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct BridgeHubRococo; + +impl UnderlyingChainProvider for BridgeHubRococo { + type Chain = bp_bridge_hub_rococo::BridgeHubRococo; +} + +impl messages::BridgedChainWithMessages for BridgeHubRococo {} + +/// BridgeHubWestend chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct BridgeHubWestend; + +impl UnderlyingChainProvider for BridgeHubWestend { + type Chain = bp_bridge_hub_westend::BridgeHubWestend; +} + +impl ThisChainWithMessages for BridgeHubWestend { + type RuntimeOrigin = RuntimeOrigin; +} + +/// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< + RefundBridgedParachainMessages< + Runtime, + RefundableParachain, + RefundableMessagesLane< + WithBridgeHubRococoMessagesInstance, + AssetHubWestendToAssetHubRococoMessagesLane, + >, + ActualFeeRefund, + PriorityBoostPerMessage, + StrOnBridgeHubWestendRefundBridgeHubRococoMessages, + >, +>; +bp_runtime::generate_static_str_provider!(OnBridgeHubWestendRefundBridgeHubRococoMessages); + +/// Add GRANDPA bridge pallet to track Rococo relay chain. +pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance1; +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_rococo::Rococo; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = RelayChainHeadersToKeep; + type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo; +} + +/// Add parachain bridge pallet to track Rococo BridgeHub parachain +pub type BridgeParachainRococoInstance = pallet_bridge_parachains::Instance1; +impl pallet_bridge_parachains::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_parachains::WeightInfo; + type BridgesGrandpaPalletInstance = BridgeGrandpaRococoInstance; + type ParasPalletName = RococoBridgeParachainPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ParachainHeadsToKeep; + type MaxParaHeadDataSize = MaxRococoParaHeadDataSize; +} + +/// Add XCM messages support for BridgeHubWestend to support Westend->Rococo XCM messages +pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance1; +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_bridge_messages::WeightInfo; + type BridgedChainId = BridgeHubRococoChainId; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = ToBridgeHubRococoMaximalOutboundPayloadSize; + type OutboundPayload = XcmAsPlainPayload; + + type InboundPayload = XcmAsPlainPayload; + type InboundRelayer = AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = ToBridgeHubRococoMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithBridgeHubRococoMessagesInstance, + DeliveryRewardInBalance, + >; + + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = XcmBlobMessageDispatch< + FromRococoMessageBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + AssetHubWestendParaId, + Runtime, + >, + >; + type OnMessagesDelivered = OnMessagesDelivered; +} + +#[cfg(test)] +mod tests { + use super::*; + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + AssertCompleteBridgeConstants, + }, + }; + use parachains_common::{westend, 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 * westend::currency::UNITS; + + #[test] + fn ensure_bridge_hub_westend_message_lane_weights_are_correct() { + check_message_lane_weights::< + bp_bridge_hub_westend::BridgeHubWestend, + Runtime, + WithBridgeHubRococoMessagesInstance, + >( + bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE, + bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + true, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: BridgeGrandpaRococoInstance, + with_bridged_chain_messages_instance: WithBridgeHubRococoMessagesInstance, + bridge: WithBridgeHubRococoMessageBridge, + this_chain: bp_westend::Westend, + bridged_chain: bp_rococo::Rococo, + ); + + assert_complete_bridge_constants::< + Runtime, + BridgeGrandpaRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_bridge_hub_westend::BlockLength::get(), + block_weights: bp_bridge_hub_westend::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: + bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + 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!( + BridgeWestendToRococoMessagesPalletInstance::get(), + X1(PalletInstance( + bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX + )) + ); + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs new file mode 100644 index 00000000000..7d4cb03aa06 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -0,0 +1,1077 @@ +// 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 . + +//! # Bridge Hub Westend Runtime +//! +//! This runtime currently supports bridging between: +//! - Rococo <> Westend + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod bridge_common_config; +pub mod bridge_to_rococo_config; +mod weights; +pub mod xcm_config; + +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::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +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}, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; +use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; + +use bp_runtime::HeaderId; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use xcm::latest::prelude::*; + +use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; + +use parachains_common::{ + impls::DealWithFees, + westend::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, + HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, +}; +use xcm_executor::XcmExecutor; + +/// The address format for describing accounts. +pub type Address = 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_transaction_payment::ChargeTransactionPayment, + BridgeRejectObsoleteHeadersAndMessages, + (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), +); + +/// 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, + 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< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + Migrations, +>; + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("bridge-hub-westend"), + impl_name: create_runtime_str!("bridge-hub-westend"), + authoring_version: 1, + spec_version: 1_003_000, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 3, + state_version: 1, +}; + +/// 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: u16 = 42; +} + +// Configure FRAME pallets to include in runtime. + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Nonce; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The block type. + type Block = Block; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// Runtime version. + type Version = Version; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The action to take on a Runtime Upgrade + 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 { + /// The type for recording an account's balance. + type Balance = Balance; + type DustRemoval = (); + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = weights::pallet_balances::WeightInfo; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + 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 OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; +} + +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 OutboundXcmpMessageSource = XcmpQueue; + type DmpMessageHandler = DmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, + >; +} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::WestendLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + +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 = XcmOriginToTransactDispatchOrigin; + type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = EnsureRoot; +} + +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, ConstU32>; + type NextSessionRotation = pallet_session::PeriodicSessions, ConstU32>; + 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; +} + +pub type CollatorSelectionUpdateOrigin = EnsureRoot; + +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 = ConstU32; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = weights::pallet_collator_selection::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); +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = ConstU32<100>; + 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; +} + +// 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} = 2, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, + + // Collator support. The order of these 4 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, 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} = 36, + + + // Bridging stuff. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 41, + BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 42, + BridgeRococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 43, + BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 44, + } +); + +bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { + RuntimeCall, AccountId, + // Grandpa + BridgeRococoGrandpa, + // Parachains + BridgeRococoParachains, + // Messages + BridgeRococoMessages +} + +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_multisig, Multisig] + [pallet_session, SessionBench::] + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_xcmp_queue, XcmpQueue] + // XCM + [pallet_xcm, PolkadotXcm] + // NOTE: Make sure you point to the individual modules below. + [pallet_xcm_benchmarks::fungible, XcmBalances] + [pallet_xcm_benchmarks::generic, XcmGeneric] + // Bridge pallets + [pallet_bridge_relayers, BridgeRelayersBench::] + [pallet_bridge_grandpa, RococoFinality] + [pallet_bridge_parachains, WithinRococo] + [pallet_bridge_messages, WestendToRococo] + ); +} + +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_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 cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl bp_rococo::RococoFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeRococoGrandpa::best_finalized() + } + fn synced_headers_grandpa_info( + ) -> Vec> { + BridgeRococoGrandpa::synced_headers_grandpa_info() + } + } + + impl bp_bridge_hub_rococo::BridgeHubRococoFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeRococoParachains::best_parachain_head_id::< + bp_bridge_hub_rococo::BridgeHubRococo + >().unwrap_or(None) + } + } + + impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >(lane, messages) + } + } + + impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + begin: bp_messages::MessageNonce, + end: bp_messages::MessageNonce, + ) -> Vec { + bridge_runtime_common::messages_api::outbound_message_details::< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >(lane, begin, end) + } + } + + #[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; + + // 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::; + + use pallet_bridge_relayers::benchmarking::Pallet as BridgeRelayersBench; + // Change weight file names. + type RococoFinality = BridgeRococoGrandpa; + type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WestendToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + + 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 xcm::latest::prelude::*; + use xcm_config::WestendLocation; + + parameter_types! { + pub ExistentialDepositMultiAsset: Option = Some(( + WestendLocation::get(), + ExistentialDeposit::get() + ).into()); + } + + impl pallet_xcm_benchmarks::Config for Runtime { + type XcmConfig = xcm_config::XcmConfig; + type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + XcmConfig, + ExistentialDepositMultiAsset, + xcm_config::PriceForParentDelivery, + >; + fn valid_destination() -> Result { + Ok(WestendLocation::get()) + } + fn worst_case_holding(_depositable_count: u32) -> MultiAssets { + // just concrete assets according to relay chain. + let assets: Vec = vec![ + MultiAsset { + id: Concrete(WestendLocation::get()), + fun: Fungible(1_000_000 * UNITS), + } + ]; + assets.into() + } + } + + parameter_types! { + pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( + WestendLocation::get(), + MultiAsset { fun: Fungible(UNITS), id: Concrete(WestendLocation::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(WestendLocation::get()), + fun: Fungible(UNITS), + } + } + } + + impl pallet_xcm_benchmarks::generic::Config for Runtime { + type TransactAsset = Balances; + 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> { + Err(BenchmarkError::Skip) + } + + fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { + Ok((WestendLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + } + + fn subscribe_origin() -> Result { + Ok(WestendLocation::get()) + } + + fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { + let origin = WestendLocation::get(); + let assets: MultiAssets = (Concrete(WestendLocation::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> { + Ok((WestendLocation::get(), NetworkId::Rococo, X1(Parachain(100)))) + } + + 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 RococoFinality = BridgeRococoGrandpa; + type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; + type WestendToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + + use bridge_runtime_common::messages_benchmarking::{ + prepare_message_delivery_proof_from_parachain, + prepare_message_proof_from_parachain, + generate_xcm_builder_bridge_message_sample, + }; + use pallet_bridge_messages::benchmarking::{ + Config as BridgeMessagesConfig, + MessageDeliveryProofParams, + MessageProofParams, + }; + + impl BridgeMessagesConfig for Runtime { + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { + let bench_lane_id = >::bench_lane_id(); + let bridged_chain_id = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; + pallet_bridge_relayers::Pallet::::relayer_reward( + relayer, + bp_relayers::RewardsAccountParams::new( + bench_lane_id, + bridged_chain_id, + bp_relayers::RewardsAccountOwner::BridgedChain + ) + ).is_some() + } + + fn prepare_message_proof( + params: MessageProofParams, + ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { + use cumulus_primitives_core::XcmpMessageSource; + assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + prepare_message_proof_from_parachain::< + Runtime, + bridge_to_rococo_config::BridgeGrandpaRococoInstance, + bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, + >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Westend), Parachain(42)))) + } + + fn prepare_message_delivery_proof( + params: MessageDeliveryProofParams, + ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { + prepare_message_delivery_proof_from_parachain::< + Runtime, + bridge_to_rococo_config::BridgeGrandpaRococoInstance, + bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, + >(params) + } + + fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool { + use cumulus_primitives_core::XcmpMessageSource; + !XcmpQueue::take_outbound_messages(usize::MAX).is_empty() + } + } + + use bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof; + use pallet_bridge_parachains::benchmarking::Config as BridgeParachainsConfig; + use pallet_bridge_relayers::benchmarking::{ + Pallet as BridgeRelayersBench, + Config as BridgeRelayersConfig, + }; + + impl BridgeParachainsConfig for Runtime { + fn parachains() -> Vec { + use bp_runtime::Parachain; + vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_rococo::BridgeHubRococo::PARACHAIN_ID)] + } + + fn prepare_parachain_heads_proof( + parachains: &[bp_polkadot_core::parachains::ParaId], + parachain_head_size: u32, + proof_size: bp_runtime::StorageProofSize, + ) -> ( + pallet_bridge_parachains::RelayBlockNumber, + pallet_bridge_parachains::RelayBlockHash, + bp_polkadot_core::parachains::ParaHeadsProof, + Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, + ) { + prepare_parachain_heads_proof::( + parachains, + parachain_head_size, + proof_size, + ) + } + } + + impl BridgeRelayersConfig for Runtime { + fn prepare_rewards_account( + account_params: bp_relayers::RewardsAccountParams, + reward: Balance, + ) { + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + AccountId + >::rewards_account(account_params); + Self::deposit_account(rewards_account, reward); + } + + fn deposit_account(account: AccountId, balance: Balance) { + use frame_support::traits::fungible::Mutate; + Balances::mint_into(&account, balance.saturating_add(ExistentialDeposit::get())).unwrap(); + } + } + + 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(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + 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! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::Encode; + use sp_runtime::{ + generic::Era, + traits::{SignedExtension, Zero}, + }; + + #[test] + fn ensure_signed_extension_definition_is_compatible_with_relay() { + use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + + sp_io::TestExternalities::default().execute_with(|| { + frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); + let payload: SignedExtra = ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(10), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(10), + BridgeRejectObsoleteHeadersAndMessages, + ( + bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), + ), + ); + + { + let bh_indirect_payload = bp_bridge_hub_westend::SignedExtension::from_params( + VERSION.spec_version, + VERSION.transaction_version, + bp_runtime::TransactionEra::Immortal, + System::block_hash(BlockNumber::zero()), + 10, + 10, + (((), ()), ((), ())), + ); + assert_eq!(payload.encode(), bh_indirect_payload.encode()); + assert_eq!( + payload.additional_signed().unwrap().encode(), + bh_indirect_payload.additional_signed().unwrap().encode() + ) + } + }); + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs new file mode 100644 index 00000000000..e7fdb2aae2a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 00000000000..0106d6398f4 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-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/bridge-hubs/bridge-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: 4_930_000 picoseconds. + Weight::from_parts(5_292_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_012_000 picoseconds. + Weight::from_parts(5_282_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/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs new file mode 100644 index 00000000000..1a4adb968bb --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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/bridge-hubs/bridge-hub-westend/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system.rs new file mode 100644 index 00000000000..3dec4cc7f18 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-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/bridge-hubs/bridge-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: 1_956_000 picoseconds. + Weight::from_parts(2_974_450, 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_432_000 picoseconds. + Weight::from_parts(7_686_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_767, 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_715_000 picoseconds. + Weight::from_parts(3_983_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: 99_688_458_000 picoseconds. + Weight::from_parts(103_623_061_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_318_000 picoseconds. + Weight::from_parts(2_421_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_168 + .saturating_add(Weight::from_parts(765_555, 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_162_000 picoseconds. + Weight::from_parts(2_228_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 951 + .saturating_add(Weight::from_parts(569_773, 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: `68 + p * (69 ±0)` + // Estimated: `71 + p * (70 ±0)` + // Minimum execution time: 3_795_000 picoseconds. + Weight::from_parts(3_895_000, 0) + .saturating_add(Weight::from_parts(0, 71)) + // Standard Error: 1_869 + .saturating_add(Weight::from_parts(1_209_251, 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/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs new file mode 100644 index 00000000000..7003e3e9253 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -0,0 +1,72 @@ +// 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. + +use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; +use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; + +pub mod block_weights; +pub mod cumulus_pallet_xcmp_queue; +pub mod extrinsic_weights; +pub mod frame_system; +pub mod pallet_balances; +pub mod pallet_bridge_grandpa; +pub mod pallet_bridge_messages; +pub mod pallet_bridge_parachains; +pub mod pallet_bridge_relayers; +pub mod pallet_collator_selection; +pub mod pallet_multisig; +pub mod pallet_session; +pub mod pallet_timestamp; +pub mod pallet_utility; +pub mod pallet_xcm; +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; + +use crate::Runtime; +use frame_support::weights::Weight; + +// import trait from dependency module +use ::pallet_bridge_relayers::WeightInfoExt as _; + +impl MessagesWeightInfoExt for pallet_bridge_messages::WeightInfo { + fn expected_extra_storage_proof_size() -> u32 { + bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE + } + + fn receive_messages_proof_overhead_from_runtime() -> Weight { + pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( + ) + } + + fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { + pallet_bridge_relayers::WeightInfo::::receive_messages_delivery_proof_overhead_from_runtime() + } +} + +impl ParachainsWeightInfoExt for pallet_bridge_parachains::WeightInfo { + fn expected_extra_storage_proof_size() -> u32 { + bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs new file mode 100644 index 00000000000..26a188a9861 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs @@ -0,0 +1,153 @@ +// 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_balances` +//! +//! 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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_balances +// --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/ + +#![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: 56_219_000 picoseconds. + Weight::from_parts(56_763_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: 41_515_000 picoseconds. + Weight::from_parts(42_186_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: 16_274_000 picoseconds. + Weight::from_parts(16_898_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_847_000 picoseconds. + Weight::from_parts(24_343_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_564_000 picoseconds. + Weight::from_parts(58_172_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: 52_131_000 picoseconds. + Weight::from_parts(52_662_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: 19_005_000 picoseconds. + Weight::from_parts(19_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:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 17_275_000 picoseconds. + Weight::from_parts(17_901_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 15_775 + .saturating_add(Weight::from_parts(15_448_147, 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/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs new file mode 100644 index 00000000000..b0634ff2ccf --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs @@ -0,0 +1,83 @@ +// 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_bridge_grandpa` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_grandpa +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_grandpa`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_grandpa::WeightInfo for WeightInfo { + /// Storage: `BridgeRococoGrandpa::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::BestFinalized` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::CurrentAuthoritySet` (r:1 w:0) + /// Proof: `BridgeRococoGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHashesPointer` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHashes` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:0 w:2) + /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + fn submit_finality_proof(p: u32, v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `268 + p * (60 ±0)` + // Estimated: `51735` + // Minimum execution time: 304_726_000 picoseconds. + Weight::from_parts(16_868_060, 0) + .saturating_add(Weight::from_parts(0, 51735)) + // Standard Error: 2_802 + .saturating_add(Weight::from_parts(55_200_017, 0).saturating_mul(p.into())) + // Standard Error: 46_745 + .saturating_add(Weight::from_parts(2_689_151, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs new file mode 100644 index 00000000000..5d229497f3e --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs @@ -0,0 +1,245 @@ +// 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_bridge_messages` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_messages +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_messages`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_messages::WeightInfo for WeightInfo { + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_single_message_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `575` + // Estimated: `52645` + // Minimum execution time: 42_332_000 picoseconds. + Weight::from_parts(43_375_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_two_messages_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `575` + // Estimated: `52645` + // Minimum execution time: 53_139_000 picoseconds. + Weight::from_parts(54_236_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + // Proof Size summary in bytes: + // Measured: `575` + // Estimated: `52645` + // Minimum execution time: 47_466_000 picoseconds. + Weight::from_parts(48_724_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + fn receive_single_message_proof_1_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `543` + // Estimated: `52645` + // Minimum execution time: 40_962_000 picoseconds. + Weight::from_parts(42_002_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + fn receive_single_message_proof_16_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `543` + // Estimated: `52645` + // Minimum execution time: 71_599_000 picoseconds. + Weight::from_parts(74_307_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_single_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `414` + // Estimated: `3879` + // Minimum execution time: 31_206_000 picoseconds. + Weight::from_parts(32_045_000, 0) + .saturating_add(Weight::from_parts(0, 3879)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + // Proof Size summary in bytes: + // Measured: `414` + // Estimated: `3879` + // Minimum execution time: 31_211_000 picoseconds. + Weight::from_parts(32_171_000, 0) + .saturating_add(Weight::from_parts(0, 3879)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + // Proof Size summary in bytes: + // Measured: `414` + // Estimated: `6086` + // Minimum execution time: 33_790_000 picoseconds. + Weight::from_parts(34_708_000, 0) + .saturating_add(Weight::from_parts(0, 6086)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `777` + // Estimated: `52645` + // Minimum execution time: 61_938_000 picoseconds. + Weight::from_parts(63_009_714, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 23 + .saturating_add(Weight::from_parts(6_677, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs new file mode 100644 index 00000000000..81cb0a66b7d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs @@ -0,0 +1,114 @@ +// 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_bridge_parachains` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_parachains +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_parachains`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_parachains::WeightInfo for WeightInfo { + /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. + fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 31_241_000 picoseconds. + Weight::from_parts(32_488_584, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + fn submit_parachain_heads_with_1kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 32_962_000 picoseconds. + Weight::from_parts(33_658_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + fn submit_parachain_heads_with_16kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 62_685_000 picoseconds. + Weight::from_parts(64_589_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs new file mode 100644 index 00000000000..fde670ab927 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs @@ -0,0 +1,123 @@ +// 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_bridge_relayers` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_relayers +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_relayers`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_relayers::WeightInfo for WeightInfo { + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn claim_rewards() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3593` + // Minimum execution time: 45_338_000 picoseconds. + Weight::from_parts(45_836_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeRelayers::RegisteredRelayers` (r:1 w:1) + /// Proof: `BridgeRelayers::RegisteredRelayers` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x1e8445dc201eeb8560e5579a5dd54655` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x1e8445dc201eeb8560e5579a5dd54655` (r:1 w:0) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `61` + // Estimated: `4714` + // Minimum execution time: 23_561_000 picoseconds. + Weight::from_parts(24_012_000, 0) + .saturating_add(Weight::from_parts(0, 4714)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeRelayers::RegisteredRelayers` (r:1 w:1) + /// Proof: `BridgeRelayers::RegisteredRelayers` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `4714` + // Minimum execution time: 25_133_000 picoseconds. + Weight::from_parts(25_728_000, 0) + .saturating_add(Weight::from_parts(0, 4714)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `BridgeRelayers::RegisteredRelayers` (r:1 w:1) + /// Proof: `BridgeRelayers::RegisteredRelayers` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn slash_and_deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `263` + // Estimated: `4714` + // Minimum execution time: 27_356_000 picoseconds. + Weight::from_parts(27_828_000, 0) + .saturating_add(Weight::from_parts(0, 4714)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn register_relayer_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3538` + // Minimum execution time: 2_955_000 picoseconds. + Weight::from_parts(3_084_000, 0) + .saturating_add(Weight::from_parts(0, 3538)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs new file mode 100644 index 00000000000..9cbfa6ce80e --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-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/bridge-hubs/bridge-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: `196 + b * (79 ±0)` + // Estimated: `1187 + b * (2555 ±0)` + // Minimum execution time: 14_728_000 picoseconds. + Weight::from_parts(11_562_750, 0) + .saturating_add(Weight::from_parts(0, 1187)) + // Standard Error: 7_121 + .saturating_add(Weight::from_parts(3_300_884, 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: `757 + b * (32 ±0) + c * (53 ±0)` + // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` + // Minimum execution time: 47_549_000 picoseconds. + Weight::from_parts(45_432_273, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 11_457 + .saturating_add(Weight::from_parts(216_469, 0).saturating_mul(b.into())) + // Standard Error: 2_171 + .saturating_add(Weight::from_parts(197_614, 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: `82 + b * (32 ±0)` + // Estimated: `6287` + // Minimum execution time: 15_417_000 picoseconds. + Weight::from_parts(15_357_487, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 4_074 + .saturating_add(Weight::from_parts(187_410, 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_407_000 picoseconds. + Weight::from_parts(7_657_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_514_000 picoseconds. + Weight::from_parts(7_695_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: `740 + c * (52 ±0)` + // Estimated: `6287 + c * (54 ±0)` + // Minimum execution time: 41_711_000 picoseconds. + Weight::from_parts(45_690_780, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_800 + .saturating_add(Weight::from_parts(194_907, 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 `[3, 100]`. + fn leave_intent(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `334 + c * (49 ±0)` + // Estimated: `6287` + // Minimum execution time: 33_901_000 picoseconds. + Weight::from_parts(35_875_905, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 1_968 + .saturating_add(Weight::from_parts(200_283, 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: `155` + // Estimated: `6196` + // Minimum execution time: 47_475_000 picoseconds. + Weight::from_parts(48_265_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: `2263 + c * (97 ±0) + r * (115 ±0)` + // Estimated: `6287 + c * (2519 ±0) + r * (2603 ±0)` + // Minimum execution time: 16_907_000 picoseconds. + Weight::from_parts(17_203_000, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 354_098 + .saturating_add(Weight::from_parts(15_341_462, 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_multisig.rs new file mode 100644 index 00000000000..91840ae0c6d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_multisig.rs @@ -0,0 +1,165 @@ +// 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_multisig` +//! +//! 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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_multisig +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-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_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_958_000 picoseconds. + Weight::from_parts(14_501_711, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(626, 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: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 44_067_000 picoseconds. + Weight::from_parts(33_432_998, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_250 + .saturating_add(Weight::from_parts(131_851, 0).saturating_mul(s.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_459, 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: `282` + // Estimated: `6811` + // Minimum execution time: 29_373_000 picoseconds. + Weight::from_parts(19_409_201, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 725 + .saturating_add(Weight::from_parts(110_824, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_502, 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: `388 + s * (33 ±0)` + // Estimated: `6811` + // Minimum execution time: 49_724_000 picoseconds. + Weight::from_parts(34_153_321, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_376 + .saturating_add(Weight::from_parts(174_634, 0).saturating_mul(s.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(1_753, 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: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 31_081_000 picoseconds. + Weight::from_parts(31_552_702, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_066 + .saturating_add(Weight::from_parts(135_081, 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: `282` + // Estimated: `6811` + // Minimum execution time: 17_807_000 picoseconds. + Weight::from_parts(18_241_044, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 768 + .saturating_add(Weight::from_parts(112_957, 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: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 32_421_000 picoseconds. + Weight::from_parts(32_554_061, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_157 + .saturating_add(Weight::from_parts(141_221, 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/bridge-hubs/bridge-hub-westend/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_session.rs new file mode 100644 index 00000000000..c9d04f9c6df --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-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/bridge-hubs/bridge-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: `297` + // Estimated: `3762` + // Minimum execution time: 16_965_000 picoseconds. + Weight::from_parts(17_384_000, 0) + .saturating_add(Weight::from_parts(0, 3762)) + .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: `279` + // Estimated: `3744` + // Minimum execution time: 12_444_000 picoseconds. + Weight::from_parts(12_832_000, 0) + .saturating_add(Weight::from_parts(0, 3744)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000000..0a5bf9b9f9c --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_timestamp.rs @@ -0,0 +1,75 @@ +// 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_timestamp` +//! +//! 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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_timestamp +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-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_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `85` + // Estimated: `1493` + // Minimum execution time: 9_231_000 picoseconds. + Weight::from_parts(9_595_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_869_000 picoseconds. + Weight::from_parts(4_041_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs new file mode 100644 index 00000000000..44cd0cf91e7 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs @@ -0,0 +1,102 @@ +// 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_utility` +//! +//! 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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_utility +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-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_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_831_000 picoseconds. + Weight::from_parts(12_945_569, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_949 + .saturating_add(Weight::from_parts(5_125_189, 0).saturating_mul(c.into())) + } + fn as_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_790_000 picoseconds. + Weight::from_parts(5_063_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_894_000 picoseconds. + Weight::from_parts(14_201_341, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_501 + .saturating_add(Weight::from_parts(5_466_047, 0).saturating_mul(c.into())) + } + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_624_000 picoseconds. + Weight::from_parts(9_064_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_912_000 picoseconds. + Weight::from_parts(9_228_121, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_601 + .saturating_add(Weight::from_parts(5_138_293, 0).saturating_mul(c.into())) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs new file mode 100644 index 00000000000..72bdb282585 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -0,0 +1,289 @@ +// 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("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-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/bridge-hubs/bridge-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: `75` + // Estimated: `3540` + // Minimum execution time: 29_724_000 picoseconds. + Weight::from_parts(30_440_000, 0) + .saturating_add(Weight::from_parts(0, 3540)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 26_779_000 picoseconds. + Weight::from_parts(27_249_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 reserve_transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn 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_170_000 picoseconds. + Weight::from_parts(9_629_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_769_000 picoseconds. + Weight::from_parts(2_933_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: `75` + // Estimated: `3540` + // Minimum execution time: 34_547_000 picoseconds. + Weight::from_parts(35_653_000, 0) + .saturating_add(Weight::from_parts(0, 3540)) + .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: `292` + // Estimated: `3757` + // Minimum execution time: 36_274_000 picoseconds. + Weight::from_parts(37_281_000, 0) + .saturating_add(Weight::from_parts(0, 3757)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `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_749_000 picoseconds. + Weight::from_parts(2_917_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: `187` + // Estimated: `11077` + // Minimum execution time: 17_649_000 picoseconds. + Weight::from_parts(17_964_000, 0) + .saturating_add(Weight::from_parts(0, 11077)) + .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: `191` + // Estimated: `11081` + // Minimum execution time: 17_551_000 picoseconds. + Weight::from_parts(18_176_000, 0) + .saturating_add(Weight::from_parts(0, 11081)) + .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: `198` + // Estimated: `13563` + // Minimum execution time: 19_261_000 picoseconds. + Weight::from_parts(19_714_000, 0) + .saturating_add(Weight::from_parts(0, 13563)) + .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: `142` + // Estimated: `6082` + // Minimum execution time: 31_630_000 picoseconds. + Weight::from_parts(32_340_000, 0) + .saturating_add(Weight::from_parts(0, 6082)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn notify_target_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `172` + // Estimated: `8587` + // Minimum execution time: 9_218_000 picoseconds. + Weight::from_parts(9_558_000, 0) + .saturating_add(Weight::from_parts(0, 8587)) + .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: `198` + // Estimated: `11088` + // Minimum execution time: 18_133_000 picoseconds. + Weight::from_parts(18_663_000, 0) + .saturating_add(Weight::from_parts(0, 11088)) + .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: `204` + // Estimated: `11094` + // Minimum execution time: 38_878_000 picoseconds. + Weight::from_parts(39_779_000, 0) + .saturating_add(Weight::from_parts(0, 11094)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs new file mode 100644 index 00000000000..25679703831 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 50_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs new file mode 100644 index 00000000000..3dd817aa6f1 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 100_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs new file mode 100644 index 00000000000..7269fa84f84 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs @@ -0,0 +1,247 @@ +// 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 . + +mod pallet_xcm_benchmarks_fungible; +mod pallet_xcm_benchmarks_generic; + +use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use codec::Encode; +use frame_support::weights::Weight; +use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; +use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; +use sp_std::prelude::*; +use xcm::{latest::prelude::*, DoubleEncoded}; + +trait WeighMultiAssets { + fn weigh_multi_assets(&self, weight: Weight) -> Weight; +} + +const MAX_ASSETS: u64 = 100; + +impl WeighMultiAssets for MultiAssetFilter { + fn weigh_multi_assets(&self, weight: Weight) -> Weight { + match self { + 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, weight: Weight) -> Weight { + weight.saturating_mul(self.inner().iter().count() as u64) + } +} + +pub struct BridgeHubWestendXcmWeight(core::marker::PhantomData); +impl XcmWeightInfo for BridgeHubWestendXcmWeight { + fn withdraw_asset(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) + } + 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()) + } + 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(XcmFungibleWeight::::transfer_asset()) + } + fn transfer_reserve_asset( + assets: &MultiAssets, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) + } + fn transact( + _origin_type: &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(XcmFungibleWeight::::deposit_asset()) + } + fn deposit_reserve_asset( + assets: &MultiAssetFilter, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) + } + fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { + Weight::MAX + } + fn initiate_reserve_withdraw( + assets: &MultiAssetFilter, + _reserve: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) + } + fn initiate_teleport( + assets: &MultiAssetFilter, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::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 { + Weight::MAX + } + fn export_message(_: &NetworkId, _: &Junctions, inner: &Xcm<()>) -> Weight { + let inner_encoded_len = inner.encode().len() as u32; + XcmGeneric::::export_message(inner_encoded_len) + } + fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { + Weight::MAX + } + fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { + 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() + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs new file mode 100644 index 00000000000..295abd481d7 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -0,0 +1,208 @@ +// 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-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-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_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)] +#![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: 19_037_000 picoseconds. + Weight::from_parts(19_602_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: `153` + // Estimated: `6196` + // Minimum execution time: 43_115_000 picoseconds. + Weight::from_parts(43_897_000, 6196) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: `System::Account` (r:3 w:3) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn transfer_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `294` + // Estimated: `8799` + // Minimum execution time: 90_267_000 picoseconds. + Weight::from_parts(91_460_000, 8799) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // Storage: `Benchmark::Override` (r:0 w:0) + // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn reserve_asset_deposited() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 60_477_000 picoseconds. + Weight::from_parts(61_314_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + pub fn receive_teleported_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_996_000 picoseconds. + Weight::from_parts(3_107_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: `52` + // Estimated: `3593` + // Minimum execution time: 18_907_000 picoseconds. + Weight::from_parts(19_475_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn deposit_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `193` + // Estimated: `6196` + // Minimum execution time: 59_143_000 picoseconds. + Weight::from_parts(60_316_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_teleport() -> Weight { + // Proof Size summary in bytes: + // Measured: `141` + // Estimated: `3606` + // Minimum execution time: 44_459_000 picoseconds. + Weight::from_parts(45_365_000, 3606) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs new file mode 100644 index 00000000000..7c686190208 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,377 @@ +// 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-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-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_benchmarks::generic +// --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)] +#![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: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_holding() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 62_732_000 picoseconds. + Weight::from_parts(64_581_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + pub fn buy_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_987_000 picoseconds. + Weight::from_parts(2_107_000, 0) + } + // Storage: `PolkadotXcm::Queries` (r:1 w:0) + // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn query_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3568` + // Minimum execution time: 8_098_000 picoseconds. + Weight::from_parts(8_564_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: 8_539_000 picoseconds. + Weight::from_parts(9_085_000, 0) + } + pub fn refund_surplus() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_205_000 picoseconds. + Weight::from_parts(2_369_000, 0) + } + pub fn set_error_handler() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_828_000 picoseconds. + Weight::from_parts(1_994_000, 0) + } + pub fn set_appendix() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(1_946_000, 0) + } + pub fn clear_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_842_000 picoseconds. + Weight::from_parts(1_949_000, 0) + } + pub fn descend_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_460_000 picoseconds. + Weight::from_parts(2_593_000, 0) + } + pub fn clear_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(2_003_000, 0) + } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 56_813_000 picoseconds. + Weight::from_parts(57_728_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // 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: 11_364_000 picoseconds. + Weight::from_parts(11_872_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: 1_821_000 picoseconds. + Weight::from_parts(1_936_000, 0) + } + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // 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: 23_081_000 picoseconds. + Weight::from_parts(23_512_000, 3574) + .saturating_add(T::DbWeight::get().reads(7)) + .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: 3_747_000 picoseconds. + Weight::from_parts(4_068_000, 0) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn burn_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_045_000 picoseconds. + Weight::from_parts(3_208_000, 0) + } + pub fn expect_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_962_000 picoseconds. + Weight::from_parts(2_284_000, 0) + } + pub fn expect_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_951_000 picoseconds. + Weight::from_parts(2_026_000, 0) + } + pub fn expect_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(2_084_000, 0) + } + pub fn expect_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_042_000 picoseconds. + Weight::from_parts(2_145_000, 0) + } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn query_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 61_350_000 picoseconds. + Weight::from_parts(62_440_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + pub fn expect_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_993_000 picoseconds. + Weight::from_parts(5_309_000, 0) + } + // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `6196` + // Minimum execution time: 57_133_000 picoseconds. + Weight::from_parts(58_100_000, 6196) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + pub fn clear_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_899_000 picoseconds. + Weight::from_parts(2_153_000, 0) + } + pub fn set_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_880_000 picoseconds. + Weight::from_parts(1_960_000, 0) + } + pub fn clear_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_825_000 picoseconds. + Weight::from_parts(1_960_000, 0) + } + // 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: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) + // Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) + // Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) + // Proof: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoToWococoMessages::OutboundMessages` (r:0 w:1) + // Proof: `BridgeRococoToWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + pub fn export_message(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `3604` + // Minimum execution time: 28_419_000 picoseconds. + Weight::from_parts(29_387_791, 3604) + // Standard Error: 552 + .saturating_add(Weight::from_parts(316_277, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + pub fn set_fees_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_903_000 picoseconds. + Weight::from_parts(2_023_000, 0) + } + pub fn unpaid_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_963_000 picoseconds. + Weight::from_parts(2_143_000, 0) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs new file mode 100644 index 00000000000..8efc75ed13e --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -0,0 +1,329 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use super::{ + AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + TransactionByteFee, WeightToFee, XcmpQueue, +}; +use crate::bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlash}; +use frame_support::{ + match_types, parameter_types, + traits::{ConstU32, Contains, Equals, Everything, Nothing}, +}; +use frame_system::EnsureRoot; +use pallet_xcm::XcmPassthrough; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + TREASURY_PALLET_ID, +}; +use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use sp_runtime::traits::AccountIdConversion; +use westend_runtime_constants::system_parachain; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, + ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, +}; +use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; + +parameter_types! { + pub const WestendLocation: MultiLocation = MultiLocation::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Westend; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); +} + +/// 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, +); + +/// 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, + // 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): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// 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 + // recognized. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognized. + 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, +); + +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(_) } + }; +} + +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains for SafeCallFilter { + fn contains(call: &RuntimeCall) -> bool { + #[cfg(feature = "runtime-benchmarks")] + { + if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { + return true + } + } + + // Allow to change dedicated storage items (called by governance-like) + match call { + RuntimeCall::System(frame_system::Call::set_storage { items }) + if items.iter().all(|(k, _)| { + k.eq(&DeliveryRewardInBalance::key()) | + k.eq(&RequiredStakeForStakeAndSlash::key()) + }) => + return true, + _ => (), + }; + + matches!( + call, + RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | + 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::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< + Runtime, + crate::bridge_to_rococo_config::BridgeGrandpaRococoInstance, + >::initialize { .. }) + ) + } +} + +pub type Barrier = TrailingSetTopicAsId< + DenyThenTry< + DenyReserveTransferToRelayChain, + ( + // Allow local users to buy weight credit. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + 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 relay treasury pallet + // get free execution. + AllowExplicitUnpaidExecutionFrom<( + ParentOrParentsPlurality, + Equals, + )>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, + ), + >, +>; + +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::BRIDGE_HUB_ID | + system_parachain::COLLECTIVES_ID + )), + } + }; +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); + +/// 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; + type XcmSender = XcmRouter; + type AssetTransactor = CurrencyTransactor; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native + // token where allowed (e.g. with the Relay Chain). + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = WeightInfoBounds< + crate::weights::xcm::BridgeHubWestendXcmWeight, + RuntimeCall, + MaxInstructions, + >; + type Trader = + UsingComponents>; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + XcmFeeToAccount, + >; + type MessageExporter = (crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter,); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; +} + +pub type PriceForParentDelivery = + ExponentialPrice; + +/// Converts a local signed origin into an XCM multilocation. +/// Forms the basis for local origins sending/executing XCMs. +pub type LocalOriginToLocation = SignedToAccountId32; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = WithUniqueTopic<( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +)>; + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parent.into()); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmRouter = XcmRouter; + // We want to disallow users sending (arbitrary) XCMs from this chain. + type SendXcmOrigin = EnsureXcmOrigin; + // We support local origins dispatching XCM executions in principle... + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. + type Weigher = WeightInfoBounds< + crate::weights::xcm::BridgeHubWestendXcmWeight, + 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; +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs new file mode 100644 index 00000000000..babd579f002 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -0,0 +1,285 @@ +// 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 . + +#![cfg(test)] + +use bp_polkadot_core::Signature; +use bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlash}; +use bridge_hub_westend_runtime::{ + bridge_common_config, bridge_to_rococo_config, + xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, + UncheckedExtrinsic, +}; +use bridge_to_rococo_config::{ + BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeParachainRococoInstance, + WithBridgeHubRococoMessageBridge, WithBridgeHubRococoMessagesInstance, + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, +}; +use codec::{Decode, Encode}; +use frame_support::parameter_types; +use frame_system::pallet_prelude::HeaderFor; +use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance}; +use sp_keyring::AccountKeyring::Alice; +use sp_runtime::{ + generic::{Era, SignedPayload}, + AccountId32, +}; +use xcm::latest::prelude::*; + +// Para id of sibling chain used in tests. +pub const SIBLING_PARACHAIN_ID: u32 = 1000; + +parameter_types! { + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); +} + +fn construct_extrinsic( + sender: sp_keyring::AccountKeyring, + call: RuntimeCall, +) -> UncheckedExtrinsic { + let extra: SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(Era::immortal()), + frame_system::CheckNonce::::from(0), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(0), + BridgeRejectObsoleteHeadersAndMessages::default(), + (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), + ); + let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + let signature = payload.using_encoded(|e| sender.sign(e)); + UncheckedExtrinsic::new_signed( + call, + AccountId32::from(sender.public()).into(), + Signature::Sr25519(signature.clone()), + extra, + ) +} + +fn construct_and_apply_extrinsic( + relayer_at_target: sp_keyring::AccountKeyring, + batch: pallet_utility::Call, +) -> sp_runtime::DispatchOutcome { + let batch_call = RuntimeCall::Utility(batch); + let xt = construct_extrinsic(relayer_at_target, batch_call); + let r = Executive::apply_extrinsic(xt); + r.unwrap() +} + +fn executive_init_block(header: &HeaderFor) { + Executive::initialize_block(header) +} + +fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { + bridge_hub_test_utils::CollatorSessionKeys::new( + AccountId::from(Alice), + AccountId::from(Alice), + SessionKeys { aura: AuraId::from(Alice.public()) }, + ) +} + +bridge_hub_test_utils::test_cases::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, + } + }), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID +); + +#[test] +fn initialize_bridge_by_governance_works() { + bridge_hub_test_utils::test_cases::initialize_bridge_by_governance_works::< + Runtime, + BridgeGrandpaRococoInstance, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + Box::new(|call| RuntimeCall::BridgeRococoGrandpa(call).encode()), + ) +} + +#[test] +fn change_delivery_reward_by_governance_works() { + bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< + Runtime, + DeliveryRewardInBalance, + u64, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + Box::new(|call| RuntimeCall::System(call).encode()), + || (DeliveryRewardInBalance::key().to_vec(), DeliveryRewardInBalance::get()), + |old_value| old_value.checked_mul(2).unwrap(), + ) +} + +#[test] +fn change_required_stake_by_governance_works() { + bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< + Runtime, + RequiredStakeForStakeAndSlash, + Balance, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + Box::new(|call| RuntimeCall::System(call).encode()), + || (RequiredStakeForStakeAndSlash::key().to_vec(), RequiredStakeForStakeAndSlash::get()), + |old_value| old_value.checked_mul(2).unwrap(), + ) +} + +#[test] +fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { + bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< + Runtime, + XcmConfig, + WithBridgeHubRococoMessagesInstance, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::BridgeRococoMessages(event)) => Some(event), + _ => None, + } + }), + || ExportMessage { network: Rococo, destination: X1(Parachain(4321)), xcm: Xcm(vec![]) }, + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + Some((WestendLocation::get(), ExistentialDeposit::get()).into()), + // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` + Some((WestendLocation::get(), bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds::get()).into()), + || (), + ) +} + +#[test] +fn message_dispatch_routing_works() { + bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + WithBridgeHubRococoMessagesInstance, + RelayNetwork, + bridge_to_rococo_config::RococoGlobalConsensusNetwork, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + || (), + ) +} + +#[test] +fn relayed_incoming_message_works() { + bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Westend, + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + || (), + ) +} + +#[test] +pub fn complex_relay_extrinsic_works() { + bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + BridgeHubRococoChainId::get(), + Westend, + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + 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_westend::BridgeHubWestendBaseFeeInWnds::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds` value", + estimated, + max_expected + ); +} diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 6cacb5d764a..4e758d3f3e6 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -35,6 +35,7 @@ contracts-rococo-runtime = { path = "../parachains/runtimes/contracts/contracts- bridge-hub-rococo-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-rococo" } bridge-hub-kusama-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-kusama" } bridge-hub-polkadot-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-polkadot" } +bridge-hub-westend-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-westend" } penpal-runtime = { path = "../parachains/runtimes/testing/penpal" } jsonrpsee = { version = "0.16.2", features = ["server"] } parachains-common = { path = "../parachains/common" } @@ -115,6 +116,7 @@ runtime-benchmarks = [ "bridge-hub-kusama-runtime/runtime-benchmarks", "bridge-hub-polkadot-runtime/runtime-benchmarks", "bridge-hub-rococo-runtime/runtime-benchmarks", + "bridge-hub-westend-runtime/runtime-benchmarks", "collectives-polkadot-runtime/runtime-benchmarks", "contracts-rococo-runtime/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", @@ -137,6 +139,7 @@ try-runtime = [ "bridge-hub-kusama-runtime/try-runtime", "bridge-hub-polkadot-runtime/try-runtime", "bridge-hub-rococo-runtime/try-runtime", + "bridge-hub-westend-runtime/try-runtime", "collectives-polkadot-runtime/try-runtime", "contracts-rococo-runtime/try-runtime", "glutton-runtime/try-runtime", diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index ca5583fe2e5..2910d81ee29 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -42,8 +42,10 @@ pub enum BridgeHubRuntimeType { // used by benchmarks PolkadotDevelopment, - // used with kusama runtime Westend, + WestendLocal, + // used by benchmarks + WestendDevelopment, } impl FromStr for BridgeHubRuntimeType { @@ -59,6 +61,8 @@ impl FromStr for BridgeHubRuntimeType { kusama::BRIDGE_HUB_KUSAMA_LOCAL => Ok(BridgeHubRuntimeType::KusamaLocal), kusama::BRIDGE_HUB_KUSAMA_DEVELOPMENT => Ok(BridgeHubRuntimeType::KusamaDevelopment), westend::BRIDGE_HUB_WESTEND => Ok(BridgeHubRuntimeType::Westend), + westend::BRIDGE_HUB_WESTEND_LOCAL => Ok(BridgeHubRuntimeType::WestendLocal), + westend::BRIDGE_HUB_WESTEND_DEVELOPMENT => Ok(BridgeHubRuntimeType::WestendDevelopment), rococo::BRIDGE_HUB_ROCOCO => Ok(BridgeHubRuntimeType::Rococo), rococo::BRIDGE_HUB_ROCOCO_LOCAL => Ok(BridgeHubRuntimeType::RococoLocal), rococo::BRIDGE_HUB_ROCOCO_DEVELOPMENT => Ok(BridgeHubRuntimeType::RococoDevelopment), @@ -82,7 +86,9 @@ impl BridgeHubRuntimeType { BridgeHubRuntimeType::KusamaLocal | BridgeHubRuntimeType::KusamaDevelopment => Ok(Box::new(kusama::BridgeHubChainSpec::from_json_file(path)?)), - BridgeHubRuntimeType::Westend => + BridgeHubRuntimeType::Westend | + BridgeHubRuntimeType::WestendLocal | + BridgeHubRuntimeType::WestendDevelopment => Ok(Box::new(westend::BridgeHubChainSpec::from_json_file(path)?)), BridgeHubRuntimeType::Rococo | BridgeHubRuntimeType::RococoLocal | @@ -131,6 +137,20 @@ impl BridgeHubRuntimeType { Ok(Box::new(westend::BridgeHubChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-westend.json")[..], )?)), + BridgeHubRuntimeType::WestendLocal => Ok(Box::new(westend::local_config( + westend::BRIDGE_HUB_WESTEND_LOCAL, + "Westend BridgeHub Local", + "westend-local", + ParaId::new(1002), + Some("Bob".to_string()), + ))), + BridgeHubRuntimeType::WestendDevelopment => Ok(Box::new(westend::local_config( + westend::BRIDGE_HUB_WESTEND_DEVELOPMENT, + "Westend BridgeHub Development", + "westend-dev", + ParaId::new(1002), + Some("Bob".to_string()), + ))), BridgeHubRuntimeType::Rococo => Ok(Box::new(rococo::BridgeHubChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-rococo.json")[..], @@ -311,20 +331,26 @@ pub mod rococo { owner: bridges_pallet_owner.clone(), ..Default::default() }, + bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { owner: bridges_pallet_owner.clone(), ..Default::default() }, - bridge_wococo_to_rococo_messages: - bridge_hub_rococo_runtime::BridgeWococoToRococoMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() - }, - bridge_rococo_to_wococo_messages: - bridge_hub_rococo_runtime::BridgeRococoToWococoMessagesConfig { - owner: bridges_pallet_owner, - ..Default::default() - }, + bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, } } } @@ -488,13 +514,139 @@ pub mod kusama { } } -/// Sub-module for Westend setup (uses Kusama runtime) +/// Sub-module for Westend setup. pub mod westend { - use crate::chain_spec::bridge_hubs::kusama; + use super::{get_account_id_from_seed, get_collator_keys_from_seed, sr25519, ParaId}; + use crate::chain_spec::{Extensions, SAFE_XCM_VERSION}; + use parachains_common::{AccountId, AuraId}; + use sc_chain_spec::ChainType; + + use super::BridgeHubBalance; pub(crate) const BRIDGE_HUB_WESTEND: &str = "bridge-hub-westend"; - pub type BridgeHubChainSpec = kusama::BridgeHubChainSpec; - pub type RuntimeApi = bridge_hub_kusama_runtime::RuntimeApi; + pub(crate) const BRIDGE_HUB_WESTEND_LOCAL: &str = "bridge-hub-westend-local"; + pub(crate) const BRIDGE_HUB_WESTEND_DEVELOPMENT: &str = "bridge-hub-westend-dev"; + const BRIDGE_HUB_WESTEND_ED: BridgeHubBalance = + parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + + /// Specialized `ChainSpec` for the normal parachain runtime. + pub type BridgeHubChainSpec = + sc_service::GenericChainSpec; + pub type RuntimeApi = bridge_hub_westend_runtime::RuntimeApi; + + pub fn local_config( + id: &str, + chain_name: &str, + relay_chain: &str, + para_id: ParaId, + bridges_pallet_owner_seed: Option, + ) -> BridgeHubChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "WND".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + BridgeHubChainSpec::from_genesis( + // Name + chain_name, + // ID + super::ensure_id(id).expect("invalid id"), + ChainType::Local, + move || { + 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, + bridges_pallet_owner_seed + .as_ref() + .map(|seed| get_account_id_from_seed::(seed)), + ) + }, + Vec::new(), + None, + None, + None, + Some(properties), + Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, + ) + } + + fn genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, + bridges_pallet_owner: Option, + ) -> bridge_hub_westend_runtime::RuntimeGenesisConfig { + bridge_hub_westend_runtime::RuntimeGenesisConfig { + system: bridge_hub_westend_runtime::SystemConfig { + code: bridge_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + ..Default::default() + }, + balances: bridge_hub_westend_runtime::BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + parachain_info: bridge_hub_westend_runtime::ParachainInfoConfig { + parachain_id: id, + ..Default::default() + }, + collator_selection: bridge_hub_westend_runtime::CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: BRIDGE_HUB_WESTEND_ED * 16, + ..Default::default() + }, + session: bridge_hub_westend_runtime::SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + } + } } /// Sub-module for Polkadot setup diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 870e45e1d55..9787465fb0a 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -467,7 +467,9 @@ macro_rules! construct_partials { )?; $code }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend => { + chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => { let $partials = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AuraId>, @@ -650,7 +652,9 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend => { + chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => { runner.async_run(|$config| { let $components = new_partial::( &$config, @@ -976,7 +980,9 @@ pub fn run() -> Result<()> { >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend => + chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | + chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => crate::service::start_generic_aura_node::< chain_spec::bridge_hubs::westend::RuntimeApi, AuraId, diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh new file mode 100755 index 00000000000..ce8480685aa --- /dev/null +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -0,0 +1,368 @@ +#!/bin/bash + +# import common functions +source "$(dirname "$0")"/bridges_common.sh + +# Expected sovereign accounts. +# +# 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(Westend), 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_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!("GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Westend)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusParachainConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X2(GlobalConsensus(Westend), 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_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" +GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT="5He2Qdztyxxa4GoagY6q1jaiLMmKy1gXS7PdZkhfj8ZG9hk5" +GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT="5GUD9X494SnhfBTNReHwhV1599McpyVrAqFY6WnTfVQVYNUM" +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 bp_messages::LaneId; +# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; +# use sp_core::crypto::Ss58Codec; +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# } +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5BhiSGP5hbdsoVGtzi2sQVgpDNToTxLYeQvKoMPEm" +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5BhiSGP5hbdt5EJSapXYbxEv678jyWHEUskCXcjqo" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5BhiSGP5h9Rg8sgUJqoLym3iEaWUiboT8S9AT5xFh" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" + +LANE_ID="00000002" + +function init_ro_wnd() { + ensure_relayer + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + ~/local_bridge_testing/bin/substrate-relay init-bridge rococo-to-bridge-hub-westend \ + --source-host localhost \ + --source-port 9942 \ + --source-version-mode Auto \ + --target-host localhost \ + --target-port 8945 \ + --target-version-mode Auto \ + --target-signer //Bob +} + +function init_wnd_ro() { + ensure_relayer + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + ~/local_bridge_testing/bin/substrate-relay init-bridge westend-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 +} + +function run_relay() { + ensure_relayer + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + ~/local_bridge_testing/bin/substrate-relay relay-headers-and-messages bridge-hub-rococo-bridge-hub-westend \ + --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 \ + --westend-headers-to-bridge-hub-rococo-signer //Bob \ + --westend-parachains-to-bridge-hub-rococo-signer //Bob \ + --bridge-hub-rococo-transactions-mortality 4 \ + --westend-host localhost \ + --westend-port 9945 \ + --westend-version-mode Auto \ + --bridge-hub-westend-host localhost \ + --bridge-hub-westend-port 8945 \ + --bridge-hub-westend-version-mode Auto \ + --bridge-hub-westend-signer //Charlie \ + --rococo-headers-to-bridge-hub-westend-signer //Bob \ + --rococo-parachains-to-bridge-hub-westend-signer //Bob \ + --bridge-hub-westend-transactions-mortality 4 \ + --lane "${LANE_ID}" +} + +case "$1" in + run-relay) + init_ro_wnd + init_wnd_ro + run_relay + ;; + init-asset-hub-rococo-local) + ensure_polkadot_js_api + # create foreign assets for native Westend token (governance call on Rococo) + force_create_foreign_asset \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9910" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } }')" \ + "$GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT" \ + 10000000000 \ + true + # drip SA which holds reserves + transfer_balance \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_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_00000002_bhwd_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_00000002_bhwd_BridgedChain" \ + $((1000000000 + 2000000000000)) + ;; + init-asset-hub-westend-local) + ensure_polkadot_js_api + # create foreign assets for native Rococo token (governance call on Westend) + force_create_foreign_asset \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "$(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" \ + "$GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ + $((1000000000 + 50000000000 * 20)) + # HRMP + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 1002 4 524288 + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1002 1000 4 524288 + ;; + init-bridge-hub-westend-local) + # SA of sibling asset hub pays for the execution + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND" \ + $((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_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_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_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain" \ + $((1000000000 + 2000000000000)) + ;; + reserve-transfer-assets-from-asset-hub-rococo-local) + ensure_polkadot_js_api + # send ROCs to Alice account on AHW + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": 200000000000 } } ] }')" \ + 0 \ + "Unlimited" + ;; + reserve-transfer-assets-from-asset-hub-westend-local) + ensure_polkadot_js_api + # 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" + ;; + claim-rewards-bridge-hub-rococo-local) + ensure_polkadot_js_api + # bhwd -> [62, 68, 77, 64] -> 0x62687764 + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x62687764" \ + "ThisChain" + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x62687764" \ + "BridgedChain" + ;; + claim-rewards-bridge-hub-westend-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 + pkill -f parachain + ;; + import) + # to avoid trigger anything here + ;; + *) + echo "A command is require. Supported commands for: + Local (zombienet) run: + - run-relay + - init-asset-hub-rococo-local + - init-bridge-hub-rococo-local + - init-asset-hub-westend-local + - init-bridge-hub-westend-local + - reserve-transfer-assets-from-asset-hub-rococo-local + - reserve-transfer-assets-from-asset-hub-westend-local + - claim-rewards-bridge-hub-rococo-local + - claim-rewards-bridge-hub-westend-local"; + exit 1 + ;; +esac diff --git a/cumulus/scripts/bridges_rococo_wococo.sh b/cumulus/scripts/bridges_rococo_wococo.sh index 4211a37226d..dd7c7062a3b 100755 --- a/cumulus/scripts/bridges_rococo_wococo.sh +++ b/cumulus/scripts/bridges_rococo_wococo.sh @@ -69,6 +69,8 @@ ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZ # Generated by: #[test] #fn generate_sovereign_accounts_for_rewards() { +# use bp_messages::LaneId; +# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; # use sp_core::crypto::Ss58Codec; # # // SS58=42 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 d83cf13607d..a117942858e 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml @@ -42,7 +42,7 @@ cumulus_based = true args = [ "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", "--force-authoring", - "--", "--port 41333", "--rpc-port 48933", "--ws-port 48943" + "--", "--rpc-port 48933" ] # run bob as parachain collator @@ -55,7 +55,7 @@ cumulus_based = true args = [ "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", "--force-authoring", - "--", "--port 41334", "--rpc-port 48934", "--ws-port 48944" + "--", "--rpc-port 48934" ] [[parachains]] @@ -70,7 +70,7 @@ cumulus_based = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--port 51333", "--rpc-port 58933", "--ws-port 58943" + "--", "--rpc-port 58933" ] [[parachains.collators]] @@ -78,7 +78,7 @@ cumulus_based = true 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" + "--", "--rpc-port 58833" ] #[[hrmp_channels]] diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml new file mode 100644 index 00000000000..4c345d3825c --- /dev/null +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml @@ -0,0 +1,94 @@ +[settings] +node_spawn_timeout = 240 + +[relaychain] +default_command = "{{POLKADOT_BINARY_PATH}}" +default_args = [ "-lparachain=debug,xcm=trace" ] +chain = "westend-local" + + [[relaychain.nodes]] + name = "alice-westend-validator" + validator = true + rpc_port = 9935 + ws_port = 9945 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "bob-westend-validator" + validator = true + rpc_port = 9936 + ws_port = 9946 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "charlie-westend-validator" + validator = true + rpc_port = 9937 + ws_port = 9947 + balance = 2000000000000 + +[[parachains]] +id = 1002 +chain = "bridge-hub-westend-local" +cumulus_based = true + + # run alice as parachain collator + [[parachains.collators]] + name = "bridge-hub-westend-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", + "--force-authoring", + "--", "--rpc-port 48935" + ] + + # run bob as parachain collator + [[parachains.collators]] + name = "bridge-hub-westend-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", + "--force-authoring", + "--", "--rpc-port 48936" + ] + +[[parachains]] +id = 1000 +chain = "asset-hub-westend-local" +cumulus_based = true + + [[parachains.collators]] + name = "asset-hub-westend-collator1" + rpc_port = 9011 + ws_port = 9010 + command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", + "--", "--rpc-port 38933" + ] + + [[parachains.collators]] + name = "asset-hub-westend-collator2" + command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", + "--", "--rpc-port 38833" + ] + +#[[hrmp_channels]] +#sender = 1000 +#recipient = 1002 +#max_capacity = 4 +#max_message_size = 524288 +# +#[[hrmp_channels]] +#sender = 1002 +#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 76b368cfa28..ae5cf641f66 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml @@ -42,7 +42,7 @@ cumulus_based = true args = [ "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", "--force-authoring", - "--", "--port 41335", "--rpc-port 48935", "--ws-port 48945" + "--", "--port 41335", "--rpc-port 48935" ] # run bob as parachain collator @@ -55,7 +55,7 @@ cumulus_based = true args = [ "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", "--force-authoring", - "--", "--port 41336", "--rpc-port 48936", "--ws-port 48946" + "--", "--port 41336", "--rpc-port 48936" ] [[parachains]] @@ -70,7 +70,7 @@ cumulus_based = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--port 31333", "--rpc-port 38933", "--ws-port 38943" + "--", "--port 31333", "--rpc-port 38933" ] [[parachains.collators]] @@ -78,7 +78,7 @@ cumulus_based = true 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" + "--", "--port 31433", "--rpc-port 38833" ] #[[hrmp_channels]] -- GitLab From fe9435db2fda7c9e2f4e29521564c72cac38f59b Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 2 Nov 2023 07:05:56 +0100 Subject: [PATCH 420/633] Fix for failed pipeline `test-doc` (#2127) Fix for failed pipeline `test-doc`: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4174859 I just wonder how could have other PR been merged after this was merged: https://github.com/paritytech/polkadot-sdk/pull/1714/files#diff-1bde7bb2be0165cbe6db391e10a4a0b2f333348681373a86a0f8502d14d20d32R56 --- substrate/frame/support/src/storage/types/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 81a3dd270d8..75988220e3f 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -53,7 +53,7 @@ use sp_std::prelude::*; /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] /// pub type Foo = StorageMap< -/// _ +/// _, /// Blake2_128Concat, /// u32, /// u32, -- GitLab From 9ff5088115d2ecba15e013b96331b540ba4c3b32 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 2 Nov 2023 09:54:13 +0100 Subject: [PATCH 421/633] Bandersnatch dependency update (#2114) Closes https://github.com/paritytech/polkadot-sdk/issues/2013 --- .config/zepter.yaml | 2 - Cargo.lock | 879 ++++++++++-------- substrate/primitives/core/Cargo.toml | 4 +- .../primitives/crypto/ec-utils/Cargo.toml | 1 + 4 files changed, 510 insertions(+), 376 deletions(-) diff --git a/.config/zepter.yaml b/.config/zepter.yaml index 2bdc106b2da..33bf3a044cf 100644 --- a/.config/zepter.yaml +++ b/.config/zepter.yaml @@ -15,8 +15,6 @@ workflows: '--features=try-runtime,runtime-benchmarks,std', # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. '--left-side-feature-missing=ignore', - # Enabling this feature somehow pulls in two versions of `sp-runtime-interface` and makes it impossible to build that crate with `cargo b -p sp-runtime-interface`. We therefore disable it for now. - '--ignore-missing-propagate=sp-core/std:bandersnatch_vrfs/std', # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. '--left-side-outside-workspace=ignore', # Some features imply that they activate a specific dependency as non-optional. Otherwise the default behaviour with a `?` is used. diff --git a/Cargo.lock b/Cargo.lock index dc972af8714..99062a1eecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -544,7 +544,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ec", "ark-ff", @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ff", "ark-serialize", @@ -791,8 +791,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "sp-weights", @@ -860,8 +860,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "sp-weights", @@ -965,8 +965,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "sp-weights", @@ -1074,8 +1074,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -1114,7 +1114,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -1138,7 +1138,7 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1339,8 +1339,8 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" -version = "0.0.1" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +version = "0.0.3" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1355,6 +1355,8 @@ dependencies = [ "rand_core 0.6.4", "ring 0.1.0", "sha2 0.10.7", + "sp-ark-bls12-381", + "sp-ark-ed-on-bls12-381-bandersnatch", "zeroize", ] @@ -1717,7 +1719,7 @@ dependencies = [ "frame-system", "polkadot-primitives", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1730,7 +1732,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1743,7 +1745,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1756,7 +1758,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1769,7 +1771,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1782,7 +1784,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1801,7 +1803,7 @@ dependencies = [ "sp-consensus-grandpa", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1813,7 +1815,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1829,7 +1831,7 @@ dependencies = [ "scale-info", "serde", "sp-core", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1845,7 +1847,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1857,7 +1859,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1874,7 +1876,7 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1892,7 +1894,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1907,7 +1909,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1919,7 +1921,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1940,7 +1942,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", "trie-db", ] @@ -1960,7 +1962,7 @@ dependencies = [ "sp-consensus-grandpa", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -1973,7 +1975,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1986,7 +1988,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -2051,8 +2053,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2114,8 +2116,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2222,8 +2224,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2274,7 +2276,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -2350,8 +2352,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2392,7 +2394,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", "staging-xcm", "staging-xcm-builder", @@ -2900,8 +2902,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -3110,8 +3112,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -3560,7 +3562,7 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-runtime", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "tracing", ] @@ -3631,7 +3633,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "sp-trie", "substrate-prometheus-endpoint", "tracing", @@ -3782,7 +3784,7 @@ dependencies = [ "sp-application-crypto", "sp-consensus-aura", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3798,7 +3800,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version", "staging-xcm", ] @@ -3827,14 +3829,14 @@ dependencies = [ "sc-client-api", "scale-info", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-inherents", "sp-io", "sp-keyring", "sp-runtime", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-trie", "sp-version", "staging-xcm", @@ -3861,7 +3863,7 @@ dependencies = [ "pallet-session", "parity-scale-codec", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3876,7 +3878,7 @@ dependencies = [ "polkadot-primitives", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3890,7 +3892,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -3914,7 +3916,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -3931,7 +3933,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -3945,7 +3947,7 @@ dependencies = [ "sp-api", "sp-consensus-aura", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3959,7 +3961,7 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", "staging-xcm", ] @@ -3980,8 +3982,8 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-trie", "tracing", ] @@ -3994,7 +3996,7 @@ dependencies = [ "futures", "parity-scale-codec", "sp-inherents", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -4011,7 +4013,7 @@ dependencies = [ "polkadot-runtime-parachains", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -4125,7 +4127,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", - "sp-storage", + "sp-storage 13.0.0", "thiserror", "tokio", "tokio-util", @@ -4173,7 +4175,7 @@ dependencies = [ "polkadot-primitives", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -4202,7 +4204,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", "substrate-wasm-builder", @@ -4275,7 +4277,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-test-client", "substrate-test-utils", "tempfile", @@ -4703,7 +4705,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ec", "ark-ff", @@ -5411,7 +5413,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", ] @@ -5437,9 +5439,9 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-runtime-interface", - "sp-std", - "sp-storage", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", "static_assertions", ] @@ -5477,15 +5479,15 @@ dependencies = [ "sp-blockchain", "sp-core", "sp-database", - "sp-externalities", + "sp-externalities 0.19.0", "sp-inherents", "sp-io", "sp-keystore", "sp-runtime", "sp-state-machine", - "sp-storage", + "sp-storage 13.0.0", "sp-trie", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "thiserror", "thousands", ] @@ -5501,7 +5503,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -5535,7 +5537,7 @@ dependencies = [ "sp-io", "sp-npos-elections", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -5572,8 +5574,8 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-version", ] @@ -5603,7 +5605,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "spinners", "substrate-rpc-client", "tokio", @@ -5638,7 +5640,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", - "sp-debug-derive", + "sp-debug-derive 8.0.0", "sp-genesis-builder", "sp-inherents", "sp-io", @@ -5646,8 +5648,8 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-weights", "static_assertions", "tt-call", @@ -5713,7 +5715,7 @@ dependencies = [ "sp-metadata-ir", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-version", "static_assertions", "trybuild", @@ -5765,10 +5767,10 @@ dependencies = [ "scale-info", "serde", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version", "sp-weights", "substrate-test-runtime-client", @@ -5784,10 +5786,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version", ] @@ -5807,7 +5809,7 @@ dependencies = [ "parity-scale-codec", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6133,8 +6135,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -7149,8 +7151,8 @@ dependencies = [ "sp-session", "sp-staking", "sp-statement-store", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "static_assertions", @@ -8263,7 +8265,7 @@ dependencies = [ "sp-core", "sp-mmr-primitives", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-test-runtime-client", "tokio", ] @@ -8573,7 +8575,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "sp-trie", "tempfile", ] @@ -8715,8 +8717,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "substrate-wasm-builder", @@ -9061,7 +9063,7 @@ dependencies = [ "sp-core-hashing", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9081,7 +9083,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9099,8 +9101,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", ] [[package]] @@ -9116,7 +9118,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9137,8 +9139,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", ] [[package]] @@ -9155,7 +9157,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9170,7 +9172,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9188,7 +9190,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9205,7 +9207,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9220,7 +9222,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9248,7 +9250,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9268,8 +9270,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -9295,9 +9297,9 @@ dependencies = [ "pallet-staking", "sp-core", "sp-runtime", - "sp-std", - "sp-storage", - "sp-tracing", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -9315,7 +9317,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9343,7 +9345,7 @@ dependencies = [ "sp-session", "sp-staking", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9368,7 +9370,7 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9386,7 +9388,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9407,7 +9409,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -9429,7 +9431,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9451,7 +9453,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -9474,7 +9476,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9491,7 +9493,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9510,7 +9512,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9534,8 +9536,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -9551,7 +9553,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9566,7 +9568,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9602,7 +9604,7 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "wasm-instrument 0.4.0", "wasmi", "wat", @@ -9616,7 +9618,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", ] @@ -9645,7 +9647,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9662,7 +9664,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9676,7 +9678,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9696,7 +9698,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9712,7 +9714,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9737,8 +9739,8 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -9761,8 +9763,8 @@ dependencies = [ "sp-io", "sp-npos-elections", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "strum", ] @@ -9776,7 +9778,7 @@ dependencies = [ "parity-scale-codec", "sp-npos-elections", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9795,8 +9797,8 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "substrate-test-utils", ] @@ -9814,7 +9816,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9840,7 +9842,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9857,7 +9859,7 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9872,7 +9874,7 @@ dependencies = [ "scale-info", "sp-core", "sp-io", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9908,8 +9910,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "substrate-test-utils", ] @@ -9928,7 +9930,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9958,7 +9960,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9975,7 +9977,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9995,7 +9997,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10012,7 +10014,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10027,7 +10029,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10044,7 +10046,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10060,7 +10062,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10080,8 +10082,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-weights", ] @@ -10101,7 +10103,7 @@ dependencies = [ "sp-io", "sp-mixnet", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10121,7 +10123,7 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10137,7 +10139,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10156,7 +10158,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10175,7 +10177,7 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10199,7 +10201,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10216,7 +10218,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10231,7 +10233,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10248,8 +10250,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -10271,9 +10273,9 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10288,7 +10290,7 @@ dependencies = [ "rand 0.8.5", "sp-io", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", ] [[package]] @@ -10298,7 +10300,7 @@ dependencies = [ "pallet-nomination-pools", "parity-scale-codec", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10321,8 +10323,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -10340,7 +10342,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10367,7 +10369,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10384,7 +10386,7 @@ dependencies = [ "sp-io", "sp-metadata-ir", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10427,7 +10429,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10444,7 +10446,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10461,7 +10463,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10477,7 +10479,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10499,7 +10501,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10515,7 +10517,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10536,7 +10538,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10550,7 +10552,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10569,7 +10571,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10586,7 +10588,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10604,7 +10606,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", "substrate-test-utils", ] @@ -10621,7 +10623,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10641,7 +10643,7 @@ dependencies = [ "sp-session", "sp-staking", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -10665,7 +10667,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10685,7 +10687,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10713,8 +10715,8 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "substrate-test-utils", ] @@ -10763,8 +10765,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "substrate-state-trie-migration-rpc", "thousands", "tokio", @@ -10786,7 +10788,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-statement-store", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10802,7 +10804,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10817,7 +10819,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10835,8 +10837,8 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-timestamp", ] @@ -10856,8 +10858,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", ] [[package]] @@ -10874,7 +10876,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10920,7 +10922,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-transaction-storage-proof", ] @@ -10941,7 +10943,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10959,7 +10961,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10976,7 +10978,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10995,7 +10997,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -11012,7 +11014,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -11030,7 +11032,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -11051,7 +11053,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -11075,8 +11077,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -11096,7 +11098,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", ] @@ -11204,7 +11206,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -11239,7 +11241,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -11273,8 +11275,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -11526,8 +11528,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -11794,7 +11796,7 @@ dependencies = [ "sp-core", "sp-keyring", "sp-keystore", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing-gum", ] @@ -11895,7 +11897,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -11926,7 +11928,7 @@ dependencies = [ "sp-application-crypto", "sp-keyring", "sp-keystore", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing-gum", ] @@ -11969,7 +11971,7 @@ dependencies = [ "sp-core", "sp-keyring", "sp-keystore", - "sp-tracing", + "sp-tracing 10.0.0", "tracing-gum", ] @@ -12113,7 +12115,7 @@ dependencies = [ "sp-core", "sp-keyring", "sp-keystore", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing-gum", ] @@ -12222,7 +12224,7 @@ dependencies = [ "sp-core", "sp-keyring", "sp-keystore", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing-gum", ] @@ -12319,7 +12321,7 @@ dependencies = [ "slotmap", "sp-core", "sp-maybe-compressed-blob", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "tempfile", "test-parachain-adder", "test-parachain-halt", @@ -12368,9 +12370,9 @@ dependencies = [ "sc-executor-wasmtime", "seccompiler", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", - "sp-tracing", + "sp-tracing 10.0.0", "tempfile", "thiserror", "tracing-gum", @@ -12733,7 +12735,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", ] @@ -12759,7 +12761,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -12853,7 +12855,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -12868,8 +12870,8 @@ dependencies = [ "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -12920,8 +12922,8 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-xcm", "staging-xcm-executor", "static_assertions", @@ -13038,7 +13040,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-state-machine", - "sp-storage", + "sp-storage 13.0.0", "sp-timestamp", "sp-transaction-pool", "sp-version", @@ -13081,7 +13083,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-staking", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing-gum", ] @@ -13209,7 +13211,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-trie", "sp-version", @@ -14068,7 +14070,7 @@ dependencies = [ "log", "pallet-bags-list-remote-tests", "sp-core", - "sp-tracing", + "sp-tracing 10.0.0", "tokio", "westend-runtime", "westend-runtime-constants", @@ -14240,7 +14242,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -14338,9 +14340,9 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", - "sp-storage", - "sp-tracing", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", "sp-transaction-pool", "sp-trie", "sp-version", @@ -14671,7 +14673,7 @@ version = "4.1.0-dev" dependencies = [ "log", "sp-core", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "thiserror", ] @@ -14699,7 +14701,7 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", @@ -14810,7 +14812,7 @@ dependencies = [ "sp-keystore", "sp-panic-handler", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "sp-version", "tempfile", "thiserror", @@ -14834,11 +14836,11 @@ dependencies = [ "sp-consensus", "sp-core", "sp-database", - "sp-externalities", + "sp-externalities 0.19.0", "sp-runtime", "sp-state-machine", "sp-statement-store", - "sp-storage", + "sp-storage 13.0.0", "sp-test-primitives", "sp-trie", "substrate-prometheus-endpoint", @@ -14873,7 +14875,7 @@ dependencies = [ "sp-database", "sp-runtime", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "sp-trie", "substrate-test-runtime-client", "tempfile", @@ -14934,7 +14936,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", @@ -14976,7 +14978,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", @@ -15044,7 +15046,7 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", @@ -15127,7 +15129,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", @@ -15263,17 +15265,17 @@ dependencies = [ "schnellru", "sp-api", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-runtime", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "sp-trie", "sp-version", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "substrate-test-runtime", "tempfile", "tracing", @@ -15287,7 +15289,7 @@ version = "0.10.0-dev" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "thiserror", "wasm-instrument 0.3.0", ] @@ -15309,8 +15311,8 @@ dependencies = [ "sc-executor-common", "sc-runtime-test", "sp-io", - "sp-runtime-interface", - "sp-wasm-interface", + "sp-runtime-interface 17.0.0", + "sp-wasm-interface 14.0.0", "tempfile", "wasmtime", "wat", @@ -15411,7 +15413,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-test-primitives", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime", "substrate-test-runtime-client", @@ -15559,7 +15561,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-test-primitives", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", @@ -15591,7 +15593,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-test-runtime", "substrate-test-runtime-client", "tokio", @@ -15645,11 +15647,11 @@ dependencies = [ "sp-api", "sp-consensus", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keystore", "sp-offchain", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-test-runtime-client", "threadpool", "tokio", @@ -15780,8 +15782,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-runtime-interface", - "sp-std", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", "substrate-wasm-builder", ] @@ -15829,12 +15831,12 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keystore", "sp-runtime", "sp-session", "sp-state-machine", - "sp-storage", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", @@ -15877,8 +15879,8 @@ dependencies = [ "sp-io", "sp-runtime", "sp-state-machine", - "sp-storage", - "sp-tracing", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", "sp-trie", "substrate-test-runtime", "substrate-test-runtime-client", @@ -15963,7 +15965,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -16006,7 +16008,7 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing", "tracing-log", @@ -16047,7 +16049,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "sp-transaction-pool", "substrate-prometheus-endpoint", "substrate-test-runtime", @@ -16326,7 +16328,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -16574,7 +16576,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", + "sp-std 8.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -16676,7 +16678,7 @@ dependencies = [ "parity-scale-codec", "paste", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -16871,11 +16873,11 @@ dependencies = [ "scale-info", "sp-api-proc-macro", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-metadata-ir", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-test-primitives", "sp-trie", "sp-version", @@ -16912,7 +16914,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "sp-version", "static_assertions", "substrate-test-runtime-client", @@ -16928,7 +16930,7 @@ dependencies = [ "serde", "sp-core", "sp-io", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -16955,7 +16957,7 @@ dependencies = [ "scale-info", "serde", "sp-core", - "sp-std", + "sp-std 8.0.0", "static_assertions", ] @@ -16970,6 +16972,24 @@ dependencies = [ "sp-arithmetic", ] +[[package]] +name = "sp-ark-bls12-381" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-bls12-381-ext", + "sp-crypto-ec-utils 0.4.1 (git+https://github.com/paritytech/polkadot-sdk)", +] + +[[package]] +name = "sp-ark-ed-on-bls12-381-bandersnatch" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-ed-on-bls12-381-bandersnatch-ext", + "sp-crypto-ec-utils 0.4.1 (git+https://github.com/paritytech/polkadot-sdk)", +] + [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" @@ -16979,7 +16999,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -16989,7 +17009,7 @@ dependencies = [ "sp-api", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17036,7 +17056,7 @@ dependencies = [ "sp-consensus-slots", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -17054,7 +17074,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -17073,7 +17093,7 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "strum", "w3f-bls", ] @@ -17092,7 +17112,7 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17103,7 +17123,7 @@ dependencies = [ "sp-api", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17118,7 +17138,7 @@ dependencies = [ "sp-consensus-slots", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17128,7 +17148,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -17169,11 +17189,11 @@ dependencies = [ "serde_json", "sp-core-hashing", "sp-core-hashing-proc-macro", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", + "sp-debug-derive 8.0.0", + "sp-externalities 0.19.0", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", "ss58-registry", "substrate-bip39", "thiserror", @@ -17219,8 +17239,29 @@ dependencies = [ "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", "ark-scale", - "sp-runtime-interface", - "sp-std", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", +] + +[[package]] +name = "sp-crypto-ec-utils" +version = "0.4.1" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "ark-bls12-377", + "ark-bls12-377-ext", + "ark-bls12-381", + "ark-bls12-381-ext", + "ark-bw6-761", + "ark-bw6-761-ext", + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "ark-scale", + "sp-runtime-interface 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -17240,14 +17281,35 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "sp-debug-derive" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "sp-externalities" version = "0.19.0" dependencies = [ "environmental", "parity-scale-codec", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", +] + +[[package]] +name = "sp-externalities" +version = "0.19.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 13.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -17257,7 +17319,7 @@ dependencies = [ "serde_json", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17270,7 +17332,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", ] @@ -17286,12 +17348,12 @@ dependencies = [ "rustversion", "secp256k1", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keystore", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-trie", "tracing", "tracing-core", @@ -17316,7 +17378,7 @@ dependencies = [ "rand 0.7.3", "rand_chacha 0.2.2", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "thiserror", ] @@ -17335,7 +17397,7 @@ dependencies = [ "frame-metadata", "parity-scale-codec", "scale-info", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17346,7 +17408,7 @@ dependencies = [ "scale-info", "sp-api", "sp-application-crypto", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17361,9 +17423,9 @@ dependencies = [ "serde", "sp-api", "sp-core", - "sp-debug-derive", + "sp-debug-derive 8.0.0", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", ] @@ -17378,7 +17440,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "substrate-test-utils", ] @@ -17441,8 +17503,8 @@ dependencies = [ "sp-core", "sp-io", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-weights", "substrate-test-runtime-client", "zstd 0.12.4", @@ -17458,22 +17520,52 @@ dependencies = [ "primitive-types", "rustversion", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", - "sp-runtime-interface-proc-macro", + "sp-runtime-interface-proc-macro 11.0.0", "sp-runtime-interface-test-wasm", "sp-state-machine", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-wasm-interface", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", + "sp-wasm-interface 14.0.0", "static_assertions", "trybuild", ] +[[package]] +name = "sp-runtime-interface" +version = "17.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities 0.19.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-runtime-interface-proc-macro 11.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 13.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-tracing 10.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-wasm-interface 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "11.0.0" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" dependencies = [ "Inflector", "proc-macro-crate", @@ -17490,7 +17582,7 @@ dependencies = [ "sc-executor-common", "sp-io", "sp-runtime", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-runtime-interface-test-wasm", "sp-runtime-interface-test-wasm-deprecated", "sp-state-machine", @@ -17505,8 +17597,8 @@ dependencies = [ "bytes", "sp-core", "sp-io", - "sp-runtime-interface", - "sp-std", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", "substrate-wasm-builder", ] @@ -17516,7 +17608,7 @@ version = "2.0.0" dependencies = [ "sp-core", "sp-io", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "substrate-wasm-builder", ] @@ -17531,7 +17623,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17544,7 +17636,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17561,10 +17653,10 @@ dependencies = [ "rand 0.8.5", "smallvec", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-panic-handler", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", "thiserror", "tracing", @@ -17586,10 +17678,10 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-runtime", - "sp-runtime-interface", - "sp-std", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", "thiserror", "x25519-dalek 2.0.0", ] @@ -17598,16 +17690,34 @@ dependencies = [ name = "sp-std" version = "8.0.0" +[[package]] +name = "sp-std" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" + +[[package]] +name = "sp-storage" +version = "13.0.0" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive 8.0.0", + "sp-std 8.0.0", +] + [[package]] name = "sp-storage" version = "13.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" dependencies = [ "impl-serde", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -17620,7 +17730,7 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -17631,7 +17741,7 @@ dependencies = [ "parity-scale-codec", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", ] @@ -17640,7 +17750,19 @@ name = "sp-tracing" version = "10.0.0" dependencies = [ "parity-scale-codec", - "sp-std", + "sp-std 8.0.0", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-tracing" +version = "10.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "tracing", "tracing-core", "tracing-subscriber", @@ -17664,7 +17786,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -17687,7 +17809,7 @@ dependencies = [ "schnellru", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", "tracing", "trie-bench", @@ -17707,7 +17829,7 @@ dependencies = [ "serde", "sp-core-hashing-proc-macro", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version-proc-macro", "thiserror", ] @@ -17731,7 +17853,20 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std", + "sp-std 8.0.0", + "wasmtime", +] + +[[package]] +name = "sp-wasm-interface" +version = "14.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "wasmtime", ] @@ -17745,8 +17880,8 @@ dependencies = [ "smallvec", "sp-arithmetic", "sp-core", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 8.0.0", + "sp-std 8.0.0", ] [[package]] @@ -17904,7 +18039,7 @@ dependencies = [ "sp-runtime", "sp-statement-store", "sp-timestamp", - "sp-tracing", + "sp-tracing 10.0.0", "sp-transaction-storage-proof", "staging-node-executor", "staging-node-inspect", @@ -17946,13 +18081,13 @@ dependencies = [ "sp-application-crypto", "sp-consensus-babe", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keyring", "sp-keystore", "sp-runtime", "sp-state-machine", "sp-statement-store", - "sp-tracing", + "sp-tracing 10.0.0", "sp-trie", "wat", ] @@ -17982,7 +18117,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -18028,7 +18163,7 @@ dependencies = [ "sp-arithmetic", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", "staging-xcm", "staging-xcm-executor", @@ -18048,7 +18183,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", "staging-xcm", ] @@ -18245,7 +18380,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-storage", + "sp-storage 13.0.0", "tokio", ] @@ -18267,7 +18402,7 @@ dependencies = [ "sp-blockchain", "sp-core", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "substrate-test-runtime-client", "tokio", ] @@ -18370,7 +18505,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-grandpa", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-genesis-builder", "sp-inherents", "sp-io", @@ -18379,8 +18514,8 @@ dependencies = [ "sp-runtime", "sp-session", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-transaction-pool", "sp-trie", "sp-version", @@ -18690,7 +18825,7 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-io", - "sp-std", + "sp-std 8.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -18738,7 +18873,7 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-io", - "sp-std", + "sp-std 8.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -19400,8 +19535,8 @@ dependencies = [ "sp-consensus-aura", "sp-consensus-babe", "sp-core", - "sp-debug-derive", - "sp-externalities", + "sp-debug-derive 8.0.0", + "sp-externalities 0.19.0", "sp-inherents", "sp-io", "sp-keystore", @@ -20538,9 +20673,9 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", - "sp-storage", - "sp-tracing", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", "sp-transaction-pool", "sp-version", "staging-xcm", @@ -20930,8 +21065,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-xcm", "staging-xcm-executor", ] @@ -20952,7 +21087,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "sp-state-machine", - "sp-tracing", + "sp-tracing 10.0.0", "staging-xcm", "staging-xcm-executor", ] @@ -20978,7 +21113,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-parachains", "sp-io", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -21003,8 +21138,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -21030,7 +21165,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 7f329832efd..9098b6e48ed 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -58,7 +58,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 = "4b09416", default-features = false, optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "cbc342e", default-features = false, optional = true } [dev-dependencies] criterion = "0.4.0" @@ -76,7 +76,7 @@ bench = false default = [ "std" ] std = [ "array-bytes", - "bandersnatch_vrfs?/getrandom", + "bandersnatch_vrfs?/std", "bip39/rand", "bip39/std", "blake2/std", diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 3c84c17a5c2..1484406e7b2 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -37,6 +37,7 @@ std = [ "ark-bw6-761-ext?/std", "ark-bw6-761?/std", "ark-ec?/parallel", + "ark-ec?/std", "ark-ed-on-bls12-377-ext?/std", "ark-ed-on-bls12-377?/std", "ark-ed-on-bls12-381-bandersnatch-ext?/std", -- GitLab From 8ff489875b2f63c825d76c357fdbad6e9c111875 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 2 Nov 2023 10:09:45 +0100 Subject: [PATCH 422/633] Added `bridge-hub-westend-runtime` to the `short-benchmarks` pipeline (#2128) --- .gitlab/pipeline/short-benchmarks.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 6d060077a7c..76c75e815ce 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -84,6 +84,11 @@ short-benchmark-bridge-hub-rococo: variables: RUNTIME_CHAIN: bridge-hub-rococo-dev +short-benchmark-bridge-hub-westend: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: bridge-hub-westend-dev + short-benchmark-collectives-polkadot: <<: *short-bench-cumulus variables: -- GitLab From 10857d0b58698c4d3cb0d8d8ec6cff395ed2258e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Thu, 2 Nov 2023 10:28:52 +0100 Subject: [PATCH 423/633] Make `ExecResult` encodable (#1809) # Description We derive few useful traits on `ErrorOrigin` and `ExecError`, including `codec::Encode` and `codec::Decode`, so that `ExecResult` is en/decodable as well. This is required for a contract mocking feature (already prepared in drink: https://github.com/Cardinal-Cryptography/drink/pull/61). In more detail: `ExecResult` must be passed from runtime extension, through runtime interface, back to the pallet, which requires that it is serializable to bytes in some form (or implements some rare, auxiliary traits). **Impact on runtime size**: Since most of these traits is used directly in the pallet now, compiler should be able to throw it out (and thus we bring no new overhead). However, they are very useful in secondary tools like drink or other testing libraries. # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works (if applicable) --- substrate/frame/contracts/src/exec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 9090aa9cb11..c26d82f7f11 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -100,7 +100,7 @@ impl Key { /// Call or instantiate both called into other contracts and pass through errors happening /// in those to the caller. This enum is for the caller to distinguish whether the error /// happened during the execution of the callee or in the current execution context. -#[cfg_attr(test, derive(Debug, PartialEq))] +#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)] pub enum ErrorOrigin { /// Caller error origin. /// @@ -112,7 +112,7 @@ pub enum ErrorOrigin { } /// Error returned by contract execution. -#[cfg_attr(test, derive(Debug, PartialEq))] +#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)] pub struct ExecError { /// The reason why the execution failed. pub error: DispatchError, -- GitLab From 29b4bd423387c0704d467a49f99444beaa2690eb Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 2 Nov 2023 19:45:24 +0800 Subject: [PATCH 424/633] impl Clone for `MemoryKeystore` (#2131) --- substrate/primitives/keystore/src/testing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 7f5dfd9faa7..08110e8e497 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -32,7 +32,7 @@ use parking_lot::RwLock; use std::{collections::HashMap, sync::Arc}; /// A keystore implementation usable in tests. -#[derive(Default)] +#[derive(Default, Clone)] pub struct MemoryKeystore { /// `KeyTypeId` maps to public keys and public keys map to private keys. keys: Arc, String>>>>, -- GitLab From 7df0417bcdcbc62f8b12b631076cb824bc917f87 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Thu, 2 Nov 2023 16:02:41 +0200 Subject: [PATCH 425/633] XCM MultiAssets: sort after reanchoring (#2129) Fixes https://github.com/paritytech/polkadot-sdk/issues/2123 --- polkadot/xcm/src/v3/multiasset.rs | 42 ++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 9d86fb8deff..454120a1a7b 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -689,12 +689,16 @@ impl MultiAssets { /// Mutate the location of the asset identifier if concrete, giving it the same location /// relative to a `target` context. The local context is provided as `context`. + /// + /// This will also re-sort the inner assets to preserve ordering guarantees. pub fn reanchor( &mut self, target: &MultiLocation, context: InteriorMultiLocation, ) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.reanchor(target, context)) + self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?; + self.0.sort(); + Ok(()) } /// Return a reference to an item at a specific index or `None` if it doesn't exist. @@ -985,6 +989,42 @@ mod tests { assert!(r.is_err()); } + #[test] + fn reanchor_preserves_sorting() { + use super::*; + use alloc::vec; + + let reanchor_context = X1(Parachain(2000)); + let dest = MultiLocation::new(1, Here); + + let asset_1: MultiAsset = + (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into(); + let mut asset_1_reanchored = asset_1.clone(); + assert!(asset_1_reanchored.reanchor(&dest, reanchor_context).is_ok()); + assert_eq!( + asset_1_reanchored, + (MultiLocation::new(0, X3(Parachain(2000), PalletInstance(50), GeneralIndex(1))), 10) + .into() + ); + + let asset_2: MultiAsset = (MultiLocation::new(1, Here), 10).into(); + let mut asset_2_reanchored = asset_2.clone(); + assert!(asset_2_reanchored.reanchor(&dest, reanchor_context).is_ok()); + assert_eq!(asset_2_reanchored, (MultiLocation::new(0, Here), 10).into()); + + let asset_3: MultiAsset = (MultiLocation::new(1, X1(Parachain(1000))), 10).into(); + let mut asset_3_reanchored = asset_3.clone(); + assert!(asset_3_reanchored.reanchor(&dest, reanchor_context).is_ok()); + assert_eq!(asset_3_reanchored, (MultiLocation::new(0, X1(Parachain(1000))), 10).into()); + + let mut assets: MultiAssets = + vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into(); + assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into()); + + assert!(assets.reanchor(&dest, reanchor_context).is_ok()); + assert_eq!(assets, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored].into()); + } + #[test] fn decoding_respects_limit() { use super::*; -- GitLab From e1c033ebe15e6de5ee6a5a81eab2dd213f09d574 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 2 Nov 2023 15:31:38 +0100 Subject: [PATCH 426/633] Use `Message Queue` as DMP and XCMP dispatch queue (#1246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (imported from https://github.com/paritytech/cumulus/pull/2157) ## Changes This MR refactores the XCMP, Parachains System and DMP pallets to use the [MessageQueue](https://github.com/paritytech/substrate/pull/12485) for delayed execution of incoming messages. The DMP pallet is entirely replaced by the MQ and thereby removed. This allows for PoV-bounded execution and resolves a number of issues that stem from the current work-around. All System Parachains adopt this change. The most important changes are in `primitives/core/src/lib.rs`, `parachains/common/src/process_xcm_message.rs`, `pallets/parachain-system/src/lib.rs`, `pallets/xcmp-queue/src/lib.rs` and the runtime configs. ### DMP Queue Pallet The pallet got removed and its logic refactored into parachain-system. Overweight message management can be done directly through the MQ pallet. Final undeployment migrations are provided by `cumulus_pallet_dmp_queue::UndeployDmpQueue` and `DeleteDmpQueue` that can be configured with an aux config trait like: ```rust parameter_types! { pub const DmpQueuePalletName: &'static str = \"DmpQueue\" < CHANGE ME; pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } impl cumulus_pallet_dmp_queue::MigrationConfig for Runtime { type PalletName = DmpQueuePalletName; type DmpHandler = frame_support::traits::EnqueueWithOrigin; type DbWeight = ::DbWeight; } // And adding them to your Migrations tuple: pub type Migrations = ( ... cumulus_pallet_dmp_queue::UndeployDmpQueue, cumulus_pallet_dmp_queue::DeleteDmpQueue, ); ``` ### XCMP Queue pallet Removed all dispatch queue functionality. Incoming XCMP messages are now either: Immediately handled if they are Signals, enqueued into the MQ pallet otherwise. New config items for the XCMP queue pallet: ```rust /// The actual queue implementation that retains the messages for later processing. type XcmpQueue: EnqueueMessage; /// How a XCM over HRMP from a sibling parachain should be processed. type XcmpProcessor: ProcessMessage; /// The maximal number of suspended XCMP channels at the same time. #[pallet::constant] type MaxInboundSuspended: Get; ``` How to configure those: ```rust // Use the MessageQueue pallet to store messages for later processing. The `TransformOrigin` is needed since // the MQ pallet itself operators on `AggregateMessageOrigin` but we want to enqueue `ParaId`s. type XcmpQueue = TransformOrigin; // Process XCMP messages from siblings. This is type-safe to only accept `ParaId`s. They will be dispatched // with origin `Junction::Sibling(…)`. type XcmpProcessor = ProcessFromSibling< ProcessXcmMessage< AggregateMessageOrigin, xcm_executor::XcmExecutor, RuntimeCall, >, >; // Not really important what to choose here. Just something larger than the maximal number of channels. type MaxInboundSuspended = sp_core::ConstU32<1_000>; ``` The `InboundXcmpStatus` storage item was replaced by `InboundXcmpSuspended` since it now only tracks inbound queue suspension and no message indices anymore. Now only sends the most recent channel `Signals`, as all prio ones are out-dated anyway. ### Parachain System pallet For `DMP` messages instead of forwarding them to the `DMP` pallet, it now pushes them to the configured `DmpQueue`. The message processing which was triggered in `set_validation_data` is now being done by the MQ pallet `on_initialize`. XCMP messages are still handed off to the `XcmpMessageHandler` (XCMP-Queue pallet) - no change here. New config items for the parachain system pallet: ```rust /// Queues inbound downward messages for delayed processing. /// /// Analogous to the `XcmpQueue` of the XCMP queue pallet. type DmpQueue: EnqueueMessage; ``` How to configure: ```rust /// Use the MQ pallet to store DMP messages for delayed processing. type DmpQueue = MessageQueue; ``` ## Message Flow The flow of messages on the parachain side. Messages come in from the left via the `Validation Data` and finally end up at the `Xcm Executor` on the right. ![Untitled (1)](https://github.com/paritytech/cumulus/assets/10380170/6cf8b377-88c9-4aed-96df-baace266e04d) ## Further changes - Bumped the default suspension, drop and resume thresholds in `QueueConfigData::default()`. - `XcmpQueue::{suspend_xcm_execution, resume_xcm_execution}` errors when they would be a noop. - Properly validate the `QueueConfigData` before setting it. - Marked weight files as auto-generated so they wont auto-expand in the MR files view. - Move the `hypothetical` asserts to `frame_support` under the name `experimental_hypothetically` Questions: - [ ] What about the ugly `#[cfg(feature = \"runtime-benchmarks\")]` in the runtimes? Not sure how to best fix. Just having them like this makes tests fail that rely on the real message processor when the feature is enabled. - [ ] Need a good weight for `MessageQueueServiceWeight`. The scheduler already takes 80% so I put it to 10% but that is quite low. TODO: - [x] Remove c&p code after https://github.com/paritytech/polkadot/pull/6271 - [x] Use `HandleMessage` once it is public in Substrate - [x] fix `runtime-benchmarks` feature https://github.com/paritytech/polkadot/pull/6966 - [x] Benchmarks - [x] Tests - [ ] Migrate `InboundXcmpStatus` to `InboundXcmpSuspended` - [x] Possibly cleanup Migrations (DMP+XCMP) - [x] optional: create `TransformProcessMessageOrigin` in Substrate and replace `ProcessFromSibling` - [ ] Rerun weights on ref HW --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Liam Aharon Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> --- Cargo.lock | 39 +- cumulus/pallets/dmp-queue/Cargo.toml | 36 +- cumulus/pallets/dmp-queue/src/benchmarking.rs | 108 ++ cumulus/pallets/dmp-queue/src/lib.rs | 1067 ++++------------- cumulus/pallets/dmp-queue/src/migration.rs | 174 ++- cumulus/pallets/dmp-queue/src/mock.rs | 83 ++ cumulus/pallets/dmp-queue/src/tests.rs | 234 ++++ cumulus/pallets/dmp-queue/src/weights.rs | 222 ++++ cumulus/pallets/parachain-system/Cargo.toml | 11 + .../parachain-system/src/benchmarking.rs | 68 ++ cumulus/pallets/parachain-system/src/lib.rs | 83 +- cumulus/pallets/parachain-system/src/mock.rs | 485 ++++++++ cumulus/pallets/parachain-system/src/tests.rs | 702 +++-------- .../pallets/parachain-system/src/weights.rs | 115 ++ cumulus/pallets/xcm/src/lib.rs | 97 +- cumulus/pallets/xcmp-queue/Cargo.toml | 10 +- .../pallets/xcmp-queue/src/benchmarking.rs | 158 ++- cumulus/pallets/xcmp-queue/src/lib.rs | 955 +++++---------- cumulus/pallets/xcmp-queue/src/migration.rs | 108 +- cumulus/pallets/xcmp-queue/src/mock.rs | 119 +- cumulus/pallets/xcmp-queue/src/tests.rs | 685 ++++++++--- cumulus/pallets/xcmp-queue/src/weights.rs | 228 +++- cumulus/parachain-template/node/Cargo.toml | 1 + cumulus/parachain-template/runtime/Cargo.toml | 9 + cumulus/parachain-template/runtime/src/lib.rs | 55 +- cumulus/parachains/common/Cargo.toml | 4 + cumulus/parachains/common/src/lib.rs | 1 + .../parachains/common/src/message_queue.rs | 55 + .../src/tests/reserve_transfer.rs | 412 +++++++ .../src/tests/reserve_transfer.rs | 5 +- .../assets/asset-hub-westend/Cargo.toml | 3 + .../src/tests/reserve_transfer.rs | 5 +- .../asset-hub-westend/src/tests/swap.rs | 4 +- .../asset-hub-westend/src/tests/treasury.rs | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 6 + .../bridge-hub-rococo/src/tests/example.rs | 8 +- .../emulated/common/Cargo.toml | 6 +- .../emulated/common/src/impls.rs | 32 +- .../emulated/common/src/lib.rs | 26 +- .../emulated/common/src/macros.rs | 4 +- .../assets/asset-hub-kusama/Cargo.toml | 7 + .../assets/asset-hub-kusama/src/lib.rs | 67 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../asset-hub-kusama/src/weights/mod.rs | 28 +- .../src/weights/pallet_asset_conversion.rs | 25 +- .../src/weights/pallet_assets_foreign.rs | 25 +- .../src/weights/pallet_assets_local.rs | 25 +- .../src/weights/pallet_assets_pool.rs | 25 +- .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../weights/pallet_nft_fractionalization.rs | 25 +- .../src/weights/pallet_nfts.rs | 25 +- .../src/weights/pallet_proxy.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_uniques.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../asset-hub-kusama/src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 2 +- .../assets/asset-hub-polkadot/Cargo.toml | 6 + .../assets/asset-hub-polkadot/src/lib.rs | 71 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../asset-hub-polkadot/src/weights/mod.rs | 28 +- .../src/weights/pallet_assets_foreign.rs | 25 +- .../src/weights/pallet_assets_local.rs | 25 +- .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../src/weights/pallet_nfts.rs | 25 +- .../src/weights/pallet_proxy.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_uniques.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../asset-hub-polkadot/src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../asset-hub-polkadot/src/xcm_config.rs | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 1 + .../assets/asset-hub-rococo/src/lib.rs | 57 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../asset-hub-rococo/src/weights/mod.rs | 3 + .../src/weights/pallet_message_queue.rs | 179 +++ .../assets/asset-hub-rococo/src/xcm_config.rs | 2 +- .../assets/asset-hub-westend/Cargo.toml | 6 + .../assets/asset-hub-westend/src/lib.rs | 63 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../asset-hub-westend/src/weights/mod.rs | 28 +- .../src/weights/pallet_asset_conversion.rs | 25 +- .../src/weights/pallet_assets_foreign.rs | 25 +- .../src/weights/pallet_assets_local.rs | 25 +- .../src/weights/pallet_assets_pool.rs | 25 +- .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../weights/pallet_nft_fractionalization.rs | 25 +- .../src/weights/pallet_nfts.rs | 25 +- .../src/weights/pallet_proxy.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_uniques.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../asset-hub-westend/src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../asset-hub-westend/src/xcm_config.rs | 2 +- .../runtimes/assets/common/Cargo.toml | 1 + .../runtimes/assets/test-utils/Cargo.toml | 2 - .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 6 + .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 72 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../bridge-hub-kusama/src/weights/mod.rs | 3 + .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../bridge-hub-kusama/src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../bridge-hub-kusama/src/xcm_config.rs | 2 +- .../bridge-hub-polkadot/Cargo.toml | 6 + .../bridge-hub-polkadot/src/lib.rs | 73 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../bridge-hub-polkadot/src/weights/mod.rs | 3 + .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../bridge-hub-polkadot/src/xcm_config.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 + .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 61 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../bridge-hub-rococo/src/weights/mod.rs | 3 + .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_bridge_grandpa.rs | 80 ++ .../pallet_bridge_grandpa_rococo_finality.rs | 25 +- .../pallet_bridge_grandpa_wococo_finality.rs | 25 +- .../src/weights/pallet_bridge_messages.rs | 230 ++++ ...pallet_bridge_messages_rococo_to_wococo.rs | 25 +- ...pallet_bridge_messages_wococo_to_rococo.rs | 25 +- .../src/weights/pallet_bridge_parachains.rs | 112 ++ .../pallet_bridge_parachains_within_rococo.rs | 25 +- .../pallet_bridge_parachains_within_wococo.rs | 25 +- .../src/weights/pallet_bridge_relayers.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../bridge-hub-rococo/src/weights/xcm/mod.rs | 25 +- .../xcm/pallet_xcm_benchmarks_fungible.rs | 25 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 25 +- .../bridge-hub-rococo/src/xcm_config.rs | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 1 + .../bridge-hubs/bridge-hub-westend/src/lib.rs | 53 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../bridge-hub-westend/src/weights/mod.rs | 3 + .../src/weights/pallet_message_queue.rs | 179 +++ .../bridge-hub-westend/src/xcm_config.rs | 2 +- .../bridge-hubs/test-utils/Cargo.toml | 2 - .../bridge-hubs/test-utils/src/test_cases.rs | 5 - .../collectives-polkadot/Cargo.toml | 6 + .../collectives-polkadot/src/lib.rs | 62 +- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 141 ++- .../src/weights/frame_system.rs | 25 +- .../collectives-polkadot/src/weights/mod.rs | 28 +- .../src/weights/pallet_alliance.rs | 25 +- .../src/weights/pallet_balances.rs | 25 +- .../src/weights/pallet_collator_selection.rs | 25 +- .../src/weights/pallet_collective.rs | 25 +- .../src/weights/pallet_collective_content.rs | 25 +- .../pallet_core_fellowship_fellowship_core.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 25 +- .../src/weights/pallet_preimage.rs | 25 +- .../src/weights/pallet_proxy.rs | 25 +- ...ranked_collective_fellowship_collective.rs | 25 +- .../pallet_referenda_fellowship_referenda.rs | 25 +- .../pallet_salary_fellowship_salary.rs | 25 +- .../src/weights/pallet_scheduler.rs | 25 +- .../src/weights/pallet_session.rs | 25 +- .../src/weights/pallet_timestamp.rs | 25 +- .../src/weights/pallet_utility.rs | 25 +- .../src/weights/pallet_xcm.rs | 25 +- .../collectives-polkadot/src/xcm_config.rs | 2 +- .../contracts/contracts-rococo/Cargo.toml | 6 + .../contracts/contracts-rococo/src/lib.rs | 46 +- .../contracts-rococo/src/xcm_config.rs | 24 +- .../glutton/glutton-kusama/Cargo.toml | 8 +- .../glutton/glutton-kusama/src/lib.rs | 32 +- .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/frame_system.rs | 25 +- .../glutton/glutton-kusama/src/weights/mod.rs | 27 +- .../src/weights/pallet_glutton.rs | 25 +- .../src/weights/pallet_message_queue.rs | 179 +++ .../runtimes/starters/seedling/src/lib.rs | 4 +- .../runtimes/starters/shell/Cargo.toml | 3 + .../runtimes/starters/shell/src/lib.rs | 36 +- .../parachains/runtimes/test-utils/Cargo.toml | 2 - .../parachains/runtimes/test-utils/src/lib.rs | 4 +- .../runtimes/test-utils/src/test_cases.rs | 1 - .../runtimes/testing/penpal/Cargo.toml | 6 + .../runtimes/testing/penpal/src/lib.rs | 56 +- .../testing/rococo-parachain/Cargo.toml | 5 + .../testing/rococo-parachain/src/lib.rs | 43 +- cumulus/polkadot-parachain/Cargo.toml | 1 + cumulus/primitives/core/Cargo.toml | 5 + cumulus/primitives/core/src/lib.rs | 39 +- cumulus/primitives/utility/Cargo.toml | 1 + cumulus/test/client/Cargo.toml | 12 + cumulus/test/runtime/Cargo.toml | 2 + cumulus/test/runtime/src/lib.rs | 4 +- cumulus/test/service/Cargo.toml | 2 + cumulus/xcm/xcm-emulator/Cargo.toml | 1 + cumulus/xcm/xcm-emulator/src/lib.rs | 129 +- polkadot/parachain/src/primitives.rs | 2 +- .../runtime/parachains/src/inclusion/mod.rs | 11 +- polkadot/runtime/parachains/src/ump_tests.rs | 4 +- polkadot/xcm/src/double_encoded.rs | 5 + polkadot/xcm/src/v3/mod.rs | 3 + .../xcm-builder/src/process_xcm_message.rs | 1 + prdoc/pr_1246.prdoc | 17 + substrate/frame/message-queue/src/lib.rs | 42 +- substrate/frame/message-queue/src/mock.rs | 8 +- substrate/frame/message-queue/src/tests.rs | 51 +- substrate/frame/safe-mode/Cargo.toml | 1 + substrate/frame/safe-mode/src/tests.rs | 28 +- substrate/frame/support/src/lib.rs | 29 +- substrate/frame/support/src/traits.rs | 3 +- .../frame/support/src/traits/messages.rs | 21 +- substrate/primitives/core/Cargo.toml | 2 +- 277 files changed, 11556 insertions(+), 4685 deletions(-) create mode 100644 cumulus/pallets/dmp-queue/src/benchmarking.rs create mode 100644 cumulus/pallets/dmp-queue/src/mock.rs create mode 100644 cumulus/pallets/dmp-queue/src/tests.rs create mode 100644 cumulus/pallets/dmp-queue/src/weights.rs create mode 100644 cumulus/pallets/parachain-system/src/benchmarking.rs create mode 100644 cumulus/pallets/parachain-system/src/mock.rs create mode 100644 cumulus/pallets/parachain-system/src/weights.rs create mode 100644 cumulus/parachains/common/src/message_queue.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs create mode 100644 prdoc/pr_1246.prdoc diff --git a/Cargo.lock b/Cargo.lock index 99062a1eecc..808a1976e07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,6 +760,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", @@ -832,6 +833,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-nfts", "pallet-nfts-runtime-api", @@ -933,6 +935,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", @@ -993,6 +996,7 @@ dependencies = [ "pallet-asset-rate", "pallet-assets", "pallet-balances", + "pallet-message-queue", "pallet-treasury", "pallet-xcm", "parachains-common", @@ -1043,6 +1047,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", @@ -1091,7 +1096,6 @@ name = "asset-test-utils" version = "1.0.0" dependencies = [ "assets-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -2027,6 +2031,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -2090,6 +2095,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -2137,14 +2143,20 @@ dependencies = [ "cumulus-pallet-dmp-queue", "cumulus-pallet-xcmp-queue", "frame-support", + "frame-system", "integration-tests-common", + "pallet-assets", + "pallet-balances", "pallet-bridge-messages", + "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-parachains", + "sp-core", + "sp-weights", "staging-xcm", "staging-xcm-executor", "xcm-emulator", @@ -2196,6 +2208,7 @@ dependencies = [ "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -2251,7 +2264,6 @@ dependencies = [ "bp-runtime", "bp-test-utils", "bridge-runtime-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "frame-benchmarking", @@ -2325,6 +2337,7 @@ dependencies = [ "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-collator-selection", + "pallet-message-queue", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -2871,6 +2884,7 @@ dependencies = [ "pallet-collective", "pallet-collective-content", "pallet-core-fellowship", + "pallet-message-queue", "pallet-multisig", "pallet-preimage", "pallet-proxy", @@ -3087,6 +3101,7 @@ dependencies = [ "pallet-contracts", "pallet-contracts-primitives", "pallet-insecure-randomness-collective-flip", + "pallet-message-queue", "pallet-multisig", "pallet-session", "pallet-sudo", @@ -3792,6 +3807,7 @@ name = "cumulus-pallet-dmp-queue" version = "0.1.0" dependencies = [ "cumulus-primitives-core", + "frame-benchmarking", "frame-support", "frame-system", "log", @@ -3801,7 +3817,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std 8.0.0", - "sp-version", + "sp-tracing 10.0.0", "staging-xcm", ] @@ -3817,15 +3833,18 @@ dependencies = [ "cumulus-test-client", "cumulus-test-relay-sproof-builder", "environmental", + "frame-benchmarking", "frame-support", "frame-system", "hex-literal", "impl-trait-for-tuples", "lazy_static", "log", + "pallet-message-queue", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-parachains", + "rand 0.8.5", "sc-client-api", "scale-info", "sp-core", @@ -3900,6 +3919,7 @@ dependencies = [ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" dependencies = [ + "bounded-collections", "bp-xcm-bridge-hub-router", "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -3908,10 +3928,10 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-message-queue", "parity-scale-codec", "polkadot-runtime-common", "polkadot-runtime-parachains", - "rand_chacha 0.3.1", "scale-info", "sp-core", "sp-io", @@ -4191,6 +4211,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "pallet-balances", "pallet-glutton", + "pallet-message-queue", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -6121,6 +6142,7 @@ dependencies = [ "frame-try-runtime", "pallet-aura", "pallet-glutton", + "pallet-message-queue", "pallet-sudo", "pallet-timestamp", "parachains-common", @@ -6692,7 +6714,6 @@ dependencies = [ "bridge-hub-rococo-runtime", "bridge-runtime-common", "collectives-polkadot-runtime", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -11185,6 +11206,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-parachain-template", "pallet-session", "pallet-sudo", @@ -11192,6 +11214,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-xcm", + "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-common", @@ -11231,6 +11254,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", @@ -11254,7 +11278,6 @@ name = "parachains-runtimes-test-utils" version = "1.0.0" dependencies = [ "assets-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -11506,6 +11529,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -14223,6 +14247,7 @@ dependencies = [ "pallet-assets", "pallet-aura", "pallet-balances", + "pallet-message-queue", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -16563,6 +16588,7 @@ dependencies = [ "frame-system", "frame-try-runtime", "pallet-aura", + "pallet-message-queue", "pallet-timestamp", "parachains-common", "parity-scale-codec", @@ -21045,6 +21071,7 @@ name = "xcm-emulator" version = "0.1.0" dependencies = [ "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-test-relay-sproof-builder", diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 3d48074d5c5..43fb131aec2 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -3,19 +3,24 @@ name = "cumulus-pallet-dmp-queue" version = "0.1.0" authors.workspace = true edition.workspace = true +repository.workspace = true +description = "Migrates messages from the old DMP queue pallet." license = "Apache-2.0" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.20", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -# Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} @@ -24,25 +29,34 @@ xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-feature cumulus-primitives-core = { path = "../../primitives/core", default-features = false } [dev-dependencies] -sp-core = { path = "../../../substrate/primitives/core", default-features = false} -sp-version = { path = "../../../substrate/primitives/version", default-features = false} +sp-core = { path = "../../../substrate/primitives/core" } +sp-tracing = { path = "../../../substrate/primitives/tracing" } [features] default = [ "std" ] + std = [ "codec/std", "cumulus-primitives-core/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", "scale-info/std", - "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "sp-version/std", "xcm/std", ] + +runtime-benchmarks = [ + "cumulus-primitives-core/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", diff --git a/cumulus/pallets/dmp-queue/src/benchmarking.rs b/cumulus/pallets/dmp-queue/src/benchmarking.rs new file mode 100644 index 00000000000..91d1e0eab7e --- /dev/null +++ b/cumulus/pallets/dmp-queue/src/benchmarking.rs @@ -0,0 +1,108 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarking for the `cumulus-pallet-dmp-queue`. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::*; + +use frame_benchmarking::v2::*; +use frame_support::{pallet_prelude::*, traits::Hooks}; +use sp_std::vec; + +#[benchmarks] +mod benchmarks { + use super::*; + + /// This benchmark uses the proper maximal message length. + #[benchmark] + fn on_idle_good_msg() { + let msg = vec![123; MaxDmpMessageLenOf::::get() as usize]; + + Pages::::insert(0, vec![(123, msg.clone())]); + PageIndex::::put(PageIndexData { begin_used: 0, end_used: 1, overweight_count: 0 }); + MigrationStatus::::set(MigrationState::StartedExport { next_begin_used: 0 }); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + + assert_last_event::(Event::Exported { page: 0 }.into()); + } + + /// This benchmark uses 64 KiB messages to emulate a large old message. + #[benchmark] + fn on_idle_large_msg() { + let msg = vec![123; 1 << 16]; + + Pages::::insert(0, vec![(123, msg.clone())]); + PageIndex::::put(PageIndexData { begin_used: 0, end_used: 1, overweight_count: 0 }); + MigrationStatus::::set(MigrationState::StartedExport { next_begin_used: 0 }); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + + assert_last_event::(Event::Exported { page: 0 }.into()); + } + + #[benchmark] + fn on_idle_overweight_good_msg() { + let msg = vec![123; MaxDmpMessageLenOf::::get() as usize]; + + Overweight::::insert(0, (123, msg.clone())); + PageIndex::::put(PageIndexData { begin_used: 0, end_used: 1, overweight_count: 1 }); + MigrationStatus::::set(MigrationState::StartedOverweightExport { + next_overweight_index: 0, + }); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + + assert_last_event::(Event::ExportedOverweight { index: 0 }.into()); + } + + #[benchmark] + fn on_idle_overweight_large_msg() { + let msg = vec![123; 1 << 16]; + + Overweight::::insert(0, (123, msg.clone())); + PageIndex::::put(PageIndexData { begin_used: 0, end_used: 1, overweight_count: 1 }); + MigrationStatus::::set(MigrationState::StartedOverweightExport { + next_overweight_index: 0, + }); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + + assert_last_event::(Event::ExportOverweightFailed { index: 0 }.into()); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); +} + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + let frame_system::EventRecord { event, .. } = events.last().expect("Event expected"); + assert_eq!(event, &system_event.into()); +} diff --git a/cumulus/pallets/dmp-queue/src/lib.rs b/cumulus/pallets/dmp-queue/src/lib.rs index eff4a625ef1..79cc4bc895e 100644 --- a/cumulus/pallets/dmp-queue/src/lib.rs +++ b/cumulus/pallets/dmp-queue/src/lib.rs @@ -1,915 +1,284 @@ // 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 . - -//! Pallet implementing a message queue for downward messages from the relay-chain. -//! Executes downward messages if there is enough weight available and schedules the rest for later -//! execution (by `on_idle` or another `handle_dmp_messages` call). Individual overweight messages -//! are scheduled into a separate queue that is only serviced by explicit extrinsic calls. +// 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 used to implement a message queue for downward messages from the relay-chain. +//! +//! It is now deprecated and has been refactored to simply drain any remaining messages into +//! something implementing `HandleMessage`. It proceeds in the state of +//! [`MigrationState`] one by one by their listing in the source code. The pallet can be removed +//! from the runtime once `Completed` was emitted. #![cfg_attr(not(feature = "std"), no_std)] -pub mod migration; - -use codec::{Decode, DecodeLimit, Encode}; -use cumulus_primitives_core::{relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler}; -use frame_support::{ - traits::EnsureOrigin, - weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, -}; +use migration::*; pub use pallet::*; -use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; -use sp_std::{convert::TryFrom, prelude::*}; -use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH}; - -const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB - -// Maximum amount of messages to process per block. This is a temporary measure until we properly -// account for proof size weights. -const MAX_MESSAGES_PER_BLOCK: u8 = 10; -// Maximum amount of messages that can exist in the overweight queue at any given time. -const MAX_OVERWEIGHT_MESSAGES: u32 = 1000; - -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct ConfigData { - /// The maximum amount of weight any individual message may consume. Messages above this weight - /// go into the overweight queue and may only be serviced explicitly by the - /// `ExecuteOverweightOrigin`. - max_individual: Weight, -} -impl Default for ConfigData { - fn default() -> Self { - Self { - max_individual: Weight::from_parts( - 10u64 * WEIGHT_REF_TIME_PER_MILLIS, // 10 ms of execution time maximum by default - DEFAULT_POV_SIZE, // 64 KB of proof size by default - ), - } - } -} +mod benchmarking; +mod migration; +mod mock; +mod tests; +pub mod weights; -/// Information concerning our message pages. -#[derive(Copy, Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct PageIndexData { - /// The lowest used page index. - begin_used: PageCounter, - /// The lowest unused page index. - end_used: PageCounter, - /// The number of overweight messages ever recorded (and thus the lowest free index). - overweight_count: OverweightIndex, -} - -/// Simple type used to identify messages for the purpose of reporting events. Secure if and only -/// if the message content is unique. -pub type MessageId = XcmHash; +pub use weights::WeightInfo; -/// Index used to identify overweight messages. -pub type OverweightIndex = u64; - -/// Index used to identify normal pages. -pub type PageCounter = u32; +/// The maximal length of a DMP message. +pub type MaxDmpMessageLenOf = + <::DmpSink as frame_support::traits::HandleMessage>::MaxMessageLen; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::HandleMessage, weights::WeightMeter}; use frame_system::pallet_prelude::*; + use sp_io::hashing::twox_128; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] - #[pallet::storage_version(migration::STORAGE_VERSION)] - #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - /// The module configuration trait. #[pallet::config] pub trait Config: frame_system::Config { - /// The overarching event type. + /// The overarching event type of the runtime. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type XcmExecutor: ExecuteXcm; + /// The sink for all DMP messages that the lazy migration will use. + type DmpSink: HandleMessage; - /// Origin which is allowed to execute overweight messages. - type ExecuteOverweightOrigin: EnsureOrigin; + /// Weight info for this pallet (only needed for the lazy migration). + type WeightInfo: WeightInfo; } - /// The configuration. - #[pallet::storage] - pub(super) type Configuration = StorageValue<_, ConfigData, ValueQuery>; - - /// The page index. - #[pallet::storage] - pub(super) type PageIndex = StorageValue<_, PageIndexData, ValueQuery>; - - /// The queue pages. + /// The migration state of this pallet. #[pallet::storage] - pub(super) type Pages = - StorageMap<_, Blake2_128Concat, PageCounter, Vec<(RelayBlockNumber, Vec)>, ValueQuery>; - - /// The overweight messages. - #[pallet::storage] - pub(super) type Overweight = CountedStorageMap< - _, - Blake2_128Concat, - OverweightIndex, - (RelayBlockNumber, Vec), - OptionQuery, - >; - - #[pallet::error] - pub enum Error { - /// The message index given is unknown. - Unknown, - /// The amount of weight given is possibly not enough for executing the message. - OverLimit, + pub type MigrationStatus = StorageValue<_, MigrationState, ValueQuery>; + + /// The lazy-migration state of the pallet. + #[derive( + codec::Encode, codec::Decode, Debug, PartialEq, Eq, Clone, MaxEncodedLen, TypeInfo, + )] + pub enum MigrationState { + /// Migration has not started yet. + NotStarted, + /// The export of pages started. + StartedExport { + /// The next page that should be exported. + next_begin_used: PageCounter, + }, + /// The page export completed. + CompletedExport, + /// The export of overweight messages started. + StartedOverweightExport { + /// The next overweight index that should be exported. + next_overweight_index: u64, + }, + /// The export of overweight messages completed. + CompletedOverweightExport, + /// The storage cleanup started. + StartedCleanup { cursor: Option>> }, + /// The migration finished. The pallet can now be removed from the runtime. + Completed, } - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_idle(_now: BlockNumberFor, max_weight: Weight) -> Weight { - // on_idle processes additional messages with any remaining block weight. - Self::service_queue(max_weight) - } - } - - #[pallet::call] - impl Pallet { - /// Service a single overweight message. - #[pallet::call_index(0)] - #[pallet::weight(weight_limit.saturating_add(Weight::from_parts(1_000_000, 0)))] - pub fn service_overweight( - origin: OriginFor, - index: OverweightIndex, - weight_limit: Weight, - ) -> DispatchResultWithPostInfo { - T::ExecuteOverweightOrigin::ensure_origin(origin)?; - - let (sent_at, data) = Overweight::::get(index).ok_or(Error::::Unknown)?; - let weight_used = Self::try_service_message(weight_limit, sent_at, &data[..]) - .map_err(|_| Error::::OverLimit)?; - Overweight::::remove(index); - Self::deposit_event(Event::OverweightServiced { overweight_index: index, weight_used }); - Ok(Some(weight_used.saturating_add(Weight::from_parts(1_000_000, 0))).into()) + impl Default for MigrationState { + fn default() -> Self { + Self::NotStarted } } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Downward message is invalid XCM. - InvalidFormat { message_hash: XcmHash }, - /// Downward message is unsupported version of XCM. - UnsupportedVersion { message_hash: XcmHash }, - /// Downward message executed with the given outcome. - ExecutedDownward { message_hash: XcmHash, message_id: XcmHash, outcome: Outcome }, - /// The weight limit for handling downward messages was reached. - WeightExhausted { - message_hash: XcmHash, - message_id: XcmHash, - remaining_weight: Weight, - required_weight: Weight, - }, - /// Downward message is overweight and was placed in the overweight queue. - OverweightEnqueued { - message_hash: XcmHash, - message_id: XcmHash, - overweight_index: OverweightIndex, - required_weight: Weight, - }, - /// Downward message from the overweight queue was executed. - OverweightServiced { overweight_index: OverweightIndex, weight_used: Weight }, - /// The maximum number of downward messages was reached. - MaxMessagesExhausted { message_hash: XcmHash }, - } + /// The export of pages started. + StartedExport, - /// Error type when a message was failed to be serviced. - pub(crate) struct ServiceMessageError { - /// The message's hash. - message_hash: XcmHash, - /// The message's ID (which could also be its hash if nothing overrides it). - message_id: XcmHash, - /// Weight required for the message to be executed. - required_weight: Weight, - } + /// The export of a page completed. + Exported { page: PageCounter }, - impl Pallet { - /// Service the message queue up to some given weight `limit`. + /// The export of a page failed. /// - /// Returns the weight consumed by executing messages in the queue. - fn service_queue(limit: Weight) -> Weight { - let mut messages_processed = 0; - PageIndex::::mutate(|page_index| { - Self::do_service_queue(limit, page_index, &mut messages_processed) - }) - } + /// This should never be emitted. + ExportFailed { page: PageCounter }, - /// Exactly equivalent to `service_queue` but expects a mutable `page_index` to be passed - /// in and any changes stored. - fn do_service_queue( - limit: Weight, - page_index: &mut PageIndexData, - messages_processed: &mut u8, - ) -> Weight { - let mut used = Weight::zero(); - while page_index.begin_used < page_index.end_used { - let page = Pages::::take(page_index.begin_used); - for (i, &(sent_at, ref data)) in page.iter().enumerate() { - if *messages_processed >= MAX_MESSAGES_PER_BLOCK { - // Exceeded block message limit - put the remaining messages back and bail - Pages::::insert(page_index.begin_used, &page[i..]); - return used - } - *messages_processed += 1; - match Self::try_service_message(limit.saturating_sub(used), sent_at, &data[..]) - { - Ok(w) => used += w, - Err(..) => { - // Too much weight needed - put the remaining messages back and bail - Pages::::insert(page_index.begin_used, &page[i..]); - return used - }, - } - } - page_index.begin_used += 1; - } - if page_index.begin_used == page_index.end_used { - // Reset if there's no pages left. - page_index.begin_used = 0; - page_index.end_used = 0; - } - used - } + /// The export of pages completed. + CompletedExport, - /// Attempt to service an individual message. Will return `Ok` with the execution weight - /// consumed unless the message was found to need more weight than `limit`. - /// - /// NOTE: This will return `Ok` in the case of an error decoding, weighing or executing - /// the message. This is why it's called message "servicing" rather than "execution". - pub(crate) fn try_service_message( - limit: Weight, - _sent_at: RelayBlockNumber, - mut data: &[u8], - ) -> Result { - let message_hash = sp_io::hashing::blake2_256(data); - let mut message_id = message_hash; - let maybe_msg = VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data, - ) - .map(Xcm::::try_from); - match maybe_msg { - Err(_) => { - Self::deposit_event(Event::InvalidFormat { message_hash }); - Ok(Weight::zero()) - }, - Ok(Err(())) => { - Self::deposit_event(Event::UnsupportedVersion { message_hash }); - Ok(Weight::zero()) - }, - Ok(Ok(x)) => { - let outcome = T::XcmExecutor::prepare_and_execute( - Parent, - x, - &mut message_id, - limit, - Weight::zero(), - ); - match outcome { - Outcome::Error(XcmError::WeightLimitReached(required_weight)) => - Err(ServiceMessageError { message_hash, message_id, required_weight }), - outcome => { - let weight_used = outcome.weight_used(); - Self::deposit_event(Event::ExecutedDownward { - message_hash, - message_id, - outcome, - }); - Ok(weight_used) - }, - } - }, - } - } - } + /// The export of overweight messages started. + StartedOverweightExport, - /// For an incoming downward message, this just adapts an XCM executor and executes DMP messages - /// immediately up until some `MaxWeight` at which point it errors. Their origin is asserted to - /// be the `Parent` location. - impl DmpMessageHandler for Pallet { - fn handle_dmp_messages( - iter: impl Iterator)>, - limit: Weight, - ) -> Weight { - let mut messages_processed = 0; - let mut page_index = PageIndex::::get(); - let config = Configuration::::get(); - - // First try to use `max_weight` to service the current queue. - let mut used = Self::do_service_queue(limit, &mut page_index, &mut messages_processed); - - // Then if the queue is empty, use the weight remaining to service the incoming messages - // and once we run out of weight, place them in the queue. - let item_count = iter.size_hint().0; - let mut maybe_enqueue_page = if page_index.end_used > page_index.begin_used { - // queue is already non-empty - start a fresh page. - Some(Vec::with_capacity(item_count)) - } else { - None - }; - - for (i, (sent_at, data)) in iter.enumerate() { - if maybe_enqueue_page.is_none() { - if messages_processed >= MAX_MESSAGES_PER_BLOCK { - let item_count_left = item_count.saturating_sub(i); - maybe_enqueue_page = Some(Vec::with_capacity(item_count_left)); - - Self::deposit_event(Event::MaxMessagesExhausted { - message_hash: sp_io::hashing::blake2_256(&data), - }); - } else { - // We're not currently enqueuing - try to execute inline. - let remaining_weight = limit.saturating_sub(used); - messages_processed += 1; - match Self::try_service_message(remaining_weight, sent_at, &data[..]) { - Ok(consumed) => used += consumed, - Err(ServiceMessageError { - message_hash, - message_id, - required_weight, - }) => - // Too much weight required right now. - { - let is_under_limit = - Overweight::::count() < MAX_OVERWEIGHT_MESSAGES; - used.saturating_accrue(T::DbWeight::get().reads(1)); - if required_weight.any_gt(config.max_individual) && is_under_limit { - // overweight - add to overweight queue and continue with - // message execution. - let overweight_index = page_index.overweight_count; - Overweight::::insert(overweight_index, (sent_at, data)); - Self::deposit_event(Event::OverweightEnqueued { - message_hash, - message_id, - overweight_index, - required_weight, - }); - page_index.overweight_count += 1; - // Not needed for control flow, but only to ensure that the - // compiler understands that we won't attempt to re-use `data` - // later. - continue - } else { - // not overweight. stop executing inline and enqueue normally - // from here on. - let item_count_left = item_count.saturating_sub(i); - maybe_enqueue_page = Some(Vec::with_capacity(item_count_left)); - Self::deposit_event(Event::WeightExhausted { - message_hash, - message_id, - remaining_weight, - required_weight, - }); - } - }, - } - } - } - // Cannot be an `else` here since the `maybe_enqueue_page` may have changed. - if let Some(ref mut enqueue_page) = maybe_enqueue_page { - enqueue_page.push((sent_at, data)); - } - } - - // Deposit the enqueued page if any and save the index. - if let Some(enqueue_page) = maybe_enqueue_page { - Pages::::insert(page_index.end_used, enqueue_page); - page_index.end_used += 1; - } - PageIndex::::put(page_index); - - used - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate as dmp_queue; - - use codec::Encode; - use cumulus_primitives_core::ParaId; - use frame_support::{assert_noop, parameter_types, traits::OnIdle}; - use sp_core::H256; - use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, - DispatchError::BadOrigin, - }; - use sp_version::RuntimeVersion; - use std::cell::RefCell; - use xcm::latest::{MultiLocation, OriginKind}; - - type Block = frame_system::mocking::MockBlock; - type Xcm = xcm::latest::Xcm; - - frame_support::construct_runtime!( - pub enum Test - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - DmpQueue: dmp_queue::{Pallet, Call, Storage, Event}, - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub Version: RuntimeVersion = RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("system-test"), - authoring_version: 1, - spec_version: 1, - impl_version: 1, - apis: sp_version::create_apis_vec!([]), - transaction_version: 1, - state_version: 1, - }; - pub const ParachainId: ParaId = ParaId::new(200); - pub const ReservedXcmpWeight: Weight = Weight::zero(); - pub const ReservedDmpWeight: Weight = Weight::zero(); - } - - type AccountId = u64; - - impl frame_system::Config for Test { - 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 BlockLength = (); - type BlockWeights = (); - type Version = Version; - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } + /// The export of an overweight message completed. + ExportedOverweight { index: OverweightIndex }, - thread_local! { - pub static TRACE: RefCell> = RefCell::new(Vec::new()); - } - pub fn take_trace() -> Vec<(Xcm, Outcome)> { - TRACE.with(|q| { - let q = &mut *q.borrow_mut(); - let r = q.clone(); - q.clear(); - r - }) - } - - pub struct MockPrepared(Xcm); - impl PreparedMessage for MockPrepared { - fn weight_of(&self) -> Weight { - match ((self.0).0.len(), &(self.0).0.first()) { - (1, Some(Transact { require_weight_at_most, .. })) => *require_weight_at_most, - _ => Weight::from_parts(1, 1), - } - } - } + /// The export of an overweight message failed. + /// + /// This should never be emitted. + ExportOverweightFailed { index: OverweightIndex }, - pub struct MockExec; - impl ExecuteXcm for MockExec { - type Prepared = MockPrepared; + /// The export of overweight messages completed. + CompletedOverweightExport, - fn prepare(message: Xcm) -> Result { - Ok(MockPrepared(message)) - } + /// The cleanup of remaining pallet storage started. + StartedCleanup, - fn execute( - _origin: impl Into, - prepared: MockPrepared, - _id: &mut XcmHash, - _weight_credit: Weight, - ) -> Outcome { - let message = prepared.0; - let o = match (message.0.len(), &message.0.first()) { - (1, Some(Transact { require_weight_at_most, .. })) => - Outcome::Complete(*require_weight_at_most), - // use 1000 to decide that it's not supported. - _ => Outcome::Incomplete(Weight::from_parts(1, 1), XcmError::Unimplemented), - }; - TRACE.with(|q| q.borrow_mut().push((message, o.clone()))); - o - } + /// Some debris was cleaned up. + CleanedSome { keys_removed: u32 }, - fn charge_fees(_location: impl Into, _fees: MultiAssets) -> XcmResult { - Err(XcmError::Unimplemented) - } + /// The cleanup of remaining pallet storage completed. + Completed { error: bool }, } - impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = MockExec; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; - } - - pub(crate) fn new_test_ext() -> sp_io::TestExternalities { - frame_system::GenesisConfig::::default().build_storage().unwrap().into() - } + #[pallet::call] + impl Pallet {} - fn enqueue(enqueued: &[Xcm]) { - if !enqueued.is_empty() { - let mut index = PageIndex::::get(); - Pages::::insert( - index.end_used, - enqueued - .iter() - .map(|m| (0, VersionedXcm::::from(m.clone()).encode())) - .collect::>(), - ); - index.end_used += 1; - PageIndex::::put(index); + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + let w = Self::on_idle_weight(); + assert!(w != Weight::zero()); + assert!(w.all_lte(T::BlockWeights::get().max_block)); } - } - fn handle_messages(incoming: &[Xcm], limit: Weight) -> Weight { - let iter = incoming - .iter() - .map(|m| (0, VersionedXcm::::from(m.clone()).encode())); - DmpQueue::handle_dmp_messages(iter, limit) - } + fn on_idle(now: BlockNumberFor, limit: Weight) -> Weight { + let mut meter = WeightMeter::with_limit(limit); - fn msg(weight: u64) -> Xcm { - Xcm(vec![Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(weight, weight), - call: Vec::new().into(), - }]) - } - - fn msg_complete(weight: u64) -> (Xcm, Outcome) { - (msg(weight), Outcome::Complete(Weight::from_parts(weight, weight))) - } - - fn pages_queued() -> PageCounter { - PageIndex::::get().end_used - PageIndex::::get().begin_used - } - - fn queue_is_empty() -> bool { - pages_queued() == 0 - } - - fn overweights() -> Vec { - (0..PageIndex::::get().overweight_count) - .filter(|i| Overweight::::contains_key(i)) - .collect::>() - } - - #[test] - fn basic_setup_works() { - new_test_ext().execute_with(|| { - let weight_used = handle_messages(&[], Weight::from_parts(1000, 1000)); - assert_eq!(weight_used, Weight::zero()); - assert_eq!(take_trace(), Vec::new()); - assert!(queue_is_empty()); - }); - } + if meter.try_consume(Self::on_idle_weight()).is_err() { + log::debug!(target: LOG, "Not enough weight for on_idle. {} < {}", Self::on_idle_weight(), limit); + return meter.consumed() + } - #[test] - fn service_inline_complete_works() { - new_test_ext().execute_with(|| { - let incoming = vec![msg(1000), msg(1001)]; - let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(2001, 2001)); - assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]); - assert!(queue_is_empty()); - }); - } + let state = MigrationStatus::::get(); + let index = PageIndex::::get(); + log::debug!(target: LOG, "on_idle: block={:?}, state={:?}, index={:?}", now, state, index); - #[test] - fn service_enqueued_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(1001), msg(1002)]; - enqueue(&enqueued); - let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(2001, 2001)); - assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001),]); - }); - } + match state { + MigrationState::NotStarted => { + log::debug!(target: LOG, "Init export at page {}", index.begin_used); - #[test] - fn enqueue_works() { - new_test_ext().execute_with(|| { - let incoming = vec![msg(1000), msg(1001), msg(1002)]; - let weight_used = handle_messages(&incoming, Weight::from_parts(999, 999)); - assert_eq!(weight_used, Weight::zero()); - assert_eq!( - PageIndex::::get(), - PageIndexData { begin_used: 0, end_used: 1, overweight_count: 0 } - ); - assert_eq!(Pages::::get(0).len(), 3); - assert_eq!(take_trace(), vec![]); - - let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(2001, 2001)); - assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]); - - let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(1002, 1002)); - assert_eq!(take_trace(), vec![msg_complete(1002)]); - assert!(queue_is_empty()); - }); - } + MigrationStatus::::put(MigrationState::StartedExport { + next_begin_used: index.begin_used, + }); + Self::deposit_event(Event::StartedExport); + }, + MigrationState::StartedExport { next_begin_used } => { + log::debug!(target: LOG, "Exporting page {}", next_begin_used); - #[test] - fn service_inline_then_enqueue_works() { - new_test_ext().execute_with(|| { - let incoming = vec![msg(1000), msg(1001), msg(1002)]; - let weight_used = handle_messages(&incoming, Weight::from_parts(1500, 1500)); - assert_eq!(weight_used, Weight::from_parts(1000, 1000)); - assert_eq!(pages_queued(), 1); - assert_eq!(Pages::::get(0).len(), 2); - assert_eq!(take_trace(), vec![msg_complete(1000)]); - - let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(2003, 2003)); - assert_eq!(take_trace(), vec![msg_complete(1001), msg_complete(1002),]); - assert!(queue_is_empty()); - }); - } + if next_begin_used == index.end_used { + MigrationStatus::::put(MigrationState::CompletedExport); + log::debug!(target: LOG, "CompletedExport"); + Self::deposit_event(Event::CompletedExport); + } else { + let res = migration::migrate_page::(next_begin_used); - #[test] - fn service_enqueued_and_inline_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(1001)]; - let incoming = vec![msg(1002), msg(1003)]; - enqueue(&enqueued); - let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000)); - assert_eq!(weight_used, Weight::from_parts(4006, 4006)); - assert_eq!( - take_trace(), - vec![ - msg_complete(1000), - msg_complete(1001), - msg_complete(1002), - msg_complete(1003), - ] - ); - assert!(queue_is_empty()); - }); - } + MigrationStatus::::put(MigrationState::StartedExport { + next_begin_used: next_begin_used.saturating_add(1), + }); - #[test] - fn service_enqueued_partially_and_then_enqueue_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(10001)]; - let incoming = vec![msg(1002), msg(1003)]; - enqueue(&enqueued); - let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000)); - assert_eq!(weight_used, Weight::from_parts(1000, 1000)); - assert_eq!(take_trace(), vec![msg_complete(1000)]); - assert_eq!(pages_queued(), 2); - - // 5000 is not enough to process the 10001 blocker, so nothing happens. - let weight_used = handle_messages(&[], Weight::from_parts(5000, 5000)); - assert_eq!(weight_used, Weight::zero()); - assert_eq!(take_trace(), vec![]); - - // 20000 is now enough to process everything. - let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000)); - assert_eq!(weight_used, Weight::from_parts(12006, 12006)); - assert_eq!( - take_trace(), - vec![msg_complete(10001), msg_complete(1002), msg_complete(1003),] - ); - assert!(queue_is_empty()); - }); - } + if let Ok(()) = res { + log::debug!(target: LOG, "Exported page {}", next_begin_used); + Self::deposit_event(Event::Exported { page: next_begin_used }); + } else { + Self::deposit_event(Event::ExportFailed { page: next_begin_used }); + } + } + }, + MigrationState::CompletedExport => { + log::debug!(target: LOG, "Init export overweight at index 0"); - #[test] - fn service_enqueued_completely_and_then_enqueue_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(1001)]; - let incoming = vec![msg(10002), msg(1003)]; - enqueue(&enqueued); - let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000)); - assert_eq!(weight_used, Weight::from_parts(2001, 2001)); - assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]); - assert_eq!(pages_queued(), 1); - - // 20000 is now enough to process everything. - let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000)); - assert_eq!(weight_used, Weight::from_parts(11005, 11005)); - assert_eq!(take_trace(), vec![msg_complete(10002), msg_complete(1003),]); - assert!(queue_is_empty()); - }); - } + MigrationStatus::::put(MigrationState::StartedOverweightExport { + next_overweight_index: 0, + }); + Self::deposit_event(Event::StartedOverweightExport); + }, + MigrationState::StartedOverweightExport { next_overweight_index } => { + log::debug!(target: LOG, "Exporting overweight index {}", next_overweight_index); - #[test] - fn service_enqueued_then_inline_then_enqueue_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(1001)]; - let incoming = vec![msg(1002), msg(10003)]; - enqueue(&enqueued); - let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000)); - assert_eq!(weight_used, Weight::from_parts(3003, 3003)); - assert_eq!( - take_trace(), - vec![msg_complete(1000), msg_complete(1001), msg_complete(1002),] - ); - assert_eq!(pages_queued(), 1); - - // 20000 is now enough to process everything. - let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000)); - assert_eq!(weight_used, Weight::from_parts(10003, 10003)); - assert_eq!(take_trace(), vec![msg_complete(10003),]); - assert!(queue_is_empty()); - }); - } + if next_overweight_index == index.overweight_count { + MigrationStatus::::put(MigrationState::CompletedOverweightExport); + log::debug!(target: LOG, "CompletedOverweightExport"); + Self::deposit_event(Event::CompletedOverweightExport); + } else { + let res = migration::migrate_overweight::(next_overweight_index); - #[test] - fn page_crawling_works() { - new_test_ext().execute_with(|| { - let enqueued = vec![msg(1000), msg(1001)]; - enqueue(&enqueued); - let weight_used = handle_messages(&[msg(1002)], Weight::from_parts(1500, 1500)); - assert_eq!(weight_used, Weight::from_parts(1000, 1000)); - assert_eq!(take_trace(), vec![msg_complete(1000)]); - assert_eq!(pages_queued(), 2); - assert_eq!(PageIndex::::get().begin_used, 0); - - let weight_used = handle_messages(&[msg(1003)], Weight::from_parts(1500, 1500)); - assert_eq!(weight_used, Weight::from_parts(1001, 1001)); - assert_eq!(take_trace(), vec![msg_complete(1001)]); - assert_eq!(pages_queued(), 2); - assert_eq!(PageIndex::::get().begin_used, 1); - - let weight_used = handle_messages(&[msg(1004)], Weight::from_parts(1500, 1500)); - assert_eq!(weight_used, Weight::from_parts(1002, 1002)); - assert_eq!(take_trace(), vec![msg_complete(1002)]); - assert_eq!(pages_queued(), 2); - assert_eq!(PageIndex::::get().begin_used, 2); - }); - } + MigrationStatus::::put(MigrationState::StartedOverweightExport { + next_overweight_index: next_overweight_index.saturating_add(1), + }); - #[test] - fn overweight_should_not_block_queue() { - new_test_ext().execute_with(|| { - // Set the overweight threshold to 9999. - Configuration::::put(ConfigData { - max_individual: Weight::from_parts(9999, 9999), - }); - - let incoming = vec![msg(1000), msg(10001), msg(1002)]; - let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::from_parts(2002, 2002)); - assert!(queue_is_empty()); - assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1002),]); - - assert_eq!(overweights(), vec![0]); - }); - } + if let Ok(()) = res { + log::debug!(target: LOG, "Exported overweight index {next_overweight_index}"); + Self::deposit_event(Event::ExportedOverweight { + index: next_overweight_index, + }); + } else { + Self::deposit_event(Event::ExportOverweightFailed { + index: next_overweight_index, + }); + } + } + }, + MigrationState::CompletedOverweightExport => { + log::debug!(target: LOG, "Init cleanup"); - #[test] - fn overweights_should_be_manually_executable() { - new_test_ext().execute_with(|| { - // Set the overweight threshold to 9999. - Configuration::::put(ConfigData { - max_individual: Weight::from_parts(9999, 9999), - }); - - let incoming = vec![msg(10000)]; - let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500)); - assert_eq!(weight_used, Weight::zero()); - assert_eq!(take_trace(), vec![]); - assert_eq!(overweights(), vec![0]); - - assert_noop!( - DmpQueue::service_overweight( - RuntimeOrigin::signed(1), - 0, - Weight::from_parts(20000, 20000) - ), - BadOrigin - ); - assert_noop!( - DmpQueue::service_overweight( - RuntimeOrigin::root(), - 1, - Weight::from_parts(20000, 20000) - ), - Error::::Unknown - ); - assert_noop!( - DmpQueue::service_overweight( - RuntimeOrigin::root(), - 0, - Weight::from_parts(9999, 9999) - ), - Error::::OverLimit - ); - assert_eq!(take_trace(), vec![]); - - let base_weight = - super::Call::::service_overweight { index: 0, weight_limit: Weight::zero() } - .get_dispatch_info() - .weight; - use frame_support::dispatch::GetDispatchInfo; - let info = DmpQueue::service_overweight( - RuntimeOrigin::root(), - 0, - Weight::from_parts(20000, 20000), - ) - .unwrap(); - let actual_weight = info.actual_weight.unwrap(); - assert_eq!(actual_weight, base_weight + Weight::from_parts(10000, 10000)); - assert_eq!(take_trace(), vec![msg_complete(10000)]); - assert!(overweights().is_empty()); - - assert_noop!( - DmpQueue::service_overweight( - RuntimeOrigin::root(), - 0, - Weight::from_parts(20000, 20000) - ), - Error::::Unknown - ); - }); - } + MigrationStatus::::put(MigrationState::StartedCleanup { cursor: None }); + Self::deposit_event(Event::StartedCleanup); + }, + MigrationState::StartedCleanup { cursor } => { + log::debug!(target: LOG, "Cleaning up"); + let hashed_prefix = + twox_128( as PalletInfoAccess>::name().as_bytes()); + + let result = frame_support::storage::unhashed::clear_prefix( + &hashed_prefix, + Some(2), // Somehow it does nothing when set to 1, so we set it to 2. + cursor.as_ref().map(|c| c.as_ref()), + ); + Self::deposit_event(Event::CleanedSome { keys_removed: result.backend }); + + // GOTCHA! We deleted *all* pallet storage; hence we also our own + // `MigrationState`. BUT we insert it back: + if let Some(unbound_cursor) = result.maybe_cursor { + if let Ok(cursor) = unbound_cursor.try_into() { + log::debug!(target: LOG, "Next cursor: {:?}", &cursor); + MigrationStatus::::put(MigrationState::StartedCleanup { + cursor: Some(cursor), + }); + } else { + MigrationStatus::::put(MigrationState::Completed); + log::error!(target: LOG, "Completed with error: could not bound cursor"); + Self::deposit_event(Event::Completed { error: true }); + } + } else { + MigrationStatus::::put(MigrationState::Completed); + log::debug!(target: LOG, "Completed"); + Self::deposit_event(Event::Completed { error: false }); + } + }, + MigrationState::Completed => { + log::debug!(target: LOG, "Idle; you can remove this pallet"); + }, + } - #[test] - fn on_idle_should_service_queue() { - new_test_ext().execute_with(|| { - enqueue(&[msg(1000), msg(1001)]); - enqueue(&[msg(1002), msg(1003)]); - enqueue(&[msg(1004), msg(1005)]); - - let weight_used = DmpQueue::on_idle(1, Weight::from_parts(6000, 6000)); - assert_eq!(weight_used, Weight::from_parts(5010, 5010)); - assert_eq!( - take_trace(), - vec![ - msg_complete(1000), - msg_complete(1001), - msg_complete(1002), - msg_complete(1003), - msg_complete(1004), - ] - ); - assert_eq!(pages_queued(), 1); - }); + meter.consumed() + } } - #[test] - fn handle_max_messages_per_block() { - new_test_ext().execute_with(|| { - enqueue(&[msg(1000), msg(1001)]); - enqueue(&[msg(1002), msg(1003)]); - enqueue(&[msg(1004), msg(1005)]); - - let incoming = - (0..MAX_MESSAGES_PER_BLOCK).map(|i| msg(1006 + i as u64)).collect::>(); - handle_messages(&incoming, Weight::from_parts(25000, 25000)); - - assert_eq!( - take_trace(), - (0..MAX_MESSAGES_PER_BLOCK) - .map(|i| msg_complete(1000 + i as u64)) - .collect::>(), - ); - assert_eq!(pages_queued(), 1); - - handle_messages(&[], Weight::from_parts(25000, 25000)); - assert_eq!( - take_trace(), - (MAX_MESSAGES_PER_BLOCK..MAX_MESSAGES_PER_BLOCK + 6) - .map(|i| msg_complete(1000 + i as u64)) - .collect::>(), - ); - }); + impl Pallet { + /// The worst-case weight of [`Self::on_idle`]. + pub fn on_idle_weight() -> Weight { + ::WeightInfo::on_idle_good_msg() + .max(::WeightInfo::on_idle_large_msg()) + } } } diff --git a/cumulus/pallets/dmp-queue/src/migration.rs b/cumulus/pallets/dmp-queue/src/migration.rs index 63457ee4936..349635cce54 100644 --- a/cumulus/pallets/dmp-queue/src/migration.rs +++ b/cumulus/pallets/dmp-queue/src/migration.rs @@ -14,110 +14,100 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! A module that is responsible for migration of storage. - -use crate::{Config, Configuration, Overweight, Pallet, DEFAULT_POV_SIZE}; -use frame_support::{ - pallet_prelude::*, - traits::{OnRuntimeUpgrade, StorageVersion}, - weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, -}; - -/// The current storage version. -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); - -/// Migrates the pallet storage to the most recent version. -pub struct Migration(PhantomData); - -impl OnRuntimeUpgrade for Migration { - fn on_runtime_upgrade() -> Weight { - let mut weight = T::DbWeight::get().reads(1); - - if StorageVersion::get::>() == 0 { - weight.saturating_accrue(migrate_to_v1::()); - StorageVersion::new(1).put::>(); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - if StorageVersion::get::>() == 1 { - weight.saturating_accrue(migrate_to_v2::()); - StorageVersion::new(2).put::>(); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - weight - } +//! Migrates the storage from the previously deleted DMP pallet. + +use crate::*; +use cumulus_primitives_core::relay_chain::BlockNumber as RelayBlockNumber; +use frame_support::{pallet_prelude::*, storage_alias, traits::HandleMessage}; +use sp_std::vec::Vec; + +pub(crate) const LOG: &str = "runtime::dmp-queue-export-xcms"; + +/// The old `PageIndexData` struct. +#[derive(Copy, Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PageIndexData { + /// The lowest used page index. + pub begin_used: PageCounter, + /// The lowest unused page index. + pub end_used: PageCounter, + /// The number of overweight messages ever recorded (and thus the lowest free index). + pub overweight_count: OverweightIndex, } -mod v0 { +/// The old `MigrationState` type. +pub type OverweightIndex = u64; +/// The old `MigrationState` type. +pub type PageCounter = u32; + +/// The old `PageIndex` storage item. +#[storage_alias] +pub type PageIndex = StorageValue, PageIndexData, ValueQuery>; + +/// The old `Pages` storage item. +#[storage_alias] +pub type Pages = StorageMap< + Pallet, + Blake2_128Concat, + PageCounter, + Vec<(RelayBlockNumber, Vec)>, + ValueQuery, +>; + +/// The old `Overweight` storage item. +#[storage_alias] +pub type Overweight = CountedStorageMap< + Pallet, + Blake2_128Concat, + OverweightIndex, + (RelayBlockNumber, Vec), + OptionQuery, +>; + +pub(crate) mod testing_only { use super::*; - use codec::{Decode, Encode}; - - #[derive(Decode, Encode, Debug)] - pub struct ConfigData { - pub max_individual: u64, - } - impl Default for ConfigData { - fn default() -> Self { - ConfigData { max_individual: 10u64 * WEIGHT_REF_TIME_PER_MILLIS } - } - } + /// This alias is not used by the migration but only for testing. + /// + /// Note that the alias type is wrong on purpose. + #[storage_alias] + pub type Configuration = StorageValue, u32>; } -/// Migrates `QueueConfigData` from v1 (using only reference time weights) to v2 (with -/// 2D weights). -/// -/// NOTE: Only use this function if you know what you're doing. Default to using -/// `migrate_to_latest`. -pub fn migrate_to_v1() -> Weight { - let translate = |pre: v0::ConfigData| -> super::ConfigData { - super::ConfigData { - max_individual: Weight::from_parts(pre.max_individual, DEFAULT_POV_SIZE), - } - }; - - if Configuration::::translate(|pre| pre.map(translate)).is_err() { - log::error!( - target: "dmp_queue", - "unexpected error when performing translation of the QueueConfig type during storage upgrade to v2" - ); +/// Migrates a single page to the `DmpSink`. +pub(crate) fn migrate_page(p: PageCounter) -> Result<(), ()> { + let page = Pages::::take(p); + log::debug!(target: LOG, "Migrating page #{p} with {} messages ...", page.len()); + if page.is_empty() { + log::error!(target: LOG, "Page #{p}: EMPTY - storage corrupted?"); + return Err(()) } - T::DbWeight::get().reads_writes(1, 1) -} + for (m, (block, msg)) in page.iter().enumerate() { + let Ok(bound) = BoundedVec::::try_from(msg.clone()) else { + log::error!(target: LOG, "[Page {p}] Message #{m}: TOO LONG - dropping"); + continue + }; -/// Migrates `Overweight` so that it initializes the storage map's counter. -/// -/// NOTE: Only use this function if you know what you're doing. Default to using -/// `migrate_to_latest`. -pub fn migrate_to_v2() -> Weight { - let overweight_messages = Overweight::::initialize_counter() as u64; + T::DmpSink::handle_message(bound.as_bounded_slice()); + log::debug!(target: LOG, "[Page {p}] Migrated message #{m} from block {block}"); + } - T::DbWeight::get().reads_writes(overweight_messages, 1) + Ok(()) } -#[cfg(test)] -mod tests { - use super::*; - use crate::tests::{new_test_ext, Test}; - - #[test] - fn test_migration_to_v1() { - let v0 = v0::ConfigData { max_individual: 30_000_000_000 }; - - new_test_ext().execute_with(|| { - frame_support::storage::unhashed::put_raw( - &crate::Configuration::::hashed_key(), - &v0.encode(), - ); - - migrate_to_v1::(); +/// Migrates a single overweight message to the `DmpSink`. +pub(crate) fn migrate_overweight(i: OverweightIndex) -> Result<(), ()> { + let Some((block, msg)) = Overweight::::take(i) else { + log::error!(target: LOG, "[Overweight {i}] Message: EMPTY - storage corrupted?"); + return Err(()) + }; + let Ok(bound) = BoundedVec::::try_from(msg) else { + log::error!(target: LOG, "[Overweight {i}] Message: TOO LONG - dropping"); + return Err(()) + }; - let v1 = crate::Configuration::::get(); + T::DmpSink::handle_message(bound.as_bounded_slice()); + log::debug!(target: LOG, "[Overweight {i}] Migrated message from block {block}"); - assert_eq!(v0.max_individual, v1.max_individual.ref_time()); - assert_eq!(v1.max_individual.proof_size(), DEFAULT_POV_SIZE); - }); - } + Ok(()) } diff --git a/cumulus/pallets/dmp-queue/src/mock.rs b/cumulus/pallets/dmp-queue/src/mock.rs new file mode 100644 index 00000000000..6bd74a047eb --- /dev/null +++ b/cumulus/pallets/dmp-queue/src/mock.rs @@ -0,0 +1,83 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +use frame_support::{ + derive_impl, parameter_types, + traits::{HandleMessage, QueueFootprint}, +}; +use sp_core::{bounded_vec::BoundedSlice, ConstU32}; +use sp_runtime::traits::IdentityLookup; + +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Runtime + { + System: frame_system, + DmpQueue: crate, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; +} + +impl crate::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = RecordingDmpSink; + type WeightInfo = (); +} + +parameter_types! { + /// All messages that came into the `DmpSink`. + pub static RecordedMessages: Vec> = vec![]; +} + +/// Can be used as [`Config::DmpSink`] to record all messages that came in. +pub struct RecordingDmpSink; +impl HandleMessage for RecordingDmpSink { + type MaxMessageLen = ConstU32<16>; + + fn handle_message(msg: BoundedSlice) { + RecordedMessages::mutate(|n| n.push(msg.to_vec())); + } + + fn handle_messages<'a>(_: impl Iterator>) { + unimplemented!() + } + + fn sweep_queue() { + unimplemented!() + } + + fn footprint() -> QueueFootprint { + unimplemented!() + } +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} diff --git a/cumulus/pallets/dmp-queue/src/tests.rs b/cumulus/pallets/dmp-queue/src/tests.rs new file mode 100644 index 00000000000..a157d0584f2 --- /dev/null +++ b/cumulus/pallets/dmp-queue/src/tests.rs @@ -0,0 +1,234 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Test the lazy migration. + +#![cfg(test)] + +use super::{migration::*, mock::*}; +use crate::*; + +use frame_support::{ + pallet_prelude::*, + traits::{OnFinalize, OnIdle, OnInitialize}, + StorageNoopGuard, +}; + +#[test] +fn migration_works() { + let mut ext = new_test_ext(); + ext.execute_with(|| { + sp_tracing::try_init_simple(); + // Insert some storage: + PageIndex::::set(PageIndexData { + begin_used: 10, + end_used: 20, + overweight_count: 5, + }); + for p in 10..20 { + let msgs = (0..16).map(|i| (p, vec![i as u8; 1])).collect::>(); + Pages::::insert(p, msgs); + } + for i in 0..5 { + Overweight::::insert(i, (0, vec![i as u8; 1])); + } + testing_only::Configuration::::put(123); + }); + // We need to commit, otherwise the keys are removed from the overlay; not the backend. + ext.commit_all().unwrap(); + ext.execute_with(|| { + // Run one step of the migration: + pre_upgrade_checks::(); + run_to_block(1); + // First we expect a StartedExport event: + assert_only_event(Event::StartedExport); + + // Then we expect 10 Exported events: + for page in 0..10 { + run_to_block(2 + page); + assert_only_event(Event::Exported { page: page as u32 + 10 }); + assert!(!Pages::::contains_key(page as u32), "Page is gone"); + assert_eq!( + MigrationStatus::::get(), + MigrationState::StartedExport { next_begin_used: page as u32 + 11 } + ); + } + + // Then we expect a CompletedExport event: + run_to_block(12); + assert_only_event(Event::CompletedExport); + assert_eq!(MigrationStatus::::get(), MigrationState::CompletedExport); + + // Then we expect a StartedOverweightExport event: + run_to_block(13); + assert_only_event(Event::StartedOverweightExport); + assert_eq!( + MigrationStatus::::get(), + MigrationState::StartedOverweightExport { next_overweight_index: 0 } + ); + + // Then we expect 5 ExportedOverweight events: + for index in 0..5 { + run_to_block(14 + index); + assert_only_event(Event::ExportedOverweight { index }); + assert!(!Overweight::::contains_key(index), "Overweight msg is gone"); + assert_eq!( + MigrationStatus::::get(), + MigrationState::StartedOverweightExport { next_overweight_index: index + 1 } + ); + } + + // Then we expect a CompletedOverweightExport event: + run_to_block(19); + assert_only_event(Event::CompletedOverweightExport); + assert_eq!(MigrationStatus::::get(), MigrationState::CompletedOverweightExport); + + // Then we expect a StartedCleanup event: + run_to_block(20); + assert_only_event(Event::StartedCleanup); + assert_eq!( + MigrationStatus::::get(), + MigrationState::StartedCleanup { cursor: None } + ); + }); + ext.commit_all().unwrap(); + // Then it cleans up the remaining storage items: + ext.execute_with(|| { + run_to_block(21); + assert_only_event(Event::CleanedSome { keys_removed: 2 }); + }); + ext.commit_all().unwrap(); + ext.execute_with(|| { + run_to_block(22); + assert_only_event(Event::CleanedSome { keys_removed: 2 }); + }); + ext.commit_all().unwrap(); + ext.execute_with(|| { + run_to_block(24); + assert_eq!( + System::events().into_iter().map(|e| e.event).collect::>(), + vec![ + Event::CleanedSome { keys_removed: 2 }.into(), + Event::Completed { error: false }.into() + ] + ); + System::reset_events(); + assert_eq!(MigrationStatus::::get(), MigrationState::Completed); + + post_upgrade_checks::(); + assert_eq!(RecordedMessages::take().len(), 10 * 16 + 5); + + // Test the storage removal: + assert!(!PageIndex::::exists()); + assert!(!testing_only::Configuration::::exists()); + assert_eq!(Pages::::iter_keys().count(), 0); + assert_eq!(Overweight::::iter_keys().count(), 0); + + // The `MigrationStatus` never disappears and there are no more storage changes: + { + let _g = StorageNoopGuard::default(); + + run_to_block(100); + assert_eq!(MigrationStatus::::get(), MigrationState::Completed); + assert!(System::events().is_empty()); + // ... besides the block number + System::set_block_number(24); + } + }); +} + +/// Too long messages are dropped by the migration. +#[test] +fn migration_too_long_ignored() { + new_test_ext().execute_with(|| { + // Setup the storage: + PageIndex::::set(PageIndexData { + begin_used: 10, + end_used: 11, + overweight_count: 2, + }); + + let short = vec![1; 16]; + let long = vec![0; 17]; + Pages::::insert(10, vec![(10, short.clone()), (10, long.clone())]); + // Insert one good and one bad overweight msg: + Overweight::::insert(0, (0, short.clone())); + Overweight::::insert(1, (0, long.clone())); + + // Run the migration: + pre_upgrade_checks::(); + run_to_block(100); + post_upgrade_checks::(); + + assert_eq!(RecordedMessages::take(), vec![short.clone(), short]); + + // Test the storage removal: + assert!(!PageIndex::::exists()); + assert_eq!(Pages::::iter_keys().count(), 0); + assert_eq!(Overweight::::iter_keys().count(), 0); + }); +} + +fn run_to_block(n: u64) { + assert!(n > System::block_number(), "Cannot go back in time"); + + while System::block_number() < n { + AllPalletsWithSystem::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + AllPalletsWithSystem::on_initialize(System::block_number()); + AllPalletsWithSystem::on_idle(System::block_number(), Weight::MAX); + } +} + +fn assert_only_event(e: Event) { + assert_eq!(System::events().pop().expect("Event expected").event, e.clone().into()); + assert_eq!(System::events().len(), 1, "Got events: {:?} but wanted {:?}", System::events(), e); + System::reset_events(); +} + +/// TESTING ONLY +fn pre_upgrade_checks() { + let index = PageIndex::::get(); + + // Check that all pages are present. + assert!(index.begin_used <= index.end_used, "Invalid page index"); + for p in index.begin_used..index.end_used { + assert!(Pages::::contains_key(p), "Missing page"); + assert!(Pages::::get(p).len() > 0, "Empty page"); + } + + // Check that all overweight messages are present. + for i in 0..index.overweight_count { + assert!(Overweight::::contains_key(i), "Missing overweight message"); + } +} + +/// TESTING ONLY +fn post_upgrade_checks() { + let index = PageIndex::::get(); + + // Check that all pages are removed. + for p in index.begin_used..index.end_used { + assert!(!Pages::::contains_key(p), "Page should be gone"); + } + assert!(Pages::::iter_keys().next().is_none(), "Un-indexed pages"); + + // Check that all overweight messages are removed. + for i in 0..index.overweight_count { + assert!(!Overweight::::contains_key(i), "Overweight message should be gone"); + } + assert!(Overweight::::iter_keys().next().is_none(), "Un-indexed overweight messages"); +} diff --git a/cumulus/pallets/dmp-queue/src/weights.rs b/cumulus/pallets/dmp-queue/src/weights.rs new file mode 100644 index 00000000000..e095d46a073 --- /dev/null +++ b/cumulus/pallets/dmp-queue/src/weights.rs @@ -0,0 +1,222 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --pallet +// cumulus-pallet-dmp-queue +// --chain +// asset-hub-kusama-dev +// --output +// cumulus/pallets/dmp-queue/src/weights.rs +// --template +// substrate/.maintain/frame-weight-template.hbs +// --extrinsic +// + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `cumulus_pallet_dmp_queue`. +pub trait WeightInfo { + fn on_idle_good_msg() -> Weight; + fn on_idle_large_msg() -> Weight; + fn on_idle_overweight_good_msg() -> Weight; + fn on_idle_overweight_large_msg() -> Weight; +} + +/// Weights for `cumulus_pallet_dmp_queue` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) + } +} diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 76a77651cac..1c26b3a7486 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -16,8 +16,10 @@ trie-db = { version = "0.28.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} +pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } sp-core = { path = "../../../substrate/primitives/core", default-features = false} sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false} sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false} @@ -42,6 +44,7 @@ cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inh assert_matches = "1.5" hex-literal = "0.4.1" lazy_static = "1.4" +rand = "0.8.5" # Substrate sc-client-api = { path = "../../../substrate/client/api" } @@ -62,9 +65,11 @@ std = [ "cumulus-primitives-core/std", "cumulus-primitives-parachain-inherent/std", "environmental/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", + "pallet-message-queue/std", "polkadot-parachain-primitives/std", "polkadot-runtime-parachains/std", "scale-info/std", @@ -75,14 +80,19 @@ std = [ "sp-runtime/std", "sp-state-machine/std", "sp-std/std", + "sp-tracing/std", "sp-trie/std", "trie-db/std", "xcm/std", ] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-test-client/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -91,6 +101,7 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-message-queue/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] diff --git a/cumulus/pallets/parachain-system/src/benchmarking.rs b/cumulus/pallets/parachain-system/src/benchmarking.rs new file mode 100644 index 00000000000..5cde8eb5b78 --- /dev/null +++ b/cumulus/pallets/parachain-system/src/benchmarking.rs @@ -0,0 +1,68 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarking for the parachain-system pallet. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use cumulus_primitives_core::relay_chain::Hash as RelayHash; +use frame_benchmarking::v2::*; +use sp_runtime::traits::BlakeTwo256; + +#[benchmarks] +mod benchmarks { + use super::*; + + /// Enqueue `n` messages via `enqueue_inbound_downward_messages`. + /// + /// The limit is set to `1000` for benchmarking purposes as the actual limit is only known at + /// runtime. However, the limit (and default) for Dotsama are magnitudes smaller. + #[benchmark] + fn enqueue_inbound_downward_messages(n: Linear<0, 1000>) { + let msg = InboundDownwardMessage { + sent_at: n, // The block number does not matter. + msg: vec![0u8; MaxDmpMessageLenOf::::get() as usize], + }; + let msgs = vec![msg; n as usize]; + let head = mqp_head(&msgs); + + #[block] + { + Pallet::::enqueue_inbound_downward_messages(head, msgs); + } + + assert_eq!(ProcessedDownwardMessages::::get(), n); + assert_eq!(LastDmqMqcHead::::get().head(), head); + } + + /// Re-implements an easy version of the `MessageQueueChain` for testing purposes. + fn mqp_head(msgs: &Vec) -> RelayHash { + let mut head = Default::default(); + for msg in msgs.iter() { + let msg_hash = BlakeTwo256::hash_of(&msg.msg); + head = BlakeTwo256::hash_of(&(head, msg.sent_at, msg_hash)); + } + head + } + + impl_benchmark_test_suite! { + Pallet, + crate::mock::new_test_ext(), + crate::mock::Test + } +} diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 84b4cda1534..bac1ee28a7c 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -30,16 +30,17 @@ use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_primitives_core::{ relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, - DmpMessageHandler, GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, - MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, - UpwardMessageSender, XcmpMessageHandler, XcmpMessageSource, + GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, MessageSendError, + OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, + XcmpMessageHandler, XcmpMessageSource, }; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ + defensive, dispatch::{DispatchResult, Pays, PostDispatchInfo}, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, - traits::Get, + traits::{Get, HandleMessage}, weights::Weight, }; use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor}; @@ -52,15 +53,20 @@ use sp_runtime::{ InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity, ValidTransaction, }, - DispatchError, FixedU128, RuntimeDebug, Saturating, + BoundedSlice, DispatchError, FixedU128, RuntimeDebug, Saturating, }; use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; use xcm::latest::XcmHash; +mod benchmarking; pub mod migration; - +mod mock; #[cfg(test)] mod tests; +pub mod weights; + +pub use weights::WeightInfo; + mod unincluded_segment; pub mod consensus_hook; @@ -177,6 +183,9 @@ where check_version: bool, } +/// The max length of a DMP message. +pub type MaxDmpMessageLenOf = <::DmpQueue as HandleMessage>::MaxMessageLen; + pub mod ump_constants { use super::FixedU128; @@ -216,17 +225,18 @@ pub mod pallet { /// The place where outbound XCMP messages come from. This is queried in `finalize_block`. type OutboundXcmpMessageSource: XcmpMessageSource; - /// The message handler that will be invoked when messages are received via DMP. - type DmpMessageHandler: DmpMessageHandler; + /// Queues inbound downward messages for delayed processing. + /// + /// All inbound DMP messages from the relay are pushed into this. The handler is expected to + /// eventually process all the messages that are pushed to it. + type DmpQueue: HandleMessage; /// The weight we reserve at the beginning of the block for processing DMP messages. type ReservedDmpWeight: Get; /// The message handler that will be invoked when messages are received via XCMP. /// - /// The messages are dispatched in the order they were relayed by the relay chain. If - /// multiple messages were relayed at one block, these will be dispatched in ascending - /// order of the sender's para ID. + /// This should normally link to the XCMP Queue pallet. type XcmpMessageHandler: XcmpMessageHandler; /// The weight we reserve at the beginning of the block for processing XCMP messages. @@ -235,6 +245,9 @@ pub mod pallet { /// Something that can check the associated relay parent block number. type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber; + /// Weight info for functions and calls. + type WeightInfo: WeightInfo; + /// An entry-point for higher-level logic to manage the backlog of unincluded parachain /// blocks and authorship rights for those blocks. /// @@ -631,15 +644,15 @@ pub mod pallet { ::on_validation_data(&vfp); - total_weight += Self::process_inbound_downward_messages( + total_weight.saturating_accrue(Self::enqueue_inbound_downward_messages( relevant_messaging_state.dmq_mqc_head, downward_messages, - ); - total_weight += Self::process_inbound_horizontal_messages( + )); + total_weight.saturating_accrue(Self::enqueue_inbound_horizontal_messages( &relevant_messaging_state.ingress_channels, horizontal_messages, vfp.relay_parent_number, - ); + )); Ok(PostDispatchInfo { actual_weight: Some(total_weight), pays_fee: Pays::No }) } @@ -1130,7 +1143,7 @@ impl Pallet { // inherent. } - /// Process all inbound downward messages relayed by the collator. + /// Enqueue all inbound downward messages relayed by the collator into the MQ pallet. /// /// Checks if the sequence of the messages is valid, dispatches them and communicates the /// number of processed messages to the collator via a storage update. @@ -1139,26 +1152,33 @@ impl Pallet { /// /// If it turns out that after processing all messages the Message Queue Chain /// hash doesn't match the expected. - fn process_inbound_downward_messages( + fn enqueue_inbound_downward_messages( expected_dmq_mqc_head: relay_chain::Hash, downward_messages: Vec, ) -> Weight { let dm_count = downward_messages.len() as u32; let mut dmq_head = >::get(); - let mut weight_used = Weight::zero(); + let weight_used = T::WeightInfo::enqueue_inbound_downward_messages(dm_count); if dm_count != 0 { Self::deposit_event(Event::DownwardMessagesReceived { count: dm_count }); - let max_weight = - >::get().unwrap_or_else(T::ReservedDmpWeight::get); - - let message_iter = downward_messages - .into_iter() - .inspect(|m| { - dmq_head.extend_downward(m); - }) - .map(|m| (m.sent_at, m.msg)); - weight_used += T::DmpMessageHandler::handle_dmp_messages(message_iter, max_weight); + + // Eagerly update the MQC head hash: + for m in &downward_messages { + dmq_head.extend_downward(m); + } + let bounded = downward_messages + .iter() + // Note: we are not using `.defensive()` here since that prints the whole value to + // console. In case that the message is too long, this clogs up the log quite badly. + .filter_map(|m| match BoundedSlice::try_from(&m.msg[..]) { + Ok(bounded) => Some(bounded), + Err(_) => { + defensive!("Inbound Downward message was too long; dropping"); + None + }, + }); + T::DmpQueue::handle_messages(bounded); >::put(&dmq_head); Self::deposit_event(Event::DownwardMessagesProcessed { @@ -1181,14 +1201,15 @@ impl Pallet { /// Process all inbound horizontal messages relayed by the collator. /// - /// This is similar to `Pallet::process_inbound_downward_messages`, but works on multiple - /// inbound channels. + /// This is similar to [`enqueue_inbound_downward_messages`], but works with multiple inbound + /// channels. It immediately dispatches signals and queues all other XCMs. Blob messages are + /// ignored. /// /// **Panics** if either any of horizontal messages submitted by the collator was sent from /// a para which has no open channel to this parachain or if after processing /// messages across all inbound channels MQCs were obtained which do not /// correspond to the ones found on the relay-chain. - fn process_inbound_horizontal_messages( + fn enqueue_inbound_horizontal_messages( ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)], horizontal_messages: BTreeMap>, relay_parent_number: relay_chain::BlockNumber, diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs new file mode 100644 index 00000000000..b76553a5384 --- /dev/null +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -0,0 +1,485 @@ +// 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 . + +//! Test setup and helpers. + +#![cfg(test)] + +use super::*; + +use codec::Encode; +use cumulus_primitives_core::{ + relay_chain::BlockNumber as RelayBlockNumber, AggregateMessageOrigin, InboundDownwardMessage, + InboundHrmpMessage, PersistedValidationData, +}; +use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; +use frame_support::{ + derive_impl, + inherent::{InherentData, ProvideInherent}, + parameter_types, + traits::{ + OnFinalize, OnInitialize, ProcessMessage, ProcessMessageError, UnfilteredDispatchable, + }, + weights::{Weight, WeightMeter}, +}; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use sp_runtime::{traits::BlakeTwo256, BuildStorage}; +use sp_std::{collections::vec_deque::VecDeque, num::NonZeroU32}; +use sp_version::RuntimeVersion; +use std::cell::RefCell; + +use crate as parachain_system; +use crate::consensus_hook::UnincludedSegmentCapacity; + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + ParachainSystem: parachain_system::{Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned}, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub Version: RuntimeVersion = RuntimeVersion { + spec_name: sp_version::create_runtime_str!("test"), + impl_name: sp_version::create_runtime_str!("system-test"), + authoring_version: 1, + spec_version: 1, + impl_version: 1, + apis: sp_version::create_apis_vec!([]), + transaction_version: 1, + state_version: 1, + }; + pub const ParachainId: ParaId = ParaId::new(200); + pub const ReservedXcmpWeight: Weight = Weight::zero(); + pub const ReservedDmpWeight: Weight = Weight::zero(); +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type BlockHashCount = BlockHashCount; + type Version = Version; + type OnSetCode = ParachainSetCode; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainId; + type OutboundXcmpMessageSource = FromThreadLocal; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = SaveIntoThreadLocal; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = AnyRelayNumber; + type ConsensusHook = TestConsensusHook; + type WeightInfo = (); +} + +std::thread_local! { + pub static CONSENSUS_HOOK: RefCell (Weight, UnincludedSegmentCapacity)>> + = RefCell::new(Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into()))); +} + +pub struct TestConsensusHook; + +impl ConsensusHook for TestConsensusHook { + fn on_state_proof(s: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) { + CONSENSUS_HOOK.with(|f| f.borrow_mut()(s)) + } +} + +parameter_types! { + pub const MaxWeight: Weight = Weight::MAX; +} + +impl pallet_message_queue::Config for Test { + type RuntimeEvent = RuntimeEvent; + // NOTE that normally for benchmarking we should use the No-OP message processor, but in this + // case its a mocked runtime and will only be used to generate insecure default weights. + type MessageProcessor = SaveIntoThreadLocal; + type Size = u32; + type QueueChangeHandler = (); + type QueuePausedQuery = (); + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MaxWeight; + type WeightInfo = (); +} + +/// A `XcmpMessageSource` that takes messages from thread-local. +pub struct FromThreadLocal; + +/// A `MessageProcessor` that stores all messages in thread-local. +pub struct SaveIntoThreadLocal; + +std::thread_local! { + pub static HANDLED_DMP_MESSAGES: RefCell>> = RefCell::new(Vec::new()); + pub static HANDLED_XCMP_MESSAGES: RefCell)>> = RefCell::new(Vec::new()); + pub static SENT_MESSAGES: RefCell)>> = RefCell::new(Vec::new()); +} + +pub fn send_message(dest: ParaId, message: Vec) { + SENT_MESSAGES.with(|m| m.borrow_mut().push((dest, message))); +} + +impl XcmpMessageSource for FromThreadLocal { + fn take_outbound_messages(maximum_channels: usize) -> Vec<(ParaId, Vec)> { + let mut ids = std::collections::BTreeSet::::new(); + let mut taken_messages = 0; + let mut taken_bytes = 0; + let mut result = Vec::new(); + SENT_MESSAGES.with(|ms| { + ms.borrow_mut().retain(|m| { + let status = as GetChannelInfo>::get_channel_status(m.0); + let (max_size_now, max_size_ever) = match status { + ChannelStatus::Ready(now, ever) => (now, ever), + ChannelStatus::Closed => return false, // drop message + ChannelStatus::Full => return true, // keep message queued. + }; + + let msg_len = m.1.len(); + + if !ids.contains(&m.0) && + taken_messages < maximum_channels && + msg_len <= max_size_ever && + taken_bytes + msg_len <= max_size_now + { + ids.insert(m.0); + taken_messages += 1; + taken_bytes += msg_len; + result.push(m.clone()); + false + } else { + true + } + }) + }); + result + } +} + +impl ProcessMessage for SaveIntoThreadLocal { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + _meter: &mut WeightMeter, + _id: &mut [u8; 32], + ) -> Result { + assert_eq!(origin, Self::Origin::Parent); + + HANDLED_DMP_MESSAGES.with(|m| { + m.borrow_mut().push(message.to_vec()); + Weight::zero() + }); + Ok(true) + } +} + +impl XcmpMessageHandler for SaveIntoThreadLocal { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + _max_weight: Weight, + ) -> Weight { + HANDLED_XCMP_MESSAGES.with(|m| { + for (sender, sent_at, message) in iter { + m.borrow_mut().push((sender, sent_at, message.to_vec())); + } + Weight::zero() + }) + } +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + HANDLED_DMP_MESSAGES.with(|m| m.borrow_mut().clear()); + HANDLED_XCMP_MESSAGES.with(|m| m.borrow_mut().clear()); + + frame_system::GenesisConfig::::default().build_storage().unwrap().into() +} + +#[allow(dead_code)] +pub fn mk_dmp(sent_at: u32) -> InboundDownwardMessage { + InboundDownwardMessage { sent_at, msg: format!("down{}", sent_at).into_bytes() } +} + +pub fn mk_hrmp(sent_at: u32) -> InboundHrmpMessage { + InboundHrmpMessage { sent_at, data: format!("{}", sent_at).into_bytes() } +} + +pub struct ReadRuntimeVersion(pub Vec); + +impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion { + fn read_runtime_version( + &self, + _wasm_code: &[u8], + _ext: &mut dyn sp_externalities::Externalities, + ) -> Result, String> { + Ok(self.0.clone()) + } +} + +pub fn wasm_ext() -> sp_io::TestExternalities { + let version = RuntimeVersion { + spec_name: "test".into(), + spec_version: 2, + impl_version: 1, + ..Default::default() + }; + + let mut ext = new_test_ext(); + ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion( + version.encode(), + ))); + ext +} + +pub struct BlockTest { + n: BlockNumberFor, + within_block: Box, + after_block: Option>, +} + +/// BlockTests exist to test blocks with some setup: we have to assume that +/// `validate_block` will mutate and check storage in certain predictable +/// ways, for example, and we want to always ensure that tests are executed +/// in the context of some particular block number. +#[derive(Default)] +pub struct BlockTests { + tests: Vec, + without_externalities: bool, + pending_upgrade: Option, + ran: bool, + relay_sproof_builder_hook: + Option>, + inherent_data_hook: + Option>, + inclusion_delay: Option, + relay_block_number: Option) -> RelayChainBlockNumber>>, + + included_para_head: Option, + pending_blocks: VecDeque, +} + +impl BlockTests { + pub fn new() -> BlockTests { + Default::default() + } + + pub fn new_without_externalities() -> BlockTests { + let mut tests = BlockTests::new(); + tests.without_externalities = true; + tests + } + + pub fn add_raw(mut self, test: BlockTest) -> Self { + self.tests.push(test); + self + } + + pub fn add(self, n: BlockNumberFor, within_block: F) -> Self + where + F: 'static + Fn(), + { + self.add_raw(BlockTest { n, within_block: Box::new(within_block), after_block: None }) + } + + pub fn add_with_post_test( + self, + n: BlockNumberFor, + within_block: F1, + after_block: F2, + ) -> Self + where + F1: 'static + Fn(), + F2: 'static + Fn(), + { + self.add_raw(BlockTest { + n, + within_block: Box::new(within_block), + after_block: Some(Box::new(after_block)), + }) + } + + pub fn with_relay_sproof_builder(mut self, f: F) -> Self + where + F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut RelayStateSproofBuilder), + { + self.relay_sproof_builder_hook = Some(Box::new(f)); + self + } + + pub fn with_relay_block_number(mut self, f: F) -> Self + where + F: 'static + Fn(&BlockNumberFor) -> RelayChainBlockNumber, + { + self.relay_block_number = Some(Box::new(f)); + self + } + + pub fn with_inherent_data(mut self, f: F) -> Self + where + F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut ParachainInherentData), + { + self.inherent_data_hook = Some(Box::new(f)); + self + } + + pub fn with_inclusion_delay(mut self, inclusion_delay: usize) -> Self { + self.inclusion_delay.replace(inclusion_delay); + self + } + + pub fn run(&mut self) { + wasm_ext().execute_with(|| { + self.run_without_ext(); + }); + } + + pub fn run_without_ext(&mut self) { + self.ran = true; + + let mut parent_head_data = { + let header = HeaderFor::::new_from_number(0); + relay_chain::HeadData(header.encode()) + }; + + self.included_para_head = Some(parent_head_data.clone()); + + for BlockTest { n, within_block, after_block } in self.tests.iter() { + let relay_parent_number = self + .relay_block_number + .as_ref() + .map(|f| f(n)) + .unwrap_or(*n as RelayChainBlockNumber); + // clear pending updates, as applicable + if let Some(upgrade_block) = self.pending_upgrade { + if n >= &upgrade_block.into() { + self.pending_upgrade = None; + } + } + + // begin initialization + let parent_hash = BlakeTwo256::hash(&parent_head_data.0); + System::reset_events(); + System::initialize(n, &parent_hash, &Default::default()); + + // now mess with the storage the way validate_block does + let mut sproof_builder = RelayStateSproofBuilder::default(); + sproof_builder.included_para_head = self + .included_para_head + .clone() + .unwrap_or_else(|| parent_head_data.clone()) + .into(); + if let Some(ref hook) = self.relay_sproof_builder_hook { + hook(self, relay_parent_number, &mut sproof_builder); + } + let (relay_parent_storage_root, relay_chain_state) = + sproof_builder.into_state_root_and_proof(); + let vfp = PersistedValidationData { + relay_parent_number, + relay_parent_storage_root, + ..Default::default() + }; + + >::put(&vfp); + NewValidationCode::::kill(); + + // It is insufficient to push the validation function params + // to storage; they must also be included in the inherent data. + let inherent_data = { + let mut inherent_data = InherentData::default(); + let mut system_inherent_data = ParachainInherentData { + validation_data: vfp.clone(), + relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + if let Some(ref hook) = self.inherent_data_hook { + hook(self, relay_parent_number, &mut system_inherent_data); + } + inherent_data + .put_data( + cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER, + &system_inherent_data, + ) + .expect("failed to put VFP inherent"); + inherent_data + }; + + // execute the block + ParachainSystem::on_initialize(*n); + ParachainSystem::create_inherent(&inherent_data) + .expect("got an inherent") + .dispatch_bypass_filter(RawOrigin::None.into()) + .expect("dispatch succeeded"); + MessageQueue::on_initialize(*n); + within_block(); + MessageQueue::on_finalize(*n); + ParachainSystem::on_finalize(*n); + + // did block execution set new validation code? + if NewValidationCode::::exists() && self.pending_upgrade.is_some() { + panic!("attempted to set validation code while upgrade was pending"); + } + + // clean up + let header = System::finalize(); + let head_data = relay_chain::HeadData(header.encode()); + parent_head_data = head_data.clone(); + match self.inclusion_delay { + Some(delay) if delay > 0 => { + self.pending_blocks.push_back(head_data); + if self.pending_blocks.len() > delay { + let included = self.pending_blocks.pop_front().unwrap(); + + self.included_para_head.replace(included); + } + }, + _ => { + self.included_para_head.replace(head_data); + }, + } + + if let Some(after_block) = after_block { + after_block(); + } + } + } +} + +impl Drop for BlockTests { + fn drop(&mut self) { + if !self.ran { + if self.without_externalities { + self.run_without_ext(); + } else { + self.run(); + } + } + } +} diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 7db6a966ec9..ab1775b40a8 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -13,433 +13,20 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . + +#![cfg(test)] + use super::*; +use crate::mock::*; -use codec::Encode; -use cumulus_primitives_core::{ - relay_chain::BlockNumber as RelayBlockNumber, AbridgedHrmpChannel, InboundDownwardMessage, - InboundHrmpMessage, PersistedValidationData, -}; -use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; -use frame_support::{ - assert_ok, - inherent::{InherentData, ProvideInherent}, - parameter_types, - traits::{OnFinalize, OnInitialize, UnfilteredDispatchable}, - weights::Weight, -}; -use frame_system::{ - pallet_prelude::{BlockNumberFor, HeaderFor}, - RawOrigin, -}; +use cumulus_primitives_core::{AbridgedHrmpChannel, InboundDownwardMessage, InboundHrmpMessage}; +use frame_support::{assert_ok, parameter_types, weights::Weight}; +use frame_system::RawOrigin; use hex_literal::hex; +use rand::Rng; use relay_chain::HrmpChannelId; -use sp_core::{blake2_256, H256}; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, DispatchErrorWithPostInfo, -}; -use sp_std::{collections::vec_deque::VecDeque, num::NonZeroU32}; -use sp_version::RuntimeVersion; -use std::cell::RefCell; - -use crate as parachain_system; -use crate::consensus_hook::UnincludedSegmentCapacity; - -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Test - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - ParachainSystem: parachain_system::{Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned}, - } -); - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub Version: RuntimeVersion = RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("system-test"), - authoring_version: 1, - spec_version: 1, - impl_version: 1, - apis: sp_version::create_apis_vec!([]), - transaction_version: 1, - state_version: 1, - }; - pub const ParachainId: ParaId = ParaId::new(200); - pub const ReservedXcmpWeight: Weight = Weight::zero(); - pub const ReservedDmpWeight: Weight = Weight::zero(); -} -impl frame_system::Config for Test { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockLength = (); - type BlockWeights = (); - type Version = Version; - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = ParachainId; - type OutboundXcmpMessageSource = FromThreadLocal; - type DmpMessageHandler = SaveIntoThreadLocal; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = SaveIntoThreadLocal; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = AnyRelayNumber; - type ConsensusHook = TestConsensusHook; -} - -pub struct FromThreadLocal; -pub struct SaveIntoThreadLocal; - -std::thread_local! { - static HANDLED_DMP_MESSAGES: RefCell)>> = RefCell::new(Vec::new()); - static HANDLED_XCMP_MESSAGES: RefCell)>> = RefCell::new(Vec::new()); - static SENT_MESSAGES: RefCell)>> = RefCell::new(Vec::new()); - static CONSENSUS_HOOK: RefCell (Weight, UnincludedSegmentCapacity)>> - = RefCell::new(Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into()))); -} - -pub struct TestConsensusHook; - -impl ConsensusHook for TestConsensusHook { - fn on_state_proof(s: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) { - CONSENSUS_HOOK.with(|f| f.borrow_mut()(s)) - } -} - -fn send_message(dest: ParaId, message: Vec) { - SENT_MESSAGES.with(|m| m.borrow_mut().push((dest, message))); -} - -impl XcmpMessageSource for FromThreadLocal { - fn take_outbound_messages(maximum_channels: usize) -> Vec<(ParaId, Vec)> { - let mut ids = std::collections::BTreeSet::::new(); - let mut taken_messages = 0; - let mut taken_bytes = 0; - let mut result = Vec::new(); - SENT_MESSAGES.with(|ms| { - ms.borrow_mut().retain(|m| { - let status = as GetChannelInfo>::get_channel_status(m.0); - let (max_size_now, max_size_ever) = match status { - ChannelStatus::Ready(now, ever) => (now, ever), - ChannelStatus::Closed => return false, // drop message - ChannelStatus::Full => return true, // keep message queued. - }; - - let msg_len = m.1.len(); - - if !ids.contains(&m.0) && - taken_messages < maximum_channels && - msg_len <= max_size_ever && - taken_bytes + msg_len <= max_size_now - { - ids.insert(m.0); - taken_messages += 1; - taken_bytes += msg_len; - result.push(m.clone()); - false - } else { - true - } - }) - }); - result - } -} - -impl DmpMessageHandler for SaveIntoThreadLocal { - fn handle_dmp_messages( - iter: impl Iterator)>, - _max_weight: Weight, - ) -> Weight { - HANDLED_DMP_MESSAGES.with(|m| { - for i in iter { - m.borrow_mut().push(i); - } - Weight::zero() - }) - } -} - -impl XcmpMessageHandler for SaveIntoThreadLocal { - fn handle_xcmp_messages<'a, I: Iterator>( - iter: I, - _max_weight: Weight, - ) -> Weight { - HANDLED_XCMP_MESSAGES.with(|m| { - for (sender, sent_at, message) in iter { - m.borrow_mut().push((sender, sent_at, message.to_vec())); - } - Weight::zero() - }) - } -} - -// This function basically just builds a genesis storage key/value store according to -// our desired mockup. -fn new_test_ext() -> sp_io::TestExternalities { - HANDLED_DMP_MESSAGES.with(|m| m.borrow_mut().clear()); - HANDLED_XCMP_MESSAGES.with(|m| m.borrow_mut().clear()); - - frame_system::GenesisConfig::::default().build_storage().unwrap().into() -} - -struct ReadRuntimeVersion(Vec); - -impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion { - fn read_runtime_version( - &self, - _wasm_code: &[u8], - _ext: &mut dyn sp_externalities::Externalities, - ) -> Result, String> { - Ok(self.0.clone()) - } -} - -fn wasm_ext() -> sp_io::TestExternalities { - let version = RuntimeVersion { - spec_name: "test".into(), - spec_version: 2, - impl_version: 1, - ..Default::default() - }; - - let mut ext = new_test_ext(); - ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion( - version.encode(), - ))); - ext -} - -struct BlockTest { - n: BlockNumberFor, - within_block: Box, - after_block: Option>, -} - -/// BlockTests exist to test blocks with some setup: we have to assume that -/// `validate_block` will mutate and check storage in certain predictable -/// ways, for example, and we want to always ensure that tests are executed -/// in the context of some particular block number. -#[derive(Default)] -struct BlockTests { - tests: Vec, - pending_upgrade: Option, - ran: bool, - relay_sproof_builder_hook: - Option>, - inherent_data_hook: - Option>, - inclusion_delay: Option, - relay_block_number: Option) -> RelayChainBlockNumber>>, - - included_para_head: Option, - pending_blocks: VecDeque, -} - -impl BlockTests { - fn new() -> BlockTests { - Default::default() - } - - fn add_raw(mut self, test: BlockTest) -> Self { - self.tests.push(test); - self - } - - fn add(self, n: BlockNumberFor, within_block: F) -> Self - where - F: 'static + Fn(), - { - self.add_raw(BlockTest { n, within_block: Box::new(within_block), after_block: None }) - } - - fn add_with_post_test( - self, - n: BlockNumberFor, - within_block: F1, - after_block: F2, - ) -> Self - where - F1: 'static + Fn(), - F2: 'static + Fn(), - { - self.add_raw(BlockTest { - n, - within_block: Box::new(within_block), - after_block: Some(Box::new(after_block)), - }) - } - - fn with_relay_sproof_builder(mut self, f: F) -> Self - where - F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut RelayStateSproofBuilder), - { - self.relay_sproof_builder_hook = Some(Box::new(f)); - self - } - - fn with_relay_block_number(mut self, f: F) -> Self - where - F: 'static + Fn(&BlockNumberFor) -> RelayChainBlockNumber, - { - self.relay_block_number = Some(Box::new(f)); - self - } - - fn with_inherent_data(mut self, f: F) -> Self - where - F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut ParachainInherentData), - { - self.inherent_data_hook = Some(Box::new(f)); - self - } - - fn with_inclusion_delay(mut self, inclusion_delay: usize) -> Self { - self.inclusion_delay.replace(inclusion_delay); - self - } - - fn run(&mut self) { - self.ran = true; - wasm_ext().execute_with(|| { - let mut parent_head_data = { - let header = HeaderFor::::new_from_number(0); - relay_chain::HeadData(header.encode()) - }; - - self.included_para_head = Some(parent_head_data.clone()); - - for BlockTest { n, within_block, after_block } in self.tests.iter() { - let relay_parent_number = self - .relay_block_number - .as_ref() - .map(|f| f(n)) - .unwrap_or(*n as RelayChainBlockNumber); - // clear pending updates, as applicable - if let Some(upgrade_block) = self.pending_upgrade { - if n >= &upgrade_block.into() { - self.pending_upgrade = None; - } - } - - // begin initialization - let parent_hash = BlakeTwo256::hash(&parent_head_data.0); - System::reset_events(); - System::initialize(n, &parent_hash, &Default::default()); - - // now mess with the storage the way validate_block does - let mut sproof_builder = RelayStateSproofBuilder::default(); - sproof_builder.included_para_head = self - .included_para_head - .clone() - .unwrap_or_else(|| parent_head_data.clone()) - .into(); - if let Some(ref hook) = self.relay_sproof_builder_hook { - hook(self, relay_parent_number, &mut sproof_builder); - } - let (relay_parent_storage_root, relay_chain_state) = - sproof_builder.into_state_root_and_proof(); - let vfp = PersistedValidationData { - relay_parent_number, - relay_parent_storage_root, - ..Default::default() - }; - - >::put(&vfp); - NewValidationCode::::kill(); - - // It is insufficient to push the validation function params - // to storage; they must also be included in the inherent data. - let inherent_data = { - let mut inherent_data = InherentData::default(); - let mut system_inherent_data = ParachainInherentData { - validation_data: vfp.clone(), - relay_chain_state, - downward_messages: Default::default(), - horizontal_messages: Default::default(), - }; - if let Some(ref hook) = self.inherent_data_hook { - hook(self, relay_parent_number, &mut system_inherent_data); - } - inherent_data - .put_data( - cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER, - &system_inherent_data, - ) - .expect("failed to put VFP inherent"); - inherent_data - }; - - // execute the block - ParachainSystem::on_initialize(*n); - ParachainSystem::create_inherent(&inherent_data) - .expect("got an inherent") - .dispatch_bypass_filter(RawOrigin::None.into()) - .expect("dispatch succeeded"); - within_block(); - ParachainSystem::on_finalize(*n); - - // did block execution set new validation code? - if NewValidationCode::::exists() && self.pending_upgrade.is_some() { - panic!("attempted to set validation code while upgrade was pending"); - } - - // clean up - let header = System::finalize(); - let head_data = relay_chain::HeadData(header.encode()); - parent_head_data = head_data.clone(); - match self.inclusion_delay { - Some(delay) if delay > 0 => { - self.pending_blocks.push_back(head_data); - if self.pending_blocks.len() > delay { - let included = self.pending_blocks.pop_front().unwrap(); - - self.included_para_head.replace(included); - } - }, - _ => { - self.included_para_head.replace(head_data); - }, - } - - if let Some(after_block) = after_block { - after_block(); - } - } - }); - } -} - -impl Drop for BlockTests { - fn drop(&mut self) { - if !self.ran { - self.run(); - } - } -} +use sp_core::H256; +use sp_std::num::NonZeroU32; #[test] #[should_panic] @@ -659,30 +246,6 @@ fn inherent_processed_messages_are_ignored() { CONSENSUS_HOOK.with(|c| { *c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(2).unwrap().into())) }); - lazy_static::lazy_static! { - static ref DMQ_MSG: InboundDownwardMessage = InboundDownwardMessage { - sent_at: 3, - msg: b"down".to_vec(), - }; - - static ref XCMP_MSG_1: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 2, - data: b"h1".to_vec(), - }; - - static ref XCMP_MSG_2: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 3, - data: b"h2".to_vec(), - }; - - static ref EXPECTED_PROCESSED_DMQ: Vec<(RelayChainBlockNumber, Vec)> = vec![ - (DMQ_MSG.sent_at, DMQ_MSG.msg.clone()) - ]; - static ref EXPECTED_PROCESSED_XCMP: Vec<(ParaId, RelayChainBlockNumber, Vec)> = vec![ - (ParaId::from(200), XCMP_MSG_1.sent_at, XCMP_MSG_1.data.clone()), - (ParaId::from(200), XCMP_MSG_2.sent_at, XCMP_MSG_2.data.clone()), - ]; - } BlockTests::new() .with_inclusion_delay(1) @@ -690,11 +253,11 @@ fn inherent_processed_messages_are_ignored() { .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { 3 => { sproof.dmq_mqc_head = - Some(MessageQueueChain::default().extend_downward(&DMQ_MSG).head()); + Some(MessageQueueChain::default().extend_downward(&mk_dmp(3)).head()); sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head = Some( MessageQueueChain::default() - .extend_hrmp(&XCMP_MSG_1) - .extend_hrmp(&XCMP_MSG_2) + .extend_hrmp(&mk_hrmp(2)) + .extend_hrmp(&mk_hrmp(3)) .head(), ); }, @@ -702,9 +265,8 @@ fn inherent_processed_messages_are_ignored() { }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 3 => { - data.downward_messages.push(DMQ_MSG.clone()); - data.horizontal_messages - .insert(ParaId::from(200), vec![XCMP_MSG_1.clone(), XCMP_MSG_2.clone()]); + data.downward_messages.push(mk_dmp(3)); + data.horizontal_messages.insert(ParaId::from(200), vec![mk_hrmp(2), mk_hrmp(3)]); }, _ => unreachable!(), }) @@ -712,22 +274,29 @@ fn inherent_processed_messages_are_ignored() { // Don't drop processed messages for this test. HANDLED_DMP_MESSAGES.with(|m| { let m = m.borrow(); - assert_eq!(&*m, EXPECTED_PROCESSED_DMQ.as_slice()); + // NOTE: if this fails, then run the test without benchmark features. + assert_eq!(&*m, &[mk_dmp(3).msg]); }); HANDLED_XCMP_MESSAGES.with(|m| { let m = m.borrow_mut(); - assert_eq!(&*m, EXPECTED_PROCESSED_XCMP.as_slice()); + assert_eq!( + &*m, + &[(ParaId::from(200), 2, b"2".to_vec()), (ParaId::from(200), 3, b"3".to_vec()),] + ); }); }) .add(2, || {}) .add(3, || { HANDLED_DMP_MESSAGES.with(|m| { let m = m.borrow(); - assert_eq!(&*m, EXPECTED_PROCESSED_DMQ.as_slice()); + assert_eq!(&*m, &[mk_dmp(3).msg]); }); HANDLED_XCMP_MESSAGES.with(|m| { let m = m.borrow_mut(); - assert_eq!(&*m, EXPECTED_PROCESSED_XCMP.as_slice()); + assert_eq!( + &*m, + &[(ParaId::from(200), 2, b"2".to_vec()), (ParaId::from(200), 3, b"3".to_vec()),] + ); }); }); } @@ -1183,6 +752,7 @@ fn message_queue_chain() { } #[test] +#[cfg(not(feature = "runtime-benchmarks"))] fn receive_dmp() { lazy_static::lazy_static! { static ref MSG: InboundDownwardMessage = InboundDownwardMessage { @@ -1208,41 +778,31 @@ fn receive_dmp() { .add(1, || { HANDLED_DMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(MSG.sent_at, MSG.msg.clone())]); + assert_eq!(&*m, &[(MSG.msg.clone())]); m.clear(); }); }); } #[test] +#[cfg(not(feature = "runtime-benchmarks"))] fn receive_dmp_after_pause() { - lazy_static::lazy_static! { - static ref MSG_1: InboundDownwardMessage = InboundDownwardMessage { - sent_at: 1, - msg: b"down1".to_vec(), - }; - static ref MSG_2: InboundDownwardMessage = InboundDownwardMessage { - sent_at: 3, - msg: b"down2".to_vec(), - }; - } - BlockTests::new() .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { 1 => { sproof.dmq_mqc_head = - Some(MessageQueueChain::default().extend_downward(&MSG_1).head()); + Some(MessageQueueChain::default().extend_downward(&mk_dmp(1)).head()); }, 2 => { // no new messages, mqc stayed the same. sproof.dmq_mqc_head = - Some(MessageQueueChain::default().extend_downward(&MSG_1).head()); + Some(MessageQueueChain::default().extend_downward(&mk_dmp(1)).head()); }, 3 => { sproof.dmq_mqc_head = Some( MessageQueueChain::default() - .extend_downward(&MSG_1) - .extend_downward(&MSG_2) + .extend_downward(&mk_dmp(1)) + .extend_downward(&mk_dmp(3)) .head(), ); }, @@ -1250,20 +810,20 @@ fn receive_dmp_after_pause() { }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 1 => { - data.downward_messages.push(MSG_1.clone()); + data.downward_messages.push(mk_dmp(1)); }, 2 => { // no new messages }, 3 => { - data.downward_messages.push(MSG_2.clone()); + data.downward_messages.push(mk_dmp(3)); }, _ => unreachable!(), }) .add(1, || { HANDLED_DMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(MSG_1.sent_at, MSG_1.msg.clone())]); + assert_eq!(&*m, &[(mk_dmp(1).msg.clone())]); m.clear(); }); }) @@ -1271,54 +831,88 @@ fn receive_dmp_after_pause() { .add(3, || { HANDLED_DMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(MSG_2.sent_at, MSG_2.msg.clone())]); + assert_eq!(&*m, &[(mk_dmp(3).msg.clone())]); m.clear(); }); }); } +// Sent up to 100 DMP messages per block over a period of 100 blocks. #[test] -fn receive_hrmp() { - lazy_static::lazy_static! { - static ref MSG_1: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 1, - data: b"1".to_vec(), - }; +#[cfg(not(feature = "runtime-benchmarks"))] +fn receive_dmp_many() { + wasm_ext().execute_with(|| { + parameter_types! { + pub storage MqcHead: MessageQueueChain = Default::default(); + pub storage SentInBlock: Vec> = Default::default(); + } - static ref MSG_2: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 2, - data: b"2".to_vec(), - }; + let mut sent_in_block = vec![vec![]]; + let mut rng = rand::thread_rng(); - static ref MSG_3: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 2, - data: b"3".to_vec(), - }; + for block in 1..100 { + let mut msgs = vec![]; + for _ in 1..=rng.gen_range(1..=100) { + // Just use the same message multiple times per block. + msgs.push(mk_dmp(block)); + } + sent_in_block.push(msgs); + } + SentInBlock::set(&sent_in_block); - static ref MSG_4: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 2, - data: b"4".to_vec(), - }; - } + let mut tester = BlockTests::new_without_externalities() + .with_relay_sproof_builder(|_, relay_block_num, sproof| { + let mut new_hash = MqcHead::get(); + + for msg in SentInBlock::get()[relay_block_num as usize].iter() { + new_hash.extend_downward(&msg); + } + + sproof.dmq_mqc_head = Some(new_hash.head()); + MqcHead::set(&new_hash); + }) + .with_inherent_data(|_, relay_block_num, data| { + for msg in SentInBlock::get()[relay_block_num as usize].iter() { + data.downward_messages.push(msg.clone()); + } + }); + for block in 1..100 { + tester = tester.add(block, move || { + HANDLED_DMP_MESSAGES.with(|m| { + let mut m = m.borrow_mut(); + let msgs = SentInBlock::get()[block as usize] + .iter() + .map(|m| m.msg.clone()) + .collect::>(); + assert_eq!(&*m, &msgs); + m.clear(); + }); + }); + } + }); +} + +#[test] +fn receive_hrmp() { BlockTests::new() .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { 1 => { // 200 - doesn't exist yet // 300 - one new message sproof.upsert_inbound_channel(ParaId::from(300)).mqc_head = - Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head()); + Some(MessageQueueChain::default().extend_hrmp(&mk_hrmp(1)).head()); }, 2 => { // 200 - now present with one message // 300 - two new messages sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head = - Some(MessageQueueChain::default().extend_hrmp(&MSG_4).head()); + Some(MessageQueueChain::default().extend_hrmp(&mk_hrmp(4)).head()); sproof.upsert_inbound_channel(ParaId::from(300)).mqc_head = Some( MessageQueueChain::default() - .extend_hrmp(&MSG_1) - .extend_hrmp(&MSG_2) - .extend_hrmp(&MSG_3) + .extend_hrmp(&mk_hrmp(1)) + .extend_hrmp(&mk_hrmp(2)) + .extend_hrmp(&mk_hrmp(3)) .head(), ); }, @@ -1326,13 +920,13 @@ fn receive_hrmp() { // 200 - no new messages // 300 - is gone sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head = - Some(MessageQueueChain::default().extend_hrmp(&MSG_4).head()); + Some(MessageQueueChain::default().extend_hrmp(&mk_hrmp(4)).head()); }, _ => unreachable!(), }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 1 => { - data.horizontal_messages.insert(ParaId::from(300), vec![MSG_1.clone()]); + data.horizontal_messages.insert(ParaId::from(300), vec![mk_hrmp(1)]); }, 2 => { data.horizontal_messages.insert( @@ -1341,11 +935,11 @@ fn receive_hrmp() { // can't be sent at the block 1 actually. However, we cheat here // because we want to test the case where there are multiple messages // but the harness at the moment doesn't support block skipping. - MSG_2.clone(), - MSG_3.clone(), + mk_hrmp(2).clone(), + mk_hrmp(3).clone(), ], ); - data.horizontal_messages.insert(ParaId::from(200), vec![MSG_4.clone()]); + data.horizontal_messages.insert(ParaId::from(200), vec![mk_hrmp(4)]); }, 3 => {}, _ => unreachable!(), @@ -1363,9 +957,9 @@ fn receive_hrmp() { assert_eq!( &*m, &[ - (ParaId::from(200), 2, b"4".to_vec()), (ParaId::from(300), 2, b"2".to_vec()), - (ParaId::from(300), 2, b"3".to_vec()), + (ParaId::from(300), 3, b"3".to_vec()), + (ParaId::from(200), 4, b"4".to_vec()), ] ); m.clear(); @@ -1394,55 +988,46 @@ fn receive_hrmp_empty_channel() { #[test] fn receive_hrmp_after_pause() { - lazy_static::lazy_static! { - static ref MSG_1: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 1, - data: b"mikhailinvanovich".to_vec(), - }; - - static ref MSG_2: InboundHrmpMessage = InboundHrmpMessage { - sent_at: 3, - data: b"1000000000".to_vec(), - }; - } - const ALICE: ParaId = ParaId::new(300); BlockTests::new() .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { 1 => { sproof.upsert_inbound_channel(ALICE).mqc_head = - Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head()); + Some(MessageQueueChain::default().extend_hrmp(&mk_hrmp(1)).head()); }, 2 => { // 300 - no new messages, mqc stayed the same. sproof.upsert_inbound_channel(ALICE).mqc_head = - Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head()); + Some(MessageQueueChain::default().extend_hrmp(&mk_hrmp(1)).head()); }, 3 => { // 300 - new message. sproof.upsert_inbound_channel(ALICE).mqc_head = Some( - MessageQueueChain::default().extend_hrmp(&MSG_1).extend_hrmp(&MSG_2).head(), + MessageQueueChain::default() + .extend_hrmp(&mk_hrmp(1)) + .extend_hrmp(&mk_hrmp(3)) + .head(), ); }, _ => unreachable!(), }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 1 => { - data.horizontal_messages.insert(ALICE, vec![MSG_1.clone()]); + data.horizontal_messages.insert(ALICE, vec![mk_hrmp(1)]); }, 2 => { // no new messages }, 3 => { - data.horizontal_messages.insert(ALICE, vec![MSG_2.clone()]); + data.horizontal_messages.insert(ALICE, vec![mk_hrmp(3)]); }, _ => unreachable!(), }) .add(1, || { HANDLED_XCMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(ALICE, 1, b"mikhailinvanovich".to_vec())]); + assert_eq!(&*m, &[(ALICE, 1, b"1".to_vec())]); m.clear(); }); }) @@ -1450,14 +1035,75 @@ fn receive_hrmp_after_pause() { .add(3, || { HANDLED_XCMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(ALICE, 3, b"1000000000".to_vec())]); + assert_eq!(&*m, &[(ALICE, 3, b"3".to_vec())]); m.clear(); }); }); } +// Sent up to 100 HRMP messages per block over a period of 100 blocks. +#[test] +fn receive_hrmp_many() { + const ALICE: ParaId = ParaId::new(300); + + wasm_ext().execute_with(|| { + parameter_types! { + pub storage MqcHead: MessageQueueChain = Default::default(); + pub storage SentInBlock: Vec> = Default::default(); + } + + let mut sent_in_block = vec![vec![]]; + let mut rng = rand::thread_rng(); + + for block in 1..100 { + let mut msgs = vec![]; + for _ in 1..=rng.gen_range(1..=100) { + // Just use the same message multiple times per block. + msgs.push(mk_hrmp(block)); + } + sent_in_block.push(msgs); + } + SentInBlock::set(&sent_in_block); + + let mut tester = BlockTests::new_without_externalities() + .with_relay_sproof_builder(|_, relay_block_num, sproof| { + let mut new_hash = MqcHead::get(); + + for msg in SentInBlock::get()[relay_block_num as usize].iter() { + new_hash.extend_hrmp(&msg); + } + + sproof.upsert_inbound_channel(ALICE).mqc_head = Some(new_hash.head()); + MqcHead::set(&new_hash); + }) + .with_inherent_data(|_, relay_block_num, data| { + // TODO use vector for dmp as well + data.horizontal_messages + .insert(ALICE, SentInBlock::get()[relay_block_num as usize].clone()); + }); + + for block in 1..100 { + tester = tester.add(block, move || { + HANDLED_XCMP_MESSAGES.with(|m| { + let mut m = m.borrow_mut(); + let msgs = SentInBlock::get()[block as usize] + .iter() + .map(|m| (ALICE, m.sent_at, m.data.clone())) + .collect::>(); + assert_eq!(&*m, &msgs); + m.clear(); + }); + }); + } + }); +} + #[test] fn upgrade_version_checks_should_work() { + use codec::Encode; + use sp_runtime::DispatchErrorWithPostInfo; + use sp_version::RuntimeVersion; + let test_data = vec![ ("test", 0, 1, Err(frame_system::Error::::SpecVersionNeedsToIncrease)), ("test", 1, 0, Err(frame_system::Error::::SpecVersionNeedsToIncrease)), @@ -1479,7 +1125,7 @@ fn upgrade_version_checks_should_work() { ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(read_runtime_version)); ext.execute_with(|| { let new_code = vec![1, 2, 3, 4]; - let new_code_hash = sp_core::H256(blake2_256(&new_code)); + let new_code_hash = H256(sp_core::blake2_256(&new_code)); let _authorize = ParachainSystem::authorize_upgrade(RawOrigin::Root.into(), new_code_hash, true); diff --git a/cumulus/pallets/parachain-system/src/weights.rs b/cumulus/pallets/parachain-system/src/weights.rs new file mode 100644 index 00000000000..da7f64237e9 --- /dev/null +++ b/cumulus/pallets/parachain-system/src/weights.rs @@ -0,0 +1,115 @@ +// 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 cumulus_pallet_parachain_system +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// westmint-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// pallets/parachain-system/src/weights.rs +// --steps +// 50 +// --repeat +// 20 +// --template +// ../substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for cumulus_pallet_parachain_system. +pub trait WeightInfo { + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight; +} + +/// Weights for cumulus_pallet_parachain_system using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_625_000 picoseconds. + Weight::from_parts(1_735_000, 8013) + // Standard Error: 14_563 + .saturating_add(Weight::from_parts(25_300_108, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_625_000 picoseconds. + Weight::from_parts(1_735_000, 8013) + // Standard Error: 14_563 + .saturating_add(Weight::from_parts(25_300_108, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } +} diff --git a/cumulus/pallets/xcm/src/lib.rs b/cumulus/pallets/xcm/src/lib.rs index 69b4f437540..90a0ec76def 100644 --- a/cumulus/pallets/xcm/src/lib.rs +++ b/cumulus/pallets/xcm/src/lib.rs @@ -20,25 +20,18 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, DecodeLimit, Encode}; -use cumulus_primitives_core::{ - relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, -}; -use frame_support::weights::Weight; +use codec::{Decode, Encode}; +use cumulus_primitives_core::ParaId; pub use pallet::*; use scale_info::TypeInfo; use sp_runtime::{traits::BadOrigin, RuntimeDebug}; -use sp_std::{convert::TryFrom, prelude::*}; -use xcm::{ - latest::{ExecuteXcm, Outcome, Parent, Xcm}, - VersionedXcm, MAX_XCM_DECODE_DEPTH, -}; +use sp_std::prelude::*; +use xcm::latest::{ExecuteXcm, Outcome}; #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::pallet] pub struct Pallet(_); @@ -52,17 +45,7 @@ pub mod pallet { type XcmExecutor: ExecuteXcm; } - #[pallet::error] - pub enum Error {} - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Downward message is invalid XCM. /// \[ id \] @@ -85,6 +68,9 @@ pub mod pallet { SiblingParachain(ParaId), } + #[pallet::call] + impl Pallet {} + impl From for Origin { fn from(id: ParaId) -> Origin { Origin::SiblingParachain(id) @@ -97,75 +83,6 @@ pub mod pallet { } } -/// For an incoming downward message, this just adapts an XCM executor and executes DMP messages -/// immediately. Their origin is asserted to be the Parent location. -/// -/// The weight `limit` is only respected as the maximum for an individual message. -/// -/// Because this largely ignores the given weight limit, it probably isn't good for most production -/// uses. Use DmpQueue pallet for a more robust design. -pub struct UnlimitedDmpExecution(sp_std::marker::PhantomData); -impl DmpMessageHandler for UnlimitedDmpExecution { - fn handle_dmp_messages( - iter: impl Iterator)>, - limit: Weight, - ) -> Weight { - let mut used = Weight::zero(); - for (_sent_at, data) in iter { - let id = sp_io::hashing::blake2_256(&data[..]); - let msg = VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data.as_slice(), - ) - .map(Xcm::::try_from); - match msg { - Err(_) => Pallet::::deposit_event(Event::InvalidFormat(id)), - Ok(Err(())) => Pallet::::deposit_event(Event::UnsupportedVersion(id)), - Ok(Ok(x)) => { - let outcome = T::XcmExecutor::execute_xcm(Parent, x, id, limit); - used = used.saturating_add(outcome.weight_used()); - Pallet::::deposit_event(Event::ExecutedDownward(id, outcome)); - }, - } - } - used - } -} - -/// For an incoming downward message, this just adapts an XCM executor and executes DMP messages -/// immediately. Their origin is asserted to be the Parent location. -/// -/// This respects the given weight limit and silently drops messages if they would break it. It -/// probably isn't good for most production uses. Use DmpQueue pallet for a more robust design. -pub struct LimitAndDropDmpExecution(sp_std::marker::PhantomData); -impl DmpMessageHandler for LimitAndDropDmpExecution { - fn handle_dmp_messages( - iter: impl Iterator)>, - limit: Weight, - ) -> Weight { - let mut used = Weight::zero(); - for (_sent_at, data) in iter { - let id = sp_io::hashing::blake2_256(&data[..]); - let msg = VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data.as_slice(), - ) - .map(Xcm::::try_from); - match msg { - Err(_) => Pallet::::deposit_event(Event::InvalidFormat(id)), - Ok(Err(())) => Pallet::::deposit_event(Event::UnsupportedVersion(id)), - Ok(Ok(x)) => { - let weight_limit = limit.saturating_sub(used); - let outcome = T::XcmExecutor::execute_xcm(Parent, x, id, weight_limit); - used = used.saturating_add(outcome.weight_used()); - Pallet::::deposit_event(Event::ExecutedDownward(id, outcome)); - }, - } - } - used - } -} - /// Ensure that the origin `o` represents a sibling parachain. /// Returns `Ok` with the parachain ID of the sibling or an `Err` otherwise. pub fn ensure_sibling_para(o: OuterOrigin) -> Result diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index fdb5654d59f..e526a28d084 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -8,7 +8,6 @@ license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.20", default-features = false } -rand_chacha = { version = "0.3.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate @@ -18,6 +17,7 @@ sp-io = { path = "../../../substrate/primitives/io", 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} +pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } # Polkadot polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } @@ -30,6 +30,7 @@ cumulus-primitives-core = { path = "../../primitives/core", default-features = f # Optional import for benchmarking frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} +bounded-collections = { version = "0.1.4", default-features = false } # Bridges bp-xcm-bridge-hub-router = { path = "../../../bridges/primitives/xcm-bridge-hub-router", default-features = false, optional = true } @@ -39,6 +40,7 @@ bp-xcm-bridge-hub-router = { path = "../../../bridges/primitives/xcm-bridge-hub- # Substrate sp-core = { path = "../../../substrate/primitives/core" } pallet-balances = { path = "../../../substrate/frame/balances" } +frame-support = { path = "../../../substrate/frame/support", features = ["experimental"] } # Polkadot xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder" } @@ -49,6 +51,7 @@ cumulus-pallet-parachain-system = { path = "../parachain-system", features = ["p [features] default = [ "std" ] std = [ + "bounded-collections/std", "bp-xcm-bridge-hub-router?/std", "codec/std", "cumulus-primitives-core/std", @@ -56,9 +59,9 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-message-queue/std", "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", - "rand_chacha/std", "scale-info/std", "sp-core/std", "sp-io/std", @@ -70,10 +73,12 @@ std = [ runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -85,6 +90,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-message-queue/try-runtime", "polkadot-runtime-common/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", diff --git a/cumulus/pallets/xcmp-queue/src/benchmarking.rs b/cumulus/pallets/xcmp-queue/src/benchmarking.rs index 17ec60a2f3f..81dfbc2bb71 100644 --- a/cumulus/pallets/xcmp-queue/src/benchmarking.rs +++ b/cumulus/pallets/xcmp-queue/src/benchmarking.rs @@ -17,12 +17,158 @@ use crate::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use codec::DecodeAll; +use frame_benchmarking::v2::*; +use frame_support::traits::Hooks; use frame_system::RawOrigin; +use xcm::v3::MAX_INSTRUCTIONS_TO_DECODE; -benchmarks! { - set_config_with_u32 {}: update_resume_threshold(RawOrigin::Root, 100) - set_config_with_weight {}: update_weight_restrict_decay(RawOrigin::Root, Weight::from_parts(3_000_000, 0)) -} +#[benchmarks] +mod benchmarks { + use super::*; + + /// Modify any of the `QueueConfig` fields with a new `u32` value. + /// + /// Used as weight for: + /// - update_suspend_threshold + /// - update_drop_threshold + /// - update_resume_threshold + #[benchmark] + fn set_config_with_u32() { + #[extrinsic_call] + Pallet::::update_resume_threshold(RawOrigin::Root, 1); + } + + #[benchmark] + fn enqueue_xcmp_message() { + assert!(QueueConfig::::get().drop_threshold * MaxXcmpMessageLenOf::::get() > 1000); + let msg = BoundedVec::>::default(); + + #[block] + { + Pallet::::enqueue_xcmp_message(0.into(), msg, &mut WeightMeter::new()).unwrap(); + } + } + + #[benchmark] + fn suspend_channel() { + let para = 123.into(); + let data = ChannelSignal::Suspend.encode(); + + #[block] + { + ChannelSignal::decode_all(&mut &data[..]).unwrap(); + Pallet::::suspend_channel(para); + } + + assert_eq!( + OutboundXcmpStatus::::get() + .iter() + .find(|p| p.recipient == para) + .unwrap() + .state, + OutboundState::Suspended + ); + } + + #[benchmark] + fn resume_channel() { + let para = 123.into(); + let data = ChannelSignal::Resume.encode(); + + Pallet::::suspend_channel(para); + + #[block] + { + ChannelSignal::decode_all(&mut &data[..]).unwrap(); + Pallet::::resume_channel(para); + } + + assert!( + OutboundXcmpStatus::::get().iter().find(|p| p.recipient == para).is_none(), + "No messages in the channel; therefore removed." + ); + } + + /// Split a singular XCM. + #[benchmark] + fn take_first_concatenated_xcm() { + let max_downward_message_size = MaxXcmpMessageLenOf::::get() as usize; + + assert!(MAX_INSTRUCTIONS_TO_DECODE as u32 > MAX_XCM_DECODE_DEPTH, "Preconditon failed"); + let max_instrs = MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH; + let mut xcm = Xcm::(vec![ClearOrigin; max_instrs as usize]); -impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + xcm = Xcm::(vec![Instruction::SetAppendix(xcm)]); + } + + let data = VersionedXcm::::from(xcm).encode(); + assert!(data.len() < max_downward_message_size, "Page size is too small"); + // Verify that decoding works with the exact recursion limit: + VersionedXcm::::decode_with_depth_limit( + MAX_XCM_DECODE_DEPTH, + &mut &data[..], + ) + .unwrap(); + VersionedXcm::::decode_with_depth_limit( + MAX_XCM_DECODE_DEPTH - 1, + &mut &data[..], + ) + .unwrap_err(); + + #[block] + { + Pallet::::take_first_concatenated_xcm(&mut &data[..], &mut WeightMeter::new()) + .unwrap(); + } + } + + /// Benchmark the migration for a maximal sized message. + #[benchmark] + fn on_idle_good_msg() { + use migration::v3; + + let block = 5; + let para = ParaId::from(4); + let message = vec![123u8; MaxXcmpMessageLenOf::::get() as usize]; + let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)]; + + v3::InboundXcmpMessages::::insert(para, block, message); + v3::InboundXcmpStatus::::set(Some(vec![v3::InboundChannelDetails { + sender: para, + state: v3::InboundState::Ok, + message_metadata, + }])); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + } + + /// Benchmark the migration with a 64 KiB message that will not be possible to enqueue. + #[benchmark] + fn on_idle_large_msg() { + use migration::v3; + + let block = 5; + let para = ParaId::from(4); + let message = vec![123u8; 1 << 16]; // 64 KiB message + let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)]; + + v3::InboundXcmpMessages::::insert(para, block, message); + v3::InboundXcmpStatus::::set(Some(vec![v3::InboundChannelDetails { + sender: para, + state: v3::InboundState::Ok, + message_metadata, + }])); + + #[block] + { + Pallet::::on_idle(0u32.into(), Weight::MAX); + } + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index b62dc0a47fc..d687f83d8b3 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -50,25 +50,26 @@ pub mod bridging; pub mod weights; pub use weights::WeightInfo; +use bounded_collections::BoundedBTreeSet; use codec::{Decode, DecodeLimit, Encode}; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError, ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource, }; + use frame_support::{ - traits::{EnsureOrigin, Get}, - weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, + defensive, defensive_assert, + traits::{EnqueueMessage, EnsureOrigin, Get, QueueFootprint, QueuePausedQuery}, + weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight, WeightMeter}, + BoundedVec, }; +use pallet_message_queue::OnQueueChanged; use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery; use polkadot_runtime_parachains::FeeTracker; -use rand_chacha::{ - rand_core::{RngCore, SeedableRng}, - ChaChaRng, -}; use scale_info::TypeInfo; use sp_core::MAX_POSSIBLE_ALLOCATION; use sp_runtime::{FixedU128, RuntimeDebug, Saturating}; -use sp_std::{convert::TryFrom, prelude::*}; +use sp_std::prelude::*; use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; use xcm_executor::traits::ConvertOrigin; @@ -76,6 +77,9 @@ pub use pallet::*; /// Index used to identify overweight XCMs. pub type OverweightIndex = u64; +/// The max length of an XCMP message. +pub type MaxXcmpMessageLenOf = + <::XcmpQueue as EnqueueMessage>::MaxMessageLen; const LOG_TARGET: &str = "xcmp_queue"; const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB @@ -93,12 +97,6 @@ pub mod delivery_fee_constants { pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001 } -// Maximum amount of messages to process per block. This is a temporary measure until we properly -// account for proof size weights. -const MAX_MESSAGES_PER_BLOCK: u8 = 10; -// Maximum amount of messages that can exist in the overweight queue at any given time. -const MAX_OVERWEIGHT_MESSAGES: u32 = 1000; - #[frame_support::pallet] pub mod pallet { use super::*; @@ -114,17 +112,25 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Something to execute an XCM message. We need this to service the XCMoXCMP queue. - type XcmExecutor: ExecuteXcm; - - /// Information on the avaialble XCMP channels. + /// Information on the available XCMP channels. type ChannelInfo: GetChannelInfo; /// Means of converting an `Xcm` into a `VersionedXcm`. type VersionWrapper: WrapVersion; - /// The origin that is allowed to execute overweight messages. - type ExecuteOverweightOrigin: EnsureOrigin; + /// Enqueue an inbound horizontal message for later processing. + /// + /// This defines the maximal message length via [`crate::MaxXcmpMessageLenOf`]. The pallet + /// assumes that this hook will eventually process all the pushed messages. + type XcmpQueue: EnqueueMessage; + + /// The maximum number of inbound XCMP channels that can be suspended simultaneously. + /// + /// Any further channel suspensions will fail and messages may get dropped without further + /// notice. Choosing a high value (1000) is okay; the trade-off that is described in + /// [`InboundXcmpSuspended`] still applies at that scale. + #[pallet::constant] + type MaxInboundSuspended: Get; /// The origin that is allowed to resume or suspend the XCMP queue. type ControllerOrigin: EnsureOrigin; @@ -140,52 +146,8 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_idle(_now: BlockNumberFor, max_weight: Weight) -> Weight { - // on_idle processes additional messages with any remaining block weight. - Self::service_xcmp_queue(max_weight) - } - } - #[pallet::call] impl Pallet { - /// Services a single overweight XCM. - /// - /// - `origin`: Must pass `ExecuteOverweightOrigin`. - /// - `index`: The index of the overweight XCM to service - /// - `weight_limit`: The amount of weight that XCM execution may take. - /// - /// Errors: - /// - `BadOverweightIndex`: XCM under `index` is not found in the `Overweight` storage map. - /// - `BadXcm`: XCM under `index` cannot be properly decoded into a valid XCM format. - /// - `WeightOverLimit`: XCM execution may use greater `weight_limit`. - /// - /// Events: - /// - `OverweightServiced`: On success. - #[pallet::call_index(0)] - #[pallet::weight((weight_limit.saturating_add(Weight::from_parts(1_000_000, 0)), DispatchClass::Operational))] - pub fn service_overweight( - origin: OriginFor, - index: OverweightIndex, - weight_limit: Weight, - ) -> DispatchResultWithPostInfo { - T::ExecuteOverweightOrigin::ensure_origin(origin)?; - - let (sender, sent_at, data) = - Overweight::::get(index).ok_or(Error::::BadOverweightIndex)?; - let xcm = VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data.as_slice(), - ) - .map_err(|_| Error::::BadXcm)?; - let used = Self::handle_xcm_message(sender, sent_at, xcm, weight_limit) - .map_err(|_| Error::::WeightOverLimit)?; - Overweight::::remove(index); - Self::deposit_event(Event::OverweightServiced { index, used }); - Ok(Some(used.saturating_add(Weight::from_parts(1_000_000, 0))).into()) - } - /// Suspends all XCM executions for the XCMP queue, regardless of the sender's origin. /// /// - `origin`: Must pass `ControllerOrigin`. @@ -194,9 +156,14 @@ pub mod pallet { pub fn suspend_xcm_execution(origin: OriginFor) -> DispatchResult { T::ControllerOrigin::ensure_origin(origin)?; - QueueSuspended::::put(true); - - Ok(()) + QueueSuspended::::try_mutate(|suspended| { + if *suspended { + Err(Error::::AlreadySuspended.into()) + } else { + *suspended = true; + Ok(()) + } + }) } /// Resumes all XCM executions for the XCMP queue. @@ -209,13 +176,18 @@ pub mod pallet { pub fn resume_xcm_execution(origin: OriginFor) -> DispatchResult { T::ControllerOrigin::ensure_origin(origin)?; - QueueSuspended::::put(false); - - Ok(()) + QueueSuspended::::try_mutate(|suspended| { + if !*suspended { + Err(Error::::AlreadyResumed.into()) + } else { + *suspended = false; + Ok(()) + } + }) } - /// Overwrites the number of pages of messages which must be in the queue for the other side - /// to be told to suspend their sending. + /// Overwrites the number of pages which must be in the queue for the other side to be + /// told to suspend their sending. /// /// - `origin`: Must pass `Root`. /// - `new`: Desired value for `QueueConfigData.suspend_value` @@ -223,13 +195,15 @@ pub mod pallet { #[pallet::weight((T::WeightInfo::set_config_with_u32(), DispatchClass::Operational,))] pub fn update_suspend_threshold(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; - QueueConfig::::mutate(|data| data.suspend_threshold = new); - Ok(()) + QueueConfig::::try_mutate(|data| { + data.suspend_threshold = new; + data.validate::() + }) } - /// Overwrites the number of pages of messages which must be in the queue after which we - /// drop any further messages from the channel. + /// Overwrites the number of pages which must be in the queue after which we drop any + /// further messages from the channel. /// /// - `origin`: Must pass `Root`. /// - `new`: Desired value for `QueueConfigData.drop_threshold` @@ -237,13 +211,15 @@ pub mod pallet { #[pallet::weight((T::WeightInfo::set_config_with_u32(),DispatchClass::Operational,))] pub fn update_drop_threshold(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; - QueueConfig::::mutate(|data| data.drop_threshold = new); - Ok(()) + QueueConfig::::try_mutate(|data| { + data.drop_threshold = new; + data.validate::() + }) } - /// Overwrites the number of pages of messages which the queue must be reduced to before it - /// signals that message sending may recommence after it has been suspended. + /// Overwrites the number of pages which the queue must be reduced to before it signals + /// that message sending may recommence after it has been suspended. /// /// - `origin`: Must pass `Root`. /// - `new`: Desired value for `QueueConfigData.resume_threshold` @@ -251,112 +227,68 @@ pub mod pallet { #[pallet::weight((T::WeightInfo::set_config_with_u32(), DispatchClass::Operational,))] pub fn update_resume_threshold(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; - QueueConfig::::mutate(|data| data.resume_threshold = new); - Ok(()) + QueueConfig::::try_mutate(|data| { + data.resume_threshold = new; + data.validate::() + }) } + } - /// Overwrites the amount of remaining weight under which we stop processing messages. - /// - /// - `origin`: Must pass `Root`. - /// - `new`: Desired value for `QueueConfigData.threshold_weight` - #[pallet::call_index(6)] - #[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))] - pub fn update_threshold_weight(origin: OriginFor, new: Weight) -> DispatchResult { - ensure_root(origin)?; - QueueConfig::::mutate(|data| data.threshold_weight = new); - - Ok(()) + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + let w = Self::on_idle_weight(); + assert!(w != Weight::zero()); + assert!(w.all_lte(T::BlockWeights::get().max_block)); } - /// Overwrites the speed to which the available weight approaches the maximum weight. - /// A lower number results in a faster progression. A value of 1 makes the entire weight - /// available initially. - /// - /// - `origin`: Must pass `Root`. - /// - `new`: Desired value for `QueueConfigData.weight_restrict_decay`. - #[pallet::call_index(7)] - #[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))] - pub fn update_weight_restrict_decay(origin: OriginFor, new: Weight) -> DispatchResult { - ensure_root(origin)?; - QueueConfig::::mutate(|data| data.weight_restrict_decay = new); + fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { + let mut meter = WeightMeter::with_limit(limit); - Ok(()) - } + if meter.try_consume(Self::on_idle_weight()).is_err() { + log::debug!( + "Not enough weight for on_idle. {} < {}", + Self::on_idle_weight(), + limit + ); + return meter.consumed() + } - /// Overwrite the maximum amount of weight any individual message may consume. - /// Messages above this weight go into the overweight queue and may only be serviced - /// explicitly. - /// - /// - `origin`: Must pass `Root`. - /// - `new`: Desired value for `QueueConfigData.xcmp_max_individual_weight`. - #[pallet::call_index(8)] - #[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))] - pub fn update_xcmp_max_individual_weight( - origin: OriginFor, - new: Weight, - ) -> DispatchResult { - ensure_root(origin)?; - QueueConfig::::mutate(|data| data.xcmp_max_individual_weight = new); + migration::lazy_migrate_inbound_queue::(); - Ok(()) + meter.consumed() } } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Some XCM was executed ok. - Success { message_hash: XcmHash, message_id: XcmHash, weight: Weight }, - /// Some XCM failed. - Fail { message_hash: XcmHash, message_id: XcmHash, error: XcmError, weight: Weight }, - /// Bad XCM version used. - BadVersion { message_hash: XcmHash }, - /// Bad XCM format used. - BadFormat { message_hash: XcmHash }, /// An HRMP message was sent to a sibling parachain. XcmpMessageSent { message_hash: XcmHash }, - /// An XCM exceeded the individual message weight budget. - OverweightEnqueued { - sender: ParaId, - sent_at: RelayBlockNumber, - index: OverweightIndex, - required: Weight, - }, - /// An XCM from the overweight queue was executed with the given actual weight used. - OverweightServiced { index: OverweightIndex, used: Weight }, } #[pallet::error] pub enum Error { - /// Failed to send XCM message. - FailedToSend, - /// Bad XCM origin. - BadXcmOrigin, - /// Bad XCM data. - BadXcm, - /// Bad overweight index. - BadOverweightIndex, - /// Provided weight is possibly not enough to execute the message. - WeightOverLimit, + /// Setting the queue config failed since one of its values was invalid. + BadQueueConfig, + /// The execution is already suspended. + AlreadySuspended, + /// The execution is already resumed. + AlreadyResumed, } - /// Status of the inbound XCMP channels. - #[pallet::storage] - pub(super) type InboundXcmpStatus = - StorageValue<_, Vec, ValueQuery>; - - /// Inbound aggregate XCMP messages. It can only be one per ParaId/block. + /// The suspended inbound XCMP channels. All others are not suspended. + /// + /// This is a `StorageValue` instead of a `StorageMap` since we expect multiple reads per block + /// to different keys with a one byte payload. The access to `BoundedBTreeSet` will be cached + /// within the block and therefore only included once in the proof size. + /// + /// NOTE: The PoV benchmarking cannot know this and will over-estimate, but the actual proof + /// will be smaller. #[pallet::storage] - pub(super) type InboundXcmpMessages = StorageDoubleMap< - _, - Blake2_128Concat, - ParaId, - Twox64Concat, - RelayBlockNumber, - Vec, - ValueQuery, - >; + pub type InboundXcmpSuspended = + StorageValue<_, BoundedBTreeSet, ValueQuery>; /// The non-empty XCMP channels in order of becoming non-empty, and the index of the first /// and last outbound message. If the two indices are equal, then it indicates an empty @@ -383,19 +315,6 @@ pub mod pallet { #[pallet::storage] pub(super) type QueueConfig = StorageValue<_, QueueConfigData, ValueQuery>; - /// The messages that exceeded max individual message weight budget. - /// - /// These message stay in this storage map until they are manually dispatched via - /// `service_overweight`. - #[pallet::storage] - pub(super) type Overweight = - CountedStorageMap<_, Twox64Concat, OverweightIndex, (ParaId, RelayBlockNumber, Vec)>; - - /// The number of overweight messages ever recorded in `Overweight`. Also doubles as the next - /// available free overweight index. - #[pallet::storage] - pub(super) type OverweightCount = StorageValue<_, OverweightIndex, ValueQuery>; - /// Whether or not the XCMP queue is suspended from executing incoming XCMs or not. #[pallet::storage] pub(super) type QueueSuspended = StorageValue<_, bool, ValueQuery>; @@ -412,34 +331,15 @@ pub mod pallet { StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>; } -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum InboundState { - Ok, - Suspended, -} - #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum OutboundState { Ok, Suspended, } -/// Struct containing detailed information about the inbound channel. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] -pub struct InboundChannelDetails { - /// The `ParaId` of the parachain that this channel is connected with. - sender: ParaId, - /// The state of the channel. - state: InboundState, - /// The ordered metadata of each inbound message. - /// - /// Contains info about the relay block number that the message was sent at, and the format - /// of the incoming message. - message_metadata: Vec<(RelayBlockNumber, XcmpMessageFormat)>, -} - /// Struct containing detailed information about the outbound channel. -#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] pub struct OutboundChannelDetails { /// The `ParaId` of the parachain that this channel is connected with. recipient: ParaId, @@ -477,31 +377,40 @@ impl OutboundChannelDetails { #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct QueueConfigData { - /// The number of pages of messages which must be in the queue for the other side to be told to - /// suspend their sending. + /// The number of pages which must be in the queue for the other side to be told to suspend + /// their sending. suspend_threshold: u32, - /// The number of pages of messages which must be in the queue after which we drop any further - /// messages from the channel. + /// The number of pages which must be in the queue after which we drop any further messages + /// from the channel. This should normally not happen since the `suspend_threshold` can be used + /// to suspend the channel. drop_threshold: u32, - /// The number of pages of messages which the queue must be reduced to before it signals that + /// The number of pages which the queue must be reduced to before it signals that /// message sending may recommence after it has been suspended. resume_threshold: u32, - /// The amount of remaining weight under which we stop processing messages. + /// UNUSED - The amount of remaining weight under which we stop processing messages. + #[deprecated(note = "Will be removed")] threshold_weight: Weight, - /// The speed to which the available weight approaches the maximum weight. A lower number - /// results in a faster progression. A value of 1 makes the entire weight available initially. + /// UNUSED - The speed to which the available weight approaches the maximum weight. A lower + /// number results in a faster progression. A value of 1 makes the entire weight available + /// initially. + #[deprecated(note = "Will be removed")] weight_restrict_decay: Weight, - /// The maximum amount of weight any individual message may consume. Messages above this weight - /// go into the overweight queue and may only be serviced explicitly. + /// UNUSED - The maximum amount of weight any individual message may consume. Messages above + /// this weight go into the overweight queue and may only be serviced explicitly. + #[deprecated(note = "Will be removed")] xcmp_max_individual_weight: Weight, } impl Default for QueueConfigData { fn default() -> Self { + // NOTE that these default values are only used on genesis. They should give a rough idea of + // what to set these values to, but is in no way a requirement. + #![allow(deprecated)] Self { - suspend_threshold: 2, - drop_threshold: 5, - resume_threshold: 1, + drop_threshold: 48, // 64KiB * 48 = 3MiB + suspend_threshold: 32, // 64KiB * 32 = 2MiB + resume_threshold: 8, // 64KiB * 8 = 512KiB + // unused: threshold_weight: Weight::from_parts(100_000, 0), weight_restrict_decay: Weight::from_parts(2, 0), xcmp_max_individual_weight: Weight::from_parts( @@ -512,6 +421,22 @@ impl Default for QueueConfigData { } } +impl QueueConfigData { + /// Validate all assumptions about `Self`. + /// + /// Should be called prior to accepting this as new config. + pub fn validate(&self) -> sp_runtime::DispatchResult { + if self.resume_threshold < self.suspend_threshold && + self.suspend_threshold <= self.drop_threshold && + self.resume_threshold > 0 + { + Ok(()) + } else { + Err(Error::::BadQueueConfig.into()) + } + } +} + #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, TypeInfo)] pub enum ChannelSignal { Suspend, @@ -582,6 +507,7 @@ impl Pallet { &mut &page[..], ) != Ok(format) { + defensive!("Bad format in outbound queue; dropping message"); return None } if page.len() + encoded_fragment.len() > max_message_size { @@ -627,7 +553,7 @@ impl Pallet { /// Sends a signal to the `dest` chain over XCMP. This is guaranteed to be dispatched on this /// block. - fn send_signal(dest: ParaId, signal: ChannelSignal) -> Result<(), ()> { + fn send_signal(dest: ParaId, signal: ChannelSignal) { let mut s = >::get(); if let Some(details) = s.iter_mut().find(|item| item.recipient == dest) { details.signals_exist = true; @@ -635,365 +561,16 @@ impl Pallet { s.push(OutboundChannelDetails::new(dest).with_signals()); } >::mutate(dest, |page| { - if page.is_empty() { - *page = (XcmpMessageFormat::Signals, signal).encode(); - } else { - signal.using_encoded(|s| page.extend_from_slice(s)); - } + *page = (XcmpMessageFormat::Signals, signal).encode(); }); >::put(s); - - Ok(()) - } - - pub fn send_blob_message(recipient: ParaId, blob: Vec) -> Result { - Self::send_fragment(recipient, XcmpMessageFormat::ConcatenatedEncodedBlob, blob) - } - - pub fn send_xcm_message( - recipient: ParaId, - xcm: VersionedXcm<()>, - ) -> Result { - Self::send_fragment(recipient, XcmpMessageFormat::ConcatenatedVersionedXcm, xcm) - } - - fn create_shuffle(len: usize) -> Vec { - // Create a shuffled order for use to iterate through. - // Not a great random seed, but good enough for our purposes. - let seed = frame_system::Pallet::::parent_hash(); - let seed = - <[u8; 32]>::decode(&mut sp_runtime::traits::TrailingZeroInput::new(seed.as_ref())) - .expect("input is padded with zeroes; qed"); - let mut rng = ChaChaRng::from_seed(seed); - let mut shuffled = (0..len).collect::>(); - for i in 0..len { - let j = (rng.next_u32() as usize) % len; - shuffled.as_mut_slice().swap(i, j); - } - shuffled - } - - fn handle_blob_message( - _sender: ParaId, - _sent_at: RelayBlockNumber, - _blob: Vec, - _weight_limit: Weight, - ) -> Result { - debug_assert!(false, "Blob messages not handled."); - Err(false) - } - - fn handle_xcm_message( - sender: ParaId, - _sent_at: RelayBlockNumber, - xcm: VersionedXcm, - max_weight: Weight, - ) -> Result { - let message_hash = xcm.using_encoded(sp_io::hashing::blake2_256); - log::debug!("Processing XCMP-XCM: {:?}", &message_hash); - let (result, event) = match Xcm::::try_from(xcm) { - Ok(xcm) => { - let location = (Parent, Parachain(sender.into())); - let mut message_id = message_hash; - - match T::XcmExecutor::prepare_and_execute( - location, - xcm, - &mut message_id, - max_weight, - Weight::zero(), - ) { - Outcome::Error(error) => ( - Err(error), - Event::Fail { message_hash, message_id, error, weight: Weight::zero() }, - ), - Outcome::Complete(weight) => - (Ok(weight), Event::Success { message_hash, message_id, weight }), - // As far as the caller is concerned, this was dispatched without error, so - // we just report the weight used. - Outcome::Incomplete(weight, error) => - (Ok(weight), Event::Fail { message_hash, message_id, error, weight }), - } - }, - Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion { message_hash }), - }; - Self::deposit_event(event); - result - } - - fn process_xcmp_message( - sender: ParaId, - (sent_at, format): (RelayBlockNumber, XcmpMessageFormat), - messages_processed: &mut u8, - max_weight: Weight, - max_individual_weight: Weight, - ) -> (Weight, bool) { - let data = >::get(sender, sent_at); - let mut last_remaining_fragments; - let mut remaining_fragments = &data[..]; - let mut weight_used = Weight::zero(); - match format { - XcmpMessageFormat::ConcatenatedVersionedXcm => { - while !remaining_fragments.is_empty() && - *messages_processed < MAX_MESSAGES_PER_BLOCK - { - last_remaining_fragments = remaining_fragments; - if let Ok(xcm) = VersionedXcm::::decode_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut remaining_fragments, - ) { - let weight = max_weight - weight_used; - *messages_processed += 1; - match Self::handle_xcm_message(sender, sent_at, xcm, weight) { - Ok(used) => weight_used = weight_used.saturating_add(used), - Err(XcmError::WeightLimitReached(required)) - if required.any_gt(max_individual_weight) => - { - let is_under_limit = - Overweight::::count() < MAX_OVERWEIGHT_MESSAGES; - weight_used.saturating_accrue(T::DbWeight::get().reads(1)); - if is_under_limit { - // overweight - add to overweight queue and continue with - // message execution consuming the message. - let msg_len = last_remaining_fragments - .len() - .saturating_sub(remaining_fragments.len()); - let overweight_xcm = - last_remaining_fragments[..msg_len].to_vec(); - let index = - Self::stash_overweight(sender, sent_at, overweight_xcm); - let e = Event::OverweightEnqueued { - sender, - sent_at, - index, - required, - }; - Self::deposit_event(e); - } - }, - Err(XcmError::WeightLimitReached(required)) - if required.all_lte(max_weight) => - { - // That message didn't get processed this time because of being - // too heavy. We leave it around for next time and bail. - remaining_fragments = last_remaining_fragments; - break - }, - Err(error) => { - log::error!( - "Failed to process XCMP-XCM message, caused by {:?}", - error - ); - // Message looks invalid; don't attempt to retry - }, - } - } else { - debug_assert!(false, "Invalid incoming XCMP message data"); - remaining_fragments = &b""[..]; - } - } - }, - XcmpMessageFormat::ConcatenatedEncodedBlob => { - while !remaining_fragments.is_empty() { - last_remaining_fragments = remaining_fragments; - - if let Ok(blob) = >::decode(&mut remaining_fragments) { - let weight = max_weight - weight_used; - *messages_processed += 1; - match Self::handle_blob_message(sender, sent_at, blob, weight) { - Ok(used) => weight_used = weight_used.saturating_add(used), - Err(true) => { - // That message didn't get processed this time because of being - // too heavy. We leave it around for next time and bail. - remaining_fragments = last_remaining_fragments; - break - }, - Err(false) => { - // Message invalid; don't attempt to retry - }, - } - } else { - debug_assert!(false, "Invalid incoming blob message data"); - remaining_fragments = &b""[..]; - } - } - }, - XcmpMessageFormat::Signals => { - debug_assert!(false, "All signals are handled immediately; qed"); - remaining_fragments = &b""[..]; - }, - } - let is_empty = remaining_fragments.is_empty(); - if is_empty { - >::remove(sender, sent_at); - } else { - >::insert(sender, sent_at, remaining_fragments); - } - (weight_used, is_empty) - } - - /// Puts a given XCM into the list of overweight messages, allowing it to be executed later. - fn stash_overweight( - sender: ParaId, - sent_at: RelayBlockNumber, - xcm: Vec, - ) -> OverweightIndex { - let index = OverweightCount::::mutate(|count| { - let index = *count; - *count += 1; - index - }); - - Overweight::::insert(index, (sender, sent_at, xcm)); - index - } - - /// Service the incoming XCMP message queue attempting to execute up to `max_weight` execution - /// weight of messages. - /// - /// Channels are first shuffled and then processed in this random one page at a time, order over - /// and over until either `max_weight` is exhausted or no channel has messages that can be - /// processed any more. - /// - /// There are two obvious "modes" that we could apportion `max_weight`: one would be to attempt - /// to spend it all on the first channel's first page, then use the leftover (if any) for the - /// second channel's first page and so on until finally we cycle back and the process messages - /// on the first channel's second page &c. The other mode would be to apportion only `1/N` of - /// `max_weight` for the first page (where `N` could be, perhaps, the number of channels to - /// service, using the remainder plus the next `1/N` for the next channel's page &c. - /// - /// Both modes have good qualities, the first ensures that a channel with a large message (over - /// `1/N` does not get indefinitely blocked if other channels have continuous, light traffic. - /// The second is fairer, and ensures that channels with continuous light messages don't suffer - /// high latency. - /// - /// The following code is a hybrid solution; we have a concept of `weight_available` which - /// incrementally approaches `max_weight` as more channels are attempted to be processed. We use - /// the parameter `weight_restrict_decay` to control the speed with which `weight_available` - /// approaches `max_weight`, with `0` being strictly equivalent to the first aforementioned - /// mode, and `N` approximating the second. A reasonable parameter may be `1`, which makes - /// half of the `max_weight` available for the first page, then a quarter plus the remainder - /// for the second &c. though empirical and or practical factors may give rise to adjusting it - /// further. - fn service_xcmp_queue(max_weight: Weight) -> Weight { - let suspended = QueueSuspended::::get(); - let mut messages_processed = 0; - - let mut status = >::get(); // <- sorted. - if status.is_empty() { - return Weight::zero() - } - - let QueueConfigData { - resume_threshold, - threshold_weight, - weight_restrict_decay, - xcmp_max_individual_weight, - .. - } = >::get(); - - let mut shuffled = Self::create_shuffle(status.len()); - let mut weight_used = Weight::zero(); - let mut weight_available = Weight::zero(); - - // We don't want the possibility of a chain sending a series of really heavy messages and - // tying up the block's execution time from other chains. Therefore we execute any remaining - // messages in a random order. - // Order within a single channel will always be preserved, however this does mean that - // relative order between channels may not. The result is that chains which tend to send - // fewer, lighter messages will generally have a lower latency than chains which tend to - // send more, heavier messages. - - let mut shuffle_index = 0; - while shuffle_index < shuffled.len() && - max_weight.saturating_sub(weight_used).all_gte(threshold_weight) && - messages_processed < MAX_MESSAGES_PER_BLOCK - { - let index = shuffled[shuffle_index]; - let sender = status[index].sender; - let sender_origin = T::ControllerOriginConverter::convert_origin( - (Parent, Parachain(sender.into())), - OriginKind::Superuser, - ); - let is_controller = sender_origin - .map_or(false, |origin| T::ControllerOrigin::try_origin(origin).is_ok()); - - if suspended && !is_controller { - shuffle_index += 1; - continue - } - - if weight_available != max_weight { - // Get incrementally closer to freeing up max_weight for message execution over the - // first round. For the second round we unlock all weight. If we come close enough - // on the first round to unlocking everything, then we do so. - if shuffle_index < status.len() { - weight_available += - (max_weight - weight_available) / (weight_restrict_decay.ref_time() + 1); - if (weight_available + threshold_weight).any_gt(max_weight) { - weight_available = max_weight; - } - } else { - weight_available = max_weight; - } - } - - let weight_processed = if status[index].message_metadata.is_empty() { - debug_assert!(false, "channel exists in status; there must be messages; qed"); - Weight::zero() - } else { - // Process up to one block's worth for now. - let weight_remaining = weight_available.saturating_sub(weight_used); - let (weight_processed, is_empty) = Self::process_xcmp_message( - sender, - status[index].message_metadata[0], - &mut messages_processed, - weight_remaining, - xcmp_max_individual_weight, - ); - if is_empty { - status[index].message_metadata.remove(0); - } - weight_processed - }; - weight_used += weight_processed; - - if status[index].message_metadata.len() as u32 <= resume_threshold && - status[index].state == InboundState::Suspended - { - // Resume - let r = Self::send_signal(sender, ChannelSignal::Resume); - debug_assert!(r.is_ok(), "WARNING: Failed sending resume into suspended channel"); - status[index].state = InboundState::Ok; - } - - // If there are more and we're making progress, we process them after we've given the - // other channels a look in. If we've still not unlocked all weight, then we set them - // up for processing a second time anyway. - if !status[index].message_metadata.is_empty() && - (weight_processed.any_gt(Weight::zero()) || weight_available != max_weight) - { - if shuffle_index + 1 == shuffled.len() { - // Only this queue left. Just run around this loop once more. - continue - } - shuffled.push(index); - } - shuffle_index += 1; - } - - // Only retain the senders that have non-empty queues. - status.retain(|item| !item.message_metadata.is_empty()); - - >::put(status); - weight_used } fn suspend_channel(target: ParaId) { >::mutate(|s| { if let Some(details) = s.iter_mut().find(|item| item.recipient == target) { let ok = details.state == OutboundState::Ok; - debug_assert!(ok, "WARNING: Attempt to suspend channel that was not Ok."); + defensive_assert!(ok, "WARNING: Attempt to suspend channel that was not Ok."); details.state = OutboundState::Suspended; } else { s.push(OutboundChannelDetails::new(target).with_suspended_state()); @@ -1005,7 +582,7 @@ impl Pallet { >::mutate(|s| { if let Some(index) = s.iter().position(|item| item.recipient == target) { let suspended = s[index].state == OutboundState::Suspended; - debug_assert!( + defensive_assert!( suspended, "WARNING: Attempt to resume channel that was not suspended." ); @@ -1015,18 +592,67 @@ impl Pallet { s[index].state = OutboundState::Ok; } } else { - debug_assert!(false, "WARNING: Attempt to resume channel that was not suspended."); + defensive!("WARNING: Attempt to resume channel that was not suspended."); } }); } + fn enqueue_xcmp_message( + sender: ParaId, + xcm: BoundedVec>, + meter: &mut WeightMeter, + ) -> Result<(), ()> { + if meter.try_consume(T::WeightInfo::enqueue_xcmp_message()).is_err() { + defensive!("Out of weight: cannot enqueue XCMP messages; dropping msg"); + return Err(()) + } + + let QueueConfigData { drop_threshold, .. } = >::get(); + let fp = T::XcmpQueue::footprint(sender); + // Assume that it will not fit into the current page: + let new_pages = fp.pages.saturating_add(1); + if new_pages > drop_threshold { + // This should not happen since the channel should have been suspended in + // [`on_queue_changed`]. + log::error!("XCMP queue for sibling {:?} is full; dropping messages.", sender); + return Err(()) + } + + T::XcmpQueue::enqueue_message(xcm.as_bounded_slice(), sender); + Ok(()) + } + + /// Split concatenated encoded `VersionedXcm`s or `MaybeDoubleEncodedVersionedXcm`s into + /// individual items. + /// + /// We directly encode them again since that is needed later on. + pub(crate) fn take_first_concatenated_xcm( + data: &mut &[u8], + meter: &mut WeightMeter, + ) -> Result>, ()> { + if data.is_empty() { + return Err(()) + } + + if meter.try_consume(T::WeightInfo::take_first_concatenated_xcm()).is_err() { + defensive!("Out of weight; could not decode all; dropping"); + return Err(()) + } + + let xcm = VersionedXcm::<()>::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, data) + .map_err(|_| ())?; + xcm.encode().try_into().map_err(|_| ()) + } + + /// The worst-case weight of `on_idle`. + pub fn on_idle_weight() -> Weight { + ::WeightInfo::on_idle_good_msg() + .max(::WeightInfo::on_idle_large_msg()) + } + #[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) + >::get().iter().any(|c| c == &sender) } #[cfg(feature = "bridging")] @@ -1039,84 +665,112 @@ impl Pallet { } } +impl OnQueueChanged for Pallet { + // Suspends/Resumes the queue when certain thresholds are reached. + fn on_queue_changed(para: ParaId, fp: QueueFootprint) { + let QueueConfigData { resume_threshold, suspend_threshold, .. } = >::get(); + + let mut suspended_channels = >::get(); + let suspended = suspended_channels.contains(¶); + + if suspended && fp.pages <= resume_threshold { + Self::send_signal(para, ChannelSignal::Resume); + + suspended_channels.remove(¶); + >::put(suspended_channels); + } else if !suspended && fp.pages >= suspend_threshold { + log::warn!("XCMP queue for sibling {:?} is full; suspending channel.", para); + Self::send_signal(para, ChannelSignal::Suspend); + + if let Err(err) = suspended_channels.try_insert(para) { + log::error!("Too many channels suspended; cannot suspend sibling {:?}: {:?}; further messages may be dropped.", para, err); + } + >::put(suspended_channels); + } + } +} + +impl QueuePausedQuery for Pallet { + fn is_paused(para: &ParaId) -> bool { + if !QueueSuspended::::get() { + return false + } + + // Make an exception for the superuser queue: + let sender_origin = T::ControllerOriginConverter::convert_origin( + (Parent, Parachain((*para).into())), + OriginKind::Superuser, + ); + let is_controller = + sender_origin.map_or(false, |origin| T::ControllerOrigin::try_origin(origin).is_ok()); + + !is_controller + } +} + impl XcmpMessageHandler for Pallet { fn handle_xcmp_messages<'a, I: Iterator>( iter: I, max_weight: Weight, ) -> Weight { - let mut status = >::get(); - - let QueueConfigData { suspend_threshold, drop_threshold, .. } = >::get(); + let mut meter = WeightMeter::with_limit(max_weight); - for (sender, sent_at, data) in iter { - // Figure out the message format. - let mut data_ref = data; - let format = match XcmpMessageFormat::decode_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut data_ref, - ) { + for (sender, _sent_at, mut data) in iter { + let format = match XcmpMessageFormat::decode(&mut data) { Ok(f) => f, Err(_) => { - debug_assert!(false, "Unknown XCMP message format. Silently dropping message"); + defensive!("Unknown XCMP message format - dropping"); continue }, }; - if format == XcmpMessageFormat::Signals { - while !data_ref.is_empty() { - use ChannelSignal::*; - match ChannelSignal::decode(&mut data_ref) { - Ok(Suspend) => Self::suspend_channel(sender), - Ok(Resume) => Self::resume_channel(sender), - Err(_) => break, - } - } - } else { - // Record the fact we received it. - match status.binary_search_by_key(&sender, |item| item.sender) { - Ok(i) => { - let count = status[i].message_metadata.len() as u32; - if count >= suspend_threshold && status[i].state == InboundState::Ok { - status[i].state = InboundState::Suspended; - let r = Self::send_signal(sender, ChannelSignal::Suspend); - if r.is_err() { - log::warn!( - "Attempt to suspend channel failed. Messages may be dropped." - ); - } + + match format { + XcmpMessageFormat::Signals => + while !data.is_empty() { + if meter + .try_consume( + T::WeightInfo::suspend_channel() + .max(T::WeightInfo::resume_channel()), + ) + .is_err() + { + defensive!("Not enough weight to process signals - dropping"); + break } - if count < drop_threshold { - status[i].message_metadata.push((sent_at, format)); - } else { - debug_assert!( - false, - "XCMP channel queue full. Silently dropping message" - ); + + match ChannelSignal::decode(&mut data) { + Ok(ChannelSignal::Suspend) => Self::suspend_channel(sender), + Ok(ChannelSignal::Resume) => Self::resume_channel(sender), + Err(_) => { + defensive!("Undecodable channel signal - dropping"); + break + }, } - // Update the delivery fee factor, if applicable. - if count > suspend_threshold { - let message_size_factor = - FixedU128::from((data_ref.len() / 1024) as u128) - .saturating_mul(delivery_fee_constants::MESSAGE_SIZE_FEE_BASE); - Self::increase_fee_factor(sender, message_size_factor); + }, + XcmpMessageFormat::ConcatenatedVersionedXcm => + while !data.is_empty() { + let Ok(xcm) = Self::take_first_concatenated_xcm(&mut data, &mut meter) + else { + defensive!("HRMP inbound decode stream broke; page will be dropped.",); + break + }; + + if let Err(()) = Self::enqueue_xcmp_message(sender, xcm, &mut meter) { + defensive!( + "Could not enqueue XCMP messages. Used weight: ", + meter.consumed_ratio() + ); + break } }, - Err(_) => status.push(InboundChannelDetails { - sender, - state: InboundState::Ok, - message_metadata: vec![(sent_at, format)], - }), - } - // Queue the payload for later execution. - >::insert(sender, sent_at, data_ref); + XcmpMessageFormat::ConcatenatedEncodedBlob => { + defensive!("Blob messages are unhandled - dropping"); + continue + }, } - - // Optimization note; it would make sense to execute messages immediately if - // `status.is_empty()` here. } - status.sort(); - >::put(status); - Self::service_xcmp_queue(max_weight) + meter.consumed() } } @@ -1136,14 +790,6 @@ impl XcmpMessageSource for Pallet { mut last_index, } = *status; - if result.len() == max_message_count { - // We check this condition in the beginning of the loop so that we don't include - // a message where the limit is 0. - break - } - if outbound_state == OutboundState::Suspended { - continue - } let (max_size_now, max_size_ever) = match T::ChannelInfo::get_channel_status(para_id) { ChannelStatus::Closed => { // This means that there is no such channel anymore. Nothing to be done but @@ -1161,15 +807,28 @@ impl XcmpMessageSource for Pallet { ChannelStatus::Ready(n, e) => (n, e), }; + // This is a hard limit from the host config; not even signals can bypass it. + if result.len() == max_message_count { + // We check this condition in the beginning of the loop so that we don't include + // a message where the limit is 0. + break + } + let page = if signals_exist { let page = >::get(para_id); + defensive_assert!(!page.is_empty(), "Signals must exist"); + if page.len() < max_size_now { >::remove(para_id); signals_exist = false; page } else { + defensive!("Signals should fit into a single page"); continue } + } else if outbound_state == OutboundState::Suspended { + // Signals are exempt from suspension. + continue } else if last_index > first_index { let page = >::get(para_id, first_index); if page.len() < max_size_now { @@ -1189,9 +848,9 @@ impl XcmpMessageSource for Pallet { if page.len() > max_size_ever { // TODO: #274 This means that the channel's max message size has changed since - // the message was sent. We should parse it and split into smaller mesasges but + // the message was sent. We should parse it and split into smaller messages but // since it's so unlikely then for now we just drop it. - log::warn!("WARNING: oversize message in queue. silently dropping."); + defensive!("WARNING: oversize message in queue - dropping"); } else { result.push((para_id, page)); } @@ -1219,6 +878,7 @@ impl XcmpMessageSource for Pallet { last_index, }; } + debug_assert!(!statuses.iter().any(|s| s.signals_exist), "Signals should be handled"); // Sort the outbound messages by ascending recipient para id to satisfy the acceptance // criteria requirement. @@ -1266,6 +926,9 @@ impl SendXcm for Pallet { let price = T::PriceForSiblingDelivery::price_for_delivery(id, &xcm); let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm) .map_err(|()| SendError::DestinationUnsupported)?; + validate_xcm_nesting(&versioned_xcm) + .map_err(|()| SendError::ExceedsMaxMessageSize)?; + Ok(((id, versioned_xcm), price)) }, _ => { @@ -1279,17 +942,31 @@ impl SendXcm for Pallet { fn deliver((id, xcm): (ParaId, VersionedXcm<()>)) -> Result { let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + defensive_assert!( + validate_xcm_nesting(&xcm).is_ok(), + "Tickets are valid prior to delivery by trait XCM; qed" + ); match Self::send_fragment(id, XcmpMessageFormat::ConcatenatedVersionedXcm, xcm) { Ok(_) => { Self::deposit_event(Event::XcmpMessageSent { message_hash: hash }); Ok(hash) }, - Err(e) => Err(SendError::Transport(<&'static str>::from(e))), + Err(e) => Err(SendError::Transport(e.into())), } } } +/// Checks that the XCM is decodable with `MAX_XCM_DECODE_DEPTH`. +/// +/// Note that this uses the limit of the sender - not the receiver. It it best effort. +pub(crate) fn validate_xcm_nesting(xcm: &VersionedXcm<()>) -> Result<(), ()> { + xcm.using_encoded(|mut enc| { + VersionedXcm::<()>::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut enc).map(|_| ()) + }) + .map_err(|_| ()) +} + impl FeeTracker for Pallet { type Id = ParaId; diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index a54ddfb9cec..6d7f434b041 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -16,20 +16,23 @@ //! A module that is responsible for migration of storage. -use crate::{Config, Overweight, Pallet, QueueConfig, DEFAULT_POV_SIZE}; +use crate::{Config, OverweightIndex, Pallet, ParaId, QueueConfig, DEFAULT_POV_SIZE}; +use cumulus_primitives_core::XcmpMessageFormat; use frame_support::{ pallet_prelude::*, - traits::{OnRuntimeUpgrade, StorageVersion}, + traits::{EnqueueMessage, OnRuntimeUpgrade, StorageVersion}, weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, }; /// The current storage version. pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); +pub const LOG: &str = "runtime::xcmp-queue-migration"; + /// Migrates the pallet storage to the most recent version. -pub struct Migration(PhantomData); +pub struct MigrationToV3(PhantomData); -impl OnRuntimeUpgrade for Migration { +impl OnRuntimeUpgrade for MigrationToV3 { fn on_runtime_upgrade() -> Weight { let mut weight = T::DbWeight::get().reads(1); @@ -77,11 +80,55 @@ mod v1 { } } +pub mod v3 { + use super::*; + use crate::*; + + /// Status of the inbound XCMP channels. + #[frame_support::storage_alias] + pub(crate) type InboundXcmpStatus = + StorageValue, Vec, OptionQuery>; + + /// Inbound aggregate XCMP messages. It can only be one per ParaId/block. + #[frame_support::storage_alias] + pub(crate) type InboundXcmpMessages = StorageDoubleMap< + Pallet, + Blake2_128Concat, + ParaId, + Twox64Concat, + RelayBlockNumber, + Vec, + OptionQuery, + >; + + #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] + pub struct InboundChannelDetails { + /// The `ParaId` of the parachain that this channel is connected with. + pub sender: ParaId, + /// The state of the channel. + pub state: InboundState, + /// The ordered metadata of each inbound message. + /// + /// Contains info about the relay block number that the message was sent at, and the format + /// of the incoming message. + pub message_metadata: Vec<(RelayBlockNumber, XcmpMessageFormat)>, + } + + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo, + )] + pub enum InboundState { + Ok, + Suspended, + } +} + /// Migrates `QueueConfigData` from v1 (using only reference time weights) to v2 (with /// 2D weights). /// /// NOTE: Only use this function if you know what you're doing. Default to using /// `migrate_to_latest`. +#[allow(deprecated)] pub fn migrate_to_v2() -> Weight { let translate = |pre: v1::QueueConfigData| -> super::QueueConfigData { super::QueueConfigData { @@ -108,17 +155,70 @@ pub fn migrate_to_v2() -> Weight { } pub fn migrate_to_v3() -> Weight { + #[frame_support::storage_alias] + type Overweight = + CountedStorageMap, Twox64Concat, OverweightIndex, ParaId>; let overweight_messages = Overweight::::initialize_counter() as u64; T::DbWeight::get().reads_writes(overweight_messages, 1) } +pub fn lazy_migrate_inbound_queue() { + let Some(mut states) = v3::InboundXcmpStatus::::get() else { + log::debug!(target: LOG, "Lazy migration finished: item gone"); + return + }; + let Some(ref mut next) = states.first_mut() else { + log::debug!(target: LOG, "Lazy migration finished: item empty"); + v3::InboundXcmpStatus::::kill(); + return + }; + log::debug!( + "Migrating inbound HRMP channel with sibling {:?}, msgs left {}.", + next.sender, + next.message_metadata.len() + ); + // We take the last element since the MQ is a FIFO and we want to keep the order. + let Some((block_number, format)) = next.message_metadata.pop() else { + states.remove(0); + v3::InboundXcmpStatus::::put(states); + return + }; + if format != XcmpMessageFormat::ConcatenatedVersionedXcm { + log::warn!(target: LOG, + "Dropping message with format {:?} (not ConcatenatedVersionedXcm)", + format + ); + v3::InboundXcmpMessages::::remove(&next.sender, &block_number); + v3::InboundXcmpStatus::::put(states); + return + } + + let Some(msg) = v3::InboundXcmpMessages::::take(&next.sender, &block_number) else { + defensive!("Storage corrupted: HRMP message missing:", (next.sender, block_number)); + v3::InboundXcmpStatus::::put(states); + return + }; + + let Ok(msg): Result, _> = msg.try_into() else { + log::error!(target: LOG, "Message dropped: too big"); + v3::InboundXcmpStatus::::put(states); + return + }; + + // Finally! We have a proper message. + T::XcmpQueue::enqueue_message(msg.as_bounded_slice(), next.sender); + log::debug!(target: LOG, "Migrated HRMP message to MQ: {:?}", (next.sender, block_number)); + v3::InboundXcmpStatus::::put(states); +} + #[cfg(test)] mod tests { use super::*; use crate::mock::{new_test_ext, Test}; #[test] + #[allow(deprecated)] fn test_migration_to_v2() { let v1 = v1::QueueConfigData { suspend_threshold: 5, diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 8f567aac2f6..7c3a3bd1bd0 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -17,10 +17,11 @@ use super::*; use crate as xcmp_queue; use core::marker::PhantomData; use cumulus_pallet_parachain_system::AnyRelayNumber; -use cumulus_primitives_core::{IsSystem, ParaId}; +use cumulus_primitives_core::{ChannelInfo, IsSystem, ParaId}; use frame_support::{ parameter_types, traits::{ConstU32, Everything, Nothing, OriginTrait}, + BoundedSlice, }; use frame_system::EnsureRoot; use sp_core::H256; @@ -105,11 +106,13 @@ impl pallet_balances::Config for Test { } impl cumulus_pallet_parachain_system::Config for Test { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = (); type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = (); + // Ignore all DMP messages by enqueueing them into `()`: + type DmpQueue = frame_support::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; type ReservedDmpWeight = (); type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = (); @@ -199,6 +202,54 @@ impl ConvertOrigin } } +parameter_types! { + pub static EnqueuedMessages: Vec<(ParaId, Vec)> = Default::default(); +} + +/// An `EnqueueMessage` implementation that puts all messages in thread-local storage. +pub struct EnqueueToLocalStorage(PhantomData); + +impl> EnqueueMessage for EnqueueToLocalStorage { + type MaxMessageLen = sp_core::ConstU32<65_536>; + + fn enqueue_message(message: BoundedSlice, origin: ParaId) { + let mut msgs = EnqueuedMessages::get(); + msgs.push((origin, message.to_vec())); + EnqueuedMessages::set(msgs); + T::on_queue_changed(origin, Self::footprint(origin)); + } + + fn enqueue_messages<'a>( + iter: impl Iterator>, + origin: ParaId, + ) { + let mut msgs = EnqueuedMessages::get(); + msgs.extend(iter.map(|m| (origin, m.to_vec()))); + EnqueuedMessages::set(msgs); + T::on_queue_changed(origin, Self::footprint(origin)); + } + + fn sweep_queue(origin: ParaId) { + let mut msgs = EnqueuedMessages::get(); + msgs.retain(|(o, _)| o != &origin); + EnqueuedMessages::set(msgs); + T::on_queue_changed(origin, Self::footprint(origin)); + } + + fn footprint(origin: ParaId) -> QueueFootprint { + let msgs = EnqueuedMessages::get(); + let mut footprint = QueueFootprint::default(); + for (o, m) in msgs { + if o == origin { + footprint.storage.count += 1; + footprint.storage.size += m.len() as u64; + } + } + footprint.pages = footprint.storage.size as u32 / 16; // Number does not matter + footprint + } +} + parameter_types! { /// The asset ID for the asset that we use to pay for message delivery fees. pub FeeAssetId: AssetId = Concrete(RelayChain::get()); @@ -217,10 +268,10 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl Config for Test { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = xcm_executor::XcmExecutor; - type ChannelInfo = ParachainSystem; + type ChannelInfo = MockedChannelInfo; type VersionWrapper = (); - type ExecuteOverweightOrigin = EnsureRoot; + type XcmpQueue = EnqueueToLocalStorage>; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = SystemParachainAsSuperuser; type WeightInfo = (); @@ -228,6 +279,60 @@ impl Config for Test { } pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - t.into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() +} + +/// A para that we have an HRMP channel with. +pub const HRMP_PARA_ID: u32 = 7777; + +pub struct MockedChannelInfo; +impl GetChannelInfo for MockedChannelInfo { + fn get_channel_status(id: ParaId) -> ChannelStatus { + if id == HRMP_PARA_ID.into() { + return ChannelStatus::Ready(usize::MAX, usize::MAX) + } + + ParachainSystem::get_channel_status(id) + } + + fn get_channel_info(id: ParaId) -> Option { + if id == HRMP_PARA_ID.into() { + return Some(ChannelInfo { + max_capacity: u32::MAX, + max_total_size: u32::MAX, + max_message_size: u32::MAX, + msg_count: 0, + total_size: 0, + }) + } + + ParachainSystem::get_channel_info(id) + } +} + +pub(crate) fn mk_page() -> Vec { + let mut page = Vec::::new(); + + for i in 0..100 { + page.extend(match i % 2 { + 0 => v2_xcm().encode(), + 1 => v3_xcm().encode(), + // We cannot push an undecodable XCM here since it would break the decode stream. + // This is expected and the whole reason to introduce `MaybeDoubleEncodedVersionedXcm` + // instead. + _ => unreachable!(), + }); + } + + page +} + +pub(crate) fn v2_xcm() -> VersionedXcm<()> { + let instr = xcm::v2::Instruction::<()>::ClearOrigin; + VersionedXcm::V2(xcm::v2::Xcm::<()>(vec![instr; 3])) +} + +pub(crate) fn v3_xcm() -> VersionedXcm<()> { + let instr = xcm::v3::Instruction::<()>::Trap(1); + VersionedXcm::V3(xcm::v3::Xcm::<()>(vec![instr; 3])) } diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index bab7e92ca2d..30dba6ead34 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -13,247 +13,325 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::*; +use super::{ + mock::{mk_page, v2_xcm, v3_xcm, EnqueuedMessages, HRMP_PARA_ID}, + *, +}; +use XcmpMessageFormat::*; + +use codec::Input; use cumulus_primitives_core::{ParaId, XcmpMessageHandler}; -use frame_support::{assert_noop, assert_ok}; -use mock::{new_test_ext, ParachainSystem, RuntimeCall, RuntimeOrigin, Test, XcmpQueue}; -use sp_runtime::traits::BadOrigin; +use frame_support::{ + assert_err, assert_noop, assert_ok, assert_storage_noop, hypothetically, + traits::{Footprint, Hooks}, + StorageNoopGuard, +}; +use mock::{new_test_ext, ParachainSystem, RuntimeOrigin as Origin, Test, XcmpQueue}; +use sp_runtime::traits::{BadOrigin, Zero}; +use std::iter::{once, repeat}; #[test] -fn one_message_does_not_panic() { +fn empty_concatenated_works() { new_test_ext().execute_with(|| { - let message_format = XcmpMessageFormat::ConcatenatedVersionedXcm.encode(); - let messages = vec![(Default::default(), 1u32, message_format.as_slice())]; + let data = ConcatenatedVersionedXcm.encode(); - // This shouldn't cause a panic - XcmpQueue::handle_xcmp_messages(messages.into_iter(), Weight::MAX); + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); }) } #[test] -#[should_panic = "Invalid incoming blob message data"] -#[cfg(debug_assertions)] -fn bad_message_is_handled() { +fn xcm_enqueueing_basic_works() { new_test_ext().execute_with(|| { - let bad_data = vec![ - 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 64, 239, 139, 0, - 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 37, 0, - 0, 0, 0, 0, 0, 0, 16, 0, 127, 147, - ]; - InboundXcmpMessages::::insert(ParaId::from(1000), 1, bad_data); - let format = XcmpMessageFormat::ConcatenatedEncodedBlob; - // This should exit with an error. - XcmpQueue::process_xcmp_message( - 1000.into(), - (1, format), - &mut 0, - Weight::from_parts(10_000_000_000, 0), - Weight::from_parts(10_000_000_000, 0), - ); - }); + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])).encode(); + let data = [ConcatenatedVersionedXcm.encode(), xcm.clone()].concat(); + + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); + + assert_eq!(EnqueuedMessages::get(), vec![(1000.into(), xcm)]); + }) } -/// Tests that a blob message is handled. Currently this isn't implemented and panics when debug -/// assertions are enabled. When this feature is enabled, this test should be rewritten properly. #[test] -#[should_panic = "Blob messages not handled."] -#[cfg(debug_assertions)] -fn handle_blob_message() { +fn xcm_enqueueing_many_works() { new_test_ext().execute_with(|| { - let bad_data = vec![ - 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 64, 239, - 139, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, - 37, 0, 0, 0, 0, 0, 0, 0, 16, 0, 127, 147, - ]; - InboundXcmpMessages::::insert(ParaId::from(1000), 1, bad_data); - let format = XcmpMessageFormat::ConcatenatedEncodedBlob; - XcmpQueue::process_xcmp_message( - 1000.into(), - (1, format), - &mut 0, - Weight::from_parts(10_000_000_000, 0), - Weight::from_parts(10_000_000_000, 0), + let mut encoded_xcms = vec![]; + for i in 0..10 { + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin; i as usize])); + encoded_xcms.push(xcm.encode()); + } + let mut data = ConcatenatedVersionedXcm.encode(); + data.extend(encoded_xcms.iter().flatten()); + + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); + + assert_eq!( + EnqueuedMessages::get(), + encoded_xcms.into_iter().map(|xcm| (1000.into(), xcm)).collect::>(), ); - }); + }) } #[test] -#[should_panic = "Invalid incoming XCMP message data"] -#[cfg(debug_assertions)] -fn handle_invalid_data() { +fn xcm_enqueueing_multiple_times_works() { new_test_ext().execute_with(|| { - let data = Xcm::(vec![]).encode(); - InboundXcmpMessages::::insert(ParaId::from(1000), 1, data); - let format = XcmpMessageFormat::ConcatenatedVersionedXcm; - XcmpQueue::process_xcmp_message( - 1000.into(), - (1, format), - &mut 0, - Weight::from_parts(10_000_000_000, 0), - Weight::from_parts(10_000_000_000, 0), + let mut encoded_xcms = vec![]; + for _ in 0..10 { + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])); + encoded_xcms.push(xcm.encode()); + } + let mut data = ConcatenatedVersionedXcm.encode(); + data.extend(encoded_xcms.iter().flatten()); + + for i in 0..10 { + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); + assert_eq!((i + 1) * 10, EnqueuedMessages::get().len()); + } + + assert_eq!( + EnqueuedMessages::get(), + encoded_xcms + .into_iter() + .map(|xcm| (1000.into(), xcm)) + .cycle() + .take(100) + .collect::>(), ); - }); + }) } #[test] -fn service_overweight_unknown() { +#[cfg_attr(debug_assertions, should_panic = "Defensive failure")] +fn xcm_enqueueing_starts_dropping_on_overflow() { new_test_ext().execute_with(|| { - assert_noop!( - XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)), - Error::::BadOverweightIndex, + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])); + let data = (ConcatenatedVersionedXcm, xcm).encode(); + // Its possible to enqueue 256 messages at most: + let limit = 256; + + XcmpQueue::handle_xcmp_messages( + repeat((1000.into(), 1, data.as_slice())).take(limit * 2), + Weight::MAX, ); - }); + assert_eq!(EnqueuedMessages::get().len(), limit); + // The drop threshold for pages is 48, the others numbers dont really matter: + assert_eq!( + ::XcmpQueue::footprint(1000.into()), + QueueFootprint { storage: Footprint { count: 256, size: 768 }, pages: 48 } + ); + }) } +/// First enqueue 10 good, 1 bad and then 10 good XCMs. +/// +/// It should only process the first 10 good though. #[test] -fn service_overweight_bad_xcm_format() { +#[cfg(not(debug_assertions))] +fn xcm_enqueueing_broken_xcm_works() { new_test_ext().execute_with(|| { - let bad_xcm = vec![255]; - Overweight::::insert(0, (ParaId::from(1000), 0, bad_xcm)); + let mut encoded_xcms = vec![]; + for _ in 0..10 { + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])); + encoded_xcms.push(xcm.encode()); + } + let mut good = ConcatenatedVersionedXcm.encode(); + good.extend(encoded_xcms.iter().flatten()); - assert_noop!( - XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)), - Error::::BadXcm + let mut bad = ConcatenatedVersionedXcm.encode(); + bad.extend(vec![0u8].into_iter()); + + // Of we enqueue them in multiple pages, then its fine. + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, good.as_slice())), Weight::MAX); + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, bad.as_slice())), Weight::MAX); + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, good.as_slice())), Weight::MAX); + assert_eq!(20, EnqueuedMessages::get().len()); + + assert_eq!( + EnqueuedMessages::get(), + encoded_xcms + .clone() + .into_iter() + .map(|xcm| (1000.into(), xcm)) + .cycle() + .take(20) + .collect::>(), ); - }); + EnqueuedMessages::set(&vec![]); + + // But if we do it all in one page, then it only uses the first 10: + XcmpQueue::handle_xcmp_messages( + vec![(1000.into(), 1, good.as_slice()), (1000.into(), 1, bad.as_slice())].into_iter(), + Weight::MAX, + ); + assert_eq!(10, EnqueuedMessages::get().len()); + assert_eq!( + EnqueuedMessages::get(), + encoded_xcms + .into_iter() + .map(|xcm| (1000.into(), xcm)) + .cycle() + .take(10) + .collect::>(), + ); + }) } +/// Message blobs are not supported and panic in debug mode. #[test] -fn suspend_xcm_execution_works() { +#[should_panic = "Blob messages are unhandled"] +#[cfg(debug_assertions)] +fn bad_blob_message_panics() { new_test_ext().execute_with(|| { - QueueSuspended::::put(true); + let data = [ConcatenatedEncodedBlob.encode(), vec![1].encode()].concat(); - let xcm = - VersionedXcm::from(Xcm::(vec![Instruction::::ClearOrigin])) - .encode(); - let mut message_format = XcmpMessageFormat::ConcatenatedVersionedXcm.encode(); - message_format.extend(xcm.clone()); - let messages = vec![(ParaId::from(999), 1u32, message_format.as_slice())]; - - // This should have executed the incoming XCM, because it came from a system parachain - XcmpQueue::handle_xcmp_messages(messages.into_iter(), Weight::MAX); - - let queued_xcm = InboundXcmpMessages::::get(ParaId::from(999), 1u32); - assert!(queued_xcm.is_empty()); - - let messages = vec![(ParaId::from(2000), 1u32, message_format.as_slice())]; + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); + }); +} - // This shouldn't have executed the incoming XCM - XcmpQueue::handle_xcmp_messages(messages.into_iter(), Weight::MAX); +/// Message blobs do not panic in release mode but are just a No-OP. +#[test] +#[cfg(not(debug_assertions))] +fn bad_blob_message_no_panic() { + new_test_ext().execute_with(|| { + let data = [ConcatenatedEncodedBlob.encode(), vec![1].encode()].concat(); - let queued_xcm = InboundXcmpMessages::::get(ParaId::from(2000), 1u32); - assert_eq!(queued_xcm, xcm); + frame_support::assert_storage_noop!(XcmpQueue::handle_xcmp_messages( + once((1000.into(), 1, data.as_slice())), + Weight::MAX, + )); }); } +/// Invalid concatenated XCMs panic in debug mode. #[test] -fn update_suspend_threshold_works() { +#[should_panic = "HRMP inbound decode stream broke; page will be dropped."] +#[cfg(debug_assertions)] +fn handle_invalid_data_panics() { new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!(data.suspend_threshold, 2); - assert_ok!(XcmpQueue::update_suspend_threshold(RuntimeOrigin::root(), 3)); - assert_noop!(XcmpQueue::update_suspend_threshold(RuntimeOrigin::signed(2), 5), BadOrigin); - let data: QueueConfigData = >::get(); + let data = [ConcatenatedVersionedXcm.encode(), Xcm::(vec![]).encode()].concat(); - assert_eq!(data.suspend_threshold, 3); + XcmpQueue::handle_xcmp_messages(once((1000.into(), 1, data.as_slice())), Weight::MAX); }); } +/// Invalid concatenated XCMs do not panic in release mode but are just a No-OP. #[test] -fn update_drop_threshold_works() { +#[cfg(not(debug_assertions))] +fn handle_invalid_data_no_panic() { new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!(data.drop_threshold, 5); - assert_ok!(XcmpQueue::update_drop_threshold(RuntimeOrigin::root(), 6)); - assert_noop!(XcmpQueue::update_drop_threshold(RuntimeOrigin::signed(2), 7), BadOrigin); - let data: QueueConfigData = >::get(); + let data = [ConcatenatedVersionedXcm.encode(), Xcm::(vec![]).encode()].concat(); - assert_eq!(data.drop_threshold, 6); + frame_support::assert_storage_noop!(XcmpQueue::handle_xcmp_messages( + once((1000.into(), 1, data.as_slice())), + Weight::MAX, + )); }); } #[test] -fn update_resume_threshold_works() { +fn suspend_xcm_execution_works() { new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!(data.resume_threshold, 1); - assert_ok!(XcmpQueue::update_resume_threshold(RuntimeOrigin::root(), 2)); - assert_noop!(XcmpQueue::update_resume_threshold(RuntimeOrigin::signed(7), 3), BadOrigin); - let data: QueueConfigData = >::get(); - - assert_eq!(data.resume_threshold, 2); + assert!(!XcmpQueue::is_paused(&2000.into())); + QueueSuspended::::put(true); + assert!(XcmpQueue::is_paused(&2000.into())); + // System parachains can bypass suspension: + assert!(!XcmpQueue::is_paused(&999.into())); }); } #[test] -fn update_threshold_weight_works() { +fn suspend_and_resume_xcm_execution_work() { new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!(data.threshold_weight, Weight::from_parts(100_000, 0)); - assert_ok!(XcmpQueue::update_threshold_weight( - RuntimeOrigin::root(), - Weight::from_parts(10_000, 0) - )); + assert_noop!(XcmpQueue::suspend_xcm_execution(Origin::signed(1)), BadOrigin); + assert_ok!(XcmpQueue::suspend_xcm_execution(Origin::root())); assert_noop!( - XcmpQueue::update_threshold_weight( - RuntimeOrigin::signed(5), - Weight::from_parts(10_000_000, 0), - ), - BadOrigin + XcmpQueue::suspend_xcm_execution(Origin::root()), + Error::::AlreadySuspended ); - let data: QueueConfigData = >::get(); + assert!(QueueSuspended::::get()); - assert_eq!(data.threshold_weight, Weight::from_parts(10_000, 0)); + assert_noop!(XcmpQueue::resume_xcm_execution(Origin::signed(1)), BadOrigin); + assert_ok!(XcmpQueue::resume_xcm_execution(Origin::root())); + assert_noop!( + XcmpQueue::resume_xcm_execution(Origin::root()), + Error::::AlreadyResumed + ); + assert!(!QueueSuspended::::get()); }); } #[test] -fn update_weight_restrict_decay_works() { +#[cfg(not(debug_assertions))] +fn xcm_enqueueing_backpressure_works() { + let para: ParaId = 1000.into(); new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!(data.weight_restrict_decay, Weight::from_parts(2, 0)); - assert_ok!(XcmpQueue::update_weight_restrict_decay( - RuntimeOrigin::root(), - Weight::from_parts(5, 0) - )); - assert_noop!( - XcmpQueue::update_weight_restrict_decay( - RuntimeOrigin::signed(6), - Weight::from_parts(4, 0), - ), - BadOrigin - ); - let data: QueueConfigData = >::get(); + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])); + let data = (ConcatenatedVersionedXcm, xcm).encode(); + + XcmpQueue::handle_xcmp_messages(repeat((para, 1, data.as_slice())).take(170), Weight::MAX); + + assert_eq!(EnqueuedMessages::get().len(), 170,); + // Not yet suspended: + assert!(InboundXcmpSuspended::::get().is_empty()); + // Enqueueing one more will suspend it: + let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])).encode(); + let small = [ConcatenatedVersionedXcm.encode(), xcm].concat(); + + XcmpQueue::handle_xcmp_messages(once((para, 1, small.as_slice())), Weight::MAX); + // Suspended: + assert_eq!(InboundXcmpSuspended::::get().iter().collect::>(), vec![¶]); + + // Now enqueueing many more will only work until the drop threshold: + XcmpQueue::handle_xcmp_messages(repeat((para, 1, data.as_slice())).take(100), Weight::MAX); + assert_eq!(mock::EnqueuedMessages::get().len(), 256); + + crate::mock::EnqueueToLocalStorage::>::sweep_queue(para); + XcmpQueue::handle_xcmp_messages(once((para, 1, small.as_slice())), Weight::MAX); + // Got resumed: + assert!(InboundXcmpSuspended::::get().is_empty()); + // Still resumed: + XcmpQueue::handle_xcmp_messages(once((para, 1, small.as_slice())), Weight::MAX); + assert!(InboundXcmpSuspended::::get().is_empty()); + }); +} + +#[test] +fn update_suspend_threshold_works() { + new_test_ext().execute_with(|| { + assert_eq!(>::get().suspend_threshold, 32); + assert_noop!(XcmpQueue::update_suspend_threshold(Origin::signed(2), 49), BadOrigin); - assert_eq!(data.weight_restrict_decay, Weight::from_parts(5, 0)); + assert_ok!(XcmpQueue::update_suspend_threshold(Origin::root(), 33)); + assert_eq!(>::get().suspend_threshold, 33); }); } #[test] -fn update_xcmp_max_individual_weight() { +fn update_drop_threshold_works() { new_test_ext().execute_with(|| { - let data: QueueConfigData = >::get(); - assert_eq!( - data.xcmp_max_individual_weight, - Weight::from_parts(20u64 * WEIGHT_REF_TIME_PER_MILLIS, DEFAULT_POV_SIZE), + assert_eq!(>::get().drop_threshold, 48); + assert_ok!(XcmpQueue::update_drop_threshold(Origin::root(), 4000)); + assert_noop!(XcmpQueue::update_drop_threshold(Origin::signed(2), 7), BadOrigin); + + assert_eq!(>::get().drop_threshold, 4000); + }); +} + +#[test] +fn update_resume_threshold_works() { + new_test_ext().execute_with(|| { + assert_eq!(>::get().resume_threshold, 8); + assert_noop!( + XcmpQueue::update_resume_threshold(Origin::root(), 0), + Error::::BadQueueConfig ); - assert_ok!(XcmpQueue::update_xcmp_max_individual_weight( - RuntimeOrigin::root(), - Weight::from_parts(30u64 * WEIGHT_REF_TIME_PER_MILLIS, 0) - )); assert_noop!( - XcmpQueue::update_xcmp_max_individual_weight( - RuntimeOrigin::signed(3), - Weight::from_parts(10u64 * WEIGHT_REF_TIME_PER_MILLIS, 0) - ), - BadOrigin + XcmpQueue::update_resume_threshold(Origin::root(), 33), + Error::::BadQueueConfig ); - let data: QueueConfigData = >::get(); + assert_ok!(XcmpQueue::update_resume_threshold(Origin::root(), 16)); + assert_noop!(XcmpQueue::update_resume_threshold(Origin::signed(7), 3), BadOrigin); - assert_eq!( - data.xcmp_max_individual_weight, - Weight::from_parts(30u64 * WEIGHT_REF_TIME_PER_MILLIS, 0) - ); + assert_eq!(>::get().resume_threshold, 16); }); } @@ -343,6 +421,287 @@ fn xcmp_queue_consumes_dest_and_msg_on_ok_validate() { }); } +#[test] +fn xcmp_queue_validate_nested_xcm_works() { + let dest = (Parent, X1(Parachain(5555))); + // Message that is not too deeply nested: + let mut good = Xcm(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + good = Xcm(vec![SetAppendix(good)]); + } + + new_test_ext().execute_with(|| { + // Check that the good message is validated: + assert_ok!(::validate( + &mut Some(dest.into()), + &mut Some(good.clone()) + )); + + // Nesting the message one more time should reject it: + let bad = Xcm(vec![SetAppendix(good)]); + assert_eq!( + Err(SendError::ExceedsMaxMessageSize), + ::validate(&mut Some(dest.into()), &mut Some(bad)) + ); + }); +} + +#[test] +fn send_xcm_nested_works() { + let dest = (Parent, X1(Parachain(HRMP_PARA_ID))); + // Message that is not too deeply nested: + let mut good = Xcm(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + good = Xcm(vec![SetAppendix(good)]); + } + + // Check that the good message is sent: + new_test_ext().execute_with(|| { + assert_ok!(send_xcm::(dest.into(), good.clone())); + assert_eq!( + XcmpQueue::take_outbound_messages(usize::MAX), + vec![( + HRMP_PARA_ID.into(), + (XcmpMessageFormat::ConcatenatedVersionedXcm, VersionedXcm::V3(good.clone())) + .encode(), + )] + ); + }); + + // Nesting the message one more time should not send it: + let bad = Xcm(vec![SetAppendix(good)]); + new_test_ext().execute_with(|| { + assert_err!(send_xcm::(dest.into(), bad), SendError::ExceedsMaxMessageSize); + assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); + }); +} + +#[test] +fn hrmp_signals_are_prioritized() { + let message = Xcm(vec![Trap(5)]); + + let sibling_para_id = ParaId::from(12345); + let dest = (Parent, X1(Parachain(sibling_para_id.into()))); + let mut dest_wrapper = Some(dest.into()); + let mut msg_wrapper = Some(message.clone()); + + new_test_ext().execute_with(|| { + frame_system::Pallet::::set_block_number(1); + ::validate(&mut dest_wrapper, &mut msg_wrapper).unwrap(); + + // check wrapper were consumed + assert_eq!(None, dest_wrapper.take()); + assert_eq!(None, msg_wrapper.take()); + + ParachainSystem::open_custom_outbound_hrmp_channel_for_benchmarks_or_tests( + sibling_para_id, + cumulus_primitives_core::AbridgedHrmpChannel { + max_capacity: 128, + max_total_size: 1 << 16, + max_message_size: 128, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + + let taken = XcmpQueue::take_outbound_messages(130); + assert_eq!(taken, vec![]); + + // Enqueue some messages + let num_events = frame_system::Pallet::::events().len(); + for _ in 0..256 { + assert_ok!(send_xcm::(dest.into(), message.clone())); + } + assert_eq!(num_events + 256, frame_system::Pallet::::events().len()); + + // Without a signal we get the messages in order: + let mut expected_msg = XcmpMessageFormat::ConcatenatedVersionedXcm.encode(); + for _ in 0..31 { + expected_msg.extend(VersionedXcm::V3(message.clone()).encode()); + } + + hypothetically!({ + let taken = XcmpQueue::take_outbound_messages(usize::MAX); + assert_eq!(taken, vec![(sibling_para_id.into(), expected_msg,)]); + }); + + // But a signal gets prioritized instead of the messages: + XcmpQueue::send_signal(sibling_para_id.into(), ChannelSignal::Suspend); + + let taken = XcmpQueue::take_outbound_messages(130); + assert_eq!( + taken, + vec![( + sibling_para_id.into(), + (XcmpMessageFormat::Signals, ChannelSignal::Suspend).encode() + )] + ); + }); +} + +#[test] +fn maybe_double_encoded_versioned_xcm_works() { + // pre conditions + assert_eq!(VersionedXcm::<()>::V2(Default::default()).encode(), &[2, 0]); + assert_eq!(VersionedXcm::<()>::V3(Default::default()).encode(), &[3, 0]); +} + +// Now also testing a page instead of just concat messages. +#[test] +fn maybe_double_encoded_versioned_xcm_decode_page_works() { + let page = mk_page(); + + // Now try to decode the page. + let input = &mut &page[..]; + for i in 0..100 { + match (i % 2, VersionedXcm::<()>::decode(input)) { + (0, Ok(xcm)) => { + assert_eq!(xcm, v2_xcm()); + }, + (1, Ok(xcm)) => { + assert_eq!(xcm, v3_xcm()); + }, + unexpected => unreachable!("{:?}", unexpected), + } + } + + assert_eq!(input.remaining_len(), Ok(Some(0)), "All data consumed"); +} + +/// Check that `take_first_concatenated_xcm` correctly splits a page into its XCMs. +#[test] +fn take_first_concatenated_xcm_works() { + let page = mk_page(); + let input = &mut &page[..]; + + for i in 0..100 { + let xcm = XcmpQueue::take_first_concatenated_xcm(input, &mut WeightMeter::new()).unwrap(); + match (i % 2, xcm) { + (0, data) | (2, data) => { + assert_eq!(data, v2_xcm().encode()); + }, + (1, data) | (3, data) => { + assert_eq!(data, v3_xcm().encode()); + }, + unexpected => unreachable!("{:?}", unexpected), + } + } + assert_eq!(input.remaining_len(), Ok(Some(0)), "All data consumed"); +} + +/// A message that is not too deeply nested will be accepted by `take_first_concatenated_xcm`. +#[test] +fn take_first_concatenated_xcm_good_recursion_depth_works() { + let mut good = Xcm::<()>(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + good = Xcm(vec![SetAppendix(good)]); + } + let good = VersionedXcm::V3(good); + + let page = good.encode(); + assert_ok!(XcmpQueue::take_first_concatenated_xcm(&mut &page[..], &mut WeightMeter::new())); +} + +/// A message that is too deeply nested will be rejected by `take_first_concatenated_xcm`. +#[test] +fn take_first_concatenated_xcm_good_bad_depth_errors() { + let mut bad = Xcm::<()>(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH { + bad = Xcm(vec![SetAppendix(bad)]); + } + let bad = VersionedXcm::V3(bad); + + let page = bad.encode(); + assert_err!( + XcmpQueue::take_first_concatenated_xcm(&mut &page[..], &mut WeightMeter::new()), + () + ); +} + +#[test] +fn lazy_migration_works() { + use crate::migration::v3::*; + + new_test_ext().execute_with(|| { + EnqueuedMessages::set(vec![]); + let _g = StorageNoopGuard::default(); // No storage is leaked. + + let mut channels = vec![]; + for i in 0..20 { + let para = ParaId::from(i); + let mut message_metadata = vec![]; + for block in 0..30 { + message_metadata.push((block, XcmpMessageFormat::ConcatenatedVersionedXcm)); + InboundXcmpMessages::::insert(para, block, vec![(i + block) as u8]); + } + + channels.push(InboundChannelDetails { + sender: para, + state: InboundState::Ok, + message_metadata, + }); + } + InboundXcmpStatus::::set(Some(channels)); + + for para in 0..20u32 { + assert_eq!(InboundXcmpStatus::::get().unwrap().len() as u32, 20 - para); + assert_eq!(InboundXcmpMessages::::iter_prefix(ParaId::from(para)).count(), 30); + + for block in 0..30 { + XcmpQueue::on_idle(0u32.into(), Weight::MAX); + assert_eq!( + EnqueuedMessages::get(), + vec![(para.into(), vec![(29 - block + para) as u8])] + ); + EnqueuedMessages::set(vec![]); + } + // One more to jump to the next channel: + XcmpQueue::on_idle(0u32.into(), Weight::MAX); + + assert_eq!(InboundXcmpStatus::::get().unwrap().len() as u32, 20 - para - 1); + assert_eq!(InboundXcmpMessages::::iter_prefix(ParaId::from(para)).count(), 0); + } + // One more for the cleanup: + XcmpQueue::on_idle(0u32.into(), Weight::MAX); + + assert!(!InboundXcmpStatus::::exists()); + assert_eq!(InboundXcmpMessages::::iter().count(), 0); + EnqueuedMessages::set(vec![]); + }); +} + +#[test] +fn lazy_migration_noop_when_out_of_weight() { + use crate::migration::v3::*; + assert!(!XcmpQueue::on_idle_weight().is_zero(), "pre condition"); + + new_test_ext().execute_with(|| { + let _g = StorageNoopGuard::default(); // No storage is leaked. + let block = 5; + let para = ParaId::from(4); + let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)]; + + InboundXcmpMessages::::insert(para, block, vec![123u8]); + InboundXcmpStatus::::set(Some(vec![InboundChannelDetails { + sender: para, + state: InboundState::Ok, + message_metadata, + }])); + + // Hypothetically, it would do something with enough weight limit: + hypothetically!({ + XcmpQueue::on_idle(0u32.into(), Weight::MAX); + assert_eq!(EnqueuedMessages::get(), vec![(para, vec![123u8])]); + }); + // But does not, since the limit is zero: + assert_storage_noop!({ XcmpQueue::on_idle(0u32.into(), Weight::zero()) }); + + InboundXcmpMessages::::remove(para, block); + InboundXcmpStatus::::kill(); + }); +} + #[test] fn xcmp_queue_send_xcm_works() { new_test_ext().execute_with(|| { diff --git a/cumulus/pallets/xcmp-queue/src/weights.rs b/cumulus/pallets/xcmp-queue/src/weights.rs index 2d20bba6f8f..27daa791e19 100644 --- a/cumulus/pallets/xcmp-queue/src/weights.rs +++ b/cumulus/pallets/xcmp-queue/src/weights.rs @@ -13,51 +13,239 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Autogenerated weights for `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// asset-hub-kusama-dev +// --output +// cumulus/pallets/xcmp-queue/src/weights.rs +// --template +// substrate/.maintain/frame-weight-template.hbs +// --extrinsic +// + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; -use sp_std::marker::PhantomData; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; -// Implemented by autogenerated benchmarking code. +/// Weight functions needed for `cumulus_pallet_xcmp_queue`. pub trait WeightInfo { fn set_config_with_u32() -> Weight; - fn set_config_with_weight() -> Weight; + fn enqueue_xcmp_message() -> Weight; + fn suspend_channel() -> Weight; + fn resume_channel() -> Weight; + fn take_first_concatenated_xcm() -> Weight; + fn on_idle_good_msg() -> Weight; + fn on_idle_large_msg() -> Weight; } +/// Weights for `cumulus_pallet_xcmp_queue` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - // Storage: XcmpQueue QueueConfig (r:1 w:1) + /// 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 { - Weight::from_parts(2_717_000_u64, 0) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 1561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - - // Storage: XcmpQueue QueueConfig (r:1 w:1) - fn set_config_with_weight() -> Weight { - Weight::from_parts(2_717_000_u64, 0) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3517` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 3517) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1596) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65747` + // Estimated: `69212` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(66_000_000, 69212) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(52_000_000, 69175) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } } +// For backwards compatibility and tests. impl WeightInfo for () { - // Storage: XcmpQueue QueueConfig (r:1 w:1) + /// 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 { - Weight::from_parts(2_717_000_u64, 0) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 1561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - - // Storage: XcmpQueue QueueConfig (r:1 w:1) - fn set_config_with_weight() -> Weight { - Weight::from_parts(2_717_000_u64, 0) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3517` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 3517) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1596) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65747` + // Estimated: `69212` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(66_000_000, 69212) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(52_000_000, 69175) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index e73c7b50726..3507e9bcd32 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -76,6 +76,7 @@ substrate-build-script-utils = { path = "../../../substrate/utils/build-script-u [features] default = [] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "parachain-template-runtime/runtime-benchmarks", diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 06e818dcdbc..01e25007873 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -35,6 +35,7 @@ frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-fea 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-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } pallet-session = { path = "../../../substrate/frame/session", default-features = false} pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false} pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false} @@ -71,6 +72,7 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } +parachains-common = { path = "../../parachains/common", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../parachains/pallets/parachain-info", default-features = false } [features] @@ -97,6 +99,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-parachain-template/std", "pallet-session/std", "pallet-sudo/std", @@ -105,6 +108,7 @@ std = [ "pallet-transaction-payment/std", "pallet-xcm/std", "parachain-info/std", + "parachains-common/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", @@ -127,9 +131,11 @@ std = [ ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -138,10 +144,12 @@ runtime-benchmarks = [ "hex-literal", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-parachain-template/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -163,6 +171,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-parachain-template/try-runtime", "pallet-session/try-runtime", "pallet-sudo/try-runtime", diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index bfb3e74be9c..7a064e227d4 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -10,7 +10,6 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; @@ -27,12 +26,15 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, + }, weights::{ constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, @@ -44,9 +46,10 @@ use frame_system::{ EnsureRoot, }; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{RelayLocation, XcmConfig, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -58,7 +61,6 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; // XCM Imports use xcm::latest::prelude::BodyId; -use xcm_executor::XcmExecutor; /// Import the template pallet. pub use pallet_parachain_template; @@ -382,14 +384,16 @@ impl pallet_sudo::Config for Runtime { parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -404,26 +408,47 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + 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 = (); - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery; } -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; @@ -514,7 +539,7 @@ construct_runtime!( XcmpQueue: cumulus_pallet_xcmp_queue = 30, PolkadotXcm: pallet_xcm = 31, CumulusXcm: cumulus_pallet_xcm = 32, - DmpQueue: cumulus_pallet_dmp_queue = 33, + MessageQueue: pallet_message_queue = 33, // Template TemplatePallet: pallet_parachain_template = 50, @@ -528,8 +553,10 @@ mod benches { [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] + [pallet_message_queue, MessageQueue] [pallet_sudo, Sudo] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] ); } diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index ebb3cdeaa5d..4aad4dec236 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -23,6 +23,7 @@ pallet-asset-tx-payment = { path = "../../../substrate/frame/transaction-payment pallet-assets = { path = "../../../substrate/frame/assets", default-features = false } pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } +pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } sp-core = { path = "../../../substrate/primitives/core", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } @@ -65,6 +66,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "parachain-info/std", "polkadot-core-primitives/std", "polkadot-primitives/std", @@ -81,6 +83,7 @@ std = [ ] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -88,6 +91,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index 4ebc2cc6e1e..68425a00b35 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -17,6 +17,7 @@ pub mod impls; pub mod kusama; +pub mod message_queue; pub mod polkadot; pub mod rococo; pub mod westend; diff --git a/cumulus/parachains/common/src/message_queue.rs b/cumulus/parachains/common/src/message_queue.rs new file mode 100644 index 00000000000..0c9f4b840c9 --- /dev/null +++ b/cumulus/parachains/common/src/message_queue.rs @@ -0,0 +1,55 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Helpers to deal with configuring the message queue in the runtime. + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use frame_support::traits::{QueueFootprint, QueuePausedQuery}; +use pallet_message_queue::OnQueueChanged; +use sp_std::marker::PhantomData; + +/// Narrow the scope of the `Inner` query from `AggregateMessageOrigin` to `ParaId`. +/// +/// All non-`Sibling` variants will be ignored. +pub struct NarrowOriginToSibling(PhantomData); +impl> QueuePausedQuery + for NarrowOriginToSibling +{ + fn is_paused(origin: &AggregateMessageOrigin) -> bool { + match origin { + AggregateMessageOrigin::Sibling(id) => Inner::is_paused(id), + _ => false, + } + } +} + +impl> OnQueueChanged + for NarrowOriginToSibling +{ + fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) { + if let AggregateMessageOrigin::Sibling(id) = origin { + Inner::on_queue_changed(id, fp) + } + } +} + +/// Convert a sibling `ParaId` to an `AggregateMessageOrigin`. +pub struct ParaIdToSibling; +impl sp_runtime::traits::Convert for ParaIdToSibling { + fn convert(para_id: ParaId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Sibling(para_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 new file mode 100644 index 00000000000..312df8f7a33 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs @@ -0,0 +1,412 @@ +// 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) { + // Errors with `UntrustedReserveLocation`, but the MQ pallet does not report back errors. + AssetHubPolkadot::assert_dmp_queue_incomplete(Some(Weight::from_parts(1_000_000_000, 0))); +} + +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-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 1b6bf995863..9c3378de226 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -38,10 +38,7 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { } fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubRococo::assert_dmp_queue_incomplete( - Some(Weight::from_parts(57_185_000, 3504)), - Some(Error::UntrustedReserveLocation), - ); + AssetHubRococo::assert_dmp_queue_incomplete(Some(Weight::from_parts(57_185_000, 3504))); } fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { 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 4b6b8874b6a..2043431dcc2 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,6 +18,7 @@ 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-message-queue = { path = "../../../../../../substrate/frame/message-queue", default-features = false } pallet-treasury = { path = "../../../../../../substrate/frame/treasury", default-features = false} pallet-asset-rate = { path = "../../../../../../substrate/frame/asset-rate", default-features = false} @@ -47,6 +48,7 @@ integration-tests-common = { path = "../../common", default-features = false} [features] runtime-benchmarks = [ "asset-hub-westend-runtime/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -55,6 +57,7 @@ runtime-benchmarks = [ "pallet-asset-rate/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", 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 6923cd13126..9b646035c29 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 @@ -38,10 +38,7 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { } fn system_para_dest_assertions(_t: RelayToSystemParaTest) { - AssetHubWestend::assert_dmp_queue_incomplete( - Some(Weight::from_parts(31_352_000, 1489)), - Some(Error::UntrustedReserveLocation), - ); + AssetHubWestend::assert_dmp_queue_incomplete(Some(Weight::from_parts(31_352_000, 1489))); } fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index 7d1615c9e29..88d44d9a4fb 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -208,7 +208,9 @@ fn swap_locally_on_chain_using_foreign_assets() { ); }); - // Receive XCM message in Assets Parachain + // One block for the MessageQueue to process the message. + AssetHubWestend::execute_with(|| {}); + // Receive XCM message in Assets Parachain in the next block. AssetHubWestend::execute_with(|| { assert!(::ForeignAssets::asset_exists( *foreign_asset1_at_asset_hub_westend 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 index cf06f58682d..7040d061f5b 100644 --- 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 @@ -103,7 +103,7 @@ fn create_and_claim_treasury_spend() { amount: amount == &SPEND_AMOUNT, }, RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { outcome: Outcome::Complete(..) ,.. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, ] ); // beneficiary received the assets from the treasury. 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 b3ce2a99f70..b969c27aab9 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 @@ -12,6 +12,12 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = # Substrate 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-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} +pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} +pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} +pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index f24e13bb71b..35cfa394174 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -60,8 +60,8 @@ fn example() { assert_expected_events!( BridgeHubRococo, vec![ - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Complete(_), + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: true, .. }) => {}, RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { @@ -91,7 +91,9 @@ fn example() { assert_expected_events!( AssetHubWococo, vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { + .. + }) => {}, ] ); }); diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 1691d21e173..5845e6940fb 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -50,9 +50,8 @@ collectives-polkadot-runtime = { path = "../../../runtimes/collectives/collectiv bridge-hub-kusama-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-kusama" } bridge-hub-polkadot-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-polkadot" } bridge-hub-rococo-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-rococo" } -xcm-emulator = { path = "../../../../xcm/xcm-emulator", default-features = false} -cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue" } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false} +xcm-emulator = { default-features = false, path = "../../../../xcm/xcm-emulator" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../pallets/xcmp-queue" } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } bp-messages = { path = "../../../../../bridges/primitives/messages" } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages" } @@ -71,6 +70,7 @@ runtime-benchmarks = [ "collectives-polkadot-runtime/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "frame-support/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index bb4c9d102e9..613bb302e56 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -23,7 +23,11 @@ pub use crate::{ }; // Substrate -pub use frame_support::{assert_ok, traits::fungibles::Inspect}; +pub use frame_support::{ + assert_ok, + traits::fungibles::Inspect, + weights::{Weight, WeightMeter}, +}; pub use pallet_assets; pub use pallet_message_queue; use sp_core::Get; @@ -34,7 +38,6 @@ use bp_messages::{ LaneId, MessageKey, OutboundLaneData, }; use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; -pub use cumulus_pallet_dmp_queue; pub use cumulus_pallet_parachain_system; pub use cumulus_pallet_xcmp_queue; pub use cumulus_primitives_core::{ @@ -54,7 +57,7 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm, Weight}, + prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm}, v3::Error, DoubleEncoded, }; @@ -489,8 +492,8 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: $crate::impls::Outcome::Complete(weight), .. + [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { + success: true, weight_used: weight, .. }) => { weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), @@ -505,36 +508,32 @@ macro_rules! impl_assert_events_helpers_for_parachain { /// Asserts a XCM from Relay Chain is incompletely executed pub fn assert_dmp_queue_incomplete( expected_weight: Option<$crate::impls::Weight>, - expected_error: Option<$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::Incomplete(weight, error), .. + [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { + success: false, weight_used: weight, .. }) => { weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight ), - error: *error == expected_error.unwrap_or(*error), }, ] ); } /// Asserts a XCM from Relay Chain is executed with error - pub fn assert_dmp_queue_error( - expected_error: $crate::impls::Error, - ) { + pub fn assert_dmp_queue_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), .. + [<$chain RuntimeEvent>]::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed { + .. }) => { - error: *error == expected_error, + }, ] ); @@ -545,8 +544,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::XcmpQueue( - $crate::impls::cumulus_pallet_xcmp_queue::Event::Success { weight, .. } + [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } ) => { weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 8a8081c9fac..2cb90650b94 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -29,13 +29,15 @@ pub use paste; // Substrate use frame_support::traits::OnInitialize; pub use pallet_balances; +pub use pallet_message_queue; // 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, + decl_test_sender_receiver_accounts_parameter_types, DefaultParaMessageProcessor, + DefaultRelayMessageProcessor, Parachain, TestExt, }; // Polkadot @@ -49,7 +51,7 @@ decl_test_relay_chains! { on_init = (), runtime = westend_runtime, core = { - MessageProcessor: DefaultMessageProcessor, + MessageProcessor: DefaultRelayMessageProcessor, SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, }, pallets = { @@ -66,7 +68,7 @@ decl_test_relay_chains! { on_init = (), runtime = rococo_runtime, core = { - MessageProcessor: DefaultMessageProcessor, + MessageProcessor: DefaultRelayMessageProcessor, SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, }, pallets = { @@ -82,7 +84,7 @@ decl_test_relay_chains! { on_init = (), runtime = rococo_runtime, core = { - MessageProcessor: DefaultMessageProcessor, + MessageProcessor: DefaultRelayMessageProcessor, SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, }, pallets = { @@ -103,9 +105,9 @@ decl_test_parachains! { 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, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm, @@ -124,9 +126,9 @@ decl_test_parachains! { runtime = penpal_runtime, core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, ParachainInfo: penpal_runtime::ParachainInfo, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, @@ -143,9 +145,9 @@ decl_test_parachains! { 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, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, @@ -161,9 +163,9 @@ decl_test_parachains! { runtime = asset_hub_rococo_runtime, core = { 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, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: asset_hub_rococo_runtime::PolkadotXcm, @@ -182,9 +184,9 @@ decl_test_parachains! { runtime = penpal_runtime, core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, ParachainInfo: penpal_runtime::ParachainInfo, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, @@ -199,9 +201,9 @@ decl_test_parachains! { runtime = penpal_runtime, core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, ParachainInfo: penpal_runtime::ParachainInfo, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, @@ -218,9 +220,9 @@ decl_test_parachains! { 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, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, @@ -235,9 +237,9 @@ decl_test_parachains! { runtime = asset_hub_rococo_runtime, core = { 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, + MessageProcessor: DefaultParaMessageProcessor, }, pallets = { PolkadotXcm: asset_hub_rococo_runtime::PolkadotXcm, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index a65b2057afd..6efe7f1731e 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -77,8 +77,8 @@ macro_rules! test_parachain_is_trusted_teleporter { RuntimeEvent::Balances( $crate::pallet_balances::Event::Deposit { who: receiver, .. } ) => {}, - RuntimeEvent::XcmpQueue( - $crate::cumulus_pallet_xcmp_queue::Event::Success { .. } + RuntimeEvent::MessageQueue( + $crate::pallet_message_queue::Event::Processed { success: true, .. } ) => {}, ] ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index bde9cce7531..f71499e0c29 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -68,6 +68,8 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -98,9 +100,11 @@ default = [ "std" ] state-trie-version-1 = [ "pallet-state-trie-migration" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -110,6 +114,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", @@ -144,6 +149,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-nft-fractionalization/try-runtime", "pallet-nfts/try-runtime", @@ -185,6 +191,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-nft-fractionalization/std", "pallet-nfts-runtime-api/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 bc17fcada23..52ad3241e51 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -34,7 +34,6 @@ use assets_common::{ AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -42,7 +41,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Permill, + ApplyExtrinsicResult, Perbill, Permill, }; use sp_std::prelude::*; @@ -51,6 +50,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -58,7 +58,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - InstanceFilter, + InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -73,6 +73,7 @@ pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, kusama::{consensus::*, currency::*, fee::WeightToFee}, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, @@ -81,7 +82,7 @@ use sp_runtime::RuntimeDebug; use xcm::opaque::v3::MultiLocation; use xcm_config::{ FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, KsmLocation, - PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, XcmConfig, + PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, }; #[cfg(any(feature = "std", test))] @@ -90,8 +91,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; +use xcm::latest::BodyId; use crate::xcm_config::{ ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, @@ -610,10 +610,11 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -629,6 +630,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -638,10 +665,11 @@ parameter_types! { impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, @@ -651,10 +679,14 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type PriceForSiblingDelivery = NoPriceForMessageDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } parameter_types! { @@ -848,7 +880,9 @@ construct_runtime!( 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, + // Temporary to migrate the remaining DMP messages: DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -905,19 +939,16 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_nft_fractionalization, NftFractionalization] [pallet_nfts, Nfts] @@ -927,7 +958,9 @@ mod benches { [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -1225,7 +1258,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..f787aa32701 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemint-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemint/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_660_000 picoseconds. + Weight::from_parts(1_720_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 28_418 + .saturating_add(Weight::from_parts(24_636_963, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs index 9c7a56687b3..e394e8b837a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=asset-hub-kusama-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-kusama/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// asset-hub-kusama-dev +// --output +// cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_467_000 picoseconds. - Weight::from_parts(5_634_000, 0) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3517` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_409_000 picoseconds. - Weight::from_parts(5_570_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65747` + // Estimated: `69212` + // Minimum execution time: 62_000_000 picoseconds. + Weight::from_parts(66_000_000, 0) + .saturating_add(Weight::from_parts(0, 69212)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs index 96477ddf4bd..6304051e6cb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs index 281c013b337..f04081a84fb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs @@ -1,20 +1,21 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -24,6 +25,7 @@ pub mod pallet_assets_local; pub mod pallet_assets_pool; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_nft_fractionalization; pub mod pallet_nfts; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs index 702f3743a72..3fcf2f8f4ec 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_asset_conversion` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs index 7c237b20389..c2688d97905 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs index 10bd4b1f8b0..957e33fcd9e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs index 444699e33ef..e0b4ff36552 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs index be1ac3011f7..79c88f30580 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs index 7fe56ac31f7..5c5a31eb348 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..792b7d18b67 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemint-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemint/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 18_976_000 picoseconds. + Weight::from_parts(18_976_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 12_686_000 picoseconds. + Weight::from_parts(12_686_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_951_000 picoseconds. + Weight::from_parts(4_951_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_023_000 picoseconds. + Weight::from_parts(6_023_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_901_000 picoseconds. + Weight::from_parts(6_901_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_503_000 picoseconds. + Weight::from_parts(58_503_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 9_318_000 picoseconds. + Weight::from_parts(9_318_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 52_228_000 picoseconds. + Weight::from_parts(52_228_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 59_617_000 picoseconds. + Weight::from_parts(59_617_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 69_681_000 picoseconds. + Weight::from_parts(69_681_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs index ee7b7073641..d2e0f0ec7f0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs index c55a18adc52..4becc569514 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_nft_fractionalization` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs index 2de706bbdc7..7a51830799a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_nfts` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs index 9bc4ba448e5..0cdffc653bc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_proxy` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs index 56982f565ac..73c3c06945d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs index 94914eefba0..e27289a49e9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs index 43bc74931cb..69d3e773afb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_uniques` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs index 680e65a2dcf..e6c3e1295ef 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs index c2ed67d2f5d..becfca7a891 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 ce6e9206515..405d7c72e55 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 9b8611fd663..e680c2d5c11 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 625549ecfcc..9e8f3bfe75c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 3628641544b..d63c126f082 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 @@ -272,7 +272,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::Assets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index 4c3651eb8cf..b5eff6b63af 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -63,6 +63,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -86,9 +87,11 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", default = [ "std" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -99,6 +102,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", @@ -130,6 +134,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-nfts/try-runtime", "pallet-proxy/try-runtime", @@ -168,6 +173,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-nfts-runtime-api/std", "pallet-nfts/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 7033e1c2dca..57a1150bc88 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -66,7 +66,7 @@ use assets_common::{ foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -74,7 +74,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, + ApplyExtrinsicResult, Perbill, }; use sp_std::prelude::*; @@ -90,7 +90,7 @@ use frame_support::{ parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - InstanceFilter, + InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, PalletId, @@ -103,6 +103,7 @@ use pallet_nfts::PalletFeatures; pub use parachains_common as common; use parachains_common::{ impls::{AssetsToBlockAuthor, DealWithFees}, + message_queue::*, polkadot::{consensus::*, currency::*, fee::WeightToFee}, AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, @@ -111,7 +112,7 @@ use parachains_common::{ use sp_runtime::RuntimeDebug; use xcm_config::{ DotLocation, FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, - TrustBackedAssetsConvertedConcreteId, XcmConfig, XcmOriginToTransactDispatchOrigin, + TrustBackedAssetsConvertedConcreteId, XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -120,8 +121,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; +use xcm::latest::BodyId; use crate::xcm_config::ForeignCreatorsSovereignAccountOf; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -546,10 +546,11 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -563,6 +564,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { >; } +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -575,10 +602,11 @@ parameter_types! { impl cumulus_pallet_xcmp_queue::Config for Runtime { type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, @@ -587,10 +615,14 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type PriceForSiblingDelivery = NoPriceForMessageDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } parameter_types! { @@ -763,6 +795,7 @@ construct_runtime!( 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, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -800,7 +833,10 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -pub type Migrations = (pallet_collator_selection::migration::v1::MigrateToV1,); +pub type Migrations = ( + // unreleased + pallet_collator_selection::migration::v1::MigrateToV1, +); /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -812,17 +848,14 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_nfts, Nfts] [pallet_proxy, Proxy] @@ -831,7 +864,9 @@ mod benches { [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -1104,7 +1139,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..970534560c6 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// westmint-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/westmint/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_638_000 picoseconds. + Weight::from_parts(1_690_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 22_873 + .saturating_add(Weight::from_parts(24_208_496, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 65844ce194a..89c80d0be62 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=asset-hub-polkadot-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-polkadot/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// asset-hub-polkadot-dev +// --output +// cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_240_000 picoseconds. - Weight::from_parts(5_487_000, 0) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_243_000 picoseconds. - Weight::from_parts(5_549_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(46_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 62_000_000 picoseconds. + Weight::from_parts(68_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs index 713c33d34f7..0b988fd0f6f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs index 3eb3b925e65..0823dcad88e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs @@ -1,20 +1,21 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -22,6 +23,7 @@ pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_nfts; pub mod pallet_proxy; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs index 51413bb471b..adb686c0afc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs index c8420e72ba2..810f5b57c45 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs index a7f02ba24fd..7c4501e6d88 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs index 53efb218440..c33e79970ff 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..a9f0cb07cfe --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// westmint-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/westmint/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 12_192_000 picoseconds. + Weight::from_parts(12_192_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 10_447_000 picoseconds. + Weight::from_parts(10_447_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_851_000 picoseconds. + Weight::from_parts(4_851_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_342_000 picoseconds. + Weight::from_parts(6_342_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_199_000 picoseconds. + Weight::from_parts(6_199_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_612_000 picoseconds. + Weight::from_parts(58_612_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 7_296_000 picoseconds. + Weight::from_parts(7_296_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 48_345_000 picoseconds. + Weight::from_parts(48_345_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 56_441_000 picoseconds. + Weight::from_parts(56_441_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 70_858_000 picoseconds. + Weight::from_parts(70_858_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs index 705aca9e1a4..0bb05511d7a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs index 6d6f7cbbafb..842daf49f59 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_nfts` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs index 99db2865692..b6121f2fca2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_proxy` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs index 8a6943d5304..560322abeb3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs index 8c6a2b5505e..17b050c3e90 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs index a88928be653..5b13d56f5bb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_uniques` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs index c6fc093cc4b..d028fb898a4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs index bd7615895e2..0d3fe0adb1b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 eb140c4bf32..44fcb91d688 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 96d86ec423f..1036d4cbf00 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 061992691a6..12ef504727e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 91663a75970..6035789a1ae 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 @@ -231,7 +231,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::Assets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 766cadb93b0..764d0eb989f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -27,6 +27,7 @@ pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-convers 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-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 24c511e1a68..2c6c85619c9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -40,6 +40,7 @@ use assets_common::{ AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::AggregateMessageOrigin; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -55,13 +56,14 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; +use cumulus_primitives_core::ParaId; use frame_support::{ construct_runtime, dispatch::DispatchClass, ord_parameter_types, parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - Equals, InstanceFilter, + Equals, InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -75,16 +77,18 @@ use pallet_nfts::PalletFeatures; pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, 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 sp_runtime::{Perbill, RuntimeDebug}; use xcm::opaque::v3::MultiLocation; use xcm_config::{ ForeignAssetsConvertedConcreteId, GovernanceLocation, PoolAssetsConvertedConcreteId, - TokenLocation, TrustBackedAssetsConvertedConcreteId, XcmConfig, + TokenLocation, TrustBackedAssetsConvertedConcreteId, }; #[cfg(any(feature = "std", test))] @@ -94,7 +98,6 @@ pub use sp_runtime::BuildStorage; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; use crate::xcm_config::{ ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, @@ -616,10 +619,11 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -633,6 +637,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { >; } +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -652,21 +682,25 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: >; impl cumulus_pallet_xcmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } parameter_types! { @@ -953,6 +987,7 @@ construct_runtime!( 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, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -1388,7 +1423,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..c1e5c6a7429 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemine-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemine/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_622_000 picoseconds. + Weight::from_parts(1_709_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 22_138 + .saturating_add(Weight::from_parts(23_923_169, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} 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 index 26ce4c8c9c5..70fc3617bce 100644 --- 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 @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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 +//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/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/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// bridge-hub-rococo-dev +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_467_000 picoseconds. - Weight::from_parts(5_634_000, 0) + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_409_000 picoseconds. - Weight::from_parts(5_570_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 67_000_000 picoseconds. + Weight::from_parts(73_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(55_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index 4997e589c3c..0fc36d74ff0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -15,6 +15,8 @@ // along with Cumulus. If not, see . pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -24,6 +26,7 @@ pub mod pallet_assets_local; pub mod pallet_assets_pool; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_nft_fractionalization; pub mod pallet_nfts; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..45531ccfa79 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemine-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemine/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 13_668_000 picoseconds. + Weight::from_parts(13_668_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 11_106_000 picoseconds. + Weight::from_parts(11_106_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_921_000 picoseconds. + Weight::from_parts(4_921_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_879_000 picoseconds. + Weight::from_parts(6_879_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 7_564_000 picoseconds. + Weight::from_parts(7_564_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 59_963_000 picoseconds. + Weight::from_parts(59_963_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 7_200_000 picoseconds. + Weight::from_parts(7_200_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 41_366_000 picoseconds. + Weight::from_parts(41_366_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 60_538_000 picoseconds. + Weight::from_parts(60_538_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 73_665_000 picoseconds. + Weight::from_parts(73_665_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 367c18966e4..a17d0a6cf0c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -309,7 +309,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::Assets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 1a7f019d4f9..dbcb0be3cb7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -67,6 +67,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -96,9 +97,11 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", default = [ "std" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -109,6 +112,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", @@ -143,6 +147,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-nft-fractionalization/try-runtime", "pallet-nfts/try-runtime", @@ -187,6 +192,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-nft-fractionalization/std", "pallet-nfts-runtime-api/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 737b8625881..f1a15265b90 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -36,6 +36,7 @@ use assets_common::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -43,7 +44,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, - ConstU64, ConstU8, Equals, InstanceFilter, + ConstU64, ConstU8, Equals, InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -58,6 +59,7 @@ use pallet_xcm::EnsureXcm; pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, + message_queue::*, westend::{consensus::*, currency::*, fee::WeightToFee}, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, @@ -69,7 +71,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Permill, RuntimeDebug, + ApplyExtrinsicResult, Perbill, Permill, RuntimeDebug, }; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -78,8 +80,7 @@ use sp_version::RuntimeVersion; use xcm::opaque::v3::MultiLocation; use xcm_config::{ ForeignAssetsConvertedConcreteId, PoolAssetsConvertedConcreteId, - TrustBackedAssetsConvertedConcreteId, WestendLocation, XcmConfig, - XcmOriginToTransactDispatchOrigin, + TrustBackedAssetsConvertedConcreteId, WestendLocation, XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -90,7 +91,6 @@ use assets_common::{ }; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; use crate::xcm_config::ForeignCreatorsSovereignAccountOf; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -586,10 +586,11 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -605,6 +606,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -623,20 +650,25 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } parameter_types! { @@ -859,6 +891,7 @@ construct_runtime!( DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, // Bridge utilities. ToRococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 34, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 35, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -957,19 +990,16 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_nft_fractionalization, NftFractionalization] [pallet_nfts, Nfts] @@ -980,6 +1010,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] // XCM [pallet_xcm, PolkadotXcm] @@ -1346,7 +1377,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..c1e5c6a7429 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemine-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemine/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_622_000 picoseconds. + Weight::from_parts(1_709_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 22_138 + .saturating_add(Weight::from_parts(23_923_169, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs index cda66f6ea7e..b34c959a355 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=asset-hub-westend-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-westend/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// asset-hub-westend-dev +// --output +// cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_109_000 picoseconds. - Weight::from_parts(5_324_000, 0) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3517` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_183_000 picoseconds. - Weight::from_parts(5_408_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65747` + // Estimated: `69212` + // Minimum execution time: 66_000_000 picoseconds. + Weight::from_parts(68_000_000, 0) + .saturating_add(Weight::from_parts(0, 69212)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs index c70ea9d58b2..6c741af2a13 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index a857dc62062..1646c00989d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -1,20 +1,21 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -24,6 +25,7 @@ pub mod pallet_assets_local; pub mod pallet_assets_pool; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_nft_fractionalization; pub mod pallet_nfts; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs index 2f39df65403..e48f2e2ef72 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_asset_conversion` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs index 5be1319b10d..52ba2fd6c40 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs index aa09be829c8..e78366b91cb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs index bfe73e1cfaf..65cae81069c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_assets` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs index f6bf09d63ba..c98ac75ff66 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs index 2473c58e458..095e784cf66 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..45531ccfa79 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemine-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemine/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 13_668_000 picoseconds. + Weight::from_parts(13_668_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 11_106_000 picoseconds. + Weight::from_parts(11_106_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_921_000 picoseconds. + Weight::from_parts(4_921_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_879_000 picoseconds. + Weight::from_parts(6_879_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 7_564_000 picoseconds. + Weight::from_parts(7_564_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 59_963_000 picoseconds. + Weight::from_parts(59_963_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 7_200_000 picoseconds. + Weight::from_parts(7_200_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 41_366_000 picoseconds. + Weight::from_parts(41_366_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 60_538_000 picoseconds. + Weight::from_parts(60_538_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 73_665_000 picoseconds. + Weight::from_parts(73_665_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs index 107d78c98f9..27687e10751 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs index e155e1bada3..601b47227c5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nft_fractionalization.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_nft_fractionalization` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs index 687dfa07f75..fa7085c7344 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_nfts.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_nfts` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs index 657bd2764cf..d0042419719 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_proxy.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_proxy` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs index 92602191744..2f9a39d2f80 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs index 13f18861d37..85207bc7c7e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs index 53bead08f5d..8c20f160154 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_uniques.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_uniques` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs index 7db443ebbf1..a7952d6da00 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 1cc4c2d0e24..5c97d358591 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 b321f396ea1..bcd51167f97 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 89b0d97e7c1..eaf07aac52c 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 3b19e61fa21..fc196abea0f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 a44c4524656..526c8eb4af4 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 @@ -288,7 +288,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::Assets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index a7f2b86a6c8..49fc2a0fa5e 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -54,6 +54,7 @@ std = [ ] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", "frame-support/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 0bcbe79691c..1dc7cecbb62 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -24,7 +24,6 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features # Cumulus cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -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 } assets-common = { path = "../common", default-features = false } @@ -55,7 +54,6 @@ default = [ "std" ] std = [ "assets-common/std", "codec/std", - "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-core/std", 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 8572c9ba3d0..2cd002b1c60 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -61,6 +61,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -99,6 +100,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -135,9 +137,11 @@ std = [ ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -145,6 +149,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -172,6 +177,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", 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 9fdf8380bc3..bd95ec3fda7 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 @@ -26,7 +26,6 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -42,12 +41,15 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, + }, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -58,9 +60,7 @@ use frame_system::{ use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{ - FellowshipLocation, GovernanceLocation, XcmConfig, XcmOriginToTransactDispatchOrigin, -}; +use xcm_config::{FellowshipLocation, GovernanceLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -72,13 +72,13 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use parachains_common::{ impls::DealWithFees, kusama::{consensus::*, currency::*, fee::WeightToFee}, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; // XCM Imports -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; +use xcm::latest::prelude::BodyId; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -109,7 +109,10 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -pub type Migrations = (pallet_collator_selection::migration::v1::MigrateToV1,); +pub type Migrations = ( + // unreleased + pallet_collator_selection::migration::v1::MigrateToV1, +); /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -276,11 +279,12 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -295,6 +299,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -310,20 +340,25 @@ pub type RootOrFellows = EitherOfDiverse< impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = NoPriceForMessageDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } pub const PERIOD: u32 = 6 * HOURS; @@ -433,6 +468,7 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -440,21 +476,19 @@ construct_runtime!( } ); -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -685,7 +719,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..a30a2ae8d4d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-kusama-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(1_761_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 28_250 + .saturating_add(Weight::from_parts(24_261_433, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs index 991cba573bf..ffd311ceecd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-kusama-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-kusama/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// bridge-hub-kusama-dev +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_129_000 picoseconds. - Weight::from_parts(5_367_000, 0) + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_050_000 picoseconds. - Weight::from_parts(5_565_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 60_000_000 picoseconds. + Weight::from_parts(63_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs index 5a0a60cc995..6b9313cdaba 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs index e226021e77a..36733d6d4a6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs @@ -18,11 +18,14 @@ //! Expose the auto generated weight files. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs index 51ca2e660b3..04ceb5bed75 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs index fa0ac199ca2..cccb7c60924 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..c5a4235055d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-kusama-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 11_692_000 picoseconds. + Weight::from_parts(11_692_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 10_614_000 picoseconds. + Weight::from_parts(10_614_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 7_085_000 picoseconds. + Weight::from_parts(7_085_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_813_000 picoseconds. + Weight::from_parts(5_813_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_090_000 picoseconds. + Weight::from_parts(6_090_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_905_000 picoseconds. + Weight::from_parts(58_905_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 6_501_000 picoseconds. + Weight::from_parts(6_501_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 39_695_000 picoseconds. + Weight::from_parts(39_695_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 50_543_000 picoseconds. + Weight::from_parts(50_543_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 69_294_000 picoseconds. + Weight::from_parts(69_294_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs index 96b2d859ed8..f4135e975fb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs index cc1b4aeb0dd..f508e1daaef 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs index 32f6e4a6b43..6162b1d48c5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs index 15b06676cd3..93d0ea596e7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs index 71bc5830771..730bc492684 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 ded5dc6702e..71732961d3d 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 17ee5cb6a8d..ff3cb452a8a 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index b1e8107b30b..c5c14e6917e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 85b983a6ab9..727735c9285 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 @@ -149,7 +149,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) + RuntimeCall::MessageQueue(..) ) } } 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 b9b0f50006e..3847a352e07 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -28,6 +28,7 @@ frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", defau 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-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} @@ -99,6 +100,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -135,9 +137,11 @@ std = [ ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -145,6 +149,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -172,6 +177,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", 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 6ce1df99295..4744dc08e8e 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 @@ -26,7 +26,6 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -42,12 +41,15 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, + }, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -58,9 +60,7 @@ use frame_system::{ use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{ - FellowshipLocation, GovernanceLocation, XcmConfig, XcmOriginToTransactDispatchOrigin, -}; +use xcm_config::{FellowshipLocation, GovernanceLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -72,13 +72,13 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use parachains_common::{ impls::DealWithFees, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, polkadot::{consensus::*, currency::*, fee::WeightToFee}, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; // XCM Imports -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; +use xcm::latest::prelude::BodyId; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -109,7 +109,10 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -pub type Migrations = (pallet_collator_selection::migration::v1::MigrateToV1,); +pub type Migrations = ( + // unreleased + pallet_collator_selection::migration::v1::MigrateToV1, +); /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -276,11 +279,12 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -293,6 +297,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { >; } +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -310,20 +340,25 @@ pub type RootOrFellows = EitherOfDiverse< impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = NoPriceForMessageDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } pub const PERIOD: u32 = 6 * HOURS; @@ -433,6 +468,7 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -440,21 +476,20 @@ construct_runtime!( } ); -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -685,7 +720,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..4b0cface146 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-polkadot-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(1_729_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 19_565 + .saturating_add(Weight::from_parts(24_482_828, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 98834cc44e8..ac6ad093faf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-polkadot/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// bridge-hub-polkadot-dev +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_043_000 picoseconds. - Weight::from_parts(5_211_000, 0) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_011_000 picoseconds. - Weight::from_parts(5_171_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 61_000_000 picoseconds. + Weight::from_parts(64_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(44_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs index 4aeb4660d87..8676be67b2f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs index e226021e77a..36733d6d4a6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs @@ -18,11 +18,14 @@ //! Expose the auto generated weight files. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_balances; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs index 5abe64bb411..b95ea83585f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs index e0f4156fe4d..6ed2c429186 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..38cc21cfad9 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-polkadot-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-polkadot/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 38_974_000 picoseconds. + Weight::from_parts(38_974_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 11_194_000 picoseconds. + Weight::from_parts(11_194_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 5_196_000 picoseconds. + Weight::from_parts(5_196_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_408_000 picoseconds. + Weight::from_parts(6_408_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_354_000 picoseconds. + Weight::from_parts(6_354_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 63_855_000 picoseconds. + Weight::from_parts(63_855_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 6_764_000 picoseconds. + Weight::from_parts(6_764_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 40_293_000 picoseconds. + Weight::from_parts(40_293_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 50_903_000 picoseconds. + Weight::from_parts(50_903_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 96_657_000 picoseconds. + Weight::from_parts(96_657_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs index 4625c4f474e..44f3da351f6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs index 29bc576ebc8..86ecc787e97 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs index 8252834cc11..a0984d72aac 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs index 5205e9fff85..2f04094b347 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs index ffc5fa2fc23..98dd7e36f07 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 7e9f2184272..33a48f36812 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 f45f3936365..814c416bd4c 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 7968649d143..9a039a6d63b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 7378961f576..ac7e00fc427 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 @@ -152,7 +152,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) + RuntimeCall::MessageQueue(..) ) } } 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 339544da901..76ff63db4da 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -62,6 +62,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -145,6 +146,7 @@ std = [ "pallet-bridge-parachains/std", "pallet-bridge-relayers/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -183,9 +185,11 @@ std = [ runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -197,6 +201,7 @@ runtime-benchmarks = [ "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -228,6 +233,7 @@ try-runtime = [ "pallet-bridge-parachains/try-runtime", "pallet-bridge-relayers/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", 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 0743b6e91f9..b533f7adc2a 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 @@ -57,12 +57,13 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, Everything}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, Everything, TransformOrigin}, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -70,9 +71,10 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; +use xcm_config::{XcmOriginToTransactDispatchOrigin, XcmRouter}; use bp_runtime::HeaderId; @@ -90,7 +92,6 @@ use parachains_common::{ AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; -use xcm_executor::XcmExecutor; /// Enum for handling differences in the runtime configuration for BridgeHubRococo vs /// BridgeHubWococo. @@ -337,11 +338,12 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -356,6 +358,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -374,20 +402,25 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } pub const PERIOD: u32 = 6 * HOURS; @@ -491,6 +524,7 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -543,21 +577,20 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { BridgeRococoMessages, BridgeWococoMessages, BridgeWestendMessages } -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PolkadotXcm] // NOTE: Make sure you point to the individual modules below. @@ -958,7 +991,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..dc480c39163 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-rococo-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_645_000 picoseconds. + Weight::from_parts(1_717_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 12_258 + .saturating_add(Weight::from_parts(24_890_934, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 0106d6398f4..70fc3617bce 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=bridge-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/bridge-hubs/bridge-hub-rococo/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// bridge-hub-rococo-dev +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 4_930_000 picoseconds. - Weight::from_parts(5_292_000, 0) + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_012_000 picoseconds. - Weight::from_parts(5_282_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 67_000_000 picoseconds. + Weight::from_parts(73_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(55_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs index 3dec4cc7f18..b0f7806be8e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index a657b588c02..66f8f1edf3c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -18,6 +18,8 @@ //! Expose the auto generated weight files. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -33,6 +35,7 @@ pub mod pallet_bridge_parachains_within_westend; pub mod pallet_bridge_parachains_within_wococo; pub mod pallet_bridge_relayers; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs index 26a188a9861..ba8551a5ebb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs new file mode 100644 index 00000000000..8ef05f17856 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_bridge_grandpa` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./artifacts/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet_bridge_grandpa +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_bridge_grandpa`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_grandpa::WeightInfo for WeightInfo { + /// Storage: BridgeRococoGrandpa PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: BridgeRococoGrandpa BestFinalized (r:1 w:1) + /// Proof: BridgeRococoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) + /// Storage: BridgeRococoGrandpa CurrentAuthoritySet (r:1 w:0) + /// Proof: BridgeRococoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(50250), added: 50745, mode: MaxEncodedLen) + /// Storage: BridgeRococoGrandpa ImportedHashesPointer (r:1 w:1) + /// Proof: BridgeRococoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: BridgeRococoGrandpa ImportedHashes (r:1 w:1) + /// Proof: BridgeRococoGrandpa ImportedHashes (max_values: Some(1024), max_size: Some(36), added: 1521, mode: MaxEncodedLen) + /// Storage: BridgeRococoGrandpa ImportedHeaders (r:0 w:2) + /// Proof: BridgeRococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + /// The range of component `p` is `[1, 838]`. + /// The range of component `v` is `[50, 100]`. + fn submit_finality_proof(p: u32, v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `231 + p * (60 ±0)` + // Estimated: `51735` + // Minimum execution time: 241_332_000 picoseconds. + Weight::from_parts(69_790_821, 0) + .saturating_add(Weight::from_parts(0, 51735)) + // Standard Error: 6_013 + .saturating_add(Weight::from_parts(47_580_554, 0).saturating_mul(p.into())) + // Standard Error: 100_298 + .saturating_add(Weight::from_parts(1_213_475, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs index b0634ff2ccf..0bb798bd9ec 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_grandpa` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs index 05474ed224d..a82854e0c67 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_grandpa` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs new file mode 100644 index 00000000000..319a4de8e96 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs @@ -0,0 +1,230 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_bridge_messages` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./artifacts/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet_bridge_messages +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_bridge_messages`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_messages::WeightInfo for WeightInfo { + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn receive_single_message_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `52645` + // Minimum execution time: 43_187_000 picoseconds. + Weight::from_parts(43_681_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn receive_two_messages_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `52645` + // Minimum execution time: 54_131_000 picoseconds. + Weight::from_parts(54_813_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `52645` + // Minimum execution time: 48_120_000 picoseconds. + Weight::from_parts(48_733_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + fn receive_single_message_proof_1_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `335` + // Estimated: `52645` + // Minimum execution time: 41_028_000 picoseconds. + Weight::from_parts(41_635_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + fn receive_single_message_proof_16_kb() -> Weight { + // Proof Size summary in bytes: + // Measured: `335` + // Estimated: `52645` + // Minimum execution time: 68_499_000 picoseconds. + Weight::from_parts(69_263_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) + /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + fn receive_delivery_proof_for_single_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `3804` + // Minimum execution time: 32_277_000 picoseconds. + Weight::from_parts(32_880_000, 0) + .saturating_add(Weight::from_parts(0, 3804)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) + /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `3804` + // Minimum execution time: 32_504_000 picoseconds. + Weight::from_parts(33_085_000, 0) + .saturating_add(Weight::from_parts(0, 3804)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) + /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `6086` + // Minimum execution time: 34_963_000 picoseconds. + Weight::from_parts(35_473_000, 0) + .saturating_add(Weight::from_parts(0, 6086)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) + /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) + /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) + /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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 Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) + /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem RelevantMessagingState (r:1 w:0) + /// Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[128, 2048]`. + /// The range of component `i` is `[128, 2048]`. + fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `635` + // Estimated: `52645` + // Minimum execution time: 129_978_000 picoseconds. + Weight::from_parts(98_246_356, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 2_554 + .saturating_add(Weight::from_parts(544_728, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs index f4f5e85f562..e2f58cdfad5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_messages` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs index 596b8dd3cc6..d9c0fd15468 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_messages` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs new file mode 100644 index 00000000000..bd7384a05fe --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -0,0 +1,112 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_bridge_parachains` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./artifacts/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet_bridge_parachains +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_bridge_parachains`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_parachains::WeightInfo for WeightInfo { + /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) + /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) + /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) + /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) + /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) + /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 2]`. + /// The range of component `p` is `[1, 2]`. + fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 34_759_000 picoseconds. + Weight::from_parts(35_709_034, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) + /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) + /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) + /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) + /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) + /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + fn submit_parachain_heads_with_1kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 36_005_000 picoseconds. + Weight::from_parts(36_492_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) + /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) + /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) + /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) + /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) + /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) + /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + fn submit_parachain_heads_with_16kb_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `367` + // Estimated: `2543` + // Minimum execution time: 62_374_000 picoseconds. + Weight::from_parts(62_977_000, 0) + .saturating_add(Weight::from_parts(0, 2543)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs index 81cb0a66b7d..e36bbcca42e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_parachains` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs index 416e16c78c4..d685daf930f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_parachains` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index fde670ab927..48f0c1f949b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_bridge_relayers` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs index 9cbfa6ce80e..1fb0b765c06 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..2fcd573ceb2 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-rococo-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 11_446_000 picoseconds. + Weight::from_parts(11_446_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 10_613_000 picoseconds. + Weight::from_parts(10_613_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_854_000 picoseconds. + Weight::from_parts(4_854_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_748_000 picoseconds. + Weight::from_parts(5_748_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_136_000 picoseconds. + Weight::from_parts(6_136_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 59_505_000 picoseconds. + Weight::from_parts(59_505_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 6_506_000 picoseconds. + Weight::from_parts(6_506_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 40_646_000 picoseconds. + Weight::from_parts(40_646_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 51_424_000 picoseconds. + Weight::from_parts(51_424_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 81_153_000 picoseconds. + Weight::from_parts(81_153_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs index 91840ae0c6d..832380d3876 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs index c9d04f9c6df..06b2f3bcd27 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs index 0a5bf9b9f9c..1c54e9519b3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs index 44cd0cf91e7..d96b9e88840 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 72bdb282585..a6e093c4b94 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 78a0eed9174..1c2334a89e2 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; 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 295abd481d7..cb7ad7a7803 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 7c686190208..4eee8f0e613 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! 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 87ae9a8e0fa..d98012e061b 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 @@ -198,7 +198,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< Runtime, BridgeGrandpaRococoInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 92250a84786..c4461a0d4c3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -29,6 +29,7 @@ pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false} pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 7d4cb03aa06..c0b0bf87180 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -33,6 +33,8 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -52,7 +54,7 @@ use frame_support::{ dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, Everything}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, Everything, TransformOrigin}, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -62,7 +64,7 @@ use frame_system::{ }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; +use xcm_config::{XcmOriginToTransactDispatchOrigin, XcmRouter}; use bp_runtime::HeaderId; @@ -80,7 +82,6 @@ use parachains_common::{ AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; -use xcm_executor::XcmExecutor; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -314,11 +315,12 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -333,6 +335,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -351,20 +379,24 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } pub const PERIOD: u32 = 6 * HOURS; @@ -468,12 +500,12 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, - // Bridging stuff. BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 41, BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 42, @@ -501,6 +533,7 @@ mod benches { define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] @@ -791,7 +824,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..dc480c39163 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-rococo-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_645_000 picoseconds. + Weight::from_parts(1_717_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 12_258 + .saturating_add(Weight::from_parts(24_890_934, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs index 0106d6398f4..70fc3617bce 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, 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: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./target/release/polkadot-parachain // benchmark // pallet -// --chain=bridge-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/bridge-hubs/bridge-hub-rococo/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// bridge-hub-rococo-dev +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 4_930_000 picoseconds. - Weight::from_parts(5_292_000, 0) + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_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) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_012_000 picoseconds. - Weight::from_parts(5_282_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_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::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `111` + // Estimated: `1596` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 1596)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65711` + // Estimated: `69176` + // Minimum execution time: 67_000_000 picoseconds. + Weight::from_parts(73_000_000, 0) + .saturating_add(Weight::from_parts(0, 69176)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65710` + // Estimated: `69175` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(55_000_000, 0) + .saturating_add(Weight::from_parts(0, 69175)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index 7003e3e9253..833944ebfa5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -21,6 +21,8 @@ use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -30,6 +32,7 @@ pub mod pallet_bridge_messages; pub mod pallet_bridge_parachains; pub mod pallet_bridge_relayers; pub mod pallet_collator_selection; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..2fcd573ceb2 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-rococo-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 11_446_000 picoseconds. + Weight::from_parts(11_446_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 10_613_000 picoseconds. + Weight::from_parts(10_613_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_854_000 picoseconds. + Weight::from_parts(4_854_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_748_000 picoseconds. + Weight::from_parts(5_748_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_136_000 picoseconds. + Weight::from_parts(6_136_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 59_505_000 picoseconds. + Weight::from_parts(59_505_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 6_506_000 picoseconds. + Weight::from_parts(6_506_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 40_646_000 picoseconds. + Weight::from_parts(40_646_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 51_424_000 picoseconds. + Weight::from_parts(51_424_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 81_153_000 picoseconds. + Weight::from_parts(81_153_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 8efc75ed13e..a6abca42215 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -169,7 +169,7 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< Runtime, crate::bridge_to_rococo_config::BridgeGrandpaRococoInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 40d7741fb38..18181ed3e05 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -26,7 +26,6 @@ pallet-session = { path = "../../../../../substrate/frame/session", default-feat # Cumulus asset-test-utils = { path = "../../assets/test-utils" } -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-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } @@ -72,7 +71,6 @@ std = [ "bp-test-utils/std", "bridge-runtime-common/std", "codec/std", - "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", "frame-benchmarking/std", 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 e77af189b4f..7281680416b 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 @@ -80,7 +80,6 @@ pub fn initialize_bridge_by_governance_works( + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config - + cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config + pallet_bridge_grandpa::Config, GrandpaPalletInstance: 'static, @@ -152,7 +151,6 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config - + cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config + pallet_bridge_messages::Config, XcmConfig: xcm_executor::Config, @@ -274,7 +272,6 @@ pub fn message_dispatch_routing_works< + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config - + cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config + cumulus_pallet_xcmp_queue::Config + pallet_bridge_messages::Config, @@ -390,7 +387,6 @@ pub fn relayed_incoming_message_works @@ -617,7 +613,6 @@ pub fn complex_relay_extrinsic_works diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index b5f22c828e7..ca83b84cd8f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -65,6 +65,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -86,9 +87,11 @@ sp-io = { path = "../../../../../substrate/primitives/io", default-features = fa [features] default = [ "std" ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -100,6 +103,7 @@ runtime-benchmarks = [ "pallet-collective-content/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-core-fellowship/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", @@ -135,6 +139,7 @@ try-runtime = [ "pallet-collective-content/try-runtime", "pallet-collective/try-runtime", "pallet-core-fellowship/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", @@ -177,6 +182,7 @@ std = [ "pallet-collective-content/std", "pallet-collective/std", "pallet-core-fellowship/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-preimage/std", "pallet-proxy/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index edfbfa851fe..b7bfc9f9c6a 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -45,7 +45,6 @@ pub mod fellowship; pub use ambassador::pallet_ambassador_origins; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use fellowship::{ migration::import_kusama_fellowship, pallet_fellowship_origins, Fellows, FellowshipCollectiveInstance, @@ -66,6 +65,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -73,7 +73,7 @@ use frame_support::{ parameter_types, traits::{ fungible::HoldConsideration, ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, - EitherOfDiverse, InstanceFilter, LinearStoragePrice, + EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, PalletId, @@ -85,13 +85,14 @@ use frame_system::{ pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, + message_queue::*, polkadot::{account::*, consensus::*, currency::*, fee::WeightToFee}, AccountId, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; use sp_runtime::RuntimeDebug; -use xcm_config::{GovernanceLocation, XcmConfig, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -99,8 +100,7 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; +use xcm::latest::{prelude::*, BodyId}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -382,10 +382,11 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -401,6 +402,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -419,10 +446,11 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EitherOfDiverse, Fellows>; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; @@ -430,10 +458,14 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } pub const PERIOD: u32 = 6 * HOURS; @@ -626,6 +658,7 @@ construct_runtime!( 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, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -701,22 +734,21 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_proxy, Proxy] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] [pallet_alliance, Alliance] [pallet_collective, AllianceMotion] [pallet_xcm, PolkadotXcm] diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..0b7a2fc21cd --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// collectives-polkadot-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/collectives/collectives-polkadot/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `48` + // Estimated: `8121` + // Minimum execution time: 1_988_000 picoseconds. + Weight::from_parts(2_039_000, 0) + .saturating_add(Weight::from_parts(0, 8121)) + // Standard Error: 30_660 + .saturating_add(Weight::from_parts(24_419_204, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index ccd9478bf10..e68c075bffc 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,43 +1,38 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! 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: `[]` +//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `Olivers-MacBook-Pro.local`, 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=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/collectives/collectives-polkadot/src/weights/ +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// collectives-polkadot-dev +// --output +// cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,22 +51,98 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 5_136_000 picoseconds. - Weight::from_parts(5_399_000, 0) + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) .saturating_add(Weight::from_parts(0, 1627)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_weight() -> Weight { + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `148` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 5_056_000 picoseconds. - Weight::from_parts(5_301_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 0) .saturating_add(Weight::from_parts(0, 1627)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `177` + // Estimated: `1662` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1662)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65777` + // Estimated: `69242` + // Minimum execution time: 60_000_000 picoseconds. + Weight::from_parts(63_000_000, 0) + .saturating_add(Weight::from_parts(0, 69242)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65776` + // Estimated: `69241` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 69241)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs index 31cd502d192..b6f1dc8dc08 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! 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 b5a3a892f79..1d877fdbd2b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs @@ -1,20 +1,21 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. pub mod block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; @@ -25,6 +26,7 @@ pub mod pallet_collective; pub mod pallet_collective_content; pub mod pallet_core_fellowship_ambassador_core; pub mod pallet_core_fellowship_fellowship_core; +pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_preimage; pub mod pallet_proxy; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs index 9e3acac46a4..d8ede609a67 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_alliance` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs index dd0c02ab873..6c1cf072257 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_balances` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs index ea237d602a9..2c729e8dc10 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collator_selection` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs index 2d344ad0db7..9133baa6120 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collective` //! 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 index e66907b9453..6be94db22db 100644 --- 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 @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_collective_content` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs index 434986b03bb..471ee82ead7 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_core_fellowship` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..4bd71c4e7d4 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// collectives-polkadot-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/collectives/collectives-polkadot/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 11_440_000 picoseconds. + Weight::from_parts(11_440_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 11_077_000 picoseconds. + Weight::from_parts(11_077_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 3_977_000 picoseconds. + Weight::from_parts(3_977_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 4_831_000 picoseconds. + Weight::from_parts(4_831_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_192_000 picoseconds. + Weight::from_parts(5_192_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_750_000 picoseconds. + Weight::from_parts(58_750_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 5_107_000 picoseconds. + Weight::from_parts(5_107_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 46_814_000 picoseconds. + Weight::from_parts(46_814_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 52_510_000 picoseconds. + Weight::from_parts(52_510_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 71_930_000 picoseconds. + Weight::from_parts(71_930_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs index a8dd58320cc..a7827b72009 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_multisig` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs index e9f565d9387..9b45c875818 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_preimage` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs index faf100d23bb..59d9f912bf1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_proxy` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs index 7515aecbb52..9c773c56ac3 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_ranked_collective` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs index 5b4aed06899..63f68833795 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_referenda` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs index 9bb7e68d314..37680b4e5df 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_salary` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs index d30ac82bf05..cf5610df665 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_scheduler` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs index 2af8ce29a19..2ac0804df89 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_session` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs index bc149ec63a1..ca06f43f92e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_timestamp` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs index 5d6b0cb8285..c60a79d91da 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_utility` //! diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs index 738742b6108..26e668854f2 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_xcm` //! 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 c64d688e5f1..c0b3108d2fb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -174,7 +174,7 @@ impl Contains for SafeCallFilter { ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::DmpQueue(..) | + RuntimeCall::MessageQueue(..) | RuntimeCall::Alliance( // `init_members` accepts unbounded vecs as arguments, // but the call can be initiated only by root origin. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 1ee069d5cc3..eded360436b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -66,6 +66,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } @@ -104,6 +105,7 @@ std = [ "pallet-contracts-primitives/std", "pallet-contracts/std", "pallet-insecure-randomness-collective-flip/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", "pallet-sudo/std", @@ -139,9 +141,11 @@ std = [ ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -151,6 +155,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-contracts/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -180,6 +185,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-contracts/try-runtime", "pallet-insecure-randomness-collective-flip/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-sudo/try-runtime", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 71733d48e81..e41db7d9213 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -30,13 +30,14 @@ mod weights; mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::AggregateMessageOrigin; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, + ApplyExtrinsicResult, Perbill, }; use sp_std::prelude::*; @@ -57,6 +58,7 @@ use frame_system::limits::{BlockLength, BlockWeights}; pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, + message_queue::*, rococo::{consensus::*, currency::*, fee::WeightToFee}, AccountId, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, @@ -97,10 +99,10 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( - cumulus_pallet_dmp_queue::migration::Migration, cumulus_pallet_parachain_system::migration::Migration, - cumulus_pallet_xcmp_queue::migration::Migration, + cumulus_pallet_xcmp_queue::migration::MigrationToV3, pallet_contracts::Migration, + // unreleased ); type EventRecord = frame_system::EventRecord< @@ -267,13 +269,15 @@ impl pallet_utility::Config for Runtime { parameter_types! { pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -291,6 +295,32 @@ impl pallet_insecure_randomness_collective_flip::Config for Runtime {} impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -376,6 +406,7 @@ construct_runtime!( 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, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Smart Contracts. Contracts: pallet_contracts::{Pallet, Call, Storage, Event, HoldReason} = 40, @@ -389,15 +420,12 @@ construct_runtime!( } ); -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] 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 ebb3de740b9..4c9f357e111 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -18,6 +18,7 @@ use super::{ Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; use crate::common::rococo::currency::CENTS; +use cumulus_primitives_core::AggregateMessageOrigin; use frame_support::{ match_types, parameter_types, traits::{ConstU32, EitherOfDiverse, Equals, Everything, Nothing}, @@ -285,10 +286,19 @@ pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender: impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + #[cfg(feature = "runtime-benchmarks")] + type XcmpQueue = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type XcmpQueue = frame_support::traits::TransformOrigin< + crate::MessageQueue, + AggregateMessageOrigin, + cumulus_primitives_core::ParaId, + parachains_common::message_queue::ParaIdToSibling, + >; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, @@ -298,8 +308,12 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + impl cumulus_pallet_dmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; + type RuntimeEvent = crate::RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; } diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 6051d029a1d..efae74049a7 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -28,6 +28,7 @@ sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura 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} +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -58,12 +59,14 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" default = [ "std" ] runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-glutton/runtime-benchmarks", - "pallet-sudo?/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "parachains-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -87,11 +90,11 @@ std = [ "frame-try-runtime?/std", "pallet-aura/std", "pallet-glutton/std", + "pallet-message-queue/std", "pallet-sudo/std", "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", - "scale-info/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -119,6 +122,7 @@ try-runtime = [ "frame-try-runtime/try-runtime", "pallet-aura/try-runtime", "pallet-glutton/try-runtime", + "pallet-message-queue/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "parachain-info/try-runtime", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index 7f4f88fc055..60a5d004e6c 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -61,6 +61,7 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use cumulus_primitives_core::AggregateMessageOrigin; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -195,6 +196,7 @@ impl frame_system::Config for Runtime { parameter_types! { // We do anything the parent chain tells us in this runtime. pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(2); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -208,13 +210,40 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type OutboundXcmpMessageSource = (); - type DmpMessageHandler = cumulus_pallet_xcm::UnlimitedDmpExecution; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = (); type ReservedXcmpWeight = (); type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; +} + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(80) * + RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + type QueueChangeHandler = (); + type QueuePausedQuery = (); // No XCMP queue pallet deployed. + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; } impl parachain_info::Config for Runtime {} @@ -264,6 +293,7 @@ construct_runtime! { // DMP handler. CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 10, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 11, // The main stage. Glutton: pallet_glutton::{Pallet, Call, Storage, Event, Config} = 20, diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..f787aa32701 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// statemint-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/statemint/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `8013` + // Minimum execution time: 1_660_000 picoseconds. + Weight::from_parts(1_720_000, 0) + .saturating_add(Weight::from_parts(0, 8013)) + // Standard Error: 28_418 + .saturating_add(Weight::from_parts(24_636_963, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs index 36c4abc4006..cf7ef948fd6 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `frame_system` //! diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs index 955010505d3..47f9d1ee105 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs @@ -1,18 +1,19 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. +pub mod cumulus_pallet_parachain_system; pub mod pallet_glutton; +pub mod pallet_message_queue; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs index f278d246b33..e1b0c5bf232 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs @@ -1,18 +1,17 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// 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. //! Autogenerated weights for `pallet_glutton` //! diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..a9f0cb07cfe --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// westmint-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/assets/westmint/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 12_192_000 picoseconds. + Weight::from_parts(12_192_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 10_447_000 picoseconds. + Weight::from_parts(10_447_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 4_851_000 picoseconds. + Weight::from_parts(4_851_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_342_000 picoseconds. + Weight::from_parts(6_342_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 6_199_000 picoseconds. + Weight::from_parts(6_199_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_612_000 picoseconds. + Weight::from_parts(58_612_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 7_296_000 picoseconds. + Weight::from_parts(7_296_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 48_345_000 picoseconds. + Weight::from_parts(48_345_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 56_441_000 picoseconds. + Weight::from_parts(56_441_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 70_858_000 picoseconds. + Weight::from_parts(70_858_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 9efbf563123..43c8f1488a6 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -183,11 +183,13 @@ impl cumulus_pallet_solo_to_para::Config for Runtime { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = cumulus_pallet_solo_to_para::Pallet; type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = (); - type DmpMessageHandler = (); + // Ignore all DMP messages by enqueueing them into `()`: + type DmpQueue = frame_support::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; type ReservedDmpWeight = (); type XcmpMessageHandler = (); type ReservedXcmpWeight = (); diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index b9f63133cce..77449f977bb 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -29,6 +29,7 @@ sp-session = { path = "../../../../../substrate/primitives/session", default-fea sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false} sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} @@ -59,6 +60,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "pallet-aura/std", + "pallet-message-queue/std", "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", @@ -89,6 +91,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime/try-runtime", "pallet-aura/try-runtime", + "pallet-message-queue/try-runtime", "pallet-timestamp/try-runtime", "parachain-info/try-runtime", "sp-runtime/try-runtime", diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 18c1fcbb4ba..f67c0c19ec6 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -33,6 +33,7 @@ pub mod xcm_config; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; +use cumulus_primitives_core::AggregateMessageOrigin; use frame_support::unsigned::TransactionValidityError; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; @@ -181,16 +182,17 @@ impl frame_system::Config for Runtime { } parameter_types! { - // We do anything the parent chain tells us in this runtime. - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(2); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = (); - type DmpMessageHandler = cumulus_pallet_xcm::UnlimitedDmpExecution; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = (); type ReservedXcmpWeight = (); @@ -205,6 +207,32 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // These need to be configured to the XCMP pallet - if it is deployed. + type QueueChangeHandler = (); + type QueuePausedQuery = (); + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} impl pallet_aura::Config for Runtime { @@ -237,8 +265,8 @@ construct_runtime! { }, ParachainInfo: parachain_info::{Pallet, Storage, Config}, - // DMP handler. CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, Aura: pallet_aura::{Pallet, Storage, Config}, AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config}, diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 9cc4b604f33..62bce02bd35 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -25,7 +25,6 @@ sp-core = { path = "../../../../substrate/primitives/core", default-features = f # Cumulus cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue", default-features = false } -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 = {package = "staging-parachain-info", path = "../../pallets/parachain-info", default-features = false } @@ -51,7 +50,6 @@ default = [ "std" ] std = [ "assets-common/std", "codec/std", - "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-core/std", diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 3215242464a..e2a6fb45aec 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -361,7 +361,7 @@ impl< } impl< - Runtime: cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config, + Runtime: cumulus_pallet_parachain_system::Config + pallet_xcm::Config, AllPalletsWithoutSystem, > RuntimeHelper { @@ -378,7 +378,7 @@ impl< // execute xcm as parent origin let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - <::XcmExecutor>::execute_xcm( + <::XcmExecutor>::execute_xcm( MultiLocation::parent(), xcm, hash, diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index 4ccb54496b3..950d0498130 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -37,7 +37,6 @@ pub fn change_storage_constant_by_governance_works: From>, StorageConstant: Get, diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index d5db4a02034..fb66275b025 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -64,6 +64,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} @@ -101,6 +102,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -133,9 +135,11 @@ std = [ ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -146,6 +150,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -174,6 +179,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-session/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 522cbf1face..5ef9af7c712 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -33,14 +33,16 @@ mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; 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}, + traits::{ + AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, Everything, TransformOrigin, + }, weights::{ constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, FeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, @@ -51,6 +53,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, }; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; @@ -67,7 +70,7 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm_config::{AssetsToBlockAuthor, XcmConfig, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{AssetsToBlockAuthor, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -80,7 +83,6 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; // XCM Imports use parachains_common::{AccountId, Signature}; use xcm::latest::prelude::BodyId; -use xcm_executor::XcmExecutor; /// Balance of an account. pub type Balance = u128; @@ -458,13 +460,15 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type OutboundXcmpMessageSource = XcmpQueue; type XcmpMessageHandler = XcmpQueue; @@ -480,26 +484,42 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + 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; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery; } -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; @@ -596,7 +616,7 @@ construct_runtime!( XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // The main stage. Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, @@ -605,19 +625,17 @@ construct_runtime!( } ); -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( + frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] [pallet_session, SessionBench::] [pallet_sudo, Sudo] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] ); } diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 4f45b3ea89b..5e9d347a25d 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -46,6 +46,7 @@ polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", def # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-xcm = { path = "../../../../pallets/xcm", default-features = false } @@ -79,6 +80,7 @@ std = [ "pallet-assets/std", "pallet-aura/std", "pallet-balances/std", + "pallet-message-queue/std", "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -107,14 +109,17 @@ std = [ "xcm/std", ] runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 0523f0ad978..4cb83ccf820 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -23,7 +23,6 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::ParaId; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; @@ -67,8 +66,11 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use frame_support::traits::TransformOrigin; use parachains_common::{ impls::{AssetsFrom, NonZeroIssuance}, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AccountId, AssetIdForTrustBackedAssets, Signature, }; use xcm_builder::{ @@ -272,14 +274,16 @@ impl pallet_sudo::Config for Runtime { parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; @@ -294,6 +298,27 @@ impl cumulus_pallet_parachain_system::Config for Runtime { impl parachain_info::Config for Runtime {} +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -507,22 +532,17 @@ impl cumulus_pallet_xcm::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = (); - type ExecuteOverweightOrigin = EnsureRoot; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; type PriceForSiblingDelivery = NoPriceForMessageDelivery; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; -} - impl cumulus_ping::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; @@ -599,7 +619,8 @@ construct_runtime! { XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 51, CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, + // RIP DmpQueue 53 + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 54, Spambot: cumulus_ping::{Pallet, Call, Storage, Event} = 99, } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 4e758d3f3e6..56646efc61a 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -119,6 +119,7 @@ runtime-benchmarks = [ "bridge-hub-westend-runtime/runtime-benchmarks", "collectives-polkadot-runtime/runtime-benchmarks", "contracts-rococo-runtime/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "glutton-runtime/runtime-benchmarks", diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 6c923a700ec..e7bf15252f2 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -35,3 +35,8 @@ std = [ "sp-trie/std", "xcm/std", ] +runtime-benchmarks = [ + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index f216af2aaee..835c9de649e 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use polkadot_parachain_primitives::primitives::HeadData; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; @@ -78,6 +78,43 @@ impl From for &'static str { } } +/// The origin of an inbound message. +#[derive(Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, Debug)] +pub enum AggregateMessageOrigin { + /// The message came from the para-chain itself. + Here, + /// The message came from the relay-chain. + /// + /// This is used by the DMP queue. + Parent, + /// The message came from a sibling para-chain. + /// + /// This is used by the HRMP queue. + Sibling(ParaId), +} + +impl From for xcm::v3::MultiLocation { + fn from(origin: AggregateMessageOrigin) -> Self { + match origin { + AggregateMessageOrigin::Here => MultiLocation::here(), + AggregateMessageOrigin::Parent => MultiLocation::parent(), + AggregateMessageOrigin::Sibling(id) => + MultiLocation::new(1, Junction::Parachain(id.into())), + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl From for AggregateMessageOrigin { + fn from(x: u32) -> Self { + match x { + 0 => Self::Here, + 1 => Self::Parent, + p => Self::Sibling(ParaId::from(p)), + } + } +} + /// Information about an XCMP channel. pub struct ChannelInfo { /// The maximum number of messages that can be pending in the channel at once. diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index c159bca5d2a..23e2287d1fe 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -45,6 +45,7 @@ std = [ ] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", "frame-support/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 290cfd7e4d8..b760b796ec9 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -37,3 +37,15 @@ cumulus-test-service = { path = "../service" } cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } + +[features] +runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-test-service/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 445de328639..e1e723449ea 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -15,6 +15,7 @@ frame-support = { path = "../../../substrate/frame/support", default-features = 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-balances = { path = "../../../substrate/frame/balances", default-features = false} +pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false} pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false} pallet-glutton = { path = "../../../substrate/frame/glutton", default-features = false} @@ -50,6 +51,7 @@ std = [ "frame-system/std", "pallet-balances/std", "pallet-glutton/std", + "pallet-message-queue/std", "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment/std", diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index e9b242ac638..85a1caa0ce3 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -278,11 +278,13 @@ impl pallet_glutton::Config for Runtime { } impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); type SelfParaId = ParachainId; type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); type OutboundXcmpMessageSource = (); - type DmpMessageHandler = (); + // Ignore all DMP messages by enqueueing them into `()`: + type DmpQueue = frame_support::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; type ReservedDmpWeight = (); type XcmpMessageHandler = (); type ReservedXcmpWeight = (); diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index c996a01a12e..14e45a4c7e6 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -98,6 +98,8 @@ substrate-test-utils = { path = "../../../substrate/test-utils" } [features] runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 5d43b48ea32..2f851f1bcde 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -27,6 +27,7 @@ pallet-message-queue = { path = "../../../substrate/frame/message-queue" } # Cumulus cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue" } cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 3da7814bec3..f11a3d5c5af 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -24,19 +24,23 @@ pub use std::{ }; // Substrate +pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessageOrigin; pub use frame_support::{ assert_ok, sp_runtime::{traits::Header as HeaderT, DispatchResult}, traits::{ - EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues, + EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnInitialize, OriginTrait, + ProcessMessage, ProcessMessageError, ServiceQueues, }, weights::{Weight, WeightMeter}, }; pub use frame_system::{Config as SystemConfig, Pallet as SystemPallet}; pub use pallet_balances::AccountData; +pub use pallet_message_queue; pub use sp_arithmetic::traits::Bounded; pub use sp_core::{blake2_256, parameter_types, sr25519, storage::Storage, Pair}; pub use sp_io::TestExternalities; +pub use sp_runtime::BoundedSlice; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, fmt::Debug}; pub use sp_tracing; @@ -227,8 +231,8 @@ pub trait Chain: TestExt + NetworkComponent { } pub trait RelayChain: Chain { - type MessageProcessor: ProcessMessage; type SovereignAccountOf: ConvertLocation>; + type MessageProcessor: ProcessMessage + ServiceQueues; fn child_location_of(id: ParaId) -> MultiLocation { (Ancestor(0), ParachainJunction(id.into())).into() @@ -245,10 +249,10 @@ pub trait RelayChain: Chain { pub trait Parachain: Chain { type XcmpMessageHandler: XcmpMessageHandler; - type DmpMessageHandler: DmpMessageHandler; type LocationToAccountId: ConvertLocation>; type ParachainInfo: Get; type ParachainSystem; + type MessageProcessor: ProcessMessage + ServiceQueues; fn init(); @@ -346,7 +350,6 @@ macro_rules! decl_test_relay_chains { core = { MessageProcessor: $mp:path, SovereignAccountOf: $sovereign_acc_of:path, - }, pallets = { $($pallet_name:ident: $pallet_path:path,)* @@ -569,9 +572,9 @@ macro_rules! decl_test_parachains { runtime = $runtime:ident, core = { XcmpMessageHandler: $xcmp_message_handler:path, - DmpMessageHandler: $dmp_message_handler:path, LocationToAccountId: $location_to_account:path, ParachainInfo: $parachain_info:path, + MessageProcessor: $message_processor:path, }, pallets = { $($pallet_name:ident: $pallet_path:path,)* @@ -606,10 +609,10 @@ macro_rules! decl_test_parachains { impl $crate::Parachain for $name { type XcmpMessageHandler = $xcmp_message_handler; - type DmpMessageHandler = $dmp_message_handler; type LocationToAccountId = $location_to_account; type ParachainSystem = $crate::ParachainSystemPallet<::Runtime>; type ParachainInfo = $parachain_info; + type MessageProcessor = $message_processor; // We run an empty block during initialisation to open HRMP channels // and have them ready for the next block @@ -968,7 +971,7 @@ macro_rules! decl_test_networks { } fn process_downward_messages() { - use $crate::{DmpMessageHandler, Bounded, Parachain, RelayChainBlockNumber, TestExt}; + use $crate::{DmpMessageHandler, Bounded, Parachain, RelayChainBlockNumber, TestExt, Encode}; while let Some((to_para_id, messages)) = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { @@ -983,16 +986,25 @@ macro_rules! decl_test_networks { msg_dedup.dedup(); let msgs = msg_dedup.clone().into_iter().filter(|m| { - !$crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap_or(&mut $crate::VecDeque::new()).contains(&(to_para_id, m.0, m.1.clone()))) + !$crate::DMP_DONE.with(|b| b.borrow().get(stringify!($name)) + .unwrap_or(&mut $crate::VecDeque::new()) + .contains(&(to_para_id, m.0, m.1.clone())) + ) }).collect::)>>(); - if msgs.len() != 0 { + + use $crate::{ProcessMessage, CumulusAggregateMessageOrigin, BoundedSlice, WeightMeter, TestExt}; + for (block, msg) in msgs.clone().into_iter() { + let mut weight_meter = WeightMeter::new(); <$parachain>::ext_wrapper(|| { - <$parachain as Parachain>::DmpMessageHandler::handle_dmp_messages(msgs.clone().into_iter(), $crate::Weight::max_value()); + let _ = <$parachain as Parachain>::MessageProcessor::process_message( + &msg[..], + $crate::CumulusAggregateMessageOrigin::Parent, + &mut weight_meter, + &mut msg.using_encoded(sp_core::blake2_256), + ); }); $crate::log::debug!(target: concat!("dmp::", stringify!($name)) , "DMP messages processed {:?} to para_id {:?}", msgs.clone(), &to_para_id); - for m in msgs { - $crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((to_para_id, m.0, m.1))); - } + $crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((to_para_id, block, msg))); } } )* @@ -1000,7 +1012,7 @@ macro_rules! decl_test_networks { } fn process_horizontal_messages() { - use $crate::{XcmpMessageHandler, Bounded, Parachain, TestExt}; + use $crate::{XcmpMessageHandler, ServiceQueues, Bounded}; while let Some((to_para_id, messages)) = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { @@ -1010,7 +1022,9 @@ macro_rules! decl_test_networks { if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id { <$parachain>::ext_wrapper(|| { - <$parachain as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::max_value()); + <$parachain as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::MAX); + // Nudge the MQ pallet to process immediately instead of in the next block. + let _ = <$parachain as Parachain>::MessageProcessor::service_queues($crate::Weight::MAX); }); $crate::log::debug!(target: concat!("hrmp::", stringify!($name)) , "HRMP messages processed {:?} to para_id {:?}", &messages, &to_para_id); } @@ -1019,10 +1033,10 @@ macro_rules! decl_test_networks { } fn process_upward_messages() { - use $crate::{Encode, ProcessMessage, TestExt}; + use $crate::{Encode, ProcessMessage, TestExt, WeightMeter}; while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { - let mut weight_meter = $crate::WeightMeter::new(); + let mut weight_meter = WeightMeter::new(); <$relay_chain>::ext_wrapper(|| { let _ = <$relay_chain as $crate::RelayChain>::MessageProcessor::process_message( &msg[..], @@ -1199,6 +1213,7 @@ macro_rules! assert_expected_events { let mut event_message: Vec = Vec::new(); for (index, event) in events.iter().enumerate() { + $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); // Have to reset the variable to override a previous partial match meet_conditions = true; match event { @@ -1244,7 +1259,7 @@ macro_rules! assert_expected_events { ) ); } else if !event_received { - message.push(format!("\n\n{}::\x1b[31m{}\x1b[0m was never received", stringify!($chain), stringify!($event_pat))); + message.push(format!("\n\n{}::\x1b[31m{}\x1b[0m was never received. All events:\n{:#?}", stringify!($chain), stringify!($event_pat), <$chain>::events())); } else { // If we find a perfect match we remove the event to avoid being potentially assessed multiple times events.remove(index_match); @@ -1282,10 +1297,60 @@ macro_rules! decl_test_sender_receiver_accounts_parameter_types { }; } -pub struct DefaultMessageProcessor(PhantomData); -impl ProcessMessage for DefaultMessageProcessor +pub struct DefaultParaMessageProcessor(PhantomData); +// Process HRMP messages from sibling paraids +impl ProcessMessage for DefaultParaMessageProcessor +where + T: Parachain, + T::Runtime: MessageQueueConfig, + <::MessageProcessor as ProcessMessage>::Origin: + PartialEq, + MessageQueuePallet: EnqueueMessage + ServiceQueues, +{ + type Origin = CumulusAggregateMessageOrigin; + + fn process_message( + msg: &[u8], + orig: Self::Origin, + _meter: &mut WeightMeter, + _id: &mut XcmHash, + ) -> Result { + MessageQueuePallet::::enqueue_message( + msg.try_into().expect("Message too long"), + orig.clone(), + ); + MessageQueuePallet::::service_queues(Weight::MAX); + + Ok(true) + } +} +impl ServiceQueues for DefaultParaMessageProcessor +where + T: Parachain, + T::Runtime: MessageQueueConfig, + <::MessageProcessor as ProcessMessage>::Origin: + PartialEq, + MessageQueuePallet: EnqueueMessage + ServiceQueues, +{ + type OverweightMessageAddress = (); + + fn service_queues(weight_limit: Weight) -> Weight { + MessageQueuePallet::::service_queues(weight_limit) + } + + fn execute_overweight( + _weight_limit: Weight, + _address: Self::OverweightMessageAddress, + ) -> Result { + unimplemented!() + } +} + +pub struct DefaultRelayMessageProcessor(PhantomData); +// Process UMP messages on the relay +impl ProcessMessage for DefaultRelayMessageProcessor where - T: Chain + RelayChain, + T: RelayChain, T::Runtime: MessageQueueConfig, <::MessageProcessor as ProcessMessage>::Origin: PartialEq, @@ -1309,6 +1374,28 @@ where } } +impl ServiceQueues for DefaultRelayMessageProcessor +where + T: RelayChain, + T::Runtime: MessageQueueConfig, + <::MessageProcessor as ProcessMessage>::Origin: + PartialEq, + MessageQueuePallet: EnqueueMessage + ServiceQueues, +{ + type OverweightMessageAddress = (); + + fn service_queues(weight_limit: Weight) -> Weight { + MessageQueuePallet::::service_queues(weight_limit) + } + + fn execute_overweight( + _weight_limit: Weight, + _address: Self::OverweightMessageAddress, + ) -> Result { + unimplemented!() + } +} + /// Struct that keeps account's id and balance #[derive(Clone)] pub struct TestAccount { diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index dc89ae7868e..5a1efdf8982 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -333,7 +333,7 @@ impl DmpMessageHandler for () { } /// The aggregate XCMP message format. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo, RuntimeDebug)] pub enum XcmpMessageFormat { /// Encoded `VersionedXcm` messages, all concatenated. ConcatenatedVersionedXcm, diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index e34286d750a..90af9cde00a 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -30,7 +30,7 @@ use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::{ defensive, pallet_prelude::*, - traits::{Defensive, EnqueueMessage}, + traits::{Defensive, EnqueueMessage, Footprint, QueueFootprint}, BoundedSlice, }; use frame_system::pallet_prelude::*; @@ -231,7 +231,7 @@ pub enum AggregateMessageOrigin { /// Identifies a UMP queue inside the `MessageQueue` pallet. /// -/// It is written in verbose form since future variants like `Loopback` and `Bridged` are already +/// It is written in verbose form since future variants like `Here` and `Bridged` are already /// forseeable. #[derive(Encode, Decode, Clone, MaxEncodedLen, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub enum UmpQueueId { @@ -925,7 +925,7 @@ impl Pallet { pub(crate) fn relay_dispatch_queue_size(para_id: ParaId) -> (u32, u32) { let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id))); - (fp.count as u32, fp.size as u32) + (fp.storage.count as u32, fp.storage.size as u32) } /// Check that all the upward messages sent by a candidate pass the acceptance criteria. @@ -1149,10 +1149,11 @@ impl AcceptanceCheckErr { impl OnQueueChanged for Pallet { // Write back the remaining queue capacity into `relay_dispatch_queue_remaining_capacity`. - fn on_queue_changed(origin: AggregateMessageOrigin, count: u64, size: u64) { + fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) { let para = match origin { AggregateMessageOrigin::Ump(UmpQueueId::Para(p)) => p, }; + let QueueFootprint { storage: Footprint { count, size }, .. } = fp; let (count, size) = (count.saturated_into(), size.saturated_into()); // TODO paritytech/polkadot#6283: Remove all usages of `relay_dispatch_queue_size` #[allow(deprecated)] @@ -1329,6 +1330,6 @@ impl QueueFootprinter for Pallet { type Origin = UmpQueueId; fn message_count(origin: Self::Origin) -> u64 { - T::MessageQueue::footprint(AggregateMessageOrigin::Ump(origin)).count + T::MessageQueue::footprint(AggregateMessageOrigin::Ump(origin)).storage.count } } diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index e96b5e96892..def60888205 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -386,7 +386,7 @@ fn relay_dispatch_queue_size_is_updated() { MessageQueue::service_queues(Weight::from_all(u64::MAX)); let fp = MessageQueue::footprint(AggregateMessageOrigin::Ump(para)); - let (para_queue_count, para_queue_size) = (fp.count, fp.size); + let (para_queue_count, para_queue_size) = (fp.storage.count, fp.storage.size); assert_eq!(para_queue_count, 1, "count wrong for para: {}", p); assert_eq!(para_queue_size, 8, "size wrong for para: {}", p); } @@ -400,7 +400,7 @@ fn relay_dispatch_queue_size_is_updated() { assert_queue_remaining(p.into(), cfg.max_upward_queue_count, cfg.max_upward_queue_size); let fp = MessageQueue::footprint(AggregateMessageOrigin::Ump(para)); - let (para_queue_count, para_queue_size) = (fp.count, fp.size); + let (para_queue_count, para_queue_size) = (fp.storage.count, fp.storage.size); assert_eq!(para_queue_count, 0, "count wrong for para: {}", p); assert_eq!(para_queue_size, 0, "size wrong for para: {}", p); } diff --git a/polkadot/xcm/src/double_encoded.rs b/polkadot/xcm/src/double_encoded.rs index 2dc9b012257..875b811da3f 100644 --- a/polkadot/xcm/src/double_encoded.rs +++ b/polkadot/xcm/src/double_encoded.rs @@ -70,6 +70,11 @@ impl DoubleEncoded { pub fn as_ref(&self) -> Option<&T> { self.decoded.as_ref() } + + /// Access the encoded data. + pub fn into_encoded(self) -> Vec { + self.encoded + } } impl DoubleEncoded { diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index f9f31b752a9..aa5bfe169ac 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -71,6 +71,9 @@ pub type QueryId = u64; #[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct Xcm(pub Vec>); +/// The maximal number of instructions in an XCM before decoding fails. +/// +/// This is a deliberate limit - not a technical one. pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; environmental::environmental!(instructions_count: u8); diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index dba45a8310a..330ff40aac0 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -50,6 +50,7 @@ impl< let message = Xcm::::try_from(versioned_message) .map_err(|_| ProcessMessageError::Unsupported)?; let pre = XcmExecutor::prepare(message).map_err(|_| ProcessMessageError::Unsupported)?; + // The worst-case weight: let required = pre.weight_of(); ensure!(meter.can_consume(required), ProcessMessageError::Overweight(required)); diff --git a/prdoc/pr_1246.prdoc b/prdoc/pr_1246.prdoc new file mode 100644 index 00000000000..f9c86781233 --- /dev/null +++ b/prdoc/pr_1246.prdoc @@ -0,0 +1,17 @@ +title: Use the `Message Queue` Pallet for DMP and XCMP dispatch queueing + +doc: + - audience: Parachain Dev + description: Replaces the queueing capabilities of the `DMP and `XCMP-Queue` pallet for incoming messages with the `MessageQueue` pallet. This simplifies the code and improves security. + +migrations: + runtime: + - + pallet: "cumulus_pallet_dmp_queue" + description: "Messages from the DMP dispatch queue will be moved over to the MQ pallet via `on_initialize`. This happens over multiple blocks and emits a `Completed` event at the end. The pallet can be un-deployed and deleted afterwards. Note that the migration reverses the order of messages, which should be acceptable as a one-off." + +crates: + - name: "cumulus_pallet_xcmp_queue" + note: Pallet config must be altered according to the MR description. + +host_functions: [] diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 04bbea121dd..12d289478b3 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -195,7 +195,7 @@ use frame_support::{ pallet_prelude::*, traits::{ DefensiveTruncateFrom, EnqueueMessage, ExecuteOverweightError, Footprint, ProcessMessage, - ProcessMessageError, QueuePausedQuery, ServiceQueues, + ProcessMessageError, QueueFootprint, QueuePausedQuery, ServiceQueues, }, BoundedSlice, CloneNoBound, DefaultNoBound, }; @@ -423,14 +423,23 @@ impl Default for BookState { } } +impl From> for QueueFootprint { + fn from(book: BookState) -> Self { + QueueFootprint { + pages: book.count, + storage: Footprint { count: book.message_count, size: book.size }, + } + } +} + /// Handler code for when the items in a queue change. pub trait OnQueueChanged { /// Note that the queue `id` now has `item_count` items in it, taking up `items_size` bytes. - fn on_queue_changed(id: Id, items_count: u64, items_size: u64); + fn on_queue_changed(id: Id, fp: QueueFootprint); } impl OnQueueChanged for () { - fn on_queue_changed(_: Id, _: u64, _: u64) {} + fn on_queue_changed(_: Id, _: QueueFootprint) {} } #[frame_support::pallet] @@ -907,11 +916,7 @@ impl Pallet { T::WeightInfo::execute_overweight_page_updated() }; BookStateFor::::insert(&origin, &book_state); - T::QueueChangeHandler::on_queue_changed( - origin, - book_state.message_count, - book_state.size, - ); + T::QueueChangeHandler::on_queue_changed(origin, book_state.into()); Ok(weight_counter.consumed().saturating_add(page_weight)) }, } @@ -976,11 +981,7 @@ impl Pallet { book_state.message_count.saturating_reduce(page.remaining.into() as u64); book_state.size.saturating_reduce(page.remaining_size.into() as u64); BookStateFor::::insert(origin, &book_state); - T::QueueChangeHandler::on_queue_changed( - origin.clone(), - book_state.message_count, - book_state.size, - ); + T::QueueChangeHandler::on_queue_changed(origin.clone(), book_state.into()); Self::deposit_event(Event::PageReaped { origin: origin.clone(), index: page_index }); Ok(()) @@ -1035,11 +1036,7 @@ impl Pallet { } BookStateFor::::insert(&origin, &book_state); if total_processed > 0 { - T::QueueChangeHandler::on_queue_changed( - origin, - book_state.message_count, - book_state.size, - ); + T::QueueChangeHandler::on_queue_changed(origin, book_state.into()); } (total_processed > 0, next_ready) } @@ -1482,7 +1479,7 @@ impl EnqueueMessage> for Pallet { ) { Self::do_enqueue_message(&origin, message); let book_state = BookStateFor::::get(&origin); - T::QueueChangeHandler::on_queue_changed(origin, book_state.message_count, book_state.size); + T::QueueChangeHandler::on_queue_changed(origin, book_state.into()); } fn enqueue_messages<'a>( @@ -1493,7 +1490,7 @@ impl EnqueueMessage> for Pallet { Self::do_enqueue_message(&origin, message); } let book_state = BookStateFor::::get(&origin); - T::QueueChangeHandler::on_queue_changed(origin, book_state.message_count, book_state.size); + T::QueueChangeHandler::on_queue_changed(origin, book_state.into()); } fn sweep_queue(origin: MessageOriginOf) { @@ -1508,8 +1505,7 @@ impl EnqueueMessage> for Pallet { BookStateFor::::insert(&origin, &book_state); } - fn footprint(origin: MessageOriginOf) -> Footprint { - let book_state = BookStateFor::::get(&origin); - Footprint { count: book_state.message_count, size: book_state.size } + fn footprint(origin: MessageOriginOf) -> QueueFootprint { + BookStateFor::::get(&origin).into() } } diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index e6af0d9f1ee..55a64574354 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -278,8 +278,8 @@ parameter_types! { /// Records all queue changes into [`QueueChanges`]. pub struct RecordingQueueChangeHandler; impl OnQueueChanged for RecordingQueueChangeHandler { - fn on_queue_changed(id: MessageOrigin, items_count: u64, items_size: u64) { - QueueChanges::mutate(|cs| cs.push((id, items_count, items_size))); + fn on_queue_changed(id: MessageOrigin, fp: QueueFootprint) { + QueueChanges::mutate(|cs| cs.push((id, fp.storage.count, fp.storage.size))); } } @@ -366,3 +366,7 @@ pub fn num_overweight_enqueued_events() -> u32 { }) .count() as u32 } + +pub fn fp(pages: u32, count: u64, size: u64) -> QueueFootprint { + QueueFootprint { storage: Footprint { count, size }, pages } +} diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index 5a235a8750e..d94ad581ea0 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -49,6 +49,7 @@ fn enqueue_within_one_page_works() { MessageQueue::enqueue_message(msg("c"), Here); assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); assert_eq!(MessagesProcessed::take(), vec![(b"a".to_vec(), Here), (b"b".to_vec(), Here)]); + assert_eq!(MessageQueue::footprint(Here).pages, 1); assert_eq!(MessageQueue::service_queues(2.into_weight()), 1.into_weight()); assert_eq!(MessagesProcessed::take(), vec![(b"c".to_vec(), Here)]); @@ -314,6 +315,7 @@ fn reap_page_permanent_overweight_works() { MessageQueue::enqueue_message(msg("weight=2"), Here); } assert_eq!(Pages::::iter().count(), n); + assert_eq!(MessageQueue::footprint(Here).pages, n as u32); assert_eq!(QueueChanges::take().len(), n); // Mark all pages as stale since their message is permanently overweight. MessageQueue::service_queues(1.into_weight()); @@ -339,6 +341,7 @@ fn reap_page_permanent_overweight_works() { assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); assert!(QueueChanges::take().is_empty()); } + assert_eq!(MessageQueue::footprint(Here).pages, 3); }); } @@ -1022,8 +1025,9 @@ fn footprint_works() { BookStateFor::::insert(origin, book); let info = MessageQueue::footprint(origin); - assert_eq!(info.count as usize, msgs); - assert_eq!(info.size, page.remaining_size as u64); + assert_eq!(info.storage.count as usize, msgs); + assert_eq!(info.storage.size, page.remaining_size as u64); + assert_eq!(info.pages, 1); // Sweeping a queue never calls OnQueueChanged. assert!(QueueChanges::take().is_empty()); @@ -1044,16 +1048,44 @@ fn footprint_invalid_works() { fn footprint_on_swept_works() { use MessageOrigin::*; build_and_execute::(|| { - let mut book = empty_book::(); - book.message_count = 3; - book.size = 10; - BookStateFor::::insert(Here, &book); - knit(&Here); + build_ring::(&[Here]); MessageQueue::sweep_queue(Here); let fp = MessageQueue::footprint(Here); - assert_eq!(fp.count, 3); - assert_eq!(fp.size, 10); + assert_eq!((1, 1, 1), (fp.storage.count, fp.storage.size, fp.pages)); + }) +} + +/// The number of reported pages takes overweight pages into account. +#[test] +fn footprint_num_pages_works() { + use MessageOrigin::*; + build_and_execute::(|| { + MessageQueue::enqueue_message(msg("weight=2"), Here); + MessageQueue::enqueue_message(msg("weight=3"), Here); + + assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 16)); + + // Mark the messages as overweight. + assert_eq!(MessageQueue::service_queues(1.into_weight()), 0.into_weight()); + assert_eq!(System::events().len(), 2); + // Overweight does not change the footprint. + assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 16)); + + // Now execute the second message. + assert_eq!( + ::execute_overweight(3.into_weight(), (Here, 1, 0)) + .unwrap(), + 3.into_weight() + ); + assert_eq!(MessageQueue::footprint(Here), fp(1, 1, 8)); + // And the first one: + assert_eq!( + ::execute_overweight(2.into_weight(), (Here, 0, 0)) + .unwrap(), + 2.into_weight() + ); + assert_eq!(MessageQueue::footprint(Here), Default::default()); }) } @@ -1143,6 +1175,7 @@ fn permanently_overweight_book_unknits() { assert_ring(&[]); assert_eq!(MessagesProcessed::take().len(), 0); assert_eq!(BookStateFor::::get(Here).message_count, 1); + assert_eq!(MessageQueue::footprint(Here).pages, 1); // Now if we enqueue another message, it will become ready again. MessageQueue::enqueue_messages([msg("weight=1")].into_iter(), Here); assert_ring(&[Here]); diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index 1b8054c51a8..ac469bb385c 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -30,6 +30,7 @@ sp-io = { path = "../../primitives/io" } pallet-balances = { path = "../balances" } pallet-utility = { path = "../utility" } pallet-proxy = { path = "../proxy" } +frame-support = { path = "../support", features = ["experimental"] } [features] default = [ "std" ] diff --git a/substrate/frame/safe-mode/src/tests.rs b/substrate/frame/safe-mode/src/tests.rs index ca1d7eb1d93..b92c5b87a53 100644 --- a/substrate/frame/safe-mode/src/tests.rs +++ b/substrate/frame/safe-mode/src/tests.rs @@ -22,32 +22,8 @@ use super::*; use crate::mock::{RuntimeCall, *}; -use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; -use sp_runtime::{traits::Dispatchable, TransactionOutcome}; - -/// Do something hypothetically by rolling back any changes afterwards. -/// -/// Returns the original result of the closure. -macro_rules! hypothetically { - ( $e:expr ) => { - frame_support::storage::transactional::with_transaction( - || -> TransactionOutcome> { - sp_runtime::TransactionOutcome::Rollback(Ok($e)) - }, - ) - .expect("Always returning Ok; qed") - }; -} - -/// Assert something to be [*hypothetically*] `Ok` without actually committing it. -/// -/// Reverts any storage changes made by the closure. -macro_rules! hypothetically_ok { - ($e:expr $(, $args:expr)* $(,)?) => { - let result = hypothetically!($e); - assert_ok!(result $(, $args)*); - }; -} +use frame_support::{assert_err, assert_noop, assert_ok, hypothetically_ok, traits::Currency}; +use sp_runtime::traits::Dispatchable; #[test] fn fails_to_filter_calls_to_safe_mode_pallet() { diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 4888b8996d1..d4958868685 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -51,7 +51,9 @@ pub mod __private { pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; - pub use sp_runtime::{traits::Dispatchable, RuntimeDebug, StateVersion}; + pub use sp_runtime::{ + traits::Dispatchable, DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, + }; #[cfg(feature = "std")] pub use sp_state_machine::BasicExternalities; pub use sp_std; @@ -781,6 +783,31 @@ macro_rules! assert_error_encoded_size { } => {}; } +/// Do something hypothetically by rolling back any changes afterwards. +/// +/// Returns the original result of the closure. +#[macro_export] +#[cfg(feature = "experimental")] +macro_rules! hypothetically { + ( $e:expr ) => { + $crate::storage::transactional::with_transaction(|| -> $crate::__private::TransactionOutcome> { + $crate::__private::TransactionOutcome::Rollback(Ok($e)) + }, + ).expect("Always returning Ok; qed") + }; +} + +/// Assert something to be *hypothetically* `Ok`, without actually committing it. +/// +/// Reverts any storage changes made by the closure. +#[macro_export] +#[cfg(feature = "experimental")] +macro_rules! hypothetically_ok { + ($e:expr $(, $args:expr)* $(,)?) => { + $crate::assert_ok!($crate::hypothetically!($e) $(, $args)*); + }; +} + #[doc(hidden)] pub use serde::{Deserialize, Serialize}; diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 75c43d8cc50..4c692f848fd 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -113,7 +113,8 @@ pub use preimages::{Bounded, BoundedInline, FetchResult, QueryPreimage, StorePre mod messages; pub use messages::{ EnqueueMessage, EnqueueWithOrigin, ExecuteOverweightError, HandleMessage, NoopServiceQueues, - ProcessMessage, ProcessMessageError, QueuePausedQuery, ServiceQueues, TransformOrigin, + ProcessMessage, ProcessMessageError, QueueFootprint, QueuePausedQuery, ServiceQueues, + TransformOrigin, }; mod safe_mode; diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index 0db163e072b..654380dbb0a 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -116,6 +116,15 @@ impl ServiceQueues for NoopServiceQueues { } } +/// The resource footprint of a queue. +#[derive(Default, Copy, Clone, Eq, PartialEq, RuntimeDebug)] +pub struct QueueFootprint { + /// The number of pages in the queue (including overweight pages). + pub pages: u32, + /// The storage footprint of the queue (including overweight messages). + pub storage: Footprint, +} + /// Can enqueue messages for multiple origins. pub trait EnqueueMessage { /// The maximal length any enqueued message may have. @@ -134,7 +143,7 @@ pub trait EnqueueMessage { fn sweep_queue(origin: Origin); /// Return the state footprint of the given queue. - fn footprint(origin: Origin) -> Footprint; + fn footprint(origin: Origin) -> QueueFootprint; } impl EnqueueMessage for () { @@ -146,8 +155,8 @@ impl EnqueueMessage for () { ) { } fn sweep_queue(_: Origin) {} - fn footprint(_: Origin) -> Footprint { - Footprint::default() + fn footprint(_: Origin) -> QueueFootprint { + QueueFootprint::default() } } @@ -173,7 +182,7 @@ impl, O: MaxEncodedLen, N: MaxEncodedLen, C: Convert> E::sweep_queue(C::convert(origin)); } - fn footprint(origin: N) -> Footprint { + fn footprint(origin: N) -> QueueFootprint { E::footprint(C::convert(origin)) } } @@ -195,7 +204,7 @@ pub trait HandleMessage { fn sweep_queue(); /// Return the state footprint of the queue. - fn footprint() -> Footprint; + fn footprint() -> QueueFootprint; } /// Adapter type to transform an [`EnqueueMessage`] with an origin into a [`HandleMessage`] impl. @@ -220,7 +229,7 @@ where E::sweep_queue(O::get()); } - fn footprint() -> Footprint { + fn footprint() -> QueueFootprint { E::footprint(O::get()) } } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 9098b6e48ed..fe0905c3bed 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.188", optional = true, default-features = false, features = ["derive", "alloc"] } bounded-collections = { version = "0.1.8", default-features = false } -- GitLab From 15a34838819f09f3bcfb3c05c08fb53934d8efc4 Mon Sep 17 00:00:00 2001 From: Richard Melkonian <35300528+0xmovses@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:02:01 +0000 Subject: [PATCH 427/633] Create new trait for non-dedup storage decode (#1932) - This adds the new trait `StorageDecodeNonDedupLength` and implements them for `BTreeSet` and its bounded types. - New unit test has been added to cover the case. - See linked [issue](https://github.com/paritytech/polkadot-sdk/issues/126) which outlines the original issue. Note that the added trait here doesn't add new logic but improves semantics. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- .../support/src/storage/bounded_btree_map.rs | 11 ++ .../support/src/storage/bounded_btree_set.rs | 22 ++-- substrate/frame/support/src/storage/mod.rs | 122 +++++++++++++++++- .../support/src/storage/types/double_map.rs | 26 ++++ .../frame/support/src/storage/types/map.rs | 22 ++++ .../frame/support/src/storage/types/value.rs | 22 ++++ 6 files changed, 210 insertions(+), 15 deletions(-) diff --git a/substrate/frame/support/src/storage/bounded_btree_map.rs b/substrate/frame/support/src/storage/bounded_btree_map.rs index f2f32d890b8..91196be9e80 100644 --- a/substrate/frame/support/src/storage/bounded_btree_map.rs +++ b/substrate/frame/support/src/storage/bounded_btree_map.rs @@ -79,5 +79,16 @@ pub mod test { assert!(FooDoubleMap::decode_len(1, 2).is_none()); assert!(FooDoubleMap::decode_len(2, 2).is_none()); }); + + TestExternalities::default().execute_with(|| { + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + FooDoubleMap::insert(1, 1, bounded.clone()); + FooDoubleMap::insert(2, 2, bounded); // duplicate value + + assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); + assert_eq!(FooDoubleMap::decode_len(2, 2).unwrap(), 3); + assert!(FooDoubleMap::decode_len(2, 1).is_none()); + assert!(FooDoubleMap::decode_len(1, 2).is_none()); + }); } } diff --git a/substrate/frame/support/src/storage/bounded_btree_set.rs b/substrate/frame/support/src/storage/bounded_btree_set.rs index 52be1bb99f1..cf801eb4787 100644 --- a/substrate/frame/support/src/storage/bounded_btree_set.rs +++ b/substrate/frame/support/src/storage/bounded_btree_set.rs @@ -17,10 +17,10 @@ //! Traits, types and structs to support a bounded `BTreeSet`. -use crate::storage::StorageDecodeLength; +use frame_support::storage::StorageDecodeNonDedupLength; pub use sp_runtime::BoundedBTreeSet; -impl StorageDecodeLength for BoundedBTreeSet {} +impl StorageDecodeNonDedupLength for BoundedBTreeSet {} #[cfg(test)] pub mod test { @@ -56,28 +56,28 @@ pub mod test { } #[test] - fn decode_len_works() { + fn decode_non_dedup_len_works() { TestExternalities::default().execute_with(|| { let bounded = boundedset_from_keys::>(&[1, 2, 3]); Foo::put(bounded); - assert_eq!(Foo::decode_len().unwrap(), 3); + assert_eq!(Foo::decode_non_dedup_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { let bounded = boundedset_from_keys::>(&[1, 2, 3]); FooMap::insert(1, bounded); - assert_eq!(FooMap::decode_len(1).unwrap(), 3); - assert!(FooMap::decode_len(0).is_none()); - assert!(FooMap::decode_len(2).is_none()); + assert_eq!(FooMap::decode_non_dedup_len(1).unwrap(), 3); + assert!(FooMap::decode_non_dedup_len(0).is_none()); + assert!(FooMap::decode_non_dedup_len(2).is_none()); }); TestExternalities::default().execute_with(|| { let bounded = boundedset_from_keys::>(&[1, 2, 3]); FooDoubleMap::insert(1, 1, bounded); - assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); - assert!(FooDoubleMap::decode_len(2, 1).is_none()); - assert!(FooDoubleMap::decode_len(1, 2).is_none()); - assert!(FooDoubleMap::decode_len(2, 2).is_none()); + assert_eq!(FooDoubleMap::decode_non_dedup_len(1, 1).unwrap(), 3); + assert!(FooDoubleMap::decode_non_dedup_len(2, 1).is_none()); + assert!(FooDoubleMap::decode_non_dedup_len(1, 2).is_none()); + assert!(FooDoubleMap::decode_non_dedup_len(2, 2).is_none()); }); } } diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index 851b0687bd1..7f39a3fdad8 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -167,6 +167,32 @@ pub trait StorageValue { { T::decode_len(&Self::hashed_key()) } + + /// Read the length of the storage value without decoding the entire value. + /// + /// `T` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This + /// means that any duplicate items are included. + /// + /// - `None` does not mean that `get()` does not return a value. The default value is completely + /// ignored by this function. + /// + /// # Example + #[doc = docify::embed!("src/storage/mod.rs", btree_set_decode_non_dedup_len)] + /// This demonstrates how `decode_non_dedup_len` will count even the duplicate values in the + /// storage (in this case, the number `4` is counted twice). + fn decode_non_dedup_len() -> Option + where + T: StorageDecodeNonDedupLength, + { + T::decode_non_dedup_len(&Self::hashed_key()) + } } /// A non-continuous container type. @@ -346,6 +372,27 @@ pub trait StorageMap { V::decode_len(&Self::hashed_key_for(key)) } + /// Read the length of the storage value without decoding the entire value. + /// + /// `V` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + /// + /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This + /// means that any duplicate items are included. + fn decode_non_dedup_len>(key: KeyArg) -> Option + where + V: StorageDecodeNonDedupLength, + { + V::decode_non_dedup_len(&Self::hashed_key_for(key)) + } + /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. @@ -741,6 +788,27 @@ pub trait StorageDoubleMap { V::decode_len(&Self::hashed_key_for(key1, key2)) } + /// Read the length of the storage value without decoding the entire value under the + /// given `key1` and `key2`. + /// + /// `V` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + fn decode_non_dedup_len(key1: KArg1, key2: KArg2) -> Option + where + KArg1: EncodeLike, + KArg2: EncodeLike, + V: StorageDecodeNonDedupLength, + { + V::decode_non_dedup_len(&Self::hashed_key_for(key1, key2)) + } + /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and /// `OldHasher2` to the current hashers. /// @@ -1400,8 +1468,7 @@ pub trait StoragePrefixedMap { /// This trait is sealed. pub trait StorageAppend: private::Sealed {} -/// Marker trait that will be implemented for types that support to decode their length in an -/// efficient way. It is expected that the length is at the beginning of the encoded object +/// It is expected that the length is at the beginning of the encoded object /// and that the length is a `Compact`. /// /// This trait is sealed. @@ -1421,6 +1488,29 @@ pub trait StorageDecodeLength: private::Sealed + codec::DecodeLength { } } +/// It is expected that the length is at the beginning of the encoded objectand that the length is a +/// `Compact`. +/// +/// # Note +/// The length returned by this trait is not deduplicated, i.e. it is the length of the underlying +/// stored Vec. +/// +/// This trait is sealed. +pub trait StorageDecodeNonDedupLength: private::Sealed + codec::DecodeLength { + /// Decode the length of the storage value at `key`. + /// + /// This function assumes that the length is at the beginning of the encoded object and is a + /// `Compact`. + /// + /// Returns `None` if the storage value does not exist or the decoding failed. + fn decode_non_dedup_len(key: &[u8]) -> Option { + let mut data = [0u8; 5]; + let len = sp_io::storage::read(key, &mut data, 0)?; + let len = data.len().min(len as usize); + ::len(&data[..len]).ok() + } +} + /// Provides `Sealed` trait to prevent implementing trait `StorageAppend` & `StorageDecodeLength` /// & `EncodeLikeTuple` outside of this crate. mod private { @@ -1471,7 +1561,14 @@ impl StorageAppend for Vec {} impl StorageDecodeLength for Vec {} impl StorageAppend for BTreeSet {} -impl StorageDecodeLength for BTreeSet {} +impl StorageDecodeNonDedupLength for BTreeSet {} + +// Blanket implementation StorageDecodeNonDedupLength for all types that are StorageDecodeLength. +impl StorageDecodeNonDedupLength for T { + fn decode_non_dedup_len(key: &[u8]) -> Option { + T::decode_len(key) + } +} /// We abuse the fact that SCALE does not put any marker into the encoding, i.e. we only encode the /// internal vec and we can append to this vec. We have a test that ensures that if the `Digest` @@ -2026,7 +2123,24 @@ mod test { FooSet::append(6); FooSet::append(7); - assert_eq!(FooSet::decode_len().unwrap(), 7); + assert_eq!(FooSet::decode_non_dedup_len().unwrap(), 7); + }); + } + + #[docify::export] + #[test] + fn btree_set_decode_non_dedup_len() { + #[crate::storage_alias] + type Store = StorageValue>; + + TestExternalities::default().execute_with(|| { + Store::append(4); + Store::append(4); // duplicate value + Store::append(5); + + let length_with_dup_items = 3; + + assert_eq!(Store::decode_non_dedup_len().unwrap(), length_with_dup_items); }); } } diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 1002222a895..cb9479d491c 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -27,6 +27,7 @@ use crate::{ StorageHasher, Twox128, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; +use frame_support::storage::StorageDecodeNonDedupLength; use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; @@ -455,6 +456,31 @@ where >::decode_len(key1, key2) } + /// Read the length of the storage value without decoding the entire value. + /// + /// `Value` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + /// + /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This + /// means that any duplicate items are included. + pub fn decode_non_dedup_len(key1: KArg1, key2: KArg2) -> Option + where + KArg1: EncodeLike, + KArg2: EncodeLike, + Value: StorageDecodeNonDedupLength, + { + >::decode_non_dedup_len( + key1, key2, + ) + } + /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and /// `OldHasher2` to the current hashers. /// diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 75988220e3f..d0149cf3fc8 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -27,6 +27,7 @@ use crate::{ StorageHasher, Twox128, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; +use frame_support::storage::StorageDecodeNonDedupLength; use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; @@ -285,6 +286,27 @@ where >::decode_len(key) } + /// Read the length of the storage value without decoding the entire value. + /// + /// `Value` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + /// + /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This + /// means that any duplicate items are included. + pub fn decode_non_dedup_len>(key: KeyArg) -> Option + where + Value: StorageDecodeNonDedupLength, + { + >::decode_non_dedup_len(key) + } + /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 9fff1774d7b..34cc3e24956 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -26,6 +26,7 @@ use crate::{ traits::{GetDefault, StorageInfo, StorageInstance}, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; +use frame_support::storage::StorageDecodeNonDedupLength; use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; @@ -233,6 +234,27 @@ where >::decode_len() } + /// Read the length of the storage value without decoding the entire value. + /// + /// `Value` is required to implement [`StorageDecodeNonDedupLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + /// + /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This + /// means that any duplicate items are included. + pub fn decode_non_dedup_len() -> Option + where + Value: StorageDecodeNonDedupLength, + { + >::decode_non_dedup_len() + } + /// Try and append the given item to the value in the storage. /// /// Is only available if `Value` of the storage implements [`StorageTryAppend`]. -- GitLab From 0d3c67d96beda62b729e8328c5755358ac244246 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 3 Nov 2023 11:32:41 +0300 Subject: [PATCH 428/633] [testnet] Allow governance to control fees for Rococo <> Westend bridge (#2139) Right now governance could only control byte-fee component of Rococo <> Westend message fees (paid at Asset Hubs). This PR changes it a bit: 1) governance now allowed to control both fee components - byte fee and base fee; 2) base fee now includes cost of "default" delivery and confirmation transactions, in addition to `ExportMessage` instruction cost. --- Cargo.lock | 2 + .../src/messages_benchmarking.rs | 54 +- .../runtime-common/src/messages_generation.rs | 37 +- .../chain-asset-hub-rococo/src/lib.rs | 4 - .../chain-asset-hub-westend/src/lib.rs | 4 - .../chain-asset-hub-wococo/src/lib.rs | 4 - .../chain-bridge-hub-rococo/src/lib.rs | 15 + .../chain-bridge-hub-westend/src/lib.rs | 15 + .../chain-bridge-hub-wococo/src/lib.rs | 15 + .../assets/asset-hub-rococo/Cargo.toml | 2 + .../assets/asset-hub-rococo/src/xcm_config.rs | 30 +- .../assets/asset-hub-westend/Cargo.toml | 2 + .../asset-hub-westend/src/xcm_config.rs | 28 +- .../bridge-hub-rococo/tests/tests.rs | 117 +++- .../bridge-hub-westend/tests/tests.rs | 63 +- .../bridge-hubs/test-utils/src/test_cases.rs | 540 ++++++++++++++++-- 16 files changed, 801 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 808a1976e07..bfe54bf8eea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -910,6 +910,7 @@ dependencies = [ "bp-asset-hub-westend", "bp-asset-hub-wococo", "bp-bridge-hub-rococo", + "bp-bridge-hub-westend", "bp-bridge-hub-wococo", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -1022,6 +1023,7 @@ dependencies = [ "assets-common", "bp-asset-hub-rococo", "bp-asset-hub-westend", + "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs index d80a88f1068..e7e7891461b 100644 --- a/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -22,24 +22,22 @@ use crate::{ messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - AccountIdOf, BridgedChain, HashOf, HasherOf, MessageBridge, ThisChain, + AccountIdOf, BridgedChain, HashOf, MessageBridge, ThisChain, }, messages_generation::{ - encode_all_messages, encode_lane_data, grow_trie_leaf_value, prepare_messages_storage_proof, + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, }, }; -use bp_messages::{storage_keys, MessagePayload}; +use bp_messages::MessagePayload; use bp_polkadot_core::parachains::ParaHash; -use bp_runtime::{ - record_all_trie_keys, Chain, Parachain, RawStorageProof, StorageProofSize, UnderlyingChainOf, -}; +use bp_runtime::{Chain, Parachain, StorageProofSize, UnderlyingChainOf}; use codec::Encode; use frame_support::weights::Weight; use pallet_bridge_messages::benchmarking::{MessageDeliveryProofParams, MessageProofParams}; use sp_runtime::traits::{Header, Zero}; use sp_std::prelude::*; -use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; use xcm::v3::prelude::*; /// Prepare inbound bridge message according to given message proof parameters. @@ -172,7 +170,11 @@ where { // prepare storage proof let lane = params.lane; - let (state_root, storage_proof) = prepare_message_delivery_proof::(params); + let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( + params.lane, + params.inbound_lane_data, + params.size, + ); // update runtime storage let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); @@ -200,7 +202,11 @@ where { // prepare storage proof let lane = params.lane; - let (state_root, storage_proof) = prepare_message_delivery_proof::(params); + let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( + params.lane, + params.inbound_lane_data, + params.size, + ); // update runtime storage let (_, bridged_header_hash) = @@ -213,36 +219,6 @@ where } } -/// Prepare in-memory message delivery proof, without inserting anything to the runtime storage. -fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams>>, -) -> (HashOf>, RawStorageProof) -where - B: MessageBridge, -{ - // prepare Bridged chain storage with inbound lane state - let storage_key = - storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, ¶ms.lane).0; - let mut root = Default::default(); - let mut mdb = MemoryDB::default(); - { - let mut trie = - TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); - let inbound_lane_data = - grow_trie_leaf_value(params.inbound_lane_data.encode(), params.size); - trie.insert(&storage_key, &inbound_lane_data) - .map_err(|_| "TrieMut::insert has failed") - .expect("TrieMut::insert should not fail in benchmarks"); - } - - // generate storage proof to be delivered to This chain - let storage_proof = record_all_trie_keys::>>, _>(&mdb, &root) - .map_err(|_| "record_all_trie_keys has failed") - .expect("record_all_trie_keys should not fail in benchmarks"); - - (root, storage_proof) -} - /// Insert header to the bridge GRANDPA pallet. pub(crate) fn insert_header_to_grandpa_pallet( state_root: bp_runtime::HashOf, diff --git a/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/bin/runtime-common/src/messages_generation.rs index 3c550a9bd0f..c37aaa5d4d5 100644 --- a/bridges/bin/runtime-common/src/messages_generation.rs +++ b/bridges/bin/runtime-common/src/messages_generation.rs @@ -16,10 +16,11 @@ //! Helpers for generating message storage proofs, that are used by tests and by benchmarks. -use crate::messages::{BridgedChain, HashOf, HasherOf, MessageBridge}; +use crate::messages::{AccountIdOf, BridgedChain, HashOf, HasherOf, MessageBridge, ThisChain}; use bp_messages::{ - storage_keys, LaneId, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, + storage_keys, InboundLaneData, LaneId, MessageKey, MessageNonce, MessagePayload, + OutboundLaneData, }; use bp_runtime::{record_all_trie_keys, RawStorageProof, StorageProofSize}; use codec::Encode; @@ -104,6 +105,38 @@ where (root, storage_proof) } +/// Prepare storage proof of given messages delivery. +/// +/// Returns state trie root and nodes with prepared messages. +pub fn prepare_message_delivery_storage_proof( + lane: LaneId, + inbound_lane_data: InboundLaneData>>, + size: StorageProofSize, +) -> (HashOf>, RawStorageProof) +where + B: MessageBridge, +{ + // prepare Bridged chain storage with inbound lane state + let storage_key = storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane).0; + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = + TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); + let inbound_lane_data = grow_trie_leaf_value(inbound_lane_data.encode(), size); + trie.insert(&storage_key, &inbound_lane_data) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + } + + // generate storage proof to be delivered to This chain + let storage_proof = record_all_trie_keys::>>, _>(&mdb, &root) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); + + (root, storage_proof) +} + /// Add extra data to the trie leaf value so that it'll be of given size. pub fn grow_trie_leaf_value(mut value: Vec, size: StorageProofSize) -> Vec { match size { diff --git a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs index 1a08ade2f4f..6216b24d75c 100644 --- a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs @@ -45,10 +45,6 @@ pub enum Call { 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` + `33%`) - pub const BridgeHubRococoBaseFeeInRocs: u128 = 1624803349; } /// Identifier of AssetHubRococo in the Rococo relay chain. diff --git a/bridges/primitives/chain-asset-hub-westend/src/lib.rs b/bridges/primitives/chain-asset-hub-westend/src/lib.rs index 2d317e4aee4..9de1c880989 100644 --- a/bridges/primitives/chain-asset-hub-westend/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-westend/src/lib.rs @@ -42,10 +42,6 @@ pub enum Call { 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 `BridgeHubWestend`. - /// (initially was calculated by test `BridgeHubWestend::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubWestendBaseFeeInWnds: u128 = 487441010000; } /// Identifier of AssetHubWestend in the Westend relay chain. diff --git a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs index 809e56934e9..c04eb04cce7 100644 --- a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs @@ -42,10 +42,6 @@ pub enum Call { 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` + `33%`) - pub const BridgeHubWococoBaseFeeInWocs: u128 = 1624803349; } /// Identifier of AssetHubWococo in the Wococo relay chain. diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index 039d681951c..e72e711de92 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -82,3 +82,18 @@ pub const WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX: u8 = 51; decl_bridge_finality_runtime_apis!(bridge_hub_rococo); decl_bridge_messages_runtime_apis!(bridge_hub_rococo); + +frame_support::parameter_types! { + /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Rococo + /// BridgeHub. + /// (initially was calculated by test `BridgeHubRococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 1628875538; + + /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. + /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) + pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 6417262881; + + /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. + /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 6159996668; +} diff --git a/bridges/primitives/chain-bridge-hub-westend/src/lib.rs b/bridges/primitives/chain-bridge-hub-westend/src/lib.rs index a52e328b687..0124e05bf88 100644 --- a/bridges/primitives/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-westend/src/lib.rs @@ -73,3 +73,18 @@ pub const WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 44; decl_bridge_finality_runtime_apis!(bridge_hub_westend); decl_bridge_messages_runtime_apis!(bridge_hub_westend); + +frame_support::parameter_types! { + /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Westend + /// BridgeHub. + /// (initially was calculated by test `BridgeHubWestend::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 488662666666; + + /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. + /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) + pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 1925196628010; + + /// Transaction fee that is paid at the Westend BridgeHub for delivering single outbound message confirmation. + /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) + pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 1848016628010; +} diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs index 750a8f7ecb9..c8bd397cec5 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -73,3 +73,18 @@ pub const WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 45; decl_bridge_finality_runtime_apis!(bridge_hub_wococo); decl_bridge_messages_runtime_apis!(bridge_hub_wococo); + +frame_support::parameter_types! { + /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Wococo + /// BridgeHub. + /// (initially was calculated by test `BridgeHubWococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) + pub const BridgeHubWococoBaseXcmFeeInWocs: u128 = 1624803349; + + /// Transaction fee that is paid at the Wococo BridgeHub for delivering single inbound message. + /// (initially was calculated by test `BridgeHubWococo::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) + pub const BridgeHubWococoBaseDeliveryFeeInWocs: u128 = 6417262881; + + /// Transaction fee that is paid at the Wococo BridgeHub for delivering single outbound message confirmation. + /// (initially was calculated by test `BridgeHubWococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) + pub const BridgeHubWococoBaseConfirmationFeeInWocs: u128 = 6159996668; +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 764d0eb989f..7efcf1e1585 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -88,6 +88,7 @@ bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-h 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-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } [dev-dependencies] asset-test-utils = { path = "../test-utils" } @@ -177,6 +178,7 @@ std = [ "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-wococo/std", + "bp-bridge-hub-westend/std", "codec/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index a17d0a6cf0c..ff37ff74e75 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -283,6 +283,9 @@ impl Contains for SafeCallFilter { match call { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) || + items + .iter() + .all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterBaseFee::key())) || items.iter().all(|(k, _)| k.eq(&Flavor::key())) => return true, _ => (), @@ -760,6 +763,25 @@ pub mod bridging { // common/shared parameters for Wococo/Rococo parameter_types! { + /// Base price of every byte of the Rococo -> Westend message. Can be adjusted via + /// governance `set_storage` call. + /// + /// Default value is our estimation of the: + /// + /// 1) an approximate cost of XCM execution (`ExportMessage` and surroundings) at Rococo bridge hub; + /// + /// 2) the approximate cost of Rococo -> Westend message delivery transaction on Westend Bridge Hub, + /// converted into ROCs using 1:1 conversion rate; + /// + /// 3) the approximate cost of Rococo -> Westend message confirmation transaction on Rococo Bridge Hub. + pub storage XcmBridgeHubRouterBaseFee: Balance = + bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get() + .saturating_add(bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds::get()) + .saturating_add(bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get()); + /// Price of every byte of the Rococo -> Westend message. Can be adjusted via + /// governance `set_storage` call. + pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + 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, @@ -768,8 +790,6 @@ pub mod bridging { /// 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 BridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() @@ -814,7 +834,7 @@ pub mod bridging { // base delivery fee to local `BridgeHub` Some(( XcmBridgeHubRouterFeeAssetId::get(), - bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(), + XcmBridgeHubRouterBaseFee::get(), ).into()) ) ]; @@ -890,7 +910,7 @@ pub mod bridging { // base delivery fee to local `BridgeHub` Some(( XcmBridgeHubRouterFeeAssetId::get(), - bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(), + XcmBridgeHubRouterBaseFee::get(), ).into()) ) ]; @@ -966,7 +986,7 @@ pub mod bridging { // base delivery fee to local `BridgeHub` Some(( XcmBridgeHubRouterFeeAssetId::get(), - bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs::get(), + XcmBridgeHubRouterBaseFee::get(), ).into()) ) ]; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index dbcb0be3cb7..49b80b067cf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -84,6 +84,7 @@ assets-common = { path = "../common", default-features = false } 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } [dev-dependencies] @@ -167,6 +168,7 @@ std = [ "assets-common/std", "bp-asset-hub-rococo/std", "bp-asset-hub-westend/std", + "bp-bridge-hub-rococo/std", "bp-bridge-hub-westend/std", "codec/std", "cumulus-pallet-aura-ext/std", 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 526c8eb4af4..ec42618513a 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 @@ -262,7 +262,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().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) => + if items.iter().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) || + items + .iter() + .all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterBaseFee::key())) => return true, _ => (), }; @@ -725,13 +728,30 @@ pub mod bridging { use sp_std::collections::btree_set::BTreeSet; parameter_types! { + /// Base price of every byte of the Westend -> Rococo message. Can be adjusted via + /// governance `set_storage` call. + /// + /// Default value is our estimation of the: + /// + /// 1) an approximate cost of XCM execution (`ExportMessage` and surroundings) at Westend bridge hub; + /// + /// 2) the approximate cost of Westend -> Rococo message delivery transaction on Rococo Bridge Hub, + /// converted into WNDs using 1:1 conversion rate; + /// + /// 3) the approximate cost of Westend -> Rococo message confirmation transaction on Westend Bridge Hub. + pub storage XcmBridgeHubRouterBaseFee: Balance = + bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get() + .saturating_add(bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get()) + .saturating_add(bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds::get()); + /// Price of every byte of the Westend -> Rococo message. Can be adjusted via + /// governance `set_storage` call. + pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_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 = WestendLocation::get().into(); - /// Price per byte - can be adjusted via governance `set_storage` call. - pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); pub BridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() @@ -774,7 +794,7 @@ pub mod bridging { // base delivery fee to local `BridgeHub` Some(( XcmBridgeHubRouterFeeAssetId::get(), - bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds::get(), + XcmBridgeHubRouterBaseFee::get(), ).into()) ) ]; 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 b5b1c3778c0..65cca67dac1 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 @@ -23,10 +23,10 @@ use bridge_hub_rococo_runtime::{ xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - UncheckedExtrinsic, + TransactionPayment, UncheckedExtrinsic, }; use codec::{Decode, Encode}; -use frame_support::parameter_types; +use frame_support::{dispatch::GetDispatchInfo, parameter_types}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -83,6 +83,13 @@ fn construct_and_apply_extrinsic( r.unwrap() } +fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> Balance { + let batch_call = RuntimeCall::Utility(batch); + let batch_info = batch_call.get_dispatch_info(); + let xt = construct_extrinsic(Alice, batch_call); + TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) +} + fn executive_init_block(header: &HeaderFor) { Executive::initialize_block(header) } @@ -213,7 +220,7 @@ mod bridge_hub_rococo_tests { XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_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()), + Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), || (), ); // for Westend @@ -235,7 +242,7 @@ mod bridge_hub_rococo_tests { XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, 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()), + Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), || (), ) } @@ -401,10 +408,56 @@ mod bridge_hub_rococo_tests { >(); // check if estimated value is sane - let max_expected = bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(); + let max_expected = bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs` value", + estimated, + max_expected + ); + } + + #[test] + pub fn can_calculate_fee_for_complex_message_delivery_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< + Runtime, + BridgeGrandpaWestendInstance, + BridgeParachainWestendInstance, + WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get(); assert!( estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs` value", + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs` value", + estimated, + max_expected + ); + } + + #[test] + pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< + Runtime, + BridgeGrandpaWestendInstance, + BridgeParachainWestendInstance, + WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs` value", estimated, max_expected ); @@ -540,7 +593,7 @@ mod bridge_hub_wococo_tests { XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_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()), + Some((TokenLocation::get(), bp_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs::get()).into()), set_wococo_flavor, ) } @@ -633,10 +686,56 @@ mod bridge_hub_wococo_tests { >(); // check if estimated value is sane - let max_expected = bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs::get(); + let max_expected = bp_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs` value", + estimated, + max_expected + ); + } + + #[test] + pub fn can_calculate_fee_for_complex_message_delivery_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< + Runtime, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_wococo::BridgeHubWococoBaseDeliveryFeeInWocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseDeliveryFeeInWocs` value", + estimated, + max_expected + ); + } + + #[test] + pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< + Runtime, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_wococo::BridgeHubWococoBaseConfirmationFeeInWocs::get(); assert!( estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs` value", + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseConfirmationFeeInWocs` value", estimated, max_expected ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index babd579f002..16dcd10a2ca 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -23,7 +23,7 @@ use bridge_hub_westend_runtime::{ xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - UncheckedExtrinsic, + TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeParachainRococoInstance, @@ -31,7 +31,7 @@ use bridge_to_rococo_config::{ XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, }; use codec::{Decode, Encode}; -use frame_support::parameter_types; +use frame_support::{dispatch::GetDispatchInfo, parameter_types}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -84,6 +84,13 @@ fn construct_and_apply_extrinsic( r.unwrap() } +fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> Balance { + let batch_call = RuntimeCall::Utility(batch); + let batch_info = batch_call.get_dispatch_info(); + let xt = construct_extrinsic(Alice, batch_call); + TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) +} + fn executive_init_block(header: &HeaderFor) { Executive::initialize_block(header) } @@ -182,7 +189,7 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` - Some((WestendLocation::get(), bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds::get()).into()), + Some((WestendLocation::get(), bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()).into()), || (), ) } @@ -275,11 +282,57 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { >(); // check if estimated value is sane - let max_expected = bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds::get(); + let max_expected = bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get(); assert!( estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds` value", + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds` value", estimated, max_expected ); } + +#[test] +pub fn can_calculate_fee_for_complex_message_delivery_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< + Runtime, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds` value", + estimated, + max_expected + ); +} + +#[test] +pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< + Runtime, + BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessageBridge, + >( + collator_session_keys(), + construct_and_estimate_extrinsic_fee + ); + + // check if estimated value is sane + let max_expected = bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds` value", + estimated, + max_expected + ); +} 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 7281680416b..b421eea6bcf 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 @@ -17,8 +17,9 @@ //! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities. use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch, SourceHeaderChain}, - LaneId, MessageKey, OutboundLaneData, Weight, + LaneId, MessageKey, OutboundLaneData, UnrewardedRelayersState, Weight, }; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHash, ParaId}; @@ -27,9 +28,13 @@ use bp_runtime::{HeaderOf, Parachain, StorageProofSize, UnderlyingChainOf}; use bp_test_utils::{make_default_justification, prepare_parachain_heads_proof}; use bridge_runtime_common::{ messages::{ - target::FromBridgedChainMessagesProof, BridgedChain as MessageBridgedChain, MessageBridge, + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + BridgedChain as MessageBridgedChain, MessageBridge, + }, + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, }, - messages_generation::{encode_all_messages, encode_lane_data, prepare_messages_storage_proof}, messages_xcm_extension::{XcmAsPlainPayload, XcmBlobMessageDispatchResult}, }; use codec::Encode; @@ -399,6 +404,7 @@ pub fn relayed_incoming_message_works::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, UnderlyingChainOf>: bp_runtime::Chain + Parachain, XcmConfig: xcm_executor::Config, HrmpChannelOpener: frame_support::inherent::ProvideInherent< @@ -484,7 +490,11 @@ pub fn relayed_incoming_message_works, MB, ()>( + ) = test_data::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( lane_id, xcm.into(), message_nonce, @@ -626,6 +636,7 @@ pub fn complex_relay_extrinsic_works::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, UnderlyingChainOf>: bp_runtime::Chain + Parachain, XcmConfig: xcm_executor::Config, HrmpChannelOpener: frame_support::inherent::ProvideInherent< @@ -725,7 +736,11 @@ pub fn complex_relay_extrinsic_works, MB, ()>( + ) = test_data::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( lane_id, xcm.clone().into(), message_nonce, @@ -735,27 +750,15 @@ pub fn complex_relay_extrinsic_works::submit_finality_proof { - finality_target: Box::new(relay_chain_header.clone()), - justification: grandpa_justification, - }; - let submit_para_head = - pallet_bridge_parachains::Call::::submit_parachain_heads { - at_relay_block: (relay_header_number, relay_chain_header.hash().into()), - parachains: parachain_heads, - parachain_heads_proof: para_heads_proof, - }; - let submit_message = - pallet_bridge_messages::Call::::receive_messages_proof { - relayer_id_at_bridged_chain: relayer_id_on_source.into(), - proof: message_proof.into(), - messages_count: 1, - dispatch_weight: Weight::from_parts(1000000000, 0), - }; - let batch = pallet_utility::Call::::batch_all { - calls: vec![submit_grandpa.into(), submit_para_head.into(), submit_message.into()], - }; + let relay_chain_header_hash = relay_chain_header.hash(); + let batch = test_data::make_complex_relayer_delivery_batch::( + relay_chain_header, + grandpa_justification, + parachain_heads, + para_heads_proof, + message_proof, + relayer_id_on_source, + ); // sanity checks - before relayer extrinsic assert!(RuntimeHelper::>::take_xcm( @@ -790,10 +793,10 @@ pub fn complex_relay_extrinsic_works>::get().unwrap().1, - relay_chain_header.hash() + relay_chain_header_hash ); assert!(>::contains_key( - relay_chain_header.hash() + relay_chain_header_hash )); // verify parachain head proof correctly imported assert_eq!( @@ -839,7 +842,7 @@ pub fn complex_relay_extrinsic_works( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, +) -> u128 +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 + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + ValidatorIdOf: From>, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + <>::BridgedChain as bp_runtime::Chain>::Hash: From, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: + From> + + From> + + From>, +{ + ExtBuilder::::default() + .with_collators(collator_session_key.collators()) + .with_session_keys(collator_session_key.session_keys()) + .with_safe_xcm_version(XCM_VERSION) + .with_para_id(1000.into()) + .with_tracing() + .build() + .execute_with(|| { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + // + // we don't care about parameter values here, apart from the XCM message size. But we + // do not need to have a large message here, because we're charging for every byte of + // the message additionally + let ( + relay_chain_header, + grandpa_justification, + _, + parachain_heads, + para_heads_proof, + message_proof, + ) = test_data::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( + LaneId::default(), + vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(), + 1, + X2(GlobalConsensus(Polkadot), Parachain(1_000)), + 1, + 5, + 1_000, + ); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::make_complex_relayer_delivery_batch::( + relay_chain_header, + grandpa_justification, + parachain_heads, + para_heads_proof, + message_proof, + Dave.public().into(), + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message delivery for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} + +/// Estimates transaction fee for default message confirmation transaction (batched with required +/// proofs) from bridged parachain. +pub fn can_calculate_fee_for_complex_message_confirmation_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, +) -> u128 +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 + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + <::ThisChain as bp_runtime::Chain>::AccountId: From, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + ValidatorIdOf: From>, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + <>::BridgedChain as bp_runtime::Chain>::Hash: From, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + <>::TargetHeaderChain as TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + >>::MessagesDeliveryProof: From>, + ::RuntimeCall: + From> + + From> + + From>, +{ + ExtBuilder::::default() + .with_collators(collator_session_key.collators()) + .with_session_keys(collator_session_key.session_keys()) + .with_safe_xcm_version(XCM_VERSION) + .with_para_id(1000.into()) + .with_tracing() + .build() + .execute_with(|| { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let unrewarded_relayers = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }; + let ( + relay_chain_header, + grandpa_justification, + _, + parachain_heads, + para_heads_proof, + message_delivery_proof, + ) = test_data::make_complex_relayer_confirmation_proofs::< + >::BridgedChain, + MB, + (), + >(LaneId::default(), 1, 5, 1_000, Alice.public().into(), unrewarded_relayers.clone()); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::make_complex_relayer_confirmation_batch::( + relay_chain_header, + grandpa_justification, + parachain_heads, + para_heads_proof, + message_delivery_proof, + unrewarded_relayers, + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message confirmation for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} + pub mod test_data { use super::*; - use bp_header_chain::justification::GrandpaJustification; - use bp_messages::MessageNonce; + use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; + use bp_messages::{DeliveredMessages, InboundLaneData, MessageNonce, UnrewardedRelayer}; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; - use bp_runtime::BasicOperatingMode; + use bp_runtime::{BasicOperatingMode, HashOf}; use bp_test_utils::authority_list; + use sp_runtime::{DigestItem, SaturatedConversion}; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::{validate_export, ExportXcm}; @@ -968,7 +1166,117 @@ pub mod test_data { (location, xcm).encode().encode() } - pub fn make_complex_relayer_proofs( + /// Prepare a batch call with relay finality proof, parachain head proof and message proof. + pub fn make_complex_relayer_delivery_batch( + relay_chain_header: BridgedHeader, + grandpa_justification: GrandpaJustification>, + parachain_heads: Vec<(ParaId, ParaHash)>, + para_heads_proof: ParaHeadsProof, + message_proof: FromBridgedChainMessagesProof, + relayer_id_at_bridged_chain: AccountId32, + ) -> pallet_utility::Call where + Runtime:pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + <>::BridgedChain as bp_runtime::Chain>::Hash: From, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + >::InboundRelayer: From, + ::RuntimeCall: + From> + + From> + + From>, + { + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }; + let submit_para_head = + pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: ( + relay_chain_header_number.saturated_into(), + relay_chain_header_hash.into(), + ), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }; + let submit_message = pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), + proof: message_proof.into(), + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }; + pallet_utility::Call::::batch_all { + calls: vec![submit_grandpa.into(), submit_para_head.into(), submit_message.into()], + } + } + + /// Prepare a batch call with relay finality proof, parachain head proof and message delivery + /// proof. + pub fn make_complex_relayer_confirmation_batch( + relay_chain_header: BridgedHeader, + grandpa_justification: GrandpaJustification>, + parachain_heads: Vec<(ParaId, ParaHash)>, + para_heads_proof: ParaHeadsProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + relayers_state: UnrewardedRelayersState, + ) -> pallet_utility::Call where + Runtime:pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + <>::BridgedChain as bp_runtime::Chain>::Hash: From, + <>::TargetHeaderChain as TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + >>::MessagesDeliveryProof: From>, + ::RuntimeCall: + From> + + From> + + From>, + { + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }; + let submit_para_head = + pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: ( + relay_chain_header_number.saturated_into(), + relay_chain_header_hash.into(), + ), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }; + let submit_message_delivery_proof = + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: message_delivery_proof.into(), + relayers_state, + }; + pallet_utility::Call::::batch_all { + calls: vec![ + submit_grandpa.into(), + submit_para_head.into(), + submit_message_delivery_proof.into(), + ], + } + } + + /// Prepare storage proofs of messages, stored at the source chain. + pub fn make_complex_relayer_delivery_proofs( lane_id: LaneId, xcm_message: Xcm, message_nonce: MessageNonce, @@ -977,18 +1285,19 @@ pub mod test_data { relay_header_number: u32, bridged_para_id: u32, ) -> ( - BridgedRelayHeader, - GrandpaJustification, + HeaderOf, + GrandpaJustification>, ParaHead, Vec<(ParaId, ParaHash)>, ParaHeadsProof, FromBridgedChainMessagesProof, ) where - BridgedRelayHeader: HeaderT, - ::Hash: From, + BridgedRelayChain: ChainWithGrandpa, + HashOf: From, MB: MessageBridge, ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, UnderlyingChainOf>: bp_runtime::Chain + Parachain, { let message_payload = prepare_inbound_xcm(xcm_message, message_destination); @@ -1004,19 +1313,18 @@ pub mod test_data { encode_lane_data, ); - let bridged_para_head = ParaHead( - bp_test_utils::test_header_with_root::>( - para_header_number.into(), - para_state_root.into(), - ) - .encode(), + let ( + relay_chain_header, + justification, + bridged_para_head, + parachain_heads, + para_heads_proof, + ) = make_complex_bridged_heads_proof::( + para_state_root, + para_header_number, + relay_header_number, + bridged_para_id, ); - let (relay_state_root, para_heads_proof, parachain_heads) = - prepare_parachain_heads_proof::>(vec![( - bridged_para_id, - bridged_para_head.clone(), - )]); - assert_eq!(bridged_para_head.hash(), parachain_heads[0].1); let message_proof = FromBridgedChainMessagesProof { bridged_header_hash: bridged_para_head.hash(), @@ -1026,12 +1334,6 @@ pub mod test_data { nonces_end: message_nonce, }; - // import bridged relay chain block#1 with state root containing head#5 of bridged parachain - let relay_chain_header: BridgedRelayHeader = bp_test_utils::test_header_with_root( - relay_header_number.into(), - relay_state_root.into(), - ); - let justification = make_default_justification(&relay_chain_header); ( relay_chain_header, justification, @@ -1042,6 +1344,134 @@ pub mod test_data { ) } + /// Prepare storage proofs of message confirmations, stored at the target chain. + pub fn make_complex_relayer_confirmation_proofs( + lane_id: LaneId, + para_header_number: u32, + relay_header_number: u32, + bridged_para_id: u32, + relayer_id_at_this_chain: AccountId32, + relayers_state: UnrewardedRelayersState, + ) -> ( + HeaderOf, + GrandpaJustification>, + ParaHead, + Vec<(ParaId, ParaHash)>, + ParaHeadsProof, + FromBridgedChainMessagesDeliveryProof, + ) + where + BridgedRelayChain: ChainWithGrandpa, + HashOf: From, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + <::ThisChain as bp_runtime::Chain>::AccountId: From, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + { + // prepare para storage proof containing message delivery proof + let (para_state_root, para_storage_proof) = prepare_message_delivery_storage_proof::( + lane_id, + InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer_id_at_this_chain.into(), + messages: DeliveredMessages::new(1) + }; + relayers_state.unrewarded_relayer_entries as usize + ] + .into(), + last_confirmed_nonce: 1, + }, + StorageProofSize::Minimal(0), + ); + + let ( + relay_chain_header, + justification, + bridged_para_head, + parachain_heads, + para_heads_proof, + ) = make_complex_bridged_heads_proof::( + para_state_root, + para_header_number, + relay_header_number, + bridged_para_id, + ); + + let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: bridged_para_head.hash(), + storage_proof: para_storage_proof, + lane: lane_id, + }; + + ( + relay_chain_header, + justification, + bridged_para_head, + parachain_heads, + para_heads_proof, + message_delivery_proof, + ) + } + + /// Make bridged parachain header with given state root and relay header that is finalizing it. + pub fn make_complex_bridged_heads_proof( + para_state_root: ParaHash, + para_header_number: u32, + relay_header_number: u32, + bridged_para_id: u32, + ) -> ( + HeaderOf, + GrandpaJustification>, + ParaHead, + Vec<(ParaId, ParaHash)>, + ParaHeadsProof, + ) + where + BridgedRelayChain: ChainWithGrandpa, + HashOf: From, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + { + let bridged_para_head = ParaHead( + bp_test_utils::test_header_with_root::>( + para_header_number.into(), + para_state_root.into(), + ) + .encode(), + ); + let (relay_state_root, para_heads_proof, parachain_heads) = + prepare_parachain_heads_proof::>(vec![( + bridged_para_id, + bridged_para_head.clone(), + )]); + assert_eq!(bridged_para_head.hash(), parachain_heads[0].1); + + // import bridged relay chain block#1 with state root containing head#5 of bridged parachain + let mut relay_chain_header: BridgedRelayChain::Header = + bp_test_utils::test_header_with_root( + relay_header_number.into(), + relay_state_root.into(), + ); + // to compute proper cost of GRANDPA call, let's add some dummy bytes to header, so that the + // `submit_finality_proof` call size would be close to maximal expected (and refundable) + let expected_bytes_in_grandpa_call = BridgedRelayChain::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION + .saturating_mul(BridgedRelayChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY) + .saturating_add(BridgedRelayChain::MAX_HEADER_SIZE) + as usize; + let extra_bytes_required = + expected_bytes_in_grandpa_call.saturating_sub(relay_chain_header.encoded_size()); + relay_chain_header + .digest_mut() + .push(DigestItem::Other(vec![42; extra_bytes_required])); + + let justification = make_default_justification(&relay_chain_header); + (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) + } + /// Helper that creates InitializationData mock data, that can be used to initialize bridge /// GRANDPA pallet pub fn initialization_data< -- GitLab From e9987401f3e8edba1b831bd1874a44ace7d58d13 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Fri, 3 Nov 2023 13:43:29 +0100 Subject: [PATCH 429/633] skip trigger for review bot on draft PRs (#2145) Added if condition on review-bot's trigger so it does not trigger in `draft` PRs. --- .github/workflows/review-trigger.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml index 40e2918df2b..1ae6b79ffbd 100644 --- a/.github/workflows/review-trigger.yml +++ b/.github/workflows/review-trigger.yml @@ -13,6 +13,7 @@ on: jobs: trigger-review-bot: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest name: trigger review bot steps: -- GitLab From dca142398e00786429d69eb8b9e4454499962b2a Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:26:40 +0200 Subject: [PATCH 430/633] substrate: sysinfo: Expose failed hardware requirements (#2144) The check_hardware functions does not give us too much information as to what is failing, so let's return the list of failed metrics, so that callers can print it. This would make debugging easier, rather than try to guess which dimension is actually failing. Signed-off-by: Alexandru Gheorghe --- Cargo.lock | 1 + .../parachain-template/node/src/service.rs | 10 ++- cumulus/polkadot-parachain/src/service.rs | 7 +- polkadot/node/service/src/lib.rs | 12 ++-- substrate/bin/node/cli/src/service.rs | 12 ++-- substrate/client/sysinfo/Cargo.toml | 1 + substrate/client/sysinfo/src/sysinfo.rs | 66 +++++++++++++++++-- 7 files changed, 89 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfe54bf8eea..7d9e4bf725c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15980,6 +15980,7 @@ dependencies = [ name = "sc-sysinfo" version = "6.0.0-dev" dependencies = [ + "derive_more", "futures", "libc", "log", diff --git a/cumulus/parachain-template/node/src/service.rs b/cumulus/parachain-template/node/src/service.rs index 84dcd6dd1b3..43d16ee0d5b 100644 --- a/cumulus/parachain-template/node/src/service.rs +++ b/cumulus/parachain-template/node/src/service.rs @@ -255,10 +255,14 @@ async fn start_node_impl( // Here you can check whether the hardware meets your chains' requirements. Putting a link // in there and swapping out the requirements for your own are probably a good idea. The // requirements for a para-chain are dictated by its relay-chain. - if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && validator { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements for role 'Authority'." + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + Err(err) if validator => { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.", + err ); + }, + _ => {}, } if let Some(ref mut telemetry) = telemetry { diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 438d09a4c77..3bcc9b7f60d 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -1955,10 +1955,11 @@ pub async fn start_contracts_rococo_node( fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { // Polkadot para-chains should generally use these requirements to ensure that the relay-chain // will not take longer than expected to import its blocks. - if !frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { + if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { log::warn!( - "⚠️ The hardware does not meet the minimal requirements for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware" + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err ); } } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index ced89c3843a..0ed7940b3e8 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -965,11 +965,15 @@ pub fn new_full( if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && role.is_authority() { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware" + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + Err(err) if role.is_authority() => { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err ); + }, + _ => {}, } if let Some(ref mut telemetry) = telemetry { diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 5a85f4cde0a..153dda5c0a5 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -449,10 +449,14 @@ pub fn new_full_base( if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && role.is_authority() { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements for role 'Authority'." - ); + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + Err(err) if role.is_authority() => { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.", + err + ); + }, + _ => {}, } if let Some(ref mut telemetry) = telemetry { diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index fdf987ed45f..86f4d217dd9 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -19,6 +19,7 @@ libc = "0.2" log = "0.4.17" rand = "0.8.5" rand_pcg = "0.3.1" +derive_more = "0.99" regex = "1" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index 41161fc685d..bef87a83e46 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -23,9 +23,11 @@ use sp_core::{sr25519, Pair}; use sp_io::crypto::sr25519_verify; use sp_std::{fmt, fmt::Formatter, prelude::*}; +use derive_more::From; use rand::{seq::SliceRandom, Rng, RngCore}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{ + fmt::Display, fs::File, io::{Seek, SeekFrom, Write}, ops::{Deref, DerefMut}, @@ -48,6 +50,37 @@ pub enum Metric { DiskRndWrite, } +/// Describes a checking failure for the hardware requirements. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct CheckFailure { + /// The metric that failed the check. + pub metric: Metric, + /// The expected minimum value. + pub expected: Throughput, + /// The measured value. + pub found: Throughput, +} + +/// A list of metrics that failed to meet the minimum hardware requirements. +#[derive(Debug, Clone, PartialEq, From)] +pub struct CheckFailures(pub Vec); + +impl Display for CheckFailures { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!(formatter, "Failed checks: ")?; + for failure in &self.0 { + write!( + formatter, + "{}(expected: {}, found: {}), ", + failure.metric.name(), + failure.expected, + failure.found + )? + } + Ok(()) + } +} + impl Metric { /// The category of the metric. pub fn category(&self) -> &'static str { @@ -626,33 +659,54 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { impl Requirements { /// Whether the hardware requirements are met by the provided benchmark results. - pub fn check_hardware(&self, hwbench: &HwBench) -> bool { + pub fn check_hardware(&self, hwbench: &HwBench) -> Result<(), CheckFailures> { + let mut failures = Vec::new(); for requirement in self.0.iter() { match requirement.metric { Metric::Blake2256 => if requirement.minimum > hwbench.cpu_hashrate_score { - return false + failures.push(CheckFailure { + metric: requirement.metric, + expected: requirement.minimum, + found: hwbench.cpu_hashrate_score, + }); }, Metric::MemCopy => if requirement.minimum > hwbench.memory_memcpy_score { - return false + failures.push(CheckFailure { + metric: requirement.metric, + expected: requirement.minimum, + found: hwbench.memory_memcpy_score, + }); }, Metric::DiskSeqWrite => if let Some(score) = hwbench.disk_sequential_write_score { if requirement.minimum > score { - return false + failures.push(CheckFailure { + metric: requirement.metric, + expected: requirement.minimum, + found: score, + }); } }, Metric::DiskRndWrite => if let Some(score) = hwbench.disk_random_write_score { if requirement.minimum > score { - return false + failures.push(CheckFailure { + metric: requirement.metric, + expected: requirement.minimum, + found: score, + }); } }, Metric::Sr25519Verify => {}, } } - true + if failures.is_empty() { + Ok(()) + } else { + Err(failures.into()) + } } } -- GitLab From f6f4c5aac8a672512dbe1530e6184a7d07f0fb08 Mon Sep 17 00:00:00 2001 From: Anthony Lazam Date: Fri, 3 Nov 2023 16:04:39 +0100 Subject: [PATCH 431/633] Update Kusama Parachains Bootnode (#2148) # Description Update the bootnode of kusama parachains before decommissioning the nodes. This will avoid connecting to non-existing bootnodes. --- cumulus/parachains/chain-specs/asset-hub-kusama.json | 4 ---- cumulus/parachains/chain-specs/bridge-hub-kusama.json | 4 ---- 2 files changed, 8 deletions(-) diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index e5085879562..91a821efab9 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -9,10 +9,6 @@ "/dns/kusama-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWMzvdGcUXxacLdMQzRVrsP1mJrZHcrz8LtGbhLzve84Qx", "/dns/kusama-asset-hub-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWQmGf5z3DU1kKcZoLzMNgdbP31ybjuwxS1VGLKMUjq5ez", "/dns/kusama-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQmGf5z3DU1kKcZoLzMNgdbP31ybjuwxS1VGLKMUjq5ez", - "/dns/kusama-asset-hub-connect-2.polkadot.io/tcp/30334/p2p/12D3KooWLm6iHcmA3YD4xn2zfbm4KLF5KSUqJJAnmt2UGr9o2PgB", - "/dns/kusama-asset-hub-connect-2.polkadot.io/tcp/443/wss/p2p/12D3KooWLm6iHcmA3YD4xn2zfbm4KLF5KSUqJJAnmt2UGr9o2PgB", - "/dns/kusama-asset-hub-connect-3.polkadot.io/tcp/30334/p2p/12D3KooWD8Bma5qPbq7N5qdED3Xy6GXHfvfk86TL8aVTQKxmWkHG", - "/dns/kusama-asset-hub-connect-3.polkadot.io/tcp/443/wss/p2p/12D3KooWD8Bma5qPbq7N5qdED3Xy6GXHfvfk86TL8aVTQKxmWkHG", "/dns/boot.stake.plus/tcp/34333/p2p/12D3KooWAzSSZ7jLqMw1WPomYEKCYANQaKemXQ8BKoFvNEvfmdqR", "/dns/boot.stake.plus/tcp/34334/wss/p2p/12D3KooWAzSSZ7jLqMw1WPomYEKCYANQaKemXQ8BKoFvNEvfmdqR", "/dns/boot.metaspan.io/tcp/26052/p2p/12D3KooW9z9hKqe3mqYAp5UJMhZiCqhkTHyiR43fegnGmTJ3JAba", diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 5e45e1528a1..c4a7d6358f7 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -5,12 +5,8 @@ "bootNodes": [ "/dns/kusama-bridge-hub-connect-ew1-0.polkadot.io/tcp/30334/p2p/12D3KooWPQQPivrqQ51kRTDc2R1mtqwKT4GGtk2rapkY4FrwHrEp", "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/30334/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", - "/dns/kusama-bridge-hub-connect-ue4-0.polkadot.io/tcp/30334/p2p/12D3KooWMf1sVnJDTkKWtaThqvrgcSPLbfGXttSqbwhM2DJp9BUG", - "/dns/kusama-bridge-hub-connect-ue4-1.polkadot.io/tcp/30334/p2p/12D3KooWQaV7wMfNVKy2aMz4Lds3TTxgSDyZAUEnbAZMfD8rW3ow", "/dns/kusama-bridge-hub-connect-ew1-0.polkadot.io/tcp/443/wss/p2p/12D3KooWPQQPivrqQ51kRTDc2R1mtqwKT4GGtk2rapkY4FrwHrEp", "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", - "/dns/kusama-bridge-hub-connect-ue4-0.polkadot.io/tcp/443/wss/p2p/12D3KooWMf1sVnJDTkKWtaThqvrgcSPLbfGXttSqbwhM2DJp9BUG", - "/dns/kusama-bridge-hub-connect-ue4-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQaV7wMfNVKy2aMz4Lds3TTxgSDyZAUEnbAZMfD8rW3ow", "/dns/boot.stake.plus/tcp/41333/p2p/12D3KooWBzbs2jsXjG5dipktGPKaUm9XWvkmeJFsEAGkVt946Aa7", "/dns/boot.stake.plus/tcp/41334/wss/p2p/12D3KooWBzbs2jsXjG5dipktGPKaUm9XWvkmeJFsEAGkVt946Aa7", "/dns/boot.metaspan.io/tcp/26032/p2p/12D3KooWKfuSaZrLNz43PDgM4inMALXRHTSh2WBuqQtZRq8zmT1Z", -- GitLab From 8dc41ba49d0a63959b0b5e8b75ebd5d0a1084c07 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 3 Nov 2023 17:09:01 +0200 Subject: [PATCH 432/633] Do not request blocks below the common number when syncing (#2045) This changes `BlockCollection` logic so we don't download block ranges from peers with which we have these ranges already in sync. Improves situation with https://github.com/paritytech/polkadot-sdk/issues/1915. --- substrate/client/network/sync/src/blocks.rs | 232 +++++++++++++++++- .../client/network/sync/src/chain_sync.rs | 38 ++- .../network/sync/src/chain_sync/test.rs | 107 -------- 3 files changed, 255 insertions(+), 122 deletions(-) diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index 240c1ca1f8b..539a8a5d612 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -123,20 +123,36 @@ impl BlockCollection { let first_different = common + >::one(); let count = (count as u32).into(); let (mut range, downloading) = { + // Iterate through the ranges in `self.blocks` looking for a range to download let mut downloading_iter = self.blocks.iter().peekable(); let mut prev: Option<(&NumberFor, &BlockRangeState)> = None; loop { let next = downloading_iter.next(); break match (prev, next) { + // If we are already downloading this range, request it from `max_parallel` + // peers (`max_parallel = 5` by default). + // Do not request already downloading range from peers with common number above + // the range start. (Some((start, &BlockRangeState::Downloading { ref len, downloading })), _) - if downloading < max_parallel => + if downloading < max_parallel && *start >= first_different => (*start..*start + *len, downloading), - (Some((start, r)), Some((next_start, _))) if *start + r.len() < *next_start => - (*start + r.len()..cmp::min(*next_start, *start + r.len() + count), 0), // gap - (Some((start, r)), None) => (*start + r.len()..*start + r.len() + count, 0), /* last range */ - (None, None) => (first_different..first_different + count, 0), /* empty */ + // If there is a gap between ranges requested, download this gap unless the peer + // has common number above the gap start + (Some((start, r)), Some((next_start, _))) + if *start + r.len() < *next_start && + *start + r.len() >= first_different => + (*start + r.len()..cmp::min(*next_start, *start + r.len() + count), 0), + // Download `count` blocks after the last range requested unless the peer + // has common number above this new range + (Some((start, r)), None) if *start + r.len() >= first_different => + (*start + r.len()..*start + r.len() + count, 0), + // If there are no ranges currently requested, download `count` blocks after + // `common` number + (None, None) => (first_different..first_different + count, 0), + // If the first range starts above `common + 1`, download the gap at the start (None, Some((start, _))) if *start > first_different => - (first_different..cmp::min(first_different + count, *start), 0), /* gap at the start */ + (first_different..cmp::min(first_different + count, *start), 0), + // Move on to the next range pair _ => { prev = next; continue @@ -365,10 +381,10 @@ mod test { bc.blocks.insert(114305, BlockRangeState::Complete(blocks)); let peer0 = PeerId::random(); - assert_eq!(bc.needed_blocks(peer0, 128, 10000, 000, 1, 200), Some(1..100)); - assert_eq!(bc.needed_blocks(peer0, 128, 10000, 600, 1, 200), None); // too far ahead + assert_eq!(bc.needed_blocks(peer0, 128, 10000, 0, 1, 200), Some(1..100)); + assert_eq!(bc.needed_blocks(peer0, 128, 10000, 0, 1, 200), None); // too far ahead assert_eq!( - bc.needed_blocks(peer0, 128, 10000, 600, 1, 200000), + bc.needed_blocks(peer0, 128, 10000, 0, 1, 200000), Some(100 + 128..100 + 128 + 128) ); } @@ -431,4 +447,202 @@ mod test { assert!(bc.blocks.is_empty()); assert!(bc.queued_blocks.is_empty()); } + + #[test] + fn downloaded_range_is_requested_from_max_parallel_peers() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + // identical ranges requested from 2 peers + let max_parallel = 2; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + let peer3 = PeerId::random(); + + // common for all peers + let best = 100; + let common = 10; + + assert_eq!( + bc.needed_blocks(peer1, count, best, common, max_parallel, max_ahead), + Some(11..16) + ); + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(11..16) + ); + assert_eq!( + bc.needed_blocks(peer3, count, best, common, max_parallel, max_ahead), + Some(16..21) + ); + } + #[test] + fn downloaded_range_not_requested_from_peers_with_higher_common_number() { + // A peer connects with a common number falling behind our best number + // (either a fork or lagging behind). + // We request a range from this peer starting at its common number + 1. + // Even though we have less than `max_parallel` downloads, we do not request + // this range from peers with a common number above the start of this range. + + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + let max_parallel = 2; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer1_best = 20; + let peer1_common = 10; + + // `peer2` has first different above the start of the range downloaded from `peer1` + let peer2 = PeerId::random(); + let peer2_best = 20; + let peer2_common = 11; // first_different = 12 + + assert_eq!( + bc.needed_blocks(peer1, count, peer1_best, peer1_common, max_parallel, max_ahead), + Some(11..16), + ); + assert_eq!( + bc.needed_blocks(peer2, count, peer2_best, peer2_common, max_parallel, max_ahead), + Some(16..21), + ); + } + + #[test] + fn gap_above_common_number_requested() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + let best = 30; + // We need at least 3 ranges requested to have a gap, so to minimize the number of peers + // set `max_parallel = 1` + let max_parallel = 1; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + let peer3 = PeerId::random(); + + let common = 10; + assert_eq!( + bc.needed_blocks(peer1, count, best, common, max_parallel, max_ahead), + Some(11..16), + ); + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(16..21), + ); + assert_eq!( + bc.needed_blocks(peer3, count, best, common, max_parallel, max_ahead), + Some(21..26), + ); + + // For some reason there is now a gap at 16..21. We just disconnect `peer2`, but it might + // also happen that 16..21 received first and got imported if our best is actually >= 15. + bc.clear_peer_download(&peer2); + + // Some peer connects with common number below the gap. The gap is requested from it. + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(16..21), + ); + } + + #[test] + fn gap_below_common_number_not_requested() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + let best = 30; + // We need at least 3 ranges requested to have a gap, so to minimize the number of peers + // set `max_parallel = 1` + let max_parallel = 1; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + let peer3 = PeerId::random(); + + let common = 10; + assert_eq!( + bc.needed_blocks(peer1, count, best, common, max_parallel, max_ahead), + Some(11..16), + ); + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(16..21), + ); + assert_eq!( + bc.needed_blocks(peer3, count, best, common, max_parallel, max_ahead), + Some(21..26), + ); + + // For some reason there is now a gap at 16..21. We just disconnect `peer2`, but it might + // also happen that 16..21 received first and got imported if our best is actually >= 15. + bc.clear_peer_download(&peer2); + + // Some peer connects with common number above the gap. The gap is not requested from it. + let common = 23; + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(26..31), // not 16..21 + ); + } + + #[test] + fn range_at_the_end_above_common_number_requested() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + let best = 30; + let max_parallel = 1; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + + let common = 10; + assert_eq!( + bc.needed_blocks(peer1, count, best, common, max_parallel, max_ahead), + Some(11..16), + ); + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(16..21), + ); + } + + #[test] + fn range_at_the_end_below_common_number_not_requested() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + + let count = 5; + let best = 30; + let max_parallel = 1; + let max_ahead = 200; + + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + + let common = 10; + assert_eq!( + bc.needed_blocks(peer1, count, best, common, max_parallel, max_ahead), + Some(11..16), + ); + + let common = 20; + assert_eq!( + bc.needed_blocks(peer2, count, best, common, max_parallel, max_ahead), + Some(21..26), // not 16..21 + ); + } } diff --git a/substrate/client/network/sync/src/chain_sync.rs b/substrate/client/network/sync/src/chain_sync.rs index 9cf0080e36a..5721bd59a84 100644 --- a/substrate/client/network/sync/src/chain_sync.rs +++ b/substrate/client/network/sync/src/chain_sync.rs @@ -520,12 +520,15 @@ where Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) }, Ok(BlockStatus::KnownBad) => { - info!("💔 New peer with known bad best block {} ({}).", best_hash, best_number); + info!("💔 New peer {who} with known bad best block {best_hash} ({best_number})."); Err(BadPeer(who, rep::BAD_BLOCK)) }, Ok(BlockStatus::Unknown) => { if best_number.is_zero() { - info!("💔 New peer with unknown genesis hash {} ({}).", best_hash, best_number); + info!( + "💔 New peer {} with unknown genesis hash {} ({}).", + who, best_hash, best_number, + ); return Err(BadPeer(who, rep::GENESIS_MISMATCH)) } @@ -535,7 +538,8 @@ where if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS.into() { debug!( target:LOG_TARGET, - "New peer with unknown best hash {} ({}), assuming common block.", + "New peer {} with unknown best hash {} ({}), assuming common block.", + who, self.best_queued_hash, self.best_queued_number ); @@ -556,7 +560,7 @@ where let (state, req) = if self.best_queued_number.is_zero() { debug!( target:LOG_TARGET, - "New peer with best hash {best_hash} ({best_number}).", + "New peer {who} with best hash {best_hash} ({best_number}).", ); (PeerSyncState::Available, None) @@ -565,7 +569,8 @@ where debug!( target:LOG_TARGET, - "New peer with unknown best hash {} ({}), searching for common ancestor.", + "New peer {} with unknown best hash {} ({}), searching for common ancestor.", + who, best_hash, best_number ); @@ -613,7 +618,7 @@ where Ok(BlockStatus::InChainPruned) => { debug!( target: LOG_TARGET, - "New peer with known best hash {best_hash} ({best_number}).", + "New peer {who} with known best hash {best_hash} ({best_number}).", ); self.peers.insert( who, @@ -848,8 +853,22 @@ where // We've made progress on this chain since the search was started. // Opportunistically set common number to updated number // instead of the one that started the search. + trace!( + target: LOG_TARGET, + "Ancestry search: opportunistically updating peer {} common number from={} => to={}.", + *who, + peer.common_number, + self.best_queued_number, + ); peer.common_number = self.best_queued_number; } else if peer.common_number < *current { + trace!( + target: LOG_TARGET, + "Ancestry search: updating peer {} common number from={} => to={}.", + *who, + peer.common_number, + *current, + ); peer.common_number = *current; } } @@ -1338,6 +1357,13 @@ where // should be kept in that state. if let PeerSyncState::DownloadingJustification(_) = p.state { // We make sure our commmon number is at least something we have. + trace!( + target: LOG_TARGET, + "Keeping peer {} after restart, updating common number from={} => to={} (our best).", + peer_id, + p.common_number, + self.best_queued_number, + ); p.common_number = self.best_queued_number; self.peers.insert(peer_id, p); return None diff --git a/substrate/client/network/sync/src/chain_sync/test.rs b/substrate/client/network/sync/src/chain_sync/test.rs index 6f9fea1b161..23316eaa194 100644 --- a/substrate/client/network/sync/src/chain_sync/test.rs +++ b/substrate/client/network/sync/src/chain_sync/test.rs @@ -245,113 +245,6 @@ fn build_block(client: &mut Arc, at: Option, fork: bool) -> Bl block } -/// This test is a regression test as observed on a real network. -/// -/// The node is connected to multiple peers. Both of these peers are having a best block (1) -/// that is below our best block (3). Now peer 2 announces a fork of block 3 that we will -/// request from peer 2. After importing the fork, peer 2 and then peer 1 will announce block 4. -/// But as peer 1 in our view is still at block 1, we will request block 2 (which we already -/// have) from it. In the meanwhile peer 2 sends us block 4 and 3 and we send another request -/// for block 2 to peer 2. Peer 1 answers with block 2 and then peer 2. This will need to -/// succeed, as we have requested block 2 from both peers. -#[test] -fn do_not_report_peer_on_block_response_for_block_request() { - sp_tracing::try_init_simple(); - - let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); - - let peer_id1 = PeerId::random(); - let peer_id2 = PeerId::random(); - - let mut client2 = client.clone(); - let mut build_block_at = |at, import| { - let mut block_builder = client2.new_block_at(at, Default::default(), false).unwrap(); - // Make sure we generate a different block as fork - block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); - - let block = block_builder.build().unwrap().block; - - if import { - block_on(client2.import(BlockOrigin::Own, block.clone())).unwrap(); - } - - block - }; - - let block1 = build_block(&mut client, None, false); - let block2 = build_block(&mut client, None, false); - let block3 = build_block(&mut client, None, false); - let block3_fork = build_block_at(block2.hash(), false); - - // Add two peers which are on block 1. - sync.new_peer(peer_id1, block1.hash(), 1).unwrap(); - sync.new_peer(peer_id2, block1.hash(), 1).unwrap(); - - // Tell sync that our best block is 3. - sync.update_chain_info(&block3.hash(), 3); - - // There should be no requests. - assert!(sync.block_requests().is_empty()); - - // Let peer2 announce a fork of block 3 - send_block_announce(block3_fork.header().clone(), peer_id2, &mut sync); - - // Import and tell sync that we now have the fork. - block_on(client.import(BlockOrigin::Own, block3_fork.clone())).unwrap(); - sync.update_chain_info(&block3_fork.hash(), 3); - - let block4 = build_block_at(block3_fork.hash(), false); - - // Let peer2 announce block 4 and check that sync wants to get the block. - send_block_announce(block4.header().clone(), peer_id2, &mut sync); - - let request = get_block_request(&mut sync, FromBlock::Hash(block4.hash()), 2, &peer_id2); - - // Peer1 announces the same block, but as the common block is still `1`, sync will request - // block 2 again. - send_block_announce(block4.header().clone(), peer_id1, &mut sync); - - let request2 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id1); - - let response = create_block_response(vec![block4.clone(), block3_fork.clone()]); - let res = sync.on_block_data(&peer_id2, Some(request), response).unwrap(); - - // 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) - ); - - let request3 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id2); - - let response = create_block_response(vec![block2.clone()]); - let res = sync.on_block_data(&peer_id1, Some(request2), response).unwrap(); - assert!(matches!( - res, - 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(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) - ); -} - fn unwrap_from_block_number(from: FromBlock) -> u64 { if let FromBlock::Number(from) = from { from -- GitLab From d512b3f00bca98ebf300608bf841e0558a82d7ad Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 3 Nov 2023 17:10:24 +0200 Subject: [PATCH 433/633] Convert `SyncingEngine::run` to use `tokio::select!` instead of polling (#2132) --- substrate/client/network/sync/Cargo.toml | 1 + .../sync/src/block_announce_validator.rs | 12 +- substrate/client/network/sync/src/engine.rs | 403 +++++++++--------- .../network/sync/src/pending_responses.rs | 33 +- 4 files changed, 235 insertions(+), 214 deletions(-) diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index 39312cc4b32..a1ea39a852f 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -30,6 +30,7 @@ schnellru = "0.2.1" smallvec = "1.11.0" thiserror = "1.0" tokio-stream = "0.1.14" +tokio = { version = "1.32.0", features = ["time", "macros"] } 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/block_announce_validator.rs b/substrate/client/network/sync/src/block_announce_validator.rs index f083f9e29e4..961b581cddc 100644 --- a/substrate/client/network/sync/src/block_announce_validator.rs +++ b/substrate/client/network/sync/src/block_announce_validator.rs @@ -16,10 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! `BlockAnnounceValidator` is responsible for async validation of block announcements. +//! [`BlockAnnounceValidator`] is responsible for async validation of block announcements. +//! [`Stream`] implemented by [`BlockAnnounceValidator`] never terminates. use crate::futures_stream::FuturesStream; -use futures::{Future, FutureExt, Stream, StreamExt}; +use futures::{stream::FusedStream, Future, FutureExt, Stream, StreamExt}; use libp2p::PeerId; use log::{debug, error, trace, warn}; use sc_network_common::sync::message::BlockAnnounce; @@ -300,6 +301,13 @@ impl Stream for BlockAnnounceValidator { } } +// As [`BlockAnnounceValidator`] never terminates, we can easily implement [`FusedStream`] for it. +impl FusedStream for BlockAnnounceValidator { + fn is_terminated(&self) -> bool { + false + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 0f689742bc5..02a0dc2e915 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -47,7 +47,6 @@ use futures::{ future::{BoxFuture, Fuse}, FutureExt, StreamExt, }; -use futures_timer::Delay; use libp2p::{request_response::OutboundFailure, PeerId}; use log::{debug, trace}; use prometheus_endpoint::{ @@ -56,6 +55,7 @@ use prometheus_endpoint::{ }; use prost::Message; use schnellru::{ByLength, LruMap}; +use tokio::time::{Interval, MissedTickBehavior}; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::ImportQueueService; @@ -85,7 +85,6 @@ use std::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, }, - task::Poll, time::{Duration, Instant}, }; @@ -254,7 +253,7 @@ pub struct SyncingEngine { service_rx: TracingUnboundedReceiver>, /// Channel for receiving inbound connections from `Protocol`. - rx: sc_utils::mpsc::TracingUnboundedReceiver>, + sync_events_rx: sc_utils::mpsc::TracingUnboundedReceiver>, /// Assigned roles. roles: Roles, @@ -266,7 +265,7 @@ pub struct SyncingEngine { event_streams: Vec>, /// Interval at which we call `tick`. - tick_timeout: Delay, + tick_timeout: Interval, /// All connected peers. Contains both full and light node peers. peers: HashMap>, @@ -304,7 +303,7 @@ pub struct SyncingEngine { boot_node_ids: HashSet, /// A channel to get target block header if we skip over proofs downloading during warp sync. - warp_sync_target_block_header_rx: + warp_sync_target_block_header_rx_fused: Fuse>>, /// Protocol name used for block announcements @@ -363,7 +362,7 @@ where block_downloader: Arc>, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - rx: sc_utils::mpsc::TracingUnboundedReceiver>, + sync_events_rx: sc_utils::mpsc::TracingUnboundedReceiver>, ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = net_config.network_config.sync_mode; let max_parallel_downloads = net_config.network_config.max_parallel_downloads; @@ -436,7 +435,7 @@ where // Make sure polling of the target block channel is a no-op if there is no block to // retrieve. - let warp_sync_target_block_header_rx = warp_sync_target_block_header_rx + let warp_sync_target_block_header_rx_fused = warp_sync_target_block_header_rx .map_or(futures::future::pending().boxed().fuse(), |rx| rx.boxed().fuse()); let block_announce_config = Self::get_block_announce_proto_config( @@ -478,6 +477,12 @@ where let max_out_peers = net_config.network_config.default_peers_set.out_peers; let max_in_peers = (max_full_peers - max_out_peers) as usize; + let tick_timeout = { + let mut interval = tokio::time::interval(TICK_TIMEOUT); + interval.set_missed_tick_behavior(MissedTickBehavior::Delay); + interval + }; + Ok(( Self { roles, @@ -493,11 +498,11 @@ where num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), service_rx, - rx, + sync_events_rx, genesis_hash, important_peers, default_peers_set_no_slot_connected_peers: HashSet::new(), - warp_sync_target_block_header_rx, + warp_sync_target_block_header_rx_fused, boot_node_ids, default_peers_set_no_slot_peers, default_peers_set_num_full, @@ -505,7 +510,7 @@ where num_in_peers: 0usize, max_in_peers, event_streams: Vec::new(), - tick_timeout: Delay::new(TICK_TIMEOUT), + tick_timeout, syncing_started: None, last_notification_io: Instant::now(), metrics: if let Some(r) = metrics_registry { @@ -691,230 +696,222 @@ where self.syncing_started = Some(Instant::now()); loop { - futures::future::poll_fn(|cx| self.poll(cx)).await; + tokio::select! { + _ = self.tick_timeout.tick() => self.perform_periodic_actions(), + command = self.service_rx.select_next_some() => + self.process_service_command(command), + sync_event = self.sync_events_rx.select_next_some() => + self.process_sync_event(sync_event), + warp_target_block_header = &mut self.warp_sync_target_block_header_rx_fused => + self.pass_warp_sync_target_block_header(warp_target_block_header), + response_event = self.pending_responses.select_next_some() => + self.process_response_event(response_event), + validation_result = self.block_announce_validator.select_next_some() => + self.process_block_announce_validation_result(validation_result), + } + + // Update atomic variables + self.num_connected.store(self.peers.len(), Ordering::Relaxed); + self.is_major_syncing + .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); + + // Send outbound requests on `ChanSync`'s behalf. + self.send_chain_sync_requests(); } } - pub fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { - self.num_connected.store(self.peers.len(), Ordering::Relaxed); - self.is_major_syncing - .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); - - while let Poll::Ready(()) = self.tick_timeout.poll_unpin(cx) { - self.report_metrics(); - self.tick_timeout.reset(TICK_TIMEOUT); - - // if `SyncingEngine` has just started, don't evict seemingly inactive peers right away - // as they may not have produced blocks not because they've disconnected but because - // they're still waiting to receive enough relaychain blocks to start producing blocks. - if let Some(started) = self.syncing_started { - if started.elapsed() < INITIAL_EVICTION_WAIT_PERIOD { - continue - } + fn perform_periodic_actions(&mut self) { + self.report_metrics(); - self.syncing_started = None; - self.last_notification_io = Instant::now(); + // if `SyncingEngine` has just started, don't evict seemingly inactive peers right away + // as they may not have produced blocks not because they've disconnected but because + // they're still waiting to receive enough relaychain blocks to start producing blocks. + if let Some(started) = self.syncing_started { + if started.elapsed() < INITIAL_EVICTION_WAIT_PERIOD { + return } - // if syncing hasn't sent or received any blocks within `INACTIVITY_EVICT_THRESHOLD`, - // it means the local node has stalled and is connected to peers who either don't - // consider it connected or are also all stalled. In order to unstall the node, - // disconnect all peers and allow `ProtocolController` to establish new connections. - if self.last_notification_io.elapsed() > INACTIVITY_EVICT_THRESHOLD { - log::debug!( - target: LOG_TARGET, - "syncing has halted due to inactivity, evicting all peers", - ); + self.syncing_started = None; + self.last_notification_io = Instant::now(); + } - for peer in self.peers.keys() { - self.network_service.report_peer(*peer, rep::INACTIVE_SUBSTREAM); - self.network_service - .disconnect_peer(*peer, self.block_announce_protocol_name.clone()); - } + // if syncing hasn't sent or received any blocks within `INACTIVITY_EVICT_THRESHOLD`, + // it means the local node has stalled and is connected to peers who either don't + // consider it connected or are also all stalled. In order to unstall the node, + // disconnect all peers and allow `ProtocolController` to establish new connections. + if self.last_notification_io.elapsed() > INACTIVITY_EVICT_THRESHOLD { + log::debug!( + target: LOG_TARGET, + "syncing has halted due to inactivity, evicting all peers", + ); - // after all the peers have been evicted, start timer again to prevent evicting - // new peers that join after the old peer have been evicted - self.last_notification_io = Instant::now(); + for peer in self.peers.keys() { + self.network_service.report_peer(*peer, rep::INACTIVE_SUBSTREAM); + self.network_service + .disconnect_peer(*peer, self.block_announce_protocol_name.clone()); } + + // after all the peers have been evicted, start timer again to prevent evicting + // new peers that join after the old peer have been evicted + self.last_notification_io = Instant::now(); } + } - while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { - match event { - ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { - self.chain_sync.set_sync_fork_request(peers, &hash, number); - }, - ToServiceCommand::EventStream(tx) => self.event_streams.push(tx), - ToServiceCommand::RequestJustification(hash, number) => - self.chain_sync.request_justification(&hash, number), - ToServiceCommand::ClearJustificationRequests => - self.chain_sync.clear_justification_requests(), - ToServiceCommand::BlocksProcessed(imported, count, results) => { - for result in self.chain_sync.on_blocks_processed(imported, count, results) { - match result { - 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); - }, + fn process_service_command(&mut self, command: ToServiceCommand) { + match command { + ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { + self.chain_sync.set_sync_fork_request(peers, &hash, number); + }, + ToServiceCommand::EventStream(tx) => self.event_streams.push(tx), + ToServiceCommand::RequestJustification(hash, number) => + self.chain_sync.request_justification(&hash, number), + ToServiceCommand::ClearJustificationRequests => + self.chain_sync.clear_justification_requests(), + ToServiceCommand::BlocksProcessed(imported, count, results) => { + for result in self.chain_sync.on_blocks_processed(imported, count, results) { + match result { + 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); }, - Err(BadPeer(peer_id, repu)) => { + BlockRequestAction::RemoveStale { peer_id } => { 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) }, - } - } - }, - ToServiceCommand::JustificationImported(peer_id, hash, number, success) => { - self.chain_sync.on_justification_import(hash, number, success); - if !success { - log::info!( - target: LOG_TARGET, - "💔 Invalid justification provided by {peer_id} for #{hash}", - ); - self.network_service - .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer( - peer_id, - ReputationChange::new_fatal("Invalid justification"), - ); + }, + 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) + }, } - }, - ToServiceCommand::AnnounceBlock(hash, data) => self.announce_block(hash, data), - ToServiceCommand::NewBestBlockImported(hash, number) => - self.new_best_block_imported(hash, number), - ToServiceCommand::Status(tx) => { - let mut status = self.chain_sync.status(); - status.num_connected_peers = self.peers.len() as u32; - let _ = tx.send(status); - }, - ToServiceCommand::NumActivePeers(tx) => { - let _ = tx.send(self.num_active_peers()); - }, - ToServiceCommand::SyncState(tx) => { - let _ = tx.send(self.chain_sync.status()); - }, - ToServiceCommand::BestSeenBlock(tx) => { - let _ = tx.send(self.chain_sync.status().best_seen_block); - }, - ToServiceCommand::NumSyncPeers(tx) => { - let _ = tx.send(self.chain_sync.status().num_peers); - }, - ToServiceCommand::NumQueuedBlocks(tx) => { - let _ = tx.send(self.chain_sync.status().queued_blocks); - }, - ToServiceCommand::NumDownloadedBlocks(tx) => { - let _ = tx.send(self.chain_sync.num_downloaded_blocks()); - }, - ToServiceCommand::NumSyncRequests(tx) => { - let _ = tx.send(self.chain_sync.num_sync_requests()); - }, - ToServiceCommand::PeersInfo(tx) => { - let peers_info = self - .peers - .iter() - .map(|(peer_id, peer)| (*peer_id, peer.info.clone())) - .collect(); - let _ = tx.send(peers_info); - }, - ToServiceCommand::OnBlockFinalized(hash, header) => - self.chain_sync.on_block_finalized(&hash, *header.number()), - } + } + }, + ToServiceCommand::JustificationImported(peer_id, hash, number, success) => { + self.chain_sync.on_justification_import(hash, number, success); + if !success { + log::info!( + target: LOG_TARGET, + "💔 Invalid justification provided by {peer_id} for #{hash}", + ); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + self.network_service + .report_peer(peer_id, ReputationChange::new_fatal("Invalid justification")); + } + }, + ToServiceCommand::AnnounceBlock(hash, data) => self.announce_block(hash, data), + ToServiceCommand::NewBestBlockImported(hash, number) => + self.new_best_block_imported(hash, number), + ToServiceCommand::Status(tx) => { + let mut status = self.chain_sync.status(); + status.num_connected_peers = self.peers.len() as u32; + let _ = tx.send(status); + }, + ToServiceCommand::NumActivePeers(tx) => { + let _ = tx.send(self.num_active_peers()); + }, + ToServiceCommand::SyncState(tx) => { + let _ = tx.send(self.chain_sync.status()); + }, + ToServiceCommand::BestSeenBlock(tx) => { + let _ = tx.send(self.chain_sync.status().best_seen_block); + }, + ToServiceCommand::NumSyncPeers(tx) => { + let _ = tx.send(self.chain_sync.status().num_peers); + }, + ToServiceCommand::NumQueuedBlocks(tx) => { + let _ = tx.send(self.chain_sync.status().queued_blocks); + }, + ToServiceCommand::NumDownloadedBlocks(tx) => { + let _ = tx.send(self.chain_sync.num_downloaded_blocks()); + }, + ToServiceCommand::NumSyncRequests(tx) => { + let _ = tx.send(self.chain_sync.num_sync_requests()); + }, + ToServiceCommand::PeersInfo(tx) => { + let peers_info = self + .peers + .iter() + .map(|(peer_id, peer)| (*peer_id, peer.info.clone())) + .collect(); + let _ = tx.send(peers_info); + }, + ToServiceCommand::OnBlockFinalized(hash, header) => + self.chain_sync.on_block_finalized(&hash, *header.number()), } + } - while let Poll::Ready(Some(event)) = self.rx.poll_next_unpin(cx) { - match event { - sc_network::SyncEvent::NotificationStreamOpened { - remote, - received_handshake, - sink, - inbound, - tx, - } => match self.on_sync_peer_connected(remote, &received_handshake, sink, inbound) { - Ok(()) => { - let _ = tx.send(true); - }, - Err(()) => { - log::debug!( - target: LOG_TARGET, - "Failed to register peer {remote:?}: {received_handshake:?}", - ); - let _ = tx.send(false); - }, + fn process_sync_event(&mut self, event: sc_network::SyncEvent) { + match event { + sc_network::SyncEvent::NotificationStreamOpened { + remote, + received_handshake, + sink, + inbound, + tx, + } => match self.on_sync_peer_connected(remote, &received_handshake, sink, inbound) { + Ok(()) => { + let _ = tx.send(true); }, - sc_network::SyncEvent::NotificationStreamClosed { remote } => { - if self.on_sync_peer_disconnected(remote).is_err() { - log::trace!( - target: LOG_TARGET, - "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", - remote - ); - } + Err(()) => { + log::debug!( + target: LOG_TARGET, + "Failed to register peer {remote:?}: {received_handshake:?}", + ); + let _ = tx.send(false); }, - sc_network::SyncEvent::NotificationsReceived { remote, messages } => { - for message in messages { - if self.peers.contains_key(&remote) { - if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { - self.last_notification_io = Instant::now(); - self.push_block_announce_validation(remote, announce); - } else { - log::warn!(target: "sub-libp2p", "Failed to decode block announce"); - } + }, + sc_network::SyncEvent::NotificationStreamClosed { remote } => { + if self.on_sync_peer_disconnected(remote).is_err() { + log::trace!( + target: LOG_TARGET, + "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", + remote + ); + } + }, + sc_network::SyncEvent::NotificationsReceived { remote, messages } => { + for message in messages { + if self.peers.contains_key(&remote) { + if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { + self.last_notification_io = Instant::now(); + self.push_block_announce_validation(remote, announce); } else { - log::trace!( - target: LOG_TARGET, - "Received sync for peer earlier refused by sync layer: {remote}", - ); + log::warn!(target: "sub-libp2p", "Failed to decode block announce"); } + } else { + log::trace!( + target: LOG_TARGET, + "Received sync for peer earlier refused by sync layer: {remote}", + ); } - }, - sc_network::SyncEvent::NotificationSinkReplaced { remote, sink } => { - if let Some(peer) = self.peers.get_mut(&remote) { - peer.sink = sink; - } - }, - } + } + }, + sc_network::SyncEvent::NotificationSinkReplaced { remote, sink } => { + if let Some(peer) = self.peers.get_mut(&remote) { + peer.sink = sink; + } + }, } + } - // Retreive warp sync target block header just before polling `ChainSync` - // to make progress as soon as we receive it. - match self.warp_sync_target_block_header_rx.poll_unpin(cx) { - Poll::Ready(Ok(target)) => { - self.chain_sync.set_warp_sync_target_block(target); + fn pass_warp_sync_target_block_header(&mut self, header: Result) { + match header { + Ok(header) => { + self.chain_sync.set_warp_sync_target_block(header); }, - Poll::Ready(Err(err)) => { + Err(err) => { log::error!( target: LOG_TARGET, "Failed to get target block for warp sync. Error: {err:?}", ); }, - Poll::Pending => {}, } - - // 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 - // finished right after it is queued, the resulting block request (if any) can be sent - // right away. - while let Poll::Ready(Some(result)) = self.block_announce_validator.poll_next_unpin(cx) { - self.process_block_announce_validation_result(result); - } - - Poll::Pending } /// Called by peer when it is disconnecting. diff --git a/substrate/client/network/sync/src/pending_responses.rs b/substrate/client/network/sync/src/pending_responses.rs index 9e2fd5cfd67..55308dfc1ea 100644 --- a/substrate/client/network/sync/src/pending_responses.rs +++ b/substrate/client/network/sync/src/pending_responses.rs @@ -17,20 +17,20 @@ // along with this program. If not, see . //! [`PendingResponses`] is responsible for keeping track of pending responses and -//! polling them. +//! polling them. [`Stream`] implemented by [`PendingResponses`] never terminates. use crate::types::PeerRequest; use futures::{ channel::oneshot, future::BoxFuture, - stream::{BoxStream, Stream}, + stream::{BoxStream, FusedStream, Stream}, FutureExt, StreamExt, }; use libp2p::PeerId; use log::error; use sc_network::request_responses::RequestFailure; use sp_runtime::traits::Block as BlockT; -use std::task::{Context, Poll}; +use std::task::{Context, Poll, Waker}; use tokio_stream::StreamMap; /// Log target for this file. @@ -53,11 +53,13 @@ pub(crate) struct ResponseEvent { pub(crate) struct PendingResponses { /// Pending responses pending_responses: StreamMap, ResponseResult)>>, + /// Waker to implement never terminating stream + waker: Option, } impl PendingResponses { pub fn new() -> Self { - Self { pending_responses: StreamMap::new() } + Self { pending_responses: StreamMap::new(), waker: None } } pub fn insert( @@ -82,6 +84,10 @@ impl PendingResponses { ); debug_assert!(false); } + + if let Some(waker) = self.waker.take() { + waker.wake(); + } } pub fn remove(&mut self, peer_id: &PeerId) -> bool { @@ -93,8 +99,6 @@ impl PendingResponses { } } -impl Unpin for PendingResponses {} - impl Stream for PendingResponses { type Item = ResponseEvent; @@ -102,8 +106,8 @@ impl Stream for PendingResponses { 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))) => { + match self.pending_responses.poll_next_unpin(cx) { + Poll::Ready(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. @@ -111,7 +115,18 @@ impl Stream for PendingResponses { Poll::Ready(Some(ResponseEvent { peer_id, request, response })) }, - None => Poll::Ready(None), + Poll::Ready(None) | Poll::Pending => { + self.waker = Some(cx.waker().clone()); + + Poll::Pending + }, } } } + +// As [`PendingResponses`] never terminates, we can easily implement [`FusedStream`] for it. +impl FusedStream for PendingResponses { + fn is_terminated(&self) -> bool { + false + } +} -- GitLab From 8cfbee706dab7bf55fe6c9fb3a8bfbe29e6776aa Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Fri, 3 Nov 2023 16:36:48 +0100 Subject: [PATCH 434/633] Add deprecation checklist document for Substrate (#1583) fixes https://github.com/paritytech/polkadot-sdk/issues/182 This PR adds a document with recommendations of how deprecations should be handled. Initiated within FRAME, this checklist could be extended to the rest of the repo. I want to quote here a comment from @kianenigma that summarizes the spirit of this new document: > I would see it as a guideline of "what an extensive deprecation process looks like". As the author of a PR, you should match this against your "common sense" and see if it is needed or not. Someone else can nudge you to "hey, this is an important PR, you should go through the deprecation process". > > For some trivial things, all the steps might be an overkill. --------- Co-authored-by: Francisco Aguirre --- docs/DEPRECATION_CHECKLIST.md | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 docs/DEPRECATION_CHECKLIST.md diff --git a/docs/DEPRECATION_CHECKLIST.md b/docs/DEPRECATION_CHECKLIST.md new file mode 100644 index 00000000000..fccf93d2273 --- /dev/null +++ b/docs/DEPRECATION_CHECKLIST.md @@ -0,0 +1,79 @@ +# Deprecation Checklist + +This deprecation checklist makes sense while we don’t use [SemVer](https://semver.org/). +After that, this document will most likely change. +As deprecation and removal of existing code can happen on any release, we need to be mindful that external builders +could be impacted by the changes we make. +The deprecation checklist tries to mitigate this impact, while still keeping the developer experience, the DevEx, as +smooth as possible. + +To start a deprecation process, a new issue with the label `T15-deprecation` needs to be created for correct tracking. +Then these are the actions to take: + +## Hard deprecate by adding a warning message + +The warning message shall include a removal month and year, which is suggested to be 6 months after the deprecation +notice is released. +This means that the code will be removed in a release within that month (or after, but never before). Please use this +template, doing so makes it easy to search through the code base: + +```rust +#[deprecated(note = "[DEPRECATED] will be removed after [DATE]. [ALTERNATIVE]")] +``` +`[ALTERNATIVE]` won't always be possible but offer it if it is. + +E.g. +```rust +#[deprecated(note = "`GenesisConfig` will be removed after December 2023. Use `RuntimeGenesisConfig` instead.")] +``` + +Some pieces of code cannot be labeled as deprecated, like [reexports](https://github.com/rust-lang/rust/issues/30827) +or [dispatchables](https://github.com/paritytech/polkadot-sdk/issues/182#issuecomment-1691684159), for instance. +In cases like that we can only make a visible enough comment, and make sure that we [announce the deprecation properly](#announce-the-deprecation-and-removal). + +## Remove usage of the deprecated code in the code base + +Just make sure that we are not using the deprecated code ourselves. +If you added the deprecation warning from the previous step, this can be done by making sure that warning is not shown +when building the code. + +## Update examples and tutorials + +Make sure that the rust docs are updated. +We also need [https://docs.substrate.io/](https://docs.substrate.io/) to be updated accordingly. The repo behind it is +[https://github.com/substrate-developer-hub/substrate-docs](https://github.com/substrate-developer-hub/substrate-docs). + +## Announce the deprecation and removal + +**At minimum they should be noted in the release log.** Please see how to document a PR [here](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#documentation). +There you can give instructions based on the audience and tell them what they need to do to upgrade the code. + +Some breaking changes have a bigger impact than others. When the impact is big the release note is not enough, though +it should still be the primary place for the notice. You can link back to the changelog files in other channels if you +want to announce it somewhere else. +Make sure you are as loud as you need to be for the magnitude of the breaking change. + +## Removal version is planned + +Depending on the removal date indicated in the deprecation warning in the [first step](#hard-deprecate-by-adding-a-warning-message), +the nature and the importance of the change, it might make sense to coordinate the release with other developers and +with the Release team. + +## Deprecated code is removed + +The deprecated code finally gets removed. +Don’t forget to [announce this accordingly](#announce-the-deprecation-and-removal). + +✅ In order to not forget any of these steps, consider using this template in your deprecation issue: + +```markdown +### Tasks + +- [ ] Deprecate code by adding a warning message +- [ ] Remove usage of the deprecated code in the code base +- [ ] Update examples and tutorials +- [ ] Announce code deprecation +- [ ] Plan removal version +- [ ] Announce code removal +- [ ] Remove deprecated code +``` -- GitLab From cd2d5d2579f12dff6d6999b5c9e1f011dcd19a36 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:48:41 +0100 Subject: [PATCH 435/633] Tracking/limiting memory allocator (#1192) --- Cargo.lock | 9 + polkadot/node/core/pvf/common/src/error.rs | 27 +- .../node/core/pvf/common/src/executor_intf.rs | 27 +- polkadot/node/core/pvf/common/src/prepare.rs | 4 +- .../node/core/pvf/prepare-worker/Cargo.toml | 13 + .../benches/prepare_rococo_runtime.rs | 65 +++++ .../pvf/prepare-worker/src/executor_intf.rs | 42 --- .../node/core/pvf/prepare-worker/src/lib.rs | 93 ++++++- polkadot/node/core/pvf/src/metrics.rs | 20 ++ polkadot/node/core/pvf/src/prepare/pool.rs | 14 + .../node/core/pvf/src/prepare/worker_intf.rs | 3 + polkadot/node/core/pvf/src/testing.rs | 2 +- polkadot/node/core/pvf/tests/it/adder.rs | 2 + polkadot/node/core/pvf/tests/it/main.rs | 44 +++- polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/tracking-allocator/Cargo.toml | 6 + polkadot/node/tracking-allocator/src/lib.rs | 242 ++++++++++++++++++ polkadot/primitives/src/v6/executor_params.rs | 10 + polkadot/src/main.rs | 2 +- 19 files changed, 569 insertions(+), 58 deletions(-) create mode 100644 polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs delete mode 100644 polkadot/node/core/pvf/prepare-worker/src/executor_intf.rs create mode 100644 polkadot/node/tracking-allocator/Cargo.toml create mode 100644 polkadot/node/tracking-allocator/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7d9e4bf725c..ccd410f1415 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12421,15 +12421,20 @@ name = "polkadot-node-core-pvf-prepare-worker" version = "1.0.0" dependencies = [ "cfg-if", + "criterion 0.4.0", "libc", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-primitives", "rayon", + "rococo-runtime", "sc-executor-common", "sc-executor-wasmtime", + "sp-maybe-compressed-blob", "tikv-jemalloc-ctl", + "tikv-jemallocator", "tracing-gum", + "tracking-allocator", ] [[package]] @@ -19442,6 +19447,10 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracking-allocator" +version = "1.0.0" + [[package]] name = "trie-bench" version = "0.38.0" diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 6fdd06057c8..82b56562d8c 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -23,27 +23,36 @@ use std::fmt; pub type PrepareResult = Result; /// An error that occurred during the prepare part of the PVF pipeline. +// Codec indexes are intended to stabilize pre-encoded payloads (see `OOM_PAYLOAD` below) #[derive(Debug, Clone, Encode, Decode)] pub enum PrepareError { /// During the prevalidation stage of preparation an issue was found with the PVF. + #[codec(index = 0)] Prevalidation(String), /// Compilation failed for the given PVF. + #[codec(index = 1)] Preparation(String), /// Instantiation of the WASM module instance failed. + #[codec(index = 2)] RuntimeConstruction(String), /// An unexpected panic has occurred in the preparation worker. + #[codec(index = 3)] Panic(String), /// Failed to prepare the PVF due to the time limit. + #[codec(index = 4)] TimedOut, /// An IO error occurred. This state is reported by either the validation host or by the /// worker. + #[codec(index = 5)] IoErr(String), /// The temporary file for the artifact could not be created at the given cache path. This /// state is reported by the validation host (not by the worker). + #[codec(index = 6)] CreateTmpFileErr(String), /// 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). + #[codec(index = 7)] RenameTmpFileErr { err: String, // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible @@ -51,12 +60,19 @@ pub enum PrepareError { src: Option, dest: Option, }, + /// Memory limit reached + #[codec(index = 8)] + OutOfMemory, /// 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). + #[codec(index = 9)] ClearWorkerDir(String), } +/// Pre-encoded length-prefixed `PrepareResult::Err(PrepareError::OutOfMemory)` +pub const OOM_PAYLOAD: &[u8] = b"\x02\x00\x00\x00\x00\x00\x00\x00\x01\x08"; + impl PrepareError { /// Returns whether this is a deterministic error, i.e. one that should trigger reliably. Those /// errors depend on the PVF itself and the sc-executor/wasmtime logic. @@ -67,7 +83,7 @@ impl PrepareError { pub fn is_deterministic(&self) -> bool { use PrepareError::*; match self { - Prevalidation(_) | Preparation(_) | Panic(_) => true, + Prevalidation(_) | Preparation(_) | Panic(_) | OutOfMemory => true, TimedOut | IoErr(_) | CreateTmpFileErr(_) | @@ -92,6 +108,7 @@ impl fmt::Display for PrepareError { CreateTmpFileErr(err) => write!(f, "prepare: error creating tmp file: {}", err), RenameTmpFileErr { err, src, dest } => write!(f, "prepare: error renaming tmp file ({:?} -> {:?}): {}", src, dest, err), + OutOfMemory => write!(f, "prepare: out of memory"), ClearWorkerDir(err) => write!(f, "prepare: error clearing worker cache: {}", err), } } @@ -147,3 +164,11 @@ impl fmt::Display for InternalValidationError { } } } + +#[test] +fn pre_encoded_payloads() { + let oom_enc = PrepareResult::Err(PrepareError::OutOfMemory).encode(); + let mut oom_payload = oom_enc.len().to_le_bytes().to_vec(); + oom_payload.extend(oom_enc); + assert_eq!(oom_payload, OOM_PAYLOAD); +} diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 58d2a90371c..3a1d3ac1ba0 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_intf.rs @@ -166,15 +166,36 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result stack_limit.logical_max = *slm, ExecutorParam::StackNativeMax(snm) => stack_limit.native_stack_max = *snm, ExecutorParam::WasmExtBulkMemory => sem.wasm_bulk_memory = true, - // TODO: Not implemented yet; . - ExecutorParam::PrecheckingMaxMemory(_) => (), - ExecutorParam::PvfPrepTimeout(_, _) | ExecutorParam::PvfExecTimeout(_, _) => (), /* Not used here */ + ExecutorParam::PrecheckingMaxMemory(_) | + ExecutorParam::PvfPrepTimeout(_, _) | + ExecutorParam::PvfExecTimeout(_, _) => (), /* Not used here */ } } sem.deterministic_stack_limit = Some(stack_limit); Ok(sem) } +/// Runs the prevalidation on the given code. Returns a [`RuntimeBlob`] if it succeeds. +pub fn prevalidate(code: &[u8]) -> Result { + let blob = RuntimeBlob::new(code)?; + // It's assumed this function will take care of any prevalidation logic + // that needs to be done. + // + // Do nothing for now. + Ok(blob) +} + +/// Runs preparation on the given runtime blob. If successful, it returns a serialized compiled +/// artifact which can then be used to pass into `Executor::execute` after writing it to the disk. +pub fn prepare( + blob: RuntimeBlob, + executor_params: &ExecutorParams, +) -> Result, sc_executor_common::error::WasmError> { + let semantics = params_to_wasmtime_semantics(executor_params) + .map_err(|e| sc_executor_common::error::WasmError::Other(e))?; + sc_executor_wasmtime::prepare_runtime_artifact(blob, &semantics) +} + /// 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/prepare.rs b/polkadot/node/core/pvf/common/src/prepare.rs index c205eddfb8b..4436ebe4861 100644 --- a/polkadot/node/core/pvf/common/src/prepare.rs +++ b/polkadot/node/core/pvf/common/src/prepare.rs @@ -29,12 +29,14 @@ pub struct PrepareStats { /// supported by the OS, `ru_maxrss`. #[derive(Clone, Debug, Default, Encode, Decode)] pub struct MemoryStats { - /// Memory stats from `tikv_jemalloc_ctl`. + /// Memory stats from `tikv_jemalloc_ctl`, polling-based and not very precise. #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] pub memory_tracker_stats: Option, /// `ru_maxrss` from `getrusage`. `None` if an error occurred. #[cfg(target_os = "linux")] pub max_rss: Option, + /// Peak allocation in bytes measured by tracking allocator + pub peak_tracked_alloc: u64, } /// Statistics of collected memory metrics. diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index e5a08f8a153..dae88afc555 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -11,7 +11,9 @@ cfg-if = "1.0" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" rayon = "1.5.1" +tracking-allocator = { path = "../../../tracking-allocator" } tikv-jemalloc-ctl = { version = "0.5.0", optional = true } +tikv-jemallocator = { version = "0.5.0", optional = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -22,11 +24,22 @@ sc-executor-common = { path = "../../../../../substrate/client/executor/common" sc-executor-wasmtime = { path = "../../../../../substrate/client/executor/wasmtime" } [target.'cfg(target_os = "linux")'.dependencies] +tikv-jemallocator = "0.5.0" tikv-jemalloc-ctl = "0.5.0" [features] builder = [] jemalloc-allocator = [ "dep:tikv-jemalloc-ctl", + "dep:tikv-jemallocator", "polkadot-node-core-pvf-common/jemalloc-allocator", ] + +[dev-dependencies] +criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } +rococo-runtime = { path = "../../../../runtime/rococo" } +sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } + +[[bench]] +name = "prepare_rococo_runtime" +harness = false diff --git a/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs new file mode 100644 index 00000000000..ba2568cd80c --- /dev/null +++ b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs @@ -0,0 +1,65 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use criterion::{criterion_group, criterion_main, Criterion, SamplingMode}; +use polkadot_node_core_pvf_common::{ + executor_intf::{prepare, prevalidate}, + prepare::PrepareJobKind, + pvf::PvfPrepData, +}; +use polkadot_primitives::ExecutorParams; +use std::time::Duration; + +fn do_prepare_runtime(pvf: PvfPrepData) { + let blob = match prevalidate(&pvf.code()) { + Err(err) => panic!("{:?}", err), + Ok(b) => b, + }; + + match prepare(blob, &pvf.executor_params()) { + Ok(_) => (), + Err(err) => panic!("{:?}", err), + } +} + +fn prepare_rococo_runtime(c: &mut Criterion) { + let blob = rococo_runtime::WASM_BINARY.unwrap(); + let pvf = match sp_maybe_compressed_blob::decompress(&blob, 64 * 1024 * 1024) { + Ok(code) => PvfPrepData::from_code( + code.into_owned(), + ExecutorParams::default(), + Duration::from_secs(360), + PrepareJobKind::Compilation, + ), + Err(e) => { + panic!("Cannot decompress blob: {:?}", e); + }, + }; + + let mut group = c.benchmark_group("rococo"); + group.sampling_mode(SamplingMode::Flat); + group.sample_size(20); + group.measurement_time(Duration::from_secs(240)); + group.bench_function("prepare Rococo runtime", |b| { + // `PvfPrepData` is designed to be cheap to clone, so cloning shouldn't affect the + // benchmark accuracy + b.iter(|| do_prepare_runtime(pvf.clone())) + }); + group.finish(); +} + +criterion_group!(preparation, prepare_rococo_runtime); +criterion_main!(preparation); diff --git a/polkadot/node/core/pvf/prepare-worker/src/executor_intf.rs b/polkadot/node/core/pvf/prepare-worker/src/executor_intf.rs deleted file mode 100644 index 1f88f6a6dd6..00000000000 --- a/polkadot/node/core/pvf/prepare-worker/src/executor_intf.rs +++ /dev/null @@ -1,42 +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 . - -//! Interface to the Substrate Executor - -use polkadot_node_core_pvf_common::executor_intf::params_to_wasmtime_semantics; -use polkadot_primitives::ExecutorParams; -use sc_executor_common::runtime_blob::RuntimeBlob; - -/// Runs the prevalidation on the given code. Returns a [`RuntimeBlob`] if it succeeds. -pub fn prevalidate(code: &[u8]) -> Result { - let blob = RuntimeBlob::new(code)?; - // It's assumed this function will take care of any prevalidation logic - // that needs to be done. - // - // Do nothing for now. - Ok(blob) -} - -/// Runs preparation on the given runtime blob. If successful, it returns a serialized compiled -/// artifact which can then be used to pass into `Executor::execute` after writing it to the disk. -pub fn prepare( - blob: RuntimeBlob, - executor_params: &ExecutorParams, -) -> Result, sc_executor_common::error::WasmError> { - let semantics = params_to_wasmtime_semantics(executor_params) - .map_err(|e| sc_executor_common::error::WasmError::Other(e))?; - sc_executor_wasmtime::prepare_runtime_artifact(blob, &semantics) -} diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index 926d9cabe18..37a4dd06075 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -16,10 +16,9 @@ //! Contains the logic for preparing PVFs. Used by the polkadot-prepare-worker binary. -mod executor_intf; mod memory_stats; -pub use executor_intf::{prepare, prevalidate}; +use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate}; // 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-prepare-worker=trace`. @@ -31,7 +30,7 @@ use crate::memory_stats::max_rss_stat::{extract_max_rss_stat, get_max_rss_thread use crate::memory_stats::memory_tracker::{get_memory_tracker_loop_stats, memory_tracker_loop}; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ - error::{PrepareError, PrepareResult}, + error::{PrepareError, PrepareResult, OOM_PAYLOAD}, executor_intf::create_runtime_from_artifact_bytes, framed_recv_blocking, framed_send_blocking, prepare::{MemoryStats, PrepareJobKind, PrepareStats}, @@ -46,11 +45,24 @@ use polkadot_node_core_pvf_common::{ use polkadot_primitives::ExecutorParams; use std::{ fs, io, - os::unix::net::UnixStream, + os::{ + fd::{AsRawFd, RawFd}, + unix::net::UnixStream, + }, path::PathBuf, sync::{mpsc::channel, Arc}, time::Duration, }; +use tracking_allocator::TrackingAllocator; + +#[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] +#[global_allocator] +static ALLOC: TrackingAllocator = + TrackingAllocator(tikv_jemallocator::Jemalloc); + +#[cfg(not(any(target_os = "linux", feature = "jemalloc-allocator")))] +#[global_allocator] +static ALLOC: TrackingAllocator = TrackingAllocator(std::alloc::System); /// Contains the bytes for a successfully compiled artifact. pub struct CompiledArtifact(Vec); @@ -83,6 +95,44 @@ fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<( framed_send_blocking(stream, &result.encode()) } +fn start_memory_tracking(fd: RawFd, limit: Option) { + unsafe { + // SAFETY: Inside the failure handler, the allocator is locked and no allocations or + // deallocations are possible. For Linux, that always holds for the code below, so it's + // safe. For MacOS, that technically holds at the time of writing, but there are no future + // guarantees. + // The arguments of unsafe `libc` calls are valid, the payload validity is covered with + // a test. + ALLOC.start_tracking( + limit, + Some(Box::new(move || { + #[cfg(target_os = "linux")] + { + // Syscalls never allocate or deallocate, so this is safe. + libc::syscall(libc::SYS_write, fd, OOM_PAYLOAD.as_ptr(), OOM_PAYLOAD.len()); + libc::syscall(libc::SYS_close, fd); + libc::syscall(libc::SYS_exit, 1); + } + #[cfg(not(target_os = "linux"))] + { + // Syscalls are not available on MacOS, so we have to use `libc` wrappers. + // Technicaly, there may be allocations inside, although they shouldn't be + // there. In that case, we'll see deadlocks on MacOS after the OOM condition + // triggered. As we consider running a validator on MacOS unsafe, and this + // code is only run by a validator, it's a lesser evil. + libc::write(fd, OOM_PAYLOAD.as_ptr().cast(), OOM_PAYLOAD.len()); + libc::close(fd); + std::process::exit(1); + } + })), + ); + } +} + +fn end_memory_tracking() -> isize { + ALLOC.end_tracking() +} + /// The entrypoint that the spawned prepare worker should start with. /// /// # Parameters @@ -172,6 +222,22 @@ pub fn worker_entrypoint( Arc::clone(&condvar), WaitOutcome::TimedOut, )?; + + start_memory_tracking( + stream.as_raw_fd(), + executor_params.prechecking_max_memory().map(|v| { + v.try_into().unwrap_or_else(|_| { + gum::warn!( + LOG_TARGET, + %worker_pid, + "Illegal pre-checking max memory value {} discarded", + v, + ); + 0 + }) + }), + ); + // Spawn another thread for preparation. let prepare_thread = thread::spawn_worker_thread( "prepare thread", @@ -207,6 +273,17 @@ pub fn worker_entrypoint( let outcome = thread::wait_for_threads(condvar); + let peak_alloc = { + let peak = end_memory_tracking(); + gum::debug!( + target: LOG_TARGET, + %worker_pid, + "prepare job peak allocation is {} bytes", + peak, + ); + peak + }; + let result = match outcome { WaitOutcome::Finished => { let _ = cpu_time_monitor_tx.send(()); @@ -238,6 +315,14 @@ pub fn worker_entrypoint( memory_tracker_stats, #[cfg(target_os = "linux")] max_rss: extract_max_rss_stat(max_rss, worker_pid), + // Negative peak allocation values are legit; they are narrow + // corner cases and shouldn't affect overall statistics + // significantly + peak_tracked_alloc: if peak_alloc > 0 { + peak_alloc as u64 + } else { + 0u64 + }, }; // Write the serialized artifact into a temp file. diff --git a/polkadot/node/core/pvf/src/metrics.rs b/polkadot/node/core/pvf/src/metrics.rs index 3d792793498..7fd876cf174 100644 --- a/polkadot/node/core/pvf/src/metrics.rs +++ b/polkadot/node/core/pvf/src/metrics.rs @@ -93,6 +93,10 @@ impl Metrics { metrics.preparation_max_resident.observe(max_resident_kb); metrics.preparation_max_allocated.observe(max_allocated_kb); } + + metrics + .preparation_peak_tracked_allocation + .observe((memory_stats.peak_tracked_alloc / 1024) as f64); } } } @@ -110,10 +114,14 @@ struct MetricsInner { execution_time: prometheus::Histogram, #[cfg(target_os = "linux")] preparation_max_rss: prometheus::Histogram, + // Max. allocated memory, tracked by Jemallocator, polling-based #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] preparation_max_allocated: prometheus::Histogram, + // Max. resident memory, tracked by Jemallocator, polling-based #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] preparation_max_resident: prometheus::Histogram, + // Peak allocation value, tracked by tracking-allocator + preparation_peak_tracked_allocation: prometheus::Histogram, } impl metrics::Metrics for Metrics { @@ -271,6 +279,18 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + preparation_peak_tracked_allocation: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_pvf_preparation_peak_tracked_allocation", + "peak allocation observed for preparation (in kilobytes)", + ).buckets( + prometheus::exponential_buckets(8192.0, 2.0, 10) + .expect("arguments are always valid; qed"), + ), + )?, + registry, + )?, }; Ok(Metrics(Some(inner))) } diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 7933b0319a6..6bb6ca5b644 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -399,6 +399,20 @@ fn handle_mux( )?; } + Ok(()) + }, + Outcome::OutOfMemory => { + if attempt_retire(metrics, spawned, worker) { + reply( + from_pool, + FromPool::Concluded { + worker, + rip: true, + result: Err(PrepareError::OutOfMemory), + }, + )?; + } + Ok(()) }, } diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index 1f6ab0b7655..0e50caf1feb 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -98,6 +98,8 @@ pub enum Outcome { /// /// This doesn't return an idle worker instance, thus this worker is no longer usable. IoErr(String), + /// The worker ran out of memory and is aborting. The worker should be ripped. + OutOfMemory, } /// Given the idle token of a worker and parameters of work, communicates with the worker and @@ -234,6 +236,7 @@ async fn handle_response( Ok(result) => result, // Timed out on the child. This should already be logged by the child. Err(PrepareError::TimedOut) => return Outcome::TimedOut, + Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, Err(_) => return Outcome::Concluded { worker, result }, }; diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 169b55d34b5..4c038896f7f 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -36,8 +36,8 @@ pub fn validate_candidate( code: &[u8], params: &[u8], ) -> Result, Box> { + use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate}; 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"); diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index e8d8a9a6b63..9a7ddcb4089 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! PVF host integration tests checking the chain production pipeline. + use super::TestHost; use adder::{hash_state, BlockData, HeadData}; use parity_scale_codec::{Decode, Encode}; diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index a69a488adb9..f4fd7f802f5 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! General PVF host integration tests checking the functionality of the PVF host itself. + use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ @@ -22,13 +24,10 @@ use polkadot_node_core_pvf::{ JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; -use polkadot_primitives::ExecutorParams; +use polkadot_primitives::{ExecutorParam, ExecutorParams}; #[cfg(target_os = "linux")] use rusty_fork::rusty_fork_test; -#[cfg(feature = "ci-only-tests")] -use polkadot_primitives::ExecutorParam; - use std::time::Duration; use tokio::sync::Mutex; @@ -434,6 +433,43 @@ async fn deleting_prepared_artifact_does_not_dispute() { } } +// This test checks if the adder parachain runtime can be prepared with 10Mb preparation memory +// limit enforced. At the moment of writing, the limit if far enough to prepare the PVF. If it +// starts failing, either Wasmtime version has changed, or the PVF code itself has changed, and +// more memory is required now. Multi-threaded preparation, if ever enabled, may also affect +// memory consumption. +#[tokio::test] +async fn prechecking_within_memory_limits() { + let host = TestHost::new().await; + let result = host + .precheck_pvf( + ::adder::wasm_binary_unwrap(), + ExecutorParams::from(&[ExecutorParam::PrecheckingMaxMemory(10 * 1024 * 1024)][..]), + ) + .await; + + assert_matches!(result, Ok(_)); +} + +// This test checks if the adder parachain runtime can be prepared with 512Kb preparation memory +// limit enforced. At the moment of writing, the limit if not enough to prepare the PVF, and the +// preparation is supposed to generate an error. If the test starts failing, either Wasmtime +// version has changed, or the PVF code itself has changed, and less memory is required now. +#[tokio::test] +async fn prechecking_out_of_memory() { + use polkadot_node_core_pvf::PrepareError; + + let host = TestHost::new().await; + let result = host + .precheck_pvf( + ::adder::wasm_binary_unwrap(), + ExecutorParams::from(&[ExecutorParam::PrecheckingMaxMemory(512 * 1024)][..]), + ) + .await; + + assert_matches!(result, Err(PrepareError::OutOfMemory)); +} + // With one worker, run multiple preparation jobs serially. They should not conflict. #[tokio::test] async fn prepare_can_run_serially() { diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 9ce725f1682..f52f0cc0282 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -48,7 +48,7 @@ erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } rand = "0.8.5" # Required for worker binaries to build. -polkadot-node-core-pvf-common = { path = "../core/pvf/common", features = ["test-utils"] } +polkadot-node-core-pvf-common = { path = "../core/pvf/common" } polkadot-node-core-pvf-execute-worker = { path = "../core/pvf/execute-worker" } polkadot-node-core-pvf-prepare-worker = { path = "../core/pvf/prepare-worker" } diff --git a/polkadot/node/tracking-allocator/Cargo.toml b/polkadot/node/tracking-allocator/Cargo.toml new file mode 100644 index 00000000000..2ea3f69c7d0 --- /dev/null +++ b/polkadot/node/tracking-allocator/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "tracking-allocator" +description = "Tracking allocator to control the amount of memory consumed by the process" +version = "1.0.0" +authors.workspace = true +edition.workspace = true diff --git a/polkadot/node/tracking-allocator/src/lib.rs b/polkadot/node/tracking-allocator/src/lib.rs new file mode 100644 index 00000000000..8441bd1ffaf --- /dev/null +++ b/polkadot/node/tracking-allocator/src/lib.rs @@ -0,0 +1,242 @@ +// 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 . + +//! Tracking/limiting global allocator. Calculates the peak allocation between two checkpoints for +//! the whole process. Accepts an optional limit and a failure handler which is called if the limit +//! is overflown. + +use core::{ + alloc::{GlobalAlloc, Layout}, + ops::{Deref, DerefMut}, +}; +use std::{ + cell::UnsafeCell, + ptr::null_mut, + sync::atomic::{AtomicBool, Ordering}, +}; + +struct Spinlock { + lock: AtomicBool, + data: UnsafeCell, +} + +struct SpinlockGuard<'a, T: 'a> { + lock: &'a Spinlock, +} + +// SAFETY: We require that the data inside of the `SpinLock` is `Send`, so it can be sent +// and accessed by any thread as long as it's accessed by only one thread at a time. +// The `SpinLock` provides an exclusive lock over it, so it guarantees that multiple +// threads cannot access it at the same time, hence it implements `Sync` (that is, it can be +// accessed concurrently from multiple threads, even though the `T` itself might not +// necessarily be `Sync` too). +unsafe impl Sync for Spinlock {} + +impl Spinlock { + pub const fn new(t: T) -> Spinlock { + Spinlock { lock: AtomicBool::new(false), data: UnsafeCell::new(t) } + } + + #[inline] + pub fn lock(&self) -> SpinlockGuard { + loop { + // Try to acquire the lock. + if self + .lock + .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + { + return SpinlockGuard { lock: self } + } + // We failed to acquire the lock; wait until it's unlocked. + // + // In theory this should result in less coherency traffic as unlike `compare_exchange` + // it is a read-only operation, so multiple cores can execute it simultaneously + // without taking an exclusive lock over the cache line. + while self.lock.load(Ordering::Relaxed) { + std::hint::spin_loop(); + } + } + } + + #[inline] + fn unlock(&self) { + self.lock.store(false, Ordering::Release); + } +} + +impl Deref for SpinlockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: It is safe to dereference a guard to the `UnsafeCell` underlying data as the + // presence of the guard means the data is already locked. + unsafe { &*self.lock.data.get() } + } +} + +impl DerefMut for SpinlockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: Same as for `Deref::deref`. + unsafe { &mut *self.lock.data.get() } + } +} + +impl Drop for SpinlockGuard<'_, T> { + fn drop(&mut self) { + self.lock.unlock(); + } +} + +struct TrackingAllocatorData { + current: isize, + peak: isize, + limit: isize, + failure_handler: Option>, +} + +impl TrackingAllocatorData { + fn start_tracking( + mut guard: SpinlockGuard, + limit: isize, + failure_handler: Option>, + ) { + guard.current = 0; + guard.peak = 0; + guard.limit = limit; + // Cannot drop it yet, as it would trigger a deallocation + let old_handler = guard.failure_handler.take(); + guard.failure_handler = failure_handler; + drop(guard); + drop(old_handler); + } + + fn end_tracking(mut guard: SpinlockGuard) -> isize { + let peak = guard.peak; + guard.limit = 0; + // Cannot drop it yet, as it would trigger a deallocation + let old_handler = guard.failure_handler.take(); + drop(guard); + drop(old_handler); + peak + } + + #[inline] + fn track_and_check_limits( + mut guard: SpinlockGuard, + alloc: isize, + ) -> Option> { + guard.current += alloc; + if guard.current > guard.peak { + guard.peak = guard.current; + } + if guard.limit == 0 || guard.peak <= guard.limit { + None + } else { + Some(guard) + } + } +} + +static ALLOCATOR_DATA: Spinlock = + Spinlock::new(TrackingAllocatorData { current: 0, peak: 0, limit: 0, failure_handler: None }); + +pub struct TrackingAllocator(pub A); + +impl TrackingAllocator { + /// Start tracking memory allocations and deallocations. + /// + /// # Safety + /// + /// Failure handler is called with the allocator being in the locked state. Thus, no + /// allocations or deallocations are allowed inside the failure handler; otherwise, a + /// deadlock will occur. + pub unsafe fn start_tracking( + &self, + limit: Option, + failure_handler: Option>, + ) { + TrackingAllocatorData::start_tracking( + ALLOCATOR_DATA.lock(), + limit.unwrap_or(0), + failure_handler, + ); + } + + /// End tracking and return the peak allocation value in bytes (as `isize`). Peak allocation + /// value is not guaranteed to be neither non-zero nor positive. + pub fn end_tracking(&self) -> isize { + TrackingAllocatorData::end_tracking(ALLOCATOR_DATA.lock()) + } +} + +#[cold] +#[inline(never)] +unsafe fn fail_allocation(guard: SpinlockGuard) -> *mut u8 { + if let Some(failure_handler) = &guard.failure_handler { + failure_handler() + } + null_mut() +} + +unsafe impl GlobalAlloc for TrackingAllocator { + // SAFETY: + // * The wrapped methods are as safe as the underlying allocator implementation is + + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let guard = ALLOCATOR_DATA.lock(); + if let Some(guard) = + TrackingAllocatorData::track_and_check_limits(guard, layout.size() as isize) + { + fail_allocation(guard) + } else { + self.0.alloc(layout) + } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + let guard = ALLOCATOR_DATA.lock(); + if let Some(guard) = + TrackingAllocatorData::track_and_check_limits(guard, layout.size() as isize) + { + fail_allocation(guard) + } else { + self.0.alloc_zeroed(layout) + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) -> () { + let guard = ALLOCATOR_DATA.lock(); + TrackingAllocatorData::track_and_check_limits(guard, -(layout.size() as isize)); + self.0.dealloc(ptr, layout) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + let guard = ALLOCATOR_DATA.lock(); + if let Some(guard) = TrackingAllocatorData::track_and_check_limits( + guard, + (new_size as isize) - (layout.size() as isize), + ) { + fail_allocation(guard) + } else { + self.0.realloc(ptr, layout, new_size) + } + } +} diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs index 8ea0889bd23..bb9980f6879 100644 --- a/polkadot/primitives/src/v6/executor_params.rs +++ b/polkadot/primitives/src/v6/executor_params.rs @@ -197,6 +197,16 @@ impl ExecutorParams { None } + /// Returns pre-checking memory limit, if any + pub fn prechecking_max_memory(&self) -> Option { + for param in &self.0 { + if let ExecutorParam::PrecheckingMaxMemory(limit) = param { + return Some(*limit) + } + } + None + } + /// Check params coherence. pub fn check_consistency(&self) -> Result<(), ExecutorParamError> { use ExecutorParam::*; diff --git a/polkadot/src/main.rs b/polkadot/src/main.rs index 5986d8cea7b..1a96bf8fb00 100644 --- a/polkadot/src/main.rs +++ b/polkadot/src/main.rs @@ -24,7 +24,7 @@ use color_eyre::eyre; /// `memory_stats::MemoryAllocationTracker`. #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] #[global_allocator] -pub static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; fn main() -> eyre::Result<()> { color_eyre::install()?; -- GitLab From ca5f10567a4647e53ba5a2f900c60994f6e855b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 3 Nov 2023 19:06:31 +0100 Subject: [PATCH 436/633] `sc-block-builder`: Remove `BlockBuilderProvider` (#2099) The `BlockBuilderProvider` was a trait that was defined in `sc-block-builder`. The trait was implemented for `Client`. This basically meant that you needed to import `sc-block-builder` any way to have access to the block builder. So, this trait was not providing any real value. This pull request is removing the said trait. Instead of the trait it introduces a builder for creating a `BlockBuilder`. The builder currently has the quite fabulous name `BlockBuilderBuilder` (I'm open to any better name :sweat_smile:). The rest of the pull request is about replacing the old trait with the new builder. # Downstream code changes If you used `new_block` or `new_block_at` before you now need to switch it over to the new `BlockBuilderBuilder` pattern: ```rust // `new` requires a type that implements `CallApiAt`. let mut block_builder = BlockBuilderBuilder::new(client) // Then you need to specify the hash of the parent block the block will be build on top of .on_parent_block(at) // The block builder also needs the block number of the parent block. // Here it is fetched from the given `client` using the `HeaderBackend` // However, there also exists `with_parent_block_number` for directly passing the number .fetch_parent_block_number(client) .unwrap() // Enable proof recording if required. This call is optional. .enable_proof_recording() // Pass the digests. This call is optional. .with_inherent_digests(digests) .build() .expect("Creates new block builder"); ``` --------- Co-authored-by: Sebastian Kunert Co-authored-by: command-bot <> --- Cargo.lock | 2 - cumulus/test/client/src/block_builder.rs | 28 +- cumulus/test/service/benches/block_import.rs | 10 +- .../service/benches/block_import_glutton.rs | 13 +- .../test/service/benches/block_production.rs | 25 +- .../benches/block_production_glutton.rs | 22 +- .../test/service/benches/validate_block.rs | 8 +- cumulus/test/service/src/bench_utils.rs | 16 +- .../node/test/client/src/block_builder.rs | 24 +- .../bin/node/cli/benches/block_production.rs | 32 +- substrate/bin/node/testing/src/bench.rs | 11 +- substrate/client/basic-authorship/Cargo.toml | 2 +- .../basic-authorship/src/basic_authorship.rs | 87 ++- substrate/client/block-builder/Cargo.toml | 1 - substrate/client/block-builder/src/lib.rs | 275 +++++---- substrate/client/consensus/aura/src/lib.rs | 11 +- substrate/client/consensus/babe/src/tests.rs | 13 +- substrate/client/consensus/beefy/src/tests.rs | 26 +- .../client/consensus/grandpa/rpc/src/lib.rs | 21 +- .../consensus/grandpa/src/finality_proof.rs | 11 +- .../client/consensus/grandpa/src/tests.rs | 26 +- .../consensus/grandpa/src/voting_rule.rs | 20 +- .../consensus/grandpa/src/warp_proof.rs | 8 +- .../merkle-mountain-range/src/test_utils.rs | 9 +- substrate/client/network/bitswap/src/lib.rs | 8 +- .../network/sync/src/chain_sync/test.rs | 36 +- .../client/network/test/src/block_import.rs | 10 +- substrate/client/network/test/src/lib.rs | 21 +- substrate/client/offchain/src/lib.rs | 17 +- .../client/rpc-spec-v2/src/archive/tests.rs | 73 ++- .../src/chain_head/subscription/inner.rs | 105 +++- .../rpc-spec-v2/src/chain_head/tests.rs | 522 ++++++++++++---- substrate/client/rpc/src/chain/tests.rs | 38 +- substrate/client/rpc/src/dev/tests.rs | 20 +- substrate/client/rpc/src/state/tests.rs | 20 +- substrate/client/service/Cargo.toml | 1 - substrate/client/service/src/client/client.rs | 43 +- .../client/service/test/src/client/mod.rs | 572 +++++++++++++----- .../client/transaction-pool/tests/pool.rs | 8 +- substrate/primitives/api/src/lib.rs | 28 + .../api/test/tests/runtime_calls.rs | 11 +- .../runtime/client/src/block_builder_ext.rs | 12 +- .../runtime/client/src/trait_tests.rs | 225 +++++-- substrate/test-utils/runtime/src/lib.rs | 8 +- .../frame/benchmarking-cli/src/block/bench.rs | 5 +- .../frame/benchmarking-cli/src/block/cmd.rs | 5 +- .../benchmarking-cli/src/extrinsic/bench.rs | 26 +- .../benchmarking-cli/src/extrinsic/cmd.rs | 14 +- .../benchmarking-cli/src/overhead/cmd.rs | 14 +- 49 files changed, 1807 insertions(+), 736 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccd410f1415..b4501b5d751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14769,7 +14769,6 @@ name = "sc-block-builder" version = "0.10.0-dev" dependencies = [ "parity-scale-codec", - "sc-client-api", "sp-api", "sp-block-builder", "sp-blockchain", @@ -15834,7 +15833,6 @@ dependencies = [ "parking_lot 0.12.1", "pin-project", "rand 0.8.5", - "sc-block-builder", "sc-chain-spec", "sc-client-api", "sc-client-db", diff --git a/cumulus/test/client/src/block_builder.rs b/cumulus/test/client/src/block_builder.rs index 2d930d1be59..929f9f5f48c 100644 --- a/cumulus/test/client/src/block_builder.rs +++ b/cumulus/test/client/src/block_builder.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::{Backend, Client}; +use crate::Client; use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData}; use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER}; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use cumulus_test_runtime::{Block, GetLastTimestamp, Hash, Header}; use polkadot_primitives::{BlockNumber as PBlockNumber, Hash as PHash}; -use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; use sp_api::ProvideRuntimeApi; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -37,7 +37,7 @@ pub trait InitBlockBuilder { &self, validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, - ) -> sc_block_builder::BlockBuilder; + ) -> sc_block_builder::BlockBuilder; /// Init a specific block builder at a specific block that works for the test runtime. /// @@ -48,7 +48,7 @@ pub trait InitBlockBuilder { at: Hash, validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, - ) -> sc_block_builder::BlockBuilder; + ) -> sc_block_builder::BlockBuilder; /// Init a specific block builder that works for the test runtime. /// @@ -61,7 +61,7 @@ pub trait InitBlockBuilder { validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, timestamp: u64, - ) -> sc_block_builder::BlockBuilder; + ) -> sc_block_builder::BlockBuilder; } fn init_block_builder( @@ -70,9 +70,13 @@ fn init_block_builder( validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, timestamp: u64, -) -> BlockBuilder<'_, Block, Client, Backend> { - let mut block_builder = client - .new_block_at(at, Default::default(), true) +) -> BlockBuilder<'_, Block, Client> { + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(at) + .fetch_parent_block_number(client) + .unwrap() + .enable_proof_recording() + .build() .expect("Creates new block builder for test runtime"); let mut inherent_data = sp_inherents::InherentData::new(); @@ -118,7 +122,7 @@ impl InitBlockBuilder for Client { &self, validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, - ) -> BlockBuilder { + ) -> BlockBuilder { let chain_info = self.chain_info(); self.init_block_builder_at(chain_info.best_hash, validation_data, relay_sproof_builder) } @@ -128,7 +132,7 @@ impl InitBlockBuilder for Client { at: Hash, validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, - ) -> BlockBuilder { + ) -> BlockBuilder { let last_timestamp = self.runtime_api().get_last_timestamp(at).expect("Get last timestamp"); let timestamp = last_timestamp + cumulus_test_runtime::MinimumPeriod::get(); @@ -142,7 +146,7 @@ impl InitBlockBuilder for Client { validation_data: Option>, relay_sproof_builder: RelayStateSproofBuilder, timestamp: u64, - ) -> sc_block_builder::BlockBuilder { + ) -> sc_block_builder::BlockBuilder { init_block_builder(self, at, validation_data, relay_sproof_builder, timestamp) } } @@ -155,7 +159,7 @@ pub trait BuildParachainBlockData { fn build_parachain_block(self, parent_state_root: Hash) -> ParachainBlockData; } -impl<'a> BuildParachainBlockData for sc_block_builder::BlockBuilder<'a, Block, Client, Backend> { +impl<'a> BuildParachainBlockData for sc_block_builder::BlockBuilder<'a, Block, Client> { fn build_parachain_block(self, parent_state_root: Hash) -> ParachainBlockData { let built_block = self.build().expect("Builds the block"); diff --git a/cumulus/test/service/benches/block_import.rs b/cumulus/test/service/benches/block_import.rs index b79598b1530..254e03b9263 100644 --- a/cumulus/test/service/benches/block_import.rs +++ b/cumulus/test/service/benches/block_import.rs @@ -17,12 +17,12 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::UsageProvider; use core::time::Duration; use cumulus_primitives_core::ParaId; -use sc_block_builder::{BlockBuilderProvider, RecordProof}; use sp_api::{Core, ProvideRuntimeApi}; use sp_keyring::Sr25519Keyring::Alice; @@ -52,8 +52,12 @@ fn benchmark_block_import(c: &mut Criterion) { utils::create_benchmarking_transfer_extrinsics(&client, &src_accounts, &dst_accounts); let parent_hash = client.usage_info().chain.best_hash; - let mut block_builder = - client.new_block_at(parent_hash, Default::default(), RecordProof::No).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .fetch_parent_block_number(&*client) + .unwrap() + .build() + .unwrap(); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } diff --git a/cumulus/test/service/benches/block_import_glutton.rs b/cumulus/test/service/benches/block_import_glutton.rs index b49db9f449e..aeaf0722e72 100644 --- a/cumulus/test/service/benches/block_import_glutton.rs +++ b/cumulus/test/service/benches/block_import_glutton.rs @@ -17,7 +17,6 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use sc_client_api::UsageProvider; use sp_api::{Core, ProvideRuntimeApi}; use sp_arithmetic::{ traits::{One, Zero}, @@ -27,7 +26,7 @@ use sp_arithmetic::{ use core::time::Duration; use cumulus_primitives_core::ParaId; -use sc_block_builder::{BlockBuilderProvider, RecordProof}; +use sc_block_builder::BlockBuilderBuilder; use sp_keyring::Sr25519Keyring::Alice; use cumulus_test_service::bench_utils as utils; @@ -61,10 +60,14 @@ fn benchmark_block_import(c: &mut Criterion) { runtime.block_on(utils::import_block(&client, &block, false)); // Build the block we will use for benchmarking - let parent_hash = client.usage_info().chain.best_hash; + let parent_hash = client.chain_info().best_hash; let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap(); - let mut block_builder = - client.new_block_at(parent_hash, Default::default(), RecordProof::No).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .fetch_parent_block_number(&*client) + .unwrap() + .build() + .unwrap(); block_builder .push(utils::extrinsic_set_validation_data(parent_header.clone()).clone()) .unwrap(); diff --git a/cumulus/test/service/benches/block_production.rs b/cumulus/test/service/benches/block_production.rs index 1b868d73630..3b0db578041 100644 --- a/cumulus/test/service/benches/block_production.rs +++ b/cumulus/test/service/benches/block_production.rs @@ -21,7 +21,7 @@ use sc_client_api::UsageProvider; use core::time::Duration; use cumulus_primitives_core::ParaId; -use sc_block_builder::{BlockBuilderProvider, RecordProof}; +use sc_block_builder::BlockBuilderBuilder; use sp_keyring::Sr25519Keyring::Alice; @@ -50,7 +50,11 @@ fn benchmark_block_production(c: &mut Criterion) { let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap(); let set_validation_data_extrinsic = utils::extrinsic_set_validation_data(parent_header); - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); block_builder.push(utils::extrinsic_set_time(&client)).unwrap(); block_builder.push(set_validation_data_extrinsic).unwrap(); let built_block = block_builder.build().unwrap(); @@ -66,7 +70,7 @@ fn benchmark_block_production(c: &mut Criterion) { group.measurement_time(Duration::from_secs(120)); group.throughput(Throughput::Elements(max_transfer_count as u64)); - let best_hash = client.chain_info().best_hash; + let chain = client.chain_info(); group.bench_function( format!("(proof = true, transfers = {}) block production", max_transfer_count), @@ -74,9 +78,13 @@ fn benchmark_block_production(c: &mut Criterion) { b.iter_batched( || extrinsics.clone(), |extrinsics| { - let mut block_builder = client - .new_block_at(best_hash, Default::default(), RecordProof::Yes) + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .enable_proof_recording() + .build() .unwrap(); + for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } @@ -93,9 +101,12 @@ fn benchmark_block_production(c: &mut Criterion) { b.iter_batched( || extrinsics.clone(), |extrinsics| { - let mut block_builder = client - .new_block_at(best_hash, Default::default(), RecordProof::No) + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() .unwrap(); + for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } diff --git a/cumulus/test/service/benches/block_production_glutton.rs b/cumulus/test/service/benches/block_production_glutton.rs index 92a368c88c8..6ab2c0e56bd 100644 --- a/cumulus/test/service/benches/block_production_glutton.rs +++ b/cumulus/test/service/benches/block_production_glutton.rs @@ -17,7 +17,6 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use sc_client_api::UsageProvider; use sp_arithmetic::{ traits::{One, Zero}, FixedPointNumber, @@ -26,7 +25,7 @@ use sp_arithmetic::{ use core::time::Duration; use cumulus_primitives_core::ParaId; -use sc_block_builder::{BlockBuilderProvider, RecordProof}; +use sc_block_builder::BlockBuilderBuilder; use sp_keyring::Sr25519Keyring::Alice; @@ -60,11 +59,11 @@ fn benchmark_block_production_compute(c: &mut Criterion) { runtime.block_on(utils::import_block(&client, &block, false)); initialize_glutton_pallet = false; - let parent_hash = client.usage_info().chain.best_hash; - let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap(); + let best_hash = client.chain_info().best_hash; + let best_number = client.chain_info().best_number; + let parent_header = client.header(best_hash).expect("Just fetched this hash.").unwrap(); let set_validation_data_extrinsic = utils::extrinsic_set_validation_data(parent_header); let set_time_extrinsic = utils::extrinsic_set_time(&client); - let best_hash = client.chain_info().best_hash; group.bench_function( format!( @@ -76,8 +75,11 @@ fn benchmark_block_production_compute(c: &mut Criterion) { b.iter_batched( || (set_validation_data_extrinsic.clone(), set_time_extrinsic.clone()), |(validation_data, time)| { - let mut block_builder = client - .new_block_at(best_hash, Default::default(), RecordProof::Yes) + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(best_hash) + .with_parent_block_number(best_number) + .enable_proof_recording() + .build() .unwrap(); block_builder.push(validation_data).unwrap(); block_builder.push(time).unwrap(); @@ -98,8 +100,10 @@ fn benchmark_block_production_compute(c: &mut Criterion) { b.iter_batched( || (set_validation_data_extrinsic.clone(), set_time_extrinsic.clone()), |(validation_data, time)| { - let mut block_builder = client - .new_block_at(best_hash, Default::default(), RecordProof::No) + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(best_hash) + .with_parent_block_number(best_number) + .build() .unwrap(); block_builder.push(validation_data).unwrap(); block_builder.push(time).unwrap(); diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index f3b4d0b1214..11a7c4376d4 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -27,7 +27,7 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use cumulus_test_runtime::{BalancesCall, Block, Header, UncheckedExtrinsic}; use cumulus_test_service::bench_utils as utils; use polkadot_primitives::HeadData; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::UsageProvider; use sc_executor_common::wasm_runtime::WasmModule; @@ -46,7 +46,11 @@ fn create_extrinsics( dst_accounts: &[sr25519::Pair], ) -> (usize, Vec) { // Add as many tranfer extrinsics as possible into a single block. - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); let mut max_transfer_count = 0; let mut extrinsics = Vec::new(); diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 172c9e50419..82142f21695 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -16,6 +16,7 @@ // limitations under the License. use codec::Encode; +use sc_block_builder::BlockBuilderBuilder; use crate::{construct_extrinsic, Client as TestClient}; use cumulus_primitives_core::{relay_chain::AccountId, PersistedValidationData}; @@ -26,7 +27,6 @@ use cumulus_test_runtime::{ }; use frame_system_rpc_runtime_api::AccountNonceApi; use polkadot_primitives::HeadData; -use sc_block_builder::BlockBuilderProvider; use sc_client_api::UsageProvider; use sc_consensus::{ block_import::{BlockImportParams, ForkChoiceStrategy}, @@ -126,8 +126,13 @@ pub fn create_benchmarking_transfer_extrinsics( src_accounts: &[sr25519::Pair], dst_accounts: &[sr25519::Pair], ) -> (usize, Vec) { + let chain = client.usage_info().chain; // Add as many transfer extrinsics as possible into a single block. - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .expect("Creates block builder"); let mut max_transfer_count = 0; let mut extrinsics = Vec::new(); // Every block needs one timestamp extrinsic. @@ -248,8 +253,13 @@ pub fn set_glutton_parameters( Some(last_nonce), ); extrinsics.push(set_storage); + let chain = client.usage_info().chain; - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .unwrap(); block_builder.push(extrinsic_set_time(client)).unwrap(); block_builder.push(extrinsic_set_validation_data(parent_header)).unwrap(); for extrinsic in extrinsics { diff --git a/polkadot/node/test/client/src/block_builder.rs b/polkadot/node/test/client/src/block_builder.rs index b4ff050ff15..57e6008917a 100644 --- a/polkadot/node/test/client/src/block_builder.rs +++ b/polkadot/node/test/client/src/block_builder.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::{Client, FullBackend}; +use crate::Client; use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::{Block, InherentData as ParachainsInherentData}; use polkadot_test_runtime::UncheckedExtrinsic; use polkadot_test_service::GetLastTimestamp; -use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; use sp_api::ProvideRuntimeApi; use sp_consensus_babe::{ digests::{PreDigest, SecondaryPlainPreDigest}, @@ -34,9 +34,7 @@ pub trait InitPolkadotBlockBuilder { /// /// This will automatically create and push the inherents for you to make the block valid for /// the test runtime. - fn init_polkadot_block_builder( - &self, - ) -> sc_block_builder::BlockBuilder; + fn init_polkadot_block_builder(&self) -> sc_block_builder::BlockBuilder; /// Init a Polkadot specific block builder at a specific block that works for the test runtime. /// @@ -45,11 +43,11 @@ pub trait InitPolkadotBlockBuilder { fn init_polkadot_block_builder_at( &self, hash: ::Hash, - ) -> sc_block_builder::BlockBuilder; + ) -> sc_block_builder::BlockBuilder; } impl InitPolkadotBlockBuilder for Client { - fn init_polkadot_block_builder(&self) -> BlockBuilder { + fn init_polkadot_block_builder(&self) -> BlockBuilder { let chain_info = self.chain_info(); self.init_polkadot_block_builder_at(chain_info.best_hash) } @@ -57,7 +55,7 @@ impl InitPolkadotBlockBuilder for Client { fn init_polkadot_block_builder_at( &self, hash: ::Hash, - ) -> BlockBuilder { + ) -> BlockBuilder { let last_timestamp = self.runtime_api().get_last_timestamp(hash).expect("Get last timestamp"); @@ -90,8 +88,12 @@ impl InitPolkadotBlockBuilder for Client { )], }; - let mut block_builder = self - .new_block_at(hash, digest, false) + let mut block_builder = BlockBuilderBuilder::new(self) + .on_parent_block(hash) + .fetch_parent_block_number(&self) + .expect("Fetches parent block number") + .with_inherent_digests(digest) + .build() .expect("Creates new block builder for test runtime"); let mut inherent_data = sp_inherents::InherentData::new(); @@ -144,7 +146,7 @@ pub trait BlockBuilderExt { ) -> Result<(), sp_blockchain::Error>; } -impl BlockBuilderExt for BlockBuilder<'_, Block, Client, FullBackend> { +impl BlockBuilderExt for BlockBuilder<'_, Block, Client> { fn push_polkadot_extrinsic( &mut self, ext: UncheckedExtrinsic, diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index a22aa365e04..f59a125e1c0 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -20,7 +20,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughpu use kitchensink_runtime::{constants::currency::*, BalancesCall}; use node_cli::service::{create_extrinsic, FullClient}; -use sc_block_builder::{BlockBuilderProvider, BuiltBlock, RecordProof}; +use sc_block_builder::{BlockBuilderBuilder, BuiltBlock}; use sc_consensus::{ block_import::{BlockImportParams, ForkChoiceStrategy}, BlockImport, StateAction, @@ -127,7 +127,11 @@ fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { let mut max_transfer_count = 0; let mut extrinsics = Vec::new(); - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); // Every block needs one timestamp extrinsic. let extrinsic_set_time = extrinsic_set_time(1 + MINIMUM_PERIOD_FOR_BLOCKS); @@ -174,7 +178,11 @@ fn block_production(c: &mut Criterion) { // Buliding the very first block is around ~30x slower than any subsequent one, // so let's make sure it's built and imported before we benchmark anything. - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); block_builder.push(extrinsic_set_time(1)).unwrap(); import_block(client, block_builder.build().unwrap()); @@ -186,14 +194,19 @@ fn block_production(c: &mut Criterion) { group.sample_size(10); group.throughput(Throughput::Elements(max_transfer_count as u64)); - let best_hash = client.chain_info().best_hash; + let chain = client.chain_info(); + let best_hash = chain.best_hash; + let best_number = chain.best_number; group.bench_function(format!("{} transfers (no proof)", max_transfer_count), |b| { b.iter_batched( || extrinsics.clone(), |extrinsics| { - let mut block_builder = - client.new_block_at(best_hash, Default::default(), RecordProof::No).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(best_hash) + .with_parent_block_number(best_number) + .build() + .unwrap(); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } @@ -207,8 +220,11 @@ fn block_production(c: &mut Criterion) { b.iter_batched( || extrinsics.clone(), |extrinsics| { - let mut block_builder = - client.new_block_at(best_hash, Default::default(), RecordProof::Yes).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(client) + .on_parent_block(best_hash) + .with_parent_block_number(best_number) + .build() + .unwrap(); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index f1ab2212239..af3701f218a 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -39,8 +39,8 @@ use kitchensink_runtime::{ RuntimeCall, Signature, SystemCall, UncheckedExtrinsic, }; use node_primitives::Block; -use sc_block_builder::BlockBuilderProvider; -use sc_client_api::execution_extensions::ExecutionExtensions; +use sc_block_builder::BlockBuilderBuilder; +use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; use sc_client_db::PruningMode; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux}; use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod, WasmtimeInstantiationStrategy}; @@ -455,8 +455,13 @@ impl BenchDb { /// Generate new block using this database. pub fn generate_block(&mut self, content: BlockContent) -> Block { let client = self.client(); + let chain = client.usage_info().chain; - let mut block = client.new_block(Default::default()).expect("Block creation failed"); + let mut block = BlockBuilderBuilder::new(&client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .expect("Failed to create block builder."); for extrinsic in self.generate_inherents(&client) { block.push(extrinsic).expect("Push inherent failed"); diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index b65a5917955..1d60fc7f53e 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -19,7 +19,6 @@ futures-timer = "3.0.1" log = "0.4.17" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-block-builder = { path = "../block-builder" } -sc-client-api = { path = "../api" } sc-proposer-metrics = { path = "../proposer-metrics" } sc-telemetry = { path = "../telemetry" } sc-transaction-pool-api = { path = "../transaction-pool/api" } @@ -32,5 +31,6 @@ sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] parking_lot = "0.12.1" +sc-client-api = { path = "../api" } sc-transaction-pool = { path = "../transaction-pool" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 4db2de61cb4..c07f3e639c3 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -28,11 +28,10 @@ use futures::{ select, }; use log::{debug, error, info, trace, warn}; -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; -use sc_client_api::backend; +use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; -use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi}; use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed, HeaderBackend}; use sp_consensus::{DisableProofRecording, EnableProofRecording, ProofRecording, Proposal}; use sp_core::traits::SpawnNamed; @@ -60,7 +59,7 @@ const DEFAULT_SOFT_DEADLINE_PERCENT: Percent = Percent::from_percent(50); const LOG_TARGET: &'static str = "basic-authorship"; /// [`Proposer`] factory. -pub struct ProposerFactory { +pub struct ProposerFactory { spawn_handle: Box, /// The client instance. client: Arc, @@ -84,11 +83,11 @@ pub struct ProposerFactory { telemetry: Option, /// When estimating the block size, should the proof be included? include_proof_in_block_size_estimation: bool, - /// phantom member to pin the `Backend`/`ProofRecording` type. - _phantom: PhantomData<(B, PR)>, + /// phantom member to pin the `ProofRecording` type. + _phantom: PhantomData, } -impl ProposerFactory { +impl ProposerFactory { /// Create a new proposer factory. /// /// Proof recording will be disabled when using proposers built by this instance to build @@ -114,7 +113,7 @@ impl ProposerFactory { } } -impl ProposerFactory { +impl ProposerFactory { /// Create a new proposer factory with proof recording enabled. /// /// Each proposer created by this instance will record a proof while building a block. @@ -147,7 +146,7 @@ impl ProposerFactory { } } -impl ProposerFactory { +impl ProposerFactory { /// Set the default block size limit in bytes. /// /// The default value for the block size limit is: @@ -176,29 +175,23 @@ impl ProposerFactory { } } -impl ProposerFactory +impl ProposerFactory where A: TransactionPool + 'static, - B: backend::Backend + Send + Sync + 'static, Block: BlockT, - C: BlockBuilderProvider - + HeaderBackend - + ProvideRuntimeApi - + Send - + Sync - + 'static, + C: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, C::Api: ApiExt + BlockBuilderApi, { fn init_with_now( &mut self, parent_header: &::Header, now: Box time::Instant + Send + Sync>, - ) -> Proposer { + ) -> Proposer { let parent_hash = parent_header.hash(); info!("🙌 Starting consensus session on top of parent {:?}", parent_hash); - let proposer = Proposer::<_, _, _, _, PR> { + let proposer = Proposer::<_, _, _, PR> { spawn_handle: self.spawn_handle.clone(), client: self.client.clone(), parent_hash, @@ -217,22 +210,16 @@ where } } -impl sp_consensus::Environment for ProposerFactory +impl sp_consensus::Environment for ProposerFactory where A: TransactionPool + 'static, - B: backend::Backend + Send + Sync + 'static, Block: BlockT, - C: BlockBuilderProvider - + HeaderBackend - + ProvideRuntimeApi - + Send - + Sync - + 'static, + C: HeaderBackend + ProvideRuntimeApi + CallApiAt + Send + Sync + 'static, C::Api: ApiExt + BlockBuilderApi, PR: ProofRecording, { type CreateProposer = future::Ready>; - type Proposer = Proposer; + type Proposer = Proposer; type Error = sp_blockchain::Error; fn init(&mut self, parent_header: &::Header) -> Self::CreateProposer { @@ -241,7 +228,7 @@ where } /// The proposer logic. -pub struct Proposer { +pub struct Proposer { spawn_handle: Box, client: Arc, parent_hash: Block::Hash, @@ -253,20 +240,14 @@ pub struct Proposer { include_proof_in_block_size_estimation: bool, soft_deadline_percent: Percent, telemetry: Option, - _phantom: PhantomData<(B, PR)>, + _phantom: PhantomData, } -impl sp_consensus::Proposer for Proposer +impl sp_consensus::Proposer for Proposer where A: TransactionPool + 'static, - B: backend::Backend + Send + Sync + 'static, Block: BlockT, - C: BlockBuilderProvider - + HeaderBackend - + ProvideRuntimeApi - + Send - + Sync - + 'static, + C: HeaderBackend + ProvideRuntimeApi + CallApiAt + Send + Sync + 'static, C::Api: ApiExt + BlockBuilderApi, PR: ProofRecording, { @@ -313,17 +294,11 @@ where /// It allows us to increase block utilization. const MAX_SKIPPED_TRANSACTIONS: usize = 8; -impl Proposer +impl Proposer where A: TransactionPool, - B: backend::Backend + Send + Sync + 'static, Block: BlockT, - C: BlockBuilderProvider - + HeaderBackend - + ProvideRuntimeApi - + Send - + Sync - + 'static, + C: HeaderBackend + ProvideRuntimeApi + CallApiAt + Send + Sync + 'static, C::Api: ApiExt + BlockBuilderApi, PR: ProofRecording, { @@ -335,8 +310,12 @@ where block_size_limit: Option, ) -> Result, sp_blockchain::Error> { let block_timer = time::Instant::now(); - let mut block_builder = - self.client.new_block_at(self.parent_hash, inherent_digests, PR::ENABLED)?; + let mut block_builder = BlockBuilderBuilder::new(&*self.client) + .on_parent_block(self.parent_hash) + .with_parent_block_number(self.parent_number) + .with_proof_recording(PR::ENABLED) + .with_inherent_digests(inherent_digests) + .build()?; self.apply_inherents(&mut block_builder, inherent_data)?; @@ -358,7 +337,7 @@ where /// Apply all inherents to the block. fn apply_inherents( &self, - block_builder: &mut sc_block_builder::BlockBuilder<'_, Block, C, B>, + block_builder: &mut sc_block_builder::BlockBuilder<'_, Block, C>, inherent_data: InherentData, ) -> Result<(), sp_blockchain::Error> { let create_inherents_start = time::Instant::now(); @@ -402,7 +381,7 @@ where /// Apply as many extrinsics as possible to the block. async fn apply_extrinsics( &self, - block_builder: &mut sc_block_builder::BlockBuilder<'_, Block, C, B>, + block_builder: &mut sc_block_builder::BlockBuilder<'_, Block, C>, deadline: time::Instant, block_size_limit: Option, ) -> Result { @@ -976,8 +955,12 @@ mod tests { // Exact block_limit, which includes: // 99 (header_size) + 718 (proof@initialize_block) + 246 (one Transfer extrinsic) let block_limit = { - let builder = - client.new_block_at(genesis_header.hash(), Default::default(), true).unwrap(); + let builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(genesis_header.hash()) + .with_parent_block_number(0) + .enable_proof_recording() + .build() + .unwrap(); builder.estimate_block_size(true) + extrinsics[0].encoded_size() }; let block = block_on(proposer.propose( diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index ff2f9635b7a..2492c4101b2 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -16,7 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive", ] } -sc-client-api = { path = "../api" } sp-api = { path = "../../primitives/api" } sp-block-builder = { path = "../../primitives/block-builder" } sp-blockchain = { path = "../../primitives/blockchain" } diff --git a/substrate/client/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index 1878e762748..f62b941fdb1 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -29,56 +29,147 @@ use codec::Encode; use sp_api::{ - ApiExt, ApiRef, Core, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome, + ApiExt, ApiRef, CallApiAt, Core, ProvideRuntimeApi, StorageChanges, StorageProof, + TransactionOutcome, }; -use sp_blockchain::{ApplyExtrinsicFailed, Error}; +use sp_blockchain::{ApplyExtrinsicFailed, Error, HeaderBackend}; use sp_core::traits::CallContext; use sp_runtime::{ legacy, traits::{Block as BlockT, Hash, HashingFor, Header as HeaderT, NumberFor, One}, Digest, }; +use std::marker::PhantomData; -use sc_client_api::backend; pub use sp_block_builder::BlockBuilder as BlockBuilderApi; -/// Used as parameter to [`BlockBuilderProvider`] to express if proof recording should be enabled. -/// -/// When `RecordProof::Yes` is given, all accessed trie nodes should be saved. These recorded -/// trie nodes can be used by a third party to proof this proposal without having access to the -/// full storage. -#[derive(Copy, Clone, PartialEq)] -pub enum RecordProof { - /// `Yes`, record a proof. - Yes, - /// `No`, don't record any proof. - No, +/// A builder for creating an instance of [`BlockBuilder`]. +pub struct BlockBuilderBuilder<'a, B, C> { + call_api_at: &'a C, + _phantom: PhantomData, } -impl RecordProof { - /// Returns if `Self` == `Yes`. - pub fn yes(&self) -> bool { - matches!(self, Self::Yes) +impl<'a, B, C> BlockBuilderBuilder<'a, B, C> +where + B: BlockT, +{ + /// Create a new instance of the builder. + /// + /// `call_api_at`: Something that implements [`CallApiAt`]. + pub fn new(call_api_at: &'a C) -> Self { + Self { call_api_at, _phantom: PhantomData } } -} -/// Will return [`RecordProof::No`] as default value. -impl Default for RecordProof { - fn default() -> Self { - Self::No + /// Specify the parent block to build on top of. + pub fn on_parent_block(self, parent_block: B::Hash) -> BlockBuilderBuilderStage1<'a, B, C> { + BlockBuilderBuilderStage1 { call_api_at: self.call_api_at, parent_block } } } -impl From for RecordProof { - fn from(val: bool) -> Self { - if val { - Self::Yes - } else { - Self::No +/// The second stage of the [`BlockBuilderBuilder`]. +/// +/// This type can not be instantiated directly. To get an instance of it +/// [`BlockBuilderBuilder::new`] needs to be used. +pub struct BlockBuilderBuilderStage1<'a, B: BlockT, C> { + call_api_at: &'a C, + parent_block: B::Hash, +} + +impl<'a, B, C> BlockBuilderBuilderStage1<'a, B, C> +where + B: BlockT, +{ + /// Fetch the parent block number from the given `header_backend`. + /// + /// The parent block number is used to initialize the block number of the new block. + /// + /// Returns an error if the parent block specified in + /// [`on_parent_block`](BlockBuilderBuilder::on_parent_block) does not exist. + pub fn fetch_parent_block_number>( + self, + header_backend: &H, + ) -> Result, Error> { + let parent_number = header_backend.number(self.parent_block)?.ok_or_else(|| { + Error::Backend(format!( + "Could not fetch block number for block: {:?}", + self.parent_block + )) + })?; + + Ok(BlockBuilderBuilderStage2 { + call_api_at: self.call_api_at, + enable_proof_recording: false, + inherent_digests: Default::default(), + parent_block: self.parent_block, + parent_number, + }) + } + + /// Provide the block number for the parent block directly. + /// + /// The parent block is specified in [`on_parent_block`](BlockBuilderBuilder::on_parent_block). + /// The parent block number is used to initialize the block number of the new block. + pub fn with_parent_block_number( + self, + parent_number: NumberFor, + ) -> BlockBuilderBuilderStage2<'a, B, C> { + BlockBuilderBuilderStage2 { + call_api_at: self.call_api_at, + enable_proof_recording: false, + inherent_digests: Default::default(), + parent_block: self.parent_block, + parent_number, } } } +/// The second stage of the [`BlockBuilderBuilder`]. +/// +/// This type can not be instantiated directly. To get an instance of it +/// [`BlockBuilderBuilder::new`] needs to be used. +pub struct BlockBuilderBuilderStage2<'a, B: BlockT, C> { + call_api_at: &'a C, + enable_proof_recording: bool, + inherent_digests: Digest, + parent_block: B::Hash, + parent_number: NumberFor, +} + +impl<'a, B: BlockT, C> BlockBuilderBuilderStage2<'a, B, C> { + /// Enable proof recording for the block builder. + pub fn enable_proof_recording(mut self) -> Self { + self.enable_proof_recording = true; + self + } + + /// Enable/disable proof recording for the block builder. + pub fn with_proof_recording(mut self, enable: bool) -> Self { + self.enable_proof_recording = enable; + self + } + + /// Build the block with the given inherent digests. + pub fn with_inherent_digests(mut self, inherent_digests: Digest) -> Self { + self.inherent_digests = inherent_digests; + self + } + + /// Create the instance of the [`BlockBuilder`]. + pub fn build(self) -> Result, Error> + where + C: CallApiAt + ProvideRuntimeApi, + C::Api: BlockBuilderApi, + { + BlockBuilder::new( + self.call_api_at, + self.parent_block, + self.parent_number, + self.enable_proof_recording, + self.inherent_digests, + ) + } +} + /// A block that was build by [`BlockBuilder`] plus some additional data. /// /// This additional data includes the `storage_changes`, these changes can be applied to the @@ -101,63 +192,34 @@ impl BuiltBlock { } } -/// Block builder provider -pub trait BlockBuilderProvider -where - Block: BlockT, - B: backend::Backend, - Self: Sized, - RA: ProvideRuntimeApi, -{ - /// Create a new block, built on top of `parent`. - /// - /// When proof recording is enabled, all accessed trie nodes are saved. - /// These recorded trie nodes can be used by a third party to proof the - /// output of this block builder without having access to the full storage. - fn new_block_at>( - &self, - parent: Block::Hash, - inherent_digests: Digest, - record_proof: R, - ) -> sp_blockchain::Result>; - - /// Create a new block, built on the head of the chain. - fn new_block( - &self, - inherent_digests: Digest, - ) -> sp_blockchain::Result>; -} - /// Utility for building new (valid) blocks from a stream of extrinsics. -pub struct BlockBuilder<'a, Block: BlockT, A: ProvideRuntimeApi, B> { +pub struct BlockBuilder<'a, Block: BlockT, C: ProvideRuntimeApi + 'a> { extrinsics: Vec, - api: ApiRef<'a, A::Api>, + api: ApiRef<'a, C::Api>, + call_api_at: &'a C, version: u32, parent_hash: Block::Hash, - backend: &'a B, /// The estimated size of the block header. estimated_header_size: usize, } -impl<'a, Block, A, B> BlockBuilder<'a, Block, A, B> +impl<'a, Block, C> BlockBuilder<'a, Block, C> where Block: BlockT, - A: ProvideRuntimeApi + 'a, - A::Api: BlockBuilderApi + ApiExt, - B: backend::Backend, + C: CallApiAt + ProvideRuntimeApi + 'a, + C::Api: BlockBuilderApi, { /// Create a new instance of builder based on the given `parent_hash` and `parent_number`. /// /// While proof recording is enabled, all accessed trie nodes are saved. /// These recorded trie nodes can be used by a third party to prove the /// output of this block builder without having access to the full storage. - pub fn new( - api: &'a A, + fn new( + call_api_at: &'a C, parent_hash: Block::Hash, parent_number: NumberFor, - record_proof: RecordProof, + record_proof: bool, inherent_digests: Digest, - backend: &'a B, ) -> Result { let header = <::Header as HeaderT>::new( parent_number + One::one(), @@ -169,9 +231,9 @@ where let estimated_header_size = header.encoded_size(); - let mut api = api.runtime_api(); + let mut api = call_api_at.runtime_api(); - if record_proof.yes() { + if record_proof { api.record_proof(); } @@ -188,8 +250,8 @@ where extrinsics: Vec::new(), api, version, - backend, estimated_header_size, + call_api_at, }) } @@ -241,7 +303,7 @@ where let proof = self.api.extract_proof(); - let state = self.backend.state_at(self.parent_hash)?; + let state = self.call_api_at.state_at(self.parent_hash)?; let storage_changes = self .api @@ -300,22 +362,18 @@ mod tests { #[test] fn block_building_storage_proof_does_not_include_runtime_by_default() { let builder = substrate_test_runtime_client::TestClientBuilder::new(); - let backend = builder.backend(); let client = builder.build(); let genesis_hash = client.info().best_hash; - let block = BlockBuilder::new( - &client, - genesis_hash, - client.info().best_number, - RecordProof::Yes, - Default::default(), - &*backend, - ) - .unwrap() - .build() - .unwrap(); + let block = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .with_parent_block_number(0) + .enable_proof_recording() + .build() + .unwrap() + .build() + .unwrap(); let proof = block.proof.expect("Proof is build on request"); let genesis_state_root = client.header(genesis_hash).unwrap().unwrap().state_root; @@ -333,18 +391,15 @@ mod tests { #[test] fn failing_extrinsic_rolls_back_changes_in_storage_proof() { let builder = substrate_test_runtime_client::TestClientBuilder::new(); - let backend = builder.backend(); let client = builder.build(); + let genesis_hash = client.info().best_hash; - let mut block_builder = BlockBuilder::new( - &client, - client.info().best_hash, - client.info().best_number, - RecordProof::Yes, - Default::default(), - &*backend, - ) - .unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .with_parent_block_number(0) + .enable_proof_recording() + .build() + .unwrap(); block_builder.push(ExtrinsicBuilder::new_read_and_panic(8).build()).unwrap_err(); @@ -352,15 +407,12 @@ mod tests { let proof_with_panic = block.proof.expect("Proof is build on request").encoded_size(); - let mut block_builder = BlockBuilder::new( - &client, - client.info().best_hash, - client.info().best_number, - RecordProof::Yes, - Default::default(), - &*backend, - ) - .unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .with_parent_block_number(0) + .enable_proof_recording() + .build() + .unwrap(); block_builder.push(ExtrinsicBuilder::new_read(8).build()).unwrap(); @@ -368,17 +420,14 @@ mod tests { let proof_without_panic = block.proof.expect("Proof is build on request").encoded_size(); - let block = BlockBuilder::new( - &client, - client.info().best_hash, - client.info().best_number, - RecordProof::Yes, - Default::default(), - &*backend, - ) - .unwrap() - .build() - .unwrap(); + let block = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .with_parent_block_number(0) + .enable_proof_recording() + .build() + .unwrap() + .build() + .unwrap(); let proof_empty_block = block.proof.expect("Proof is build on request").encoded_size(); diff --git a/substrate/client/consensus/aura/src/lib.rs b/substrate/client/consensus/aura/src/lib.rs index 2ed451ef663..1be7be8eeea 100644 --- a/substrate/client/consensus/aura/src/lib.rs +++ b/substrate/client/consensus/aura/src/lib.rs @@ -548,7 +548,7 @@ where mod tests { use super::*; use parking_lot::Mutex; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::BlockchainEvents; use sc_consensus::BoxJustificationImport; use sc_consensus_slots::{BackoffAuthoringOnFinalizedHeadLagging, SimpleSlotWorker}; @@ -604,7 +604,14 @@ mod tests { _: Duration, _: Option, ) -> Self::Proposal { - let r = self.1.new_block(digests).unwrap().build().map_err(|e| e.into()); + let r = BlockBuilderBuilder::new(&*self.1) + .on_parent_block(self.1.chain_info().best_hash) + .fetch_parent_block_number(&*self.1) + .unwrap() + .with_inherent_digests(digests) + .build() + .unwrap() + .build(); future::ready(r.map(|b| Proposal { block: b.block, diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index 02882d8baae..d097f37c325 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use authorship::claim_slot; -use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; use sc_client_api::{BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; use sc_consensus_epochs::{EpochIdentifier, EpochIdentifierPosition}; @@ -98,8 +98,13 @@ impl DummyProposer { &mut self, pre_digests: Digest, ) -> future::Ready, Error>> { - let block_builder = - self.factory.client.new_block_at(self.parent_hash, pre_digests, false).unwrap(); + let block_builder = BlockBuilderBuilder::new(&*self.factory.client) + .on_parent_block(self.parent_hash) + .fetch_parent_block_number(&*self.factory.client) + .unwrap() + .with_inherent_digests(pre_digests) + .build() + .unwrap(); let mut block = match block_builder.build().map_err(|e| e.into()) { Ok(b) => b.block, @@ -297,7 +302,7 @@ impl TestNetFactory for BabeTestNet { async fn rejects_empty_block() { sp_tracing::try_init_simple(); let mut net = BabeTestNet::new(3); - let block_builder = |builder: BlockBuilder<_, _, _>| builder.build().unwrap().block; + let block_builder = |builder: BlockBuilder<_, _>| builder.build().unwrap().block; net.mut_peers(|peer| { peer[0].generate_blocks(1, BlockOrigin::NetworkInitialSync, block_builder); }) diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 902feca1639..3aaa59cbfa1 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -35,6 +35,7 @@ use crate::{ }; use futures::{future, stream::FuturesUnordered, Future, FutureExt, StreamExt}; use parking_lot::Mutex; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, @@ -741,7 +742,6 @@ async fn correct_beefy_payload() { #[tokio::test] async fn beefy_importing_justifications() { use futures::{future::poll_fn, task::Poll}; - use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockBackend; sp_tracing::try_init_simple(); @@ -774,8 +774,10 @@ async fn beefy_importing_justifications() { .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()) }; - let builder = full_client - .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(full_client.genesis_hash()) + .with_parent_block_number(0) + .build() .unwrap(); let block = builder.build().unwrap().block; let hashof1 = block.header.hash(); @@ -792,7 +794,11 @@ async fn beefy_importing_justifications() { // Import block 2 with "valid" justification (beefy pallet genesis block not yet reached). let block_num = 2; - let builder = full_client.new_block_at(hashof1, Default::default(), false).unwrap(); + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(hashof1) + .with_parent_block_number(1) + .build() + .unwrap(); let block = builder.build().unwrap().block; let hashof2 = block.header.hash(); @@ -824,7 +830,11 @@ async fn beefy_importing_justifications() { // Import block 3 with valid justification. let block_num = 3; - let builder = full_client.new_block_at(hashof2, Default::default(), false).unwrap(); + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(hashof2) + .with_parent_block_number(2) + .build() + .unwrap(); let block = builder.build().unwrap().block; let hashof3 = block.header.hash(); let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); @@ -858,7 +868,11 @@ async fn beefy_importing_justifications() { // Import block 4 with invalid justification (incorrect validator set). let block_num = 4; - let builder = full_client.new_block_at(hashof3, Default::default(), false).unwrap(); + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(hashof3) + .with_parent_block_number(3) + .build() + .unwrap(); let block = builder.build().unwrap().block; let hashof4 = block.header.hash(); let keys = &[BeefyKeyring::Alice]; diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index c6298bff969..a7daefaab8e 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -142,7 +142,7 @@ mod tests { RpcModule, }; use parity_scale_codec::{Decode, Encode}; - use sc_block_builder::{BlockBuilder, RecordProof}; + use sc_block_builder::BlockBuilderBuilder; use sc_consensus_grandpa::{ report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender, }; @@ -335,21 +335,16 @@ mod tests { let peers = &[Ed25519Keyring::Alice]; let builder = TestClientBuilder::new(); - let backend = builder.backend(); let client = builder.build(); let client = Arc::new(client); - let built_block = BlockBuilder::new( - &*client, - client.info().best_hash, - client.info().best_number, - RecordProof::No, - Default::default(), - &*backend, - ) - .unwrap() - .build() - .unwrap(); + let built_block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.info().best_hash) + .with_parent_block_number(client.info().best_number) + .build() + .unwrap() + .build() + .unwrap(); let block = built_block.block; let block_hash = block.hash(); diff --git a/substrate/client/consensus/grandpa/src/finality_proof.rs b/substrate/client/consensus/grandpa/src/finality_proof.rs index 8a8a688583e..80b6249ade8 100644 --- a/substrate/client/consensus/grandpa/src/finality_proof.rs +++ b/substrate/client/consensus/grandpa/src/finality_proof.rs @@ -261,7 +261,7 @@ mod tests { use super::*; use crate::{authorities::AuthoritySetChanges, BlockNumberOps, ClientError, SetId}; use futures::executor::block_on; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{apply_aux, LockImportRun}; use sp_consensus::BlockOrigin; use sp_consensus_grandpa::GRANDPA_ENGINE_ID as ID; @@ -323,7 +323,14 @@ mod tests { let mut blocks = Vec::new(); for _ in 0..number_of_blocks { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); blocks.push(block); } diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 0175f7d1b47..644befe9885 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -54,7 +54,7 @@ use tokio::runtime::Handle; use authorities::AuthoritySet; use communication::grandpa_protocol_name; -use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; use sc_consensus::LongestChain; use sp_application_crypto::key_types::GRANDPA; @@ -897,8 +897,11 @@ async fn allows_reimporting_change_blocks() { let (mut block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_client(); - let mut builder = full_client - .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) + let mut builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(full_client.chain_info().best_hash) + .fetch_parent_block_number(&*full_client) + .unwrap() + .build() .unwrap(); add_scheduled_change( @@ -942,8 +945,11 @@ async fn test_bad_justification() { let (mut block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_client(); - let mut builder = full_client - .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) + let mut builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(full_client.chain_info().best_hash) + .fetch_parent_block_number(&*full_client) + .unwrap() + .build() .unwrap(); add_scheduled_change( @@ -1913,7 +1919,12 @@ async fn imports_justification_for_regular_blocks_on_import() { // create a new block (without importing it) let generate_block = |parent| { - let builder = full_client.new_block_at(parent, Default::default(), false).unwrap(); + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(parent) + .fetch_parent_block_number(&*full_client) + .unwrap() + .build() + .unwrap(); builder.build().unwrap().block }; @@ -2042,8 +2053,7 @@ async fn revert_prunes_authority_changes() { let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; - type TestBlockBuilder<'a> = - BlockBuilder<'a, Block, PeersFullClient, substrate_test_runtime_client::Backend>; + type TestBlockBuilder<'a> = BlockBuilder<'a, Block, PeersFullClient>; let edit_block = |mut builder: TestBlockBuilder| { add_scheduled_change( &mut builder, diff --git a/substrate/client/consensus/grandpa/src/voting_rule.rs b/substrate/client/consensus/grandpa/src/voting_rule.rs index 27a91d54783..e09780739c7 100644 --- a/substrate/client/consensus/grandpa/src/voting_rule.rs +++ b/substrate/client/consensus/grandpa/src/voting_rule.rs @@ -330,7 +330,7 @@ where #[cfg(test)] mod tests { use super::*; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sp_consensus::BlockOrigin; use sp_runtime::traits::Header as _; @@ -371,7 +371,14 @@ mod tests { let mut hashes = Vec::with_capacity(200); for _ in 0..200 { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; hashes.push(block.hash()); futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); @@ -414,7 +421,14 @@ mod tests { let n = 5; let mut hashes = Vec::with_capacity(n); for _ in 0..n { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; hashes.push(block.hash()); futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index dcd55dcdf3a..a0fae6998f5 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -322,7 +322,7 @@ mod tests { use crate::{AuthoritySetChanges, GrandpaJustification}; use parity_scale_codec::Encode; use rand::prelude::*; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_consensus_grandpa::GRANDPA_ENGINE_ID; @@ -348,7 +348,11 @@ mod tests { let mut authority_set_changes = Vec::new(); for n in 1..=100 { - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); let mut new_authorities = None; // we will trigger an authority set change every 10 blocks diff --git a/substrate/client/merkle-mountain-range/src/test_utils.rs b/substrate/client/merkle-mountain-range/src/test_utils.rs index 010b48bb3d7..5775b4cfe67 100644 --- a/substrate/client/merkle-mountain-range/src/test_utils.rs +++ b/substrate/client/merkle-mountain-range/src/test_utils.rs @@ -18,7 +18,7 @@ use crate::MmrGadget; use parking_lot::Mutex; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{ Backend as BackendT, BlockchainEvents, FinalityNotifications, ImportNotifications, StorageEventStream, StorageKey, @@ -125,7 +125,12 @@ impl MockClient { let mut client = self.client.lock(); let hash = client.expect_block_hash_from_id(&at).unwrap(); - let mut block_builder = client.new_block_at(hash, Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash) + .fetch_parent_block_number(&*client) + .unwrap() + .build() + .unwrap(); // Make sure the block has a different hash than its siblings block_builder .push_storage_change(b"name".to_vec(), Some(name.to_vec())) diff --git a/substrate/client/network/bitswap/src/lib.rs b/substrate/client/network/bitswap/src/lib.rs index 7bb8b003065..9200c2fa772 100644 --- a/substrate/client/network/bitswap/src/lib.rs +++ b/substrate/client/network/bitswap/src/lib.rs @@ -290,7 +290,7 @@ pub enum BitswapError { mod tests { use super::*; use futures::channel::oneshot; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use schema::bitswap::{ message::{wantlist::Entry, Wantlist}, Message as BitswapMessage, @@ -468,7 +468,11 @@ mod tests { #[tokio::test] async fn transaction_found() { let mut client = TestClientBuilder::with_tx_storage(u32::MAX).build(); - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); // encoded extrinsic: [161, .. , 2, 6, 16, 19, 55, 19, 56] let ext = ExtrinsicBuilder::new_indexed_call(vec![0x13, 0x37, 0x13, 0x38]).build(); diff --git a/substrate/client/network/sync/src/chain_sync/test.rs b/substrate/client/network/sync/src/chain_sync/test.rs index 23316eaa194..de908f0449c 100644 --- a/substrate/client/network/sync/src/chain_sync/test.rs +++ b/substrate/client/network/sync/src/chain_sync/test.rs @@ -21,7 +21,7 @@ use super::*; use crate::service::network::NetworkServiceProvider; use futures::executor::block_on; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; use sp_blockchain::HeaderBackend; use substrate_test_runtime_client::{ @@ -52,7 +52,14 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { .unwrap(); let (a1_hash, a1_number) = { - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; (a1.hash(), *a1.header.number()) }; @@ -115,7 +122,14 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { let mut new_blocks = |n| { for _ in 0..n { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); } @@ -233,7 +247,12 @@ fn get_block_request( fn build_block(client: &mut Arc, at: Option, fork: bool) -> Block { let at = at.unwrap_or_else(|| client.info().best_hash); - let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&**client) + .on_parent_block(at) + .fetch_parent_block_number(&**client) + .unwrap() + .build() + .unwrap(); if fork { block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); @@ -774,7 +793,14 @@ fn sync_restart_removes_block_but_not_justification_requests() { let mut new_blocks = |n| { for _ in 0..n { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); } diff --git a/substrate/client/network/test/src/block_import.rs b/substrate/client/network/test/src/block_import.rs index 25e3b9bee87..35795432b37 100644 --- a/substrate/client/network/test/src/block_import.rs +++ b/substrate/client/network/test/src/block_import.rs @@ -20,7 +20,6 @@ use super::*; use futures::executor::block_on; -use sc_block_builder::BlockBuilderProvider; use sc_consensus::{ import_single_block, BasicQueue, BlockImportError, BlockImportStatus, ImportedAux, IncomingBlock, @@ -34,7 +33,14 @@ use substrate_test_runtime_client::{ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) { let mut client = substrate_test_runtime_client::new(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::File, block)).unwrap(); let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1); diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index ad4201f94a2..f869e3a171a 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -38,7 +38,7 @@ use futures::{channel::oneshot, future::BoxFuture, pin_mut, prelude::*}; use libp2p::{build_multiaddr, PeerId}; use log::trace; use parking_lot::Mutex; -use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; use sc_client_api::{ backend::{AuxStore, Backend, Finalizer}, BlockBackend, BlockImportNotification, BlockchainEvents, FinalityNotification, @@ -305,9 +305,7 @@ where edit_block: F, ) -> Vec where - F: FnMut( - BlockBuilder, - ) -> Block, + F: FnMut(BlockBuilder) -> Block, { let best_hash = self.client.info().best_hash; self.generate_blocks_at( @@ -331,9 +329,7 @@ where fork_choice: ForkChoiceStrategy, ) -> Vec where - F: FnMut( - BlockBuilder, - ) -> Block, + F: FnMut(BlockBuilder) -> Block, { let best_hash = self.client.info().best_hash; self.generate_blocks_at( @@ -362,15 +358,18 @@ where fork_choice: ForkChoiceStrategy, ) -> Vec where - F: FnMut( - BlockBuilder, - ) -> Block, + F: FnMut(BlockBuilder) -> Block, { let mut hashes = Vec::with_capacity(count); let full_client = self.client.as_client(); let mut at = full_client.block_hash_from_id(&at).unwrap().unwrap(); for _ in 0..count { - let builder = full_client.new_block_at(at, Default::default(), false).unwrap(); + let builder = BlockBuilderBuilder::new(&*full_client) + .on_parent_block(at) + .fetch_parent_block_number(&*full_client) + .unwrap() + .build() + .unwrap(); let block = edit_block(builder); let hash = block.header.hash(); trace!( diff --git a/substrate/client/offchain/src/lib.rs b/substrate/client/offchain/src/lib.rs index a11ac7d86ec..756ab77ff94 100644 --- a/substrate/client/offchain/src/lib.rs +++ b/substrate/client/offchain/src/lib.rs @@ -328,12 +328,13 @@ mod tests { use super::*; use futures::executor::block_on; use libp2p::{Multiaddr, PeerId}; - use sc_block_builder::BlockBuilderProvider as _; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::Backend as _; use sc_network::{config::MultiaddrWithPeerId, types::ProtocolName, ReputationChange}; use sc_transaction_pool::BasicPool; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; + use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime_client::{ runtime::{ @@ -470,16 +471,24 @@ mod tests { let key = &b"hello"[..]; let value = &b"world"[..]; - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); let ext = ExtrinsicBuilder::new_offchain_index_set(key.to_vec(), value.to_vec()).build(); block_builder.push(ext).unwrap(); let block = block_builder.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); assert_eq!(value, &offchain_db.get(sp_offchain::STORAGE_PREFIX, &key).unwrap()); - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); let ext = ExtrinsicBuilder::new_offchain_index_clear(key.to_vec()).nonce(1).build(); block_builder.push(ext).unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs index 36f7716e393..6b288c2c954 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -27,10 +27,13 @@ use jsonrpsee::{ types::{error::CallError, EmptyServerParams as EmptyParams}, RpcModule, }; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; -use sp_runtime::SaturatedConversion; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT}, + SaturatedConversion, +}; use std::sync::Arc; use substrate_test_runtime::Transfer; use substrate_test_runtime_client::{ @@ -72,7 +75,12 @@ async fn archive_body() { assert!(res.is_none()); // Import a new block with an extrinsic. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); + builder .push_transfer(runtime::Transfer { from: AccountKeyring::Alice.into(), @@ -101,7 +109,12 @@ async fn archive_header() { assert!(res.is_none()); // Import a new block with an extrinsic. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); + builder .push_transfer(runtime::Transfer { from: AccountKeyring::Alice.into(), @@ -147,24 +160,57 @@ async fn archive_hash_by_height() { // ^^^ h = N // ^^^ h = N + 1 // ^^^ h = N + 2 - let finalized = client.new_block(Default::default()).unwrap().build().unwrap().block; + let finalized = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .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 = BlockBuilderBuilder::new(&*client) + .on_parent_block(finalized.hash()) + .with_parent_block_number(*finalized.header().number()) + .build() + .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 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(*block_1.header().number()) + .build() + .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 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2.hash()) + .with_parent_block_number(*block_2.header().number()) + .build() + .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(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(*block_1.header().number()) + .build() + .unwrap(); + // This push is required as otherwise block 3 has the same hash as block 1 and won't get // imported block_builder @@ -238,7 +284,14 @@ async fn archive_call() { .unwrap(); assert_matches!(result, MethodResult::Err(_)); - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_1_hash = block_1.header.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index d6f64acd63f..8a75029a994 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -806,7 +806,7 @@ impl> SubscriptionsInner { #[cfg(test)] mod tests { use super::*; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sc_service::client::new_in_mem; use sp_consensus::BlockOrigin; use sp_core::{testing::TaskExecutor, H256}; @@ -1004,8 +1004,15 @@ mod tests { fn subscription_check_block() { let (backend, mut client) = init_backend(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let hash = block.header.hash(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash = block.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); let mut subs = @@ -1034,7 +1041,14 @@ mod tests { #[test] fn subscription_ref_count() { let (backend, mut client) = init_backend(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); @@ -1077,13 +1091,34 @@ mod tests { #[test] fn subscription_remove_subscription() { let (backend, mut client) = init_backend(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_1 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_1) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_2 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_2) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_3 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); @@ -1122,13 +1157,34 @@ mod tests { #[test] fn subscription_check_limits() { let (backend, mut client) = init_backend(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_1 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_1) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_2 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_2) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_3 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); @@ -1173,13 +1229,34 @@ mod tests { #[test] fn subscription_check_limits_with_duration() { let (backend, mut client) = init_backend(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let hash_1 = block.header.hash(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash_1 = block.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_1) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_2 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_2) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash_3 = block.header.hash(); futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); 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 8aaeb413cdf..c3f5564ebc4 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -31,7 +31,7 @@ use jsonrpsee::{ types::{error::CallError, EmptyServerParams as EmptyParams}, RpcModule, }; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_service::client::new_in_mem; use sp_api::BlockT; @@ -125,7 +125,14 @@ async fn setup_api() -> ( let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); // Ensure the imported block is propagated and pinned for this subscription. @@ -177,7 +184,14 @@ async fn follow_subscription_produces_blocks() { }); assert_eq!(event, expected); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let best_hash = block.header.hash(); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); @@ -255,8 +269,15 @@ async fn follow_with_runtime() { // Import a new block without runtime changes. // The runtime field must be None in this case. - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let best_hash = block.header.hash(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let best_hash = block.hash(); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); let event: FollowEvent = get_next_event(&mut sub).await; @@ -302,7 +323,11 @@ async fn follow_with_runtime() { ) .unwrap(); - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(best_hash) + .with_parent_block_number(1) + .build() + .unwrap(); builder.push_storage_change(CODE.to_vec(), Some(wasm)).unwrap(); let block = builder.build().unwrap().block; let best_hash = block.header.hash(); @@ -411,7 +436,11 @@ async fn get_body() { ); // Import a block with extrinsics. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); builder .push_transfer(runtime::Transfer { from: AccountKeyring::Alice.into(), @@ -554,7 +583,14 @@ async fn call_runtime_without_flag() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_hash = format!("{:?}", block.header.hash()); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); @@ -648,7 +684,11 @@ async fn get_storage_hash() { ); // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); builder.push_storage_change(KEY.to_vec(), Some(VALUE.to_vec())).unwrap(); let block = builder.build().unwrap().block; let block_hash = format!("{:?}", block.header.hash()); @@ -730,11 +770,15 @@ async fn get_storage_hash() { #[tokio::test] async fn get_storage_multi_query_iter() { - let (mut client, api, mut block_sub, sub_id, _) = setup_api().await; + let (mut client, api, mut block_sub, sub_id, block) = setup_api().await; let key = hex_string(&KEY); // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); builder.push_storage_change(KEY.to_vec(), Some(VALUE.to_vec())).unwrap(); let block = builder.build().unwrap().block; let block_hash = format!("{:?}", block.header.hash()); @@ -851,7 +895,7 @@ async fn get_storage_multi_query_iter() { #[tokio::test] async fn get_storage_value() { let (mut client, api, mut block_sub, sub_id, block) = setup_api().await; - let block_hash = format!("{:?}", block.header.hash()); + let block_hash = format!("{:?}", block.hash()); let invalid_hash = hex_string(&INVALID_HASH); let key = hex_string(&KEY); @@ -908,10 +952,14 @@ async fn get_storage_value() { ); // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); builder.push_storage_change(KEY.to_vec(), Some(VALUE.to_vec())).unwrap(); let block = builder.build().unwrap().block; - let block_hash = format!("{:?}", block.header.hash()); + let block_hash = format!("{:?}", block.hash()); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); // Ensure the imported block is propagated and pinned for this subscription. @@ -1199,7 +1247,14 @@ async fn separate_operation_ids_for_subscriptions() { let sub_id_second = sub_second.subscription_id(); let sub_id_second = serde_json::to_string(&sub_id_second).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); let block_hash = format!("{:?}", block.header.hash()); @@ -1274,18 +1329,35 @@ async fn follow_generates_initial_blocks() { let finalized_hash = client.info().finalized_hash; // Block tree: - // finalized -> block 1 -> block 2 -> block 4 - // -> block 1 -> block 3 - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + // finalized -> block 1 -> block 2 -> block 3 + // -> block 1 -> block 2_f + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_1_hash = block_1.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 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_2_hash = block_2.header.hash(); client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); - let mut block_builder = - client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(1) + .build() + .unwrap(); // This push is required as otherwise block 3 has the same hash as block 2 and won't get // imported block_builder @@ -1296,9 +1368,9 @@ async fn follow_generates_initial_blocks() { nonce: 0, }) .unwrap(); - let block_3 = block_builder.build().unwrap().block; - let block_3_hash = block_3.header.hash(); - client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + let block_2_f = block_builder.build().unwrap().block; + let block_2_f_hash = block_2_f.header.hash(); + client.import(BlockOrigin::Own, block_2_f.clone()).await.unwrap(); let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); @@ -1333,7 +1405,7 @@ async fn follow_generates_initial_blocks() { // Check block 3. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_3_hash), + block_hash: format!("{:?}", block_2_f_hash), parent_block_hash: format!("{:?}", block_1_hash), new_runtime: None, with_runtime: false, @@ -1346,14 +1418,21 @@ async fn follow_generates_initial_blocks() { }); assert_eq!(event, expected); - // Import block 4. - let block_4 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_4_hash = block_4.header.hash(); - client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + // Import block 3. + let block_3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2_hash) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_3_hash = block_3.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_4_hash), + block_hash: format!("{:?}", block_3_hash), parent_block_hash: format!("{:?}", block_2_hash), new_runtime: None, with_runtime: false, @@ -1362,23 +1441,23 @@ async fn follow_generates_initial_blocks() { let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::BestBlockChanged(BestBlockChanged { - best_block_hash: format!("{:?}", block_4_hash), + best_block_hash: format!("{:?}", block_3_hash), }); assert_eq!(event, expected); // Check the finalized event: // - blocks 1, 2, 4 from canonical chain are finalized // - block 3 from the fork is pruned - client.finalize_block(block_4_hash, None).unwrap(); + client.finalize_block(block_3_hash, None).unwrap(); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Finalized(Finalized { finalized_block_hashes: vec![ format!("{:?}", block_1_hash), format!("{:?}", block_2_hash), - format!("{:?}", block_4_hash), + format!("{:?}", block_3_hash), ], - pruned_block_hashes: vec![format!("{:?}", block_3_hash)], + pruned_block_hashes: vec![format!("{:?}", block_2_f_hash)], }); assert_eq!(event, expected); } @@ -1405,7 +1484,15 @@ async fn follow_exceeding_pinned_blocks() { let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); // Ensure the imported block is propagated and pinned for this subscription. @@ -1426,13 +1513,27 @@ async fn follow_exceeding_pinned_blocks() { // finalized_block -> block -> block2 // The first 2 blocks are pinned into the subscription, but the block2 will exceed the limit (2 // blocks). - let block2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block2.clone()).await.unwrap(); assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); // Subscription will not produce any more event for further blocks. - let block3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block3.clone()).await.unwrap(); assert!(sub.next::>().await.is_none()); @@ -1462,7 +1563,14 @@ async fn follow_with_unpin() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_hash = format!("{:?}", block.header.hash()); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); @@ -1503,7 +1611,14 @@ async fn follow_with_unpin() { // Block tree: // finalized_block -> block -> block2 // ^ has been unpinned - let block2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block2.clone()).await.unwrap(); assert_matches!( @@ -1516,7 +1631,14 @@ async fn follow_with_unpin() { FollowEvent::BestBlockChanged(_) ); - let block3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block3.clone()).await.unwrap(); assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); @@ -1560,27 +1682,52 @@ async fn follow_prune_best_block() { // finalized -> block 1 -> block 2 // ^^^ best block reported // - // -> block 1 -> block 3 -> block 4 + // -> block 1 -> block 2_f -> block 4 // ^^^ finalized // // The block 4 is needed on the longest chain because we want the // best block 2 to be reported as pruned. Pruning is happening at // height (N - 1), where N is the finalized block number. - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_1_hash = block_1.header.hash(); + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_1_hash = block_1.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); - let block_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(); - - let block_4 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_4_hash = block_4.header.hash(); + let block_2_f = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_2_f_hash = block_2_f.hash(); + client.import(BlockOrigin::Own, block_2_f.clone()).await.unwrap(); + + let block_4 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2_f_hash) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_4_hash = block_4.hash(); client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); // Import block 2 as best on the fork. - let mut block_builder = client.new_block_at(block_1_hash, Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(1) + .build() + .unwrap(); // This push is required as otherwise block 3 has the same hash as block 2 and won't get // imported block_builder @@ -1613,7 +1760,7 @@ async fn follow_prune_best_block() { // Check block 3. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_3_hash), + block_hash: format!("{:?}", block_2_f_hash), parent_block_hash: format!("{:?}", block_1_hash), new_runtime: None, with_runtime: false, @@ -1621,7 +1768,7 @@ async fn follow_prune_best_block() { assert_eq!(event, expected); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::BestBlockChanged(BestBlockChanged { - best_block_hash: format!("{:?}", block_3_hash), + best_block_hash: format!("{:?}", block_2_f_hash), }); assert_eq!(event, expected); @@ -1629,7 +1776,7 @@ async fn follow_prune_best_block() { let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { block_hash: format!("{:?}", block_4_hash), - parent_block_hash: format!("{:?}", block_3_hash), + parent_block_hash: format!("{:?}", block_2_f_hash), new_runtime: None, with_runtime: false, }); @@ -1670,7 +1817,7 @@ async fn follow_prune_best_block() { let expected = FollowEvent::Finalized(Finalized { finalized_block_hashes: vec![ format!("{:?}", block_1_hash), - format!("{:?}", block_3_hash), + format!("{:?}", block_2_f_hash), format!("{:?}", block_4_hash), ], pruned_block_hashes: vec![format!("{:?}", block_2_hash)], @@ -1708,22 +1855,46 @@ async fn follow_forks_pruned_block() { // // finalized -> block 1 -> block 2 -> block 3 // ^^^ finalized - // -> block 1 -> block 4 -> block 5 + // -> block 1 -> block 2_f -> block 3_f // - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); - let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); - let block_3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_3_hash = block_3.header.hash(); client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); // Block 4 with parent Block 1 is not the best imported. - let mut block_builder = - client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); // This push is required as otherwise block 4 has the same hash as block 2 and won't get // imported block_builder @@ -1734,11 +1905,14 @@ async fn follow_forks_pruned_block() { nonce: 0, }) .unwrap(); - let block_4 = block_builder.build().unwrap().block; - client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + let block_2_f = block_builder.build().unwrap().block; + client.import(BlockOrigin::Own, block_2_f.clone()).await.unwrap(); - let mut block_builder = - client.new_block_at(block_4.header.hash(), Default::default(), false).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2_f.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); block_builder .push_transfer(Transfer { from: AccountKeyring::Bob.into(), @@ -1747,10 +1921,10 @@ async fn follow_forks_pruned_block() { nonce: 0, }) .unwrap(); - let block_5 = block_builder.build().unwrap().block; - client.import(BlockOrigin::Own, block_5.clone()).await.unwrap(); + let block_3_f = block_builder.build().unwrap().block; + client.import(BlockOrigin::Own, block_3_f.clone()).await.unwrap(); - // Block 4 and 5 are not pruned, pruning happens at height (N - 1). + // Block 2_f and 3_f are not pruned, pruning happens at height (N - 1). client.finalize_block(block_3_hash, None).unwrap(); let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); @@ -1766,22 +1940,29 @@ async fn follow_forks_pruned_block() { // Block tree: // - // finalized -> block 1 -> block 2 -> block 3 -> block 6 + // finalized -> block 1 -> block 2 -> block 3 -> block 4 // ^^^ finalized - // -> block 1 -> block 4 -> block 5 + // -> block 1 -> block 2_f -> block 3_f // - // Mark block 6 as finalized to force block 4 and 5 to get pruned. + // Mark block 4 as finalized to force block 2_f and 3_f to get pruned. - let block_6 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_6_hash = block_6.header.hash(); - client.import(BlockOrigin::Own, block_6.clone()).await.unwrap(); + let block_4 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_3.hash()) + .with_parent_block_number(3) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_4_hash = block_4.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); - client.finalize_block(block_6_hash, None).unwrap(); + client.finalize_block(block_4_hash, None).unwrap(); // Check block 6. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_6_hash), + block_hash: format!("{:?}", block_4_hash), parent_block_hash: format!("{:?}", block_3_hash), new_runtime: None, with_runtime: false, @@ -1789,14 +1970,14 @@ async fn follow_forks_pruned_block() { assert_eq!(event, expected); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::BestBlockChanged(BestBlockChanged { - best_block_hash: format!("{:?}", block_6_hash), + best_block_hash: format!("{:?}", block_4_hash), }); assert_eq!(event, expected); // Block 4 and 5 must not be reported as pruned. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Finalized(Finalized { - finalized_block_hashes: vec![format!("{:?}", block_6_hash)], + finalized_block_hashes: vec![format!("{:?}", block_4_hash)], pruned_block_hashes: vec![], }); assert_eq!(event, expected); @@ -1826,26 +2007,51 @@ async fn follow_report_multiple_pruned_block() { // // finalized -> block 1 -> block 2 -> block 3 // ^^^ finalized after subscription - // -> block 1 -> block 4 -> block 5 + // -> block 1 -> block 2_f -> block 3_f let finalized_hash = client.info().finalized_hash; - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_1_hash = block_1.header.hash(); + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_1_hash = block_1.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); - let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_2_hash = block_2.header.hash(); + let block_2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_2_hash = block_2.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(); + let block_3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_3_hash = block_3.hash(); client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); - // Block 4 with parent Block 1 is not the best imported. - let mut block_builder = - client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); - // This push is required as otherwise block 4 has the same hash as block 2 and won't get + // Block 2_f with parent Block 1 is not the best imported. + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + + // This push is required as otherwise block 2_f has the same hash as block 2 and won't get // imported block_builder .push_transfer(Transfer { @@ -1855,12 +2061,16 @@ async fn follow_report_multiple_pruned_block() { 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(); + let block_2_f = block_builder.build().unwrap().block; + let block_2_f_hash = block_2_f.hash(); + client.import(BlockOrigin::Own, block_2_f.clone()).await.unwrap(); + + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2_f.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); - let mut block_builder = - client.new_block_at(block_4.header.hash(), Default::default(), false).unwrap(); block_builder .push_transfer(Transfer { from: AccountKeyring::Bob.into(), @@ -1869,9 +2079,9 @@ async fn follow_report_multiple_pruned_block() { nonce: 0, }) .unwrap(); - let block_5 = block_builder.build().unwrap().block; - let block_5_hash = block_5.header.hash(); - client.import(BlockOrigin::Own, block_5.clone()).await.unwrap(); + let block_3_f = block_builder.build().unwrap().block; + let block_3_f_hash = block_3_f.hash(); + client.import(BlockOrigin::Own, block_3_f.clone()).await.unwrap(); let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. @@ -1913,7 +2123,7 @@ async fn follow_report_multiple_pruned_block() { // The fork must also be reported. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_4_hash), + block_hash: format!("{:?}", block_2_f_hash), parent_block_hash: format!("{:?}", block_1_hash), new_runtime: None, with_runtime: false, @@ -1922,8 +2132,8 @@ async fn follow_report_multiple_pruned_block() { let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_5_hash), - parent_block_hash: format!("{:?}", block_4_hash), + block_hash: format!("{:?}", block_3_f_hash), + parent_block_hash: format!("{:?}", block_2_f_hash), new_runtime: None, with_runtime: false, }); @@ -1953,22 +2163,30 @@ async fn follow_report_multiple_pruned_block() { // Block tree: // - // finalized -> block 1 -> block 2 -> block 3 -> block 6 + // finalized -> block 1 -> block 2 -> block 3 -> block 4 // ^^^ finalized - // -> block 1 -> block 4 -> block 5 + // -> block 1 -> block 2_f -> block 3_f // - // Mark block 6 as finalized to force block 4 and 5 to get pruned. + // Mark block 4 as finalized to force block 2_f and 3_f to get pruned. - let block_6 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_6_hash = block_6.header.hash(); - client.import(BlockOrigin::Own, block_6.clone()).await.unwrap(); + let block_4 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_3.hash()) + .with_parent_block_number(3) + .build() + .unwrap() + .build() + .unwrap() + .block; - client.finalize_block(block_6_hash, None).unwrap(); + let block_4_hash = block_4.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + client.finalize_block(block_4_hash, None).unwrap(); // Check block 6. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { - block_hash: format!("{:?}", block_6_hash), + block_hash: format!("{:?}", block_4_hash), parent_block_hash: format!("{:?}", block_3_hash), new_runtime: None, with_runtime: false, @@ -1976,15 +2194,15 @@ async fn follow_report_multiple_pruned_block() { assert_eq!(event, expected); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::BestBlockChanged(BestBlockChanged { - best_block_hash: format!("{:?}", block_6_hash), + best_block_hash: format!("{:?}", block_4_hash), }); assert_eq!(event, expected); // Block 4 and 5 be reported as pruned, not just the stale head (block 5). let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Finalized(Finalized { - finalized_block_hashes: vec![format!("{:?}", block_6_hash)], - pruned_block_hashes: vec![format!("{:?}", block_4_hash), format!("{:?}", block_5_hash)], + finalized_block_hashes: vec![format!("{:?}", block_4_hash)], + pruned_block_hashes: vec![format!("{:?}", block_2_f_hash), format!("{:?}", block_3_f_hash)], }); assert_eq!(event, expected); } @@ -2052,7 +2270,14 @@ async fn pin_block_references() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let hash = block.header.hash(); let block_hash = format!("{:?}", hash); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); @@ -2089,8 +2314,15 @@ async fn pin_block_references() { // Add another 2 blocks and make sure we drop the subscription with the blocks pinned. let mut hashes = Vec::new(); for _ in 0..2 { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let hash = block.header.hash(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash = block.hash(); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); // Ensure the imported block is propagated for this subscription. @@ -2115,7 +2347,14 @@ async fn pin_block_references() { drop(sub); // The `chainHead` detects the subscription was terminated when it tries // to send another block. - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); for hash in &hashes { @@ -2146,7 +2385,14 @@ async fn follow_finalized_before_new_block() { .into_rpc(); // Make sure the block is imported for it to be pinned. - let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_1_hash = block_1.header.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); @@ -2191,8 +2437,15 @@ async fn follow_finalized_before_new_block() { }); assert_eq!(event, expected); - let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; - let block_2_hash = block_2.header.hash(); + let block_2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_2_hash = block_2.hash(); client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); // Triggering the `BlockImportNotification` notification for block 1 should have no effect @@ -2250,7 +2503,14 @@ async fn ensure_operation_limits_works() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); // Ensure the imported block is propagated and pinned for this subscription. @@ -2349,7 +2609,11 @@ async fn check_continue_operation() { let sub_id = serde_json::to_string(&sub_id).unwrap(); // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); builder.push_storage_change(b":m".to_vec(), Some(b"a".to_vec())).unwrap(); builder.push_storage_change(b":mo".to_vec(), Some(b"ab".to_vec())).unwrap(); builder.push_storage_change(b":moc".to_vec(), Some(b"abc".to_vec())).unwrap(); @@ -2528,7 +2792,11 @@ async fn stop_storage_operation() { let sub_id = serde_json::to_string(&sub_id).unwrap(); // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); builder.push_storage_change(b":m".to_vec(), Some(b"a".to_vec())).unwrap(); builder.push_storage_change(b":mo".to_vec(), Some(b"ab".to_vec())).unwrap(); let block = builder.build().unwrap().block; @@ -2612,7 +2880,7 @@ async fn stop_storage_operation() { #[tokio::test] async fn storage_closest_merkle_value() { - let (mut client, api, mut sub, sub_id, _) = setup_api().await; + let (mut client, api, mut sub, sub_id, block) = setup_api().await; /// The core of this test. /// @@ -2738,7 +3006,11 @@ async fn storage_closest_merkle_value() { } // Import a new block with storage changes. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); builder.push_storage_change(b":AAAA".to_vec(), Some(vec![1; 64])).unwrap(); builder.push_storage_change(b":AAAB".to_vec(), Some(vec![2; 64])).unwrap(); let block = builder.build().unwrap().block; @@ -2758,7 +3030,11 @@ async fn storage_closest_merkle_value() { let merkle_values_lhs = expect_merkle_request(&api, &mut sub, sub_id.clone(), block_hash).await; // Import a new block with and change AAAB value. - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); builder.push_storage_change(b":AAAA".to_vec(), Some(vec![1; 64])).unwrap(); builder.push_storage_change(b":AAAB".to_vec(), Some(vec![3; 64])).unwrap(); let block = builder.build().unwrap().block; diff --git a/substrate/client/rpc/src/chain/tests.rs b/substrate/client/rpc/src/chain/tests.rs index 75211a43bd9..cff5bf39811 100644 --- a/substrate/client/rpc/src/chain/tests.rs +++ b/substrate/client/rpc/src/chain/tests.rs @@ -20,7 +20,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use jsonrpsee::types::EmptyServerParams as EmptyParams; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sp_consensus::BlockOrigin; use sp_rpc::list::ListOrValue; use substrate_test_runtime_client::{ @@ -75,7 +75,14 @@ async fn should_return_a_block() { let mut client = Arc::new(substrate_test_runtime_client::new()); let api = new_full(client.clone(), test_executor()).into_rpc(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); @@ -152,7 +159,14 @@ async fn should_return_block_hash() { api.call("chain_getBlockHash", [ListOrValue::from(1_u64)]).await.unwrap(); assert_matches!(res, None); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); let res: ListOrValue> = @@ -197,7 +211,14 @@ async fn should_return_finalized_hash() { assert_eq!(res, client.genesis_hash()); // import new block - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); @@ -232,7 +253,14 @@ async fn test_head_subscription(method: &str) { let mut sub = { let api = new_full(client.clone(), test_executor()).into_rpc(); let sub = api.subscribe(method, EmptyParams::new()).await.unwrap(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); client.finalize_block(block_hash, None).unwrap(); diff --git a/substrate/client/rpc/src/dev/tests.rs b/substrate/client/rpc/src/dev/tests.rs index db6a9a119da..448d16274f2 100644 --- a/substrate/client/rpc/src/dev/tests.rs +++ b/substrate/client/rpc/src/dev/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::*; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use substrate_test_runtime_client::{prelude::*, runtime::Block}; @@ -27,7 +27,14 @@ async fn block_stats_work() { let mut client = Arc::new(substrate_test_runtime_client::new()); let api = >::new(client.clone(), DenyUnsafe::No).into_rpc(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; let (expected_witness_len, expected_witness_compact_len, expected_block_len) = { let genesis_hash = client.chain_info().genesis_hash; @@ -72,7 +79,14 @@ async fn deny_unsafe_works() { let mut client = Arc::new(substrate_test_runtime_client::new()); let api = >::new(client.clone(), DenyUnsafe::Yes).into_rpc(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; client.import(BlockOrigin::Own, block).await.unwrap(); let best_hash = client.info().best_hash; diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index 35352f6d890..594f51efba6 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -25,7 +25,7 @@ use jsonrpsee::{ core::Error as RpcError, types::{error::CallError as RpcCallError, EmptyServerParams as EmptyParams, ErrorObject}, }; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; use sp_core::{hash::H256, storage::ChildInfo}; @@ -218,7 +218,11 @@ async fn should_notify_about_storage_changes() { let sub = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await.unwrap(); // Cause a change: - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); builder .push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -263,7 +267,11 @@ async fn should_send_initial_storage_changes_and_notifications() { .await .unwrap(); - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); builder .push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -291,7 +299,11 @@ async fn should_query_storage() { let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let mut add_block = |index| { - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap(); // fake change: None -> None -> None builder .push(ExtrinsicBuilder::new_storage_change(vec![1], None).build()) diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 2386bebf24d..e5520eb21c3 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -69,7 +69,6 @@ sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-pr sc-rpc-server = { path = "../rpc-servers" } sc-rpc = { path = "../rpc" } sc-rpc-spec-v2 = { path = "../rpc-spec-v2" } -sc-block-builder = { path = "../block-builder" } sc-informant = { path = "../informant" } sc-telemetry = { path = "../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index da4a4f66e2a..9d51aae55b2 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -24,7 +24,6 @@ use log::{error, info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; use rand::Rng; -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof}; use sc_chain_spec::{resolve_state_version_from_wasm, BuildGenesisBlock}; use sc_client_api::{ backend::{ @@ -70,7 +69,7 @@ use sp_runtime::{ Block as BlockT, BlockIdTo, HashingFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, - Digest, Justification, Justifications, StateVersion, + Justification, Justifications, StateVersion, }; use sp_state_machine::{ prove_child_read, prove_range_read_with_child_with_size, prove_read, @@ -1402,46 +1401,6 @@ where } } -impl BlockBuilderProvider for Client -where - B: backend::Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static, - Block: BlockT, - Self: ChainHeaderBackend + ProvideRuntimeApi, - >::Api: ApiExt + BlockBuilderApi, -{ - fn new_block_at>( - &self, - parent: Block::Hash, - inherent_digests: Digest, - record_proof: R, - ) -> sp_blockchain::Result> { - sc_block_builder::BlockBuilder::new( - self, - parent, - self.expect_block_number_from_id(&BlockId::Hash(parent))?, - record_proof.into(), - inherent_digests, - &self.backend, - ) - } - - fn new_block( - &self, - inherent_digests: Digest, - ) -> sp_blockchain::Result> { - let info = self.chain_info(); - sc_block_builder::BlockBuilder::new( - self, - info.best_hash, - info.best_number, - RecordProof::No, - inherent_digests, - &self.backend, - ) - } -} - impl ExecutorProvider for Client where B: backend::Backend, diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index f8200875587..ba83bec8276 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -19,7 +19,7 @@ use async_channel::TryRecvError; use futures::executor::block_on; use parity_scale_codec::{Decode, Encode, Joiner}; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{ in_mem, BlockBackend, BlockchainEvents, ExecutorProvider, FinalityNotifications, HeaderBackend, StorageProvider, @@ -241,7 +241,14 @@ fn client_initializes_from_genesis_ok() { fn block_builder_works_with_no_transactions() { let mut client = substrate_test_runtime_client::new(); - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, block)).unwrap(); @@ -252,7 +259,11 @@ fn block_builder_works_with_no_transactions() { fn block_builder_works_with_transactions() { let mut client = substrate_test_runtime_client::new(); - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); builder .push_transfer(Transfer { @@ -307,7 +318,11 @@ fn block_builder_works_with_transactions() { #[test] fn block_builder_does_not_include_invalid() { let mut client = substrate_test_runtime_client::new(); - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); builder .push_transfer(Transfer { @@ -379,11 +394,25 @@ fn uncles_with_only_ancestors() { let mut client = substrate_test_runtime_client::new(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(*a1.header().number()) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let v: Vec = Vec::new(); assert_eq!(v, client.uncles(a2.hash(), 3).unwrap()); @@ -399,12 +428,21 @@ fn uncles_with_multiple_forks() { let mut client = substrate_test_runtime_client::new(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -412,8 +450,10 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -421,8 +461,10 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); // A3 -> A4 - let a4 = client - .new_block_at(a3.hash(), Default::default(), false) + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .with_parent_block_number(3) + .build() .unwrap() .build() .unwrap() @@ -430,8 +472,10 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); // A4 -> A5 - let a5 = client - .new_block_at(a4.hash(), Default::default(), false) + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .with_parent_block_number(4) + .build() .unwrap() .build() .unwrap() @@ -439,7 +483,12 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -453,8 +502,10 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -462,8 +513,10 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .with_parent_block_number(3) + .build() .unwrap() .build() .unwrap() @@ -471,7 +524,11 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap(); // // B2 -> C3 - let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -485,7 +542,11 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -527,11 +588,25 @@ fn finality_target_on_longest_chain_with_single_chain_3_blocks() { let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(*a1.header().number()) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let genesis_hash = client.chain_info().genesis_hash; @@ -554,12 +629,21 @@ fn finality_target_on_longest_chain_with_multiple_forks() { let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(*a1.header().number()) + .build() .unwrap() .build() .unwrap() @@ -567,8 +651,10 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(*a2.header().number()) + .build() .unwrap() .build() .unwrap() @@ -576,8 +662,10 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); // A3 -> A4 - let a4 = client - .new_block_at(a3.hash(), Default::default(), false) + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .with_parent_block_number(*a3.header().number()) + .build() .unwrap() .build() .unwrap() @@ -585,8 +673,10 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); // A4 -> A5 - let a5 = client - .new_block_at(a4.hash(), Default::default(), false) + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .with_parent_block_number(4) + .build() .unwrap() .build() .unwrap() @@ -594,7 +684,11 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -608,8 +702,10 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -617,8 +713,10 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .with_parent_block_number(3) + .build() .unwrap() .build() .unwrap() @@ -626,7 +724,12 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap(); // B2 -> C3 - let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); + // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -640,7 +743,12 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -771,13 +879,28 @@ fn finality_target_on_longest_chain_with_max_depth_higher_than_best() { // G -> A1 -> A2 let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); + let chain = client.chain_info(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let genesis_hash = client.chain_info().genesis_hash; @@ -793,30 +916,70 @@ fn finality_target_with_best_not_on_longest_chain() { // ^best let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); - let genesis_hash = client.chain_info().genesis_hash; + let chain = client.chain_info(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); // A3 -> A4 - let a4 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .with_parent_block_number(3) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); // A3 -> A5 - let a5 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .with_parent_block_number(4) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -829,7 +992,10 @@ fn finality_target_with_best_not_on_longest_chain() { let b2 = builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); - assert_eq!(a5.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!( + a5.hash(), + block_on(chain_select.finality_target(client.chain_info().genesis_hash, None)).unwrap() + ); assert_eq!(a5.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); assert_eq!(a5.hash(), block_on(chain_select.finality_target(a2.hash(), None)).unwrap()); assert_eq!(a5.hash(), block_on(chain_select.finality_target(a3.hash(), None)).unwrap()); @@ -837,8 +1003,10 @@ fn finality_target_with_best_not_on_longest_chain() { assert_eq!(a5.hash(), block_on(chain_select.finality_target(a5.hash(), None)).unwrap()); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -846,8 +1014,10 @@ fn finality_target_with_best_not_on_longest_chain() { block_on(client.import_as_best(BlockOrigin::Own, b3.clone())).unwrap(); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .with_parent_block_number(3) + .build() .unwrap() .build() .unwrap() @@ -861,7 +1031,10 @@ fn finality_target_with_best_not_on_longest_chain() { // double check that B3 is still the best... assert_eq!(client.info().best_hash, b3.hash()); - assert_eq!(b4.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!( + b4.hash(), + block_on(chain_select.finality_target(client.chain_info().genesis_hash, None)).unwrap() + ); assert_eq!(b4.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); assert!(block_on(chain_select.finality_target(a2.hash(), None)).is_err()); assert_eq!(b4.hash(), block_on(chain_select.finality_target(b2.hash(), None)).unwrap()); @@ -878,12 +1051,21 @@ fn import_with_justification() { let mut finality_notifications = client.finality_notification_stream(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -893,8 +1075,10 @@ fn import_with_justification() { // A2 -> A3 let justification = Justifications::from((TEST_ENGINE_ID, vec![1, 2, 3])); - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -924,24 +1108,30 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { let mut finality_notifications = client.finality_notification_stream(); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { @@ -979,24 +1169,30 @@ fn finalizing_diverged_block_should_trigger_reorg() { let mut finality_notifications = client.finality_notification_stream(); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { @@ -1009,8 +1205,10 @@ fn finalizing_diverged_block_should_trigger_reorg() { let b1 = b1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); - let b2 = client - .new_block_at(b1.hash(), Default::default(), false) + let b2 = BlockBuilderBuilder::new(&client) + .on_parent_block(b1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -1035,8 +1233,10 @@ fn finalizing_diverged_block_should_trigger_reorg() { assert_eq!(block_on(select_chain.best_chain()).unwrap().hash(), b2.hash()); // after we build B3 on top of B2 and import it, it should be the new best block - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -1067,32 +1267,40 @@ fn finality_notifications_content() { let mut finality_notifications = client.finality_notification_stream(); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { @@ -1105,16 +1313,20 @@ fn finality_notifications_content() { let b1 = b1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); - let b2 = client - .new_block_at(b1.hash(), Default::default(), false) + let b2 = BlockBuilderBuilder::new(&client) + .on_parent_block(b1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); - let mut c1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut c1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure B1 gets a different hash from A1 c1.push_transfer(Transfer { @@ -1127,7 +1339,12 @@ fn finality_notifications_content() { let c1 = c1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, c1.clone())).unwrap(); - let mut d3 = client.new_block_at(a2.hash(), Default::default(), false).unwrap(); + let mut d3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() + .unwrap(); + // needed to make sure D3 gets a different hash from A3 d3.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1139,8 +1356,10 @@ fn finality_notifications_content() { let d3 = d3.build().unwrap().block; block_on(client.import(BlockOrigin::Own, d3.clone())).unwrap(); - let d4 = client - .new_block_at(d3.hash(), Default::default(), false) + let d4 = BlockBuilderBuilder::new(&client) + .on_parent_block(d3.hash()) + .with_parent_block_number(3) + .build() .unwrap() .build() .unwrap() @@ -1200,8 +1419,10 @@ fn state_reverted_on_reorg() { // G -> A1 -> A2 // \ // -> B1 - let mut a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); a1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1213,8 +1434,10 @@ fn state_reverted_on_reorg() { let a1 = a1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1228,7 +1451,11 @@ fn state_reverted_on_reorg() { block_on(client.import_as_best(BlockOrigin::Own, b1.clone())).unwrap(); assert_eq!(950 * DOLLARS, current_balance(&client)); - let mut a2 = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); a2.push_transfer(Transfer { from: AccountKeyring::Alice.into(), to: AccountKeyring::Charlie.into(), @@ -1272,24 +1499,30 @@ fn doesnt_import_blocks_that_revert_finality() { // \ // -> B1 -> B2 -> B3 - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure B1 gets a different hash from A1 @@ -1303,8 +1536,10 @@ fn doesnt_import_blocks_that_revert_finality() { let b1 = b1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); - let b2 = client - .new_block_at(b1.hash(), Default::default(), false) + let b2 = BlockBuilderBuilder::new(&client) + .on_parent_block(b1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -1313,8 +1548,10 @@ fn doesnt_import_blocks_that_revert_finality() { // prepare B3 before we finalize A2, because otherwise we won't be able to // read changes trie configuration after A2 is finalized - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -1332,8 +1569,10 @@ fn doesnt_import_blocks_that_revert_finality() { // adding a C1 block which is lower than the last finalized should also // fail (with a cheaper check that doesn't require checking ancestry). - let mut c1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut c1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // needed to make sure C1 gets a different hash from A1 and B1 @@ -1352,8 +1591,10 @@ fn doesnt_import_blocks_that_revert_finality() { assert_eq!(import_err.to_string(), expected_err.to_string()); - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -1400,8 +1641,10 @@ fn respects_block_rules() { // B'[2] - block not ok, (incorrect fork) // build B[1] - let block_ok = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let block_ok = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() @@ -1419,8 +1662,10 @@ fn respects_block_rules() { assert_eq!(block_on(client.check_block(params)).unwrap(), ImportResult::imported(false)); // build B'[1] - let mut block_not_ok = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut block_not_ok = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); block_not_ok.push_storage_change(vec![0], Some(vec![1])).unwrap(); let block_not_ok = block_not_ok.build().unwrap().block; @@ -1443,7 +1688,11 @@ fn respects_block_rules() { block_on(client.import_as_final(BlockOrigin::Own, block_ok)).unwrap(); // And check good fork (build B[2]) - let mut block_ok = client.new_block_at(block_ok_1_hash, Default::default(), false).unwrap(); + let mut block_ok = BlockBuilderBuilder::new(&client) + .on_parent_block(block_ok_1_hash) + .with_parent_block_number(1) + .build() + .unwrap(); block_ok.push_storage_change(vec![0], Some(vec![2])).unwrap(); let block_ok = block_ok.build().unwrap().block; assert_eq!(*block_ok.header().number(), 2); @@ -1462,8 +1711,11 @@ fn respects_block_rules() { assert_eq!(block_on(client.check_block(params)).unwrap(), ImportResult::imported(false)); // And now try bad fork (build B'[2]) - let mut block_not_ok = - client.new_block_at(block_ok_1_hash, Default::default(), false).unwrap(); + let mut block_not_ok = BlockBuilderBuilder::new(&client) + .on_parent_block(block_ok_1_hash) + .with_parent_block_number(1) + .build() + .unwrap(); block_not_ok.push_storage_change(vec![0], Some(vec![3])).unwrap(); let block_not_ok = block_not_ok.build().unwrap().block; assert_eq!(*block_not_ok.header().number(), 2); @@ -1518,15 +1770,19 @@ fn returns_status_for_pruned_blocks() { let mut client = TestClientBuilder::with_backend(backend).build(); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); // b1 is created, but not imported @@ -1562,8 +1818,10 @@ fn returns_status_for_pruned_blocks() { ); assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::InChainWithState); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -1590,8 +1848,10 @@ fn returns_status_for_pruned_blocks() { ); assert_eq!(client.block_status(check_block_a2.hash).unwrap(), BlockStatus::InChainWithState); - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() @@ -1855,7 +2115,15 @@ fn cleans_up_closed_notification_sinks_on_block_import() { // for some reason I can't seem to use `ClientBlockImportExt` let bake_and_import_block = |client: &mut TestClient, origin| { - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let chain = client.chain_info(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; let (header, extrinsics) = block.deconstruct(); let mut import = BlockImportParams::new(origin, header); @@ -1898,25 +2166,32 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi let mut notification_stream = futures::executor::block_on_stream(client.import_notification_stream()); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::NetworkInitialSync, a1.clone())).unwrap(); - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::NetworkInitialSync, a2.clone())).unwrap(); - let mut b1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let mut b1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); + // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1928,8 +2203,10 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi let b1 = b1.build().unwrap().block; block_on(client.import(BlockOrigin::NetworkInitialSync, b1.clone())).unwrap(); - let b2 = client - .new_block_at(b1.hash(), Default::default(), false) + let b2 = BlockBuilderBuilder::new(&client) + .on_parent_block(b1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -1964,8 +2241,10 @@ fn use_dalek_ext_works() { ), ); - let a1 = client - .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap() .build() .unwrap() @@ -1988,12 +2267,21 @@ fn finalize_after_best_block_updates_best() { let mut client = substrate_test_runtime_client::new(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .with_parent_block_number(1) + .build() .unwrap() .build() .unwrap() @@ -2001,8 +2289,10 @@ fn finalize_after_best_block_updates_best() { block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .with_parent_block_number(2) + .build() .unwrap() .build() .unwrap() diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index e5ab01ffbf0..6b1a197440c 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -24,7 +24,7 @@ use futures::{ prelude::*, task::Poll, }; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::client::BlockchainEvents; use sc_transaction_pool::*; use sc_transaction_pool_api::{ @@ -1011,7 +1011,11 @@ fn import_notification_to_pool_maintain_works() { let mut import_stream = block_on_stream(client.import_notification_stream()); // Build the block with the transaction included - let mut block_builder = client.new_block(Default::default()).unwrap(); + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(best_hash) + .with_parent_block_number(0) + .build() + .unwrap(); block_builder.push(xt).unwrap(); let block = block_builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, block)).unwrap(); diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index c3f80acf09a..c122a2348b8 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -665,6 +665,34 @@ pub trait CallApiAt { ) -> Result<(), ApiError>; } +#[cfg(feature = "std")] +impl> CallApiAt for std::sync::Arc { + type StateBackend = T::StateBackend; + + fn call_api_at(&self, params: CallApiAtParams) -> Result, ApiError> { + (**self).call_api_at(params) + } + + fn runtime_version_at( + &self, + at_hash: ::Hash, + ) -> Result { + (**self).runtime_version_at(at_hash) + } + + fn state_at(&self, at: ::Hash) -> Result { + (**self).state_at(at) + } + + fn initialize_extensions( + &self, + at: ::Hash, + extensions: &mut Extensions, + ) -> Result<(), ApiError> { + (**self).initialize_extensions(at, extensions) + } +} + /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. #[cfg(feature = "std")] pub struct ApiRef<'a, T>(T, std::marker::PhantomData<&'a ()>); diff --git a/substrate/primitives/api/test/tests/runtime_calls.rs b/substrate/primitives/api/test/tests/runtime_calls.rs index 353be73dccc..e66be7f9bf1 100644 --- a/substrate/primitives/api/test/tests/runtime_calls.rs +++ b/substrate/primitives/api/test/tests/runtime_calls.rs @@ -17,6 +17,7 @@ use std::panic::UnwindSafe; +use sc_block_builder::BlockBuilderBuilder; use sp_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_runtime::{ traits::{HashingFor, Header as HeaderT}, @@ -31,7 +32,6 @@ use substrate_test_runtime_client::{ }; use codec::Encode; -use sc_block_builder::BlockBuilderProvider; use sp_consensus::SelectChain; use substrate_test_runtime_client::sc_executor::WasmExecutor; @@ -105,9 +105,12 @@ fn record_proof_works() { .into_unchecked_extrinsic(); // Build the block and record proof - let mut builder = client - .new_block_at(client.chain_info().best_hash, Default::default(), true) - .expect("Creates block builder"); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .enable_proof_recording() + .build() + .unwrap(); builder.push(transaction.clone()).unwrap(); let (block, _, proof) = builder.build().expect("Bake block").into_inner(); diff --git a/substrate/test-utils/runtime/client/src/block_builder_ext.rs b/substrate/test-utils/runtime/client/src/block_builder_ext.rs index 78863209e33..f7bf76b017e 100644 --- a/substrate/test-utils/runtime/client/src/block_builder_ext.rs +++ b/substrate/test-utils/runtime/client/src/block_builder_ext.rs @@ -17,10 +17,8 @@ //! Block Builder extensions for tests. -use sc_client_api::backend; -use sp_api::{ApiExt, ProvideRuntimeApi}; - use sc_block_builder::BlockBuilderApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use substrate_test_runtime::*; /// Extension trait for test block builder. @@ -45,12 +43,12 @@ pub trait BlockBuilderExt { ) -> Result<(), sp_blockchain::Error>; } -impl<'a, A, B> BlockBuilderExt - for sc_block_builder::BlockBuilder<'a, substrate_test_runtime::Block, A, B> +impl<'a, A> BlockBuilderExt for sc_block_builder::BlockBuilder<'a, substrate_test_runtime::Block, A> where - A: ProvideRuntimeApi + 'a, + A: ProvideRuntimeApi + + sp_api::CallApiAt + + 'a, A::Api: BlockBuilderApi + ApiExt, - B: backend::Backend, { fn push_transfer( &mut self, diff --git a/substrate/test-utils/runtime/client/src/trait_tests.rs b/substrate/test-utils/runtime/client/src/trait_tests.rs index 5fce7a2860b..6f6bb5c36ee 100644 --- a/substrate/test-utils/runtime/client/src/trait_tests.rs +++ b/substrate/test-utils/runtime/client/src/trait_tests.rs @@ -26,14 +26,14 @@ use crate::{ AccountKeyring, BlockBuilderExt, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt, }; use futures::executor::block_on; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{ backend, blockchain::{Backend as BlockChainBackendT, HeaderBackend}, }; use sp_consensus::BlockOrigin; use sp_runtime::traits::Block as BlockT; -use substrate_test_runtime::{self, Transfer}; +use substrate_test_runtime::Transfer; /// helper to test the `leaves` implementation for various backends pub fn test_leaves_for_backend(backend: Arc) @@ -54,13 +54,24 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![genesis_hash]); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); assert_eq!(blockchain.leaves().unwrap(), vec![a1.hash()]); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -70,8 +81,11 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a2.hash()]); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -81,8 +95,11 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a3.hash()]); // A3 -> A4 - let a4 = client - .new_block_at(a3.hash(), Default::default(), false) + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -91,8 +108,11 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a4.hash()]); // A4 -> A5 - let a5 = client - .new_block_at(a4.hash(), Default::default(), false) + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -102,7 +122,12 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash()]); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder @@ -118,8 +143,11 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b2.hash()]); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -129,8 +157,11 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b3.hash()]); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -139,7 +170,12 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash()]); // // B2 -> C3 - let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -154,7 +190,12 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash(), c3.hash()]); // A1 -> D2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -182,14 +223,26 @@ where let mut client = TestClientBuilder::with_backend(backend.clone()).build(); let blockchain = backend.blockchain(); + let genesis_hash = client.chain_info().genesis_hash; // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -197,8 +250,11 @@ where block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -206,8 +262,11 @@ where block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); // A3 -> A4 - let a4 = client - .new_block_at(a3.hash(), Default::default(), false) + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -215,8 +274,11 @@ where block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); // A4 -> A5 - let a5 = client - .new_block_at(a4.hash(), Default::default(), false) + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -224,7 +286,12 @@ where block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -238,8 +305,11 @@ where block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -247,8 +317,11 @@ where block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -256,7 +329,12 @@ where block_on(client.import(BlockOrigin::Own, b4)).unwrap(); // // B2 -> C3 - let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -270,7 +348,12 @@ where block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -309,14 +392,26 @@ where // A1 -> D2 let mut client = TestClientBuilder::with_backend(backend.clone()).build(); let blockchain = backend.blockchain(); + let genesis_hash = client.chain_info().genesis_hash; // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = BlockBuilderBuilder::new(&client) + .on_parent_block(genesis_hash) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client - .new_block_at(a1.hash(), Default::default(), false) + let a2 = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -324,8 +419,11 @@ where block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); // A2 -> A3 - let a3 = client - .new_block_at(a2.hash(), Default::default(), false) + let a3 = BlockBuilderBuilder::new(&client) + .on_parent_block(a2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -333,8 +431,11 @@ where block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); // A3 -> A4 - let a4 = client - .new_block_at(a3.hash(), Default::default(), false) + let a4 = BlockBuilderBuilder::new(&client) + .on_parent_block(a3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -342,8 +443,11 @@ where block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); // A4 -> A5 - let a5 = client - .new_block_at(a4.hash(), Default::default(), false) + let a5 = BlockBuilderBuilder::new(&client) + .on_parent_block(a4.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -351,7 +455,12 @@ where block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -365,8 +474,11 @@ where block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); // B2 -> B3 - let b3 = client - .new_block_at(b2.hash(), Default::default(), false) + let b3 = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -374,8 +486,11 @@ where block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); // B3 -> B4 - let b4 = client - .new_block_at(b3.hash(), Default::default(), false) + let b4 = BlockBuilderBuilder::new(&client) + .on_parent_block(b3.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() .unwrap() .build() .unwrap() @@ -383,7 +498,12 @@ where block_on(client.import(BlockOrigin::Own, b4)).unwrap(); // // B2 -> C3 - let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(b2.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -397,7 +517,12 @@ where block_on(client.import(BlockOrigin::Own, c3)).unwrap(); // A1 -> D2 - let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(a1.hash()) + .fetch_parent_block_number(&client) + .unwrap() + .build() + .unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 845ef2c4456..6b963deb589 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -1020,7 +1020,7 @@ mod tests { use super::*; use codec::Encode; use frame_support::dispatch::DispatchInfo; - use sc_block_builder::BlockBuilderProvider; + use sc_block_builder::BlockBuilderBuilder; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext}; @@ -1052,7 +1052,11 @@ mod tests { // Create a block that sets the `:heap_pages` to 32 pages of memory which corresponds to // ~2048k of heap memory. let (new_at_hash, block) = { - let mut builder = client.new_block(Default::default()).unwrap(); + let mut builder = BlockBuilderBuilder::new(&client) + .on_parent_block(best_hash) + .with_parent_block_number(0) + .build() + .unwrap(); builder.push_storage_change(HEAP_PAGES.to_vec(), Some(32u64.encode())).unwrap(); let block = builder.build().unwrap().block; let hash = block.header.hash(); diff --git a/substrate/utils/frame/benchmarking-cli/src/block/bench.rs b/substrate/utils/frame/benchmarking-cli/src/block/bench.rs index c9a7fb1ad33..a028c7d438e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/block/bench.rs @@ -20,7 +20,7 @@ use codec::DecodeAll; use frame_support::weights::constants::WEIGHT_REF_TIME_PER_NANOS; use frame_system::ConsumedWeight; -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_block_builder::BlockBuilderApi; use sc_cli::{Error, Result}; use sc_client_api::{ Backend as ClientBackend, BlockBackend, HeaderBackend, StorageProvider, UsageProvider, @@ -71,8 +71,7 @@ impl Benchmark where Block: BlockT, BA: ClientBackend, - C: BlockBuilderProvider - + ProvideRuntimeApi + C: ProvideRuntimeApi + StorageProvider + UsageProvider + BlockBackend diff --git a/substrate/utils/frame/benchmarking-cli/src/block/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/block/cmd.rs index ee12c1c5dac..e28688caa2d 100644 --- a/substrate/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -18,7 +18,7 @@ //! Contains the [`BlockCmd`] as entry point for the CLI to execute //! the *block* benchmark. -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_block_builder::BlockBuilderApi; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; use sp_api::{ApiExt, ProvideRuntimeApi}; @@ -84,8 +84,7 @@ impl BlockCmd { where Block: BlockT, BA: ClientBackend, - C: BlockBuilderProvider - + BlockBackend + C: BlockBackend + ProvideRuntimeApi + StorageProvider + UsageProvider diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 693b9f99f08..f0a7436dc72 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -17,10 +17,10 @@ //! Contains the core benchmarking logic. -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; use sc_cli::{Error, Result}; -use sc_client_api::Backend as ClientBackend; -use sp_api::{ApiExt, Core, ProvideRuntimeApi}; +use sc_client_api::UsageProvider; +use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::{ ApplyExtrinsicFailed::Validity, Error::{ApplyExtrinsicFailed, RuntimeApiError}, @@ -61,20 +61,20 @@ pub struct BenchmarkParams { pub(crate) type BenchRecord = Vec; /// Holds all objects needed to run the *overhead* benchmarks. -pub(crate) struct Benchmark { +pub(crate) struct Benchmark { client: Arc, params: BenchmarkParams, inherent_data: sp_inherents::InherentData, digest_items: Vec, - _p: PhantomData<(Block, BA)>, + _p: PhantomData, } -impl Benchmark +impl Benchmark where Block: BlockT, - BA: ClientBackend, - C: BlockBuilderProvider - + ProvideRuntimeApi + C: ProvideRuntimeApi + + CallApiAt + + UsageProvider + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { @@ -129,7 +129,13 @@ where &self, ext_builder: Option<&dyn ExtrinsicBuilder>, ) -> Result<(Block, Option)> { - let mut builder = self.client.new_block(Digest { logs: self.digest_items.clone() })?; + let chain = self.client.usage_info().chain; + let mut builder = BlockBuilderBuilder::new(&*self.client) + .on_parent_block(chain.best_hash) + .with_parent_block_number(chain.best_number) + .with_inherent_digests(Digest { logs: self.digest_items.clone() }) + .build()?; + // Create and insert the inherents. let inherents = builder.create_inherents(self.inherent_data.clone())?; for inherent in inherents { diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 4c3a6ed1bcd..99c0230617c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -15,10 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_block_builder::BlockBuilderApi; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_client_api::Backend as ClientBackend; -use sp_api::{ApiExt, ProvideRuntimeApi}; +use sc_client_api::UsageProvider; +use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi}; use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; @@ -84,7 +84,7 @@ impl ExtrinsicCmd { /// Benchmark the execution time of a specific type of extrinsic. /// /// The output will be printed to console. - pub fn run( + pub fn run( &self, client: Arc, inherent_data: sp_inherents::InherentData, @@ -93,9 +93,9 @@ impl ExtrinsicCmd { ) -> Result<()> where Block: BlockT, - BA: ClientBackend, - C: BlockBuilderProvider - + ProvideRuntimeApi + C: ProvideRuntimeApi + + CallApiAt + + UsageProvider + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 5a4c37b1f6f..4fa8cecf2f7 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -18,11 +18,11 @@ //! Contains the [`OverheadCmd`] as entry point for the CLI to execute //! the *overhead* benchmarks. -use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_block_builder::BlockBuilderApi; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_client_api::Backend as ClientBackend; +use sc_client_api::UsageProvider; use sc_service::Configuration; -use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi}; use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; @@ -97,7 +97,7 @@ impl OverheadCmd { /// /// Writes the results to console and into two instances of the /// `weights.hbs` template, one for each benchmark. - pub fn run( + pub fn run( &self, cfg: Configuration, client: Arc, @@ -107,9 +107,9 @@ impl OverheadCmd { ) -> Result<()> where Block: BlockT, - BA: ClientBackend, - C: BlockBuilderProvider - + ProvideRuntimeApi + C: ProvideRuntimeApi + + CallApiAt + + UsageProvider + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { -- GitLab From 21fbc00d04f511df4c374edd3a2f99d73207be50 Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Fri, 3 Nov 2023 21:38:26 +0200 Subject: [PATCH 437/633] Identity pallet improvements (#2048) This PR is a follow up to #1661 - [x] rename the `simple` module to `legacy` - [x] fix benchmarks to disregard the number of additional fields - [x] change the storage deposits to charge per encoded byte of the identity information instance, removing the need for `fn additional(&self) -> usize` in `IdentityInformationProvider` - [x] ~add an extrinsic to rejig deposits to account for the change above~ - [ ] ~ensure through proper configuration that the new byte-based deposit is always lower than whatever is reserved now~ - [x] remove `IdentityFields` from the `set_fields` extrinsic signature, as per [this discussion](https://github.com/paritytech/polkadot-sdk/pull/1661#discussion_r1371703403) > ensure through proper configuration that the new byte-based deposit is always lower than whatever is reserved now Not sure this is needed anymore. If the new deposits are higher than what is currently on chain and users don't have enough funds to reserve what is needed, the extrinisc fails and they're basically grandfathered and frozen until they add more funds and/or make a change to their identity. This behavior seems fine to me. Original idea [here](https://github.com/paritytech/polkadot-sdk/pull/1661#issuecomment-1779606319). > add an extrinsic to rejig deposits to account for the change above This was initially implemented but now removed from this PR in favor of the implementation detailed [here](https://github.com/paritytech/polkadot-sdk/pull/2088). --------- Signed-off-by: georgepisaltu Co-authored-by: joepetrowski --- polkadot/runtime/rococo/src/lib.rs | 7 +- .../rococo/src/weights/pallet_identity.rs | 31 +- polkadot/runtime/westend/src/lib.rs | 7 +- .../westend/src/weights/pallet_identity.rs | 30 +- substrate/bin/node/runtime/src/impls.rs | 5 +- substrate/bin/node/runtime/src/lib.rs | 11 +- substrate/frame/alliance/src/lib.rs | 18 +- substrate/frame/alliance/src/mock.rs | 68 +++-- substrate/frame/alliance/src/tests.rs | 20 +- substrate/frame/identity/src/benchmarking.rs | 44 +-- .../identity/src/{simple.rs => legacy.rs} | 32 ++- substrate/frame/identity/src/lib.rs | 120 +++----- substrate/frame/identity/src/tests.rs | 269 +++++++++++------- substrate/frame/identity/src/types.rs | 84 ++---- substrate/frame/identity/src/weights.rs | 72 ++--- 15 files changed, 356 insertions(+), 462 deletions(-) rename substrate/frame/identity/src/{simple.rs => legacy.rs} (89%) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index b127eda3ba9..257f364dca0 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -76,7 +76,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; -use pallet_identity::simple::IdentityInfo; +use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; @@ -596,7 +596,7 @@ impl claims::Config for Runtime { parameter_types! { // Minimum 100 bytes/ROC 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 ByteDeposit: Balance = deposit(0, 1); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -607,10 +607,9 @@ impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; + type ByteDeposit = ByteDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index e10c042dde6..e8c25269ac3 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -65,8 +65,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` @@ -75,8 +74,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 2_307 .saturating_add(Weight::from_parts(92_753, 0).saturating_mul(r.into())) - // Standard Error: 450 - .saturating_add(Weight::from_parts(449_529, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,8 +127,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn clear_identity(_r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -140,8 +136,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 1_353 .saturating_add(Weight::from_parts(1_074_019, 0).saturating_mul(s.into())) - // Standard Error: 1_353 - .saturating_add(Weight::from_parts(229_947, 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()))) @@ -151,8 +145,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -161,16 +154,14 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 2_214 .saturating_add(Weight::from_parts(83_822, 0).saturating_mul(r.into())) - // Standard Error: 432 - .saturating_add(Weight::from_parts(458_801, 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 { + fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` @@ -179,8 +170,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 2_528 .saturating_add(Weight::from_parts(85_593, 0).saturating_mul(r.into())) - // Standard Error: 493 - .saturating_add(Weight::from_parts(468_140, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -234,8 +223,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -244,8 +232,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 2_881 .saturating_add(Weight::from_parts(109_812, 0).saturating_mul(r.into())) - // Standard Error: 533 - .saturating_add(Weight::from_parts(733_244, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -259,8 +245,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -271,8 +256,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(15_486, 0).saturating_mul(r.into())) // Standard Error: 1_275 .saturating_add(Weight::from_parts(1_085_117, 0).saturating_mul(s.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(228_226, 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()))) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9dfc3389d57..ec94973af4f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -40,7 +40,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; -use pallet_identity::simple::IdentityInfo; +use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; @@ -863,7 +863,7 @@ where 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 ByteDeposit: Balance = deposit(0, 1); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -875,10 +875,9 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type Slashed = (); type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; + type ByteDeposit = ByteDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type ForceOrigin = EitherOf, GeneralAdmin>; diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index 8c11482ebdc..dea631b9316 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -68,8 +68,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` @@ -78,8 +77,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 7_269 .saturating_add(Weight::from_parts(250_439, 0).saturating_mul(r.into())) - // Standard Error: 1_418 - .saturating_add(Weight::from_parts(483_981, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,8 +130,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -145,8 +141,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(475_120, 0).saturating_mul(r.into())) // Standard Error: 4_092 .saturating_add(Weight::from_parts(1_348_869, 0).saturating_mul(s.into())) - // Standard Error: 4_092 - .saturating_add(Weight::from_parts(314_033, 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()))) @@ -156,8 +150,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -166,16 +159,13 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 7_973 .saturating_add(Weight::from_parts(124_283, 0).saturating_mul(r.into())) - // Standard Error: 1_555 - .saturating_add(Weight::from_parts(512_825, 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 { + fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` @@ -184,8 +174,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 5_154 .saturating_add(Weight::from_parts(147_560, 0).saturating_mul(r.into())) - // Standard Error: 1_005 - .saturating_add(Weight::from_parts(490_754, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -239,8 +227,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -249,8 +236,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 11003)) // Standard Error: 10_027 .saturating_add(Weight::from_parts(154_816, 0).saturating_mul(r.into())) - // Standard Error: 1_855 - .saturating_add(Weight::from_parts(803_084, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -264,8 +249,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// 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 { + fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -276,8 +260,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(666_376, 0).saturating_mul(r.into())) // Standard Error: 4_433 .saturating_add(Weight::from_parts(1_396_065, 0).saturating_mul(s.into())) - // Standard Error: 4_433 - .saturating_add(Weight::from_parts(300_762, 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()))) diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 430a1ac2824..717fbeadada 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -26,6 +26,7 @@ use frame_support::{ }; use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider}; use pallet_asset_tx_payment::HandleCredit; +use pallet_identity::legacy::IdentityField; use sp_std::prelude::*; use crate::{ @@ -56,8 +57,8 @@ impl HandleCredit for CreditToBlockAuthor { pub struct AllianceIdentityVerifier; impl IdentityVerifier for AllianceIdentityVerifier { - fn has_identity(who: &AccountId, fields: u64) -> bool { - crate::Identity::has_identity(who, fields) + fn has_required_identities(who: &AccountId) -> bool { + crate::Identity::has_identity(who, (IdentityField::Display | IdentityField::Web).bits()) } fn has_good_judgement(who: &AccountId) -> bool { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 127faec3562..620e89a65e5 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -60,7 +60,7 @@ use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; -use pallet_identity::simple::IdentityInfo; +use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; @@ -1459,8 +1459,10 @@ impl pallet_grandpa::Config for Runtime { } parameter_types! { - pub const BasicDeposit: Balance = 10 * DOLLARS; // 258 bytes on-chain - pub const FieldDeposit: Balance = 250 * CENTS; // 66 bytes on-chain + // difference of 26 bytes on-chain for the registration and 9 bytes on-chain for the identity + // information, already accounted for by the byte deposit + pub const BasicDeposit: Balance = deposit(1, 17); + pub const ByteDeposit: Balance = deposit(0, 1); pub const SubAccountDeposit: Balance = 2 * DOLLARS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -1471,10 +1473,9 @@ impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; + type ByteDeposit = ByteDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index f3ff03780f5..d4703db68db 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -112,7 +112,6 @@ use frame_support::{ }, weights::Weight, }; -use pallet_identity::simple::IdentityField; use scale_info::TypeInfo; pub use pallet::*; @@ -135,9 +134,9 @@ type NegativeImbalanceOf = <>::Currency as Currency< /// Interface required for identity verification. pub trait IdentityVerifier { - /// Function that returns whether an account has an identity registered with the identity - /// provider. - fn has_identity(who: &AccountId, fields: u64) -> bool; + /// Function that returns whether an account has the required identities registered with the + /// identity provider. + fn has_required_identities(who: &AccountId) -> bool; /// Whether an account has been deemed "good" by the provider. fn has_good_judgement(who: &AccountId) -> bool; @@ -149,7 +148,7 @@ pub trait IdentityVerifier { /// The non-provider. Imposes no restrictions on account identity. impl IdentityVerifier for () { - fn has_identity(_who: &AccountId, _fields: u64) -> bool { + fn has_required_identities(_who: &AccountId) -> bool { true } @@ -339,7 +338,7 @@ pub mod pallet { /// Balance is insufficient for the required deposit. InsufficientFunds, /// The account's identity does not have display field and website field. - WithoutIdentityDisplayAndWebsite, + WithoutRequiredIdentityFields, /// The account's identity has no good judgement. WithoutGoodIdentityJudgement, /// The proposal hash is not found. @@ -1082,13 +1081,10 @@ impl, I: 'static> Pallet { } fn has_identity(who: &T::AccountId) -> DispatchResult { - const IDENTITY_FIELD_DISPLAY: u64 = IdentityField::Display as u64; - const IDENTITY_FIELD_WEB: u64 = IdentityField::Web as u64; - let judgement = |who: &T::AccountId| -> DispatchResult { ensure!( - T::IdentityVerifier::has_identity(who, IDENTITY_FIELD_DISPLAY | IDENTITY_FIELD_WEB), - Error::::WithoutIdentityDisplayAndWebsite + T::IdentityVerifier::has_required_identities(who), + Error::::WithoutRequiredIdentityFields ); ensure!( T::IdentityVerifier::has_good_judgement(who), diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index a5970bc7af6..ace5214f145 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -31,7 +31,10 @@ pub use frame_support::{ BoundedVec, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use pallet_identity::{simple::IdentityInfo, Data, Judgement}; +use pallet_identity::{ + legacy::{IdentityField, IdentityInfo}, + Data, Judgement, +}; pub use crate as pallet_alliance; @@ -96,9 +99,9 @@ impl pallet_collective::Config for Test { } parameter_types! { - pub const BasicDeposit: u64 = 10; - pub const FieldDeposit: u64 = 10; - pub const SubAccountDeposit: u64 = 10; + pub const BasicDeposit: u64 = 100; + pub const ByteDeposit: u64 = 10; + pub const SubAccountDeposit: u64 = 100; pub const MaxSubAccounts: u32 = 2; pub const MaxAdditionalFields: u32 = 2; pub const MaxRegistrars: u32 = 20; @@ -117,10 +120,9 @@ impl pallet_identity::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; + type ByteDeposit = ByteDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = (); @@ -131,8 +133,8 @@ impl pallet_identity::Config for Test { pub struct AllianceIdentityVerifier; impl IdentityVerifier for AllianceIdentityVerifier { - fn has_identity(who: &AccountId, fields: u64) -> bool { - Identity::has_identity(who, fields) + fn has_required_identities(who: &AccountId) -> bool { + Identity::has_identity(who, (IdentityField::Display | IdentityField::Web).bits()) } fn has_good_judgement(who: &AccountId) -> bool { @@ -232,20 +234,40 @@ frame_support::construct_runtime!( } ); +fn test_identity_info() -> IdentityInfo { + IdentityInfo { + additional: BoundedVec::default(), + display: Data::Raw(b"name".to_vec().try_into().unwrap()), + legal: Data::default(), + web: Data::Raw(b"website".to_vec().try_into().unwrap()), + riot: Data::default(), + email: Data::default(), + pgp_fingerprint: None, + image: Data::default(), + twitter: Data::default(), + } +} + +pub(super) fn test_identity_info_deposit() -> ::Balance { + let basic_deposit: u64 = ::BasicDeposit::get(); + let byte_deposit: u64 = ::ByteDeposit::get(); + byte_deposit * test_identity_info().encoded_size() as u64 + basic_deposit +} + pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![ - (1, 50), - (2, 50), - (3, 50), - (4, 50), - (5, 30), - (6, 50), - (7, 50), - (8, 50), - (9, 50), + (1, 1000), + (2, 1000), + (3, 1000), + (4, 1000), + (5, test_identity_info_deposit() + 10), + (6, 1000), + (7, 1000), + (8, 1000), + (9, 1000), ], } .assimilate_storage(&mut t) @@ -263,17 +285,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext.execute_with(|| { assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 1)); - let info = IdentityInfo { - additional: BoundedVec::default(), - display: Data::Raw(b"name".to_vec().try_into().unwrap()), - legal: Data::default(), - web: Data::Raw(b"website".to_vec().try_into().unwrap()), - riot: Data::default(), - email: Data::default(), - pgp_fingerprint: None, - image: Data::default(), - twitter: Data::default(), - }; + let info = test_identity_info(); assert_ok!(Identity::set_identity(RuntimeOrigin::signed(1), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( RuntimeOrigin::signed(1), diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index 098fd86bbae..8011627b237 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -105,6 +105,9 @@ fn init_members_works() { #[test] fn disband_works() { new_test_ext().execute_with(|| { + let id_deposit = test_identity_info_deposit(); + let expected_join_deposit = ::AllyDeposit::get(); + assert_eq!(Balances::free_balance(9), 1000 - id_deposit); // ensure alliance is set assert_eq!(Alliance::voting_members(), vec![1, 2, 3]); @@ -113,10 +116,10 @@ fn disband_works() { assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // join alliance and reserve funds - assert_eq!(Balances::free_balance(9), 40); + assert_eq!(Balances::free_balance(9), 1000 - id_deposit); assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(9))); - assert_eq!(Alliance::deposit_of(9), Some(25)); - assert_eq!(Balances::free_balance(9), 15); + assert_eq!(Alliance::deposit_of(9), Some(expected_join_deposit)); + assert_eq!(Balances::free_balance(9), 1000 - id_deposit - expected_join_deposit); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); // fails without root @@ -146,7 +149,7 @@ fn disband_works() { // assert a retiring member from the previous Alliance not removed assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // deposit unreserved - assert_eq!(Balances::free_balance(9), 40); + assert_eq!(Balances::free_balance(9), 1000 - id_deposit); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::AllianceDisbanded { fellow_members: 2, @@ -358,6 +361,9 @@ fn remove_announcement_works() { #[test] fn join_alliance_works() { new_test_ext().execute_with(|| { + let id_deposit = test_identity_info_deposit(); + let join_deposit = ::AllyDeposit::get(); + assert_eq!(Balances::free_balance(9), 1000 - id_deposit); // check already member assert_noop!( Alliance::join_alliance(RuntimeOrigin::signed(1)), @@ -384,8 +390,10 @@ fn join_alliance_works() { Error::::InsufficientFunds ); + assert_eq!(Balances::free_balance(4), 1000 - id_deposit); // success to submit assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); + assert_eq!(Balances::free_balance(4), 1000 - id_deposit - join_deposit); assert_eq!(Alliance::deposit_of(4), Some(25)); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); @@ -405,7 +413,7 @@ fn join_alliance_works() { #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( Alliance::join_alliance(RuntimeOrigin::signed(7)), - Error::::WithoutIdentityDisplayAndWebsite + Error::::WithoutRequiredIdentityFields ); }); } @@ -460,7 +468,7 @@ fn nominate_ally_works() { #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( Alliance::join_alliance(RuntimeOrigin::signed(7)), - Error::::WithoutIdentityDisplayAndWebsite + Error::::WithoutRequiredIdentityFields ); }); } diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 16ce4d8246e..3d976bd6c88 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -22,7 +22,6 @@ use super::*; use crate::Pallet as Identity; -use enumflags2::BitFlag; use frame_benchmarking::{ account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, }; @@ -49,9 +48,7 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, registrar_lookup)?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; - let fields = IdentityFields( - ::IdentityField::all(), - ); + let fields = T::IdentityInformation::all_fields(); Identity::::set_fields(RawOrigin::Signed(registrar.clone()).into(), i, fields)?; } @@ -77,7 +74,7 @@ fn create_sub_accounts( // Set identity so `set_subs` does not fail. if IdentityOf::::get(who).is_none() { let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); - let info = T::IdentityInformation::create_identity_info(1); + let info = T::IdentityInformation::create_identity_info(); Identity::::set_identity(who_origin.into(), Box::new(info))?; } @@ -118,10 +115,7 @@ mod benchmarks { } #[benchmark] - fn set_identity( - r: Linear<1, { T::MaxRegistrars::get() }>, - x: Linear<0, { T::MaxAdditionalFields::get() }>, - ) -> Result<(), BenchmarkError> { + fn set_identity(r: Linear<1, { T::MaxRegistrars::get() }>) -> Result<(), BenchmarkError> { add_registrars::(r)?; let caller: T::AccountId = whitelisted_caller(); @@ -131,7 +125,7 @@ mod benchmarks { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Add an initial identity - let initial_info = T::IdentityInformation::create_identity_info(1); + let initial_info = T::IdentityInformation::create_identity_info(); Identity::::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?; // User requests judgement from all the registrars, and they approve @@ -154,7 +148,7 @@ mod benchmarks { #[extrinsic_call] _( RawOrigin::Signed(caller.clone()), - Box::new(T::IdentityInformation::create_identity_info(x)), + Box::new(T::IdentityInformation::create_identity_info()), ); assert_last_event::(Event::::IdentitySet { who: caller }.into()); @@ -201,7 +195,6 @@ mod benchmarks { 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 = @@ -216,7 +209,7 @@ mod benchmarks { let _ = add_sub_accounts::(&caller, s)?; // Create their main identity with x additional fields - let info = T::IdentityInformation::create_identity_info(x); + let info = T::IdentityInformation::create_identity_info(); Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve @@ -245,10 +238,7 @@ mod benchmarks { } #[benchmark] - fn request_judgement( - r: Linear<1, { T::MaxRegistrars::get() }>, - x: Linear<0, { T::MaxAdditionalFields::get() }>, - ) -> Result<(), BenchmarkError> { + fn request_judgement(r: Linear<1, { T::MaxRegistrars::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -256,7 +246,7 @@ mod benchmarks { add_registrars::(r)?; // Create their main identity with x additional fields - let info = T::IdentityInformation::create_identity_info(x); + let info = T::IdentityInformation::create_identity_info(); let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info))?; @@ -272,10 +262,7 @@ mod benchmarks { } #[benchmark] - fn cancel_request( - r: Linear<1, { T::MaxRegistrars::get() }>, - x: Linear<0, { T::MaxAdditionalFields::get() }>, - ) -> Result<(), BenchmarkError> { + fn cancel_request(r: Linear<1, { T::MaxRegistrars::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -283,7 +270,7 @@ mod benchmarks { add_registrars::(r)?; // Create their main identity with x additional fields - let info = T::IdentityInformation::create_identity_info(x); + let info = T::IdentityInformation::create_identity_info(); let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info))?; @@ -367,15 +354,12 @@ mod benchmarks { .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; - let fields = IdentityFields( - ::IdentityField::all(), - ); - let registrars = Registrars::::get(); ensure!( registrars[r as usize].as_ref().unwrap().fields == Default::default(), "fields already set." ); + let fields = T::IdentityInformation::all_fields(); #[extrinsic_call] _(RawOrigin::Signed(caller), r, fields); @@ -392,7 +376,6 @@ mod benchmarks { #[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); @@ -407,7 +390,7 @@ mod benchmarks { add_registrars::(r)?; - let info = T::IdentityInformation::create_identity_info(x); + let info = T::IdentityInformation::create_identity_info(); let info_hash = T::Hashing::hash_of(&info); Identity::::set_identity(user_origin.clone(), Box::new(info))?; @@ -430,7 +413,6 @@ mod benchmarks { 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)?; @@ -440,7 +422,7 @@ mod benchmarks { let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); - let info = T::IdentityInformation::create_identity_info(x); + let info = T::IdentityInformation::create_identity_info(); Identity::::set_identity(target_origin.clone(), Box::new(info.clone()))?; let _ = add_sub_accounts::(&target, s)?; diff --git a/substrate/frame/identity/src/simple.rs b/substrate/frame/identity/src/legacy.rs similarity index 89% rename from substrate/frame/identity/src/simple.rs rename to substrate/frame/identity/src/legacy.rs index db5ecf3b1c9..a7953f7e178 100644 --- a/substrate/frame/identity/src/simple.rs +++ b/substrate/frame/identity/src/legacy.rs @@ -16,13 +16,15 @@ // limitations under the License. use codec::{Decode, Encode, MaxEncodedLen}; +#[cfg(feature = "runtime-benchmarks")] +use enumflags2::BitFlag; use enumflags2::{bitflags, BitFlags}; use frame_support::{traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use scale_info::{build::Variants, Path, Type, TypeInfo}; use sp_runtime::{BoundedVec, RuntimeDebug}; use sp_std::prelude::*; -use crate::types::{Data, IdentityFields, IdentityInformationProvider, U64BitFlag}; +use crate::types::{Data, IdentityInformationProvider}; /// The fields that we use to identify the owner of an account with. Each corresponds to a field /// in the `IdentityInfo` struct. @@ -58,8 +60,6 @@ impl TypeInfo for IdentityField { } } -impl U64BitFlag for IdentityField {} - /// Information concerning the identity of the controller of an account. /// /// NOTE: This should be stored at the end of the storage item to facilitate the addition of extra @@ -124,22 +124,20 @@ pub struct IdentityInfo> { } impl + 'static> IdentityInformationProvider for IdentityInfo { - type IdentityField = IdentityField; - - fn has_identity(&self, fields: u64) -> bool { - self.fields().0.bits() & fields == fields - } + type FieldsIdentifier = u64; - fn additional(&self) -> usize { - self.additional.len() + fn has_identity(&self, fields: Self::FieldsIdentifier) -> bool { + self.fields().bits() & fields == fields } #[cfg(feature = "runtime-benchmarks")] - fn create_identity_info(num_fields: u32) -> Self { + fn create_identity_info() -> Self { let data = Data::Raw(vec![0; 32].try_into().unwrap()); IdentityInfo { - additional: vec![(data.clone(), data.clone()); num_fields as usize].try_into().unwrap(), + additional: vec![(data.clone(), data.clone()); FieldLimit::get().try_into().unwrap()] + .try_into() + .unwrap(), display: data.clone(), legal: data.clone(), web: data.clone(), @@ -150,11 +148,15 @@ impl + 'static> IdentityInformationProvider for IdentityInf twitter: data, } } + + #[cfg(feature = "runtime-benchmarks")] + fn all_fields() -> Self::FieldsIdentifier { + IdentityField::all().bits() + } } impl> IdentityInfo { - #[allow(unused)] - pub(crate) fn fields(&self) -> IdentityFields { + pub(crate) fn fields(&self) -> BitFlags { let mut res = >::empty(); if !self.display.is_none() { res.insert(IdentityField::Display); @@ -180,6 +182,6 @@ impl> IdentityInfo { if !self.twitter.is_none() { res.insert(IdentityField::Twitter); } - IdentityFields(res) + res } } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index a341cc6bb9b..264ea3ddb41 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -73,21 +73,23 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; -pub mod simple; +pub mod legacy; #[cfg(test)] mod tests; mod types; pub mod weights; -use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency}; +use frame_support::{ + pallet_prelude::DispatchResult, + traits::{BalanceStatus, Currency, Get, OnUnbalanced, ReservableCurrency}, +}; use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero}; use sp_std::prelude::*; pub use weights::WeightInfo; pub use pallet::*; pub use types::{ - Data, IdentityFields, IdentityInformationProvider, Judgement, RegistrarIndex, RegistrarInfo, - Registration, + Data, IdentityInformationProvider, Judgement, RegistrarIndex, RegistrarInfo, Registration, }; type BalanceOf = @@ -115,9 +117,9 @@ pub mod pallet { #[pallet::constant] type BasicDeposit: Get>; - /// The amount held on deposit per additional field for a registered identity. + /// The amount held on deposit per encoded byte for a registered identity. #[pallet::constant] - type FieldDeposit: Get>; + type ByteDeposit: Get>; /// The amount held on deposit for a registered subaccount. This should account for the fact /// that one storage item's value will increase by the size of an account ID, and there will @@ -129,11 +131,6 @@ pub mod pallet { #[pallet::constant] type MaxSubAccounts: Get; - /// Maximum number of additional fields that may be stored in an ID. Needed to bound the I/O - /// required to access an identity, but can be pretty high. - #[pallet::constant] - type MaxAdditionalFields: Get; - /// Structure holding information about an identity. type IdentityInformation: IdentityInformationProvider; @@ -206,7 +203,7 @@ pub mod pallet { RegistrarInfo< BalanceOf, T::AccountId, - ::IdentityField, + ::FieldsIdentifier, >, >, T::MaxRegistrars, @@ -238,8 +235,6 @@ pub mod pallet { InvalidIndex, /// The target is invalid. InvalidTarget, - /// Too many additional fields. - TooManyFields, /// Maximum amount of registrars reached. Cannot add any more. TooManyRegistrars, /// Account ID is already named. @@ -328,19 +323,15 @@ pub mod pallet { /// /// Emits `IdentitySet` if successful. #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::set_identity( - T::MaxRegistrars::get(), - T::MaxAdditionalFields::get(), - ))] + #[pallet::weight(T::WeightInfo::set_identity(T::MaxRegistrars::get()))] pub fn set_identity( origin: OriginFor, info: Box, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - #[allow(deprecated)] - let extra_fields = info.additional() as u32; - ensure!(extra_fields <= T::MaxAdditionalFields::get(), Error::::TooManyFields); - let fd = >::from(extra_fields) * T::FieldDeposit::get(); + let encoded_byte_size = info.encoded_size() as u32; + let byte_deposit = + T::ByteDeposit::get().saturating_mul(>::from(encoded_byte_size)); let mut id = match >::get(&sender) { Some(mut id) => { @@ -357,7 +348,7 @@ pub mod pallet { }; let old_deposit = id.deposit; - id.deposit = T::BasicDeposit::get() + fd; + id.deposit = T::BasicDeposit::get().saturating_add(byte_deposit); if id.deposit > old_deposit { T::Currency::reserve(&sender, id.deposit - old_deposit)?; } @@ -370,7 +361,7 @@ pub mod pallet { >::insert(&sender, id); Self::deposit_event(Event::IdentitySet { who: sender }); - Ok(Some(T::WeightInfo::set_identity(judgements as u32, extra_fields)).into()) + Ok(Some(T::WeightInfo::set_identity(judgements as u32)).into()) } /// Set the sub-accounts of the sender. @@ -404,7 +395,8 @@ pub mod pallet { ); let (old_deposit, old_ids) = >::get(&sender); - let new_deposit = T::SubAccountDeposit::get() * >::from(subs.len() as u32); + let new_deposit = + T::SubAccountDeposit::get().saturating_mul(>::from(subs.len() as u32)); let not_other_sub = subs.iter().filter_map(|i| SuperOf::::get(&i.0)).all(|i| i.0 == sender); @@ -454,14 +446,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_identity( T::MaxRegistrars::get(), T::MaxSubAccounts::get(), - T::MaxAdditionalFields::get(), ))] pub fn clear_identity(origin: OriginFor) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; let (subs_deposit, sub_ids) = >::take(&sender); let id = >::take(&sender).ok_or(Error::::NotNamed)?; - let deposit = id.total_deposit() + subs_deposit; + let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { >::remove(sub); } @@ -475,7 +466,6 @@ pub mod pallet { Ok(Some(T::WeightInfo::clear_identity( id.judgements.len() as u32, sub_ids.len() as u32, - id.info.additional() as u32, )) .into()) } @@ -497,10 +487,7 @@ pub mod pallet { /// /// Emits `JudgementRequested` if successful. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::request_judgement( - T::MaxRegistrars::get(), - T::MaxAdditionalFields::get(), - ))] + #[pallet::weight(T::WeightInfo::request_judgement(T::MaxRegistrars::get(),))] pub fn request_judgement( origin: OriginFor, #[pallet::compact] reg_index: RegistrarIndex, @@ -530,8 +517,6 @@ pub mod pallet { T::Currency::reserve(&sender, registrar.fee)?; let judgements = id.judgements.len(); - #[allow(deprecated)] - let extra_fields = id.info.additional(); >::insert(&sender, id); Self::deposit_event(Event::JudgementRequested { @@ -539,8 +524,7 @@ pub mod pallet { registrar_index: reg_index, }); - Ok(Some(T::WeightInfo::request_judgement(judgements as u32, extra_fields as u32)) - .into()) + Ok(Some(T::WeightInfo::request_judgement(judgements as u32)).into()) } /// Cancel a previous request. @@ -554,10 +538,7 @@ pub mod pallet { /// /// Emits `JudgementUnrequested` if successful. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::cancel_request( - T::MaxRegistrars::get(), - T::MaxAdditionalFields::get(), - ))] + #[pallet::weight(T::WeightInfo::cancel_request(T::MaxRegistrars::get()))] pub fn cancel_request( origin: OriginFor, reg_index: RegistrarIndex, @@ -578,8 +559,6 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, fee); debug_assert!(err_amount.is_zero()); let judgements = id.judgements.len(); - #[allow(deprecated)] - let extra_fields = id.info.additional(); >::insert(&sender, id); Self::deposit_event(Event::JudgementUnrequested { @@ -587,7 +566,7 @@ pub mod pallet { registrar_index: reg_index, }); - Ok(Some(T::WeightInfo::cancel_request(judgements as u32, extra_fields as u32)).into()) + Ok(Some(T::WeightInfo::cancel_request(judgements as u32)).into()) } /// Set the fee required for a judgement to be requested from a registrar. @@ -669,26 +648,21 @@ pub mod pallet { pub fn set_fields( origin: OriginFor, #[pallet::compact] index: RegistrarIndex, - fields: IdentityFields< - ::IdentityField, - >, + fields: ::FieldsIdentifier, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let registrars = >::mutate(|rs| -> Result { - rs.get_mut(index as usize) - .and_then(|x| x.as_mut()) - .and_then(|r| { - if r.account == who { - r.fields = fields; - Some(()) - } else { - None - } - }) - .ok_or_else(|| DispatchError::from(Error::::InvalidIndex))?; - Ok(rs.len()) - })?; + let registrars = + >::mutate(|registrars| -> Result { + let registrar = registrars + .get_mut(index as usize) + .and_then(|r| r.as_mut()) + .filter(|r| r.account == who) + .ok_or_else(|| DispatchError::from(Error::::InvalidIndex))?; + registrar.fields = fields; + + Ok(registrars.len()) + })?; Ok(Some(T::WeightInfo::set_fields(registrars as u32)).into()) } @@ -706,10 +680,7 @@ pub mod pallet { /// /// Emits `JudgementGiven` if successful. #[pallet::call_index(9)] - #[pallet::weight(T::WeightInfo::provide_judgement( - T::MaxRegistrars::get(), - T::MaxAdditionalFields::get(), - ))] + #[pallet::weight(T::WeightInfo::provide_judgement(T::MaxRegistrars::get()))] pub fn provide_judgement( origin: OriginFor, #[pallet::compact] reg_index: RegistrarIndex, @@ -752,13 +723,10 @@ pub mod pallet { } let judgements = id.judgements.len(); - #[allow(deprecated)] - let extra_fields = id.info.additional(); >::insert(&target, id); Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); - Ok(Some(T::WeightInfo::provide_judgement(judgements as u32, extra_fields as u32)) - .into()) + Ok(Some(T::WeightInfo::provide_judgement(judgements as u32)).into()) } /// Remove an account's identity and sub-account information and slash the deposits. @@ -777,7 +745,6 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::kill_identity( T::MaxRegistrars::get(), T::MaxSubAccounts::get(), - T::MaxAdditionalFields::get(), ))] pub fn kill_identity( origin: OriginFor, @@ -790,7 +757,7 @@ pub mod pallet { // Grab their deposit (and check that they have one). let (subs_deposit, sub_ids) = >::take(&target); let id = >::take(&target).ok_or(Error::::NotNamed)?; - let deposit = id.total_deposit() + subs_deposit; + let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { >::remove(sub); } @@ -800,12 +767,8 @@ pub mod pallet { Self::deposit_event(Event::IdentityKilled { who: target, deposit }); #[allow(deprecated)] - Ok(Some(T::WeightInfo::kill_identity( - id.judgements.len() as u32, - sub_ids.len() as u32, - id.info.additional() as u32, - )) - .into()) + Ok(Some(T::WeightInfo::kill_identity(id.judgements.len() as u32, sub_ids.len() as u32)) + .into()) } /// Add the given account to the sender's subs. @@ -936,7 +899,10 @@ impl Pallet { } /// Check if the account has corresponding identity information by the identity field. - pub fn has_identity(who: &T::AccountId, fields: u64) -> bool { + pub fn has_identity( + who: &T::AccountId, + fields: ::FieldsIdentifier, + ) -> bool { IdentityOf::::get(who) .map_or(false, |registration| (registration.info.has_identity(fields))) } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index f0980e9c7cc..71192ea65a8 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -20,13 +20,13 @@ use super::*; use crate::{ self as pallet_identity, - simple::{IdentityField as SimpleIdentityField, IdentityInfo}, + legacy::{IdentityField, IdentityInfo}, }; use codec::{Decode, Encode}; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{ConstU32, ConstU64, EitherOfDiverse}, + traits::{ConstU32, ConstU64, EitherOfDiverse, Get}, BoundedVec, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -105,11 +105,10 @@ impl pallet_identity::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type Slashed = (); - type BasicDeposit = ConstU64<10>; - type FieldDeposit = ConstU64<10>; - type SubAccountDeposit = ConstU64<10>; + type BasicDeposit = ConstU64<100>; + type ByteDeposit = ConstU64<10>; + type SubAccountDeposit = ConstU64<100>; type MaxSubAccounts = ConstU32<2>; - type MaxAdditionalFields = MaxAdditionalFields; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type RegistrarOrigin = EnsureOneOrRoot; @@ -120,7 +119,7 @@ impl pallet_identity::Config for Test { pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(1, 10), (2, 10), (3, 10), (10, 100), (20, 100), (30, 100)], + balances: vec![(1, 100), (2, 100), (3, 100), (10, 1000), (20, 1000), (30, 1000)], } .assimilate_storage(&mut t) .unwrap(); @@ -143,39 +142,43 @@ fn twenty() -> IdentityInfo { } } +fn id_deposit(id: &IdentityInfo) -> u64 { + let base_deposit: u64 = <::BasicDeposit as Get>::get(); + let byte_deposit: u64 = <::ByteDeposit as Get>::get() * + TryInto::::try_into(id.encoded_size()).unwrap(); + base_deposit + byte_deposit +} + #[test] fn identity_fields_repr_works() { - // `SimpleIdentityField` sanity checks. - assert_eq!(SimpleIdentityField::Display as u64, 1 << 0); - assert_eq!(SimpleIdentityField::Legal as u64, 1 << 1); - assert_eq!(SimpleIdentityField::Web as u64, 1 << 2); - assert_eq!(SimpleIdentityField::Riot as u64, 1 << 3); - assert_eq!(SimpleIdentityField::Email as u64, 1 << 4); - assert_eq!(SimpleIdentityField::PgpFingerprint as u64, 1 << 5); - assert_eq!(SimpleIdentityField::Image as u64, 1 << 6); - assert_eq!(SimpleIdentityField::Twitter as u64, 1 << 7); - - let fields = IdentityFields( - SimpleIdentityField::Legal | - SimpleIdentityField::Web | - SimpleIdentityField::Riot | - SimpleIdentityField::PgpFingerprint | - SimpleIdentityField::Twitter, - ); - - assert!(!fields.0.contains(SimpleIdentityField::Display)); - assert!(fields.0.contains(SimpleIdentityField::Legal)); - assert!(fields.0.contains(SimpleIdentityField::Web)); - assert!(fields.0.contains(SimpleIdentityField::Riot)); - assert!(!fields.0.contains(SimpleIdentityField::Email)); - assert!(fields.0.contains(SimpleIdentityField::PgpFingerprint)); - assert!(!fields.0.contains(SimpleIdentityField::Image)); - assert!(fields.0.contains(SimpleIdentityField::Twitter)); - - // The `IdentityFields` inner `BitFlags::bits` is used for `Encode`/`Decode`, so we ensure that - // the `u64` representation matches what we expect during encode/decode operations. + // `IdentityField` sanity checks. + assert_eq!(IdentityField::Display as u64, 1 << 0); + assert_eq!(IdentityField::Legal as u64, 1 << 1); + assert_eq!(IdentityField::Web as u64, 1 << 2); + assert_eq!(IdentityField::Riot as u64, 1 << 3); + assert_eq!(IdentityField::Email as u64, 1 << 4); + assert_eq!(IdentityField::PgpFingerprint as u64, 1 << 5); + assert_eq!(IdentityField::Image as u64, 1 << 6); + assert_eq!(IdentityField::Twitter as u64, 1 << 7); + + let fields = IdentityField::Legal | + IdentityField::Web | + IdentityField::Riot | + IdentityField::PgpFingerprint | + IdentityField::Twitter; + + assert!(!fields.contains(IdentityField::Display)); + assert!(fields.contains(IdentityField::Legal)); + assert!(fields.contains(IdentityField::Web)); + assert!(fields.contains(IdentityField::Riot)); + assert!(!fields.contains(IdentityField::Email)); + assert!(fields.contains(IdentityField::PgpFingerprint)); + assert!(!fields.contains(IdentityField::Image)); + assert!(fields.contains(IdentityField::Twitter)); + + // Ensure that the `u64` representation matches what we expect. assert_eq!( - fields.0.bits(), + fields.bits(), 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_10101110 ); } @@ -190,18 +193,23 @@ fn editing_subaccounts_should_work() { Error::::NoIdentity ); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); + let id_deposit = id_deposit(&ten); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); + + let sub_deposit: u64 = <::SubAccountDeposit as Get>::get(); // first sub account assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - sub_deposit); // second sub account assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 2, data(2))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 2 * sub_deposit); // third sub account is too many assert_noop!( @@ -213,20 +221,20 @@ fn editing_subaccounts_should_work() { assert_ok!(Identity::rename_sub(RuntimeOrigin::signed(10), 1, data(11))); assert_eq!(SuperOf::::get(1), Some((10, data(11)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 2 * sub_deposit); // remove first sub account assert_ok!(Identity::remove_sub(RuntimeOrigin::signed(10), 1)); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - sub_deposit); // add third sub account assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3))); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(SuperOf::::get(3), Some((10, data(3)))); - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 2 * sub_deposit); }); } @@ -234,15 +242,22 @@ fn editing_subaccounts_should_work() { fn resolving_subaccount_ownership_works() { new_test_ext().execute_with(|| { let data = |x| Data::Raw(vec![x; 1].try_into().unwrap()); + let sub_deposit: u64 = <::SubAccountDeposit as Get>::get(); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(20), Box::new(twenty()))); + let ten = ten(); + let ten_deposit = id_deposit(&ten); + let twenty = twenty(); + let twenty_deposit = id_deposit(&twenty); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten))); + assert_eq!(Balances::free_balance(10), 1000 - ten_deposit); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(20), Box::new(twenty))); + assert_eq!(Balances::free_balance(20), 1000 - twenty_deposit); // 10 claims 1 as a subaccount assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(10), 80); - assert_eq!(Balances::reserved_balance(10), 20); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(Balances::free_balance(10), 1000 - ten_deposit - sub_deposit); + assert_eq!(Balances::reserved_balance(10), ten_deposit + sub_deposit); // 20 cannot claim 1 now assert_noop!( Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1)), @@ -251,9 +266,9 @@ fn resolving_subaccount_ownership_works() { // 1 wants to be with 20 so it quits from 10 assert_ok!(Identity::quit_sub(RuntimeOrigin::signed(1))); // 1 gets the 10 that 10 paid. - assert_eq!(Balances::free_balance(1), 20); - assert_eq!(Balances::free_balance(10), 80); - assert_eq!(Balances::reserved_balance(10), 10); + assert_eq!(Balances::free_balance(1), 100 + sub_deposit); + assert_eq!(Balances::free_balance(10), 1000 - ten_deposit - sub_deposit); + assert_eq!(Balances::reserved_balance(10), ten_deposit); // 20 can claim 1 now assert_ok!(Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1))); }); @@ -269,16 +284,29 @@ fn trailing_zeros_decodes_into_default_data() { assert_eq!(b, Data::None); } +#[test] +fn adding_registrar_invalid_index() { + new_test_ext().execute_with(|| { + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + let fields = IdentityField::Display | IdentityField::Legal; + assert_noop!( + Identity::set_fields(RuntimeOrigin::signed(3), 100, fields.bits()), + Error::::InvalidIndex + ); + }); +} + #[test] fn adding_registrar_should_work() { new_test_ext().execute_with(|| { assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); - let fields = IdentityFields(SimpleIdentityField::Display | SimpleIdentityField::Legal); - assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields)); + let fields = IdentityField::Display | IdentityField::Legal; + assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields.bits())); assert_eq!( Identity::registrars(), - vec![Some(RegistrarInfo { account: 3, fee: 10, fields })] + vec![Some(RegistrarInfo { account: 3, fee: 10, fields: fields.bits() })] ); }); } @@ -306,11 +334,13 @@ fn registration_should_work() { three_fields.additional.try_push(Default::default()).unwrap(); three_fields.additional.try_push(Default::default()).unwrap(); assert!(three_fields.additional.try_push(Default::default()).is_err()); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); - assert_eq!(Identity::identity(10).unwrap().info, ten()); - assert_eq!(Balances::free_balance(10), 90); + let ten = ten(); + let id_deposit = id_deposit(&ten); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); + assert_eq!(Identity::identity(10).unwrap().info, ten); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); - assert_eq!(Balances::free_balance(10), 100); + assert_eq!(Balances::free_balance(10), 1000); assert_noop!(Identity::clear_identity(RuntimeOrigin::signed(10)), Error::::NotNamed); }); } @@ -407,11 +437,13 @@ fn clearing_judgement_should_work() { #[test] fn killing_slashing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + let id_deposit = id_deposit(&ten); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten))); assert_noop!(Identity::kill_identity(RuntimeOrigin::signed(1), 10), BadOrigin); assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); assert_eq!(Identity::identity(10), None); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_noop!( Identity::kill_identity(RuntimeOrigin::signed(2), 10), Error::::NotNamed @@ -422,38 +454,43 @@ fn killing_slashing_should_work() { #[test] fn setting_subaccounts_should_work() { new_test_ext().execute_with(|| { + let ten = ten(); + let id_deposit = id_deposit(&ten); + let sub_deposit: u64 = <::SubAccountDeposit as Get>::get(); let mut subs = vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))]; assert_noop!( Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()), Error::::NotFound ); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 80); - assert_eq!(Identity::subs_of(10), (10, vec![20].try_into().unwrap())); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - sub_deposit); + assert_eq!(Identity::subs_of(10), (sub_deposit, vec![20].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); // push another item and re-set it. subs.push((30, Data::Raw(vec![50; 1].try_into().unwrap()))); assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 70); - assert_eq!(Identity::subs_of(10), (20, vec![20, 30].try_into().unwrap())); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 2 * sub_deposit); + assert_eq!(Identity::subs_of(10), (2 * sub_deposit, vec![20, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1].try_into().unwrap())))); // switch out one of the items and re-set. subs[0] = (40, Data::Raw(vec![60; 1].try_into().unwrap())); assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); - assert_eq!(Balances::free_balance(10), 70); // no change in the balance - assert_eq!(Identity::subs_of(10), (20, vec![40, 30].try_into().unwrap())); + // no change in the balance + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 2 * sub_deposit); + assert_eq!(Identity::subs_of(10), (2 * sub_deposit, vec![40, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), None); assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1].try_into().unwrap())))); assert_eq!(Identity::super_of(40), Some((10, Data::Raw(vec![60; 1].try_into().unwrap())))); // clear assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), vec![])); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_eq!(Identity::subs_of(10), (0, BoundedVec::default())); assert_eq!(Identity::super_of(30), None); assert_eq!(Identity::super_of(40), None); @@ -469,13 +506,15 @@ fn setting_subaccounts_should_work() { #[test] fn clearing_account_should_remove_subaccounts_and_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit(&ten)); assert_ok!(Identity::set_subs( RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); - assert_eq!(Balances::free_balance(10), 100); + assert_eq!(Balances::free_balance(10), 1000); assert!(Identity::super_of(20).is_none()); }); } @@ -483,13 +522,18 @@ fn clearing_account_should_remove_subaccounts_and_refund() { #[test] fn killing_account_should_remove_subaccounts_and_not_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + let id_deposit = id_deposit(&ten); + let sub_deposit: u64 = <::SubAccountDeposit as Get>::get(); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_ok!(Identity::set_subs( RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - sub_deposit); assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); - assert_eq!(Balances::free_balance(10), 80); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - sub_deposit); assert!(Identity::super_of(20).is_none()); }); } @@ -503,10 +547,12 @@ fn cancelling_requested_judgement_should_work() { Identity::cancel_request(RuntimeOrigin::signed(10), 0), Error::::NoIdentity ); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit(&ten)); assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); assert_ok!(Identity::cancel_request(RuntimeOrigin::signed(10), 0)); - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit(&ten)); assert_noop!( Identity::cancel_request(RuntimeOrigin::signed(10), 0), Error::::NotFound @@ -517,7 +563,7 @@ fn cancelling_requested_judgement_should_work() { 0, 10, Judgement::Reasonable, - BlakeTwo256::hash_of(&ten()) + BlakeTwo256::hash_of(&ten) )); assert_noop!( Identity::cancel_request(RuntimeOrigin::signed(10), 0), @@ -531,14 +577,17 @@ fn requesting_judgement_should_work() { new_test_ext().execute_with(|| { assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + let ten = ten(); + let id_deposit = id_deposit(&ten); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); assert_noop!( Identity::request_judgement(RuntimeOrigin::signed(10), 0, 9), Error::::FeeChanged ); assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); - // 10 for the judgement request, 10 for the identity. - assert_eq!(Balances::free_balance(10), 80); + // 10 for the judgement request and the deposit for the identity. + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 10); // Re-requesting won't work as we already paid. assert_noop!( @@ -550,10 +599,11 @@ fn requesting_judgement_should_work() { 0, 10, Judgement::Erroneous, - BlakeTwo256::hash_of(&ten()) + BlakeTwo256::hash_of(&ten) )); // Registrar got their payment now. - assert_eq!(Balances::free_balance(3), 20); + // 100 initial balance and 10 for the judgement. + assert_eq!(Balances::free_balance(3), 100 + 10); // Re-requesting still won't work as it's erroneous. assert_noop!( @@ -571,7 +621,7 @@ fn requesting_judgement_should_work() { 0, 10, Judgement::OutOfDate, - BlakeTwo256::hash_of(&ten()) + BlakeTwo256::hash_of(&ten) )); assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); }); @@ -580,12 +630,14 @@ fn requesting_judgement_should_work() { #[test] fn provide_judgement_should_return_judgement_payment_failed_error() { new_test_ext().execute_with(|| { + let ten = ten(); + let id_deposit = id_deposit(&ten); assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); - assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten.clone()))); assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); - // 10 for the judgement request, 10 for the identity. - assert_eq!(Balances::free_balance(10), 80); + // 10 for the judgement request and the deposit for the identity. + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - 10); // This forces judgement payment failed error Balances::make_free_balance_be(&3, 0); @@ -595,7 +647,7 @@ fn provide_judgement_should_return_judgement_payment_failed_error() { 0, 10, Judgement::Erroneous, - BlakeTwo256::hash_of(&ten()) + BlakeTwo256::hash_of(&ten) ), Error::::JudgementPaymentFailed ); @@ -607,25 +659,24 @@ fn field_deposit_should_work() { new_test_ext().execute_with(|| { assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); - assert_ok!(Identity::set_identity( - RuntimeOrigin::signed(10), - Box::new(IdentityInfo { - additional: vec![ - ( - Data::Raw(b"number".to_vec().try_into().unwrap()), - Data::Raw(10u32.encode().try_into().unwrap()) - ), - ( - Data::Raw(b"text".to_vec().try_into().unwrap()), - Data::Raw(b"10".to_vec().try_into().unwrap()) - ), - ] - .try_into() - .unwrap(), - ..Default::default() - }) - )); - assert_eq!(Balances::free_balance(10), 70); + let id = IdentityInfo { + additional: vec![ + ( + Data::Raw(b"number".to_vec().try_into().unwrap()), + Data::Raw(10u32.encode().try_into().unwrap()), + ), + ( + Data::Raw(b"text".to_vec().try_into().unwrap()), + Data::Raw(b"10".to_vec().try_into().unwrap()), + ), + ] + .try_into() + .unwrap(), + ..Default::default() + }; + let id_deposit = id_deposit(&id); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(id))); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit); }); } @@ -649,17 +700,15 @@ fn setting_account_id_should_work() { fn test_has_identity() { new_test_ext().execute_with(|| { assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); - assert!(Identity::has_identity(&10, SimpleIdentityField::Display as u64)); - assert!(Identity::has_identity(&10, SimpleIdentityField::Legal as u64)); + assert!(Identity::has_identity(&10, IdentityField::Display as u64)); + assert!(Identity::has_identity(&10, IdentityField::Legal as u64)); assert!(Identity::has_identity( &10, - SimpleIdentityField::Display as u64 | SimpleIdentityField::Legal as u64 + IdentityField::Display as u64 | IdentityField::Legal as u64 )); assert!(!Identity::has_identity( &10, - SimpleIdentityField::Display as u64 | - SimpleIdentityField::Legal as u64 | - SimpleIdentityField::Web as u64 + IdentityField::Display as u64 | IdentityField::Legal as u64 | IdentityField::Web as u64 )); }); } diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index 7055f6d80cf..d3e6bf3973f 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -17,23 +17,23 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; -use enumflags2::{BitFlag, BitFlags, _internal::RawBitFlags}; use frame_support::{ traits::{ConstU32, Get}, BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::{ build::{Fields, Variants}, - meta_type, Path, Type, TypeInfo, TypeParameter, + Path, Type, TypeInfo, +}; +use sp_runtime::{ + traits::{Member, Zero}, + RuntimeDebug, }; -use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::{fmt::Debug, iter::once, ops::Add, prelude::*}; /// An identifier for a single name registrar/identity verification service. pub type RegistrarIndex = u32; -pub trait U64BitFlag: BitFlag + RawBitFlags {} - /// Either underlying data blob if it is at most 32 bytes, or a hash of it. If the data is greater /// than 32-bytes then it will be truncated when encoding. /// @@ -234,24 +234,19 @@ impl bool; - - /// Interface for providing the number of additional fields this identity information provider - /// holds, used to charge for additional storage and weight. This interface is present for - /// backwards compatibility reasons only and will be removed as soon as the reference identity - /// provider removes additional fields. - #[deprecated] - fn additional(&self) -> usize { - 0 - } + fn has_identity(&self, fields: Self::FieldsIdentifier) -> bool; + /// Create a basic instance of the identity information. #[cfg(feature = "runtime-benchmarks")] - fn create_identity_info(num_fields: u32) -> Self; + fn create_identity_info() -> Self; + + /// The identity information representation for all identity fields enabled. + #[cfg(feature = "runtime-benchmarks")] + fn all_fields() -> Self::FieldsIdentifier; } /// Information on an identity along with judgements from registrars. @@ -262,7 +257,7 @@ pub trait IdentityInformationProvider: CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] #[codec(mel_bound())] -#[scale_info(skip_type_params(MaxJudgements, MaxAdditionalFields))] +#[scale_info(skip_type_params(MaxJudgements))] pub struct Registration< Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq, MaxJudgements: Get, @@ -311,7 +306,7 @@ impl< pub struct RegistrarInfo< Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq, - IdField: Clone + Debug + Eq + PartialEq + TypeInfo + U64BitFlag, + IdField: Encode + Decode + Clone + Debug + Default + Eq + PartialEq + TypeInfo + MaxEncodedLen, > { /// The account of the registrar. pub account: AccountId, @@ -321,52 +316,7 @@ pub struct RegistrarInfo< /// Relevant fields for this registrar. Registrar judgements are limited to attestations on /// these fields. - pub fields: IdentityFields, -} - -/// Wrapper type for `BitFlags` that implements `Codec`. -#[derive(Clone, Copy, PartialEq, RuntimeDebug)] -pub struct IdentityFields(pub BitFlags); - -impl Default for IdentityFields { - fn default() -> Self { - Self(Default::default()) - } -} - -impl MaxEncodedLen for IdentityFields -where - IdentityFields: Encode, -{ - fn max_encoded_len() -> usize { - u64::max_encoded_len() - } -} - -impl Eq for IdentityFields {} -impl Encode for IdentityFields { - fn using_encoded R>(&self, f: F) -> R { - let bits: u64 = self.0.bits(); - bits.using_encoded(f) - } -} -impl Decode for IdentityFields { - fn decode(input: &mut I) -> sp_std::result::Result { - let field = u64::decode(input)?; - Ok(Self(>::from_bits(field).map_err(|_| "invalid value")?)) - } -} -impl TypeInfo - for IdentityFields -{ - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("BitFlags", module_path!())) - .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) - .composite(Fields::unnamed().field(|f| f.ty::().type_name("IdentityField"))) - } + pub fields: IdField, } #[cfg(test)] diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 02fcd7db3c9..95898e6c6cd 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -53,17 +53,17 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_identity. pub trait WeightInfo { fn add_registrar(r: u32, ) -> Weight; - fn set_identity(r: u32, x: u32, ) -> Weight; + fn set_identity(r: u32, ) -> Weight; fn set_subs_new(s: u32, ) -> Weight; fn set_subs_old(p: u32, ) -> Weight; - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight; - fn request_judgement(r: u32, x: u32, ) -> Weight; - fn cancel_request(r: u32, x: u32, ) -> Weight; + fn clear_identity(r: u32, s: u32, ) -> Weight; + fn request_judgement(r: u32, ) -> Weight; + fn cancel_request(r: u32, ) -> Weight; fn set_fee(r: u32, ) -> Weight; fn set_account_id(r: u32, ) -> Weight; fn set_fields(r: u32, ) -> Weight; - fn provide_judgement(r: u32, x: u32, ) -> Weight; - fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight; + fn provide_judgement(r: u32, ) -> Weight; + fn kill_identity(r: u32, s: u32, ) -> Weight; fn add_sub(s: u32, ) -> Weight; fn rename_sub(s: u32, ) -> Weight; fn remove_sub(s: u32, ) -> Weight; @@ -90,8 +90,7 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` @@ -99,8 +98,6 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(31_329_634, 11003) // Standard Error: 4_496 .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) - // Standard Error: 877 - .saturating_add(Weight::from_parts(429_346, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -152,8 +149,7 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -163,8 +159,6 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) // Standard Error: 1_937 .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) - // Standard Error: 1_937 - .saturating_add(Weight::from_parts(247_578, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -174,8 +168,7 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -183,16 +176,13 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(32_207_018, 11003) // Standard Error: 5_247 .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) - // Standard Error: 1_023 - .saturating_add(Weight::from_parts(458_329, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Identity IdentityOf (r:1 w:1) /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { + fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` @@ -200,8 +190,6 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(31_967_170, 11003) // Standard Error: 5_387 .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) - // Standard Error: 1_051 - .saturating_add(Weight::from_parts(446_213, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -252,8 +240,7 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -261,8 +248,6 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(17_817_684, 11003) // Standard Error: 8_612 .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) - // Standard Error: 1_593 - .saturating_add(Weight::from_parts(755_225, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -276,8 +261,7 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -287,8 +271,6 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) // Standard Error: 2_472 .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(240_907, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -384,8 +366,7 @@ impl WeightInfo for () { /// 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 { + fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` @@ -393,8 +374,6 @@ impl WeightInfo for () { Weight::from_parts(31_329_634, 11003) // Standard Error: 4_496 .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) - // Standard Error: 877 - .saturating_add(Weight::from_parts(429_346, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -446,8 +425,7 @@ impl WeightInfo for () { /// 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 { + fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -457,8 +435,6 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) // Standard Error: 1_937 .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) - // Standard Error: 1_937 - .saturating_add(Weight::from_parts(247_578, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -468,8 +444,7 @@ impl WeightInfo for () { /// 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 { + fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -477,16 +452,13 @@ impl WeightInfo for () { Weight::from_parts(32_207_018, 11003) // Standard Error: 5_247 .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) - // Standard Error: 1_023 - .saturating_add(Weight::from_parts(458_329, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Identity IdentityOf (r:1 w:1) /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { + fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` @@ -494,8 +466,6 @@ impl WeightInfo for () { Weight::from_parts(31_967_170, 11003) // Standard Error: 5_387 .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) - // Standard Error: 1_051 - .saturating_add(Weight::from_parts(446_213, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -546,8 +516,7 @@ impl WeightInfo for () { /// 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 { + fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -555,8 +524,6 @@ impl WeightInfo for () { Weight::from_parts(17_817_684, 11003) // Standard Error: 8_612 .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) - // Standard Error: 1_593 - .saturating_add(Weight::from_parts(755_225, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -570,8 +537,7 @@ impl WeightInfo for () { /// 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 { + fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` // Estimated: `11003` @@ -581,8 +547,6 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) // Standard Error: 2_472 .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(240_907, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) -- GitLab From 1c0b437330f971d898fc75f0ed148998e9e60625 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sat, 4 Nov 2023 10:25:07 +0100 Subject: [PATCH 438/633] cumulus test runtime: remove `GenesisExt` (#2147) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR removes the `GenesisExt` wrapper over the `GenesisRuntimeConfig` in `cumulus-test-service`. Initialization of values that were performed by `GenesisExt::BuildStorage` was moved into `test_pallet` genesis. --------- Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher --- cumulus/test/client/src/lib.rs | 3 +- cumulus/test/runtime/src/lib.rs | 10 +++--- cumulus/test/runtime/src/test_pallet.rs | 23 ++++++++++++ cumulus/test/service/src/chain_spec.rs | 36 ++++--------------- .../zombienet/tests/0002-pov_recovery.toml | 2 +- .../tests/0005-migrate_solo_to_para.toml | 2 +- 6 files changed, 39 insertions(+), 37 deletions(-) diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index 61249bdb066..635455d5033 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -90,6 +90,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { cumulus_test_service::testnet_genesis( cumulus_test_service::get_account_id_from_seed::("Alice"), self.endowed_accounts.clone(), + None, ) .build_storage() .unwrap() @@ -127,7 +128,7 @@ impl DefaultTestClientBuilderExt for TestClientBuilder { } fn genesis_config() -> RuntimeGenesisConfig { - cumulus_test_service::testnet_genesis_with_default_endowed(Default::default()) + cumulus_test_service::testnet_genesis_with_default_endowed(Default::default(), None) } /// Create an unsigned extrinsic from a runtime call. diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 85a1caa0ce3..381cc64cef8 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -76,10 +76,6 @@ impl_opaque_keys! { pub struct SessionKeys {} } -/// Some key that we set in genesis and only read in [`TestOnRuntimeUpgrade`] to ensure that -/// [`OnRuntimeUpgrade`] works as expected. -pub const TEST_RUNTIME_UPGRADE_KEY: &[u8] = b"+test_runtime_upgrade_key+"; - /// The para-id used in this runtime. pub const PARACHAIN_ID: u32 = 100; @@ -293,6 +289,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { } parameter_types! { + // will be set by test_pallet during genesis init pub storage ParachainId: cumulus_primitives_core::ParaId = PARACHAIN_ID.into(); } @@ -367,7 +364,10 @@ pub struct TestOnRuntimeUpgrade; impl OnRuntimeUpgrade for TestOnRuntimeUpgrade { fn on_runtime_upgrade() -> frame_support::weights::Weight { - assert_eq!(sp_io::storage::get(TEST_RUNTIME_UPGRADE_KEY), Some(vec![1, 2, 3, 4].into())); + assert_eq!( + sp_io::storage::get(test_pallet::TEST_RUNTIME_UPGRADE_KEY), + Some(vec![1, 2, 3, 4].into()) + ); Weight::from_parts(1, 0) } } diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index 0af23797dad..a0763c9069c 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -17,8 +17,13 @@ /// A special pallet that exposes dispatchables that are only useful for testing. pub use pallet::*; +/// Some key that we set in genesis and only read in [`TestOnRuntimeUpgrade`] to ensure that +/// [`OnRuntimeUpgrade`] works as expected. +pub const TEST_RUNTIME_UPGRADE_KEY: &[u8] = b"+test_runtime_upgrade_key+"; + #[frame_support::pallet(dev_mode)] pub mod pallet { + use crate::test_pallet::TEST_RUNTIME_UPGRADE_KEY; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -45,4 +50,22 @@ pub mod pallet { Ok(()) } } + + #[derive(frame_support::DefaultNoBound)] + #[pallet::genesis_config] + pub struct GenesisConfig { + pub self_para_id: Option, + #[serde(skip)] + pub _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + sp_io::storage::set(TEST_RUNTIME_UPGRADE_KEY, &[1, 2, 3, 4]); + self.self_para_id.map(|para_id| { + crate::ParachainId::set(¶_id); + }); + } + } } diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 7c8c984c2b2..c7dac7082fe 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -17,7 +17,7 @@ #![allow(missing_docs)] use cumulus_primitives_core::ParaId; -use cumulus_test_runtime::{AccountId, Signature}; +use cumulus_test_runtime::{AccountId, RuntimeGenesisConfig, Signature}; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; @@ -25,27 +25,7 @@ use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; /// Specialized `ChainSpec` for the normal parachain runtime. -pub type ChainSpec = sc_service::GenericChainSpec; - -/// Extension for the genesis config to add custom keys easily. -#[derive(serde::Serialize, serde::Deserialize)] -pub struct GenesisExt { - /// The runtime genesis config. - runtime_genesis_config: cumulus_test_runtime::RuntimeGenesisConfig, - /// The parachain id. - para_id: ParaId, -} - -impl sp_runtime::BuildStorage for GenesisExt { - fn assimilate_storage(&self, storage: &mut sp_core::storage::Storage) -> Result<(), String> { - sp_state_machine::BasicExternalities::execute_with_storage(storage, || { - sp_io::storage::set(cumulus_test_runtime::TEST_RUNTIME_UPGRADE_KEY, &[1, 2, 3, 4]); - cumulus_test_runtime::ParachainId::set(&self.para_id); - }); - - self.runtime_genesis_config.assimilate_storage(storage) - } -} +pub type ChainSpec = sc_service::GenericChainSpec; /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { @@ -90,12 +70,7 @@ pub fn get_chain_spec_with_extra_endowed( "Local Testnet", "local_testnet", ChainType::Local, - move || GenesisExt { - runtime_genesis_config: testnet_genesis_with_default_endowed( - extra_endowed_accounts.clone(), - ), - para_id: id, - }, + move || testnet_genesis_with_default_endowed(extra_endowed_accounts.clone(), Some(id)), Vec::new(), None, None, @@ -113,6 +88,7 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec { /// Local testnet genesis for testing. pub fn testnet_genesis_with_default_endowed( mut extra_endowed_accounts: Vec, + self_para_id: Option, ) -> cumulus_test_runtime::RuntimeGenesisConfig { let mut endowed = vec![ get_account_id_from_seed::("Alice"), @@ -130,13 +106,14 @@ pub fn testnet_genesis_with_default_endowed( ]; endowed.append(&mut extra_endowed_accounts); - testnet_genesis(get_account_id_from_seed::("Alice"), endowed) + testnet_genesis(get_account_id_from_seed::("Alice"), endowed, self_para_id) } /// Creates a local testnet genesis with endowed accounts. pub fn testnet_genesis( root_key: AccountId, endowed_accounts: Vec, + self_para_id: Option, ) -> cumulus_test_runtime::RuntimeGenesisConfig { cumulus_test_runtime::RuntimeGenesisConfig { system: cumulus_test_runtime::SystemConfig { @@ -152,5 +129,6 @@ pub fn testnet_genesis( }, sudo: cumulus_test_runtime::SudoConfig { key: Some(root_key) }, transaction_payment: Default::default(), + test_pallet: cumulus_test_runtime::TestPalletConfig { self_para_id, ..Default::default() }, } } diff --git a/cumulus/zombienet/tests/0002-pov_recovery.toml b/cumulus/zombienet/tests/0002-pov_recovery.toml index 7c74a74a750..a7c1fbfd441 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.toml +++ b/cumulus/zombienet/tests/0002-pov_recovery.toml @@ -4,7 +4,7 @@ default_command = "polkadot" chain = "rococo-local" -[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] +[relaychain.genesis.runtime.configuration.config] # set parameters such that collators only connect to 1 validator as a backing group max_validators_per_core = 1 group_rotation_frequency = 100 # 10 mins diff --git a/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml b/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml index f98c0e6f259..a500b51f794 100644 --- a/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml +++ b/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml @@ -32,7 +32,7 @@ cumulus_based = true add_to_genesis = false register_para = false # Set some random value in the genesis state to create a different genesis hash. -[parachains.genesis.runtime.runtime_genesis_config.sudo] +[parachains.genesis.runtime.sudo] key = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty" # run the parachain that will be used to return the header of the solo chain. -- GitLab From 8d4ae36276af3f8131f37542ef860a64c5d8cc37 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Sat, 4 Nov 2023 16:41:40 +0100 Subject: [PATCH 439/633] Speed up try runtime checks for pallet-bags-list (#2151) closes https://github.com/paritytech/polkadot-sdk/issues/2020. This improves running time for pallet-bags-list try runtime checks on westend from ~90 minutes to 6 seconds on M2 pro. --- substrate/frame/bags-list/src/list/mod.rs | 27 ++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/substrate/frame/bags-list/src/list/mod.rs b/substrate/frame/bags-list/src/list/mod.rs index d8626080e25..e90530341a1 100644 --- a/substrate/frame/bags-list/src/list/mod.rs +++ b/substrate/frame/bags-list/src/list/mod.rs @@ -543,7 +543,16 @@ impl, I: 'static> List { thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; - let _ = active_bags.clone().try_for_each(|b| b.do_try_state())?; + // build map of bags and the corresponding nodes to avoid multiple lookups + let mut bags_map = BTreeMap::>::new(); + + let _ = active_bags.clone().try_for_each(|b| { + bags_map.insert( + b.bag_upper, + b.iter().map(|n: Node| n.id().clone()).collect::>(), + ); + b.do_try_state() + })?; let nodes_in_bags_count = active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); @@ -554,6 +563,13 @@ impl, I: 'static> List { // check that all nodes are sane. We check the `ListNodes` storage item directly in case we // have some "stale" nodes that are not in a bag. for (_id, node) in crate::ListNodes::::iter() { + // check that the node is in the correct bag + let expected_bag = bags_map + .get(&node.bag_upper) + .ok_or("bag not found for the node in active bags")?; + frame_support::ensure!(expected_bag.contains(node.id()), "node not found in the bag"); + + // verify node state node.do_try_state()? } @@ -790,12 +806,6 @@ impl, I: 'static> Bag { pub fn std_iter(&self) -> impl Iterator> { sp_std::iter::successors(self.head(), |prev| prev.next()) } - - /// Check if the bag contains a node with `id`. - #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] - fn contains(&self, id: &T::AccountId) -> bool { - self.iter().any(|n| n.id() == id) - } } /// A Node is the fundamental element comprising the doubly-linked list described by `Bag`. @@ -900,11 +910,8 @@ impl, I: 'static> Node { #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] fn do_try_state(&self) -> Result<(), TryRuntimeError> { let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; - let id = self.id(); - frame_support::ensure!(expected_bag.contains(id), "node does not exist in the bag"); - let non_terminal_check = !self.is_terminal() && expected_bag.head.as_ref() != Some(id) && expected_bag.tail.as_ref() != Some(id); -- GitLab From f84b89710b0e6da655a1b40a491a8184780489e7 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Sat, 4 Nov 2023 16:41:51 +0100 Subject: [PATCH 440/633] Speed up nominator state checks in staking pallet (#2153) Should help https://github.com/paritytech/polkadot-sdk/issues/234. Related to https://github.com/paritytech/polkadot-sdk/issues/2020 and https://github.com/paritytech/polkadot-sdk/issues/2108. Refactors and improves running time for try runtime checks for staking pallet. Tested on westend on my M2 pro: running time drops from 90 seconds to 7 seconds. --- substrate/frame/staking/src/pallet/impls.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index bb16fe56d51..9c36c94b87b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1864,6 +1864,13 @@ impl Pallet { // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. let era = Self::active_era().unwrap().index; + + // cache era exposures to avoid too many db reads. + let era_exposures = T::SessionInterface::validators() + .iter() + .map(|v| Self::eras_stakers(era, v)) + .collect::>(); + >::iter() .filter_map( |(nominator, nomination)| { @@ -1878,9 +1885,8 @@ impl Pallet { // must be bonded. Self::ensure_is_stash(&nominator)?; let mut sum = BalanceOf::::zero(); - T::SessionInterface::validators() + era_exposures .iter() - .map(|v| Self::eras_stakers(era, v)) .map(|e| -> Result<(), TryRuntimeError> { let individual = e.others.iter().filter(|e| e.who == nominator).collect::>(); @@ -1896,6 +1902,14 @@ impl Pallet { Ok(()) }) .collect::, _>>()?; + + // We take total instead of active as the nominator might have requested to unbond + // some of their stake that is still exposed in the current era. + if sum <= Self::ledger(Stash(nominator.clone()))?.total { + // This can happen when there is a slash in the current era so we only warn. + log!(warn, "nominator stake exceeds what is bonded."); + } + Ok(()) }) .collect::, _>>()?; -- GitLab From 0c39cf049e47f7f167d6bb4137d1f97afc3aebae Mon Sep 17 00:00:00 2001 From: Bulat Saifullin Date: Sun, 5 Nov 2023 16:36:42 +0400 Subject: [PATCH 441/633] Update bootnode lists (#2150) # Description Update the bootnode of kusama parachains before decommissioning the nodes. This will avoid connecting to non-existing bootnodes. --- .../chain-specs/asset-hub-kusama.json | 4 +--- .../chain-specs/asset-hub-polkadot.json | 8 +------- .../chain-specs/asset-hub-rococo.json | 4 +--- .../chain-specs/asset-hub-westend.json | 4 +--- .../chain-specs/bridge-hub-polkadot.json | 6 +----- .../chain-specs/bridge-hub-rococo.json | 4 +--- .../chain-specs/bridge-hub-westend.json | 4 +--- .../chain-specs/collectives-polkadot.json | 4 ---- .../chain-specs/collectives-westend.json | 6 +----- .../chain-specs/contracts-rococo.json | 6 +----- polkadot/node/service/chain-specs/rococo.json | 20 +------------------ .../node/service/chain-specs/westend.json | 6 ------ 12 files changed, 10 insertions(+), 66 deletions(-) diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 91a821efab9..519811f5ec8 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -3,8 +3,6 @@ "id": "asset-hub-kusama", "chainType": "Live", "bootNodes": [ - "/ip4/34.77.217.152/tcp/30334/p2p/12D3KooWF63ZxKtZMYs5247WQA8fcTiGJb2osXykc31cmjwNLwem", - "/ip4/34.77.119.77/tcp/30334/p2p/12D3KooWGowDwrXAh9cxkbPHPHuwMouFHrMcJhCVXcFS2B8vc5Ry", "/dns/kusama-asset-hub-connect-0.polkadot.io/tcp/30334/p2p/12D3KooWMzvdGcUXxacLdMQzRVrsP1mJrZHcrz8LtGbhLzve84Qx", "/dns/kusama-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWMzvdGcUXxacLdMQzRVrsP1mJrZHcrz8LtGbhLzve84Qx", "/dns/kusama-asset-hub-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWQmGf5z3DU1kKcZoLzMNgdbP31ybjuwxS1VGLKMUjq5ez", @@ -53,4 +51,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index 46f3e0e4a95..bbf90693ca3 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -3,16 +3,10 @@ "id": "asset-hub-polkadot", "chainType": "Live", "bootNodes": [ - "/ip4/34.65.251.121/tcp/30334/p2p/12D3KooWG3GrM6XKMM4gp3cvemdwUvu96ziYoJmqmetLZBXE8bSa", - "/ip4/34.65.35.228/tcp/30334/p2p/12D3KooWMRyTLrCEPcAQD6c4EnudL3vVzg9zji3whvsMYPUYevpq", "/dns/polkadot-asset-hub-connect-0.polkadot.io/tcp/30334/p2p/12D3KooWLHqbcQtoBygf7GJgVjVa3TaeLuf7VbicNdooaCmQM2JZ", "/dns/polkadot-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWLHqbcQtoBygf7GJgVjVa3TaeLuf7VbicNdooaCmQM2JZ", "/dns/polkadot-asset-hub-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWNDrKSayoZXGGE2dRSFW2g1iGPq3fTZE2U39ma9yZGKd3", "/dns/polkadot-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWNDrKSayoZXGGE2dRSFW2g1iGPq3fTZE2U39ma9yZGKd3", - "/dns/polkadot-asset-hub-connect-2.polkadot.io/tcp/30334/p2p/12D3KooWApa2JW4rbLtgzuK7fjLMupLS9HZheX9cdkQKyu6AnGrP", - "/dns/polkadot-asset-hub-connect-2.polkadot.io/tcp/443/wss/p2p/12D3KooWApa2JW4rbLtgzuK7fjLMupLS9HZheX9cdkQKyu6AnGrP", - "/dns/polkadot-asset-hub-connect-3.polkadot.io/tcp/30334/p2p/12D3KooWRsVeHqRs2iKmjLiguxp8myL4G2mDAWhtX2jHwyWujseV", - "/dns/polkadot-asset-hub-connect-3.polkadot.io/tcp/443/wss/p2p/12D3KooWRsVeHqRs2iKmjLiguxp8myL4G2mDAWhtX2jHwyWujseV", "/dns/boot.stake.plus/tcp/35333/p2p/12D3KooWFrQjYaPZSSLLxEVmoaHFcrF6VoY4awG4KRSLaqy3JCdQ", "/dns/boot.stake.plus/tcp/35334/wss/p2p/12D3KooWFrQjYaPZSSLLxEVmoaHFcrF6VoY4awG4KRSLaqy3JCdQ", "/dns/boot.metaspan.io/tcp/16052/p2p/12D3KooWLwiJuvqQUB4kYaSjLenFKH9dWZhGZ4qi7pSb3sUYU651", @@ -59,4 +53,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/asset-hub-rococo.json b/cumulus/parachains/chain-specs/asset-hub-rococo.json index 064a2dfc0db..900d9f0ffb2 100644 --- a/cumulus/parachains/chain-specs/asset-hub-rococo.json +++ b/cumulus/parachains/chain-specs/asset-hub-rococo.json @@ -4,9 +4,7 @@ "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" + "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index d168803e1c3..f6cdccee10a 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -5,8 +5,6 @@ "bootNodes": [ "/dns/westend-asset-hub-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWJaAfPyiye7ZQBuHengTJJoMrcaz7Jj1UzHiKdNxA1Nkd", "/dns/westend-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", - "/dns/westend-asset-hub-bootnode-2.polkadot.io/tcp/30333/p2p/12D3KooWBkKDWhHzu6Hhe492adEpVV7wzuaWGxUfEnr6g5JCr7Gr", - "/dns/westend-asset-hub-bootnode-3.polkadot.io/tcp/30333/p2p/12D3KooWMGpzCmhD6np6eKqxL7AAunKn1dN86Dr7a9E2xgZ2rt6G", "/dns/boot.stake.plus/tcp/33333/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", "/dns/boot.stake.plus/tcp/33334/wss/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", "/dns/boot.metaspan.io/tcp/36052/p2p/12D3KooWBCqfNb6Y39DXTr4UBWXyjuS3hcZM1qTbHhDXxF6HkAJJ", @@ -50,4 +48,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index fd56b61115d..e44a4dacd48 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -5,12 +5,8 @@ "bootNodes": [ "/dns/polkadot-bridge-hub-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWAVQMhkXmc5ueSYasdsRWQbKus2YGZ6HDZUB4ViJMCxXy", "/dns/polkadot-bridge-hub-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWG4ypDHLKGCv4BZ6PuaGUwQHKAH6p2D6arR2uQ1eiR1T3", - "/dns/polkadot-bridge-hub-connect-b-0.polkadot.io/tcp/30334/p2p/12D3KooWCwGKxjpJXnx1mwXKvaxGQm769EM3b6Pg5vbU33wbhsNw", - "/dns/polkadot-bridge-hub-connect-b-1.polkadot.io/tcp/30334/p2p/12D3KooWLiSEdhriJUPdZKFtAjZrQncxN2ssEoDKVrt5mGM4Qu4J", "/dns/polkadot-bridge-hub-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWAVQMhkXmc5ueSYasdsRWQbKus2YGZ6HDZUB4ViJMCxXy", "/dns/polkadot-bridge-hub-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWG4ypDHLKGCv4BZ6PuaGUwQHKAH6p2D6arR2uQ1eiR1T3", - "/dns/polkadot-bridge-hub-connect-b-0.polkadot.io/tcp/443/wss/p2p/12D3KooWCwGKxjpJXnx1mwXKvaxGQm769EM3b6Pg5vbU33wbhsNw", - "/dns/polkadot-bridge-hub-connect-b-1.polkadot.io/tcp/443/wss/p2p/12D3KooWLiSEdhriJUPdZKFtAjZrQncxN2ssEoDKVrt5mGM4Qu4J", "/dns/polkadot-bridge-hub-boot-ng.dwellir.com/tcp/30339/p2p/12D3KooWPZ38PL3PhRVcUVYDNn7nRcZF8MykmWWLBKeDV2yna1vV", "/dns/polkadot-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPZ38PL3PhRVcUVYDNn7nRcZF8MykmWWLBKeDV2yna1vV", "/dns/boot-cr.gatotech.network/tcp/33130/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", @@ -87,4 +83,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/bridge-hub-rococo.json b/cumulus/parachains/chain-specs/bridge-hub-rococo.json index ff20d8fb482..6b430678a86 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-rococo.json +++ b/cumulus/parachains/chain-specs/bridge-hub-rococo.json @@ -4,9 +4,7 @@ "chainType": "Live", "bootNodes": [ "/dns/rococo-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJCFBJmFF65xz5xHeZQRSCf35BxfSEB3RHQFoLza28LWU", - "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ", - "/dns/rococo-bridge-hub-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPZLWbbDJzEXAHPuAcVssPrjQLyZK4nvvmV2ez6gy2FQ3", - "/dns/rococo-bridge-hub-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKWMENpCNH7wBVQoHLwQoWUs6acAEmfdV694v9jCuJwYc" + "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index fbed89729c7..0a441b3a295 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -5,8 +5,6 @@ "bootNodes": [ "/dns/westend-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKyEuqkkWvFSrwZWKWBAsHgLV3HGfHj7yH3LNJLAVhmxY", "/dns/westend-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWBpvudthz61XC4oP2YYFFJdhWohBeQ1ffn1BMSGWhapjd", - "/dns/westend-bridge-hub-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPXqdRRthjKAMPFtaXUK7yBxsvh83QsmzXzALA3inoJfo", - "/dns/westend-bridge-hub-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWAp2YpVaiNBy7rozEHJGocDpaLFt3VFZsGMBEYh4BoEz7", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/30338/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", "/dns/boot-cr.gatotech.network/tcp/33330/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", @@ -82,4 +80,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index e17958f1f68..974be338857 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -5,12 +5,8 @@ "bootNodes": [ "/dns/polkadot-collectives-connect-ew6-0.polkadot.io/tcp/30334/p2p/12D3KooWLDZT5gAjMtC8fojiCwiz17SC61oeX2C7GWBCqqf9TwVD", "/dns/polkadot-collectives-connect-ew6-1.polkadot.io/tcp/30334/p2p/12D3KooWC9BwKMDyRUTXsE7teSmoKMgbyxqAp3zi2MTGRJR5nhCL", - "/dns/polkadot-collectives-connect-uw1-0.polkadot.io/tcp/30334/p2p/12D3KooWPrJ9VTn3GEs2e7GQs4zoEFiTFcjXFNbQ2iDxFDQAbstQ", - "/dns/polkadot-collectives-connect-uw1-1.polkadot.io/tcp/30334/p2p/12D3KooWGFYW6hJYn3pkpJawyMk6souXh7sznK8yvPmVQ7ktfHbV", "/dns/polkadot-collectives-connect-ew6-0.polkadot.io/tcp/443/wss/p2p/12D3KooWLDZT5gAjMtC8fojiCwiz17SC61oeX2C7GWBCqqf9TwVD", "/dns/polkadot-collectives-connect-ew6-1.polkadot.io/tcp/443/wss/p2p/12D3KooWC9BwKMDyRUTXsE7teSmoKMgbyxqAp3zi2MTGRJR5nhCL", - "/dns/polkadot-collectives-connect-uw1-0.polkadot.io/tcp/443/wss/p2p/12D3KooWPrJ9VTn3GEs2e7GQs4zoEFiTFcjXFNbQ2iDxFDQAbstQ", - "/dns/polkadot-collectives-connect-uw1-1.polkadot.io/tcp/443/wss/p2p/12D3KooWGFYW6hJYn3pkpJawyMk6souXh7sznK8yvPmVQ7ktfHbV", "/dns/boot.stake.plus/tcp/37333/p2p/12D3KooWRgFfEtwPo3xorKGYALRHRteKNgF37iN9q8xTLPYc34LA", "/dns/boot.stake.plus/tcp/37334/wss/p2p/12D3KooWRgFfEtwPo3xorKGYALRHRteKNgF37iN9q8xTLPYc34LA", "/dns/boot.metaspan.io/tcp/16072/p2p/12D3KooWJWTTu2t2yg5bFRH6tjEpfzKwZir5R9JRRjQpgFPXdDfp", diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index a40512997da..e06671faa04 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -5,12 +5,8 @@ "bootNodes": [ "/dns/westend-collectives-collator-node-0.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", "/dns/westend-collectives-collator-node-1.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", - "/dns/westend-collectives-collator-node-2.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWP4pJg6pZUpxETd8Rs6GmS9FeRCeNtrBerqZhUyEPCiPp", - "/dns/westend-collectives-collator-node-3.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWBbrBYhXxFXhdio3AiuaqMG26pn91SUnd12gJiVn2Wh8Q", "/dns/westend-collectives-collator-0.polkadot.io/tcp/443/wss/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", "/dns/westend-collectives-collator-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", - "/dns/westend-collectives-collator-2.polkadot.io/tcp/443/wss/p2p/12D3KooWP4pJg6pZUpxETd8Rs6GmS9FeRCeNtrBerqZhUyEPCiPp", - "/dns/westend-collectives-collator-3.polkadot.io/tcp/443/wss/p2p/12D3KooWBbrBYhXxFXhdio3AiuaqMG26pn91SUnd12gJiVn2Wh8Q", "/dns/boot.stake.plus/tcp/38333/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", "/dns/boot.stake.plus/tcp/38334/wss/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", "/dns/boot.metaspan.io/tcp/36072/p2p/12D3KooWEf2QXWq5pAbFJLfbnexA7KYtRRDSPkqTP64n1KtdsdV2", @@ -107,4 +103,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/contracts-rococo.json b/cumulus/parachains/chain-specs/contracts-rococo.json index 09108e9c099..422268a5efd 100644 --- a/cumulus/parachains/chain-specs/contracts-rococo.json +++ b/cumulus/parachains/chain-specs/contracts-rococo.json @@ -5,12 +5,8 @@ "bootNodes": [ "/dns/rococo-contracts-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj", "/dns/rococo-contracts-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh", - "/dns/rococo-contracts-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk", - "/dns/rococo-contracts-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX", "/dns/rococo-contracts-collator-node-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj", - "/dns/rococo-contracts-collator-node-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh", - "/dns/rococo-contracts-collator-node-2.polkadot.io/tcp/443/wss/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk", - "/dns/rococo-contracts-collator-node-3.polkadot.io/tcp/443/wss/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX" + "/dns/rococo-contracts-collator-node-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" ], "telemetryEndpoints": null, diff --git a/polkadot/node/service/chain-specs/rococo.json b/polkadot/node/service/chain-specs/rococo.json index 2648063641c..e16962981e1 100644 --- a/polkadot/node/service/chain-specs/rococo.json +++ b/polkadot/node/service/chain-specs/rococo.json @@ -5,28 +5,10 @@ "bootNodes": [ "/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", - "/dns/rococo-bootnode-3.polkadot.io/tcp/443/wss/p2p/12D3KooWPeKuW1BBPv4pNr8xqEv7jqy7rQnS3oq9U7xTCvj9qt2k", - "/dns/rococo-bootnode-4.polkadot.io/tcp/443/wss/p2p/12D3KooWNy7K8TNaP2Whcp3tsjBVUg2HcKMUvAArsimjvd1g31w4", - "/dns/rococo-bootnode-5.polkadot.io/tcp/443/wss/p2p/12D3KooWAVV9DZfvJp2brvs5zcQDTBFxNmEFJKy2dsvezWL4Bmy8", - "/dns/rococo-bootnode-6.polkadot.io/tcp/443/wss/p2p/12D3KooWM3hvXvaShyp7drQCavFHuwobkYdnCp2uHU5iRRAQwsw2", - "/dns/rococo-bootnode-7.polkadot.io/tcp/443/wss/p2p/12D3KooWSbGtxfWCwn1tdmfZYESbmxzbTG2LKwKUrioDaZBcdMY4" + "/dns/rococo-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWLDfH9mHRCidrd5NfQjp7rRMUcJSEUwSvEKyu7xU2cG3d" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index fd1f4550127..b2ffba9304b 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -8,12 +8,6 @@ "/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", -- GitLab From c46a7dbb6126c368766a0e8a02fc04853c241643 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Sun, 5 Nov 2023 13:51:36 +0100 Subject: [PATCH 442/633] Tracking allocator: mark `Spinlock::unlock()` as unsafe and provide a safety contract (#2156) --- polkadot/node/tracking-allocator/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/polkadot/node/tracking-allocator/src/lib.rs b/polkadot/node/tracking-allocator/src/lib.rs index 8441bd1ffaf..ab8597b5c38 100644 --- a/polkadot/node/tracking-allocator/src/lib.rs +++ b/polkadot/node/tracking-allocator/src/lib.rs @@ -72,8 +72,11 @@ impl Spinlock { } } + // SAFETY: It should be only called from the guard's destructor. Calling it explicitly while + // the guard is alive is undefined behavior, as it breaks the security contract of `Deref` and + // `DerefMut`, which implies that lock is held at the moment of dereferencing. #[inline] - fn unlock(&self) { + unsafe fn unlock(&self) { self.lock.store(false, Ordering::Release); } } @@ -97,7 +100,9 @@ impl DerefMut for SpinlockGuard<'_, T> { impl Drop for SpinlockGuard<'_, T> { fn drop(&mut self) { - self.lock.unlock(); + // SAFETY: Calling `unlock` is only safe when it's guaranteed no guard outlives the + // unlocking point; here, the guard is dropped, so it is safe. + unsafe { self.lock.unlock() } } } -- GitLab From 8ba7a6aba89fe7b2fd22a66f5b7c7b13e75f5e91 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:19:23 +0100 Subject: [PATCH 443/633] `chain-spec`: getting ready for native-runtime-free world (#1256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR prepares chains specs for _native-runtime-free_ world. This PR has following changes: - `substrate`: - adds support for: - JSON based `GenesisConfig` to `ChainSpec` allowing interaction with runtime `GenesisBuilder` API. - interacting with arbitrary runtime wasm blob to[ `chain-spec-builder`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/bin/utils/chain-spec-builder/src/lib.rs#L46) command line util, - removes [`code`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/frame/system/src/lib.rs#L660) from `system_pallet` - adds `code` to the `ChainSpec` - deprecates [`ChainSpec::from_genesis`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/client/chain-spec/src/chain_spec.rs#L263), but also changes the signature of this method extending it with `code` argument. [`ChainSpec::builder()`](https://github.com/paritytech/substrate/blob/20bee680ed098be7239cf7a6b804cd4de267983e/client/chain-spec/src/chain_spec.rs#L507) should be used instead. - `polkadot`: - all references to `RuntimeGenesisConfig` in `node/service` are removed, - all `(kusama|polkadot|versi|rococo|wococo)_(staging|dev)_genesis_config` functions now return the JSON patch for default runtime `GenesisConfig`, - `ChainSpecBuilder` is used, `ChainSpec::from_genesis` is removed, - `cumulus`: - `ChainSpecBuilder` is used, `ChainSpec::from_genesis` is removed, - _JSON_ patch configuration used instead of `RuntimeGenesisConfig struct` in all chain specs. --------- Co-authored-by: command-bot <> Co-authored-by: Javier Viola Co-authored-by: Davide Galassi Co-authored-by: Francisco Aguirre Co-authored-by: Kevin Krone Co-authored-by: Bastian Köcher --- .gitlab-ci.yml | 2 +- Cargo.lock | 29 + cumulus/parachain-template/node/Cargo.toml | 1 + .../parachain-template/node/src/chain_spec.rs | 221 ++-- .../emulated/common/Cargo.toml | 2 + .../emulated/common/src/constants.rs | 895 ++++++++++---- .../assets/asset-hub-rococo/Cargo.toml | 2 + .../assets/asset-hub-rococo/src/lib.rs | 11 + cumulus/polkadot-parachain/Cargo.toml | 1 + .../src/chain_spec/asset_hubs.rs | 1093 ++++++++--------- .../src/chain_spec/bridge_hubs.rs | 548 ++++----- .../src/chain_spec/collectives.rs | 181 ++- .../src/chain_spec/contracts.rs | 346 +++--- .../src/chain_spec/glutton.rs | 125 +- .../src/chain_spec/penpal.rs | 128 +- .../src/chain_spec/rococo_parachain.rs | 136 +- .../src/chain_spec/seedling.rs | 54 +- .../src/chain_spec/shell.rs | 47 +- cumulus/polkadot-parachain/src/command.rs | 39 +- cumulus/test/client/src/lib.rs | 27 +- cumulus/test/runtime/Cargo.toml | 2 + cumulus/test/runtime/src/lib.rs | 11 + cumulus/test/service/Cargo.toml | 1 + cumulus/test/service/src/chain_spec.rs | 49 +- cumulus/test/service/src/cli.rs | 5 +- cumulus/test/service/src/genesis.rs | 2 +- cumulus/test/service/src/lib.rs | 2 +- cumulus/test/service/src/main.rs | 2 +- .../zombienet/tests/0002-pov_recovery.toml | 2 +- .../tests/0005-migrate_solo_to_para.toml | 2 +- polkadot/node/service/src/chain_spec.rs | 536 +++----- polkadot/node/test/client/src/lib.rs | 2 +- polkadot/node/test/service/Cargo.toml | 1 - polkadot/node/test/service/src/chain_spec.rs | 83 +- polkadot/runtime/common/src/lib.rs | 5 +- .../runtime/parachains/src/configuration.rs | 1 + polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/rococo/constants/Cargo.toml | 3 + .../functional/0002-parachains-disputes.toml | 2 +- .../0004-parachains-garbage-candidate.toml | 2 +- ...0005-parachains-disputes-past-session.toml | 2 +- .../zombienet_tests/misc/0001-paritydb.toml | 2 +- prdoc/pr_1256.prdoc | 19 + substrate/Cargo.toml | 1 + substrate/bin/minimal/node/Cargo.toml | 1 + substrate/bin/minimal/node/src/chain_spec.rs | 41 +- substrate/bin/minimal/runtime/Cargo.toml | 4 + substrate/bin/minimal/runtime/src/lib.rs | 11 + substrate/bin/node-template/node/Cargo.toml | 1 + .../bin/node-template/node/src/chain_spec.rs | 161 +-- .../bin/node-template/runtime/Cargo.toml | 14 +- substrate/bin/node/cli/Cargo.toml | 1 - substrate/bin/node/cli/src/chain_spec.rs | 246 ++-- substrate/bin/node/executor/Cargo.toml | 7 +- substrate/bin/node/executor/benches/bench.rs | 2 +- substrate/bin/node/executor/tests/basic.rs | 16 + substrate/bin/node/executor/tests/common.rs | 2 +- .../tests/res/default_genesis_config.json | 108 ++ substrate/bin/node/runtime/Cargo.toml | 20 +- substrate/bin/node/testing/src/bench.rs | 22 +- substrate/bin/node/testing/src/client.rs | 7 +- substrate/bin/node/testing/src/genesis.rs | 18 +- .../bin/utils/chain-spec-builder/Cargo.toml | 4 + .../bin/utils/chain-spec-builder/bin/main.rs | 87 +- .../bin/utils/chain-spec-builder/src/lib.rs | 311 +++-- substrate/client/chain-spec/Cargo.toml | 12 + substrate/client/chain-spec/README.md | 90 +- .../client/chain-spec/res/raw_no_code.json | 18 + .../client/chain-spec/res/raw_with_code.json | 19 + .../substrate_test_runtime_from_config.json | 128 ++ ...ubstrate_test_runtime_from_config_raw.json | 53 + .../substrate_test_runtime_from_patch.json | 32 + ...substrate_test_runtime_from_patch_raw.json | 32 + substrate/client/chain-spec/src/chain_spec.rs | 830 ++++++++++++- .../src/{genesis.rs => genesis_block.rs} | 0 .../chain-spec/src/genesis_config_builder.rs | 183 +++ substrate/client/chain-spec/src/json_patch.rs | 191 +++ substrate/client/chain-spec/src/lib.rs | 352 ++++-- .../client/cli/src/commands/insert_key.rs | 20 +- substrate/client/cli/src/runner.rs | 20 +- substrate/frame/system/src/lib.rs | 3 - substrate/src/lib.rs | 8 +- substrate/test-utils/runtime/Cargo.toml | 4 +- .../runtime/{src/test_json => res}/README.md | 0 .../default_genesis_config.json | 4 +- .../default_genesis_config_incomplete.json | 4 +- .../default_genesis_config_invalid.json | 4 +- .../res/default_genesis_config_invalid_2.json | 113 ++ .../test-utils/runtime/src/genesismap.rs | 10 +- substrate/test-utils/runtime/src/lib.rs | 51 +- 90 files changed, 4833 insertions(+), 3059 deletions(-) create mode 100644 prdoc/pr_1256.prdoc create mode 100644 substrate/bin/node/executor/tests/res/default_genesis_config.json create mode 100644 substrate/client/chain-spec/res/raw_no_code.json create mode 100644 substrate/client/chain-spec/res/raw_with_code.json create mode 100644 substrate/client/chain-spec/res/substrate_test_runtime_from_config.json create mode 100644 substrate/client/chain-spec/res/substrate_test_runtime_from_config_raw.json create mode 100644 substrate/client/chain-spec/res/substrate_test_runtime_from_patch.json create mode 100644 substrate/client/chain-spec/res/substrate_test_runtime_from_patch_raw.json rename substrate/client/chain-spec/src/{genesis.rs => genesis_block.rs} (100%) create mode 100644 substrate/client/chain-spec/src/genesis_config_builder.rs create mode 100644 substrate/client/chain-spec/src/json_patch.rs rename substrate/test-utils/runtime/{src/test_json => res}/README.md (100%) rename substrate/test-utils/runtime/{src/test_json => res}/default_genesis_config.json (98%) rename substrate/test-utils/runtime/{src/test_json => res}/default_genesis_config_incomplete.json (98%) rename substrate/test-utils/runtime/{src/test_json => res}/default_genesis_config_invalid.json (98%) create mode 100644 substrate/test-utils/runtime/res/default_genesis_config_invalid_2.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 835b668de25..f507afda23e 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.75" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.79" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/Cargo.lock b/Cargo.lock index b4501b5d751..1b4496368ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -965,6 +965,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -4222,6 +4223,7 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -4288,6 +4290,7 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "serde", + "serde_json", "sp-api", "sp-arithmetic", "sp-authority-discovery", @@ -6738,7 +6741,9 @@ dependencies = [ "polkadot-service", "rococo-runtime", "rococo-runtime-constants", + "sc-chain-spec", "sc-consensus-grandpa", + "serde_json", "sp-authority-discovery", "sp-consensus-babe", "sp-consensus-beefy", @@ -7159,6 +7164,7 @@ dependencies = [ "parity-scale-codec", "primitive-types", "scale-info", + "serde_json", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -8199,6 +8205,7 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", + "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -8215,6 +8222,7 @@ name = "minimal-runtime" version = "0.1.0" dependencies = [ "frame", + "frame-support", "pallet-balances", "pallet-sudo", "pallet-timestamp", @@ -8222,6 +8230,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "scale-info", + "sp-genesis-builder", "substrate-wasm-builder", ] @@ -8679,6 +8688,7 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", + "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -8730,6 +8740,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "scale-info", + "serde_json", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -11168,6 +11179,7 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "serde", + "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -12743,6 +12755,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-timestamp", + "sp-tracing 10.0.0", "sp-transaction-pool", "staging-xcm", "substrate-build-script-utils", @@ -14783,7 +14796,11 @@ dependencies = [ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ + "array-bytes 6.1.0", + "docify", + "log", "memmap2", + "parity-scale-codec", "sc-chain-spec-derive", "sc-client-api", "sc-executor", @@ -14791,10 +14808,16 @@ dependencies = [ "sc-telemetry", "serde", "serde_json", + "sp-application-crypto", "sp-blockchain", + "sp-consensus-babe", "sp-core", + "sp-genesis-builder", + "sp-io", + "sp-keyring", "sp-runtime", "sp-state-machine", + "substrate-test-runtime", ] [[package]] @@ -17986,11 +18009,15 @@ version = "2.0.0" dependencies = [ "ansi_term", "clap 4.4.6", + "kitchensink-runtime", + "log", "rand 0.8.5", "sc-chain-spec", "sc-keystore", + "serde_json", "sp-core", "sp-keystore", + "sp-tracing 10.0.0", "staging-node-cli", ] @@ -18110,6 +18137,7 @@ dependencies = [ "parity-scale-codec", "sc-executor", "scale-info", + "serde_json", "sp-application-crypto", "sp-consensus-babe", "sp-core", @@ -18339,6 +18367,7 @@ name = "substrate" version = "1.0.0" dependencies = [ "frame-support", + "sc-chain-spec", "sc-cli", "sc-consensus-aura", "sc-consensus-babe", diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 3507e9bcd32..2a08395008f 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.28" +serde_json = "1.0.104" # Local parachain-template-runtime = { path = "../runtime" } diff --git a/cumulus/parachain-template/node/src/chain_spec.rs b/cumulus/parachain-template/node/src/chain_spec.rs index 0ca3c51900f..a79c78699c0 100644 --- a/cumulus/parachain-template/node/src/chain_spec.rs +++ b/cumulus/parachain-template/node/src/chain_spec.rs @@ -7,8 +7,7 @@ use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; /// Specialized `ChainSpec` for the normal parachain runtime. -pub type ChainSpec = - sc_service::GenericChainSpec; +pub type ChainSpec = sc_service::GenericChainSpec<(), Extensions>; /// The default XCM version to set in genesis config. const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; @@ -68,53 +67,48 @@ pub fn development_config() -> ChainSpec { properties.insert("tokenDecimals".into(), 12.into()); properties.insert("ss58Format".into(), 42.into()); - ChainSpec::from_genesis( - // Name - "Development", - // ID - "dev", - ChainType::Development, - move || { - testnet_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - get_account_id_from_seed::("Alice"), - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - None, + ChainSpec::builder( + parachain_template_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + relay_chain: "rococo-local".into(), + // You MUST set this to the correct network! para_id: 1000, }, ) + .with_name("Development") + .with_id("dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + 1000.into(), + )) + .build() } pub fn local_testnet_config() -> ChainSpec { @@ -124,59 +118,51 @@ pub fn local_testnet_config() -> ChainSpec { properties.insert("tokenDecimals".into(), 12.into()); properties.insert("ss58Format".into(), 42.into()); - ChainSpec::from_genesis( - // Name - "Local Testnet", - // ID - "local_testnet", - ChainType::Local, - move || { - testnet_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - get_account_id_from_seed::("Alice"), - 1000.into(), - ) - }, - // Bootnodes - Vec::new(), - // Telemetry - None, - // Protocol ID - Some("template-local"), - // Fork ID - None, - // Properties - Some(properties), - // Extensions + #[allow(deprecated)] + ChainSpec::builder( + parachain_template_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + relay_chain: "rococo-local".into(), + // You MUST set this to the correct network! para_id: 1000, }, ) + .with_name("Local Testnet") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + 1000.into(), + )) + .with_protocol_id("template-local") + .with_properties(properties) + .build() } fn testnet_genesis( @@ -184,28 +170,20 @@ fn testnet_genesis( endowed_accounts: Vec, root: AccountId, id: ParaId, -) -> parachain_template_runtime::RuntimeGenesisConfig { - parachain_template_runtime::RuntimeGenesisConfig { - system: parachain_template_runtime::SystemConfig { - code: parachain_template_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: parachain_template_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), +) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - parachain_info: parachain_template_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: parachain_template_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: EXISTENTIAL_DEPOSIT * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": EXISTENTIAL_DEPOSIT * 16, }, - session: parachain_template_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -214,18 +192,11 @@ fn testnet_genesis( template_session_keys(aura), // session keys ) }) - .collect(), + .collect::>(), }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: parachain_template_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - transaction_payment: Default::default(), - sudo: parachain_template_runtime::SudoConfig { key: Some(root) }, - } + "sudo": { "key": Some(root) } + }) } diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 5845e6940fb..4182fea5274 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -10,6 +10,7 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } paste = "1.0.14" +serde_json = "1.0.104" # Substrate grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/client/consensus/grandpa" } @@ -24,6 +25,7 @@ pallet-staking = { path = "../../../../../substrate/frame/staking", default-feat pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} pallet-im-online = { path = "../../../../../substrate/frame/im-online", default-features = false} beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../substrate/primitives/consensus/beefy" } +sc-chain-spec = { path = "../../../../../substrate/client/chain-spec", default-features = false } # Polkadot polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 592269e9aa3..86027229c59 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -17,12 +17,15 @@ use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{sr25519, storage::Storage, Pair, Public}; +#[cfg(test)] +use sp_runtime::BuildStorage; use sp_runtime::{ traits::{IdentifyAccount, Verify}, - BuildStorage, MultiSignature, Perbill, + MultiSignature, Perbill, }; // Cumulus @@ -58,6 +61,29 @@ where AccountPublic::from(get_from_seed::(seed)).into_account() } +/// Helper function to build the genesis storage using given json patch and code +fn build_genesis_storage(patch: serde_json::Value, code: &[u8]) -> Storage { + let mut storage = GenesisConfigBuilderRuntimeCaller::new(code) + .get_storage_for_patch(patch) + .unwrap(); + storage + .top + .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.into()); + storage +} + +#[cfg(test)] +/// Helper function used in tests to build the genesis storage using given RuntimeGenesisConfig and +/// code Used in `legacy_vs_json_check` submods to verify storage building with JSON patch against +/// building with RuntimeGenesisConfig struct. +fn build_genesis_storage_legacy(builder: &dyn BuildStorage, code: &[u8]) -> Storage { + let mut storage = builder.build_storage().unwrap(); + storage + .top + .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.into()); + storage +} + pub mod accounts { use super::*; pub const ALICE: &str = "Alice"; @@ -186,20 +212,16 @@ pub mod westend { } pub fn genesis() -> Storage { - let genesis_config = westend_runtime::RuntimeGenesisConfig { - system: westend_runtime::SystemConfig { - code: westend_runtime::WASM_BINARY.unwrap().to_vec(), - ..Default::default() - }, - balances: westend_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ENDOWMENT)) - .collect(), + .collect::>(), }, - session: westend_runtime::SessionConfig { - keys: validators::initial_authorities() + "session": { + "keys": validators::initial_authorities() .iter() .map(|x| { ( @@ -218,33 +240,106 @@ pub mod westend { }) .collect::>(), }, - staking: westend_runtime::StakingConfig { - validator_count: validators::initial_authorities().len() as u32, - minimum_validator_count: 1, - stakers: validators::initial_authorities() + "staking": { + "validatorCount": validators::initial_authorities().len() as u32, + "minimumValidatorCount": 1, + "stakers": validators::initial_authorities() .iter() .map(|x| { - (x.0.clone(), x.1.clone(), STASH, westend_runtime::StakerStatus::Validator) + (x.0.clone(), x.1.clone(), STASH, westend_runtime::StakerStatus::::Validator) }) - .collect(), - invulnerables: validators::initial_authorities() + .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() + .collect::>(), + "forceEra": pallet_staking::Forcing::ForceNone, + "slashRewardFraction": Perbill::from_percent(10), }, - babe: westend_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + "babe": { + "epochConfig": Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), }, - configuration: westend_runtime::ConfigurationConfig { config: get_host_config() }, - ..Default::default() - }; + "configuration": { "config": get_host_config() }, + }); - genesis_config.build_storage().unwrap() + build_genesis_storage(genesis_config, westend_runtime::WASM_BINARY.unwrap()) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + fn genesis() -> Storage { + let genesis_config = westend_runtime::RuntimeGenesisConfig { + system: westend_runtime::SystemConfig::default(), + balances: westend_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ENDOWMENT)) + .collect(), + }, + session: westend_runtime::SessionConfig { + keys: validators::initial_authorities() + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + westend::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::>(), + }, + staking: westend_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, + westend_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: westend_runtime::BabeConfig { + authorities: Default::default(), + epoch_config: Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), + ..Default::default() + }, + configuration: westend_runtime::ConfigurationConfig { config: get_host_config() }, + ..Default::default() + }; + + build_genesis_storage_legacy(&genesis_config, westend_runtime::WASM_BINARY.unwrap()) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } @@ -294,20 +389,16 @@ pub mod rococo { } 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() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .map(|k| (k.clone(), ENDOWMENT)) - .collect(), + .collect::>(), }, // indices: rococo_runtime::IndicesConfig { indices: vec![] }, - session: rococo_runtime::SessionConfig { - keys: validators::initial_authorities() + "session": { + "keys": validators::initial_authorities() .iter() .map(|x| { ( @@ -326,16 +417,14 @@ pub mod rococo { }) .collect::>(), }, - babe: rococo_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + "babe": { + "epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), }, - sudo: rococo_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + "sudo": { + "key": Some(get_account_id_from_seed::("Alice")), }, - configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, - paras: rococo_runtime::ParasConfig { + "configuration": { "config": get_host_config() }, + "paras": rococo_runtime::ParasConfig { paras: vec![ ( asset_hub_rococo::PARA_ID.into(), @@ -370,14 +459,109 @@ pub mod rococo { ], ..Default::default() }, - registrar: rococo_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() + "registrar": { + "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, }, - ..Default::default() - }; + }); + + build_genesis_storage(genesis_config, rococo_runtime::WASM_BINARY.unwrap()) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + fn genesis() -> Storage { + let genesis_config = rococo_runtime::RuntimeGenesisConfig { + system: rococo_runtime::SystemConfig::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() }, + paras: rococo_runtime::ParasConfig { + paras: vec![ + ( + asset_hub_rococo::PARA_ID.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + asset_hub_rococo_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() + }, + registrar: rococo_runtime::RegistrarConfig { + next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, + ..Default::default() + }, + ..Default::default() + }; - genesis_config.build_storage().unwrap() + build_genesis_storage_legacy(&genesis_config, rococo_runtime::WASM_BINARY.unwrap()) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } @@ -388,35 +572,27 @@ pub mod asset_hub_westend { pub const ED: Balance = parachains_common::westend::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 - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: asset_hub_westend_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), }, - collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() + "collatorSelection": { + "invulnerables": collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() + .collect::>(), + "candidacyBond": ED * 16, }, - session: asset_hub_westend_runtime::SessionConfig { - keys: collators::invulnerables() + "session": { + "keys": collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( @@ -425,16 +601,80 @@ pub mod asset_hub_westend { asset_hub_westend_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - ..Default::default() - }; + }); - genesis_config.build_storage().unwrap() + build_genesis_storage( + genesis_config, + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + fn genesis() -> Storage { + let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { + system: asset_hub_westend_runtime::SystemConfig::default(), + balances: asset_hub_westend_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_westend_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 + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } @@ -444,109 +684,221 @@ pub mod asset_hub_rococo { pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - 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_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096 * 4096)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), }, - collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() + "collatorSelection": { + "invulnerables": collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() + .collect::>(), + "candidacyBond": ED * 16, }, - session: asset_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() + "session": { + "keys": collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( - acc.clone(), // account id - acc, // validator id + acc.clone(), // account id + acc, // validator id asset_hub_rococo_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - ..Default::default() - }; + }); + + build_genesis_storage( + genesis_config, + asset_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + pub fn genesis() -> Storage { + let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig::default(), + balances: asset_hub_rococo_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096 * 4096)) + .collect(), + }, + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + asset_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } - genesis_config.build_storage().unwrap() + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } pub mod asset_hub_wococo { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::wococo::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - 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_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), }, - collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() + "collatorSelection": { + "invulnerables": collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() + .collect::>(), + "candidacyBond": ED * 16, }, - session: asset_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() + "session": { + "keys": collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( - acc.clone(), // account id - acc, // validator id - asset_hub_rococo_runtime::SessionKeys { aura }, // session keys + acc.clone(), // account id + acc, // validator id + asset_hub_westend_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - ..Default::default() - }; + }); + + build_genesis_storage( + genesis_config, + asset_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + pub fn genesis() -> Storage { + let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig::default(), + balances: asset_hub_rococo_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; - genesis_config.build_storage().unwrap() + build_genesis_storage_legacy( + &genesis_config, + asset_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } @@ -558,35 +910,27 @@ pub mod penpal { pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; pub fn genesis(para_id: u32) -> Storage { - let genesis_config = penpal_runtime::RuntimeGenesisConfig { - system: penpal_runtime::SystemConfig { - code: penpal_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: penpal_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: penpal_runtime::ParachainInfoConfig { - parachain_id: para_id.into(), - ..Default::default() + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(para_id), }, - collator_selection: penpal_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() + "collatorSelection": { + "invulnerables": collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() + .collect::>(), + "candidacyBond": ED * 16, }, - session: penpal_runtime::SessionConfig { - keys: collators::invulnerables() + "session": { + "keys": collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( @@ -595,19 +939,84 @@ pub mod penpal { penpal_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - polkadot_xcm: penpal_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - sudo: penpal_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + "sudo": { + "key": Some(get_account_id_from_seed::("Alice")), }, - ..Default::default() - }; + }); - genesis_config.build_storage().unwrap() + build_genesis_storage( + genesis_config, + penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + fn genesis(para_id: u32) -> Storage { + let genesis_config = penpal_runtime::RuntimeGenesisConfig { + system: penpal_runtime::SystemConfig::default(), + balances: penpal_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: penpal_runtime::ParachainInfoConfig { + parachain_id: para_id.into(), + ..Default::default() + }, + collator_selection: penpal_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: penpal_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + penpal_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: penpal_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + sudo: penpal_runtime::SudoConfig { + key: Some(get_account_id_from_seed::("Alice")), + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(101); + let j2 = genesis(101); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } @@ -618,35 +1027,27 @@ pub mod bridge_hub_rococo { pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { - system: bridge_hub_rococo_runtime::SystemConfig { - code: bridge_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: bridge_hub_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), }, - collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() + "collatorSelection": { + "invulnerables": collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() + .collect::>(), + "candidacyBond": ED * 16, }, - session: bridge_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() + "session": { + "keys": collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( @@ -655,31 +1056,107 @@ pub mod bridge_hub_rococo { bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() + "bridgeWococoGrandpa": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), }, - bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() + "bridgeRococoGrandpa": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() + "bridgeRococoMessages": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + "bridgeWococoMessages": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), + } + }); + + build_genesis_storage( + genesis_config, + bridge_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[cfg(test)] + mod legacy_vs_json_check { + use super::*; + fn genesis() -> Storage { + let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { + system: bridge_hub_rococo_runtime::SystemConfig::default(), + balances: bridge_hub_rococo_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: bridge_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, ..Default::default() - }, - ..Default::default() - }; + }; - genesis_config.build_storage().unwrap() + build_genesis_storage_legacy( + &genesis_config, + bridge_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } + + #[test] + fn test_genesis() { + let j1 = super::genesis(); + let j2 = genesis(); + + assert_eq!(j1.top, j2.top); + assert_eq!(j1.children_default, j2.children_default); + } } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 7efcf1e1585..0b163ae1a20 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -45,6 +45,7 @@ sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", 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-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", 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} @@ -230,6 +231,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-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 2c6c85619c9..f649ebedeff 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -60,6 +60,7 @@ use cumulus_primitives_core::ParaId; 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, @@ -1568,6 +1569,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/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 56646efc61a..c7a79e3e97a 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -48,6 +48,7 @@ sp-io = { path = "../../substrate/primitives/io" } sp-core = { path = "../../substrate/primitives/core" } sp-session = { path = "../../substrate/primitives/session" } sc-consensus = { path = "../../substrate/client/consensus/common" } +sp-tracing = { path = "../../substrate/primitives/tracing" } sc-cli = { path = "../../substrate/client/cli" } sc-client-api = { path = "../../substrate/client/api" } sc-executor = { path = "../../substrate/client/executor" } diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 636488cbfe2..b4a73ff8aaa 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -79,35 +79,30 @@ pub fn asset_hub_polkadot_development_config() -> AssetHubPolkadotChainSpec { properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::from_genesis( - // Name - "Polkadot Asset Hub Development", - // ID - "asset-hub-polkadot-dev", - ChainType::Local, - move || { - asset_hub_polkadot_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubPolkadotChainSpec::builder( + asset_hub_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-dev".into(), para_id: 1000 }, ) + .with_name("Polkadot Asset Hub Development") + .with_id("asset-hub-polkadot-dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_polkadot_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"), + ], + 1000.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_polkadot_local_config() -> AssetHubPolkadotChainSpec { @@ -116,49 +111,45 @@ pub fn asset_hub_polkadot_local_config() -> AssetHubPolkadotChainSpec { properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::from_genesis( - // Name - "Polkadot Asset Hub Local", - // ID - "asset-hub-polkadot-local", - ChainType::Local, - move || { - asset_hub_polkadot_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubPolkadotChainSpec::builder( + asset_hub_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 }, ) + .with_name("Polkadot Asset Hub Local") + .with_id("asset-hub-polkadot-local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_polkadot_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"), + ], + 1000.into(), + )) + .with_boot_nodes(Vec::new()) + .with_properties(properties) + .build() } // Not used for syncing, but just to determine the genesis values set for the upgrade from shell. @@ -168,89 +159,81 @@ pub fn asset_hub_polkadot_config() -> AssetHubPolkadotChainSpec { properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::from_genesis( - // Name - "Polkadot Asset Hub", - // ID - "asset-hub-polkadot", - ChainType::Live, - move || { - asset_hub_polkadot_genesis( - // initial collators. - vec![ - ( - hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421") - .into(), - hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421") - .unchecked_into(), - ), - ( - hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811") - .into(), - hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811") - .unchecked_into(), - ), - ( - hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762") - .into(), - hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762") - .unchecked_into(), - ), - ( - hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3") - .into(), - hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3") - .unchecked_into(), - ), - ], - vec![], - 1000u32.into(), - ) - }, - vec![ - "/ip4/34.65.251.121/tcp/30334/p2p/12D3KooWG3GrM6XKMM4gp3cvemdwUvu96ziYoJmqmetLZBXE8bSa".parse().unwrap(), - "/ip4/34.65.35.228/tcp/30334/p2p/12D3KooWMRyTLrCEPcAQD6c4EnudL3vVzg9zji3whvsMYPUYevpq".parse().unwrap(), - "/ip4/34.83.247.146/tcp/30334/p2p/12D3KooWE4jFh5FpJDkWVZhnWtFnbSqRhdjvC7Dp9b8b3FTuubQC".parse().unwrap(), - "/ip4/104.199.117.230/tcp/30334/p2p/12D3KooWG9R8pVXKumVo2rdkeVD4j5PVhRTqmYgLHY3a4yPYgLqM".parse().unwrap(), - ], - None, - None, - None, - Some(properties), + AssetHubPolkadotChainSpec::builder( + asset_hub_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot".into(), para_id: 1000 }, ) + .with_name("Polkadot Asset Hub") + .with_id("asset-hub-polkadot") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(asset_hub_polkadot_genesis( + // initial collators. + vec![ + ( + hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421").into(), + hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421") + .unchecked_into(), + ), + ( + hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811").into(), + hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811") + .unchecked_into(), + ), + ( + hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762").into(), + hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762") + .unchecked_into(), + ), + ( + hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3").into(), + hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3") + .unchecked_into(), + ), + ], + vec![], + 1000u32.into(), + )) + .with_boot_nodes(vec![ + "/ip4/34.65.251.121/tcp/30334/p2p/12D3KooWG3GrM6XKMM4gp3cvemdwUvu96ziYoJmqmetLZBXE8bSa" + .parse() + .unwrap(), + "/ip4/34.65.35.228/tcp/30334/p2p/12D3KooWMRyTLrCEPcAQD6c4EnudL3vVzg9zji3whvsMYPUYevpq" + .parse() + .unwrap(), + "/ip4/34.83.247.146/tcp/30334/p2p/12D3KooWE4jFh5FpJDkWVZhnWtFnbSqRhdjvC7Dp9b8b3FTuubQC" + .parse() + .unwrap(), + "/ip4/104.199.117.230/tcp/30334/p2p/12D3KooWG9R8pVXKumVo2rdkeVD4j5PVhRTqmYgLHY3a4yPYgLqM" + .parse() + .unwrap(), + ]) + .with_properties(properties) + .build() } fn asset_hub_polkadot_genesis( invulnerables: Vec<(AccountId, AssetHubPolkadotAuraId)>, endowed_accounts: Vec, id: ParaId, -) -> asset_hub_polkadot_runtime::RuntimeGenesisConfig { - asset_hub_polkadot_runtime::RuntimeGenesisConfig { - system: asset_hub_polkadot_runtime::SystemConfig { - code: asset_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: asset_hub_polkadot_runtime::BalancesConfig { - balances: endowed_accounts +) -> serde_json::Value { + serde_json::json!( { + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, ASSET_HUB_POLKADOT_ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: asset_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ASSET_HUB_POLKADOT_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": ASSET_HUB_POLKADOT_ED * 16, }, - session: asset_hub_polkadot_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -259,18 +242,12 @@ fn asset_hub_polkadot_genesis( asset_hub_polkadot_session_keys(aura), // session keys ) }) - .collect(), - }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: asset_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + .collect::>(), }, - } + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + } + }) } pub fn asset_hub_kusama_development_config() -> AssetHubKusamaChainSpec { @@ -279,35 +256,29 @@ pub fn asset_hub_kusama_development_config() -> AssetHubKusamaChainSpec { properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::from_genesis( - // Name - "Kusama Asset Hub Development", - // ID - "asset-hub-kusama-dev", - ChainType::Local, - move || { - asset_hub_kusama_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubKusamaChainSpec::builder( + asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-dev".into(), para_id: 1000 }, ) + .with_name("Kusama Asset Hub Development") + .with_id("asset-hub-kusama-dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_kusama_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"), + ], + 1000.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_kusama_local_config() -> AssetHubKusamaChainSpec { @@ -316,49 +287,43 @@ pub fn asset_hub_kusama_local_config() -> AssetHubKusamaChainSpec { properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::from_genesis( - // Name - "Kusama Asset Hub Local", - // ID - "asset-hub-kusama-local", - ChainType::Local, - move || { - asset_hub_kusama_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubKusamaChainSpec::builder( + asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-local".into(), para_id: 1000 }, ) + .with_name("Kusama Asset Hub Local") + .with_id("asset-hub-kusama-local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_kusama_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"), + ], + 1000.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_kusama_config() -> AssetHubKusamaChainSpec { @@ -367,84 +332,66 @@ pub fn asset_hub_kusama_config() -> AssetHubKusamaChainSpec { properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::from_genesis( - // Name - "Kusama Asset Hub", - // ID - "asset-hub-kusama", - ChainType::Live, - move || { - asset_hub_kusama_genesis( - // initial collators. - vec![ - ( - hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730") - .into(), - hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730") - .unchecked_into(), - ), - ( - hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a") - .into(), - hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a") - .unchecked_into(), - ), - ( - hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a") - .into(), - hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a") - .unchecked_into(), - ), - ( - hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415") - .into(), - hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415") - .unchecked_into(), - ), - ], - Vec::new(), - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubKusamaChainSpec::builder( + asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama".into(), para_id: 1000 }, ) + .with_name("Kusama Asset Hub") + .with_id("asset-hub-kusama") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(asset_hub_kusama_genesis( + // initial collators. + vec![ + ( + hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730").into(), + hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730") + .unchecked_into(), + ), + ( + hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a").into(), + hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a") + .unchecked_into(), + ), + ( + hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a").into(), + hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a") + .unchecked_into(), + ), + ( + hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415").into(), + hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415") + .unchecked_into(), + ), + ], + Vec::new(), + 1000.into(), + )) + .with_properties(properties) + .build() } fn asset_hub_kusama_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, -) -> asset_hub_kusama_runtime::RuntimeGenesisConfig { - asset_hub_kusama_runtime::RuntimeGenesisConfig { - system: asset_hub_kusama_runtime::SystemConfig { - code: asset_hub_kusama_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: asset_hub_kusama_runtime::BalancesConfig { - balances: endowed_accounts +) -> serde_json::Value { + serde_json::json!( { + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, ASSET_HUB_KUSAMA_ED * 524_288)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_kusama_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: asset_hub_kusama_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ASSET_HUB_KUSAMA_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": ASSET_HUB_KUSAMA_ED * 16, }, - session: asset_hub_kusama_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -453,16 +400,12 @@ fn asset_hub_kusama_genesis( asset_hub_kusama_session_keys(aura), // session keys ) }) - .collect(), + .collect::>(), }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: asset_hub_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - } + }) } pub fn asset_hub_westend_development_config() -> AssetHubWestendChainSpec { @@ -470,35 +413,30 @@ pub fn asset_hub_westend_development_config() -> AssetHubWestendChainSpec { properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::from_genesis( - // Name - "Westend Asset Hub Development", - // ID - "asset-hub-westend-dev", - ChainType::Local, - move || { - asset_hub_westend_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubWestendChainSpec::builder( + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) + .with_name("Westend Asset Hub Development") + .with_id("asset-hub-westend-dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_westend_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"), + ], + 1000.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_westend_local_config() -> AssetHubWestendChainSpec { @@ -506,49 +444,44 @@ pub fn asset_hub_westend_local_config() -> AssetHubWestendChainSpec { properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::from_genesis( - // Name - "Westend Asset Hub Local", - // ID - "asset-hub-westend-local", - ChainType::Local, - move || { - asset_hub_westend_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubWestendChainSpec::builder( + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-local".into(), para_id: 1000 }, ) + .with_name("Westend Asset Hub Local") + .with_id("asset-hub-westend-local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(asset_hub_westend_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + 1000.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_westend_config() -> AssetHubWestendChainSpec { @@ -556,84 +489,67 @@ pub fn asset_hub_westend_config() -> AssetHubWestendChainSpec { properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::from_genesis( - // Name - "Westend Asset Hub", - // ID - "asset-hub-westend", - ChainType::Live, - move || { - asset_hub_westend_genesis( - // initial collators. - vec![ - ( - hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325") - .into(), - hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325") - .unchecked_into(), - ), - ( - hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876") - .into(), - hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876") - .unchecked_into(), - ), - ( - hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f") - .into(), - hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f") - .unchecked_into(), - ), - ( - hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322") - .into(), - hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322") - .unchecked_into(), - ), - ], - Vec::new(), - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubWestendChainSpec::builder( + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) + .with_name("Westend Asset Hub") + .with_id("asset-hub-westend") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(asset_hub_westend_genesis( + // initial collators. + vec![ + ( + hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325").into(), + hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325") + .unchecked_into(), + ), + ( + hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876").into(), + hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876") + .unchecked_into(), + ), + ( + hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f").into(), + hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f") + .unchecked_into(), + ), + ( + hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322").into(), + hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322") + .unchecked_into(), + ), + ], + Vec::new(), + 1000.into(), + )) + .with_properties(properties) + .build() } fn asset_hub_westend_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, -) -> asset_hub_westend_runtime::RuntimeGenesisConfig { - 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_westend_runtime::BalancesConfig { - balances: endowed_accounts +) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, ASSET_HUB_WESTEND_ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ASSET_HUB_WESTEND_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": ASSET_HUB_WESTEND_ED * 16, }, - session: asset_hub_westend_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -642,18 +558,12 @@ fn asset_hub_westend_genesis( asset_hub_westend_session_keys(aura), // session keys ) }) - .collect(), + .collect::>(), }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - } + }) } pub fn asset_hub_rococo_development_config() -> AssetHubRococoChainSpec { @@ -688,35 +598,29 @@ fn asset_hub_rococo_like_development_config( 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), + AssetHubRococoChainSpec::builder( + asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-dev".into(), para_id }, ) + .with_name(name) + .with_id(chain_id) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(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(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_rococo_local_config() -> AssetHubRococoChainSpec { @@ -751,49 +655,43 @@ fn asset_hub_rococo_like_local_config( 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), + AssetHubRococoChainSpec::builder( + asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id }, ) + .with_name(name) + .with_id(chain_id) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(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(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_rococo_genesis_config() -> AssetHubRococoChainSpec { @@ -801,56 +699,46 @@ pub fn asset_hub_rococo_genesis_config() -> AssetHubRococoChainSpec { properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); let para_id = 1000; - AssetHubRococoChainSpec::from_genesis( - // Name - "Rococo Asset Hub", - // ID - "asset-hub-rococo", - ChainType::Live, - move || { - asset_hub_rococo_genesis( - // initial collators. - vec![ - // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG - ( - hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") - .into(), - hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") - .unchecked_into(), - ), - // G28iWEybndgGRbhfx83t7Q42YhMPByHpyqWDUgeyoGF94ri - ( - hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") - .into(), - hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") - .unchecked_into(), - ), - // G839e2eMiq7UXbConsY6DS1XDAYG2XnQxAmLuRLGGQ3Px9c - ( - hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") - .into(), - hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") - .unchecked_into(), - ), - // GLao4ukFUW6qhexuZowdFrKa2NLCfnEjZMftSXXfvGv1vvt - ( - hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") - .into(), - hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") - .unchecked_into(), - ), - ], - Vec::new(), - para_id.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubRococoChainSpec::builder( + asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo".into(), para_id }, ) + .with_name("Rococo Asset Hub") + .with_id("asset-hub-rococo") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(asset_hub_rococo_genesis( + // initial collators. + vec![ + // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG + ( + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608").into(), + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") + .unchecked_into(), + ), + // G28iWEybndgGRbhfx83t7Q42YhMPByHpyqWDUgeyoGF94ri + ( + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944").into(), + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") + .unchecked_into(), + ), + // G839e2eMiq7UXbConsY6DS1XDAYG2XnQxAmLuRLGGQ3Px9c + ( + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948").into(), + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") + .unchecked_into(), + ), + // GLao4ukFUW6qhexuZowdFrKa2NLCfnEjZMftSXXfvGv1vvt + ( + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f").into(), + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") + .unchecked_into(), + ), + ], + Vec::new(), + para_id.into(), + )) + .with_properties(properties) + .build() } pub fn asset_hub_wococo_genesis_config() -> AssetHubWococoChainSpec { @@ -859,87 +747,71 @@ pub fn asset_hub_wococo_genesis_config() -> AssetHubWococoChainSpec { properties.insert("tokenSymbol".into(), "WOC".into()); properties.insert("tokenDecimals".into(), 12.into()); let para_id = 1000; - AssetHubWococoChainSpec::from_genesis( - // Name - "Wococo Asset Hub", - // ID - "asset-hub-wococo", - ChainType::Live, - move || { - asset_hub_rococo_genesis( - // initial collators. - vec![ - // 5C8RGkS8t5K93fB2hkgKbvSYs5iG6AknJMuQmbBDeazon9Lj - ( - hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") - .into(), - hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") - .unchecked_into(), - ), - // 5GePeDZQeBagXH7kH5QPKnQKi39Z5hoYFB5FmUtEvc4yxKej - ( - hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") - .into(), - hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") - .unchecked_into(), - ), - // 5CfnTTb9NMJDNKDntA83mHKoedZ7wjDC8ypLCTDd4NwUx3zv - ( - hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") - .into(), - hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") - .unchecked_into(), - ), - // 5EqheiwiG22gvGpN7cvrbeaQzhg7rzsYYVkYK4yj5vRrTQRQ - ( - hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") - .into(), - hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") - .unchecked_into(), - ), - ], - Vec::new(), - para_id.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + AssetHubRococoChainSpec::builder( + asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "wococo".into(), para_id }, ) + .with_name("Wococo Asset Hub") + .with_id("asset-hub-wococo") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(asset_hub_rococo_genesis( + // initial collators. + vec![ + // 5C8RGkS8t5K93fB2hkgKbvSYs5iG6AknJMuQmbBDeazon9Lj + ( + hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534").into(), + hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") + .unchecked_into(), + ), + // 5GePeDZQeBagXH7kH5QPKnQKi39Z5hoYFB5FmUtEvc4yxKej + ( + hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814").into(), + hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") + .unchecked_into(), + ), + // 5CfnTTb9NMJDNKDntA83mHKoedZ7wjDC8ypLCTDd4NwUx3zv + ( + hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965").into(), + hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") + .unchecked_into(), + ), + // 5EqheiwiG22gvGpN7cvrbeaQzhg7rzsYYVkYK4yj5vRrTQRQ + ( + hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66").into(), + hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") + .unchecked_into(), + ), + ], + Vec::new(), + para_id.into(), + )) + .with_properties(properties) + .build() } 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 { +) -> serde_json::Value { + serde_json::json!({ + "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 { + "parachainInfo": asset_hub_rococo_runtime::ParachainInfoConfig { parachain_id: id, ..Default::default() }, - collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + "collatorSelection": 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 { + "session": asset_hub_rococo_runtime::SessionConfig { keys: invulnerables .into_iter() .map(|(acc, aura)| { @@ -951,12 +823,9 @@ fn asset_hub_rococo_genesis( }) .collect(), }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + "polkadotXcm": asset_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() - }, - } + } + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 2910d81ee29..71fb9e5b140 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -215,8 +215,7 @@ pub mod rococo { parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = - sc_service::GenericChainSpec; + pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub type RuntimeApi = bridge_hub_rococo_runtime::RuntimeApi; @@ -235,52 +234,47 @@ pub mod rococo { properties.insert("tokenDecimals".into(), 12.into()); modify_props(&mut properties); - BridgeHubChainSpec::from_genesis( - // Name - chain_name, - // ID - super::ensure_id(id).expect("invalid id"), - ChainType::Local, - move || { - 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, - bridges_pallet_owner_seed - .as_ref() - .map(|seed| get_account_id_from_seed::(seed)), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + BridgeHubChainSpec::builder( + bridge_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, ) + .with_name(chain_name) + .with_id(super::ensure_id(id).expect("invalid id")) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + para_id, + bridges_pallet_owner_seed + .as_ref() + .map(|seed| get_account_id_from_seed::(seed)), + )) + .with_properties(properties) + .build() } fn genesis( @@ -288,28 +282,20 @@ pub mod rococo { endowed_accounts: Vec, id: ParaId, bridges_pallet_owner: Option, - ) -> bridge_hub_rococo_runtime::RuntimeGenesisConfig { - bridge_hub_rococo_runtime::RuntimeGenesisConfig { - system: bridge_hub_rococo_runtime::SystemConfig { - code: bridge_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: bridge_hub_rococo_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + ) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: BRIDGE_HUB_ROCOCO_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": BRIDGE_HUB_ROCOCO_ED * 16, }, - session: bridge_hub_rococo_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -318,40 +304,31 @@ pub mod rococo { bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + + "bridgeWococoGrandpa": { + "owner": bridges_pallet_owner.clone(), }, - bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeWestendGrandpa": { + "owner": bridges_pallet_owner.clone(), }, - bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeRococoGrandpa": { + "owner": bridges_pallet_owner.clone(), }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeRococoMessages": { + "owner": bridges_pallet_owner.clone(), }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeWococoMessages": { + "owner": bridges_pallet_owner.clone(), }, - bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeWestendMessages": { + "owner": bridges_pallet_owner.clone(), }, - } + }) } } @@ -403,8 +380,7 @@ pub mod kusama { parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = - sc_service::GenericChainSpec; + pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub type RuntimeApi = bridge_hub_kusama_runtime::RuntimeApi; pub fn local_config( @@ -418,81 +394,68 @@ pub mod kusama { properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - BridgeHubChainSpec::from_genesis( - // Name - chain_name, - // ID - super::ensure_id(id).expect("invalid id"), - ChainType::Local, - move || { - 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, - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + BridgeHubChainSpec::builder( + bridge_hub_kusama_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, ) + .with_name(chain_name) + .with_id(super::ensure_id(id).expect("invalid id")) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + para_id, + )) + .with_properties(properties) + .build() } fn genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, - ) -> bridge_hub_kusama_runtime::RuntimeGenesisConfig { - 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: endowed_accounts + ) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, BRIDGE_HUB_KUSAMA_ED * 524_288)) - .collect(), + .collect::>(), }, - parachain_info: bridge_hub_kusama_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: bridge_hub_kusama_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: BRIDGE_HUB_KUSAMA_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": BRIDGE_HUB_KUSAMA_ED * 16, }, - session: bridge_hub_kusama_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -501,16 +464,12 @@ pub mod kusama { bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: bridge_hub_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - } + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + } + }) } } @@ -545,52 +504,47 @@ pub mod westend { properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - BridgeHubChainSpec::from_genesis( - // Name - chain_name, - // ID - super::ensure_id(id).expect("invalid id"), - ChainType::Local, - move || { - 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, - bridges_pallet_owner_seed - .as_ref() - .map(|seed| get_account_id_from_seed::(seed)), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + BridgeHubChainSpec::builder( + bridge_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, ) + .with_name(chain_name) + .with_id(super::ensure_id(id).expect("invalid id")) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + para_id, + bridges_pallet_owner_seed + .as_ref() + .map(|seed| get_account_id_from_seed::(seed)), + )) + .with_properties(properties) + .build() } fn genesis( @@ -598,28 +552,20 @@ pub mod westend { endowed_accounts: Vec, id: ParaId, bridges_pallet_owner: Option, - ) -> bridge_hub_westend_runtime::RuntimeGenesisConfig { - bridge_hub_westend_runtime::RuntimeGenesisConfig { - system: bridge_hub_westend_runtime::SystemConfig { - code: bridge_hub_westend_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: bridge_hub_westend_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + ) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - parachain_info: bridge_hub_westend_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: bridge_hub_westend_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: BRIDGE_HUB_WESTEND_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": BRIDGE_HUB_WESTEND_ED * 16, }, - session: bridge_hub_westend_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -628,24 +574,18 @@ pub mod westend { bridge_hub_westend_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), - }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + .collect::>(), }, - bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() + "bridgeRococoGrandpa": { + "owner": bridges_pallet_owner.clone(), }, - } + "bridgeRococoMessages": { + "owner": bridges_pallet_owner.clone(), + } + }) } } @@ -666,8 +606,7 @@ pub mod polkadot { parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = - sc_service::GenericChainSpec; + pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub type RuntimeApi = bridge_hub_polkadot_runtime::RuntimeApi; pub fn local_config( @@ -681,81 +620,68 @@ pub mod polkadot { properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - BridgeHubChainSpec::from_genesis( - // Name - chain_name, - // ID - super::ensure_id(id).expect("invalid id"), - ChainType::Local, - move || { - 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, - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + BridgeHubChainSpec::builder( + bridge_hub_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, ) + .with_name(chain_name) + .with_id(super::ensure_id(id).expect("invalid id")) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + para_id, + )) + .with_properties(properties) + .build() } fn genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, - ) -> bridge_hub_polkadot_runtime::RuntimeGenesisConfig { - 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: endowed_accounts + ) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, BRIDGE_HUB_POLKADOT_ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: bridge_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: bridge_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: BRIDGE_HUB_POLKADOT_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": BRIDGE_HUB_POLKADOT_ED * 16, }, - session: bridge_hub_polkadot_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -764,15 +690,11 @@ pub mod polkadot { bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: bridge_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - } + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + } + }) } } diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index fbf49b9535a..0a8064f50ca 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -22,8 +22,7 @@ use parachains_common::{AccountId, AuraId, Balance as CollectivesBalance}; use sc_service::ChainType; use sp_core::sr25519; -pub type CollectivesPolkadotChainSpec = - sc_service::GenericChainSpec; +pub type CollectivesPolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>; const COLLECTIVES_POLKADOT_ED: CollectivesBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; @@ -43,37 +42,33 @@ pub fn collectives_polkadot_development_config() -> CollectivesPolkadotChainSpec properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - CollectivesPolkadotChainSpec::from_genesis( - // Name - "Polkadot Collectives Development", - // ID - "collectives_polkadot_dev", - ChainType::Local, - move || { - collectives_polkadot_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"), - ], - // 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever - // be a collective para on Kusama. - 1002.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + CollectivesPolkadotChainSpec::builder( + collectives_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-dev".into(), para_id: 1002 }, ) + .with_name("Polkadot Collectives Development") + .with_id("collectives_polkadot_dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(collectives_polkadot_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"), + ], + // 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever + // be a collective para on Kusama. + 1002.into(), + )) + .with_boot_nodes(Vec::new()) + .with_properties(properties) + .build() } /// Collectives Polkadot Local Config. @@ -83,81 +78,69 @@ pub fn collectives_polkadot_local_config() -> CollectivesPolkadotChainSpec { properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - CollectivesPolkadotChainSpec::from_genesis( - // Name - "Polkadot Collectives Local", - // ID - "collectives_polkadot_local", - ChainType::Local, - move || { - collectives_polkadot_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"), - ], - 1002.into(), - ) - }, - Vec::new(), - None, - None, - None, - Some(properties), + CollectivesPolkadotChainSpec::builder( + collectives_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-local".into(), para_id: 1002 }, ) + .with_name("Polkadot Collectives Local") + .with_id("collectives_polkadot_local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(collectives_polkadot_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"), + ], + 1002.into(), + )) + .with_boot_nodes(Vec::new()) + .with_properties(properties) + .build() } fn collectives_polkadot_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, -) -> collectives_polkadot_runtime::RuntimeGenesisConfig { - 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: endowed_accounts +) -> serde_json::Value { + serde_json::json!( { + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, COLLECTIVES_POLKADOT_ED * 4096)) - .collect(), + .collect::>(), }, - parachain_info: collectives_polkadot_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: collectives_polkadot_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: COLLECTIVES_POLKADOT_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": COLLECTIVES_POLKADOT_ED * 16, }, - session: collectives_polkadot_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -166,18 +149,12 @@ fn collectives_polkadot_genesis( collectives_polkadot_session_keys(aura), // session keys ) }) - .collect(), + .collect::>(), }, // no need to pass anything to aura, in fact it will panic if we do. Session will take care // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: collectives_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - alliance: Default::default(), - alliance_motion: Default::default(), - } + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs index 0d5012858ed..7ca66354fbf 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs @@ -23,8 +23,7 @@ use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -pub type ContractsRococoChainSpec = - sc_service::GenericChainSpec; +pub type ContractsRococoChainSpec = sc_service::GenericChainSpec<(), Extensions>; /// No relay chain suffix because the id is the same over all relay chains. const CONTRACTS_PARACHAIN_ID: u32 = 1002; @@ -38,52 +37,46 @@ pub fn contracts_rococo_development_config() -> ContractsRococoChainSpec { properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::from_genesis( - // Name - "Contracts on Rococo Development", - // ID - "contracts-rococo-dev", - ChainType::Development, - move || { - contracts_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"), - ], - CONTRACTS_PARACHAIN_ID.into(), - ) - }, - Vec::new(), - None, - None, - None, - None, + ContractsRococoChainSpec::builder( + contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! para_id: CONTRACTS_PARACHAIN_ID, }, ) + .with_name("Contracts on Rococo Development") + .with_id("contracts-rococo-dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(contracts_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"), + ], + CONTRACTS_PARACHAIN_ID.into(), + )) + .with_boot_nodes(Vec::new()) + .build() } pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec { @@ -91,58 +84,46 @@ pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec { properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::from_genesis( - // Name - "Contracts on Rococo", - // ID - "contracts-rococo-local", - ChainType::Local, - move || { - contracts_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"), - ], - CONTRACTS_PARACHAIN_ID.into(), - ) - }, - // Bootnodes - Vec::new(), - // Telemetry - None, - // Protocol ID - None, - // Fork ID - None, - // Properties - Some(properties), - // Extensions + ContractsRococoChainSpec::builder( + contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! para_id: CONTRACTS_PARACHAIN_ID, }, ) + .with_name("Contracts on Rococo") + .with_id("contracts-rococo-local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(contracts_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"), + ], + CONTRACTS_PARACHAIN_ID.into(), + )) + .with_properties(properties) + .build() } pub fn contracts_rococo_config() -> ContractsRococoChainSpec { @@ -151,111 +132,92 @@ pub fn contracts_rococo_config() -> ContractsRococoChainSpec { properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::from_genesis( - // Name - "Contracts on Rococo", - // ID - "contracts-rococo", - ChainType::Live, - move || { - contracts_rococo_genesis( - vec![ - // 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26 - ( - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .into(), - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .unchecked_into(), - ), - // 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2 - ( - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .into(), - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .unchecked_into(), - ), - // 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM - ( - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .into(), - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .unchecked_into(), - ), - // 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF - ( - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .into(), - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .unchecked_into(), - ), - ], - // Warning: The configuration for a production chain should not contain - // any endowed accounts here, otherwise it'll be minting extra native tokens - // from the relay chain on the parachain. - vec![ - // NOTE: Remove endowed accounts if deployed on other relay chains. - // Endowed accounts - hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(), - // AccountId of an account which `ink-waterfall` uses for automated testing - hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(), - ], - CONTRACTS_PARACHAIN_ID.into(), - ) - }, - // Bootnodes - vec![ + ContractsRococoChainSpec::builder( + contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID } + ) + .with_name("Contracts on Rococo") + .with_id("contracts-rococo") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(contracts_rococo_genesis( + vec![ + // 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26 + ( + hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] + .into(), + hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] + .unchecked_into(), + ), + // 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2 + ( + hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] + .into(), + hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] + .unchecked_into(), + ), + // 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM + ( + hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] + .into(), + hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] + .unchecked_into(), + ), + // 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF + ( + hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] + .into(), + hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] + .unchecked_into(), + ), + ], + // Warning: The configuration for a production chain should not contain + // any endowed accounts here, otherwise it'll be minting extra native tokens + // from the relay chain on the parachain. + vec![ + // NOTE: Remove endowed accounts if deployed on other relay chains. + // Endowed accounts + hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(), + // AccountId of an account which `ink-waterfall` uses for automated testing + hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(), + ], + CONTRACTS_PARACHAIN_ID.into(), + )) + .with_boot_nodes(vec![ "/dns/contracts-collator-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj" - .parse() - .expect("MultiaddrWithPeerId"), + .parse() + .expect("MultiaddrWithPeerId"), "/dns/contracts-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" - .parse() - .expect("MultiaddrWithPeerId"), + .parse() + .expect("MultiaddrWithPeerId"), "/dns/contracts-collator-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk" - .parse() - .expect("MultiaddrWithPeerId"), + .parse() + .expect("MultiaddrWithPeerId"), "/dns/contracts-collator-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX" - .parse() - .expect("MultiaddrWithPeerId"), - ], - // Telemetry - None, - // Protocol ID - None, - // Fork ID - None, - // Properties - Some(properties), - // Extensions - Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID }, - ) + .parse() + .expect("MultiaddrWithPeerId"), + ]) + .with_properties(properties) + .build() } fn contracts_rococo_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, -) -> contracts_rococo_runtime::RuntimeGenesisConfig { - contracts_rococo_runtime::RuntimeGenesisConfig { - system: contracts_rococo_runtime::SystemConfig { - code: contracts_rococo_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: contracts_rococo_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), +) -> serde_json::Value { + serde_json::json!( { + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - parachain_info: contracts_rococo_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: contracts_rococo_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: CONTRACTS_ROCOCO_ED * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": CONTRACTS_ROCOCO_ED * 16, }, - session: contracts_rococo_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -264,21 +226,17 @@ fn contracts_rococo_genesis( contracts_rococo_runtime::SessionKeys { aura }, // session keys ) }) - .collect(), + .collect::>(), }, // no need to pass anything to aura, in fact it will panic if we do. Session will take care // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: contracts_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - sudo: contracts_rococo_runtime::SudoConfig { - key: Some( - hex!["2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14"].into(), - ), + "sudo": { + "key": Some(sp_runtime::AccountId32::from(hex![ + "2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14" + ])), }, - } + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 881fae39882..1a0a06404c5 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -23,103 +23,72 @@ use sp_core::sr25519; use super::get_collator_keys_from_seed; /// Specialized `ChainSpec` for the Glutton parachain runtime. -pub type GluttonChainSpec = - sc_service::GenericChainSpec; +pub type GluttonChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec { - GluttonChainSpec::from_genesis( - // Name - "Glutton Development", - // ID - "glutton_dev", - ChainType::Local, - move || glutton_genesis(para_id, vec![get_collator_keys_from_seed::("Alice")]), - Vec::new(), - None, - None, - None, - None, + GluttonChainSpec::builder( + glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-dev".into(), para_id: para_id.into() }, ) + .with_name("Glutton Development") + .with_id("glutton_dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(glutton_genesis( + para_id, + vec![get_collator_keys_from_seed::("Alice")], + )) + .build() } pub fn glutton_local_config(para_id: ParaId) -> GluttonChainSpec { - GluttonChainSpec::from_genesis( - // Name - "Glutton Local", - // ID - "glutton_local", - ChainType::Local, - move || { - glutton_genesis( - para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], - ) - }, - Vec::new(), - None, - None, - None, - None, + GluttonChainSpec::builder( + glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-local".into(), para_id: para_id.into() }, ) + .with_name("Glutton Local") + .with_id("glutton_local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(glutton_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + )) + .build() } pub fn glutton_config(para_id: ParaId) -> GluttonChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); - GluttonChainSpec::from_genesis( - // Name - format!("Glutton {}", para_id).as_str(), - // ID - format!("glutton-kusama-{}", para_id).as_str(), - ChainType::Live, - move || { - glutton_genesis( - para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], - ) - }, - Vec::new(), - None, - // Protocol ID - Some(format!("glutton-kusama-{}", para_id).as_str()), - None, - Some(properties), + GluttonChainSpec::builder( + glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama".into(), para_id: para_id.into() }, ) + .with_name(format!("Glutton {}", para_id).as_str()) + .with_id(format!("glutton-kusama-{}", para_id).as_str()) + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(glutton_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + )) + .with_protocol_id(format!("glutton-kusama-{}", para_id).as_str()) + .with_properties(properties) + .build() } -fn glutton_genesis( - parachain_id: ParaId, - collators: Vec, -) -> glutton_runtime::RuntimeGenesisConfig { - glutton_runtime::RuntimeGenesisConfig { - system: glutton_runtime::SystemConfig { - code: glutton_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - parachain_info: glutton_runtime::ParachainInfoConfig { parachain_id, ..Default::default() }, - parachain_system: Default::default(), - glutton: glutton_runtime::GluttonConfig { - compute: Default::default(), - storage: Default::default(), - trash_data_count: Default::default(), - ..Default::default() +fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { + serde_json::json!( { + "parachainInfo": { + "parachainId": parachain_id }, - aura: glutton_runtime::AuraConfig { authorities: collators }, - aura_ext: Default::default(), - sudo: glutton_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + "sudo": { + "key": Some(get_account_id_from_seed::("Alice")), }, - } + "aura": { "authorities": collators }, + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index 479d1701e37..2e35ee231df 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -22,8 +22,7 @@ use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; use sp_core::sr25519; /// Specialized `ChainSpec` for the normal parachain runtime. -pub type PenpalChainSpec = - sc_service::GenericChainSpec; +pub type PenpalChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> PenpalChainSpec { // Give your base currency a unit name and decimal places @@ -32,84 +31,69 @@ pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> PenpalChainSpec { properties.insert("tokenDecimals".into(), 12u32.into()); properties.insert("ss58Format".into(), 42u32.into()); - PenpalChainSpec::from_genesis( - // Name - "Penpal Parachain", - // ID - &format!("penpal-{}", relay_chain.replace("-local", "")), - ChainType::Development, - move || { - penpal_testnet_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - id, - ) - }, - Vec::new(), - None, - None, - None, - None, + PenpalChainSpec::builder( + penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.into(), // You MUST set this to the correct network! para_id: id.into(), }, ) + .with_name("Penpal Parachain") + .with_id(&format!("penpal-{}", relay_chain.replace("-local", ""))) + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(penpal_testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + id, + )) + .build() } fn penpal_testnet_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, id: ParaId, -) -> penpal_runtime::RuntimeGenesisConfig { - penpal_runtime::RuntimeGenesisConfig { - system: penpal_runtime::SystemConfig { - code: penpal_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: penpal_runtime::BalancesConfig { - balances: endowed_accounts +) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .cloned() .map(|k| (k, penpal_runtime::EXISTENTIAL_DEPOSIT * 4096)) - .collect(), + .collect::>(), }, - parachain_info: penpal_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "parachainInfo": { + "parachainId": id, }, - collator_selection: penpal_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: penpal_runtime::EXISTENTIAL_DEPOSIT * 16, - ..Default::default() + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": penpal_runtime::EXISTENTIAL_DEPOSIT * 16, }, - session: penpal_runtime::SessionConfig { - keys: invulnerables + "session": { + "keys": invulnerables .into_iter() .map(|(acc, aura)| { ( @@ -118,21 +102,15 @@ fn penpal_testnet_genesis( penpal_session_keys(aura), // session keys ) }) - .collect(), + .collect::>(), }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - aura: Default::default(), - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: penpal_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - sudo: penpal_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + "sudo": { + "key": Some(get_account_id_from_seed::("Alice")), }, - } + }) } /// Generate the session keys from individual elements. diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index fb66efbf9ae..c2ba4431456 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -25,73 +25,61 @@ use rococo_parachain_runtime::AuraId; use sc_chain_spec::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -pub type RococoParachainChainSpec = - sc_service::GenericChainSpec; +pub type RococoParachainChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn rococo_parachain_local_config() -> RococoParachainChainSpec { - RococoParachainChainSpec::from_genesis( - "Rococo Parachain Local", - "local_testnet", - ChainType::Local, - move || { - testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![get_from_seed::("Alice"), get_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"), - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - None, + RococoParachainChainSpec::builder( + rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id: 1000 }, ) + .with_name("Rococo Parachain Local") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(testnet_genesis( + get_account_id_from_seed::("Alice"), + vec![get_from_seed::("Alice"), get_from_seed::("Bob")], + 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"), + ], + 1000.into(), + )) + .build() } pub fn staging_rococo_parachain_local_config() -> RococoParachainChainSpec { - RococoParachainChainSpec::from_genesis( - "Staging Rococo Parachain Local", - "staging_testnet", - ChainType::Live, - move || { - testnet_genesis( - hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(), - vec![ - // $secret//one - hex!["aad9fa2249f87a210a0f93400b7f90e47b810c6d65caa0ca3f5af982904c2a33"] - .unchecked_into(), - // $secret//two - hex!["d47753f0cca9dd8da00c70e82ec4fc5501a69c49a5952a643d18802837c88212"] - .unchecked_into(), - ], - vec![ - hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into() - ], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - None, + #[allow(deprecated)] + RococoParachainChainSpec::builder( + rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id: 1000 }, ) + .with_name("Staging Rococo Parachain Local") + .with_id("staging_testnet") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(testnet_genesis( + hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(), + vec![ + // $secret//one + hex!["aad9fa2249f87a210a0f93400b7f90e47b810c6d65caa0ca3f5af982904c2a33"] + .unchecked_into(), + // $secret//two + hex!["d47753f0cca9dd8da00c70e82ec4fc5501a69c49a5952a643d18802837c88212"] + .unchecked_into(), + ], + vec![hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()], + 1000.into(), + )) + .build() } pub(crate) fn testnet_genesis( @@ -99,28 +87,18 @@ pub(crate) fn testnet_genesis( initial_authorities: Vec, endowed_accounts: Vec, id: ParaId, -) -> rococo_parachain_runtime::RuntimeGenesisConfig { - rococo_parachain_runtime::RuntimeGenesisConfig { - system: rococo_parachain_runtime::SystemConfig { - code: rococo_parachain_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: rococo_parachain_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), +) -> serde_json::Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - sudo: rococo_parachain_runtime::SudoConfig { key: Some(root_key) }, - parachain_info: rococo_parachain_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() + "sudo": { "key": Some(root_key) }, + "parachainInfo": { + "parachainId": id, }, - aura: rococo_parachain_runtime::AuraConfig { authorities: initial_authorities }, - aura_ext: Default::default(), - parachain_system: Default::default(), - polkadot_xcm: rococo_parachain_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() + "aura": { "authorities": initial_authorities }, + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - } + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs index 6a584232097..b034588e14c 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs @@ -23,49 +23,35 @@ use sp_core::sr25519; use super::get_collator_keys_from_seed; /// Specialized `ChainSpec` for the seedling parachain runtime. -pub type SeedlingChainSpec = - sc_service::GenericChainSpec; +pub type SeedlingChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn get_seedling_chain_spec() -> SeedlingChainSpec { - SeedlingChainSpec::from_genesis( - "Seedling Local Testnet", - "seedling_local_testnet", - ChainType::Local, - move || { - seedling_testnet_genesis( - get_account_id_from_seed::("Alice"), - 2000.into(), - vec![get_collator_keys_from_seed::("Alice")], - ) - }, - Vec::new(), - None, - None, - None, - None, + SeedlingChainSpec::builder( + seedling_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 2000 }, ) + .with_name("Seedling Local Testnet") + .with_id("seedling_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(seedling_testnet_genesis( + get_account_id_from_seed::("Alice"), + 2000.into(), + vec![get_collator_keys_from_seed::("Alice")], + )) + .with_boot_nodes(Vec::new()) + .build() } fn seedling_testnet_genesis( root_key: AccountId, parachain_id: ParaId, collators: Vec, -) -> seedling_runtime::RuntimeGenesisConfig { - seedling_runtime::RuntimeGenesisConfig { - system: seedling_runtime::SystemConfig { - code: seedling_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - sudo: seedling_runtime::SudoConfig { key: Some(root_key) }, - parachain_info: seedling_runtime::ParachainInfoConfig { - parachain_id, - ..Default::default() +) -> serde_json::Value { + serde_json::json!({ + "sudo": { "key": Some(root_key) }, + "parachainInfo": { + "parachainId": parachain_id, }, - parachain_system: Default::default(), - aura: seedling_runtime::AuraConfig { authorities: collators }, - aura_ext: Default::default(), - } + "aura": { "authorities": collators }, + }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/shell.rs b/cumulus/polkadot-parachain/src/chain_spec/shell.rs index 0899c1af3b4..02c65e809a6 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/shell.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/shell.rs @@ -22,40 +22,27 @@ use sc_service::ChainType; use super::get_collator_keys_from_seed; /// Specialized `ChainSpec` for the shell parachain runtime. -pub type ShellChainSpec = - sc_service::GenericChainSpec; +pub type ShellChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn get_shell_chain_spec() -> ShellChainSpec { - ShellChainSpec::from_genesis( - "Shell Local Testnet", - "shell_local_testnet", - ChainType::Local, - move || { - shell_testnet_genesis(1000.into(), vec![get_collator_keys_from_seed::("Alice")]) - }, - Vec::new(), - None, - None, - None, - None, + ShellChainSpec::builder( + shell_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) + .with_name("Shell Local Testnet") + .with_id("shell_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(shell_testnet_genesis( + 1000.into(), + vec![get_collator_keys_from_seed::("Alice")], + )) + .with_boot_nodes(Vec::new()) + .build() } -fn shell_testnet_genesis( - parachain_id: ParaId, - collators: Vec, -) -> shell_runtime::RuntimeGenesisConfig { - shell_runtime::RuntimeGenesisConfig { - system: shell_runtime::SystemConfig { - code: shell_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - parachain_info: shell_runtime::ParachainInfoConfig { parachain_id, ..Default::default() }, - parachain_system: Default::default(), - aura: shell_runtime::AuraConfig { authorities: collators }, - aura_ext: Default::default(), - } +fn shell_testnet_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { + serde_json::json!({ + "parachainInfo": { "parachainId": parachain_id}, + "aura": { "authorities": collators }, + }) } diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 9787465fb0a..3f93c90558a 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -1200,35 +1200,30 @@ mod tests { cfg_file_path } - pub type DummyChainSpec = - sc_service::GenericChainSpec; + pub type DummyChainSpec = sc_service::GenericChainSpec<(), E>; pub fn create_default_with_extensions( id: &str, extension: E, ) -> DummyChainSpec { - DummyChainSpec::from_genesis( - "Dummy local testnet", - id, - ChainType::Local, - move || { - crate::chain_spec::rococo_parachain::testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - ], - vec![get_account_id_from_seed::("Alice")], - 1000.into(), - ) - }, - Vec::new(), - None, - None, - None, - None, + DummyChainSpec::builder( + rococo_parachain_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), extension, ) + .with_name("Dummy local testnet") + .with_id(id) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(crate::chain_spec::rococo_parachain::testnet_genesis( + get_account_id_from_seed::("Alice"), + vec![ + get_from_seed::("Alice"), + get_from_seed::("Bob"), + ], + vec![get_account_id_from_seed::("Alice")], + 1000.into(), + )) + .build() } #[test] diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index 635455d5033..a3c79158f49 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -19,13 +19,13 @@ mod block_builder; use codec::{Decode, Encode}; use runtime::{ - Balance, Block, BlockHashCount, Runtime, RuntimeCall, RuntimeGenesisConfig, Signature, - SignedExtra, SignedPayload, UncheckedExtrinsic, VERSION, + Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, + UncheckedExtrinsic, VERSION, }; use sc_executor::HeapAllocStrategy; use sc_executor_common::runtime_blob::RuntimeBlob; use sp_blockchain::HeaderBackend; -use sp_core::{sr25519, Pair}; +use sp_core::Pair; use sp_io::TestExternalities; use sp_runtime::{generic::Era, BuildStorage, SaturatedConversion}; @@ -84,17 +84,12 @@ pub struct GenesisParameters { impl substrate_test_client::GenesisInit for GenesisParameters { fn genesis_storage(&self) -> Storage { - if self.endowed_accounts.is_empty() { - genesis_config().build_storage().unwrap() - } else { - cumulus_test_service::testnet_genesis( - cumulus_test_service::get_account_id_from_seed::("Alice"), - self.endowed_accounts.clone(), - None, - ) - .build_storage() - .unwrap() - } + cumulus_test_service::chain_spec::get_chain_spec_with_extra_endowed( + None, + self.endowed_accounts.clone(), + ) + .build_storage() + .expect("Builds test runtime genesis storage") } } @@ -127,10 +122,6 @@ impl DefaultTestClientBuilderExt for TestClientBuilder { } } -fn genesis_config() -> RuntimeGenesisConfig { - cumulus_test_service::testnet_genesis_with_default_endowed(Default::default(), None) -} - /// Create an unsigned extrinsic from a runtime call. pub fn generate_unsigned(function: impl Into) -> UncheckedExtrinsic { UncheckedExtrinsic::new_unsigned(function.into()) diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index e1e723449ea..3ea51c1973f 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -23,6 +23,7 @@ pallet-transaction-payment = { path = "../../../substrate/frame/transaction-paym sp-api = { path = "../../../substrate/primitives/api", default-features = false} sp-block-builder = { path = "../../../substrate/primitives/block-builder", 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} @@ -59,6 +60,7 @@ std = [ "sp-api/std", "sp-block-builder/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 381cc64cef8..19fd6d5f02d 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -47,6 +47,7 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstU8, Randomness}, weights::{ @@ -473,6 +474,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/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 14e45a4c7e6..5d73ba83d52 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -17,6 +17,7 @@ criterion = { version = "0.5.1", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } +serde_json = "1.0.107" tokio = { version = "1.32.0", features = ["macros"] } tracing = "0.1.37" url = "2.4.0" diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index c7dac7082fe..61bbf755d89 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -63,25 +63,25 @@ where /// The given accounts are initialized with funds in addition /// to the default known accounts. pub fn get_chain_spec_with_extra_endowed( - id: ParaId, + id: Option, extra_endowed_accounts: Vec, ) -> ChainSpec { - ChainSpec::from_genesis( - "Local Testnet", - "local_testnet", - ChainType::Local, - move || testnet_genesis_with_default_endowed(extra_endowed_accounts.clone(), Some(id)), - Vec::new(), - None, - None, - None, - None, - Extensions { para_id: id.into() }, + ChainSpec::builder( + cumulus_test_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + Extensions { para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into() }, ) + .with_name("Local Testnet") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(testnet_genesis_with_default_endowed( + extra_endowed_accounts.clone(), + id, + )) + .build() } /// Get the chain spec for a specific parachain ID. -pub fn get_chain_spec(id: ParaId) -> ChainSpec { +pub fn get_chain_spec(id: Option) -> ChainSpec { get_chain_spec_with_extra_endowed(id, Default::default()) } @@ -89,7 +89,7 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec { pub fn testnet_genesis_with_default_endowed( mut extra_endowed_accounts: Vec, self_para_id: Option, -) -> cumulus_test_runtime::RuntimeGenesisConfig { +) -> serde_json::Value { let mut endowed = vec![ get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), @@ -114,21 +114,12 @@ pub fn testnet_genesis( root_key: AccountId, endowed_accounts: Vec, self_para_id: Option, -) -> cumulus_test_runtime::RuntimeGenesisConfig { - cumulus_test_runtime::RuntimeGenesisConfig { - system: cumulus_test_runtime::SystemConfig { - code: cumulus_test_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - glutton: Default::default(), - parachain_system: Default::default(), - balances: cumulus_test_runtime::BalancesConfig { +) -> serde_json::Value { + serde_json::json!({ + "balances": cumulus_test_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, - sudo: cumulus_test_runtime::SudoConfig { key: Some(root_key) }, - transaction_payment: Default::default(), - test_pallet: cumulus_test_runtime::TestPalletConfig { self_para_id, ..Default::default() }, - } + "sudo": cumulus_test_runtime::SudoConfig { key: Some(root_key) }, + "testPallet": cumulus_test_runtime::TestPalletConfig { self_para_id, ..Default::default() } + }) } diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 9235a0c45c5..ef1159a3c1f 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -287,8 +287,9 @@ impl SubstrateCli for TestCollatorCli { fn load_spec(&self, id: &str) -> std::result::Result, String> { Ok(match id { - "" => Box::new(cumulus_test_service::get_chain_spec(ParaId::from(self.parachain_id))) - as Box<_>, + "" => Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from( + self.parachain_id, + )))) as Box<_>, path => { let chain_spec = cumulus_test_service::chain_spec::ChainSpec::from_json_file(path.into())?; diff --git a/cumulus/test/service/src/genesis.rs b/cumulus/test/service/src/genesis.rs index 9dba57ba9fb..d4a9a225626 100644 --- a/cumulus/test/service/src/genesis.rs +++ b/cumulus/test/service/src/genesis.rs @@ -23,7 +23,7 @@ use sp_runtime::traits::Block as BlockT; /// Returns the initial head data for a parachain ID. pub fn initial_head_data(para_id: ParaId) -> HeadData { - let spec = crate::chain_spec::get_chain_spec(para_id); + let spec = crate::chain_spec::get_chain_spec(Some(para_id)); let block: Block = generate_genesis_block(&spec, sp_runtime::StateVersion::V1).unwrap(); let genesis_state = block.header().encode(); genesis_state.into() diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index a721645546a..6fd3e4d43d7 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -719,7 +719,7 @@ pub fn node_config( let role = if is_collator { Role::Authority } else { Role::Full }; let key_seed = key.to_seed(); let mut spec = - Box::new(chain_spec::get_chain_spec_with_extra_endowed(para_id, endowed_accounts)); + Box::new(chain_spec::get_chain_spec_with_extra_endowed(Some(para_id), endowed_accounts)); let mut storage = spec.as_storage_builder().build_storage().expect("could not build storage"); diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index 5946e9cc350..16b68796bd3 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -73,7 +73,7 @@ fn main() -> Result<(), sc_cli::Error> { let runner = cli.create_runner(cmd)?; runner.sync_run(|_config| { let parachain_id = ParaId::from(cmd.parachain_id); - let spec = cumulus_test_service::get_chain_spec(parachain_id); + let spec = cumulus_test_service::get_chain_spec(Some(parachain_id)); cmd.base.run(&spec) }) }, diff --git a/cumulus/zombienet/tests/0002-pov_recovery.toml b/cumulus/zombienet/tests/0002-pov_recovery.toml index a7c1fbfd441..34cacbc2a9b 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.toml +++ b/cumulus/zombienet/tests/0002-pov_recovery.toml @@ -4,7 +4,7 @@ default_command = "polkadot" chain = "rococo-local" -[relaychain.genesis.runtime.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config] # set parameters such that collators only connect to 1 validator as a backing group max_validators_per_core = 1 group_rotation_frequency = 100 # 10 mins diff --git a/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml b/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml index a500b51f794..180ed8bf7b9 100644 --- a/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml +++ b/cumulus/zombienet/tests/0005-migrate_solo_to_para.toml @@ -32,7 +32,7 @@ cumulus_based = true add_to_genesis = false register_para = false # Set some random value in the genesis state to create a different genesis hash. -[parachains.genesis.runtime.sudo] +[parachains.genesis.runtimeGenesis.patch.sudo] key = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty" # run the parachain that will be used to return the header of the solo chain. diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index ce25c08b877..04e142230b4 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -75,7 +75,7 @@ pub type GenericChainSpec = service::GenericChainSpec<(), Extensions>; /// The `ChainSpec` parameterized for the westend runtime. #[cfg(feature = "westend-native")] -pub type WestendChainSpec = service::GenericChainSpec; +pub type WestendChainSpec = service::GenericChainSpec<(), Extensions>; /// The `ChainSpec` parameterized for the westend runtime. // Dummy chain spec, but that is fine when we don't have the native runtime. @@ -84,12 +84,7 @@ pub type WestendChainSpec = GenericChainSpec; /// The `ChainSpec` parameterized for the rococo runtime. #[cfg(feature = "rococo-native")] -pub type RococoChainSpec = service::GenericChainSpec; - -/// The `ChainSpec` parameterized for the `versi` runtime. -/// -/// As of now `Versi` will just be a clone of `Rococo`, until we need it to differ. -pub type VersiChainSpec = RococoChainSpec; +pub type RococoChainSpec = service::GenericChainSpec<(), Extensions>; /// The `ChainSpec` parameterized for the rococo runtime. // Dummy chain spec, but that is fine when we don't have the native runtime. @@ -206,7 +201,7 @@ fn rococo_session_keys( } #[cfg(feature = "westend-native")] -fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { +fn westend_staging_testnet_config_genesis() -> serde_json::Value { use hex_literal::hex; use sp_core::crypto::UncheckedInto; @@ -344,19 +339,16 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim const ENDOWMENT: u128 = 1_000_000 * WND; const STASH: u128 = 100 * WND; - westend::RuntimeGenesisConfig { - system: westend::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - balances: westend::BalancesConfig { - balances: endowed_accounts + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .map(|k: &AccountId| (k.clone(), ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) - .collect(), + .collect::>(), }, - beefy: Default::default(), - indices: westend::IndicesConfig { indices: vec![] }, - session: westend::SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -375,51 +367,32 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim }) .collect::>(), }, - staking: westend::StakingConfig { - validator_count: 50, - minimum_validator_count: 4, - stakers: initial_authorities + "staking": { + "validatorCount": 50, + "minimumValidatorCount": 4, + "stakers": initial_authorities .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::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: westend::BabeConfig { - authorities: Default::default(), - epoch_config: Some(westend::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::::Validator)) + .collect::>(), + "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + "forceEra": Forcing::ForceNone, + "slashRewardFraction": Perbill::from_percent(10), }, - grandpa: Default::default(), - im_online: Default::default(), - authority_discovery: westend::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() + "babe": { + "epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG), }, - 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(), + "sudo": { "key": Some(endowed_accounts[0].clone()) }, + "configuration": { + "config": default_parachains_host_configuration(), }, - paras: Default::default(), - registrar: westend_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() + "registrar": { + "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, }, - xcm_pallet: Default::default(), - nomination_pools: Default::default(), - assigned_slots: Default::default(), - } + }) } #[cfg(feature = "rococo-native")] -fn rococo_staging_testnet_config_genesis( - wasm_binary: &[u8], -) -> rococo_runtime::RuntimeGenesisConfig { +fn rococo_staging_testnet_config_genesis() -> serde_json::Value { use hex_literal::hex; use sp_core::crypto::UncheckedInto; @@ -662,19 +635,16 @@ fn rococo_staging_testnet_config_genesis( const ENDOWMENT: u128 = 1_000_000 * ROC; const STASH: u128 = 100 * ROC; - rococo_runtime::RuntimeGenesisConfig { - system: rococo_runtime::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - balances: rococo_runtime::BalancesConfig { - balances: endowed_accounts + serde_json::json!({ + "balances": { + "balances": endowed_accounts .iter() .map(|k: &AccountId| (k.clone(), ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) - .collect(), + .collect::>(), }, - beefy: Default::default(), - indices: rococo_runtime::IndicesConfig { indices: vec![] }, - session: rococo_runtime::SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -693,80 +663,55 @@ fn rococo_staging_testnet_config_genesis( }) .collect::>(), }, - babe: rococo_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + "babe": { + "epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), }, - grandpa: Default::default(), - im_online: Default::default(), - treasury: Default::default(), - authority_discovery: rococo_runtime::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() + "sudo": { "key": Some(endowed_accounts[0].clone()) }, + "configuration": { + "config": default_parachains_host_configuration(), }, - claims: rococo::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: rococo::VestingConfig { vesting: vec![] }, - sudo: rococo_runtime::SudoConfig { key: Some(endowed_accounts[0].clone()) }, - paras: rococo_runtime::ParasConfig { paras: vec![], ..Default::default() }, - hrmp: Default::default(), - configuration: rococo_runtime::ConfigurationConfig { - config: default_parachains_host_configuration(), + "registrar": { + "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, }, - registrar: rococo_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - xcm_pallet: Default::default(), - nis_counterpart_balances: Default::default(), - assigned_slots: Default::default(), - } + }) } /// Westend staging testnet config. #[cfg(feature = "westend-native")] pub fn westend_staging_testnet_config() -> Result { - let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?; - let boot_nodes = vec![]; - - Ok(WestendChainSpec::from_genesis( - "Westend Staging Testnet", - "westend_staging_testnet", - ChainType::Live, - move || westend_staging_testnet_config_genesis(wasm_binary), - boot_nodes, - Some( - TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)]) - .expect("Westend Staging telemetry url is valid; qed"), - ), - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(WestendChainSpec::builder( + westend::WASM_BINARY.ok_or("Westend development wasm not available")?, Default::default(), - )) + ) + .with_name("Westend Staging Testnet") + .with_id("westend_staging_testnet") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(westend_staging_testnet_config_genesis()) + .with_telemetry_endpoints( + TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)]) + .expect("Westend Staging telemetry url is valid; qed"), + ) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } /// Rococo staging testnet config. #[cfg(feature = "rococo-native")] pub fn rococo_staging_testnet_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?; - let boot_nodes = vec![]; - - Ok(RococoChainSpec::from_genesis( - "Rococo Staging Testnet", - "rococo_staging_testnet", - ChainType::Live, - move || rococo_staging_testnet_config_genesis(wasm_binary), - boot_nodes, - Some( - TelemetryEndpoints::new(vec![(ROCOCO_STAGING_TELEMETRY_URL.to_string(), 0)]) - .expect("Rococo Staging telemetry url is valid; qed"), - ), - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?, Default::default(), - )) + ) + .with_name("Rococo Staging Testnet") + .with_id("rococo_staging_testnet") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(rococo_staging_testnet_config_genesis()) + .with_telemetry_endpoints( + TelemetryEndpoints::new(vec![(ROCOCO_STAGING_TELEMETRY_URL.to_string(), 0)]) + .expect("Rococo Staging telemetry url is valid; qed"), + ) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } pub fn versi_chain_spec_properties() -> serde_json::map::Map { @@ -783,24 +728,21 @@ pub fn versi_chain_spec_properties() -> serde_json::map::Map Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?; - let boot_nodes = vec![]; - - Ok(RococoChainSpec::from_genesis( - "Versi Staging Testnet", - "versi_staging_testnet", - ChainType::Live, - move || rococo_staging_testnet_config_genesis(wasm_binary), - boot_nodes, - Some( - TelemetryEndpoints::new(vec![(VERSI_STAGING_TELEMETRY_URL.to_string(), 0)]) - .expect("Versi Staging telemetry url is valid; qed"), - ), - Some("versi"), - None, - Some(versi_chain_spec_properties()), + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Versi development wasm not available")?, Default::default(), - )) + ) + .with_name("Versi Staging Testnet") + .with_id("versi_staging_testnet") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(rococo_staging_testnet_config_genesis()) + .with_telemetry_endpoints( + TelemetryEndpoints::new(vec![(VERSI_STAGING_TELEMETRY_URL.to_string(), 0)]) + .expect("Versi Staging telemetry url is valid; qed"), + ) + .with_protocol_id("versi") + .with_properties(versi_chain_spec_properties()) + .build()) } /// Helper function to generate a crypto pair from seed @@ -879,10 +821,9 @@ fn testnet_accounts() -> Vec { ] } -/// Helper function to create westend `RuntimeGenesisConfig` for testing +/// Helper function to create westend runtime `GenesisConfig` patch for testing #[cfg(feature = "westend-native")] pub fn westend_testnet_genesis( - wasm_binary: &[u8], initial_authorities: Vec<( AccountId, AccountId, @@ -896,21 +837,18 @@ pub fn westend_testnet_genesis( )>, root_key: AccountId, endowed_accounts: Option>, -) -> westend::RuntimeGenesisConfig { +) -> serde_json::Value { let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); const ENDOWMENT: u128 = 1_000_000 * WND; const STASH: u128 = 100 * WND; - westend::RuntimeGenesisConfig { - system: westend::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - indices: westend::IndicesConfig { indices: vec![] }, - balances: westend::BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, - beefy: Default::default(), - session: westend::SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -929,51 +867,33 @@ pub fn westend_testnet_genesis( }) .collect::>(), }, - staking: westend::StakingConfig { - minimum_validator_count: 1, - validator_count: initial_authorities.len() as u32, - stakers: initial_authorities + "staking": { + "minimumValidatorCount": 1, + "validatorCount": initial_authorities.len() as u32, + "stakers": initial_authorities .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::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: westend::BabeConfig { - authorities: Default::default(), - epoch_config: Some(westend::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::::Validator)) + .collect::>(), + "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + "forceEra": Forcing::NotForcing, + "slashRewardFraction": Perbill::from_percent(10), }, - grandpa: Default::default(), - im_online: Default::default(), - authority_discovery: westend::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() + "babe": { + "epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG), }, - 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(), + "sudo": { "key": Some(root_key) }, + "configuration": { + "config": default_parachains_host_configuration(), }, - paras: Default::default(), - registrar: westend_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() + "registrar": { + "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, }, - xcm_pallet: Default::default(), - nomination_pools: Default::default(), - assigned_slots: Default::default(), - } + }) } -/// Helper function to create rococo `RuntimeGenesisConfig` for testing +/// Helper function to create rococo runtime `GenesisConfig` patch for testing #[cfg(feature = "rococo-native")] pub fn rococo_testnet_genesis( - wasm_binary: &[u8], initial_authorities: Vec<( AccountId, AccountId, @@ -987,20 +907,17 @@ pub fn rococo_testnet_genesis( )>, root_key: AccountId, endowed_accounts: Option>, -) -> rococo_runtime::RuntimeGenesisConfig { +) -> serde_json::Value { let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); const ENDOWMENT: u128 = 1_000_000 * ROC; - rococo_runtime::RuntimeGenesisConfig { - system: rococo_runtime::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - beefy: Default::default(), - indices: rococo_runtime::IndicesConfig { indices: vec![] }, - balances: rococo_runtime::BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, - session: rococo_runtime::SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -1019,43 +936,25 @@ pub fn rococo_testnet_genesis( }) .collect::>(), }, - babe: rococo_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - grandpa: Default::default(), - im_online: Default::default(), - treasury: Default::default(), - claims: rococo::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: rococo::VestingConfig { vesting: vec![] }, - authority_discovery: rococo_runtime::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() + "babe": { + "epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), }, - sudo: rococo_runtime::SudoConfig { key: Some(root_key.clone()) }, - hrmp: Default::default(), - configuration: rococo_runtime::ConfigurationConfig { - config: polkadot_runtime_parachains::configuration::HostConfiguration { + "sudo": { "key": Some(root_key.clone()) }, + "configuration": { + "config": polkadot_runtime_parachains::configuration::HostConfiguration { max_validators_per_core: Some(1), ..default_parachains_host_configuration() }, }, - paras: rococo_runtime::ParasConfig { paras: vec![], ..Default::default() }, - registrar: rococo_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - xcm_pallet: Default::default(), - nis_counterpart_balances: Default::default(), - assigned_slots: Default::default(), - } + "registrar": { + "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, + } + }) } #[cfg(feature = "westend-native")] -fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { +fn westend_development_config_genesis() -> serde_json::Value { westend_testnet_genesis( - wasm_binary, vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), None, @@ -1063,9 +962,8 @@ fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGen } #[cfg(feature = "rococo-native")] -fn rococo_development_config_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig { +fn rococo_development_config_genesis() -> serde_json::Value { rococo_testnet_genesis( - wasm_binary, vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), None, @@ -1075,84 +973,67 @@ fn rococo_development_config_genesis(wasm_binary: &[u8]) -> rococo_runtime::Runt /// Westend development config (single validator Alice) #[cfg(feature = "westend-native")] pub fn westend_development_config() -> Result { - let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?; - - Ok(WestendChainSpec::from_genesis( - "Development", - "westend_dev", - ChainType::Development, - move || westend_development_config_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(WestendChainSpec::builder( + westend::WASM_BINARY.ok_or("Westend development wasm not available")?, Default::default(), - )) + ) + .with_name("Development") + .with_id("westend_dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(westend_development_config_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } /// Rococo development config (single validator Alice) #[cfg(feature = "rococo-native")] pub fn rococo_development_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Development", - "rococo_dev", - ChainType::Development, - move || rococo_development_config_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?, Default::default(), - )) + ) + .with_name("Development") + .with_id("rococo_dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(rococo_development_config_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } /// `Versi` development config (single validator Alice) #[cfg(feature = "rococo-native")] pub fn versi_development_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Development", - "versi_dev", - ChainType::Development, - move || rococo_development_config_genesis(wasm_binary), - vec![], - None, - Some("versi"), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Versi development wasm not available")?, Default::default(), - )) + ) + .with_name("Development") + .with_id("versi_dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(rococo_development_config_genesis()) + .with_protocol_id("versi") + .build()) } /// Wococo development config (single validator Alice) #[cfg(feature = "rococo-native")] pub fn wococo_development_config() -> Result { const WOCOCO_DEV_PROTOCOL_ID: &str = "woco"; - let wasm_binary = rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Development", - "wococo_dev", - ChainType::Development, - move || rococo_development_config_genesis(wasm_binary), - vec![], - None, - Some(WOCOCO_DEV_PROTOCOL_ID), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?, Default::default(), - )) + ) + .with_name("Development") + .with_id("wococo_dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(rococo_development_config_genesis()) + .with_protocol_id(WOCOCO_DEV_PROTOCOL_ID) + .build()) } #[cfg(feature = "westend-native")] -fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { +fn westend_local_testnet_genesis() -> serde_json::Value { westend_testnet_genesis( - wasm_binary, vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], get_account_id_from_seed::("Alice"), None, @@ -1162,26 +1043,21 @@ fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisC /// Westend local testnet config (multivalidator Alice + Bob) #[cfg(feature = "westend-native")] pub fn westend_local_testnet_config() -> Result { - let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?; - - Ok(WestendChainSpec::from_genesis( - "Westend Local Testnet", - "westend_local_testnet", - ChainType::Local, - move || westend_local_testnet_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(WestendChainSpec::builder( + westend::WASM_BINARY.ok_or("Westend development wasm not available")?, Default::default(), - )) + ) + .with_name("Westend Local Testnet") + .with_id("westend_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(westend_local_testnet_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } #[cfg(feature = "rococo-native")] -fn rococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig { +fn rococo_local_testnet_genesis() -> serde_json::Value { rococo_testnet_genesis( - wasm_binary, vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], get_account_id_from_seed::("Alice"), None, @@ -1191,27 +1067,22 @@ fn rococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGe /// Rococo local testnet config (multivalidator Alice + Bob) #[cfg(feature = "rococo-native")] pub fn rococo_local_testnet_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Rococo Local Testnet", - "rococo_local_testnet", - ChainType::Local, - move || rococo_local_testnet_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?, Default::default(), - )) + ) + .with_name("Rococo Local Testnet") + .with_id("rococo_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(rococo_local_testnet_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } /// Wococo is a temporary testnet that uses almost the same runtime as rococo. #[cfg(feature = "rococo-native")] -fn wococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig { +fn wococo_local_testnet_genesis() -> serde_json::Value { rococo_testnet_genesis( - wasm_binary, vec![ get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), @@ -1226,27 +1097,22 @@ fn wococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGe /// Wococo local testnet config (multivalidator Alice + Bob + Charlie + Dave) #[cfg(feature = "rococo-native")] pub fn wococo_local_testnet_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Wococo Local Testnet", - "wococo_local_testnet", - ChainType::Local, - move || wococo_local_testnet_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Rococo development wasm (used for wococo) not available")?, Default::default(), - )) + ) + .with_name("Wococo Local Testnet") + .with_id("wococo_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(wococo_local_testnet_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .build()) } /// `Versi` is a temporary testnet that uses the same runtime as rococo. #[cfg(feature = "rococo-native")] -fn versi_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig { +fn versi_local_testnet_genesis() -> serde_json::Value { rococo_testnet_genesis( - wasm_binary, vec![ get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), @@ -1261,18 +1127,14 @@ fn versi_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGen /// `Versi` local testnet config (multivalidator Alice + Bob + Charlie + Dave) #[cfg(feature = "rococo-native")] pub fn versi_local_testnet_config() -> Result { - let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?; - - Ok(RococoChainSpec::from_genesis( - "Versi Local Testnet", - "versi_local_testnet", - ChainType::Local, - move || versi_local_testnet_genesis(wasm_binary), - vec![], - None, - Some("versi"), - None, - None, + Ok(RococoChainSpec::builder( + rococo::WASM_BINARY.ok_or("Rococo development wasm (used for versi) not available")?, Default::default(), - )) + ) + .with_name("Versi Local Testnet") + .with_id("versi_local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(versi_local_testnet_genesis()) + .with_protocol_id("versi") + .build()) } diff --git a/polkadot/node/test/client/src/lib.rs b/polkadot/node/test/client/src/lib.rs index 5d97ffcdf1d..6b205c09f2f 100644 --- a/polkadot/node/test/client/src/lib.rs +++ b/polkadot/node/test/client/src/lib.rs @@ -51,7 +51,7 @@ pub struct GenesisParameters; impl substrate_test_client::GenesisInit for GenesisParameters { fn genesis_storage(&self) -> Storage { - polkadot_test_service::chain_spec::polkadot_local_testnet_genesis() + polkadot_test_service::chain_spec::polkadot_local_testnet_config() .build_storage() .expect("Builds test runtime genesis storage") } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 1924418a485..6c13e45a566 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -59,7 +59,6 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" } [dev-dependencies] pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -serde_json = "1.0.107" substrate-test-utils = { path = "../../../../substrate/test-utils" } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/node/test/service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs index bedb1250b2a..0295090b952 100644 --- a/polkadot/node/test/service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -31,8 +31,7 @@ use test_runtime_constants::currency::DOTS; const DEFAULT_PROTOCOL_ID: &str = "dot"; /// The `ChainSpec` parameterized for polkadot test runtime. -pub type PolkadotChainSpec = - sc_service::GenericChainSpec; +pub type PolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>; /// Returns the properties for the [`PolkadotChainSpec`]. pub fn polkadot_chain_spec_properties() -> serde_json::map::Map { @@ -46,22 +45,21 @@ pub fn polkadot_chain_spec_properties() -> serde_json::map::Map PolkadotChainSpec { - PolkadotChainSpec::from_genesis( - "Local Testnet", - "local_testnet", - ChainType::Local, - || polkadot_local_testnet_genesis(), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - Some(polkadot_chain_spec_properties()), + PolkadotChainSpec::builder( + polkadot_test_runtime::WASM_BINARY.expect("Wasm binary must be built for testing"), Default::default(), ) + .with_name("Local Testnet") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(polkadot_local_testnet_genesis()) + .with_protocol_id(DEFAULT_PROTOCOL_ID) + .with_properties(polkadot_chain_spec_properties()) + .build() } /// Local testnet genesis config (multivalidator Alice + Bob) -pub fn polkadot_local_testnet_genesis() -> polkadot_test_runtime::RuntimeGenesisConfig { +pub fn polkadot_local_testnet_genesis() -> serde_json::Value { polkadot_testnet_genesis( vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], get_account_id_from_seed::("Alice"), @@ -114,7 +112,7 @@ fn polkadot_testnet_genesis( )>, root_key: AccountId, endowed_accounts: Option>, -) -> polkadot_test_runtime::RuntimeGenesisConfig { +) -> serde_json::Value { use polkadot_test_runtime as runtime; let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); @@ -122,17 +120,12 @@ fn polkadot_testnet_genesis( const ENDOWMENT: u128 = 1_000_000 * DOTS; const STASH: u128 = 100 * DOTS; - runtime::RuntimeGenesisConfig { - system: runtime::SystemConfig { - code: runtime::WASM_BINARY.expect("Wasm binary must be built for testing").to_vec(), - ..Default::default() - }, - indices: runtime::IndicesConfig { indices: vec![] }, - balances: runtime::BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, - session: runtime::SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -149,33 +142,23 @@ fn polkadot_testnet_genesis( }) .collect::>(), }, - staking: runtime::StakingConfig { - minimum_validator_count: 1, - validator_count: 2, - stakers: initial_authorities + "staking": { + "minimumValidatorCount": 1, + "validatorCount": 2, + "stakers": initial_authorities .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, runtime::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: runtime::BabeConfig { - authorities: vec![], - epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + .map(|x| (x.0.clone(), x.0.clone(), STASH, runtime::StakerStatus::::Validator)) + .collect::>(), + "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + "forceEra": Forcing::NotForcing, + "slashRewardFraction": Perbill::from_percent(10), }, - grandpa: Default::default(), - authority_discovery: runtime::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() + "babe": { + "epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG), }, - claims: runtime::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: runtime::VestingConfig { vesting: vec![] }, - sudo: runtime::SudoConfig { key: Some(root_key) }, - configuration: runtime::ConfigurationConfig { - config: polkadot_runtime_parachains::configuration::HostConfiguration { + "sudo": { "key": Some(root_key) }, + "configuration": { + "config": polkadot_runtime_parachains::configuration::HostConfiguration { validation_upgrade_cooldown: 10u32, validation_upgrade_delay: 5, code_retention_period: 1200, @@ -188,8 +171,8 @@ fn polkadot_testnet_genesis( minimum_validation_upgrade_delay: 5, ..Default::default() }, - }, - } + } + }) } /// Can be called for a `Configuration` to check if it is a configuration for the `Test` network. diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 46a9f7d12cd..70722d50988 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/src/lib.rs @@ -246,7 +246,8 @@ impl sp_runtime::traits::Convert for U256ToBalance { } /// Macro to set a value (e.g. when using the `parameter_types` macro) to either a production value -/// or to an environment variable or testing value (in case the `fast-runtime` feature is selected). +/// or to an environment variable or testing value (in case the `fast-runtime` feature is selected) +/// or one of two testing values depending on feature. /// Note that the environment variable is evaluated _at compile time_. /// /// Usage: @@ -255,6 +256,8 @@ impl sp_runtime::traits::Convert for U256ToBalance { /// // Note that the env variable version parameter cannot be const. /// pub LaunchPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "KSM_LAUNCH_PERIOD"); /// pub const VotingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1 * MINUTES); +/// pub const EpochDuration: BlockNumber = +/// prod_or_fast!(1 * HOURS, "fast-runtime", 1 * MINUTES, "fast-runtime-10m", 10 * MINUTES); /// } /// ``` #[macro_export] diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index a65fda37048..d85c267496f 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -56,6 +56,7 @@ const LOG_TARGET: &str = "runtime::configuration"; serde::Serialize, serde::Deserialize, )] +#[serde(deny_unknown_fields)] pub struct HostConfiguration { // NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct // requires special treatment. diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 5b55d3fec50..135e5e94056 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -313,7 +313,7 @@ try-runtime = [ ] # Set timing constants (e.g. session period) to faster versions to speed up testing. -fast-runtime = [] +fast-runtime = [ "rococo-runtime-constants/fast-runtime" ] runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index f99dbd12336..8ff6d57ea5b 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -29,3 +29,6 @@ std = [ "sp-weights/std", "xcm/std", ] + +# Set timing constants (e.g. session period) to faster versions to speed up testing. +fast-runtime = [] diff --git a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index c63d3e02170..e70322e13e6 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.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.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 94eb6bb5bb1..5d6f299d461 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.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config] max_validators_per_core = 1 needed_approvals = 2 diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml index 25d922bb682..e2fbec079b1 100644 --- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml +++ b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml @@ -2,7 +2,7 @@ timeout = 1000 bootnode = true -[relaychain.genesis.runtime.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config] max_validators_per_core = 1 needed_approvals = 2 group_rotation_frequency = 2 diff --git a/polkadot/zombienet_tests/misc/0001-paritydb.toml b/polkadot/zombienet_tests/misc/0001-paritydb.toml index e2130963f0e..399f848d3ac 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.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config] max_validators_per_core = 1 needed_approvals = 3 diff --git a/prdoc/pr_1256.prdoc b/prdoc/pr_1256.prdoc new file mode 100644 index 00000000000..f486786fec3 --- /dev/null +++ b/prdoc/pr_1256.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "`chain-spec`: getting ready for native-runtime-free world" + +doc: + - audience: Node Dev + description: | + - [`ChainSpec::from_genesis`](https://github.com/paritytech/polkadot-sdk/blob/3df6b4d00eb310900de6f4858114baf68239412c/substrate/client/chain-spec/src/chain_spec.rs#L525) becomes deprecated in favor of [`ChainSpec::builder()`](https://github.com/paritytech/polkadot-sdk/blob/3df6b4d00eb310900de6f4858114baf68239412c/substrate/client/chain-spec/src/chain_spec.rs#L432), + - The signature of [`ChainSpec::from_genesis`] method was changed by extending it with `code` argument. + +migrations: + db: [] + + runtime: [] + +crates: [] + +host_functions: [] diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 47cde0ca70c..8fb1be5821b 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -17,6 +17,7 @@ subkey = { path = "bin/utils/subkey" } chain-spec-builder = { package = "staging-chain-spec-builder", path = "bin/utils/chain-spec-builder" } sc-service = { path = "client/service" } +sc-chain-spec = { path = "client/chain-spec" } sc-cli = { path = "client/cli" } sc-consensus-aura = { path = "client/consensus/aura" } sc-consensus-babe = { path = "client/consensus/babe" } diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 11ce98eec0d..39d39d7e312 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -21,6 +21,7 @@ clap = { version = "4.0.9", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.16.2", features = ["server"] } +serde_json = "1.0.107" sc-cli = { path = "../../../client/cli" } sc-executor = { path = "../../../client/executor" } diff --git a/substrate/bin/minimal/node/src/chain_spec.rs b/substrate/bin/minimal/node/src/chain_spec.rs index 91fa9ef4520..6b721deb6d1 100644 --- a/substrate/bin/minimal/node/src/chain_spec.rs +++ b/substrate/bin/minimal/node/src/chain_spec.rs @@ -15,12 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use runtime::{BalancesConfig, RuntimeGenesisConfig, SudoConfig, SystemConfig, WASM_BINARY}; +use runtime::{BalancesConfig, SudoConfig, WASM_BINARY}; use sc_service::{ChainType, Properties}; +use serde_json::{json, Value}; use sp_keyring::AccountKeyring; /// This is a specialization of the general Substrate ChainSpec type. -pub type ChainSpec = sc_service::GenericChainSpec; +pub type ChainSpec = sc_service::GenericChainSpec<()>; fn props() -> Properties { let mut properties = Properties::new(); @@ -30,37 +31,25 @@ fn props() -> Properties { } pub fn development_config() -> Result { - let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; - Ok(ChainSpec::from_genesis( - "Development", - "dev", - ChainType::Development, - move || testnet_genesis(wasm_binary), - vec![], - None, - None, - None, - Some(props()), - None, - )) + Ok(ChainSpec::builder(WASM_BINARY.expect("Development wasm not available"), Default::default()) + .with_name("Development") + .with_id("dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(testnet_genesis()) + .with_properties(props()) + .build()) } /// Configure initial storage state for FRAME pallets. -fn testnet_genesis(wasm_binary: &[u8]) -> RuntimeGenesisConfig { +fn testnet_genesis() -> Value { use frame::traits::Get; use runtime::interface::{Balance, MinimumBalance}; let endowment = >::get().max(1) * 1000; let balances = AccountKeyring::iter() .map(|a| (a.to_account_id(), endowment)) .collect::>(); - RuntimeGenesisConfig { - system: SystemConfig { - // Add Wasm runtime to storage. - code: wasm_binary.to_vec(), - _config: Default::default(), - }, - balances: BalancesConfig { balances }, - sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) }, - ..Default::default() - } + json!({ + "balances": BalancesConfig { balances }, + "sudo": SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) }, + }) } diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index 1f9b49da7bc..08feb445879 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -9,6 +9,7 @@ scale-info = { version = "2.6.0", default-features = false } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. frame = { path = "../../../frame", default-features = false, features = ["runtime", "experimental"] } +frame-support = { path = "../../../frame/support", default-features = false} # pallets that we want to use pallet-balances = { path = "../../../frame/balances", default-features = false } @@ -17,6 +18,9 @@ pallet-timestamp = { path = "../../../frame/timestamp", default-features = false pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } +# genesis builder that allows us to interacto with runtime genesis config +sp-genesis-builder = { path = "../../../primitives/genesis-builder", default-features = false} + [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } diff --git a/substrate/bin/minimal/runtime/src/lib.rs b/substrate/bin/minimal/runtime/src/lib.rs index 6c59592554c..efee400c3f5 100644 --- a/substrate/bin/minimal/runtime/src/lib.rs +++ b/substrate/bin/minimal/runtime/src/lib.rs @@ -31,6 +31,7 @@ use frame::{ prelude::*, }, }; +use frame_support::genesis_builder_helper::{build_config, create_default_config}; #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -210,6 +211,16 @@ impl_runtime_apis! { TransactionPayment::length_to_fee(length) } } + + 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) + } + } } /// Some re-exports that the node side code needs to know. Some are useful in this context as well. diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 23840cce222..4e87675514d 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -19,6 +19,7 @@ name = "node-template" [dependencies] clap = { version = "4.4.6", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} +serde_json = "1.0.85" sc-cli = { path = "../../../client/cli" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/bin/node-template/node/src/chain_spec.rs b/substrate/bin/node-template/node/src/chain_spec.rs index 2cd2d072930..6e0d78f647a 100644 --- a/substrate/bin/node-template/node/src/chain_spec.rs +++ b/substrate/bin/node-template/node/src/chain_spec.rs @@ -1,7 +1,4 @@ -use node_template_runtime::{ - AccountId, AuraConfig, BalancesConfig, GrandpaConfig, RuntimeGenesisConfig, Signature, - SudoConfig, SystemConfig, WASM_BINARY, -}; +use node_template_runtime::{AccountId, RuntimeGenesisConfig, Signature, WASM_BINARY}; use sc_service::ChainType; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_grandpa::AuthorityId as GrandpaId; @@ -37,122 +34,84 @@ pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { } pub fn development_config() -> Result { - let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; - - Ok(ChainSpec::from_genesis( - // Name - "Development", - // ID - "dev", - ChainType::Development, - move || { - testnet_genesis( - wasm_binary, - // Initial PoA authorities - vec![authority_keys_from_seed("Alice")], - // Sudo account - get_account_id_from_seed::("Alice"), - // Pre-funded accounts - 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"), - ], - true, - ) - }, - // Bootnodes - vec![], - // Telemetry - None, - // Protocol ID - None, - None, - // Properties - None, - // Extensions + Ok(ChainSpec::builder( + WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?, None, + ) + .with_name("Development") + .with_id("dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(testnet_genesis( + // Initial PoA authorities + vec![authority_keys_from_seed("Alice")], + // Sudo account + get_account_id_from_seed::("Alice"), + // Pre-funded accounts + 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"), + ], + true, )) + .build()) } pub fn local_testnet_config() -> Result { - let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; - - Ok(ChainSpec::from_genesis( - // Name - "Local Testnet", - // ID - "local_testnet", - ChainType::Local, - move || { - testnet_genesis( - wasm_binary, - // Initial PoA authorities - vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], - // Sudo account - get_account_id_from_seed::("Alice"), - // Pre-funded accounts - 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"), - ], - true, - ) - }, - // Bootnodes - vec![], - // Telemetry - None, - // Protocol ID - None, - // Properties - None, - None, - // Extensions + Ok(ChainSpec::builder( + WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?, None, + ) + .with_name("Local Testnet") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(testnet_genesis( + // Initial PoA authorities + vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], + // Sudo account + get_account_id_from_seed::("Alice"), + // Pre-funded accounts + 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"), + ], + true, )) + .build()) } /// Configure initial storage state for FRAME modules. fn testnet_genesis( - wasm_binary: &[u8], initial_authorities: Vec<(AuraId, GrandpaId)>, root_key: AccountId, endowed_accounts: Vec, _enable_println: bool, -) -> RuntimeGenesisConfig { - RuntimeGenesisConfig { - system: SystemConfig { - // Add Wasm runtime to storage. - code: wasm_binary.to_vec(), - ..Default::default() - }, - balances: BalancesConfig { +) -> serde_json::Value { + serde_json::json!({ + "balances": { // Configure endowed accounts with initial balance of 1 << 60. - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), }, - aura: AuraConfig { - authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), + "aura": { + "authorities": initial_authorities.iter().map(|x| (x.0.clone())).collect::>(), }, - grandpa: GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), - ..Default::default() + "grandpa": { + "authorities": initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::>(), }, - sudo: SudoConfig { + "sudo": { // Assign network admin rights. - key: Some(root_key), + "key": Some(root_key), }, - transaction_payment: Default::default(), - } + }) } diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index c6d75148423..0008c82a49d 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } pallet-aura = { path = "../../../frame/aura", default-features = false} pallet-balances = { path = "../../../frame/balances", default-features = false} @@ -28,17 +28,18 @@ pallet-transaction-payment = { path = "../../../frame/transaction-payment", defa frame-executive = { path = "../../../frame/executive", default-features = false} sp-api = { path = "../../../primitives/api", default-features = false} sp-block-builder = { path = "../../../primitives/block-builder", default-features = false} -sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false} -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false} -sp-core = { path = "../../../primitives/core", default-features = false} +sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false, features = ["serde"] } +sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } +sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"]} sp-inherents = { path = "../../../primitives/inherents", default-features = false} sp-offchain = { path = "../../../primitives/offchain", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false, features = ["serde"] } sp-session = { path = "../../../primitives/session", default-features = false} sp-std = { path = "../../../primitives/std", default-features = false} sp-storage = { path = "../../../primitives/storage", default-features = false} sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../primitives/version", default-features = false} +sp-version = { path = "../../../primitives/version", default-features = false, features = ["serde"] } +serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } # Used for the node template's RPCs @@ -75,6 +76,7 @@ std = [ "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 34cca4495da..01c532ad20d 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -124,7 +124,6 @@ futures = "0.3.21" tempfile = "3.1.0" assert_cmd = "2.0.2" nix = { version = "0.26.1", features = ["signal"] } -serde_json = "1.0" regex = "1.6.0" platforms = "3.0" soketto = "0.7.1" diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 52b480925aa..3559348d188 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -20,10 +20,7 @@ use grandpa_primitives::AuthorityId as GrandpaId; use kitchensink_runtime::{ - constants::currency::*, wasm_binary_unwrap, BabeConfig, BalancesConfig, Block, CouncilConfig, - DemocracyConfig, ElectionsConfig, ImOnlineConfig, IndicesConfig, MaxNominations, - NominationPoolsConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus, StakingConfig, - SudoConfig, SystemConfig, TechnicalCommitteeConfig, + constants::currency::*, wasm_binary_unwrap, Block, MaxNominations, SessionKeys, StakerStatus, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sc_chain_spec::ChainSpecExtension; @@ -45,6 +42,8 @@ pub use node_primitives::{AccountId, Balance, Signature}; type AccountPublic = ::Signer; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; +const ENDOWMENT: Balance = 10_000_000 * DOLLARS; +const STASH: Balance = ENDOWMENT / 1000; /// Node `ChainSpec` extensions. /// @@ -78,7 +77,11 @@ fn session_keys( SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet } } -fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { +fn configure_accounts_for_staging_testnet() -> ( + Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId)>, + AccountId, + Vec, +) { #[rustfmt::skip] // stash, controller, session-key // generated with secret: @@ -190,28 +193,27 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { ); let endowed_accounts: Vec = vec![root_key.clone()]; + (initial_authorities, root_key, endowed_accounts) +} +fn staging_testnet_config_genesis() -> serde_json::Value { + let (initial_authorities, root_key, endowed_accounts) = + configure_accounts_for_staging_testnet(); testnet_genesis(initial_authorities, vec![], root_key, Some(endowed_accounts)) } /// Staging testnet config. pub fn staging_testnet_config() -> ChainSpec { - let boot_nodes = vec![]; - ChainSpec::from_genesis( - "Staging Testnet", - "staging_testnet", - ChainType::Live, - staging_testnet_config_genesis, - boot_nodes, - Some( + ChainSpec::builder(wasm_binary_unwrap(), Default::default()) + .with_name("Staging Testnet") + .with_id("staging_testnet") + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(staging_testnet_config_genesis()) + .with_telemetry_endpoints( TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)]) .expect("Staging telemetry url is valid; qed"), - ), - None, - None, - None, - Default::default(), - ) + ) + .build() } /// Helper function to generate a crypto pair from seed. @@ -244,8 +246,7 @@ pub fn authority_keys_from_seed( ) } -/// Helper function to create RuntimeGenesisConfig for testing. -pub fn testnet_genesis( +fn configure_accounts( initial_authorities: Vec<( AccountId, AccountId, @@ -256,9 +257,14 @@ pub fn testnet_genesis( MixnetId, )>, initial_nominators: Vec, - root_key: AccountId, endowed_accounts: Option>, -) -> RuntimeGenesisConfig { + stash: Balance, +) -> ( + Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId)>, + Vec, + usize, + Vec<(AccountId, AccountId, Balance, StakerStatus)>, +) { let mut endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { vec![ get_account_id_from_seed::("Alice"), @@ -290,7 +296,7 @@ pub fn testnet_genesis( let mut rng = rand::thread_rng(); let stakers = initial_authorities .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::Validator)) + .map(|x| (x.0.clone(), x.0.clone(), stash, StakerStatus::Validator)) .chain(initial_nominators.iter().map(|x| { use rand::{seq::SliceRandom, Rng}; let limit = (MaxNominations::get() as usize).min(initial_authorities.len()); @@ -301,23 +307,39 @@ pub fn testnet_genesis( .into_iter() .map(|choice| choice.0.clone()) .collect::>(); - (x.clone(), x.clone(), STASH, StakerStatus::Nominator(nominations)) + (x.clone(), x.clone(), stash, StakerStatus::Nominator(nominations)) })) .collect::>(); let num_endowed_accounts = endowed_accounts.len(); - const ENDOWMENT: Balance = 10_000_000 * DOLLARS; - const STASH: Balance = ENDOWMENT / 1000; + (initial_authorities, endowed_accounts, num_endowed_accounts, stakers) +} + +/// Helper function to create RuntimeGenesisConfig json patch for testing. +pub fn testnet_genesis( + initial_authorities: Vec<( + AccountId, + AccountId, + GrandpaId, + BabeId, + ImOnlineId, + AuthorityDiscoveryId, + MixnetId, + )>, + initial_nominators: Vec, + root_key: AccountId, + endowed_accounts: Option>, +) -> serde_json::Value { + let (initial_authorities, endowed_accounts, num_endowed_accounts, stakers) = + configure_accounts(initial_authorities, initial_nominators, endowed_accounts, STASH); - RuntimeGenesisConfig { - system: SystemConfig { code: wasm_binary_unwrap().to_vec(), ..Default::default() }, - balances: BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(), + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect::>(), }, - indices: IndicesConfig { indices: vec![] }, - session: SessionConfig { - keys: initial_authorities + "session": { + "keys": initial_authorities .iter() .map(|x| { ( @@ -334,67 +356,45 @@ pub fn testnet_genesis( }) .collect::>(), }, - staking: StakingConfig { - validator_count: initial_authorities.len() as u32, - minimum_validator_count: initial_authorities.len() as u32, - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), - slash_reward_fraction: Perbill::from_percent(10), - stakers, - ..Default::default() + "staking": { + "validatorCount": initial_authorities.len() as u32, + "minimumValidatorCount": initial_authorities.len() as u32, + "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + "slashRewardFraction": Perbill::from_percent(10), + "stakers": stakers.clone(), }, - democracy: DemocracyConfig::default(), - elections: ElectionsConfig { - members: endowed_accounts + "elections": { + "members": endowed_accounts .iter() .take((num_endowed_accounts + 1) / 2) .cloned() .map(|member| (member, STASH)) - .collect(), + .collect::>(), }, - council: CouncilConfig::default(), - technical_committee: TechnicalCommitteeConfig { - members: endowed_accounts + "technicalCommittee": { + "members": endowed_accounts .iter() .take((num_endowed_accounts + 1) / 2) .cloned() - .collect(), - phantom: Default::default(), + .collect::>(), }, - sudo: SudoConfig { key: Some(root_key) }, - babe: BabeConfig { - epoch_config: Some(kitchensink_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() + "sudo": { "key": Some(root_key.clone()) }, + "babe": { + "epochConfig": Some(kitchensink_runtime::BABE_GENESIS_EPOCH_CONFIG), }, - im_online: ImOnlineConfig { keys: vec![] }, - authority_discovery: Default::default(), - grandpa: Default::default(), - technical_membership: Default::default(), - treasury: Default::default(), - society: SocietyConfig { pot: 0 }, - vesting: Default::default(), - assets: pallet_assets::GenesisConfig { + "society": { "pot": 0 }, + "assets": { // This asset is used by the NIS pallet as counterpart currency. - assets: vec![(9, get_account_id_from_seed::("Alice"), true, 1)], - ..Default::default() + "assets": vec![(9, get_account_id_from_seed::("Alice"), true, 1)], }, - pool_assets: Default::default(), - transaction_storage: Default::default(), - transaction_payment: Default::default(), - alliance: Default::default(), - safe_mode: Default::default(), - tx_pause: Default::default(), - alliance_motion: Default::default(), - nomination_pools: NominationPoolsConfig { - min_create_bond: 10 * DOLLARS, - min_join_bond: 1 * DOLLARS, - ..Default::default() + "nominationPools": { + "minCreateBond": 10 * DOLLARS, + "minJoinBond": 1 * DOLLARS, }, - glutton: Default::default(), - mixnet: Default::default(), - } + }) } -fn development_config_genesis() -> RuntimeGenesisConfig { +fn development_config_genesis_json() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice")], vec![], @@ -405,21 +405,15 @@ fn development_config_genesis() -> RuntimeGenesisConfig { /// Development config (single validator Alice). pub fn development_config() -> ChainSpec { - ChainSpec::from_genesis( - "Development", - "dev", - ChainType::Development, - development_config_genesis, - vec![], - None, - None, - None, - None, - Default::default(), - ) + ChainSpec::builder(wasm_binary_unwrap(), Default::default()) + .with_name("Development") + .with_id("dev") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(development_config_genesis_json()) + .build() } -fn local_testnet_genesis() -> RuntimeGenesisConfig { +fn local_testnet_genesis() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], vec![], @@ -430,18 +424,12 @@ fn local_testnet_genesis() -> RuntimeGenesisConfig { /// Local testnet config (multivalidator Alice + Bob). pub fn local_testnet_config() -> ChainSpec { - ChainSpec::from_genesis( - "Local Testnet", - "local_testnet", - ChainType::Local, - local_testnet_genesis, - vec![], - None, - None, - None, - None, - Default::default(), - ) + ChainSpec::builder(wasm_binary_unwrap(), Default::default()) + .with_name("Local Testnet") + .with_id("local_testnet") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(local_testnet_genesis()) + .build() } #[cfg(test)] @@ -451,45 +439,29 @@ pub(crate) mod tests { use sc_service_test; use sp_runtime::BuildStorage; - fn local_testnet_genesis_instant_single() -> RuntimeGenesisConfig { - testnet_genesis( - vec![authority_keys_from_seed("Alice")], - vec![], - get_account_id_from_seed::("Alice"), - None, - ) - } - /// Local testnet config (single validator - Alice). pub fn integration_test_config_with_single_authority() -> ChainSpec { - ChainSpec::from_genesis( - "Integration Test", - "test", - ChainType::Development, - local_testnet_genesis_instant_single, - vec![], - None, - None, - None, - None, - Default::default(), - ) + ChainSpec::builder(wasm_binary_unwrap(), Default::default()) + .with_name("Integration Test") + .with_id("test") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(testnet_genesis( + vec![authority_keys_from_seed("Alice")], + vec![], + get_account_id_from_seed::("Alice"), + None, + )) + .build() } /// Local testnet config (multivalidator Alice + Bob). pub fn integration_test_config_with_two_authorities() -> ChainSpec { - ChainSpec::from_genesis( - "Integration Test", - "test", - ChainType::Development, - local_testnet_genesis, - vec![], - None, - None, - None, - None, - Default::default(), - ) + ChainSpec::builder(wasm_binary_unwrap(), Default::default()) + .with_name("Integration Test") + .with_id("test") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(local_testnet_genesis()) + .build() } #[test] diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml index 5f43b5839e6..12280a9ba1d 100644 --- a/substrate/bin/node/executor/Cargo.toml +++ b/substrate/bin/node/executor/Cargo.toml @@ -14,17 +14,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive", "serde"] } frame-benchmarking = { path = "../../../frame/benchmarking" } node-primitives = { path = "../primitives" } kitchensink-runtime = { path = "../runtime" } sc-executor = { path = "../../../client/executor" } -sp-core = { path = "../../../primitives/core" } +sp-core = { path = "../../../primitives/core", features=["serde"] } sp-keystore = { path = "../../../primitives/keystore" } sp-state-machine = { path = "../../../primitives/state-machine" } sp-tracing = { path = "../../../primitives/tracing" } sp-trie = { path = "../../../primitives/trie" } -sp-statement-store = { path = "../../../primitives/statement-store" } +sp-statement-store = { path = "../../../primitives/statement-store", features=["serde"] } [dev-dependencies] criterion = "0.4.0" @@ -47,6 +47,7 @@ sp-consensus-babe = { path = "../../../primitives/consensus/babe" } sp-externalities = { path = "../../../primitives/externalities" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } +serde_json = "1.0.85" [features] stress-test = [] diff --git a/substrate/bin/node/executor/benches/bench.rs b/substrate/bin/node/executor/benches/bench.rs index 95c8afd5506..587e76af867 100644 --- a/substrate/bin/node/executor/benches/bench.rs +++ b/substrate/bin/node/executor/benches/bench.rs @@ -190,7 +190,7 @@ fn bench_execute_block(c: &mut Criterion) { for strategy in execution_methods { group.bench_function(format!("{:?}", strategy), |b| { - let genesis_config = node_testing::genesis::config(Some(compact_code_unwrap())); + let genesis_config = node_testing::genesis::config(); let use_native = match strategy { ExecutionMethod::Native => true, ExecutionMethod::Wasm(..) => false, diff --git a/substrate/bin/node/executor/tests/basic.rs b/substrate/bin/node/executor/tests/basic.rs index a2f46e9fdbe..cbceac04e8e 100644 --- a/substrate/bin/node/executor/tests/basic.rs +++ b/substrate/bin/node/executor/tests/basic.rs @@ -857,3 +857,19 @@ fn should_import_block_with_test_client() { futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); } + +#[test] +fn default_config_as_json_works() { + let mut t = new_test_ext(compact_code_unwrap()); + let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![], false) + .0 + .unwrap(); + let r = Vec::::decode(&mut &r[..]).unwrap(); + let json = String::from_utf8(r.into()).expect("returned value is json. qed."); + let expected = include_str!("res/default_genesis_config.json").to_string(); + + assert_eq!( + serde_json::from_str::(&expected).unwrap(), + serde_json::from_str::(&json).unwrap() + ); +} diff --git a/substrate/bin/node/executor/tests/common.rs b/substrate/bin/node/executor/tests/common.rs index 5f88ba85adf..2d68c88db92 100644 --- a/substrate/bin/node/executor/tests/common.rs +++ b/substrate/bin/node/executor/tests/common.rs @@ -124,7 +124,7 @@ pub fn executor_call( pub fn new_test_ext(code: &[u8]) -> TestExternalities { let ext = TestExternalities::new_with_code( code, - node_testing::genesis::config(Some(code)).build_storage().unwrap(), + node_testing::genesis::config().build_storage().unwrap(), ); ext } diff --git a/substrate/bin/node/executor/tests/res/default_genesis_config.json b/substrate/bin/node/executor/tests/res/default_genesis_config.json new file mode 100644 index 00000000000..caf12a443d3 --- /dev/null +++ b/substrate/bin/node/executor/tests/res/default_genesis_config.json @@ -0,0 +1,108 @@ +{ + "system": {}, + "babe": { + "authorities": [], + "epochConfig": null + }, + "indices": { + "indices": [] + }, + "balances": { + "balances": [] + }, + "transactionPayment": { + "multiplier": "1000000000000000000" + }, + "staking": { + "validatorCount": 0, + "minimumValidatorCount": 0, + "invulnerables": [], + "forceEra": "NotForcing", + "slashRewardFraction": 0, + "canceledPayout": 0, + "stakers": [], + "minNominatorBond": 0, + "minValidatorBond": 0, + "maxValidatorCount": null, + "maxNominatorCount": null + }, + "session": { + "keys": [] + }, + "democracy": {}, + "council": { + "members": [] + }, + "technicalCommittee": { + "members": [] + }, + "elections": { + "members": [] + }, + "technicalMembership": { + "members": [] + }, + "grandpa": { + "authorities": [] + }, + "treasury": {}, + "sudo": { + "key": null + }, + "imOnline": { + "keys": [] + }, + "authorityDiscovery": { + "keys": [] + }, + "society": { + "pot": 0 + }, + "vesting": { + "vesting": [] + }, + "glutton": { + "compute": "0", + "storage": "0", + "trashDataCount": 0 + }, + "assets": { + "assets": [], + "metadata": [], + "accounts": [] + }, + "poolAssets": { + "assets": [], + "metadata": [], + "accounts": [] + }, + "transactionStorage": { + "byteFee": 10, + "entryFee": 1000, + "storagePeriod": 100800 + }, + "allianceMotion": { + "members": [] + }, + "alliance": { + "fellows": [], + "allies": [] + }, + "mixnet": { + "mixnodes": [] + }, + "nominationPools": { + "minJoinBond": 0, + "minCreateBond": 0, + "maxPools": 16, + "maxMembersPerPool": 32, + "maxMembers": 512, + "globalMaxCommission": null + }, + "txPause": { + "paused": [] + }, + "safeMode": { + "enteredUntil": null + } +} diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index a9d685523f6..85d3971e492 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -20,33 +20,34 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } static_assertions = "1.1.0" log = { version = "0.4.17", default-features = false } +serde_json = { version = "1.0.85", default-features = false, features = ["alloc", "arbitrary_precision"] } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "num-traits"] } # primitives -sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false} -sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false} -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false} +sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false, features=["serde"] } +sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false, features=["serde"] } +sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features=["serde"] } 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-core = { path = "../../../primitives/core", default-features = false, features=["serde"] } sp-std = { path = "../../../primitives/std", default-features = false} sp-api = { path = "../../../primitives/api", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-staking = { path = "../../../primitives/staking", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false, features=["serde"] } +sp-staking = { path = "../../../primitives/staking", default-features = false, features=["serde"] } sp-storage = { path = "../../../primitives/storage", default-features = false} sp-session = { path = "../../../primitives/session", default-features = false} sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false} -sp-statement-store = { path = "../../../primitives/statement-store", default-features = false} -sp-version = { path = "../../../primitives/version", default-features = false} +sp-statement-store = { path = "../../../primitives/statement-store", default-features = false, features=["serde"] } +sp-version = { path = "../../../primitives/version", default-features = false, features=["serde"] } sp-io = { path = "../../../primitives/io", default-features = false} # frame dependencies @@ -230,6 +231,7 @@ std = [ "pallet-whitelist/std", "primitive-types/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-authority-discovery/std", "sp-block-builder/std", diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index af3701f218a..89b96c0191c 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -398,7 +398,7 @@ impl BenchDb { let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( - &keyring.generate_genesis(), + keyring.as_storage_builder(), !client_config.no_genesis, backend.clone(), executor.clone(), @@ -590,12 +590,20 @@ impl BenchKeyring { } } - /// Generate genesis with accounts from this keyring endowed with some balance. - pub fn generate_genesis(&self) -> kitchensink_runtime::RuntimeGenesisConfig { - crate::genesis::config_endowed( - Some(kitchensink_runtime::wasm_binary_unwrap()), - self.collect_account_ids(), - ) + /// Generate genesis with accounts from this keyring endowed with some balance and + /// kitchensink_runtime code blob. + pub fn as_storage_builder(&self) -> &dyn sp_runtime::BuildStorage { + self + } +} + +impl sp_runtime::BuildStorage for BenchKeyring { + fn assimilate_storage(&self, storage: &mut sp_core::storage::Storage) -> Result<(), String> { + storage.top.insert( + sp_core::storage::well_known_keys::CODE.to_vec(), + kitchensink_runtime::wasm_binary_unwrap().into(), + ); + crate::genesis::config_endowed(self.collect_account_ids()).assimilate_storage(storage) } } diff --git a/substrate/bin/node/testing/src/client.rs b/substrate/bin/node/testing/src/client.rs index c55867360bd..22276833fb6 100644 --- a/substrate/bin/node/testing/src/client.rs +++ b/substrate/bin/node/testing/src/client.rs @@ -42,7 +42,12 @@ pub struct GenesisParameters; impl substrate_test_client::GenesisInit for GenesisParameters { fn genesis_storage(&self) -> Storage { - crate::genesis::config(None).build_storage().unwrap() + let mut storage = crate::genesis::config().build_storage().unwrap(); + storage.top.insert( + sp_core::storage::well_known_keys::CODE.to_vec(), + kitchensink_runtime::wasm_binary_unwrap().into(), + ); + storage } } diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index ab5311751a5..eecbf64775b 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -20,22 +20,21 @@ use crate::keyring::*; use kitchensink_runtime::{ - constants::currency::*, wasm_binary_unwrap, AccountId, AssetsConfig, BabeConfig, - BalancesConfig, GluttonConfig, GrandpaConfig, IndicesConfig, RuntimeGenesisConfig, - SessionConfig, SocietyConfig, StakerStatus, StakingConfig, SystemConfig, - BABE_GENESIS_EPOCH_CONFIG, + constants::currency::*, AccountId, AssetsConfig, BabeConfig, BalancesConfig, GluttonConfig, + GrandpaConfig, IndicesConfig, RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus, + StakingConfig, BABE_GENESIS_EPOCH_CONFIG, }; use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; use sp_runtime::Perbill; /// Create genesis runtime configuration for tests. -pub fn config(code: Option<&[u8]>) -> RuntimeGenesisConfig { - config_endowed(code, Default::default()) +pub fn config() -> RuntimeGenesisConfig { + config_endowed(Default::default()) } /// Create genesis runtime configuration for tests with some extra /// endowed accounts. -pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> RuntimeGenesisConfig { +pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { let mut endowed = vec![ (alice(), 111 * DOLLARS), (bob(), 100 * DOLLARS), @@ -48,10 +47,7 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Run endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS))); RuntimeGenesisConfig { - system: SystemConfig { - code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()), - ..Default::default() - }, + system: Default::default(), indices: IndicesConfig { indices: vec![] }, balances: BalancesConfig { balances: endowed }, session: SessionConfig { diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index f25358e52c2..5c7e21abeab 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -23,8 +23,12 @@ crate-type = ["rlib"] ansi_term = "0.12.1" clap = { version = "4.4.6", features = ["derive"] } rand = "0.8" +kitchensink-runtime = { version = "3.0.0-dev", path = "../../node/runtime" } +log = "0.4.17" node-cli = { package = "staging-node-cli", path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } sc-keystore = { path = "../../../client/keystore" } +serde_json = "1.0.100" sp-core = { path = "../../../primitives/core" } sp-keystore = { path = "../../../primitives/keystore" } +sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" } diff --git a/substrate/bin/utils/chain-spec-builder/bin/main.rs b/substrate/bin/utils/chain-spec-builder/bin/main.rs index a002f6dc0e7..83892afd6ac 100644 --- a/substrate/bin/utils/chain-spec-builder/bin/main.rs +++ b/substrate/bin/utils/chain-spec-builder/bin/main.rs @@ -17,28 +17,40 @@ // along with this program. If not, see . use chain_spec_builder::{ - generate_authority_keys_and_store, generate_chain_spec, print_seeds, ChainSpecBuilder, + generate_authority_keys_and_store, generate_chain_spec, generate_chain_spec_for_runtime, + print_seeds, ChainSpecBuilder, ChainSpecBuilderCmd, EditCmd, GenerateCmd, NewCmd, VerifyCmd, }; use clap::Parser; use node_cli::chain_spec; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; +use sc_chain_spec::{update_code_in_json_chain_spec, GenericChainSpec}; use sp_core::{crypto::Ss58Codec, sr25519}; use staging_chain_spec_builder as chain_spec_builder; use std::fs; fn main() -> Result<(), String> { + sp_tracing::try_init_simple(); + + let builder = ChainSpecBuilder::parse(); #[cfg(build_type = "debug")] - println!( - "The chain spec builder builds a chain specification that includes a Substrate runtime \ + if matches!(builder.command, ChainSpecBuilderCmd::Generate(_) | ChainSpecBuilderCmd::New(_)) { + println!( + "The chain spec builder builds a chain specification that includes a Substrate runtime \ compiled as WASM. To ensure proper functioning of the included runtime compile (or run) \ the chain spec builder binary in `--release` mode.\n", - ); - - let builder = ChainSpecBuilder::parse(); - let chain_spec_path = builder.chain_spec_path().to_path_buf(); - - let (authority_seeds, nominator_accounts, endowed_accounts, sudo_account) = match builder { - ChainSpecBuilder::Generate { authorities, nominators, endowed, keystore_path, .. } => { + ); + } + + let chain_spec_path = builder.chain_spec_path.to_path_buf(); + let mut write_chain_spec = true; + + let chain_spec_json = match builder.command { + ChainSpecBuilderCmd::Generate(GenerateCmd { + authorities, + nominators, + endowed, + keystore_path, + }) => { let authorities = authorities.max(1); let rand_str = || -> String { OsRng.sample_iter(&Alphanumeric).take(32).map(char::from).collect() @@ -72,19 +84,58 @@ fn main() -> Result<(), String> { let sudo_account = chain_spec::get_account_id_from_seed::(&sudo_seed).to_ss58check(); - (authority_seeds, nominator_accounts, endowed_accounts, sudo_account) + generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account) }, - ChainSpecBuilder::New { + ChainSpecBuilderCmd::New(NewCmd { authority_seeds, nominator_accounts, endowed_accounts, sudo_account, - .. - } => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account), - }; + }) => + generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account), + ChainSpecBuilderCmd::Runtime(cmd) => generate_chain_spec_for_runtime(&cmd), + ChainSpecBuilderCmd::Edit(EditCmd { + ref input_chain_spec, + ref runtime_wasm_path, + convert_to_raw, + }) => { + let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + + let mut chain_spec_json = + serde_json::from_str::(&chain_spec.as_json(convert_to_raw)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + if let Some(path) = runtime_wasm_path { + update_code_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(path.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + ); + } - let json = - generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)?; + serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}")) + }, + ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec, ref runtime_wasm_path }) => { + write_chain_spec = false; + let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + let mut chain_spec_json = + serde_json::from_str::(&chain_spec.as_json(true)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + if let Some(path) = runtime_wasm_path { + update_code_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(path.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + ); + }; + serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}")) + }, + }?; - fs::write(chain_spec_path, json).map_err(|err| err.to_string()) + if write_chain_spec { + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string()) + } else { + Ok(()) + } } diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 2b88e40ef74..50a8dd08996 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -29,96 +29,169 @@ //! [`sc-chain-spec`]: ../sc_chain_spec/index.html //! [`node-cli`]: ../node_cli/index.html -use std::path::{Path, PathBuf}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use ansi_term::Style; -use clap::Parser; +use clap::{Parser, Subcommand}; +use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; use node_cli::chain_spec::{self, AccountId}; use sc_keystore::LocalKeystore; +use serde_json::Value; use sp_core::crypto::{ByteArray, Ss58Codec}; use sp_keystore::KeystorePtr; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. -#[derive(Parser)] +#[derive(Debug, Parser)] #[command(rename_all = "kebab-case")] -pub enum ChainSpecBuilder { - /// Create a new chain spec with the given authorities, endowed and sudo - /// accounts. - New { - /// Authority key seed. - #[arg(long, short, required = true)] - authority_seeds: Vec, - /// Active nominators (SS58 format), each backing a random subset of the aforementioned - /// authorities. - #[arg(long, short, default_value = "0")] - nominator_accounts: Vec, - /// Endowed account address (SS58 format). - #[arg(long, short)] - endowed_accounts: Vec, - /// Sudo account address (SS58 format). - #[arg(long, short)] - sudo_account: String, - /// The path where the chain spec should be saved. - #[arg(long, short, default_value = "./chain_spec.json")] - chain_spec_path: PathBuf, - }, - /// Create a new chain spec with the given number of authorities and endowed - /// accounts. Random keys will be generated as required. - Generate { - /// The number of authorities. - #[arg(long, short)] - authorities: usize, - /// The number of nominators backing the aforementioned authorities. - /// - /// Will nominate a random subset of `authorities`. - #[arg(long, short, default_value_t = 0)] - nominators: usize, - /// The number of endowed accounts. - #[arg(long, short, default_value_t = 0)] - endowed: usize, - /// The path where the chain spec should be saved. - #[arg(long, short, default_value = "./chain_spec.json")] - chain_spec_path: PathBuf, - /// Path to use when saving generated keystores for each authority. - /// - /// At this path, a new folder will be created for each authority's - /// keystore named `auth-$i` where `i` is the authority index, i.e. - /// `auth-0`, `auth-1`, etc. - #[arg(long, short)] - keystore_path: Option, - }, +pub struct ChainSpecBuilder { + #[command(subcommand)] + pub command: ChainSpecBuilderCmd, + /// The path where the chain spec should be saved. + #[arg(long, short, default_value = "./chain_spec.json")] + pub chain_spec_path: PathBuf, } -impl ChainSpecBuilder { - /// Returns the path where the chain spec should be saved. - pub fn chain_spec_path(&self) -> &Path { - match self { - ChainSpecBuilder::New { chain_spec_path, .. } => chain_spec_path.as_path(), - ChainSpecBuilder::Generate { chain_spec_path, .. } => chain_spec_path.as_path(), - } - } +#[derive(Debug, Subcommand)] +#[command(rename_all = "kebab-case")] +pub enum ChainSpecBuilderCmd { + New(NewCmd), + Generate(GenerateCmd), + Runtime(RuntimeCmd), + Edit(EditCmd), + Verify(VerifyCmd), } -fn genesis_constructor( - authority_seeds: &[String], - nominator_accounts: &[AccountId], - endowed_accounts: &[AccountId], - sudo_account: &AccountId, -) -> chain_spec::RuntimeGenesisConfig { - let authorities = authority_seeds - .iter() - .map(AsRef::as_ref) - .map(chain_spec::authority_keys_from_seed) - .collect::>(); +/// Create a new chain spec with the given authorities, endowed and sudo +/// accounts. Only works for kitchen-sink runtime +#[derive(Parser, Debug)] +#[command(rename_all = "kebab-case")] +pub struct NewCmd { + /// Authority key seed. + #[arg(long, short, required = true)] + pub authority_seeds: Vec, + /// Active nominators (SS58 format), each backing a random subset of the aforementioned + /// authorities. + #[arg(long, short, default_value = "0")] + pub nominator_accounts: Vec, + /// Endowed account address (SS58 format). + #[arg(long, short)] + pub endowed_accounts: Vec, + /// Sudo account address (SS58 format). + #[arg(long, short)] + pub sudo_account: String, +} + +/// Create a new chain spec with the given number of authorities and endowed +/// accounts. Random keys will be generated as required. +#[derive(Parser, Debug)] +pub struct GenerateCmd { + /// The number of authorities. + #[arg(long, short)] + pub authorities: usize, + /// The number of nominators backing the aforementioned authorities. + /// + /// Will nominate a random subset of `authorities`. + #[arg(long, short, default_value_t = 0)] + pub nominators: usize, + /// The number of endowed accounts. + #[arg(long, short, default_value_t = 0)] + pub endowed: usize, + /// Path to use when saving generated keystores for each authority. + /// + /// At this path, a new folder will be created for each authority's + /// keystore named `auth-$i` where `i` is the authority index, i.e. + /// `auth-0`, `auth-1`, etc. + #[arg(long, short)] + pub keystore_path: Option, +} + +/// Create a new chain spec by interacting with the provided runtime wasm blob. +#[derive(Parser, Debug)] +pub struct RuntimeCmd { + /// The name of chain + #[arg(long, short = 'n', default_value = "Custom")] + chain_name: String, + /// The chain id + #[arg(long, short = 'i', default_value = "custom")] + chain_id: String, + /// The path to runtime wasm blob + #[arg(long, short)] + runtime_wasm_path: PathBuf, + /// Export chainspec as raw storage + #[arg(long, short = 's')] + raw_storage: bool, + /// Verify the genesis config. This silently generates the raw storage from genesis config. Any + /// errors will be reported. + #[arg(long, short = 'v')] + verify: bool, + #[command(subcommand)] + action: GenesisBuildAction, +} + +#[derive(Subcommand, Debug, Clone)] +enum GenesisBuildAction { + Patch(PatchCmd), + Full(FullCmd), + Default(DefaultCmd), +} + +/// Patches the runtime's default genesis config with provided patch. +#[derive(Parser, Debug, Clone)] +struct PatchCmd { + /// The path to the runtime genesis config patch. + #[arg(long, short)] + patch_path: PathBuf, +} + +/// Build the genesis config for runtime using provided json file. No defaults will be used. +#[derive(Parser, Debug, Clone)] +struct FullCmd { + /// The path to the full runtime genesis config json file. + #[arg(long, short)] + config_path: PathBuf, +} - chain_spec::testnet_genesis( - authorities, - nominator_accounts.to_vec(), - sudo_account.clone(), - Some(endowed_accounts.to_vec()), - ) +/// Gets the default genesis config for the runtime and uses it in ChainSpec. Please note that +/// default genesis config may not be valid. For some runtimes initial values should be added there +/// (e.g. session keys, babe epoch). +#[derive(Parser, Debug, Clone)] +struct DefaultCmd { + /// If provided stores the default genesis config json file at given path (in addition to + /// chain-spec). + #[arg(long, short)] + default_config_path: Option, +} + +/// Edits provided input chain spec. Input can be converted into raw storage chain-spec. The code +/// can be updated with the runtime provided in the command line. +#[derive(Parser, Debug, Clone)] +pub struct EditCmd { + /// Chain spec to be edited + #[arg(long, short)] + pub input_chain_spec: PathBuf, + /// The path to new runtime wasm blob to be stored into chain-spec + #[arg(long, short = 'r')] + pub runtime_wasm_path: Option, + /// Convert genesis spec to raw format + #[arg(long, short = 's')] + pub convert_to_raw: bool, +} + +/// Verifies provided input chain spec. If the runtime is provided verification is performed against +/// new runtime. +#[derive(Parser, Debug, Clone)] +pub struct VerifyCmd { + /// Chain spec to be edited + #[arg(long, short)] + pub input_chain_spec: PathBuf, + /// The path to new runtime wasm blob to be stored into chain-spec + #[arg(long, short = 'r')] + pub runtime_wasm_path: Option, } /// Generate the chain spec using the given seeds and accounts. @@ -145,27 +218,24 @@ pub fn generate_chain_spec( let sudo_account = parse_account(sudo_account)?; - let chain_spec = chain_spec::ChainSpec::from_genesis( - "Custom", - "custom", - sc_chain_spec::ChainType::Live, - move || { - genesis_constructor( - &authority_seeds, - &nominator_accounts, - &endowed_accounts, - &sudo_account, - ) - }, - vec![], - None, - None, - None, - None, - Default::default(), - ); - - chain_spec.as_json(false) + let authorities = authority_seeds + .iter() + .map(AsRef::as_ref) + .map(chain_spec::authority_keys_from_seed) + .collect::>(); + + chain_spec::ChainSpec::builder(kitchensink_runtime::wasm_binary_unwrap(), Default::default()) + .with_name("Custom") + .with_id("custom") + .with_chain_type(sc_chain_spec::ChainType::Live) + .with_genesis_config_patch(chain_spec::testnet_genesis( + authorities, + nominator_accounts, + sudo_account, + Some(endowed_accounts), + )) + .build() + .as_json(false) } /// Generate the authority keys and store them in the given `keystore_path`. @@ -241,3 +311,54 @@ pub fn print_seeds( println!("{}", header.paint("Sudo seed")); println!("//{}", sudo_seed); } + +/// Processes `RuntimeCmd` and returns JSON version of `ChainSpec` +pub fn generate_chain_spec_for_runtime(cmd: &RuntimeCmd) -> Result { + let code = fs::read(cmd.runtime_wasm_path.as_path()) + .map_err(|e| format!("wasm blob shall be readable {e}"))?; + + let builder = chain_spec::ChainSpec::builder(&code[..], Default::default()) + .with_name(&cmd.chain_name[..]) + .with_id(&cmd.chain_id[..]) + .with_chain_type(sc_chain_spec::ChainType::Live); + + let builder = match cmd.action { + GenesisBuildAction::Patch(PatchCmd { ref patch_path }) => { + let patch = fs::read(patch_path.as_path()) + .map_err(|e| format!("patch file {patch_path:?} shall be readable: {e}"))?; + builder.with_genesis_config_patch(serde_json::from_slice::(&patch[..]).map_err( + |e| format!("patch file {patch_path:?} shall contain a valid json: {e}"), + )?) + }, + GenesisBuildAction::Full(FullCmd { ref config_path }) => { + let config = fs::read(config_path.as_path()) + .map_err(|e| format!("config file {config_path:?} shall be readable: {e}"))?; + builder.with_genesis_config(serde_json::from_slice::(&config[..]).map_err( + |e| format!("config file {config_path:?} shall contain a valid json: {e}"), + )?) + }, + GenesisBuildAction::Default(DefaultCmd { ref default_config_path }) => { + let caller = GenesisConfigBuilderRuntimeCaller::new(&code[..]); + let default_config = caller + .get_default_config() + .map_err(|e| format!("getting default config from runtime should work: {e}"))?; + default_config_path.clone().map(|path| { + fs::write(path.as_path(), serde_json::to_string_pretty(&default_config).unwrap()) + .map_err(|err| err.to_string()) + }); + builder.with_genesis_config(default_config) + }, + }; + + let chain_spec = builder.build(); + + match (cmd.verify, cmd.raw_storage) { + (_, true) => chain_spec.as_json(true), + (true, false) => { + chain_spec.as_json(true)?; + println!("Genesis config verification: OK"); + chain_spec.as_json(false) + }, + (false, false) => chain_spec.as_json(false), + } +} diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index e326d84ae50..b11088190d1 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -13,15 +13,27 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } memmap2 = "0.5.0" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } sc-executor = { path = "../executor" } +sp-io = { default-features = false, path = "../../primitives/io" } sc-network = { path = "../network" } sc-telemetry = { path = "../telemetry" } sp-blockchain = { path = "../../primitives/blockchain" } sp-core = { path = "../../primitives/core" } +sp-genesis-builder = { path = "../../primitives/genesis-builder" } sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } +log = { version = "0.4.17", default-features = false } +array-bytes = { version = "6.1" } +docify = "0.2.0" + +[dev-dependencies] +substrate-test-runtime = { path = "../../test-utils/runtime" } +sp-keyring = { path = "../../primitives/keyring" } +sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto", features = ["serde"] } +sp-consensus-babe = { default-features = false, path = "../../primitives/consensus/babe", features = ["serde"] } diff --git a/substrate/client/chain-spec/README.md b/substrate/client/chain-spec/README.md index dad1662d323..9f746d2d4ce 100644 --- a/substrate/client/chain-spec/README.md +++ b/substrate/client/chain-spec/README.md @@ -1,92 +1,6 @@ Substrate chain configurations. -This crate contains structs and utilities to declare -a runtime-specific configuration file (a.k.a chain spec). - -Basic chain spec type containing all required parameters is -[`ChainSpec`](https://docs.rs/sc-chain-spec/latest/sc_chain_spec/struct.GenericChainSpec.html). It can be extended with -additional options that contain configuration specific to your chain. -Usually the extension is going to be an amalgamate of types exposed -by Substrate core modules. To allow the core modules to retrieve -their configuration from your extension you should use `ChainSpecExtension` -macro exposed by this crate. - -```rust -use std::collections::HashMap; -use sc_chain_spec::{GenericChainSpec, ChainSpecExtension}; - -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)] -pub struct MyExtension { - pub known_blocks: HashMap, -} - -pub type MyChainSpec = GenericChainSpec; -``` - -Some parameters may require different values depending on the -current blockchain height (a.k.a. forks). You can use `ChainSpecGroup` -macro and provided [`Forks`](https://docs.rs/sc-chain-spec/latest/sc_chain_spec/struct.Forks.html) structure to put -such parameters to your chain spec. -This will allow to override a single parameter starting at specific -block number. - -```rust -use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec}; - -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] -pub struct ClientParams { - max_block_size: usize, - max_extrinsic_size: usize, -} - -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] -pub struct PoolParams { - max_transaction_size: usize, -} - -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)] -pub struct Extension { - pub client: ClientParams, - pub pool: PoolParams, -} - -pub type BlockNumber = u64; - -/// A chain spec supporting forkable `ClientParams`. -pub type MyChainSpec1 = GenericChainSpec>; - -/// A chain spec supporting forkable `Extension`. -pub type MyChainSpec2 = GenericChainSpec>; -``` - -It's also possible to have a set of parameters that is allowed to change -with block numbers (i.e. is forkable), and another set that is not subject to changes. -This is also possible by declaring an extension that contains `Forks` within it. - - -```rust -use serde::{Serialize, Deserialize}; -use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension}; - -#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] -pub struct ClientParams { - max_block_size: usize, - max_extrinsic_size: usize, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] -pub struct PoolParams { - max_transaction_size: usize, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)] -pub struct Extension { - pub client: ClientParams, - #[forks] - pub pool: Forks, -} - -pub type MyChainSpec = GenericChainSpec; -``` +This crate contains structs and utilities to declare a runtime-specific configuration file (a.k.a chain spec). +Refer to crate documentation for details. License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/chain-spec/res/raw_no_code.json b/substrate/client/chain-spec/res/raw_no_code.json new file mode 100644 index 00000000000..bac7c25582f --- /dev/null +++ b/substrate/client/chain-spec/res/raw_no_code.json @@ -0,0 +1,18 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x3a636f6465": "0x010101" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/client/chain-spec/res/raw_with_code.json b/substrate/client/chain-spec/res/raw_with_code.json new file mode 100644 index 00000000000..c12cec57ba7 --- /dev/null +++ b/substrate/client/chain-spec/res/raw_with_code.json @@ -0,0 +1,19 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x3a636f6465": "0x010101" + }, + "childrenDefault": {} + } + }, + "code": "0x060708" +} diff --git a/substrate/client/chain-spec/res/substrate_test_runtime_from_config.json b/substrate/client/chain-spec/res/substrate_test_runtime_from_config.json new file mode 100644 index 00000000000..d16f26d1254 --- /dev/null +++ b/substrate/client/chain-spec/res/substrate_test_runtime_from_config.json @@ -0,0 +1,128 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "config": { + "babe": { + "authorities": [ + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1 + ] + ], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryPlainSlots", + "c": [ + 3, + 10 + ] + } + }, + "balances": { + "balances": [ + [ + "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH", + 100000000000000000 + ], + [ + "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o", + 100000000000000000 + ], + [ + "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9", + 100000000000000000 + ], + [ + "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK", + 100000000000000000 + ], + [ + "5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW", + 100000000000000000 + ], + [ + "5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR", + 100000000000000000 + ], + [ + "5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY", + 100000000000000000 + ], + [ + "5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ", + 100000000000000000 + ], + [ + "5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX", + 100000000000000000 + ], + [ + "5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q", + 100000000000000000 + ], + [ + "5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz", + 100000000000000000 + ], + [ + "5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf", + 100000000000000000 + ], + [ + "5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz", + 100000000000000000 + ], + [ + "5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC", + 100000000000000000 + ], + [ + "5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51", + 100000000000000000 + ], + [ + "5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e", + 100000000000000000 + ], + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 100000000000000000 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 100000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 100000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" + ] + }, + "system": {} + }, + "code": "0x0" + } + } +} diff --git a/substrate/client/chain-spec/res/substrate_test_runtime_from_config_raw.json b/substrate/client/chain-spec/res/substrate_test_runtime_from_config_raw.json new file mode 100644 index 00000000000..f033163ab19 --- /dev/null +++ b/substrate/client/chain-spec/res/substrate_test_runtime_from_config_raw.json @@ -0,0 +1,53 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48010000000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe220100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48010000000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe220100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x03000000000000000a0000000000000001", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901cae4e3edfbb32c91ed3f01ab964f4eeeab50338d8e5176d3141802d7b010a55dadcd5f23cf8aaafa724627e967e90e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da91b614bd4a126f2d5d294e9a8af9da25248d7e931307afb4b68d8d565d4c66e00d856c6d65f5fed6bb82dcfb60e936c67": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94b21aff9fe1e8b2fc4b0775b8cbeff28ba8e2c7594dd74730f3ca835e95455d199261897edc9735d602ea29615e2b10b": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95786a2916fcb81e1bd5dcd81e0d2452884617f575372edb5a36d85c04cdf2e4699f96fe33eb5f94a28c041b88e398d0c": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95b8542d9672c7b7e779cc7c1e6b605691c2115d06120ea2bee32dd601d02f36367564e7ddf84ae2717ca3f097459652e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da996c30bdbfab640838e6b6d3c33ab4adb4211b79e34ee8072eab506edd4b93a7b85a14c9a05e5cdd056d98e7dbca87730": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99dc65b1339ec388fbf2ca0cdef51253512c6cfd663203ea16968594f24690338befd906856c4d2f4ef32dad578dba20c": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99e6eb5abd62f5fd54793da91a47e6af6125d57171ff9241f07acaa1bb6a6103517965cf2cd00e643b27e7599ebccba70": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d0052993b6f3bd0544fd1f5e4125b9fbde3e789ecd53431fe5c06c12b72137153496dace35c695b5f4d7b41f7ed5763b": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d6b7e9a5f12bc571053265dade10d3b4b606fc73f57f03cdb4c932d475ab426043e429cecc2ffff0d2672b0df8398c48": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e1a35f56ee295d39287cbffcfc60c4b346f136b564e1fad55031404dd84e5cd3fa76bfe7cc7599b39d38fd06663bbc0a": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e2c1dc507e2035edbbd8776c440d870460c57f0008067cc01c5ff9eb2e2f9b3a94299a915a91198bd1021a6c55596f57": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9eca0e653a94f4080f6311b4e7b6934eb2afba9278e30ccf6a6ceb3a8b6e336b70068f045c666f2e7f4f9cc5f47db8972": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ee8bf7ef90fc56a8aa3b90b344c599550c29b161e27ff8ba45bf6bad4711f326fc506a8803453a4d7e3158e993495f10": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9f5d6f1c082fe63eec7a71fcad00f4a892e3d43b7b0d04e776e69e7be35247cecdac65504c579195731eaf64b7940966e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9fbf0818841edf110e05228a6379763c4fc3c37459d9bdc61f58a5ebc01e9e2305a19d390c0543dc733861ec3cf1de01f": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x0", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00003ef1ee275e1a" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/client/chain-spec/res/substrate_test_runtime_from_patch.json b/substrate/client/chain-spec/res/substrate_test_runtime_from_patch.json new file mode 100644 index 00000000000..6cef1dac7ac --- /dev/null +++ b/substrate/client/chain-spec/res/substrate_test_runtime_from_patch.json @@ -0,0 +1,32 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "patch": { + "babe": { + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryPlainSlots", + "c": [ + 7, + 10 + ] + } + }, + "substrateTest": { + "authorities": [ + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" + ] + } + }, + "code": "0x0" + } + } +} diff --git a/substrate/client/chain-spec/res/substrate_test_runtime_from_patch_raw.json b/substrate/client/chain-spec/res/substrate_test_runtime_from_patch_raw.json new file mode 100644 index 00000000000..9f4b2731649 --- /dev/null +++ b/substrate/client/chain-spec/res/substrate_test_runtime_from_patch_raw.json @@ -0,0 +1,32 @@ +{ + "name": "TestName", + "id": "test_id", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x081cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x07000000000000000a0000000000000001", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x0", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0000000000000000" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index 96e36d8399e..a44a3b4fbd9 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -18,8 +18,10 @@ //! Substrate chain configurations. #![warn(missing_docs)] - -use crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis}; +use crate::{ + extension::GetExtension, ChainType, GenesisConfigBuilderRuntimeCaller as RuntimeCaller, + Properties, RuntimeGenesis, +}; use sc_network::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; use serde::{Deserialize, Serialize}; @@ -29,13 +31,32 @@ use sp_core::{ Bytes, }; use sp_runtime::BuildStorage; -use std::{borrow::Cow, collections::BTreeMap, fs::File, path::PathBuf, sync::Arc}; +use std::{ + borrow::Cow, + collections::{BTreeMap, VecDeque}, + fs::File, + marker::PhantomData, + path::PathBuf, + sync::Arc, +}; + +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +enum GenesisBuildAction { + Patch(json::Value), + Full(json::Value), +} +#[allow(deprecated)] enum GenesisSource { File(PathBuf), Binary(Cow<'static, [u8]>), - Factory(Arc G + Send + Sync>), + /// factory function + code + //Factory and G type parameter shall be removed togheter with `ChainSpec::from_genesis` + Factory(Arc G + Send + Sync>, Vec), Storage(Storage), + /// build action + code + GenesisBuilderApi(GenesisBuildAction, Vec), } impl Clone for GenesisSource { @@ -43,14 +64,17 @@ impl Clone for GenesisSource { match *self { Self::File(ref path) => Self::File(path.clone()), Self::Binary(ref d) => Self::Binary(d.clone()), - Self::Factory(ref f) => Self::Factory(f.clone()), + Self::Factory(ref f, ref c) => Self::Factory(f.clone(), c.clone()), Self::Storage(ref s) => Self::Storage(s.clone()), + Self::GenesisBuilderApi(ref s, ref c) => Self::GenesisBuilderApi(s.clone(), c.clone()), } } } impl GenesisSource { fn resolve(&self) -> Result, String> { + /// helper container for deserializing genesis from the JSON file (ChainSpec JSON file is + /// also supported here) #[derive(Serialize, Deserialize)] struct GenesisContainer { genesis: Genesis, @@ -79,31 +103,21 @@ impl GenesisSource { .map_err(|e| format!("Error parsing embedded file: {}", e))?; Ok(genesis.genesis) }, - Self::Factory(f) => Ok(Genesis::Runtime(f())), - Self::Storage(storage) => { - let top = storage - .top - .iter() - .map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone()))) - .collect(); - - let children_default = storage - .children_default - .iter() - .map(|(k, child)| { - ( - StorageKey(k.clone()), - child - .data - .iter() - .map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone()))) - .collect(), - ) - }) - .collect(); - - Ok(Genesis::Raw(RawGenesis { top, children_default })) - }, + Self::Factory(f, code) => Ok(Genesis::RuntimeAndCode(RuntimeInnerWrapper { + runtime: f(), + code: code.clone(), + })), + Self::Storage(storage) => Ok(Genesis::Raw(RawGenesis::from(storage.clone()))), + Self::GenesisBuilderApi(GenesisBuildAction::Full(config), code) => + Ok(Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Config(config.clone()), + code: code.clone(), + })), + Self::GenesisBuilderApi(GenesisBuildAction::Patch(patch), code) => + Ok(Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Patch(patch.clone()), + code: code.clone(), + })), } } } @@ -111,7 +125,18 @@ impl GenesisSource { impl BuildStorage for ChainSpec { fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { match self.genesis.resolve()? { - Genesis::Runtime(gc) => gc.assimilate_storage(storage), + #[allow(deprecated)] + Genesis::Runtime(runtime_genesis_config) => { + runtime_genesis_config.assimilate_storage(storage)?; + }, + #[allow(deprecated)] + Genesis::RuntimeAndCode(RuntimeInnerWrapper { + runtime: runtime_genesis_config, + code, + }) => { + runtime_genesis_config.assimilate_storage(storage)?; + storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); + }, Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => { storage.top.extend(map.into_iter().map(|(k, v)| (k.0, v.0))); children_map.into_iter().for_each(|(k, v)| { @@ -123,13 +148,37 @@ impl BuildStorage for ChainSpec { .data .extend(v.into_iter().map(|(k, v)| (k.0, v.0))); }); - Ok(()) }, // The `StateRootHash` variant exists as a way to keep note that other clients support // it, but Substrate itself isn't capable of loading chain specs with just a hash at the // moment. - Genesis::StateRootHash(_) => Err("Genesis storage in hash format not supported".into()), - } + Genesis::StateRootHash(_) => + return Err("Genesis storage in hash format not supported".into()), + Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Config(config), + code, + }) => { + RuntimeCaller::new(&code[..]) + .get_storage_for_config(config)? + .assimilate_storage(storage)?; + storage + .top + .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone()); + }, + Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Patch(patch), + code, + }) => { + RuntimeCaller::new(&code[..]) + .get_storage_for_patch(patch)? + .assimilate_storage(storage)?; + storage + .top + .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone()); + }, + }; + + Ok(()) } } @@ -144,20 +193,98 @@ pub struct RawGenesis { pub children_default: BTreeMap, } +impl From for RawGenesis { + fn from(value: sp_core::storage::Storage) -> Self { + Self { + top: value.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect(), + children_default: value + .children_default + .into_iter() + .map(|(sk, child)| { + ( + StorageKey(sk), + child + .data + .into_iter() + .map(|(k, v)| (StorageKey(k), StorageData(v))) + .collect(), + ) + }) + .collect(), + } + } +} + +/// Inner representation of [`Genesis::RuntimeGenesis`] format +#[derive(Serialize, Deserialize, Debug)] +struct RuntimeGenesisInner { + /// Runtime wasm code, expected to be hex-encoded in JSON. + /// The code shall be capable of parsing `json_blob`. + #[serde(default, with = "sp_core::bytes")] + code: Vec, + /// The patch or full representation of runtime's `RuntimeGenesisConfig` struct. + #[serde(flatten)] + json_blob: RuntimeGenesisConfigJson, +} + +/// Represents two possible variants of the contained JSON blob for the +/// [`Genesis::RuntimeGenesis`] format. +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +enum RuntimeGenesisConfigJson { + /// Represents the explicit and comprehensive runtime genesis config in JSON format. + /// The contained object is a JSON blob that can be parsed by a compatible runtime. + /// + /// Using a full config is useful for when someone wants to ensure that a change in the runtime + /// makes the deserialization fail and not silently add some default values. + Config(json::Value), + /// Represents a patch for the default runtime genesis config in JSON format which is + /// essentially a list of keys that are to be customized in runtime genesis config. + /// The contained value is a JSON blob that can be parsed by a compatible runtime. + Patch(json::Value), +} + +/// Inner variant wrapper for deprecated runtime. +#[derive(Serialize, Deserialize, Debug)] +struct RuntimeInnerWrapper { + /// The native `RuntimeGenesisConfig` struct. + runtime: G, + /// Runtime code. + #[serde(with = "sp_core::bytes")] + code: Vec, +} + +/// Represents the different formats of the genesis state within chain spec JSON blob. #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] enum Genesis { + /// (Deprecated) Contains the JSON representation of G (the native type representing the + /// runtime's `RuntimeGenesisConfig` struct) (will be removed with `ChainSpec::from_genesis`) + /// without the runtime code. It is required to deserialize the legacy chainspecs genereted + /// with `ChainsSpec::from_genesis` method. Runtime(G), + /// (Deprecated) Contains the JSON representation of G (the native type representing the + /// runtime's `RuntimeGenesisConfig` struct) (will be removed with `ChainSpec::from_genesis`) + /// and the runtime code. It is required to create and deserialize JSON chainspecs created with + /// deprecated `ChainSpec::from_genesis` method. + RuntimeAndCode(RuntimeInnerWrapper), + /// The genesis storage as raw data. Typically raw key-value entries in state. Raw(RawGenesis), /// State root hash of the genesis storage. StateRootHash(StorageData), + /// Represents the runtime genesis config in JSON format toghether with runtime code. + RuntimeGenesis(RuntimeGenesisInner), } /// A configuration of a client. Does not include runtime storage initialization. +/// Note: `genesis` field is ignored due to way how the chain specification is serialized into +/// JSON file. Refer to [`ChainSpecJsonContainer`], which flattens [`ClientSpec`] and denies uknown +/// fields. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] +// we cannot #[serde(deny_unknown_fields)]. Otherwise chain-spec-builder will fail on any +// non-standard spec struct ClientSpec { name: String, id: String, @@ -194,6 +321,137 @@ struct ClientSpec { /// We use `Option` here since `()` is not flattenable by serde. pub type NoExtension = Option<()>; +/// Builder for creating [`ChainSpec`] instances. +pub struct ChainSpecBuilder { + code: Vec, + extensions: E, + name: String, + id: String, + chain_type: ChainType, + genesis_build_action: GenesisBuildAction, + boot_nodes: Option>, + telemetry_endpoints: Option, + protocol_id: Option, + fork_id: Option, + properties: Option, + _genesis: PhantomData, +} + +impl ChainSpecBuilder { + /// Creates a new builder instance with no defaults. + pub fn new(code: &[u8], extensions: E) -> Self { + Self { + code: code.into(), + extensions, + name: "Development".to_string(), + id: "dev".to_string(), + chain_type: ChainType::Local, + genesis_build_action: GenesisBuildAction::Patch(Default::default()), + boot_nodes: None, + telemetry_endpoints: None, + protocol_id: None, + fork_id: None, + properties: None, + _genesis: Default::default(), + } + } + + /// Sets the spec name. + pub fn with_name(mut self, name: &str) -> Self { + self.name = name.into(); + self + } + + /// Sets the spec ID. + pub fn with_id(mut self, id: &str) -> Self { + self.id = id.into(); + self + } + + /// Sets the type of the chain. + pub fn with_chain_type(mut self, chain_type: ChainType) -> Self { + self.chain_type = chain_type; + self + } + + /// Sets a list of bootnode addresses. + pub fn with_boot_nodes(mut self, boot_nodes: Vec) -> Self { + self.boot_nodes = Some(boot_nodes); + self + } + + /// Sets telemetry endpoints. + pub fn with_telemetry_endpoints(mut self, telemetry_endpoints: TelemetryEndpoints) -> Self { + self.telemetry_endpoints = Some(telemetry_endpoints); + self + } + + /// Sets the network protocol ID. + pub fn with_protocol_id(mut self, protocol_id: &str) -> Self { + self.protocol_id = Some(protocol_id.into()); + self + } + + /// Sets an optional network fork identifier. + pub fn with_fork_id(mut self, fork_id: &str) -> Self { + self.fork_id = Some(fork_id.into()); + self + } + + /// Sets additional loosely-typed properties of the chain. + pub fn with_properties(mut self, properties: Properties) -> Self { + self.properties = Some(properties); + self + } + + /// Sets chain spec extensions. + pub fn with_extensions(mut self, extensions: E) -> Self { + self.extensions = extensions; + self + } + + /// Sets the code. + pub fn with_code(mut self, code: &[u8]) -> Self { + self.code = code.into(); + self + } + + /// Sets the JSON patch for runtime's GenesisConfig. + pub fn with_genesis_config_patch(mut self, patch: json::Value) -> Self { + self.genesis_build_action = GenesisBuildAction::Patch(patch); + self + } + + /// Sets the full runtime's GenesisConfig JSON. + pub fn with_genesis_config(mut self, config: json::Value) -> Self { + self.genesis_build_action = GenesisBuildAction::Full(config); + self + } + + /// Builds a [`ChainSpec`] instance using the provided settings. + pub fn build(self) -> ChainSpec { + let client_spec = ClientSpec { + name: self.name, + id: self.id, + chain_type: self.chain_type, + boot_nodes: self.boot_nodes.unwrap_or_default(), + telemetry_endpoints: self.telemetry_endpoints, + protocol_id: self.protocol_id, + fork_id: self.fork_id, + properties: self.properties, + extensions: self.extensions, + consensus_engine: (), + genesis: Default::default(), + code_substitutes: BTreeMap::new(), + }; + + ChainSpec { + client_spec, + genesis: GenesisSource::GenesisBuilderApi(self.genesis_build_action, self.code.into()), + } + } +} + /// A configuration of a chain. Can be used to build a genesis block. pub struct ChainSpec { client_spec: ClientSpec, @@ -260,6 +518,10 @@ impl ChainSpec { } /// Create hardcoded spec. + #[deprecated( + note = "`from_genesis` is planned to be removed in May 2024. Use `builder()` instead." + )] + // deprecated note: Genesis::Runtime + GenesisSource::Factory shall also be removed pub fn from_genesis G + 'static + Send + Sync>( name: &str, id: &str, @@ -271,6 +533,7 @@ impl ChainSpec { fork_id: Option<&str>, properties: Option, extensions: E, + code: &[u8], ) -> Self { let client_spec = ClientSpec { name: name.to_owned(), @@ -287,21 +550,30 @@ impl ChainSpec { code_substitutes: BTreeMap::new(), }; - ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) } + ChainSpec { + client_spec, + genesis: GenesisSource::Factory(Arc::new(constructor), code.into()), + } } /// Type of the chain. fn chain_type(&self) -> ChainType { self.client_spec.chain_type.clone() } + + /// Provides a `ChainSpec` builder. + pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder { + ChainSpecBuilder::new(code, extensions) + } } -impl ChainSpec { +impl ChainSpec { /// Parse json content into a `ChainSpec` pub fn from_json_bytes(json: impl Into>) -> Result { let json = json.into(); let client_spec = json::from_slice(json.as_ref()) .map_err(|e| format!("Error parsing spec file: {}", e))?; + Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) }) } @@ -318,50 +590,74 @@ impl ChainSpec { memmap2::Mmap::map(&file) .map_err(|e| format!("Error mmaping spec file `{}`: {}", path.display(), e))? }; - let client_spec = json::from_slice(&bytes).map_err(|e| format!("Error parsing spec file: {}", e))?; + Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) }) } } +/// Helper structure for serializing (and only serializing) the ChainSpec into JSON file. It +/// represents the layout of `ChainSpec` JSON file. #[derive(Serialize, Deserialize)] -struct JsonContainer { +// we cannot #[serde(deny_unknown_fields)]. Otherwise chain-spec-builder will fail on any +// non-standard spec. +struct ChainSpecJsonContainer { #[serde(flatten)] client_spec: ClientSpec, genesis: Genesis, } impl ChainSpec { - fn json_container(&self, raw: bool) -> Result, String> { - let genesis = match (raw, self.genesis.resolve()?) { + fn json_container(&self, raw: bool) -> Result, String> { + let raw_genesis = match (raw, self.genesis.resolve()?) { + ( + true, + Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Config(config), + code, + }), + ) => { + let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_config(config)?; + storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); + RawGenesis::from(storage) + }, + ( + true, + Genesis::RuntimeGenesis(RuntimeGenesisInner { + json_blob: RuntimeGenesisConfigJson::Patch(patch), + code, + }), + ) => { + let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_patch(patch)?; + storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); + RawGenesis::from(storage) + }, + + #[allow(deprecated)] + (true, Genesis::RuntimeAndCode(RuntimeInnerWrapper { runtime: g, code })) => { + let mut storage = g.build_storage()?; + storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); + RawGenesis::from(storage) + }, + #[allow(deprecated)] (true, Genesis::Runtime(g)) => { let storage = g.build_storage()?; - let top = - storage.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect(); - let children_default = storage - .children_default - .into_iter() - .map(|(sk, child)| { - ( - StorageKey(sk), - child - .data - .into_iter() - .map(|(k, v)| (StorageKey(k), StorageData(v))) - .collect(), - ) - }) - .collect(); - - Genesis::Raw(RawGenesis { top, children_default }) + RawGenesis::from(storage) }, - (_, genesis) => genesis, + (true, Genesis::Raw(raw)) => raw, + + (_, genesis) => + return Ok(ChainSpecJsonContainer { client_spec: self.client_spec.clone(), genesis }), }; - Ok(JsonContainer { client_spec: self.client_spec.clone(), genesis }) + + Ok(ChainSpecJsonContainer { + client_spec: self.client_spec.clone(), + genesis: Genesis::Raw(raw_genesis), + }) } - /// Dump to json string. + /// Dump the chain specification to JSON string. pub fn as_json(&self, raw: bool) -> Result { let container = self.json_container(raw)?; json::to_string_pretty(&container).map_err(|e| format!("Error generating spec json: {}", e)) @@ -442,9 +738,87 @@ where } } +/// The `fun` will be called with the value at `path`. +/// +/// If exists, the value at given `path` will be passed to the `fun` and the result of `fun` +/// call will be returned. Otherwise false is returned. +/// `path` will be modified. +/// +/// # Examples +/// ```ignore +/// use serde_json::{from_str, json, Value}; +/// let doc = json!({"a":{"b":{"c":"5"}}}); +/// let mut path = ["a", "b", "c"].into(); +/// assert!(json_eval_value_at_key(&doc, &mut path, &|v| { assert_eq!(v,"5"); true })); +/// ``` +fn json_eval_value_at_key( + doc: &json::Value, + path: &mut VecDeque<&str>, + fun: &dyn Fn(&json::Value) -> bool, +) -> bool { + let Some(key) = path.pop_front() else { + return false; + }; + + if path.is_empty() { + doc.as_object().map_or(false, |o| o.get(key).map_or(false, |v| fun(v))) + } else { + doc.as_object() + .map_or(false, |o| o.get(key).map_or(false, |v| json_eval_value_at_key(v, path, fun))) + } +} + +macro_rules! json_path { + [ $($x:expr),+ ] => { + VecDeque::<&str>::from([$($x),+]) + }; +} + +fn json_contains_path(doc: &json::Value, path: &mut VecDeque<&str>) -> bool { + json_eval_value_at_key(doc, path, &|_| true) +} + +/// This function updates the code in given chain spec. +/// +/// Function support updating the runtime code in provided JSON chain spec blob. `Genesis::Raw` +/// and `Genesis::RuntimeGenesis` formats are supported. +/// +/// If update was successful `true` is returned, otherwise `false`. Chain spec JSON is modified in +/// place. +pub fn update_code_in_json_chain_spec(chain_spec: &mut json::Value, code: &[u8]) -> bool { + let mut path = json_path!["genesis", "runtimeGenesis", "code"]; + let mut raw_path = json_path!["genesis", "raw", "top"]; + + if json_contains_path(&chain_spec, &mut path) { + #[derive(Serialize)] + struct Container<'a> { + #[serde(with = "sp_core::bytes")] + code: &'a [u8], + } + let code_patch = json::json!({"genesis":{"runtimeGenesis": Container { code }}}); + crate::json_patch::merge(chain_spec, code_patch); + true + } else if json_contains_path(&chain_spec, &mut raw_path) { + #[derive(Serialize)] + struct Container<'a> { + #[serde(with = "sp_core::bytes", rename = "0x3a636f6465")] + code: &'a [u8], + } + let code_patch = json::json!({"genesis":{"raw":{"top": Container { code }}}}); + crate::json_patch::merge(chain_spec, code_patch); + true + } else { + false + } +} + #[cfg(test)] mod tests { use super::*; + use serde_json::{from_str, json, Value}; + use sp_application_crypto::Ss58Codec; + use sp_core::storage::well_known_keys; + use sp_keyring::AccountKeyring; #[derive(Debug, Serialize, Deserialize)] struct Genesis(BTreeMap); @@ -536,4 +910,336 @@ mod tests { ); } } + + #[test] + // some tests for json path utils + fn test_json_eval_value_at_key() { + let doc = json!({"a":{"b1":"20","b":{"c":{"d":"10"}}}}); + + assert!(json_eval_value_at_key(&doc, &mut json_path!["a", "b1"], &|v| { *v == "20" })); + assert!(json_eval_value_at_key(&doc, &mut json_path!["a", "b", "c", "d"], &|v| { + *v == "10" + })); + assert!(!json_eval_value_at_key(&doc, &mut json_path!["a", "c", "d"], &|_| { true })); + assert!(!json_eval_value_at_key(&doc, &mut json_path!["d"], &|_| { true })); + + assert!(json_contains_path(&doc, &mut json_path!["a", "b1"])); + assert!(json_contains_path(&doc, &mut json_path!["a", "b"])); + assert!(json_contains_path(&doc, &mut json_path!["a", "b", "c"])); + assert!(json_contains_path(&doc, &mut json_path!["a", "b", "c", "d"])); + assert!(!json_contains_path(&doc, &mut json_path!["a", "b", "c", "d", "e"])); + assert!(!json_contains_path(&doc, &mut json_path!["a", "b", "b1"])); + assert!(!json_contains_path(&doc, &mut json_path!["d"])); + } + + fn zeroize_code_key_in_json(encoded: bool, json: &str) -> Value { + let mut json = from_str::(json).unwrap(); + let (zeroing_patch, mut path) = if encoded { + ( + json!({"genesis":{"raw":{"top":{"0x3a636f6465":"0x0"}}}}), + json_path!["genesis", "raw", "top", "0x3a636f6465"], + ) + } else { + ( + json!({"genesis":{"runtimeGenesis":{"code":"0x0"}}}), + json_path!["genesis", "runtimeGenesis", "code"], + ) + }; + assert!(json_contains_path(&json, &mut path)); + crate::json_patch::merge(&mut json, zeroing_patch); + json + } + + #[docify::export] + #[test] + fn build_chain_spec_with_patch_works() { + let output: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(json!({ + "babe": { + "epochConfig": { + "c": [ + 7, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + AccountKeyring::Ferdie.public().to_ss58check(), + AccountKeyring::Alice.public().to_ss58check() + ], + } + })) + .build(); + + let raw_chain_spec = output.as_json(true); + assert!(raw_chain_spec.is_ok()); + } + + #[docify::export] + #[test] + fn generate_chain_spec_with_patch_works() { + let output: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(json!({ + "babe": { + "epochConfig": { + "c": [ + 7, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + AccountKeyring::Ferdie.public().to_ss58check(), + AccountKeyring::Alice.public().to_ss58check() + ], + } + })) + .build(); + + let actual = output.as_json(false).unwrap(); + let actual_raw = output.as_json(true).unwrap(); + + let expected = + from_str::(include_str!("../res/substrate_test_runtime_from_patch.json")) + .unwrap(); + let expected_raw = + from_str::(include_str!("../res/substrate_test_runtime_from_patch_raw.json")) + .unwrap(); + + //wasm blob may change overtime so let's zero it. Also ensure it is there: + let actual = zeroize_code_key_in_json(false, actual.as_str()); + let actual_raw = zeroize_code_key_in_json(true, actual_raw.as_str()); + + assert_eq!(actual, expected); + assert_eq!(actual_raw, expected_raw); + } + + #[test] + fn generate_chain_spec_with_full_config_works() { + let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); + let output: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config(from_str(j).unwrap()) + .build(); + + let actual = output.as_json(false).unwrap(); + let actual_raw = output.as_json(true).unwrap(); + + let expected = + from_str::(include_str!("../res/substrate_test_runtime_from_config.json")) + .unwrap(); + let expected_raw = + from_str::(include_str!("../res/substrate_test_runtime_from_config_raw.json")) + .unwrap(); + + //wasm blob may change overtime so let's zero it. Also ensure it is there: + let actual = zeroize_code_key_in_json(false, actual.as_str()); + let actual_raw = zeroize_code_key_in_json(true, actual_raw.as_str()); + + assert_eq!(actual, expected); + assert_eq!(actual_raw, expected_raw); + } + + #[test] + fn chain_spec_as_json_fails_with_invalid_config() { + let j = + include_str!("../../../test-utils/runtime/res/default_genesis_config_invalid_2.json"); + let output: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config(from_str(j).unwrap()) + .build(); + + assert_eq!( + output.as_json(true), + Err("Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 1 column 8".to_string()) + ); + } + + #[test] + fn chain_spec_as_json_fails_with_invalid_patch() { + let output: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(json!({ + "invalid_pallet": {}, + "substrateTest": { + "authorities": [ + AccountKeyring::Ferdie.public().to_ss58check(), + AccountKeyring::Alice.public().to_ss58check() + ], + } + })) + .build(); + + assert!(output.as_json(true).unwrap_err().contains("Invalid JSON blob: unknown field `invalid_pallet`, expected one of `system`, `babe`, `substrateTest`, `balances`")); + } + + #[test] + fn check_if_code_is_valid_for_raw_without_code() { + let spec = ChainSpec::<()>::from_json_bytes(Cow::Owned( + include_bytes!("../res/raw_no_code.json").to_vec(), + )) + .unwrap(); + + let j = from_str::(&spec.as_json(true).unwrap()).unwrap(); + + assert!(json_eval_value_at_key( + &j, + &mut json_path!["genesis", "raw", "top", "0x3a636f6465"], + &|v| { *v == "0x010101" } + )); + assert!(!json_contains_path(&j, &mut json_path!["code"])); + } + + #[test] + fn check_code_in_assimilated_storage_for_raw_without_code() { + let spec = ChainSpec::<()>::from_json_bytes(Cow::Owned( + include_bytes!("../res/raw_no_code.json").to_vec(), + )) + .unwrap(); + + let storage = spec.build_storage().unwrap(); + assert!(storage + .top + .get(&well_known_keys::CODE.to_vec()) + .map(|v| *v == vec![1, 1, 1]) + .unwrap()) + } + + #[test] + fn update_code_works_with_runtime_genesis_config() { + let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); + let chain_spec: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config(from_str(j).unwrap()) + .build(); + + let mut chain_spec_json = from_str::(&chain_spec.as_json(false).unwrap()).unwrap(); + assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6])); + + assert!(json_eval_value_at_key( + &chain_spec_json, + &mut json_path!["genesis", "runtimeGenesis", "code"], + &|v| { *v == "0x000102040506" } + )); + } + + #[test] + fn update_code_works_for_raw() { + let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); + let chain_spec: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config(from_str(j).unwrap()) + .build(); + + let mut chain_spec_json = from_str::(&chain_spec.as_json(true).unwrap()).unwrap(); + assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6])); + + assert!(json_eval_value_at_key( + &chain_spec_json, + &mut json_path!["genesis", "raw", "top", "0x3a636f6465"], + &|v| { *v == "0x000102040506" } + )); + } + + #[test] + fn update_code_works_with_runtime_genesis_patch() { + let chain_spec: ChainSpec<()> = ChainSpec::builder( + substrate_test_runtime::wasm_binary_unwrap().into(), + Default::default(), + ) + .with_name("TestName") + .with_id("test_id") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(json!({})) + .build(); + + let mut chain_spec_json = from_str::(&chain_spec.as_json(false).unwrap()).unwrap(); + assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6])); + + assert!(json_eval_value_at_key( + &chain_spec_json, + &mut json_path!["genesis", "runtimeGenesis", "code"], + &|v| { *v == "0x000102040506" } + )); + } + + #[test] + fn generate_from_genesis_is_still_supported() { + #[allow(deprecated)] + let chain_spec: ChainSpec = ChainSpec::from_genesis( + "TestName", + "test", + ChainType::Local, + move || substrate_test_runtime::RuntimeGenesisConfig { + babe: substrate_test_runtime::BabeConfig { + epoch_config: Some( + substrate_test_runtime::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION, + ), + ..Default::default() + }, + ..Default::default() + }, + Vec::new(), + None, + None, + None, + None, + Default::default(), + &vec![0, 1, 2, 4, 5, 6], + ); + + let chain_spec_json = from_str::(&chain_spec.as_json(false).unwrap()).unwrap(); + assert!(json_eval_value_at_key( + &chain_spec_json, + &mut json_path!["genesis", "runtimeAndCode", "code"], + &|v| { *v == "0x000102040506" } + )); + let chain_spec_json = from_str::(&chain_spec.as_json(true).unwrap()).unwrap(); + assert!(json_eval_value_at_key( + &chain_spec_json, + &mut json_path!["genesis", "raw", "top", "0x3a636f6465"], + &|v| { *v == "0x000102040506" } + )); + } } diff --git a/substrate/client/chain-spec/src/genesis.rs b/substrate/client/chain-spec/src/genesis_block.rs similarity index 100% rename from substrate/client/chain-spec/src/genesis.rs rename to substrate/client/chain-spec/src/genesis_block.rs diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs new file mode 100644 index 00000000000..c2c6249563f --- /dev/null +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -0,0 +1,183 @@ +// 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 . + +//! A helper module for calling the GenesisBuilder API from arbitrary runtime wasm blobs. + +use codec::{Decode, Encode}; +use sc_executor::{error::Result, WasmExecutor}; +use serde_json::{from_slice, Value}; +use sp_core::{ + storage::Storage, + traits::{CallContext, CodeExecutor, Externalities, FetchRuntimeCode, RuntimeCode}, +}; +use sp_genesis_builder::Result as BuildResult; +use sp_state_machine::BasicExternalities; +use std::borrow::Cow; + +/// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob. +pub struct GenesisConfigBuilderRuntimeCaller<'a> { + code: Cow<'a, [u8]>, + code_hash: Vec, + executor: WasmExecutor, +} + +impl<'a> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a> { + fn fetch_runtime_code(&self) -> Option> { + Some(self.code.as_ref().into()) + } +} + +impl<'a> GenesisConfigBuilderRuntimeCaller<'a> { + /// Creates new instance using the provided code blob. + /// + /// This code is later referred to as `runtime`. + pub fn new(code: &'a [u8]) -> Self { + GenesisConfigBuilderRuntimeCaller { + code: code.into(), + code_hash: sp_core::blake2_256(code).to_vec(), + executor: WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(), + } + } + + fn call(&self, ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result> { + self.executor + .call( + ext, + &RuntimeCode { heap_pages: None, code_fetcher: self, hash: self.code_hash.clone() }, + method, + data, + false, + CallContext::Offchain, + ) + .0 + } + + /// Returns the default `GenesisConfig` provided by the `runtime`. + /// + /// Calls [`GenesisBuilder::create_default_config`](sp_genesis_builder::GenesisBuilder::create_default_config) in the `runtime`. + pub fn get_default_config(&self) -> core::result::Result { + let mut t = BasicExternalities::new_empty(); + let call_result = self + .call(&mut t, "GenesisBuilder_create_default_config", &[]) + .map_err(|e| format!("wasm call error {e}"))?; + let default_config = Vec::::decode(&mut &call_result[..]) + .map_err(|e| format!("scale codec error: {e}"))?; + Ok(from_slice(&default_config[..]).expect("returned value is json. qed.")) + } + + /// Build the given `GenesisConfig` and returns the genesis state. + /// + /// Calls [`GenesisBuilder::build_config`](sp_genesis_builder::GenesisBuilder::build_config) + /// provided by the `runtime`. + pub fn get_storage_for_config(&self, config: Value) -> core::result::Result { + let mut ext = BasicExternalities::new_empty(); + + let call_result = self + .call(&mut ext, "GenesisBuilder_build_config", &config.to_string().encode()) + .map_err(|e| format!("wasm call error {e}"))?; + + BuildResult::decode(&mut &call_result[..]) + .map_err(|e| format!("scale codec error: {e}"))??; + + Ok(ext.into_storages()) + } + + /// Creates the genesis state by patching the default `GenesisConfig` and applying it. + /// + /// This function generates the `GenesisConfig` for the runtime by applying a provided JSON + /// patch. The patch modifies the default `GenesisConfig` allowing customization of the specific + /// keys. The resulting `GenesisConfig` is then deserialized from the patched JSON + /// representation and stored in the storage. + /// + /// If the provided JSON patch is incorrect or the deserialization fails the error will be + /// returned. + /// + /// The patching process modifies the default `GenesisConfig` according to the following rules: + /// 1. Existing keys in the default configuration will be overridden by the corresponding values + /// in the patch. + /// 2. If a key exists in the patch but not in the default configuration, it will be added to + /// the resulting `GenesisConfig`. + /// 3. Keys in the default configuration that have null values in the patch will be removed from + /// the resulting `GenesisConfig`. This is helpful for changing enum variant value. + /// + /// Please note that the patch may contain full `GenesisConfig`. + pub fn get_storage_for_patch(&self, patch: Value) -> core::result::Result { + let mut config = self.get_default_config()?; + crate::json_patch::merge(&mut config, patch); + self.get_storage_for_config(config) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::{from_str, json}; + pub use sp_consensus_babe::{AllowedSlots, BabeEpochConfiguration, Slot}; + + #[test] + fn get_default_config_works() { + let config = + GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap()) + .get_default_config() + .unwrap(); + let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + assert_eq!(from_str::(expected).unwrap(), config); + } + + #[test] + fn get_storage_for_patch_works() { + let patch = json!({ + "babe": { + "epochConfig": { + "c": [ + 69, + 696 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + }); + + let storage = + GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap()) + .get_storage_for_patch(patch) + .unwrap(); + + //Babe|Authorities + let value: Vec = storage + .top + .get( + &array_bytes::hex2bytes( + "1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef", + ) + .unwrap(), + ) + .unwrap() + .clone(); + + assert_eq!( + BabeEpochConfiguration::decode(&mut &value[..]).unwrap(), + BabeEpochConfiguration { + c: (69, 696), + allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots + } + ); + } +} diff --git a/substrate/client/chain-spec/src/json_patch.rs b/substrate/client/chain-spec/src/json_patch.rs new file mode 100644 index 00000000000..c3930069a60 --- /dev/null +++ b/substrate/client/chain-spec/src/json_patch.rs @@ -0,0 +1,191 @@ +// 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 . + +//! A helper module providing json patching functions. + +use serde_json::Value; + +/// Recursively merges two JSON objects, `a` and `b`, into a single object. +/// +/// If a key exists in both objects, the value from `b` will override the value from `a`. +/// If a key exists in `b` with a `null` value, it will be removed from `a`. +/// If a key exists only in `b` and not in `a`, it will be added to `a`. +/// +/// # Arguments +/// +/// * `a` - A mutable reference to the target JSON object to merge into. +/// * `b` - The JSON object to merge with `a`. +pub fn merge(a: &mut Value, b: Value) { + match (a, b) { + (Value::Object(a), Value::Object(b)) => + for (k, v) in b { + if v.is_null() { + a.remove(&k); + } else { + merge(a.entry(k).or_insert(Value::Null), v); + } + }, + (a, b) => *a = b, + }; +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test1_simple_merge() { + let mut j1 = json!({ "a":123 }); + merge(&mut j1, json!({ "b":256 })); + assert_eq!(j1, json!({ "a":123, "b":256 })); + } + + #[test] + fn test2_patch_simple_merge_nested() { + let mut j1 = json!({ + "a": { + "name": "xxx", + "value": 123 + }, + "b": { "c" : { "inner_name": "yyy" } } + }); + + let j2 = json!({ + "a": { + "keys": ["a", "b", "c" ] + } + }); + + merge(&mut j1, j2); + assert_eq!( + j1, + json!({"a":{"keys":["a","b","c"],"name":"xxx","value":123}, "b": { "c" : { "inner_name": "yyy" } }}) + ); + } + + #[test] + fn test3_patch_overrides_existing_keys() { + let mut j1 = json!({ + "a": { + "name": "xxx", + "value": 123, + "keys": ["d"] + + } + }); + + let j2 = json!({ + "a": { + "keys": ["a", "b", "c" ] + } + }); + + merge(&mut j1, j2); + assert_eq!(j1, json!({"a":{"keys":["a","b","c"],"name":"xxx","value":123}})); + } + + #[test] + fn test4_patch_overrides_existing_keys() { + let mut j1 = json!({ + "a": { + "name": "xxx", + "value": 123, + "b" : { + "inner_name": "yyy" + } + } + }); + + let j2 = json!({ + "a": { + "name": "new_name", + "b" : { + "inner_name": "inner_new_name" + } + } + }); + + merge(&mut j1, j2); + assert_eq!( + j1, + json!({ "a": {"name":"new_name", "value":123, "b" : { "inner_name": "inner_new_name" }} }) + ); + } + + #[test] + fn test5_patch_overrides_existing_nested_keys() { + let mut j1 = json!({ + "a": { + "name": "xxx", + "value": 123, + "b": { + "c": { + "d": { + "name": "yyy", + "value": 256 + } + } + } + }, + }); + + let j2 = json!({ + "a": { + "value": 456, + "b": { + "c": { + "d": { + "name": "new_name" + } + } + } + } + }); + + merge(&mut j1, j2); + assert_eq!( + j1, + json!({ "a": {"name":"xxx", "value":456, "b": { "c": { "d": { "name": "new_name", "value": 256 }}}}}) + ); + } + + #[test] + fn test6_patch_removes_keys_if_null() { + let mut j1 = json!({ + "a": { + "name": "xxx", + "value": 123, + "enum_variant_1": { + "name": "yyy", + } + }, + }); + + let j2 = json!({ + "a": { + "value": 456, + "enum_variant_1": null, + "enum_variant_2": 32, + } + }); + + merge(&mut j1, j2); + assert_eq!(j1, json!({ "a": {"name":"xxx", "value":456, "enum_variant_2": 32 }})); + } +} diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index 341c5f28e4a..6a922e7b40b 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -16,38 +16,253 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Substrate chain configurations. +//! This crate includes structs and utilities for defining configuration files (known as chain +//! specification) for both runtime and node. +//! +//! # Intro: Chain Specification +//! +//! The chain specification comprises parameters and settings that define the properties and an +//! initial state of a chain. Users typically interact with the JSON representation of the chain +//! spec. Internally, the chain spec is embodied by the [`GenericChainSpec`] struct, and specific +//! properties can be accessed using the [`ChainSpec`] trait. +//! +//! In summary, although not restricted to, the primary role of the chain spec is to provide a list +//! of well-known boot nodes for the blockchain network and the means for initializing the genesis +//! storage. This initialization is necessary for creating a genesis block upon which subsequent +//! blocks are built. When the node is launched for the first time, it reads the chain spec, +//! initializes the genesis block, and establishes connections with the boot nodes. +//! +//! The JSON chain spec is divided into two main logical sections: +//! - one section details general chain properties, +//! - second explicitly or indirectly defines the genesis storage, which, in turn, determines the +//! genesis hash of the chain, +//! +//! The chain specification consists of the following fields: +//! +//!
Commits
+//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//!
Chain spec keyDescription
nameThe human readable name of the chain.
idThe id of the chain.
chainTypeThe chain type of this chain +//! (refer to +//! +//! ChainType +//! ). +//!
bootNodesA list of +//! multi addresses +//! that belong to boot nodes of the chain.
telemetryEndpointsOptional list of multi address, verbosity of telemetry endpoints. The +//! verbosity goes from 0 to 9. With 0 being the mode with the lowest verbosity.
protocolIdOptional networking protocol id that identifies the chain.
forkIdOptional fork id. Should most likely be left empty. Can be used to signal a fork on +//! the network level when two chains have the same genesis hash.
propertiesCustom properties. Shall be provided in the form of +//! key-value json object. +//!
consensusEngineDeprecated field. Should be ignored.
codeSubstitutesOptional map of block_number to wasm_code. More details in +//! material to follow.
genesisDefines the initial state of the runtime. More details in material to follow.
+//! +//! # `genesis`: Initial Runtime State +//! +//! All nodes in the network must build subsequent blocks upon exactly the same genesis block. +//! +//! The information configured in the `genesis` section of a chain specification is used to build +//! the genesis storage, which is essential for creating the genesis block, since the block header +//! includes the storage root hash. +//! +//! The `genesis` key of the chain specification definition describes the +//! initial state of the runtime. For example, it may contain: +//! - an initial list of funded accounts, +//! - the administrative account that controls the sudo key, +//! - an initial authorities set for consensus, etc. +//! +//! As the compiled WASM blob of the runtime code is stored in the chain's state, the initial +//! runtime must also be provided within the chain specification. +//! +//! In essence, the most important formats of genesis initial state are: +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//!
FormatDescription
+//! runtime / full config +//! A JSON object that provides an explicit and comprehensive representation of the +//! RuntimeGenesisConfig struct, which is generated by frame::runtime::prelude::construct_runtime macro (example of generated struct). Must contain all the keys of +//! the genesis config, no defaults will be used. +//! +//! This format explicitly provides the code of the runtime. +//!
+//! patch +//! A JSON object that offers a partial representation of the +//! RuntimeGenesisConfig provided by the runtime. It contains a patch, which is +//! essentially a list of key-value pairs to customize in the default runtime's +//! RuntimeGenesisConfig. +//! This format explicitly provides the code of the runtime. +//!
+//! raw +//! A JSON object with two fields: top and children_default. +//! Each field is a map of key => value pairs representing entries in a genesis storage +//! trie. The runtime code is one of such entries.
+//! +//! For production or long-lasting blockchains, using the `raw` format in the chain specification is +//! recommended. Only the `raw` format guarantees that storage root hash will remain unchanged when +//! the `RuntimeGenesisConfig` format changes due to software upgrade. +//! +//! JSON examples in the [following section](#json-chain-specification-example) illustrate the `raw` +//! `patch` and full genesis fields. +//! +//! # From Initial State to Raw Genesis. +//! +//! To generate a raw genesis storage from the JSON representation of the runtime genesis config, +//! the node needs to interact with the runtime. +//! +//! This interaction involves passing the runtime genesis config JSON blob to the runtime using the +//! [`sp_genesis_builder::GenesisBuilder::build_config`] function. During this operation, the +//! runtime converts the JSON representation of the genesis config into [`sp_io::storage`] items. It +//! is a crucial step for computing the storage root hash, which is a key component in determining +//! the genesis hash. +//! +//! Consequently, the runtime must support the [`sp_genesis_builder::GenesisBuilder`] API to +//! utilize either `patch` or `full` formats. +//! +//! This entire process is encapsulated within the implementation of the [`BuildStorage`] trait, +//! which can be accessed through the [`ChainSpec::as_storage_builder`] method. There is an +//! intermediate internal helper that facilitates this interaction, +//! [`GenesisConfigBuilderRuntimeCaller`], which serves as a straightforward wrapper for +//! [`sc_executor::WasmExecutor`]. +//! +//! In case of `raw` genesis state the node does not interact with the runtime regarding the +//! computation of initial state. +//! +//! The plain and `raw` chain specification JSON blobs can be found in +//! [JSON examples](#json-chain-specification-example) section. +//! +//! # Optional Code Mapping +//! +//! Optional map of `block_number` to `wasm_code`. +//! +//! The given `wasm_code` will be used to substitute the on-chain wasm code starting with the +//! given block number until the `spec_version` on-chain changes. The given `wasm_code` should +//! be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug +//! that cannot be fixed with a runtime upgrade, if for example the runtime is constantly +//! panicking. Introducing new runtime APIs isn't supported, because the node +//! will read the runtime version from the on-chain wasm code. +//! +//! Use this functionality only when there is no other way around it, and only patch the problematic +//! bug; the rest should be done with an on-chain runtime upgrade. +//! +//! # Building a Chain Specification +//! +//! The [`ChainSpecBuilder`] should be used to create an instance of a chain specification. Its API +//! allows configuration of all fields of the chain spec. To generate a JSON representation of the +//! specification, use [`ChainSpec::as_json`]. +//! +//! The sample code to generate a chain spec is as follows: +#![doc = docify::embed!("src/chain_spec.rs", build_chain_spec_with_patch_works)] +//! # JSON chain specification example +//! +//! The following are the plain and `raw` versions of the chain specification JSON files, resulting +//! from executing of the above [example](#building-a-chain-specification): +//! ```ignore +#![doc = include_str!("../res/substrate_test_runtime_from_patch.json")] +//! ``` +//! ```ignore +#![doc = include_str!("../res/substrate_test_runtime_from_patch_raw.json")] +//! ``` +//! The following example shows the plain full config version of chain spec: +//! ```ignore +#![doc = include_str!("../res/substrate_test_runtime_from_config.json")] +//! ``` +//! The [`ChainSpec`] trait represents the API to access values defined in the JSON chain specification. +//! //! -//! This crate contains structs and utilities to declare -//! a runtime-specific configuration file (a.k.a chain spec). +//! # Custom Chain Spec Extensions //! -//! Basic chain spec type containing all required parameters is -//! [`GenericChainSpec`]. It can be extended with -//! additional options that contain configuration specific to your chain. -//! Usually the extension is going to be an amalgamate of types exposed -//! by Substrate core modules. To allow the core modules to retrieve -//! their configuration from your extension you should use `ChainSpecExtension` -//! macro exposed by this crate. +//! The basic chain spec type containing all required parameters is [`GenericChainSpec`]. It can be +//! extended with additional options containing configuration specific to your chain. Usually, the +//! extension will be a combination of types exposed by Substrate core modules. //! +//! To allow the core modules to retrieve their configuration from your extension, you should use +//! `ChainSpecExtension` macro exposed by this crate. //! ```rust //! use std::collections::HashMap; //! use sc_chain_spec::{GenericChainSpec, ChainSpecExtension}; //! //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)] //! pub struct MyExtension { -//! pub known_blocks: HashMap, +//! pub known_blocks: HashMap, //! } //! //! pub type MyChainSpec = GenericChainSpec; //! ``` -//! -//! Some parameters may require different values depending on the -//! current blockchain height (a.k.a. forks). You can use `ChainSpecGroup` -//! macro and provided [`Forks`](./struct.Forks.html) structure to put -//! such parameters to your chain spec. -//! This will allow to override a single parameter starting at specific -//! block number. -//! +//! Some parameters may require different values depending on the current blockchain height (a.k.a. +//! forks). You can use the [`ChainSpecGroup`](macro@ChainSpecGroup) macro and the provided [`Forks`] +//! structure to add such parameters to your chain spec. This will allow overriding a single +//! parameter starting at a specific block number. //! ```rust //! use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec}; //! @@ -76,12 +291,9 @@ //! /// A chain spec supporting forkable `Extension`. //! pub type MyChainSpec2 = GenericChainSpec>; //! ``` -//! -//! It's also possible to have a set of parameters that is allowed to change -//! with block numbers (i.e. is forkable), and another set that is not subject to changes. -//! This is also possible by declaring an extension that contains `Forks` within it. -//! -//! +//! It's also possible to have a set of parameters that are allowed to change with block numbers +//! (i.e., they are forkable), and another set that is not subject to changes. This can also be +//! achieved by declaring an extension that contains [`Forks`] within it. //! ```rust //! use serde::{Serialize, Deserialize}; //! use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension}; @@ -106,98 +318,26 @@ //! //! pub type MyChainSpec = GenericChainSpec; //! ``` -//! -//! # Substrate chain specification format -//! -//! The Substrate chain specification is a `json` file that describes the basics of a chain. Most -//! importantly it lays out the genesis storage which leads to the genesis hash. The default -//! Substrate chain specification format is the following: -//! -//! ```json -//! // The human readable name of the chain. -//! "name": "Flaming Fir", -//! -//! // The id of the chain. -//! "id": "flamingfir9", -//! -//! // The chain type of this chain. -//! // Possible values are `Live`, `Development`, `Local`. -//! "chainType": "Live", -//! -//! // A list of multi addresses that belong to boot nodes of the chain. -//! "bootNodes": [ -//! "/dns/0.flamingfir.paritytech.net/tcp/30333/p2p/12D3KooWLK2gMLhWsYJzjW3q35zAs9FDDVqfqVfVuskiGZGRSMvR", -//! ], -//! -//! // Optional list of "multi address, verbosity" of telemetry endpoints. -//! // The verbosity goes from `0` to `9`. With `0` being the mode with the lowest verbosity. -//! "telemetryEndpoints": [ -//! [ -//! "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F", -//! 0 -//! ] -//! ], -//! -//! // Optional networking protocol id that identifies the chain. -//! "protocolId": "fir9", -//! -//! // Optional fork id. Should most likely be left empty. -//! // Can be used to signal a fork on the network level when two chains have the -//! // same genesis hash. -//! "forkId": "random_fork", -//! -//! // Custom properties. -//! "properties": { -//! "tokenDecimals": 15, -//! "tokenSymbol": "FIR" -//! }, -//! -//! // Deprecated field. Should be ignored. -//! "consensusEngine": null, -//! -//! // The genesis declaration of the chain. -//! // -//! // `runtime`, `raw`, `stateRootHash` denote the type of the genesis declaration. -//! // -//! // These declarations are in the following formats: -//! // - `runtime` is a `json` object that can be parsed by a compatible `GenesisConfig`. This -//! // `GenesisConfig` is declared by a runtime and opaque to the node. -//! // - `raw` is a `json` object with two fields `top` and `children_default`. Each of these -//! // fields is a map of `key => value`. These key/value pairs represent the genesis storage. -//! // - `stateRootHash` is a single hex encoded hash that represents the genesis hash. The hash -//! // type depends on the hash used by the chain. -//! // -//! "genesis": { "runtime": {} }, -//! -//! /// Optional map of `block_number` to `wasm_code`. -//! /// -//! /// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the -//! /// given block number until the `spec_version` on-chain changes. The given `wasm_code` should -//! /// be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug -//! /// that can not be fixed with a runtime upgrade, if for example the runtime is constantly -//! /// panicking. Introducing new runtime apis isn't supported, because the node -//! /// will read the runtime version from the on-chain wasm code. Use this functionality only when -//! /// there is no other way around it and only patch the problematic bug, the rest should be done -//! /// with a on-chain runtime upgrade. -//! "codeSubstitutes": [], -//! ``` -//! -//! See [`ChainSpec`] for a trait representation of the above. -//! //! The chain spec can be extended with other fields that are opaque to the default chain spec. //! Specific node implementations will need to be able to deserialize these extensions. mod chain_spec; mod extension; -mod genesis; +mod genesis_block; +mod genesis_config_builder; +mod json_patch; pub use self::{ - chain_spec::{ChainSpec as GenericChainSpec, NoExtension}, + chain_spec::{ + update_code_in_json_chain_spec, ChainSpec as GenericChainSpec, ChainSpecBuilder, + NoExtension, + }, extension::{get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group}, - genesis::{ + genesis_block::{ construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock, GenesisBlockBuilder, }, + genesis_config_builder::GenesisConfigBuilderRuntimeCaller, }; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; diff --git a/substrate/client/cli/src/commands/insert_key.rs b/substrate/client/cli/src/commands/insert_key.rs index 732d874319a..3d89610b28b 100644 --- a/substrate/client/cli/src/commands/insert_key.rs +++ b/substrate/client/cli/src/commands/insert_key.rs @@ -126,18 +126,14 @@ mod tests { } fn load_spec(&self, _: &str) -> std::result::Result, String> { - Ok(Box::new(GenericChainSpec::from_genesis( - "test", - "test_id", - ChainType::Development, - || unimplemented!("Not required in tests"), - Vec::new(), - None, - None, - None, - None, - NoExtension::None, - ))) + Ok(Box::new( + GenericChainSpec::<()>::builder(Default::default(), NoExtension::None) + .with_name("test") + .with_id("test_id") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(Default::default()) + .build(), + )) } } diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index 59f53200a19..1707a76cbe7 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -251,18 +251,14 @@ mod tests { trie_cache_maximum_size: None, state_pruning: None, blocks_pruning: sc_client_db::BlocksPruning::KeepAll, - chain_spec: Box::new(GenericChainSpec::from_genesis( - "test", - "test_id", - ChainType::Development, - || unimplemented!("Not required in tests"), - Vec::new(), - None, - None, - None, - None, - NoExtension::None, - )), + chain_spec: Box::new( + GenericChainSpec::<()>::builder(Default::default(), NoExtension::None) + .with_name("test") + .with_id("test_id") + .with_chain_type(ChainType::Development) + .with_genesis_config_patch(Default::default()) + .build(), + ), wasm_method: Default::default(), wasm_runtime_overrides: None, rpc_addr: None, diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index dfdacc9a8eb..0e394a11041 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -724,8 +724,6 @@ pub mod pallet { #[derive(frame_support::DefaultNoBound)] #[pallet::genesis_config] pub struct GenesisConfig { - #[serde(with = "sp_core::bytes")] - pub code: Vec, #[serde(skip)] pub _config: sp_std::marker::PhantomData, } @@ -739,7 +737,6 @@ pub mod pallet { >::put(true); >::put(true); - sp_io::storage::set(well_known_keys::CODE, &self.code); sp_io::storage::set(well_known_keys::EXTRINSIC_INDEX, &0u32.encode()); } } diff --git a/substrate/src/lib.rs b/substrate/src/lib.rs index be9eef9952f..b5a583fcfcf 100644 --- a/substrate/src/lib.rs +++ b/substrate/src/lib.rs @@ -141,8 +141,9 @@ //! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the //! modules that are provided with `FRAME`. This node and runtime is only used for testing and //! demonstration. -//! * [`chain-spec-builder`]: Utility to build more detailed chain-specs for the aforementioned -//! node. Other projects typically contain a `build-spec` subcommand that does the same. +//! * [`chain-spec-builder`]: Utility to build more detailed [chain-spec][`sc-chain-spec`] for the +//! aforementioned node. Other projects typically contain a `build-spec` subcommand that does the +//! same. //! * [`node-template`]: a template node that contains a minimal set of features and can act as a //! starting point of a project. //! * [`subkey`]: Substrate's key management utility. @@ -177,6 +178,8 @@ //! //! Additional noteworthy crates within substrate: //! +//! - Chain specification of a Substrate node: +//! - [`sc-chain-spec`] //! - RPC APIs of a Substrate node: [`sc-rpc-api`]/[`sc-rpc`] //! - CLI Options of a Substrate node: [`sc-cli`] //! - All of the consensus related crates provided by Substrate: @@ -217,6 +220,7 @@ //! [`sp-api`]: ../sp_api/index.html //! [`sp-api`]: ../sp_api/index.html //! [`sc-client-db`]: ../sc_client_db/index.html +//! [`sc-chain-spec`]: ../sc_chain_spec/index.html //! [`sc-network`]: ../sc_network/index.html //! [`sc-rpc-api`]: ../sc_rpc_api/index.html //! [`sc-rpc`]: ../sc_rpc/index.html diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 84b214a0b9c..6a1f8914444 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -48,8 +48,6 @@ sp-externalities = { path = "../../primitives/externalities", default-features = # 3rd party array-bytes = { version = "6.1", optional = true } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } -serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } [dev-dependencies] futures = "0.3.21" @@ -60,6 +58,8 @@ sp-consensus = { path = "../../primitives/consensus/common" } substrate-test-runtime-client = { path = "client" } sp-tracing = { path = "../../primitives/tracing" } json-patch = { version = "1.0.0", default-features = false } +serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } +serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } [build-dependencies] substrate-wasm-builder = { path = "../../utils/wasm-builder", optional = true } diff --git a/substrate/test-utils/runtime/src/test_json/README.md b/substrate/test-utils/runtime/res/README.md similarity index 100% rename from substrate/test-utils/runtime/src/test_json/README.md rename to substrate/test-utils/runtime/res/README.md diff --git a/substrate/test-utils/runtime/src/test_json/default_genesis_config.json b/substrate/test-utils/runtime/res/default_genesis_config.json similarity index 98% rename from substrate/test-utils/runtime/src/test_json/default_genesis_config.json rename to substrate/test-utils/runtime/res/default_genesis_config.json index b0218d417da..95c7799a033 100644 --- a/substrate/test-utils/runtime/src/test_json/default_genesis_config.json +++ b/substrate/test-utils/runtime/res/default_genesis_config.json @@ -1,7 +1,5 @@ { - "system": { - "code": "0x52" - }, + "system": {}, "babe": { "authorities": [ [ diff --git a/substrate/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json b/substrate/test-utils/runtime/res/default_genesis_config_incomplete.json similarity index 98% rename from substrate/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json rename to substrate/test-utils/runtime/res/default_genesis_config_incomplete.json index e25730ee11c..510ed87c93c 100644 --- a/substrate/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json +++ b/substrate/test-utils/runtime/res/default_genesis_config_incomplete.json @@ -1,7 +1,5 @@ { - "system": { - "code": "0x52" - }, + "system": {}, "babe": { "epochConfig": { "c": [ diff --git a/substrate/test-utils/runtime/src/test_json/default_genesis_config_invalid.json b/substrate/test-utils/runtime/res/default_genesis_config_invalid.json similarity index 98% rename from substrate/test-utils/runtime/src/test_json/default_genesis_config_invalid.json rename to substrate/test-utils/runtime/res/default_genesis_config_invalid.json index 00550efaeec..f8e06f91d66 100644 --- a/substrate/test-utils/runtime/src/test_json/default_genesis_config_invalid.json +++ b/substrate/test-utils/runtime/res/default_genesis_config_invalid.json @@ -1,7 +1,5 @@ { - "system": { - "code": "0x52" - }, + "system": {}, "babe": { "renamed_authorities": [ [ diff --git a/substrate/test-utils/runtime/res/default_genesis_config_invalid_2.json b/substrate/test-utils/runtime/res/default_genesis_config_invalid_2.json new file mode 100644 index 00000000000..a1345542bcd --- /dev/null +++ b/substrate/test-utils/runtime/res/default_genesis_config_invalid_2.json @@ -0,0 +1,113 @@ +{ + "system": {}, + "babex": { + "authorities": [ + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1 + ] + ], + "epochConfig": { + "c": [ + 3, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" + ] + }, + "balances": { + "balances": [ + [ + "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH", + 100000000000000000 + ], + [ + "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o", + 100000000000000000 + ], + [ + "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9", + 100000000000000000 + ], + [ + "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK", + 100000000000000000 + ], + [ + "5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW", + 100000000000000000 + ], + [ + "5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR", + 100000000000000000 + ], + [ + "5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY", + 100000000000000000 + ], + [ + "5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ", + 100000000000000000 + ], + [ + "5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX", + 100000000000000000 + ], + [ + "5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q", + 100000000000000000 + ], + [ + "5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz", + 100000000000000000 + ], + [ + "5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf", + 100000000000000000 + ], + [ + "5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz", + 100000000000000000 + ], + [ + "5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC", + 100000000000000000 + ], + [ + "5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51", + 100000000000000000 + ], + [ + "5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e", + 100000000000000000 + ], + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 100000000000000000 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 100000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 100000000000000000 + ] + ] + } +} diff --git a/substrate/test-utils/runtime/src/genesismap.rs b/substrate/test-utils/runtime/src/genesismap.rs index 8a4d6dbe4a7..5ed9c8a6458 100644 --- a/substrate/test-utils/runtime/src/genesismap.rs +++ b/substrate/test-utils/runtime/src/genesismap.rs @@ -117,10 +117,7 @@ impl GenesisStorageBuilder { .collect(); RuntimeGenesisConfig { - system: frame_system::GenesisConfig { - code: self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()), - ..Default::default() - }, + system: Default::default(), babe: pallet_babe::GenesisConfig { authorities: authorities_sr25519 .clone() @@ -149,6 +146,11 @@ impl GenesisStorageBuilder { storage.top.insert(well_known_keys::HEAP_PAGES.into(), heap_pages.encode()); } + storage.top.insert( + well_known_keys::CODE.into(), + self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()), + ); + storage.top.extend(self.extra_storage.top.clone()); storage.children_default.extend(self.extra_storage.children_default.clone()); diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 6b963deb589..1a4e9fd0466 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -464,11 +464,10 @@ impl_opaque_keys! { } } -pub(crate) const TEST_RUNTIME_BABE_EPOCH_CONFIGURATION: BabeEpochConfiguration = - BabeEpochConfiguration { - c: (3, 10), - allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, - }; +pub const TEST_RUNTIME_BABE_EPOCH_CONFIGURATION: BabeEpochConfiguration = BabeEpochConfiguration { + c: (3, 10), + allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, +}; impl_runtime_apis! { impl sp_api::Core for Runtime { @@ -1237,7 +1236,7 @@ mod tests { #[test] fn build_minimal_genesis_config_works() { sp_tracing::try_init_simple(); - let default_minimal_json = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":{"c": [ 3, 10 ],"allowed_slots":"PrimaryAndSecondaryPlainSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + let default_minimal_json = r#"{"system":{},"babe":{"authorities":[],"epochConfig":{"c": [ 3, 10 ],"allowed_slots":"PrimaryAndSecondaryPlainSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; let mut t = BasicExternalities::new_empty(); executor_call(&mut t, "GenesisBuilder_build_config", &default_minimal_json.encode()) @@ -1264,8 +1263,6 @@ mod tests { // System|LastRuntimeUpgrade "26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8", - // :code - "3a636f6465", // :extrinsic_index "3a65787472696e7369635f696e646578", // Balances|TotalIssuance @@ -1294,35 +1291,55 @@ mod tests { let r = Vec::::decode(&mut &r[..]).unwrap(); let json = String::from_utf8(r.into()).expect("returned value is json. qed."); - let expected = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; assert_eq!(expected.to_string(), json); } #[test] fn build_config_from_json_works() { sp_tracing::try_init_simple(); - let j = include_str!("test_json/default_genesis_config.json"); + let j = include_str!("../res/default_genesis_config.json"); let mut t = BasicExternalities::new_empty(); let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); let r = BuildResult::decode(&mut &r[..]); assert!(r.is_ok()); - let keys = t.into_storages().top.keys().cloned().map(hex).collect::>(); + let mut keys = t.into_storages().top.keys().cloned().map(hex).collect::>(); + + // following keys are not placed during `::build` + // process, add them `keys` to assert against known keys. + keys.push(hex(b":code")); + keys.sort(); + assert_eq!(keys, storage_key_generator::get_expected_storage_hashed_keys(false)); } #[test] fn build_config_from_invalid_json_fails() { sp_tracing::try_init_simple(); - let j = include_str!("test_json/default_genesis_config_invalid.json"); + let j = include_str!("../res/default_genesis_config_invalid.json"); let mut t = BasicExternalities::new_empty(); let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); let r = BuildResult::decode(&mut &r[..]).unwrap(); log::info!("result: {:#?}", r); assert_eq!(r, Err( sp_runtime::RuntimeString::Owned( - "Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 6 column 25".to_string(), + "Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 4 column 25".to_string(), + )) + ); + } + + #[test] + fn build_config_from_invalid_json_fails_2() { + sp_tracing::try_init_simple(); + let j = include_str!("../res/default_genesis_config_invalid_2.json"); + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); + let r = BuildResult::decode(&mut &r[..]).unwrap(); + assert_eq!(r, Err( + sp_runtime::RuntimeString::Owned( + "Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 3 column 9".to_string(), )) ); } @@ -1330,7 +1347,7 @@ mod tests { #[test] fn build_config_from_incomplete_json_fails() { sp_tracing::try_init_simple(); - let j = include_str!("test_json/default_genesis_config_incomplete.json"); + let j = include_str!("../res/default_genesis_config_incomplete.json"); let mut t = BasicExternalities::new_empty(); let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); @@ -1339,7 +1356,7 @@ mod tests { assert_eq!( r, Err(sp_runtime::RuntimeString::Owned( - "Invalid JSON blob: missing field `authorities` at line 13 column 3" + "Invalid JSON blob: missing field `authorities` at line 11 column 3" .to_string() )) ); @@ -1438,10 +1455,6 @@ mod tests { ); assert_eq!(u64::decode(&mut &value[..]).unwrap(), 0); - // :code - let value: Vec = get_from_storage("3a636f6465"); - assert!(Vec::::decode(&mut &value[..]).is_err()); - //System|ParentHash let value: Vec = get_from_storage( "26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", -- GitLab From 15beef20fe96a6b5480b659a23d9ddcf82c6f8ba Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sun, 5 Nov 2023 22:47:18 +0100 Subject: [PATCH 444/633] Fix update-ui-tests.sh (#2161) Related https://github.com/paritytech/polkadot-sdk/issues/2013 Signed-off-by: Oliver Tale-Yazdi --- scripts/update-ui-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh index 785cc7bd329..02c1eec8c4b 100755 --- a/scripts/update-ui-tests.sh +++ b/scripts/update-ui-tests.sh @@ -34,7 +34,7 @@ export SKIP_WASM_BUILD=1 export TRYBUILD=overwrite # ./substrate -$RUSTUP_RUN cargo test -p sp-runtime-interface ui +$RUSTUP_RUN cargo test --manifest-path substrate/primitives/runtime-interface/Cargo.toml 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 -- GitLab From f6ee4781f633f0f89598f7b230595afe401da8dc Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sun, 5 Nov 2023 23:35:40 +0100 Subject: [PATCH 445/633] [CI] Update deps (#2159) Otherwise the return code is not correctly propagated (ref https://github.com/ggwpez/zepter/pull/48). --------- Signed-off-by: Oliver Tale-Yazdi --- .gitlab/pipeline/check.yml | 2 +- .../parachains/runtimes/assets/asset-hub-rococo/Cargo.toml | 7 ++++++- .../runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml | 5 +++++ .../parachains/runtimes/glutton/glutton-kusama/Cargo.toml | 1 + substrate/frame/bags-list/Cargo.toml | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index ce3a6155792..cbb3baf277c 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -87,7 +87,7 @@ check-rust-feature-propagation: - .kubernetes-env - .common-refs script: - - cargo install --locked --version 0.13.2 -q -f zepter && zepter --version + - cargo install --locked --version 0.13.3 -q -f zepter && zepter --version - zepter run check # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 0b163ae1a20..f4f33677d4a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -109,9 +109,11 @@ default = [ "std" ] state-trie-version-1 = [ "pallet-state-trie-migration" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -121,6 +123,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", @@ -156,6 +159,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-nft-fractionalization/try-runtime", "pallet-nfts/try-runtime", @@ -178,8 +182,8 @@ std = [ "bp-asset-hub-westend/std", "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", - "bp-bridge-hub-wococo/std", "bp-bridge-hub-westend/std", + "bp-bridge-hub-wococo/std", "codec/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", @@ -204,6 +208,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-nft-fractionalization/std", "pallet-nfts-runtime-api/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index c4461a0d4c3..7e384126ab6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -138,6 +138,7 @@ std = [ "pallet-bridge-parachains/std", "pallet-bridge-relayers/std", "pallet-collator-selection/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -176,9 +177,11 @@ std = [ runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -190,6 +193,7 @@ runtime-benchmarks = [ "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -221,6 +225,7 @@ try-runtime = [ "pallet-bridge-parachains/try-runtime", "pallet-bridge-relayers/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index efae74049a7..7f5feb1c880 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -95,6 +95,7 @@ std = [ "pallet-timestamp/std", "parachain-info/std", "parachains-common/std", + "scale-info/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index b99726ebf2d..cb07ef94ff5 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -50,7 +50,7 @@ frame-election-provider-support = { path = "../election-provider-support" } frame-benchmarking = { path = "../benchmarking" } [features] -default = ["std"] +default = [ "std" ] std = [ "codec/std", "frame-benchmarking?/std", -- GitLab From 7b06e634fe749508b639e50cccbeb58ce794323c Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 6 Nov 2023 12:42:48 +0200 Subject: [PATCH 446/633] Get rid of `NetworkService` in `ChainSync` (#2143) Move peer banning from `ChainSync` to `SyncingEngine`. --- substrate/bin/minimal/runtime/Cargo.toml | 2 + .../client/network/sync/src/chain_sync.rs | 324 +++++++++--------- .../network/sync/src/chain_sync/test.rs | 111 +----- substrate/client/network/sync/src/engine.rs | 38 +- 4 files changed, 197 insertions(+), 278 deletions(-) diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index 08feb445879..b75816a5ea3 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -28,6 +28,7 @@ substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true [features] default = [ "std" ] std = [ + "frame-support/std", "frame/std", "pallet-balances/std", "pallet-sudo/std", @@ -36,5 +37,6 @@ std = [ "pallet-transaction-payment/std", "parity-scale-codec/std", "scale-info/std", + "sp-genesis-builder/std", "substrate-wasm-builder", ] diff --git a/substrate/client/network/sync/src/chain_sync.rs b/substrate/client/network/sync/src/chain_sync.rs index 5721bd59a84..858125f93f1 100644 --- a/substrate/client/network/sync/src/chain_sync.rs +++ b/substrate/client/network/sync/src/chain_sync.rs @@ -32,7 +32,6 @@ use crate::{ blocks::BlockCollection, extra_requests::ExtraRequests, schema::v1::StateResponse, - service::network::NetworkServiceHandle, state::{ImportResult, StateSync}, types::{ BadPeer, Metrics, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, SyncMode, SyncState, @@ -50,7 +49,6 @@ use log::{debug, error, info, trace, warn}; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; -use sc_network::types::ProtocolName; use sc_network_common::sync::message::{ BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, }; @@ -212,7 +210,7 @@ pub struct ImportJustificationsAction { /// Result of [`ChainSync::on_block_data`]. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockData { +enum OnBlockData { /// The block should be imported. Import(ImportBlocksAction), /// A new block request needs to be made to the given peer. @@ -223,7 +221,7 @@ pub enum OnBlockData { /// Result of [`ChainSync::on_block_justification`]. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockJustification { +enum OnBlockJustification { /// The justification needs no further handling. Nothing, /// The justification should be imported. @@ -237,7 +235,7 @@ pub enum OnBlockJustification { // Result of [`ChainSync::on_state_data`]. #[derive(Debug)] -pub enum OnStateData { +enum OnStateData { /// The block and state that should be imported. Import(BlockOrigin, IncomingBlock), /// A new state request needs to be made to the given peer. @@ -247,7 +245,7 @@ pub enum OnStateData { /// Action that the parent of [`ChainSync`] should perform after reporting block response with /// [`ChainSync::on_block_response`]. pub enum OnBlockResponse { - /// Nothing to do + /// Nothing to do. Nothing, /// Perform block request. SendBlockRequest { peer_id: PeerId, request: BlockRequest }, @@ -255,6 +253,19 @@ pub enum OnBlockResponse { ImportBlocks(ImportBlocksAction), /// Import justifications. ImportJustifications(ImportJustificationsAction), + /// Invalid block response, the peer should be disconnected and reported. + DisconnectPeer(BadPeer), +} + +/// Action that the parent of [`ChainSync`] should perform after reporting state response with +/// [`ChainSync::on_state_response`]. +pub enum OnStateResponse { + /// Nothing to do. + Nothing, + /// Import blocks. + ImportBlocks(ImportBlocksAction), + /// Invalid state response, the peer should be disconnected and reported. + DisconnectPeer(BadPeer), } /// The main data structure which contains all the state for a chains @@ -302,10 +313,6 @@ pub struct ChainSync { import_existing: bool, /// Gap download process. gap_sync: Option>, - /// Handle for communicating with `NetworkService` - network_service: NetworkServiceHandle, - /// Protocol name used for block announcements - block_announce_protocol_name: ProtocolName, } /// All the data we have about a Peer that we are trying to sync with @@ -396,11 +403,9 @@ where pub fn new( mode: SyncMode, client: Arc, - block_announce_protocol_name: ProtocolName, max_parallel_downloads: u32, max_blocks_per_request: u32, warp_sync_config: Option>, - network_service: NetworkServiceHandle, ) -> Result { let mut sync = Self { client, @@ -420,10 +425,8 @@ where warp_sync: None, import_existing: false, gap_sync: None, - network_service, warp_sync_config, warp_sync_target_block_header: None, - block_announce_protocol_name, }; sync.reset_sync_start_point()?; @@ -431,9 +434,9 @@ where } /// Get peer's best hash & number. - pub fn peer_info(&self, who: &PeerId) -> Option> { + pub fn peer_info(&self, peer_id: &PeerId) -> Option> { self.peers - .get(who) + .get(peer_id) .map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) } @@ -509,7 +512,7 @@ where #[must_use] pub fn new_peer( &mut self, - who: PeerId, + peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor, ) -> Result>, BadPeer> { @@ -517,19 +520,21 @@ where match self.block_status(&best_hash) { Err(e) => { debug!(target:LOG_TARGET, "Error reading blockchain: {e}"); - Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) + Err(BadPeer(peer_id, rep::BLOCKCHAIN_READ_ERROR)) }, Ok(BlockStatus::KnownBad) => { - info!("💔 New peer {who} with known bad best block {best_hash} ({best_number})."); - Err(BadPeer(who, rep::BAD_BLOCK)) + info!( + "💔 New peer {peer_id} with known bad best block {best_hash} ({best_number})." + ); + Err(BadPeer(peer_id, rep::BAD_BLOCK)) }, Ok(BlockStatus::Unknown) => { if best_number.is_zero() { info!( "💔 New peer {} with unknown genesis hash {} ({}).", - who, best_hash, best_number, + peer_id, best_hash, best_number, ); - return Err(BadPeer(who, rep::GENESIS_MISMATCH)) + return Err(BadPeer(peer_id, rep::GENESIS_MISMATCH)) } // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have @@ -539,14 +544,14 @@ where debug!( target:LOG_TARGET, "New peer {} with unknown best hash {} ({}), assuming common block.", - who, + peer_id, self.best_queued_hash, self.best_queued_number ); self.peers.insert( - who, + peer_id, PeerSync { - peer_id: who, + peer_id, common_number: self.best_queued_number, best_hash, best_number, @@ -560,7 +565,7 @@ where let (state, req) = if self.best_queued_number.is_zero() { debug!( target:LOG_TARGET, - "New peer {who} with best hash {best_hash} ({best_number}).", + "New peer {peer_id} with best hash {best_hash} ({best_number}).", ); (PeerSyncState::Available, None) @@ -570,7 +575,7 @@ where debug!( target:LOG_TARGET, "New peer {} with unknown best hash {} ({}), searching for common ancestor.", - who, + peer_id, best_hash, best_number ); @@ -585,11 +590,11 @@ where ) }; - self.allowed_requests.add(&who); + self.allowed_requests.add(&peer_id); self.peers.insert( - who, + peer_id, PeerSync { - peer_id: who, + peer_id, common_number: Zero::zero(), best_hash, best_number, @@ -618,19 +623,19 @@ where Ok(BlockStatus::InChainPruned) => { debug!( target: LOG_TARGET, - "New peer {who} with known best hash {best_hash} ({best_number}).", + "New peer {peer_id} with known best hash {best_hash} ({best_number}).", ); self.peers.insert( - who, + peer_id, PeerSync { - peer_id: who, + peer_id, common_number: std::cmp::min(self.best_queued_number, best_number), best_hash, best_number, state: PeerSyncState::Available, }, ); - self.allowed_requests.add(&who); + self.allowed_requests.add(&peer_id); Ok(None) }, } @@ -717,41 +722,41 @@ where /// Submit a block response for processing. #[must_use] - pub fn on_block_data( + fn on_block_data( &mut self, - who: &PeerId, + peer_id: &PeerId, request: Option>, response: BlockResponse, ) -> Result, BadPeer> { self.downloaded_blocks += response.blocks.len(); let mut gap = false; - let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { + let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(peer_id) { let mut blocks = response.blocks; if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) { trace!(target: LOG_TARGET, "Reversing incoming block list"); blocks.reverse() } - self.allowed_requests.add(who); + self.allowed_requests.add(peer_id); if let Some(request) = request { match &mut peer.state { PeerSyncState::DownloadingNew(_) => { - self.blocks.clear_peer_download(who); + self.blocks.clear_peer_download(peer_id); peer.state = PeerSyncState::Available; if let Some(start_block) = - validate_blocks::(&blocks, who, Some(request))? + validate_blocks::(&blocks, peer_id, Some(request))? { - self.blocks.insert(start_block, blocks, *who); + self.blocks.insert(start_block, blocks, *peer_id); } self.ready_blocks() }, PeerSyncState::DownloadingGap(_) => { peer.state = PeerSyncState::Available; if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_peer_download(who); + gap_sync.blocks.clear_peer_download(peer_id); if let Some(start_block) = - validate_blocks::(&blocks, who, Some(request))? + validate_blocks::(&blocks, peer_id, Some(request))? { - gap_sync.blocks.insert(start_block, blocks, *who); + gap_sync.blocks.insert(start_block, blocks, *peer_id); } gap = true; let blocks: Vec<_> = gap_sync @@ -787,17 +792,17 @@ where ); blocks } else { - debug!(target: LOG_TARGET, "Unexpected gap block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) + debug!(target: LOG_TARGET, "Unexpected gap block response from {peer_id}"); + return Err(BadPeer(*peer_id, rep::NO_BLOCK)) } }, PeerSyncState::DownloadingStale(_) => { peer.state = PeerSyncState::Available; if blocks.is_empty() { - debug!(target: LOG_TARGET, "Empty block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) + debug!(target: LOG_TARGET, "Empty block response from {peer_id}"); + return Err(BadPeer(*peer_id, rep::NO_BLOCK)) } - validate_blocks::(&blocks, who, Some(request))?; + validate_blocks::(&blocks, peer_id, Some(request))?; blocks .into_iter() .map(|b| { @@ -810,7 +815,7 @@ where body: b.body, indexed_body: None, justifications, - origin: Some(*who), + origin: Some(*peer_id), allow_missing_state: true, import_existing: self.import_existing, skip_execution: self.skip_execution(), @@ -827,23 +832,23 @@ where "Got ancestry block #{} ({}) from peer {}", current, block.hash, - who, + peer_id, ); maybe_our_block_hash.filter(|x| x == &block.hash) }, (None, _) => { debug!( target: LOG_TARGET, - "Invalid response when searching for ancestor from {who}", + "Invalid response when searching for ancestor from {peer_id}", ); - return Err(BadPeer(*who, rep::UNKNOWN_ANCESTOR)) + return Err(BadPeer(*peer_id, rep::UNKNOWN_ANCESTOR)) }, (_, Err(e)) => { info!( target: LOG_TARGET, "❌ Error answering legitimate blockchain query: {e}", ); - return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR)) + return Err(BadPeer(*peer_id, rep::BLOCKCHAIN_READ_ERROR)) }, }; if matching_hash.is_some() { @@ -856,7 +861,7 @@ where trace!( target: LOG_TARGET, "Ancestry search: opportunistically updating peer {} common number from={} => to={}.", - *who, + *peer_id, peer.common_number, self.best_queued_number, ); @@ -865,7 +870,7 @@ where trace!( target: LOG_TARGET, "Ancestry search: updating peer {} common number from={} => to={}.", - *who, + *peer_id, peer.common_number, *current, ); @@ -875,9 +880,9 @@ where if matching_hash.is_none() && current.is_zero() { trace!( target:LOG_TARGET, - "Ancestry search: genesis mismatch for peer {who}", + "Ancestry search: genesis mismatch for peer {peer_id}", ); - return Err(BadPeer(*who, rep::GENESIS_MISMATCH)) + return Err(BadPeer(*peer_id, rep::GENESIS_MISMATCH)) } if let Some((next_state, next_num)) = handle_ancestor_search_state(state, *current, matching_hash.is_some()) @@ -887,7 +892,10 @@ where start: *start, state: next_state, }; - return Ok(OnBlockData::Request(*who, ancestry_request::(next_num))) + return Ok(OnBlockData::Request( + *peer_id, + ancestry_request::(next_num), + )) } else { // Ancestry search is complete. Check if peer is on a stale fork unknown // to us and add it to sync targets if necessary. @@ -908,7 +916,7 @@ where target: LOG_TARGET, "Added fork target {} for {}", peer.best_hash, - who, + peer_id, ); self.fork_targets .entry(peer.best_hash) @@ -918,7 +926,7 @@ where peers: Default::default(), }) .peers - .insert(*who); + .insert(*peer_id); } peer.state = PeerSyncState::Available; Vec::new() @@ -928,32 +936,32 @@ where peer.state = PeerSyncState::Available; if let Some(warp_sync) = &mut self.warp_sync { if blocks.len() == 1 { - validate_blocks::(&blocks, who, Some(request))?; + validate_blocks::(&blocks, peer_id, Some(request))?; match warp_sync.import_target_block( blocks.pop().expect("`blocks` len checked above."), ) { warp::TargetBlockImportResult::Success => return Ok(OnBlockData::Continue), warp::TargetBlockImportResult::BadResponse => - return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), + return Err(BadPeer(*peer_id, rep::VERIFICATION_FAIL)), } } else if blocks.is_empty() { - debug!(target: LOG_TARGET, "Empty block response from {who}"); - return Err(BadPeer(*who, rep::NO_BLOCK)) + debug!(target: LOG_TARGET, "Empty block response from {peer_id}"); + return Err(BadPeer(*peer_id, rep::NO_BLOCK)) } else { debug!( target: LOG_TARGET, "Too many blocks ({}) in warp target block response from {}", blocks.len(), - who, + peer_id, ); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) } } else { debug!( target: LOG_TARGET, "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", - who, + peer_id, ); return Ok(OnBlockData::Continue) } @@ -965,7 +973,7 @@ where } } else { // When request.is_none() this is a block announcement. Just accept blocks. - validate_blocks::(&blocks, who, None)?; + validate_blocks::(&blocks, peer_id, None)?; blocks .into_iter() .map(|b| { @@ -978,7 +986,7 @@ where body: b.body, indexed_body: None, justifications, - origin: Some(*who), + origin: Some(*peer_id), allow_missing_state: true, import_existing: false, skip_execution: true, @@ -989,7 +997,7 @@ where } } else { // We don't know of this peer, so we also did not request anything from it. - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) }; Ok(OnBlockData::Import(self.validate_and_queue_blocks(new_blocks, gap))) @@ -997,12 +1005,12 @@ where /// Submit a justification response for processing. #[must_use] - pub fn on_block_justification( + fn on_block_justification( &mut self, - who: PeerId, + peer_id: PeerId, response: BlockResponse, ) -> Result, BadPeer> { - let peer = if let Some(peer) = self.peers.get_mut(&who) { + let peer = if let Some(peer) = self.peers.get_mut(&peer_id) { peer } else { error!( @@ -1012,7 +1020,7 @@ where return Ok(OnBlockJustification::Nothing) }; - self.allowed_requests.add(&who); + self.allowed_requests.add(&peer_id); if let PeerSyncState::DownloadingJustification(hash) = peer.state { peer.state = PeerSyncState::Available; @@ -1022,11 +1030,11 @@ where warn!( target: LOG_TARGET, "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", - who, + peer_id, hash, block.hash, ); - return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) + return Err(BadPeer(peer_id, rep::BAD_JUSTIFICATION)) } block @@ -1037,14 +1045,14 @@ where // had but didn't (regardless of whether it had a justification for it or not). trace!( target: LOG_TARGET, - "Peer {who:?} provided empty response for justification request {hash:?}", + "Peer {peer_id:?} provided empty response for justification request {hash:?}", ); None }; if let Some((peer_id, hash, number, justifications)) = - self.extra_justifications.on_response(who, justification) + self.extra_justifications.on_response(peer_id, justification) { return Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) } @@ -1105,7 +1113,7 @@ where pub fn on_validated_block_announce( &mut self, is_best: bool, - who: PeerId, + peer_id: PeerId, announce: &BlockAnnounce, ) { let number = *announce.header.number(); @@ -1116,7 +1124,7 @@ where let ancient_parent = parent_status == BlockStatus::InChainPruned; let known = self.is_known(&hash); - let peer = if let Some(peer) = self.peers.get_mut(&who) { + let peer = if let Some(peer) = self.peers.get_mut(&peer_id) { peer } else { error!(target: LOG_TARGET, "💔 Called `on_validated_block_announce` with a bad peer ID"); @@ -1124,7 +1132,7 @@ where }; if let PeerSyncState::AncestorSearch { .. } = peer.state { - trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", who); + trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", peer_id); return } @@ -1138,20 +1146,20 @@ where // is either one further ahead or it's the one they just announced, if we know about it. if is_best { if known && self.best_queued_number >= number { - self.update_peer_common_number(&who, number); + self.update_peer_common_number(&peer_id, number); } else if announce.header.parent_hash() == &self.best_queued_hash || known_parent && self.best_queued_number >= number { - self.update_peer_common_number(&who, number.saturating_sub(One::one())); + self.update_peer_common_number(&peer_id, number.saturating_sub(One::one())); } } - self.allowed_requests.add(&who); + self.allowed_requests.add(&peer_id); // known block case if known || self.is_already_downloading(&hash) { - trace!(target: "sync", "Known block announce from {}: {}", who, hash); + trace!(target: "sync", "Known block announce from {}: {}", peer_id, hash); if let Some(target) = self.fork_targets.get_mut(&hash) { - target.peers.insert(who); + target.peers.insert(peer_id); } return } @@ -1160,7 +1168,7 @@ where trace!( target: "sync", "Ignored ancient block announced from {}: {} {:?}", - who, + peer_id, hash, announce.header, ); @@ -1171,7 +1179,7 @@ where trace!( target: "sync", "Added sync target for block announced from {}: {} {:?}", - who, + peer_id, hash, announce.summary(), ); @@ -1183,22 +1191,22 @@ where peers: Default::default(), }) .peers - .insert(who); + .insert(peer_id); } } /// Notify that a sync peer has disconnected. #[must_use] - pub fn peer_disconnected(&mut self, who: &PeerId) -> Option> { - self.blocks.clear_peer_download(who); + pub fn peer_disconnected(&mut self, peer_id: &PeerId) -> Option> { + self.blocks.clear_peer_download(peer_id); if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_peer_download(who) + gap_sync.blocks.clear_peer_download(peer_id) } - self.peers.remove(who); - self.extra_justifications.peer_disconnected(who); + self.peers.remove(peer_id); + self.extra_justifications.peer_disconnected(peer_id); self.allowed_requests.set_all(); self.fork_targets.retain(|_, target| { - target.peers.remove(who); + target.peers.remove(peer_id); !target.peers.is_empty() }); @@ -1565,12 +1573,7 @@ where 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); - OnBlockResponse::Nothing - }, + Err(bad_peer) => OnBlockResponse::DisconnectPeer(bad_peer), } } else { match self.on_block_data(&peer_id, Some(request), block_response) { @@ -1578,12 +1581,7 @@ where 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); - OnBlockResponse::Nothing - }, + Err(bad_peer) => OnBlockResponse::DisconnectPeer(bad_peer), } } } @@ -1594,26 +1592,12 @@ where &mut self, peer_id: PeerId, response: OpaqueStateResponse, - ) -> Option> { + ) -> OnStateResponse { match self.on_state_data(&peer_id, response) { Ok(OnStateData::Import(origin, block)) => - Some(ImportBlocksAction { origin, blocks: vec![block] }), - Ok(OnStateData::Continue) => None, - Err(BadPeer(id, repu)) => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(id, repu); - None - }, - } - } - - /// Submit a warp proof response received. - pub fn on_warp_sync_response(&mut self, peer_id: PeerId, response: EncodedProof) { - if let Err(BadPeer(id, repu)) = self.on_warp_sync_data(&peer_id, response) { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(id, repu); + OnStateResponse::ImportBlocks(ImportBlocksAction { origin, blocks: vec![block] }), + Ok(OnStateData::Continue) => OnStateResponse::Nothing, + Err(bad_peer) => OnStateResponse::DisconnectPeer(bad_peer), } } @@ -1851,7 +1835,7 @@ where fn on_state_data( &mut self, - who: &PeerId, + peer_id: &PeerId, response: OpaqueStateResponse, ) -> Result, BadPeer> { let response: Box = response.0.downcast().map_err(|_error| { @@ -1860,10 +1844,10 @@ where "Failed to downcast opaque state response, this is an implementation bug." ); - BadPeer(*who, rep::BAD_RESPONSE) + BadPeer(*peer_id, rep::BAD_RESPONSE) })?; - if let Some(peer) = self.peers.get_mut(who) { + if let Some(peer) = self.peers.get_mut(peer_id) { if let PeerSyncState::DownloadingState = peer.state { peer.state = PeerSyncState::Available; self.allowed_requests.set_all(); @@ -1873,7 +1857,7 @@ where debug!( target: LOG_TARGET, "Importing state data from {} with {} keys, {} proof nodes.", - who, + peer_id, response.entries.len(), response.proof.len(), ); @@ -1882,14 +1866,14 @@ where debug!( target: LOG_TARGET, "Importing state data from {} with {} keys, {} proof nodes.", - who, + peer_id, response.entries.len(), response.proof.len(), ); sync.import_state(*response) } else { - debug!(target: LOG_TARGET, "Ignored obsolete state response from {who}"); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + debug!(target: LOG_TARGET, "Ignored obsolete state response from {peer_id}"); + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) }; match import_result { @@ -1912,14 +1896,20 @@ where }, ImportResult::Continue => Ok(OnStateData::Continue), ImportResult::BadResponse => { - debug!(target: LOG_TARGET, "Bad state data received from {who}"); - Err(BadPeer(*who, rep::BAD_BLOCK)) + debug!(target: LOG_TARGET, "Bad state data received from {peer_id}"); + Err(BadPeer(*peer_id, rep::BAD_BLOCK)) }, } } - fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { - if let Some(peer) = self.peers.get_mut(who) { + /// Submit a warp proof response received. + #[must_use] + pub fn on_warp_sync_response( + &mut self, + peer_id: &PeerId, + response: EncodedProof, + ) -> Result<(), BadPeer> { + if let Some(peer) = self.peers.get_mut(peer_id) { if let PeerSyncState::DownloadingWarpProof = peer.state { peer.state = PeerSyncState::Available; self.allowed_requests.set_all(); @@ -1929,20 +1919,20 @@ where debug!( target: LOG_TARGET, "Importing warp proof data from {}, {} bytes.", - who, + peer_id, response.0.len(), ); sync.import_warp_proof(response) } else { - debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {who}"); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {peer_id}"); + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) }; match import_result { WarpProofImportResult::Success => Ok(()), WarpProofImportResult::BadResponse => { - debug!(target: LOG_TARGET, "Bad proof data received from {who}"); - Err(BadPeer(*who, rep::BAD_BLOCK)) + debug!(target: LOG_TARGET, "Bad proof data received from {peer_id}"); + Err(BadPeer(*peer_id, rep::BAD_BLOCK)) }, } } @@ -1979,11 +1969,11 @@ where has_error |= result.is_err(); match result { - Ok(BlockImportStatus::ImportedKnown(number, who)) => - if let Some(peer) = who { + Ok(BlockImportStatus::ImportedKnown(number, peer_id)) => + if let Some(peer) = peer_id { self.update_peer_common_number(&peer, number); }, - Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { + Ok(BlockImportStatus::ImportedUnknown(number, aux, peer_id)) => { if aux.clear_justification_requests { trace!( target: LOG_TARGET, @@ -2001,13 +1991,13 @@ where } if aux.bad_justification { - if let Some(ref peer) = who { + if let Some(ref peer) = peer_id { warn!("💔 Sent block with bad justification to import"); output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); } } - if let Some(peer) = who { + if let Some(peer) = peer_id { self.update_peer_common_number(&peer, number); } let state_sync_complete = @@ -2046,8 +2036,8 @@ where self.gap_sync = None; } }, - Err(BlockImportError::IncompleteHeader(who)) => - if let Some(peer) = who { + Err(BlockImportError::IncompleteHeader(peer_id)) => + if let Some(peer) = peer_id { warn!( target: LOG_TARGET, "💔 Peer sent block with incomplete header to import", @@ -2055,23 +2045,23 @@ where output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); output.extend(self.restart()); }, - Err(BlockImportError::VerificationFailed(who, e)) => { - let extra_message = - who.map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); + Err(BlockImportError::VerificationFailed(peer_id, e)) => { + let extra_message = peer_id + .map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); warn!( target: LOG_TARGET, "💔 Verification failed for block {hash:?}{extra_message}: {e:?}", ); - if let Some(peer) = who { + if let Some(peer) = peer_id { output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); } output.extend(self.restart()); }, - Err(BlockImportError::BadBlock(who)) => - if let Some(peer) = who { + Err(BlockImportError::BadBlock(peer_id)) => + if let Some(peer) = peer_id { warn!( target: LOG_TARGET, "💔 Block {hash:?} received from peer {peer} has been blacklisted", @@ -2365,7 +2355,7 @@ where /// It is expected that `blocks` are in ascending order. fn validate_blocks( blocks: &Vec>, - who: &PeerId, + peer_id: &PeerId, request: Option>, ) -> Result>, BadPeer> { if let Some(request) = request { @@ -2373,12 +2363,12 @@ fn validate_blocks( debug!( target: LOG_TARGET, "Received more blocks than requested from {}. Expected in maximum {:?}, got {}.", - who, + peer_id, request.max, blocks.len(), ); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) } let block_header = @@ -2398,7 +2388,7 @@ fn validate_blocks( block_header, ); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) + return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) } if request.fields.contains(BlockAttributes::HEADER) && @@ -2406,20 +2396,20 @@ fn validate_blocks( { trace!( target: LOG_TARGET, - "Missing requested header for a block in response from {who}.", + "Missing requested header for a block in response from {peer_id}.", ); - return Err(BadPeer(*who, rep::BAD_RESPONSE)) + return Err(BadPeer(*peer_id, rep::BAD_RESPONSE)) } if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none()) { trace!( target: LOG_TARGET, - "Missing requested body for a block in response from {who}.", + "Missing requested body for a block in response from {peer_id}.", ); - return Err(BadPeer(*who, rep::BAD_RESPONSE)) + return Err(BadPeer(*peer_id, rep::BAD_RESPONSE)) } } @@ -2430,11 +2420,11 @@ fn validate_blocks( debug!( target:LOG_TARGET, "Bad header received from {}. Expected hash {:?}, got {:?}", - who, + peer_id, b.hash, hash, ); - return Err(BadPeer(*who, rep::BAD_BLOCK)) + return Err(BadPeer(*peer_id, rep::BAD_BLOCK)) } } if let (Some(header), Some(body)) = (&b.header, &b.body) { @@ -2448,11 +2438,11 @@ fn validate_blocks( target:LOG_TARGET, "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", b.hash, - who, + peer_id, expected, got, ); - return Err(BadPeer(*who, rep::BAD_BLOCK)) + return Err(BadPeer(*peer_id, rep::BAD_BLOCK)) } } } diff --git a/substrate/client/network/sync/src/chain_sync/test.rs b/substrate/client/network/sync/src/chain_sync/test.rs index de908f0449c..2eefd2ad13e 100644 --- a/substrate/client/network/sync/src/chain_sync/test.rs +++ b/substrate/client/network/sync/src/chain_sync/test.rs @@ -19,7 +19,6 @@ //! Tests of [`ChainSync`]. use super::*; -use crate::service::network::NetworkServiceProvider; use futures::executor::block_on; use sc_block_builder::BlockBuilderBuilder; use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; @@ -39,17 +38,7 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { let client = Arc::new(TestClientBuilder::new().build()); let peer_id = PeerId::random(); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 1, 64, None).unwrap(); let (a1_hash, a1_number) = { let a1 = BlockBuilderBuilder::new(&*client) @@ -103,18 +92,8 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 1, 64, None).unwrap(); let peer_id1 = PeerId::random(); let peer_id2 = PeerId::random(); @@ -291,19 +270,9 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { }; let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let info = client.info(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 5, 64, None).unwrap(); let peer_id1 = PeerId::random(); let peer_id2 = PeerId::random(); @@ -417,7 +386,6 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { fn can_sync_huge_fork() { sp_tracing::try_init_simple(); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) .map(|_| build_block(&mut client, None, false)) @@ -442,16 +410,7 @@ fn can_sync_huge_fork() { let info = client.info(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 5, 64, None).unwrap(); let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); @@ -545,7 +504,6 @@ fn can_sync_huge_fork() { fn syncs_fork_without_duplicate_requests() { sp_tracing::try_init_simple(); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) .map(|_| build_block(&mut client, None, false)) @@ -570,16 +528,7 @@ fn syncs_fork_without_duplicate_requests() { let info = client.info(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 5, 64, None).unwrap(); let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); @@ -696,20 +645,10 @@ fn syncs_fork_without_duplicate_requests() { #[test] fn removes_target_fork_on_disconnect() { sp_tracing::try_init_simple(); - 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( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 1, 64, None).unwrap(); let peer_id1 = PeerId::random(); let common_block = blocks[1].clone(); @@ -730,22 +669,12 @@ fn removes_target_fork_on_disconnect() { #[test] fn can_import_response_with_missing_blocks() { sp_tracing::try_init_simple(); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client2 = Arc::new(TestClientBuilder::new().build()); let blocks = (0..4).map(|_| build_block(&mut client2, None, false)).collect::>(); let empty_client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( - SyncMode::Full, - empty_client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, empty_client.clone(), 1, 64, None).unwrap(); let peer_id1 = PeerId::random(); let best_block = blocks[3].clone(); @@ -777,17 +706,7 @@ fn ancestor_search_repeat() { #[test] fn sync_restart_removes_block_but_not_justification_requests() { let mut client = Arc::new(TestClientBuilder::new().build()); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 1, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 1, 64, None).unwrap(); let peers = vec![PeerId::random(), PeerId::random()]; @@ -889,7 +808,6 @@ fn sync_restart_removes_block_but_not_justification_requests() { fn request_across_forks() { sp_tracing::try_init_simple(); - let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..100).map(|_| build_block(&mut client, None, false)).collect::>(); @@ -925,16 +843,7 @@ fn request_across_forks() { fork_blocks }; - let mut sync = ChainSync::new( - SyncMode::Full, - client.clone(), - ProtocolName::from("test-block-announce-protocol"), - 5, - 64, - None, - chain_sync_network_handle, - ) - .unwrap(); + let mut sync = ChainSync::new(SyncMode::Full, client.clone(), 5, 64, None).unwrap(); // Add the peers, all at the common ancestor 100. let common_block = blocks.last().unwrap(); diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 02a0dc2e915..560887132e3 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -27,7 +27,7 @@ use crate::{ block_request_handler::MAX_BLOCKS_IN_RESPONSE, chain_sync::{ BlockRequestAction, ChainSync, ImportBlocksAction, ImportJustificationsAction, - OnBlockResponse, + OnBlockResponse, OnStateResponse, }, pending_responses::{PendingResponses, ResponseEvent}, schema::v1::{StateRequest, StateResponse}, @@ -455,11 +455,9 @@ where let chain_sync = ChainSync::new( mode, client.clone(), - block_announce_protocol_name.clone(), max_parallel_downloads, max_blocks_per_request, warp_sync_config, - network_service.clone(), )?; let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); @@ -917,7 +915,7 @@ where /// Called by peer when it is disconnecting. /// /// Returns a result if the handshake of this peer was indeed accepted. - pub fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) -> Result<(), ()> { + fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) -> Result<(), ()> { if let Some(info) = self.peers.remove(&peer_id) { if self.important_peers.contains(&peer_id) { log::warn!(target: LOG_TARGET, "Reserved peer {peer_id} disconnected"); @@ -961,7 +959,7 @@ where /// /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync /// from. - pub fn on_sync_peer_connected( + fn on_sync_peer_connected( &mut self, peer_id: PeerId, status: &BlockAnnouncesHandshake, @@ -1212,6 +1210,13 @@ where OnBlockResponse::ImportJustifications(action) => self.import_justifications(action), OnBlockResponse::Nothing => {}, + OnBlockResponse::DisconnectPeer(BadPeer(peer_id, rep)) => { + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + self.network_service.report_peer(peer_id, rep); + }, } }, Err(BlockResponseError::DecodeFailed(e)) => { @@ -1257,14 +1262,27 @@ where }, }; - if let Some(import_blocks_action) = - self.chain_sync.on_state_response(peer_id, response) - { - self.import_blocks(import_blocks_action); + match self.chain_sync.on_state_response(peer_id, response) { + OnStateResponse::ImportBlocks(import_blocks_action) => + self.import_blocks(import_blocks_action), + OnStateResponse::DisconnectPeer(BadPeer(peer_id, rep)) => { + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + self.network_service.report_peer(peer_id, rep); + }, + OnStateResponse::Nothing => {}, } }, PeerRequest::WarpProof => { - self.chain_sync.on_warp_sync_response(peer_id, EncodedProof(resp)); + if let Err(BadPeer(peer_id, rep)) = + self.chain_sync.on_warp_sync_response(&peer_id, EncodedProof(resp)) + { + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(peer_id, rep); + } }, }, Ok(Err(e)) => { -- GitLab From 305aefc43d14eb06c32c6f49d6c576a6751afbe5 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:00:06 +0100 Subject: [PATCH 447/633] `serde_json`: bumped to 1.0.108 (#2168) This PR updates the version of `serde_json` to `1.0.108` throughout the codebase. --- Cargo.lock | 8 ++++---- cumulus/client/relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- .../integration-tests/emulated/common/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 2 +- polkadot/node/zombienet-backchannel/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- substrate/bin/minimal/node/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node-template/runtime/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 2 +- substrate/bin/node/executor/Cargo.toml | 2 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/consensus/babe/rpc/Cargo.toml | 2 +- substrate/client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/grandpa/Cargo.toml | 2 +- substrate/client/keystore/Cargo.toml | 2 +- substrate/client/merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-servers/Cargo.toml | 2 +- substrate/client/rpc-spec-v2/Cargo.toml | 2 +- substrate/client/rpc/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/transaction-pool/api/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/transaction-payment/Cargo.toml | 2 +- .../frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- substrate/primitives/consensus/sassafras/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/genesis-builder/Cargo.toml | 2 +- substrate/primitives/rpc/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- substrate/utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../utils/frame/rpc/state-trie-migration-rpc/Cargo.toml | 2 +- substrate/utils/frame/try-runtime/cli/Cargo.toml | 2 +- 52 files changed, 55 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b4496368ee..1a4c532f9c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1470,8 +1470,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -16459,9 +16459,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 102ce75508d..9e5a8f1eccb 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -33,7 +33,7 @@ jsonrpsee = { version = "0.16.2", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" -serde_json = "1.0.107" +serde_json = "1.0.108" serde = "1.0.188" schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 2a08395008f..73bbbb6d771 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.28" -serde_json = "1.0.104" +serde_json = "1.0.108" # Local parachain-template-runtime = { path = "../runtime" } diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 4182fea5274..6688c80eb9a 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -10,7 +10,7 @@ publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } paste = "1.0.14" -serde_json = "1.0.104" +serde_json = "1.0.108" # Substrate grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/client/consensus/grandpa" } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index c7a79e3e97a..f7252a39a38 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.20" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 5d73ba83d52..ed8c8748cc8 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -17,7 +17,7 @@ criterion = { version = "0.5.1", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" tokio = { version = "1.32.0", features = ["macros"] } tracing = "0.1.37" url = "2.4.0" diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 3429f4e0a3a..41b86f2151e 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -82,7 +82,7 @@ gum = { package = "tracing-gum", path = "../gum" } log = "0.4.17" schnellru = "0.2.1" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0.48" kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 6c13e45a566..437fa66b75a 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -11,7 +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" +serde_json = "1.0.108" tempfile = "3.2.0" tokio = "1.24.2" diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 9bf56b550bb..c1b08b4a2bb 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -19,4 +19,4 @@ reqwest = { version = "0.11", features = ["rustls-tls"], default-features = fals thiserror = "1.0.48" gum = { package = "tracing-gum", path = "../gum" } serde = { version = "1.0", features = ["derive"] } -serde_json = "1" +serde_json = "1.0.108" diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 18332156d99..a6642f9c9c7 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -64,7 +64,7 @@ pallet-babe = { path = "../../../substrate/frame/babe" } pallet-treasury = { path = "../../../substrate/frame/treasury" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.107" +serde_json = "1.0.108" libsecp256k1 = "0.7.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index e49c00459de..004a0545d55 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -62,7 +62,7 @@ test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../pri sp-tracing = { path = "../../../substrate/primitives/tracing" } thousands = "0.2.0" assert_matches = "1" -serde_json = "1.0.107" +serde_json = "1.0.108" [features] default = [ "std" ] diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 135e5e94056..9693d351cf4 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -108,7 +108,7 @@ keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyrin remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } sp-trie = { path = "../../../substrate/primitives/trie" } separator = "0.4.1" -serde_json = "1.0.107" +serde_json = "1.0.108" sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index db014a5d864..29debad7b53 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -71,7 +71,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.107" +serde_json = "1.0.108" [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 4148d610591..eaebf01e3a7 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -116,7 +116,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.107" +serde_json = "1.0.108" 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 } diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 39d39d7e312..0506d0838f1 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -21,7 +21,7 @@ clap = { version = "4.0.9", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.16.2", features = ["server"] } -serde_json = "1.0.107" +serde_json = "1.0.108" sc-cli = { path = "../../../client/cli" } sc-executor = { path = "../../../client/executor" } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 4e87675514d..61953631d79 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -19,7 +19,7 @@ name = "node-template" [dependencies] clap = { version = "4.4.6", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} -serde_json = "1.0.85" +serde_json = "1.0.108" sc-cli = { path = "../../../client/cli" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 0008c82a49d..7711ddba34d 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -39,7 +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, features = ["serde"] } -serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } # Used for the node template's RPCs diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index c111d345623..ee429ee8c0c 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -22,7 +22,7 @@ sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" kvdb-rocksdb = "0.19.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 01c532ad20d..5e7ffebaa8e 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -108,7 +108,7 @@ sc-cli = { path = "../../../client/cli", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} -serde_json = "1.0.107" +serde_json = "1.0.108" [dev-dependencies] sc-keystore = { path = "../../../client/keystore" } diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml index 12280a9ba1d..595a313d2cb 100644 --- a/substrate/bin/node/executor/Cargo.toml +++ b/substrate/bin/node/executor/Cargo.toml @@ -47,7 +47,7 @@ sp-consensus-babe = { path = "../../../primitives/consensus/babe" } sp-externalities = { path = "../../../primitives/externalities" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } -serde_json = "1.0.85" +serde_json = "1.0.108" [features] stress-test = [] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 85d3971e492..836f90e7654 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } static_assertions = "1.1.0" log = { version = "0.4.17", default-features = false } -serde_json = { version = "1.0.85", default-features = false, features = ["alloc", "arbitrary_precision"] } +serde_json = { version = "1.0.108", default-features = false, features = ["alloc", "arbitrary_precision"] } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "num-traits"] } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 5c7e21abeab..0b373b8e924 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -28,7 +28,7 @@ log = "0.4.17" node-cli = { package = "staging-node-cli", path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } sc-keystore = { path = "../../../client/keystore" } -serde_json = "1.0.100" +serde_json = "1.0.108" sp-core = { path = "../../../primitives/core" } sp-keystore = { path = "../../../primitives/keystore" } sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index b11088190d1..5b7cdda8ebe 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } memmap2 = "0.5.0" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } sc-executor = { path = "../executor" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 5a98b43f43c..c415527c372 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -27,7 +27,7 @@ rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0.48" bip39 = "2.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index f54edb29684..c95d95ae427 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -30,7 +30,7 @@ sp-keystore = { path = "../../../../primitives/keystore" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" tokio = "1.22.0" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 74733ea9edd..c7464fdc653 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -23,7 +23,7 @@ sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" sc-rpc = { path = "../../../rpc", features = ["test-helpers"]} substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 921b9c539e3..85f98e7546e 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -25,7 +25,7 @@ log = "0.4.17" parity-scale-codec = { version = "3.6.1", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0" fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index 6303ff5c27e..3fd88ae8b87 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" parking_lot = "0.12.1" -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0" sp-application-crypto = { path = "../../primitives/application-crypto" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 05d8547d243..e75c5f1baa8 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -23,4 +23,4 @@ sp-runtime = { path = "../../../primitives/runtime" } anyhow = "1" [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 8b188176fc5..7b0536addda 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -34,7 +34,7 @@ partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" smallvec = "1.11.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index e07bdf0d15a..e72bbe48ee3 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } sc-mixnet = { path = "../mixnet" } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 674a8db39cb..a7cc374f97a 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" -serde_json = "1.0.107" +serde_json = "1.0.108" tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } tower-http = { version = "0.4.0", features = ["cors"] } diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 1eaed65706e..cfe7f8a117d 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -37,7 +37,7 @@ array-bytes = "6.1" log = "0.4.17" futures-util = { version = "0.3.19", default-features = false } [dev-dependencies] -serde_json = "1.0" +serde_json = "1.0.108" tokio = { version = "1.22.0", features = ["macros"] } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index dd1120e5b0f..1cedcb3a6d0 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" parking_lot = "0.12.1" -serde_json = "1.0.107" +serde_json = "1.0.108" sc-block-builder = { path = "../block-builder" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index e5520eb21c3..de69c50702a 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -35,7 +35,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-trie = { path = "../../primitives/trie" } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index e582d0b7e4f..569cd067f27 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0.48" sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 86f4d217dd9..86f03050c44 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -22,7 +22,7 @@ rand_pcg = "0.3.1" derive_more = "0.99" regex = "1" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 6d59b9dfc1a..a693a2884b5 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0.48" wasm-timer = "0.2.5" diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index 5ff5a4149ca..f5760c271ad 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -20,4 +20,4 @@ sp-core = { path = "../../../primitives/core", default-features = false} sp-runtime = { path = "../../../primitives/runtime", default-features = false} [dev-dependencies] -serde_json = "1.0" +serde_json = "1.0.108" diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 82942c3a4f1..f8c8edc0510 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -42,7 +42,7 @@ sp-core-hashing-proc-macro = { path = "../../primitives/core/hashing/proc-macro" k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features=false} -serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } docify = "0.2.6" static_assertions = "1.1.0" diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index e3a2965e2a0..ad384755614 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" pallet-balances = { path = "../balances" } [features] diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 2b1ee52692c..ae236728cd5 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.188", optional = true } [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" sp-storage = { path = "../../../primitives/storage", default-features = false} diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 03fdd4439cb..696e0a64596 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.163", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0.188", default-features = false, features = ["derive"], optional = true } 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" } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index fe0905c3bed..79df81e62c6 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -62,7 +62,7 @@ bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "cbc342e", [dev-dependencies] criterion = "0.4.0" -serde_json = "1.0" +serde_json = "1.0.108" sp-core-hashing-proc-macro = { path = "hashing/proc-macro" } [[bench]] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 8f083e2d7d5..cf7ce995711 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { path = "../api", default-features = false} sp-runtime = { path = "../runtime", default-features = false} sp-std = { path = "../std", default-features = false} -serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } [features] default = [ "std" ] diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index 4739c96740e..77bdcc4f89a 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ serde = { version = "1.0.188", features = ["derive"] } sp-core = { path = "../core" } [dev-dependencies] -serde_json = "1.0.107" +serde_json = "1.0.108" diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index fcd1779fb5a..bf6cf93c5f0 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-weights = { path = "../weights", default-features = false} [dev-dependencies] rand = "0.8.5" -serde_json = "1.0.107" +serde_json = "1.0.108" zstd = { version = "0.12.4", default-features = false } sp-api = { path = "../api" } sp-state-machine = { path = "../state-machine" } diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 12863ac184c..032fbaf4e65 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ "test-helpers", diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 6a1f8914444..2f1e192eded 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -59,7 +59,7 @@ substrate-test-runtime-client = { path = "client" } sp-tracing = { path = "../../primitives/tracing" } json-patch = { version = "1.0.0", default-features = false } serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } -serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } [build-dependencies] substrate-wasm-builder = { path = "../../utils/wasm-builder", optional = true } diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index e32fe47b729..b67d08a85c2 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ log = "0.4.17" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" thiserror = "1.0.48" thousands = "0.2.0" frame-benchmarking = { path = "../../../frame/benchmarking" } diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 8ce9d06c2d1..d25e6ec67c9 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -29,4 +29,4 @@ sc-rpc-api = { path = "../../../../client/rpc-api" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1" +serde_json = "1.0.108" diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 65380a22ce6..6be4306193c 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -40,7 +40,7 @@ hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.108" zstd = { version = "0.12.4", default-features = false } [dev-dependencies] -- GitLab From fb2dc6df8d01ef472be30e27960fa02d6a90e906 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:28:29 +0200 Subject: [PATCH 448/633] Add warning when peer_id is not available when building topology (#2140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... see https://github.com/paritytech/polkadot-sdk/issues/2138 for why is not good, until we fix it let's add a warning to understand if this is happening in the wild. --------- Signed-off-by: Alexandru Gheorghe Co-authored-by: Bastian Köcher --- polkadot/node/network/bridge/src/rx/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 7e86b46a7e0..f64410c1353 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -551,6 +551,15 @@ where let mut peers = Vec::with_capacity(neighbors.len()); for (discovery_id, validator_index) in neighbors { let addr = get_peer_id_by_authority_id(ads, discovery_id.clone()).await; + if addr.is_none() { + // See on why is not good in https://github.com/paritytech/polkadot-sdk/issues/2138 + gum::debug!( + target: LOG_TARGET, + ?validator_index, + "Could not determine peer_id for validator, let the team know in \n + https://github.com/paritytech/polkadot-sdk/issues/2138" + ) + } peers.push(TopologyPeerInfo { peer_ids: addr.into_iter().collect(), validator_index, -- GitLab From 318e5969c72de5339210f5f9edd5d4be85bcde70 Mon Sep 17 00:00:00 2001 From: Richard Melkonian <35300528+0xmovses@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:44:53 +0000 Subject: [PATCH 449/633] Add force remove vesting (#1982) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR exposes a `force_remove_vesting` through a ROOT call. See linked [issue](https://github.com/paritytech/polkadot-sdk/issues/269) --------- Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Dónal Murray --- .../rococo/src/weights/pallet_vesting.rs | 29 +- .../westend/src/weights/pallet_vesting.rs | 24 + substrate/frame/vesting/src/benchmarking.rs | 27 + substrate/frame/vesting/src/lib.rs | 30 ++ substrate/frame/vesting/src/tests.rs | 36 ++ substrate/frame/vesting/src/weights.rs | 510 ++++++++++-------- 6 files changed, 415 insertions(+), 241 deletions(-) diff --git a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs index fd820f1aea3..2596207d583 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs @@ -187,16 +187,29 @@ impl pallet_vesting::WeightInfo for WeightInfo { .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(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `378 + l * (25 ±0) + s * (36 ±0)` diff --git a/polkadot/runtime/westend/src/weights/pallet_vesting.rs b/polkadot/runtime/westend/src/weights/pallet_vesting.rs index 4ccd524ffc2..dfd87d1c550 100644 --- a/polkadot/runtime/westend/src/weights/pallet_vesting.rs +++ b/polkadot/runtime/westend/src/weights/pallet_vesting.rs @@ -238,4 +238,28 @@ impl pallet_vesting::WeightInfo for WeightInfo { .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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. + fn force_remove_vesting_schedule(l: u32, s: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } diff --git a/substrate/frame/vesting/src/benchmarking.rs b/substrate/frame/vesting/src/benchmarking.rs index 4af48f5d368..34aa04607ad 100644 --- a/substrate/frame/vesting/src/benchmarking.rs +++ b/substrate/frame/vesting/src/benchmarking.rs @@ -383,6 +383,33 @@ benchmarks! { ); } +force_remove_vesting_schedule { + let l in 0 .. MaxLocksOf::::get() - 1; + let s in 2 .. T::MAX_VESTING_SCHEDULES; + + let source: T::AccountId = account("source", 0, SEED); + let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); + + let target: T::AccountId = account("target", 0, SEED); + let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + + // Give target existing locks. + add_locks::(&target, l as u8); + let _ = add_vesting_schedules::(target_lookup.clone(), s)?; + + // The last vesting schedule. + let schedule_index = s - 1; + }: _(RawOrigin::Root, target_lookup, schedule_index) + verify { + assert_eq!( + Vesting::::vesting(&target).unwrap().len(), + schedule_index as usize, + "Schedule count should reduce by 1" + ); + } + impl_benchmark_test_suite!( Vesting, crate::mock::ExtBuilder::default().existential_deposit(256).build(), diff --git a/substrate/frame/vesting/src/lib.rs b/substrate/frame/vesting/src/lib.rs index ee67a038e4d..dbad7926a30 100644 --- a/substrate/frame/vesting/src/lib.rs +++ b/substrate/frame/vesting/src/lib.rs @@ -427,6 +427,36 @@ pub mod pallet { Ok(()) } + + /// Force remove a vesting schedule + /// + /// The dispatch origin for this call must be _Root_. + /// + /// - `target`: An account that has a vesting schedule + /// - `schedule_index`: The vesting schedule index that should be removed + #[pallet::call_index(5)] + #[pallet::weight( + T::WeightInfo::force_remove_vesting_schedule(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) + )] + pub fn force_remove_vesting_schedule( + origin: OriginFor, + target: ::Source, + schedule_index: u32, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let who = T::Lookup::lookup(target)?; + + let schedules_count = Vesting::::decode_len(&who).unwrap_or_default(); + ensure!(schedule_index < schedules_count as u32, Error::::InvalidScheduleParams); + + Self::remove_vesting_schedule(&who, schedule_index)?; + + Ok(Some(T::WeightInfo::force_remove_vesting_schedule( + MaxLocksOf::::get(), + schedules_count as u32, + )) + .into()) + } } } diff --git a/substrate/frame/vesting/src/tests.rs b/substrate/frame/vesting/src/tests.rs index c35686bd514..2e1e41fc957 100644 --- a/substrate/frame/vesting/src/tests.rs +++ b/substrate/frame/vesting/src/tests.rs @@ -1155,3 +1155,39 @@ fn vested_transfer_less_than_existential_deposit_fails() { ); }); } + +#[test] +fn remove_vesting_schedule() { + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + assert_eq!(Balances::free_balance(&3), 256 * 30); + assert_eq!(Balances::free_balance(&4), 256 * 40); + // Account 4 should not have any vesting yet. + assert_eq!(Vesting::vesting(&4), None); + // Make the schedule for the new transfer. + let new_vesting_schedule = VestingInfo::new( + ED * 5, + (ED * 5) / 20, // Vesting over 20 blocks + 10, + ); + assert_ok!(Vesting::vested_transfer(Some(3).into(), 4, new_vesting_schedule)); + // Now account 4 should have vesting. + assert_eq!(Vesting::vesting(&4).unwrap(), vec![new_vesting_schedule]); + // Account 4 has 5 * 256 locked. + assert_eq!(Vesting::vesting_balance(&4), Some(256 * 5)); + // Verify only root can call. + assert_noop!(Vesting::force_remove_vesting_schedule(Some(4).into(), 4, 0), BadOrigin); + // Verify that root can remove the schedule. + assert_ok!(Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0)); + // Verify that last event is VestingCompleted. + System::assert_last_event(Event::VestingCompleted { account: 4 }.into()); + // Appropriate storage is cleaned up. + assert!(!>::contains_key(4)); + // Check the vesting balance is zero. + assert_eq!(Vesting::vesting(&4), None); + // Verifies that trying to remove a schedule when it doesnt exist throws error. + assert_noop!( + Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0), + Error::::InvalidScheduleParams + ); + }); +} diff --git a/substrate/frame/vesting/src/weights.rs b/substrate/frame/vesting/src/weights.rs index 17bde888577..ddc7db8fa61 100644 --- a/substrate/frame/vesting/src/weights.rs +++ b/substrate/frame/vesting/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_vesting +//! Autogenerated weights for `pallet_vesting` //! //! 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-10-29, 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-vmdtonbz-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_vesting -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/vesting/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_vesting +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/vesting/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_vesting. +/// Weight functions needed for `pallet_vesting`. pub trait WeightInfo { fn vest_locked(l: u32, s: u32, ) -> Weight; fn vest_unlocked(l: u32, s: u32, ) -> Weight; @@ -60,372 +57,419 @@ pub trait WeightInfo { fn force_vested_transfer(l: u32, s: u32, ) -> Weight; fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight; fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight; + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight; } -/// Weights for pallet_vesting using the Substrate node and recommended hardware. +/// Weights for `pallet_vesting` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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: `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(67), added: 2542, 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: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_336_000 picoseconds. - Weight::from_parts(34_290_169, 4764) - // Standard Error: 1_381 - .saturating_add(Weight::from_parts(76_354, 0).saturating_mul(l.into())) - // Standard Error: 2_457 - .saturating_add(Weight::from_parts(81_362, 0).saturating_mul(s.into())) + // Minimum execution time: 32_846_000 picoseconds. + Weight::from_parts(30_974_459, 4764) + // Standard Error: 1_755 + .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) + // Standard Error: 3_123 + .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// 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: `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(67), added: 2542, 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: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_540_000 picoseconds. - Weight::from_parts(38_893_820, 4764) - // Standard Error: 1_710 - .saturating_add(Weight::from_parts(62_106, 0).saturating_mul(l.into())) - // Standard Error: 3_043 - .saturating_add(Weight::from_parts(41_966, 0).saturating_mul(s.into())) + // Minimum execution time: 34_360_000 picoseconds. + Weight::from_parts(34_964_080, 4764) + // Standard Error: 1_996 + .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) + // Standard Error: 3_552 + .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// 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: `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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_529_000 picoseconds. - Weight::from_parts(36_781_151, 4764) - // Standard Error: 1_490 - .saturating_add(Weight::from_parts(76_322, 0).saturating_mul(l.into())) - // Standard Error: 2_652 - .saturating_add(Weight::from_parts(76_914, 0).saturating_mul(s.into())) + // Minimum execution time: 33_859_000 picoseconds. + Weight::from_parts(32_950_681, 4764) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) + // Standard Error: 3_105 + .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 41_217_000 picoseconds. - Weight::from_parts(40_942_515, 4764) - // Standard Error: 2_098 - .saturating_add(Weight::from_parts(65_213, 0).saturating_mul(l.into())) - // Standard Error: 3_733 - .saturating_add(Weight::from_parts(63_326, 0).saturating_mul(s.into())) + // Minimum execution time: 36_239_000 picoseconds. + Weight::from_parts(36_459_756, 4764) + // Standard Error: 2_051 + .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) + // Standard Error: 3_650 + .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, 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: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 76_396_000 picoseconds. - Weight::from_parts(77_085_336, 4764) - // Standard Error: 2_795 - .saturating_add(Weight::from_parts(88_995, 0).saturating_mul(l.into())) - // Standard Error: 4_974 - .saturating_add(Weight::from_parts(135_384, 0).saturating_mul(s.into())) + // Minimum execution time: 70_330_000 picoseconds. + Weight::from_parts(71_196_328, 4764) + // Standard Error: 2_923 + .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) + // Standard Error: 5_201 + .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, 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: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 77_312_000 picoseconds. - Weight::from_parts(79_600_900, 6196) - // Standard Error: 3_232 - .saturating_add(Weight::from_parts(78_018, 0).saturating_mul(l.into())) - // Standard Error: 5_750 - .saturating_add(Weight::from_parts(100_848, 0).saturating_mul(s.into())) + // Minimum execution time: 70_235_000 picoseconds. + Weight::from_parts(71_960_020, 6196) + // Standard Error: 2_493 + .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) + // Standard Error: 4_436 + .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_769_000 picoseconds. - Weight::from_parts(37_752_437, 4764) - // Standard Error: 1_415 - .saturating_add(Weight::from_parts(78_398, 0).saturating_mul(l.into())) - // Standard Error: 2_614 - .saturating_add(Weight::from_parts(78_922, 0).saturating_mul(s.into())) + // Minimum execution time: 34_352_000 picoseconds. + Weight::from_parts(33_697_027, 4764) + // Standard Error: 2_008 + .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) + // Standard Error: 3_710 + .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 43_021_000 picoseconds. - Weight::from_parts(42_182_858, 4764) - // Standard Error: 1_747 - .saturating_add(Weight::from_parts(83_938, 0).saturating_mul(l.into())) - // Standard Error: 3_227 - .saturating_add(Weight::from_parts(84_652, 0).saturating_mul(s.into())) + // Minimum execution time: 37_467_000 picoseconds. + Weight::from_parts(36_866_847, 4764) + // Standard Error: 1_692 + .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) + // Standard Error: 3_124 + .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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: `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(67), added: 2542, 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: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_336_000 picoseconds. - Weight::from_parts(34_290_169, 4764) - // Standard Error: 1_381 - .saturating_add(Weight::from_parts(76_354, 0).saturating_mul(l.into())) - // Standard Error: 2_457 - .saturating_add(Weight::from_parts(81_362, 0).saturating_mul(s.into())) + // Minimum execution time: 32_846_000 picoseconds. + Weight::from_parts(30_974_459, 4764) + // Standard Error: 1_755 + .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) + // Standard Error: 3_123 + .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// 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: `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(67), added: 2542, 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: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_540_000 picoseconds. - Weight::from_parts(38_893_820, 4764) - // Standard Error: 1_710 - .saturating_add(Weight::from_parts(62_106, 0).saturating_mul(l.into())) - // Standard Error: 3_043 - .saturating_add(Weight::from_parts(41_966, 0).saturating_mul(s.into())) + // Minimum execution time: 34_360_000 picoseconds. + Weight::from_parts(34_964_080, 4764) + // Standard Error: 1_996 + .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) + // Standard Error: 3_552 + .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// 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: `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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_529_000 picoseconds. - Weight::from_parts(36_781_151, 4764) - // Standard Error: 1_490 - .saturating_add(Weight::from_parts(76_322, 0).saturating_mul(l.into())) - // Standard Error: 2_652 - .saturating_add(Weight::from_parts(76_914, 0).saturating_mul(s.into())) + // Minimum execution time: 33_859_000 picoseconds. + Weight::from_parts(32_950_681, 4764) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) + // Standard Error: 3_105 + .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 41_217_000 picoseconds. - Weight::from_parts(40_942_515, 4764) - // Standard Error: 2_098 - .saturating_add(Weight::from_parts(65_213, 0).saturating_mul(l.into())) - // Standard Error: 3_733 - .saturating_add(Weight::from_parts(63_326, 0).saturating_mul(s.into())) + // Minimum execution time: 36_239_000 picoseconds. + Weight::from_parts(36_459_756, 4764) + // Standard Error: 2_051 + .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) + // Standard Error: 3_650 + .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, 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: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 76_396_000 picoseconds. - Weight::from_parts(77_085_336, 4764) - // Standard Error: 2_795 - .saturating_add(Weight::from_parts(88_995, 0).saturating_mul(l.into())) - // Standard Error: 4_974 - .saturating_add(Weight::from_parts(135_384, 0).saturating_mul(s.into())) + // Minimum execution time: 70_330_000 picoseconds. + Weight::from_parts(71_196_328, 4764) + // Standard Error: 2_923 + .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) + // Standard Error: 5_201 + .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, 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: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 77_312_000 picoseconds. - Weight::from_parts(79_600_900, 6196) - // Standard Error: 3_232 - .saturating_add(Weight::from_parts(78_018, 0).saturating_mul(l.into())) - // Standard Error: 5_750 - .saturating_add(Weight::from_parts(100_848, 0).saturating_mul(s.into())) + // Minimum execution time: 70_235_000 picoseconds. + Weight::from_parts(71_960_020, 6196) + // Standard Error: 2_493 + .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) + // Standard Error: 4_436 + .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_769_000 picoseconds. - Weight::from_parts(37_752_437, 4764) - // Standard Error: 1_415 - .saturating_add(Weight::from_parts(78_398, 0).saturating_mul(l.into())) - // Standard Error: 2_614 - .saturating_add(Weight::from_parts(78_922, 0).saturating_mul(s.into())) + // Minimum execution time: 34_352_000 picoseconds. + Weight::from_parts(33_697_027, 4764) + // Standard Error: 2_008 + .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) + // Standard Error: 3_710 + .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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) + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 43_021_000 picoseconds. - Weight::from_parts(42_182_858, 4764) - // Standard Error: 1_747 - .saturating_add(Weight::from_parts(83_938, 0).saturating_mul(l.into())) - // Standard Error: 3_227 - .saturating_add(Weight::from_parts(84_652, 0).saturating_mul(s.into())) + // Minimum execution time: 37_467_000 picoseconds. + Weight::from_parts(36_866_847, 4764) + // Standard Error: 1_692 + .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) + // Standard Error: 3_124 + .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } -- GitLab From 4ac9c4a36419439eb3c7288eade40e67c2af28ff Mon Sep 17 00:00:00 2001 From: Richard Melkonian <35300528+0xmovses@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:54:37 +0000 Subject: [PATCH 450/633] rename benchmark (#2173) A quick fix where a benchmark test was wrongly renamed in this PR https://github.com/paritytech/polkadot-sdk/pull/1868 --- substrate/frame/alliance/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 77294c6b664..37cc3314037 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -782,7 +782,7 @@ mod benchmarks { } #[benchmark] - fn add_scrupulous_items( + fn add_unscrupulous_items( n: Linear<0, { T::MaxUnscrupulousItems::get() }>, l: Linear<0, { T::MaxWebsiteUrlLength::get() }>, ) -> Result<(), BenchmarkError> { -- GitLab From 0570b6fa9e605258623ec55851111534d21d2f8a Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:21:32 +0200 Subject: [PATCH 451/633] approval-voting improvement: include all tranche0 assignments in one certificate (#1178) **_PR migrated from https://github.com/paritytech/polkadot/pull/6782_** This PR will upgrade the network protocol to version 3 -> VStaging which will later be renamed to V3. This version introduces a new kind of assignment certificate that will be used for tranche0 assignments. Instead of issuing/importing one tranche0 assignment per candidate, there will be just one certificate per relay chain block per validator. However, we will not be sending out the new assignment certificates, yet. So everything should work exactly as before. Once the majority of the validators have been upgraded to the new protocol version we will enable the new certificates (starting at a specific relay chain block) with a new client update. There are still a few things that need to be done: - [x] Use bitfield instead of Vec: https://github.com/paritytech/polkadot/pull/6802 - [x] Fix existing approval-distribution and approval-voting tests - [x] Fix bitfield-distribution and statement-distribution tests - [x] Fix network bridge tests - [x] Implement todos in the code - [x] Add tests to cover new code - [x] Update metrics - [x] Remove the approval distribution aggression levels: TBD PR - [x] Parachains DB migration - [x] Test network protocol upgrade on Versi - [x] Versi Load test - [x] Add Zombienet test - [x] Documentation updates - [x] Fix for sending DistributeAssignment for each candidate claimed by a v2 assignment (warning: Importing locally an already known assignment) - [x] Fix AcceptedDuplicate - [x] Fix DB migration so that we can still keep old data. - [x] Final Versi burn in --------- Signed-off-by: Andrei Sandu Signed-off-by: Alexandru Gheorghe Co-authored-by: Alexandru Gheorghe --- .gitlab/pipeline/zombienet/polkadot.yml | 8 + Cargo.lock | 10 + polkadot/Cargo.toml | 2 + polkadot/cli/Cargo.toml | 2 + polkadot/node/core/approval-voting/Cargo.toml | 6 + .../approval-voting/src/approval_checking.rs | 60 +- .../approval-voting/src/approval_db/mod.rs | 1 + .../approval-voting/src/approval_db/v1/mod.rs | 268 +--- .../src/approval_db/v2/migration_helpers.rs | 244 +++ .../approval-voting/src/approval_db/v2/mod.rs | 394 +++++ .../src/approval_db/v2/tests.rs | 570 +++++++ .../node/core/approval-voting/src/backend.rs | 16 +- .../node/core/approval-voting/src/criteria.rs | 546 +++++-- .../node/core/approval-voting/src/import.rs | 38 +- polkadot/node/core/approval-voting/src/lib.rs | 520 +++++-- polkadot/node/core/approval-voting/src/ops.rs | 2 +- .../approval-voting/src/persisted_entries.rs | 135 +- .../node/core/approval-voting/src/tests.rs | 395 ++++- .../node/core/approval-voting/src/time.rs | 2 +- .../core/dispute-coordinator/src/import.rs | 2 +- .../network/approval-distribution/Cargo.toml | 2 + .../network/approval-distribution/src/lib.rs | 1375 +++++++++++------ .../approval-distribution/src/metrics.rs | 45 +- .../approval-distribution/src/tests.rs | 502 ++++-- .../network/bitfield-distribution/src/lib.rs | 52 +- polkadot/node/network/bridge/src/network.rs | 127 +- polkadot/node/network/bridge/src/rx/mod.rs | 155 +- polkadot/node/network/bridge/src/rx/tests.rs | 3 + polkadot/node/network/bridge/src/tx/mod.rs | 101 +- polkadot/node/network/bridge/src/tx/tests.rs | 5 +- .../src/collator_side/mod.rs | 11 +- .../src/validator_side/mod.rs | 12 +- .../node/network/gossip-support/src/lib.rs | 1 + polkadot/node/network/protocol/Cargo.toml | 3 + polkadot/node/network/protocol/src/lib.rs | 130 +- .../node/network/protocol/src/peer_set.rs | 12 + .../src/legacy_v1/mod.rs | 57 +- .../network/statement-distribution/src/lib.rs | 7 +- .../statement-distribution/src/v2/mod.rs | 318 +++- polkadot/node/primitives/Cargo.toml | 1 + polkadot/node/primitives/src/approval.rs | 655 ++++++-- polkadot/node/service/Cargo.toml | 5 + .../node/service/src/parachains_db/mod.rs | 36 +- .../node/service/src/parachains_db/upgrade.rs | 369 ++++- polkadot/node/service/src/tests.rs | 2 +- polkadot/node/subsystem-types/Cargo.toml | 1 + polkadot/node/subsystem-types/src/messages.rs | 13 +- .../undying/collator/Cargo.toml | 3 + .../src/node/approval/approval-voting.md | 61 +- .../src/protocol-approval.md | 33 +- .../implementers-guide/src/types/approval.md | 29 + .../implementers-guide/src/types/runtime.md | 2 +- .../0006-parachains-max-tranche0.toml | 39 + .../0006-parachains-max-tranche0.zndsl | 27 + prdoc/pr_1178.prdoc | 23 + 55 files changed, 5641 insertions(+), 1797 deletions(-) create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs create mode 100644 polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml create mode 100644 polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.zndsl create mode 100644 prdoc/pr_1178.prdoc diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 0402c194134..8fc8b280bba 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -105,6 +105,14 @@ zombienet-polkadot-functional-0005-parachains-disputes-past-session: --local-dir="${LOCAL_DIR}/functional" --test="0005-parachains-disputes-past-session.zndsl" +zombienet-polkadot-functional-0006-parachains-max-tranche0: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0006-parachains-max-tranche0.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common diff --git a/Cargo.lock b/Cargo.lock index 1a4c532f9c7..764d4ed01aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11761,9 +11761,11 @@ name = "polkadot-approval-distribution" version = "1.0.0" dependencies = [ "assert_matches", + "bitvec", "env_logger 0.9.3", "futures", "futures-timer", + "itertools 0.10.5", "log", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -12071,10 +12073,13 @@ dependencies = [ "async-trait", "bitvec", "derive_more", + "env_logger 0.9.3", "futures", "futures-timer", + "itertools 0.10.5", "kvdb", "kvdb-memorydb", + "log", "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", @@ -12086,6 +12091,8 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_core 0.5.1", "sc-keystore", "schnellru", @@ -12541,6 +12548,7 @@ dependencies = [ name = "polkadot-node-primitives" version = "1.0.0" dependencies = [ + "bitvec", "bounded-vec", "futures", "parity-scale-codec", @@ -12592,6 +12600,7 @@ name = "polkadot-node-subsystem-types" version = "1.0.0" dependencies = [ "async-trait", + "bitvec", "derive_more", "futures", "orchestra", @@ -13033,6 +13042,7 @@ dependencies = [ "polkadot-overseer", "polkadot-parachain-primitives", "polkadot-primitives", + "polkadot-primitives-test-helpers", "polkadot-rpc", "polkadot-runtime-parachains", "polkadot-statement-distribution", diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 8540f65d70c..fb161848fb6 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -64,6 +64,8 @@ jemalloc-allocator = [ "polkadot-node-core-pvf/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator", ] +network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] + # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky # when run locally depending on system load diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 9cad7e88dfe..0c2925c76e8 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -74,3 +74,5 @@ runtime-metrics = [ "polkadot-node-metrics/runtime-metrics", "service/runtime-metrics", ] + +network-protocol-staging = [ "service/network-protocol-staging" ] diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index acad0d1fa4e..f7ea1d21077 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -17,6 +17,7 @@ schnorrkel = "0.9.1" kvdb = "0.13.0" derive_more = "0.99.17" thiserror = "1.0.48" +itertools = "0.10.5" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } @@ -30,6 +31,9 @@ sp-consensus = { path = "../../../../substrate/primitives/consensus/common", def sp-consensus-slots = { path = "../../../../substrate/primitives/consensus/slots", default-features = false } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false, features = ["full_crypto"] } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +rand_core = "0.5.1" +rand_chacha = { version = "0.3.1" } +rand = "0.8.5" [dev-dependencies] async-trait = "0.1.57" @@ -43,3 +47,5 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } +log = "0.4.17" +env_logger = "0.9.0" diff --git a/polkadot/node/core/approval-voting/src/approval_checking.rs b/polkadot/node/core/approval-voting/src/approval_checking.rs index f345b57029b..5d24ff16419 100644 --- a/polkadot/node/core/approval-voting/src/approval_checking.rs +++ b/polkadot/node/core/approval-voting/src/approval_checking.rs @@ -17,7 +17,7 @@ //! Utilities for checking whether a candidate has been approved under a given block. use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice}; -use polkadot_node_primitives::approval::DelayTranche; +use polkadot_node_primitives::approval::v1::DelayTranche; use polkadot_primitives::ValidatorIndex; use crate::{ @@ -472,9 +472,9 @@ mod tests { } .into(); - let approval_entry = approval_db::v1::ApprovalEntry { + let approval_entry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: BitVec::default(), + assigned_validators: BitVec::default(), our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -509,22 +509,22 @@ mod tests { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v1::ApprovalEntry { + let approval_entry = approval_db::v2::ApprovalEntry { tranches: vec![ - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 0, assignments: (0..2).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 1, assignments: (2..5).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 2, assignments: (5..10).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, ], - assignments: bitvec![u8, BitOrderLsb0; 1; 10], + assigned_validators: bitvec![u8, BitOrderLsb0; 1; 10], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -581,22 +581,22 @@ mod tests { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v1::ApprovalEntry { + let approval_entry = approval_db::v2::ApprovalEntry { tranches: vec![ - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 0, assignments: (0..4).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 1, assignments: (4..6).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 2, assignments: (6..10).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, ], - assignments: bitvec![u8, BitOrderLsb0; 1; 10], + assigned_validators: bitvec![u8, BitOrderLsb0; 1; 10], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -647,9 +647,9 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; 5], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; 5], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -691,9 +691,9 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; 10], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; 10], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -731,9 +731,9 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; 10], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; 10], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -776,9 +776,9 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; n_validators], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -843,9 +843,9 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; n_validators], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -934,9 +934,9 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), - assignments: bitvec![u8, BitOrderLsb0; 0; n_validators], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -1041,15 +1041,15 @@ mod tests { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v1::ApprovalEntry { + let approval_entry = approval_db::v2::ApprovalEntry { tranches: vec![ // Assignments with invalid validator indexes. - approval_db::v1::TrancheEntry { + approval_db::v2::TrancheEntry { tranche: 1, assignments: (2..5).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, ], - assignments: bitvec![u8, BitOrderLsb0; 1; 3], + assigned_validators: bitvec![u8, BitOrderLsb0; 1; 3], our_assignment: None, our_approval_sig: None, backing_group: GroupIndex(0), @@ -1094,12 +1094,12 @@ mod tests { ]; for test_tranche in test_tranches { - let mut approval_entry: ApprovalEntry = approval_db::v1::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { tranches: Vec::new(), backing_group: GroupIndex(0), our_assignment: None, our_approval_sig: None, - assignments: bitvec![u8, BitOrderLsb0; 0; 3], + assigned_validators: bitvec![u8, BitOrderLsb0; 0; 3], approved: false, } .into(); diff --git a/polkadot/node/core/approval-voting/src/approval_db/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/mod.rs index f0ace95613d..20fb6aa82d8 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/mod.rs @@ -31,3 +31,4 @@ //! time being we share the same DB with the rest of Substrate. pub mod v1; +pub mod v2; diff --git a/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs index c31389269d2..011d0a559c0 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs @@ -23,144 +23,15 @@ //! require a db migration (check `node/service/src/parachains_db/upgrade.rs`). use parity_scale_codec::{Decode, Encode}; -use polkadot_node_primitives::approval::{AssignmentCert, DelayTranche}; -use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; -use polkadot_node_subsystem_util::database::{DBTransaction, Database}; +use polkadot_node_primitives::approval::v1::{AssignmentCert, DelayTranche}; use polkadot_primitives::{ BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; +use std::collections::BTreeMap; -use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; -use std::{collections::BTreeMap, sync::Arc}; - -use crate::{ - backend::{Backend, BackendWriteOp}, - persisted_entries, -}; - -const STORED_BLOCKS_KEY: &[u8] = b"Approvals_StoredBlocks"; - -#[cfg(test)] -pub mod tests; - -/// `DbBackend` is a concrete implementation of the higher-level Backend trait -pub struct DbBackend { - inner: Arc, - config: Config, -} - -impl DbBackend { - /// Create a new [`DbBackend`] with the supplied key-value store and - /// config. - pub fn new(db: Arc, config: Config) -> Self { - DbBackend { inner: db, config } - } -} - -impl Backend for DbBackend { - fn load_block_entry( - &self, - block_hash: &Hash, - ) -> SubsystemResult> { - load_block_entry(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) - } - - fn load_candidate_entry( - &self, - candidate_hash: &CandidateHash, - ) -> SubsystemResult> { - load_candidate_entry(&*self.inner, &self.config, candidate_hash).map(|e| e.map(Into::into)) - } - - fn load_blocks_at_height(&self, block_height: &BlockNumber) -> SubsystemResult> { - load_blocks_at_height(&*self.inner, &self.config, block_height) - } - - fn load_all_blocks(&self) -> SubsystemResult> { - load_all_blocks(&*self.inner, &self.config) - } - - fn load_stored_blocks(&self) -> SubsystemResult> { - load_stored_blocks(&*self.inner, &self.config) - } - - /// Atomically write the list of operations, with later operations taking precedence over prior. - fn write(&mut self, ops: I) -> SubsystemResult<()> - where - I: IntoIterator, - { - let mut tx = DBTransaction::new(); - for op in ops { - match op { - BackendWriteOp::WriteStoredBlockRange(stored_block_range) => { - tx.put_vec( - self.config.col_approval_data, - &STORED_BLOCKS_KEY, - stored_block_range.encode(), - ); - }, - BackendWriteOp::DeleteStoredBlockRange => { - tx.delete(self.config.col_approval_data, &STORED_BLOCKS_KEY); - }, - BackendWriteOp::WriteBlocksAtHeight(h, blocks) => { - tx.put_vec( - self.config.col_approval_data, - &blocks_at_height_key(h), - blocks.encode(), - ); - }, - BackendWriteOp::DeleteBlocksAtHeight(h) => { - tx.delete(self.config.col_approval_data, &blocks_at_height_key(h)); - }, - BackendWriteOp::WriteBlockEntry(block_entry) => { - let block_entry: BlockEntry = block_entry.into(); - tx.put_vec( - self.config.col_approval_data, - &block_entry_key(&block_entry.block_hash), - block_entry.encode(), - ); - }, - BackendWriteOp::DeleteBlockEntry(hash) => { - tx.delete(self.config.col_approval_data, &block_entry_key(&hash)); - }, - BackendWriteOp::WriteCandidateEntry(candidate_entry) => { - let candidate_entry: CandidateEntry = candidate_entry.into(); - tx.put_vec( - self.config.col_approval_data, - &candidate_entry_key(&candidate_entry.candidate.hash()), - candidate_entry.encode(), - ); - }, - BackendWriteOp::DeleteCandidateEntry(candidate_hash) => { - tx.delete(self.config.col_approval_data, &candidate_entry_key(&candidate_hash)); - }, - } - } - - self.inner.write(tx).map_err(|e| e.into()) - } -} - -/// A range from earliest..last block number stored within the DB. -#[derive(Encode, Decode, Debug, Clone, PartialEq)] -pub struct StoredBlockRange(pub BlockNumber, pub BlockNumber); - -// slot_duration * 2 + DelayTranche gives the number of delay tranches since the -// unix epoch. -#[derive(Encode, Decode, Clone, Copy, Debug, PartialEq)] -pub struct Tick(u64); - -/// Convenience type definition -pub type Bitfield = BitVec; - -/// The database config. -#[derive(Debug, Clone, Copy)] -pub struct Config { - /// The column family in the database where data is stored. - pub col_approval_data: u32, -} +use super::v2::Bitfield; /// Details pertaining to our assignment on a block. #[derive(Encode, Decode, Debug, Clone, PartialEq)] @@ -171,15 +42,7 @@ pub struct OurAssignment { // Whether the assignment has been triggered already. pub triggered: bool, } - -/// Metadata regarding a specific tranche of assignments for a specific candidate. -#[derive(Encode, Decode, Debug, Clone, PartialEq)] -pub struct TrancheEntry { - pub tranche: DelayTranche, - // Assigned validators, and the instant we received their assignment, rounded - // to the nearest tick. - pub assignments: Vec<(ValidatorIndex, Tick)>, -} +use super::v2::TrancheEntry; /// Metadata regarding approval of a particular candidate within the context of some /// particular block. @@ -226,126 +89,3 @@ pub struct BlockEntry { pub approved_bitfield: Bitfield, pub children: Vec, } - -impl From for Tick { - fn from(tick: crate::Tick) -> Tick { - Tick(tick) - } -} - -impl From for crate::Tick { - fn from(tick: Tick) -> crate::Tick { - tick.0 - } -} - -/// Errors while accessing things from the DB. -#[derive(Debug, derive_more::From, derive_more::Display)] -pub enum Error { - Io(std::io::Error), - InvalidDecoding(parity_scale_codec::Error), -} - -impl std::error::Error for Error {} - -/// Result alias for DB errors. -pub type Result = std::result::Result; - -pub(crate) fn load_decode( - store: &dyn Database, - col_approval_data: u32, - key: &[u8], -) -> Result> { - match store.get(col_approval_data, key)? { - None => Ok(None), - Some(raw) => D::decode(&mut &raw[..]).map(Some).map_err(Into::into), - } -} - -/// The key a given block entry is stored under. -pub(crate) fn block_entry_key(block_hash: &Hash) -> [u8; 46] { - const BLOCK_ENTRY_PREFIX: [u8; 14] = *b"Approvals_blck"; - - let mut key = [0u8; 14 + 32]; - key[0..14].copy_from_slice(&BLOCK_ENTRY_PREFIX); - key[14..][..32].copy_from_slice(block_hash.as_ref()); - - key -} - -/// The key a given candidate entry is stored under. -pub(crate) fn candidate_entry_key(candidate_hash: &CandidateHash) -> [u8; 46] { - const CANDIDATE_ENTRY_PREFIX: [u8; 14] = *b"Approvals_cand"; - - let mut key = [0u8; 14 + 32]; - key[0..14].copy_from_slice(&CANDIDATE_ENTRY_PREFIX); - key[14..][..32].copy_from_slice(candidate_hash.0.as_ref()); - - key -} - -/// The key a set of block hashes corresponding to a block number is stored under. -pub(crate) fn blocks_at_height_key(block_number: BlockNumber) -> [u8; 16] { - const BLOCKS_AT_HEIGHT_PREFIX: [u8; 12] = *b"Approvals_at"; - - let mut key = [0u8; 12 + 4]; - key[0..12].copy_from_slice(&BLOCKS_AT_HEIGHT_PREFIX); - block_number.using_encoded(|s| key[12..16].copy_from_slice(s)); - - key -} - -/// Return all blocks which have entries in the DB, ascending, by height. -pub fn load_all_blocks(store: &dyn Database, config: &Config) -> SubsystemResult> { - let mut hashes = Vec::new(); - if let Some(stored_blocks) = load_stored_blocks(store, config)? { - for height in stored_blocks.0..stored_blocks.1 { - let blocks = load_blocks_at_height(store, config, &height)?; - hashes.extend(blocks); - } - } - - Ok(hashes) -} - -/// Load the stored-blocks key from the state. -pub fn load_stored_blocks( - store: &dyn Database, - config: &Config, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, STORED_BLOCKS_KEY) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a blocks-at-height entry for a given block number. -pub fn load_blocks_at_height( - store: &dyn Database, - config: &Config, - block_number: &BlockNumber, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &blocks_at_height_key(*block_number)) - .map(|x| x.unwrap_or_default()) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a block entry from the aux store. -pub fn load_block_entry( - store: &dyn Database, - config: &Config, - block_hash: &Hash, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) - .map(|u: Option| u.map(|v| v.into())) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a candidate entry from the aux store. -pub fn load_candidate_entry( - store: &dyn Database, - config: &Config, - candidate_hash: &CandidateHash, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) - .map(|u: Option| u.map(|v| v.into())) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs new file mode 100644 index 00000000000..74e997c7af8 --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs @@ -0,0 +1,244 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Approval DB migration helpers. +use super::*; +use crate::backend::Backend; +use polkadot_node_primitives::approval::v1::{ + AssignmentCert, AssignmentCertKind, VrfOutput, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT, +}; +use polkadot_node_subsystem_util::database::Database; +use sp_application_crypto::sp_core::H256; +use std::{collections::HashSet, sync::Arc}; + +fn dummy_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"test-garbage"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let out = inout.to_output(); + + AssignmentCert { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } +} + +fn make_block_entry_v1( + block_hash: Hash, + parent_hash: Hash, + block_number: BlockNumber, + candidates: Vec<(CoreIndex, CandidateHash)>, +) -> crate::approval_db::v1::BlockEntry { + crate::approval_db::v1::BlockEntry { + block_hash, + parent_hash, + block_number, + session: 1, + slot: Slot::from(1), + relay_vrf_story: [0u8; 32], + approved_bitfield: make_bitvec(candidates.len()), + candidates, + children: Vec::new(), + } +} + +fn make_bitvec(len: usize) -> BitVec { + bitvec::bitvec![u8, BitOrderLsb0; 0; len] +} + +/// Migrates `OurAssignment`, `CandidateEntry` and `ApprovalEntry` to version 2. +/// Returns on any error. +/// Must only be used in parachains DB migration code - `polkadot-service` crate. +pub fn v1_to_v2(db: Arc, config: Config) -> Result<()> { + let mut backend = crate::DbBackend::new(db, config); + let all_blocks = backend + .load_all_blocks() + .map_err(|e| Error::InternalError(e))? + .iter() + .filter_map(|block_hash| { + backend + .load_block_entry_v1(block_hash) + .map_err(|e| Error::InternalError(e)) + .ok()? + }) + .collect::>(); + + gum::info!( + target: crate::LOG_TARGET, + "Migrating candidate entries on top of {} blocks", + all_blocks.len() + ); + + let mut overlay = crate::OverlayedBackend::new(&backend); + let mut counter = 0; + // Get all candidate entries, approval entries and convert each of them. + for block in all_blocks { + for (_core_index, candidate_hash) in block.candidates() { + // Loading the candidate will also perform the conversion to the updated format and + // return that represantation. + if let Some(candidate_entry) = backend + .load_candidate_entry_v1(&candidate_hash) + .map_err(|e| Error::InternalError(e))? + { + // Write the updated representation. + overlay.write_candidate_entry(candidate_entry); + counter += 1; + } + } + overlay.write_block_entry(block); + } + + gum::info!(target: crate::LOG_TARGET, "Migrated {} entries", counter); + + // Commit all changes to DB. + let write_ops = overlay.into_write_ops(); + backend.write(write_ops).unwrap(); + + Ok(()) +} + +// Checks if the migration doesn't leave the DB in an unsane state. +// This function is to be used in tests. +pub fn v1_to_v2_sanity_check( + db: Arc, + config: Config, + expected_candidates: HashSet, +) -> Result<()> { + let backend = crate::DbBackend::new(db, config); + + let all_blocks = backend + .load_all_blocks() + .unwrap() + .iter() + .map(|block_hash| backend.load_block_entry(block_hash).unwrap().unwrap()) + .collect::>(); + + let mut candidates = HashSet::new(); + + // Iterate all blocks and approval entries. + for block in all_blocks { + for (_core_index, candidate_hash) in block.candidates() { + // Loading the candidate will also perform the conversion to the updated format and + // return that represantation. + if let Some(candidate_entry) = backend.load_candidate_entry(&candidate_hash).unwrap() { + candidates.insert(candidate_entry.candidate.hash()); + } + } + } + + assert_eq!(candidates, expected_candidates); + + Ok(()) +} + +// Fills the db with dummy data in v1 scheme. +pub fn v1_to_v2_fill_test_data( + db: Arc, + config: Config, + dummy_candidate_create: F, +) -> Result> +where + F: Fn(H256) -> CandidateReceipt, +{ + let mut backend = crate::DbBackend::new(db.clone(), config); + let mut overlay_db = crate::OverlayedBackend::new(&backend); + let mut expected_candidates = HashSet::new(); + + const RELAY_BLOCK_COUNT: u32 = 10; + + let range = StoredBlockRange(1, 11); + overlay_db.write_stored_block_range(range.clone()); + + for relay_number in 1..=RELAY_BLOCK_COUNT { + let relay_hash = Hash::repeat_byte(relay_number as u8); + let assignment_core_index = CoreIndex(relay_number); + let candidate = dummy_candidate_create(relay_hash); + let candidate_hash = candidate.hash(); + + let at_height = vec![relay_hash]; + + let block_entry = make_block_entry_v1( + relay_hash, + Default::default(), + relay_number, + vec![(assignment_core_index, candidate_hash)], + ); + + let dummy_assignment = crate::approval_db::v1::OurAssignment { + cert: dummy_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }).into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + }; + + let candidate_entry = crate::approval_db::v1::CandidateEntry { + candidate, + session: 123, + block_assignments: vec![( + relay_hash, + crate::approval_db::v1::ApprovalEntry { + tranches: Vec::new(), + backing_group: GroupIndex(1), + our_assignment: Some(dummy_assignment), + our_approval_sig: None, + assignments: Default::default(), + approved: false, + }, + )] + .into_iter() + .collect(), + approvals: Default::default(), + }; + + overlay_db.write_blocks_at_height(relay_number, at_height.clone()); + expected_candidates.insert(candidate_entry.candidate.hash()); + + db.write(write_candidate_entry_v1(candidate_entry, config)).unwrap(); + db.write(write_block_entry_v1(block_entry, config)).unwrap(); + } + + let write_ops = overlay_db.into_write_ops(); + backend.write(write_ops).unwrap(); + + Ok(expected_candidates) +} + +// Low level DB helper to write a candidate entry in v1 scheme. +fn write_candidate_entry_v1( + candidate_entry: crate::approval_db::v1::CandidateEntry, + config: Config, +) -> DBTransaction { + let mut tx = DBTransaction::new(); + tx.put_vec( + config.col_approval_data, + &candidate_entry_key(&candidate_entry.candidate.hash()), + candidate_entry.encode(), + ); + tx +} + +// Low level DB helper to write a block entry in v1 scheme. +fn write_block_entry_v1( + block_entry: crate::approval_db::v1::BlockEntry, + config: Config, +) -> DBTransaction { + let mut tx = DBTransaction::new(); + tx.put_vec( + config.col_approval_data, + &block_entry_key(&block_entry.block_hash), + block_entry.encode(), + ); + tx +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs new file mode 100644 index 00000000000..66df6ee8f65 --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs @@ -0,0 +1,394 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Version 2 of the DB schema. + +use parity_scale_codec::{Decode, Encode}; +use polkadot_node_primitives::approval::{v1::DelayTranche, v2::AssignmentCertV2}; +use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; +use polkadot_node_subsystem_util::database::{DBTransaction, Database}; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, + ValidatorIndex, ValidatorSignature, +}; + +use sp_consensus_slots::Slot; + +use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; +use std::{collections::BTreeMap, sync::Arc}; + +use crate::{ + backend::{Backend, BackendWriteOp, V1ReadBackend}, + persisted_entries, +}; + +const STORED_BLOCKS_KEY: &[u8] = b"Approvals_StoredBlocks"; + +pub mod migration_helpers; +#[cfg(test)] +pub mod tests; + +/// `DbBackend` is a concrete implementation of the higher-level Backend trait +pub struct DbBackend { + inner: Arc, + config: Config, +} + +impl DbBackend { + /// Create a new [`DbBackend`] with the supplied key-value store and + /// config. + pub fn new(db: Arc, config: Config) -> Self { + DbBackend { inner: db, config } + } +} + +impl V1ReadBackend for DbBackend { + fn load_candidate_entry_v1( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult> { + load_candidate_entry_v1(&*self.inner, &self.config, candidate_hash) + .map(|e| e.map(Into::into)) + } + + fn load_block_entry_v1( + &self, + block_hash: &Hash, + ) -> SubsystemResult> { + load_block_entry_v1(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) + } +} + +impl Backend for DbBackend { + fn load_block_entry( + &self, + block_hash: &Hash, + ) -> SubsystemResult> { + load_block_entry(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) + } + + fn load_candidate_entry( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult> { + load_candidate_entry(&*self.inner, &self.config, candidate_hash).map(|e| e.map(Into::into)) + } + + fn load_blocks_at_height(&self, block_height: &BlockNumber) -> SubsystemResult> { + load_blocks_at_height(&*self.inner, &self.config, block_height) + } + + fn load_all_blocks(&self) -> SubsystemResult> { + load_all_blocks(&*self.inner, &self.config) + } + + fn load_stored_blocks(&self) -> SubsystemResult> { + load_stored_blocks(&*self.inner, &self.config) + } + + /// Atomically write the list of operations, with later operations taking precedence over prior. + fn write(&mut self, ops: I) -> SubsystemResult<()> + where + I: IntoIterator, + { + let mut tx = DBTransaction::new(); + for op in ops { + match op { + BackendWriteOp::WriteStoredBlockRange(stored_block_range) => { + tx.put_vec( + self.config.col_approval_data, + &STORED_BLOCKS_KEY, + stored_block_range.encode(), + ); + }, + BackendWriteOp::DeleteStoredBlockRange => { + tx.delete(self.config.col_approval_data, &STORED_BLOCKS_KEY); + }, + BackendWriteOp::WriteBlocksAtHeight(h, blocks) => { + tx.put_vec( + self.config.col_approval_data, + &blocks_at_height_key(h), + blocks.encode(), + ); + }, + BackendWriteOp::DeleteBlocksAtHeight(h) => { + tx.delete(self.config.col_approval_data, &blocks_at_height_key(h)); + }, + BackendWriteOp::WriteBlockEntry(block_entry) => { + let block_entry: BlockEntry = block_entry.into(); + tx.put_vec( + self.config.col_approval_data, + &block_entry_key(&block_entry.block_hash), + block_entry.encode(), + ); + }, + BackendWriteOp::DeleteBlockEntry(hash) => { + tx.delete(self.config.col_approval_data, &block_entry_key(&hash)); + }, + BackendWriteOp::WriteCandidateEntry(candidate_entry) => { + let candidate_entry: CandidateEntry = candidate_entry.into(); + tx.put_vec( + self.config.col_approval_data, + &candidate_entry_key(&candidate_entry.candidate.hash()), + candidate_entry.encode(), + ); + }, + BackendWriteOp::DeleteCandidateEntry(candidate_hash) => { + tx.delete(self.config.col_approval_data, &candidate_entry_key(&candidate_hash)); + }, + } + } + + self.inner.write(tx).map_err(|e| e.into()) + } +} + +/// A range from earliest..last block number stored within the DB. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct StoredBlockRange(pub BlockNumber, pub BlockNumber); + +// slot_duration * 2 + DelayTranche gives the number of delay tranches since the +// unix epoch. +#[derive(Encode, Decode, Clone, Copy, Debug, PartialEq)] +pub struct Tick(u64); + +/// Convenience type definition +pub type Bitfield = BitVec; + +/// The database config. +#[derive(Debug, Clone, Copy)] +pub struct Config { + /// The column family in the database where data is stored. + pub col_approval_data: u32, +} + +/// Details pertaining to our assignment on a block. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct OurAssignment { + /// Our assignment certificate. + pub cert: AssignmentCertV2, + /// The tranche for which the assignment refers to. + pub tranche: DelayTranche, + /// Our validator index for the session in which the candidates were included. + pub validator_index: ValidatorIndex, + /// Whether the assignment has been triggered already. + pub triggered: bool, +} + +/// Metadata regarding a specific tranche of assignments for a specific candidate. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct TrancheEntry { + pub tranche: DelayTranche, + // Assigned validators, and the instant we received their assignment, rounded + // to the nearest tick. + pub assignments: Vec<(ValidatorIndex, Tick)>, +} + +/// Metadata regarding approval of a particular candidate within the context of some +/// particular block. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct ApprovalEntry { + pub tranches: Vec, + pub backing_group: GroupIndex, + pub our_assignment: Option, + pub our_approval_sig: Option, + // `n_validators` bits. + pub assigned_validators: Bitfield, + pub approved: bool, +} + +/// Metadata regarding approval of a particular candidate. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct CandidateEntry { + pub candidate: CandidateReceipt, + pub session: SessionIndex, + // Assignments are based on blocks, so we need to track assignments separately + // based on the block we are looking at. + pub block_assignments: BTreeMap, + pub approvals: Bitfield, +} + +/// Metadata regarding approval of a particular block, by way of approval of the +/// candidates contained within it. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct BlockEntry { + pub block_hash: Hash, + pub block_number: BlockNumber, + pub parent_hash: Hash, + pub session: SessionIndex, + pub slot: Slot, + /// Random bytes derived from the VRF submitted within the block by the block + /// author as a credential and used as input to approval assignment criteria. + pub relay_vrf_story: [u8; 32], + // The candidates included as-of this block and the index of the core they are + // leaving. Sorted ascending by core index. + pub candidates: Vec<(CoreIndex, CandidateHash)>, + // A bitfield where the i'th bit corresponds to the i'th candidate in `candidates`. + // The i'th bit is `true` iff the candidate has been approved in the context of this + // block. The block can be considered approved if the bitfield has all bits set to `true`. + pub approved_bitfield: Bitfield, + pub children: Vec, + // Assignments we already distributed. A 1 bit means the candidate index for which + // we already have sent out an assignment. We need this to avoid distributing + // multiple core assignments more than once. + pub distributed_assignments: Bitfield, +} + +impl From for Tick { + fn from(tick: crate::Tick) -> Tick { + Tick(tick) + } +} + +impl From for crate::Tick { + fn from(tick: Tick) -> crate::Tick { + tick.0 + } +} + +/// Errors while accessing things from the DB. +#[derive(Debug, derive_more::From, derive_more::Display)] +pub enum Error { + Io(std::io::Error), + InvalidDecoding(parity_scale_codec::Error), + InternalError(SubsystemError), +} + +impl std::error::Error for Error {} + +/// Result alias for DB errors. +pub type Result = std::result::Result; + +pub(crate) fn load_decode( + store: &dyn Database, + col_approval_data: u32, + key: &[u8], +) -> Result> { + match store.get(col_approval_data, key)? { + None => Ok(None), + Some(raw) => D::decode(&mut &raw[..]).map(Some).map_err(Into::into), + } +} + +/// The key a given block entry is stored under. +pub(crate) fn block_entry_key(block_hash: &Hash) -> [u8; 46] { + const BLOCK_ENTRY_PREFIX: [u8; 14] = *b"Approvals_blck"; + + let mut key = [0u8; 14 + 32]; + key[0..14].copy_from_slice(&BLOCK_ENTRY_PREFIX); + key[14..][..32].copy_from_slice(block_hash.as_ref()); + + key +} + +/// The key a given candidate entry is stored under. +pub(crate) fn candidate_entry_key(candidate_hash: &CandidateHash) -> [u8; 46] { + const CANDIDATE_ENTRY_PREFIX: [u8; 14] = *b"Approvals_cand"; + + let mut key = [0u8; 14 + 32]; + key[0..14].copy_from_slice(&CANDIDATE_ENTRY_PREFIX); + key[14..][..32].copy_from_slice(candidate_hash.0.as_ref()); + + key +} + +/// The key a set of block hashes corresponding to a block number is stored under. +pub(crate) fn blocks_at_height_key(block_number: BlockNumber) -> [u8; 16] { + const BLOCKS_AT_HEIGHT_PREFIX: [u8; 12] = *b"Approvals_at"; + + let mut key = [0u8; 12 + 4]; + key[0..12].copy_from_slice(&BLOCKS_AT_HEIGHT_PREFIX); + block_number.using_encoded(|s| key[12..16].copy_from_slice(s)); + + key +} + +/// Return all blocks which have entries in the DB, ascending, by height. +pub fn load_all_blocks(store: &dyn Database, config: &Config) -> SubsystemResult> { + let mut hashes = Vec::new(); + if let Some(stored_blocks) = load_stored_blocks(store, config)? { + for height in stored_blocks.0..stored_blocks.1 { + let blocks = load_blocks_at_height(store, config, &height)?; + hashes.extend(blocks); + } + } + + Ok(hashes) +} + +/// Load the stored-blocks key from the state. +pub fn load_stored_blocks( + store: &dyn Database, + config: &Config, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, STORED_BLOCKS_KEY) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a blocks-at-height entry for a given block number. +pub fn load_blocks_at_height( + store: &dyn Database, + config: &Config, + block_number: &BlockNumber, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &blocks_at_height_key(*block_number)) + .map(|x| x.unwrap_or_default()) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a block entry from the aux store. +pub fn load_block_entry( + store: &dyn Database, + config: &Config, + block_hash: &Hash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a candidate entry from the aux store in current version format. +pub fn load_candidate_entry( + store: &dyn Database, + config: &Config, + candidate_hash: &CandidateHash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a candidate entry from the aux store in v1 format. +pub fn load_candidate_entry_v1( + store: &dyn Database, + config: &Config, + candidate_hash: &CandidateHash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a block entry from the aux store in v1 format. +pub fn load_block_entry_v1( + store: &dyn Database, + config: &Config, + block_hash: &Hash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs new file mode 100644 index 00000000000..50a5a924ca8 --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs @@ -0,0 +1,570 @@ +// 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 aux-schema of approval voting. + +use super::{DbBackend, StoredBlockRange, *}; +use crate::{ + backend::{Backend, OverlayedBackend}, + ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo}, +}; +use polkadot_node_subsystem_util::database::Database; +use polkadot_primitives::Id as ParaId; +use std::{collections::HashMap, sync::Arc}; + +use ::test_helpers::{dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash}; + +const DATA_COL: u32 = 0; + +const NUM_COLUMNS: u32 = 1; + +const TEST_CONFIG: Config = Config { col_approval_data: DATA_COL }; + +fn make_db() -> (DbBackend, Arc) { + let db = kvdb_memorydb::create(NUM_COLUMNS); + let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); + let db_writer: Arc = Arc::new(db); + (DbBackend::new(db_writer.clone(), TEST_CONFIG), db_writer) +} + +fn make_block_entry( + block_hash: Hash, + parent_hash: Hash, + block_number: BlockNumber, + candidates: Vec<(CoreIndex, CandidateHash)>, +) -> BlockEntry { + BlockEntry { + block_hash, + parent_hash, + block_number, + session: 1, + slot: Slot::from(1), + relay_vrf_story: [0u8; 32], + approved_bitfield: make_bitvec(candidates.len()), + candidates, + children: Vec::new(), + distributed_assignments: Default::default(), + } +} + +fn make_bitvec(len: usize) -> BitVec { + bitvec::bitvec![u8, BitOrderLsb0; 0; len] +} + +fn make_candidate(para_id: ParaId, relay_parent: Hash) -> CandidateReceipt { + let mut c = dummy_candidate_receipt(dummy_hash()); + + c.descriptor.para_id = para_id; + c.descriptor.relay_parent = relay_parent; + + c +} + +#[test] +fn read_write() { + let (mut db, store) = make_db(); + + let hash_a = Hash::repeat_byte(1); + let hash_b = Hash::repeat_byte(2); + let candidate_hash = dummy_candidate_receipt_bad_sig(dummy_hash(), None).hash(); + + let range = StoredBlockRange(10, 20); + let at_height = vec![hash_a, hash_b]; + + let block_entry = + make_block_entry(hash_a, Default::default(), 1, vec![(CoreIndex(0), candidate_hash)]); + + let candidate_entry = CandidateEntry { + candidate: dummy_candidate_receipt_bad_sig(dummy_hash(), None), + session: 5, + block_assignments: vec![( + hash_a, + ApprovalEntry { + tranches: Vec::new(), + backing_group: GroupIndex(1), + our_assignment: None, + our_approval_sig: None, + assigned_validators: Default::default(), + approved: false, + }, + )] + .into_iter() + .collect(), + approvals: Default::default(), + }; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(range.clone()); + overlay_db.write_blocks_at_height(1, at_height.clone()); + overlay_db.write_block_entry(block_entry.clone().into()); + overlay_db.write_candidate_entry(candidate_entry.clone().into()); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!(load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), Some(range)); + assert_eq!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap(), at_height); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(), + Some(block_entry.into()) + ); + assert_eq!( + load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap(), + Some(candidate_entry.into()), + ); + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.delete_blocks_at_height(1); + overlay_db.delete_block_entry(&hash_a); + overlay_db.delete_candidate_entry(&candidate_hash); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap().is_empty()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap().is_none()); + assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash) + .unwrap() + .is_none()); +} + +#[test] +fn add_block_entry_works() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + + let candidate_receipt_a = make_candidate(ParaId::from(1_u32), parent_hash); + let candidate_receipt_b = make_candidate(ParaId::from(2_u32), parent_hash); + + let candidate_hash_a = candidate_receipt_a.hash(); + let candidate_hash_b = candidate_receipt_b.hash(); + + let block_number = 10; + + let block_entry_a = make_block_entry( + block_hash_a, + parent_hash, + block_number, + vec![(CoreIndex(0), candidate_hash_a)], + ); + + let block_entry_b = make_block_entry( + block_hash_b, + parent_hash, + block_number, + vec![(CoreIndex(0), candidate_hash_a), (CoreIndex(1), candidate_hash_b)], + ); + + let n_validators = 10; + + let mut new_candidate_info = HashMap::new(); + new_candidate_info + .insert(candidate_hash_a, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(0), None)); + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |h| { + new_candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + new_candidate_info + .insert(candidate_hash_b, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(1), None)); + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |h| { + new_candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + Some(block_entry_a.into()) + ); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + Some(block_entry_b.into()) + ); + + let candidate_entry_a = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_a) + .unwrap() + .unwrap(); + assert_eq!( + candidate_entry_a.block_assignments.keys().collect::>(), + vec![&block_hash_a, &block_hash_b] + ); + + let candidate_entry_b = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_b) + .unwrap() + .unwrap(); + assert_eq!(candidate_entry_b.block_assignments.keys().collect::>(), vec![&block_hash_b]); +} + +#[test] +fn add_block_entry_adds_child() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + + let mut block_entry_a = make_block_entry(block_hash_a, parent_hash, 1, Vec::new()); + + let block_entry_b = make_block_entry(block_hash_b, block_hash_a, 2, Vec::new()); + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap(); + + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap(); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + block_entry_a.children.push(block_hash_b); + + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + Some(block_entry_a.into()) + ); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + Some(block_entry_b.into()) + ); +} + +#[test] +fn canonicalize_works() { + let (mut db, store) = make_db(); + + // -> B1 -> C1 -> D1 + // A -> B2 -> C2 -> D2 + // + // We'll canonicalize C1. Everytning except D1 should disappear. + // + // Candidates: + // Cand1 in B2 + // Cand2 in C2 + // Cand3 in C2 and D1 + // Cand4 in D1 + // Cand5 in D2 + // Only Cand3 and Cand4 should remain after canonicalize. + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(StoredBlockRange(1, 5)); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let genesis = Hash::repeat_byte(0); + + let block_hash_a = Hash::repeat_byte(1); + let block_hash_b1 = Hash::repeat_byte(2); + let block_hash_b2 = Hash::repeat_byte(3); + let block_hash_c1 = Hash::repeat_byte(4); + let block_hash_c2 = Hash::repeat_byte(5); + let block_hash_d1 = Hash::repeat_byte(6); + let block_hash_d2 = Hash::repeat_byte(7); + + let candidate_receipt_genesis = make_candidate(ParaId::from(1_u32), genesis); + let candidate_receipt_a = make_candidate(ParaId::from(2_u32), block_hash_a); + let candidate_receipt_b = make_candidate(ParaId::from(3_u32), block_hash_a); + let candidate_receipt_b1 = make_candidate(ParaId::from(4_u32), block_hash_b1); + let candidate_receipt_c1 = make_candidate(ParaId::from(5_u32), block_hash_c1); + + let cand_hash_1 = candidate_receipt_genesis.hash(); + let cand_hash_2 = candidate_receipt_a.hash(); + let cand_hash_3 = candidate_receipt_b.hash(); + let cand_hash_4 = candidate_receipt_b1.hash(); + let cand_hash_5 = candidate_receipt_c1.hash(); + + let block_entry_a = make_block_entry(block_hash_a, genesis, 1, Vec::new()); + let block_entry_b1 = make_block_entry(block_hash_b1, block_hash_a, 2, Vec::new()); + let block_entry_b2 = + make_block_entry(block_hash_b2, block_hash_a, 2, vec![(CoreIndex(0), cand_hash_1)]); + let block_entry_c1 = make_block_entry(block_hash_c1, block_hash_b1, 3, Vec::new()); + let block_entry_c2 = make_block_entry( + block_hash_c2, + block_hash_b2, + 3, + vec![(CoreIndex(0), cand_hash_2), (CoreIndex(1), cand_hash_3)], + ); + let block_entry_d1 = make_block_entry( + block_hash_d1, + block_hash_c1, + 4, + vec![(CoreIndex(0), cand_hash_3), (CoreIndex(1), cand_hash_4)], + ); + let block_entry_d2 = + make_block_entry(block_hash_d2, block_hash_c2, 4, vec![(CoreIndex(0), cand_hash_5)]); + + let candidate_info = { + let mut candidate_info = HashMap::new(); + candidate_info.insert( + cand_hash_1, + NewCandidateInfo::new(candidate_receipt_genesis, GroupIndex(1), None), + ); + + candidate_info + .insert(cand_hash_2, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(2), None)); + + candidate_info + .insert(cand_hash_3, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(3), None)); + + candidate_info + .insert(cand_hash_4, NewCandidateInfo::new(candidate_receipt_b1, GroupIndex(4), None)); + + candidate_info + .insert(cand_hash_5, NewCandidateInfo::new(candidate_receipt_c1, GroupIndex(5), None)); + + candidate_info + }; + + // now insert all the blocks. + let blocks = vec![ + block_entry_a.clone(), + block_entry_b1.clone(), + block_entry_b2.clone(), + block_entry_c1.clone(), + block_entry_c2.clone(), + block_entry_d1.clone(), + block_entry_d2.clone(), + ]; + + let mut overlay_db = OverlayedBackend::new(&db); + for block_entry in blocks { + add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| { + candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + } + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let check_candidates_in_store = |expected: Vec<(CandidateHash, Option>)>| { + for (c_hash, in_blocks) in expected { + let (entry, in_blocks) = match in_blocks { + None => { + assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash) + .unwrap() + .is_none()); + continue + }, + Some(i) => ( + load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash).unwrap().unwrap(), + i, + ), + }; + + assert_eq!(entry.block_assignments.len(), in_blocks.len()); + + for x in in_blocks { + assert!(entry.block_assignments.contains_key(&x)); + } + } + }; + + let check_blocks_in_store = |expected: Vec<(Hash, Option>)>| { + for (hash, with_candidates) in expected { + let (entry, with_candidates) = match with_candidates { + None => { + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash) + .unwrap() + .is_none()); + continue + }, + Some(i) => + (load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(), i), + }; + + assert_eq!(entry.candidates.len(), with_candidates.len()); + + for x in with_candidates { + assert!(entry.candidates.iter().any(|(_, c)| c == &x)); + } + } + }; + + check_candidates_in_store(vec![ + (cand_hash_1, Some(vec![block_hash_b2])), + (cand_hash_2, Some(vec![block_hash_c2])), + (cand_hash_3, Some(vec![block_hash_c2, block_hash_d1])), + (cand_hash_4, Some(vec![block_hash_d1])), + (cand_hash_5, Some(vec![block_hash_d2])), + ]); + + check_blocks_in_store(vec![ + (block_hash_a, Some(vec![])), + (block_hash_b1, Some(vec![])), + (block_hash_b2, Some(vec![cand_hash_1])), + (block_hash_c1, Some(vec![])), + (block_hash_c2, Some(vec![cand_hash_2, cand_hash_3])), + (block_hash_d1, Some(vec![cand_hash_3, cand_hash_4])), + (block_hash_d2, Some(vec![cand_hash_5])), + ]); + + let mut overlay_db = OverlayedBackend::new(&db); + canonicalize(&mut overlay_db, 3, block_hash_c1).unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(), + StoredBlockRange(4, 5) + ); + + check_candidates_in_store(vec![ + (cand_hash_1, None), + (cand_hash_2, None), + (cand_hash_3, Some(vec![block_hash_d1])), + (cand_hash_4, Some(vec![block_hash_d1])), + (cand_hash_5, None), + ]); + + check_blocks_in_store(vec![ + (block_hash_a, None), + (block_hash_b1, None), + (block_hash_b2, None), + (block_hash_c1, None), + (block_hash_c2, None), + (block_hash_d1, Some(vec![cand_hash_3, cand_hash_4])), + (block_hash_d2, None), + ]); +} + +#[test] +fn force_approve_works() { + let (mut db, store) = make_db(); + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(StoredBlockRange(1, 4)); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let single_candidate_vec = vec![(CoreIndex(0), candidate_hash)]; + let candidate_info = { + let mut candidate_info = HashMap::new(); + candidate_info.insert( + candidate_hash, + NewCandidateInfo::new( + make_candidate(ParaId::from(1_u32), Default::default()), + GroupIndex(1), + None, + ), + ); + + candidate_info + }; + + let block_hash_a = Hash::repeat_byte(1); // 1 + let block_hash_b = Hash::repeat_byte(2); + let block_hash_c = Hash::repeat_byte(3); + let block_hash_d = Hash::repeat_byte(4); // 4 + + let block_entry_a = + make_block_entry(block_hash_a, Default::default(), 1, single_candidate_vec.clone()); + let block_entry_b = + make_block_entry(block_hash_b, block_hash_a, 2, single_candidate_vec.clone()); + let block_entry_c = + make_block_entry(block_hash_c, block_hash_b, 3, single_candidate_vec.clone()); + let block_entry_d = + make_block_entry(block_hash_d, block_hash_c, 4, single_candidate_vec.clone()); + + let blocks = vec![ + block_entry_a.clone(), + block_entry_b.clone(), + block_entry_c.clone(), + block_entry_d.clone(), + ]; + + let mut overlay_db = OverlayedBackend::new(&db); + for block_entry in blocks { + add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| { + candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + } + let approved_hashes = force_approve(&mut overlay_db, block_hash_d, 2).unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a,) + .unwrap() + .unwrap() + .approved_bitfield + .all()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b,) + .unwrap() + .unwrap() + .approved_bitfield + .all()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_c,) + .unwrap() + .unwrap() + .approved_bitfield + .not_any()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_d,) + .unwrap() + .unwrap() + .approved_bitfield + .not_any()); + assert_eq!(approved_hashes, vec![block_hash_b, block_hash_a]); +} + +#[test] +fn load_all_blocks_works() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + let block_hash_c = Hash::repeat_byte(42); + + let block_number = 10; + + let block_entry_a = make_block_entry(block_hash_a, parent_hash, block_number, vec![]); + + let block_entry_b = make_block_entry(block_hash_b, parent_hash, block_number, vec![]); + + let block_entry_c = make_block_entry(block_hash_c, block_hash_a, block_number + 1, vec![]); + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap(); + + // add C before B to test sorting. + add_block_entry(&mut overlay_db, block_entry_c.clone().into(), n_validators, |_| None).unwrap(); + + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap(); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_all_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), + vec![block_hash_a, block_hash_b, block_hash_c], + ) +} diff --git a/polkadot/node/core/approval-voting/src/backend.rs b/polkadot/node/core/approval-voting/src/backend.rs index 87d67c52c46..d98f3c5fd20 100644 --- a/polkadot/node/core/approval-voting/src/backend.rs +++ b/polkadot/node/core/approval-voting/src/backend.rs @@ -27,7 +27,7 @@ use polkadot_primitives::{BlockNumber, CandidateHash, Hash}; use std::collections::HashMap; use super::{ - approval_db::v1::StoredBlockRange, + approval_db::v2::StoredBlockRange, persisted_entries::{BlockEntry, CandidateEntry}, }; @@ -44,6 +44,7 @@ pub enum BackendWriteOp { } /// An abstraction over backend storage for the logic of this subsystem. +/// Implementation must always target latest storage version. pub trait Backend { /// Load a block entry from the DB. fn load_block_entry(&self, hash: &Hash) -> SubsystemResult>; @@ -52,6 +53,7 @@ pub trait Backend { &self, candidate_hash: &CandidateHash, ) -> SubsystemResult>; + /// Load all blocks at a specific height. fn load_blocks_at_height(&self, height: &BlockNumber) -> SubsystemResult>; /// Load all block from the DB. @@ -64,6 +66,18 @@ pub trait Backend { I: IntoIterator; } +/// A read only backend to enable db migration from version 1 of DB. +pub trait V1ReadBackend: Backend { + /// Load a candidate entry from the DB with scheme version 1. + fn load_candidate_entry_v1( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult>; + + /// Load a block entry from the DB with scheme version 1. + fn load_block_entry_v1(&self, block_hash: &Hash) -> SubsystemResult>; +} + // Status of block range in the `OverlayedBackend`. #[derive(PartialEq)] enum BlockRangeStatus { diff --git a/polkadot/node/core/approval-voting/src/criteria.rs b/polkadot/node/core/approval-voting/src/criteria.rs index 0e1d18198c2..2bb5a151fe2 100644 --- a/polkadot/node/core/approval-voting/src/criteria.rs +++ b/polkadot/node/core/approval-voting/src/criteria.rs @@ -16,28 +16,36 @@ //! Assignment criteria VRF generation and checking. +use itertools::Itertools; use parity_scale_codec::{Decode, Encode}; use polkadot_node_primitives::approval::{ - self as approval_types, AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory, + self as approval_types, + v1::{AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory}, + v2::{AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, VrfOutput, VrfProof, VrfSignature}, }; use polkadot_primitives::{ AssignmentId, AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, SessionInfo, ValidatorIndex, }; +use rand::{seq::SliceRandom, SeedableRng}; +use rand_chacha::ChaCha20Rng; use sc_keystore::LocalKeystore; use sp_application_crypto::ByteArray; use merlin::Transcript; use schnorrkel::vrf::VRFInOut; -use std::collections::{hash_map::Entry, HashMap}; +use std::{ + cmp::min, + collections::{hash_map::Entry, HashMap}, +}; use super::LOG_TARGET; /// Details pertaining to our assignment on a block. #[derive(Debug, Clone, Encode, Decode, PartialEq)] pub struct OurAssignment { - cert: AssignmentCert, + cert: AssignmentCertV2, tranche: DelayTranche, validator_index: ValidatorIndex, // Whether the assignment has been triggered already. @@ -45,7 +53,7 @@ pub struct OurAssignment { } impl OurAssignment { - pub(crate) fn cert(&self) -> &AssignmentCert { + pub(crate) fn cert(&self) -> &AssignmentCertV2 { &self.cert } @@ -66,8 +74,8 @@ impl OurAssignment { } } -impl From for OurAssignment { - fn from(entry: crate::approval_db::v1::OurAssignment) -> Self { +impl From for OurAssignment { + fn from(entry: crate::approval_db::v2::OurAssignment) -> Self { OurAssignment { cert: entry.cert, tranche: entry.tranche, @@ -77,7 +85,7 @@ impl From for OurAssignment { } } -impl From for crate::approval_db::v1::OurAssignment { +impl From for crate::approval_db::v2::OurAssignment { fn from(entry: OurAssignment) -> Self { Self { cert: entry.cert, @@ -88,17 +96,97 @@ impl From for crate::approval_db::v1::OurAssignment { } } -fn relay_vrf_modulo_transcript(relay_vrf_story: RelayVRFStory, sample: u32) -> Transcript { - // combine the relay VRF story with a sample number. - let mut t = Transcript::new(approval_types::RELAY_VRF_MODULO_CONTEXT); - t.append_message(b"RC-VRF", &relay_vrf_story.0); - sample.using_encoded(|s| t.append_message(b"sample", s)); +// Combines the relay VRF story with a sample number if any. +fn relay_vrf_modulo_transcript_inner( + mut transcript: Transcript, + relay_vrf_story: RelayVRFStory, + sample: Option, +) -> Transcript { + transcript.append_message(b"RC-VRF", &relay_vrf_story.0); - t + if let Some(sample) = sample { + sample.using_encoded(|s| transcript.append_message(b"sample", s)); + } + + transcript +} + +fn relay_vrf_modulo_transcript_v1(relay_vrf_story: RelayVRFStory, sample: u32) -> Transcript { + relay_vrf_modulo_transcript_inner( + Transcript::new(approval_types::v1::RELAY_VRF_MODULO_CONTEXT), + relay_vrf_story, + Some(sample), + ) +} + +fn relay_vrf_modulo_transcript_v2(relay_vrf_story: RelayVRFStory) -> Transcript { + relay_vrf_modulo_transcript_inner( + Transcript::new(approval_types::v2::RELAY_VRF_MODULO_CONTEXT), + relay_vrf_story, + None, + ) +} + +/// A hard upper bound on num_cores * target_checkers / num_validators +const MAX_MODULO_SAMPLES: usize = 40; + +/// Takes the VRF output as input and returns a Vec of cores the validator is assigned +/// to as a tranche0 checker. +fn relay_vrf_modulo_cores( + vrf_in_out: &VRFInOut, + // Configuration - `relay_vrf_modulo_samples`. + num_samples: u32, + // Configuration - `n_cores`. + max_cores: u32, +) -> Vec { + let rand_chacha = + ChaCha20Rng::from_seed(vrf_in_out.make_bytes::<::Seed>( + approval_types::v2::CORE_RANDOMNESS_CONTEXT, + )); + generate_samples(rand_chacha, num_samples as usize, max_cores as usize) +} + +/// Generates `num_sumples` randomly from (0..max_cores) range +/// +/// Note! The algorithm can't change because validators on the other +/// side won't be able to check the assignments until they update. +/// This invariant is tested with `generate_samples_invariant`, so the +/// tests will catch any subtle changes in the implementation of this function +/// and its dependencies. +fn generate_samples( + mut rand_chacha: ChaCha20Rng, + num_samples: usize, + max_cores: usize, +) -> Vec { + if num_samples as usize > MAX_MODULO_SAMPLES { + gum::warn!( + target: LOG_TARGET, + n_cores = max_cores, + num_samples, + max_modulo_samples = MAX_MODULO_SAMPLES, + "`num_samples` is greater than `MAX_MODULO_SAMPLES`", + ); + } + + if 2 * num_samples > max_cores { + gum::debug!( + target: LOG_TARGET, + n_cores = max_cores, + num_samples, + max_modulo_samples = MAX_MODULO_SAMPLES, + "Suboptimal configuration `num_samples` should be less than `n_cores` / 2", + ); + } + + let num_samples = min(MAX_MODULO_SAMPLES, min(num_samples, max_cores)); + + let mut random_cores = (0..max_cores as u32).map(|val| val.into()).collect::>(); + let (samples, _) = random_cores.partial_shuffle(&mut rand_chacha, num_samples as usize); + samples.into_iter().map(|val| *val).collect_vec() } fn relay_vrf_modulo_core(vrf_in_out: &VRFInOut, n_cores: u32) -> CoreIndex { - let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::CORE_RANDOMNESS_CONTEXT); + let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::v1::CORE_RANDOMNESS_CONTEXT); // interpret as little-endian u32. let random_core = u32::from_le_bytes(bytes) % n_cores; @@ -106,7 +194,7 @@ fn relay_vrf_modulo_core(vrf_in_out: &VRFInOut, n_cores: u32) -> CoreIndex { } fn relay_vrf_delay_transcript(relay_vrf_story: RelayVRFStory, core_index: CoreIndex) -> Transcript { - let mut t = Transcript::new(approval_types::RELAY_VRF_DELAY_CONTEXT); + let mut t = Transcript::new(approval_types::v1::RELAY_VRF_DELAY_CONTEXT); t.append_message(b"RC-VRF", &relay_vrf_story.0); core_index.0.using_encoded(|s| t.append_message(b"core", s)); t @@ -117,7 +205,7 @@ fn relay_vrf_delay_tranche( num_delay_tranches: u32, zeroth_delay_tranche_width: u32, ) -> DelayTranche { - let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::TRANCHE_RANDOMNESS_CONTEXT); + let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::v1::TRANCHE_RANDOMNESS_CONTEXT); // interpret as little-endian u32 and reduce by the number of tranches. let wide_tranche = @@ -128,13 +216,13 @@ fn relay_vrf_delay_tranche( } fn assigned_core_transcript(core_index: CoreIndex) -> Transcript { - let mut t = Transcript::new(approval_types::ASSIGNED_CORE_CONTEXT); + let mut t = Transcript::new(approval_types::v1::ASSIGNED_CORE_CONTEXT); core_index.0.using_encoded(|s| t.append_message(b"core", s)); t } /// Information about the world assignments are being produced in. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct Config { /// The assignment public keys for validators. assignment_keys: Vec, @@ -175,12 +263,13 @@ pub(crate) trait AssignmentCriteria { fn check_assignment_cert( &self, - claimed_core_index: CoreIndex, + claimed_core_bitfield: CoreBitfield, validator_index: ValidatorIndex, config: &Config, relay_vrf_story: RelayVRFStory, - assignment: &AssignmentCert, - backing_group: GroupIndex, + assignment: &AssignmentCertV2, + // Backing groups for each "leaving core". + backing_groups: Vec, ) -> Result; } @@ -194,25 +283,25 @@ impl AssignmentCriteria for RealAssignmentCriteria { config: &Config, leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>, ) -> HashMap { - compute_assignments(keystore, relay_vrf_story, config, leaving_cores) + compute_assignments(keystore, relay_vrf_story, config, leaving_cores, false) } fn check_assignment_cert( &self, - claimed_core_index: CoreIndex, + claimed_core_bitfield: CoreBitfield, validator_index: ValidatorIndex, config: &Config, relay_vrf_story: RelayVRFStory, - assignment: &AssignmentCert, - backing_group: GroupIndex, + assignment: &AssignmentCertV2, + backing_groups: Vec, ) -> Result { check_assignment_cert( - claimed_core_index, + claimed_core_bitfield, validator_index, config, relay_vrf_story, assignment, - backing_group, + backing_groups, ) } } @@ -233,6 +322,7 @@ pub(crate) fn compute_assignments( relay_vrf_story: RelayVRFStory, config: &Config, leaving_cores: impl IntoIterator + Clone, + enable_v2_assignments: bool, ) -> HashMap { if config.n_cores == 0 || config.assignment_keys.is_empty() || @@ -291,14 +381,25 @@ pub(crate) fn compute_assignments( let mut assignments = HashMap::new(); // First run `RelayVRFModulo` for each sample. - compute_relay_vrf_modulo_assignments( - &assignments_key, - index, - config, - relay_vrf_story.clone(), - leaving_cores.iter().cloned(), - &mut assignments, - ); + if enable_v2_assignments { + compute_relay_vrf_modulo_assignments_v2( + &assignments_key, + index, + config, + relay_vrf_story.clone(), + leaving_cores.clone(), + &mut assignments, + ); + } else { + compute_relay_vrf_modulo_assignments_v1( + &assignments_key, + index, + config, + relay_vrf_story.clone(), + leaving_cores.clone(), + &mut assignments, + ); + } // Then run `RelayVRFDelay` once for the whole block. compute_relay_vrf_delay_assignments( @@ -313,7 +414,7 @@ pub(crate) fn compute_assignments( assignments } -fn compute_relay_vrf_modulo_assignments( +fn compute_relay_vrf_modulo_assignments_v1( assignments_key: &schnorrkel::Keypair, validator_index: ValidatorIndex, config: &Config, @@ -329,7 +430,7 @@ fn compute_relay_vrf_modulo_assignments( // into closure. let core = &mut core; assignments_key.vrf_sign_extra_after_check( - relay_vrf_modulo_transcript(relay_vrf_story.clone(), rvm_sample), + relay_vrf_modulo_transcript_v1(relay_vrf_story.clone(), rvm_sample), |vrf_in_out| { *core = relay_vrf_modulo_core(&vrf_in_out, config.n_cores); if let Some((candidate_hash, _)) = @@ -357,15 +458,15 @@ fn compute_relay_vrf_modulo_assignments( // has been executed. let cert = AssignmentCert { kind: AssignmentCertKind::RelayVRFModulo { sample: rvm_sample }, - vrf: approval_types::VrfSignature { - output: approval_types::VrfOutput(vrf_in_out.to_output()), - proof: approval_types::VrfProof(vrf_proof), + vrf: VrfSignature { + output: VrfOutput(vrf_in_out.to_output()), + proof: VrfProof(vrf_proof), }, }; // All assignments of type RelayVRFModulo have tranche 0. assignments.entry(core).or_insert(OurAssignment { - cert, + cert: cert.into(), tranche: 0, validator_index, triggered: false, @@ -374,6 +475,84 @@ fn compute_relay_vrf_modulo_assignments( } } +fn assigned_cores_transcript(core_bitfield: &CoreBitfield) -> Transcript { + let mut t = Transcript::new(approval_types::v2::ASSIGNED_CORE_CONTEXT); + core_bitfield.using_encoded(|s| t.append_message(b"cores", s)); + t +} + +fn compute_relay_vrf_modulo_assignments_v2( + assignments_key: &schnorrkel::Keypair, + validator_index: ValidatorIndex, + config: &Config, + relay_vrf_story: RelayVRFStory, + leaving_cores: Vec<(CandidateHash, CoreIndex)>, + assignments: &mut HashMap, +) { + let mut assigned_cores = Vec::new(); + let leaving_cores = leaving_cores.iter().map(|(_, core)| core).collect::>(); + + let maybe_assignment = { + let assigned_cores = &mut assigned_cores; + assignments_key.vrf_sign_extra_after_check( + relay_vrf_modulo_transcript_v2(relay_vrf_story.clone()), + |vrf_in_out| { + *assigned_cores = relay_vrf_modulo_cores( + &vrf_in_out, + config.relay_vrf_modulo_samples, + config.n_cores, + ) + .into_iter() + .filter(|core| leaving_cores.contains(&core)) + .collect::>(); + + if !assigned_cores.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?assigned_cores, + ?validator_index, + tranche = 0, + "RelayVRFModuloCompact Assignment." + ); + + let assignment_bitfield: CoreBitfield = assigned_cores + .clone() + .try_into() + .expect("Just checked `!assigned_cores.is_empty()`; qed"); + + Some(assigned_cores_transcript(&assignment_bitfield)) + } else { + None + } + }, + ) + }; + + if let Some(assignment) = maybe_assignment.map(|(vrf_in_out, vrf_proof, _)| { + let assignment_bitfield: CoreBitfield = assigned_cores + .clone() + .try_into() + .expect("Just checked `!assigned_cores.is_empty()`; qed"); + + let cert = AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: assignment_bitfield.clone(), + }, + vrf: VrfSignature { + output: VrfOutput(vrf_in_out.to_output()), + proof: VrfProof(vrf_proof), + }, + }; + + // All assignments of type RelayVRFModulo have tranche 0. + OurAssignment { cert, tranche: 0, validator_index, triggered: false } + }) { + for core_index in assigned_cores { + assignments.insert(core_index, assignment.clone()); + } + } +} + fn compute_relay_vrf_delay_assignments( assignments_key: &schnorrkel::Keypair, validator_index: ValidatorIndex, @@ -392,11 +571,11 @@ fn compute_relay_vrf_delay_assignments( config.zeroth_delay_tranche_width, ); - let cert = AssignmentCert { - kind: AssignmentCertKind::RelayVRFDelay { core_index: core }, - vrf: approval_types::VrfSignature { - output: approval_types::VrfOutput(vrf_in_out.to_output()), - proof: approval_types::VrfProof(vrf_proof), + let cert = AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFDelay { core_index: core }, + vrf: VrfSignature { + output: VrfOutput(vrf_in_out.to_output()), + proof: VrfProof(vrf_proof), }, }; @@ -453,12 +632,15 @@ pub(crate) enum InvalidAssignmentReason { VRFModuloOutputMismatch, VRFDelayCoreIndexMismatch, VRFDelayOutputMismatch, + InvalidArguments, + /// Assignment vrf check resulted in 0 assigned cores. + NullAssignment, } /// Checks the crypto of an assignment cert. Failure conditions: /// * Validator index out of bounds /// * VRF signature check fails -/// * VRF output doesn't match assigned core +/// * VRF output doesn't match assigned cores /// * Core is not covered by extra data in signature /// * Core index out of bounds /// * Sample is out of bounds @@ -467,12 +649,12 @@ pub(crate) enum InvalidAssignmentReason { /// This function does not check whether the core is actually a valid assignment or not. That should /// be done outside the scope of this function. pub(crate) fn check_assignment_cert( - claimed_core_index: CoreIndex, + claimed_core_indices: CoreBitfield, validator_index: ValidatorIndex, config: &Config, relay_vrf_story: RelayVRFStory, - assignment: &AssignmentCert, - backing_group: GroupIndex, + assignment: &AssignmentCertV2, + backing_groups: Vec, ) -> Result { use InvalidAssignmentReason as Reason; @@ -484,52 +666,133 @@ pub(crate) fn check_assignment_cert( let public = schnorrkel::PublicKey::from_bytes(validator_public.as_slice()) .map_err(|_| InvalidAssignment(Reason::InvalidAssignmentKey))?; - if claimed_core_index.0 >= config.n_cores { - return Err(InvalidAssignment(Reason::CoreIndexOutOfBounds)) + // Check that we have all backing groups for claimed cores. + if claimed_core_indices.count_ones() == 0 || + claimed_core_indices.count_ones() != backing_groups.len() + { + return Err(InvalidAssignment(Reason::InvalidArguments)) } // Check that the validator was not part of the backing group // and not already assigned. - let is_in_backing = - is_in_backing_group(&config.validator_groups, validator_index, backing_group); + for (claimed_core, backing_group) in claimed_core_indices.iter_ones().zip(backing_groups.iter()) + { + if claimed_core >= config.n_cores as usize { + return Err(InvalidAssignment(Reason::CoreIndexOutOfBounds)) + } + + let is_in_backing = + is_in_backing_group(&config.validator_groups, validator_index, *backing_group); - if is_in_backing { - return Err(InvalidAssignment(Reason::IsInBackingGroup)) + if is_in_backing { + return Err(InvalidAssignment(Reason::IsInBackingGroup)) + } } - let vrf_signature = &assignment.vrf; - match assignment.kind { - AssignmentCertKind::RelayVRFModulo { sample } => { - if sample >= config.relay_vrf_modulo_samples { + let vrf_output = &assignment.vrf.output; + let vrf_proof = &assignment.vrf.proof; + let first_claimed_core_index = + claimed_core_indices.first_one().expect("Checked above; qed") as u32; + + match &assignment.kind { + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => { + // Check that claimed core bitfield match the one from certificate. + if &claimed_core_indices != core_bitfield { + return Err(InvalidAssignment(Reason::VRFModuloCoreIndexMismatch)) + } + + let (vrf_in_out, _) = public + .vrf_verify_extra( + relay_vrf_modulo_transcript_v2(relay_vrf_story), + &vrf_output.0, + &vrf_proof.0, + assigned_cores_transcript(core_bitfield), + ) + .map_err(|_| InvalidAssignment(Reason::VRFModuloOutputMismatch))?; + + let resulting_cores = relay_vrf_modulo_cores( + &vrf_in_out, + config.relay_vrf_modulo_samples, + config.n_cores, + ); + + // Currently validators can opt out of checking specific cores. + // This is the same issue to how validator can opt out and not send their assignments in + // the first place. Ensure that the `vrf_in_out` actually includes all of the claimed + // cores. + for claimed_core_index in claimed_core_indices.iter_ones() { + if !resulting_cores.contains(&CoreIndex(claimed_core_index as u32)) { + gum::debug!( + target: LOG_TARGET, + ?resulting_cores, + ?claimed_core_indices, + vrf_modulo_cores = ?resulting_cores, + "Assignment claimed cores mismatch", + ); + return Err(InvalidAssignment(Reason::VRFModuloCoreIndexMismatch)) + } + } + + Ok(0) + }, + AssignmentCertKindV2::RelayVRFModulo { sample } => { + if *sample >= config.relay_vrf_modulo_samples { return Err(InvalidAssignment(Reason::SampleOutOfBounds)) } + // Enforce claimed candidates is 1. + if claimed_core_indices.count_ones() != 1 { + gum::warn!( + target: LOG_TARGET, + ?claimed_core_indices, + "`RelayVRFModulo` assignment must always claim 1 core", + ); + return Err(InvalidAssignment(Reason::InvalidArguments)) + } + let (vrf_in_out, _) = public .vrf_verify_extra( - relay_vrf_modulo_transcript(relay_vrf_story, sample), - &vrf_signature.output.0, - &vrf_signature.proof.0, - assigned_core_transcript(claimed_core_index), + relay_vrf_modulo_transcript_v1(relay_vrf_story, *sample), + &vrf_output.0, + &vrf_proof.0, + assigned_core_transcript(CoreIndex(first_claimed_core_index)), ) .map_err(|_| InvalidAssignment(Reason::VRFModuloOutputMismatch))?; + let core = relay_vrf_modulo_core(&vrf_in_out, config.n_cores); // ensure that the `vrf_in_out` actually gives us the claimed core. - if relay_vrf_modulo_core(&vrf_in_out, config.n_cores) == claimed_core_index { + if core.0 == first_claimed_core_index { Ok(0) } else { + gum::debug!( + target: LOG_TARGET, + ?core, + ?claimed_core_indices, + "Assignment claimed cores mismatch", + ); Err(InvalidAssignment(Reason::VRFModuloCoreIndexMismatch)) } }, - AssignmentCertKind::RelayVRFDelay { core_index } => { - if core_index != claimed_core_index { + AssignmentCertKindV2::RelayVRFDelay { core_index } => { + // Enforce claimed candidates is 1. + if claimed_core_indices.count_ones() != 1 { + gum::debug!( + target: LOG_TARGET, + ?claimed_core_indices, + "`RelayVRFDelay` assignment must always claim 1 core", + ); + return Err(InvalidAssignment(Reason::InvalidArguments)) + } + + if core_index.0 != first_claimed_core_index { return Err(InvalidAssignment(Reason::VRFDelayCoreIndexMismatch)) } let (vrf_in_out, _) = public .vrf_verify( - relay_vrf_delay_transcript(relay_vrf_story, core_index), - &vrf_signature.output.0, - &vrf_signature.proof.0, + relay_vrf_delay_transcript(relay_vrf_story, *core_index), + &vrf_output.0, + &vrf_proof.0, ) .map_err(|_| InvalidAssignment(Reason::VRFDelayOutputMismatch))?; @@ -550,6 +813,19 @@ fn is_in_backing_group( validator_groups.get(group).map_or(false, |g| g.contains(&validator)) } +/// Migration helpers. +impl From for OurAssignment { + fn from(value: crate::approval_db::v1::OurAssignment) -> Self { + Self { + cert: value.cert.into(), + tranche: value.tranche, + validator_index: value.validator_index, + // Whether the assignment has been triggered already. + triggered: value.triggered, + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -630,10 +906,11 @@ mod tests { ]), n_cores: 2, zeroth_delay_tranche_width: 10, - relay_vrf_modulo_samples: 3, + relay_vrf_modulo_samples: 10, n_delay_tranches: 40, }, vec![(c_a, CoreIndex(0), GroupIndex(1)), (c_b, CoreIndex(1), GroupIndex(0))], + false, ); // Note that alice is in group 0, which was the backing group for core 1. @@ -665,10 +942,11 @@ mod tests { ]), n_cores: 2, zeroth_delay_tranche_width: 10, - relay_vrf_modulo_samples: 3, + relay_vrf_modulo_samples: 10, n_delay_tranches: 40, }, vec![(c_a, CoreIndex(0), GroupIndex(0)), (c_b, CoreIndex(1), GroupIndex(1))], + false, ); assert_eq!(assignments.len(), 1); @@ -692,19 +970,21 @@ mod tests { validator_groups: Default::default(), n_cores: 0, zeroth_delay_tranche_width: 10, - relay_vrf_modulo_samples: 3, + relay_vrf_modulo_samples: 10, n_delay_tranches: 40, }, vec![], + false, ); assert!(assignments.is_empty()); } + #[derive(Debug)] struct MutatedAssignment { - core: CoreIndex, - cert: AssignmentCert, - group: GroupIndex, + cores: CoreBitfield, + cert: AssignmentCertV2, + groups: Vec, own_group: GroupIndex, val_index: ValidatorIndex, config: Config, @@ -729,12 +1009,12 @@ mod tests { validator_groups: basic_groups(n_validators, n_cores), n_cores: n_cores as u32, zeroth_delay_tranche_width: 10, - relay_vrf_modulo_samples: 3, + relay_vrf_modulo_samples: 15, n_delay_tranches: 40, }; let relay_vrf_story = RelayVRFStory([42u8; 32]); - let assignments = compute_assignments( + let mut assignments = compute_assignments( &keystore, relay_vrf_story.clone(), &config, @@ -747,19 +1027,42 @@ mod tests { ) }) .collect::>(), + false, ); + // Extend with v2 assignments as well + assignments.extend(compute_assignments( + &keystore, + relay_vrf_story.clone(), + &config, + (0..n_cores) + .map(|i| { + ( + CandidateHash(Hash::repeat_byte(i as u8)), + CoreIndex(i as u32), + group_for_core(i), + ) + }) + .collect::>(), + true, + )); + let mut counted = 0; for (core, assignment) in assignments { + let cores = match assignment.cert.kind.clone() { + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => core_bitfield, + AssignmentCertKindV2::RelayVRFModulo { sample: _ } => core.into(), + AssignmentCertKindV2::RelayVRFDelay { core_index } => core_index.into(), + }; + let mut mutated = MutatedAssignment { - core, - group: group_for_core(core.0 as _), + cores: cores.clone(), + groups: cores.iter_ones().map(|core| group_for_core(core)).collect(), cert: assignment.cert, own_group: GroupIndex(0), val_index: ValidatorIndex(0), config: config.clone(), }; - let expected = match f(&mut mutated) { None => continue, Some(e) => e, @@ -768,16 +1071,16 @@ mod tests { counted += 1; let is_good = check_assignment_cert( - mutated.core, + mutated.cores, mutated.val_index, &mutated.config, relay_vrf_story.clone(), &mutated.cert, - mutated.group, + mutated.groups, ) .is_ok(); - assert_eq!(expected, is_good) + assert_eq!(expected, is_good); } assert!(counted > 0); @@ -791,7 +1094,7 @@ mod tests { #[test] fn check_rejects_claimed_core_out_of_bounds() { check_mutated_assignments(200, 100, 25, |m| { - m.core.0 += 100; + m.cores = CoreIndex(100).into(); Some(false) }); } @@ -799,7 +1102,7 @@ mod tests { #[test] fn check_rejects_in_backing_group() { check_mutated_assignments(200, 100, 25, |m| { - m.group = m.own_group; + m.groups[0] = m.own_group; Some(false) }); } @@ -814,10 +1117,11 @@ mod tests { #[test] fn check_rejects_delay_bad_vrf() { - check_mutated_assignments(40, 10, 8, |m| { + check_mutated_assignments(40, 100, 8, |m| { + let vrf_signature = garbage_vrf_signature(); match m.cert.kind.clone() { - AssignmentCertKind::RelayVRFDelay { .. } => { - m.cert.vrf = garbage_vrf_signature(); + AssignmentCertKindV2::RelayVRFDelay { .. } => { + m.cert.vrf = vrf_signature; Some(false) }, _ => None, // skip everything else. @@ -828,9 +1132,14 @@ mod tests { #[test] fn check_rejects_modulo_bad_vrf() { check_mutated_assignments(200, 100, 25, |m| { + let vrf_signature = garbage_vrf_signature(); match m.cert.kind.clone() { - AssignmentCertKind::RelayVRFModulo { .. } => { - m.cert.vrf = garbage_vrf_signature(); + AssignmentCertKindV2::RelayVRFModulo { .. } => { + m.cert.vrf = vrf_signature; + Some(false) + }, + AssignmentCertKindV2::RelayVRFModuloCompact { .. } => { + m.cert.vrf = vrf_signature; Some(false) }, _ => None, // skip everything else. @@ -842,10 +1151,11 @@ mod tests { fn check_rejects_modulo_sample_out_of_bounds() { check_mutated_assignments(200, 100, 25, |m| { match m.cert.kind.clone() { - AssignmentCertKind::RelayVRFModulo { sample } => { + AssignmentCertKindV2::RelayVRFModulo { sample } => { m.config.relay_vrf_modulo_samples = sample; Some(false) }, + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield: _ } => Some(true), _ => None, // skip everything else. } }); @@ -855,8 +1165,11 @@ mod tests { fn check_rejects_delay_claimed_core_wrong() { check_mutated_assignments(200, 100, 25, |m| { match m.cert.kind.clone() { - AssignmentCertKind::RelayVRFDelay { .. } => { - m.core = CoreIndex((m.core.0 + 1) % 100); + AssignmentCertKindV2::RelayVRFDelay { .. } => { + // for core in &mut m.cores { + // core.0 = (core.0 + 1) % 100; + // } + m.cores = CoreIndex((m.cores.first_one().unwrap() + 1) as u32 % 100).into(); Some(false) }, _ => None, // skip everything else. @@ -868,12 +1181,53 @@ mod tests { fn check_rejects_modulo_core_wrong() { check_mutated_assignments(200, 100, 25, |m| { match m.cert.kind.clone() { - AssignmentCertKind::RelayVRFModulo { .. } => { - m.core = CoreIndex((m.core.0 + 1) % 100); + AssignmentCertKindV2::RelayVRFModulo { .. } | + AssignmentCertKindV2::RelayVRFModuloCompact { .. } => { + m.cores = CoreIndex((m.cores.first_one().unwrap() + 1) as u32 % 100).into(); + Some(false) }, _ => None, // skip everything else. } }); } + + #[test] + fn generate_samples_invariant() { + let seed = [ + 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, + 0, 0, 0, 2, 92, + ]; + let rand_chacha = ChaCha20Rng::from_seed(seed); + + let samples = generate_samples(rand_chacha.clone(), 6, 100); + let expected = vec![19, 79, 17, 75, 66, 30].into_iter().map(Into::into).collect_vec(); + assert_eq!(samples, expected); + + let samples = generate_samples(rand_chacha.clone(), 6, 7); + let expected = vec![0, 3, 6, 5, 4, 2].into_iter().map(Into::into).collect_vec(); + assert_eq!(samples, expected); + + let samples = generate_samples(rand_chacha.clone(), 6, 12); + let expected = vec![2, 4, 7, 5, 11, 3].into_iter().map(Into::into).collect_vec(); + assert_eq!(samples, expected); + + let samples = generate_samples(rand_chacha.clone(), 1, 100); + let expected = vec![30].into_iter().map(Into::into).collect_vec(); + assert_eq!(samples, expected); + + let samples = generate_samples(rand_chacha.clone(), 0, 100); + let expected = vec![]; + assert_eq!(samples, expected); + + let samples = generate_samples(rand_chacha, MAX_MODULO_SAMPLES + 1, 100); + let expected = vec![ + 42, 54, 55, 93, 64, 27, 49, 15, 83, 71, 62, 1, 43, 77, 97, 41, 7, 69, 0, 88, 59, 14, + 23, 87, 47, 4, 51, 12, 74, 56, 50, 44, 9, 82, 19, 79, 17, 75, 66, 30, + ] + .into_iter() + .map(Into::into) + .collect_vec(); + assert_eq!(samples, expected); + } } diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index df712fc45a5..d7667e8e405 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -30,7 +30,10 @@ use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ - approval::{self as approval_types, BlockApprovalMeta, RelayVRFStory}, + approval::{ + self as approval_types, + v1::{BlockApprovalMeta, RelayVRFStory}, + }, MAX_FINALITY_LAG, }; use polkadot_node_subsystem::{ @@ -53,7 +56,7 @@ use futures::{channel::oneshot, prelude::*}; use std::collections::HashMap; -use super::approval_db::v1; +use super::approval_db::v2; use crate::{ backend::{Backend, OverlayedBackend}, criteria::{AssignmentCriteria, OurAssignment}, @@ -92,7 +95,7 @@ enum ImportedBlockInfoError { FutureCancelled(&'static str, futures::channel::oneshot::Canceled), #[error(transparent)] - ApprovalError(approval_types::ApprovalError), + ApprovalError(approval_types::v1::ApprovalError), #[error("block is already finalized")] BlockAlreadyFinalized, @@ -216,7 +219,7 @@ async fn imported_block_info( .ok_or(ImportedBlockInfoError::SessionInfoUnavailable)?; let (assignments, slot, relay_vrf_story) = { - let unsafe_vrf = approval_types::babe_unsafe_vrf_info(&block_header); + let unsafe_vrf = approval_types::v1::babe_unsafe_vrf_info(&block_header); match unsafe_vrf { Some(unsafe_vrf) => { @@ -497,7 +500,7 @@ pub(crate) async fn handle_new_head( ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await; } - let block_entry = v1::BlockEntry { + let block_entry = v2::BlockEntry { block_hash, parent_hash: block_header.parent_hash, block_number: block_header.number, @@ -510,6 +513,7 @@ pub(crate) async fn handle_new_head( .collect(), approved_bitfield, children: Vec::new(), + distributed_assignments: Default::default(), }; gum::trace!( @@ -588,11 +592,11 @@ pub(crate) async fn handle_new_head( #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::{approval_db::v1::DbBackend, RuntimeInfo, RuntimeInfoConfig}; + use crate::{approval_db::v2::DbBackend, RuntimeInfo, RuntimeInfoConfig}; use ::test_helpers::{dummy_candidate_receipt, dummy_hash}; use assert_matches::assert_matches; use polkadot_node_primitives::{ - approval::{VrfSignature, VrfTranscript}, + approval::v1::{VrfSignature, VrfTranscript}, DISPUTE_WINDOW, }; use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage}; @@ -610,7 +614,7 @@ pub(crate) mod tests { pub(crate) use sp_runtime::{Digest, DigestItem}; use std::{pin::Pin, sync::Arc}; - use crate::{approval_db::v1::Config as DatabaseConfig, criteria, BlockEntry}; + use crate::{approval_db::v2::Config as DatabaseConfig, criteria, BlockEntry}; const DATA_COL: u32 = 0; @@ -656,7 +660,7 @@ pub(crate) mod tests { fn compute_assignments( &self, _keystore: &LocalKeystore, - _relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory, + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, _config: &criteria::Config, _leaving_cores: Vec<( CandidateHash, @@ -669,13 +673,14 @@ pub(crate) mod tests { fn check_assignment_cert( &self, - _claimed_core_index: polkadot_primitives::CoreIndex, + _claimed_core_bitfield: polkadot_node_primitives::approval::v2::CoreBitfield, _validator_index: polkadot_primitives::ValidatorIndex, _config: &criteria::Config, - _relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory, - _assignment: &polkadot_node_primitives::approval::AssignmentCert, - _backing_group: polkadot_primitives::GroupIndex, - ) -> Result { + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, + _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, + _backing_groups: Vec, + ) -> Result + { Ok(0) } } @@ -1296,7 +1301,7 @@ pub(crate) mod tests { let (state, mut session_info_provider) = single_session_state(); overlay_db.write_block_entry( - v1::BlockEntry { + v2::BlockEntry { block_hash: parent_hash, parent_hash: Default::default(), block_number: 4, @@ -1306,6 +1311,7 @@ pub(crate) mod tests { candidates: Vec::new(), approved_bitfield: Default::default(), children: Vec::new(), + distributed_assignments: Default::default(), } .into(), ); @@ -1338,7 +1344,7 @@ pub(crate) mod tests { // the first candidate should be insta-approved // the second should not let entry: BlockEntry = - v1::load_block_entry(db_writer.as_ref(), &TEST_CONFIG, &hash) + v2::load_block_entry(db_writer.as_ref(), &TEST_CONFIG, &hash) .unwrap() .unwrap() .into(); diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index ddef736feab..e7cbde56739 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -25,7 +25,11 @@ use jaeger::{hash_to_trace_identifier, PerLeafSpan}; use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ - BlockApprovalMeta, DelayTranche, IndirectAssignmentCert, IndirectSignedApprovalVote, + v1::{BlockApprovalMeta, DelayTranche, IndirectSignedApprovalVote}, + v2::{ + AssignmentCertKindV2, BitfieldError, CandidateBitfield, CoreBitfield, + IndirectAssignmentCertV2, + }, }, ValidationResult, DISPUTE_WINDOW, }; @@ -76,12 +80,13 @@ use std::{ use schnellru::{ByLength, LruMap}; use approval_checking::RequiredTranches; +use bitvec::{order::Lsb0, vec::BitVec}; use criteria::{AssignmentCriteria, RealAssignmentCriteria}; use persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}; use time::{slot_number_to_tick, Clock, ClockExt, SystemClock, Tick}; mod approval_checking; -mod approval_db; +pub mod approval_db; mod backend; mod criteria; mod import; @@ -90,8 +95,9 @@ mod persisted_entries; mod time; use crate::{ - approval_db::v1::{Config as DatabaseConfig, DbBackend}, + approval_db::v2::{Config as DatabaseConfig, DbBackend}, backend::{Backend, OverlayedBackend}, + criteria::InvalidAssignmentReason, }; #[cfg(test)] @@ -107,7 +113,7 @@ const APPROVAL_CACHE_SIZE: u32 = 1024; const TICK_TOO_FAR_IN_FUTURE: Tick = 20; // 10 seconds. const APPROVAL_DELAY: Tick = 2; -const LOG_TARGET: &str = "parachain::approval-voting"; +pub(crate) const LOG_TARGET: &str = "parachain::approval-voting"; /// Configuration for the approval voting subsystem #[derive(Debug, Clone)] @@ -377,8 +383,8 @@ impl ApprovalVotingSubsystem { /// The operation is not allowed for blocks older than the last finalized one. pub fn revert_to(&self, hash: Hash) -> Result<(), SubsystemError> { let config = - approval_db::v1::Config { col_approval_data: self.db_config.col_approval_data }; - let mut backend = approval_db::v1::DbBackend::new(self.db.clone(), config); + approval_db::v2::Config { col_approval_data: self.db_config.col_approval_data }; + let mut backend = approval_db::v2::DbBackend::new(self.db.clone(), config); let mut overlay = OverlayedBackend::new(&backend); ops::revert_to(&mut overlay, hash)?; @@ -754,15 +760,16 @@ enum Action { tick: Tick, }, LaunchApproval { + claimed_candidate_indices: CandidateBitfield, candidate_hash: CandidateHash, - indirect_cert: IndirectAssignmentCert, + indirect_cert: IndirectAssignmentCertV2, assignment_tranche: DelayTranche, relay_block_hash: Hash, - candidate_index: CandidateIndex, session: SessionIndex, executor_params: ExecutorParams, candidate: CandidateReceipt, backing_group: GroupIndex, + distribute_assignment: bool, }, NoteApprovedInChainSelection(Hash), IssueApproval(CandidateHash, ApprovalVoteRequest), @@ -977,15 +984,16 @@ async fn handle_actions( actions_iter = next_actions.into_iter(); }, Action::LaunchApproval { + claimed_candidate_indices, candidate_hash, indirect_cert, assignment_tranche, relay_block_hash, - candidate_index, session, executor_params, candidate, backing_group, + distribute_assignment, } => { // Don't launch approval work if the node is syncing. if let Mode::Syncing(_) = *mode { @@ -1006,10 +1014,12 @@ async fn handle_actions( launch_approval_span.add_string_tag("block-hash", format!("{:?}", block_hash)); let validator_index = indirect_cert.validator; - ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeAssignment( - indirect_cert, - candidate_index, - )); + if distribute_assignment { + ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeAssignment( + indirect_cert, + claimed_candidate_indices, + )); + } match approvals_cache.get(&candidate_hash) { Some(ApprovalOutcome::Approved) => { @@ -1078,6 +1088,49 @@ async fn handle_actions( Ok(conclude) } +fn cores_to_candidate_indices( + core_indices: &CoreBitfield, + block_entry: &BlockEntry, +) -> Result { + let mut candidate_indices = Vec::new(); + + // Map from core index to candidate index. + for claimed_core_index in core_indices.iter_ones() { + if let Some(candidate_index) = block_entry + .candidates() + .iter() + .position(|(core_index, _)| core_index.0 == claimed_core_index as u32) + { + candidate_indices.push(candidate_index as CandidateIndex); + } + } + + CandidateBitfield::try_from(candidate_indices) +} + +// Returns the claimed core bitfield from the assignment cert, the candidate hash and a +// `BlockEntry`. Can fail only for VRF Delay assignments for which we cannot find the candidate hash +// in the block entry which indicates a bug or corrupted storage. +fn get_assignment_core_indices( + assignment: &AssignmentCertKindV2, + candidate_hash: &CandidateHash, + block_entry: &BlockEntry, +) -> Option { + match &assignment { + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => + Some(core_bitfield.clone()), + AssignmentCertKindV2::RelayVRFModulo { sample: _ } => block_entry + .candidates() + .iter() + .find(|(_core_index, h)| candidate_hash == h) + .map(|(core_index, _candidate_hash)| { + CoreBitfield::try_from(vec![*core_index]).expect("Not an empty vec; qed") + }), + AssignmentCertKindV2::RelayVRFDelay { core_index } => + Some(CoreBitfield::try_from(vec![*core_index]).expect("Not an empty vec; qed")), + } +} + fn distribution_messages_for_activation( db: &OverlayedBackend<'_, impl Backend>, state: &State, @@ -1142,33 +1195,95 @@ fn distribution_messages_for_activation( match approval_entry.local_statements() { (None, None) | (None, Some(_)) => {}, // second is impossible case. (Some(assignment), None) => { - messages.push(ApprovalDistributionMessage::DistributeAssignment( - IndirectAssignmentCert { - block_hash, - validator: assignment.validator_index(), - cert: assignment.cert().clone(), - }, - i as _, - )); + if let Some(claimed_core_indices) = get_assignment_core_indices( + &assignment.cert().kind, + &candidate_hash, + &block_entry, + ) { + match cores_to_candidate_indices( + &claimed_core_indices, + &block_entry, + ) { + Ok(bitfield) => messages.push( + ApprovalDistributionMessage::DistributeAssignment( + IndirectAssignmentCertV2 { + block_hash, + validator: assignment.validator_index(), + cert: assignment.cert().clone(), + }, + bitfield, + ), + ), + Err(err) => { + // Should never happen. If we fail here it means the + // assignment is null (no cores claimed). + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + ?err, + "Failed to create assignment bitfield", + ); + }, + } + } else { + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + "Cannot get assignment claimed core indices", + ); + } }, (Some(assignment), Some(approval_sig)) => { - messages.push(ApprovalDistributionMessage::DistributeAssignment( - IndirectAssignmentCert { - block_hash, - validator: assignment.validator_index(), - cert: assignment.cert().clone(), - }, - i as _, - )); + if let Some(claimed_core_indices) = get_assignment_core_indices( + &assignment.cert().kind, + &candidate_hash, + &block_entry, + ) { + match cores_to_candidate_indices( + &claimed_core_indices, + &block_entry, + ) { + Ok(bitfield) => messages.push( + ApprovalDistributionMessage::DistributeAssignment( + IndirectAssignmentCertV2 { + block_hash, + validator: assignment.validator_index(), + cert: assignment.cert().clone(), + }, + bitfield, + ), + ), + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + ?err, + "Failed to create assignment bitfield", + ); + // If we didn't send assignment, we don't send approval. + continue + }, + } - messages.push(ApprovalDistributionMessage::DistributeApproval( - IndirectSignedApprovalVote { - block_hash, - candidate_index: i as _, - validator: assignment.validator_index(), - signature: approval_sig, - }, - )) + messages.push(ApprovalDistributionMessage::DistributeApproval( + IndirectSignedApprovalVote { + block_hash, + candidate_index: i as _, + validator: assignment.validator_index(), + signature: approval_sig, + }, + )); + } else { + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + "Cannot get assignment claimed core indices", + ); + } }, } }, @@ -1288,14 +1403,14 @@ async fn handle_from_overseer( vec![Action::Conclude] }, FromOrchestra::Communication { msg } => match msg { - ApprovalVotingMessage::CheckAndImportAssignment(a, claimed_core, res) => { + ApprovalVotingMessage::CheckAndImportAssignment(a, claimed_cores, res) => { let (check_outcome, actions) = check_and_import_assignment( ctx.sender(), state, db, session_info_provider, a, - claimed_core, + claimed_cores, ) .await?; let _ = res.send(check_outcome); @@ -1465,7 +1580,6 @@ async fn handle_approved_ancestor( let mut span = span .child("handle-approved-ancestor") .with_stage(jaeger::Stage::ApprovalChecking); - use bitvec::{order::Lsb0, vec::BitVec}; let mut all_approved_max = None; @@ -1804,8 +1918,8 @@ async fn check_and_import_assignment( state: &State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, - assignment: IndirectAssignmentCert, - candidate_index: CandidateIndex, + assignment: IndirectAssignmentCertV2, + candidate_indices: CandidateBitfield, ) -> SubsystemResult<(AssignmentCheckResult, Vec)> where Sender: SubsystemSender, @@ -1818,9 +1932,12 @@ where .map(|span| span.child("check-and-import-assignment")) .unwrap_or_else(|| jaeger::Span::new(assignment.block_hash, "check-and-import-assignment")) .with_relay_parent(assignment.block_hash) - .with_uint_tag("candidate-index", candidate_index as u64) .with_stage(jaeger::Stage::ApprovalChecking); + for candidate_index in candidate_indices.iter_ones() { + check_and_import_assignment_span.add_uint_tag("candidate-index", candidate_index as u64); + } + let block_entry = match db.load_block_entry(&assignment.block_hash)? { Some(b) => b, None => @@ -1850,39 +1967,64 @@ where )), }; - let (claimed_core_index, assigned_candidate_hash) = - match block_entry.candidate(candidate_index as usize) { - Some((c, h)) => (*c, *h), + let n_cores = session_info.n_cores as usize; + + // Early check the candidate bitfield and core bitfields lengths < `n_cores`. + // Core bitfield length is checked later in `check_assignment_cert`. + if candidate_indices.len() > n_cores { + gum::debug!( + target: LOG_TARGET, + validator = assignment.validator.0, + n_cores, + candidate_bitfield_len = ?candidate_indices.len(), + "Oversized bitfield", + ); + + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidBitfield( + candidate_indices.len(), + )), + Vec::new(), + )) + } + + // The Compact VRF modulo assignment cert has multiple core assignments. + let mut backing_groups = Vec::new(); + let mut claimed_core_indices = Vec::new(); + let mut assigned_candidate_hashes = Vec::new(); + + for candidate_index in candidate_indices.iter_ones() { + let (claimed_core_index, assigned_candidate_hash) = + match block_entry.candidate(candidate_index) { + Some((c, h)) => (*c, *h), + None => + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidateIndex( + candidate_index as _, + )), + Vec::new(), + )), // no candidate at core. + }; + + let mut candidate_entry = match db.load_candidate_entry(&assigned_candidate_hash)? { + Some(c) => c, None => return Ok(( - AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidateIndex( - candidate_index, + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidate( + candidate_index as _, + assigned_candidate_hash, )), Vec::new(), )), // no candidate at core. }; - check_and_import_assignment_span - .add_string_tag("candidate-hash", format!("{:?}", assigned_candidate_hash)); - check_and_import_assignment_span.add_string_tag( - "traceID", - format!("{:?}", jaeger::hash_to_trace_identifier(assigned_candidate_hash.0)), - ); - - let mut candidate_entry = match db.load_candidate_entry(&assigned_candidate_hash)? { - Some(c) => c, - None => - return Ok(( - AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidate( - candidate_index, - assigned_candidate_hash, - )), - Vec::new(), - )), - }; + check_and_import_assignment_span + .add_string_tag("candidate-hash", format!("{:?}", assigned_candidate_hash)); + check_and_import_assignment_span.add_string_tag( + "traceID", + format!("{:?}", jaeger::hash_to_trace_identifier(assigned_candidate_hash.0)), + ); - let res = { - // import the assignment. let approval_entry = match candidate_entry.approval_entry_mut(&assignment.block_hash) { Some(a) => a, None => @@ -1895,79 +2037,144 @@ where )), }; - let res = state.assignment_criteria.check_assignment_cert( - claimed_core_index, - assignment.validator, - &criteria::Config::from(session_info), - block_entry.relay_vrf_story(), - &assignment.cert, - approval_entry.backing_group(), - ); + backing_groups.push(approval_entry.backing_group()); + claimed_core_indices.push(claimed_core_index); + assigned_candidate_hashes.push(assigned_candidate_hash); + } - let tranche = match res { - Err(crate::criteria::InvalidAssignment(reason)) => - return Ok(( - AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCert( - assignment.validator, - format!("{:?}", reason), - )), - Vec::new(), + // Error on null assignments. + if claimed_core_indices.is_empty() { + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCert( + assignment.validator, + format!("{:?}", InvalidAssignmentReason::NullAssignment), + )), + Vec::new(), + )) + } + + // Check the assignment certificate. + let res = state.assignment_criteria.check_assignment_cert( + claimed_core_indices + .clone() + .try_into() + .expect("Checked for null assignment above; qed"), + assignment.validator, + &criteria::Config::from(session_info), + block_entry.relay_vrf_story(), + &assignment.cert, + backing_groups, + ); + + let tranche = match res { + Err(crate::criteria::InvalidAssignment(reason)) => + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCert( + assignment.validator, + format!("{:?}", reason), )), - Ok(tranche) => { - let current_tranche = - state.clock.tranche_now(state.slot_duration_millis, block_entry.slot()); + Vec::new(), + )), + Ok(tranche) => { + let current_tranche = + state.clock.tranche_now(state.slot_duration_millis, block_entry.slot()); - let too_far_in_future = current_tranche + TICK_TOO_FAR_IN_FUTURE as DelayTranche; + let too_far_in_future = current_tranche + TICK_TOO_FAR_IN_FUTURE as DelayTranche; - if tranche >= too_far_in_future { - return Ok((AssignmentCheckResult::TooFarInFuture, Vec::new())) - } + if tranche >= too_far_in_future { + return Ok((AssignmentCheckResult::TooFarInFuture, Vec::new())) + } - tranche - }, - }; + tranche + }, + }; - check_and_import_assignment_span.add_uint_tag("tranche", tranche as u64); + let mut actions = Vec::new(); + let res = { + let mut is_duplicate = true; + // Import the assignments for all cores in the cert. + for (assigned_candidate_hash, candidate_index) in + assigned_candidate_hashes.iter().zip(candidate_indices.iter_ones()) + { + let mut candidate_entry = match db.load_candidate_entry(&assigned_candidate_hash)? { + Some(c) => c, + None => + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidate( + candidate_index as _, + *assigned_candidate_hash, + )), + Vec::new(), + )), + }; - let is_duplicate = approval_entry.is_assigned(assignment.validator); - approval_entry.import_assignment(tranche, assignment.validator, tick_now); + let approval_entry = match candidate_entry.approval_entry_mut(&assignment.block_hash) { + Some(a) => a, + None => + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::Internal( + assignment.block_hash, + *assigned_candidate_hash, + )), + Vec::new(), + )), + }; + is_duplicate &= approval_entry.is_assigned(assignment.validator); + approval_entry.import_assignment(tranche, assignment.validator, tick_now); + check_and_import_assignment_span.add_uint_tag("tranche", tranche as u64); + + // We've imported a new assignment, so we need to schedule a wake-up for when that might + // no-show. + if let Some((approval_entry, status)) = state + .approval_status(sender, session_info_provider, &block_entry, &candidate_entry) + .await + { + actions.extend(schedule_wakeup_action( + approval_entry, + block_entry.block_hash(), + block_entry.block_number(), + *assigned_candidate_hash, + status.block_tick, + tick_now, + status.required_tranches, + )); + } + + // We also write the candidate entry as it now contains the new candidate. + db.write_candidate_entry(candidate_entry.into()); + } + // Since we don't account for tranche in distribution message fingerprinting, some + // validators can be assigned to the same core (VRF modulo vs VRF delay). These can be + // safely ignored. However, if an assignment is for multiple cores (these are only + // tranche0), we cannot ignore it, because it would mean ignoring other non duplicate + // assignments. if is_duplicate { AssignmentCheckResult::AcceptedDuplicate + } else if candidate_indices.count_ones() > 1 { + gum::trace!( + target: LOG_TARGET, + validator = assignment.validator.0, + candidate_hashes = ?assigned_candidate_hashes, + assigned_cores = ?claimed_core_indices, + ?tranche, + "Imported assignments for multiple cores.", + ); + + AssignmentCheckResult::Accepted } else { gum::trace!( target: LOG_TARGET, validator = assignment.validator.0, - candidate_hash = ?assigned_candidate_hash, - para_id = ?candidate_entry.candidate_receipt().descriptor.para_id, - "Imported assignment.", + candidate_hashes = ?assigned_candidate_hashes, + assigned_cores = ?claimed_core_indices, + "Imported assignment for a single core.", ); AssignmentCheckResult::Accepted } }; - let mut actions = Vec::new(); - - // We've imported a new approval, so we need to schedule a wake-up for when that might no-show. - if let Some((approval_entry, status)) = state - .approval_status(sender, session_info_provider, &block_entry, &candidate_entry) - .await - { - actions.extend(schedule_wakeup_action( - approval_entry, - block_entry.block_hash(), - block_entry.block_number(), - assigned_candidate_hash, - status.block_tick, - tick_now, - status.required_tranches, - )); - } - - // We also write the candidate entry as it now contains the new candidate. - db.write_candidate_entry(candidate_entry.into()); - Ok((res, actions)) } @@ -2341,7 +2548,7 @@ async fn process_wakeup( let candidate_entry = db.load_candidate_entry(&candidate_hash)?; // If either is not present, we have nothing to wakeup. Might have lost a race with finality - let (block_entry, mut candidate_entry) = match (block_entry, candidate_entry) { + let (mut block_entry, mut candidate_entry) = match (block_entry, candidate_entry) { (Some(b), Some(c)) => (b, c), _ => return Ok(Vec::new()), }; @@ -2422,32 +2629,59 @@ async fn process_wakeup( if let Some((cert, val_index, tranche)) = maybe_cert { let indirect_cert = - IndirectAssignmentCert { block_hash: relay_block, validator: val_index, cert }; + IndirectAssignmentCertV2 { block_hash: relay_block, validator: val_index, cert }; + + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + para_id = ?candidate_receipt.descriptor.para_id, + block_hash = ?relay_block, + "Launching approval work.", + ); - let index_in_candidate = - block_entry.candidates().iter().position(|(_, h)| &candidate_hash == h); + if let Some(claimed_core_indices) = + get_assignment_core_indices(&indirect_cert.cert.kind, &candidate_hash, &block_entry) + { + match cores_to_candidate_indices(&claimed_core_indices, &block_entry) { + Ok(claimed_candidate_indices) => { + // Ensure we distribute multiple core assignments just once. + let distribute_assignment = if claimed_candidate_indices.count_ones() > 1 { + !block_entry.mark_assignment_distributed(claimed_candidate_indices.clone()) + } else { + true + }; + db.write_block_entry(block_entry.clone()); - if let Some(i) = index_in_candidate { - gum::trace!( + actions.push(Action::LaunchApproval { + claimed_candidate_indices, + candidate_hash, + indirect_cert, + assignment_tranche: tranche, + relay_block_hash: relay_block, + session: block_entry.session(), + executor_params: executor_params.clone(), + candidate: candidate_receipt, + backing_group, + distribute_assignment, + }); + }, + Err(err) => { + // Never happens, it should only happen if no cores are claimed, which is a bug. + gum::warn!( + target: LOG_TARGET, + block_hash = ?relay_block, + ?err, + "Failed to create assignment bitfield" + ); + }, + }; + } else { + gum::warn!( target: LOG_TARGET, - ?candidate_hash, - para_id = ?candidate_receipt.descriptor.para_id, block_hash = ?relay_block, - "Launching approval work.", + ?candidate_hash, + "Cannot get assignment claimed core indices", ); - - // sanity: should always be present. - actions.push(Action::LaunchApproval { - candidate_hash, - indirect_cert, - assignment_tranche: tranche, - relay_block_hash: relay_block, - candidate_index: i as _, - session: block_entry.session(), - executor_params: executor_params.clone(), - candidate: candidate_receipt, - backing_group, - }); } } // Although we checked approval earlier in this function, diff --git a/polkadot/node/core/approval-voting/src/ops.rs b/polkadot/node/core/approval-voting/src/ops.rs index 6f57b2f80e8..a6f0ecf9d1f 100644 --- a/polkadot/node/core/approval-voting/src/ops.rs +++ b/polkadot/node/core/approval-voting/src/ops.rs @@ -25,7 +25,7 @@ use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, GroupInd use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use super::{ - approval_db::v1::{OurAssignment, StoredBlockRange}, + approval_db::v2::{OurAssignment, StoredBlockRange}, backend::{Backend, OverlayedBackend}, persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}, LOG_TARGET, diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index 9b659222027..9cfe1c4cf8d 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -20,16 +20,21 @@ //! Within that context, things are plain-old-data. Within this module, //! data and logic are intertwined. -use polkadot_node_primitives::approval::{AssignmentCert, DelayTranche, RelayVRFStory}; +use polkadot_node_primitives::approval::{ + v1::{DelayTranche, RelayVRFStory}, + v2::{AssignmentCertV2, CandidateBitfield}, +}; use polkadot_primitives::{ BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; -use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice, vec::BitVec}; +use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice}; use std::collections::BTreeMap; +use crate::approval_db::v2::Bitfield; + use super::{criteria::OurAssignment, time::Tick}; /// Metadata regarding a specific tranche of assignments for a specific candidate. @@ -53,8 +58,8 @@ impl TrancheEntry { } } -impl From for TrancheEntry { - fn from(entry: crate::approval_db::v1::TrancheEntry) -> Self { +impl From for TrancheEntry { + fn from(entry: crate::approval_db::v2::TrancheEntry) -> Self { TrancheEntry { tranche: entry.tranche, assignments: entry.assignments.into_iter().map(|(v, t)| (v, t.into())).collect(), @@ -62,7 +67,7 @@ impl From for TrancheEntry { } } -impl From for crate::approval_db::v1::TrancheEntry { +impl From for crate::approval_db::v2::TrancheEntry { fn from(entry: TrancheEntry) -> Self { Self { tranche: entry.tranche, @@ -80,7 +85,7 @@ pub struct ApprovalEntry { our_assignment: Option, our_approval_sig: Option, // `n_validators` bits. - assignments: BitVec, + assigned_validators: Bitfield, approved: bool, } @@ -92,10 +97,17 @@ impl ApprovalEntry { our_assignment: Option, our_approval_sig: Option, // `n_validators` bits. - assignments: BitVec, + assigned_validators: Bitfield, approved: bool, ) -> Self { - Self { tranches, backing_group, our_assignment, our_approval_sig, assignments, approved } + Self { + tranches, + backing_group, + our_assignment, + our_approval_sig, + assigned_validators, + approved, + } } // Access our assignment for this approval entry. @@ -107,7 +119,7 @@ impl ApprovalEntry { pub fn trigger_our_assignment( &mut self, tick_now: Tick, - ) -> Option<(AssignmentCert, ValidatorIndex, DelayTranche)> { + ) -> Option<(AssignmentCertV2, ValidatorIndex, DelayTranche)> { let our = self.our_assignment.as_mut().and_then(|a| { if a.triggered() { return None @@ -131,7 +143,10 @@ impl ApprovalEntry { /// Whether a validator is already assigned. pub fn is_assigned(&self, validator_index: ValidatorIndex) -> bool { - self.assignments.get(validator_index.0 as usize).map(|b| *b).unwrap_or(false) + self.assigned_validators + .get(validator_index.0 as usize) + .map(|b| *b) + .unwrap_or(false) } /// Import an assignment. No-op if already assigned on the same tranche. @@ -158,14 +173,14 @@ impl ApprovalEntry { }; self.tranches[idx].assignments.push((validator_index, tick_now)); - self.assignments.set(validator_index.0 as _, true); + self.assigned_validators.set(validator_index.0 as _, true); } // Produce a bitvec indicating the assignments of all validators up to and // including `tranche`. - pub fn assignments_up_to(&self, tranche: DelayTranche) -> BitVec { + pub fn assignments_up_to(&self, tranche: DelayTranche) -> Bitfield { self.tranches.iter().take_while(|e| e.tranche <= tranche).fold( - bitvec::bitvec![u8, BitOrderLsb0; 0; self.assignments.len()], + bitvec::bitvec![u8, BitOrderLsb0; 0; self.assigned_validators.len()], |mut a, e| { for &(v, _) in &e.assignments { a.set(v.0 as _, true); @@ -193,12 +208,12 @@ impl ApprovalEntry { /// Get the number of validators in this approval entry. pub fn n_validators(&self) -> usize { - self.assignments.len() + self.assigned_validators.len() } /// Get the number of assignments by validators, including the local validator. pub fn n_assignments(&self) -> usize { - self.assignments.count_ones() + self.assigned_validators.count_ones() } /// Get the backing group index of the approval entry. @@ -219,27 +234,27 @@ impl ApprovalEntry { } } -impl From for ApprovalEntry { - fn from(entry: crate::approval_db::v1::ApprovalEntry) -> Self { +impl From for ApprovalEntry { + fn from(entry: crate::approval_db::v2::ApprovalEntry) -> Self { ApprovalEntry { tranches: entry.tranches.into_iter().map(Into::into).collect(), backing_group: entry.backing_group, our_assignment: entry.our_assignment.map(Into::into), our_approval_sig: entry.our_approval_sig.map(Into::into), - assignments: entry.assignments, + assigned_validators: entry.assigned_validators, approved: entry.approved, } } } -impl From for crate::approval_db::v1::ApprovalEntry { +impl From for crate::approval_db::v2::ApprovalEntry { fn from(entry: ApprovalEntry) -> Self { Self { tranches: entry.tranches.into_iter().map(Into::into).collect(), backing_group: entry.backing_group, our_assignment: entry.our_assignment.map(Into::into), our_approval_sig: entry.our_approval_sig.map(Into::into), - assignments: entry.assignments, + assigned_validators: entry.assigned_validators, approved: entry.approved, } } @@ -253,7 +268,7 @@ pub struct CandidateEntry { // Assignments are based on blocks, so we need to track assignments separately // based on the block we are looking at. pub block_assignments: BTreeMap, - pub approvals: BitVec, + pub approvals: Bitfield, } impl CandidateEntry { @@ -290,8 +305,8 @@ impl CandidateEntry { } } -impl From for CandidateEntry { - fn from(entry: crate::approval_db::v1::CandidateEntry) -> Self { +impl From for CandidateEntry { + fn from(entry: crate::approval_db::v2::CandidateEntry) -> Self { CandidateEntry { candidate: entry.candidate, session: entry.session, @@ -305,7 +320,7 @@ impl From for CandidateEntry { } } -impl From for crate::approval_db::v1::CandidateEntry { +impl From for crate::approval_db::v2::CandidateEntry { fn from(entry: CandidateEntry) -> Self { Self { candidate: entry.candidate, @@ -336,8 +351,12 @@ pub struct BlockEntry { // A bitfield where the i'th bit corresponds to the i'th candidate in `candidates`. // The i'th bit is `true` iff the candidate has been approved in the context of this // block. The block can be considered approved if the bitfield has all bits set to `true`. - pub approved_bitfield: BitVec, + pub approved_bitfield: Bitfield, pub children: Vec, + // A list of assignments for which we already distributed the assignment. + // We use this to ensure we don't distribute multiple core assignments twice as we track + // individual wakeups for each core. + distributed_assignments: Bitfield, } impl BlockEntry { @@ -412,6 +431,39 @@ impl BlockEntry { pub fn parent_hash(&self) -> Hash { self.parent_hash } + + /// Mark distributed assignment for many candidate indices. + /// Returns `true` if an assignment was already distributed for the `candidates`. + pub fn mark_assignment_distributed(&mut self, candidates: CandidateBitfield) -> bool { + let bitfield = candidates.into_inner(); + let total_one_bits = self.distributed_assignments.count_ones(); + + let new_len = std::cmp::max(self.distributed_assignments.len(), bitfield.len()); + self.distributed_assignments.resize(new_len, false); + self.distributed_assignments |= bitfield; + + // If the an operation did not change our current bitfied, we return true. + let distributed = total_one_bits == self.distributed_assignments.count_ones(); + + distributed + } +} + +impl From for BlockEntry { + fn from(entry: crate::approval_db::v2::BlockEntry) -> Self { + BlockEntry { + block_hash: entry.block_hash, + parent_hash: entry.parent_hash, + block_number: entry.block_number, + session: entry.session, + slot: entry.slot, + relay_vrf_story: RelayVRFStory(entry.relay_vrf_story), + candidates: entry.candidates, + approved_bitfield: entry.approved_bitfield, + children: entry.children, + distributed_assignments: entry.distributed_assignments, + } + } } impl From for BlockEntry { @@ -426,11 +478,12 @@ impl From for BlockEntry { candidates: entry.candidates, approved_bitfield: entry.approved_bitfield, children: entry.children, + distributed_assignments: Default::default(), } } } -impl From for crate::approval_db::v1::BlockEntry { +impl From for crate::approval_db::v2::BlockEntry { fn from(entry: BlockEntry) -> Self { Self { block_hash: entry.block_hash, @@ -442,6 +495,36 @@ impl From for crate::approval_db::v1::BlockEntry { candidates: entry.candidates, approved_bitfield: entry.approved_bitfield, children: entry.children, + distributed_assignments: entry.distributed_assignments, + } + } +} + +/// Migration helpers. +impl From for CandidateEntry { + fn from(value: crate::approval_db::v1::CandidateEntry) -> Self { + Self { + approvals: value.approvals, + block_assignments: value + .block_assignments + .into_iter() + .map(|(h, ae)| (h, ae.into())) + .collect(), + candidate: value.candidate, + session: value.session, + } + } +} + +impl From for ApprovalEntry { + fn from(value: crate::approval_db::v1::ApprovalEntry) -> Self { + ApprovalEntry { + tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(), + backing_group: value.backing_group, + our_assignment: value.our_assignment.map(|assignment| assignment.into()), + our_approval_sig: value.our_approval_sig, + assigned_validators: value.assignments, + approved: value.approved, } } } diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 0b98f28fbbf..13213c158cd 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -16,10 +16,14 @@ use self::test_helpers::mock::new_leaf; use super::*; +use crate::backend::V1ReadBackend; use polkadot_node_primitives::{ approval::{ - AssignmentCert, AssignmentCertKind, DelayTranche, VrfOutput, VrfProof, VrfSignature, - RELAY_VRF_MODULO_CONTEXT, + v1::{ + AssignmentCert, AssignmentCertKind, DelayTranche, VrfOutput, VrfProof, VrfSignature, + RELAY_VRF_MODULO_CONTEXT, + }, + v2::{AssignmentCertKindV2, AssignmentCertV2}, }, AvailableData, BlockData, PoV, }; @@ -52,7 +56,7 @@ use std::{ }; use super::{ - approval_db::v1::StoredBlockRange, + approval_db::v2::StoredBlockRange, backend::BackendWriteOp, import::tests::{ garbage_vrf_signature, AllowedSlots, BabeEpoch, BabeEpochConfiguration, @@ -112,7 +116,7 @@ fn make_sync_oracle(val: bool) -> (Box, TestSyncOracleHan #[cfg(test)] pub mod test_constants { - use crate::approval_db::v1::Config as DatabaseConfig; + use crate::approval_db::v2::Config as DatabaseConfig; const DATA_COL: u32 = 0; pub(crate) const NUM_COLUMNS: u32 = 1; @@ -162,7 +166,7 @@ impl Clock for MockClock { // This mock clock allows us to manipulate the time and // be notified when wakeups have been triggered. -#[derive(Default)] +#[derive(Default, Debug)] struct MockClockInner { tick: Tick, wakeups: Vec<(Tick, oneshot::Sender<()>)>, @@ -232,7 +236,7 @@ where fn compute_assignments( &self, _keystore: &LocalKeystore, - _relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory, + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, _config: &criteria::Config, _leaving_cores: Vec<( CandidateHash, @@ -245,13 +249,13 @@ where fn check_assignment_cert( &self, - _claimed_core_index: polkadot_primitives::CoreIndex, + _claimed_core_bitfield: polkadot_node_primitives::approval::v2::CoreBitfield, validator_index: ValidatorIndex, _config: &criteria::Config, - _relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory, - _assignment: &polkadot_node_primitives::approval::AssignmentCert, - _backing_group: polkadot_primitives::GroupIndex, - ) -> Result { + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, + _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, + _backing_groups: Vec, + ) -> Result { self.1(validator_index) } } @@ -272,6 +276,18 @@ struct TestStoreInner { candidate_entries: HashMap, } +impl V1ReadBackend for TestStoreInner { + fn load_candidate_entry_v1( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult> { + self.load_candidate_entry(candidate_hash) + } + fn load_block_entry_v1(&self, block_hash: &Hash) -> SubsystemResult> { + self.load_block_entry(block_hash) + } +} + impl Backend for TestStoreInner { fn load_block_entry(&self, block_hash: &Hash) -> SubsystemResult> { Ok(self.block_entries.get(block_hash).cloned()) @@ -343,6 +359,18 @@ pub struct TestStore { store: Arc>, } +impl V1ReadBackend for TestStore { + fn load_candidate_entry_v1( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult> { + self.load_candidate_entry(candidate_hash) + } + fn load_block_entry_v1(&self, block_hash: &Hash) -> SubsystemResult> { + self.load_block_entry(block_hash) + } +} + impl Backend for TestStore { fn load_block_entry(&self, block_hash: &Hash) -> SubsystemResult> { let store = self.store.lock(); @@ -392,6 +420,17 @@ fn garbage_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { AssignmentCert { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } } +fn garbage_assignment_cert_v2(kind: AssignmentCertKindV2) -> AssignmentCertV2 { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"test-garbage"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let out = inout.to_output(); + + AssignmentCertV2 { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } +} + fn sign_approval( key: Sr25519Keyring, candidate_hash: CandidateHash, @@ -468,6 +507,12 @@ fn test_harness>( config: HarnessConfig, test: impl FnOnce(TestHarness) -> T, ) { + let _ = env_logger::builder() + .is_test(true) + .filter(Some("polkadot_node_core_approval_voting"), log::LevelFilter::Trace) + .filter(Some(LOG_TARGET), log::LevelFilter::Trace) + .try_init(); + let HarnessConfig { sync_oracle, sync_oracle_handle, clock, backend, assignment_criteria } = config; @@ -617,12 +662,13 @@ async fn check_and_import_assignment( overseer, FromOrchestra::Communication { msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCert { + IndirectAssignmentCertV2 { block_hash, validator, - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }), + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), }, - candidate_index, + candidate_index.into(), tx, ), }, @@ -631,6 +677,38 @@ async fn check_and_import_assignment( rx } +async fn check_and_import_assignment_v2( + overseer: &mut VirtualOverseer, + block_hash: Hash, + core_indices: Vec, + validator: ValidatorIndex, +) -> oneshot::Receiver { + let (tx, rx) = oneshot::channel(); + overseer_send( + overseer, + FromOrchestra::Communication { + msg: ApprovalVotingMessage::CheckAndImportAssignment( + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: core_indices + .clone() + .into_iter() + .map(|c| CoreIndex(c)) + .collect::>() + .try_into() + .unwrap(), + }), + }, + core_indices.try_into().unwrap(), + tx, + ), + }, + ) + .await; + rx +} struct BlockConfig { slot: Slot, candidates: Option>, @@ -743,7 +821,7 @@ fn session_info(keys: &[Sr25519Keyring]) -> SessionInfo { vec![ValidatorIndex(0)], vec![ValidatorIndex(1)], ]), - n_cores: keys.len() as _, + n_cores: 10, needed_approvals: 2, zeroth_delay_tranche_width: 5, relay_vrf_modulo_samples: 3, @@ -1068,14 +1146,15 @@ fn blank_subsystem_act_on_bad_block() { &mut virtual_overseer, FromOrchestra::Communication { msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCert { + IndirectAssignmentCertV2 { block_hash: bad_block_hash, validator: 0u32.into(), cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0, - }), + }) + .into(), }, - 0u32, + 0u32.into(), tx, ), }, @@ -1331,9 +1410,22 @@ fn subsystem_accepts_duplicate_assignment() { } ); - let block_hash = Hash::repeat_byte(0x01); - let candidate_index = 0; let validator = ValidatorIndex(0); + let candidate_index = 0; + let block_hash = Hash::repeat_byte(0x01); + + let candidate_receipt1 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(1_u32); + receipt + }; + let candidate_receipt2 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(2_u32); + receipt + }; + let candidate_index1 = 0; + let candidate_index2 = 1; // Add block hash 00. ChainBuilder::new() @@ -1341,21 +1433,30 @@ fn subsystem_accepts_duplicate_assignment() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: Some(vec![ + (candidate_receipt1, CoreIndex(0), GroupIndex(1)), + (candidate_receipt2, CoreIndex(1), GroupIndex(1)), + ]), + session_info: None, + }, ) .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( + // Initial assignment. + let rx = check_and_import_assignment_v2( &mut virtual_overseer, block_hash, - candidate_index, + vec![candidate_index1, candidate_index2], validator, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); + // Test with single assigned core. let rx = check_and_import_assignment( &mut virtual_overseer, block_hash, @@ -1366,6 +1467,18 @@ fn subsystem_accepts_duplicate_assignment() { assert_eq!(rx.await, Ok(AssignmentCheckResult::AcceptedDuplicate)); + // Test with multiple assigned cores. This cannot happen in practice, as tranche0 + // assignments are sent first, but we should still ensure correct behavior. + let rx = check_and_import_assignment_v2( + &mut virtual_overseer, + block_hash, + vec![candidate_index1, candidate_index2], + validator, + ) + .await; + + assert_eq!(rx.await, Ok(AssignmentCheckResult::AcceptedDuplicate)); + virtual_overseer }); } @@ -1416,6 +1529,63 @@ fn subsystem_rejects_assignment_with_unknown_candidate() { }); } +#[test] +fn subsystem_rejects_oversized_bitfields() { + test_harness(HarnessConfig::default(), |test_harness| async move { + let TestHarness { mut virtual_overseer, sync_oracle_handle: _sync_oracle_handle, .. } = + test_harness; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let candidate_index = 10; + let validator = ValidatorIndex(0); + + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + ) + .build(&mut virtual_overseer) + .await; + + let rx = check_and_import_assignment( + &mut virtual_overseer, + block_hash, + candidate_index, + validator, + ) + .await; + + assert_eq!( + rx.await, + Ok(AssignmentCheckResult::Bad(AssignmentCheckError::InvalidBitfield( + candidate_index as usize + 1 + ))), + ); + + let rx = check_and_import_assignment_v2( + &mut virtual_overseer, + block_hash, + vec![1, 2, 10, 50], + validator, + ) + .await; + + assert_eq!( + rx.await, + Ok(AssignmentCheckResult::Bad(AssignmentCheckError::InvalidBitfield(51))), + ); + virtual_overseer + }); +} + #[test] fn subsystem_accepts_and_imports_approval_after_assignment() { test_harness(HarnessConfig::default(), |test_harness| async move { @@ -1736,14 +1906,15 @@ fn linear_import_act_on_leaf() { &mut virtual_overseer, FromOrchestra::Communication { msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCert { + IndirectAssignmentCertV2 { block_hash: head, validator: 0u32.into(), cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0, - }), + }) + .into(), }, - 0u32, + 0u32.into(), tx, ), }, @@ -1806,14 +1977,15 @@ fn forkful_import_at_same_height_act_on_leaf() { &mut virtual_overseer, FromOrchestra::Communication { msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCert { + IndirectAssignmentCertV2 { block_hash: head, validator: 0u32.into(), cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0, - }), + }) + .into(), }, - 0u32, + 0u32.into(), tx, ), }, @@ -2257,8 +2429,24 @@ fn subsystem_validate_approvals_cache() { let mut assignments = HashMap::new(); let _ = assignments.insert( CoreIndex(0), - approval_db::v1::OurAssignment { - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }), tranche: 0, validator_index: ValidatorIndex(0), triggered: false, @@ -2355,6 +2543,137 @@ fn subsystem_validate_approvals_cache() { }); } +#[test] +fn subsystem_doesnt_distribute_duplicate_compact_assignments() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + let cert = garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1)].try_into().unwrap(), + }); + + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: cert.clone(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(1), + approval_db::v2::OurAssignment { + cert, + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { + mut virtual_overseer, + sync_oracle_handle: _sync_oracle_handle, + clock, + .. + } = test_harness; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + + let candidate_receipt1 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(1_u32); + receipt + }; + let candidate_receipt2 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(2_u32); + receipt + }; + let candidate_index1 = 0; + let candidate_index2 = 1; + + // Add block hash 00. + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot: Slot::from(0), + candidates: Some(vec![ + (candidate_receipt1.clone(), CoreIndex(0), GroupIndex(1)), + (candidate_receipt2.clone(), CoreIndex(1), GroupIndex(1)), + ]), + session_info: None, + }, + ) + .build(&mut virtual_overseer) + .await; + + // Activate the wakeup present above, and sleep to allow process_wakeups to execute.. + assert_eq!(Some(2), clock.inner.lock().next_wakeup()); + gum::trace!("clock \n{:?}\n", clock.inner.lock()); + + clock.inner.lock().wakeup_all(100); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(100)).await; + + // Assignment is distributed only once from `approval-voting` + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + c_indices, + )) => { + assert_eq!(c_indices, vec![candidate_index1, candidate_index2].try_into().unwrap()); + } + ); + + // Candidate 1 + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + // Candidate 2 + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + // Check if assignment was triggered for candidate 1. + let candidate_entry = + store.load_candidate_entry(&candidate_receipt1.hash()).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + // Check if assignment was triggered for candidate 2. + let candidate_entry = + store.load_candidate_entry(&candidate_receipt2.hash()).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + virtual_overseer + }); +} + /// Ensure that when two assignments are imported, only one triggers the Approval Checking work async fn handle_double_assignment_import( virtual_overseer: &mut VirtualOverseer, @@ -2364,9 +2683,9 @@ async fn handle_double_assignment_import( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( _, - c_index, + c_indices, )) => { - assert_eq!(candidate_index, c_index); + assert_eq!(Into::::into(candidate_index), c_indices); } ); @@ -2379,7 +2698,7 @@ async fn handle_double_assignment_import( _, c_index )) => { - assert_eq!(candidate_index, c_index); + assert_eq!(Into::::into(candidate_index), c_index); } ); @@ -2400,7 +2719,6 @@ async fn handle_double_assignment_import( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) ); - // Assert that there are no more messages being sent by the subsystem assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); } @@ -2475,8 +2793,9 @@ where let mut assignments = HashMap::new(); let _ = assignments.insert( CoreIndex(0), - approval_db::v1::OurAssignment { - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), tranche: our_assigned_tranche, validator_index: ValidatorIndex(0), triggered: false, @@ -2610,14 +2929,12 @@ async fn step_until_done(clock: &MockClock) { futures_timer::Delay::new(Duration::from_millis(200)).await; let mut clock = clock.inner.lock(); if let Some(tick) = clock.next_wakeup() { - println!("TICK: {:?}", tick); relevant_ticks.push(tick); clock.set_tick(tick); } else { break } } - println!("relevant_ticks: {:?}", relevant_ticks); } #[test] diff --git a/polkadot/node/core/approval-voting/src/time.rs b/polkadot/node/core/approval-voting/src/time.rs index 34132dc22b2..a45866402c8 100644 --- a/polkadot/node/core/approval-voting/src/time.rs +++ b/polkadot/node/core/approval-voting/src/time.rs @@ -17,7 +17,7 @@ //! Time utilities for approval voting. use futures::prelude::*; -use polkadot_node_primitives::approval::DelayTranche; +use polkadot_node_primitives::approval::v1::DelayTranche; use sp_consensus_slots::Slot; use std::{ pin::Pin, diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs index cf51ae4d365..837ad7856e7 100644 --- a/polkadot/node/core/dispute-coordinator/src/import.rs +++ b/polkadot/node/core/dispute-coordinator/src/import.rs @@ -117,7 +117,7 @@ pub enum OwnVoteState { } impl OwnVoteState { - fn new(votes: &CandidateVotes, env: &CandidateEnvironment<'_>) -> Self { + fn new(votes: &CandidateVotes, env: &CandidateEnvironment) -> Self { let controlled_indices = env.controlled_indices(); if controlled_indices.is_empty() { return Self::CannotVote diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index e19a1b83a62..32b7f489efa 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -14,10 +14,12 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-jaeger = { path = "../../jaeger" } rand = "0.8" +itertools = "0.10.5" futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } +bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } [dev-dependencies] sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index d8949b1c112..47482eef764 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -23,17 +23,23 @@ #![warn(missing_docs)] +use self::metrics::Metrics; use futures::{channel::oneshot, select, FutureExt as _}; +use itertools::Itertools; +use net_protocol::peer_set::{ProtocolVersion, ValidationVersion}; use polkadot_node_jaeger as jaeger; use polkadot_node_network_protocol::{ - self as net_protocol, + self as net_protocol, filter_by_peer_version, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, - peer_set::{ValidationVersion, MAX_NOTIFICATION_SIZE}, - v1 as protocol_v1, v2 as protocol_v2, PeerId, UnifiedReputationChange as Rep, Versioned, - VersionedValidationProtocol, View, + peer_set::MAX_NOTIFICATION_SIZE, + v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::approval::{ - AssignmentCert, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, + v1::{ + AssignmentCertKind, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, + }, + v2::{AsBitIndex, AssignmentCertKindV2, CandidateBitfield, IndirectAssignmentCertV2}, }; use polkadot_node_subsystem::{ messages::{ @@ -52,8 +58,6 @@ use std::{ time::Duration, }; -use self::metrics::Metrics; - mod metrics; #[cfg(test)] @@ -67,11 +71,15 @@ const COST_DUPLICATE_MESSAGE: Rep = Rep::CostMinorRepeated("Peer sent identical const COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE: Rep = Rep::CostMinor("The vote was valid but too far in the future"); const COST_INVALID_MESSAGE: Rep = Rep::CostMajor("The vote was bad"); +const COST_OVERSIZED_BITFIELD: Rep = Rep::CostMajor("Oversized certificate or candidate bitfield"); const BENEFIT_VALID_MESSAGE: Rep = Rep::BenefitMinor("Peer sent a valid message"); const BENEFIT_VALID_MESSAGE_FIRST: Rep = Rep::BenefitMinorFirst("Valid message with new information"); +// Maximum valid size for the `CandidateBitfield` in the assignment messages. +const MAX_BITFIELD_SIZE: usize = 500; + /// The Approval Distribution subsystem. pub struct ApprovalDistribution { metrics: Metrics, @@ -100,7 +108,144 @@ impl RecentlyOutdated { } } -// In case the original gtid topology mechanisms don't work on their own, we need to trade bandwidth +// Contains topology routing information for assignments and approvals. +struct ApprovalRouting { + required_routing: RequiredRouting, + local: bool, + random_routing: RandomRouting, +} + +// This struct is responsible for tracking the full state of an assignment and grid routing +// information. +struct ApprovalEntry { + // The assignment certificate. + assignment: IndirectAssignmentCertV2, + // The candidates claimed by the certificate. A mapping between bit index and candidate index. + candidates: CandidateBitfield, + // The approval signatures for each `CandidateIndex` claimed by the assignment certificate. + approvals: HashMap, + // The validator index of the assignment signer. + validator_index: ValidatorIndex, + // Information required for gossiping to other peers using the grid topology. + routing_info: ApprovalRouting, +} + +#[derive(Debug)] +enum ApprovalEntryError { + InvalidValidatorIndex, + CandidateIndexOutOfBounds, + InvalidCandidateIndex, + DuplicateApproval, +} + +impl ApprovalEntry { + pub fn new( + assignment: IndirectAssignmentCertV2, + candidates: CandidateBitfield, + routing_info: ApprovalRouting, + ) -> ApprovalEntry { + Self { + validator_index: assignment.validator, + assignment, + approvals: HashMap::with_capacity(candidates.len()), + candidates, + routing_info, + } + } + + // Create a `MessageSubject` to reference the assignment. + pub fn create_assignment_knowledge(&self, block_hash: Hash) -> (MessageSubject, MessageKind) { + ( + MessageSubject(block_hash, self.candidates.clone(), self.validator_index), + MessageKind::Assignment, + ) + } + + // Create a `MessageSubject` to reference the approval. + pub fn create_approval_knowledge( + &self, + block_hash: Hash, + candidate_index: CandidateIndex, + ) -> (MessageSubject, MessageKind) { + ( + MessageSubject(block_hash, candidate_index.into(), self.validator_index), + MessageKind::Approval, + ) + } + + // Updates routing information and returns the previous information if any. + pub fn routing_info_mut(&mut self) -> &mut ApprovalRouting { + &mut self.routing_info + } + + // Get the routing information. + pub fn routing_info(&self) -> &ApprovalRouting { + &self.routing_info + } + + // Update routing information. + pub fn update_required_routing(&mut self, required_routing: RequiredRouting) { + self.routing_info.required_routing = required_routing; + } + + // Records a new approval. Returns error if the claimed candidate is not found or we already + // have received the approval. + pub fn note_approval( + &mut self, + approval: IndirectSignedApprovalVote, + ) -> Result<(), ApprovalEntryError> { + // First do some sanity checks: + // - check validator index matches + // - check claimed candidate + // - check for duplicate approval + if self.validator_index != approval.validator { + return Err(ApprovalEntryError::InvalidValidatorIndex) + } + + if self.candidates.len() <= approval.candidate_index as usize { + return Err(ApprovalEntryError::CandidateIndexOutOfBounds) + } + + if !self.candidates.bit_at(approval.candidate_index.as_bit_index()) { + return Err(ApprovalEntryError::InvalidCandidateIndex) + } + + if self.approvals.contains_key(&approval.candidate_index) { + return Err(ApprovalEntryError::DuplicateApproval) + } + + self.approvals.insert(approval.candidate_index, approval); + Ok(()) + } + + // Get the assignment certiticate and claimed candidates. + pub fn assignment(&self) -> (IndirectAssignmentCertV2, CandidateBitfield) { + (self.assignment.clone(), self.candidates.clone()) + } + + // Get all approvals for all candidates claimed by the assignment. + pub fn approvals(&self) -> Vec { + self.approvals.values().cloned().collect::>() + } + + // Get the approval for a specific candidate index. + pub fn approval(&self, candidate_index: CandidateIndex) -> Option { + self.approvals.get(&candidate_index).cloned() + } + + // Get validator index. + pub fn validator_index(&self) -> ValidatorIndex { + self.validator_index + } +} + +// We keep track of each peer view and protocol version using this struct. +struct PeerEntry { + pub view: View, + pub version: ProtocolVersion, +} + +// In case the original grid topology mechanisms don't work on their own, we need to trade bandwidth // for protocol liveliness by introducing aggression. // // Aggression has 3 levels: @@ -120,7 +265,6 @@ impl RecentlyOutdated { // not to all blocks older than the threshold. Most likely, a few assignments struggle to // be propagated in a single block and this holds up all of its descendants blocks. // Accordingly, we only step on the gas for the block which is most obviously holding up finality. - /// Aggression configuration representation #[derive(Clone)] struct AggressionConfig { @@ -163,15 +307,6 @@ enum Resend { No, } -/// Data stored on a per-peer basis. -#[derive(Debug)] -struct PeerData { - /// The peer's view. - view: View, - /// The peer's protocol version. - version: ValidationVersion, -} - /// The [`State`] struct is responsible for tracking the overall state of the subsystem. /// /// It tracks metadata about our view of the unfinalized chain, @@ -192,7 +327,7 @@ struct State { pending_known: HashMap>, /// Peer data is partially stored here, and partially inline within the [`BlockEntry`]s - peer_data: HashMap, + peer_views: HashMap, /// Keeps a topology for various different sessions. topologies: SessionGridTopologies, @@ -200,12 +335,12 @@ struct State { /// Tracks recently finalized blocks. recent_outdated_blocks: RecentlyOutdated, - /// Config for aggression. - aggression_config: AggressionConfig, - - /// `HashMap` from active leaves to spans + /// HashMap from active leaves to spans spans: HashMap, + /// Aggression configuration. + aggression_config: AggressionConfig, + /// Current approval checking finality lag. approval_checking_lag: BlockNumber, @@ -219,8 +354,11 @@ enum MessageKind { Approval, } +// Utility structure to identify assignments and approvals for specific candidates. +// Assignments can span multiple candidates, while approvals refer to only one candidate. +// #[derive(Debug, Clone, Hash, PartialEq, Eq)] -struct MessageSubject(Hash, CandidateIndex, ValidatorIndex); +struct MessageSubject(Hash, pub CandidateBitfield, ValidatorIndex); #[derive(Debug, Clone, Default)] struct Knowledge { @@ -241,9 +379,11 @@ impl Knowledge { } fn insert(&mut self, message: MessageSubject, kind: MessageKind) -> bool { - match self.known_messages.entry(message) { + let mut success = match self.known_messages.entry(message.clone()) { hash_map::Entry::Vacant(vacant) => { vacant.insert(kind); + // If there are multiple candidates assigned in the message, create + // separate entries for each one. true }, hash_map::Entry::Occupied(mut occupied) => match (*occupied.get(), kind) { @@ -255,7 +395,25 @@ impl Knowledge { true }, }, + }; + + // In case of succesful insertion of multiple candidate assignments create additional + // entries for each assigned candidate. This fakes knowledge of individual assignments, but + // we need to share the same `MessageSubject` with the followup approval candidate index. + if kind == MessageKind::Assignment && success && message.1.count_ones() > 1 { + for candidate_index in message.1.iter_ones() { + success = success && + self.insert( + MessageSubject( + message.0, + vec![candidate_index as u32].try_into().expect("Non-empty vec; qed"), + message.2, + ), + kind, + ); + } } + success } } @@ -289,47 +447,97 @@ struct BlockEntry { candidates: Vec, /// The session index of this block. session: SessionIndex, + /// Approval entries for whole block. These also contain all approvals in the case of multiple + /// candidates being claimed by assignments. + approval_entries: HashMap<(ValidatorIndex, CandidateBitfield), ApprovalEntry>, } -#[derive(Debug)] -enum ApprovalState { - Assigned(AssignmentCert), - Approved(AssignmentCert, ValidatorSignature), -} +impl BlockEntry { + // Returns the peer which currently know this block. + pub fn known_by(&self) -> Vec { + self.known_by.keys().cloned().collect::>() + } -impl ApprovalState { - fn assignment_cert(&self) -> &AssignmentCert { - match *self { - ApprovalState::Assigned(ref cert) => cert, - ApprovalState::Approved(ref cert, _) => cert, + pub fn insert_approval_entry(&mut self, entry: ApprovalEntry) -> &mut ApprovalEntry { + // First map one entry per candidate to the same key we will use in `approval_entries`. + // Key is (Validator_index, CandidateBitfield) that links the `ApprovalEntry` to the (K,V) + // entry in `candidate_entry.messages`. + for claimed_candidate_index in entry.candidates.iter_ones() { + match self.candidates.get_mut(claimed_candidate_index) { + Some(candidate_entry) => { + candidate_entry + .messages + .entry(entry.validator_index()) + .or_insert(entry.candidates.clone()); + }, + None => { + // This should never happen, but if it happens, it means the subsystem is + // broken. + gum::warn!( + target: LOG_TARGET, + hash = ?entry.assignment.block_hash, + ?claimed_candidate_index, + "Missing candidate entry on `import_and_circulate_assignment`", + ); + }, + }; } + + self.approval_entries + .entry((entry.validator_index, entry.candidates.clone())) + .or_insert(entry) } - fn approval_signature(&self) -> Option { - match *self { - ApprovalState::Assigned(_) => None, - ApprovalState::Approved(_, ref sig) => Some(sig.clone()), - } + // Returns a mutable reference of `ApprovalEntry` for `candidate_index` from validator + // `validator_index`. + pub fn approval_entry( + &mut self, + candidate_index: CandidateIndex, + validator_index: ValidatorIndex, + ) -> Option<&mut ApprovalEntry> { + self.candidates + .get(candidate_index as usize) + .map_or(None, |candidate_entry| candidate_entry.messages.get(&validator_index)) + .map_or(None, |candidate_indices| { + self.approval_entries.get_mut(&(validator_index, candidate_indices.clone())) + }) } -} -// routing state bundled with messages for the candidate. Corresponding assignments -// and approvals are stored together and should be routed in the same way, with -// assignments preceding approvals in all cases. -#[derive(Debug)] -struct MessageState { - required_routing: RequiredRouting, - local: bool, - random_routing: RandomRouting, - approval_state: ApprovalState, + // Get all approval entries for a given candidate. + pub fn approval_entries(&self, candidate_index: CandidateIndex) -> Vec<&ApprovalEntry> { + // Get the keys for fetching `ApprovalEntry` from `self.approval_entries`, + let approval_entry_keys = self + .candidates + .get(candidate_index as usize) + .map(|candidate_entry| &candidate_entry.messages); + + if let Some(approval_entry_keys) = approval_entry_keys { + // Ensure no duplicates. + let approval_entry_keys = approval_entry_keys.iter().unique().collect::>(); + + let mut entries = Vec::new(); + for (validator_index, candidate_indices) in approval_entry_keys { + if let Some(entry) = + self.approval_entries.get(&(*validator_index, candidate_indices.clone())) + { + entries.push(entry); + } + } + entries + } else { + vec![] + } + } } -/// Information about candidates in the context of a particular block they are included in. -/// In other words, multiple `CandidateEntry`s may exist for the same candidate, -/// if it is included by multiple blocks - this is likely the case when there are forks. +// Information about candidates in the context of a particular block they are included in. +// In other words, multiple `CandidateEntry`s may exist for the same candidate, +// if it is included by multiple blocks - this is likely the case when there are forks. #[derive(Debug, Default)] struct CandidateEntry { - messages: HashMap, + // The value represents part of the lookup key in `approval_entries` to fetch the assignment + // and existing votes. + messages: HashMap, } #[derive(Debug, Clone, PartialEq)] @@ -348,7 +556,7 @@ impl MessageSource { } enum PendingMessage { - Assignment(IndirectAssignmentCert, CandidateIndex), + Assignment(IndirectAssignmentCertV2, CandidateBitfield), Approval(IndirectSignedApprovalVote), } @@ -365,27 +573,13 @@ impl State { NetworkBridgeEvent::PeerConnected(peer_id, role, version, _) => { // insert a blank view if none already present gum::trace!(target: LOG_TARGET, ?peer_id, ?role, "Peer connected"); - let version = match ValidationVersion::try_from(version).ok() { - Some(v) => v, - None => { - // sanity: network bridge is supposed to detect this already. - gum::error!( - target: LOG_TARGET, - ?peer_id, - ?version, - "Unsupported protocol version" - ); - return - }, - }; - - self.peer_data + self.peer_views .entry(peer_id) - .or_insert_with(|| PeerData { version, view: Default::default() }); + .or_insert(PeerEntry { view: Default::default(), version }); }, NetworkBridgeEvent::PeerDisconnected(peer_id) => { gum::trace!(target: LOG_TARGET, ?peer_id, "Peer disconnected"); - self.peer_data.remove(&peer_id); + self.peer_views.remove(&peer_id); self.blocks.iter_mut().for_each(|(_hash, entry)| { entry.known_by.remove(&peer_id); }) @@ -422,8 +616,8 @@ impl State { live }); }, - NetworkBridgeEvent::PeerMessage(peer_id, msg) => { - self.process_incoming_peer_message(ctx, metrics, peer_id, msg, rng).await; + NetworkBridgeEvent::PeerMessage(peer_id, message) => { + self.process_incoming_peer_message(ctx, metrics, peer_id, message, rng).await; }, NetworkBridgeEvent::UpdatedAuthorityIds { .. } => { // The approval-distribution subsystem doesn't deal with `AuthorityDiscoveryId`s. @@ -462,6 +656,7 @@ impl State { knowledge: Knowledge::default(), candidates, session: meta.session, + approval_entries: HashMap::new(), }); self.topologies.inc_session_refs(meta.session); @@ -484,18 +679,17 @@ impl State { { let sender = ctx.sender(); - for (peer_id, data) in self.peer_data.iter() { - let intersection = data.view.iter().filter(|h| new_hashes.contains(h)); - let view_intersection = - View::new(intersection.cloned(), data.view.finalized_number); + for (peer_id, PeerEntry { view, version }) in self.peer_views.iter() { + let intersection = view.iter().filter(|h| new_hashes.contains(h)); + let view_intersection = View::new(intersection.cloned(), view.finalized_number); Self::unify_with_peer( sender, metrics, &mut self.blocks, &self.topologies, - self.peer_data.len(), + self.peer_views.len(), *peer_id, - data.version, + *version, view_intersection, rng, ) @@ -533,13 +727,13 @@ impl State { for (peer_id, message) in to_import { match message { - PendingMessage::Assignment(assignment, claimed_index) => { + PendingMessage::Assignment(assignment, claimed_indices) => { self.import_and_circulate_assignment( ctx, metrics, MessageSource::Peer(peer_id), assignment, - claimed_index, + claimed_indices, rng, ) .await; @@ -578,32 +772,100 @@ impl State { adjust_required_routing_and_propagate( ctx, - &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| block_entry.session == session, |required_routing, local, validator_index| { - if *required_routing == RequiredRouting::PendingTopology { - *required_routing = topology + if required_routing == &RequiredRouting::PendingTopology { + topology .local_grid_neighbors() - .required_routing_by_index(*validator_index, local); + .required_routing_by_index(*validator_index, local) + } else { + *required_routing } }, + &self.peer_views, ) .await; } + async fn process_incoming_assignments( + &mut self, + ctx: &mut Context, + metrics: &Metrics, + peer_id: PeerId, + assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)>, + rng: &mut R, + ) where + R: CryptoRng + Rng, + { + for (assignment, claimed_indices) in assignments { + if let Some(pending) = self.pending_known.get_mut(&assignment.block_hash) { + let block_hash = &assignment.block_hash; + let validator_index = assignment.validator; + + gum::trace!( + target: LOG_TARGET, + %peer_id, + ?block_hash, + ?claimed_indices, + ?validator_index, + "Pending assignment", + ); + + pending.push((peer_id, PendingMessage::Assignment(assignment, claimed_indices))); + + continue + } + + self.import_and_circulate_assignment( + ctx, + metrics, + MessageSource::Peer(peer_id), + assignment, + claimed_indices, + rng, + ) + .await; + } + } + async fn process_incoming_peer_message( &mut self, ctx: &mut Context, metrics: &Metrics, peer_id: PeerId, - msg: net_protocol::ApprovalDistributionMessage, + msg: Versioned< + protocol_v1::ApprovalDistributionMessage, + protocol_v2::ApprovalDistributionMessage, + protocol_vstaging::ApprovalDistributionMessage, + >, rng: &mut R, ) where R: CryptoRng + Rng, { match msg { + Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Assignments( + assignments, + )) => { + gum::trace!( + target: LOG_TARGET, + peer_id = %peer_id, + num = assignments.len(), + "Processing assignments from a peer", + ); + let sanitized_assignments = + self.sanitize_v2_assignments(peer_id, ctx.sender(), assignments).await; + + self.process_incoming_assignments( + ctx, + metrics, + peer_id, + sanitized_assignments, + rng, + ) + .await; + }, Versioned::V1(protocol_v1::ApprovalDistributionMessage::Assignments(assignments)) | Versioned::V2(protocol_v2::ApprovalDistributionMessage::Assignments(assignments)) => { gum::trace!( @@ -612,38 +874,22 @@ impl State { num = assignments.len(), "Processing assignments from a peer", ); - for (assignment, claimed_index) in assignments.into_iter() { - if let Some(pending) = self.pending_known.get_mut(&assignment.block_hash) { - let message_subject = MessageSubject( - assignment.block_hash, - claimed_index, - assignment.validator, - ); - gum::trace!( - target: LOG_TARGET, - %peer_id, - ?message_subject, - "Pending assignment", - ); - - pending - .push((peer_id, PendingMessage::Assignment(assignment, claimed_index))); - - continue - } + let sanitized_assignments = + self.sanitize_v1_assignments(peer_id, ctx.sender(), assignments).await; - self.import_and_circulate_assignment( - ctx, - metrics, - MessageSource::Peer(peer_id), - assignment, - claimed_index, - rng, - ) - .await; - } + self.process_incoming_assignments( + ctx, + metrics, + peer_id, + sanitized_assignments, + rng, + ) + .await; }, + Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Approvals( + approvals, + )) | Versioned::V1(protocol_v1::ApprovalDistributionMessage::Approvals(approvals)) | Versioned::V2(protocol_v2::ApprovalDistributionMessage::Approvals(approvals)) => { gum::trace!( @@ -654,17 +900,17 @@ impl State { ); for approval_vote in approvals.into_iter() { if let Some(pending) = self.pending_known.get_mut(&approval_vote.block_hash) { - let message_subject = MessageSubject( - approval_vote.block_hash, - approval_vote.candidate_index, - approval_vote.validator, - ); + let block_hash = approval_vote.block_hash; + let candidate_index = approval_vote.candidate_index; + let validator_index = approval_vote.validator; gum::trace!( target: LOG_TARGET, %peer_id, - ?message_subject, - "Pending approval", + ?block_hash, + ?candidate_index, + ?validator_index, + "Pending assignment", ); pending.push((peer_id, PendingMessage::Approval(approval_vote))); @@ -698,14 +944,23 @@ impl State { { gum::trace!(target: LOG_TARGET, ?view, "Peer view change"); let finalized_number = view.finalized_number; - let (peer_protocol_version, old_finalized_number) = match self - .peer_data - .get_mut(&peer_id) - .map(|d| (d.version, std::mem::replace(&mut d.view, view.clone()))) - { - Some((v, view)) => (v, view.finalized_number), - None => return, // unknown peer - }; + + let (old_view, protocol_version) = + if let Some(peer_entry) = self.peer_views.get_mut(&peer_id) { + (Some(std::mem::replace(&mut peer_entry.view, view.clone())), peer_entry.version) + } else { + // This shouldn't happen, but if it does we assume protocol version 1. + gum::warn!( + target: LOG_TARGET, + ?peer_id, + ?view, + "Peer view change for missing `peer_entry`" + ); + + (None, ValidationVersion::V1.into()) + }; + + let old_finalized_number = old_view.map(|v| v.finalized_number).unwrap_or(0); // we want to prune every block known_by peer up to (including) view.finalized_number let blocks = &mut self.blocks; @@ -730,9 +985,9 @@ impl State { metrics, &mut self.blocks, &self.topologies, - self.peer_data.len(), + self.peer_views.len(), peer_id, - peer_protocol_version, + protocol_version, view, rng, ) @@ -773,8 +1028,8 @@ impl State { ctx: &mut Context, metrics: &Metrics, source: MessageSource, - assignment: IndirectAssignmentCert, - claimed_candidate_index: CandidateIndex, + assignment: IndirectAssignmentCertV2, + claimed_candidate_indices: CandidateBitfield, rng: &mut R, ) where R: CryptoRng + Rng, @@ -822,9 +1077,11 @@ impl State { }, }; - // compute metadata on the assignment. - let message_subject = MessageSubject(block_hash, claimed_candidate_index, validator_index); - let message_kind = MessageKind::Assignment; + // Compute metadata on the assignment. + let (message_subject, message_kind) = ( + MessageSubject(block_hash, claimed_candidate_indices.clone(), validator_index), + MessageKind::Assignment, + ); if let Some(peer_id) = source.peer_id() { // check if our knowledge of the peer already contains this assignment @@ -840,6 +1097,7 @@ impl State { ?message_subject, "Duplicate assignment", ); + modify_reputation( &mut self.reputation, ctx.sender(), @@ -847,6 +1105,15 @@ impl State { COST_DUPLICATE_MESSAGE, ) .await; + } else { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + hash = ?block_hash, + ?validator_index, + ?message_subject, + "We sent the message to the peer while peer was sending it to us. Known race condition.", + ); } return } @@ -888,7 +1155,7 @@ impl State { ctx.send_message(ApprovalVotingMessage::CheckAndImportAssignment( assignment.clone(), - claimed_candidate_index, + claimed_candidate_indices.clone(), tx, )) .await; @@ -919,7 +1186,7 @@ impl State { BENEFIT_VALID_MESSAGE_FIRST, ) .await; - entry.knowledge.known_messages.insert(message_subject.clone(), message_kind); + entry.knowledge.insert(message_subject.clone(), message_kind); if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { peer_knowledge.received.insert(message_subject.clone(), message_kind); } @@ -993,7 +1260,7 @@ impl State { // Invariant: to our knowledge, none of the peers except for the `source` know about the // assignment. - metrics.on_assignment_imported(); + metrics.on_assignment_imported(&assignment.cert.kind); let topology = self.topologies.get_topology(entry.session); let local = source == MessageSource::Local; @@ -1002,28 +1269,14 @@ impl State { t.local_grid_neighbors().required_routing_by_index(validator_index, local) }); - let message_state = match entry.candidates.get_mut(claimed_candidate_index as usize) { - Some(candidate_entry) => { - // set the approval state for validator_index to Assigned - // unless the approval state is set already - candidate_entry.messages.entry(validator_index).or_insert_with(|| MessageState { - required_routing, - local, - random_routing: Default::default(), - approval_state: ApprovalState::Assigned(assignment.cert.clone()), - }) - }, - None => { - gum::warn!( - target: LOG_TARGET, - hash = ?block_hash, - ?claimed_candidate_index, - "Expected a candidate entry on import_and_circulate_assignment", - ); + // All the peers that know the relay chain block. + let peers_to_filter = entry.known_by(); - return - }, - }; + let approval_entry = entry.insert_approval_entry(ApprovalEntry::new( + assignment.clone(), + claimed_candidate_indices.clone(), + ApprovalRouting { required_routing, local, random_routing: Default::default() }, + )); // Dispatch the message to all peers in the routing set which // know the block. @@ -1031,83 +1284,65 @@ impl State { // If the topology isn't known yet (race with networking subsystems) // then messages will be sent when we get it. - let assignments = vec![(assignment, claimed_candidate_index)]; - let n_peers_total = self.peer_data.len(); + let assignments = vec![(assignment, claimed_candidate_indices.clone())]; + let n_peers_total = self.peer_views.len(); let source_peer = source.peer_id(); - let mut peer_filter = move |peer| { - if Some(peer) == source_peer.as_ref() { - return false + // Peers that we will send the assignment to. + let mut peers = Vec::new(); + + // Filter destination peers + for peer in peers_to_filter.into_iter() { + if Some(peer) == source_peer { + continue } if let Some(true) = topology .as_ref() - .map(|t| t.local_grid_neighbors().route_to_peer(required_routing, peer)) + .map(|t| t.local_grid_neighbors().route_to_peer(required_routing, &peer)) { - return true + peers.push(peer); + continue } // Note: at this point, we haven't received the message from any peers // other than the source peer, and we just got it, so we haven't sent it // to any peers either. - let route_random = message_state.random_routing.sample(n_peers_total, rng); + let route_random = + approval_entry.routing_info().random_routing.sample(n_peers_total, rng); if route_random { - message_state.random_routing.inc_sent(); - } - - route_random - }; - - let (v1_peers, v2_peers) = { - let peer_data = &self.peer_data; - let peers = entry - .known_by - .keys() - .filter_map(|p| peer_data.get_key_value(p)) - .filter(|(p, _)| peer_filter(p)) - .map(|(p, peer_data)| (*p, peer_data.version)) - .collect::>(); - - // Add the metadata of the assignment to the knowledge of each peer. - for (peer, _) in peers.iter() { - // we already filtered peers above, so this should always be Some - if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { - peer_knowledge.sent.insert(message_subject.clone(), message_kind); - } + approval_entry.routing_info_mut().random_routing.inc_sent(); + peers.push(peer); } + } - if !peers.is_empty() { - gum::trace!( - target: LOG_TARGET, - ?block_hash, - ?claimed_candidate_index, - local = source.peer_id().is_none(), - num_peers = peers.len(), - "Sending an assignment to peers", - ); + // Add the metadata of the assignment to the knowledge of each peer. + for peer in peers.iter() { + // we already filtered peers above, so this should always be Some + if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { + peer_knowledge.sent.insert(message_subject.clone(), message_kind); } + } - let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); - let v2_peers = filter_peers_by_version(&peers, ValidationVersion::V2); - - (v1_peers, v2_peers) - }; + if !peers.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?block_hash, + ?claimed_candidate_indices, + local = source.peer_id().is_none(), + num_peers = peers.len(), + "Sending an assignment to peers", + ); - if !v1_peers.is_empty() { - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - v1_peers, - versioned_assignments_packet(ValidationVersion::V1, assignments.clone()), - )) - .await; - } + let peers = peers + .iter() + .filter_map(|peer_id| { + self.peer_views.get(peer_id).map(|peer_entry| (*peer_id, peer_entry.version)) + }) + .collect::>(); - if !v2_peers.is_empty() { - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - v2_peers, - versioned_assignments_packet(ValidationVersion::V2, assignments.clone()), - )) - .await; + send_assignments_batched(ctx.sender(), assignments, &peers).await; } } @@ -1142,6 +1377,14 @@ impl State { _ => { if let Some(peer_id) = source.peer_id() { if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) { + gum::debug!( + target: LOG_TARGET, + ?peer_id, + ?block_hash, + ?validator_index, + ?candidate_index, + "Approval from a peer is out of view", + ); modify_reputation( &mut self.reputation, ctx.sender(), @@ -1156,7 +1399,7 @@ impl State { }; // compute metadata on the assignment. - let message_subject = MessageSubject(block_hash, candidate_index, validator_index); + let message_subject = MessageSubject(block_hash, candidate_index.into(), validator_index); let message_kind = MessageKind::Approval; if let Some(peer_id) = source.peer_id() { @@ -1306,71 +1549,48 @@ impl State { } } - // Invariant: to our knowledge, none of the peers except for the `source` know about the - // approval. - metrics.on_approval_imported(); - - let required_routing = match entry.candidates.get_mut(candidate_index as usize) { - Some(candidate_entry) => { - // set the approval state for validator_index to Approved - // it should be in assigned state already - match candidate_entry.messages.remove(&validator_index) { - Some(MessageState { - approval_state: ApprovalState::Assigned(cert), - required_routing, - local, - random_routing, - }) => { - candidate_entry.messages.insert( - validator_index, - MessageState { - approval_state: ApprovalState::Approved( - cert, - vote.signature.clone(), - ), - required_routing, - local, - random_routing, - }, - ); - - required_routing - }, - Some(_) => { - unreachable!( - "we only insert it after the metadata, checked the metadata above; qed" - ); - }, - None => { - // this would indicate a bug in approval-voting - gum::warn!( - target: LOG_TARGET, - hash = ?block_hash, - ?candidate_index, - ?validator_index, - "Importing an approval we don't have an assignment for", - ); + let required_routing = match entry.approval_entry(candidate_index, validator_index) { + Some(approval_entry) => { + // Invariant: to our knowledge, none of the peers except for the `source` know about + // the approval. + metrics.on_approval_imported(); + + if let Err(err) = approval_entry.note_approval(vote.clone()) { + // this would indicate a bug in approval-voting: + // - validator index mismatch + // - candidate index mismatch + // - duplicate approval + gum::warn!( + target: LOG_TARGET, + hash = ?block_hash, + ?candidate_index, + ?validator_index, + ?err, + "Possible bug: Vote import failed", + ); - return - }, + return } + + approval_entry.routing_info().required_routing }, None => { + let peer_id = source.peer_id(); + // This indicates a bug in approval-distribution, since we check the knowledge at + // the begining of the function. gum::warn!( target: LOG_TARGET, - hash = ?block_hash, - ?candidate_index, - ?validator_index, - "Expected a candidate entry on import_and_circulate_approval", + ?peer_id, + ?message_subject, + "Unknown approval assignment", ); - + // No rep change as this is caused by an issue return }, }; // Dispatch a ApprovalDistributionV1Message::Approval(vote) // to all peers required by the topology, with the exception of the source peer. - let topology = self.topologies.get_topology(entry.session); let source_peer = source.peer_id(); @@ -1394,57 +1614,32 @@ impl State { in_topology || knowledge.sent.contains(message_subject, MessageKind::Assignment) }; - let (v1_peers, v2_peers) = { - let peer_data = &self.peer_data; - let peers = entry - .known_by - .iter() - .filter_map(|(p, k)| peer_data.get(&p).map(|pd| (p, k, pd.version))) - .filter(|(p, k, _)| peer_filter(p, k)) - .map(|(p, _, v)| (*p, v)) - .collect::>(); - - // Add the metadata of the assignment to the knowledge of each peer. - for (peer, _) in peers.iter() { - // we already filtered peers above, so this should always be Some - if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { - peer_knowledge.sent.insert(message_subject.clone(), message_kind); - } - } - - if !peers.is_empty() { - gum::trace!( - target: LOG_TARGET, - ?block_hash, - ?candidate_index, - local = source.peer_id().is_none(), - num_peers = peers.len(), - "Sending an approval to peers", - ); + let peers = entry + .known_by + .iter() + .filter(|(p, k)| peer_filter(p, k)) + .filter_map(|(p, _)| self.peer_views.get(p).map(|entry| (*p, entry.version))) + .collect::>(); + + // Add the metadata of the assignment to the knowledge of each peer. + for peer in peers.iter() { + // we already filtered peers above, so this should always be Some + if let Some(entry) = entry.known_by.get_mut(&peer.0) { + entry.sent.insert(message_subject.clone(), message_kind); } - - let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); - let v2_peers = filter_peers_by_version(&peers, ValidationVersion::V2); - - (v1_peers, v2_peers) - }; - - let approvals = vec![vote]; - - if !v1_peers.is_empty() { - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - v1_peers, - versioned_approvals_packet(ValidationVersion::V1, approvals.clone()), - )) - .await; } - if !v2_peers.is_empty() { - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - v2_peers, - versioned_approvals_packet(ValidationVersion::V2, approvals), - )) - .await; + if !peers.is_empty() { + let approvals = vec![vote]; + gum::trace!( + target: LOG_TARGET, + ?block_hash, + ?candidate_index, + local = source.peer_id().is_none(), + num_peers = peers.len(), + "Sending an approval to peers", + ); + send_approvals_batched(ctx.sender(), approvals, &peers).await; } } @@ -1475,25 +1670,11 @@ impl State { Some(e) => e, }; - let candidate_entry = match block_entry.candidates.get(index as usize) { - None => { - gum::debug!( - target: LOG_TARGET, - ?hash, - ?index, - "`get_approval_signatures`: could not find candidate entry for given hash and index!" - ); - continue - }, - Some(e) => e, - }; - let sigs = - candidate_entry.messages.iter().filter_map(|(validator_index, message_state)| { - match &message_state.approval_state { - ApprovalState::Approved(_, sig) => Some((*validator_index, sig.clone())), - ApprovalState::Assigned(_) => None, - } - }); + let sigs = block_entry + .approval_entries(index) + .into_iter() + .filter_map(|approval_entry| approval_entry.approval(index)) + .map(|approval| (approval.validator, approval.signature)); all_sigs.extend(sigs); } all_sigs @@ -1506,7 +1687,7 @@ impl State { topologies: &SessionGridTopologies, total_peers: usize, peer_id: PeerId, - peer_protocol_version: ValidationVersion, + protocol_version: ProtocolVersion, view: View, rng: &mut (impl CryptoRng + Rng), ) { @@ -1519,6 +1700,8 @@ impl State { let view_finalized_number = view.finalized_number; for head in view.into_iter() { let mut block = head; + + // Walk the chain back to last finalized block of the peer view. loop { let entry = match entries.get_mut(&block) { Some(entry) if entry.number > view_finalized_number => entry, @@ -1533,19 +1716,16 @@ impl State { } let peer_knowledge = entry.known_by.entry(peer_id).or_default(); - let topology = topologies.get_topology(entry.session); - // Iterate all messages in all candidates. - for (candidate_index, validator, message_state) in - entry.candidates.iter_mut().enumerate().flat_map(|(c_i, c)| { - c.messages.iter_mut().map(move |(k, v)| (c_i as _, k, v)) - }) { + // We want to iterate the `approval_entries` of the block entry as these contain all + // assignments that also link all approval votes. + for approval_entry in entry.approval_entries.values_mut() { // Propagate the message to all peers in the required routing set OR // randomly sample peers. { - let random_routing = &mut message_state.random_routing; - let required_routing = message_state.required_routing; + let required_routing = approval_entry.routing_info().required_routing; + let random_routing = &mut approval_entry.routing_info_mut().random_routing; let rng = &mut *rng; let mut peer_filter = move |peer_id| { let in_topology = topology.as_ref().map_or(false, |t| { @@ -1566,39 +1746,24 @@ impl State { } } - let message_subject = MessageSubject(block, candidate_index, *validator); - - let assignment_message = ( - IndirectAssignmentCert { - block_hash: block, - validator: *validator, - cert: message_state.approval_state.assignment_cert().clone(), - }, - candidate_index, - ); + let assignment_message = approval_entry.assignment(); + let approval_messages = approval_entry.approvals(); + let (assignment_knowledge, message_kind) = + approval_entry.create_assignment_knowledge(block); - let approval_message = - message_state.approval_state.approval_signature().map(|signature| { - IndirectSignedApprovalVote { - block_hash: block, - validator: *validator, - candidate_index, - signature, - } - }); - - if !peer_knowledge.contains(&message_subject, MessageKind::Assignment) { - peer_knowledge - .sent - .insert(message_subject.clone(), MessageKind::Assignment); + // Only send stuff a peer doesn't know in the context of a relay chain block. + if !peer_knowledge.contains(&assignment_knowledge, message_kind) { + peer_knowledge.sent.insert(assignment_knowledge, message_kind); assignments_to_send.push(assignment_message); } - if let Some(approval_message) = approval_message { - if !peer_knowledge.contains(&message_subject, MessageKind::Approval) { - peer_knowledge - .sent - .insert(message_subject.clone(), MessageKind::Approval); + // Filter approval votes. + for approval_message in approval_messages { + let (approval_knowledge, message_kind) = approval_entry + .create_approval_knowledge(block, approval_message.candidate_index); + + if !peer_knowledge.contains(&approval_knowledge, message_kind) { + peer_knowledge.sent.insert(approval_knowledge, message_kind); approvals_to_send.push(approval_message); } } @@ -1612,23 +1777,30 @@ impl State { gum::trace!( target: LOG_TARGET, ?peer_id, + ?protocol_version, num = assignments_to_send.len(), "Sending assignments to unified peer", ); - send_assignments_batched(sender, assignments_to_send, peer_id, peer_protocol_version) - .await; + send_assignments_batched( + sender, + assignments_to_send, + &vec![(peer_id, protocol_version)], + ) + .await; } if !approvals_to_send.is_empty() { gum::trace!( target: LOG_TARGET, ?peer_id, + ?protocol_version, num = approvals_to_send.len(), "Sending approvals to unified peer", ); - send_approvals_batched(sender, approvals_to_send, peer_id, peer_protocol_version).await; + send_approvals_batched(sender, approvals_to_send, &vec![(peer_id, protocol_version)]) + .await; } } @@ -1664,7 +1836,6 @@ impl State { adjust_required_routing_and_propagate( ctx, - &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| { @@ -1686,13 +1857,13 @@ impl State { false } }, - |_, _, _| {}, + |required_routing, _, _| *required_routing, + &self.peer_views, ) .await; adjust_required_routing_and_propagate( ctx, - &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| { @@ -1711,30 +1882,110 @@ impl State { lag = ?self.approval_checking_lag, "Encountered old block pending gossip topology", ); - return + return *required_routing } + let mut new_required_routing = *required_routing; + if config.l1_threshold.as_ref().map_or(false, |t| &self.approval_checking_lag >= t) { // Message originator sends to everyone. - if local && *required_routing != RequiredRouting::All { + if local && new_required_routing != RequiredRouting::All { metrics.on_aggression_l1(); - *required_routing = RequiredRouting::All; + new_required_routing = RequiredRouting::All; } } if config.l2_threshold.as_ref().map_or(false, |t| &self.approval_checking_lag >= t) { // Message originator sends to everyone. Everyone else sends to XY. - if !local && *required_routing != RequiredRouting::GridXY { + if !local && new_required_routing != RequiredRouting::GridXY { metrics.on_aggression_l2(); - *required_routing = RequiredRouting::GridXY; + new_required_routing = RequiredRouting::GridXY; } } + new_required_routing }, + &self.peer_views, ) .await; } + + // Filter out invalid candidate index and certificate core bitfields. + // For each invalid assignment we also punish the peer. + async fn sanitize_v1_assignments( + &mut self, + peer_id: PeerId, + sender: &mut impl overseer::ApprovalDistributionSenderTrait, + assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, + ) -> Vec<(IndirectAssignmentCertV2, CandidateBitfield)> { + let mut sanitized_assignments = Vec::new(); + for (cert, candidate_index) in assignments.into_iter() { + let cert_bitfield_bits = match cert.cert.kind { + AssignmentCertKind::RelayVRFDelay { core_index } => core_index.0 as usize + 1, + // We don't want to run the VRF yet, but the output is always bounded by `n_cores`. + // We assume `candidate_bitfield` length for the core bitfield and we just check + // against `MAX_BITFIELD_SIZE` later. + AssignmentCertKind::RelayVRFModulo { .. } => candidate_index as usize + 1, + }; + + let candidate_bitfield_bits = candidate_index as usize + 1; + + // Ensure bitfields length under hard limit. + if cert_bitfield_bits > MAX_BITFIELD_SIZE || candidate_bitfield_bits > MAX_BITFIELD_SIZE + { + // Punish the peer for the invalid message. + modify_reputation(&mut self.reputation, sender, peer_id, COST_OVERSIZED_BITFIELD) + .await; + } else { + sanitized_assignments.push((cert.into(), candidate_index.into())) + } + } + + sanitized_assignments + } + + // Filter out oversized candidate and certificate core bitfields. + // For each invalid assignment we also punish the peer. + async fn sanitize_v2_assignments( + &mut self, + peer_id: PeerId, + sender: &mut impl overseer::ApprovalDistributionSenderTrait, + assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)>, + ) -> Vec<(IndirectAssignmentCertV2, CandidateBitfield)> { + let mut sanitized_assignments = Vec::new(); + for (cert, candidate_bitfield) in assignments.into_iter() { + let cert_bitfield_bits = match &cert.cert.kind { + AssignmentCertKindV2::RelayVRFDelay { core_index } => core_index.0 as usize + 1, + // We don't want to run the VRF yet, but the output is always bounded by `n_cores`. + // We assume `candidate_bitfield` length for the core bitfield and we just check + // against `MAX_BITFIELD_SIZE` later. + AssignmentCertKindV2::RelayVRFModulo { .. } => candidate_bitfield.len(), + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => + core_bitfield.len(), + }; + + let candidate_bitfield_bits = candidate_bitfield.len(); + + // Our bitfield has `Lsb0`. + let msb = candidate_bitfield_bits - 1; + + // Ensure bitfields length under hard limit. + if cert_bitfield_bits > MAX_BITFIELD_SIZE + || candidate_bitfield_bits > MAX_BITFIELD_SIZE + // Ensure minimum bitfield size - MSB needs to be one. + || !candidate_bitfield.bit_at(msb.as_bit_index()) + { + // Punish the peer for the invalid message. + modify_reputation(&mut self.reputation, sender, peer_id, COST_OVERSIZED_BITFIELD) + .await; + } else { + sanitized_assignments.push((cert, candidate_bitfield)) + } + } + + sanitized_assignments + } } // This adjusts the required routing of messages in blocks that pass the block filter @@ -1752,14 +2003,14 @@ impl State { #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] async fn adjust_required_routing_and_propagate( ctx: &mut Context, - peer_data: &HashMap, blocks: &mut HashMap, topologies: &SessionGridTopologies, block_filter: BlockFilter, routing_modifier: RoutingModifier, + peer_views: &HashMap, ) where BlockFilter: Fn(&mut BlockEntry) -> bool, - RoutingModifier: Fn(&mut RequiredRouting, bool, &ValidatorIndex), + RoutingModifier: Fn(&RequiredRouting, bool, &ValidatorIndex) -> RequiredRouting, { let mut peer_assignments = HashMap::new(); let mut peer_approvals = HashMap::new(); @@ -1771,64 +2022,55 @@ async fn adjust_required_routing_and_propagate t, + None => continue, + }; - if message_state.required_routing.is_empty() { - continue - } + // We just need to iterate the `approval_entries` of the block entry as these contain all + // assignments that also link all approval votes. + for approval_entry in block_entry.approval_entries.values_mut() { + let new_required_routing = routing_modifier( + &approval_entry.routing_info().required_routing, + approval_entry.routing_info().local, + &approval_entry.validator_index(), + ); - let topology = match topologies.get_topology(block_entry.session) { - Some(t) => t, - None => continue, - }; + approval_entry.update_required_routing(new_required_routing); - // Propagate the message to all peers in the required routing set. - let message_subject = MessageSubject(*block_hash, candidate_index, *validator); + if approval_entry.routing_info().required_routing.is_empty() { + continue + } - let assignment_message = ( - IndirectAssignmentCert { - block_hash: *block_hash, - validator: *validator, - cert: message_state.approval_state.assignment_cert().clone(), - }, - candidate_index, - ); - let approval_message = - message_state.approval_state.approval_signature().map(|signature| { - IndirectSignedApprovalVote { - block_hash: *block_hash, - validator: *validator, - candidate_index, - signature, - } - }); + let assignment_message = approval_entry.assignment(); + let approval_messages = approval_entry.approvals(); + let (assignment_knowledge, message_kind) = + approval_entry.create_assignment_knowledge(*block_hash); for (peer, peer_knowledge) in &mut block_entry.known_by { if !topology .local_grid_neighbors() - .route_to_peer(message_state.required_routing, peer) + .route_to_peer(approval_entry.routing_info().required_routing, peer) { continue } - if !peer_knowledge.contains(&message_subject, MessageKind::Assignment) { - peer_knowledge.sent.insert(message_subject.clone(), MessageKind::Assignment); + // Only send stuff a peer doesn't know in the context of a relay chain block. + if !peer_knowledge.contains(&assignment_knowledge, message_kind) { + peer_knowledge.sent.insert(assignment_knowledge.clone(), message_kind); peer_assignments .entry(*peer) .or_insert_with(Vec::new) .push(assignment_message.clone()); } - if let Some(approval_message) = approval_message.as_ref() { - if !peer_knowledge.contains(&message_subject, MessageKind::Approval) { - peer_knowledge.sent.insert(message_subject.clone(), MessageKind::Approval); + // Filter approval votes. + for approval_message in &approval_messages { + let (approval_knowledge, message_kind) = approval_entry + .create_approval_knowledge(*block_hash, approval_message.candidate_index); + + if !peer_knowledge.contains(&approval_knowledge, message_kind) { + peer_knowledge.sent.insert(approval_knowledge, message_kind); peer_approvals .entry(*peer) .or_insert_with(Vec::new) @@ -1840,24 +2082,32 @@ async fn adjust_required_routing_and_propagate continue, - Some(v) => v, - }; - - send_assignments_batched(ctx.sender(), assignments_packet, peer, peer_protocol_version) + if let Some(peer_view) = peer_views.get(&peer) { + send_assignments_batched( + ctx.sender(), + assignments_packet, + &vec![(peer, peer_view.version)], + ) .await; + } else { + // This should never happen. + gum::warn!(target: LOG_TARGET, ?peer, "Unknown protocol version for peer",); + } } for (peer, approvals_packet) in peer_approvals { - let peer_protocol_version = match peer_data.get(&peer).map(|pd| pd.version) { - None => continue, - Some(v) => v, - }; - - send_approvals_batched(ctx.sender(), approvals_packet, peer, peer_protocol_version).await; + if let Some(peer_view) = peer_views.get(&peer) { + send_approvals_batched( + ctx.sender(), + approvals_packet, + &vec![(peer, peer_view.version)], + ) + .await; + } else { + // This should never happen. + gum::warn!(target: LOG_TARGET, ?peer, "Unknown protocol version for peer",); + } } } @@ -1959,12 +2209,21 @@ impl ApprovalDistribution { ApprovalDistributionMessage::NewBlocks(metas) => { state.handle_new_blocks(ctx, metrics, metas, rng).await; }, - ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index) => { + ApprovalDistributionMessage::DistributeAssignment(cert, candidate_indices) => { + let _span = state + .spans + .get(&cert.block_hash) + .map(|span| span.child("import-and-distribute-assignment")) + .unwrap_or_else(|| jaeger::Span::new(&cert.block_hash, "distribute-assignment")) + .with_string_tag("block-hash", format!("{:?}", cert.block_hash)) + .with_stage(jaeger::Stage::ApprovalDistribution); + gum::debug!( target: LOG_TARGET, - "Distributing our assignment on candidate (block={}, index={})", - cert.block_hash, - candidate_index, + ?candidate_indices, + block_hash = ?cert.block_hash, + assignment_kind = ?cert.cert.kind, + "Distributing our assignment on candidates", ); state @@ -1973,7 +2232,7 @@ impl ApprovalDistribution { &metrics, MessageSource::Local, cert, - candidate_index, + candidate_indices, rng, ) .await; @@ -2007,49 +2266,6 @@ impl ApprovalDistribution { } } -fn versioned_approvals_packet( - version: ValidationVersion, - approvals: Vec, -) -> VersionedValidationProtocol { - match version { - ValidationVersion::V1 => - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(approvals), - )), - ValidationVersion::V2 => - Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( - protocol_v2::ApprovalDistributionMessage::Approvals(approvals), - )), - } -} - -fn versioned_assignments_packet( - version: ValidationVersion, - assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, -) -> VersionedValidationProtocol { - match version { - ValidationVersion::V1 => - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments), - )), - ValidationVersion::V2 => - Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( - protocol_v2::ApprovalDistributionMessage::Assignments(assignments), - )), - } -} - -fn filter_peers_by_version( - peers: &[(PeerId, ValidationVersion)], - version: ValidationVersion, -) -> Vec { - peers - .iter() - .filter(|(_, v)| v == &version) - .map(|(peer_id, _)| *peer_id) - .collect() -} - #[overseer::subsystem(ApprovalDistribution, error=SubsystemError, prefix=self::overseer)] impl ApprovalDistribution { fn start(self, ctx: Context) -> SpawnedSubsystem { @@ -2074,7 +2290,7 @@ const fn ensure_size_not_zero(size: usize) -> usize { /// the protocol configuration. pub const MAX_ASSIGNMENT_BATCH_SIZE: usize = ensure_size_not_zero( MAX_NOTIFICATION_SIZE as usize / - std::mem::size_of::<(IndirectAssignmentCert, CandidateIndex)>() / + std::mem::size_of::<(IndirectAssignmentCertV2, CandidateIndex)>() / 3, ); @@ -2083,6 +2299,57 @@ pub const MAX_APPROVAL_BATCH_SIZE: usize = ensure_size_not_zero( MAX_NOTIFICATION_SIZE as usize / std::mem::size_of::() / 3, ); +// Low level helper for sending assignments. +async fn send_assignments_batched_inner( + sender: &mut impl overseer::ApprovalDistributionSenderTrait, + batch: impl IntoIterator, + peers: Vec, + peer_version: ValidationVersion, +) { + if peer_version == ValidationVersion::VStaging { + sender + .send_message(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments( + batch.into_iter().collect(), + ), + )), + )) + .await; + } else { + // Create a batch of v1 assignments from v2 assignments that are compatible with v1. + // `IndirectAssignmentCertV2` -> `IndirectAssignmentCert` + let batch = batch + .into_iter() + .filter_map(|(cert, candidates)| { + cert.try_into().ok().map(|cert| { + ( + cert, + // First 1 bit index is the candidate index. + candidates + .first_one() + .map(|index| index as CandidateIndex) + .expect("Assignment was checked for not being empty; qed"), + ) + }) + }) + .collect(); + let message = if peer_version == ValidationVersion::V1 { + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(batch), + )) + } else { + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Assignments(batch), + )) + }; + sender + .send_message(NetworkBridgeTxMessage::SendValidationMessage(peers, message)) + .await; + } +} + /// Send assignments while honoring the `max_notification_size` of the protocol. /// /// Splitting the messages into multiple notifications allows more granular processing at the @@ -2090,37 +2357,121 @@ pub const MAX_APPROVAL_BATCH_SIZE: usize = ensure_size_not_zero( /// of assignments and can `select!` other tasks. pub(crate) async fn send_assignments_batched( sender: &mut impl overseer::ApprovalDistributionSenderTrait, - assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, - peer: PeerId, - protocol_version: ValidationVersion, + v2_assignments: impl IntoIterator + Clone, + peers: &[(PeerId, ProtocolVersion)], ) { - let mut batches = assignments.into_iter().peekable(); + let v1_peers = filter_by_peer_version(peers, ValidationVersion::V1.into()); + let v2_peers = filter_by_peer_version(peers, ValidationVersion::V2.into()); + let vstaging_peers = filter_by_peer_version(peers, ValidationVersion::VStaging.into()); + + // V1 and V2 validation protocol do not have any changes with regard to + // ApprovalDistributionMessage so they can be treated the same. + if !v1_peers.is_empty() || !v2_peers.is_empty() { + // Older peers(v1) do not understand `AssignmentsV2` messages, so we have to filter these + // out. + let v1_assignments = v2_assignments + .clone() + .into_iter() + .filter(|(_, candidates)| candidates.count_ones() == 1); + + let mut v1_batches = v1_assignments.peekable(); + + while v1_batches.peek().is_some() { + let batch: Vec<_> = v1_batches.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect(); + if !v1_peers.is_empty() { + send_assignments_batched_inner( + sender, + batch.clone(), + v1_peers.clone(), + ValidationVersion::V1, + ) + .await; + } - while batches.peek().is_some() { - let batch: Vec<_> = batches.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect(); - let versioned = versioned_assignments_packet(protocol_version, batch); + if !v2_peers.is_empty() { + send_assignments_batched_inner( + sender, + batch, + v2_peers.clone(), + ValidationVersion::V2, + ) + .await; + } + } + } - sender - .send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], versioned)) + if !vstaging_peers.is_empty() { + let mut vstaging = v2_assignments.into_iter().peekable(); + + while vstaging.peek().is_some() { + let batch = vstaging.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect::>(); + send_assignments_batched_inner( + sender, + batch, + vstaging_peers.clone(), + ValidationVersion::VStaging, + ) .await; + } } } -/// Send approvals while honoring the `max_notification_size` of the protocol. +/// Send approvals while honoring the `max_notification_size` of the protocol and peer version. pub(crate) async fn send_approvals_batched( sender: &mut impl overseer::ApprovalDistributionSenderTrait, - approvals: Vec, - peer: PeerId, - protocol_version: ValidationVersion, + approvals: impl IntoIterator + Clone, + peers: &[(PeerId, ProtocolVersion)], ) { - let mut batches = approvals.into_iter().peekable(); + let v1_peers = filter_by_peer_version(peers, ValidationVersion::V1.into()); + let v2_peers = filter_by_peer_version(peers, ValidationVersion::V2.into()); + let vstaging_peers = filter_by_peer_version(peers, ValidationVersion::VStaging.into()); + + if !v1_peers.is_empty() || !v2_peers.is_empty() { + let mut batches = approvals.clone().into_iter().peekable(); + + while batches.peek().is_some() { + let batch: Vec<_> = batches.by_ref().take(MAX_APPROVAL_BATCH_SIZE).collect(); + + if !v1_peers.is_empty() { + sender + .send_message(NetworkBridgeTxMessage::SendValidationMessage( + v1_peers.clone(), + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(batch.clone()), + )), + )) + .await; + } - while batches.peek().is_some() { - let batch: Vec<_> = batches.by_ref().take(MAX_APPROVAL_BATCH_SIZE).collect(); - let versioned = versioned_approvals_packet(protocol_version, batch); + if !v2_peers.is_empty() { + sender + .send_message(NetworkBridgeTxMessage::SendValidationMessage( + v2_peers.clone(), + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Approvals(batch), + )), + )) + .await; + } + } + } - sender - .send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], versioned)) - .await; + if !vstaging_peers.is_empty() { + let mut batches = approvals.into_iter().peekable(); + + while batches.peek().is_some() { + let batch: Vec<_> = batches.by_ref().take(MAX_APPROVAL_BATCH_SIZE).collect(); + + sender + .send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_peers.clone(), + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Approvals(batch), + ), + ), + )) + .await; + } } } diff --git a/polkadot/node/network/approval-distribution/src/metrics.rs b/polkadot/node/network/approval-distribution/src/metrics.rs index 896866ce099..6864259e6fd 100644 --- a/polkadot/node/network/approval-distribution/src/metrics.rs +++ b/polkadot/node/network/approval-distribution/src/metrics.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . use polkadot_node_metrics::metrics::{prometheus, Metrics as MetricsTrait}; +use polkadot_node_primitives::approval::v2::AssignmentCertKindV2; /// Approval Distribution metrics. #[derive(Default, Clone)] @@ -22,21 +23,34 @@ pub struct Metrics(Option); #[derive(Clone)] struct MetricsInner { - assignments_imported_total: prometheus::Counter, + assignments_imported_total: prometheus::CounterVec, approvals_imported_total: prometheus::Counter, unified_with_peer_total: prometheus::Counter, aggression_l1_messages_total: prometheus::Counter, aggression_l2_messages_total: prometheus::Counter, - time_unify_with_peer: prometheus::Histogram, time_import_pending_now_known: prometheus::Histogram, time_awaiting_approval_voting: prometheus::Histogram, } +trait AsLabel { + fn as_label(&self) -> &str; +} + +impl AsLabel for &AssignmentCertKindV2 { + fn as_label(&self) -> &str { + match self { + AssignmentCertKindV2::RelayVRFDelay { .. } => "VRF Delay", + AssignmentCertKindV2::RelayVRFModulo { .. } => "VRF Modulo", + AssignmentCertKindV2::RelayVRFModuloCompact { .. } => "VRF Modulo Compact", + } + } +} + impl Metrics { - pub(crate) fn on_assignment_imported(&self) { + pub(crate) fn on_assignment_imported(&self, kind: &AssignmentCertKindV2) { if let Some(metrics) = &self.0 { - metrics.assignments_imported_total.inc(); + metrics.assignments_imported_total.with_label_values(&[kind.as_label()]).inc(); } } @@ -89,9 +103,12 @@ impl MetricsTrait for Metrics { fn try_register(registry: &prometheus::Registry) -> Result { let metrics = MetricsInner { assignments_imported_total: prometheus::register( - prometheus::Counter::new( - "polkadot_parachain_assignments_imported_total", - "Number of valid assignments imported locally or from other peers.", + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_parachain_assignments_imported_total", + "Number of valid assignments imported locally or from other peers.", + ), + &["kind"], )?, registry, )?, @@ -124,10 +141,16 @@ impl MetricsTrait for Metrics { registry, )?, time_unify_with_peer: prometheus::register( - prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_time_unify_with_peer", - "Time spent within fn `unify_with_peer`.", - ).buckets(vec![0.000625, 0.00125,0.0025, 0.005, 0.0075, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,]))?, + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_time_unify_with_peer", + "Time spent within fn `unify_with_peer`.", + ) + .buckets(vec![ + 0.000625, 0.00125, 0.0025, 0.005, 0.0075, 0.01, 0.025, 0.05, 0.1, 0.25, + 0.5, 1.0, 2.5, 5.0, 10.0, + ]), + )?, registry, )?, time_import_pending_now_known: prometheus::register( diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 29c7d8aa45d..33c38c7c5df 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -24,20 +24,26 @@ use polkadot_node_network_protocol::{ view, ObservedRole, }; use polkadot_node_primitives::approval::{ - AssignmentCertKind, VrfOutput, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT, + v1::{ + AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, VrfOutput, VrfProof, + VrfSignature, + }, + v2::{ + AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, IndirectAssignmentCertV2, + RELAY_VRF_MODULO_CONTEXT, + }, }; use polkadot_node_subsystem::messages::{ network_bridge_event, AllMessages, ApprovalCheckError, ReportPeerMessage, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt as _}; -use polkadot_primitives::{AuthorityDiscoveryId, BlakeTwo256, HashT}; +use polkadot_primitives::{AuthorityDiscoveryId, BlakeTwo256, CoreIndex, HashT}; use polkadot_primitives_test_helpers::dummy_signature; use rand::SeedableRng; use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; use sp_core::crypto::Pair as PairT; use std::time::Duration; - type VirtualOverseer = test_helpers::TestSubsystemContextHandle; fn test_harness>( @@ -219,15 +225,15 @@ async fn setup_gossip_topology( async fn setup_peer_with_view( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, - validation_version: ValidationVersion, view: View, + version: ValidationVersion, ) { overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( *peer_id, ObservedRole::Full, - validation_version.into(), + version.into(), None, )), ) @@ -244,12 +250,43 @@ async fn setup_peer_with_view( async fn send_message_from_peer( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, - msg: net_protocol::ApprovalDistributionMessage, + msg: protocol_v1::ApprovalDistributionMessage, +) { + overseer_send( + virtual_overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( + *peer_id, + Versioned::V1(msg), + )), + ) + .await; +} + +async fn send_message_from_peer_v2( + virtual_overseer: &mut VirtualOverseer, + peer_id: &PeerId, + msg: protocol_v2::ApprovalDistributionMessage, ) { overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - *peer_id, msg, + *peer_id, + Versioned::V2(msg), + )), + ) + .await; +} + +async fn send_message_from_peer_vstaging( + virtual_overseer: &mut VirtualOverseer, + peer_id: &PeerId, + msg: protocol_vstaging::ApprovalDistributionMessage, +) { + overseer_send( + virtual_overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( + *peer_id, + Versioned::VStaging(msg), )), ) .await; @@ -273,6 +310,28 @@ fn fake_assignment_cert(block_hash: Hash, validator: ValidatorIndex) -> Indirect } } +fn fake_assignment_cert_v2( + block_hash: Hash, + validator: ValidatorIndex, + core_bitfield: CoreBitfield, +) -> IndirectAssignmentCertV2 { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let out = inout.to_output(); + + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield }, + vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) }, + }, + } +} + async fn expect_reputation_change( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, @@ -331,9 +390,9 @@ fn try_import_the_same_assignment() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; - setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -353,7 +412,7 @@ fn try_import_the_same_assignment() { let assignments = vec![(cert.clone(), 0u32)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer_a, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_a, msg).await; expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; @@ -362,10 +421,11 @@ fn try_import_the_same_assignment() { overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( assignment, - 0u32, + claimed_indices, tx, )) => { - assert_eq!(assignment, cert); + assert_eq!(claimed_indices, 0u32.into()); + assert_eq!(assignment, cert.into()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -385,12 +445,104 @@ fn try_import_the_same_assignment() { } ); - // setup new peer - setup_peer_with_view(overseer, &peer_d, ValidationVersion::V1, view![]).await; + // setup new peer with V2 + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await; // send the same assignment from peer_d let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_d, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_d, msg).await; + + expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }); +} + +/// Just like `try_import_the_same_assignment` but use `VRFModuloCompact` assignments for multiple +/// cores. +#[test] +fn try_import_the_same_assignment_v2() { + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::VStaging).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cores = vec![1, 2, 3, 4]; + let core_bitfield: CoreBitfield = cores + .iter() + .map(|index| CoreIndex(*index)) + .collect::>() + .try_into() + .unwrap(); + + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); + let assignments = vec![(cert.clone(), cores.clone().try_into().unwrap())]; + + let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_vstaging(overseer, &peer_a, msg).await; + + expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; + + // send an `Accept` message from the Approval Voting subsystem + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( + assignment, + claimed_indices, + tx, + )) => { + assert_eq!(claimed_indices, cores.try_into().unwrap()); + assert_eq!(assignment, cert.into()); + tx.send(AssignmentCheckResult::Accepted).unwrap(); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert_eq!(assignments.len(), 1); + } + ); + + // setup new peer + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await; + + // send the same assignment from peer_d + let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer_vstaging(overseer, &peer_d, msg).await; expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; @@ -413,7 +565,7 @@ fn delay_reputation_change() { let overseer = &mut virtual_overseer; // Setup peers - setup_peer_with_view(overseer, &peer, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, &peer, view![], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -433,17 +585,18 @@ fn delay_reputation_change() { let assignments = vec![(cert.clone(), 0u32)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer, msg).await; // send an `Accept` message from the Approval Voting subsystem assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( assignment, - 0u32, + claimed_candidates, tx, )) => { - assert_eq!(assignment, cert); + assert_eq!(assignment.cert, cert.cert.into()); + assert_eq!(claimed_candidates, vec![0u32].try_into().unwrap()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -474,7 +627,7 @@ fn spam_attack_results_in_negative_reputation_change() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; let peer = &peer_a; - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; // new block `hash_b` with 20 candidates let candidates_count = 20; @@ -501,7 +654,7 @@ fn spam_attack_results_in_negative_reputation_change() { .collect(); let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; + send_message_from_peer(overseer, peer, msg.clone()).await; for i in 0..candidates_count { expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; @@ -513,8 +666,8 @@ fn spam_attack_results_in_negative_reputation_change() { claimed_candidate_index, tx, )) => { - assert_eq!(assignment, assignments[i].0); - assert_eq!(claimed_candidate_index, assignments[i].1); + assert_eq!(assignment, assignments[i].0.clone().into()); + assert_eq!(claimed_candidate_index, assignments[i].1.into()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -533,7 +686,7 @@ fn spam_attack_results_in_negative_reputation_change() { .await; // send the assignments again - send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; + send_message_from_peer(overseer, peer, msg.clone()).await; // each of them will incur `COST_UNEXPECTED_MESSAGE`, not only the first one for _ in 0..candidates_count { @@ -558,7 +711,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; let peer = &peer_a; - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; // new block `hash` with 1 candidates let meta = BlockApprovalMeta { @@ -578,7 +731,10 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let cert = fake_assignment_cert(hash, validator_index); overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -610,12 +766,12 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { // the peer could send us it as well let assignments = vec![(cert, candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; + send_message_from_peer(overseer, peer, msg.clone()).await; assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "we should not punish the peer"); // send the assignments again - send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; + send_message_from_peer(overseer, peer, msg).await; // now we should expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; @@ -633,10 +789,10 @@ fn import_approval_happy_path() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; - // setup peers - setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; - setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await; + // setup peers with V1 and V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -656,10 +812,14 @@ fn import_approval_happy_path() { let cert = fake_assignment_cert(hash, validator_index); overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; + // 1 peer is v1 assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( @@ -668,7 +828,21 @@ fn import_approval_happy_path() { protocol_v1::ApprovalDistributionMessage::Assignments(assignments) )) )) => { - assert_eq!(peers.len(), 2); + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + // 1 peer is v2 + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); assert_eq!(assignments.len(), 1); } ); @@ -681,7 +855,7 @@ fn import_approval_happy_path() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_b, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -722,8 +896,8 @@ fn import_approval_bad() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; - setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -749,14 +923,14 @@ fn import_approval_bad() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_b, msg).await; expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await; // now import an assignment from peer_b let assignments = vec![(cert.clone(), candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_b, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -765,8 +939,8 @@ fn import_approval_bad() { i, tx, )) => { - assert_eq!(assignment, cert); - assert_eq!(i, candidate_index); + assert_eq!(assignment, cert.into()); + assert_eq!(i, candidate_index.into()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -775,7 +949,7 @@ fn import_approval_bad() { // and try again let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peer_b, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -911,12 +1085,20 @@ fn update_peer_view() { let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(0)); let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(0)); - overseer_send(overseer, ApprovalDistributionMessage::DistributeAssignment(cert_a, 0)).await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()), + ) + .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeAssignment(cert_b, 0)).await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()), + ) + .await; // connect a peer - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_a]).await; + setup_peer_with_view(overseer, peer, view![hash_a], ValidationVersion::V1).await; // we should send relevant assignments to the peer assert_matches!( @@ -934,7 +1116,7 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(0)); + assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(0)); assert_eq!( state .blocks @@ -965,7 +1147,7 @@ fn update_peer_view() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_c.clone(), 0), + ApprovalDistributionMessage::DistributeAssignment(cert_c.clone().into(), 0.into()), ) .await; @@ -986,7 +1168,7 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(2)); + assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(2)); assert_eq!( state .blocks @@ -1016,10 +1198,7 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!( - state.peer_data.get(peer).map(|data| data.view.finalized_number), - Some(finalized_number) - ); + assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(finalized_number)); assert!(state.blocks.get(&hash_c).unwrap().known_by.get(peer).is_none()); } @@ -1034,7 +1213,7 @@ fn import_remotely_then_locally() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup the peer - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -1054,7 +1233,7 @@ fn import_remotely_then_locally() { let cert = fake_assignment_cert(hash, validator_index); let assignments = vec![(cert.clone(), candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; + send_message_from_peer(overseer, peer, msg).await; // send an `Accept` message from the Approval Voting subsystem assert_matches!( @@ -1064,8 +1243,8 @@ fn import_remotely_then_locally() { i, tx, )) => { - assert_eq!(assignment, cert); - assert_eq!(i, candidate_index); + assert_eq!(assignment, cert.clone().into()); + assert_eq!(i, candidate_index.into()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -1075,7 +1254,10 @@ fn import_remotely_then_locally() { // import the same assignment locally overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1089,7 +1271,7 @@ fn import_remotely_then_locally() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; + send_message_from_peer(overseer, peer, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -1147,7 +1329,10 @@ fn sends_assignments_even_when_state_is_approved() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1155,7 +1340,7 @@ fn sends_assignments_even_when_state_is_approved() { .await; // connect the peer. - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; @@ -1191,6 +1376,112 @@ fn sends_assignments_even_when_state_is_approved() { }); } +/// Same as `sends_assignments_even_when_state_is_approved_v2` but with `VRFModuloCompact` +/// assignemnts. +#[test] +fn sends_assignments_even_when_state_is_approved_v2() { + let peer_a = PeerId::random(); + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + let peer = &peer_a; + + let _ = test_harness(State::default(), |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 4], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let validator_index = ValidatorIndex(0); + let cores = vec![0, 1, 2, 3]; + let candidate_bitfield: CandidateBitfield = cores.clone().try_into().unwrap(); + + let core_bitfield: CoreBitfield = cores + .iter() + .map(|index| CoreIndex(*index)) + .collect::>() + .try_into() + .unwrap(); + + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); + + // Assumes candidate index == core index. + let approvals = cores + .iter() + .map(|core| IndirectSignedApprovalVote { + block_hash: hash, + candidate_index: *core, + validator: validator_index, + signature: dummy_signature(), + }) + .collect::>(); + + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_bitfield.clone(), + ), + ) + .await; + + for approval in &approvals { + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone()), + ) + .await; + } + + // connect the peer. + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::VStaging).await; + + let assignments = vec![(cert.clone(), candidate_bitfield.clone())]; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_assignments, assignments); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + // Construct a hashmaps of approvals for comparison. Approval distribution reorders messages because they are kept in a + // hashmap as well. + let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::>(); + let approvals = approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::>(); + + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_approvals, approvals); + } + ); + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }); +} + /// /// /// 1. Receive remote peer view update with an unknown head @@ -1219,7 +1510,7 @@ fn race_condition_in_local_vs_remote_view_update() { }; // This will send a peer view that is ahead of our view - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_b]).await; + setup_peer_with_view(overseer, peer, view![hash_b], ValidationVersion::V1).await; // Send our view update to include a new head overseer_send( @@ -1240,7 +1531,7 @@ fn race_condition_in_local_vs_remote_view_update() { .collect(); let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; + send_message_from_peer(overseer, peer, msg.clone()).await; // This will handle pending messages being processed let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); @@ -1257,8 +1548,8 @@ fn race_condition_in_local_vs_remote_view_update() { claimed_candidate_index, tx, )) => { - assert_eq!(assignment, assignments[i].0); - assert_eq!(claimed_candidate_index, assignments[i].1); + assert_eq!(assignment, assignments[i].0.clone().into()); + assert_eq!(claimed_candidate_index, assignments[i].1.into()); tx.send(AssignmentCheckResult::Accepted).unwrap(); } ); @@ -1283,7 +1574,7 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // Set up a gossip topology. @@ -1325,7 +1616,10 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1388,7 +1682,7 @@ fn propagates_assignments_along_unshared_dimension() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // Set up a gossip topology. @@ -1424,7 +1718,7 @@ fn propagates_assignments_along_unshared_dimension() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peers[99].0, msg).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -1473,7 +1767,7 @@ fn propagates_assignments_along_unshared_dimension() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peers[99].0, msg).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -1530,7 +1824,7 @@ fn propagates_to_required_after_connect() { // Connect all peers except omitted. for (i, (peer, _)) in peers.iter().enumerate() { if !omitted.contains(&i) { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } } @@ -1573,7 +1867,10 @@ fn propagates_to_required_after_connect() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1619,7 +1916,7 @@ fn propagates_to_required_after_connect() { ); for i in omitted.iter().copied() { - setup_peer_with_view(overseer, &peers[i].0, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peers[i].0, view![hash], ValidationVersion::V1).await; assert_matches!( overseer_recv(overseer).await, @@ -1668,7 +1965,7 @@ fn sends_to_more_peers_after_getting_topology() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // new block `hash_a` with 1 candidates @@ -1698,7 +1995,10 @@ fn sends_to_more_peers_after_getting_topology() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1820,7 +2120,7 @@ fn originator_aggression_l1() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // new block `hash_a` with 1 candidates @@ -1857,7 +2157,10 @@ fn originator_aggression_l1() { overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), ) .await; @@ -1979,7 +2282,7 @@ fn non_originator_aggression_l1() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // new block `hash_a` with 1 candidates @@ -2008,12 +2311,12 @@ fn non_originator_aggression_l1() { ) .await; - let assignments = vec![(cert.clone(), candidate_index)]; + let assignments = vec![(cert.clone().into(), candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peers[99].0, msg).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2084,7 +2387,7 @@ fn non_originator_aggression_l2() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // new block `hash_a` with 1 candidates @@ -2118,7 +2421,7 @@ fn non_originator_aggression_l2() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peers[99].0, msg).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2249,7 +2552,7 @@ fn resends_messages_periodically() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } // Set up a gossip topology. @@ -2284,7 +2587,7 @@ fn resends_messages_periodically() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; + send_message_from_peer(overseer, &peers[99].0, msg).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2388,9 +2691,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::V2, view![hash]).await; - setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, ValidationVersion::V2, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V2).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -2410,7 +2713,7 @@ fn import_versioned_approval() { let cert = fake_assignment_cert(hash, validator_index); overseer_send( overseer, - ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index), + ApprovalDistributionMessage::DistributeAssignment(cert.into(), candidate_index.into()), ) .await; @@ -2451,7 +2754,7 @@ fn import_versioned_approval() { signature: dummy_signature(), }; let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_a, Versioned::V2(msg)).await; + send_message_from_peer_v2(overseer, &peer_a, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -2512,7 +2815,9 @@ fn batch_test_round(message_count: usize) { let validators = 0..message_count; let assignments: Vec<_> = validators .clone() - .map(|index| (fake_assignment_cert(Hash::zero(), ValidatorIndex(index as u32)), 0)) + .map(|index| { + (fake_assignment_cert(Hash::zero(), ValidatorIndex(index as u32)).into(), 0.into()) + }) .collect(); let approvals: Vec<_> = validators @@ -2525,9 +2830,18 @@ fn batch_test_round(message_count: usize) { .collect(); let peer = PeerId::random(); - send_assignments_batched(&mut sender, assignments.clone(), peer, ValidationVersion::V1) - .await; - send_approvals_batched(&mut sender, approvals.clone(), peer, ValidationVersion::V1).await; + send_assignments_batched( + &mut sender, + assignments.clone(), + &vec![(peer, ValidationVersion::V1.into())], + ) + .await; + send_approvals_batched( + &mut sender, + approvals.clone(), + &vec![(peer, ValidationVersion::V1.into())], + ) + .await; // Check expected assignments batches. for assignment_index in (0..assignments.len()).step_by(super::MAX_ASSIGNMENT_BATCH_SIZE) { @@ -2549,7 +2863,7 @@ fn batch_test_round(message_count: usize) { assert_eq!(peers.len(), 1); for (message_index, assignment) in sent_assignments.iter().enumerate() { - assert_eq!(assignment.0, assignments[assignment_index + message_index].0); + assert_eq!(assignment.0, assignments[assignment_index + message_index].0.clone().try_into().unwrap()); assert_eq!(assignment.1, 0); } } diff --git a/polkadot/node/network/bitfield-distribution/src/lib.rs b/polkadot/node/network/bitfield-distribution/src/lib.rs index 68e381ab6be..9cc79aee849 100644 --- a/polkadot/node/network/bitfield-distribution/src/lib.rs +++ b/polkadot/node/network/bitfield-distribution/src/lib.rs @@ -25,14 +25,15 @@ use always_assert::never; use futures::{channel::oneshot, FutureExt}; +use net_protocol::filter_by_peer_version; use polkadot_node_network_protocol::{ self as net_protocol, grid_topology::{ GridNeighbors, RandomRouting, RequiredRouting, SessionBoundGridTopologyStorage, }, peer_set::{ProtocolVersion, ValidationVersion}, - v1 as protocol_v1, v2 as protocol_v2, OurView, PeerId, UnifiedReputationChange as Rep, - Versioned, View, + v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, OurView, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_subsystem::{ jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, @@ -101,6 +102,11 @@ impl BitfieldGossipMessage { self.relay_parent, self.signed_availability.into(), )), + Some(ValidationVersion::VStaging) => + Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + self.relay_parent, + self.signed_availability.into(), + )), None => { never!("Peers should only have supported protocol versions."); @@ -131,9 +137,9 @@ pub struct PeerData { /// Data used to track information of peers and relay parents the /// overseer ordered us to work on. -#[derive(Default, Debug)] +#[derive(Default)] struct ProtocolState { - /// Track all active peers and their views + /// Track all active peer views and protocol versions /// to determine what is relevant to them. peer_data: HashMap, @@ -492,17 +498,13 @@ async fn relay_message( } else { let _span = span.child("gossip"); - let filter_by_version = |peers: &[(PeerId, ProtocolVersion)], - version: ValidationVersion| { - peers - .iter() - .filter(|(_, v)| v == &version.into()) - .map(|(peer_id, _)| *peer_id) - .collect::>() - }; + let v1_interested_peers = + filter_by_peer_version(&interested_peers, ValidationVersion::V1.into()); + let v2_interested_peers = + filter_by_peer_version(&interested_peers, ValidationVersion::V2.into()); - let v1_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V1); - let v2_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V2); + let vstaging_interested_peers = + filter_by_peer_version(&interested_peers, ValidationVersion::VStaging.into()); if !v1_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( @@ -515,7 +517,15 @@ async fn relay_message( if !v2_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( v2_interested_peers, - message.into_validation_protocol(ValidationVersion::V2.into()), + message.clone().into_validation_protocol(ValidationVersion::V2.into()), + )) + .await + } + + if !vstaging_interested_peers.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_interested_peers, + message.into_validation_protocol(ValidationVersion::VStaging.into()), )) .await } @@ -540,6 +550,10 @@ async fn process_incoming_peer_message( Versioned::V2(protocol_v2::BitfieldDistributionMessage::Bitfield( relay_parent, bitfield, + )) | + Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + relay_parent, + bitfield, )) => (relay_parent, bitfield), }; @@ -774,9 +788,11 @@ async fn handle_network_msg( handle_peer_view_change(ctx, state, new_peer, old_view, rng).await; } }, - NetworkBridgeEvent::PeerViewChange(peerid, new_view) => { - gum::trace!(target: LOG_TARGET, ?peerid, ?new_view, "Peer view change"); - handle_peer_view_change(ctx, state, peerid, new_view, rng).await; + NetworkBridgeEvent::PeerViewChange(peer_id, new_view) => { + gum::trace!(target: LOG_TARGET, ?peer_id, ?new_view, "Peer view change"); + if state.peer_data.get(&peer_id).is_some() { + handle_peer_view_change(ctx, state, peer_id, new_view, rng).await; + } }, NetworkBridgeEvent::OurViewChange(new_view) => { gum::trace!(target: LOG_TARGET, ?new_view, "Our view change"); diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index 823e1254612..c264c94cc19 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -28,23 +28,129 @@ use sc_network::{ }; use polkadot_node_network_protocol::{ - peer_set::{PeerSet, PeerSetProtocolNames, ProtocolVersion}, + peer_set::{ + CollationVersion, PeerSet, PeerSetProtocolNames, ProtocolVersion, ValidationVersion, + }, request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests}, - PeerId, + v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, }; use polkadot_primitives::{AuthorityDiscoveryId, Block, Hash}; -use crate::validator_discovery::AuthorityDiscovery; +use crate::{metrics::Metrics, validator_discovery::AuthorityDiscovery, WireMessage}; // network bridge network abstraction log target const LOG_TARGET: &'static str = "parachain::network-bridge-net"; -/// Send a message to the network. +// Helper function to send a validation v1 message to a list of peers. +// Messages are always sent via the main protocol, even legacy protocol messages. +pub(crate) fn send_validation_message_v1( + net: &mut impl Network, + peers: Vec, + peerset_protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v1 message to peers",); + + send_message( + net, + peers, + PeerSet::Validation, + ValidationVersion::V1.into(), + peerset_protocol_names, + message, + metrics, + ); +} + +// Helper function to send a validation vstaging message to a list of peers. +// Messages are always sent via the main protocol, even legacy protocol messages. +pub(crate) fn send_validation_message_vstaging( + net: &mut impl Network, + peers: Vec, + peerset_protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",); + + send_message( + net, + peers, + PeerSet::Validation, + ValidationVersion::VStaging.into(), + peerset_protocol_names, + message, + metrics, + ); +} + +// Helper function to send a validation v2 message to a list of peers. +// Messages are always sent via the main protocol, even legacy protocol messages. +pub(crate) fn send_validation_message_v2( + net: &mut impl Network, + peers: Vec, + protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Validation, + ValidationVersion::V2.into(), + protocol_names, + message, + metrics, + ); +} + +// Helper function to send a collation v1 message to a list of peers. +// Messages are always sent via the main protocol, even legacy protocol messages. +pub(crate) fn send_collation_message_v1( + net: &mut impl Network, + peers: Vec, + peerset_protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Collation, + CollationVersion::V1.into(), + peerset_protocol_names, + message, + metrics, + ); +} + +// Helper function to send a collation v2 message to a list of peers. +// Messages are always sent via the main protocol, even legacy protocol messages. +pub(crate) fn send_collation_message_v2( + net: &mut impl Network, + peers: Vec, + peerset_protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Collation, + CollationVersion::V2.into(), + peerset_protocol_names, + message, + metrics, + ); +} + +/// Lower level function that sends a message to the network using the main protocol version. /// /// This function is only used internally by the network-bridge, which is responsible to only send /// messages that are compatible with the passed peer set, as that is currently not enforced by /// this function. These are messages of type `WireMessage` parameterized on the matching type. -pub(crate) fn send_message( +fn send_message( net: &mut impl Network, mut peers: Vec, peer_set: PeerSet, @@ -65,6 +171,17 @@ pub(crate) fn send_message( encoded }; + // optimization: generate the protocol name once. + let protocol_name = protocol_names.get_name(peer_set, version); + gum::trace!( + target: LOG_TARGET, + ?peers, + ?version, + ?protocol_name, + ?message, + "Sending message to peers", + ); + // optimization: avoid cloning the message for the last peer in the // list. The message payload can be quite large. If the underlying // network used `Bytes` this would not be necessary. diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index f64410c1353..06be57ead00 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -21,6 +21,7 @@ use super::*; use always_assert::never; use bytes::Bytes; use futures::stream::{BoxStream, StreamExt}; +use net_protocol::filter_by_peer_version; use parity_scale_codec::{Decode, DecodeAll}; use sc_network::Event as NetworkEvent; @@ -33,8 +34,8 @@ use polkadot_node_network_protocol::{ CollationVersion, PeerSet, PeerSetProtocolNames, PerPeerSet, ProtocolVersion, ValidationVersion, }, - v1 as protocol_v1, v2 as protocol_v2, ObservedRole, OurView, PeerId, - UnifiedReputationChange as Rep, View, + v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, ObservedRole, OurView, + PeerId, UnifiedReputationChange as Rep, View, }; use polkadot_node_subsystem::{ @@ -64,9 +65,11 @@ use super::validator_discovery; /// Actual interfacing to the network based on the `Network` trait. /// /// Defines the `Network` trait with an implementation for an `Arc`. -use crate::network::{send_message, Network}; - -use crate::network::get_peer_id_by_authority_id; +use crate::network::{ + send_collation_message_v1, send_collation_message_v2, send_validation_message_v1, + send_validation_message_v2, send_validation_message_vstaging, Network, +}; +use crate::{network::get_peer_id_by_authority_id, WireMessage}; use super::metrics::Metrics; @@ -251,22 +254,27 @@ where match ValidationVersion::try_from(version) .expect("try_get_protocol has already checked version is known; qed") { - ValidationVersion::V1 => send_message( + ValidationVersion::V1 => send_validation_message_v1( &mut network_service, vec![peer], - PeerSet::Validation, - version, &peerset_protocol_names, WireMessage::::ViewUpdate( local_view, ), &metrics, ), - ValidationVersion::V2 => send_message( + ValidationVersion::VStaging => send_validation_message_vstaging( + &mut network_service, + vec![peer], + &peerset_protocol_names, + WireMessage::::ViewUpdate( + local_view, + ), + &metrics, + ), + ValidationVersion::V2 => send_validation_message_v2( &mut network_service, vec![peer], - PeerSet::Validation, - version, &peerset_protocol_names, WireMessage::::ViewUpdate( local_view, @@ -293,22 +301,18 @@ where match CollationVersion::try_from(version) .expect("try_get_protocol has already checked version is known; qed") { - CollationVersion::V1 => send_message( + CollationVersion::V1 => send_collation_message_v1( &mut network_service, vec![peer], - PeerSet::Collation, - version, &peerset_protocol_names, WireMessage::::ViewUpdate( local_view, ), &metrics, ), - CollationVersion::V2 => send_message( + CollationVersion::V2 => send_collation_message_v2( &mut network_service, vec![peer], - PeerSet::Collation, - version, &peerset_protocol_names, WireMessage::::ViewUpdate( local_view, @@ -386,8 +390,16 @@ where .filter_map(|(protocol, msg_bytes)| { // version doesn't matter because we always receive on the 'correct' // protocol name, not the negotiated fallback. - let (peer_set, _version) = + let (peer_set, version) = peerset_protocol_names.try_get_protocol(protocol)?; + gum::trace!( + target: LOG_TARGET, + ?peer_set, + ?protocol, + ?version, + "Received notification" + ); + if peer_set == PeerSet::Validation { if expected_versions[PeerSet::Validation].is_none() { return Some(Err(UNCONNECTED_PEERSET_COST)) @@ -474,6 +486,16 @@ where v_messages, &metrics, ) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::VStaging.into()) + { + handle_peer_messages::( + remote, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + v_messages, + &metrics, + ) } else { gum::warn!( target: LOG_TARGET, @@ -815,15 +837,16 @@ fn update_our_view( ) }; - let filter_by_version = |peers: &[(PeerId, ProtocolVersion)], version| { - peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::>() - }; + let v1_validation_peers = + filter_by_peer_version(&validation_peers, ValidationVersion::V1.into()); + let v1_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V1.into()); - 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 v2_validation_peers = + filter_by_peer_version(&validation_peers, ValidationVersion::V2.into()); + let v2_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V2.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()); + let vstaging_validation_peers = + filter_by_peer_version(&validation_peers, ValidationVersion::VStaging.into()); send_validation_message_v1( net, @@ -853,7 +876,15 @@ fn update_our_view( net, v2_collation_peers, peerset_protocol_names, - WireMessage::ViewUpdate(new_view), + WireMessage::ViewUpdate(new_view.clone()), + metrics, + ); + + send_validation_message_vstaging( + net, + vstaging_validation_peers, + peerset_protocol_names, + WireMessage::ViewUpdate(new_view.clone()), metrics, ); @@ -926,78 +957,6 @@ fn handle_peer_messages>( (outgoing_events, reports) } -fn send_validation_message_v1( - net: &mut impl Network, - peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Validation, - ValidationVersion::V1.into(), - peerset_protocol_names, - message, - metrics, - ); -} - -fn send_collation_message_v1( - net: &mut impl Network, - peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Collation, - CollationVersion::V1.into(), - peerset_protocol_names, - message, - metrics, - ); -} - -fn send_validation_message_v2( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Validation, - ValidationVersion::V2.into(), - protocol_names, - message, - metrics, - ); -} - -fn send_collation_message_v2( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Collation, - CollationVersion::V2.into(), - protocol_names, - message, - metrics, - ); -} - async fn dispatch_validation_event_to_all( event: NetworkBridgeEvent, ctx: &mut impl overseer::NetworkBridgeRxSenderTrait, diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 7c69cce4839..f784e78a7f2 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -1248,6 +1248,9 @@ fn network_protocol_versioning_view_update() { ValidationVersion::V2 => WireMessage::::ViewUpdate(view.clone()) .encode(), + ValidationVersion::VStaging => + WireMessage::::ViewUpdate(view.clone()) + .encode(), }; assert_network_actions_contains( &actions, diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index f15635f1f41..5f222ad59c7 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -18,9 +18,7 @@ use super::*; use polkadot_node_network_protocol::{ - peer_set::{CollationVersion, PeerSet, PeerSetProtocolNames, ValidationVersion}, - request_response::ReqProtocolNames, - v1 as protocol_v1, v2 as protocol_v2, PeerId, Versioned, + peer_set::PeerSetProtocolNames, request_response::ReqProtocolNames, Versioned, }; use polkadot_node_subsystem::{ @@ -41,7 +39,10 @@ use crate::validator_discovery; /// Actual interfacing to the network based on the `Network` trait. /// /// Defines the `Network` trait with an implementation for an `Arc`. -use crate::network::{send_message, Network}; +use crate::network::{ + send_collation_message_v1, send_collation_message_v2, send_validation_message_v1, + send_validation_message_v2, send_validation_message_vstaging, Network, +}; use crate::metrics::Metrics; @@ -187,6 +188,7 @@ where gum::trace!( target: LOG_TARGET, action = "SendValidationMessages", + ?msg, num_messages = 1usize, ); @@ -198,6 +200,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_validation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), Versioned::V2(msg) => send_validation_message_v2( &mut network_service, peers, @@ -212,6 +221,7 @@ where target: LOG_TARGET, action = "SendValidationMessages", num_messages = %msgs.len(), + ?msgs, ); for (peers, msg) in msgs { @@ -223,6 +233,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_validation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), Versioned::V2(msg) => send_validation_message_v2( &mut network_service, peers, @@ -248,7 +265,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::V2(msg) => send_collation_message_v2( + Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -273,7 +290,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::V2(msg) => send_collation_message_v2( + Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -386,75 +403,3 @@ where Ok(()) } - -fn send_validation_message_v1( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Validation, - ValidationVersion::V1.into(), - protocol_names, - message, - metrics, - ); -} - -fn send_collation_message_v1( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Collation, - CollationVersion::V1.into(), - protocol_names, - message, - metrics, - ); -} - -fn send_validation_message_v2( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Validation, - ValidationVersion::V2.into(), - protocol_names, - message, - metrics, - ); -} - -fn send_collation_message_v2( - net: &mut impl Network, - peers: Vec, - protocol_names: &PeerSetProtocolNames, - message: WireMessage, - metrics: &Metrics, -) { - send_message( - net, - peers, - PeerSet::Collation, - 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 48287f8b74c..1a2d9a7a424 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -25,9 +25,9 @@ use std::collections::HashSet; use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSetProtocolNames, ValidationVersion}, request_response::{outgoing::Requests, ReqProtocolNames}, - ObservedRole, Versioned, + v1 as protocol_v1, v2 as protocol_v2, ObservedRole, Versioned, }; use polkadot_node_subsystem::{FromOrchestra, OverseerSignal}; use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; @@ -356,7 +356,6 @@ fn network_protocol_versioning_send() { } // send a validation protocol message. - { let approval_distribution_message = protocol_v2::ApprovalDistributionMessage::Approvals(Vec::new()); 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 e4b95f24d5a..b3a396e1be3 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -880,7 +880,9 @@ async fn handle_incoming_peer_message( use protocol_v2::CollatorProtocolMessage as V2; match msg { - Versioned::V1(V1::Declare(..)) | Versioned::V2(V2::Declare(..)) => { + Versioned::V1(V1::Declare(..)) | + Versioned::V2(V2::Declare(..)) | + Versioned::VStaging(V2::Declare(..)) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -891,7 +893,9 @@ async fn handle_incoming_peer_message( ctx.send_message(NetworkBridgeTxMessage::DisconnectPeer(origin, PeerSet::Collation)) .await; }, - Versioned::V1(V1::AdvertiseCollation(_)) | Versioned::V2(V2::AdvertiseCollation { .. }) => { + Versioned::V1(V1::AdvertiseCollation(_)) | + Versioned::V2(V2::AdvertiseCollation { .. }) | + Versioned::VStaging(V2::AdvertiseCollation { .. }) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -906,7 +910,8 @@ async fn handle_incoming_peer_message( .await; }, Versioned::V1(V1::CollationSeconded(relay_parent, statement)) | - Versioned::V2(V2::CollationSeconded(relay_parent, statement)) => { + Versioned::V2(V2::CollationSeconded(relay_parent, statement)) | + Versioned::VStaging(V2::CollationSeconded(relay_parent, statement)) => { if !matches!(statement.unchecked_payload(), Statement::Seconded(_)) { gum::warn!( target: LOG_TARGET, 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 00bf50013a5..20b3b9ea1d2 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -776,7 +776,8 @@ async fn process_incoming_peer_message( match msg { Versioned::V1(V1::Declare(collator_id, para_id, signature)) | - Versioned::V2(V2::Declare(collator_id, para_id, signature)) => { + Versioned::V2(V2::Declare(collator_id, para_id, signature)) | + Versioned::VStaging(V2::Declare(collator_id, para_id, signature)) => { if collator_peer_id(&state.peer_data, &collator_id).is_some() { modify_reputation( &mut state.reputation, @@ -892,6 +893,11 @@ async fn process_incoming_peer_message( relay_parent, candidate_hash, parent_head_data_hash, + }) | + Versioned::VStaging(V2::AdvertiseCollation { + relay_parent, + candidate_hash, + parent_head_data_hash, }) => if let Err(err) = handle_advertisement( ctx.sender(), @@ -915,7 +921,9 @@ async fn process_incoming_peer_message( modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; } }, - Versioned::V1(V1::CollationSeconded(..)) | Versioned::V2(V2::CollationSeconded(..)) => { + Versioned::V1(V1::CollationSeconded(..)) | + Versioned::V2(V2::CollationSeconded(..)) | + Versioned::VStaging(V2::CollationSeconded(..)) => { gum::warn!( target: LOG_TARGET, peer_id = ?origin, diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 2b2b2d0933e..674c86e5ce2 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -477,6 +477,7 @@ where match message { Versioned::V1(m) => match m {}, Versioned::V2(m) => match m {}, + Versioned::VStaging(m) => match m {}, } }, } diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 379334ded24..c33b9eae325 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -27,3 +27,6 @@ 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 901ac99b669..9aeeb98ea9d 100644 --- a/polkadot/node/network/protocol/src/lib.rs +++ b/polkadot/node/network/protocol/src/lib.rs @@ -253,25 +253,29 @@ impl View { /// A protocol-versioned type. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Versioned { +pub enum Versioned { /// V1 type. V1(V1), /// V2 type. V2(V2), + /// VStaging type + VStaging(VStaging), } -impl Versioned<&'_ V1, &'_ V2> { +impl Versioned<&'_ V1, &'_ V2, &'_ VStaging> { /// 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::V2(inner) => Versioned::V2(inner.clone()), + Versioned::VStaging(inner) => Versioned::VStaging(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 { @@ -285,6 +289,12 @@ impl From for VersionedValidationProtocol { } } +impl From for VersionedValidationProtocol { + fn from(vstaging: vstaging::ValidationProtocol) -> Self { + VersionedValidationProtocol::VStaging(vstaging) + } +} + /// All supported versions of the collation protocol message. pub type VersionedCollationProtocol = Versioned; @@ -307,12 +317,12 @@ macro_rules! impl_versioned_full_protocol_from { match versioned_from { Versioned::V1(x) => Versioned::V1(x.into()), Versioned::V2(x) => Versioned::V2(x.into()), + Versioned::VStaging(x) => Versioned::VStaging(x.into()), } } } }; } - /// Implement `TryFrom` for one versioned enum variant into the inner type. /// `$m_ty::$variant(inner) -> Ok(inner)` macro_rules! impl_versioned_try_from { @@ -320,7 +330,8 @@ macro_rules! impl_versioned_try_from { $from:ty, $out:ty, $v1_pat:pat => $v1_out:expr, - $v2_pat:pat => $v2_out:expr + $v2_pat:pat => $v2_out:expr, + $vstaging_pat:pat => $vstaging_out:expr ) => { impl TryFrom<$from> for $out { type Error = crate::WrongVariant; @@ -330,6 +341,7 @@ macro_rules! impl_versioned_try_from { match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)), + Versioned::VStaging($vstaging_pat) => Ok(Versioned::VStaging($vstaging_out)), _ => Err(crate::WrongVariant), } } @@ -343,6 +355,8 @@ macro_rules! impl_versioned_try_from { match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())), + Versioned::VStaging($vstaging_pat) => + Ok(Versioned::VStaging($vstaging_out.clone())), _ => Err(crate::WrongVariant), } } @@ -351,8 +365,11 @@ macro_rules! impl_versioned_try_from { } /// Version-annotated messages used by the bitfield distribution subsystem. -pub type BitfieldDistributionMessage = - Versioned; +pub type BitfieldDistributionMessage = Versioned< + v1::BitfieldDistributionMessage, + v2::BitfieldDistributionMessage, + vstaging::BitfieldDistributionMessage, +>; impl_versioned_full_protocol_from!( BitfieldDistributionMessage, VersionedValidationProtocol, @@ -362,12 +379,16 @@ impl_versioned_try_from!( VersionedValidationProtocol, BitfieldDistributionMessage, v1::ValidationProtocol::BitfieldDistribution(x) => x, - v2::ValidationProtocol::BitfieldDistribution(x) => x + v2::ValidationProtocol::BitfieldDistribution(x) => x, + vstaging::ValidationProtocol::BitfieldDistribution(x) => x ); /// Version-annotated messages used by the statement distribution subsystem. -pub type StatementDistributionMessage = - Versioned; +pub type StatementDistributionMessage = Versioned< + v1::StatementDistributionMessage, + v2::StatementDistributionMessage, + vstaging::StatementDistributionMessage, +>; impl_versioned_full_protocol_from!( StatementDistributionMessage, VersionedValidationProtocol, @@ -377,12 +398,16 @@ impl_versioned_try_from!( VersionedValidationProtocol, StatementDistributionMessage, v1::ValidationProtocol::StatementDistribution(x) => x, - v2::ValidationProtocol::StatementDistribution(x) => x + v2::ValidationProtocol::StatementDistribution(x) => x, + vstaging::ValidationProtocol::StatementDistribution(x) => x ); /// Version-annotated messages used by the approval distribution subsystem. -pub type ApprovalDistributionMessage = - Versioned; +pub type ApprovalDistributionMessage = Versioned< + v1::ApprovalDistributionMessage, + v2::ApprovalDistributionMessage, + vstaging::ApprovalDistributionMessage, +>; impl_versioned_full_protocol_from!( ApprovalDistributionMessage, VersionedValidationProtocol, @@ -392,13 +417,18 @@ impl_versioned_try_from!( VersionedValidationProtocol, ApprovalDistributionMessage, v1::ValidationProtocol::ApprovalDistribution(x) => x, - v2::ValidationProtocol::ApprovalDistribution(x) => x + v2::ValidationProtocol::ApprovalDistribution(x) => x, + vstaging::ValidationProtocol::ApprovalDistribution(x) => x ); /// Version-annotated messages used by the gossip-support subsystem (this is void). -pub type GossipSupportNetworkMessage = - Versioned; +pub type GossipSupportNetworkMessage = Versioned< + v1::GossipSupportNetworkMessage, + v2::GossipSupportNetworkMessage, + vstaging::GossipSupportNetworkMessage, +>; + // This is a void enum placeholder, so never gets sent over the wire. impl TryFrom for GossipSupportNetworkMessage { type Error = WrongVariant; @@ -426,6 +456,7 @@ impl_versioned_try_from!( VersionedCollationProtocol, CollatorProtocolMessage, v1::CollationProtocol::CollatorProtocol(x) => x, + v2::CollationProtocol::CollatorProtocol(x) => x, v2::CollationProtocol::CollatorProtocol(x) => x ); @@ -439,7 +470,7 @@ pub mod v1 { }; use polkadot_node_primitives::{ - approval::{IndirectAssignmentCert, IndirectSignedApprovalVote}, + approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote}, UncheckedSignedFullStatement, }; @@ -598,7 +629,7 @@ pub mod v2 { }; use polkadot_node_primitives::{ - approval::{IndirectAssignmentCert, IndirectSignedApprovalVote}, + approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote}, UncheckedSignedFullStatement, }; @@ -839,3 +870,64 @@ pub mod v2 { payload } } + +/// vstaging network protocol types, intended to become v3. +/// Initial purpose is for chaning ApprovalDistributionMessage to +/// include more than one assignment in the message. +pub mod vstaging { + use parity_scale_codec::{Decode, Encode}; + + use polkadot_node_primitives::approval::{ + v1::IndirectSignedApprovalVote, + v2::{CandidateBitfield, IndirectAssignmentCertV2}, + }; + + /// This parts of the protocol did not change from v2, so just alias them in vstaging, + /// no reason why they can't be change untill vstaging becomes v3 and is released. + pub use super::v2::{ + declare_signature_payload, BackedCandidateAcknowledgement, BackedCandidateManifest, + BitfieldDistributionMessage, GossipSupportNetworkMessage, StatementDistributionMessage, + StatementFilter, + }; + + /// Network messages used by the approval distribution subsystem. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum ApprovalDistributionMessage { + /// Assignments for candidates in recent, unfinalized blocks. + /// We use a bitfield to reference claimed candidates, where the bit index is equal to + /// candidate index. + /// + /// Actually checking the assignment may yield a different result. + /// TODO: Look at getting rid of bitfield in the future. + #[codec(index = 0)] + Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>), + /// Approvals for candidates in some recent, unfinalized block. + #[codec(index = 1)] + Approvals(Vec), + } + + /// All network messages on the validation peer-set. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] + pub enum ValidationProtocol { + /// Bitfield distribution messages + #[codec(index = 1)] + #[from] + BitfieldDistribution(BitfieldDistributionMessage), + /// Statement distribution messages + #[codec(index = 3)] + #[from] + StatementDistribution(StatementDistributionMessage), + /// Approval distribution messages + #[codec(index = 4)] + #[from] + ApprovalDistribution(ApprovalDistributionMessage), + } +} + +/// Returns the subset of `peers` with the specified `version`. +pub fn filter_by_peer_version( + peers: &[(PeerId, peer_set::ProtocolVersion)], + version: peer_set::ProtocolVersion, +) -> Vec { + peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::>() +} diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index 8dd68b297e3..eb483dec970 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -118,10 +118,17 @@ 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::V2.into(), PeerSet::Collation => CollationVersion::V2.into(), } + + #[cfg(feature = "network-protocol-staging")] + match self { + PeerSet::Validation => ValidationVersion::VStaging.into(), + PeerSet::Collation => CollationVersion::V2.into(), + } } /// Get the max notification size for this peer set. @@ -147,6 +154,8 @@ impl PeerSet { Some("validation/1") } else if version == ValidationVersion::V2.into() { Some("validation/2") + } else if version == ValidationVersion::VStaging.into() { + Some("validation/3") } else { None }, @@ -218,6 +227,9 @@ pub enum ValidationVersion { V1 = 1, /// The second version. V2 = 2, + /// The staging version to gather changes + /// that before the release become v3. + VStaging = 3, } /// Supported collation protocol versions. Only versions defined here must be used in the codebase. 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 fc2aff0da30..d9866af1ee2 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use net_protocol::{filter_by_peer_version, peer_set::ProtocolVersion}; use parity_scale_codec::Encode; use polkadot_node_network_protocol::{ @@ -21,7 +22,8 @@ use polkadot_node_network_protocol::{ grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage}, peer_set::{IsAuthority, PeerSet, ValidationVersion}, v1::{self as protocol_v1, StatementMetadata}, - v2 as protocol_v2, IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, + v2 as protocol_v2, vstaging as protocol_vstaging, IfDisconnected, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::{ SignedFullStatement, Statement, StatementWithPVD, UncheckedSignedFullStatement, @@ -1061,7 +1063,7 @@ async fn circulate_statement<'a, Context>( "We filter out duplicates above. qed.", ); - let (v1_peers_to_send, v2_peers_to_send) = peers_to_send + let (v1_peers_to_send, non_v1_peers_to_send) = peers_to_send .into_iter() .map(|peer_id| { let peer_data = @@ -1073,7 +1075,7 @@ async fn circulate_statement<'a, Context>( }) .partition::, _>(|(_, _, version)| match version { ValidationVersion::V1 => true, - ValidationVersion::V2 => false, + ValidationVersion::V2 | ValidationVersion::VStaging => false, }); // partition is handy here but not if we add more protocol versions let payload = v1_statement_message(relay_parent, stored.statement.clone(), metrics); @@ -1093,6 +1095,22 @@ async fn circulate_statement<'a, Context>( )) .await; } + + let peers_to_send: Vec<(PeerId, ProtocolVersion)> = non_v1_peers_to_send + .iter() + .map(|(p, _, version)| (*p, (*version).into())) + .collect(); + + let peer_needs_dependent_statement = v1_peers_to_send + .into_iter() + .chain(non_v1_peers_to_send) + .filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None }) + .collect(); + + let v2_peers_to_send = filter_by_peer_version(&peers_to_send, ValidationVersion::V2.into()); + let vstaging_to_send = + filter_by_peer_version(&peers_to_send, ValidationVersion::VStaging.into()); + if !v2_peers_to_send.is_empty() { gum::trace!( target: LOG_TARGET, @@ -1102,17 +1120,28 @@ async fn circulate_statement<'a, Context>( "Sending statement to v2 peers", ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - v2_peers_to_send.iter().map(|(p, _, _)| *p).collect(), + v2_peers_to_send, compatible_v1_message(ValidationVersion::V2, payload.clone()).into(), )) .await; } - v1_peers_to_send - .into_iter() - .chain(v2_peers_to_send) - .filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None }) - .collect() + if !vstaging_to_send.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?vstaging_to_send, + ?relay_parent, + statement = ?stored.statement, + "Sending statement to vstaging peers", + ); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_to_send, + compatible_v1_message(ValidationVersion::VStaging, payload.clone()).into(), + )) + .await; + } + + peer_needs_dependent_statement } /// Send all statements about a given candidate hash to a peer. @@ -1442,8 +1471,11 @@ async fn handle_incoming_message<'a, Context>( let message = match message { Versioned::V1(m) => m, - Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) => m, - Versioned::V2(_) => { + Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) | + Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::V1Compatibility( + m, + )) => m, + Versioned::V2(_) | Versioned::VStaging(_) => { // The higher-level subsystem code is supposed to filter out // all non v1 messages. gum::debug!( @@ -2169,5 +2201,8 @@ fn compatible_v1_message( ValidationVersion::V1 => Versioned::V1(message), ValidationVersion::V2 => Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(message)), + ValidationVersion::VStaging => Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(message), + ), } } diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index 259c8f6a360..0a80c1491a9 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -27,7 +27,7 @@ use std::time::Duration; use polkadot_node_network_protocol::{ request_response::{v1 as request_v1, v2::AttestedCandidateRequest, IncomingRequestReceiver}, - v2 as protocol_v2, Versioned, + v2 as protocol_v2, vstaging as protocol_vstaging, Versioned, }; use polkadot_node_primitives::StatementWithPVD; use polkadot_node_subsystem::{ @@ -399,9 +399,12 @@ impl StatementDistributionSubsystem { NetworkBridgeEvent::PeerMessage(_, message) => match message { Versioned::V2( protocol_v2::StatementDistributionMessage::V1Compatibility(_), + ) | + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), ) => VersionTarget::Legacy, Versioned::V1(_) => VersionTarget::Legacy, - Versioned::V2(_) => VersionTarget::Current, + Versioned::V2(_) | Versioned::VStaging(_) => VersionTarget::Current, }, _ => VersionTarget::Both, }; diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 95104732df0..6f39a5c504d 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -17,6 +17,7 @@ //! Implementation of the v2 statement distribution protocol, //! designed for asynchronous backing. +use net_protocol::{filter_by_peer_version, peer_set::ProtocolVersion}; use polkadot_node_network_protocol::{ self as net_protocol, grid_topology::SessionGridTopology, @@ -28,7 +29,8 @@ use polkadot_node_network_protocol::{ MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, }, v2::{self as protocol_v2, StatementFilter}, - IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, + vstaging as protocol_vstaging, IfDisconnected, PeerId, UnifiedReputationChange as Rep, + Versioned, View, }; use polkadot_node_primitives::{ SignedFullStatementWithPVD, StatementWithPVD as FullStatementWithPVD, @@ -260,6 +262,7 @@ fn connected_validator_peer( struct PeerState { view: View, + protocol_version: ValidationVersion, implicit_view: HashSet, discovery_ids: Option>, } @@ -332,9 +335,13 @@ 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::V2.into() { + let versioned_protocol = if protocol_version != ValidationVersion::V2.into() && + protocol_version != ValidationVersion::VStaging.into() + { return - } + } else { + protocol_version.try_into().expect("Qed, we checked above") + }; if let Some(ref mut authority_ids) = authority_ids { authority_ids.retain(|a| match state.authorities.entry(a.clone()) { @@ -361,6 +368,7 @@ pub(crate) async fn handle_network_update( PeerState { view: View::default(), implicit_view: HashSet::new(), + protocol_version: versioned_protocol, discovery_ids: authority_ids, }, ); @@ -393,17 +401,29 @@ pub(crate) async fn handle_network_update( net_protocol::StatementDistributionMessage::V1(_) => return, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::V1Compatibility(_), + ) | + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), ) => return, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), + ) | + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), ) => handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation) .await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateManifest(inner), + ) | + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(inner), ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateKnown(inner), + ) | + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(inner), ) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await, }, NetworkBridgeEvent::PeerViewChange(peer_id, view) => @@ -709,7 +729,7 @@ async fn send_peer_messages_for_relay_parent( send_pending_cluster_statements( ctx, relay_parent, - &peer, + &(peer, peer_data.protocol_version), validator_id, &mut local_validator_state.cluster_tracker, &state.candidates, @@ -721,7 +741,7 @@ async fn send_peer_messages_for_relay_parent( send_pending_grid_messages( ctx, relay_parent, - &peer, + &(peer, peer_data.protocol_version), validator_id, &per_session_state.groups, relay_parent_state, @@ -734,15 +754,34 @@ async fn send_peer_messages_for_relay_parent( fn pending_statement_network_message( statement_store: &StatementStore, relay_parent: Hash, - peer: &PeerId, + peer: &(PeerId, ValidationVersion), originator: ValidatorIndex, compact: CompactStatement, ) -> Option<(Vec, net_protocol::VersionedValidationProtocol)> { - statement_store - .validator_statement(originator, compact) - .map(|s| s.as_unchecked().clone()) - .map(|signed| protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed)) - .map(|msg| (vec![*peer], Versioned::V2(msg).into())) + match peer.1 { + ValidationVersion::V2 => statement_store + .validator_statement(originator, compact) + .map(|s| s.as_unchecked().clone()) + .map(|signed| { + protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed) + }) + .map(|msg| (vec![peer.0], Versioned::V2(msg).into())), + ValidationVersion::VStaging => 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.0], Versioned::VStaging(msg).into())), + ValidationVersion::V1 => { + gum::error!( + target: LOG_TARGET, + "Bug ValidationVersion::V1 should not be used in statement-distribution v2, + legacy should have handled this" + ); + None + }, + } } /// Send a peer all pending cluster statements for a relay parent. @@ -750,7 +789,7 @@ fn pending_statement_network_message( async fn send_pending_cluster_statements( ctx: &mut Context, relay_parent: Hash, - peer_id: &PeerId, + peer_id: &(PeerId, ValidationVersion), peer_validator_id: ValidatorIndex, cluster_tracker: &mut ClusterTracker, candidates: &Candidates, @@ -794,7 +833,7 @@ async fn send_pending_cluster_statements( async fn send_pending_grid_messages( ctx: &mut Context, relay_parent: Hash, - peer_id: &PeerId, + peer_id: &(PeerId, ValidationVersion), peer_validator_id: ValidatorIndex, groups: &Groups, relay_parent_state: &mut PerRelayParentState, @@ -856,20 +895,37 @@ async fn send_pending_grid_messages( candidate_hash, local_knowledge.clone(), ); - - messages.push(( - vec![*peer_id], - Versioned::V2( - protocol_v2::StatementDistributionMessage::BackedCandidateManifest( - manifest, - ), - ) - .into(), - )); + match peer_id.1 { + ValidationVersion::V2 => messages.push(( + vec![peer_id.0], + Versioned::V2( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( + manifest, + ), + ) + .into(), + )), + ValidationVersion::VStaging => messages.push(( + vec![peer_id.0], + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest, + ), + ) + .into(), + )), + ValidationVersion::V1 => { + gum::error!( + target: LOG_TARGET, + "Bug ValidationVersion::V1 should not be used in statement-distribution v2, + legacy should have handled this" + ); + } + }; }, grid::ManifestKind::Acknowledgement => { messages.extend(acknowledgement_and_statement_messages( - *peer_id, + peer_id, peer_validator_id, groups, relay_parent_state, @@ -1156,11 +1212,18 @@ async fn circulate_statement( (local_validator, targets) }; - let mut statement_to = Vec::new(); + let mut statement_to_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new(); for (target, authority_id, kind) in targets { // Find peer ID based on authority ID, and also filter to connected. - let peer_id: PeerId = match authorities.get(&authority_id) { - Some(p) if peers.get(p).map_or(false, |p| p.knows_relay_parent(&relay_parent)) => *p, + let peer_id: (PeerId, ProtocolVersion) = match authorities.get(&authority_id) { + Some(p) if peers.get(p).map_or(false, |p| p.knows_relay_parent(&relay_parent)) => ( + *p, + peers + .get(p) + .expect("Qed, can't fail because it was checked above") + .protocol_version + .into(), + ), None | Some(_) => continue, }; @@ -1178,11 +1241,11 @@ async fn circulate_statement( originator, compact_statement.clone(), ); - statement_to.push(peer_id); + statement_to_peers.push(peer_id); } }, DirectTargetKind::Grid => { - statement_to.push(peer_id); + statement_to_peers.push(peer_id); local_validator.grid_tracker.sent_or_received_direct_statement( &per_session.groups, originator, @@ -1193,17 +1256,23 @@ async fn circulate_statement( } } + let statement_to_v2_peers = + filter_by_peer_version(&statement_to_peers, ValidationVersion::V2.into()); + + let statement_to_vstaging_peers = + filter_by_peer_version(&statement_to_peers, ValidationVersion::VStaging.into()); + // ship off the network messages to the network bridge. - if !statement_to.is_empty() { + if !statement_to_v2_peers.is_empty() { gum::debug!( target: LOG_TARGET, ?compact_statement, - n_peers = ?statement_to.len(), - "Sending statement to peers", + n_peers = ?statement_to_v2_peers.len(), + "Sending statement to v2 peers", ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - statement_to, + statement_to_v2_peers, Versioned::V2(protocol_v2::StatementDistributionMessage::Statement( relay_parent, statement.as_unchecked().clone(), @@ -1212,6 +1281,25 @@ async fn circulate_statement( )) .await; } + + if !statement_to_vstaging_peers.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?compact_statement, + n_peers = ?statement_to_peers.len(), + "Sending statement to vstaging peers", + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + statement_to_vstaging_peers, + Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement.as_unchecked().clone(), + )) + .into(), + )) + .await; + } } /// Check a statement signature under this parent hash. fn check_statement_signature( @@ -1697,14 +1785,8 @@ async fn provide_candidate_to_grid( statement_knowledge: filter.clone(), }; - 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(); - let mut ack_peers = Vec::new(); + let mut manifest_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new(); + let mut ack_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new(); let mut post_statements = Vec::new(); for (v, action) in actions { @@ -1712,7 +1794,7 @@ async fn provide_candidate_to_grid( None => continue, Some(p) => if peers.get(&p).map_or(false, |d| d.knows_relay_parent(&relay_parent)) { - p + (p, peers.get(&p).expect("Qed, was checked above").protocol_version.into()) } else { continue }, @@ -1738,44 +1820,95 @@ async fn provide_candidate_to_grid( &per_session.groups, group_index, candidate_hash, + &(p.0, p.1.try_into().expect("Qed, can not fail was checked above")), ) .into_iter() - .map(|m| (vec![p], m)), + .map(|m| (vec![p.0], m)), ); } - if !manifest_peers.is_empty() { + let manifest_peers_v2 = filter_by_peer_version(&manifest_peers, ValidationVersion::V2.into()); + let manifest_peers_vstaging = + filter_by_peer_version(&manifest_peers, ValidationVersion::VStaging.into()); + if !manifest_peers_v2.is_empty() { gum::debug!( target: LOG_TARGET, ?candidate_hash, local_validator = ?local_validator.index, - n_peers = manifest_peers.len(), - "Sending manifest to peers" + n_peers = manifest_peers_v2.len(), + "Sending manifest to v2 peers" ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - manifest_peers, - manifest_message.into(), + manifest_peers_v2, + Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + )) + .into(), )) .await; } - if !ack_peers.is_empty() { + if !manifest_peers_vstaging.is_empty() { gum::debug!( target: LOG_TARGET, ?candidate_hash, local_validator = ?local_validator.index, - n_peers = ack_peers.len(), - "Sending acknowledgement to peers" + n_peers = manifest_peers_vstaging.len(), + "Sending manifest to vstaging peers" ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - ack_peers, - ack_message.into(), + manifest_peers_vstaging, + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ) + .into(), )) .await; } + let ack_peers_v2 = filter_by_peer_version(&ack_peers, ValidationVersion::V2.into()); + let ack_peers_vstaging = filter_by_peer_version(&ack_peers, ValidationVersion::VStaging.into()); + if !ack_peers_v2.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + local_validator = ?local_validator.index, + n_peers = ack_peers_v2.len(), + "Sending acknowledgement to v2 peers" + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + ack_peers_v2, + Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement.clone(), + )) + .into(), + )) + .await; + } + + if !ack_peers_vstaging.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + local_validator = ?local_validator.index, + n_peers = ack_peers_vstaging.len(), + "Sending acknowledgement to vstaging peers" + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + ack_peers_vstaging, + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement, + ), + ) + .into(), + )) + .await; + } if !post_statements.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(post_statements)) .await; @@ -2074,6 +2207,7 @@ fn post_acknowledgement_statement_messages( groups: &Groups, group_index: GroupIndex, candidate_hash: CandidateHash, + peer: &(PeerId, ValidationVersion), ) -> Vec { let sending_filter = match grid_tracker.pending_statements_for(recipient, candidate_hash) { None => return Vec::new(), @@ -2090,14 +2224,29 @@ fn post_acknowledgement_statement_messages( recipient, statement.payload(), ); - - messages.push(Versioned::V2( - protocol_v2::StatementDistributionMessage::Statement( - relay_parent, - statement.as_unchecked().clone(), - ) - .into(), - )); + match peer.1.into() { + ValidationVersion::V2 => messages.push(Versioned::V2( + protocol_v2::StatementDistributionMessage::Statement( + relay_parent, + statement.as_unchecked().clone(), + ) + .into(), + )), + ValidationVersion::VStaging => messages.push(Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement.as_unchecked().clone(), + ) + .into(), + )), + ValidationVersion::V1 => { + gum::error!( + target: LOG_TARGET, + "Bug ValidationVersion::V1 should not be used in statement-distribution v2, + legacy should have handled this" + ); + }, + }; } messages @@ -2167,7 +2316,15 @@ async fn handle_incoming_manifest( }; let messages = acknowledgement_and_statement_messages( - peer, + &( + peer, + state + .peers + .get(&peer) + .map(|val| val.protocol_version) + // Assume the latest stable version, if we don't have info about peer version. + .unwrap_or(ValidationVersion::V2), + ), sender_index, &per_session.groups, relay_parent_state, @@ -2198,7 +2355,7 @@ async fn handle_incoming_manifest( /// Produces acknowledgement and statement messages to be sent over the network, /// noting that they have been sent within the grid topology tracker as well. fn acknowledgement_and_statement_messages( - peer: PeerId, + peer: &(PeerId, ValidationVersion), validator_index: ValidatorIndex, groups: &Groups, relay_parent_state: &mut PerRelayParentState, @@ -2217,11 +2374,28 @@ fn acknowledgement_and_statement_messages( statement_knowledge: local_knowledge.clone(), }; - let msg = Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( - acknowledgement, + let msg_v2 = Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement.clone(), )); - let mut messages = vec![(vec![peer], msg.into())]; + let mut messages = match peer.1 { + ValidationVersion::V2 => vec![(vec![peer.0], msg_v2.into())], + ValidationVersion::VStaging => vec![( + vec![peer.0], + Versioned::VStaging(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement, + )) + .into(), + )], + ValidationVersion::V1 => { + gum::error!( + target: LOG_TARGET, + "Bug ValidationVersion::V1 should not be used in statement-distribution v2, + legacy should have handled this" + ); + return Vec::new() + }, + }; local_validator.grid_tracker.manifest_sent_to( groups, @@ -2238,9 +2412,10 @@ fn acknowledgement_and_statement_messages( &groups, group_index, candidate_hash, + peer, ); - messages.extend(statement_messages.into_iter().map(|m| (vec![peer], m))); + messages.extend(statement_messages.into_iter().map(|m| (vec![peer.0], m))); messages } @@ -2320,6 +2495,15 @@ async fn handle_incoming_acknowledgement( &per_session.groups, group_index, candidate_hash, + &( + peer, + state + .peers + .get(&peer) + .map(|val| val.protocol_version) + // Assume the latest stable version, if we don't have info about peer version. + .unwrap_or(ValidationVersion::V2), + ), ); if !messages.is_empty() { diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 55dfa673870..c39fd5947b0 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -20,6 +20,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime" } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } schnorrkel = "0.9.1" thiserror = "1.0.48" +bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } serde = { version = "1.0.188", features = ["derive"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/polkadot/node/primitives/src/approval.rs b/polkadot/node/primitives/src/approval.rs index 01f45a20787..e5ae24f7a51 100644 --- a/polkadot/node/primitives/src/approval.rs +++ b/polkadot/node/primitives/src/approval.rs @@ -16,190 +16,515 @@ //! Types relevant for approval. -pub use sp_consensus_babe::{Randomness, Slot, VrfOutput, VrfProof, VrfSignature, VrfTranscript}; - -use parity_scale_codec::{Decode, Encode}; -use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateIndex, CoreIndex, Hash, Header, SessionIndex, - ValidatorIndex, ValidatorSignature, -}; -use sp_application_crypto::ByteArray; -use sp_consensus_babe as babe_primitives; - -/// Validators assigning to check a particular candidate are split up into tranches. -/// Earlier tranches of validators check first, with later tranches serving as backup. -pub type DelayTranche = u32; - -/// A static context used to compute the Relay VRF story based on the -/// VRF output included in the header-chain. -pub const RELAY_VRF_STORY_CONTEXT: &[u8] = b"A&V RC-VRF"; - -/// A static context used for all relay-vrf-modulo VRFs. -pub const RELAY_VRF_MODULO_CONTEXT: &[u8] = b"A&V MOD"; - -/// A static context used for all relay-vrf-modulo VRFs. -pub const RELAY_VRF_DELAY_CONTEXT: &[u8] = b"A&V DELAY"; - -/// A static context used for transcripts indicating assigned availability core. -pub const ASSIGNED_CORE_CONTEXT: &[u8] = b"A&V ASSIGNED"; - -/// A static context associated with producing randomness for a core. -pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE"; - -/// A static context associated with producing randomness for a tranche. -pub const TRANCHE_RANDOMNESS_CONTEXT: &[u8] = b"A&V TRANCHE"; - -/// random bytes derived from the VRF submitted within the block by the -/// block author as a credential and used as input to approval assignment criteria. -#[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub struct RelayVRFStory(pub [u8; 32]); - -/// Different kinds of input data or criteria that can prove a validator's assignment -/// to check a particular parachain. -#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] -pub enum AssignmentCertKind { - /// An assignment story based on the VRF that authorized the relay-chain block where the - /// candidate was included combined with a sample number. +/// A list of primitives introduced in v1. +pub mod v1 { + use sp_consensus_babe as babe_primitives; + pub use sp_consensus_babe::{ + Randomness, Slot, VrfOutput, VrfProof, VrfSignature, VrfTranscript, + }; + + use parity_scale_codec::{Decode, Encode}; + use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateIndex, CoreIndex, Hash, Header, SessionIndex, + ValidatorIndex, ValidatorSignature, + }; + use sp_application_crypto::ByteArray; + + /// Validators assigning to check a particular candidate are split up into tranches. + /// Earlier tranches of validators check first, with later tranches serving as backup. + pub type DelayTranche = u32; + + /// A static context used to compute the Relay VRF story based on the + /// VRF output included in the header-chain. + pub const RELAY_VRF_STORY_CONTEXT: &[u8] = b"A&V RC-VRF"; + + /// A static context used for all relay-vrf-modulo VRFs. + pub const RELAY_VRF_MODULO_CONTEXT: &[u8] = b"A&V MOD"; + + /// A static context used for all relay-vrf-modulo VRFs. + pub const RELAY_VRF_DELAY_CONTEXT: &[u8] = b"A&V DELAY"; + + /// A static context used for transcripts indicating assigned availability core. + pub const ASSIGNED_CORE_CONTEXT: &[u8] = b"A&V ASSIGNED"; + + /// A static context associated with producing randomness for a core. + pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE"; + + /// A static context associated with producing randomness for a tranche. + pub const TRANCHE_RANDOMNESS_CONTEXT: &[u8] = b"A&V TRANCHE"; + + /// random bytes derived from the VRF submitted within the block by the + /// block author as a credential and used as input to approval assignment criteria. + #[derive(Debug, Clone, Encode, Decode, PartialEq)] + pub struct RelayVRFStory(pub [u8; 32]); + + /// Different kinds of input data or criteria that can prove a validator's assignment + /// to check a particular parachain. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum AssignmentCertKind { + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with a sample number. + /// + /// The context used to produce bytes is [`RELAY_VRF_MODULO_CONTEXT`] + RelayVRFModulo { + /// The sample number used in this cert. + sample: u32, + }, + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with the index of a particular core. + /// + /// The context is [`RELAY_VRF_DELAY_CONTEXT`] + RelayVRFDelay { + /// The core index chosen in this cert. + core_index: CoreIndex, + }, + } + + /// A certification of assignment. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct AssignmentCert { + /// The criterion which is claimed to be met by this cert. + pub kind: AssignmentCertKind, + /// The VRF signature showing the criterion is met. + pub vrf: VrfSignature, + } + + /// An assignment criterion which refers to the candidate under which the assignment is + /// relevant by block hash. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct IndirectAssignmentCert { + /// A block hash where the candidate appears. + pub block_hash: Hash, + /// The validator index. + pub validator: ValidatorIndex, + /// The cert itself. + pub cert: AssignmentCert, + } + + /// A signed approval vote which references the candidate indirectly via the block. /// - /// The context used to produce bytes is [`RELAY_VRF_MODULO_CONTEXT`] - RelayVRFModulo { - /// The sample number used in this cert. - sample: u32, - }, - /// An assignment story based on the VRF that authorized the relay-chain block where the - /// candidate was included combined with the index of a particular core. + /// In practice, we have a look-up from block hash and candidate index to candidate hash, + /// so this can be transformed into a `SignedApprovalVote`. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct IndirectSignedApprovalVote { + /// A block hash where the candidate appears. + pub block_hash: Hash, + /// The index of the candidate in the list of candidates fully included as-of the block. + pub candidate_index: CandidateIndex, + /// The validator index. + pub validator: ValidatorIndex, + /// The signature by the validator. + pub signature: ValidatorSignature, + } + + /// Metadata about a block which is now live in the approval protocol. + #[derive(Debug)] + pub struct BlockApprovalMeta { + /// The hash of the block. + pub hash: Hash, + /// The number of the block. + pub number: BlockNumber, + /// The hash of the parent block. + pub parent_hash: Hash, + /// The candidates included by the block. + /// Note that these are not the same as the candidates that appear within the block body. + pub candidates: Vec, + /// The consensus slot of the block. + pub slot: Slot, + /// The session of the block. + pub session: SessionIndex, + } + + /// Errors that can occur during the approvals protocol. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum ApprovalError { + #[error("Schnorrkel signature error")] + SchnorrkelSignature(schnorrkel::errors::SignatureError), + #[error("Authority index {0} out of bounds")] + AuthorityOutOfBounds(usize), + } + + /// An unsafe VRF output. Provide BABE Epoch info to create a `RelayVRFStory`. + pub struct UnsafeVRFOutput { + vrf_output: VrfOutput, + slot: Slot, + authority_index: u32, + } + + impl UnsafeVRFOutput { + /// Get the slot. + pub fn slot(&self) -> Slot { + self.slot + } + + /// Compute the randomness associated with this VRF output. + pub fn compute_randomness( + self, + authorities: &[(babe_primitives::AuthorityId, babe_primitives::BabeAuthorityWeight)], + randomness: &babe_primitives::Randomness, + epoch_index: u64, + ) -> Result { + let author = match authorities.get(self.authority_index as usize) { + None => return Err(ApprovalError::AuthorityOutOfBounds(self.authority_index as _)), + Some(x) => &x.0, + }; + + let pubkey = schnorrkel::PublicKey::from_bytes(author.as_slice()) + .map_err(ApprovalError::SchnorrkelSignature)?; + + let transcript = + sp_consensus_babe::make_vrf_transcript(randomness, self.slot, epoch_index); + + let inout = self + .vrf_output + .0 + .attach_input_hash(&pubkey, transcript.0) + .map_err(ApprovalError::SchnorrkelSignature)?; + Ok(RelayVRFStory(inout.make_bytes(super::v1::RELAY_VRF_STORY_CONTEXT))) + } + } + + /// Extract the slot number and relay VRF from a header. /// - /// The context is [`RELAY_VRF_DELAY_CONTEXT`] - RelayVRFDelay { - /// The core index chosen in this cert. - core_index: CoreIndex, - }, -} + /// This fails if either there is no BABE `PreRuntime` digest or + /// the digest has type `SecondaryPlain`, which Substrate nodes do + /// not produce or accept anymore. + pub fn babe_unsafe_vrf_info(header: &Header) -> Option { + use babe_primitives::digests::CompatibleDigestItem; -/// A certification of assignment. -#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] -pub struct AssignmentCert { - /// The criterion which is claimed to be met by this cert. - pub kind: AssignmentCertKind, - /// The VRF signature showing the criterion is met. - pub vrf: VrfSignature, -} + for digest in &header.digest.logs { + if let Some(pre) = digest.as_babe_pre_digest() { + let slot = pre.slot(); + let authority_index = pre.authority_index(); -/// An assignment criterion which refers to the candidate under which the assignment is -/// relevant by block hash. -#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] -pub struct IndirectAssignmentCert { - /// A block hash where the candidate appears. - pub block_hash: Hash, - /// The validator index. - pub validator: ValidatorIndex, - /// The cert itself. - pub cert: AssignmentCert, -} + return pre.vrf_signature().map(|sig| UnsafeVRFOutput { + vrf_output: sig.output.clone(), + slot, + authority_index, + }) + } + } -/// A signed approval vote which references the candidate indirectly via the block. -/// -/// In practice, we have a look-up from block hash and candidate index to candidate hash, -/// so this can be transformed into a `SignedApprovalVote`. -#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] -pub struct IndirectSignedApprovalVote { - /// A block hash where the candidate appears. - pub block_hash: Hash, - /// The index of the candidate in the list of candidates fully included as-of the block. - pub candidate_index: CandidateIndex, - /// The validator index. - pub validator: ValidatorIndex, - /// The signature by the validator. - pub signature: ValidatorSignature, + None + } } -/// Metadata about a block which is now live in the approval protocol. -#[derive(Debug)] -pub struct BlockApprovalMeta { - /// The hash of the block. - pub hash: Hash, - /// The number of the block. - pub number: BlockNumber, - /// The hash of the parent block. - pub parent_hash: Hash, - /// The candidates included by the block. - /// Note that these are not the same as the candidates that appear within the block body. - pub candidates: Vec, - /// The consensus slot of the block. - pub slot: Slot, - /// The session of the block. - pub session: SessionIndex, -} +/// A list of primitives introduced by v2. +pub mod v2 { + use parity_scale_codec::{Decode, Encode}; + pub use sp_consensus_babe::{ + Randomness, Slot, VrfOutput, VrfProof, VrfSignature, VrfTranscript, + }; + use std::ops::BitOr; -/// Errors that can occur during the approvals protocol. -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -pub enum ApprovalError { - #[error("Schnorrkel signature error")] - SchnorrkelSignature(schnorrkel::errors::SignatureError), - #[error("Authority index {0} out of bounds")] - AuthorityOutOfBounds(usize), -} + use bitvec::{prelude::Lsb0, vec::BitVec}; + use polkadot_primitives::{CandidateIndex, CoreIndex, Hash, ValidatorIndex}; -/// An unsafe VRF output. Provide BABE Epoch info to create a `RelayVRFStory`. -pub struct UnsafeVRFOutput { - vrf_output: VrfOutput, - slot: Slot, - authority_index: u32, -} + /// A static context associated with producing randomness for a core. + pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE v2"; + /// A static context associated with producing randomness for v2 multi-core assignments. + pub const ASSIGNED_CORE_CONTEXT: &[u8] = b"A&V ASSIGNED v2"; + /// A static context used for all relay-vrf-modulo VRFs for v2 multi-core assignments. + pub const RELAY_VRF_MODULO_CONTEXT: &[u8] = b"A&V MOD v2"; + /// A read-only bitvec wrapper + #[derive(Clone, Debug, Encode, Decode, Hash, PartialEq, Eq)] + pub struct Bitfield(BitVec, std::marker::PhantomData); + + /// A `read-only`, `non-zero` bitfield. + /// Each 1 bit identifies a candidate by the bitfield bit index. + pub type CandidateBitfield = Bitfield; + /// A bitfield of core assignments. + pub type CoreBitfield = Bitfield; + + /// Errors that can occur when creating and manipulating bitfields. + #[derive(Debug)] + pub enum BitfieldError { + /// All bits are zero. + NullAssignment, + } + + /// A bit index in `Bitfield`. + #[cfg_attr(test, derive(PartialEq, Clone))] + pub struct BitIndex(pub usize); + + /// Helper trait to convert primitives to `BitIndex`. + pub trait AsBitIndex { + /// Returns the index of the corresponding bit in `Bitfield`. + fn as_bit_index(&self) -> BitIndex; + } + + impl Bitfield { + /// Returns the bit value at specified `index`. If `index` is greater than bitfield size, + /// returns `false`. + pub fn bit_at(&self, index: BitIndex) -> bool { + if self.0.len() <= index.0 { + false + } else { + self.0[index.0] + } + } + + /// Returns number of bits. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns the number of 1 bits. + pub fn count_ones(&self) -> usize { + self.0.count_ones() + } + + /// Returns the index of the first 1 bit. + pub fn first_one(&self) -> Option { + self.0.first_one() + } + + /// Returns an iterator over inner bits. + pub fn iter_ones(&self) -> bitvec::slice::IterOnes { + self.0.iter_ones() + } -impl UnsafeVRFOutput { - /// Get the slot. - pub fn slot(&self) -> Slot { - self.slot + /// For testing purpose, we want a inner mutable ref. + #[cfg(test)] + pub fn inner_mut(&mut self) -> &mut BitVec { + &mut self.0 + } + + /// Returns the inner bitfield and consumes `self`. + pub fn into_inner(self) -> BitVec { + self.0 + } } - /// Compute the randomness associated with this VRF output. - pub fn compute_randomness( - self, - authorities: &[(babe_primitives::AuthorityId, babe_primitives::BabeAuthorityWeight)], - randomness: &babe_primitives::Randomness, - epoch_index: u64, - ) -> Result { - let author = match authorities.get(self.authority_index as usize) { - None => return Err(ApprovalError::AuthorityOutOfBounds(self.authority_index as _)), - Some(x) => &x.0, - }; + impl AsBitIndex for CandidateIndex { + fn as_bit_index(&self) -> BitIndex { + BitIndex(*self as usize) + } + } - let pubkey = schnorrkel::PublicKey::from_bytes(author.as_slice()) - .map_err(ApprovalError::SchnorrkelSignature)?; + impl AsBitIndex for CoreIndex { + fn as_bit_index(&self) -> BitIndex { + BitIndex(self.0 as usize) + } + } - let transcript = sp_consensus_babe::make_vrf_transcript(randomness, self.slot, epoch_index); + impl AsBitIndex for usize { + fn as_bit_index(&self) -> BitIndex { + BitIndex(*self) + } + } - let inout = self - .vrf_output - .0 - .attach_input_hash(&pubkey, transcript.0) - .map_err(ApprovalError::SchnorrkelSignature)?; - Ok(RelayVRFStory(inout.make_bytes(RELAY_VRF_STORY_CONTEXT))) + impl From for Bitfield + where + T: AsBitIndex, + { + fn from(value: T) -> Self { + Self( + { + let mut bv = bitvec::bitvec![u8, Lsb0; 0; value.as_bit_index().0 + 1]; + bv.set(value.as_bit_index().0, true); + bv + }, + Default::default(), + ) + } + } + + impl TryFrom> for Bitfield + where + T: Into>, + { + type Error = BitfieldError; + + fn try_from(mut value: Vec) -> Result { + if value.is_empty() { + return Err(BitfieldError::NullAssignment) + } + + let initial_bitfield = + value.pop().expect("Just checked above it's not empty; qed").into(); + + Ok(Self( + value.into_iter().fold(initial_bitfield.0, |initial_bitfield, element| { + let mut bitfield: Bitfield = element.into(); + bitfield + .0 + .resize(std::cmp::max(initial_bitfield.len(), bitfield.0.len()), false); + bitfield.0.bitor(initial_bitfield) + }), + Default::default(), + )) + } + } + + /// Certificate is changed compared to `AssignmentCertKind`: + /// - introduced RelayVRFModuloCompact + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum AssignmentCertKindV2 { + /// Multiple assignment stories based on the VRF that authorized the relay-chain block + /// where the candidates were included. + /// + /// The context is [`super::v2::RELAY_VRF_MODULO_CONTEXT`] + #[codec(index = 0)] + RelayVRFModuloCompact { + /// A bitfield representing the core indices claimed by this assignment. + core_bitfield: CoreBitfield, + }, + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with the index of a particular core. + /// + /// The context is [`super::v1::RELAY_VRF_DELAY_CONTEXT`] + #[codec(index = 1)] + RelayVRFDelay { + /// The core index chosen in this cert. + core_index: CoreIndex, + }, + /// Deprectated assignment. Soon to be removed. + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with a sample number. + /// + /// The context used to produce bytes is [`super::v1::RELAY_VRF_MODULO_CONTEXT`] + #[codec(index = 2)] + RelayVRFModulo { + /// The sample number used in this cert. + sample: u32, + }, + } + + /// A certification of assignment. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct AssignmentCertV2 { + /// The criterion which is claimed to be met by this cert. + pub kind: AssignmentCertKindV2, + /// The VRF showing the criterion is met. + pub vrf: VrfSignature, + } + + impl From for AssignmentCertV2 { + fn from(cert: super::v1::AssignmentCert) -> Self { + Self { + kind: match cert.kind { + super::v1::AssignmentCertKind::RelayVRFDelay { core_index } => + AssignmentCertKindV2::RelayVRFDelay { core_index }, + super::v1::AssignmentCertKind::RelayVRFModulo { sample } => + AssignmentCertKindV2::RelayVRFModulo { sample }, + }, + vrf: cert.vrf, + } + } } -} -/// Extract the slot number and relay VRF from a header. -/// -/// This fails if either there is no BABE `PreRuntime` digest or -/// the digest has type `SecondaryPlain`, which Substrate nodes do -/// not produce or accept anymore. -pub fn babe_unsafe_vrf_info(header: &Header) -> Option { - use babe_primitives::digests::CompatibleDigestItem; - - for digest in &header.digest.logs { - if let Some(pre) = digest.as_babe_pre_digest() { - let slot = pre.slot(); - let authority_index = pre.authority_index(); - - return pre.vrf_signature().map(|sig| UnsafeVRFOutput { - vrf_output: sig.output.clone(), - slot, - authority_index, + /// Errors that can occur when trying to convert to/from assignment v1/v2 + #[derive(Debug)] + pub enum AssignmentConversionError { + /// Assignment certificate is not supported in v1. + CertificateNotSupported, + } + + impl TryFrom for super::v1::AssignmentCert { + type Error = AssignmentConversionError; + fn try_from(cert: AssignmentCertV2) -> Result { + Ok(Self { + kind: match cert.kind { + AssignmentCertKindV2::RelayVRFDelay { core_index } => + super::v1::AssignmentCertKind::RelayVRFDelay { core_index }, + AssignmentCertKindV2::RelayVRFModulo { sample } => + super::v1::AssignmentCertKind::RelayVRFModulo { sample }, + // Not supported + _ => return Err(AssignmentConversionError::CertificateNotSupported), + }, + vrf: cert.vrf, }) } } - None + /// An assignment criterion which refers to the candidate under which the assignment is + /// relevant by block hash. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct IndirectAssignmentCertV2 { + /// A block hash where the candidate appears. + pub block_hash: Hash, + /// The validator index. + pub validator: ValidatorIndex, + /// The cert itself. + pub cert: AssignmentCertV2, + } + + impl From for IndirectAssignmentCertV2 { + fn from(indirect_cert: super::v1::IndirectAssignmentCert) -> Self { + Self { + block_hash: indirect_cert.block_hash, + validator: indirect_cert.validator, + cert: indirect_cert.cert.into(), + } + } + } + + impl TryFrom for super::v1::IndirectAssignmentCert { + type Error = AssignmentConversionError; + fn try_from( + indirect_cert: IndirectAssignmentCertV2, + ) -> Result { + Ok(Self { + block_hash: indirect_cert.block_hash, + validator: indirect_cert.validator, + cert: indirect_cert.cert.try_into()?, + }) + } + } +} + +#[cfg(test)] +mod test { + use super::v2::{BitIndex, Bitfield}; + + use polkadot_primitives::{CandidateIndex, CoreIndex}; + + #[test] + fn test_assignment_bitfield_from_vec() { + let candidate_indices = vec![1u32, 7, 3, 10, 45, 8, 200, 2]; + let max_index = *candidate_indices.iter().max().unwrap(); + let bitfield = Bitfield::try_from(candidate_indices.clone()).unwrap(); + let candidate_indices = + candidate_indices.into_iter().map(|i| BitIndex(i as usize)).collect::>(); + + // Test 1 bits. + for index in candidate_indices.clone() { + assert!(bitfield.bit_at(index)); + } + + // Test 0 bits. + for index in 0..max_index { + if candidate_indices.contains(&BitIndex(index as usize)) { + continue + } + assert!(!bitfield.bit_at(BitIndex(index as usize))); + } + } + + #[test] + fn test_assignment_bitfield_invariant_msb() { + let core_indices = vec![CoreIndex(1), CoreIndex(3), CoreIndex(10), CoreIndex(20)]; + let mut bitfield = Bitfield::try_from(core_indices.clone()).unwrap(); + assert!(bitfield.inner_mut().pop().unwrap()); + + for i in 0..1024 { + assert!(Bitfield::try_from(CoreIndex(i)).unwrap().inner_mut().pop().unwrap()); + assert!(Bitfield::try_from(i).unwrap().inner_mut().pop().unwrap()); + } + } + + #[test] + fn test_assignment_bitfield_basic() { + let bitfield = Bitfield::try_from(CoreIndex(0)).unwrap(); + assert!(bitfield.bit_at(BitIndex(0))); + assert!(!bitfield.bit_at(BitIndex(1))); + assert_eq!(bitfield.len(), 1); + + let mut bitfield = Bitfield::try_from(20 as CandidateIndex).unwrap(); + assert!(bitfield.bit_at(BitIndex(20))); + assert_eq!(bitfield.inner_mut().count_ones(), 1); + assert_eq!(bitfield.len(), 21); + } } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 41b86f2151e..0ed50086f86 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -139,6 +139,7 @@ polkadot-statement-distribution = { path = "../network/statement-distribution", [dev-dependencies] polkadot-test-client = { path = "../test/client" } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } +test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } env_logger = "0.9.0" assert_matches = "1.5.0" serial_test = "2.0.0" @@ -222,3 +223,7 @@ 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/src/parachains_db/mod.rs b/polkadot/node/service/src/parachains_db/mod.rs index 519afbe0ccd..92f3f167f22 100644 --- a/polkadot/node/service/src/parachains_db/mod.rs +++ b/polkadot/node/service/src/parachains_db/mod.rs @@ -41,7 +41,15 @@ pub(crate) mod columns { pub const COL_SESSION_WINDOW_DATA: u32 = 5; } + // Version 4 only changed structures in approval voting, so we can re-export the v4 definitions. pub mod v3 { + pub use super::v4::{ + COL_APPROVAL_DATA, COL_AVAILABILITY_DATA, COL_AVAILABILITY_META, + COL_CHAIN_SELECTION_DATA, COL_DISPUTE_COORDINATOR_DATA, NUM_COLUMNS, ORDERED_COL, + }; + } + + pub mod v4 { pub const NUM_COLUMNS: u32 = 5; pub const COL_AVAILABILITY_DATA: u32 = 0; pub const COL_AVAILABILITY_META: u32 = 1; @@ -73,14 +81,14 @@ pub struct ColumnsConfig { /// The real columns used by the parachains DB. #[cfg(any(test, feature = "full-node"))] pub const REAL_COLUMNS: ColumnsConfig = ColumnsConfig { - col_availability_data: columns::v3::COL_AVAILABILITY_DATA, - col_availability_meta: columns::v3::COL_AVAILABILITY_META, - col_approval_data: columns::v3::COL_APPROVAL_DATA, - col_chain_selection_data: columns::v3::COL_CHAIN_SELECTION_DATA, - col_dispute_coordinator_data: columns::v3::COL_DISPUTE_COORDINATOR_DATA, + col_availability_data: columns::v4::COL_AVAILABILITY_DATA, + col_availability_meta: columns::v4::COL_AVAILABILITY_META, + col_approval_data: columns::v4::COL_APPROVAL_DATA, + col_chain_selection_data: columns::v4::COL_CHAIN_SELECTION_DATA, + col_dispute_coordinator_data: columns::v4::COL_DISPUTE_COORDINATOR_DATA, }; -#[derive(PartialEq)] +#[derive(PartialEq, Copy, Clone)] pub(crate) enum DatabaseKind { ParityDB, RocksDB, @@ -125,28 +133,28 @@ pub fn open_creating_rocksdb( let path = root.join("parachains").join("db"); - let mut db_config = DatabaseConfig::with_columns(columns::v3::NUM_COLUMNS); + let mut db_config = DatabaseConfig::with_columns(columns::v4::NUM_COLUMNS); let _ = db_config .memory_budget - .insert(columns::v3::COL_AVAILABILITY_DATA, cache_sizes.availability_data); + .insert(columns::v4::COL_AVAILABILITY_DATA, cache_sizes.availability_data); let _ = db_config .memory_budget - .insert(columns::v3::COL_AVAILABILITY_META, cache_sizes.availability_meta); + .insert(columns::v4::COL_AVAILABILITY_META, cache_sizes.availability_meta); let _ = db_config .memory_budget - .insert(columns::v3::COL_APPROVAL_DATA, cache_sizes.approval_data); + .insert(columns::v4::COL_APPROVAL_DATA, cache_sizes.approval_data); let path_str = path .to_str() .ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?; std::fs::create_dir_all(&path_str)?; - upgrade::try_upgrade_db(&path, DatabaseKind::RocksDB)?; + upgrade::try_upgrade_db(&path, DatabaseKind::RocksDB, upgrade::CURRENT_VERSION)?; let db = Database::open(&db_config, &path_str)?; let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new( db, - columns::v3::ORDERED_COL, + columns::v4::ORDERED_COL, ); Ok(Arc::new(db)) @@ -164,14 +172,14 @@ pub fn open_creating_paritydb( .ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?; std::fs::create_dir_all(&path_str)?; - upgrade::try_upgrade_db(&path, DatabaseKind::ParityDB)?; + upgrade::try_upgrade_db(&path, DatabaseKind::ParityDB, upgrade::CURRENT_VERSION)?; let db = parity_db::Db::open_or_create(&upgrade::paritydb_version_3_config(&path)) .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?; let db = polkadot_node_subsystem_util::database::paritydb_impl::DbAdapter::new( db, - columns::v3::ORDERED_COL, + columns::v4::ORDERED_COL, ); Ok(Arc::new(db)) } diff --git a/polkadot/node/service/src/parachains_db/upgrade.rs b/polkadot/node/service/src/parachains_db/upgrade.rs index 54ef97afd71..1d76c79d3e3 100644 --- a/polkadot/node/service/src/parachains_db/upgrade.rs +++ b/polkadot/node/service/src/parachains_db/upgrade.rs @@ -22,13 +22,17 @@ use std::{ str::FromStr, }; +use polkadot_node_core_approval_voting::approval_db::v2::{ + migration_helpers::v1_to_v2, Config as ApprovalDbConfig, +}; type Version = u32; /// Version file name. const VERSION_FILE_NAME: &'static str = "parachain_db_version"; /// Current db version. -const CURRENT_VERSION: Version = 3; +/// Version 4 changes approval db format for `OurAssignment`. +pub(crate) const CURRENT_VERSION: Version = 4; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -38,6 +42,10 @@ pub enum Error { CorruptedVersionFile, #[error("Parachains DB has a future version (expected {current:?}, found {got:?})")] FutureVersion { current: Version, got: Version }, + #[error("Parachain DB migration failed")] + MigrationFailed, + #[error("Parachain DB migration would take forever")] + MigrationLoop, } impl From for io::Error { @@ -49,10 +57,42 @@ impl From for io::Error { } } -/// Try upgrading parachain's database to the current version. -pub(crate) fn try_upgrade_db(db_path: &Path, db_kind: DatabaseKind) -> Result<(), Error> { +/// Try upgrading parachain's database to a target version. +pub(crate) fn try_upgrade_db( + db_path: &Path, + db_kind: DatabaseKind, + target_version: Version, +) -> Result<(), Error> { + // Ensure we don't loop forever below because of a bug. + const MAX_MIGRATIONS: u32 = 30; + + #[cfg(test)] + remove_file_lock(&db_path); + + // Loop migrations until we reach the target version. + for _ in 0..MAX_MIGRATIONS { + let version = try_upgrade_db_to_next_version(db_path, db_kind)?; + + #[cfg(test)] + remove_file_lock(&db_path); + + if version == target_version { + return Ok(()) + } + } + + Err(Error::MigrationLoop) +} + +/// Try upgrading parachain's database to the next version. +/// If successfull, it returns the current version. +pub(crate) fn try_upgrade_db_to_next_version( + db_path: &Path, + db_kind: DatabaseKind, +) -> Result { let is_empty = db_path.read_dir().map_or(true, |mut d| d.next().is_none()); - if !is_empty { + + let new_version = if !is_empty { match get_db_version(db_path)? { // 0 -> 1 migration Some(0) => migrate_from_version_0_to_1(db_path, db_kind)?, @@ -60,21 +100,26 @@ pub(crate) fn try_upgrade_db(db_path: &Path, db_kind: DatabaseKind) -> Result<() Some(1) => migrate_from_version_1_to_2(db_path, db_kind)?, // 2 -> 3 migration Some(2) => migrate_from_version_2_to_3(db_path, db_kind)?, + // 3 -> 4 migration + Some(3) => migrate_from_version_3_to_4(db_path, db_kind)?, // Already at current version, do nothing. - Some(CURRENT_VERSION) => (), + Some(CURRENT_VERSION) => CURRENT_VERSION, // This is an arbitrary future version, we don't handle it. Some(v) => return Err(Error::FutureVersion { current: CURRENT_VERSION, got: v }), // No version file. For `RocksDB` we dont need to do anything. - None if db_kind == DatabaseKind::RocksDB => (), + None if db_kind == DatabaseKind::RocksDB => CURRENT_VERSION, // No version file. `ParityDB` did not previously have a version defined. // We handle this as a `0 -> 1` migration. None if db_kind == DatabaseKind::ParityDB => migrate_from_version_0_to_1(db_path, db_kind)?, None => unreachable!(), } - } + } else { + CURRENT_VERSION + }; - update_version(db_path) + update_version(db_path, new_version)?; + Ok(new_version) } /// Reads current database version from the file at given path. @@ -91,9 +136,9 @@ fn get_db_version(path: &Path) -> Result, Error> { /// Writes current database version to the file. /// Creates a new file if the version file does not exist yet. -fn update_version(path: &Path) -> Result<(), Error> { +fn update_version(path: &Path, new_version: Version) -> Result<(), Error> { fs::create_dir_all(path)?; - fs::write(version_file_path(path), CURRENT_VERSION.to_string()).map_err(Into::into) + fs::write(version_file_path(path), new_version.to_string()).map_err(Into::into) } /// Returns the version file path. @@ -103,7 +148,7 @@ fn version_file_path(path: &Path) -> PathBuf { file_path } -fn migrate_from_version_0_to_1(path: &Path, db_kind: DatabaseKind) -> Result<(), Error> { +fn migrate_from_version_0_to_1(path: &Path, db_kind: DatabaseKind) -> Result { gum::info!(target: LOG_TARGET, "Migrating parachains db from version 0 to version 1 ..."); match db_kind { @@ -116,7 +161,7 @@ fn migrate_from_version_0_to_1(path: &Path, db_kind: DatabaseKind) -> Result<(), }) } -fn migrate_from_version_1_to_2(path: &Path, db_kind: DatabaseKind) -> Result<(), Error> { +fn migrate_from_version_1_to_2(path: &Path, db_kind: DatabaseKind) -> Result { gum::info!(target: LOG_TARGET, "Migrating parachains db from version 1 to version 2 ..."); match db_kind { @@ -129,7 +174,48 @@ fn migrate_from_version_1_to_2(path: &Path, db_kind: DatabaseKind) -> Result<(), }) } -fn migrate_from_version_2_to_3(path: &Path, db_kind: DatabaseKind) -> Result<(), Error> { +// Migrade approval voting database. `OurAssignment` has been changed to support the v2 assignments. +// As these are backwards compatible, we'll convert the old entries in the new format. +fn migrate_from_version_3_to_4(path: &Path, db_kind: DatabaseKind) -> Result { + gum::info!(target: LOG_TARGET, "Migrating parachains db from version 3 to version 4 ..."); + use polkadot_node_subsystem_util::database::{ + kvdb_impl::DbAdapter as RocksDbAdapter, paritydb_impl::DbAdapter as ParityDbAdapter, + }; + use std::sync::Arc; + + let approval_db_config = + ApprovalDbConfig { col_approval_data: super::REAL_COLUMNS.col_approval_data }; + + let _result = match db_kind { + DatabaseKind::ParityDB => { + let db = ParityDbAdapter::new( + parity_db::Db::open(&paritydb_version_3_config(path)) + .map_err(|e| other_io_error(format!("Error opening db {:?}", e)))?, + super::columns::v3::ORDERED_COL, + ); + + v1_to_v2(Arc::new(db), approval_db_config).map_err(|_| Error::MigrationFailed)?; + }, + DatabaseKind::RocksDB => { + let db_path = path + .to_str() + .ok_or_else(|| super::other_io_error("Invalid database path".into()))?; + let db_cfg = + kvdb_rocksdb::DatabaseConfig::with_columns(super::columns::v3::NUM_COLUMNS); + let db = RocksDbAdapter::new( + kvdb_rocksdb::Database::open(&db_cfg, db_path)?, + &super::columns::v3::ORDERED_COL, + ); + + v1_to_v2(Arc::new(db), approval_db_config).map_err(|_| Error::MigrationFailed)?; + }, + }; + + gum::info!(target: LOG_TARGET, "Migration complete! "); + Ok(CURRENT_VERSION) +} + +fn migrate_from_version_2_to_3(path: &Path, db_kind: DatabaseKind) -> Result { gum::info!(target: LOG_TARGET, "Migrating parachains db from version 2 to version 3 ..."); match db_kind { DatabaseKind::ParityDB => paritydb_migrate_from_version_2_to_3(path), @@ -143,7 +229,7 @@ fn migrate_from_version_2_to_3(path: &Path, db_kind: DatabaseKind) -> Result<(), /// Migration from version 0 to version 1: /// * the number of columns has changed from 3 to 5; -fn rocksdb_migrate_from_version_0_to_1(path: &Path) -> Result<(), Error> { +fn rocksdb_migrate_from_version_0_to_1(path: &Path) -> Result { use kvdb_rocksdb::{Database, DatabaseConfig}; let db_path = path @@ -155,12 +241,12 @@ fn rocksdb_migrate_from_version_0_to_1(path: &Path) -> Result<(), Error> { db.add_column()?; db.add_column()?; - Ok(()) + Ok(1) } /// Migration from version 1 to version 2: /// * the number of columns has changed from 5 to 6; -fn rocksdb_migrate_from_version_1_to_2(path: &Path) -> Result<(), Error> { +fn rocksdb_migrate_from_version_1_to_2(path: &Path) -> Result { use kvdb_rocksdb::{Database, DatabaseConfig}; let db_path = path @@ -171,10 +257,10 @@ fn rocksdb_migrate_from_version_1_to_2(path: &Path) -> Result<(), Error> { db.add_column()?; - Ok(()) + Ok(2) } -fn rocksdb_migrate_from_version_2_to_3(path: &Path) -> Result<(), Error> { +fn rocksdb_migrate_from_version_2_to_3(path: &Path) -> Result { use kvdb_rocksdb::{Database, DatabaseConfig}; let db_path = path @@ -185,7 +271,7 @@ fn rocksdb_migrate_from_version_2_to_3(path: &Path) -> Result<(), Error> { db.remove_last_column()?; - Ok(()) + Ok(3) } // This currently clears columns which had their configs altered between versions. @@ -249,7 +335,7 @@ fn paritydb_fix_columns( pub(crate) fn paritydb_version_1_config(path: &Path) -> parity_db::Options { let mut options = parity_db::Options::with_columns(&path, super::columns::v1::NUM_COLUMNS as u8); - for i in columns::v3::ORDERED_COL { + for i in columns::v4::ORDERED_COL { options.columns[*i as usize].btree_index = true; } @@ -260,7 +346,7 @@ pub(crate) fn paritydb_version_1_config(path: &Path) -> parity_db::Options { pub(crate) fn paritydb_version_2_config(path: &Path) -> parity_db::Options { let mut options = parity_db::Options::with_columns(&path, super::columns::v2::NUM_COLUMNS as u8); - for i in columns::v3::ORDERED_COL { + for i in columns::v4::ORDERED_COL { options.columns[*i as usize].btree_index = true; } @@ -278,48 +364,161 @@ pub(crate) fn paritydb_version_3_config(path: &Path) -> parity_db::Options { options } +/// Database configuration for version 0. This is useful just for testing. +#[cfg(test)] +pub(crate) fn paritydb_version_0_config(path: &Path) -> parity_db::Options { + let mut options = + parity_db::Options::with_columns(&path, super::columns::v0::NUM_COLUMNS as u8); + options.columns[super::columns::v4::COL_AVAILABILITY_META as usize].btree_index = true; + + options +} + /// Migration from version 0 to version 1. /// Cases covered: /// - upgrading from v0.9.23 or earlier -> the `dispute coordinator column` was changed /// - upgrading from v0.9.24+ -> this is a no op assuming the DB has been manually fixed as per /// release notes -fn paritydb_migrate_from_version_0_to_1(path: &Path) -> Result<(), Error> { +fn paritydb_migrate_from_version_0_to_1(path: &Path) -> Result { // Delete the `dispute coordinator` column if needed (if column configuration is changed). paritydb_fix_columns( path, paritydb_version_1_config(path), - vec![super::columns::v3::COL_DISPUTE_COORDINATOR_DATA], + vec![super::columns::v4::COL_DISPUTE_COORDINATOR_DATA], )?; - Ok(()) + Ok(1) } /// Migration from version 1 to version 2: /// - add a new column for session information storage -fn paritydb_migrate_from_version_1_to_2(path: &Path) -> Result<(), Error> { +fn paritydb_migrate_from_version_1_to_2(path: &Path) -> Result { let mut options = paritydb_version_1_config(path); // Adds the session info column. parity_db::Db::add_column(&mut options, Default::default()) .map_err(|e| other_io_error(format!("Error adding column {:?}", e)))?; - Ok(()) + Ok(2) } /// Migration from version 2 to version 3: /// - drop the column used by `RollingSessionWindow` -fn paritydb_migrate_from_version_2_to_3(path: &Path) -> Result<(), Error> { +fn paritydb_migrate_from_version_2_to_3(path: &Path) -> Result { parity_db::Db::drop_last_column(&mut paritydb_version_2_config(path)) .map_err(|e| other_io_error(format!("Error removing COL_SESSION_WINDOW_DATA {:?}", e)))?; - Ok(()) + Ok(3) +} + +/// Remove the lock file. If file is locked, it will wait up to 1s. +#[cfg(test)] +pub fn remove_file_lock(path: &std::path::Path) { + use std::{io::ErrorKind, thread::sleep, time::Duration}; + + let mut lock_path = std::path::PathBuf::from(path); + lock_path.push("lock"); + + for _ in 0..10 { + let result = std::fs::remove_file(lock_path.as_path()); + match result { + Err(error) => match error.kind() { + ErrorKind::WouldBlock => { + sleep(Duration::from_millis(100)); + continue + }, + _ => return, + }, + Ok(_) => {}, + } + } + + unreachable!("Database is locked, waited 1s for lock file: {:?}", lock_path); } #[cfg(test)] mod tests { use super::{ - columns::{v2::COL_SESSION_WINDOW_DATA, v3::*}, + columns::{v2::COL_SESSION_WINDOW_DATA, v4::*}, *, }; + use polkadot_node_core_approval_voting::approval_db::v2::migration_helpers::v1_to_v2_fill_test_data; + use test_helpers::dummy_candidate_receipt; + + #[test] + fn test_paritydb_migrate_0_to_1() { + use parity_db::Db; + + let db_dir = tempfile::tempdir().unwrap(); + let path = db_dir.path(); + { + let db = Db::open_or_create(&paritydb_version_0_config(&path)).unwrap(); + + db.commit(vec![( + COL_AVAILABILITY_META as u8, + b"5678".to_vec(), + Some(b"somevalue".to_vec()), + )]) + .unwrap(); + } + + try_upgrade_db(&path, DatabaseKind::ParityDB, 1).unwrap(); + + let db = Db::open(&paritydb_version_1_config(&path)).unwrap(); + assert_eq!( + db.get(COL_AVAILABILITY_META as u8, b"5678").unwrap(), + Some("somevalue".as_bytes().to_vec()) + ); + } + + #[test] + fn test_paritydb_migrate_1_to_2() { + use parity_db::Db; + + let db_dir = tempfile::tempdir().unwrap(); + let path = db_dir.path(); + + // We need to properly set db version for upgrade to work. + fs::write(version_file_path(path), "1").expect("Failed to write DB version"); + + { + let db = Db::open_or_create(&paritydb_version_1_config(&path)).unwrap(); + + // Write some dummy data + db.commit(vec![( + COL_DISPUTE_COORDINATOR_DATA as u8, + b"1234".to_vec(), + Some(b"somevalue".to_vec()), + )]) + .unwrap(); + + assert_eq!(db.num_columns(), columns::v1::NUM_COLUMNS as u8); + } + + try_upgrade_db(&path, DatabaseKind::ParityDB, 2).unwrap(); + + let db = Db::open(&paritydb_version_2_config(&path)).unwrap(); + + assert_eq!(db.num_columns(), columns::v2::NUM_COLUMNS as u8); + + assert_eq!( + db.get(COL_DISPUTE_COORDINATOR_DATA as u8, b"1234").unwrap(), + Some("somevalue".as_bytes().to_vec()) + ); + + // Test we can write the new column. + db.commit(vec![( + COL_SESSION_WINDOW_DATA as u8, + b"1337".to_vec(), + Some(b"0xdeadb00b".to_vec()), + )]) + .unwrap(); + + // Read back data from new column. + assert_eq!( + db.get(COL_SESSION_WINDOW_DATA as u8, b"1337").unwrap(), + Some("0xdeadb00b".as_bytes().to_vec()) + ); + } #[test] fn test_rocksdb_migrate_1_to_2() { @@ -338,7 +537,7 @@ mod tests { // We need to properly set db version for upgrade to work. fs::write(version_file_path(db_dir.path()), "1").expect("Failed to write DB version"); { - let db = DbAdapter::new(db, columns::v3::ORDERED_COL); + let db = DbAdapter::new(db, columns::v4::ORDERED_COL); db.write(DBTransaction { ops: vec![DBOp::Insert { col: COL_DISPUTE_COORDINATOR_DATA, @@ -349,14 +548,14 @@ mod tests { .unwrap(); } - try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB).unwrap(); + try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB, 2).unwrap(); let db_cfg = DatabaseConfig::with_columns(super::columns::v2::NUM_COLUMNS); let db = Database::open(&db_cfg, db_path).unwrap(); assert_eq!(db.num_columns(), super::columns::v2::NUM_COLUMNS); - let db = DbAdapter::new(db, columns::v3::ORDERED_COL); + let db = DbAdapter::new(db, columns::v4::ORDERED_COL); assert_eq!( db.get(COL_DISPUTE_COORDINATOR_DATA, b"1234").unwrap(), @@ -380,6 +579,109 @@ mod tests { ); } + #[test] + fn test_migrate_3_to_4() { + use kvdb_rocksdb::{Database, DatabaseConfig}; + use polkadot_node_core_approval_voting::approval_db::v2::migration_helpers::v1_to_v2_sanity_check; + use polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter; + + let db_dir = tempfile::tempdir().unwrap(); + let db_path = db_dir.path().to_str().unwrap(); + let db_cfg: DatabaseConfig = DatabaseConfig::with_columns(super::columns::v3::NUM_COLUMNS); + + let approval_cfg = ApprovalDbConfig { + col_approval_data: crate::parachains_db::REAL_COLUMNS.col_approval_data, + }; + + // We need to properly set db version for upgrade to work. + fs::write(version_file_path(db_dir.path()), "3").expect("Failed to write DB version"); + let expected_candidates = { + let db = Database::open(&db_cfg, db_path).unwrap(); + assert_eq!(db.num_columns(), super::columns::v3::NUM_COLUMNS as u32); + let db = DbAdapter::new(db, columns::v3::ORDERED_COL); + // Fill the approval voting column with test data. + v1_to_v2_fill_test_data(std::sync::Arc::new(db), approval_cfg, dummy_candidate_receipt) + .unwrap() + }; + + try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB, 4).unwrap(); + + let db_cfg = DatabaseConfig::with_columns(super::columns::v4::NUM_COLUMNS); + let db = Database::open(&db_cfg, db_path).unwrap(); + let db = DbAdapter::new(db, columns::v4::ORDERED_COL); + + v1_to_v2_sanity_check(std::sync::Arc::new(db), approval_cfg, expected_candidates).unwrap(); + } + + #[test] + fn test_rocksdb_migrate_0_to_4() { + use kvdb_rocksdb::{Database, DatabaseConfig}; + + let db_dir = tempfile::tempdir().unwrap(); + let db_path = db_dir.path().to_str().unwrap(); + + fs::write(version_file_path(db_dir.path()), "0").expect("Failed to write DB version"); + try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB, 4).unwrap(); + + let db_cfg = DatabaseConfig::with_columns(super::columns::v4::NUM_COLUMNS); + let db = Database::open(&db_cfg, db_path).unwrap(); + + assert_eq!(db.num_columns(), columns::v4::NUM_COLUMNS); + } + + #[test] + fn test_paritydb_migrate_0_to_4() { + use parity_db::Db; + + let db_dir = tempfile::tempdir().unwrap(); + let path = db_dir.path(); + + // We need to properly set db version for upgrade to work. + fs::write(version_file_path(path), "0").expect("Failed to write DB version"); + + { + let db = Db::open_or_create(&paritydb_version_0_config(&path)).unwrap(); + assert_eq!(db.num_columns(), columns::v0::NUM_COLUMNS as u8); + } + + try_upgrade_db(&path, DatabaseKind::ParityDB, 4).unwrap(); + + let db = Db::open(&paritydb_version_3_config(&path)).unwrap(); + assert_eq!(db.num_columns(), columns::v4::NUM_COLUMNS as u8); + } + + #[test] + fn test_paritydb_migrate_2_to_3() { + use parity_db::Db; + + let db_dir = tempfile::tempdir().unwrap(); + let path = db_dir.path(); + let test_key = b"1337"; + + // We need to properly set db version for upgrade to work. + fs::write(version_file_path(path), "2").expect("Failed to write DB version"); + + { + let db = Db::open_or_create(&paritydb_version_2_config(&path)).unwrap(); + + // Write some dummy data + db.commit(vec![( + COL_SESSION_WINDOW_DATA as u8, + test_key.to_vec(), + Some(b"0xdeadb00b".to_vec()), + )]) + .unwrap(); + + assert_eq!(db.num_columns(), columns::v2::NUM_COLUMNS as u8); + } + + try_upgrade_db(&path, DatabaseKind::ParityDB, 3).unwrap(); + + let db = Db::open(&paritydb_version_3_config(&path)).unwrap(); + + assert_eq!(db.num_columns(), columns::v3::NUM_COLUMNS as u8); + } + #[test] fn test_rocksdb_migrate_2_to_3() { use kvdb_rocksdb::{Database, DatabaseConfig}; @@ -387,6 +689,7 @@ mod tests { let db_dir = tempfile::tempdir().unwrap(); let db_path = db_dir.path().to_str().unwrap(); let db_cfg = DatabaseConfig::with_columns(super::columns::v2::NUM_COLUMNS); + { let db = Database::open(&db_cfg, db_path).unwrap(); assert_eq!(db.num_columns(), super::columns::v2::NUM_COLUMNS as u32); @@ -395,7 +698,7 @@ mod tests { // We need to properly set db version for upgrade to work. fs::write(version_file_path(db_dir.path()), "2").expect("Failed to write DB version"); - try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB).unwrap(); + try_upgrade_db(&db_dir.path(), DatabaseKind::RocksDB, 3).unwrap(); let db_cfg = DatabaseConfig::with_columns(super::columns::v3::NUM_COLUMNS); let db = Database::open(&db_cfg, db_path).unwrap(); diff --git a/polkadot/node/service/src/tests.rs b/polkadot/node/service/src/tests.rs index 86119662d9b..26c8083185d 100644 --- a/polkadot/node/service/src/tests.rs +++ b/polkadot/node/service/src/tests.rs @@ -17,7 +17,7 @@ use super::{relay_chain_selection::*, *}; use futures::channel::oneshot::Receiver; -use polkadot_node_primitives::approval::VrfSignature; +use polkadot_node_primitives::approval::v2::VrfSignature; use polkadot_node_subsystem::messages::{AllMessages, BlockDescription}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index a1c00cb0652..9fd3775da59 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -25,3 +25,4 @@ smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } thiserror = "1.0.48" async-trait = "0.1.57" +bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 6bc87438459..ce4fa6633dc 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -32,7 +32,10 @@ use polkadot_node_network_protocol::{ self as net_protocol, peer_set::PeerSet, request_response::Requests, PeerId, }; use polkadot_node_primitives::{ - approval::{BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote}, + approval::{ + v1::{BlockApprovalMeta, IndirectSignedApprovalVote}, + v2::{CandidateBitfield, IndirectAssignmentCertV2}, + }, AvailableData, BabeEpoch, BlockWeight, CandidateVotes, CollationGenerationConfig, CollationSecondedSignal, DisputeMessage, DisputeStatus, ErasureChunk, PoV, SignedDisputeStatement, SignedFullStatement, SignedFullStatementWithPVD, SubmitCollationParams, @@ -841,6 +844,8 @@ pub enum AssignmentCheckError { InvalidCert(ValidatorIndex, String), #[error("Internal state mismatch: {0:?}, {1:?}")] Internal(Hash, CandidateHash), + #[error("Oversized candidate or core bitfield >= {0}")] + InvalidBitfield(usize), } /// The result type of [`ApprovalVotingMessage::CheckAndImportApproval`] request. @@ -906,8 +911,8 @@ pub enum ApprovalVotingMessage { /// Check if the assignment is valid and can be accepted by our view of the protocol. /// Should not be sent unless the block hash is known. CheckAndImportAssignment( - IndirectAssignmentCert, - CandidateIndex, + IndirectAssignmentCertV2, + CandidateBitfield, oneshot::Sender, ), /// Check if the approval vote is valid and can be accepted by our view of the @@ -942,7 +947,7 @@ pub enum ApprovalDistributionMessage { NewBlocks(Vec), /// Distribute an assignment cert from the local validator. The cert is assumed /// to be valid, relevant, and for the given relay-parent and validator index. - DistributeAssignment(IndirectAssignmentCert, CandidateIndex), + DistributeAssignment(IndirectAssignmentCertV2, CandidateBitfield), /// Distribute an approval vote for the local validator. The approval vote is assumed to be /// valid, relevant, and the corresponding approval already issued. /// If not, the subsystem is free to drop the message. diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 4569d4e153b..578c3d6715d 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -39,3 +39,6 @@ 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/roadmap/implementers-guide/src/node/approval/approval-voting.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md index 6da2f5d9b88..1a17f90d9ba 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md @@ -75,22 +75,27 @@ struct TrancheEntry { assignments: Vec<(ValidatorIndex, Tick)>, } -struct OurAssignment { - cert: AssignmentCert, - tranche: DelayTranche, - validator_index: ValidatorIndex, - triggered: bool, +pub struct OurAssignment { + /// Our assignment certificate. + cert: AssignmentCertV2, + /// The tranche for which the assignment refers to. + tranche: DelayTranche, + /// Our validator index for the session in which the candidates were included. + validator_index: ValidatorIndex, + /// Whether the assignment has been triggered already. + triggered: bool, } -struct ApprovalEntry { - tranches: Vec, // sorted ascending by tranche number. - backing_group: GroupIndex, - our_assignment: Option, - our_approval_sig: Option, - assignments: Bitfield, // n_validators bits - approved: bool, +pub struct ApprovalEntry { + tranches: Vec, // sorted ascending by tranche number. + backing_group: GroupIndex, + our_assignment: Option, + our_approval_sig: Option, + assigned_validators: Bitfield, // `n_validators` bits. + approved: bool, } + struct CandidateEntry { candidate: CandidateReceipt, session: SessionIndex, @@ -264,19 +269,25 @@ entry. The cert itself contains information necessary to determine the candidate * Check the assignment cert * If the cert kind is `RelayVRFModulo`, then the certificate is valid as long as `sample < session_info.relay_vrf_samples` and the VRF is valid for the validator's key with the input - `block_entry.relay_vrf_story ++ sample.encode()` as described with [the approvals protocol - section](../../protocol-approval.md#assignment-criteria). We set `core_index = vrf.make_bytes().to_u32() % - session_info.n_cores`. If the `BlockEntry` causes inclusion of a candidate at `core_index`, then this is a valid - assignment for the candidate at `core_index` and has delay tranche 0. Otherwise, it can be ignored. - * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the input - `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol - section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not cause - inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included candidate. The - delay tranche for the assignment is determined by reducing `(vrf.make_bytes().to_u64() % - (session_info.n_delay_tranches + - session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. - * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary - signature. + `block_entry.relay_vrf_story ++ sample.encode()` as described with + [the approvals protocol section](../../protocol-approval.md#assignment-criteria). We set + `core_index = vrf.make_bytes().to_u32() % session_info.n_cores`. If the `BlockEntry` causes + inclusion of a candidate at `core_index`, then this is a valid assignment for the candidate + at `core_index` and has delay tranche 0. Otherwise, it can be ignored. + * If the cert kind is `RelayVRFModuloCompact`, then the certificate is valid as long as the VRF + is valid for the validator's key with the input `block_entry.relay_vrf_story ++ relay_vrf_samples.encode()` + as described with [the approvals protocol section](../../protocol-approval.md#assignment-criteria). + We enforce that all `core_bitfield` indices are included in the set of the core indices sampled from the + VRF Output. The assignment is considered a valid tranche0 assignment for all claimed candidates if all + `core_bitfield` indices match the core indices where the claimed candidates were included at. + + * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the + input `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol + section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not + cause inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included + candidate. The delay tranche for the assignment is determined by reducing + `(vrf.make_bytes().to_u64() % (session_info.n_delay_tranches + session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. + * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary signature. * If the delay tranche is too far in the future, return `AssignmentCheckResult::TooFarInFuture`. * Import the assignment. * Load the candidate in question and access the `approval_entry` for the block hash the cert references. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-approval.md b/polkadot/roadmap/implementers-guide/src/protocol-approval.md index 9ba7f6da173..4fac8459145 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-approval.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-approval.md @@ -189,9 +189,10 @@ Assignment criteria compute actual assignments using stories and the validators' Assignment criteria output a `Position` consisting of both a `ParaId` to be checked, as well as a precedence `DelayTranche` for when the assignment becomes valid. -Assignment criteria come in three flavors, `RelayVRFModulo`, `RelayVRFDelay` and `RelayEquivocation`. Among these, both -`RelayVRFModulo` and `RelayVRFDelay` run a VRF whose input is the output of a `RelayVRFStory`, while `RelayEquivocation` -runs a VRF whose input is the output of a `RelayEquivocationStory`. +Assignment criteria come in four flavors, `RelayVRFModuloCompact`, `RelayVRFDelay`, `RelayEquivocation` and the +deprecated `RelayVRFModulo`. Among these, `RelayVRFModulo`, `RelayVRFModuloCompact` and `RelayVRFDelay` run a +VRF whose input is the output of a `RelayVRFStory`, while `RelayEquivocation` runs a VRF whose input is the +output of a `RelayEquivocationStory`. Among these, we have two distinct VRF output computations: @@ -203,6 +204,12 @@ sampled availability core in this relay chain block. We choose three samples in secure and efficient by increasing this to four or five, and reducing the backing checks accordingly. All successful `RelayVRFModulo` samples are assigned delay tranche zero. +`RelayVRFModuloCompact` runs a single samples whose VRF input is the `RelayVRFStory` and the sample count. Similar +to `RelayVRFModulo` introduces multiple core assignments for tranche zero. It computes the VRF output with +`schnorrkel::vrf::VRFInOut::make_bytes` using the context "A&V Core v2" and samples up to 160 bytes of the output +as an array of `u32`. Then reduces each `u32` modulo the number of availability cores, and outputs up +to `relay_vrf_modulo_samples` availability core indices. + There is no sampling process for `RelayVRFDelay` and `RelayEquivocation`. We instead run them on specific candidates and they compute a delay from their VRF output. `RelayVRFDelay` runs for all candidates included under, aka declared available by, a relay chain block, and inputs the associated VRF output via `RelayVRFStory`. `RelayEquivocation` runs @@ -223,14 +230,14 @@ We track all validators' announced approval assignments for each candidate assoc tells us which validators were assigned to which candidates. We permit at most one assignment per candidate per story per validator, so one validator could be assigned under both -the `RelayVRFDelay` and `RelayEquivocation` criteria, but not under both `RelayVRFModulo` and `RelayVRFDelay` criteria, -since those both use the same story. We permit only one approval vote per candidate per validator, which counts for any -applicable criteria. +the `RelayVRFDelay` and `RelayEquivocation` criteria, but not under both `RelayVRFModulo/RelayVRFModuloCompact` +and `RelayVRFDelay` criteria, since those both use the same story. We permit only one approval vote per candidate per +validator, which counts for any applicable criteria. We announce, and start checking for, our own assignments when the delay of their tranche is reached, but only if the -tracker says the assignee candidate requires more approval checkers. We never announce an assignment we believe -unnecessary because early announcements gives an adversary information. All delay tranche zero assignments always get -announced, which includes all `RelayVRFModulo` assignments. +tracker says the assignee candidate requires more approval checkers. We never announce an assignment we believe unnecessary +because early announcements gives an adversary information. All delay tranche zero assignments always get announced, +which includes all `RelayVRFModulo` and `RelayVRFModuloCompact` assignments. In other words, if some candidate `C` needs more approval checkers by the time we reach round `t` then any validators with an assignment to `C` in delay tranche `t` gossip their send assignment notice for `C`, and begin reconstruction and @@ -318,10 +325,10 @@ finality. We might explore limits on postponement too, but this sounds much har ## Parameters -We prefer doing approval checkers assignments under `RelayVRFModulo` as opposed to `RelayVRFDelay` because -`RelayVRFModulo` avoids giving individual checkers too many assignments and tranche zero assignments benefit security -the most. We suggest assigning at least 16 checkers under `RelayVRFModulo` although assignment levels have never been -properly analyzed. +We prefer doing approval checkers assignments under `RelayVRFModulo` or `RelayVRFModuloCompact` as opposed to +`RelayVRFDelay` because `RelayVRFModulo` avoids giving individual checkers too many assignments and tranche zero +assignments benefit security the most. We suggest assigning at least 16 checkers under `RelayVRFModulo` or +`RelayVRFModuloCompact` although assignment levels have never been properly analyzed. Our delay criteria `RelayVRFDelay` and `RelayEquivocation` both have two primary paramaters, expected checkers per tranche and the zeroth delay tranche width. diff --git a/polkadot/roadmap/implementers-guide/src/types/approval.md b/polkadot/roadmap/implementers-guide/src/types/approval.md index bc33f024426..c19ffa53762 100644 --- a/polkadot/roadmap/implementers-guide/src/types/approval.md +++ b/polkadot/roadmap/implementers-guide/src/types/approval.md @@ -22,6 +22,35 @@ enum AssignmentCertKind { } } +enum AssignmentCertKindV2 { + /// Multiple assignment stories based on the VRF that authorized the relay-chain block where the + /// candidates were included. + /// + /// The context is [`v2::RELAY_VRF_MODULO_CONTEXT`] + RelayVRFModuloCompact { + /// A bitfield representing the core indices claimed by this assignment. + core_bitfield: CoreBitfield, + }, + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with the index of a particular core. + /// + /// The context is [`v2::RELAY_VRF_DELAY_CONTEXT`] + RelayVRFDelay { + /// The core index chosen in this cert. + core_index: CoreIndex, + }, + /// Deprectated assignment. Soon to be removed. + /// + /// An assignment story based on the VRF that authorized the relay-chain block where the + /// candidate was included combined with a sample number. + /// + /// The context used to produce bytes is [`v1::RELAY_VRF_MODULO_CONTEXT`] + RelayVRFModulo { + /// The sample number used in this cert. + sample: u32, + }, +} + struct AssignmentCert { // The criterion which is claimed to be met by this cert. kind: AssignmentCertKind, diff --git a/polkadot/roadmap/implementers-guide/src/types/runtime.md b/polkadot/roadmap/implementers-guide/src/types/runtime.md index 79da899bd35..4b97409f8df 100644 --- a/polkadot/roadmap/implementers-guide/src/types/runtime.md +++ b/polkadot/roadmap/implementers-guide/src/types/runtime.md @@ -55,7 +55,7 @@ struct HostConfiguration { pub zeroth_delay_tranche_width: u32, /// The number of validators needed to approve a block. pub needed_approvals: u32, - /// The number of samples to do of the RelayVRFModulo approval assignment criterion. + /// The number of samples to use in `RelayVRFModulo` or `RelayVRFModuloCompact` approval assignment criterions. pub relay_vrf_modulo_samples: u32, /// Total number of individual messages allowed in the parachain -> relay-chain message queue. pub max_upward_queue_count: u32, diff --git a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml new file mode 100644 index 00000000000..68ac90f5a7e --- /dev/null +++ b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml @@ -0,0 +1,39 @@ +[settings] +timeout = 1000 +bootnode = true + +[relaychain.genesis.runtime.configuration.config] + max_validators_per_core = 1 + needed_approvals = 7 + relay_vrf_modulo_samples = 5 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "some-validator" + count = 8 + args = ["-lparachain=debug,runtime=debug"] + +{% for id in range(2000,2005) %} +[[parachains]] +id = {{id}} +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size={{10000*(id-1999)}} --pvf-complexity={{id - 1999}}" + [parachains.collator] + image = "{{COL_IMAGE}}" + name = "collator" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size={{10000*(id-1999)}}", "--parachain-id={{id}}", "--pvf-complexity={{id - 1999}}"] +{% endfor %} + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.zndsl b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.zndsl new file mode 100644 index 00000000000..6cec6c66797 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.zndsl @@ -0,0 +1,27 @@ +Description: Test if parachains make progress with most of approvals being tranch0 +Network: ./0006-parachains-max-tranche0.toml +Creds: config + +# Check authority status. +some-validator-0: reports node_roles is 4 +some-validator-1: reports node_roles is 4 +some-validator-3: reports node_roles is 4 +some-validator-4: reports node_roles is 4 +some-validator-5: reports node_roles is 4 +some-validator-6: reports node_roles is 4 +some-validator-7: reports node_roles is 4 + +some-validator-0: parachain 2000 block height is at least 5 within 180 seconds +some-validator-1: parachain 2001 block height is at least 5 within 180 seconds +some-validator-2: parachain 2002 block height is at least 5 within 180 seconds +some-validator-3: parachain 2003 block height is at least 5 within 180 seconds +some-validator-4: parachain 2004 block height is at least 5 within 180 seconds + +some-validator-0: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-1: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-2: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-3: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-4: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-5: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-6: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 +some-validator-7: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 diff --git a/prdoc/pr_1178.prdoc b/prdoc/pr_1178.prdoc new file mode 100644 index 00000000000..36c3b05c7a3 --- /dev/null +++ b/prdoc/pr_1178.prdoc @@ -0,0 +1,23 @@ +title: tranche0 assignments in one certificate part1 + +doc: + - audience: Node Operator + description: | + Changed approval-voting, approval-distribution to send all messages tranche0 assignments in one message. + This required: + * A new parachains_db version. + * A new validation protocol to support the new message types. + The new logic will be disabled and will be enabled at a later date after all validators have upgraded. + +migrations: + db: + - name: Parachains database change from v3 to v4. + description: | + Approval-voting column format has been updated with several new fields. All existing data will be automatically + be migrated to the new values. + +crates: + - name: "polkadot" + semver: patch + +host_functions: [] -- GitLab From 15df7f54d2c32a94bb91f73f19552c8bcde6a9fe Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Mon, 6 Nov 2023 18:30:09 +0200 Subject: [PATCH 452/633] minor: overseer availability-distribution message declaration update (#2179) availability-distribution subsystem is not sending availability-recovery messages. Update the overseer declaration to reflect this --- polkadot/node/overseer/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 6802426d3c7..5207bb830d8 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -498,7 +498,6 @@ pub struct Overseer { #[subsystem(AvailabilityDistributionMessage, sends: [ AvailabilityStoreMessage, - AvailabilityRecoveryMessage, ChainApiMessage, RuntimeApiMessage, NetworkBridgeTxMessage, -- GitLab From 32a974088c43d9abf849b15349268e0a8426845a Mon Sep 17 00:00:00 2001 From: Piet <75956460+PieWol@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:40:14 +0100 Subject: [PATCH 453/633] TryDecodeEntireState check for storage types and pallets (#1805) ### This PR is a port of this [PR for substrate](https://github.com/paritytech/substrate/pull/13013) by @kianenigma Add infrastructure needed to have a Pallet::decode_entire_state(), which makes sure all "typed" storage items defined in the pallet are decode-able. This is not enforced in any way at the moment. Teams who wish to integrate/use this in the try-runtime feature flag should add frame_support::storage::migration::EnsureStateDecodes as the LAST ITEM of the runtime's custom migrations, and pass it to frame-executive. This will make it usable in try-runtime on-runtime-upgrade. This now catches cases like https://github.com/paritytech/polkadot-sdk/pull/1969: ```pre ERROR runtime::executive] failed to decode the value at key: Failed to decode value at key: 0x94eadf0156a8ad5156507773d0471e4ab8ebad86f546c7e0b135a4212aace339. Storage info StorageInfo { pallet_name: Ok("ParaScheduler"), storage_name: Ok("AvailabilityCores"), prefix: Err(Utf8Error { valid_up_to: 0, error_len: Some(1) }), max_values: Some(1), max_size: None }. Raw value: Some("0x0c010101010101") ``` ... or: ![image](https://github.com/paritytech/polkadot-sdk/assets/10380170/73052d4f-4da5-4b21-a8dd-b17004e5965e) Closes #241 --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Liam Aharon --- prdoc/pr_1805.prdoc | 19 + .../bin/node-template/runtime/src/lib.rs | 7 + substrate/frame/executive/src/lib.rs | 72 ++- substrate/frame/glutton/src/lib.rs | 5 +- substrate/frame/support/Cargo.toml | 2 +- .../procedural/src/pallet/expand/event.rs | 3 +- .../procedural/src/pallet/expand/storage.rs | 59 +++ .../procedural/src/pallet/parse/storage.rs | 2 +- .../support/src/storage/generator/mod.rs | 6 +- .../support/src/storage/types/counted_map.rs | 14 +- .../support/src/storage/types/counted_nmap.rs | 6 +- .../frame/support/src/storage/types/mod.rs | 2 +- .../frame/support/src/storage/types/value.rs | 4 +- substrate/frame/support/src/traits.rs | 5 +- substrate/frame/support/src/traits/storage.rs | 4 +- .../traits/try_runtime/decode_entire_state.rs | 498 ++++++++++++++++++ .../{try_runtime.rs => try_runtime/mod.rs} | 17 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 59 +++ ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 59 +++ 19 files changed, 807 insertions(+), 36 deletions(-) create mode 100644 prdoc/pr_1805.prdoc create mode 100644 substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs rename substrate/frame/support/src/traits/{try_runtime.rs => try_runtime/mod.rs} (94%) diff --git a/prdoc/pr_1805.prdoc b/prdoc/pr_1805.prdoc new file mode 100644 index 00000000000..8a8e6c2fde2 --- /dev/null +++ b/prdoc/pr_1805.prdoc @@ -0,0 +1,19 @@ +title: Introduce state decoding check after runtime upgrades. + +doc: + - audience: Core Dev + description: | + Adds a check to the try-runtime logic that will verify that all pallet on-chain storage still decodes. This can help to spot missing migrations before they become a problem. The check is enabled as soon as the `--checks` option of the `try-runtime` CLI is not `None`. + +migrations: + db: [] + + runtime: [] + +crates: + - name: frame-support + semver: minor + - name: frame-support-procedural + semver: minor + +host_functions: [] diff --git a/substrate/bin/node-template/runtime/src/lib.rs b/substrate/bin/node-template/runtime/src/lib.rs index 62c24081cbe..6aa4cb70fde 100644 --- a/substrate/bin/node-template/runtime/src/lib.rs +++ b/substrate/bin/node-template/runtime/src/lib.rs @@ -313,6 +313,12 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, ); +/// All migrations of the runtime, aside from the ones declared in the pallets. +/// +/// This can be a tuple of types, each implementing `OnRuntimeUpgrade`. +#[allow(unused_parens)] +type Migrations = (); + /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; @@ -325,6 +331,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, + Migrations, >; #[cfg(feature = "runtime-benchmarks")] diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 1ca9629fd42..5f390c77baf 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -139,9 +139,15 @@ use sp_runtime::{ use sp_std::{marker::PhantomData, prelude::*}; #[cfg(feature = "try-runtime")] -use log; -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; +use ::{ + frame_support::{ + traits::{TryDecodeEntireStorage, TryDecodeEntireStorageError, TryState}, + StorageNoopGuard, + }, + frame_try_runtime::{TryStateSelect, UpgradeCheckSelect}, + log, + sp_runtime::TryRuntimeError, +}; #[allow(dead_code)] const LOG_TARGET: &str = "runtime::executive"; @@ -229,7 +235,8 @@ impl< + OnIdle> + OnFinalize> + OffchainWorker> - + frame_support::traits::TryState>, + + TryState> + + TryDecodeEntireStorage, COnRuntimeUpgrade: OnRuntimeUpgrade, > Executive where @@ -308,11 +315,15 @@ where let _guard = frame_support::StorageNoopGuard::default(); , - >>::try_state(*header.number(), select) + >>::try_state(*header.number(), select.clone()) .map_err(|e| { log::error!(target: LOG_TARGET, "failure: {:?}", e); e })?; + if select.any() { + let res = AllPalletsWithSystem::try_decode_entire_state(); + Self::log_decode_result(res)?; + } drop(_guard); // do some of the checks that would normally happen in `final_checks`, but perhaps skip @@ -352,26 +363,61 @@ where /// Execute all `OnRuntimeUpgrade` of this runtime. /// /// The `checks` param determines whether to execute `pre/post_upgrade` and `try_state` hooks. - pub fn try_runtime_upgrade( - checks: frame_try_runtime::UpgradeCheckSelect, - ) -> Result { + pub fn try_runtime_upgrade(checks: UpgradeCheckSelect) -> Result { let weight = <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( checks.pre_and_post(), )?; + // Nothing should modify the state after the migrations ran: + let _guard = StorageNoopGuard::default(); + // The state must be decodable: + if checks.any() { + let res = AllPalletsWithSystem::try_decode_entire_state(); + Self::log_decode_result(res)?; + } + + // Check all storage invariants: if checks.try_state() { - let _guard = frame_support::StorageNoopGuard::default(); - , - >>::try_state( + AllPalletsWithSystem::try_state( frame_system::Pallet::::block_number(), - frame_try_runtime::TryStateSelect::All, + TryStateSelect::All, )?; } Ok(weight) } + + /// Logs the result of trying to decode the entire state. + fn log_decode_result( + res: Result>, + ) -> Result<(), TryRuntimeError> { + match res { + Ok(bytes) => { + log::debug!( + target: LOG_TARGET, + "decoded the entire state ({bytes} bytes)", + ); + + Ok(()) + }, + Err(errors) => { + log::error!( + target: LOG_TARGET, + "`try_decode_entire_state` failed with {} errors", + errors.len(), + ); + + for (i, err) in errors.iter().enumerate() { + // We log the short version to `error` and then the full debug info to `debug`: + log::error!(target: LOG_TARGET, "- {i}. error: {err}"); + log::debug!(target: LOG_TARGET, "- {i}. error: {err:?}"); + } + + Err("`try_decode_entire_state` failed".into()) + }, + } + } } impl< diff --git a/substrate/frame/glutton/src/lib.rs b/substrate/frame/glutton/src/lib.rs index f5e90a17c73..344a70becae 100644 --- a/substrate/frame/glutton/src/lib.rs +++ b/substrate/frame/glutton/src/lib.rs @@ -21,9 +21,8 @@ //! //! # Glutton Pallet //! -//! Pallet that consumes `ref_time` and `proof_size` of a block. Based on the -//! `Compute` and `Storage` parameters the pallet consumes the adequate amount -//! of weight. +//! Pallet that consumes `ref_time` and `proof_size` of a block. Based on the `Compute` and +//! `Storage` parameters the pallet consumes the adequate amount of weight. #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index f8c8edc0510..b8e21e60761 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = { version = "6.1", default-features = false } serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } @@ -52,7 +53,6 @@ aquamarine = { version = "0.3.2" } assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { path = "../system" } -array-bytes = "6.1" [features] default = [ "std" ] diff --git a/substrate/frame/support/procedural/src/pallet/expand/event.rs b/substrate/frame/support/procedural/src/pallet/expand/event.rs index fbb699b4d41..2713f45fc3d 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/event.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/event.rs @@ -127,11 +127,12 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { let trait_use_gen = &def.trait_use_generics(event.attr_span); let type_impl_gen = &def.type_impl_generics(event.attr_span); let type_use_gen = &def.type_use_generics(event.attr_span); + let pallet_ident = &def.pallet_struct.pallet; let PalletEventDepositAttr { fn_vis, fn_span, .. } = deposit_event; quote::quote_spanned!(*fn_span => - impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause { + impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause { #fn_vis fn deposit_event(event: Event<#event_use_gen>) { let event = < ::RuntimeEvent as diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index e7f7cf548f0..96c2c8e3120 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -822,12 +822,69 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { ) }); + // aggregated where clause of all storage types and the whole pallet. let mut where_clauses = vec![&def.config.where_clause]; where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause)); let completed_where_clause = super::merge_where_clauses(&where_clauses); let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site()); + let try_decode_entire_state = { + let mut storage_names = def + .storages + .iter() + .filter_map(|storage| { + if storage.cfg_attrs.is_empty() { + let ident = &storage.ident; + let gen = &def.type_use_generics(storage.attr_span); + Some(quote::quote_spanned!(storage.attr_span => #ident<#gen> )) + } else { + None + } + }) + .collect::>(); + storage_names.sort_by_cached_key(|ident| ident.to_string()); + + quote::quote!( + #[cfg(feature = "try-runtime")] + impl<#type_impl_gen> #frame_support::traits::TryDecodeEntireStorage + for #pallet_ident<#type_use_gen> #completed_where_clause + { + fn try_decode_entire_state() -> Result> { + let pallet_name = <::PalletInfo as frame_support::traits::PalletInfo> + ::name::<#pallet_ident<#type_use_gen>>() + .expect("Every active pallet has a name in the runtime; qed"); + + #frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode pallet: {pallet_name}"); + + // NOTE: for now, we have to exclude storage items that are feature gated. + let mut errors = #frame_support::__private::sp_std::vec::Vec::new(); + let mut decoded = 0usize; + + #( + #frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode storage: \ + {pallet_name}::{}", stringify!(#storage_names)); + + match <#storage_names as #frame_support::traits::TryDecodeEntireStorage>::try_decode_entire_state() { + Ok(count) => { + decoded += count; + }, + Err(err) => { + errors.extend(err); + }, + } + )* + + if errors.is_empty() { + Ok(decoded) + } else { + Err(errors) + } + } + } + ) + }; + quote::quote!( impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause @@ -853,5 +910,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #( #getters )* #( #prefix_structs )* #( #on_empty_structs )* + + #try_decode_entire_state ) } diff --git a/substrate/frame/support/procedural/src/pallet/parse/storage.rs b/substrate/frame/support/procedural/src/pallet/parse/storage.rs index 3a0ec474715..d1c7ba2e5e3 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/storage.rs @@ -151,7 +151,7 @@ pub enum QueryKind { /// `type MyStorage = StorageValue` /// The keys and values types are parsed in order to get metadata pub struct StorageDef { - /// The index of error item in pallet module. + /// The index of storage item in pallet module. pub index: usize, /// Visibility of the storage type. pub vis: syn::Visibility, diff --git a/substrate/frame/support/src/storage/generator/mod.rs b/substrate/frame/support/src/storage/generator/mod.rs index bac9f642e37..2b2abdc2e83 100644 --- a/substrate/frame/support/src/storage/generator/mod.rs +++ b/substrate/frame/support/src/storage/generator/mod.rs @@ -24,10 +24,10 @@ //! //! This is internal api and is subject to change. -mod double_map; +pub(crate) mod double_map; pub(crate) mod map; -mod nmap; -mod value; +pub(crate) mod nmap; +pub(crate) mod value; pub use double_map::StorageDoubleMap; pub use map::StorageMap; diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 75fbdf2617d..04e69751c16 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -119,7 +119,11 @@ impl MapWrapper type Map = StorageMap; } -type CounterFor

= StorageValue<

::CounterPrefix, u32, ValueQuery>; +/// The numeric counter type. +pub type Counter = u32; + +type CounterFor

= + StorageValue<

::CounterPrefix, Counter, ValueQuery>; /// On removal logic for updating counter while draining upon some prefix with /// [`crate::storage::PrefixIterator`]. @@ -423,14 +427,14 @@ where /// can be very heavy, so use with caution. /// /// Returns the number of items in the map which is used to set the counter. - pub fn initialize_counter() -> u32 { - let count = Self::iter_values().count() as u32; + pub fn initialize_counter() -> Counter { + let count = Self::iter_values().count() as Counter; CounterFor::::set(count); count } /// Return the count. - pub fn count() -> u32 { + pub fn count() -> Counter { CounterFor::::get() } } @@ -1207,7 +1211,7 @@ mod test { StorageEntryMetadataIR { name: "counter_for_foo", modifier: StorageEntryModifierIR::Default, - ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: if cfg!(feature = "no-metadata-docs") { vec![] diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index c2c2197acee..279894ee973 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -114,8 +114,10 @@ impl MapWrapper type Map = StorageNMap; } +type Counter = super::counted_map::Counter; + type CounterFor

= - StorageValue<

::CounterPrefix, u32, ValueQuery>; + StorageValue<

::CounterPrefix, Counter, ValueQuery>; /// On removal logic for updating counter while draining upon some prefix with /// [`crate::storage::PrefixIterator`]. @@ -472,7 +474,7 @@ where } /// Return the count. - pub fn count() -> u32 { + pub fn count() -> Counter { CounterFor::::get() } } diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index 1d995d93e88..9dd6f4066e4 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -30,7 +30,7 @@ mod map; mod nmap; mod value; -pub use counted_map::{CountedStorageMap, CountedStorageMapInstance}; +pub use counted_map::{CountedStorageMap, CountedStorageMapInstance, Counter}; pub use counted_nmap::{CountedStorageNMap, CountedStorageNMapInstance}; pub use double_map::StorageDoubleMap; pub use key::{ diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 34cc3e24956..263091dd252 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -23,7 +23,7 @@ use crate::{ types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, StorageAppend, StorageDecodeLength, StorageTryAppend, }, - traits::{GetDefault, StorageInfo, StorageInstance}, + traits::{Get, GetDefault, StorageInfo, StorageInstance}, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use frame_support::storage::StorageDecodeNonDedupLength; @@ -72,7 +72,7 @@ where Prefix: StorageInstance, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, { type Query = QueryKind::Query; fn pallet_prefix() -> &'static [u8] { diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 4c692f848fd..12cc84027c4 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -126,4 +126,7 @@ pub use tx_pause::{TransactionPause, TransactionPauseError}; #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] -pub use try_runtime::{Select as TryStateSelect, TryState, UpgradeCheckSelect}; +pub use try_runtime::{ + Select as TryStateSelect, TryDecodeEntireStorage, TryDecodeEntireStorageError, TryState, + UpgradeCheckSelect, +}; diff --git a/substrate/frame/support/src/traits/storage.rs b/substrate/frame/support/src/traits/storage.rs index fe1b9bf13bb..9e467aea422 100644 --- a/substrate/frame/support/src/traits/storage.rs +++ b/substrate/frame/support/src/traits/storage.rs @@ -93,9 +93,7 @@ pub trait StorageInstance { } /// Metadata about storage from the runtime. -#[derive( - codec::Encode, codec::Decode, RuntimeDebug, Eq, PartialEq, Clone, scale_info::TypeInfo, -)] +#[derive(Debug, codec::Encode, codec::Decode, Eq, PartialEq, Clone, scale_info::TypeInfo)] pub struct StorageInfo { /// Encoded string of pallet name. pub pallet_name: Vec, diff --git a/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs new file mode 100644 index 00000000000..afbf291a0bb --- /dev/null +++ b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs @@ -0,0 +1,498 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types to check that the entire storage can be decoded. + +use super::StorageInstance; +use crate::{ + storage::types::{ + CountedStorageMapInstance, CountedStorageNMapInstance, Counter, KeyGenerator, + QueryKindTrait, + }, + traits::{PartialStorageInfoTrait, StorageInfo}, + StorageHasher, +}; +use codec::{Decode, DecodeAll, FullCodec}; +use impl_trait_for_tuples::impl_for_tuples; +use sp_core::Get; +use sp_std::prelude::*; + +/// Decode the entire data under the given storage type. +/// +/// For values, this is trivial. For all kinds of maps, it should decode all the values associated +/// with all keys existing in the map. +/// +/// Tuple implementations are provided and simply decode each type in the tuple, summing up the +/// decoded bytes if `Ok(_)`. +pub trait TryDecodeEntireStorage { + /// Decode the entire data under the given storage, returning `Ok(bytes_decoded)` if success. + fn try_decode_entire_state() -> Result>; +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl TryDecodeEntireStorage for Tuple { + fn try_decode_entire_state() -> Result> { + let mut errors = Vec::new(); + let mut len = 0usize; + + for_tuples!(#( + match Tuple::try_decode_entire_state() { + Ok(bytes) => len += bytes, + Err(errs) => errors.extend(errs), + } + )*); + + if errors.is_empty() { + Ok(len) + } else { + Err(errors) + } + } +} + +/// A value could not be decoded. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TryDecodeEntireStorageError { + /// The key of the undecodable value. + pub key: Vec, + /// The raw value. + pub raw: Option>, + /// The storage info of the key. + pub info: StorageInfo, +} + +impl core::fmt::Display for TryDecodeEntireStorageError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Failed to decode storage item `{}::{}`", + &sp_std::str::from_utf8(&self.info.pallet_name).unwrap_or(""), + &sp_std::str::from_utf8(&self.info.storage_name).unwrap_or(""), + ) + } +} + +/// Decode all the values based on the prefix of `info` to `V`. +/// +/// Basically, it decodes and sums up all the values who's key start with `info.prefix`. For values, +/// this would be the value itself. For all sorts of maps, this should be all map items in the +/// absence of key collision. +fn decode_storage_info( + info: StorageInfo, +) -> Result> { + let mut next_key = info.prefix.clone(); + let mut decoded = 0; + + let decode_key = |key: &[u8]| match sp_io::storage::get(key) { + None => Ok(0), + Some(bytes) => { + let len = bytes.len(); + let _ = ::decode_all(&mut bytes.as_ref()).map_err(|_| { + vec![TryDecodeEntireStorageError { + key: key.to_vec(), + raw: Some(bytes.to_vec()), + info: info.clone(), + }] + })?; + + Ok::>(len) + }, + }; + + decoded += decode_key(&next_key)?; + loop { + match sp_io::storage::next_key(&next_key) { + Some(key) if key.starts_with(&info.prefix) => { + decoded += decode_key(&key)?; + next_key = key; + }, + _ => break, + } + } + + Ok(decoded) +} + +impl TryDecodeEntireStorage + for crate::storage::types::StorageValue +where + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, +{ + fn try_decode_entire_state() -> Result> { + let info = Self::partial_storage_info() + .first() + .cloned() + .expect("Value has only one storage info; qed"); + decode_storage_info::(info) + } +} + +impl TryDecodeEntireStorage + for crate::storage::types::StorageMap +where + Prefix: StorageInstance, + Hasher: StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn try_decode_entire_state() -> Result> { + let info = Self::partial_storage_info() + .first() + .cloned() + .expect("Map has only one storage info; qed"); + decode_storage_info::(info) + } +} + +impl TryDecodeEntireStorage + for crate::storage::types::CountedStorageMap< + Prefix, + Hasher, + Key, + Value, + QueryKind, + OnEmpty, + MaxValues, + > where + Prefix: CountedStorageMapInstance, + Hasher: StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn try_decode_entire_state() -> Result> { + let (map_info, counter_info) = match &Self::partial_storage_info()[..] { + [a, b] => (a.clone(), b.clone()), + _ => panic!("Counted map has two storage info items; qed"), + }; + let mut decoded = decode_storage_info::(counter_info)?; + decoded += decode_storage_info::(map_info)?; + Ok(decoded) + } +} + +impl + TryDecodeEntireStorage + for crate::storage::types::StorageDoubleMap< + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind, + OnEmpty, + MaxValues, + > where + Prefix: StorageInstance, + Hasher1: StorageHasher, + Key1: FullCodec, + Hasher2: StorageHasher, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn try_decode_entire_state() -> Result> { + let info = Self::partial_storage_info() + .first() + .cloned() + .expect("Double-map has only one storage info; qed"); + decode_storage_info::(info) + } +} + +impl TryDecodeEntireStorage + for crate::storage::types::StorageNMap +where + Prefix: StorageInstance, + Key: KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn try_decode_entire_state() -> Result> { + let info = Self::partial_storage_info() + .first() + .cloned() + .expect("N-map has only one storage info; qed"); + decode_storage_info::(info) + } +} + +impl TryDecodeEntireStorage + for crate::storage::types::CountedStorageNMap +where + Prefix: CountedStorageNMapInstance, + Key: KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn try_decode_entire_state() -> Result> { + let (map_info, counter_info) = match &Self::partial_storage_info()[..] { + [a, b] => (a.clone(), b.clone()), + _ => panic!("Counted NMap has two storage info items; qed"), + }; + + let mut decoded = decode_storage_info::(counter_info)?; + decoded += decode_storage_info::(map_info)?; + Ok(decoded) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + storage::types::{self, CountedStorageMapInstance, CountedStorageNMapInstance, Key}, + Blake2_128Concat, + }; + + type H = Blake2_128Concat; + + macro_rules! build_prefix { + ($name:ident) => { + struct $name; + impl StorageInstance for $name { + fn pallet_prefix() -> &'static str { + "test_pallet" + } + const STORAGE_PREFIX: &'static str = stringify!($name); + } + }; + } + + build_prefix!(ValuePrefix); + type Value = types::StorageValue; + + build_prefix!(MapPrefix); + type Map = types::StorageMap; + + build_prefix!(CMapCounterPrefix); + build_prefix!(CMapPrefix); + impl CountedStorageMapInstance for CMapPrefix { + type CounterPrefix = CMapCounterPrefix; + } + type CMap = types::CountedStorageMap; + + build_prefix!(DMapPrefix); + type DMap = types::StorageDoubleMap; + + build_prefix!(NMapPrefix); + type NMap = types::StorageNMap, Key), u128>; + + build_prefix!(CountedNMapCounterPrefix); + build_prefix!(CountedNMapPrefix); + impl CountedStorageNMapInstance for CountedNMapPrefix { + type CounterPrefix = CountedNMapCounterPrefix; + } + type CNMap = types::CountedStorageNMap, Key), u128>; + + #[test] + fn try_decode_entire_state_value_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(Value::try_decode_entire_state(), Ok(0)); + + Value::put(42); + assert_eq!(Value::try_decode_entire_state(), Ok(4)); + + Value::kill(); + assert_eq!(Value::try_decode_entire_state(), Ok(0)); + + // two bytes, cannot be decoded into u32. + sp_io::storage::set(&Value::hashed_key(), &[0u8, 1]); + assert!(Value::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_map_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(Map::try_decode_entire_state(), Ok(0)); + + Map::insert(0, 42); + assert_eq!(Map::try_decode_entire_state(), Ok(4)); + + Map::insert(0, 42); + assert_eq!(Map::try_decode_entire_state(), Ok(4)); + + Map::insert(1, 42); + assert_eq!(Map::try_decode_entire_state(), Ok(8)); + + Map::remove(0); + assert_eq!(Map::try_decode_entire_state(), Ok(4)); + + // two bytes, cannot be decoded into u32. + sp_io::storage::set(&Map::hashed_key_for(2), &[0u8, 1]); + assert!(Map::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_counted_map_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + // counter is not even initialized; + assert_eq!(CMap::try_decode_entire_state(), Ok(0 + 0)); + + let counter = 4; + let value_size = std::mem::size_of::(); + + CMap::insert(0, 42); + assert_eq!(CMap::try_decode_entire_state(), Ok(value_size + counter)); + + CMap::insert(0, 42); + assert_eq!(CMap::try_decode_entire_state(), Ok(value_size + counter)); + + CMap::insert(1, 42); + assert_eq!(CMap::try_decode_entire_state(), Ok(value_size * 2 + counter)); + + CMap::remove(0); + assert_eq!(CMap::try_decode_entire_state(), Ok(value_size + counter)); + + // counter is cleared again. + let _ = CMap::clear(u32::MAX, None); + assert_eq!(CMap::try_decode_entire_state(), Ok(0 + 0)); + + // 1 bytes, cannot be decoded into u16. + sp_io::storage::set(&CMap::hashed_key_for(2), &[0u8]); + assert!(CMap::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_double_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(DMap::try_decode_entire_state(), Ok(0)); + + DMap::insert(0, 0, 42); + assert_eq!(DMap::try_decode_entire_state(), Ok(4)); + + DMap::insert(0, 0, 42); + assert_eq!(DMap::try_decode_entire_state(), Ok(4)); + + DMap::insert(0, 1, 42); + assert_eq!(DMap::try_decode_entire_state(), Ok(8)); + + DMap::insert(1, 0, 42); + assert_eq!(DMap::try_decode_entire_state(), Ok(12)); + + DMap::remove(0, 0); + assert_eq!(DMap::try_decode_entire_state(), Ok(8)); + + // two bytes, cannot be decoded into u32. + sp_io::storage::set(&DMap::hashed_key_for(1, 1), &[0u8, 1]); + assert!(DMap::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_n_map_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(NMap::try_decode_entire_state(), Ok(0)); + + let value_size = std::mem::size_of::(); + + NMap::insert((0u8, 0), 42); + assert_eq!(NMap::try_decode_entire_state(), Ok(value_size)); + + NMap::insert((0, 0), 42); + assert_eq!(NMap::try_decode_entire_state(), Ok(value_size)); + + NMap::insert((0, 1), 42); + assert_eq!(NMap::try_decode_entire_state(), Ok(value_size * 2)); + + NMap::insert((1, 0), 42); + assert_eq!(NMap::try_decode_entire_state(), Ok(value_size * 3)); + + NMap::remove((0, 0)); + assert_eq!(NMap::try_decode_entire_state(), Ok(value_size * 2)); + + // two bytes, cannot be decoded into u128. + sp_io::storage::set(&NMap::hashed_key_for((1, 1)), &[0u8, 1]); + assert!(NMap::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_counted_n_map_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(NMap::try_decode_entire_state(), Ok(0)); + + let value_size = std::mem::size_of::(); + let counter = 4; + + CNMap::insert((0u8, 0), 42); + assert_eq!(CNMap::try_decode_entire_state(), Ok(value_size + counter)); + + CNMap::insert((0, 0), 42); + assert_eq!(CNMap::try_decode_entire_state(), Ok(value_size + counter)); + + CNMap::insert((0, 1), 42); + assert_eq!(CNMap::try_decode_entire_state(), Ok(value_size * 2 + counter)); + + CNMap::insert((1, 0), 42); + assert_eq!(CNMap::try_decode_entire_state(), Ok(value_size * 3 + counter)); + + CNMap::remove((0, 0)); + assert_eq!(CNMap::try_decode_entire_state(), Ok(value_size * 2 + counter)); + + // two bytes, cannot be decoded into u128. + sp_io::storage::set(&CNMap::hashed_key_for((1, 1)), &[0u8, 1]); + assert!(CNMap::try_decode_entire_state().is_err()); + }) + }) + } + + #[test] + fn extra_bytes_are_rejected() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(Map::try_decode_entire_state(), Ok(0)); + + // 6bytes, too many to fit in u32, should be rejected. + sp_io::storage::set(&Map::hashed_key_for(2), &[0u8, 1, 3, 4, 5, 6]); + assert!(Map::try_decode_entire_state().is_err()); + }) + } + + #[test] + fn try_decode_entire_state_tuple_of_storage_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!(<(Value, Map) as TryDecodeEntireStorage>::try_decode_entire_state(), Ok(0)); + + Value::put(42); + assert_eq!(<(Value, Map) as TryDecodeEntireStorage>::try_decode_entire_state(), Ok(4)); + + Map::insert(0, 42); + assert_eq!(<(Value, Map) as TryDecodeEntireStorage>::try_decode_entire_state(), Ok(8)); + }); + } +} diff --git a/substrate/frame/support/src/traits/try_runtime.rs b/substrate/frame/support/src/traits/try_runtime/mod.rs similarity index 94% rename from substrate/frame/support/src/traits/try_runtime.rs rename to substrate/frame/support/src/traits/try_runtime/mod.rs index e7a1fe109fc..bec2dbf549a 100644 --- a/substrate/frame/support/src/traits/try_runtime.rs +++ b/substrate/frame/support/src/traits/try_runtime/mod.rs @@ -17,6 +17,11 @@ //! Try-runtime specific traits and types. +pub mod decode_entire_state; +pub use decode_entire_state::{TryDecodeEntireStorage, TryDecodeEntireStorageError}; + +use super::StorageInstance; + use impl_trait_for_tuples::impl_for_tuples; use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_runtime::TryRuntimeError; @@ -37,6 +42,13 @@ pub enum Select { Only(Vec>), } +impl Select { + /// Whether to run any checks at all. + pub fn any(&self) -> bool { + !matches!(self, Select::None) + } +} + impl Default for Select { fn default() -> Self { Select::None @@ -105,6 +117,11 @@ impl UpgradeCheckSelect { pub fn try_state(&self) -> bool { matches!(self, Self::All | Self::TryState) } + + /// Whether to run any checks at all. + pub fn any(&self) -> bool { + !matches!(self, Self::None) + } } #[cfg(feature = "std")] 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 930af1d7fcb..7375bcd2f16 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 @@ -128,3 +128,62 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = help: the following other types implement trait `WrapperTypeDecode`: + Box + 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 `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = help: the following other types implement trait `EncodeLike`: + + + + + + + + + and $N others + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = help: the following other types implement trait `WrapperTypeEncode`: + 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 + and $N others + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/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 79798963c8b..3a0a25712aa 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 @@ -128,3 +128,62 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = help: the following other types implement trait `WrapperTypeDecode`: + Box + 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 `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = help: the following other types implement trait `EncodeLike`: + + + + + + + + + and $N others + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + | +18 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = help: the following other types implement trait `WrapperTypeEncode`: + 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 + and $N others + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) -- GitLab From c4211b6533bd4dbb5a77b861c1ea35d9885b4f4f Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 7 Nov 2023 15:12:40 +1100 Subject: [PATCH 454/633] Initialise on-chain `StorageVersion` for pallets added after genesis (#1297) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original PR https://github.com/paritytech/substrate/pull/14641 --- Closes https://github.com/paritytech/polkadot-sdk/issues/109 ### Problem Quoting from the above issue: > When adding a pallet to chain after genesis we currently don't set the StorageVersion. So, when calling on_chain_storage_version it returns 0 while the pallet is maybe already at storage version 9 when it was added to the chain. This could lead to issues when running migrations. ### Solution - Create a new trait `BeforeAllRuntimeMigrations` with a single method `fn before_all_runtime_migrations() -> Weight` trait with a noop default implementation - Modify `Executive` to call `BeforeAllRuntimeMigrations::before_all_runtime_migrations` for all pallets before running any other hooks - Implement `BeforeAllRuntimeMigrations` in the pallet proc macro to initialize the on-chain version to the current pallet version if the pallet has no storage set (indicating it has been recently added to the runtime and needs to have its version initialised). ### Other changes in this PR - Abstracted repeated boilerplate to access the `pallet_name` in the pallet expand proc macro. ### FAQ #### Why create a new hook instead of adding this logic to the pallet `pre_upgrade`? `Executive` currently runs `COnRuntimeUpgrade` (custom migrations) before `AllPalletsWithSystem` migrations. We need versions to be initialized before the `COnRuntimeUpgrade` migrations are run, because `COnRuntimeUpgrade` migrations may use the on-chain version for critical logic. e.g. `VersionedRuntimeUpgrade` uses it to decide whether or not to execute. We cannot reorder `COnRuntimeUpgrade` and `AllPalletsWithSystem` so `AllPalletsWithSystem` runs first, because `AllPalletsWithSystem` have some logic in their `post_upgrade` hooks to verify that the on-chain version and current pallet version match. A common use case of `COnRuntimeUpgrade` migrations is to perform a migration which will result in the versions matching, so if they were reordered these `post_upgrade` checks would fail. #### Why init the on-chain version for pallets without a current storage version? We must init the on-chain version for pallets even if they don't have a defined storage version so if there is a future version bump, the on-chain version is not automatically set to that new version without a proper migration. e.g. bad scenario: 1. A pallet with no 'current version' is added to the runtime 2. Later, the pallet is upgraded with the 'current version' getting set to 1 and a migration is added to Executive Migrations to migrate the storage from 0 to 1 a. Runtime upgrade occurs b. `before_all` hook initializes the on-chain version to 1 c. `on_runtime_upgrade` of the migration executes, and sees the on-chain version is already 1 therefore think storage is already migrated and does not execute the storage migration Now, on-chain version is 1 but storage is still at version 0. By always initializing the on-chain version when the pallet is added to the runtime we avoid that scenario. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- substrate/frame/executive/src/lib.rs | 16 +++- .../procedural/src/pallet/expand/hooks.rs | 93 +++++++++++++------ substrate/frame/support/src/lib.rs | 2 +- substrate/frame/support/src/migrations.rs | 4 +- substrate/frame/support/src/traits.rs | 4 +- substrate/frame/support/src/traits/hooks.rs | 27 ++++++ .../frame/support/src/traits/metadata.rs | 17 ++++ substrate/frame/support/test/tests/pallet.rs | 60 +++++++++++- 8 files changed, 182 insertions(+), 41 deletions(-) diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 5f390c77baf..e2c906c1bf6 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -121,8 +121,8 @@ use frame_support::{ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::InvalidTransaction, traits::{ - EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, OnFinalize, OnIdle, OnInitialize, - OnRuntimeUpgrade, + BeforeAllRuntimeMigrations, EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, + OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, }, weights::Weight, }; @@ -194,6 +194,7 @@ impl< Context: Default, UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + + BeforeAllRuntimeMigrations + OnInitialize> + OnIdle> + OnFinalize> @@ -231,6 +232,7 @@ impl< Context: Default, UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + + BeforeAllRuntimeMigrations + OnInitialize> + OnIdle> + OnFinalize> @@ -364,7 +366,9 @@ where /// /// The `checks` param determines whether to execute `pre/post_upgrade` and `try_state` hooks. pub fn try_runtime_upgrade(checks: UpgradeCheckSelect) -> Result { - let weight = + let before_all_weight = + ::before_all_runtime_migrations(); + let try_on_runtime_upgrade_weight = <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( checks.pre_and_post(), )?; @@ -385,7 +389,7 @@ where )?; } - Ok(weight) + Ok(before_all_weight.saturating_add(try_on_runtime_upgrade_weight)) } /// Logs the result of trying to decode the entire state. @@ -429,6 +433,7 @@ impl< Context: Default, UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + + BeforeAllRuntimeMigrations + OnInitialize> + OnIdle> + OnFinalize> @@ -445,7 +450,10 @@ where { /// Execute all `OnRuntimeUpgrade` of this runtime, and return the aggregate weight. pub fn execute_on_runtime_upgrade() -> Weight { + let before_all_weight = + ::before_all_runtime_migrations(); <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() + .saturating_add(before_all_weight) } /// Start the execution of a particular block. diff --git a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs index aaad4dd2be0..5044d4285bb 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs @@ -34,6 +34,38 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let type_use_gen = &def.type_use_generics(span); let pallet_ident = &def.pallet_struct.pallet; let frame_system = &def.frame_system; + let pallet_name = quote::quote! { + < + ::PalletInfo + as + #frame_support::traits::PalletInfo + >::name::().unwrap_or("") + }; + + let initialize_on_chain_storage_version = if let Some(current_version) = + &def.pallet_struct.storage_version + { + quote::quote! { + #frame_support::__private::log::info!( + target: #frame_support::LOG_TARGET, + "🐥 New pallet {:?} detected in the runtime. Initializing the on-chain storage version to match the storage version defined in the pallet: {:?}", + #pallet_name, + #current_version + ); + #current_version.put::(); + } + } else { + quote::quote! { + let default_version = #frame_support::traits::StorageVersion::new(0); + #frame_support::__private::log::info!( + target: #frame_support::LOG_TARGET, + "🐥 New pallet {:?} detected in the runtime. The pallet has no defined storage version, so the on-chain version is being initialized to {:?}.", + #pallet_name, + default_version + ); + default_version.put::(); + } + }; let log_runtime_upgrade = if has_runtime_upgrade { // a migration is defined here. @@ -42,7 +74,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { target: #frame_support::LOG_TARGET, "⚠️ {} declares internal migrations (which *might* execute). \ On-chain `{:?}` vs current storage version `{:?}`", - pallet_name, + #pallet_name, ::on_chain_storage_version(), ::current_storage_version(), ); @@ -53,7 +85,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::log::debug!( target: #frame_support::LOG_TARGET, "✅ no migration for {}", - pallet_name, + #pallet_name, ); } }; @@ -78,16 +110,10 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let current_version = ::current_storage_version(); if on_chain_version != current_version { - let pallet_name = < - ::PalletInfo - as - #frame_support::traits::PalletInfo - >::name::().unwrap_or(""); - #frame_support::__private::log::error!( target: #frame_support::LOG_TARGET, "{}: On chain storage version {:?} doesn't match current storage version {:?}.", - pallet_name, + #pallet_name, on_chain_version, current_version, ); @@ -100,17 +126,11 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let on_chain_version = ::on_chain_storage_version(); if on_chain_version != #frame_support::traits::StorageVersion::new(0) { - let pallet_name = < - ::PalletInfo - as - #frame_support::traits::PalletInfo - >::name::().unwrap_or(""); - #frame_support::__private::log::error!( target: #frame_support::LOG_TARGET, "{}: On chain storage version {:?} is set to non zero, \ while the pallet is missing the `#[pallet::storage_version(VERSION)]` attribute.", - pallet_name, + #pallet_name, on_chain_version, ); @@ -173,6 +193,32 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } } + impl<#type_impl_gen> + #frame_support::traits::BeforeAllRuntimeMigrations + for #pallet_ident<#type_use_gen> #where_clause + { + fn before_all_runtime_migrations() -> #frame_support::weights::Weight { + use #frame_support::traits::{Get, PalletInfoAccess}; + use #frame_support::__private::hashing::twox_128; + use #frame_support::storage::unhashed::contains_prefixed_key; + #frame_support::__private::sp_tracing::enter_span!( + #frame_support::__private::sp_tracing::trace_span!("before_all") + ); + + // Check if the pallet has any keys set, including the storage version. If there are + // no keys set, the pallet was just added to the runtime and needs to have its + // version initialized. + let pallet_hashed_prefix = ::name_hash(); + let exists = contains_prefixed_key(&pallet_hashed_prefix); + if !exists { + #initialize_on_chain_storage_version + ::DbWeight::get().reads_writes(1, 1) + } else { + ::DbWeight::get().reads(1) + } + } + } + impl<#type_impl_gen> #frame_support::traits::OnRuntimeUpgrade for #pallet_ident<#type_use_gen> #where_clause @@ -183,11 +229,6 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { ); // log info about the upgrade. - let pallet_name = < - ::PalletInfo - as - #frame_support::traits::PalletInfo - >::name::().unwrap_or(""); #log_runtime_upgrade < @@ -258,16 +299,10 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { n: #frame_system::pallet_prelude::BlockNumberFor::, _s: #frame_support::traits::TryStateSelect ) -> Result<(), #frame_support::sp_runtime::TryRuntimeError> { - let pallet_name = < - ::PalletInfo - as - #frame_support::traits::PalletInfo - >::name::().expect("No name found for the pallet! This usually means that the pallet wasn't added to `construct_runtime!`."); - #frame_support::__private::log::info!( target: #frame_support::LOG_TARGET, "🩺 Running {:?} try-state checks", - pallet_name, + #pallet_name, ); < Self as #frame_support::traits::Hooks< @@ -277,7 +312,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::log::error!( target: #frame_support::LOG_TARGET, "❌ {:?} try_state checks failed: {:?}", - pallet_name, + #pallet_name, err ); diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index d4958868685..a01f3a01593 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -47,7 +47,7 @@ pub mod __private { 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_io::{self, hashing, storage::root as storage_root}; pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index d6ae6c6291b..22471e883a7 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!( - "🚚 Pallet {:?} migrating storage version from {:?} to {:?}.", + "🚚 Pallet {:?} VersionedMigration migrating storage version from {:?} to {:?}.", Pallet::name(), FROM, TO @@ -134,7 +134,7 @@ impl< weight.saturating_add(DbWeight::get().reads_writes(1, 1)) } else { log::warn!( - "🚚 Pallet {:?} migration {}->{} can be removed; on-chain is already at {:?}.", + "🚚 Pallet {:?} VersionedMigration migration {}->{} can be removed; on-chain is already at {:?}.", Pallet::name(), FROM, TO, diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 12cc84027c4..6362e750d2a 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -84,8 +84,8 @@ mod hooks; #[allow(deprecated)] pub use hooks::GenesisBuild; pub use hooks::{ - BuildGenesisConfig, Hooks, IntegrityTest, OnFinalize, OnGenesis, OnIdle, OnInitialize, - OnRuntimeUpgrade, OnTimestampSet, + BeforeAllRuntimeMigrations, BuildGenesisConfig, Hooks, IntegrityTest, OnFinalize, OnGenesis, + OnIdle, OnInitialize, OnRuntimeUpgrade, OnTimestampSet, }; pub mod schedule; diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index 6acecb8928d..20788ce932d 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -99,6 +99,19 @@ pub trait OnGenesis { fn on_genesis() {} } +/// Implemented by pallets, allows defining logic to run prior to any [`OnRuntimeUpgrade`] logic. +/// +/// This hook is intended to be used internally in FRAME and not be exposed to FRAME developers. +/// +/// It is defined as a seperate trait from [`OnRuntimeUpgrade`] precisely to not pollute the public +/// API. +pub trait BeforeAllRuntimeMigrations { + /// Something that should happen before runtime migrations are executed. + fn before_all_runtime_migrations() -> Weight { + Weight::zero() + } +} + /// See [`Hooks::on_runtime_upgrade`]. pub trait OnRuntimeUpgrade { /// See [`Hooks::on_runtime_upgrade`]. @@ -150,10 +163,24 @@ pub trait OnRuntimeUpgrade { } } +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl BeforeAllRuntimeMigrations for Tuple { + /// Implements the default behavior of + /// [`BeforeAllRuntimeMigrations::before_all_runtime_migrations`] for tuples. + fn before_all_runtime_migrations() -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight = weight.saturating_add(Tuple::before_all_runtime_migrations()); )* ); + weight + } +} + #[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { + /// Implements the default behavior of [`OnRuntimeUpgrade::on_runtime_upgrade`] for tuples. fn on_runtime_upgrade() -> Weight { let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); diff --git a/substrate/frame/support/src/traits/metadata.rs b/substrate/frame/support/src/traits/metadata.rs index bd29b600916..0af8d06719f 100644 --- a/substrate/frame/support/src/traits/metadata.rs +++ b/substrate/frame/support/src/traits/metadata.rs @@ -222,6 +222,23 @@ impl StorageVersion { crate::storage::unhashed::get_or_default(&key) } + + /// Returns if the storage version key for the given pallet exists in storage. + /// + /// See [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built. + /// + /// # Panics + /// + /// This function will panic iff `Pallet` can not be found by `PalletInfo`. + /// In a runtime that is put together using + /// [`construct_runtime!`](crate::construct_runtime) this should never happen. + /// + /// It will also panic if this function isn't executed in an externalities + /// provided environment. + pub fn exists() -> bool { + let key = Self::storage_key::

Changelog

Sourced from secp256k1's changelog.

0.28.0 - 2023-10-23

  • Add bindings to the ElligatorSwift implementation #627
  • Depend on recent release of bitcoin_hashes v0.13.0 #621
  • Add a verify function to PublicKey #618
  • Add serialize function for schnorr::Signature #607
  • Bump MSRV to 1.48 #595
  • Remove implementations of PartialEq, Eq, PartialOrd, Ord, and Hash from the impl_array_newtype macro. Users will now need to derive these traits if they are wanted.

0.27.0 - 2023-03-15

0.26.0 - 2202-12-19

  • Update libsecp25k1 to v0.2.0

0.25.0 - 2022-12-07

0.24.1 - 2022-10-25

0.24.0 - 2022-07-20

0.23.4 - 2022-07-14

0.23.3 - 2022-06-29

0.23.2 - 2022-06-27

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=secp256k1&package-manager=cargo&previous-version=0.24.3&new-version=0.28.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Liam Aharon --- Cargo.lock | 8 ++++---- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/core/src/ecdsa.rs | 13 ++++--------- substrate/primitives/io/Cargo.toml | 2 +- substrate/primitives/io/src/lib.rs | 4 ++-- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed9997101fb..ac64e65ee0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16602,18 +16602,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" dependencies = [ "cc", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 25478bed2d9..34485c72ab0 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -49,7 +49,7 @@ blake2 = { version = "0.10.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } +secp256k1 = { version = "0.28.0", default-features = false, features = ["recovery", "alloc"], optional = true } sp-core-hashing = { path = "hashing", default-features = false, optional = true } sp-runtime-interface = { path = "../runtime-interface", default-features = false} diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 603fa515a30..471714582a6 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -336,7 +336,7 @@ impl Signature { pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option { let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; - let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); #[cfg(feature = "std")] let context = SECP256K1; @@ -458,7 +458,7 @@ impl Pair { /// Sign a pre-hashed message pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { - let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); #[cfg(feature = "std")] let context = SECP256K1; @@ -508,12 +508,7 @@ impl Pair { #[cfg(feature = "full_crypto")] impl Drop for Pair { fn drop(&mut self) { - let ptr = self.secret.as_mut_ptr(); - for off in 0..self.secret.len() { - unsafe { - core::ptr::write_volatile(ptr.add(off), 0); - } - } + self.secret.non_secure_erase() } } @@ -760,7 +755,7 @@ mod test { let msg = [0u8; 32]; let sig1 = pair.sign_prehashed(&msg); let sig2: Signature = { - let message = Message::from_slice(&msg).unwrap(); + let message = Message::from_digest_slice(&msg).unwrap(); SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() }; assert_eq!(sig1, sig2); diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 445104b736e..59df8895bb7 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -28,7 +28,7 @@ sp-trie = { path = "../trie", default-features = false, optional = true} sp-externalities = { path = "../externalities", default-features = false} sp-tracing = { path = "../tracing", default-features = false} log = { version = "0.4.17", optional = true } -secp256k1 = { version = "0.24.0", features = ["recovery", "global-context"], optional = true } +secp256k1 = { version = "0.28.0", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.28", default-features = false} diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index c4182d6ab3a..a300152ee66 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1139,7 +1139,7 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadV)?; let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; - let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed"); + let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed"); let pubkey = SECP256K1 .recover_ecdsa(&msg, &sig) .map_err(|_| EcdsaVerifyError::BadSignature)?; @@ -1185,7 +1185,7 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadV)?; let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; - let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed"); + let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed"); let pubkey = SECP256K1 .recover_ecdsa(&msg, &sig) .map_err(|_| EcdsaVerifyError::BadSignature)?; -- GitLab From b5858936e13a8adc800655478c965daf54dbdc71 Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Mon, 20 Nov 2023 02:04:22 +0800 Subject: [PATCH 538/633] Preserve artifact cache unless stale (#1918) Co-authored-by: Marcin S --- Cargo.lock | 8 +- .../node/core/candidate-validation/src/lib.rs | 6 +- .../core/candidate-validation/src/tests.rs | 12 +- polkadot/node/core/pvf/Cargo.toml | 1 + .../benches/host_prepare_rococo_runtime.rs | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 3 + polkadot/node/core/pvf/common/build.rs | 19 + polkadot/node/core/pvf/common/src/error.rs | 18 +- polkadot/node/core/pvf/common/src/lib.rs | 2 + polkadot/node/core/pvf/common/src/prepare.rs | 19 + polkadot/node/core/pvf/common/src/pvf.rs | 2 +- .../node/core/pvf/prepare-worker/Cargo.toml | 1 + .../node/core/pvf/prepare-worker/src/lib.rs | 37 +- polkadot/node/core/pvf/src/artifacts.rs | 383 +++++++++++++----- polkadot/node/core/pvf/src/host.rs | 125 +++--- polkadot/node/core/pvf/src/lib.rs | 2 +- polkadot/node/core/pvf/src/prepare/pool.rs | 10 +- polkadot/node/core/pvf/src/prepare/queue.rs | 28 +- .../node/core/pvf/src/prepare/worker_intf.rs | 61 +-- polkadot/node/core/pvf/src/worker_intf.rs | 4 +- polkadot/node/core/pvf/tests/it/main.rs | 5 +- .../utils/build-script-utils/src/version.rs | 31 ++ 22 files changed, 535 insertions(+), 244 deletions(-) create mode 100644 polkadot/node/core/pvf/common/build.rs diff --git a/Cargo.lock b/Cargo.lock index ac64e65ee0e..b2d655e6f41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1585,16 +1585,15 @@ dependencies = [ [[package]] name = "blake3" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", "arrayvec 0.7.4", "cc", "cfg-if", "constant_time_eq 0.3.0", - "digest 0.10.7", ] [[package]] @@ -12568,6 +12567,7 @@ version = "1.0.0" dependencies = [ "always-assert", "assert_matches", + "blake3", "cfg-if", "criterion 0.4.0", "futures", @@ -12646,6 +12646,7 @@ dependencies = [ "sp-externalities 0.19.0", "sp-io", "sp-tracing 10.0.0", + "substrate-build-script-utils", "tempfile", "thiserror", "tracing-gum", @@ -12670,6 +12671,7 @@ dependencies = [ name = "polkadot-node-core-pvf-prepare-worker" version = "1.0.0" dependencies = [ + "blake3", "cfg-if", "criterion 0.4.0", "libc", diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index a3d6f047313..96ab07d3b82 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -25,7 +25,7 @@ use polkadot_node_core_pvf::{ InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PrepareError, - PrepareJobKind, PrepareStats, PvfPrepData, ValidationError, ValidationHost, + PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, }; use polkadot_node_primitives::{ BlockData, InvalidCandidate, PoV, ValidationResult, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT, @@ -794,7 +794,7 @@ trait ValidationBackend { validation_result } - async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result; + async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result<(), PrepareError>; } #[async_trait] @@ -824,7 +824,7 @@ impl ValidationBackend for ValidationHost { })? } - async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result { + async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result<(), PrepareError> { let (tx, rx) = oneshot::channel(); if let Err(err) = self.precheck_pvf(pvf, tx).await { // Return an IO error if there was an error communicating with the host. diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index cab823e1e63..801c581938a 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -377,7 +377,7 @@ impl ValidationBackend for MockValidateCandidateBackend { result } - async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result { + async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result<(), PrepareError> { unreachable!() } } @@ -1014,11 +1014,11 @@ fn pov_decompression_failure_is_invalid() { } struct MockPreCheckBackend { - result: Result, + result: Result<(), PrepareError>, } impl MockPreCheckBackend { - fn with_hardcoded_result(result: Result) -> Self { + fn with_hardcoded_result(result: Result<(), PrepareError>) -> Self { Self { result } } } @@ -1034,7 +1034,7 @@ impl ValidationBackend for MockPreCheckBackend { unreachable!() } - async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result { + async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result<(), PrepareError> { self.result.clone() } } @@ -1051,7 +1051,7 @@ fn precheck_works() { let (check_fut, check_result) = precheck_pvf( ctx.sender(), - MockPreCheckBackend::with_hardcoded_result(Ok(PrepareStats::default())), + MockPreCheckBackend::with_hardcoded_result(Ok(())), relay_parent, validation_code_hash, ) @@ -1113,7 +1113,7 @@ fn precheck_invalid_pvf_blob_compression() { let (check_fut, check_result) = precheck_pvf( ctx.sender(), - MockPreCheckBackend::with_hardcoded_result(Ok(PrepareStats::default())), + MockPreCheckBackend::with_hardcoded_result(Ok(())), relay_parent, validation_code_hash, ) diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 3e72ca9e532..27da484fe4f 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" +blake3 = "1.5" cfg-if = "1.0" futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index 378374a10b3..c02a0b595da 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -56,7 +56,7 @@ impl TestHost { &self, code: &[u8], executor_params: ExecutorParams, - ) -> Result { + ) -> Result<(), PrepareError> { let (result_tx, result_rx) = futures::channel::oneshot::channel(); let code = sp_maybe_compressed_blob::decompress(code, 16 * 1024 * 1024) diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index e3fda06963e..bfe1be9156f 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -36,6 +36,9 @@ seccompiler = "0.4.0" assert_matches = "1.4.0" tempfile = "3.3.0" +[build-dependencies] +substrate-build-script-utils = { path = "../../../../../substrate/utils/build-script-utils" } + [features] # This feature is used to export test code to other crates without putting it in the production build. test-utils = [] diff --git a/polkadot/node/core/pvf/common/build.rs b/polkadot/node/core/pvf/common/build.rs new file mode 100644 index 00000000000..5531ad411da --- /dev/null +++ b/polkadot/node/core/pvf/common/build.rs @@ -0,0 +1,19 @@ +// 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() { + substrate_build_script_utils::generate_wasmtime_version(); +} diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 34475c481f7..6bf05ece78e 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -14,16 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::prepare::PrepareStats; +use crate::prepare::{PrepareSuccess, PrepareWorkerSuccess}; use parity_scale_codec::{Decode, Encode}; use std::fmt; -/// Result of PVF preparation performed by the validation host. Contains stats about the preparation -/// if successful -pub type PrepareResult = Result; +/// Result of PVF preparation from a worker, with checksum of the compiled PVF and stats of the +/// preparation if successful. +pub type PrepareWorkerResult = Result; + +/// Result of PVF preparation propagated all the way back to the host, with path to the concluded +/// artifact and stats of the preparation if successful. +pub type PrepareResult = Result; + +/// Result of prechecking PVF performed by the validation host. Contains stats about the preparation +/// if successful. +pub type PrecheckResult = Result<(), PrepareError>; /// An error that occurred during the prepare part of the PVF pipeline. -// Codec indexes are intended to stabilize pre-encoded payloads (see `OOM_PAYLOAD` below) +// Codec indexes are intended to stabilize pre-encoded payloads (see `OOM_PAYLOAD`) #[derive(Debug, Clone, Encode, Decode)] pub enum PrepareError { /// During the prevalidation stage of preparation an issue was found with the PVF. diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index e2211b97d87..282d2f7c41d 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -31,6 +31,8 @@ pub use sp_tracing; const LOG_TARGET: &str = "parachain::pvf-common"; +pub const RUNTIME_VERSION: &str = env!("SUBSTRATE_WASMTIME_VERSION"); + use std::{ io::{self, Read, Write}, mem, diff --git a/polkadot/node/core/pvf/common/src/prepare.rs b/polkadot/node/core/pvf/common/src/prepare.rs index 4436ebe4861..28ab682ec13 100644 --- a/polkadot/node/core/pvf/common/src/prepare.rs +++ b/polkadot/node/core/pvf/common/src/prepare.rs @@ -15,6 +15,25 @@ // along with Polkadot. If not, see . use parity_scale_codec::{Decode, Encode}; +use std::path::PathBuf; + +/// Result from prepare worker if successful. +#[derive(Debug, Clone, Default, Encode, Decode)] +pub struct PrepareWorkerSuccess { + /// Checksum of the compiled PVF. + pub checksum: String, + /// Stats of the current preparation run. + pub stats: PrepareStats, +} + +/// Result of PVF preparation if successful. +#[derive(Debug, Clone, Default)] +pub struct PrepareSuccess { + /// Canonical path to the compiled artifact. + pub path: PathBuf, + /// Stats of the current preparation run. + pub stats: PrepareStats, +} /// Preparation statistics, including the CPU time and memory taken. #[derive(Debug, Clone, Default, Encode, Decode)] diff --git a/polkadot/node/core/pvf/common/src/pvf.rs b/polkadot/node/core/pvf/common/src/pvf.rs index 0cc86434c19..2d8f6430187 100644 --- a/polkadot/node/core/pvf/common/src/pvf.rs +++ b/polkadot/node/core/pvf/common/src/pvf.rs @@ -115,7 +115,7 @@ impl fmt::Debug for PvfPrepData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "Pvf {{ code, code_hash: {:?}, executor_params: {:?}, prep_timeout: {:?} }}", + "Pvf {{ code: [...], code_hash: {:?}, executor_params: {:?}, prep_timeout: {:?} }}", self.code_hash, self.executor_params, self.prep_timeout ) } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 1cd221533f4..005f2e93511 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] +blake3 = "1.5" cfg-if = "1.0" 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 151b54efc2d..34e6a78c26a 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -40,10 +40,10 @@ use nix::{ use os_pipe::{self, PipeReader, PipeWriter}; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ - error::{PrepareError, PrepareResult}, + error::{PrepareError, PrepareWorkerResult}, executor_intf::create_runtime_from_artifact_bytes, framed_recv_blocking, framed_send_blocking, - prepare::{MemoryStats, PrepareJobKind, PrepareStats}, + prepare::{MemoryStats, PrepareJobKind, PrepareStats, PrepareWorkerSuccess}, pvf::PvfPrepData, worker::{ cpu_time_monitor_loop, run_worker, stringify_panic_payload, @@ -106,7 +106,7 @@ fn recv_request(stream: &mut UnixStream) -> io::Result { } /// Send a worker response. -fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<()> { +fn send_response(stream: &mut UnixStream, result: PrepareWorkerResult) -> io::Result<()> { framed_send_blocking(stream, &result.encode()) } @@ -186,8 +186,8 @@ fn end_memory_tracking() -> isize { /// /// 7. If compilation succeeded, write the compiled artifact into a temporary file. /// -/// 8. Send the result of preparation back to the host. If any error occurred in the above steps, we -/// send that in the `PrepareResult`. +/// 8. Send the result of preparation back to the host, including the checksum of the artifact. If +/// any error occurred in the above steps, we send that in the `PrepareWorkerResult`. pub fn worker_entrypoint( socket_path: PathBuf, worker_dir_path: PathBuf, @@ -439,11 +439,11 @@ fn handle_child_process( Err(err) => Err(err), Ok(ok) => { cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - let (artifact, max_rss) = ok; - } else { - let artifact = ok; - } + if #[cfg(target_os = "linux")] { + let (artifact, max_rss) = ok; + } else { + let artifact = ok; + } } // Stop the memory stats worker and get its observed memory stats. @@ -511,7 +511,7 @@ fn handle_parent_process( worker_pid: u32, usage_before: Usage, timeout: Duration, -) -> Result { +) -> Result { // Read from the child. Don't decode unless the process exited normally, which we check later. let mut received_data = Vec::new(); pipe_read @@ -554,7 +554,7 @@ fn handle_parent_process( match result { Err(err) => Err(err), - Ok(response) => { + Ok(JobResponse { artifact, memory_stats }) => { // The exit status should have been zero if no error occurred. if exit_status != 0 { return Err(PrepareError::JobError(format!( @@ -577,13 +577,14 @@ fn handle_parent_process( temp_artifact_dest.display(), ); // Write to the temp file created by the host. - if let Err(err) = fs::write(&temp_artifact_dest, &response.artifact) { + if let Err(err) = fs::write(&temp_artifact_dest, &artifact) { return Err(PrepareError::IoErr(err.to_string())) }; - Ok(PrepareStats { - memory_stats: response.memory_stats, - cpu_time_elapsed: cpu_tv, + let checksum = blake3::hash(&artifact.as_ref()).to_hex().to_string(); + Ok(PrepareWorkerSuccess { + checksum, + stats: PrepareStats { memory_stats, cpu_time_elapsed: cpu_tv }, }) }, } @@ -657,13 +658,13 @@ fn error_from_errno(context: &'static str, errno: Errno) -> PrepareError { type JobResult = Result; -/// Pre-encoded length-prefixed `Result::Err(PrepareError::OutOfMemory)` +/// Pre-encoded length-prefixed `JobResult::Err(PrepareError::OutOfMemory)` const OOM_PAYLOAD: &[u8] = b"\x02\x00\x00\x00\x00\x00\x00\x00\x01\x08"; #[test] fn pre_encoded_payloads() { // NOTE: This must match the type of `response` in `send_child_response`. - let oom_unencoded: JobResult = Result::Err(PrepareError::OutOfMemory); + let oom_unencoded: JobResult = JobResult::Err(PrepareError::OutOfMemory); let oom_encoded = oom_unencoded.encode(); // The payload is prefixed with its length in `framed_send`. let mut oom_payload = oom_encoded.len().to_le_bytes().to_vec(); diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index dd83f76494e..53085eade3c 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -16,10 +16,10 @@ //! PVF artifacts (final compiled code blobs). //! -//! # Lifecycle of an artifact +//! # Lifecycle of an artifact //! -//! 1. During node start-up, the artifacts cache is cleaned up. This means that all local artifacts -//! stored on-disk are cleared, and we start with an empty [`Artifacts`] table. +//! 1. During node start-up, we will check the cached artifacts, if any. The stale and corrupted +//! ones are pruned. The valid ones are registered in the [`Artifacts`] table. //! //! 2. In order to be executed, a PVF should be prepared first. This means that artifacts should //! have an [`ArtifactState::Prepared`] entry for that artifact in the table. If not, the @@ -55,18 +55,29 @@ //! older by a predefined parameter. This process is run very rarely (say, once a day). Once the //! artifact is expired it is removed from disk eagerly atomically. -use crate::host::PrepareResultSender; +use crate::{host::PrecheckResultSender, LOG_TARGET}; use always_assert::always; -use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; +use polkadot_core_primitives::Hash; +use polkadot_node_core_pvf_common::{ + error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData, RUNTIME_VERSION, +}; use polkadot_node_primitives::NODE_VERSION; use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParamsHash; use std::{ collections::HashMap, path::{Path, PathBuf}, + str::FromStr as _, time::{Duration, SystemTime}, }; +const RUNTIME_PREFIX: &str = "wasmtime_v"; +const NODE_PREFIX: &str = "polkadot_v"; + +fn artifact_prefix() -> String { + format!("{}{}_{}{}", RUNTIME_PREFIX, RUNTIME_VERSION, NODE_PREFIX, NODE_VERSION) +} + /// Identifier of an artifact. Encodes a code hash of the PVF and a hash of executor parameter set. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ArtifactId { @@ -75,9 +86,6 @@ 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 { Self { code_hash, executor_params_hash } @@ -88,38 +96,34 @@ impl ArtifactId { Self::new(pvf.code_hash(), pvf.executor_params().hash()) } - /// Tries to recover the artifact id from the given file name. - #[cfg(test)] - pub fn from_file_name(file_name: &str) -> Option { - use polkadot_core_primitives::Hash; - use std::str::FromStr as _; - - 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()?); - - Some(Self { code_hash, executor_params_hash }) - } - - /// Returns the expected path to this artifact given the root of the cache. - pub fn path(&self, cache_path: &Path) -> PathBuf { + /// Returns the canonical path to the concluded artifact. + pub(crate) fn path(&self, cache_path: &Path, checksum: &str) -> PathBuf { let file_name = format!( - "{}{}{}_{:#x}_{:#x}", - Self::PREFIX, - Self::NODE_VERSION_PREFIX, - NODE_VERSION, + "{}_{:#x}_{:#x}_0x{}", + artifact_prefix(), self.code_hash, - self.executor_params_hash + self.executor_params_hash, + checksum ); cache_path.join(file_name) } + + /// Tries to recover the artifact id from the given file name. + /// Return `None` if the given file name is invalid. + /// VALID_NAME := _ _ _ + fn from_file_name(file_name: &str) -> Option { + let file_name = file_name.strip_prefix(&artifact_prefix())?.strip_prefix('_')?; + let parts: Vec<&str> = file_name.split('_').collect(); + + if let [code_hash, param_hash, _checksum] = parts[..] { + let code_hash = Hash::from_str(code_hash).ok()?.into(); + let executor_params_hash = + ExecutorParamsHash::from_hash(Hash::from_str(param_hash).ok()?); + return Some(Self { code_hash, executor_params_hash }) + } + + None + } } /// A bundle of the artifact ID and the path. @@ -136,8 +140,8 @@ pub struct ArtifactPathId { } impl ArtifactPathId { - pub(crate) fn new(artifact_id: ArtifactId, cache_path: &Path) -> Self { - Self { path: artifact_id.path(cache_path), id: artifact_id } + pub(crate) fn new(artifact_id: ArtifactId, path: &Path) -> Self { + Self { id: artifact_id, path: path.to_owned() } } } @@ -148,6 +152,8 @@ pub enum ArtifactState { /// That means that the artifact should be accessible through the path obtained by the artifact /// id (unless, it was removed externally). Prepared { + /// The path of the compiled artifact. + path: PathBuf, /// The time when the artifact was last needed. /// /// This is updated when we get the heads up for this artifact or when we just discover @@ -159,7 +165,7 @@ pub enum ArtifactState { /// A task to prepare this artifact is scheduled. Preparing { /// List of result senders that are waiting for a response. - waiting_for_response: Vec, + waiting_for_response: Vec, /// The number of times this artifact has failed to prepare. num_failures: u32, }, @@ -177,32 +183,148 @@ pub enum ArtifactState { /// A container of all known artifact ids and their states. pub struct Artifacts { - artifacts: HashMap, + inner: HashMap, } impl Artifacts { - /// Initialize a blank cache at the given path. This will clear everything present at the - /// given path, to be populated over time. - /// - /// The recognized artifacts will be filled in the table and unrecognized will be removed. - pub async fn new(cache_path: &Path) -> Self { - // 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; + #[cfg(test)] + pub(crate) fn empty() -> Self { + Self { inner: HashMap::new() } + } + + #[cfg(test)] + pub(crate) fn len(&self) -> usize { + self.inner.len() + } + + /// Create an empty table and populate it with valid artifacts as [`ArtifactState::Prepared`], + /// if any. The existing caches will be checked by their file name to determine whether they are + /// valid, e.g., matching the current node version. The ones deemed invalid will be pruned. + pub async fn new_and_prune(cache_path: &Path) -> Self { + let mut artifacts = Self { inner: HashMap::new() }; + artifacts.insert_and_prune(cache_path).await; + artifacts + } + + async fn insert_and_prune(&mut self, cache_path: &Path) { + async fn is_corrupted(path: &Path) -> bool { + let checksum = match tokio::fs::read(path).await { + Ok(bytes) => blake3::hash(&bytes), + Err(err) => { + // just remove the file if we cannot read it + gum::warn!( + target: LOG_TARGET, + ?err, + "unable to read artifact {:?} when checking integrity, removing...", + path, + ); + return true + }, + }; + + if let Some(file_name) = path.file_name() { + if let Some(file_name) = file_name.to_str() { + return !file_name.ends_with(checksum.to_hex().as_str()) + } + } + true + } + + // Insert the entry into the artifacts table if it is valid. + // Otherwise, prune it. + async fn insert_or_prune( + artifacts: &mut Artifacts, + entry: &tokio::fs::DirEntry, + cache_path: &Path, + ) { + let file_type = entry.file_type().await; + let file_name = entry.file_name(); + + match file_type { + Ok(file_type) => + if !file_type.is_file() { + return + }, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?err, + "unable to get file type for {:?}", + file_name, + ); + return + }, + } + + if let Some(file_name) = file_name.to_str() { + let id = ArtifactId::from_file_name(file_name); + let path = cache_path.join(file_name); + + if id.is_none() || is_corrupted(&path).await { + gum::warn!( + target: LOG_TARGET, + "discarding invalid artifact {:?}", + &path, + ); + let _ = tokio::fs::remove_file(&path).await; + return + } + + if let Some(id) = id { + gum::debug!( + target: LOG_TARGET, + "reusing existing {:?} for node version v{}", + &path, + NODE_VERSION, + ); + artifacts.insert_prepared(id, path, SystemTime::now(), Default::default()); + } + } else { + gum::warn!( + target: LOG_TARGET, + "non-Unicode file name {:?} found in {:?}", + file_name, + cache_path, + ); + } + } + // 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() } - } + let mut dir = match tokio::fs::read_dir(cache_path).await { + Ok(dir) => dir, + Err(err) => { + gum::error!( + target: LOG_TARGET, + ?err, + "failed to read dir {:?}", + cache_path, + ); + return + }, + }; - #[cfg(test)] - pub(crate) fn empty() -> Self { - Self { artifacts: HashMap::new() } + loop { + match dir.next_entry().await { + Ok(Some(entry)) => insert_or_prune(self, &entry, cache_path).await, + Ok(None) => break, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?err, + "error processing artifacts in {:?}", + cache_path, + ); + break + }, + } + } } /// Returns the state of the given artifact by its ID. pub fn artifact_state_mut(&mut self, artifact_id: &ArtifactId) -> Option<&mut ArtifactState> { - self.artifacts.get_mut(artifact_id) + self.inner.get_mut(artifact_id) } /// Inform the table about the artifact with the given ID. The state will be set to "preparing". @@ -212,53 +334,52 @@ impl Artifacts { pub fn insert_preparing( &mut self, artifact_id: ArtifactId, - waiting_for_response: Vec, + waiting_for_response: Vec, ) { // See the precondition. always!(self - .artifacts + .inner .insert(artifact_id, ArtifactState::Preparing { waiting_for_response, num_failures: 0 }) .is_none()); } /// Insert an artifact with the given ID as "prepared". /// - /// This function must be used only for brand-new artifacts and should never be used for - /// replacing existing ones. - #[cfg(test)] - pub fn insert_prepared( + /// This function should only be used to build the artifact table at startup with valid + /// artifact caches. + pub(crate) fn insert_prepared( &mut self, artifact_id: ArtifactId, + path: PathBuf, last_time_needed: SystemTime, prepare_stats: PrepareStats, ) { // See the precondition. always!(self - .artifacts - .insert(artifact_id, ArtifactState::Prepared { last_time_needed, prepare_stats }) + .inner + .insert(artifact_id, ArtifactState::Prepared { path, last_time_needed, prepare_stats }) .is_none()); } - /// Remove and retrieve the artifacts from the table that are older than the supplied - /// Time-To-Live. - pub fn prune(&mut self, artifact_ttl: Duration) -> Vec { + /// Remove artifacts older than the given TTL and return id and path of the removed ones. + pub fn prune(&mut self, artifact_ttl: Duration) -> Vec<(ArtifactId, PathBuf)> { let now = SystemTime::now(); let mut to_remove = vec![]; - for (k, v) in self.artifacts.iter() { - if let ArtifactState::Prepared { last_time_needed, .. } = *v { + for (k, v) in self.inner.iter() { + if let ArtifactState::Prepared { last_time_needed, ref path, .. } = *v { if now .duration_since(last_time_needed) .map(|age| age > artifact_ttl) .unwrap_or(false) { - to_remove.push(k.clone()); + to_remove.push((k.clone(), path.clone())); } } } for artifact in &to_remove { - self.artifacts.remove(artifact); + self.inner.remove(&artifact.0); } to_remove @@ -267,13 +388,72 @@ impl Artifacts { #[cfg(test)] mod tests { - use super::{ArtifactId, Artifacts, NODE_VERSION}; + use super::{artifact_prefix as prefix, ArtifactId, Artifacts, NODE_VERSION, RUNTIME_VERSION}; use polkadot_primitives::ExecutorParamsHash; + use rand::Rng; use sp_core::H256; - use std::{path::Path, str::FromStr}; + use std::{ + fs, + io::Write, + path::{Path, PathBuf}, + str::FromStr, + }; + + fn rand_hash(len: usize) -> String { + let mut rng = rand::thread_rng(); + let hex: Vec<_> = "0123456789abcdef".chars().collect(); + (0..len).map(|_| hex[rng.gen_range(0..hex.len())]).collect() + } + + fn file_name(code_hash: &str, param_hash: &str, checksum: &str) -> String { + format!("{}_0x{}_0x{}_0x{}", prefix(), code_hash, param_hash, checksum) + } - fn file_name(code_hash: &str, param_hash: &str) -> String { - format!("wasmtime_polkadot_v{}_0x{}_0x{}", NODE_VERSION, code_hash, param_hash) + fn create_artifact( + dir: impl AsRef, + prefix: &str, + code_hash: impl AsRef, + params_hash: impl AsRef, + ) -> (PathBuf, String) { + fn artifact_path_without_checksum( + dir: impl AsRef, + prefix: &str, + code_hash: impl AsRef, + params_hash: impl AsRef, + ) -> PathBuf { + let mut path = dir.as_ref().to_path_buf(); + let file_name = + format!("{}_0x{}_0x{}", prefix, code_hash.as_ref(), params_hash.as_ref(),); + path.push(file_name); + path + } + + let (code_hash, params_hash) = (code_hash.as_ref(), params_hash.as_ref()); + let path = artifact_path_without_checksum(dir, prefix, code_hash, params_hash); + let mut file = fs::File::create(&path).unwrap(); + + let content = format!("{}{}", code_hash, params_hash).into_bytes(); + file.write_all(&content).unwrap(); + let checksum = blake3::hash(&content).to_hex().to_string(); + + (path, checksum) + } + + fn create_rand_artifact(dir: impl AsRef, prefix: &str) -> (PathBuf, String) { + create_artifact(dir, prefix, rand_hash(64), rand_hash(64)) + } + + fn concluded_path(path: impl AsRef, checksum: &str) -> PathBuf { + let path = path.as_ref(); + let mut file_name = path.file_name().unwrap().to_os_string(); + file_name.push("_0x"); + file_name.push(checksum); + path.with_file_name(file_name) + } + + #[test] + fn artifact_prefix() { + assert_eq!(prefix(), format!("wasmtime_v{}_polkadot_v{}", RUNTIME_VERSION, NODE_VERSION)); } #[test] @@ -284,6 +464,7 @@ mod tests { let file_name = file_name( "0022800000000000000000000000000000000000000000000000000000000000", "0033900000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000", ); assert_eq!( @@ -305,40 +486,54 @@ mod tests { let dir = Path::new("/test"); let code_hash = "1234567890123456789012345678901234567890123456789012345678901234"; let params_hash = "4321098765432109876543210987654321098765432109876543210987654321"; - let file_name = file_name(code_hash, params_hash); + let checksum = "34567890123456789012345678901234"; + let file_name = file_name(code_hash, params_hash, checksum); let code_hash = H256::from_str(code_hash).unwrap(); let params_hash = H256::from_str(params_hash).unwrap(); + let path = ArtifactId::new(code_hash.into(), ExecutorParamsHash::from_hash(params_hash)) + .path(dir, checksum); - assert_eq!( - ArtifactId::new(code_hash.into(), ExecutorParamsHash::from_hash(params_hash)) - .path(dir) - .to_str(), - Some(format!("/test/{}", file_name).as_str()), - ); + assert_eq!(path.to_str().unwrap(), format!("/test/{}", file_name)); } #[tokio::test] - async fn artifacts_removes_cache_on_startup() { - 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"); - p - }; + async fn remove_stale_cache_on_startup() { + let cache_dir = crate::worker_intf::tmppath("test-cache").await.unwrap(); + fs::create_dir_all(&cache_dir).unwrap(); + + // invalid prefix + create_rand_artifact(&cache_dir, ""); + create_rand_artifact(&cache_dir, "wasmtime_polkadot_v"); + create_rand_artifact(&cache_dir, "wasmtime_v8.0.0_polkadot_v1.0.0"); + + let prefix = prefix(); + + // no checksum + create_rand_artifact(&cache_dir, &prefix); + + // invalid hashes + let (path, checksum) = create_artifact(&cache_dir, &prefix, "000", "000001"); + let new_path = concluded_path(&path, &checksum); + fs::rename(&path, &new_path).unwrap(); - // create a tmp cache with 1 artifact. + // checksum tampered + let (path, checksum) = create_rand_artifact(&cache_dir, &prefix); + let new_path = concluded_path(&path, checksum.chars().rev().collect::().as_str()); + fs::rename(&path, &new_path).unwrap(); - std::fs::create_dir_all(&fake_cache_path).unwrap(); - std::fs::File::create(fake_artifact_path).unwrap(); + // valid + let (path, checksum) = create_rand_artifact(&cache_dir, &prefix); + let new_path = concluded_path(&path, &checksum); + fs::rename(&path, &new_path).unwrap(); - // this should remove it and re-create. + assert_eq!(fs::read_dir(&cache_dir).unwrap().count(), 7); - let p = &fake_cache_path; - Artifacts::new(p).await; + let artifacts = Artifacts::new_and_prune(&cache_dir).await; - assert_eq!(std::fs::read_dir(&fake_cache_path).unwrap().count(), 0); + assert_eq!(fs::read_dir(&cache_dir).unwrap().count(), 1); + assert_eq!(artifacts.len(), 1); - std::fs::remove_dir_all(fake_cache_path).unwrap(); + fs::remove_dir_all(cache_dir).unwrap(); } } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 5919b9ba32c..f67934e4171 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -32,14 +32,15 @@ use futures::{ Future, FutureExt, SinkExt, StreamExt, }; use polkadot_node_core_pvf_common::{ - error::{PrepareError, PrepareResult}, + error::{PrecheckResult, PrepareError}, + prepare::PrepareSuccess, pvf::PvfPrepData, }; use polkadot_node_subsystem::SubsystemResult; use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ collections::HashMap, - path::{Path, PathBuf}, + path::PathBuf, time::{Duration, SystemTime}, }; @@ -63,7 +64,7 @@ pub const EXECUTE_BINARY_NAME: &str = "polkadot-execute-worker"; pub(crate) type ResultSender = oneshot::Sender>; /// Transmission end used for sending the PVF preparation result. -pub(crate) type PrepareResultSender = oneshot::Sender; +pub(crate) type PrecheckResultSender = oneshot::Sender; /// A handle to the async process serving the validation host requests. #[derive(Clone)] @@ -83,7 +84,7 @@ impl ValidationHost { pub async fn precheck_pvf( &mut self, pvf: PvfPrepData, - result_tx: PrepareResultSender, + result_tx: PrecheckResultSender, ) -> Result<(), String> { self.to_host_tx .send(ToHost::PrecheckPvf { pvf, result_tx }) @@ -133,7 +134,7 @@ impl ValidationHost { } enum ToHost { - PrecheckPvf { pvf: PvfPrepData, result_tx: PrepareResultSender }, + PrecheckPvf { pvf: PvfPrepData, result_tx: PrecheckResultSender }, ExecutePvf(ExecutePvfInputs), HeadsUp { active_pvfs: Vec }, } @@ -249,10 +250,9 @@ pub async fn start( let run_sweeper = sweeper_task(to_sweeper_rx); let run_host = async move { - let artifacts = Artifacts::new(&config.cache_path).await; + let artifacts = Artifacts::new_and_prune(&config.cache_path).await; run(Inner { - cache_path: config.cache_path, cleanup_pulse_interval: Duration::from_secs(3600), artifact_ttl: Duration::from_secs(3600 * 24), artifacts, @@ -296,7 +296,6 @@ impl AwaitingPrepare { } struct Inner { - cache_path: PathBuf, cleanup_pulse_interval: Duration, artifact_ttl: Duration, artifacts: Artifacts, @@ -317,7 +316,6 @@ struct Fatal; async fn run( Inner { - cache_path, cleanup_pulse_interval, artifact_ttl, mut artifacts, @@ -361,7 +359,6 @@ async fn run( // will notice it. break_if_fatal!(handle_cleanup_pulse( - &cache_path, &mut to_sweeper_tx, &mut artifacts, artifact_ttl, @@ -380,7 +377,6 @@ async fn run( // If the artifact failed before, it could be re-scheduled for preparation here if // the preparation failure cooldown has elapsed. break_if_fatal!(handle_to_host( - &cache_path, &mut artifacts, &mut to_prepare_queue_tx, &mut to_execute_queue_tx, @@ -402,7 +398,6 @@ async fn run( // We could be eager in terms of reporting and plumb the result from the preparation // worker but we don't for the sake of simplicity. break_if_fatal!(handle_prepare_done( - &cache_path, &mut artifacts, &mut to_execute_queue_tx, &mut awaiting_prepare, @@ -414,7 +409,6 @@ async fn run( } async fn handle_to_host( - cache_path: &Path, artifacts: &mut Artifacts, prepare_queue: &mut mpsc::Sender, execute_queue: &mut mpsc::Sender, @@ -426,15 +420,8 @@ async fn handle_to_host( handle_precheck_pvf(artifacts, prepare_queue, pvf, result_tx).await?; }, ToHost::ExecutePvf(inputs) => { - handle_execute_pvf( - cache_path, - artifacts, - prepare_queue, - execute_queue, - awaiting_prepare, - inputs, - ) - .await?; + handle_execute_pvf(artifacts, prepare_queue, execute_queue, awaiting_prepare, inputs) + .await?; }, ToHost::HeadsUp { active_pvfs } => handle_heads_up(artifacts, prepare_queue, active_pvfs).await?, @@ -454,21 +441,21 @@ async fn handle_precheck_pvf( artifacts: &mut Artifacts, prepare_queue: &mut mpsc::Sender, pvf: PvfPrepData, - result_sender: PrepareResultSender, + result_sender: PrecheckResultSender, ) -> Result<(), Fatal> { let artifact_id = ArtifactId::from_pvf_prep_data(&pvf); if let Some(state) = artifacts.artifact_state_mut(&artifact_id) { match state { - ArtifactState::Prepared { last_time_needed, prepare_stats } => { + ArtifactState::Prepared { last_time_needed, .. } => { *last_time_needed = SystemTime::now(); - let _ = result_sender.send(Ok(prepare_stats.clone())); + let _ = result_sender.send(Ok(())); }, ArtifactState::Preparing { waiting_for_response, num_failures: _ } => waiting_for_response.push(result_sender), ArtifactState::FailedToProcess { error, .. } => { // Do not retry an artifact that previously failed preparation. - let _ = result_sender.send(PrepareResult::Err(error.clone())); + let _ = result_sender.send(PrecheckResult::Err(error.clone())); }, } } else { @@ -491,7 +478,6 @@ async fn handle_precheck_pvf( /// When preparing for execution, we use a more lenient timeout ([`LENIENT_PREPARATION_TIMEOUT`]) /// than when prechecking. async fn handle_execute_pvf( - cache_path: &Path, artifacts: &mut Artifacts, prepare_queue: &mut mpsc::Sender, execute_queue: &mut mpsc::Sender, @@ -504,8 +490,8 @@ async fn handle_execute_pvf( if let Some(state) = artifacts.artifact_state_mut(&artifact_id) { match state { - ArtifactState::Prepared { last_time_needed, .. } => { - let file_metadata = std::fs::metadata(artifact_id.path(cache_path)); + ArtifactState::Prepared { ref path, last_time_needed, .. } => { + let file_metadata = std::fs::metadata(path); if file_metadata.is_ok() { *last_time_needed = SystemTime::now(); @@ -514,7 +500,7 @@ async fn handle_execute_pvf( send_execute( execute_queue, execute::ToQueue::Enqueue { - artifact: ArtifactPathId::new(artifact_id, cache_path), + artifact: ArtifactPathId::new(artifact_id, path), pending_execution_request: PendingExecutionRequest { exec_timeout, params, @@ -677,7 +663,6 @@ async fn handle_heads_up( } async fn handle_prepare_done( - cache_path: &Path, artifacts: &mut Artifacts, execute_queue: &mut mpsc::Sender, awaiting_prepare: &mut AwaitingPrepare, @@ -718,7 +703,8 @@ async fn handle_prepare_done( state { for result_sender in waiting_for_response.drain(..) { - let _ = result_sender.send(result.clone()); + let result = result.clone().map(|_| ()); + let _ = result_sender.send(result); } num_failures } else { @@ -738,16 +724,18 @@ async fn handle_prepare_done( continue } - // Don't send failed artifacts to the execution's queue. - if let Err(ref error) = result { - let _ = result_tx.send(Err(ValidationError::from(error.clone()))); - continue - } + let path = match &result { + Ok(success) => success.path.clone(), + Err(error) => { + let _ = result_tx.send(Err(ValidationError::from(error.clone()))); + continue + }, + }; send_execute( execute_queue, execute::ToQueue::Enqueue { - artifact: ArtifactPathId::new(artifact_id.clone(), cache_path), + artifact: ArtifactPathId::new(artifact_id.clone(), &path), pending_execution_request: PendingExecutionRequest { exec_timeout, params, @@ -760,8 +748,8 @@ async fn handle_prepare_done( } *state = match result { - Ok(prepare_stats) => - ArtifactState::Prepared { last_time_needed: SystemTime::now(), prepare_stats }, + Ok(PrepareSuccess { path, stats: prepare_stats }) => + ArtifactState::Prepared { path, last_time_needed: SystemTime::now(), prepare_stats }, Err(error) => { let last_time_failed = SystemTime::now(); let num_failures = *num_failures + 1; @@ -814,7 +802,6 @@ async fn enqueue_prepare_for_execute( } async fn handle_cleanup_pulse( - cache_path: &Path, sweeper_tx: &mut mpsc::Sender, artifacts: &mut Artifacts, artifact_ttl: Duration, @@ -825,14 +812,13 @@ async fn handle_cleanup_pulse( "PVF pruning: {} artifacts reached their end of life", to_remove.len(), ); - for artifact_id in to_remove { + for (artifact_id, path) in to_remove { gum::debug!( target: LOG_TARGET, validation_code_hash = ?artifact_id.code_hash, "pruning artifact", ); - let artifact_path = artifact_id.path(cache_path); - sweeper_tx.send(artifact_path).await.map_err(|_| Fatal)?; + sweeper_tx.send(path).await.map_err(|_| Fatal)?; } Ok(()) @@ -890,7 +876,11 @@ pub(crate) mod tests { use crate::InvalidCandidate; use assert_matches::assert_matches; use futures::future::BoxFuture; - use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats}; + use polkadot_node_core_pvf_common::{ + error::PrepareError, + prepare::{PrepareStats, PrepareSuccess}, + }; + use sp_core::hexdisplay::AsBytesRef; const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); pub(crate) const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); @@ -910,12 +900,16 @@ pub(crate) mod tests { } /// Creates a new PVF which artifact id can be uniquely identified by the given number. - fn artifact_id(descriminator: u32) -> ArtifactId { - ArtifactId::from_pvf_prep_data(&PvfPrepData::from_discriminator(descriminator)) + fn artifact_id(discriminator: u32) -> ArtifactId { + ArtifactId::from_pvf_prep_data(&PvfPrepData::from_discriminator(discriminator)) } - fn artifact_path(descriminator: u32) -> PathBuf { - artifact_id(descriminator).path(&PathBuf::from(std::env::temp_dir())).to_owned() + fn artifact_path(discriminator: u32) -> PathBuf { + let pvf = PvfPrepData::from_discriminator(discriminator); + let checksum = blake3::hash(pvf.code().as_bytes_ref()); + artifact_id(discriminator) + .path(&PathBuf::from(std::env::temp_dir()), checksum.to_hex().as_str()) + .to_owned() } struct Builder { @@ -953,8 +947,6 @@ pub(crate) mod tests { impl Test { fn new(Builder { cleanup_pulse_interval, artifact_ttl, artifacts }: Builder) -> Self { - let cache_path = PathBuf::from(std::env::temp_dir()); - let (to_host_tx, to_host_rx) = mpsc::channel(10); let (to_prepare_queue_tx, to_prepare_queue_rx) = mpsc::channel(10); let (from_prepare_queue_tx, from_prepare_queue_rx) = mpsc::unbounded(); @@ -962,7 +954,6 @@ pub(crate) mod tests { let (to_sweeper_tx, to_sweeper_rx) = mpsc::channel(10); let run = run(Inner { - cache_path, cleanup_pulse_interval, artifact_ttl, artifacts, @@ -1111,12 +1102,18 @@ pub(crate) mod tests { let mut builder = Builder::default(); builder.cleanup_pulse_interval = Duration::from_millis(100); builder.artifact_ttl = Duration::from_millis(500); - builder - .artifacts - .insert_prepared(artifact_id(1), mock_now, PrepareStats::default()); - builder - .artifacts - .insert_prepared(artifact_id(2), mock_now, PrepareStats::default()); + builder.artifacts.insert_prepared( + artifact_id(1), + artifact_path(1), + mock_now, + PrepareStats::default(), + ); + builder.artifacts.insert_prepared( + artifact_id(2), + artifact_path(2), + mock_now, + PrepareStats::default(), + ); let mut test = builder.build(); let mut host = test.host_handle(); @@ -1188,7 +1185,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(1), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); @@ -1204,7 +1201,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(2), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); @@ -1258,7 +1255,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(1), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); @@ -1371,7 +1368,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(2), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); @@ -1527,7 +1524,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(1), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); @@ -1703,7 +1700,7 @@ pub(crate) mod tests { test.from_prepare_queue_tx .send(prepare::FromQueue { artifact_id: artifact_id(1), - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }) .await .unwrap(); diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 102a91dbdad..7e7a1325254 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -84,7 +84,7 @@ //! A pruning task will run at a fixed interval of time. This task will remove all artifacts that //! weren't used or received a heads up signal for a while. //! -//! ## Execution +//! ## Execution //! //! The execute workers will be fed by the requests from the execution queue, which is basically a //! combination of a path to the compiled artifact and the diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 8e02f540d32..21af21e5b02 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -68,7 +68,7 @@ pub enum ToPool { /// /// In either case, the worker is considered busy and no further `StartWork` messages should be /// sent until either `Concluded` or `Rip` message is received. - StartWork { worker: Worker, pvf: PvfPrepData, artifact_path: PathBuf }, + StartWork { worker: Worker, pvf: PvfPrepData, cache_path: PathBuf }, } /// A message sent from pool to its client. @@ -232,7 +232,7 @@ fn handle_to_pool( .boxed(), ); }, - ToPool::StartWork { worker, pvf, artifact_path } => { + ToPool::StartWork { worker, pvf, cache_path } => { if let Some(data) = spawned.get_mut(worker) { if let Some(idle) = data.idle.take() { let preparation_timer = metrics.time_preparation(); @@ -242,7 +242,7 @@ fn handle_to_pool( worker, idle, pvf, - artifact_path, + cache_path, preparation_timer, ) .boxed(), @@ -303,10 +303,10 @@ async fn start_work_task( worker: Worker, idle: IdleWorker, pvf: PvfPrepData, - artifact_path: PathBuf, + cache_path: PathBuf, _preparation_timer: Option, ) -> PoolEvent { - let outcome = worker_intf::start_work(&metrics, idle, pvf, artifact_path).await; + let outcome = worker_intf::start_work(&metrics, idle, pvf, cache_path).await; PoolEvent::StartWork(worker, outcome) } diff --git a/polkadot/node/core/pvf/src/prepare/queue.rs b/polkadot/node/core/pvf/src/prepare/queue.rs index c38012d7454..c140a6cafda 100644 --- a/polkadot/node/core/pvf/src/prepare/queue.rs +++ b/polkadot/node/core/pvf/src/prepare/queue.rs @@ -268,12 +268,12 @@ fn find_idle_worker(queue: &mut Queue) -> Option { } async fn handle_from_pool(queue: &mut Queue, from_pool: pool::FromPool) -> Result<(), Fatal> { - use pool::FromPool::*; + use pool::FromPool; match from_pool { - Spawned(worker) => handle_worker_spawned(queue, worker).await?, - Concluded { worker, rip, result } => + FromPool::Spawned(worker) => handle_worker_spawned(queue, worker).await?, + FromPool::Concluded { worker, rip, result } => handle_worker_concluded(queue, worker, rip, result).await?, - Rip(worker) => handle_worker_rip(queue, worker).await?, + FromPool::Rip(worker) => handle_worker_rip(queue, worker).await?, } Ok(()) } @@ -424,17 +424,17 @@ async fn spawn_extra_worker(queue: &mut Queue, critical: bool) -> Result<(), Fat /// Attaches the work to the given worker telling the poll about the job. async fn assign(queue: &mut Queue, worker: Worker, job: Job) -> Result<(), Fatal> { let job_data = &mut queue.jobs[job]; - - let artifact_id = ArtifactId::from_pvf_prep_data(&job_data.pvf); - let artifact_path = artifact_id.path(&queue.cache_path); - job_data.worker = Some(worker); queue.workers[worker].job = Some(job); send_pool( &mut queue.to_pool_tx, - pool::ToPool::StartWork { worker, pvf: job_data.pvf.clone(), artifact_path }, + pool::ToPool::StartWork { + worker, + pvf: job_data.pvf.clone(), + cache_path: queue.cache_path.clone(), + }, ) .await?; @@ -491,7 +491,7 @@ mod tests { use crate::host::tests::TEST_PREPARATION_TIMEOUT; use assert_matches::assert_matches; use futures::{future::BoxFuture, FutureExt}; - use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats}; + use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareSuccess}; use slotmap::SlotMap; use std::task::Poll; @@ -612,7 +612,7 @@ mod tests { test.send_from_pool(pool::FromPool::Concluded { worker: w, rip: false, - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }); assert_eq!( @@ -651,7 +651,7 @@ mod tests { test.send_from_pool(pool::FromPool::Concluded { worker: w1, rip: false, - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }); assert_matches!(test.poll_and_recv_to_pool().await, pool::ToPool::StartWork { .. }); @@ -697,7 +697,7 @@ mod tests { test.send_from_pool(pool::FromPool::Concluded { worker: w1, rip: false, - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }); assert_eq!(test.poll_and_recv_to_pool().await, pool::ToPool::Kill(w1)); } @@ -731,7 +731,7 @@ mod tests { test.send_from_pool(pool::FromPool::Concluded { worker: w1, rip: true, - result: Ok(PrepareStats::default()), + result: Ok(PrepareSuccess::default()), }); // Since there is still work, the queue requested one extra worker to spawn to handle the diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index a22fa74b2fe..e7f142a46bb 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -17,6 +17,7 @@ //! Host interface to the prepare worker. use crate::{ + artifacts::ArtifactId, metrics::Metrics, security, worker_intf::{ @@ -27,8 +28,8 @@ use crate::{ }; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ - error::{PrepareError, PrepareResult}, - prepare::PrepareStats, + error::{PrepareError, PrepareResult, PrepareWorkerResult}, + prepare::{PrepareStats, PrepareSuccess, PrepareWorkerSuccess}, pvf::PvfPrepData, worker_dir, SecurityStatus, }; @@ -81,7 +82,7 @@ pub enum Outcome { /// final destination location. RenameTmpFile { worker: IdleWorker, - result: PrepareResult, + result: PrepareWorkerResult, err: String, // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible // conversion to `Option`. @@ -115,7 +116,7 @@ pub async fn start_work( metrics: &Metrics, worker: IdleWorker, pvf: PvfPrepData, - artifact_path: PathBuf, + cache_path: PathBuf, ) -> Outcome { let IdleWorker { stream, pid, worker_dir } = worker; @@ -123,8 +124,8 @@ pub async fn start_work( target: LOG_TARGET, worker_pid = %pid, ?worker_dir, - "starting prepare for {}", - artifact_path.display(), + "starting prepare for {:?}", + pvf, ); with_worker_dir_setup( @@ -135,7 +136,7 @@ pub async fn start_work( let preparation_timeout = pvf.prep_timeout(); let audit_log_file = security::AuditLogFile::try_open_and_seek_to_end().await; - if let Err(err) = send_request(&mut stream, pvf.clone()).await { + if let Err(err) = send_request(&mut stream, &pvf).await { gum::warn!( target: LOG_TARGET, worker_pid = %pid, @@ -159,7 +160,7 @@ pub async fn start_work( match result { // Received bytes from worker within the time limit. - Ok(Ok(prepare_result)) => { + Ok(Ok(prepare_worker_result)) => { // Check if any syscall violations occurred during the job. For now this is only // informative, as we are not enforcing the seccomp policy yet. for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { @@ -175,10 +176,11 @@ pub async fn start_work( handle_response( metrics, IdleWorker { stream, pid, worker_dir }, - prepare_result, + prepare_worker_result, pid, tmp_artifact_file, - artifact_path, + &pvf, + &cache_path, preparation_timeout, ) .await @@ -215,20 +217,22 @@ pub async fn start_work( async fn handle_response( metrics: &Metrics, worker: IdleWorker, - result: PrepareResult, + result: PrepareWorkerResult, worker_pid: u32, tmp_file: PathBuf, - artifact_path: PathBuf, + pvf: &PvfPrepData, + cache_path: &PathBuf, preparation_timeout: Duration, ) -> Outcome { - let PrepareStats { cpu_time_elapsed, memory_stats } = match result.clone() { - Ok(result) => result, - // Timed out on the child. This should already be logged by the child. - Err(PrepareError::TimedOut) => return Outcome::TimedOut, - Err(PrepareError::JobDied(err)) => return Outcome::JobDied(err), - Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, - Err(_) => return Outcome::Concluded { worker, result }, - }; + let PrepareWorkerSuccess { checksum, stats: PrepareStats { cpu_time_elapsed, memory_stats } } = + match result.clone() { + Ok(result) => result, + // Timed out on the child. This should already be logged by the child. + Err(PrepareError::TimedOut) => return Outcome::TimedOut, + Err(PrepareError::JobDied(err)) => return Outcome::JobDied(err), + Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, + Err(err) => return Outcome::Concluded { worker, result: Err(err) }, + }; if cpu_time_elapsed > preparation_timeout { // The job didn't complete within the timeout. @@ -243,6 +247,9 @@ async fn handle_response( return Outcome::TimedOut } + let artifact_id = ArtifactId::from_pvf_prep_data(pvf); + let artifact_path = artifact_id.path(cache_path, &checksum); + gum::debug!( target: LOG_TARGET, %worker_pid, @@ -252,7 +259,13 @@ async fn handle_response( ); let outcome = match tokio::fs::rename(&tmp_file, &artifact_path).await { - Ok(()) => Outcome::Concluded { worker, result }, + Ok(()) => Outcome::Concluded { + worker, + result: Ok(PrepareSuccess { + path: artifact_path, + stats: PrepareStats { cpu_time_elapsed, memory_stats: memory_stats.clone() }, + }), + }, Err(err) => { gum::warn!( target: LOG_TARGET, @@ -329,14 +342,14 @@ where outcome } -async fn send_request(stream: &mut UnixStream, pvf: PvfPrepData) -> io::Result<()> { +async fn send_request(stream: &mut UnixStream, pvf: &PvfPrepData) -> io::Result<()> { framed_send(stream, &pvf.encode()).await?; Ok(()) } -async fn recv_response(stream: &mut UnixStream, pid: u32) -> io::Result { +async fn recv_response(stream: &mut UnixStream, pid: u32) -> io::Result { let result = framed_recv(stream).await?; - let result = PrepareResult::decode(&mut &result[..]).map_err(|e| { + let result = PrepareWorkerResult::decode(&mut &result[..]).map_err(|e| { // We received invalid bytes from the worker. let bound_bytes = &result[..result.len().min(4)]; gum::warn!( diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index 8f9a7de354b..5e589b9abce 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -198,7 +198,7 @@ pub async fn tmppath_in(prefix: &str, dir: &Path) -> 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()); + let temp_dir = std::env::temp_dir(); tmppath_in(prefix, &temp_dir).await } @@ -453,7 +453,7 @@ impl Drop for WorkerDir { /// 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)? { + for entry in std::fs::read_dir(path)? { let entry = entry?; let path = entry.path(); diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index d2d842cf84a..5bdf49cc719 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -20,8 +20,7 @@ use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ start, testing::build_workers_and_get_paths, Config, InvalidCandidate, Metrics, PrepareError, - PrepareJobKind, PrepareStats, PvfPrepData, ValidationError, ValidationHost, - JOB_TIMEOUT_WALL_CLOCK_FACTOR, + PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::{ExecutorParam, ExecutorParams}; @@ -70,7 +69,7 @@ impl TestHost { &self, code: &[u8], executor_params: ExecutorParams, - ) -> Result { + ) -> Result<(), PrepareError> { let (result_tx, result_rx) = futures::channel::oneshot::channel(); let code = sp_maybe_compressed_blob::decompress(code, 16 * 1024 * 1024) diff --git a/substrate/utils/build-script-utils/src/version.rs b/substrate/utils/build-script-utils/src/version.rs index f6a9ff9554a..549e499b110 100644 --- a/substrate/utils/build-script-utils/src/version.rs +++ b/substrate/utils/build-script-utils/src/version.rs @@ -59,3 +59,34 @@ fn get_version(impl_commit: &str) -> String { impl_commit ) } + +/// Generate `SUBSTRATE_WASMTIME_VERSION` +pub fn generate_wasmtime_version() { + generate_dependency_version("wasmtime", "SUBSTRATE_WASMTIME_VERSION"); +} + +fn generate_dependency_version(dep: &str, env_var: &str) { + // we only care about the root + match std::process::Command::new("cargo") + .args(["tree", "--depth=0", "--locked", "--package", dep]) + .output() + { + Ok(output) if output.status.success() => { + let version = String::from_utf8_lossy(&output.stdout); + + // vX.X.X + if let Some(ver) = version.strip_prefix(&format!("{} v", dep)) { + println!("cargo:rustc-env={}={}", env_var, ver); + } else { + println!("cargo:warning=Unexpected result {}", version); + } + }, + + // command errors out when it could not find the given dependency + // or when having multiple versions of it + Ok(output) => + println!("cargo:warning=`cargo tree` {}", String::from_utf8_lossy(&output.stderr)), + + Err(err) => println!("cargo:warning=Could not run `cargo tree`: {}", err), + } +} -- GitLab From aa5705bff973522a7bd4e39f2ec1a8da56f59f95 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 20 Nov 2023 09:19:34 +0000 Subject: [PATCH 539/633] Pools: Add `MaxUnbonding` to metadata (#2397) --- substrate/frame/nomination-pools/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 909a930e382..ab4bd51ffc0 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1626,6 +1626,10 @@ pub mod pallet { #[pallet::constant] type MaxPointsToBalance: Get; + /// The maximum number of simultaneous unbonding chunks that can exist per member. + #[pallet::constant] + type MaxUnbonding: Get; + /// Infallible method for converting `Currency::Balance` to `U256`. type BalanceToU256: Convert, U256>; @@ -1644,9 +1648,6 @@ pub mod pallet { /// The maximum length, in bytes, that a pools metadata maybe. type MaxMetadataLen: Get; - - /// The maximum number of simultaneous unbonding chunks that can exist per member. - type MaxUnbonding: Get; } /// The sum of funds across all pools. -- GitLab From b35300c377d502e75e9e3fb6f15934bc0f31ef53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:25:58 +0200 Subject: [PATCH 540/633] Bump docker/build-push-action from 5.0.0 to 5.1.0 (#2404) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.0.0 to 5.1.0.
Release notes

Sourced from docker/build-push-action's releases.

v5.1.0

Full Changelog: https://github.com/docker/build-push-action/compare/v5.0.0...v5.1.0

Commits
  • 4a13e50 Merge pull request #1006 from docker/dependabot/npm_and_yarn/docker/actions-t...
  • 7416668 chore: update generated content
  • b4f76a5 chore(deps): Bump @​docker/actions-toolkit from 0.13.0 to 0.14.0
  • b7feb76 Merge pull request #1005 from crazy-max/ci-inspect
  • fae8018 ci: inspect sbom and provenance
  • b625868 Merge pull request #1004 from crazy-max/ci-update-buildx
  • 5193ef1 ci: update buildx to latest
  • d3afd77 Merge pull request #991 from docker/dependabot/npm_and_yarn/babel/traverse-7....
  • 7a786bb Merge pull request #992 from crazy-max/annotations
  • c66ae3a chore: update generated content
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=5.0.0&new-version=5.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-50_publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 891f43e605c..567e996b8fd 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -268,7 +268,7 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile -- GitLab From ede4a362622dfa69eb167eaa876246b1289f4b41 Mon Sep 17 00:00:00 2001 From: jserrat <35823283+Jpserrat@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:00:19 +0000 Subject: [PATCH 541/633] remove retry from backers on failed candidate validation (#2182) Hey guys, as discussed I've changed the name to a more general one `PvfExecKind`, is this good or too general? Creating this as a draft, I still have to fix the tests. Closes #1585 Kusama address: FkB6QEo8VnV3oifugNj5NeVG3Mvq1zFbrUu4P5YwRoe5mQN --------- Co-authored-by: command-bot <> Co-authored-by: Marcin S --- polkadot/node/core/approval-voting/src/lib.rs | 4 +- .../node/core/approval-voting/src/tests.rs | 4 +- polkadot/node/core/backing/src/lib.rs | 4 +- polkadot/node/core/backing/src/tests/mod.rs | 38 ++-- .../src/tests/prospective_parachains.rs | 4 +- .../node/core/candidate-validation/src/lib.rs | 105 ++++++---- .../core/candidate-validation/src/tests.rs | 190 ++++++++++-------- .../src/participation/mod.rs | 4 +- .../src/participation/tests.rs | 16 +- polkadot/node/malus/src/variants/common.rs | 36 ++-- .../node/overseer/examples/minimal-example.rs | 4 +- polkadot/node/overseer/src/tests.rs | 6 +- polkadot/node/subsystem-types/src/messages.rs | 10 +- polkadot/primitives/src/lib.rs | 10 +- polkadot/primitives/src/v6/executor_params.rs | 39 ++-- polkadot/primitives/src/v6/mod.rs | 26 +-- .../src/node/utility/pvf-host-and-workers.md | 4 + .../src/configuration/benchmarking.rs | 10 +- 18 files changed, 271 insertions(+), 243 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 94f7fcaf941..ef01727b7eb 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -54,7 +54,7 @@ use polkadot_node_subsystem_util::{ }; use polkadot_primitives::{ ApprovalVote, BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement, - ExecutorParams, GroupIndex, Hash, PvfExecTimeoutKind, SessionIndex, SessionInfo, + ExecutorParams, GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; @@ -2867,7 +2867,7 @@ async fn launch_approval( candidate_receipt: candidate.clone(), pov: available_data.pov, executor_params, - exec_timeout_kind: PvfExecTimeoutKind::Approval, + exec_kind: PvfExecKind::Approval, response_sender: val_tx, }) .await; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 0c0dcfde9b6..11bcba9c388 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -2705,10 +2705,10 @@ async fn handle_double_assignment_import( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { - exec_timeout_kind, + exec_kind, response_sender, .. - }) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + }) if exec_kind == PvfExecKind::Approval => { response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) .unwrap(); } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index a91eefe5e04..434051f1b00 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -106,7 +106,7 @@ use polkadot_node_subsystem_util::{ use polkadot_primitives::{ BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, Hash, Id as ParaId, - PersistedValidationData, PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId, + PersistedValidationData, PvfExecKind, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, }; use sp_keystore::KeystorePtr; @@ -566,7 +566,7 @@ async fn request_candidate_validation( candidate_receipt, pov, executor_params, - exec_timeout_kind: PvfExecTimeoutKind::Backing, + exec_kind: PvfExecKind::Backing, response_sender: tx, }) .await; diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index caa85c12989..c12be72556e 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -33,7 +33,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecTimeoutKind, + CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use sp_application_crypto::AppCrypto; @@ -344,14 +344,14 @@ async fn assert_validate_from_exhaustive( validation_data, validation_code, candidate_receipt, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == *assert_pvd && validation_code == *assert_validation_code && *pov == *assert_pov && &candidate_receipt.descriptor == assert_candidate.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_receipt.commitments_hash == assert_candidate.commitments.hash() => { response_sender.send(Ok(ValidationResult::Valid( @@ -550,14 +550,14 @@ fn backing_works() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_ab && validation_code == validation_code_ab && *pov == pov_ab && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_receipt.commitments_hash == candidate_a_commitments_hash => { response_sender.send(Ok( @@ -729,14 +729,14 @@ fn backing_works_while_validation_ongoing() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_abc && validation_code == validation_code_abc && *pov == pov_abc && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { // we never validate the candidate. our local node @@ -890,14 +890,14 @@ fn backing_misbehavior_works() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { response_sender.send(Ok( @@ -1057,14 +1057,14 @@ fn backing_dont_second_invalid() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_block_a && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_a.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1097,14 +1097,14 @@ fn backing_dont_second_invalid() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_b && validation_code == validation_code_b && *pov == pov_block_b && &candidate_receipt.descriptor == candidate_b.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate_b.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok( @@ -1224,14 +1224,14 @@ fn backing_second_after_first_fails_works() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1368,14 +1368,14 @@ fn backing_works_after_failed_validation() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }, ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); @@ -1634,13 +1634,13 @@ fn retry_works() { validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, .. }, ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index fc4bd7d98e7..e7c29e11bb4 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -232,14 +232,14 @@ async fn assert_validate_seconded_candidate( validation_code, candidate_receipt, pov, - exec_timeout_kind, + exec_kind, response_sender, .. }) if &validation_data == assert_pvd && &validation_code == assert_validation_code && &*pov == assert_pov && &candidate_receipt.descriptor == candidate.descriptor() && - exec_timeout_kind == PvfExecTimeoutKind::Backing && + exec_kind == PvfExecKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Valid( diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 96ab07d3b82..f5d17af6c68 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -49,8 +49,8 @@ use polkadot_primitives::{ DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT, }, CandidateCommitments, CandidateDescriptor, CandidateReceipt, ExecutorParams, Hash, - OccupiedCoreAssumption, PersistedValidationData, PvfExecTimeoutKind, PvfPrepTimeoutKind, - ValidationCode, ValidationCodeHash, + OccupiedCoreAssumption, PersistedValidationData, PvfExecKind, PvfPrepKind, ValidationCode, + ValidationCodeHash, }; use parity_scale_codec::Encode; @@ -73,12 +73,6 @@ mod tests; const LOG_TARGET: &'static str = "parachain::candidate-validation"; -/// The amount of time to wait before retrying after a retry-able backing validation error. We use a -/// lower value for the backing case, to fit within the lower backing timeout. -#[cfg(not(test))] -const PVF_BACKING_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(500); -#[cfg(test)] -const PVF_BACKING_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); /// The amount of time to wait before retrying after a retry-able approval validation error. We use /// a higher value for the approval case since we have more time, and if we wait longer it is more /// likely that transient conditions will resolve. @@ -163,7 +157,7 @@ async fn run( candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, .. } => { @@ -180,7 +174,7 @@ async fn run( candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, &metrics, ) .await; @@ -198,7 +192,7 @@ async fn run( candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, .. } => { @@ -215,7 +209,7 @@ async fn run( candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, &metrics, ) .await; @@ -357,7 +351,7 @@ where return PreCheckOutcome::Invalid }; - let timeout = pvf_prep_timeout(&executor_params, PvfPrepTimeoutKind::Precheck); + let timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Precheck); let pvf = match sp_maybe_compressed_blob::decompress( &validation_code.0, @@ -501,7 +495,7 @@ async fn validate_from_chain_state( candidate_receipt: CandidateReceipt, pov: Arc, executor_params: ExecutorParams, - exec_timeout_kind: PvfExecTimeoutKind, + exec_kind: PvfExecKind, metrics: &Metrics, ) -> Result where @@ -521,7 +515,7 @@ where candidate_receipt.clone(), pov, executor_params, - exec_timeout_kind, + exec_kind, metrics, ) .await; @@ -557,7 +551,7 @@ async fn validate_candidate_exhaustive( candidate_receipt: CandidateReceipt, pov: Arc, executor_params: ExecutorParams, - exec_timeout_kind: PvfExecTimeoutKind, + exec_kind: PvfExecKind, metrics: &Metrics, ) -> Result { let _timer = metrics.time_validate_candidate_exhaustive(); @@ -616,15 +610,32 @@ async fn validate_candidate_exhaustive( relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root, }; - let result = validation_backend - .validate_candidate_with_retry( - raw_validation_code.to_vec(), - pvf_exec_timeout(&executor_params, exec_timeout_kind), - exec_timeout_kind, - params, - executor_params, - ) - .await; + let result = match exec_kind { + // Retry is disabled to reduce the chance of nondeterministic blocks getting backed and + // honest backers getting slashed. + PvfExecKind::Backing => { + let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); + let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind); + let pvf = PvfPrepData::from_code( + raw_validation_code.to_vec(), + executor_params, + prep_timeout, + PrepareJobKind::Compilation, + ); + + validation_backend.validate_candidate(pvf, exec_timeout, params.encode()).await + }, + PvfExecKind::Approval => + validation_backend + .validate_candidate_with_retry( + raw_validation_code.to_vec(), + pvf_exec_timeout(&executor_params, exec_kind), + params, + executor_params, + PVF_APPROVAL_EXECUTION_RETRY_DELAY, + ) + .await, + }; if let Err(ref error) = result { gum::info!(target: LOG_TARGET, ?para_id, ?error, "Failed to validate candidate"); @@ -709,8 +720,8 @@ trait ValidationBackend { encoded_params: Vec, ) -> Result; - /// Tries executing a PVF. Will retry once if an error is encountered that may have been - /// transient. + /// Tries executing a PVF for the approval subsystem. Will retry once if an error is encountered + /// that may have been transient. /// /// NOTE: Should retry only on errors that are a result of execution itself, and not of /// preparation. @@ -718,11 +729,11 @@ trait ValidationBackend { &mut self, raw_validation_code: Vec, exec_timeout: Duration, - exec_timeout_kind: PvfExecTimeoutKind, params: ValidationParams, executor_params: ExecutorParams, + retry_delay: Duration, ) -> Result { - let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepTimeoutKind::Lenient); + let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); // Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap. let pvf = PvfPrepData::from_code( raw_validation_code, @@ -740,11 +751,6 @@ trait ValidationBackend { return validation_result } - let retry_delay = match exec_timeout_kind { - PvfExecTimeoutKind::Backing => PVF_BACKING_EXECUTION_RETRY_DELAY, - PvfExecTimeoutKind::Approval => PVF_APPROVAL_EXECUTION_RETRY_DELAY, - }; - // Allow limited retries for each kind of error. let mut num_death_retries_left = 1; let mut num_job_error_retries_left = 1; @@ -867,22 +873,41 @@ fn perform_basic_checks( Ok(()) } -fn pvf_prep_timeout(executor_params: &ExecutorParams, kind: PvfPrepTimeoutKind) -> Duration { +/// To determine the amount of timeout time for the pvf execution. +/// +/// Precheck +/// The time period after which the preparation worker is considered +/// unresponsive and will be killed. +/// +/// Prepare +///The time period after which the preparation worker is considered +/// unresponsive and will be killed. +fn pvf_prep_timeout(executor_params: &ExecutorParams, kind: PvfPrepKind) -> Duration { if let Some(timeout) = executor_params.pvf_prep_timeout(kind) { return timeout } match kind { - PvfPrepTimeoutKind::Precheck => DEFAULT_PRECHECK_PREPARATION_TIMEOUT, - PvfPrepTimeoutKind::Lenient => DEFAULT_LENIENT_PREPARATION_TIMEOUT, + PvfPrepKind::Precheck => DEFAULT_PRECHECK_PREPARATION_TIMEOUT, + PvfPrepKind::Prepare => DEFAULT_LENIENT_PREPARATION_TIMEOUT, } } -fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: PvfExecTimeoutKind) -> Duration { +/// To determine the amount of timeout time for the pvf execution. +/// +/// Backing subsystem +/// The amount of time to spend on execution during backing. +/// +/// Approval subsystem +/// The amount of time to spend on execution during approval or disputes. +/// This should be much longer than the backing execution timeout to ensure that in the +/// absence of extremely large disparities between hardware, blocks that pass backing are +/// considered executable by approval checkers or dispute participants. +fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: PvfExecKind) -> Duration { if let Some(timeout) = executor_params.pvf_exec_timeout(kind) { return timeout } match kind { - PvfExecTimeoutKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, - PvfExecTimeoutKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, + PvfExecKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, + PvfExecKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, } } diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 801c581938a..5e2585d6873 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -436,7 +436,7 @@ fn candidate_validation_ok_is_ok() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )) .unwrap(); @@ -488,7 +488,7 @@ fn candidate_validation_bad_return_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )) .unwrap(); @@ -496,23 +496,20 @@ fn candidate_validation_bad_return_is_invalid() { assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::Timeout)); } -// Test that we vote valid if we get `AmbiguousWorkerDeath`, retry, and then succeed. -#[test] -fn candidate_validation_one_ambiguous_error_is_valid() { - let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; - - let pov = PoV { block_data: BlockData(vec![1; 32]) }; - let head_data = HeadData(vec![1, 1, 1]); - let validation_code = ValidationCode(vec![2; 16]); - +fn perform_basic_checks_on_valid_candidate( + pov: &PoV, + validation_code: &ValidationCode, + validation_data: &PersistedValidationData, + head_data_hash: Hash, +) -> CandidateDescriptor { let descriptor = make_valid_candidate_descriptor( ParaId::from(1_u32), dummy_hash(), validation_data.hash(), pov.hash(), validation_code.hash(), - head_data.hash(), - dummy_hash(), + head_data_hash, + head_data_hash, Sr25519Keyring::Alice, ); @@ -523,6 +520,24 @@ fn candidate_validation_one_ambiguous_error_is_valid() { &validation_code.hash(), ); assert!(check.is_ok()); + descriptor +} + +// Test that we vote valid if we get `AmbiguousWorkerDeath`, retry, and then succeed. +#[test] +fn candidate_validation_one_ambiguous_error_is_valid() { + let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; + + let pov = PoV { block_data: BlockData(vec![1; 32]) }; + let head_data = HeadData(vec![1, 1, 1]); + let validation_code = ValidationCode(vec![2; 16]); + + let descriptor = perform_basic_checks_on_valid_candidate( + &pov, + &validation_code, + &validation_data, + head_data.hash(), + ); let validation_result = WasmValidationResult { head_data, @@ -554,7 +569,7 @@ fn candidate_validation_one_ambiguous_error_is_valid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Approval, &Default::default(), )) .unwrap(); @@ -576,24 +591,12 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { let pov = PoV { block_data: BlockData(vec![1; 32]) }; let validation_code = ValidationCode(vec![2; 16]); - let descriptor = make_valid_candidate_descriptor( - ParaId::from(1_u32), - dummy_hash(), - validation_data.hash(), - pov.hash(), - validation_code.hash(), - dummy_hash(), - dummy_hash(), - Sr25519Keyring::Alice, - ); - - let check = perform_basic_checks( - &descriptor, - validation_data.max_pov_size, + let descriptor = perform_basic_checks_on_valid_candidate( &pov, - &validation_code.hash(), + &validation_code, + &validation_data, + dummy_hash(), ); - assert!(check.is_ok()); let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; @@ -607,7 +610,7 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Approval, &Default::default(), )) .unwrap(); @@ -615,58 +618,79 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::ExecutionError(_))); } -// Test that we retry on internal errors. +// Test that we retry for approval on internal errors. #[test] fn candidate_validation_retry_internal_errors() { - let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; - - let pov = PoV { block_data: BlockData(vec![1; 32]) }; - let validation_code = ValidationCode(vec![2; 16]); - - let descriptor = make_valid_candidate_descriptor( - ParaId::from(1_u32), - dummy_hash(), - validation_data.hash(), - pov.hash(), - validation_code.hash(), - dummy_hash(), - dummy_hash(), - Sr25519Keyring::Alice, - ); - - let check = perform_basic_checks( - &descriptor, - validation_data.max_pov_size, - &pov, - &validation_code.hash(), + let v = candidate_validation_retry_on_error_helper( + PvfExecKind::Approval, + vec![ + Err(InternalValidationError::HostCommunication("foo".into()).into()), + // Throw an AJD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath( + "baz".into(), + ))), + // Throw another internal error. + Err(InternalValidationError::HostCommunication("bar".into()).into()), + ], ); - assert!(check.is_ok()); - - let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + assert_matches!(v, Err(ValidationFailed(s)) if s.contains("bar")); +} - let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ +// Test that we don't retry for backing on internal errors. +#[test] +fn candidate_validation_dont_retry_internal_errors() { + let v = candidate_validation_retry_on_error_helper( + PvfExecKind::Backing, + vec![ Err(InternalValidationError::HostCommunication("foo".into()).into()), // Throw an AWD error, we should still retry again. Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), // Throw another internal error. Err(InternalValidationError::HostCommunication("bar".into()).into()), - ]), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - ExecutorParams::default(), - PvfExecTimeoutKind::Backing, - &Default::default(), - )); + ], + ); - assert_matches!(v, Err(ValidationFailed(s)) if s.contains("bar")); + assert_matches!(v, Err(ValidationFailed(s)) if s.contains("foo")); } -// Test that we retry on panic errors. +// Test that we retry for approval on panic errors. #[test] fn candidate_validation_retry_panic_errors() { + let v = candidate_validation_retry_on_error_helper( + PvfExecKind::Approval, + vec![ + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), + // Throw an AWD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + // Throw another panic error. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), + ], + ); + + assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(s))) if s == "bar".to_string()); +} + +// Test that we don't retry for backing on panic errors. +#[test] +fn candidate_validation_dont_retry_panic_errors() { + let v = candidate_validation_retry_on_error_helper( + PvfExecKind::Backing, + vec![ + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), + // Throw an AWD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + // Throw another panic error. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), + ], + ); + + assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(s))) if s == "foo".to_string()); +} + +fn candidate_validation_retry_on_error_helper( + exec_kind: PvfExecKind, + mock_errors: Vec>, +) -> Result { let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; let pov = PoV { block_data: BlockData(vec![1; 32]) }; @@ -693,26 +717,16 @@ fn candidate_validation_retry_panic_errors() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), - // Throw an AJD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath( - "baz".into(), - ))), - // Throw another panic error. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), - ]), + return executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result_list(mock_errors), validation_data, validation_code, candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + exec_kind, &Default::default(), )); - - assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(s))) if s == "bar".to_string()); } #[test] @@ -752,7 +766,7 @@ fn candidate_validation_timeout_is_internal_error() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )); @@ -797,7 +811,7 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )) .unwrap(); @@ -846,7 +860,7 @@ fn candidate_validation_code_mismatch_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )) .unwrap(); @@ -903,7 +917,7 @@ fn compressed_code_works() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )); @@ -954,7 +968,7 @@ fn code_decompression_failure_is_error() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )); @@ -1006,7 +1020,7 @@ fn pov_decompression_failure_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecTimeoutKind::Backing, + PvfExecKind::Backing, &Default::default(), )); diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index 90268516e9d..05ea7323af1 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -32,7 +32,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, Hash, PvfExecTimeoutKind, SessionIndex, + BlockNumber, CandidateHash, CandidateReceipt, Hash, PvfExecKind, SessionIndex, }; use crate::LOG_TARGET; @@ -386,7 +386,7 @@ async fn participate( candidate_receipt: req.candidate_receipt().clone(), pov: available_data.pov, executor_params: req.executor_params(), - exec_timeout_kind: PvfExecTimeoutKind::Approval, + exec_kind: PvfExecKind::Approval, response_sender: validation_tx, }) .await; diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index 0aa0d772005..012df51d0cd 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -115,8 +115,8 @@ pub async fn participation_full_happy_path( assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { candidate_receipt, exec_timeout_kind, response_sender, .. } - ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + CandidateValidationMessage::ValidateFromExhaustive { candidate_receipt, exec_kind, response_sender, .. } + ) if exec_kind == PvfExecKind::Approval => { if expected_commitments_hash != candidate_receipt.commitments_hash { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { @@ -450,8 +450,8 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } - ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } + ) if exec_kind == PvfExecKind::Approval => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, "overseer did not receive candidate validation message", @@ -487,8 +487,8 @@ fn cast_invalid_vote_if_commitments_dont_match() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } - ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } + ) if exec_kind == PvfExecKind::Approval => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", @@ -524,8 +524,8 @@ fn cast_valid_vote_if_validation_passes() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } - ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } + ) if exec_kind == PvfExecKind::Approval => { response_sender.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, "overseer did not receive candidate validation message", diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 474887ee8df..20b6654638e 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -30,7 +30,7 @@ use polkadot_node_subsystem::{ use polkadot_primitives::{ CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, - PvfExecTimeoutKind, + PvfExecKind, }; use futures::channel::oneshot; @@ -90,10 +90,10 @@ impl FakeCandidateValidation { } } - fn should_misbehave(&self, timeout: PvfExecTimeoutKind) -> bool { + fn should_misbehave(&self, timeout: PvfExecKind) -> bool { match timeout { - PvfExecTimeoutKind::Backing => self.includes_backing(), - PvfExecTimeoutKind::Approval => self.includes_approval(), + PvfExecKind::Backing => self.includes_backing(), + PvfExecKind::Approval => self.includes_approval(), } } } @@ -279,13 +279,13 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, .. }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_timeout_kind) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -295,7 +295,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }) @@ -333,14 +333,14 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }) }, } }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_timeout_kind) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { // Set the validation result to invalid with probability `p` and trigger a // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -373,7 +373,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }) @@ -388,7 +388,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }), @@ -401,13 +401,13 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, .. }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_timeout_kind) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -415,7 +415,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }) @@ -445,13 +445,13 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }), } }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_timeout_kind) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { // Maliciously set the validation result to invalid for a valid candidate // with probability `p` let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -479,7 +479,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }) @@ -491,7 +491,7 @@ where candidate_receipt, pov, executor_params, - exec_timeout_kind, + exec_kind, response_sender, }, }), diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index b2c0ea2f75a..857cdba673d 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -32,7 +32,7 @@ use polkadot_overseer::{ gen::{FromOrchestra, SpawnedSubsystem}, HeadSupportsParachains, SubsystemError, }; -use polkadot_primitives::{CandidateReceipt, Hash, PvfExecTimeoutKind}; +use polkadot_primitives::{CandidateReceipt, Hash, PvfExecKind}; struct AlwaysSupportsParachains; @@ -77,7 +77,7 @@ impl Subsystem1 { candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), - exec_timeout_kind: PvfExecTimeoutKind::Backing, + exec_kind: PvfExecKind::Backing, response_sender: tx, }; ctx.send_message(msg).await; diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 254f5fe4512..0494274367d 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -30,7 +30,7 @@ use polkadot_node_subsystem_types::messages::{ }; use polkadot_primitives::{ CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, - PvfExecTimeoutKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + PvfExecKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, }; use crate::{ @@ -106,7 +106,7 @@ where candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), - exec_timeout_kind: PvfExecTimeoutKind::Backing, + exec_kind: PvfExecKind::Backing, response_sender: tx, }) .await; @@ -804,7 +804,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { candidate_receipt, pov, executor_params: Default::default(), - exec_timeout_kind: PvfExecTimeoutKind::Backing, + exec_kind: PvfExecKind::Backing, response_sender, } } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 43456daec30..44c6f27b17c 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -47,7 +47,7 @@ use polkadot_primitives::{ CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, - PvfCheckStatement, PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + PvfCheckStatement, PvfExecKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; @@ -150,8 +150,8 @@ pub enum CandidateValidationMessage { pov: Arc, /// Session's executor parameters executor_params: ExecutorParams, - /// Execution timeout kind (backing/approvals) - exec_timeout_kind: PvfExecTimeoutKind, + /// Execution kind, used for timeouts and retries (backing/approvals) + exec_kind: PvfExecKind, /// The sending side of the response channel response_sender: oneshot::Sender>, }, @@ -175,8 +175,8 @@ pub enum CandidateValidationMessage { pov: Arc, /// Session's executor parameters executor_params: ExecutorParams, - /// Execution timeout kind (backing/approvals) - exec_timeout_kind: PvfExecTimeoutKind, + /// Execution kind, used for timeouts and retries (backing/approvals) + exec_kind: PvfExecKind, /// The sending side of the response channel response_sender: oneshot::Sender>, }, diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 4ba8b8b031f..2570bcadf60 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -48,11 +48,11 @@ pub use v6::{ HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec, InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce, OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, - PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, PvfPrepTimeoutKind, - RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, - RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, - SessionInfo, Signature, Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, - SignedStatement, SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, + PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, RuntimeMetricLabel, + RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, RuntimeMetricOp, + RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, + Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SignedStatement, + SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs index bb9980f6879..112a529f62b 100644 --- a/polkadot/primitives/src/v6/executor_params.rs +++ b/polkadot/primitives/src/v6/executor_params.rs @@ -21,7 +21,7 @@ //! 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 crate::{BlakeTwo256, HashT as _, PvfExecKind, PvfPrepKind}; use parity_scale_codec::{Decode, Encode}; use polkadot_core_primitives::Hash; use scale_info::TypeInfo; @@ -45,7 +45,7 @@ pub const PRECHECK_MEM_MAX_LO: u64 = 256 * 1024 * 1024; 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. +// See also `PvfPrepKind` and `PvfExecKind` docs. /// Default PVF preparation timeout for prechecking requests. pub const DEFAULT_PRECHECK_PREPARATION_TIMEOUT: Duration = Duration::from_secs(60); @@ -99,12 +99,12 @@ pub enum ExecutorParam { /// Always ensure that `precheck_timeout` < `lenient_timeout`. /// When absent, the default values will be used. #[codec(index = 5)] - PvfPrepTimeout(PvfPrepTimeoutKind, u64), + PvfPrepTimeout(PvfPrepKind, 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), + PvfExecTimeout(PvfExecKind, u64), /// Enables WASM bulk memory proposal #[codec(index = 7)] WasmExtBulkMemory, @@ -174,7 +174,7 @@ impl ExecutorParams { } /// Returns a PVF preparation timeout, if any - pub fn pvf_prep_timeout(&self, kind: PvfPrepTimeoutKind) -> Option { + pub fn pvf_prep_timeout(&self, kind: PvfPrepKind) -> Option { for param in &self.0 { if let ExecutorParam::PvfPrepTimeout(k, timeout) = param { if kind == *k { @@ -186,7 +186,7 @@ impl ExecutorParams { } /// Returns a PVF execution timeout, if any - pub fn pvf_exec_timeout(&self, kind: PvfExecTimeoutKind) -> Option { + pub fn pvf_exec_timeout(&self, kind: PvfExecKind) -> Option { for param in &self.0 { if let ExecutorParam::PvfExecTimeout(k, timeout) = param { if kind == *k { @@ -242,12 +242,12 @@ impl ExecutorParams { StackNativeMax(_) => "StackNativeMax", PrecheckingMaxMemory(_) => "PrecheckingMaxMemory", PvfPrepTimeout(kind, _) => match kind { - PvfPrepTimeoutKind::Precheck => "PvfPrepTimeoutKind::Precheck", - PvfPrepTimeoutKind::Lenient => "PvfPrepTimeoutKind::Lenient", + PvfPrepKind::Precheck => "PvfPrepKind::Precheck", + PvfPrepKind::Prepare => "PvfPrepKind::Prepare", }, PvfExecTimeout(kind, _) => match kind { - PvfExecTimeoutKind::Backing => "PvfExecTimeoutKind::Backing", - PvfExecTimeoutKind::Approval => "PvfExecTimeoutKind::Approval", + PvfExecKind::Backing => "PvfExecKind::Backing", + PvfExecKind::Approval => "PvfExecKind::Approval", }, WasmExtBulkMemory => "WasmExtBulkMemory", }; @@ -297,30 +297,23 @@ impl ExecutorParams { } if let (Some(precheck), Some(lenient)) = ( - seen.get("PvfPrepTimeoutKind::Precheck") + seen.get("PvfPrepKind::Precheck") .or(Some(&DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS)), - seen.get("PvfPrepTimeoutKind::Lenient") + seen.get("PvfPrepKind::Prepare") .or(Some(&DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS)), ) { if *precheck >= *lenient { - return Err(IncompatibleValues( - "PvfPrepTimeoutKind::Precheck", - "PvfPrepTimeoutKind::Lenient", - )) + return Err(IncompatibleValues("PvfPrepKind::Precheck", "PvfPrepKind::Prepare")) } } if let (Some(backing), Some(approval)) = ( - seen.get("PvfExecTimeoutKind::Backing") - .or(Some(&DEFAULT_BACKING_EXECUTION_TIMEOUT_MS)), - seen.get("PvfExecTimeoutKind::Approval") + seen.get("PvfExecKind::Backing").or(Some(&DEFAULT_BACKING_EXECUTION_TIMEOUT_MS)), + seen.get("PvfExecKind::Approval") .or(Some(&DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS)), ) { if *backing >= *approval { - return Err(IncompatibleValues( - "PvfExecTimeoutKind::Backing", - "PvfExecTimeoutKind::Approval", - )) + return Err(IncompatibleValues("PvfExecKind::Backing", "PvfExecKind::Approval")) } } diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index 9371b3db406..83b590dc320 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -1781,30 +1781,22 @@ impl WellKnownKey { } } -/// Type discriminator for PVF preparation timeouts +/// Type discriminator for PVF preparation. #[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PvfPrepTimeoutKind { - /// For prechecking requests, the time period after which the preparation worker is considered - /// unresponsive and will be killed. +pub enum PvfPrepKind { + /// For prechecking requests. Precheck, - /// For execution and heads-up requests, the time period after which the preparation worker is - /// considered unresponsive and will be killed. More lenient than the timeout for prechecking - /// to prevent honest validators from timing out on valid PVFs. - Lenient, + /// For execution and heads-up requests. + Prepare, } -/// Type discriminator for PVF execution timeouts +/// Type discriminator for PVF execution. #[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PvfExecTimeoutKind { - /// The amount of time to spend on execution during backing. +pub enum PvfExecKind { + /// For backing requests. Backing, - - /// The amount of time to spend on execution during approval or disputes. - /// - /// This should be much longer than the backing execution timeout to ensure that in the - /// absence of extremely large disparities between hardware, blocks that pass backing are - /// considered executable by approval checkers or dispute participants. + /// For approval and dispute request. Approval, } 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 4dbb7980c1b..74d88ba3ad9 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 @@ -31,6 +31,10 @@ hopefully resolve. We use a more brief delay here (1 second as opposed to 15 minutes for preparation (see above)), because a successful execution must happen in a short amount of time. +If the execution fails during the backing phase, we won't retry to reduce the chance of +supporting nondeterministic candidates. This reduces the chance of nondeterministic blocks +getting backed and honest backers getting slashed. + We currently know of the following specific cases that will lead to a retried execution request: diff --git a/polkadot/runtime/parachains/src/configuration/benchmarking.rs b/polkadot/runtime/parachains/src/configuration/benchmarking.rs index 508e0579a09..67daf1c4598 100644 --- a/polkadot/runtime/parachains/src/configuration/benchmarking.rs +++ b/polkadot/runtime/parachains/src/configuration/benchmarking.rs @@ -17,7 +17,7 @@ use crate::configuration::*; use frame_benchmarking::{benchmarks, BenchmarkError, BenchmarkResult}; use frame_system::RawOrigin; -use primitives::{ExecutorParam, ExecutorParams, PvfExecTimeoutKind, PvfPrepTimeoutKind}; +use primitives::{ExecutorParam, ExecutorParams, PvfExecKind, PvfPrepKind}; use sp_runtime::traits::One; benchmarks! { @@ -41,10 +41,10 @@ benchmarks! { ExecutorParam::StackNativeMax(256 * 1024 * 1024), ExecutorParam::WasmExtBulkMemory, ExecutorParam::PrecheckingMaxMemory(2 * 1024 * 1024 * 1024), - ExecutorParam::PvfPrepTimeout(PvfPrepTimeoutKind::Precheck, 60_000), - ExecutorParam::PvfPrepTimeout(PvfPrepTimeoutKind::Lenient, 360_000), - ExecutorParam::PvfExecTimeout(PvfExecTimeoutKind::Backing, 2_000), - ExecutorParam::PvfExecTimeout(PvfExecTimeoutKind::Approval, 12_000), + ExecutorParam::PvfPrepTimeout(PvfPrepKind::Precheck, 60_000), + ExecutorParam::PvfPrepTimeout(PvfPrepKind::Prepare, 360_000), + ExecutorParam::PvfExecTimeout(PvfExecKind::Backing, 2_000), + ExecutorParam::PvfExecTimeout(PvfExecKind::Approval, 12_000), ][..])) set_config_with_perbill {}: set_on_demand_fee_variability(RawOrigin::Root, Perbill::from_percent(100)) -- GitLab From 126f64a91ee0c0333f368fe67bb00d56d68ecb34 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 21 Nov 2023 07:38:04 -0300 Subject: [PATCH 542/633] bump zombienet version `v1.3.82` (#2396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes: - bump `pjs` modules versions - re-enable test disable in https://github.com/paritytech/polkadot-sdk/pull/2294 --------- Co-authored-by: Bastian Köcher --- .gitlab-ci.yml | 4 ---- .gitlab/pipeline/zombienet.yml | 5 +++++ .gitlab/pipeline/zombienet/substrate.yml | 15 +++++++-------- .../skip-feeless-payment/src/lib.rs | 15 +++++++++------ 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b485ca3317e..e698aba81d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,7 +30,6 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.80" DOCKER_IMAGES_VERSION: "${CI_COMMIT_SHA}" default: @@ -199,9 +198,6 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues -.zombienet-refs: - extends: .build-refs - include: # check jobs - .gitlab/pipeline/check.yml diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 64210d6a00a..fc3fd125619 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,3 +1,8 @@ +.zombienet-refs: + extends: .build-refs + variables: + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.82" + include: # substrate tests - .gitlab/pipeline/zombienet/substrate.yml diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 6334e7db9a3..b687576267d 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -40,14 +40,13 @@ tags: - zombienet-polkadot-integration-test -# Skip this one until PolkadotJS includes `SkipCheckIfFeeless` extension -# zombienet-substrate-0000-block-building: -# extends: -# - .zombienet-substrate-common -# script: -# - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh -# --local-dir="${LOCAL_DIR}/0000-block-building" -# --test="block-building.zndsl" +zombienet-substrate-0000-block-building: + extends: + - .zombienet-substrate-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/0000-block-building" + --test="block-building.zndsl" zombienet-substrate-0001-basic-warp-sync: extends: diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs index 923c7e7ebc2..55afaaf93d7 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -77,9 +77,9 @@ pub mod pallet { /// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct SkipCheckIfFeeless(pub S, sp_std::marker::PhantomData); +pub struct SkipCheckIfFeeless(pub S, sp_std::marker::PhantomData); -impl sp_std::fmt::Debug for SkipCheckIfFeeless { +impl sp_std::fmt::Debug for SkipCheckIfFeeless { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "SkipCheckIfFeeless<{:?}>", self.0.encode()) @@ -90,9 +90,8 @@ impl sp_std::fmt::Debug for SkipCheckIfFeeless SkipCheckIfFeeless { - /// utility constructor. Used only in client/factory code. - pub fn from(s: S) -> Self { +impl From for SkipCheckIfFeeless { + fn from(s: S) -> Self { Self(s, sp_std::marker::PhantomData) } } @@ -106,7 +105,11 @@ where type Call = S::Call; type AdditionalSigned = S::AdditionalSigned; type Pre = (Self::AccountId, Option<::Pre>); - const IDENTIFIER: &'static str = "SkipCheckIfFeeless"; + // From the outside this extension should be "invisible", because it just extends the wrapped + // extension with an extra check in `pre_dispatch` and `post_dispatch`. Thus, we should forward + // the identifier of the wrapped extension to let wallets see this extension as it would only be + // the wrapped extension itself. + const IDENTIFIER: &'static str = S::IDENTIFIER; fn additional_signed(&self) -> Result { self.0.additional_signed() -- GitLab From 2fd8c51ebcfcf7d10cab2a2827211583418a90a0 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:51:23 +0100 Subject: [PATCH 543/633] `chain-spec-builder`: cleanup (#2174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR removes: - `New`, `Generate`, `Edit` commands, - `kitchensink` dependency from the `chain-spec-builder` util. New `convert-to-raw`, `update-code` commands were added. Additionally renames the `runtime` command (which was added in #1256) to `create`. --------- Co-authored-by: Sebastian Kunert Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- Cargo.lock | 7 - .../bin/utils/chain-spec-builder/Cargo.toml | 7 - .../bin/utils/chain-spec-builder/bin/main.rs | 127 ++------ .../bin/utils/chain-spec-builder/src/lib.rs | 295 +++++------------- 4 files changed, 116 insertions(+), 320 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2d655e6f41..697f232f971 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18315,18 +18315,11 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "ansi_term", "clap 4.4.6", - "kitchensink-runtime", "log", - "rand 0.8.5", "sc-chain-spec", - "sc-keystore", "serde_json", - "sp-core", - "sp-keystore", "sp-tracing 10.0.0", - "staging-node-cli", ] [[package]] diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 0b373b8e924..f587989e003 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -20,15 +20,8 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -ansi_term = "0.12.1" clap = { version = "4.4.6", features = ["derive"] } -rand = "0.8" -kitchensink-runtime = { version = "3.0.0-dev", path = "../../node/runtime" } log = "0.4.17" -node-cli = { package = "staging-node-cli", path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } -sc-keystore = { path = "../../../client/keystore" } serde_json = "1.0.108" -sp-core = { path = "../../../primitives/core" } -sp-keystore = { path = "../../../primitives/keystore" } sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" } diff --git a/substrate/bin/utils/chain-spec-builder/bin/main.rs b/substrate/bin/utils/chain-spec-builder/bin/main.rs index 83892afd6ac..986293179a9 100644 --- a/substrate/bin/utils/chain-spec-builder/bin/main.rs +++ b/substrate/bin/utils/chain-spec-builder/bin/main.rs @@ -17,14 +17,11 @@ // along with this program. If not, see . use chain_spec_builder::{ - generate_authority_keys_and_store, generate_chain_spec, generate_chain_spec_for_runtime, - print_seeds, ChainSpecBuilder, ChainSpecBuilderCmd, EditCmd, GenerateCmd, NewCmd, VerifyCmd, + generate_chain_spec_for_runtime, ChainSpecBuilder, ChainSpecBuilderCmd, ConvertToRawCmd, + UpdateCodeCmd, VerifyCmd, }; use clap::Parser; -use node_cli::chain_spec; -use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use sc_chain_spec::{update_code_in_json_chain_spec, GenericChainSpec}; -use sp_core::{crypto::Ss58Codec, sr25519}; use staging_chain_spec_builder as chain_spec_builder; use std::fs; @@ -32,110 +29,48 @@ fn main() -> Result<(), String> { sp_tracing::try_init_simple(); let builder = ChainSpecBuilder::parse(); - #[cfg(build_type = "debug")] - if matches!(builder.command, ChainSpecBuilderCmd::Generate(_) | ChainSpecBuilderCmd::New(_)) { - println!( - "The chain spec builder builds a chain specification that includes a Substrate runtime \ - compiled as WASM. To ensure proper functioning of the included runtime compile (or run) \ - the chain spec builder binary in `--release` mode.\n", - ); - } - let chain_spec_path = builder.chain_spec_path.to_path_buf(); - let mut write_chain_spec = true; - - let chain_spec_json = match builder.command { - ChainSpecBuilderCmd::Generate(GenerateCmd { - authorities, - nominators, - endowed, - keystore_path, - }) => { - let authorities = authorities.max(1); - let rand_str = || -> String { - OsRng.sample_iter(&Alphanumeric).take(32).map(char::from).collect() - }; - - let authority_seeds = (0..authorities).map(|_| rand_str()).collect::>(); - let nominator_seeds = (0..nominators).map(|_| rand_str()).collect::>(); - let endowed_seeds = (0..endowed).map(|_| rand_str()).collect::>(); - let sudo_seed = rand_str(); - - print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed); - - if let Some(keystore_path) = keystore_path { - generate_authority_keys_and_store(&authority_seeds, &keystore_path)?; - } - - let nominator_accounts = nominator_seeds - .into_iter() - .map(|seed| { - chain_spec::get_account_id_from_seed::(&seed).to_ss58check() - }) - .collect(); - - let endowed_accounts = endowed_seeds - .into_iter() - .map(|seed| { - chain_spec::get_account_id_from_seed::(&seed).to_ss58check() - }) - .collect(); - let sudo_account = - chain_spec::get_account_id_from_seed::(&sudo_seed).to_ss58check(); - - generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account) + match builder.command { + ChainSpecBuilderCmd::Create(cmd) => { + let chain_spec_json = generate_chain_spec_for_runtime(&cmd)?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; }, - ChainSpecBuilderCmd::New(NewCmd { - authority_seeds, - nominator_accounts, - endowed_accounts, - sudo_account, - }) => - generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account), - ChainSpecBuilderCmd::Runtime(cmd) => generate_chain_spec_for_runtime(&cmd), - ChainSpecBuilderCmd::Edit(EditCmd { + ChainSpecBuilderCmd::UpdateCode(UpdateCodeCmd { ref input_chain_spec, ref runtime_wasm_path, - convert_to_raw, }) => { let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; let mut chain_spec_json = - serde_json::from_str::(&chain_spec.as_json(convert_to_raw)?) + serde_json::from_str::(&chain_spec.as_json(false)?) .map_err(|e| format!("Conversion to json failed: {e}"))?; - if let Some(path) = runtime_wasm_path { - update_code_in_json_chain_spec( - &mut chain_spec_json, - &fs::read(path.as_path()) - .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], - ); - } - - serde_json::to_string_pretty(&chain_spec_json) - .map_err(|e| format!("to pretty failed: {e}")) + update_code_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(runtime_wasm_path.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + ); + + let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; }, - ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec, ref runtime_wasm_path }) => { - write_chain_spec = false; + ChainSpecBuilderCmd::ConvertToRaw(ConvertToRawCmd { ref input_chain_spec }) => { let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; - let mut chain_spec_json = + + let chain_spec_json = serde_json::from_str::(&chain_spec.as_json(true)?) .map_err(|e| format!("Conversion to json failed: {e}"))?; - if let Some(path) = runtime_wasm_path { - update_code_in_json_chain_spec( - &mut chain_spec_json, - &fs::read(path.as_path()) - .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], - ); - }; - serde_json::to_string_pretty(&chain_spec_json) - .map_err(|e| format!("to pretty failed: {e}")) - }, - }?; - if write_chain_spec { - fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string()) - } else { - Ok(()) - } + let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("Conversion to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, + ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec }) => { + let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + let _ = serde_json::from_str::(&chain_spec.as_json(true)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + }, + }; + Ok(()) } diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 6f21b68c368..60ec0f1a656 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -21,31 +21,69 @@ //! A chain-spec is short for `chain-configuration`. See the [`sc-chain-spec`] for more information. //! //! Note that this binary is analogous to the `build-spec` subcommand, contained in typical -//! substrate-based nodes. This particular binary is capable of building a more sophisticated chain -//! specification that can be used with the substrate-node, ie. [`node-cli`]. +//! substrate-based nodes. This particular binary is capable of interacting with +//! [`sp-genesis-builder`] implementation of any provided runtime allowing to build chain-spec JSON +//! files. //! -//! See [`ChainSpecBuilder`] for a list of available commands. +//! See [`ChainSpecBuilderCmd`] for a list of available commands. +//! +//! ## Typical use-cases. +//! ##### Get default config from runtime. +//! +//! Query the default genesis config from the provided `runtime.wasm` and use it in the chain +//! spec. Tool can also store runtime's default genesis config in given file: +//! ```text +//! chain-spec-builder create -r runtime.wasm default /dev/stdout +//! ``` +//! +//! _Note:_ [`GenesisBuilder::create_default_config`][sp-genesis-builder-create] runtime function is called. +//! +//! +//! ##### Generate raw storage chain spec using genesis config patch. +//! +//! Patch the runtime's default genesis config with provided `patch.json` and generate raw +//! storage (`-s`) version of chain spec: +//! ```text +//! chain-spec-builder create -s -r runtime.wasm patch patch.json +//! ``` +//! +//! _Note:_ [`GenesisBuilder::build_config`][sp-genesis-builder-build] runtime function is called. +//! +//! ##### Generate raw storage chain spec using full genesis config. +//! +//! Build the chain spec using provided full genesis config json file. No defaults will be used: +//! ```text +//! chain-spec-builder create -s -r runtime.wasm full full-genesis-config.json +//! ``` +//! +//! _Note_: [`GenesisBuilder::build_config`][sp-genesis-builder-build] runtime function is called. +//! +//! ##### Generate human readable chain spec using provided genesis config patch. +//! ```text +//! chain-spec-builder create -r runtime.wasm patch patch.json +//! ``` +//! +//! ##### Generate human readable chain spec using provided full genesis config. +//! ```text +//! chain-spec-builder create -r runtime.wasm full full-genesis-config.json +//! ``` +//! +//! ##### Extra tools. +//! The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`], [`ConvertToRawCmd`], [`UpdateCodeCmd`]. //! //! [`sc-chain-spec`]: ../sc_chain_spec/index.html //! [`node-cli`]: ../node_cli/index.html +//! [`sp-genesis-builder`]: ../sp_genesis_builder/index.html +//! [sp-genesis-builder-create]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.create_default_config +//! [sp-genesis-builder-build]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.build_config -use std::{ - fs, - path::{Path, PathBuf}, -}; +use std::{fs, path::PathBuf}; -use ansi_term::Style; use clap::{Parser, Subcommand}; -use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; - -use node_cli::chain_spec::{self, AccountId}; -use sc_keystore::LocalKeystore; +use sc_chain_spec::{GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; use serde_json::Value; -use sp_core::crypto::{ByteArray, Ss58Codec}; -use sp_keystore::KeystorePtr; -/// A utility to easily create a testnet chain spec definition with a given set -/// of authorities and endowed accounts and/or generate random accounts. +/// A utility to easily create a chain spec definition. #[derive(Debug, Parser)] #[command(rename_all = "kebab-case")] pub struct ChainSpecBuilder { @@ -59,70 +97,25 @@ pub struct ChainSpecBuilder { #[derive(Debug, Subcommand)] #[command(rename_all = "kebab-case")] pub enum ChainSpecBuilderCmd { - New(NewCmd), - Generate(GenerateCmd), - Runtime(RuntimeCmd), - Edit(EditCmd), + Create(CreateCmd), Verify(VerifyCmd), -} - -/// Create a new chain spec with the given authorities, endowed and sudo -/// accounts. Only works for kitchen-sink runtime -#[derive(Parser, Debug)] -#[command(rename_all = "kebab-case")] -pub struct NewCmd { - /// Authority key seed. - #[arg(long, short, required = true)] - pub authority_seeds: Vec, - /// Active nominators (SS58 format), each backing a random subset of the aforementioned - /// authorities. - #[arg(long, short, default_value = "0")] - pub nominator_accounts: Vec, - /// Endowed account address (SS58 format). - #[arg(long, short)] - pub endowed_accounts: Vec, - /// Sudo account address (SS58 format). - #[arg(long, short)] - pub sudo_account: String, -} - -/// Create a new chain spec with the given number of authorities and endowed -/// accounts. Random keys will be generated as required. -#[derive(Parser, Debug)] -pub struct GenerateCmd { - /// The number of authorities. - #[arg(long, short)] - pub authorities: usize, - /// The number of nominators backing the aforementioned authorities. - /// - /// Will nominate a random subset of `authorities`. - #[arg(long, short, default_value_t = 0)] - pub nominators: usize, - /// The number of endowed accounts. - #[arg(long, short, default_value_t = 0)] - pub endowed: usize, - /// Path to use when saving generated keystores for each authority. - /// - /// At this path, a new folder will be created for each authority's - /// keystore named `auth-$i` where `i` is the authority index, i.e. - /// `auth-0`, `auth-1`, etc. - #[arg(long, short)] - pub keystore_path: Option, + UpdateCode(UpdateCodeCmd), + ConvertToRaw(ConvertToRawCmd), } /// Create a new chain spec by interacting with the provided runtime wasm blob. #[derive(Parser, Debug)] -pub struct RuntimeCmd { - /// The name of chain +pub struct CreateCmd { + /// The name of chain. #[arg(long, short = 'n', default_value = "Custom")] chain_name: String, - /// The chain id + /// The chain id. #[arg(long, short = 'i', default_value = "custom")] chain_id: String, - /// The path to runtime wasm blob + /// The path to runtime wasm blob. #[arg(long, short)] runtime_wasm_path: PathBuf, - /// Export chainspec as raw storage + /// Export chainspec as raw storage. #[arg(long, short = 's')] raw_storage: bool, /// Verify the genesis config. This silently generates the raw storage from genesis config. Any @@ -144,7 +137,6 @@ enum GenesisBuildAction { #[derive(Parser, Debug, Clone)] struct PatchCmd { /// The path to the runtime genesis config patch. - #[arg(long, short)] patch_path: PathBuf, } @@ -152,7 +144,6 @@ struct PatchCmd { #[derive(Parser, Debug, Clone)] struct FullCmd { /// The path to the full runtime genesis config json file. - #[arg(long, short)] config_path: PathBuf, } @@ -163,161 +154,45 @@ struct FullCmd { struct DefaultCmd { /// If provided stores the default genesis config json file at given path (in addition to /// chain-spec). - #[arg(long, short)] default_config_path: Option, } -/// Edits provided input chain spec. Input can be converted into raw storage chain-spec. The code -/// can be updated with the runtime provided in the command line. +/// Updates the code in the provided input chain spec. +/// +/// The code field of the chain spec will be updated with the runtime provided in the +/// command line. This operation supports both plain and raw formats. #[derive(Parser, Debug, Clone)] -pub struct EditCmd { - /// Chain spec to be edited - #[arg(long, short)] +pub struct UpdateCodeCmd { + /// Chain spec to be updated. pub input_chain_spec: PathBuf, - /// The path to new runtime wasm blob to be stored into chain-spec - #[arg(long, short = 'r')] - pub runtime_wasm_path: Option, - /// Convert genesis spec to raw format - #[arg(long, short = 's')] - pub convert_to_raw: bool, + /// The path to new runtime wasm blob to be stored into chain-spec. + pub runtime_wasm_path: PathBuf, } -/// Verifies provided input chain spec. If the runtime is provided verification is performed against -/// new runtime. +/// Converts the given chain spec into the raw format. #[derive(Parser, Debug, Clone)] -pub struct VerifyCmd { - /// Chain spec to be edited - #[arg(long, short)] +pub struct ConvertToRawCmd { + /// Chain spec to be converted. pub input_chain_spec: PathBuf, - /// The path to new runtime wasm blob to be stored into chain-spec - #[arg(long, short = 'r')] - pub runtime_wasm_path: Option, -} - -/// Generate the chain spec using the given seeds and accounts. -pub fn generate_chain_spec( - authority_seeds: Vec, - nominator_accounts: Vec, - endowed_accounts: Vec, - sudo_account: String, -) -> Result { - let parse_account = |address: String| { - AccountId::from_string(&address) - .map_err(|err| format!("Failed to parse account address: {:?}", err)) - }; - - let nominator_accounts = nominator_accounts - .into_iter() - .map(parse_account) - .collect::, String>>()?; - - let endowed_accounts = endowed_accounts - .into_iter() - .map(parse_account) - .collect::, String>>()?; - - let sudo_account = parse_account(sudo_account)?; - - let authorities = authority_seeds - .iter() - .map(AsRef::as_ref) - .map(chain_spec::authority_keys_from_seed) - .collect::>(); - - chain_spec::ChainSpec::builder(kitchensink_runtime::wasm_binary_unwrap(), Default::default()) - .with_name("Custom") - .with_id("custom") - .with_chain_type(sc_chain_spec::ChainType::Live) - .with_genesis_config_patch(chain_spec::testnet_genesis( - authorities, - nominator_accounts, - sudo_account, - Some(endowed_accounts), - )) - .build() - .as_json(false) -} - -/// Generate the authority keys and store them in the given `keystore_path`. -pub fn generate_authority_keys_and_store( - seeds: &[String], - keystore_path: &Path, -) -> Result<(), String> { - for (n, seed) in seeds.iter().enumerate() { - let keystore: KeystorePtr = - LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None) - .map_err(|err| err.to_string())? - .into(); - - let (_, _, grandpa, babe, im_online, authority_discovery, mixnet) = - chain_spec::authority_keys_from_seed(seed); - - let insert_key = |key_type, public| { - keystore - .insert(key_type, &format!("//{}", seed), public) - .map_err(|_| format!("Failed to insert key: {}", grandpa)) - }; - - insert_key(sp_core::crypto::key_types::BABE, babe.as_slice())?; - - insert_key(sp_core::crypto::key_types::GRANDPA, grandpa.as_slice())?; - - insert_key(sp_core::crypto::key_types::IM_ONLINE, im_online.as_slice())?; - - insert_key( - sp_core::crypto::key_types::AUTHORITY_DISCOVERY, - authority_discovery.as_slice(), - )?; - - insert_key(sp_core::crypto::key_types::MIXNET, mixnet.as_slice())?; - } - - Ok(()) } -/// Print the given seeds -pub fn print_seeds( - authority_seeds: &[String], - nominator_seeds: &[String], - endowed_seeds: &[String], - sudo_seed: &str, -) { - let header = Style::new().bold().underline(); - let entry = Style::new().bold(); - - println!("{}", header.paint("Authority seeds")); - - for (n, seed) in authority_seeds.iter().enumerate() { - println!("{} //{}", entry.paint(format!("auth-{}:", n)), seed); - } - - println!("{}", header.paint("Nominator seeds")); - - for (n, seed) in nominator_seeds.iter().enumerate() { - println!("{} //{}", entry.paint(format!("nom-{}:", n)), seed); - } - - println!(); - - if !endowed_seeds.is_empty() { - println!("{}", header.paint("Endowed seeds")); - for (n, seed) in endowed_seeds.iter().enumerate() { - println!("{} //{}", entry.paint(format!("endowed-{}:", n)), seed); - } - - println!(); - } - - println!("{}", header.paint("Sudo seed")); - println!("//{}", sudo_seed); +/// Verifies the provided input chain spec. +/// +/// Silently checks if given input chain spec can be converted to raw. It allows to check if all +/// RuntimeGenesisConfig fiels are properly initialized and if the json does not contain invalid +/// fields. +#[derive(Parser, Debug, Clone)] +pub struct VerifyCmd { + /// Chain spec to be verified. + pub input_chain_spec: PathBuf, } -/// Processes `RuntimeCmd` and returns JSON version of `ChainSpec` -pub fn generate_chain_spec_for_runtime(cmd: &RuntimeCmd) -> Result { +/// Processes `CreateCmd` and returns JSON version of `ChainSpec`. +pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result { let code = fs::read(cmd.runtime_wasm_path.as_path()) .map_err(|e| format!("wasm blob shall be readable {e}"))?; - let builder = chain_spec::ChainSpec::builder(&code[..], Default::default()) + let builder = GenericChainSpec::<()>::builder(&code[..], Default::default()) .with_name(&cmd.chain_name[..]) .with_id(&cmd.chain_id[..]) .with_chain_type(sc_chain_spec::ChainType::Live); -- GitLab From 06190498a00ff913975fa8853c3c6a94783c4124 Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Tue, 21 Nov 2023 19:10:59 +0800 Subject: [PATCH 544/633] Refactor `ValidationError` (#2406) --- .../node/core/candidate-validation/src/lib.rs | 60 +++++++++++-------- .../core/candidate-validation/src/tests.rs | 40 ++++++------- .../benches/host_prepare_rococo_runtime.rs | 3 +- .../node/core/pvf/common/src/executor_intf.rs | 19 +++--- polkadot/node/core/pvf/src/error.rs | 37 ++++++++---- polkadot/node/core/pvf/src/execute/queue.rs | 14 ++--- polkadot/node/core/pvf/src/host.rs | 39 +++++------- polkadot/node/core/pvf/src/lib.rs | 2 +- polkadot/node/core/pvf/tests/it/main.rs | 8 +-- polkadot/node/core/pvf/tests/it/process.rs | 10 ++-- 10 files changed, 122 insertions(+), 110 deletions(-) diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index f5d17af6c68..9f7b17f6129 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -24,8 +24,8 @@ #![warn(missing_docs)] use polkadot_node_core_pvf::{ - InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PrepareError, - PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, + InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PossiblyInvalidError, + PrepareError, PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, }; use polkadot_node_primitives::{ BlockData, InvalidCandidate, PoV, ValidationResult, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT, @@ -642,7 +642,7 @@ async fn validate_candidate_exhaustive( } match result { - Err(ValidationError::InternalError(e)) => { + Err(ValidationError::Internal(e)) => { gum::warn!( target: LOG_TARGET, ?para_id, @@ -651,34 +651,29 @@ async fn validate_candidate_exhaustive( ); Err(ValidationFailed(e.to_string())) }, - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout)) => + Err(ValidationError::Invalid(WasmInvalidCandidate::HardTimeout)) => Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::WorkerReportedInvalid(e))) => + Err(ValidationError::Invalid(WasmInvalidCandidate::WorkerReportedInvalid(e))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e))), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)) => + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError( "ambiguous worker death".to_string(), ))), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError(err))) => + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(err))), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath(err))) => + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(format!( "ambiguous job death: {err}" )))), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::PrepareError(e))) => { - // In principle if preparation of the `WASM` fails, the current candidate can not be the - // reason for that. So we can't say whether it is invalid or not. In addition, with - // pre-checking enabled only valid runtimes should ever get enacted, so we can be - // reasonably sure that this is some local problem on the current node. However, as this - // particular error *seems* to indicate a deterministic error, we raise a warning. + Err(ValidationError::Preparation(e)) => { gum::warn!( target: LOG_TARGET, ?para_id, ?e, "Deterministic error occurred during preparation (should have been ruled out by pre-checking phase)", ); - Err(ValidationFailed(e)) + Err(ValidationFailed(e.to_string())) }, Ok(res) => if res.head_data.hash() != candidate_receipt.descriptor.para_head { @@ -762,16 +757,31 @@ trait ValidationBackend { } match validation_result { - Err(ValidationError::InvalidCandidate( - WasmInvalidCandidate::AmbiguousWorkerDeath | - WasmInvalidCandidate::AmbiguousJobDeath(_), - )) if num_death_retries_left > 0 => num_death_retries_left -= 1, - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError(_))) - if num_job_error_retries_left > 0 => - num_job_error_retries_left -= 1, - Err(ValidationError::InternalError(_)) if num_internal_retries_left > 0 => - num_internal_retries_left -= 1, - _ => break, + Err(ValidationError::PossiblyInvalid( + PossiblyInvalidError::AmbiguousWorkerDeath | + PossiblyInvalidError::AmbiguousJobDeath(_), + )) => + if num_death_retries_left > 0 { + num_death_retries_left -= 1; + } else { + break; + }, + + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(_))) => + if num_job_error_retries_left > 0 { + num_job_error_retries_left -= 1; + } else { + break; + }, + + Err(ValidationError::Internal(_)) => + if num_internal_retries_left > 0 { + num_internal_retries_left -= 1; + } else { + break; + }, + + Ok(_) | Err(ValidationError::Invalid(_) | ValidationError::Preparation(_)) => break, } // If we got a possibly transient error, retry once after a brief delay, on the diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 5e2585d6873..11078580465 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -480,9 +480,9 @@ fn candidate_validation_bad_return_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result(Err( - ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), - )), + MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( + WasmInvalidCandidate::HardTimeout, + ))), validation_data, validation_code, candidate_receipt, @@ -561,7 +561,7 @@ fn candidate_validation_one_ambiguous_error_is_valid() { let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), Ok(validation_result), ]), validation_data.clone(), @@ -602,8 +602,8 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), ]), validation_data, validation_code, @@ -626,7 +626,7 @@ fn candidate_validation_retry_internal_errors() { vec![ Err(InternalValidationError::HostCommunication("foo".into()).into()), // Throw an AJD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath( + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath( "baz".into(), ))), // Throw another internal error. @@ -644,7 +644,7 @@ fn candidate_validation_dont_retry_internal_errors() { vec![ Err(InternalValidationError::HostCommunication("foo".into()).into()), // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), // Throw another internal error. Err(InternalValidationError::HostCommunication("bar".into()).into()), ], @@ -659,11 +659,11 @@ fn candidate_validation_retry_panic_errors() { let v = candidate_validation_retry_on_error_helper( PvfExecKind::Approval, vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError("foo".into()))), // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), // Throw another panic error. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError("bar".into()))), ], ); @@ -676,11 +676,11 @@ fn candidate_validation_dont_retry_panic_errors() { let v = candidate_validation_retry_on_error_helper( PvfExecKind::Backing, vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError("foo".into()))), // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), // Throw another panic error. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError("bar".into()))), ], ); @@ -758,9 +758,9 @@ fn candidate_validation_timeout_is_internal_error() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result(Err( - ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), - )), + MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( + WasmInvalidCandidate::HardTimeout, + ))), validation_data, validation_code, candidate_receipt, @@ -852,9 +852,9 @@ fn candidate_validation_code_mismatch_is_invalid() { let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::(pool.clone()); let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result(Err( - ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), - )), + MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( + WasmInvalidCandidate::HardTimeout, + ))), validation_data, validation_code, candidate_receipt, diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index c02a0b595da..f2551b701c2 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -18,8 +18,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, SamplingMode}; use polkadot_node_core_pvf::{ - start, testing, Config, Metrics, PrepareError, PrepareJobKind, PrepareStats, PvfPrepData, - ValidationHost, + start, testing, Config, Metrics, PrepareError, PrepareJobKind, PvfPrepData, ValidationHost, }; use polkadot_primitives::ExecutorParams; use rococo_runtime::WASM_BINARY; diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 3a1d3ac1ba0..4bafc3f4291 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_intf.rs @@ -140,8 +140,7 @@ pub unsafe fn create_runtime_from_artifact_bytes( executor_params: &ExecutorParams, ) -> Result { let mut config = DEFAULT_CONFIG.clone(); - config.semantics = - params_to_wasmtime_semantics(executor_params).map_err(|err| WasmError::Other(err))?; + config.semantics = params_to_wasmtime_semantics(executor_params); sc_executor_wasmtime::create_runtime_from_artifact_bytes::( compiled_artifact_blob, @@ -149,13 +148,12 @@ pub unsafe fn create_runtime_from_artifact_bytes( ) } -pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result { +pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Semantics { let mut sem = DEFAULT_CONFIG.semantics.clone(); - let mut stack_limit = if let Some(stack_limit) = sem.deterministic_stack_limit.clone() { - stack_limit - } else { - return Err("No default stack limit set".to_owned()) - }; + let mut stack_limit = sem + .deterministic_stack_limit + .expect("There is a comment to not change the default stack limit; it should always be available; qed") + .clone(); for p in par.iter() { match p { @@ -172,7 +170,7 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result Result, sc_executor_common::error::WasmError> { - let semantics = params_to_wasmtime_semantics(executor_params) - .map_err(|e| sc_executor_common::error::WasmError::Other(e))?; + let semantics = params_to_wasmtime_semantics(executor_params); sc_executor_wasmtime::prepare_runtime_artifact(blob, &semantics) } diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index 7fdb8c56ec9..442443f326e 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -19,31 +19,44 @@ use polkadot_node_core_pvf_common::error::{InternalValidationError, PrepareError /// A error raised during validation of the candidate. #[derive(Debug, Clone)] pub enum ValidationError { - /// The error was raised because the candidate is invalid. + /// Deterministic preparation issue. In practice, most of the problems should be caught by + /// prechecking, so this may be a sign of internal conditions. /// - /// Whenever we are unsure if the error was due to the candidate or not, we must vote invalid. - InvalidCandidate(InvalidCandidate), - /// Some internal error occurred. - InternalError(InternalValidationError), + /// In principle if preparation of the `WASM` fails, the current candidate cannot be the + /// reason for that. So we can't say whether it is invalid or not. In addition, with + /// pre-checking enabled only valid runtimes should ever get enacted, so we can be + /// reasonably sure that this is some local problem on the current node. However, as this + /// particular error *seems* to indicate a deterministic error, we raise a warning. + Preparation(PrepareError), + /// The error was raised because the candidate is invalid. Should vote against. + Invalid(InvalidCandidate), + /// Possibly transient issue that may resolve after retries. Should vote against when retries + /// fail. + PossiblyInvalid(PossiblyInvalidError), + /// Preparation or execution issue caused by an internal condition. Should not vote against. + Internal(InternalValidationError), } /// A description of an error raised during executing a PVF and can be attributed to the combination /// of the candidate [`polkadot_parachain_primitives::primitives::ValidationParams`] and the PVF. #[derive(Debug, Clone)] pub enum InvalidCandidate { - /// PVF preparation ended up with a deterministic error. - PrepareError(String), /// The candidate is reported to be invalid by the execution worker. The string contains the /// error message. WorkerReportedInvalid(String), + /// PVF execution (compilation is not included) took more time than was allotted. + HardTimeout, +} + +/// Possibly transient issue that may resolve after retries. +#[derive(Debug, Clone)] +pub enum PossiblyInvalidError { /// The worker process (not the job) has died during validation of a candidate. /// /// It's unlikely that this is caused by malicious code since workers spawn separate job /// processes, and those job processes are sandboxed. But, it is possible. We retry in this /// case, and if the error persists, we assume it's caused by the candidate and vote against. AmbiguousWorkerDeath, - /// PVF execution (compilation is not included) took more time than was allotted. - HardTimeout, /// The job process (not the worker) has died for one of the following reasons: /// /// (a) A seccomp violation occurred, most likely due to an attempt by malicious code to @@ -68,7 +81,7 @@ pub enum InvalidCandidate { impl From for ValidationError { fn from(error: InternalValidationError) -> Self { - Self::InternalError(error) + Self::Internal(error) } } @@ -77,9 +90,9 @@ impl From for ValidationError { // Here we need to classify the errors into two errors: deterministic and non-deterministic. // See [`PrepareError::is_deterministic`]. if error.is_deterministic() { - Self::InvalidCandidate(InvalidCandidate::PrepareError(error.to_string())) + Self::Preparation(error) } else { - Self::InternalError(InternalValidationError::NonDeterministicPrepareError(error)) + Self::Internal(InternalValidationError::NonDeterministicPrepareError(error)) } } } diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index 257377df3f4..a0c24fd4432 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -22,7 +22,7 @@ use crate::{ host::ResultSender, metrics::Metrics, worker_intf::{IdleWorker, WorkerHandle}, - InvalidCandidate, ValidationError, LOG_TARGET, + InvalidCandidate, PossiblyInvalidError, ValidationError, LOG_TARGET, }; use futures::{ channel::mpsc, @@ -342,27 +342,27 @@ fn handle_job_finish( }, Outcome::InvalidCandidate { err, idle_worker } => ( Some(idle_worker), - Err(ValidationError::InvalidCandidate(InvalidCandidate::WorkerReportedInvalid(err))), + Err(ValidationError::Invalid(InvalidCandidate::WorkerReportedInvalid(err))), None, ), - Outcome::InternalError { err } => (None, Err(ValidationError::InternalError(err)), None), + Outcome::InternalError { err } => (None, Err(ValidationError::Internal(err)), None), // Either the worker or the job timed out. Kill the worker in either case. Treated as // definitely-invalid, because if we timed out, there's no time left for a retry. Outcome::HardTimeout => - (None, Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)), None), + (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None), // "Maybe invalid" errors (will retry). Outcome::WorkerIntfErr => ( None, - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), None, ), Outcome::JobDied { err } => ( None, - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousJobDeath(err))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))), None, ), Outcome::JobError { err } => - (None, Err(ValidationError::InvalidCandidate(InvalidCandidate::JobError(err))), None), + (None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))), None), }; queue.metrics.execute_finished(); diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index f67934e4171..6049f51834e 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -873,7 +873,7 @@ fn pulse_every(interval: std::time::Duration) -> impl futures::Stream #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::InvalidCandidate; + use crate::PossiblyInvalidError; use assert_matches::assert_matches; use futures::future::BoxFuture; use polkadot_node_core_pvf_common::{ @@ -1211,27 +1211,27 @@ pub(crate) mod tests { ); result_tx_pvf_1_1 - .send(Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath))) + .send(Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath))) .unwrap(); assert_matches!( result_rx_pvf_1_1.now_or_never().unwrap().unwrap(), - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) ); result_tx_pvf_1_2 - .send(Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath))) + .send(Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath))) .unwrap(); assert_matches!( result_rx_pvf_1_2.now_or_never().unwrap().unwrap(), - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) ); result_tx_pvf_2 - .send(Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath))) + .send(Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath))) .unwrap(); assert_matches!( result_rx_pvf_2.now_or_never().unwrap().unwrap(), - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) ); } @@ -1337,7 +1337,7 @@ pub(crate) mod tests { assert_matches!(result_rx.now_or_never().unwrap().unwrap(), Err(PrepareError::TimedOut)); assert_matches!( result_rx_execute.now_or_never().unwrap().unwrap(), - Err(ValidationError::InternalError(_)) + Err(ValidationError::Internal(_)) ); // Reversed case: first send multiple precheck requests, then ask for an execution. @@ -1479,7 +1479,7 @@ pub(crate) mod tests { // The result should contain the error. let result = test.poll_and_recv_result(result_rx).await; - assert_matches!(result, Err(ValidationError::InternalError(_))); + assert_matches!(result, Err(ValidationError::Internal(_))); // Submit another execute request. We shouldn't try to prepare again, yet. let (result_tx_2, result_rx_2) = oneshot::channel(); @@ -1498,7 +1498,7 @@ pub(crate) mod tests { // The result should contain the original error. let result = test.poll_and_recv_result(result_rx_2).await; - assert_matches!(result, Err(ValidationError::InternalError(_))); + assert_matches!(result, Err(ValidationError::Internal(_))); // Pause for enough time to reset the cooldown for this failed prepare request. futures_timer::Delay::new(PREPARE_FAILURE_COOLDOWN).await; @@ -1538,11 +1538,11 @@ pub(crate) mod tests { // Send an error for the execution here, just so we can check the result receiver is still // alive. result_tx_3 - .send(Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath))) + .send(Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath))) .unwrap(); assert_matches!( result_rx_3.now_or_never().unwrap().unwrap(), - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) ); } @@ -1581,10 +1581,7 @@ pub(crate) mod tests { // The result should contain the error. let result = test.poll_and_recv_result(result_rx).await; - assert_matches!( - result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::PrepareError(_))) - ); + assert_matches!(result, Err(ValidationError::Preparation(_))); // Submit another execute request. let (result_tx_2, result_rx_2) = oneshot::channel(); @@ -1603,10 +1600,7 @@ pub(crate) mod tests { // The result should contain the original error. let result = test.poll_and_recv_result(result_rx_2).await; - assert_matches!( - result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::PrepareError(_))) - ); + assert_matches!(result, Err(ValidationError::Preparation(_))); // Pause for enough time to reset the cooldown for this failed prepare request. futures_timer::Delay::new(PREPARE_FAILURE_COOLDOWN).await; @@ -1628,10 +1622,7 @@ pub(crate) mod tests { // The result should still contain the original error. let result = test.poll_and_recv_result(result_rx_3).await; - assert_matches!( - result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::PrepareError(_))) - ); + assert_matches!(result, Err(ValidationError::Preparation(_))); } // Test that multiple heads-up requests trigger preparation retries if the first one failed. diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 7e7a1325254..3306a2461c1 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -103,7 +103,7 @@ mod worker_intf; #[cfg(feature = "test-utils")] pub mod testing; -pub use error::{InvalidCandidate, ValidationError}; +pub use error::{InvalidCandidate, PossiblyInvalidError, ValidationError}; pub use host::{start, Config, ValidationHost, EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}; pub use metrics::Metrics; pub use priority::Priority; diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 5bdf49cc719..4c81ac502dd 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -162,7 +162,7 @@ async fn execute_job_terminates_on_timeout() { .await; match result { - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) => {}, + Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)) => {}, r => panic!("{:?}", r), } @@ -202,8 +202,8 @@ async fn ensure_parallel_execution() { assert_matches!( (res1, res2), ( - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)), - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) + Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), + Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)) ) ); @@ -344,7 +344,7 @@ async fn deleting_prepared_artifact_does_not_dispute() { .await; match result { - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) => {}, + Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)) => {}, r => panic!("{:?}", r), } } diff --git a/polkadot/node/core/pvf/tests/it/process.rs b/polkadot/node/core/pvf/tests/it/process.rs index 725d060ab91..075d94373df 100644 --- a/polkadot/node/core/pvf/tests/it/process.rs +++ b/polkadot/node/core/pvf/tests/it/process.rs @@ -19,7 +19,9 @@ use super::TestHost; use assert_matches::assert_matches; -use polkadot_node_core_pvf::{InvalidCandidate, PrepareError, ValidationError}; +use polkadot_node_core_pvf::{ + InvalidCandidate, PossiblyInvalidError, PrepareError, ValidationError, +}; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams}; use procfs::process; use rusty_fork::rusty_fork_test; @@ -151,7 +153,7 @@ rusty_fork_test! { assert_matches!( result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) + Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)) ); }) } @@ -217,7 +219,7 @@ rusty_fork_test! { assert_matches!( result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) ); }) } @@ -288,7 +290,7 @@ rusty_fork_test! { // Note that we get a more specific error if the job died than if the whole worker died. assert_matches!( result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousJobDeath(err))) + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))) if err == "received signal: SIGKILL" ); }) -- GitLab From 40afc77c4e6efff56649174a35384499f601f8d4 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 21 Nov 2023 08:40:55 -0300 Subject: [PATCH 545/633] Add output positional arg to undying-collator cli (#2375) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up from https://github.com/paritytech/polkadot-sdk/pull/2370 to add `output` positional argument to undying-collator. cc @JoshOrndorff --------- Co-authored-by: Bastian Köcher --- .../undying/collator/src/cli.rs | 11 +++++++- .../undying/collator/src/main.rs | 26 ++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs index cd16133dbf1..d04122f2f68 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs @@ -18,6 +18,7 @@ use clap::Parser; use sc_cli::SubstrateCli; +use std::path::PathBuf; /// Sub-commands supported by the collator. #[derive(Debug, Parser)] @@ -34,6 +35,10 @@ pub enum Subcommand { /// Command for exporting the genesis state of the parachain #[derive(Debug, Parser)] pub struct ExportGenesisStateCommand { + /// Output file name or stdout if unspecified. + #[arg()] + pub output: Option, + /// Id of the parachain this collator collates for. #[arg(long, default_value_t = 100)] pub parachain_id: u32, @@ -50,7 +55,11 @@ pub struct ExportGenesisStateCommand { /// Command for exporting the genesis wasm file. #[derive(Debug, Parser)] -pub struct ExportGenesisWasmCommand {} +pub struct ExportGenesisWasmCommand { + /// Output file name or stdout if unspecified. + #[arg()] + pub output: Option, +} #[allow(missing_docs)] #[derive(Debug, Parser)] diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index e564e221f01..c6b338a20dc 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -22,6 +22,10 @@ use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProt use polkadot_primitives::Id as ParaId; use sc_cli::{Error as SubstrateCliError, SubstrateCli}; use sp_core::hexdisplay::HexDisplay; +use std::{ + fs, + io::{self, Write}, +}; use test_parachain_undying_collator::Collator; mod cli; @@ -35,14 +39,30 @@ fn main() -> Result<()> { // `pov_size` and `pvf_complexity` need to match the ones that we start the collator // with. let collator = Collator::new(params.pov_size, params.pvf_complexity); - println!("0x{:?}", HexDisplay::from(&collator.genesis_head())); + + let output_buf = + format!("0x{:?}", HexDisplay::from(&collator.genesis_head())).into_bytes(); + + if let Some(output) = params.output { + std::fs::write(output, output_buf)?; + } else { + std::io::stdout().write_all(&output_buf)?; + } Ok::<_, Error>(()) }, - Some(cli::Subcommand::ExportGenesisWasm(_params)) => { + Some(cli::Subcommand::ExportGenesisWasm(params)) => { // We pass some dummy values for `pov_size` and `pvf_complexity` as these don't // matter for `wasm` export. - println!("0x{:?}", HexDisplay::from(&Collator::default().validation_code())); + let output_buf = + format!("0x{:?}", HexDisplay::from(&Collator::default().validation_code())) + .into_bytes(); + + if let Some(output) = params.output { + fs::write(output, output_buf)?; + } else { + io::stdout().write_all(&output_buf)?; + } Ok(()) }, -- GitLab From 552be4800d9e4b480f79a300fc531783e04be099 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 21 Nov 2023 12:52:46 +0100 Subject: [PATCH 546/633] PVF worker: switch on seccomp networking restrictions (#2221) --- polkadot/node/core/pvf/common/src/error.rs | 7 +- polkadot/node/core/pvf/common/src/execute.rs | 2 +- polkadot/node/core/pvf/common/src/lib.rs | 2 +- .../node/core/pvf/common/src/worker/mod.rs | 2 +- .../pvf/common/src/worker/security/seccomp.rs | 10 +- .../node/core/pvf/execute-worker/src/lib.rs | 26 ++-- .../node/core/pvf/prepare-worker/src/lib.rs | 24 ++-- .../node/core/pvf/src/execute/worker_intf.rs | 111 ++++++++++-------- polkadot/node/core/pvf/src/prepare/pool.rs | 4 +- .../node/core/pvf/src/prepare/worker_intf.rs | 45 ++++--- polkadot/node/core/pvf/src/security.rs | 75 ++++++++---- polkadot/node/core/pvf/tests/it/process.rs | 2 +- .../src/node/utility/pvf-host-and-workers.md | 38 +++--- 13 files changed, 202 insertions(+), 146 deletions(-) diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 6bf05ece78e..7db7f9a5945 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -77,7 +77,7 @@ pub enum PrepareError { #[codec(index = 9)] ClearWorkerDir(String), /// The preparation job process died, due to OOM, a seccomp violation, or some other factor. - JobDied(String), + JobDied { err: String, job_pid: i32 }, #[codec(index = 10)] /// Some error occurred when interfacing with the kernel. #[codec(index = 11)] @@ -96,7 +96,7 @@ impl PrepareError { match self { Prevalidation(_) | Preparation(_) | JobError(_) | OutOfMemory => true, IoErr(_) | - JobDied(_) | + JobDied { .. } | CreateTmpFile(_) | RenameTmpFile { .. } | ClearWorkerDir(_) | @@ -119,7 +119,8 @@ impl fmt::Display for PrepareError { JobError(err) => write!(f, "panic: {}", err), TimedOut => write!(f, "prepare: timeout"), IoErr(err) => write!(f, "prepare: io error while receiving response: {}", err), - JobDied(err) => write!(f, "prepare: prepare job died: {}", err), + JobDied { err, job_pid } => + write!(f, "prepare: prepare job with pid {job_pid} died: {err}"), CreateTmpFile(err) => write!(f, "prepare: error creating tmp file: {}", err), RenameTmpFile { err, src, dest } => write!(f, "prepare: error renaming tmp file ({:?} -> {:?}): {}", src, dest, err), diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index 89e7c8e471a..aa1c1c53968 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -46,7 +46,7 @@ pub enum WorkerResponse { /// /// We cannot treat this as an internal error because malicious code may have killed the job. /// We still retry it, because in the non-malicious case it is likely spurious. - JobDied(String), + JobDied { err: String, job_pid: i32 }, /// An unexpected error occurred in the job process, e.g. failing to spawn a thread, panic, /// etc. /// diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index 282d2f7c41d..278fa3fe821 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -53,7 +53,7 @@ pub struct SecurityStatus { pub can_enable_landlock: bool, /// Whether the seccomp features we use are fully available on this system. pub can_enable_seccomp: bool, - // Whether we are able to unshare the user namespace and change the filesystem root. + /// Whether we are able to unshare the user namespace and change the filesystem root. pub can_unshare_user_namespace_and_change_root: bool, } diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index 86f47acccac..d4f9bbc27ea 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -219,7 +219,7 @@ pub fn run_worker( #[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, + security_status: &SecurityStatus, mut event_loop: F, ) where F: FnMut(UnixStream, PathBuf) -> io::Result, diff --git a/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs b/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs index 5539ad28440..c3822d3c4c6 100644 --- a/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs +++ b/polkadot/node/core/pvf/common/src/worker/security/seccomp.rs @@ -67,11 +67,9 @@ //! //! # Action on syscall violations //! -//! On syscall violations we currently only log, to make sure this works correctly before enforcing. -//! -//! In the future, when a forbidden syscall is attempted we immediately kill the process in order to -//! prevent the attacker from doing anything else. In execution, this will result in voting against -//! the candidate. +//! When a forbidden syscall is attempted we immediately kill the process in order to prevent the +//! attacker from doing anything else. In execution, this will result in voting against the +//! candidate. use crate::{ worker::{stringify_panic_payload, WorkerKind}, @@ -82,7 +80,7 @@ use std::{collections::BTreeMap, path::Path}; /// The action to take on caught syscalls. #[cfg(not(test))] -const CAUGHT_ACTION: SeccompAction = SeccompAction::Log; +const CAUGHT_ACTION: SeccompAction = SeccompAction::KillProcess; /// Don't kill the process when testing. #[cfg(test)] const CAUGHT_ACTION: SeccompAction = SeccompAction::Errno(libc::EACCES as u32); diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 9ec811686b8..d82a8fca65d 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -222,12 +222,6 @@ pub fn worker_entrypoint( }, }; - gum::trace!( - target: LOG_TARGET, - %worker_pid, - "worker: sending response to host: {:?}", - response - ); send_response(&mut stream, response)?; } }, @@ -360,7 +354,7 @@ fn handle_child_process( /// - The response, either `Ok` or some error state. fn handle_parent_process( mut pipe_read: PipeReader, - child: Pid, + job_pid: Pid, worker_pid: u32, usage_before: Usage, timeout: Duration, @@ -373,10 +367,11 @@ fn handle_parent_process( // Should retry at any rate. .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?; - let status = nix::sys::wait::waitpid(child, None); + let status = nix::sys::wait::waitpid(job_pid, None); gum::trace!( target: LOG_TARGET, %worker_pid, + %job_pid, "execute worker received wait status from job: {:?}", status, ); @@ -396,6 +391,7 @@ fn handle_parent_process( gum::warn!( target: LOG_TARGET, %worker_pid, + %job_pid, "execute job took {}ms cpu time, exceeded execute timeout {}ms", cpu_tv.as_millis(), timeout.as_millis(), @@ -428,6 +424,7 @@ fn handle_parent_process( gum::warn!( target: LOG_TARGET, %worker_pid, + %job_pid, "execute job error: {}", job_error, ); @@ -443,15 +440,18 @@ fn handle_parent_process( // // The job gets SIGSYS on seccomp violations, but this signal may have been sent for some // other reason, so we still need to check for seccomp violations elsewhere. - Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => - Ok(WorkerResponse::JobDied(format!("received signal: {signal:?}"))), + Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => Ok(WorkerResponse::JobDied { + err: format!("received signal: {signal:?}"), + job_pid: job_pid.as_raw(), + }), Err(errno) => Ok(internal_error_from_errno("waitpid", errno)), // It is within an attacker's power to send an unexpected exit status. So we cannot treat // this as an internal error (which would make us abstain), but must vote against. - Ok(unexpected_wait_status) => Ok(WorkerResponse::JobDied(format!( - "unexpected status from wait: {unexpected_wait_status:?}" - ))), + Ok(unexpected_wait_status) => Ok(WorkerResponse::JobDied { + err: format!("unexpected status from wait: {unexpected_wait_status:?}"), + job_pid: job_pid.as_raw(), + }), } } diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index 34e6a78c26a..499e87c6e20 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -257,9 +257,9 @@ pub fn worker_entrypoint( handle_parent_process( pipe_reader, + worker_pid, child, temp_artifact_dest.clone(), - worker_pid, usage_before, preparation_timeout, ) @@ -506,9 +506,9 @@ fn handle_child_process( /// - If the child process timeout, it returns `PrepareError::TimedOut`. fn handle_parent_process( mut pipe_read: PipeReader, - child: Pid, - temp_artifact_dest: PathBuf, worker_pid: u32, + job_pid: Pid, + temp_artifact_dest: PathBuf, usage_before: Usage, timeout: Duration, ) -> Result { @@ -518,10 +518,11 @@ fn handle_parent_process( .read_to_end(&mut received_data) .map_err(|err| PrepareError::IoErr(err.to_string()))?; - let status = nix::sys::wait::waitpid(child, None); + let status = nix::sys::wait::waitpid(job_pid, None); gum::trace!( target: LOG_TARGET, %worker_pid, + %job_pid, "prepare worker received wait status from job: {:?}", status, ); @@ -539,6 +540,7 @@ fn handle_parent_process( gum::warn!( target: LOG_TARGET, %worker_pid, + %job_pid, "prepare job took {}ms cpu time, exceeded prepare timeout {}ms", cpu_tv.as_millis(), timeout.as_millis(), @@ -573,6 +575,7 @@ fn handle_parent_process( gum::debug!( target: LOG_TARGET, %worker_pid, + %job_pid, "worker: writing artifact to {}", temp_artifact_dest.display(), ); @@ -593,15 +596,18 @@ fn handle_parent_process( // // The job gets SIGSYS on seccomp violations, but this signal may have been sent for some // other reason, so we still need to check for seccomp violations elsewhere. - Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => - Err(PrepareError::JobDied(format!("received signal: {signal:?}"))), + Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => Err(PrepareError::JobDied { + err: format!("received signal: {signal:?}"), + job_pid: job_pid.as_raw(), + }), Err(errno) => Err(error_from_errno("waitpid", errno)), // An attacker can make the child process return any exit status it wants. So we can treat // all unexpected cases the same way. - Ok(unexpected_wait_status) => Err(PrepareError::JobDied(format!( - "unexpected status from wait: {unexpected_wait_status:?}" - ))), + Ok(unexpected_wait_status) => Err(PrepareError::JobDied { + err: format!("unexpected status from wait: {unexpected_wait_status:?}"), + job_pid: job_pid.as_raw(), + }), } } diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index bf44ba01725..4faaf13e62f 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -33,7 +33,7 @@ use polkadot_node_core_pvf_common::{ execute::{Handshake, WorkerResponse}, worker_dir, SecurityStatus, }; -use polkadot_parachain_primitives::primitives::ValidationResult; +use polkadot_parachain_primitives::primitives::{ValidationCodeHash, ValidationResult}; use polkadot_primitives::ExecutorParams; use std::{path::Path, time::Duration}; use tokio::{io, net::UnixStream}; @@ -156,6 +156,16 @@ pub async fn start_work( let response = futures::select! { response = recv_response(&mut stream).fuse() => { match response { + Ok(response) => + handle_response( + response, + pid, + &artifact.id.code_hash, + &artifact_path, + execution_timeout, + audit_log_file + ) + .await, Err(error) => { gum::warn!( target: LOG_TARGET, @@ -164,56 +174,9 @@ pub async fn start_work( ?error, "failed to recv an execute response", ); - // The worker died. Check if it was due to a seccomp violation. - // - // NOTE: Log, but don't change the outcome. Not all validators may have - // auditing enabled, so we don't want attackers to abuse a non-deterministic - // outcome. - for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { - gum::error!( - target: LOG_TARGET, - worker_pid = %pid, - %syscall, - validation_code_hash = ?artifact.id.code_hash, - ?artifact_path, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } return Outcome::WorkerIntfErr }, - Ok(response) => { - // Check if any syscall violations occurred during the job. For now this is - // only informative, as we are not enforcing the seccomp policy yet. - for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { - gum::error!( - target: LOG_TARGET, - worker_pid = %pid, - %syscall, - validation_code_hash = ?artifact.id.code_hash, - ?artifact_path, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } - - if let WorkerResponse::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() => { @@ -238,7 +201,7 @@ pub async fn start_work( idle_worker: IdleWorker { stream, pid, worker_dir }, }, WorkerResponse::JobTimedOut => Outcome::HardTimeout, - WorkerResponse::JobDied(err) => Outcome::JobDied { err }, + WorkerResponse::JobDied { err, job_pid: _ } => Outcome::JobDied { err }, WorkerResponse::JobError(err) => Outcome::JobError { err }, WorkerResponse::InternalError(err) => Outcome::InternalError { err }, @@ -247,6 +210,56 @@ pub async fn start_work( .await } +/// Handles the case where we successfully received response bytes on the host from the child. +/// +/// Here we know the artifact exists, but is still located in a temporary file which will be cleared +/// by [`with_worker_dir_setup`]. +async fn handle_response( + response: WorkerResponse, + worker_pid: u32, + validation_code_hash: &ValidationCodeHash, + artifact_path: &Path, + execution_timeout: Duration, + audit_log_file: Option, +) -> WorkerResponse { + if let WorkerResponse::Ok { duration, .. } = response { + if duration > execution_timeout { + // The job didn't complete within the timeout. + gum::warn!( + target: LOG_TARGET, + worker_pid, + "execute job took {}ms cpu time, exceeded execution timeout {}ms.", + duration.as_millis(), + execution_timeout.as_millis(), + ); + + // Return a timeout error. + return WorkerResponse::JobTimedOut + } + } + + if let WorkerResponse::JobDied { err: _, job_pid } = response { + // The job died. Check if it was due to a seccomp violation. + // + // NOTE: Log, but don't change the outcome. Not all validators may have + // auditing enabled, so we don't want attackers to abuse a non-deterministic + // outcome. + for syscall in security::check_seccomp_violations_for_job(audit_log_file, job_pid).await { + gum::error!( + target: LOG_TARGET, + %worker_pid, + %job_pid, + %syscall, + ?validation_code_hash, + ?artifact_path, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + } + + response +} + /// 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. /// diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 21af21e5b02..4901be9fe1b 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -388,14 +388,14 @@ fn handle_mux( Ok(()) }, // The worker might still be usable, but we kill it just in case. - Outcome::JobDied(err) => { + Outcome::JobDied { err, job_pid } => { if attempt_retire(metrics, spawned, worker) { reply( from_pool, FromPool::Concluded { worker, rip: true, - result: Err(PrepareError::JobDied(err)), + result: Err(PrepareError::JobDied { err, job_pid }), }, )?; } diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index e7f142a46bb..318aea7295d 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -104,7 +104,7 @@ pub enum Outcome { /// The preparation job process died, due to OOM, a seccomp violation, or some other factor. /// /// The worker might still be usable, but we kill it just in case. - JobDied(String), + JobDied { err: String, job_pid: i32 }, } /// Given the idle token of a worker and parameters of work, communicates with the worker and @@ -160,19 +160,7 @@ pub async fn start_work( match result { // Received bytes from worker within the time limit. - Ok(Ok(prepare_worker_result)) => { - // Check if any syscall violations occurred during the job. For now this is only - // informative, as we are not enforcing the seccomp policy yet. - for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { - gum::error!( - target: LOG_TARGET, - worker_pid = %pid, - %syscall, - ?pvf, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } - + Ok(Ok(prepare_worker_result)) => handle_response( metrics, IdleWorker { stream, pid, worker_dir }, @@ -182,9 +170,9 @@ pub async fn start_work( &pvf, &cache_path, preparation_timeout, + audit_log_file, ) - .await - }, + .await, Ok(Err(err)) => { // Communication error within the time limit. gum::warn!( @@ -221,15 +209,36 @@ async fn handle_response( worker_pid: u32, tmp_file: PathBuf, pvf: &PvfPrepData, - cache_path: &PathBuf, + cache_path: &Path, preparation_timeout: Duration, + audit_log_file: Option, ) -> Outcome { let PrepareWorkerSuccess { checksum, stats: PrepareStats { cpu_time_elapsed, memory_stats } } = match result.clone() { Ok(result) => result, // Timed out on the child. This should already be logged by the child. Err(PrepareError::TimedOut) => return Outcome::TimedOut, - Err(PrepareError::JobDied(err)) => return Outcome::JobDied(err), + Err(PrepareError::JobDied { err, job_pid }) => { + // The job died. Check if it was due to a seccomp violation. + // + // NOTE: Log, but don't change the outcome. Not all validators may have + // auditing enabled, so we don't want attackers to abuse a non-deterministic + // outcome. + for syscall in + security::check_seccomp_violations_for_job(audit_log_file, job_pid).await + { + gum::error!( + target: LOG_TARGET, + %worker_pid, + %job_pid, + %syscall, + ?pvf, + "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" + ); + } + + return Outcome::JobDied { err, job_pid } + }, Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, Err(err) => return Outcome::Concluded { worker, result: Err(err) }, }; diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index 0c0c5f40166..8c06c68392f 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -178,9 +178,15 @@ async fn check_can_unshare_user_namespace_and_change_root( let stderr = std::str::from_utf8(&output.stderr) .expect("child process writes a UTF-8 string to stderr; qed") .trim(); - Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( - format!("not available: {}", stderr) - )) + if stderr.is_empty() { + Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + "not available".into() + )) + } else { + Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + format!("not available: {}", stderr) + )) + } }, Err(err) => Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( @@ -208,16 +214,25 @@ async fn check_landlock( if #[cfg(target_os = "linux")] { match tokio::process::Command::new(prepare_worker_program_path) .arg("--check-can-enable-landlock") - .status() + .output() .await { - Ok(status) if status.success() => Ok(()), - Ok(_status) => { + Ok(output) if output.status.success() => Ok(()), + Ok(output) => { let abi = polkadot_node_core_pvf_common::worker::security::landlock::LANDLOCK_ABI as u8; - Err(SecureModeError::CannotEnableLandlock( - format!("landlock ABI {} not available", abi) - )) + let stderr = std::str::from_utf8(&output.stderr) + .expect("child process writes a UTF-8 string to stderr; qed") + .trim(); + if stderr.is_empty() { + Err(SecureModeError::CannotEnableLandlock( + format!("landlock ABI {} not available", abi) + )) + } else { + Err(SecureModeError::CannotEnableLandlock( + format!("not available: {}", stderr) + )) + } }, Err(err) => Err(SecureModeError::CannotEnableLandlock( @@ -238,7 +253,7 @@ async fn check_landlock( /// to running the check in a worker, we try it... in a worker. The expected return status is 0 on /// success and -1 on failure. async fn check_seccomp( - #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] + #[cfg_attr(not(all(target_os = "linux", target_arch = "x86_64")), allow(unused_variables))] prepare_worker_program_path: &Path, ) -> SecureModeResult { cfg_if::cfg_if! { @@ -247,14 +262,24 @@ async fn check_seccomp( if #[cfg(target_arch = "x86_64")] { match tokio::process::Command::new(prepare_worker_program_path) .arg("--check-can-enable-seccomp") - .status() + .output() .await { - Ok(status) if status.success() => Ok(()), - Ok(_status) => - Err(SecureModeError::CannotEnableSeccomp( - "not available".into() - )), + Ok(output) if output.status.success() => Ok(()), + Ok(output) => { + let stderr = std::str::from_utf8(&output.stderr) + .expect("child process writes a UTF-8 string to stderr; qed") + .trim(); + if stderr.is_empty() { + Err(SecureModeError::CannotEnableSeccomp( + "not available".into() + )) + } else { + Err(SecureModeError::CannotEnableSeccomp( + format!("not available: {}", stderr) + )) + } + }, Err(err) => Err(SecureModeError::CannotEnableSeccomp( format!("could not start child process: {}", err) @@ -320,25 +345,25 @@ impl AuditLogFile { } } -/// Check if a seccomp violation occurred for the given worker. As the syslog may be in a different -/// location, or seccomp auditing may be disabled, this function provides a best-effort attempt -/// only. +/// Check if a seccomp violation occurred for the given job process. As the syslog may be in a +/// different location, or seccomp auditing may be disabled, this function provides a best-effort +/// attempt only. /// /// The `audit_log_file` must have been obtained before the job started. It only allows reading /// entries that were written since it was obtained, so that we do not consider events from previous /// processes with the same pid. This can still be racy, but it's unlikely and fine for a /// best-effort attempt. -pub async fn check_seccomp_violations_for_worker( +pub async fn check_seccomp_violations_for_job( audit_log_file: Option, - worker_pid: u32, + job_pid: i32, ) -> Vec { - let audit_event_pid_field = format!("pid={worker_pid}"); + let audit_event_pid_field = format!("pid={job_pid}"); let audit_log_file = match audit_log_file { Some(file) => { - gum::debug!( + gum::trace!( target: LOG_TARGET, - %worker_pid, + %job_pid, audit_log_path = ?file.path, "checking audit log for seccomp violations", ); @@ -347,7 +372,7 @@ pub async fn check_seccomp_violations_for_worker( None => { gum::warn!( target: LOG_TARGET, - %worker_pid, + %job_pid, "could not open either {AUDIT_LOG_PATH} or {SYSLOG_PATH} for reading audit logs" ); return vec![] diff --git a/polkadot/node/core/pvf/tests/it/process.rs b/polkadot/node/core/pvf/tests/it/process.rs index 075d94373df..b742acb15d0 100644 --- a/polkadot/node/core/pvf/tests/it/process.rs +++ b/polkadot/node/core/pvf/tests/it/process.rs @@ -248,7 +248,7 @@ rusty_fork_test! { // Note that we get a more specific error if the job died than if the whole worker died. assert_matches!( result, - Err(PrepareError::JobDied(err)) if err == "received signal: SIGKILL" + Err(PrepareError::JobDied{ err, job_pid: _ }) if err == "received signal: SIGKILL" ); }) } 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 74d88ba3ad9..56bdd48bc0c 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 @@ -38,16 +38,22 @@ getting backed and honest backers getting slashed. We currently know of the following specific cases that will lead to a retried execution request: -1. **OOM:** The host might have been temporarily low on memory due to other - processes running on the same machine. **NOTE:** This case will lead to - voting against the candidate (and possibly a dispute) if the retry is still - not successful. -2. **Artifact missing:** The prepared artifact might have been deleted due to +1. **OOM:** We have memory limits to try to prevent attackers from exhausting + host memory. If the memory limit is hit, we kill the job process and retry + the job. Alternatively, the host might have been temporarily low on memory + due to other processes running on the same machine. **NOTE:** This case will + lead to voting against the candidate (and possibly a dispute) if the retry is + still not successful. +2. **Syscall violations:** If the job attempts a system call that is blocked by + the sandbox's security policy, the job process is immediately killed and we + retry. **NOTE:** In the future, if we have a proper way to detect that the + job died due to a security violation, it might make sense not to retry in + this case. +3. **Artifact missing:** The prepared artifact might have been deleted due to operator error or some bug in the system. -3. **Job errors:** For example, the worker thread panicked for some - indeterminate reason, which may or may not be independent of the candidate or - PVF. -4. **Internal errors:** See "Internal Errors" section. In this case, after the +4. **Job errors:** For example, the job process panicked for some indeterminate + reason, which may or may not be independent of the candidate or PVF. +5. **Internal errors:** See "Internal Errors" section. In this case, after the retry we abstain from voting. ### Preparation timeouts @@ -159,16 +165,14 @@ data on the host machine. *Currently this is only supported on Linux.* - +### Restricting networking - +We also disable networking on PVF threads by disabling certain syscalls, such as +the creation of sockets. This prevents attackers from either downloading +payloads or communicating sensitive data from the validator's machine to the +outside world. - - - - - - +*Currently this is only supported on Linux.* ### Clearing env vars -- GitLab From b25d29a50247f284cde5b24e270b6db7b4a81e7e Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:22:42 +0100 Subject: [PATCH 547/633] cumulus-consensus-common: block import: `delayed_best_block` flag added (#2001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds the `delayed_best_block` flag to `ParachainBlockImport`. If not set, the `params.fork_choice` is not updated (to `ForkChoiceStrategy::Custom`) during the block import. When `delayed_best_block` is set to `false` all parachain blocks on the [longest fork](https://github.com/paritytech/polkadot-sdk/blob/552be4800d9e4b480f79a300fc531783e04be099/substrate/client/service/src/client/client.rs#L708-L709) will be notified as the best block, allowing transaction pool to be updated with every imported block. Otherwise imported blocks will not be notified as best blocks (`fork_choice=ForkChoiceStrategy::Custom(false)`), and transaction pool would be updated only with best block received from relay-chain. Improvement for: #1202 --------- Co-authored-by: Bastian Köcher --- cumulus/client/consensus/common/src/lib.rs | 39 +++++++++++++++----- cumulus/client/consensus/common/src/tests.rs | 6 ++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index 08bceabb2bd..cebe34e7ea5 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -111,12 +111,15 @@ impl ParachainConsensus for Box + Send + /// Parachain specific block import. /// -/// This is used to set `block_import_params.fork_choice` to `false` as long as the block origin is -/// not `NetworkInitialSync`. The best block for parachains is determined by the relay chain. -/// Meaning we will update the best block, as it is included by the relay-chain. +/// Specialized block import for parachains. It supports to delay setting the best block until the +/// relay chain has included a candidate in its best block. By default the delayed best block +/// setting is disabled. The block import also monitors the imported blocks and prunes by default if +/// there are too many blocks at the same height. Too many blocks at the same height can for example +/// happen if the relay chain is rejecting the parachain blocks in the validation. pub struct ParachainBlockImport { inner: BI, monitor: Option>>, + delayed_best_block: bool, } impl> ParachainBlockImport { @@ -141,13 +144,27 @@ impl> ParachainBlockImport let monitor = level_limit.map(|level_limit| SharedData::new(LevelMonitor::new(level_limit, backend))); - Self { inner, monitor } + Self { inner, monitor, delayed_best_block: false } + } + + /// Create a new instance which delays setting the best block. + /// + /// The number of leaves per level limit is set to `LevelLimit::Default`. + pub fn new_with_delayed_best_block(inner: BI, backend: Arc) -> Self { + Self { + delayed_best_block: true, + ..Self::new_with_limit(inner, backend, LevelLimit::Default) + } } } impl Clone for ParachainBlockImport { fn clone(&self) -> Self { - ParachainBlockImport { inner: self.inner.clone(), monitor: self.monitor.clone() } + ParachainBlockImport { + inner: self.inner.clone(), + monitor: self.monitor.clone(), + delayed_best_block: self.delayed_best_block, + } } } @@ -182,11 +199,13 @@ where params.finalized = true; } - // Best block is determined by the relay chain, or if we are doing the initial sync - // we import all blocks as new best. - params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom( - params.origin == sp_consensus::BlockOrigin::NetworkInitialSync, - )); + if self.delayed_best_block { + // Best block is determined by the relay chain, or if we are doing the initial sync + // we import all blocks as new best. + params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom( + params.origin == sp_consensus::BlockOrigin::NetworkInitialSync, + )); + } let maybe_lock = self.monitor.as_ref().map(|monitor_lock| { let mut monitor = monitor_lock.shared_data_locked(); diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 9658a0add79..597d1ab2acc 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -1124,7 +1124,8 @@ fn find_potential_parents_aligned_with_pending() { let backend = Arc::new(Backend::new_test(1000, 1)); let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); - let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + let mut para_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); let relay_parent = relay_hash_from_block_num(10); // Choose different relay parent for alternative chain to get new hashes. @@ -1279,7 +1280,8 @@ fn find_potential_parents_aligned_no_pending() { let backend = Arc::new(Backend::new_test(1000, 1)); let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); - let mut para_import = ParachainBlockImport::new(client.clone(), backend.clone()); + let mut para_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); let relay_parent = relay_hash_from_block_num(10); // Choose different relay parent for alternative chain to get new hashes. -- GitLab From b3841b6b71cd3707d80e90492059d1a2e3bd33a6 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 21 Nov 2023 16:09:40 +0100 Subject: [PATCH 548/633] Different XCM builders, default one requires fee payment (#2253) Adding on top of the new builder pattern for creating XCM programs, I'm adding some more APIs: ```rust let paying_fees: Xcm<()> = Xcm::builder() // Only allow paying for fees .withdraw_asset() // First instruction has to load the holding register .buy_execution() // Second instruction has to be `buy_execution` .build(); let paying_fees_invalid: Xcm<()> = Xcm::builder() .withdraw_asset() .build(); // Invalid, need to pay for fees let not_paying_fees: Xcm<()> = Xcm::builder_unpaid() .unpaid_execution() // Needed .withdraw_asset() .deposit_asset() .build(); let all_goes: Xcm<()> = Xcm::builder_unsafe() // You can do anything .withdraw_asset() .deposit_asset() .build(); ``` The invalid bits are because the methods don't even exist on the types that you'd want to call them on. --------- Co-authored-by: command-bot <> --- Cargo.lock | 1 + polkadot/xcm/procedural/Cargo.toml | 1 + .../xcm/procedural/src/builder_pattern.rs | 287 ++++++++++++++++-- polkadot/xcm/procedural/src/lib.rs | 6 +- .../xcm/procedural/tests/builder_pattern.rs | 81 +++++ polkadot/xcm/procedural/tests/ui.rs | 2 +- .../badly_formatted_attribute.rs | 32 ++ .../badly_formatted_attribute.stderr | 5 + .../buy_execution_named_fields.rs | 30 ++ .../buy_execution_named_fields.stderr | 5 + .../loads_holding_no_operands.rs | 32 ++ .../loads_holding_no_operands.stderr | 6 + .../ui/builder_pattern/no_buy_execution.rs | 29 ++ .../builder_pattern/no_buy_execution.stderr | 6 + .../ui/builder_pattern/no_unpaid_execution.rs | 29 ++ .../no_unpaid_execution.stderr | 6 + .../builder_pattern/unexpected_attribute.rs | 32 ++ .../unexpected_attribute.stderr | 5 + .../unpaid_execution_named_fields.rs | 30 ++ .../unpaid_execution_named_fields.stderr | 5 + .../wrong_target.rs} | 0 .../wrong_target.stderr} | 2 +- polkadot/xcm/src/v3/mod.rs | 4 + polkadot/xcm/xcm-simulator/example/src/lib.rs | 19 -- prdoc/pr_2253.prdoc | 24 ++ 25 files changed, 625 insertions(+), 54 deletions(-) create mode 100644 polkadot/xcm/procedural/tests/builder_pattern.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr rename polkadot/xcm/procedural/tests/ui/{builder_pattern.rs => builder_pattern/wrong_target.rs} (100%) rename polkadot/xcm/procedural/tests/ui/{builder_pattern.stderr => builder_pattern/wrong_target.stderr} (63%) create mode 100644 prdoc/pr_2253.prdoc diff --git a/Cargo.lock b/Cargo.lock index 697f232f971..88cefe7bbef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21512,6 +21512,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", + "staging-xcm", "syn 2.0.38", "trybuild", ] diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 33c2a94be0e..8ab27c91dae 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -18,3 +18,4 @@ Inflector = "0.11.4" [dev-dependencies] trybuild = { version = "1.0.74", features = ["diff"] } +xcm = { package = "staging-xcm", path = ".." } diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs index ebad54e972b..1cb795ea9b2 100644 --- a/polkadot/xcm/procedural/src/builder_pattern.rs +++ b/polkadot/xcm/procedural/src/builder_pattern.rs @@ -17,56 +17,83 @@ //! Derive macro for creating XCMs with a builder pattern use inflector::Inflector; -use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use syn::{ - parse_macro_input, Data, DeriveInput, Error, Expr, ExprLit, Fields, Lit, Meta, MetaNameValue, + Data, DataEnum, DeriveInput, Error, Expr, ExprLit, Fields, Ident, Lit, Meta, MetaNameValue, + Result, Variant, }; -pub fn derive(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let builder_impl = match &input.data { - Data::Enum(data_enum) => generate_methods_for_enum(input.ident, data_enum), - _ => - return Error::new_spanned(&input, "Expected the `Instruction` enum") - .to_compile_error() - .into(), +pub fn derive(input: DeriveInput) -> Result { + let data_enum = match &input.data { + Data::Enum(data_enum) => data_enum, + _ => return Err(Error::new_spanned(&input, "Expected the `Instruction` enum")), }; + let builder_raw_impl = generate_builder_raw_impl(&input.ident, data_enum); + let builder_impl = generate_builder_impl(&input.ident, data_enum)?; + let builder_unpaid_impl = generate_builder_unpaid_impl(&input.ident, data_enum)?; let output = quote! { - pub struct XcmBuilder(Vec>); + /// A trait for types that track state inside the XcmBuilder + pub trait XcmBuilderState {} + + /// Access to all the instructions + pub enum AnythingGoes {} + /// You need to pay for execution + pub enum PaymentRequired {} + /// The holding register was loaded, now to buy execution + pub enum LoadedHolding {} + /// Need to explicitly state it won't pay for fees + pub enum ExplicitUnpaidRequired {} + + impl XcmBuilderState for AnythingGoes {} + impl XcmBuilderState for PaymentRequired {} + impl XcmBuilderState for LoadedHolding {} + impl XcmBuilderState for ExplicitUnpaidRequired {} + + /// Type used to build XCM programs + pub struct XcmBuilder { + pub(crate) instructions: Vec>, + pub state: core::marker::PhantomData, + } + impl Xcm { - pub fn builder() -> XcmBuilder { - XcmBuilder::(Vec::new()) + pub fn builder() -> XcmBuilder { + XcmBuilder:: { + instructions: Vec::new(), + state: core::marker::PhantomData, + } + } + pub fn builder_unpaid() -> XcmBuilder { + XcmBuilder:: { + instructions: Vec::new(), + state: core::marker::PhantomData, + } + } + pub fn builder_unsafe() -> XcmBuilder { + XcmBuilder:: { + instructions: Vec::new(), + state: core::marker::PhantomData, + } } } #builder_impl + #builder_unpaid_impl + #builder_raw_impl }; - output.into() + Ok(output) } -fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> TokenStream2 { +fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> TokenStream2 { let methods = data_enum.variants.iter().map(|variant| { let variant_name = &variant.ident; let method_name_string = &variant_name.to_string().to_snake_case(); let method_name = syn::Ident::new(&method_name_string, variant_name.span()); - let docs: Vec<_> = variant - .attrs - .iter() - .filter_map(|attr| match &attr.meta { - Meta::NameValue(MetaNameValue { - value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }), - .. - }) if attr.path().is_ident("doc") => Some(literal.value()), - _ => None, - }) - .map(|doc| syn::parse_str::(&format!("/// {}", doc)).unwrap()) - .collect(); + let docs = get_doc_comments(&variant); let method = match &variant.fields { Fields::Unit => { quote! { pub fn #method_name(mut self) -> Self { - self.0.push(#name::::#variant_name); + self.instructions.push(#name::::#variant_name); self } } @@ -81,7 +108,7 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); quote! { pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self { - self.0.push(#name::::#variant_name(#(#arg_names),*)); + self.instructions.push(#name::::#variant_name(#(#arg_names),*)); self } } @@ -91,7 +118,7 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); quote! { pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self { - self.0.push(#name::::#variant_name { #(#arg_names),* }); + self.instructions.push(#name::::#variant_name { #(#arg_names),* }); self } } @@ -103,13 +130,209 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok } }); let output = quote! { - impl XcmBuilder { + impl XcmBuilder { #(#methods)* pub fn build(self) -> Xcm { - Xcm(self.0) + Xcm(self.instructions) } } }; output } + +fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result { + // We first require an instruction that load the holding register + let load_holding_variants = data_enum + .variants + .iter() + .map(|variant| { + let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta { + Meta::List(ref list) => { + return list.path.is_ident("builder"); + }, + _ => false, + }); + let builder_attr = match maybe_builder_attr { + Some(builder) => builder.clone(), + None => return Ok(None), /* It's not going to be an instruction that loads the + * holding register */ + }; + let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") }; + let inner_ident: Ident = syn::parse2(list.tokens.clone().into()).map_err(|_| { + Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`") + })?; + let ident_to_match: Ident = syn::parse_quote!(loads_holding); + if inner_ident == ident_to_match { + Ok(Some(variant)) + } else { + Err(Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`")) + } + }) + .collect::>>()?; + + let load_holding_methods = load_holding_variants + .into_iter() + .flatten() + .map(|variant| { + let variant_name = &variant.ident; + let method_name_string = &variant_name.to_string().to_snake_case(); + let method_name = syn::Ident::new(&method_name_string, variant_name.span()); + let docs = get_doc_comments(&variant); + let method = match &variant.fields { + Fields::Unnamed(fields) => { + let arg_names: Vec<_> = fields + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("arg{}", index)) + .collect(); + let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); + quote! { + #(#docs)* + pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder { + let mut new_instructions = self.instructions; + new_instructions.push(#name::::#variant_name(#(#arg_names),*)); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + }, + Fields::Named(fields) => { + let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); + let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); + quote! { + #(#docs)* + pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder { + let mut new_instructions = self.instructions; + new_instructions.push(#name::::#variant_name { #(#arg_names),* }); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + }, + _ => + return Err(Error::new_spanned( + &variant, + "Instructions that load the holding register should take operands", + )), + }; + Ok(method) + }) + .collect::, _>>()?; + + let first_impl = quote! { + impl XcmBuilder { + #(#load_holding_methods)* + } + }; + + // Then we require fees to be paid + let buy_execution_method = data_enum + .variants + .iter() + .find(|variant| variant.ident.to_string() == "BuyExecution") + .map_or( + Err(Error::new_spanned(&data_enum.variants, "No BuyExecution instruction")), + |variant| { + let variant_name = &variant.ident; + let method_name_string = &variant_name.to_string().to_snake_case(); + let method_name = syn::Ident::new(&method_name_string, variant_name.span()); + let docs = get_doc_comments(&variant); + let fields = match &variant.fields { + Fields::Named(fields) => { + let arg_names: Vec<_> = + fields.named.iter().map(|field| &field.ident).collect(); + let arg_types: Vec<_> = + fields.named.iter().map(|field| &field.ty).collect(); + quote! { + #(#docs)* + pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder { + let mut new_instructions = self.instructions; + new_instructions.push(#name::::#variant_name { #(#arg_names),* }); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + }, + _ => + return Err(Error::new_spanned( + &variant, + "BuyExecution should have named fields", + )), + }; + Ok(fields) + }, + )?; + + let second_impl = quote! { + impl XcmBuilder { + #buy_execution_method + } + }; + + let output = quote! { + #first_impl + #second_impl + }; + + Ok(output) +} + +fn generate_builder_unpaid_impl(name: &Ident, data_enum: &DataEnum) -> Result { + let unpaid_execution_variant = data_enum + .variants + .iter() + .find(|variant| variant.ident.to_string() == "UnpaidExecution") + .ok_or(Error::new_spanned(&data_enum.variants, "No UnpaidExecution instruction"))?; + let unpaid_execution_ident = &unpaid_execution_variant.ident; + let unpaid_execution_method_name = Ident::new( + &unpaid_execution_ident.to_string().to_snake_case(), + unpaid_execution_ident.span(), + ); + let docs = get_doc_comments(&unpaid_execution_variant); + let fields = match &unpaid_execution_variant.fields { + Fields::Named(fields) => fields, + _ => + return Err(Error::new_spanned( + &unpaid_execution_variant, + "UnpaidExecution should have named fields", + )), + }; + let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); + let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); + Ok(quote! { + impl XcmBuilder { + #(#docs)* + pub fn #unpaid_execution_method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder { + let mut new_instructions = self.instructions; + new_instructions.push(#name::::#unpaid_execution_ident { #(#arg_names),* }); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + }) +} + +fn get_doc_comments(variant: &Variant) -> Vec { + variant + .attrs + .iter() + .filter_map(|attr| match &attr.meta { + Meta::NameValue(MetaNameValue { + value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }), + .. + }) if attr.path().is_ident("doc") => Some(literal.value()), + _ => None, + }) + .map(|doc| syn::parse_str::(&format!("/// {}", doc)).unwrap()) + .collect() +} diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs index 83cc6cdf98f..7600e817d0e 100644 --- a/polkadot/xcm/procedural/src/lib.rs +++ b/polkadot/xcm/procedural/src/lib.rs @@ -17,6 +17,7 @@ //! Procedural macros used in XCM. use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; mod builder_pattern; mod v2; @@ -56,7 +57,10 @@ pub fn impl_conversion_functions_for_junctions_v3(input: TokenStream) -> TokenSt /// .buy_execution(fees, weight_limit) /// .deposit_asset(assets, beneficiary) /// .build(); -#[proc_macro_derive(Builder)] +#[proc_macro_derive(Builder, attributes(builder))] pub fn derive_builder(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); builder_pattern::derive(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } diff --git a/polkadot/xcm/procedural/tests/builder_pattern.rs b/polkadot/xcm/procedural/tests/builder_pattern.rs new file mode 100644 index 00000000000..eab9d67121f --- /dev/null +++ b/polkadot/xcm/procedural/tests/builder_pattern.rs @@ -0,0 +1,81 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test the methods generated by the Builder derive macro. +//! Tests directly on the actual Xcm struct and Instruction enum. + +use xcm::latest::prelude::*; + +#[test] +fn builder_pattern_works() { + let asset: MultiAsset = (Here, 100u128).into(); + let beneficiary: MultiLocation = AccountId32 { id: [0u8; 32], network: None }.into(); + let message: Xcm<()> = Xcm::builder() + .receive_teleported_asset(asset.clone().into()) + .buy_execution(asset.clone(), Unlimited) + .deposit_asset(asset.clone().into(), beneficiary) + .build(); + assert_eq!( + message, + Xcm(vec![ + ReceiveTeleportedAsset(asset.clone().into()), + BuyExecution { fees: asset.clone(), weight_limit: Unlimited }, + DepositAsset { assets: asset.into(), beneficiary }, + ]) + ); +} + +#[test] +fn default_builder_requires_buy_execution() { + let asset: MultiAsset = (Here, 100u128).into(); + let beneficiary: MultiLocation = AccountId32 { id: [0u8; 32], network: None }.into(); + // This is invalid, since it doesn't pay for fees. + // This is enforced by the runtime, because the build() method doesn't exist + // on the resulting type. + // let message: Xcm<()> = Xcm::builder() + // .withdraw_asset(asset.clone().into()) + // .deposit_asset(asset.into(), beneficiary) + // .build(); + + // To be able to do that, we need to use the explicitly unpaid variant + let message: Xcm<()> = Xcm::builder_unpaid() + .unpaid_execution(Unlimited, None) + .withdraw_asset(asset.clone().into()) + .deposit_asset(asset.clone().into(), beneficiary) + .build(); // This works + assert_eq!( + message, + Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + WithdrawAsset(asset.clone().into()), + DepositAsset { assets: asset.clone().into(), beneficiary }, + ]) + ); + + // The other option doesn't have any limits whatsoever, so it should + // only be used when you really know what you're doing. + let message: Xcm<()> = Xcm::builder_unsafe() + .withdraw_asset(asset.clone().into()) + .deposit_asset(asset.clone().into(), beneficiary) + .build(); + assert_eq!( + message, + Xcm(vec![ + WithdrawAsset(asset.clone().into()), + DepositAsset { assets: asset.clone().into(), beneficiary }, + ]) + ); +} diff --git a/polkadot/xcm/procedural/tests/ui.rs b/polkadot/xcm/procedural/tests/ui.rs index a6ec35d0862..a30f4d7dee5 100644 --- a/polkadot/xcm/procedural/tests/ui.rs +++ b/polkadot/xcm/procedural/tests/ui.rs @@ -28,5 +28,5 @@ fn ui() { std::env::set_var("SKIP_WASM_BUILD", "1"); let t = trybuild::TestCases::new(); - t.compile_fail("tests/ui/*.rs"); + t.compile_fail("tests/ui/**/*.rs"); } diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.rs new file mode 100644 index 00000000000..3a103f3ddc4 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.rs @@ -0,0 +1,32 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when using a badly formatted attribute. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + #[builder(funds_holding = 2)] + WithdrawAsset(u128), + BuyExecution { fees: u128 }, + UnpaidExecution { weight_limit: (u32, u32) }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr new file mode 100644 index 00000000000..978faf2e868 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr @@ -0,0 +1,5 @@ +error: Expected `builder(loads_holding)` + --> tests/ui/builder_pattern/badly_formatted_attribute.rs:25:5 + | +25 | #[builder(funds_holding = 2)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs new file mode 100644 index 00000000000..dc5c679a96e --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs @@ -0,0 +1,30 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when the `BuyExecution` instruction doesn't take named fields. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + BuyExecution(u128), + UnpaidExecution { weight_limit: (u32, u32) }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr new file mode 100644 index 00000000000..dc8246770ba --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr @@ -0,0 +1,5 @@ +error: BuyExecution should have named fields + --> tests/ui/builder_pattern/buy_execution_named_fields.rs:25:5 + | +25 | BuyExecution(u128), + | ^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs new file mode 100644 index 00000000000..070f0be6bac --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs @@ -0,0 +1,32 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when an instruction that loads the holding register doesn't take operands. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + #[builder(loads_holding)] + WithdrawAsset, + BuyExecution { fees: u128 }, + UnpaidExecution { weight_limit: (u32, u32) }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr new file mode 100644 index 00000000000..0358a35ad3d --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr @@ -0,0 +1,6 @@ +error: Instructions that load the holding register should take operands + --> tests/ui/builder_pattern/loads_holding_no_operands.rs:25:5 + | +25 | / #[builder(loads_holding)] +26 | | WithdrawAsset, + | |_________________^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs new file mode 100644 index 00000000000..1ed8dd38cba --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when there's no `BuyExecution` instruction. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + UnpaidExecution { weight_limit: (u32, u32) }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr new file mode 100644 index 00000000000..d8798c8223f --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr @@ -0,0 +1,6 @@ +error: No BuyExecution instruction + --> tests/ui/builder_pattern/no_buy_execution.rs:25:5 + | +25 | / UnpaidExecution { weight_limit: (u32, u32) }, +26 | | Transact { call: Call }, + | |____________________________^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.rs new file mode 100644 index 00000000000..d542102d2d3 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when there's no `UnpaidExecution` instruction. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + BuyExecution { fees: u128 }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.stderr new file mode 100644 index 00000000000..c8c0748da72 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_unpaid_execution.stderr @@ -0,0 +1,6 @@ +error: No UnpaidExecution instruction + --> tests/ui/builder_pattern/no_unpaid_execution.rs:25:5 + | +25 | / BuyExecution { fees: u128 }, +26 | | Transact { call: Call }, + | |____________________________^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs new file mode 100644 index 00000000000..5808ec571ce --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs @@ -0,0 +1,32 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when using wrong attribute. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + #[builder(funds_holding)] + WithdrawAsset(u128), + BuyExecution { fees: u128 }, + UnpaidExecution { weight_limit: (u32, u32) }, + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr new file mode 100644 index 00000000000..1ff9d185136 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr @@ -0,0 +1,5 @@ +error: Expected `builder(loads_holding)` + --> tests/ui/builder_pattern/unexpected_attribute.rs:25:5 + | +25 | #[builder(funds_holding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs new file mode 100644 index 00000000000..bb98d603fd9 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs @@ -0,0 +1,30 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when the `BuyExecution` instruction doesn't take named fields. + +use xcm_procedural::Builder; + +struct Xcm(pub Vec>); + +#[derive(Builder)] +enum Instruction { + BuyExecution { fees: u128 }, + UnpaidExecution(u32, u32), + Transact { call: Call }, +} + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr new file mode 100644 index 00000000000..0a3c0a40a33 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr @@ -0,0 +1,5 @@ +error: UnpaidExecution should have named fields + --> tests/ui/builder_pattern/unpaid_execution_named_fields.rs:26:5 + | +26 | UnpaidExecution(u32, u32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/wrong_target.rs similarity index 100% rename from polkadot/xcm/procedural/tests/ui/builder_pattern.rs rename to polkadot/xcm/procedural/tests/ui/builder_pattern/wrong_target.rs diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/wrong_target.stderr similarity index 63% rename from polkadot/xcm/procedural/tests/ui/builder_pattern.stderr rename to polkadot/xcm/procedural/tests/ui/builder_pattern/wrong_target.stderr index 439b40f31ca..007aa0b5ff3 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern.stderr +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/wrong_target.stderr @@ -1,5 +1,5 @@ error: Expected the `Instruction` enum - --> tests/ui/builder_pattern.rs:23:1 + --> tests/ui/builder_pattern/wrong_target.rs:23:1 | 23 | struct SomeStruct; | ^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 4217528f227..bbdd504ceb0 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -426,6 +426,7 @@ pub enum Instruction { /// Kind: *Command*. /// /// Errors: + #[builder(loads_holding)] WithdrawAsset(MultiAssets), /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` @@ -439,6 +440,7 @@ pub enum Instruction { /// Kind: *Trusted Indication*. /// /// Errors: + #[builder(loads_holding)] ReserveAssetDeposited(MultiAssets), /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should @@ -452,6 +454,7 @@ pub enum Instruction { /// Kind: *Trusted Indication*. /// /// Errors: + #[builder(loads_holding)] ReceiveTeleportedAsset(MultiAssets), /// Respond with information that the local system is expecting. @@ -776,6 +779,7 @@ pub enum Instruction { /// Kind: *Command* /// /// Errors: + #[builder(loads_holding)] ClaimAsset { assets: MultiAssets, ticket: MultiLocation }, /// Always throws an error of type `Trap`. diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index 03e7c19a914..85b8ad1c5cb 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -649,23 +649,4 @@ mod tests { ); }); } - - #[test] - fn builder_pattern_works() { - let asset: MultiAsset = (Here, 100u128).into(); - let beneficiary: MultiLocation = AccountId32 { id: [0u8; 32], network: None }.into(); - let message: Xcm<()> = Xcm::builder() - .withdraw_asset(asset.clone().into()) - .buy_execution(asset.clone(), Unlimited) - .deposit_asset(asset.clone().into(), beneficiary) - .build(); - assert_eq!( - message, - Xcm(vec![ - WithdrawAsset(asset.clone().into()), - BuyExecution { fees: asset.clone(), weight_limit: Unlimited }, - DepositAsset { assets: asset.into(), beneficiary }, - ]) - ); - } } diff --git a/prdoc/pr_2253.prdoc b/prdoc/pr_2253.prdoc new file mode 100644 index 00000000000..398b0a29066 --- /dev/null +++ b/prdoc/pr_2253.prdoc @@ -0,0 +1,24 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Different builder pattern constructors for XCM + +doc: + - audience: Core Dev + description: | + The `builder()` constructor for XCM programs now only allows building messages that pay for fees, + i.e. messages that would pass the `AllowTopLevelPaidExecutionFrom` barrier. + Another constructor, `builder_unpaid()` requires an explicit `UnpaidExecution` instruction before + anything else. + For building messages without any restriction, `builder_unsafe` can be used. + This has been named like that since in general the other two should be used instead, but it's okay + to use it for teaching purposes or for experimenting. + +migrations: + db: [] + + runtime: [] + +crates: [] + +host_functions: [] -- GitLab From f5ad32e406e5108ea87f05a0b99406b80ed3226c Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Tue, 21 Nov 2023 16:49:47 +0100 Subject: [PATCH 549/633] added action to pass review bot on merge queue (#2414) This action will trigger when a merge queue is created and will add a positive status check under the `review-bot` account, allowing the PR to pass the required check for the merge. --------- Co-authored-by: Chevdor --- .github/workflows/merge-queue.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/merge-queue.yml diff --git a/.github/workflows/merge-queue.yml b/.github/workflows/merge-queue.yml new file mode 100644 index 00000000000..f3fb7765ca6 --- /dev/null +++ b/.github/workflows/merge-queue.yml @@ -0,0 +1,24 @@ +name: Merge-Queue + +on: + merge_group: + +jobs: + trigger-merge-queue-action: + runs-on: ubuntu-latest + environment: master + steps: + - name: Generate token + id: app_token + uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0 + with: + app_id: ${{ secrets.REVIEW_APP_ID }} + private_key: ${{ secrets.REVIEW_APP_KEY }} + - name: Add Merge Queue status check + uses: billyjbryant/create-status-check@3e6fa0ac599d10d9588cf9516ca4330ef669b858 # v2 + with: + authToken: ${{ steps.app_token.outputs.token }} + context: 'review-bot' + description: 'PRs for merge queue gets approved' + state: 'success' + sha: ${{ github.event.merge_group.head_commit.id }} -- GitLab From 50811d6b424185e1e6c0762a8b1c95db893c6750 Mon Sep 17 00:00:00 2001 From: Sophia Gold Date: Tue, 21 Nov 2023 11:34:05 -0500 Subject: [PATCH 550/633] Update tick collator for async backing (#1497) This updates the tick runtime and polkadot-parachain collator to use async backing. --- Cargo.lock | 1 + .../testing/rococo-parachain/Cargo.toml | 2 + .../testing/rococo-parachain/src/lib.rs | 47 ++++++++++++------- cumulus/polkadot-parachain/src/service.rs | 34 +++++++++----- 4 files changed, 55 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88cefe7bbef..903e9463cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14530,6 +14530,7 @@ dependencies = [ "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-utility", "frame-benchmarking", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 5e9d347a25d..08fa8b69127 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -52,6 +52,7 @@ cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } cumulus-ping = { path = "../../../pallets/ping", default-features = false } +cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -70,6 +71,7 @@ std = [ "cumulus-pallet-xcm/std", "cumulus-pallet-xcmp-queue/std", "cumulus-ping/std", + "cumulus-primitives-aura/std", "cumulus-primitives-core/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 6df00d43e8d..965fb0d6adc 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -22,13 +22,13 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, Hash as HashT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; @@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { state_version: 0, }; -pub const MILLISECS_PER_BLOCK: u64 = 12000; +pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; @@ -143,18 +143,18 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for .5 seconds of compute with a 12 second average block time. +/// We allow for 2 seconds of compute with a 6 second average block time. const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), + WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, ); /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included /// into the relay chain. -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; /// How many parachain blocks are processed by the relay chain per parent. Limits the /// number of blocks authored per slot. -const BLOCK_PROCESSING_VELOCITY: u32 = 1; +const BLOCK_PROCESSING_VELOCITY: u32 = 2; /// Relay chain slot duration, in milliseconds. const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; @@ -277,6 +277,13 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } +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 WeightInfo = (); type RuntimeEvent = RuntimeEvent; @@ -287,13 +294,8 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + type ConsensusHook = ConsensusHook; } impl parachain_info::Config for Runtime {} @@ -584,9 +586,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; } construct_runtime! { @@ -624,7 +626,7 @@ pub type Balance = u128; /// Index of a transaction in the chain. pub type Nonce = u32; /// A hash of some data used by the chain. -pub type Hash = sp_core::H256; +pub type Hash = ::Output; /// An index to a block. pub type BlockNumber = u32; /// The address format for describing accounts. @@ -751,7 +753,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 { @@ -824,6 +826,15 @@ impl_runtime_apis! { build_config::(config) } } + + 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) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 3884fce246c..f580835db55 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -590,6 +590,7 @@ where CollatorPair, OverseerHandle, Arc>) + Send + Sync>, + Arc, ) -> Result<(), sc_service::Error>, { let parachain_config = prepare_node_config(parachain_config); @@ -723,6 +724,7 @@ where collator_key.expect("Command line arguments do not allow this. qed"), overseer_handle, announce_block, + backend.clone(), )?; } @@ -983,7 +985,8 @@ pub async fn start_rococo_parachain_node( para_id, collator_key, overseer_handle, - announce_block| { + announce_block, + backend| { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -1002,11 +1005,15 @@ pub async fn start_rococo_parachain_node( client.clone(), ); - let params = BasicAuraParams { + let params = AuraParams { create_inherent_data_providers: move |_, ()| async move { Ok(()) }, block_import, - para_client: client, + para_client: client.clone(), + para_backend: backend.clone(), relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, sync_oracle, keystore, collator_key, @@ -1016,12 +1023,10 @@ pub async fn start_rococo_parachain_node( relay_chain_slot_duration, proposer, collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: None, + authoring_duration: Duration::from_millis(1500), }; - let fut = basic_aura::run::< + let fut = aura::run::< Block, sp_consensus_aura::sr25519::AuthorityPair, _, @@ -1031,6 +1036,8 @@ pub async fn start_rococo_parachain_node( _, _, _, + _, + _, >(params); task_manager.spawn_essential_handle().spawn("aura", None, fut); @@ -1376,7 +1383,8 @@ where para_id, collator_key, overseer_handle, - announce_block| { + announce_block, + _backend| { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -1471,7 +1479,8 @@ where para_id, collator_key, overseer_handle, - announce_block| { + announce_block, + _backend| { let relay_chain_interface2 = relay_chain_interface.clone(); let collator_service = CollatorService::new( @@ -1642,7 +1651,7 @@ where 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()) + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) }, sync_oracle, keystore, @@ -1713,6 +1722,7 @@ where CollatorPair, OverseerHandle, Arc>) + Send + Sync>, + Arc, ) -> Result<(), sc_service::Error>, { let parachain_config = prepare_node_config(parachain_config); @@ -1845,6 +1855,7 @@ where collator_key.expect("Command line arguments do not allow this. qed"), overseer_handle, announce_block, + backend.clone(), )?; } @@ -1923,7 +1934,8 @@ pub async fn start_contracts_rococo_node( para_id, collator_key, overseer_handle, - announce_block| { + announce_block, + _backend| { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( -- GitLab From 2183669d05f9b510f979a0cc3c7847707bacba2e Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:03:55 +0100 Subject: [PATCH 551/633] cumulus-test-service: block import fix (#2430) This is follow-up for: https://github.com/paritytech/polkadot-sdk/pull/2001 Block import queue for `test-parachain` (`cumulus-test-service`) shall use delayed best block feature. This should fixed broken zombienet tests. --- cumulus/test/service/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 6fd3e4d43d7..4d4c60d1bda 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -211,7 +211,8 @@ pub fn new_partial( sc_service::new_full_parts::(config, None, executor)?; let client = Arc::new(client); - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + let block_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); let registry = config.prometheus_registry(); -- GitLab From 7a32f4be48e514eccfbe5f8d2c2366c049cc4e3d Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Wed, 22 Nov 2023 16:22:28 +0700 Subject: [PATCH 552/633] Deprecate `RewardDestination::Controller` (#2380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecates `RewardDestination::Controller` variant. - [x] `RewardDestination::Controller` annotated with `#[deprecated]`. - [x] `Controller` variant is now handled the same way as `Stash` in `payout_stakers`. - [x] `set_payee` errors if `RewardDestination::Controller` is provided. - [x] Added `update_payee` call to lazily migrate `RewardDestination::Controller` `Payee` storage entries to `RewardDestination::Account(controller)` . - [x] `payout_stakers_dead_controller` has been removed from benches & weights - was not used. - [x] Tests no longer use `RewardDestination::Controller`. --------- Co-authored-by: command-bot <> Co-authored-by: Gonçalo Pestana Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> --- .../westend/src/weights/pallet_staking.rs | 238 ++++----- substrate/frame/staking/src/benchmarking.rs | 54 +- substrate/frame/staking/src/lib.rs | 6 +- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 13 +- substrate/frame/staking/src/pallet/mod.rs | 45 +- substrate/frame/staking/src/tests.rs | 203 ++++---- substrate/frame/staking/src/weights.rs | 468 ++++++++---------- 8 files changed, 475 insertions(+), 554 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 3c4542c6d6f..87b603621e8 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 @@ -62,8 +62,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `894` // Estimated: `4764` - // Minimum execution time: 39_950_000 picoseconds. - Weight::from_parts(41_107_000, 0) + // Minimum execution time: 38_052_000 picoseconds. + Weight::from_parts(39_303_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) @@ -84,8 +84,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 83_828_000 picoseconds. - Weight::from_parts(85_733_000, 0) + // Minimum execution time: 81_690_000 picoseconds. + Weight::from_parts(83_889_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) @@ -112,8 +112,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 89_002_000 picoseconds. - Weight::from_parts(91_556_000, 0) + // Minimum execution time: 84_409_000 picoseconds. + Weight::from_parts(87_330_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -133,11 +133,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1075` // Estimated: `4764` - // Minimum execution time: 40_839_000 picoseconds. - Weight::from_parts(42_122_428, 0) + // Minimum execution time: 39_770_000 picoseconds. + Weight::from_parts(40_828_632, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 884 - .saturating_add(Weight::from_parts(46_036, 0).saturating_mul(s.into())) + // Standard Error: 824 + .saturating_add(Weight::from_parts(51_107, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -174,11 +174,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 84_244_000 picoseconds. - Weight::from_parts(91_199_964, 0) + // Minimum execution time: 82_500_000 picoseconds. + Weight::from_parts(90_099_121, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_381 - .saturating_add(Weight::from_parts(1_327_289, 0).saturating_mul(s.into())) + // Standard Error: 3_280 + .saturating_add(Weight::from_parts(1_273_212, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -210,8 +210,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 49_693_000 picoseconds. - Weight::from_parts(50_814_000, 0) + // Minimum execution time: 48_236_000 picoseconds. + Weight::from_parts(49_518_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) @@ -225,11 +225,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1243 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_140_000 picoseconds. - Weight::from_parts(28_309_627, 0) + // Minimum execution time: 28_280_000 picoseconds. + Weight::from_parts(29_182_740, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 5_780 - .saturating_add(Weight::from_parts(6_509_869, 0).saturating_mul(k.into())) + // Standard Error: 6_102 + .saturating_add(Weight::from_parts(6_412_107, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -262,11 +262,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 61_377_000 picoseconds. - Weight::from_parts(58_805_232, 0) + // Minimum execution time: 59_846_000 picoseconds. + Weight::from_parts(58_029_857, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 14_197 - .saturating_add(Weight::from_parts(4_090_197, 0).saturating_mul(n.into())) + // Standard Error: 15_967 + .saturating_add(Weight::from_parts(3_898_764, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -290,8 +290,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1581` // Estimated: `6248` - // Minimum execution time: 52_736_000 picoseconds. - Weight::from_parts(54_573_000, 0) + // Minimum execution time: 51_223_000 picoseconds. + Weight::from_parts(52_310_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) @@ -306,12 +306,28 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 16_496_000 picoseconds. - Weight::from_parts(17_045_000, 0) + // Minimum execution time: 15_762_000 picoseconds. + Weight::from_parts(16_381_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + /// 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:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + fn update_payee() -> Weight { + // Proof Size summary in bytes: + // Measured: `932` + // Estimated: `4556` + // Minimum execution time: 21_904_000 picoseconds. + Weight::from_parts(22_373_000, 0) + .saturating_add(Weight::from_parts(0, 4556)) + .saturating_add(T::DbWeight::get().reads(3)) + .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:1 w:2) @@ -320,8 +336,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 19_339_000 picoseconds. - Weight::from_parts(20_187_000, 0) + // Minimum execution time: 18_869_000 picoseconds. + Weight::from_parts(19_422_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -332,8 +348,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_340_000 picoseconds. - Weight::from_parts(2_551_000, 0) + // Minimum execution time: 2_205_000 picoseconds. + Weight::from_parts(2_320_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -343,8 +359,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_483_000 picoseconds. - Weight::from_parts(8_101_000, 0) + // Minimum execution time: 7_179_000 picoseconds. + Weight::from_parts(7_843_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -354,8 +370,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_773_000 picoseconds. - Weight::from_parts(8_610_000, 0) + // Minimum execution time: 7_206_000 picoseconds. + Weight::from_parts(7_829_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -365,8 +381,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_577_000 picoseconds. - Weight::from_parts(7_937_000, 0) + // Minimum execution time: 7_414_000 picoseconds. + Weight::from_parts(7_770_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +393,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_522_000 picoseconds. - Weight::from_parts(2_735_307, 0) + // Minimum execution time: 2_256_000 picoseconds. + Weight::from_parts(2_645_840, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 38 - .saturating_add(Weight::from_parts(10_553, 0).saturating_mul(v.into())) + // Standard Error: 37 + .saturating_add(Weight::from_parts(10_207, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) @@ -417,11 +433,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_547_000 picoseconds. - Weight::from_parts(89_373_781, 0) + // Minimum execution time: 81_032_000 picoseconds. + Weight::from_parts(88_297_596, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_589 - .saturating_add(Weight::from_parts(1_258_878, 0).saturating_mul(s.into())) + // Standard Error: 3_070 + .saturating_add(Weight::from_parts(1_207_207, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -434,56 +450,14 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 134_619_000 picoseconds. - Weight::from_parts(1_194_949_665, 0) + // Minimum execution time: 131_456_000 picoseconds. + Weight::from_parts(935_254_517, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 76_719 - .saturating_add(Weight::from_parts(6_455_953, 0).saturating_mul(s.into())) + // Standard Error: 57_806 + .saturating_add(Weight::from_parts(4_823_189, 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::ErasStakersOverview` (r:1 w:0) - /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:65 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:66 w:66) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ClaimedRewards` (r:1 w:1) - /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) - /// Proof: `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:65 w:0) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 64]`. - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `6895 + n * (156 ±0)` - // Estimated: `9802 + n * (2603 ±0)` - // Minimum execution time: 114_338_000 picoseconds. - Weight::from_parts(138_518_124, 0) - .saturating_add(Weight::from_parts(0, 9802)) - // Standard Error: 53_621 - .saturating_add(Weight::from_parts(25_676_781, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) - .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::Bonded` (r:65 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:65 w:65) @@ -516,12 +490,12 @@ impl pallet_staking::WeightInfo for WeightInfo { fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±3)` - // Minimum execution time: 132_719_000 picoseconds. - Weight::from_parts(170_505_880, 0) + // Estimated: `10779 + n * (3774 ±0)` + // Minimum execution time: 129_233_000 picoseconds. + Weight::from_parts(165_096_042, 0) .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 32_527 - .saturating_add(Weight::from_parts(42_453_136, 0).saturating_mul(n.into())) + // Standard Error: 29_598 + .saturating_add(Weight::from_parts(40_716_425, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -545,11 +519,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 78_438_000 picoseconds. - Weight::from_parts(81_774_734, 0) + // Minimum execution time: 77_223_000 picoseconds. + Weight::from_parts(80_026_259, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_706 - .saturating_add(Weight::from_parts(51_358, 0).saturating_mul(l.into())) + // Standard Error: 4_493 + .saturating_add(Weight::from_parts(52_909, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -584,11 +558,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_129_000 picoseconds. - Weight::from_parts(94_137_611, 0) + // Minimum execution time: 89_871_000 picoseconds. + Weight::from_parts(92_313_331, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 4_141 - .saturating_add(Weight::from_parts(1_283_823, 0).saturating_mul(s.into())) + // Standard Error: 3_321 + .saturating_add(Weight::from_parts(1_243_347, 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()))) @@ -634,13 +608,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 527_896_000 picoseconds. - Weight::from_parts(533_325_000, 0) + // Minimum execution time: 518_819_000 picoseconds. + Weight::from_parts(522_108_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_064_813 - .saturating_add(Weight::from_parts(68_484_503, 0).saturating_mul(v.into())) - // Standard Error: 205_747 - .saturating_add(Weight::from_parts(18_833_735, 0).saturating_mul(n.into())) + // Standard Error: 1_987_848 + .saturating_add(Weight::from_parts(64_855_377, 0).saturating_mul(v.into())) + // Standard Error: 198_078 + .saturating_add(Weight::from_parts(18_343_485, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -671,13 +645,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 35_302_472_000 picoseconds. - Weight::from_parts(35_651_169_000, 0) + // Minimum execution time: 34_976_277_000 picoseconds. + Weight::from_parts(35_245_501_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 412_098 - .saturating_add(Weight::from_parts(5_172_265, 0).saturating_mul(v.into())) - // Standard Error: 412_098 - .saturating_add(Weight::from_parts(4_142_772, 0).saturating_mul(n.into())) + // Standard Error: 386_461 + .saturating_add(Weight::from_parts(5_145_210, 0).saturating_mul(v.into())) + // Standard Error: 386_461 + .saturating_add(Weight::from_parts(3_762_623, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -694,11 +668,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_522_650_000 picoseconds. - Weight::from_parts(97_022_833, 0) + // Minimum execution time: 2_577_411_000 picoseconds. + Weight::from_parts(86_073_486, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 6_751 - .saturating_add(Weight::from_parts(4_990_018, 0).saturating_mul(v.into())) + // Standard Error: 8_363 + .saturating_add(Weight::from_parts(5_074_828, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -719,8 +693,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_833_000 picoseconds. - Weight::from_parts(4_108_000, 0) + // Minimum execution time: 3_539_000 picoseconds. + Weight::from_parts(3_903_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -740,8 +714,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_520_000 picoseconds. - Weight::from_parts(3_686_000, 0) + // Minimum execution time: 3_244_000 picoseconds. + Weight::from_parts(3_450_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -769,8 +743,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1704` // Estimated: `6248` - // Minimum execution time: 63_983_000 picoseconds. - Weight::from_parts(66_140_000, 0) + // Minimum execution time: 62_606_000 picoseconds. + Weight::from_parts(64_678_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) @@ -783,8 +757,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 11_830_000 picoseconds. - Weight::from_parts(12_210_000, 0) + // Minimum execution time: 11_490_000 picoseconds. + Weight::from_parts(11_867_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -795,8 +769,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_364_000 picoseconds. - Weight::from_parts(2_555_000, 0) + // Minimum execution time: 2_125_000 picoseconds. + Weight::from_parts(2_337_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 05c6bc39709..6f60c4909f4 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -464,16 +464,28 @@ benchmarks! { } set_payee { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; + let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; assert_eq!(Payee::::get(&stash), RewardDestination::Staked); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), RewardDestination::Controller) + }: _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone())) verify { - assert_eq!(Payee::::get(&stash), RewardDestination::Controller); + assert_eq!(Payee::::get(&stash), RewardDestination::Account(controller)); + } + + update_payee { + let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + Payee::::insert(&stash, { + #[allow(deprecated)] + RewardDestination::Controller + }); + whitelist_account!(controller); + }: _(RawOrigin::Signed(controller.clone()), controller.clone()) + verify { + assert_eq!(Payee::::get(&stash), RewardDestination::Account(controller)); } set_controller { - let (stash, ctlr) = create_unique_stash_controller::(9000, 100, Default::default(), false)?; + let (stash, ctlr) = create_unique_stash_controller::(9000, 100, RewardDestination::Staked, false)?; // ensure `ctlr` is the currently stored controller. assert!(!Ledger::::contains_key(&stash)); assert!(Ledger::::contains_key(&ctlr)); @@ -551,40 +563,6 @@ benchmarks! { assert_eq!(UnappliedSlashes::::get(&era).len(), (MAX_SLASHES - s) as usize); } - payout_stakers_dead_controller { - let n in 0 .. T::MaxExposurePageSize::get() as u32; - let (validator, nominators) = create_validator_with_nominators::( - n, - T::MaxExposurePageSize::get() as u32, - true, - true, - RewardDestination::Controller, - )?; - - let current_era = CurrentEra::::get().unwrap(); - // set the commission for this particular era as well. - >::insert(current_era, validator.clone(), >::validators(&validator)); - - let caller = whitelisted_caller(); - let validator_controller = >::get(&validator).unwrap(); - let balance_before = T::Currency::free_balance(&validator_controller); - for (_, controller) in &nominators { - let balance = T::Currency::free_balance(controller); - ensure!(balance.is_zero(), "Controller has balance, but should be dead."); - } - }: payout_stakers_by_page(RawOrigin::Signed(caller), validator, current_era, 0) - verify { - let balance_after = T::Currency::free_balance(&validator_controller); - ensure!( - balance_before < balance_after, - "Balance of validator controller should have increased after payout.", - ); - for (_, controller) in &nominators { - let balance = T::Currency::free_balance(controller); - ensure!(!balance.is_zero(), "Payout not given to controller."); - } - } - payout_stakers_alive_staked { let n in 0 .. T::MaxExposurePageSize::get() as u32; let (validator, nominators) = create_validator_with_nominators::( diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 9e4697e845b..2cfee38ab4f 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -240,9 +240,9 @@ //! [`Payee`] storage item (see //! [`set_payee`](Call::set_payee)), to be one of the following: //! -//! - Controller account, (obviously) not increasing the staked value. //! - Stash account, not increasing the staked value. //! - Stash account, also increasing the staked value. +//! - Any other account, sent as free balance. //! //! ### Additional Fund Management Operations //! @@ -404,7 +404,9 @@ pub enum RewardDestination { Staked, /// Pay into the stash account, not increasing the amount at stake. Stash, - /// Pay into the controller account. + #[deprecated( + note = "`Controller` will be removed after January 2024. Use `Account(controller)` instead. This variant now behaves the same as `Stash` variant." + )] Controller, /// Pay into a specified account. Account(AccountId), diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index d2afd8f26e2..364d125792b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -594,7 +594,7 @@ pub(crate) fn current_era() -> EraIndex { pub(crate) fn bond(who: AccountId, val: Balance) { let _ = Balances::make_free_balance_be(&who, val); - assert_ok!(Staking::bond(RuntimeOrigin::signed(who), val, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(who), val, RewardDestination::Stash)); } pub(crate) fn bond_validator(who: AccountId, val: Balance) { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 40f30735258..6ea8e4c9d3b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -338,9 +338,8 @@ impl Pallet { 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::Stash => + T::Currency::deposit_into_existing(stash, amount).ok(), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; @@ -357,6 +356,14 @@ impl Pallet { RewardDestination::Account(dest_account) => Some(T::Currency::deposit_creating(&dest_account, amount)), RewardDestination::None => None, + #[allow(deprecated)] + RewardDestination::Controller => Self::bonded(stash) + .map(|controller| { + defensive!("Paying out controller as reward destination which is deprecated and should be migrated"); + // This should never happen once payees with a `Controller` variant have been migrated. + // But if it does, just pay the controller account. + T::Currency::deposit_creating(&controller, amount) + }), }; maybe_imbalance .map(|imbalance| (imbalance, Self::payee(StakingAccount::Stash(stash.clone())))) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 18ad3e4a6cf..a68e9c90da9 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -842,6 +842,8 @@ pub mod pallet { CommissionTooLow, /// Some bound is not met. BoundNotMet, + /// Used when attempting to use deprecated controller account logic. + ControllerDeprecated, } #[pallet::hooks] @@ -1283,10 +1285,19 @@ pub mod pallet { payee: RewardDestination, ) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(Controller(controller))?; + let ledger = Self::ledger(Controller(controller.clone()))?; + + ensure!( + (payee != { + #[allow(deprecated)] + RewardDestination::Controller + }), + Error::::ControllerDeprecated + ); + let _ = ledger .set_payee(payee) - .defensive_proof("ledger was retrieved from storage, thus its bonded; qed."); + .defensive_proof("ledger was retrieved from storage, thus its bonded; qed.")?; Ok(()) } @@ -1872,6 +1883,36 @@ pub mod pallet { ensure_signed(origin)?; Self::do_payout_stakers_by_page(validator_stash, era, page) } + + /// Migrates an account's `RewardDestination::Controller` to + /// `RewardDestination::Account(controller)`. + /// + /// Effects will be felt instantly (as soon as this function is completed successfully). + /// + /// This will waive the transaction fee if the `payee` is successfully migrated. + #[pallet::call_index(27)] + #[pallet::weight(T::WeightInfo::update_payee())] + pub fn update_payee( + origin: OriginFor, + controller: T::AccountId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?; + + ensure!( + (Payee::::get(&ledger.stash) == { + #[allow(deprecated)] + RewardDestination::Controller + }), + Error::::NotController + ); + + let _ = ledger + .set_payee(RewardDestination::Account(controller)) + .defensive_proof("ledger should have been previously retrieved from storage.")?; + + Ok(Pays::No.into()) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index bac2530b19b..7d967609f52 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -298,9 +298,9 @@ fn rewards_should_work() { let init_balance_101 = Balances::total_balance(&101); // Set payees - Payee::::insert(11, RewardDestination::Controller); - Payee::::insert(21, RewardDestination::Controller); - Payee::::insert(101, RewardDestination::Controller); + Payee::::insert(11, RewardDestination::Account(11)); + Payee::::insert(21, RewardDestination::Account(21)); + Payee::::insert(101, RewardDestination::Account(101)); Pallet::::reward_by_ids(vec![(11, 50)]); Pallet::::reward_by_ids(vec![(11, 50)]); @@ -417,7 +417,7 @@ fn staking_should_work() { // --- Block 2: start_session(2); // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Account(3))); assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default())); assert_ok!(Session::set_keys( RuntimeOrigin::signed(3), @@ -585,22 +585,10 @@ fn nominating_and_rewards_should_work() { assert_ok!(Staking::validate(RuntimeOrigin::signed(31), Default::default())); // Set payee to controller. - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(11), - RewardDestination::Controller - )); - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(21), - RewardDestination::Controller - )); - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(31), - RewardDestination::Controller - )); - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(41), - RewardDestination::Controller - )); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(21), RewardDestination::Stash)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(31), RewardDestination::Stash)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(41), RewardDestination::Stash)); // give the man some money let initial_balance = 1000; @@ -612,14 +600,14 @@ fn nominating_and_rewards_should_work() { assert_ok!(Staking::bond( RuntimeOrigin::signed(1), 1000, - RewardDestination::Controller + RewardDestination::Account(1) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 21, 31])); assert_ok!(Staking::bond( RuntimeOrigin::signed(3), 1000, - RewardDestination::Controller + RewardDestination::Account(3) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11, 21, 41])); @@ -1116,8 +1104,8 @@ fn reward_destination_works() { // (era 1, page 0) is claimed assert_eq!(Staking::claimed_rewards(1, &11), vec![0]); - // Change RewardDestination to Controller - >::insert(&11, RewardDestination::Controller); + // Change RewardDestination to Account + >::insert(&11, RewardDestination::Account(11)); // Check controller balance assert_eq!(Balances::free_balance(11), 23150); @@ -1129,8 +1117,8 @@ fn reward_destination_works() { mock::start_active_era(3); mock::make_all_reward_payment(2); - // Check that RewardDestination is Controller - assert_eq!(Staking::payee(11.into()), RewardDestination::Controller); + // Check that RewardDestination is Account(11) + assert_eq!(Staking::payee(11.into()), RewardDestination::Account(11)); // Check that reward went to the controller account assert_eq!(Balances::free_balance(11), recorded_stash_balance + total_payout_2); // Check that amount at stake is NOT increased @@ -1159,9 +1147,9 @@ fn validator_payment_prefs_work() { let commission = Perbill::from_percent(40); >::insert(&11, ValidatorPrefs { commission, ..Default::default() }); - // Reward controller so staked ratio doesn't change. - >::insert(&11, RewardDestination::Controller); - >::insert(&101, RewardDestination::Controller); + // Reward stash so staked ratio doesn't change. + >::insert(&11, RewardDestination::Stash); + >::insert(&101, RewardDestination::Stash); mock::start_active_era(1); mock::make_all_reward_payment(0); @@ -1250,8 +1238,8 @@ fn bond_extra_and_withdraw_unbonded_works() { // * it can unbond a portion of its funds from the stash account. // * Once the unbonding period is done, it can actually take the funds out of the stash. ExtBuilder::default().nominate(false).build_and_execute(|| { - // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller)); + // Set payee to stash. + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1461,8 +1449,8 @@ fn rebond_works() { // * it can unbond a portion of its funds from the stash account. // * it can re-bond a portion of the funds scheduled to unlock. ExtBuilder::default().nominate(false).build_and_execute(|| { - // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller)); + // Set payee to stash. + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1587,8 +1575,8 @@ fn rebond_works() { fn rebond_is_fifo() { // Rebond should proceed by reversing the most recent bond operations. ExtBuilder::default().nominate(false).build_and_execute(|| { - // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller)); + // Set payee to stash. + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1683,8 +1671,8 @@ fn rebond_emits_right_value_in_event() { // When a user calls rebond with more than can be rebonded, things succeed, // and the rebond event emits the actual value rebonded. ExtBuilder::default().nominate(false).build_and_execute(|| { - // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller)); + // Set payee to stash. + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1836,10 +1824,7 @@ fn switching_roles() { ExtBuilder::default().nominate(false).build_and_execute(|| { // Reset reward destination for i in &[11, 21] { - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(*i), - RewardDestination::Controller - )); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(*i), RewardDestination::Stash)); } assert_eq_uvec!(validator_controllers(), vec![21, 11]); @@ -1850,14 +1835,14 @@ fn switching_roles() { } // add 2 nominators - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Account(1))); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 5])); - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Account(3))); assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 1])); // add a new validator candidate - assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1000, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1000, RewardDestination::Account(5))); assert_ok!(Staking::validate(RuntimeOrigin::signed(5), ValidatorPrefs::default())); assert_ok!(Session::set_keys( RuntimeOrigin::signed(5), @@ -1928,11 +1913,11 @@ fn bond_with_no_staked_value() { .build_and_execute(|| { // Can't bond with 1 assert_noop!( - Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Controller), + Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1)), Error::::InsufficientBond, ); // bonded with absolute minimum value possible. - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Account(1))); assert_eq!(Balances::locks(&1)[0].amount, 5); // unbonding even 1 will cause all to be unbonded. @@ -1974,15 +1959,12 @@ fn bond_with_little_staked_value_bounded() { .build_and_execute(|| { // setup assert_ok!(Staking::chill(RuntimeOrigin::signed(31))); - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(11), - RewardDestination::Controller - )); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); let init_balance_1 = Balances::free_balance(&1); let init_balance_11 = Balances::free_balance(&11); // Stingy validator. - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1))); assert_ok!(Staking::validate(RuntimeOrigin::signed(1), ValidatorPrefs::default())); assert_ok!(Session::set_keys( RuntimeOrigin::signed(1), @@ -2061,14 +2043,14 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { assert_ok!(Staking::bond( RuntimeOrigin::signed(1), 1000, - RewardDestination::Controller + RewardDestination::Account(1) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 11, 11, 21, 31])); assert_ok!(Staking::bond( RuntimeOrigin::signed(3), 1000, - RewardDestination::Controller + RewardDestination::Account(3) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 31])); @@ -2114,14 +2096,14 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { assert_ok!(Staking::bond( RuntimeOrigin::signed(1), 1000, - RewardDestination::Controller + RewardDestination::Account(1) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 11, 11, 21])); assert_ok!(Staking::bond( RuntimeOrigin::signed(3), 1000, - RewardDestination::Controller + RewardDestination::Account(3) )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21])); @@ -3530,8 +3512,8 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let part_for_101 = Perbill::from_rational::(125, 1125); // Check state - Payee::::insert(11, RewardDestination::Controller); - Payee::::insert(101, RewardDestination::Controller); + Payee::::insert(11, RewardDestination::Account(11)); + Payee::::insert(101, RewardDestination::Account(101)); Pallet::::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change @@ -3820,8 +3802,8 @@ fn test_multi_page_payout_stakers_by_page() { staking_events_since_last_call().as_slice(), &[ .., - Event::Rewarded { stash: 1063, dest: RewardDestination::Controller, amount: 111 }, - Event::Rewarded { stash: 1064, dest: RewardDestination::Controller, amount: 111 }, + Event::Rewarded { stash: 1063, dest: RewardDestination::Stash, amount: 111 }, + Event::Rewarded { stash: 1064, dest: RewardDestination::Stash, amount: 111 }, ] )); @@ -3843,8 +3825,8 @@ fn test_multi_page_payout_stakers_by_page() { events.as_slice(), &[ Event::PayoutStarted { era_index: 1, validator_stash: 11 }, - Event::Rewarded { stash: 1065, dest: RewardDestination::Controller, amount: 111 }, - Event::Rewarded { stash: 1066, dest: RewardDestination::Controller, amount: 111 }, + Event::Rewarded { stash: 1065, dest: RewardDestination::Stash, amount: 111 }, + Event::Rewarded { stash: 1066, dest: RewardDestination::Stash, amount: 111 }, .. ] )); @@ -4685,40 +4667,6 @@ fn offences_weight_calculated_correctly() { }); } -#[test] -fn payout_creates_controller() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { - let balance = 1000; - // Create a validator: - bond_validator(11, balance); - - // create a stash/controller pair and nominate - let (stash, controller) = testing_utils::create_unique_stash_controller::( - 0, - 100, - RewardDestination::Controller, - false, - ) - .unwrap(); - - assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); - - // kill controller - assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(controller), stash, 100)); - assert_eq!(Balances::free_balance(controller), 0); - - mock::start_active_era(1); - Staking::reward_by_ids(vec![(11, 1)]); - // compute and ensure the reward amount is greater than zero. - let _ = current_total_payout_for_duration(reward_time_per_era()); - mock::start_active_era(2); - assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); - - // Controller is created - assert!(Balances::free_balance(controller) > 0); - }) -} - #[test] fn payout_to_any_account_works() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { @@ -5462,7 +5410,7 @@ fn min_bond_checks_work() { .min_validator_bond(1_500) .build_and_execute(|| { // 500 is not enough for any role - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Controller)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Stash)); assert_noop!( Staking::nominate(RuntimeOrigin::signed(3), vec![1]), Error::::InsufficientBond @@ -5524,19 +5472,11 @@ fn chill_other_works() { Balances::make_free_balance_be(&c, 100_000); // Nominator - assert_ok!(Staking::bond( - RuntimeOrigin::signed(a), - 1000, - RewardDestination::Controller - )); + assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![1])); // Validator - assert_ok!(Staking::bond( - RuntimeOrigin::signed(b), - 1500, - RewardDestination::Controller - )); + assert_ok!(Staking::bond(RuntimeOrigin::signed(b), 1500, RewardDestination::Stash)); assert_ok!(Staking::validate(RuntimeOrigin::signed(b), ValidatorPrefs::default())); } @@ -5683,7 +5623,7 @@ fn capped_stakers_works() { let (_, controller) = testing_utils::create_stash_controller::( i + 10_000_000, 100, - RewardDestination::Controller, + RewardDestination::Stash, ) .unwrap(); assert_ok!(Staking::validate( @@ -5694,12 +5634,9 @@ fn capped_stakers_works() { } // but no more - let (_, last_validator) = testing_utils::create_stash_controller::( - 1337, - 100, - RewardDestination::Controller, - ) - .unwrap(); + let (_, last_validator) = + testing_utils::create_stash_controller::(1337, 100, RewardDestination::Stash) + .unwrap(); assert_noop!( Staking::validate(RuntimeOrigin::signed(last_validator), ValidatorPrefs::default()), @@ -5712,7 +5649,7 @@ fn capped_stakers_works() { let (_, controller) = testing_utils::create_stash_controller::( i + 20_000_000, 100, - RewardDestination::Controller, + RewardDestination::Stash, ) .unwrap(); assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1])); @@ -5723,7 +5660,7 @@ fn capped_stakers_works() { let (_, last_nominator) = testing_utils::create_stash_controller::( 30_000_000, 100, - RewardDestination::Controller, + RewardDestination::Stash, ) .unwrap(); assert_noop!( @@ -6787,7 +6724,7 @@ mod ledger { assert_ok!(Staking::bond( RuntimeOrigin::signed(10), 100, - RewardDestination::Controller + RewardDestination::Account(10) )); assert_eq!(>::get(&10), Some(10)); @@ -6896,4 +6833,38 @@ mod ledger { >::remove(42); // ensures try-state checks pass. }) } + + #[test] + #[allow(deprecated)] + fn set_payee_errors_on_controller_destination() { + ExtBuilder::default().build_and_execute(|| { + Payee::::insert(11, RewardDestination::Staked); + assert_noop!( + Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller), + Error::::ControllerDeprecated + ); + assert_eq!(Payee::::get(&11), RewardDestination::Staked); + }) + } + + #[test] + #[allow(deprecated)] + fn update_payee_migration_works() { + ExtBuilder::default().build_and_execute(|| { + // migrate a `Controller` variant to `Account` variant. + Payee::::insert(11, RewardDestination::Controller); + assert_eq!(Payee::::get(&11), RewardDestination::Controller); + assert_ok!(Staking::update_payee(RuntimeOrigin::signed(11), 11)); + assert_eq!(Payee::::get(&11), RewardDestination::Account(11)); + + // Do not migrate a variant if not `Controller`. + Payee::::insert(21, RewardDestination::Stash); + assert_eq!(Payee::::get(&21), RewardDestination::Stash); + assert_noop!( + Staking::update_payee(RuntimeOrigin::signed(11), 21), + Error::::NotController + ); + assert_eq!(Payee::::get(&21), RewardDestination::Stash); + }) + } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index ad6dbccde9f..ad9ca75a032 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -59,6 +59,7 @@ pub trait WeightInfo { fn nominate(n: u32, ) -> Weight; fn chill() -> Weight; fn set_payee() -> Weight; + fn update_payee() -> Weight; fn set_controller() -> Weight; fn set_validator_count() -> Weight; fn force_no_eras() -> Weight; @@ -67,7 +68,6 @@ pub trait WeightInfo { fn set_invulnerables(v: u32, ) -> Weight; fn force_unstake(s: u32, ) -> Weight; fn cancel_deferred_slash(s: u32, ) -> Weight; - fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_811_000 picoseconds. - Weight::from_parts(44_465_000, 4764) + // Minimum execution time: 43_427_000 picoseconds. + Weight::from_parts(45_221_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -119,8 +119,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_628_000 picoseconds. - Weight::from_parts(90_020_000, 8877) + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(90_599_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_655_000 picoseconds. - Weight::from_parts(94_146_000, 8877) + // Minimum execution time: 91_488_000 picoseconds. + Weight::from_parts(94_126_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -166,10 +166,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 42_953_000 picoseconds. - Weight::from_parts(44_648_505, 4764) - // Standard Error: 937 - .saturating_add(Weight::from_parts(51_090, 0).saturating_mul(s.into())) + // Minimum execution time: 42_713_000 picoseconds. + Weight::from_parts(44_530_499, 4764) + // Standard Error: 1_067 + .saturating_add(Weight::from_parts(51_411, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -206,10 +206,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_218_000 picoseconds. - Weight::from_parts(97_761_884, 6248) - // Standard Error: 3_888 - .saturating_add(Weight::from_parts(1_346_441, 0).saturating_mul(s.into())) + // Minimum execution time: 88_700_000 picoseconds. + Weight::from_parts(98_329_624, 6248) + // Standard Error: 4_477 + .saturating_add(Weight::from_parts(1_347_380, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -241,8 +241,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_200_000 picoseconds. - Weight::from_parts(53_403_000, 4556) + // Minimum execution time: 51_877_000 picoseconds. + Weight::from_parts(53_503_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -255,10 +255,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_963_000 picoseconds. - Weight::from_parts(29_884_371, 4556) - // Standard Error: 9_063 - .saturating_add(Weight::from_parts(6_532_967, 0).saturating_mul(k.into())) + // Minimum execution time: 29_604_000 picoseconds. + Weight::from_parts(31_726_296, 4556) + // Standard Error: 6_350 + .saturating_add(Weight::from_parts(6_416_846, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -291,10 +291,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_644_000 picoseconds. - Weight::from_parts(62_855_016, 6248) - // Standard Error: 17_528 - .saturating_add(Weight::from_parts(3_993_850, 0).saturating_mul(n.into())) + // Minimum execution time: 64_276_000 picoseconds. + Weight::from_parts(62_615_844, 6248) + // Standard Error: 14_914 + .saturating_add(Weight::from_parts(4_097_019, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -318,8 +318,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_505_000 picoseconds. - Weight::from_parts(56_026_000, 6248) + // Minimum execution time: 55_064_000 picoseconds. + Weight::from_parts(56_566_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -333,11 +333,26 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_639_000 picoseconds. - Weight::from_parts(17_342_000, 4556) + // Minimum execution time: 16_626_000 picoseconds. + Weight::from_parts(17_519_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// 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:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + fn update_payee() -> Weight { + // Proof Size summary in bytes: + // Measured: `969` + // Estimated: `4556` + // Minimum execution time: 20_545_000 picoseconds. + Weight::from_parts(21_395_000, 4556) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } /// 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:2) @@ -346,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_334_000 picoseconds. - Weight::from_parts(21_067_000, 4556) + // Minimum execution time: 20_179_000 picoseconds. + Weight::from_parts(20_728_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -357,8 +372,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_680_000 picoseconds. - Weight::from_parts(2_774_000, 0) + // Minimum execution time: 2_594_000 picoseconds. + Weight::from_parts(2_777_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -367,8 +382,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_613_000 picoseconds. - Weight::from_parts(8_922_000, 0) + // Minimum execution time: 8_302_000 picoseconds. + Weight::from_parts(8_741_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -377,8 +392,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_657_000 picoseconds. - Weight::from_parts(9_020_000, 0) + // Minimum execution time: 8_504_000 picoseconds. + Weight::from_parts(8_774_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -387,8 +402,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_600_000 picoseconds. - Weight::from_parts(9_157_000, 0) + // Minimum execution time: 8_474_000 picoseconds. + Weight::from_parts(8_740_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -398,10 +413,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(3_293_694, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(10_668, 0).saturating_mul(v.into())) + // Minimum execution time: 2_732_000 picoseconds. + Weight::from_parts(3_360_048, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) @@ -437,10 +452,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_537_000 picoseconds. - Weight::from_parts(95_127_637, 6248) - // Standard Error: 3_902 - .saturating_add(Weight::from_parts(1_336_182, 0).saturating_mul(s.into())) + // Minimum execution time: 87_495_000 picoseconds. + Weight::from_parts(95_710_388, 6248) + // Standard Error: 5_849 + .saturating_add(Weight::from_parts(1_339_335, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -453,54 +468,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 100_777_000 picoseconds. - Weight::from_parts(896_540_406, 70137) - // Standard Error: 57_788 - .saturating_add(Weight::from_parts(4_870_910, 0).saturating_mul(s.into())) + // Minimum execution time: 98_255_000 picoseconds. + Weight::from_parts(892_807_378, 70137) + // Standard Error: 57_735 + .saturating_add(Weight::from_parts(4_876_449, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) - /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:257 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:258 w:258) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ClaimedRewards` (r:1 w:1) - /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) - /// Proof: `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:257 w:0) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 256]`. - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `21644 + n * (155 ±0)` - // Estimated: `21412 + n * (2603 ±0)` - // Minimum execution time: 133_129_000 picoseconds. - Weight::from_parts(190_983_630, 21412) - // Standard Error: 17_497 - .saturating_add(Weight::from_parts(24_723_153, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(14_u64)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5_u64)) - .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::Bonded` (r:257 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:257 w:257) @@ -534,10 +508,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 149_773_000 picoseconds. - Weight::from_parts(151_527_124, 30944) - // Standard Error: 24_152 - .saturating_add(Weight::from_parts(46_124_074, 0).saturating_mul(n.into())) + // Minimum execution time: 144_258_000 picoseconds. + Weight::from_parts(175_256_796, 30944) + // Standard Error: 24_339 + .saturating_add(Weight::from_parts(46_011_700, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -561,10 +535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_618_000 picoseconds. - Weight::from_parts(85_245_630, 8877) - // Standard Error: 5_049 - .saturating_add(Weight::from_parts(39_811, 0).saturating_mul(l.into())) + // Minimum execution time: 83_532_000 picoseconds. + Weight::from_parts(86_757_943, 8877) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(57_566, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -599,10 +573,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 95_395_000 picoseconds. - Weight::from_parts(100_459_234, 6248) - // Standard Error: 3_781 - .saturating_add(Weight::from_parts(1_333_607, 0).saturating_mul(s.into())) + // Minimum execution time: 96_776_000 picoseconds. + Weight::from_parts(100_950_027, 6248) + // Standard Error: 4_719 + .saturating_add(Weight::from_parts(1_432_091, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -648,12 +622,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 571_337_000 picoseconds. - Weight::from_parts(578_857_000, 512390) - // Standard Error: 2_090_511 - .saturating_add(Weight::from_parts(68_626_083, 0).saturating_mul(v.into())) - // Standard Error: 208_307 - .saturating_add(Weight::from_parts(18_645_374, 0).saturating_mul(n.into())) + // Minimum execution time: 577_699_000 picoseconds. + Weight::from_parts(582_827_000, 512390) + // Standard Error: 2_000_851 + .saturating_add(Weight::from_parts(67_316_744, 0).saturating_mul(v.into())) + // Standard Error: 199_373 + .saturating_add(Weight::from_parts(18_503_387, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -684,12 +658,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_590_734_000 picoseconds. - Weight::from_parts(35_238_091_000, 512390) - // Standard Error: 427_974 - .saturating_add(Weight::from_parts(5_084_196, 0).saturating_mul(v.into())) - // Standard Error: 427_974 - .saturating_add(Weight::from_parts(4_503_420, 0).saturating_mul(n.into())) + // Minimum execution time: 34_048_778_000 picoseconds. + Weight::from_parts(34_397_777_000, 512390) + // Standard Error: 346_115 + .saturating_add(Weight::from_parts(3_704_941, 0).saturating_mul(v.into())) + // Standard Error: 346_115 + .saturating_add(Weight::from_parts(4_064_819, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -706,10 +680,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_509_588_000 picoseconds. - Weight::from_parts(89_050_539, 3510) - // Standard Error: 11_803 - .saturating_add(Weight::from_parts(5_031_416, 0).saturating_mul(v.into())) + // Minimum execution time: 2_473_149_000 picoseconds. + Weight::from_parts(84_721_859, 3510) + // Standard Error: 8_690 + .saturating_add(Weight::from_parts(4_870_439, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -730,8 +704,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_347_000 picoseconds. - Weight::from_parts(5_562_000, 0) + // Minimum execution time: 5_312_000 picoseconds. + Weight::from_parts(5_897_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -750,8 +724,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_725_000 picoseconds. - Weight::from_parts(5_075_000, 0) + // Minimum execution time: 4_676_000 picoseconds. + Weight::from_parts(4_913_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -778,8 +752,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1773` // Estimated: `6248` - // Minimum execution time: 67_204_000 picoseconds. - Weight::from_parts(69_197_000, 6248) + // Minimum execution time: 67_286_000 picoseconds. + Weight::from_parts(69_081_000, 6248) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -791,8 +765,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_497_000 picoseconds. - Weight::from_parts(12_943_000, 3510) + // Minimum execution time: 12_749_000 picoseconds. + Weight::from_parts(13_275_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -802,8 +776,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_245_000 picoseconds. - Weight::from_parts(3_352_000, 0) + // Minimum execution time: 3_155_000 picoseconds. + Weight::from_parts(3_319_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -824,8 +798,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_811_000 picoseconds. - Weight::from_parts(44_465_000, 4764) + // Minimum execution time: 43_427_000 picoseconds. + Weight::from_parts(45_221_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -845,8 +819,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_628_000 picoseconds. - Weight::from_parts(90_020_000, 8877) + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(90_599_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -872,8 +846,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_655_000 picoseconds. - Weight::from_parts(94_146_000, 8877) + // Minimum execution time: 91_488_000 picoseconds. + Weight::from_parts(94_126_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -892,10 +866,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 42_953_000 picoseconds. - Weight::from_parts(44_648_505, 4764) - // Standard Error: 937 - .saturating_add(Weight::from_parts(51_090, 0).saturating_mul(s.into())) + // Minimum execution time: 42_713_000 picoseconds. + Weight::from_parts(44_530_499, 4764) + // Standard Error: 1_067 + .saturating_add(Weight::from_parts(51_411, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -932,10 +906,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_218_000 picoseconds. - Weight::from_parts(97_761_884, 6248) - // Standard Error: 3_888 - .saturating_add(Weight::from_parts(1_346_441, 0).saturating_mul(s.into())) + // Minimum execution time: 88_700_000 picoseconds. + Weight::from_parts(98_329_624, 6248) + // Standard Error: 4_477 + .saturating_add(Weight::from_parts(1_347_380, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -967,8 +941,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_200_000 picoseconds. - Weight::from_parts(53_403_000, 4556) + // Minimum execution time: 51_877_000 picoseconds. + Weight::from_parts(53_503_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -981,10 +955,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_963_000 picoseconds. - Weight::from_parts(29_884_371, 4556) - // Standard Error: 9_063 - .saturating_add(Weight::from_parts(6_532_967, 0).saturating_mul(k.into())) + // Minimum execution time: 29_604_000 picoseconds. + Weight::from_parts(31_726_296, 4556) + // Standard Error: 6_350 + .saturating_add(Weight::from_parts(6_416_846, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -1017,10 +991,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_644_000 picoseconds. - Weight::from_parts(62_855_016, 6248) - // Standard Error: 17_528 - .saturating_add(Weight::from_parts(3_993_850, 0).saturating_mul(n.into())) + // Minimum execution time: 64_276_000 picoseconds. + Weight::from_parts(62_615_844, 6248) + // Standard Error: 14_914 + .saturating_add(Weight::from_parts(4_097_019, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1044,8 +1018,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_505_000 picoseconds. - Weight::from_parts(56_026_000, 6248) + // Minimum execution time: 55_064_000 picoseconds. + Weight::from_parts(56_566_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1059,11 +1033,26 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_639_000 picoseconds. - Weight::from_parts(17_342_000, 4556) + // Minimum execution time: 16_626_000 picoseconds. + Weight::from_parts(17_519_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// 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:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + fn update_payee() -> Weight { + // Proof Size summary in bytes: + // Measured: `969` + // Estimated: `4556` + // Minimum execution time: 20_545_000 picoseconds. + Weight::from_parts(21_395_000, 4556) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } /// 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:2) @@ -1072,8 +1061,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_334_000 picoseconds. - Weight::from_parts(21_067_000, 4556) + // Minimum execution time: 20_179_000 picoseconds. + Weight::from_parts(20_728_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1083,8 +1072,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_680_000 picoseconds. - Weight::from_parts(2_774_000, 0) + // Minimum execution time: 2_594_000 picoseconds. + Weight::from_parts(2_777_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1093,8 +1082,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_613_000 picoseconds. - Weight::from_parts(8_922_000, 0) + // Minimum execution time: 8_302_000 picoseconds. + Weight::from_parts(8_741_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1103,8 +1092,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_657_000 picoseconds. - Weight::from_parts(9_020_000, 0) + // Minimum execution time: 8_504_000 picoseconds. + Weight::from_parts(8_774_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1113,8 +1102,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_600_000 picoseconds. - Weight::from_parts(9_157_000, 0) + // Minimum execution time: 8_474_000 picoseconds. + Weight::from_parts(8_740_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1124,10 +1113,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(3_293_694, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(10_668, 0).saturating_mul(v.into())) + // Minimum execution time: 2_732_000 picoseconds. + Weight::from_parts(3_360_048, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) @@ -1163,10 +1152,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_537_000 picoseconds. - Weight::from_parts(95_127_637, 6248) - // Standard Error: 3_902 - .saturating_add(Weight::from_parts(1_336_182, 0).saturating_mul(s.into())) + // Minimum execution time: 87_495_000 picoseconds. + Weight::from_parts(95_710_388, 6248) + // Standard Error: 5_849 + .saturating_add(Weight::from_parts(1_339_335, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1179,54 +1168,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 100_777_000 picoseconds. - Weight::from_parts(896_540_406, 70137) - // Standard Error: 57_788 - .saturating_add(Weight::from_parts(4_870_910, 0).saturating_mul(s.into())) + // Minimum execution time: 98_255_000 picoseconds. + Weight::from_parts(892_807_378, 70137) + // Standard Error: 57_735 + .saturating_add(Weight::from_parts(4_876_449, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) - /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, 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:257 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:258 w:258) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ClaimedRewards` (r:1 w:1) - /// Proof: `Staking::ClaimedRewards` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) - /// Proof: `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:257 w:0) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 256]`. - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `21644 + n * (155 ±0)` - // Estimated: `21412 + n * (2603 ±0)` - // Minimum execution time: 133_129_000 picoseconds. - Weight::from_parts(190_983_630, 21412) - // Standard Error: 17_497 - .saturating_add(Weight::from_parts(24_723_153, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(14_u64)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(5_u64)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) - } /// Storage: `Staking::Bonded` (r:257 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:257 w:257) @@ -1260,10 +1208,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 149_773_000 picoseconds. - Weight::from_parts(151_527_124, 30944) - // Standard Error: 24_152 - .saturating_add(Weight::from_parts(46_124_074, 0).saturating_mul(n.into())) + // Minimum execution time: 144_258_000 picoseconds. + Weight::from_parts(175_256_796, 30944) + // Standard Error: 24_339 + .saturating_add(Weight::from_parts(46_011_700, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1287,10 +1235,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_618_000 picoseconds. - Weight::from_parts(85_245_630, 8877) - // Standard Error: 5_049 - .saturating_add(Weight::from_parts(39_811, 0).saturating_mul(l.into())) + // Minimum execution time: 83_532_000 picoseconds. + Weight::from_parts(86_757_943, 8877) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(57_566, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1325,10 +1273,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 95_395_000 picoseconds. - Weight::from_parts(100_459_234, 6248) - // Standard Error: 3_781 - .saturating_add(Weight::from_parts(1_333_607, 0).saturating_mul(s.into())) + // Minimum execution time: 96_776_000 picoseconds. + Weight::from_parts(100_950_027, 6248) + // Standard Error: 4_719 + .saturating_add(Weight::from_parts(1_432_091, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1374,12 +1322,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 571_337_000 picoseconds. - Weight::from_parts(578_857_000, 512390) - // Standard Error: 2_090_511 - .saturating_add(Weight::from_parts(68_626_083, 0).saturating_mul(v.into())) - // Standard Error: 208_307 - .saturating_add(Weight::from_parts(18_645_374, 0).saturating_mul(n.into())) + // Minimum execution time: 577_699_000 picoseconds. + Weight::from_parts(582_827_000, 512390) + // Standard Error: 2_000_851 + .saturating_add(Weight::from_parts(67_316_744, 0).saturating_mul(v.into())) + // Standard Error: 199_373 + .saturating_add(Weight::from_parts(18_503_387, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1410,12 +1358,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_590_734_000 picoseconds. - Weight::from_parts(35_238_091_000, 512390) - // Standard Error: 427_974 - .saturating_add(Weight::from_parts(5_084_196, 0).saturating_mul(v.into())) - // Standard Error: 427_974 - .saturating_add(Weight::from_parts(4_503_420, 0).saturating_mul(n.into())) + // Minimum execution time: 34_048_778_000 picoseconds. + Weight::from_parts(34_397_777_000, 512390) + // Standard Error: 346_115 + .saturating_add(Weight::from_parts(3_704_941, 0).saturating_mul(v.into())) + // Standard Error: 346_115 + .saturating_add(Weight::from_parts(4_064_819, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1432,10 +1380,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_509_588_000 picoseconds. - Weight::from_parts(89_050_539, 3510) - // Standard Error: 11_803 - .saturating_add(Weight::from_parts(5_031_416, 0).saturating_mul(v.into())) + // Minimum execution time: 2_473_149_000 picoseconds. + Weight::from_parts(84_721_859, 3510) + // Standard Error: 8_690 + .saturating_add(Weight::from_parts(4_870_439, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1456,8 +1404,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_347_000 picoseconds. - Weight::from_parts(5_562_000, 0) + // Minimum execution time: 5_312_000 picoseconds. + Weight::from_parts(5_897_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1476,8 +1424,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_725_000 picoseconds. - Weight::from_parts(5_075_000, 0) + // Minimum execution time: 4_676_000 picoseconds. + Weight::from_parts(4_913_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -1504,8 +1452,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1773` // Estimated: `6248` - // Minimum execution time: 67_204_000 picoseconds. - Weight::from_parts(69_197_000, 6248) + // Minimum execution time: 67_286_000 picoseconds. + Weight::from_parts(69_081_000, 6248) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1517,8 +1465,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_497_000 picoseconds. - Weight::from_parts(12_943_000, 3510) + // Minimum execution time: 12_749_000 picoseconds. + Weight::from_parts(13_275_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1528,8 +1476,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_245_000 picoseconds. - Weight::from_parts(3_352_000, 0) + // Minimum execution time: 3_155_000 picoseconds. + Weight::from_parts(3_319_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } -- GitLab From a9ba1e540ff524dda0dec8bb0b7da204e043adae Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:29:56 +0100 Subject: [PATCH 553/633] Revert docker images tag naming to (#2434) Docker images from paritypr are also used in testnets. PR reverts docker tags naming to a more convenient. cc @PierreBesson --- .gitlab-ci.yml | 2 +- .gitlab/pipeline/publish.yml | 201 +---------------------------------- 2 files changed, 5 insertions(+), 198 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e698aba81d5..f7e54961fa9 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 - DOCKER_IMAGES_VERSION: "${CI_COMMIT_SHA}" + DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: retry: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 3cc2002cc1c..92ebc9eea1f 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -63,16 +63,16 @@ publish-rustdoc: after_script: - rm -rf .git/ ./* -# cumulus - +# note: images are used not only in zombienet but also in rococo, wococo and versi .build-push-image: image: $BUILDAH_IMAGE variables: DOCKERFILE: "" # docker/path-to.Dockerfile IMAGE_NAME: "" # docker.io/paritypr/image_name script: - # Exit if the job is not running in a merge queue - # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # Dockertag should differ in a merge queue + # TODO: test this + # - if [[ $CI_COMMIT_REF_NAME == *"gh-readonly-queue"* ]]; export DOCKER_IMAGES_VERSION="${CI_COMMIT_SHORT_SHA}"; fi - $BUILDAH_COMMAND build --format=docker --build-arg VCS_REF="${CI_COMMIT_SHA}" @@ -112,59 +112,6 @@ build-push-image-test-parachain: variables: DOCKERFILE: "docker/dockerfiles/test-parachain_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/test-parachain" -# publish-s3: -# stage: publish -# extends: -# - .kubernetes-env -# - .publish-refs -# image: paritytech/awscli:latest -# needs: -# - job: build-linux-stable-cumulus -# artifacts: true -# variables: -# GIT_STRATEGY: none -# BUCKET: "releases.parity.io" -# PREFIX: "cumulus/${ARCH}-${DOCKER_OS}" -# script: -# - echo "___Publishing a binary with debug assertions!___" -# - echo "___VERSION = $(cat ./artifacts/VERSION) ___" -# - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/VERSION)/ -# - echo "___Updating objects in latest path___" -# - aws s3 sync s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/VERSION)/ s3://${BUCKET}/${PREFIX}/latest/ -# after_script: -# - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ -# --recursive --human-readable --summarize - -# publish-benchmarks-assets-s3: &publish-benchmarks -# stage: publish -# extends: -# - .kubernetes-env -# - .benchmarks-refs -# image: paritytech/awscli:latest -# needs: -# - job: benchmarks-assets -# artifacts: true -# variables: -# GIT_STRATEGY: none -# BUCKET: "releases.parity.io" -# PREFIX: "cumulus/$CI_COMMIT_REF_NAME/benchmarks-assets" -# script: -# - echo "___Publishing benchmark results___" -# - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/ -# after_script: -# - aws s3 ls s3://${BUCKET}/${PREFIX}/ --recursive --human-readable --summarize - -# publish-benchmarks-collectives-s3: -# <<: *publish-benchmarks -# variables: -# GIT_STRATEGY: none -# BUCKET: "releases.parity.io" -# PREFIX: "cumulus/$CI_COMMIT_REF_NAME/benchmarks-collectives" -# needs: -# - job: benchmarks-collectives -# artifacts: true - -### Polkadot build-push-image-polkadot-debug: stage: publish @@ -217,143 +164,3 @@ build-push-image-substrate-pr: variables: DOCKERFILE: "docker/dockerfiles/substrate_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/substrate" -# old way - -# .build-push-image-polkadot: -# before_script: -# # - test -s ./artifacts/VERSION || exit 1 -# # - test -s ./artifacts/EXTRATAG || exit 1 -# - 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 ) -# - cd ./artifacts -# - $BUILDAH_COMMAND build -# --format=docker -# --build-arg VCS_REF="${CI_COMMIT_SHA}" -# --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" -# --build-arg IMAGE_NAME="${IMAGE_NAME}" -# --tag "$IMAGE_NAME:$VERSION" -# --tag "$IMAGE_NAME:$EXTRATAG" -# --file ${DOCKERFILE} . -# # The job will success only on the protected branch -# # - echo "$DOCKER_PASS" | -# # buildah login --username "$DOCKER_USER" --password-stdin docker.io -# # - $BUILDAH_COMMAND info -# # - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$VERSION" -# # - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$EXTRATAG" -# after_script: -# - buildah logout --all - -# publish-polkadot-debug-image: -# stage: publish -# image: ${BUILDAH_IMAGE} -# extends: -# - .kubernetes-env -# - .build-push-image-polkadot -# 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 -# variables: -# GIT_STRATEGY: none -# DOCKER_USER: ${PARITYPR_USER} -# DOCKER_PASS: ${PARITYPR_PASS} -# # docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile -# DOCKERFILE: polkadot_injected_debug.Dockerfile -# IMAGE_NAME: docker.io/paritypr/polkadot-debug -# needs: -# - job: build-linux-stable -# artifacts: true -# after_script: -# # pass artifacts to the zombienet-tests job -# # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance -# - echo "PARACHAINS_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/parachains.env -# - echo "PARACHAINS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/parachains.env -# artifacts: -# reports: -# # this artifact is used in zombienet-tests job -# dotenv: ./artifacts/parachains.env -# expire_in: 1 days - -# publish-test-collators-image: -# # service image for zombienet -# stage: publish -# extends: -# - .kubernetes-env -# - .build-push-image-polkadot -# - .zombienet-refs -# variables: -# CI_IMAGE: ${BUILDAH_IMAGE} -# GIT_STRATEGY: none -# DOCKER_USER: ${PARITYPR_USER} -# DOCKER_PASS: ${PARITYPR_PASS} -# # docker/dockerfiles/collator_injected.Dockerfile -# DOCKERFILE: collator_injected.Dockerfile -# IMAGE_NAME: docker.io/paritypr/colander -# needs: -# - job: build-test-collators -# artifacts: true -# after_script: -# - buildah logout --all -# # pass artifacts to the zombienet-tests job -# - echo "COLLATOR_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/collator.env -# - echo "COLLATOR_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/collator.env -# artifacts: -# reports: -# # this artifact is used in zombienet-tests job -# dotenv: ./artifacts/collator.env - -# publish-malus-image: -# # service image for Simnet -# stage: publish -# extends: -# - .kubernetes-env -# - .build-push-image-polkadot -# - .zombienet-refs -# variables: -# CI_IMAGE: ${BUILDAH_IMAGE} -# GIT_STRATEGY: none -# DOCKER_USER: ${PARITYPR_USER} -# DOCKER_PASS: ${PARITYPR_PASS} -# # docker/dockerfiles/malus_injected.Dockerfile -# DOCKERFILE: malus_injected.Dockerfile -# IMAGE_NAME: docker.io/paritypr/malus -# needs: -# - job: build-malus -# artifacts: true -# after_script: -# - buildah logout "$IMAGE_NAME" -# # pass artifacts to the zombienet-tests job -# - echo "MALUS_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/malus.env -# - echo "MALUS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/malus.env -# artifacts: -# reports: -# # this artifact is used in zombienet-tests job -# dotenv: ./artifacts/malus.env - -# substrate - -# publish-substrate-image-pr: -# # service image for zombienet -# stage: publish -# extends: -# - .kubernetes-env -# - .build-push-image-polkadot -# - .zombienet-refs -# variables: -# CI_IMAGE: ${BUILDAH_IMAGE} -# GIT_STRATEGY: none -# DOCKER_USER: ${PARITYPR_USER} -# DOCKER_PASS: ${PARITYPR_PASS} -# DOCKERFILE: substrate_injected.Dockerfile -# IMAGE_NAME: docker.io/paritypr/substrate -# needs: -# - job: build-linux-substrate -# artifacts: true -# after_script: -# - buildah logout "$IMAGE_NAME" -- GitLab From 98f9e2ea9d5d034e85de7a87f6ba941827bc1a13 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Wed, 22 Nov 2023 17:32:49 +0530 Subject: [PATCH 554/633] Fixes import path in benchmark macro (#2437) Fully-qualified path was not being used in benchmark macro for one of the cases. This PR fixes this and removes the unnecessary import in a couple of files, which I believe was done to fix this issue. --- .../bin/node-template/pallets/template/src/benchmarking.rs | 1 - substrate/frame/asset-rate/src/benchmarking.rs | 1 - substrate/frame/support/procedural/src/benchmark.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/bin/node-template/pallets/template/src/benchmarking.rs b/substrate/bin/node-template/pallets/template/src/benchmarking.rs index 6c3cae6066b..5a262417629 100644 --- a/substrate/bin/node-template/pallets/template/src/benchmarking.rs +++ b/substrate/bin/node-template/pallets/template/src/benchmarking.rs @@ -1,7 +1,6 @@ //! Benchmarking setup for pallet-template #![cfg(feature = "runtime-benchmarks")] use super::*; -use sp_std::vec; #[allow(unused)] use crate::Pallet as Template; diff --git a/substrate/frame/asset-rate/src/benchmarking.rs b/substrate/frame/asset-rate/src/benchmarking.rs index 21d53a89e39..6fcc7c7fadb 100644 --- a/substrate/frame/asset-rate/src/benchmarking.rs +++ b/substrate/frame/asset-rate/src/benchmarking.rs @@ -25,7 +25,6 @@ use frame_benchmarking::v2::*; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_core::crypto::FromEntropy; -use sp_std::vec; /// Trait describing the factory function for the `AssetKind` parameter. pub trait AssetKindFactory { diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index fb55e8c9f66..6ded82d91aa 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -517,7 +517,7 @@ pub fn benchmarks( components, // TODO: Not supported by V2 syntax as of yet. // https://github.com/paritytech/substrate/issues/13132 - pov_modes: vec![], + pov_modes: #krate::__private::vec![], } }).collect::<#krate::__private::Vec<_>>() } -- GitLab From 408af9b32d95acbbac5e18bee66fd1b74230a699 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Wed, 22 Nov 2023 15:45:52 +0100 Subject: [PATCH 555/633] PVF: Fix unshare "no such file or directory" error (#2426) --- .gitlab/pipeline/test.yml | 2 +- Cargo.lock | 1 + polkadot/node/core/pvf/Cargo.toml | 1 + polkadot/node/core/pvf/common/src/lib.rs | 2 +- polkadot/node/core/pvf/src/artifacts.rs | 5 +- .../node/core/pvf/src/execute/worker_intf.rs | 4 +- polkadot/node/core/pvf/src/host.rs | 9 +- .../node/core/pvf/src/prepare/worker_intf.rs | 4 +- polkadot/node/core/pvf/src/security.rs | 19 ++-- polkadot/node/core/pvf/src/worker_intf.rs | 105 ++++++++---------- polkadot/node/core/pvf/tests/it/main.rs | 32 ++++++ .../functional/0001-parachains-pvf.zndsl | 4 +- 12 files changed, 105 insertions(+), 83 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 4ed3ec19c48..79ef9070dba 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -29,7 +29,7 @@ test-linux-stable: --locked \ --release \ --no-fail-fast \ - --features try-runtime,experimental \ + --features try-runtime,experimental,ci-only-tests \ --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} # Upload tests results to Elasticsearch - echo "Upload test results to Elasticsearch" diff --git a/Cargo.lock b/Cargo.lock index 903e9463cf6..bfe24e528eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12591,6 +12591,7 @@ dependencies = [ "rand 0.8.5", "rococo-runtime", "rusty-fork", + "sc-sysinfo", "slotmap", "sp-core", "sp-maybe-compressed-blob", diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 27da484fe4f..05509a5f853 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -54,6 +54,7 @@ halt = { package = "test-parachain-halt", path = "../../../parachain/test-parach [target.'cfg(target_os = "linux")'.dev-dependencies] procfs = "0.16.0" rusty-fork = "0.3.0" +sc-sysinfo = { path = "../../../../substrate/client/sysinfo" } [[bench]] name = "host_prepare_rococo_runtime" diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index 278fa3fe821..c041c60aaf9 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -47,7 +47,7 @@ pub mod tests { } /// Status of security features on the current system. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct SecurityStatus { /// Whether the landlock features we use are fully available on this system. pub can_enable_landlock: bool, diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 53085eade3c..79b53467b4e 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -499,8 +499,7 @@ mod tests { #[tokio::test] async fn remove_stale_cache_on_startup() { - let cache_dir = crate::worker_intf::tmppath("test-cache").await.unwrap(); - fs::create_dir_all(&cache_dir).unwrap(); + let cache_dir = tempfile::Builder::new().prefix("test-cache-").tempdir().unwrap(); // invalid prefix create_rand_artifact(&cache_dir, ""); @@ -529,7 +528,7 @@ mod tests { assert_eq!(fs::read_dir(&cache_dir).unwrap().count(), 7); - let artifacts = Artifacts::new_and_prune(&cache_dir).await; + let artifacts = Artifacts::new_and_prune(cache_dir.path()).await; assert_eq!(fs::read_dir(&cache_dir).unwrap().count(), 1); assert_eq!(artifacts.len(), 1); diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index 4faaf13e62f..fc6cd8fc725 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -278,7 +278,7 @@ where // 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); + 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, @@ -292,7 +292,7 @@ where } } - let worker_dir_path = worker_dir.path.clone(); + let worker_dir_path = worker_dir.path().to_owned(); let outcome = f(worker_dir).await; // Try to clear the worker dir. diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 6049f51834e..be8f7aee778 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -24,7 +24,7 @@ use crate::{ artifacts::{ArtifactId, ArtifactPathId, ArtifactState, Artifacts}, execute::{self, PendingExecutionRequest}, metrics::Metrics, - prepare, security, Priority, ValidationError, LOG_TARGET, + prepare, security, Priority, SecurityStatus, ValidationError, LOG_TARGET, }; use always_assert::never; use futures::{ @@ -70,6 +70,8 @@ pub(crate) type PrecheckResultSender = oneshot::Sender; #[derive(Clone)] pub struct ValidationHost { to_host_tx: mpsc::Sender, + /// Available security features, detected by the host during startup. + pub security_status: SecurityStatus, } impl ValidationHost { @@ -216,7 +218,7 @@ pub async fn start( let (to_host_tx, to_host_rx) = mpsc::channel(10); - let validation_host = ValidationHost { to_host_tx }; + let validation_host = ValidationHost { to_host_tx, security_status: security_status.clone() }; let (to_prepare_pool, from_prepare_pool, run_prepare_pool) = prepare::start_pool( metrics.clone(), @@ -978,7 +980,8 @@ pub(crate) mod tests { fn host_handle(&mut self) -> ValidationHost { let to_host_tx = self.to_host_tx.take().unwrap(); - ValidationHost { to_host_tx } + let security_status = Default::default(); + ValidationHost { to_host_tx, security_status } } async fn poll_and_recv_result(&mut self, result_rx: oneshot::Receiver) -> T diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index 318aea7295d..f978005068c 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -318,7 +318,7 @@ where { // 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); + 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, @@ -333,7 +333,7 @@ where } }; - let worker_dir_path = worker_dir.path.clone(); + let worker_dir_path = worker_dir.path().to_owned(); let outcome = f(tmp_file, stream, worker_dir).await; // Try to clear the worker dir. diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index 8c06c68392f..ef8714f58c8 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -28,7 +28,7 @@ const SECURE_MODE_ANNOUNCEMENT: &'static str = /// Run checks for supported security features. /// -/// # Return +/// # Returns /// /// Returns the set of security features that we were able to enable. If an error occurs while /// enabling a security feature we set the corresponding status to `false`. @@ -158,18 +158,15 @@ async fn check_can_unshare_user_namespace_and_change_root( ) -> SecureModeResult { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - let cache_dir_tempdir = - crate::worker_intf::tmppath_in("check-can-unshare", cache_path) - .await - .map_err( - |err| - SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( - format!("could not create a temporary directory in {:?}: {}", cache_path, err) - ) - )?; + let cache_dir_tempdir = tempfile::Builder::new() + .prefix("check-can-unshare-") + .tempdir_in(cache_path) + .map_err(|err| SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + format!("could not create a temporary directory in {:?}: {}", cache_path, err) + ))?; match tokio::process::Command::new(prepare_worker_program_path) .arg("--check-can-unshare-user-namespace-and-change-root") - .arg(cache_dir_tempdir) + .arg(cache_dir_tempdir.path()) .output() .await { diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index 5e589b9abce..9d6907c1092 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -71,6 +71,7 @@ pub async fn spawn_with_program_path( with_transient_socket_path(debug_id, |socket_path| { let socket_path = socket_path.to_owned(); + let worker_dir_path = worker_dir.path().to_owned(); async move { let listener = UnixListener::bind(&socket_path).map_err(|err| { @@ -91,7 +92,7 @@ pub async fn spawn_with_program_path( &program_path, &extra_args, &socket_path, - &worker_dir.path, + &worker_dir_path, security_status, ) .map_err(|err| { @@ -100,7 +101,7 @@ pub async fn spawn_with_program_path( %debug_id, ?program_path, ?extra_args, - ?worker_dir.path, + ?worker_dir_path, ?socket_path, "cannot spawn a worker: {:?}", err, @@ -108,7 +109,6 @@ pub async fn spawn_with_program_path( SpawnErr::ProcessSpawn })?; - let worker_dir_path = worker_dir.path.clone(); futures::select! { accept_result = listener.accept().fuse() => { let (stream, _) = accept_result.map_err(|err| { @@ -150,7 +150,42 @@ where F: FnOnce(&Path) -> Fut, Fut: futures::Future> + 'static, { - let socket_path = tmppath(&format!("pvf-host-{}", debug_id)) + /// Returns a path under [`std::env::temp_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 tmppath(prefix: &str) -> io::Result { + fn make_tmppath(prefix: &str, dir: &Path) -> PathBuf { + use rand::distributions::Alphanumeric; + + const DESCRIMINATOR_LEN: usize = 10; + + let mut buf = Vec::with_capacity(prefix.len() + DESCRIMINATOR_LEN); + buf.extend(prefix.as_bytes()); + buf.extend(rand::thread_rng().sample_iter(&Alphanumeric).take(DESCRIMINATOR_LEN)); + + let s = std::str::from_utf8(&buf) + .expect("the string is collected from a valid utf-8 sequence; qed"); + + let mut path = dir.to_owned(); + path.push(s); + path + } + + const NUM_RETRIES: usize = 50; + + let dir = std::env::temp_dir(); + for _ in 0..NUM_RETRIES { + 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 path")) + } + + let socket_path = tmppath(&format!("pvf-host-{}-", debug_id)) .await .map_err(|_| SpawnErr::TmpPath)?; let result = f(&socket_path).await; @@ -162,46 +197,6 @@ where result } -/// 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 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; - - let mut buf = Vec::with_capacity(prefix.len() + DESCRIMINATOR_LEN); - buf.extend(prefix.as_bytes()); - buf.extend(rand::thread_rng().sample_iter(&Alphanumeric).take(DESCRIMINATOR_LEN)); - - let s = std::str::from_utf8(&buf) - .expect("the string is collected from a valid utf-8 sequence; qed"); - - let mut path = dir.to_owned(); - path.push(s); - path - } - - const NUM_RETRIES: usize = 50; - - for _ in 0..NUM_RETRIES { - 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 path")) -} - -/// 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 = std::env::temp_dir(); - tmppath_in(prefix, &temp_dir).await -} - /// A struct that represents an idle worker. /// /// This struct is supposed to be used as a token that is passed by move into a subroutine that @@ -224,8 +219,6 @@ pub struct IdleWorker { pub enum SpawnErr { /// 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. @@ -419,26 +412,22 @@ pub async fn framed_recv(r: &mut (impl AsyncRead + Unpin)) -> io::Result /// ``` #[derive(Debug)] pub struct WorkerDir { - pub path: PathBuf, + tempdir: tempfile::TempDir, } 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 }) + let tempdir = tempfile::Builder::new() + .prefix(&prefix) + .tempdir_in(cache_dir) + .map_err(|_| SpawnErr::TmpPath)?; + Ok(Self { tempdir }) } -} -// 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); + pub fn path(&self) -> &Path { + self.tempdir.path() } } diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 4c81ac502dd..b53d598cd0f 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -18,6 +18,8 @@ use assert_matches::assert_matches; use parity_scale_codec::Encode as _; +#[cfg(all(feature = "ci-only-tests", target_os = "linux"))] +use polkadot_node_core_pvf::SecurityStatus; use polkadot_node_core_pvf::{ start, testing::build_workers_and_get_paths, Config, InvalidCandidate, Metrics, PrepareError, PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, @@ -122,6 +124,11 @@ impl TestHost { .unwrap(); result_rx.await.unwrap() } + + #[cfg(all(feature = "ci-only-tests", target_os = "linux"))] + async fn security_status(&self) -> SecurityStatus { + self.host.lock().await.security_status.clone() + } } #[tokio::test] @@ -402,3 +409,28 @@ async fn prepare_can_run_serially() { // Prepare a different wasm blob to prevent skipping work. let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); } + +// CI machines should be able to enable all the security features. +#[cfg(all(feature = "ci-only-tests", target_os = "linux"))] +#[tokio::test] +async fn all_security_features_work() { + // Landlock is only available starting Linux 5.13, and we may be testing on an old kernel. + let sysinfo = sc_sysinfo::gather_sysinfo(); + // The version will look something like "5.15.0-87-generic". + let version = sysinfo.linux_kernel.unwrap(); + let version_split: Vec<&str> = version.split(".").collect(); + let major: u32 = version_split[0].parse().unwrap(); + let minor: u32 = version_split[1].parse().unwrap(); + let can_enable_landlock = if major >= 6 { true } else { minor >= 13 }; + + let host = TestHost::new().await; + + assert_eq!( + host.security_status().await, + SecurityStatus { + can_enable_landlock, + can_enable_seccomp: true, + can_unshare_user_namespace_and_change_root: true, + } + ); +} diff --git a/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl b/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl index 46bb8bcdf72..135999a092a 100644 --- a/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl +++ b/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl @@ -54,8 +54,8 @@ one: reports histogram polkadot_pvf_preparation_time has 0 samples in buckets [" two: reports histogram polkadot_pvf_preparation_time has 0 samples in buckets ["20", "30", "60", "120", "+Inf"] within 10 seconds # Check execution time. -# There are two different timeout conditions: BACKING_EXECUTION_TIMEOUT(2s) and -# APPROVAL_EXECUTION_TIMEOUT(6s). Currently these are not differentiated by metrics +# There are two different timeout conditions: DEFAULT_BACKING_EXECUTION_TIMEOUT(2s) and +# DEFAULT_APPROVAL_EXECUTION_TIMEOUT(12s). Currently these are not differentiated by metrics # because the metrics are defined in `polkadot-node-core-pvf` which is a level below # the relevant subsystems. # That being said, we will take the simplifying assumption of testing only the -- GitLab From 0d6dcb3f48559eff24b3a4e2233fc31e145717d2 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 22 Nov 2023 17:27:53 +0000 Subject: [PATCH 556/633] Make TypeInfo for SkipCheckIfFeeless transparent, too (#2449) The `SkipCheckifFeeless::IDENTIFIER` became transparent (ie was whatever the inner signed ext was). This PR just makes the `TypeInfo` transparent too, so that libraries that use said info to decode the data (ie subxt) can behave identically whether or not the `SkipCheckifFeeless` wrapper is used or not. --------- Co-authored-by: Oliver Tale-Yazdi --- .../skip-feeless-payment/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs index 55afaaf93d7..6c34c26ce92 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -40,7 +40,7 @@ use frame_support::{ dispatch::{CheckIfFeeless, DispatchResult}, traits::{IsType, OriginTrait}, }; -use scale_info::TypeInfo; +use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ traits::{DispatchInfoOf, PostDispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, @@ -75,10 +75,17 @@ pub mod pallet { } /// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless. -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] +#[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct SkipCheckIfFeeless(pub S, sp_std::marker::PhantomData); +// Make this extension "invisible" from the outside (ie metadata type information) +impl TypeInfo for SkipCheckIfFeeless { + type Identity = S; + fn type_info() -> scale_info::Type { + S::type_info() + } +} + impl sp_std::fmt::Debug for SkipCheckIfFeeless { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { -- GitLab From 0956357b602af1bb10f9bd6fb3998b856bd07592 Mon Sep 17 00:00:00 2001 From: girazoki Date: Wed, 22 Nov 2023 18:29:06 +0100 Subject: [PATCH 557/633] work with additional key values (#1757) Add the possibility to inject additional key-values in the sproof-builder that generates the relay root that gets stored in parachain-system. Rationale: pallets that verify additional storage items (not those verified by parachain-system) from the relay should be able to proof against the relay root that gets stored in parachain-system. This PR allows to create provide additional nibles that can later be used for verifiability in other pallets --- cumulus/primitives/parachain-inherent/src/mock.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cumulus/primitives/parachain-inherent/src/mock.rs b/cumulus/primitives/parachain-inherent/src/mock.rs index 5168b46a14d..e40cb49acdd 100644 --- a/cumulus/primitives/parachain-inherent/src/mock.rs +++ b/cumulus/primitives/parachain-inherent/src/mock.rs @@ -61,6 +61,8 @@ pub struct MockValidationDataInherentDataProvider { pub raw_downward_messages: Vec>, // Inbound Horizontal messages sorted by channel pub raw_horizontal_messages: Vec<(ParaId, Vec)>, + // Additional key-value pairs that should be injected. + pub additional_key_values: Option, Vec)>>, } pub trait GenerateRandomness { @@ -210,6 +212,10 @@ impl> InherentDataProvider sproof_builder.randomness = self.relay_randomness_config.generate_randomness(self.current_para_block.into()); + if let Some(key_values) = &self.additional_key_values { + sproof_builder.additional_key_values = key_values.clone() + } + let (relay_parent_storage_root, proof) = sproof_builder.into_state_root_and_proof(); inherent_data.put_data( -- GitLab From 49874882cf3eadde01951ee48916c9811d6a8c7e Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 22 Nov 2023 19:24:11 +0100 Subject: [PATCH 558/633] polkadot-node-subsystems: `ChainApiBackend` added + `polkadot-debug` image version fixed (#2411) The out-dated version (bad tag) of [polkadot image](https://github.com/paritytech/polkadot-sdk/blob/ede4a362622dfa69eb167eaa876246b1289f4b41/.gitlab/pipeline/zombienet/cumulus.yml#L31) ([docker info](https://hub.docker.com/layers/paritypr/polkadot-debug/master/images/sha256:adb1658052cf671b50c90d5cece5c7a131efa1a95978249bd5cb85a5ad654f7a?context=explore)) was used. This PR fixes this. See also: https://github.com/paritytech/polkadot-sdk/pull/2411#issuecomment-1822632724 Also adds an abstraction that allows asynchronous backends to be passed to `ChainApiSubsystem` --------- Co-authored-by: Sebastian Kunert --- .gitlab/pipeline/zombienet/cumulus.yml | 2 +- Cargo.lock | 6 ++ .../relay-chain-minimal-node/Cargo.toml | 4 + .../src/blockchain_rpc_client.rs | 86 ++++++++++++++++++- .../src/collator_overseer.rs | 3 +- polkadot/node/core/chain-api/Cargo.toml | 5 +- polkadot/node/core/chain-api/src/lib.rs | 79 +++++++++-------- polkadot/node/core/chain-api/src/tests.rs | 21 +++-- polkadot/node/overseer/src/lib.rs | 4 +- polkadot/node/subsystem-types/Cargo.toml | 1 + polkadot/node/subsystem-types/src/lib.rs | 2 +- .../subsystem-types/src/runtime_client.rs | 57 +++++++++++- 12 files changed, 214 insertions(+), 56 deletions(-) diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 3cac67c2966..3e4df000b7f 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -28,7 +28,7 @@ - job: build-push-image-test-parachain artifacts: true variables: - POLKADOT_IMAGE: "docker.io/paritypr/polkadot-debug:master" + POLKADOT_IMAGE: "docker.io/paritypr/polkadot-debug:${DOCKER_IMAGES_VERSION}" GH_DIR: "https://github.com/paritytech/cumulus/tree/${CI_COMMIT_SHORT_SHA}/zombienet/tests" LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/cumulus/zombienet/tests" COL_IMAGE: "docker.io/paritypr/test-parachain:${DOCKER_IMAGES_VERSION}" diff --git a/Cargo.lock b/Cargo.lock index bfe24e528eb..26da3b4f825 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4183,6 +4183,7 @@ dependencies = [ "polkadot-core-primitives", "polkadot-network-bridge", "polkadot-node-collation-generation", + "polkadot-node-core-chain-api", "polkadot-node-core-prospective-parachains", "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", @@ -4190,16 +4191,19 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "sc-authority-discovery", + "sc-client-api", "sc-network", "sc-network-common", "sc-service", "sc-tracing", "sc-utils", "sp-api", + "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-runtime", "substrate-prometheus-endpoint", + "tokio", "tracing", ] @@ -12443,6 +12447,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-types", "polkadot-primitives", "sc-client-api", "sc-consensus-babe", @@ -12851,6 +12856,7 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", + "sp-blockchain", "sp-consensus-babe", "substrate-prometheus-endpoint", "thiserror", diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 53173fb4118..ce76fc5cd6d 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -19,6 +19,7 @@ polkadot-collator-protocol = { path = "../../../polkadot/node/network/collator-p polkadot-network-bridge = { path = "../../../polkadot/node/network/bridge" } polkadot-node-collation-generation = { path = "../../../polkadot/node/collation-generation" } polkadot-node-core-runtime-api = { path = "../../../polkadot/node/core/runtime-api" } +polkadot-node-core-chain-api = { path = "../../../polkadot/node/core/chain-api" } polkadot-node-core-prospective-parachains = { path = "../../../polkadot/node/core/prospective-parachains" } # substrate deps @@ -26,6 +27,7 @@ sc-authority-discovery = { path = "../../../substrate/client/authority-discovery sc-network = { path = "../../../substrate/client/network" } sc-network-common = { path = "../../../substrate/client/network/common" } sc-service = { path = "../../../substrate/client/service" } +sc-client-api = { path = "../../../substrate/client/api" } substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } sc-tracing = { path = "../../../substrate/client/tracing" } sc-utils = { path = "../../../substrate/client/utils" } @@ -33,6 +35,8 @@ sp-api = { path = "../../../substrate/primitives/api" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-consensus = { path = "../../../substrate/primitives/consensus/common" } sp-runtime = { path = "../../../substrate/primitives/runtime" } +sp-blockchain = { path = "../../../substrate/primitives/blockchain" } +tokio = { version = "1.32.0", features = ["macros"] } # cumulus deps cumulus-relay-chain-interface = { path = "../relay-chain-interface" } 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 a473b3bced0..c40ca5c858b 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 @@ -20,14 +20,16 @@ use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_relay_chain_rpc_interface::RelayChainRpcClient; use futures::{Stream, StreamExt}; use polkadot_core_primitives::{Block, BlockNumber, Hash, Header}; -use polkadot_overseer::RuntimeApiSubsystemClient; +use polkadot_overseer::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, slashing, vstaging::NodeFeatures, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; -use sp_api::{ApiError, RuntimeApiInfo}; +use sc_client_api::AuxStore; +use sp_api::{ApiError, BlockT, HeaderT, NumberFor, RuntimeApiInfo}; +use sp_blockchain::Info; #[derive(Clone)] pub struct BlockChainRpcClient { @@ -54,6 +56,64 @@ impl BlockChainRpcClient { } } +#[async_trait::async_trait] +impl ChainApiBackend for BlockChainRpcClient { + async fn header( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result::Header>> { + Ok(self.rpc_client.chain_get_header(Some(hash)).await?) + } + + async fn info(&self) -> sp_blockchain::Result> { + let (best_header_opt, genesis_hash, finalized_head) = futures::try_join!( + self.rpc_client.chain_get_header(None), + self.rpc_client.chain_get_head(Some(0)), + self.rpc_client.chain_get_finalized_head() + )?; + let best_header = best_header_opt.ok_or_else(|| { + RelayChainError::GenericError( + "Unable to retrieve best header from relay chain.".to_string(), + ) + })?; + + let finalized_header = + self.rpc_client.chain_get_header(Some(finalized_head)).await?.ok_or_else(|| { + RelayChainError::GenericError( + "Unable to retrieve finalized header from relay chain.".to_string(), + ) + })?; + Ok(Info { + best_hash: best_header.hash(), + best_number: best_header.number, + genesis_hash, + finalized_hash: finalized_head, + finalized_number: finalized_header.number, + finalized_state: Some((finalized_header.hash(), finalized_header.number)), + number_leaves: 1, + block_gap: None, + }) + } + + async fn number( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result::Header as HeaderT>::Number>> { + Ok(self + .rpc_client + .chain_get_header(Some(hash)) + .await? + .map(|maybe_header| maybe_header.number)) + } + + async fn hash( + &self, + number: NumberFor, + ) -> sp_blockchain::Result::Hash>> { + Ok(self.rpc_client.chain_get_block_hash(number.into()).await?) + } +} + #[async_trait::async_trait] impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn validators( @@ -403,3 +463,25 @@ impl BlockChainRpcClient { Ok(self.rpc_client.get_finalized_heads_stream()?.boxed()) } } + +// Implementation required by ChainApiSubsystem +// but never called in our case. +impl AuxStore for BlockChainRpcClient { + fn insert_aux< + 'a, + 'b: 'a, + 'c: 'a, + I: IntoIterator, + D: IntoIterator, + >( + &self, + _insert: I, + _delete: D, + ) -> sp_blockchain::Result<()> { + unimplemented!("Not supported on the RPC collator") + } + + fn get_aux(&self, _key: &[u8]) -> sp_blockchain::Result>> { + unimplemented!("Not supported on the RPC collator") + } +} 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 945344f85e9..a785a9f6f79 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -24,6 +24,7 @@ use polkadot_network_bridge::{ NetworkBridgeTx as NetworkBridgeTxSubsystem, }; use polkadot_node_collation_generation::CollationGenerationSubsystem; +use polkadot_node_core_chain_api::ChainApiSubsystem; use polkadot_node_core_prospective_parachains::ProspectiveParachainsSubsystem; use polkadot_node_core_runtime_api::RuntimeApiSubsystem; use polkadot_node_network_protocol::{ @@ -112,7 +113,7 @@ fn build_overseer( .candidate_backing(DummySubsystem) .candidate_validation(DummySubsystem) .pvf_checker(DummySubsystem) - .chain_api(DummySubsystem) + .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) .collator_protocol({ let side = ProtocolSide::Collator { diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index 154fa20e75d..fa824e78ffe 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -9,10 +9,9 @@ description = "The Chain API subsystem provides access to chain related utility [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -polkadot-primitives = { path = "../../../primitives" } polkadot-node-metrics = { path = "../../metrics" } polkadot-node-subsystem = { path = "../../subsystem" } +polkadot-node-subsystem-types = { path = "../../subsystem-types" } sc-client-api = { path = "../../../../substrate/client/api" } sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } @@ -21,5 +20,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] } maplit = "1.0.2" parity-scale-codec = "3.6.1" polkadot-node-primitives = { path = "../../primitives" } +polkadot-primitives = { path = "../../../primitives" } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-core = { path = "../../../../substrate/primitives/core" } +sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } diff --git a/polkadot/node/core/chain-api/src/lib.rs b/polkadot/node/core/chain-api/src/lib.rs index 9b25481d718..7fd5166310f 100644 --- a/polkadot/node/core/chain-api/src/lib.rs +++ b/polkadot/node/core/chain-api/src/lib.rs @@ -35,13 +35,13 @@ use std::sync::Arc; use futures::prelude::*; use sc_client_api::AuxStore; -use sp_blockchain::HeaderBackend; +use futures::stream::StreamExt; use polkadot_node_subsystem::{ messages::ChainApiMessage, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, }; -use polkadot_primitives::Block; +use polkadot_node_subsystem_types::ChainApiBackend; mod metrics; use self::metrics::Metrics; @@ -67,7 +67,7 @@ impl ChainApiSubsystem { #[overseer::subsystem(ChainApi, error = SubsystemError, prefix = self::overseer)] impl ChainApiSubsystem where - Client: HeaderBackend + AuxStore + 'static, + Client: ChainApiBackend + AuxStore + 'static, { fn start(self, ctx: Context) -> SpawnedSubsystem { let future = run::(ctx, self) @@ -83,7 +83,7 @@ async fn run( subsystem: ChainApiSubsystem, ) -> SubsystemResult<()> where - Client: HeaderBackend + AuxStore, + Client: ChainApiBackend + AuxStore, { loop { match ctx.recv().await? { @@ -93,13 +93,15 @@ where FromOrchestra::Communication { msg } => match msg { ChainApiMessage::BlockNumber(hash, response_channel) => { let _timer = subsystem.metrics.time_block_number(); - let result = subsystem.client.number(hash).map_err(|e| e.to_string().into()); + let result = + subsystem.client.number(hash).await.map_err(|e| e.to_string().into()); subsystem.metrics.on_request(result.is_ok()); let _ = response_channel.send(result); }, ChainApiMessage::BlockHeader(hash, response_channel) => { let _timer = subsystem.metrics.time_block_header(); - let result = subsystem.client.header(hash).map_err(|e| e.to_string().into()); + let result = + subsystem.client.header(hash).await.map_err(|e| e.to_string().into()); subsystem.metrics.on_request(result.is_ok()); let _ = response_channel.send(result); }, @@ -113,46 +115,51 @@ where ChainApiMessage::FinalizedBlockHash(number, response_channel) => { let _timer = subsystem.metrics.time_finalized_block_hash(); // Note: we don't verify it's finalized - let result = subsystem.client.hash(number).map_err(|e| e.to_string().into()); + let result = + subsystem.client.hash(number).await.map_err(|e| e.to_string().into()); subsystem.metrics.on_request(result.is_ok()); let _ = response_channel.send(result); }, ChainApiMessage::FinalizedBlockNumber(response_channel) => { let _timer = subsystem.metrics.time_finalized_block_number(); - let result = subsystem.client.info().finalized_number; - // always succeeds - subsystem.metrics.on_request(true); - let _ = response_channel.send(Ok(result)); + let result = subsystem + .client + .info() + .await + .map_err(|e| e.to_string().into()) + .map(|info| info.finalized_number); + subsystem.metrics.on_request(result.is_ok()); + let _ = response_channel.send(result); }, ChainApiMessage::Ancestors { hash, k, response_channel } => { let _timer = subsystem.metrics.time_ancestors(); gum::trace!(target: LOG_TARGET, hash=%hash, k=k, "ChainApiMessage::Ancestors"); - let mut hash = hash; - - let next_parent = core::iter::from_fn(|| { - let maybe_header = subsystem.client.header(hash); - match maybe_header { - // propagate the error - Err(e) => { - let e = e.to_string().into(); - Some(Err(e)) - }, - // fewer than `k` ancestors are available - Ok(None) => None, - Ok(Some(header)) => { - // stop at the genesis header. - if header.number == 0 { - None - } else { - hash = header.parent_hash; - Some(Ok(hash)) - } - }, - } - }); - - let result = next_parent.take(k).collect::, _>>(); + let next_parent_stream = futures::stream::unfold( + (hash, subsystem.client.clone()), + |(hash, client)| async move { + let maybe_header = client.header(hash).await; + match maybe_header { + // propagate the error + Err(e) => { + let e = e.to_string().into(); + Some((Err(e), (hash, client))) + }, + // fewer than `k` ancestors are available + Ok(None) => None, + Ok(Some(header)) => { + // stop at the genesis header. + if header.number == 0 { + None + } else { + Some((Ok(header.parent_hash), (header.parent_hash, client))) + } + }, + } + }, + ); + + let result = next_parent_stream.take(k).try_collect().await; subsystem.metrics.on_request(result.is_ok()); let _ = response_channel.send(result); }, diff --git a/polkadot/node/core/chain-api/src/tests.rs b/polkadot/node/core/chain-api/src/tests.rs index 331a4f9ba82..eae8f6fa4ac 100644 --- a/polkadot/node/core/chain-api/src/tests.rs +++ b/polkadot/node/core/chain-api/src/tests.rs @@ -22,7 +22,8 @@ use std::collections::BTreeMap; use polkadot_node_primitives::BlockWeight; use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle}; -use polkadot_primitives::{BlockNumber, Hash, Header}; +use polkadot_node_subsystem_types::ChainApiBackend; +use polkadot_primitives::{Block, BlockNumber, Hash, Header}; use sp_blockchain::Info as BlockInfo; use sp_core::testing::TaskExecutor; @@ -110,7 +111,7 @@ fn last_key_value(map: &BTreeMap) -> (K, V) { map.iter().last().map(|(k, v)| (k.clone(), v.clone())).unwrap() } -impl HeaderBackend for TestClient { +impl sp_blockchain::HeaderBackend for TestClient { fn info(&self) -> BlockInfo { let genesis_hash = self.blocks.iter().next().map(|(h, _)| *h).unwrap(); let (best_hash, best_number) = last_key_value(&self.blocks); @@ -191,8 +192,8 @@ fn request_block_number() { async move { let zero = Hash::zero(); let test_cases = [ - (TWO, client.number(TWO).unwrap()), - (zero, client.number(zero).unwrap()), // not here + (TWO, client.number(TWO).await.unwrap()), + (zero, client.number(zero).await.unwrap()), // not here ]; for (hash, expected) in &test_cases { let (tx, rx) = oneshot::channel(); @@ -217,8 +218,10 @@ fn request_block_header() { test_harness(|client, mut sender| { async move { const NOT_HERE: Hash = Hash::repeat_byte(0x5); - let test_cases = - [(TWO, client.header(TWO).unwrap()), (NOT_HERE, client.header(NOT_HERE).unwrap())]; + let test_cases = [ + (TWO, client.header(TWO).await.unwrap()), + (NOT_HERE, client.header(NOT_HERE).await.unwrap()), + ]; for (hash, expected) in &test_cases { let (tx, rx) = oneshot::channel(); @@ -270,8 +273,8 @@ fn request_finalized_hash() { test_harness(|client, mut sender| { async move { let test_cases = [ - (1, client.hash(1).unwrap()), // not here - (2, client.hash(2).unwrap()), + (1, client.hash(1).await.unwrap()), // not here + (2, client.hash(2).await.unwrap()), ]; for (number, expected) in &test_cases { let (tx, rx) = oneshot::channel(); @@ -297,7 +300,7 @@ fn request_last_finalized_number() { async move { let (tx, rx) = oneshot::channel(); - let expected = client.info().finalized_number; + let expected = client.info().await.unwrap().finalized_number; sender .send(FromOrchestra::Communication { msg: ChainApiMessage::FinalizedBlockNumber(tx), diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 5207bb830d8..da99546a44f 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -87,8 +87,8 @@ use polkadot_node_subsystem_types::messages::{ pub use polkadot_node_subsystem_types::{ errors::{SubsystemError, SubsystemResult}, - jaeger, ActivatedLeaf, ActiveLeavesUpdate, OverseerSignal, RuntimeApiSubsystemClient, - UnpinHandle, + jaeger, ActivatedLeaf, ActiveLeavesUpdate, ChainApiBackend, OverseerSignal, + RuntimeApiSubsystemClient, UnpinHandle, }; pub mod metrics; diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 9fd3775da59..8e345cf222c 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -17,6 +17,7 @@ polkadot-node-jaeger = { path = "../jaeger" } orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } sc-network = { path = "../../../substrate/client/network" } sp-api = { path = "../../../substrate/primitives/api" } +sp-blockchain = { path = "../../../substrate/primitives/blockchain" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } sc-client-api = { path = "../../../substrate/client/api" } diff --git a/polkadot/node/subsystem-types/src/lib.rs b/polkadot/node/subsystem-types/src/lib.rs index e3d6e4decf2..cd39aa03e56 100644 --- a/polkadot/node/subsystem-types/src/lib.rs +++ b/polkadot/node/subsystem-types/src/lib.rs @@ -40,7 +40,7 @@ pub mod errors; pub mod messages; mod runtime_client; -pub use runtime_client::{DefaultSubsystemClient, RuntimeApiSubsystemClient}; +pub use runtime_client::{ChainApiBackend, DefaultSubsystemClient, RuntimeApiSubsystemClient}; pub use jaeger::*; pub use polkadot_node_jaeger as jaeger; diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 8369fd215f4..36e3365cf08 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -18,17 +18,70 @@ use async_trait::async_trait; use polkadot_primitives::{ async_backing, runtime_api::ParachainHost, slashing, vstaging, Block, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id, InboundDownwardMessage, + DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; +use sc_client_api::HeaderBackend; use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_api::{ApiError, ApiExt, ProvideRuntimeApi}; +use sp_api::{ApiError, ApiExt, HeaderT, NumberFor, ProvideRuntimeApi}; use sp_authority_discovery::AuthorityDiscoveryApi; +use sp_blockchain::Info; use sp_consensus_babe::{BabeApi, Epoch}; use std::{collections::BTreeMap, sync::Arc}; +/// Offers header utilities. +/// +/// This is a async wrapper trait for ['HeaderBackend'] to be used with the +/// `ChainApiSubsystem`. +// This trait was introduced to suit the needs of collators. Depending on their operating mode, they +// might not have a client of the relay chain that can supply a synchronous HeaderBackend +// implementation. +#[async_trait] +pub trait ChainApiBackend: Send + Sync { + /// Get block header. Returns `None` if block is not found. + async fn header(&self, hash: Hash) -> sp_blockchain::Result>; + /// Get blockchain info. + async fn info(&self) -> sp_blockchain::Result>; + /// Get block number by hash. Returns `None` if the header is not in the chain. + async fn number( + &self, + hash: Hash, + ) -> sp_blockchain::Result::Number>>; + /// Get block hash by number. Returns `None` if the header is not in the chain. + async fn hash(&self, number: NumberFor) -> sp_blockchain::Result>; +} + +#[async_trait] +impl ChainApiBackend for T +where + T: HeaderBackend, +{ + /// Get block header. Returns `None` if block is not found. + async fn header(&self, hash: Hash) -> sp_blockchain::Result> { + HeaderBackend::header(self, hash) + } + + /// Get blockchain info. + async fn info(&self) -> sp_blockchain::Result> { + Ok(HeaderBackend::info(self)) + } + + /// Get block number by hash. Returns `None` if the header is not in the chain. + async fn number( + &self, + hash: Hash, + ) -> sp_blockchain::Result::Number>> { + HeaderBackend::number(self, hash) + } + + /// Get block hash by number. Returns `None` if the header is not in the chain. + async fn hash(&self, number: NumberFor) -> sp_blockchain::Result> { + HeaderBackend::hash(self, number) + } +} + /// Exposes all runtime calls that are used by the runtime API subsystem. #[async_trait] pub trait RuntimeApiSubsystemClient { -- GitLab From ec189333845fffebd45bf023b0797d6a4f121d8d Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Wed, 22 Nov 2023 17:21:20 -0500 Subject: [PATCH 559/633] Remove `#[macro_use]` annotation from `mod service` in all nodes. (#2456) This PR removes `#[macro_use]` from the service module in each of the Substrate nodes in the repo. * Parachain Template * Polkadot Parachain * Minimal Node * Node Template * Kitchen Sink Node IDK why this annotation was present, maybe from when we had the `new_partial!` macro? --------- Co-authored-by: Joshy Orndorff --- cumulus/parachain-template/node/src/main.rs | 3 +-- cumulus/polkadot-parachain/src/main.rs | 3 +-- substrate/bin/minimal/node/src/main.rs | 3 +-- substrate/bin/node-template/node/src/main.rs | 5 ++--- substrate/bin/node/cli/src/lib.rs | 6 ++---- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/cumulus/parachain-template/node/src/main.rs b/cumulus/parachain-template/node/src/main.rs index ba9f28b354f..12738a6793c 100644 --- a/cumulus/parachain-template/node/src/main.rs +++ b/cumulus/parachain-template/node/src/main.rs @@ -3,11 +3,10 @@ #![warn(missing_docs)] mod chain_spec; -#[macro_use] -mod service; mod cli; mod command; mod rpc; +mod service; fn main() -> sc_cli::Result<()> { command::run() diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index e40af8128f7..26d7dae4b8a 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -20,11 +20,10 @@ #![warn(unused_extern_crates)] mod chain_spec; -#[macro_use] -mod service; mod cli; mod command; mod rpc; +mod service; fn main() -> sc_cli::Result<()> { command::run() diff --git a/substrate/bin/minimal/node/src/main.rs b/substrate/bin/minimal/node/src/main.rs index 900651fd1fd..3cf7d98311e 100644 --- a/substrate/bin/minimal/node/src/main.rs +++ b/substrate/bin/minimal/node/src/main.rs @@ -19,11 +19,10 @@ #![warn(missing_docs)] mod chain_spec; -#[macro_use] -mod service; mod cli; mod command; mod rpc; +mod service; fn main() -> sc_cli::Result<()> { command::run() diff --git a/substrate/bin/node-template/node/src/main.rs b/substrate/bin/node-template/node/src/main.rs index 426cbabb6fb..8918dd43a01 100644 --- a/substrate/bin/node-template/node/src/main.rs +++ b/substrate/bin/node-template/node/src/main.rs @@ -1,13 +1,12 @@ //! Substrate Node Template CLI library. #![warn(missing_docs)] -mod chain_spec; -#[macro_use] -mod service; mod benchmarking; +mod chain_spec; mod cli; mod command; mod rpc; +mod service; fn main() -> sc_cli::Result<()> { command::run() diff --git a/substrate/bin/node/cli/src/lib.rs b/substrate/bin/node/cli/src/lib.rs index 2fe238ef316..0ff544932a9 100644 --- a/substrate/bin/node/cli/src/lib.rs +++ b/substrate/bin/node/cli/src/lib.rs @@ -30,16 +30,14 @@ #![warn(missing_docs)] -pub mod chain_spec; - -#[macro_use] -pub mod service; #[cfg(feature = "cli")] mod benchmarking; +pub mod chain_spec; #[cfg(feature = "cli")] mod cli; #[cfg(feature = "cli")] mod command; +pub mod service; #[cfg(feature = "cli")] pub use cli::*; -- GitLab From 2d09e83d0703ca6bf6aba773e80ea14576887ac7 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 23 Nov 2023 15:18:24 +0400 Subject: [PATCH 560/633] Add `on-chain-release-build` feature for Collectives Westend (#2463) Collectives Westend is missing an `on-chain-release-build` feature flag. --- .../collectives-westend/Cargo.toml | 108 ++++++++++-------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 94f2de33e90..79d6c697b5f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -7,69 +7,76 @@ license = "Apache-2.0" description = "Westend Collectives Parachain Runtime" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.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.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.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-alliance = { path = "../../../../../substrate/frame/alliance", 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-collective = { path = "../../../../../substrate/frame/collective", default-features = false} -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} +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-alliance = { path = "../../../../../substrate/frame/alliance", 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-collective = { path = "../../../../../substrate/frame/collective", default-features = false } +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } pallet-preimage = { path = "../../../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false} +pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } pallet-scheduler = { path = "../../../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-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-utility = { path = "../../../../../substrate/frame/utility", default-features = false} -pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false} -pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false} -pallet-core-fellowship = { path = "../../../../../substrate/frame/core-fellowship", default-features = false} -pallet-salary = { path = "../../../../../substrate/frame/salary", default-features = false} -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} +pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } +pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false } +pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false } +pallet-core-fellowship = { path = "../../../../../substrate/frame/core-fellowship", default-features = false } +pallet-salary = { path = "../../../../../substrate/frame/salary", default-features = false } +sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", 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-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} -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-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 } # Polkadot -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} -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} -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/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 } +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 } +westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = [ + "parameterized-consensus-hook", +] } +cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } @@ -84,7 +91,7 @@ testnets-common = { path = "../../../testnets-common", default-features = false substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [dev-dependencies] -sp-io = { path = "../../../../../substrate/primitives/io", features = [ "std" ]} +sp-io = { path = "../../../../../substrate/primitives/io", features = ["std"] } [features] default = [ "std" ] @@ -228,3 +235,8 @@ std = [ ] experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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" ] -- GitLab From 12062f6a3a75a36e6e61836ab15c5926d9773583 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 23 Nov 2023 17:52:06 +0400 Subject: [PATCH 561/633] CI: Disable runtime upgrade spec name check on Westend Asset Hub and fix Staking pallet migration (#2447) Westend Asset Hub currently failing because the spec name is being changed next runtime upgrade (https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4413125). This also fixes an idempotency issue with a staking pallet migration. Similar issues will be caught automatically now that we've also updated to try-runtime-cli v0.5.0 which checks for idempotency issues. This also enables try-state checks running in the CI. --- .gitlab/pipeline/check.yml | 13 +++++++------ substrate/frame/staking/src/migrations.rs | 12 +----------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 429491fb174..b2f2efc5e66 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -101,16 +101,16 @@ check-rust-feature-propagation: export RUST_LOG=remote-ext=debug,runtime=debug echo "---------- Downloading try-runtime CLI ----------" - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.3.3/try-runtime-x86_64-unknown-linux-musl -o try-runtime + curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.0/try-runtime-x86_64-unknown-linux-musl -o try-runtime chmod +x ./try-runtime echo "---------- Building ${PACKAGE} runtime ----------" time cargo build --release --locked -p "$PACKAGE" --features try-runtime echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" - time ./try-runtime \ + time ./try-runtime ${COMMAND_EXTRA_ARGS} \ --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ - on-runtime-upgrade --checks=pre-and-post ${EXTRA_ARGS} live --uri ${URI} + on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} # Check runtime migrations for Parity managed relay chains check-runtime-migration-westend: @@ -124,7 +124,7 @@ check-runtime-migration-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" + SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" check-runtime-migration-rococo: stage: check @@ -137,7 +137,7 @@ check-runtime-migration-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" + SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" # Check runtime migrations for Parity managed asset hub chains check-runtime-migration-asset-hub-westend: @@ -151,7 +151,7 @@ check-runtime-migration-asset-hub-westend: PACKAGE: "asset-hub-westend-runtime" WASM: "asset_hub_westend_runtime.compact.compressed.wasm" URI: "wss://westend-asset-hub-rpc.polkadot.io:443" - + check-runtime-migration-asset-hub-rococo: stage: check extends: @@ -214,6 +214,7 @@ check-runtime-migration-collectives-westend: PACKAGE: "collectives-westend-runtime" WASM: "collectives_westend_runtime.compact.compressed.wasm" URI: "wss://westend-collectives-rpc.polkadot.io:443" + COMMAND_EXTRA_ARGS: "--disable-spec-name-check" find-fail-ci-phrase: stage: check diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 84b00254126..311e9667ceb 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -81,20 +81,10 @@ pub mod v14 { } } - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - frame_support::ensure!( - Pallet::::on_chain_storage_version() == 13, - "Required v13 before upgrading to v14." - ); - - Ok(Default::default()) - } - #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { frame_support::ensure!( - Pallet::::on_chain_storage_version() == 14, + Pallet::::on_chain_storage_version() >= 14, "v14 not applied" ); Ok(()) -- GitLab From 21f1811c6600d8a7fe043592ff34dcb79284d583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 23 Nov 2023 14:52:46 +0100 Subject: [PATCH 562/633] sp-api: Move macro related re-exports to `__private` (#2446) This moves the macro related re-exports to `__private` to make it more obvious for downstream users that they are using an internal api. --------- Co-authored-by: command-bot <> --- Cargo.lock | 10 ++- .../relay-chain-rpc-interface/Cargo.toml | 1 + .../src/rpc_client.rs | 2 +- cumulus/pallets/xcmp-queue/src/tests.rs | 2 +- polkadot/node/service/src/lib.rs | 2 +- substrate/client/api/src/call_executor.rs | 4 +- substrate/client/api/src/in_mem.rs | 3 +- substrate/client/consensus/beefy/src/lib.rs | 4 +- .../client/consensus/beefy/src/worker.rs | 7 +- substrate/client/executor/src/wasm_runtime.rs | 15 ++-- .../merkle-mountain-range/rpc/src/lib.rs | 4 +- substrate/client/rpc-spec-v2/Cargo.toml | 2 + .../client/rpc-spec-v2/src/archive/archive.rs | 4 +- .../src/chain_head/chain_head_storage.rs | 2 +- .../rpc-spec-v2/src/chain_head/test_utils.rs | 7 +- .../rpc-spec-v2/src/chain_head/tests.rs | 2 +- substrate/client/tracing/Cargo.toml | 1 + substrate/client/tracing/src/block/mod.rs | 3 +- substrate/frame/beefy-mmr/src/lib.rs | 3 +- .../frame/contracts/src/storage/meter.rs | 3 +- substrate/frame/nfts/runtime-api/Cargo.toml | 7 +- substrate/frame/nfts/runtime-api/src/lib.rs | 2 +- .../support/test/tests/construct_runtime.rs | 2 +- substrate/primitives/api/Cargo.toml | 16 ++-- .../primitives/api/proc-macro/src/utils.rs | 6 +- substrate/primitives/api/src/lib.rs | 80 +++++++++++-------- .../primitives/consensus/beefy/Cargo.toml | 16 ++-- .../primitives/consensus/beefy/src/mmr.rs | 3 +- .../frame/benchmarking-cli/src/block/bench.rs | 8 +- .../benchmarking-cli/src/storage/write.rs | 2 +- 30 files changed, 124 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26da3b4f825..1fe9d1b8192 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1493,8 +1493,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -4237,6 +4237,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-storage 13.0.0", + "sp-version", "thiserror", "tokio", "tokio-util", @@ -10423,6 +10424,7 @@ dependencies = [ "pallet-nfts", "parity-scale-codec", "sp-api", + "sp-std 8.0.0", ] [[package]] @@ -16124,6 +16126,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", + "sp-externalities 0.19.0", "sp-maybe-compressed-blob", "sp-rpc", "sp-runtime", @@ -16357,6 +16360,7 @@ dependencies = [ "lazy_static", "libc", "log", + "parity-scale-codec", "parking_lot 0.12.1", "regex", "rustc-hash", @@ -20011,7 +20015,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 93fe57145b0..0159cade23f 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -20,6 +20,7 @@ sp-authority-discovery = { path = "../../../substrate/primitives/authority-disco sp-state-machine = { path = "../../../substrate/primitives/state-machine" } sp-storage = { path = "../../../substrate/primitives/storage" } sp-runtime = { path = "../../../substrate/primitives/runtime" } +sp-version = { path = "../../../substrate/primitives/version" } sc-client-api = { path = "../../../substrate/client/api" } sc-rpc-api = { path = "../../../substrate/client/rpc-api" } sc-service = { path = "../../../substrate/client/service" } 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 cc993c6ff9f..8e0d5fae677 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -46,10 +46,10 @@ use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use sc_client_api::StorageData; use sc_rpc_api::{state::ReadProof, system::Health}; use sc_service::TaskManager; -use sp_api::RuntimeVersion; use sp_consensus_babe::Epoch; use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_storage::StorageKey; +use sp_version::RuntimeVersion; use crate::{ light_client_worker::{build_smoldot_client, LightClientRpcWorker}, diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 30dba6ead34..f88dedc1ece 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -155,7 +155,7 @@ fn xcm_enqueueing_broken_xcm_works() { .take(20) .collect::>(), ); - EnqueuedMessages::set(&vec![]); + EnqueuedMessages::take(); // But if we do it all in one page, then it only uses the first 10: XcmpQueue::handle_xcmp_messages( diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 0ed7940b3e8..c03835b2a4b 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -98,7 +98,7 @@ pub use service::{ ChainSpec, Configuration, Error as SubstrateServiceError, PruningMode, Role, RuntimeGenesis, TFullBackend, TFullCallExecutor, TFullClient, TaskManager, TransactionPoolOptions, }; -pub use sp_api::{ApiRef, ConstructRuntimeApi, Core as CoreApi, ProvideRuntimeApi, StateBackend}; +pub use sp_api::{ApiRef, ConstructRuntimeApi, Core as CoreApi, ProvideRuntimeApi}; pub use sp_runtime::{ generic, traits::{self as runtime_traits, BlakeTwo256, Block as BlockT, Header as HeaderT, NumberFor}, diff --git a/substrate/client/api/src/call_executor.rs b/substrate/client/api/src/call_executor.rs index 49b51ccc943..d131cbcec00 100644 --- a/substrate/client/api/src/call_executor.rs +++ b/substrate/client/api/src/call_executor.rs @@ -21,12 +21,12 @@ use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_core::traits::CallContext; use sp_externalities::Extensions; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, HashingFor}; use sp_state_machine::{OverlayedChanges, StorageProof}; use std::cell::RefCell; use crate::execution_extensions::ExecutionExtensions; -use sp_api::{HashingFor, ProofRecorder}; +use sp_api::ProofRecorder; /// Executor Provider pub trait ExecutorProvider { diff --git a/substrate/client/api/src/in_mem.rs b/substrate/client/api/src/in_mem.rs index 807bdf0e334..b933ed1f17e 100644 --- a/substrate/client/api/src/in_mem.rs +++ b/substrate/client/api/src/in_mem.rs @@ -812,9 +812,8 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> { #[cfg(test)] mod tests { use crate::{in_mem::Blockchain, NewBlockState}; - use sp_api::HeaderT; use sp_blockchain::Backend; - use sp_runtime::{ConsensusEngineId, Justifications}; + use sp_runtime::{traits::Header as HeaderT, ConsensusEngineId, Justifications}; use substrate_test_runtime::{Block, Header, H256}; pub const ID1: ConsensusEngineId = *b"TST1"; diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 89a5d51c887..3d104f13250 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -40,7 +40,7 @@ use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotificatio use sc_consensus::BlockImport; use sc_network::{NetworkRequest, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; -use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; @@ -51,7 +51,7 @@ use sp_consensus_beefy::{ }; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; -use sp_runtime::traits::{Block, Zero}; +use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; use std::{ collections::{BTreeMap, VecDeque}, marker::PhantomData, diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 966c7410365..0eea5647e51 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -36,7 +36,7 @@ use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; use sc_network_gossip::GossipEngine; use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; -use sp_api::{BlockId, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ @@ -46,7 +46,7 @@ use sp_consensus_beefy::{ VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ - generic::OpaqueDigestItemId, + generic::{BlockId, OpaqueDigestItemId}, traits::{Block, Header, NumberFor, Zero}, SaturatedConversion, }; @@ -1074,13 +1074,12 @@ pub(crate) mod tests { use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network_sync::SyncingService; use sc_network_test::TestNetFactory; - use sp_api::HeaderT; use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, }; - use sp_runtime::traits::One; + use sp_runtime::traits::{Header as HeaderT, One}; use substrate_test_runtime_client::{ runtime::{Block, Digest, DigestItem, Header}, Backend, diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index 6dec3abdb20..501279a312c 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -441,6 +441,7 @@ mod tests { use codec::Encode; use sp_api::{Core, RuntimeApiInfo}; use sp_runtime::RuntimeString; + use sp_version::{create_apis_vec, RuntimeVersion}; use sp_wasm_interface::HostFunctions; use substrate_test_runtime::Block; @@ -470,7 +471,7 @@ mod tests { authoring_version: 1, spec_version: 1, impl_version: 1, - apis: sp_api::create_apis_vec!([(>::ID, 1)]), + apis: create_apis_vec!([(>::ID, 1)]), }; let version = decode_version(&old_runtime_version.encode()).unwrap(); @@ -486,7 +487,7 @@ mod tests { authoring_version: 1, spec_version: 1, impl_version: 1, - apis: sp_api::create_apis_vec!([(>::ID, 3)]), + apis: create_apis_vec!([(>::ID, 3)]), }; decode_version(&old_runtime_version.encode()).unwrap_err(); @@ -494,13 +495,13 @@ mod tests { #[test] fn new_runtime_version_decodes() { - let old_runtime_version = sp_api::RuntimeVersion { + let old_runtime_version = RuntimeVersion { spec_name: "test".into(), impl_name: "test".into(), authoring_version: 1, spec_version: 1, impl_version: 1, - apis: sp_api::create_apis_vec!([(>::ID, 3)]), + apis: create_apis_vec!([(>::ID, 3)]), transaction_version: 3, state_version: 4, }; @@ -509,13 +510,13 @@ mod tests { assert_eq!(3, version.transaction_version); assert_eq!(0, version.state_version); - let old_runtime_version = sp_api::RuntimeVersion { + let old_runtime_version = RuntimeVersion { spec_name: "test".into(), impl_name: "test".into(), authoring_version: 1, spec_version: 1, impl_version: 1, - apis: sp_api::create_apis_vec!([(>::ID, 4)]), + apis: create_apis_vec!([(>::ID, 4)]), transaction_version: 3, state_version: 4, }; @@ -538,7 +539,7 @@ mod tests { authoring_version: 100, spec_version: 100, impl_version: 100, - apis: sp_api::create_apis_vec!([(>::ID, 4)]), + apis: create_apis_vec!([(>::ID, 4)]), transaction_version: 100, state_version: 1, }; diff --git a/substrate/client/merkle-mountain-range/rpc/src/lib.rs b/substrate/client/merkle-mountain-range/rpc/src/lib.rs index 5be82b600d9..1653749ffab 100644 --- a/substrate/client/merkle-mountain-range/rpc/src/lib.rs +++ b/substrate/client/merkle-mountain-range/rpc/src/lib.rs @@ -30,14 +30,14 @@ use jsonrpsee::{ }; use serde::{Deserialize, Serialize}; -use sp_api::{ApiExt, NumberFor, ProvideRuntimeApi}; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::{ offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage}, Bytes, }; use sp_mmr_primitives::{Error as MmrError, Proof}; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, NumberFor}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index ca61286ddfa..8ca4f321f71 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -37,12 +37,14 @@ 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.108" tokio = { version = "1.22.0", features = ["macros"] } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } substrate-test-runtime = { path = "../../test-utils/runtime" } sp-consensus = { path = "../../primitives/consensus/common" } +sp-externalities = { path = "../../primitives/externalities" } sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } sc-block-builder = { path = "../block-builder" } sc-service = { path = "../service", features = ["test-helpers"]} diff --git a/substrate/client/rpc-spec-v2/src/archive/archive.rs b/substrate/client/rpc-spec-v2/src/archive/archive.rs index bded842d8fd..b2bcc62ce31 100644 --- a/substrate/client/rpc-spec-v2/src/archive/archive.rs +++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs @@ -29,13 +29,13 @@ use jsonrpsee::core::{async_trait, RpcResult}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, StorageProvider, }; -use sp_api::{CallApiAt, CallContext, NumberFor}; +use sp_api::{CallApiAt, CallContext}; 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}, + traits::{Block as BlockT, Header as HeaderT, NumberFor}, SaturatedConversion, }; use std::{collections::HashSet, marker::PhantomData, sync::Arc}; 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 6e19f59a5d6..c23489a050e 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 @@ -22,8 +22,8 @@ use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider}; use sc_utils::mpsc::TracingUnboundedSender; -use sp_api::BlockT; use sp_core::storage::well_known_keys; +use sp_runtime::traits::Block as BlockT; use crate::chain_head::event::OperationStorageItems; diff --git a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs index a901f3039ff..d63a98a5cb0 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs @@ -24,14 +24,15 @@ use sc_client_api::{ StorageData, StorageEventStream, StorageKey, StorageProvider, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; -use sp_api::{CallApiAt, CallApiAtParams, NumberFor, RuntimeVersion}; +use sp_api::{CallApiAt, CallApiAtParams}; use sp_blockchain::{BlockStatus, CachedHeaderMetadata, HeaderBackend, HeaderMetadata, Info}; use sp_consensus::BlockOrigin; use sp_runtime::{ generic::SignedBlock, - traits::{Block as BlockT, Header as HeaderT}, + traits::{Block as BlockT, Header as HeaderT, NumberFor}, Justifications, }; +use sp_version::RuntimeVersion; use std::sync::Arc; use substrate_test_runtime::{Block, Hash, Header}; @@ -235,7 +236,7 @@ impl> CallApiAt for ChainHeadMock fn initialize_extensions( &self, at: ::Hash, - extensions: &mut sp_api::Extensions, + extensions: &mut sp_externalities::Extensions, ) -> Result<(), sp_api::ApiError> { self.client.initialize_extensions(at, extensions) } 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 4e6775fe280..518b7da432b 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -34,7 +34,6 @@ use jsonrpsee::{ use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_service::client::new_in_mem; -use sp_api::BlockT; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_core::{ @@ -42,6 +41,7 @@ use sp_core::{ testing::TaskExecutor, Blake2Hasher, Hasher, }; +use sp_runtime::traits::Block as BlockT; use sp_version::RuntimeVersion; use std::{ collections::{HashMap, HashSet}, diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index ffcbf074908..796d4f1d826 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.27" +codec = { package = "parity-scale-codec", version = "3.6.1" } lazy_static = "1.4.0" libc = "0.2.121" log = { version = "0.4.17" } diff --git a/substrate/client/tracing/src/block/mod.rs b/substrate/client/tracing/src/block/mod.rs index 9ebf8e55c94..01744cd5563 100644 --- a/substrate/client/tracing/src/block/mod.rs +++ b/substrate/client/tracing/src/block/mod.rs @@ -25,6 +25,7 @@ use std::{ time::Instant, }; +use codec::Encode; use parking_lot::Mutex; use tracing::{ dispatcher, @@ -34,7 +35,7 @@ use tracing::{ use crate::{SpanDatum, TraceEvent, Values}; use sc_client_api::BlockBackend; -use sp_api::{Core, Encode, Metadata, ProvideRuntimeApi}; +use sp_api::{Core, Metadata, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::hexdisplay::HexDisplay; use sp_rpc::tracing::{BlockTrace, Span, TraceBlockResponse}; diff --git a/substrate/frame/beefy-mmr/src/lib.rs b/substrate/frame/beefy-mmr/src/lib.rs index a0bf7cdcf86..fa3caba7977 100644 --- a/substrate/frame/beefy-mmr/src/lib.rs +++ b/substrate/frame/beefy-mmr/src/lib.rs @@ -36,6 +36,7 @@ use sp_runtime::traits::{Convert, Member}; use sp_std::prelude::*; +use codec::Decode; use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; use sp_consensus_beefy::{ mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}, @@ -226,7 +227,7 @@ sp_api::decl_runtime_apis! { /// API useful for BEEFY light clients. pub trait BeefyMmrApi where - BeefyAuthoritySet: sp_api::Decode, + BeefyAuthoritySet: Decode, { /// Return the currently active BEEFY authority set proof. fn authority_set_proof() -> BeefyAuthoritySet; diff --git a/substrate/frame/contracts/src/storage/meter.rs b/substrate/frame/contracts/src/storage/meter.rs index 9f098090bc8..495cbd90db5 100644 --- a/substrate/frame/contracts/src/storage/meter.rs +++ b/substrate/frame/contracts/src/storage/meter.rs @@ -33,9 +33,8 @@ use frame_support::{ }, DefaultNoBound, RuntimeDebugNoBound, }; -use sp_api::HashT; use sp_runtime::{ - traits::{Saturating, Zero}, + traits::{Hash as HashT, Saturating, Zero}, DispatchError, FixedPointNumber, FixedU128, }; use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec}; diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index 483c4bd3234..092edaaaa89 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -14,9 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -pallet-nfts = { path = "..", default-features = false} -sp-api = { path = "../../../primitives/api", default-features = false} +pallet-nfts = { path = "..", default-features = false } +sp-api = { path = "../../../primitives/api", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [features] default = [ "std" ] -std = [ "codec/std", "pallet-nfts/std", "sp-api/std" ] +std = [ "codec/std", "pallet-nfts/std", "sp-api/std", "sp-std/std" ] diff --git a/substrate/frame/nfts/runtime-api/src/lib.rs b/substrate/frame/nfts/runtime-api/src/lib.rs index 77535c64069..816088f1b71 100644 --- a/substrate/frame/nfts/runtime-api/src/lib.rs +++ b/substrate/frame/nfts/runtime-api/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use sp_api::vec::Vec; +use sp_std::vec::Vec; sp_api::decl_runtime_apis! { pub trait NftsApi diff --git a/substrate/frame/support/test/tests/construct_runtime.rs b/substrate/frame/support/test/tests/construct_runtime.rs index 9ad51ad530e..b8341b25cb0 100644 --- a/substrate/frame/support/test/tests/construct_runtime.rs +++ b/substrate/frame/support/test/tests/construct_runtime.rs @@ -27,13 +27,13 @@ use frame_support::{ }; use frame_system::limits::{BlockLength, BlockWeights}; use scale_info::TypeInfo; -use sp_api::RuntimeVersion; use sp_core::{sr25519, ConstU64}; use sp_runtime::{ generic, traits::{BlakeTwo256, Verify}, DispatchError, ModuleError, }; +use sp_version::RuntimeVersion; parameter_types! { pub static IntegrityTestExec: u32 = 0; diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index c3a68af097b..e95333c9eeb 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -15,17 +15,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } sp-api-proc-macro = { path = "proc-macro" } -sp-core = { path = "../core", default-features = false} -sp-std = { path = "../std", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-externalities = { path = "../externalities", default-features = false, optional = true} -sp-version = { path = "../version", default-features = false} -sp-state-machine = { path = "../state-machine", default-features = false, optional = true} -sp-trie = { path = "../trie", default-features = false, optional = true} +sp-core = { path = "../core", default-features = false } +sp-std = { path = "../std", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-externalities = { path = "../externalities", default-features = false, optional = true } +sp-version = { path = "../version", default-features = false } +sp-state-machine = { path = "../state-machine", default-features = false, optional = true } +sp-trie = { path = "../trie", default-features = false, optional = true } hash-db = { version = "0.16.0", optional = true } thiserror = { version = "1.0.48", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true} +sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true } log = { version = "0.4.17", default-features = false } [dev-dependencies] diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index e261b162b5a..68f0a77a399 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -28,14 +28,14 @@ use syn::{ /// Generates the access to the `sc_client` crate. pub fn generate_crate_access() -> TokenStream { match crate_name("sp-api") { - Ok(FoundCrate::Itself) => quote!(sp_api), + Ok(FoundCrate::Itself) => quote!(sp_api::__private), Ok(FoundCrate::Name(renamed_name)) => { let renamed_name = Ident::new(&renamed_name, Span::call_site()); - quote!(#renamed_name) + quote!(#renamed_name::__private) }, Err(e) => if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { - let path = format!("{}::deps::{}", name, "sp_api"); + let path = format!("{}::deps::sp_api::__private", name); let path = syn::parse_str::(&path).expect("is a valid path; qed"); quote!( #path ) } else { diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index c122a2348b8..3b00e6b418b 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -70,48 +70,58 @@ // Make doc tests happy extern crate self as sp_api; +/// Private exports used by the macros. +/// +/// This is seen as internal API and can change at any point. #[doc(hidden)] -pub use codec::{self, Decode, DecodeLimit, Encode}; -#[doc(hidden)] -#[cfg(feature = "std")] -pub use hash_db::Hasher; -#[doc(hidden)] -pub use scale_info; -#[doc(hidden)] -pub use sp_core::offchain; -#[doc(hidden)] -#[cfg(not(feature = "std"))] -pub use sp_core::to_substrate_wasm_fn_return_value; -#[doc(hidden)] +pub mod __private { + #[cfg(feature = "std")] + mod std_imports { + pub use hash_db::Hasher; + pub use sp_core::traits::CallContext; + pub use sp_externalities::{Extension, Extensions}; + pub use sp_runtime::StateVersion; + pub use sp_state_machine::{ + Backend as StateBackend, InMemoryBackend, OverlayedChanges, StorageProof, TrieBackend, + TrieBackendBuilder, + }; + } + #[cfg(feature = "std")] + pub use std_imports::*; + + pub use crate::*; + pub use codec::{self, Decode, DecodeLimit, Encode}; + pub use scale_info; + pub use sp_core::offchain; + #[cfg(not(feature = "std"))] + pub use sp_core::to_substrate_wasm_fn_return_value; + #[cfg(feature = "frame-metadata")] + pub use sp_metadata_ir::{self as metadata_ir, frame_metadata as metadata}; + pub use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, NumberFor}, + transaction_validity::TransactionValidity, + RuntimeString, TransactionOutcome, + }; + pub use sp_std::{mem, slice, vec}; + pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; +} + #[cfg(feature = "std")] pub use sp_core::traits::CallContext; use sp_core::OpaqueMetadata; -#[doc(hidden)] #[cfg(feature = "std")] -pub use sp_externalities::{Extension, Extensions}; -#[doc(hidden)] -#[cfg(feature = "frame-metadata")] -pub use sp_metadata_ir::{self as metadata_ir, frame_metadata as metadata}; -#[doc(hidden)] +use sp_externalities::{Extension, Extensions}; +use sp_runtime::traits::Block as BlockT; #[cfg(feature = "std")] -pub use sp_runtime::StateVersion; -#[doc(hidden)] -pub use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, NumberFor}, - transaction_validity::TransactionValidity, - RuntimeString, TransactionOutcome, -}; -#[doc(hidden)] +use sp_runtime::traits::HashingFor; #[cfg(feature = "std")] -pub use sp_state_machine::{ - backend::AsTrieBackend, Backend as StateBackend, InMemoryBackend, OverlayedChanges, - StorageProof, TrieBackend, TrieBackendBuilder, -}; -#[doc(hidden)] -pub use sp_std::{mem, slice, vec}; -#[doc(hidden)] -pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; +pub use sp_runtime::TransactionOutcome; +#[cfg(feature = "std")] +pub use sp_state_machine::StorageProof; +#[cfg(feature = "std")] +use sp_state_machine::{backend::AsTrieBackend, Backend as StateBackend, OverlayedChanges}; +use sp_version::RuntimeVersion; #[cfg(feature = "std")] use std::cell::RefCell; diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 5ff0a2ebc70..e78323c8980 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -15,19 +15,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } -sp-api = { path = "../../api", default-features = false} -sp-application-crypto = { path = "../../application-crypto", default-features = false} -sp-core = { path = "../../core", default-features = false} -sp-io = { path = "../../io", default-features = false} -sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false} -sp-runtime = { path = "../../runtime", default-features = false} -sp-std = { path = "../../std", default-features = false} +sp-api = { path = "../../api", default-features = false } +sp-application-crypto = { path = "../../application-crypto", default-features = false } +sp-core = { path = "../../core", default-features = false } +sp-io = { path = "../../io", default-features = false } +sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false } +sp-runtime = { path = "../../runtime", default-features = false } +sp-std = { path = "../../std", default-features = false } strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = "1.4.0" [dev-dependencies] array-bytes = "6.1" -w3f-bls = { version = "0.1.3", features = ["std"]} +w3f-bls = { version = "0.1.3", features = ["std"] } [features] default = [ "std" ] diff --git a/substrate/primitives/consensus/beefy/src/mmr.rs b/substrate/primitives/consensus/beefy/src/mmr.rs index 660506b8763..9ac1624ca75 100644 --- a/substrate/primitives/consensus/beefy/src/mmr.rs +++ b/substrate/primitives/consensus/beefy/src/mmr.rs @@ -150,8 +150,9 @@ pub use mmr_root_provider::MmrRootProvider; mod mmr_root_provider { use super::*; use crate::{known_payloads, payload::PayloadProvider, Payload}; - use sp_api::{NumberFor, ProvideRuntimeApi}; + use sp_api::ProvideRuntimeApi; use sp_mmr_primitives::MmrApi; + use sp_runtime::traits::NumberFor; use sp_std::{marker::PhantomData, sync::Arc}; /// A [`crate::Payload`] provider where payload is Merkle Mountain Range root hash. diff --git a/substrate/utils/frame/benchmarking-cli/src/block/bench.rs b/substrate/utils/frame/benchmarking-cli/src/block/bench.rs index a028c7d438e..ef8dc29dde8 100644 --- a/substrate/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/block/bench.rs @@ -25,9 +25,13 @@ use sc_cli::{Error, Result}; use sc_client_api::{ Backend as ClientBackend, BlockBackend, HeaderBackend, StorageProvider, UsageProvider, }; -use sp_api::{ApiExt, Core, HeaderT, ProvideRuntimeApi}; +use sp_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_blockchain::Error::RuntimeApiError; -use sp_runtime::{generic::BlockId, traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as HeaderT}, + DigestItem, OpaqueExtrinsic, +}; use sp_storage::StorageKey; use clap::Args; diff --git a/substrate/utils/frame/benchmarking-cli/src/storage/write.rs b/substrate/utils/frame/benchmarking-cli/src/storage/write.rs index 4def1909ead..65941497bda 100644 --- a/substrate/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/substrate/utils/frame/benchmarking-cli/src/storage/write.rs @@ -18,10 +18,10 @@ use sc_cli::Result; use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; use sc_client_db::{DbHash, DbState, DbStateBuilder}; -use sp_api::StateBackend; use sp_blockchain::HeaderBackend; use sp_database::{ColumnId, Transaction}; use sp_runtime::traits::{Block as BlockT, HashingFor, Header as HeaderT}; +use sp_state_machine::Backend as StateBackend; use sp_trie::PrefixedMemoryDB; use log::{info, trace}; -- GitLab From 19c05e8d43fc4aef12668ecc9144bb9669cc7bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:00:54 +0000 Subject: [PATCH 563/633] Fix trait imports from sp-api (#2472) Broken after #2446. --- Cargo.lock | 1 + .../relay-chain-minimal-node/src/blockchain_rpc_client.rs | 3 ++- polkadot/node/subsystem-types/Cargo.toml | 1 + polkadot/node/subsystem-types/src/runtime_client.rs | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fe9d1b8192..abd539ea799 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12860,6 +12860,7 @@ dependencies = [ "sp-authority-discovery", "sp-blockchain", "sp-consensus-babe", + "sp-runtime", "substrate-prometheus-endpoint", "thiserror", ] 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 c40ca5c858b..d9e4155d9c5 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 @@ -28,8 +28,9 @@ use polkadot_primitives::{ }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sc_client_api::AuxStore; -use sp_api::{ApiError, BlockT, HeaderT, NumberFor, RuntimeApiInfo}; +use sp_api::{ApiError, RuntimeApiInfo}; use sp_blockchain::Info; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; #[derive(Clone)] pub struct BlockChainRpcClient { diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 8e345cf222c..71e5257cab9 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -19,6 +19,7 @@ sc-network = { path = "../../../substrate/client/network" } sp-api = { path = "../../../substrate/primitives/api" } sp-blockchain = { path = "../../../substrate/primitives/blockchain" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } +sp-runtime = { path = "../../../substrate/primitives/runtime" } sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } sc-client-api = { path = "../../../substrate/client/api" } sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 36e3365cf08..21df1483b9e 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -25,10 +25,11 @@ use polkadot_primitives::{ }; use sc_client_api::HeaderBackend; use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_api::{ApiError, ApiExt, HeaderT, NumberFor, ProvideRuntimeApi}; +use sp_api::{ApiError, ApiExt, ProvideRuntimeApi}; use sp_authority_discovery::AuthorityDiscoveryApi; use sp_blockchain::Info; use sp_consensus_babe::{BabeApi, Epoch}; +use sp_runtime::traits::{Header as HeaderT, NumberFor}; use std::{collections::BTreeMap, sync::Arc}; /// Offers header utilities. -- GitLab From c29b74dc36fc20a76cee4a029a70e7ad42fa0b6e Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Fri, 24 Nov 2023 00:14:59 +0700 Subject: [PATCH 564/633] Amend staking docs to account for state of controller deprecation (#2451) Amends some staking pallet docs, and deprecation comment, to adjust to the latest controller deprecation state. Note, do we need the `README.md` file, which is a duplicate of the pallet docs? Docs would be easier to maintain, and less ambiguity for devs to refer to, if we had one source of truth in the generated pallet docs. --- substrate/frame/staking/README.md | 12 +-- substrate/frame/staking/src/lib.rs | 93 ++++++++++----------- substrate/frame/staking/src/pallet/impls.rs | 2 +- 3 files changed, 50 insertions(+), 57 deletions(-) diff --git a/substrate/frame/staking/README.md b/substrate/frame/staking/README.md index 8c91cfcaa7f..2938e2fe770 100644 --- a/substrate/frame/staking/README.md +++ b/substrate/frame/staking/README.md @@ -24,7 +24,7 @@ be found not to be discharging its duties properly. - Nominating: The process of placing staked funds behind one or more validators in order to share in any reward, and punishment, they take. - Stash account: The account holding an owner's funds used for staking. -- Controller account: The account that controls an owner's funds for staking. +- Controller account (being deprecated): The account that controls an owner's funds for staking. - Era: A (whole) number of sessions, which is the period that the validator set (and each validator's active nominator set) is recalculated and where rewards are paid out. - Slash: The punishment of a staker by reducing its funds. @@ -45,10 +45,10 @@ The staking system in Substrate NPoS is designed to make the following possible: Almost any interaction with the Staking module requires a process of _**bonding**_ (also known as being a _staker_). To become *bonded*, a fund-holding account known as the _stash account_, which holds some or all of the funds that become -frozen in place as part of the staking process, is paired with an active **controller** account, which issues -instructions on how they shall be used. +frozen in place as part of the staking process. The controller account, which this pallet now assigns the stash account to, +issues instructions on how funds shall be used. -An account pair can become bonded using the +An account can become a bonded stash account using the [`bond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.bond) call. Stash accounts can update their associated controller back to their stash account using the @@ -231,8 +231,8 @@ following: Any funds already placed into stash can be the target of the following operations: The controller account can free a portion (or all) of the funds using the -[`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond) call. Note that the funds -are not immediately accessible. Instead, a duration denoted by +[`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond) call. Note that the +funds are not immediately accessible. Instead, a duration denoted by [`BondingDuration`](https://docs.rs/pallet-staking/latest/pallet_staking/trait.Config.html#associatedtype.BondingDuration) (in number of eras) must pass until the funds can actually be removed. Once the `BondingDuration` is over, the [`withdraw_unbonded`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.withdraw_unbonded) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 2cfee38ab4f..de989e8943d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -41,7 +41,7 @@ //! - Nominating: The process of placing staked funds behind one or more validators in order to //! share in any reward, and punishment, they take. //! - Stash account: The account holding an owner's funds used for staking. -//! - Controller account: The account that controls an owner's funds for staking. +//! - Controller account (being deprecated): The account that controls an owner's funds for staking. //! - Era: A (whole) number of sessions, which is the period that the validator set (and each //! validator's active nominator set) is recalculated and where rewards are paid out. //! - Slash: The punishment of a staker by reducing its funds. @@ -61,20 +61,20 @@ //! //! Almost any interaction with the Staking pallet requires a process of _**bonding**_ (also known //! as being a _staker_). To become *bonded*, a fund-holding register known as the _stash account_, -//! which holds some or all of the funds that become frozen in place as part of the staking process, -//! is paired with an active **controller** account, which issues instructions on how they shall be -//! used. +//! which holds some or all of the funds that become frozen in place as part of the staking process. +//! The controller account, which this pallet now assigns the stash account to, issues instructions +//! on how funds shall be used. //! -//! An account pair can become bonded using the [`bond`](Call::bond) call. +//! An account can become a bonded stash account using the [`bond`](Call::bond) call. //! -//! Stash accounts can update their associated controller back to the stash account using the +//! In the event stash accounts registered a unique controller account before the controller account +//! deprecation, they can update their associated controller back to the stash account using the //! [`set_controller`](Call::set_controller) call. //! //! There are three possible roles that any staked account pair can be in: `Validator`, `Nominator` -//! and `Idle` (defined in [`StakerStatus`]). There are three -//! corresponding instructions to change between roles, namely: -//! [`validate`](Call::validate), -//! [`nominate`](Call::nominate), and [`chill`](Call::chill). +//! and `Idle` (defined in [`StakerStatus`]). There are three corresponding instructions to change +//! between roles, namely: [`validate`](Call::validate), [`nominate`](Call::nominate), and +//! [`chill`](Call::chill). //! //! #### Validating //! @@ -85,14 +85,13 @@ //! _might_ get elected at the _next era_ as a validator. The result of the election is determined //! by nominators and their votes. //! -//! An account can become a validator candidate via the -//! [`validate`](Call::validate) call. +//! An account can become a validator candidate via the [`validate`](Call::validate) call. //! //! #### 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 -//! takes effect at the next election round. The funds in the nominator's stash account indicate the +//! 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 //! the misbehaving/offline validators as much as possible, simply because the nominators will also @@ -104,8 +103,8 @@ //! //! Staking is closely related to elections; actual validators are chosen from among all potential //! validators via election by the potential validators and nominators. To reduce use of the phrase -//! "potential validators and nominators", we often use the term **voters**, who are simply -//! the union of potential validators and nominators. +//! "potential validators and nominators", we often use the term **voters**, who are simply the +//! union of potential validators and nominators. //! //! #### Rewards and Slash //! @@ -117,10 +116,9 @@ //! `payout_stakers`, which pays the reward to the validator as well as its nominators. Only //! [`Config::MaxExposurePageSize`] nominator rewards can be claimed in a single call. When the //! number of nominators exceeds [`Config::MaxExposurePageSize`], then the exposed nominators are -//! stored in multiple pages, with each page containing up to -//! [`Config::MaxExposurePageSize`] nominators. To pay out all nominators, `payout_stakers` must be -//! called once for each available page. Paging exists to limit the i/o cost to mutate storage for -//! each nominator's account. +//! stored in multiple pages, with each page containing up to [`Config::MaxExposurePageSize`] +//! nominators. To pay out all nominators, `payout_stakers` must be called once for each available +//! page. Paging exists to limit the i/o cost to mutate storage for each nominator's account. //! //! Slashing can occur at any point in time, once misbehavior is reported. Once slashing is //! determined, a value is deducted from the balance of the validator and all the nominators who @@ -165,18 +163,18 @@ //! //! #[frame_support::pallet(dev_mode)] //! pub mod pallet { -//! use super::*; -//! use frame_support::pallet_prelude::*; -//! use frame_system::pallet_prelude::*; +//! use super::*; +//! use frame_support::pallet_prelude::*; +//! use frame_system::pallet_prelude::*; //! -//! #[pallet::pallet] -//! pub struct Pallet(_); +//! #[pallet::pallet] +//! pub struct Pallet(_); //! -//! #[pallet::config] -//! pub trait Config: frame_system::Config + staking::Config {} +//! #[pallet::config] +//! pub trait Config: frame_system::Config + staking::Config {} //! -//! #[pallet::call] -//! impl Pallet { +//! #[pallet::call] +//! impl Pallet { //! /// Reward a validator. //! #[pallet::weight(0)] //! pub fn reward_myself(origin: OriginFor) -> DispatchResult { @@ -193,8 +191,8 @@ //! //! ### Era payout //! -//! The era payout is computed using yearly inflation curve defined at -//! [`Config::EraPayout`] as such: +//! The era payout is computed using yearly inflation curve defined at [`Config::EraPayout`] as +//! such: //! //! ```nocompile //! staker_payout = yearly_inflation(npos_token_staked / total_tokens) * total_tokens / era_per_year @@ -204,8 +202,7 @@ //! ```nocompile //! remaining_payout = max_yearly_inflation * total_tokens / era_per_year - staker_payout //! ``` -//! The remaining reward is send to the configurable end-point -//! [`Config::RewardRemainder`]. +//! The remaining reward is send to the configurable end-point [`Config::RewardRemainder`]. //! //! ### Reward Calculation //! @@ -219,9 +216,8 @@ //! they received during the era. Points are added to a validator using //! [`reward_by_ids`](Pallet::reward_by_ids). //! -//! [`Pallet`] implements -//! [`pallet_authorship::EventHandler`] to add reward -//! points to block producer and block producer of referenced uncles. +//! [`Pallet`] implements [`pallet_authorship::EventHandler`] to add reward points to block producer +//! and block producer of referenced uncles. //! //! The validator and its nominator split their reward as following: //! @@ -232,13 +228,12 @@ //! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at -//! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across -//! pages may be unsorted. The total commission is paid out proportionally across pages based on the -//! total stake of the page. +//! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across pages may be +//! unsorted. The total commission is paid out proportionally across pages based on the total stake +//! of the page. //! //! All entities who receive a reward have the option to choose their reward destination through the -//! [`Payee`] storage item (see -//! [`set_payee`](Call::set_payee)), to be one of the following: +//! [`Payee`] storage item (see [`set_payee`](Call::set_payee)), to be one of the following: //! //! - Stash account, not increasing the staked value. //! - Stash account, also increasing the staked value. @@ -249,12 +244,10 @@ //! Any funds already placed into stash can be the target of the following operations: //! //! The controller account can free a portion (or all) of the funds using the -//! [`unbond`](Call::unbond) call. Note that the funds are not immediately -//! accessible. Instead, a duration denoted by -//! [`Config::BondingDuration`] (in number of eras) must -//! pass until the funds can actually be removed. Once the `BondingDuration` is over, the -//! [`withdraw_unbonded`](Call::withdraw_unbonded) call can be used to actually -//! withdraw the funds. +//! [`unbond`](Call::unbond) call. Note that the funds are not immediately accessible. Instead, a +//! duration denoted by [`Config::BondingDuration`] (in number of eras) must pass until the funds +//! can actually be removed. Once the `BondingDuration` is over, the +//! [`withdraw_unbonded`](Call::withdraw_unbonded) call can be used to actually withdraw the funds. //! //! Note that there is a limitation to the number of fund-chunks that can be scheduled to be //! unlocked in the future via [`unbond`](Call::unbond). In case this maximum @@ -274,8 +267,8 @@ //! //! ## GenesisConfig //! -//! The Staking pallet depends on the [`GenesisConfig`]. The -//! `GenesisConfig` is optional and allow to set some initial stakers. +//! The Staking pallet depends on the [`GenesisConfig`]. The `GenesisConfig` is optional and allow +//! to set some initial stakers. //! //! ## Related Modules //! @@ -405,7 +398,7 @@ pub enum RewardDestination { /// Pay into the stash account, not increasing the amount at stake. Stash, #[deprecated( - note = "`Controller` will be removed after January 2024. Use `Account(controller)` instead. This variant now behaves the same as `Stash` variant." + note = "`Controller` will be removed after January 2024. Use `Account(controller)` instead." )] Controller, /// Pay into a specified account. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 6ea8e4c9d3b..e18d9378b5e 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -359,7 +359,7 @@ impl Pallet { #[allow(deprecated)] RewardDestination::Controller => Self::bonded(stash) .map(|controller| { - defensive!("Paying out controller as reward destination which is deprecated and should be migrated"); + defensive!("Paying out controller as reward destination which is deprecated and should be migrated."); // This should never happen once payees with a `Controller` variant have been migrated. // But if it does, just pay the controller account. T::Currency::deposit_creating(&controller, amount) -- GitLab From a00a767604db59e4f045f8e73e90c6c8b7ff95c5 Mon Sep 17 00:00:00 2001 From: Lulu Date: Fri, 24 Nov 2023 09:07:35 +0000 Subject: [PATCH 565/633] Make publish CI consistant and bump to v0.3.0 (#2453) --- .github/workflows/check-publish.yml | 7 ++----- .github/workflows/claim-crates.yml | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check-publish.yml b/.github/workflows/check-publish.yml index c0d2b889381..db0863888b8 100644 --- a/.github/workflows/check-publish.yml +++ b/.github/workflows/check-publish.yml @@ -10,10 +10,7 @@ on: jobs: check-publish: - strategy: - matrix: - os: ["ubuntu-latest"] - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 @@ -23,7 +20,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish --profile dev + run: cargo install parity-publish@0.3.0 - name: parity-publish check run: parity-publish check --allow-unpublished diff --git a/.github/workflows/claim-crates.yml b/.github/workflows/claim-crates.yml index 345d24c7566..0bd5593b54f 100644 --- a/.github/workflows/claim-crates.yml +++ b/.github/workflows/claim-crates.yml @@ -18,7 +18,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.2.0 + run: cargo install parity-publish@0.3.0 - name: parity-publish claim env: -- GitLab From 4163152506883c985e82d2730693910aabd65a2d Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Fri, 24 Nov 2023 22:13:57 +1300 Subject: [PATCH 566/633] pallet-xcm: ensure xcm outcome is always complete, revert effects otherwise (#2405) On extrinsics/call, ensure local XCM execution is complete/successful. Otherwise, fail the extrinsic so that state changes don't get committed to the db. Added regression tests that fail without the fix. fixes #2237 --------- Co-authored-by: Adrian Catangiu --- Cargo.lock | 1 + .../assets/test-utils/src/test_cases.rs | 8 +- .../test-utils/src/test_cases_over_bridge.rs | 4 +- polkadot/xcm/pallet-xcm/src/lib.rs | 28 ++++-- polkadot/xcm/pallet-xcm/src/mock.rs | 7 ++ .../pallet-xcm/src/tests/assets_transfer.rs | 58 +++++++++++++ polkadot/xcm/pallet-xcm/src/tests/mod.rs | 48 ++++++++++- polkadot/xcm/src/v3/traits.rs | 4 +- .../xcm-executor/integration-tests/Cargo.toml | 1 + .../xcm-executor/integration-tests/src/lib.rs | 86 ++++++++++++++----- 10 files changed, 210 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abd539ea799..ab51be3d5db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21504,6 +21504,7 @@ dependencies = [ "frame-support", "frame-system", "futures", + "pallet-transaction-payment", "pallet-xcm", "parity-scale-codec", "polkadot-test-client", 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 f1cc76350a0..915d99470c3 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -152,7 +152,7 @@ pub fn teleports_for_native_asset_works< hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Parent), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); // check Balances after assert_ne!(>::free_balance(&target_account), 0.into()); @@ -499,7 +499,7 @@ pub fn teleports_for_foreign_assets_works< hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); // checks target_account after assert_eq!( @@ -1211,7 +1211,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); // check events let mut events = >::events() @@ -1319,7 +1319,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); additional_checks_after(); }) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 851fcd5c7d6..8007b275cb5 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -483,7 +483,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< XcmReceivedFrom::Sibling, ), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); // author actual balance after (received fees from Trader for ForeignAssets) let author_received_fees = @@ -588,7 +588,7 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), ); - assert_eq!(outcome.ensure_complete(), Ok(())); + assert_ok!(outcome.ensure_complete()); assert_eq!(is_congested, pallet_xcm_bridge_hub_router::Pallet::::bridge().is_congested); }; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 38ea7555fc3..74a24b132da 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -547,7 +547,7 @@ pub mod pallet { InvalidAssetUnsupportedReserve, /// Too many assets with different reserve locations have been attempted for transfer. TooManyReserves, - /// Local XCM execution of asset transfer incomplete. + /// Local XCM execution incomplete. LocalExecutionIncomplete, } @@ -1009,8 +1009,14 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { + log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); let outcome = >::execute(origin, message, max_weight)?; - Ok(Some(outcome.weight_used().saturating_add(T::WeightInfo::execute())).into()) + let weight_used = outcome.weight_used(); + outcome.ensure_complete().map_err(|error| { + log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); + Error::::LocalExecutionIncomplete + })?; + Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } /// Extoll that a particular destination can be communicated with through a particular @@ -1495,13 +1501,25 @@ impl Pallet { let outcome = T::XcmExecutor::execute_xcm_in_credit(origin, local_xcm, hash, weight, weight); Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - if let Some(remote_xcm) = remote_xcm { - outcome.ensure_complete().map_err(|_| Error::::LocalExecutionIncomplete)?; + outcome.ensure_complete().map_err(|error| { + log::error!( + target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + "XCM execution failed with error {:?}", error + ); + Error::::LocalExecutionIncomplete + })?; + if let Some(remote_xcm) = remote_xcm { let (ticket, price) = validate_send::(dest, remote_xcm.clone()) .map_err(Error::::from)?; if origin != Here.into_location() { - Self::charge_fees(origin, price).map_err(|_| Error::::FeesNotMet)?; + Self::charge_fees(origin, price).map_err(|error| { + log::error!( + target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + "Unable to charge fee with error {:?}", error + ); + Error::::FeesNotMet + })?; } let message_id = T::XcmRouter::deliver(ticket).map_err(Error::::from)?; diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index e744cefb162..0b0f795100c 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -153,6 +153,7 @@ construct_runtime!( thread_local! { pub static SENT_XCM: RefCell)>> = RefCell::new(Vec::new()); + pub static FAIL_SEND_XCM: RefCell = RefCell::new(false); } pub(crate) fn sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> { SENT_XCM.with(|q| (*q.borrow()).clone()) @@ -164,6 +165,9 @@ pub(crate) fn take_sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> { r }) } +pub(crate) fn set_send_xcm_artificial_failure(should_fail: bool) { + FAIL_SEND_XCM.with(|q| *q.borrow_mut() = should_fail); +} /// Sender that never returns error. pub struct TestSendXcm; impl SendXcm for TestSendXcm { @@ -172,6 +176,9 @@ impl SendXcm for TestSendXcm { dest: &mut Option, msg: &mut Option>, ) -> SendResult<(MultiLocation, Xcm<()>)> { + if FAIL_SEND_XCM.with(|q| *q.borrow()) { + return Err(SendError::Transport("Intentional send failure used in tests")) + } let pair = (dest.take().unwrap(), msg.take().unwrap()); Ok((pair, MultiAssets::new())) } diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index bf39e1ca288..d1b298765e2 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -1457,3 +1457,61 @@ fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() { ); }); } + +/// Test failure to complete execution of local XCM instructions reverts intermediate side-effects. +/// +/// Extrinsic will execute XCM to withdraw & burn reserve-based assets, then fail sending XCM to +/// reserve chain for releasing reserve assets. Assert that the previous instructions (withdraw & +/// burn) effects are reverted. +#[test] +fn intermediary_error_reverts_side_effects() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 142; + let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // transfer destination is some other parachain + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // introduce artificial error in sending outbound XCM + set_send_xcm_artificial_failure(true); + + // do the transfer - extrinsic should completely fail on xcm send failure + assert!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ) + .is_err()); + + // Alice no changes + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Destination account (parachain account) no changes + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify total and active issuance of USDC has not changed + assert_eq!(Assets::total_issuance(usdc_id_multilocation), usdc_initial_local_amount); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), usdc_initial_local_amount); + // Verify no XCM program sent + assert_eq!(sent_xcm(), vec![]); + }); +} diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 72814e507f2..056c7dcc196 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -445,7 +445,7 @@ fn trapped_assets_can_be_claimed() { assert_eq!(AssetTraps::::iter().collect::>(), vec![]); let weight = BaseXcmWeight::get() * 3; - assert_ok!(XcmPallet::execute( + assert_ok!(>::execute( RuntimeOrigin::signed(ALICE), Box::new(VersionedXcm::from(Xcm(vec![ ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, @@ -459,6 +459,52 @@ fn trapped_assets_can_be_claimed() { }); } +/// Test failure to complete execution reverts intermediate side-effects. +/// +/// XCM program will withdraw and deposit some assets, then fail execution of a further withdraw. +/// Assert that the previous instructions effects are reverted. +#[test] +fn incomplete_execute_reverts_side_effects() { + let balances = vec![(ALICE, INITIAL_BALANCE), (BOB, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + let weight = BaseXcmWeight::get() * 4; + let dest: MultiLocation = Junction::AccountId32 { network: None, id: BOB.into() }.into(); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + let amount_to_send = INITIAL_BALANCE - ExistentialDeposit::get(); + let assets: MultiAssets = (Here, amount_to_send).into(); + let result = XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + // Withdraw + BuyExec + Deposit should work + WithdrawAsset(assets.clone()), + buy_execution(assets.inner()[0].clone()), + DepositAsset { assets: assets.clone().into(), beneficiary: dest }, + // Withdrawing once more will fail because of InsufficientBalance, and we expect to + // revert the effects of the above instructions as well + WithdrawAsset(assets), + ]))), + weight, + ); + // all effects are reverted and balances unchanged for either sender or receiver + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE); + assert_eq!( + result, + Err(sp_runtime::DispatchErrorWithPostInfo { + post_info: frame_support::dispatch::PostDispatchInfo { + actual_weight: None, + pays_fee: frame_support::dispatch::Pays::Yes, + }, + error: sp_runtime::DispatchError::Module(sp_runtime::ModuleError { + index: 4, + error: [24, 0, 0, 0,], + message: Some("LocalExecutionIncomplete") + }) + }) + ); + }); +} + #[test] fn fake_latest_versioned_multilocation_works() { use codec::Encode; diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index 1043d17b710..6054bf1456a 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -275,9 +275,9 @@ pub enum Outcome { } impl Outcome { - pub fn ensure_complete(self) -> Result { + pub fn ensure_complete(self) -> result::Result { match self { - Outcome::Complete(_) => Ok(()), + Outcome::Complete(weight) => Ok(weight), Outcome::Incomplete(_, e) => Err(e), Outcome::Error(e) => Err(e), } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index d869fc6f2dc..ddb45965ee4 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -12,6 +12,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system" } futures = "0.3.21" +pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-test-client = { path = "../../../node/test/client" } polkadot-test-runtime = { path = "../../../runtime/test-runtime" } diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index d8c77f8317e..c02cb218885 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -76,33 +76,59 @@ fn transact_recursion_limit_works() { sp_tracing::try_init_simple(); let mut client = TestClientBuilder::new().build(); - let mut msg = Xcm(vec![ClearOrigin]); - let max_weight = ::Weigher::weight(&mut msg).unwrap(); - let mut call = polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg)), - max_weight, - }); - - for _ in 0..11 { - let mut msg = Xcm(vec![ - WithdrawAsset((Parent, 1_000).into()), - BuyExecution { fees: (Parent, 1).into(), weight_limit: Unlimited }, + let base_xcm = |call: polkadot_test_runtime::RuntimeCall| { + Xcm(vec![ + WithdrawAsset((Here, 1_000).into()), + BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Native, require_weight_at_most: call.get_dispatch_info().weight, call: call.encode().into(), }, - ]); + ]) + }; + let mut call: Option = None; + // set up transacts with recursive depth of 11 + for depth in (1..12).rev() { + let mut msg; + match depth { + // this one should fail with `XcmError::ExceedsStackLimit` + 11 => { + msg = Xcm(vec![ClearOrigin]); + }, + // this one checks that the inner one (depth 11) fails as expected, + // itself should not fail => should have outcome == Complete + 10 => { + let inner_call = call.take().unwrap(); + let expected_transact_status = + sp_runtime::DispatchError::Module(sp_runtime::ModuleError { + index: 27, + error: [24, 0, 0, 0], + message: Some("LocalExecutionIncomplete"), + }) + .encode() + .into(); + msg = base_xcm(inner_call); + msg.inner_mut().push(ExpectTransactStatus(expected_transact_status)); + }, + // these are the outer 9 calls that expect `ExpectTransactStatus(Success)` + d if d >= 1 && d <= 9 => { + let inner_call = call.take().unwrap(); + msg = base_xcm(inner_call); + msg.inner_mut().push(ExpectTransactStatus(MaybeErrorCode::Success)); + }, + _ => unreachable!(), + } let max_weight = ::Weigher::weight(&mut msg).unwrap(); - call = polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg)), + call = Some(polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { + message: Box::new(VersionedXcm::from(msg.clone())), max_weight, - }); + })); } let mut block_builder = client.init_polkadot_block_builder(); - let execute = construct_extrinsic(&client, call, sp_keyring::Sr25519Keyring::Alice, 0); + let execute = construct_extrinsic(&client, call.unwrap(), sp_keyring::Sr25519Keyring::Alice, 0); block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic"); @@ -113,11 +139,29 @@ fn transact_recursion_limit_works() { .expect("imports the block"); client.state_at(block_hash).expect("state should exist").inspect_state(|| { - assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!( - r.event, - polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted { - outcome: Outcome::Incomplete(_, XcmError::ExceedsStackLimit) - }), + let events = polkadot_test_runtime::System::events(); + // verify 10 pallet_xcm calls were successful + assert_eq!( + polkadot_test_runtime::System::events() + .iter() + .filter(|r| matches!( + r.event, + polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted { + outcome: Outcome::Complete(_) + }), + )) + .count(), + 10 + ); + // verify transaction fees have been paid + assert!(events.iter().any(|r| matches!( + &r.event, + polkadot_test_runtime::RuntimeEvent::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: payer, + .. + } + ) if *payer == sp_keyring::Sr25519Keyring::Alice.into(), ))); }); } -- GitLab From f086d540ae06b891f1a03bc1281809821d38a6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 24 Nov 2023 10:36:22 +0100 Subject: [PATCH 567/633] pallet-staking: Converts all math operations to safe (#2435) This PR converts unsafe math operations to safe in the staking pallet. Closes https://github.com/paritytech/polkadot-sdk/issues/2431 --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/staking/src/lib.rs | 11 +++++---- substrate/frame/staking/src/pallet/impls.rs | 14 ++++++----- substrate/frame/staking/src/pallet/mod.rs | 4 ++- substrate/frame/staking/src/slashing.rs | 27 ++++++++++++--------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index de989e8943d..e6250bb9681 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -530,12 +530,12 @@ impl StakingLedger { let mut unlocking_balance = BalanceOf::::zero(); while let Some(last) = self.unlocking.last_mut() { - if unlocking_balance + last.value <= value { + if unlocking_balance.defensive_saturating_add(last.value) <= value { unlocking_balance += last.value; self.active += last.value; self.unlocking.pop(); } else { - let diff = value - unlocking_balance; + let diff = value.defensive_saturating_sub(unlocking_balance); unlocking_balance += diff; self.active += diff; @@ -589,7 +589,7 @@ impl StakingLedger { // for a `slash_era = x`, any chunk that is scheduled to be unlocked at era `x + 28` // (assuming 28 is the bonding duration) onwards should be slashed. - let slashable_chunks_start = slash_era + T::BondingDuration::get(); + let slashable_chunks_start = slash_era.saturating_add(T::BondingDuration::get()); // `Some(ratio)` if this is proportional, with `ratio`, `None` otherwise. In both cases, we // slash first the active chunk, and then `slash_chunks_priority`. @@ -1185,8 +1185,9 @@ impl EraInfo { let nominator_count = exposure.others.len(); // expected page count is the number of nominators divided by the page size, rounded up. - let expected_page_count = - nominator_count.defensive_saturating_add(page_size as usize - 1) / page_size as usize; + let expected_page_count = nominator_count + .defensive_saturating_add((page_size as usize).defensive_saturating_sub(1)) + .saturating_div(page_size as usize); let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index e18d9378b5e..d294686751c 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, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, TryCollect, - UnixTime, + Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, + OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; @@ -148,7 +148,7 @@ impl Pallet { // `consolidate_unlocked` strictly subtracts balance. if new_total < old_total { // Already checked that this won't overflow by entry condition. - let value = old_total - new_total; + let value = old_total.defensive_saturating_sub(new_total); Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } @@ -262,7 +262,8 @@ impl Pallet { // total commission validator takes across all nominator pages let validator_total_commission_payout = validator_commission * validator_total_payout; - let validator_leftover_payout = validator_total_payout - validator_total_commission_payout; + let validator_leftover_payout = + validator_total_payout.defensive_saturating_sub(validator_total_commission_payout); // Now let's calculate how this is split to the validator. let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; @@ -475,7 +476,7 @@ impl Pallet { bonded.push((active_era, start_session)); if active_era > bonding_duration { - let first_kept = active_era - bonding_duration; + let first_kept = active_era.defensive_saturating_sub(bonding_duration); // Prune out everything that's from before the first-kept index. let n_to_prune = @@ -501,7 +502,8 @@ impl Pallet { if let Some(active_era_start) = active_era.start { let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::(); - let era_duration = (now_as_millis_u64 - active_era_start).saturated_into::(); + let era_duration = (now_as_millis_u64.defensive_saturating_sub(active_era_start)) + .saturated_into::(); let staked = Self::eras_total_stake(&active_era.index); let issuance = T::Currency::total_issuance(); let (validator_payout, remainder) = diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index a68e9c90da9..1f79ef63a47 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1068,7 +1068,9 @@ pub mod pallet { ensure!(ledger.active >= min_active_bond, Error::::InsufficientBond); // Note: in case there is no current era it is fine to bond one era more. - let era = Self::current_era().unwrap_or(0) + T::BondingDuration::get(); + let era = Self::current_era() + .unwrap_or(0) + .defensive_saturating_add(T::BondingDuration::get()); if let Some(chunk) = ledger.unlocking.last_mut().filter(|chunk| chunk.era == era) { // To keep the chunk count down, we only keep one chunk per era. Since // `unlocking` is a FiFo queue, if a chunk exists for `era` we know that it will diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 0d84d503733..709fd1441ec 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -57,7 +57,7 @@ use crate::{ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, - traits::{Currency, Defensive, Get, Imbalance, OnUnbalanced}, + traits::{Currency, Defensive, DefensiveSaturating, Get, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -85,7 +85,7 @@ pub(crate) struct SlashingSpan { impl SlashingSpan { fn contains_era(&self, era: EraIndex) -> bool { - self.start <= era && self.length.map_or(true, |l| self.start + l > era) + self.start <= era && self.length.map_or(true, |l| self.start.saturating_add(l) > era) } } @@ -123,15 +123,15 @@ impl SlashingSpans { // returns `true` if a new span was started, `false` otherwise. `false` indicates // that internal state is unchanged. pub(crate) fn end_span(&mut self, now: EraIndex) -> bool { - let next_start = now + 1; + let next_start = now.defensive_saturating_add(1); if next_start <= self.last_start { return false } - let last_length = next_start - self.last_start; + let last_length = next_start.defensive_saturating_sub(self.last_start); self.prior.insert(0, last_length); self.last_start = next_start; - self.span_index += 1; + self.span_index.defensive_saturating_accrue(1); true } @@ -141,9 +141,9 @@ impl SlashingSpans { let mut index = self.span_index; let last = SlashingSpan { index, start: last_start, length: None }; let prior = self.prior.iter().cloned().map(move |length| { - let start = last_start - length; + let start = last_start.defensive_saturating_sub(length); last_start = start; - index -= 1; + index.defensive_saturating_reduce(1); SlashingSpan { index, start, length: Some(length) } }); @@ -164,13 +164,18 @@ impl SlashingSpans { let old_idx = self .iter() .skip(1) // skip ongoing span. - .position(|span| span.length.map_or(false, |len| span.start + len <= window_start)); + .position(|span| { + span.length + .map_or(false, |len| span.start.defensive_saturating_add(len) <= window_start) + }); - let earliest_span_index = self.span_index - self.prior.len() as SpanIndex; + let earliest_span_index = + self.span_index.defensive_saturating_sub(self.prior.len() as SpanIndex); let pruned = match old_idx { Some(o) => { self.prior.truncate(o); - let new_earliest = self.span_index - self.prior.len() as SpanIndex; + let new_earliest = + self.span_index.defensive_saturating_sub(self.prior.len() as SpanIndex); Some((earliest_span_index, new_earliest)) }, None => None, @@ -500,7 +505,7 @@ impl<'a, T: 'a + Config> InspectingSpans<'a, T> { let reward = if span_record.slashed < slash { // new maximum span slash. apply the difference. - let difference = slash - span_record.slashed; + let difference = slash.defensive_saturating_sub(span_record.slashed); span_record.slashed = slash; // compute reward. -- GitLab From e3242d2c1e2018395c218357046cc88caaed78f3 Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Fri, 24 Nov 2023 18:32:43 +0800 Subject: [PATCH 568/633] Adapt test worker to profile flag (#2450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #2194 cc @mrcnski --------- Co-authored-by: Bastian Köcher --- .../benches/host_prepare_rococo_runtime.rs | 2 +- polkadot/node/core/pvf/build.rs | 21 +++++++++++++++++++ polkadot/node/core/pvf/src/testing.rs | 11 +++++----- polkadot/node/core/pvf/tests/it/main.rs | 2 +- .../node/core/pvf/tests/it/worker_common.rs | 6 +++--- 5 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 polkadot/node/core/pvf/build.rs diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index f2551b701c2..e625a2303b5 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -36,7 +36,7 @@ impl TestHost { where F: FnOnce(&mut Config), { - let (prepare_worker_path, execute_worker_path) = testing::build_workers_and_get_paths(true); + let (prepare_worker_path, execute_worker_path) = testing::build_workers_and_get_paths(); let cache_dir = tempfile::tempdir().unwrap(); let mut config = Config::new( diff --git a/polkadot/node/core/pvf/build.rs b/polkadot/node/core/pvf/build.rs new file mode 100644 index 00000000000..e01cc6deecc --- /dev/null +++ b/polkadot/node/core/pvf/build.rs @@ -0,0 +1,21 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +fn main() { + if let Ok(profile) = std::env::var("PROFILE") { + println!(r#"cargo:rustc-cfg=build_type="{}""#, profile); + } +} diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 400b65bfe7d..c7c885c4342 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -59,21 +59,22 @@ pub fn validate_candidate( /// /// NOTE: This should only be called in dev code (tests, benchmarks) as it relies on the relative /// paths of the built workers. -pub fn build_workers_and_get_paths(is_bench: bool) -> (PathBuf, PathBuf) { +pub fn build_workers_and_get_paths() -> (PathBuf, PathBuf) { // Only needs to be called once for the current process. static WORKER_PATHS: OnceLock> = OnceLock::new(); - fn build_workers(is_bench: bool) { + fn build_workers() { let mut build_args = vec![ "build", "--package=polkadot", "--bin=polkadot-prepare-worker", "--bin=polkadot-execute-worker", ]; - if is_bench { - // Benches require --release. Regular tests are debug (no flag needed). + + if cfg!(build_type = "release") { build_args.push("--release"); } + let mut cargo = std::process::Command::new("cargo"); let cmd = cargo // wasm runtime not needed @@ -117,7 +118,7 @@ pub fn build_workers_and_get_paths(is_bench: bool) -> (PathBuf, PathBuf) { } } - build_workers(is_bench); + build_workers(); Mutex::new((prepare_worker_path, execute_worker_path)) }); diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index b53d598cd0f..bd6b04182fd 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -52,7 +52,7 @@ impl TestHost { where F: FnOnce(&mut Config), { - let (prepare_worker_path, execute_worker_path) = build_workers_and_get_paths(false); + let (prepare_worker_path, execute_worker_path) = build_workers_and_get_paths(); let cache_dir = tempfile::tempdir().unwrap(); let mut config = Config::new( diff --git a/polkadot/node/core/pvf/tests/it/worker_common.rs b/polkadot/node/core/pvf/tests/it/worker_common.rs index 0d33af7e096..4b736b08ba6 100644 --- a/polkadot/node/core/pvf/tests/it/worker_common.rs +++ b/polkadot/node/core/pvf/tests/it/worker_common.rs @@ -23,7 +23,7 @@ use std::{env, time::Duration}; // Test spawning a program that immediately exits with a failure code. #[tokio::test] async fn spawn_immediate_exit() { - let (prepare_worker_path, _) = build_workers_and_get_paths(false); + let (prepare_worker_path, _) = build_workers_and_get_paths(); // There's no explicit `exit` subcommand in the worker; it will panic on an unknown // subcommand anyway @@ -41,7 +41,7 @@ async fn spawn_immediate_exit() { #[tokio::test] async fn spawn_timeout() { - let (_, execute_worker_path) = build_workers_and_get_paths(false); + let (_, execute_worker_path) = build_workers_and_get_paths(); let result = spawn_with_program_path( "integration-test", @@ -57,7 +57,7 @@ async fn spawn_timeout() { #[tokio::test] async fn should_connect() { - let (prepare_worker_path, _) = build_workers_and_get_paths(false); + let (prepare_worker_path, _) = build_workers_and_get_paths(); let _ = spawn_with_program_path( "integration-test", -- GitLab From 471eafcb8de32c0aac393a3cf3874ae62a495bf8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 24 Nov 2023 13:52:55 +0100 Subject: [PATCH 569/633] Disable any peer connections for parachain nodes in pov-recovery zombienet test (#2475) I noticed that this test broke at some point. The parachain nodes should only acquire their blocks from the relay chain. But they were connecting to their peers and started fetching blocks from there. In this test I now take additional measures so we check that each nodes really uses pov-recovery to get the blocks. --- cumulus/zombienet/tests/0002-pov_recovery.toml | 10 +++++----- cumulus/zombienet/tests/0002-pov_recovery.zndsl | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cumulus/zombienet/tests/0002-pov_recovery.toml b/cumulus/zombienet/tests/0002-pov_recovery.toml index 34cacbc2a9b..105e4a324f3 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.toml +++ b/cumulus/zombienet/tests/0002-pov_recovery.toml @@ -48,7 +48,7 @@ add_to_genesis = false validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}","--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0","--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # we fail recovery for 'eve' from time to time to test retries [[parachains.collators]] @@ -56,7 +56,7 @@ add_to_genesis = false validator = true # collator image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--fail-pov-recovery", "--use-null-consensus", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--fail-pov-recovery", "--in-peers 0", "--out-peers 0", "--use-null-consensus", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # run 'one' as a RPC collator who does not produce blocks [[parachains.collators]] @@ -64,7 +64,7 @@ add_to_genesis = false validator = true # collator image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--use-null-consensus", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-rpc-url {{'ferdie'|zombie('wsUri')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--use-null-consensus", "--in-peers 0", "--out-peers 0", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-rpc-url {{'ferdie'|zombie('wsUri')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # run 'two' as a RPC parachain full node [[parachains.collators]] @@ -72,7 +72,7 @@ add_to_genesis = false validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-rpc-url {{'ferdie'|zombie('wsUri')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--in-peers 0", "--out-peers 0", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-rpc-url {{'ferdie'|zombie('wsUri')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # run 'three' with light client [[parachains.collators]] @@ -80,4 +80,4 @@ add_to_genesis = false validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-light-client", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--in-peers 0", "--out-peers 0", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--relay-chain-light-client", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] diff --git a/cumulus/zombienet/tests/0002-pov_recovery.zndsl b/cumulus/zombienet/tests/0002-pov_recovery.zndsl index 12ff00210f3..7a93e2f3742 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.zndsl +++ b/cumulus/zombienet/tests/0002-pov_recovery.zndsl @@ -15,3 +15,10 @@ one: reports block height is at least 20 within 800 seconds two: reports block height is at least 20 within 800 seconds three: reports block height is at least 20 within 800 seconds eve: reports block height is at least 20 within 800 seconds + +one: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds +two: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds +three: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds +eve: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds +charlie: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds +alice: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 19 within 10 seconds -- GitLab From 7554f53f9e02f6ea5c7cb6a4ef977925f7e78b96 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 24 Nov 2023 17:06:01 +0400 Subject: [PATCH 570/633] Remove dmp-queue pallet from Rococo Asset Hub and Bridge Hub (#2483) DMP queue migration is complete and the pallet should be removed to fix the check runtime upgrade CI. Screenshot 2023-11-24 at 16 05 37 Screenshot 2023-11-24 at 16 06 44 --- Cargo.lock | 2 - .../assets/asset-hub-rococo/Cargo.toml | 123 ++++++++-------- .../assets/asset-hub-rococo/src/lib.rs | 7 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ------------------ .../asset-hub-rococo/src/weights/mod.rs | 1 - .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 100 ++++++------- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 8 -- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ------------------ .../bridge-hub-rococo/src/weights/mod.rs | 1 - 9 files changed, 119 insertions(+), 385 deletions(-) delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs diff --git a/Cargo.lock b/Cargo.lock index ab51be3d5db..ce43f78fa4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -924,7 +924,6 @@ dependencies = [ "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", @@ -2158,7 +2157,6 @@ dependencies = [ "bridge-hub-test-utils", "bridge-runtime-common", "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 0773eb0c8eb..f3bdabd9cef 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -7,74 +7,86 @@ description = "Rococo variant of Asset Hub parachain runtime" license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.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.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.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-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} +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-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", 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} +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-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", 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"] } +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} +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} +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-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-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 } @@ -107,7 +119,6 @@ default = [ "std" ] state-trie-version-1 = [ "pallet-state-trie-migration" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", - "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", @@ -142,7 +153,6 @@ 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", @@ -182,7 +192,6 @@ std = [ "bp-bridge-hub-westend/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", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index b274f45877b..02b51310890 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -685,12 +685,6 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - parameter_types! { pub const Period: u32 = 6 * HOURS; pub const Offset: u32 = 0; @@ -912,7 +906,6 @@ construct_runtime!( 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, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index 252cf2630f4..aa994a7608a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -15,7 +15,6 @@ // along with Cumulus. If not, see . pub mod block_weights; -pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; 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 c475768d5dd..42ea63bfea5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -10,64 +10,71 @@ license = "Apache-2.0" substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } hex-literal = { version = "0.4.1" } log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } serde = { version = "1.0.188", optional = true, 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-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-session = { path = "../../../../../substrate/frame/session", default-features = false} +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-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-session = { path = "../../../../../substrate/frame/session", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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} +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +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-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} -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-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 } +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 } # Polkadot -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false} -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} +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} +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-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-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 } @@ -96,7 +103,9 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", de [dev-dependencies] static_assertions = "1.1" bridge-hub-test-utils = { path = "../test-utils" } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = ["integrity-test"] } +bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = [ + "integrity-test", +] } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] @@ -117,7 +126,6 @@ std = [ "bridge-runtime-common/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", @@ -179,7 +187,6 @@ std = [ runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", - "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", @@ -211,7 +218,6 @@ 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", 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 8e138822696..7d64623f551 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 @@ -394,12 +394,6 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; @@ -500,7 +494,6 @@ construct_runtime!( 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, @@ -552,7 +545,6 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index a615f539547..3604ab3c0ff 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -21,7 +21,6 @@ use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; pub mod block_weights; -pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; -- GitLab From 891628a7f1afcc210f83e944ddf3dcf4748fd0b6 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 24 Nov 2023 14:06:19 +0100 Subject: [PATCH 571/633] relay-chain-consensus: set a fork_choice (#2462) After #2001 the `fork_choice` strategy may remain uninitialized in the block import pipeline which uses relay-chain verifier. Refer to https://github.com/paritytech/polkadot-sdk/pull/2430#issuecomment-1823979813 for some further discussion. --- cumulus/client/consensus/relay-chain/src/import_queue.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cumulus/client/consensus/relay-chain/src/import_queue.rs b/cumulus/client/consensus/relay-chain/src/import_queue.rs index 9ee03b95904..f44f4409324 100644 --- a/cumulus/client/consensus/relay-chain/src/import_queue.rs +++ b/cumulus/client/consensus/relay-chain/src/import_queue.rs @@ -55,6 +55,10 @@ where &mut self, mut block_params: BlockImportParams, ) -> Result, String> { + block_params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom( + block_params.origin == sp_consensus::BlockOrigin::NetworkInitialSync, + )); + // Skip checks that include execution, if being told so, or when importing only state. // // This is done for example when gap syncing and it is expected that the block after the gap @@ -100,7 +104,6 @@ where } block_params.post_hash = Some(block_params.header.hash()); - Ok(block_params) } } -- GitLab From 803ea7605937f3f452c38dc17c66d73049a7ba00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 24 Nov 2023 15:20:21 +0100 Subject: [PATCH 572/633] Improve `UnpinHandleInner` debug (#2485) Printing the `unpin_worker_sender` included the entire stacktrace and that is a little bit too verbose. --- substrate/client/api/src/client.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/substrate/client/api/src/client.rs b/substrate/client/api/src/client.rs index e334f2f9fb4..46232c74539 100644 --- a/substrate/client/api/src/client.rs +++ b/substrate/client/api/src/client.rs @@ -25,7 +25,11 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{collections::HashSet, fmt, sync::Arc}; +use std::{ + collections::HashSet, + fmt::{self, Debug}, + sync::Arc, +}; use crate::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary}; @@ -271,13 +275,18 @@ impl fmt::Display for UsageInfo { } /// Sends a message to the pinning-worker once dropped to unpin a block in the backend. -#[derive(Debug)] pub struct UnpinHandleInner { /// Hash of the block pinned by this handle hash: Block::Hash, unpin_worker_sender: TracingUnboundedSender, } +impl Debug for UnpinHandleInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnpinHandleInner").field("pinned_block", &self.hash).finish() + } +} + impl UnpinHandleInner { /// Create a new [`UnpinHandleInner`] pub fn new( -- GitLab From 07ea6da2d8d4f0eb5f563d6803768d4ef0de6cda Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 24 Nov 2023 16:21:10 +0200 Subject: [PATCH 573/633] Derive `MaxEncodedLen` on `SlotDuration` (#2484) # Description Needed this in my code as part of the larger data structure. --------- Co-authored-by: command-bot <> --- substrate/primitives/consensus/slots/src/lib.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/consensus/slots/src/lib.rs b/substrate/primitives/consensus/slots/src/lib.rs index a299ce395ea..b9a032c1bcf 100644 --- a/substrate/primitives/consensus/slots/src/lib.rs +++ b/substrate/primitives/consensus/slots/src/lib.rs @@ -121,7 +121,20 @@ impl From for u64 { } /// A slot duration defined in milliseconds. -#[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq, TypeInfo)] +#[derive( + Clone, + Copy, + Debug, + Encode, + Decode, + MaxEncodedLen, + Hash, + PartialOrd, + Ord, + PartialEq, + Eq, + TypeInfo, +)] pub struct SlotDuration(u64); impl SlotDuration { -- GitLab From 90488ff7e32c79a601e95eeee0675a43c17ba157 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 24 Nov 2023 17:30:25 +0200 Subject: [PATCH 574/633] pallet-xcm: fix benchmarking (#2489) Use non-zero weight limit in benchmarking `pallet_xcm::execute()` so the given XCM actually executes. --- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index 3aca24791fc..f0289512399 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -168,7 +168,7 @@ benchmarks! { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let versioned_msg = VersionedXcm::from(msg); - }: _>(execute_origin, Box::new(versioned_msg), Weight::zero()) + }: _>(execute_origin, Box::new(versioned_msg), Weight::MAX) force_xcm_version { let loc = T::reachable_dest().ok_or( -- GitLab From 8af61d03b62d541370015608b48c7399d5f67320 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:31:20 +0100 Subject: [PATCH 575/633] [NPoS] Use EraInfo to manipulate exposure in fast-unstake tests (#2459) The FastUnstake pallet tests were previously directly modifying storage items in the pallet-staking to alter exposure. However, due to the introduction of the [new paged exposure feature](https://github.com/paritytech/polkadot-sdk/pull/1189) these tests were not testing against correct storage items. This issue resulted in a bug that I didn't catch, which has been addressed in [this fix](https://github.com/paritytech/polkadot-sdk/pull/2369). This PR introduces a modification to how the pallet-fast-unstake handles exposure. It now utilizes `pallet-staking::EraInfo` to set or mutate Exposures. --- substrate/frame/fast-unstake/src/mock.rs | 11 ++++++----- substrate/frame/fast-unstake/src/tests.rs | 8 +++++--- substrate/frame/staking/src/lib.rs | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index df133bdfd47..09a08f222b6 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -244,7 +244,7 @@ impl ExtBuilder { (v, Exposure { total: 0, own: 0, others }) }) .for_each(|(validator, exposure)| { - pallet_staking::ErasStakers::::insert(era, validator, exposure); + pallet_staking::EraInfo::::set_exposure(era, &validator, exposure); }); } @@ -342,10 +342,11 @@ pub fn assert_unstaked(stash: &AccountId) { } pub fn create_exposed_nominator(exposed: AccountId, era: u32) { - // create an exposed nominator in era 1 - pallet_staking::ErasStakers::::mutate(era, VALIDATORS_PER_ERA, |expo| { - expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); - }); + // create an exposed nominator in passed era + let mut exposure = pallet_staking::EraInfo::::get_full_exposure(era, &VALIDATORS_PER_ERA); + exposure.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + pallet_staking::EraInfo::::set_exposure(era, &VALIDATORS_PER_ERA, exposure); + Balances::make_free_balance_be(&exposed, 100); assert_ok!(Staking::bond( RuntimeOrigin::signed(exposed), diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 94ad6a84b85..b19fe3b8c46 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -788,10 +788,12 @@ mod on_idle { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX))); // but they indeed are exposed! - assert!(pallet_staking::ErasStakers::::contains_key( + assert!(pallet_staking::EraInfo::::get_paged_exposure( BondingDuration::get() - 1, - VALIDATOR_PREFIX - )); + &VALIDATOR_PREFIX, + 0 + ) + .is_some()); // process a block, this validator is exposed and has been slashed. next_block(true); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e6250bb9681..41cb2a12c3a 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -724,7 +724,7 @@ pub struct Nominations { /// This is useful where we need to take into account the validator's own stake and total exposure /// in consideration, in addition to the individual nominators backing them. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] -struct PagedExposure { +pub struct PagedExposure { exposure_metadata: PagedExposureMetadata, exposure_page: ExposurePage, } @@ -1017,7 +1017,7 @@ where /// Wrapper struct for Era related information. It is not a pure encapsulation as these storage /// items can be accessed directly but nevertheless, its recommended to use `EraInfo` where we /// can and add more functions to it as needed. -pub(crate) struct EraInfo(sp_std::marker::PhantomData); +pub struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be @@ -1047,7 +1047,7 @@ impl EraInfo { /// /// This builds a paged exposure from `PagedExposureMetadata` and `ExposurePage` of the /// validator. For older non-paged exposure, it returns the clipped exposure directly. - pub(crate) fn get_paged_exposure( + pub fn get_paged_exposure( era: EraIndex, validator: &T::AccountId, page: Page, @@ -1082,7 +1082,7 @@ impl EraInfo { } /// Get full exposure of the validator at a given era. - pub(crate) fn get_full_exposure( + pub fn get_full_exposure( era: EraIndex, validator: &T::AccountId, ) -> Exposure> { @@ -1176,7 +1176,7 @@ impl EraInfo { } /// Store exposure for elected validators at start of an era. - pub(crate) fn set_exposure( + pub fn set_exposure( era: EraIndex, validator: &T::AccountId, exposure: Exposure>, -- GitLab From d07186b8e3ec6634187936caaae48bb8558e3346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Fri, 24 Nov 2023 16:48:56 +0000 Subject: [PATCH 576/633] Remove `RuntimeApi` dependency on system parachain runtime code (#2455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last issue blocking the removal of the Polkadot and Kusama system parachains from the repo in #1737 is the dependency on the runtime code through the RuntimeApi in `polkadot-parachain`. This PR introduces two fake runtimes to satisfy the build requirements and changes the `new_partial` function to make it not be generic over the runtimes. The reason for the second runtime is the different Aura keys used in Polkadot Asset Hub, as the impl for AuraApi depends on this type. If this changes the `RuntimeApi` generic could be removed completely from all functions in `services.rs` and and generic type parameters in `services.rs` and specified as a concrete type to TFullClient`. --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 9 + cumulus/polkadot-parachain/Cargo.toml | 13 + .../src/chain_spec/bridge_hubs.rs | 5 - cumulus/polkadot-parachain/src/command.rs | 285 +++--------------- .../asset_hub_polkadot_aura.rs | 200 ++++++++++++ .../src/fake_runtime_api/aura.rs | 200 ++++++++++++ .../src/fake_runtime_api/mod.rs | 21 ++ cumulus/polkadot-parachain/src/main.rs | 1 + cumulus/polkadot-parachain/src/service.rs | 24 +- 9 files changed, 497 insertions(+), 261 deletions(-) create mode 100644 cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs create mode 100644 cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs create mode 100644 cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ce43f78fa4f..3fbede968bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12964,6 +12964,9 @@ dependencies = [ "cumulus-relay-chain-interface", "frame-benchmarking", "frame-benchmarking-cli", + "frame-support", + "frame-system-rpc-runtime-api", + "frame-try-runtime", "futures", "glutton-runtime", "glutton-westend-runtime", @@ -12971,7 +12974,9 @@ dependencies = [ "jsonrpsee", "log", "nix 0.26.2", + "pallet-transaction-payment", "pallet-transaction-payment-rpc", + "pallet-transaction-payment-rpc-runtime-api", "parachains-common", "parity-scale-codec", "penpal-runtime", @@ -13003,14 +13008,18 @@ dependencies = [ "sp-blockchain", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", + "sp-inherents", "sp-io", "sp-keystore", "sp-offchain", "sp-runtime", "sp-session", + "sp-std 8.0.0", "sp-timestamp", "sp-tracing 10.0.0", "sp-transaction-pool", + "sp-version", "staging-xcm", "substrate-build-script-utils", "substrate-frame-rpc-system", diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index d5deda9e7bf..e23a7aeb22b 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -49,8 +49,10 @@ sp-runtime = { path = "../../substrate/primitives/runtime", default-features = f sp-io = { path = "../../substrate/primitives/io" } sp-core = { path = "../../substrate/primitives/core" } sp-session = { path = "../../substrate/primitives/session" } +frame-try-runtime = { path = "../../substrate/frame/try-runtime", optional = true } sc-consensus = { path = "../../substrate/client/consensus/common" } sp-tracing = { path = "../../substrate/primitives/tracing" } +frame-support = { path = "../../substrate/frame/support" } sc-cli = { path = "../../substrate/client/cli" } sc-client-api = { path = "../../substrate/client/api" } sc-executor = { path = "../../substrate/client/executor" } @@ -63,12 +65,19 @@ sc-network-sync = { path = "../../substrate/client/network/sync" } sc-basic-authorship = { path = "../../substrate/client/basic-authorship" } sp-timestamp = { path = "../../substrate/primitives/timestamp" } sp-blockchain = { path = "../../substrate/primitives/blockchain" } +sp-genesis-builder = { path = "../../substrate/primitives/genesis-builder", default-features = false } sp-block-builder = { path = "../../substrate/primitives/block-builder" } sp-keystore = { path = "../../substrate/primitives/keystore" } sc-chain-spec = { path = "../../substrate/client/chain-spec" } sc-rpc = { path = "../../substrate/client/rpc" } +sp-version = { path = "../../substrate/primitives/version" } sc-tracing = { path = "../../substrate/client/tracing" } sp-offchain = { path = "../../substrate/primitives/offchain" } +frame-system-rpc-runtime-api = { path = "../../substrate/frame/system/rpc/runtime-api" } +pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } +pallet-transaction-payment-rpc-runtime-api = { path = "../../substrate/frame/transaction-payment/rpc/runtime-api" } +sp-std = { path = "../../substrate/primitives/std" } +sp-inherents = { path = "../../substrate/primitives/inherents" } sp-api = { path = "../../substrate/primitives/api" } sp-consensus-aura = { path = "../../substrate/primitives/consensus/aura" } sc-sysinfo = { path = "../../substrate/client/sysinfo" } @@ -126,6 +135,7 @@ runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", "glutton-runtime/runtime-benchmarks", "glutton-westend-runtime/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -149,8 +159,11 @@ try-runtime = [ "collectives-polkadot-runtime/try-runtime", "collectives-westend-runtime/try-runtime", "contracts-rococo-runtime/try-runtime", + "frame-support/try-runtime", + "frame-try-runtime/try-runtime", "glutton-runtime/try-runtime", "glutton-westend-runtime/try-runtime", + "pallet-transaction-payment/try-runtime", "penpal-runtime/try-runtime", "polkadot-cli/try-runtime", "polkadot-service/try-runtime", diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 94cef106001..eb253908f5f 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -199,8 +199,6 @@ pub mod rococo { /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub type RuntimeApi = bridge_hub_rococo_runtime::RuntimeApi; - pub fn local_config( id: &str, chain_name: &str, @@ -319,7 +317,6 @@ pub mod kusama { /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub type RuntimeApi = bridge_hub_kusama_runtime::RuntimeApi; pub fn local_config( id: &str, @@ -429,7 +426,6 @@ pub mod westend { /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = sc_service::GenericChainSpec; - pub type RuntimeApi = bridge_hub_westend_runtime::RuntimeApi; pub fn local_config( id: &str, @@ -545,7 +541,6 @@ pub mod polkadot { /// Specialized `ChainSpec` for the normal parachain runtime. pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub type RuntimeApi = bridge_hub_polkadot_runtime::RuntimeApi; pub fn local_config( id: &str, diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 7bede22fea7..ea19ad12ba0 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -17,6 +17,9 @@ use crate::{ chain_spec, cli::{Cli, RelayChainCli, Subcommand}, + fake_runtime_api::{ + asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, aura::RuntimeApi, + }, service::{new_partial, Block}, }; use cumulus_primitives_core::ParaId; @@ -439,128 +442,46 @@ impl SubstrateCli for RelayChainCli { macro_rules! construct_partials { ($config:expr, |$partials:ident| $code:expr) => { match $config.chain_spec.runtime() { - Runtime::AssetHubKusama => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - Runtime::AssetHubRococo => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - Runtime::AssetHubWestend => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, Runtime::AssetHubPolkadot => { - let $partials = new_partial::( + let $partials = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, )?; $code }, - Runtime::BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { - chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotDevelopment => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaDevelopment => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Rococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, - }, - Runtime::CollectivesPolkadot => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, + Runtime::AssetHubKusama | + Runtime::AssetHubRococo | + Runtime::AssetHubWestend | + Runtime::BridgeHub(_) | + Runtime::CollectivesPolkadot | Runtime::CollectivesWestend => { - let $partials = new_partial::( + let $partials = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AuraId>, )?; $code }, - Runtime::Shell => { - let $partials = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - $code - }, - Runtime::Seedling => { - let $partials = new_partial::( + Runtime::GluttonWestend | Runtime::Glutton | Runtime::Shell | Runtime::Seedling => { + let $partials = new_partial::( &$config, crate::service::shell_build_import_queue, )?; $code }, Runtime::ContractsRococo => { - let $partials = new_partial::( + let $partials = new_partial::( &$config, crate::service::contracts_rococo_build_import_queue, )?; $code }, Runtime::Penpal(_) | Runtime::Default => { - let $partials = new_partial::( + let $partials = new_partial::( &$config, crate::service::rococo_parachain_build_import_queue, )?; $code }, - Runtime::GluttonWestend => { - let $partials = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - $code - }, - Runtime::Glutton => { - let $partials = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - $code - }, } }; } @@ -569,39 +490,9 @@ macro_rules! construct_async_run { (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ let runner = $cli.create_runner($cmd)?; match runner.config().chain_spec.runtime() { - Runtime::AssetHubWestend => { - 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::AssetHubRococo => { - 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::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, Runtime::AssetHubPolkadot => { runner.async_run(|$config| { - let $components = new_partial::( + let $components = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, )?; @@ -609,9 +500,14 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::CollectivesPolkadot => { + Runtime::AssetHubWestend | + Runtime::AssetHubRococo | + Runtime::AssetHubKusama | + Runtime::CollectivesPolkadot | + Runtime::CollectivesWestend | + Runtime::BridgeHub(_) => { runner.async_run(|$config| { - let $components = new_partial::( + let $components = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AuraId>, )?; @@ -619,39 +515,22 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::CollectivesWestend => { - 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::Shell => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::Seedling => { + Runtime::Shell | + Runtime::Seedling | + Runtime::GluttonWestend | + Runtime::Glutton => { runner.async_run(|$config| { - let $components = new_partial::( + let $components = new_partial::( &$config, crate::service::shell_build_import_queue, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) }) - }, + } Runtime::ContractsRococo => { runner.async_run(|$config| { - let $components = new_partial::( + let $components = new_partial::( &$config, crate::service::contracts_rococo_build_import_queue, )?; @@ -659,66 +538,10 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::BridgeHub(bridge_hub_runtime_type) => { - match bridge_hub_runtime_type { - chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotDevelopment => { - 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)) - }) - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaDevelopment => { - 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)) - }) - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => { - 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)) - }) - }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Rococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => { - 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::Penpal(_) | Runtime::Default => { runner.async_run(|$config| { let $components = new_partial::< - rococo_parachain_runtime::RuntimeApi, + RuntimeApi, _, >( &$config, @@ -728,26 +551,6 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::GluttonWestend => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::Glutton => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::shell_build_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - } } }} } @@ -927,28 +730,28 @@ pub fn run() -> Result<()> { match config.chain_spec.runtime() { Runtime::AssetHubPolkadot => crate::service::start_asset_hub_node::< - asset_hub_polkadot_runtime::RuntimeApi, + AssetHubPolkadotRuntimeApi, AssetHubPolkadotAuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), Runtime::AssetHubKusama => crate::service::start_asset_hub_node::< - asset_hub_kusama_runtime::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), Runtime::AssetHubRococo => crate::service::start_asset_hub_node::< - asset_hub_rococo_runtime::RuntimeApi, + 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, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -956,7 +759,7 @@ pub fn run() -> Result<()> { .map_err(Into::into), Runtime::CollectivesPolkadot => crate::service::start_generic_aura_node::< - collectives_polkadot_runtime::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -964,14 +767,14 @@ pub fn run() -> Result<()> { .map_err(Into::into), Runtime::CollectivesWestend => crate::service::start_generic_aura_node::< - collectives_westend_runtime::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), Runtime::Shell => - crate::service::start_shell_node::( + crate::service::start_shell_node::( config, polkadot_config, collator_options, @@ -982,7 +785,7 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into), Runtime::Seedling => - crate::service::start_shell_node::( + crate::service::start_shell_node::( config, polkadot_config, collator_options, @@ -1007,7 +810,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotDevelopment => crate::service::start_generic_aura_node::< - chain_spec::bridge_hubs::polkadot::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -1016,7 +819,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaDevelopment => crate::service::start_generic_aura_node::< - chain_spec::bridge_hubs::kusama::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -1025,7 +828,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => crate::service::start_generic_aura_node::< - chain_spec::bridge_hubs::westend::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -1034,7 +837,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => crate::service::start_generic_aura_node::< - chain_spec::bridge_hubs::rococo::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -1054,7 +857,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | .map_err(Into::into), Runtime::GluttonWestend => crate::service::start_basic_lookahead_node::< - glutton_westend_runtime::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await @@ -1062,7 +865,7 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | .map_err(Into::into), Runtime::Glutton => crate::service::start_basic_lookahead_node::< - glutton_runtime::RuntimeApi, + RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs new file mode 100644 index 00000000000..76dd7347ccb --- /dev/null +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs @@ -0,0 +1,200 @@ +// 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 . + +//! These are used to provide a type that implements these runtime APIs without requiring to import +//! the native runtimes. + +use frame_support::weights::Weight; +use parachains_common::{AccountId, AssetHubPolkadotAuraId, Balance, Nonce}; +use polkadot_primitives::Block; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; + +pub struct Runtime; + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + + fn execute_block(_: Block) { + unimplemented!() + } + + fn initialize_block(_: &::Header) { + unimplemented!() + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> sp_std::vec::Vec { + unimplemented!() + } + } + + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + unimplemented!() + } + + fn authorities() -> Vec { + unimplemented!() + } + } + + impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { + fn can_build_upon( + _: ::Hash, + _: cumulus_primitives_aura::Slot, + ) -> bool { + unimplemented!() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> ::Header { + unimplemented!() + } + + fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { + unimplemented!() + } + + fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + _: TransactionSource, + _: ::Extrinsic, + _: ::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(_: &::Header) { + unimplemented!() + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(_: Option>) -> Vec { + unimplemented!() + } + + fn decode_session_keys( + _: Vec, + ) -> Option, KeyTypeId)>> { + unimplemented!() + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + _: ::Extrinsic, + _: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + unimplemented!() + } + fn query_fee_details( + _: ::Extrinsic, + _: u32, + ) -> pallet_transaction_payment::FeeDetails { + unimplemented!() + } + fn query_weight_to_fee(_: Weight) -> Balance { + unimplemented!() + } + fn query_length_to_fee(_: u32) -> Balance { + unimplemented!() + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { + unimplemented!() + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + unimplemented!() + } + + fn execute_block( + _: Block, + _: bool, + _: bool, + _: frame_try_runtime::TryStateSelect, + ) -> Weight { + unimplemented!() + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_: AccountId) -> Nonce { + unimplemented!() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(_: bool) -> ( + Vec, + Vec, + ) { + unimplemented!() + } + + fn dispatch_benchmark( + _: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + unimplemented!() + } + + fn build_config(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + } +} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs new file mode 100644 index 00000000000..0f01b85ebcf --- /dev/null +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs @@ -0,0 +1,200 @@ +// 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 . + +//! These are used to provide a type that implements these runtime APIs without requiring to import +//! the native runtimes. + +use frame_support::weights::Weight; +use parachains_common::{AccountId, AuraId, Balance, Nonce}; +use polkadot_primitives::Block; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; + +pub struct Runtime; + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + + fn execute_block(_: Block) { + unimplemented!() + } + + fn initialize_block(_: &::Header) { + unimplemented!() + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> sp_std::vec::Vec { + unimplemented!() + } + } + + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + unimplemented!() + } + + fn authorities() -> Vec { + unimplemented!() + } + } + + impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { + fn can_build_upon( + _: ::Hash, + _: cumulus_primitives_aura::Slot, + ) -> bool { + unimplemented!() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> ::Header { + unimplemented!() + } + + fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { + unimplemented!() + } + + fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + _: TransactionSource, + _: ::Extrinsic, + _: ::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(_: &::Header) { + unimplemented!() + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(_: Option>) -> Vec { + unimplemented!() + } + + fn decode_session_keys( + _: Vec, + ) -> Option, KeyTypeId)>> { + unimplemented!() + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + _: ::Extrinsic, + _: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + unimplemented!() + } + fn query_fee_details( + _: ::Extrinsic, + _: u32, + ) -> pallet_transaction_payment::FeeDetails { + unimplemented!() + } + fn query_weight_to_fee(_: Weight) -> Balance { + unimplemented!() + } + fn query_length_to_fee(_: u32) -> Balance { + unimplemented!() + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { + unimplemented!() + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + unimplemented!() + } + + fn execute_block( + _: Block, + _: bool, + _: bool, + _: frame_try_runtime::TryStateSelect, + ) -> Weight { + unimplemented!() + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_: AccountId) -> Nonce { + unimplemented!() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(_: bool) -> ( + Vec, + Vec, + ) { + unimplemented!() + } + + fn dispatch_benchmark( + _: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + unimplemented!() + } + + fn build_config(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + } +} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs new file mode 100644 index 00000000000..29e2736b06f --- /dev/null +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs @@ -0,0 +1,21 @@ +// 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 . + +//! In an ideal world this would be one runtime which would simplify the code massively. +//! This is not an ideal world - Polkadot Asset Hub has a different key type. + +pub mod asset_hub_polkadot_aura; +pub mod aura; diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index 26d7dae4b8a..0757bea84aa 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -22,6 +22,7 @@ mod chain_spec; mod cli; mod command; +mod fake_runtime_api; mod rpc; mod service; diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index f580835db55..b0fca518201 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -40,7 +40,7 @@ use sp_core::Pair; use jsonrpsee::RpcModule; -use crate::rpc; +use crate::{fake_runtime_api::aura::RuntimeApi, rpc}; pub use parachains_common::{AccountId, Balance, Block, BlockNumber, Hash, Header, Nonce}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; @@ -917,8 +917,8 @@ where /// Build the import queue for the rococo parachain runtime. pub fn rococo_parachain_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + block_import: ParachainBlockImport, config: &Configuration, telemetry: Option, task_manager: &TaskManager, @@ -960,11 +960,8 @@ pub async fn start_rococo_parachain_node( collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<( - TaskManager, - Arc>, -)> { - start_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( parachain_config, polkadot_config, collator_options, @@ -1866,8 +1863,8 @@ where #[allow(clippy::type_complexity)] pub fn contracts_rococo_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + block_import: ParachainBlockImport, config: &Configuration, telemetry: Option, task_manager: &TaskManager, @@ -1909,11 +1906,8 @@ pub async fn start_contracts_rococo_node( collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<( - TaskManager, - Arc>, -)> { - start_contracts_rococo_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_contracts_rococo_node_impl::( parachain_config, polkadot_config, collator_options, -- GitLab From 81638d4d5e78b67fda4130308930bb4a19b20144 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 24 Nov 2023 18:22:28 +0100 Subject: [PATCH 577/633] Add missing workspace members (#2491) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following members have been added: ```pre cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal cumulus/parachains/testnets-common polkadot/node/tracking-allocator substrate/frame/examples/frame-crate ``` CI check can be added after https://github.com/paritytech/pipeline-scripts/pull/105 is merged. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- Cargo.toml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 57079aa4d03..6af3ea4c3cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ members = [ "bridges/primitives/chain-bridge-hub-rococo", "bridges/primitives/chain-bridge-hub-westend", "bridges/primitives/chain-kusama", - "bridges/primitives/chain-polkadot", "bridges/primitives/chain-polkadot-bulletin", + "bridges/primitives/chain-polkadot", "bridges/primitives/chain-rococo", "bridges/primitives/chain-westend", "bridges/primitives/header-chain", @@ -60,20 +60,20 @@ members = [ "cumulus/parachain-template/pallets/template", "cumulus/parachain-template/runtime", "cumulus/parachains/common", - "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo", - "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend", - "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo", - "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", - "cumulus/parachains/integration-tests/emulated/common", - "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", - "cumulus/parachains/integration-tests/emulated/chains/relays/westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal", + "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", + "cumulus/parachains/integration-tests/emulated/chains/relays/westend", + "cumulus/parachains/integration-tests/emulated/common", "cumulus/parachains/integration-tests/emulated/networks/rococo-system", - "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system", "cumulus/parachains/integration-tests/emulated/networks/westend-system", + "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo", + "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend", + "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo", + "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", "cumulus/parachains/pallets/collective-content", "cumulus/parachains/pallets/parachain-info", "cumulus/parachains/pallets/ping", @@ -98,6 +98,7 @@ members = [ "cumulus/parachains/runtimes/test-utils", "cumulus/parachains/runtimes/testing/penpal", "cumulus/parachains/runtimes/testing/rococo-parachain", + "cumulus/parachains/testnets-common", "cumulus/polkadot-parachain", "cumulus/primitives/aura", "cumulus/primitives/core", @@ -156,6 +157,7 @@ members = [ "polkadot/node/subsystem", "polkadot/node/test/client", "polkadot/node/test/service", + "polkadot/node/tracking-allocator", "polkadot/node/zombienet-backchannel", "polkadot/parachain", "polkadot/parachain/test-parachains", @@ -190,9 +192,9 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", + "substrate", "substrate/bin/minimal/node", "substrate/bin/minimal/runtime", - "substrate", "substrate/bin/node-template/node", "substrate/bin/node-template/pallets/template", "substrate/bin/node-template/runtime", @@ -288,9 +290,9 @@ members = [ "substrate/frame/collective", "substrate/frame/contracts", "substrate/frame/contracts/fixtures", + "substrate/frame/contracts/mock-network", "substrate/frame/contracts/primitives", "substrate/frame/contracts/proc-macro", - "substrate/frame/contracts/mock-network", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", "substrate/frame/democracy", @@ -305,6 +307,7 @@ members = [ "substrate/frame/examples/basic", "substrate/frame/examples/default-config", "substrate/frame/examples/dev-mode", + "substrate/frame/examples/frame-crate", "substrate/frame/examples/kitchensink", "substrate/frame/examples/offchain-worker", "substrate/frame/examples/split", @@ -470,6 +473,7 @@ members = [ "substrate/utils/frame/try-runtime/cli", "substrate/utils/prometheus", "substrate/utils/wasm-builder", + "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system", ] default-members = [ "polkadot", "substrate/bin/node/cli" ] -- GitLab From 63f1210d084014e77bc5a33ac8a35e4508587dcb Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 24 Nov 2023 20:02:27 -0300 Subject: [PATCH 578/633] bump zombienet version `v1.3.83` (#2492) Include fix for `0002-parachains-upgrade-smoke-test` test. --- .github/review-bot.yml | 2 +- .gitlab/pipeline/zombienet.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/review-bot.yml b/.github/review-bot.yml index b053ead37fb..c522988f02e 100644 --- a/.github/review-bot.yml +++ b/.github/review-bot.yml @@ -9,7 +9,7 @@ rules: - ^\.config/nextest.toml - ^\.cargo/.* exclude: - - ^./gitlab/pipeline/zombienet.* + - ^\.gitlab/pipeline/zombienet.* minApprovals: 2 type: basic teams: diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index fc3fd125619..558cc549cb0 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,7 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.82" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.83" include: # substrate tests -- GitLab From 5e2734219880b688e63d033968dafe0960f234ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 25 Nov 2023 00:22:52 +0100 Subject: [PATCH 579/633] Do not pollute global base path with export genesis/wasm (#2487) Otherwise the user may runs into weird errors if there is already a db. --- cumulus/client/cli/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index a2238b73b2b..7e78afe6efb 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -215,6 +215,13 @@ impl sc_cli::CliConfiguration for ExportGenesisStateCommand { fn shared_params(&self) -> &sc_cli::SharedParams { &self.shared_params } + + fn base_path(&self) -> sc_cli::Result> { + // As we are just exporting the genesis wasm a tmp database is enough. + // + // As otherwise we may "pollute" the global base path. + Ok(Some(BasePath::new_temp_dir()?)) + } } /// Command for exporting the genesis wasm file. @@ -266,6 +273,13 @@ impl sc_cli::CliConfiguration for ExportGenesisWasmCommand { fn shared_params(&self) -> &sc_cli::SharedParams { &self.shared_params } + + fn base_path(&self) -> sc_cli::Result> { + // As we are just exporting the genesis wasm a tmp database is enough. + // + // As otherwise we may "pollute" the global base path. + Ok(Some(BasePath::new_temp_dir()?)) + } } fn validate_relay_chain_url(arg: &str) -> Result { -- GitLab From ffc64fd255bc3f1d60138e01a2987540c3f72791 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 24 Nov 2023 20:42:20 -0300 Subject: [PATCH 580/633] Zombienet: add polkadot-debug image publish as needs for cumulus tests (#2493) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `build-push-image-polkadot-debug` job to needs since we changed to use the polkadot-debug image from the current branch for cumulus test and we need to be sure that the image is ready. Fix issues like https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4481059 cc: @bkchr Co-authored-by: Bastian Köcher --- .gitlab/pipeline/zombienet/cumulus.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 3e4df000b7f..409c0aba68e 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -27,6 +27,8 @@ needs: - job: build-push-image-test-parachain artifacts: true + - job: build-push-image-polkadot-debug + artifacts: true variables: POLKADOT_IMAGE: "docker.io/paritypr/polkadot-debug:${DOCKER_IMAGES_VERSION}" GH_DIR: "https://github.com/paritytech/cumulus/tree/${CI_COMMIT_SHORT_SHA}/zombienet/tests" -- GitLab From d5d15a18029eed59914fbf807956ee6ab3bcabf1 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sat, 25 Nov 2023 09:56:17 +0100 Subject: [PATCH 581/633] polkadot-parachain: one chain-spec for all (#2457) This PR removes some `ChainSpec` types which are not necessary (left-overs from #1256). Currently `ChainSpec` does not have to be generic over the specific `RuntimeGenesisConfig`, it is enough to use single type for all: https://github.com/paritytech/polkadot-sdk/blob/9f787018857660440182142adc806954d7d07709/cumulus/polkadot-parachain/src/chain_spec/mod.rs#L53-L54 related to: https://github.com/paritytech/polkadot-sdk/issues/25 --------- Co-authored-by: command-bot <> --- .../src/chain_spec/asset_hubs.rs | 65 +++++------ .../src/chain_spec/bridge_hubs.rs | 92 +++++---------- .../src/chain_spec/collectives.rs | 22 ++-- .../src/chain_spec/contracts.rs | 17 ++- .../src/chain_spec/glutton.rs | 30 +++-- .../polkadot-parachain/src/chain_spec/mod.rs | 3 + .../src/chain_spec/penpal.rs | 9 +- .../src/chain_spec/rococo_parachain.rs | 12 +- .../src/chain_spec/seedling.rs | 9 +- .../src/chain_spec/shell.rs | 9 +- cumulus/polkadot-parachain/src/command.rs | 110 +++++------------- 11 files changed, 137 insertions(+), 241 deletions(-) diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index a8d3d2975ad..2988d6af0d1 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -15,7 +15,8 @@ // along with Cumulus. If not, see . use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use cumulus_primitives_core::ParaId; use hex_literal::hex; @@ -23,16 +24,6 @@ use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance as As use sc_service::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -/// Specialized `ChainSpec` for the normal parachain runtime. -pub type AssetHubPolkadotChainSpec = - sc_service::GenericChainSpec; -pub type AssetHubKusamaChainSpec = - sc_service::GenericChainSpec; -pub type AssetHubWestendChainSpec = - sc_service::GenericChainSpec; -pub type AssetHubRococoChainSpec = - sc_service::GenericChainSpec; - const ASSET_HUB_POLKADOT_ED: AssetHubBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; const ASSET_HUB_KUSAMA_ED: AssetHubBalance = @@ -72,13 +63,13 @@ pub fn asset_hub_westend_session_keys(keys: AuraId) -> asset_hub_westend_runtime asset_hub_westend_runtime::SessionKeys { aura: keys } } -pub fn asset_hub_polkadot_development_config() -> AssetHubPolkadotChainSpec { +pub fn asset_hub_polkadot_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::builder( + GenericChainSpec::builder( asset_hub_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-dev".into(), para_id: 1000 }, @@ -104,13 +95,13 @@ pub fn asset_hub_polkadot_development_config() -> AssetHubPolkadotChainSpec { .build() } -pub fn asset_hub_polkadot_local_config() -> AssetHubPolkadotChainSpec { +pub fn asset_hub_polkadot_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::builder( + GenericChainSpec::builder( asset_hub_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 }, @@ -152,13 +143,13 @@ pub fn asset_hub_polkadot_local_config() -> AssetHubPolkadotChainSpec { } // Not used for syncing, but just to determine the genesis values set for the upgrade from shell. -pub fn asset_hub_polkadot_config() -> AssetHubPolkadotChainSpec { +pub fn asset_hub_polkadot_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - AssetHubPolkadotChainSpec::builder( + GenericChainSpec::builder( asset_hub_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot".into(), para_id: 1000 }, @@ -249,13 +240,13 @@ fn asset_hub_polkadot_genesis( }) } -pub fn asset_hub_kusama_development_config() -> AssetHubKusamaChainSpec { +pub fn asset_hub_kusama_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::builder( + GenericChainSpec::builder( asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-dev".into(), para_id: 1000 }, ) @@ -280,13 +271,13 @@ pub fn asset_hub_kusama_development_config() -> AssetHubKusamaChainSpec { .build() } -pub fn asset_hub_kusama_local_config() -> AssetHubKusamaChainSpec { +pub fn asset_hub_kusama_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::builder( + GenericChainSpec::builder( asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-local".into(), para_id: 1000 }, ) @@ -325,13 +316,13 @@ pub fn asset_hub_kusama_local_config() -> AssetHubKusamaChainSpec { .build() } -pub fn asset_hub_kusama_config() -> AssetHubKusamaChainSpec { +pub fn asset_hub_kusama_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubKusamaChainSpec::builder( + GenericChainSpec::builder( asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama".into(), para_id: 1000 }, ) @@ -407,12 +398,12 @@ fn asset_hub_kusama_genesis( }) } -pub fn asset_hub_westend_development_config() -> AssetHubWestendChainSpec { +pub fn asset_hub_westend_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::builder( + GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, @@ -439,12 +430,12 @@ pub fn asset_hub_westend_development_config() -> AssetHubWestendChainSpec { .build() } -pub fn asset_hub_westend_local_config() -> AssetHubWestendChainSpec { +pub fn asset_hub_westend_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::builder( + GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-local".into(), para_id: 1000 }, @@ -485,12 +476,12 @@ pub fn asset_hub_westend_local_config() -> AssetHubWestendChainSpec { .build() } -pub fn asset_hub_westend_config() -> AssetHubWestendChainSpec { +pub fn asset_hub_westend_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - AssetHubWestendChainSpec::builder( + GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, @@ -569,7 +560,7 @@ fn asset_hub_westend_genesis( }) } -pub fn asset_hub_rococo_development_config() -> AssetHubRococoChainSpec { +pub fn asset_hub_rococo_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); properties.insert("tokenSymbol".into(), "ROC".into()); @@ -587,8 +578,8 @@ fn asset_hub_rococo_like_development_config( name: &str, chain_id: &str, para_id: u32, -) -> AssetHubRococoChainSpec { - AssetHubRococoChainSpec::builder( +) -> GenericChainSpec { + GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-dev".into(), para_id }, ) @@ -614,7 +605,7 @@ fn asset_hub_rococo_like_development_config( .build() } -pub fn asset_hub_rococo_local_config() -> AssetHubRococoChainSpec { +pub fn asset_hub_rococo_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); properties.insert("tokenSymbol".into(), "ROC".into()); @@ -632,8 +623,8 @@ fn asset_hub_rococo_like_local_config( name: &str, chain_id: &str, para_id: u32, -) -> AssetHubRococoChainSpec { - AssetHubRococoChainSpec::builder( +) -> GenericChainSpec { + GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id }, ) @@ -673,12 +664,12 @@ fn asset_hub_rococo_like_local_config( .build() } -pub fn asset_hub_rococo_genesis_config() -> AssetHubRococoChainSpec { +pub fn asset_hub_rococo_genesis_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); let para_id = 1000; - AssetHubRococoChainSpec::builder( + GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo".into(), para_id }, ) diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index eb253908f5f..377ceb20e1e 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, get_collator_keys_from_seed}; +use crate::chain_spec::{get_account_id_from_seed, get_collator_keys_from_seed, GenericChainSpec}; use cumulus_primitives_core::ParaId; use parachains_common::Balance as BridgeHubBalance; use sc_chain_spec::ChainSpec; use sp_core::sr25519; -use std::{path::PathBuf, str::FromStr}; +use std::str::FromStr; /// Collects all supported BridgeHub configurations #[derive(Debug, PartialEq)] @@ -71,33 +71,11 @@ impl FromStr for BridgeHubRuntimeType { impl BridgeHubRuntimeType { pub const ID_PREFIX: &'static str = "bridge-hub"; - pub fn chain_spec_from_json_file(&self, path: PathBuf) -> Result, String> { - match self { - BridgeHubRuntimeType::Polkadot | - BridgeHubRuntimeType::PolkadotLocal | - BridgeHubRuntimeType::PolkadotDevelopment => - Ok(Box::new(polkadot::BridgeHubChainSpec::from_json_file(path)?)), - BridgeHubRuntimeType::Kusama | - BridgeHubRuntimeType::KusamaLocal | - BridgeHubRuntimeType::KusamaDevelopment => - Ok(Box::new(kusama::BridgeHubChainSpec::from_json_file(path)?)), - BridgeHubRuntimeType::Westend | - BridgeHubRuntimeType::WestendLocal | - BridgeHubRuntimeType::WestendDevelopment => - Ok(Box::new(westend::BridgeHubChainSpec::from_json_file(path)?)), - BridgeHubRuntimeType::Rococo | - BridgeHubRuntimeType::RococoLocal | - BridgeHubRuntimeType::RococoDevelopment => - Ok(Box::new(rococo::BridgeHubChainSpec::from_json_file(path)?)), - } - } - pub fn load_config(&self) -> Result, String> { match self { - BridgeHubRuntimeType::Polkadot => - Ok(Box::new(polkadot::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/bridge-hub-polkadot.json")[..], - )?)), + BridgeHubRuntimeType::Polkadot => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/bridge-hub-polkadot.json")[..], + )?)), BridgeHubRuntimeType::PolkadotLocal => Ok(Box::new(polkadot::local_config( polkadot::BRIDGE_HUB_POLKADOT_LOCAL, "Polkadot BridgeHub Local", @@ -110,10 +88,9 @@ impl BridgeHubRuntimeType { "polkadot-dev", ParaId::new(1002), ))), - BridgeHubRuntimeType::Kusama => - Ok(Box::new(kusama::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/bridge-hub-kusama.json")[..], - )?)), + BridgeHubRuntimeType::Kusama => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/bridge-hub-kusama.json")[..], + )?)), BridgeHubRuntimeType::KusamaLocal => Ok(Box::new(kusama::local_config( kusama::BRIDGE_HUB_KUSAMA_LOCAL, "Kusama BridgeHub Local", @@ -126,10 +103,9 @@ impl BridgeHubRuntimeType { "kusama-dev", ParaId::new(1003), ))), - BridgeHubRuntimeType::Westend => - Ok(Box::new(westend::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/bridge-hub-westend.json")[..], - )?)), + BridgeHubRuntimeType::Westend => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/bridge-hub-westend.json")[..], + )?)), BridgeHubRuntimeType::WestendLocal => Ok(Box::new(westend::local_config( westend::BRIDGE_HUB_WESTEND_LOCAL, "Westend BridgeHub Local", @@ -144,10 +120,9 @@ impl BridgeHubRuntimeType { ParaId::new(1002), Some("Bob".to_string()), ))), - BridgeHubRuntimeType::Rococo => - Ok(Box::new(rococo::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/bridge-hub-rococo.json")[..], - )?)), + BridgeHubRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/bridge-hub-rococo.json")[..], + )?)), BridgeHubRuntimeType::RococoLocal => Ok(Box::new(rococo::local_config( rococo::BRIDGE_HUB_ROCOCO_LOCAL, "Rococo BridgeHub Local", @@ -184,7 +159,7 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup pub mod rococo { use super::{get_account_id_from_seed, get_collator_keys_from_seed, sr25519, ParaId}; - use crate::chain_spec::{Extensions, SAFE_XCM_VERSION}; + use crate::chain_spec::{Extensions, GenericChainSpec, SAFE_XCM_VERSION}; use parachains_common::{AccountId, AuraId}; use sc_chain_spec::ChainType; @@ -196,9 +171,6 @@ pub mod rococo { const BRIDGE_HUB_ROCOCO_ED: BridgeHubBalance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; - /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub fn local_config( id: &str, chain_name: &str, @@ -206,7 +178,7 @@ pub mod rococo { para_id: ParaId, bridges_pallet_owner_seed: Option, modify_props: ModifyProperties, - ) -> BridgeHubChainSpec { + ) -> GenericChainSpec { // Rococo defaults let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); @@ -214,7 +186,7 @@ pub mod rococo { properties.insert("tokenDecimals".into(), 12.into()); modify_props(&mut properties); - BridgeHubChainSpec::builder( + GenericChainSpec::builder( bridge_hub_rococo_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, @@ -303,7 +275,8 @@ pub mod rococo { pub mod kusama { use super::{BridgeHubBalance, ParaId}; use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use parachains_common::{AccountId, AuraId}; use sc_chain_spec::ChainType; @@ -315,21 +288,18 @@ pub mod kusama { const BRIDGE_HUB_KUSAMA_ED: BridgeHubBalance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; - /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub fn local_config( id: &str, chain_name: &str, relay_chain: &str, para_id: ParaId, - ) -> BridgeHubChainSpec { + ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); - BridgeHubChainSpec::builder( + GenericChainSpec::builder( bridge_hub_kusama_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, @@ -411,7 +381,7 @@ pub mod kusama { /// Sub-module for Westend setup. pub mod westend { use super::{get_account_id_from_seed, get_collator_keys_from_seed, sr25519, ParaId}; - use crate::chain_spec::{Extensions, SAFE_XCM_VERSION}; + use crate::chain_spec::{Extensions, GenericChainSpec, SAFE_XCM_VERSION}; use parachains_common::{AccountId, AuraId}; use sc_chain_spec::ChainType; @@ -423,22 +393,18 @@ pub mod westend { const BRIDGE_HUB_WESTEND_ED: BridgeHubBalance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; - /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = - sc_service::GenericChainSpec; - pub fn local_config( id: &str, chain_name: &str, relay_chain: &str, para_id: ParaId, bridges_pallet_owner_seed: Option, - ) -> BridgeHubChainSpec { + ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - BridgeHubChainSpec::builder( + GenericChainSpec::builder( bridge_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, @@ -527,7 +493,8 @@ pub mod westend { pub mod polkadot { use super::{BridgeHubBalance, ParaId}; use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use parachains_common::{AccountId, AuraId}; use sc_chain_spec::ChainType; @@ -539,21 +506,18 @@ pub mod polkadot { const BRIDGE_HUB_POLKADOT_ED: BridgeHubBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; - /// Specialized `ChainSpec` for the normal parachain runtime. - pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>; - pub fn local_config( id: &str, chain_name: &str, relay_chain: &str, para_id: ParaId, - ) -> BridgeHubChainSpec { + ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - BridgeHubChainSpec::builder( + GenericChainSpec::builder( bridge_hub_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 07bd742fa8e..ac75a40ebde 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -15,16 +15,14 @@ // along with Cumulus. If not, see . use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, AuraId, Balance as CollectivesBalance}; use sc_service::ChainType; use sp_core::sr25519; -pub type CollectivesPolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>; -pub type CollectivesWestendChainSpec = sc_service::GenericChainSpec<(), Extensions>; - const COLLECTIVES_POLKADOT_ED: CollectivesBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; const COLLECTIVES_WESTEND_ED: CollectivesBalance = @@ -39,13 +37,13 @@ pub fn collectives_polkadot_session_keys( collectives_polkadot_runtime::SessionKeys { aura: keys } } -pub fn collectives_polkadot_development_config() -> CollectivesPolkadotChainSpec { +pub fn collectives_polkadot_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - CollectivesPolkadotChainSpec::builder( + GenericChainSpec::builder( collectives_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-dev".into(), para_id: 1002 }, @@ -75,13 +73,13 @@ pub fn collectives_polkadot_development_config() -> CollectivesPolkadotChainSpec } /// Collectives Polkadot Local Config. -pub fn collectives_polkadot_local_config() -> CollectivesPolkadotChainSpec { +pub fn collectives_polkadot_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 0.into()); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); - CollectivesPolkadotChainSpec::builder( + GenericChainSpec::builder( collectives_polkadot_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "polkadot-local".into(), para_id: 1002 }, @@ -169,13 +167,13 @@ pub fn collectives_westend_session_keys(keys: AuraId) -> collectives_westend_run collectives_westend_runtime::SessionKeys { aura: keys } } -pub fn collectives_westend_development_config() -> CollectivesWestendChainSpec { +pub fn collectives_westend_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - CollectivesWestendChainSpec::builder( + GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-dev".into(), para_id: 1002 }, @@ -205,13 +203,13 @@ pub fn collectives_westend_development_config() -> CollectivesWestendChainSpec { } /// Collectives Westend Local Config. -pub fn collectives_westend_local_config() -> CollectivesWestendChainSpec { +pub fn collectives_westend_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); - CollectivesWestendChainSpec::builder( + GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-local".into(), para_id: 1002 }, diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs index 7ca66354fbf..87ac1ed2fa1 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs @@ -15,7 +15,8 @@ // along with Cumulus. If not, see . use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use cumulus_primitives_core::ParaId; use hex_literal::hex; @@ -23,8 +24,6 @@ use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -pub type ContractsRococoChainSpec = sc_service::GenericChainSpec<(), Extensions>; - /// No relay chain suffix because the id is the same over all relay chains. const CONTRACTS_PARACHAIN_ID: u32 = 1002; @@ -32,12 +31,12 @@ const CONTRACTS_PARACHAIN_ID: u32 = 1002; const CONTRACTS_ROCOCO_ED: contracts_rococo_runtime::Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; -pub fn contracts_rococo_development_config() -> ContractsRococoChainSpec { +pub fn contracts_rococo_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::builder( + GenericChainSpec::builder( contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! @@ -79,12 +78,12 @@ pub fn contracts_rococo_development_config() -> ContractsRococoChainSpec { .build() } -pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec { +pub fn contracts_rococo_local_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::builder( + GenericChainSpec::builder( contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! @@ -126,13 +125,13 @@ pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec { .build() } -pub fn contracts_rococo_config() -> ContractsRococoChainSpec { +pub fn contracts_rococo_config() -> GenericChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "ROC".into()); properties.insert("tokenDecimals".into(), 12.into()); - ContractsRococoChainSpec::builder( + GenericChainSpec::builder( contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID } ) diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index aff1358d1ae..8eced8d8f81 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, Extensions}; +use crate::chain_spec::{get_account_id_from_seed, Extensions, GenericChainSpec}; use cumulus_primitives_core::ParaId; use parachains_common::AuraId; use sc_service::ChainType; @@ -22,12 +22,8 @@ use sp_core::sr25519; use super::get_collator_keys_from_seed; -/// Specialized `ChainSpec` for the Glutton parachain runtime. -pub type GluttonChainSpec = sc_service::GenericChainSpec<(), Extensions>; -pub type GluttonWestendChainSpec = sc_service::GenericChainSpec<(), Extensions>; - -pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec { - GluttonChainSpec::builder( +pub fn glutton_development_config(para_id: ParaId) -> GenericChainSpec { + GenericChainSpec::builder( glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-dev".into(), para_id: para_id.into() }, ) @@ -41,8 +37,8 @@ pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec { .build() } -pub fn glutton_local_config(para_id: ParaId) -> GluttonChainSpec { - GluttonChainSpec::builder( +pub fn glutton_local_config(para_id: ParaId) -> GenericChainSpec { + GenericChainSpec::builder( glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama-local".into(), para_id: para_id.into() }, ) @@ -59,11 +55,11 @@ pub fn glutton_local_config(para_id: ParaId) -> GluttonChainSpec { .build() } -pub fn glutton_config(para_id: ParaId) -> GluttonChainSpec { +pub fn glutton_config(para_id: ParaId) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 2.into()); - GluttonChainSpec::builder( + GenericChainSpec::builder( glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "kusama".into(), para_id: para_id.into() }, ) @@ -94,8 +90,8 @@ fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json:: }) } -pub fn glutton_westend_development_config(para_id: ParaId) -> GluttonWestendChainSpec { - GluttonWestendChainSpec::builder( +pub fn glutton_westend_development_config(para_id: ParaId) -> GenericChainSpec { + GenericChainSpec::builder( glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-dev".into(), para_id: para_id.into() }, ) @@ -109,8 +105,8 @@ pub fn glutton_westend_development_config(para_id: ParaId) -> GluttonWestendChai .build() } -pub fn glutton_westend_local_config(para_id: ParaId) -> GluttonWestendChainSpec { - GluttonWestendChainSpec::builder( +pub fn glutton_westend_local_config(para_id: ParaId) -> GenericChainSpec { + GenericChainSpec::builder( glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend-local".into(), para_id: para_id.into() }, ) @@ -127,11 +123,11 @@ pub fn glutton_westend_local_config(para_id: ParaId) -> GluttonWestendChainSpec .build() } -pub fn glutton_westend_config(para_id: ParaId) -> GluttonWestendChainSpec { +pub fn glutton_westend_config(para_id: ParaId) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); - GluttonChainSpec::builder( + GenericChainSpec::builder( glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: para_id.into() }, ) diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index 9cd0a37ad63..e8ed8a74ed7 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -50,6 +50,9 @@ impl Extensions { } } +/// Generic chain spec for all polkadot-parachain runtimes +pub type GenericChainSpec = sc_service::GenericChainSpec<(), Extensions>; + /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index 2e35ee231df..cb1cb632d63 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -15,23 +15,22 @@ // along with Cumulus. If not, see . use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, + get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, + SAFE_XCM_VERSION, }; use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; use sp_core::sr25519; -/// Specialized `ChainSpec` for the normal parachain runtime. -pub type PenpalChainSpec = sc_service::GenericChainSpec<(), Extensions>; -pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> PenpalChainSpec { +pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "UNIT".into()); properties.insert("tokenDecimals".into(), 12u32.into()); properties.insert("ss58Format".into(), 42u32.into()); - PenpalChainSpec::builder( + GenericChainSpec::builder( penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: relay_chain.into(), // You MUST set this to the correct network! diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index c2ba4431456..0434e5f7be8 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -16,7 +16,7 @@ //! ChainSpecs dedicated to Rococo parachain setups (for testing and example purposes) -use crate::chain_spec::{get_from_seed, Extensions, SAFE_XCM_VERSION}; +use crate::chain_spec::{get_from_seed, Extensions, GenericChainSpec, SAFE_XCM_VERSION}; use cumulus_primitives_core::ParaId; use hex_literal::hex; use parachains_common::AccountId; @@ -25,10 +25,8 @@ use rococo_parachain_runtime::AuraId; use sc_chain_spec::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -pub type RococoParachainChainSpec = sc_service::GenericChainSpec<(), Extensions>; - -pub fn rococo_parachain_local_config() -> RococoParachainChainSpec { - RococoParachainChainSpec::builder( +pub fn rococo_parachain_local_config() -> GenericChainSpec { + GenericChainSpec::builder( rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id: 1000 }, ) @@ -57,9 +55,9 @@ pub fn rococo_parachain_local_config() -> RococoParachainChainSpec { .build() } -pub fn staging_rococo_parachain_local_config() -> RococoParachainChainSpec { +pub fn staging_rococo_parachain_local_config() -> GenericChainSpec { #[allow(deprecated)] - RococoParachainChainSpec::builder( + GenericChainSpec::builder( rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), para_id: 1000 }, ) diff --git a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs index b034588e14c..32d51622054 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, Extensions}; +use crate::chain_spec::{get_account_id_from_seed, Extensions, GenericChainSpec}; use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, AuraId}; use sc_service::ChainType; @@ -22,11 +22,8 @@ use sp_core::sr25519; use super::get_collator_keys_from_seed; -/// Specialized `ChainSpec` for the seedling parachain runtime. -pub type SeedlingChainSpec = sc_service::GenericChainSpec<(), Extensions>; - -pub fn get_seedling_chain_spec() -> SeedlingChainSpec { - SeedlingChainSpec::builder( +pub fn get_seedling_chain_spec() -> GenericChainSpec { + GenericChainSpec::builder( seedling_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 2000 }, ) diff --git a/cumulus/polkadot-parachain/src/chain_spec/shell.rs b/cumulus/polkadot-parachain/src/chain_spec/shell.rs index 02c65e809a6..e0a9875fb96 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/shell.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/shell.rs @@ -14,18 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::Extensions; +use crate::chain_spec::{Extensions, GenericChainSpec}; use cumulus_primitives_core::ParaId; use parachains_common::AuraId; use sc_service::ChainType; use super::get_collator_keys_from_seed; -/// Specialized `ChainSpec` for the shell parachain runtime. -pub type ShellChainSpec = sc_service::GenericChainSpec<(), Extensions>; - -pub fn get_shell_chain_spec() -> ShellChainSpec { - ShellChainSpec::builder( +pub fn get_shell_chain_spec() -> GenericChainSpec { + GenericChainSpec::builder( shell_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index ea19ad12ba0..f966a5db8f3 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -16,6 +16,7 @@ use crate::{ chain_spec, + chain_spec::GenericChainSpec, cli::{Cli, RelayChainCli, Subcommand}, fake_runtime_api::{ asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, aura::RuntimeApi, @@ -128,18 +129,15 @@ fn load_spec(id: &str) -> std::result::Result, String> { // - Defaul-like "staging" => Box::new(chain_spec::rococo_parachain::staging_rococo_parachain_local_config()), - "tick" => - Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/tick.json")[..], - )?), - "trick" => - Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/trick.json")[..], - )?), - "track" => - Box::new(chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/track.json")[..], - )?), + "tick" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/tick.json")[..], + )?), + "trick" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/trick.json")[..], + )?), + "track" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/track.json")[..], + )?), // -- Starters "shell" => Box::new(chain_spec::shell::get_shell_chain_spec()), @@ -154,10 +152,9 @@ fn load_spec(id: &str) -> std::result::Result, String> { "asset-hub-polkadot-genesis" | "statemint-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_polkadot_config()), // the shell-based chain spec as used for syncing - "asset-hub-polkadot" | "statemint" => - Box::new(chain_spec::asset_hubs::AssetHubPolkadotChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-polkadot.json")[..], - )?), + "asset-hub-polkadot" | "statemint" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-polkadot.json")[..], + )?), // -- Asset Hub Kusama "asset-hub-kusama-dev" | "statemine-dev" => @@ -168,10 +165,9 @@ fn load_spec(id: &str) -> std::result::Result, String> { "asset-hub-kusama-genesis" | "statemine-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_kusama_config()), // the shell-based chain spec as used for syncing - "asset-hub-kusama" | "statemine" => - Box::new(chain_spec::asset_hubs::AssetHubKusamaChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], - )?), + "asset-hub-kusama" | "statemine" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], + )?), // -- Asset Hub Rococo "asset-hub-rococo-dev" => @@ -181,10 +177,9 @@ fn load_spec(id: &str) -> std::result::Result, String> { // the chain spec as used for generating the upgrade genesis values "asset-hub-rococo-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_rococo_genesis_config()), - "asset-hub-rococo" => - Box::new(chain_spec::asset_hubs::AssetHubRococoChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-rococo.json")[..], - )?), + "asset-hub-rococo" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-rococo.json")[..], + )?), // -- Asset Hub Westend "asset-hub-westend-dev" | "westmint-dev" => @@ -195,28 +190,25 @@ fn load_spec(id: &str) -> std::result::Result, String> { "asset-hub-westend-genesis" | "westmint-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_westend_config()), // the shell-based chain spec as used for syncing - "asset-hub-westend" | "westmint" => - Box::new(chain_spec::asset_hubs::AssetHubWestendChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-westend.json")[..], - )?), + "asset-hub-westend" | "westmint" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-westend.json")[..], + )?), // -- Polkadot Collectives "collectives-polkadot-dev" => Box::new(chain_spec::collectives::collectives_polkadot_development_config()), "collectives-polkadot-local" => Box::new(chain_spec::collectives::collectives_polkadot_local_config()), - "collectives-polkadot" => - Box::new(chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/collectives-polkadot.json")[..], - )?), + "collectives-polkadot" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/collectives-polkadot.json")[..], + )?), "collectives-westend-dev" => Box::new(chain_spec::collectives::collectives_westend_development_config()), "collectives-westend-local" => Box::new(chain_spec::collectives::collectives_westend_local_config()), - "collectives-westend" => - Box::new(chain_spec::collectives::CollectivesWestendChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/collectives-westend.json")[..], - )?), + "collectives-westend" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/collectives-westend.json")[..], + )?), // -- Contracts on Rococo "contracts-rococo-dev" => @@ -224,10 +216,9 @@ fn load_spec(id: &str) -> std::result::Result, String> { "contracts-rococo-local" => Box::new(chain_spec::contracts::contracts_rococo_local_config()), "contracts-rococo-genesis" => Box::new(chain_spec::contracts::contracts_rococo_config()), - "contracts-rococo" => - Box::new(chain_spec::contracts::ContractsRococoChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/contracts-rococo.json")[..], - )?), + "contracts-rococo" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/contracts-rococo.json")[..], + )?), // -- BridgeHub bridge_like_id @@ -279,44 +270,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { }, // -- Loading a specific spec from disk - path => { - let path: PathBuf = path.into(); - match path.runtime() { - Runtime::AssetHubPolkadot => Box::new( - chain_spec::asset_hubs::AssetHubPolkadotChainSpec::from_json_file(path)?, - ), - 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::AssetHubWestend => Box::new( - chain_spec::asset_hubs::AssetHubWestendChainSpec::from_json_file(path)?, - ), - Runtime::CollectivesPolkadot => Box::new( - chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_file(path)?, - ), - Runtime::CollectivesWestend => Box::new( - chain_spec::collectives::CollectivesWestendChainSpec::from_json_file(path)?, - ), - Runtime::Shell => - Box::new(chain_spec::shell::ShellChainSpec::from_json_file(path)?), - Runtime::Seedling => - Box::new(chain_spec::seedling::SeedlingChainSpec::from_json_file(path)?), - Runtime::ContractsRococo => - Box::new(chain_spec::contracts::ContractsRococoChainSpec::from_json_file(path)?), - Runtime::BridgeHub(bridge_hub_runtime_type) => - bridge_hub_runtime_type.chain_spec_from_json_file(path)?, - Runtime::Penpal(_para_id) => - Box::new(chain_spec::penpal::PenpalChainSpec::from_json_file(path)?), - Runtime::GluttonWestend => - Box::new(chain_spec::glutton::GluttonChainSpec::from_json_file(path)?), - Runtime::Glutton => - Box::new(chain_spec::glutton::GluttonChainSpec::from_json_file(path)?), - Runtime::Default => Box::new( - chain_spec::rococo_parachain::RococoParachainChainSpec::from_json_file(path)?, - ), - } - }, + path => Box::new(GenericChainSpec::from_json_file(path.into())?), }) } -- GitLab From 73ff1c3647024d3a5e94727e7fb74714c3a98b47 Mon Sep 17 00:00:00 2001 From: Wil Wade Date: Sat, 25 Nov 2023 05:30:57 -0500 Subject: [PATCH 582/633] Update documentation for SafeMode and TxPause Pallets (#2413) # Description Documentation for the TxPause and SafeMode pallets. Based on reading and the notes from the following related PRs: - https://github.com/paritytech/substrate/pull/12092 I believe this also completes the checklist to be able to close the related PRs: - Close #302 - Close #274 --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 2 + substrate/frame/safe-mode/Cargo.toml | 1 + substrate/frame/safe-mode/src/lib.rs | 56 ++++++++++++++++++++++++++ substrate/frame/safe-mode/src/tests.rs | 3 ++ substrate/frame/tx-pause/Cargo.toml | 1 + substrate/frame/tx-pause/src/lib.rs | 56 ++++++++++++++++++++++++++ substrate/frame/tx-pause/src/tests.rs | 3 ++ 7 files changed, 122 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 3fbede968bc..8a3f8e05fbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10795,6 +10795,7 @@ dependencies = [ name = "pallet-safe-mode" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11198,6 +11199,7 @@ dependencies = [ name = "pallet-tx-pause" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index ac469bb385c..f7b4ea4dd8c 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +docify = "0.2.6" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/safe-mode/src/lib.rs b/substrate/frame/safe-mode/src/lib.rs index b8e8378fa9e..554f509db63 100644 --- a/substrate/frame/safe-mode/src/lib.rs +++ b/substrate/frame/safe-mode/src/lib.rs @@ -15,6 +15,62 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # Safe Mode +//! +//! Trigger for stopping all extrinsics outside of a specific whitelist. +//! +//! ## WARNING +//! +//! NOT YET AUDITED. DO NOT USE IN PRODUCTION. +//! +//! ## Pallet API +//! +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events, and errors. +//! +//! ## Overview +//! +//! Safe mode is entered via two paths (deposit or forced) until a set block number. +//! The mode is exited when the block number is reached or a call to one of the exit extrinsics is +//! made. A `WhitelistedCalls` configuration item contains all calls that can be executed while in +//! safe mode. +//! +//! ### Primary Features +//! +//! - Entering safe mode can be via privileged origin or anyone who places a deposit. +//! - Origin configuration items are separated for privileged entering and exiting safe mode. +//! - A configurable duration sets the number of blocks after which the system will exit safe mode. +//! - Safe mode may be extended beyond the configured exit by additional calls. +//! +//! ### Example +//! +//! Configuration of call filters: +//! +//! ```ignore +//! impl frame_system::Config for Runtime { +//! // … +//! type BaseCallFilter = InsideBoth; +//! // … +//! } +//! ``` +//! +//! Entering safe mode with deposit: +#![doc = docify::embed!("src/tests.rs", can_activate)] +//! +//! Entering safe mode via privileged origin: +#![doc = docify::embed!("src/tests.rs", can_force_activate_with_config_origin)] +//! +//! Exiting safe mode via privileged origin: +#![doc = docify::embed!("src/tests.rs", can_force_deactivate_with_config_origin)] +//! +//! ## Low Level / Implementation Details +//! +//! ### Use Cost +//! +//! A storage value (`EnteredUntil`) is used to store the block safe mode will be exited on. +//! Using the call filter will require a db read of that storage on the first extrinsic. +//! The storage will be added to the overlay and incur low cost for all additional calls. + #![cfg_attr(not(feature = "std"), no_std)] #![deny(rustdoc::broken_intra_doc_links)] diff --git a/substrate/frame/safe-mode/src/tests.rs b/substrate/frame/safe-mode/src/tests.rs index b92c5b87a53..c0a2f45a3e7 100644 --- a/substrate/frame/safe-mode/src/tests.rs +++ b/substrate/frame/safe-mode/src/tests.rs @@ -189,6 +189,7 @@ fn can_filter_balance_in_proxy_when_activated() { }); } +#[docify::export] #[test] fn can_activate() { new_test_ext().execute_with(|| { @@ -271,6 +272,7 @@ fn fails_force_deactivate_if_not_activated() { }); } +#[docify::export] #[test] fn can_force_activate_with_config_origin() { new_test_ext().execute_with(|| { @@ -288,6 +290,7 @@ fn can_force_activate_with_config_origin() { }); } +#[docify::export] #[test] fn can_force_deactivate_with_config_origin() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 9af424f541c..bf0641f5b6d 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +docify = "0.2.6" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/tx-pause/src/lib.rs b/substrate/frame/tx-pause/src/lib.rs index a3be0f50172..31be575fba7 100644 --- a/substrate/frame/tx-pause/src/lib.rs +++ b/substrate/frame/tx-pause/src/lib.rs @@ -15,6 +15,62 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # Transaction Pause +//! +//! Allows dynamic, chain-state-based pausing and unpausing of specific extrinsics via call filters. +//! +//! ## WARNING +//! +//! NOT YET AUDITED. DO NOT USE IN PRODUCTION. +//! +//! ## Pallet API +//! +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events, and errors. +//! +//! ## Overview +//! +//! A dynamic call filter that can be controlled with extrinsics. +//! +//! Pausing an extrinsic means that the extrinsic CANNOT be called again until it is unpaused. +//! The exception is calls that use `dispatch_bypass_filter`, typically only with the root origin. +//! +//! ### Primary Features +//! +//! - Calls that should never be paused can be added to a whitelist. +//! - Separate origins are configurable for pausing and pausing. +//! - Pausing is triggered using the string representation of the call. +//! - Pauses can target a single extrinsic or an entire pallet. +//! - Pauses can target future extrinsics or pallets. +//! +//! ### Example +//! +//! Configuration of call filters: +//! +//! ```ignore +//! impl frame_system::Config for Runtime { +//! // … +//! type BaseCallFilter = InsideBoth; +//! // … +//! } +//! ``` +//! +//! Pause specific all: +#![doc = docify::embed!("src/tests.rs", can_pause_specific_call)] +//! +//! Unpause specific all: +#![doc = docify::embed!("src/tests.rs", can_unpause_specific_call)] +//! +//! Pause all calls in a pallet: +#![doc = docify::embed!("src/tests.rs", can_pause_all_calls_in_pallet_except_on_whitelist)] +//! +//! ## Low Level / Implementation Details +//! +//! ### Use Cost +//! +//! A storage map (`PausedCalls`) is used to store currently paused calls. +//! Using the call filter will require a db read of that storage on each extrinsic. + #![cfg_attr(not(feature = "std"), no_std)] #![deny(rustdoc::broken_intra_doc_links)] diff --git a/substrate/frame/tx-pause/src/tests.rs b/substrate/frame/tx-pause/src/tests.rs index a71ff3439d9..823abf9d9c4 100644 --- a/substrate/frame/tx-pause/src/tests.rs +++ b/substrate/frame/tx-pause/src/tests.rs @@ -25,6 +25,7 @@ use sp_runtime::DispatchError; // GENERAL SUCCESS/POSITIVE TESTS --------------------- +#[docify::export] #[test] fn can_pause_specific_call() { new_test_ext().execute_with(|| { @@ -43,6 +44,7 @@ fn can_pause_specific_call() { }); } +#[docify::export] #[test] fn can_pause_all_calls_in_pallet_except_on_whitelist() { new_test_ext().execute_with(|| { @@ -64,6 +66,7 @@ fn can_pause_all_calls_in_pallet_except_on_whitelist() { }); } +#[docify::export] #[test] fn can_unpause_specific_call() { new_test_ext().execute_with(|| { -- GitLab From cfa19c37e60f094a2954ffa73b1da261c050f61f Mon Sep 17 00:00:00 2001 From: Marcin S Date: Sat, 25 Nov 2023 17:03:58 +0100 Subject: [PATCH 583/633] PVF: remove audit log access (#2461) --- .gitlab/pipeline/test.yml | 2 +- .../node/core/pvf/src/execute/worker_intf.rs | 31 +--- .../node/core/pvf/src/prepare/worker_intf.rs | 26 +-- polkadot/node/core/pvf/src/security.rs | 149 ------------------ 4 files changed, 3 insertions(+), 205 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 79ef9070dba..9c3fa7701c8 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -522,4 +522,4 @@ test-syscalls: - 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 + allow_failure: false # this rarely triggers in practice diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index fc6cd8fc725..16a7c290b52 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -18,7 +18,6 @@ use crate::{ artifacts::ArtifactPathId, - security, worker_intf::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, @@ -33,7 +32,7 @@ use polkadot_node_core_pvf_common::{ execute::{Handshake, WorkerResponse}, worker_dir, SecurityStatus, }; -use polkadot_parachain_primitives::primitives::{ValidationCodeHash, ValidationResult}; +use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::ExecutorParams; use std::{path::Path, time::Duration}; use tokio::{io, net::UnixStream}; @@ -132,10 +131,7 @@ pub async fn start_work( artifact.path.display(), ); - let artifact_path = artifact.path.clone(); with_worker_dir_setup(worker_dir, pid, &artifact.path, |worker_dir| async move { - let audit_log_file = security::AuditLogFile::try_open_and_seek_to_end().await; - if let Err(error) = send_request(&mut stream, &validation_params, execution_timeout).await { gum::warn!( target: LOG_TARGET, @@ -160,10 +156,7 @@ pub async fn start_work( handle_response( response, pid, - &artifact.id.code_hash, - &artifact_path, execution_timeout, - audit_log_file ) .await, Err(error) => { @@ -217,10 +210,7 @@ pub async fn start_work( async fn handle_response( response: WorkerResponse, worker_pid: u32, - validation_code_hash: &ValidationCodeHash, - artifact_path: &Path, execution_timeout: Duration, - audit_log_file: Option, ) -> WorkerResponse { if let WorkerResponse::Ok { duration, .. } = response { if duration > execution_timeout { @@ -238,25 +228,6 @@ async fn handle_response( } } - if let WorkerResponse::JobDied { err: _, job_pid } = response { - // The job died. Check if it was due to a seccomp violation. - // - // NOTE: Log, but don't change the outcome. Not all validators may have - // auditing enabled, so we don't want attackers to abuse a non-deterministic - // outcome. - for syscall in security::check_seccomp_violations_for_job(audit_log_file, job_pid).await { - gum::error!( - target: LOG_TARGET, - %worker_pid, - %job_pid, - %syscall, - ?validation_code_hash, - ?artifact_path, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } - } - response } diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index f978005068c..a393e9baa9e 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -19,7 +19,6 @@ use crate::{ artifacts::ArtifactId, metrics::Metrics, - security, worker_intf::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, @@ -134,7 +133,6 @@ pub async fn start_work( pid, |tmp_artifact_file, mut stream, worker_dir| async move { let preparation_timeout = pvf.prep_timeout(); - let audit_log_file = security::AuditLogFile::try_open_and_seek_to_end().await; if let Err(err) = send_request(&mut stream, &pvf).await { gum::warn!( @@ -170,7 +168,6 @@ pub async fn start_work( &pvf, &cache_path, preparation_timeout, - audit_log_file, ) .await, Ok(Err(err)) => { @@ -211,34 +208,13 @@ async fn handle_response( pvf: &PvfPrepData, cache_path: &Path, preparation_timeout: Duration, - audit_log_file: Option, ) -> Outcome { let PrepareWorkerSuccess { checksum, stats: PrepareStats { cpu_time_elapsed, memory_stats } } = match result.clone() { Ok(result) => result, // Timed out on the child. This should already be logged by the child. Err(PrepareError::TimedOut) => return Outcome::TimedOut, - Err(PrepareError::JobDied { err, job_pid }) => { - // The job died. Check if it was due to a seccomp violation. - // - // NOTE: Log, but don't change the outcome. Not all validators may have - // auditing enabled, so we don't want attackers to abuse a non-deterministic - // outcome. - for syscall in - security::check_seccomp_violations_for_job(audit_log_file, job_pid).await - { - gum::error!( - target: LOG_TARGET, - %worker_pid, - %job_pid, - %syscall, - ?pvf, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } - - return Outcome::JobDied { err, job_pid } - }, + Err(PrepareError::JobDied { err, job_pid }) => return Outcome::JobDied { err, job_pid }, Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, Err(err) => return Outcome::Concluded { worker, result: Err(err) }, }; diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index ef8714f58c8..2fd3b53e96b 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -17,10 +17,6 @@ use crate::{Config, SecurityStatus, LOG_TARGET}; use futures::join; use std::{fmt, path::Path}; -use tokio::{ - fs::{File, OpenOptions}, - io::{AsyncReadExt, AsyncSeekExt, SeekFrom}, -}; const SECURE_MODE_ANNOUNCEMENT: &'static str = "In the next release this will be a hard error by default. @@ -35,7 +31,6 @@ const SECURE_MODE_ANNOUNCEMENT: &'static str = pub async fn check_security_status(config: &Config) -> SecurityStatus { let Config { prepare_worker_program_path, cache_path, .. } = config; - // TODO: add check that syslog is available and that seccomp violations are logged? let (landlock, seccomp, change_root) = join!( check_landlock(prepare_worker_program_path), check_seccomp(prepare_worker_program_path), @@ -303,147 +298,3 @@ async fn check_seccomp( } } } - -const AUDIT_LOG_PATH: &'static str = "/var/log/audit/audit.log"; -const SYSLOG_PATH: &'static str = "/var/log/syslog"; - -/// System audit log. -pub struct AuditLogFile { - file: File, - path: &'static str, -} - -impl AuditLogFile { - /// Looks for an audit log file on the system and opens it, seeking to the end to skip any - /// events from before this was called. - /// - /// A bit of a verbose name, but it should clue future refactorers not to move calls closer to - /// where the `AuditLogFile` is used. - pub async fn try_open_and_seek_to_end() -> Option { - let mut path = AUDIT_LOG_PATH; - let mut file = match OpenOptions::new().read(true).open(AUDIT_LOG_PATH).await { - Ok(file) => Ok(file), - Err(_) => { - path = SYSLOG_PATH; - OpenOptions::new().read(true).open(SYSLOG_PATH).await - }, - } - .ok()?; - - let _pos = file.seek(SeekFrom::End(0)).await; - - Some(Self { file, path }) - } - - async fn read_new_since_open(mut self) -> String { - let mut buf = String::new(); - let _len = self.file.read_to_string(&mut buf).await; - buf - } -} - -/// Check if a seccomp violation occurred for the given job process. As the syslog may be in a -/// different location, or seccomp auditing may be disabled, this function provides a best-effort -/// attempt only. -/// -/// The `audit_log_file` must have been obtained before the job started. It only allows reading -/// entries that were written since it was obtained, so that we do not consider events from previous -/// processes with the same pid. This can still be racy, but it's unlikely and fine for a -/// best-effort attempt. -pub async fn check_seccomp_violations_for_job( - audit_log_file: Option, - job_pid: i32, -) -> Vec { - let audit_event_pid_field = format!("pid={job_pid}"); - - let audit_log_file = match audit_log_file { - Some(file) => { - gum::trace!( - target: LOG_TARGET, - %job_pid, - audit_log_path = ?file.path, - "checking audit log for seccomp violations", - ); - file - }, - None => { - gum::warn!( - target: LOG_TARGET, - %job_pid, - "could not open either {AUDIT_LOG_PATH} or {SYSLOG_PATH} for reading audit logs" - ); - return vec![] - }, - }; - let events = audit_log_file.read_new_since_open().await; - - let mut violations = vec![]; - for event in events.lines() { - if let Some(syscall) = parse_audit_log_for_seccomp_event(event, &audit_event_pid_field) { - violations.push(syscall); - } - } - - violations -} - -fn parse_audit_log_for_seccomp_event(event: &str, audit_event_pid_field: &str) -> Option { - const SECCOMP_AUDIT_EVENT_TYPE: &'static str = "type=1326"; - - // Do a series of simple .contains instead of a regex, because I'm not sure if the fields are - // guaranteed to always be in the same order. - if !event.contains(SECCOMP_AUDIT_EVENT_TYPE) || !event.contains(&audit_event_pid_field) { - return None - } - - // Get the syscall. Let's avoid a dependency on regex just for this. - for field in event.split(" ") { - if let Some(syscall) = field.strip_prefix("syscall=") { - return syscall.parse::().ok() - } - } - - None -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_audit_log_for_seccomp_event() { - let audit_event_pid_field = "pid=2559058"; - - assert_eq!( - parse_audit_log_for_seccomp_event( - r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1326 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559058 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, - audit_event_pid_field - ), - Some(53) - ); - // pid is wrong - assert_eq!( - parse_audit_log_for_seccomp_event( - r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1326 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, - audit_event_pid_field - ), - None - ); - // type is wrong - assert_eq!( - parse_audit_log_for_seccomp_event( - r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1327 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e syscall=53 compat=0 ip=0x7f7542c80d5e code=0x80000000"#, - audit_event_pid_field - ), - None - ); - // no syscall field - assert_eq!( - parse_audit_log_for_seccomp_event( - r#"Oct 24 13:15:24 build kernel: [5883980.283910] audit: type=1327 audit(1698153324.786:23): auid=0 uid=0 gid=0 ses=2162 subj=unconfined pid=2559057 comm="polkadot-prepar" exe="/root/paritytech/polkadot-sdk-2/target/debug/polkadot-prepare-worker" sig=31 arch=c000003e compat=0 ip=0x7f7542c80d5e code=0x80000000"#, - audit_event_pid_field - ), - None - ); - } -} -- GitLab From 4f8048b9c7a333cd8020ec4498fe96567ddeee18 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 27 Nov 2023 10:16:35 +0100 Subject: [PATCH 584/633] New runtime `spec_version` format + backport of the bump to 1.4.0 (#2468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Overview This PR aligns the `spec_version` formatting to the [recent changes](https://github.com/polkadot-fellows/runtimes/pull/26/files#diff-efa4caeb17487ecb13d8f5eb7863c3241d84afa2e73fbf25909a2ca89df0f362R142) made for the Polkadot/Kusama runtimes. It also backports the latest version `v1.4.0` bumps as `1_004_000`. ## Details During the switch from `v0.9` to `v1.x`, the format of the `spec_version` was modified from: `(M)m_ppp` for a runtime considered on version `M.m.pp`. For instance `0.9.42` had a `spec_version` of `9420`. With the transition to `v1.x`, the format was changed to a bigger number (still `u32`) formatted as `MM_mm_ppp` where `1.2.3` would be stored as `01_02_003`. This PR aligns the format with that has been introduced in the fellowship repo: `MMM_mmm_ppp`. --------- Co-authored-by: Bastian Köcher --- .../parachains/runtimes/assets/asset-hub-kusama/src/lib.rs | 4 ++-- .../parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs | 2 +- .../parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 4 ++-- .../parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../runtimes/collectives/collectives-polkadot/src/lib.rs | 2 +- .../runtimes/collectives/collectives-westend/src/lib.rs | 2 +- .../parachains/runtimes/contracts/contracts-rococo/src/lib.rs | 2 +- cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs | 2 +- .../parachains/runtimes/glutton/glutton-westend/src/lib.rs | 2 +- cumulus/parachains/runtimes/starters/seedling/src/lib.rs | 2 +- cumulus/parachains/runtimes/testing/penpal/src/lib.rs | 2 +- .../parachains/runtimes/testing/rococo-parachain/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) 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 af0116d7014..4c76262f60a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -114,7 +114,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -130,7 +130,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, 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 1b7ef10f485..78721b194d0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -140,7 +140,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemint"), impl_name: create_runtime_str!("statemint"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 02b51310890..c6c9735ecb1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -114,7 +114,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -127,7 +127,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, 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 d52edfe479c..a0d5a528c3f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -111,7 +111,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, 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 d2db0340790..a511791d347 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 @@ -135,7 +135,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-kusama"), impl_name: create_runtime_str!("bridge-hub-kusama"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, 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 02f05a8bb87..e5c4f00f28e 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 @@ -135,7 +135,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-polkadot"), impl_name: create_runtime_str!("bridge-hub-polkadot"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, 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 7d64623f551..152e071a26a 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 @@ -170,7 +170,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 9c97728058f..764b9825d4e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -170,7 +170,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-westend"), impl_name: create_runtime_str!("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index c3d671c9085..90c44f8bfc5 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -115,7 +115,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives"), impl_name: create_runtime_str!("collectives"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 8c5593e154d..54cb898fd6c 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -110,7 +110,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_003_000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 9d6a53c5ed3..a7c06103c4a 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -131,7 +131,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 10001, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index 60a5d004e6c..ef0734df25f 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -98,7 +98,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton"), impl_name: create_runtime_str!("glutton"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 60107281c22..10f4d5f3307 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -99,7 +99,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 43c8f1488a6..7619ed19798 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -75,7 +75,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("seedling"), impl_name: create_runtime_str!("seedling"), authoring_version: 1, - spec_version: 10000, + spec_version: 1, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 1ddad31920a..b2a04272a4a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -230,7 +230,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("penpal-parachain"), impl_name: create_runtime_str!("penpal-parachain"), authoring_version: 1, - spec_version: 10000, + spec_version: 1, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 965fb0d6adc..3a890d7953a 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -106,7 +106,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 10000, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 675e0a20b2b..12388da1868 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -150,7 +150,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: 10020, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 29183fdfe00..6bbdb2db098 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -145,7 +145,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 10020, + spec_version: 1_004_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, -- GitLab From dc69dbba728bf447bb447746e41a86367d939030 Mon Sep 17 00:00:00 2001 From: Maciej Date: Mon, 27 Nov 2023 09:30:13 +0000 Subject: [PATCH 585/633] Zombienet tests - disputes on finalized blocks (#2184) **Overview:** Adding an extra malus variant focusing on disputing finalized blocks. It will: - wrap around approval-voting - listen to `OverseerSignal::BlockFinalized` and when encountered start a dispute for the `dispute_offset`th ancestor - simply pass through all other messages and signals Add zombienet tests testing various edgecases: - disputing freshly finalized blocks - disputing stale finalized blocks - disputing eagerly pruned finalized blocks (might be separate PR) **TODO:** - [x] Register new malus variant - [x] Simple pass through wrapper (approval-voting) - [x] Simple network definition - [x] Listen to block finalizations - [x] Fetch ancestor hash - [x] Fetch session index - [x] Fetch candidate - [x] Construct and send dispute message - [x] zndsl test 1 checking that disputes on fresh finalizations resolve valid Closes #1365 - [x] zndsl test 2 checking that disputes for too old finalized blocks are not possible Closes #1364 - [ ] zndsl test 3 checking that disputes for candidates with eagerly pruned relay parent state are handled correctly #1359 (deferred to a separate PR) - [x] Unit tests for new malus variant (testing cli etc) - [x] Clean/streamline error handling - [ ] ~~Ensure it tests properly on session boundaries~~ --------- Co-authored-by: Javier Viola Co-authored-by: Marcin S. Co-authored-by: Tsvetomir Dimitrov --- .gitlab/pipeline/zombienet/polkadot.yml | 16 ++ polkadot/node/malus/src/malus.rs | 46 +++ polkadot/node/malus/src/variants/common.rs | 4 +- .../variants/dispute_finalized_candidates.rs | 265 ++++++++++++++++++ polkadot/node/malus/src/variants/mod.rs | 2 + .../src/variants/suggest_garbage_candidate.rs | 2 +- .../0007-dispute-freshly-finalized.toml | 40 +++ .../0007-dispute-freshly-finalized.zndsl | 29 ++ .../0008-dispute-old-finalized.toml | 40 +++ .../0008-dispute-old-finalized.zndsl | 21 ++ 10 files changed, 462 insertions(+), 3 deletions(-) create mode 100644 polkadot/node/malus/src/variants/dispute_finalized_candidates.rs create mode 100644 polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml create mode 100644 polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl create mode 100644 polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml create mode 100644 polkadot/zombienet_tests/functional/0008-dispute-old-finalized.zndsl diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 995dd982532..d1f3a201c80 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -115,6 +115,22 @@ zombienet-polkadot-functional-0006-parachains-max-tranche0: --local-dir="${LOCAL_DIR}/functional" --test="0006-parachains-max-tranche0.zndsl" +zombienet-polkadot-functional-0007-dispute-freshly-finalized: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0007-dispute-freshly-finalized.zndsl" + +zombienet-polkadot-functional-0008-dispute-old-finalized: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0008-dispute-old-finalized.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common diff --git a/polkadot/node/malus/src/malus.rs b/polkadot/node/malus/src/malus.rs index 69dd7c869fc..b8a83e54d4f 100644 --- a/polkadot/node/malus/src/malus.rs +++ b/polkadot/node/malus/src/malus.rs @@ -36,6 +36,8 @@ enum NemesisVariant { BackGarbageCandidate(BackGarbageCandidateOptions), /// Delayed disputing of ancestors that are perfectly fine. DisputeAncestor(DisputeAncestorOptions), + /// Delayed disputing of finalized candidates. + DisputeFinalizedCandidates(DisputeFinalizedCandidatesOptions), } #[derive(Debug, Parser)] @@ -80,6 +82,15 @@ impl MalusCli { finality_delay, )? }, + NemesisVariant::DisputeFinalizedCandidates(opts) => { + let DisputeFinalizedCandidatesOptions { dispute_offset, cli } = opts; + + polkadot_cli::run_node( + cli, + DisputeFinalizedCandidates { dispute_offset }, + finality_delay, + )? + }, } Ok(()) } @@ -184,4 +195,39 @@ mod tests { assert!(run.cli.run.base.bob); }); } + + #[test] + fn dispute_finalized_candidates_works() { + let cli = MalusCli::try_parse_from(IntoIterator::into_iter([ + "malus", + "dispute-finalized-candidates", + "--bob", + ])) + .unwrap(); + assert_matches::assert_matches!(cli, MalusCli { + variant: NemesisVariant::DisputeFinalizedCandidates(run), + .. + } => { + assert!(run.cli.run.base.bob); + }); + } + + #[test] + fn dispute_finalized_offset_value_works() { + let cli = MalusCli::try_parse_from(IntoIterator::into_iter([ + "malus", + "dispute-finalized-candidates", + "--dispute-offset", + "13", + "--bob", + ])) + .unwrap(); + assert_matches::assert_matches!(cli, MalusCli { + variant: NemesisVariant::DisputeFinalizedCandidates(opts), + .. + } => { + assert_eq!(opts.dispute_offset, 13); // This line checks that dispute_offset is correctly set to 13 + assert!(opts.cli.run.base.bob); + }); + } } diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 20b6654638e..92264cd653d 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Implements common code for nemesis. Currently, only `FakeValidationResult` +//! Implements common code for nemesis. Currently, only `ReplaceValidationResult` //! interceptor is implemented. use crate::{ interceptor::*, @@ -188,7 +188,7 @@ where let _candidate_descriptor = candidate_descriptor.clone(); let mut subsystem_sender = subsystem_sender.clone(); let (sender, receiver) = std::sync::mpsc::channel(); - self.spawner.spawn_blocking( + self.spawner.spawn( "malus-get-validation-data", Some("malus"), Box::pin(async move { diff --git a/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs new file mode 100644 index 00000000000..113ab026879 --- /dev/null +++ b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs @@ -0,0 +1,265 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A malicious node variant that attempts to dispute finalized candidates. +//! +//! This malus variant behaves honestly in backing and approval voting. +//! The maliciousness comes from emitting an extra dispute statement on top of the other ones. +//! +//! Some extra quirks which generally should be insignificant: +//! - The malus node will not dispute at session boundaries +//! - The malus node will not dispute blocks it backed itself +//! - Be cautious about the size of the network to make sure disputes are not auto-confirmed +//! (7 validators is the smallest network size as it needs [(7-1)//3]+1 = 3 votes to get +//! confirmed but it only gets 1 from backing and 1 from malus so 2 in total) +//! +//! +//! Attention: For usage with `zombienet` only! + +#![allow(missing_docs)] + +use futures::channel::oneshot; +use polkadot_cli::{ + prepared_overseer_builder, + service::{ + AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, HeaderBackend, Overseer, + OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, ParachainHost, + ProvideRuntimeApi, + }, + Cli, +}; +use polkadot_node_subsystem::{messages::ApprovalVotingMessage, SpawnGlue}; +use polkadot_node_subsystem_types::{DefaultSubsystemClient, OverseerSignal}; +use polkadot_node_subsystem_util::request_candidate_events; +use polkadot_primitives::CandidateEvent; +use sp_core::traits::SpawnNamed; + +// Filter wrapping related types. +use crate::{interceptor::*, shared::MALUS}; + +use std::sync::Arc; + +/// Wraps around ApprovalVotingSubsystem and replaces it. +/// Listens to finalization messages and if possible triggers disputes for their ancestors. +#[derive(Clone)] +struct AncestorDisputer { + spawner: Spawner, //stores the actual ApprovalVotingSubsystem spawner + dispute_offset: u32, /* relative depth of the disputed block to the finalized block, + * 0=finalized, 1=parent of finalized etc */ +} + +impl MessageInterceptor for AncestorDisputer +where + Sender: overseer::ApprovalVotingSenderTrait + Clone + Send + 'static, + Spawner: overseer::gen::Spawner + Clone + 'static, +{ + type Message = ApprovalVotingMessage; + + /// Intercept incoming `OverseerSignal::BlockFinalized' and pass the rest as normal. + fn intercept_incoming( + &self, + subsystem_sender: &mut Sender, + msg: FromOrchestra, + ) -> Option> { + match msg { + FromOrchestra::Communication { msg } => Some(FromOrchestra::Communication { msg }), + FromOrchestra::Signal(OverseerSignal::BlockFinalized( + finalized_hash, + finalized_height, + )) => { + gum::debug!( + target: MALUS, + "😈 Block Finalization Interception! Block: {:?}", finalized_hash, + ); + + //Ensure that the chain is long enough for the target ancestor to exist + if finalized_height <= self.dispute_offset { + return Some(FromOrchestra::Signal(OverseerSignal::BlockFinalized( + finalized_hash, + finalized_height, + ))) + } + + let dispute_offset = self.dispute_offset; + let mut sender = subsystem_sender.clone(); + self.spawner.spawn( + "malus-dispute-finalized-block", + Some("malus"), + Box::pin(async move { + // Query chain for the block hash at the target depth + let (tx, rx) = oneshot::channel(); + sender + .send_message(ChainApiMessage::FinalizedBlockHash( + finalized_height - dispute_offset, + tx, + )) + .await; + let disputable_hash = match rx.await { + Ok(Ok(Some(hash))) => { + gum::debug!( + target: MALUS, + "😈 Time to search {:?}`th ancestor! Block: {:?}", dispute_offset, hash, + ); + hash + }, + _ => { + gum::debug!( + target: MALUS, + "😈 Seems the target is not yet finalized! Nothing to dispute." + ); + return // Early return from the async block + }, + }; + + // Fetch all candidate events for the target ancestor + let events = + request_candidate_events(disputable_hash, &mut sender).await.await; + let events = match events { + Ok(Ok(events)) => events, + Ok(Err(e)) => { + gum::error!( + target: MALUS, + "😈 Failed to fetch candidate events: {:?}", e + ); + return // Early return from the async block + }, + Err(e) => { + gum::error!( + target: MALUS, + "😈 Failed to fetch candidate events: {:?}", e + ); + return // Early return from the async block + }, + }; + + // Extract a token candidate from the events to use for disputing + let event = events.iter().find(|event| { + matches!(event, CandidateEvent::CandidateIncluded(_, _, _, _)) + }); + let candidate = match event { + Some(CandidateEvent::CandidateIncluded(candidate, _, _, _)) => + candidate, + _ => { + gum::error!( + target: MALUS, + "😈 No candidate included event found! Nothing to dispute." + ); + return // Early return from the async block + }, + }; + + // Extract the candidate hash from the candidate + let candidate_hash = candidate.hash(); + + // Fetch the session index for the candidate + let (tx, rx) = oneshot::channel(); + sender + .send_message(RuntimeApiMessage::Request( + disputable_hash, + RuntimeApiRequest::SessionIndexForChild(tx), + )) + .await; + let session_index = match rx.await { + Ok(Ok(session_index)) => session_index, + _ => { + gum::error!( + target: MALUS, + "😈 Failed to fetch session index for candidate." + ); + return // Early return from the async block + }, + }; + gum::info!( + target: MALUS, + "😈 Disputing candidate with hash: {:?} in session {:?}", candidate_hash, session_index, + ); + + // Start dispute + sender.send_unbounded_message( + DisputeCoordinatorMessage::IssueLocalStatement( + session_index, + candidate_hash, + candidate.clone(), + false, // indicates candidate is invalid -> dispute starts + ), + ); + }), + ); + + // Passthrough the finalization signal as usual (using it as hook only) + Some(FromOrchestra::Signal(OverseerSignal::BlockFinalized( + finalized_hash, + finalized_height, + ))) + }, + FromOrchestra::Signal(signal) => Some(FromOrchestra::Signal(signal)), + } + } +} + +//---------------------------------------------------------------------------------- + +#[derive(Debug, clap::Parser)] +#[clap(rename_all = "kebab-case")] +#[allow(missing_docs)] +pub struct DisputeFinalizedCandidatesOptions { + /// relative depth of the disputed block to the finalized block, 0=finalized, 1=parent of + /// finalized etc + #[clap(long, ignore_case = true, default_value_t = 2, value_parser = clap::value_parser!(u32).range(0..=50))] + pub dispute_offset: u32, + + #[clap(flatten)] + pub cli: Cli, +} + +/// DisputeFinalizedCandidates implementation wrapper which implements `OverseerGen` glue. +pub(crate) struct DisputeFinalizedCandidates { + /// relative depth of the disputed block to the finalized block, 0=finalized, 1=parent of + /// finalized etc + pub dispute_offset: u32, +} + +impl OverseerGen for DisputeFinalizedCandidates { + fn generate( + &self, + connector: OverseerConnector, + args: OverseerGenArgs<'_, Spawner, RuntimeClient>, + ) -> Result< + (Overseer, Arc>>, OverseerHandle), + Error, + > + where + RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, + RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + Spawner: 'static + SpawnNamed + Clone + Unpin, + { + gum::info!( + target: MALUS, + "😈 Started Malus node that disputes finalized blocks after they are {:?} finalizations deep.", + &self.dispute_offset, + ); + + let ancestor_disputer = AncestorDisputer { + spawner: SpawnGlue(args.spawner.clone()), + dispute_offset: self.dispute_offset, + }; + + prepared_overseer_builder(args)? + .replace_approval_voting(move |cb| InterceptedSubsystem::new(cb, ancestor_disputer)) + .build_with_connector(connector) + .map_err(|e| e.into()) + } +} diff --git a/polkadot/node/malus/src/variants/mod.rs b/polkadot/node/malus/src/variants/mod.rs index 3789f33ac98..bb4971c145c 100644 --- a/polkadot/node/malus/src/variants/mod.rs +++ b/polkadot/node/malus/src/variants/mod.rs @@ -18,11 +18,13 @@ mod back_garbage_candidate; mod common; +mod dispute_finalized_candidates; mod dispute_valid_candidates; mod suggest_garbage_candidate; pub(crate) use self::{ back_garbage_candidate::{BackGarbageCandidateOptions, BackGarbageCandidates}, + dispute_finalized_candidates::{DisputeFinalizedCandidates, DisputeFinalizedCandidatesOptions}, dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates}, suggest_garbage_candidate::{SuggestGarbageCandidateOptions, SuggestGarbageCandidates}, }; diff --git a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs index cf0ff5f809d..817afb58437 100644 --- a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs @@ -113,7 +113,7 @@ where let (sender, receiver) = std::sync::mpsc::channel(); let mut new_sender = subsystem_sender.clone(); let _candidate = candidate.clone(); - self.spawner.spawn_blocking( + self.spawner.spawn( "malus-get-validation-data", Some("malus"), Box::pin(async move { diff --git a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml new file mode 100644 index 00000000000..69eb0804d8c --- /dev/null +++ b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml @@ -0,0 +1,40 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + max_validators_per_core = 1 + needed_approvals = 1 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "honest" + count = 6 + args = ["-lparachain=debug"] + + [[relaychain.nodes]] + image = "{{MALUS_IMAGE}}" + name = "malus" + command = "malus dispute-finalized-candidates" + args = [ "--alice", "-lparachain=debug,MALUS=trace", "--dispute-offset=3" ] + +[[parachains]] +id = 2000 + + [parachains.collator] + image = "{{COL_IMAGE}}" + name = "collator" + command = "undying-collator" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl new file mode 100644 index 00000000000..62d5a9768f9 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl @@ -0,0 +1,29 @@ +Description: Test if disputes triggered on finalized blocks within scope always end as valid. +Network: ./0007-dispute-freshly-finalized.toml +Creds: config + +# Check authority status and peers. +malus: reports node_roles is 4 +honest: reports node_roles is 4 + +# Ensure parachains are registered. +honest: parachain 2000 is registered within 30 seconds + +# Ensure parachains made progress. +honest: parachain 2000 block height is at least 10 within 200 seconds + +# Ensure that malus is already attempting to dispute +malus: log line contains "😈 Disputing candidate with hash:" within 180 seconds + +# Check if disputes are initiated and concluded. +honest: reports polkadot_parachain_candidate_disputes_total is at least 2 within 100 seconds +honest: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 2 within 100 seconds +honest: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 100 seconds + +# Check lag - approval +honest: reports polkadot_parachain_approval_checking_finality_lag is 0 + +# Check lag - dispute conclusion +honest: reports polkadot_parachain_disputes_finality_lag is 0 + + diff --git a/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml new file mode 100644 index 00000000000..1ea385c3a42 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml @@ -0,0 +1,40 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + max_validators_per_core = 1 + needed_approvals = 1 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "honest" + count = 6 + args = ["-lparachain=debug"] + + [[relaychain.nodes]] + image = "{{MALUS_IMAGE}}" + name = "malus" + command = "malus dispute-finalized-candidates" + args = [ "--alice", "-lparachain=debug,MALUS=trace", "--dispute-offset=14" ] + +[[parachains]] +id = 2000 + + [parachains.collator] + image = "{{COL_IMAGE}}" + name = "collator" + command = "undying-collator" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.zndsl b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.zndsl new file mode 100644 index 00000000000..b30c5801a1d --- /dev/null +++ b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.zndsl @@ -0,0 +1,21 @@ +Description: Test if disputes triggered on finalized blocks out of scope never get to be confirmed and concluded. +Network: ./0008-dispute-old-finalized.toml +Creds: config + +# Check authority status and peers. +malus: reports node_roles is 4 +honest: reports node_roles is 4 + + +# Ensure parachains are registered. +honest: parachain 2000 is registered within 30 seconds + +# Ensure parachains made progress. +honest: parachain 2000 block height is at least 20 within 300 seconds + +# Ensure that malus is already attempting to dispute +malus: log line contains "😈 Disputing candidate with hash:" within 180 seconds + +# Ensure that honest nodes don't participate and conclude any disputes +honest: count of log lines containing "Dispute on candidate concluded" is 0 within 100 seconds + -- GitLab From 0317501758c97c940d3ceec165f22f8b54dee047 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Mon, 27 Nov 2023 11:33:36 +0100 Subject: [PATCH 586/633] Decomissioned PR-Custom-Review (#2503) This PR decomissions [`PR-Custom-Review`](https://github.com/paritytech/pr-custom-review) in replacement for [`Review-bot`](https://github.com/paritytech/review-bot). --- .github/pr-custom-review.yml | 63 -------------------------- .github/workflows/pr-custom-review.yml | 46 ------------------- 2 files changed, 109 deletions(-) delete mode 100644 .github/pr-custom-review.yml delete mode 100644 .github/workflows/pr-custom-review.yml diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml deleted file mode 100644 index ac13d862a4a..00000000000 --- a/.github/pr-custom-review.yml +++ /dev/null @@ -1,63 +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: CI files - check_type: changed_files - condition: - include: ^\.gitlab-ci\.yml|^docker/.*|^\.github/.*|^\.gitlab/.*|^\.config/nextest.toml|^\.cargo/.* - exclude: ^\.gitlab/pipeline/zombienet.* - min_approvals: 2 - teams: - - ci - - release-engineering - - - name: Core developers - check_type: changed_files - 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/.* - min_approvals: 2 - teams: - - core-devs - - # cumulus - - name: Runtime files cumulus - check_type: changed_files - condition: ^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$ - all_distinct: - - min_approvals: 1 - teams: - - locks-review - - min_approvals: 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 - check_type: changed_files - condition: ^bridges/.* - min_approvals: 1 - teams: - - bridges-core - - # substrate - - - name: FRAME coders substrate - check_type: changed_files - condition: - include: ^substrate/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 - -prevent-review-request: - teams: - - core-devs diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml deleted file mode 100644 index 4e0809cbfdc..00000000000 --- a/.github/workflows/pr-custom-review.yml +++ /dev/null @@ -1,46 +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: - merge_group: - -jobs: - pr-custom-review: - runs-on: ubuntu-latest - steps: - - name: Skip merge queue - if: ${{ contains(github.ref, 'gh-readonly-queue') }} - run: exit 0 - - 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@master - with: - checks-reviews-api: http://pcr.parity-prod.parity.io/api/v1/check_reviews -- GitLab From 2610450a18e64079abfe98f0a5b57069bbb61009 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 27 Nov 2023 19:40:27 +0900 Subject: [PATCH 587/633] Build the standard library crates when building the runtimes (#2217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our executor currently only supports the WASM MVP feature set, however nowadays when compiling WASM the Rust compiler has more features enabled by default. We do set the `-C target-cpu=mvp` flag to make sure that *our* code gets compiled in a way that is compatible with our executor, however this doesn't affect Rust's standard library crates (`std`, `core` and `alloc`) which are by default precompiled and still can make use of these extra features. So in this PR we force the compiler to also compile the standard library crates for us to make sure that they also only use the MVP features. I've added the `WASM_BUILD_STD` environment variable which can be used to disable this behavior if set to `0`. Unfortunately this *will* slow down the compile times when building runtimes, but there isn't much that we can do about that. Fixes https://github.com/paritytech/polkadot-sdk/issues/1755 --------- Co-authored-by: Bastian Köcher --- polkadot/parachain/src/lib.rs | 2 - substrate/utils/wasm-builder/README.md | 12 +- substrate/utils/wasm-builder/src/lib.rs | 126 +++--------- .../utils/wasm-builder/src/prerequisites.rs | 192 ++++++++---------- substrate/utils/wasm-builder/src/version.rs | 17 ++ .../utils/wasm-builder/src/wasm_project.rs | 20 ++ 6 files changed, 163 insertions(+), 206 deletions(-) diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs index 913d887e4a8..bd75296bf83 100644 --- a/polkadot/parachain/src/lib.rs +++ b/polkadot/parachain/src/lib.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -#![warn(unused_crate_dependencies)] - //! Defines primitive types for creating or validating a parachain. //! //! When compiled with standard library support, this crate exports a `wasm` diff --git a/substrate/utils/wasm-builder/README.md b/substrate/utils/wasm-builder/README.md index db32f5cbc95..6dfc743816c 100644 --- a/substrate/utils/wasm-builder/README.md +++ b/substrate/utils/wasm-builder/README.md @@ -13,7 +13,7 @@ A project that should be compiled as a Wasm binary needs to: The `build.rs` file needs to contain the following code: -```rust +```rust,no_run fn main() { #[cfg(feature = "std")] { @@ -32,7 +32,7 @@ fn main() { As the final step, you need to add the following to your project: -```rust +```rust,ignore include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); ``` @@ -63,11 +63,17 @@ By using environment variables, you can configure which Wasm binaries are built - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path needs to be absolute. - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. +- `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not required as we walk up from + the target directory until we find a `Cargo.toml`. If the target directory is changed for + the build, this environment variable can be used to point to the actual workspace. +- `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will also be built. This is necessary to make sure + the standard library crates only use the exact WASM feature set that our executor supports. + Enabled by default. - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to prevent network access. Useful in offline environments. Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. Where -`PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will be `NODE_RUNTIME`. +`PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. ## Prerequisites diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index c9011f97be7..cd31a8cba10 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -15,99 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Wasm builder is a utility for building a project as a Wasm binary -//! -//! The Wasm builder is a tool that integrates the process of building the WASM binary of your -//! project into the main `cargo` build process. -//! -//! ## Project setup -//! -//! A project that should be compiled as a Wasm binary needs to: -//! -//! 1. Add a `build.rs` file. -//! 2. Add `wasm-builder` as dependency into `build-dependencies`. -//! -//! The `build.rs` file needs to contain the following code: -//! -//! ```no_run -//! use substrate_wasm_builder::WasmBuilder; -//! -//! fn main() { -//! WasmBuilder::new() -//! // Tell the builder to build the project (crate) this `build.rs` is part of. -//! .with_current_project() -//! // Make sure to export the `heap_base` global, this is required by Substrate -//! .export_heap_base() -//! // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) -//! .import_memory() -//! // Build it. -//! .build() -//! } -//! ``` -//! -//! As the final step, you need to add the following to your project: -//! -//! ```ignore -//! include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -//! ``` -//! -//! This will include the generated Wasm binary as two constants `WASM_BINARY` and -//! `WASM_BINARY_BLOATY`. The former is a compact Wasm binary and the latter is the Wasm binary as -//! being generated by the compiler. Both variables have `Option<&'static [u8]>` as type. -//! -//! ### Feature -//! -//! Wasm builder supports to enable cargo features while building the Wasm binary. By default it -//! will enable all features in the wasm build that are enabled for the native build except the -//! `default` and `std` features. Besides that, wasm builder supports the special `runtime-wasm` -//! feature. This `runtime-wasm` feature will be enabled by the wasm builder when it compiles the -//! Wasm binary. If this feature is not present, it will not be enabled. -//! -//! ## Environment variables -//! -//! By using environment variables, you can configure which Wasm binaries are built and how: -//! -//! - `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be -//! recompiled. If this is the first run and there doesn't exist a Wasm binary, this will set both -//! variables to `None`. -//! - `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are -//! `release` or `debug`. By default the build type is equal to the build type used by the main -//! build. -//! - `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the -//! variable needs to change. As wasm-builder instructs `cargo` to watch for file changes this -//! environment variable should only be required in certain circumstances. -//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm -//! binary. -//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. -//! - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path -//! needs to be absolute. -//! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The -//! format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. -//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not -//! required as we walk up from the target directory until we find a `Cargo.toml`. If the target -//! directory is changed for the build, this environment variable can be used to point to the -//! actual workspace. -//! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to -//! prevent network access. Useful in offline environments. -//! -//! Each project can be skipped individually by using the environment variable -//! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the -//! cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. -//! -//! ## Prerequisites: -//! -//! Wasm builder requires the following prerequisites for building the Wasm binary: -//! -//! - rust nightly + `wasm32-unknown-unknown` toolchain -//! -//! or -//! -//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain -//! -//! If a specific rust is installed with `rustup`, it is important that the wasm target is -//! installed as well. For example if installing the rust from 20.02.2020 using `rustup -//! install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add -//! wasm32-unknown-unknown --toolchain nightly-2020-02-20`. +#![doc = include_str!("../README.md")] use std::{ env, fs, @@ -158,6 +66,9 @@ const FORCE_WASM_BUILD_ENV: &str = "FORCE_WASM_BUILD"; /// Environment variable that hints the workspace we are building. const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT"; +/// Environment variable to set whether we'll build `core`/`std`. +const WASM_BUILD_STD: &str = "WASM_BUILD_STD"; + /// Write to the given `file` if the `content` is different. fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { @@ -282,6 +193,12 @@ impl CargoCommand { self.version } + /// Returns whether this version of the toolchain supports nightly features. + fn supports_nightly_features(&self) -> bool { + self.version.map_or(false, |version| version.is_nightly) || + env::var("RUSTC_BOOTSTRAP").is_ok() + } + /// Check if the supplied cargo command supports our Substrate wasm environment. /// /// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo. @@ -332,3 +249,26 @@ impl std::ops::Deref for CargoCommandVersioned { fn color_output_enabled() -> bool { env::var(crate::WASM_BUILD_NO_COLOR).is_err() } + +/// Fetches a boolean environment variable. Will exit the process if the value is invalid. +fn get_bool_environment_variable(name: &str) -> Option { + let value = env::var_os(name)?; + + // We're comparing `OsString`s here so we can't use a `match`. + if value == "1" { + Some(true) + } else if value == "0" { + Some(false) + } else { + build_helper::warning!( + "the '{}' environment variable has an invalid value; it must be either '1' or '0'", + name + ); + std::process::exit(1); + } +} + +/// Returns whether we need to also compile the standard library when compiling the runtime. +fn build_std_required() -> bool { + crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(true) +} diff --git a/substrate/utils/wasm-builder/src/prerequisites.rs b/substrate/utils/wasm-builder/src/prerequisites.rs index 8e81e6774fa..2cdbdd2798e 100644 --- a/substrate/utils/wasm-builder/src/prerequisites.rs +++ b/substrate/utils/wasm-builder/src/prerequisites.rs @@ -47,14 +47,11 @@ pub(crate) fn check() -> Result { check_wasm_toolchain_installed(cargo_command) } -/// Create the project that will be used to check that the wasm toolchain is installed and to -/// extract the rustc version. -fn create_check_toolchain_project(project_dir: &Path) { - let lib_rs_file = project_dir.join("src/lib.rs"); - let main_rs_file = project_dir.join("src/main.rs"); - let build_rs_file = project_dir.join("build.rs"); - let manifest_path = project_dir.join("Cargo.toml"); +/// Creates a minimal dummy crate at the given path and returns the manifest path. +fn create_minimal_crate(project_dir: &Path) -> std::path::PathBuf { + fs::create_dir_all(project_dir.join("src")).expect("Creating src dir does not fail; qed"); + let manifest_path = project_dir.join("Cargo.toml"); write_file_if_changed( &manifest_path, r#" @@ -62,120 +59,99 @@ fn create_check_toolchain_project(project_dir: &Path) { name = "wasm-test" version = "1.0.0" edition = "2021" - build = "build.rs" - - [lib] - name = "wasm_test" - crate-type = ["cdylib"] [workspace] "#, ); - write_file_if_changed(lib_rs_file, "pub fn test() {}"); - - // We want to know the rustc version of the rustc that is being used by our cargo command. - // The cargo command is determined by some *very* complex algorithm to find the cargo command - // that supports nightly. - // The best solution would be if there is a `cargo rustc --version` command, which sadly - // doesn't exists. So, the only available way of getting the rustc version is to build a project - // and capture the rustc version in this build process. This `build.rs` is exactly doing this. - // It gets the rustc version by calling `rustc --version` and exposing it in the `RUSTC_VERSION` - // environment variable. - write_file_if_changed( - build_rs_file, - r#" - fn main() { - let rustc_cmd = std::env::var("RUSTC").ok().unwrap_or_else(|| "rustc".into()); - - let rustc_version = std::process::Command::new(rustc_cmd) - .arg("--version") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()); - - println!( - "cargo:rustc-env=RUSTC_VERSION={}", - rustc_version.unwrap_or_else(|| "unknown rustc version".into()), - ); - } - "#, - ); - // Just prints the `RURSTC_VERSION` environment variable that is being created by the - // `build.rs` script. - write_file_if_changed( - main_rs_file, - r#" - fn main() { - println!("{}", env!("RUSTC_VERSION")); - } - "#, - ); + + write_file_if_changed(project_dir.join("src/main.rs"), "fn main() {}"); + manifest_path } fn check_wasm_toolchain_installed( cargo_command: CargoCommand, ) -> Result { let temp = tempdir().expect("Creating temp dir does not fail; qed"); - fs::create_dir_all(temp.path().join("src")).expect("Creating src dir does not fail; qed"); - create_check_toolchain_project(temp.path()); - - let err_msg = print_error_message("Rust WASM toolchain not installed, please install it!"); - let manifest_path = temp.path().join("Cargo.toml").display().to_string(); - - let mut build_cmd = cargo_command.command(); - // Chdir to temp to avoid including project's .cargo/config.toml - // by accident - it can happen in some CI environments. - build_cmd.current_dir(&temp); - build_cmd.args(&[ - "build", - "--target=wasm32-unknown-unknown", - "--manifest-path", - &manifest_path, - ]); + let manifest_path = create_minimal_crate(temp.path()).display().to_string(); + + let prepare_command = |subcommand| { + let mut cmd = cargo_command.command(); + // Chdir to temp to avoid including project's .cargo/config.toml + // by accident - it can happen in some CI environments. + cmd.current_dir(&temp); + cmd.args(&[ + subcommand, + "--target=wasm32-unknown-unknown", + "--manifest-path", + &manifest_path, + ]); + + if super::color_output_enabled() { + cmd.arg("--color=always"); + } - if super::color_output_enabled() { - build_cmd.arg("--color=always"); + // manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock + let target_dir = temp.path().join("target").display().to_string(); + cmd.env("CARGO_TARGET_DIR", &target_dir); + + // Make sure the host's flags aren't used here, e.g. if an alternative linker is specified + // in the RUSTFLAGS then the check we do here will break unless we clear these. + cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); + cmd.env_remove("RUSTFLAGS"); + cmd + }; + + let err_msg = + print_error_message("Rust WASM toolchain is not properly installed; please install it!"); + let build_result = prepare_command("build").output().map_err(|_| err_msg.clone())?; + if !build_result.status.success() { + return match String::from_utf8(build_result.stderr) { + Ok(ref err) if err.contains("the `wasm32-unknown-unknown` target may not be installed") => + Err(print_error_message("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ + You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.")), + + // Apparently this can happen when we're running on a non Tier 1 platform. + Ok(ref err) if err.contains("linker `rust-lld` not found") => + Err(print_error_message("Cannot compile the WASM runtime: `rust-lld` not found!")), + + Ok(ref err) => Err(format!( + "{}\n\n{}\n{}\n{}{}\n", + err_msg, + Color::Yellow.bold().paint("Further error information:"), + Color::Yellow.bold().paint("-".repeat(60)), + err, + Color::Yellow.bold().paint("-".repeat(60)), + )), + + Err(_) => Err(err_msg), + }; } - let mut run_cmd = cargo_command.command(); - // Chdir to temp to avoid including project's .cargo/config.toml - // by accident - it can happen in some CI environments. - run_cmd.current_dir(&temp); - run_cmd.args(&["run", "--manifest-path", &manifest_path]); - - // manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock - let target_dir = temp.path().join("target").display().to_string(); - build_cmd.env("CARGO_TARGET_DIR", &target_dir); - run_cmd.env("CARGO_TARGET_DIR", &target_dir); - - // Make sure the host's flags aren't used here, e.g. if an alternative linker is specified - // in the RUSTFLAGS then the check we do here will break unless we clear these. - build_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); - run_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); - build_cmd.env_remove("RUSTFLAGS"); - run_cmd.env_remove("RUSTFLAGS"); - - build_cmd.output().map_err(|_| err_msg.clone()).and_then(|s| { - if s.status.success() { - let version = run_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()); - Ok(CargoCommandVersioned::new( - cargo_command, - version.unwrap_or_else(|| "unknown rustc version".into()), - )) - } else { - match String::from_utf8(s.stderr) { - Ok(ref err) if err.contains("linker `rust-lld` not found") => - Err(print_error_message("`rust-lld` not found, please install it!")), - Ok(ref err) => Err(format!( - "{}\n\n{}\n{}\n{}{}\n", - err_msg, - Color::Yellow.bold().paint("Further error information:"), - Color::Yellow.bold().paint("-".repeat(60)), - err, - Color::Yellow.bold().paint("-".repeat(60)), - )), - Err(_) => Err(err_msg), + let mut run_cmd = prepare_command("rustc"); + run_cmd.args(&["-q", "--", "--version"]); + + let version = run_cmd + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or_else(|| "unknown rustc version".into()); + + if crate::build_std_required() { + let mut sysroot_cmd = prepare_command("rustc"); + sysroot_cmd.args(&["-q", "--", "--print", "sysroot"]); + if let Some(sysroot) = + sysroot_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()) + { + let src_path = + Path::new(sysroot.trim()).join("lib").join("rustlib").join("src").join("rust"); + if !src_path.exists() { + return Err(print_error_message( + "Cannot compile the WASM runtime: no standard library sources found!\n\ + You can install them with `rustup component add rust-src` if you're using `rustup`.", + )) } } - }) + } + + Ok(CargoCommandVersioned::new(cargo_command, version)) } diff --git a/substrate/utils/wasm-builder/src/version.rs b/substrate/utils/wasm-builder/src/version.rs index e4f7d98be61..3a0a306d737 100644 --- a/substrate/utils/wasm-builder/src/version.rs +++ b/substrate/utils/wasm-builder/src/version.rs @@ -212,4 +212,21 @@ mod tests { version_1_69_0, ); } + + #[test] + fn parse_rustc_version() { + let version = Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap(); + assert_eq!( + version, + Version { + major: 1, + minor: 73, + patch: 0, + is_nightly: false, + year: Some(2023), + month: Some(10), + day: Some(03), + } + ); + } } diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 2e6f671c45e..5bf44c2c9b2 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -750,6 +750,25 @@ fn build_bloaty_blob( build_cmd.arg("--offline"); } + // Our executor currently only supports the WASM MVP feature set, however nowadays + // when compiling WASM the Rust compiler has more features enabled by default. + // + // We do set the `-C target-cpu=mvp` flag to make sure that *our* code gets compiled + // in a way that is compatible with our executor, however this doesn't affect Rust's + // standard library crates (`std`, `core` and `alloc`) which are by default precompiled + // and still can make use of these extra features. + // + // So here we force the compiler to also compile the standard library crates for us + // to make sure that they also only use the MVP features. + if crate::build_std_required() { + // Unfortunately this is still a nightly-only flag, but FWIW it is pretty widely used + // so it's unlikely to break without a replacement. + build_cmd.arg("-Z").arg("build-std"); + if !cargo_cmd.supports_nightly_features() { + build_cmd.env("RUSTC_BOOTSTRAP", "1"); + } + } + println!("{}", colorize_info_message("Information that should be included in a bug report.")); println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); @@ -952,6 +971,7 @@ fn generate_rerun_if_changed_instructions( println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_RUSTFLAGS_ENV); println!("cargo:rerun-if-env-changed={}", crate::WASM_TARGET_DIRECTORY); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TOOLCHAIN); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_STD); } /// Track files and paths related to the given package to rerun `build.rs` on any relevant change. -- GitLab From 4298bc608fa8e5d8b8fb1ca0c1028613d82bc99b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 27 Nov 2023 14:22:13 +0200 Subject: [PATCH 588/633] asset-hub-westend-integration-tests: add more asset transfers tests (#2488) Just adds more tests. --- Cargo.lock | 2 + .../assets/asset-hub-rococo/src/lib.rs | 2 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../bridges/bridge-hub-westend/src/lib.rs | 2 +- .../parachains/testing/penpal/Cargo.toml | 1 + .../parachains/testing/penpal/src/lib.rs | 6 +- .../emulated/common/src/impls.rs | 12 +- .../src/tests/reserve_transfer.rs | 43 +-- .../assets/asset-hub-rococo/src/tests/swap.rs | 6 - .../tests/assets/asset-hub-westend/Cargo.toml | 1 + .../tests/assets/asset-hub-westend/src/lib.rs | 32 +- .../src/tests/reserve_transfer.rs | 337 ++++++++++++++++-- .../asset-hub-westend/src/tests/send.rs | 12 +- .../asset-hub-westend/src/tests/swap.rs | 24 +- .../asset-hub-westend/src/tests/teleport.rs | 45 +-- 16 files changed, 402 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a3f8e05fbc..f99b579bfe9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1028,6 +1028,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "polkadot-runtime-common", "sp-runtime", "staging-xcm", @@ -11746,6 +11747,7 @@ dependencies = [ "serde_json", "sp-core", "sp-runtime", + "westend-emulated-chain", ] [[package]] diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 1ed22b3cc4f..877edceae32 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -52,6 +52,6 @@ decl_test_parachains! { // AssetHubRococo implementation impl_accounts_helpers_for_parachain!(AssetHubRococo); -impl_assert_events_helpers_for_parachain!(AssetHubRococo, false); +impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 4dcdb613ac2..1c017c63c6f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -52,6 +52,6 @@ decl_test_parachains! { // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); -impl_assert_events_helpers_for_parachain!(AssetHubWestend, false); +impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index ea0c9513abc..8e5b29e6561 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); -impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index 4a130ac1f27..a774f31b0fb 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); -impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index c55b10d7180..5886158c263 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -23,3 +23,4 @@ cumulus-primitives-core = { path = "../../../../../../../primitives/core", defau emulated-integration-tests-common = { path = "../../../../common", default-features = false } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } rococo-emulated-chain = { path = "../../../relays/rococo" } +westend-emulated-chain = { path = "../../../relays/westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index f9a422bfcba..c76120adb79 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -25,6 +25,7 @@ use emulated_integration_tests_common::{ impl_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; +use westend_emulated_chain::Westend; // Penpal Parachain declaration decl_test_parachains! { @@ -67,5 +68,6 @@ decl_test_parachains! { // Penpal implementation impl_accounts_helpers_for_parachain!(PenpalA); impl_assets_helpers_for_parachain!(PenpalA, Rococo); -impl_assert_events_helpers_for_parachain!(PenpalA, true); -impl_assert_events_helpers_for_parachain!(PenpalB, true); +impl_assets_helpers_for_parachain!(PenpalB, Westend); +impl_assert_events_helpers_for_parachain!(PenpalA); +impl_assert_events_helpers_for_parachain!(PenpalB); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 8c94df6d888..768784ac067 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -418,7 +418,7 @@ macro_rules! impl_accounts_helpers_for_parachain { #[macro_export] macro_rules! impl_assert_events_helpers_for_parachain { - ( $chain:ident, $ignore_weight:expr ) => { + ( $chain:ident ) => { $crate::impls::paste::paste! { type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; @@ -431,7 +431,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { - weight: $ignore_weight || $crate::impls::weight_within_threshold( + weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -453,7 +453,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { - weight: $ignore_weight || $crate::impls::weight_within_threshold( + weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -509,7 +509,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }) => { - weight: $ignore_weight || $crate::impls::weight_within_threshold( + weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -529,7 +529,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: false, weight_used: weight, .. }) => { - weight: $ignore_weight || $crate::impls::weight_within_threshold( + weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -560,7 +560,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { vec![ [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } ) => { - weight: $ignore_weight || $crate::impls::weight_within_threshold( + weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index d0e9b72176b..18483762ae1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -40,19 +40,6 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { ); } -fn relay_to_para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -78,7 +65,7 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ); } -fn system_para_to_para_receiver_assertions(_: Test) { +fn para_receiver_assertions(_: Test) { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( PenpalA, @@ -297,7 +284,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(relay_to_para_receiver_assertions); + test.set_assertion::(para_receiver_assertions); test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); test.assert(); @@ -314,6 +301,10 @@ fn reserve_transfer_native_asset_from_relay_to_para() { assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } /// Reserve Transfers of native asset from System Parachain to Parachain should work @@ -337,7 +328,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_assertion::(para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); @@ -354,6 +345,10 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } /// Reserve Transfers of native asset from Parachain to System Parachain should work @@ -400,6 +395,10 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } /// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should @@ -420,7 +419,7 @@ fn reserve_transfer_assets_from_system_para_to_para() { ASSET_MIN_BALANCE, false, PenpalASender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), + None, 0, ); @@ -485,6 +484,10 @@ fn reserve_transfer_assets_from_system_para_to_para() { assert!(sender_balance_after < sender_balance_before); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); let sender_assets_after = AssetHubRococo::execute_with(|| { type Assets = ::Assets; @@ -495,8 +498,8 @@ fn reserve_transfer_assets_from_system_para_to_para() { >::balance(ASSET_ID, &PenpalAReceiver::get()) }); - // Sender's balance is reduced + // Sender's balance is reduced by exact amount assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's balance is increased - assert!(receiver_assets_after > receiver_assets_before); + // Receiver's balance is increased by exact amount + assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index e08af50c14e..9e691bf02f1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -44,12 +44,6 @@ fn swap_locally_on_chain_using_local_assets() { 100_000_000_000_000, )); - assert_ok!(::Balances::force_set_balance( - ::RuntimeOrigin::root(), - AssetHubRococoSender::get().into(), - 100_000_000_000_000, - )); - assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 7080abc0a44..4c7537bfd53 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -38,4 +38,5 @@ asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } emulated-integration-tests-common = { path = "../../../common", default-features = false} +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } westend-system-emulated-network ={ path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 83a867e6ae3..e2c03d2f8f0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -47,11 +47,12 @@ pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet, westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, - AssetHubWestendParaSender as AssetHubWestendSender, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, PenpalBPara as PenpalB, + PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; @@ -62,18 +63,20 @@ pub const ASSET_MIN_BALANCE: u128 = 1000; pub const ASSETS_PALLET_ID: u8 = 50; pub type RelayToSystemParaTest = Test; +pub type RelayToParaTest = Test; pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; +pub type SystemParaToParaTest = Test; +pub type ParaToSystemParaTest = Test; /// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests -pub fn relay_test_args(amount: Balance) -> TestArgs { +pub fn relay_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, +) -> TestArgs { TestArgs { - dest: Westend::child_location_of(AssetHubWestend::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubWestendReceiver::get().into(), - } - .into(), + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), amount, assets: (Here, amount).into(), asset_id: None, @@ -82,13 +85,14 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to be used for the System Parachain across integration tests -pub fn system_para_test_args( +/// Returns a `TestArgs` instance to be used by parachains across integration tests +pub fn para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, amount: Balance, assets: MultiAssets, asset_id: Option, + fee_asset_item: u32, ) -> TestArgs { TestArgs { dest, @@ -96,7 +100,7 @@ pub fn system_para_test_args( amount, assets, asset_id, - fee_asset_item: 0, + fee_asset_item, weight_limit: WeightLimit::Unlimited, } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 5b2c648b7b0..1a69a4f3f71 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -14,7 +14,31 @@ // limitations under the License. use crate::*; -use asset_hub_westend_runtime::xcm_config::XcmConfig; +use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; +use penpal_runtime::xcm_config::XcmConfig as PenpalWestendXcmConfig; +use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; + +fn relay_to_para_sender_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + + assert_expected_events!( + Westend, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == Westend::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -42,10 +66,54 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { } fn para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + PenpalB::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + + assert_expected_events!( + PenpalB, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + assert_expected_events!( - PenpalA, + AssetHubWestend, vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_penpal_on_ahw.clone().into(), + amount: *amount == t.args.amount, + }, RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } @@ -54,7 +122,7 @@ fn para_receiver_assertions(_: Test) { ); } -fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -80,6 +148,31 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } +fn system_para_to_para_assets_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> 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 system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -91,6 +184,17 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } +fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> 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, + ) +} + /// 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() { @@ -159,19 +263,62 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } +/// Reserve Transfers of native asset from Relay to Parachain should work +#[test] +fn reserve_transfer_native_asset_from_relay_to_para() { + // Init values for Relay + let destination = Westend::child_location_of(PenpalB::para_id()); + let beneficiary_id = PenpalBReceiver::get(); + let amount_to_send: Balance = WESTEND_ED * 1000; + + let test_args = TestContext { + sender: WestendSender::get(), + receiver: PenpalBReceiver::get(), + args: relay_test_args(destination, beneficiary_id, amount_to_send), + }; + + let mut test = RelayToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::(relay_to_para_sender_assertions); + test.set_assertion::(para_receiver_assertions); + test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); + test.assert(); + + let delivery_fees = Westend::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + 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 - delivery_fees, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); +} + /// 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 = AssetHubWestend::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); + let destination = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let beneficiary_id = PenpalBReceiver::get(); 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: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + receiver: PenpalBReceiver::get(), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToParaTest::new(test_args); @@ -180,7 +327,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); @@ -188,53 +335,171 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( - test.args.assets.clone(), - 0, - test.args.weight_limit, - test.args.beneficiary, - test.args.dest, - ) + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } -/// Reserve Transfers of a local asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from Parachain to System 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 +fn reserve_transfer_native_asset_from_para_to_system_para() { + // Init values for Penpal Parachain + let destination = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let beneficiary_id = AssetHubWestendReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: PenpalBSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), + }; + + let mut test = ParaToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + let penpal_location_as_seen_by_ahw = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahw = + AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahw); + + // fund the Penpal's SA on AHW with the native tokens held in reserve + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount_to_send * 2)]); + + test.set_assertion::(para_to_system_para_sender_assertions); + test.set_assertion::(para_to_system_para_receiver_assertions); + test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + let delivery_fees = PenpalB::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); +} + +/// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should +/// work +#[test] +fn reserve_transfer_assets_from_system_para_to_para() { + // Force create asset on AssetHubWestend and PenpalB from Relay Chain AssetHubWestend::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, true, AssetHubWestendSender::get(), Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, + ASSET_MIN_BALANCE * 1_000_000, + ); + PenpalB::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + false, + PenpalBSender::get(), + None, + 0, ); // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::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 { + let destination = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let beneficiary_id = PenpalBReceiver::get(); + let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), asset_amount_to_send) + .into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + let para_test_args = TestContext { sender: AssetHubWestendSender::get(), - receiver: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + receiver: PenpalBReceiver::get(), + args: para_test_args( + destination, + beneficiary_id, + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), }; - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + let mut test = SystemParaToParaTest::new(para_test_args); + + // Create SA-of-Penpal-on-AHW with ED. + let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), WESTEND_ED)]); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + let sender_assets_before = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubWestendSender::get()) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalBReceiver::get()) + }); + + test.set_assertion::(system_para_to_para_assets_sender_assertions); + test.set_assertion::(system_para_to_para_assets_receiver_assertions); + test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert!(sender_balance_after < sender_balance_before); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); + + let sender_assets_after = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubWestendSender::get()) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalBReceiver::get()) + }); - 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(); + // Sender's balance is reduced by exact amount + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // Receiver's balance is increased by exact amount + assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index bda9a3e69c4..4b98eeb0ed3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -33,7 +33,7 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { #[test] fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalA::para_id()), + AssetHubWestend::sibling_location_of(PenpalB::para_id()), ); // Force create and mint assets for Parachain's sovereign account @@ -60,8 +60,8 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let native_asset = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into(); + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalB::sibling_location_of(AssetHubWestend::para_id()).into(); let xcm = xcm_transact_paid_execution( call, origin_kind, @@ -69,14 +69,14 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { para_sovereign_account.clone(), ); - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + PenpalB::execute_with(|| { + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), bx!(xcm), )); - PenpalA::assert_xcm_pallet_sent(); + PenpalB::assert_xcm_pallet_sent(); }); AssetHubWestend::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index a8e19f9ef4b..aca60f68802 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -114,7 +114,7 @@ fn swap_locally_on_chain_using_foreign_assets() { let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation { parents: 1, interior: X3( - Parachain(PenpalA::para_id().into()), + Parachain(PenpalB::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), @@ -125,18 +125,18 @@ fn swap_locally_on_chain_using_foreign_assets() { .into(); let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }; + MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) }; // 1. Create asset on penpal: - PenpalA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalASender::get()), + PenpalB::execute_with(|| { + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(PenpalBSender::get()), ASSET_ID.into(), - PenpalASender::get().into(), + PenpalBSender::get().into(), 1000, )); - assert!(::Assets::asset_exists(ASSET_ID)); + assert!(::Assets::asset_exists(ASSET_ID)); }); // 2. Create foreign asset on asset_hub_westend: @@ -190,18 +190,18 @@ fn swap_locally_on_chain_using_foreign_assets() { ])); // Send XCM message from penpal => asset_hub_westend - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + let sudo_penpal_origin = ::RuntimeOrigin::root(); + PenpalB::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!( - PenpalA, + PenpalB, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, ] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index d618cd2fe04..2c43bb9d801 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -157,10 +157,12 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { fn limited_teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = WESTEND_ED * 1000; + let dest = Westend::child_location_of(AssetHubWestend::para_id()); + let beneficiary = AssetHubWestendReceiver::get(); let test_args = TestContext { sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(amount_to_send), + receiver: beneficiary.clone(), + args: relay_test_args(dest, beneficiary, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -204,7 +206,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubWestendSender::get(), receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -245,7 +247,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubWestendSender::get(), receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -278,10 +280,12 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { fn teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = WESTEND_ED * 1000; + let dest = Westend::child_location_of(AssetHubWestend::para_id()); + let beneficiary = AssetHubWestendReceiver::get(); let test_args = TestContext { sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(amount_to_send), + receiver: beneficiary.clone(), + args: relay_test_args(dest, beneficiary, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -325,7 +329,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubWestendSender::get(), receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -366,7 +370,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubWestendSender::get(), receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -394,16 +398,15 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { 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_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) -// ); -// } +#[test] +fn teleport_to_other_system_parachains_works() { + let amount = ASSET_HUB_WESTEND_ED * 100; + let native_asset: MultiAssets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + AssetHubWestend, // Origin + AssetHubWestendXcmConfig, // XCM Configuration + vec![BridgeHubWestend], // Destinations + (native_asset, amount) + ); +} -- GitLab From fd1ed403c95e1802c2c1bbb5cc724bb645ff0d8b Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Mon, 27 Nov 2023 17:50:38 +0400 Subject: [PATCH 589/633] Remove the timestamp handler (#2506) --- .gitlab-ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7e54961fa9..aada30f1dda 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -69,7 +69,6 @@ default: .common-before-script: before_script: - !reference [.job-switcher, before_script] - - !reference [.timestamp, before_script] - !reference [.pipeline-stopper-vars, script] .job-switcher: @@ -211,10 +210,6 @@ include: - .gitlab/pipeline/publish.yml # zombienet jobs - .gitlab/pipeline/zombienet.yml - # timestamp handler - - project: parity/infrastructure/ci_cd/shared - ref: v0.2 - file: /common/timestamp.yml # ci image - project: parity/infrastructure/ci_cd/shared ref: main -- GitLab From 838a534da874cf6071fba1df07643c6c5b033ae0 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 27 Nov 2023 21:42:04 +0700 Subject: [PATCH 590/633] Staking: `chill_other` takes stash instead of controller (#2501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `chill_other` call is the only staking call that explicitly requires `controller` in its signature. This PR changes the controller arg to be the stash instead, with `StakingLedger` then fetching the controller from storage. This is not a breaking change per se - the call types do not change, but is noteworthy as UIs will now want to pass the stash account into `chill_other` calls, & metadata will reflect this. Note: This is very low impact. `chill_other` has [hardly ever been used](https://polkadot.subscan.io/extrinsic?address=&module=staking&call=chill_other&result=all&signedChecked=signed%20only&startDate=&endDate=&startBlock=&timeType=date&version=9431&endBlock=) on Polkadot - notwithstanding the one called 11 days ago at block 18177457 that was a part of test I did, the last call was made 493 days ago. Only 2 calls have ever been successful. Addresses controller deprecation #2500 --------- Co-authored-by: command-bot <> Co-authored-by: Gonçalo Pestana --- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 13 +- substrate/frame/staking/src/weights.rs | 382 ++++++++++---------- 3 files changed, 203 insertions(+), 194 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 6f60c4909f4..c0c6a838aa5 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -873,7 +873,7 @@ benchmarks! { )?; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), controller) + }: _(RawOrigin::Signed(caller), stash.clone()) verify { assert!(!T::VoterList::contains(&stash)); } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1f79ef63a47..ce80f22c2bb 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1327,7 +1327,7 @@ pub mod pallet { // (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.") + .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.") .ok_or(Error::::NotController)?; if controller == stash { @@ -1764,11 +1764,16 @@ pub mod pallet { /// who do not satisfy these requirements. #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::chill_other())] - pub fn chill_other(origin: OriginFor, controller: T::AccountId) -> DispatchResult { + pub fn chill_other(origin: OriginFor, stash: T::AccountId) -> DispatchResult { // Anyone can call this function. let caller = ensure_signed(origin)?; - let ledger = Self::ledger(Controller(controller.clone()))?; - let stash = ledger.stash; + let ledger = Self::ledger(Stash(stash.clone()))?; + let controller = ledger + .controller() + .defensive_proof( + "Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.", + ) + .ok_or(Error::::NotController)?; // In order for one user to chill another user, the following conditions must be met: // diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index ad9ca75a032..ae00509eaa8 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 43_427_000 picoseconds. - Weight::from_parts(45_221_000, 4764) + // Minimum execution time: 42_895_000 picoseconds. + Weight::from_parts(44_924_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -119,8 +119,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_100_000 picoseconds. - Weight::from_parts(90_599_000, 8877) + // Minimum execution time: 87_734_000 picoseconds. + Weight::from_parts(90_762_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_488_000 picoseconds. - Weight::from_parts(94_126_000, 8877) + // Minimum execution time: 90_914_000 picoseconds. + Weight::from_parts(94_156_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -166,10 +166,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 42_713_000 picoseconds. - Weight::from_parts(44_530_499, 4764) - // Standard Error: 1_067 - .saturating_add(Weight::from_parts(51_411, 0).saturating_mul(s.into())) + // Minimum execution time: 43_141_000 picoseconds. + Weight::from_parts(45_081_969, 4764) + // Standard Error: 1_010 + .saturating_add(Weight::from_parts(39_539, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -206,10 +206,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 88_700_000 picoseconds. - Weight::from_parts(98_329_624, 6248) - // Standard Error: 4_477 - .saturating_add(Weight::from_parts(1_347_380, 0).saturating_mul(s.into())) + // Minimum execution time: 87_743_000 picoseconds. + Weight::from_parts(96_983_484, 6248) + // Standard Error: 4_271 + .saturating_add(Weight::from_parts(1_382_993, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -241,8 +241,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_877_000 picoseconds. - Weight::from_parts(53_503_000, 4556) + // Minimum execution time: 51_888_000 picoseconds. + Weight::from_parts(54_353_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -255,10 +255,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_604_000 picoseconds. - Weight::from_parts(31_726_296, 4556) - // Standard Error: 6_350 - .saturating_add(Weight::from_parts(6_416_846, 0).saturating_mul(k.into())) + // Minimum execution time: 28_944_000 picoseconds. + Weight::from_parts(31_116_533, 4556) + // Standard Error: 11_848 + .saturating_add(Weight::from_parts(6_422_601, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -291,10 +291,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_276_000 picoseconds. - Weight::from_parts(62_615_844, 6248) - // Standard Error: 14_914 - .saturating_add(Weight::from_parts(4_097_019, 0).saturating_mul(n.into())) + // Minimum execution time: 63_921_000 picoseconds. + Weight::from_parts(62_662_863, 6248) + // Standard Error: 15_071 + .saturating_add(Weight::from_parts(3_950_084, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -318,8 +318,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 55_064_000 picoseconds. - Weight::from_parts(56_566_000, 6248) + // Minimum execution time: 54_605_000 picoseconds. + Weight::from_parts(56_406_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -333,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_626_000 picoseconds. - Weight::from_parts(17_519_000, 4556) + // Minimum execution time: 16_826_000 picoseconds. + Weight::from_parts(17_326_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -348,8 +348,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_545_000 picoseconds. - Weight::from_parts(21_395_000, 4556) + // Minimum execution time: 20_831_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -361,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_179_000 picoseconds. - Weight::from_parts(20_728_000, 4556) + // Minimum execution time: 20_190_000 picoseconds. + Weight::from_parts(20_993_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -372,8 +372,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_594_000 picoseconds. - Weight::from_parts(2_777_000, 0) + // Minimum execution time: 2_603_000 picoseconds. + Weight::from_parts(2_747_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -382,8 +382,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_302_000 picoseconds. - Weight::from_parts(8_741_000, 0) + // Minimum execution time: 8_070_000 picoseconds. + Weight::from_parts(8_745_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -392,8 +392,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_504_000 picoseconds. - Weight::from_parts(8_774_000, 0) + // Minimum execution time: 7_999_000 picoseconds. + Weight::from_parts(8_624_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -402,8 +402,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_474_000 picoseconds. - Weight::from_parts(8_740_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_467_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -413,10 +413,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_732_000 picoseconds. - Weight::from_parts(3_360_048, 0) - // Standard Error: 34 - .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(v.into())) + // Minimum execution time: 2_731_000 picoseconds. + Weight::from_parts(3_298_421, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_075, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) @@ -452,10 +452,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_495_000 picoseconds. - Weight::from_parts(95_710_388, 6248) - // Standard Error: 5_849 - .saturating_add(Weight::from_parts(1_339_335, 0).saturating_mul(s.into())) + // Minimum execution time: 86_305_000 picoseconds. + Weight::from_parts(94_494_401, 6248) + // Standard Error: 3_602 + .saturating_add(Weight::from_parts(1_339_477, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -468,10 +468,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 98_255_000 picoseconds. - Weight::from_parts(892_807_378, 70137) - // Standard Error: 57_735 - .saturating_add(Weight::from_parts(4_876_449, 0).saturating_mul(s.into())) + // Minimum execution time: 100_007_000 picoseconds. + Weight::from_parts(894_033_025, 70137) + // Standard Error: 57_584 + .saturating_add(Weight::from_parts(4_870_504, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -507,11 +507,11 @@ impl WeightInfo for SubstrateWeight { fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 144_258_000 picoseconds. - Weight::from_parts(175_256_796, 30944) - // Standard Error: 24_339 - .saturating_add(Weight::from_parts(46_011_700, 0).saturating_mul(n.into())) + // Estimated: `30944 + n * (3774 ±0)` + // Minimum execution time: 142_575_000 picoseconds. + Weight::from_parts(196_320_577, 30944) + // Standard Error: 29_330 + .saturating_add(Weight::from_parts(45_325_062, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -535,10 +535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 83_532_000 picoseconds. - Weight::from_parts(86_757_943, 8877) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(57_566, 0).saturating_mul(l.into())) + // Minimum execution time: 81_113_000 picoseconds. + Weight::from_parts(84_470_927, 8877) + // Standard Error: 5_588 + .saturating_add(Weight::from_parts(97_606, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -573,10 +573,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 96_776_000 picoseconds. - Weight::from_parts(100_950_027, 6248) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(1_432_091, 0).saturating_mul(s.into())) + // Minimum execution time: 94_810_000 picoseconds. + Weight::from_parts(99_292_156, 6248) + // Standard Error: 3_677 + .saturating_add(Weight::from_parts(1_345_598, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -621,13 +621,13 @@ impl WeightInfo for SubstrateWeight { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 577_699_000 picoseconds. - Weight::from_parts(582_827_000, 512390) - // Standard Error: 2_000_851 - .saturating_add(Weight::from_parts(67_316_744, 0).saturating_mul(v.into())) - // Standard Error: 199_373 - .saturating_add(Weight::from_parts(18_503_387, 0).saturating_mul(n.into())) + // Estimated: `512390 + n * (3566 ±4) + v * (3566 ±40)` + // Minimum execution time: 583_230_000 picoseconds. + Weight::from_parts(585_794_000, 512390) + // Standard Error: 1_984_644 + .saturating_add(Weight::from_parts(65_914_551, 0).saturating_mul(v.into())) + // Standard Error: 197_758 + .saturating_add(Weight::from_parts(18_105_424, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -658,12 +658,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_048_778_000 picoseconds. - Weight::from_parts(34_397_777_000, 512390) - // Standard Error: 346_115 - .saturating_add(Weight::from_parts(3_704_941, 0).saturating_mul(v.into())) - // Standard Error: 346_115 - .saturating_add(Weight::from_parts(4_064_819, 0).saturating_mul(n.into())) + // Minimum execution time: 33_312_958_000 picoseconds. + Weight::from_parts(4_949_866_209, 512390) + // Standard Error: 402_931 + .saturating_add(Weight::from_parts(16_448_367, 0).saturating_mul(v.into())) + // Standard Error: 402_931 + .saturating_add(Weight::from_parts(25_361_503, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -680,10 +680,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_473_149_000 picoseconds. - Weight::from_parts(84_721_859, 3510) - // Standard Error: 8_690 - .saturating_add(Weight::from_parts(4_870_439, 0).saturating_mul(v.into())) + // Minimum execution time: 2_474_646_000 picoseconds. + Weight::from_parts(2_512_113_000, 3510) + // Standard Error: 33_996 + .saturating_add(Weight::from_parts(1_992_173, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -704,8 +704,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_312_000 picoseconds. - Weight::from_parts(5_897_000, 0) + // Minimum execution time: 5_466_000 picoseconds. + Weight::from_parts(5_861_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -724,10 +724,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_676_000 picoseconds. - Weight::from_parts(4_913_000, 0) + // Minimum execution time: 4_780_000 picoseconds. + Weight::from_parts(4_998_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -750,11 +752,11 @@ impl WeightInfo for SubstrateWeight { /// 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: `1773` + // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 67_286_000 picoseconds. - Weight::from_parts(69_081_000, 6248) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Minimum execution time: 71_261_000 picoseconds. + Weight::from_parts(72_778_000, 6248) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -765,8 +767,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_749_000 picoseconds. - Weight::from_parts(13_275_000, 3510) + // Minimum execution time: 12_497_000 picoseconds. + Weight::from_parts(13_049_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -776,8 +778,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_155_000 picoseconds. - Weight::from_parts(3_319_000, 0) + // Minimum execution time: 3_044_000 picoseconds. + Weight::from_parts(3_278_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -798,8 +800,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 43_427_000 picoseconds. - Weight::from_parts(45_221_000, 4764) + // Minimum execution time: 42_895_000 picoseconds. + Weight::from_parts(44_924_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -819,8 +821,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_100_000 picoseconds. - Weight::from_parts(90_599_000, 8877) + // Minimum execution time: 87_734_000 picoseconds. + Weight::from_parts(90_762_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -846,8 +848,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_488_000 picoseconds. - Weight::from_parts(94_126_000, 8877) + // Minimum execution time: 90_914_000 picoseconds. + Weight::from_parts(94_156_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -866,10 +868,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 42_713_000 picoseconds. - Weight::from_parts(44_530_499, 4764) - // Standard Error: 1_067 - .saturating_add(Weight::from_parts(51_411, 0).saturating_mul(s.into())) + // Minimum execution time: 43_141_000 picoseconds. + Weight::from_parts(45_081_969, 4764) + // Standard Error: 1_010 + .saturating_add(Weight::from_parts(39_539, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -906,10 +908,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 88_700_000 picoseconds. - Weight::from_parts(98_329_624, 6248) - // Standard Error: 4_477 - .saturating_add(Weight::from_parts(1_347_380, 0).saturating_mul(s.into())) + // Minimum execution time: 87_743_000 picoseconds. + Weight::from_parts(96_983_484, 6248) + // Standard Error: 4_271 + .saturating_add(Weight::from_parts(1_382_993, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -941,8 +943,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_877_000 picoseconds. - Weight::from_parts(53_503_000, 4556) + // Minimum execution time: 51_888_000 picoseconds. + Weight::from_parts(54_353_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -955,10 +957,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_604_000 picoseconds. - Weight::from_parts(31_726_296, 4556) - // Standard Error: 6_350 - .saturating_add(Weight::from_parts(6_416_846, 0).saturating_mul(k.into())) + // Minimum execution time: 28_944_000 picoseconds. + Weight::from_parts(31_116_533, 4556) + // Standard Error: 11_848 + .saturating_add(Weight::from_parts(6_422_601, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -991,10 +993,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_276_000 picoseconds. - Weight::from_parts(62_615_844, 6248) - // Standard Error: 14_914 - .saturating_add(Weight::from_parts(4_097_019, 0).saturating_mul(n.into())) + // Minimum execution time: 63_921_000 picoseconds. + Weight::from_parts(62_662_863, 6248) + // Standard Error: 15_071 + .saturating_add(Weight::from_parts(3_950_084, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1018,8 +1020,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 55_064_000 picoseconds. - Weight::from_parts(56_566_000, 6248) + // Minimum execution time: 54_605_000 picoseconds. + Weight::from_parts(56_406_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1033,8 +1035,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_626_000 picoseconds. - Weight::from_parts(17_519_000, 4556) + // Minimum execution time: 16_826_000 picoseconds. + Weight::from_parts(17_326_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1048,8 +1050,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_545_000 picoseconds. - Weight::from_parts(21_395_000, 4556) + // Minimum execution time: 20_831_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1061,8 +1063,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_179_000 picoseconds. - Weight::from_parts(20_728_000, 4556) + // Minimum execution time: 20_190_000 picoseconds. + Weight::from_parts(20_993_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1072,8 +1074,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_594_000 picoseconds. - Weight::from_parts(2_777_000, 0) + // Minimum execution time: 2_603_000 picoseconds. + Weight::from_parts(2_747_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1082,8 +1084,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_302_000 picoseconds. - Weight::from_parts(8_741_000, 0) + // Minimum execution time: 8_070_000 picoseconds. + Weight::from_parts(8_745_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1092,8 +1094,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_504_000 picoseconds. - Weight::from_parts(8_774_000, 0) + // Minimum execution time: 7_999_000 picoseconds. + Weight::from_parts(8_624_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1102,8 +1104,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_474_000 picoseconds. - Weight::from_parts(8_740_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_467_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1113,10 +1115,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_732_000 picoseconds. - Weight::from_parts(3_360_048, 0) - // Standard Error: 34 - .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(v.into())) + // Minimum execution time: 2_731_000 picoseconds. + Weight::from_parts(3_298_421, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_075, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) @@ -1152,10 +1154,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_495_000 picoseconds. - Weight::from_parts(95_710_388, 6248) - // Standard Error: 5_849 - .saturating_add(Weight::from_parts(1_339_335, 0).saturating_mul(s.into())) + // Minimum execution time: 86_305_000 picoseconds. + Weight::from_parts(94_494_401, 6248) + // Standard Error: 3_602 + .saturating_add(Weight::from_parts(1_339_477, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1168,10 +1170,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 98_255_000 picoseconds. - Weight::from_parts(892_807_378, 70137) - // Standard Error: 57_735 - .saturating_add(Weight::from_parts(4_876_449, 0).saturating_mul(s.into())) + // Minimum execution time: 100_007_000 picoseconds. + Weight::from_parts(894_033_025, 70137) + // Standard Error: 57_584 + .saturating_add(Weight::from_parts(4_870_504, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1207,11 +1209,11 @@ impl WeightInfo for () { fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 144_258_000 picoseconds. - Weight::from_parts(175_256_796, 30944) - // Standard Error: 24_339 - .saturating_add(Weight::from_parts(46_011_700, 0).saturating_mul(n.into())) + // Estimated: `30944 + n * (3774 ±0)` + // Minimum execution time: 142_575_000 picoseconds. + Weight::from_parts(196_320_577, 30944) + // Standard Error: 29_330 + .saturating_add(Weight::from_parts(45_325_062, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1235,10 +1237,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 83_532_000 picoseconds. - Weight::from_parts(86_757_943, 8877) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(57_566, 0).saturating_mul(l.into())) + // Minimum execution time: 81_113_000 picoseconds. + Weight::from_parts(84_470_927, 8877) + // Standard Error: 5_588 + .saturating_add(Weight::from_parts(97_606, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1273,10 +1275,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 96_776_000 picoseconds. - Weight::from_parts(100_950_027, 6248) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(1_432_091, 0).saturating_mul(s.into())) + // Minimum execution time: 94_810_000 picoseconds. + Weight::from_parts(99_292_156, 6248) + // Standard Error: 3_677 + .saturating_add(Weight::from_parts(1_345_598, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1321,13 +1323,13 @@ impl WeightInfo for () { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 577_699_000 picoseconds. - Weight::from_parts(582_827_000, 512390) - // Standard Error: 2_000_851 - .saturating_add(Weight::from_parts(67_316_744, 0).saturating_mul(v.into())) - // Standard Error: 199_373 - .saturating_add(Weight::from_parts(18_503_387, 0).saturating_mul(n.into())) + // Estimated: `512390 + n * (3566 ±4) + v * (3566 ±40)` + // Minimum execution time: 583_230_000 picoseconds. + Weight::from_parts(585_794_000, 512390) + // Standard Error: 1_984_644 + .saturating_add(Weight::from_parts(65_914_551, 0).saturating_mul(v.into())) + // Standard Error: 197_758 + .saturating_add(Weight::from_parts(18_105_424, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1358,12 +1360,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_048_778_000 picoseconds. - Weight::from_parts(34_397_777_000, 512390) - // Standard Error: 346_115 - .saturating_add(Weight::from_parts(3_704_941, 0).saturating_mul(v.into())) - // Standard Error: 346_115 - .saturating_add(Weight::from_parts(4_064_819, 0).saturating_mul(n.into())) + // Minimum execution time: 33_312_958_000 picoseconds. + Weight::from_parts(4_949_866_209, 512390) + // Standard Error: 402_931 + .saturating_add(Weight::from_parts(16_448_367, 0).saturating_mul(v.into())) + // Standard Error: 402_931 + .saturating_add(Weight::from_parts(25_361_503, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1380,10 +1382,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_473_149_000 picoseconds. - Weight::from_parts(84_721_859, 3510) - // Standard Error: 8_690 - .saturating_add(Weight::from_parts(4_870_439, 0).saturating_mul(v.into())) + // Minimum execution time: 2_474_646_000 picoseconds. + Weight::from_parts(2_512_113_000, 3510) + // Standard Error: 33_996 + .saturating_add(Weight::from_parts(1_992_173, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1404,8 +1406,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_312_000 picoseconds. - Weight::from_parts(5_897_000, 0) + // Minimum execution time: 5_466_000 picoseconds. + Weight::from_parts(5_861_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1424,10 +1426,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_676_000 picoseconds. - Weight::from_parts(4_913_000, 0) + // Minimum execution time: 4_780_000 picoseconds. + Weight::from_parts(4_998_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1450,11 +1454,11 @@ impl WeightInfo for () { /// 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: `1773` + // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 67_286_000 picoseconds. - Weight::from_parts(69_081_000, 6248) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Minimum execution time: 71_261_000 picoseconds. + Weight::from_parts(72_778_000, 6248) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -1465,8 +1469,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_749_000 picoseconds. - Weight::from_parts(13_275_000, 3510) + // Minimum execution time: 12_497_000 picoseconds. + Weight::from_parts(13_049_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1476,8 +1480,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_155_000 picoseconds. - Weight::from_parts(3_319_000, 0) + // Minimum execution time: 3_044_000 picoseconds. + Weight::from_parts(3_278_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } -- GitLab From db290997651dae8615be706efdd74f0ab0db52ee Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 28 Nov 2023 09:42:14 +0400 Subject: [PATCH 591/633] CI: Fix `build-and-attach-release-runtimes.yml` (#2471) Incorporate suggestion from release team to get this workflow working. edit: worked on this test GH release: https://github.com/paritytech/polkadot-sdk/releases/tag/liam-debug-ghw. let's try it. --- .github/workflows/build-and-attach-release-runtimes.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml index db0175c6855..8e0a5ba04b4 100644 --- a/.github/workflows/build-and-attach-release-runtimes.yml +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -3,7 +3,7 @@ name: Build and Attach Runtimes to Releases/RC on: release: types: - - created + - published env: PROFILE: production @@ -44,12 +44,6 @@ jobs: runtime_dir: ${{ matrix.runtime.path }} profile: ${{ env.PROFILE }} - - name: Build Summary - run: | - echo "${{ steps.srtool_build.outputs.json }}" | jq . > ${{ matrix.runtime.name }}-srtool-digest.json - cat ${{ matrix.runtime.name }}-srtool-digest.json - echo "Runtime location: ${{ steps.srtool_build.outputs.wasm }}" - - name: Set up paths and runtime names id: setup run: | -- GitLab From 2ac23d247d2d81e6f67116a1696beaf189192b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 28 Nov 2023 08:11:46 +0100 Subject: [PATCH 592/633] Fixes cumulus README instructions (#2442) README instructions fixes to be compatible with the `polkadot-prepare` and `polkadot-execute` binary split. --- cumulus/README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cumulus/README.md b/cumulus/README.md index 19f9f3f113d..6acbf6dc2ca 100644 --- a/cumulus/README.md +++ b/cumulus/README.md @@ -142,8 +142,8 @@ zombienet --provider native spawn ./zombienet/examples/small_network.toml # Clone git clone https://github.com/paritytech/polkadot-sdk -# Compile Polkadot -cargo build --release --bin polkadot +# Compile Polkadot's required binaries +cargo build --release -p polkadot # Generate a raw chain spec ./target/release/polkadot build-spec --chain rococo-local --disable-default-bootnode --raw > rococo-local-cfde.json @@ -158,11 +158,8 @@ cargo build --release --bin polkadot #### Launch the Parachain ```bash -# Clone -git clone https://github.com/paritytech/polkadot-sdk - # Compile -cargo build --release --bin polkadot-parachain +cargo build --release -p polkadot-parachain-bin # Export genesis state ./target/release/polkadot-parachain export-genesis-state > genesis-state @@ -172,15 +169,15 @@ cargo build --release --bin polkadot-parachain # Collator1 ./target/release/polkadot-parachain --collator --alice --force-authoring \ - --tmp --port 40335 --rpc-port 9946 -- --chain ../polkadot/rococo-local-cfde.json --port 30335 + --tmp --port 40335 --rpc-port 9946 -- --chain rococo-local-cfde.json --port 30335 # Collator2 ./target/release/polkadot-parachain --collator --bob --force-authoring \ - --tmp --port 40336 --rpc-port 9947 -- --chain ../polkadot/rococo-local-cfde.json --port 30336 + --tmp --port 40336 --rpc-port 9947 -- --chain rococo-local-cfde.json --port 30336 # Parachain Full Node 1 ./target/release/polkadot-parachain --tmp --port 40337 --rpc-port 9948 -- \ - --chain ../polkadot/rococo-local-cfde.json --port 30337 + --chain rococo-local-cfde.json --port 30337 ``` #### Register the parachain -- GitLab From 75062717de9f3dbe741d058309600c864cc603c3 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Tue, 28 Nov 2023 14:19:49 +0700 Subject: [PATCH 593/633] Pools: Add ability to configure commission claiming permissions (#2474) Addresses #409. This request has been raised by multiple community members - the ability for the nomination pool root role to configure permissionless commission claiming: > Would it be possible to have a claim_commission_other extrinsic for claiming commission of nomination pools permissionless? This PR does not quite introduce this additional call, but amends `do_claim_commission` to check a new `claim_permission` field in the `Commission` struct, configured by an enum: ``` enum CommissionClaimPermission { Permissionless, Account(AccountId), } ``` This can be optionally set in a bonded pool's `commission.claim_permission` field: ``` struct BondedPool { commission: { claim_permission: Option>, }, } ``` This is a new field and requires a migration to add it to existing pools. This will be `None` on pool creation, falling back to the `root` role having sole access to claim commission if it is not set; this is the behaviour as it is today. Once set, the field _can_ be set to `None` again. #### Changes - [x] Add `commision.claim_permission` field. - [x] Add `can_claim_commission` and amend `do_claim_commission`. - [x] Add `set_commission_claim_permission` call. - [x] Test to cover new configs and call. - [x] Add and amend benchmarks. - [x] Generate new weights + slot into call `set_commission_claim_permission`. - [x] Add migration to introduce `commission.claim_permission`, bump storage version. - [x] Update Westend weights. - [x] Migration working. --------- Co-authored-by: command-bot <> --- polkadot/runtime/westend/src/lib.rs | 3 +- .../src/weights/pallet_nomination_pools.rs | 276 ++++----- .../nomination-pools/benchmarking/src/lib.rs | 41 +- substrate/frame/nomination-pools/src/lib.rs | 58 +- .../frame/nomination-pools/src/migration.rs | 77 +++ substrate/frame/nomination-pools/src/tests.rs | 211 ++++++- .../frame/nomination-pools/src/weights.rs | 523 ++++++++++-------- 7 files changed, 796 insertions(+), 393 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 6bbdb2db098..bb6331e9534 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1533,11 +1533,10 @@ pub mod migrations { parachains_configuration::migration::v8::MigrateToV8, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::MigrateToV1, - pallet_nomination_pools::migration::versioned::V5toV6, pallet_referenda::migration::v1::MigrateV0ToV1, - pallet_nomination_pools::migration::versioned::V6ToV7, pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, + pallet_nomination_pools::migration::versioned::V7ToV8, ); } diff --git a/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs b/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs index 49bc687a3e4..6aa5ddd1ec8 100644 --- a/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs +++ b/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_nomination_pools` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -53,7 +53,7 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -78,20 +78,22 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3318` + // Measured: `3355` // Estimated: `8877` - // Minimum execution time: 187_795_000 picoseconds. - Weight::from_parts(193_857_000, 0) + // Minimum execution time: 173_707_000 picoseconds. + Weight::from_parts(179_920_000, 0) .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().reads(20)) + .saturating_add(T::DbWeight::get().writes(13)) } /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -110,22 +112,24 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3328` + // Measured: `3365` // Estimated: `8877` - // Minimum execution time: 186_245_000 picoseconds. - Weight::from_parts(190_916_000, 0) + // Minimum execution time: 174_414_000 picoseconds. + Weight::from_parts(178_068_000, 0) .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(12)) + .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -144,22 +148,24 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3274` + // Measured: `3312` // Estimated: `8799` - // Minimum execution time: 217_918_000 picoseconds. - Weight::from_parts(224_772_000, 0) + // Minimum execution time: 198_864_000 picoseconds. + Weight::from_parts(203_783_000, 0) .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(12)) + .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -168,10 +174,10 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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` + // Measured: `1138` // Estimated: `4182` - // Minimum execution time: 76_958_000 picoseconds. - Weight::from_parts(78_278_000, 0) + // Minimum execution time: 70_250_000 picoseconds. + Weight::from_parts(72_231_000, 0) .saturating_add(Weight::from_parts(0, 4182)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -179,7 +185,7 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -210,16 +216,16 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3597` + // Measured: `3545` // Estimated: `8877` - // Minimum execution time: 170_992_000 picoseconds. - Weight::from_parts(179_987_000, 0) + // Minimum execution time: 155_853_000 picoseconds. + Weight::from_parts(161_032_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -230,25 +236,27 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1670` + // Measured: `1744` // Estimated: `4764` - // Minimum execution time: 60_740_000 picoseconds. - Weight::from_parts(64_502_831, 0) + // Minimum execution time: 62_933_000 picoseconds. + Weight::from_parts(65_847_171, 0) .saturating_add(Weight::from_parts(0, 4764)) - // 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)) + // Standard Error: 1_476 + .saturating_add(Weight::from_parts(59_648, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -261,6 +269,8 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) @@ -268,22 +278,22 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2098` + // Measured: `2134` // Estimated: `4764` - // Minimum execution time: 127_322_000 picoseconds. - Weight::from_parts(132_064_603, 0) + // Minimum execution time: 123_641_000 picoseconds. + Weight::from_parts(127_222_589, 0) .saturating_add(Weight::from_parts(0, 4764)) - // 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)) + // Standard Error: 2_493 + .saturating_add(Weight::from_parts(83_361, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(9)) } /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -292,16 +302,18 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) @@ -323,17 +335,15 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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: `2454` + // Measured: `2453` // Estimated: `8538` - // Minimum execution time: 236_510_000 picoseconds. - Weight::from_parts(243_943_334, 0) + // Minimum execution time: 219_469_000 picoseconds. + Weight::from_parts(227_526_000, 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)) + .saturating_add(T::DbWeight::get().reads(24)) + .saturating_add(T::DbWeight::get().writes(20)) } /// Storage: `NominationPools::LastPoolId` (r:1 w:1) /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -359,14 +369,12 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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) @@ -376,21 +384,23 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `1222` + // Measured: `1102` // Estimated: `8538` - // Minimum execution time: 197_883_000 picoseconds. - Weight::from_parts(201_750_000, 0) + // Minimum execution time: 166_466_000 picoseconds. + Weight::from_parts(171_425_000, 0) .saturating_add(Weight::from_parts(0, 8538)) - .saturating_add(T::DbWeight::get().reads(24)) - .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(T::DbWeight::get().reads(23)) + .saturating_add(T::DbWeight::get().writes(17)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) - /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -416,36 +426,36 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1779` + // Measured: `1738` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 65_505_000 picoseconds. - Weight::from_parts(67_148_657, 0) + // Minimum execution time: 59_650_000 picoseconds. + Weight::from_parts(60_620_077, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 9_115 - .saturating_add(Weight::from_parts(1_421_198, 0).saturating_mul(n.into())) + // Standard Error: 7_316 + .saturating_add(Weight::from_parts(1_467_406, 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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` + // Measured: `1363` // Estimated: `4556` - // Minimum execution time: 34_157_000 picoseconds. - Weight::from_parts(35_557_000, 0) + // Minimum execution time: 31_170_000 picoseconds. + Weight::from_parts(32_217_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -453,13 +463,13 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `497` + // Measured: `498` // Estimated: `3735` - // Minimum execution time: 13_806_000 picoseconds. - Weight::from_parts(14_540_018, 0) + // Minimum execution time: 12_603_000 picoseconds. + Weight::from_parts(13_241_702, 0) .saturating_add(Weight::from_parts(0, 3735)) - // Standard Error: 123 - .saturating_add(Weight::from_parts(644, 0).saturating_mul(n.into())) + // Standard Error: 116 + .saturating_add(Weight::from_parts(1_428, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -479,25 +489,25 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_870_000 picoseconds. - Weight::from_parts(6_253_000, 0) + // Minimum execution time: 3_608_000 picoseconds. + Weight::from_parts(3_801_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3685` - // Minimum execution time: 18_290_000 picoseconds. - Weight::from_parts(18_961_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `498` + // Estimated: `3719` + // Minimum execution time: 16_053_000 picoseconds. + Weight::from_parts(16_473_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -516,16 +526,16 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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` + // Measured: `1901` // Estimated: `4556` - // Minimum execution time: 63_708_000 picoseconds. - Weight::from_parts(65_570_000, 0) + // Minimum execution time: 57_251_000 picoseconds. + Weight::from_parts(59_390_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -534,37 +544,49 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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: 34_291_000 picoseconds. - Weight::from_parts(34_767_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `770` + // Estimated: `3719` + // Minimum execution time: 29_888_000 picoseconds. + Weight::from_parts(31_056_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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_406_000 picoseconds. - Weight::from_parts(18_999_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `538` + // Estimated: `3719` + // Minimum execution time: 15_769_000 picoseconds. + Weight::from_parts(16_579_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3685` - // Minimum execution time: 18_440_000 picoseconds. - Weight::from_parts(19_230_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `498` + // Estimated: `3719` + // Minimum execution time: 15_385_000 picoseconds. + Weight::from_parts(16_402_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) + .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(254), added: 2729, mode: `MaxEncodedLen`) + fn set_commission_claim_permission() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3719` + // Minimum execution time: 14_965_000 picoseconds. + Weight::from_parts(15_548_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -576,14 +598,14 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo // Proof Size summary in bytes: // Measured: `508` // Estimated: `4182` - // Minimum execution time: 14_310_000 picoseconds. - Weight::from_parts(14_681_000, 0) + // Minimum execution time: 13_549_000 picoseconds. + Weight::from_parts(14_307_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -592,16 +614,16 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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: 64_526_000 picoseconds. - Weight::from_parts(66_800_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `968` + // Estimated: `3719` + // Minimum execution time: 60_153_000 picoseconds. + Weight::from_parts(61_369_000, 0) + .saturating_add(Weight::from_parts(0, 3719)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -610,10 +632,10 @@ impl pallet_nomination_pools::WeightInfo for WeightInfo /// 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` + // Measured: `867` // Estimated: `4764` - // Minimum execution time: 73_472_000 picoseconds. - Weight::from_parts(74_698_000, 0) + // Minimum execution time: 64_985_000 picoseconds. + Weight::from_parts(66_616_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/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index fc86a6f56c0..48d7dae29ef 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -35,9 +35,9 @@ use frame_support::{ use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, - Commission, CommissionChangeRate, ConfigOp, GlobalMaxCommission, MaxPoolMembers, - MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, - PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, + Commission, CommissionChangeRate, CommissionClaimPermission, ConfigOp, GlobalMaxCommission, + MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, + Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, }; use pallet_staking::MaxNominationsOf; use sp_runtime::{ @@ -706,17 +706,24 @@ frame_benchmarking::benchmarks! { max_increase: Perbill::from_percent(20), min_delay: 0u32.into(), }).unwrap(); + // set a claim permission to an account. + Pools::::set_commission_claim_permission( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + Some(CommissionClaimPermission::Account(depositor.clone())) + ).unwrap(); }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some((Perbill::from_percent(20), depositor.clone()))) verify { assert_eq!(BondedPools::::get(1).unwrap().commission, Commission { - current: Some((Perbill::from_percent(20), depositor)), + current: Some((Perbill::from_percent(20), depositor.clone())), max: Some(Perbill::from_percent(50)), change_rate: Some(CommissionChangeRate { max_increase: Perbill::from_percent(20), min_delay: 0u32.into() }), throttle_from: Some(1u32.into()), + claim_permission: Some(CommissionClaimPermission::Account(depositor)), }); } @@ -731,6 +738,7 @@ frame_benchmarking::benchmarks! { max: Some(Perbill::from_percent(50)), change_rate: None, throttle_from: Some(0u32.into()), + claim_permission: None, }); } @@ -751,9 +759,25 @@ frame_benchmarking::benchmarks! { min_delay: 1000u32.into(), }), throttle_from: Some(1_u32.into()), + claim_permission: None, }); } + set_commission_claim_permission { + // Create a pool. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some(CommissionClaimPermission::Account(depositor.clone()))) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: None, + max: None, + change_rate: None, + throttle_from: None, + claim_permission: Some(CommissionClaimPermission::Account(depositor)), + }); + } + set_claim_permission { // Create a pool let min_create_bond = Pools::::depositor_min_bond(); @@ -786,8 +810,13 @@ frame_benchmarking::benchmarks! { 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()); - + let _ = Pools::::claim_payout(RuntimeOrigin::Signed(claimer.clone()).into()); + // set a claim permission to an account. + let _ = Pools::::set_commission_claim_permission( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + Some(CommissionClaimPermission::Account(claimer)) + ); whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) verify { diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index ab4bd51ffc0..f191126fbdd 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -676,6 +676,13 @@ pub struct PoolRoles { pub bouncer: Option, } +// A pool's possible commission claiming permissions. +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum CommissionClaimPermission { + Permissionless, + Account(AccountId), +} + /// Pool commission. /// /// The pool `root` can set commission configuration after pool creation. By default, all commission @@ -705,6 +712,9 @@ pub struct Commission { /// The block from where throttling should be checked from. This value will be updated on all /// commission updates and when setting an initial `change_rate`. pub throttle_from: Option>, + // Whether commission can be claimed permissionlessly, or whether an account can claim + // commission. `Root` role can always claim. + pub claim_permission: Option>, } impl Commission { @@ -1078,6 +1088,17 @@ impl BondedPool { self.is_root(who) } + fn can_claim_commission(&self, who: &T::AccountId) -> bool { + if let Some(permission) = self.commission.claim_permission.as_ref() { + match permission { + CommissionClaimPermission::Permissionless => true, + CommissionClaimPermission::Account(account) => account == who || self.is_root(who), + } + } else { + self.is_root(who) + } + } + fn is_destroying(&self) -> bool { matches!(self.state, PoolState::Destroying) } @@ -1572,7 +1593,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1850,6 +1871,11 @@ pub mod pallet { pool_id: PoolId, change_rate: CommissionChangeRate>, }, + /// Pool commission claim permission has been updated. + PoolCommissionClaimPermissionUpdated { + pool_id: PoolId, + permission: Option>, + }, /// Pool commission has been claimed. PoolCommissionClaimed { pool_id: PoolId, commission: BalanceOf }, /// Topped up deficit in frozen ED of the reward pool. @@ -2742,6 +2768,32 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::do_adjust_pool_deposit(who, pool_id) } + + /// Set or remove a pool's commission claim permission. + /// + /// Determines who can claim the pool's pending commission. Only the `Root` role of the pool + /// is able to conifigure commission claim permissions. + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::set_commission_claim_permission())] + pub fn set_commission_claim_permission( + origin: OriginFor, + pool_id: PoolId, + permission: Option>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + + bonded_pool.commission.claim_permission = permission.clone(); + bonded_pool.put(); + + Self::deposit_event(Event::::PoolCommissionClaimPermissionUpdated { + pool_id, + permission, + }); + + Ok(()) + } } #[pallet::hooks] @@ -3106,12 +3158,12 @@ impl Pallet { fn do_claim_commission(who: T::AccountId, pool_id: PoolId) -> DispatchResult { let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; - ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + ensure!(bonded_pool.can_claim_commission(&who), Error::::DoesNotHavePermission); let mut reward_pool = RewardPools::::get(pool_id) .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; - // IMPORTANT: make sure that any newly pending commission not yet processed is added to + // IMPORTANT: ensure newly pending commission not yet processed is added to // `total_commission_pending`. reward_pool.update_records( pool_id, diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 3d68fee1dca..3adfd926d95 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -27,6 +27,15 @@ use sp_runtime::TryRuntimeError; pub mod versioned { use super::*; + /// v8: Adds commission claim permissions to `BondedPools`. + pub type V7ToV8 = frame_support::migrations::VersionedMigration< + 7, + 8, + v8::VersionUncheckedMigrateV7ToV8, + crate::pallet::Pallet, + ::DbWeight, + >; + /// 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< @@ -47,6 +56,74 @@ pub mod versioned { >; } +pub mod v8 { + use super::*; + + #[derive(Decode)] + pub struct OldCommission { + pub current: Option<(Perbill, T::AccountId)>, + pub max: Option, + pub change_rate: Option>>, + pub throttle_from: Option>, + } + + #[derive(Decode)] + pub struct OldBondedPoolInner { + pub commission: OldCommission, + pub member_counter: u32, + pub points: BalanceOf, + pub roles: PoolRoles, + pub state: PoolState, + } + + impl OldBondedPoolInner { + fn migrate_to_v8(self) -> BondedPoolInner { + BondedPoolInner { + commission: Commission { + current: self.commission.current, + max: self.commission.max, + change_rate: self.commission.change_rate, + throttle_from: self.commission.throttle_from, + // `claim_permission` is a new field. + claim_permission: None, + }, + member_counter: self.member_counter, + points: self.points, + roles: self.roles, + state: self.state, + } + } + } + + pub struct VersionUncheckedMigrateV7ToV8(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for VersionUncheckedMigrateV7ToV8 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + let mut translated = 0u64; + BondedPools::::translate::, _>(|_key, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v8()) + }); + T::DbWeight::get().reads_writes(translated, translated + 1) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + // Check new `claim_permission` field is present. + ensure!( + BondedPools::::iter() + .all(|(_, inner)| inner.commission.claim_permission.is_none()), + "`claim_permission` value has not been set correctly." + ); + Ok(()) + } + } +} + /// This migration accumulates and initializes the [`TotalValueLocked`] for all pools. /// /// WARNING: This migration works under the assumption that the [`BondedPools`] cannot be inflated diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 2749e89ecff..7fe1e704bb1 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -5761,7 +5761,13 @@ mod commission { // Then: assert_eq!( BondedPool::::get(1).unwrap().commission, - Commission { current: None, max: None, change_rate: None, throttle_from: Some(1) } + Commission { + current: None, + max: None, + change_rate: None, + throttle_from: Some(1), + claim_permission: None, + } ); assert_eq!( pool_events_since_last_call(), @@ -5956,6 +5962,7 @@ mod commission { min_delay: 2_u64 }), throttle_from: Some(1_u64), + claim_permission: None, } ); assert_eq!( @@ -6007,6 +6014,7 @@ mod commission { min_delay: 2_u64 }), throttle_from: Some(3_u64), + claim_permission: None, } ); assert_eq!( @@ -6082,7 +6090,8 @@ mod commission { max_increase: Perbill::from_percent(1), min_delay: 2 }), - throttle_from: Some(7) + throttle_from: Some(7), + claim_permission: None, } ); assert_eq!( @@ -6183,6 +6192,7 @@ mod commission { max: Some(Perbill::from_percent(50)), change_rate: None, throttle_from: Some(1), + claim_permission: None, } ); @@ -6409,6 +6419,7 @@ mod commission { min_delay: 10_u64 }), throttle_from: Some(11), + claim_permission: None, } ); @@ -6502,7 +6513,8 @@ mod commission { max_increase: Perbill::from_percent(1), min_delay: 0 }), - throttle_from: Some(1) + throttle_from: Some(1), + claim_permission: None, } ); @@ -6885,6 +6897,13 @@ mod commission { #[test] fn claim_commission_works() { ExtBuilder::default().build_and_execute(|| { + /// Deposit rewards into the pool and claim payout. This will set up pending commission + /// to be tested in various scenarios. + fn deposit_rewards_and_claim_payout(caller: AccountId, points: u128) { + deposit_rewards(points); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(caller))); + } + let pool_id = 1; let _ = Currency::set_balance(&900, 5); @@ -6905,21 +6924,9 @@ mod commission { ] ); - // Pool earns 80 points, payout is triggered. - deposit_rewards(80); - assert_eq!( - PoolMembers::::get(10).unwrap(), - PoolMember:: { pool_id, points: 10, ..Default::default() } - ); - - assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id, payout: 40 }] - ); - // Given: - assert_eq!(RewardPool::::current_balance(pool_id), 40); + deposit_rewards_and_claim_payout(10, 100); + assert_eq!(RewardPool::::current_balance(pool_id), 50); // Pool does not exist assert_noop!( @@ -6944,6 +6951,176 @@ mod commission { Pools::claim_commission(RuntimeOrigin::signed(900), pool_id,), Error::::NoPendingCommission ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id, payout: 50 }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 50 } + ] + ); + + // The pool commission's claim_permission field is updated to `Permissionless` by the + // root member, which means anyone can now claim commission for the pool. + + // Given: + // Some random non-pool member to claim commission. + let non_pool_member = 1001; + let _ = Currency::set_balance(&non_pool_member, 5); + + // Set up pending commission. + deposit_rewards_and_claim_payout(10, 100); + assert_ok!(Pools::set_commission_claim_permission( + RuntimeOrigin::signed(900), + pool_id, + Some(CommissionClaimPermission::Permissionless) + )); + + // When: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(non_pool_member), pool_id)); + + // Then: + assert_eq!(RewardPool::::current_balance(pool_id), 0); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id, payout: 50 }, + Event::PoolCommissionClaimPermissionUpdated { + pool_id: 1, + permission: Some(CommissionClaimPermission::Permissionless) + }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 50 }, + ] + ); + + // The pool commission's claim_permission is updated to an adhoc account by the root + // member, which means now only that account (in addition to the root role) can claim + // commission for the pool. + + // Given: + // The account designated to claim commission. + let designated_commission_claimer = 2001; + let _ = Currency::set_balance(&designated_commission_claimer, 5); + + // Set up pending commission. + deposit_rewards_and_claim_payout(10, 100); + assert_ok!(Pools::set_commission_claim_permission( + RuntimeOrigin::signed(900), + pool_id, + Some(CommissionClaimPermission::Account(designated_commission_claimer)) + )); + + // When: + // Previous claimer can no longer claim commission. + assert_noop!( + Pools::claim_commission(RuntimeOrigin::signed(1001), pool_id,), + Error::::DoesNotHavePermission + ); + // Designated claimer can claim commission. + assert_ok!(Pools::claim_commission( + RuntimeOrigin::signed(designated_commission_claimer), + pool_id + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id, payout: 50 }, + Event::PoolCommissionClaimPermissionUpdated { + pool_id: 1, + permission: Some(CommissionClaimPermission::Account(2001)) + }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 50 }, + ] + ); + + // Even with an Account claim permission set, the `root` role of the pool can still + // claim commission. + + // Given: + deposit_rewards_and_claim_payout(10, 100); + + // When: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(900), pool_id)); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id, payout: 50 }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 50 }, + ] + ); + + // The root role updates commission's claim_permission back to `None`, which results in + // only the root member being able to claim commission for the pool. + + // Given: + deposit_rewards_and_claim_payout(10, 100); + + // When: + assert_ok!(Pools::set_commission_claim_permission( + RuntimeOrigin::signed(900), + pool_id, + None + )); + // Previous claimer can no longer claim commission. + assert_noop!( + Pools::claim_commission( + RuntimeOrigin::signed(designated_commission_claimer), + pool_id, + ), + Error::::DoesNotHavePermission + ); + // Root can claim commission. + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(900), pool_id)); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id, payout: 50 }, + Event::PoolCommissionClaimPermissionUpdated { pool_id: 1, permission: None }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 50 }, + ] + ); + }) + } + + #[test] + fn set_commission_claim_permission_handles_errors() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + + let _ = Currency::set_balance(&900, 5); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id }, + Event::Bonded { member: 10, pool_id, bonded: 10, joined: true }, + ] + ); + + // Cannot operate on a non-existing pool. + assert_noop!( + Pools::set_commission_claim_permission( + RuntimeOrigin::signed(10), + 90, + Some(CommissionClaimPermission::Permissionless) + ), + Error::::PoolNotFound + ); + + // Only the root role can change the commission claim permission. + assert_noop!( + Pools::set_commission_claim_permission( + RuntimeOrigin::signed(10), + pool_id, + Some(CommissionClaimPermission::Permissionless) + ), + Error::::DoesNotHavePermission + ); }) } } diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index 2cb414fc2a0..047a17c3f9a 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_nomination_pools` //! //! 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: `[]` +//! DATE: 2023-11-23, 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` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -67,6 +67,7 @@ pub trait WeightInfo { fn set_commission() -> Weight; fn set_commission_max() -> Weight; fn set_commission_change_rate() -> Weight; + fn set_commission_claim_permission() -> Weight; fn set_claim_permission() -> Weight; fn claim_commission() -> Weight; fn adjust_pool_deposit() -> Weight; @@ -80,7 +81,7 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -105,19 +106,21 @@ impl WeightInfo for SubstrateWeight { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3388` + // Measured: `3425` // Estimated: `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)) + // Minimum execution time: 184_295_000 picoseconds. + Weight::from_parts(188_860_000, 8877) + .saturating_add(T::DbWeight::get().reads(20_u64)) + .saturating_add(T::DbWeight::get().writes(13_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -136,21 +139,23 @@ impl WeightInfo for SubstrateWeight { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3398` + // Measured: `3435` // Estimated: `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)) + // Minimum execution time: 188_777_000 picoseconds. + Weight::from_parts(192_646_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -169,21 +174,23 @@ impl WeightInfo for SubstrateWeight { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3463` + // Measured: `3500` // Estimated: `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)) + // Minimum execution time: 221_728_000 picoseconds. + Weight::from_parts(227_569_000, 8877) + .saturating_add(T::DbWeight::get().reads(18_u64)) + .saturating_add(T::DbWeight::get().writes(14_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -192,17 +199,17 @@ impl WeightInfo for SubstrateWeight { /// 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_115_000 picoseconds. - Weight::from_parts(83_604_000, 3702) + // Measured: `1172` + // Estimated: `3719` + // Minimum execution time: 75_310_000 picoseconds. + Weight::from_parts(77_709_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -233,15 +240,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3674` + // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 187_210_000 picoseconds. - Weight::from_parts(189_477_000, 27847) + // Minimum execution time: 170_656_000 picoseconds. + Weight::from_parts(174_950_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -252,24 +259,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1743` + // Measured: `1817` // Estimated: `4764` - // 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)) + // Minimum execution time: 68_866_000 picoseconds. + Weight::from_parts(72_312_887, 4764) + // Standard Error: 1_635 + .saturating_add(Weight::from_parts(41_679, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -282,6 +291,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) @@ -289,21 +300,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2171` + // Measured: `2207` // Estimated: `27847` - // 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)) + // Minimum execution time: 131_383_000 picoseconds. + Weight::from_parts(136_595_971, 27847) + // Standard Error: 2_715 + .saturating_add(Weight::from_parts(52_351, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(9_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -312,16 +323,18 @@ impl WeightInfo for SubstrateWeight { /// 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: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) @@ -345,12 +358,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2526` + // Measured: `2525` // Estimated: `27847` - // 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)) + // Minimum execution time: 233_314_000 picoseconds. + Weight::from_parts(241_694_316, 27847) + .saturating_add(T::DbWeight::get().reads(24_u64)) + .saturating_add(T::DbWeight::get().writes(20_u64)) } /// Storage: `NominationPools::LastPoolId` (r:1 w:1) /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -376,14 +389,12 @@ impl WeightInfo for SubstrateWeight { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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) @@ -393,20 +404,22 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `1289` + // Measured: `1169` // 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)) + // Minimum execution time: 171_465_000 picoseconds. + Weight::from_parts(176_478_000, 8538) + .saturating_add(T::DbWeight::get().reads(23_u64)) + .saturating_add(T::DbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) - /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -432,34 +445,34 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1849` + // Measured: `1808` // Estimated: `4556 + n * (2520 ±0)` - // 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())) + // Minimum execution time: 63_588_000 picoseconds. + Weight::from_parts(64_930_584, 4556) + // Standard Error: 9_167 + .saturating_add(Weight::from_parts(1_595_779, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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` + // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 36_542_000 picoseconds. - Weight::from_parts(37_644_000, 4556) + // Minimum execution time: 32_899_000 picoseconds. + Weight::from_parts(33_955_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -467,12 +480,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `531` + // Measured: `532` // Estimated: `3735` - // 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())) + // Minimum execution time: 13_778_000 picoseconds. + Weight::from_parts(14_770_006, 3735) + // Standard Error: 151 + .saturating_add(Weight::from_parts(1_900, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -492,23 +505,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_819_000 picoseconds. - Weight::from_parts(7_253_000, 0) + // Minimum execution time: 4_550_000 picoseconds. + Weight::from_parts(4_935_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_596_000 picoseconds. - Weight::from_parts(20_828_000, 3685) + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_759_000 picoseconds. + Weight::from_parts(17_346_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) - /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -527,15 +540,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2012` + // Measured: `1971` // Estimated: `4556` - // Minimum execution time: 68_551_000 picoseconds. - Weight::from_parts(71_768_000, 4556) + // Minimum execution time: 61_970_000 picoseconds. + Weight::from_parts(63_738_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -544,34 +557,45 @@ impl WeightInfo for SubstrateWeight { /// 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: 36_128_000 picoseconds. - Weight::from_parts(38_547_000, 3685) + // Measured: `804` + // Estimated: `3719` + // Minimum execution time: 31_950_000 picoseconds. + Weight::from_parts(33_190_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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: 20_067_000 picoseconds. - Weight::from_parts(21_044_000, 3685) + // Measured: `572` + // Estimated: `3719` + // Minimum execution time: 16_807_000 picoseconds. + Weight::from_parts(17_733_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_186_000 picoseconds. - Weight::from_parts(20_189_000, 3685) + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_710_000 picoseconds. + Weight::from_parts(17_563_000, 3719) + .saturating_add(T::DbWeight::get().reads(1_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(254), added: 2729, mode: `MaxEncodedLen`) + fn set_commission_claim_permission() -> Weight { + // Proof Size summary in bytes: + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_493_000 picoseconds. + Weight::from_parts(17_022_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -583,13 +607,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 15_275_000 picoseconds. - Weight::from_parts(15_932_000, 3702) + // Minimum execution time: 14_248_000 picoseconds. + Weight::from_parts(15_095_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -598,15 +622,15 @@ impl WeightInfo for SubstrateWeight { /// 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: 67_931_000 picoseconds. - Weight::from_parts(72_202_000, 3685) + // Measured: `1002` + // Estimated: `3719` + // Minimum execution time: 61_969_000 picoseconds. + Weight::from_parts(63_965_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -615,10 +639,10 @@ impl WeightInfo for SubstrateWeight { /// 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` + // Measured: `901` // Estimated: `4764` - // Minimum execution time: 72_783_000 picoseconds. - Weight::from_parts(75_841_000, 4764) + // Minimum execution time: 65_462_000 picoseconds. + Weight::from_parts(67_250_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -631,7 +655,7 @@ impl WeightInfo for () { /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -656,19 +680,21 @@ impl WeightInfo for () { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3388` + // Measured: `3425` // Estimated: `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)) + // Minimum execution time: 184_295_000 picoseconds. + Weight::from_parts(188_860_000, 8877) + .saturating_add(RocksDbWeight::get().reads(20_u64)) + .saturating_add(RocksDbWeight::get().writes(13_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -687,21 +713,23 @@ impl WeightInfo for () { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3398` + // Measured: `3435` // Estimated: `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)) + // Minimum execution time: 188_777_000 picoseconds. + Weight::from_parts(192_646_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -720,21 +748,23 @@ impl WeightInfo for () { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3463` + // Measured: `3500` // Estimated: `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)) + // Minimum execution time: 221_728_000 picoseconds. + Weight::from_parts(227_569_000, 8877) + .saturating_add(RocksDbWeight::get().reads(18_u64)) + .saturating_add(RocksDbWeight::get().writes(14_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -743,17 +773,17 @@ impl WeightInfo for () { /// 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_115_000 picoseconds. - Weight::from_parts(83_604_000, 3702) + // Measured: `1172` + // Estimated: `3719` + // Minimum execution time: 75_310_000 picoseconds. + Weight::from_parts(77_709_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -784,15 +814,15 @@ impl WeightInfo for () { /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3674` + // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 187_210_000 picoseconds. - Weight::from_parts(189_477_000, 27847) + // Minimum execution time: 170_656_000 picoseconds. + Weight::from_parts(174_950_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -803,24 +833,26 @@ impl WeightInfo for () { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1743` + // Measured: `1817` // Estimated: `4764` - // 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)) + // Minimum execution time: 68_866_000 picoseconds. + Weight::from_parts(72_312_887, 4764) + // Standard Error: 1_635 + .saturating_add(Weight::from_parts(41_679, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(3_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -833,6 +865,8 @@ impl WeightInfo for () { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) @@ -840,21 +874,21 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2171` + // Measured: `2207` // Estimated: `27847` - // 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)) + // Minimum execution time: 131_383_000 picoseconds. + Weight::from_parts(136_595_971, 27847) + // Standard Error: 2_715 + .saturating_add(Weight::from_parts(52_351, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(9_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -863,16 +897,18 @@ impl WeightInfo for () { /// 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: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) @@ -896,12 +932,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2526` + // Measured: `2525` // Estimated: `27847` - // 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)) + // Minimum execution time: 233_314_000 picoseconds. + Weight::from_parts(241_694_316, 27847) + .saturating_add(RocksDbWeight::get().reads(24_u64)) + .saturating_add(RocksDbWeight::get().writes(20_u64)) } /// Storage: `NominationPools::LastPoolId` (r:1 w:1) /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -927,14 +963,12 @@ impl WeightInfo for () { /// 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::TotalValueLocked` (r:1 w:1) + /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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) @@ -944,20 +978,22 @@ impl WeightInfo for () { /// 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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `1289` + // Measured: `1169` // 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)) + // Minimum execution time: 171_465_000 picoseconds. + Weight::from_parts(176_478_000, 8538) + .saturating_add(RocksDbWeight::get().reads(23_u64)) + .saturating_add(RocksDbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) - /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -983,34 +1019,34 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1849` + // Measured: `1808` // Estimated: `4556 + n * (2520 ±0)` - // 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())) + // Minimum execution time: 63_588_000 picoseconds. + Weight::from_parts(64_930_584, 4556) + // Standard Error: 9_167 + .saturating_add(Weight::from_parts(1_595_779, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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` + // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 36_542_000 picoseconds. - Weight::from_parts(37_644_000, 4556) + // Minimum execution time: 32_899_000 picoseconds. + Weight::from_parts(33_955_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -1018,12 +1054,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `531` + // Measured: `532` // Estimated: `3735` - // 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())) + // Minimum execution time: 13_778_000 picoseconds. + Weight::from_parts(14_770_006, 3735) + // Standard Error: 151 + .saturating_add(Weight::from_parts(1_900, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1043,23 +1079,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_819_000 picoseconds. - Weight::from_parts(7_253_000, 0) + // Minimum execution time: 4_550_000 picoseconds. + Weight::from_parts(4_935_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_596_000 picoseconds. - Weight::from_parts(20_828_000, 3685) + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_759_000 picoseconds. + Weight::from_parts(17_346_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) - /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -1078,15 +1114,15 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2012` + // Measured: `1971` // Estimated: `4556` - // Minimum execution time: 68_551_000 picoseconds. - Weight::from_parts(71_768_000, 4556) + // Minimum execution time: 61_970_000 picoseconds. + Weight::from_parts(63_738_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -1095,34 +1131,45 @@ impl WeightInfo for () { /// 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: 36_128_000 picoseconds. - Weight::from_parts(38_547_000, 3685) + // Measured: `804` + // Estimated: `3719` + // Minimum execution time: 31_950_000 picoseconds. + Weight::from_parts(33_190_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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: 20_067_000 picoseconds. - Weight::from_parts(21_044_000, 3685) + // Measured: `572` + // Estimated: `3719` + // Minimum execution time: 16_807_000 picoseconds. + Weight::from_parts(17_733_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_186_000 picoseconds. - Weight::from_parts(20_189_000, 3685) + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_710_000 picoseconds. + Weight::from_parts(17_563_000, 3719) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + fn set_commission_claim_permission() -> Weight { + // Proof Size summary in bytes: + // Measured: `532` + // Estimated: `3719` + // Minimum execution time: 16_493_000 picoseconds. + Weight::from_parts(17_022_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1134,13 +1181,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 15_275_000 picoseconds. - Weight::from_parts(15_932_000, 3702) + // Minimum execution time: 14_248_000 picoseconds. + Weight::from_parts(15_095_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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -1149,15 +1196,15 @@ impl WeightInfo for () { /// 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: 67_931_000 picoseconds. - Weight::from_parts(72_202_000, 3685) + // Measured: `1002` + // Estimated: `3719` + // Minimum execution time: 61_969_000 picoseconds. + Weight::from_parts(63_965_000, 3719) .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`) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, 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) @@ -1166,10 +1213,10 @@ impl WeightInfo for () { /// 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` + // Measured: `901` // Estimated: `4764` - // Minimum execution time: 72_783_000 picoseconds. - Weight::from_parts(75_841_000, 4764) + // Minimum execution time: 65_462_000 picoseconds. + Weight::from_parts(67_250_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } -- GitLab From 0f7ffc66a59526968c5cad39edf63bb54ca11585 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 28 Nov 2023 12:14:50 +0300 Subject: [PATCH 594/633] Added NetworkId::PolkadotBulletin variant (#2517) We're going to bridge Polkadot Bridge Hub with [Polkadot Bulletin chain](https://github.com/zdave-parity/polkadot-bulletin-chain) soon (and Rococo Bridge Hub with 1:1 copy of Polkadot Bulletin chain even sooner), so we need a variant for that chain in `NetworkId`. As suggested, I'm adding a new variant for it to the `NetworkId` (we may have used `ByGenesis(_)`, but decision was made to have a dedicated variant for that). --- polkadot/xcm/src/v3/junction.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index 47429a8c36e..5e6e4ab903b 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -75,6 +75,8 @@ pub enum NetworkId { BitcoinCore, /// The Bitcoin network, including hard-forks supported by Bitcoin Cash developers. BitcoinCash, + /// The Polkadot Bulletin chain. + PolkadotBulletin, } impl From for Option { -- GitLab From 58a1f9c53dbf8766bd703b4fd417a9ca1ab99df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:18:26 +0000 Subject: [PATCH 595/633] polkadot: disable block authoring backoff on production networks (#2510) Currently the polkadot node will backoff from block authoring if finality starts lagging. This PR disables this mechanism on production networks (polkadot and kusama) and adds a flags to optionally force enabling it. --- .../relay-chain-inprocess-interface/src/lib.rs | 1 + polkadot/cli/src/cli.rs | 4 ++++ polkadot/cli/src/command.rs | 1 + polkadot/node/service/src/lib.rs | 18 ++++++++++++++---- polkadot/node/test/service/src/lib.rs | 1 + .../test-parachains/adder/collator/src/main.rs | 1 + .../undying/collator/src/main.rs | 1 + 7 files changed, 23 insertions(+), 4 deletions(-) diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 42a56b649f0..3d297af00f2 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -286,6 +286,7 @@ fn build_polkadot_full_node( grandpa_pause: None, // Disable BEEFY. It should not be required by the internal relay chain node. enable_beefy: false, + force_authoring_backoff: false, jaeger_agent: None, telemetry_worker_handle, diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index e20e35c9103..6a7a8b4ad7b 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -98,6 +98,10 @@ pub struct RunCmd { #[arg(long)] pub no_beefy: bool, + /// Enable the block authoring backoff that is triggered when finality is lagging. + #[arg(long)] + pub force_authoring_backoff: bool, + /// Add the destination address to the 'Jaeger' agent. /// /// Must be valid socket address, of format `IP:Port` (commonly `127.0.0.1:6831`). diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 2dcf5e0e8d7..c9c3c39aab1 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -259,6 +259,7 @@ where is_parachain_node: service::IsParachainNode::No, grandpa_pause, enable_beefy, + force_authoring_backoff: cli.run.force_authoring_backoff, jaeger_agent, telemetry_worker_handle: None, node_version, diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index c03835b2a4b..fafdc586009 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -625,6 +625,9 @@ pub struct NewFullParams { pub is_parachain_node: IsParachainNode, pub grandpa_pause: Option<(u32, u32)>, pub enable_beefy: bool, + /// Whether to enable the block authoring backoff on production networks + /// where it isn't enabled by default. + pub force_authoring_backoff: bool, pub jaeger_agent: Option, pub telemetry_worker_handle: Option, /// The version of the node. TESTING ONLY: `None` can be passed to skip the node/worker version @@ -716,6 +719,7 @@ pub fn new_full( is_parachain_node, grandpa_pause, enable_beefy, + force_authoring_backoff, jaeger_agent, telemetry_worker_handle, node_version, @@ -733,15 +737,21 @@ pub fn new_full( let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled; let role = config.role.clone(); let force_authoring = config.force_authoring; - let backoff_authoring_blocks = { + let backoff_authoring_blocks = if !force_authoring_backoff && + (config.chain_spec.is_polkadot() || config.chain_spec.is_kusama()) + { + // the block authoring backoff is disabled by default on production networks + None + } else { let mut backoff = sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default(); if config.chain_spec.is_rococo() || config.chain_spec.is_wococo() || - config.chain_spec.is_versi() + config.chain_spec.is_versi() || + config.chain_spec.is_dev() { - // it's a testnet that's in flux, finality has stalled sometimes due - // to operational issues and it's annoying to slow down block + // on testnets that are in flux (like rococo or versi), finality has stalled + // sometimes due to operational issues and it's annoying to slow down block // production to 1 block per hour. backoff.max_interval = 10; } diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index be2746daf32..a8352b60751 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -82,6 +82,7 @@ pub fn new_full( is_parachain_node, grandpa_pause: None, enable_beefy: true, + force_authoring_backoff: false, jaeger_agent: None, telemetry_worker_handle: None, node_version: None, diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index dfaa1973206..1558df6708d 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -64,6 +64,7 @@ fn main() -> Result<()> { ), grandpa_pause: None, enable_beefy: false, + force_authoring_backoff: false, jaeger_agent: None, telemetry_worker_handle: None, diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index c6b338a20dc..1db1b6f1102 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -84,6 +84,7 @@ fn main() -> Result<()> { ), grandpa_pause: None, enable_beefy: false, + force_authoring_backoff: false, jaeger_agent: None, telemetry_worker_handle: None, -- GitLab From 6dc3e6c909361c6643b8d91c2929c306de4aee4a Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 28 Nov 2023 14:02:48 +0400 Subject: [PATCH 596/633] Set `frame_system::LastRuntimeUpgrade` after running `try-runtime` migrations (#2515) Sets `frame_system::LastRuntimeUpgrade` after running try-runtime migrations to better emulate real behavior. This fixes an issue where migrations using the spec version to determine whether to execute can incorrectly fail idempotency checks. @s0me0ne-unkn0wn noticed this issue with the session key migration introduced in https://github.com/paritytech/polkadot-sdk/pull/2265. --- substrate/frame/executive/src/lib.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index dec1fe158bd..4eb76325bab 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -362,9 +362,13 @@ where Ok(frame_system::Pallet::::block_weight().total()) } - /// Execute all `OnRuntimeUpgrade` of this runtime. + /// Execute all Migrations of this runtime. /// /// The `checks` param determines whether to execute `pre/post_upgrade` and `try_state` hooks. + /// + /// [`frame_system::LastRuntimeUpgrade`] is set to the current runtime version after + /// migrations execute. This is important for idempotency checks, because some migrations use + /// this value to determine whether or not they should execute. pub fn try_runtime_upgrade(checks: UpgradeCheckSelect) -> Result { let before_all_weight = ::before_all_runtime_migrations(); @@ -372,6 +376,13 @@ where <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( checks.pre_and_post(), )?; + + frame_system::LastRuntimeUpgrade::::put( + frame_system::LastRuntimeUpgradeInfo::from( + >::get(), + ), + ); + // Nothing should modify the state after the migrations ran: let _guard = StorageNoopGuard::default(); -- GitLab From 6a417eb9c22f329f252bb48afe705fc43962817c Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Tue, 28 Nov 2023 15:02:10 +0400 Subject: [PATCH 597/633] Increase `cargo-check-each-crate-macos` timeout (#2519) --- .gitlab/pipeline/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 9c3fa7701c8..190249d2d0f 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -270,7 +270,7 @@ cargo-check-benches: SKIP_WASM_BUILD=1 time cargo check --locked --benches --all; cargo run --locked --release -p node-bench -- ::trie::read::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; - echo "___Uploading cache for rusty-cachier___"; + echo "___Cache could be uploaded___"; ;; 2) cargo run --locked --release -p node-bench -- ::node::import::sr25519::transfer_keep_alive::paritydb::small --json @@ -439,7 +439,7 @@ cargo-check-each-crate: - .run-immediately # - .collect-artifacts variables: - # $CI_JOB_NAME is set manually so that rusty-cachier can share the cache for all + # $CI_JOB_NAME is set manually so that cache could be shared for all jobs # "cargo-check-each-crate I/N" jobs CI_JOB_NAME: cargo-check-each-crate timeout: 2h @@ -462,10 +462,10 @@ cargo-check-each-crate-macos: variables: SKIP_WASM_BUILD: 1 script: - # TODO: enable rusty-cachier once it supports Mac # TODO: use parallel jobs, as per cargo-check-each-crate, once more Mac runners are available # - time ./scripts/ci/gitlab/check-each-crate.py 1 1 - time cargo check --workspace --locked + timeout: 2h tags: - osx @@ -488,7 +488,7 @@ cargo-hfuzz: # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr - # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling rusty-cachier's absolute CARGO_TARGET_DIR + # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling absolute CARGO_TARGET_DIR HFUZZ_BUILD_ARGS: > --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" -- GitLab From cd8741c8b591407a78fdfef1dccdd3b5d03e13f4 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:43:57 +0530 Subject: [PATCH 598/633] Moves all test runtimes to use `derive_impl` (#2409) Step in https://github.com/paritytech/polkadot-sdk/issues/171 This PR adds `derive_impl` on all `frame_system` config impls for mock runtimes. The overridden configs are maintained as of now to ensure minimal changes. --------- Co-authored-by: Oliver Tale-Yazdi --- cumulus/pallets/xcmp-queue/src/mock.rs | 3 +- cumulus/parachains/common/src/impls.rs | 3 +- .../pallets/collective-content/src/mock.rs | 3 +- .../runtimes/starters/seedling/src/lib.rs | 4 +- .../runtimes/starters/shell/src/lib.rs | 3 +- .../runtimes/testing/penpal/src/lib.rs | 3 +- .../testing/rococo-parachain/src/lib.rs | 3 +- .../runtime/common/src/assigned_slots/mod.rs | 4 +- polkadot/runtime/common/src/auctions.rs | 5 +- polkadot/runtime/common/src/claims.rs | 4 +- polkadot/runtime/common/src/crowdloan/mod.rs | 3 +- polkadot/runtime/common/src/impls.rs | 2 + .../runtime/common/src/integration_tests.rs | 3 +- .../runtime/common/src/paras_registrar/mod.rs | 3 +- polkadot/runtime/common/src/purchase.rs | 4 +- polkadot/runtime/common/src/slots/mod.rs | 4 +- polkadot/runtime/parachains/src/mock.rs | 3 +- .../src/fungible/mock.rs | 2 + .../pallet-xcm-benchmarks/src/generic/mock.rs | 1 + polkadot/xcm/pallet-xcm/src/mock.rs | 3 +- polkadot/xcm/procedural/tests/ui.rs | 2 +- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 3 +- .../xcm-simulator/example/src/parachain.rs | 3 +- .../xcm-simulator/example/src/relay_chain.rs | 3 +- .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 3 +- .../xcm-simulator/fuzzer/src/relay_chain.rs | 3 +- .../pallets/template/src/mock.rs | 6 +- .../src/chain_head/subscription/inner.rs | 2 +- substrate/frame/asset-conversion/src/mock.rs | 3 +- substrate/frame/asset-rate/src/mock.rs | 6 +- substrate/frame/assets/src/mock.rs | 3 +- substrate/frame/atomic-swap/src/tests.rs | 6 +- substrate/frame/aura/src/mock.rs | 3 +- .../frame/authority-discovery/src/lib.rs | 3 +- substrate/frame/balances/src/tests/mod.rs | 4 +- .../benchmarking/pov/src/benchmarking.rs | 2 + substrate/frame/benchmarking/pov/src/tests.rs | 2 + substrate/frame/benchmarking/src/baseline.rs | 2 + substrate/frame/benchmarking/src/tests.rs | 3 +- .../frame/benchmarking/src/tests_instance.rs | 3 +- substrate/frame/bounties/src/tests.rs | 3 +- substrate/frame/broker/src/mock.rs | 3 +- substrate/frame/child-bounties/src/tests.rs | 3 +- substrate/frame/collective/src/tests.rs | 4 +- .../contracts/mock-network/src/parachain.rs | 3 +- .../contracts/mock-network/src/relay_chain.rs | 3 +- substrate/frame/contracts/src/tests.rs | 3 + .../frame/conviction-voting/src/tests.rs | 3 +- substrate/frame/core-fellowship/src/tests.rs | 4 +- substrate/frame/democracy/src/tests.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 3 +- .../election-provider-support/src/onchain.rs | 3 +- substrate/frame/elections-phragmen/src/lib.rs | 3 +- substrate/frame/examples/basic/src/tests.rs | 3 +- .../frame/examples/dev-mode/src/tests.rs | 3 +- .../examples/offchain-worker/src/tests.rs | 3 +- substrate/frame/executive/src/lib.rs | 3 +- substrate/frame/glutton/src/mock.rs | 3 +- substrate/frame/grandpa/src/mock.rs | 3 +- substrate/frame/identity/src/tests.rs | 3 +- substrate/frame/im-online/src/mock.rs | 3 +- substrate/frame/indices/src/mock.rs | 6 +- .../src/lib.rs | 3 +- substrate/frame/lottery/src/mock.rs | 3 +- substrate/frame/membership/src/lib.rs | 3 +- .../message-queue/src/integration_test.rs | 3 +- substrate/frame/message-queue/src/mock.rs | 4 +- .../frame/nft-fractionalization/src/mock.rs | 4 +- substrate/frame/nfts/src/mock.rs | 3 +- substrate/frame/nicks/src/lib.rs | 3 +- substrate/frame/nis/src/mock.rs | 3 +- .../frame/node-authorization/src/mock.rs | 3 +- .../nomination-pools/benchmarking/src/mock.rs | 3 +- substrate/frame/nomination-pools/src/mock.rs | 3 +- .../nomination-pools/test-staking/src/mock.rs | 3 +- .../frame/offences/benchmarking/src/mock.rs | 3 +- substrate/frame/offences/src/mock.rs | 3 +- substrate/frame/paged-list/src/mock.rs | 6 +- substrate/frame/preimage/src/mock.rs | 3 +- .../frame/ranked-collective/src/tests.rs | 3 +- substrate/frame/recovery/src/mock.rs | 3 +- substrate/frame/referenda/src/mock.rs | 3 +- substrate/frame/remark/src/mock.rs | 6 +- substrate/frame/root-offences/src/mock.rs | 3 +- substrate/frame/safe-mode/src/mock.rs | 3 +- substrate/frame/salary/src/tests.rs | 4 +- substrate/frame/scored-pool/src/mock.rs | 3 +- .../frame/session/benchmarking/src/mock.rs | 3 +- substrate/frame/session/src/mock.rs | 3 +- substrate/frame/society/src/mock.rs | 3 +- substrate/frame/staking/src/mock.rs | 3 +- .../frame/state-trie-migration/src/lib.rs | 3 +- substrate/frame/statement/src/mock.rs | 3 +- substrate/frame/sudo/src/mock.rs | 6 +- .../number_of_pallets_exceeds_tuple_size.rs | 3 +- ...umber_of_pallets_exceeds_tuple_size.stderr | 26 ++--- .../pallet_error_too_large.rs | 3 +- .../pallet_error_too_large.stderr | 18 ++-- .../undefined_call_part.rs | 3 +- .../undefined_call_part.stderr | 14 +-- .../undefined_event_part.rs | 3 +- .../undefined_event_part.stderr | 30 +++--- .../undefined_genesis_config_part.rs | 3 +- .../undefined_genesis_config_part.stderr | 30 +++--- .../undefined_inherent_part.rs | 3 +- .../undefined_inherent_part.stderr | 94 +++++++++---------- .../undefined_origin_part.rs | 3 +- .../undefined_origin_part.stderr | 30 +++--- .../undefined_validate_unsigned_part.rs | 3 +- .../undefined_validate_unsigned_part.stderr | 58 ++++++------ substrate/frame/support/test/tests/pallet.rs | 3 +- .../support/test/tests/pallet_instance.rs | 2 + .../tests/pallet_ui/pass/dev_mode_valid.rs | 3 +- .../pallet_ui/pass/no_std_genesis_config.rs | 3 +- .../support/test/tests/runtime_metadata.rs | 3 +- .../support/test/tests/storage_layers.rs | 5 +- substrate/frame/system/benches/bench.rs | 7 +- .../frame/system/benchmarking/src/mock.rs | 2 + substrate/frame/timestamp/src/mock.rs | 3 +- substrate/frame/tips/src/tests.rs | 4 +- .../asset-conversion-tx-payment/src/mock.rs | 2 + .../asset-tx-payment/src/mock.rs | 2 + .../frame/transaction-payment/src/mock.rs | 2 + substrate/frame/treasury/src/tests.rs | 3 +- substrate/frame/tx-pause/src/mock.rs | 3 +- substrate/frame/uniques/src/mock.rs | 3 +- substrate/frame/utility/src/tests.rs | 3 +- substrate/frame/vesting/src/mock.rs | 3 +- substrate/frame/whitelist/src/mock.rs | 3 +- substrate/utils/frame/rpc/support/src/lib.rs | 3 +- 130 files changed, 433 insertions(+), 261 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 7c3a3bd1bd0..755b685d5b8 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -19,7 +19,7 @@ use core::marker::PhantomData; use cumulus_pallet_parachain_system::AnyRelayNumber; use cumulus_primitives_core::{ChannelInfo, IsSystem, ParaId}; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, Everything, Nothing, OriginTrait}, BoundedSlice, }; @@ -55,6 +55,7 @@ parameter_types! { type AccountId = u64; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 81d78baba54..50cb1c7f3e8 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -122,7 +122,7 @@ impl> ContainsPair for AssetsFr mod tests { use super::*; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, FindAuthor, ValidatorRegistration}, PalletId, }; @@ -155,6 +155,7 @@ mod tests { pub const MaxReserves: u32 = 50; } + #[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; diff --git a/cumulus/parachains/pallets/collective-content/src/mock.rs b/cumulus/parachains/pallets/collective-content/src/mock.rs index 2ae5943f332..7a752da71fc 100644 --- a/cumulus/parachains/pallets/collective-content/src/mock.rs +++ b/cumulus/parachains/pallets/collective-content/src/mock.rs @@ -18,7 +18,7 @@ pub use crate as pallet_collective_content; use crate::WeightInfo; use frame_support::{ - ord_parameter_types, parameter_types, + derive_impl, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64}, weights::Weight, }; @@ -55,6 +55,7 @@ impl pallet_collective_content::Config for Test { type WeightInfo = CCWeightInfo; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = (); type BlockWeights = (); diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 7619ed19798..cb868627e79 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -44,7 +44,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, @@ -134,6 +134,8 @@ parameter_types! { .build_or_panic(); pub const SS58Prefix: u8 = 42; } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index f67c0c19ec6..de95969f71d 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -52,7 +52,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, @@ -143,6 +143,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index b2a04272a4a..9387c454715 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -35,7 +35,7 @@ pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, pallet_prelude::Weight, @@ -323,6 +323,7 @@ parameter_types! { // Configure FRAME pallets to include in runtime. +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 3a890d7953a..9d2ba98a67c 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -39,7 +39,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, match_types, parameter_types, @@ -184,6 +184,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index cb2e5083b0a..f5e3aaef632 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -636,7 +636,7 @@ mod tests { use crate::{assigned_slots, mock::TestRegistrar, slots}; use ::test_helpers::{dummy_head_data, dummy_validation_code}; - use frame_support::{assert_noop, assert_ok, parameter_types}; + use frame_support::{assert_noop, assert_ok, derive_impl, parameter_types}; use frame_system::EnsureRoot; use pallet_balances; use primitives::BlockNumber; @@ -679,6 +679,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u32 = 250; } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index 267413eb1ba..baa66d83a3f 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -677,7 +677,8 @@ mod tests { use crate::{auctions, mock::TestRegistrar}; use ::test_helpers::{dummy_hash, dummy_head_data, dummy_validation_code}; use frame_support::{ - assert_noop, assert_ok, assert_storage_noop, ord_parameter_types, parameter_types, + assert_noop, assert_ok, assert_storage_noop, derive_impl, ord_parameter_types, + parameter_types, traits::{ConstU32, EitherOfDiverse, OnFinalize, OnInitialize}, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -705,6 +706,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u32 = 250; } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 548adc6fbd5..4f04a79be55 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -710,7 +710,7 @@ mod tests { use crate::claims; use claims::Call as ClaimsCall; use frame_support::{ - assert_err, assert_noop, assert_ok, + assert_err, assert_noop, assert_ok, derive_impl, dispatch::{GetDispatchInfo, Pays}, ord_parameter_types, parameter_types, traits::{ConstU32, ExistenceRequirement, WithdrawReasons}, @@ -739,6 +739,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u32 = 250; } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index f67fc12a67f..77ef406e579 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -863,7 +863,7 @@ mod tests { use super::*; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{ConstU32, OnFinalize, OnInitialize}, }; use primitives::Id as ParaId; @@ -900,6 +900,7 @@ mod tests { type BlockNumber = u64; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index e50ffb634b3..60e631a03ee 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -192,6 +192,7 @@ pub mod benchmarks { mod tests { use super::*; use frame_support::{ + derive_impl, dispatch::DispatchClass, parameter_types, traits::{ @@ -237,6 +238,7 @@ mod tests { pub const AvailableBlockRatio: Perbill = Perbill::one(); } + #[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; diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 793f75e79cd..b0d277a702d 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -25,7 +25,7 @@ use crate::{ traits::{AuctionStatus, Auctioneer, Leaser, Registrar as RegistrarT}, }; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{ConstU32, Currency, OnFinalize, OnInitialize}, weights::Weight, PalletId, @@ -114,6 +114,7 @@ parameter_types! { ); } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 2d33cf28993..12376ae6f1f 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -699,7 +699,7 @@ mod tests { mock::conclude_pvf_checking, paras_registrar, traits::Registrar as RegistrarTrait, }; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, derive_impl, error::BadOrigin, parameter_types, traits::{ConstU32, OnFinalize, OnInitialize}, @@ -751,6 +751,7 @@ mod tests { limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO); } + #[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; diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index bc95483dd7e..06b0a0a0211 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -484,7 +484,7 @@ mod tests { // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use crate::purchase; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{Currency, WithdrawReasons}, }; use sp_runtime::{ @@ -511,6 +511,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u32 = 250; } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/slots/mod.rs b/polkadot/runtime/common/src/slots/mod.rs index 01f6365b791..c3aaf8b51b8 100644 --- a/polkadot/runtime/common/src/slots/mod.rs +++ b/polkadot/runtime/common/src/slots/mod.rs @@ -505,7 +505,7 @@ mod tests { use crate::{mock::TestRegistrar, slots}; use ::test_helpers::{dummy_head_data, dummy_validation_code}; - use frame_support::{assert_noop, assert_ok, parameter_types}; + use frame_support::{assert_noop, assert_ok, derive_impl, parameter_types}; use frame_system::EnsureRoot; use pallet_balances; use primitives::BlockNumber; @@ -529,6 +529,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u32 = 250; } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 9df54bf29d3..222942922f9 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -25,7 +25,7 @@ use crate::{ }; use frame_support::{ - assert_ok, parameter_types, + assert_ok, derive_impl, parameter_types, traits::{ Currency, ProcessMessage, ProcessMessageError, ValidatorSet, ValidatorSetWithIdentification, }, @@ -94,6 +94,7 @@ parameter_types! { pub type AccountId = u64; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index 9adc706fc18..4d566fd585d 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -45,6 +45,8 @@ parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index 710ff0d8019..6efd2304e28 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -51,6 +51,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 0b0f795100c..606d51bb8bc 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -16,7 +16,7 @@ use codec::Encode; use frame_support::{ - construct_runtime, match_types, parameter_types, + construct_runtime, derive_impl, match_types, parameter_types, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Equals, Everything, EverythingBut, Nothing, @@ -246,6 +246,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/procedural/tests/ui.rs b/polkadot/xcm/procedural/tests/ui.rs index a30f4d7dee5..b3469b520eb 100644 --- a/polkadot/xcm/procedural/tests/ui.rs +++ b/polkadot/xcm/procedural/tests/ui.rs @@ -21,7 +21,7 @@ fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. if std::env::var("RUN_UI_TESTS").is_err() { - return; + return } // As trybuild is using `cargo check`, we don't need the real WASM binaries. diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 4f183c7a15b..968b294c6a4 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{ConstU32, Everything, Nothing}, weights::Weight, }; @@ -76,6 +76,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index 9f0411970ce..951e946372d 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -19,7 +19,7 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing}, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; @@ -63,6 +63,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index bdd7ff6d3ea..20070d192b5 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -17,7 +17,7 @@ //! Relay chain runtime mock. use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, Everything, Nothing, ProcessMessage, ProcessMessageError}, weights::{Weight, WeightMeter}, }; @@ -49,6 +49,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 41234837aca..0aa1b54f5e7 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode}; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{Everything, Nothing}, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; @@ -52,6 +52,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index c9a57db970a..085773f3073 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -17,7 +17,7 @@ //! Relay chain runtime mock. use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, weights::{Weight, WeightMeter}, }; @@ -48,6 +48,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/substrate/bin/node-template/pallets/template/src/mock.rs b/substrate/bin/node-template/pallets/template/src/mock.rs index 244ae1b3785..8346461e6ed 100644 --- a/substrate/bin/node-template/pallets/template/src/mock.rs +++ b/substrate/bin/node-template/pallets/template/src/mock.rs @@ -1,5 +1,8 @@ use crate as pallet_template; -use frame_support::traits::{ConstU16, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU16, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -17,6 +20,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index abd42ad9678..2b250f3dc2c 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -763,7 +763,7 @@ impl> SubscriptionsInner { // blocks. for hash in hashes.clone() { if !sub.contains_block(hash) { - return Err(SubscriptionManagementError::BlockHashAbsent); + return Err(SubscriptionManagementError::BlockHashAbsent) } } diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 4eee701f193..c84263b0796 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_asset_conversion; use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, instances::{Instance1, Instance2}, ord_parameter_types, parameter_types, traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64}, @@ -48,6 +48,7 @@ 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 = (); diff --git a/substrate/frame/asset-rate/src/mock.rs b/substrate/frame/asset-rate/src/mock.rs index 9ca0f0f3cc3..041f3740952 100644 --- a/substrate/frame/asset-rate/src/mock.rs +++ b/substrate/frame/asset-rate/src/mock.rs @@ -18,7 +18,10 @@ //! The crate's mock. use crate as pallet_asset_rate; -use frame_support::traits::{ConstU16, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU16, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -36,6 +39,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/assets/src/mock.rs b/substrate/frame/assets/src/mock.rs index 2c2203bcdad..a4d85b64922 100644 --- a/substrate/frame/assets/src/mock.rs +++ b/substrate/frame/assets/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_assets; use codec::Encode; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; @@ -46,6 +46,7 @@ construct_runtime!( type AccountId = u64; type AssetId = u32; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index 92eb9a04458..7e2f22b1836 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_atomic_swap; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -38,6 +41,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/aura/src/mock.rs b/substrate/frame/aura/src/mock.rs index 39b798c2f68..14b87089ce3 100644 --- a/substrate/frame/aura/src/mock.rs +++ b/substrate/frame/aura/src/mock.rs @@ -21,7 +21,7 @@ use crate as pallet_aura; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, DisabledValidators}, }; use sp_consensus_aura::{ed25519::AuthorityId, AuthorityIndex}; @@ -41,6 +41,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/authority-discovery/src/lib.rs b/substrate/frame/authority-discovery/src/lib.rs index 87b743ae196..3044b41e31d 100644 --- a/substrate/frame/authority-discovery/src/lib.rs +++ b/substrate/frame/authority-discovery/src/lib.rs @@ -169,7 +169,7 @@ mod tests { use super::*; use crate as pallet_authority_discovery; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_application_crypto::Pair; @@ -225,6 +225,7 @@ mod tests { pub const Offset: BlockNumber = 0; } + #[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 = (); diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index dd3e5b7a85a..8e834483cbe 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -22,7 +22,7 @@ use crate::{self as pallet_balances, AccountData, Config, CreditOf, Error, Pallet}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - assert_err, assert_noop, assert_ok, assert_storage_noop, + assert_err, assert_noop, assert_ok, assert_storage_noop, derive_impl, dispatch::{DispatchInfo, GetDispatchInfo}, parameter_types, traits::{ @@ -90,6 +90,8 @@ parameter_types! { ); pub static ExistentialDeposit: u64 = 1; } + +#[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; diff --git a/substrate/frame/benchmarking/pov/src/benchmarking.rs b/substrate/frame/benchmarking/pov/src/benchmarking.rs index 473947b171a..a24b772ade0 100644 --- a/substrate/frame/benchmarking/pov/src/benchmarking.rs +++ b/substrate/frame/benchmarking/pov/src/benchmarking.rs @@ -339,6 +339,7 @@ frame_benchmarking::benchmarks! { #[cfg(test)] mod mock { + use frame_support::derive_impl; use sp_runtime::{testing::H256, BuildStorage}; type AccountId = u64; @@ -354,6 +355,7 @@ mod mock { } ); + #[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 = (); diff --git a/substrate/frame/benchmarking/pov/src/tests.rs b/substrate/frame/benchmarking/pov/src/tests.rs index f09e37a5288..dda29c071de 100644 --- a/substrate/frame/benchmarking/pov/src/tests.rs +++ b/substrate/frame/benchmarking/pov/src/tests.rs @@ -162,6 +162,7 @@ fn noop_is_free() { } mod mock { + use frame_support::derive_impl; use sp_runtime::testing::H256; type Block = frame_system::mocking::MockBlock; @@ -174,6 +175,7 @@ mod mock { } ); + #[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 = (); diff --git a/substrate/frame/benchmarking/src/baseline.rs b/substrate/frame/benchmarking/src/baseline.rs index 6cd23ebe028..6451284e012 100644 --- a/substrate/frame/benchmarking/src/baseline.rs +++ b/substrate/frame/benchmarking/src/baseline.rs @@ -110,6 +110,7 @@ benchmarks! { #[cfg(test)] pub mod mock { + use frame_support::derive_impl; use sp_runtime::{testing::H256, BuildStorage}; type AccountId = u64; @@ -124,6 +125,7 @@ pub mod mock { } ); + #[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 = (); diff --git a/substrate/frame/benchmarking/src/tests.rs b/substrate/frame/benchmarking/src/tests.rs index e5bacbdb236..7d6cfaad609 100644 --- a/substrate/frame/benchmarking/src/tests.rs +++ b/substrate/frame/benchmarking/src/tests.rs @@ -19,7 +19,7 @@ #![cfg(test)] -use frame_support::{parameter_types, traits::ConstU32}; +use frame_support::{derive_impl, parameter_types, traits::ConstU32}; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, IdentityLookup}, @@ -75,6 +75,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/benchmarking/src/tests_instance.rs b/substrate/frame/benchmarking/src/tests_instance.rs index f2c721c8114..55010840896 100644 --- a/substrate/frame/benchmarking/src/tests_instance.rs +++ b/substrate/frame/benchmarking/src/tests_instance.rs @@ -19,7 +19,7 @@ #![cfg(test)] -use frame_support::traits::ConstU32; +use frame_support::{derive_impl, traits::ConstU32}; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, IdentityLookup}, @@ -85,6 +85,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 233e41b474c..22e608cce63 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -23,7 +23,7 @@ use super::*; use crate as pallet_bounties; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{ tokens::{PayFromAccount, UnityAssetBalanceConversion}, ConstU32, ConstU64, OnInitialize, @@ -59,6 +59,7 @@ parameter_types! { type Balance = u64; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/broker/src/mock.rs b/substrate/frame/broker/src/mock.rs index cab6b7389c0..8b8cfa55abc 100644 --- a/substrate/frame/broker/src/mock.rs +++ b/substrate/frame/broker/src/mock.rs @@ -19,7 +19,7 @@ use crate::{test_fungibles::TestFungibles, *}; use frame_support::{ - assert_ok, ensure, ord_parameter_types, parameter_types, + assert_ok, derive_impl, ensure, ord_parameter_types, parameter_types, traits::{ fungible::{Balanced, Credit, Inspect, ItemOf, Mutate}, nonfungible::Inspect as NftInspect, @@ -47,6 +47,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 46f8fa65dd3..7de45c73127 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -23,7 +23,7 @@ use super::*; use crate as pallet_child_bounties; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{ tokens::{PayFromAccount, UnityAssetBalanceConversion}, ConstU32, ConstU64, OnInitialize, @@ -62,6 +62,7 @@ parameter_types! { type Balance = u64; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index 86b85e07a8b..06a91cf6fe9 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -18,7 +18,7 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, derive_impl, dispatch::Pays, parameter_types, traits::{ConstU32, ConstU64, StorageVersion}, @@ -90,6 +90,8 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::MAX); pub static MaxProposalWeight: Weight = default_max_proposal_weight(); } + +#[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; diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 1465b02f903..2ef579276ae 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -23,7 +23,7 @@ use crate::{ }; use core::marker::PhantomData; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, EverythingBut, Nothing}, weights::{ constants::{WEIGHT_PROOF_SIZE_PER_MB, WEIGHT_REF_TIME_PER_SECOND}, @@ -53,6 +53,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index c59c8e4bfa8..17e36eada25 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -17,7 +17,7 @@ //! Relay chain runtime mock. use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{Contains, Everything, Nothing}, weights::Weight, }; @@ -47,6 +47,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 76fd012852a..79ad451964d 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -42,6 +42,7 @@ use assert_matches::assert_matches; use codec::Encode; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_err_with_weight, assert_noop, assert_ok, + derive_impl, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, storage::child, @@ -332,6 +333,8 @@ parameter_types! { ); pub static ExistentialDeposit: u64 = 1; } + +#[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; diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index 850b98b218b..371d0364384 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -20,7 +20,7 @@ use std::collections::BTreeMap; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{ConstU32, ConstU64, Contains, Polling, VoteTally}, }; use sp_core::H256; @@ -51,6 +51,7 @@ impl Contains for BaseFilter { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = (); diff --git a/substrate/frame/core-fellowship/src/tests.rs b/substrate/frame/core-fellowship/src/tests.rs index a02c010718c..9ac381ab7f5 100644 --- a/substrate/frame/core-fellowship/src/tests.rs +++ b/substrate/frame/core-fellowship/src/tests.rs @@ -20,7 +20,7 @@ use std::collections::BTreeMap; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, pallet_prelude::Weight, parameter_types, traits::{tokens::GetSalary, ConstU32, ConstU64, Everything, IsInVec, TryMapSuccess}, @@ -50,6 +50,8 @@ parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, u64::max_value())); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index 07a0ef5c3d5..00d8fedca0c 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use crate as pallet_democracy; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, SortedMembers, StorePreimage, @@ -77,6 +77,8 @@ parameter_types! { Weight::from_parts(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), ); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = BlockWeights; diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 92144351e8f..15a50165ff3 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -21,7 +21,7 @@ use frame_election_provider_support::{ bounds::{DataProviderBounds, ElectionBounds}, data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, }; -pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; +pub use frame_support::{assert_noop, assert_ok, derive_impl, pallet_prelude::GetDefault}; use frame_support::{ parameter_types, traits::{ConstU32, Hooks}, @@ -204,6 +204,7 @@ pub fn witness() -> SolutionOrSnapshotSize { .unwrap_or_default() } +#[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; diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 8ac245a360b..412aac45475 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -182,7 +182,7 @@ impl ElectionProvider for OnChainExecution { mod tests { use super::*; use crate::{ElectionProvider, PhragMMS, SequentialPhragmen}; - use frame_support::{assert_noop, parameter_types}; + use frame_support::{assert_noop, derive_impl, parameter_types}; use sp_npos_elections::Support; use sp_runtime::Perbill; type AccountId = u64; @@ -200,6 +200,7 @@ mod tests { } ); + #[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; diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index e4c56e68f9a..5e50027e344 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -1307,7 +1307,7 @@ mod tests { use super::*; use crate as elections_phragmen; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, derive_impl, dispatch::DispatchResultWithPostInfo, parameter_types, traits::{ConstU32, ConstU64, OnInitialize}, @@ -1321,6 +1321,7 @@ mod tests { }; use substrate_test_utils::assert_eq_uvec; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index c7b5b9e9a84..e00b1ac01b3 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -19,7 +19,7 @@ use crate::*; use frame_support::{ - assert_ok, + assert_ok, derive_impl, dispatch::{DispatchInfo, GetDispatchInfo}, traits::{ConstU64, OnInitialize}, }; @@ -45,6 +45,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/dev-mode/src/tests.rs b/substrate/frame/examples/dev-mode/src/tests.rs index c7722bc0524..3acedcd0fd1 100644 --- a/substrate/frame/examples/dev-mode/src/tests.rs +++ b/substrate/frame/examples/dev-mode/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for pallet-dev-mode. use crate::*; -use frame_support::{assert_ok, traits::ConstU64}; +use frame_support::{assert_ok, derive_impl, traits::ConstU64}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -39,6 +39,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index 203a59a8af0..48a8d86588c 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -19,7 +19,7 @@ use crate as example_offchain_worker; use crate::*; use codec::Decode; use frame_support::{ - assert_ok, parameter_types, + assert_ok, derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_core::{ @@ -46,6 +46,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 4eb76325bab..b351819f612 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -761,7 +761,7 @@ mod tests { }; use frame_support::{ - assert_err, parameter_types, + assert_err, derive_impl, parameter_types, traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; @@ -917,6 +917,7 @@ mod tests { write: 100, }; } + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/substrate/frame/glutton/src/mock.rs b/substrate/frame/glutton/src/mock.rs index 4bc40b54788..31b78efc574 100644 --- a/substrate/frame/glutton/src/mock.rs +++ b/substrate/frame/glutton/src/mock.rs @@ -19,7 +19,7 @@ use super::*; use crate as pallet_glutton; use frame_support::{ - assert_ok, + assert_ok, derive_impl, traits::{ConstU32, ConstU64}, }; use sp_core::H256; @@ -38,6 +38,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 9afcec1c797..4766d5c3780 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -27,7 +27,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU128, ConstU32, ConstU64, KeyOwnerProofSystem, OnFinalize, OnInitialize}, }; use pallet_session::historical as pallet_session_historical; @@ -66,6 +66,7 @@ impl_opaque_keys! { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 78074df933a..8ac7b4d66cb 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -25,7 +25,7 @@ use crate::{ use codec::{Decode, Encode}; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64, EitherOfDiverse, Get}, BoundedVec, }; @@ -47,6 +47,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs index 85da061fe90..2f4e3922026 100644 --- a/substrate/frame/im-online/src/mock.rs +++ b/substrate/frame/im-online/src/mock.rs @@ -20,7 +20,7 @@ #![cfg(test)] use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, weights::Weight, }; @@ -113,6 +113,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { result } +#[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 = (); diff --git a/substrate/frame/indices/src/mock.rs b/substrate/frame/indices/src/mock.rs index 7dc6730d34e..913a37fe55b 100644 --- a/substrate/frame/indices/src/mock.rs +++ b/substrate/frame/indices/src/mock.rs @@ -20,7 +20,10 @@ #![cfg(test)] use crate::{self as pallet_indices, Config}; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::BuildStorage; @@ -35,6 +38,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs index 474087777c4..c7ed22d1dd5 100644 --- a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs +++ b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs @@ -169,7 +169,7 @@ mod tests { }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, OnInitialize, Randomness}, }; use frame_system::limits; @@ -189,6 +189,7 @@ mod tests { ::max(2 * 1024); } + #[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 = (); diff --git a/substrate/frame/lottery/src/mock.rs b/substrate/frame/lottery/src/mock.rs index e50ec3441b2..6e50529619b 100644 --- a/substrate/frame/lottery/src/mock.rs +++ b/substrate/frame/lottery/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_lottery; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, }; use frame_support_test::TestRandomness; @@ -47,6 +47,7 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } +#[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 = (); diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index 6fb61f0e491..2f4bf4bc4ff 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -531,7 +531,7 @@ mod tests { }; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64, StorageVersion}, }; use frame_system::EnsureSignedBy; @@ -551,6 +551,7 @@ mod tests { pub static Prime: Option = None; } + #[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 = (); diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index 965b96a99ca..53dc204ab9c 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -38,7 +38,7 @@ use crate::{ use crate as pallet_message_queue; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use rand::{rngs::StdRng, Rng, SeedableRng}; @@ -57,6 +57,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index 55a64574354..97246900597 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -24,7 +24,7 @@ use super::*; use crate as pallet_message_queue; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_core::H256; @@ -43,6 +43,8 @@ frame_support::construct_runtime!( MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, } ); + +#[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 = (); diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index 987c65a8954..855109adcbe 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_nft_fractionalization; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, BoundedVec, PalletId, }; @@ -49,6 +49,8 @@ construct_runtime!( Nfts: pallet_nfts, } ); + +#[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 = (); diff --git a/substrate/frame/nfts/src/mock.rs b/substrate/frame/nfts/src/mock.rs index 248522aafff..4363eccc7ff 100644 --- a/substrate/frame/nfts/src/mock.rs +++ b/substrate/frame/nfts/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_nfts; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; @@ -46,6 +46,7 @@ pub type Signature = MultiSignature; pub type AccountPublic = ::Signer; pub type AccountId = ::AccountId; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/nicks/src/lib.rs b/substrate/frame/nicks/src/lib.rs index ad30c628adf..540777f87ca 100644 --- a/substrate/frame/nicks/src/lib.rs +++ b/substrate/frame/nicks/src/lib.rs @@ -253,7 +253,7 @@ mod tests { use crate as pallet_nicks; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; @@ -274,6 +274,7 @@ mod tests { } ); + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/nis/src/mock.rs b/substrate/frame/nis/src/mock.rs index 30f7ef95f33..be6e79ac6f6 100644 --- a/substrate/frame/nis/src/mock.rs +++ b/substrate/frame/nis/src/mock.rs @@ -20,7 +20,7 @@ use crate::{self as pallet_nis, Perquintill, WithMaximumOf}; use frame_support::{ - ord_parameter_types, parameter_types, + derive_impl, ord_parameter_types, parameter_types, traits::{ fungible::Inspect, ConstU16, ConstU32, ConstU64, Everything, OnFinalize, OnInitialize, StorageMapShim, @@ -50,6 +50,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/node-authorization/src/mock.rs b/substrate/frame/node-authorization/src/mock.rs index 84e3336b3bd..3c99d41b89e 100644 --- a/substrate/frame/node-authorization/src/mock.rs +++ b/substrate/frame/node-authorization/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_node_authorization; use frame_support::{ - ord_parameter_types, + derive_impl, ord_parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; @@ -43,6 +43,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type DbWeight = (); diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 9a7f2197a7b..095df219dc8 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -17,7 +17,7 @@ use crate::VoterBagsListInstance; use frame_election_provider_support::VoteWeight; -use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; +use frame_support::{derive_impl, pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; use sp_runtime::{ traits::{Convert, IdentityLookup}, BuildStorage, FixedU128, Perbill, @@ -28,6 +28,7 @@ type Nonce = u32; type BlockNumber = u64; type Balance = u128; +#[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 = (); diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 24bea0b87f2..1bd969230da 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -17,7 +17,7 @@ use super::*; use crate::{self as pools}; -use frame_support::{assert_ok, parameter_types, traits::fungible::Mutate, PalletId}; +use frame_support::{assert_ok, derive_impl, parameter_types, traits::fungible::Mutate, PalletId}; use frame_system::RawOrigin; use sp_runtime::{BuildStorage, FixedU128}; use sp_staking::{OnStakingUpdate, Stake}; @@ -209,6 +209,7 @@ impl sp_staking::StakingInterface 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; diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index 0db24e9c244..ee24b53db06 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -17,7 +17,7 @@ use frame_election_provider_support::VoteWeight; use frame_support::{ - assert_ok, + assert_ok, derive_impl, pallet_prelude::*, parameter_types, traits::{ConstU64, ConstU8}, @@ -38,6 +38,7 @@ pub(crate) type T = Runtime; pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; +#[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 = (); diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index 1a458ec90d5..62ce1990112 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -25,7 +25,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system as system; @@ -40,6 +40,7 @@ type AccountId = u64; type Nonce = u32; type Balance = u64; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/offences/src/mock.rs b/substrate/frame/offences/src/mock.rs index 990ceae5ac0..61f680f6db9 100644 --- a/substrate/frame/offences/src/mock.rs +++ b/substrate/frame/offences/src/mock.rs @@ -23,7 +23,7 @@ use crate as offences; use crate::Config; use codec::Encode; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, weights::{constants::RocksDbWeight, Weight}, }; @@ -75,6 +75,7 @@ frame_support::construct_runtime!( } ); +#[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 = (); diff --git a/substrate/frame/paged-list/src/mock.rs b/substrate/frame/paged-list/src/mock.rs index 390b4a8530d..37bdc4f157c 100644 --- a/substrate/frame/paged-list/src/mock.rs +++ b/substrate/frame/paged-list/src/mock.rs @@ -20,7 +20,10 @@ #![cfg(feature = "std")] use crate::{paged_list::StoragePagedListMeta, Config, ListPrefix}; -use frame_support::traits::{ConstU16, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU16, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -38,6 +41,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs index 0f966312d9e..357f088f5ba 100644 --- a/substrate/frame/preimage/src/mock.rs +++ b/substrate/frame/preimage/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_preimage; use frame_support::{ - ord_parameter_types, + derive_impl, ord_parameter_types, traits::{fungible::HoldConsideration, ConstU32, ConstU64, Everything}, weights::constants::RocksDbWeight, }; @@ -43,6 +43,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/ranked-collective/src/tests.rs b/substrate/frame/ranked-collective/src/tests.rs index ba8c5a0f937..3a557065160 100644 --- a/substrate/frame/ranked-collective/src/tests.rs +++ b/substrate/frame/ranked-collective/src/tests.rs @@ -20,7 +20,7 @@ use std::collections::BTreeMap; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, derive_impl, error::BadOrigin, parameter_types, traits::{ConstU16, ConstU32, ConstU64, EitherOf, Everything, MapSuccess, Polling}, @@ -45,6 +45,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/recovery/src/mock.rs b/substrate/frame/recovery/src/mock.rs index bc81d07bec2..44cbeec0986 100644 --- a/substrate/frame/recovery/src/mock.rs +++ b/substrate/frame/recovery/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as recovery; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, }; use sp_core::H256; @@ -41,6 +41,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index 345accbe268..b75558723e9 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_referenda; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - assert_ok, ord_parameter_types, parameter_types, + assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, SortedMembers, @@ -59,6 +59,7 @@ impl Contains for BaseFilter { parameter_types! { pub MaxWeight: Weight = Weight::from_parts(2_000_000_000_000, u64::MAX); } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = (); diff --git a/substrate/frame/remark/src/mock.rs b/substrate/frame/remark/src/mock.rs index e597a1ca4df..0a385c30eac 100644 --- a/substrate/frame/remark/src/mock.rs +++ b/substrate/frame/remark/src/mock.rs @@ -18,7 +18,10 @@ //! Test environment for remarks pallet. use crate as pallet_remark; -use frame_support::traits::{ConstU16, ConstU32, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU16, ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -36,6 +39,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 82da429e00a..5e04e9abc13 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -23,7 +23,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, Hooks, OneSessionHandler}, }; use pallet_staking::StakerStatus; @@ -84,6 +84,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { type Public = UintAuthorityId; } +#[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 = (); diff --git a/substrate/frame/safe-mode/src/mock.rs b/substrate/frame/safe-mode/src/mock.rs index 10afe5bd4b5..7574d64d59d 100644 --- a/substrate/frame/safe-mode/src/mock.rs +++ b/substrate/frame/safe-mode/src/mock.rs @@ -23,7 +23,7 @@ use super::*; use crate as pallet_safe_mode; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU64, Everything, InsideBoth, InstanceFilter, IsInVec, SafeModeNotify}, }; use frame_system::EnsureSignedBy; @@ -33,6 +33,7 @@ use sp_runtime::{ BuildStorage, }; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = InsideBoth; type BlockWeights = (); diff --git a/substrate/frame/salary/src/tests.rs b/substrate/frame/salary/src/tests.rs index 1136ea746f6..fbca1be1188 100644 --- a/substrate/frame/salary/src/tests.rs +++ b/substrate/frame/salary/src/tests.rs @@ -20,7 +20,7 @@ use std::collections::BTreeMap; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, derive_impl, pallet_prelude::Weight, parameter_types, traits::{tokens::ConvertRank, ConstU32, ConstU64, Everything}, @@ -49,6 +49,8 @@ parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, 0)); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/scored-pool/src/mock.rs b/substrate/frame/scored-pool/src/mock.rs index 32a66c0cdc5..6c032ab808c 100644 --- a/substrate/frame/scored-pool/src/mock.rs +++ b/substrate/frame/scored-pool/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_scored_pool; use frame_support::{ - construct_runtime, ord_parameter_types, parameter_types, + construct_runtime, derive_impl, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; @@ -51,6 +51,7 @@ ord_parameter_types! { pub const ScoreOrigin: u64 = 3; } +#[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 = (); diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 47c337569a0..5c00d4bb491 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -24,7 +24,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_runtime::{traits::IdentityLookup, BuildStorage}; @@ -45,6 +45,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/session/src/mock.rs b/substrate/frame/session/src/mock.rs index 2db54e1a597..f3f18fde168 100644 --- a/substrate/frame/session/src/mock.rs +++ b/substrate/frame/session/src/mock.rs @@ -35,7 +35,7 @@ use sp_staking::SessionIndex; use sp_state_machine::BasicExternalities; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; @@ -232,6 +232,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(t) } +#[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 = (); diff --git a/substrate/frame/society/src/mock.rs b/substrate/frame/society/src/mock.rs index 0bee08236f7..3e29d01ca8e 100644 --- a/substrate/frame/society/src/mock.rs +++ b/substrate/frame/society/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_society; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64}, }; use frame_support_test::TestRandomness; @@ -58,6 +58,7 @@ ord_parameter_types! { pub const MaxBids: u32 = 10; } +#[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 = (); diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 364d125792b..90b0ee0260d 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -23,7 +23,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, VoteWeight, }; use frame_support::{ - assert_ok, ord_parameter_types, parameter_types, + assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, OneSessionHandler, @@ -124,6 +124,7 @@ parameter_types! { pub static Offset: BlockNumber = 0; } +#[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 = (); diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index ac3996459cd..5330634ca07 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -1051,7 +1051,7 @@ mod mock { use super::*; use crate as pallet_state_trie_migration; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, Hooks}, weights::Weight, }; @@ -1081,6 +1081,7 @@ mod mock { pub const SS58Prefix: u8 = 42; } + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/statement/src/mock.rs b/substrate/frame/statement/src/mock.rs index 10a74e100df..192baa1f218 100644 --- a/substrate/frame/statement/src/mock.rs +++ b/substrate/frame/statement/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_statement; use frame_support::{ - ord_parameter_types, + derive_impl, ord_parameter_types, traits::{ConstU32, ConstU64, Everything}, weights::constants::RocksDbWeight, }; @@ -47,6 +47,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/sudo/src/mock.rs b/substrate/frame/sudo/src/mock.rs index 6f123b7c82b..878e9239080 100644 --- a/substrate/frame/sudo/src/mock.rs +++ b/substrate/frame/sudo/src/mock.rs @@ -19,7 +19,10 @@ use super::*; use crate as sudo; -use frame_support::traits::{ConstU32, Contains}; +use frame_support::{ + derive_impl, + traits::{ConstU32, Contains}, +}; use sp_core::{ConstU64, H256}; use sp_io; use sp_runtime::{ @@ -108,6 +111,7 @@ impl Contains for BlockEverything { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BlockEverything; type BlockWeights = (); diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs index ea52293a673..78ae6f57f08 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:66:2 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:67:2 | -66 | pub struct Runtime +67 | pub struct Runtime | ^^^ error[E0412]: cannot find type `RuntimeCall` in this scope @@ -22,38 +22,38 @@ error[E0412]: cannot find type `Runtime` in this scope | ^^^^^^^ not found in this scope error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:31 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:40:31 | -39 | impl frame_system::Config for Runtime { +40 | impl frame_system::Config for Runtime { | ^^^^^^^ not found in this scope error[E0412]: cannot find type `RuntimeOrigin` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:41:23 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:42:23 | -41 | type RuntimeOrigin = RuntimeOrigin; +42 | type RuntimeOrigin = RuntimeOrigin; | ^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeOrigin` error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:43:21 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:44:21 | -43 | type RuntimeCall = RuntimeCall; +44 | type RuntimeCall = RuntimeCall; | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` error[E0412]: cannot find type `RuntimeEvent` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:49:22 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:50:22 | -49 | type RuntimeEvent = RuntimeEvent; +50 | type RuntimeEvent = RuntimeEvent; | ^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeEvent` error[E0412]: cannot find type `PalletInfo` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:55:20 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:56:20 | -55 | type PalletInfo = PalletInfo; +56 | type PalletInfo = PalletInfo; | ^^^^^^^^^^ | help: you might have meant to use the associated type | -55 | type PalletInfo = Self::PalletInfo; +56 | type PalletInfo = Self::PalletInfo; | ~~~~~~~~~~~~~~~~ help: consider importing one of these items | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs index 2834b5b8f2a..d3e519af551 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -61,6 +61,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic tests/construct_runtime_ui/pallet_error_too_large.rs:90:1 + --> tests/construct_runtime_ui/pallet_error_too_large.rs:91:1 | -90 | / construct_runtime! { -91 | | pub struct Runtime -92 | | { -93 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, -94 | | Pallet: pallet::{Pallet}, -95 | | } -96 | | } - | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:90:1 +91 | / construct_runtime! { +92 | | pub struct Runtime +93 | | { +94 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +95 | | Pallet: pallet::{Pallet}, +96 | | } +97 | | } + | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:91:1 | = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index 62c4b1327e0..8193d12120c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet::{Pallet, Call}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet::{Pallet, Call}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index 893690501a8..ef3a790b61a 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Event}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Event}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Event` in module `pallet` - --> tests/construct_runtime_ui/undefined_event_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:66:1 | -65 | / construct_runtime! { -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Event}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Event}, +71 | | } +72 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index a3501ca31a3..b4dd41750c8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Config}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Config}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in module `pallet` - --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:66:1 | -65 | / construct_runtime! { -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Config}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Config}, +71 | | } +72 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index e22745930d6..5e0b8f3c44f 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `create_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `create_inherent` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | _^ -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -37,19 +37,19 @@ error[E0599]: no function or associated item named `create_inherent` found for s = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `is_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `is_inherent` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | _^ -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -58,19 +58,19 @@ error[E0599]: no function or associated item named `is_inherent` found for struc = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `check_inherent` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | _^ -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -79,19 +79,19 @@ error[E0599]: no function or associated item named `check_inherent` found for st = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- associated item `INHERENT_IDENTIFIER` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | _^ -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_^ associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope @@ -100,19 +100,19 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `is_inherent_required` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_inherent_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `is_inherent_required` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | _^ -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, -70 | | } -71 | | } +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 656365279b8..40a4a1ebcb5 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Origin}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Origin}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Origin` in module `pallet` - --> tests/construct_runtime_ui/undefined_origin_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:66:1 | -65 | / construct_runtime! { -66 | | pub struct Runtime -67 | | { -68 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, -69 | | Pallet: pallet expanded::{}::{Pallet, Origin}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Origin}, +71 | | } +72 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 05545821ab0..be9e4ac2c30 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -36,6 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic, Event}, -69 | | Pallet: pallet::{Pallet, ValidateUnsigned}, -70 | | } -71 | | } +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet::{Pallet, ValidateUnsigned}, +71 | | } +72 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:69:3 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:70:3 | -65 | // construct_runtime! { -66 | || pub struct Runtime -67 | || { -68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +66 | // construct_runtime! { +67 | || pub struct Runtime +68 | || { +69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | || Pallet: pallet::{Pallet, ValidateUnsigned}, | || -^^^^^^ variant or associated item not found in `RuntimeCall` | ||________| | | ... | error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `pre_dispatch` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | __^ | | _| | || -66 | || pub struct Runtime -67 | || { -68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -70 | || } -71 | || } +67 | || pub struct Runtime +68 | || { +69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +71 | || } +72 | || } | ||_- in this macro invocation ... | | @@ -54,21 +54,21 @@ error[E0599]: no function or associated item named `pre_dispatch` found for stru = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope - --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:65:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:66:1 | 28 | pub struct Pallet(_); | -------------------- function or associated item `validate_unsigned` not found for this struct ... -65 | construct_runtime! { +66 | construct_runtime! { | __^ | | _| | || -66 | || pub struct Runtime -67 | || { -68 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -69 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -70 | || } -71 | || } +67 | || pub struct Runtime +68 | || { +69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | || Pallet: pallet::{Pallet, ValidateUnsigned}, +71 | || } +72 | || } | ||_- in this macro invocation ... | | diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 00e7adafb0b..1afb8fdf497 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -16,7 +16,7 @@ // limitations under the License. use frame_support::{ - assert_ok, + assert_ok, derive_impl, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays}, dispatch_context::with_context, pallet_prelude::{StorageInfoTrait, ValueQuery}, @@ -682,6 +682,7 @@ frame_support::parameter_types!( pub const MyGetParam3: u32 = 12; ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index 724734ec4fc..e9ac03302b2 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -16,6 +16,7 @@ // limitations under the License. use frame_support::{ + derive_impl, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, pallet_prelude::ValueQuery, parameter_types, @@ -292,6 +293,7 @@ pub mod pallet2 { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs index bf26cfd95b1..4dc33991b12 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs @@ -17,7 +17,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::ConstU32; +use frame_support::{derive_impl, traits::ConstU32}; pub use pallet::*; @@ -70,6 +70,7 @@ pub mod pallet { impl Pallet {} } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs index 9ab486c718c..de856ddcd3e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use sp_core::sr25519; use sp_runtime::{generic, traits::BlakeTwo256}; @@ -27,6 +27,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); diff --git a/substrate/frame/support/test/tests/storage_layers.rs b/substrate/frame/support/test/tests/storage_layers.rs index b825c85f956..a6d16e0d66d 100644 --- a/substrate/frame/support/test/tests/storage_layers.rs +++ b/substrate/frame/support/test/tests/storage_layers.rs @@ -16,8 +16,8 @@ // limitations under the License. use frame_support::{ - assert_noop, assert_ok, dispatch::DispatchResult, ensure, pallet_prelude::ConstU32, - storage::with_storage_layer, + assert_noop, assert_ok, derive_impl, dispatch::DispatchResult, ensure, + pallet_prelude::ConstU32, storage::with_storage_layer, }; use pallet::*; use sp_io::TestExternalities; @@ -64,6 +64,7 @@ pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; +#[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 = (); diff --git a/substrate/frame/system/benches/bench.rs b/substrate/frame/system/benches/bench.rs index da8bb10fd4e..79d5a2d8689 100644 --- a/substrate/frame/system/benches/bench.rs +++ b/substrate/frame/system/benches/bench.rs @@ -16,7 +16,10 @@ // limitations under the License. use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + derive_impl, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -57,6 +60,8 @@ frame_support::parameter_types! { 4 * 1024 * 1024, Perbill::from_percent(75), ); } + +#[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 = (); diff --git a/substrate/frame/system/benchmarking/src/mock.rs b/substrate/frame/system/benchmarking/src/mock.rs index 4e6b1221da3..9a81cddca14 100644 --- a/substrate/frame/system/benchmarking/src/mock.rs +++ b/substrate/frame/system/benchmarking/src/mock.rs @@ -20,6 +20,7 @@ #![cfg(test)] use codec::Encode; +use frame_support::derive_impl; use sp_runtime::{traits::IdentityLookup, BuildStorage}; type AccountId = u64; @@ -34,6 +35,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/timestamp/src/mock.rs b/substrate/frame/timestamp/src/mock.rs index 418d257b3f0..b75bcaeb0e0 100644 --- a/substrate/frame/timestamp/src/mock.rs +++ b/substrate/frame/timestamp/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_timestamp; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_core::H256; @@ -42,6 +42,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 189623b520e..d5c8e17a396 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -27,7 +27,7 @@ use sp_runtime::{ use sp_storage::Storage; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, storage::StoragePrefixedMap, traits::{ tokens::{PayFromAccount, UnityAssetBalanceConversion}, @@ -56,6 +56,8 @@ frame_support::construct_runtime!( parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } + +#[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 = (); diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index 76c78fb4222..081e8e53db2 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -18,6 +18,7 @@ use crate as pallet_asset_conversion_tx_payment; use codec; use frame_support::{ + derive_impl, dispatch::DispatchClass, instances::Instance2, ord_parameter_types, @@ -78,6 +79,7 @@ parameter_types! { pub static TransactionByteFee: u64 = 1; } +#[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; diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs index 5fa8a4ab27d..c9b00be8e2c 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -18,6 +18,7 @@ use crate as pallet_asset_tx_payment; use codec; use frame_support::{ + derive_impl, dispatch::DispatchClass, pallet_prelude::*, parameter_types, @@ -70,6 +71,7 @@ parameter_types! { pub static TransactionByteFee: u64 = 1; } +#[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; diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 419989bef12..d6686d44c80 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -22,6 +22,7 @@ use sp_core::H256; use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use frame_support::{ + derive_impl, dispatch::DispatchClass, parameter_types, traits::{ConstU32, ConstU64, Imbalance, OnUnbalanced}, @@ -69,6 +70,7 @@ parameter_types! { pub static OperationalFeeMultiplier: u8 = 5; } +#[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; diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index 522ecf6b18f..093757b2770 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -27,7 +27,7 @@ use sp_runtime::{ }; use frame_support::{ - assert_err_ignore_postinfo, assert_noop, assert_ok, + assert_err_ignore_postinfo, assert_noop, assert_ok, derive_impl, pallet_prelude::Pays, parameter_types, traits::{ @@ -54,6 +54,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 66218c8c015..4f1c981abc6 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -23,7 +23,7 @@ use super::*; use crate as pallet_tx_pause; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU64, Everything, InsideBoth, InstanceFilter}, }; use frame_system::EnsureSignedBy; @@ -36,6 +36,7 @@ use sp_runtime::{ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = InsideBoth; type BlockWeights = (); diff --git a/substrate/frame/uniques/src/mock.rs b/substrate/frame/uniques/src/mock.rs index 1f62c3c4e93..056c19ec559 100644 --- a/substrate/frame/uniques/src/mock.rs +++ b/substrate/frame/uniques/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_uniques; use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; @@ -41,6 +41,7 @@ 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 = (); diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 01e3f5264bf..7b42fa511d1 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -23,7 +23,7 @@ use super::*; use crate as utility; use frame_support::{ - assert_err_ignore_postinfo, assert_noop, assert_ok, + assert_err_ignore_postinfo, assert_noop, assert_ok, derive_impl, dispatch::{DispatchErrorWithPostInfo, Pays}, error::BadOrigin, parameter_types, storage, @@ -144,6 +144,7 @@ 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 = TestBaseCallFilter; type BlockWeights = BlockWeights; diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index 13d6d5ba57a..67444b8d125 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -16,7 +16,7 @@ // limitations under the License. use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64, WithdrawReasons}, }; use sp_core::H256; @@ -39,6 +39,7 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; type AccountId = u64; diff --git a/substrate/frame/whitelist/src/mock.rs b/substrate/frame/whitelist/src/mock.rs index 4e70a503c28..200e589c6aa 100644 --- a/substrate/frame/whitelist/src/mock.rs +++ b/substrate/frame/whitelist/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_whitelist; use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, traits::{ConstU32, ConstU64, Nothing}, }; use frame_system::EnsureRoot; @@ -44,6 +44,7 @@ construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Nothing; type BlockWeights = (); diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index 2d8e45cbfc6..b91ae436127 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -34,7 +34,7 @@ use sp_storage::{StorageData, StorageKey}; /// # use jsonrpsee::core::Error as RpcError; /// # use jsonrpsee::ws_client::WsClientBuilder; /// # use codec::Encode; -/// # use frame_support::{construct_runtime, traits::ConstU32}; +/// # use frame_support::{construct_runtime, derive_impl, traits::ConstU32}; /// # use substrate_frame_rpc_support::StorageQuery; /// # use sc_rpc_api::state::StateApiClient; /// # use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; @@ -49,6 +49,7 @@ use sp_storage::{StorageData, StorageKey}; /// # /// # type Hash = sp_core::H256; /// # +/// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] /// # impl frame_system::Config for TestRuntime { /// # type BaseCallFilter = (); /// # type BlockWeights = (); -- GitLab From dbd8d20b25b29abf138e3ad35c40df4c55bd7c5c Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 28 Nov 2023 14:23:25 +0100 Subject: [PATCH 599/633] PVF: Add test instructions (#2058) --- polkadot/doc/testing.md | 91 ++++++++++++++----- polkadot/node/core/pvf/README.md | 47 ++++++++++ ...executor_intf.rs => executor_interface.rs} | 6 +- polkadot/node/core/pvf/common/src/lib.rs | 2 +- .../node/core/pvf/execute-worker/src/lib.rs | 4 +- .../benches/prepare_rococo_runtime.rs | 2 +- .../node/core/pvf/prepare-worker/src/lib.rs | 4 +- polkadot/node/core/pvf/src/execute/mod.rs | 2 +- polkadot/node/core/pvf/src/execute/queue.rs | 8 +- .../{worker_intf.rs => worker_interface.rs} | 2 +- polkadot/node/core/pvf/src/lib.rs | 4 +- polkadot/node/core/pvf/src/prepare/mod.rs | 2 +- polkadot/node/core/pvf/src/prepare/pool.rs | 8 +- .../{worker_intf.rs => worker_interface.rs} | 2 +- polkadot/node/core/pvf/src/testing.rs | 4 +- .../{worker_intf.rs => worker_interface.rs} | 0 polkadot/node/core/pvf/tests/README.md | 9 -- .../implementers-guide/src/glossary.md | 9 +- 18 files changed, 146 insertions(+), 60 deletions(-) create mode 100644 polkadot/node/core/pvf/README.md rename polkadot/node/core/pvf/common/src/{executor_intf.rs => executor_interface.rs} (98%) rename polkadot/node/core/pvf/src/execute/{worker_intf.rs => worker_interface.rs} (99%) rename polkadot/node/core/pvf/src/prepare/{worker_intf.rs => worker_interface.rs} (99%) rename polkadot/node/core/pvf/src/{worker_intf.rs => worker_interface.rs} (100%) delete mode 100644 polkadot/node/core/pvf/tests/README.md diff --git a/polkadot/doc/testing.md b/polkadot/doc/testing.md index 1045303baf0..76703b1b439 100644 --- a/polkadot/doc/testing.md +++ b/polkadot/doc/testing.md @@ -1,6 +1,7 @@ # Testing -Automated testing is an essential tool to assure correctness. +Testing is an essential tool to assure correctness. This document describes how we test the Polkadot code, whether +locally, at scale, and/or automatically in CI. ## Scopes @@ -8,27 +9,57 @@ The testing strategy for Polkadot is 4-fold: ### Unit testing (1) -Boring, small scale correctness tests of individual functions. +Boring, small scale correctness tests of individual functions. It is usually +enough to run `cargo test` in the crate you are testing. + +For full coverage you may have to pass some additional features. For example: + +```sh +cargo test --features ci-only-tests +``` ### Integration tests -There are two variants of integration tests: +There are the following variants of integration tests: #### Subsystem tests (2) One particular subsystem (subsystem under test) interacts with a mocked overseer that is made to assert incoming and -outgoing messages of the subsystem under test. This is largely present today, but has some fragmentation in the evolved -integration test implementation. A `proc-macro`/`macro_rules` would allow for more consistent implementation and -structure. +outgoing messages of the subsystem under test. See e.g. the `statement-distribution` tests. #### Behavior tests (3) -Launching small scale networks, with multiple adversarial nodes without any further tooling required. This should -include tests around the thresholds in order to evaluate the error handling once certain assumed invariants fail. +Launching small scale networks, with multiple adversarial nodes. This should include tests around the thresholds in +order to evaluate the error handling once certain assumed invariants fail. + +Currently, we commonly use **zombienet** to run mini test-networks, whether locally or in CI. To run on your machine: + +- First, make sure you have [zombienet][zombienet] installed. + +- Now, all the required binaries must be installed in your $PATH. You must run the following from the `polkadot/` +directory in order to test your changes. (Not `zombienet setup`, or you will get the released binaries without your +local changes!) -For this purpose based on `AllSubsystems` and `proc-macro` `AllSubsystemsGen`. +```sh +cargo install --path . --locked +``` + +- You will also need to install whatever binaries are required for your specific tests. For example, to install +`undying-collator`, from `polkadot/`, run: + +```sh +cargo install --path ./parachain/test-parachains/undying/collator --locked +``` -This assumes a simplistic test runtime. +- Finally, run the zombienet test from the `polkadot` directory: + +```sh +RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/functional/0001-parachains-pvf.toml +``` + +- You can pick a validator node like `alice` from the output and view its logs +(`tail -f `) or metrics. Make sure there is nothing funny in the logs +(try `grep WARN `). #### Testing at scale (4) @@ -41,13 +72,27 @@ addition prometheus avoiding additional Polkadot source changes. _Behavior tests_ and _testing at scale_ have naturally soft boundary. The most significant difference is the presence of a real network and the number of nodes, since a single host often not capable to run multiple nodes at once. ---- +## Observing Logs + +To verify expected behavior it's often useful to observe logs. To avoid too many +logs at once, you can run one test at a time: + +1. Add `sp_tracing::try_init_simple();` to the beginning of a test +2. Specify `RUST_LOG=::=trace` before the cargo command. + +For example: + +```sh +RUST_LOG=parachain::pvf=trace cargo test execute_can_run_serially +``` + +For more info on how our logs work, check [the docs][logs]. ## Coverage Coverage gives a _hint_ of the actually covered source lines by tests and test applications. -The state of the art is currently [tarpaulin][tarpaulin] which unfortunately yields a lot of false negatives. Lines that +The state of the art is currently tarpaulin which unfortunately yields a lot of false negatives. Lines that are in fact covered, marked as uncovered due to a mere linebreak in a statement can cause these artifacts. This leads to lower coverage percentages than there actually is. @@ -102,7 +147,7 @@ Fuzzing is an approach to verify correctness against arbitrary or partially stru Currently implemented fuzzing targets: -* `erasure-coding` +- `erasure-coding` The tooling of choice here is `honggfuzz-rs` as it allows _fastest_ coverage according to "some paper" which is a positive feature when run as part of PRs. @@ -113,16 +158,16 @@ hence simply not feasible due to the amount of state that is required. Other candidates to implement fuzzing are: -* `rpc` -* ... +- `rpc` +- ... ## Performance metrics There are various ways of performance metrics. -* timing with `criterion` -* cache hits/misses w/ `iai` harness or `criterion-perf` -* `coz` a performance based compiler +- timing with `criterion` +- cache hits/misses w/ `iai` harness or `criterion-perf` +- `coz` a performance based compiler Most of them are standard tools to aid in the creation of statistical tests regarding change in time of certain unit tests. @@ -140,10 +185,10 @@ pursued at the current time. Requirements: -* spawn nodes with preconfigured behaviors -* allow multiple types of configuration to be specified -* allow extendability via external crates -* ... +- spawn nodes with preconfigured behaviors +- allow multiple types of configuration to be specified +- allow extendability via external crates +- ... --- @@ -251,5 +296,7 @@ behavior_testcase!{ } ``` +[zombienet]: https://github.com/paritytech/zombienet [Gurke]: https://github.com/paritytech/gurke [simnet]: https://github.com/paritytech/simnet_scripts +[logs]: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/node/gum/src/lib.rs diff --git a/polkadot/node/core/pvf/README.md b/polkadot/node/core/pvf/README.md new file mode 100644 index 00000000000..796e17c05fa --- /dev/null +++ b/polkadot/node/core/pvf/README.md @@ -0,0 +1,47 @@ +# PVF Host + +This is the PVF host, responsible for responding to requests from Candidate +Validation and spawning worker tasks to fulfill those requests. + +See also: + +- for more information: [the Implementer's Guide][impl-guide] +- for an explanation of terminology: [the Glossary][glossary] + +## Running basic tests + +Running `cargo test` in the `pvf/` directory will run unit and integration +tests. + +**Note:** some tests run only under Linux, amd64, and/or with the +`ci-only-tests` feature enabled. + +See the general [Testing][testing] instructions for more information on +**running tests** and **observing logs**. + +## Running a test-network with zombienet + +Since this crate is consensus-critical, for major changes it is highly +recommended to run a test-network. See the "Behavior tests" section of the +[Testing][testing] docs for full instructions. + +To run the PVF-specific zombienet test: + +```sh +RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/functional/0001-parachains-pvf.toml +``` + +## Testing on Linux + +Some of the PVF functionality, especially related to security, is Linux-only, +and some is amd64-only. If you touch anything security-related, make sure to +test on Linux amd64! If you're on a Mac, you can either run a VM or you can hire +a VPS and use the open-source tool [EternalTerminal][et] to connect to it.[^et] + +[^et]: Unlike ssh, ET preserves your session across disconnects, and unlike +another popular persistent shell, mosh, it allows scrollback. + +[impl-guide]: https://paritytech.github.io/polkadot-sdk/book/pvf-prechecking.html#summary +[glossary]: https://paritytech.github.io/polkadot-sdk/book/glossary.html +[testing]: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/doc/testing.md +[et]: https://github.com/MisterTea/EternalTerminal diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_interface.rs similarity index 98% rename from polkadot/node/core/pvf/common/src/executor_intf.rs rename to polkadot/node/core/pvf/common/src/executor_interface.rs index 4bafc3f4291..e634940dbe6 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_interface.rs @@ -175,11 +175,9 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Semantics { /// Runs the prevalidation on the given code. Returns a [`RuntimeBlob`] if it succeeds. pub fn prevalidate(code: &[u8]) -> Result { + // Construct the runtime blob and do some basic checks for consistency. let blob = RuntimeBlob::new(code)?; - // It's assumed this function will take care of any prevalidation logic - // that needs to be done. - // - // Do nothing for now. + // In the future this function should take care of any further prevalidation logic. Ok(blob) } diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index c041c60aaf9..dced43ef213 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -18,7 +18,7 @@ pub mod error; pub mod execute; -pub mod executor_intf; +pub mod executor_interface; pub mod prepare; pub mod pvf; pub mod worker; diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index d82a8fca65d..8c985fc7996 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -17,7 +17,7 @@ //! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary. pub use polkadot_node_core_pvf_common::{ - executor_intf::execute_artifact, worker_dir, SecurityStatus, + executor_interface::execute_artifact, worker_dir, SecurityStatus, }; // NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are @@ -236,7 +236,7 @@ fn validate_using_artifact( 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_interface::prepare`]. execute_artifact(compiled_artifact_blob, executor_params, params) } { Err(err) => return JobResponse::format_invalid("execute", &err), diff --git a/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs index ba2568cd80c..d531c90b64b 100644 --- a/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs @@ -16,7 +16,7 @@ use criterion::{criterion_group, criterion_main, Criterion, SamplingMode}; use polkadot_node_core_pvf_common::{ - executor_intf::{prepare, prevalidate}, + executor_interface::{prepare, prevalidate}, prepare::PrepareJobKind, pvf::PvfPrepData, }; diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index 499e87c6e20..b3f8a6b11ba 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -18,7 +18,7 @@ mod memory_stats; -use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate}; +use polkadot_node_core_pvf_common::executor_interface::{prepare, prevalidate}; // 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-prepare-worker=trace`. @@ -41,7 +41,7 @@ use os_pipe::{self, PipeReader, PipeWriter}; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareWorkerResult}, - executor_intf::create_runtime_from_artifact_bytes, + executor_interface::create_runtime_from_artifact_bytes, framed_recv_blocking, framed_send_blocking, prepare::{MemoryStats, PrepareJobKind, PrepareStats, PrepareWorkerSuccess}, pvf::PvfPrepData, diff --git a/polkadot/node/core/pvf/src/execute/mod.rs b/polkadot/node/core/pvf/src/execute/mod.rs index 669b9dc04d7..c6d9cf90fa2 100644 --- a/polkadot/node/core/pvf/src/execute/mod.rs +++ b/polkadot/node/core/pvf/src/execute/mod.rs @@ -21,6 +21,6 @@ //! `polkadot_node_core_pvf_worker::execute_worker_entrypoint`. mod queue; -mod worker_intf; +mod worker_interface; pub use queue::{start, PendingExecutionRequest, ToQueue}; diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index a0c24fd4432..be607fe1c20 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -16,12 +16,12 @@ //! A queue that handles requests for PVF execution. -use super::worker_intf::Outcome; +use super::worker_interface::Outcome; use crate::{ artifacts::{ArtifactId, ArtifactPathId}, host::ResultSender, metrics::Metrics, - worker_intf::{IdleWorker, WorkerHandle}, + worker_interface::{IdleWorker, WorkerHandle}, InvalidCandidate, PossiblyInvalidError, ValidationError, LOG_TARGET, }; use futures::{ @@ -448,7 +448,7 @@ async fn spawn_worker_task( use futures_timer::Delay; loop { - match super::worker_intf::spawn( + match super::worker_interface::spawn( &program_path, &cache_path, job.executor_params.clone(), @@ -500,7 +500,7 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) { queue.mux.push( async move { let _timer = execution_timer; - let outcome = super::worker_intf::start_work( + let outcome = super::worker_interface::start_work( idle, job.artifact.clone(), job.exec_timeout, diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_interface.rs similarity index 99% rename from polkadot/node/core/pvf/src/execute/worker_intf.rs rename to polkadot/node/core/pvf/src/execute/worker_interface.rs index 16a7c290b52..7864ce548c2 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_interface.rs @@ -18,7 +18,7 @@ use crate::{ artifacts::ArtifactPathId, - worker_intf::{ + worker_interface::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }, diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 3306a2461c1..79391630b2d 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -98,7 +98,7 @@ mod metrics; mod prepare; mod priority; mod security; -mod worker_intf; +mod worker_interface; #[cfg(feature = "test-utils")] pub mod testing; @@ -107,7 +107,7 @@ pub use error::{InvalidCandidate, PossiblyInvalidError, ValidationError}; pub use host::{start, Config, ValidationHost, EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}; pub use metrics::Metrics; pub use priority::Priority; -pub use worker_intf::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR}; +pub use worker_interface::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR}; // Re-export some common types. pub use polkadot_node_core_pvf_common::{ diff --git a/polkadot/node/core/pvf/src/prepare/mod.rs b/polkadot/node/core/pvf/src/prepare/mod.rs index 580f67f73fa..eb88070c2ba 100644 --- a/polkadot/node/core/pvf/src/prepare/mod.rs +++ b/polkadot/node/core/pvf/src/prepare/mod.rs @@ -24,7 +24,7 @@ mod pool; mod queue; -mod worker_intf; +mod worker_interface; pub use pool::start as start_pool; pub use queue::{start as start_queue, FromQueue, ToQueue}; diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 4901be9fe1b..4e11f977c9e 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::worker_intf::{self, Outcome}; +use super::worker_interface::{self, Outcome}; use crate::{ metrics::Metrics, - worker_intf::{IdleWorker, WorkerHandle}, + worker_interface::{IdleWorker, WorkerHandle}, LOG_TARGET, }; use always_assert::never; @@ -278,7 +278,7 @@ async fn spawn_worker_task( use futures_timer::Delay; loop { - match worker_intf::spawn( + match worker_interface::spawn( &program_path, &cache_path, spawn_timeout, @@ -306,7 +306,7 @@ async fn start_work_task( cache_path: PathBuf, _preparation_timer: Option, ) -> PoolEvent { - let outcome = worker_intf::start_work(&metrics, idle, pvf, cache_path).await; + let outcome = worker_interface::start_work(&metrics, idle, pvf, cache_path).await; PoolEvent::StartWork(worker, outcome) } diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_interface.rs similarity index 99% rename from polkadot/node/core/pvf/src/prepare/worker_intf.rs rename to polkadot/node/core/pvf/src/prepare/worker_interface.rs index a393e9baa9e..984a87ce5c9 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_interface.rs @@ -19,7 +19,7 @@ use crate::{ artifacts::ArtifactId, metrics::Metrics, - worker_intf::{ + worker_interface::{ clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }, diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index c7c885c4342..60b0b4b8d3d 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -18,7 +18,7 @@ pub use crate::{ host::{EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}, - worker_intf::{spawn_with_program_path, SpawnErr}, + worker_interface::{spawn_with_program_path, SpawnErr}, }; use crate::get_worker_version; @@ -36,7 +36,7 @@ pub fn validate_candidate( code: &[u8], params: &[u8], ) -> Result, Box> { - use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate}; + use polkadot_node_core_pvf_common::executor_interface::{prepare, prevalidate}; use polkadot_node_core_pvf_execute_worker::execute_artifact; let code = sp_maybe_compressed_blob::decompress(code, 10 * 1024 * 1024) diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_interface.rs similarity index 100% rename from polkadot/node/core/pvf/src/worker_intf.rs rename to polkadot/node/core/pvf/src/worker_interface.rs diff --git a/polkadot/node/core/pvf/tests/README.md b/polkadot/node/core/pvf/tests/README.md deleted file mode 100644 index 27385e19025..00000000000 --- a/polkadot/node/core/pvf/tests/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# PVF host integration tests - -## Testing - -Before running these tests, make sure the worker binaries are built first. This can be done with: - -```sh -cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker -``` diff --git a/polkadot/roadmap/implementers-guide/src/glossary.md b/polkadot/roadmap/implementers-guide/src/glossary.md index b2365ba51c5..ac2392b14d2 100644 --- a/polkadot/roadmap/implementers-guide/src/glossary.md +++ b/polkadot/roadmap/implementers-guide/src/glossary.md @@ -48,10 +48,13 @@ has exactly one downward message queue. - **Proof-of-Validity (PoV):** A stateless-client proof that a parachain candidate is valid, with respect to some validation function. - **PVF:** Parachain Validation Function. The validation code that is run by validators on parachains. -- **PVF Prechecking:** This is the process of initially checking the PVF when it is first added. We attempt preparation - of the PVF and make sure it succeeds within a given timeout, plus some additional checks. +- **PVF Prechecking:** This is the process of checking a PVF when it appears + on-chain, either when the parachain is onboarded or when it signalled an + upgrade of its validation code. We attempt preparation of the PVF and make + sure it that succeeds within a given timeout, plus some additional checks. - **PVF Preparation:** This is the process of preparing the WASM blob and includes both prevalidation and compilation. - As there is no prevalidation right now, preparation just consists of compilation. +- **PVF Prevalidation:** Some basic checks for correctness of the PVF blob. The + first step of PVF preparation, before compilation. - **Relay Parent:** A block in the relay chain, referred to in a context where work is being done in the context of the state at this block. - **Runtime:** The relay-chain state machine. -- GitLab From f01781a9021d1a95db9e77174b94745b8bed244c Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 28 Nov 2023 22:30:02 +0900 Subject: [PATCH 600/633] Remove `wasm-builder`'s README (#2525) Followup of https://github.com/paritytech/polkadot-sdk/pull/2217 This PR deletes the README of the `wasm-builder` crate and moves its docs back into the rustdoc, [as requested here](https://github.com/paritytech/polkadot-sdk/pull/2217#discussion_r1406401175). (: --- substrate/utils/wasm-builder/Cargo.toml | 1 - substrate/utils/wasm-builder/README.md | 92 ----------------------- substrate/utils/wasm-builder/src/lib.rs | 97 ++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 94 deletions(-) delete mode 100644 substrate/utils/wasm-builder/README.md diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 2550122ad4b..fc3f6450fd7 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -4,7 +4,6 @@ version = "5.0.0-dev" authors.workspace = true description = "Utility for building WASM binaries" edition.workspace = true -readme = "README.md" repository.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/substrate/utils/wasm-builder/README.md b/substrate/utils/wasm-builder/README.md deleted file mode 100644 index 6dfc743816c..00000000000 --- a/substrate/utils/wasm-builder/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# Wasm builder is a utility for building a project as a Wasm binary - -The Wasm builder is a tool that integrates the process of building the WASM binary of your project into the main `cargo` -build process. - -## Project setup - -A project that should be compiled as a Wasm binary needs to: - -1. Add a `build.rs` file. -2. Add `wasm-builder` as dependency into `build-dependencies` (can be made optional and only enabled when `std` feature - is used). - -The `build.rs` file needs to contain the following code: - -```rust,no_run -fn main() { - #[cfg(feature = "std")] - { - substrate_wasm_builder::WasmBuilder::new() - // Tell the builder to build the project (crate) this `build.rs` is part of. - .with_current_project() - // Make sure to export the `heap_base` global, this is required by Substrate - .export_heap_base() - // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) - .import_memory() - // Build it. - .build(); - } -} -``` - -As the final step, you need to add the following to your project: - -```rust,ignore -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -``` - -This will include the generated Wasm binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`. The former is a -compact Wasm binary and the latter is the Wasm binary as being generated by the compiler. Both variables have -`Option<&'static [u8]>` as type. - -### Features - -Wasm builder supports to enable cargo features while building the Wasm binary. By default it will enable all features in -the wasm build that are enabled for the native build except the `default` and `std` features. Besides that, wasm builder -supports the special `runtime-wasm` feature. This `runtime-wasm` feature will be enabled by the wasm builder when it -compiles the Wasm binary. If this feature is not present, it will not be enabled. - -## Environment variables - -By using environment variables, you can configure which Wasm binaries are built and how: - -- `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be recompiled. If this is - the first run and there doesn't exist a Wasm binary, this will set both variables to `None`. -- `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are `release` or `debug`. By - default the build type is equal to the build type used by the main build. -- `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the variable needs to change. - As wasm-builder instructs `cargo` to watch for file changes this environment variable should only - be required in certain circumstances. -- `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm binary. -- `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. -- `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path needs to be absolute. -- `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The format needs to be the same - as used by cargo, e.g. `nightly-2020-02-20`. -- `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not required as we walk up from - the target directory until we find a `Cargo.toml`. If the target directory is changed for - the build, this environment variable can be used to point to the actual workspace. -- `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will also be built. This is necessary to make sure - the standard library crates only use the exact WASM feature set that our executor supports. - Enabled by default. -- `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to prevent network access. - Useful in offline environments. - -Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. Where -`PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. - -## Prerequisites - -Wasm builder requires the following prerequisites for building the Wasm binary: - -- rust nightly + `wasm32-unknown-unknown` toolchain - -or - -- rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain - -If a specific rust is installed with `rustup`, it is important that the wasm target is installed as well. For example if -installing the rust from 20.02.2020 using `rustup install nightly-2020-02-20`, the wasm target needs to be installed as -well `rustup target add wasm32-unknown-unknown --toolchain nightly-2020-02-20`. - -License: Apache-2.0 diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index cd31a8cba10..ec85fd1ffdd 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -15,7 +15,102 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![doc = include_str!("../README.md")] +//! # Wasm builder is a utility for building a project as a Wasm binary +//! +//! The Wasm builder is a tool that integrates the process of building the WASM binary of your +//! project into the main `cargo` build process. +//! +//! ## Project setup +//! +//! A project that should be compiled as a Wasm binary needs to: +//! +//! 1. Add a `build.rs` file. +//! 2. Add `wasm-builder` as dependency into `build-dependencies`. +//! +//! The `build.rs` file needs to contain the following code: +//! +//! ```no_run +//! use substrate_wasm_builder::WasmBuilder; +//! +//! fn main() { +//! WasmBuilder::new() +//! // Tell the builder to build the project (crate) this `build.rs` is part of. +//! .with_current_project() +//! // Make sure to export the `heap_base` global, this is required by Substrate +//! .export_heap_base() +//! // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) +//! .import_memory() +//! // Build it. +//! .build() +//! } +//! ``` +//! +//! As the final step, you need to add the following to your project: +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +//! ``` +//! +//! This will include the generated Wasm binary as two constants `WASM_BINARY` and +//! `WASM_BINARY_BLOATY`. The former is a compact Wasm binary and the latter is the Wasm binary as +//! being generated by the compiler. Both variables have `Option<&'static [u8]>` as type. +//! +//! ### Feature +//! +//! Wasm builder supports to enable cargo features while building the Wasm binary. By default it +//! will enable all features in the wasm build that are enabled for the native build except the +//! `default` and `std` features. Besides that, wasm builder supports the special `runtime-wasm` +//! feature. This `runtime-wasm` feature will be enabled by the wasm builder when it compiles the +//! Wasm binary. If this feature is not present, it will not be enabled. +//! +//! ## Environment variables +//! +//! By using environment variables, you can configure which Wasm binaries are built and how: +//! +//! - `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be +//! recompiled. If this is the first run and there doesn't exist a Wasm binary, this will set both +//! variables to `None`. +//! - `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are +//! `release` or `debug`. By default the build type is equal to the build type used by the main +//! build. +//! - `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the +//! variable needs to change. As wasm-builder instructs `cargo` to watch for file changes this +//! environment variable should only be required in certain circumstances. +//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm +//! binary. +//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. +//! - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path +//! needs to be absolute. +//! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The +//! format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. +//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not +//! required as we walk up from the target directory until we find a `Cargo.toml`. If the target +//! directory is changed for the build, this environment variable can be used to point to the +//! actual workspace. +//! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will also be built. This is +//! necessary to make sure the standard library crates only use the exact WASM feature set that +//! our executor supports. Enabled by default. +//! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to +//! prevent network access. Useful in offline environments. +//! +//! Each project can be skipped individually by using the environment variable +//! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the +//! cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. +//! +//! ## Prerequisites: +//! +//! Wasm builder requires the following prerequisites for building the Wasm binary: +//! +//! - rust nightly + `wasm32-unknown-unknown` toolchain +//! +//! or +//! +//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain +//! +//! If a specific rust is installed with `rustup`, it is important that the wasm target is +//! installed as well. For example if installing the rust from 20.02.2020 using `rustup +//! install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add +//! wasm32-unknown-unknown --toolchain nightly-2020-02-20`. use std::{ env, fs, -- GitLab From c5f211d0dee5e698ded0700469fb81a8c22c244a Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:36:04 +0100 Subject: [PATCH 601/633] Remove `im-online` pallet from Rococo and Westend (#2265) Co-authored-by: ordian Co-authored-by: Vladimir Istyufeev --- .gitlab/pipeline/check.yml | 1 + .../chains/relays/rococo/src/genesis.rs | 4 - .../chains/relays/westend/src/genesis.rs | 4 - .../emulated/common/src/lib.rs | 2 - polkadot/node/service/src/chain_spec.rs | 64 +---- polkadot/runtime/rococo/src/lib.rs | 164 ++++++++++-- polkadot/runtime/westend/src/lib.rs | 163 ++++++++++-- .../frame/offences/benchmarking/src/lib.rs | 235 +----------------- 8 files changed, 288 insertions(+), 349 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index b2f2efc5e66..3ef3865aa43 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -111,6 +111,7 @@ check-rust-feature-propagation: time ./try-runtime ${COMMAND_EXTRA_ARGS} \ --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} + sleep 5 # Check runtime migrations for Parity managed relay chains check-runtime-migration-westend: diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs index 6f5f3923ead..45e1e94de01 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs @@ -16,7 +16,6 @@ // Substrate use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{sr25519, storage::Storage}; @@ -38,7 +37,6 @@ const ENDOWMENT: u128 = 1_000_000 * ROC; fn session_keys( babe: BabeId, grandpa: GrandpaId, - im_online: ImOnlineId, para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, @@ -47,7 +45,6 @@ fn session_keys( rococo_runtime::SessionKeys { babe, grandpa, - im_online, para_validator, para_assignment, authority_discovery, @@ -74,7 +71,6 @@ pub fn genesis() -> Storage { x.4.clone(), x.5.clone(), x.6.clone(), - x.7.clone(), get_from_seed::("Alice"), ), ) diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index e87b85881d3..e2297100a45 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -16,7 +16,6 @@ // Substrate use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::storage::Storage; @@ -39,7 +38,6 @@ const STASH: u128 = 100 * WND; fn session_keys( babe: BabeId, grandpa: GrandpaId, - im_online: ImOnlineId, para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, @@ -48,7 +46,6 @@ fn session_keys( westend_runtime::SessionKeys { babe, grandpa, - im_online, para_validator, para_assignment, authority_discovery, @@ -75,7 +72,6 @@ pub fn genesis() -> Storage { x.4.clone(), x.5.clone(), x.6.clone(), - x.7.clone(), get_from_seed::("Alice"), ), ) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 952b053f2aa..58222f622c2 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -21,7 +21,6 @@ pub use xcm_emulator; // Substrate use grandpa::AuthorityId as GrandpaId; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{sr25519, storage::Storage, Pair, Public}; @@ -163,7 +162,6 @@ pub mod validators { AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 871d7e82911..fd35a4aaf6a 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -18,7 +18,6 @@ use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; #[cfg(feature = "westend-native")] use pallet_staking::Forcing; use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId}; @@ -162,7 +161,6 @@ fn default_parachains_host_configuration_is_consistent() { fn westend_session_keys( babe: BabeId, grandpa: GrandpaId, - im_online: ImOnlineId, para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, @@ -171,7 +169,6 @@ fn westend_session_keys( westend::SessionKeys { babe, grandpa, - im_online, para_validator, para_assignment, authority_discovery, @@ -183,7 +180,6 @@ fn westend_session_keys( fn rococo_session_keys( babe: BabeId, grandpa: GrandpaId, - im_online: ImOnlineId, para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, @@ -192,7 +188,6 @@ fn rococo_session_keys( rococo_runtime::SessionKeys { babe, grandpa, - im_online, para_validator, para_assignment, authority_discovery, @@ -220,7 +215,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, @@ -237,9 +231,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { //5Eb7wM65PNgtY6e33FEAzYtU5cRTXt6WQvZTnzaKQwkVcABk hex!["6faae44b21c6f2681a7f60df708e9f79d340f7d441d28bd987fab8d05c6487e8"] .unchecked_into(), - //5CdS2wGo4qdTQceVfEnbZH8vULeBrnGYCxSCxDna4tQSMV6y - hex!["18f5d55f138bfa8e0ea26ed6fa56817b247de3c2e2030a908c63fb37c146473f"] - .unchecked_into(), //5FqMLAgygdX9UqzukDp15Uid9PAKdFAR621U7xtp5ut2NfrW hex!["a6c1a5b501985a83cb1c37630c5b41e6b0a15b3675b2fd94694758e6cfa6794d"] .unchecked_into(), @@ -264,9 +255,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { //5FXFsPReTUEYPRNKhbTdUathcWBsxTNsLbk2mTpYdKCJewjA hex!["98f4d81cb383898c2c3d54dab28698c0f717c81b509cb32dc6905af3cc697b18"] .unchecked_into(), - //5CDYSCJK91r8y2r1V4Ddrit4PFMEkwZXJe8mNBqGXJ4xWCWq - hex!["06bd7dd4ab4c808c7d09d9cb6bd27fbcd99ad8400e99212b335056c475c24031"] - .unchecked_into(), //5CZjurB78XbSHf6SLkLhCdkqw52Zm7aBYUDdfkLqEDWJ9Zhj hex!["162508accd470e379b04cb0c7c60b35a7d5357e84407a89ed2dd48db4b726960"] .unchecked_into(), @@ -291,9 +279,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { //5G4kCbgqUhEyrRHCyFwFEkgBZXoYA8sbgsRxT9rY8Tp5Jj5F hex!["b0f8d2b9e4e1eafd4dab6358e0b9d5380d78af27c094e69ae9d6d30ca300fd86"] .unchecked_into(), - //5HVhFBLFTKSZK9fX6RktckWDTgYNoSd33fgonsEC8zfr4ddm - hex!["f03c3e184b2883eec9beaeb97f54321587e7476b228831ea0b5fc6da847ea975"] - .unchecked_into(), //5CS7thd2n54WfqeKU3cjvZzK4z5p7zku1Zw97mSzXgPioAAs hex!["1055100a283968271a0781450b389b9093231be809be1e48a305ebad2a90497e"] .unchecked_into(), @@ -318,9 +303,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { //5ChfdrAqmLjCeDJvynbMjcxYLHYzPe8UWXd3HnX9JDThUMbn hex!["1c309a70b4e274314b84c9a0a1f973c9c4fc084df5479ef686c54b1ae4950424"] .unchecked_into(), - //5DnsMm24575xK2b2aGfmafiDxwCet6Mr4iiZQeDdWvi8CzuF - hex!["4c64868ba6d8ace235d3efb4c10d745a67cf3bdfeae23b264d7ea2f3439dec42"] - .unchecked_into(), //5D8C3HHEp5E8fJsXRD56494F413CdRSR9QKGXe7v5ZEfymdj hex!["2ee4d78f328db178c54f205ac809da12e291a33bcbd4f29f081ce7e74bdc5044"] .unchecked_into(), @@ -361,7 +343,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { x.5.clone(), x.6.clone(), x.7.clone(), - x.8.clone(), ), ) }) @@ -408,7 +389,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, @@ -425,9 +405,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5CPd3zoV9Aaah4xWucuDivMHJ2nEEmpdi864nPTiyRZp4t87 hex!["0e6d7d1afbcc6547b92995a394ba0daed07a2420be08220a5a1336c6731f0bfa"] .unchecked_into(), - //5F7BEa1LGFksUihyatf3dCDYneB8pWzVyavnByCsm5nBgezi - hex!["86975a37211f8704e947a365b720f7a3e2757988eaa7d0f197e83dba355ef743"] - .unchecked_into(), //5CP6oGfwqbEfML8efqm1tCZsUgRsJztp9L8ZkEUxA16W8PPz hex!["0e07a51d3213842f8e9363ce8e444255990a225f87e80a3d651db7841e1a0205"] .unchecked_into(), @@ -452,9 +429,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5HnDVBN9mD6mXyx8oryhDbJtezwNSj1VRXgLoYCBA6uEkiao hex!["fcd5f87a6fd5707a25122a01b4dac0a8482259df7d42a9a096606df1320df08d"] .unchecked_into(), - //5DhyXZiuB1LvqYKFgT5tRpgGsN3is2cM9QxgW7FikvakbAZP - hex!["48a910c0af90898f11bd57d37ceaea53c78994f8e1833a7ade483c9a84bde055"] - .unchecked_into(), //5EPEWRecy2ApL5n18n3aHyU1956zXTRqaJpzDa9DoqiggNwF hex!["669a10892119453e9feb4e3f1ee8e028916cc3240022920ad643846fbdbee816"] .unchecked_into(), @@ -479,9 +453,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5HAes2RQYPbYKbLBfKb88f4zoXv6pPA6Ke8CjN7dob3GpmSP hex!["e1b68fbd84333e31486c08e6153d9a1415b2e7e71b413702b7d64e9b631184a1"] .unchecked_into(), - //5HTXBf36LXmkFWJLokNUK6fPxVpkr2ToUnB1pvaagdGu4c1T - hex!["ee93e26259decb89afcf17ef2aa0fa2db2e1042fb8f56ecfb24d19eae8629878"] - .unchecked_into(), //5FtAGDZYJKXkhVhAxCQrXmaP7EE2mGbBMfmKDHjfYDgq2BiU hex!["a8e61ffacafaf546283dc92d14d7cc70ea0151a5dd81fdf73ff5a2951f2b6037"] .unchecked_into(), @@ -506,9 +477,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5DJV3zCBTJBLGNDCcdWrYxWDacSz84goGTa4pFeKVvehEBte hex!["36be9069cdb4a8a07ecd51f257875150f0a8a1be44a10d9d98dabf10a030aef4"] .unchecked_into(), - //5FHf8kpK4fPjEJeYcYon2gAPwEBubRvtwpzkUbhMWSweKPUY - hex!["8e95b9b5b4dc69790b67b566567ca8bf8cdef3a3a8bb65393c0d1d1c87cd2d2c"] - .unchecked_into(), //5F9FsRjpecP9GonktmtFL3kjqNAMKjHVFjyjRdTPa4hbQRZA hex!["882d72965e642677583b333b2d173ac94b5fd6c405c76184bb14293be748a13b"] .unchecked_into(), @@ -533,9 +501,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5EX1JBghGbQqWohTPU6msR9qZ2nYPhK9r3RTQ2oD1K8TCxaG hex!["6c878e33b83c20324238d22240f735457b6fba544b383e70bb62a27b57380c81"] .unchecked_into(), - //5GqL8RbVAuNXpDhjQi1KrS1MyNuKhvus2AbmQwRGjpuGZmFu - hex!["d2f9d537ffa59919a4028afdb627c14c14c97a1547e13e8e82203d2049b15b1a"] - .unchecked_into(), //5EUNaBpX9mJgcmLQHyG5Pkms6tbDiKuLbeTEJS924Js9cA1N hex!["6a8570b9c6408e54bacf123cc2bb1b0f087f9c149147d0005badba63a5a4ac01"] .unchecked_into(), @@ -560,9 +525,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5GzDPGbUM9uH52ZEwydasTj8edokGUJ7vEpoFWp9FE1YNuFB hex!["d9c056c98ca0e6b4eb7f5c58c007c1db7be0fe1f3776108f797dd4990d1ccc33"] .unchecked_into(), - //5GWZbVkJEfWZ7fRca39YAQeqri2Z7pkeHyd7rUctUHyQifLp - hex!["c4a980da30939d5bb9e4a734d12bf81259ae286aa21fa4b65405347fa40eff35"] - .unchecked_into(), //5CmLCFeSurRXXtwMmLcVo7sdJ9EqDguvJbuCYDcHkr3cpqyE hex!["1efc23c0b51ad609ab670ecf45807e31acbd8e7e5cb7c07cf49ee42992d2867c"] .unchecked_into(), @@ -587,9 +549,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5DnEySxbnppWEyN8cCLqvGjAorGdLRg2VmkY96dbJ1LHFK8N hex!["4bea0b37e0cce9bddd80835fa2bfd5606f5dcfb8388bbb10b10c483f0856cf14"] .unchecked_into(), - //5E1Y1FJ7dVP7qtE3wm241pTm72rTMcDT5Jd8Czv7Pwp7N3AH - hex!["560d90ca51e9c9481b8a9810060e04d0708d246714960439f804e5c6f40ca651"] - .unchecked_into(), //5CAC278tFCHAeHYqE51FTWYxHmeLcENSS1RG77EFRTvPZMJT hex!["042f07fc5268f13c026bbe199d63e6ac77a0c2a780f71cda05cee5a6f1b3f11f"] .unchecked_into(), @@ -614,9 +573,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { //5DrA2fZdzmNqT5j6DXNwVxPBjDV9jhkAqvjt6Us3bQHKy3cF hex!["4ee66173993dd0db5d628c4c9cb61a27b76611ad3c3925947f0d0011ee2c5dcc"] .unchecked_into(), - //5FNFDUGNLUtqg5LgrwYLNmBiGoP8KRxsvQpBkc7GQP6qaBUG - hex!["92156f54a114ee191415898f2da013d9db6a5362d6b36330d5fc23e27360ab66"] - .unchecked_into(), //5Gx6YeNhynqn8qkda9QKpc9S7oDr4sBrfAu516d3sPpEt26F hex!["d822d4088b20dca29a580a577a97d6f024bb24c9550bebdfd7d2d18e946a1c7d"] .unchecked_into(), @@ -657,7 +613,6 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { x.5.clone(), x.6.clone(), x.7.clone(), - x.8.clone(), ), ) }) @@ -768,35 +723,24 @@ pub fn get_authority_keys_from_seed( AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, BeefyId, ) { let keys = get_authority_keys_from_seed_no_beefy(seed); - (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, keys.7, get_from_seed::(seed)) + (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, get_from_seed::(seed)) } /// Helper function to generate stash, controller and session key from seed pub fn get_authority_keys_from_seed_no_beefy( seed: &str, -) -> ( - AccountId, - AccountId, - BabeId, - GrandpaId, - ImOnlineId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, -) { +) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( get_account_id_from_seed::(&format!("{}//stash", seed)), get_account_id_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), - get_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), @@ -829,7 +773,6 @@ pub fn westend_testnet_genesis( AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, @@ -861,7 +804,6 @@ pub fn westend_testnet_genesis( x.5.clone(), x.6.clone(), x.7.clone(), - x.8.clone(), ), ) }) @@ -899,7 +841,6 @@ pub fn rococo_testnet_genesis( AccountId, BabeId, GrandpaId, - ImOnlineId, ValidatorId, AssignmentId, AuthorityDiscoveryId, @@ -930,7 +871,6 @@ pub fn rococo_testnet_genesis( x.5.clone(), x.6.clone(), x.7.clone(), - x.8.clone(), ), ) }) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 12388da1868..5ac92a73732 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -78,7 +78,6 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; -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}; @@ -90,7 +89,8 @@ use sp_runtime::{ Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, + ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, + RuntimeAppPublic, RuntimeDebug, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -354,14 +354,53 @@ impl pallet_timestamp::Config for Runtime { impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = ImOnline; + type EventHandler = (); +} + +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +pub struct OldSessionKeys { + pub grandpa: ::Public, + pub babe: ::Public, + pub im_online: pallet_im_online::sr25519::AuthorityId, + pub para_validator: ::Public, + pub para_assignment: ::Public, + pub authority_discovery: ::Public, + pub beefy: ::Public, +} + +impl OpaqueKeys for OldSessionKeys { + type KeyTypeIdProviders = (); + fn key_ids() -> &'static [KeyTypeId] { + &[ + <::Public>::ID, + <::Public>::ID, + sp_core::crypto::key_types::IM_ONLINE, + <::Public>::ID, + <::Public>::ID, + <::Public>::ID, + <::Public>::ID, + ] + } + fn get_raw(&self, i: KeyTypeId) -> &[u8] { + match i { + <::Public>::ID => self.grandpa.as_ref(), + <::Public>::ID => self.babe.as_ref(), + sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), + <::Public>::ID => self.para_validator.as_ref(), + <::Public>::ID => + self.para_assignment.as_ref(), + <::Public>::ID => + self.authority_discovery.as_ref(), + <::Public>::ID => self.beefy.as_ref(), + _ => &[], + } + } } 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, @@ -369,6 +408,18 @@ impl_opaque_keys! { } } +// remove this when removing `OldSessionKeys` +fn transform_session_keys(_val: AccountId, old: OldSessionKeys) -> SessionKeys { + SessionKeys { + grandpa: old.grandpa, + babe: old.babe, + para_validator: old.para_validator, + para_assignment: old.para_assignment, + authority_discovery: old.authority_discovery, + beefy: old.beefy, + } +} + /// Special `ValidatorIdOf` implementation that is just returning the input as result. pub struct ValidatorIdOf; impl sp_runtime::traits::Convert> for ValidatorIdOf { @@ -513,22 +564,6 @@ 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 const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); } @@ -778,7 +813,6 @@ impl InstanceFilter for ProxyType { // Specifically omitting the entire Balances pallet RuntimeCall::Session(..) | RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | RuntimeCall::Treasury(..) | RuntimeCall::Bounties(..) | RuntimeCall::ChildBounties(..) | @@ -1292,8 +1326,7 @@ construct_runtime! { 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. + // Authorship must be before session in order to note author in the correct session and era. Authorship: pallet_authorship::{Pallet, Storage} = 5, Offences: pallet_offences::{Pallet, Storage, Event} = 7, Historical: session_historical::{Pallet} = 34, @@ -1307,7 +1340,6 @@ construct_runtime! { 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; uncallable initially. @@ -1453,6 +1485,8 @@ pub mod migrations { use frame_support::traits::LockIdentifier; use frame_system::pallet_prelude::BlockNumberFor; + #[cfg(feature = "try-runtime")] + use sp_core::crypto::ByteArray; parameter_types! { pub const DemocracyPalletName: &'static str = "Democracy"; @@ -1461,6 +1495,7 @@ pub mod migrations { pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; pub const TipsPalletName: &'static str = "Tips"; + pub const ImOnlinePalletName: &'static str = "ImOnline"; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; } @@ -1497,10 +1532,82 @@ pub mod migrations { type PalletName = TipsPalletName; } + /// Upgrade Session keys to exclude `ImOnline` key. + /// When this is removed, should also remove `OldSessionKeys`. + pub struct UpgradeSessionKeys; + const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; + + impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); + return Ok(Vec::new()) + } + + log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); + let key_ids = SessionKeys::key_ids(); + frame_support::ensure!( + key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, + "New session keys contain the ImOnline key that should have been removed", + ); + let storage_key = pallet_session::QueuedKeys::::hashed_key(); + let mut state: Vec = Vec::new(); + frame_support::storage::unhashed::get::>( + &storage_key, + ) + .ok_or::("Queued keys are not available".into())? + .into_iter() + .for_each(|(id, keys)| { + state.extend_from_slice(id.as_slice()); + for key_id in key_ids { + state.extend_from_slice(keys.get_raw(*key_id)); + } + }); + frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); + Ok(state) + } + + fn on_runtime_upgrade() -> Weight { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::info!("Skipping session keys upgrade: already applied"); + return ::DbWeight::get().reads(1) + } + log::trace!("Upgrading session keys"); + Session::upgrade_keys::(transform_session_keys); + Perbill::from_percent(50) * BlockWeights::get().max_block + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade( + old_state: sp_std::vec::Vec, + ) -> Result<(), sp_runtime::TryRuntimeError> { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); + return Ok(()) + } + + let key_ids = SessionKeys::key_ids(); + let mut new_state: Vec = Vec::new(); + pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { + new_state.extend_from_slice(id.as_slice()); + for key_id in key_ids { + new_state.extend_from_slice(keys.get_raw(*key_id)); + } + }); + frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); + frame_support::ensure!( + old_state == new_state, + "Pre-upgrade and post-upgrade keys do not match!" + ); + log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); + Ok(()) + } + } + /// Unreleased migrations. Add new ones here: pub type Unreleased = ( pallet_society::migrations::MigrateToV2, - pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, assigned_slots::migration::v1::MigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, @@ -1527,6 +1634,12 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, + + // Upgrade `SessionKeys` to exclude `ImOnline` + UpgradeSessionKeys, + + // Remove `im-online` pallet on-chain storage + frame_support::migrations::RemovePallet::DbWeight>, ); } @@ -1597,7 +1710,6 @@ mod benches { [pallet_conviction_voting, ConvictionVoting] [pallet_nis, Nis] [pallet_identity, Identity] - [pallet_im_online, ImOnline] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index bb6331e9534..f7ff2d5e9e1 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -41,7 +41,6 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -88,7 +87,8 @@ use sp_runtime::{ IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, + ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, + RuntimeAppPublic, }; use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -417,7 +417,7 @@ impl pallet_timestamp::Config for Runtime { impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (Staking, ImOnline); + type EventHandler = Staking; } parameter_types! { @@ -425,11 +425,50 @@ parameter_types! { pub const Offset: BlockNumber = 0; } +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +pub struct OldSessionKeys { + pub grandpa: ::Public, + pub babe: ::Public, + pub im_online: pallet_im_online::sr25519::AuthorityId, + pub para_validator: ::Public, + pub para_assignment: ::Public, + pub authority_discovery: ::Public, + pub beefy: ::Public, +} + +impl OpaqueKeys for OldSessionKeys { + type KeyTypeIdProviders = (); + fn key_ids() -> &'static [KeyTypeId] { + &[ + <::Public>::ID, + <::Public>::ID, + sp_core::crypto::key_types::IM_ONLINE, + <::Public>::ID, + <::Public>::ID, + <::Public>::ID, + <::Public>::ID, + ] + } + fn get_raw(&self, i: KeyTypeId) -> &[u8] { + match i { + <::Public>::ID => self.grandpa.as_ref(), + <::Public>::ID => self.babe.as_ref(), + sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), + <::Public>::ID => self.para_validator.as_ref(), + <::Public>::ID => + self.para_assignment.as_ref(), + <::Public>::ID => + self.authority_discovery.as_ref(), + <::Public>::ID => self.beefy.as_ref(), + _ => &[], + } + } +} + 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, @@ -437,6 +476,18 @@ impl_opaque_keys! { } } +// remove this when removing `OldSessionKeys` +fn transform_session_keys(_v: AccountId, old: OldSessionKeys) -> SessionKeys { + SessionKeys { + grandpa: old.grandpa, + babe: old.babe, + para_validator: old.para_validator, + para_assignment: old.para_assignment, + authority_discovery: old.authority_discovery, + beefy: old.beefy, + } +} + impl pallet_session::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; @@ -744,19 +795,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(); -} - -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! { @@ -986,7 +1024,6 @@ impl InstanceFilter for ProxyType { RuntimeCall::Staking(..) | RuntimeCall::Session(..) | RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | RuntimeCall::Utility(..) | RuntimeCall::Identity(..) | RuntimeCall::ConvictionVoting(..) | @@ -1374,8 +1411,7 @@ construct_runtime! { TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 26, // Consensus support. - // Authorship must be before session in order to note author in the correct session and era - // for im-online and staking. + // Authorship must be before session in order to note author in the correct session and era. Authorship: pallet_authorship::{Pallet, Storage} = 5, Staking: pallet_staking::{Pallet, Call, Storage, Config, Event} = 6, Offences: pallet_offences::{Pallet, Storage, Event} = 7, @@ -1390,7 +1426,6 @@ construct_runtime! { 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, // Utility module. @@ -1522,10 +1557,88 @@ pub type Migrations = migrations::Unreleased; #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; + #[cfg(feature = "try-runtime")] + use sp_core::crypto::ByteArray; + + parameter_types! { + pub const ImOnlinePalletName: &'static str = "ImOnline"; + } + + /// Upgrade Session keys to exclude `ImOnline` key. + /// When this is removed, should also remove `OldSessionKeys`. + pub struct UpgradeSessionKeys; + const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; + + impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); + return Ok(Vec::new()) + } + + log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); + let key_ids = SessionKeys::key_ids(); + frame_support::ensure!( + key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, + "New session keys contain the ImOnline key that should have been removed", + ); + let storage_key = pallet_session::QueuedKeys::::hashed_key(); + let mut state: Vec = Vec::new(); + frame_support::storage::unhashed::get::>( + &storage_key, + ) + .ok_or::("Queued keys are not available".into())? + .into_iter() + .for_each(|(id, keys)| { + state.extend_from_slice(id.as_slice()); + for key_id in key_ids { + state.extend_from_slice(keys.get_raw(*key_id)); + } + }); + frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); + Ok(state) + } + + fn on_runtime_upgrade() -> Weight { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::warn!("Skipping session keys upgrade: already applied"); + return ::DbWeight::get().reads(1) + } + log::info!("Upgrading session keys"); + Session::upgrade_keys::(transform_session_keys); + Perbill::from_percent(50) * BlockWeights::get().max_block + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade( + old_state: sp_std::vec::Vec, + ) -> Result<(), sp_runtime::TryRuntimeError> { + if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { + log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); + return Ok(()) + } + + let key_ids = SessionKeys::key_ids(); + let mut new_state: Vec = Vec::new(); + pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { + new_state.extend_from_slice(id.as_slice()); + for key_id in key_ids { + new_state.extend_from_slice(keys.get_raw(*key_id)); + } + }); + frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); + frame_support::ensure!( + old_state == new_state, + "Pre-upgrade and post-upgrade keys do not match!" + ); + log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); + Ok(()) + } + } /// Unreleased migrations. Add new ones here: pub type Unreleased = ( - pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, pallet_staking::migrations::v14::MigrateToV14, assigned_slots::migration::v1::MigrateToV1, @@ -1537,6 +1650,11 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, pallet_nomination_pools::migration::versioned::V7ToV8, + UpgradeSessionKeys, + frame_support::migrations::RemovePallet< + ImOnlinePalletName, + ::DbWeight, + >, ); } @@ -1583,7 +1701,6 @@ mod benches { [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] diff --git a/substrate/frame/offences/benchmarking/src/lib.rs b/substrate/frame/offences/benchmarking/src/lib.rs index c190927b84b..563aa4755ce 100644 --- a/substrate/frame/offences/benchmarking/src/lib.rs +++ b/substrate/frame/offences/benchmarking/src/lib.rs @@ -25,30 +25,25 @@ mod mock; use sp_std::{prelude::*, vec}; use frame_benchmarking::v1::{account, benchmarks}; -use frame_support::traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}; +use frame_support::traits::{Currency, Get}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; -#[cfg(test)] -use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::{ traits::{Convert, Saturating, StaticLookup}, Perbill, }; -use sp_staking::offence::{Offence, ReportOffence}; +use sp_staking::offence::ReportOffence; use pallet_babe::EquivocationOffence as BabeEquivocationOffence; use pallet_balances::Config as BalancesConfig; use pallet_grandpa::{ EquivocationOffence as GrandpaEquivocationOffence, TimeSlot as GrandpaTimeSlot, }; -use pallet_im_online::{Config as ImOnlineConfig, Pallet as ImOnline, UnresponsivenessOffence}; use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; use pallet_session::{ historical::{Config as HistoricalConfig, IdentificationTuple}, - Config as SessionConfig, SessionManager, + Config as SessionConfig, Pallet as Session, SessionManager, }; -#[cfg(test)] -use pallet_staking::Event as StakingEvent; use pallet_staking::{ Config as StakingConfig, Exposure, IndividualExposure, MaxNominationsOf, Pallet as Staking, RewardDestination, ValidatorPrefs, @@ -56,8 +51,6 @@ use pallet_staking::{ const SEED: u32 = 0; -const MAX_REPORTERS: u32 = 100; -const MAX_OFFENDERS: u32 = 100; const MAX_NOMINATORS: u32 = 100; pub struct Pallet(Offences); @@ -66,7 +59,6 @@ pub trait Config: SessionConfig + StakingConfig + OffencesConfig - + ImOnlineConfig + HistoricalConfig + BalancesConfig + IdTupleConvert @@ -184,220 +176,7 @@ fn make_offenders( Ok((id_tuples, offenders)) } -fn make_offenders_im_online( - num_offenders: u32, - num_nominators: u32, -) -> Result<(Vec>, Vec>), &'static str> { - Staking::::new_session(0); - - let mut offenders = vec![]; - for i in 0..num_offenders { - let offender = create_offender::(i + 1, num_nominators)?; - offenders.push(offender); - } - - Staking::::start_session(0); - - let id_tuples = offenders - .iter() - .map(|offender| { - < - ::ValidatorSet as ValidatorSet - >::ValidatorIdOf::convert(offender.controller.clone()) - .expect("failed to get validator id from account id") - }) - .map(|validator_id| { - < - ::ValidatorSet as ValidatorSetWithIdentification - >::IdentificationOf::convert(validator_id.clone()) - .map(|full_id| (validator_id, full_id)) - .expect("failed to convert validator id to full identification") - }) - .collect::>>(); - Ok((id_tuples, offenders)) -} - -#[cfg(test)] -fn check_events< - T: Config, - I: Iterator, - Item: sp_std::borrow::Borrow<::RuntimeEvent> + sp_std::fmt::Debug, ->( - expected: I, -) { - let events = System::::events() - .into_iter() - .map(|frame_system::EventRecord { event, .. }| event) - .collect::>(); - let expected = expected.collect::>(); - - fn pretty(header: &str, ev: &[D], offset: usize) { - log::info!("{}", header); - for (idx, ev) in ev.iter().enumerate() { - log::info!("\t[{:04}] {:?}", idx + offset, ev); - } - } - fn print_events( - idx: usize, - events: &[D], - expected: &[E], - ) { - let window = 10; - let start = idx.saturating_sub(window / 2); - let end_got = (idx + window / 2).min(events.len()); - pretty("Got(window):", &events[start..end_got], start); - let end_expected = (idx + window / 2).min(expected.len()); - pretty("Expected(window):", &expected[start..end_expected], start); - log::info!("---------------"); - let start_got = events.len().saturating_sub(window); - pretty("Got(end):", &events[start_got..], start_got); - let start_expected = expected.len().saturating_sub(window); - pretty("Expected(end):", &expected[start_expected..], start_expected); - } - - for (idx, (a, b)) in events.iter().zip(expected.iter()).enumerate() { - if a != sp_std::borrow::Borrow::borrow(b) { - print_events(idx, &events, &expected); - log::info!("Mismatch at: {}", idx); - log::info!(" Got: {:?}", b); - log::info!("Expected: {:?}", a); - if events.len() != expected.len() { - log::info!( - "Mismatching lengths. Got: {}, Expected: {}", - events.len(), - expected.len() - ) - } - panic!("Mismatching events."); - } - } - - if events.len() != expected.len() { - print_events(0, &events, &expected); - panic!("Mismatching lengths. Got: {}, Expected: {}", events.len(), expected.len(),) - } -} - benchmarks! { - report_offence_im_online { - let r in 1 .. MAX_REPORTERS; - // we skip 1 offender, because in such case there is no slashing - let o in 2 .. MAX_OFFENDERS; - let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); - - // Make r reporters - let mut reporters = vec![]; - for i in 0 .. r { - let reporter = account("reporter", i, SEED); - reporters.push(reporter); - } - - // make sure reporters actually get rewarded - Staking::::set_slash_reward_fraction(Perbill::one()); - - let (offenders, raw_offenders) = make_offenders_im_online::(o, n)?; - let keys = ImOnline::::keys(); - let validator_set_count = keys.len() as u32; - let offenders_count = offenders.len() as u32; - let offence = UnresponsivenessOffence { - session_index: 0, - validator_set_count, - offenders, - }; - let slash_fraction = offence.slash_fraction(offenders_count); - assert_eq!(System::::event_count(), 0); - }: { - let _ = ::ReportUnresponsiveness::report_offence( - reporters.clone(), - offence - ); - } - verify { - #[cfg(test)] - { - let bond_amount: u32 = UniqueSaturatedInto::::unique_saturated_into(bond_amount::()); - let slash_amount = slash_fraction * bond_amount; - let reward_amount = slash_amount.saturating_mul(1 + n) / 2; - let reward = reward_amount / r; - let slash_report = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::SlashReported{ validator: id, fraction: slash_fraction, slash_era: 0}) - ); - let slash = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Slashed{ staker: id, amount: BalanceOf::::from(slash_amount) }) - ); - let balance_slash = |id| core::iter::once( - ::RuntimeEvent::from(pallet_balances::Event::::Slashed{ who: id, amount: slash_amount.into() }) - ); - let balance_locked = |id| core::iter::once( - ::RuntimeEvent::from(pallet_balances::Event::::Locked{ who: id, amount: slash_amount.into() }) - ); - let balance_unlocked = |id| core::iter::once( - ::RuntimeEvent::from(pallet_balances::Event::::Unlocked{ who: id, amount: slash_amount.into() }) - ); - let chill = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Chilled{ stash: id }) - ); - let balance_deposit = |id, amount: u32| - ::RuntimeEvent::from(pallet_balances::Event::::Deposit{ who: id, amount: amount.into() }); - let mut first = true; - - // We need to box all events to prevent running into too big allocations in wasm. - // The event in FRAME is represented as an enum and the size of the enum depends on the biggest variant. - // So, instead of requiring `size_of() * expected_events` we only need to - // allocate `size_of>() * expected_events`. - let slash_events = raw_offenders.into_iter() - .flat_map(|offender| { - let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { - balance_slash(nom.clone()).map(Into::into) - .chain(balance_unlocked(nom.clone()).map(Into::into)) - .chain(slash(nom).map(Into::into)).map(Box::new) - }); - - let events = chill(offender.stash.clone()).map(Into::into).map(Box::new) - .chain(slash_report(offender.stash.clone()).map(Into::into).map(Box::new)) - .chain(balance_slash(offender.stash.clone()).map(Into::into).map(Box::new)) - .chain(balance_unlocked(offender.stash.clone()).map(Into::into).map(Box::new)) - .chain(slash(offender.stash).map(Into::into).map(Box::new)) - .chain(nom_slashes) - .collect::>(); - - // the first deposit creates endowed events, see `endowed_reward_events` - if first { - first = false; - let reward_events = reporters.iter() - .flat_map(|reporter| vec![ - Box::new(balance_deposit(reporter.clone(), reward).into()), - Box::new(frame_system::Event::::NewAccount { account: reporter.clone() }.into()), - Box::new(::RuntimeEvent::from( - pallet_balances::Event::::Endowed{ account: reporter.clone(), free_balance: reward.into() } - ).into()), - ]) - .collect::>(); - events.into_iter().chain(reward_events) - } else { - let reward_events = reporters.iter() - .map(|reporter| Box::new(balance_deposit(reporter.clone(), reward).into())) - .collect::>(); - events.into_iter().chain(reward_events) - } - }); - - // In case of error it's useful to see the inputs - log::info!("Inputs: r: {}, o: {}, n: {}", r, o, n); - // make sure that all slashes have been applied - check_events::( - sp_std::iter::empty() - .chain(slash_events) - .chain(sp_std::iter::once(Box::new(::RuntimeEvent::from( - pallet_offences::Event::Offence{ - kind: UnresponsivenessOffence::::ID, - timeslot: 0_u32.to_le_bytes().to_vec(), - } - ).into()))) - ); - } - } - report_offence_grandpa { let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); @@ -409,12 +188,12 @@ benchmarks! { Staking::::set_slash_reward_fraction(Perbill::one()); let (mut offenders, raw_offenders) = make_offenders::(1, n)?; - let keys = ImOnline::::keys(); + let validator_set_count = Session::::validators().len() as u32; let offence = GrandpaEquivocationOffence { time_slot: GrandpaTimeSlot { set_id: 0, round: 0 }, session_index: 0, - validator_set_count: keys.len() as u32, + validator_set_count, offender: T::convert(offenders.pop().unwrap()), }; assert_eq!(System::::event_count(), 0); @@ -446,12 +225,12 @@ benchmarks! { Staking::::set_slash_reward_fraction(Perbill::one()); let (mut offenders, raw_offenders) = make_offenders::(1, n)?; - let keys = ImOnline::::keys(); + let validator_set_count = Session::::validators().len() as u32; let offence = BabeEquivocationOffence { slot: 0u64.into(), session_index: 0, - validator_set_count: keys.len() as u32, + validator_set_count, offender: T::convert(offenders.pop().unwrap()), }; assert_eq!(System::::event_count(), 0); -- GitLab From b0b4451f31dcd9da04e2952d7c4cdcc219271b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:00:18 +0000 Subject: [PATCH 602/633] polkadot: remove grandpa pause support (#2511) This was never used and we probably don't need it anyway. --- .../src/lib.rs | 1 - polkadot/cli/src/cli.rs | 10 - polkadot/cli/src/command.rs | 7 - polkadot/node/service/src/grandpa_support.rs | 178 ------------------ polkadot/node/service/src/lib.rs | 26 +-- polkadot/node/test/service/src/lib.rs | 1 - .../adder/collator/src/main.rs | 1 - .../undying/collator/src/main.rs | 1 - 8 files changed, 3 insertions(+), 222 deletions(-) diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 3d297af00f2..4096cd2523f 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -283,7 +283,6 @@ fn build_polkadot_full_node( config, polkadot_service::NewFullParams { is_parachain_node, - grandpa_pause: None, // Disable BEEFY. It should not be required by the internal relay chain node. enable_beefy: false, force_authoring_backoff: false, diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 6a7a8b4ad7b..f1e0d1e99d7 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -82,16 +82,6 @@ pub struct RunCmd { #[arg(long = "force-rococo")] pub force_rococo: bool, - /// Setup a GRANDPA scheduled voting pause. - /// - /// This parameter takes two values, namely a block number and a delay (in blocks). - /// - /// After the given block number is finalized the GRANDPA voter will temporarily - /// stop voting for new blocks until the given delay has elapsed (i.e. until a - /// block at height `pause_block + delay` is imported). - #[arg(long = "grandpa-pause", num_args = 2)] - pub grandpa_pause: Vec, - /// Disable the BEEFY gadget. /// /// Currently enabled by default on 'Rococo', 'Wococo' and 'Versi'. diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index c9c3c39aab1..ba41383c279 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -215,12 +215,6 @@ where set_default_ss58_version(chain_spec); - let grandpa_pause = if cli.run.grandpa_pause.is_empty() { - None - } else { - Some((cli.run.grandpa_pause[0], cli.run.grandpa_pause[1])) - }; - if chain_spec.is_kusama() { info!("----------------------------"); info!("This chain is not in any way"); @@ -257,7 +251,6 @@ where config, service::NewFullParams { is_parachain_node: service::IsParachainNode::No, - grandpa_pause, enable_beefy, force_authoring_backoff: cli.run.force_authoring_backoff, jaeger_agent, diff --git a/polkadot/node/service/src/grandpa_support.rs b/polkadot/node/service/src/grandpa_support.rs index 3a767d9783f..729dbfde5c7 100644 --- a/polkadot/node/service/src/grandpa_support.rs +++ b/polkadot/node/service/src/grandpa_support.rs @@ -16,8 +16,6 @@ //! Polkadot-specific GRANDPA integration utilities. -use std::sync::Arc; - use sp_runtime::traits::{Block as BlockT, Header as _, NumberFor}; use crate::HeaderProvider; @@ -59,55 +57,6 @@ where } } -/// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the -/// same last finalized block) after a given block at height `N` has been -/// finalized and for a delay of `M` blocks, i.e. until the best block reaches -/// `N` + `M`, the voter will keep voting for block `N`. -#[derive(Clone)] -pub(crate) struct PauseAfterBlockFor(pub(crate) N, pub(crate) N); - -impl grandpa::VotingRule for PauseAfterBlockFor> -where - Block: BlockT, - B: sp_blockchain::HeaderBackend + 'static, -{ - fn restrict_vote( - &self, - backend: Arc, - base: &Block::Header, - best_target: &Block::Header, - current_target: &Block::Header, - ) -> grandpa::VotingRuleResult { - let aux = || { - // only restrict votes targeting a block higher than the block - // we've set for the pause - if *current_target.number() > self.0 { - // if we're past the pause period (i.e. `self.0 + self.1`) - // then we no longer need to restrict any votes - if *best_target.number() > self.0 + self.1 { - return None - } - - // if we've finalized the pause block, just keep returning it - // until best number increases enough to pass the condition above - if *base.number() >= self.0 { - return Some((base.hash(), *base.number())) - } - - // otherwise find the target header at the pause block - // to vote on - return walk_backwards_to_target_block(&*backend, self.0, current_target).ok() - } - - None - }; - - let target = aux(); - - Box::pin(async move { target }) - } -} - /// GRANDPA hard forks due to borked migration of session keys after a runtime /// upgrade (at #1491596), the signaled authority set changes were invalid /// (blank keys) and were impossible to finalize. The authorities for these @@ -214,130 +163,3 @@ pub(crate) fn kusama_hard_forks() -> Vec> { }) .collect() } - -#[cfg(test)] -mod tests { - use consensus_common::BlockOrigin; - use grandpa::VotingRule; - use polkadot_test_client::{ - ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, - TestClientBuilder, TestClientBuilderExt, - }; - use sp_blockchain::HeaderBackend; - use sp_runtime::traits::Header; - use std::sync::Arc; - - #[test] - fn grandpa_pause_voting_rule_works() { - let _ = env_logger::try_init(); - - let client = Arc::new(TestClientBuilder::new().build()); - let mut hashes = vec![]; - hashes.push(client.info().genesis_hash); - - let mut push_blocks = { - let mut client = client.clone(); - - move |hashes: &mut Vec<_>, n| { - for _ in 0..n { - let block = client.init_polkadot_block_builder().build().unwrap().block; - hashes.push(block.header.hash()); - futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); - } - } - }; - - let get_header = { - let client = client.clone(); - move |n| client.expect_header(n).unwrap() - }; - - // the rule should filter all votes after block #20 - // is finalized until block #50 is imported. - let voting_rule = super::PauseAfterBlockFor(20, 30); - - // add 10 blocks - push_blocks(&mut hashes, 10); - assert_eq!(client.info().best_number, 10); - - // we have not reached the pause block - // therefore nothing should be restricted - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &get_header(hashes[0]), - &get_header(hashes[10]), - &get_header(hashes[10]) - )), - None, - ); - - // add 15 more blocks - // best block: #25 - push_blocks(&mut hashes, 15); - - // we are targeting the pause block, - // the vote should not be restricted - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &get_header(hashes[10]), - &get_header(hashes[20]), - &get_header(hashes[20]) - )), - None, - ); - - // we are past the pause block, votes should - // be limited to the pause block. - let pause_block = get_header(hashes[20]); - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &get_header(hashes[10]), - &get_header(hashes[21]), - &get_header(hashes[21]) - )), - Some((pause_block.hash(), *pause_block.number())), - ); - - // we've finalized the pause block, so we'll keep - // restricting our votes to it. - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &pause_block, // #20 - &get_header(hashes[21]), - &get_header(hashes[21]), - )), - Some((pause_block.hash(), *pause_block.number())), - ); - - // add 30 more blocks - // best block: #55 - push_blocks(&mut hashes, 30); - - // we're at the last block of the pause, this block - // should still be considered in the pause period - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &pause_block, // #20 - &get_header(hashes[50]), - &get_header(hashes[50]), - )), - Some((pause_block.hash(), *pause_block.number())), - ); - - // we're past the pause period, no votes should be filtered - assert_eq!( - futures::executor::block_on(voting_rule.restrict_vote( - client.clone(), - &pause_block, // #20 - &get_header(hashes[51]), - &get_header(hashes[51]), - )), - None, - ); - } -} diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index fafdc586009..5069ec467c9 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -623,7 +623,6 @@ where #[cfg(feature = "full-node")] pub struct NewFullParams { pub is_parachain_node: IsParachainNode, - pub grandpa_pause: Option<(u32, u32)>, pub enable_beefy: bool, /// Whether to enable the block authoring backoff on production networks /// where it isn't enabled by default. @@ -717,7 +716,6 @@ pub fn new_full( mut config: Configuration, NewFullParams { is_parachain_node, - grandpa_pause, enable_beefy, force_authoring_backoff, jaeger_agent, @@ -1248,32 +1246,14 @@ pub fn new_full( // provide better guarantees of block and vote data availability than // the observer. - // add a custom voting rule to temporarily stop voting for new blocks - // after the given pause block is finalized and restarting after the - // given delay. - let mut builder = grandpa::VotingRulesBuilder::default(); + let mut voting_rules_builder = grandpa::VotingRulesBuilder::default(); #[cfg(not(feature = "malus"))] let _malus_finality_delay = None; if let Some(delay) = _malus_finality_delay { info!(?delay, "Enabling malus finality delay",); - builder = builder.add(grandpa::BeforeBestBlockBy(delay)); - }; - - let voting_rule = match grandpa_pause { - Some((block, delay)) => { - info!( - block_number = %block, - delay = %delay, - "GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.", - block, - delay, - ); - - builder.add(grandpa_support::PauseAfterBlockFor(block, delay)).build() - }, - None => builder.build(), + voting_rules_builder = voting_rules_builder.add(grandpa::BeforeBestBlockBy(delay)); }; let grandpa_config = grandpa::GrandpaParams { @@ -1281,7 +1261,7 @@ pub fn new_full( link: link_half, network: network.clone(), sync: sync_service.clone(), - voting_rule, + voting_rule: voting_rules_builder.build(), prometheus_registry: prometheus_registry.clone(), shared_voter_state, telemetry: telemetry.as_ref().map(|x| x.handle()), diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index a8352b60751..312113869bc 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -80,7 +80,6 @@ pub fn new_full( config, polkadot_service::NewFullParams { is_parachain_node, - grandpa_pause: None, enable_beefy: true, force_authoring_backoff: false, jaeger_agent: None, diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index 1558df6708d..3984026f511 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -62,7 +62,6 @@ fn main() -> Result<()> { is_parachain_node: polkadot_service::IsParachainNode::Collator( collator.collator_key(), ), - grandpa_pause: None, enable_beefy: false, force_authoring_backoff: false, jaeger_agent: None, diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index 1db1b6f1102..d70a98c7ef6 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -82,7 +82,6 @@ fn main() -> Result<()> { is_parachain_node: polkadot_service::IsParachainNode::Collator( collator.collator_key(), ), - grandpa_pause: None, enable_beefy: false, force_authoring_backoff: false, jaeger_agent: None, -- GitLab From ec3a61ed86305e5b70ce6e466cf127addf560186 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 28 Nov 2023 16:59:06 +0100 Subject: [PATCH 603/633] Remove pov-recovery race condition/Improve zombienet test (#2526) The test was a bit flaky on CI. There was a race condition in the pov-recovery system. If the timing is bad, it can happen that a block waits for a parent that is already queued for import. The check if a block has children waiting happens when we insert into the import queue. So we need to do an additional check once we receive the import notification for the parent block. Second issue is that `alice` was missing `--in-peers 0` and `--out-peers 0`, so alice was sometimes still fetching block via sync and the assertion on the logs in zombienet would fail. There is another potential issue that I saw once locally. We have a failing pov-recovery queue that fails from time to time to check that the retry mechanism does what it should. We now make sure that the same candidate is never failed twice, so the tests become more predictable. --- cumulus/client/pov-recovery/src/lib.rs | 17 ++++++++++++++--- cumulus/test/service/src/lib.rs | 18 ++++++++++++------ cumulus/zombienet/tests/0002-pov_recovery.toml | 5 ++--- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index b9a140f55c6..32aba6c8993 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -410,6 +410,7 @@ where ?block_hash, parent_hash = ?parent, parent_scheduled_for_recovery, + waiting_blocks = self.waiting_for_parent.len(), "Waiting for recovery of parent.", ); @@ -442,13 +443,13 @@ where _ => (), } - self.import_block(block).await; + self.import_block(block); } /// Import the given `block`. /// /// This will also recursivley drain `waiting_for_parent` and import them as well. - async fn import_block(&mut self, block: Block) { + fn import_block(&mut self, block: Block) { let mut blocks = VecDeque::new(); tracing::debug!(target: LOG_TARGET, block_hash = ?block.hash(), "Importing block retrieved using pov_recovery"); @@ -551,7 +552,6 @@ where }; futures::pin_mut!(pending_candidates); - loop { select! { pending_candidate = pending_candidates.next() => { @@ -573,6 +573,17 @@ where imported = imported_blocks.next() => { if let Some(imported) = imported { self.clear_waiting_recovery(&imported.hash); + + // We need to double check that no blocks are waiting for this block. + // Can happen when a waiting child block is queued to wait for parent while the parent block is still + // in the import queue. + if let Some(waiting_blocks) = self.waiting_for_parent.remove(&imported.hash) { + for block in waiting_blocks { + tracing::debug!(target: LOG_TARGET, block_hash = ?block.hash(), resolved_parent = ?imported.hash, "Found new waiting child block during import, queuing."); + self.import_block(block); + } + }; + } else { tracing::debug!(target: LOG_TARGET, "Imported blocks stream ended"); return; diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 4d4c60d1bda..fb858ce0b71 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -27,6 +27,7 @@ mod genesis; use runtime::AccountId; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use std::{ + collections::HashSet, future::Future, net::{IpAddr, Ipv4Addr, SocketAddr}, time::Duration, @@ -57,7 +58,7 @@ use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; use frame_system_rpc_runtime_api::AccountNonceApi; use polkadot_node_subsystem::{errors::RecoveryError, messages::AvailabilityRecoveryMessage}; use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::{CollatorPair, Hash as PHash, PersistedValidationData}; +use polkadot_primitives::{CandidateHash, CollatorPair, Hash as PHash, PersistedValidationData}; use polkadot_service::ProvideRuntimeApi; use sc_consensus::ImportQueue; use sc_network::{ @@ -144,12 +145,13 @@ pub type TransactionPool = Arc>; pub struct FailingRecoveryHandle { overseer_handle: OverseerHandle, counter: u32, + failed_hashes: HashSet, } impl FailingRecoveryHandle { /// Create a new FailingRecoveryHandle pub fn new(overseer_handle: OverseerHandle) -> Self { - Self { overseer_handle, counter: 0 } + Self { overseer_handle, counter: 0, failed_hashes: Default::default() } } } @@ -160,11 +162,15 @@ impl RecoveryHandle for FailingRecoveryHandle { message: AvailabilityRecoveryMessage, origin: &'static str, ) { - // For every 5th block we immediately signal unavailability to trigger - // a retry. - if self.counter % 5 == 0 { + let AvailabilityRecoveryMessage::RecoverAvailableData(ref receipt, _, _, _) = message; + let candidate_hash = receipt.hash(); + + // For every 3rd block we immediately signal unavailability to trigger + // a retry. The same candidate is never failed multiple times to ensure progress. + if self.counter % 3 == 0 && self.failed_hashes.insert(candidate_hash) { + tracing::info!(target: LOG_TARGET, ?candidate_hash, "Failing pov recovery."); + let AvailabilityRecoveryMessage::RecoverAvailableData(_, _, _, back_sender) = message; - tracing::info!(target: LOG_TARGET, "Failing pov recovery."); back_sender .send(Err(RecoveryError::Unavailable)) .expect("Return channel should work here."); diff --git a/cumulus/zombienet/tests/0002-pov_recovery.toml b/cumulus/zombienet/tests/0002-pov_recovery.toml index 105e4a324f3..fe42fd4b2f6 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.toml +++ b/cumulus/zombienet/tests/0002-pov_recovery.toml @@ -34,13 +34,12 @@ add_to_genesis = false args = ["--disable-block-announcements"] # run 'alice' as a parachain collator who does not produce blocks - # 'alice' is a bootnode for 'bob' and 'charlie' [[parachains.collators]] name = "alice" validator = true # collator image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--use-null-consensus", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--use-null-consensus", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # run 'charlie' as a parachain full node [[parachains.collators]] @@ -48,7 +47,7 @@ add_to_genesis = false validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0","--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'bob'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0", "--", "--reserved-only", "--reserved-nodes {{'ferdie'|zombie('multiAddress')}}"] # we fail recovery for 'eve' from time to time to test retries [[parachains.collators]] -- GitLab From e71c484d5bd12330e16f568ad582e1fc1c878669 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:18:52 +0200 Subject: [PATCH 604/633] Rework the event system of `sc-network` (#1370) This commit introduces a new concept called `NotificationService` which allows Polkadot protocols to communicate with the underlying notification protocol implementation directly, without routing events through `NetworkWorker`. This implies that each protocol has its own service which it uses to communicate with remote peers and that each `NotificationService` is unique with respect to the underlying notification protocol, meaning `NotificationService` for the transaction protocol can only be used to send and receive transaction-related notifications. The `NotificationService` concept introduces two additional benefits: * allow protocols to start using custom handshakes * allow protocols to accept/reject inbound peers Previously the validation of inbound connections was solely the responsibility of `ProtocolController`. This caused issues with light peers and `SyncingEngine` as `ProtocolController` would accept more peers than `SyncingEngine` could accept which caused peers to have differing views of their own states. `SyncingEngine` would reject excess peers but these rejections were not properly communicated to those peers causing them to assume that they were accepted. With `NotificationService`, the local handshake is not sent to remote peer if peer is rejected which allows it to detect that it was rejected. This commit also deprecates the use of `NetworkEventStream` for all notification-related events and going forward only DHT events are provided through `NetworkEventStream`. If protocols wish to follow each other's events, they must introduce additional abtractions, as is done for GRANDPA and transactions protocols by following the syncing protocol through `SyncEventStream`. Fixes https://github.com/paritytech/polkadot-sdk/issues/512 Fixes https://github.com/paritytech/polkadot-sdk/issues/514 Fixes https://github.com/paritytech/polkadot-sdk/issues/515 Fixes https://github.com/paritytech/polkadot-sdk/issues/554 Fixes https://github.com/paritytech/polkadot-sdk/issues/556 --- These changes are transferred from https://github.com/paritytech/substrate/pull/14197 but there are no functional changes compared to that PR --------- Co-authored-by: Dmitry Markin Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> --- Cargo.lock | 6 + .../relay-chain-minimal-node/Cargo.toml | 1 + .../src/collator_overseer.rs | 15 +- .../relay-chain-minimal-node/src/lib.rs | 14 +- .../relay-chain-minimal-node/src/network.rs | 25 +- polkadot/node/network/bridge/src/lib.rs | 1 + polkadot/node/network/bridge/src/network.rs | 96 +- polkadot/node/network/bridge/src/rx/mod.rs | 952 +++++++++-------- polkadot/node/network/bridge/src/rx/tests.rs | 335 ++++-- polkadot/node/network/bridge/src/tx/mod.rs | 42 +- polkadot/node/network/bridge/src/tx/tests.rs | 130 ++- .../network/bridge/src/validator_discovery.rs | 13 +- .../node/network/protocol/src/peer_set.rs | 77 +- polkadot/node/service/Cargo.toml | 1 + polkadot/node/service/src/lib.rs | 56 +- polkadot/node/service/src/overseer.rs | 14 +- .../bin/node-template/node/src/service.rs | 7 +- substrate/bin/node/cli/src/service.rs | 33 +- .../consensus/beefy/src/communication/mod.rs | 12 +- substrate/client/consensus/beefy/src/lib.rs | 6 +- substrate/client/consensus/beefy/src/tests.rs | 41 +- .../client/consensus/beefy/src/worker.rs | 4 + .../grandpa/src/communication/mod.rs | 4 +- .../grandpa/src/communication/tests.rs | 232 ++-- substrate/client/consensus/grandpa/src/lib.rs | 22 +- .../client/consensus/grandpa/src/observer.rs | 23 +- .../client/consensus/grandpa/src/tests.rs | 82 +- .../client/executor/wasmtime/src/tests.rs | 8 +- substrate/client/mixnet/Cargo.toml | 1 + .../client/mixnet/src/packet_dispatcher.rs | 36 +- substrate/client/mixnet/src/protocol.rs | 25 +- substrate/client/mixnet/src/run.rs | 60 +- .../client/mixnet/src/sync_with_runtime.rs | 1 + substrate/client/network-gossip/Cargo.toml | 2 + substrate/client/network-gossip/src/bridge.rs | 268 +++-- .../network-gossip/src/state_machine.rs | 166 ++- substrate/client/network/Cargo.toml | 2 + substrate/client/network/common/src/role.rs | 14 +- substrate/client/network/src/behaviour.rs | 55 +- substrate/client/network/src/config.rs | 90 +- substrate/client/network/src/error.rs | 9 + substrate/client/network/src/event.rs | 49 +- substrate/client/network/src/lib.rs | 22 +- substrate/client/network/src/mock.rs | 9 + substrate/client/network/src/peer_store.rs | 41 +- substrate/client/network/src/protocol.rs | 441 +++----- .../client/network/src/protocol/message.rs | 1 + .../network/src/protocol/notifications.rs | 4 + .../src/protocol/notifications/behaviour.rs | 994 ++++++++++++++---- .../src/protocol/notifications/handler.rs | 73 +- .../protocol/notifications/service/metrics.rs | 130 +++ .../src/protocol/notifications/service/mod.rs | 634 +++++++++++ .../protocol/notifications/service/tests.rs | 839 +++++++++++++++ .../src/protocol/notifications/tests.rs | 31 +- .../client/network/src/protocol_controller.rs | 3 + substrate/client/network/src/service.rs | 218 ++-- .../client/network/src/service/metrics.rs | 28 - .../client/network/src/service/signature.rs | 2 + .../client/network/src/service/traits.rs | 205 +++- substrate/client/network/statement/src/lib.rs | 123 ++- substrate/client/network/sync/src/engine.rs | 386 ++++--- .../client/network/sync/src/service/mock.rs | 2 + substrate/client/network/test/src/lib.rs | 97 +- substrate/client/network/test/src/service.rs | 337 +++--- substrate/client/network/test/src/sync.rs | 86 +- .../client/network/transactions/src/lib.rs | 156 ++- substrate/client/offchain/src/api.rs | 6 +- substrate/client/offchain/src/lib.rs | 8 +- substrate/client/service/src/builder.rs | 33 +- .../data/account_reentrance_count_call.wat | 2 +- .../data/add_remove_delegate_dependency.wat | 16 +- .../frame/contracts/fixtures/data/balance.wat | 2 +- .../frame/contracts/fixtures/data/call.wat | 2 +- .../fixtures/data/call_runtime_and_call.wat | 2 +- .../fixtures/data/caller_contract.wat | 66 +- .../fixtures/data/chain_extension.wat | 2 +- .../data/chain_extension_temp_storage.wat | 2 +- .../fixtures/data/create_storage_and_call.wat | 2 +- .../data/create_storage_and_instantiate.wat | 2 +- .../contracts/fixtures/data/crypto_hashes.wat | 6 +- .../data/debug_message_invalid_utf8.wat | 2 +- .../data/debug_message_logging_disabled.wat | 2 +- .../fixtures/data/debug_message_works.wat | 2 +- .../contracts/fixtures/data/delegate_call.wat | 6 +- .../fixtures/data/delegate_call_lib.wat | 2 +- .../fixtures/data/delegate_call_simple.wat | 2 +- .../fixtures/data/destroy_and_transfer.wat | 2 +- .../frame/contracts/fixtures/data/drain.wat | 2 +- .../contracts/fixtures/data/ecdsa_recover.wat | 2 +- .../contracts/fixtures/data/event_size.wat | 2 +- .../contracts/fixtures/data/multi_store.wat | 2 +- .../fixtures/data/reentrance_count_call.wat | 10 +- .../data/reentrance_count_delegated_call.wat | 12 +- .../contracts/fixtures/data/self_destruct.wat | 2 +- .../data/self_destructing_constructor.wat | 2 +- .../contracts/fixtures/data/set_code_hash.wat | 6 +- .../contracts/fixtures/data/storage_size.wat | 2 +- .../contracts/fixtures/data/store_call.wat | 2 +- .../contracts/fixtures/data/store_deploy.wat | 2 +- .../contracts/fixtures/data/xcm_execute.wat | 2 +- .../contracts/fixtures/data/xcm_send.wat | 2 +- substrate/frame/contracts/src/wasm/mod.rs | 54 +- 102 files changed, 5628 insertions(+), 2537 deletions(-) create mode 100644 substrate/client/network/src/protocol/notifications/service/metrics.rs create mode 100644 substrate/client/network/src/protocol/notifications/service/mod.rs create mode 100644 substrate/client/network/src/protocol/notifications/service/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f99b579bfe9..4fa9e83a173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4177,6 +4177,7 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", + "parking_lot 0.12.1", "polkadot-availability-recovery", "polkadot-collator-protocol", "polkadot-core-primitives", @@ -13268,6 +13269,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", + "parking_lot 0.12.1", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -15728,6 +15730,7 @@ dependencies = [ "array-bytes 4.2.0", "arrayvec 0.7.4", "blake2 0.10.6", + "bytes", "futures", "futures-timer", "libp2p-identity", @@ -15793,6 +15796,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-stream", "tokio-test", "tokio-util", "unsigned-varint", @@ -15848,10 +15852,12 @@ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ "ahash 0.8.3", + "async-trait", "futures", "futures-timer", "libp2p", "log", + "parity-scale-codec", "quickcheck", "sc-network", "sc-network-common", diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index ce76fc5cd6d..ee93df09ce1 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -47,4 +47,5 @@ array-bytes = "6.1" tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" +parking_lot = "0.12.1" 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 a785a9f6f79..5f5bf338ef9 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -15,7 +15,8 @@ // along with Polkadot. If not, see . use futures::{select, StreamExt}; -use std::sync::Arc; +use parking_lot::Mutex; +use std::{collections::HashMap, sync::Arc}; use polkadot_availability_recovery::AvailabilityRecoverySubsystem; use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide}; @@ -28,7 +29,7 @@ use polkadot_node_core_chain_api::ChainApiSubsystem; use polkadot_node_core_prospective_parachains::ProspectiveParachainsSubsystem; use polkadot_node_core_runtime_api::RuntimeApiSubsystem; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1::{self, AvailableDataFetchingRequest}, v2, IncomingRequestReceiver, ReqProtocolNames, @@ -42,7 +43,7 @@ use polkadot_overseer::{ use polkadot_primitives::CollatorPair; use sc_authority_discovery::Service as AuthorityDiscoveryService; -use sc_network::NetworkStateInfo; +use sc_network::{NetworkStateInfo, NotificationService}; use sc_service::TaskManager; use sc_utils::mpsc::tracing_unbounded; @@ -77,6 +78,8 @@ pub(crate) struct CollatorOverseerGenArgs<'a> { pub req_protocol_names: ReqProtocolNames, /// Peerset protocols name mapping pub peer_set_protocol_names: PeerSetProtocolNames, + /// Notification services for validation/collation protocols. + pub notification_services: HashMap>, } fn build_overseer( @@ -94,6 +97,7 @@ fn build_overseer( collator_pair, req_protocol_names, peer_set_protocol_names, + notification_services, }: CollatorOverseerGenArgs<'_>, ) -> Result< (Overseer, Arc>, OverseerHandle), @@ -101,6 +105,8 @@ fn build_overseer( > { let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + let builder = Overseer::builder() .availability_distribution(DummySubsystem) .availability_recovery(AvailabilityRecoverySubsystem::for_collator( @@ -131,6 +137,8 @@ fn build_overseer( sync_oracle, network_bridge_metrics.clone(), peer_set_protocol_names.clone(), + notification_services, + notification_sinks.clone(), )) .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service, @@ -138,6 +146,7 @@ fn build_overseer( network_bridge_metrics, req_protocol_names, peer_set_protocol_names, + notification_sinks, )) .provisioner(DummySubsystem) .runtime_api(RuntimeApiSubsystem::new( diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 8801f93640c..d121d2d3356 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -21,7 +21,7 @@ use cumulus_relay_chain_rpc_interface::{RelayChainRpcClient, RelayChainRpcInterf use network::build_collator_network; use polkadot_network_bridge::{peer_sets_info, IsAuthority}; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1, v2, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames, }, @@ -175,10 +175,13 @@ async fn new_minimal_relay_chain( let peer_set_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - - for config in peer_sets_info(is_authority, &peer_set_protocol_names) { - net_config.add_notification_protocol(config); - } + let notification_services = peer_sets_info(is_authority, &peer_set_protocol_names) + .into_iter() + .map(|(config, (peerset, service))| { + net_config.add_notification_protocol(config); + (peerset, service) + }) + .collect::>>(); let request_protocol_names = ReqProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let (collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver) = @@ -218,6 +221,7 @@ async fn new_minimal_relay_chain( collator_pair, req_protocol_names: request_protocol_names, peer_set_protocol_names, + notification_services, }; let overseer_handle = diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index 813dca47a03..95785063c1a 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -26,10 +26,9 @@ use sc_network::{ NetworkService, }; -use sc_network::config::FullNetworkConfiguration; +use sc_network::{config::FullNetworkConfiguration, NotificationService}; use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; use sc_service::{error::Error, Configuration, NetworkStarter, SpawnTaskHandle}; -use sc_utils::mpsc::tracing_unbounded; use std::{iter, sync::Arc}; @@ -45,7 +44,7 @@ pub(crate) fn build_collator_network( Error, > { let protocol_id = config.protocol_id(); - let block_announce_config = get_block_announce_proto_config::( + let (block_announce_config, _notification_service) = get_block_announce_proto_config::( protocol_id.clone(), &None, Roles::from(&config.role), @@ -69,8 +68,6 @@ pub(crate) fn build_collator_network( let peer_store_handle = peer_store.handle(); spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); - // RX is not used for anything because syncing is not started for the minimal node - let (tx, _rx) = tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let network_params = sc_network::config::Params:: { role: config.role.clone(), executor: { @@ -86,7 +83,6 @@ pub(crate) fn build_collator_network( protocol_id, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, - tx, }; let network_worker = sc_network::NetworkWorker::new(network_params)?; @@ -150,7 +146,7 @@ fn get_block_announce_proto_config( best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, -) -> NonDefaultSetConfig { +) -> (NonDefaultSetConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); if let Some(ref fork_id) = fork_id { @@ -160,12 +156,11 @@ fn get_block_announce_proto_config( } }; - NonDefaultSetConfig { - notifications_protocol: block_announces_protocol.into(), - fallback_names: iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()) - .collect(), - max_notification_size: 1024 * 1024, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + NonDefaultSetConfig::new( + block_announces_protocol.into(), + iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()).collect(), + 1024 * 1024, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( roles, best_number, best_hash, @@ -173,11 +168,11 @@ fn get_block_announce_proto_config( ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. - set_config: SetConfig { + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ) } diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs index 46d4a00faac..ddce99d5c2a 100644 --- a/polkadot/node/network/bridge/src/lib.rs +++ b/polkadot/node/network/bridge/src/lib.rs @@ -83,6 +83,7 @@ pub(crate) enum WireMessage { ViewUpdate(View), } +#[derive(Debug)] pub(crate) struct PeerData { /// The Latest view sent by the peer. view: View, diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index c264c94cc19..a9339a5c443 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -14,23 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{collections::HashSet, sync::Arc}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use async_trait::async_trait; -use futures::{prelude::*, stream::BoxStream}; +use parking_lot::Mutex; use parity_scale_codec::Encode; use sc_network::{ - config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, Event as NetworkEvent, - IfDisconnected, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkRequest, - NetworkService, OutboundFailure, ReputationChange, RequestFailure, + config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, IfDisconnected, MessageSink, + NetworkPeers, NetworkRequest, NetworkService, OutboundFailure, ReputationChange, + RequestFailure, }; use polkadot_node_network_protocol::{ - peer_set::{ - CollationVersion, PeerSet, PeerSetProtocolNames, ProtocolVersion, ValidationVersion, - }, + peer_set::{CollationVersion, PeerSet, ProtocolVersion, ValidationVersion}, request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests}, v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, }; @@ -44,104 +45,94 @@ const LOG_TARGET: &'static str = "parachain::network-bridge-net"; // Helper function to send a validation v1 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_v1( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v1 message to peers",); send_message( - net, peers, PeerSet::Validation, ValidationVersion::V1.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } // Helper function to send a validation vstaging message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_vstaging( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",); send_message( - net, peers, PeerSet::Validation, ValidationVersion::VStaging.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } // Helper function to send a validation v2 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_v2( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::V2.into(), - protocol_names, message, metrics, + notification_sinks, ); } // Helper function to send a collation v1 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_collation_message_v1( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V1.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } // Helper function to send a collation v2 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_collation_message_v2( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V2.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } @@ -151,19 +142,19 @@ pub(crate) fn send_collation_message_v2( /// messages that are compatible with the passed peer set, as that is currently not enforced by /// this function. These are messages of type `WireMessage` parameterized on the matching type. fn send_message( - net: &mut impl Network, mut peers: Vec, peer_set: PeerSet, version: ProtocolVersion, - protocol_names: &PeerSetProtocolNames, message: M, metrics: &super::Metrics, + network_notification_sinks: &Arc>>>, ) where M: Encode + Clone, { if peers.is_empty() { return } + let message = { let encoded = message.encode(); metrics.on_notification_sent(peer_set, version, encoded.len(), peers.len()); @@ -171,13 +162,13 @@ fn send_message( encoded }; - // optimization: generate the protocol name once. - let protocol_name = protocol_names.get_name(peer_set, version); + let notification_sinks = network_notification_sinks.lock(); + gum::trace!( target: LOG_TARGET, ?peers, + ?peer_set, ?version, - ?protocol_name, ?message, "Sending message to peers", ); @@ -185,29 +176,26 @@ fn send_message( // optimization: avoid cloning the message for the last peer in the // list. The message payload can be quite large. If the underlying // network used `Bytes` this would not be necessary. + // + // peer may have gotten disconnect by the time `send_message()` is called + // at which point the the sink is not available. let last_peer = peers.pop(); - - // We always send messages on the "main" name even when a negotiated - // fallback is used. The libp2p implementation handles the fallback - // under the hood. - let protocol_name = protocol_names.get_main_name(peer_set); peers.into_iter().for_each(|peer| { - net.write_notification(peer, protocol_name.clone(), message.clone()); + if let Some(sink) = notification_sinks.get(&(peer_set, peer)) { + sink.send_sync_notification(message.clone()); + } }); + if let Some(peer) = last_peer { - net.write_notification(peer, protocol_name, message); + if let Some(sink) = notification_sinks.get(&(peer_set, peer)) { + sink.send_sync_notification(message.clone()); + } } } /// An abstraction over networking for the purposes of this subsystem. #[async_trait] pub trait Network: Clone + Send + 'static { - /// Get a stream of all events occurring on the network. This may include events unrelated - /// to the Polkadot protocol - the user of this function should filter only for events related - /// to the [`VALIDATION_PROTOCOL_NAME`](VALIDATION_PROTOCOL_NAME) - /// or [`COLLATION_PROTOCOL_NAME`](COLLATION_PROTOCOL_NAME) - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent>; - /// Ask the network to keep a substream open with these nodes and not disconnect from them /// until removed from the protocol's peer set. /// Note that `out_peers` setting has no effect on this. @@ -239,16 +227,12 @@ pub trait Network: Clone + Send + 'static { /// Disconnect a given peer from the protocol specified without harming reputation. fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); - /// Write a notification to a peer on the given protocol. - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec); + /// Get peer role. + fn peer_role(&self, who: PeerId, handshake: Vec) -> Option; } #[async_trait] impl Network for Arc> { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - NetworkService::event_stream(self, "polkadot-network-bridge").boxed() - } - async fn set_reserved_peers( &mut self, protocol: ProtocolName, @@ -273,10 +257,6 @@ impl Network for Arc> { NetworkService::disconnect_peer(&**self, who, protocol); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - NetworkService::write_notification(&**self, who, protocol, message); - } - async fn start_request( &self, authority_discovery: &mut AD, @@ -348,6 +328,10 @@ impl Network for Arc> { if_disconnected, ); } + + fn peer_role(&self, who: PeerId, handshake: Vec) -> Option { + NetworkService::peer_role(self, who, handshake) + } } /// We assume one `peer_id` per `authority_id`. diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 06be57ead00..40cd167a968 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -20,11 +20,14 @@ use super::*; use always_assert::never; use bytes::Bytes; -use futures::stream::{BoxStream, StreamExt}; use net_protocol::filter_by_peer_version; use parity_scale_codec::{Decode, DecodeAll}; +use parking_lot::Mutex; -use sc_network::Event as NetworkEvent; +use sc_network::{ + service::traits::{NotificationEvent, ValidationResult}, + MessageSink, NotificationService, +}; use sp_consensus::SyncOracle; use polkadot_node_network_protocol::{ @@ -88,6 +91,9 @@ pub struct NetworkBridgeRx { shared: Shared, metrics: Metrics, peerset_protocol_names: PeerSetProtocolNames, + validation_service: Box, + collation_service: Box, + notification_sinks: Arc>>>, } impl NetworkBridgeRx { @@ -102,8 +108,18 @@ impl NetworkBridgeRx { sync_oracle: Box, metrics: Metrics, peerset_protocol_names: PeerSetProtocolNames, + mut notification_services: HashMap>, + notification_sinks: Arc>>>, ) -> Self { let shared = Shared::default(); + + let validation_service = notification_services + .remove(&PeerSet::Validation) + .expect("validation protocol was enabled so `NotificationService` must exist; qed"); + let collation_service = notification_services + .remove(&PeerSet::Collation) + .expect("collation protocol was enabled so `NotificationService` must exist; qed"); + Self { network_service, authority_discovery_service, @@ -111,6 +127,9 @@ impl NetworkBridgeRx { shared, metrics, peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, } } } @@ -121,444 +140,563 @@ where Net: Network + Sync, AD: validator_discovery::AuthorityDiscovery + Clone + Sync, { - fn start(mut self, ctx: Context) -> SpawnedSubsystem { - // The stream of networking events has to be created at initialization, otherwise the - // networking might open connections before the stream of events has been grabbed. - let network_stream = self.network_service.event_stream(); - + fn start(self, ctx: Context) -> SpawnedSubsystem { // Swallow error because failure is fatal to the node and we log with more precision // within `run_network`. - let future = run_network_in(self, ctx, network_stream) + let future = run_network_in(self, ctx) .map_err(|e| SubsystemError::with_origin("network-bridge", e)) .boxed(); SpawnedSubsystem { name: "network-bridge-rx-subsystem", future } } } -async fn handle_network_messages( - mut sender: impl overseer::NetworkBridgeRxSenderTrait, - mut network_service: impl Network, - network_stream: BoxStream<'static, NetworkEvent>, - mut authority_discovery_service: AD, - metrics: Metrics, - shared: Shared, - peerset_protocol_names: PeerSetProtocolNames, -) -> Result<(), Error> -where +/// Handle notification event received over the validation protocol. +async fn handle_validation_message( + event: NotificationEvent, + network_service: &mut impl Network, + sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + authority_discovery_service: &mut AD, + metrics: &Metrics, + shared: &Shared, + peerset_protocol_names: &PeerSetProtocolNames, + notification_service: &mut Box, + notification_sinks: &mut Arc>>>, +) where AD: validator_discovery::AuthorityDiscovery + Send, { - let mut network_stream = network_stream.fuse(); - loop { - match network_stream.next().await { - None => return Err(Error::EventStreamConcluded), - Some(NetworkEvent::Dht(_)) => {}, - Some(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol, - role, - negotiated_fallback, - received_handshake: _, - }) => { - let role = ObservedRole::from(role); - let (peer_set, version) = { - let (peer_set, version) = - match peerset_protocol_names.try_get_protocol(&protocol) { - None => continue, - Some(p) => p, - }; - - if let Some(fallback) = negotiated_fallback { - match peerset_protocol_names.try_get_protocol(&fallback) { - None => { + match event { + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = network_service + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); + }, + NotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + .. + } => { + let role = match network_service.peer_role(peer, handshake) { + Some(role) => ObservedRole::from(role), + None => { + gum::debug!( + target: LOG_TARGET, + ?peer, + "Failed to determine peer role for validation protocol", + ); + return + }, + }; + + let (peer_set, version) = { + let (peer_set, version) = + (PeerSet::Validation, PeerSet::Validation.get_main_version()); + + if let Some(fallback) = negotiated_fallback { + match peerset_protocol_names.try_get_protocol(&fallback) { + None => { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + ?peer, + peerset = ?peer_set, + "Unknown fallback", + ); + + return + }, + Some((p2, v2)) => { + if p2 != peer_set { gum::debug!( target: LOG_TARGET, fallback = &*fallback, - ?peer, - ?peer_set, - "Unknown fallback", + fallback_peerset = ?p2, + peerset = ?peer_set, + "Fallback mismatched peer-set", ); - continue - }, - Some((p2, v2)) => { - if p2 != peer_set { - gum::debug!( - target: LOG_TARGET, - fallback = &*fallback, - fallback_peerset = ?p2, - protocol = &*protocol, - peerset = ?peer_set, - "Fallback mismatched peer-set", - ); - - continue - } - - (p2, v2) - }, - } - } else { - (peer_set, version) - } - }; - - gum::debug!( - target: LOG_TARGET, - action = "PeerConnected", - peer_set = ?peer_set, - version = %version, - peer = ?peer, - role = ?role - ); - - let local_view = { - let mut shared = shared.0.lock(); - let peer_map = match peer_set { - PeerSet::Validation => &mut shared.validation_peers, - PeerSet::Collation => &mut shared.collation_peers, - }; + return + } - match peer_map.entry(peer) { - hash_map::Entry::Occupied(_) => continue, - hash_map::Entry::Vacant(vacant) => { - vacant.insert(PeerData { view: View::default(), version }); + (p2, v2) }, } + } else { + (peer_set, version) + } + }; + // store the notification sink to `notification_sinks` so both `NetworkBridgeRx` + // and `NetworkBridgeTx` can send messages to the peer. + match notification_service.message_sink(&peer) { + Some(sink) => { + notification_sinks.lock().insert((peer_set, peer), sink); + }, + None => { + gum::warn!( + target: LOG_TARGET, + peerset = ?peer_set, + version = %version, + ?peer, + ?role, + "Message sink not available for peer", + ); + return + }, + } - metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); - - shared.local_view.clone().unwrap_or(View::default()) - }; - - let maybe_authority = - authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - - match peer_set { - PeerSet::Validation => { - dispatch_validation_events_to_all( - vec![ - NetworkBridgeEvent::PeerConnected( - peer, - role, - version, - maybe_authority, - ), - NetworkBridgeEvent::PeerViewChange(peer, View::default()), - ], - &mut sender, - &metrics, - ) - .await; - - match ValidationVersion::try_from(version) - .expect("try_get_protocol has already checked version is known; qed") - { - ValidationVersion::V1 => send_validation_message_v1( - &mut network_service, - vec![peer], - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - ValidationVersion::VStaging => send_validation_message_vstaging( - &mut network_service, - vec![peer], - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - ValidationVersion::V2 => send_validation_message_v2( - &mut network_service, - vec![peer], - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - } - }, - PeerSet::Collation => { - dispatch_collation_events_to_all( - vec![ - NetworkBridgeEvent::PeerConnected( - peer, - role, - version, - maybe_authority, - ), - NetworkBridgeEvent::PeerViewChange(peer, View::default()), - ], - &mut sender, - ) - .await; - - match CollationVersion::try_from(version) - .expect("try_get_protocol has already checked version is known; qed") - { - CollationVersion::V1 => send_collation_message_v1( - &mut network_service, - vec![peer], - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - CollationVersion::V2 => send_collation_message_v2( - &mut network_service, - vec![peer], - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - } + gum::debug!( + target: LOG_TARGET, + action = "PeerConnected", + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role + ); + + let local_view = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.validation_peers; + + match peer_map.entry(peer) { + hash_map::Entry::Occupied(_) => return, + hash_map::Entry::Vacant(vacant) => { + vacant.insert(PeerData { view: View::default(), version }); }, } - }, - Some(NetworkEvent::NotificationStreamClosed { remote: peer, protocol }) => { - let (peer_set, version) = match peerset_protocol_names.try_get_protocol(&protocol) { - None => continue, - Some(peer_set) => peer_set, - }; - gum::debug!( - target: LOG_TARGET, - action = "PeerDisconnected", - peer_set = ?peer_set, - peer = ?peer - ); + metrics.on_peer_connected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); - let was_connected = { - let mut shared = shared.0.lock(); - let peer_map = match peer_set { - PeerSet::Validation => &mut shared.validation_peers, - PeerSet::Collation => &mut shared.collation_peers, - }; + shared.local_view.clone().unwrap_or(View::default()) + }; - let w = peer_map.remove(&peer).is_some(); + let maybe_authority = + authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); + dispatch_validation_events_to_all( + vec![ + NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), + ], + sender, + &metrics, + ) + .await; - w - }; + match ValidationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + ValidationVersion::V1 => send_validation_message_v1( + vec![peer], + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + ValidationVersion::VStaging => send_validation_message_vstaging( + vec![peer], + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + ValidationVersion::V2 => send_validation_message_v2( + vec![peer], + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + } + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let (peer_set, version) = (PeerSet::Validation, PeerSet::Validation.get_main_version()); - if was_connected && version == peer_set.get_main_version() { - match peer_set { - PeerSet::Validation => - dispatch_validation_event_to_all( - NetworkBridgeEvent::PeerDisconnected(peer), - &mut sender, - &metrics, - ) - .await, - PeerSet::Collation => - dispatch_collation_event_to_all( - NetworkBridgeEvent::PeerDisconnected(peer), - &mut sender, - ) - .await, - } + gum::debug!( + target: LOG_TARGET, + action = "PeerDisconnected", + ?peer_set, + ?peer + ); + + let was_connected = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.validation_peers; + + let w = peer_map.remove(&peer).is_some(); + + metrics.on_peer_disconnected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); + + w + }; + + notification_sinks.lock().remove(&(peer_set, peer)); + + if was_connected && version == peer_set.get_main_version() { + dispatch_validation_event_to_all( + NetworkBridgeEvent::PeerDisconnected(peer), + sender, + &metrics, + ) + .await; + } + }, + NotificationEvent::NotificationReceived { peer, notification } => { + let expected_versions = { + let mut versions = PerPeerSet::>::default(); + let shared = shared.0.lock(); + + if let Some(peer_data) = shared.validation_peers.get(&peer) { + versions[PeerSet::Validation] = Some(peer_data.version); } - }, - Some(NetworkEvent::NotificationsReceived { remote, messages }) => { - let expected_versions = { - let mut versions = PerPeerSet::>::default(); - let shared = shared.0.lock(); - if let Some(peer_data) = shared.validation_peers.get(&remote) { - versions[PeerSet::Validation] = Some(peer_data.version); - } - if let Some(peer_data) = shared.collation_peers.get(&remote) { - versions[PeerSet::Collation] = Some(peer_data.version); - } + versions + }; - versions + gum::trace!( + target: LOG_TARGET, + action = "PeerMessage", + peerset = ?PeerSet::Validation, + ?peer, + ); + + let (events, reports) = + if expected_versions[PeerSet::Validation] == Some(ValidationVersion::V1.into()) { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::V2.into()) + { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::VStaging.into()) + { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Validation], + "Major logic bug. Peer somehow has unsupported validation protocol version." + ); + + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) }; - // non-decoded, but version-checked validation messages. - let v_messages: Result, _> = messages - .iter() - .filter_map(|(protocol, msg_bytes)| { - // version doesn't matter because we always receive on the 'correct' - // protocol name, not the negotiated fallback. - let (peer_set, version) = - peerset_protocol_names.try_get_protocol(protocol)?; - gum::trace!( - target: LOG_TARGET, - ?peer_set, - ?protocol, - ?version, - "Received notification" - ); + for report in reports { + network_service.report_peer(peer, report.into()); + } - if peer_set == PeerSet::Validation { - if expected_versions[PeerSet::Validation].is_none() { - return Some(Err(UNCONNECTED_PEERSET_COST)) - } + dispatch_validation_events_to_all(events, sender, &metrics).await; + }, + } +} + +/// Handle notification event received over the collation protocol. +async fn handle_collation_message( + event: NotificationEvent, + network_service: &mut impl Network, + sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + authority_discovery_service: &mut AD, + metrics: &Metrics, + shared: &Shared, + peerset_protocol_names: &PeerSetProtocolNames, + notification_service: &mut Box, + notification_sinks: &mut Arc>>>, +) where + AD: validator_discovery::AuthorityDiscovery + Send, +{ + match event { + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = network_service + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); + }, + NotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + .. + } => { + let role = match network_service.peer_role(peer, handshake) { + Some(role) => ObservedRole::from(role), + None => { + gum::debug!( + target: LOG_TARGET, + ?peer, + "Failed to determine peer role for validation protocol", + ); + return + }, + }; + + let (peer_set, version) = { + let (peer_set, version) = + (PeerSet::Collation, PeerSet::Collation.get_main_version()); + + if let Some(fallback) = negotiated_fallback { + match peerset_protocol_names.try_get_protocol(&fallback) { + None => { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + ?peer, + ?peer_set, + "Unknown fallback", + ); + + return + }, + Some((p2, v2)) => { + if p2 != peer_set { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + fallback_peerset = ?p2, + peerset = ?peer_set, + "Fallback mismatched peer-set", + ); - Some(Ok(msg_bytes.clone())) - } else { - None - } - }) - .collect(); + return + } - let v_messages = match v_messages { - Err(rep) => { - gum::debug!(target: LOG_TARGET, action = "ReportPeer"); - network_service.report_peer(remote, rep.into()); + (p2, v2) + }, + } + } else { + (peer_set, version) + } + }; + + // store the notification sink to `notification_sinks` so both `NetworkBridgeRx` + // and `NetworkBridgeTx` can send messages to the peer. + match notification_service.message_sink(&peer) { + Some(sink) => { + notification_sinks.lock().insert((peer_set, peer), sink); + }, + None => { + gum::warn!( + target: LOG_TARGET, + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role, + "Message sink not available for peer", + ); + return + }, + } - continue + gum::debug!( + target: LOG_TARGET, + action = "PeerConnected", + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role + ); + + let local_view = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.collation_peers; + + match peer_map.entry(peer) { + hash_map::Entry::Occupied(_) => return, + hash_map::Entry::Vacant(vacant) => { + vacant.insert(PeerData { view: View::default(), version }); }, - Ok(v) => v, - }; + } - // non-decoded, but version-checked collation messages. - let c_messages: Result, _> = messages - .iter() - .filter_map(|(protocol, msg_bytes)| { - // version doesn't matter because we always receive on the 'correct' - // protocol name, not the negotiated fallback. - let (peer_set, _version) = - peerset_protocol_names.try_get_protocol(protocol)?; - - if peer_set == PeerSet::Collation { - if expected_versions[PeerSet::Collation].is_none() { - return Some(Err(UNCONNECTED_PEERSET_COST)) - } + metrics.on_peer_connected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); - Some(Ok(msg_bytes.clone())) - } else { - None - } - }) - .collect(); + shared.local_view.clone().unwrap_or(View::default()) + }; - let c_messages = match c_messages { - Err(rep) => { - gum::debug!(target: LOG_TARGET, action = "ReportPeer"); - network_service.report_peer(remote, rep.into()); + let maybe_authority = + authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - continue - }, - Ok(v) => v, - }; + dispatch_collation_events_to_all( + vec![ + NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), + ], + sender, + ) + .await; - if v_messages.is_empty() && c_messages.is_empty() { - continue - } + match CollationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + CollationVersion::V1 => send_collation_message_v1( + vec![peer], + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + CollationVersion::V2 => send_collation_message_v2( + vec![peer], + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + } + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let (peer_set, version) = (PeerSet::Collation, PeerSet::Collation.get_main_version()); - gum::trace!( - target: LOG_TARGET, - action = "PeerMessages", - peer = ?remote, - num_validation_messages = %v_messages.len(), - num_collation_messages = %c_messages.len() - ); + gum::debug!( + target: LOG_TARGET, + action = "PeerDisconnected", + ?peer_set, + ?peer + ); - if !v_messages.is_empty() { - let (events, reports) = if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::V1.into()) - { - handle_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::V2.into()) - { - handle_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::VStaging.into()) - { - handle_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Validation], - "Major logic bug. Peer somehow has unsupported validation protocol version." - ); + let was_connected = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.collation_peers; - never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + let w = peer_map.remove(&peer).is_some(); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + metrics.on_peer_disconnected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); - for report in reports { - network_service.report_peer(remote, report.into()); - } + w + }; - dispatch_validation_events_to_all(events, &mut sender, &metrics).await; + notification_sinks.lock().remove(&(peer_set, peer)); + + if was_connected && version == peer_set.get_main_version() { + dispatch_collation_event_to_all(NetworkBridgeEvent::PeerDisconnected(peer), sender) + .await; + } + }, + NotificationEvent::NotificationReceived { peer, notification } => { + let expected_versions = { + let mut versions = PerPeerSet::>::default(); + let shared = shared.0.lock(); + + if let Some(peer_data) = shared.collation_peers.get(&peer) { + versions[PeerSet::Collation] = Some(peer_data.version); } - if !c_messages.is_empty() { - let (events, reports) = if expected_versions[PeerSet::Collation] == - Some(CollationVersion::V1.into()) - { - handle_peer_messages::( - remote, - PeerSet::Collation, - &mut shared.0.lock().collation_peers, - c_messages, - &metrics, - ) - } else if expected_versions[PeerSet::Collation] == - Some(CollationVersion::V2.into()) - { - handle_peer_messages::( - remote, - PeerSet::Collation, - &mut shared.0.lock().collation_peers, - c_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Collation], - "Major logic bug. Peer somehow has unsupported collation protocol version." - ); + versions + }; - never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + gum::trace!( + target: LOG_TARGET, + action = "PeerMessage", + peerset = ?PeerSet::Collation, + ?peer, + ); + + let (events, reports) = + if expected_versions[PeerSet::Collation] == Some(CollationVersion::V1.into()) { + handle_peer_messages::( + peer, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Collation] == Some(CollationVersion::V2.into()) + { + handle_peer_messages::( + peer, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + vec![notification.into()], + metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Collation], + "Major logic bug. Peer somehow has unsupported collation protocol version." + ); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); - for report in reports { - network_service.report_peer(remote, report.into()); - } + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; - dispatch_collation_events_to_all(events, &mut sender).await; - } + for report in reports { + network_service.report_peer(peer, report.into()); + } + + dispatch_collation_events_to_all(events, sender).await; + }, + } +} + +async fn handle_network_messages( + mut sender: impl overseer::NetworkBridgeRxSenderTrait, + mut network_service: impl Network, + mut authority_discovery_service: AD, + metrics: Metrics, + shared: Shared, + peerset_protocol_names: PeerSetProtocolNames, + mut validation_service: Box, + mut collation_service: Box, + mut notification_sinks: Arc>>>, +) -> Result<(), Error> +where + AD: validator_discovery::AuthorityDiscovery + Send, +{ + loop { + futures::select! { + event = validation_service.next_event().fuse() => match event { + Some(event) => handle_validation_message( + event, + &mut network_service, + &mut sender, + &mut authority_discovery_service, + &metrics, + &shared, + &peerset_protocol_names, + &mut validation_service, + &mut notification_sinks, + ).await, + None => return Err(Error::EventStreamConcluded), }, + event = collation_service.next_event().fuse() => match event { + Some(event) => handle_collation_message( + event, + &mut network_service, + &mut sender, + &mut authority_discovery_service, + &metrics, + &shared, + &peerset_protocol_names, + &mut collation_service, + &mut notification_sinks, + ).await, + None => return Err(Error::EventStreamConcluded), + } } } } @@ -593,17 +731,15 @@ where } #[overseer::contextbounds(NetworkBridgeRx, prefix = self::overseer)] -async fn run_incoming_orchestra_signals( +async fn run_incoming_orchestra_signals( mut ctx: Context, - mut network_service: N, mut authority_discovery_service: AD, shared: Shared, sync_oracle: Box, metrics: Metrics, - peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Result<(), Error> where - N: Network, AD: validator_discovery::AuthorityDiscovery + Clone, { // This is kept sorted, descending, by block number. @@ -695,13 +831,12 @@ where mode = Mode::Active; update_our_view( - &mut network_service, &mut ctx, &live_heads, &shared, finalized_number, &metrics, - &peerset_protocol_names, + ¬ification_sinks, ); } } @@ -735,7 +870,6 @@ where async fn run_network_in( bridge: NetworkBridgeRx, mut ctx: Context, - network_stream: BoxStream<'static, NetworkEvent>, ) -> Result<(), Error> where N: Network, @@ -748,16 +882,21 @@ where sync_oracle, shared, peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, } = bridge; let (task, network_event_handler) = handle_network_messages( ctx.sender().clone(), network_service.clone(), - network_stream, authority_discovery_service.clone(), metrics.clone(), shared.clone(), peerset_protocol_names.clone(), + validation_service, + collation_service, + notification_sinks.clone(), ) .remote_handle(); @@ -766,12 +905,11 @@ where let orchestra_signal_handler = run_incoming_orchestra_signals( ctx, - network_service, authority_discovery_service, shared, sync_oracle, metrics, - peerset_protocol_names, + notification_sinks, ); futures::pin_mut!(orchestra_signal_handler); @@ -791,17 +929,14 @@ fn construct_view( } #[overseer::contextbounds(NetworkBridgeRx, prefix = self::overseer)] -fn update_our_view( - net: &mut Net, +fn update_our_view( ctx: &mut Context, live_heads: &[ActivatedLeaf], shared: &Shared, finalized_number: BlockNumber, metrics: &Metrics, - peerset_protocol_names: &PeerSetProtocolNames, -) where - Net: Network, -{ + notification_sinks: &Arc>>>, +) { let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number); let (validation_peers, collation_peers) = { @@ -849,43 +984,38 @@ fn update_our_view( filter_by_peer_version(&validation_peers, ValidationVersion::VStaging.into()); send_validation_message_v1( - net, v1_validation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_collation_message_v1( - net, v1_collation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_validation_message_v2( - net, v2_validation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_collation_message_v2( - net, v2_collation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_validation_message_vstaging( - net, vstaging_validation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); let our_view = OurView::new( diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index f784e78a7f2..e0b86feb644 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use futures::{channel::oneshot, executor, stream::BoxStream}; +use futures::{channel::oneshot, executor}; use overseer::jaeger; use polkadot_node_network_protocol::{self as net_protocol, OurView}; use polkadot_node_subsystem::messages::NetworkBridgeEvent; @@ -26,10 +26,13 @@ use parking_lot::Mutex; use std::{ collections::HashSet, sync::atomic::{AtomicBool, Ordering}, - task::Poll, }; -use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; +use sc_network::{ + service::traits::{Direction, MessageSink, NotificationService}, + IfDisconnected, Multiaddr, ObservedRole as SubstrateObservedRole, ProtocolName, + ReputationChange, Roles, +}; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, @@ -47,9 +50,8 @@ use polkadot_node_subsystem_test_helpers::{ mock::new_leaf, SingleItemSink, SingleItemStream, TestSubsystemContextHandle, }; use polkadot_node_subsystem_util::metered; -use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash}; +use polkadot_primitives::{AuthorityDiscoveryId, Hash}; -use sc_network::Multiaddr; use sp_keyring::Sr25519Keyring; use crate::{network::Network, validator_discovery::AuthorityDiscovery}; @@ -64,10 +66,9 @@ pub enum NetworkAction { WriteNotification(PeerId, PeerSet, Vec), } -// The subsystem's view of the network - only supports a single call to `event_stream`. +// The subsystem's view of the network. #[derive(Clone)] struct TestNetwork { - net_events: Arc>>>, action_tx: Arc>>, protocol_names: Arc, } @@ -79,37 +80,42 @@ struct TestAuthorityDiscovery; // of `NetworkAction`s. struct TestNetworkHandle { action_rx: metered::UnboundedMeteredReceiver, - net_tx: SingleItemSink, - protocol_names: PeerSetProtocolNames, + validation_tx: SingleItemSink, + collation_tx: SingleItemSink, } fn new_test_network( protocol_names: PeerSetProtocolNames, -) -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) { - let (net_tx, net_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); +) -> ( + TestNetwork, + TestNetworkHandle, + TestAuthorityDiscovery, + Box, + Box, +) { let (action_tx, action_rx) = metered::unbounded(); + let (validation_tx, validation_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); + let (collation_tx, collation_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); + let action_tx = Arc::new(Mutex::new(action_tx)); ( TestNetwork { - net_events: Arc::new(Mutex::new(Some(net_rx))), - action_tx: Arc::new(Mutex::new(action_tx)), + action_tx: action_tx.clone(), protocol_names: Arc::new(protocol_names.clone()), }, - TestNetworkHandle { action_rx, net_tx, protocol_names }, + TestNetworkHandle { action_rx, validation_tx, collation_tx }, TestAuthorityDiscovery, + Box::new(TestNotificationService::new( + PeerSet::Validation, + action_tx.clone(), + validation_rx, + )), + Box::new(TestNotificationService::new(PeerSet::Collation, action_tx, collation_rx)), ) } #[async_trait] impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - self.net_events - .lock() - .take() - .expect("Subsystem made more than one call to `event_stream`") - .boxed() - } - async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -143,7 +149,8 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); + let (peer_set, version) = self.protocol_names.try_get_protocol(&protocol).unwrap(); + assert_eq!(version, peer_set.get_main_version()); self.action_tx .lock() @@ -151,13 +158,10 @@ impl Network for TestNetwork { .unwrap(); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); - - self.action_tx - .lock() - .unbounded_send(NetworkAction::WriteNotification(who, peer_set, message)) - .unwrap(); + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(SubstrateObservedRole::from(role))) } } @@ -201,35 +205,85 @@ impl TestNetworkHandle { peer_set: PeerSet, role: ObservedRole, ) { - let protocol_version = ProtocolVersion::from(protocol_version); - self.send_network_event(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol: self.protocol_names.get_name(peer_set, protocol_version), - negotiated_fallback: None, - role: role.into(), - received_handshake: vec![], - }) - .await; + fn observed_role_to_handshake(role: &ObservedRole) -> Vec { + match role { + &ObservedRole::Light => Roles::LIGHT.encode(), + &ObservedRole::Authority => Roles::AUTHORITY.encode(), + &ObservedRole::Full => Roles::FULL.encode(), + } + } + + // because of how protocol negotiation works, if two peers support at least one common + // protocol, the protocol is negotiated over the main protocol (`ValidationVersion::V2`) but + // if either one of the peers used a fallback protocol for the negotiation (meaning they + // don't support the main protocol but some older version of it ), `negotiated_fallback` is + // set to that protocol. + let negotiated_fallback = match protocol_version { + ValidationVersion::V2 => None, + ValidationVersion::V1 => match peer_set { + PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/1")), + PeerSet::Collation => Some(ProtocolName::from("/polkadot/collation/1")), + }, + ValidationVersion::VStaging => match peer_set { + PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/3")), + PeerSet::Collation => unreachable!(), + }, + }; + + match peer_set { + PeerSet::Validation => { + self.validation_tx + .send(NotificationEvent::NotificationStreamOpened { + peer, + direction: Direction::Inbound, + handshake: observed_role_to_handshake(&role), + negotiated_fallback, + }) + .await + .expect("subsystem concluded early"); + }, + PeerSet::Collation => { + self.collation_tx + .send(NotificationEvent::NotificationStreamOpened { + peer, + direction: Direction::Inbound, + handshake: observed_role_to_handshake(&role), + negotiated_fallback, + }) + .await + .expect("subsystem concluded early"); + }, + } } async fn disconnect_peer(&mut self, peer: PeerId, peer_set: PeerSet) { - self.send_network_event(NetworkEvent::NotificationStreamClosed { - remote: peer, - protocol: self.protocol_names.get_main_name(peer_set), - }) - .await; + match peer_set { + PeerSet::Validation => self + .validation_tx + .send(NotificationEvent::NotificationStreamClosed { peer }) + .await + .expect("subsystem concluded early"), + PeerSet::Collation => self + .collation_tx + .send(NotificationEvent::NotificationStreamClosed { peer }) + .await + .expect("subsystem concluded early"), + } } async fn peer_message(&mut self, peer: PeerId, peer_set: PeerSet, message: Vec) { - self.send_network_event(NetworkEvent::NotificationsReceived { - remote: peer, - messages: vec![(self.protocol_names.get_main_name(peer_set), message.into())], - }) - .await; - } - - async fn send_network_event(&mut self, event: NetworkEvent) { - self.net_tx.send(event).await.expect("subsystem concluded early"); + match peer_set { + PeerSet::Validation => self + .validation_tx + .send(NotificationEvent::NotificationReceived { peer, notification: message }) + .await + .expect("subsystem concluded early"), + PeerSet::Collation => self + .collation_tx + .send(NotificationEvent::NotificationReceived { peer, notification: message }) + .await + .expect("subsystem concluded early"), + } } } @@ -240,6 +294,121 @@ fn assert_network_actions_contains(actions: &[NetworkAction], action: &NetworkAc } } +struct TestNotificationService { + peer_set: PeerSet, + action_tx: Arc>>, + rx: SingleItemStream, +} + +impl std::fmt::Debug for TestNotificationService { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + +impl TestNotificationService { + pub fn new( + peer_set: PeerSet, + action_tx: Arc>>, + rx: SingleItemStream, + ) -> Self { + Self { peer_set, action_tx, rx } + } +} + +struct TestMessageSink { + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, +} + +impl TestMessageSink { + fn new( + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, + ) -> TestMessageSink { + Self { peer, peer_set, action_tx } + } +} + +#[async_trait::async_trait] +impl MessageSink for TestMessageSink { + fn send_sync_notification(&self, notification: Vec) { + self.action_tx + .lock() + .unbounded_send(NetworkAction::WriteNotification( + self.peer, + self.peer_set, + notification, + )) + .unwrap(); + } + + async fn send_async_notification( + &self, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } +} + +#[async_trait::async_trait] +impl NotificationService for TestNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + // Clone [`NotificationService`] + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + /// Get protocol name. + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + /// Get notification sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option> { + Some(Box::new(TestMessageSink::new(*peer, self.peer_set, self.action_tx.clone()))) + } +} + #[derive(Clone)] struct TestSyncOracle { is_major_syncing: Arc, @@ -335,10 +504,11 @@ fn test_harness>( let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, fork_id); let pool = sp_core::testing::TaskExecutor::new(); - let (mut network, network_handle, discovery) = new_test_network(peerset_protocol_names.clone()); + let (network, network_handle, discovery, validation_service, collation_service) = + new_test_network(peerset_protocol_names.clone()); let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); - let network_stream = network.event_stream(); + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); let shared = Shared::default(); let bridge = NetworkBridgeRx { @@ -348,9 +518,12 @@ fn test_harness>( sync_oracle, shared: shared.clone(), peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, }; - let network_bridge = run_network_in(bridge, context, network_stream) + let network_bridge = run_network_in(bridge, context) .map_err(|_| panic!("subsystem execution failed")) .map(|_| ()); @@ -942,8 +1115,6 @@ fn relays_collation_protocol_messages() { .await; } - // peer A gets reported for sending a collation message. - let collator_protocol_message = protocol_v1::CollatorProtocolMessage::Declare( Sr25519Keyring::Alice.public().into(), Default::default(), @@ -953,19 +1124,23 @@ fn relays_collation_protocol_messages() { let message_v1 = protocol_v1::CollationProtocol::CollatorProtocol(collator_protocol_message.clone()); - network_handle - .peer_message( - peer_a, - PeerSet::Collation, - WireMessage::ProtocolMessage(message_v1.clone()).encode(), - ) - .await; - - let actions = network_handle.next_network_actions(3).await; - assert_network_actions_contains( - &actions, - &NetworkAction::ReputationChange(peer_a, UNCONNECTED_PEERSET_COST.into()), - ); + // peer A gets reported for sending a collation message. + // NOTE: this is not possible since peer A cannot send + // a collation message if it has not opened a collation protocol + + // network_handle + // .peer_message( + // peer_a, + // PeerSet::Collation, + // WireMessage::ProtocolMessage(message_v1.clone()).encode(), + // ) + // .await; + + // let actions = network_handle.next_network_actions(3).await; + // assert_network_actions_contains( + // &actions, + // &NetworkAction::ReputationChange(peer_a, UNCONNECTED_PEERSET_COST.into()), + // ); // peer B has the message relayed. @@ -1212,7 +1387,7 @@ fn our_view_updates_decreasing_order_and_limited_to_max() { fn network_protocol_versioning_view_update() { let (oracle, handle) = make_sync_oracle(false); test_harness(Box::new(oracle), |test_harness| async move { - let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + let TestHarness { mut network_handle, mut virtual_overseer, shared } = test_harness; let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); let peers = [ @@ -1231,12 +1406,22 @@ fn network_protocol_versioning_view_update() { handle.await_mode_switch().await; + let mut total_validation_peers = 0; + let mut total_collation_peers = 0; + for &(peer_id, peer_set, version) in &peers { network_handle .connect_peer(peer_id, version, peer_set, ObservedRole::Full) .await; + + match peer_set { + PeerSet::Validation => total_validation_peers += 1, + PeerSet::Collation => total_collation_peers += 1, + } } + await_peer_connections(&shared, total_validation_peers, total_collation_peers).await; + let view = view![head]; let actions = network_handle.next_network_actions(4).await; @@ -1264,15 +1449,19 @@ fn network_protocol_versioning_view_update() { #[test] fn network_protocol_versioning_subsystem_msg() { + use polkadot_primitives::CandidateHash; + use std::task::Poll; + let (oracle, _handle) = make_sync_oracle(false); test_harness(Box::new(oracle), |test_harness| async move { - let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + let TestHarness { mut network_handle, mut virtual_overseer, shared } = test_harness; let peer = PeerId::random(); network_handle .connect_peer(peer, ValidationVersion::V2, PeerSet::Validation, ObservedRole::Full) .await; + await_peer_connections(&shared, 1, 0).await; // bridge will inform about all connected peers. { diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 5f222ad59c7..bdcd1574e33 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -32,7 +32,7 @@ use polkadot_node_subsystem::{ /// To be passed to [`FullNetworkConfiguration::add_notification_protocol`](). pub use polkadot_node_network_protocol::peer_set::{peer_sets_info, IsAuthority}; use polkadot_node_network_protocol::request_response::Requests; -use sc_network::ReputationChange; +use sc_network::{MessageSink, ReputationChange}; use crate::validator_discovery; @@ -60,6 +60,7 @@ pub struct NetworkBridgeTx { metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, } impl NetworkBridgeTx { @@ -74,6 +75,7 @@ impl NetworkBridgeTx { metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Self { Self { network_service, @@ -81,6 +83,7 @@ impl NetworkBridgeTx { metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, } } } @@ -107,6 +110,7 @@ async fn handle_subsystem_messages( metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Result<(), Error> where N: Network, @@ -130,6 +134,7 @@ where &metrics, &req_protocol_names, &peerset_protocol_names, + ¬ification_sinks, ) .await; }, @@ -140,13 +145,14 @@ where #[overseer::contextbounds(NetworkBridgeTx, prefix = self::overseer)] async fn handle_incoming_subsystem_communication( _ctx: &mut Context, - mut network_service: N, + network_service: N, validator_discovery: &mut validator_discovery::Service, mut authority_discovery_service: AD, msg: NetworkBridgeTxMessage, metrics: &Metrics, req_protocol_names: &ReqProtocolNames, peerset_protocol_names: &PeerSetProtocolNames, + notification_sinks: &Arc>>>, ) -> (N, AD) where N: Network, @@ -194,25 +200,22 @@ where match msg { Versioned::V1(msg) => send_validation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_validation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) => send_validation_message_v2( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } }, @@ -227,25 +230,22 @@ where for (peers, msg) in msgs { match msg { Versioned::V1(msg) => send_validation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_validation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) => send_validation_message_v2( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } } @@ -259,18 +259,16 @@ where match msg { Versioned::V1(msg) => send_collation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } }, @@ -284,18 +282,16 @@ where for (peers, msg) in msgs { match msg { Versioned::V1(msg) => send_collation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } } @@ -389,6 +385,7 @@ where metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, } = bridge; handle_subsystem_messages( @@ -398,6 +395,7 @@ where metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, ) .await?; diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 1a2d9a7a424..c3cf0f322f6 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -15,15 +15,18 @@ // along with Polkadot. If not, see . use super::*; -use futures::{executor, stream::BoxStream}; +use futures::executor; use polkadot_node_subsystem_util::TimeoutExt; use async_trait::async_trait; use parking_lot::Mutex; use std::collections::HashSet; -use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; +use sc_network::{ + IfDisconnected, ObservedRole as SubstrateObservedRole, ProtocolName, ReputationChange, Roles, +}; +use parity_scale_codec::DecodeAll; use polkadot_node_network_protocol::{ peer_set::{PeerSetProtocolNames, ValidationVersion}, request_response::{outgoing::Requests, ReqProtocolNames}, @@ -51,10 +54,9 @@ pub enum NetworkAction { WriteNotification(PeerId, PeerSet, Vec), } -// The subsystem's view of the network - only supports a single call to `event_stream`. +// The subsystem's view of the network. #[derive(Clone)] struct TestNetwork { - net_events: Arc>>>, action_tx: Arc>>, peerset_protocol_names: Arc, } @@ -66,37 +68,78 @@ struct TestAuthorityDiscovery; // of `NetworkAction`s. struct TestNetworkHandle { action_rx: metered::UnboundedMeteredReceiver, - net_tx: metered::MeteredSender, - peerset_protocol_names: PeerSetProtocolNames, + _peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, + action_tx: Arc>>, +} + +struct TestMessageSink { + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, +} + +impl TestMessageSink { + fn new( + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, + ) -> TestMessageSink { + Self { peer, peer_set, action_tx } + } +} + +#[async_trait::async_trait] +impl MessageSink for TestMessageSink { + fn send_sync_notification(&self, notification: Vec) { + self.action_tx + .lock() + .unbounded_send(NetworkAction::WriteNotification( + self.peer, + self.peer_set, + notification, + )) + .unwrap(); + } + + async fn send_async_notification( + &self, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } } fn new_test_network( peerset_protocol_names: PeerSetProtocolNames, -) -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) { - let (net_tx, net_rx) = metered::channel(10); +) -> ( + TestNetwork, + TestNetworkHandle, + TestAuthorityDiscovery, + Arc>>>, +) { let (action_tx, action_rx) = metered::unbounded(); + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + let action_tx = Arc::new(Mutex::new(action_tx)); ( TestNetwork { - net_events: Arc::new(Mutex::new(Some(net_rx))), - action_tx: Arc::new(Mutex::new(action_tx)), + action_tx: action_tx.clone(), peerset_protocol_names: Arc::new(peerset_protocol_names.clone()), }, - TestNetworkHandle { action_rx, net_tx, peerset_protocol_names }, + TestNetworkHandle { + action_rx, + _peerset_protocol_names: peerset_protocol_names, + action_tx, + notification_sinks: notification_sinks.clone(), + }, TestAuthorityDiscovery, + notification_sinks, ) } #[async_trait] impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - self.net_events - .lock() - .take() - .expect("Subsystem made more than one call to `event_stream`") - .boxed() - } - async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -130,7 +173,8 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); + let (peer_set, version) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); + assert_eq!(version, peer_set.get_main_version()); self.action_tx .lock() @@ -138,13 +182,10 @@ impl Network for TestNetwork { .unwrap(); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); - - self.action_tx - .lock() - .unbounded_send(NetworkAction::WriteNotification(who, peer_set, message)) - .unwrap(); + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(SubstrateObservedRole::from(role))) } } @@ -174,23 +215,14 @@ impl TestNetworkHandle { async fn connect_peer( &mut self, peer: PeerId, - protocol_version: ValidationVersion, + _protocol_version: ValidationVersion, peer_set: PeerSet, - role: ObservedRole, + _role: ObservedRole, ) { - let protocol_version = ProtocolVersion::from(protocol_version); - self.send_network_event(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol: self.peerset_protocol_names.get_name(peer_set, protocol_version), - negotiated_fallback: None, - role: role.into(), - received_handshake: vec![], - }) - .await; - } - - async fn send_network_event(&mut self, event: NetworkEvent) { - self.net_tx.send(event).await.expect("subsystem concluded early"); + self.notification_sinks.lock().insert( + (peer_set, peer), + Box::new(TestMessageSink::new(peer, peer_set, self.action_tx.clone())), + ); } } @@ -208,7 +240,8 @@ fn test_harness>(test: impl FnOnce(TestHarne let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, fork_id); let pool = sp_core::testing::TaskExecutor::new(); - let (network, network_handle, discovery) = new_test_network(peerset_protocol_names.clone()); + let (network, network_handle, discovery, network_notification_sinks) = + new_test_network(peerset_protocol_names.clone()); let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); @@ -219,6 +252,7 @@ fn test_harness>(test: impl FnOnce(TestHarne Metrics(None), req_protocol_names, peerset_protocol_names, + network_notification_sinks, ); let network_bridge_out_fut = run_network_out(bridge_out, context) @@ -364,9 +398,9 @@ fn network_protocol_versioning_send() { approval_distribution_message.clone(), ); - // Note that bridge doesn't ensure neither peer's protocol version - // or peer set match the message. - let receivers = vec![peer_ids[0], peer_ids[3]]; + // only `peer_ids[0]` opened the validation protocol v2 + // so only they will be sent a notification + let receivers = vec![peer_ids[0]]; virtual_overseer .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendValidationMessage( @@ -406,7 +440,9 @@ fn network_protocol_versioning_send() { let msg = protocol_v2::CollationProtocol::CollatorProtocol(collator_protocol_message.clone()); - let receivers = vec![peer_ids[1], peer_ids[2]]; + // only `peer_ids[0]` opened the collation protocol v2 + // so only they will be sent a notification + let receivers = vec![peer_ids[1]]; virtual_overseer .send(FromOrchestra::Communication { diff --git a/polkadot/node/network/bridge/src/validator_discovery.rs b/polkadot/node/network/bridge/src/validator_discovery.rs index 86e861fbc5b..b11af8a8a08 100644 --- a/polkadot/node/network/bridge/src/validator_discovery.rs +++ b/polkadot/node/network/bridge/src/validator_discovery.rs @@ -169,13 +169,12 @@ mod tests { use crate::network::Network; use async_trait::async_trait; - use futures::stream::BoxStream; use polkadot_node_network_protocol::{ request_response::{outgoing::Requests, ReqProtocolNames}, PeerId, }; use polkadot_primitives::Hash; - use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; + use sc_network::{IfDisconnected, ProtocolName, ReputationChange}; use sp_keyring::Sr25519Keyring; use std::collections::{HashMap, HashSet}; @@ -224,10 +223,6 @@ mod tests { #[async_trait] impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - panic!() - } - async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -263,7 +258,11 @@ mod tests { panic!() } - fn write_notification(&self, _: PeerId, _: ProtocolName, _: Vec) { + fn peer_role( + &self, + _peer_id: PeerId, + _handshake: Vec, + ) -> Option { panic!() } } diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index eb483dec970..7e257d508b5 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -21,6 +21,7 @@ use polkadot_primitives::Hash; use sc_network::{ config::{NonDefaultSetConfig, SetConfig}, types::ProtocolName, + NotificationService, }; use std::{ collections::{hash_map::Entry, HashMap}, @@ -68,7 +69,7 @@ impl PeerSet { self, is_authority: IsAuthority, peerset_protocol_names: &PeerSetProtocolNames, - ) -> NonDefaultSetConfig { + ) -> (NonDefaultSetConfig, (PeerSet, Box)) { // Networking layer relies on `get_main_name()` being the main name of the protocol // for peersets and connection management. let protocol = peerset_protocol_names.get_main_name(self); @@ -76,39 +77,47 @@ impl PeerSet { let max_notification_size = self.get_max_notification_size(is_authority); match self { - PeerSet::Validation => NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names, - max_notification_size, - handshake: None, - set_config: SetConfig { - // we allow full nodes to connect to validators for gossip - // to ensure any `MIN_GOSSIP_PEERS` always include reserved peers - // we limit the amount of non-reserved slots to be less - // than `MIN_GOSSIP_PEERS` in total - in_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, - out_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, - reserved_nodes: Vec::new(), - non_reserved_mode: sc_network::config::NonReservedPeerMode::Accept, - }, + PeerSet::Validation => { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol, + fallback_names, + max_notification_size, + None, + SetConfig { + // we allow full nodes to connect to validators for gossip + // to ensure any `MIN_GOSSIP_PEERS` always include reserved peers + // we limit the amount of non-reserved slots to be less + // than `MIN_GOSSIP_PEERS` in total + in_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, + out_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, + reserved_nodes: Vec::new(), + non_reserved_mode: sc_network::config::NonReservedPeerMode::Accept, + }, + ); + + (config, (PeerSet::Validation, notification_service)) }, - PeerSet::Collation => NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names, - max_notification_size, - handshake: None, - set_config: SetConfig { - // Non-authority nodes don't need to accept incoming connections on this peer - // set: - in_peers: if is_authority == IsAuthority::Yes { 100 } else { 0 }, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: if is_authority == IsAuthority::Yes { - sc_network::config::NonReservedPeerMode::Accept - } else { - sc_network::config::NonReservedPeerMode::Deny + PeerSet::Collation => { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol, + fallback_names, + max_notification_size, + None, + SetConfig { + // Non-authority nodes don't need to accept incoming connections on this + // peer set: + in_peers: if is_authority == IsAuthority::Yes { 100 } else { 0 }, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: if is_authority == IsAuthority::Yes { + sc_network::config::NonReservedPeerMode::Accept + } else { + sc_network::config::NonReservedPeerMode::Deny + }, }, - }, + ); + + (config, (PeerSet::Collation, notification_service)) }, } } @@ -204,7 +213,7 @@ impl IndexMut for PerPeerSet { pub fn peer_sets_info( is_authority: IsAuthority, peerset_protocol_names: &PeerSetProtocolNames, -) -> Vec { +) -> Vec<(NonDefaultSetConfig, (PeerSet, Box))> { PeerSet::iter() .map(|s| s.get_info(is_authority, &peerset_protocol_names)) .collect() @@ -286,7 +295,7 @@ impl From for ProtocolVersion { } /// On the wire protocol name to [`PeerSet`] mapping. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct PeerSetProtocolNames { protocols: HashMap, names: HashMap<(PeerSet, ProtocolVersion), ProtocolName>, diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index e7a4f4a825c..19efd1b66c4 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -89,6 +89,7 @@ kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } +parking_lot = "0.12.1" # Polkadot polkadot-core-primitives = { path = "../../core-primitives" } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 5069ec467c9..70159301fc4 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -51,7 +51,8 @@ use { }, polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig, polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, request_response::ReqProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, + request_response::ReqProtocolNames, }, sc_client_api::BlockBackend, sc_transaction_pool_api::OffchainTransactionPoolFactory, @@ -74,7 +75,7 @@ pub use { #[cfg(feature = "full-node")] use polkadot_node_subsystem::jaeger; -use std::{path::PathBuf, sync::Arc, time::Duration}; +use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; use prometheus_endpoint::Registry; #[cfg(feature = "full-node")] @@ -809,9 +810,9 @@ pub fn new_full( // anything in terms of behaviour, but makes the logs more consistent with the other // Substrate nodes. 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 (grandpa_protocol_config, grandpa_notification_service) = + grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); let beefy_gossip_proto_name = beefy::gossip_protocol_name(&genesis_hash, config.chain_spec.fork_id()); @@ -824,12 +825,17 @@ pub fn new_full( client.clone(), prometheus_registry.clone(), ); - if enable_beefy { - net_config.add_notification_protocol(beefy::communication::beefy_peers_set_config( - beefy_gossip_proto_name.clone(), - )); - net_config.add_request_response_protocol(beefy_req_resp_cfg); - } + let beefy_notification_service = match enable_beefy { + false => None, + true => { + let (beefy_notification_config, beefy_notification_service) = + beefy::communication::beefy_peers_set_config(beefy_gossip_proto_name.clone()); + + net_config.add_notification_protocol(beefy_notification_config); + net_config.add_request_response_protocol(beefy_req_resp_cfg); + Some(beefy_notification_service) + }, + }; // validation/collation protocols are enabled only if `Overseer` is enabled let peerset_protocol_names = @@ -840,13 +846,21 @@ pub fn new_full( // // Collators and parachain full nodes require the collator and validator networking to send // collations and to be able to recover PoVs. - if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { - use polkadot_network_bridge::{peer_sets_info, IsAuthority}; - let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - for config in peer_sets_info(is_authority, &peerset_protocol_names) { - net_config.add_notification_protocol(config); - } - } + let notification_services = + if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { + use polkadot_network_bridge::{peer_sets_info, IsAuthority}; + let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; + + peer_sets_info(is_authority, &peerset_protocol_names) + .into_iter() + .map(|(config, (peerset, service))| { + net_config.add_notification_protocol(config); + (peerset, service) + }) + .collect::>>() + } else { + std::collections::HashMap::new() + }; let req_protocol_names = ReqProtocolNames::new(&genesis_hash, config.chain_spec.fork_id()); @@ -1078,6 +1092,7 @@ pub fn new_full( offchain_transaction_pool_factory: OffchainTransactionPoolFactory::new( transaction_pool.clone(), ), + notification_services, }, ) .map_err(|e| { @@ -1179,13 +1194,15 @@ pub fn new_full( // need a keystore, regardless of which protocol we use below. let keystore_opt = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; - if enable_beefy { + // beefy is enabled if its notification service exists + if let Some(notification_service) = beefy_notification_service { let justifications_protocol_name = beefy_on_demand_justifications_handler.protocol_name(); let network_params = beefy::BeefyNetworkParams { network: network.clone(), sync: sync_service.clone(), gossip_protocol_name: beefy_gossip_proto_name, justifications_protocol_name, + notification_service, _phantom: core::marker::PhantomData::, }; let payload_provider = beefy_primitives::mmr::MmrRootProvider::new(client.clone()); @@ -1265,6 +1282,7 @@ pub fn new_full( prometheus_registry: prometheus_registry.clone(), shared_voter_state, telemetry: telemetry.as_ref().map(|x| x.handle()), + notification_service: grandpa_notification_service, offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()), }; diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index fd618863eea..599563d6454 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -26,7 +26,7 @@ use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1 as request_v1, v2 as request_v2, IncomingRequestReceiver, ReqProtocolNames, }, @@ -41,15 +41,16 @@ use polkadot_overseer::{ OverseerConnector, OverseerHandle, SpawnGlue, }; +use parking_lot::Mutex; use polkadot_primitives::runtime_api::ParachainHost; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_client_api::AuxStore; use sc_keystore::LocalKeystore; -use sc_network::NetworkStateInfo; +use sc_network::{NetworkStateInfo, NotificationService}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_consensus_babe::BabeApi; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem; pub use polkadot_availability_bitfield_distribution::BitfieldDistribution as BitfieldDistributionSubsystem; @@ -140,6 +141,8 @@ where pub peerset_protocol_names: PeerSetProtocolNames, /// The offchain transaction pool factory. pub offchain_transaction_pool_factory: OffchainTransactionPoolFactory, + /// Notification services for validation/collation protocols. + pub notification_services: HashMap>, } /// Obtain a prepared `OverseerBuilder`, that is initialized @@ -173,6 +176,7 @@ pub fn prepared_overseer_builder( req_protocol_names, peerset_protocol_names, offchain_transaction_pool_factory, + notification_services, }: OverseerGenArgs, ) -> Result< InitializedOverseerBuilder< @@ -218,6 +222,7 @@ where use polkadot_node_subsystem_util::metrics::Metrics; let metrics = ::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); let spawner = SpawnGlue(spawner); @@ -235,6 +240,7 @@ where network_bridge_metrics.clone(), req_protocol_names, peerset_protocol_names.clone(), + notification_sinks.clone(), )) .network_bridge_rx(NetworkBridgeRxSubsystem::new( network_service.clone(), @@ -242,6 +248,8 @@ where Box::new(sync_service.clone()), network_bridge_metrics, peerset_protocol_names, + notification_services, + notification_sinks, )) .availability_distribution(AvailabilityDistributionSubsystem::new( keystore.clone(), diff --git a/substrate/bin/node-template/node/src/service.rs b/substrate/bin/node-template/node/src/service.rs index 40320282924..e69428d8190 100644 --- a/substrate/bin/node-template/node/src/service.rs +++ b/substrate/bin/node-template/node/src/service.rs @@ -163,9 +163,9 @@ pub fn new_full(config: Configuration) -> Result { &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); - net_config.add_notification_protocol(sc_consensus_grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); + let (grandpa_protocol_config, grandpa_notification_service) = + sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( backend.clone(), @@ -316,6 +316,7 @@ pub fn new_full(config: Configuration) -> Result { link: grandpa_link, network, sync: Arc::new(sync_service), + notification_service: grandpa_notification_service, voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 1c71b5a3956..a746de8de84 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -370,28 +370,28 @@ pub fn new_full_base( 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 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 (grandpa_protocol_config, grandpa_notification_service) = + grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); - let statement_handler_proto = sc_network_statement::StatementHandlerPrototype::new( - genesis_hash, - config.chain_spec.fork_id(), - ); - net_config.add_notification_protocol(statement_handler_proto.set_config()); + let (statement_handler_proto, statement_config) = + sc_network_statement::StatementHandlerPrototype::new( + genesis_hash, + config.chain_spec.fork_id(), + ); + net_config.add_notification_protocol(statement_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 mixnet_notification_service = mixnet_config.as_ref().map(|mixnet_config| { + let (config, notification_service) = + sc_mixnet::peers_set_config(mixnet_protocol_name.clone(), mixnet_config); + net_config.add_notification_protocol(config); + notification_service + }); let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), @@ -422,6 +422,8 @@ pub fn new_full_base( mixnet_protocol_name, transaction_pool.clone(), Some(keystore_container.keystore()), + mixnet_notification_service + .expect("`NotificationService` exists since mixnet was enabled; qed"), ); task_manager.spawn_handle().spawn("mixnet", None, mixnet); } @@ -590,6 +592,7 @@ pub fn new_full_base( link: grandpa_link, network: network.clone(), sync: Arc::new(sync_service.clone()), + notification_service: grandpa_notification_service, telemetry: telemetry.as_ref().map(|x| x.handle()), voting_rule: grandpa::VotingRulesBuilder::default().build(), prometheus_registry: prometheus_registry.clone(), diff --git a/substrate/client/consensus/beefy/src/communication/mod.rs b/substrate/client/consensus/beefy/src/communication/mod.rs index 10a6071aae6..3827559057d 100644 --- a/substrate/client/consensus/beefy/src/communication/mod.rs +++ b/substrate/client/consensus/beefy/src/communication/mod.rs @@ -67,10 +67,16 @@ pub(crate) mod beefy_protocol_name { /// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. pub fn beefy_peers_set_config( gossip_protocol_name: sc_network::ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { - let mut cfg = sc_network::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); +) -> (sc_network::config::NonDefaultSetConfig, Box) { + let (mut cfg, notification_service) = sc_network::config::NonDefaultSetConfig::new( + gossip_protocol_name, + Vec::new(), + 1024 * 1024, + None, + Default::default(), + ); cfg.allow_non_reserved(25, 25); - cfg + (cfg, notification_service) } // cost scalars for reporting peers. diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 3d104f13250..b3ff11add27 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -38,7 +38,7 @@ use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; use sc_consensus::BlockImport; -use sc_network::{NetworkRequest, ProtocolName}; +use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::ProvideRuntimeApi; use sp_blockchain::{ @@ -178,6 +178,8 @@ pub struct BeefyNetworkParams { pub network: Arc, /// Syncing service implementing a sync oracle and an event stream for peers. pub sync: Arc, + /// Handle for receiving notification events. + pub notification_service: Box, /// Chain specific BEEFY gossip protocol name. See /// [`communication::beefy_protocol_name::gossip_protocol_name`]. pub gossip_protocol_name: ProtocolName, @@ -243,6 +245,7 @@ pub async fn start_beefy_gadget( let BeefyNetworkParams { network, sync, + notification_service, gossip_protocol_name, justifications_protocol_name, .. @@ -264,6 +267,7 @@ pub async fn start_beefy_gadget( let gossip_engine = GossipEngine::new( network.clone(), sync.clone(), + notification_service, gossip_protocol_name.clone(), gossip_validator.clone(), None, diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 3aaa59cbfa1..3f800166e26 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -72,7 +72,7 @@ use substrate_test_runtime_client::{BlockBuilderExt, ClientExt}; use tokio::time::Duration; const GENESIS_HASH: H256 = H256::zero(); -fn beefy_gossip_proto_name() -> ProtocolName { +pub(crate) fn beefy_gossip_proto_name() -> ProtocolName { gossip_protocol_name(GENESIS_HASH, None) } @@ -371,6 +371,7 @@ async fn voter_init_setup( let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), net.peer(0).sync_service().clone(), + net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), "/beefy/whatever", gossip_validator, None, @@ -392,6 +393,14 @@ where { let tasks = FuturesUnordered::new(); + let mut notification_services = peers + .iter() + .map(|(peer_id, _, _)| { + let peer = &mut net.peers[*peer_id]; + (*peer_id, peer.take_notification_service(&beefy_gossip_proto_name()).unwrap()) + }) + .collect::>(); + for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; @@ -409,6 +418,7 @@ where let network_params = crate::BeefyNetworkParams { network: peer.network_service().clone(), sync: peer.sync_service().clone(), + notification_service: notification_services.remove(&peer_id).unwrap(), gossip_protocol_name: beefy_gossip_proto_name(), justifications_protocol_name: on_demand_justif_handler.protocol_name(), _phantom: PhantomData, @@ -1045,7 +1055,25 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + // + // NOTE: code from `voter_init_setup()` is moved here because the new network event system + // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the + // first `GossipEngine` + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let (gossip_validator, _) = GossipValidator::new(known_peers); + let gossip_validator = Arc::new(gossip_validator); + let mut gossip_engine = sc_network_gossip::GossipEngine::new( + net.peer(0).network_service().clone(), + net.peer(0).sync_service().clone(), + net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), + "/beefy/whatever", + gossip_validator, + None, + ); + let (beefy_genesis, best_grandpa) = + wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); + let persisted_state = + load_or_init_voter_state(&*backend, &api, beefy_genesis, best_grandpa, 1).unwrap(); // Test initialization at session boundary. // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) @@ -1075,7 +1103,11 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[10], None).unwrap(); // load persistent state - state preset in DB, but with different pallet genesis - let new_persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + // the network state persists and uses the old `GossipEngine` initialized for `peer(0)` + let (beefy_genesis, best_grandpa) = + wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); + let new_persisted_state = + load_or_init_voter_state(&*backend, &api, beefy_genesis, best_grandpa, 1).unwrap(); // verify voter initialized with single session starting at block `new_pallet_genesis` (10) let sessions = new_persisted_state.voting_oracle().sessions(); @@ -1371,7 +1403,7 @@ async fn gossipped_finality_proofs() { let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - let charlie = &net.peers[2]; + let charlie = &mut net.peers[2]; let known_peers = Arc::new(Mutex::new(KnownPeers::::new())); // Charlie will run just the gossip engine and not the full voter. let (gossip_validator, _) = GossipValidator::new(known_peers); @@ -1384,6 +1416,7 @@ async fn gossipped_finality_proofs() { let mut charlie_gossip_engine = sc_network_gossip::GossipEngine::new( charlie.network_service().clone(), charlie.sync_service().clone(), + charlie.take_notification_service(&beefy_gossip_proto_name()).unwrap(), beefy_gossip_proto_name(), charlie_gossip_validator.clone(), None, diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 0eea5647e51..1fbda974053 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1145,12 +1145,16 @@ pub(crate) mod tests { let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); let network = peer.network_service().clone(); let sync = peer.sync_service().clone(); + let notification_service = peer + .take_notification_service(&crate::tests::beefy_gossip_proto_name()) + .unwrap(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let (gossip_validator, gossip_report_stream) = GossipValidator::new(known_peers.clone()); let gossip_validator = Arc::new(gossip_validator); let gossip_engine = GossipEngine::new( network.clone(), sync.clone(), + notification_service, "/beefy/1", gossip_validator.clone(), None, diff --git a/substrate/client/consensus/grandpa/src/communication/mod.rs b/substrate/client/consensus/grandpa/src/communication/mod.rs index 6d9e956b41b..5c7e1276297 100644 --- a/substrate/client/consensus/grandpa/src/communication/mod.rs +++ b/substrate/client/consensus/grandpa/src/communication/mod.rs @@ -46,7 +46,7 @@ use finality_grandpa::{ Message::{Precommit, Prevote, PrimaryPropose}, }; use parity_scale_codec::{Decode, DecodeAll, Encode}; -use sc_network::{NetworkBlock, NetworkSyncForkRequest, ReputationChange}; +use sc_network::{NetworkBlock, NetworkSyncForkRequest, NotificationService, ReputationChange}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_keystore::KeystorePtr; @@ -247,6 +247,7 @@ impl, S: Syncing> NetworkBridge { pub(crate) fn new( service: N, sync: S, + notification_service: Box, config: crate::Config, set_state: crate::environment::SharedVoterSetState, prometheus_registry: Option<&Registry>, @@ -260,6 +261,7 @@ impl, S: Syncing> NetworkBridge { let gossip_engine = Arc::new(Mutex::new(GossipEngine::new( service.clone(), sync.clone(), + notification_service, protocol, validator.clone(), prometheus_registry, diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 4a869d0f515..b76b1af93da 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -24,16 +24,17 @@ use super::{ }; use crate::{communication::grandpa_protocol_name, environment::SharedVoterSetState}; use futures::prelude::*; -use parity_scale_codec::Encode; +use parity_scale_codec::{DecodeAll, Encode}; use sc_network::{ config::{MultiaddrWithPeerId, Role}, event::Event as NetworkEvent, + service::traits::{Direction, MessageSink, NotificationEvent, NotificationService}, types::ProtocolName, Multiaddr, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT as NotificationSender, PeerId, ReputationChange, }; -use sc_network_common::role::ObservedRole; +use sc_network_common::role::{ObservedRole, Roles}; use sc_network_gossip::Validator; use sc_network_sync::{SyncEvent as SyncStreamEvent, SyncEventStream}; use sc_network_test::{Block, Hash}; @@ -123,6 +124,12 @@ impl NetworkPeers for TestNetwork { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(ObservedRole::from(role))) + } } impl NetworkEventStream for TestNetwork { @@ -211,10 +218,70 @@ impl NetworkSyncForkRequest> for TestSync { fn set_sync_fork_request(&self, _peers: Vec, _hash: Hash, _number: NumberFor) {} } +#[derive(Debug)] +pub(crate) struct TestNotificationService { + sender: TracingUnboundedSender, + rx: TracingUnboundedReceiver, +} + +#[async_trait::async_trait] +impl NotificationService for TestNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, peer: &PeerId, notification: Vec) { + let _ = self.sender.unbounded_send(Event::WriteNotification(*peer, notification)); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } +} + pub(crate) struct Tester { pub(crate) net_handle: super::NetworkBridge, gossip_validator: Arc>, pub(crate) events: TracingUnboundedReceiver, + pub(crate) notification_tx: TracingUnboundedSender, } impl Tester { @@ -279,6 +346,9 @@ fn voter_set_state() -> SharedVoterSetState { // needs to run in a tokio runtime. pub(crate) fn make_test_network() -> (impl Future, TestNetwork) { let (tx, rx) = tracing_unbounded("test", 100_000); + let (notification_tx, notification_rx) = tracing_unbounded("test-notification", 100_000); + + let notification_service = TestNotificationService { rx: notification_rx, sender: tx.clone() }; let net = TestNetwork { sender: tx }; let sync = TestSync {}; @@ -293,14 +363,22 @@ pub(crate) fn make_test_network() -> (impl Future, TestNetwork) } } - let bridge = - super::NetworkBridge::new(net.clone(), sync, config(), voter_set_state(), None, None); + let bridge = super::NetworkBridge::new( + net.clone(), + sync, + Box::new(notification_service), + config(), + voter_set_state(), + None, + None, + ); ( futures::future::ready(Tester { gossip_validator: bridge.validator.clone(), net_handle: bridge, events: rx, + notification_tx, }), net, ) @@ -385,63 +463,62 @@ fn good_commit_leads_to_relay() { let commit_to_send = encoded_commit.clone(); let network_bridge = tester.net_handle.clone(); - // asking for global communication will cause the test network - // to send us an event asking us for a stream. use it to - // send a message. + // `NetworkBridge` will be operational as soon as it's created and it's + // waiting for events from the network. Send it events that inform that + // a notification stream was opened and that a notification was received. + // + // Since each protocol has its own notification stream, events need not be filtered. let sender_id = id; - let send_message = tester.filter_network_events(move |event| match event { - Event::EventStream(sender) => { - // Add the sending peer and send the commit - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id, - protocol: grandpa_protocol_name::NAME.into(), + + let send_message = async move { + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: sender_id, + direction: Direction::Inbound, negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], + handshake: Roles::FULL.encode(), + }, + ); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: sender_id, + notification: commit_to_send.clone(), + }, + ); + + // Add a random peer which will be the recipient of this message + let receiver_id = PeerId::random(); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: receiver_id, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }, + ); + + // Announce its local set being on the current set id through a neighbor + // packet, otherwise it won't be eligible to receive the commit + let _ = { + let update = gossip::VersionedNeighborPacket::V1(gossip::NeighborPacket { + round: Round(round), + set_id: SetId(set_id), + commit_finalized_height: 1, }); - let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - commit_to_send.clone().into(), - )], - }); + let msg = gossip::GossipMessage::::Neighbor(update); - // Add a random peer which will be the recipient of this message - let receiver_id = PeerId::random(); - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: receiver_id, - protocol: grandpa_protocol_name::NAME.into(), - negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], - }); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: receiver_id, + notification: msg.encode(), + }, + ); + }; - // Announce its local set has being on the current set id through a neighbor - // packet, otherwise it won't be eligible to receive the commit - let _ = { - let update = gossip::VersionedNeighborPacket::V1(gossip::NeighborPacket { - round: Round(round), - set_id: SetId(set_id), - commit_finalized_height: 1, - }); - - let msg = gossip::GossipMessage::::Neighbor(update); - - sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: receiver_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - msg.encode().into(), - )], - }) - }; - - true - }, - _ => false, - }); + tester + } + .boxed(); // when the commit comes in, we'll tell the callback it was good. let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() { @@ -537,31 +614,32 @@ fn bad_commit_leads_to_report() { let commit_to_send = encoded_commit.clone(); let network_bridge = tester.net_handle.clone(); - // asking for global communication will cause the test network - // to send us an event asking us for a stream. use it to - // send a message. + // `NetworkBridge` will be operational as soon as it's created and it's + // waiting for events from the network. Send it events that inform that + // a notification stream was opened and that a notification was received. + // + // Since each protocol has its own notification stream, events need not be filtered. let sender_id = id; - let send_message = tester.filter_network_events(move |event| match event { - Event::EventStream(sender) => { - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id, - protocol: grandpa_protocol_name::NAME.into(), + + let send_message = async move { + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: sender_id, + direction: Direction::Inbound, negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], - }); - let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - commit_to_send.clone().into(), - )], - }); + handshake: Roles::FULL.encode(), + }, + ); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: sender_id, + notification: commit_to_send.clone(), + }, + ); - true - }, - _ => false, - }); + tester + } + .boxed(); // when the commit comes in, we'll tell the callback it was bad. let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() { diff --git a/substrate/client/consensus/grandpa/src/lib.rs b/substrate/client/consensus/grandpa/src/lib.rs index a4584e6fc80..b7cfc9f5b60 100644 --- a/substrate/client/consensus/grandpa/src/lib.rs +++ b/substrate/client/consensus/grandpa/src/lib.rs @@ -67,7 +67,7 @@ use sc_client_api::{ BlockchainEvents, CallExecutor, ExecutorProvider, Finalizer, LockImportRun, StorageProvider, }; use sc_consensus::BlockImport; -use sc_network::types::ProtocolName; +use sc_network::{types::ProtocolName, NotificationService}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; @@ -687,6 +687,8 @@ pub struct GrandpaParams { pub network: N, /// Event stream for syncing-related events. pub sync: S, + /// Handle for interacting with `Notifications`. + pub notification_service: Box, /// A voting rule used to potentially restrict target votes. pub voting_rule: VR, /// The prometheus metrics registry. @@ -707,21 +709,21 @@ pub struct GrandpaParams { /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { +) -> (sc_network::config::NonDefaultSetConfig, Box) { use communication::grandpa_protocol_name; - sc_network::config::NonDefaultSetConfig { - notifications_protocol: protocol_name, - fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), + sc_network::config::NonDefaultSetConfig::new( + protocol_name, + grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. - max_notification_size: 1024 * 1024, - handshake: None, - set_config: sc_network::config::SetConfig { + 1024 * 1024, + None, + sc_network::config::SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny, }, - } + ) } /// Run a GRANDPA voter as a task. Provide configuration and a link to a @@ -744,6 +746,7 @@ where link, network, sync, + notification_service, voting_rule, prometheus_registry, shared_voter_state, @@ -770,6 +773,7 @@ where let network = NetworkBridge::new( network, sync, + notification_service, config.clone(), persistent_data.set_state.clone(), prometheus_registry.as_ref(), diff --git a/substrate/client/consensus/grandpa/src/observer.rs b/substrate/client/consensus/grandpa/src/observer.rs index 8541baa822b..608ff5e46a0 100644 --- a/substrate/client/consensus/grandpa/src/observer.rs +++ b/substrate/client/consensus/grandpa/src/observer.rs @@ -28,6 +28,7 @@ use futures::prelude::*; use log::{debug, info, warn}; use sc_client_api::backend::Backend; +use sc_network::NotificationService; use sc_telemetry::TelemetryHandle; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; @@ -168,6 +169,7 @@ pub fn run_grandpa_observer( link: LinkHalf, network: N, sync: S, + notification_service: Box, ) -> sp_blockchain::Result + Send> where BE: Backend + Unpin + 'static, @@ -189,6 +191,7 @@ where let network = NetworkBridge::new( network, sync, + notification_service, config.clone(), persistent_data.set_state.clone(), None, @@ -414,14 +417,14 @@ mod tests { use futures::executor; - /// Ensure `Future` implementation of `ObserverWork` is polling its `NetworkBridge`. Regression - /// test for bug introduced in d4fbb897c and fixed in b7af8b339. + /// Ensure `Future` implementation of `ObserverWork` is polling its `NetworkBridge`. + /// Regression test for bug introduced in d4fbb897c and fixed in b7af8b339. /// - /// When polled, `NetworkBridge` forwards reputation change requests from the `GossipValidator` - /// to the underlying `dyn Network`. This test triggers a reputation change by calling - /// `GossipValidator::validate` with an invalid gossip message. After polling the `ObserverWork` - /// which should poll the `NetworkBridge`, the reputation change should be forwarded to the test - /// network. + /// When polled, `NetworkBridge` forwards reputation change requests from the + /// `GossipValidator` to the underlying `dyn Network`. This test triggers a reputation change + /// by calling `GossipValidator::validate` with an invalid gossip message. After polling the + /// `ObserverWork` which should poll the `NetworkBridge`, the reputation change should be + /// forwarded to the test network. #[test] fn observer_work_polls_underlying_network_bridge() { // Create a test network. @@ -463,12 +466,6 @@ mod tests { // validator to the test network. assert!(observer.now_or_never().is_none()); - // Ignore initial event stream request by gossip engine. - match tester.events.next().now_or_never() { - Some(Some(Event::EventStream(_))) => {}, - _ => panic!("expected event stream request"), - }; - assert_matches!(tester.events.next().now_or_never(), Some(Some(Event::Report(_, _)))); }); } diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 644befe9885..7e42c2d45c7 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -317,6 +317,9 @@ fn initialize_grandpa( (net.peers[peer_id].network_service().clone(), link) }; let sync = net.peers[peer_id].sync_service().clone(); + let notification_service = net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -332,6 +335,7 @@ fn initialize_grandpa( link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -472,6 +476,9 @@ async fn finalize_3_voters_1_full_observer() { let net_service = net.peers[peer_id].network_service().clone(); let sync = net.peers[peer_id].sync_service().clone(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); + let notification_service = net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -487,6 +494,7 @@ async fn finalize_3_voters_1_full_observer() { link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -557,14 +565,17 @@ async fn transition_3_voters_twice_1_full_observer() { for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { let keystore = create_keystore(local_key); - let (net_service, link, sync) = { - let net = net.lock(); + let (net_service, link, sync, notification_service) = { + let mut net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); ( net.peers[peer_id].network_service().clone(), link, net.peers[peer_id].sync_service().clone(), + net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), ) }; @@ -582,6 +593,7 @@ async fn transition_3_voters_twice_1_full_observer() { link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1025,6 +1037,9 @@ async fn voter_persists_its_votes() { communication::NetworkBridge::new( net.peers[1].network_service().clone(), net.peers[1].sync_service().clone(), + net.peers[1] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), config.clone(), set_state, None, @@ -1043,6 +1058,9 @@ async fn voter_persists_its_votes() { (net.peers[0].network_service().clone(), link) }; let sync = net.peers[0].sync_service().clone(); + let notification_service = net.peers[0] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -1058,6 +1076,7 @@ async fn voter_persists_its_votes() { link, network: net_service, sync, + notification_service, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1082,6 +1101,9 @@ async fn voter_persists_its_votes() { net.add_authority_peer(); let net_service = net.peers[2].network_service().clone(); let sync = net.peers[2].sync_service().clone(); + let notification_service = net.peers[2] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); // but we'll reuse the client from the first peer (alice_voter1) // since we want to share the same database, so that we can // read the persisted state after aborting alice_voter1. @@ -1104,6 +1126,7 @@ async fn voter_persists_its_votes() { link, network: net_service, sync, + notification_service, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1255,6 +1278,9 @@ async fn finalize_3_voters_1_light_observer() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); let voters = initialize_grandpa(&mut net, authorities); + let notification_service = net.peers[3] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let observer = observer::run_grandpa_observer( Config { gossip_duration: TEST_GOSSIP_DURATION, @@ -1269,6 +1295,7 @@ async fn finalize_3_voters_1_light_observer() { net.peers[3].data.lock().take().expect("link initialized at startup; qed"), net.peers[3].network_service().clone(), net.peers[3].sync_service().clone(), + notification_service, ) .unwrap(); net.peer(0).push_blocks(20, false); @@ -1317,6 +1344,10 @@ async fn voter_catches_up_to_latest_round_when_behind() { link, network: net.peer(peer_id).network_service().clone(), sync: net.peer(peer_id).sync_service().clone(), + notification_service: net + .peer(peer_id) + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1409,6 +1440,7 @@ fn test_environment_with_select_chain( keystore: Option, network_service: N, sync_service: S, + notification_service: Box, select_chain: SC, voting_rule: VR, ) -> TestEnvironment @@ -1433,6 +1465,7 @@ where let network = NetworkBridge::new( network_service.clone(), sync_service, + notification_service, config.clone(), set_state.clone(), None, @@ -1462,6 +1495,7 @@ fn test_environment( keystore: Option, network_service: N, sync_service: S, + notification_service: Box, voting_rule: VR, ) -> TestEnvironment, VR> where @@ -1474,6 +1508,7 @@ where keystore, network_service, sync_service, + notification_service, link.select_chain.clone(), voting_rule, ) @@ -1490,14 +1525,22 @@ async fn grandpa_environment_respects_voting_rules() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let mut notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); // add 21 blocks let hashes = peer.push_blocks(21, false); // create an environment with no voting rule restrictions - let unrestricted_env = - test_environment(&link, None, network_service.clone(), sync_service.clone(), ()); + let unrestricted_env = test_environment( + &link, + None, + network_service.clone(), + sync_service.clone(), + notification_service.clone().unwrap(), + (), + ); // another with 3/4 unfinalized chain voting rule restriction let three_quarters_env = test_environment( @@ -1505,6 +1548,7 @@ async fn grandpa_environment_respects_voting_rules() { None, network_service.clone(), sync_service.clone(), + notification_service.clone().unwrap(), voting_rule::ThreeQuartersOfTheUnfinalizedChain, ); @@ -1515,6 +1559,7 @@ async fn grandpa_environment_respects_voting_rules() { None, network_service.clone(), sync_service, + notification_service, VotingRulesBuilder::default().build(), ); @@ -1608,6 +1653,8 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1622,6 +1669,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { None, network_service.clone(), sync_service, + notification_service, select_chain.clone(), voting_rule::BeforeBestBlockBy(5), ); @@ -1669,6 +1717,8 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1678,6 +1728,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ None, network_service.clone(), sync_service.clone(), + notification_service, select_chain.clone(), voting_rule.clone(), ); @@ -1780,11 +1831,19 @@ async fn grandpa_environment_never_overwrites_round_voter_state() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(peers[0]); - let environment = - test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()); + let environment = test_environment( + &link, + Some(keystore), + network_service.clone(), + sync_service, + notification_service, + (), + ); let round_state = || finality_grandpa::round::State::genesis(Default::default()); let base = || Default::default(); @@ -2012,9 +2071,18 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(alice); - test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()) + test_environment( + &link, + Some(keystore), + network_service.clone(), + sync_service, + notification_service, + (), + ) }; let signed_prevote = { diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index e185754b076..1c06da1e3c1 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -384,7 +384,9 @@ fn test_max_memory_pages( ) (i32.const -1) ) - (unreachable) + (then + (unreachable) + ) ) (i64.const 0) @@ -421,7 +423,9 @@ fn test_max_memory_pages( ) (i32.const -1) ) - (unreachable) + (then + (unreachable) + ) ) (i64.const 0) diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 86c5a37754a..d11cb1805ff 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "4.1" arrayvec = "0.7.2" blake2 = "0.10.4" +bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } futures = "0.3.25" futures-timer = "3.0.2" diff --git a/substrate/client/mixnet/src/packet_dispatcher.rs b/substrate/client/mixnet/src/packet_dispatcher.rs index 856208ecb34..420e0c68847 100644 --- a/substrate/client/mixnet/src/packet_dispatcher.rs +++ b/substrate/client/mixnet/src/packet_dispatcher.rs @@ -24,7 +24,7 @@ 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 sc_network::NotificationService; use std::{collections::HashMap, future::Future, sync::Arc}; const LOG_TARGET: &str = "mixnet"; @@ -77,41 +77,37 @@ pub struct ReadyPeer { } 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. + /// 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, + notification_service: &Box, ) -> Option>> { - match network.notification_sender(self.id, protocol_name) { - Err(err) => { + match notification_service.message_sink(&self.id) { + None => { debug!( target: LOG_TARGET, - "Failed to get notification sender for peer ID {}: {err}", self.id + "Failed to get message sink for peer ID {}", 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) - }) { + Some(sink) => Some(async move { + let (packet, more_packets) = self.queue.pop(); + let packet = packet.expect("Should only be called if there is a packet to send"); + + match sink.send_async_notification((packet as Box<[_]>).into()).await { + Ok(_) => more_packets.then_some(self), Err(err) => { debug!( target: LOG_TARGET, - "Notification sender for peer ID {} failed: {err}", self.id + "Failed to send packet to peer ID {}: {err}", self.id, ); self.queue.clear(); None }, - Ok(more_packets) => more_packets.then(|| self), } }), } diff --git a/substrate/client/mixnet/src/protocol.rs b/substrate/client/mixnet/src/protocol.rs index 555c267b86e..955502a4856 100644 --- a/substrate/client/mixnet/src/protocol.rs +++ b/substrate/client/mixnet/src/protocol.rs @@ -18,7 +18,10 @@ use super::config::Config; use mixnet::core::PACKET_SIZE; -use sc_network::{config::NonDefaultSetConfig, ProtocolName}; +use sc_network::{ + config::{NonDefaultSetConfig, NonReservedPeerMode, SetConfig}, + NotificationService, 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 { @@ -31,12 +34,26 @@ pub fn protocol_name(genesis_hash: &[u8], fork_id: Option<&str>) -> ProtocolName } /// 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); +pub fn peers_set_config( + name: ProtocolName, + config: &Config, +) -> (NonDefaultSetConfig, Box) { + let (mut set_config, service) = NonDefaultSetConfig::new( + name, + Vec::new(), + PACKET_SIZE as u64, + None, + SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + ); 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 + (set_config, service) } diff --git a/substrate/client/mixnet/src/run.rs b/substrate/client/mixnet/src/run.rs index 09020469d5e..14d188df097 100644 --- a/substrate/client/mixnet/src/run.rs +++ b/substrate/client/mixnet/src/run.rs @@ -29,11 +29,12 @@ use super::{ request::{extrinsic_delay, Request, SUBMIT_EXTRINSIC}, sync_with_runtime::sync_with_runtime, }; +use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; use futures::{ future::{pending, Either}, stream::FuturesUnordered, - StreamExt, + FutureExt, StreamExt, }; use log::{debug, error, trace, warn}; use mixnet::{ @@ -43,8 +44,8 @@ use mixnet::{ }; use sc_client_api::{BlockchainEvents, HeaderBackend}; use sc_network::{ - Event::{NotificationStreamClosed, NotificationStreamOpened, NotificationsReceived}, - NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo, ProtocolName, + service::traits::{NotificationEvent, ValidationResult}, + NetworkNotification, NetworkPeers, NetworkStateInfo, NotificationService, ProtocolName, }; use sc_transaction_pool_api::{ LocalTransactionPool, OffchainTransactionPoolFactory, TransactionPool, @@ -154,12 +155,13 @@ pub async fn run( protocol_name: ProtocolName, transaction_pool: Arc

, keystore: Option, + mut notification_service: Box, ) where B: Block, C: BlockchainEvents + ProvideRuntimeApi + HeaderBackend, C::Api: MixnetApi, S: SyncOracle, - N: NetworkStateInfo + NetworkEventStream + NetworkNotification + NetworkPeers, + N: NetworkStateInfo + NetworkNotification + NetworkPeers, P: TransactionPool + LocalTransactionPool + 'static, { let local_peer_id = network.local_peer_id(); @@ -189,7 +191,6 @@ pub async fn run( } 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(); @@ -248,33 +249,36 @@ pub async fn run( } } - 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(), - ), - } - } + event = notification_service.next_event().fuse() => match event { + None => todo!(), + Some(NotificationEvent::ValidateInboundSubstream { result_tx, .. }) => { + let _ = result_tx.send(ValidationResult::Accept); + }, + Some(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + packet_dispatcher.add_peer(&peer); + }, + Some(NotificationEvent::NotificationStreamClosed { peer }) => { + packet_dispatcher.remove_peer(&peer); + }, + Some(NotificationEvent::NotificationReceived { peer, notification }) => { + let notification: Bytes = notification.into(); + + match notification.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 {peer}", + notification.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()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } @@ -288,7 +292,7 @@ pub async fn run( _ = 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()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } @@ -297,7 +301,7 @@ pub async fn run( 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()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } diff --git a/substrate/client/mixnet/src/sync_with_runtime.rs b/substrate/client/mixnet/src/sync_with_runtime.rs index 4a80b3c75f4..f3be9602541 100644 --- a/substrate/client/mixnet/src/sync_with_runtime.rs +++ b/substrate/client/mixnet/src/sync_with_runtime.rs @@ -196,6 +196,7 @@ where #[cfg(test)] mod tests { use super::*; + use multiaddr::multiaddr; #[test] fn fixup_empty_external_addresses() { diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 95e26a232c1..5006d5d0e3e 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -29,5 +29,7 @@ sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] tokio = "1.22.0" +async-trait = "0.1.73" +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 8f7d490757b..c1bc414c3a3 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -21,7 +21,11 @@ use crate::{ Network, Syncing, Validator, }; -use sc_network::{event::Event, types::ProtocolName, ReputationChange}; +use sc_network::{ + service::traits::{NotificationEvent, ValidationResult}, + types::ProtocolName, + NotificationService, ReputationChange, +}; use sc_network_sync::SyncEvent; use futures::{ @@ -48,10 +52,10 @@ pub struct GossipEngine { periodic_maintenance_interval: futures_timer::Delay, protocol: ProtocolName, - /// Incoming events from the network. - network_event_stream: Pin + Send>>, /// Incoming events from the syncing service. sync_event_stream: Pin + Send>>, + /// Handle for polling notification-related events. + notification_service: Box, /// Outgoing events to the consumer. message_sinks: HashMap>>, /// Buffered messages (see [`ForwardingState`]). @@ -81,6 +85,7 @@ impl GossipEngine { pub fn new( network: N, sync: S, + notification_service: Box, protocol: impl Into, validator: Arc>, metrics_registry: Option<&Registry>, @@ -91,17 +96,16 @@ impl GossipEngine { S: Syncing + Send + Clone + 'static, { let protocol = protocol.into(); - let network_event_stream = network.event_stream("network-gossip"); let sync_event_stream = sync.event_stream("network-gossip"); GossipEngine { state_machine: ConsensusGossip::new(validator, protocol.clone(), metrics_registry), network: Box::new(network), sync: Box::new(sync), + notification_service, periodic_maintenance_interval: futures_timer::Delay::new(PERIODIC_MAINTENANCE_INTERVAL), protocol, - network_event_stream, sync_event_stream, message_sinks: HashMap::new(), forwarding_state: ForwardingState::Idle, @@ -125,7 +129,7 @@ impl GossipEngine { /// Broadcast all messages with given topic. pub fn broadcast_topic(&mut self, topic: B::Hash, force: bool) { - self.state_machine.broadcast_topic(&mut *self.network, topic, force); + self.state_machine.broadcast_topic(&mut self.notification_service, topic, force); } /// Get data of valid, incoming messages for a topic (but might have expired meanwhile). @@ -150,19 +154,21 @@ impl GossipEngine { /// Send all messages with given topic to a peer. pub fn send_topic(&mut self, who: &PeerId, topic: B::Hash, force: bool) { - self.state_machine.send_topic(&mut *self.network, who, topic, force) + self.state_machine.send_topic(&mut self.notification_service, who, topic, force) } /// Multicast a message to all peers. pub fn gossip_message(&mut self, topic: B::Hash, message: Vec, force: bool) { - self.state_machine.multicast(&mut *self.network, topic, message, force) + self.state_machine + .multicast(&mut self.notification_service, topic, message, force) } /// Send addressed message to the given peers. The message is not kept or multicast /// later on. pub fn send_message(&mut self, who: Vec, data: Vec) { for who in &who { - self.state_machine.send_message(&mut *self.network, who, data.clone()); + self.state_machine + .send_message(&mut self.notification_service, who, data.clone()); } } @@ -173,6 +179,11 @@ impl GossipEngine { pub fn announce(&self, block: B::Hash, associated_data: Option>) { self.sync.announce_block(block, associated_data); } + + /// Consume [`GossipEngine`] and return the notification service. + pub fn take_notification_service(self) -> Box { + self.notification_service + } } impl Future for GossipEngine { @@ -184,46 +195,56 @@ impl Future for GossipEngine { 'outer: loop { match &mut this.forwarding_state { ForwardingState::Idle => { - let net_event_stream = this.network_event_stream.poll_next_unpin(cx); + let next_notification_event = + this.notification_service.next_event().poll_unpin(cx); let sync_event_stream = this.sync_event_stream.poll_next_unpin(cx); - if net_event_stream.is_pending() && sync_event_stream.is_pending() { + if next_notification_event.is_pending() && sync_event_stream.is_pending() { break } - match net_event_stream { + match next_notification_event { Poll::Ready(Some(event)) => match event { - Event::NotificationStreamOpened { remote, protocol, role, .. } => - if protocol == this.protocol { - this.state_machine.new_peer(&mut *this.network, remote, role); - }, - Event::NotificationStreamClosed { remote, protocol } => { - if protocol == this.protocol { - this.state_machine - .peer_disconnected(&mut *this.network, remote); - } + NotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + .. + } => { + // only accept peers whose role can be determined + let result = this + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, - Event::NotificationsReceived { remote, messages } => { - let messages = messages - .into_iter() - .filter_map(|(engine, data)| { - if engine == this.protocol { - Some(data.to_vec()) - } else { - None - } - }) - .collect(); - + NotificationEvent::NotificationStreamOpened { + peer, handshake, .. + } => { + let Some(role) = this.network.peer_role(peer, handshake) else { + log::debug!(target: "gossip", "role for {peer} couldn't be determined"); + continue + }; + + this.state_machine.new_peer( + &mut this.notification_service, + peer, + role, + ); + }, + NotificationEvent::NotificationStreamClosed { peer } => { + this.state_machine + .peer_disconnected(&mut this.notification_service, peer); + }, + NotificationEvent::NotificationReceived { peer, notification } => { let to_forward = this.state_machine.on_incoming( &mut *this.network, - remote, - messages, + &mut this.notification_service, + peer, + vec![notification], ); - this.forwarding_state = ForwardingState::Busy(to_forward.into()); }, - Event::Dht(_) => {}, }, // The network event stream closed. Do the same for [`GossipValidator`]. Poll::Ready(None) => { @@ -306,7 +327,7 @@ impl Future for GossipEngine { while let Poll::Ready(()) = this.periodic_maintenance_interval.poll_unpin(cx) { this.periodic_maintenance_interval.reset(PERIODIC_MAINTENANCE_INTERVAL); - this.state_machine.tick(&mut *this.network); + this.state_machine.tick(&mut this.notification_service); this.message_sinks.retain(|_, sinks| { sinks.retain(|sink| !sink.is_closed()); @@ -328,15 +349,19 @@ impl futures::future::FusedFuture for GossipEngine { mod tests { use super::*; use crate::{multiaddr::Multiaddr, ValidationResult, ValidatorContext}; + use codec::{DecodeAll, Encode}; use futures::{ - channel::mpsc::{unbounded, UnboundedSender}, + channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, executor::{block_on, block_on_stream}, future::poll_fn, }; use quickcheck::{Arbitrary, Gen, QuickCheck}; use sc_network::{ - config::MultiaddrWithPeerId, NetworkBlock, NetworkEventStream, NetworkNotification, - NetworkPeers, NotificationSenderError, NotificationSenderT as NotificationSender, + config::MultiaddrWithPeerId, + service::traits::{Direction, MessageSink, NotificationEvent}, + Event, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSenderError, NotificationSenderT as NotificationSender, NotificationService, + Roles, }; use sc_network_common::role::ObservedRole; use sc_network_sync::SyncEventStream; @@ -351,14 +376,10 @@ mod tests { use substrate_test_runtime_client::runtime::Block; #[derive(Clone, Default)] - struct TestNetwork { - inner: Arc>, - } + struct TestNetwork {} #[derive(Clone, Default)] - struct TestNetworkInner { - event_senders: Vec>, - } + struct TestNetworkInner {} impl NetworkPeers for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { @@ -422,14 +443,17 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(ObservedRole::from(role))) + } } impl NetworkEventStream for TestNetwork { fn event_stream(&self, _name: &'static str) -> Pin + Send>> { - let (tx, rx) = unbounded(); - self.inner.lock().unwrap().event_senders.push(tx); - - Box::pin(rx) + unimplemented!(); } } @@ -501,6 +525,58 @@ mod tests { } } + #[derive(Debug)] + pub(crate) struct TestNotificationService { + rx: UnboundedReceiver, + } + + #[async_trait::async_trait] + impl sc_network::service::traits::NotificationService for TestNotificationService { + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } + } + struct AllowAll; impl Validator for AllowAll { fn validate( @@ -521,16 +597,19 @@ mod tests { fn returns_when_network_event_stream_closes() { let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let mut gossip_engine = GossipEngine::::new( network.clone(), sync, + notification_service, "/my_protocol", Arc::new(AllowAll {}), None, ); - // Drop network event stream sender side. - drop(network.inner.lock().unwrap().event_senders.pop()); + // drop notification service sender side. + drop(tx); block_on(poll_fn(move |ctx| { if let Poll::Pending = gossip_engine.poll_unpin(ctx) { @@ -550,42 +629,37 @@ mod tests { let remote_peer = PeerId::random(); let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (mut tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let mut gossip_engine = GossipEngine::::new( network.clone(), sync.clone(), + notification_service, protocol.clone(), Arc::new(AllowAll {}), None, ); - let mut event_sender = network.inner.lock().unwrap().event_senders.pop().unwrap(); - // Register the remote peer. - event_sender - .start_send(Event::NotificationStreamOpened { - remote: remote_peer, - protocol: protocol.clone(), - negotiated_fallback: None, - role: ObservedRole::Authority, - received_handshake: vec![], - }) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationStreamOpened { + peer: remote_peer, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }) + .await + .unwrap(); let messages = vec![vec![1], vec![2]]; - let events = messages - .iter() - .cloned() - .map(|m| Event::NotificationsReceived { - remote: remote_peer, - messages: vec![(protocol.clone(), m.into())], - }) - .collect::>(); // Send first event before subscribing. - event_sender - .start_send(events[0].clone()) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: messages[0].clone().into(), + }) + .await + .unwrap(); let mut subscribers = vec![]; for _ in 0..2 { @@ -593,9 +667,12 @@ mod tests { } // Send second event after subscribing. - event_sender - .start_send(events[1].clone()) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: messages[1].clone().into(), + }) + .await + .unwrap(); tokio::spawn(gossip_engine); @@ -672,6 +749,8 @@ mod tests { let remote_peer = PeerId::random(); let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (mut tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let num_channels_per_topic = channels.iter().fold( HashMap::new(), @@ -699,6 +778,7 @@ mod tests { let mut gossip_engine = GossipEngine::::new( network.clone(), sync.clone(), + notification_service, protocol.clone(), Arc::new(TestValidator {}), None, @@ -724,22 +804,18 @@ mod tests { } } - let mut event_sender = network.inner.lock().unwrap().event_senders.pop().unwrap(); - // Register the remote peer. - event_sender - .start_send(Event::NotificationStreamOpened { - remote: remote_peer, - protocol: protocol.clone(), - negotiated_fallback: None, - role: ObservedRole::Authority, - received_handshake: vec![], - }) - .expect("Event stream is unbounded; qed."); + tx.start_send(NotificationEvent::NotificationStreamOpened { + peer: remote_peer, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }) + .unwrap(); // Send messages into the network event stream. for (i_notification, messages) in notifications.iter().enumerate() { - let messages = messages + let messages: Vec> = messages .into_iter() .enumerate() .map(|(i_message, Message { topic })| { @@ -752,13 +828,17 @@ mod tests { message.push(i_notification.try_into().unwrap()); message.push(i_message.try_into().unwrap()); - (protocol.clone(), message.into()) + message.into() }) .collect(); - event_sender - .start_send(Event::NotificationsReceived { remote: remote_peer, messages }) - .expect("Event stream is unbounded; qed."); + for message in messages { + tx.start_send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: message, + }) + .unwrap(); + } } let mut received_msgs_per_topic_all_chan = HashMap::::new(); diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index 4bfb5a7d37f..91b56b0f097 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -23,7 +23,7 @@ use libp2p::PeerId; use schnellru::{ByLength, LruMap}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network::types::ProtocolName; +use sc_network::{types::ProtocolName, NotificationService}; use sc_network_common::role::ObservedRole; use sp_runtime::traits::{Block as BlockT, Hash, HashingFor}; use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; @@ -74,33 +74,33 @@ struct MessageEntry { /// Local implementation of `ValidatorContext`. struct NetworkContext<'g, 'p, B: BlockT> { gossip: &'g mut ConsensusGossip, - network: &'p mut dyn Network, + notification_service: &'p mut Box, } impl<'g, 'p, B: BlockT> ValidatorContext for NetworkContext<'g, 'p, B> { /// Broadcast all messages with given topic to peers that do not have it yet. fn broadcast_topic(&mut self, topic: B::Hash, force: bool) { - self.gossip.broadcast_topic(self.network, topic, force); + self.gossip.broadcast_topic(self.notification_service, topic, force); } /// Broadcast a message to all peers that have not received it previously. fn broadcast_message(&mut self, topic: B::Hash, message: Vec, force: bool) { - self.gossip.multicast(self.network, topic, message, force); + self.gossip.multicast(self.notification_service, topic, message, force); } /// Send addressed message to a peer. fn send_message(&mut self, who: &PeerId, message: Vec) { - self.network.write_notification(*who, self.gossip.protocol.clone(), message); + self.notification_service.send_sync_notification(who, message); } /// Send all messages with given topic to a peer. fn send_topic(&mut self, who: &PeerId, topic: B::Hash, force: bool) { - self.gossip.send_topic(self.network, who, topic, force); + self.gossip.send_topic(self.notification_service, who, topic, force); } } fn propagate<'a, B: BlockT, I>( - network: &mut dyn Network, + notification_service: &mut Box, protocol: ProtocolName, messages: I, intent: MessageIntent, @@ -147,7 +147,7 @@ where ?message, "Propagating message", ); - network.write_notification(*id, protocol.clone(), message.clone()); + notification_service.send_sync_notification(id, message.clone()); } } } @@ -191,7 +191,12 @@ impl ConsensusGossip { } /// Handle new connected peer. - pub fn new_peer(&mut self, network: &mut dyn Network, who: PeerId, role: ObservedRole) { + pub fn new_peer( + &mut self, + notification_service: &mut Box, + who: PeerId, + role: ObservedRole, + ) { tracing::trace!( target:"gossip", %who, @@ -202,7 +207,7 @@ impl ConsensusGossip { self.peers.insert(who, PeerConsensus { known_messages: Default::default() }); let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.new_peer(&mut context, &who, role); } @@ -233,30 +238,35 @@ impl ConsensusGossip { } /// Call when a peer has been disconnected to stop tracking gossip status. - pub fn peer_disconnected(&mut self, network: &mut dyn Network, who: PeerId) { + pub fn peer_disconnected( + &mut self, + notification_service: &mut Box, + who: PeerId, + ) { let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.peer_disconnected(&mut context, &who); self.peers.remove(&who); } /// Perform periodic maintenance - pub fn tick(&mut self, network: &mut dyn Network) { + pub fn tick(&mut self, notification_service: &mut Box) { self.collect_garbage(); if Instant::now() >= self.next_broadcast { - self.rebroadcast(network); + self.rebroadcast(notification_service); self.next_broadcast = Instant::now() + REBROADCAST_INTERVAL; } } /// Rebroadcast all messages to all peers. - fn rebroadcast(&mut self, network: &mut dyn Network) { + fn rebroadcast(&mut self, notification_service: &mut Box) { let messages = self .messages .iter() .map(|entry| (&entry.message_hash, &entry.topic, &entry.message)); + propagate( - network, + notification_service, self.protocol.clone(), messages, MessageIntent::PeriodicRebroadcast, @@ -266,7 +276,12 @@ impl ConsensusGossip { } /// Broadcast all messages with given topic. - pub fn broadcast_topic(&mut self, network: &mut dyn Network, topic: B::Hash, force: bool) { + pub fn broadcast_topic( + &mut self, + notification_service: &mut Box, + topic: B::Hash, + force: bool, + ) { let messages = self.messages.iter().filter_map(|entry| { if entry.topic == topic { Some((&entry.message_hash, &entry.topic, &entry.message)) @@ -276,7 +291,7 @@ impl ConsensusGossip { }); let intent = if force { MessageIntent::ForcedBroadcast } else { MessageIntent::Broadcast }; propagate( - network, + notification_service, self.protocol.clone(), messages, intent, @@ -327,6 +342,7 @@ impl ConsensusGossip { pub fn on_incoming( &mut self, network: &mut dyn Network, + notification_service: &mut Box, who: PeerId, messages: Vec>, ) -> Vec<(B::Hash, TopicNotification)> { @@ -367,7 +383,7 @@ impl ConsensusGossip { // validate the message let validation = { let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.validate(&mut context, &who, &message) }; @@ -414,7 +430,7 @@ impl ConsensusGossip { /// Send all messages with given topic to a peer. pub fn send_topic( &mut self, - network: &mut dyn Network, + notification_service: &mut Box, who: &PeerId, topic: B::Hash, force: bool, @@ -443,7 +459,7 @@ impl ConsensusGossip { ?entry.message, "Sending topic message", ); - network.write_notification(*who, self.protocol.clone(), entry.message.clone()); + notification_service.send_sync_notification(who, entry.message.clone()); } } } @@ -451,7 +467,7 @@ impl ConsensusGossip { /// Multicast a message to all peers. pub fn multicast( &mut self, - network: &mut dyn Network, + notification_service: &mut Box, topic: B::Hash, message: Vec, force: bool, @@ -460,7 +476,7 @@ impl ConsensusGossip { self.register_message_hashed(message_hash, topic, message.clone(), None); let intent = if force { MessageIntent::ForcedBroadcast } else { MessageIntent::Broadcast }; propagate( - network, + notification_service, self.protocol.clone(), iter::once((&message_hash, &topic, &message)), intent, @@ -471,7 +487,12 @@ impl ConsensusGossip { /// Send addressed message to a peer. The message is not kept or multicast /// later on. - pub fn send_message(&mut self, network: &mut dyn Network, who: &PeerId, message: Vec) { + pub fn send_message( + &mut self, + notification_service: &mut Box, + who: &PeerId, + message: Vec, + ) { let peer = match self.peers.get_mut(who) { None => return, Some(peer) => peer, @@ -488,7 +509,7 @@ impl ConsensusGossip { ); peer.known_messages.insert(message_hash); - network.write_notification(*who, self.protocol.clone(), message); + notification_service.send_sync_notification(who, message) } } @@ -524,9 +545,9 @@ mod tests { use crate::multiaddr::Multiaddr; use futures::prelude::*; use sc_network::{ - config::MultiaddrWithPeerId, event::Event, NetworkBlock, NetworkEventStream, - NetworkNotification, NetworkPeers, NotificationSenderError, - NotificationSenderT as NotificationSender, ReputationChange, + config::MultiaddrWithPeerId, event::Event, service::traits::NotificationEvent, MessageSink, + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSenderError, NotificationSenderT as NotificationSender, ReputationChange, }; use sp_runtime::{ testing::{Block as RawBlock, ExtrinsicWrapper, H256}, @@ -651,6 +672,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } impl NetworkEventStream for NoOpNetwork { @@ -691,6 +716,62 @@ mod tests { } } + #[derive(Debug, Default)] + struct NoOpNotificationService {} + + #[async_trait::async_trait] + impl NotificationService for NoOpNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + None + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } + } + #[test] fn collects_garbage() { struct AllowOne; @@ -773,20 +854,28 @@ mod tests { fn peer_is_removed_on_disconnect() { let mut consensus = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None); - let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let peer_id = PeerId::random(); - consensus.new_peer(&mut network, peer_id, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id)); - consensus.peer_disconnected(&mut network, peer_id); + consensus.peer_disconnected(&mut notification_service, peer_id); assert!(!consensus.peers.contains_key(&peer_id)); } #[test] fn on_incoming_ignores_discarded_messages() { + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let to_forward = ConsensusGossip::::new(Arc::new(DiscardAll), "/foo".into(), None) - .on_incoming(&mut NoOpNetwork::default(), PeerId::random(), vec![vec![1, 2, 3]]); + .on_incoming( + &mut NoOpNetwork::default(), + &mut notification_service, + PeerId::random(), + vec![vec![1, 2, 3]], + ); assert!( to_forward.is_empty(), @@ -798,11 +887,14 @@ mod tests { #[test] fn on_incoming_ignores_unregistered_peer() { let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let remote = PeerId::random(); let to_forward = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None) .on_incoming( &mut network, + &mut notification_service, // Unregistered peer. remote, vec![vec![1, 2, 3]], @@ -822,18 +914,20 @@ mod tests { let mut consensus = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None); let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let peer_id = PeerId::random(); - consensus.new_peer(&mut network, peer_id, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id)); let peer_id2 = PeerId::random(); - consensus.new_peer(&mut network, peer_id2, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id2, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id2)); let message = vec![vec![1, 2, 3]]; - consensus.on_incoming(&mut network, peer_id, message.clone()); - consensus.on_incoming(&mut network, peer_id2, message.clone()); + consensus.on_incoming(&mut network, &mut notification_service, peer_id, message.clone()); + consensus.on_incoming(&mut network, &mut notification_service, peer_id2, message.clone()); assert_eq!( vec![(peer_id, rep::GOSSIP_SUCCESS)], diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 7b0536addda..8b599f058f7 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -37,6 +37,8 @@ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.108" smallvec = "1.11.0" thiserror = "1.0" +tokio = { version = "1.22.0", features = ["macros", "sync"] } +tokio-stream = "0.1.7" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } zeroize = "1.4.3" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/network/common/src/role.rs b/substrate/client/network/common/src/role.rs index fd02c00e232..11b7a7924c4 100644 --- a/substrate/client/network/common/src/role.rs +++ b/substrate/client/network/common/src/role.rs @@ -28,7 +28,7 @@ use codec::{self, Encode, EncodeLike, Input, Output}; /// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a /// > node says about itself, while `ObservedRole` is a `Role` merged with the /// > information known locally about that node. -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ObservedRole { /// Full node. Full, @@ -45,6 +45,18 @@ impl ObservedRole { } } +impl From for ObservedRole { + fn from(roles: Roles) -> Self { + if roles.is_authority() { + ObservedRole::Authority + } else if roles.is_full() { + ObservedRole::Full + } else { + ObservedRole::Light + } + } +} + /// Role of the local node. #[derive(Debug, Clone)] pub enum Role { diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 0aa724818e0..9f770bc3ba7 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -22,12 +22,13 @@ use crate::{ peer_info, peer_store::PeerStoreHandle, protocol::{CustomMessageOutcome, NotificationsSink, Protocol}, + protocol_controller::SetId, request_responses::{self, IfDisconnected, ProtocolConfig, RequestFailure}, + service::traits::Direction, types::ProtocolName, ReputationChange, }; -use bytes::Bytes; use futures::channel::oneshot; use libp2p::{ core::Multiaddr, identify::Info as IdentifyInfo, identity::PublicKey, kad::RecordKey, @@ -35,7 +36,6 @@ use libp2p::{ }; use parking_lot::Mutex; -use sc_network_common::role::{ObservedRole, Roles}; use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, sync::Arc, time::Duration}; @@ -97,8 +97,10 @@ pub enum BehaviourOut { NotificationStreamOpened { /// Node we opened the substream with. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, + /// Direction of the stream. + direction: Direction, /// If the negotiation didn't use the main name of the protocol (the one in /// `notifications_protocol`), then this field contains which name has actually been /// used. @@ -106,8 +108,6 @@ pub enum BehaviourOut { negotiated_fallback: Option, /// Object that permits sending notifications to the peer. notifications_sink: NotificationsSink, - /// Role of the remote. - role: ObservedRole, /// Received handshake. received_handshake: Vec, }, @@ -120,8 +120,8 @@ pub enum BehaviourOut { NotificationStreamReplaced { /// Id of the peer we are connected to. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, /// Replacement for the previous [`NotificationsSink`]. notifications_sink: NotificationsSink, }, @@ -131,16 +131,18 @@ pub enum BehaviourOut { NotificationStreamClosed { /// Node we closed the substream with. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, }, /// Received one or more messages from the given node using the given protocol. NotificationsReceived { /// Node we received the message from. remote: PeerId, + /// Set ID. + set_id: SetId, /// Concerned protocol and associated message. - messages: Vec<(ProtocolName, Bytes)>, + notification: Vec, }, /// We have obtained identity information from a peer, including the addresses it is listening @@ -272,44 +274,33 @@ impl Behaviour { } } -fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { - if roles.is_authority() { - ObservedRole::Authority - } else if roles.is_full() { - ObservedRole::Full - } else { - ObservedRole::Light - } -} - impl From for BehaviourOut { fn from(event: CustomMessageOutcome) -> Self { match event { CustomMessageOutcome::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, - roles, received_handshake, notifications_sink, } => BehaviourOut::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, - role: reported_roles_to_observed_role(roles), received_handshake, notifications_sink, }, CustomMessageOutcome::NotificationStreamReplaced { remote, - protocol, + set_id, notifications_sink, - } => BehaviourOut::NotificationStreamReplaced { remote, protocol, notifications_sink }, - CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => - BehaviourOut::NotificationStreamClosed { remote, protocol }, - CustomMessageOutcome::NotificationsReceived { remote, messages } => - BehaviourOut::NotificationsReceived { remote, messages }, - CustomMessageOutcome::None => BehaviourOut::None, + } => BehaviourOut::NotificationStreamReplaced { remote, set_id, notifications_sink }, + CustomMessageOutcome::NotificationStreamClosed { remote, set_id } => + BehaviourOut::NotificationStreamClosed { remote, set_id }, + CustomMessageOutcome::NotificationsReceived { remote, set_id, notification } => + BehaviourOut::NotificationsReceived { remote, set_id, notification }, } } } diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index 124d73a74db..24e96843c32 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -23,10 +23,11 @@ pub use crate::{ discovery::DEFAULT_KADEMLIA_REPLICATION_FACTOR, - protocol::NotificationsSink, + protocol::{notification_service, NotificationsSink, ProtocolHandlePair}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, + service::traits::NotificationService, types::ProtocolName, }; @@ -47,7 +48,6 @@ pub use sc_network_common::{ ExHashT, }; -use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::Block as BlockT; use std::{ @@ -454,14 +454,14 @@ impl Default for SetConfig { /// /// > **Note**: As new fields might be added in the future, please consider using the `new` method /// > and modifiers instead of creating this struct manually. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct NonDefaultSetConfig { /// Name of the notifications protocols of this set. A substream on this set will be /// considered established once this protocol is open. /// /// > **Note**: This field isn't present for the default set, as this is handled internally /// > by the networking code. - pub notifications_protocol: ProtocolName, + protocol_name: ProtocolName, /// If the remote reports that it doesn't support the protocol indicated in the /// `notifications_protocol` field, then each of these fallback names will be tried one by @@ -469,37 +469,84 @@ pub struct NonDefaultSetConfig { /// /// If a fallback is used, it will be reported in /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` - pub fallback_names: Vec, + fallback_names: Vec, /// Handshake of the protocol /// /// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more /// details. This field is temporarily used to allow moving the hardcoded block announcement /// protocol out of `protocol.rs`. - pub handshake: Option, + handshake: Option, /// Maximum allowed size of single notifications. - pub max_notification_size: u64, + max_notification_size: u64, /// Base configuration. - pub set_config: SetConfig, + set_config: SetConfig, + + /// Notification handle. + /// + /// Notification handle is created during `NonDefaultSetConfig` creation and its other half, + /// `Box` is given to the protocol created the config and + /// `ProtocolHandle` is given to `Notifications` when it initializes itself. This handle allows + /// `Notifications ` to communicate with the protocol directly without relaying events through + /// `sc-network.` + protocol_handle_pair: ProtocolHandlePair, } impl NonDefaultSetConfig { /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. - pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self { - Self { - notifications_protocol, - max_notification_size, - fallback_names: Vec::new(), - handshake: None, - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, + /// Also returns an object which allows the protocol to communicate with `Notifications`. + pub fn new( + protocol_name: ProtocolName, + fallback_names: Vec, + max_notification_size: u64, + handshake: Option, + set_config: SetConfig, + ) -> (Self, Box) { + let (protocol_handle_pair, notification_service) = + notification_service(protocol_name.clone()); + ( + Self { + protocol_name, + max_notification_size, + fallback_names, + handshake, + set_config, + protocol_handle_pair, }, - } + notification_service, + ) + } + + /// Get reference to protocol name. + pub fn protocol_name(&self) -> &ProtocolName { + &self.protocol_name + } + + /// Get reference to fallback protocol names. + pub fn fallback_names(&self) -> impl Iterator { + self.fallback_names.iter() + } + + /// Get reference to handshake. + pub fn handshake(&self) -> &Option { + &self.handshake + } + + /// Get maximum notification size. + pub fn max_notification_size(&self) -> u64 { + self.max_notification_size + } + + /// Get reference to `SetConfig`. + pub fn set_config(&self) -> &SetConfig { + &self.set_config + } + + /// Take `ProtocolHandlePair` from `NonDefaultSetConfig` + pub fn take_protocol_handle(self) -> ProtocolHandlePair { + self.protocol_handle_pair } /// Modifies the configuration to allow non-reserved nodes. @@ -703,9 +750,6 @@ pub struct Params { /// Block announce protocol configuration pub block_announce_config: NonDefaultSetConfig, - - /// TX channel for direct communication with `SyncingEngine` and `Protocol`. - pub tx: TracingUnboundedSender>, } /// Full network configuration. diff --git a/substrate/client/network/src/error.rs b/substrate/client/network/src/error.rs index f0828fb821f..01e8356fb55 100644 --- a/substrate/client/network/src/error.rs +++ b/substrate/client/network/src/error.rs @@ -68,6 +68,15 @@ pub enum Error { /// Name of the protocol registered multiple times. protocol: ProtocolName, }, + /// Peer does not exist. + #[error("Peer `{0}` does not exist.")] + PeerDoesntExist(PeerId), + /// Channel closed. + #[error("Channel closed")] + ChannelClosed, + /// Connection closed. + #[error("Connection closed")] + ConnectionClosed, } // Make `Debug` use the `Display` implementation. diff --git a/substrate/client/network/src/event.rs b/substrate/client/network/src/event.rs index 2913f0b5522..dc4fd53a49a 100644 --- a/substrate/client/network/src/event.rs +++ b/substrate/client/network/src/event.rs @@ -19,14 +19,12 @@ //! Network event types. These are are not the part of the protocol, but rather //! events that happen on the network like DHT get/put results received. -use crate::{types::ProtocolName, NotificationsSink}; +use crate::types::ProtocolName; use bytes::Bytes; -use futures::channel::oneshot; use libp2p::{kad::record::Key, PeerId}; -use sc_network_common::{role::ObservedRole, sync::message::BlockAnnouncesHandshake}; -use sp_runtime::traits::Block as BlockT; +use sc_network_common::role::ObservedRole; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] @@ -92,46 +90,3 @@ pub enum Event { messages: Vec<(ProtocolName, Bytes)>, }, } - -/// Event sent to `SyncingEngine` -// TODO: remove once `NotificationService` is implemented. -pub enum SyncEvent { - /// Opened a substream with the given node with the given notifications protocol. - /// - /// The protocol is always one of the notification protocols that have been registered. - NotificationStreamOpened { - /// Node we opened the substream with. - remote: PeerId, - /// Received handshake. - received_handshake: BlockAnnouncesHandshake, - /// Notification sink. - sink: NotificationsSink, - /// Is the connection inbound. - inbound: bool, - /// Channel for reporting accept/reject of the substream. - tx: oneshot::Sender, - }, - - /// Closed a substream with the given node. Always matches a corresponding previous - /// `NotificationStreamOpened` message. - NotificationStreamClosed { - /// Node we closed the substream with. - remote: PeerId, - }, - - /// Notification sink was replaced. - NotificationSinkReplaced { - /// Node we closed the substream with. - remote: PeerId, - /// Notification sink. - sink: NotificationsSink, - }, - - /// Received one or more messages from the given node using the given protocol. - NotificationsReceived { - /// Node we received the message from. - remote: PeerId, - /// Concerned protocol and associated message. - messages: Vec, - }, -} diff --git a/substrate/client/network/src/lib.rs b/substrate/client/network/src/lib.rs index 4dc9bdb4cc1..4c39c57e8df 100644 --- a/substrate/client/network/src/lib.rs +++ b/substrate/client/network/src/lib.rs @@ -244,7 +244,6 @@ mod behaviour; mod protocol; -mod service; #[cfg(test)] mod mock; @@ -258,25 +257,30 @@ pub mod peer_info; pub mod peer_store; pub mod protocol_controller; pub mod request_responses; +pub mod service; pub mod transport; pub mod types; pub mod utils; -pub use event::{DhtEvent, Event, SyncEvent}; +pub use event::{DhtEvent, Event}; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use request_responses::{Config, IfDisconnected, RequestFailure}; -pub use sc_network_common::{role::ObservedRole, types::ReputationChange}; +pub use sc_network_common::{ + role::{ObservedRole, Roles}, + types::ReputationChange, +}; pub use service::{ signature::Signature, traits::{ - KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkEventStream, NetworkNotification, - NetworkPeers, NetworkRequest, NetworkSigner, NetworkStateInfo, NetworkStatus, - NetworkStatusProvider, NetworkSyncForkRequest, NotificationSender as NotificationSenderT, - NotificationSenderError, NotificationSenderReady, + KademliaKey, MessageSink, NetworkBlock, NetworkDHTProvider, NetworkEventStream, + NetworkNotification, NetworkPeers, NetworkRequest, NetworkSigner, NetworkStateInfo, + NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, + NotificationSender as NotificationSenderT, NotificationSenderError, + NotificationSenderReady, NotificationService, }, - DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationsSink, - OutboundFailure, PublicKey, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, OutboundFailure, + PublicKey, }; pub use types::ProtocolName; diff --git a/substrate/client/network/src/mock.rs b/substrate/client/network/src/mock.rs index bc596b0fa57..534b8118970 100644 --- a/substrate/client/network/src/mock.rs +++ b/substrate/client/network/src/mock.rs @@ -20,6 +20,7 @@ use crate::{peer_store::PeerStoreProvider, protocol_controller::ProtocolHandle, ReputationChange}; use libp2p::PeerId; +use sc_network_common::role::ObservedRole; use std::collections::HashSet; /// No-op `PeerStore`. @@ -49,6 +50,14 @@ impl PeerStoreProvider for MockPeerStore { 0 } + fn peer_role(&self, _peer_id: &PeerId) -> Option { + None + } + + fn set_peer_role(&mut self, _peer_id: &PeerId, _role: ObservedRole) { + unimplemented!(); + } + fn outgoing_candidates(&self, _count: usize, _ignored: HashSet<&PeerId>) -> Vec { unimplemented!() } diff --git a/substrate/client/network/src/peer_store.rs b/substrate/client/network/src/peer_store.rs index 35d17e588cb..4b28b8e7544 100644 --- a/substrate/client/network/src/peer_store.rs +++ b/substrate/client/network/src/peer_store.rs @@ -23,7 +23,7 @@ use libp2p::PeerId; use log::trace; use parking_lot::Mutex; use partial_sort::PartialSort; -use sc_network_common::types::ReputationChange; +use sc_network_common::{role::ObservedRole, types::ReputationChange}; use std::{ cmp::{Ord, Ordering, PartialOrd}, collections::{hash_map::Entry, HashMap, HashSet}, @@ -66,9 +66,15 @@ pub trait PeerStoreProvider: Debug + Send { /// Adjust peer reputation. fn report_peer(&mut self, peer_id: PeerId, change: ReputationChange); + /// Set peer role. + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole); + /// Get peer reputation. fn peer_reputation(&self, peer_id: &PeerId) -> i32; + /// Get peer role, if available. + fn peer_role(&self, peer_id: &PeerId) -> Option; + /// Get candidates with highest reputations for initiating outgoing connections. fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec; } @@ -96,10 +102,18 @@ impl PeerStoreProvider for PeerStoreHandle { self.inner.lock().report_peer(peer_id, change) } + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole) { + self.inner.lock().set_peer_role(peer_id, role) + } + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { self.inner.lock().peer_reputation(peer_id) } + fn peer_role(&self, peer_id: &PeerId) -> Option { + self.inner.lock().peer_role(peer_id) + } + fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec { self.inner.lock().outgoing_candidates(count, ignored) } @@ -122,13 +136,19 @@ impl PeerStoreHandle { #[derive(Debug, Clone, Copy)] struct PeerInfo { + /// Reputation of the peer. reputation: i32, + + /// Instant when the peer was last updated. last_updated: Instant, + + /// Role of the peer, if known. + role: Option, } impl Default for PeerInfo { fn default() -> Self { - Self { reputation: 0, last_updated: Instant::now() } + Self { reputation: 0, last_updated: Instant::now(), role: None } } } @@ -242,10 +262,27 @@ impl PeerStoreInner { } } + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole) { + log::trace!(target: LOG_TARGET, "Set {peer_id} role to {role:?}"); + + match self.peers.entry(*peer_id) { + Entry::Occupied(mut entry) => { + entry.get_mut().role = Some(role); + }, + Entry::Vacant(entry) => { + entry.insert(PeerInfo { role: Some(role), ..Default::default() }); + }, + } + } + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { self.peers.get(peer_id).map_or(0, |info| info.reputation) } + fn peer_role(&self, peer_id: &PeerId) -> Option { + self.peers.get(peer_id).map_or(None, |info| info.role) + } + fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec { let mut candidates = self .peers diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 9b94f288352..ea7977cc9ae 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -20,12 +20,11 @@ use crate::{ config, error, peer_store::{PeerStoreHandle, PeerStoreProvider}, protocol_controller::{self, SetId}, + service::traits::Direction, types::ProtocolName, }; -use bytes::Bytes; -use codec::{DecodeAll, Encode}; -use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; +use codec::Encode; use libp2p::{ core::Endpoint, swarm::{ @@ -34,24 +33,23 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use log::{debug, error, warn}; +use log::warn; -use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; -use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}; +use codec::DecodeAll; +use prometheus_endpoint::Registry; +use sc_network_common::role::Roles; +use sc_utils::mpsc::TracingUnboundedReceiver; use sp_runtime::traits::Block as BlockT; -use std::{ - collections::{HashMap, HashSet}, - future::Future, - iter, - pin::Pin, - task::Poll, -}; +use std::{collections::HashSet, iter, task::Poll}; -use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; -pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; +pub(crate) use notifications::ProtocolHandle; + +pub use notifications::{ + notification_service, NotificationsSink, NotifsHandlerError, ProtocolHandlePair, Ready, +}; mod notifications; @@ -64,85 +62,93 @@ pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * /// Identifier of the peerset for the block announces protocol. const HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); -mod rep { - use crate::ReputationChange as Rep; - /// We received a message that failed to decode. - pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); -} - -type PendingSyncSubstreamValidation = - Pin> + Send>>; - // Lock must always be taken in order declared here. pub struct Protocol { - /// Used to report reputation changes. - peer_store_handle: PeerStoreHandle, /// Handles opening the unique substream and sending and receiving raw messages. behaviour: Notifications, /// List of notifications protocols that have been registered. notification_protocols: Vec, - /// If we receive a new "substream open" event that contains an invalid handshake, we ask the - /// inner layer to force-close the substream. Force-closing the substream will generate a - /// "substream closed" event. This is a problem: since we can't propagate the "substream open" - /// event to the outer layers, we also shouldn't propagate this "substream closed" event. To - /// solve this, an entry is added to this map whenever an invalid handshake is received. - /// Entries are removed when the corresponding "substream closed" is later received. - bad_handshake_substreams: HashSet<(PeerId, SetId)>, - /// Connected peers on sync protocol. - peers: HashMap, - sync_substream_validations: FuturesUnordered, - tx: TracingUnboundedSender>, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, + /// Streams for peers whose handshake couldn't be determined. + bad_handshake_streams: HashSet, + sync_handle: ProtocolHandle, _marker: std::marker::PhantomData, } impl Protocol { /// Create a new instance. - pub fn new( + pub(crate) fn new( roles: Roles, + registry: &Option, notification_protocols: Vec, block_announces_protocol: config::NonDefaultSetConfig, peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - tx: TracingUnboundedSender>, - ) -> error::Result { - let behaviour = { - Notifications::new( - protocol_controller_handles, - from_protocol_controllers, - // NOTE: Block announcement protocol is still very much hardcoded into `Protocol`. - // This protocol must be the first notification protocol given to - // `Notifications` - iter::once(notifications::ProtocolConfig { - name: block_announces_protocol.notifications_protocol.clone(), - fallback_names: block_announces_protocol.fallback_names.clone(), - handshake: block_announces_protocol.handshake.as_ref().unwrap().to_vec(), - max_notification_size: block_announces_protocol.max_notification_size, - }) - .chain(notification_protocols.iter().map(|s| notifications::ProtocolConfig { - name: s.notifications_protocol.clone(), - fallback_names: s.fallback_names.clone(), - handshake: s.handshake.as_ref().map_or(roles.encode(), |h| (*h).to_vec()), - max_notification_size: s.max_notification_size, - })), + ) -> error::Result<(Self, Vec)> { + let (behaviour, notification_protocols, handles) = { + let installed_protocols = iter::once(block_announces_protocol.protocol_name().clone()) + .chain(notification_protocols.iter().map(|p| p.protocol_name().clone())) + .collect::>(); + + // NOTE: Block announcement protocol is still very much hardcoded into + // `Protocol`. This protocol must be the first notification protocol given to + // `Notifications` + let (protocol_configs, handles): (Vec<_>, Vec<_>) = iter::once({ + let config = notifications::ProtocolConfig { + name: block_announces_protocol.protocol_name().clone(), + fallback_names: block_announces_protocol.fallback_names().cloned().collect(), + handshake: block_announces_protocol.handshake().as_ref().unwrap().to_vec(), + max_notification_size: block_announces_protocol.max_notification_size(), + }; + + let (handle, command_stream) = + block_announces_protocol.take_protocol_handle().split(); + + ((config, handle.clone(), command_stream), handle) + }) + .chain(notification_protocols.into_iter().map(|s| { + let config = notifications::ProtocolConfig { + name: s.protocol_name().clone(), + fallback_names: s.fallback_names().cloned().collect(), + handshake: s.handshake().as_ref().map_or(roles.encode(), |h| (*h).to_vec()), + max_notification_size: s.max_notification_size(), + }; + + let (handle, command_stream) = s.take_protocol_handle().split(); + + ((config, handle.clone(), command_stream), handle) + })) + .unzip(); + + ( + Notifications::new( + protocol_controller_handles, + from_protocol_controllers, + registry, + protocol_configs.into_iter(), + ), + installed_protocols, + handles, ) }; let protocol = Self { - peer_store_handle, behaviour, - notification_protocols: iter::once(block_announces_protocol.notifications_protocol) - .chain(notification_protocols.iter().map(|s| s.notifications_protocol.clone())) - .collect(), - bad_handshake_substreams: Default::default(), - peers: HashMap::new(), - sync_substream_validations: FuturesUnordered::new(), - tx, + sync_handle: handles[0].clone(), + peer_store_handle, + notification_protocols, + bad_handshake_streams: HashSet::new(), // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; - Ok(protocol) + Ok((protocol, handles)) + } + + pub fn num_sync_peers(&self) -> usize { + self.sync_handle.num_peers() } /// Returns the list of all the peers we have an open channel to. @@ -163,21 +169,12 @@ impl Protocol { } } - /// Returns the number of peers we're connected to on sync protocol. - pub fn num_connected_peers(&self) -> usize { - self.peers.len() - } - - /// Set handshake for the notification protocol. - pub fn set_notification_handshake(&mut self, protocol: ProtocolName, handshake: Vec) { - if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.behaviour.set_notif_protocol_handshake(SetId::from(index), handshake); - } else { - error!( - target: "sub-libp2p", - "set_notification_handshake with unknown protocol: {}", - protocol - ); + /// Check if role is available for `peer_id` by attempt to decode the handshake to roles and if + /// that fails, check if the role has been registered to `PeerStore`. + fn role_available(&self, peer_id: &PeerId, handshake: &Vec) -> bool { + match Roles::decode_all(&mut &handshake[..]) { + Ok(_) => true, + Err(_) => self.peer_store_handle.peer_role(&peer_id).is_some(), } } } @@ -189,25 +186,42 @@ pub enum CustomMessageOutcome { /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, - protocol: ProtocolName, + // protocol: ProtocolName, + set_id: SetId, + /// Direction of the stream. + direction: Direction, /// See [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. negotiated_fallback: Option, - roles: Roles, + /// Received handshake. received_handshake: Vec, + /// Notification sink. notifications_sink: NotificationsSink, }, /// The [`NotificationsSink`] of some notification protocols need an update. NotificationStreamReplaced { + // Peer ID. remote: PeerId, - protocol: ProtocolName, + /// Set ID. + set_id: SetId, + /// New notification sink. notifications_sink: NotificationsSink, }, /// Notification protocols have been closed with a remote. - NotificationStreamClosed { remote: PeerId, protocol: ProtocolName }, + NotificationStreamClosed { + // Peer ID. + remote: PeerId, + /// Set ID. + set_id: SetId, + }, /// Messages have been received on one or more notifications protocols. - NotificationsReceived { remote: PeerId, messages: Vec<(ProtocolName, Bytes)> }, - /// Now connected to a new peer for syncing purposes. - None, + NotificationsReceived { + // Peer ID. + remote: PeerId, + /// Set ID. + set_id: SetId, + /// Received notification. + notification: Vec, + }, } impl NetworkBehaviour for Protocol { @@ -274,23 +288,6 @@ impl NetworkBehaviour for Protocol { cx: &mut std::task::Context, params: &mut impl PollParameters, ) -> Poll>> { - while let Poll::Ready(Some(validation_result)) = - self.sync_substream_validations.poll_next_unpin(cx) - { - match validation_result { - Ok((peer, roles)) => { - self.peers.insert(peer, roles); - }, - Err(peer) => { - log::debug!( - target: "sub-libp2p", - "`SyncingEngine` rejected stream" - ); - self.behaviour.disconnect_peer(&peer, HARDCODED_PEERSETS_SYNC); - }, - } - } - let event = match self.behaviour.poll(cx, params) { Poll::Pending => return Poll::Pending, Poll::Ready(ToSwarm::GenerateEvent(ev)) => ev, @@ -307,204 +304,86 @@ impl NetworkBehaviour for Protocol { NotificationsOut::CustomProtocolOpen { peer_id, set_id, + direction, received_handshake, notifications_sink, negotiated_fallback, - inbound, - } => { - // Set number 0 is hardcoded the default set of peers we sync from. + .. + } => if set_id == HARDCODED_PEERSETS_SYNC { - // `received_handshake` can be either a `Status` message if received from the - // legacy substream ,or a `BlockAnnouncesHandshake` if received from the block - // announces substream. - match as DecodeAll>::decode_all(&mut &received_handshake[..]) { - Ok(GenericMessage::Status(handshake)) => { - let roles = handshake.roles; - let handshake = BlockAnnouncesHandshake:: { - roles: handshake.roles, - best_number: handshake.best_number, - best_hash: handshake.best_hash, - genesis_hash: handshake.genesis_hash, - }; - - let (tx, rx) = oneshot::channel(); - let _ = self.tx.unbounded_send( - crate::SyncEvent::NotificationStreamOpened { - inbound, - remote: peer_id, - received_handshake: handshake, - sink: notifications_sink, - tx, - }, - ); - self.sync_substream_validations.push(Box::pin(async move { - match rx.await { - Ok(accepted) => - if accepted { - Ok((peer_id, roles)) - } else { - Err(peer_id) - }, - Err(_) => Err(peer_id), - } - })); - - CustomMessageOutcome::None - }, - Ok(msg) => { - debug!( - target: "sync", - "Expected Status message from {}, but got {:?}", - peer_id, - msg, - ); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); - CustomMessageOutcome::None - }, - Err(err) => { - match as DecodeAll>::decode_all( - &mut &received_handshake[..], - ) { - Ok(handshake) => { - let roles = handshake.roles; - - let (tx, rx) = oneshot::channel(); - let _ = self.tx.unbounded_send( - crate::SyncEvent::NotificationStreamOpened { - inbound, - remote: peer_id, - received_handshake: handshake, - sink: notifications_sink, - tx, - }, - ); - self.sync_substream_validations.push(Box::pin(async move { - match rx.await { - Ok(accepted) => - if accepted { - Ok((peer_id, roles)) - } else { - Err(peer_id) - }, - Err(_) => Err(peer_id), - } - })); - CustomMessageOutcome::None - }, - Err(err2) => { - log::debug!( - target: "sync", - "Couldn't decode handshake sent by {}: {:?}: {} & {}", - peer_id, - received_handshake, - err, - err2, - ); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); - CustomMessageOutcome::None - }, - } - }, - } + let _ = self.sync_handle.report_substream_opened( + peer_id, + direction, + received_handshake, + negotiated_fallback, + notifications_sink, + ); + None } else { - match ( - Roles::decode_all(&mut &received_handshake[..]), - self.peers.get(&peer_id), - ) { - (Ok(roles), _) => CustomMessageOutcome::NotificationStreamOpened { + match self.role_available(&peer_id, &received_handshake) { + true => Some(CustomMessageOutcome::NotificationStreamOpened { remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), + set_id, + direction, negotiated_fallback, - roles, received_handshake, notifications_sink, - }, - (Err(_), Some(roles)) if received_handshake.is_empty() => { - // As a convenience, we allow opening substreams for "external" - // notification protocols with an empty handshake. This fetches the - // roles from the locally-known roles. - // TODO: remove this after https://github.com/paritytech/substrate/issues/5685 - CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - negotiated_fallback, - roles: *roles, - received_handshake, - notifications_sink, - } - }, - (Err(err), _) => { - debug!(target: "sync", "Failed to parse remote handshake: {}", err); - self.bad_handshake_substreams.insert((peer_id, set_id)); - self.behaviour.disconnect_peer(&peer_id, set_id); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); - CustomMessageOutcome::None + }), + false => { + self.bad_handshake_streams.insert(peer_id); + None }, } - } - }, + }, NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => - if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationSinkReplaced { - remote: peer_id, - sink: notifications_sink, - }); - CustomMessageOutcome::None + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self + .sync_handle + .report_notification_sink_replaced(peer_id, notifications_sink); + None } else { - CustomMessageOutcome::NotificationStreamReplaced { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - notifications_sink, - } + (!self.bad_handshake_streams.contains(&peer_id)).then_some( + CustomMessageOutcome::NotificationStreamReplaced { + remote: peer_id, + set_id, + notifications_sink, + }, + ) }, NotificationsOut::CustomProtocolClosed { peer_id, set_id } => { - if self.bad_handshake_substreams.remove(&(peer_id, set_id)) { - // The substream that has just been closed had been opened with a bad - // handshake. The outer layers have never received an opening event about this - // substream, and consequently shouldn't receive a closing event either. - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationStreamClosed { - remote: peer_id, - }); - self.peers.remove(&peer_id); - CustomMessageOutcome::None + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.sync_handle.report_substream_closed(peer_id); + None } else { - CustomMessageOutcome::NotificationStreamClosed { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - } + (!self.bad_handshake_streams.remove(&peer_id)).then_some( + CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, set_id }, + ) } }, NotificationsOut::Notification { peer_id, set_id, message } => { - if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationsReceived { - remote: peer_id, - messages: vec![message.freeze()], - }); - CustomMessageOutcome::None + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self + .sync_handle + .report_notification_received(peer_id, message.freeze().into()); + None } else { - let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); - CustomMessageOutcome::NotificationsReceived { - remote: peer_id, - messages: vec![(protocol_name, message.freeze())], - } + (!self.bad_handshake_streams.contains(&peer_id)).then_some( + CustomMessageOutcome::NotificationsReceived { + remote: peer_id, + set_id, + notification: message.freeze().into(), + }, + ) } }, }; - if !matches!(outcome, CustomMessageOutcome::None) { - return Poll::Ready(ToSwarm::GenerateEvent(outcome)) + match outcome { + Some(event) => Poll::Ready(ToSwarm::GenerateEvent(event)), + None => { + cx.waker().wake_by_ref(); + Poll::Pending + }, } - - // This block can only be reached if an event was pulled from the behaviour and that - // resulted in `CustomMessageOutcome::None`. Since there might be another pending - // message from the behaviour, the task is scheduled again. - cx.waker().wake_by_ref(); - Poll::Pending } } diff --git a/substrate/client/network/src/protocol/message.rs b/substrate/client/network/src/protocol/message.rs index 66dca297537..247580083f9 100644 --- a/substrate/client/network/src/protocol/message.rs +++ b/substrate/client/network/src/protocol/message.rs @@ -29,6 +29,7 @@ use sc_network_common::message::RequestId; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; /// Type alias for using the message type using block type parameters. +#[allow(unused)] pub type Message = generic::Message< ::Header, ::Hash, diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index aa49cfcf9d4..10fa329097d 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -22,9 +22,13 @@ pub use self::{ behaviour::{Notifications, NotificationsOut, ProtocolConfig}, handler::{NotificationsSink, NotifsHandlerError, Ready}, + service::{notification_service, ProtocolHandlePair}, }; +pub(crate) use self::service::ProtocolHandle; + mod behaviour; mod handler; +mod service; mod tests; mod upgrade; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index b78f15f8529..ef0c6540eee 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -17,16 +17,18 @@ // along with this program. If not, see . use crate::{ - protocol::notifications::handler::{ - self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut, + protocol::notifications::{ + handler::{self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut}, + service::{metrics, NotificationCommand, ProtocolHandle, ValidationCallResult}, }, protocol_controller::{self, IncomingIndex, Message, SetId}, + service::traits::{Direction, ValidationResult}, types::ProtocolName, }; use bytes::BytesMut; use fnv::FnvHashMap; -use futures::prelude::*; +use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; use libp2p::{ core::{ConnectedPoint, Endpoint, Multiaddr}, swarm::{ @@ -36,11 +38,15 @@ use libp2p::{ }, PeerId, }; -use log::{debug, error, info, trace, warn}; +use log::{debug, error, trace, warn}; use parking_lot::RwLock; +use prometheus_endpoint::Registry; use rand::distributions::{Distribution as _, Uniform}; use sc_utils::mpsc::TracingUnboundedReceiver; use smallvec::SmallVec; +use tokio::sync::oneshot::error::RecvError; +use tokio_stream::StreamMap; + use std::{ cmp, collections::{hash_map::Entry, VecDeque}, @@ -51,6 +57,13 @@ use std::{ time::{Duration, Instant}, }; +/// Type representing a pending substream validation. +type PendingInboundValidation = + BoxFuture<'static, (Result, IncomingIndex)>; + +/// Logging target for the file. +const LOG_TARGET: &str = "sub-libp2p"; + /// Network behaviour that handles opening substreams for custom protocols with other peers. /// /// # How it works @@ -106,6 +119,12 @@ pub struct Notifications { /// Notification protocols. Entries never change after initialization. notif_protocols: Vec, + /// Protocol handles. + protocol_handles: Vec, + + // Command streams. + command_streams: StreamMap + Send + Unpin>>, + /// Protocol controllers are responsible for peer connections management. protocol_controller_handles: Vec, @@ -138,6 +157,18 @@ pub struct Notifications { /// Events to produce from `poll()`. events: VecDeque>, + + /// Pending inbound substream validations. + // + // NOTE: it's possible to read a stale response from `pending_inbound_validations` + // as the substream may get closed by the remote peer before the protocol has had + // a chance to validate it. [`Notifications`] must compare the `crate::peerset::IncomingIndex` + // returned by the completed future against the `crate::peerset::IncomingIndex` stored in + // `PeerState::Incoming` to check whether the completed future is stale or not. + pending_inbound_validations: FuturesUnordered, + + /// Metrics for notifications. + metrics: Option, } /// Configuration for a notifications protocol. @@ -235,6 +266,9 @@ enum PeerState { /// Incoming index tracking this connection. incoming_index: IncomingIndex, + /// Peerset has signaled it wants the substream closed. + peerset_rejected: bool, + /// List of connections with this peer, and their state. connections: SmallVec<[(ConnectionId, ConnectionState); crate::MAX_CONNECTIONS_PER_PEER]>, }, @@ -303,6 +337,8 @@ struct IncomingPeer { alive: bool, /// Id that the we sent to the peerset. incoming_id: IncomingIndex, + /// Received handshake. + handshake: Vec, } /// Event that can be emitted by the `Notifications`. @@ -314,6 +350,8 @@ pub enum NotificationsOut { peer_id: PeerId, /// Peerset set ID the substream is tied to. set_id: SetId, + /// Direction of the stream. + direction: Direction, /// If `Some`, a fallback protocol name has been used rather the main protocol name. /// Always matches one of the fallback names passed at initialization. negotiated_fallback: Option, @@ -364,24 +402,52 @@ pub enum NotificationsOut { impl Notifications { /// Creates a `CustomProtos`. - pub fn new( + pub(crate) fn new( protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - notif_protocols: impl Iterator, + registry: &Option, + notif_protocols: impl Iterator< + Item = ( + ProtocolConfig, + ProtocolHandle, + Box + Send + Unpin>, + ), + >, ) -> Self { - let notif_protocols = notif_protocols - .map(|cfg| handler::ProtocolConfig { - name: cfg.name, - fallback_names: cfg.fallback_names, - handshake: Arc::new(RwLock::new(cfg.handshake)), - max_notification_size: cfg.max_notification_size, + let (notif_protocols, protocol_handles): (Vec<_>, Vec<_>) = notif_protocols + .map(|(cfg, protocol_handle, command_stream)| { + ( + handler::ProtocolConfig { + name: cfg.name, + fallback_names: cfg.fallback_names, + handshake: Arc::new(RwLock::new(cfg.handshake)), + max_notification_size: cfg.max_notification_size, + }, + (protocol_handle, command_stream), + ) }) - .collect::>(); - + .unzip(); assert!(!notif_protocols.is_empty()); + let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); + let (mut protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handles + .into_iter() + .enumerate() + .map(|(set_id, (mut protocol_handle, command_stream))| { + protocol_handle.set_metrics(metrics.clone()); + + (protocol_handle, (set_id, command_stream)) + }) + .unzip(); + + protocol_handles.iter_mut().skip(1).for_each(|handle| { + handle.delegate_to_peerset(true); + }); + Self { notif_protocols, + protocol_handles, + command_streams: StreamMap::from_iter(command_streams.into_iter()), protocol_controller_handles, from_protocol_controllers, peers: FnvHashMap::default(), @@ -390,6 +456,8 @@ impl Notifications { incoming: SmallVec::new(), next_incoming_index: IncomingIndex(0), events: VecDeque::new(), + pending_inbound_validations: FuturesUnordered::new(), + metrics, } } @@ -807,14 +875,21 @@ impl Notifications { *entry.into_mut() = PeerState::Backoff { timer, timer_deadline } }, - // Invalid state transitions. - st @ PeerState::Incoming { .. } => { - info!( + // `ProtocolController` disconnected peer while it was still being validated by the + // protocol, mark the connection as rejected and once the validation is received from + // the protocol, reject the substream + PeerState::Incoming { backoff_until, connections, incoming_index, .. } => { + debug!( target: "sub-libp2p", "PSM => Drop({}, {:?}): Ignoring obsolete disconnect, we are awaiting accept/reject.", entry.key().0, set_id, ); - *entry.into_mut() = st; + *entry.into_mut() = PeerState::Incoming { + backoff_until, + connections, + incoming_index, + peerset_rejected: true, + }; }, PeerState::Poisoned => { error!(target: "sub-libp2p", "State of {:?} is poisoned", entry.key()); @@ -823,20 +898,71 @@ impl Notifications { } } + /// Substream has been accepted by the `ProtocolController` and must now be sent + /// to the protocol for validation. + fn peerset_report_preaccept(&mut self, index: IncomingIndex) { + let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) else { + error!(target: LOG_TARGET, "PSM => Preaccept({:?}): Invalid index", index); + return + }; + + trace!( + target: LOG_TARGET, + "PSM => Preaccept({:?}): Sent to protocol for validation", + index + ); + let incoming = &self.incoming[pos]; + + match self.protocol_handles[usize::from(incoming.set_id)] + .report_incoming_substream(incoming.peer_id, incoming.handshake.clone()) + { + Ok(ValidationCallResult::Delegated) => { + self.protocol_report_accept(index); + }, + Ok(ValidationCallResult::WaitForValidation(rx)) => { + self.pending_inbound_validations + .push(Box::pin(async move { (rx.await, index) })); + }, + Err(err) => { + // parachain collators enable the syncing protocol but `NotificationService` for + // `SyncingEngine` is not created which causes `report_incoming_substream()` to + // fail. This is not a fatal error and should be ignored even though in typical + // cases the `NotificationService` not existing is a fatal error and indicates that + // the protocol has exited. Until the parachain collator issue is fixed, just report + // and error and reject the peer. + debug!(target: LOG_TARGET, "protocol has exited: {err:?} {:?}", incoming.set_id); + + self.protocol_report_reject(index); + }, + } + } + /// Function that is called when the peerset wants us to accept a connection /// request from a peer. - fn peerset_report_accept(&mut self, index: IncomingIndex) { - let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) - { - self.incoming.remove(pos) - } else { - error!(target: "sub-libp2p", "PSM => Accept({:?}): Invalid index", index); - return + fn protocol_report_accept(&mut self, index: IncomingIndex) { + let (pos, incoming) = + if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { + (pos, self.incoming.get(pos)) + } else { + error!(target: "sub-libp2p", "PSM => Accept({:?}): Invalid index", index); + return + }; + + let Some(incoming) = incoming else { + error!(target: "sub-libp2p", "Incoming connection ({:?}) doesn't exist", index); + debug_assert!(false); + return; }; if !incoming.alive { - trace!(target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Obsolete incoming", - index, incoming.peer_id, incoming.set_id); + trace!( + target: "sub-libp2p", + "PSM => Accept({:?}, {}, {:?}): Obsolete incoming", + index, + incoming.peer_id, + incoming.set_id, + ); + match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(PeerState::DisabledPendingEnable { .. }) | Some(PeerState::Enabled { .. }) => { }, @@ -847,26 +973,42 @@ impl Notifications { .dropped(incoming.peer_id); }, } + + self.incoming.remove(pos); return } let state = match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(s) => s, None => { - debug_assert!(false); + log::debug!( + target: "sub-libp2p", + "Connection to {:?} closed, ({:?} {:?}), ignoring accept", + incoming.peer_id, + incoming.set_id, + index, + ); + self.incoming.remove(pos); return }, }; match mem::replace(state, PeerState::Poisoned) { // Incoming => Enabled - PeerState::Incoming { mut connections, incoming_index, .. } => { + PeerState::Incoming { + mut connections, + incoming_index, + peerset_rejected, + backoff_until, + } => { if index < incoming_index { warn!( target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Ignoring obsolete incoming index, we are already awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); + + self.incoming.remove(pos); return } else if index > incoming_index { error!( @@ -874,12 +1016,39 @@ impl Notifications { "PSM => Accept({:?}, {}, {:?}): Ignoring incoming index from the future, we are awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); + + self.incoming.remove(pos); debug_assert!(false); return } - trace!(target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Enabling connections.", - index, incoming.peer_id, incoming.set_id); + // while the substream was being validated by the protocol, `Peerset` had request + // for the it to be closed so reject the substream now + if peerset_rejected { + trace!( + target: "sub-libp2p", + "Protocol accepted ({:?} {:?} {:?}) but Peerset had request disconnection, rejecting", + index, + incoming.peer_id, + incoming.set_id + ); + + *state = PeerState::Incoming { + connections, + backoff_until, + peerset_rejected, + incoming_index, + }; + return self.report_reject(index).map_or((), |_| ()); + } + + trace!( + target: "sub-libp2p", + "PSM => Accept({:?}, {}, {:?}): Enabling connections.", + index, + incoming.peer_id, + incoming.set_id + ); debug_assert!(connections .iter() @@ -898,53 +1067,85 @@ impl Notifications { *connec_state = ConnectionState::Opening; } + self.incoming.remove(pos); *state = PeerState::Enabled { connections }; }, - + st @ PeerState::Disabled { .. } | st @ PeerState::Backoff { .. } => { + self.incoming.remove(pos); + *state = st; + }, // Any state other than `Incoming` is invalid. peer => { - error!(target: "sub-libp2p", + error!( + target: "sub-libp2p", "State mismatch in libp2p: Expected alive incoming. Got {:?}.", - peer); + peer + ); + + self.incoming.remove(pos); debug_assert!(false); }, } } - /// Function that is called when the peerset wants us to reject an incoming peer. + /// Function that is called when `ProtocolController` wants us to reject an incoming peer. fn peerset_report_reject(&mut self, index: IncomingIndex) { + let _ = self.report_reject(index); + } + + /// Function that is called when the protocol wants us to reject an incoming peer. + fn protocol_report_reject(&mut self, index: IncomingIndex) { + if let Some((set_id, peer_id)) = self.report_reject(index) { + self.protocol_controller_handles[usize::from(set_id)].dropped(peer_id) + } + } + + /// Function that is called when the peerset wants us to reject an incoming peer. + fn report_reject(&mut self, index: IncomingIndex) -> Option<(SetId, PeerId)> { let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { self.incoming.remove(pos) } else { error!(target: "sub-libp2p", "PSM => Reject({:?}): Invalid index", index); - return + return None }; if !incoming.alive { - trace!(target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Obsolete incoming, \ - ignoring", index, incoming.peer_id, incoming.set_id); - return + trace!( + target: "sub-libp2p", + "PSM => Reject({:?}, {}, {:?}): Obsolete incoming, ignoring", + index, + incoming.peer_id, + incoming.set_id, + ); + + return None } let state = match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(s) => s, None => { - debug_assert!(false); - return + log::debug!( + target: "sub-libp2p", + "Connection to {:?} closed, ({:?} {:?}), ignoring accept", + incoming.peer_id, + incoming.set_id, + index, + ); + return None }, }; match mem::replace(state, PeerState::Poisoned) { // Incoming => Disabled - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { mut connections, backoff_until, incoming_index, .. } => { if index < incoming_index { warn!( target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Ignoring obsolete incoming index, we are already awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); - return + return None } else if index > incoming_index { error!( target: "sub-libp2p", @@ -952,7 +1153,7 @@ impl Notifications { index, incoming.peer_id, incoming.set_id, incoming_index ); debug_assert!(false); - return + return None } trace!(target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Rejecting connections.", @@ -976,10 +1177,20 @@ impl Notifications { } *state = PeerState::Disabled { connections, backoff_until }; + Some((incoming.set_id, incoming.peer_id)) + }, + // connection to peer may have been closed already + st @ PeerState::Disabled { .. } | st @ PeerState::Backoff { .. } => { + *state = st; + None + }, + peer => { + error!( + target: LOG_TARGET, + "State mismatch in libp2p: Expected alive incoming. Got {peer:?}.", + ); + None }, - peer => error!(target: "sub-libp2p", - "State mismatch in libp2p: Expected alive incoming. Got {:?}.", - peer), } } } @@ -1021,6 +1232,7 @@ impl NetworkBehaviour for Notifications { send_back_addr: remote_addr.clone(), }, self.notif_protocols.clone(), + self.metrics.clone(), )) } @@ -1035,6 +1247,7 @@ impl NetworkBehaviour for Notifications { peer, ConnectedPoint::Dialer { address: addr.clone(), role_override }, self.notif_protocols.clone(), + self.metrics.clone(), )) } @@ -1195,7 +1408,12 @@ impl NetworkBehaviour for Notifications { }, // Incoming => Incoming | Disabled | Backoff | Ø - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { + mut connections, + backoff_until, + incoming_index, + peerset_rejected, + } => { trace!( target: "sub-libp2p", "Libp2p => Disconnected({}, {:?}, {:?}): OpenDesiredByRemote.", @@ -1274,6 +1492,7 @@ impl NetworkBehaviour for Notifications { connections, backoff_until, incoming_index, + peerset_rejected, }; } }, @@ -1313,7 +1532,7 @@ impl NetworkBehaviour for Notifications { let event = NotificationsOut::CustomProtocolReplaced { peer_id, set_id, - notifications_sink: replacement_sink, + notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); } @@ -1474,7 +1693,7 @@ impl NetworkBehaviour for Notifications { event: THandlerOutEvent, ) { match event { - NotifsHandlerOut::OpenDesiredByRemote { protocol_index } => { + NotifsHandlerOut::OpenDesiredByRemote { protocol_index, handshake } => { let set_id = SetId::from(protocol_index); trace!(target: "sub-libp2p", @@ -1495,7 +1714,12 @@ impl NetworkBehaviour for Notifications { match mem::replace(entry.get_mut(), PeerState::Poisoned) { // Incoming => Incoming - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { + mut connections, + backoff_until, + incoming_index, + peerset_rejected, + } => { debug_assert!(connections .iter() .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); @@ -1523,8 +1747,12 @@ impl NetworkBehaviour for Notifications { debug_assert!(false); } - *entry.into_mut() = - PeerState::Incoming { connections, backoff_until, incoming_index }; + *entry.into_mut() = PeerState::Incoming { + connections, + backoff_until, + incoming_index, + peerset_rejected, + }; }, PeerState::Enabled { mut connections } => { @@ -1588,11 +1816,13 @@ impl NetworkBehaviour for Notifications { set_id, alive: true, incoming_id, + handshake, }); *entry.into_mut() = PeerState::Incoming { connections, backoff_until, + peerset_rejected: false, incoming_index: incoming_id, }; } else { @@ -1725,7 +1955,7 @@ impl NetworkBehaviour for Notifications { let event = NotificationsOut::CustomProtocolReplaced { peer_id, set_id, - notifications_sink: replacement_sink, + notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); } @@ -1830,8 +2060,13 @@ impl NetworkBehaviour for Notifications { peer_id, set_id, inbound, - negotiated_fallback, - received_handshake, + direction: if inbound { + Direction::Inbound + } else { + Direction::Outbound + }, + received_handshake: received_handshake.clone(), + negotiated_fallback: negotiated_fallback.clone(), notifications_sink: notifications_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); @@ -1979,8 +2214,11 @@ impl NetworkBehaviour for Notifications { peer_id, set_id, ); - let event = NotificationsOut::Notification { peer_id, set_id, message }; - + let event = NotificationsOut::Notification { + peer_id, + set_id, + message: message.clone(), + }; self.events.push_back(ToSwarm::GenerateEvent(event)); } else { trace!( @@ -2009,10 +2247,10 @@ impl NetworkBehaviour for Notifications { loop { match futures::Stream::poll_next(Pin::new(&mut self.from_protocol_controllers), cx) { Poll::Ready(Some(Message::Accept(index))) => { - self.peerset_report_accept(index); + self.peerset_report_preaccept(index); }, Poll::Ready(Some(Message::Reject(index))) => { - self.peerset_report_reject(index); + let _ = self.peerset_report_reject(index); }, Poll::Ready(Some(Message::Connect { peer_id, set_id, .. })) => { self.peerset_report_connect(peer_id, set_id); @@ -2031,6 +2269,43 @@ impl NetworkBehaviour for Notifications { } } + // poll commands from protocols + loop { + match futures::Stream::poll_next(Pin::new(&mut self.command_streams), cx) { + Poll::Ready(Some((set_id, command))) => match command { + NotificationCommand::SetHandshake(handshake) => { + self.set_notif_protocol_handshake(set_id.into(), handshake); + }, + NotificationCommand::OpenSubstream(_peer) | + NotificationCommand::CloseSubstream(_peer) => { + todo!("substream control not implemented"); + }, + }, + Poll::Ready(None) => { + error!(target: LOG_TARGET, "Protocol command streams have been shut down"); + break + }, + Poll::Pending => break, + } + } + + while let Poll::Ready(Some((result, index))) = + self.pending_inbound_validations.poll_next_unpin(cx) + { + match result { + Ok(ValidationResult::Accept) => { + self.protocol_report_accept(index); + }, + Ok(ValidationResult::Reject) => { + self.protocol_report_reject(index); + }, + Err(_) => { + error!(target: LOG_TARGET, "Protocol has shut down"); + break + }, + } + } + while let Poll::Ready(Some((delay_id, peer_id, set_id))) = Pin::new(&mut self.delays).poll_next(cx) { @@ -2153,7 +2428,10 @@ mod tests { } } - fn development_notifs() -> (Notifications, ProtocolController) { + fn development_notifs( + ) -> (Notifications, ProtocolController, Box) { + let (protocol_handle_pair, notif_service) = + crate::protocol::notifications::service::notification_service("/proto/1".into()); let (to_notifications, from_controller) = tracing_unbounded("test_controller_to_notifications", 10_000); @@ -2169,24 +2447,31 @@ mod tests { Box::new(MockPeerStore {}), ); + let (notif_handle, command_stream) = protocol_handle_pair.split(); ( Notifications::new( vec![handle], from_controller, - iter::once(ProtocolConfig { - name: "/foo".into(), - fallback_names: Vec::new(), - handshake: vec![1, 2, 3, 4], - max_notification_size: u64::MAX, - }), + &None, + iter::once(( + ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: vec![1, 2, 3, 4], + max_notification_size: u64::MAX, + }, + notif_handle, + command_stream, + )), ), controller, + notif_service, ) } #[test] fn update_handshake() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); assert_eq!(inner, vec![1, 2, 3, 4]); @@ -2201,14 +2486,14 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn update_unknown_handshake() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); notif.set_notif_protocol_handshake(1337.into(), vec![5, 6, 7, 8]); } #[test] fn disconnect_backoff_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( @@ -2225,7 +2510,7 @@ mod tests { #[test] fn disconnect_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( @@ -2242,7 +2527,7 @@ mod tests { #[test] fn disconnect_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert((peer, 0.into()), PeerState::Requested); @@ -2253,7 +2538,7 @@ mod tests { #[test] fn disconnect_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( (peer, 0.into()), @@ -2269,7 +2554,7 @@ mod tests { #[test] fn remote_opens_connection_and_substream() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { @@ -2299,7 +2584,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(&PeerState::Incoming { ref connections, backoff_until: None, .. }) = @@ -2319,7 +2607,7 @@ mod tests { #[tokio::test] async fn disconnect_remote_substream_before_handled_by_controller() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { @@ -2339,7 +2627,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); notif.disconnect_peer(&peer, 0.into()); @@ -2355,7 +2646,7 @@ mod tests { #[test] fn peerset_report_connect_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2393,7 +2684,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2420,7 +2711,7 @@ mod tests { #[test] fn peerset_connect_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2444,19 +2735,22 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // attempt to connect to the peer and verify that the peer state is `Enabled`; // we rely on implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); } #[test] fn peerset_disconnect_disable_pending_enable() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2503,7 +2797,7 @@ mod tests { #[test] fn peerset_disconnect_enabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2525,11 +2819,14 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // we rely on the implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); // disconnect peer and verify that the state is `Disabled` @@ -2539,7 +2836,7 @@ mod tests { #[test] fn peerset_disconnect_requested() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -2554,7 +2851,7 @@ mod tests { #[test] fn peerset_disconnect_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2587,7 +2884,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2607,7 +2904,7 @@ mod tests { #[test] fn peerset_accept_peer_not_alive() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2631,7 +2928,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2647,14 +2947,14 @@ mod tests { IncomingPeer { alive: false, incoming_id: IncomingIndex(0), .. }, )); - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert_eq!(notif.incoming.len(), 0); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(PeerState::Disabled { .. }))); } #[test] fn secondary_connection_peer_state_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -2678,7 +2978,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Incoming { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections.len(), 1); @@ -2709,7 +3012,7 @@ mod tests { #[test] fn close_connection_for_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2734,7 +3037,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2743,7 +3046,7 @@ mod tests { #[test] fn close_connection_for_incoming_peer_one_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2766,7 +3069,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2775,7 +3081,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2788,7 +3094,7 @@ mod tests { #[test] fn close_connection_for_incoming_peer_two_connections() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let conn1 = ConnectionId::new_unchecked(1); @@ -2815,7 +3121,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2842,7 +3151,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2857,7 +3166,7 @@ mod tests { #[test] fn connection_and_substream_open() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2882,13 +3191,16 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); // We rely on the implementation detail that incoming indices are counted // from 0 to not mock the `Peerset`. - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); // open new substream @@ -2911,7 +3223,7 @@ mod tests { #[test] fn connection_closed_sink_replaced() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -2947,7 +3259,10 @@ mod tests { notif.on_connection_handler_event( peer, conn2, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Enabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { @@ -2984,7 +3299,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3005,7 +3320,7 @@ mod tests { #[test] fn dial_failure_for_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -3028,7 +3343,7 @@ mod tests { #[tokio::test] async fn write_notification() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3077,7 +3392,7 @@ mod tests { #[test] fn peerset_report_connect_backoff_expired() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3110,7 +3425,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3125,7 +3440,7 @@ mod tests { #[test] fn peerset_report_disconnect_disabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3151,7 +3466,7 @@ mod tests { #[test] fn peerset_report_disconnect_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3184,7 +3499,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3197,7 +3512,7 @@ mod tests { #[test] fn peer_is_backed_off_if_both_connections_get_closed_while_peer_is_disabled_with_back_off() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); @@ -3247,7 +3562,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![]), + handler: NotifsHandler::new(peer, connected.clone(), vec![], None), remaining_established: 0usize, }, )); @@ -3261,7 +3576,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3270,7 +3585,7 @@ mod tests { #[test] fn inject_connection_closed_incoming_with_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3294,7 +3609,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // manually add backoff for the entry @@ -3312,7 +3630,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3321,7 +3639,7 @@ mod tests { #[test] fn two_connections_inactive_connection_gets_closed_peer_state_is_still_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3355,7 +3673,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!( notif.peers.get_mut(&(peer, 0.into())), @@ -3367,7 +3688,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3376,7 +3697,7 @@ mod tests { #[test] fn two_connections_active_connection_gets_closed_peer_state_is_disabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3413,7 +3734,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!( notif.peers.get_mut(&(peer, 0.into())), @@ -3425,7 +3749,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3434,7 +3758,7 @@ mod tests { #[test] fn inject_connection_closed_for_active_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3494,7 +3818,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3502,7 +3826,7 @@ mod tests { #[test] fn inject_dial_failure_for_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3535,7 +3859,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3565,7 +3889,7 @@ mod tests { #[test] fn peerstate_incoming_open_desired_by_remote() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn1 = ConnectionId::new_unchecked(0); @@ -3599,7 +3923,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -3607,7 +3934,10 @@ mod tests { notif.on_connection_handler_event( peer, conn2, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) @@ -3619,7 +3949,7 @@ mod tests { #[tokio::test] async fn remove_backoff_peer_after_timeout() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3652,7 +3982,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3697,7 +4027,7 @@ mod tests { #[tokio::test] async fn reschedule_disabled_pending_enable_when_connection_not_closed() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3726,13 +4056,16 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); // we rely on the implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); @@ -3815,7 +4148,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn peerset_report_connect_with_enabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3840,7 +4173,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -3865,7 +4201,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_disabled_pending_enable_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3911,7 +4247,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -3927,7 +4263,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_pending_requested() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3960,7 +4296,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3984,7 +4320,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -4008,7 +4344,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4019,7 +4358,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_disconnect_with_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -4043,7 +4382,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4052,13 +4394,68 @@ mod tests { } #[test] - #[should_panic] #[cfg(debug_assertions)] - fn peerset_report_accept_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + fn peerset_report_disconnect_with_incoming_peer_protocol_accepts() { + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); + let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // `Peerset` wants to disconnect the peer but since it's still under validation, + // it won't be disabled automatically + notif.peerset_report_disconnect(peer, set_id); + + let incoming_index = match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Incoming { peerset_rejected, incoming_index, .. }) => { + assert!(peerset_rejected); + incoming_index + }, + state => panic!("invalid state: {state:?}"), + }; + + // protocol accepted peer but since `Peerset` wanted to disconnect it, the peer will be + // disabled + notif.protocol_report_accept(incoming_index); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + } + + #[test] + #[cfg(debug_assertions)] + fn peer_disconnected_protocol_accepts() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), send_back_addr: Multiaddr::empty(), @@ -4079,24 +4476,188 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(std::matches!( - notif.incoming[0], - IncomingPeer { alive: true, incoming_id: IncomingIndex(0), .. }, + assert!(notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); + notif.disconnect_peer(&peer, set_id); + + // since the connection was closed, nothing happens for the peer state because + // there is nothing actionable + notif.protocol_report_accept(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + + assert!(!notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); + } + + #[test] + #[cfg(debug_assertions)] + fn connection_closed_protocol_accepts() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new_unchecked(0), + endpoint: &connected.clone(), + handler: NotifsHandler::new(peer, connected, vec![], None), + remaining_established: 0usize, + }, )); - notif.peers.remove(&(peer, set_id)); - notif.peerset_report_accept(IncomingIndex(0)); + // connection closed, nothing to do + notif.protocol_report_accept(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + None => {}, + state => panic!("invalid state: {state:?}"), + }; + } + + #[test] + #[cfg(debug_assertions)] + fn peer_disconnected_protocol_reject() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); + notif.disconnect_peer(&peer, set_id); + + // since the connection was closed, nothing happens for the peer state because + // there is nothing actionable + notif.protocol_report_reject(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + + assert!(!notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); + } + + #[test] + #[cfg(debug_assertions)] + fn connection_closed_protocol_rejects() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new_unchecked(0), + endpoint: &connected.clone(), + handler: NotifsHandler::new(peer, connected, vec![], None), + remaining_established: 0usize, + }, + )); + + // connection closed, nothing to do + notif.protocol_report_reject(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + None => {}, + state => panic!("invalid state: {state:?}"), + }; } #[test] #[should_panic] #[cfg(debug_assertions)] - fn peerset_report_accept_not_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + fn protocol_report_accept_not_incoming_peer() { + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4121,7 +4682,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4138,14 +4702,14 @@ mod tests { assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); notif.incoming[0].alive = true; - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); } #[test] #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let endpoint = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), @@ -4157,7 +4721,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &endpoint.clone(), - handler: NotifsHandler::new(peer, endpoint, vec![]), + handler: NotifsHandler::new(peer, endpoint, vec![], None), remaining_established: 0usize, }, )); @@ -4165,7 +4729,7 @@ mod tests { #[test] fn disconnect_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -4177,9 +4741,9 @@ mod tests { #[test] fn accept_non_existent_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); - notif.peerset_report_accept(0.into()); + notif.protocol_report_accept(0.into()); assert!(notif.peers.is_empty()); assert!(notif.incoming.is_empty()); @@ -4187,9 +4751,9 @@ mod tests { #[test] fn reject_non_existent_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); - notif.peerset_report_reject(0.into()); + notif.protocol_report_reject(0.into()); assert!(notif.peers.is_empty()); assert!(notif.incoming.is_empty()); @@ -4197,7 +4761,7 @@ mod tests { #[test] fn reject_non_active_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4221,61 +4785,24 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); notif.incoming[0].alive = false; - notif.peerset_report_reject(0.into()); - - assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - } - - #[test] - #[should_panic] - #[cfg(debug_assertions)] - fn reject_non_existent_peer_but_alive_connection() { - let (mut notif, _controller) = development_notifs(); - let peer = PeerId::random(); - let conn = ConnectionId::new_unchecked(0); - let set_id = SetId::from(0); - let connected = ConnectedPoint::Listener { - local_addr: Multiaddr::empty(), - send_back_addr: Multiaddr::empty(), - }; - - notif.on_swarm_event(FromSwarm::ConnectionEstablished( - libp2p::swarm::behaviour::ConnectionEstablished { - peer_id: peer, - connection_id: conn, - endpoint: &connected, - failed_addresses: &[], - other_established: 0usize, - }, - )); - assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + notif.protocol_report_reject(0.into()); - // remote opens a substream, verify that peer state is updated to `Incoming` - notif.on_connection_handler_event( - peer, - conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, - ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(std::matches!( - notif.incoming[0], - IncomingPeer { alive: true, incoming_id: IncomingIndex(0), .. }, - )); - - notif.peers.remove(&(peer, set_id)); - notif.peerset_report_reject(0.into()); } #[test] #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4299,7 +4826,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4308,7 +4838,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4318,7 +4848,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4343,7 +4873,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4353,7 +4883,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_disabled_pending_enable() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4394,7 +4924,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4404,7 +4934,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_incoming_peer_state_mismatch() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4428,7 +4958,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); notif.incoming[0].alive = false; @@ -4438,7 +4971,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4448,7 +4981,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_enabled_state_mismatch() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4472,7 +5005,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4485,7 +5021,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4495,7 +5031,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_backoff_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4528,7 +5064,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![]), + handler: NotifsHandler::new(peer, connected.clone(), vec![], None), remaining_established: 0usize, }, )); @@ -4539,7 +5075,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4549,7 +5085,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn open_result_ok_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index cffdec7d71e..28662be29fe 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -58,9 +58,12 @@ //! [`NotifsHandlerIn::Open`] has gotten an answer. use crate::{ - protocol::notifications::upgrade::{ - NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, - UpgradeCollec, + protocol::notifications::{ + service::metrics, + upgrade::{ + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, + }, }, types::ProtocolName, }; @@ -92,7 +95,7 @@ use std::{ /// Number of pending notifications in asynchronous contexts. /// See [`NotificationsSink::reserve_notification`] for context. -const ASYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 8; +pub(crate) const ASYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 8; /// Number of pending notifications in synchronous contexts. const SYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 2048; @@ -126,11 +129,19 @@ pub struct NotifsHandler { events_queue: VecDeque< ConnectionHandlerEvent, >, + + /// Metrics. + metrics: Option>, } impl NotifsHandler { /// Creates new [`NotifsHandler`]. - pub fn new(peer_id: PeerId, endpoint: ConnectedPoint, protocols: Vec) -> Self { + pub fn new( + peer_id: PeerId, + endpoint: ConnectedPoint, + protocols: Vec, + metrics: Option, + ) -> Self { Self { protocols: protocols .into_iter() @@ -148,6 +159,7 @@ impl NotifsHandler { endpoint, when_connection_open: Instant::now(), events_queue: VecDeque::with_capacity(16), + metrics: metrics.map_or(None, |metrics| Some(Arc::new(metrics))), } } } @@ -303,6 +315,8 @@ pub enum NotifsHandlerOut { OpenDesiredByRemote { /// Index of the protocol in the list of protocols passed at initialization. protocol_index: usize, + /// Received handshake. + handshake: Vec, }, /// The remote would like the substreams to be closed. Send a [`NotifsHandlerIn::Close`] in @@ -331,6 +345,36 @@ pub enum NotifsHandlerOut { #[derive(Debug, Clone)] pub struct NotificationsSink { inner: Arc, + metrics: Option>, +} + +impl NotificationsSink { + /// Create new [`NotificationsSink`]. + /// NOTE: only used for testing but must be `pub` as other crates in `client/network` use this. + pub fn new( + peer_id: PeerId, + ) -> (Self, mpsc::Receiver, mpsc::Receiver) + { + let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + ( + NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + metrics: None, + }, + async_rx, + sync_rx, + ) + } + + /// Get reference to metrics. + pub fn metrics(&self) -> &Option> { + &self.metrics + } } #[derive(Debug)] @@ -350,8 +394,8 @@ struct NotificationsSinkInner { /// Message emitted through the [`NotificationsSink`] and processed by the background task /// dedicated to the peer. -#[derive(Debug)] -enum NotificationsSinkMessage { +#[derive(Debug, PartialEq, Eq)] +pub enum NotificationsSinkMessage { /// Message emitted by [`NotificationsSink::reserve_notification`] and /// [`NotificationsSink::write_notification_now`]. Notification { message: Vec }, @@ -379,8 +423,8 @@ impl NotificationsSink { let mut lock = self.inner.sync_channel.lock(); if let Some(tx) = lock.as_mut() { - let result = - tx.try_send(NotificationsSinkMessage::Notification { message: message.into() }); + let message = message.into(); + let result = tx.try_send(NotificationsSinkMessage::Notification { message }); if result.is_err() { // Cloning the `mpsc::Sender` guarantees the allocation of an extra spot in the @@ -476,7 +520,10 @@ impl ConnectionHandler for NotifsHandler { match protocol_info.state { State::Closed { pending_opening } => { self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index, + handshake: in_substream_open.handshake, + }, )); protocol_info.state = State::OpenDesiredByRemote { @@ -531,6 +578,7 @@ impl ConnectionHandler for NotifsHandler { async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), }), + metrics: self.metrics.clone(), }; self.protocols[protocol_index].state = State::Open { @@ -881,6 +929,7 @@ pub mod tests { async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), }), + metrics: None, }; let (in_substream, out_substream) = MockSubstream::new(); @@ -1040,6 +1089,7 @@ pub mod tests { }, peer_id: PeerId::random(), events_queue: VecDeque::new(), + metrics: None, } } @@ -1545,6 +1595,7 @@ pub mod tests { async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), }), + metrics: None, }; handler.protocols[0].state = State::Open { @@ -1597,7 +1648,7 @@ pub mod tests { assert!(std::matches!( handler.poll(cx), Poll::Ready(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0, .. }, )) )); assert!(std::matches!( diff --git a/substrate/client/network/src/protocol/notifications/service/metrics.rs b/substrate/client/network/src/protocol/notifications/service/metrics.rs new file mode 100644 index 00000000000..2a57d57c175 --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/metrics.rs @@ -0,0 +1,130 @@ +// 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::types::ProtocolName; + +use prometheus_endpoint::{ + self as prometheus, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, + U64, +}; + +use std::sync::Arc; + +/// Notification metrics. +#[derive(Debug, Clone)] +pub struct Metrics { + // Total number of opened substreams. + pub notifications_streams_opened_total: CounterVec, + + /// Total number of closed substreams. + pub notifications_streams_closed_total: CounterVec, + + /// In/outbound notification sizes. + pub notifications_sizes: HistogramVec, +} + +impl Metrics { + fn register(registry: &Registry) -> Result { + Ok(Self { + notifications_sizes: prometheus::register( + HistogramVec::new( + HistogramOpts { + common_opts: Opts::new( + "substrate_sub_libp2p_notifications_sizes", + "Sizes of the notifications send to and received from all nodes", + ), + buckets: prometheus::exponential_buckets(64.0, 4.0, 8) + .expect("parameters are always valid values; qed"), + }, + &["direction", "protocol"], + )?, + registry, + )?, + notifications_streams_closed_total: prometheus::register( + CounterVec::new( + Opts::new( + "substrate_sub_libp2p_notifications_streams_closed_total", + "Total number of notification substreams that have been closed", + ), + &["protocol"], + )?, + registry, + )?, + notifications_streams_opened_total: prometheus::register( + CounterVec::new( + Opts::new( + "substrate_sub_libp2p_notifications_streams_opened_total", + "Total number of notification substreams that have been opened", + ), + &["protocol"], + )?, + registry, + )?, + }) + } +} + +/// Register metrics. +pub fn register(registry: &Registry) -> Result { + Metrics::register(registry) +} + +/// Register opened substream to Prometheus. +pub fn register_substream_opened(metrics: &Option, protocol: &ProtocolName) { + if let Some(metrics) = metrics { + metrics.notifications_streams_opened_total.with_label_values(&[&protocol]).inc(); + } +} + +/// Register closed substream to Prometheus. +pub fn register_substream_closed(metrics: &Option, protocol: &ProtocolName) { + if let Some(metrics) = metrics { + metrics + .notifications_streams_closed_total + .with_label_values(&[&protocol[..]]) + .inc(); + } +} + +/// Register sent notification to Prometheus. +pub fn register_notification_sent( + metrics: &Option>, + protocol: &ProtocolName, + size: usize, +) { + if let Some(metrics) = metrics { + metrics + .notifications_sizes + .with_label_values(&["out", protocol]) + .observe(size as f64); + } +} + +/// Register received notification to Prometheus. +pub fn register_notification_received( + metrics: &Option, + protocol: &ProtocolName, + size: usize, +) { + if let Some(metrics) = metrics { + metrics + .notifications_sizes + .with_label_values(&["in", protocol]) + .observe(size as f64); + } +} diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs new file mode 100644 index 00000000000..62e6d88a3d5 --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -0,0 +1,634 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Notification service implementation. + +use crate::{ + error, + protocol::notifications::handler::NotificationsSink, + service::traits::{ + Direction, MessageSink, NotificationEvent, NotificationService, ValidationResult, + }, + types::ProtocolName, +}; + +use futures::{ + stream::{FuturesUnordered, Stream}, + StreamExt, +}; +use libp2p::PeerId; +use parking_lot::Mutex; +use tokio::sync::{mpsc, oneshot}; +use tokio_stream::wrappers::ReceiverStream; + +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; + +use std::{collections::HashMap, fmt::Debug, sync::Arc}; + +pub(crate) mod metrics; + +#[cfg(test)] +mod tests; + +/// Logging target for the file. +const LOG_TARGET: &str = "sub-libp2p"; + +/// Default command queue size. +const COMMAND_QUEUE_SIZE: usize = 64; + +/// Type representing subscribers of a notification protocol. +type Subscribers = Arc>>>; + +/// Type represending a distributable message sink. +/// Detached message sink must carry the protocol name for registering metrics. +/// +/// See documentation for [`PeerContext`] for more details. +type NotificationSink = Arc>; + +#[async_trait::async_trait] +impl MessageSink for NotificationSink { + /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. + fn send_sync_notification(&self, notification: Vec) { + let sink = self.lock(); + + metrics::register_notification_sent(&sink.0.metrics(), &sink.1, notification.len()); + sink.0.send_sync_notification(notification); + } + + /// Send an asynchronous `notification` to the peer associated with this [`MessageSink`], + /// allowing sender to exercise backpressure. + /// + /// Returns an error if the peer does not exist. + async fn send_async_notification(&self, notification: Vec) -> Result<(), error::Error> { + // notification sink must be cloned because the lock cannot be held across `.await` + // this makes the implementation less efficient but not prohibitively so as the same + // method is also used by `NetworkService` when sending notifications. + let notification_len = notification.len(); + let sink = self.lock().clone(); + let permit = sink + .0 + .reserve_notification() + .await + .map_err(|_| error::Error::ConnectionClosed)?; + + permit.send(notification).map_err(|_| error::Error::ChannelClosed).map(|res| { + metrics::register_notification_sent(&sink.0.metrics(), &sink.1, notification_len); + res + }) + } +} + +/// Inner notification event to deal with `NotificationsSinks` without exposing that +/// implementation detail to [`NotificationService`] consumers. +#[derive(Debug)] +enum InnerNotificationEvent { + /// Validate inbound substream. + ValidateInboundSubstream { + /// Peer ID. + peer: PeerId, + + /// Received handshake. + handshake: Vec, + + /// `oneshot::Sender` for sending validation result back to `Notifications` + result_tx: oneshot::Sender, + }, + + /// Notification substream open to `peer`. + NotificationStreamOpened { + /// Peer ID. + peer: PeerId, + + /// Direction of the substream. + direction: Direction, + + /// Received handshake. + handshake: Vec, + + /// Negotiated fallback. + negotiated_fallback: Option, + + /// Notification sink. + sink: NotificationsSink, + }, + + /// Substream was closed. + NotificationStreamClosed { + /// Peer ID. + peer: PeerId, + }, + + /// Notification was received from the substream. + NotificationReceived { + /// Peer ID. + peer: PeerId, + + /// Received notification. + notification: Vec, + }, + + /// Notification sink has been replaced. + NotificationSinkReplaced { + /// Peer ID. + peer: PeerId, + + /// Notification sink. + sink: NotificationsSink, + }, +} + +/// Notification commands. +/// +/// Sent by the installed protocols to `Notifications` to open/close/modify substreams. +#[derive(Debug)] +pub enum NotificationCommand { + /// Instruct `Notifications` to open a substream to peer. + #[allow(unused)] + OpenSubstream(PeerId), + + /// Instruct `Notifications` to close the substream to peer. + #[allow(unused)] + CloseSubstream(PeerId), + + /// Set handshake for the notifications protocol. + SetHandshake(Vec), +} + +/// Context assigned to each peer. +/// +/// Contains `NotificationsSink` used by [`NotificationService`] to send notifications +/// and an additional, distributable `NotificationsSink` which the protocol may acquire +/// if it wishes to send notifications through `NotificationsSink` directly. +/// +/// The distributable `NoticationsSink` is wrapped in an `Arc>` to allow +/// `NotificationsService` to swap the underlying sink in case it's replaced. +#[derive(Debug, Clone)] +struct PeerContext { + /// Sink for sending notificaitons. + sink: NotificationsSink, + + /// Distributable notification sink. + shared_sink: NotificationSink, +} + +/// Handle that is passed on to the notifications protocol. +#[derive(Debug)] +pub struct NotificationHandle { + /// Protocol name. + protocol: ProtocolName, + + /// TX channel for sending commands to `Notifications`. + tx: mpsc::Sender, + + /// RX channel for receiving events from `Notifications`. + rx: TracingUnboundedReceiver, + + /// All subscribers of `NotificationEvent`s. + subscribers: Subscribers, + + /// Connected peers. + peers: HashMap, +} + +impl NotificationHandle { + /// Create new [`NotificationHandle`]. + fn new( + protocol: ProtocolName, + tx: mpsc::Sender, + rx: TracingUnboundedReceiver, + subscribers: Arc>>>, + ) -> Self { + Self { protocol, tx, rx, subscribers, peers: HashMap::new() } + } +} + +#[async_trait::async_trait] +impl NotificationService for NotificationHandle { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + todo!("support for opening substreams not implemented yet"); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + todo!("support for closing substreams not implemented yet, call `NetworkService::disconnect_peer()` instead"); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, peer: &PeerId, notification: Vec) { + if let Some(info) = self.peers.get(&peer) { + metrics::register_notification_sent( + &info.sink.metrics(), + &self.protocol, + notification.len(), + ); + + let _ = info.sink.send_sync_notification(notification); + } + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + peer: &PeerId, + notification: Vec, + ) -> Result<(), error::Error> { + let notification_len = notification.len(); + let sink = &self.peers.get(&peer).ok_or_else(|| error::Error::PeerDoesntExist(*peer))?.sink; + + sink.reserve_notification() + .await + .map_err(|_| error::Error::ConnectionClosed)? + .send(notification) + .map_err(|_| error::Error::ChannelClosed) + .map(|res| { + metrics::register_notification_sent( + &sink.metrics(), + &self.protocol, + notification_len, + ); + res + }) + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()> { + log::trace!(target: LOG_TARGET, "{}: set handshake to {handshake:?}", self.protocol); + + self.tx.send(NotificationCommand::SetHandshake(handshake)).await.map_err(|_| ()) + } + + /// Non-blocking variant of `set_handshake()` that attempts to update the handshake + /// and returns an error if the channel is blocked. + /// + /// Technically the function can return an error if the channel to `Notifications` is closed + /// but that doesn't happen under normal operation. + fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()> { + self.tx.try_send(NotificationCommand::SetHandshake(handshake)).map_err(|_| ()) + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + loop { + match self.rx.next().await? { + InnerNotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx } => + return Some(NotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + }), + InnerNotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + direction, + sink, + } => { + self.peers.insert( + peer, + PeerContext { + sink: sink.clone(), + shared_sink: Arc::new(Mutex::new((sink, self.protocol.clone()))), + }, + ); + return Some(NotificationEvent::NotificationStreamOpened { + peer, + handshake, + direction, + negotiated_fallback, + }) + }, + InnerNotificationEvent::NotificationStreamClosed { peer } => { + self.peers.remove(&peer); + return Some(NotificationEvent::NotificationStreamClosed { peer }) + }, + InnerNotificationEvent::NotificationReceived { peer, notification } => + return Some(NotificationEvent::NotificationReceived { peer, notification }), + InnerNotificationEvent::NotificationSinkReplaced { peer, sink } => { + match self.peers.get_mut(&peer) { + None => log::error!( + "{}: notification sink replaced for {peer} but peer does not exist", + self.protocol + ), + Some(context) => { + context.sink = sink.clone(); + *context.shared_sink.lock() = (sink.clone(), self.protocol.clone()); + }, + } + }, + } + } + } + + // Clone [`NotificationService`] + fn clone(&mut self) -> Result, ()> { + let mut subscribers = self.subscribers.lock(); + let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + subscribers.push(event_tx); + + Ok(Box::new(NotificationHandle { + protocol: self.protocol.clone(), + tx: self.tx.clone(), + rx: event_rx, + peers: self.peers.clone(), + subscribers: self.subscribers.clone(), + })) + } + + /// Get protocol name. + fn protocol(&self) -> &ProtocolName { + &self.protocol + } + + /// Get message sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option> { + match self.peers.get(peer) { + Some(context) => Some(Box::new(context.shared_sink.clone())), + None => None, + } + } +} + +/// Channel pair which allows `Notifications` to interact with a protocol. +#[derive(Debug)] +pub struct ProtocolHandlePair { + /// Protocol name. + protocol: ProtocolName, + + /// Subscribers of the notification protocol events. + subscribers: Subscribers, + + // Receiver for notification commands received from the protocol implementation. + rx: mpsc::Receiver, +} + +impl ProtocolHandlePair { + /// Create new [`ProtocolHandlePair`]. + fn new( + protocol: ProtocolName, + subscribers: Subscribers, + rx: mpsc::Receiver, + ) -> Self { + Self { protocol, subscribers, rx } + } + + /// Consume `self` and split [`ProtocolHandlePair`] into a handle which allows it to send events + /// to the protocol and a stream of commands received from the protocol. + pub(crate) fn split( + self, + ) -> (ProtocolHandle, Box + Send + Unpin>) { + ( + ProtocolHandle::new(self.protocol, self.subscribers), + Box::new(ReceiverStream::new(self.rx)), + ) + } +} + +/// Handle that is passed on to `Notifications` and allows it to directly communicate +/// with the protocol. +#[derive(Debug, Clone)] +pub(crate) struct ProtocolHandle { + /// Protocol name. + protocol: ProtocolName, + + /// Subscribers of the notification protocol. + subscribers: Subscribers, + + /// Number of connected peers. + num_peers: usize, + + /// Delegate validation to `Peerset`. + delegate_to_peerset: bool, + + /// Prometheus metrics. + metrics: Option, +} + +pub(crate) enum ValidationCallResult { + WaitForValidation(oneshot::Receiver), + Delegated, +} + +impl ProtocolHandle { + /// Create new [`ProtocolHandle`]. + fn new(protocol: ProtocolName, subscribers: Subscribers) -> Self { + Self { protocol, subscribers, num_peers: 0usize, metrics: None, delegate_to_peerset: false } + } + + /// Set metrics. + pub fn set_metrics(&mut self, metrics: Option) { + self.metrics = metrics; + } + + /// Delegate validation to `Peerset`. + /// + /// Protocols that do not do any validation themselves and only rely on `Peerset` handling + /// validation can disable protocol-side validation entirely by delegating all validation to + /// `Peerset`. + pub fn delegate_to_peerset(&mut self, delegate: bool) { + self.delegate_to_peerset = delegate; + } + + /// Report to the protocol that a substream has been opened and it must be validated by the + /// protocol. + /// + /// Return `oneshot::Receiver` which allows `Notifications` to poll for the validation result + /// from protocol. + pub fn report_incoming_substream( + &self, + peer: PeerId, + handshake: Vec, + ) -> Result { + let subscribers = self.subscribers.lock(); + + log::trace!( + target: LOG_TARGET, + "{}: report incoming substream for {peer}, handshake {handshake:?}", + self.protocol + ); + + if self.delegate_to_peerset { + return Ok(ValidationCallResult::Delegated) + } + + // if there is only one subscriber, `Notifications` can wait directly on the + // `oneshot::channel()`'s RX half without indirection + if subscribers.len() == 1 { + let (result_tx, rx) = oneshot::channel(); + return subscribers[0] + .unbounded_send(InnerNotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + }) + .map(|_| ValidationCallResult::WaitForValidation(rx)) + .map_err(|_| ()) + } + + // if there are multiple subscribers, create a task which waits for all of the + // validations to finish and returns the combined result to `Notifications` + let mut results: FuturesUnordered<_> = subscribers + .iter() + .filter_map(|subscriber| { + let (result_tx, rx) = oneshot::channel(); + + subscriber + .unbounded_send(InnerNotificationEvent::ValidateInboundSubstream { + peer, + handshake: handshake.clone(), + result_tx, + }) + .is_ok() + .then_some(rx) + }) + .collect(); + + let (tx, rx) = oneshot::channel(); + tokio::spawn(async move { + while let Some(event) = results.next().await { + match event { + Err(_) | Ok(ValidationResult::Reject) => + return tx.send(ValidationResult::Reject), + Ok(ValidationResult::Accept) => {}, + } + } + + return tx.send(ValidationResult::Accept) + }); + + Ok(ValidationCallResult::WaitForValidation(rx)) + } + + /// Report to the protocol that a substream has been opened and that it can now use the handle + /// to send notifications to the remote peer. + pub fn report_substream_opened( + &mut self, + peer: PeerId, + direction: Direction, + handshake: Vec, + negotiated_fallback: Option, + sink: NotificationsSink, + ) -> Result<(), ()> { + metrics::register_substream_opened(&self.metrics, &self.protocol); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: substream opened for {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationStreamOpened { + peer, + direction, + handshake: handshake.clone(), + negotiated_fallback: negotiated_fallback.clone(), + sink: sink.clone(), + }) + .is_ok() + }); + self.num_peers += 1; + + Ok(()) + } + + /// Substream was closed. + pub fn report_substream_closed(&mut self, peer: PeerId) -> Result<(), ()> { + metrics::register_substream_closed(&self.metrics, &self.protocol); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: substream closed for {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationStreamClosed { peer }) + .is_ok() + }); + self.num_peers -= 1; + + Ok(()) + } + + /// Notification was received from the substream. + pub fn report_notification_received( + &mut self, + peer: PeerId, + notification: Vec, + ) -> Result<(), ()> { + metrics::register_notification_received(&self.metrics, &self.protocol, notification.len()); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: notification received from {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationReceived { + peer, + notification: notification.clone(), + }) + .is_ok() + }); + + Ok(()) + } + + /// Notification sink was replaced. + pub fn report_notification_sink_replaced( + &mut self, + peer: PeerId, + sink: NotificationsSink, + ) -> Result<(), ()> { + let mut subscribers = self.subscribers.lock(); + + log::trace!( + target: LOG_TARGET, + "{}: notification sink replaced for {peer:?}", + self.protocol + ); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationSinkReplaced { + peer, + sink: sink.clone(), + }) + .is_ok() + }); + + Ok(()) + } + + /// Get the number of connected peers. + pub fn num_peers(&self) -> usize { + self.num_peers + } +} + +/// Create new (protocol, notification) handle pair. +/// +/// Handle pair allows `Notifications` and the protocol to communicate with each other directly. +pub fn notification_service( + protocol: ProtocolName, +) -> (ProtocolHandlePair, Box) { + let (cmd_tx, cmd_rx) = mpsc::channel(COMMAND_QUEUE_SIZE); + let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + let subscribers = Arc::new(Mutex::new(vec![event_tx])); + + ( + ProtocolHandlePair::new(protocol.clone(), subscribers.clone(), cmd_rx), + Box::new(NotificationHandle::new(protocol.clone(), cmd_tx, event_rx, subscribers)), + ) +} diff --git a/substrate/client/network/src/protocol/notifications/service/tests.rs b/substrate/client/network/src/protocol/notifications/service/tests.rs new file mode 100644 index 00000000000..02ba9e1711c --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/tests.rs @@ -0,0 +1,839 @@ +// 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::*; +use crate::protocol::notifications::handler::{ + NotificationsSinkMessage, ASYNC_NOTIFICATIONS_BUFFER_SIZE, +}; + +use std::future::Future; + +#[tokio::test] +async fn validate_and_accept_substream() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (handle, _stream) = proto.split(); + + let peer_id = PeerId::random(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); +} + +#[tokio::test] +async fn substream_opened() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + + let peer_id = PeerId::random(); + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } +} + +#[tokio::test] +async fn send_sync_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }) + ); +} + +#[tokio::test] +async fn send_async_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }) + ); +} + +#[tokio::test] +async fn send_sync_notification_to_non_existent_peer() { + let (proto, notif) = notification_service("/proto/1".into()); + let (_sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (_handle, _stream) = proto.split(); + let peer = PeerId::random(); + + // as per the original implementation, the call doesn't fail + notif.send_sync_notification(&peer, vec![1, 3, 3, 7]) +} + +#[tokio::test] +async fn send_async_notification_to_non_existent_peer() { + let (proto, notif) = notification_service("/proto/1".into()); + let (_sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (_handle, _stream) = proto.split(); + let peer = PeerId::random(); + + if let Err(error::Error::PeerDoesntExist(peer_id)) = + notif.send_async_notification(&peer, vec![1, 3, 3, 7]).await + { + assert_eq!(peer, peer_id); + } else { + panic!("invalid error received from `send_async_notification()`"); + } +} + +#[tokio::test] +async fn receive_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // notification is received + handle.report_notification_received(peer_id, vec![1, 3, 3, 8]).unwrap(); + + if let Some(NotificationEvent::NotificationReceived { peer, notification }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(notification, vec![1, 3, 3, 8]); + } else { + panic!("invalid event received"); + } +} + +#[tokio::test] +async fn backpressure_works() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // fill the message buffer with messages + for i in 0..=ASYNC_NOTIFICATIONS_BUFFER_SIZE { + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, i as u8])) + .is_ready()); + } + + // try to send one more message and verify that the call blocks + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, 9])).is_pending()); + + // release one slot from the buffer for new message + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 0] }) + ); + + // verify that a message can be sent + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, 9])).is_ready()); +} + +#[tokio::test] +async fn peer_disconnects_then_sync_notification_is_sent() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // report that a substream has been closed but don't poll `notif` to receive this + // information + handle.report_substream_closed(peer_id).unwrap(); + drop(sync_rx); + + // as per documentation, error is not reported but the notification is silently dropped + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 7]); +} + +#[tokio::test] +async fn peer_disconnects_then_async_notification_is_sent() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // report that a substream has been closed but don't poll `notif` to receive this + // information + handle.report_substream_closed(peer_id).unwrap(); + drop(async_rx); + + // as per documentation, error is not reported but the notification is silently dropped + if let Err(error::Error::ConnectionClosed) = + notif.send_async_notification(&peer_id, vec![1, 3, 3, 7]).await + { + } else { + panic!("invalid state after calling `send_async_notificatio()` on closed connection") + } +} + +#[tokio::test] +async fn cloned_service_opening_substream_works() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (_sink, _async_rx, _) = NotificationsSink::new(PeerId::random()); + let (handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(mut result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + // verify that `notif1` gets the event + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif1.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + // verify that because only one listener has thus far send their result, the result is + // pending + assert!(result_rx.try_recv().is_err()); + + // verify that `notif2` also gets the event + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif2.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); +} + +#[tokio::test] +async fn cloned_service_one_service_rejects_substream() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (_sink, _async_rx, _) = NotificationsSink::new(PeerId::random()); + let (handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let mut notif3 = notif2.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(mut result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + for notif in vec![&mut notif1, &mut notif2] { + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + } + + // `notif3` has not yet sent their validation result + assert!(result_rx.try_recv().is_err()); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif3.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Reject).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Reject); +} + +#[tokio::test] +async fn cloned_service_opening_substream_sending_and_receiving_notifications_work() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (sink, _, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let mut notif3 = notif1.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + // accept the inbound substream for all services + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that then notification stream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + } + // receive a notification from peer and verify all services receive it + handle.report_notification_received(peer_id, vec![1, 3, 3, 8]).unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationReceived { peer, notification }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(notification, vec![1, 3, 3, 8]); + } else { + panic!("invalid event received"); + } + } + + for (i, notif) in vec![&mut notif1, &mut notif2, &mut notif3].iter().enumerate() { + // send notification from each service and verify peer receives it + notif.send_sync_notification(&peer_id, vec![1, 3, 3, i as u8]); + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, i as u8] }) + ); + } + + // close the substream for peer and verify all services receive the event + handle.report_substream_closed(peer_id).unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationStreamClosed { peer }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + } else { + panic!("invalid event received"); + } + } +} + +#[tokio::test] +async fn sending_notifications_using_notifications_sink_works() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // get a copy of the notification sink and send a synchronous notification using. + let sink = notif.message_sink(&peer_id).unwrap(); + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); + + // send notifications using the stored notification sink as well. + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); +} + +#[test] +fn try_to_get_notifications_sink_for_non_existent_peer() { + let (_proto, notif) = notification_service("/proto/1".into()); + assert!(notif.message_sink(&PeerId::random()).is_none()); +} + +#[tokio::test] +async fn notification_sink_replaced() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // get a copy of the notification sink and send a synchronous notification using. + let sink = notif.message_sink(&peer_id).unwrap(); + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); + + // send notifications using the stored notification sink as well. + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); + + // the initial connection was closed and `Notifications` switched to secondary connection + // and emitted `CustomProtocolReplaced` which informs the local `NotificationService` that + // the notification sink was replaced. + let (new_sink, mut new_async_rx, mut new_sync_rx) = NotificationsSink::new(PeerId::random()); + handle.report_notification_sink_replaced(peer_id, new_sink).unwrap(); + + // drop the old sinks and poll `notif` once to register the sink replacement + drop(sync_rx); + drop(async_rx); + + futures::future::poll_fn(|cx| { + let _ = std::pin::Pin::new(&mut notif.next_event()).poll(cx); + std::task::Poll::Ready(()) + }) + .await; + + // verify that using the `NotificationService` API automatically results in using the correct + // sink + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + new_sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + new_async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); + + // now send two notifications using the acquired message sink and verify that + // it's also updated + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + new_sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + new_async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); +} + +#[tokio::test] +async fn set_handshake() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (_handle, mut stream) = proto.split(); + + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_ok()); + + match stream.next().await { + Some(NotificationCommand::SetHandshake(handshake)) => { + assert_eq!(handshake, vec![1, 3, 3, 7]); + }, + _ => panic!("invalid event received"), + } + + for _ in 0..COMMAND_QUEUE_SIZE { + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_ok()); + } + + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_err()); +} diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index d57c24144f5..92d269f89c3 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -22,6 +22,7 @@ use crate::{ peer_store::PeerStore, protocol::notifications::{Notifications, NotificationsOut, ProtocolConfig}, protocol_controller::{ProtoSetConfig, ProtocolController, SetId}, + service::traits::{NotificationEvent, ValidationResult}, }; use futures::{future::BoxFuture, prelude::*}; @@ -70,6 +71,8 @@ fn build_nodes() -> (Swarm, Swarm) { .timeout(Duration::from_secs(20)) .boxed(); + let (protocol_handle_pair, mut notif_service) = + crate::protocol::notifications::service::notification_service("/foo".into()); let peer_store = PeerStore::new(if index == 0 { keypairs.iter().skip(1).map(|keypair| keypair.public().to_peer_id()).collect() } else { @@ -91,16 +94,22 @@ fn build_nodes() -> (Swarm, Swarm) { Box::new(peer_store.handle()), ); + let (notif_handle, command_stream) = protocol_handle_pair.split(); let behaviour = CustomProtoWithAddr { inner: Notifications::new( vec![controller_handle], from_controller, - iter::once(ProtocolConfig { - name: "/foo".into(), - fallback_names: Vec::new(), - handshake: Vec::new(), - max_notification_size: 1024 * 1024, - }), + &None, + iter::once(( + ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: Vec::new(), + max_notification_size: 1024 * 1024, + }, + notif_handle, + command_stream, + )), ), peer_store_future: peer_store.run().boxed(), protocol_controller_future: controller.run().boxed(), @@ -118,6 +127,16 @@ fn build_nodes() -> (Swarm, Swarm) { }; let runtime = tokio::runtime::Runtime::new().unwrap(); + runtime.spawn(async move { + loop { + if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = + notif_service.next_event().await.unwrap() + { + result_tx.send(ValidationResult::Accept).unwrap(); + } + } + }); + let mut swarm = SwarmBuilder::with_executor( transport, behaviour, diff --git a/substrate/client/network/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index 3a305011ded..4c8f119baa2 100644 --- a/substrate/client/network/src/protocol_controller.rs +++ b/substrate/client/network/src/protocol_controller.rs @@ -847,6 +847,7 @@ mod tests { use super::*; use crate::{peer_store::PeerStoreProvider, ReputationChange}; use libp2p::PeerId; + use sc_network_common::role::ObservedRole; use sc_utils::mpsc::{tracing_unbounded, TryRecvError}; use std::collections::HashSet; @@ -858,8 +859,10 @@ mod tests { fn is_banned(&self, peer_id: &PeerId) -> bool; fn register_protocol(&self, protocol_handle: ProtocolHandle); fn report_disconnect(&mut self, peer_id: PeerId); + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole); fn report_peer(&mut self, peer_id: PeerId, change: ReputationChange); fn peer_reputation(&self, peer_id: &PeerId) -> i32; + fn peer_role(&self, peer_id: &PeerId) -> Option; fn outgoing_candidates<'a>(&self, count: usize, ignored: HashSet<&'a PeerId>) -> Vec; } } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index c1df48ad785..43a3ab09115 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -54,6 +54,7 @@ use crate::{ ReputationChange, }; +use codec::DecodeAll; use either::Either; use futures::{channel::oneshot, prelude::*}; #[allow(deprecated)] @@ -71,10 +72,13 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, info, trace, warn}; -use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; +use metrics::{Histogram, MetricSources, Metrics}; use parking_lot::Mutex; -use sc_network_common::ExHashT; +use sc_network_common::{ + role::{ObservedRole, Roles}, + ExHashT, +}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; @@ -118,12 +122,6 @@ pub struct NetworkService { bandwidth: Arc, /// Channel that sends messages to the actual worker. to_worker: TracingUnboundedSender, - /// For each peer and protocol combination, an object that allows sending notifications to - /// that peer. Updated by the [`NetworkWorker`]. - peers_notifications_sinks: Arc>>, - /// Field extracted from the [`Metrics`] struct and necessary to report the - /// notifications-related metrics. - notifications_sizes_metric: Option, /// Protocol name -> `SetId` mapping for notification protocols. The map never changes after /// initialization. notification_protocol_ids: HashMap, @@ -132,6 +130,8 @@ pub struct NetworkService { protocol_handles: Vec, /// Shortcut to sync protocol handle (`protocol_handles[0]`). sync_protocol_handle: protocol_controller::ProtocolHandle, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -199,7 +199,7 @@ where )?; for notification_protocol in ¬ification_protocols { ensure_addresses_consistent_with_transport( - notification_protocol.set_config.reserved_nodes.iter().map(|x| &x.multiaddr), + notification_protocol.set_config().reserved_nodes.iter().map(|x| &x.multiaddr), &network_config.transport, )?; } @@ -241,7 +241,7 @@ where .map(|cfg| usize::try_from(cfg.max_response_size).unwrap_or(usize::MAX)); let notifs_max = notification_protocols .iter() - .map(|cfg| usize::try_from(cfg.max_notification_size).unwrap_or(usize::MAX)); + .map(|cfg| usize::try_from(cfg.max_notification_size()).unwrap_or(usize::MAX)); // A "default" max is added to cover all the other protocols: ping, identify, // kademlia, block announces, and transactions. @@ -273,7 +273,7 @@ where // We must prepend a hardcoded default peer set to notification protocols. let all_peer_sets_iter = iter::once(&network_config.default_peers_set) - .chain(notification_protocols.iter().map(|protocol| &protocol.set_config)); + .chain(notification_protocols.iter().map(|protocol| protocol.set_config())); let (protocol_handles, protocol_controllers): (Vec<_>, Vec<_>) = all_peer_sets_iter .enumerate() @@ -312,21 +312,9 @@ where iter::once(¶ms.block_announce_config) .chain(notification_protocols.iter()) .enumerate() - .map(|(index, protocol)| { - (protocol.notifications_protocol.clone(), SetId::from(index)) - }) + .map(|(index, protocol)| (protocol.protocol_name().clone(), SetId::from(index))) .collect(); - let protocol = Protocol::new( - From::from(¶ms.role), - notification_protocols.clone(), - params.block_announce_config, - params.peer_store.clone(), - protocol_handles.clone(), - from_protocol_controllers, - params.tx, - )?; - let known_addresses = { // Collect all reserved nodes and bootnodes addresses. let mut addresses: Vec<_> = network_config @@ -336,7 +324,7 @@ where .map(|reserved| (reserved.peer_id, reserved.multiaddr.clone())) .chain(notification_protocols.iter().flat_map(|protocol| { protocol - .set_config + .set_config() .reserved_nodes .iter() .map(|reserved| (reserved.peer_id, reserved.multiaddr.clone())) @@ -389,6 +377,16 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let external_addresses = Arc::new(Mutex::new(HashSet::new())); + let (protocol, notif_protocol_handles) = Protocol::new( + From::from(¶ms.role), + ¶ms.metrics_registry, + notification_protocols, + params.block_announce_config, + params.peer_store.clone(), + protocol_handles.clone(), + from_protocol_controllers, + )?; + // Build the swarm. let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = @@ -508,7 +506,6 @@ where } let listen_addresses = Arc::new(Mutex::new(HashSet::new())); - let peers_notifications_sinks = Arc::new(Mutex::new(HashMap::new())); let service = Arc::new(NetworkService { bandwidth, @@ -518,13 +515,10 @@ where local_peer_id, local_identity, to_worker, - peers_notifications_sinks: peers_notifications_sinks.clone(), - notifications_sizes_metric: metrics - .as_ref() - .map(|metrics| metrics.notifications_sizes.clone()), notification_protocol_ids, protocol_handles, sync_protocol_handle, + peer_store_handle: params.peer_store.clone(), _marker: PhantomData, _block: Default::default(), }); @@ -539,8 +533,8 @@ where metrics, boot_node_ids, reported_invalid_boot_nodes: Default::default(), - peers_notifications_sinks, peer_store_handle: params.peer_store, + notif_protocol_handles, _marker: Default::default(), _block: Default::default(), }) @@ -567,7 +561,7 @@ where /// Returns the number of peers we're connected to. pub fn num_connected_peers(&self) -> usize { - self.network_service.behaviour().user_protocol().num_connected_peers() + self.network_service.behaviour().user_protocol().num_sync_peers() } /// Adds an address for a node. @@ -991,6 +985,16 @@ where fn sync_num_connected(&self) -> usize { self.num_connected.load(Ordering::Relaxed) } + + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option { + match Roles::decode_all(&mut &handshake[..]) { + Ok(role) => Some(role.into()), + Err(_) => { + log::debug!(target: "sub-libp2p", "handshake doesn't contain peer role: {handshake:?}"); + self.peer_store_handle.peer_role(&peer_id) + }, + } + } } impl NetworkEventStream for NetworkService @@ -1010,68 +1014,20 @@ where B: BlockT + 'static, H: ExHashT, { - fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec) { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - // Notification silently discarded, as documented. - debug!( - target: "sub-libp2p", - "Attempted to send notification on missing or closed substream: {}, {:?}", - target, protocol, - ); - return - } - }; - - if let Some(notifications_sizes_metric) = self.notifications_sizes_metric.as_ref() { - notifications_sizes_metric - .with_label_values(&["out", &protocol]) - .observe(message.len() as f64); - } - - // Sending is communicated to the `NotificationsSink`. - trace!( - target: "sub-libp2p", - "External API => Notification({:?}, {:?}, {} bytes)", - target, protocol, message.len() - ); - trace!(target: "sub-libp2p", "Handler({:?}) <= Sync notification", target); - sink.send_sync_notification(message); + fn write_notification(&self, _target: PeerId, _protocol: ProtocolName, _message: Vec) { + unimplemented!(); } fn notification_sender( &self, - target: PeerId, - protocol: ProtocolName, + _target: PeerId, + _protocol: ProtocolName, ) -> Result, NotificationSenderError> { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - return Err(NotificationSenderError::Closed) - } - }; - - let notification_size_metric = self - .notifications_sizes_metric - .as_ref() - .map(|histogram| histogram.with_label_values(&["out", &protocol])); - - Ok(Box::new(NotificationSender { sink, protocol_name: protocol, notification_size_metric })) + unimplemented!(); } - fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake)); + fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec) { + unimplemented!(); } } @@ -1209,7 +1165,6 @@ enum ServiceToWorkerMsg { pending_response: oneshot::Sender>, }, DisconnectPeer(PeerId, ProtocolName), - SetNotificationHandshake(ProtocolName, Vec), } /// Main network worker. Must be polled in order for the network to advance. @@ -1239,11 +1194,10 @@ where boot_node_ids: Arc>>, /// Boot nodes that we already have reported as invalid. reported_invalid_boot_nodes: HashSet, - /// For each peer and protocol combination, an object that allows sending notifications to - /// that peer. Shared with the [`NetworkService`]. - peers_notifications_sinks: Arc>>, /// Peer reputation store handle. peer_store_handle: PeerStoreHandle, + /// Notification protocol handles. + notif_protocol_handles: Vec, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -1282,8 +1236,7 @@ where }; // Update the `num_connected` count shared with the `NetworkService`. - let num_connected_peers = - self.network_service.behaviour_mut().user_protocol_mut().num_connected_peers(); + let num_connected_peers = self.network_service.behaviour().user_protocol().num_sync_peers(); self.num_connected.store(num_connected_peers, Ordering::Relaxed); if let Some(metrics) = self.metrics.as_ref() { @@ -1353,11 +1306,6 @@ where .behaviour_mut() .user_protocol_mut() .disconnect_peer(&who, protocol_name), - ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake) => self - .network_service - .behaviour_mut() - .user_protocol_mut() - .set_notification_handshake(protocol, handshake), } } @@ -1472,47 +1420,27 @@ where }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, notifications_sink, - role, received_handshake, }) => { - if let Some(metrics) = self.metrics.as_ref() { - metrics - .notifications_streams_opened_total - .with_label_values(&[&protocol]) - .inc(); - } - { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks - .insert((remote, protocol.clone()), notifications_sink); - debug_assert!(_previous_value.is_none()); - } - self.event_streams.send(Event::NotificationStreamOpened { + let _ = self.notif_protocol_handles[usize::from(set_id)].report_substream_opened( remote, - protocol, - negotiated_fallback, - role, + direction, received_handshake, - }); + negotiated_fallback, + notifications_sink, + ); }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamReplaced { remote, - protocol, + set_id, notifications_sink, }) => { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(s) = peers_notifications_sinks.get_mut(&(remote, protocol)) { - *s = notifications_sink; - } else { - error!( - target: "sub-libp2p", - "NotificationStreamReplaced for non-existing substream" - ); - debug_assert!(false); - } + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_notification_sink_replaced(remote, notifications_sink); // TODO: Notifications might have been lost as a result of the previous // connection being dropped, and as a result it would be preferable to notify @@ -1535,31 +1463,17 @@ where // role, // }); }, - SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { remote, protocol }) => { - if let Some(metrics) = self.metrics.as_ref() { - metrics - .notifications_streams_closed_total - .with_label_values(&[&protocol[..]]) - .inc(); - } - self.event_streams - .send(Event::NotificationStreamClosed { remote, protocol: protocol.clone() }); - { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks.remove(&(remote, protocol)); - debug_assert!(_previous_value.is_some()); - } + SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { remote, set_id }) => { + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_substream_closed(remote); }, - SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { remote, messages }) => { - if let Some(metrics) = self.metrics.as_ref() { - for (protocol, message) in &messages { - metrics - .notifications_sizes - .with_label_values(&["in", protocol]) - .observe(message.len() as f64); - } - } - self.event_streams.send(Event::NotificationsReceived { remote, messages }); + SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { + remote, + set_id, + notification, + }) => { + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_notification_received(remote, notification); }, SwarmEvent::Behaviour(BehaviourOut::Dht(event, duration)) => { if let Some(metrics) = self.metrics.as_ref() { diff --git a/substrate/client/network/src/service/metrics.rs b/substrate/client/network/src/service/metrics.rs index 13bc4b4e7af..c349fd98c76 100644 --- a/substrate/client/network/src/service/metrics.rs +++ b/substrate/client/network/src/service/metrics.rs @@ -61,9 +61,6 @@ pub struct Metrics { pub kbuckets_num_nodes: GaugeVec, pub listeners_local_addresses: Gauge, pub listeners_errors_total: Counter, - pub notifications_sizes: HistogramVec, - pub notifications_streams_closed_total: CounterVec, - pub notifications_streams_opened_total: CounterVec, pub peerset_num_discovered: Gauge, pub pending_connections: Gauge, pub pending_connections_errors_total: CounterVec, @@ -153,31 +150,6 @@ impl Metrics { "substrate_sub_libp2p_listeners_errors_total", "Total number of non-fatal errors reported by a listener" )?, registry)?, - notifications_sizes: prometheus::register(HistogramVec::new( - HistogramOpts { - common_opts: Opts::new( - "substrate_sub_libp2p_notifications_sizes", - "Sizes of the notifications send to and received from all nodes" - ), - buckets: prometheus::exponential_buckets(64.0, 4.0, 8) - .expect("parameters are always valid values; qed"), - }, - &["direction", "protocol"] - )?, registry)?, - notifications_streams_closed_total: prometheus::register(CounterVec::new( - Opts::new( - "substrate_sub_libp2p_notifications_streams_closed_total", - "Total number of notification substreams that have been closed" - ), - &["protocol"] - )?, registry)?, - notifications_streams_opened_total: prometheus::register(CounterVec::new( - Opts::new( - "substrate_sub_libp2p_notifications_streams_opened_total", - "Total number of notification substreams that have been opened" - ), - &["protocol"] - )?, registry)?, peerset_num_discovered: prometheus::register(Gauge::new( "substrate_sub_libp2p_peerset_num_discovered", "Number of nodes stored in the peerset manager", diff --git a/substrate/client/network/src/service/signature.rs b/substrate/client/network/src/service/signature.rs index 024f60e4c46..5b2ba6be8cf 100644 --- a/substrate/client/network/src/service/signature.rs +++ b/substrate/client/network/src/service/signature.rs @@ -18,6 +18,8 @@ // // If you read this, you are very thorough, congratulations. +//! Signature-related code + use libp2p::{ identity::{Keypair, PublicKey}, PeerId, diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index bed325ede4a..f66e810be11 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -18,8 +18,11 @@ // // If you read this, you are very thorough, congratulations. +//! Traits defined by `sc-network`. + use crate::{ config::MultiaddrWithPeerId, + error, event::Event, request_responses::{IfDisconnected, RequestFailure}, service::signature::Signature, @@ -30,7 +33,9 @@ use crate::{ use futures::{channel::oneshot, Stream}; use libp2p::{Multiaddr, PeerId}; -use std::{collections::HashSet, future::Future, pin::Pin, sync::Arc}; +use sc_network_common::role::ObservedRole; + +use std::{collections::HashSet, fmt::Debug, future::Future, pin::Pin, sync::Arc}; pub use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; @@ -221,6 +226,14 @@ pub trait NetworkPeers { /// Returns the number of peers in the sync peer set we're connected to. fn sync_num_connected(&self) -> usize; + + /// Attempt to get peer role. + /// + /// Right now the peer role is decoded from the received handshake for all protocols + /// (`/block-announces/1` has other information as well). If the handshake cannot be + /// decoded into a role, the role queried from `PeerStore` and if the role is not stored + /// there either, `None` is returned and the peer should be discarded. + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option; } // Manual implementation to avoid extra boxing here @@ -296,6 +309,10 @@ where fn sync_num_connected(&self) -> usize { T::sync_num_connected(self) } + + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option { + T::peer_role(self, peer_id, handshake) + } } /// Provides access to network-level event stream. @@ -611,3 +628,189 @@ where T::new_best_block_imported(self, hash, number) } } + +/// Substream acceptance result. +#[derive(Debug, PartialEq, Eq)] +pub enum ValidationResult { + /// Accept inbound substream. + Accept, + + /// Reject inbound substream. + Reject, +} + +/// Substream direction. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Direction { + /// Substream opened by the remote node. + Inbound, + + /// Substream opened by the local node. + Outbound, +} + +impl Direction { + /// Is the direction inbound. + pub fn is_inbound(&self) -> bool { + std::matches!(self, Direction::Inbound) + } +} + +/// Events received by the protocol from `Notifications`. +#[derive(Debug)] +pub enum NotificationEvent { + /// Validate inbound substream. + ValidateInboundSubstream { + /// Peer ID. + peer: PeerId, + + /// Received handshake. + handshake: Vec, + + /// `oneshot::Sender` for sending validation result back to `Notifications` + result_tx: tokio::sync::oneshot::Sender, + }, + + /// Remote identified by `PeerId` opened a substream and sent `Handshake`. + /// Validate `Handshake` and report status (accept/reject) to `Notifications`. + NotificationStreamOpened { + /// Peer ID. + peer: PeerId, + + /// Is the substream inbound or outbound. + direction: Direction, + + /// Received handshake. + handshake: Vec, + + /// Negotiated fallback. + negotiated_fallback: Option, + }, + + /// Substream was closed. + NotificationStreamClosed { + /// Peer Id. + peer: PeerId, + }, + + /// Notification was received from the substream. + NotificationReceived { + /// Peer ID. + peer: PeerId, + + /// Received notification. + notification: Vec, + }, +} + +/// Notification service +/// +/// Defines behaviors that both the protocol implementations and `Notifications` can expect from +/// each other. +/// +/// `Notifications` can send two different kinds of information to protocol: +/// * substream-related information +/// * notification-related information +/// +/// When an unvalidated, inbound substream is received by `Notifications`, it sends the inbound +/// stream information (peer ID, handshake) to protocol for validation. Protocol must then verify +/// that the handshake is valid (and in the future that it has a slot it can allocate for the peer) +/// and then report back the `ValidationResult` which is either `Accept` or `Reject`. +/// +/// After the validation result has been received by `Notifications`, it prepares the +/// substream for communication by initializing the necessary sinks and emits +/// `NotificationStreamOpened` which informs the protocol that the remote peer is ready to receive +/// notifications. +/// +/// Two different flavors of sending options are provided: +/// * synchronous sending ([`NotificationService::send_sync_notification()`]) +/// * asynchronous sending ([`NotificationService::send_async_notification()`]) +/// +/// The former is used by the protocols not ready to exercise backpressure and the latter by the +/// protocols that can do it. +/// +/// Both local and remote peer can close the substream at any time. Local peer can do so by calling +/// [`NotificationService::close_substream()`] which instructs `Notifications` to close the +/// substream. Remote closing the substream is indicated to the local peer by receiving +/// [`NotificationEvent::NotificationStreamClosed`] event. +/// +/// In case the protocol must update its handshake while it's operating (such as updating the best +/// block information), it can do so by calling [`NotificationService::set_handshake()`] +/// which instructs `Notifications` to update the handshake it stored during protocol +/// initialization. +/// +/// All peer events are multiplexed on the same incoming event stream from `Notifications` and thus +/// each event carries a `PeerId` so the protocol knows whose information to update when receiving +/// an event. +#[async_trait::async_trait] +pub trait NotificationService: Debug + Send { + /// Instruct `Notifications` to open a new substream for `peer`. + /// + /// `dial_if_disconnected` informs `Notifications` whether to dial + // the peer if there is currently no active connection to it. + // + // NOTE: not offered by the current implementation + async fn open_substream(&mut self, peer: PeerId) -> Result<(), ()>; + + /// Instruct `Notifications` to close substream for `peer`. + // + // NOTE: not offered by the current implementation + async fn close_substream(&mut self, peer: PeerId) -> Result<(), ()>; + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, peer: &PeerId, notification: Vec); + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + /// + /// Returns an error if the peer doesn't exist. + async fn send_async_notification( + &self, + peer: &PeerId, + notification: Vec, + ) -> Result<(), error::Error>; + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; + + /// Non-blocking variant of `set_handshake()` that attempts to update the handshake + /// and returns an error if the channel is blocked. + /// + /// Technically the function can return an error if the channel to `Notifications` is closed + /// but that doesn't happen under normal operation. + fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option; + + /// Make a copy of the object so it can be shared between protocol components + /// who wish to have access to the same underlying notification protocol. + fn clone(&mut self) -> Result, ()>; + + /// Get protocol name of the `NotificationService`. + fn protocol(&self) -> &ProtocolName; + + /// Get message sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option>; +} + +/// Message sink for peers. +/// +/// If protocol cannot use [`NotificationService`] to send notifications to peers and requires, +/// e.g., notifications to be sent in another task, the protocol may acquire a [`MessageSink`] +/// object for each peer by calling [`NotificationService::message_sink()`]. Calling this +/// function returns an object which allows the protocol to send notifications to the remote peer. +/// +/// Use of this API is discouraged as it's not as performant as sending notifications through +/// [`NotificationService`] due to synchronization required to keep the underlying notification +/// sink up to date with possible sink replacement events. +#[async_trait::async_trait] +pub trait MessageSink: Send + Sync { + /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. + fn send_sync_notification(&self, notification: Vec); + + /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`], + /// allowing sender to exercise backpressure. + /// + /// Returns an error if the peer does not exist. + async fn send_async_notification(&self, notification: Vec) -> Result<(), error::Error>; +} diff --git a/substrate/client/network/statement/src/lib.rs b/substrate/client/network/statement/src/lib.rs index 69d4faa13ef..5187e681d83 100644 --- a/substrate/client/network/statement/src/lib.rs +++ b/substrate/client/network/statement/src/lib.rs @@ -21,12 +21,13 @@ //! Usage: //! //! - Use [`StatementHandlerPrototype::new`] to create a prototype. -//! - Pass the return value of [`StatementHandlerPrototype::set_config`] to the network -//! configuration as an extra peers set. +//! - Pass the `NonDefaultSetConfig` returned from [`StatementHandlerPrototype::new`] to the network +//! configuration as an extra peers set. //! - Use [`StatementHandlerPrototype::build`] then [`StatementHandler::run`] to obtain a //! `Future` that processes statements. use crate::config::*; + use codec::{Decode, Encode}; use futures::{channel::oneshot, prelude::*, stream::FuturesUnordered, FutureExt}; use libp2p::{multiaddr, PeerId}; @@ -34,7 +35,7 @@ use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonDefaultSetConfig, NonReservedPeerMode, SetConfig}, error, - event::Event, + service::traits::{NotificationEvent, NotificationService, ValidationResult}, types::ProtocolName, utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -101,35 +102,35 @@ impl Metrics { /// Prototype for a [`StatementHandler`]. pub struct StatementHandlerPrototype { protocol_name: ProtocolName, + notification_service: Box, } impl StatementHandlerPrototype { /// Create a new instance. - pub fn new>(genesis_hash: Hash, fork_id: Option<&str>) -> Self { + pub fn new>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> (Self, NonDefaultSetConfig) { let genesis_hash = genesis_hash.as_ref(); let protocol_name = if let Some(fork_id) = fork_id { format!("/{}/{}/statement/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { format!("/{}/statement/1", array_bytes::bytes2hex("", genesis_hash)) }; - - Self { protocol_name: protocol_name.into() } - } - - /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> NonDefaultSetConfig { - NonDefaultSetConfig { - notifications_protocol: self.protocol_name.clone(), - fallback_names: Vec::new(), - max_notification_size: MAX_STATEMENT_SIZE, - handshake: None, - set_config: SetConfig { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol_name.clone().into(), + Vec::new(), + MAX_STATEMENT_SIZE, + None, + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ); + + (Self { protocol_name: protocol_name.into(), notification_service }, config) } /// Turns the prototype into the actual handler. @@ -147,7 +148,6 @@ impl StatementHandlerPrototype { metrics_registry: Option<&Registry>, executor: impl Fn(Pin + Send>>) + Send, ) -> error::Result> { - let net_event_stream = network.event_stream("statement-handler-net"); let sync_event_stream = sync.event_stream("statement-handler-sync"); let (queue_sender, mut queue_receiver) = async_channel::bounded(100_000); @@ -176,6 +176,7 @@ impl StatementHandlerPrototype { let handler = StatementHandler { protocol_name: self.protocol_name, + notification_service: self.notification_service, propagate_timeout: (Box::pin(interval(PROPAGATE_TIMEOUT)) as Pin + Send>>) .fuse(), @@ -183,7 +184,6 @@ impl StatementHandlerPrototype { pending_statements_peers: HashMap::new(), network, sync, - net_event_stream: net_event_stream.fuse(), sync_event_stream: sync_event_stream.fuse(), peers: HashMap::new(), statement_store, @@ -219,10 +219,10 @@ pub struct StatementHandler< network: N, /// Syncing service. sync: S, - /// Stream of networking events. - net_event_stream: stream::Fuse + Send>>>, /// Receiver for syncing-related events. sync_event_stream: stream::Fuse + Send>>>, + /// Notification service. + notification_service: Box, // All connected peers peers: HashMap, statement_store: Arc, @@ -261,14 +261,6 @@ where log::warn!(target: LOG_TARGET, "Inconsistent state, no peers for pending statement!"); } }, - network_event = self.net_event_stream.next() => { - if let Some(network_event) = network_event { - self.handle_network_event(network_event).await; - } else { - // Networking has seemingly closed. Closing as well. - return; - } - }, sync_event = self.sync_event_stream.next() => { if let Some(sync_event) = sync_event { self.handle_sync_event(sync_event); @@ -277,6 +269,14 @@ where return; } } + event = self.notification_service.next_event().fuse() => { + if let Some(event) = event { + self.handle_notification_event(event) + } else { + // `Notifications` has seemingly closed. Closing as well. + return + } + } } } } @@ -306,14 +306,24 @@ where } } - async fn handle_network_event(&mut self, event: Event) { + fn handle_notification_event(&mut self, event: NotificationEvent) { match event { - Event::Dht(_) => {}, - Event::NotificationStreamOpened { remote, protocol, role, .. } - if protocol == self.protocol_name => - { + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); + }, + NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { + let Some(role) = self.network.peer_role(peer, handshake) else { + log::debug!(target: LOG_TARGET, "role for {peer} couldn't be determined"); + return + }; + let _was_in = self.peers.insert( - remote, + peer, Peer { known_statements: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_STATEMENTS).expect("Constant is nonzero"), @@ -323,39 +333,26 @@ where ); debug_assert!(_was_in.is_none()); }, - Event::NotificationStreamClosed { remote, protocol } - if protocol == self.protocol_name => - { - let _peer = self.peers.remove(&remote); + NotificationEvent::NotificationStreamClosed { peer } => { + let _peer = self.peers.remove(&peer); debug_assert!(_peer.is_some()); }, + NotificationEvent::NotificationReceived { peer, notification } => { + // Accept statements only when node is not major syncing + if self.sync.is_major_syncing() { + log::trace!( + target: LOG_TARGET, + "{peer}: Ignoring statements while major syncing or offline" + ); + return + } - Event::NotificationsReceived { remote, messages } => { - for (protocol, message) in messages { - if protocol != self.protocol_name { - continue - } - // Accept statements only when node is not major syncing - if self.sync.is_major_syncing() { - log::trace!( - target: LOG_TARGET, - "{remote}: Ignoring statements while major syncing or offline" - ); - continue - } - if let Ok(statements) = ::decode(&mut message.as_ref()) { - self.on_statements(remote, statements); - } else { - log::debug!( - target: LOG_TARGET, - "Failed to decode statement list from {remote}" - ); - } + if let Ok(statements) = ::decode(&mut notification.as_ref()) { + self.on_statements(peer, statements); + } else { + log::debug!(target: LOG_TARGET, "Failed to decode statement list from {peer}"); } }, - - // Not our concern. - Event::NotificationStreamOpened { .. } | Event::NotificationStreamClosed { .. } => {}, } } diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 2cb8eab22f7..d7b024cd801 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -38,7 +38,7 @@ use crate::{ warp::{EncodedProof, WarpProofRequest, WarpSyncParams}, }; -use codec::{Decode, Encode}; +use codec::{Decode, DecodeAll, Encode}; use futures::{ channel::oneshot, future::{BoxFuture, Fuse}, @@ -61,9 +61,12 @@ use sc_network::{ FullNetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, }, + peer_store::{PeerStoreHandle, PeerStoreProvider}, request_responses::{IfDisconnected, RequestFailure}, + service::traits::{Direction, NotificationEvent, ValidationResult}, + types::ProtocolName, utils::LruHashSet, - NotificationsSink, ProtocolName, ReputationChange, + NotificationService, ReputationChange, }; use sc_network_common::{ role::Roles, @@ -88,15 +91,15 @@ use std::{ time::{Duration, Instant}, }; -/// Log target for this file. -const LOG_TARGET: &'static str = "sync"; - /// Interval at which we perform time based maintenance const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100); /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead +/// Logging target for the file. +const LOG_TARGET: &str = "sync"; + /// If the block announces stream to peer has been inactive for 30 seconds meaning local node /// has not sent or received block announcements to/from the peer, report the node for inactivity, /// disconnect it and attempt to establish connection to some other peer. @@ -226,8 +229,6 @@ pub struct Peer { pub info: ExtendedPeerInfo, /// Holds a set of blocks known to this peer. pub known_blocks: LruHashSet, - /// Notification sink. - sink: NotificationsSink, /// Is the peer inbound. inbound: bool, } @@ -252,9 +253,6 @@ pub struct SyncingEngine { /// Channel for receiving service commands service_rx: TracingUnboundedReceiver>, - /// Channel for receiving inbound connections from `Protocol`. - sync_events_rx: sc_utils::mpsc::TracingUnboundedReceiver>, - /// Assigned roles. roles: Roles, @@ -312,12 +310,18 @@ pub struct SyncingEngine { /// Prometheus metrics. metrics: Option, + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, + /// When the syncing was started. /// /// Stored as an `Option` so once the initial wait has passed, `SyncingEngine` /// can reset the peer timers and continue with the normal eviction process. syncing_started: Option, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, + /// Instant when the last notification was sent or received. last_notification_io: Instant, @@ -362,7 +366,7 @@ where block_downloader: Arc>, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - sync_events_rx: sc_utils::mpsc::TracingUnboundedReceiver>, + peer_store_handle: PeerStoreHandle, ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = net_config.network_config.sync_mode; let max_parallel_downloads = net_config.network_config.max_parallel_downloads; @@ -387,7 +391,7 @@ where } for config in net_config.notification_protocols() { let peer_ids = config - .set_config + .set_config() .reserved_nodes .iter() .map(|info| info.peer_id) @@ -438,7 +442,7 @@ where let warp_sync_target_block_header_rx_fused = warp_sync_target_block_header_rx .map_or(futures::future::pending().boxed().fuse(), |rx| rx.boxed().fuse()); - let block_announce_config = Self::get_block_announce_proto_config( + let (block_announce_config, notification_service) = Self::get_block_announce_proto_config( protocol_id, fork_id, roles, @@ -450,7 +454,6 @@ where .flatten() .expect("Genesis block exists; qed"), ); - let block_announce_protocol_name = block_announce_config.notifications_protocol.clone(); let chain_sync = ChainSync::new( mode, @@ -460,6 +463,7 @@ where warp_sync_config, )?; + let block_announce_protocol_name = block_announce_config.protocol_name().clone(); let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); @@ -496,7 +500,6 @@ where num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), service_rx, - sync_events_rx, genesis_hash, important_peers, default_peers_set_no_slot_connected_peers: HashSet::new(), @@ -508,8 +511,10 @@ where num_in_peers: 0usize, max_in_peers, event_streams: Vec::new(), + notification_service, tick_timeout, syncing_started: None, + peer_store_handle, last_notification_io: Instant::now(), metrics: if let Some(r) = metrics_registry { match Metrics::register(r, is_major_syncing.clone()) { @@ -673,23 +678,11 @@ where }; self.last_notification_io = Instant::now(); - peer.sink.send_sync_notification(message.encode()); + let _ = self.notification_service.send_sync_notification(peer_id, message.encode()); } } } - /// Inform sync about new best imported block. - pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { - log::debug!(target: LOG_TARGET, "New best block imported {hash:?}/#{number}"); - - self.chain_sync.update_chain_info(&hash, number); - self.network_service.set_notification_handshake( - self.block_announce_protocol_name.clone(), - BlockAnnouncesHandshake::::build(self.roles, number, hash, self.genesis_hash) - .encode(), - ) - } - pub async fn run(mut self) { self.syncing_started = Some(Instant::now()); @@ -698,8 +691,10 @@ where _ = self.tick_timeout.tick() => self.perform_periodic_actions(), command = self.service_rx.select_next_some() => self.process_service_command(command), - sync_event = self.sync_events_rx.select_next_some() => - self.process_sync_event(sync_event), + notification_event = self.notification_service.next_event() => match notification_event { + Some(event) => self.process_notification_event(event), + None => return, + }, warp_target_block_header = &mut self.warp_sync_target_block_header_rx_fused => self.pass_warp_sync_target_block_header(warp_target_block_header), response_event = self.pending_responses.select_next_some() => @@ -853,8 +848,20 @@ where } }, ToServiceCommand::AnnounceBlock(hash, data) => self.announce_block(hash, data), - ToServiceCommand::NewBestBlockImported(hash, number) => - self.new_best_block_imported(hash, number), + ToServiceCommand::NewBestBlockImported(hash, number) => { + log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); + + self.chain_sync.update_chain_info(&hash, number); + let _ = self.notification_service.try_set_handshake( + BlockAnnouncesHandshake::::build( + self.roles, + number, + hash, + self.genesis_hash, + ) + .encode(), + ); + }, ToServiceCommand::Status(tx) => { let mut status = self.chain_sync.status(); status.num_connected_peers = self.peers.len() as u32; @@ -894,56 +901,60 @@ where } } - fn process_sync_event(&mut self, event: sc_network::SyncEvent) { + fn process_notification_event(&mut self, event: NotificationEvent) { match event { - sc_network::SyncEvent::NotificationStreamOpened { - remote, - received_handshake, - sink, - inbound, - tx, - } => match self.on_sync_peer_connected(remote, &received_handshake, sink, inbound) { - Ok(()) => { - let _ = tx.send(true); - }, - Err(()) => { - log::debug!( - target: LOG_TARGET, - "Failed to register peer {remote:?}: {received_handshake:?}", - ); - let _ = tx.send(false); - }, - }, - sc_network::SyncEvent::NotificationStreamClosed { remote } => { - if self.on_sync_peer_disconnected(remote).is_err() { - log::trace!( - target: LOG_TARGET, - "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", - remote - ); - } + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx } => { + let validation_result = self + .validate_connection(&peer, handshake, Direction::Inbound) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + + let _ = result_tx.send(validation_result); }, - sc_network::SyncEvent::NotificationsReceived { remote, messages } => { - for message in messages { - if self.peers.contains_key(&remote) { - if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { - self.last_notification_io = Instant::now(); - self.push_block_announce_validation(remote, announce); - } else { - log::warn!(target: "sub-libp2p", "Failed to decode block announce"); + NotificationEvent::NotificationStreamOpened { peer, handshake, direction, .. } => { + log::debug!( + target: LOG_TARGET, + "Substream opened for {peer}, handshake {handshake:?}" + ); + + match self.validate_connection(&peer, handshake, direction) { + Ok(handshake) => { + if self.on_sync_peer_connected(peer, &handshake, direction).is_err() { + log::debug!(target: LOG_TARGET, "Failed to register peer {peer}"); + self.network_service + .disconnect_peer(peer, self.block_announce_protocol_name.clone()); } - } else { - log::trace!( - target: LOG_TARGET, - "Received sync for peer earlier refused by sync layer: {remote}", - ); - } + }, + Err(wrong_genesis) => { + log::debug!(target: LOG_TARGET, "`SyncingEngine` rejected {peer}"); + + if wrong_genesis { + self.peer_store_handle.report_peer(peer, rep::GENESIS_MISMATCH); + } + + self.network_service + .disconnect_peer(peer, self.block_announce_protocol_name.clone()); + }, } }, - sc_network::SyncEvent::NotificationSinkReplaced { remote, sink } => { - if let Some(peer) = self.peers.get_mut(&remote) { - peer.sink = sink; + NotificationEvent::NotificationStreamClosed { peer } => { + self.on_sync_peer_disconnected(peer); + }, + NotificationEvent::NotificationReceived { peer, notification } => { + if !self.peers.contains_key(&peer) { + log::error!( + target: LOG_TARGET, + "received notification from {peer} who had been earlier refused by `SyncingEngine`", + ); + return } + + let Ok(announce) = BlockAnnounce::decode(&mut notification.as_ref()) else { + log::warn!(target: LOG_TARGET, "failed to decode block announce"); + return + }; + + self.last_notification_io = Instant::now(); + self.push_block_announce_validation(peer, announce); }, } } @@ -965,129 +976,167 @@ where /// Called by peer when it is disconnecting. /// /// Returns a result if the handshake of this peer was indeed accepted. - fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) -> Result<(), ()> { - if let Some(info) = self.peers.remove(&peer_id) { - if self.important_peers.contains(&peer_id) { - log::warn!(target: LOG_TARGET, "Reserved peer {peer_id} disconnected"); - } else { - log::debug!(target: LOG_TARGET, "{peer_id} disconnected"); - } - - if !self.default_peers_set_no_slot_connected_peers.remove(&peer_id) && - info.inbound && info.info.roles.is_full() - { - match self.num_in_peers.checked_sub(1) { - Some(value) => { - self.num_in_peers = value; - }, - None => { - log::error!( - target: LOG_TARGET, - "trying to disconnect an inbound node which is not counted as inbound" - ); - debug_assert!(false); - }, - } - } - - self.chain_sync.peer_disconnected(&peer_id); + fn on_sync_peer_disconnected(&mut self, peer_id: PeerId) { + let Some(info) = self.peers.remove(&peer_id) else { + log::debug!(target: LOG_TARGET, "{peer_id} does not exist in `SyncingEngine`"); + return + }; - self.pending_responses.remove(&peer_id); - self.event_streams.retain(|stream| { - stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok() - }); - Ok(()) + if self.important_peers.contains(&peer_id) { + log::warn!(target: LOG_TARGET, "Reserved peer {peer_id} disconnected"); } else { - Err(()) + log::debug!(target: LOG_TARGET, "{peer_id} disconnected"); } - } - /// Called on the first connection between two peers on the default set, after their exchange - /// of handshake. - /// - /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync - /// from. - fn on_sync_peer_connected( - &mut self, - peer_id: PeerId, - status: &BlockAnnouncesHandshake, - sink: NotificationsSink, - inbound: bool, - ) -> Result<(), ()> { - log::trace!(target: LOG_TARGET, "New peer {peer_id} {status:?}"); - - if self.peers.contains_key(&peer_id) { - log::error!( - target: LOG_TARGET, - "Called on_sync_peer_connected with already connected peer {peer_id}", - ); - debug_assert!(false); - return Err(()) + if !self.default_peers_set_no_slot_connected_peers.remove(&peer_id) && + info.inbound && info.info.roles.is_full() + { + match self.num_in_peers.checked_sub(1) { + Some(value) => { + self.num_in_peers = value; + }, + None => { + log::error!( + target: LOG_TARGET, + "trying to disconnect an inbound node which is not counted as inbound" + ); + debug_assert!(false); + }, + } } - if status.genesis_hash != self.genesis_hash { - self.network_service.report_peer(peer_id, rep::GENESIS_MISMATCH); + self.chain_sync.peer_disconnected(&peer_id); + self.pending_responses.remove(&peer_id); + self.event_streams + .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok()); + } + /// Validate received handshake. + fn validate_handshake( + &mut self, + peer_id: &PeerId, + handshake: Vec, + ) -> Result, bool> { + log::trace!(target: LOG_TARGET, "Validate handshake for {peer_id}"); + + let handshake = as DecodeAll>::decode_all(&mut &handshake[..]) + .map_err(|error| { + log::debug!(target: LOG_TARGET, "Failed to decode handshake for {peer_id}: {error:?}"); + false + })?; + + if handshake.genesis_hash != self.genesis_hash { if self.important_peers.contains(&peer_id) { log::error!( target: LOG_TARGET, - "Reserved peer id `{}` is on a different chain (our genesis: {} theirs: {})", - peer_id, + "Reserved peer id `{peer_id}` is on a different chain (our genesis: {} theirs: {})", self.genesis_hash, - status.genesis_hash, + handshake.genesis_hash, ); } else if self.boot_node_ids.contains(&peer_id) { log::error!( target: LOG_TARGET, - "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", - peer_id, + "Bootnode with peer id `{peer_id}` is on a different chain (our genesis: {} theirs: {})", self.genesis_hash, - status.genesis_hash, + handshake.genesis_hash, ); } else { log::debug!( target: LOG_TARGET, "Peer is on different chain (our genesis: {} theirs: {})", - self.genesis_hash, status.genesis_hash + self.genesis_hash, + handshake.genesis_hash ); } - return Err(()) + return Err(true) } - let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&peer_id); - let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; + Ok(handshake) + } - // make sure to accept no more than `--in-peers` many full nodes - if !no_slot_peer && - status.roles.is_full() && - inbound && self.num_in_peers == self.max_in_peers - { - log::debug!( + /// Validate connection. + // NOTE Returning `Err(bool)` is a really ugly hack to work around the issue + // that `ProtocolController` thinks the peer is connected when in fact it can + // still be under validation. If the peer has different genesis than the + // local node the validation fails but the peer cannot be reported in + // `validate_connection()` as that is also called by + // `ValiateInboundSubstream` which means that the peer is still being + // validated and banning the peer when handling that event would + // result in peer getting dropped twice. + // + // The proper way to fix this is to integrate `ProtocolController` more + // tightly with `NotificationService` or add an additional API call for + // banning pre-accepted peers (which is not desirable) + fn validate_connection( + &mut self, + peer_id: &PeerId, + handshake: Vec, + direction: Direction, + ) -> Result, bool> { + log::trace!(target: LOG_TARGET, "New peer {peer_id} {handshake:?}"); + + let handshake = self.validate_handshake(peer_id, handshake)?; + + if self.peers.contains_key(&peer_id) { + log::error!( target: LOG_TARGET, - "All inbound slots have been consumed, rejecting {peer_id}", + "Called `validate_connection()` with already connected peer {peer_id}", ); - return Err(()) + debug_assert!(false); + return Err(false) } - if status.roles.is_full() && + let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&peer_id); + let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; + + if handshake.roles.is_full() && self.chain_sync.num_peers() >= self.default_peers_set_num_full + self.default_peers_set_no_slot_connected_peers.len() + this_peer_reserved_slot { log::debug!(target: LOG_TARGET, "Too many full nodes, rejecting {peer_id}"); - return Err(()) + return Err(false) } - if status.roles.is_light() && + // make sure to accept no more than `--in-peers` many full nodes + if !no_slot_peer && + handshake.roles.is_full() && + direction.is_inbound() && + self.num_in_peers == self.max_in_peers + { + log::debug!(target: LOG_TARGET, "All inbound slots have been consumed, rejecting {peer_id}"); + return Err(false) + } + + // make sure that all slots are not occupied by light peers + // + // `ChainSync` only accepts full peers whereas `SyncingEngine` accepts both full and light + // peers. Verify that there is a slot in `SyncingEngine` for the inbound light peer + if handshake.roles.is_light() && (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light { - // Make sure that not all slots are occupied by light clients. log::debug!(target: LOG_TARGET, "Too many light nodes, rejecting {peer_id}"); - return Err(()) + return Err(false) } + Ok(handshake) + } + + /// Called on the first connection between two peers on the default set, after their exchange + /// of handshake. + /// + /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync + /// from. + fn on_sync_peer_connected( + &mut self, + peer_id: PeerId, + status: &BlockAnnouncesHandshake, + direction: Direction, + ) -> Result<(), ()> { + log::trace!(target: LOG_TARGET, "New peer {peer_id} {status:?}"); + let peer = Peer { info: ExtendedPeerInfo { roles: status.roles, @@ -1097,8 +1146,7 @@ where known_blocks: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), ), - sink, - inbound, + inbound: direction.is_inbound(), }; self.chain_sync.new_peer(peer_id, peer.info.best_hash, peer.info.best_number); @@ -1106,10 +1154,11 @@ where log::debug!(target: LOG_TARGET, "Connected {peer_id}"); self.peers.insert(peer_id, peer); + self.peer_store_handle.set_peer_role(&peer_id, status.roles.into()); - if no_slot_peer { + if self.default_peers_set_no_slot_peers.contains(&peer_id) { self.default_peers_set_no_slot_connected_peers.insert(peer_id); - } else if inbound && status.roles.is_full() { + } else if direction.is_inbound() && status.roles.is_full() { self.num_in_peers += 1; } @@ -1333,7 +1382,7 @@ where best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, - ) -> NonDefaultSetConfig { + ) -> (NonDefaultSetConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); if let Some(ref fork_id) = fork_id { @@ -1347,14 +1396,11 @@ where } }; - 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( + NonDefaultSetConfig::new( + block_announces_protocol.into(), + iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()).collect(), + MAX_BLOCK_ANNOUNCE_SIZE, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( roles, best_number, best_hash, @@ -1362,13 +1408,13 @@ where ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. - set_config: SetConfig { + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ) } /// Import blocks. diff --git a/substrate/client/network/sync/src/service/mock.rs b/substrate/client/network/sync/src/service/mock.rs index 885eb1f8da5..47986a71d01 100644 --- a/substrate/client/network/sync/src/service/mock.rs +++ b/substrate/client/network/sync/src/service/mock.rs @@ -27,6 +27,7 @@ use sc_network::{ NetworkNotification, NetworkPeers, NetworkRequest, NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT, ReputationChange, }; +use sc_network_common::role::ObservedRole; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::collections::HashSet; @@ -105,6 +106,7 @@ mockall::mock! { peers: Vec ) -> Result<(), String>; fn sync_num_connected(&self) -> usize; + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option; } #[async_trait::async_trait] diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index cfc3cb7af3f..71f13b74a53 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -58,7 +58,7 @@ use sc_network::{ request_responses::ProtocolConfig as RequestResponseConfig, types::ProtocolName, Multiaddr, NetworkBlock, NetworkService, NetworkStateInfo, NetworkSyncForkRequest, - NetworkWorker, + NetworkWorker, NotificationService, }; use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -239,6 +239,7 @@ pub struct Peer { imported_blocks_stream: Pin> + Send>>, finality_notification_stream: Pin> + Send>>, listen_addr: Multiaddr, + notification_services: HashMap>, } impl Peer @@ -263,8 +264,8 @@ where } /// Returns the number of peers we're connected to. - pub fn num_peers(&self) -> usize { - self.network.num_connected_peers() + pub async fn num_peers(&self) -> usize { + self.sync_service.status().await.unwrap().num_connected_peers as usize } /// Returns the number of downloaded blocks. @@ -502,10 +503,19 @@ where self.network.service() } + /// Get `SyncingService`. pub fn sync_service(&self) -> &Arc> { &self.sync_service } + /// Take notification handle for enabled protocol. + pub fn take_notification_service( + &mut self, + protocol: &ProtocolName, + ) -> Option> { + self.notification_services.remove(protocol) + } + /// Get a reference to the network worker. pub fn network(&self) -> &NetworkWorker::Hash> { &self.network @@ -778,6 +788,23 @@ pub trait TestNetFactory: Default + Sized + Send { network_config.transport = TransportConfig::MemoryOnly; network_config.listen_addresses = vec![listen_addr.clone()]; network_config.allow_non_globals_in_dht = true; + + let (notif_configs, notif_handles): (Vec<_>, Vec<_>) = config + .notifications_protocols + .into_iter() + .map(|p| { + let (config, handle) = NonDefaultSetConfig::new( + p.clone(), + Vec::new(), + 1024 * 1024, + None, + Default::default(), + ); + + (config, (p, handle)) + }) + .unzip(); + if let Some(connect_to) = config.connect_to_peers { let addrs = connect_to .iter() @@ -849,11 +876,16 @@ pub trait TestNetFactory: Default + Sized + Send { protocol_config }; + let peer_store = PeerStore::new( + network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), + ); + let peer_store_handle = peer_store.handle(); + self.spawn_task(peer_store.run().boxed()); + let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, sync_service, block_announce_config) = sc_network_sync::engine::SyncingEngine::new( Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), @@ -869,7 +901,7 @@ pub trait TestNetFactory: Default + Sized + Send { block_relay_params.downloader, state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), - rx, + peer_store_handle.clone(), ) .unwrap(); let sync_service_import_queue = Box::new(sync_service.clone()); @@ -887,22 +919,10 @@ pub trait TestNetFactory: Default + Sized + Send { full_net_config.add_request_response_protocol(config); } - for protocol in config.notifications_protocols { - full_net_config.add_notification_protocol(NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }); + for config in notif_configs { + full_net_config.add_notification_protocol(config); } - let peer_store = PeerStore::new( - network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), - ); - let peer_store_handle = peer_store.handle(); - self.spawn_task(peer_store.run().boxed()); - let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); let network = NetworkWorker::new(sc_network::config::Params { @@ -917,7 +937,6 @@ pub trait TestNetFactory: Default + Sized + Send { fork_id, metrics_registry: None, block_announce_config, - tx, }) .unwrap(); @@ -953,6 +972,7 @@ pub trait TestNetFactory: Default + Sized + Send { backend: Some(backend), imported_blocks_stream, finality_notification_stream, + notification_services: HashMap::from_iter(notif_handles.into_iter()), block_import, verifier, network, @@ -967,20 +987,6 @@ pub trait TestNetFactory: Default + Sized + Send { tokio::spawn(f); } - /// Polls the testnet until all peers are connected to each other. - /// - /// Must be executed in a task context. - fn poll_until_connected(&mut self, cx: &mut FutureContext) -> Poll<()> { - self.poll(cx); - - let num_peers = self.peers().len(); - if self.peers().iter().all(|p| p.num_peers() == num_peers - 1) { - return Poll::Ready(()) - } - - Poll::Pending - } - async fn is_in_sync(&mut self) -> bool { let mut highest = None; let peers = self.peers_mut(); @@ -1058,10 +1064,27 @@ pub trait TestNetFactory: Default + Sized + Send { } /// Run the network until all peers are connected to each other. - /// - /// Calls `poll_until_connected` repeatedly with the runtime passed as parameter. async fn run_until_connected(&mut self) { - futures::future::poll_fn::<(), _>(|cx| self.poll_until_connected(cx)).await; + let num_peers = self.peers().len(); + let sync_services = + self.peers().iter().map(|info| info.sync_service.clone()).collect::>(); + + 'outer: loop { + for sync_service in &sync_services { + if sync_service.status().await.unwrap().num_connected_peers as usize != + num_peers - 1 + { + futures::future::poll_fn::<(), _>(|cx| { + self.poll(cx); + Poll::Ready(()) + }) + .await; + continue 'outer + } + } + + break + } } /// Polls the testnet. Processes all the pending actions. diff --git a/substrate/client/network/test/src/service.rs b/substrate/client/network/test/src/service.rs index 62d7f9f9d1b..800c0d4369c 100644 --- a/substrate/client/network/test/src/service.rs +++ b/substrate/client/network/test/src/service.rs @@ -24,8 +24,9 @@ use sc_network::{ config::{self, FullNetworkConfiguration, MultiaddrWithPeerId, ProtocolId, TransportConfig}, event::Event, peer_store::PeerStore, - NetworkEventStream, NetworkNotification, NetworkPeers, NetworkService, NetworkStateInfo, - NetworkWorker, + service::traits::{NotificationEvent, ValidationResult}, + NetworkEventStream, NetworkPeers, NetworkService, NetworkStateInfo, NetworkWorker, + NotificationService, }; use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -116,7 +117,7 @@ impl TestNetworkBuilder { self } - pub fn build(mut self) -> TestNetwork { + pub fn build(mut self) -> (TestNetwork, Option>) { let client = self.client.as_mut().map_or( Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), |v| v.clone(), @@ -183,7 +184,12 @@ impl TestNetworkBuilder { protocol_config }; - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); + let peer_store = PeerStore::new( + network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), + ); + let peer_store_handle = peer_store.handle(); + tokio::spawn(peer_store.run().boxed()); + let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config::Role::Full), client.clone(), @@ -198,24 +204,27 @@ impl TestNetworkBuilder { block_relay_params.downloader, state_request_protocol_config.name.clone(), None, - rx, + peer_store_handle.clone(), ) .unwrap(); let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); - if !self.notification_protocols.is_empty() { + let handle = if !self.notification_protocols.is_empty() { for config in self.notification_protocols { full_net_config.add_notification_protocol(config); } + None } else { - full_net_config.add_notification_protocol(config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: self.set_config.unwrap_or_default(), - }); - } + let (config, handle) = config::NonDefaultSetConfig::new( + PROTOCOL_NAME.into(), + Vec::new(), + 1024 * 1024, + None, + self.set_config.unwrap_or_default(), + ); + full_net_config.add_notification_protocol(config); + Some(handle) + }; for config in [ block_relay_params.request_response_config, @@ -225,12 +234,6 @@ impl TestNetworkBuilder { full_net_config.add_request_response_protocol(config); } - let peer_store = PeerStore::new( - network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), - ); - let peer_store_handle = peer_store.handle(); - tokio::spawn(peer_store.run().boxed()); - let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); let worker = NetworkWorker::< @@ -248,7 +251,6 @@ impl TestNetworkBuilder { protocol_id, fork_id, metrics_registry: None, - tx, }) .unwrap(); @@ -268,7 +270,7 @@ impl TestNetworkBuilder { }); tokio::spawn(engine.run()); - TestNetwork::new(worker) + (TestNetwork::new(worker), handle) } } @@ -276,18 +278,18 @@ impl TestNetworkBuilder { /// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered. fn build_nodes_one_proto() -> ( Arc, - impl Stream, + Option>, Arc, - impl Stream, + Option>, ) { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, events_stream1) = TestNetworkBuilder::new() + let (network1, handle1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) - .build() - .start_network(); + .build(); + let (node1, _) = network1.start_network(); - let (node2, events_stream2) = TestNetworkBuilder::new() + let (network2, handle2) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -295,10 +297,11 @@ fn build_nodes_one_proto() -> ( }], ..Default::default() }) - .build() - .start_network(); + .build(); + + let (node2, _) = network2.start_network(); - (node1, events_stream1, node2, events_stream2) + (node1, handle1, node2, handle2) } #[tokio::test] @@ -306,22 +309,15 @@ async fn notifications_state_consistent() { // Runs two nodes and ensures that events are propagated out of the API in a consistent // correct order, which means no notification received on a closed substream. - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let (node1, handle1, node2, handle2) = build_nodes_one_proto(); + let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap()); // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } for _ in 0..(rand::random::() % 5) { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } // True if we have an active substream from node1 to node2. @@ -343,18 +339,10 @@ async fn notifications_state_consistent() { // Start by sending a notification from node1 to node2 and vice-versa. Part of the // test consists in ensuring that notifications get ignored if the stream isn't open. if rand::random::() % 5 >= 3 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } if rand::random::() % 5 >= 3 { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } // Also randomly disconnect the two nodes from time to time. @@ -367,8 +355,8 @@ async fn notifications_state_consistent() { // Grab next event from either `events_stream1` or `events_stream2`. let next_event = { - let next1 = events_stream1.next(); - let next2 = events_stream2.next(); + let next1 = handle1.next_event(); + let next2 = handle2.next_event(); // We also await on a small timer, otherwise it is possible for the test to wait // forever while nothing at all happens on the network. let continue_test = futures_timer::Delay::new(Duration::from_millis(20)); @@ -383,58 +371,55 @@ async fn notifications_state_consistent() { }; match next_event { - future::Either::Left(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node1_to_node2_open); - node1_to_node2_open = true; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node2_to_node1_open); - node2_to_node1_open = true; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node1_to_node2_open); - node1_to_node2_open = false; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node2_to_node1_open); - node2_to_node1_open = false; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationsReceived { remote, .. }) => { + future::Either::Left(NotificationEvent::ValidateInboundSubstream { + result_tx, .. + }) => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + future::Either::Right(NotificationEvent::ValidateInboundSubstream { + result_tx, + .. + }) => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + future::Either::Left(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + something_happened = true; + assert!(!node1_to_node2_open); + node1_to_node2_open = true; + assert_eq!(peer, node2.local_peer_id()); + }, + future::Either::Right(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + something_happened = true; + assert!(!node2_to_node1_open); + node2_to_node1_open = true; + assert_eq!(peer, node1.local_peer_id()); + }, + future::Either::Left(NotificationEvent::NotificationStreamClosed { peer, .. }) => { assert!(node1_to_node2_open); - assert_eq!(remote, node2.local_peer_id()); + node1_to_node2_open = false; + assert_eq!(peer, node2.local_peer_id()); + }, + future::Either::Right(NotificationEvent::NotificationStreamClosed { peer, .. }) => { + assert!(node2_to_node1_open); + node2_to_node1_open = false; + assert_eq!(peer, node1.local_peer_id()); + }, + future::Either::Left(NotificationEvent::NotificationReceived { peer, .. }) => { + assert!(node1_to_node2_open); + assert_eq!(peer, node2.local_peer_id()); if rand::random::() % 5 >= 4 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1 + .send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } }, - future::Either::Right(Event::NotificationsReceived { remote, .. }) => { + future::Either::Right(NotificationEvent::NotificationReceived { peer, .. }) => { assert!(node2_to_node1_open); - assert_eq!(remote, node1.local_peer_id()); + assert_eq!(peer, node1.local_peer_id()); if rand::random::() % 5 >= 4 { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2 + .send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } }, - - // Add new events here. - future::Either::Left(Event::Dht(_)) => {}, - future::Either::Right(Event::Dht(_)) => {}, }; } } @@ -444,20 +429,29 @@ async fn lots_of_incoming_peers_works() { sp_tracing::try_init_simple(); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (main_node, _) = TestNetworkBuilder::new() + let (main_node, handle1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) .with_set_config(config::SetConfig { in_peers: u32::MAX, ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle1 = handle1.unwrap(); + let (main_node, _) = main_node.start_network(); let main_node_peer_id = main_node.local_peer_id(); + tokio::spawn(async move { + while let Some(event) = handle1.next_event().await { + if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = event { + result_tx.send(ValidationResult::Accept).unwrap(); + } + } + }); + // We spawn background tasks and push them in this `Vec`. They will all be waited upon before // this test ends. let mut background_tasks_to_wait = Vec::new(); for _ in 0..32 { - let (_dialing_node, event_stream) = TestNetworkBuilder::new() + let (dialing_node, handle) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), @@ -465,8 +459,9 @@ async fn lots_of_incoming_peers_works() { }], ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle = handle.unwrap(); + let (_, _) = dialing_node.start_network(); background_tasks_to_wait.push(tokio::spawn(async move { // Create a dummy timer that will "never" fire, and that will be overwritten when we @@ -474,34 +469,23 @@ async fn lots_of_incoming_peers_works() { // make the code below way more complicated. let mut timer = futures_timer::Delay::new(Duration::from_secs(3600 * 24 * 7)).fuse(); - let mut event_stream = event_stream.fuse(); - let mut sync_protocol_name = None; loop { futures::select! { _ = timer => { // Test succeeds when timer fires. return; } - ev = event_stream.next() => { - match ev.unwrap() { - Event::NotificationStreamOpened { protocol, remote, .. } => { - if let None = sync_protocol_name { - sync_protocol_name = Some(protocol.clone()); - } - - assert_eq!(remote, main_node_peer_id); - // Test succeeds after 5 seconds. This timer is here in order to - // detect a potential problem after opening. - timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse(); - } - Event::NotificationStreamClosed { protocol, .. } => { - if Some(protocol) != sync_protocol_name { - // Test failed. - panic!(); - } - } - _ => {} + ev = handle.next_event().fuse() => match ev.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); } + NotificationEvent::NotificationStreamOpened { peer, .. } => { + assert_eq!(peer, main_node_peer_id); + // Test succeeds after 5 seconds. This timer is here in order to + // detect a potential problem after opening. + timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse(); + } + _ => {} } } } @@ -518,33 +502,27 @@ async fn notifications_back_pressure() { const TOTAL_NOTIFS: usize = 10_000; - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let (_node1, handle1, node2, handle2) = build_nodes_one_proto(); + let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap()); let node2_id = node2.local_peer_id(); let receiver = tokio::spawn(async move { let mut received_notifications = 0; - let mut sync_protocol_name = None; while received_notifications < TOTAL_NOTIFS { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, .. } => { - if let None = sync_protocol_name { - sync_protocol_name = Some(protocol); - } + match handle2.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); }, - Event::NotificationStreamClosed { protocol, .. } => { - if Some(&protocol) != sync_protocol_name.as_ref() { - panic!() - } + NotificationEvent::NotificationReceived { notification, .. } => { + assert_eq!( + notification, + format!("hello #{}", received_notifications).into_bytes() + ); + received_notifications += 1; }, - Event::NotificationsReceived { messages, .. } => - for message in messages { - assert_eq!(message.0, PROTOCOL_NAME.into()); - assert_eq!(message.1, format!("hello #{}", received_notifications)); - received_notifications += 1; - }, _ => {}, - }; + } if rand::random::() < 2 { tokio::time::sleep(Duration::from_millis(rand::random::() % 750)).await; @@ -554,20 +532,20 @@ async fn notifications_back_pressure() { // Wait for the `NotificationStreamOpened`. loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, + match handle1.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { .. } => break, _ => {}, }; } // Sending! for num in 0..TOTAL_NOTIFS { - let notif = node1.notification_sender(node2_id, PROTOCOL_NAME.into()).unwrap(); - notif - .ready() + handle1 + .send_async_notification(&node2_id, format!("hello #{}", num).into_bytes()) .await - .unwrap() - .send(format!("hello #{}", num).into_bytes()) .unwrap(); } @@ -576,28 +554,31 @@ async fn notifications_back_pressure() { #[tokio::test] async fn fallback_name_working() { + sp_tracing::try_init_simple(); // Node 1 supports the protocols "new" and "old". Node 2 only supports "old". Checks whether // they can connect. const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME"; let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, mut events_stream1) = TestNetworkBuilder::new() - .with_notification_protocol(config::NonDefaultSetConfig { - notifications_protocol: NEW_PROTOCOL_NAME.into(), - fallback_names: vec![PROTOCOL_NAME.into()], - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }) + let (config, mut handle1) = config::NonDefaultSetConfig::new( + NEW_PROTOCOL_NAME.into(), + vec![PROTOCOL_NAME.into()], + 1024 * 1024, + None, + Default::default(), + ); + let (network1, _) = TestNetworkBuilder::new() + .with_notification_protocol(config) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }) - .build() - .start_network(); + .build(); - let (_, mut events_stream2) = TestNetworkBuilder::new() + let (node1, _) = network1.start_network(); + + let (network2, handle2) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -605,34 +586,38 @@ async fn fallback_name_working() { }], ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle2 = handle2.unwrap(); + let _ = network2.start_network(); let receiver = tokio::spawn(async move { // Wait for the `NotificationStreamOpened`. loop { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } => { - assert_eq!(protocol, PROTOCOL_NAME.into()); + match handle2.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => { assert_eq!(negotiated_fallback, None); break }, _ => {}, - }; + } } }); // Wait for the `NotificationStreamOpened`. loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } - if protocol == NEW_PROTOCOL_NAME.into() => - { + match handle1.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => { assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into())); break }, _ => {}, - }; + } } receiver.await.unwrap(); @@ -655,6 +640,7 @@ async fn ensure_listen_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -674,6 +660,7 @@ async fn ensure_listen_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -699,6 +686,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -723,6 +711,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -751,6 +740,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -778,6 +768,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -800,6 +791,7 @@ async fn ensure_public_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -821,5 +813,6 @@ async fn ensure_public_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } diff --git a/substrate/client/network/test/src/sync.rs b/substrate/client/network/test/src/sync.rs index 389177b4aaf..f2be662ada1 100644 --- a/substrate/client/network/test/src/sync.rs +++ b/substrate/client/network/test/src/sync.rs @@ -44,16 +44,16 @@ async fn sync_peers_works() { sp_tracing::try_init_simple(); let mut net = TestNet::new(3); - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - for peer in 0..3 { - if net.peer(peer).num_peers() != 2 { - return Poll::Pending - } - } - Poll::Ready(()) - }) - .await; + while net.peer(0).num_peers().await != 2 && + net.peer(1).num_peers().await != 2 && + net.peer(2).num_peers().await != 2 + { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + Poll::Ready(()) + }) + .await; + } } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -412,15 +412,13 @@ async fn can_sync_small_non_best_forks() { assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -465,6 +463,7 @@ async fn can_sync_forks_ahead_of_the_best_chain() { net.peer(1).push_blocks(1, false); net.run_until_connected().await; + // Peer 0 is on 2-block fork which is announced with is_best=false let fork_hash = net .peer(0) @@ -516,15 +515,13 @@ async fn can_sync_explicit_forks() { assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -613,15 +610,14 @@ async fn full_sync_requires_block_body() { net.peer(0).push_headers(1); // Wait for nodes to connect - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } + net.run_until_idle().await; assert_eq!(net.peer(1).client.info().best_number, 0); } @@ -917,18 +913,16 @@ async fn block_announce_data_is_propagated() { }); // Wait until peer 1 is connected to both nodes. - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(1).num_peers() == 2 && - net.peer(0).num_peers() == 1 && - net.peer(2).num_peers() == 1 - { + while net.peer(1).num_peers().await != 2 || + net.peer(0).num_peers().await != 1 || + net.peer(2).num_peers().await != 1 + { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; + }) + .await; + } let block_hash = net .peer(0) @@ -1010,7 +1004,7 @@ async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; net.peer(0).push_blocks(1, false); net.run_until_sync().await; - assert_eq!(1, net.peer(0).num_peers()); + assert_eq!(1, net.peer(0).num_peers().await); } let hashof10 = hashes[9]; diff --git a/substrate/client/network/transactions/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index 1b97d4b96c9..9758ea4c4fc 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -21,8 +21,8 @@ //! Usage: //! //! - Use [`TransactionsHandlerPrototype::new`] to create a prototype. -//! - Pass the return value of [`TransactionsHandlerPrototype::set_config`] to the network -//! configuration as an extra peers set. +//! - Pass the `NonDefaultSetConfig` returned from [`TransactionsHandlerPrototype::new`] to the +//! network configuration as an extra peers set. //! - Use [`TransactionsHandlerPrototype::build`] then [`TransactionsHandler::run`] to obtain a //! `Future` that processes transactions. @@ -37,7 +37,7 @@ use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, error, - event::Event, + service::traits::{NotificationEvent, NotificationService, ValidationResult}, types::ProtocolName, utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -115,8 +115,11 @@ impl Future for PendingTransaction { /// Prototype for a [`TransactionsHandler`]. pub struct TransactionsHandlerPrototype { + /// Name of the transaction protocol. protocol_name: ProtocolName, - fallback_protocol_names: Vec, + + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, } impl TransactionsHandlerPrototype { @@ -125,35 +128,28 @@ impl TransactionsHandlerPrototype { protocol_id: ProtocolId, genesis_hash: Hash, fork_id: Option<&str>, - ) -> Self { + ) -> (Self, NonDefaultSetConfig) { let genesis_hash = genesis_hash.as_ref(); - let protocol_name = if let Some(fork_id) = fork_id { + let protocol_name: ProtocolName = if let Some(fork_id) = fork_id { format!("/{}/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { format!("/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash)) - }; - let legacy_protocol_name = format!("/{}/transactions/1", protocol_id.as_ref()); - - Self { - protocol_name: protocol_name.into(), - fallback_protocol_names: iter::once(legacy_protocol_name.into()).collect(), } - } - - /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> NonDefaultSetConfig { - NonDefaultSetConfig { - notifications_protocol: self.protocol_name.clone(), - fallback_names: self.fallback_protocol_names.clone(), - max_notification_size: MAX_TRANSACTIONS_SIZE, - handshake: None, - set_config: SetConfig { + .into(); + let (config, notification_service) = NonDefaultSetConfig::new( + protocol_name.clone(), + vec![format!("/{}/transactions/1", protocol_id.as_ref()).into()], + MAX_TRANSACTIONS_SIZE, + None, + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ); + + (Self { protocol_name, notification_service }, config) } /// Turns the prototype into the actual handler. Returns a controller that allows controlling @@ -173,12 +169,12 @@ impl TransactionsHandlerPrototype { transaction_pool: Arc>, metrics_registry: Option<&Registry>, ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { - let net_event_stream = network.event_stream("transactions-handler-net"); let sync_event_stream = sync.event_stream("transactions-handler-sync"); let (to_handler, from_controller) = tracing_unbounded("mpsc_transactions_handler", 100_000); let handler = TransactionsHandler { protocol_name: self.protocol_name, + notification_service: self.notification_service, propagate_timeout: (Box::pin(interval(PROPAGATE_TIMEOUT)) as Pin + Send>>) .fuse(), @@ -186,7 +182,6 @@ impl TransactionsHandlerPrototype { pending_transactions_peers: HashMap::new(), network, sync, - net_event_stream: net_event_stream.fuse(), sync_event_stream: sync_event_stream.fuse(), peers: HashMap::new(), transaction_pool, @@ -253,8 +248,6 @@ pub struct TransactionsHandler< network: N, /// Syncing service. sync: S, - /// Stream of networking events. - net_event_stream: stream::Fuse + Send>>>, /// Receiver for syncing-related events. sync_event_stream: stream::Fuse + Send>>>, // All connected peers @@ -263,6 +256,8 @@ pub struct TransactionsHandler< from_controller: TracingUnboundedReceiver>, /// Prometheus metrics. metrics: Option, + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, } /// Peer information @@ -295,14 +290,6 @@ where warn!(target: "sub-libp2p", "Inconsistent state, no peers for pending transaction!"); } }, - network_event = self.net_event_stream.next() => { - if let Some(network_event) = network_event { - self.handle_network_event(network_event).await; - } else { - // Networking has seemingly closed. Closing as well. - return; - } - }, sync_event = self.sync_event_stream.next() => { if let Some(sync_event) = sync_event { self.handle_sync_event(sync_event); @@ -317,10 +304,61 @@ where ToHandler::PropagateTransactions => self.propagate_transactions(), } }, + event = self.notification_service.next_event().fuse() => { + if let Some(event) = event { + self.handle_notification_event(event) + } else { + // `Notifications` has seemingly closed. Closing as well. + return + } + } } } } + fn handle_notification_event(&mut self, event: NotificationEvent) { + match event { + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); + }, + NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { + let Some(role) = self.network.peer_role(peer, handshake) else { + log::debug!(target: "sub-libp2p", "role for {peer} couldn't be determined"); + return + }; + + let _was_in = self.peers.insert( + peer, + Peer { + known_transactions: LruHashSet::new( + NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS).expect("Constant is nonzero"), + ), + role, + }, + ); + debug_assert!(_was_in.is_none()); + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let _peer = self.peers.remove(&peer); + debug_assert!(_peer.is_some()); + }, + NotificationEvent::NotificationReceived { peer, notification } => { + if let Ok(m) = + as Decode>::decode(&mut notification.as_ref()) + { + self.on_transactions(peer, m); + } else { + warn!(target: "sub-libp2p", "Failed to decode transactions list"); + } + }, + } + } + fn handle_sync_event(&mut self, event: SyncEvent) { match event { SyncEvent::PeerConnected(remote) => { @@ -346,51 +384,6 @@ where } } - async fn handle_network_event(&mut self, event: Event) { - match event { - Event::Dht(_) => {}, - Event::NotificationStreamOpened { remote, protocol, role, .. } - if protocol == self.protocol_name => - { - let _was_in = self.peers.insert( - remote, - Peer { - known_transactions: LruHashSet::new( - NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS).expect("Constant is nonzero"), - ), - role, - }, - ); - debug_assert!(_was_in.is_none()); - }, - Event::NotificationStreamClosed { remote, protocol } - if protocol == self.protocol_name => - { - let _peer = self.peers.remove(&remote); - debug_assert!(_peer.is_some()); - }, - - Event::NotificationsReceived { remote, messages } => { - for (protocol, message) in messages { - if protocol != self.protocol_name { - continue - } - - if let Ok(m) = - as Decode>::decode(&mut message.as_ref()) - { - self.on_transactions(remote, m); - } else { - warn!(target: "sub-libp2p", "Failed to decode transactions list"); - } - } - }, - - // Not our concern. - Event::NotificationStreamOpened { .. } | Event::NotificationStreamClosed { .. } => {}, - } - } - /// Called when peer sends us new transactions fn on_transactions(&mut self, who: PeerId, transactions: Transactions) { // Accept transactions only when node is not major syncing @@ -482,8 +475,7 @@ where propagated_to.entry(hash).or_default().push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - self.network - .write_notification(*who, self.protocol_name.clone(), to_send.encode()); + let _ = self.notification_service.send_sync_notification(who, to_send.encode()); } } diff --git a/substrate/client/offchain/src/api.rs b/substrate/client/offchain/src/api.rs index c7df5784d32..2901bab2f26 100644 --- a/substrate/client/offchain/src/api.rs +++ b/substrate/client/offchain/src/api.rs @@ -223,7 +223,7 @@ mod tests { use sc_client_db::offchain::LocalStorage; use sc_network::{ config::MultiaddrWithPeerId, types::ProtocolName, NetworkPeers, NetworkStateInfo, - ReputationChange, + ObservedRole, ReputationChange, }; use sp_core::offchain::{storage::OffchainDb, DbExternalities, Externalities, StorageKind}; use std::time::SystemTime; @@ -294,6 +294,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } impl NetworkStateInfo for TestNetwork { diff --git a/substrate/client/offchain/src/lib.rs b/substrate/client/offchain/src/lib.rs index 756ab77ff94..8bcfa66a5af 100644 --- a/substrate/client/offchain/src/lib.rs +++ b/substrate/client/offchain/src/lib.rs @@ -330,7 +330,9 @@ mod tests { use libp2p::{Multiaddr, PeerId}; use sc_block_builder::BlockBuilderBuilder; use sc_client_api::Backend as _; - use sc_network::{config::MultiaddrWithPeerId, types::ProtocolName, ReputationChange}; + use sc_network::{ + config::MultiaddrWithPeerId, types::ProtocolName, ObservedRole, ReputationChange, + }; use sc_transaction_pool::BasicPool; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; @@ -423,6 +425,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } #[test] diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 25f998385ba..d078f44f198 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -753,6 +753,11 @@ where } let protocol_id = config.protocol_id(); + let genesis_hash = client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"); let block_announce_validator = if let Some(f) = block_announce_validator_builder { f(client.clone()) @@ -802,11 +807,7 @@ where // Allow both outgoing and incoming requests. let (handler, protocol_config) = WarpSyncRequestHandler::new( protocol_id.clone(), - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), + genesis_hash, config.chain_spec.fork_id(), warp_with_provider.clone(), ); @@ -845,17 +846,13 @@ where } // create transactions protocol and add it to the list of supported protocols of - // `network_params` - let transactions_handler_proto = sc_network_transactions::TransactionsHandlerPrototype::new( - protocol_id.clone(), - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - config.chain_spec.fork_id(), - ); - net_config.add_notification_protocol(transactions_handler_proto.set_config()); + let (transactions_handler_proto, transactions_config) = + sc_network_transactions::TransactionsHandlerPrototype::new( + protocol_id.clone(), + genesis_hash, + config.chain_spec.fork_id(), + ); + net_config.add_notification_protocol(transactions_config); // Create `PeerStore` and initialize it with bootnode peer ids. let peer_store = PeerStore::new( @@ -869,7 +866,6 @@ where let peer_store_handle = peer_store.handle(); spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config.role), client.clone(), @@ -884,7 +880,7 @@ where block_downloader, state_request_protocol_name, warp_request_protocol_name, - rx, + peer_store_handle.clone(), )?; let sync_service_import_queue = sync_service.clone(); let sync_service = Arc::new(sync_service); @@ -905,7 +901,6 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, - tx, }; let has_bootnodes = !network_params.network_config.network_config.boot_nodes.is_empty(); diff --git a/substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat b/substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat index ab678906648..e6d6ba8bb81 100644 --- a/substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat +++ b/substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat @@ -14,7 +14,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat b/substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat index ef456b6d620..dac7736244d 100644 --- a/substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat +++ b/substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat @@ -16,7 +16,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -44,8 +44,8 @@ ;; [0..4) - size of the call ;; [4..8) - action to perform ;; [8..42) - code hash of the callee - (set_local $action (i32.load (i32.const 4))) - (set_local $code_hash_ptr (i32.const 8)) + (local.set $action (i32.load (i32.const 4))) + (local.set $code_hash_ptr (i32.const 8)) ;; Assert input size == 36 (4 for action + 32 for code_hash). (call $assert @@ -56,25 +56,25 @@ ) ;; Call add_delegate_dependency when action == 1. - (if (i32.eq (get_local $action) (i32.const 1)) + (if (i32.eq (local.get $action) (i32.const 1)) (then - (call $add_delegate_dependency (get_local $code_hash_ptr)) + (call $add_delegate_dependency (local.get $code_hash_ptr)) ) (else) ) ;; Call remove_delegate_dependency when action == 2. - (if (i32.eq (get_local $action) (i32.const 2)) + (if (i32.eq (local.get $action) (i32.const 2)) (then (call $remove_delegate_dependency - (get_local $code_hash_ptr) + (local.get $code_hash_ptr) ) ) (else) ) ;; Call terminate when action == 3. - (if (i32.eq (get_local $action) (i32.const 3)) + (if (i32.eq (local.get $action) (i32.const 3)) (then (call $terminate (i32.const 100) ;; Pointer to beneficiary address diff --git a/substrate/frame/contracts/fixtures/data/balance.wat b/substrate/frame/contracts/fixtures/data/balance.wat index d86d5c4b1c6..d7970c92e41 100644 --- a/substrate/frame/contracts/fixtures/data/balance.wat +++ b/substrate/frame/contracts/fixtures/data/balance.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/call.wat b/substrate/frame/contracts/fixtures/data/call.wat index 4558b2c6409..43b32049c88 100644 --- a/substrate/frame/contracts/fixtures/data/call.wat +++ b/substrate/frame/contracts/fixtures/data/call.wat @@ -7,7 +7,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat b/substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat index 3320922d9e2..5d76e19a74c 100644 --- a/substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat +++ b/substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat @@ -7,7 +7,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/data/caller_contract.wat b/substrate/frame/contracts/fixtures/data/caller_contract.wat index 929171b9a26..43eb8ccfd54 100644 --- a/substrate/frame/contracts/fixtures/data/caller_contract.wat +++ b/substrate/frame/contracts/fixtures/data/caller_contract.wat @@ -10,7 +10,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -37,10 +37,10 @@ ) ;; Read current balance into local variable. - (set_local $sp (i32.const 1024)) + (local.set $sp (i32.const 1024)) ;; Fail to deploy the contract since it returns a non-zero exit status. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -60,11 +60,11 @@ ;; Check non-zero exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted + (i32.eq (local.get $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) ;; Fail to deploy the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 1) ;; Supply too little ref_time weight @@ -85,11 +85,11 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Fail to deploy the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -110,17 +110,17 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 256) ) ;; Deploy the contract successfully. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -130,7 +130,7 @@ (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer (i32.const 16) ;; Pointer to the address output buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Pointer to the address buffer length + (i32.sub (local.get $sp) (i32.const 4)) ;; Pointer to the address buffer length (i32.const 4294967295) ;; u32 max sentinel value: do not copy output (i32.const 0) ;; Length is ignored in this case (i32.const 0) ;; salt_ptr @@ -141,28 +141,28 @@ ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; Check that address has the expected length (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 4))) (i32.const 32)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 32)) ) ;; Zero out destination buffer of output (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 0) ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 8)) + (i32.sub (local.get $sp) (i32.const 8)) (i32.const 4) ) ;; Call the new contract and expect it to return failing exit code. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -172,29 +172,29 @@ (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 9) ;; Pointer to input data buffer address (i32.const 7) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (local.get $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (local.get $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) ;; Check non-zero exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted + (i32.eq (local.get $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) ;; Check that output buffer contains the expected return data. (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 3)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 8))) (i32.const 3)) ) (call $assert (i32.eq - (i32.load (i32.sub (get_local $sp) (i32.const 4))) + (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 0x00776655) ) ) ;; Fail to call the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -211,11 +211,11 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Fail to call the contract due to insufficient proof_size weight. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -232,23 +232,23 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Zero out destination buffer of output (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 0) ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 8)) + (i32.sub (local.get $sp) (i32.const 8)) (i32.const 4) ) ;; Call the contract successfully. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -258,23 +258,23 @@ (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (local.get $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (local.get $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; Check that the output buffer contains the expected return data. (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 4)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 8))) (i32.const 4)) ) (call $assert (i32.eq - (i32.load (i32.sub (get_local $sp) (i32.const 4))) + (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 0x77665544) ) ) diff --git a/substrate/frame/contracts/fixtures/data/chain_extension.wat b/substrate/frame/contracts/fixtures/data/chain_extension.wat index 670f8e70172..c24ca286ff8 100644 --- a/substrate/frame/contracts/fixtures/data/chain_extension.wat +++ b/substrate/frame/contracts/fixtures/data/chain_extension.wat @@ -9,7 +9,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat b/substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat index b481abb5bc7..504646df1b0 100644 --- a/substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat +++ b/substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat @@ -11,7 +11,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/data/create_storage_and_call.wat b/substrate/frame/contracts/fixtures/data/create_storage_and_call.wat index 5592e7e96a9..2bff53b638f 100644 --- a/substrate/frame/contracts/fixtures/data/create_storage_and_call.wat +++ b/substrate/frame/contracts/fixtures/data/create_storage_and_call.wat @@ -8,7 +8,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat b/substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat index cd720247843..00c9a657f39 100644 --- a/substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat +++ b/substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat @@ -14,7 +14,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/crypto_hashes.wat b/substrate/frame/contracts/fixtures/data/crypto_hashes.wat index c2b4d6b81ed..9d86b02f419 100644 --- a/substrate/frame/contracts/fixtures/data/crypto_hashes.wat +++ b/substrate/frame/contracts/fixtures/data/crypto_hashes.wat @@ -59,8 +59,10 @@ (call $seal_input (local.get $input_ptr) (local.get $input_len_ptr)) (local.set $chosen_hash_fn (i32.load8_u (local.get $input_ptr))) (if (i32.gt_u (local.get $chosen_hash_fn) (i32.const 7)) - ;; We check that the chosen hash fn identifier is within bounds: [0,7] - (unreachable) + (then + ;; We check that the chosen hash fn identifier is within bounds: [0,7] + (unreachable) + ) ) (local.set $input_ptr (i32.add (local.get $input_ptr) (i32.const 1))) (local.set $input_len (i32.sub (i32.load (local.get $input_len_ptr)) (i32.const 1))) diff --git a/substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat b/substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat index e8c447b42fc..dae0de88418 100644 --- a/substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat +++ b/substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat b/substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat index fc6ee72df8b..e9ce20ba42b 100644 --- a/substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat +++ b/substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/debug_message_works.wat b/substrate/frame/contracts/fixtures/data/debug_message_works.wat index 61933c23296..44a7b6db1be 100644 --- a/substrate/frame/contracts/fixtures/data/debug_message_works.wat +++ b/substrate/frame/contracts/fixtures/data/debug_message_works.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/delegate_call.wat b/substrate/frame/contracts/fixtures/data/delegate_call.wat index 7fe422af455..b8d4f0d47f0 100644 --- a/substrate/frame/contracts/fixtures/data/delegate_call.wat +++ b/substrate/frame/contracts/fixtures/data/delegate_call.wat @@ -24,7 +24,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -70,7 +70,7 @@ ) ;; Call deployed library contract code. - (set_local $exit_code + (local.set $exit_code (call $seal_delegate_call (i32.const 0) ;; Set no call flags (i32.const 64) ;; Pointer to "callee" code_hash. @@ -83,7 +83,7 @@ ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) (call $assert diff --git a/substrate/frame/contracts/fixtures/data/delegate_call_lib.wat b/substrate/frame/contracts/fixtures/data/delegate_call_lib.wat index 340b9699f87..62eea32800a 100644 --- a/substrate/frame/contracts/fixtures/data/delegate_call_lib.wat +++ b/substrate/frame/contracts/fixtures/data/delegate_call_lib.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/delegate_call_simple.wat b/substrate/frame/contracts/fixtures/data/delegate_call_simple.wat index 24ae5a13e33..ba0a8fcc8ae 100644 --- a/substrate/frame/contracts/fixtures/data/delegate_call_simple.wat +++ b/substrate/frame/contracts/fixtures/data/delegate_call_simple.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat b/substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat index 25554795552..2afd3b2fbac 100644 --- a/substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat +++ b/substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat @@ -33,7 +33,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/drain.wat b/substrate/frame/contracts/fixtures/data/drain.wat index cb8ff0aed61..18a21cca803 100644 --- a/substrate/frame/contracts/fixtures/data/drain.wat +++ b/substrate/frame/contracts/fixtures/data/drain.wat @@ -19,7 +19,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/ecdsa_recover.wat b/substrate/frame/contracts/fixtures/data/ecdsa_recover.wat index d694b3215e8..4910e706069 100644 --- a/substrate/frame/contracts/fixtures/data/ecdsa_recover.wat +++ b/substrate/frame/contracts/fixtures/data/ecdsa_recover.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/event_size.wat b/substrate/frame/contracts/fixtures/data/event_size.wat index 4bd6158d72f..1c1f34b24d7 100644 --- a/substrate/frame/contracts/fixtures/data/event_size.wat +++ b/substrate/frame/contracts/fixtures/data/event_size.wat @@ -9,7 +9,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/multi_store.wat b/substrate/frame/contracts/fixtures/data/multi_store.wat index 2592baf6183..c334ed54c4e 100644 --- a/substrate/frame/contracts/fixtures/data/multi_store.wat +++ b/substrate/frame/contracts/fixtures/data/multi_store.wat @@ -19,7 +19,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/reentrance_count_call.wat b/substrate/frame/contracts/fixtures/data/reentrance_count_call.wat index c6b529e2aff..44db8d041b1 100644 --- a/substrate/frame/contracts/fixtures/data/reentrance_count_call.wat +++ b/substrate/frame/contracts/fixtures/data/reentrance_count_call.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -36,11 +36,11 @@ (call $seal_input (i32.const 32) (i32.const 36)) ;; reading manually passed reentrant count - (set_local $expected_reentrance_count (i32.load (i32.const 32))) + (local.set $expected_reentrance_count (i32.load (i32.const 32))) ;; reentrance count is calculated correctly (call $assert - (i32.eq (call $reentrance_count) (get_local $expected_reentrance_count)) + (i32.eq (call $reentrance_count) (local.get $expected_reentrance_count)) ) ;; re-enter 5 times in a row and assert that the reentrant counter works as expected @@ -52,7 +52,7 @@ (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) ;; Call to itself - (set_local $seal_call_exit_code + (local.set $seal_call_exit_code (call $seal_call (i32.const 8) ;; Allow reentrancy flag set (i32.const 0) ;; Pointer to "callee" address @@ -66,7 +66,7 @@ ) (call $assert - (i32.eq (get_local $seal_call_exit_code) (i32.const 0)) + (i32.eq (local.get $seal_call_exit_code) (i32.const 0)) ) ) ) diff --git a/substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat b/substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat index b8219a8462e..49e0193bcdb 100644 --- a/substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat +++ b/substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat @@ -17,7 +17,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -30,7 +30,7 @@ (call $seal_input (i32.const 0) (i32.const 36)) ;; reading passed callstack height - (set_local $callstack_height (i32.load (i32.const 32))) + (local.set $callstack_height (i32.load (i32.const 32))) ;; incrementing callstack height (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) @@ -40,12 +40,12 @@ (i32.eq (call $reentrance_count) (i32.const 0)) ) - (i32.eq (get_local $callstack_height) (i32.const 5)) + (i32.eq (local.get $callstack_height) (i32.const 5)) (if (then) ;; exit recursion case (else ;; Call to itself - (set_local $delegate_call_exit_code + (local.set $delegate_call_exit_code (call $seal_delegate_call (i32.const 0) ;; Set no call flags (i32.const 0) ;; Pointer to "callee" code_hash. @@ -57,13 +57,13 @@ ) (call $assert - (i32.eq (get_local $delegate_call_exit_code) (i32.const 0)) + (i32.eq (local.get $delegate_call_exit_code) (i32.const 0)) ) ) ) (call $assert - (i32.le_s (get_local $callstack_height) (i32.const 5)) + (i32.le_s (local.get $callstack_height) (i32.const 5)) ) ) diff --git a/substrate/frame/contracts/fixtures/data/self_destruct.wat b/substrate/frame/contracts/fixtures/data/self_destruct.wat index b8a37306e20..00c3895fdde 100644 --- a/substrate/frame/contracts/fixtures/data/self_destruct.wat +++ b/substrate/frame/contracts/fixtures/data/self_destruct.wat @@ -26,7 +26,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat b/substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat index 85fce511e21..628f283a19f 100644 --- a/substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat +++ b/substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat @@ -5,7 +5,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/set_code_hash.wat b/substrate/frame/contracts/fixtures/data/set_code_hash.wat index b4df1b13318..c0a9557b4d0 100644 --- a/substrate/frame/contracts/fixtures/data/set_code_hash.wat +++ b/substrate/frame/contracts/fixtures/data/set_code_hash.wat @@ -16,7 +16,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -27,11 +27,11 @@ (call $seal_input (i32.const 0) (i32.const 32)) - (set_local $exit_code + (local.set $exit_code (call $seal_set_code_hash (i32.const 0)) ;; Pointer to the input data. ) (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; we return 1 after setting new code_hash diff --git a/substrate/frame/contracts/fixtures/data/storage_size.wat b/substrate/frame/contracts/fixtures/data/storage_size.wat index 293a656d4f6..728bb4fcf3c 100644 --- a/substrate/frame/contracts/fixtures/data/storage_size.wat +++ b/substrate/frame/contracts/fixtures/data/storage_size.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/store_call.wat b/substrate/frame/contracts/fixtures/data/store_call.wat index 9e090d31801..746b7a48b55 100644 --- a/substrate/frame/contracts/fixtures/data/store_call.wat +++ b/substrate/frame/contracts/fixtures/data/store_call.wat @@ -15,7 +15,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/store_deploy.wat b/substrate/frame/contracts/fixtures/data/store_deploy.wat index cc428e9623b..7f115cba977 100644 --- a/substrate/frame/contracts/fixtures/data/store_deploy.wat +++ b/substrate/frame/contracts/fixtures/data/store_deploy.wat @@ -15,7 +15,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/xcm_execute.wat b/substrate/frame/contracts/fixtures/data/xcm_execute.wat index b3459996a2e..72ef14ed82c 100644 --- a/substrate/frame/contracts/fixtures/data/xcm_execute.wat +++ b/substrate/frame/contracts/fixtures/data/xcm_execute.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/xcm_send.wat b/substrate/frame/contracts/fixtures/data/xcm_send.wat index 9eec6388de9..fe29ddf0f14 100644 --- a/substrate/frame/contracts/fixtures/data/xcm_send.wat +++ b/substrate/frame/contracts/fixtures/data/xcm_send.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 77e94b16777..f73655e9920 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -1506,7 +1506,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1531,7 +1531,7 @@ mod tests { ) ;; Find out the size of the buffer - (set_local $buf_size + (local.set $buf_size (i32.load (i32.const 32)) ) @@ -1539,7 +1539,7 @@ mod tests { (call $seal_return (i32.const 0) (i32.const 36) - (get_local $buf_size) + (local.get $buf_size) ) ;; env:seal_return doesn't return, so this is effectively unreachable. @@ -1575,7 +1575,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1633,7 +1633,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1680,7 +1680,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1726,7 +1726,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1773,7 +1773,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1836,7 +1836,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1925,7 +1925,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1966,7 +1966,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2013,7 +2013,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2067,7 +2067,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2137,7 +2137,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2327,7 +2327,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2995,7 +2995,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -3047,7 +3047,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -3162,18 +3162,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $exit_code i32) - (set_local $exit_code + (local.set $exit_code (call $seal_set_code_hash (i32.const 0)) ) (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ) @@ -3202,18 +3202,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $return_val i32) - (set_local $return_val + (local.set $return_val (call $reentrance_count) ) (call $assert - (i32.eq (get_local $return_val) (i32.const 12)) + (i32.eq (local.get $return_val) (i32.const 12)) ) ) @@ -3234,18 +3234,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $return_val i32) - (set_local $return_val + (local.set $return_val (call $account_reentrance_count (i32.const 0)) ) (call $assert - (i32.eq (get_local $return_val) (i32.const 12)) + (i32.eq (local.get $return_val) (i32.const 12)) ) ) @@ -3267,7 +3267,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) -- GitLab From aada961da9400d6f1e1fcccecd5aac627dd230c4 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:07:40 +0100 Subject: [PATCH 605/633] [ci] Run gitspiegel trigger with merge conflicts (#2531) Currently gitspiegel trigger won't run if there is merge conflict. This PR fixes it. close https://github.com/paritytech/gitspiegel/issues/183 --- .github/workflows/gitspiegel-trigger.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/gitspiegel-trigger.yml b/.github/workflows/gitspiegel-trigger.yml index 59347fad6d6..b338f7a3f62 100644 --- a/.github/workflows/gitspiegel-trigger.yml +++ b/.github/workflows/gitspiegel-trigger.yml @@ -13,8 +13,19 @@ on: - unlocked - ready_for_review - reopened + # the job doesn't check out any code, so it is relatively safe to run it on any event + pull_request_target: + types: + - opened + - synchronize + - unlocked + - ready_for_review + - reopened merge_group: +# drop all permissions for GITHUB_TOKEN +permissions: {} + jobs: sync: runs-on: ubuntu-latest -- GitLab From 820179348c1c56bbe00236be6115a7bab451d1fd Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 28 Nov 2023 23:13:36 +0100 Subject: [PATCH 606/633] Remove long deprecated `AllPalletsWithoutSystemReversed` (#2509) Remove deprecated `AllPalletsXY` types. They have been deprecated for nearly 1.5 years now, I think its fine to remove them. If anyone feels like we should first put a date on the deprecation as stated in the deprecation guideline, feel free to speak up. To me it looks like this has been forgotten and can be directly removed. --- substrate/frame/executive/README.md | 6 +- .../procedural/src/construct_runtime/mod.rs | 54 -------- substrate/frame/support/test/tests/pallet.rs | 117 ------------------ 3 files changed, 2 insertions(+), 175 deletions(-) diff --git a/substrate/frame/executive/README.md b/substrate/frame/executive/README.md index 96a412a4537..6151232ecaf 100644 --- a/substrate/frame/executive/README.md +++ b/substrate/frame/executive/README.md @@ -34,14 +34,13 @@ The default Substrate node template declares the `Executive` type declaration from the node template. ```rust -# /// Executive: handles dispatch to the various modules. pub type Executive = executive::Executive< Runtime, Block, Context, Runtime, - AllPallets, + AllPalletsWithSystem, >; ``` @@ -51,7 +50,6 @@ You can add custom logic that should be called in your runtime on a runtime upgr generic parameter. The custom logic will be called before the on runtime upgrade logic of all modules is called. ```rust -# struct CustomOnRuntimeUpgrade; impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade { fn on_runtime_upgrade() -> frame_support::weights::Weight { @@ -65,7 +63,7 @@ pub type Executive = executive::Executive< Block, Context, Runtime, - AllPallets, + AllPalletsWithSystem, CustomOnRuntimeUpgrade, >; ``` diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index ce34694275b..d1d6040d33a 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -600,66 +600,12 @@ fn decl_all_pallets<'a>( } }); - let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| { - let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// Excludes the System pallet. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); - } - }); - - let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| { - let names = names.iter().rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithSystemReversed = ( #(#names,)* ); - } - }); - - let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| { - let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME); - let names = std::iter::once(&system) - .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned()); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// With the system pallet first. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); - } - }); - quote!( #types - /// All pallets included in the runtime as a nested tuple of types. - #[deprecated(note = "The type definition has changed from representing all pallets \ - excluding system, in reversed order to become the representation of all pallets \ - including system pallet in regular order. For this reason it is encouraged to use \ - explicitly one of `AllPalletsWithSystem`, `AllPalletsWithoutSystem`, \ - `AllPalletsWithSystemReversed`, `AllPalletsWithoutSystemReversed`. \ - Note that the type `frame_executive::Executive` expects one of `AllPalletsWithSystem` \ - , `AllPalletsWithSystemReversed`, `AllPalletsReversedWithSystemFirst`. More details in \ - https://github.com/paritytech/substrate/pull/10043")] - pub type AllPallets = AllPalletsWithSystem; - #( #all_pallets_with_system )* #( #all_pallets_without_system )* - - #( #all_pallets_with_system_reversed )* - - #( #all_pallets_without_system_reversed )* - - #( #all_pallets_reversed_with_system_first )* ) } fn decl_pallet_runtime_setup( diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 1afb8fdf497..d2e5b185163 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -1271,52 +1271,6 @@ fn pallet_hooks_expand() { }) } -#[test] -fn all_pallets_type_reversed_order_is_correct() { - TestExternalities::default().execute_with(|| { - frame_system::Pallet::::set_block_number(1); - - #[allow(deprecated)] - { - assert_eq!( - AllPalletsWithoutSystemReversed::on_initialize(1), - Weight::from_parts(10, 0) - ); - AllPalletsWithoutSystemReversed::on_finalize(1); - - assert_eq!( - AllPalletsWithoutSystemReversed::on_runtime_upgrade(), - Weight::from_parts(30, 0) - ); - } - - assert_eq!( - frame_system::Pallet::::events()[0].event, - RuntimeEvent::Example2(pallet2::Event::Something(11)), - ); - assert_eq!( - frame_system::Pallet::::events()[1].event, - RuntimeEvent::Example(pallet::Event::Something(10)), - ); - assert_eq!( - frame_system::Pallet::::events()[2].event, - RuntimeEvent::Example2(pallet2::Event::Something(21)), - ); - assert_eq!( - frame_system::Pallet::::events()[3].event, - RuntimeEvent::Example(pallet::Event::Something(20)), - ); - assert_eq!( - frame_system::Pallet::::events()[4].event, - RuntimeEvent::Example2(pallet2::Event::Something(31)), - ); - assert_eq!( - frame_system::Pallet::::events()[5].event, - RuntimeEvent::Example(pallet::Event::Something(30)), - ); - }) -} - #[test] fn pallet_on_genesis() { TestExternalities::default().execute_with(|| { @@ -2186,31 +2140,6 @@ fn test_storage_info() { ); } -#[test] -fn assert_type_all_pallets_reversed_with_system_first_is_correct() { - // Just ensure the 2 types are same. - #[allow(deprecated)] - fn _a(_t: AllPalletsReversedWithSystemFirst) {} - #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] - fn _b(t: (System, Example4, Example2, Example)) { - _a(t) - } - #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] - fn _b(t: (System, Example4, Example3, Example2, Example)) { - _a(t) - } - - #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] - fn _b(t: (System, Example5, Example4, Example2, Example)) { - _a(t) - } - - #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] - fn _b(t: (System, Example5, Example4, Example3, Example2, Example)) { - _a(t) - } -} - #[test] fn assert_type_all_pallets_with_system_is_correct() { // Just ensure the 2 types are same. @@ -2255,52 +2184,6 @@ fn assert_type_all_pallets_without_system_is_correct() { } } -#[test] -fn assert_type_all_pallets_with_system_reversed_is_correct() { - // Just ensure the 2 types are same. - #[allow(deprecated)] - fn _a(_t: AllPalletsWithSystemReversed) {} - #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] - fn _b(t: (Example4, Example2, Example, System)) { - _a(t) - } - #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] - fn _b(t: (Example4, Example3, Example2, Example, System)) { - _a(t) - } - #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] - fn _b(t: (Example5, Example4, Example2, Example, System)) { - _a(t) - } - #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] - fn _b(t: (Example5, Example4, Example3, Example2, Example, System)) { - _a(t) - } -} - -#[test] -fn assert_type_all_pallets_without_system_reversed_is_correct() { - // Just ensure the 2 types are same. - #[allow(deprecated)] - fn _a(_t: AllPalletsWithoutSystemReversed) {} - #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] - fn _b(t: (Example4, Example2, Example)) { - _a(t) - } - #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] - fn _b(t: (Example4, Example3, Example2, Example)) { - _a(t) - } - #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] - fn _b(t: (Example5, Example4, Example2, Example)) { - _a(t) - } - #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] - fn _b(t: (Example5, Example4, Example3, Example2, Example)) { - _a(t) - } -} - #[test] fn test_storage_alias() { use frame_support::Twox64Concat; -- GitLab From a9aa2d1f1c7b73ddfa69f8fb61f3035d091018d2 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 29 Nov 2023 10:44:44 +0400 Subject: [PATCH 607/633] Remove `dmp_queue` pallet from Westend SP runtimes (#2516) Westend SP dmp queue pallet removal is complete. Screenshot 2023-11-28 at 08 31 27 Screenshot 2023-11-28 at 08 32 08 Screenshot 2023-11-28 at 08 31 45 --- Cargo.lock | 3 - .../assets/asset-hub-westend/Cargo.toml | 96 ++++++------- .../assets/asset-hub-westend/src/lib.rs | 8 -- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ------------------ .../asset-hub-westend/src/weights/mod.rs | 1 - .../bridge-hubs/bridge-hub-westend/Cargo.toml | 84 ++++++----- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 7 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ------------------ .../bridge-hub-westend/src/weights/mod.rs | 1 - .../collectives-westend/Cargo.toml | 8 +- .../collectives-westend/src/lib.rs | 8 -- .../src/weights/cumulus_pallet_dmp_queue.rs | 131 ------------------ .../collectives-westend/src/weights/mod.rs | 1 - 13 files changed, 87 insertions(+), 523 deletions(-) delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs diff --git a/Cargo.lock b/Cargo.lock index 4fa9e83a173..871d46ea844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1050,7 +1050,6 @@ dependencies = [ "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", @@ -2321,7 +2320,6 @@ dependencies = [ "bridge-hub-test-utils", "bridge-runtime-common", "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", @@ -2940,7 +2938,6 @@ name = "collectives-westend-runtime" version = "1.0.0" dependencies = [ "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 49b80b067cf..bc06c6fe9a1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -14,63 +14,62 @@ scale-info = { version = "2.10.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-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} +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-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-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} -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-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 } # 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 -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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} -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/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} +polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false } +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } +polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } +westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } +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 } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-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 } @@ -98,7 +97,6 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", default = [ "std" ] runtime-benchmarks = [ "assets-common/runtime-benchmarks", - "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", @@ -133,7 +131,6 @@ 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", @@ -172,7 +169,6 @@ std = [ "bp-bridge-hub-westend/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", 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 a0d5a528c3f..4eb3e2471ce 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -667,12 +667,6 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - parameter_types! { pub const Period: u32 = 6 * HOURS; pub const Offset: u32 = 0; @@ -890,7 +884,6 @@ construct_runtime!( 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, // Bridge utilities. ToRococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 34, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 35, @@ -1082,7 +1075,6 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 1646c00989d..2462138b04a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -14,7 +14,6 @@ // limitations under the License. pub mod block_weights; -pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 7e384126ab6..4d2e60d971d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -18,54 +18,53 @@ serde = { version = "1.0.188", optional = true, 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-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-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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} +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-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-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +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-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} -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-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 } +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 } # Polkadot -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} +westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/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} +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-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 } @@ -115,7 +114,6 @@ std = [ "bridge-runtime-common/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", @@ -177,7 +175,6 @@ std = [ runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", - "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", @@ -209,7 +206,6 @@ 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", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 764b9825d4e..7b8ea1b7734 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -393,12 +393,6 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; @@ -499,7 +493,6 @@ construct_runtime!( 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, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index 833944ebfa5..ee49c72ea5f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -21,7 +21,6 @@ use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; pub mod block_weights; -pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 79d6c697b5f..1801488eeed 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -72,10 +72,7 @@ westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/co # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-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 } @@ -96,7 +93,6 @@ sp-io = { path = "../../../../../substrate/primitives/io", features = ["std"] } [features] default = [ "std" ] runtime-benchmarks = [ - "cumulus-pallet-dmp-queue/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", @@ -133,7 +129,6 @@ 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", @@ -169,7 +164,6 @@ try-runtime = [ 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", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 54cb898fd6c..1017ac30499 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -456,12 +456,6 @@ parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; @@ -651,7 +645,6 @@ construct_runtime!( 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, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. @@ -740,7 +733,6 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] [pallet_alliance, Alliance] [pallet_collective, AllianceMotion] [pallet_xcm, PalletXcmExtrinsicsBenchmark::] diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index 1d877fdbd2b..d49a2905e7f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -14,7 +14,6 @@ // limitations under the License. pub mod block_weights; -pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; -- GitLab From 1d5d4a484021ede73152bf71af37718fa38bb72b Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Wed, 29 Nov 2023 14:46:10 +0800 Subject: [PATCH 608/633] Enable parallel key scraping (#1985) closes #174 --------- Co-authored-by: Liam Aharon Co-authored-by: Oliver Tale-Yazdi --- .../frame/remote-externalities/src/lib.rs | 193 ++++++++++++++---- 1 file changed, 156 insertions(+), 37 deletions(-) diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 71e9320ebee..5c7a36867ff 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -47,6 +47,7 @@ use std::{ fs, ops::{Deref, DerefMut}, path::{Path, PathBuf}, + sync::Arc, time::{Duration, Instant}, }; use substrate_rpc_client::{rpc_params, BatchRequestBuilder, ChainApi, ClientT, StateApi}; @@ -298,6 +299,7 @@ impl Default for SnapshotConfig { } /// Builder for remote-externalities. +#[derive(Clone)] pub struct Builder { /// Custom key-pairs to be injected into the final externalities. The *hashed* keys and values /// must be given. @@ -400,41 +402,134 @@ where }) } - /// Get all the keys at `prefix` at `hash` using the paged, safe RPC methods. - async fn rpc_get_keys_paged( + /// Get keys with `prefix` at `block` in a parallel manner. + async fn rpc_get_keys_parallel( &self, - prefix: StorageKey, - at: B::Hash, + prefix: &StorageKey, + block: B::Hash, + parallel: usize, + ) -> Result, &'static str> { + /// Divide the workload and return the start key of each chunks. Guaranteed to return a + /// non-empty list. + fn gen_start_keys(prefix: &StorageKey) -> Vec { + let mut prefix = prefix.as_ref().to_vec(); + let scale = 32usize.saturating_sub(prefix.len()); + + // no need to divide workload + if scale < 9 { + prefix.extend(vec![0; scale]); + return vec![StorageKey(prefix)] + } + + let chunks = 16; + let step = 0x10000 / chunks; + let ext = scale - 2; + + (0..chunks) + .map(|i| { + let mut key = prefix.clone(); + let start = i * step; + key.extend(vec![(start >> 8) as u8, (start & 0xff) as u8]); + key.extend(vec![0; ext]); + StorageKey(key) + }) + .collect() + } + + let start_keys = gen_start_keys(&prefix); + let start_keys: Vec> = start_keys.iter().map(Some).collect(); + let mut end_keys: Vec> = start_keys[1..].to_vec(); + end_keys.push(None); + + // use a semaphore to limit max scraping tasks + let parallel = Arc::new(tokio::sync::Semaphore::new(parallel)); + let builder = Arc::new(self.clone()); + let mut handles = vec![]; + + for (start_key, end_key) in start_keys.into_iter().zip(end_keys) { + let permit = parallel + .clone() + .acquire_owned() + .await + .expect("semaphore is not closed until the end of loop"); + + let builder = builder.clone(); + let prefix = prefix.clone(); + let start_key = start_key.cloned(); + let end_key = end_key.cloned(); + + let handle = tokio::spawn(async move { + let res = builder + .rpc_get_keys_in_range(&prefix, block, start_key.as_ref(), end_key.as_ref()) + .await; + drop(permit); + res + }); + + handles.push(handle); + } + + parallel.close(); + + let keys = futures::future::join_all(handles) + .await + .into_iter() + .filter_map(|res| match res { + Ok(Ok(keys)) => Some(keys), + _ => None, + }) + .flatten() + .collect::>(); + + Ok(keys) + } + + /// Get all keys with `prefix` within the given range at `block`. + /// Both `start_key` and `end_key` are optional if you want an open-ended range. + async fn rpc_get_keys_in_range( + &self, + prefix: &StorageKey, + block: B::Hash, + start_key: Option<&StorageKey>, + end_key: Option<&StorageKey>, ) -> Result, &'static str> { - let mut last_key: Option = None; - let mut all_keys: Vec = vec![]; - let keys = loop { + let mut last_key: Option<&StorageKey> = start_key; + let mut keys: Vec = vec![]; + + 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::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?; - let page_len = page.len(); + || self.get_keys_single_page(Some(prefix.clone()), last_key.cloned(), block); + let mut page = Retry::spawn(retry_strategy, get_page_closure).await?; - all_keys.extend(page); + // avoid duplicated keys across workloads + if let (Some(last), Some(end)) = (page.last(), end_key) { + if last >= end { + page.retain(|key| key < end); + } + } + let page_len = page.len(); + keys.extend(page); + last_key = keys.last(); + + // scraping out of range or no more matches, + // we are done either way if page_len < Self::DEFAULT_KEY_DOWNLOAD_PAGE as usize { log::debug!(target: LOG_TARGET, "last page received: {}", page_len); - break all_keys - } else { - let new_last_key = - all_keys.last().expect("all_keys is populated; has .last(); qed"); - log::debug!( - target: LOG_TARGET, - "new total = {}, full page received: {}", - all_keys.len(), - HexDisplay::from(new_last_key) - ); - last_key = Some(new_last_key.clone()); - }; - }; + break + } + + log::debug!( + target: LOG_TARGET, + "new total = {}, full page received: {}", + keys.len(), + HexDisplay::from(last_key.expect("full page received, cannot be None")) + ); + } Ok(keys) } @@ -529,7 +624,7 @@ where "Batch request failed ({}/{} retries). Error: {}", retries, Self::MAX_RETRIES, - e.to_string() + e ); // after 2 subsequent failures something very wrong is happening. log a warning // and reset the batch size down to 1. @@ -590,7 +685,7 @@ where /// map them to values one by one. /// /// This can work with public nodes. But, expect it to be darn slow. - pub(crate) async fn rpc_get_pairs_paged( + pub(crate) async fn rpc_get_pairs( &self, prefix: StorageKey, at: B::Hash, @@ -598,8 +693,10 @@ where ) -> Result, &'static str> { let start = Instant::now(); let mut sp = Spinner::with_timer(Spinners::Dots, "Scraping keys...".into()); + // TODO We could start downloading when having collected the first batch of keys + // https://github.com/paritytech/polkadot-sdk/issues/2494 let keys = self - .rpc_get_keys_paged(prefix.clone(), at) + .rpc_get_keys_parallel(&prefix, at, Self::PARALLEL_REQUESTS) .await? .into_iter() .collect::>(); @@ -628,9 +725,9 @@ where .unwrap() .progress_chars("=>-"), ); - let payloads_chunked = payloads.chunks((&payloads.len() / Self::PARALLEL_REQUESTS).max(1)); + 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(), &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, _> = @@ -644,7 +741,7 @@ where }, }; bar.finish_with_message("✅ Downloaded key values"); - print!("\n"); + println!(); // Check if we got responses for all submitted requests. assert_eq!(keys.len(), storage_data.len()); @@ -778,8 +875,9 @@ where pending_ext: &mut TestExternalities>, ) -> Result { let child_roots = top_kv - .into_iter() - .filter_map(|(k, _)| is_default_child_storage_key(k.as_ref()).then(|| k.clone())) + .iter() + .filter(|(k, _)| is_default_child_storage_key(k.as_ref())) + .map(|(k, _)| k.clone()) .collect::>(); if child_roots.is_empty() { @@ -799,11 +897,10 @@ where let mut child_kv = vec![]; for prefixed_top_key in child_roots { let child_keys = - Self::rpc_child_get_keys(&client, &prefixed_top_key, StorageKey(vec![]), at) - .await?; + Self::rpc_child_get_keys(client, &prefixed_top_key, StorageKey(vec![]), at).await?; let child_kv_inner = - Self::rpc_child_get_storage_paged(&client, &prefixed_top_key, child_keys, at) + Self::rpc_child_get_storage_paged(client, &prefixed_top_key, child_keys, at) .await?; let prefixed_top_key = PrefixedStorageKey::new(prefixed_top_key.clone().0); @@ -846,7 +943,7 @@ where for prefix in &config.hashed_prefixes { let now = std::time::Instant::now(); let additional_key_values = - self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at, pending_ext).await?; + self.rpc_get_pairs(StorageKey(prefix.to_vec()), at, pending_ext).await?; let elapsed = now.elapsed(); log::info!( target: LOG_TARGET, @@ -1110,7 +1207,7 @@ mod test_prelude { pub(crate) type Block = RawBlock>; pub(crate) fn init_logger() { - let _ = sp_tracing::try_init_simple(); + sp_tracing::try_init_simple(); } } @@ -1440,4 +1537,26 @@ mod remote_tests { .unwrap() .execute_with(|| {}); } + + #[tokio::test] + async fn can_fetch_in_parallel() { + init_logger(); + + let uri = String::from("wss://kusama-bridge-hub-rpc.polkadot.io:443"); + let mut builder = Builder::::new() + .mode(Mode::Online(OnlineConfig { transport: uri.into(), ..Default::default() })); + builder.init_remote_client().await.unwrap(); + + let at = builder.as_online().at.unwrap(); + + let prefix = StorageKey(vec![13]); + let paged = builder.rpc_get_keys_in_range(&prefix, at, None, None).await.unwrap(); + let para = builder.rpc_get_keys_parallel(&prefix, at, 4).await.unwrap(); + assert_eq!(paged, para); + + let prefix = StorageKey(vec![]); + let paged = builder.rpc_get_keys_in_range(&prefix, at, None, None).await.unwrap(); + let para = builder.rpc_get_keys_parallel(&prefix, at, 8).await.unwrap(); + assert_eq!(paged, para); + } } -- GitLab From 39d6c95c0daa4e42c30836919150a67317f0e408 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:30:09 +0100 Subject: [PATCH 609/633] substrate-node: `NativeElseWasmExecutor` is no longer used (#2521) This PR removes `NativeElseWasmExecutor` usage from substrate node. Instead [`WasmExecutor<(sp_io::SubstrateHostFunctions, sp_statement_store::runtime_api::HostFunctions)>`](https://github.com/paritytech/polkadot-sdk/blob/49a41ab3bb3f630c20e5b24cec8d92382404631c/substrate/bin/node/executor/src/lib.rs#L26) is used. Related to #2358. --------- Co-authored-by: Davide Galassi --- Cargo.lock | 57 +++------ Cargo.toml | 1 - .../bin/node-template/node/src/service.rs | 30 +---- substrate/bin/node/cli/Cargo.toml | 40 ++++++- .../bench.rs => cli/benches/executor.rs} | 109 +++++++----------- substrate/bin/node/cli/src/command.rs | 3 +- substrate/bin/node/cli/src/service.rs | 24 +++- .../bin/node/{executor => cli}/tests/basic.rs | 0 .../node/{executor => cli}/tests/common.rs | 9 +- .../bin/node/{executor => cli}/tests/fees.rs | 0 .../tests/res/default_genesis_config.json | 0 .../tests/submit_transaction.rs | 0 substrate/bin/node/executor/Cargo.toml | 57 --------- substrate/bin/node/executor/src/lib.rs | 40 ------- substrate/bin/node/inspect/Cargo.toml | 8 ++ substrate/bin/node/inspect/src/command.rs | 10 +- substrate/bin/node/testing/Cargo.toml | 2 +- substrate/bin/node/testing/src/bench.rs | 14 +-- substrate/bin/node/testing/src/client.rs | 19 ++- 19 files changed, 164 insertions(+), 259 deletions(-) rename substrate/bin/node/{executor/benches/bench.rs => cli/benches/executor.rs} (71%) rename substrate/bin/node/{executor => cli}/tests/basic.rs (100%) rename substrate/bin/node/{executor => cli}/tests/common.rs (95%) rename substrate/bin/node/{executor => cli}/tests/fees.rs (100%) rename substrate/bin/node/{executor => cli}/tests/res/default_genesis_config.json (100%) rename substrate/bin/node/{executor => cli}/tests/submit_transaction.rs (100%) delete mode 100644 substrate/bin/node/executor/Cargo.toml delete mode 100644 substrate/bin/node/executor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 871d46ea844..bf4efa60ad7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8928,7 +8928,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "sp-timestamp", - "staging-node-executor", + "staging-node-cli", "substrate-test-client", "tempfile", ] @@ -18358,7 +18358,9 @@ dependencies = [ "clap 4.4.6", "clap_complete", "criterion 0.4.0", + "frame-benchmarking", "frame-benchmarking-cli", + "frame-support", "frame-system", "frame-system-rpc-runtime-api", "futures", @@ -18368,13 +18370,20 @@ dependencies = [ "nix 0.26.2", "node-primitives", "node-rpc", + "node-testing", "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", "pallet-assets", "pallet-balances", + "pallet-contracts", + "pallet-glutton", "pallet-im-online", + "pallet-root-testing", "pallet-skip-feeless-payment", + "pallet-sudo", "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", "parity-scale-codec", "platforms", "rand 0.8.5", @@ -18409,27 +18418,31 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", + "scale-info", "serde", "serde_json", "soketto", "sp-api", + "sp-application-crypto", "sp-authority-discovery", "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-consensus-grandpa", "sp-core", + "sp-externalities 0.19.0", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-mixnet", "sp-runtime", + "sp-state-machine", "sp-statement-store", "sp-timestamp", "sp-tracing 10.0.0", "sp-transaction-storage-proof", - "staging-node-executor", + "sp-trie", "staging-node-inspect", "substrate-build-script-utils", "substrate-cli-test-utils", @@ -18440,44 +18453,6 @@ dependencies = [ "tokio-util", "try-runtime-cli", "wait-timeout", -] - -[[package]] -name = "staging-node-executor" -version = "3.0.0-dev" -dependencies = [ - "criterion 0.4.0", - "frame-benchmarking", - "frame-support", - "frame-system", - "futures", - "kitchensink-runtime", - "node-primitives", - "node-testing", - "pallet-balances", - "pallet-contracts", - "pallet-glutton", - "pallet-im-online", - "pallet-root-testing", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-treasury", - "parity-scale-codec", - "sc-executor", - "scale-info", - "serde_json", - "sp-application-crypto", - "sp-consensus-babe", - "sp-core", - "sp-externalities 0.19.0", - "sp-keyring", - "sp-keystore", - "sp-runtime", - "sp-state-machine", - "sp-statement-store", - "sp-tracing 10.0.0", - "sp-trie", "wat", ] @@ -18492,7 +18467,9 @@ dependencies = [ "sc-service", "sp-blockchain", "sp-core", + "sp-io", "sp-runtime", + "sp-statement-store", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 6af3ea4c3cb..f16c8393183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -200,7 +200,6 @@ members = [ "substrate/bin/node-template/runtime", "substrate/bin/node/bench", "substrate/bin/node/cli", - "substrate/bin/node/executor", "substrate/bin/node/inspect", "substrate/bin/node/primitives", "substrate/bin/node/rpc", diff --git a/substrate/bin/node-template/node/src/service.rs b/substrate/bin/node-template/node/src/service.rs index e69428d8190..c4a2b2f39d2 100644 --- a/substrate/bin/node-template/node/src/service.rs +++ b/substrate/bin/node-template/node/src/service.rs @@ -5,35 +5,17 @@ use node_template_runtime::{self, opaque::Block, RuntimeApi}; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; -pub use sc_executor::NativeElseWasmExecutor; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use std::{sync::Arc, time::Duration}; -// Our native executor instance. -pub struct ExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - /// Only enable the benchmarking host functions when we actually want to benchmark. - #[cfg(feature = "runtime-benchmarks")] - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - /// Otherwise we only use the default Substrate host functions. - #[cfg(not(feature = "runtime-benchmarks"))] - type ExtendHostFunctions = (); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - node_template_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - node_template_runtime::native_version() - } -} - -pub(crate) type FullClient = - sc_service::TFullClient>; +pub(crate) type FullClient = sc_service::TFullClient< + Block, + RuntimeApi, + sc_executor::WasmExecutor, +>; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; @@ -75,7 +57,7 @@ pub fn new_partial( }) .transpose()?; - let executor = sc_service::new_native_or_wasm_executor(config); + let executor = sc_service::new_wasm_executor::(config); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( config, diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 8f3c2185deb..656d6f86505 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -90,6 +90,7 @@ sc-storage-monitor = { path = "../../../client/storage-monitor" } sc-offchain = { path = "../../../client/offchain" } # frame dependencies +frame-benchmarking = { path = "../../../frame/benchmarking" } frame-system = { path = "../../../frame/system" } frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api" } pallet-assets = { path = "../../../frame/assets" } @@ -102,7 +103,6 @@ pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip- kitchensink-runtime = { path = "../runtime" } node-rpc = { path = "../rpc" } node-primitives = { path = "../primitives" } -node-executor = { package = "staging-node-executor", path = "../executor" } # CLI-specific dependencies sc-cli = { path = "../../../client/cli", optional = true} @@ -136,6 +136,26 @@ substrate-rpc-client = { path = "../../../utils/frame/rpc/client" } pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } +wat = "1.0" +frame-support = { path = "../../../frame/support" } +node-testing = { path = "../testing" } +pallet-balances = { path = "../../../frame/balances" } +pallet-contracts = { path = "../../../frame/contracts" } +pallet-glutton = { path = "../../../frame/glutton" } +pallet-sudo = { path = "../../../frame/sudo" } +pallet-treasury = { path = "../../../frame/treasury" } +pallet-transaction-payment = { path = "../../../frame/transaction-payment" } +sp-application-crypto = { path = "../../../primitives/application-crypto" } +pallet-root-testing = { path = "../../../frame/root-testing" } +sp-consensus-babe = { path = "../../../primitives/consensus/babe" } +sp-externalities = { path = "../../../primitives/externalities" } +sp-keyring = { path = "../../../primitives/keyring" } +sp-runtime = { path = "../../../primitives/runtime" } +serde_json = "1.0.108" +scale-info = { version = "2.10.0", features = ["derive", "serde"] } +sp-trie = { path = "../../../primitives/trie" } +sp-state-machine = { path = "../../../primitives/state-machine" } + [build-dependencies] clap = { version = "4.4.6", optional = true } clap_complete = { version = "4.0.2", optional = true } @@ -163,14 +183,21 @@ cli = [ ] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "kitchensink-runtime/runtime-benchmarks", + "node-inspect?/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", + "pallet-glutton/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-skip-feeless-payment/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -178,15 +205,22 @@ runtime-benchmarks = [ # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = [ + "frame-support/try-runtime", "frame-system/try-runtime", "kitchensink-runtime/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-tx-payment/try-runtime", "pallet-assets/try-runtime", "pallet-balances/try-runtime", + "pallet-contracts/try-runtime", + "pallet-glutton/try-runtime", "pallet-im-online/try-runtime", + "pallet-root-testing/try-runtime", "pallet-skip-feeless-payment/try-runtime", + "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-treasury/try-runtime", "sp-runtime/try-runtime", "substrate-cli-test-utils/try-runtime", "try-runtime-cli/try-runtime", @@ -199,3 +233,7 @@ harness = false [[bench]] name = "block_production" harness = false + +[[bench]] +name = "executor" +harness = false diff --git a/substrate/bin/node/executor/benches/bench.rs b/substrate/bin/node/cli/benches/executor.rs similarity index 71% rename from substrate/bin/node/executor/benches/bench.rs rename to substrate/bin/node/cli/benches/executor.rs index 587e76af867..d654646904b 100644 --- a/substrate/bin/node/executor/benches/bench.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -22,20 +22,16 @@ use kitchensink_runtime::{ constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, RuntimeCall, RuntimeGenesisConfig, UncheckedExtrinsic, }; -use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; -use sc_executor::{ - Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod, WasmExecutor, - WasmtimeInstantiationStrategy, -}; +use sc_executor::{Externalities, RuntimeVersionOf}; use sp_core::{ storage::well_known_keys, traits::{CallContext, CodeExecutor, RuntimeCode}, }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; -use staging_node_executor as node_executor; +use staging_node_cli::service::RuntimeExecutor; criterion_group!(benches, bench_execute_block); criterion_main!(benches); @@ -58,12 +54,6 @@ const HEAP_PAGES: u64 = 20; type TestExternalities = CoreTestExternalities; -#[derive(Debug)] -enum ExecutionMethod { - Native, - Wasm(WasmExecutionMethod), -} - fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH) } @@ -80,7 +70,7 @@ fn new_test_ext(genesis_config: &RuntimeGenesisConfig) -> TestExternalities( - executor: &NativeElseWasmExecutor, + executor: &RuntimeExecutor, ext: &mut E, number: BlockNumber, parent_hash: Hash, @@ -159,7 +149,7 @@ fn construct_block( fn test_blocks( genesis_config: &RuntimeGenesisConfig, - executor: &NativeElseWasmExecutor, + executor: &RuntimeExecutor, ) -> Vec<(Vec, Hash)> { let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { @@ -181,56 +171,43 @@ fn test_blocks( fn bench_execute_block(c: &mut Criterion) { let mut group = c.benchmark_group("execute blocks"); - let execution_methods = vec![ - ExecutionMethod::Native, - ExecutionMethod::Wasm(WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, - }), - ]; - - for strategy in execution_methods { - group.bench_function(format!("{:?}", strategy), |b| { - let genesis_config = node_testing::genesis::config(); - let use_native = match strategy { - ExecutionMethod::Native => true, - ExecutionMethod::Wasm(..) => false, - }; - - let executor = - NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()); - let runtime_code = RuntimeCode { - code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), - hash: vec![1, 2, 3], - heap_pages: None, - }; - - // Get the runtime version to initialize the runtimes cache. - { - let mut test_ext = new_test_ext(&genesis_config); - executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap(); - } - - let blocks = test_blocks(&genesis_config, &executor); - - b.iter_batched_ref( - || new_test_ext(&genesis_config), - |test_ext| { - for block in blocks.iter() { - executor - .call( - &mut test_ext.ext(), - &runtime_code, - "Core_execute_block", - &block.0, - use_native, - CallContext::Offchain, - ) - .0 - .unwrap(); - } - }, - BatchSize::LargeInput, - ); - }); - } + + group.bench_function("wasm", |b| { + let genesis_config = node_testing::genesis::config(); + + let executor = RuntimeExecutor::builder().build(); + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), + hash: vec![1, 2, 3], + heap_pages: None, + }; + + // Get the runtime version to initialize the runtimes cache. + { + let mut test_ext = new_test_ext(&genesis_config); + executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap(); + } + + let blocks = test_blocks(&genesis_config, &executor); + + b.iter_batched_ref( + || new_test_ext(&genesis_config), + |test_ext| { + for block in blocks.iter() { + executor + .call( + &mut test_ext.ext(), + &runtime_code, + "Core_execute_block", + &block.0, + false, + CallContext::Offchain, + ) + .0 + .unwrap(); + } + }, + BatchSize::LargeInput, + ); + }); } diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 16d0415ff26..dc28705c2ae 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -24,7 +24,6 @@ use crate::{ }; use frame_benchmarking_cli::*; use kitchensink_runtime::{ExistentialDeposit, RuntimeApi}; -use node_executor::ExecutorDispatch; use node_primitives::Block; use sc_cli::{Result, SubstrateCli}; use sc_service::PartialComponents; @@ -89,7 +88,7 @@ pub fn run() -> Result<()> { Some(Subcommand::Inspect(cmd)) => { let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| cmd.run::(config)) + runner.sync_run(|config| cmd.run::(config)) }, Some(Subcommand::Benchmark(cmd)) => { let runner = cli.create_runner(cmd)?; diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index a746de8de84..4f8c6198cdc 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -26,11 +26,9 @@ use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; use kitchensink_runtime::RuntimeApi; -use node_executor::ExecutorDispatch; use node_primitives::Block; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_babe::{self, SlotProportion}; -use sc_executor::NativeElseWasmExecutor; use sc_network::{event::Event, NetworkEventStream, NetworkService}; use sc_network_sync::{warp::WarpSyncParams, SyncingService}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; @@ -42,9 +40,25 @@ use sp_core::crypto::Pair; use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion}; use std::sync::Arc; +/// Host functions required for kitchensink runtime and Substrate node. +#[cfg(not(feature = "runtime-benchmarks"))] +pub type HostFunctions = + (sp_io::SubstrateHostFunctions, sp_statement_store::runtime_api::HostFunctions); + +/// Host functions required for kitchensink runtime and Substrate node. +#[cfg(feature = "runtime-benchmarks")] +pub type HostFunctions = ( + sp_io::SubstrateHostFunctions, + sp_statement_store::runtime_api::HostFunctions, + frame_benchmarking::benchmarking::HostFunctions, +); + +/// A specialized `WasmExecutor` intended to use accross substrate node. It provides all required +/// HostFunctions. +pub type RuntimeExecutor = sc_executor::WasmExecutor; + /// The full client type definition. -pub type FullClient = - sc_service::TFullClient>; +pub type FullClient = sc_service::TFullClient; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; type FullGrandpaBlockImport = @@ -174,7 +188,7 @@ pub fn new_partial( }) .transpose()?; - let executor = sc_service::new_native_or_wasm_executor(&config); + let executor = sc_service::new_wasm_executor(&config); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/substrate/bin/node/executor/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs similarity index 100% rename from substrate/bin/node/executor/tests/basic.rs rename to substrate/bin/node/cli/tests/basic.rs diff --git a/substrate/bin/node/executor/tests/common.rs b/substrate/bin/node/cli/tests/common.rs similarity index 95% rename from substrate/bin/node/executor/tests/common.rs rename to substrate/bin/node/cli/tests/common.rs index 2d68c88db92..7d8f6a9a0e7 100644 --- a/substrate/bin/node/executor/tests/common.rs +++ b/substrate/bin/node/cli/tests/common.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode}; use frame_support::Hashable; use frame_system::offchain::AppCrypto; -use sc_executor::{error::Result, NativeElseWasmExecutor, WasmExecutor}; +use sc_executor::error::Result; use sp_consensus_babe::{ digests::{PreDigest, SecondaryPlainPreDigest}, Slot, BABE_ENGINE_ID, @@ -38,11 +38,10 @@ use kitchensink_runtime::{ constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime, UncheckedExtrinsic, }; -use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; use sp_externalities::Externalities; -use staging_node_executor as node_executor; +use staging_node_cli::service::RuntimeExecutor; pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); @@ -98,8 +97,8 @@ pub fn from_block_number(n: u32) -> Header { Header::new(n, Default::default(), Default::default(), [69; 32].into(), Default::default()) } -pub fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) +pub fn executor() -> RuntimeExecutor { + RuntimeExecutor::builder().build() } pub fn executor_call( diff --git a/substrate/bin/node/executor/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs similarity index 100% rename from substrate/bin/node/executor/tests/fees.rs rename to substrate/bin/node/cli/tests/fees.rs diff --git a/substrate/bin/node/executor/tests/res/default_genesis_config.json b/substrate/bin/node/cli/tests/res/default_genesis_config.json similarity index 100% rename from substrate/bin/node/executor/tests/res/default_genesis_config.json rename to substrate/bin/node/cli/tests/res/default_genesis_config.json diff --git a/substrate/bin/node/executor/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs similarity index 100% rename from substrate/bin/node/executor/tests/submit_transaction.rs rename to substrate/bin/node/cli/tests/submit_transaction.rs diff --git a/substrate/bin/node/executor/Cargo.toml b/substrate/bin/node/executor/Cargo.toml deleted file mode 100644 index 595a313d2cb..00000000000 --- a/substrate/bin/node/executor/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -name = "staging-node-executor" -version = "3.0.0-dev" -authors.workspace = true -description = "Substrate node implementation in Rust." -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", features = ["derive", "serde"] } -frame-benchmarking = { path = "../../../frame/benchmarking" } -node-primitives = { path = "../primitives" } -kitchensink-runtime = { path = "../runtime" } -sc-executor = { path = "../../../client/executor" } -sp-core = { path = "../../../primitives/core", features=["serde"] } -sp-keystore = { path = "../../../primitives/keystore" } -sp-state-machine = { path = "../../../primitives/state-machine" } -sp-tracing = { path = "../../../primitives/tracing" } -sp-trie = { path = "../../../primitives/trie" } -sp-statement-store = { path = "../../../primitives/statement-store", features=["serde"] } - -[dev-dependencies] -criterion = "0.4.0" -futures = "0.3.21" -wat = "1.0" -frame-support = { path = "../../../frame/support" } -frame-system = { path = "../../../frame/system" } -node-testing = { path = "../testing" } -pallet-balances = { path = "../../../frame/balances" } -pallet-contracts = { path = "../../../frame/contracts" } -pallet-im-online = { path = "../../../frame/im-online" } -pallet-glutton = { path = "../../../frame/glutton" } -pallet-sudo = { path = "../../../frame/sudo" } -pallet-timestamp = { path = "../../../frame/timestamp" } -pallet-treasury = { path = "../../../frame/treasury" } -pallet-transaction-payment = { path = "../../../frame/transaction-payment" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -pallet-root-testing = { path = "../../../frame/root-testing" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe" } -sp-externalities = { path = "../../../primitives/externalities" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-runtime = { path = "../../../primitives/runtime" } -serde_json = "1.0.108" - -[features] -stress-test = [] - -[[bench]] -name = "bench" -harness = false diff --git a/substrate/bin/node/executor/src/lib.rs b/substrate/bin/node/executor/src/lib.rs deleted file mode 100644 index 3557a16740b..00000000000 --- a/substrate/bin/node/executor/src/lib.rs +++ /dev/null @@ -1,40 +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. - -//! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be -//! executed is equivalent to the natively compiled code. - -pub use sc_executor::NativeElseWasmExecutor; - -// Declare an instance of the native executor named `ExecutorDispatch`. Include the wasm binary as -// the equivalent wasm code. -pub struct ExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - type ExtendHostFunctions = ( - frame_benchmarking::benchmarking::HostFunctions, - sp_statement_store::runtime_api::HostFunctions, - ); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - kitchensink_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - kitchensink_runtime::native_version() - } -} diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 30cc22b0e8c..cfdec6af5de 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -20,4 +20,12 @@ sc-client-api = { path = "../../../client/api" } sc-service = { path = "../../../client/service", default-features = false} sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } +sp-io = { path = "../../../primitives/io" } sp-runtime = { path = "../../../primitives/runtime" } +sp-statement-store = { path = "../../../primitives/statement-store" } + +[features] +runtime-benchmarks = [ + "sc-service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/substrate/bin/node/inspect/src/command.rs b/substrate/bin/node/inspect/src/command.rs index dcecfd78826..e0e25707e31 100644 --- a/substrate/bin/node/inspect/src/command.rs +++ b/substrate/bin/node/inspect/src/command.rs @@ -23,18 +23,20 @@ use crate::{ Inspector, }; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_service::{Configuration, NativeExecutionDispatch}; +use sc_service::Configuration; use sp_runtime::traits::Block; +type HostFunctions = + (sp_io::SubstrateHostFunctions, sp_statement_store::runtime_api::HostFunctions); + impl InspectCmd { /// Run the inspect command, passing the inspector. - pub fn run(&self, config: Configuration) -> Result<()> + pub fn run(&self, config: Configuration) -> Result<()> where B: Block, RA: Send + Sync + 'static, - D: NativeExecutionDispatch + 'static, { - let executor = sc_service::new_native_or_wasm_executor::(&config); + let executor = sc_service::new_wasm_executor::(&config); let client = sc_service::new_full_client::(&config, None, executor)?; let inspect = Inspector::::new(client); diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index e4fb06b5dcd..dba5016fb3e 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" log = "0.4.17" tempfile = "3.1.0" frame-system = { path = "../../../frame/system" } -node-executor = { package = "staging-node-executor", path = "../executor" } +node-cli = { package = "staging-node-cli", path = "../cli" } node-primitives = { path = "../primitives" } kitchensink-runtime = { path = "../runtime" } pallet-asset-conversion = { path = "../../../frame/asset-conversion" } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 89b96c0191c..98d3b968a35 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -43,7 +43,7 @@ use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; use sc_client_db::PruningMode; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux}; -use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod, WasmtimeInstantiationStrategy}; +use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_consensus::BlockOrigin; @@ -388,13 +388,11 @@ impl BenchDb { let task_executor = TaskExecutor::new(); let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); - let executor = NativeElseWasmExecutor::new_with_wasm_executor( - sc_executor::WasmExecutor::builder() - .with_execution_method(WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, - }) - .build(), - ); + let executor = sc_executor::WasmExecutor::builder() + .with_execution_method(WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }) + .build(); let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( diff --git a/substrate/bin/node/testing/src/client.rs b/substrate/bin/node/testing/src/client.rs index 22276833fb6..07ba1cdbbfb 100644 --- a/substrate/bin/node/testing/src/client.rs +++ b/substrate/bin/node/testing/src/client.rs @@ -23,7 +23,7 @@ use sp_runtime::BuildStorage; pub use substrate_test_client::*; /// Call executor for `kitchensink-runtime` `TestClient`. -pub type ExecutorDispatch = sc_executor::NativeElseWasmExecutor; +use node_cli::service::RuntimeExecutor; /// Default backend type. pub type Backend = sc_client_db::Backend; @@ -31,7 +31,7 @@ pub type Backend = sc_client_db::Backend; /// Test client type. pub type Client = client::Client< Backend, - client::LocalCallExecutor, + client::LocalCallExecutor, node_primitives::Block, kitchensink_runtime::RuntimeApi, >; @@ -63,7 +63,7 @@ pub trait TestClientBuilderExt: Sized { impl TestClientBuilderExt for substrate_test_client::TestClientBuilder< node_primitives::Block, - client::LocalCallExecutor, + client::LocalCallExecutor, Backend, GenesisParameters, > @@ -71,8 +71,17 @@ impl TestClientBuilderExt fn new() -> Self { Self::default() } - fn build(self) -> Client { - self.build_with_native_executor(None).0 + let executor = RuntimeExecutor::builder().build(); + use sc_service::client::LocalCallExecutor; + use std::sync::Arc; + let executor = LocalCallExecutor::new( + self.backend().clone(), + executor.clone(), + Default::default(), + ExecutionExtensions::new(None, Arc::new(executor)), + ) + .expect("Creates LocalCallExecutor"); + self.build_with_executor(executor).0 } } -- GitLab From 63ac2471aa0210f0ac9903bdd7d8f9351f9a635f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Wed, 29 Nov 2023 11:07:07 +0000 Subject: [PATCH 610/633] Remove system parachains Polkadot and Kusama runtimes (#1737) Since the Polkadot and Kusama runtimes are no longer in the repo, the relevant systems parachains runtimes also need to be removed. More context [here](https://github.com/paritytech/polkadot-sdk/issues/603) and [here](https://github.com/paritytech/polkadot-sdk/pull/1731). Removes the following: - `asset-hub-kusama` and `asset-hub-polkadot` - `bridge-hub-kusama` and `bridge-hub-polkadot` - `collectives-polkadot` - `glutton-kusama` Partially solves #603 and adds to #1731. --- .gitlab/pipeline/short-benchmarks.yml | 30 - Cargo.lock | 395 ----- Cargo.toml | 6 - .../assets/asset-hub-kusama/0_xcm/0_init.yml | 145 -- .../assets/asset-hub-kusama/0_xcm/1_dmp.yml | 263 --- .../assets/asset-hub-kusama/0_xcm/2_ump.yml | 191 -- .../0_xcm/3_force_hrmp-open-channels.yml | 122 -- .../assets/asset-hub-kusama/0_xcm/4_hrmp.yml | 388 ----- .../e2e/assets/asset-hub-kusama/config.toml | 71 - .../asset-hub-polkadot/0_xcm/0_init.yml | 145 -- .../assets/asset-hub-polkadot/0_xcm/1_dmp.yml | 263 --- .../assets/asset-hub-polkadot/0_xcm/2_ump.yml | 194 --- .../0_xcm/3_force_hrmp-open-channels.yml | 120 -- .../asset-hub-polkadot/0_xcm/4_hrmp.yml | 388 ----- .../e2e/assets/asset-hub-polkadot/config.toml | 72 - .../e2e/collectives/README.md | 26 - .../collectives-polkadot/0_xcm/0_init.yml | 166 -- .../collectives-polkadot/0_xcm/1_teleport.yml | 168 -- .../collectives-polkadot/0_xcm/2_reserve.yml | 53 - .../0_xcm/3_hrmp-open-channels.yml | 69 - .../1_alliance/0_join_alliance_fails.yml | 29 - .../1_alliance/1_init_alliance.yml | 256 --- .../1_alliance/2_join_alliance_fails.yml | 30 - .../1_alliance/3_kick_member.yml | 175 -- .../2_opengov/0_assethub.yml | 149 -- .../3_fellowship/0_init.yml | 209 --- .../3_fellowship/1_whitelist_call.yml | 146 -- .../3_fellowship/2_assethub.yml | 126 -- .../collectives-polkadot/config.toml | 42 - .../assets/asset-hub-kusama/Cargo.toml | 236 --- .../runtimes/assets/asset-hub-kusama/build.rs | 26 - .../assets/asset-hub-kusama/src/lib.rs | 1549 ----------------- .../src/weights/block_weights.rs | 53 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 -- .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 -- .../src/weights/extrinsic_weights.rs | 53 - .../src/weights/frame_system.rs | 154 -- .../asset-hub-kusama/src/weights/mod.rs | 45 - .../src/weights/pallet_asset_conversion.rs | 154 -- .../src/weights/pallet_assets_foreign.rs | 533 ------ .../src/weights/pallet_assets_local.rs | 530 ------ .../src/weights/pallet_assets_pool.rs | 530 ------ .../src/weights/pallet_balances.rs | 152 -- .../src/weights/pallet_collator_selection.rs | 248 --- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_multisig.rs | 164 -- .../weights/pallet_nft_fractionalization.rs | 114 -- .../src/weights/pallet_nfts.rs | 772 -------- .../src/weights/pallet_proxy.rs | 225 --- .../src/weights/pallet_session.rs | 80 - .../src/weights/pallet_timestamp.rs | 74 - .../src/weights/pallet_uniques.rs | 466 ----- .../src/weights/pallet_utility.rs | 101 -- .../src/weights/pallet_xcm.rs | 324 ---- .../src/weights/paritydb_weights.rs | 63 - .../src/weights/rocksdb_weights.rs | 63 - .../asset-hub-kusama/src/weights/xcm/mod.rs | 244 --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 187 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 328 ---- .../assets/asset-hub-kusama/src/xcm_config.rs | 634 ------- .../assets/asset-hub-kusama/tests/tests.rs | 658 ------- .../assets/asset-hub-polkadot/Cargo.toml | 215 --- .../assets/asset-hub-polkadot/build.rs | 26 - .../assets/asset-hub-polkadot/src/lib.rs | 1383 --------------- .../src/weights/block_weights.rs | 53 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 -- .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 -- .../src/weights/extrinsic_weights.rs | 53 - .../src/weights/frame_system.rs | 154 -- .../asset-hub-polkadot/src/weights/mod.rs | 42 - .../src/weights/pallet_assets_foreign.rs | 532 ------ .../src/weights/pallet_assets_local.rs | 528 ------ .../src/weights/pallet_balances.rs | 152 -- .../src/weights/pallet_collator_selection.rs | 246 --- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_multisig.rs | 164 -- .../src/weights/pallet_nfts.rs | 772 -------- .../src/weights/pallet_proxy.rs | 225 --- .../src/weights/pallet_session.rs | 80 - .../src/weights/pallet_timestamp.rs | 74 - .../src/weights/pallet_uniques.rs | 466 ----- .../src/weights/pallet_utility.rs | 101 -- .../src/weights/pallet_xcm.rs | 324 ---- .../src/weights/paritydb_weights.rs | 63 - .../src/weights/rocksdb_weights.rs | 63 - .../asset-hub-polkadot/src/weights/xcm/mod.rs | 244 --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 187 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 328 ---- .../asset-hub-polkadot/src/xcm_config.rs | 546 ------ .../assets/asset-hub-polkadot/tests/tests.rs | 683 -------- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 192 -- .../bridge-hubs/bridge-hub-kusama/build.rs | 26 - .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 872 ---------- .../src/weights/block_weights.rs | 53 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 -- .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 -- .../src/weights/extrinsic_weights.rs | 53 - .../src/weights/frame_system.rs | 154 -- .../bridge-hub-kusama/src/weights/mod.rs | 41 - .../src/weights/pallet_balances.rs | 152 -- .../src/weights/pallet_collator_selection.rs | 248 --- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_multisig.rs | 164 -- .../src/weights/pallet_session.rs | 80 - .../src/weights/pallet_timestamp.rs | 74 - .../src/weights/pallet_utility.rs | 101 -- .../src/weights/pallet_xcm.rs | 323 ---- .../src/weights/paritydb_weights.rs | 63 - .../src/weights/rocksdb_weights.rs | 63 - .../bridge-hub-kusama/src/weights/xcm/mod.rs | 244 --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 187 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 328 ---- .../bridge-hub-kusama/src/xcm_config.rs | 280 --- .../bridge-hub-kusama/tests/tests.rs | 51 - .../bridge-hub-polkadot/Cargo.toml | 192 -- .../bridge-hubs/bridge-hub-polkadot/build.rs | 26 - .../bridge-hub-polkadot/src/lib.rs | 873 ---------- .../src/weights/block_weights.rs | 53 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 -- .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 -- .../src/weights/extrinsic_weights.rs | 53 - .../src/weights/frame_system.rs | 154 -- .../bridge-hub-polkadot/src/weights/mod.rs | 41 - .../src/weights/pallet_balances.rs | 152 -- .../src/weights/pallet_collator_selection.rs | 248 --- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_multisig.rs | 164 -- .../src/weights/pallet_session.rs | 80 - .../src/weights/pallet_timestamp.rs | 74 - .../src/weights/pallet_utility.rs | 101 -- .../src/weights/pallet_xcm.rs | 323 ---- .../src/weights/paritydb_weights.rs | 63 - .../src/weights/rocksdb_weights.rs | 63 - .../src/weights/xcm/mod.rs | 244 --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 187 -- .../xcm/pallet_xcm_benchmarks_generic.rs | 328 ---- .../bridge-hub-polkadot/src/xcm_config.rs | 284 --- .../bridge-hub-polkadot/tests/tests.rs | 51 - .../collectives-polkadot/Cargo.toml | 226 --- .../collectives/collectives-polkadot/build.rs | 26 - .../src/ambassador/mod.rs | 255 --- .../src/ambassador/origins.rs | 135 -- .../src/ambassador/tracks.rs | 282 --- .../src/fellowship/migration.rs | 261 --- .../src/fellowship/mod.rs | 239 --- .../src/fellowship/origins.rs | 247 --- .../src/fellowship/tracks.rs | 532 ------ .../collectives-polkadot/src/impls.rs | 229 --- .../collectives-polkadot/src/lib.rs | 1031 ----------- .../src/weights/block_weights.rs | 53 - .../src/weights/cumulus_pallet_dmp_queue.rs | 131 -- .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 -- .../src/weights/extrinsic_weights.rs | 53 - .../src/weights/frame_system.rs | 154 -- .../collectives-polkadot/src/weights/mod.rs | 50 - .../src/weights/pallet_alliance.rs | 494 ------ .../src/weights/pallet_balances.rs | 152 -- .../src/weights/pallet_collator_selection.rs | 246 --- .../src/weights/pallet_collective.rs | 304 ---- .../src/weights/pallet_collective_content.rs | 93 - .../pallet_core_fellowship_ambassador_core.rs | 223 --- .../pallet_core_fellowship_fellowship_core.rs | 222 --- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_multisig.rs | 164 -- .../src/weights/pallet_preimage.rs | 232 --- .../src/weights/pallet_proxy.rs | 225 --- ...ranked_collective_ambassador_collective.rs | 177 -- ...ranked_collective_fellowship_collective.rs | 176 -- .../pallet_referenda_ambassador_referenda.rs | 536 ------ .../pallet_referenda_fellowship_referenda.rs | 535 ------ .../pallet_salary_ambassador_salary.rs | 190 -- .../pallet_salary_fellowship_salary.rs | 189 -- .../src/weights/pallet_scheduler.rs | 206 --- .../src/weights/pallet_session.rs | 80 - .../src/weights/pallet_timestamp.rs | 74 - .../src/weights/pallet_utility.rs | 101 -- .../src/weights/pallet_xcm.rs | 323 ---- .../src/weights/paritydb_weights.rs | 63 - .../src/weights/rocksdb_weights.rs | 63 - .../collectives-polkadot/src/xcm_config.rs | 331 ---- .../glutton/glutton-kusama/Cargo.toml | 138 -- .../runtimes/glutton/glutton-kusama/build.rs | 24 - .../glutton/glutton-kusama/src/lib.rs | 528 ------ .../cumulus_pallet_parachain_system.rs | 80 - .../src/weights/frame_system.rs | 154 -- .../glutton/glutton-kusama/src/weights/mod.rs | 19 - .../src/weights/pallet_glutton.rs | 179 -- .../src/weights/pallet_message_queue.rs | 179 -- .../src/weights/pallet_timestamp.rs | 75 - .../glutton/glutton-kusama/src/xcm_config.rs | 92 - cumulus/polkadot-parachain/Cargo.toml | 18 - .../src/chain_spec/asset_hubs.rs | 357 +--- .../src/chain_spec/bridge_hubs.rs | 246 +-- .../src/chain_spec/collectives.rs | 134 -- .../src/chain_spec/glutton.rs | 56 - cumulus/polkadot-parachain/src/command.rs | 58 +- cumulus/polkadot-parachain/src/service.rs | 90 - .../tests/benchmark_storage_works.rs | 2 +- cumulus/scripts/benchmarks.sh | 9 - .../scripts/create_bridge_hub_kusama_spec.sh | 108 -- .../create_bridge_hub_polkadot_spec.sh | 108 -- cumulus/scripts/create_glutton_spec.sh | 2 +- .../scripts/parachains_integration_tests.sh | 32 - ...l => asset_hub_westend_local_network.toml} | 18 +- .../bridge_hub_kusama_local_network.toml | 67 - .../bridge_hub_polkadot_local_network.toml | 67 - cumulus/zombienet/examples/small_network.toml | 2 +- 212 files changed, 25 insertions(+), 43083 deletions(-) delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/0_init.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/1_dmp.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/2_ump.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/3_force_hrmp-open-channels.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/4_hrmp.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/config.toml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/0_init.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/1_dmp.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/2_ump.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/3_force_hrmp-open-channels.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/4_hrmp.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/config.toml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/README.md delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/0_init.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/1_teleport.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/2_reserve.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/0_join_alliance_fails.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/1_init_alliance.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/2_join_alliance_fails.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/3_kick_member.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/2_opengov/0_assethub.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/0_init.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/1_whitelist_call.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/2_assethub.yml delete mode 100644 cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/config.toml delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/build.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/build.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/build.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/build.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/build.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs delete mode 100755 cumulus/scripts/create_bridge_hub_kusama_spec.sh delete mode 100755 cumulus/scripts/create_bridge_hub_polkadot_spec.sh delete mode 100755 cumulus/scripts/parachains_integration_tests.sh rename cumulus/zombienet/examples/{statemine_kusama_local_network.toml => asset_hub_westend_local_network.toml} (71%) delete mode 100644 cumulus/zombienet/examples/bridge_hub_kusama_local_network.toml delete mode 100644 cumulus/zombienet/examples/bridge_hub_polkadot_local_network.toml diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 0218d3fdac0..97bce479927 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -49,16 +49,6 @@ short-benchmark-westend: &short-bench script: - ./artifacts/polkadot-parachain benchmark pallet --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 -short-benchmark-asset-hub-polkadot: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-polkadot-dev - -short-benchmark-asset-hub-kusama: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-kusama-dev - short-benchmark-asset-hub-rococo: <<: *short-bench-cumulus variables: @@ -69,16 +59,6 @@ short-benchmark-asset-hub-westend: variables: RUNTIME_CHAIN: asset-hub-westend-dev -short-benchmark-bridge-hub-polkadot: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-polkadot-dev - -short-benchmark-bridge-hub-kusama: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-kusama-dev - short-benchmark-bridge-hub-rococo: <<: *short-bench-cumulus variables: @@ -89,21 +69,11 @@ short-benchmark-bridge-hub-westend: variables: RUNTIME_CHAIN: bridge-hub-westend-dev -short-benchmark-collectives-polkadot: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: collectives-polkadot-dev - short-benchmark-collectives-westend: <<: *short-bench-cumulus variables: RUNTIME_CHAIN: collectives-westend-dev -short-benchmark-glutton-kusama: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: glutton-kusama-dev-1300 - short-benchmark-glutton-westend: <<: *short-bench-cumulus variables: diff --git a/Cargo.lock b/Cargo.lock index bf4efa60ad7..db5717a67ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,150 +730,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "asset-hub-kusama-runtime" -version = "0.9.420" -dependencies = [ - "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", - "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-message-queue", - "pallet-multisig", - "pallet-nft-fractionalization", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-proxy", - "pallet-session", - "pallet-state-trie-migration", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-uniques", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "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", - "sp-session", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "sp-weights", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - -[[package]] -name = "asset-hub-polkadot-runtime" -version = "0.9.420" -dependencies = [ - "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", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-uniques", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "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 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "sp-weights", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - [[package]] name = "asset-hub-rococo-emulated-chain" version = "0.0.0" @@ -1973,134 +1829,6 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "bridge-hub-kusama-runtime" -version = "0.1.0" -dependencies = [ - "bridge-hub-test-utils", - "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", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "scale-info", - "serde", - "smallvec", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - -[[package]] -name = "bridge-hub-polkadot-runtime" -version = "0.1.0" -dependencies = [ - "bridge-hub-test-utils", - "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", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "scale-info", - "serde", - "smallvec", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - [[package]] name = "bridge-hub-rococo-emulated-chain" version = "0.0.0" @@ -2861,78 +2589,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "collectives-polkadot-runtime" -version = "1.0.0" -dependencies = [ - "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", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-alliance", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-collective", - "pallet-collective-content", - "pallet-core-fellowship", - "pallet-message-queue", - "pallet-multisig", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-referenda", - "pallet-salary", - "pallet-scheduler", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "scale-info", - "smallvec", - "sp-api", - "sp-arithmetic", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - [[package]] name = "collectives-westend-runtime" version = "1.0.0" @@ -6248,51 +5904,6 @@ dependencies = [ "regex", ] -[[package]] -name = "glutton-runtime" -version = "1.0.0" -dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-timestamp", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "pallet-aura", - "pallet-glutton", - "pallet-message-queue", - "pallet-sudo", - "pallet-timestamp", - "parachains-common", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - [[package]] name = "glutton-westend-runtime" version = "1.0.0" @@ -12939,17 +12550,12 @@ name = "polkadot-parachain-bin" version = "1.1.0" 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", "bridge-hub-westend-runtime", "clap 4.4.6", - "collectives-polkadot-runtime", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -12970,7 +12576,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "futures", - "glutton-runtime", "glutton-westend-runtime", "hex-literal", "jsonrpsee", diff --git a/Cargo.toml b/Cargo.toml index f16c8393183..e154c2f3bc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,21 +77,15 @@ members = [ "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", - "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama", - "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot", "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", "cumulus/parachains/runtimes/bridge-hubs/test-utils", - "cumulus/parachains/runtimes/collectives/collectives-polkadot", "cumulus/parachains/runtimes/collectives/collectives-westend", "cumulus/parachains/runtimes/contracts/contracts-rococo", - "cumulus/parachains/runtimes/glutton/glutton-kusama", "cumulus/parachains/runtimes/glutton/glutton-westend", "cumulus/parachains/runtimes/starters/seedling", "cumulus/parachains/runtimes/starters/shell", diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/0_init.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/0_init.yml deleted file mode 100644 index fdc1aa258d4..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/0_init.yml +++ /dev/null @@ -1,145 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9900 - assets_parachain: &assets_parachain - wsPort: 9910 - paraId: &ap_id 1000 - penpal_parachain: &penpal_parachain - wsPort: 9920 - paraId: &pp_id 2000 - variables: - common: - xcm_version: &xcm_version 3 - require_weight_at_most: &weight_at_most {refTime: 1000000000, proofSize: 200000} - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - penpal_parachain: - signer: &pp_signer //Alice - decodedCalls: - ap_force_xcm_version: - chain: *assets_parachain - pallet: polkadotXcm - call: forceXcmVersion - args: [ - { # location - parents: 1, - interior: Here - }, - *xcm_version # xcmVersion - ] - -tests: - - name: Initialize Chains - its: - - name: XCM supported versions between chains - actions: - - extrinsics: # Relay Chain sets supported version for Asset Parachain - - chain: *relay_chain - sudo: true - signer: *rc_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *ap_id - } - } - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *ap_id }}}, version: *xcm_version } - - extrinsics: # Relay Chain sets supported version for Penpal Parachain - - chain: *relay_chain - sudo: true - signer: *rc_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *pp_id - } - } - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *pp_id }}}, version: *xcm_version } - - extrinsics: # Asset Parachain sets supported version for Relay Chain through it - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 2200000000, - proofSize: 200000 - } - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: *weight_at_most, - call: $ap_force_xcm_version - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { - outcome: { Complete: { refTime: '1,019,210,000', proofSize: '200,000' }} - } - - name: polkadotXcm.SupportedVersionChanged - chain: *assets_parachain - result: { location: { parents: 1, interior: Here }, version: *xcm_version } - - extrinsics: # Penpal Parachain sets supported version for Relay Chain - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: forceXcmVersion - args: [ - { # location - parents: 1, - interior: Here - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: polkadotXcm.SupportedVersionChanged - result: { location: { parents: 1, interior: Here }, version: *xcm_version } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/1_dmp.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/1_dmp.yml deleted file mode 100644 index 0e207e632a0..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/1_dmp.yml +++ /dev/null @@ -1,263 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9900 - assets_parachain: &assets_parachain - wsPort: 9910 - paraId: &ap_id 1000 - variables: - common: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - wallet: &rc_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - assets_parachain_destination: &ap_dest { v3: { parents: 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_account: &ap_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - assets_parachain_beneficiary: &ap_benf { v3: { parents: 0, interior: { x1: { accountId32: { id: *ap_acc }}}}} - ksm: &rc_ksm { concrete: { parents: 0, interior: { here: true }}} - amount: &amount 1000000000000 - ksm_fungible: &rc_ksm_fungible { id: *rc_ksm, fun: { fungible: *amount }} - require_weight_at_most: &rc_weight_at_most { refTime: 1000000000, proofSize: 200000 } - assets_parachain_account: - wallet: &ap_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - asset_id: &asset_id 1 - asset_min_balance: &asset_ed 1000 - decodedCalls: - force_create_asset: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - -tests: - - name: DMP - its: [] - describes: - - name: xcmPallet.limitedTeleportAssets - before: &before_get_balances - - name: Get the balances of the Relay Chain's sender & Assets Parachain's receiver - actions: - - queries: - balance_rc_sender_before: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_before: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - its: - - name: Should teleport native assets from the Relay Chain to the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedTeleportAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '764,772,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '166,944,000', proofSize: 0 }}} - - queries: - balance_rc_sender_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_rc_sender_before, - after: $balance_rc_sender_after, - }, - amount: *amount - } - ] - - - name: Should increase the balance of the receiver - actions: - - asserts: - balanceIncreased: - args: [ - { - balances: { - before: $balance_ap_receiver_before, - after: $balance_ap_receiver_after, - } - } - ] - - - name: xcmPallet.send | Superuser - Transact(assets.forceCreate) - its: - - name: Relay Chain Superuser account SHOULD be able to execute a XCM Transact instruction in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: *rc_weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '1,014,103,000', proofSize: '200,000' }}} - - queries: - forced_created_asset: - chain: *assets_parachain - pallet: assets - call: asset - args: [ *asset_id ] - - asserts: - isSome: - args: [ $forced_created_asset ] - - - name: xcmPallet.send | Native - Transact(assets.forceCreate) - its: - - name: Relay Chain Native account SHOULD NOT be able to execute a XCM Transact instruction in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Native, - requireWeightAtMost: *rc_weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: system.ExtrinsicFailed - result: { dispatchError: BadOrigin } - - - name: xcmPallet.limitedReserveTransferAssets - before: *before_get_balances - its: - - name: SHOULD NOT reserved transfer native assets from the Relay Chain to the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedReserveTransferAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '750,645,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { - outcome: { - Incomplete: [ - { refTime: '1,000,000,000', proofSize: 0 }, - UntrustedReserveLocation - ] - } - } - - queries: - balance_rc_sender_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_rc_sender_before, - after: $balance_rc_sender_after, - }, - amount: *amount - } - ] - - - name: Should keep the balance of the receiver - actions: - - asserts: - equal: - args: - [ - $balance_ap_receiver_before, - $balance_ap_receiver_after - ] diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/2_ump.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/2_ump.yml deleted file mode 100644 index 2a0bb88090e..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/2_ump.yml +++ /dev/null @@ -1,191 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9900 - assets_parachain: &assets_parachain - wsPort: 9910 - paraId: &ap_id 1000 - variables: - common: - amount: &amount 1000000000000 - require_weight_at_most: &weight_at_most {refTime: 1000000000, proofSize: 0} - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - wallet: &rc_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F #Alice - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_account: &ap_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - assets_parachain_beneficiary: &ap_benf {v3: { parents: 0, interior: { x1: { accountId32: { id: *ap_acc }}}}} - ksm: &rc_ksm { concrete: { 0, interior: { here: true }}} - ksm_fungible: &rc_ksm_fungible { id: *rc_ksm, fun: { fungible: *amount }} - assets_parachain_account: - signer: &ap_signer //Alice - wallet: &ap_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - relay_chain_destination: &rc_dest { v3: { parents: 1, interior: { here: true }}} - assets_parachain_account: &rc_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' #Alice - relay_chain_beneficiary: &rc_benf {v3: { parents: 0, interior: { x1: { accountId32: { id: *rc_acc }}}}} - ksm: &ap_ksm { concrete: { parents: 1, interior: { here: true }}} - ksm_fungible: &ap_ksm_fungible { id: *ap_ksm, fun: { fungible: *amount }} - decodedCalls: - system_remark: - chain: *relay_chain - pallet: system - call: remark - args: [ 0x0011 ] - -tests: - - name: UMP - describes: - - name: polkadotXcm.limitedTeleportAssets - before: - - name: DEPENDENCY | Do a 'limitedTeleportAssets' from the Relay Chain to the Assets Parachain to have funds to send them back - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedTeleportAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '761,173,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '166,944,000', proofSize: 0 }}} - - - name: Get the balances of the Assets Parachain's sender & Relay Chain's receiver - actions: - - queries: - balance_ap_sender_before: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - balance_rc_receiver_before: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - its: - - name: Should teleport native assets back from Assets Parachain to the Relay Chain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedTeleportAssets - args: [ - *rc_dest, # destination - *rc_benf, # beneficiary - { v3: [ *ap_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '539,494,000', proofSize: '7,133' }}} - - name: messageQueue.Processed - chain: *relay_chain - threshold: *weight_threshold - result: { origin: { Ump: { Para: '1,000' } }, weightUsed: { refTime: '298,716,000', proofSize: '0' }, success: true } - - queries: - balance_ap_sender_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - balance_rc_receiver_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_ap_sender_before, - after: $balance_ap_sender_after, - }, - amount: *amount - } - ] - - - name: Should increase the balance of the receiver - actions: - - asserts: - balanceIncreased: - args: [ - { - balances: { - before: $balance_rc_receiver_before, - after: $balance_rc_receiver_after, - } - } - ] - - - name: polkadotXcm.send | Native - Transact(system.remark) - its: - - name: Assets Parachain SHOULD NOT be able to dispatch 'send' call - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: send - args: [ - *rc_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Native, - requireWeightAtMost: *weight_at_most, - call: $system_remark - } - } - ] - } - ] - events: - - name: system.ExtrinsicFailed - result: { dispatchError: BadOrigin } - - - name: polkadotXcm.limitedReserveTransferAssets - its: - - name: Should NOT be able to reserve transfer native assets from the Assets Parachain to the Relay Chain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *rc_dest, # destination - *rc_benf, # beneficiary - { v3: [ *ap_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: polkadotXcm.Attempted - result: { outcome: { Error: Barrier }} diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/3_force_hrmp-open-channels.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/3_force_hrmp-open-channels.yml deleted file mode 100644 index dfdae028f00..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/3_force_hrmp-open-channels.yml +++ /dev/null @@ -1,122 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9900 - assets_parachain: - wsPort: 9910 - paraId: &ap_id 1000 - penpal_parachain: - wsPort: 9920 - paraId: &pp_id 2000 - variables: - common: - amount: &amount 2000000000000 - hrmp_channels: - proposed_max_capacity: &max_capacity 8 - proposed_max_message_size: &max_message_size 8192 - channel: &channel { - maxCapacity: *max_capacity, - maxTotalSize: *max_message_size, - maxMessageSize: *max_message_size, - msgCount: 0, - totalSize: 0, - mqcHead: null, - senderDeposit: 0, - recipientDeposit: 0 - } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_account: - sovereign_account: &ap_sovereign F7fq1jSNVTPfJmaHaXCMtatT1EZefCUsa7rRiQVNR5efcah - penpal_parachain: - sovereign_account: &pp_sovereign F7fq1jMZkfuCuoMTyiEVAP2DMpMt18WopgBqTJznLihLNbZ - -tests: - - name: HRMP - beforeEach: - - name: DEPENDENCY | Penpal Parachain Sovereign account in the Relay Chain needs to be funded - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: balances - call: transfer - args: [ - *pp_sovereign, # destination - *amount, # value - ] - events: - - name: balances.Transfer - - - name: DEPENDENCY | Assets Parachain Sovereign account in the Relay Chain needs to be funded - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: balances - call: transfer - args: [ - *ap_sovereign, # destination - *amount, # value - ] - events: - - name: balances.Transfer - describes: - - name: hrmp.forceOpenHrmpChannel (Penpal Parachain → Assets Parachain) - its: - - name: Open Penpal Parachain to Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *pp_id, - *ap_id, - *max_capacity, - *max_message_size - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: hrmp.HrmpChannelForceOpened - - - name: hrmp.forceOpenHrmpChannel (Assets Parachain → PenPal Parachain) - its: - - name: Open Assets Parachain to PenPal Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *ap_id, - *pp_id, - *max_capacity, - *max_message_size - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: hrmp.HrmpChannelForceOpened - - - name: hrmp.forceProcessHrmpOpen (make sure all the channels are open) - its: - - name: Make sure all the pending channels are open - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceProcessHrmpOpen - args: [ 2 ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/4_hrmp.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/4_hrmp.yml deleted file mode 100644 index 02e53da7558..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/0_xcm/4_hrmp.yml +++ /dev/null @@ -1,388 +0,0 @@ ---- -# Note: This tests depends on the 3_hrmp-open-channels.yml for opening channels, otherwise teleports aren't going to -# work. -settings: - chains: - relay_chain: &relay_chain - wsPort: 9900 - assets_parachain: &assets_parachain - wsPort: 9910 - paraId: &ap_id 1000 - penpal_parachain: &penpal_parachain - wsPort: 9920 - paraId: &pp_id 2000 - variables: - common: - mint_amount: &mint_amount 1000000000000 - amount: &amount 100000000000 - require_weight_at_most: &weight_at_most {refTime: 1200000000, proofSize: 20000} - amount_to_send: &amount_to_send 500000000000 - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_dest_routed: &ap_dest_routed { v3: { parents: 1, interior: { x1: { parachain: *ap_id } }}} - assets_parachain_account: - signer: &ap_signer //Alice - wallet: &ap_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - asset_id: &asset_id 2 - assets_pallet_id: &assets_pallet_id 50 - asset_min_balance: &asset_ed 1000 - penpal_parachain_destination: &pp_dest { v3: { parents: 1, interior: { x1: { parachain: *pp_id } }}} - ksm: &ap_ksm { concrete: { parents: 1, interior: { here: true }}} - ksm_fungible: &ap_ksm_fungible { id: *ap_ksm, fun: { fungible: *amount }} - suff_asset: &suff_asset { concrete: { parents: 0, interior: { x2: [ { PalletInstance: *assets_pallet_id }, { GeneralIndex: *asset_id } ] }}} - suff_asset_fail: &suff_asset_fail { concrete: { parents: 0, interior: { x2: [ { PalletInstance: *assets_pallet_id }, { GeneralIndex: 3 } ] }}} - suff_asset_fungible_fail: &ap_suff_asset_fungible_fail { id: *suff_asset_fail, fun: { fungible: 200000000000 }} - penpal_parachain: - sovereign_account: &pp_sovereign_sibl FBeL7EAeUroLWXW1yfKboiqTqVfbRBcsUKd6QqVf4kGBySS - signer: &pp_signer //Alice - penpal_parachain_account: &pp_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - decodedCalls: - force_create_asset: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - force_create_asset2: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - -tests: - - name: HRMP - describes: - - name: polkadotXcm.limitedReserveTransferAssets (Asset) | Assets Parachain -> Penpal Parachain - before: - - name: DEPENDENCY | A sufficient Asset should exist in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - SetTopic: '0x0123456789012345678901234567891201234567890123456789012345678912' - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '1,216,703,000', proofSize: '20,000' }}} - - queries: - forced_created_asset: - chain: *assets_parachain - pallet: assets - call: asset - args: [ *asset_id ] - - asserts: - isSome: - args: [ $forced_created_asset ] - - - name: DEPENDENCY | Some Assets should be minted for the sender - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: assets - call: mint - args: [ - *asset_id, - *ap_wallet, - *mint_amount - ] - events: - - name: assets.Issued - result: { assetId: *asset_id, owner: *ap_wallet, amount: *mint_amount } - - its: - - name: Assets Parachain should be able to reserve transfer an Asset to Penpal Parachain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *pp_dest, # destination - { # beneficiary - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - id: *pp_acc - } - } - } - } - }, - { # assets - V3: [ - { - id: { - Concrete: { - parents: 0, - interior: { - X2: [ - { - PalletInstance: *assets_pallet_id - }, - { - GeneralIndex: *asset_id - } - ] - } - } - }, - fun: { - Fungible: *amount_to_send - } - } - ] - }, - 0, # feeAssetItem - Unlimited # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '679,150,000', proofSize: '6,196' }}} - - name: assets.Transferred - result: { - assetId: *asset_id, - from: *ap_wallet, - to: *pp_sovereign_sibl, - amount: *amount_to_send - } - - - name: polkadotXcm.limitedReserveTransferAssets (KSM) | Assets Parachain -> Penpal Parachain - its: - - name: Assets Parachain should be able to reserve transfer KSM to Penpal Parachain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *pp_dest, # destination - { # beneficiary - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - id: *pp_acc - } - } - } - } - }, - { # assets - V3: [ - *ap_ksm_fungible - ] - }, - 0, # feeAssetItem - Unlimited # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '679,150,000', proofSize: '6,196' }}} - - name: balances.Endowed - result: { - account: *pp_sovereign_sibl, - freeBalance: *amount - } - - - name: polkadotXcm.send( assets.forceCreateAsset ) | Penpal Parachain -> Assets Parachain - before: - - name: Get the asset balance of the Penpal Parachain Sovereign account in Assets Parachain - actions: - - queries: - assets_balance_pp_sovereign_before: - chain: *assets_parachain - pallet: assets - call: account - args: [ - *asset_id, - *pp_sovereign_sibl - ] - its: - - name: Penpal Parachain should be able to send XCM message paying its fee with sufficient asset in Assets Parachain - actions: - - extrinsics: - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: send - args: [ - *ap_dest_routed, # destination - { - v3: [ #message - { - WithdrawAsset: [ - { - id: { - concrete: { - parents: 0, - interior: { - X2: [ - { PalletInstance: *assets_pallet_id }, - { GeneralIndex: *asset_id } - ] - } - } - }, - fun: { fungible: *amount }} - ] - }, - { - BuyExecution: { - fees: { id: *suff_asset, fun: { fungible: *amount }}, - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: SovereignAccount, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset2 - } - }, - { - RefundSurplus - }, - { - DepositAsset: { - assets: { Wild: All }, - beneficiary: { - parents: 0, - interior: { - X1: { - AccountId32: { - network: , # None - id: *pp_acc - } - } - }} - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: polkadotXcm.Sent - - name: assets.Burned - chain: *assets_parachain - result: { assetId: *asset_id, owner: *pp_sovereign_sibl } - - name: assets.Issued - chain: *assets_parachain - result: { assetId: *asset_id } - - queries: - assets_balance_pp_sovereign_after: - chain: *assets_parachain - pallet: assets - call: account - args: [ - *asset_id, - *pp_sovereign_sibl - ] - forced_created_asset2: - chain: *assets_parachain - pallet: assets - call: asset - args: [ 3 ] - - asserts: - isSome: - args: [ $forced_created_asset2 ] - - name: Should reduce the assets balance of the Penpal Parachain's SovereignAccount in the Assets Parachain - actions: - - asserts: - assetsDecreased: - args: [ - { - balances: { - before: $assets_balance_pp_sovereign_before, - after: $assets_balance_pp_sovereign_after, - }, - } - ] - - - name: Penpal Parachain SHOULD NOT be able to send XCM message paying its fee with sufficient assets if not enough balance - actions: - - extrinsics: - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: send - args: [ - *ap_dest_routed, # destination - { - v3: [ #message - { - WithdrawAsset: [*ap_suff_asset_fungible_fail] - }, - { - BuyExecution: { - fees: *ap_suff_asset_fungible_fail, - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: SovereignAccount, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset2 - } - } - ] - } - ] - events: - - name: xcmpQueue.Fail - chain: *assets_parachain - threshold: *weight_threshold - result: { - error: FailedToTransactAsset, - weight: { refTime: '152,426,000', proofSize: '3,593' } - } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/config.toml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/config.toml deleted file mode 100644 index 1ec06b3fa10..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-kusama/config.toml +++ /dev/null @@ -1,71 +0,0 @@ -[relaychain] -default_command = "./bin/polkadot" -default_args = [ "-lparachain=debug", "-lxcm=trace" ] -chain = "kusama-local" - - [[relaychain.nodes]] - name = "alice" - ws_port = 9900 - validator = true - args = ["--state-cache-size=0"] - - [[relaychain.nodes]] - name = "bob" - ws_port = 9901 - validator = true - - [[relaychain.nodes]] - name = "charlie" - ws_port = 9902 - validator = true - - [[relaychain.nodes]] - name = "dave" - ws_port = 9903 - validator = true - -[[parachains]] -id = 1000 -chain = "asset-hub-kusama-local" -cumulus_based = true - - [[parachains.collators]] - name = "collator1" - ws_port = 9910 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace", "--state-cache-size=0" ] - - [[parachains.collators]] - name = "collator2" - ws_port = 9911 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace" ] - -[[parachains]] -id = 2000 -chain = "penpal-kusama-2000" -cumulus_based = true - - [[parachains.collators]] - name = "collator3" - ws_port = 9920 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace", "--state-cache-size=0" ] - - [[parachains.collators]] - name = "collator4" - ws_port = 9921 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace" ] - -# [[hrmpChannels]] -# sender = 1000 -# recipient = 2000 -# maxCapacity = 8 -# maxMessageSize = 8192 - -# [[hrmpChannels]] -# sender = 2000 -# recipient = 1000 -# maxCapacity = 8 -# maxMessageSize = 8192 diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/0_init.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/0_init.yml deleted file mode 100644 index a6d3fb3ec83..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/0_init.yml +++ /dev/null @@ -1,145 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9800 - assets_parachain: &assets_parachain - wsPort: 9810 - paraId: &ap_id 1000 - penpal_parachain: &penpal_parachain - wsPort: 9820 - paraId: &pp_id 2000 - variables: - common: - xcm_version: &xcm_version '3' - require_weight_at_most: &weight_at_most {refTime: 1000000000, proofSize: 200000} - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - penpal_parachain: - signer: &pp_signer //Alice - decodedCalls: - ap_force_xcm_version: - chain: *assets_parachain - pallet: polkadotXcm - call: forceXcmVersion - args: [ - { # location - parents: 1, - interior: Here - }, - *xcm_version # xcmVersion - ] - -tests: - - name: Initialize Chains - its: - - name: XCM supported versions between chains - actions: - - extrinsics: # Relay Chain sets supported version for Asset Parachain - - chain: *relay_chain - sudo: true - signer: *rc_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *ap_id - } - } - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *ap_id }}}, version: *xcm_version } - - extrinsics: # Relay Chain sets supported version for Penpal Parachain - - chain: *relay_chain - sudo: true - signer: *rc_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *pp_id - } - } - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *pp_id }}}, version: *xcm_version } - - extrinsics: # Asset Parachain sets supported version for Relay Chain through it - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 3200000000, - proofSize: 200000 - } - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: *weight_at_most, - call: $ap_force_xcm_version - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { - outcome: { Complete: { refTime: '1,019,210,000', proofSize: '200,000' }} - } - - name: polkadotXcm.SupportedVersionChanged - chain: *assets_parachain - result: { location: { parents: 1, interior: Here }, version: *xcm_version } - - extrinsics: # Penpal Parachain sets supported version for Relay Chain - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: forceXcmVersion - args: [ - { # location - parents: 1, - interior: Here - }, - *xcm_version # xcmVersion - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: polkadotXcm.SupportedVersionChanged - result: { location: { parents: 1, interior: Here}, version: *xcm_version } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/1_dmp.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/1_dmp.yml deleted file mode 100644 index 36b296f3eb1..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/1_dmp.yml +++ /dev/null @@ -1,263 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9800 - assets_parachain: &assets_parachain - wsPort: 9810 - paraId: &ap_id 1000 - variables: - common: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - wallet: &rc_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - assets_parachain_destination: &ap_dest { v3: { parents: 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_account: &ap_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - assets_parachain_beneficiary: &ap_benf {v3: { parents: 0, interior: { x1: { accountId32: { id: *ap_acc }}}}} - ksm: &rc_ksm { concrete: { parents: 0, interior: { here: true }}} - amount: &amount 1000000000000 - ksm_fungible: &rc_ksm_fungible { id: *rc_ksm, fun: { fungible: *amount }} - require_weight_at_most: &rc_weight_at_most {refTime: 1000000000, proofSize: 200000} - assets_parachain_account: - wallet: &ap_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - asset_id: &asset_id 1 - asset_min_balance: &asset_ed 1000 - decodedCalls: - force_create_asset: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - -tests: - - name: DMP - its: [] - describes: - - name: xcmPallet.limitedTeleportAssets - before: &before_get_balances - - name: Get the balances of the Relay Chain's sender & Assets Parachain's receiver - actions: - - queries: - balance_rc_sender_before: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_before: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - its: - - name: Should teleport native assets from the Relay Chain to the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedTeleportAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '166,944,000', proofSize: 0 }}} - - queries: - balance_rc_sender_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_rc_sender_before, - after: $balance_rc_sender_after, - }, - amount: *amount - } - ] - - - name: Should increase the balance of the receiver - actions: - - asserts: - balanceIncreased: - args: [ - { - balances: { - before: $balance_ap_receiver_before, - after: $balance_ap_receiver_after, - } - } - ] - - - name: xcmPallet.send | Superuser - Transact(assets.forceCreate) - its: - - name: Relay Chain Superuser account SHOULD be able to execute a XCM Transact instruction in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originType: Superuser, - requireWeightAtMost: *rc_weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '1,014,103,000', proofSize: '200,000' }}} - - queries: - forced_created_asset: - chain: *assets_parachain - pallet: assets - call: asset - args: [ *asset_id ] - - asserts: - isSome: - args: [ $forced_created_asset ] - - - name: xcmPallet.send | Native - Transact(assets.forceCreate) - its: - - name: Relay Chain Native account SHOULD NOT be able to execute a XCM Transact instruction in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originType: Native, - requireWeightAtMost: *rc_weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: system.ExtrinsicFailed - result: { dispatchError: BadOrigin } - - - name: xcmPallet.limitedReserveTransferAssets - before: *before_get_balances - its: - - name: SHOULD NOT reserved transfer native assets from the Relay Chain to the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedReserveTransferAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '2,000,000,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { - outcome: { - Incomplete: [ - { refTime: '1,000,000,000', proofSize: 0 }, - UntrustedReserveLocation - ] - } - } - - queries: - balance_rc_sender_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - balance_ap_receiver_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_rc_sender_before, - after: $balance_rc_sender_after, - }, - amount: *amount - } - ] - - - name: Should keep the balance of the receiver - actions: - - asserts: - equal: - args: - [ - $balance_ap_receiver_before, - $balance_ap_receiver_after - ] diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/2_ump.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/2_ump.yml deleted file mode 100644 index fa84d4b006a..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/2_ump.yml +++ /dev/null @@ -1,194 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9800 - assets_parachain: &assets_parachain - wsPort: 9810 - paraId: &ap_id 1000 - variables: - common: - amount: &amount 1000000000000 - require_weight_at_most: &weight_at_most {refTime: 1000000000, proofSize: 0} - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - wallet: &rc_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_account: &ap_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - assets_parachain_beneficiary: &ap_benf {v3: { parents: 0, interior: { x1: { accountId32: { id: *ap_acc }}}}} - ksm: &rc_ksm { concrete: { 0, interior: { here: true }}} - ksm_fungible: &rc_ksm_fungible { id: *rc_ksm, fun: { fungible: *amount }} - assets_parachain_account: - signer: &ap_signer //Alice - wallet: &ap_wallet HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F - relay_chain_destination: &rc_dest { v3: { parents: 1, interior: { here: true }}} - assets_parachain_account: &rc_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - relay_chain_beneficiary: &rc_benf {v3: { parents: 0, interior: { x1: { accountId32: { id: *rc_acc }}}}} - ksm: &ap_ksm { concrete: { parents: 1, interior: { here: true }}} - ksm_fungible: &ap_ksm_fungible { id: *ap_ksm, fun: { fungible: *amount }} - decodedCalls: - system_remark: - chain: *relay_chain - pallet: system - call: remark - args: [ 0x0011 ] - -tests: - - name: UMP - describes: - - name: polkadotXcm.limitedTeleportAssets - before: - - name: DEPENDENCY | Do a 'limitedTeleportAssets' from the Relay Chain to the Assets Parachain to have funds to send them back - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: xcmPallet - call: limitedTeleportAssets - args: [ - *ap_dest, # destination - *ap_benf, # beneficiary - { v3: [ *rc_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '166,944,000', proofSize: 0 }}} - - - name: Get the balances of the Assets Parachain's sender & Relay Chain's receiver - actions: - - queries: - balance_ap_sender_before: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - balance_rc_receiver_before: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - - its: - - name: Should be able to teleport native assets back from Assets Parachain to the Relay Chain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedTeleportAssets - args: [ - *rc_dest, # destination - *rc_benf, # beneficiary - { v3: [ *ap_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '533,283,000', proofSize: '7,096' }}} - - name: messageQueue.Processed - chain: *relay_chain - threshold: *weight_threshold - result: { origin: { Ump: { Para: '1,000' } }, weightUsed: { refTime: '4,000,000,000', proofSize: '0' }, success: true } - - queries: - balance_ap_sender_after: - chain: *assets_parachain - pallet: system - call: account - args: [ *ap_wallet ] - balance_rc_receiver_after: - chain: *relay_chain - pallet: system - call: account - args: [ *rc_wallet ] - - - name: Should reduce the balance of the sender - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_ap_sender_before, - after: $balance_ap_sender_after, - }, - amount: *amount - } - ] - - - name: Should increase the balance of the receiver - actions: - - asserts: - balanceIncreased: - args: [ - { - balances: { - before: $balance_rc_receiver_before, - after: $balance_rc_receiver_after, - } - } - ] - - - name: polkadotXcm.send | Native - Transact(system.remark) - its: - - name: Assets Parachain SHOULD NOT be able to dispatch 'send' call - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: send - args: [ - *rc_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originType: Native, - requireWeightAtMost: *weight_at_most, - call: $system_remark - } - } - ] - } - ] - events: - - name: system.ExtrinsicFailed - attributes: - - type: SpRuntimeDispatchError - value: BadOrigin - - - name: polkadotXcm.limitedReserveTransferAssets - its: - - name: Should NOT be able to reserve transfer native assets from the Assets Parachain to the Relay Chain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *rc_dest, # destination - *rc_benf, # beneficiary - { v3: [ *ap_ksm_fungible ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: polkadotXcm.Attempted - result: { outcome: { Error: Barrier }} diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/3_force_hrmp-open-channels.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/3_force_hrmp-open-channels.yml deleted file mode 100644 index ecf344a073b..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/3_force_hrmp-open-channels.yml +++ /dev/null @@ -1,120 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9800 - assets_parachain: - wsPort: 9810 - paraId: &ap_id 1000 - penpal_parachain: - wsPort: 9820 - paraId: &pp_id 2000 - variables: - common: - amount: &amount 2000000000000 - hrmp_channels: - proposed_max_capacity: &max_capacity 8 - proposed_max_message_size: &max_message_size 8192 - channel: &channel { - maxCapacity: *max_capacity, - maxTotalSize: *max_message_size, - maxMessageSize: *max_message_size, - msgCount: 0, - totalSize: 0, - mqcHead: null, - senderDeposit: 0, - recipientDeposit: 0 - } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_account: - sovereign_account: &ap_sovereign 5Ec4AhPZk8STuex8Wsi9TwDtJQxKqzPJRCH7348Xtcs9vZLJ - penpal_parachain: - sovereign_account: &pp_sovereign F7fq1jMZkfuCuoMTyiEVAP2DMpMt18WopgBqTJznLihLNbZ - -tests: - - name: HRMP - beforeEach: - - name: DEPENDENCY | Penpal Parachain Sovereign account in the Relay Chain needs to be funded - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: balances - call: transfer - args: [ - *pp_sovereign, # destination - *amount, # value - ] - events: - - name: balances.Transfer - - - name: DEPENDENCY | Assets Parachain Sovereign account in the Relay Chain needs to be funded - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - pallet: balances - call: transfer - args: [ - *ap_sovereign, # destination - *amount, # value - ] - events: - - name: balances.Transfer - describes: - - name: hrmp.hrmpInitOpenChannel (Penpal Parachain → Assets Parachain) - its: - - name: Open Penpal Parachain to Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *pp_id, - *ap_id, - *max_capacity, - *max_message_size - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: hrmp.HrmpChannelForceOpened - - name: hrmp.hrmpInitOpenChannel (Assets Parachain → PenPal Parachain) - its: - - name: Open Assets Parachain to PenPal Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *ap_id, - *pp_id, - *max_capacity, - *max_message_size - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: hrmp.HrmpChannelForceOpened - - name: hrmp.forceProcessHrmpOpen (make sure all the channels are open) - its: - - name: Make sure all the pending channels are open - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: hrmp - call: forceProcessHrmpOpen - args: [ 2 ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/4_hrmp.yml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/4_hrmp.yml deleted file mode 100644 index 681af698c16..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/0_xcm/4_hrmp.yml +++ /dev/null @@ -1,388 +0,0 @@ ---- -# Note: This tests depends on the 3_hrmp-open-channels.yml for opening channels, otherwise teleports aren't going to -# work. -settings: - chains: - relay_chain: &relay_chain - wsPort: 9800 - assets_parachain: &assets_parachain - wsPort: 9810 - paraId: &ap_id 1000 - penpal_parachain: &penpal_parachain - wsPort: 9820 - paraId: &pp_id 2000 - variables: - common: - mint_amount: &mint_amount 1000000000000 - amount: &amount 1000000000000 - require_weight_at_most: &weight_at_most {refTime: 1200000000, proofSize: 20000} - amount_to_send: &amount_to_send 500000000000 - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - relay_chain: - signer: &rc_signer //Alice - assets_parachain_destination: &ap_dest { v3: { 0, interior: { x1: { parachain: *ap_id }}}} - assets_parachain_dest_routed: &ap_dest_routed { v3: { parents: 1, interior: { x1: { parachain: *ap_id } }}} - assets_parachain_account: - signer: &ap_signer //Alice - wallet: &ap_wallet 15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5 - asset_id: &asset_id 2 - assets_pallet_id: &assets_pallet_id 50 - asset_min_balance: &asset_ed 1000 - penpal_parachain_destination: &pp_dest { v3: { parents: 1, interior: { x1: { parachain: *pp_id } }}} - ksm: &ap_ksm { concrete: { parents: 1, interior: { here: true }}} - ksm_fungible: &ap_ksm_fungible { id: *ap_ksm, fun: { fungible: *amount }} - suff_asset: &suff_asset { concrete: { parents: 0, interior: { x2: [ { PalletInstance: *assets_pallet_id }, { GeneralIndex: *asset_id } ] }}} - suff_asset_fail: &suff_asset_fail { concrete: { parents: 0, interior: { x2: [ { PalletInstance: *assets_pallet_id }, { GeneralIndex: 3 } ] }}} - suff_asset_fungible_fail: &ap_suff_asset_fungible_fail { id: *suff_asset_fail, fun: { fungible: 200000000000 }} - penpal_parachain: - sovereign_account: &pp_sovereign_sibl 13cKp89Msu7M2PiaCuuGr1BzAsD5V3vaVbDMs3YtjMZHdGwR - signer: &pp_signer //Alice - penpal_parachain_account: &pp_acc '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - decodedCalls: - force_create_asset: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - force_create_asset2: - chain: *assets_parachain - pallet: assets - call: forceCreate - args: [ - *asset_id, - { Id: *ap_wallet }, # owner - true, # isSufficient - *asset_ed # minBalance - ] - -tests: - - name: HRMP - describes: - - name: polkadotXcm.limitedReserveTransferAssets (Asset) | Assets Parachain -> Penpal Parachain - before: - - name: DEPENDENCY | A sufficient Asset should exist in the Assets Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *rc_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - *ap_dest, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - SetTopic: '0x0123456789012345678901234567891201234567890123456789012345678912' - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset - } - } - ] - } - ] - events: - - name: xcmPallet.Sent - - name: dmpQueue.ExecutedDownward - chain: *assets_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '1,216,703,000', proofSize: '20,000' }}} - - queries: - forced_created_asset: - chain: *assets_parachain - pallet: assets - call: asset - args: [ *asset_id ] - - asserts: - isSome: - args: [ $forced_created_asset ] - - - name: DEPENDENCY | Some Assets should be minted for the sender - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: assets - call: mint - args: [ - *asset_id, - *ap_wallet, - *mint_amount - ] - events: - - name: assets.Issued - result: { assetId: *asset_id, owner: *ap_wallet, amount: *mint_amount } - - its: - - name: Assets Parachain should be able to reserve transfer an Asset to Penpal Parachain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *pp_dest, # destination - { # beneficiary - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - id: *pp_acc - } - } - } - } - }, - { # assets - V3: [ - { - id: { - Concrete: { - parents: 0, - interior: { - X2: [ - { - PalletInstance: *assets_pallet_id - }, - { - GeneralIndex: *asset_id - } - ] - } - } - }, - fun: { - Fungible: *amount_to_send - } - } - ] - }, - 0, # feeAssetItem - Unlimited # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '673,627,000', proofSize: '6,196' }}} - - name: assets.Transferred - result: { - assetId: *asset_id, - from: *ap_wallet, - to: *pp_sovereign_sibl, - amount: *amount_to_send - } - - - name: polkadotXcm.limitedReserveTransferAssets (KSM) | Assets Parachain -> Penpal Parachain - its: - - name: Assets Parachain should be able to reserve transfer KSM to Penpal Parachain - actions: - - extrinsics: - - chain: *assets_parachain - signer: *ap_signer - pallet: polkadotXcm - call: limitedReserveTransferAssets - args: [ - *pp_dest, # destination - { # beneficiary - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - id: *pp_acc - } - } - } - } - }, - { # assets - V3: [ - *ap_ksm_fungible - ] - }, - 0, # feeAssetItem - Unlimited # weightLimit - ] - events: - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '679,150,000', proofSize: '6,196' }}} - - name: balances.Endowed - result: { - account: *pp_sovereign_sibl, - freeBalance: *amount - } - - - name: polkadotXcm.send( assets.forceCreateAsset ) | Penpal Parachain -> Assets Parachain - before: - - name: Get the asset balance of the Penpal Parachain Sovereign account in Assets Parachain - actions: - - queries: - assets_balance_pp_sovereign_before: - chain: *assets_parachain - pallet: assets - call: account - args: [ - *asset_id, - *pp_sovereign_sibl - ] - its: - - name: Penpal Parachain should be able to send XCM message paying its fee with sufficient asset in Assets Parachain - actions: - - extrinsics: - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: send - args: [ - *ap_dest_routed, # destination - { - v3: [ #message - { - WithdrawAsset: [ - { - id: { - concrete: { - parents: 0, - interior: { - X2: [ - { PalletInstance: *assets_pallet_id }, - { GeneralIndex: *asset_id } - ] - } - } - }, - fun: { fungible: *amount_to_send }} - ] - }, - { - BuyExecution: { - fees: { id: *suff_asset, fun: { fungible: *amount_to_send }}, - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: SovereignAccount, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset2 - } - }, - { - RefundSurplus - }, - { - DepositAsset: { - assets: { Wild: All }, - beneficiary: { - parents: 0, - interior: { - X1: { - AccountId32: { - network: , # None - id: *pp_acc - } - } - }} - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: polkadotXcm.Sent - - name: assets.Burned - chain: *assets_parachain - result: { assetId: *asset_id, owner: *pp_sovereign_sibl } - - name: assets.Issued - chain: *assets_parachain - result: { assetId: *asset_id } - - queries: - assets_balance_pp_sovereign_after: - chain: *assets_parachain - pallet: assets - call: account - args: [ - *asset_id, - *pp_sovereign_sibl - ] - forced_created_asset2: - chain: *assets_parachain - pallet: assets - call: asset - args: [ 3 ] - - asserts: - isSome: - args: [ $forced_created_asset2 ] - - name: Should reduce the assets balance of the Penpal Parachain's SovereignAccount in the Assets Parachain - actions: - - asserts: - assetsDecreased: - args: [ - { - balances: { - before: $assets_balance_pp_sovereign_before, - after: $assets_balance_pp_sovereign_after, - }, - } - ] - - - name: Penpal Parachain SHOULD NOT be able to send XCM message paying its fee with sufficient assets if not enough balance - actions: - - extrinsics: - - chain: *penpal_parachain - signer: *pp_signer - sudo: true - pallet: polkadotXcm - call: send - args: [ - *ap_dest_routed, # destination - { - v3: [ #message - { - WithdrawAsset: [*ap_suff_asset_fungible_fail] - }, - { - BuyExecution: { - fees: *ap_suff_asset_fungible_fail, - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: SovereignAccount, - requireWeightAtMost: *weight_at_most, - call: $force_create_asset2 - } - } - ] - } - ] - events: - - name: xcmpQueue.Fail - chain: *assets_parachain - threshold: *weight_threshold - result: { - error: FailedToTransactAsset, - weight: { refTime: '152,426,000', proofSize: '3,593' } - } diff --git a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/config.toml b/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/config.toml deleted file mode 100644 index da53cd0ad4f..00000000000 --- a/cumulus/parachains/integration-tests/e2e/assets/asset-hub-polkadot/config.toml +++ /dev/null @@ -1,72 +0,0 @@ -[relaychain] -default_command = "./bin/polkadot" -default_args = [ "-lparachain=debug", "-lxcm=trace" ] -chain = "polkadot-local" - - [[relaychain.nodes]] - name = "alice" - ws_port = 9800 - validator = true - args = ["--state-cache-size=0"] - - [[relaychain.nodes]] - name = "bob" - ws_port = 9801 - validator = true - - [[relaychain.nodes]] - name = "charlie" - ws_port = 9802 - validator = true - - [[relaychain.nodes]] - name = "dave" - ws_port = 9803 - validator = true - -[[parachains]] -id = 1000 -chain = "asset-hub-polkadot-local" -cumulus_based = true - - [[parachains.collators]] - name = "collator1" - ws_port = 9810 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace", "--state-cache-size=0" ] - - [[parachains.collators]] - name = "collator2" - ws_port = 9811 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace" ] - - -[[parachains]] -id = 2000 -chain = "penpal-polkadot-2000" -cumulus_based = true - - [[parachains.collators]] - name = "collator3" - ws_port = 9820 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace", "--state-cache-size=0" ] - - [[parachains.collators]] - name = "collator4" - ws_port = 9821 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace" ] - -# [[hrmpChannels]] -# sender = 1000 -# recipient = 2000 -# maxCapacity = 8 -# maxMessageSize = 8192 - -# [[hrmpChannels]] -# sender = 2000 -# recipient = 1000 -# maxCapacity = 8 -# maxMessageSize = 8192 diff --git a/cumulus/parachains/integration-tests/e2e/collectives/README.md b/cumulus/parachains/integration-tests/e2e/collectives/README.md deleted file mode 100644 index 9c4efe7c950..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/README.md +++ /dev/null @@ -1,26 +0,0 @@ -E2E tests concerning Polkadot Governance and the Collectives Parachain. The tests run by the Parachain Integration Tests -[tool](https://github.com/paritytech/parachains-integration-tests/). - -# Requirements -The tests require some changes to the regular production runtime builds: - -## RelayChain runtime -1. Alice has SUDO -2. Public Referenda `StakingAdmin`, `FellowshipAdmin` tracks settings (see the corresponding keys of the `TRACKS_DATA` - constant in the `governance::tracks` module of the Relay Chain runtime crate): -``` yaml -prepare_period: 5 Block, -decision_period: 1 Block, -confirm_period: 1 Block, -min_enactment_period: 1 Block, -``` - -## Collectives runtime -1. Fellowship Referenda `Fellows` track settings (see the corresponding key of the `TRACKS_DATA` constant in the - `fellowship::tracks` module of the Collectives runtime crate): -``` yaml -prepare_period: 5 Block, -decision_period: 1 Block, -confirm_period: 1 Block, -min_enactment_period: 1 Block, -``` diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/0_init.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/0_init.yml deleted file mode 100644 index 33f4d603e2a..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/0_init.yml +++ /dev/null @@ -1,166 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - assethub_parachain: &assethub_parachain - wsPort: 9810 - paraId: &sp_id 1000 - variables: - xcm_version: &xcm_version 3 - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - accounts: - alice_signer: &alice_signer //Alice - decodedCalls: - ap_force_xcm_version: - chain: *collectives_parachain - pallet: polkadotXcm - call: forceXcmVersion - args: [ - { # location - parents: 1, - interior: Here - }, - *xcm_version - ] - -tests: - - name: Initialize Chains - its: - - name: XCM supported versions between chains - actions: - - extrinsics: # Relay Chain sets supported version for Collectives Parachain - - chain: *relay_chain - sudo: true - signer: *alice_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *cp_id - } - } - }, - *xcm_version - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *cp_id }}}, version: *xcm_version } - - extrinsics: # Collectives Parachain sets supported version for Relay Chain through it - - chain: *relay_chain - signer: *alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 2200000000, # 2_200_000_000 - proofSize: 200000, # 200_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 200000000, # 200_000_000 - proofSize: 0, - }, - call: $ap_force_xcm_version - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - - name: polkadotXcm.SupportedVersionChanged - chain: *collectives_parachain - result: { location: { parents: 1, interior: Here }, version: *xcm_version } - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '2,200,000,000', proofSize: 0 }}} - - extrinsics: # Relay Chain sets supported version for AssetHub Parachain - - chain: *relay_chain - sudo: true - signer: *alice_signer - pallet: xcmPallet - call: forceXcmVersion - args: [ - { # location - parents: 0, - interior: { - X1: { - Parachain: *sp_id - } - } - }, - *xcm_version - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.SupportedVersionChanged - result: { location: { parents: 0, interior: { X1: { Parachain: *sp_id } } }, version: *xcm_version } - - extrinsics: # AssetHub Parachain sets supported version for Relay Chain through it - - chain: *relay_chain - signer: *alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { 0, interior: { x1: { parachain: *sp_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 2200000000, # 2_200_000_000 - proofSize: 200000, # 200_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 200000000, # 200_000_000 - proofSize: 0, - }, - call: $ap_force_xcm_version - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - - name: polkadotXcm.SupportedVersionChanged - chain: *assethub_parachain - result: { location: { parents: 1, interior: Here }, version: *xcm_version } - - name: dmpQueue.ExecutedDownward - chain: *assethub_parachain - result: { outcome: { Complete: {} } } diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/1_teleport.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/1_teleport.yml deleted file mode 100644 index cda04859b19..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/1_teleport.yml +++ /dev/null @@ -1,168 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - variables: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - accounts: - alice_signer: &acc_alice_signer //Alice - alice_account32: &acc_alice_acc32 '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - alice_ss58: &acc_alice_ss58 '15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5' - checking_account: &checking_account '13UVJyLnbVp9x5XDyJv8g8r3UddNwBrdaH7AADCmw9XQWvYW' - -tests: - - name: Teleport assets from Relay Chain to Collectives Parachain successful. - before: - - name: Get the Alice balances on Relay & Collectives Chains. - actions: - - queries: - balance_rc_alice_1: - chain: *relay_chain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - balance_cp_alice_1: - chain: *collectives_parachain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - its: - - name: Teleport assets from Relay Chain to Collectives Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - pallet: xcmPallet - call: teleportAssets - args: [ - { v3: { 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { v3: { parents: 0, interior: { x1: { accountId32: { id: *acc_alice_acc32 }}}}}, # beneficiary - { - v3: [ - # { - # # TODO use a separate Assets to pay a fee, to receive an exact amount of assets on beneficiary account. - # # a call with two assets fails with an error right now. - # id: { concrete: { 0, interior: { here: true }}}, - # fun: { fungible: 1000000000000 } # 1_000_000_000_000 - # }, - { - id: { concrete: { 0, interior: { here: true }}}, - fun: { fungible: 20000000000000 } # 20_000_000_000_000 - } - ] - }, # assets - 0, # feeAssetItem - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '4,000,000,000', proofSize: 0 }}} - - queries: - balance_rc_alice_2: - chain: *relay_chain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - balance_cp_alice_2: - chain: *collectives_parachain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - - name: Alice deposit check, balance decreased on Relay Chain, increased on Collectives. - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_rc_alice_1, - after: $balance_rc_alice_2, - } - } - ] - balanceIncreased: - args: [ - { - balances: { - before: $balance_cp_alice_1, - after: $balance_cp_alice_2, - } - } - ] - - - name: Teleport assets from Collectives Parachain to Relay Chain successful - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *acc_alice_signer - pallet: polkadotXcm - call: teleportAssets - args: [ - { v3: { parents: 1, interior: { here: true }}}, # destination - { v3: { parents: 0, interior: { x1: { accountId32: { id: *acc_alice_acc32 }}}}}, # beneficiary - { - v3: [ - { - id: { concrete: { parents: 1, interior: { here: true }}}, - fun: { fungible: 10000000000000 } # 10_000_000_000_000 - } - ] - }, # assets - 0, # feeAssetItem - ] - events: - - name: balances.Withdraw - result: { who: *acc_alice_ss58, amount: 10000000000000 } - - name: polkadotXcm.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: 0 }}} - - name: balances.Withdraw - chain: *relay_chain - result: { who: *checking_account, amount: 10000000000000 } # amount received and withdrawn from registry account - - name: messageQueue.Processed - chain: *relay_chain - threshold: *weight_threshold - result: { origin: { Ump: { Para: *cp_id } }, weightUsed: { refTime: '4,000,000,000', proofSize: '0' }, success: true } - - queries: - balance_rc_alice_3: - chain: *relay_chain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - balance_cp_alice_3: - chain: *collectives_parachain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - - - name: Alice deposit check, balance decreased on Collectives, increased on Relay Chain. - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_cp_alice_2, - after: $balance_cp_alice_3, - } - } - ] - balanceIncreased: - args: [ - { - balances: { - before: $balance_rc_alice_2, - after: $balance_rc_alice_3, - } - } - ] -# TODO (P2) assert Alice balance before and after teleport (see example in kick_member test) -# TODO (P1) test: teleport of non relay chain assets fails diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/2_reserve.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/2_reserve.yml deleted file mode 100644 index bd17f07524a..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/2_reserve.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - variables: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - chains: - accounts: - alice_signer: &alice_signer //Alice - alice_account32: &alice_acc32 '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - -tests: - - name: Reserve assets from Relay Chain to Collectives Parachain fails - its: - - name: Reserve assets from Relay Chain to Collectives Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: xcmPallet - call: reserveTransferAssets - args: [ - { v3: { 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { v3: { parents: 0, interior: { x1: { accountId32: { id: *alice_acc32 }}}}}, # beneficiary - { - v3: [ - { - id: { concrete: { 0, interior: { here: true }}}, - fun: { fungible: 20000000000000 } # 20_000_000_000_000 - } - ] - }, # assets - 0, # feeAssetItem - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '2,000,000,000', proofSize: 0 }}} - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { - outcome: { - Incomplete: [ - { refTime: '1,000,000,000', proofSize: 0 }, - UntrustedReserveLocation - ] - } - } 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 deleted file mode 100644 index 17a16d9ccd7..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml +++ /dev/null @@ -1,69 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - assethub_parachain: &assethub_parachain - wsPort: 9810 - paraId: &sp_id 1000 - variables: - chains: - accounts: - alice_signer: &alice_signer //Alice - hrmp: - proposed_max_capacity: &hrmp_proposed_max_capacity 8 - proposed_max_message_size: &hrmp_proposed_max_message_size 8192 -tests: - - name: HRMP - describes: - - name: Force Open HRMP Channel From Collectives Parachain → AssetHub Parachain - its: - - name: Alice calls hrmp.forceOpenHrmpChannel - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *cp_id, # sender - *sp_id, # recipient - *hrmp_proposed_max_capacity, # proposedMaxCapacity - *hrmp_proposed_max_message_size # proposedMaxMessageSize - ] - events: - - name: hrmp.HrmpChannelForceOpened - 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 - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - sudo: true - pallet: hrmp - call: forceOpenHrmpChannel - args: [ - *sp_id, # sender - *cp_id, # recipient - *hrmp_proposed_max_capacity, # proposedMaxCapacity - *hrmp_proposed_max_message_size # proposedMaxMessageSize - ] - events: - - name: hrmp.HrmpChannelForceOpened - 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/e2e/collectives/collectives-polkadot/1_alliance/0_join_alliance_fails.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/0_join_alliance_fails.yml deleted file mode 100644 index 9aff8b1db10..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/0_join_alliance_fails.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -settings: - chains: - relay_chain: - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - variables: - accounts: - alice_signer: &alice_signer //Alice - -tests: - - name: Alice fails to join an the Alliance, since it is not initialized yet. - its: - - name: Alice joins alliance - actions: - - extrinsics: # Relay Chain sets supported version for Asset Parachain - - chain: *collectives_parachain - signer: *alice_signer - pallet: alliance - call: joinAlliance - args: [] - events: - - name: system.ExtrinsicFailed - result: { - dispatchError: { Module: { index: 50, error: '0x00000000' }} - } - # TODO assert with Alliance Error variant - alliance.AllianceNotYetInitialized - # issue - https://github.com/paritytech/parachains-integration-tests/issues/59 diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/1_init_alliance.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/1_init_alliance.yml deleted file mode 100644 index 1e01c701744..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/1_init_alliance.yml +++ /dev/null @@ -1,256 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &coll_para_id 1001 - variables: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - accounts: - alice_signer: &acc_alice_signer //Alice - liam_account32: &acc_liam_acc32 "0x3614671a5de540d891eb8c4939c8153a4aa790602b347c18177b86d0fc546221" # //Liam - olivia_account32: &acc_olivia_acc32 "0x24ee8a659c6716fe9f7cb4e9e028602aa12867654ca02737da9171b7ff697d5c" # //Olivia - noah_account32: &acc_noah_acc32 "0x9c6ad3bc3aa2f1b2e837898e6da9980445f7ef8b3eee0b8c8e305f8cfae68517" # //Noah - emma_account32: &acc_emma_acc32 "0x8ac272b333ba1127c8db57fa777ec820b24598a236efa648caf0d26d86f64572" # //Emma - james_account32: &acc_james_acc32 "0x9a52805151a0b5effc084af9264011139872a21a3950cb9ae0b2955c4bf92c18" # //James - ava_account32: &acc_ava_acc32 "0x348ef0b8776adbc09c862ddc29b1d193b9e24738e54eea3b0609c83856dc101c" # //Ava - mia_account32: &acc_mia_acc32 "0xaebf15374cf7e758d10232514c569a7abf81cc1b8f1e81a73dbc608a0e335264" # //Mia - decodedCalls: - init_alliance_members: - chain: *collectives_parachain - pallet: alliance - call: initMembers - args: [ - [ - *acc_liam_acc32, - *acc_olivia_acc32, - *acc_noah_acc32, - *acc_emma_acc32, - *acc_james_acc32, - *acc_ava_acc32 - ], - [ - *acc_mia_acc32 - ] - ] - init_alliance_voting_members: - chain: *collectives_parachain - pallet: alliance - call: initMembers - args: [ - [ - *acc_liam_acc32, - *acc_olivia_acc32, - *acc_noah_acc32, - *acc_emma_acc32, - *acc_james_acc32, - *acc_ava_acc32, - *acc_mia_acc32 - ], - [] - ] - disband: - chain: *collectives_parachain - pallet: alliance - call: disband - args: [ - { - fellowMembers: 6, - allyMembers: 1 - } - ] - -tests: - - name: Alliance initiated with the root call, second init call fails. Alliance disband and set again. - its: - - name: Alliance initiated, founders and fellows are set. - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *coll_para_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 3000000000, # 3_000_000_000 - proofSize: 2000000, # 2_000_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 1000000000, # 1_000_000_000 - proofSize: 1000000, # 1_000_000 - }, - call: $init_alliance_members - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - result: { origin: { parents: 0, interior: Here }, destination: { parents: 0, interior: { X1: { Parachain: *coll_para_id }}}} - - name: alliance.MembersInitialized - chain: *collectives_parachain - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: '1,000,000' }}} - - - name: Alliance init call fails. - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *coll_para_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 3000000000, # 3_000_000_000 - proofSize: 2000000, # 2_000_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 1000000000, # 1_000_000_000 - proofSize: 1000000, # 1_000_000 - }, - call: $init_alliance_voting_members - } - } - ] - } - ] - events: - # TODO can not currently assert variant AllianceAlreadyInitialized, XCM Transact fails silently - # issue - https://github.com/paritytech/polkadot/issues/4623 - # Next test with a disband call will fail, if this call does not fail, - # since a witness data from a disband call will be invalid. - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - result: { origin: { parents: 0, interior: Here }, destination: { parents: 0, interior: { X1: { Parachain: *coll_para_id }}}} - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: '1,000,000' }}} - - - name: Alliance disbanded and initialized again. - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *coll_para_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 5000000000, # 3_000_000_000 - proofSize: 1000000, # 1_000_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 3000000000, # 3_000_000_000 - proofSize: 200000, # 200_000 - }, - call: $disband - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - result: { origin: { parents: 0, interior: Here }, destination: { parents: 0, interior: { X1: { Parachain: *coll_para_id }}}} - - name: alliance.AllianceDisbanded - chain: *collectives_parachain - result: { fellowMembers: 6, allyMembers: 1, unreserved: 0 } - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,321,495,872', proofSize: '181,779' }}} - - name: Alliance initiated, founders and fellows are set. - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *coll_para_id }}}}, # destination - { - v3: [ # message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 3000000000, # 3_000_000_000 - proofSize: 2000000, # 2_000_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 1000000000, # 1_000_000_000 - proofSize: 1000000, # 1_000_000 - }, - call: $init_alliance_members - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - result: { origin: { parents: 0, interior: Here }, destination: { parents: 0, interior: { X1: { Parachain: *coll_para_id }}}} - - name: alliance.MembersInitialized - chain: *collectives_parachain - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { outcome: { Complete: { refTime: '3,000,000,000', proofSize: '1,000,000' }}} diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/2_join_alliance_fails.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/2_join_alliance_fails.yml deleted file mode 100644 index 2afdadae602..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/2_join_alliance_fails.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -settings: - chains: - relay_chain: - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: 1001 - variables: - accounts: - liam_signer: &acc_liam_signer //Liam - -tests: - - name: Liam fails to join an the Alliance, Liam is already a member. - its: - - name: Alice joins alliance - actions: - - extrinsics: # Relay Chain sets supported version for Asset Parachain - - chain: *collectives_parachain - signer: *acc_liam_signer - pallet: alliance - call: joinAlliance - args: [] - events: - - name: system.ExtrinsicFailed - result: { - dispatchError: { Module: { index: 50, error: '0x02000000' }} - } - # TODO assert with Alliance Error variant - alliance.AllianceNotYetInitialized - # issue - https://github.com/paritytech/parachains-integration-tests/issues/59 diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/3_kick_member.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/3_kick_member.yml deleted file mode 100644 index a5941cb4723..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/1_alliance/3_kick_member.yml +++ /dev/null @@ -1,175 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - variables: - weight_threshold: &weight_threshold { refTime: [10, 10], proofSize: [10, 10] } - init_teleport_amount: &init_teleport_amount 20000000000000 # 20_000_000_000_000 - accounts: - alice_signer: &acc_alice_signer //Alice - treasury_account32: &acc_treasury_acc32 '0x6d6f646c70792f74727372790000000000000000000000000000000000000000' - alice_account32: &acc_alice_acc32 '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - alice_ss58: &acc_alice_ss58 '15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5' - decodedCalls: - alliance_kick_member: - chain: *collectives_parachain - pallet: alliance - call: kickMember - args: [ - {Id: *acc_alice_acc32} - ] - -tests: - - name: Member kicked out, deposited assets slashed and teleported to Relay Chain treasury. - before: - - name: DEPENDENCY | Do a 'limitedTeleportAssets' from the Relay Chain to the Collectives Parachain - actions: - - extrinsics: - - chain: *relay_chain - signer: *acc_alice_signer - pallet: xcmPallet - call: limitedTeleportAssets - args: [ - { v3: { 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { v3: { parents: 0, interior: { x1: { accountId32: { id: *acc_alice_acc32 }}}}}, # beneficiary - { v3: [ { id: { concrete: { 0, interior: { here: true }}}, fun: { fungible: *init_teleport_amount }} ] }, # assets - 0, # feeAssetItem - { unlimited: true } # weightLimit - ] - events: - - name: xcmPallet.Attempted - threshold: *weight_threshold - result: { - outcome: { Complete: { refTime: '3,000,000,000', proofSize: 0 }} - } - - name: balances.Deposit - chain: *collectives_parachain - result: { who: *acc_alice_ss58 } - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { - outcome: { Complete: { refTime: '4,000,000,000', proofSize: 0 }} - } - - name: Get the balances of the Relay Chain's treasury & Collectives parachain's future alliance member - actions: - - queries: - balance_rc_treasury_before: - chain: *relay_chain - pallet: system - call: account - args: [ *acc_treasury_acc32 ] - balance_cp_alice_before: - chain: *collectives_parachain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - its: - - name: Alice joins alliance - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *acc_alice_signer - pallet: alliance - call: joinAlliance - args: [] - events: - - name: balances.Reserved - chain: *collectives_parachain - result: { who: *acc_alice_ss58, amount: 10000000000000 } - - name: alliance.NewAllyJoined - result: {ally: *acc_alice_ss58, reserved: 10000000000000 } - - queries: - balance_cp_alice_after: - chain: *collectives_parachain - pallet: system - call: account - args: [ *acc_alice_acc32 ] - - name: Alice deposit check, balance decreased - actions: - - asserts: - balanceDecreased: - args: [ - { - balances: { - before: $balance_cp_alice_before, - after: $balance_cp_alice_after, - } - # TODO (P3) set `amount` and `fee` for more strict assert - } - ] - - name: Kick Alice from alliance - actions: - - extrinsics: # Asset Parachain sets supported version for Relay Chain through it - - chain: *relay_chain - signer: *acc_alice_signer - sudo: true - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: { - limited: { - refTime: 4000000000, # 4_000_000_000 - proofSize: 2000000, # 2_000_000 - }, - } - } - }, - { - Transact: { - originKind: Superuser, - requireWeightAtMost: { - refTime: 2000000000, # 2_000_000_000 - proofSize: 1000000, # 1_000_000 - }, - call: $alliance_kick_member - } - } - ] - } - ] - events: - - name: sudo.Sudid - result: { sudoResult: Ok } - - name: xcmPallet.Sent - result: { origin: { parents: 0, interior: Here }, destination: { parents: 0, interior: { X1: { Parachain: *cp_id }}}} - - name: alliance.MemberKicked - chain: *collectives_parachain - result: { member: *acc_alice_ss58, slashed: 10000000000000 } - - name: dmpQueue.ExecutedDownward - chain: *collectives_parachain - threshold: *weight_threshold - result: { - outcome: { Complete: { refTime: '4,000,000,000', proofSize: '1,000,000' }} - } - - name: messageQueue.Processed - result: { origin: { Ump: { Para: *cp_id }}, success: true } - - - queries: - balance_rc_treasury_after: - chain: *relay_chain - pallet: system - call: account - args: [ *acc_treasury_acc32 ] - - name: Slashed balance appears on the relay chain treasury account - actions: - - asserts: - balanceIncreased: - args: [ - { - balances: { - before: $balance_rc_treasury_before, - after: $balance_rc_treasury_after, - } - # TODO (P3) set `amount` and `fee` for more strict assert - } - ] diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/2_opengov/0_assethub.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/2_opengov/0_assethub.yml deleted file mode 100644 index c53efff51fb..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/2_opengov/0_assethub.yml +++ /dev/null @@ -1,149 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - assethub_parachain: &assethub_parachain - wsPort: 9810 - paraId: &ap_id 1000 - variables: - proposal_index: &proposal_index 0 - chains: - accounts: - alice_signer: &alice_signer //Alice - bob_signer: &bob_signer //Bob - decodedCalls: - set_candidates_ap: - chain: *assethub_parachain - encode: true - pallet: collatorSelection - call: setDesiredCandidates - args: [ - 3 - ] - send_set_candidates_rc: - chain: *relay_chain - encode: false - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *ap_id }}}}, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 200000000, # 200_000_000 - proofSize: 100000, # 100_000 - }, - call: $set_candidates_ap - } - } - ] - } - ] -tests: - - name: OpenGov - describes: - - name: Set desired candidates on AssetHub from Relay Chain OpenGov Staking track - its: - - name: Note preimage from xcm send set_desired_candidates call - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: preimage - call: notePreimage - args: [ - $send_set_candidates_rc - ] - events: - - name: preimage.Noted - result: {hash_: $send_set_candidates_rc.hash } - - name: Submit a proposal to set desired candidates - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: referenda - call: submit - args: [ - { - "Origins": "StakingAdmin", - }, - { - "Lookup": { - "hash_": $send_set_candidates_rc.hash, - "len": $send_set_candidates_rc.len, - }, - }, - { - "After": 1, - }, - ] - events: - - name: referenda.Submitted - result: { - index: *proposal_index, - proposal: { Lookup: { hash_: $send_set_candidates_rc.hash, len: $send_set_candidates_rc.len }} - } - - name: Alice Vote Aye - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: convictionVoting - call: vote - args: [ - *proposal_index, - { - "Standard": { - "vote": { - "aye": true, - "conviction": "Locked1x", - }, - "balance": 200000000000000, - } - }, - ] # TODO no event to catch https://github.com/paritytech/substrate/issues/14687 - - name: Bob Vote Aye - actions: - - extrinsics: - - chain: *relay_chain - signer: *bob_signer - pallet: convictionVoting - call: vote - args: [ - *proposal_index, - { - "Standard": { - "vote": { - "aye": true, - "conviction": "Locked1x", - }, - "balance": 200000000000000, - } - }, - ] # TODO no event to catch https://github.com/paritytech/substrate/issues/14687 - - name: Submit the decision deposit - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: referenda - call: placeDecisionDeposit - args: [ - *proposal_index, - ] - events: - - name: referenda.DecisionDepositPlaced - result: { index: *proposal_index } - - name: collatorSelection.NewDesiredCandidates - chain: *assethub_parachain - result: { desiredCandidates: 3 } diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/0_init.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/0_init.yml deleted file mode 100644 index 1e4b2dabe21..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/0_init.yml +++ /dev/null @@ -1,209 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - variables: - proposal_index: &proposal_index 1 - chains: - accounts: - alice_signer: &alice_signer //Alice - bob_signer: &bob_signer //Bob - alice_account32: &acc_alice_acc32 '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' - alice_ss58: &acc_alice_ss58 '15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5' - decodedCalls: - fellowship_induct_alice_cp: - chain: *collectives_parachain - encode: true - pallet: fellowshipCore - call: induct - args: [ - *acc_alice_acc32 - ] - fellowship_promote_1_alice_cp: - chain: *collectives_parachain - encode: true - pallet: fellowshipCore - call: promote - args: [ - *acc_alice_acc32, - 1 - ] - fellowship_promote_2_alice_cp: - chain: *collectives_parachain - encode: true - pallet: fellowshipCore - call: promote - args: [ - *acc_alice_acc32, - 2 - ] - fellowship_promote_3_alice_cp: - chain: *collectives_parachain - encode: true - pallet: fellowshipCore - call: promote - args: [ - *acc_alice_acc32, - 3 - ] - send_init_fellowship_rc: - chain: *relay_chain - encode: false - pallet: xcmPallet - call: send - args: [ - { v3: { parents: 0, interior: { x1: { parachain: *cp_id }}}}, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { # since batch_all not yet allowed over xcm, we have to send multiple `Transact`. - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 1500000000, # 1_500_000_000 - proofSize: 10000, # 10_000 - }, - call: $fellowship_induct_alice_cp - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 1500000000, # 1_500_000_000 - proofSize: 10000, # 10_000 - }, - call: $fellowship_promote_1_alice_cp - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 1500000000, # 1_500_000_000 - proofSize: 10000, # 10_000 - }, - call: $fellowship_promote_2_alice_cp - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 1500000000, # 1_500_000_000 - proofSize: 10000, # 10_000 - }, - call: $fellowship_promote_3_alice_cp - } - } - ] - } - ] - -tests: - - name: Fellowship - describes: - - name: Init the Fellowship - its: - - name: Note preimage from init fellowship call - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: preimage - call: notePreimage - args: [ - $send_init_fellowship_rc - ] - events: - - name: preimage.Noted - result: { hash_: $send_init_fellowship_rc.hash } - - name: Submit a proposal to init the Fellowship - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: referenda - call: submit - args: [ - { - "Origins": "FellowshipAdmin", - }, - { - "Lookup": { - "hash_": $send_init_fellowship_rc.hash, - "len": $send_init_fellowship_rc.len, - }, - }, - { - "After": 1, - }, - ] - events: - - name: referenda.Submitted - result: { - index: *proposal_index, - proposal: { Lookup: { hash_: $send_init_fellowship_rc.hash, len: $send_init_fellowship_rc.len }} - } - - name: Alice Vote Aye - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: convictionVoting - call: vote - args: [ - *proposal_index, - { - "Standard": { - "vote": { - "aye": true, - "conviction": "Locked1x", - }, - "balance": 200000000000000, - } - }, - ] # TODO no Aye event to catch https://github.com/paritytech/substrate/issues/14687 - - name: Bob Vote Aye - actions: - - extrinsics: - - chain: *relay_chain - signer: *bob_signer - pallet: convictionVoting - call: vote - args: [ - *proposal_index, - { - "Standard": { - "vote": { - "aye": true, - "conviction": "Locked1x", - }, - "balance": 200000000000000, - } - }, - ] # TODO no Aye event to catch https://github.com/paritytech/substrate/issues/14687 - - name: Submit the decision deposit - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: referenda - call: placeDecisionDeposit - args: [ - *proposal_index, - ] - events: - - name: referenda.DecisionDepositPlaced - result: { index: *proposal_index } - - name: fellowshipCollective.MemberAdded - chain: *collectives_parachain - result: { who: *acc_alice_ss58 } diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/1_whitelist_call.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/1_whitelist_call.yml deleted file mode 100644 index 5991c7ae2f8..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/1_whitelist_call.yml +++ /dev/null @@ -1,146 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - variables: - fellows_proposal_index: &fellows_proposal_index 0 - chains: - accounts: - alice_signer: &alice_signer //Alice - decodedCalls: - remark_rc: - chain: *relay_chain - encode: false - pallet: system - call: remark - args: [ - "0x10" - ] - whitelist_remark_rc: - chain: *relay_chain - encode: true - pallet: whitelist - call: whitelistCall - args: [ - $remark_rc.hash - ] - send_whitelist_remark_cp: - chain: *collectives_parachain - encode: false - pallet: polkadotXcm - call: send - args: [ - { v3: { parents: 1, interior: { here: true }}}, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 500000000, # 500_000_000 - proofSize: 20000, # 20_000 - }, - call: $whitelist_remark_rc - } - } - ] - } - ] - -tests: - - name: Fellowship - describes: - - name: The Fellowship white list the call - its: - - name: Note preimage from the whitelist call on the Relay Chain - actions: - - extrinsics: - - chain: *relay_chain - signer: *alice_signer - pallet: preimage - call: notePreimage - args: [ - $remark_rc - ] - events: - - name: preimage.Noted - result: { hash_: $remark_rc.hash } - - name: Note preimage from the xcm send call to white list the call above - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: preimage - call: notePreimage - args: [ - $send_whitelist_remark_cp, - ] - events: - - name: preimage.Noted - result: { hash_: $send_whitelist_remark_cp.hash } - - name: Submit a proposal to while list the call - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipReferenda - call: submit - args: [ - { - "FellowshipOrigins": "Fellows", - }, - { - "Lookup": { - "hash_": $send_whitelist_remark_cp.hash, - "len": $send_whitelist_remark_cp.len, - }, - }, - { - "After": 1, - }, - ] - events: - - name: fellowshipReferenda.Submitted - result: { - index: *fellows_proposal_index, - proposal: { Lookup: { hash_: $send_whitelist_remark_cp.hash, len: $send_whitelist_remark_cp.len}} - } - - name: Vote Aye - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipCollective - call: vote - args: [ - *fellows_proposal_index, - true, - ] - events: - - name: fellowshipCollective.Voted - result: { poll: *fellows_proposal_index, vote: { Aye: 1 } } - - name: Submit the decision deposit - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipReferenda - call: placeDecisionDeposit - args: [ - *fellows_proposal_index, - ] - events: - - name: fellowshipReferenda.DecisionDepositPlaced - result: {index: *fellows_proposal_index} - - name: whitelist.CallWhitelisted - chain: *relay_chain - result: { callHash: $remark_rc.hash } diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/2_assethub.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/2_assethub.yml deleted file mode 100644 index c0805594808..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/3_fellowship/2_assethub.yml +++ /dev/null @@ -1,126 +0,0 @@ ---- -settings: - chains: - relay_chain: &relay_chain - wsPort: 9700 - collectives_parachain: &collectives_parachain - wsPort: 9710 - paraId: &cp_id 1001 - assethub_parachain: &assethub_parachain - wsPort: 9810 - paraId: &ap_id 1000 - variables: - fellows_proposal_index: &fellows_proposal_index 1 - chains: - accounts: - alice_signer: &alice_signer //Alice - - decodedCalls: - xcmp_resume_execution_ap: - chain: *assethub_parachain - encode: true - pallet: xcmpQueue - call: resumeXcmExecution - args: [] - send_xcmp_resume_execution_cp: - chain: *collectives_parachain - encode: false - pallet: polkadotXcm - call: send - args: [ - { v3: { parents: 1, interior: { x1: { parachain: *ap_id }}}}, # destination - { - v3: [ #message - { - UnpaidExecution: { - weightLimit: Unlimited - } - }, - { - Transact: { - originKind: Xcm, - requireWeightAtMost: { - refTime: 300000000, # 300_000_000 - proofSize: 10000, # 10_000 - }, - call: $xcmp_resume_execution_ap - } - } - ] - } - ] - -tests: - - name: Fellowship - describes: - - name: The Fellowship resume xcm execution for the xcmp queue on AssetHub - its: - - name: Note preimage from the xcm send call to suspend_xcm_execution - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: preimage - call: notePreimage - args: [ - $send_xcmp_resume_execution_cp - ] - events: - - name: preimage.Noted - result: {hash_: $send_xcmp_resume_execution_cp.hash } - - name: Submit a proposal to resume xcm execution on AssetHub - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipReferenda - call: submit - args: [ - { - "FellowshipOrigins": "Fellows", - }, - { - "Lookup": { - "hash_": $send_xcmp_resume_execution_cp.hash, - "len": $send_xcmp_resume_execution_cp.len, - }, - }, - { - "After": 1, - }, - ] - events: - - name: fellowshipReferenda.Submitted - result: { - index: 1, - proposal: {Lookup: {hash_: $send_xcmp_resume_execution_cp.hash, len: $send_xcmp_resume_execution_cp.len}} - } - - name: Vote Aye - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipCollective - call: vote - args: [ - *fellows_proposal_index, - true, - ] - events: - - name: fellowshipCollective.Voted - result: { poll: *fellows_proposal_index, vote: { Aye: 1 } } - - name: Submit the decision deposit - actions: - - extrinsics: - - chain: *collectives_parachain - signer: *alice_signer - pallet: fellowshipReferenda - call: placeDecisionDeposit - args: [ - *fellows_proposal_index, - ] - events: - - name: fellowshipReferenda.DecisionDepositPlaced - result: {index: *fellows_proposal_index} - - name: xcmpQueue.Success - chain: *assethub_parachain diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/config.toml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/config.toml deleted file mode 100644 index 20fda92bd08..00000000000 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/config.toml +++ /dev/null @@ -1,42 +0,0 @@ -[relaychain] -default_command = "./bin/polkadot" -default_args = [ "-lparachain=trace", "-lxcm=trace" ] -chain = "polkadot-local" - - [[relaychain.nodes]] - name = "alice" - ws_port = 9700 - validator = true - args = ["--state-cache-size=0"] - - [[relaychain.nodes]] - name = "bob" - ws_port = 9701 - validator = true - - [[relaychain.nodes]] - name = "charlie" - ws_port = 9702 - validator = true - - [[relaychain.nodes]] - name = "dave" - ws_port = 9703 - validator = true - -[[parachains]] -id = 1001 -chain = "collectives-polkadot-local" -cumulus_based = true - - [[parachains.collators]] - name = "collator1" - ws_port = 9710 - command = "./bin/polkadot-parachain" - args = [ "-lxcm=trace", "--state-cache-size=0" ] - - [[parachains.collators]] - name = "collator2" - ws_port = 9711 - command = "./bin/polkadot-parachain" - args = ["-lxcm=trace"] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml deleted file mode 100644 index f71499e0c29..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ /dev/null @@ -1,236 +0,0 @@ -[package] -name = "asset-hub-kusama-runtime" -version = "0.9.420" -authors.workspace = true -edition.workspace = true -description = "Kusama variant of Asset Hub parachain runtime" -license = "Apache-2.0" - -[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.10.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-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} -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 -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 } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } -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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -assets-common = { path = "../common", 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-dmp-queue/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-asset-conversion/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-message-queue/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/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-message-queue/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/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", -] -std = [ - "assets-common/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-message-queue/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/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-core-primitives/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "primitive-types/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", - "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-kusama/build.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/build.rs deleted file mode 100644 index 60f8a125129..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/build.rs +++ /dev/null @@ -1,26 +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. - -#[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-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs deleted file mode 100644 index 4c76262f60a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ /dev/null @@ -1,1549 +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. - -//! # Asset Hub Kusama Runtime -//! -//! Asset Hub Kusama, formerly known as "Statemine", is the canary network for its Polkadot cousin. - -#![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 polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -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, Perbill, Permill, -}; - -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use codec::{Decode, Encode, MaxEncodedLen}; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -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, - InstanceFilter, TransformOrigin, - }, - 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, - kusama::{consensus::*, currency::*, fee::WeightToFee}, - message_queue::{NarrowOriginToSibling, ParaIdToSibling}, - 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::{ - FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, KsmLocation, - PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, -}; - -#[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 crate::xcm_config::{ - ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, - TrustBackedAssetsPalletLocation, -}; -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[cfg(feature = "state-trie-version-1")] -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - // Note: "statemine" is the legacy name for this chain. It has been renamed to - // "asset-hub-kusama". Many wallets/tools depend on the `spec_name`, so it remains "statemine" - // for the time being. Wallets/tools should update to treat "asset-hub-kusama" equally. - spec_name: create_runtime_str!("statemine"), - impl_name: create_runtime_str!("statemine"), - authoring_version: 1, - spec_version: 1_004_000, - 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 { - // Note: "statemine" is the legacy name for this change. It has been renamed to - // "asset-hub-kusama". Many wallets/tools depend on the `spec_name`, so it remains "statemine" - // for the time being. Wallets/tools should update to treat "asset-hub-kusama" equally. - spec_name: create_runtime_str!("statemine"), - impl_name: create_runtime_str!("statemine"), - authoring_version: 1, - spec_version: 1_004_000, - 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 = 2; -} - -// 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 RuntimeFreezeReason = RuntimeFreezeReason; - 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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - 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 {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -parameter_types! { - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, - >; - type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - -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 = (); -} - -// 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, - // RandomnessCollectiveFlip = 2 removed - 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, - // Temporary to migrate the remaining DMP messages: - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, - - // 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, - - // 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")] -mod benches { - frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_assets, Local] - [pallet_assets, Foreign] - [pallet_assets, Pool] - [pallet_asset_conversion, AssetConversion] - [pallet_balances, Balances] - [pallet_message_queue, MessageQueue] - [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_parachain_system, ParachainSystem] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] - // XCM - [pallet_xcm, PalletXcmExtrinsicsBenchmark::] - // 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - - // 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::; - - 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - impl pallet_xcm::benchmarking::Config for Runtime { - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Relay/native token can be teleported between AH and Relay. - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - Parent.into(), - )) - } - - fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // AH can reserve transfer native token to some random parachain. - let random_para_id = 43211234; - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - random_para_id.into() - ); - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - ParentThen(Parachain(random_para_id).into()).into(), - )) - } - } - - use xcm::latest::prelude::*; - use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; - use pallet_xcm_benchmarks::asset_instance_from; - - parameter_types! { - pub ExistentialDepositMultiAsset: Option = Some(( - KsmLocation::get(), - ExistentialDeposit::get() - ).into()); - } - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = xcm_config::XcmConfig; - type AccountIdConverter = xcm_config::LocationToAccountId; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositMultiAsset, - xcm_config::PriceForParentDelivery, - >; - fn valid_destination() -> Result { - Ok(KsmLocation::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(KsmLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - KsmLocation::get(), - MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmLocation::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(KsmLocation::get()), - fun: Fungible(UNITS), - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type TransactAsset = Balances; - 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> { - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((KsmLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(KsmLocation::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = KsmLocation::get(); - let assets: MultiAssets = (Concrete(KsmLocation::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::; - - 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) - } - } - - 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! { - 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::kusama::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-kusama/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs deleted file mode 100644 index e7fdb2aae2a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +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. - -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-kusama/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index f787aa32701..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// statemint-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/statemint/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_660_000 picoseconds. - Weight::from_parts(1_720_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 28_418 - .saturating_add(Weight::from_parts(24_636_963, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs deleted file mode 100644 index e394e8b837a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ /dev/null @@ -1,148 +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. - -//! Autogenerated weights for `cumulus_pallet_xcmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --pallet -// cumulus-pallet-xcmp-queue -// --chain -// asset-hub-kusama-dev -// --output -// cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs -// --extrinsic -// - -#![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: 6_000_000 picoseconds. - Weight::from_parts(6_000_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:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn enqueue_xcmp_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `118` - // Estimated: `3517` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn suspend_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_000_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::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn resume_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `1596` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(5_000_000, 0) - .saturating_add(Weight::from_parts(0, 1596)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn take_first_concatenated_xcm() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65747` - // Estimated: `69212` - // Minimum execution time: 62_000_000 picoseconds. - Weight::from_parts(66_000_000, 0) - .saturating_add(Weight::from_parts(0, 69212)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65710` - // Estimated: `69175` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(43_000_000, 0) - .saturating_add(Weight::from_parts(0, 69175)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs deleted file mode 100644 index 1a4adb968bb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,53 +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. - -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-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs deleted file mode 100644 index 6304051e6cb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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: 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-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs deleted file mode 100644 index f04081a84fb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/mod.rs +++ /dev/null @@ -1,45 +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 mod block_weights; -pub mod cumulus_pallet_dmp_queue; -pub mod cumulus_pallet_parachain_system; -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_message_queue; -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 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-kusama/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs deleted file mode 100644 index 3fcf2f8f4ec..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +++ /dev/null @@ -1,154 +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. - -//! 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-kusama-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-kusama-dev -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_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-kusama/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs deleted file mode 100644 index c2688d97905..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_foreign.rs +++ /dev/null @@ -1,533 +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. - -//! 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-kusama-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-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_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-kusama/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs deleted file mode 100644 index 957e33fcd9e..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_local.rs +++ /dev/null @@ -1,530 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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_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-kusama/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs deleted file mode 100644 index e0b4ff36552..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_assets_pool.rs +++ /dev/null @@ -1,530 +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. - -//! 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-kusama-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-kusama-dev -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs deleted file mode 100644 index 79c88f30580..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_balances.rs +++ /dev/null @@ -1,152 +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. - -//! Autogenerated weights for `pallet_balances` -//! -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --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/ - -#![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_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`) - fn transfer_keep_alive() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // 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`) - fn force_set_balance_creating() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // 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`) - fn force_set_balance_killing() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // 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`) - fn force_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `6196` - // 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`) - fn transfer_all() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // 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`) - fn force_unreserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // 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`) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 17_259_000 picoseconds. - Weight::from_parts(17_478_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // 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-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs deleted file mode 100644 index c686bd6134a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs +++ /dev/null @@ -1,248 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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_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(_c: u32, _k: u32) -> 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)) - } - fn update_bond(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)) - } - fn take_candidate_slot(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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs deleted file mode 100644 index 792b7d18b67..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// statemint-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/statemint/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 18_976_000 picoseconds. - Weight::from_parts(18_976_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 12_686_000 picoseconds. - Weight::from_parts(12_686_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 4_951_000 picoseconds. - Weight::from_parts(4_951_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_023_000 picoseconds. - Weight::from_parts(6_023_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_901_000 picoseconds. - Weight::from_parts(6_901_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 58_503_000 picoseconds. - Weight::from_parts(58_503_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 9_318_000 picoseconds. - Weight::from_parts(9_318_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 52_228_000 picoseconds. - Weight::from_parts(52_228_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 59_617_000 picoseconds. - Weight::from_parts(59_617_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 69_681_000 picoseconds. - Weight::from_parts(69_681_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs deleted file mode 100644 index d2e0f0ec7f0..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,164 +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. - -//! Autogenerated weights for `pallet_multisig` -//! -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_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_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(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`) - /// 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: `262 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 44_768_000 picoseconds. - Weight::from_parts(33_662_218, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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`) - /// The range of component `s` is `[3, 100]`. - /// The range of component `z` is `[0, 10000]`. - fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `282` - // Estimated: `6811` - // Minimum execution time: 29_745_000 picoseconds. - Weight::from_parts(20_559_891, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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`) - /// 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: `385 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 51_506_000 picoseconds. - Weight::from_parts(36_510_777, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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`) - /// The range of component `s` is `[2, 100]`. - fn approve_as_multi_create(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 31_072_000 picoseconds. - Weight::from_parts(32_408_621, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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`) - /// The range of component `s` is `[2, 100]`. - fn approve_as_multi_approve(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `282` - // Estimated: `6811` - // Minimum execution time: 18_301_000 picoseconds. - Weight::from_parts(18_223_547, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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`) - /// The range of component `s` is `[2, 100]`. - fn cancel_as_multi(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `454 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 32_107_000 picoseconds. - Weight::from_parts(33_674_827, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // 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-kusama/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs deleted file mode 100644 index 4becc569514..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nft_fractionalization.rs +++ /dev/null @@ -1,114 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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_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-kusama/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs deleted file mode 100644 index 7a51830799a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_nfts.rs +++ /dev/null @@ -1,772 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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_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-kusama/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs deleted file mode 100644 index 0cdffc653bc..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_proxy.rs +++ /dev/null @@ -1,225 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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: `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-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs deleted file mode 100644 index 73c3c06945d..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_session.rs +++ /dev/null @@ -1,80 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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: `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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs deleted file mode 100644 index e27289a49e9..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,74 +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. - -//! Autogenerated weights for `pallet_timestamp` -//! -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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: `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: `86` - // Estimated: `1493` - // 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: `57` - // Estimated: `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-kusama/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs deleted file mode 100644 index 69d3e773afb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_uniques.rs +++ /dev/null @@ -1,466 +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. - -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-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-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_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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs deleted file mode 100644 index e6c3e1295ef..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_utility.rs +++ /dev/null @@ -1,101 +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. - -//! Autogenerated weights for `pallet_utility` -//! -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_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: 7_103_000 picoseconds. - Weight::from_parts(7_226_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // 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: 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]`. - fn batch_all(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_070_000 picoseconds. - Weight::from_parts(1_321_270, 0) - .saturating_add(Weight::from_parts(0, 0)) - // 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_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]`. - fn force_batch(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_852_000 picoseconds. - Weight::from_parts(7_007_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // 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-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs deleted file mode 100644 index 1e4a723e10f..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-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 -// 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 -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 25_043_000 picoseconds. - Weight::from_parts(25_670_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_261_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: 14_107_000 picoseconds. - Weight::from_parts(14_500_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: 7_175_000 picoseconds. - Weight::from_parts(7_493_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_162_000 picoseconds. - Weight::from_parts(2_278_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `145` - // Estimated: `3610` - // Minimum execution time: 29_144_000 picoseconds. - Weight::from_parts(30_134_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `363` - // Estimated: `3828` - // Minimum execution time: 31_522_000 picoseconds. - Weight::from_parts(32_679_000, 0) - .saturating_add(Weight::from_parts(0, 3828)) - .saturating_add(T::DbWeight::get().reads(7)) - .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_338_000 picoseconds. - Weight::from_parts(2_494_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_315_000 picoseconds. - Weight::from_parts(17_787_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_273_000 picoseconds. - Weight::from_parts(17_712_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_395_000 picoseconds. - Weight::from_parts(19_095_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `6152` - // Minimum execution time: 27_343_000 picoseconds. - Weight::from_parts(28_068_000, 0) - .saturating_add(Weight::from_parts(0, 6152)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) - /// 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_156_000 picoseconds. - Weight::from_parts(9_552_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_454_000 picoseconds. - Weight::from_parts(17_831_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `11105` - // Minimum execution time: 34_299_000 picoseconds. - Weight::from_parts(35_156_000, 0) - .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) - /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `1588` - // Minimum execution time: 4_508_000 picoseconds. - Weight::from_parts(4_702_000, 0) - .saturating_add(Weight::from_parts(0, 1588)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `PolkadotXcm::Queries` (r:1 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn take_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `7740` - // Estimated: `11205` - // Minimum execution time: 26_557_000 picoseconds. - Weight::from_parts(26_980_000, 0) - .saturating_add(Weight::from_parts(0, 11205)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/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 deleted file mode 100644 index 405d7c72e55..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs +++ /dev/null @@ -1,244 +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. - -mod pallet_xcm_benchmarks_fungible; -mod pallet_xcm_benchmarks_generic; - -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}; - -trait WeighMultiAssets { - fn weigh_multi_assets(&self, weight: Weight) -> Weight; -} - -const MAX_ASSETS: u64 = 100; - -impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, weight: Weight) -> Weight { - match self { - 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, weight: Weight) -> Weight { - weight.saturating_mul(self.inner().iter().count() as u64) - } -} - -pub struct AssetHubKusamaXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for AssetHubKusamaXcmWeight { - fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) - } - 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()) - } - 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(XcmFungibleWeight::::transfer_asset()) - } - fn transfer_reserve_asset( - assets: &MultiAssets, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) - } - fn transact( - _origin_type: &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(XcmFungibleWeight::::deposit_asset()) - } - fn deposit_reserve_asset( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) - } - fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - Weight::MAX - } - fn initiate_reserve_withdraw( - assets: &MultiAssetFilter, - _reserve: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) - } - fn initiate_teleport( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::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 { - Weight::MAX - } - fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - Weight::MAX - } - fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - 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() - } -} 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 deleted file mode 100644 index e680c2d5c11..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,187 +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. - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! 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 -// 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_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)] -#![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: 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)) - } - // 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: 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)) - } - // 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: `246` - // Estimated: `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)) - } - // 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: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `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: `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)) - } - pub fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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`) - pub fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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)) - } - // 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: `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)) - } - // 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: `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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index 9e8f3bfe75c..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,328 +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. - -//! 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-kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=asset-hub-kusama-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-kusama/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) - } - 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-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs deleted file mode 100644 index 05262e07410..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ /dev/null @@ -1,634 +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 super::{ - AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo, - ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, -}; -use crate::{ForeignAssets, CENTS}; -use assets_common::{ - local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, - 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, ConcreteAssetFromSystem}, -}; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use sp_runtime::traits::ConvertInto; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, - 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}; - -#[cfg(feature = "runtime-benchmarks")] -use {cumulus_primitives_core::ParaId, sp_core::Get}; - -parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Kusama); - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get().unwrap()), 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(); - pub const FellowshipLocation: MultiLocation = MultiLocation::parent(); -} - -/// 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>, -); - -/// 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(_) } - }; -} - -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - 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::MessageQueue(..) | - RuntimeCall::Assets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::ForeignAssets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::PoolAssets( - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::AssetConversion( - pallet_asset_conversion::Call::create_pool { .. } | - pallet_asset_conversion::Call::add_liquidity { .. } | - pallet_asset_conversion::Call::remove_liquidity { .. } | - pallet_asset_conversion::Call::swap_tokens_for_exact_tokens { .. } | - pallet_asset_conversion::Call::swap_exact_tokens_for_tokens { .. }, - ) | RuntimeCall::NftFractionalization( - pallet_nft_fractionalization::Call::fractionalize { .. } | - pallet_nft_fractionalization::Call::unify { .. }, - ) | RuntimeCall::Nfts( - pallet_nfts::Call::create { .. } | - pallet_nfts::Call::force_create { .. } | - pallet_nfts::Call::destroy { .. } | - pallet_nfts::Call::mint { .. } | - pallet_nfts::Call::force_mint { .. } | - pallet_nfts::Call::burn { .. } | - pallet_nfts::Call::transfer { .. } | - pallet_nfts::Call::lock_item_transfer { .. } | - pallet_nfts::Call::unlock_item_transfer { .. } | - pallet_nfts::Call::lock_collection { .. } | - pallet_nfts::Call::transfer_ownership { .. } | - pallet_nfts::Call::set_team { .. } | - pallet_nfts::Call::force_collection_owner { .. } | - pallet_nfts::Call::force_collection_config { .. } | - pallet_nfts::Call::approve_transfer { .. } | - pallet_nfts::Call::cancel_approval { .. } | - pallet_nfts::Call::clear_all_transfer_approvals { .. } | - pallet_nfts::Call::lock_item_properties { .. } | - pallet_nfts::Call::set_attribute { .. } | - pallet_nfts::Call::force_set_attribute { .. } | - pallet_nfts::Call::clear_attribute { .. } | - pallet_nfts::Call::approve_item_attributes { .. } | - pallet_nfts::Call::cancel_item_attributes_approval { .. } | - pallet_nfts::Call::set_metadata { .. } | - pallet_nfts::Call::clear_metadata { .. } | - pallet_nfts::Call::set_collection_metadata { .. } | - pallet_nfts::Call::clear_collection_metadata { .. } | - pallet_nfts::Call::set_accept_ownership { .. } | - pallet_nfts::Call::set_collection_max_supply { .. } | - pallet_nfts::Call::update_mint_settings { .. } | - pallet_nfts::Call::set_price { .. } | - pallet_nfts::Call::buy_item { .. } | - pallet_nfts::Call::pay_tips { .. } | - pallet_nfts::Call::create_swap { .. } | - pallet_nfts::Call::cancel_swap { .. } | - pallet_nfts::Call::claim_swap { .. }, - ) | RuntimeCall::Uniques( - pallet_uniques::Call::create { .. } | - pallet_uniques::Call::force_create { .. } | - pallet_uniques::Call::destroy { .. } | - pallet_uniques::Call::mint { .. } | - pallet_uniques::Call::burn { .. } | - pallet_uniques::Call::transfer { .. } | - pallet_uniques::Call::freeze { .. } | - pallet_uniques::Call::thaw { .. } | - pallet_uniques::Call::freeze_collection { .. } | - pallet_uniques::Call::thaw_collection { .. } | - pallet_uniques::Call::transfer_ownership { .. } | - pallet_uniques::Call::set_team { .. } | - pallet_uniques::Call::approve_transfer { .. } | - pallet_uniques::Call::cancel_approval { .. } | - pallet_uniques::Call::force_item_status { .. } | - pallet_uniques::Call::set_attribute { .. } | - pallet_uniques::Call::clear_attribute { .. } | - pallet_uniques::Call::set_metadata { .. } | - pallet_uniques::Call::clear_metadata { .. } | - pallet_uniques::Call::set_collection_metadata { .. } | - pallet_uniques::Call::clear_collection_metadata { .. } | - pallet_uniques::Call::set_accept_ownership { .. } | - pallet_uniques::Call::set_collection_max_supply { .. } | - pallet_uniques::Call::set_price { .. } | - pallet_uniques::Call::buy_item { .. } - ) - ) - } -} - -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 and its pluralities (i.e. governance bodies) get free execution. - AllowExplicitUnpaidExecutionFrom, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier< - Runtime, - WeightToFee, - pallet_assets::BalanceToAssetBalance, - 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; - type XcmSender = XcmRouter; - type AssetTransactor = AssetTransactors; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - // Asset Hub Kusama does not recognize a reserve location for any asset. This does not prevent - // 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 = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::AssetHubKusamaXcmWeight, - RuntimeCall, - MaxInstructions, - >; - type Trader = ( - UsingComponents>, - cumulus_primitives_utility::TakeFirstAssetTrader< - AccountId, - AssetFeeAsExistentialDepositMultiplierFeeCharger, - TrustBackedAssetsConvertedConcreteId, - Assets, - cumulus_primitives_utility::XcmFeesTo32ByteAccount< - FungiblesTransactor, - AccountId, - XcmAssetFeesReceiver, - >, - >, - ); - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - 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; - -parameter_types! { - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(KsmLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -pub type PriceForParentDelivery = - ExponentialPrice; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -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; - type XcmReserveTransferFilter = Everything; - type Weigher = WeightInfoBounds< - crate::weights::xcm::AssetHubKusamaXcmWeight, - 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; - 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)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs deleted file mode 100644 index cdd4290770f..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ /dev/null @@ -1,658 +0,0 @@ -// 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 Statemine (Kusama Assets Hub) chain. - -use asset_hub_kusama_runtime::xcm_config::{ - AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, LocationToAccountId, - TrustBackedAssetsPalletLocation, -}; -pub use asset_hub_kusama_runtime::{ - xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig}, - AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, -}; -use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; -use codec::{Decode, Encode}; -use cumulus_primitives_utility::ChargeWeightInFungibles; -use frame_support::{ - assert_noop, assert_ok, - traits::fungibles::InspectEnumerable, - weights::{Weight, WeightToFee as WeightToFeeT}, -}; -use parachains_common::{ - kusama::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_keys() -> CollatorSessionKeys { - CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(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, - } - }), - 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); - }) -); - -#[test] -fn reserve_transfer_native_asset_to_non_teleport_para_works() { - asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< - 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, - } - }), - WeightLimit::Unlimited, - ); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml deleted file mode 100644 index b5eff6b63af..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,215 +0,0 @@ -[package] -name = "asset-hub-polkadot-runtime" -version = "0.9.420" -authors.workspace = true -edition.workspace = true -description = "Asset Hub Polkadot parachain runtime" -license = "Apache-2.0" - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.10.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-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", 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-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-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-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} -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} - -# Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -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 } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } -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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -assets-common = { path = "../common", default-features = false } - -[dev-dependencies] -hex-literal = "0.4.1" -asset-test-utils = { path = "../test-utils" } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } - -[features] -default = [ "std" ] -runtime-benchmarks = [ - "assets-common/runtime-benchmarks", - "cumulus-pallet-dmp-queue/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "hex-literal", - "pallet-asset-tx-payment/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-nfts/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-uniques/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-xcm-benchmarks/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-tx-payment/try-runtime", - "pallet-assets/try-runtime", - "pallet-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-nfts/try-runtime", - "pallet-proxy/try-runtime", - "pallet-session/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-uniques/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", -] -std = [ - "assets-common/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-tx-payment/std", - "pallet-assets/std", - "pallet-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-nfts-runtime-api/std", - "pallet-nfts/std", - "pallet-proxy/std", - "pallet-session/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/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-core-primitives/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/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", - "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-polkadot/build.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/build.rs deleted file mode 100644 index 60f8a125129..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/build.rs +++ /dev/null @@ -1,26 +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. - -#[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-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs deleted file mode 100644 index 78721b194d0..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,1383 +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. - -//! # Asset Hub Polkadot Runtime -//! -//! Asset Hub Polkadot is a parachain that provides an interface to create, manage, and use assets. -//! Assets may be fungible or non-fungible. -//! -//! ## Renaming -//! -//! This chain was originally known as "Statemint". You may see references to Statemint, Statemine, -//! and Westmint throughout the codebase. These are synonymous with "Asset Hub Polkadot, Kusama, and -//! Westend", respectively. -//! -//! ## Assets -//! -//! - Fungibles: Configuration of `pallet-assets`. -//! - Non-Fungibles (NFTs): Configuration of `pallet-uniques`. -//! -//! ## Other Functionality -//! -//! ### Native Balances -//! -//! Asset Hub Polkadot uses its parent DOT token as its native asset. -//! -//! ### Governance -//! -//! As a system parachain, Asset Hub defers its governance (namely, its `Root` origin), to its -//! Relay Chain parent, Polkadot. -//! -//! ### Collator Selection -//! -//! Asset Hub uses `pallet-collator-selection`, a simple first-come-first-served registration -//! system where collators can reserve a small bond to join the block producer set. There is no -//! slashing. -//! -//! ### XCM -//! -//! Because Asset Hub is fully under the control of the Relay Chain, it is meant to be a -//! `TrustedTeleporter`. It can also serve as a reserve location to other parachains for DOT as well -//! as other local assets. - -#![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, matching::FromSiblingParachain, MultiLocationForAssetId, -}; -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Verify}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Perbill, -}; - -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, - genesis_builder_helper::{build_config, create_default_config}, - parameter_types, - traits::{ - AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - InstanceFilter, TransformOrigin, - }, - weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, -}; -use pallet_nfts::PalletFeatures; -pub use parachains_common as common; -use parachains_common::{ - impls::{AssetsToBlockAuthor, DealWithFees}, - message_queue::*, - polkadot::{consensus::*, currency::*, fee::WeightToFee}, - AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, 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_config::{ - DotLocation, FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, - TrustBackedAssetsConvertedConcreteId, XcmOriginToTransactDispatchOrigin, -}; - -#[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 crate::xcm_config::ForeignCreatorsSovereignAccountOf; -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - // Note: "statemint" is the legacy name for this chain. It has been renamed to - // "asset-hub-polkadot". Many wallets/tools depend on the `spec_name`, so it remains "statemint" - // for the time being. Wallets/tools should update to treat "asset-hub-polkadot" equally. - spec_name: create_runtime_str!("statemint"), - impl_name: create_runtime_str!("statemint"), - authoring_version: 1, - spec_version: 1_004_000, - 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 = 0; -} - -// 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 RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - 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 = 10 * UNITS; // 10 UNITS deposit to create fungible asset class - 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! { - // 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::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::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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - 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, - >; -} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl parachain_info::Config for Runtime {} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -parameter_types! { - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, - >; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - -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_tx_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Fungibles = Assets; - type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< - pallet_assets::BalanceToAssetBalance< - Balances, - Runtime, - ConvertInto, - TrustBackedAssetsInstance, - >, - AssetsToBlockAuthor, - >; -} - -parameter_types! { - pub const UniquesCollectionDeposit: Balance = 10 * UNITS; // 10 UNIT deposit to create uniques class - pub const UniquesItemDeposit: Balance = UNITS / 100; // 1 / 100 UNIT deposit to create uniques instance - 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>; // Max 32 bytes per key - type ValueLimit = ConstU32<64>; // Max 64 bytes per value - type WeightInfo = weights::pallet_uniques::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type CreateOrigin = AsEnsureOriginWithArg>; - type Locker = (); -} - -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 = (); -} - -// 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, - // RandomnessCollectiveFlip = 2 removed - 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_tx_payment::{Pallet, Event} = 12, - - // 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, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, - - // 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, - - // 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, - } -); - -/// 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_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 = ( - // unreleased - 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")] -mod benches { - frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_assets, Local] - [pallet_assets, Foreign] - [pallet_balances, Balances] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_nfts, Nfts] - [pallet_proxy, Proxy] - [pallet_session, SessionBench::] - [pallet_uniques, Uniques] - [pallet_utility, Utility] - [pallet_timestamp, Timestamp] - [pallet_collator_selection, CollatorSelection] - [cumulus_pallet_parachain_system, ParachainSystem] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] - // XCM - [pallet_xcm, PalletXcmExtrinsicsBenchmark::] - // 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_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) - .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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - - // 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::; - - 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - impl pallet_xcm::benchmarking::Config for Runtime { - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Relay/native token can be teleported between AH and Relay. - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - Parent.into(), - )) - } - - fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // AH can reserve transfer native token to some random parachain. - let random_para_id = 43211234; - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - random_para_id.into() - ); - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - ParentThen(Parachain(random_para_id).into()).into(), - )) - } - } - - use xcm::latest::prelude::*; - use xcm_config::{DotLocation, MaxAssetsIntoHolding}; - use pallet_xcm_benchmarks::asset_instance_from; - - parameter_types! { - pub ExistentialDepositMultiAsset: Option = Some(( - xcm_config::DotLocation::get(), - ExistentialDeposit::get() - ).into()); - } - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = xcm_config::XcmConfig; - type AccountIdConverter = xcm_config::LocationToAccountId; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositMultiAsset, - xcm_config::PriceForParentDelivery, - >; - fn valid_destination() -> Result { - Ok(DotLocation::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 - 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(DotLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - DotLocation::get(), - MultiAsset { fun: Fungible(UNITS), id: Concrete(DotLocation::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(DotLocation::get()), - fun: Fungible(UNITS), - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type TransactAsset = Balances; - 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> { - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((DotLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(DotLocation::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = DotLocation::get(); - let assets: MultiAssets = (Concrete(DotLocation::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::; - - 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) - } - } - - 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! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{CENTS, MILLICENTS}; - use parachains_common::polkadot::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-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs deleted file mode 100644 index e7fdb2aae2a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +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. - -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-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index 970534560c6..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// westmint-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/westmint/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_638_000 picoseconds. - Weight::from_parts(1_690_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 22_873 - .saturating_add(Weight::from_parts(24_208_496, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs deleted file mode 100644 index 89c80d0be62..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ /dev/null @@ -1,148 +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. - -//! Autogenerated weights for `cumulus_pallet_xcmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --pallet -// cumulus-pallet-xcmp-queue -// --chain -// asset-hub-polkadot-dev -// --output -// cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs -// --extrinsic -// - -#![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: 6_000_000 picoseconds. - Weight::from_parts(6_000_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:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn enqueue_xcmp_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `82` - // Estimated: `3517` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn suspend_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn resume_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `1596` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(5_000_000, 0) - .saturating_add(Weight::from_parts(0, 1596)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn take_first_concatenated_xcm() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(46_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65711` - // Estimated: `69176` - // Minimum execution time: 62_000_000 picoseconds. - Weight::from_parts(68_000_000, 0) - .saturating_add(Weight::from_parts(0, 69176)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65710` - // Estimated: `69175` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) - .saturating_add(Weight::from_parts(0, 69175)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs deleted file mode 100644 index 1a4adb968bb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,53 +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. - -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-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs deleted file mode 100644 index 0b988fd0f6f..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_956_000 picoseconds. - Weight::from_parts(3_441_280, 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_267_000 picoseconds. - Weight::from_parts(7_462_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_816, 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_757_000 picoseconds. - Weight::from_parts(4_021_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: 97_958_650_000 picoseconds. - Weight::from_parts(102_129_539_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_327_000 picoseconds. - Weight::from_parts(2_511_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_186 - .saturating_add(Weight::from_parts(755_085, 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_114_000 picoseconds. - Weight::from_parts(2_177_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_174 - .saturating_add(Weight::from_parts(584_644, 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: `77 + p * (70 ±0)` - // Minimum execution time: 3_799_000 picoseconds. - Weight::from_parts(3_910_000, 0) - .saturating_add(Weight::from_parts(0, 77)) - // Standard Error: 1_968 - .saturating_add(Weight::from_parts(1_220_745, 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-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs deleted file mode 100644 index 0823dcad88e..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/mod.rs +++ /dev/null @@ -1,42 +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 mod block_weights; -pub mod cumulus_pallet_dmp_queue; -pub mod cumulus_pallet_parachain_system; -pub mod cumulus_pallet_xcmp_queue; -pub mod extrinsic_weights; -pub mod frame_system; -pub mod pallet_assets_foreign; -pub mod pallet_assets_local; -pub mod pallet_balances; -pub mod pallet_collator_selection; -pub mod pallet_message_queue; -pub mod pallet_multisig; -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 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-polkadot/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs deleted file mode 100644 index adb686c0afc..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_foreign.rs +++ /dev/null @@ -1,532 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_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: 29_979_000 picoseconds. - Weight::from_parts(30_763_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_255_000 picoseconds. - Weight::from_parts(12_614_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_240_000 picoseconds. - Weight::from_parts(15_627_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: 17_814_000 picoseconds. - Weight::from_parts(18_006_000, 0) - .saturating_add(Weight::from_parts(0, 4273)) - // Standard Error: 10_358 - .saturating_add(Weight::from_parts(15_409_972, 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: 18_957_000 picoseconds. - Weight::from_parts(19_347_000, 0) - .saturating_add(Weight::from_parts(0, 4273)) - // Standard Error: 5_051 - .saturating_add(Weight::from_parts(15_416_931, 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_409_000 picoseconds. - Weight::from_parts(15_835_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: 26_753_000 picoseconds. - Weight::from_parts(27_349_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_918_000 picoseconds. - Weight::from_parts(34_624_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_863_000 picoseconds. - Weight::from_parts(46_674_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: 40_592_000 picoseconds. - Weight::from_parts(41_582_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: 46_170_000 picoseconds. - Weight::from_parts(46_880_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: 18_421_000 picoseconds. - Weight::from_parts(19_003_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_009_000 picoseconds. - Weight::from_parts(18_683_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: 14_702_000 picoseconds. - Weight::from_parts(15_118_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: 14_329_000 picoseconds. - Weight::from_parts(14_857_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: 15_776_000 picoseconds. - Weight::from_parts(16_337_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: 14_290_000 picoseconds. - Weight::from_parts(14_655_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_296_000 picoseconds. - Weight::from_parts(30_512_261, 0) - .saturating_add(Weight::from_parts(0, 4273)) - // Standard Error: 474 - .saturating_add(Weight::from_parts(530, 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 clear_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `406` - // Estimated: `4273` - // Minimum execution time: 30_342_000 picoseconds. - Weight::from_parts(31_030_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: 13_574_000 picoseconds. - Weight::from_parts(14_181_016, 0) - .saturating_add(Weight::from_parts(0, 4273)) - // Standard Error: 262 - .saturating_add(Weight::from_parts(420, 0).saturating_mul(n.into())) - // Standard Error: 262 - .saturating_add(Weight::from_parts(1_118, 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_679_000 picoseconds. - Weight::from_parts(30_346_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_334_000 picoseconds. - Weight::from_parts(13_827_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: 32_648_000 picoseconds. - Weight::from_parts(33_555_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: 65_431_000 picoseconds. - Weight::from_parts(66_502_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: 35_207_000 picoseconds. - Weight::from_parts(35_915_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_768_000 picoseconds. - Weight::from_parts(36_553_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_108_000 picoseconds. - Weight::from_parts(15_556_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_373_000 picoseconds. - Weight::from_parts(35_200_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: 32_201_000 picoseconds. - Weight::from_parts(33_591_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_148_000 picoseconds. - Weight::from_parts(31_751_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_127_000 picoseconds. - Weight::from_parts(29_922_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_386_000 picoseconds. - Weight::from_parts(18_762_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-polkadot/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs deleted file mode 100644 index 810f5b57c45..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_assets_local.rs +++ /dev/null @@ -1,528 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_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_698_000 picoseconds. - Weight::from_parts(27_507_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_833_000 picoseconds. - Weight::from_parts(11_314_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_389_000 picoseconds. - Weight::from_parts(14_231_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_027_000 picoseconds. - Weight::from_parts(16_455_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) - // Standard Error: 10_266 - .saturating_add(Weight::from_parts(15_263_742, 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: 17_167_000 picoseconds. - Weight::from_parts(17_397_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) - // Standard Error: 5_072 - .saturating_add(Weight::from_parts(15_429_203, 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: `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_694_000 picoseconds. - Weight::from_parts(14_239_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_406_000 picoseconds. - Weight::from_parts(24_981_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_372_000 picoseconds. - Weight::from_parts(32_021_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: 42_982_000 picoseconds. - Weight::from_parts(43_918_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_161_000 picoseconds. - Weight::from_parts(38_756_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_141_000 picoseconds. - Weight::from_parts(44_187_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: 16_721_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)) - } - /// 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_623_000 picoseconds. - Weight::from_parts(17_110_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_079_000 picoseconds. - Weight::from_parts(13_700_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_026_000 picoseconds. - Weight::from_parts(13_444_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: 13_945_000 picoseconds. - Weight::from_parts(14_792_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_800_000 picoseconds. - Weight::from_parts(13_183_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_637_000 picoseconds. - Weight::from_parts(28_967_060, 0) - .saturating_add(Weight::from_parts(0, 3675)) - // Standard Error: 464 - .saturating_add(Weight::from_parts(572, 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_427_000 picoseconds. - Weight::from_parts(28_961_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_251_000 picoseconds. - Weight::from_parts(12_928_907, 0) - .saturating_add(Weight::from_parts(0, 3675)) - // Standard Error: 244 - .saturating_add(Weight::from_parts(1_800, 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_263_000 picoseconds. - Weight::from_parts(29_165_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_343_000 picoseconds. - Weight::from_parts(12_659_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_113_000 picoseconds. - Weight::from_parts(31_798_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_428_000 picoseconds. - Weight::from_parts(62_707_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_538_000 picoseconds. - Weight::from_parts(34_216_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_870_000 picoseconds. - Weight::from_parts(34_709_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_358_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::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_159_000 picoseconds. - Weight::from_parts(32_998_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_709_000 picoseconds. - Weight::from_parts(31_486_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: 29_557_000 picoseconds. - Weight::from_parts(30_510_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_027_000 picoseconds. - Weight::from_parts(28_865_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_758_000 picoseconds. - Weight::from_parts(17_280_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-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs deleted file mode 100644 index 7c4501e6d88..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_balances.rs +++ /dev/null @@ -1,152 +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. - -//! Autogenerated weights for `pallet_balances` -//! -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --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/ - -#![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: 56_173_000 picoseconds. - Weight::from_parts(57_097_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: 41_470_000 picoseconds. - Weight::from_parts(42_051_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: `103` - // Estimated: `3593` - // Minimum execution time: 14_771_000 picoseconds. - Weight::from_parts(15_125_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: `103` - // Estimated: `3593` - // Minimum execution time: 22_210_000 picoseconds. - Weight::from_parts(22_712_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_475_000 picoseconds. - Weight::from_parts(58_343_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: 52_139_000 picoseconds. - Weight::from_parts(52_601_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: `103` - // Estimated: `3593` - // Minimum execution time: 17_372_000 picoseconds. - Weight::from_parts(17_978_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:999 w:999) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 17_143_000 picoseconds. - Weight::from_parts(17_475_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 16_909 - .saturating_add(Weight::from_parts(15_474_628, 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-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs deleted file mode 100644 index b3062984baf..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs +++ /dev/null @@ -1,246 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_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: 14_882_000 picoseconds. - Weight::from_parts(12_290_529, 0) - .saturating_add(Weight::from_parts(0, 1154)) - // Standard Error: 6_842 - .saturating_add(Weight::from_parts(3_189_571, 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: 48_113_000 picoseconds. - Weight::from_parts(49_767_909, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_725 - .saturating_add(Weight::from_parts(232_655, 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_228_000 picoseconds. - Weight::from_parts(16_351_387, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_953 - .saturating_add(Weight::from_parts(140_754, 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_541_000 picoseconds. - Weight::from_parts(7_720_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(_c: u32, _k: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_402_000 picoseconds. - Weight::from_parts(7_729_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: 41_874_000 picoseconds. - Weight::from_parts(45_654_015, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_317 - .saturating_add(Weight::from_parts(221_237, 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: 33_693_000 picoseconds. - Weight::from_parts(37_321_527, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 3_499 - .saturating_add(Weight::from_parts(182_068, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - fn update_bond(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)) - } - fn take_candidate_slot(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: 44_412_000 picoseconds. - Weight::from_parts(45_196_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_360_000 picoseconds. - Weight::from_parts(17_599_000, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 350_829 - .saturating_add(Weight::from_parts(15_375_949, 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/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs deleted file mode 100644 index a9f0cb07cfe..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// westmint-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/westmint/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 12_192_000 picoseconds. - Weight::from_parts(12_192_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 10_447_000 picoseconds. - Weight::from_parts(10_447_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 4_851_000 picoseconds. - Weight::from_parts(4_851_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_342_000 picoseconds. - Weight::from_parts(6_342_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_199_000 picoseconds. - Weight::from_parts(6_199_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 58_612_000 picoseconds. - Weight::from_parts(58_612_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 7_296_000 picoseconds. - Weight::from_parts(7_296_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 48_345_000 picoseconds. - Weight::from_parts(48_345_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 56_441_000 picoseconds. - Weight::from_parts(56_441_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 70_858_000 picoseconds. - Weight::from_parts(70_858_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs deleted file mode 100644 index 0bb05511d7a..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,164 +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. - -//! Autogenerated weights for `pallet_multisig` -//! -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_710_000 picoseconds. - Weight::from_parts(14_702_959, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(568, 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: `262 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 45_518_000 picoseconds. - Weight::from_parts(35_243_068, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_634 - .saturating_add(Weight::from_parts(116_658, 0).saturating_mul(s.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_444, 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: `282` - // Estimated: `6811` - // Minimum execution time: 29_590_000 picoseconds. - Weight::from_parts(21_574_604, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_622 - .saturating_add(Weight::from_parts(95_669, 0).saturating_mul(s.into())) - // Standard Error: 15 - .saturating_add(Weight::from_parts(1_459, 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: `385 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 51_056_000 picoseconds. - Weight::from_parts(35_799_301, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_629 - .saturating_add(Weight::from_parts(183_343, 0).saturating_mul(s.into())) - // Standard Error: 15 - .saturating_add(Weight::from_parts(1_686, 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: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 30_910_000 picoseconds. - Weight::from_parts(32_413_023, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_346 - .saturating_add(Weight::from_parts(128_779, 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: `282` - // Estimated: `6811` - // Minimum execution time: 17_926_000 picoseconds. - Weight::from_parts(18_477_305, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_367 - .saturating_add(Weight::from_parts(113_018, 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: `454 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 32_232_000 picoseconds. - Weight::from_parts(33_724_753, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_192 - .saturating_add(Weight::from_parts(121_574, 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-polkadot/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs deleted file mode 100644 index 842daf49f59..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_nfts.rs +++ /dev/null @@ -1,772 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_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: `145` - // Estimated: `3549` - // Minimum execution time: 37_915_000 picoseconds. - Weight::from_parts(39_275_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: `42` - // Estimated: `3549` - // Minimum execution time: 22_722_000 picoseconds. - Weight::from_parts(23_500_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: `32170 + a * (366 ±0)` - // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_231_520_000 picoseconds. - Weight::from_parts(1_228_960_098, 0) - .saturating_add(Weight::from_parts(0, 2523990)) - // Standard Error: 8_836 - .saturating_add(Weight::from_parts(6_818_975, 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: `421` - // Estimated: `4326` - // Minimum execution time: 48_581_000 picoseconds. - Weight::from_parts(50_020_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: `421` - // Estimated: `4326` - // Minimum execution time: 47_171_000 picoseconds. - Weight::from_parts(48_084_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: `530` - // Estimated: `4326` - // Minimum execution time: 53_591_000 picoseconds. - Weight::from_parts(55_074_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: `559` - // Estimated: `4326` - // Minimum execution time: 40_935_000 picoseconds. - Weight::from_parts(41_835_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: `729 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 16_543_000 picoseconds. - Weight::from_parts(16_769_000, 0) - .saturating_add(Weight::from_parts(0, 3549)) - // Standard Error: 23_638 - .saturating_add(Weight::from_parts(17_762_895, 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: `401` - // Estimated: `3534` - // Minimum execution time: 20_446_000 picoseconds. - Weight::from_parts(20_740_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: `401` - // Estimated: `3534` - // Minimum execution time: 20_088_000 picoseconds. - Weight::from_parts(20_627_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: `306` - // Estimated: `3549` - // Minimum execution time: 17_036_000 picoseconds. - Weight::from_parts(17_435_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: `354` - // Estimated: `3549` - // Minimum execution time: 22_528_000 picoseconds. - Weight::from_parts(23_047_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: `335` - // Estimated: `6078` - // Minimum execution time: 38_473_000 picoseconds. - Weight::from_parts(39_353_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: `277` - // Estimated: `3549` - // Minimum execution time: 17_708_000 picoseconds. - Weight::from_parts(18_022_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: `242` - // Estimated: `3549` - // Minimum execution time: 14_606_000 picoseconds. - Weight::from_parts(14_891_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: `401` - // Estimated: `3534` - // Minimum execution time: 19_492_000 picoseconds. - Weight::from_parts(19_919_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: `505` - // Estimated: `3944` - // Minimum execution time: 50_583_000 picoseconds. - Weight::from_parts(53_846_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: `310` - // Estimated: `3944` - // Minimum execution time: 25_937_000 picoseconds. - Weight::from_parts(26_540_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: `949` - // Estimated: `3944` - // Minimum execution time: 45_738_000 picoseconds. - Weight::from_parts(46_468_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: `347` - // Estimated: `4466` - // Minimum execution time: 17_361_000 picoseconds. - Weight::from_parts(18_191_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: `726 + n * (398 ±0)` - // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 25_884_000 picoseconds. - Weight::from_parts(26_265_000, 0) - .saturating_add(Weight::from_parts(0, 4466)) - // Standard Error: 6_423 - .saturating_add(Weight::from_parts(6_507_369, 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: `505` - // Estimated: `3812` - // Minimum execution time: 40_802_000 picoseconds. - Weight::from_parts(41_742_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: `815` - // Estimated: `3812` - // Minimum execution time: 38_904_000 picoseconds. - Weight::from_parts(39_919_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: `364` - // Estimated: `3759` - // Minimum execution time: 37_012_000 picoseconds. - Weight::from_parts(37_632_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: `682` - // Estimated: `3759` - // Minimum execution time: 36_243_000 picoseconds. - Weight::from_parts(37_313_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: `376` - // Estimated: `4326` - // Minimum execution time: 20_919_000 picoseconds. - Weight::from_parts(21_505_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: `384` - // Estimated: `4326` - // Minimum execution time: 18_943_000 picoseconds. - Weight::from_parts(19_969_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: `384` - // Estimated: `4326` - // Minimum execution time: 17_320_000 picoseconds. - Weight::from_parts(18_071_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: `42` - // Estimated: `3517` - // Minimum execution time: 14_934_000 picoseconds. - Weight::from_parts(15_422_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: `306` - // Estimated: `3549` - // Minimum execution time: 18_715_000 picoseconds. - Weight::from_parts(19_025_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: `289` - // Estimated: `3538` - // Minimum execution time: 18_249_000 picoseconds. - Weight::from_parts(18_826_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: `484` - // Estimated: `4326` - // Minimum execution time: 23_529_000 picoseconds. - Weight::from_parts(23_958_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: `671` - // Estimated: `4326` - // Minimum execution time: 50_885_000 picoseconds. - Weight::from_parts(52_157_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_258_000 picoseconds. - Weight::from_parts(3_342_691, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_268 - .saturating_add(Weight::from_parts(3_761_373, 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: `460` - // Estimated: `7662` - // Minimum execution time: 21_220_000 picoseconds. - Weight::from_parts(21_654_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: `479` - // Estimated: `4326` - // Minimum execution time: 20_430_000 picoseconds. - Weight::from_parts(21_038_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: `800` - // Estimated: `7662` - // Minimum execution time: 83_344_000 picoseconds. - Weight::from_parts(84_898_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: `524` - // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 143_435_000 picoseconds. - Weight::from_parts(151_744_537, 0) - .saturating_add(Weight::from_parts(0, 6078)) - // Standard Error: 44_459 - .saturating_add(Weight::from_parts(31_293_503, 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: `554` - // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 84_627_000 picoseconds. - Weight::from_parts(96_076_065, 0) - .saturating_add(Weight::from_parts(0, 4466)) - // Standard Error: 62_058 - .saturating_add(Weight::from_parts(30_461_383, 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-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs deleted file mode 100644 index b6121f2fca2..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_proxy.rs +++ /dev/null @@ -1,225 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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: `127 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 16_130_000 picoseconds. - Weight::from_parts(16_649_312, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 761 - .saturating_add(Weight::from_parts(42_507, 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_732_000 picoseconds. - Weight::from_parts(36_993_926, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 3_278 - .saturating_add(Weight::from_parts(144_955, 0).saturating_mul(a.into())) - // Standard Error: 3_387 - .saturating_add(Weight::from_parts(64_624, 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_229_000 picoseconds. - Weight::from_parts(24_199_507, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_672 - .saturating_add(Weight::from_parts(124_324, 0).saturating_mul(a.into())) - // Standard Error: 1_727 - .saturating_add(Weight::from_parts(28_481, 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: 23_868_000 picoseconds. - Weight::from_parts(25_293_069, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_728 - .saturating_add(Weight::from_parts(114_080, 0).saturating_mul(a.into())) - // Standard Error: 1_786 - .saturating_add(Weight::from_parts(3_690, 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: 34_343_000 picoseconds. - Weight::from_parts(34_539_112, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_917 - .saturating_add(Weight::from_parts(117_360, 0).saturating_mul(a.into())) - // Standard Error: 1_981 - .saturating_add(Weight::from_parts(40_908, 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: 25_506_000 picoseconds. - Weight::from_parts(26_350_920, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_950 - .saturating_add(Weight::from_parts(48_972, 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_234_000 picoseconds. - Weight::from_parts(26_232_489, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_468 - .saturating_add(Weight::from_parts(48_955, 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_184_000 picoseconds. - Weight::from_parts(22_974_929, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_200 - .saturating_add(Weight::from_parts(45_741, 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: 27_044_000 picoseconds. - Weight::from_parts(27_978_605, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_206 - .saturating_add(Weight::from_parts(13_736, 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: 22_770_000 picoseconds. - Weight::from_parts(23_441_470, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_959 - .saturating_add(Weight::from_parts(47_317, 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-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs deleted file mode 100644 index 560322abeb3..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_session.rs +++ /dev/null @@ -1,80 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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: `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_684_000 picoseconds. - Weight::from_parts(17_167_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: 11_692_000 picoseconds. - Weight::from_parts(12_248_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/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs deleted file mode 100644 index 17b050c3e90..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,74 +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. - -//! Autogenerated weights for `pallet_timestamp` -//! -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_timestamp`. -pub struct WeightInfo(PhantomData); -impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Aura::CurrentSlot` (r:1 w:0) - /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set() -> Weight { - // Proof Size summary in bytes: - // Measured: `86` - // Estimated: `1493` - // Minimum execution time: 9_214_000 picoseconds. - Weight::from_parts(9_535_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: `57` - // Estimated: `0` - // Minimum execution time: 3_269_000 picoseconds. - Weight::from_parts(3_458_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs deleted file mode 100644 index 5b13d56f5bb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_uniques.rs +++ /dev/null @@ -1,466 +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. - -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-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-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_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: 29_513_000 picoseconds. - Weight::from_parts(30_346_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_600_000 picoseconds. - Weight::from_parts(14_110_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_945_869_000 picoseconds. - Weight::from_parts(3_037_917_000, 0) - .saturating_add(Weight::from_parts(0, 3643)) - // Standard Error: 35_850 - .saturating_add(Weight::from_parts(7_558_563, 0).saturating_mul(n.into())) - // Standard Error: 35_850 - .saturating_add(Weight::from_parts(501_089, 0).saturating_mul(m.into())) - // Standard Error: 35_850 - .saturating_add(Weight::from_parts(538_921, 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: 36_225_000 picoseconds. - Weight::from_parts(36_858_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: 37_021_000 picoseconds. - Weight::from_parts(37_749_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_884_000 picoseconds. - Weight::from_parts(27_414_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_797_000 picoseconds. - Weight::from_parts(14_943_000, 0) - .saturating_add(Weight::from_parts(0, 3643)) - // Standard Error: 25_250 - .saturating_add(Weight::from_parts(18_014_600, 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_864_000 picoseconds. - Weight::from_parts(19_299_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_530_000 picoseconds. - Weight::from_parts(19_230_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_807_000 picoseconds. - Weight::from_parts(14_270_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_657_000 picoseconds. - Weight::from_parts(14_059_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_108_000 picoseconds. - Weight::from_parts(22_520_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: 14_128_000 picoseconds. - Weight::from_parts(14_481_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: 17_114_000 picoseconds. - Weight::from_parts(17_570_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: 40_412_000 picoseconds. - Weight::from_parts(43_009_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: 38_044_000 picoseconds. - Weight::from_parts(38_871_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: 30_016_000 picoseconds. - Weight::from_parts(30_723_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_942_000 picoseconds. - Weight::from_parts(31_527_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_727_000 picoseconds. - Weight::from_parts(31_688_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_844_000 picoseconds. - Weight::from_parts(30_403_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_155_000 picoseconds. - Weight::from_parts(19_909_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_163_000 picoseconds. - Weight::from_parts(19_804_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_413_000 picoseconds. - Weight::from_parts(15_762_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_477_000 picoseconds. - Weight::from_parts(16_811_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_415_000 picoseconds. - Weight::from_parts(16_906_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_814_000 picoseconds. - Weight::from_parts(36_569_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/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs deleted file mode 100644 index d028fb898a4..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_utility.rs +++ /dev/null @@ -1,101 +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. - -//! Autogenerated weights for `pallet_utility` -//! -//! 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-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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_918_000 picoseconds. - Weight::from_parts(2_421_521, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_252 - .saturating_add(Weight::from_parts(6_625_635, 0).saturating_mul(c.into())) - } - fn as_derivative() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_304_000 picoseconds. - Weight::from_parts(5_546_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_847_000 picoseconds. - Weight::from_parts(1_224_975, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_818 - .saturating_add(Weight::from_parts(6_891_149, 0).saturating_mul(c.into())) - } - fn dispatch_as() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_269_000 picoseconds. - Weight::from_parts(9_604_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_855_000 picoseconds. - Weight::from_parts(6_965_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_631 - .saturating_add(Weight::from_parts(6_545_496, 0).saturating_mul(c.into())) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs deleted file mode 100644 index 27867e278ed..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-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 -// 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 -// --chain=asset-hub-polkadot-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 25_203_000 picoseconds. - Weight::from_parts(25_927_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 20_113_000 picoseconds. - Weight::from_parts(20_439_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: 14_959_000 picoseconds. - Weight::from_parts(15_264_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: 7_399_000 picoseconds. - Weight::from_parts(7_674_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_388_000 picoseconds. - Weight::from_parts(2_522_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `75` - // Estimated: `3540` - // Minimum execution time: 28_791_000 picoseconds. - Weight::from_parts(29_443_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `292` - // Estimated: `3757` - // Minimum execution time: 30_880_000 picoseconds. - Weight::from_parts(31_675_000, 0) - .saturating_add(Weight::from_parts(0, 3757)) - .saturating_add(T::DbWeight::get().reads(7)) - .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_365_000 picoseconds. - Weight::from_parts(2_550_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: `129` - // Estimated: `11019` - // Minimum execution time: 17_185_000 picoseconds. - Weight::from_parts(17_680_000, 0) - .saturating_add(Weight::from_parts(0, 11019)) - .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: `133` - // Estimated: `11023` - // Minimum execution time: 16_974_000 picoseconds. - Weight::from_parts(17_660_000, 0) - .saturating_add(Weight::from_parts(0, 11023)) - .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: `140` - // Estimated: `13505` - // Minimum execution time: 18_536_000 picoseconds. - Weight::from_parts(19_292_000, 0) - .saturating_add(Weight::from_parts(0, 13505)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `6082` - // Minimum execution time: 27_368_000 picoseconds. - Weight::from_parts(28_161_000, 0) - .saturating_add(Weight::from_parts(0, 6082)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `172` - // Estimated: `8587` - // Minimum execution time: 9_553_000 picoseconds. - Weight::from_parts(9_899_000, 0) - .saturating_add(Weight::from_parts(0, 8587)) - .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: `140` - // Estimated: `11030` - // Minimum execution time: 17_445_000 picoseconds. - Weight::from_parts(18_206_000, 0) - .saturating_add(Weight::from_parts(0, 11030)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `146` - // Estimated: `11036` - // Minimum execution time: 34_200_000 picoseconds. - Weight::from_parts(35_198_000, 0) - .saturating_add(Weight::from_parts(0, 11036)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) - /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1554` - // Minimum execution time: 4_679_000 picoseconds. - Weight::from_parts(4_841_000, 0) - .saturating_add(Weight::from_parts(0, 1554)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `PolkadotXcm::Queries` (r:1 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn take_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `7706` - // Estimated: `11171` - // Minimum execution time: 27_281_000 picoseconds. - Weight::from_parts(27_694_000, 0) - .saturating_add(Weight::from_parts(0, 11171)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/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 deleted file mode 100644 index 44fcb91d688..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs +++ /dev/null @@ -1,244 +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. - -mod pallet_xcm_benchmarks_fungible; -mod pallet_xcm_benchmarks_generic; - -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}; - -trait WeighMultiAssets { - fn weigh_multi_assets(&self, weight: Weight) -> Weight; -} - -const MAX_ASSETS: u64 = 100; - -impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, weight: Weight) -> Weight { - match self { - 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, weight: Weight) -> Weight { - weight.saturating_mul(self.inner().iter().count() as u64) - } -} - -pub struct AssetHubPolkadotXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for AssetHubPolkadotXcmWeight { - fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) - } - 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()) - } - 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(XcmFungibleWeight::::transfer_asset()) - } - fn transfer_reserve_asset( - assets: &MultiAssets, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) - } - fn transact( - _origin_type: &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(XcmFungibleWeight::::deposit_asset()) - } - fn deposit_reserve_asset( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) - } - fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - Weight::MAX - } - fn initiate_reserve_withdraw( - assets: &MultiAssetFilter, - _reserve: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) - } - fn initiate_teleport( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::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 { - Weight::MAX - } - fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - Weight::MAX - } - fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - 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() - } -} 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 deleted file mode 100644 index 1036d4cbf00..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,187 +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. - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! 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 -// 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_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)] -#![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: 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)) - } - // 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: 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)) - } - // 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: `176` - // Estimated: `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)) - } - // 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: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `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: `75` - // Estimated: `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)) - } - pub fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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`) - pub fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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)) - } - // 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: `75` - // Estimated: `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)) - } - // 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: `75` - // Estimated: `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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index 12ef504727e..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,328 +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. - -//! 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-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=asset-hub-polkadot-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-polkadot/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: `75` - // Estimated: `3540` - // Minimum execution time: 425_235_000 picoseconds. - Weight::from_parts(432_935_000, 3540) - .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_070_000 picoseconds. - Weight::from_parts(4_329_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: `69` - // Estimated: `3534` - // Minimum execution time: 11_464_000 picoseconds. - Weight::from_parts(11_829_000, 3534) - .saturating_add(T::DbWeight::get().reads(1)) - } - pub fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 13_574_000 picoseconds. - Weight::from_parts(14_021_000, 0) - } - pub fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_276_000 picoseconds. - Weight::from_parts(4_479_000, 0) - } - pub fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(2_939_000, 0) - } - pub fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_797_000 picoseconds. - Weight::from_parts(2_901_000, 0) - } - pub fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_855_000 picoseconds. - Weight::from_parts(2_961_000, 0) - } - pub fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_589_000 picoseconds. - Weight::from_parts(3_720_000, 0) - } - pub fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_786_000 picoseconds. - Weight::from_parts(2_889_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: `75` - // Estimated: `3540` - // Minimum execution time: 25_740_000 picoseconds. - Weight::from_parts(26_355_000, 3540) - .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: `126` - // Estimated: `3591` - // Minimum execution time: 16_206_000 picoseconds. - Weight::from_parts(16_651_000, 3591) - .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_819_000 picoseconds. - Weight::from_parts(2_944_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: `75` - // Estimated: `3540` - // Minimum execution time: 28_216_000 picoseconds. - Weight::from_parts(28_878_000, 3540) - .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_795_000 picoseconds. - Weight::from_parts(5_008_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: 135_205_000 picoseconds. - Weight::from_parts(140_623_000, 0) - } - pub fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 12_791_000 picoseconds. - Weight::from_parts(13_114_000, 0) - } - pub fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_091_000, 0) - } - pub fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_828_000 picoseconds. - Weight::from_parts(2_947_000, 0) - } - pub fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_980_000 picoseconds. - Weight::from_parts(3_123_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: `75` - // Estimated: `3540` - // Minimum execution time: 29_672_000 picoseconds. - Weight::from_parts(30_318_000, 3540) - .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_421_000 picoseconds. - Weight::from_parts(5_614_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: `75` - // Estimated: `3540` - // Minimum execution time: 25_621_000 picoseconds. - Weight::from_parts(26_486_000, 3540) - .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_873_000 picoseconds. - Weight::from_parts(2_973_000, 0) - } - pub fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_861_000 picoseconds. - Weight::from_parts(2_923_000, 0) - } - pub fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_845_000 picoseconds. - Weight::from_parts(2_970_000, 0) - } - pub fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_773_000 picoseconds. - Weight::from_parts(2_922_000, 0) - } - pub fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_980_000 picoseconds. - Weight::from_parts(3_095_000, 0) - } -} 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 deleted file mode 100644 index b3c2ce4da76..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ /dev/null @@ -1,546 +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 super::{ - AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, - ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, CENTS, -}; -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, ConcreteAssetFromSystem}, -}; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use sp_runtime::traits::ConvertInto; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, - 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}; - -parameter_types! { - pub const DotLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Polkadot); - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); - pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); - pub TrustBackedAssetsPalletLocation: MultiLocation = - PalletInstance(::index() as u8).into(); - pub CheckingAccount: AccountId = PolkadotXcm::check_account(); - pub FellowshipLocation: MultiLocation = MultiLocation::new(1, Parachain(1001)); - pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); -} - -/// 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 chain account alias into local accounts according to a hash of their standard - // description. - HashedDescription>, -); - -/// 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 `TrustBackedAssets`. -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, ->; - -/// Means for transacting assets on this chain. -pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor); - -/// 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 FellowsPlurality: impl Contains = { - MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) } - }; - 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 -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - 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::MessageQueue(..) | - RuntimeCall::Assets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::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::refund { .. }, - ) | 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::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::refund { .. }, - ) | 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 { .. } - ) - ) - } -} - -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 the Fellows plurality - // get free execution. - AllowExplicitUnpaidExecutionFrom<( - ParentOrParentsPlurality, - FellowsPlurality, - FellowshipSalaryPallet, - AmbassadorSalaryPallet, - )>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier< - Runtime, - WeightToFee, - pallet_assets::BalanceToAssetBalance, - 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; - type XcmSender = XcmRouter; - type AssetTransactor = AssetTransactors; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - // Asset Hub Polkadot does not recognize a reserve location for any asset. This does not prevent - // 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 = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::AssetHubPolkadotXcmWeight, - RuntimeCall, - MaxInstructions, - >; - type Trader = ( - UsingComponents>, - cumulus_primitives_utility::TakeFirstAssetTrader< - AccountId, - AssetFeeAsExistentialDepositMultiplierFeeCharger, - TrustBackedAssetsConvertedConcreteId, - Assets, - cumulus_primitives_utility::XcmFeesTo32ByteAccount< - FungiblesTransactor, - AccountId, - XcmAssetFeesReceiver, - >, - >, - ); - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - 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; - -parameter_types! { - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(DotLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -pub type PriceForParentDelivery = - ExponentialPrice; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -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; - type XcmReserveTransferFilter = Everything; - type Weigher = WeightInfoBounds< - crate::weights::xcm::AssetHubPolkadotXcmWeight, - 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; - 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)) } - } -} - -#[test] -fn foreign_pallet_has_correct_local_account() { - use sp_core::crypto::{Ss58AddressFormat, Ss58Codec}; - use xcm_executor::traits::ConvertLocation; - - const COLLECTIVES_PARAID: u32 = 1001; - const FELLOWSHIP_SALARY_PALLET_ID: u8 = 64; - let fellowship_salary = - (Parent, Parachain(COLLECTIVES_PARAID), PalletInstance(FELLOWSHIP_SALARY_PALLET_ID)); - let account = LocationToAccountId::convert_location(&fellowship_salary.into()).unwrap(); - let polkadot = Ss58AddressFormat::try_from("polkadot").unwrap(); - let address = Ss58Codec::to_ss58check_with_version(&account, polkadot); - assert_eq!(address, "13w7NdvSR1Af8xsQTArDtZmVvjE8XhWNdL4yed3iFHrUNCnS"); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs deleted file mode 100644 index b7e44646ece..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ /dev/null @@ -1,683 +0,0 @@ -// 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 Statemint (Polkadot Assets Hub) chain. - -use asset_hub_polkadot_runtime::xcm_config::{ - AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation, - ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation, - XcmConfig, -}; -pub use asset_hub_polkadot_runtime::{ - AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, -}; -use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; -use codec::{Decode, Encode}; -use cumulus_primitives_utility::ChargeWeightInFungibles; -use frame_support::{ - assert_noop, assert_ok, - traits::fungibles::InspectEnumerable, - weights::{Weight, WeightToFee as WeightToFeeT}, -}; -use parachains_common::{ - polkadot::fee::WeightToFee, AccountId, AssetHubPolkadotAuraId as AuraId, - AssetIdForTrustBackedAssets, 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_keys() -> CollatorSessionKeys { - CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(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::ed25519::Public::from_raw(ALICE)) }, - )]) - .build() - .execute_with(|| { - // We need root origin to create a sufficient asset - let minimum_asset_balance = 333333333_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 400e9 weight - // Because of the ED being higher in kusama's asset hub - // and not to complicate things, we use a little - // bit more of weight - let bought = Weight::from_parts(400_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::ed25519::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 400e9 weight - // Because of the ED being higher in kusama's asset hub - // and not to complicate things, we use a little - // bit more of weight - let bought = Weight::from_parts(400_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::ed25519::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 50e9 weight - // Because of the ED being higher in kusama's asset hub - // and not to complicate things, we use a little - // bit more of weight - let bought = Weight::from_parts(50_000_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::ed25519::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::ed25519::Public::from_raw(ALICE)) }, - )]) - .build() - .execute_with(|| { - // Create a non-sufficient asset - 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 400e9 weight - // Because of the ED being higher in kusama's asset hub - // and not to complicate things, we use a little - // bit more of weight - let bought = Weight::from_parts(400_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::ed25519::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, - } - }), - 1000 -); - -asset_test_utils::include_teleports_for_foreign_assets_works!( - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - CheckingAccount, - WeightToFee, - ParachainSystem, - ForeignCreatorsSovereignAccountOf, - ForeignAssetsInstance, - asset_test_utils::CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) } - ), - 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, - asset_test_utils::CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) } - ), - 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, - asset_test_utils::CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) } - ), - 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); - }) -); - -#[test] -fn reserve_transfer_native_asset_to_non_teleport_para_works() { - asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< - 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, - } - }), - WeightLimit::Unlimited, - ); -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml deleted file mode 100644 index 2cd002b1c60..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ /dev/null @@ -1,192 +0,0 @@ -[package] -name = "bridge-hub-kusama-runtime" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -description = "Kusama's BridgeHub parachain runtime" -license = "Apache-2.0" - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true, 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-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-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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-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} -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} - -# Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -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 } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } -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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } - -[dev-dependencies] -bridge-hub-test-utils = { path = "../test-utils" } - -[features] -default = [ "std" ] -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-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-session/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-utility/std", - "pallet-xcm-benchmarks?/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-core-primitives/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "scale-info/std", - "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", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] - -runtime-benchmarks = [ - "cumulus-pallet-dmp-queue/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-xcm-benchmarks/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-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-session/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", -] - -experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/build.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/build.rs deleted file mode 100644 index 60f8a125129..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/build.rs +++ /dev/null @@ -1,26 +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. - -#[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/bridge-hubs/bridge-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs deleted file mode 100644 index a511791d347..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ /dev/null @@ -1,872 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -mod weights; -pub mod xcm_config; - -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; - -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -use frame_support::{ - construct_runtime, - dispatch::DispatchClass, - genesis_builder_helper::{build_config, create_default_config}, - parameter_types, - traits::{ - ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, - }, - weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{FellowshipLocation, GovernanceLocation, XcmOriginToTransactDispatchOrigin}; - -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; - -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; - -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -use parachains_common::{ - impls::DealWithFees, - kusama::{consensus::*, currency::*, fee::WeightToFee}, - message_queue::{NarrowOriginToSibling, ParaIdToSibling}, - AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, - HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, -}; - -// XCM Imports -use xcm::latest::prelude::BodyId; - -/// The address format for describing accounts. -pub type Address = 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_transaction_payment::ChargeTransactionPayment, -); - -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; - -/// Migrations to apply on runtime upgrade. -pub type Migrations = ( - // unreleased - 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, ->; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("bridge-hub-kusama"), - impl_name: create_runtime_str!("bridge-hub-kusama"), - authoring_version: 1, - spec_version: 1_004_000, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 3, - state_version: 1, -}; - -/// 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 = 2; -} - -// Configure FRAME pallets to include in runtime. - -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The hashing algorithm used. - type Hashing = BlakeTwo256; - /// The block type. - type Block = Block; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// The basic call filter to use in dispatchable. - type BaseCallFilter = Everything; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = weights::frame_system::WeightInfo; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = 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 { - /// The type for recording an account's balance. - type Balance = Balance; - type DustRemoval = (); - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = weights::pallet_balances::WeightInfo; - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - 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 OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; -} - -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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = XcmpQueue; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -parameter_types! { - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -/// Privileged origin that represents Root or Fellows pluralistic body. -pub type RootOrFellows = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, ->; - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = RootOrFellows; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - -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, ConstU32>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU32>; - 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 = ConstU32; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = weights::pallet_collator_selection::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); -} - -impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = ConstU32<100>; - 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; -} - -// 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} = 2, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, - - // Monetary stuff. - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, - - // Collator support. The order of these 4 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, Event, Origin, Config} = 31, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, - - // Handy utilities. - Utility: pallet_utility::{Pallet, Call, Event} = 40, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, - } -); - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_session, SessionBench::] - [pallet_utility, Utility] - [pallet_timestamp, Timestamp] - [pallet_collator_selection, CollatorSelection] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] - // XCM - [pallet_xcm, PalletXcmExtrinsicsBenchmark::] - // 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_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 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - - // 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::; - - 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - impl pallet_xcm::benchmarking::Config for Runtime { - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Relay/native token can be teleported between BH and Relay. - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - Parent.into(), - )) - } - - fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Reserve transfers are disabled on BH. - None - } - } - - use xcm::latest::prelude::*; - use xcm_config::KsmRelayLocation; - - parameter_types! { - pub ExistentialDepositMultiAsset: Option = Some(( - xcm_config::KsmRelayLocation::get(), - ExistentialDeposit::get() - ).into()); - } - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = xcm_config::XcmConfig; - type AccountIdConverter = xcm_config::LocationToAccountId; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositMultiAsset, - xcm_config::PriceForParentDelivery, - >; - fn valid_destination() -> Result { - Ok(KsmRelayLocation::get()) - } - fn worst_case_holding(_depositable_count: u32) -> MultiAssets { - // just concrete assets according to relay chain. - let assets: Vec = vec![ - MultiAsset { - id: Concrete(KsmRelayLocation::get()), - fun: Fungible(1_000_000 * UNITS), - } - ]; - assets.into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - KsmRelayLocation::get(), - MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmRelayLocation::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(KsmRelayLocation::get()), - fun: Fungible(UNITS), - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type TransactAsset = Balances; - 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> { - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((KsmRelayLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(KsmRelayLocation::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = KsmRelayLocation::get(); - let assets: MultiAssets = (Concrete(KsmRelayLocation::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::; - - 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(), - ]; - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - 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! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs deleted file mode 100644 index e7fdb2aae2a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +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. - -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/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index a30a2ae8d4d..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// bridge-hub-kusama-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(1_761_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 28_250 - .saturating_add(Weight::from_parts(24_261_433, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs deleted file mode 100644 index ffd311ceecd..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ /dev/null @@ -1,148 +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. - -//! Autogenerated weights for `cumulus_pallet_xcmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --pallet -// cumulus-pallet-xcmp-queue -// --chain -// bridge-hub-kusama-dev -// --output -// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs -// --extrinsic -// - -#![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_000_000 picoseconds. - Weight::from_parts(6_000_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:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn enqueue_xcmp_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `82` - // Estimated: `3517` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn suspend_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn resume_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `1596` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(5_000_000, 0) - .saturating_add(Weight::from_parts(0, 1596)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn take_first_concatenated_xcm() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65711` - // Estimated: `69176` - // Minimum execution time: 60_000_000 picoseconds. - Weight::from_parts(63_000_000, 0) - .saturating_add(Weight::from_parts(0, 69176)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65710` - // Estimated: `69175` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(43_000_000, 0) - .saturating_add(Weight::from_parts(0, 69175)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs deleted file mode 100644 index 1a4adb968bb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,53 +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. - -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/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs deleted file mode 100644 index 6b9313cdaba..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-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_985_000 picoseconds. - Weight::from_parts(2_177_341, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(386, 0).saturating_mul(b.into())) - } - /// The range of component `b` is `[0, 3932160]`. - fn remark_with_event(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_288_000 picoseconds. - Weight::from_parts(23_888_468, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_718, 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_700_000 picoseconds. - Weight::from_parts(3_867_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: 100_298_586_000 picoseconds. - Weight::from_parts(101_869_369_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_052_000 picoseconds. - Weight::from_parts(2_115_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_048 - .saturating_add(Weight::from_parts(755_436, 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_044_000 picoseconds. - Weight::from_parts(2_110_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_011 - .saturating_add(Weight::from_parts(569_993, 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: `68 + p * (69 ±0)` - // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 3_741_000 picoseconds. - Weight::from_parts(3_838_000, 0) - .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 2_455 - .saturating_add(Weight::from_parts(1_216_154, 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/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs deleted file mode 100644 index 36733d6d4a6..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/mod.rs +++ /dev/null @@ -1,41 +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 cumulus_pallet_dmp_queue; -pub mod cumulus_pallet_parachain_system; -pub mod cumulus_pallet_xcmp_queue; -pub mod extrinsic_weights; -pub mod frame_system; -pub mod pallet_balances; -pub mod pallet_collator_selection; -pub mod pallet_message_queue; -pub mod pallet_multisig; -pub mod pallet_session; -pub mod pallet_timestamp; -pub mod pallet_utility; -pub mod pallet_xcm; -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/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs deleted file mode 100644 index 04ceb5bed75..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs +++ /dev/null @@ -1,152 +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. - -//! Autogenerated weights for `pallet_balances` -//! -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --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/ - -#![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_163_000 picoseconds. - Weight::from_parts(56_056_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: 40_829_000 picoseconds. - Weight::from_parts(42_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`) - fn force_set_balance_creating() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 15_212_000 picoseconds. - Weight::from_parts(15_782_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: 22_866_000 picoseconds. - Weight::from_parts(23_452_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_047_000 picoseconds. - Weight::from_parts(58_536_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_622_000 picoseconds. - Weight::from_parts(52_912_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: 17_723_000 picoseconds. - Weight::from_parts(18_383_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:999 w:999) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 17_089_000 picoseconds. - Weight::from_parts(17_379_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 17_071 - .saturating_add(Weight::from_parts(15_647_341, 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/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs deleted file mode 100644 index 72d8ba4045a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs +++ /dev/null @@ -1,248 +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. - -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-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_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: `196 + b * (79 ±0)` - // Estimated: `1187 + b * (2555 ±0)` - // Minimum execution time: 14_329_000 picoseconds. - Weight::from_parts(11_605_842, 0) - .saturating_add(Weight::from_parts(0, 1187)) - // Standard Error: 4_784 - .saturating_add(Weight::from_parts(3_297_183, 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: `757 + b * (32 ±0) + c * (53 ±0)` - // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` - // Minimum execution time: 47_110_000 picoseconds. - Weight::from_parts(45_234_418, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 14_452 - .saturating_add(Weight::from_parts(156_031, 0).saturating_mul(b.into())) - // Standard Error: 2_739 - .saturating_add(Weight::from_parts(216_162, 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: `82 + b * (32 ±0)` - // Estimated: `6287` - // Minimum execution time: 15_326_000 picoseconds. - Weight::from_parts(14_914_611, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_274 - .saturating_add(Weight::from_parts(201_234, 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_288_000 picoseconds. - Weight::from_parts(7_472_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(_c: u32, _k: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_137_000 picoseconds. - Weight::from_parts(7_374_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: `740 + c * (52 ±0)` - // Estimated: `6287 + c * (54 ±0)` - // Minimum execution time: 40_718_000 picoseconds. - Weight::from_parts(43_911_837, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 3_053 - .saturating_add(Weight::from_parts(229_337, 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 `[3, 100]`. - fn leave_intent(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `334 + c * (49 ±0)` - // Estimated: `6287` - // Minimum execution time: 32_953_000 picoseconds. - Weight::from_parts(34_817_275, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_476 - .saturating_add(Weight::from_parts(198_023, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - fn update_bond(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)) - } - fn take_candidate_slot(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: `155` - // Estimated: `6196` - // Minimum execution time: 45_130_000 picoseconds. - Weight::from_parts(46_733_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: `2263 + c * (97 ±0) + r * (115 ±0)` - // Estimated: `6287 + c * (2519 ±0) + r * (2603 ±0)` - // Minimum execution time: 16_690_000 picoseconds. - Weight::from_parts(17_188_000, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 345_320 - .saturating_add(Weight::from_parts(15_166_422, 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs deleted file mode 100644 index c5a4235055d..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// bridge-hub-kusama-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/bridge-hubs/bridge-hub-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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 11_692_000 picoseconds. - Weight::from_parts(11_692_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 10_614_000 picoseconds. - Weight::from_parts(10_614_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 7_085_000 picoseconds. - Weight::from_parts(7_085_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 5_813_000 picoseconds. - Weight::from_parts(5_813_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_090_000 picoseconds. - Weight::from_parts(6_090_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 58_905_000 picoseconds. - Weight::from_parts(58_905_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 6_501_000 picoseconds. - Weight::from_parts(6_501_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 39_695_000 picoseconds. - Weight::from_parts(39_695_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 50_543_000 picoseconds. - Weight::from_parts(50_543_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 69_294_000 picoseconds. - Weight::from_parts(69_294_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs deleted file mode 100644 index f4135e975fb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,164 +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. - -//! Autogenerated weights for `pallet_multisig` -//! -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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_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_602_000 picoseconds. - Weight::from_parts(14_565_036, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(518, 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: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 46_075_000 picoseconds. - Weight::from_parts(33_730_493, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_049 - .saturating_add(Weight::from_parts(134_211, 0).saturating_mul(s.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_448, 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: `282` - // Estimated: `6811` - // Minimum execution time: 29_389_000 picoseconds. - Weight::from_parts(19_639_583, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 976 - .saturating_add(Weight::from_parts(106_598, 0).saturating_mul(s.into())) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_457, 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: `388 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 50_438_000 picoseconds. - Weight::from_parts(36_195_308, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_689 - .saturating_add(Weight::from_parts(176_067, 0).saturating_mul(s.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_545, 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: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 32_134_000 picoseconds. - Weight::from_parts(32_149_785, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_082 - .saturating_add(Weight::from_parts(145_390, 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: `282` - // Estimated: `6811` - // Minimum execution time: 17_560_000 picoseconds. - Weight::from_parts(18_144_079, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 763 - .saturating_add(Weight::from_parts(114_298, 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: `454 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 32_360_000 picoseconds. - Weight::from_parts(33_566_579, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_314 - .saturating_add(Weight::from_parts(126_583, 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/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs deleted file mode 100644 index f508e1daaef..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs +++ /dev/null @@ -1,80 +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. - -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-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: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:1 w:1) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `297` - // Estimated: `3762` - // Minimum execution time: 17_170_000 picoseconds. - Weight::from_parts(17_523_000, 0) - .saturating_add(Weight::from_parts(0, 3762)) - .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: `279` - // Estimated: `3744` - // Minimum execution time: 13_273_000 picoseconds. - Weight::from_parts(14_200_000, 0) - .saturating_add(Weight::from_parts(0, 3744)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs deleted file mode 100644 index 6162b1d48c5..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,74 +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. - -//! Autogenerated weights for `pallet_timestamp` -//! -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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: `Aura::CurrentSlot` (r:1 w:0) - /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set() -> Weight { - // Proof Size summary in bytes: - // Measured: `49` - // Estimated: `1493` - // Minimum execution time: 7_794_000 picoseconds. - Weight::from_parts(8_075_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: `57` - // Estimated: `0` - // Minimum execution time: 3_338_000 picoseconds. - Weight::from_parts(3_471_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs deleted file mode 100644 index 93d0ea596e7..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs +++ /dev/null @@ -1,101 +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. - -//! Autogenerated weights for `pallet_utility` -//! -//! 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("bridge-hub-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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_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_641_000 picoseconds. - Weight::from_parts(7_103_558, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_172 - .saturating_add(Weight::from_parts(4_907_384, 0).saturating_mul(c.into())) - } - fn as_derivative() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_741_000 picoseconds. - Weight::from_parts(4_870_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_561_000 picoseconds. - Weight::from_parts(12_252_064, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_750 - .saturating_add(Weight::from_parts(5_193_404, 0).saturating_mul(c.into())) - } - fn dispatch_as() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_646_000 picoseconds. - Weight::from_parts(8_927_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_726_000 picoseconds. - Weight::from_parts(8_025_954, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_746 - .saturating_add(Weight::from_parts(4_936_537, 0).saturating_mul(c.into())) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs deleted file mode 100644 index 7f4c2026f2b..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-kusama-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 -// --chain=bridge-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 22_520_000 picoseconds. - Weight::from_parts(23_167_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 19_639_000 picoseconds. - Weight::from_parts(20_230_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 reserve_transfer_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn 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: 7_175_000 picoseconds. - Weight::from_parts(7_496_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_126_000 picoseconds. - Weight::from_parts(2_359_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::Queries` (r:0 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn force_subscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 27_229_000 picoseconds. - Weight::from_parts(27_673_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `255` - // Estimated: `3720` - // Minimum execution time: 29_812_000 picoseconds. - Weight::from_parts(30_649_000, 0) - .saturating_add(Weight::from_parts(0, 3720)) - .saturating_add(T::DbWeight::get().reads(7)) - .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_212_000 picoseconds. - Weight::from_parts(2_367_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: `95` - // Estimated: `10985` - // Minimum execution time: 14_768_000 picoseconds. - Weight::from_parts(15_036_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .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: `99` - // Estimated: `10989` - // Minimum execution time: 14_662_000 picoseconds. - Weight::from_parts(15_155_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .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: `106` - // Estimated: `13471` - // Minimum execution time: 16_198_000 picoseconds. - Weight::from_parts(16_456_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `6046` - // Minimum execution time: 25_825_000 picoseconds. - Weight::from_parts(26_744_000, 0) - .saturating_add(Weight::from_parts(0, 6046)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) - /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn notify_target_migration_fail() -> Weight { - // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_622_000 picoseconds. - Weight::from_parts(8_931_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .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: `106` - // Estimated: `10996` - // Minimum execution time: 15_397_000 picoseconds. - Weight::from_parts(15_650_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 32_330_000 picoseconds. - Weight::from_parts(33_255_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) - /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1517` - // Minimum execution time: 4_142_000 picoseconds. - Weight::from_parts(4_308_000, 0) - .saturating_add(Weight::from_parts(0, 1517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `PolkadotXcm::Queries` (r:1 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn take_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `7669` - // Estimated: `11134` - // Minimum execution time: 25_814_000 picoseconds. - Weight::from_parts(26_213_000, 0) - .saturating_add(Weight::from_parts(0, 11134)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/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 deleted file mode 100644 index 71732961d3d..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs +++ /dev/null @@ -1,244 +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. - -mod pallet_xcm_benchmarks_fungible; -mod pallet_xcm_benchmarks_generic; - -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}; - -trait WeighMultiAssets { - fn weigh_multi_assets(&self, weight: Weight) -> Weight; -} - -const MAX_ASSETS: u64 = 100; - -impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, weight: Weight) -> Weight { - match self { - 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, weight: Weight) -> Weight { - weight.saturating_mul(self.inner().iter().count() as u64) - } -} - -pub struct BridgeHubKusamaXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for BridgeHubKusamaXcmWeight { - fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) - } - 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()) - } - 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(XcmFungibleWeight::::transfer_asset()) - } - fn transfer_reserve_asset( - assets: &MultiAssets, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) - } - fn transact( - _origin_type: &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(XcmFungibleWeight::::deposit_asset()) - } - fn deposit_reserve_asset( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) - } - fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - Weight::MAX - } - fn initiate_reserve_withdraw( - assets: &MultiAssetFilter, - _reserve: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) - } - fn initiate_teleport( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::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 { - Weight::MAX - } - fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - Weight::MAX - } - fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - 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() - } -} 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 deleted file mode 100644 index ff3cb452a8a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,187 +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. - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! 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 -// 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_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)] -#![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: 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)) - } - // 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: `153` - // Estimated: `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)) - } - // 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: `223` - // Estimated: `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)) - } - // 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: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `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: `70` - // Estimated: `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)) - } - pub fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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`) - pub fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `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)) - } - // 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: `122` - // Estimated: `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)) - } - // 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: `70` - // Estimated: `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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index c5c14e6917e..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,328 +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. - -//! 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("bridge-hub-kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-kusama/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: `70` - // Estimated: `3535` - // Minimum execution time: 33_141_000 picoseconds. - Weight::from_parts(34_380_000, 3535) - .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: 2_803_000 picoseconds. - Weight::from_parts(2_904_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: `32` - // Estimated: `3497` - // Minimum execution time: 10_308_000 picoseconds. - Weight::from_parts(10_753_000, 3497) - .saturating_add(T::DbWeight::get().reads(1)) - } - pub fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_499_000 picoseconds. - Weight::from_parts(11_786_000, 0) - } - pub fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_102_000 picoseconds. - Weight::from_parts(3_161_000, 0) - } - pub fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_678_000 picoseconds. - Weight::from_parts(2_795_000, 0) - } - pub fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_685_000 picoseconds. - Weight::from_parts(2_758_000, 0) - } - pub fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_590_000 picoseconds. - Weight::from_parts(2_754_000, 0) - } - pub fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_297_000 picoseconds. - Weight::from_parts(3_419_000, 0) - } - pub fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_606_000 picoseconds. - Weight::from_parts(2_717_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // 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: `70` - // Estimated: `3535` - // Minimum execution time: 26_242_000 picoseconds. - Weight::from_parts(29_220_000, 3535) - .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: `90` - // Estimated: `3555` - // Minimum execution time: 14_106_000 picoseconds. - Weight::from_parts(14_535_000, 3555) - .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_634_000 picoseconds. - Weight::from_parts(2_763_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: `38` - // Estimated: `3503` - // Minimum execution time: 27_802_000 picoseconds. - Weight::from_parts(28_495_000, 3503) - .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_683_000 picoseconds. - Weight::from_parts(4_907_000, 0) - .saturating_add(T::DbWeight::get().writes(1)) - } - pub fn burn_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_941_000 picoseconds. - Weight::from_parts(4_080_000, 0) - } - pub fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_775_000 picoseconds. - Weight::from_parts(2_908_000, 0) - } - pub fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_743_000 picoseconds. - Weight::from_parts(2_863_000, 0) - } - pub fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_641_000 picoseconds. - Weight::from_parts(2_771_000, 0) - } - pub fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_838_000 picoseconds. - Weight::from_parts(2_950_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: `70` - // Estimated: `3535` - // Minimum execution time: 29_284_000 picoseconds. - Weight::from_parts(29_867_000, 3535) - .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: 4_734_000 picoseconds. - Weight::from_parts(4_876_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: `70` - // Estimated: `3535` - // Minimum execution time: 26_154_000 picoseconds. - Weight::from_parts(26_851_000, 3535) - .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_678_000 picoseconds. - Weight::from_parts(2_748_000, 0) - } - pub fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_585_000 picoseconds. - Weight::from_parts(2_697_000, 0) - } - pub fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_576_000 picoseconds. - Weight::from_parts(2_701_000, 0) - } - pub fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_597_000 picoseconds. - Weight::from_parts(2_735_000, 0) - } - pub fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_744_000 picoseconds. - Weight::from_parts(2_809_000, 0) - } -} 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 deleted file mode 100644 index b3703eee830..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, - CENTS, -}; -use frame_support::{ - match_types, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - 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::WithOriginFilter, XcmExecutor}; - -parameter_types! { - pub const KsmRelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Kusama); - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; - pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); - pub const FellowshipLocation: MultiLocation = MultiLocation::parent(); -} - -/// 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, -); - -/// 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, - // 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): - AccountId, - // We don't track any teleports of `Balances`. - (), ->; - -/// 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 converts to a `Relay` origin when - // recognized. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognized. - 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, -); - -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(_) } - }; -} -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - 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::MessageQueue(..) - ) - } -} - -pub type Barrier = TrailingSetTopicAsId< - DenyThenTry< - DenyReserveTransferToRelayChain, - ( - // Allow local users to buy weight credit. - TakeWeightCredit, - // Expected responses are OK. - AllowKnownQueryResponses, - WithComputedOrigin< - ( - // If the message is one that immediately attempts to pay for execution, then - // allow it. - AllowTopLevelPaidExecutionFrom, - // Parent and its pluralities (i.e. governance bodies) get free execution. - AllowExplicitUnpaidExecutionFrom, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -/// 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; - type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - // BridgeHub does not recognize a reserve location for any asset. Users must teleport KSM - // where allowed (e.g. with the Relay Chain). - type IsReserve = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::BridgeHubKusamaXcmWeight, - RuntimeCall, - MaxInstructions, - >; - type Trader = - UsingComponents>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - 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; - -parameter_types! { - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(KsmRelayLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -pub type PriceForParentDelivery = - ExponentialPrice; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -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 are allowed. - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. - type Weigher = WeightInfoBounds< - crate::weights::xcm::BridgeHubKusamaXcmWeight, - 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; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs deleted file mode 100644 index 36d8f0846af..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -pub use bridge_hub_kusama_runtime::{ - xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, ExistentialDeposit, ParachainSystem, - PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, -}; -use codec::Decode; -use frame_support::parameter_types; -use parachains_common::{kusama::fee::WeightToFee, AccountId, AuraId}; - -const ALICE: [u8; 32] = [1u8; 32]; - -parameter_types! { - pub CheckingAccount: AccountId = PolkadotXcm::check_account(); -} - -bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - CheckingAccount, - WeightToFee, - ParachainSystem, - bridge_hub_test_utils::CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) } - ), - ExistentialDeposit::get(), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), - _ => None, - } - }), - 1002 -); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml deleted file mode 100644 index 3847a352e07..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,192 +0,0 @@ -[package] -name = "bridge-hub-polkadot-runtime" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -description = "Polkadot's BridgeHub parachain runtime" -license = "Apache-2.0" - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true, 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-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-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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-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} -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} - -# Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -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 } -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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } - -[dev-dependencies] -bridge-hub-test-utils = { path = "../test-utils" } - -[features] -default = [ "std" ] -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-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-session/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-utility/std", - "pallet-xcm-benchmarks?/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-core-primitives/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "scale-info/std", - "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", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] - -runtime-benchmarks = [ - "cumulus-pallet-dmp-queue/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-xcm-benchmarks/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-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-session/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", -] - -experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/build.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/build.rs deleted file mode 100644 index 60f8a125129..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/build.rs +++ /dev/null @@ -1,26 +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. - -#[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/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs deleted file mode 100644 index e5c4f00f28e..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,873 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -mod weights; -pub mod xcm_config; - -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; - -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -use frame_support::{ - construct_runtime, - dispatch::DispatchClass, - genesis_builder_helper::{build_config, create_default_config}, - parameter_types, - traits::{ - ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, - }, - weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{FellowshipLocation, GovernanceLocation, XcmOriginToTransactDispatchOrigin}; - -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; - -// Polkadot imports -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; - -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -use parachains_common::{ - impls::DealWithFees, - message_queue::{NarrowOriginToSibling, ParaIdToSibling}, - polkadot::{consensus::*, currency::*, fee::WeightToFee}, - AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, - HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, -}; -// XCM Imports -use xcm::latest::prelude::BodyId; - -/// The address format for describing accounts. -pub type Address = 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_transaction_payment::ChargeTransactionPayment, -); - -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; - -/// Migrations to apply on runtime upgrade. -pub type Migrations = ( - // unreleased - 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, ->; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("bridge-hub-polkadot"), - impl_name: create_runtime_str!("bridge-hub-polkadot"), - authoring_version: 1, - spec_version: 1_004_000, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 2, - state_version: 1, -}; - -/// 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 = 0; -} - -// Configure FRAME pallets to include in runtime. - -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The hashing algorithm used. - type Hashing = BlakeTwo256; - /// The block type. - type Block = Block; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// The basic call filter to use in dispatchable. - type BaseCallFilter = Everything; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = weights::frame_system::WeightInfo; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = 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 { - /// The type for recording an account's balance. - type Balance = Balance; - type DustRemoval = (); - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = weights::pallet_balances::WeightInfo; - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - 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 OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; -} - -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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = XcmpQueue; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl parachain_info::Config for Runtime {} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -parameter_types! { - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -/// Privileged origin that represents Root or Fellows. -pub type RootOrFellows = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, ->; - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = RootOrFellows; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - -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, ConstU32>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU32>; - 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, 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 = ConstU32; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = weights::pallet_collator_selection::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); -} - -impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = ConstU32<100>; - 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; -} - -// 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} = 2, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, - - // Monetary stuff. - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, - - // Collator support. The order of these 4 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, Event, Origin, Config} = 31, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, - - // Handy utilities. - Utility: pallet_utility::{Pallet, Call, Event} = 40, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, - } -); - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_session, SessionBench::] - [pallet_utility, Utility] - [pallet_timestamp, Timestamp] - [pallet_collator_selection, CollatorSelection] - [cumulus_pallet_parachain_system, ParachainSystem] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] - // XCM - [pallet_xcm, PalletXcmExtrinsicsBenchmark::] - // 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_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 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - - // 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::; - - 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - impl pallet_xcm::benchmarking::Config for Runtime { - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Relay/native token can be teleported between BH and Relay. - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }, - Parent.into(), - )) - } - - fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Reserve transfers are disabled on BH. - None - } - } - - use xcm::latest::prelude::*; - use xcm_config::DotRelayLocation; - - parameter_types! { - pub ExistentialDepositMultiAsset: Option = Some(( - xcm_config::DotRelayLocation::get(), - ExistentialDeposit::get() - ).into()); - } - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = xcm_config::XcmConfig; - type AccountIdConverter = xcm_config::LocationToAccountId; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositMultiAsset, - xcm_config::PriceForParentDelivery, - >; - fn valid_destination() -> Result { - Ok(DotRelayLocation::get()) - } - fn worst_case_holding(_depositable_count: u32) -> MultiAssets { - // just concrete assets according to relay chain. - let assets: Vec = vec![ - MultiAsset { - id: Concrete(DotRelayLocation::get()), - fun: Fungible(1_000_000 * UNITS), - } - ]; - assets.into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - DotRelayLocation::get(), - MultiAsset { fun: Fungible(UNITS), id: Concrete(DotRelayLocation::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(DotRelayLocation::get()), - fun: Fungible(UNITS), - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type TransactAsset = Balances; - 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> { - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((DotRelayLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(DotRelayLocation::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = DotRelayLocation::get(); - let assets: MultiAssets = (Concrete(DotRelayLocation::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::; - - 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(), - ]; - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - 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! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs deleted file mode 100644 index e7fdb2aae2a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +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. - -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/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index 4b0cface146..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// bridge-hub-polkadot-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(1_729_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 19_565 - .saturating_add(Weight::from_parts(24_482_828, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs deleted file mode 100644 index ac6ad093faf..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ /dev/null @@ -1,148 +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. - -//! Autogenerated weights for `cumulus_pallet_xcmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --pallet -// cumulus-pallet-xcmp-queue -// --chain -// bridge-hub-polkadot-dev -// --output -// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs -// --extrinsic -// - -#![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: 6_000_000 picoseconds. - Weight::from_parts(6_000_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:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn enqueue_xcmp_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `82` - // Estimated: `3517` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn suspend_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_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::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn resume_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `1596` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(5_000_000, 0) - .saturating_add(Weight::from_parts(0, 1596)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn take_first_concatenated_xcm() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65711` - // Estimated: `69176` - // Minimum execution time: 61_000_000 picoseconds. - Weight::from_parts(64_000_000, 0) - .saturating_add(Weight::from_parts(0, 69176)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65710` - // Estimated: `69175` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(44_000_000, 0) - .saturating_add(Weight::from_parts(0, 69175)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs deleted file mode 100644 index 1a4adb968bb..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,53 +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. - -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/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs deleted file mode 100644 index 8676be67b2f..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-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: 2_047_000 picoseconds. - Weight::from_parts(2_087_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(390, 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_335_000 picoseconds. - Weight::from_parts(7_507_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_751, 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_673_000 picoseconds. - Weight::from_parts(3_953_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: 98_791_992_000 picoseconds. - Weight::from_parts(101_799_041_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_144_000 picoseconds. - Weight::from_parts(2_206_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_254 - .saturating_add(Weight::from_parts(740_881, 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_117_000 picoseconds. - Weight::from_parts(2_192_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_024 - .saturating_add(Weight::from_parts(558_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: `68 + p * (69 ±0)` - // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 3_907_000 picoseconds. - Weight::from_parts(4_050_000, 0) - .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 2_228 - .saturating_add(Weight::from_parts(1_212_760, 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/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs deleted file mode 100644 index 36733d6d4a6..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/mod.rs +++ /dev/null @@ -1,41 +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 cumulus_pallet_dmp_queue; -pub mod cumulus_pallet_parachain_system; -pub mod cumulus_pallet_xcmp_queue; -pub mod extrinsic_weights; -pub mod frame_system; -pub mod pallet_balances; -pub mod pallet_collator_selection; -pub mod pallet_message_queue; -pub mod pallet_multisig; -pub mod pallet_session; -pub mod pallet_timestamp; -pub mod pallet_utility; -pub mod pallet_xcm; -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/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs deleted file mode 100644 index b95ea83585f..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs +++ /dev/null @@ -1,152 +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. - -//! Autogenerated weights for `pallet_balances` -//! -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --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/ - -#![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: 54_518_000 picoseconds. - Weight::from_parts(55_244_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: 40_152_000 picoseconds. - Weight::from_parts(41_084_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_234_000 picoseconds. - Weight::from_parts(15_576_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: 22_173_000 picoseconds. - Weight::from_parts(22_964_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: 56_636_000 picoseconds. - Weight::from_parts(57_316_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: 50_829_000 picoseconds. - Weight::from_parts(51_264_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: 17_887_000 picoseconds. - Weight::from_parts(18_365_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:999 w:999) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 16_754_000 picoseconds. - Weight::from_parts(17_237_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 15_088 - .saturating_add(Weight::from_parts(15_392_959, 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/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs deleted file mode 100644 index f7c78f7db82..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs +++ /dev/null @@ -1,248 +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. - -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-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_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: `196 + b * (79 ±0)` - // Estimated: `1187 + b * (2555 ±0)` - // Minimum execution time: 14_735_000 picoseconds. - Weight::from_parts(11_846_916, 0) - .saturating_add(Weight::from_parts(0, 1187)) - // Standard Error: 8_592 - .saturating_add(Weight::from_parts(3_270_517, 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: `757 + b * (32 ±0) + c * (53 ±0)` - // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` - // Minimum execution time: 48_332_000 picoseconds. - Weight::from_parts(46_158_586, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 13_938 - .saturating_add(Weight::from_parts(174_493, 0).saturating_mul(b.into())) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(196_691, 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: `82 + b * (32 ±0)` - // Estimated: `6287` - // Minimum execution time: 15_323_000 picoseconds. - Weight::from_parts(15_016_873, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_970 - .saturating_add(Weight::from_parts(199_160, 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_393_000 picoseconds. - Weight::from_parts(7_723_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(_c: u32, _k: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_426_000 picoseconds. - Weight::from_parts(7_783_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: `740 + c * (52 ±0)` - // Estimated: `6287 + c * (54 ±0)` - // Minimum execution time: 41_040_000 picoseconds. - Weight::from_parts(43_902_200, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_360 - .saturating_add(Weight::from_parts(211_897, 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 `[3, 100]`. - fn leave_intent(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `334 + c * (49 ±0)` - // Estimated: `6287` - // Minimum execution time: 33_429_000 picoseconds. - Weight::from_parts(36_413_045, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_947 - .saturating_add(Weight::from_parts(177_461, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - fn update_bond(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)) - } - fn take_candidate_slot(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: `155` - // Estimated: `6196` - // Minimum execution time: 45_300_000 picoseconds. - Weight::from_parts(46_280_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: `2263 + c * (97 ±0) + r * (115 ±0)` - // Estimated: `6287 + c * (2519 ±0) + r * (2603 ±0)` - // Minimum execution time: 17_524_000 picoseconds. - Weight::from_parts(17_590_000, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 354_091 - .saturating_add(Weight::from_parts(15_829_767, 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs deleted file mode 100644 index 38cc21cfad9..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// bridge-hub-polkadot-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/bridge-hubs/bridge-hub-polkadot/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 38_974_000 picoseconds. - Weight::from_parts(38_974_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 11_194_000 picoseconds. - Weight::from_parts(11_194_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 5_196_000 picoseconds. - Weight::from_parts(5_196_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_408_000 picoseconds. - Weight::from_parts(6_408_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_354_000 picoseconds. - Weight::from_parts(6_354_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 63_855_000 picoseconds. - Weight::from_parts(63_855_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 6_764_000 picoseconds. - Weight::from_parts(6_764_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 40_293_000 picoseconds. - Weight::from_parts(40_293_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 50_903_000 picoseconds. - Weight::from_parts(50_903_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 96_657_000 picoseconds. - Weight::from_parts(96_657_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs deleted file mode 100644 index 44f3da351f6..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,164 +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. - -//! Autogenerated weights for `pallet_multisig` -//! -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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_284_000 picoseconds. - Weight::from_parts(14_761_699, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(491, 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: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 44_043_000 picoseconds. - Weight::from_parts(32_303_705, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_280 - .saturating_add(Weight::from_parts(133_233, 0).saturating_mul(s.into())) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_467, 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: `282` - // Estimated: `6811` - // Minimum execution time: 28_494_000 picoseconds. - Weight::from_parts(19_053_318, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 791 - .saturating_add(Weight::from_parts(112_935, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_427, 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: `388 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 49_505_000 picoseconds. - Weight::from_parts(36_407_515, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_595 - .saturating_add(Weight::from_parts(166_201, 0).saturating_mul(s.into())) - // Standard Error: 15 - .saturating_add(Weight::from_parts(1_481, 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: `263 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 30_977_000 picoseconds. - Weight::from_parts(32_222_158, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_872 - .saturating_add(Weight::from_parts(125_197, 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: `282` - // Estimated: `6811` - // Minimum execution time: 17_351_000 picoseconds. - Weight::from_parts(18_130_793, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 902 - .saturating_add(Weight::from_parts(109_485, 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: `454 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 31_554_000 picoseconds. - Weight::from_parts(33_116_785, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 882 - .saturating_add(Weight::from_parts(119_357, 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/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs deleted file mode 100644 index 86ecc787e97..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs +++ /dev/null @@ -1,80 +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. - -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-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: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:1 w:1) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `297` - // Estimated: `3762` - // Minimum execution time: 16_905_000 picoseconds. - Weight::from_parts(17_310_000, 0) - .saturating_add(Weight::from_parts(0, 3762)) - .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: `279` - // Estimated: `3744` - // Minimum execution time: 12_511_000 picoseconds. - Weight::from_parts(13_055_000, 0) - .saturating_add(Weight::from_parts(0, 3744)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs deleted file mode 100644 index a0984d72aac..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,74 +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. - -//! Autogenerated weights for `pallet_timestamp` -//! -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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_timestamp`. -pub struct WeightInfo(PhantomData); -impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Aura::CurrentSlot` (r:1 w:0) - /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set() -> Weight { - // Proof Size summary in bytes: - // Measured: `49` - // Estimated: `1493` - // Minimum execution time: 7_675_000 picoseconds. - Weight::from_parts(7_947_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: `57` - // Estimated: `0` - // Minimum execution time: 3_342_000 picoseconds. - Weight::from_parts(3_443_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs deleted file mode 100644 index 2f04094b347..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs +++ /dev/null @@ -1,101 +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. - -//! Autogenerated weights for `pallet_utility` -//! -//! 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("bridge-hub-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=bridge-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-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_810_000 picoseconds. - Weight::from_parts(6_290_871, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_678 - .saturating_add(Weight::from_parts(5_193_419, 0).saturating_mul(c.into())) - } - fn as_derivative() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_753_000 picoseconds. - Weight::from_parts(4_890_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_873_000 picoseconds. - Weight::from_parts(9_780_422, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_035 - .saturating_add(Weight::from_parts(5_473_943, 0).saturating_mul(c.into())) - } - fn dispatch_as() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_443_000 picoseconds. - Weight::from_parts(8_904_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_820_000 picoseconds. - Weight::from_parts(8_206_355, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_327 - .saturating_add(Weight::from_parts(5_187_839, 0).saturating_mul(c.into())) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs deleted file mode 100644 index b73c009cbda..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-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 -// 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 -// --chain=bridge-hub-polkadot-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 22_442_000 picoseconds. - Weight::from_parts(23_346_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 19_655_000 picoseconds. - Weight::from_parts(20_086_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 reserve_transfer_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn 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: 6_858_000 picoseconds. - Weight::from_parts(7_225_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_099_000 picoseconds. - Weight::from_parts(2_190_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::Queries` (r:0 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn force_subscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 27_073_000 picoseconds. - Weight::from_parts(27_584_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `255` - // Estimated: `3720` - // Minimum execution time: 29_949_000 picoseconds. - Weight::from_parts(30_760_000, 0) - .saturating_add(Weight::from_parts(0, 3720)) - .saturating_add(T::DbWeight::get().reads(7)) - .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_192_000 picoseconds. - Weight::from_parts(2_276_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: `95` - // Estimated: `10985` - // Minimum execution time: 14_681_000 picoseconds. - Weight::from_parts(15_131_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .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: `99` - // Estimated: `10989` - // Minimum execution time: 14_523_000 picoseconds. - Weight::from_parts(15_113_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .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: `106` - // Estimated: `13471` - // Minimum execution time: 15_989_000 picoseconds. - Weight::from_parts(16_518_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `6046` - // Minimum execution time: 25_127_000 picoseconds. - Weight::from_parts(25_773_000, 0) - .saturating_add(Weight::from_parts(0, 6046)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) - /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn notify_target_migration_fail() -> Weight { - // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_352_000 picoseconds. - Weight::from_parts(8_592_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .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: `106` - // Estimated: `10996` - // Minimum execution time: 14_658_000 picoseconds. - Weight::from_parts(15_345_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 31_478_000 picoseconds. - Weight::from_parts(32_669_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) - /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1517` - // Minimum execution time: 4_066_000 picoseconds. - Weight::from_parts(4_267_000, 0) - .saturating_add(Weight::from_parts(0, 1517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `PolkadotXcm::Queries` (r:1 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn take_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `7669` - // Estimated: `11134` - // Minimum execution time: 25_260_000 picoseconds. - Weight::from_parts(25_570_000, 0) - .saturating_add(Weight::from_parts(0, 11134)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/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 deleted file mode 100644 index 33a48f36812..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs +++ /dev/null @@ -1,244 +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. - -mod pallet_xcm_benchmarks_fungible; -mod pallet_xcm_benchmarks_generic; - -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}; - -trait WeighMultiAssets { - fn weigh_multi_assets(&self, weight: Weight) -> Weight; -} - -const MAX_ASSETS: u64 = 100; - -impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, weight: Weight) -> Weight { - match self { - 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, weight: Weight) -> Weight { - weight.saturating_mul(self.inner().iter().count() as u64) - } -} - -pub struct BridgeHubPolkadotXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for BridgeHubPolkadotXcmWeight { - fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) - } - 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()) - } - 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(XcmFungibleWeight::::transfer_asset()) - } - fn transfer_reserve_asset( - assets: &MultiAssets, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) - } - fn transact( - _origin_type: &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(XcmFungibleWeight::::deposit_asset()) - } - fn deposit_reserve_asset( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) - } - fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - Weight::MAX - } - fn initiate_reserve_withdraw( - assets: &MultiAssetFilter, - _reserve: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) - } - fn initiate_teleport( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmFungibleWeight::::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 { - Weight::MAX - } - fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - Weight::MAX - } - fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - Weight::MAX - } - fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - 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() - } -} 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 deleted file mode 100644 index 814c416bd4c..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,187 +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. - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! 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 -// 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_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)] -#![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: 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)) - } - // 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: `153` - // Estimated: `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)) - } - // 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: `223` - // Estimated: `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)) - } - // 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: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `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: `70` - // Estimated: `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)) - } - pub fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `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`) - pub fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `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)) - } - // 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: `122` - // Estimated: `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)) - } - // 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: `70` - // Estimated: `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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index 9a039a6d63b..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,328 +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. - -//! 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("bridge-hub-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-polkadot/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: `70` - // Estimated: `3535` - // Minimum execution time: 30_923_000 picoseconds. - Weight::from_parts(31_653_000, 3535) - .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: 2_837_000 picoseconds. - Weight::from_parts(2_932_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: `32` - // Estimated: `3497` - // Minimum execution time: 10_319_000 picoseconds. - Weight::from_parts(10_614_000, 3497) - .saturating_add(T::DbWeight::get().reads(1)) - } - pub fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_466_000 picoseconds. - Weight::from_parts(12_005_000, 0) - } - pub fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_039_000 picoseconds. - Weight::from_parts(3_125_000, 0) - } - pub fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_655_000 picoseconds. - Weight::from_parts(2_717_000, 0) - } - pub fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_655_000 picoseconds. - Weight::from_parts(2_695_000, 0) - } - pub fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_612_000 picoseconds. - Weight::from_parts(2_685_000, 0) - } - pub fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_286_000 picoseconds. - Weight::from_parts(3_425_000, 0) - } - pub fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_613_000 picoseconds. - Weight::from_parts(2_699_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: `70` - // Estimated: `3535` - // Minimum execution time: 24_616_000 picoseconds. - Weight::from_parts(25_147_000, 3535) - .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: `90` - // Estimated: `3555` - // Minimum execution time: 14_511_000 picoseconds. - Weight::from_parts(14_831_000, 3555) - .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_640_000 picoseconds. - Weight::from_parts(2_702_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: `38` - // Estimated: `3503` - // Minimum execution time: 26_044_000 picoseconds. - Weight::from_parts(26_561_000, 3503) - .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_568_000 picoseconds. - Weight::from_parts(4_764_000, 0) - .saturating_add(T::DbWeight::get().writes(1)) - } - pub fn burn_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_953_000 picoseconds. - Weight::from_parts(4_079_000, 0) - } - pub fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_793_000 picoseconds. - Weight::from_parts(2_914_000, 0) - } - pub fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_719_000 picoseconds. - Weight::from_parts(2_829_000, 0) - } - pub fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_710_000 picoseconds. - Weight::from_parts(2_824_000, 0) - } - pub fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_941_000 picoseconds. - Weight::from_parts(3_201_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: `70` - // Estimated: `3535` - // Minimum execution time: 28_080_000 picoseconds. - Weight::from_parts(28_920_000, 3535) - .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: 4_752_000 picoseconds. - Weight::from_parts(4_982_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: `70` - // Estimated: `3535` - // Minimum execution time: 24_810_000 picoseconds. - Weight::from_parts(25_270_000, 3535) - .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_676_000 picoseconds. - Weight::from_parts(2_780_000, 0) - } - pub fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_624_000 picoseconds. - Weight::from_parts(2_710_000, 0) - } - pub fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_611_000 picoseconds. - Weight::from_parts(2_707_000, 0) - } - pub fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_653_000 picoseconds. - Weight::from_parts(2_740_000, 0) - } - pub fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_821_000 picoseconds. - Weight::from_parts(2_874_000, 0) - } -} 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 deleted file mode 100644 index 61eee1c4c5a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, - CENTS, -}; -use frame_support::{ - match_types, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - 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::WithOriginFilter, XcmExecutor}; - -parameter_types! { - pub const DotRelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Polkadot); - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; - pub FellowshipLocation: MultiLocation = MultiLocation::new(1, Parachain(1001)); - pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); -} - -/// 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, -); - -/// 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, - // 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): - AccountId, - // We don't track any teleports of `Balances`. - (), ->; - -/// 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 converts to a `Relay` origin when - // recognized. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognized. - 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, -); - -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 FellowsPlurality: impl Contains = { - MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) } - }; -} -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - 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::MessageQueue(..) - ) - } -} - -pub type Barrier = TrailingSetTopicAsId< - DenyThenTry< - DenyReserveTransferToRelayChain, - ( - // Allow local users to buy weight credit. - TakeWeightCredit, - // Expected responses are OK. - AllowKnownQueryResponses, - 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 the Fellows plurality - // get free execution. - AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, FellowsPlurality)>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -/// 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; - type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - // BridgeHub does not recognize a reserve location for any asset. Users must teleport DOT - // where allowed (e.g. with the Relay Chain). - type IsReserve = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::BridgeHubPolkadotXcmWeight, - RuntimeCall, - MaxInstructions, - >; - type Trader = - UsingComponents>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - 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; - -parameter_types! { - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(DotRelayLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -pub type PriceForParentDelivery = - ExponentialPrice; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -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 are allowed. - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. - type Weigher = WeightInfoBounds< - crate::weights::xcm::BridgeHubPolkadotXcmWeight, - 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; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs deleted file mode 100644 index 3156a5fe68e..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -pub use bridge_hub_polkadot_runtime::{ - xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances, ExistentialDeposit, ParachainSystem, - PolkadotXcm, Runtime, RuntimeEvent, SessionKeys, -}; -use codec::Decode; -use frame_support::parameter_types; -use parachains_common::{polkadot::fee::WeightToFee, AccountId, AuraId}; - -const ALICE: [u8; 32] = [1u8; 32]; - -parameter_types! { - pub CheckingAccount: AccountId = PolkadotXcm::check_account(); -} - -bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - CheckingAccount, - WeightToFee, - ParachainSystem, - bridge_hub_test_utils::CollatorSessionKeys::new( - AccountId::from(ALICE), - AccountId::from(ALICE), - SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) } - ), - ExistentialDeposit::get(), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), - _ => None, - } - }), - 1002 -); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml deleted file mode 100644 index ca83b84cd8f..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ /dev/null @@ -1,226 +0,0 @@ -[package] -name = "collectives-polkadot-runtime" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -description = "Polkadot Collectives Parachain Runtime" -license = "Apache-2.0" - -[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.10.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-alliance = { path = "../../../../../substrate/frame/alliance", 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-collective = { path = "../../../../../substrate/frame/collective", default-features = false} -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} -pallet-preimage = { path = "../../../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false} -pallet-scheduler = { path = "../../../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-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-utility = { path = "../../../../../substrate/frame/utility", default-features = false} -pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false} -pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false} -pallet-core-fellowship = { path = "../../../../../substrate/frame/core-fellowship", default-features = false} -pallet-salary = { path = "../../../../../substrate/frame/salary", default-features = false} -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", 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} -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} - -# Polkadot -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} -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 } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } -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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } - -[dev-dependencies] -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} - -[features] -default = [ "std" ] -runtime-benchmarks = [ - "cumulus-pallet-dmp-queue/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "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-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-ranked-collective/runtime-benchmarks", - "pallet-referenda/runtime-benchmarks", - "pallet-salary/runtime-benchmarks", - "pallet-scheduler/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-utility/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-alliance/try-runtime", - "pallet-aura/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-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-preimage/try-runtime", - "pallet-proxy/try-runtime", - "pallet-ranked-collective/try-runtime", - "pallet-referenda/try-runtime", - "pallet-salary/try-runtime", - "pallet-scheduler/try-runtime", - "pallet-session/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", -] -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-alliance/std", - "pallet-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-collective-content/std", - "pallet-collective/std", - "pallet-core-fellowship/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-preimage/std", - "pallet-proxy/std", - "pallet-ranked-collective/std", - "pallet-referenda/std", - "pallet-salary/std", - "pallet-scheduler/std", - "pallet-session/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-utility/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-core-primitives/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "scale-info/std", - "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", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] - -experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/build.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/build.rs deleted file mode 100644 index 60f8a125129..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/build.rs +++ /dev/null @@ -1,26 +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. - -#[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/collectives/collectives-polkadot/src/ambassador/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs deleted file mode 100644 index b055ffc8abf..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs +++ /dev/null @@ -1,255 +0,0 @@ -// 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 deleted file mode 100644 index 3ce8a6b9e5d..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs +++ /dev/null @@ -1,135 +0,0 @@ -// 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 deleted file mode 100644 index 073d8e6ee36..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs +++ /dev/null @@ -1,282 +0,0 @@ -// 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/migration.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs deleted file mode 100644 index 9350d03a2c9..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Migrations. - -use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight}; -use log; - -/// Initial import of the Kusama Technical Fellowship. -pub(crate) mod import_kusama_fellowship { - use super::*; - use frame_support::{parameter_types, traits::RankedMembers}; - use pallet_ranked_collective::{Config, MemberCount, Pallet as RankedCollective, Rank}; - #[cfg(feature = "try-runtime")] - use sp_std::vec::Vec; - - const TARGET: &str = "runtime::migration::import_fellowship"; - - parameter_types! { - // The Fellowship addresses from Kusama state. - pub const FellowshipAddresses: [(Rank, [u8; 32]); 47] = [ - (6, hex_literal::hex!("f0673d30606ee26672707e4fd2bc8b58d3becb7aba2d5f60add64abb5fea4710"),), - (6, hex_literal::hex!("3c235e80e35082b668682531b9b062fda39a46edb94f884d9122d86885fd5f1b"),), - (6, hex_literal::hex!("7628a5be63c4d3c8dbb96c2904b1a9682e02831a1af836c7efc808020b92fa63"),), - (5, hex_literal::hex!("9c84f75e0b1b92f6b003bde6212a8b2c9b776f3720f942b33fed8709f103a268"),), - (5, hex_literal::hex!("bc64065524532ed9e805fb0d39a5c0199216b52871168e5e4d0ab612f8797d61"),), - (5, hex_literal::hex!("2e1884c53071526483b14004e894415f02b55fc2e2aef8e1df8ccf7ce5bd5570"),), - (5, hex_literal::hex!("5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f28"),), - (4, hex_literal::hex!("4adf51a47b72795366d52285e329229c836ea7bbfe139dbe8fa0700c4f86fc56"),), - (4, hex_literal::hex!("1c90e3dabd3fd0f6bc648045018f78fcee8fe24122c22d8d2a14e9905073d10f"),), - (4, hex_literal::hex!("8e851ed992228f2268ee8c614fe6075d3800060ae14098e0309413a0a81c4470"),), - (3, hex_literal::hex!("720d807d46b941703ffe0278e8b173dc6738c5af8af812ceffc90c69390bbf1f"),), - (3, hex_literal::hex!("c4965f7fe7be8174717a24ffddf684986d122c7e293ddf875cdf9700a07b6812"),), - (3, hex_literal::hex!("beae5bcad1a8c156291b7ddf46b38b0c61a6aaacebd57b21c75627bfe7f9ab71"),), - (3, hex_literal::hex!("ccd87fa65729f7bdaa8305581a7a499aa24c118e83f5714152c0e22617c6fc63"),), - (3, hex_literal::hex!("e0f0f94962fc0a8c1a0f0527dc8e592c67939c46c903b6016cc0a8515da0044d"),), - (3, hex_literal::hex!("984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b5413"),), - (3, hex_literal::hex!("44a3efb5bfa9023d4ef27b7d31d76f531b4d7772b1679b7fb32b6263ac39100e"),), - (2, hex_literal::hex!("2eba9a39dbfdd5f3cba964355d45e27319f0271023c0353d97dc6df2401b0e3d"),), - (2, hex_literal::hex!("ba3e9b87792bcfcc237fa8181185b8883c77f3e24f45e4a92ab31d07a4703520"),), - (2, hex_literal::hex!("9e6eb74b0a6b39de36fb58d1fab20bc2b3fea96023ce5a47941c20480d99f92e"),), - (2, hex_literal::hex!("ee3d9d8c48ee88dce78fd7bafe3ce2052900eb465085b9324d4f5da26b145f2b"),), - (2, hex_literal::hex!("d8290537d6e31fe1ff165eaa62b63f6f3556dcc720b0d3a6d7eab96275617304"),), - (2, hex_literal::hex!("5a090c88f0438b46b451026597cee760a7bac9d396c9c7b529b68fb78aec5f43"),), - (2, hex_literal::hex!("18d30040a8245c5ff17afc9a8169d7d0771fe7ab4135a64a022c254117340720"),), - (1, hex_literal::hex!("b4f7f03bebc56ebe96bc52ea5ed3159d45a0ce3a8d7f082983c33ef133274747"),), - (1, hex_literal::hex!("caafae0aaa6333fcf4dc193146945fe8e4da74aa6c16d481eef0ca35b8279d73"),), - (1, hex_literal::hex!("a66e0f4e1a121cc83fddf3096e8ec8c9e9c85989f276e39e951fb0e4a5398763"),), - (1, hex_literal::hex!("f65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c79505073"),), - (1, hex_literal::hex!("8c232c91ef2a9983ba65c4b75bb86fcbae4d909900ea8aa06c3644ca1161db48"),), - (1, hex_literal::hex!("78e4813814891bd48bc745b79254a978833d41fbe0f387df93cd87eae2468926"),), - (1, hex_literal::hex!("d44824ac8d1edecca67639ca74d208bd2044a10e67c9677e288080191e3fec13"),), - (1, hex_literal::hex!("585e982d74da4f4290d20a73800cfd705cf59e1f5880aaee5506b5eaaf544f49"),), - (1, hex_literal::hex!("d851f44a6f0d0d2f3439a51f2f75f66f4ea1a8e6c33c32f9af75fc188afb7546"),), - (1, hex_literal::hex!("dca89b135d1a6aee0a498610a70eeaed056727c8a4d220da245842e540a54a74"),), - (1, hex_literal::hex!("aa91fc0201f26b713a018669bcd269babf25368eee2493323b1ce0190a178a27"),), - (1, hex_literal::hex!("dc20836f2e4b88c1858d1e3f918e7358043b4a8abcd2874e74d91d26c52eca2a"),), - (1, hex_literal::hex!("145d6c503d0cf97f4c7725ca773741bd02e1760bfb52e021af5a9f2de283012c"),), - (1, hex_literal::hex!("307183930b2264c5165f4a210a99520c5f1672b0413d57769fabc19e6866fb25"),), - (1, hex_literal::hex!("6201961514cf5ad87f1c4dd0c392ee28231f805f77975147bf2c33bd671b9822"),), - (1, hex_literal::hex!("c6f57237cd4abfbeed99171495fc784e45a9d5d2814d435de40de00991a73c06"),), - (1, hex_literal::hex!("c1df5c7e8ca56037450c58734326ebe34aec8f7d1928322a12164856365fea73"),), - (1, hex_literal::hex!("12c039004da5e1e846aae808277098c719cef1f4985aed00161a42ac4f0e002f"),), - (1, hex_literal::hex!("7460ac178015d2a7c289bb68ef9fdaac071596ab4425c276a0040aaac7055566"),), - (1, hex_literal::hex!("eec4bd650a277342ebba0954ac786df2623bd6a9d6d3e69b484482336c549f79"),), - (1, hex_literal::hex!("e287c7494655d636a846f5c3347ad2cb3c462a8d46e0832be70fcc0ab54ee62d"),), - (1, hex_literal::hex!("82bf733f44a840f0a5c1935a002d4e541d81298fad6d1da8124073485983860e"),), - (1, hex_literal::hex!("d5b89078eed9b9dfec5c7d8413bac0b720bad3bd4078c4d8c894325713192502"),), - ]; - } - - /// Implements `OnRuntimeUpgrade` trait. - pub struct Migration(PhantomData<(T, I)>); - - impl, I: 'static> OnRuntimeUpgrade for Migration - where - ::AccountId: From<[u8; 32]>, - { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - let onchain_version = RankedCollective::::on_chain_storage_version(); - ensure!(onchain_version == 0, "the storage version must be 0."); - let member_count = MemberCount::::get(0); - ensure!(member_count == 0, "the collective must be uninitialized."); - - Ok(Vec::new()) - } - - fn on_runtime_upgrade() -> Weight { - let current_version = RankedCollective::::current_storage_version(); - let onchain_version = RankedCollective::::on_chain_storage_version(); - let mut weight = T::DbWeight::get().reads(1); - log::info!( - target: TARGET, - "running migration with current storage version {:?} / onchain {:?}.", - current_version, - onchain_version - ); - if onchain_version != 0 { - log::warn!( - target: TARGET, - "unsupported storage version, skipping import_fellowship migration." - ); - return weight - } - let member_count = MemberCount::::get(0); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if member_count != 0 { - log::warn!( - target: TARGET, - "the collective already initialized, skipping import_fellowship migration." - ); - return weight - } - - for (rank, account_id32) in FellowshipAddresses::get() { - let who: T::AccountId = account_id32.into(); - let _ = as RankedMembers>::induct(&who); - for _ in 0..rank { - let _ = as RankedMembers>::promote(&who); - // 1 write to `IdToIndex` and `IndexToId` per member on each rank. - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - // 1 write to `IdToIndex` and `IndexToId` per member on each rank. - weight.saturating_accrue(T::DbWeight::get().writes(2)); - // 1 read and 1 write to `Members` and `MemberCount` per member. - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - weight - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - ensure!(MemberCount::::get(0) == 47, "invalid members count at rank 0."); - ensure!(MemberCount::::get(1) == 47, "invalid members count at rank 1."); - ensure!(MemberCount::::get(2) == 24, "invalid members count at rank 2."); - ensure!(MemberCount::::get(3) == 17, "invalid members count at rank 3."); - ensure!(MemberCount::::get(4) == 10, "invalid members count at rank 4."); - ensure!(MemberCount::::get(5) == 7, "invalid members count at rank 5."); - ensure!(MemberCount::::get(6) == 3, "invalid members count at rank 6."); - ensure!(MemberCount::::get(7) == 0, "invalid members count at rank 7."); - Ok(()) - } - } -} - -#[cfg(test)] -pub mod tests { - use super::import_kusama_fellowship::FellowshipAddresses; - use crate::{FellowshipCollectiveInstance as Fellowship, Runtime, System}; - use frame_support::traits::OnRuntimeUpgrade; - use pallet_ranked_collective::Rank; - use parachains_common::AccountId; - use sp_core::crypto::Ss58Codec; - use sp_runtime::{AccountId32, BuildStorage}; - - #[test] - fn check_fellowship_addresses() { - let fellowship_addresses = FellowshipAddresses::get(); - let kusama_fellowship_ss58: [(Rank, _); 47] = [ - (6, "16SDAKg9N6kKAbhgDyxBXdHEwpwHUHs2CNEiLNGeZV55qHna"), /* proof https://kusama.subscan.io/extrinsic/16832707-4 */ - (6, "12MrP337azmkTdfCUKe5XLnSQrbgEKqqfZ4PQC7CZTJKAWR3"), /* proof https://kusama.subscan.io/extrinsic/16967809-2 */ - (6, "FFFF3gBSSDFSvK2HBq4qgLH75DHqXWPHeCnR1BSksAMacBs"), - (5, "G7YVCdxZb8JLpAm9WMnJdNuojNT84AzU62zmvx5P1FMNtg2"), - (5, "15G1iXDLgFyfnJ51FKq1ts44TduMyUtekvzQi9my4hgYt2hs"), /* proof https://kusama.subscan.io/extrinsic/16917610-2 */ - (5, "Dcm1BqR4N7nHuV43TXdET7pNibt1Nzm42FggPHpxKRven53"), - (5, "1363HWTPzDrzAQ6ChFiMU6mP4b6jmQid2ae55JQcKtZnpLGv"), /* proof https://kusama.subscan.io/extrinsic/16961180-2 */ - (4, "EGVQCe73TpFyAZx5uKfE1222XfkT3BSKozjgcqzLBnc5eYo"), - (4, "1eTPAR2TuqLyidmPT9rMmuycHVm9s9czu78sePqg2KHMDrE"), /* proof https://kusama.subscan.io/extrinsic/16921712-3 */ - (4, "14DsLzVyTUTDMm2eP3czwPbH53KgqnQRp3CJJZS9GR7yxGDP"), /* proof https://kusama.subscan.io/extrinsic/16917519-2 */ - (3, "13aYUFHB3umoPoxBEAHSv451iR3RpsNi3t5yBZjX2trCtTp6"), /* proof https://kusama.subscan.io/extrinsic/16917832-3 */ - (3, "H25aCspunTUqAt4D1gC776vKZ8FX3MvQJ3Jde6qDXPQaFxk"), - (3, "GtLQoW4ZqcjExMPq6qB22bYc6NaX1yMzRuGWpSRiHqnzRb9"), - (3, "15db5ksZgmhWE9U8MDq4wLKUdFivLVBybztWV8nmaJvv3NU1"), /* proof https://kusama.subscan.io/extrinsic/16876631-2 */ - (3, "HfFpz4QUxfbocHudf8UU7cMgHqkHpf855Me5X846PZAsAYE"), - (3, "14ShUZUYUR35RBZW6uVVt1zXDxmSQddkeDdXf1JkMA6P721N"), /* proof https://kusama.subscan.io/extrinsic/16918890-8 */ - (3, "12YzxR5TvGzfMVZNnhAJ5Hwi5zExpRWMKv2MuMwZTrddvgoi"), /* proof https://kusama.subscan.io/extrinsic/16924324-3 */ - (2, "Ddb9puChKMHq4gM6o47E551wAmaNeu6kHngX1jzNNqAw782"), - (2, "15DCWHQknBjc5YPFoVj8Pn2KoqrqYywJJ95BYNYJ4Fj3NLqz"), /* proof https://kusama.subscan.io/extrinsic/16834952-2 */ - (2, "14ajTQdrtCA8wZmC4PgD8Y1B2Gy8L4Z3oi2fodxq9FehcFrM"), /* proof https://kusama.subscan.io/extrinsic/16944257-2 */ - (2, "HxhDbS3grLurk1dhDgPiuDaRowHY1xHCU8Vu8on3fdg85tx"), - (2, "HTk3eccL7WBkiyxz1gBcqQRghsJigoDMD7mnQaz1UAbMpQV"), - (2, "EcNWrSPSDcVBRymwr26kk4JVFg92PdoU5Xwp87W2FgFSt9c"), - (2, "D8sM6vKjWaeKy2zCPYWGkLLbWdUtWQrXBTQqr4dSYnVQo21"), - (1, "GfbnnEgRU94n9ed4RFZ6Z9dBAWs5obykigJSwXKU9hsT2uU"), - (1, "HA5NtttvyZsxo4wGxGoJJSMaWtdEFZAuGUMFHVWD7fgenPv"), - (1, "14mDeKZ7qp9hqBjjDg51c8BFrf9o69om8piSSRwj2fT5Yb1i"), /* proof https://kusama.subscan.io/extrinsic/16919020-4 */ - (1, "16a357f5Sxab3V2ne4emGQvqJaCLeYpTMx3TCjnQhmJQ71DX"), /* proof https://kusama.subscan.io/extrinsic/16836396-5 */ - (1, "14Ak9rrF6RKHHoLLRUYMnzcvvi1t8E1yAMa7tcmiwUfaqzYK"), /* proof https://kusama.subscan.io/extrinsic/16921990-3 */ - (1, "FJq9JpA9P7EXbmfsN9YiewJaDbQyL6vQyksGtJvzfbn6zf8"), - (1, "15oLanodWWweiZJSoDTEBtrX7oGfq6e8ct5y5E6fVRDPhUgj"), /* proof https://kusama.subscan.io/extrinsic/16876423-7 */ - (1, "EaBqDJJNsZmYdQ4xn1vomPJVNh7fjA6UztZeEjn7ZzdeT7V"), - (1, "HTxCvXKVvUZ7PQq175kCRRLu7XkGfTfErrdNXr1ZuuwVZWv"), - (1, "HZe91A6a1xqbKaw6ofx3GFepJjhVXHrwHEwn6YUDDFphpX9"), - (1, "GRy2P3kBEzSHCbmDJfquku1cyUyhZaAqojRcNE4A4U3MnLd"), - (1, "HYwiBo7Mcv7uUDg4MUoKm2fxzv4dMLAtmmNfzHV8qcQJpAE"), - (1, "1ThiBx5DDxFhoD9GY6tz5Fp4Y7Xn1xfLmDddcoFQghDvvjg"), /* proof https://kusama.subscan.io/extrinsic/16918130-2 */ - (1, "DfqY6XQUSETTszBQ1juocTcG9iiDoXhvq1CoVadBSUqTGJS"), - (1, "EnpgVWGGQVrFdSB2qeXRVdtccV6U5ZscNELBoERbkFD8Wi6"), - (1, "H5BuqCmucJhUUuvjAzPazeVwVCtUSXVQdc5Dnx2q5zD7rVn"), - (1, "GxX7S1pTDdeaGUjpEPPF2we6tgHDhbatFG25pVmVFtGHLH6"), - (1, "CzuUtvKhZNZBjyAXeYviaRXwrLhVrsupJ9PrWmdq7BJTjGR"), - (1, "FCunn2Rx8JqfT5g6noUKKazph4jLDba5rUee7o3ZmJ362Ju"), - (1, "HyPMjWRHCpJS7x2SZ2R6M2XG5ZiCiZag4U4r7gBHRsE5mTc"), - (1, "1682A5hxfiS1Kn1jrUnMYv14T9EuEnsgnBbujGfYbeEbSK3w"), /* proof https://kusama.subscan.io/extrinsic/16919077-2 */ - (1, "13xS6fK6MHjApLnjdX7TJYw1niZmiXasSN91bNtiXQjgEtNx"), /* proof https://kusama.subscan.io/extrinsic/16918212-7 */ - (1, "15qE2YAQCs5Y962RHE7RzNjQxU6Pei21nhkkSM9Sojq1hHps"), /* https://kusama.subscan.io/extrinsic/17352973-2 */ - ]; - - for (index, val) in kusama_fellowship_ss58.iter().enumerate() { - let account: AccountId32 = ::from_string(val.1).unwrap(); - let account32: [u8; 32] = account.clone().into(); - assert_eq!( - fellowship_addresses[index].0, kusama_fellowship_ss58[index].0, - "ranks must be equal." - ); - assert_eq!(fellowship_addresses[index].1, account32, "accounts must be equal."); - } - } - - #[test] - fn test_fellowship_import() { - use super::import_kusama_fellowship::Migration; - use pallet_ranked_collective::{IdToIndex, IndexToId, MemberCount, MemberRecord, Members}; - - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext.execute_with(|| { - assert_eq!(MemberCount::::get(0), 0); - Migration::::on_runtime_upgrade(); - assert_eq!(MemberCount::::get(0), 47); - assert_eq!(MemberCount::::get(6), 3); - assert_eq!(MemberCount::::get(7), 0); - for (rank, account_id32) in FellowshipAddresses::get() { - let who = ::AccountId::from(account_id32); - assert!(IdToIndex::::get(0, &who).is_some()); - assert!(IdToIndex::::get(rank + 1, &who).is_none()); - let index = IdToIndex::::get(rank, &who).unwrap(); - assert_eq!(IndexToId::::get(rank, index).unwrap(), who); - assert_eq!( - Members::::get(&who).unwrap(), - MemberRecord::new(rank) - ); - } - }); - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs deleted file mode 100644 index 2a2757ea5ce..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! The Polkadot Technical Fellowship. - -pub(crate) mod migration; -mod origins; -mod tracks; -use crate::{ - impls::ToParentTreasury, - weights, - xcm_config::{FellowshipAdminBodyId, UsdtAssetHub}, - AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, PolkadotTreasuryAccount, - Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, DAYS, -}; -use frame_support::{ - parameter_types, - traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg}, -}; -use frame_system::EnsureRootWithSuccess; -pub use origins::{ - pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt, - EnsureFellowship, Fellows, Masters, Members, ToVoice, -}; -use pallet_ranked_collective::EnsureOfRank; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::{polkadot::account, HOURS}; -use sp_core::{ConstU128, ConstU32}; -use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; -use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; - -#[cfg(feature = "runtime-benchmarks")] -use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure}; - -/// The Fellowship members' ranks. -pub mod ranks { - use pallet_ranked_collective::Rank; - - pub const DAN_1: Rank = 1; // aka Members. - pub const DAN_2: Rank = 2; - pub const DAN_3: Rank = 3; // aka Fellows. - pub const DAN_4: Rank = 4; // aka Architects. - pub const DAN_5: Rank = 5; - pub const DAN_6: Rank = 6; - pub const DAN_7: Rank = 7; // aka Masters. - pub const DAN_8: Rank = 8; - pub const DAN_9: Rank = 9; -} - -parameter_types! { - // Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting. - pub ReferendaPalletAccount: AccountId = account::REFERENDA_PALLET_ID.into_account_truncating(); -} - -impl pallet_fellowship_origins::Config for Runtime {} - -pub type FellowshipReferendaInstance = pallet_referenda::Instance1; - -impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda_fellowship_referenda::WeightInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type Scheduler = Scheduler; - type Currency = Balances; - // Fellows can submit proposals. - type SubmitOrigin = EitherOf< - pallet_ranked_collective::EnsureMember, - MapSuccess< - TryWithMorphedArg< - RuntimeOrigin, - ::PalletsOrigin, - ToVoice, - EnsureOfRank, - (AccountId, u16), - >, - TakeFirst, - >, - >; - type CancelOrigin = Architects; - type KillOrigin = Masters; - type Slash = ToParentTreasury; - type Votes = pallet_ranked_collective::Votes; - type Tally = pallet_ranked_collective::TallyOf; - type SubmissionDeposit = ConstU128<0>; - type MaxQueued = ConstU32<100>; - type UndecidingTimeout = ConstU32<{ 7 * DAYS }>; - type AlarmInterval = ConstU32<1>; - type Tracks = tracks::TracksInfo; - type Preimages = Preimage; -} - -pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; - -impl pallet_ranked_collective::Config for Runtime { - type WeightInfo = weights::pallet_ranked_collective_fellowship_collective::WeightInfo; - type RuntimeEvent = RuntimeEvent; - - #[cfg(not(feature = "runtime-benchmarks"))] - // Promotions and the induction of new members are serviced by `FellowshipCore` pallet instance. - type PromoteOrigin = frame_system::EnsureNever; - #[cfg(feature = "runtime-benchmarks")] - // The maximum value of `u16` set as a success value for the root to ensure the benchmarks will - // pass. - type PromoteOrigin = EnsureRootWithSuccess>; - - // Demotion is by any of: - // - Root can demote arbitrarily. - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - // The maximum value of `u16` set as a success value for the root to ensure the benchmarks will - // pass. - type DemoteOrigin = EitherOf< - EnsureRootWithSuccess>, - MapSuccess< - EnsureXcm>, - Replace>, - >, - >; - type Polls = FellowshipReferenda; - type MinRankOfClass = tracks::MinRankOfClass; - type VoteWeight = pallet_ranked_collective::Geometric; -} - -pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1; - -impl pallet_core_fellowship::Config for Runtime { - type WeightInfo = weights::pallet_core_fellowship_fellowship_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 Fellows. - type ParamsOrigin = EitherOfDiverse< - EnsureXcm>, - Fellows, - >; - // Induction (creating a candidate) is by any of: - // - Root; - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - a single Fellow; - // - a vote among all Members. - type InductOrigin = EitherOfDiverse< - EnsureXcm>, - EitherOfDiverse< - pallet_ranked_collective::EnsureMember< - Runtime, - FellowshipCollectiveInstance, - { ranks::DAN_3 }, - >, - Members, - >, - >; - // Approval (rank-retention) of a Member's current rank is by any of: - // - Root; - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - a vote by the rank two above the current rank for all retention up to the Master rank. - type ApproveOrigin = EitherOf< - MapSuccess< - EnsureXcm>, - Replace>, - >, - EnsureCanRetainAt, - >; - // Promotion is by any of: - // - Root can promote arbitrarily. - // - the FellowshipAdmin origin (i.e. token holder referendum); - // - a vote by the rank two above the new rank for all promotions up to the Master rank. - type PromoteOrigin = EitherOf< - MapSuccess< - EnsureXcm>, - Replace>, - >, - EnsureCanPromoteTo, - >; - type EvidenceSize = ConstU32<65536>; -} - -pub type FellowshipSalaryInstance = pallet_salary::Instance1; - -use xcm::prelude::*; - -parameter_types! { - // 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(); -} - -const USDT_UNITS: u128 = 1_000_000; - -/// [`PayOverXcm`] setup to pay the Fellowship salary on the AssetHub in USDT. -pub type FellowshipSalaryPaymaster = PayOverXcm< - Interior, - crate::xcm_config::XcmRouter, - crate::PolkadotXcm, - ConstU32<{ 6 * HOURS }>, - AccountId, - (), - ConvertToValue, - AliasesIntoAccountId32<(), AccountId>, ->; - -impl pallet_salary::Config for Runtime { - type WeightInfo = weights::pallet_salary_fellowship_salary::WeightInfo; - type RuntimeEvent = RuntimeEvent; - - #[cfg(not(feature = "runtime-benchmarks"))] - type Paymaster = FellowshipSalaryPaymaster; - #[cfg(feature = "runtime-benchmarks")] - type Paymaster = PayWithEnsure>>; - 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<{ 100_000 * USDT_UNITS }>; -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs deleted file mode 100644 index 5ed2c19f79e..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/origins.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Fellowship custom origins. - -use super::ranks; -pub use pallet_origins::*; - -#[frame_support::pallet] -pub mod pallet_origins { - use super::ranks; - use frame_support::pallet_prelude::*; - use pallet_ranked_collective::Rank; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - pub struct Pallet(_); - - #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] - #[pallet::origin] - pub enum Origin { - /// Origin aggregated through weighted votes of those with rank 1 or above; `Success` is 1. - /// Aka the "voice" of all Members. - Members, - /// Origin aggregated through weighted votes of those with rank 2 or above; `Success` is 2. - /// Aka the "voice" of members at least II Dan. - Fellowship2Dan, - /// Origin aggregated through weighted votes of those with rank 3 or above; `Success` is 3. - /// Aka the "voice" of all Fellows. - Fellows, - /// Origin aggregated through weighted votes of those with rank 4 or above; `Success` is 4. - /// Aka the "voice" of members at least IV Dan. - Architects, - /// Origin aggregated through weighted votes of those with rank 5 or above; `Success` is 5. - /// Aka the "voice" of members at least V Dan. - Fellowship5Dan, - /// Origin aggregated through weighted votes of those with rank 6 or above; `Success` is 6. - /// Aka the "voice" of members at least VI Dan. - Fellowship6Dan, - /// Origin aggregated through weighted votes of those with rank 7 or above; `Success` is 7. - /// Aka the "voice" of all Masters. - Masters, - /// Origin aggregated through weighted votes of those with rank 8 or above; `Success` is 8. - /// Aka the "voice" of members at least VIII Dan. - Fellowship8Dan, - /// Origin aggregated through weighted votes of those with rank 9 or above; `Success` is 9. - /// Aka the "voice" of members at least IX Dan. - Fellowship9Dan, - - /// Origin aggregated through weighted votes of those with rank 3 or above when voting on - /// a fortnight-long track; `Success` is 1. - RetainAt1Dan, - /// Origin aggregated through weighted votes of those with rank 4 or above when voting on - /// a fortnight-long track; `Success` is 2. - RetainAt2Dan, - /// Origin aggregated through weighted votes of those with rank 5 or above when voting on - /// a fortnight-long track; `Success` is 3. - RetainAt3Dan, - /// Origin aggregated through weighted votes of those with rank 6 or above when voting on - /// a fortnight-long track; `Success` is 4. - RetainAt4Dan, - /// Origin aggregated through weighted votes of those with rank 7 or above when voting on - /// a fortnight-long track; `Success` is 5. - RetainAt5Dan, - /// Origin aggregated through weighted votes of those with rank 8 or above when voting on - /// a fortnight-long track; `Success` is 6. - RetainAt6Dan, - - /// Origin aggregated through weighted votes of those with rank 3 or above when voting on - /// a month-long track; `Success` is 1. - PromoteTo1Dan, - /// Origin aggregated through weighted votes of those with rank 4 or above when voting on - /// a month-long track; `Success` is 2. - PromoteTo2Dan, - /// Origin aggregated through weighted votes of those with rank 5 or above when voting on - /// a month-long track; `Success` is 3. - PromoteTo3Dan, - /// Origin aggregated through weighted votes of those with rank 6 or above when voting on - /// a month-long track; `Success` is 4. - PromoteTo4Dan, - /// Origin aggregated through weighted votes of those with rank 7 or above when voting on - /// a month-long track; `Success` is 5. - PromoteTo5Dan, - /// Origin aggregated through weighted votes of those with rank 8 or above when voting on - /// a month-long track; `Success` is 6. - PromoteTo6Dan, - } - - impl Origin { - /// Returns the rank that the origin `self` speaks for, or `None` if it doesn't speak for - /// any. - /// - /// `Some` will be returned only for the first 9 elements of [Origin]. - pub fn as_voice(&self) -> Option { - Some(match &self { - Origin::Members => ranks::DAN_1, - Origin::Fellowship2Dan => ranks::DAN_2, - Origin::Fellows => ranks::DAN_3, - Origin::Architects => ranks::DAN_4, - Origin::Fellowship5Dan => ranks::DAN_5, - Origin::Fellowship6Dan => ranks::DAN_6, - Origin::Masters => ranks::DAN_7, - Origin::Fellowship8Dan => ranks::DAN_8, - Origin::Fellowship9Dan => ranks::DAN_9, - _ => return None, - }) - } - } - - /// A `TryMorph` implementation which is designed to convert an aggregate `RuntimeOrigin` - /// value into the Fellowship voice it represents if it is a Fellowship pallet origin an - /// appropriate variant. See also [Origin::as_voice]. - pub struct ToVoice; - impl<'a, O: 'a + TryInto<&'a Origin>> sp_runtime::traits::TryMorph for ToVoice { - type Outcome = pallet_ranked_collective::Rank; - fn try_morph(o: O) -> Result { - o.try_into().ok().and_then(Origin::as_voice).ok_or(()) - } - } - - macro_rules! decl_unit_ensures { - ( $name:ident: $success_type:ty = $success:expr ) => { - pub struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - Origin::$name => Ok($success), - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(Origin::$name)) - } - } - }; - ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; - ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { - decl_unit_ensures! { $name: $success_type = $success } - decl_unit_ensures! { $( $rest )* } - }; - ( $name:ident, $( $rest:tt )* ) => { - decl_unit_ensures! { $name } - decl_unit_ensures! { $( $rest )* } - }; - () => {} - } - decl_unit_ensures!( - Members: Rank = ranks::DAN_1, - Fellows: Rank = ranks::DAN_3, - Architects: Rank = ranks::DAN_4, - Masters: Rank = ranks::DAN_7, - ); - - macro_rules! decl_ensure { - ( - $vis:vis type $name:ident: EnsureOrigin { - $( $item:ident = $success:expr, )* - } - ) => { - $vis struct $name; - impl> + From> - EnsureOrigin for $name - { - type Success = $success_type; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - $( - Origin::$item => Ok($success), - )* - r => Err(O::from(r)), - }) - } - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - // By convention the more privileged origins go later, so for greatest chance - // of success, we want the last one. - let _result: Result = Err(()); - $( - let _result: Result = Ok(O::from(Origin::$item)); - )* - _result - } - } - } - } - - // Fellowship origin indicating weighted voting from at least the rank of `Success` on a - // week-long track. - decl_ensure! { - pub type EnsureFellowship: EnsureOrigin { - Members = ranks::DAN_1, - Fellowship2Dan = ranks::DAN_2, - Fellows = ranks::DAN_3, - Architects = ranks::DAN_4, - Fellowship5Dan = ranks::DAN_5, - Fellowship6Dan = ranks::DAN_6, - Masters = ranks::DAN_7, - Fellowship8Dan = ranks::DAN_8, - Fellowship9Dan = ranks::DAN_9, - } - } - - // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on - // a fortnight-long track; needed for Fellowship retention voting. - decl_ensure! { - pub type EnsureCanRetainAt: EnsureOrigin { - RetainAt1Dan = ranks::DAN_1, - RetainAt2Dan = ranks::DAN_2, - RetainAt3Dan = ranks::DAN_3, - RetainAt4Dan = ranks::DAN_4, - RetainAt5Dan = ranks::DAN_5, - RetainAt6Dan = ranks::DAN_6, - } - } - - // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on - // a month-long track; needed for Fellowship promotion voting. - decl_ensure! { - pub type EnsureCanPromoteTo: EnsureOrigin { - PromoteTo1Dan = ranks::DAN_1, - PromoteTo2Dan = ranks::DAN_2, - PromoteTo3Dan = ranks::DAN_3, - PromoteTo4Dan = ranks::DAN_4, - PromoteTo5Dan = ranks::DAN_5, - PromoteTo6Dan = ranks::DAN_6, - } - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs deleted file mode 100644 index f4ba4e05ec1..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/tracks.rs +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Track configurations for Fellowship. - -use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS, MINUTES}; -use pallet_ranked_collective::Rank; -use sp_runtime::{traits::Convert, Perbill}; - -/// Referendum `TrackId` type. -pub type TrackId = u16; - -/// Referendum track IDs. -pub mod constants { - use super::TrackId; - - // Regular tracks (7 days) used for general operations. The required rank for voting is the - // same as that which is named (and also the track ID). - pub const MEMBERS: TrackId = 1; - pub const PROFICIENTS: TrackId = 2; - pub const FELLOWS: TrackId = 3; - pub const ARCHITECTS: TrackId = 4; - pub const ARCHITECTS_ADEPT: TrackId = 5; - pub const GRAND_ARCHITECTS: TrackId = 6; - pub const MASTERS: TrackId = 7; - pub const MASTERS_CONSTANT: TrackId = 8; - pub const GRAND_MASTERS: TrackId = 9; - - // Longer tracks (14 days) used for rank retention. These require a rank of two more than the - // grade at which they retain (as per the whitepaper). This works out as the track ID minus 8. - pub const RETAIN_AT_1DAN: TrackId = 11; - pub const RETAIN_AT_2DAN: TrackId = 12; - pub const RETAIN_AT_3DAN: TrackId = 13; - pub const RETAIN_AT_4DAN: TrackId = 14; - pub const RETAIN_AT_5DAN: TrackId = 15; - pub const RETAIN_AT_6DAN: TrackId = 16; - - // Longest tracks (30 days) used for promotions. These require a rank of two more than the - // grade to which they promote (as per the whitepaper). This works out as the track ID minus 18. - pub const PROMOTE_TO_1DAN: TrackId = 21; - pub const PROMOTE_TO_2DAN: TrackId = 22; - pub const PROMOTE_TO_3DAN: TrackId = 23; - pub const PROMOTE_TO_4DAN: TrackId = 24; - pub const PROMOTE_TO_5DAN: TrackId = 25; - pub const PROMOTE_TO_6DAN: TrackId = 26; -} - -/// Convert the track ID (defined above) into the minimum rank (i.e. fellowship Dan grade) required -/// to vote on the track. -pub struct MinRankOfClass; -impl Convert for MinRankOfClass { - fn convert(a: TrackId) -> Rank { - match a { - // Just a regular vote: the track ID is conveniently the same as the minimum rank. - regular @ 1..=9 => regular, - // A retention vote; the track ID turns out to be 8 more than the minimum required rank. - retention @ 11..=16 => retention - 8, - // A promotion vote; the track ID turns out to be 18 more than the minimum required - // rank. - promotion @ 21..=26 => promotion - 18, - _ => Rank::max_value(), - } - } -} - -const RETAIN_MAX_DECIDING: u32 = 25; -const RETAIN_DECISION_DEPOSIT: Balance = 5 * DOLLARS; -const RETAIN_PREPARE_PERIOD: BlockNumber = 0; -const RETAIN_DECISION_PERIOD: BlockNumber = 14 * DAYS; -const RETAIN_CONFIRM_PERIOD: BlockNumber = 1 * HOURS; -const RETAIN_MIN_ENACTMENT_PERIOD: BlockNumber = 0; -const RETAIN_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(60), - ceil: Perbill::from_percent(100), -}; -const RETAIN_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(10), - ceil: Perbill::from_percent(100), -}; - -const PROMOTE_MAX_DECIDING: u32 = 10; -const PROMOTE_DECISION_DEPOSIT: Balance = 5 * DOLLARS; -const PROMOTE_PREPARE_PERIOD: BlockNumber = 0; -const PROMOTE_DECISION_PERIOD: BlockNumber = 30 * DAYS; -const PROMOTE_CONFIRM_PERIOD: BlockNumber = 1 * HOURS; -const PROMOTE_MIN_ENACTMENT_PERIOD: BlockNumber = 0; -const PROMOTE_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(60), - ceil: Perbill::from_percent(100), -}; -const PROMOTE_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(10), - ceil: Perbill::from_percent(100), -}; - -pub struct TracksInfo; -impl pallet_referenda::TracksInfo for TracksInfo { - type Id = TrackId; - type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - use constants as tracks; - static DATA: [(TrackId, pallet_referenda::TrackInfo); 21] = [ - ( - tracks::MEMBERS, - pallet_referenda::TrackInfo { - name: "members", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::PROFICIENTS, - pallet_referenda::TrackInfo { - name: "proficient members", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::FELLOWS, - pallet_referenda::TrackInfo { - name: "fellows", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::ARCHITECTS, - pallet_referenda::TrackInfo { - name: "architects", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::ARCHITECTS_ADEPT, - pallet_referenda::TrackInfo { - name: "architects adept", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::GRAND_ARCHITECTS, - pallet_referenda::TrackInfo { - name: "grand architects", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::MASTERS, - pallet_referenda::TrackInfo { - name: "masters", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::MASTERS_CONSTANT, - pallet_referenda::TrackInfo { - name: "masters constant", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::GRAND_MASTERS, - pallet_referenda::TrackInfo { - name: "grand masters", - max_deciding: 10, - decision_deposit: 5 * DOLLARS, - prepare_period: 30 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 30 * MINUTES, - min_enactment_period: 5 * MINUTES, - 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(0), - ceil: Perbill::from_percent(100), - }, - }, - ), - ( - tracks::RETAIN_AT_1DAN, - pallet_referenda::TrackInfo { - name: "retain at I Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::RETAIN_AT_2DAN, - pallet_referenda::TrackInfo { - name: "retain at II Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::RETAIN_AT_3DAN, - pallet_referenda::TrackInfo { - name: "retain at III Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::RETAIN_AT_4DAN, - pallet_referenda::TrackInfo { - name: "retain at IV Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::RETAIN_AT_5DAN, - pallet_referenda::TrackInfo { - name: "retain at V Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::RETAIN_AT_6DAN, - pallet_referenda::TrackInfo { - name: "retain at VI Dan", - max_deciding: RETAIN_MAX_DECIDING, - decision_deposit: RETAIN_DECISION_DEPOSIT, - prepare_period: RETAIN_PREPARE_PERIOD, - decision_period: RETAIN_DECISION_PERIOD, - confirm_period: RETAIN_CONFIRM_PERIOD, - min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, - min_approval: RETAIN_MIN_APPROVAL, - min_support: RETAIN_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_1DAN, - pallet_referenda::TrackInfo { - name: "promote to I Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_2DAN, - pallet_referenda::TrackInfo { - name: "promote to II Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_3DAN, - pallet_referenda::TrackInfo { - name: "promote to III Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_4DAN, - pallet_referenda::TrackInfo { - name: "promote to IV Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_5DAN, - pallet_referenda::TrackInfo { - name: "promote to V Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ( - tracks::PROMOTE_TO_6DAN, - pallet_referenda::TrackInfo { - name: "promote to VI Dan", - max_deciding: PROMOTE_MAX_DECIDING, - decision_deposit: PROMOTE_DECISION_DEPOSIT, - prepare_period: PROMOTE_PREPARE_PERIOD, - decision_period: PROMOTE_DECISION_PERIOD, - confirm_period: PROMOTE_CONFIRM_PERIOD, - min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, - min_approval: PROMOTE_MIN_APPROVAL, - min_support: PROMOTE_MIN_SUPPORT, - }, - ), - ]; - &DATA[..] - } - fn track_for(id: &Self::RuntimeOrigin) -> Result { - use super::origins::Origin; - use constants as tracks; - - #[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(tracks::GRAND_MASTERS) - } - } - - match Origin::try_from(id.clone()) { - Ok(Origin::Members) => Ok(tracks::MEMBERS), - Ok(Origin::Fellowship2Dan) => Ok(tracks::PROFICIENTS), - Ok(Origin::Fellows) => Ok(tracks::FELLOWS), - Ok(Origin::Architects) => Ok(tracks::ARCHITECTS), - Ok(Origin::Fellowship5Dan) => Ok(tracks::ARCHITECTS_ADEPT), - Ok(Origin::Fellowship6Dan) => Ok(tracks::GRAND_ARCHITECTS), - Ok(Origin::Masters) => Ok(tracks::MASTERS), - Ok(Origin::Fellowship8Dan) => Ok(tracks::MASTERS_CONSTANT), - Ok(Origin::Fellowship9Dan) => Ok(tracks::GRAND_MASTERS), - - Ok(Origin::RetainAt1Dan) => Ok(tracks::RETAIN_AT_1DAN), - Ok(Origin::RetainAt2Dan) => Ok(tracks::RETAIN_AT_2DAN), - Ok(Origin::RetainAt3Dan) => Ok(tracks::RETAIN_AT_3DAN), - Ok(Origin::RetainAt4Dan) => Ok(tracks::RETAIN_AT_4DAN), - Ok(Origin::RetainAt5Dan) => Ok(tracks::RETAIN_AT_5DAN), - Ok(Origin::RetainAt6Dan) => Ok(tracks::RETAIN_AT_6DAN), - - Ok(Origin::PromoteTo1Dan) => Ok(tracks::PROMOTE_TO_1DAN), - Ok(Origin::PromoteTo2Dan) => Ok(tracks::PROMOTE_TO_2DAN), - Ok(Origin::PromoteTo3Dan) => Ok(tracks::PROMOTE_TO_3DAN), - Ok(Origin::PromoteTo4Dan) => Ok(tracks::PROMOTE_TO_4DAN), - Ok(Origin::PromoteTo5Dan) => Ok(tracks::PROMOTE_TO_5DAN), - Ok(Origin::PromoteTo6Dan) => Ok(tracks::PROMOTE_TO_6DAN), - - _ => Err(()), - } - } -} -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs deleted file mode 100644 index 9f4c2a6a4c9..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/impls.rs +++ /dev/null @@ -1,229 +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::OriginCaller; -use frame_support::{ - dispatch::DispatchResultWithPostInfo, - traits::{Currency, Get, Imbalance, OnUnbalanced, OriginTrait, PrivilegeCmp}, - weights::Weight, -}; -use log; -use pallet_alliance::{ProposalIndex, ProposalProvider}; -use parachains_common::impls::NegativeImbalance; -use sp_runtime::DispatchError; -use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; -use xcm::latest::{Fungibility, Junction, Parent}; - -type AccountIdOf = ::AccountId; - -type ProposalOf = >::Proposal; - -type HashOf = ::Hash; - -/// Type alias to conveniently refer to the `Currency::Balance` associated type. -pub type BalanceOf = - as Currency<::AccountId>>::Balance; - -/// Implements `OnUnbalanced::on_unbalanced` to teleport slashed assets to relay chain treasury -/// account. -pub struct ToParentTreasury( - PhantomData<(TreasuryAccount, PalletAccount, T)>, -); - -impl OnUnbalanced> - for ToParentTreasury -where - T: pallet_balances::Config + pallet_xcm::Config + frame_system::Config, - <::RuntimeOrigin as OriginTrait>::AccountId: From>, - [u8; 32]: From<::AccountId>, - TreasuryAccount: Get>, - PalletAccount: Get>, - BalanceOf: Into, -{ - fn on_unbalanced(amount: NegativeImbalance) { - let amount = match amount.drop_zero() { - Ok(..) => return, - Err(amount) => amount, - }; - let imbalance = amount.peek(); - let pallet_acc: AccountIdOf = PalletAccount::get(); - let treasury_acc: AccountIdOf = TreasuryAccount::get(); - - >::resolve_creating(&pallet_acc, amount); - - let result = >::teleport_assets( - <::RuntimeOrigin>::signed(pallet_acc.into()), - Box::new(Parent.into()), - Box::new( - Junction::AccountId32 { network: None, id: treasury_acc.into() } - .into_location() - .into(), - ), - Box::new((Parent, imbalance).into()), - 0, - ); - - if let Err(err) = result { - log::warn!("Failed to teleport slashed assets: {:?}", err); - } - } -} - -/// Proposal provider for alliance pallet. -/// Adapter from collective pallet to alliance proposal provider trait. -pub struct AllianceProposalProvider(PhantomData<(T, I)>); - -impl ProposalProvider, HashOf, ProposalOf> - for AllianceProposalProvider -where - T: pallet_collective::Config + frame_system::Config, - I: 'static, -{ - fn propose_proposal( - who: AccountIdOf, - threshold: u32, - proposal: Box>, - length_bound: u32, - ) -> Result<(u32, u32), DispatchError> { - pallet_collective::Pallet::::do_propose_proposed( - who, - threshold, - proposal, - length_bound, - ) - } - - fn vote_proposal( - who: AccountIdOf, - proposal: HashOf, - index: ProposalIndex, - approve: bool, - ) -> Result { - pallet_collective::Pallet::::do_vote(who, proposal, index, approve) - } - - fn close_proposal( - proposal_hash: HashOf, - proposal_index: ProposalIndex, - proposal_weight_bound: Weight, - length_bound: u32, - ) -> DispatchResultWithPostInfo { - pallet_collective::Pallet::::do_close( - proposal_hash, - proposal_index, - proposal_weight_bound, - length_bound, - ) - } - - fn proposal_of(proposal_hash: HashOf) -> Option> { - pallet_collective::Pallet::::proposal_of(proposal_hash) - } -} - -/// Used to compare the privilege of an origin inside the scheduler. -pub struct EqualOrGreatestRootCmp; - -impl PrivilegeCmp for EqualOrGreatestRootCmp { - 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), - _ => None, - } - } -} - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarks { - use super::*; - use crate::ParachainSystem; - use cumulus_primitives_core::{ChannelStatus, GetChannelInfo}; - use frame_support::traits::{ - fungible, - tokens::{Pay, PaymentStatus}, - }; - use pallet_ranked_collective::Rank; - use parachains_common::{AccountId, Balance}; - use sp_runtime::traits::Convert; - - /// Rank to salary conversion helper type. - pub struct RankToSalary(PhantomData); - impl Convert for RankToSalary - where - Fungible: fungible::Inspect, - { - fn convert(r: Rank) -> Balance { - Balance::from(r).saturating_mul(Fungible::minimum_balance()) - } - } - - /// Trait for setting up any prerequisites for successful execution of benchmarks. - pub trait EnsureSuccessful { - fn ensure_successful(); - } - - /// Implementation of the [`EnsureSuccessful`] trait which opens an HRMP channel between - /// the Collectives and a parachain with a given ID. - pub struct OpenHrmpChannel(PhantomData); - impl> EnsureSuccessful for OpenHrmpChannel { - fn ensure_successful() { - if let ChannelStatus::Closed = ParachainSystem::get_channel_status(I::get().into()) { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(I::get().into()) - } - } - } - - /// Type that wraps a type implementing the [`Pay`] trait to decorate its - /// [`Pay::ensure_successful`] function with a provided implementation of the - /// [`EnsureSuccessful`] trait. - pub struct PayWithEnsure(PhantomData<(O, E)>); - impl Pay for PayWithEnsure - where - O: Pay, - E: EnsureSuccessful, - { - type AssetKind = O::AssetKind; - type Balance = O::Balance; - type Beneficiary = O::Beneficiary; - type Error = O::Error; - type Id = O::Id; - - fn pay( - who: &Self::Beneficiary, - asset_kind: Self::AssetKind, - amount: Self::Balance, - ) -> Result { - O::pay(who, asset_kind, amount) - } - fn check_payment(id: Self::Id) -> PaymentStatus { - O::check_payment(id) - } - fn ensure_successful( - who: &Self::Beneficiary, - asset_kind: Self::AssetKind, - amount: Self::Balance, - ) { - E::ensure_successful(); - O::ensure_successful(who, asset_kind, amount) - } - fn ensure_concluded(id: Self::Id) { - O::ensure_concluded(id) - } - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs deleted file mode 100644 index 90c44f8bfc5..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ /dev/null @@ -1,1031 +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. - -//! # Collectives Parachain -//! -//! This parachain is for collectives that serve the Polkadot network. -//! Each collective is defined by a specialized (possibly instanced) pallet. -//! -//! ### Governance -//! -//! As a system parachain, Collectives defers its governance (namely, its `Root` origin), to -//! its Relay Chain parent, Polkadot. -//! -//! ### Collator Selection -//! -//! Collectives uses `pallet-collator-selection`, a simple first-come-first-served registration -//! system where collators can reserve a small bond to join the block producer set. There is no -//! slashing. Collective members are generally expected to run collators. - -#![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")); - -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::{ - migration::import_kusama_fellowship, pallet_fellowship_origins, Fellows, - FellowshipCollectiveInstance, -}; -use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp, ToParentTreasury}; -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}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Perbill, -}; - -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use codec::{Decode, Encode, MaxEncodedLen}; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -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, - EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, - }, - weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -pub use parachains_common as common; -use parachains_common::{ - impls::DealWithFees, - message_queue::*, - polkadot::{account::*, consensus::*, currency::*, fee::WeightToFee}, - AccountId, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, - SLOT_DURATION, -}; -use sp_runtime::RuntimeDebug; -use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; - -#[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::{prelude::*, BodyId}; - -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("collectives"), - impl_name: create_runtime_str!("collectives"), - authoring_version: 1, - spec_version: 1_004_000, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 5, - 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() } -} - -/// Privileged origin that represents Root or more than two thirds of the Alliance. -pub type RootOrAllianceTwoThirdsMajority = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, ->; - -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(); -} - -// 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 = ConstU16<0>; - 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 RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - 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! { - // 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); -} - -impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = ConstU32<100>; - 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); - // One storage item; key size 32, value size 16 - pub const AnnouncementDepositBase: Balance = deposit(1, 48); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); -} - -/// 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. - NonTransfer, - /// Proxy with the ability to reject time-delay proxy announcements. - CancelProxy, - /// Collator selection proxy. Can execute calls related to collator selection mechanism. - Collator, - /// Alliance proxy. Allows calls related to the Alliance. - 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 { - Self::Any - } -} -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::NonTransfer => !matches!(c, RuntimeCall::Balances { .. }), - ProxyType::CancelProxy => matches!( - c, - RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), - ProxyType::Collator => matches!( - c, - RuntimeCall::CollatorSelection { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), - ProxyType::Alliance => matches!( - c, - RuntimeCall::AllianceMotion { .. } | - RuntimeCall::Alliance { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), - ProxyType::Fellowship => matches!( - 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 { .. } - ), - } - } - 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 = ConstU32<32>; - type WeightInfo = weights::pallet_proxy::WeightInfo; - type MaxPending = ConstU32<32>; - 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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - 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 {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -parameter_types! { - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(xcm_config::DotLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< - FeeAssetId, - BaseDeliveryFee, - TransactionByteFee, - XcmpQueue, ->; - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = EitherOfDiverse, Fellows>; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; - type PriceForSiblingDelivery = - polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} - -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, ConstU32>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU32>; - 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 = ConstU32; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = weights::pallet_collator_selection::WeightInfo; -} - -pub const ALLIANCE_MOTION_DURATION: BlockNumber = 5 * DAYS; - -parameter_types! { - pub const AllianceMotionDuration: BlockNumber = ALLIANCE_MOTION_DURATION; - pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; -} -pub const ALLIANCE_MAX_PROPOSALS: u32 = 100; -pub const ALLIANCE_MAX_MEMBERS: u32 = 100; - -type AllianceCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = AllianceMotionDuration; - type MaxProposals = ConstU32; - type MaxMembers = ConstU32; - type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; - type SetMembersOrigin = EnsureRoot; - type WeightInfo = weights::pallet_collective::WeightInfo; - type MaxProposalWeight = MaxProposalWeight; -} - -pub const MAX_FELLOWS: u32 = ALLIANCE_MAX_MEMBERS; -pub const MAX_ALLIES: u32 = 100; - -parameter_types! { - pub const AllyDeposit: Balance = 1_000 * UNITS; // 1,000 DOT bond to join as an Ally - // The Alliance pallet account, used as a temporary place to deposit a slashed imbalance - // before the teleport to the Treasury. - pub AlliancePalletAccount: AccountId = ALLIANCE_PALLET_ID.into_account_truncating(); - pub PolkadotTreasuryAccount: AccountId = POLKADOT_TREASURY_PALLET_ID.into_account_truncating(); - // The number of blocks a member must wait between giving a retirement notice and retiring. - // Supposed to be greater than time required to `kick_member` with alliance motion. - pub const AllianceRetirementPeriod: BlockNumber = (90 * DAYS) + ALLIANCE_MOTION_DURATION; -} - -impl pallet_alliance::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Proposal = RuntimeCall; - type AdminOrigin = RootOrAllianceTwoThirdsMajority; - type MembershipManager = RootOrAllianceTwoThirdsMajority; - type AnnouncementOrigin = RootOrAllianceTwoThirdsMajority; - type Currency = Balances; - type Slashed = ToParentTreasury; - type InitializeMembers = AllianceMotion; - type MembershipChanged = AllianceMotion; - type RetirementPeriod = AllianceRetirementPeriod; - type IdentityVerifier = (); // Don't block accounts on identity criteria - type ProposalProvider = AllianceProposalProvider; - type MaxProposals = ConstU32; - type MaxFellows = ConstU32; - type MaxAllies = ConstU32; - type MaxUnscrupulousItems = ConstU32<100>; - type MaxWebsiteUrlLength = ConstU32<255>; - type MaxAnnouncementsCount = ConstU32<100>; - type MaxMembersCount = ConstU32; - type AllyDeposit = AllyDeposit; - type WeightInfo = weights::pallet_alliance::WeightInfo; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; -} - -#[cfg(not(feature = "runtime-benchmarks"))] -parameter_types! { - pub const MaxScheduledPerBlock: u32 = 50; -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub const MaxScheduledPerBlock: u32 = 200; -} - -impl pallet_scheduler::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = weights::pallet_scheduler::WeightInfo; - type OriginPrivilegeCmp = EqualOrGreatestRootCmp; - 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, - >; -} - -// 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} = 2, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, - - // Monetary stuff. - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, - - // 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, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, - - // 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, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 43, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 44, - - // The main stage. - - // The Alliance. - Alliance: pallet_alliance::{Pallet, Call, Storage, Event, Config} = 50, - AllianceMotion: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 51, - - // The Fellowship. - // pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; - FellowshipCollective: pallet_ranked_collective::::{Pallet, Call, Storage, Event} = 60, - // pub type FellowshipReferendaInstance = pallet_referenda::Instance1; - FellowshipReferenda: pallet_referenda::::{Pallet, Call, Storage, Event} = 61, - FellowshipOrigins: pallet_fellowship_origins::{Origin} = 62, - // pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1; - 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, - } -); - -/// 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, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; -/// All migrations executed on runtime upgrade as a nested tuple of types implementing -/// `OnRuntimeUpgrade`. Included migrations must be idempotent. -type Migrations = ( - // v9420 - import_kusama_fellowship::Migration, - // unreleased - 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")] -mod benches { - frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_proxy, Proxy] - [pallet_session, SessionBench::] - [pallet_utility, Utility] - [pallet_timestamp, Timestamp] - [pallet_collator_selection, CollatorSelection] - [cumulus_pallet_parachain_system, ParachainSystem] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [cumulus_pallet_dmp_queue, DmpQueue] - [pallet_alliance, Alliance] - [pallet_collective, AllianceMotion] - [pallet_xcm, PalletXcmExtrinsicsBenchmark::] - [pallet_preimage, Preimage] - [pallet_scheduler, Scheduler] - [pallet_referenda, FellowshipReferenda] - [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] - ); -} - -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_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 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - - 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - impl pallet_xcm::benchmarking::Config for Runtime { - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Relay/native token can be teleported between Collectives and Relay. - Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Parent.into()) - }.into(), - Parent.into(), - )) - } - - fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { - // Reserve transfers are disabled on Collectives. - None - } - } - - 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(), - ]; - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } - 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! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs deleted file mode 100644 index e7fdb2aae2a..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +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. - -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/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs deleted file mode 100644 index cc41dcd6cbb..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_dmp_queue.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `cumulus_pallet_dmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue -// --chain=asset-hub-kusama-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65696` - // Estimated: `69161` - // Minimum execution time: 124_651_000 picoseconds. - Weight::from_parts(127_857_000, 0) - .saturating_add(Weight::from_parts(0, 69161)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65659` - // Estimated: `69124` - // Minimum execution time: 65_684_000 picoseconds. - Weight::from_parts(68_039_000, 0) - .saturating_add(Weight::from_parts(0, 69124)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_overweight_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65726` - // Estimated: `69191` - // Minimum execution time: 117_657_000 picoseconds. - Weight::from_parts(122_035_000, 0) - .saturating_add(Weight::from_parts(0, 69191)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) - /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) - /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) - fn on_idle_overweight_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65689` - // Estimated: `69154` - // Minimum execution time: 59_799_000 picoseconds. - Weight::from_parts(61_354_000, 0) - .saturating_add(Weight::from_parts(0, 69154)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index 0b7a2fc21cd..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// collectives-polkadot-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/collectives/collectives-polkadot/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `48` - // Estimated: `8121` - // Minimum execution time: 1_988_000 picoseconds. - Weight::from_parts(2_039_000, 0) - .saturating_add(Weight::from_parts(0, 8121)) - // Standard Error: 30_660 - .saturating_add(Weight::from_parts(24_419_204, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs deleted file mode 100644 index e68c075bffc..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ /dev/null @@ -1,148 +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. - -//! Autogenerated weights for `cumulus_pallet_xcmp_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --pallet -// cumulus-pallet-xcmp-queue -// --chain -// collectives-polkadot-dev -// --output -// cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs -// --extrinsic -// - -#![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: `142` - // Estimated: `1627` - // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 0) - .saturating_add(Weight::from_parts(0, 1627)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn enqueue_xcmp_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `148` - // Estimated: `3517` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn suspend_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `1627` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_000_000, 0) - .saturating_add(Weight::from_parts(0, 1627)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn resume_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `1662` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(5_000_000, 0) - .saturating_add(Weight::from_parts(0, 1662)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn take_first_concatenated_xcm() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) - /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) - fn on_idle_good_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65777` - // Estimated: `69242` - // Minimum execution time: 60_000_000 picoseconds. - Weight::from_parts(63_000_000, 0) - .saturating_add(Weight::from_parts(0, 69242)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { - // Proof Size summary in bytes: - // Measured: `65776` - // Estimated: `69241` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(43_000_000, 0) - .saturating_add(Weight::from_parts(0, 69241)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs deleted file mode 100644 index 1a4adb968bb..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,53 +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. - -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/collectives/collectives-polkadot/src/weights/frame_system.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs deleted file mode 100644 index b6f1dc8dc08..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-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/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 `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_926_000 picoseconds. - Weight::from_parts(1_929_666, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) - } - /// The range of component `b` is `[0, 3932160]`. - fn remark_with_event(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_221_000 picoseconds. - Weight::from_parts(34_449_539, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_706, 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_681_000 picoseconds. - Weight::from_parts(3_857_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: `156` - // Estimated: `1641` - // Minimum execution time: 101_899_621_000 picoseconds. - Weight::from_parts(106_377_672_000, 0) - .saturating_add(Weight::from_parts(0, 1641)) - .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_039_000 picoseconds. - Weight::from_parts(2_094_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_124 - .saturating_add(Weight::from_parts(754_465, 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_103_000 picoseconds. - Weight::from_parts(2_182_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_031 - .saturating_add(Weight::from_parts(570_563, 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: `82 + p * (69 ±0)` - // Estimated: `78 + p * (70 ±0)` - // Minimum execution time: 3_728_000 picoseconds. - Weight::from_parts(3_836_000, 0) - .saturating_add(Weight::from_parts(0, 78)) - // Standard Error: 1_802 - .saturating_add(Weight::from_parts(1_199_345, 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/collectives/collectives-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs deleted file mode 100644 index 1d877fdbd2b..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs +++ /dev/null @@ -1,50 +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 mod block_weights; -pub mod cumulus_pallet_dmp_queue; -pub mod cumulus_pallet_parachain_system; -pub mod cumulus_pallet_xcmp_queue; -pub mod extrinsic_weights; -pub mod frame_system; -pub mod pallet_alliance; -pub mod pallet_balances; -pub mod pallet_collator_selection; -pub mod pallet_collective; -pub mod pallet_collective_content; -pub mod pallet_core_fellowship_ambassador_core; -pub mod pallet_core_fellowship_fellowship_core; -pub mod pallet_message_queue; -pub mod pallet_multisig; -pub mod pallet_preimage; -pub mod pallet_proxy; -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; -pub mod pallet_utility; -pub mod pallet_xcm; -pub mod paritydb_weights; -pub mod rocksdb_weights; - -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/collectives/collectives-polkadot/src/weights/pallet_alliance.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs deleted file mode 100644 index d8ede609a67..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs +++ /dev/null @@ -1,494 +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. - -//! Autogenerated weights for `pallet_alliance` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_alliance -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ - -#![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_alliance`. -pub struct WeightInfo(PhantomData); -impl pallet_alliance::WeightInfo for WeightInfo { - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:0 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `439 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 32_783_000 picoseconds. - Weight::from_parts(32_174_037, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 198 - .saturating_add(Weight::from_parts(1_220, 0).saturating_mul(b.into())) - // Standard Error: 2_074 - .saturating_add(Weight::from_parts(40_945, 0).saturating_mul(m.into())) - // Standard Error: 2_048 - .saturating_add(Weight::from_parts(181_087, 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, 32).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `868 + m * (64 ±0)` - // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 28_520_000 picoseconds. - Weight::from_parts(29_661_024, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 2_336 - .saturating_add(Weight::from_parts(89_873, 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: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `312 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 39_353_000 picoseconds. - Weight::from_parts(33_028_008, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 2_137 - .saturating_add(Weight::from_parts(90_946, 0).saturating_mul(m.into())) - // Standard Error: 2_084 - .saturating_add(Weight::from_parts(175_827, 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, 97).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `762 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 52_835_000 picoseconds. - Weight::from_parts(45_963_292, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 3_189 - .saturating_add(Weight::from_parts(111_627, 0).saturating_mul(m.into())) - // Standard Error: 3_109 - .saturating_add(Weight::from_parts(207_923, 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, 97).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::Rule` (r:0 w:1) - /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `518 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `6676 + m * (109 ±0) + p * (43 ±0)` - // Minimum execution time: 49_980_000 picoseconds. - Weight::from_parts(48_110_301, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 5_057 - .saturating_add(Weight::from_parts(169_065, 0).saturating_mul(m.into())) - // Standard Error: 4_995 - .saturating_add(Weight::from_parts(201_349, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 109).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 43).saturating_mul(p.into())) - } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[5, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `417 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `6676 + m * (96 ±0) + p * (36 ±0)` - // Minimum execution time: 40_646_000 picoseconds. - Weight::from_parts(36_865_909, 0) - .saturating_add(Weight::from_parts(0, 6676)) - // Standard Error: 2_136 - .saturating_add(Weight::from_parts(74_341, 0).saturating_mul(m.into())) - // Standard Error: 2_059 - .saturating_add(Weight::from_parts(170_035, 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, 96).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:1 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[1, 100]`. - /// The range of component `z` is `[0, 100]`. - fn init_members(m: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `12362` - // Minimum execution time: 29_710_000 picoseconds. - Weight::from_parts(17_762_170, 0) - .saturating_add(Weight::from_parts(0, 12362)) - // Standard Error: 1_652 - .saturating_add(Weight::from_parts(156_967, 0).saturating_mul(m.into())) - // Standard Error: 1_632 - .saturating_add(Weight::from_parts(130_352, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:200 w:50) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:50 w:50) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `x` is `[1, 100]`. - /// The range of component `y` is `[0, 100]`. - /// The range of component `z` is `[0, 50]`. - fn disband(x: u32, y: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + x * (52 ±0) + y * (53 ±0) + z * (250 ±0)` - // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 294_258_000 picoseconds. - Weight::from_parts(295_116_000, 0) - .saturating_add(Weight::from_parts(0, 12362)) - // Standard Error: 23_663 - .saturating_add(Weight::from_parts(553_978, 0).saturating_mul(x.into())) - // Standard Error: 23_549 - .saturating_add(Weight::from_parts(567_024, 0).saturating_mul(y.into())) - // Standard Error: 47_055 - .saturating_add(Weight::from_parts(15_439_056, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) - .saturating_add(Weight::from_parts(0, 2539).saturating_mul(x.into())) - .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) - } - /// Storage: `Alliance::Rule` (r:0 w:1) - /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) - fn set_rule() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_538_000 picoseconds. - Weight::from_parts(8_752_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) - fn announce() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `10187` - // Minimum execution time: 11_213_000 picoseconds. - Weight::from_parts(11_792_000, 0) - .saturating_add(Weight::from_parts(0, 10187)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) - fn remove_announcement() -> Weight { - // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `10187` - // Minimum execution time: 12_477_000 picoseconds. - Weight::from_parts(12_942_000, 0) - .saturating_add(Weight::from_parts(0, 10187)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:0 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - fn join_alliance() -> Weight { - // Proof Size summary in bytes: - // Measured: `294` - // Estimated: `18048` - // Minimum execution time: 41_517_000 picoseconds. - Weight::from_parts(42_433_000, 0) - .saturating_add(Weight::from_parts(0, 18048)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - fn nominate_ally() -> Weight { - // Proof Size summary in bytes: - // Measured: `193` - // Estimated: `18048` - // Minimum execution time: 25_950_000 picoseconds. - Weight::from_parts(26_631_000, 0) - .saturating_add(Weight::from_parts(0, 18048)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn elevate_ally() -> Weight { - // Proof Size summary in bytes: - // Measured: `236` - // Estimated: `12362` - // Minimum execution time: 24_470_000 picoseconds. - Weight::from_parts(25_222_000, 0) - .saturating_add(Weight::from_parts(0, 12362)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `Alliance::Members` (r:4 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::RetiringMembers` (r:0 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - fn give_retirement_notice() -> Weight { - // Proof Size summary in bytes: - // Measured: `236` - // Estimated: `23734` - // Minimum execution time: 31_519_000 picoseconds. - Weight::from_parts(32_827_000, 0) - .saturating_add(Weight::from_parts(0, 23734)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: `Alliance::RetiringMembers` (r:1 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Alliance::Members` (r:1 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn retire() -> Weight { - // Proof Size summary in bytes: - // Measured: `517` - // Estimated: `6676` - // Minimum execution time: 38_799_000 picoseconds. - Weight::from_parts(39_634_000, 0) - .saturating_add(Weight::from_parts(0, 6676)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r: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`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn kick_member() -> Weight { - // Proof Size summary in bytes: - // Measured: `643` - // Estimated: `18048` - // Minimum execution time: 137_442_000 picoseconds. - Weight::from_parts(142_142_000, 0) - .saturating_add(Weight::from_parts(0, 18048)) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 100]`. - /// The range of component `l` is `[0, 255]`. - fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `27187` - // Minimum execution time: 7_189_000 picoseconds. - Weight::from_parts(7_387_000, 0) - .saturating_add(Weight::from_parts(0, 27187)) - // Standard Error: 3_417 - .saturating_add(Weight::from_parts(1_581_413, 0).saturating_mul(n.into())) - // Standard Error: 1_338 - .saturating_add(Weight::from_parts(67_739, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 100]`. - /// The range of component `l` is `[0, 255]`. - fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + l * (100 ±0) + n * (289 ±0)` - // Estimated: `27187` - // Minimum execution time: 7_201_000 picoseconds. - Weight::from_parts(7_325_000, 0) - .saturating_add(Weight::from_parts(0, 27187)) - // Standard Error: 183_302 - .saturating_add(Weight::from_parts(16_886_382, 0).saturating_mul(n.into())) - // Standard Error: 71_789 - .saturating_add(Weight::from_parts(352_937, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Alliance::Members` (r:3 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn abdicate_fellow_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `236` - // Estimated: `18048` - // Minimum execution time: 29_653_000 picoseconds. - Weight::from_parts(30_365_000, 0) - .saturating_add(Weight::from_parts(0, 18048)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs deleted file mode 100644 index 6c1cf072257..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs +++ /dev/null @@ -1,152 +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. - -//! Autogenerated weights for `pallet_balances` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ - -#![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_696_000 picoseconds. - Weight::from_parts(56_582_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: 40_885_000 picoseconds. - Weight::from_parts(41_993_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: `103` - // Estimated: `3593` - // Minimum execution time: 14_565_000 picoseconds. - Weight::from_parts(15_080_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: `103` - // Estimated: `3593` - // Minimum execution time: 22_158_000 picoseconds. - Weight::from_parts(22_715_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_957_000 picoseconds. - Weight::from_parts(58_618_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: 52_018_000 picoseconds. - Weight::from_parts(52_795_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: `103` - // Estimated: `3593` - // Minimum execution time: 17_469_000 picoseconds. - Weight::from_parts(18_030_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:999 w:999) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 17_223_000 picoseconds. - Weight::from_parts(17_587_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 16_201 - .saturating_add(Weight::from_parts(15_360_967, 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/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs deleted file mode 100644 index 03f3ff602a5..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs +++ /dev/null @@ -1,246 +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. - -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-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/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_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: 14_616_000 picoseconds. - Weight::from_parts(12_150_410, 0) - .saturating_add(Weight::from_parts(0, 1154)) - // Standard Error: 6_270 - .saturating_add(Weight::from_parts(3_256_932, 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: 48_450_000 picoseconds. - Weight::from_parts(51_166_679, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_588 - .saturating_add(Weight::from_parts(167_219, 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: 15_830_000 picoseconds. - Weight::from_parts(15_792_847, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 5_343 - .saturating_add(Weight::from_parts(167_955, 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_424_000 picoseconds. - Weight::from_parts(7_767_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(_c: u32, _k: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_388_000 picoseconds. - Weight::from_parts(7_677_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: 41_241_000 picoseconds. - Weight::from_parts(46_090_319, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_918 - .saturating_add(Weight::from_parts(161_140, 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_221_000 picoseconds. - Weight::from_parts(36_183_872, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_766 - .saturating_add(Weight::from_parts(168_742, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - fn update_bond(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)) - } - fn take_candidate_slot(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: 43_910_000 picoseconds. - Weight::from_parts(44_796_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_092_000 picoseconds. - Weight::from_parts(17_635_000, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 351_635 - .saturating_add(Weight::from_parts(15_162_192, 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/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs deleted file mode 100644 index 9133baa6120..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs +++ /dev/null @@ -1,304 +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. - -//! Autogenerated weights for `pallet_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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_collective -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ - -#![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: `AllianceMotion::Members` (r:1 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:100 w:100) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `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: `15691 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 16_410_000 picoseconds. - Weight::from_parts(16_816_000, 0) - .saturating_add(Weight::from_parts(0, 15691)) - // Standard Error: 59_812 - .saturating_add(Weight::from_parts(4_516_537, 0).saturating_mul(m.into())) - // Standard Error: 59_812 - .saturating_add(Weight::from_parts(7_992_168, 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: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::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]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `1518 + m * (32 ±0)` - // Minimum execution time: 14_418_000 picoseconds. - Weight::from_parts(13_588_617, 0) - .saturating_add(Weight::from_parts(0, 1518)) - // Standard Error: 21 - .saturating_add(Weight::from_parts(1_711, 0).saturating_mul(b.into())) - // Standard Error: 223 - .saturating_add(Weight::from_parts(13_836, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:0) - /// Proof: `AllianceMotion::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]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `3498 + m * (32 ±0)` - // Minimum execution time: 17_174_000 picoseconds. - Weight::from_parts(16_192_764, 0) - .saturating_add(Weight::from_parts(0, 3498)) - // Standard Error: 27 - .saturating_add(Weight::from_parts(1_672, 0).saturating_mul(b.into())) - // Standard Error: 280 - .saturating_add(Weight::from_parts(24_343, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:0 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[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: `322 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3714 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 23_970_000 picoseconds. - Weight::from_parts(23_004_052, 0) - .saturating_add(Weight::from_parts(0, 3714)) - // Standard Error: 123 - .saturating_add(Weight::from_parts(2_728, 0).saturating_mul(b.into())) - // Standard Error: 1_291 - .saturating_add(Weight::from_parts(32_731, 0).saturating_mul(m.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(199_537, 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: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `771 + m * (64 ±0)` - // Estimated: `4235 + m * (64 ±0)` - // Minimum execution time: 25_843_000 picoseconds. - Weight::from_parts(26_092_578, 0) - .saturating_add(Weight::from_parts(0, 4235)) - // Standard Error: 1_785 - .saturating_add(Weight::from_parts(67_298, 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: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `360 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3805 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_543_000 picoseconds. - Weight::from_parts(26_505_473, 0) - .saturating_add(Weight::from_parts(0, 3805)) - // Standard Error: 1_054 - .saturating_add(Weight::from_parts(35_295, 0).saturating_mul(m.into())) - // Standard Error: 1_028 - .saturating_add(Weight::from_parts(190_508, 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: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `662 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `3979 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_375_000 picoseconds. - Weight::from_parts(34_081_294, 0) - .saturating_add(Weight::from_parts(0, 3979)) - // Standard Error: 196 - .saturating_add(Weight::from_parts(3_796, 0).saturating_mul(b.into())) - // Standard Error: 2_072 - .saturating_add(Weight::from_parts(50_954, 0).saturating_mul(m.into())) - // Standard Error: 2_020 - .saturating_add(Weight::from_parts(246_000, 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: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `458 + m * (48 ±0) + p * (36 ±0)` - // Estimated: `3898 + m * (49 ±0) + p * (36 ±0)` - // Minimum execution time: 28_793_000 picoseconds. - Weight::from_parts(29_656_832, 0) - .saturating_add(Weight::from_parts(0, 3898)) - // Standard Error: 1_214 - .saturating_add(Weight::from_parts(22_148, 0).saturating_mul(m.into())) - // Standard Error: 1_184 - .saturating_add(Weight::from_parts(189_860, 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, 49).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `682 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `3999 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_887_000 picoseconds. - Weight::from_parts(39_529_567, 0) - .saturating_add(Weight::from_parts(0, 3999)) - // Standard Error: 191 - .saturating_add(Weight::from_parts(2_802, 0).saturating_mul(b.into())) - // Standard Error: 2_021 - .saturating_add(Weight::from_parts(35_956, 0).saturating_mul(m.into())) - // Standard Error: 1_970 - .saturating_add(Weight::from_parts(235_154, 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: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:0 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `189 + p * (32 ±0)` - // Estimated: `1674 + p * (32 ±0)` - // Minimum execution time: 14_040_000 picoseconds. - Weight::from_parts(15_075_964, 0) - .saturating_add(Weight::from_parts(0, 1674)) - // Standard Error: 854 - .saturating_add(Weight::from_parts(159_597, 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/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 deleted file mode 100644 index 6be94db22db..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs +++ /dev/null @@ -1,93 +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. - -//! 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 deleted file mode 100644 index f40940a8b25..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs +++ /dev/null @@ -1,223 +0,0 @@ -// 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_fellowship_core.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs deleted file mode 100644 index 471ee82ead7..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs +++ /dev/null @@ -1,222 +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. - -//! 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: `FellowshipCore::Params` (r:0 w:1) - /// Proof: `FellowshipCore::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(12_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:1) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Params` (r:1 w:0) - /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, 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:0) - /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) - fn bump_offboard() -> Weight { - // Proof Size summary in bytes: - // Measured: `66144` - // Estimated: `69046` - // 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)) - } - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:1) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Params` (r:1 w:0) - /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, 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:0) - /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) - fn bump_demote() -> Weight { - // Proof Size summary in bytes: - // Measured: `66254` - // Estimated: `69046` - // 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)) - } - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - fn set_active() -> Weight { - // Proof Size summary in bytes: - // Measured: `493` - // Estimated: `3514` - // 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)) - } - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// 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 induct() -> Weight { - // Proof Size summary in bytes: - // Measured: `251` - // Estimated: `3514` - // 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)) - } - /// Storage: `FellowshipCollective::Members` (r:1 w:1) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Params` (r:1 w:0) - /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::MemberCount` (r:1 w:1) - /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, 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 promote() -> Weight { - // Proof Size summary in bytes: - // Measured: `66122` - // Estimated: `69046` - // 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)) - } - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:0 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) - fn offboard() -> Weight { - // Proof Size summary in bytes: - // Measured: `464` - // Estimated: `3514` - // 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)) - } - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - fn import() -> Weight { - // Proof Size summary in bytes: - // Measured: `418` - // Estimated: `3514` - // 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)) - } - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::Member` (r:1 w:1) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) - fn approve() -> Weight { - // Proof Size summary in bytes: - // Measured: `66100` - // Estimated: `69046` - // 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)) - } - /// Storage: `FellowshipCore::Member` (r:1 w:0) - /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) - /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) - fn submit_evidence() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `69046` - // 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_message_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs deleted file mode 100644 index 4bd71c4e7d4..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// collectives-polkadot-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/collectives/collectives-polkadot/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 11_440_000 picoseconds. - Weight::from_parts(11_440_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 11_077_000 picoseconds. - Weight::from_parts(11_077_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 3_977_000 picoseconds. - Weight::from_parts(3_977_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 4_831_000 picoseconds. - Weight::from_parts(4_831_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 5_192_000 picoseconds. - Weight::from_parts(5_192_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 58_750_000 picoseconds. - Weight::from_parts(58_750_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 5_107_000 picoseconds. - Weight::from_parts(5_107_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 46_814_000 picoseconds. - Weight::from_parts(46_814_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 52_510_000 picoseconds. - Weight::from_parts(52_510_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 71_930_000 picoseconds. - Weight::from_parts(71_930_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs deleted file mode 100644 index a7827b72009..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,164 +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. - -//! Autogenerated weights for `pallet_multisig` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./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_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_288_000 picoseconds. - Weight::from_parts(14_235_741, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(500, 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: `328 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 44_865_000 picoseconds. - Weight::from_parts(33_468_056, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_513 - .saturating_add(Weight::from_parts(130_544, 0).saturating_mul(s.into())) - // Standard Error: 14 - .saturating_add(Weight::from_parts(1_422, 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: `348` - // Estimated: `6811` - // Minimum execution time: 29_284_000 picoseconds. - Weight::from_parts(18_708_967, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 916 - .saturating_add(Weight::from_parts(119_202, 0).saturating_mul(s.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_447, 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: `451 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 49_462_000 picoseconds. - Weight::from_parts(34_470_286, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_738 - .saturating_add(Weight::from_parts(178_227, 0).saturating_mul(s.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_644, 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: `329 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 30_749_000 picoseconds. - Weight::from_parts(31_841_438, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_033 - .saturating_add(Weight::from_parts(123_126, 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: `348` - // Estimated: `6811` - // Minimum execution time: 17_436_000 picoseconds. - Weight::from_parts(18_036_002, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 829 - .saturating_add(Weight::from_parts(109_450, 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: `520 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 31_532_000 picoseconds. - Weight::from_parts(32_818_015, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 977 - .saturating_add(Weight::from_parts(123_121, 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/collectives/collectives-polkadot/src/weights/pallet_preimage.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs deleted file mode 100644 index 9b45c875818..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_preimage.rs +++ /dev/null @@ -1,232 +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. - -//! Autogenerated weights for `pallet_preimage` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_preimage -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ - -#![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: `177` - // Estimated: `3556` - // Minimum execution time: 29_323_000 picoseconds. - Weight::from_parts(29_793_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_504, 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: `140` - // Estimated: `3556` - // Minimum execution time: 15_581_000 picoseconds. - Weight::from_parts(15_659_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_500, 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: `140` - // Estimated: `3556` - // Minimum execution time: 15_028_000 picoseconds. - Weight::from_parts(15_150_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(2_560, 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: `323` - // Estimated: `3556` - // Minimum execution time: 55_113_000 picoseconds. - Weight::from_parts(59_127_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: `178` - // Estimated: `3556` - // Minimum execution time: 38_033_000 picoseconds. - Weight::from_parts(41_203_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: `222` - // Estimated: `3556` - // Minimum execution time: 31_482_000 picoseconds. - Weight::from_parts(34_726_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: `178` - // Estimated: `3556` - // Minimum execution time: 20_724_000 picoseconds. - Weight::from_parts(22_928_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: `76` - // Estimated: `3556` - // Minimum execution time: 27_015_000 picoseconds. - Weight::from_parts(29_240_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: `140` - // Estimated: `3556` - // Minimum execution time: 10_712_000 picoseconds. - Weight::from_parts(11_317_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: `178` - // Estimated: `3556` - // Minimum execution time: 34_528_000 picoseconds. - Weight::from_parts(35_982_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: `140` - // Estimated: `3556` - // Minimum execution time: 11_059_000 picoseconds. - Weight::from_parts(12_458_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: `140` - // Estimated: `3556` - // Minimum execution time: 11_502_000 picoseconds. - Weight::from_parts(12_180_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/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs deleted file mode 100644 index 59d9f912bf1..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs +++ /dev/null @@ -1,225 +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. - -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-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/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_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: 15_597_000 picoseconds. - Weight::from_parts(16_231_993, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_665 - .saturating_add(Weight::from_parts(29_818, 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: 36_685_000 picoseconds. - Weight::from_parts(36_376_358, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 3_003 - .saturating_add(Weight::from_parts(133_776, 0).saturating_mul(a.into())) - // Standard Error: 3_103 - .saturating_add(Weight::from_parts(60_315, 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: 23_835_000 picoseconds. - Weight::from_parts(24_154_219, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_580 - .saturating_add(Weight::from_parts(125_884, 0).saturating_mul(a.into())) - // Standard Error: 1_632 - .saturating_add(Weight::from_parts(21_563, 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: 23_997_000 picoseconds. - Weight::from_parts(24_301_638, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_658 - .saturating_add(Weight::from_parts(133_005, 0).saturating_mul(a.into())) - // Standard Error: 1_713 - .saturating_add(Weight::from_parts(20_237, 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_604_000 picoseconds. - Weight::from_parts(33_322_880, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(114_037, 0).saturating_mul(a.into())) - // Standard Error: 1_901 - .saturating_add(Weight::from_parts(45_629, 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_634_000 picoseconds. - Weight::from_parts(25_509_118, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_278 - .saturating_add(Weight::from_parts(38_401, 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: 24_855_000 picoseconds. - Weight::from_parts(25_753_505, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_819 - .saturating_add(Weight::from_parts(44_357, 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_211_000 picoseconds. - Weight::from_parts(23_094_124, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_597 - .saturating_add(Weight::from_parts(36_725, 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_764_000 picoseconds. - Weight::from_parts(27_667_535, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_111 - .saturating_add(Weight::from_parts(3_422, 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: 22_632_000 picoseconds. - Weight::from_parts(23_678_772, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_136 - .saturating_add(Weight::from_parts(26_492, 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/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 deleted file mode 100644 index a6372c4b89d..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs +++ /dev/null @@ -1,177 +0,0 @@ -// 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_fellowship_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs deleted file mode 100644 index 9c773c56ac3..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs +++ /dev/null @@ -1,176 +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. - -//! 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: `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: `142` - // Estimated: `3507` - // 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)) - } - /// 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]`. - /// The range of component `r` is `[0, 10]`. - fn remove_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `608 + r * (281 ±0)` - // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_500_000, 0) - .saturating_add(Weight::from_parts(0, 3519)) - // 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)) - .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]`. - /// The range of component `r` is `[0, 10]`. - fn promote_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `310 + r * (17 ±0)` - // Estimated: `3507` - // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(25_500_000, 0) - .saturating_add(Weight::from_parts(0, 3507)) - // 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)) - } - /// 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]`. - /// The range of component `r` is `[0, 10]`. - fn demote_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `608 + r * (71 ±0)` - // Estimated: `3519` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_500_000, 0) - .saturating_add(Weight::from_parts(0, 3519)) - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `700` - // Estimated: `317568` - // 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)) - } - /// 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]`. - /// The range of component `n` is `[0, 100]`. - fn cleanup_poll(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // 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: 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, 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 deleted file mode 100644 index fdc451c5d31..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs +++ /dev/null @@ -1,536 +0,0 @@ -// 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_fellowship_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs deleted file mode 100644 index 63f68833795..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs +++ /dev/null @@ -1,535 +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. - -//! 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: `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(155814), added: 158289, 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: `389` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn place_decision_deposit_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `400` - // Estimated: `317568` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn place_decision_deposit_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2038` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn place_decision_deposit_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2079` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn place_decision_deposit_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `836` - // Estimated: `317568` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn place_decision_deposit_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `735` - // Estimated: `317568` - // 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)) - } - /// 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: 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)) - } - /// 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: 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `317568` - // 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)) - } - /// 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(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: `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: `587` - // Estimated: `317568` - // 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)) - } - /// 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: 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn one_fewer_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2452` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn one_fewer_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2452` - // Estimated: `159279` - // 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)) - } - /// 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: 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)) - } - /// 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: 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)) - } - /// 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_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)) - } - /// 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: 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_no_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `297` - // 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: `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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `159279` - // 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)) - } - /// 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: 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_begin_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `680` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_begin_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `781` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_begin_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_end_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `817` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_continue_not_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `159279` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_continue_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `838` - // Estimated: `159279` - // 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)) - } - /// 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(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: `838` - // Estimated: `317568` - // 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)) - } - /// 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(155814), added: 158289, mode: `MaxEncodedLen`) - fn nudge_referendum_rejected() -> Weight { - // Proof Size summary in bytes: - // Measured: `834` - // 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: `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: `453` - // Estimated: `4365` - // 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)) - } - /// 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: 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 deleted file mode 100644 index 0522420f2f5..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs +++ /dev/null @@ -1,190 +0,0 @@ -// 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_fellowship_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs deleted file mode 100644 index 37680b4e5df..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs +++ /dev/null @@ -1,189 +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. - -//! 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: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - fn init() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `1541` - // 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)) - } - /// Storage: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - fn bump() -> Weight { - // Proof Size summary in bytes: - // Measured: `224` - // Estimated: `1541` - // 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)) - } - /// Storage: `FellowshipSalary::Status` (r:1 w:0) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) - /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) - fn induct() -> Weight { - // Proof Size summary in bytes: - // Measured: `395` - // Estimated: `3551` - // 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)) - } - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) - /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) - fn register() -> Weight { - // Proof Size summary in bytes: - // Measured: `462` - // Estimated: `3551` - // 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)) - } - /// Storage: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) - /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::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: `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)) - } - /// Storage: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) - /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) - /// Storage: `FellowshipCollective::Members` (r:1 w:0) - /// Proof: `FellowshipCollective::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: `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)) - } - /// Storage: `FellowshipSalary::Status` (r:1 w:1) - /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) - /// Proof: `FellowshipSalary::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: `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/weights/pallet_scheduler.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.rs deleted file mode 100644 index cf5610df665..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_scheduler.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. - -//! Autogenerated weights for `pallet_scheduler` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_scheduler -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ - -#![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: `31` - // Estimated: `1489` - // Minimum execution time: 3_441_000 picoseconds. - Weight::from_parts(3_604_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(155814), added: 158289, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 200]`. - fn service_agenda_base(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `77 + s * (177 ±0)` - // Estimated: `159279` - // Minimum execution time: 2_879_000 picoseconds. - Weight::from_parts(2_963_000, 0) - .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 3_764 - .saturating_add(Weight::from_parts(909_557, 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_172_000 picoseconds. - Weight::from_parts(5_294_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: `213 + s * (1 ±0)` - // Estimated: `3678 + s * (1 ±0)` - // Minimum execution time: 19_704_000 picoseconds. - Weight::from_parts(19_903_000, 0) - .saturating_add(Weight::from_parts(0, 3678)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_394, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .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: 6_359_000 picoseconds. - Weight::from_parts(6_599_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_217_000 picoseconds. - Weight::from_parts(5_333_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_406_000 picoseconds. - Weight::from_parts(2_541_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_370_000 picoseconds. - Weight::from_parts(2_561_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 199]`. - fn schedule(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `77 + s * (177 ±0)` - // Estimated: `159279` - // Minimum execution time: 11_784_000 picoseconds. - Weight::from_parts(5_574_404, 0) - .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_217 - .saturating_add(Weight::from_parts(1_035_248, 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(155814), added: 158289, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:0 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 200]`. - fn cancel(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `77 + s * (177 ±0)` - // Estimated: `159279` - // Minimum execution time: 16_373_000 picoseconds. - Weight::from_parts(3_088_135, 0) - .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_095 - .saturating_add(Weight::from_parts(1_745_270, 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(155814), added: 158289, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 199]`. - fn schedule_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `468 + s * (179 ±0)` - // Estimated: `159279` - // Minimum execution time: 14_822_000 picoseconds. - Weight::from_parts(9_591_402, 0) - .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_151 - .saturating_add(Weight::from_parts(1_058_408, 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(155814), added: 158289, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 200]`. - fn cancel_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `509 + s * (179 ±0)` - // Estimated: `159279` - // Minimum execution time: 18_541_000 picoseconds. - Weight::from_parts(6_522_239, 0) - .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 8_349 - .saturating_add(Weight::from_parts(1_760_431, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs deleted file mode 100644 index 2ac0804df89..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs +++ /dev/null @@ -1,80 +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. - -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-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/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_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_663_000 picoseconds. - Weight::from_parts(17_246_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: 11_850_000 picoseconds. - Weight::from_parts(12_204_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/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs deleted file mode 100644 index ca06f43f92e..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,74 +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. - -//! Autogenerated weights for `pallet_timestamp` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./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_timestamp`. -pub struct WeightInfo(PhantomData); -impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Aura::CurrentSlot` (r:1 w:0) - /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set() -> Weight { - // Proof Size summary in bytes: - // Measured: `49` - // Estimated: `1493` - // Minimum execution time: 7_863_000 picoseconds. - Weight::from_parts(8_183_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: `57` - // Estimated: `0` - // Minimum execution time: 3_460_000 picoseconds. - Weight::from_parts(3_577_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs deleted file mode 100644 index c60a79d91da..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs +++ /dev/null @@ -1,101 +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. - -//! Autogenerated weights for `pallet_utility` -//! -//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./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_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_650_000 picoseconds. - Weight::from_parts(7_474_437, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_625 - .saturating_add(Weight::from_parts(4_996_146, 0).saturating_mul(c.into())) - } - fn as_derivative() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_612_000 picoseconds. - Weight::from_parts(4_774_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_744_000 picoseconds. - Weight::from_parts(10_889_913, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_281 - .saturating_add(Weight::from_parts(5_218_293, 0).saturating_mul(c.into())) - } - fn dispatch_as() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_673_000 picoseconds. - Weight::from_parts(8_980_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_744_000 picoseconds. - Weight::from_parts(7_801_721, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_395 - .saturating_add(Weight::from_parts(5_000_971, 0).saturating_mul(c.into())) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs deleted file mode 100644 index 57e50284147..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-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 -// --chain=collectives-polkadot-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/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_xcm`. -pub struct WeightInfo(PhantomData); -impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 25_050_000 picoseconds. - Weight::from_parts(26_382_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1489` - // Minimum execution time: 21_625_000 picoseconds. - Weight::from_parts(22_076_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 reserve_transfer_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn 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: 7_076_000 picoseconds. - Weight::from_parts(7_378_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_327_000 picoseconds. - Weight::from_parts(2_454_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `145` - // Estimated: `3610` - // Minimum execution time: 29_080_000 picoseconds. - Weight::from_parts(29_886_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(8)) - .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `363` - // Estimated: `3828` - // Minimum execution time: 30_746_000 picoseconds. - Weight::from_parts(31_631_000, 0) - .saturating_add(Weight::from_parts(0, 3828)) - .saturating_add(T::DbWeight::get().reads(7)) - .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_208_000 picoseconds. - Weight::from_parts(2_341_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: 16_239_000 picoseconds. - Weight::from_parts(16_881_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: 16_711_000 picoseconds. - Weight::from_parts(16_944_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_142_000 picoseconds. - Weight::from_parts(18_470_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `6152` - // Minimum execution time: 27_687_000 picoseconds. - Weight::from_parts(28_250_000, 0) - .saturating_add(Weight::from_parts(0, 6152)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) - /// 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_675_000 picoseconds. - Weight::from_parts(9_992_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: 16_597_000 picoseconds. - Weight::from_parts(17_248_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `11105` - // Minimum execution time: 34_649_000 picoseconds. - Weight::from_parts(35_475_000, 0) - .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) - /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `1588` - // Minimum execution time: 4_619_000 picoseconds. - Weight::from_parts(4_756_000, 0) - .saturating_add(Weight::from_parts(0, 1588)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `PolkadotXcm::Queries` (r:1 w:1) - /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn take_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `7740` - // Estimated: `11205` - // Minimum execution time: 26_721_000 picoseconds. - Weight::from_parts(27_412_000, 0) - .saturating_add(Weight::from_parts(0, 11205)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs deleted file mode 100644 index 25679703831..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs deleted file mode 100644 index 3dd817aa6f1..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,63 +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. - -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 { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * 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 sane() { - // 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/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs deleted file mode 100644 index 71845650bd6..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ /dev/null @@ -1,331 +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 super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, Fellows, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, -}; -use frame_support::{ - match_types, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, - weights::Weight, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, - 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); - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = - 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 -/// 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, -); - -/// 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`. - (), ->; - -/// 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! { - /// 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); - /// A temporary weight value for each XCM instruction. - /// NOTE: This should be removed after we account for PoV weights. - pub const TempFixedXcmWeight: Weight = Weight::from_parts(1_000_000_000, 0); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -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(_) } - }; -} - -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::System( - frame_system::Call::set_heap_pages { .. } | - frame_system::Call::set_code { .. } | - frame_system::Call::set_code_without_checks { .. } | - frame_system::Call::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::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Alliance( - // `init_members` accepts unbounded vecs as arguments, - // but the call can be initiated only by root origin. - pallet_alliance::Call::init_members { .. } | - pallet_alliance::Call::vote { .. } | - pallet_alliance::Call::disband { .. } | - pallet_alliance::Call::set_rule { .. } | - pallet_alliance::Call::announce { .. } | - pallet_alliance::Call::remove_announcement { .. } | - pallet_alliance::Call::join_alliance { .. } | - pallet_alliance::Call::nominate_ally { .. } | - pallet_alliance::Call::elevate_ally { .. } | - pallet_alliance::Call::give_retirement_notice { .. } | - pallet_alliance::Call::retire { .. } | - pallet_alliance::Call::kick_member { .. } | - pallet_alliance::Call::close { .. } | - pallet_alliance::Call::abdicate_fellow_status { .. }, - ) | RuntimeCall::AllianceMotion( - pallet_collective::Call::vote { .. } | - pallet_collective::Call::disapprove_proposal { .. } | - pallet_collective::Call::close { .. }, - ) | RuntimeCall::FellowshipCollective( - pallet_ranked_collective::Call::add_member { .. } | - pallet_ranked_collective::Call::promote_member { .. } | - pallet_ranked_collective::Call::demote_member { .. } | - pallet_ranked_collective::Call::remove_member { .. }, - ) | RuntimeCall::FellowshipCore( - pallet_core_fellowship::Call::bump { .. } | - pallet_core_fellowship::Call::set_params { .. } | - pallet_core_fellowship::Call::set_active { .. } | - pallet_core_fellowship::Call::approve { .. } | - pallet_core_fellowship::Call::induct { .. } | - pallet_core_fellowship::Call::promote { .. } | - pallet_core_fellowship::Call::offboard { .. } | - pallet_core_fellowship::Call::submit_evidence { .. } | - pallet_core_fellowship::Call::import { .. }, - ) - ) - } -} - -pub type Barrier = TrailingSetTopicAsId< - DenyThenTry< - DenyReserveTransferToRelayChain, - ( - // Allow local users to buy weight credit. - 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 and its pluralities (i.e. governance bodies) get free execution. - AllowExplicitUnpaidExecutionFrom, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -/// 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; - type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - // Collectives does not recognize a reserve location for any asset. Users must teleport DOT - // where allowed (e.g. with the Relay Chain). - type IsReserve = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = - UsingComponents>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - 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; - -pub type PriceForParentDelivery = - ExponentialPrice; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -/// Type to convert the Fellows origin to a Plurality `MultiLocation` value. -pub type FellowsToPlurality = OriginToPluralityVoice; - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - // We only allow the Fellows to send messages. - 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 are allowed. - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml deleted file mode 100644 index 7f5feb1c880..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ /dev/null @@ -1,138 +0,0 @@ -[package] -name = "glutton-runtime" -version = "1.0.0" -description = "Glutton parachain runtime." -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } - -# 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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false} -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true} -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true} -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} -pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} -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} -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} - -# 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} - -# Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } -cumulus-pallet-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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } - -[features] -default = [ "std" ] -runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-glutton/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] -std = [ - "codec/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", - "frame-executive/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime?/std", - "pallet-aura/std", - "pallet-glutton/std", - "pallet-message-queue/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "parachain-info/std", - "parachains-common/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", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] -try-runtime = [ - "cumulus-pallet-aura-ext/try-runtime", - "cumulus-pallet-parachain-system/try-runtime", - "cumulus-pallet-xcm/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-aura/try-runtime", - "pallet-glutton/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-sudo/try-runtime", - "pallet-timestamp/try-runtime", - "parachain-info/try-runtime", - "sp-runtime/try-runtime", -] - -experimental = [ "pallet-aura/experimental" ] - -# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs deleted file mode 100644 index 1580e6f07be..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/build.rs +++ /dev/null @@ -1,24 +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 substrate_wasm_builder::WasmBuilder; - -fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs deleted file mode 100644 index ef0734df25f..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ /dev/null @@ -1,528 +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. - -//! # Glutton Runtime -//! -//! The purpose of the Glutton parachain is to do stress testing on the Kusama -//! network. -//! -//! There may be multiple instances of the Glutton parachain deployed and -//! connected to Kusama. -//! -//! These parachains are not holding any real value. Their purpose is to stress -//! test the network. -//! -//! ### Governance -//! -//! Glutton defers its governance (namely, its `Root` origin), to its Relay -//! Chain parent, Kusama. -//! -//! ### XCM -//! -//! Since the main goal of Glutton is solely stress testing, the parachain will -//! only be able receive XCM messages from Kusama via DMP. This way the Glutton -//! parachains will be able to listen for upgrades that are coming from the -//! Relay chain. - -#![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")); - -pub mod weights; -pub mod xcm_config; - -use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use sp_api::impl_runtime_apis; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use cumulus_primitives_core::AggregateMessageOrigin; -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, - }, - weights::{ - constants::{ - BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, - }, - IdentityFee, Weight, - }, - PalletId, StorageValue, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use parachains_common::{AccountId, Signature}; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; -pub use sp_runtime::{Perbill, Permill}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("glutton"), - impl_name: create_runtime_str!("glutton"), - authoring_version: 1, - spec_version: 1_004_000, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 1, - state_version: 1, -}; - -/// 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() } -} - -/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. -/// This is used to limit the maximal weight of a single extrinsic. -const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); -/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used -/// by Operational extrinsics. -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_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; - 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 = 2; -} - -impl frame_system::Config for Runtime { - 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 Version = Version; - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = RuntimeBlockWeights; - type BlockLength = RuntimeBlockLength; - type SS58Prefix = SS58Prefix; - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - // We do anything the parent chain tells us in this runtime. - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(2); - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -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 = (); - type SelfParaId = parachain_info::Pallet; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type OutboundXcmpMessageSource = (); - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = (); - type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; - type ConsensusHook = ConsensusHook; - type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; -} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(80) * - RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - type QueueChangeHandler = (); - type QueuePausedQuery = (); // No XCMP queue pallet deployed. - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; -} - -impl parachain_info::Config for Runtime {} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] - type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; - type WeightInfo = weights::pallet_timestamp::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 = ConstU64; -} - -impl pallet_glutton::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_glutton::WeightInfo; - type AdminOrigin = EnsureRoot; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type WeightInfo = (); -} - -construct_runtime! { - pub enum Runtime - { - System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, - ParachainSystem: cumulus_pallet_parachain_system::{ - Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, - } = 1, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 2, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, - - // DMP handler. - CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 10, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 11, - - // The main stage. - Glutton: pallet_glutton::{Pallet, Call, Storage, Event, Config} = 20, - - // Collator support - Aura: pallet_aura::{Pallet, Storage, Config} = 30, - AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 31, - - // Sudo. - Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, - } -} - -/// Index of a transaction in the chain. -pub type Nonce = u32; -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; -/// An index to a block. -pub type BlockNumber = u32; -/// 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 = ( - pallet_sudo::CheckOnlySudoAccount, - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, -); -/// 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, ->; - -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - define_benchmarks!( - [frame_system, SystemBench::] - [pallet_glutton, Glutton] - ); -} - -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 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 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, - ) -> 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 cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Nonce { - System::account_nonce(account) - } - } - - #[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; - - 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 frame_support::traits::WhitelistedStorageKeys; - let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - 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! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs deleted file mode 100644 index f787aa32701..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/cumulus_pallet_parachain_system.rs +++ /dev/null @@ -1,80 +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. - -//! Autogenerated weights for `cumulus_pallet_parachain_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// statemint-dev -// --pallet -// cumulus_pallet_parachain_system -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/statemint/src/weights -// --steps -// 50 -// --repeat -// 20 - -#![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 `cumulus_pallet_parachain_system`. -pub struct WeightInfo(PhantomData); -impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. - fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_660_000 picoseconds. - Weight::from_parts(1_720_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 28_418 - .saturating_add(Weight::from_parts(24_636_963, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs deleted file mode 100644 index cf7ef948fd6..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/frame_system.rs +++ /dev/null @@ -1,154 +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. - -//! 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("glutton-kusama-dev-1300")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=glutton-kusama-dev-1300 -// --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/glutton/glutton-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_717_000 picoseconds. - Weight::from_parts(1_782_325, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) - } - /// The range of component `b` is `[0, 3932160]`. - fn remark_with_event(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_089_000 picoseconds. - Weight::from_parts(6_353_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_788, 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_389_000 picoseconds. - Weight::from_parts(3_605_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: 97_701_839_000 picoseconds. - Weight::from_parts(100_104_315_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: 1_638_000 picoseconds. - Weight::from_parts(1_726_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_886 - .saturating_add(Weight::from_parts(809_561, 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: 1_569_000 picoseconds. - Weight::from_parts(1_690_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 963 - .saturating_add(Weight::from_parts(580_145, 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: `52 + p * (69 ±0)` - // Estimated: `46 + p * (70 ±0)` - // Minimum execution time: 3_039_000 picoseconds. - Weight::from_parts(3_090_000, 0) - .saturating_add(Weight::from_parts(0, 46)) - // Standard Error: 2_007 - .saturating_add(Weight::from_parts(1_269_045, 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/glutton/glutton-kusama/src/weights/mod.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs deleted file mode 100644 index 47f9d1ee105..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/mod.rs +++ /dev/null @@ -1,19 +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 mod cumulus_pallet_parachain_system; -pub mod pallet_glutton; -pub mod pallet_message_queue; -pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs deleted file mode 100644 index e1b0c5bf232..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_glutton.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_glutton` -//! -//! 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("glutton-kusama-dev-1300")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=glutton-kusama-dev-1300 -// --wasm-execution=compiled -// --pallet=pallet_glutton -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/glutton/glutton-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_glutton`. -pub struct WeightInfo(PhantomData); -impl pallet_glutton::WeightInfo for WeightInfo { - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 1000]`. - fn initialize_pallet_grow(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `87` - // Estimated: `1489` - // Minimum execution time: 8_925_000 picoseconds. - Weight::from_parts(9_186_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 3_091 - .saturating_add(Weight::from_parts(9_666_196, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - } - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 1000]`. - fn initialize_pallet_shrink(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `120` - // Estimated: `1489` - // Minimum execution time: 8_924_000 picoseconds. - Weight::from_parts(8_963_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 1_202 - .saturating_add(Weight::from_parts(1_139_080, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - } - /// The range of component `i` is `[0, 100000]`. - fn waste_ref_time_iter(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 708_000 picoseconds. - Weight::from_parts(1_698_031, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(106_500, 0).saturating_mul(i.into())) - } - /// Storage: `Glutton::TrashData` (r:5000 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 5000]`. - fn waste_proof_size_some(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `119115 + i * (1022 ±0)` - // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 698_000 picoseconds. - Weight::from_parts(970_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 4_022 - .saturating_add(Weight::from_parts(6_320_519, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) - } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:1737 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) - fn on_idle_high_proof_waste() -> Weight { - // Proof Size summary in bytes: - // Measured: `1900498` - // Estimated: `5239782` - // Minimum execution time: 100_079_897_000 picoseconds. - Weight::from_parts(100_515_306_000, 0) - .saturating_add(Weight::from_parts(0, 5239782)) - .saturating_add(T::DbWeight::get().reads(1739)) - } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:5 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) - fn on_idle_low_proof_waste() -> Weight { - // Proof Size summary in bytes: - // Measured: `9548` - // Estimated: `16070` - // Minimum execution time: 100_237_009_000 picoseconds. - Weight::from_parts(100_472_213_000, 0) - .saturating_add(Weight::from_parts(0, 16070)) - .saturating_add(T::DbWeight::get().reads(7)) - } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn empty_on_idle() -> Weight { - // Proof Size summary in bytes: - // Measured: `87` - // Estimated: `1493` - // Minimum execution time: 5_120_000 picoseconds. - Weight::from_parts(5_262_000, 0) - .saturating_add(Weight::from_parts(0, 1493)) - .saturating_add(T::DbWeight::get().reads(2)) - } - /// Storage: `Glutton::Compute` (r:0 w:1) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set_compute() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_947_000 picoseconds. - Weight::from_parts(6_171_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Glutton::Storage` (r:0 w:1) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - fn set_storage() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_964_000 picoseconds. - Weight::from_parts(6_166_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs deleted file mode 100644 index a9f0cb07cfe..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,179 +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. - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --chain -// westmint-dev -// --pallet -// pallet_message_queue -// --extrinsic -// * -// --execution -// wasm -// --wasm-execution -// compiled -// --output -// parachains/runtimes/assets/westmint/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 12_192_000 picoseconds. - Weight::from_parts(12_192_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 10_447_000 picoseconds. - Weight::from_parts(10_447_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3517` - // Minimum execution time: 4_851_000 picoseconds. - Weight::from_parts(4_851_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_342_000 picoseconds. - Weight::from_parts(6_342_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `72` - // Estimated: `69050` - // Minimum execution time: 6_199_000 picoseconds. - Weight::from_parts(6_199_000, 0) - .saturating_add(Weight::from_parts(0, 69050)) - .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: 58_612_000 picoseconds. - Weight::from_parts(58_612_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 7_296_000 picoseconds. - Weight::from_parts(7_296_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 48_345_000 picoseconds. - Weight::from_parts(48_345_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 56_441_000 picoseconds. - Weight::from_parts(56_441_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 70_858_000 picoseconds. - Weight::from_parts(70_858_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs deleted file mode 100644 index 8edae065f1b..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,75 +0,0 @@ -// 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_timestamp` -//! -//! 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-kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot-parachain -// benchmark -// pallet -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-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: `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: `86` - // Estimated: `1493` - // 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: `57` - // Estimated: `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/glutton/glutton-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs deleted file mode 100644 index fb7b78b79d2..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/xcm_config.rs +++ /dev/null @@ -1,92 +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 super::{ - AccountId, AllPalletsWithSystem, ParachainInfo, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, -}; -use frame_support::{ - match_types, parameter_types, - traits::{Everything, Nothing}, - weights::Weight, -}; -use xcm::latest::prelude::*; -use xcm_builder::{ - AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, ParentAsSuperuser, ParentIsPreset, - SovereignSignedViaLocation, -}; - -parameter_types! { - pub const KusamaLocation: MultiLocation = MultiLocation::parent(); - pub const KusamaNetwork: Option = Some(NetworkId::Kusama); - pub UniversalLocation: InteriorMultiLocation = X1(Parachain(ParachainInfo::parachain_id().into())); -} - -/// 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 -/// bias 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, RuntimeOrigin>, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, -); - -match_types! { - pub type JustTheParent: impl Contains = { MultiLocation { parents:1, interior: Here } }; -} - -parameter_types! { - // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; -} - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = (); // sending XCM not supported - type AssetTransactor = (); // balances not supported - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = (); // balances not supported - type IsTeleporter = (); // balances not supported - type UniversalLocation = UniversalLocation; - type Barrier = AllowExplicitUnpaidExecutionFrom; - type Weigher = FixedWeightBounds; // balances not supported - type Trader = (); // balances not supported - type ResponseHandler = (); // Don't handle responses for now. - type AssetTrap = (); // don't trap for now - type AssetClaims = (); // don't claim for now - type SubscriptionService = (); // don't handle subscriptions for now - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = xcm_executor::XcmExecutor; -} diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index e23a7aeb22b..a7fdfb5d6c9 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -25,18 +25,12 @@ serde_json = "1.0.108" rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } shell-runtime = { path = "../parachains/runtimes/starters/shell" } glutton-westend-runtime = { path = "../parachains/runtimes/glutton/glutton-westend" } -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" } collectives-westend-runtime = { path = "../parachains/runtimes/collectives/collectives-westend" } contracts-rococo-runtime = { path = "../parachains/runtimes/contracts/contracts-rococo" } bridge-hub-rococo-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-rococo" } -bridge-hub-kusama-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-kusama" } -bridge-hub-polkadot-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-polkadot" } bridge-hub-westend-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-westend" } penpal-runtime = { path = "../parachains/runtimes/testing/penpal" } jsonrpsee = { version = "0.16.2", features = ["server"] } @@ -121,22 +115,16 @@ wait-timeout = "0.2" [features] 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", "bridge-hub-rococo-runtime/runtime-benchmarks", "bridge-hub-westend-runtime/runtime-benchmarks", - "collectives-polkadot-runtime/runtime-benchmarks", "collectives-westend-runtime/runtime-benchmarks", "contracts-rococo-runtime/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", - "glutton-runtime/runtime-benchmarks", "glutton-westend-runtime/runtime-benchmarks", "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", @@ -148,20 +136,14 @@ runtime-benchmarks = [ "sp-runtime/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", "bridge-hub-rococo-runtime/try-runtime", "bridge-hub-westend-runtime/try-runtime", - "collectives-polkadot-runtime/try-runtime", "collectives-westend-runtime/try-runtime", "contracts-rococo-runtime/try-runtime", "frame-support/try-runtime", "frame-try-runtime/try-runtime", - "glutton-runtime/try-runtime", "glutton-westend-runtime/try-runtime", "pallet-transaction-payment/try-runtime", "penpal-runtime/try-runtime", diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 2988d6af0d1..f889e05a166 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -20,35 +20,15 @@ use crate::chain_spec::{ }; use cumulus_primitives_core::ParaId; use hex_literal::hex; -use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance as AssetHubBalance}; +use parachains_common::{AccountId, AuraId, Balance as AssetHubBalance}; use sc_service::ChainType; use sp_core::{crypto::UncheckedInto, sr25519}; -const ASSET_HUB_POLKADOT_ED: AssetHubBalance = - parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; -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. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn asset_hub_polkadot_session_keys( - keys: AssetHubPolkadotAuraId, -) -> asset_hub_polkadot_runtime::SessionKeys { - asset_hub_polkadot_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_kusama_session_keys(keys: AuraId) -> asset_hub_kusama_runtime::SessionKeys { - 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). @@ -63,341 +43,6 @@ pub fn asset_hub_westend_session_keys(keys: AuraId) -> asset_hub_westend_runtime asset_hub_westend_runtime::SessionKeys { aura: keys } } -pub fn asset_hub_polkadot_development_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - asset_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "polkadot-dev".into(), para_id: 1000 }, - ) - .with_name("Polkadot Asset Hub Development") - .with_id("asset-hub-polkadot-dev") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_polkadot_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"), - ], - 1000.into(), - )) - .with_properties(properties) - .build() -} - -pub fn asset_hub_polkadot_local_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - asset_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 }, - ) - .with_name("Polkadot Asset Hub Local") - .with_id("asset-hub-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_polkadot_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"), - ], - 1000.into(), - )) - .with_boot_nodes(Vec::new()) - .with_properties(properties) - .build() -} - -// Not used for syncing, but just to determine the genesis values set for the upgrade from shell. -pub fn asset_hub_polkadot_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - asset_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "polkadot".into(), para_id: 1000 }, - ) - .with_name("Polkadot Asset Hub") - .with_id("asset-hub-polkadot") - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(asset_hub_polkadot_genesis( - // initial collators. - vec![ - ( - hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421").into(), - hex!("4c3d674d2a01060f0ded218e5dcc6f90c1726f43df79885eb3e22d97a20d5421") - .unchecked_into(), - ), - ( - hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811").into(), - hex!("c7d7d38d16bc23c6321152c50306212dc22c0efc04a2e52b5cccfc31ab3d7811") - .unchecked_into(), - ), - ( - hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762").into(), - hex!("c5c07ba203d7375675f5c1ebe70f0a5bb729ae57b48bcc877fcc2ab21309b762") - .unchecked_into(), - ), - ( - hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3").into(), - hex!("0b2d0013fb974794bd7aa452465b567d48ef70373fe231a637c1fb7c547e85b3") - .unchecked_into(), - ), - ], - vec![], - 1000u32.into(), - )) - .with_boot_nodes(vec![ - "/ip4/34.65.251.121/tcp/30334/p2p/12D3KooWG3GrM6XKMM4gp3cvemdwUvu96ziYoJmqmetLZBXE8bSa" - .parse() - .unwrap(), - "/ip4/34.65.35.228/tcp/30334/p2p/12D3KooWMRyTLrCEPcAQD6c4EnudL3vVzg9zji3whvsMYPUYevpq" - .parse() - .unwrap(), - "/ip4/34.83.247.146/tcp/30334/p2p/12D3KooWE4jFh5FpJDkWVZhnWtFnbSqRhdjvC7Dp9b8b3FTuubQC" - .parse() - .unwrap(), - "/ip4/104.199.117.230/tcp/30334/p2p/12D3KooWG9R8pVXKumVo2rdkeVD4j5PVhRTqmYgLHY3a4yPYgLqM" - .parse() - .unwrap(), - ]) - .with_properties(properties) - .build() -} - -fn asset_hub_polkadot_genesis( - invulnerables: Vec<(AccountId, AssetHubPolkadotAuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, ASSET_HUB_POLKADOT_ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": ASSET_HUB_POLKADOT_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_polkadot_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - } - }) -} - -pub fn asset_hub_kusama_development_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama-dev".into(), para_id: 1000 }, - ) - .with_name("Kusama Asset Hub Development") - .with_id("asset-hub-kusama-dev") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_kusama_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"), - ], - 1000.into(), - )) - .with_properties(properties) - .build() -} - -pub fn asset_hub_kusama_local_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1000 }, - ) - .with_name("Kusama Asset Hub Local") - .with_id("asset-hub-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_kusama_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"), - ], - 1000.into(), - )) - .with_properties(properties) - .build() -} - -pub fn asset_hub_kusama_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama".into(), para_id: 1000 }, - ) - .with_name("Kusama Asset Hub") - .with_id("asset-hub-kusama") - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(asset_hub_kusama_genesis( - // initial collators. - vec![ - ( - hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730").into(), - hex!("50673d59020488a4ffc9d8c6de3062a65977046e6990915617f85fef6d349730") - .unchecked_into(), - ), - ( - hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a").into(), - hex!("fe8102dbc244e7ea2babd9f53236d67403b046154370da5c3ea99def0bd0747a") - .unchecked_into(), - ), - ( - hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a").into(), - hex!("38144b5398e5d0da5ec936a3af23f5a96e782f676ab19d45f29075ee92eca76a") - .unchecked_into(), - ), - ( - hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415").into(), - hex!("3253947640e309120ae70fa458dcacb915e2ddd78f930f52bd3679ec63fc4415") - .unchecked_into(), - ), - ], - Vec::new(), - 1000.into(), - )) - .with_properties(properties) - .build() -} - -fn asset_hub_kusama_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, ASSET_HUB_KUSAMA_ED * 524_288)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": ASSET_HUB_KUSAMA_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_kusama_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }) -} - pub fn asset_hub_westend_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 377ceb20e1e..8dab692c1cd 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -24,21 +24,14 @@ use std::str::FromStr; /// Collects all supported BridgeHub configurations #[derive(Debug, PartialEq)] pub enum BridgeHubRuntimeType { + Kusama, + Polkadot, + Rococo, RococoLocal, // used by benchmarks RococoDevelopment, - Kusama, - KusamaLocal, - // used by benchmarks - KusamaDevelopment, - - Polkadot, - PolkadotLocal, - // used by benchmarks - PolkadotDevelopment, - Westend, WestendLocal, // used by benchmarks @@ -51,12 +44,7 @@ impl FromStr for BridgeHubRuntimeType { fn from_str(value: &str) -> Result { match value { polkadot::BRIDGE_HUB_POLKADOT => Ok(BridgeHubRuntimeType::Polkadot), - polkadot::BRIDGE_HUB_POLKADOT_LOCAL => Ok(BridgeHubRuntimeType::PolkadotLocal), - polkadot::BRIDGE_HUB_POLKADOT_DEVELOPMENT => - Ok(BridgeHubRuntimeType::PolkadotDevelopment), kusama::BRIDGE_HUB_KUSAMA => Ok(BridgeHubRuntimeType::Kusama), - kusama::BRIDGE_HUB_KUSAMA_LOCAL => Ok(BridgeHubRuntimeType::KusamaLocal), - kusama::BRIDGE_HUB_KUSAMA_DEVELOPMENT => Ok(BridgeHubRuntimeType::KusamaDevelopment), westend::BRIDGE_HUB_WESTEND => Ok(BridgeHubRuntimeType::Westend), westend::BRIDGE_HUB_WESTEND_LOCAL => Ok(BridgeHubRuntimeType::WestendLocal), westend::BRIDGE_HUB_WESTEND_DEVELOPMENT => Ok(BridgeHubRuntimeType::WestendDevelopment), @@ -76,33 +64,9 @@ impl BridgeHubRuntimeType { BridgeHubRuntimeType::Polkadot => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-polkadot.json")[..], )?)), - BridgeHubRuntimeType::PolkadotLocal => Ok(Box::new(polkadot::local_config( - polkadot::BRIDGE_HUB_POLKADOT_LOCAL, - "Polkadot BridgeHub Local", - "polkadot-local", - ParaId::new(1002), - ))), - BridgeHubRuntimeType::PolkadotDevelopment => Ok(Box::new(polkadot::local_config( - polkadot::BRIDGE_HUB_POLKADOT_DEVELOPMENT, - "Polkadot BridgeHub Development", - "polkadot-dev", - ParaId::new(1002), - ))), BridgeHubRuntimeType::Kusama => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-kusama.json")[..], )?)), - BridgeHubRuntimeType::KusamaLocal => Ok(Box::new(kusama::local_config( - kusama::BRIDGE_HUB_KUSAMA_LOCAL, - "Kusama BridgeHub Local", - "kusama-local", - ParaId::new(1003), - ))), - BridgeHubRuntimeType::KusamaDevelopment => Ok(Box::new(kusama::local_config( - kusama::BRIDGE_HUB_KUSAMA_DEVELOPMENT, - "Kusama BridgeHub Development", - "kusama-dev", - ParaId::new(1003), - ))), BridgeHubRuntimeType::Westend => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-westend.json")[..], )?)), @@ -273,109 +237,7 @@ pub mod rococo { /// Sub-module for Kusama setup pub mod kusama { - use super::{BridgeHubBalance, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, - }; - use parachains_common::{AccountId, AuraId}; - use sc_chain_spec::ChainType; - use sp_core::sr25519; - pub(crate) const BRIDGE_HUB_KUSAMA: &str = "bridge-hub-kusama"; - pub(crate) const BRIDGE_HUB_KUSAMA_LOCAL: &str = "bridge-hub-kusama-local"; - pub(crate) const BRIDGE_HUB_KUSAMA_DEVELOPMENT: &str = "bridge-hub-kusama-dev"; - const BRIDGE_HUB_KUSAMA_ED: BridgeHubBalance = - parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; - - pub fn local_config( - id: &str, - chain_name: &str, - relay_chain: &str, - para_id: ParaId, - ) -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - bridge_hub_kusama_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, - ) - .with_name(chain_name) - .with_id(super::ensure_id(id).expect("invalid id")) - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - para_id, - )) - .with_properties(properties) - .build() - } - - fn genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, - ) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, BRIDGE_HUB_KUSAMA_ED * 524_288)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": BRIDGE_HUB_KUSAMA_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - } - }) - } } /// Sub-module for Westend setup. @@ -491,107 +353,5 @@ pub mod westend { /// Sub-module for Polkadot setup pub mod polkadot { - use super::{BridgeHubBalance, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, - }; - use parachains_common::{AccountId, AuraId}; - use sc_chain_spec::ChainType; - use sp_core::sr25519; - pub(crate) const BRIDGE_HUB_POLKADOT: &str = "bridge-hub-polkadot"; - pub(crate) const BRIDGE_HUB_POLKADOT_LOCAL: &str = "bridge-hub-polkadot-local"; - pub(crate) const BRIDGE_HUB_POLKADOT_DEVELOPMENT: &str = "bridge-hub-polkadot-dev"; - const BRIDGE_HUB_POLKADOT_ED: BridgeHubBalance = - parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; - - pub fn local_config( - id: &str, - chain_name: &str, - relay_chain: &str, - para_id: ParaId, - ) -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - bridge_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() }, - ) - .with_name(chain_name) - .with_id(super::ensure_id(id).expect("invalid id")) - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - para_id, - )) - .with_properties(properties) - .build() - } - - fn genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, - ) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, BRIDGE_HUB_POLKADOT_ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": BRIDGE_HUB_POLKADOT_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - } - }) - } } diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index ac75a40ebde..dd67bf975f7 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -23,143 +23,9 @@ use parachains_common::{AccountId, AuraId, Balance as CollectivesBalance}; use sc_service::ChainType; use sp_core::sr25519; -const COLLECTIVES_POLKADOT_ED: CollectivesBalance = - parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; const COLLECTIVES_WESTEND_ED: CollectivesBalance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; -/// 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 collectives_polkadot_session_keys( - keys: AuraId, -) -> collectives_polkadot_runtime::SessionKeys { - collectives_polkadot_runtime::SessionKeys { aura: keys } -} - -pub fn collectives_polkadot_development_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - collectives_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "polkadot-dev".into(), para_id: 1002 }, - ) - .with_name("Polkadot Collectives Development") - .with_id("collectives_polkadot_dev") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(collectives_polkadot_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"), - ], - // 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever - // be a collective para on Kusama. - 1002.into(), - )) - .with_boot_nodes(Vec::new()) - .with_properties(properties) - .build() -} - -/// Collectives Polkadot Local Config. -pub fn collectives_polkadot_local_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - GenericChainSpec::builder( - collectives_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1002 }, - ) - .with_name("Polkadot Collectives Local") - .with_id("collectives_polkadot_local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(collectives_polkadot_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"), - ], - 1002.into(), - )) - .with_boot_nodes(Vec::new()) - .with_properties(properties) - .build() -} - -fn collectives_polkadot_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, COLLECTIVES_POLKADOT_ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": COLLECTIVES_POLKADOT_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - collectives_polkadot_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }) -} - /// 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). diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 8eced8d8f81..77a4123b13e 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -22,62 +22,6 @@ use sp_core::sr25519; use super::get_collator_keys_from_seed; -pub fn glutton_development_config(para_id: ParaId) -> GenericChainSpec { - GenericChainSpec::builder( - glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama-dev".into(), para_id: para_id.into() }, - ) - .with_name("Glutton Development") - .with_id("glutton_dev") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(glutton_genesis( - para_id, - vec![get_collator_keys_from_seed::("Alice")], - )) - .build() -} - -pub fn glutton_local_config(para_id: ParaId) -> GenericChainSpec { - GenericChainSpec::builder( - glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama-local".into(), para_id: para_id.into() }, - ) - .with_name("Glutton Local") - .with_id("glutton_local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(glutton_genesis( - para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], - )) - .build() -} - -pub fn glutton_config(para_id: ParaId) -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - - GenericChainSpec::builder( - glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "kusama".into(), para_id: para_id.into() }, - ) - .with_name(format!("Glutton {}", para_id).as_str()) - .with_id(format!("glutton-kusama-{}", para_id).as_str()) - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(glutton_genesis( - para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], - )) - .with_protocol_id(format!("glutton-kusama-{}", para_id).as_str()) - .with_properties(properties) - .build() -} - fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { serde_json::json!( { "parachainInfo": { diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index f966a5db8f3..98dcc2fea4a 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -144,27 +144,11 @@ fn load_spec(id: &str) -> std::result::Result, String> { "seedling" => Box::new(chain_spec::seedling::get_seedling_chain_spec()), // -- Asset Hub Polkadot - "asset-hub-polkadot-dev" | "statemint-dev" => - Box::new(chain_spec::asset_hubs::asset_hub_polkadot_development_config()), - "asset-hub-polkadot-local" | "statemint-local" => - Box::new(chain_spec::asset_hubs::asset_hub_polkadot_local_config()), - // the chain spec as used for generating the upgrade genesis values - "asset-hub-polkadot-genesis" | "statemint-genesis" => - Box::new(chain_spec::asset_hubs::asset_hub_polkadot_config()), - // the shell-based chain spec as used for syncing "asset-hub-polkadot" | "statemint" => Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../chain-specs/asset-hub-polkadot.json")[..], )?), // -- Asset Hub Kusama - "asset-hub-kusama-dev" | "statemine-dev" => - Box::new(chain_spec::asset_hubs::asset_hub_kusama_development_config()), - "asset-hub-kusama-local" | "statemine-local" => - Box::new(chain_spec::asset_hubs::asset_hub_kusama_local_config()), - // the chain spec as used for generating the upgrade genesis values - "asset-hub-kusama-genesis" | "statemine-genesis" => - Box::new(chain_spec::asset_hubs::asset_hub_kusama_config()), - // the shell-based chain spec as used for syncing "asset-hub-kusama" | "statemine" => Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], )?), @@ -195,13 +179,11 @@ fn load_spec(id: &str) -> std::result::Result, String> { )?), // -- Polkadot Collectives - "collectives-polkadot-dev" => - Box::new(chain_spec::collectives::collectives_polkadot_development_config()), - "collectives-polkadot-local" => - Box::new(chain_spec::collectives::collectives_polkadot_local_config()), "collectives-polkadot" => Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../chain-specs/collectives-polkadot.json")[..], )?), + + // -- Westend Collectives "collectives-westend-dev" => Box::new(chain_spec::collectives::collectives_westend_development_config()), "collectives-westend-local" => @@ -229,14 +211,14 @@ fn load_spec(id: &str) -> std::result::Result, String> { .expect("invalid value") .load_config()?, - // -- Penpall - "penpal-kusama" => Box::new(chain_spec::penpal::get_penpal_chain_spec( + // -- Penpal + "penpal-rococo" => Box::new(chain_spec::penpal::get_penpal_chain_spec( para_id.expect("Must specify parachain id"), - "kusama-local", + "rococo-local", )), - "penpal-polkadot" => Box::new(chain_spec::penpal::get_penpal_chain_spec( + "penpal-westend" => Box::new(chain_spec::penpal::get_penpal_chain_spec( para_id.expect("Must specify parachain id"), - "polkadot-local", + "westend-local", )), // -- Glutton Westend @@ -251,18 +233,6 @@ fn load_spec(id: &str) -> std::result::Result, String> { para_id.expect("Must specify parachain id"), )), - // -- Glutton - "glutton-kusama-dev" => Box::new(chain_spec::glutton::glutton_development_config( - para_id.expect("Must specify parachain id"), - )), - "glutton-kusama-local" => Box::new(chain_spec::glutton::glutton_local_config( - para_id.expect("Must specify parachain id"), - )), - // the chain spec as used for generating the upgrade genesis values - "glutton-kusama-genesis" => Box::new(chain_spec::glutton::glutton_config( - para_id.expect("Must specify parachain id"), - )), - // -- Fallback (generic chainspec) "" => { log::warn!("No ChainSpec.id specified, so using default one, based on rococo-parachain runtime"); @@ -760,18 +730,14 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into), Runtime::BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { -chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotDevelopment => + chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot => crate::service::start_generic_aura_node::< RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), - chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaDevelopment => + chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama => crate::service::start_generic_aura_node::< RuntimeApi, AuraId, @@ -1052,12 +1018,6 @@ mod tests { ); assert_eq!(Runtime::Default, path.runtime()); - let path = store_configuration( - &temp_dir, - Box::new(crate::chain_spec::asset_hubs::asset_hub_kusama_local_config()), - ); - assert_eq!(Runtime::AssetHubKusama, path.runtime()); - let path = store_configuration( &temp_dir, Box::new(crate::chain_spec::contracts::contracts_rococo_local_config()), diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index b0fca518201..6280d86e9f9 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -96,36 +96,6 @@ impl sc_executor::NativeExecutionDispatch for ShellRuntimeExecutor { } } -/// Native Asset Hub Polkadot (Statemint) executor instance. -pub struct AssetHubPolkadotRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for AssetHubPolkadotRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - asset_hub_polkadot_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - asset_hub_polkadot_runtime::native_version() - } -} - -/// Native Asset Hub Kusama (Statemine) executor instance. -pub struct AssetHubKusamaExecutor; - -impl sc_executor::NativeExecutionDispatch for AssetHubKusamaExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - asset_hub_kusama_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - asset_hub_kusama_runtime::native_version() - } -} - /// Native Asset Hub Westend (Westmint) executor instance. pub struct AssetHubWestendExecutor; @@ -141,21 +111,6 @@ impl sc_executor::NativeExecutionDispatch for AssetHubWestendExecutor { } } -/// Native Polkadot Collectives executor instance. -pub struct CollectivesPolkadotRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for CollectivesPolkadotRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - collectives_polkadot_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - collectives_polkadot_runtime::native_version() - } -} - /// Native Westend Collectives executor instance. pub struct CollectivesWestendRuntimeExecutor; @@ -171,36 +126,6 @@ impl sc_executor::NativeExecutionDispatch for CollectivesWestendRuntimeExecutor } } -/// Native BridgeHubPolkadot executor instance. -pub struct BridgeHubPolkadotRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for BridgeHubPolkadotRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - bridge_hub_polkadot_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - bridge_hub_polkadot_runtime::native_version() - } -} - -/// Native BridgeHubKusama executor instance. -pub struct BridgeHubKusamaRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for BridgeHubKusamaRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - bridge_hub_kusama_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - bridge_hub_kusama_runtime::native_version() - } -} - /// Native BridgeHubRococo executor instance. pub struct BridgeHubRococoRuntimeExecutor; @@ -246,21 +171,6 @@ impl sc_executor::NativeExecutionDispatch for GluttonWestendRuntimeExecutor { } } -/// Native Glutton executor instance. -pub struct GluttonRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for GluttonRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - shell_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - shell_runtime::native_version() - } -} - /// Starts a `ServiceBuilder` for a full service. /// /// Use this macro if you don't actually need the full service, but just the builder in order to diff --git a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs b/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs index c2850b64e45..c554b5b3d6b 100644 --- a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs +++ b/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs @@ -24,7 +24,7 @@ use std::{ use tempfile::tempdir; /// The runtimes that this command supports. -static RUNTIMES: [&str; 3] = ["asset-hub-westend", "asset-hub-kusama", "asset-hub-polkadot"]; +static RUNTIMES: [&str; 1] = ["asset-hub-westend"]; /// The `benchmark storage` command works for the dev runtimes. #[test] diff --git a/cumulus/scripts/benchmarks.sh b/cumulus/scripts/benchmarks.sh index 7da18d9440e..58b8419bf4a 100755 --- a/cumulus/scripts/benchmarks.sh +++ b/cumulus/scripts/benchmarks.sh @@ -6,16 +6,7 @@ repeat=${3:-20} __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -${__dir}/benchmarks-ci.sh collectives collectives-polkadot target/$target $steps $repeat ${__dir}/benchmarks-ci.sh collectives collectives-westend target/$target $steps $repeat - -${__dir}/benchmarks-ci.sh assets asset-hub-kusama target/$target $steps $repeat -${__dir}/benchmarks-ci.sh assets asset-hub-polkadot target/$target $steps $repeat ${__dir}/benchmarks-ci.sh assets asset-hub-westend target/$target $steps $repeat - -${__dir}/benchmarks-ci.sh bridge-hubs bridge-hub-polkadot target/$target $steps $repeat -${__dir}/benchmarks-ci.sh bridge-hubs bridge-hub-kusama target/$target $steps $repeat ${__dir}/benchmarks-ci.sh bridge-hubs bridge-hub-rococo target/$target $steps $repeat - -${__dir}/benchmarks-ci.sh glutton glutton-kusama target/$target $steps $repeat ${__dir}/benchmarks-ci.sh glutton glutton-westend target/$target $steps $repeat diff --git a/cumulus/scripts/create_bridge_hub_kusama_spec.sh b/cumulus/scripts/create_bridge_hub_kusama_spec.sh deleted file mode 100755 index 813921b079a..00000000000 --- a/cumulus/scripts/create_bridge_hub_kusama_spec.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash - -usage() { - echo Usage: - echo "$1 " - echo "$2 " - echo "e.g.: ./scripts/create_bridge_hub_kusama_spec.sh ./target/release/wbuild/bridge-hub-kusama-runtime/bridge_hub_kusama_runtime.compact.compressed.wasm 1002" - exit 1 -} - -if [ -z "$1" ]; then - usage -fi - -if [ -z "$2" ]; then - usage -fi - -set -e - -rt_path=$1 -para_id=$2 - -echo "Generating chain spec for runtime: $rt_path and para_id: $para_id" - -binary="./target/release/polkadot-parachain" - -# build the chain spec we'll manipulate -$binary build-spec --chain bridge-hub-kusama-dev > chain-spec-plain.json - -# convert runtime to hex -cat $rt_path | od -A n -v -t x1 | tr -d ' \n' > rt-hex.txt - -# replace the runtime in the spec with the given runtime and set some values to production -cat chain-spec-plain.json | jq --rawfile code rt-hex.txt '.genesis.runtime.system.code = ("0x" + $code)' \ - | jq '.name = "Kusama BridgeHub"' \ - | jq '.id = "bridge-hub-kusama"' \ - | jq '.chainType = "Live"' \ - | jq '.bootNodes = [ - "/dns/kusama-bridge-hub-collator-ew1-0.polkadot.io/tcp/30334/p2p/12D3KooWP2Gngt4tt2sz5BgDaAbMTxasPWk3V2Z99bQTmFcAorqa", - "/dns/kusama-bridge-hub-collator-ew1-1.polkadot.io/tcp/30334/p2p/12D3KooWMmL3FQuYmruBui1sbY4MwNmvicinrePi1Yq4QMRSYHoR", - "/dns/kusama-bridge-hub-collator-ue4-0.polkadot.io/tcp/30334/p2p/12D3KooWQpTocTck1tNBzMNTHJ3kSv4vzv8Yf9FpVkfGnungbez4", - "/dns/kusama-bridge-hub-collator-ue4-1.polkadot.io/tcp/30334/p2p/12D3KooWRgtJqKEaMi7hkU4VMiGhpHTJeL8N7JgL7d9gwooPv4eW", - - "/dns/kusama-bridge-hub-connect-ew1-0.polkadot.io/tcp/30334/p2p/12D3KooWPQQPivrqQ51kRTDc2R1mtqwKT4GGtk2rapkY4FrwHrEp", - "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/30334/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", - "/dns/kusama-bridge-hub-connect-ue4-0.polkadot.io/tcp/30334/p2p/12D3KooWMf1sVnJDTkKWtaThqvrgcSPLbfGXttSqbwhM2DJp9BUG", - "/dns/kusama-bridge-hub-connect-ue4-1.polkadot.io/tcp/30334/p2p/12D3KooWQaV7wMfNVKy2aMz4Lds3TTxgSDyZAUEnbAZMfD8rW3ow", - - "/dns/kusama-bridge-hub-connect-ew1-0.polkadot.io/tcp/443/wss/p2p/12D3KooWPQQPivrqQ51kRTDc2R1mtqwKT4GGtk2rapkY4FrwHrEp", - "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", - "/dns/kusama-bridge-hub-connect-ue4-0.polkadot.io/tcp/443/wss/p2p/12D3KooWMf1sVnJDTkKWtaThqvrgcSPLbfGXttSqbwhM2DJp9BUG", - "/dns/kusama-bridge-hub-connect-ue4-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQaV7wMfNVKy2aMz4Lds3TTxgSDyZAUEnbAZMfD8rW3ow" - - ]' \ - | jq '.relay_chain = "kusama"' \ - | jq --argjson para_id $para_id '.para_id = $para_id' \ - | jq --argjson para_id $para_id '.genesis.runtime.parachainInfo.parachainId = $para_id' \ - | jq '.genesis.runtime.balances.balances = []' \ - | jq '.genesis.runtime.collatorSelection.invulnerables = [ - "DQkekNBt8g6D7bPUEqhgfujADxzzfivr1qQZJkeGzAqnEzF", - "HbUc5qrLtKAZvasioiTSf1CunaN2SyEwvfsgMuYQjXA5sfk", - "JEe4NcVyuWFEwZe4WLfRtynDswyKgvLS8H8r4Wo9d3t61g1", - "FAe4DGhQHKTm35n5MgBFNBZvyEJcm7QAwgnVNQU8KXP2ixn" - ]' \ - | jq '.genesis.runtime.session.keys = [ - [ - "DQkekNBt8g6D7bPUEqhgfujADxzzfivr1qQZJkeGzAqnEzF", - "DQkekNBt8g6D7bPUEqhgfujADxzzfivr1qQZJkeGzAqnEzF", - { - "aura": "5E7AiV9ygGUcfdK3XVoJsew7fsu18uvKQHYhksE5PXDNfRL9" - } - ], - [ - "HbUc5qrLtKAZvasioiTSf1CunaN2SyEwvfsgMuYQjXA5sfk", - "HbUc5qrLtKAZvasioiTSf1CunaN2SyEwvfsgMuYQjXA5sfk", - { - "aura": "5CyXoMh8cA2MSk55JASpCfhCg44iSG5fBwmhvSfXUUS3uhPR" - } - ], - [ - "JEe4NcVyuWFEwZe4WLfRtynDswyKgvLS8H8r4Wo9d3t61g1", - "JEe4NcVyuWFEwZe4WLfRtynDswyKgvLS8H8r4Wo9d3t61g1", - { - "aura": "5Grj5pN52kKU61qK9qP5cf9ADuyowe2WVvYWxMNK1QqAM8qf" - } - ], - [ - "FAe4DGhQHKTm35n5MgBFNBZvyEJcm7QAwgnVNQU8KXP2ixn", - "FAe4DGhQHKTm35n5MgBFNBZvyEJcm7QAwgnVNQU8KXP2ixn", - { - "aura": "5EHTyftGjcHfe71VVuZqCeLbHNf4ptYzgdAMMyqpTNbs5Rrp" - } - ] - ]' \ - > edited-chain-spec-plain.json - -# build a raw spec -$binary build-spec --chain edited-chain-spec-plain.json --raw > chain-spec-raw.json -cp edited-chain-spec-plain.json bridge-hub-kusama-spec.json -cp chain-spec-raw.json ./parachains/chain-specs/bridge-hub-kusama.json -cp chain-spec-raw.json bridge-hub-kusama-spec-raw.json - -# build genesis data -$binary export-genesis-state --chain chain-spec-raw.json > bridge-hub-kusama-genesis-head-data - -# build genesis wasm -$binary export-genesis-wasm --chain chain-spec-raw.json > bridge-hub-kusama-wasm diff --git a/cumulus/scripts/create_bridge_hub_polkadot_spec.sh b/cumulus/scripts/create_bridge_hub_polkadot_spec.sh deleted file mode 100755 index 49bc9cee692..00000000000 --- a/cumulus/scripts/create_bridge_hub_polkadot_spec.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash - -usage() { - echo Usage: - echo "$1 " - echo "$2 " - echo "e.g.: ./scripts/create_bridge_hub_polkadot_spec.sh ./target/release/wbuild/bridge-hub-polkadot-runtime/bridge_hub_polkadot_runtime.compact.compressed.wasm 1002" - exit 1 -} - -if [ -z "$1" ]; then - usage -fi - -if [ -z "$2" ]; then - usage -fi - -set -e - -rt_path=$1 -para_id=$2 - -echo "Generating chain spec for runtime: $rt_path and para_id: $para_id" - -binary="./target/release/polkadot-parachain" - -# build the chain spec we'll manipulate -$binary build-spec --chain bridge-hub-polkadot-dev > chain-spec-plain.json - -# convert runtime to hex -cat $rt_path | od -A n -v -t x1 | tr -d ' \n' > rt-hex.txt - -# replace the runtime in the spec with the given runtime and set some values to production -cat chain-spec-plain.json | jq --rawfile code rt-hex.txt '.genesis.runtime.system.code = ("0x" + $code)' \ - | jq '.name = "Polkadot BridgeHub"' \ - | jq '.id = "bridge-hub-polkadot"' \ - | jq '.chainType = "Live"' \ - | jq '.bootNodes = [ - "/dns/polkadot-bridge-hub-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWAVQMhkXmc5ueSYasdsRWQbKus2YGZ6HDZUB4ViJMCxXy", - "/dns/polkadot-bridge-hub-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWG4ypDHLKGCv4BZ6PuaGUwQHKAH6p2D6arR2uQ1eiR1T3", - "/dns/polkadot-bridge-hub-connect-b-0.polkadot.io/tcp/30334/p2p/12D3KooWCwGKxjpJXnx1mwXKvaxGQm769EM3b6Pg5vbU33wbhsNw", - "/dns/polkadot-bridge-hub-connect-b-1.polkadot.io/tcp/30334/p2p/12D3KooWLiSEdhriJUPdZKFtAjZrQncxN2ssEoDKVrt5mGM4Qu4J", - - "/dns/polkadot-bridge-hub-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWAVQMhkXmc5ueSYasdsRWQbKus2YGZ6HDZUB4ViJMCxXy", - "/dns/polkadot-bridge-hub-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWG4ypDHLKGCv4BZ6PuaGUwQHKAH6p2D6arR2uQ1eiR1T3", - "/dns/polkadot-bridge-hub-connect-b-0.polkadot.io/tcp/443/wss/p2p/12D3KooWCwGKxjpJXnx1mwXKvaxGQm769EM3b6Pg5vbU33wbhsNw", - "/dns/polkadot-bridge-hub-connect-b-1.polkadot.io/tcp/443/wss/p2p/12D3KooWLiSEdhriJUPdZKFtAjZrQncxN2ssEoDKVrt5mGM4Qu4J" - ]' \ - | jq '.relay_chain = "polkadot"' \ - | jq --argjson para_id $para_id '.para_id = $para_id' \ - | jq --argjson para_id $para_id '.genesis.runtime.parachainInfo.parachainId = $para_id' \ - | jq '.genesis.runtime.balances.balances = []' \ - | jq '.genesis.runtime.collatorSelection.invulnerables = [ - "134AK3RiMA97Fx9dLj1CvuLJUa8Yo93EeLA1TkP6CCGnWMSd", - "15dU8Tt7kde2diuHzijGbKGPU5K8BPzrFJfYFozvrS1DdE21", - "1vXMKM8SctM28AQw1wSpd7p9yCUWn1uhbbKSVTuznsw8Q2x", - "15mCQcaj3QP1UdxBF82JRd9v3riZJcVNVEmx8xkFp7DSYR4Y" - ]' \ - | jq '.genesis.runtime.session.keys = [ - [ - "134AK3RiMA97Fx9dLj1CvuLJUa8Yo93EeLA1TkP6CCGnWMSd", - "134AK3RiMA97Fx9dLj1CvuLJUa8Yo93EeLA1TkP6CCGnWMSd", - { - "aura": "5EX6AnyuSPEFQ7HAPjRgzqk1sxgh8cyacGimwJ16y1nJ2w7g" - } - ], - [ - "15dU8Tt7kde2diuHzijGbKGPU5K8BPzrFJfYFozvrS1DdE21", - "15dU8Tt7kde2diuHzijGbKGPU5K8BPzrFJfYFozvrS1DdE21", - { - "aura": "5DZN8UhaJftvKhMMARmJBwrwzuEDpoUzzBvvWMbFXYsJ4CmK" - } - ], - [ - "1vXMKM8SctM28AQw1wSpd7p9yCUWn1uhbbKSVTuznsw8Q2x", - "1vXMKM8SctM28AQw1wSpd7p9yCUWn1uhbbKSVTuznsw8Q2x", - { - "aura": "5FKsn83rXQQiw7HwoeYoLMoYS5GP9YVNHZiCHwA4DSwDcPVa" - } - ], - [ - "15mCQcaj3QP1UdxBF82JRd9v3riZJcVNVEmx8xkFp7DSYR4Y", - "15mCQcaj3QP1UdxBF82JRd9v3riZJcVNVEmx8xkFp7DSYR4Y", - { - "aura": "5DCg19ckcJz4m52Th4o1LcSRK3H7NsUcQsRbu7pTDM3mZ26v" - } - ] - ]' \ - > edited-chain-spec-plain.json - -# build a raw spec -$binary build-spec --chain edited-chain-spec-plain.json --raw > chain-spec-raw.json -cp edited-chain-spec-plain.json bridge-hub-polkadot-spec.json -cp chain-spec-raw.json ./parachains/chain-specs/bridge-hub-polkadot.json -cp chain-spec-raw.json bridge-hub-polkadot-spec-raw.json - -# build genesis data -$binary export-genesis-state --chain chain-spec-raw.json > bridge-hub-polkadot-genesis-head-data - -# build genesis wasm -$binary export-genesis-wasm --chain chain-spec-raw.json > bridge-hub-polkadot-wasm - -# cleanup -rm -f rt-hex.txt -rm -f chain-spec-plain.json -rm -f chain-spec-raw.json -rm -f edited-chain-spec-plain.json diff --git a/cumulus/scripts/create_glutton_spec.sh b/cumulus/scripts/create_glutton_spec.sh index c5158392f52..78aafda3bd0 100755 --- a/cumulus/scripts/create_glutton_spec.sh +++ b/cumulus/scripts/create_glutton_spec.sh @@ -55,7 +55,7 @@ for (( para_id=$from_para_id; para_id<=$to_para_id; para_id++ )); do fi # build the chain spec we'll manipulate - $binary_path build-spec --disable-default-bootnode --chain "glutton-kusama-genesis-$para_id" > "$output_para_dir/plain-glutton-$relay_chain-$para_id-spec.json" + $binary_path build-spec --disable-default-bootnode --chain "glutton-westend-genesis-$para_id" > "$output_para_dir/plain-glutton-$relay_chain-$para_id-spec.json" id="glutton-$relay_chain-$para_id" protocol_id="glutton-$relay_chain-$para_id" diff --git a/cumulus/scripts/parachains_integration_tests.sh b/cumulus/scripts/parachains_integration_tests.sh deleted file mode 100755 index 2a06b930e22..00000000000 --- a/cumulus/scripts/parachains_integration_tests.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -tests=( - asset-hub-kusama - asset-hub-polkadot -) - -rm -R logs &> /dev/null - -for t in ${tests[@]} -do - printf "\n🔍 Running $t tests...\n\n" - - mkdir -p logs/$t - - parachains-integration-tests \ - -m zombienet \ - -c ./parachains/integration-tests/$t/config.toml \ - -cl ./logs/$t/chains.log 2> /dev/null & - - parachains-integration-tests \ - -m test \ - -t ./parachains/integration-tests/$t \ - -tl ./logs/$t/tests.log & tests=$! - - wait $tests - - pkill -f polkadot - pkill -f parachain - - printf "\n🎉 $t integration tests finished! \n\n" -done diff --git a/cumulus/zombienet/examples/statemine_kusama_local_network.toml b/cumulus/zombienet/examples/asset_hub_westend_local_network.toml similarity index 71% rename from cumulus/zombienet/examples/statemine_kusama_local_network.toml rename to cumulus/zombienet/examples/asset_hub_westend_local_network.toml index 1f3debfb9d2..5b0ac1f17e8 100644 --- a/cumulus/zombienet/examples/statemine_kusama_local_network.toml +++ b/cumulus/zombienet/examples/asset_hub_westend_local_network.toml @@ -1,7 +1,7 @@ [relaychain] -default_command = "../polkadot/target/release/polkadot" +default_command = "../../target/release/polkadot" default_args = [ "-lparachain=debug" ] -chain = "kusama-local" +chain = "westend-local" [[relaychain.nodes]] name = "alice" @@ -21,47 +21,47 @@ chain = "kusama-local" [[parachains]] id = 1000 -chain = "asset-hub-kusama-local" +chain = "asset-hub-westend-local" cumulus_based = true # run alice as parachain collator [[parachains.collators]] name = "alice" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] # run bob as parachain collator [[parachains.collators]] name = "bob" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] # run charlie as parachain collator [[parachains.collators]] name = "charlie" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] # run dave as parachain collator [[parachains.collators]] name = "dave" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] # run eve as parachain collator [[parachains.collators]] name = "eve" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] # run ferdie as parachain collator [[parachains.collators]] name = "ferdie" validator = true - command = "./target/release/polkadot-parachain" + command = "../../target/release/polkadot-parachain" args = ["-lparachain=debug"] diff --git a/cumulus/zombienet/examples/bridge_hub_kusama_local_network.toml b/cumulus/zombienet/examples/bridge_hub_kusama_local_network.toml deleted file mode 100644 index ae8ae07a75c..00000000000 --- a/cumulus/zombienet/examples/bridge_hub_kusama_local_network.toml +++ /dev/null @@ -1,67 +0,0 @@ -[relaychain] -default_command = "../polkadot/target/release/polkadot" -default_args = [ "-lparachain=debug" ] -chain = "kusama-local" - - [[relaychain.nodes]] - name = "alice" - validator = true - - [[relaychain.nodes]] - name = "bob" - validator = true - - [[relaychain.nodes]] - name = "charlie" - validator = true - - [[relaychain.nodes]] - name = "dave" - validator = true - -[[parachains]] -id = 1003 -chain = "bridge-hub-kusama-local" -cumulus_based = true - - # run alice as parachain collator - [[parachains.collators]] - name = "alice" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run bob as parachain collator - [[parachains.collators]] - name = "bob" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run charlie as parachain collator - [[parachains.collators]] - name = "charlie" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run dave as parachain collator - [[parachains.collators]] - name = "dave" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run eve as parachain collator - [[parachains.collators]] - name = "eve" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run ferdie as parachain collator - [[parachains.collators]] - name = "ferdie" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] diff --git a/cumulus/zombienet/examples/bridge_hub_polkadot_local_network.toml b/cumulus/zombienet/examples/bridge_hub_polkadot_local_network.toml deleted file mode 100644 index 564fece7cae..00000000000 --- a/cumulus/zombienet/examples/bridge_hub_polkadot_local_network.toml +++ /dev/null @@ -1,67 +0,0 @@ -[relaychain] -default_command = "../polkadot/target/release/polkadot" -default_args = [ "-lparachain=debug" ] -chain = "polkadot-local" - - [[relaychain.nodes]] - name = "alice" - validator = true - - [[relaychain.nodes]] - name = "bob" - validator = true - - [[relaychain.nodes]] - name = "charlie" - validator = true - - [[relaychain.nodes]] - name = "dave" - validator = true - -[[parachains]] -id = 1003 -chain = "bridge-hub-polkadot-local" -cumulus_based = true - - # run alice as parachain collator - [[parachains.collators]] - name = "alice" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run bob as parachain collator - [[parachains.collators]] - name = "bob" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run charlie as parachain collator - [[parachains.collators]] - name = "charlie" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run dave as parachain collator - [[parachains.collators]] - name = "dave" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run eve as parachain collator - [[parachains.collators]] - name = "eve" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] - - # run ferdie as parachain collator - [[parachains.collators]] - name = "ferdie" - validator = true - command = "./target/release/polkadot-parachain" - args = ["-lparachain=debug"] diff --git a/cumulus/zombienet/examples/small_network.toml b/cumulus/zombienet/examples/small_network.toml index 06ac0d0e5e7..ab726571230 100644 --- a/cumulus/zombienet/examples/small_network.toml +++ b/cumulus/zombienet/examples/small_network.toml @@ -14,7 +14,7 @@ chain = "rococo-local" [[parachains]] id = 2000 cumulus_based = true -chain = "asset-hub-kusama-local" +chain = "asset-hub-rococo-local" # run charlie as parachain collator [[parachains.collators]] -- GitLab From f2fe6a4c56ff524d9fd3a35eda8b246740af69e8 Mon Sep 17 00:00:00 2001 From: yjh Date: Wed, 29 Nov 2023 21:48:32 +0800 Subject: [PATCH 611/633] Improve `CodeExecutor` (#2358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since `sp-state-machine` and `GenesisConfigBuilderRuntimeCaller` always set `use_native` to be false. We should remove this param and make `NativeElseWasmExecutor` behave like its name. It could make the above components use the correct execution strategy. Maybe polkadot do not need about `NativeElseWasmExecutor` anymore. But it is still needed by other chains and it's useful for debugging. --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- substrate/bin/node/cli/benches/executor.rs | 12 +--- substrate/bin/node/cli/tests/basic.rs | 69 +++++++------------ substrate/bin/node/cli/tests/common.rs | 9 ++- substrate/bin/node/cli/tests/fees.rs | 14 ++-- .../chain-spec/src/genesis_config_builder.rs | 1 - substrate/client/executor/src/executor.rs | 23 +++++-- substrate/primitives/core/src/traits.rs | 1 - substrate/primitives/state-machine/src/lib.rs | 5 +- substrate/test-utils/client/src/lib.rs | 3 +- 9 files changed, 56 insertions(+), 81 deletions(-) diff --git a/substrate/bin/node/cli/benches/executor.rs b/substrate/bin/node/cli/benches/executor.rs index d654646904b..a326e1a79ea 100644 --- a/substrate/bin/node/cli/benches/executor.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -103,14 +103,7 @@ fn construct_block( // execute the block to get the real header. executor - .call( - ext, - &runtime_code, - "Core_initialize_block", - &header.encode(), - true, - CallContext::Offchain, - ) + .call(ext, &runtime_code, "Core_initialize_block", &header.encode(), CallContext::Offchain) .0 .unwrap(); @@ -121,7 +114,6 @@ fn construct_block( &runtime_code, "BlockBuilder_apply_extrinsic", &i.encode(), - true, CallContext::Offchain, ) .0 @@ -135,7 +127,6 @@ fn construct_block( &runtime_code, "BlockBuilder_finalize_block", &[0u8; 0], - true, CallContext::Offchain, ) .0 @@ -200,7 +191,6 @@ fn bench_execute_block(c: &mut Criterion) { &runtime_code, "Core_execute_block", &block.0, - false, CallContext::Offchain, ) .0 diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index cbceac04e8e..e5a8a397254 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -193,11 +193,9 @@ fn panic_execution_with_foreign_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = - executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 .unwrap(); let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); @@ -219,11 +217,9 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = - executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 .unwrap(); let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); @@ -256,14 +252,12 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = - executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { @@ -298,14 +292,12 @@ fn successful_execution_with_foreign_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = - executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { @@ -337,7 +329,7 @@ fn full_native_block_import_works() { .base_extrinsic, ); - executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -412,7 +404,7 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); let pot = t.execute_with(|| Treasury::pot()); - executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -554,7 +546,7 @@ fn full_wasm_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - executor_call(&mut t, "Core_execute_block", &block1.0, false).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -564,7 +556,7 @@ fn full_wasm_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); - executor_call(&mut t, "Core_execute_block", &block2.0, false).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -717,7 +709,7 @@ fn deploying_wasm_contract_should_work() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call(&mut t, "Core_execute_block", &b.0, false).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &b.0).0.unwrap(); t.execute_with(|| { // Verify that the contract does exist by querying some of its storage items @@ -732,8 +724,7 @@ fn wasm_big_block_import_fails() { set_heap_pages(&mut t.ext(), 4); - let result = - executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false).0; + let result = executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0).0; assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) } @@ -741,7 +732,7 @@ fn wasm_big_block_import_fails() { fn native_big_block_import_succeeds() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, true) + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0) .0 .unwrap(); } @@ -754,11 +745,9 @@ fn native_big_block_import_fails_on_fallback() { // block. set_heap_pages(&mut t.ext(), 8); - assert!( - executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false,) - .0 - .is_err() - ); + assert!(executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0) + .0 + .is_err()); } #[test] @@ -775,15 +764,9 @@ fn panic_execution_gives_error() { t.insert(>::hashed_key().to_vec(), 0_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - false, - ) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 .unwrap(); let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap(); @@ -816,13 +799,7 @@ fn successful_execution_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - false, - ) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS); @@ -830,7 +807,7 @@ fn successful_execution_gives_ok() { let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 .unwrap(); ApplyExtrinsicResult::decode(&mut &r[..]) @@ -861,7 +838,7 @@ fn should_import_block_with_test_client() { #[test] fn default_config_as_json_works() { let mut t = new_test_ext(compact_code_unwrap()); - let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![], false) + let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![]) .0 .unwrap(); let r = Vec::::decode(&mut &r[..]).unwrap(); diff --git a/substrate/bin/node/cli/tests/common.rs b/substrate/bin/node/cli/tests/common.rs index 7d8f6a9a0e7..9019594ff62 100644 --- a/substrate/bin/node/cli/tests/common.rs +++ b/substrate/bin/node/cli/tests/common.rs @@ -105,7 +105,6 @@ pub fn executor_call( t: &mut TestExternalities, method: &str, data: &[u8], - use_native: bool, ) -> (Result>, bool) { let mut t = t.ext(); @@ -117,7 +116,7 @@ pub fn executor_call( heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), }; sp_tracing::try_init_simple(); - executor().call(&mut t, &runtime_code, method, data, use_native, CallContext::Onchain) + executor().call(&mut t, &runtime_code, method, data, CallContext::Onchain) } pub fn new_test_ext(code: &[u8]) -> TestExternalities { @@ -168,12 +167,12 @@ pub fn construct_block( }; // execute the block to get the real header. - executor_call(env, "Core_initialize_block", &header.encode(), true).0.unwrap(); + executor_call(env, "Core_initialize_block", &header.encode()).0.unwrap(); for extrinsic in extrinsics.iter() { // Try to apply the `extrinsic`. It should be valid, in the sense that it passes // all pre-inclusion checks. - let r = executor_call(env, "BlockBuilder_apply_extrinsic", &extrinsic.encode(), true) + let r = executor_call(env, "BlockBuilder_apply_extrinsic", &extrinsic.encode()) .0 .expect("application of an extrinsic failed"); @@ -186,7 +185,7 @@ pub fn construct_block( } let header = Header::decode( - &mut &executor_call(env, "BlockBuilder_finalize_block", &[0u8; 0], true).0.unwrap()[..], + &mut &executor_call(env, "BlockBuilder_finalize_block", &[0u8; 0]).0.unwrap()[..], ) .unwrap(); diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 7519ce6e8b1..8c7b3c87315 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -95,7 +95,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { ); // execute a big block. - executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -106,7 +106,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { }); // execute a big block. - executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -151,12 +151,10 @@ fn transaction_fee_is_correct() { function: RuntimeCall::Balances(default_transfer_call()), }); - let r = - executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) - .0; + let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone()), true).0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone())).0; assert!(r.is_ok()); t.execute_with(|| { @@ -247,7 +245,7 @@ fn block_weight_capacity_report() { len / 1024 / 1024, ); - let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; + let r = executor_call(&mut t, "Core_execute_block", &block.0).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); @@ -310,7 +308,7 @@ fn block_length_capacity_report() { len / 1024 / 1024, ); - let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; + let r = executor_call(&mut t, "Core_execute_block", &block.0).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index 9ccf6b4efb2..68f3d886049 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -76,7 +76,6 @@ where &RuntimeCode { heap_pages: None, code_fetcher: self, hash: self.code_hash.clone() }, method, data, - false, CallContext::Offchain, ) .0 diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index 7c292a83da0..499bb704b16 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -492,7 +492,6 @@ where runtime_code: &RuntimeCode, method: &str, data: &[u8], - _use_native: bool, context: CallContext, ) -> (Result>, bool) { tracing::trace!( @@ -565,6 +564,8 @@ pub struct NativeElseWasmExecutor { /// Fallback wasm executor. wasm: WasmExecutor>, + + use_native: bool, } impl NativeElseWasmExecutor { @@ -601,7 +602,7 @@ impl NativeElseWasmExecutor { .with_runtime_cache_size(runtime_cache_size) .build(); - NativeElseWasmExecutor { native_version: D::native_version(), wasm } + NativeElseWasmExecutor { native_version: D::native_version(), wasm, use_native: true } } /// Create a new instance using the given [`WasmExecutor`]. @@ -610,7 +611,14 @@ impl NativeElseWasmExecutor { ExtendedHostFunctions, >, ) -> Self { - Self { native_version: D::native_version(), wasm: executor } + Self { native_version: D::native_version(), wasm: executor, use_native: true } + } + + /// Disable to use native runtime when possible just behave like `WasmExecutor`. + /// + /// Default to enabled. + pub fn disable_use_native(&mut self) { + self.use_native = false; } /// Ignore missing function imports if set true. @@ -645,9 +653,10 @@ impl CodeExecutor for NativeElseWasmExecut runtime_code: &RuntimeCode, method: &str, data: &[u8], - use_native: bool, context: CallContext, ) -> (Result>, bool) { + let use_native = self.use_native; + tracing::trace!( target: "executor", function = %method, @@ -711,7 +720,11 @@ impl CodeExecutor for NativeElseWasmExecut impl Clone for NativeElseWasmExecutor { fn clone(&self) -> Self { - NativeElseWasmExecutor { native_version: D::native_version(), wasm: self.wasm.clone() } + NativeElseWasmExecutor { + native_version: D::native_version(), + wasm: self.wasm.clone(), + use_native: self.use_native, + } } } diff --git a/substrate/primitives/core/src/traits.rs b/substrate/primitives/core/src/traits.rs index 9815c84f339..851d8910391 100644 --- a/substrate/primitives/core/src/traits.rs +++ b/substrate/primitives/core/src/traits.rs @@ -51,7 +51,6 @@ pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'stat runtime_code: &RuntimeCode, method: &str, data: &[u8], - use_native: bool, context: CallContext, ) -> (Result, Self::Error>, bool); } diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 0e2b9bfdfff..1345097e8f6 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -289,7 +289,7 @@ mod execution { let result = self .exec - .call(&mut ext, self.runtime_code, self.method, self.call_data, false, self.context) + .call(&mut ext, self.runtime_code, self.method, self.call_data, self.context) .0; self.overlay @@ -1120,10 +1120,9 @@ mod tests { _: &RuntimeCode, _method: &str, _data: &[u8], - use_native: bool, _: CallContext, ) -> (CallResult, bool) { - let using_native = use_native && self.native_available; + let using_native = self.native_available; match (using_native, self.native_succeeds, self.fallback_succeeds) { (true, true, _) | (false, _, true) => ( Ok(vec![ diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index 084dd2a1861..f383f7c3dc3 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -263,9 +263,10 @@ impl D: sc_executor::NativeExecutionDispatch + 'static, Backend: sc_client_api::backend::Backend + 'static, { - let executor = executor.into().unwrap_or_else(|| { + let mut executor = executor.into().unwrap_or_else(|| { NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) }); + executor.disable_use_native(); let executor = LocalCallExecutor::new( self.backend.clone(), executor.clone(), -- GitLab From 19f665f27902bfea62d24cd06723cdab40f060ab Mon Sep 17 00:00:00 2001 From: Tom Mi Date: Wed, 29 Nov 2023 21:49:11 +0800 Subject: [PATCH 612/633] add Rotko common good parachain nodes (#2533) rotko networks parachain bootnodes ``` # array of commands for testing parachains=( "./polkadot-parachain --chain asset-hub-polkadot --reserved-only --reserved-nodes /dns/mint14.rotko.net/tcp/33514/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-polkadot --reserved-only --reserved-nodes /dns/mint14.rotko.net/tcp/34514/ws/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-polkadot --reserved-only --reserved-nodes /dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-kusama --reserved-only --reserved-nodes /dns/mine14.rotko.net/tcp/33524/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-kusama --reserved-only --reserved-nodes /dns/mine14.rotko.net/tcp/34524/ws/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-kusama --reserved-only --reserved-nodes /dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-westend --reserved-only --reserved-nodes /dns/wmint14.rotko.net/tcp/33534/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-westend --reserved-only --reserved-nodes /dns/wmint14.rotko.net/tcp/34534/ws/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN --no-hardware-benchmarks" "./polkadot-parachain --chain asset-hub-westend --reserved-only --reserved-nodes /dns/wmint14.rotko.net/tcp/35534/wss/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-polkadot --reserved-only --reserved-nodes /dns/pbr13.rotko.net/tcp/33543/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-polkadot --reserved-only --reserved-nodes /dns/pbr13.rotko.net/tcp/34543/ws/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-polkadot --reserved-only --reserved-nodes /dns/pbr13.rotko.net/tcp/35543/wss/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-kusama --reserved-only --reserved-nodes /dns/kbr13.rotko.net/tcp/33553/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66 --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-kusama --reserved-only --reserved-nodes /dns/kbr13.rotko.net/tcp/34553/ws/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66 --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-kusama --reserved-only --reserved-nodes /dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66 --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-westend --reserved-only --reserved-nodes /dns/wbr13.rotko.net/tcp/33563/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-westend --reserved-only --reserved-nodes /dns/wbr13.rotko.net/tcp/34563/ws/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD --no-hardware-benchmarks" "./polkadot-parachain --chain bridge-hub-westend --reserved-only --reserved-nodes /dns/wbr13.rotko.net/tcp/35563/wss/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-polkadot --reserved-only --reserved-nodes /dns/pch13.rotko.net/tcp/33573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-polkadot --reserved-only --reserved-nodes /dns/pch13.rotko.net/tcp/34573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-polkadot --reserved-only --reserved-nodes /dns/pch13.rotko.net/tcp/35573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-westend --reserved-only --reserved-nodes /dns/wch13.rotko.net/tcp/33593/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-westend --reserved-only --reserved-nodes /dns/wch13.rotko.net/tcp/34593/ws/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr --no-hardware-benchmarks" "./polkadot-parachain --chain collectives-westend --reserved-only --reserved-nodes /dns/wch13.rotko.net/tcp/35593/wss/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr --no-hardware-benchmarks" ) ``` --- cumulus/parachains/chain-specs/asset-hub-kusama.json | 5 ++++- cumulus/parachains/chain-specs/asset-hub-polkadot.json | 5 ++++- cumulus/parachains/chain-specs/asset-hub-westend.json | 5 ++++- cumulus/parachains/chain-specs/bridge-hub-kusama.json | 5 ++++- cumulus/parachains/chain-specs/bridge-hub-polkadot.json | 5 ++++- cumulus/parachains/chain-specs/bridge-hub-westend.json | 5 ++++- cumulus/parachains/chain-specs/collectives-polkadot.json | 5 ++++- cumulus/parachains/chain-specs/collectives-westend.json | 5 ++++- 8 files changed, 32 insertions(+), 8 deletions(-) diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 946bfc5983d..fba74b17f96 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -22,7 +22,10 @@ "/dns/statemine-boot-ng.dwellir.com/tcp/30343/p2p/12D3KooWQNJKBaNfW6Nn7HZDi5pSSEFmHL2Qz7chr9RksQUDR1Wk", "/dns/statemine-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWQNJKBaNfW6Nn7HZDi5pSSEFmHL2Qz7chr9RksQUDR1Wk", "/dns/statemine-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL", - "/dns/statemine-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL" + "/dns/statemine-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL", + "/dns/mine14.rotko.net/tcp/33524/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", + "/dns/mine14.rotko.net/tcp/34524/ws/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", + "/dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index c26506eb995..685a00ddc71 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -22,7 +22,10 @@ "/dns/statemint-boot-ng.dwellir.com/tcp/30344/p2p/12D3KooWEFrNuNk8fPdQS2hf34Gmqi6dGSvrETshGJUrqrvfRDZr", "/dns/statemint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWEFrNuNk8fPdQS2hf34Gmqi6dGSvrETshGJUrqrvfRDZr", "/dns/statemint-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx", - "/dns/statemint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx" + "/dns/statemint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx", + "/dns/mint14.rotko.net/tcp/33514/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", + "/dns/mint14.rotko.net/tcp/34514/ws/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", + "/dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index f0e71981e7a..6f42b5f7d8b 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -20,7 +20,10 @@ "/dns/westmint-boot-ng.dwellir.com/tcp/30345/p2p/12D3KooWFZ9xqApB1wnFYkbe1qJ5Jqwxe2f3i8W25F3tKNXy59ux", "/dns/westmint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWFZ9xqApB1wnFYkbe1qJ5Jqwxe2f3i8W25F3tKNXy59ux", "/dns/westmint-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk", - "/dns/westmint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk" + "/dns/westmint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk", + "/dns/wmint14.rotko.net/tcp/33534/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", + "/dns/wmint14.rotko.net/tcp/34534/ws/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", + "/dns/wmint14.rotko.net/tcp/35534/wss/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 9daa60fa263..0ef81806cc5 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -22,7 +22,10 @@ "/dns/kusama-bridge-hub-boot-ng.dwellir.com/tcp/30337/p2p/12D3KooWBFskNCQDVjuUeBh6vrszWrUvYMBBhtZRLnoTZDdLYbW5", "/dns/kusama-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBFskNCQDVjuUeBh6vrszWrUvYMBBhtZRLnoTZDdLYbW5", "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW", - "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW" + "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW", + "/dns/kbr13.rotko.net/tcp/33553/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", + "/dns/kbr13.rotko.net/tcp/34553/ws/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", + "/dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index d3e884284b4..130bdf31ef2 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -18,7 +18,10 @@ "/dns/boot-node.helikon.io/tcp/8220/p2p/12D3KooWC38TZJA8ZBXZgAYVrceoJ56jNNLJPdpk3ojeFkTAwZVp", "/dns/boot-node.helikon.io/tcp/8222/wss/p2p/12D3KooWC38TZJA8ZBXZgAYVrceoJ56jNNLJPdpk3ojeFkTAwZVp", "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi", - "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi" + "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi", + "/dns/pbr13.rotko.net/tcp/33543/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", + "/dns/pbr13.rotko.net/tcp/34543/ws/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", + "/dns/pbr13.rotko.net/tcp/35543/wss/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index dde3d437f41..018ab0ee6fd 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -16,7 +16,10 @@ "/dns/boot-node.helikon.io/tcp/9220/p2p/12D3KooWK3K1Mu5Jjg96Lt9DUzg84KsWnZo44V4KB7mvhGqi6xnp", "/dns/boot-node.helikon.io/tcp/9222/wss/p2p/12D3KooWK3K1Mu5Jjg96Lt9DUzg84KsWnZo44V4KB7mvhGqi6xnp", "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke", - "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke" + "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke", + "/dns/wbr13.rotko.net/tcp/33563/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD", + "/dns/wbr13.rotko.net/tcp/34563/ws/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD", + "/dns/wbr13.rotko.net/tcp/35563/wss/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index 003c6373429..e9f690234e4 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -22,7 +22,10 @@ "/dns/polkadot-collectives-boot-ng.dwellir.com/tcp/30341/p2p/12D3KooWDMFYCNRAQcSRNV7xu2xv8319goSEbSHW4TnXRz6EpPKc", "/dns/polkadot-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWDMFYCNRAQcSRNV7xu2xv8319goSEbSHW4TnXRz6EpPKc", "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c", - "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c" + "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c", + "/dns/pch13.rotko.net/tcp/33573/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", + "/dns/pch13.rotko.net/tcp/34573/ws/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", + "/dns/pch13.rotko.net/tcp/35573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index e06671faa04..7385889f0ec 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -20,7 +20,10 @@ "/dns/collectives-westend.bootnode.amforc.com/tcp/30340/p2p/12D3KooWERPzUhHau6o2XZRUi3tn7544rYiaHL418Nw5t8fYWP1F", "/dns/collectives-westend.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWERPzUhHau6o2XZRUi3tn7544rYiaHL418Nw5t8fYWP1F", "/dns/westend-collectives-boot-ng.dwellir.com/tcp/30340/p2p/12D3KooWPFM93jgm4pgxx8PM8WJKAJF49qia8jRB95uciUQwYh7m", - "/dns/westend-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPFM93jgm4pgxx8PM8WJKAJF49qia8jRB95uciUQwYh7m" + "/dns/westend-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPFM93jgm4pgxx8PM8WJKAJF49qia8jRB95uciUQwYh7m", + "/dns/wch13.rotko.net/tcp/33593/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", + "/dns/wch13.rotko.net/tcp/34593/ws/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", + "/dns/wch13.rotko.net/tcp/35593/wss/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr" ], "telemetryEndpoints": null, "protocolId": null, -- GitLab From 8f03570a461c5a05c09ef42ae6edcaea5ef4c503 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:31:31 +0200 Subject: [PATCH 613/633] Bump fs4 from 0.6.6 to 0.7.0 (#1844) --- Cargo.lock | 4 ++-- substrate/client/storage-monitor/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db5717a67ec..f94c87dad48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5632,9 +5632,9 @@ dependencies = [ [[package]] name = "fs4" -version = "0.6.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" +checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ "rustix 0.38.21", "windows-sys 0.48.0", diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 021ee76240b..4c1f2e46504 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] clap = { version = "4.4.6", features = ["derive", "string"] } log = "0.4.17" -fs4 = "0.6.3" +fs4 = "0.7.0" sc-client-db = { path = "../db", default-features = false} sp-core = { path = "../../primitives/core" } tokio = "1.22.0" -- GitLab From d3d301fa422f113ee7fa4d62fa45b155bd42a20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Nov 2023 15:31:51 +0100 Subject: [PATCH 614/633] ParachainHost: No need to be generic over the block or hash type (#2537) The `BlockNumber` and `Hash` are fixed types any way. --- polkadot/node/service/src/fake_runtime_api.rs | 2 +- polkadot/primitives/src/runtime_api.rs | 35 ++++++++++--------- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/test-runtime/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index d9553afa024..ccc3da22400 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -116,7 +116,7 @@ sp_api::impl_runtime_apis! { } } - impl runtime_api::ParachainHost for Runtime { + impl runtime_api::ParachainHost for Runtime { fn validators() -> Vec { unimplemented!() } diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index e4c1d590f45..331728b2590 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -116,11 +116,10 @@ use crate::{ async_backing, slashing, vstaging, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, OccupiedCoreAssumption, PersistedValidationData, + ExecutorParams, GroupRotationInfo, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, }; -use parity_scale_codec::{Decode, Encode}; use polkadot_core_primitives as pcp; use polkadot_parachain_primitives::primitives as ppp; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -128,18 +127,18 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; sp_api::decl_runtime_apis! { /// The API for querying the state of parachains on-chain. #[api_version(5)] - pub trait ParachainHost { + pub trait ParachainHost { /// Get the current validators. fn validators() -> Vec; /// Returns the validator groups and rotation info localized based on the hypothetical child /// of a block whose state this is invoked on. Note that `now` in the `GroupRotationInfo` /// should be the successor of the number of the block. - fn validator_groups() -> (Vec>, GroupRotationInfo); + fn validator_groups() -> (Vec>, GroupRotationInfo); /// Yields information on all availability cores as relevant to the child block. /// Cores are either free or occupied. Free cores can have paras assigned to them. - fn availability_cores() -> Vec>; + fn availability_cores() -> Vec>; /// Yields the persisted validation data for the given `ParaId` along with an assumption that /// should be used if the para currently occupies a core. @@ -147,15 +146,15 @@ sp_api::decl_runtime_apis! { /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. fn persisted_validation_data(para_id: ppp::Id, assumption: OccupiedCoreAssumption) - -> Option>; + -> Option>; /// Returns the persisted validation data for the given `ParaId` along with the corresponding /// validation code hash. Instead of accepting assumption about the para, matches the validation /// data hash against an expected one and yields `None` if they're not equal. fn assumed_validation_data( para_id: ppp::Id, - expected_persisted_validation_data_hash: pcp::v2::Hash, - ) -> Option<(PersistedValidationData, ppp::ValidationCodeHash)>; + expected_persisted_validation_data_hash: Hash, + ) -> Option<(PersistedValidationData, ppp::ValidationCodeHash)>; /// Checks if the given validation outputs pass the acceptance criteria. fn check_validation_outputs(para_id: ppp::Id, outputs: CandidateCommitments) -> bool; @@ -169,30 +168,34 @@ sp_api::decl_runtime_apis! { /// /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. - fn validation_code(para_id: ppp::Id, assumption: OccupiedCoreAssumption) - -> Option; + fn validation_code( + para_id: ppp::Id, + assumption: OccupiedCoreAssumption, + ) -> Option; /// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. - fn candidate_pending_availability(para_id: ppp::Id) -> Option>; + fn candidate_pending_availability(para_id: ppp::Id) -> Option>; /// Get a vector of events concerning candidates that occurred within a block. - fn candidate_events() -> Vec>; + fn candidate_events() -> Vec>; /// Get all the pending inbound messages in the downward message queue for a para. fn dmq_contents( recipient: ppp::Id, - ) -> Vec>; + ) -> Vec>; /// Get the contents of all channels addressed to the given recipient. Channels that have no /// messages in them are also included. - fn inbound_hrmp_channels_contents(recipient: ppp::Id) -> BTreeMap>>; + fn inbound_hrmp_channels_contents( + recipient: ppp::Id, + ) -> BTreeMap>>; /// Get the validation code from its hash. fn validation_code_by_hash(hash: ppp::ValidationCodeHash) -> Option; /// Scrape dispute relevant from on-chain, backing votes and resolved disputes. - fn on_chain_votes() -> Option>; + fn on_chain_votes() -> Option>; /***** Added in v2 *****/ @@ -253,7 +256,7 @@ sp_api::decl_runtime_apis! { /// Returns the state of parachain backing for a given para. #[api_version(7)] - fn para_backing_state(_: ppp::Id) -> Option>; + fn para_backing_state(_: ppp::Id) -> Option>; /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. #[api_version(7)] diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5ac92a73732..23d32b59a51 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1802,7 +1802,7 @@ sp_api::impl_runtime_apis! { } #[api_version(9)] - impl primitives::runtime_api::ParachainHost for Runtime { + impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 596e65eca06..7ec9f63748c 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -826,7 +826,7 @@ sp_api::impl_runtime_apis! { } } - impl primitives::runtime_api::ParachainHost for Runtime { + impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { runtime_impl::validators::() } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f7ff2d5e9e1..36c8c12be21 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1796,7 +1796,7 @@ sp_api::impl_runtime_apis! { } #[api_version(9)] - impl primitives::runtime_api::ParachainHost for Runtime { + impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() } -- GitLab From 2858cbc2480b6747978b9fec75b620688fe0a5b2 Mon Sep 17 00:00:00 2001 From: "Will | Paradox | ParaNodes.io" <79228812+paradox-tt@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:40:26 +0000 Subject: [PATCH 615/633] Adding LuckyFriday's Bootnodes per IBP Application (#2538) Good day, This PR requests the inclusion of two bootnode entries for Polkadot, Kusama and Westend as part of LuckyFriday's IBP application. The nodes are hosted on self-owned hardware in a co-located facility. We've undertaken connectivity tests ourselves and also from members of the IBP. The test commands used are as follows: ``` polkadot --chain westend --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9" --no-hardware-benchmarks polkadot --chain westend --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-westend.luckyfriday.io/tcp/30333/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9" --no-hardware-benchmarks polkadot --chain kusama --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT" --no-hardware-benchmarks polkadot --chain kusama --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT" --no-hardware-benchmarks polkadot --chain polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ" --no-hardware-benchmarks polkadot --chain polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ" --no-hardware-benchmarks ``` All tests yielded syncing with 1 peer, a positive result. We have also backed up our node-key in the event that restoration is required. I hope that the aforementioned meets the requirement for inclusion and look forward to a speedy turnaround. Kind Regards, Will | Paradox --- polkadot/node/service/chain-specs/kusama.json | 4 +++- polkadot/node/service/chain-specs/polkadot.json | 4 +++- polkadot/node/service/chain-specs/westend.json | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 6676bbe154b..979550c7570 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -33,7 +33,9 @@ "/dns/ksm-bootnode.stakeworld.io/tcp/30301/ws/p2p/12D3KooWFRin7WWVS6RgUsSpkfUHSv4tfGKnr2zJPmf1pbMv118H", "/dns/ksm-bootnode.stakeworld.io/tcp/30302/wss/p2p/12D3KooWFRin7WWVS6RgUsSpkfUHSv4tfGKnr2zJPmf1pbMv118H", "/dns/ksm14.rotko.net/tcp/35224/wss/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK", - "/dns/ksm14.rotko.net/tcp/33224/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK" + "/dns/ksm14.rotko.net/tcp/33224/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK", + "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", + "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 53349208816..71dbb900403 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -34,7 +34,9 @@ "/dns/dot-bootnode.stakeworld.io/tcp/30311/ws/p2p/12D3KooWAb5MyC1UJiEQJk4Hg4B2Vi3AJdqSUhTGYUqSnEqCFMFg", "/dns/dot-bootnode.stakeworld.io/tcp/30312/wss/p2p/12D3KooWAb5MyC1UJiEQJk4Hg4B2Vi3AJdqSUhTGYUqSnEqCFMFg", "/dns/dot14.rotko.net/tcp/35214/wss/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff", - "/dns/dot14.rotko.net/tcp/33214/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff" + "/dns/dot14.rotko.net/tcp/33214/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff", + "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", + "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index b2ffba9304b..697675871fc 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -31,7 +31,9 @@ "/dns/wnd-bootnode.stakeworld.io/tcp/30321/ws/p2p/12D3KooWBYdKipcNbrV5rCbgT5hco8HMLME7cE9hHC3ckqCKDuzP", "/dns/wnd-bootnode.stakeworld.io/tcp/30322/wss/p2p/12D3KooWBYdKipcNbrV5rCbgT5hco8HMLME7cE9hHC3ckqCKDuzP", "/dns/wnd14.rotko.net/tcp/35234/wss/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", - "/dns/wnd14.rotko.net/tcp/33234/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ" + "/dns/wnd14.rotko.net/tcp/33234/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", + "/dns/ibp-boot-westend.luckyfriday.io/tcp/30333/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9", + "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9" ], "telemetryEndpoints": [ [ -- GitLab From 08f29af6cd7866e1010a15c2a0ddfc1a07f3a597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Nov 2023 17:29:50 +0100 Subject: [PATCH 616/633] sp-api: Sprinkle some `automatically_derived` attributes This attribute is informing tooling that the code is automatically derived and thus, should not enable any linting. --- .../primitives/api/proc-macro/src/impl_runtime_apis.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 e439a796e28..e97291bc58a 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -275,6 +275,7 @@ fn generate_runtime_api_base_structures() -> Result { extensions_generated_for: std::cell::RefCell>, } + #[automatically_derived] impl> #crate_::ApiExt for RuntimeApiImpl { @@ -367,6 +368,7 @@ fn generate_runtime_api_base_structures() -> Result { } } + #[automatically_derived] impl #crate_::ConstructRuntimeApi for RuntimeApi where @@ -389,6 +391,7 @@ fn generate_runtime_api_base_structures() -> Result { } } + #[automatically_derived] impl> RuntimeApiImpl { fn commit_or_rollback_transaction(&self, commit: bool) { let proof = "\ @@ -685,9 +688,11 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result // remove the trait to get just the module path runtime_mod_path.segments.pop(); - let processed_impl = + let mut processed_impl = ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone()); + processed_impl.attrs.push(parse_quote!(#[automatically_derived])); + result.push(processed_impl); } -- GitLab From eb46b99b29e80870caa96bb46158bc955429d105 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Wed, 29 Nov 2023 21:20:05 +0400 Subject: [PATCH 617/633] Disable trace-level logging from the `test-linux-stable-int` (#2546) --- .gitlab/pipeline/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 190249d2d0f..265b378ef5b 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -395,7 +395,6 @@ test-linux-stable-int: RUN_UI_TESTS: 1 script: - WASM_BUILD_NO_COLOR=1 - RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace time cargo test -p staging-node-cli --release --locked -- --ignored # more information about this job can be found here: -- GitLab From ecdf34392527e5b3fd50879bb57f8d860eafabe3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:15:33 +0200 Subject: [PATCH 618/633] chainHead: Backport error codes from spec (#2539) This PR backports the error codes from the spec. This relies on two specs for defining the error codes: - Our rpc-spec-v2 https://github.com/paritytech/json-rpc-interface-spec. - JSON-RPC spec https://www.jsonrpc.org/specification#error_object. To better describe the error codes, they are divided into two separate modules `rpc_spec_v2` and `json_rpc_spec` respectively. The `InvalidSubscriptionID` and `FetchBlockHeader` are merged into the JSON-RPC spec `INTERNAL_ERROR`. While the other error codes are adjusted from spec. Errors that are currently in use: - -32801 block hash not reported by chainHead_follow or block hash has been unpinned - -32802 chainHead_follow started with withRuntime == false - -32803 chainHead_follow did not generate an operationWaitingForContinue event The following are errors defined in the [JSON-RPC spec](https://www.jsonrpc.org/specification#error_object): - -32602 The provided parameter isn't one of the expected values, has different format or is missing - -32603 Internal server error Note: Error `-32801` must be introduced and generated by the outstanding https://github.com/paritytech/polkadot-sdk/issues/1505 Closes: https://github.com/paritytech/polkadot-sdk/issues/2530 --------- Signed-off-by: Alexandru Vasile --- .../rpc-spec-v2/src/chain_head/chain_head.rs | 8 ++- .../rpc-spec-v2/src/chain_head/error.rs | 64 +++++++++++-------- .../rpc-spec-v2/src/chain_head/tests.rs | 24 +++---- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 866701a7dbf..8e04ac7b177 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -198,7 +198,9 @@ where let sub_id = match self.accept_subscription(&mut sink) { Ok(sub_id) => sub_id, Err(err) => { - sink.close(ChainHeadRpcError::InvalidSubscriptionID); + sink.close(ChainHeadRpcError::InternalError( + "Cannot generate subscription ID".into(), + )); return Err(err) }, }; @@ -306,7 +308,7 @@ where self.client .header(hash) .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) - .map_err(ChainHeadRpcError::FetchBlockHeader) + .map_err(|err| ChainHeadRpcError::InternalError(err.to_string())) .map_err(Into::into) } @@ -393,7 +395,7 @@ where // Reject subscription if with_runtime is false. if !block_guard.has_runtime() { - return Err(ChainHeadRpcError::InvalidParam( + return Err(ChainHeadRpcError::InvalidRuntimeCall( "The runtime updates flag must be set".to_string(), ) .into()) 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 811666428c5..a9b7d7f96e4 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -22,7 +22,6 @@ use jsonrpsee::{ core::Error as RpcError, types::error::{CallError, ErrorObject}, }; -use sp_blockchain::Error as BlockchainError; /// ChainHead RPC errors. #[derive(Debug, thiserror::Error)] @@ -30,44 +29,55 @@ pub enum Error { /// The provided block hash is invalid. #[error("Invalid block hash")] InvalidBlock, - /// Fetch block header error. - #[error("Could not fetch block header: {0}")] - FetchBlockHeader(BlockchainError), + /// The follow subscription was started with `withRuntime` set to `false`. + #[error("The `chainHead_follow` subscription was started with `withRuntime` set to `false`")] + InvalidRuntimeCall(String), + /// Wait-for-continue event not generated. + #[error("Wait for continue event was not generated for the subscription")] + InvalidContinue, /// Invalid parameter provided to the RPC method. #[error("Invalid parameter: {0}")] InvalidParam(String), - /// Invalid subscription ID provided by the RPC server. - #[error("Invalid subscription ID")] - InvalidSubscriptionID, + /// Internal error. + #[error("Internal error: {0}")] + InternalError(String), +} + +/// Errors for `chainHead` RPC module, as defined in +/// . +pub mod rpc_spec_v2 { + /// The provided block hash is invalid. + pub const INVALID_BLOCK_ERROR: i32 = -32801; + /// The follow subscription was started with `withRuntime` set to `false`. + pub const INVALID_RUNTIME_CALL: i32 = -32802; /// Wait-for-continue event not generated. - #[error("Wait for continue event was not generated for the subscription")] - InvalidContinue, + pub const INVALID_CONTINUE: i32 = -32803; } -// Base code for all `chainHead` errors. -const BASE_ERROR: i32 = 2000; -/// The provided block hash is invalid. -const INVALID_BLOCK_ERROR: i32 = BASE_ERROR + 1; -/// Fetch block header error. -const FETCH_BLOCK_HEADER_ERROR: i32 = BASE_ERROR + 2; -/// Invalid parameter error. -const INVALID_PARAM_ERROR: i32 = BASE_ERROR + 3; -/// Invalid subscription ID. -const INVALID_SUB_ID: i32 = BASE_ERROR + 4; -/// Wait-for-continue event not generated. -const INVALID_CONTINUE: i32 = BASE_ERROR + 5; +/// General purpose errors, as defined in +/// . +pub mod json_rpc_spec { + /// Invalid parameter error. + pub const INVALID_PARAM_ERROR: i32 = -32602; + /// Internal error. + pub const INTERNAL_ERROR: i32 = -32603; +} impl From for ErrorObject<'static> { fn from(e: Error) -> Self { let msg = e.to_string(); match e { - Error::InvalidBlock => ErrorObject::owned(INVALID_BLOCK_ERROR, msg, None::<()>), - Error::FetchBlockHeader(_) => - ErrorObject::owned(FETCH_BLOCK_HEADER_ERROR, msg, None::<()>), - Error::InvalidParam(_) => ErrorObject::owned(INVALID_PARAM_ERROR, msg, None::<()>), - Error::InvalidSubscriptionID => ErrorObject::owned(INVALID_SUB_ID, msg, None::<()>), - Error::InvalidContinue => ErrorObject::owned(INVALID_CONTINUE, msg, None::<()>), + Error::InvalidBlock => + ErrorObject::owned(rpc_spec_v2::INVALID_BLOCK_ERROR, msg, None::<()>), + Error::InvalidRuntimeCall(_) => + ErrorObject::owned(rpc_spec_v2::INVALID_RUNTIME_CALL, msg, None::<()>), + Error::InvalidContinue => + ErrorObject::owned(rpc_spec_v2::INVALID_CONTINUE, msg, None::<()>), + Error::InvalidParam(_) => + ErrorObject::owned(json_rpc_spec::INVALID_PARAM_ERROR, msg, None::<()>), + Error::InternalError(_) => + ErrorObject::owned(json_rpc_spec::INTERNAL_ERROR, msg, None::<()>), } } } 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 518b7da432b..c8f2362b9eb 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -360,7 +360,7 @@ async fn get_header() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Obtain the valid header. @@ -389,7 +389,7 @@ async fn get_body() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call. @@ -474,7 +474,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Pass an invalid parameters that cannot be decode. @@ -487,7 +487,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("Invalid parameter") + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message().contains("Invalid parameter") ); // Valid call. @@ -590,7 +590,7 @@ async fn call_runtime_without_flag() { .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("The runtime updates flag must be set") + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_RUNTIME_CALL && err.message().contains("subscription was started with `withRuntime` set to `false`") ); } @@ -628,7 +628,7 @@ async fn get_storage_hash() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -896,7 +896,7 @@ async fn get_storage_value() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -1571,7 +1571,7 @@ async fn follow_with_unpin() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // To not exceed the number of pinned blocks, we need to unpin before the next import. @@ -1720,7 +1720,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let _res: () = api @@ -1737,7 +1737,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Unpin multiple blocks. @@ -1755,7 +1755,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let err = api @@ -1766,7 +1766,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); } -- GitLab From c68ce6e1472be821343ba7057857bec5626dc791 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:19:44 +0100 Subject: [PATCH 619/633] state-db: log_target usage fixed (#2547) Use `LOG_TARGET/LOG_TARGET_PIN` in logs. --- substrate/client/state-db/src/lib.rs | 6 +++--- substrate/client/state-db/src/pruning.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/client/state-db/src/lib.rs b/substrate/client/state-db/src/lib.rs index c656f126ae6..41c231c31aa 100644 --- a/substrate/client/state-db/src/lib.rs +++ b/substrate/client/state-db/src/lib.rs @@ -474,7 +474,7 @@ impl StateDbSync { if have_block { let refs = self.pinned.entry(hash.clone()).or_default(); if *refs == 0 { - trace!(target: "state-db-pin", "Pinned block: {:?}", hash); + trace!(target: LOG_TARGET_PIN, "Pinned block: {:?}", hash); self.non_canonical.pin(hash); } *refs += 1; @@ -491,11 +491,11 @@ impl StateDbSync { Entry::Occupied(mut entry) => { *entry.get_mut() -= 1; if *entry.get() == 0 { - trace!(target: "state-db-pin", "Unpinned block: {:?}", hash); + trace!(target: LOG_TARGET_PIN, "Unpinned block: {:?}", hash); entry.remove(); self.non_canonical.unpin(hash); } else { - trace!(target: "state-db-pin", "Releasing reference for {:?}", hash); + trace!(target: LOG_TARGET_PIN, "Releasing reference for {:?}", hash); } }, Entry::Vacant(_) => {}, diff --git a/substrate/client/state-db/src/pruning.rs b/substrate/client/state-db/src/pruning.rs index 623d30b098b..ae8a9a12490 100644 --- a/substrate/client/state-db/src/pruning.rs +++ b/substrate/client/state-db/src/pruning.rs @@ -385,7 +385,7 @@ impl RefWindow { /// Prune next block. Expects at least one block in the window. Adds changes to `commit`. pub fn prune_one(&mut self, commit: &mut CommitSet) -> Result<(), Error> { if let Some(pruned) = self.queue.pop_front(self.base)? { - trace!(target: "state-db", "Pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); + trace!(target: LOG_TARGET, "Pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); let index = self.base; commit.data.deleted.extend(pruned.deleted.into_iter()); commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), index.encode())); @@ -393,7 +393,7 @@ impl RefWindow { self.base += 1; Ok(()) } else { - trace!(target: "state-db", "Trying to prune when there's nothing to prune"); + trace!(target: LOG_TARGET, "Trying to prune when there's nothing to prune"); Err(Error::StateDb(StateDbError::BlockUnavailable)) } } @@ -418,7 +418,7 @@ impl RefWindow { return Err(Error::StateDb(StateDbError::InvalidBlockNumber)) } trace!( - target: "state-db", + target: LOG_TARGET, "Adding to pruning window: {:?} ({} inserted, {} deleted)", hash, commit.data.inserted.len(), -- GitLab From f69069bd4202ae35b2022fe4b78963197ecfcbc0 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Wed, 29 Nov 2023 15:27:04 -0500 Subject: [PATCH 620/633] Parachain Template: Prune `AuxStore` bound and corresponding crate dependency (#2303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This small PR removes an unnecessary trait bound to the `AuxStore` trait from the Parachain template's `rpc.rs` file. With that bound removed, the entire dependency on `sc-client-api` can also be removed. --------- Co-authored-by: Joshy Orndorff Co-authored-by: Bastian Köcher --- cumulus/parachain-template/node/src/rpc.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/cumulus/parachain-template/node/src/rpc.rs b/cumulus/parachain-template/node/src/rpc.rs index b5ca484fa48..ed4003ed6d2 100644 --- a/cumulus/parachain-template/node/src/rpc.rs +++ b/cumulus/parachain-template/node/src/rpc.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce}; -use sc_client_api::AuxStore; pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; @@ -36,7 +35,6 @@ pub fn create_full( where C: ProvideRuntimeApi + HeaderBackend - + AuxStore + HeaderMetadata + Send + Sync -- GitLab From 2135fa872b810799e997657cc621579e703774ca Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Wed, 29 Nov 2023 22:12:19 +0100 Subject: [PATCH 621/633] Contracts: use compiled rust tests (#2347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit see #2189 This PR does the following: - Bring the user api functions into a new pallet-contracts-uapi (They are currently defined in ink! [here])(https://github.com/paritytech/ink/blob/master/crates/env/src/engine/on_chain/ext.rs) - Add older api versions and unstable to the user api trait. - Remove pallet-contracts-primitives and bring the types it defined in uapi / pallet-contracts - Add the infrastructure to build fixtures from Rust files and test it works by replacing `dummy.wat` and `call.wat` - Move all the doc from wasm/runtime.rs to pallet-contracts-uapi. This will be done in a follow up: - convert the rest of the test from .wat to rust - bring risc-v uapi up to date with wasm - finalize the uapi host fns, making sure everything is codegen from the source host fns in pallet-contracts --------- Co-authored-by: Alexander Theißen --- Cargo.lock | 92 +- Cargo.toml | 3 +- .../contracts/contracts-rococo/Cargo.toml | 2 - .../contracts/contracts-rococo/src/lib.rs | 10 +- substrate/bin/node/runtime/Cargo.toml | 2 - substrate/bin/node/runtime/src/lib.rs | 10 +- substrate/frame/contracts/Cargo.toml | 4 +- substrate/frame/contracts/build.rs | 1 - substrate/frame/contracts/fixtures/Cargo.toml | 16 +- substrate/frame/contracts/fixtures/build.rs | 277 ++++++ .../contracts/fixtures/contracts/call.rs | 48 + .../fixtures/contracts/common/Cargo.toml | 9 + .../fixtures/contracts/common/src/lib.rs | 31 + .../contracts/fixtures/contracts/dummy.rs | 26 + .../frame/contracts/fixtures/data/call.wat | 39 - .../frame/contracts/fixtures/data/dummy.wat | 6 - substrate/frame/contracts/fixtures/src/lib.rs | 40 +- .../frame/contracts/mock-network/Cargo.toml | 3 +- .../frame/contracts/mock-network/src/tests.rs | 3 +- .../frame/contracts/primitives/Cargo.toml | 33 - .../frame/contracts/primitives/README.md | 3 - .../frame/contracts/proc-macro/src/lib.rs | 12 +- .../frame/contracts/src/benchmarking/mod.rs | 2 +- .../frame/contracts/src/chain_extension.rs | 2 +- substrate/frame/contracts/src/debug.rs | 6 +- substrate/frame/contracts/src/exec.rs | 4 +- substrate/frame/contracts/src/lib.rs | 8 +- .../src/lib.rs => src/primitives.rs} | 15 +- substrate/frame/contracts/src/tests.rs | 4 +- .../frame/contracts/src/tests/test_debug.rs | 2 +- substrate/frame/contracts/src/wasm/mod.rs | 23 +- substrate/frame/contracts/src/wasm/runtime.rs | 908 +++--------------- substrate/frame/contracts/uapi/Cargo.toml | 23 + substrate/frame/contracts/uapi/src/flags.rs | 73 ++ substrate/frame/contracts/uapi/src/host.rs | 793 +++++++++++++++ .../frame/contracts/uapi/src/host/riscv32.rs | 14 + .../frame/contracts/uapi/src/host/wasm32.rs | 811 ++++++++++++++++ substrate/frame/contracts/uapi/src/lib.rs | 139 +++ 38 files changed, 2520 insertions(+), 977 deletions(-) create mode 100644 substrate/frame/contracts/fixtures/build.rs create mode 100644 substrate/frame/contracts/fixtures/contracts/call.rs create mode 100644 substrate/frame/contracts/fixtures/contracts/common/Cargo.toml create mode 100644 substrate/frame/contracts/fixtures/contracts/common/src/lib.rs create mode 100644 substrate/frame/contracts/fixtures/contracts/dummy.rs delete mode 100644 substrate/frame/contracts/fixtures/data/call.wat delete mode 100644 substrate/frame/contracts/fixtures/data/dummy.wat delete mode 100644 substrate/frame/contracts/primitives/Cargo.toml delete mode 100644 substrate/frame/contracts/primitives/README.md rename substrate/frame/contracts/{primitives/src/lib.rs => src/primitives.rs} (96%) create mode 100644 substrate/frame/contracts/uapi/Cargo.toml create mode 100644 substrate/frame/contracts/uapi/src/flags.rs create mode 100644 substrate/frame/contracts/uapi/src/host.rs create mode 100644 substrate/frame/contracts/uapi/src/host/riscv32.rs create mode 100644 substrate/frame/contracts/uapi/src/host/wasm32.rs create mode 100644 substrate/frame/contracts/uapi/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f94c87dad48..346ce2f933f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2834,7 +2834,6 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "pallet-contracts", - "pallet-contracts-primitives", "pallet-insecure-randomness-collective-flip", "pallet-message-queue", "pallet-multisig", @@ -6828,7 +6827,6 @@ dependencies = [ "pallet-child-bounties", "pallet-collective", "pallet-contracts", - "pallet-contracts-primitives", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-democracy", @@ -8465,7 +8463,7 @@ dependencies = [ "itertools 0.10.5", "tar", "tempfile", - "toml_edit", + "toml_edit 0.19.14", ] [[package]] @@ -9380,8 +9378,8 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-contracts-fixtures", - "pallet-contracts-primitives", "pallet-contracts-proc-macro", + "pallet-contracts-uapi", "pallet-insecure-randomness-collective-flip", "pallet-message-queue", "pallet-proxy", @@ -9412,11 +9410,21 @@ dependencies = [ name = "pallet-contracts-fixtures" version = "1.0.0" dependencies = [ + "anyhow", + "cfg-if", "frame-system", + "parity-wasm", "sp-runtime", + "tempfile", + "toml 0.8.8", + "twox-hash", "wat", ] +[[package]] +name = "pallet-contracts-fixtures-common" +version = "1.0.0" + [[package]] name = "pallet-contracts-mock-network" version = "1.0.0" @@ -9428,8 +9436,8 @@ dependencies = [ "pallet-balances", "pallet-contracts", "pallet-contracts-fixtures", - "pallet-contracts-primitives", "pallet-contracts-proc-macro", + "pallet-contracts-uapi", "pallet-insecure-randomness-collective-flip", "pallet-message-queue", "pallet-proxy", @@ -9455,18 +9463,6 @@ dependencies = [ "xcm-simulator", ] -[[package]] -name = "pallet-contracts-primitives" -version = "24.0.0" -dependencies = [ - "bitflags 1.3.2", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std 8.0.0", - "sp-weights", -] - [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" @@ -9476,6 +9472,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "pallet-contracts-uapi" +version = "4.0.0-dev" +dependencies = [ + "bitflags 1.3.2", + "parity-scale-codec", + "paste", + "scale-info", +] + [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" @@ -13415,7 +13421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.14", ] [[package]] @@ -13878,6 +13884,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -16400,9 +16415,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -18758,13 +18773,13 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.0", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -19227,14 +19242,26 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.14", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -19252,6 +19279,19 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" diff --git a/Cargo.toml b/Cargo.toml index e154c2f3bc8..ac474ae5686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -283,8 +283,9 @@ members = [ "substrate/frame/collective", "substrate/frame/contracts", "substrate/frame/contracts/fixtures", + "substrate/frame/contracts/fixtures/contracts/common", + "substrate/frame/contracts/uapi", "substrate/frame/contracts/mock-network", - "substrate/frame/contracts/primitives", "substrate/frame/contracts/proc-macro", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index eded360436b..f5626a90f36 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -52,7 +52,6 @@ pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/ pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false} pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} pallet-contracts = { path = "../../../../../substrate/frame/contracts", default-features = false} -pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts/primitives", default-features = false} # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } @@ -102,7 +101,6 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", - "pallet-contracts-primitives/std", "pallet-contracts/std", "pallet-insecure-randomness-collective-flip/std", "pallet-message-queue/std", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index a7c06103c4a..77bc93fb968 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -588,7 +588,7 @@ impl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> pallet_contracts_primitives::ContractExecResult { + ) -> pallet_contracts::ContractExecResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); Contracts::bare_call( origin, @@ -608,10 +608,10 @@ impl_runtime_apis! { value: Balance, gas_limit: Option, storage_deposit_limit: Option, - code: pallet_contracts_primitives::Code, + code: pallet_contracts::Code, data: Vec, salt: Vec, - ) -> pallet_contracts_primitives::ContractInstantiateResult { + ) -> pallet_contracts::ContractInstantiateResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); Contracts::bare_instantiate( origin, @@ -631,7 +631,7 @@ impl_runtime_apis! { code: Vec, storage_deposit_limit: Option, determinism: pallet_contracts::Determinism, - ) -> pallet_contracts_primitives::CodeUploadResult { + ) -> pallet_contracts::CodeUploadResult { Contracts::bare_upload_code( origin, code, @@ -643,7 +643,7 @@ impl_runtime_apis! { fn get_storage( address: AccountId, key: Vec, - ) -> pallet_contracts_primitives::GetStorageResult { + ) -> pallet_contracts::GetStorageResult { Contracts::get_storage(address, key) } } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 2414358b60b..cb4970e7c9d 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -74,7 +74,6 @@ pallet-broker = { path = "../../../frame/broker", default-features = false} pallet-child-bounties = { path = "../../../frame/child-bounties", default-features = false} pallet-collective = { path = "../../../frame/collective", default-features = false} pallet-contracts = { path = "../../../frame/contracts", default-features = false} -pallet-contracts-primitives = { path = "../../../frame/contracts/primitives", default-features = false} pallet-conviction-voting = { path = "../../../frame/conviction-voting", default-features = false} pallet-core-fellowship = { path = "../../../frame/core-fellowship", default-features = false} pallet-democracy = { path = "../../../frame/democracy", default-features = false} @@ -171,7 +170,6 @@ std = [ "pallet-broker/std", "pallet-child-bounties/std", "pallet-collective/std", - "pallet-contracts-primitives/std", "pallet-contracts/std", "pallet-conviction-voting/std", "pallet-core-fellowship/std", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d7beb29becf..e2746b1c35b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2497,7 +2497,7 @@ impl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> pallet_contracts_primitives::ContractExecResult { + ) -> pallet_contracts::ContractExecResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); Contracts::bare_call( origin, @@ -2517,10 +2517,10 @@ impl_runtime_apis! { value: Balance, gas_limit: Option, storage_deposit_limit: Option, - code: pallet_contracts_primitives::Code, + code: pallet_contracts::Code, data: Vec, salt: Vec, - ) -> pallet_contracts_primitives::ContractInstantiateResult + ) -> pallet_contracts::ContractInstantiateResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); Contracts::bare_instantiate( @@ -2541,7 +2541,7 @@ impl_runtime_apis! { code: Vec, storage_deposit_limit: Option, determinism: pallet_contracts::Determinism, - ) -> pallet_contracts_primitives::CodeUploadResult + ) -> pallet_contracts::CodeUploadResult { Contracts::bare_upload_code( origin, @@ -2554,7 +2554,7 @@ impl_runtime_apis! { fn get_storage( address: AccountId, key: Vec, - ) -> pallet_contracts_primitives::GetStorageResult { + ) -> pallet_contracts::GetStorageResult { Contracts::get_storage( address, key diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 239b0865e0f..417f719d803 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -40,7 +40,7 @@ frame-benchmarking = { path = "../benchmarking", default-features = false, optio frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-balances = { path = "../balances", default-features = false , optional = true} -pallet-contracts-primitives = { path = "primitives", default-features = false} +pallet-contracts-uapi = { path = "uapi" } pallet-contracts-proc-macro = { path = "proc-macro" } sp-api = { path = "../../primitives/api", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} @@ -83,8 +83,6 @@ std = [ "frame-system/std", "log/std", "pallet-balances?/std", - "pallet-contracts-fixtures/std", - "pallet-contracts-primitives/std", "pallet-contracts-proc-macro/full", "pallet-insecure-randomness-collective-flip/std", "pallet-proxy/std", diff --git a/substrate/frame/contracts/build.rs b/substrate/frame/contracts/build.rs index 42bc45d563d..83d5d368d4b 100644 --- a/substrate/frame/contracts/build.rs +++ b/substrate/frame/contracts/build.rs @@ -68,6 +68,5 @@ fn main() -> Result<(), Box> { version - 1, )?; - println!("cargo:rerun-if-changed=src/migration"); Ok(()) } diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index b44f36f2a5f..257e01e50fa 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -9,10 +9,16 @@ description = "Fixtures for testing contracts pallet." [dependencies] wat = "1" -frame-system = { path = "../../system", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} +frame-system = { path = "../../system" } +sp-runtime = { path = "../../../primitives/runtime" } +anyhow = "1.0.0" + +[build-dependencies] +parity-wasm = "0.45.0" +tempfile = "3.8.1" +toml = "0.8.8" +twox-hash = "1.6.3" +anyhow = "1.0.0" +cfg-if = { version = "1.0", default-features = false } -[features] -default = [ "std" ] -std = [ "frame-system/std", "sp-runtime/std" ] diff --git a/substrate/frame/contracts/fixtures/build.rs b/substrate/frame/contracts/fixtures/build.rs new file mode 100644 index 00000000000..ada2650c6db --- /dev/null +++ b/substrate/frame/contracts/fixtures/build.rs @@ -0,0 +1,277 @@ +// 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. + +//! Compile contracts to wasm and RISC-V binaries. +use anyhow::Result; +use parity_wasm::elements::{deserialize_file, serialize_to_file, Internal}; +use std::{ + env, fs, + hash::Hasher, + path::{Path, PathBuf}, + process::Command, +}; +use twox_hash::XxHash32; + +/// Read the file at `path` and return its hash as a hex string. +fn file_hash(path: &Path) -> String { + let data = fs::read(path).expect("file exists; qed"); + let mut hasher = XxHash32::default(); + hasher.write(&data); + hasher.write(include_bytes!("build.rs")); + let hash = hasher.finish(); + format!("{:x}", hash) +} + +/// A contract entry. +struct Entry { + /// The path to the contract source file. + path: PathBuf, + /// The hash of the contract source file. + hash: String, +} + +impl Entry { + /// Create a new contract entry from the given path. + fn new(path: PathBuf) -> Self { + let hash = file_hash(&path); + Self { path, hash } + } + + /// Return the path to the contract source file. + fn path(&self) -> &str { + self.path.to_str().expect("path is valid unicode; qed") + } + + /// Return the name of the contract. + fn name(&self) -> &str { + self.path + .file_stem() + .expect("file exits; qed") + .to_str() + .expect("name is valid unicode; qed") + } + + /// Return the name of the output wasm file. + fn out_wasm_filename(&self) -> String { + format!("{}.wasm", self.name()) + } +} + +/// Collect all contract entries from the given source directory. +/// Contracts that have already been compiled are filtered out. +fn collect_entries(contracts_dir: &Path, out_dir: &Path) -> Vec { + fs::read_dir(&contracts_dir) + .expect("src dir exists; qed") + .filter_map(|file| { + let path = file.expect("file exists; qed").path(); + if path.extension().map_or(true, |ext| ext != "rs") { + return None; + } + + let entry = Entry::new(path); + if out_dir.join(&entry.hash).exists() { + None + } else { + Some(entry) + } + }) + .collect::>() +} + +/// Create a `Cargo.toml` to compile the given contract entries. +fn create_cargo_toml<'a>( + fixtures_dir: &Path, + entries: impl Iterator, + output_dir: &Path, +) -> Result<()> { + let uapi_path = fixtures_dir.join("../uapi").canonicalize()?; + let common_path = fixtures_dir.join("./contracts/common").canonicalize()?; + let mut cargo_toml: toml::Value = toml::from_str(&format!( + " +[package] +name = 'contracts' +version = '0.1.0' +edition = '2021' + +# Binary targets are injected below. +[[bin]] + +[dependencies] +uapi = {{ package = 'pallet-contracts-uapi', default-features = false, path = {uapi_path:?}}} +common = {{ package = 'pallet-contracts-fixtures-common', path = {common_path:?}}} + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +" + ))?; + + let binaries = entries + .map(|entry| { + let name = entry.name(); + let path = entry.path(); + toml::Value::Table(toml::toml! { + name = name + path = path + }) + }) + .collect::>(); + + cargo_toml["bin"] = toml::Value::Array(binaries); + let cargo_toml = toml::to_string_pretty(&cargo_toml)?; + fs::write(output_dir.join("Cargo.toml"), cargo_toml).map_err(Into::into) +} + +/// Invoke `cargo fmt` to check that fixtures files are formatted. +fn invoke_cargo_fmt<'a>( + config_path: &Path, + files: impl Iterator, + contract_dir: &Path, +) -> Result<()> { + // If rustfmt is not installed, skip the check. + if !Command::new("rustup") + .args(&["run", "nightly", "rustfmt", "--version"]) + .output() + .expect("failed to execute process") + .status + .success() + { + return Ok(()) + } + + let fmt_res = Command::new("rustup") + .args(&["run", "nightly", "rustfmt", "--check", "--config-path"]) + .arg(config_path) + .args(files) + .output() + .expect("failed to execute process"); + + if fmt_res.status.success() { + return Ok(()) + } + + let stdout = String::from_utf8_lossy(&fmt_res.stdout); + let stderr = String::from_utf8_lossy(&fmt_res.stderr); + eprintln!("{}\n{}", stdout, stderr); + eprintln!( + "Fixtures files are not formatted.\nPlease run `rustup run nightly rustfmt --config-path {} {}/*.rs`", + config_path.display(), + contract_dir.display() + ); + anyhow::bail!("Fixtures files are not formatted") +} + +/// Invoke `cargo build` to compile the contracts. +fn invoke_build(current_dir: &Path) -> Result<()> { + let encoded_rustflags = [ + "-Clink-arg=-zstack-size=65536", + "-Clink-arg=--import-memory", + "-Clinker-plugin-lto", + "-Ctarget-cpu=mvp", + "-Dwarnings", + ] + .join("\x1f"); + + let build_res = Command::new(env::var("CARGO")?) + .current_dir(current_dir) + .env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags) + .args(&["build", "--release", "--target=wasm32-unknown-unknown"]) + .output() + .expect("failed to execute process"); + + if build_res.status.success() { + return Ok(()) + } + + let stderr = String::from_utf8_lossy(&build_res.stderr); + eprintln!("{}", stderr); + anyhow::bail!("Failed to build contracts"); +} + +/// Post-process the compiled wasm contracts. +fn post_process_wasm(input_path: &Path, output_path: &Path) -> Result<()> { + let mut module = deserialize_file(input_path)?; + if let Some(section) = module.export_section_mut() { + section.entries_mut().retain(|entry| { + matches!(entry.internal(), Internal::Function(_)) && + (entry.field() == "call" || entry.field() == "deploy") + }); + } + + serialize_to_file(output_path, module).map_err(Into::into) +} + +/// Write the compiled contracts to the given output directory. +fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec) -> Result<()> { + for entry in entries { + let wasm_output = entry.out_wasm_filename(); + post_process_wasm( + &build_dir.join("target/wasm32-unknown-unknown/release").join(&wasm_output), + &out_dir.join(&wasm_output), + )?; + fs::write(out_dir.join(&entry.hash), "")?; + } + + Ok(()) +} + +/// Returns the root path of the wasm workspace. +fn find_workspace_root(current_dir: &Path) -> Option { + let mut current_dir = current_dir.to_path_buf(); + + while current_dir.parent().is_some() { + if current_dir.join("Cargo.toml").exists() { + let cargo_toml_contents = + std::fs::read_to_string(current_dir.join("Cargo.toml")).ok()?; + if cargo_toml_contents.contains("[workspace]") { + return Some(current_dir); + } + } + + current_dir.pop(); + } + + None +} + +fn main() -> Result<()> { + let fixtures_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into(); + let contracts_dir = fixtures_dir.join("contracts"); + let out_dir: PathBuf = env::var("OUT_DIR")?.into(); + let workspace_root = find_workspace_root(&fixtures_dir).expect("workspace root exists; qed"); + + let entries = collect_entries(&contracts_dir, &out_dir); + if entries.is_empty() { + return Ok(()); + } + + let tmp_dir = tempfile::tempdir()?; + let tmp_dir_path = tmp_dir.path(); + + create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?; + invoke_cargo_fmt( + &workspace_root.join(".rustfmt.toml"), + entries.iter().map(|entry| &entry.path as _), + &contracts_dir, + )?; + + invoke_build(tmp_dir_path)?; + write_output(tmp_dir_path, &out_dir, entries)?; + + Ok(()) +} diff --git a/substrate/frame/contracts/fixtures/contracts/call.rs b/substrate/frame/contracts/fixtures/contracts/call.rs new file mode 100644 index 00000000000..396b71d5e96 --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/call.rs @@ -0,0 +1,48 @@ +// 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 calls another contract as passed as its account id. +#![no_std] +#![no_main] + +extern crate common; +use uapi::{CallFlags, HostFn, HostFnImpl as api}; + +#[no_mangle] +pub extern "C" fn deploy() {} + +#[no_mangle] +pub extern "C" fn call() { + let mut buffer = [0u8; 40]; + let callee_input = 0..4; + let callee_addr = 4..36; + let value = 36..40; + + // Read the input data. + api::input(&mut &mut buffer[..]); + + // Call the callee + api::call_v1( + CallFlags::empty(), + &buffer[callee_addr], + 0u64, // How much gas to devote for the execution. 0 = all. + &buffer[value], + &buffer[callee_input], + None, + ) + .unwrap(); +} diff --git a/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml new file mode 100644 index 00000000000..b70db7cde45 --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "pallet-contracts-fixtures-common" +publish = false +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +description = "Common utilities for pallet-contracts-fixtures." + diff --git a/substrate/frame/contracts/fixtures/contracts/common/src/lib.rs b/substrate/frame/contracts/fixtures/contracts/common/src/lib.rs new file mode 100644 index 00000000000..29bdbfbb042 --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/common/src/lib.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![no_std] +#![cfg(any(target_arch = "wasm32", target_arch = "riscv32"))] + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + #[cfg(target_arch = "wasm32")] + core::arch::wasm32::unreachable(); + + #[cfg(target_arch = "riscv32")] + // Safety: The unimp instruction is guaranteed to trap + unsafe { + core::arch::asm!("unimp"); + core::hint::unreachable_unchecked(); + } +} diff --git a/substrate/frame/contracts/fixtures/contracts/dummy.rs b/substrate/frame/contracts/fixtures/contracts/dummy.rs new file mode 100644 index 00000000000..98b9d494bbc --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/dummy.rs @@ -0,0 +1,26 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![no_std] +#![no_main] + +extern crate common; + +#[no_mangle] +pub extern "C" fn deploy() {} + +#[no_mangle] +pub extern "C" fn call() {} diff --git a/substrate/frame/contracts/fixtures/data/call.wat b/substrate/frame/contracts/fixtures/data/call.wat deleted file mode 100644 index 43b32049c88..00000000000 --- a/substrate/frame/contracts/fixtures/data/call.wat +++ /dev/null @@ -1,39 +0,0 @@ -;; This calls another contract as passed as its account id. -(module - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) - (import "env" "memory" (memory 1 1)) - - (func $assert (param i32) - (block $ok - (br_if $ok - (local.get 0) - ) - (unreachable) - ) - ) - - (func (export "deploy")) - - (func (export "call") - ;; Store length of input buffer. - (i32.store (i32.const 0) (i32.const 512)) - - ;; Copy input at address 4. - (call $seal_input (i32.const 4) (i32.const 0)) - - ;; Call passed contract. - (call $assert (i32.eqz - (call $seal_call - (i32.const 0) ;; No flags - (i32.const 8) ;; Pointer to "callee" address. - (i64.const 0) ;; How much gas to devote for the execution. 0 = all. - (i32.const 512) ;; Pointer to the buffer with value to transfer - (i32.const 4) ;; Pointer to input data buffer address - (i32.const 4) ;; Length of input data buffer - (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output - (i32.const 0) ;; Length is ignored in this case - ) - )) - ) -) diff --git a/substrate/frame/contracts/fixtures/data/dummy.wat b/substrate/frame/contracts/fixtures/data/dummy.wat deleted file mode 100644 index a6435e49df2..00000000000 --- a/substrate/frame/contracts/fixtures/data/dummy.wat +++ /dev/null @@ -1,6 +0,0 @@ -;; A valid contract which does nothing at all -(module - (import "env" "memory" (memory 1 1)) - (func (export "deploy")) - (func (export "call")) -) diff --git a/substrate/frame/contracts/fixtures/src/lib.rs b/substrate/frame/contracts/fixtures/src/lib.rs index 48117f7ca94..fbc2647709d 100644 --- a/substrate/frame/contracts/fixtures/src/lib.rs +++ b/substrate/frame/contracts/fixtures/src/lib.rs @@ -16,9 +16,9 @@ // limitations under the License. use sp_runtime::traits::Hash; -use std::{env::var, path::PathBuf}; +use std::{env::var, fs, path::PathBuf}; -fn fixtures_root_dir() -> PathBuf { +fn wat_root_dir() -> PathBuf { match (var("CARGO_MANIFEST_DIR"), var("CARGO_PKG_NAME")) { // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder (Err(_), _) => "substrate/frame/contracts/fixtures/data".into(), @@ -33,12 +33,44 @@ fn fixtures_root_dir() -> PathBuf { /// with it's hash. /// /// The fixture files are located under the `fixtures/` directory. -pub fn compile_module(fixture_name: &str) -> wat::Result<(Vec, ::Output)> +fn legacy_compile_module( + fixture_name: &str, +) -> anyhow::Result<(Vec, ::Output)> where T: frame_system::Config, { - let fixture_path = fixtures_root_dir().join(format!("{fixture_name}.wat")); + let fixture_path = wat_root_dir().join(format!("{fixture_name}.wat")); let wasm_binary = wat::parse_file(fixture_path)?; let code_hash = T::Hashing::hash(&wasm_binary); Ok((wasm_binary, code_hash)) } + +/// Load a given wasm module and returns a wasm binary contents along with it's hash. +/// Use the legacy compile_module as fallback, if the rust fixture does not exist yet. +pub fn compile_module( + fixture_name: &str, +) -> anyhow::Result<(Vec, ::Output)> +where + T: frame_system::Config, +{ + let out_dir: std::path::PathBuf = env!("OUT_DIR").into(); + let fixture_path = out_dir.join(format!("{fixture_name}.wasm")); + match fs::read(fixture_path) { + Ok(wasm_binary) => { + let code_hash = T::Hashing::hash(&wasm_binary); + Ok((wasm_binary, code_hash)) + }, + Err(_) => legacy_compile_module::(fixture_name), + } +} + +#[cfg(test)] +mod test { + #[test] + fn out_dir_should_have_compiled_mocks() { + let out_dir: std::path::PathBuf = env!("OUT_DIR").into(); + let dummy_wasm = out_dir.join("dummy.wasm"); + println!("dummy_wasm: {:?}", dummy_wasm); + assert!(dummy_wasm.exists()); + } +} diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 9d5fe1aaf4e..28e24dd15e4 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -16,7 +16,7 @@ frame-system = { path = "../../system", default-features = false} pallet-assets = { path = "../../assets" } pallet-balances = { path = "../../balances" } pallet-contracts = { path = ".." } -pallet-contracts-primitives = { path = "../primitives", default-features = false} +pallet-contracts-uapi = { path = "../uapi", default-features = false} pallet-contracts-proc-macro = { path = "../proc-macro" } pallet-insecure-randomness-collective-flip = { path = "../../insecure-randomness-collective-flip" } pallet-message-queue = { path = "../../message-queue" } @@ -52,7 +52,6 @@ std = [ "frame-support/std", "frame-system/std", "pallet-balances/std", - "pallet-contracts-primitives/std", "pallet-contracts-proc-macro/full", "pallet-contracts/std", "pallet-insecure-randomness-collective-flip/std", diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs index 5193f657055..a66b2b08019 100644 --- a/substrate/frame/contracts/mock-network/src/tests.rs +++ b/substrate/frame/contracts/mock-network/src/tests.rs @@ -29,9 +29,8 @@ use frame_support::{ traits::{fungibles::Mutate, Currency}, }; use pallet_balances::{BalanceLock, Reasons}; -use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; +use pallet_contracts::{Code, CollectEvents, DebugInfo, Determinism}; use pallet_contracts_fixtures::compile_module; -use pallet_contracts_primitives::Code; use xcm::{v3::prelude::*, VersionedMultiLocation, VersionedXcm}; use xcm_simulator::TestExt; diff --git a/substrate/frame/contracts/primitives/Cargo.toml b/substrate/frame/contracts/primitives/Cargo.toml deleted file mode 100644 index 0394841aa1f..00000000000 --- a/substrate/frame/contracts/primitives/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "pallet-contracts-primitives" -version = "24.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "A crate that hosts a common definitions that are relevant for the pallet-contracts." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -bitflags = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } - -# Substrate Dependencies (This crate should not rely on frame) -sp-std = { path = "../../../primitives/std", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-weights = { path = "../../../primitives/weights", default-features = false} - -[features] -default = [ "std" ] -std = [ - "codec/std", - "scale-info/std", - "sp-runtime/std", - "sp-std/std", - "sp-weights/std", -] diff --git a/substrate/frame/contracts/primitives/README.md b/substrate/frame/contracts/primitives/README.md deleted file mode 100644 index c84cfbfe1a8..00000000000 --- a/substrate/frame/contracts/primitives/README.md +++ /dev/null @@ -1,3 +0,0 @@ -A crate that hosts a common definitions that are relevant for the pallet-contracts. - -License: Apache-2.0 diff --git a/substrate/frame/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index ad9cd2dadec..4ef02497b8e 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -271,7 +271,7 @@ impl HostFn { // process return type let msg = r#"Should return one of the following: - Result<(), TrapReason>, - - Result, + - Result, - Result, - Result"#; let ret_ty = match item.clone().sig.output { @@ -336,7 +336,7 @@ impl HostFn { "()" => Ok(HostFnReturn::Unit), "u32" => Ok(HostFnReturn::U32), "u64" => Ok(HostFnReturn::U64), - "ReturnCode" => Ok(HostFnReturn::ReturnCode), + "ReturnErrorCode" => Ok(HostFnReturn::ReturnCode), _ => Err(err(arg1.span(), &msg)), }?; @@ -550,7 +550,7 @@ fn expand_env(def: &EnvDef, docs: bool) -> TokenStream2 { /// consumed by humans through rustdoc. #[cfg(doc)] pub mod api_doc { - use super::{TrapReason, ReturnCode}; + use super::{TrapReason, ReturnErrorCode}; #docs } } @@ -767,7 +767,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) /// #[define_env] /// pub mod some_env { /// #[version(2)] -/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// @@ -793,7 +793,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) /// pub mod some_env { /// #[version(1)] /// #[prefixed_alias] -/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// @@ -811,7 +811,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) /// /// Only following return types are allowed for the host functions defined with the macro: /// - `Result<(), TrapReason>`, -/// - `Result`, +/// - `Result`, /// - `Result`. /// /// The macro expands to `pub struct Env` declaration, with the following traits implementations: diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index ac5787e2340..c532b354ab6 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -33,7 +33,6 @@ use crate::{ migration::{ codegen::LATEST_MIGRATION_VERSION, v09, v10, v11, v12, v13, v14, v15, MigrationStep, }, - wasm::CallFlags, Pallet as Contracts, *, }; use codec::{Encode, MaxEncodedLen}; @@ -46,6 +45,7 @@ use frame_support::{ }; use frame_system::RawOrigin; use pallet_balances; +use pallet_contracts_uapi::CallFlags; use sp_runtime::traits::{Bounded, Hash}; use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::{BlockType, Instruction, ValueType}; diff --git a/substrate/frame/contracts/src/chain_extension.rs b/substrate/frame/contracts/src/chain_extension.rs index 664504d207f..8a7243d6bb3 100644 --- a/substrate/frame/contracts/src/chain_extension.rs +++ b/substrate/frame/contracts/src/chain_extension.rs @@ -81,7 +81,7 @@ use sp_std::{marker::PhantomData, vec::Vec}; pub use crate::{exec::Ext, gas::ChargedAmount, storage::meter::Diff, Config}; pub use frame_system::Config as SysConfig; -pub use pallet_contracts_primitives::ReturnFlags; +pub use pallet_contracts_uapi::ReturnFlags; /// Result that returns a [`DispatchError`] on error. pub type Result = sp_std::result::Result; diff --git a/substrate/frame/contracts/src/debug.rs b/substrate/frame/contracts/src/debug.rs index e22a841e6fb..6cdca7aa4c7 100644 --- a/substrate/frame/contracts/src/debug.rs +++ b/substrate/frame/contracts/src/debug.rs @@ -15,9 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use crate::exec::{ExecResult, ExportedFunction}; +pub use crate::{ + exec::{ExecResult, ExportedFunction}, + primitives::ExecReturnValue, +}; use crate::{Config, LOG_TARGET}; -pub use pallet_contracts_primitives::ExecReturnValue; /// Umbrella trait for all interfaces that serves for debugging. pub trait Debugger: Tracing + CallInterceptor {} diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index c26d82f7f11..2183d6b96cc 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -18,6 +18,7 @@ use crate::{ debug::{CallInterceptor, CallSpan, Tracing}, gas::GasMeter, + primitives::{ExecReturnValue, StorageDeposit}, storage::{self, meter::Diff, WriteOutcome}, BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error, Event, Nonce, Origin, Pallet as Contracts, Schedule, @@ -37,7 +38,6 @@ use frame_support::{ Blake2_128Concat, BoundedVec, StorageHasher, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use pallet_contracts_primitives::{ExecReturnValue, StorageDeposit}; use smallvec::{Array, SmallVec}; use sp_core::{ ecdsa::Public as ECDSAPublic, @@ -1618,7 +1618,7 @@ mod tests { use codec::{Decode, Encode}; use frame_support::{assert_err, assert_ok, parameter_types}; use frame_system::{EventRecord, Phase}; - use pallet_contracts_primitives::ReturnFlags; + use pallet_contracts_uapi::ReturnFlags; use pretty_assertions::assert_eq; use sp_runtime::{traits::Hash, DispatchError}; use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc}; diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 188679dbf49..a15006e6388 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -91,6 +91,9 @@ mod address; mod benchmarking; mod exec; mod gas; +mod primitives; +pub use primitives::*; + mod schedule; mod storage; mod wasm; @@ -128,11 +131,6 @@ use frame_system::{ pallet_prelude::{BlockNumberFor, OriginFor}, EventRecord, Pallet as System, }; -use pallet_contracts_primitives::{ - Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult, - ContractInstantiateResult, ContractResult, ExecReturnValue, GetStorageResult, - InstantiateReturnValue, StorageDeposit, -}; use scale_info::TypeInfo; use smallvec::Array; use sp_runtime::{ diff --git a/substrate/frame/contracts/primitives/src/lib.rs b/substrate/frame/contracts/src/primitives.rs similarity index 96% rename from substrate/frame/contracts/primitives/src/lib.rs rename to substrate/frame/contracts/src/primitives.rs index c3314928500..ab73b28e8c4 100644 --- a/substrate/frame/contracts/primitives/src/lib.rs +++ b/substrate/frame/contracts/src/primitives.rs @@ -17,17 +17,15 @@ //! A crate that hosts a common definitions that are relevant for the pallet-contracts. -#![cfg_attr(not(feature = "std"), no_std)] - -use bitflags::bitflags; use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::weights::Weight; +use pallet_contracts_uapi::ReturnFlags; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, }; use sp_std::prelude::*; -use sp_weights::Weight; /// Result type of a `bare_call` or `bare_instantiate` call as well as `ContractsApi::call` and /// `ContractsApi::instantiate`. @@ -109,15 +107,6 @@ pub enum ContractAccessError { MigrationInProgress, } -bitflags! { - /// Flags used by a contract to customize exit behaviour. - #[derive(Encode, Decode, TypeInfo)] - pub struct ReturnFlags: u32 { - /// If this bit is set all changes made by the contract execution are rolled back. - const REVERT = 0x0000_0001; - } -} - /// Output of a contract call or instantiation which ran to completion. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExecReturnValue { diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 79ad451964d..4f63104ef26 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -30,9 +30,10 @@ use crate::{ }, exec::{Frame, Key}, migration::codegen::LATEST_MIGRATION_VERSION, + primitives::CodeUploadReturnValue, storage::DeletionQueueManager, tests::test_utils::{get_contract, get_contract_checked}, - wasm::{Determinism, ReturnCode as RuntimeReturnCode}, + wasm::{Determinism, ReturnErrorCode as RuntimeReturnCode}, weights::WeightInfo, BalanceOf, Code, CodeHash, CodeInfoOf, CollectEvents, Config, ContractInfo, ContractInfoOf, DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, HoldReason, @@ -55,7 +56,6 @@ use frame_support::{ }; use frame_system::{EventRecord, Phase}; use pallet_contracts_fixtures::compile_module; -use pallet_contracts_primitives::CodeUploadReturnValue; use pretty_assertions::{assert_eq, assert_ne}; use sp_core::ByteArray; use sp_io::hashing::blake2_256; diff --git a/substrate/frame/contracts/src/tests/test_debug.rs b/substrate/frame/contracts/src/tests/test_debug.rs index 2d7ed474365..c9b6557bbb9 100644 --- a/substrate/frame/contracts/src/tests/test_debug.rs +++ b/substrate/frame/contracts/src/tests/test_debug.rs @@ -18,10 +18,10 @@ use super::*; use crate::{ debug::{CallInterceptor, CallSpan, ExecResult, ExportedFunction, Tracing}, + primitives::ExecReturnValue, AccountIdOf, }; use frame_support::traits::Currency; -use pallet_contracts_primitives::ExecReturnValue; use pretty_assertions::assert_eq; use std::cell::RefCell; diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index f73655e9920..448c0dd7496 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -24,13 +24,13 @@ mod runtime; #[cfg(doc)] pub use crate::wasm::runtime::api_doc; -#[cfg(test)] -pub use tests::MockExt; - pub use crate::wasm::runtime::{ - AllowDeprecatedInterface, AllowUnstableInterface, CallFlags, Environment, ReturnCode, Runtime, + AllowDeprecatedInterface, AllowUnstableInterface, Environment, ReturnErrorCode, Runtime, RuntimeCosts, }; +pub use pallet_contracts_uapi::ReturnFlags; +#[cfg(test)] +pub use tests::MockExt; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, @@ -436,6 +436,7 @@ mod tests { use crate::{ exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Ext, Key, SeedOf}, gas::GasMeter, + primitives::ExecReturnValue, storage::WriteOutcome, tests::{RuntimeCall, Test, ALICE, BOB}, BalanceOf, CodeHash, Error, Origin, Pallet as Contracts, @@ -445,7 +446,7 @@ mod tests { assert_err, assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; - use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; + use pallet_contracts_uapi::ReturnFlags; use pretty_assertions::assert_eq; use sp_core::H256; use sp_runtime::DispatchError; @@ -2739,7 +2740,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::KeyNotFound as u32 + ReturnErrorCode::KeyNotFound as u32 ); // value exists @@ -2747,7 +2748,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::Success as u32 + ReturnErrorCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); assert_eq!(&result.data[4..], &[42u8]); @@ -2757,7 +2758,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::Success as u32 + ReturnErrorCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![])); assert_eq!(&result.data[4..], &([] as [u8; 0])); @@ -2920,7 +2921,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::KeyNotFound as u32 + ReturnErrorCode::KeyNotFound as u32 ); // value did exist -> value returned @@ -2928,7 +2929,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::Success as u32 + ReturnErrorCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); assert_eq!(&result.data[4..], &[42u8]); @@ -2938,7 +2939,7 @@ mod tests { let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data[0..4].try_into().unwrap()), - ReturnCode::Success as u32 + ReturnErrorCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); assert_eq!(&result.data[4..], &[0u8; 0]); diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index b3013adb790..871ef05c37e 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -20,10 +20,10 @@ use crate::{ exec::{ExecError, ExecResult, Ext, Key, TopicOf}, gas::{ChargedAmount, Token}, + primitives::ExecReturnValue, schedule::HostFnWeights, BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL, }; -use bitflags::bitflags; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{ dispatch::DispatchInfo, @@ -33,8 +33,8 @@ use frame_support::{ traits::Get, weights::Weight, }; -use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; +use pallet_contracts_uapi::{CallFlags, ReturnFlags}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::{ traits::{Bounded, Zero}, @@ -87,55 +87,16 @@ enum KeyType { Var(u32), } -/// Every error that can be returned to a contract when it calls any of the host functions. -/// -/// # Note -/// -/// This enum can be extended in the future: New codes can be added but existing codes -/// will not be changed or removed. This means that any contract **must not** exhaustively -/// match return codes. Instead, contracts should prepare for unknown variants and deal with -/// those errors gracefully in order to be forward compatible. -#[derive(Debug)] -#[repr(u32)] -pub enum ReturnCode { - /// API call successful. - Success = 0, - /// The called function trapped and has its state changes reverted. - /// In this case no output buffer is returned. - CalleeTrapped = 1, - /// The called function ran to completion but decided to revert its state. - /// An output buffer is returned when one was supplied. - CalleeReverted = 2, - /// The passed key does not exist in storage. - KeyNotFound = 3, - /// See [`Error::TransferFailed`]. - TransferFailed = 5, - /// No code could be found at the supplied code hash. - CodeNotFound = 7, - /// The contract that was called is no contract (a plain account). - NotCallable = 8, - /// The call dispatched by `seal_call_runtime` was executed but returned an error. - CallRuntimeFailed = 10, - /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or - /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably - /// wrong pubkey provided). - EcdsaRecoverFailed = 11, - /// sr25519 signature verification failed. - Sr25519VerifyFailed = 12, - /// The `xcm_execute` call failed. - XcmExecutionFailed = 13, - /// The `xcm_send` call failed. - XcmSendFailed = 14, -} +pub use pallet_contracts_uapi::ReturnErrorCode; parameter_types! { /// Getter types used by [`crate::api_doc::Current::call_runtime`] - const CallRuntimeFailed: ReturnCode = ReturnCode::CallRuntimeFailed; + const CallRuntimeFailed: ReturnErrorCode = ReturnErrorCode::CallRuntimeFailed; /// Getter types used by [`crate::api_doc::Current::xcm_execute`] - const XcmExecutionFailed: ReturnCode = ReturnCode::XcmExecutionFailed; + const XcmExecutionFailed: ReturnErrorCode = ReturnErrorCode::XcmExecutionFailed; } -impl From for ReturnCode { +impl From for ReturnErrorCode { fn from(from: ExecReturnValue) -> Self { if from.flags.contains(ReturnFlags::REVERT) { Self::CalleeReverted @@ -145,12 +106,6 @@ impl From for ReturnCode { } } -impl From for u32 { - fn from(code: ReturnCode) -> u32 { - code as u32 - } -} - /// The data passed through when a contract uses `seal_return`. #[derive(RuntimeDebug)] pub struct ReturnData { @@ -411,52 +366,6 @@ impl Token for RuntimeToken { } } -bitflags! { - /// Flags used to change the behaviour of `seal_call` and `seal_delegate_call`. - pub struct CallFlags: u32 { - /// Forward the input of current function to the callee. - /// - /// Supplied input pointers are ignored when set. - /// - /// # Note - /// - /// A forwarding call will consume the current contracts input. Any attempt to - /// access the input after this call returns will lead to [`Error::InputForwarded`]. - /// It does not matter if this is due to calling `seal_input` or trying another - /// forwarding call. Consider using [`Self::CLONE_INPUT`] in order to preserve - /// the input. - const FORWARD_INPUT = 0b0000_0001; - /// Identical to [`Self::FORWARD_INPUT`] but without consuming the input. - /// - /// This adds some additional weight costs to the call. - /// - /// # Note - /// - /// This implies [`Self::FORWARD_INPUT`] and takes precedence when both are set. - const CLONE_INPUT = 0b0000_0010; - /// Do not return from the call but rather return the result of the callee to the - /// callers caller. - /// - /// # Note - /// - /// This makes the current contract completely transparent to its caller by replacing - /// this contracts potential output by the callee ones. Any code after `seal_call` - /// can be safely considered unreachable. - const TAIL_CALL = 0b0000_0100; - /// Allow the callee to reenter into the current contract. - /// - /// Without this flag any reentrancy into the current contract that originates from - /// the callee (or any of its callees) is denied. This includes the first callee: - /// You cannot call into yourself with this flag set. - /// - /// # Note - /// - /// For `seal_delegate_call` should be always unset, otherwise - /// [`Error::InvalidCallFlags`] is returned. - const ALLOW_REENTRY = 0b0000_1000; - } -} - /// The kind of call that should be performed. enum CallType { /// Execute another instantiated contract @@ -603,20 +512,20 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { /// Charge, Run and adjust gas, for executing the given dispatchable. fn call_dispatchable< - ErrorReturnCode: Get, + ErrorReturnCode: Get, F: FnOnce(&mut Self) -> DispatchResultWithPostInfo, >( &mut self, dispatch_info: DispatchInfo, run: F, - ) -> Result { + ) -> Result { use frame_support::dispatch::extract_actual_weight; let charged = self.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; let result = run(self); let actual_weight = extract_actual_weight(&result, &dispatch_info); self.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight)); match result { - Ok(_) => Ok(ReturnCode::Success), + Ok(_) => Ok(ReturnErrorCode::Success), Err(e) => { if self.ext.append_debug_buffer("") { self.ext.append_debug_buffer("call failed with: "); @@ -807,9 +716,9 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { Ok(()) } - /// Fallible conversion of `DispatchError` to `ReturnCode`. - fn err_into_return_code(from: DispatchError) -> Result { - use ReturnCode::*; + /// Fallible conversion of `DispatchError` to `ReturnErrorCode`. + fn err_into_return_code(from: DispatchError) -> Result { + use ReturnErrorCode::*; let transfer_failed = Error::::TransferFailed.into(); let no_code = Error::::CodeNotFound.into(); @@ -823,8 +732,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { } } - /// Fallible conversion of a `ExecResult` to `ReturnCode`. - fn exec_into_return_code(from: ExecResult) -> Result { + /// Fallible conversion of a `ExecResult` to `ReturnErrorCode`. + fn exec_into_return_code(from: ExecResult) -> Result { use crate::exec::ErrorOrigin::Callee; let ExecError { error, origin } = match from { @@ -833,7 +742,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { }; match (error, origin) { - (_, Callee) => Ok(ReturnCode::CalleeTrapped), + (_, Callee) => Ok(ReturnErrorCode::CalleeTrapped), (err, _) => Self::err_into_return_code(err), } } @@ -907,7 +816,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { key_ptr: u32, out_ptr: u32, out_len_ptr: u32, - ) -> Result { + ) -> Result { let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?; let key = self.decode_key(memory, key_type, key_ptr)?; let outcome = self.ext.get_storage(&key); @@ -922,10 +831,10 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { false, already_charged, )?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) } else { self.adjust_gas(charged, RuntimeCosts::GetStorage(0)); - Ok(ReturnCode::KeyNotFound) + Ok(ReturnErrorCode::KeyNotFound) } } @@ -952,7 +861,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { input_data_len: u32, output_ptr: u32, output_len_ptr: u32, - ) -> Result { + ) -> Result { self.charge_gas(call_type.cost())?; let input_data = if flags.contains(CallFlags::CLONE_INPUT) { let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; @@ -1036,7 +945,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { output_len_ptr: u32, salt_ptr: u32, salt_len: u32, - ) -> Result { + ) -> Result { self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; let deposit_limit: BalanceOf<::T> = if deposit_ptr == SENTINEL { BalanceOf::<::T>::zero() @@ -1096,10 +1005,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { pub mod env { /// Set the value at the given key in the contract storage. - /// - /// Equivalent to the newer [`seal1`][`super::api_doc::Version1::set_storage`] version with the - /// exception of the return type. Still a valid thing to call when not interested in the return - /// value. + /// See [`pallet_contracts_uapi::HostFn::set_storage`] #[prefixed_alias] fn set_storage( ctx: _, @@ -1112,23 +1018,7 @@ pub mod env { } /// Set the value at the given key in the contract storage. - /// - /// This version is to be used with a fixed sized storage key. For runtimes supporting - /// transparent hashing, please use the newer version of this function. - /// - /// The value length must not exceed the maximum defined by the contracts module parameters. - /// Specifying a `value_len` of zero will store an empty value. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the location to store the value is placed. - /// - `value_ptr`: pointer into the linear memory where the value to set is placed. - /// - `value_len`: the length of the value in bytes. - /// - /// # Return Value - /// - /// Returns the size of the pre-existing value at the specified key if any. Otherwise - /// `SENTINEL` is returned as a sentinel value. + /// See [`pallet_contracts_uapi::HostFn::set_storage_v1`] #[version(1)] #[prefixed_alias] fn set_storage( @@ -1142,21 +1032,7 @@ pub mod env { } /// Set the value at the given key in the contract storage. - /// - /// The key and value lengths must not exceed the maximums defined by the contracts module - /// parameters. Specifying a `value_len` of zero will store an empty value. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the location to store the value is placed. - /// - `key_len`: the length of the key in bytes. - /// - `value_ptr`: pointer into the linear memory where the value to set is placed. - /// - `value_len`: the length of the value in bytes. - /// - /// # Return Value - /// - /// Returns the size of the pre-existing value at the specified key if any. Otherwise - /// `SENTINEL` is returned as a sentinel value. + /// See [`pallet_contracts_uapi::HostFn::set_storage_v2`] #[version(2)] #[prefixed_alias] fn set_storage( @@ -1171,26 +1047,14 @@ pub mod env { } /// Clear the value at the given key in the contract storage. - /// - /// Equivalent to the newer [`seal1`][`super::api_doc::Version1::clear_storage`] version with - /// the exception of the return type. Still a valid thing to call when not interested in the - /// return value. + /// See [`pallet_contracts_uapi::HostFn::clear_storage`] #[prefixed_alias] fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> { ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ()) } /// Clear the value at the given key in the contract storage. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key is placed. - /// - `key_len`: the length of the key in bytes. - /// - /// # Return Value - /// - /// Returns the size of the pre-existing value at the specified key if any. Otherwise - /// `SENTINEL` is returned as a sentinel value. + /// See [`pallet_contracts_uapi::HostFn::clear_storage_v1`] #[version(1)] #[prefixed_alias] fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { @@ -1198,20 +1062,7 @@ pub mod env { } /// Retrieve the value under the given key from storage. - /// - /// This version is to be used with a fixed sized storage key. For runtimes supporting - /// transparent hashing, please use the newer version of this function. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - /// - `out_ptr`: pointer to the linear memory where the value is written to. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. - /// - /// # Errors - /// - /// `ReturnCode::KeyNotFound` + /// See [`pallet_contracts_uapi::HostFn::get_storage`] #[prefixed_alias] fn get_storage( ctx: _, @@ -1219,28 +1070,12 @@ pub mod env { key_ptr: u32, out_ptr: u32, out_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.get_storage(memory, KeyType::Fix, key_ptr, out_ptr, out_len_ptr) } /// Retrieve the value under the given key from storage. - /// - /// This version is to be used with a fixed sized storage key. For runtimes supporting - /// transparent hashing, please use the newer version of this function. - /// - /// The key length must not exceed the maximum defined by the contracts module parameter. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - /// - `key_len`: the length of the key in bytes. - /// - `out_ptr`: pointer to the linear memory where the value is written to. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. - /// - /// # Errors - /// - /// - `ReturnCode::KeyNotFound` + /// See [`pallet_contracts_uapi::HostFn::get_storage_v1`] #[version(1)] #[prefixed_alias] fn get_storage( @@ -1250,41 +1085,19 @@ pub mod env { key_len: u32, out_ptr: u32, out_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.get_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr) } /// Checks whether there is a value stored under the given key. - /// - /// This version is to be used with a fixed sized storage key. For runtimes supporting - /// transparent hashing, please use the newer version of this function. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - /// - /// # Return Value - /// - /// Returns the size of the pre-existing value at the specified key if any. Otherwise - /// `SENTINEL` is returned as a sentinel value. + /// See [`pallet_contracts_uapi::HostFn::contains_storage`] #[prefixed_alias] fn contains_storage(ctx: _, memory: _, key_ptr: u32) -> Result { ctx.contains_storage(memory, KeyType::Fix, key_ptr) } /// Checks whether there is a value stored under the given key. - /// - /// The key length must not exceed the maximum defined by the contracts module parameter. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - /// - `key_len`: the length of the key in bytes. - /// - /// # Return Value - /// - /// Returns the size of the pre-existing value at the specified key if any. Otherwise - /// `SENTINEL` is returned as a sentinel value. + /// See [`pallet_contracts_uapi::HostFn::contains_storage_v1`] #[version(1)] #[prefixed_alias] fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { @@ -1292,18 +1105,7 @@ pub mod env { } /// Retrieve and remove the value under the given key from storage. - /// - /// # Parameters - /// - /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - /// - `key_len`: the length of the key in bytes. - /// - `out_ptr`: pointer to the linear memory where the value is written to. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. - /// - /// # Errors - /// - /// - `ReturnCode::KeyNotFound` + /// See [`pallet_contracts_uapi::HostFn::take_storage`] #[prefixed_alias] fn take_storage( ctx: _, @@ -1312,7 +1114,7 @@ pub mod env { key_len: u32, out_ptr: u32, out_len_ptr: u32, - ) -> Result { + ) -> Result { let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; ensure!( key_len <= <::T as Config>::MaxStorageKeyLen::get(), @@ -1326,27 +1128,15 @@ pub mod env { )? { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32)); ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) } else { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0)); - Ok(ReturnCode::KeyNotFound) + Ok(ReturnErrorCode::KeyNotFound) } } /// Transfer some value to another account. - /// - /// # Parameters - /// - /// - `account_ptr`: a pointer to the address of the beneficiary account Should be decodable as - /// an `T::AccountId`. Traps otherwise. - /// - `account_len`: length of the address buffer. - /// - `value_ptr`: a pointer to the buffer with value, how much value to send. Should be - /// decodable as a `T::Balance`. Traps otherwise. - /// - `value_len`: length of the value buffer. - /// - /// # Errors - /// - /// - `ReturnCode::TransferFailed` + /// See [`pallet_contracts_uapi::HostFn::transfer`]. #[prefixed_alias] fn transfer( ctx: _, @@ -1355,14 +1145,14 @@ pub mod env { _account_len: u32, value_ptr: u32, _value_len: u32, - ) -> Result { + ) -> Result { ctx.charge_gas(RuntimeCosts::Transfer)?; let callee: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(memory, account_ptr)?; let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(memory, value_ptr)?; let result = ctx.ext.transfer(&callee, value); match result { - Ok(()) => Ok(ReturnCode::Success), + Ok(()) => Ok(ReturnErrorCode::Success), Err(err) => { let code = Runtime::::err_into_return_code(err)?; Ok(code) @@ -1372,17 +1162,11 @@ pub mod env { /// Make a call to another contract. /// - /// # New version available - /// - /// This is equivalent to calling the newer version of this function with - /// `flags` set to `ALLOW_REENTRY`. See the newer version for documentation. - /// /// # Note /// - /// The values `_callee_len` and `_value_len` are ignored because the encoded sizes - /// of those types are fixed through - /// [`codec::MaxEncodedLen`]. The fields exist - /// for backwards compatibility. Consider switching to the newest version of this function. + /// The values `_callee_len` and `_value_len` are ignored because the encoded sizes of those + /// types are fixed through [`codec::MaxEncodedLen`]. The fields exist for backwards + /// compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn call( ctx: _, @@ -1396,7 +1180,7 @@ pub mod env { input_data_len: u32, output_ptr: u32, output_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.call( memory, CallFlags::ALLOW_REENTRY, @@ -1414,10 +1198,7 @@ pub mod env { } /// Make a call to another contract. - /// - /// Equivalent to the newer [`seal2`][`super::api_doc::Version2::call`] version but works with - /// *ref_time* Weight only. It is recommended to switch to the latest version, once it's - /// stabilized. + /// See [`pallet_contracts_uapi::HostFn::call_v1`]. #[version(1)] #[prefixed_alias] fn call( @@ -1431,7 +1212,7 @@ pub mod env { input_data_len: u32, output_ptr: u32, output_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, @@ -1449,39 +1230,7 @@ pub mod env { } /// Make a call to another contract. - /// - /// The callees output buffer is copied to `output_ptr` and its length to `output_len_ptr`. - /// The copy of the output buffer can be skipped by supplying the sentinel value - /// of `SENTINEL` to `output_ptr`. - /// - /// # Parameters - /// - /// - `flags`: See `crate::wasm::runtime::CallFlags` for a documentation of the supported flags. - /// - `callee_ptr`: a pointer to the address of the callee contract. Should be decodable as an - /// `T::AccountId`. Traps otherwise. - /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. - /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. - /// - `deposit_ptr`: a pointer to the buffer with value of the storage deposit limit for the - /// call. Should be decodable as a `T::Balance`. Traps otherwise. Passing `SENTINEL` means - /// setting no specific limit for the call, which implies storage usage up to the limit of the - /// parent call. - /// - `value_ptr`: a pointer to the buffer with value, how much value to send. Should be - /// decodable as a `T::Balance`. Traps otherwise. - /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the callee. - /// - `input_data_len`: length of the input data buffer. - /// - `output_ptr`: a pointer where the output buffer is copied to. - /// - `output_len_ptr`: in-out pointer to where the length of the buffer is read from and the - /// actual length is written to. - /// - /// # Errors - /// - /// An error means that the call wasn't successful output buffer is returned unless - /// stated otherwise. - /// - /// - `ReturnCode::CalleeReverted`: Output buffer is returned. - /// - `ReturnCode::CalleeTrapped` - /// - `ReturnCode::TransferFailed` - /// - `ReturnCode::NotCallable` + /// See [`pallet_contracts_uapi::HostFn::call_v2`]. #[version(2)] #[unstable] fn call( @@ -1497,7 +1246,7 @@ pub mod env { input_data_len: u32, output_ptr: u32, output_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, @@ -1515,29 +1264,7 @@ pub mod env { } /// Execute code in the context (storage, caller, value) of the current contract. - /// - /// Reentrancy protection is always disabled since the callee is allowed - /// to modify the callers storage. This makes going through a reentrancy attack - /// unnecessary for the callee when it wants to exploit the caller. - /// - /// # Parameters - /// - /// - `flags`: see `crate::wasm::runtime::CallFlags` for a documentation of the supported flags. - /// - `code_hash`: a pointer to the hash of the code to be called. - /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the callee. - /// - `input_data_len`: length of the input data buffer. - /// - `output_ptr`: a pointer where the output buffer is copied to. - /// - `output_len_ptr`: in-out pointer to where the length of the buffer is read from and the - /// actual length is written to. - /// - /// # Errors - /// - /// An error means that the call wasn't successful and no output buffer is returned unless - /// stated otherwise. - /// - /// - `ReturnCode::CalleeReverted`: Output buffer is returned. - /// - `ReturnCode::CalleeTrapped` - /// - `ReturnCode::CodeNotFound` + /// See [`pallet_contracts_uapi::HostFn::delegate_call`]. #[prefixed_alias] fn delegate_call( ctx: _, @@ -1548,7 +1275,7 @@ pub mod env { input_data_len: u32, output_ptr: u32, output_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, @@ -1561,11 +1288,7 @@ pub mod env { } /// Instantiate a contract with the specified code hash. - /// - /// # New version available - /// - /// This is equivalent to calling the newer version of this function. The newer version - /// drops the now unnecessary length fields. + /// See [`pallet_contracts_uapi::HostFn::instantiate`]. /// /// # Note /// @@ -1589,7 +1312,7 @@ pub mod env { output_len_ptr: u32, salt_ptr: u32, salt_len: u32, - ) -> Result { + ) -> Result { ctx.instantiate( memory, code_hash_ptr, @@ -1608,10 +1331,7 @@ pub mod env { } /// Instantiate a contract with the specified code hash. - /// - /// Equivalent to the newer [`seal2`][`super::api_doc::Version2::instantiate`] version but works - /// with *ref_time* Weight only. It is recommended to switch to the latest version, once it's - /// stabilized. + /// See [`pallet_contracts_uapi::HostFn::instantiate_v1`]. #[version(1)] #[prefixed_alias] fn instantiate( @@ -1628,7 +1348,7 @@ pub mod env { output_len_ptr: u32, salt_ptr: u32, salt_len: u32, - ) -> Result { + ) -> Result { ctx.instantiate( memory, code_hash_ptr, @@ -1647,48 +1367,7 @@ pub mod env { } /// Instantiate a contract with the specified code hash. - /// - /// This function creates an account and executes the constructor defined in the code specified - /// by the code hash. The address of this new account is copied to `address_ptr` and its length - /// to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its - /// length to `output_len_ptr`. The copy of the output buffer and address can be skipped by - /// supplying the sentinel value of `SENTINEL` to `output_ptr` or `address_ptr`. - /// - /// # Parameters - /// - /// - `code_hash_ptr`: a pointer to the buffer that contains the initializer code. - /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. - /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. - /// - `deposit_ptr`: a pointer to the buffer with value of the storage deposit limit for - /// instantiation. Should be decodable as a `T::Balance`. Traps otherwise. Passing `SENTINEL` - /// means setting no specific limit for the call, which implies storage usage up to the limit - /// of the parent call. - /// - `value_ptr`: a pointer to the buffer with value, how much value to send. Should be - /// decodable as a `T::Balance`. Traps otherwise. - /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the initializer code. - /// - `input_data_len`: length of the input data buffer. - /// - `address_ptr`: a pointer where the new account's address is copied to. `SENTINEL` means - /// not to copy. - /// - `address_len_ptr`: pointer to where put the length of the address. - /// - `output_ptr`: a pointer where the output buffer is copied to. `SENTINEL` means not to - /// copy. - /// - `output_len_ptr`: in-out pointer to where the length of the buffer is read from and the - /// actual length is written to. - /// - `salt_ptr`: Pointer to raw bytes used for address derivation. See `fn contract_address`. - /// - `salt_len`: length in bytes of the supplied salt. - /// - /// # Errors - /// - /// Please consult the `ReturnCode` enum declaration for more information on those - /// errors. Here we only note things specific to this function. - /// - /// An error means that the account wasn't created and no address or output buffer - /// is returned unless stated otherwise. - /// - /// - `ReturnCode::CalleeReverted`: Output buffer is returned. - /// - `ReturnCode::CalleeTrapped` - /// - `ReturnCode::TransferFailed` - /// - `ReturnCode::CodeNotFound` + /// See [`pallet_contracts_uapi::HostFn::instantiate_v2`]. #[version(2)] #[unstable] fn instantiate( @@ -1707,7 +1386,7 @@ pub mod env { output_len_ptr: u32, salt_ptr: u32, salt_len: u32, - ) -> Result { + ) -> Result { ctx.instantiate( memory, code_hash_ptr, @@ -1726,11 +1405,7 @@ pub mod env { } /// Remove the calling account and transfer remaining balance. - /// - /// # New version available - /// - /// This is equivalent to calling the newer version of this function. The newer version - /// drops the now unnecessary length fields. + /// See [`pallet_contracts_uapi::HostFn::terminate`]. /// /// # Note /// @@ -1748,20 +1423,7 @@ pub mod env { } /// Remove the calling account and transfer remaining **free** balance. - /// - /// This function never returns. Either the termination was successful and the - /// execution of the destroyed contract is halted. Or it failed during the termination - /// which is considered fatal and results in a trap + rollback. - /// - /// - `beneficiary_ptr`: a pointer to the address of the beneficiary account where all where all - /// remaining funds of the caller are transferred. Should be decodable as an `T::AccountId`. - /// Traps otherwise. - /// - /// # Traps - /// - /// - The contract is live i.e is already on the call stack. - /// - Failed to send the balance to the beneficiary. - /// - The deletion queue is full. + /// See [`pallet_contracts_uapi::HostFn::terminate_v1`]. #[version(1)] #[prefixed_alias] fn terminate(ctx: _, memory: _, beneficiary_ptr: u32) -> Result<(), TrapReason> { @@ -1769,15 +1431,7 @@ pub mod env { } /// Stores the input passed by the caller into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// # Note - /// - /// This function traps if the input was previously forwarded by a [`call()`][`Self::call()`]. + /// See [`pallet_contracts_uapi::HostFn::input`]. #[prefixed_alias] fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::InputBase)?; @@ -1793,22 +1447,7 @@ pub mod env { } /// Cease contract execution and save a data buffer as a result of the execution. - /// - /// This function never returns as it stops execution of the caller. - /// This is the only way to return a data buffer to the caller. Returning from - /// execution without calling this function is equivalent to calling: - /// ```nocompile - /// seal_return(0, 0, 0); - /// ``` - /// - /// The flags argument is a bitfield that can be used to signal special return - /// conditions to the supervisor: - /// --- lsb --- - /// bit 0 : REVERT - Revert all storage changes made by the caller. - /// bit [1, 31]: Reserved for future use. - /// --- msb --- - /// - /// Using a reserved bit triggers a trap. + /// See [`pallet_contracts_uapi::HostFn::return_value`]. fn seal_return( ctx: _, memory: _, @@ -1824,18 +1463,7 @@ pub mod env { } /// Stores the address of the caller into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the - /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then - /// the address of the contract will be returned. The value is encoded as T::AccountId. - /// - /// If there is no address associated with the caller (e.g. because the caller is root) then - /// it traps with `BadOrigin`. + /// See [`pallet_contracts_uapi::HostFn::caller`]. #[prefixed_alias] fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Caller)?; @@ -1851,13 +1479,7 @@ pub mod env { } /// Checks whether a specified address belongs to a contract. - /// - /// # Parameters - /// - /// - `account_ptr`: a pointer to the address of the beneficiary account Should be decodable as - /// an `T::AccountId`. Traps otherwise. - /// - /// Returned value is a `u32`-encoded boolean: (0 = false, 1 = true). + /// See [`pallet_contracts_uapi::HostFn::is_contract`]. #[prefixed_alias] fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::IsContract)?; @@ -1868,18 +1490,7 @@ pub mod env { } /// Retrieve the code hash for a specified contract address. - /// - /// # Parameters - /// - /// - `account_ptr`: a pointer to the address in question. Should be decodable as an - /// `T::AccountId`. Traps otherwise. - /// - `out_ptr`: pointer to the linear memory where the returning value is written to. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. - /// - /// # Errors - /// - /// - `ReturnCode::KeyNotFound` + /// See [`pallet_contracts_uapi::HostFn::code_hash`]. #[prefixed_alias] fn code_hash( ctx: _, @@ -1887,7 +1498,7 @@ pub mod env { account_ptr: u32, out_ptr: u32, out_len_ptr: u32, - ) -> Result { + ) -> Result { ctx.charge_gas(RuntimeCosts::CodeHash)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(memory, account_ptr)?; @@ -1900,19 +1511,14 @@ pub mod env { false, already_charged, )?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) } else { - Ok(ReturnCode::KeyNotFound) + Ok(ReturnErrorCode::KeyNotFound) } } /// Retrieve the code hash of the currently executing contract. - /// - /// # Parameters - /// - /// - `out_ptr`: pointer to the linear memory where the returning value is written to. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. + /// See [`pallet_contracts_uapi::HostFn::own_code_hash`]. #[prefixed_alias] fn own_code_hash(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; @@ -1928,15 +1534,7 @@ pub mod env { } /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// - /// Prefer this over [`is_contract()`][`Self::is_contract`] when checking whether your contract - /// is being called by a contract or a plain account. The reason is that it performs better - /// since it does not need to do any storage lookups. - /// - /// A return value of `true` indicates that this contract is being called by a plain account - /// and `false` indicates that the caller is another contract. - /// - /// Returned value is a `u32`-encoded boolean: (`0 = false`, `1 = true`). + /// See [`pallet_contracts_uapi::HostFn::caller_is_origin`]. #[prefixed_alias] fn caller_is_origin(ctx: _, _memory: _) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; @@ -1944,14 +1542,7 @@ pub mod env { } /// Checks whether the caller of the current contract is root. - /// - /// Note that only the origin of the call stack can be root. Hence this function returning - /// `true` implies that the contract is being called by the origin. - /// - /// A return value of `true` indicates that this contract is being called by a root origin, - /// and `false` indicates that the caller is a signed origin. - /// - /// Returned value is a `u32`-encoded boolean: (`0 = false`, `1 = true`). + /// See [`pallet_contracts_uapi::HostFn::caller_is_root`]. #[unstable] fn caller_is_root(ctx: _, _memory: _) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsRoot)?; @@ -1959,11 +1550,7 @@ pub mod env { } /// Stores the address of the current contract into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// See [`pallet_contracts_uapi::HostFn::address`]. #[prefixed_alias] fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Address)?; @@ -1978,10 +1565,7 @@ pub mod env { } /// Stores the price for the specified amount of gas into the supplied buffer. - /// - /// Equivalent to the newer [`seal1`][`super::api_doc::Version2::weight_to_fee`] version but - /// works with *ref_time* Weight only. It is recommended to switch to the latest version, once - /// it's stabilized. + /// See [`pallet_contracts_uapi::HostFn::weight_to_fee`]. #[prefixed_alias] fn weight_to_fee( ctx: _, @@ -2003,21 +1587,7 @@ pub mod env { } /// Stores the price for the specified amount of weight into the supplied buffer. - /// - /// # Parameters - /// - /// - `out_ptr`: pointer to the linear memory where the returning value is written to. If the - /// available space at `out_ptr` is less than the size of the value a trap is triggered. - /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and - /// the value length is written to. - /// - /// The data is encoded as `T::Balance`. - /// - /// # Note - /// - /// It is recommended to avoid specifying very small values for `ref_time_limit` and - /// `proof_size_limit` as the prices for a single gas can be smaller than the basic balance - /// unit. + /// See [`pallet_contracts_uapi::HostFn::weight_to_fee_v1`]. #[version(1)] #[unstable] fn weight_to_fee( @@ -2041,10 +1611,7 @@ pub mod env { } /// Stores the weight left into the supplied buffer. - /// - /// Equivalent to the newer [`seal1`][`super::api_doc::Version2::gas_left`] version but - /// works with *ref_time* Weight only. It is recommended to switch to the latest version, once - /// it's stabilized. + /// See [`pallet_contracts_uapi::HostFn::gas_left`]. #[prefixed_alias] fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; @@ -2060,13 +1627,7 @@ pub mod env { } /// Stores the amount of weight left into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// The data is encoded as Weight. + /// See [`pallet_contracts_uapi::HostFn::gas_left_v1`]. #[version(1)] #[unstable] fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { @@ -2083,13 +1644,7 @@ pub mod env { } /// Stores the *free* balance of the current account into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// The data is encoded as `T::Balance`. + /// See [`pallet_contracts_uapi::HostFn::balance`]. #[prefixed_alias] fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; @@ -2104,13 +1659,7 @@ pub mod env { } /// Stores the value transferred along with this call/instantiate into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a `u32` value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// The data is encoded as `T::Balance`. + /// See [`pallet_contracts_uapi::HostFn::value_transferred`]. #[prefixed_alias] fn value_transferred( ctx: _, @@ -2210,11 +1759,7 @@ pub mod env { } /// Load the latest block timestamp into the supplied buffer - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// See [`pallet_contracts_uapi::HostFn::now`]. #[prefixed_alias] fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Now)?; @@ -2229,8 +1774,7 @@ pub mod env { } /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// - /// The data is encoded as `T::Balance`. + /// See [`pallet_contracts_uapi::HostFn::minimum_balance`]. #[prefixed_alias] fn minimum_balance( ctx: _, @@ -2378,15 +1922,8 @@ pub mod env { )?) } - /// Deposit a contract event with the data buffer and optional list of topics. There is a limit - /// on the maximum number of topics specified by `event_topics`. - /// - /// - `topics_ptr`: a pointer to the buffer of topics encoded as `Vec`. The value of - /// this is ignored if `topics_len` is set to `0`. The topics list can't contain duplicates. - /// - `topics_len`: the length of the topics buffer. Pass 0 if you want to pass an empty - /// vector. - /// - `data_ptr`: a pointer to a raw data buffer which will saved along the event. - /// - `data_len`: the length of the data buffer. + /// Deposit a contract event with the data buffer and optional list of topics. + /// See [pallet_contracts_uapi::HostFn::deposit_event] #[prefixed_alias] fn deposit_event( ctx: _, @@ -2422,11 +1959,7 @@ pub mod env { } /// Stores the current block number of the current contract into the supplied buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at - /// `out_ptr`. This call overwrites it with the size of the value. If the available - /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// See [`pallet_contracts_uapi::HostFn::block_number`]. #[prefixed_alias] fn block_number(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::BlockNumber)?; @@ -2441,22 +1974,7 @@ pub mod env { } /// Computes the SHA2 256-bit hash on the given input buffer. - /// - /// Returns the result directly into the given output buffer. - /// - /// # Note - /// - /// - The `input` and `output` buffer may overlap. - /// - The output buffer is expected to hold at least 32 bytes (256 bits). - /// - It is the callers responsibility to provide an output buffer that is large enough to hold - /// the expected amount of bytes returned by the chosen hash function. - /// - /// # Parameters - /// - /// - `input_ptr`: the pointer into the linear memory where the input data is placed. - /// - `input_len`: the length of the input data in bytes. - /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The - /// function will write the result directly into this buffer. + /// See [`pallet_contracts_uapi::HostFn::hash_sha2_256`]. #[prefixed_alias] fn hash_sha2_256( ctx: _, @@ -2472,22 +1990,7 @@ pub mod env { } /// Computes the KECCAK 256-bit hash on the given input buffer. - /// - /// Returns the result directly into the given output buffer. - /// - /// # Note - /// - /// - The `input` and `output` buffer may overlap. - /// - The output buffer is expected to hold at least 32 bytes (256 bits). - /// - It is the callers responsibility to provide an output buffer that is large enough to hold - /// the expected amount of bytes returned by the chosen hash function. - /// - /// # Parameters - /// - /// - `input_ptr`: the pointer into the linear memory where the input data is placed. - /// - `input_len`: the length of the input data in bytes. - /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The - /// function will write the result directly into this buffer. + /// See [`pallet_contracts_uapi::HostFn::hash_keccak_256`]. #[prefixed_alias] fn hash_keccak_256( ctx: _, @@ -2503,22 +2006,7 @@ pub mod env { } /// Computes the BLAKE2 256-bit hash on the given input buffer. - /// - /// Returns the result directly into the given output buffer. - /// - /// # Note - /// - /// - The `input` and `output` buffer may overlap. - /// - The output buffer is expected to hold at least 32 bytes (256 bits). - /// - It is the callers responsibility to provide an output buffer that is large enough to hold - /// the expected amount of bytes returned by the chosen hash function. - /// - /// # Parameters - /// - /// - `input_ptr`: the pointer into the linear memory where the input data is placed. - /// - `input_len`: the length of the input data in bytes. - /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The - /// function will write the result directly into this buffer. + /// See [`pallet_contracts_uapi::HostFn::hash_blake2_256`]. #[prefixed_alias] fn hash_blake2_256( ctx: _, @@ -2534,22 +2022,7 @@ pub mod env { } /// Computes the BLAKE2 128-bit hash on the given input buffer. - /// - /// Returns the result directly into the given output buffer. - /// - /// # Note - /// - /// - The `input` and `output` buffer may overlap. - /// - The output buffer is expected to hold at least 16 bytes (128 bits). - /// - It is the callers responsibility to provide an output buffer that is large enough to hold - /// the expected amount of bytes returned by the chosen hash function. - /// - /// # Parameters - /// - /// - `input_ptr`: the pointer into the linear memory where the input data is placed. - /// - `input_len`: the length of the input data in bytes. - /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The - /// function will write the result directly into this buffer. + /// See [`pallet_contracts_uapi::HostFn::hash_blake2_128`]. #[prefixed_alias] fn hash_blake2_128( ctx: _, @@ -2565,16 +2038,7 @@ pub mod env { } /// Call into the chain extension provided by the chain if any. - /// - /// Handling of the input values is up to the specific chain extension and so is the - /// return value. The extension can decide to use the inputs as primitive inputs or as - /// in/out arguments by interpreting them as pointers. Any caller of this function - /// must therefore coordinate with the chain that it targets. - /// - /// # Note - /// - /// If no chain extension exists the contract will trap with the `NoChainExtension` - /// module error. + /// See [`pallet_contracts_uapi::HostFn::call_chain_extension`]. #[prefixed_alias] fn call_chain_extension( ctx: _, @@ -2627,7 +2091,7 @@ pub mod env { memory: _, str_ptr: u32, str_len: u32, - ) -> Result { + ) -> Result { let str_len = str_len.min(DebugBufferVec::::bound() as u32); ctx.charge_gas(RuntimeCosts::DebugMessage(str_len))?; if ctx.ext.append_debug_buffer("") { @@ -2636,47 +2100,17 @@ pub mod env { ctx.ext.append_debug_buffer(msg); } } - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) } /// Call some dispatchable of the runtime. - /// - /// This function decodes the passed in data as the overarching `Call` type of the - /// runtime and dispatches it. The weight as specified in the runtime is charged - /// from the gas meter. Any weight refunds made by the dispatchable are considered. - /// - /// The filter specified by `Config::CallFilter` is attached to the origin of - /// the dispatched call. - /// - /// # Parameters - /// - /// - `call_ptr`: the pointer into the linear memory where the input data is placed. - /// - `call_len`: the length of the input data in bytes. - /// - /// # Return Value - /// - /// Returns `ReturnCode::Success` when the dispatchable was successfully executed and - /// returned `Ok`. When the dispatchable was executed but returned an error - /// `ReturnCode::CallRuntimeFailed` is returned. The full error is not - /// provided because it is not guaranteed to be stable. - /// - /// # Comparison with `ChainExtension` - /// - /// Just as a chain extension this API allows the runtime to extend the functionality - /// of contracts. While making use of this function is generally easier it cannot be - /// used in all cases. Consider writing a chain extension if you need to do perform - /// one of the following tasks: - /// - /// - Return data. - /// - Provide functionality **exclusively** to contracts. - /// - Provide custom weights. - /// - Avoid the need to keep the `Call` data structure stable. + /// See [`frame_support::traits::call_runtime`]. fn call_runtime( ctx: _, memory: _, call_ptr: u32, call_len: u32, - ) -> Result { + ) -> Result { use frame_support::dispatch::GetDispatchInfo; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::RuntimeCall = @@ -2687,21 +2121,7 @@ pub mod env { } /// Execute an XCM program locally, using the contract's address as the origin. - /// This is equivalent to dispatching `pallet_xcm::execute` through call_runtime, except that - /// the function is called directly instead of being dispatched. - /// - /// # Parameters - /// - /// - `msg_ptr`: the pointer into the linear memory where the [`xcm::prelude::VersionedXcm`] is - /// placed. - /// - `msg_len`: the length of the message in bytes. - /// - `output_ptr`: the pointer into the linear memory where the [`xcm::prelude::Outcome`] - /// message id is placed. - /// - /// # Return Value - /// - /// Returns `ReturnCode::Success` when the XCM was successfully executed. When the XCM - /// execution fails, `ReturnCode::XcmExecutionFailed` is returned. + /// See [`pallet_contracts_uapi::HostFn::execute_xcm`]. #[unstable] fn xcm_execute( ctx: _, @@ -2709,7 +2129,7 @@ pub mod env { msg_ptr: u32, msg_len: u32, output_ptr: u32, - ) -> Result { + ) -> Result { use frame_support::dispatch::DispatchInfo; use xcm::VersionedXcm; use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; @@ -2740,23 +2160,7 @@ pub mod env { } /// Send an XCM program from the contract to the specified destination. - /// This is equivalent to dispatching `pallet_xcm::send` through `call_runtime`, except that - /// the function is called directly instead of being dispatched. - /// - /// # Parameters - /// - /// - `dest_ptr`: the pointer into the linear memory where the - /// [`xcm::prelude::VersionedMultiLocation`] is placed. - /// - `msg_ptr`: the pointer into the linear memory where the [`xcm::prelude::VersionedXcm`] is - /// placed. - /// - `msg_len`: the length of the message in bytes. - /// - `output_ptr`: the pointer into the linear memory where the [`xcm::v3::XcmHash`] message id - /// is placed. - /// - /// # Return Value - /// - /// Returns `ReturnCode::Success` when the message was successfully sent. When the XCM - /// execution fails, `ReturnCode::CallRuntimeFailed` is returned. + /// See [`pallet_contracts_uapi::HostFn::send_xcm`]. #[unstable] fn xcm_send( ctx: _, @@ -2765,7 +2169,7 @@ pub mod env { msg_ptr: u32, msg_len: u32, output_ptr: u32, - ) -> Result { + ) -> Result { use xcm::{VersionedMultiLocation, VersionedXcm}; use xcm_builder::{SendController, SendControllerWeightInfo}; @@ -2781,35 +2185,20 @@ pub mod env { match <::Xcm>::send(origin, dest.into(), message.into()) { Ok(message_id) => { ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) }, Err(e) => { if ctx.ext.append_debug_buffer("") { ctx.ext.append_debug_buffer("seal0::xcm_send failed with: "); ctx.ext.append_debug_buffer(e.into()); }; - Ok(ReturnCode::XcmSendFailed) + Ok(ReturnErrorCode::XcmSendFailed) }, } } /// Recovers the ECDSA public key from the given message hash and signature. - /// - /// Writes the public key into the given output buffer. - /// Assumes the secp256k1 curve. - /// - /// # Parameters - /// - /// - `signature_ptr`: the pointer into the linear memory where the signature is placed. Should - /// be decodable as a 65 bytes. Traps otherwise. - /// - `message_hash_ptr`: the pointer into the linear memory where the message hash is placed. - /// Should be decodable as a 32 bytes. Traps otherwise. - /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The - /// buffer should be 33 bytes. The function will write the result directly into this buffer. - /// - /// # Errors - /// - /// - `ReturnCode::EcdsaRecoverFailed` + /// See [`pallet_contracts_uapi::HostFn::ecdsa_recover`]. #[prefixed_alias] fn ecdsa_recover( ctx: _, @@ -2817,7 +2206,7 @@ pub mod env { signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32, - ) -> Result { + ) -> Result { ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?; let mut signature: [u8; 65] = [0; 65]; @@ -2833,26 +2222,14 @@ pub mod env { // buffer. ctx.write_sandbox_memory(memory, output_ptr, pub_key.as_ref())?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) }, - Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), + Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed), } } /// Verify a sr25519 signature - /// - /// # Parameters - /// - /// - `signature_ptr`: the pointer into the linear memory where the signature is placed. Should - /// be a value of 64 bytes. - /// - `pub_key_ptr`: the pointer into the linear memory where the public key is placed. Should - /// be a value of 32 bytes. - /// - `message_len`: the length of the message payload. - /// - `message_ptr`: the pointer into the linear memory where the message is placed. - /// - /// # Errors - /// - /// - `ReturnCode::Sr25519VerifyFailed + /// See [`pallet_contracts_uapi::HostFn::sr25519_verify`]. #[unstable] fn sr25519_verify( ctx: _, @@ -2861,7 +2238,7 @@ pub mod env { pub_key_ptr: u32, message_len: u32, message_ptr: u32, - ) -> Result { + ) -> Result { ctx.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; let mut signature: [u8; 64] = [0; 64]; @@ -2873,41 +2250,16 @@ pub mod env { let message: Vec = ctx.read_sandbox_memory(memory, message_ptr, message_len)?; if ctx.ext.sr25519_verify(&signature, &message, &pub_key) { - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) } else { - Ok(ReturnCode::Sr25519VerifyFailed) + Ok(ReturnErrorCode::Sr25519VerifyFailed) } } /// Replace the contract code at the specified address with new code. - /// - /// # Note - /// - /// There are a couple of important considerations which must be taken into account when - /// using this API: - /// - /// 1. The storage at the code address will remain untouched. This means that contract - /// developers must ensure that the storage layout of the new code is compatible with that of - /// the old code. - /// - /// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another - /// way, when using this API you lose the guarantee that an address always identifies a specific - /// code hash. - /// - /// 3. If a contract calls into itself after changing its code the new call would use - /// the new code. However, if the original caller panics after returning from the sub call it - /// would revert the changes made by [`set_code_hash()`][`Self::set_code_hash`] and the next - /// caller would use the old code. - /// - /// # Parameters - /// - /// - `code_hash_ptr`: A pointer to the buffer that contains the new code hash. - /// - /// # Errors - /// - /// - `ReturnCode::CodeNotFound` + /// See [`pallet_contracts_uapi::HostFn::set_code_hash`]. #[prefixed_alias] - fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result { + fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; @@ -2916,33 +2268,19 @@ pub mod env { let code = Runtime::::err_into_return_code(err)?; Ok(code) }, - Ok(()) => Ok(ReturnCode::Success), + Ok(()) => Ok(ReturnErrorCode::Success), } } /// Calculates Ethereum address from the ECDSA compressed public key and stores - /// it into the supplied buffer. - /// - /// # Parameters - /// - /// - `key_ptr`: a pointer to the ECDSA compressed public key. Should be decodable as a 33 bytes - /// value. Traps otherwise. - /// - `out_ptr`: the pointer into the linear memory where the output data is placed. The - /// function will write the result directly into this buffer. - /// - /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// If the available space at `out_ptr` is less than the size of the value a trap is triggered. - /// - /// # Errors - /// - /// - `ReturnCode::EcdsaRecoverFailed` + /// See [`pallet_contracts_uapi::HostFn::ecdsa_to_eth_address`]. #[prefixed_alias] fn ecdsa_to_eth_address( ctx: _, memory: _, key_ptr: u32, out_ptr: u32, - ) -> Result { + ) -> Result { ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; let mut compressed_key: [u8; 33] = [0; 33]; ctx.read_sandbox_memory_into_buf(memory, key_ptr, &mut compressed_key)?; @@ -2950,18 +2288,15 @@ pub mod env { match result { Ok(eth_address) => { ctx.write_sandbox_memory(memory, out_ptr, eth_address.as_ref())?; - Ok(ReturnCode::Success) + Ok(ReturnErrorCode::Success) }, - Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), + Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed), } } /// Returns the number of times the currently executing contract exists on the call stack in /// addition to the calling instance. - /// - /// # Return Value - /// - /// Returns `0` when there is no reentrancy. + /// See [`pallet_contracts_uapi::HostFn::reentrance_count`]. #[unstable] fn reentrance_count(ctx: _, memory: _) -> Result { ctx.charge_gas(RuntimeCosts::ReentrantCount)?; @@ -2970,14 +2305,7 @@ pub mod env { /// Returns the number of times specified contract exists on the call stack. Delegated calls are /// not counted as separate calls. - /// - /// # Parameters - /// - /// - `account_ptr`: a pointer to the contract address. - /// - /// # Return Value - /// - /// Returns `0` when the contract does not exist on the call stack. + /// See [`pallet_contracts_uapi::HostFn::account_reentrance_count`]. #[unstable] fn account_reentrance_count(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::AccountEntranceCount)?; @@ -2987,19 +2315,14 @@ pub mod env { } /// Returns a nonce that is unique per contract instantiation. - /// - /// The nonce is incremented for each successful contract instantiation. This is a - /// sensible default salt for contract instantiations. + /// See [`pallet_contracts_uapi::HostFn::instantiation_nonce`]. fn instantiation_nonce(ctx: _, _memory: _) -> Result { ctx.charge_gas(RuntimeCosts::InstantationNonce)?; Ok(ctx.ext.nonce()) } /// Adds a new delegate dependency to the contract. - /// - /// # Parameters - /// - /// - `code_hash_ptr`: A pointer to the code hash of the dependency. + /// See [`pallet_contracts_uapi::HostFn::add_delegate_dependency`]. #[unstable] fn add_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::AddDelegateDependency)?; @@ -3009,10 +2332,7 @@ pub mod env { } /// Removes the delegate dependency from the contract. - /// - /// # Parameters - /// - /// - `code_hash_ptr`: A pointer to the code hash of the dependency. + /// see [`pallet_contracts_uapi::HostFn::remove_delegate_dependency`]. #[unstable] fn remove_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::RemoveDelegateDependency)?; diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml new file mode 100644 index 00000000000..6717d574dfe --- /dev/null +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "pallet-contracts-uapi" +version = "4.0.0-dev" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "Exposes all the host functions that a contract can import." + +[dependencies] +paste = { version = "1.0", default-features = false } +bitflags = "1.0" +scale-info = { version = "2.10.0", default-features = false, features = ["derive"], optional = true } +scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", + "max-encoded-len", +], optional = true } + +[features] +default = [ "scale" ] +scale = [ "dep:scale", "scale-info" ] + diff --git a/substrate/frame/contracts/uapi/src/flags.rs b/substrate/frame/contracts/uapi/src/flags.rs new file mode 100644 index 00000000000..32553817fb7 --- /dev/null +++ b/substrate/frame/contracts/uapi/src/flags.rs @@ -0,0 +1,73 @@ +// 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 bitflags::bitflags; + +bitflags! { + /// Flags used by a contract to customize exit behaviour. + #[cfg_attr(feature = "scale", derive(scale::Encode, scale::Decode, scale_info::TypeInfo))] + pub struct ReturnFlags: u32 { + /// If this bit is set all changes made by the contract execution are rolled back. + const REVERT = 0x0000_0001; + } +} + +bitflags! { + /// Flags used to change the behaviour of `seal_call` and `seal_delegate_call`. + pub struct CallFlags: u32 { + /// Forward the input of current function to the callee. + /// + /// Supplied input pointers are ignored when set. + /// + /// # Note + /// + /// A forwarding call will consume the current contracts input. Any attempt to + /// access the input after this call returns will lead to [`Error::InputForwarded`]. + /// It does not matter if this is due to calling `seal_input` or trying another + /// forwarding call. Consider using [`Self::CLONE_INPUT`] in order to preserve + /// the input. + const FORWARD_INPUT = 0b0000_0001; + /// Identical to [`Self::FORWARD_INPUT`] but without consuming the input. + /// + /// This adds some additional weight costs to the call. + /// + /// # Note + /// + /// This implies [`Self::FORWARD_INPUT`] and takes precedence when both are set. + const CLONE_INPUT = 0b0000_0010; + /// Do not return from the call but rather return the result of the callee to the + /// callers caller. + /// + /// # Note + /// + /// This makes the current contract completely transparent to its caller by replacing + /// this contracts potential output by the callee ones. Any code after `seal_call` + /// can be safely considered unreachable. + const TAIL_CALL = 0b0000_0100; + /// Allow the callee to reenter into the current contract. + /// + /// Without this flag any reentrancy into the current contract that originates from + /// the callee (or any of its callees) is denied. This includes the first callee: + /// You cannot call into yourself with this flag set. + /// + /// # Note + /// + /// For `seal_delegate_call` should be always unset, otherwise + /// [`Error::InvalidCallFlags`] is returned. + const ALLOW_REENTRY = 0b0000_1000; + } +} diff --git a/substrate/frame/contracts/uapi/src/host.rs b/substrate/frame/contracts/uapi/src/host.rs new file mode 100644 index 00000000000..f8b55d3822e --- /dev/null +++ b/substrate/frame/contracts/uapi/src/host.rs @@ -0,0 +1,793 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// 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::{CallFlags, Result, ReturnFlags, SENTINEL}; +use paste::paste; + +#[cfg(target_arch = "wasm32")] +mod wasm32; + +#[cfg(target_arch = "riscv32")] +mod riscv32; + +macro_rules! hash_fn { + ( $name:ident, $bytes:literal ) => { + paste! { + #[doc = "Computes the " $name " " $bytes "-bit hash on the given input buffer."] + #[doc = "\n# Notes\n"] + #[doc = "- The `input` and `output` buffer may overlap."] + #[doc = "- The output buffer is expected to hold at least " $bytes " bits."] + #[doc = "- It is the callers responsibility to provide an output buffer that is large enough to hold the expected amount of bytes returned by the hash function."] + #[doc = "\n# Parameters\n"] + #[doc = "- `input`: The input data buffer."] + #[doc = "- `output`: The output buffer to write the hash result to."] + fn [](input: &[u8], output: &mut [u8; $bytes]); + } + }; +} + +fn extract_from_slice(output: &mut &mut [u8], new_len: usize) { + debug_assert!(new_len <= output.len()); + let tmp = core::mem::take(output); + *output = &mut tmp[..new_len]; +} + +fn ptr_len_or_sentinel(data: &mut Option<&mut [u8]>) -> (*mut u8, u32) { + match data { + Some(ref mut data) => (data.as_mut_ptr(), data.len() as _), + None => (SENTINEL as _, 0), + } +} + +fn ptr_or_sentinel(data: &Option<&[u8]>) -> *const u8 { + match data { + Some(ref data) => data.as_ptr(), + None => SENTINEL as _, + } +} + +/// Implements [`HostFn`] for each supported target architecture. +pub enum HostFnImpl {} + +/// Defines all the host apis implemented by both wasm and RISC-V vms. +pub trait HostFn { + /// Returns the number of times specified contract exists on the call stack. Delegated calls are + /// not counted as separate calls. + /// + /// # Parameters + /// + /// - `account`: The contract address. Should be decodable as an `T::AccountId`. Traps + /// otherwise. + /// + /// # Return + /// + /// Returns the number of times specified contract exists on the call stack. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn account_reentrance_count(account: &[u8]) -> u32; + + /// Stores the address of the current contract into the supplied buffer. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the address. + fn address(output: &mut &mut [u8]); + + /// Adds a new delegate dependency to the contract. + /// + /// Traps if the maximum number of delegate_dependencies is reached or if + /// the delegate dependency already exists. + /// + /// # Parameters + /// + /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps + /// otherwise. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn add_delegate_dependency(code_hash: &[u8]); + + /// Stores the *free* balance of the current account into the supplied buffer. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the balance. + fn balance(output: &mut &mut [u8]); + + /// Stores the current block number of the current contract into the supplied buffer. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the block number. + fn block_number(output: &mut &mut [u8]); + + /// Make a call to another contract. + /// + /// This is equivalent to calling the newer version of this function with + /// `flags` set to [`CallFlags::ALLOW_REENTRY`]. See the newer version for documentation. + #[deprecated(note = "Deprecated, use newer version instead")] + fn call( + callee: &[u8], + gas: u64, + value: &[u8], + input_data: &[u8], + output: Option<&mut [u8]>, + ) -> Result; + + /// Make a call to another contract. + /// + /// Equivalent to the newer [`Self::call_v2`] version but works with + /// *ref_time* Weight only + fn call_v1( + flags: CallFlags, + callee: &[u8], + gas: u64, + value: &[u8], + input_data: &[u8], + output: Option<&mut [u8]>, + ) -> Result; + + /// Call (possibly transferring some amount of funds) into the specified account. + /// + /// # Parameters + /// + /// - `flags`: See [`CallFlags`] for a documentation of the supported flags. + /// - `callee`: The address of the callee. Should be decodable as an `T::AccountId`. Traps + /// otherwise. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit`: The storage deposit limit for instantiation. Should be decodable as a + /// `Option`. Traps otherwise. Passing `None` means setting no specific limit for + /// the call, which implies storage usage up to the limit of the parent call. + /// - `value`: The value to transfer into the contract. Should be decodable as a `T::Balance`. + /// Traps otherwise. + /// - `input`: The input data buffer used to call the contract. + /// - `output`: A reference to the output data buffer to write the call output buffer. If `None` + /// is provided then the output buffer is not copied. + /// + /// # Errors + /// + /// An error means that the call wasn't successful output buffer is returned unless + /// stated otherwise. + /// + /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. + /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] + /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] + /// - [NotCallable][`crate::ReturnErrorCode::NotCallable] + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn call_v2( + flags: CallFlags, + callee: &[u8], + ref_time_limit: u64, + proof_time_limit: u64, + deposit: Option<&[u8]>, + value: &[u8], + input_data: &[u8], + output: Option<&mut [u8]>, + ) -> Result; + + /// Call into the chain extension provided by the chain if any. + /// + /// Handling of the input values is up to the specific chain extension and so is the + /// return value. The extension can decide to use the inputs as primitive inputs or as + /// in/out arguments by interpreting them as pointers. Any caller of this function + /// must therefore coordinate with the chain that it targets. + /// + /// # Note + /// + /// If no chain extension exists the contract will trap with the `NoChainExtension` + /// module error. + /// + /// # Parameters + /// + /// - `func_id`: The function id of the chain extension. + /// - `input`: The input data buffer. + /// - `output`: A reference to the output data buffer to write the output data. + /// + /// # Return + /// + /// The chain extension returned value, if executed successfully. + fn call_chain_extension(func_id: u32, input: &[u8], output: &mut &mut [u8]) -> u32; + + /// Call some dispatchable of the runtime. + /// + /// # Parameters + /// + /// - `call`: The call data. + /// + /// # Return + /// + /// Returns `Error::Success` when the dispatchable was successfully executed and + /// returned `Ok`. When the dispatchable was executed but returned an error + /// `Error::CallRuntimeFailed` is returned. The full error is not + /// provided because it is not guaranteed to be stable. + /// + /// # Comparison with `ChainExtension` + /// + /// Just as a chain extension this API allows the runtime to extend the functionality + /// of contracts. While making use of this function is generally easier it cannot be + /// used in all cases. Consider writing a chain extension if you need to do perform + /// one of the following tasks: + /// + /// - Return data. + /// - Provide functionality **exclusively** to contracts. + /// - Provide custom weights. + /// - Avoid the need to keep the `Call` data structure stable. + fn call_runtime(call: &[u8]) -> Result; + + /// Stores the address of the caller into the supplied buffer. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the + /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then + /// the address of the contract will be returned. + /// + /// If there is no address associated with the caller (e.g. because the caller is root) then + /// it traps with `BadOrigin`. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the caller address. + fn caller(output: &mut &mut [u8]); + + /// Checks whether the caller of the current contract is the origin of the whole call stack. + /// + /// Prefer this over [`is_contract()`][`Self::is_contract`] when checking whether your contract + /// is being called by a contract or a plain account. The reason is that it performs better + /// since it does not need to do any storage lookups. + /// + /// # Return + /// + /// A return value of `true` indicates that this contract is being called by a plain account + /// and `false` indicates that the caller is another contract. + fn caller_is_origin() -> bool; + + /// Checks whether the caller of the current contract is root. + /// + /// Note that only the origin of the call stack can be root. Hence this function returning + /// `true` implies that the contract is being called by the origin. + /// + /// A return value of `true` indicates that this contract is being called by a root origin, + /// and `false` indicates that the caller is a signed origin. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn caller_is_root() -> u32; + + /// Clear the value at the given key in the contract storage. + /// + /// Equivalent to the newer [`Self::clear_storage_v1`] version with + /// the exception of the return type. Still a valid thing to call when not interested in the + /// return value. + fn clear_storage(key: &[u8]); + + /// Clear the value at the given key in the contract storage. + /// + /// # Parameters + /// + /// - `key`: The storage key. + /// + /// # Return + /// + /// Returns the size of the pre-existing value at the specified key if any. + fn clear_storage_v1(key: &[u8]) -> Option; + + /// Retrieve the code hash for a specified contract address. + /// + /// # Parameters + /// + /// - `account_id`: The address of the contract.Should be decodable as an `T::AccountId`. Traps + /// otherwise. + /// - `output`: A reference to the output data buffer to write the code hash. + /// + /// + /// # Errors + /// + /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] + fn code_hash(account_id: &[u8], output: &mut [u8]) -> Result; + + /// Checks whether there is a value stored under the given key. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + fn contains_storage(key: &[u8]) -> Option; + + /// Checks whether there is a value stored under the given key. + /// + /// The key length must not exceed the maximum defined by the contracts module parameter. + /// + /// # Parameters + /// - `key`: The storage key. + /// + /// # Return + /// + /// Returns the size of the pre-existing value at the specified key if any. + fn contains_storage_v1(key: &[u8]) -> Option; + + /// Execute code in the context (storage, caller, value) of the current contract. + /// + /// Reentrancy protection is always disabled since the callee is allowed + /// to modify the callers storage. This makes going through a reentrancy attack + /// unnecessary for the callee when it wants to exploit the caller. + /// + /// # Parameters + /// + /// - `flags`: See [`CallFlags`] for a documentation of the supported flags. + /// - `code_hash`: The hash of the code to be executed. + /// - `input`: The input data buffer used to call the contract. + /// - `output`: A reference to the output data buffer to write the call output buffer. If `None` + /// is provided then the output buffer is not copied. + /// + /// # Errors + /// + /// An error means that the call wasn't successful and no output buffer is returned unless + /// stated otherwise. + /// + /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. + /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] + /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] + fn delegate_call( + flags: CallFlags, + code_hash: &[u8], + input_data: &[u8], + output: Option<&mut [u8]>, + ) -> Result; + + /// Deposit a contract event with the data buffer and optional list of topics. There is a limit + /// on the maximum number of topics specified by `event_topics`. + /// + /// There should not be any duplicates in `topics`. + /// + /// # Parameters + /// + /// - `topics`: The topics list encoded as `Vec`. It can't contain duplicates. + fn deposit_event(topics: &[u8], data: &[u8]); + + /// Recovers the ECDSA public key from the given message hash and signature. + /// + /// Writes the public key into the given output buffer. + /// Assumes the secp256k1 curve. + /// + /// # Parameters + /// + /// - `signature`: The signature bytes. + /// - `message_hash`: The message hash bytes. + /// - `output`: A reference to the output data buffer to write the public key. + /// + /// # Errors + /// + /// - [EcdsaRecoveryFailed][`crate::ReturnErrorCode::EcdsaRecoveryFailed] + fn ecdsa_recover( + signature: &[u8; 65], + message_hash: &[u8; 32], + output: &mut [u8; 33], + ) -> Result; + + /// Calculates Ethereum address from the ECDSA compressed public key and stores + /// it into the supplied buffer. + /// + /// # Parameters + /// + /// - `pubkey`: The public key bytes. + /// - `output`: A reference to the output data buffer to write the address. + /// + /// # Errors + /// + /// - [EcdsaRecoveryFailed][`crate::ReturnErrorCode::EcdsaRecoveryFailed] + fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result; + + /// Stores the weight left into the supplied buffer. + /// + /// Equivalent to the newer [`Self::gas_left_v1`] version but + /// works with *ref_time* Weight only. + fn gas_left(out: &mut &mut [u8]); + + /// Stores the amount of weight left into the supplied buffer. + /// The data is encoded as Weight. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the weight left. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn gas_left_v1(output: &mut &mut [u8]); + + /// Retrieve the value under the given key from storage. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + fn get_storage(key: &[u8], output: &mut &mut [u8]) -> Result; + + /// Retrieve the value under the given key from storage. + /// + /// The key length must not exceed the maximum defined by the contracts module parameter. + /// + /// # Parameters + /// - `key`: The storage key. + /// - `output`: A reference to the output data buffer to write the storage entry. + /// + /// # Errors + /// + /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] + fn get_storage_v1(key: &[u8], output: &mut &mut [u8]) -> Result; + + hash_fn!(sha2_256, 32); + hash_fn!(keccak_256, 32); + hash_fn!(blake2_256, 32); + hash_fn!(blake2_128, 16); + + /// Stores the input passed by the caller into the supplied buffer. + /// + /// # Note + /// + /// This function traps if: + /// - the input is larger than the available space. + /// - the input was previously forwarded by a [`call()`][`Self::call()`]. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the input data. + fn input(output: &mut &mut [u8]); + + /// Instantiate a contract with the specified code hash. + /// + /// Equivalent to the newer [`Self::instantiate_v2`] version but works + /// with *ref_time* Weight only. + fn instantiate_v1( + code_hash: &[u8], + gas: u64, + value: &[u8], + input: &[u8], + address: Option<&mut [u8]>, + output: Option<&mut [u8]>, + salt: &[u8], + ) -> Result; + + /// Instantiate a contract with the specified code hash. + /// + /// This function creates an account and executes the constructor defined in the code specified + /// by the code hash. + /// + /// # Parameters + /// + /// - `code_hash`: The hash of the code to be instantiated. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit`: The storage deposit limit for instantiation. Should be decodable as a + /// `Option`. Traps otherwise. Passing `None` means setting no specific limit for + /// the call, which implies storage usage up to the limit of the parent call. + /// - `value`: The value to transfer into the contract. Should be decodable as a `T::Balance`. + /// Traps otherwise. + /// - `input`: The input data buffer. + /// - `address`: A reference to the address buffer to write the address of the contract. If + /// `None` is provided then the output buffer is not copied. + /// - `output`: A reference to the return value buffer to write the constructor output buffer. + /// If `None` is provided then the output buffer is not copied. + /// - `salt`: The salt bytes to use for this instantiation. + /// + /// # Errors + /// + /// Please consult the [ReturnErrorCode][`crate::ReturnErrorCode`] enum declaration for more + /// information on those errors. Here we only note things specific to this function. + /// + /// An error means that the account wasn't created and no address or output buffer + /// is returned unless stated otherwise. + /// + /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. + /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] + /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] + /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn instantiate_v2( + code_hash: &[u8], + ref_time_limit: u64, + proof_size_limit: u64, + deposit: Option<&[u8]>, + value: &[u8], + input: &[u8], + address: Option<&mut [u8]>, + output: Option<&mut [u8]>, + salt: &[u8], + ) -> Result; + + /// Returns a nonce that is unique per contract instantiation. + /// + /// The nonce is incremented for each successful contract instantiation. This is a + /// sensible default salt for contract instantiations. + fn instantiation_nonce() -> u64; + + /// Checks whether a specified address belongs to a contract. + /// + /// # Parameters + /// + /// - `account_id`: The address to check. Should be decodable as an `T::AccountId`. Traps + /// otherwise. + /// + /// # Return + /// + /// Returns `true` if the address belongs to a contract. + fn is_contract(account_id: &[u8]) -> bool; + + /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. + /// The data is encoded as `T::Balance`. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the minimum balance. + fn minimum_balance(output: &mut &mut [u8]); + + /// Retrieve the code hash of the currently executing contract. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the code hash. + fn own_code_hash(output: &mut [u8]); + + /// Load the latest block timestamp into the supplied buffer + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the timestamp. + fn now(output: &mut &mut [u8]); + + /// Returns the number of times the currently executing contract exists on the call stack in + /// addition to the calling instance. + /// + /// # Return + /// + /// Returns `0` when there is no reentrancy. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn reentrance_count() -> u32; + + /// Removes the delegate dependency from the contract. + /// + /// Traps if the delegate dependency does not exist. + /// + /// # Parameters + /// + /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps + /// otherwise. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn remove_delegate_dependency(code_hash: &[u8]); + + /// Cease contract execution and save a data buffer as a result of the execution. + /// + /// This function never returns as it stops execution of the caller. + /// This is the only way to return a data buffer to the caller. Returning from + /// execution without calling this function is equivalent to calling: + /// ```nocompile + /// return_value(ReturnFlags::empty(), &[]) + /// ``` + /// + /// Using an unnamed non empty `ReturnFlags` triggers a trap. + /// + /// # Parameters + /// + /// - `flags`: Flag used to signal special return conditions to the supervisor. See + /// [`ReturnFlags`] for a documentation of the supported flags. + /// - `return_value`: The return value buffer. + fn return_value(flags: ReturnFlags, return_value: &[u8]) -> !; + + /// Replace the contract code at the specified address with new code. + /// + /// # Note + /// + /// There are a couple of important considerations which must be taken into account when + /// using this API: + /// + /// 1. The storage at the code address will remain untouched. This means that contract + /// developers must ensure that the storage layout of the new code is compatible with that of + /// the old code. + /// + /// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another + /// way, when using this API you lose the guarantee that an address always identifies a specific + /// code hash. + /// + /// 3. If a contract calls into itself after changing its code the new call would use + /// the new code. However, if the original caller panics after returning from the sub call it + /// would revert the changes made by [`set_code_hash()`][`Self::set_code_hash`] and the next + /// caller would use the old code. + /// + /// # Parameters + /// + /// - `code_hash`: The hash of the new code. Should be decodable as an `T::Hash`. Traps + /// otherwise. + /// + /// # Errors + /// + /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] + fn set_code_hash(code_hash: &[u8]) -> Result; + + /// Set the value at the given key in the contract storage. + /// + /// Equivalent to [`Self::set_storage_v1`] version with the + /// exception of the return type. Still a valid thing to call for fixed sized storage key, when + /// not interested in the return value. + fn set_storage(key: &[u8], value: &[u8]); + + /// Set the value at the given key in the contract storage. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + fn set_storage_v1(key: &[u8], value: &[u8]) -> Option; + + /// Set the value at the given key in the contract storage. + /// + /// The key and value lengths must not exceed the maximums defined by the contracts module + /// parameters. + /// + /// # Parameters + /// + /// - `key`: The storage key. + /// - `encoded_value`: The storage value. + /// + /// # Return + /// + /// Returns the size of the pre-existing value at the specified key if any. + fn set_storage_v2(key: &[u8], value: &[u8]) -> Option; + + /// Verify a sr25519 signature + /// + /// # Parameters + /// + /// - `signature`: The signature bytes. + /// - `message`: The message bytes. + /// + /// # Errors + /// + /// - [Sr25519VerifyFailed][`crate::ReturnErrorCode::Sr25519VerifyFailed] + fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result; + + /// Retrieve and remove the value under the given key from storage. + /// + /// # Parameters + /// - `key`: The storage key. + /// - `output`: A reference to the output data buffer to write the storage entry. + /// + /// # Errors + /// + /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] + fn take_storage(key: &[u8], output: &mut &mut [u8]) -> Result; + + /// Transfer some amount of funds into the specified account. + /// + /// # Parameters + /// + /// - `account_id`: The address of the account to transfer funds to. Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// - `value`: The value to transfer. Should be decodable as a `T::Balance`. Traps otherwise. + /// + /// # Errors + /// + /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] + fn transfer(account_id: &[u8], value: &[u8]) -> Result; + + /// Remove the calling account and transfer remaining balance. + /// + /// This is equivalent to calling the newer version of this function + #[deprecated(note = "Deprecated, use newer version instead")] + fn terminate(beneficiary: &[u8]) -> !; + + /// Remove the calling account and transfer remaining **free** balance. + /// + /// This function never returns. Either the termination was successful and the + /// execution of the destroyed contract is halted. Or it failed during the termination + /// which is considered fatal and results in a trap + rollback. + /// + /// # Parameters + /// + /// - `beneficiary`: The address of the beneficiary account, Should be decodable as an + /// `T::AccountId`. + /// + /// # Traps + /// + /// - The contract is live i.e is already on the call stack. + /// - Failed to send the balance to the beneficiary. + /// - The deletion queue is full. + fn terminate_v1(beneficiary: &[u8]) -> !; + + /// Stores the value transferred along with this call/instantiate into the supplied buffer. + /// The data is encoded as `T::Balance`. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the transferred value. + fn value_transferred(output: &mut &mut [u8]); + + /// Stores the price for the specified amount of gas into the supplied buffer. + /// + /// Equivalent to the newer [`Self::weight_to_fee_v1`] version but + /// works with *ref_time* Weight only. It is recommended to switch to the latest version, once + /// it's stabilized. + fn weight_to_fee(gas: u64, output: &mut &mut [u8]); + + /// Stores the price for the specified amount of gas into the supplied buffer. + /// The data is encoded as `T::Balance`. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. + /// + /// # Parameters + /// + /// - `ref_time_limit`: The *ref_time* Weight limit to query the price for. + /// - `proof_size_limit`: The *proof_size* Weight limit to query the price for. + /// - `output`: A reference to the output data buffer to write the price. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn weight_to_fee_v1(ref_time_limit: u64, proof_size_limit: u64, output: &mut &mut [u8]); + + /// Execute an XCM program locally, using the contract's address as the origin. + /// This is equivalent to dispatching `pallet_xcm::execute` through call_runtime, except that + /// the function is called directly instead of being dispatched. + /// + /// # Parameters + /// + /// - `msg`: The message, should be decodable as a [VersionedXcm](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedXcm.html), + /// traps otherwise. + /// - `output`: A reference to the output data buffer to write the [Outcome](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v3/enum.Outcome.html) + /// + /// # Return + /// + /// Returns `Error::Success` when the XCM execution attempt is successful. When the XCM + /// execution fails, `ReturnCode::XcmExecutionFailed` is returned + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn xcm_execute(msg: &[u8], output: &mut &mut [u8]) -> Result; + + /// Send an XCM program from the contract to the specified destination. + /// This is equivalent to dispatching `pallet_xcm::send` through `call_runtime`, except that + /// the function is called directly instead of being dispatched. + /// + /// # Parameters + /// + /// - `dest`: The XCM destination, should be decodable as [VersionedMultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedMultiLocation.html), + /// traps otherwise. + /// - `msg`: The message, should be decodable as a [VersionedXcm](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedXcm.html), + /// traps otherwise. + /// - `output`: A reference to the output data buffer to write the [XcmHash](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v3/type.XcmHash.html) + /// + /// # Return + /// + /// Returns `ReturnCode::Success` when the message was successfully sent. When the XCM + /// execution fails, `ReturnErrorCode::XcmSendFailed` is returned. + #[deprecated( + note = "Unstable function. Behaviour can change without further notice. Use only for testing." + )] + fn xcm_send(dest: &[u8], msg: &[u8], output: &mut &mut [u8]) -> Result; +} diff --git a/substrate/frame/contracts/uapi/src/host/riscv32.rs b/substrate/frame/contracts/uapi/src/host/riscv32.rs new file mode 100644 index 00000000000..f58b8831f06 --- /dev/null +++ b/substrate/frame/contracts/uapi/src/host/riscv32.rs @@ -0,0 +1,14 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// 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. +// TODO: bring up to date with wasm32.rs diff --git a/substrate/frame/contracts/uapi/src/host/wasm32.rs b/substrate/frame/contracts/uapi/src/host/wasm32.rs new file mode 100644 index 00000000000..d30058daf3d --- /dev/null +++ b/substrate/frame/contracts/uapi/src/host/wasm32.rs @@ -0,0 +1,811 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// 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::{ + extract_from_slice, ptr_len_or_sentinel, ptr_or_sentinel, CallFlags, HostFn, HostFnImpl, Result, +}; +use crate::{ReturnCode, ReturnFlags}; + +mod sys { + use super::ReturnCode; + + #[link(wasm_import_module = "seal0")] + extern "C" { + pub fn account_reentrance_count(account_ptr: *const u8) -> u32; + + pub fn add_delegate_dependency(code_hash_ptr: *const u8); + + pub fn address(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn balance(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn block_number(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn call( + callee_ptr: *const u8, + callee_len: u32, + gas: u64, + value_ptr: *const u8, + value_len: u32, + input_data_ptr: *const u8, + input_data_len: u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn call_chain_extension( + func_id: u32, + input_ptr: *const u8, + input_len: u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn call_runtime(call_ptr: *const u8, call_len: u32) -> ReturnCode; + + pub fn caller(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn caller_is_origin() -> ReturnCode; + + pub fn caller_is_root() -> ReturnCode; + + pub fn clear_storage(key_ptr: *const u8, key_len: u32) -> ReturnCode; + + pub fn code_hash( + account_id_ptr: *const u8, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn contains_storage(key_ptr: *const u8, key_len: u32) -> ReturnCode; + + pub fn delegate_call( + flags: u32, + code_hash_ptr: *const u8, + input_data_ptr: *const u8, + input_data_len: u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn deposit_event( + topics_ptr: *const u8, + topics_len: u32, + data_ptr: *const u8, + data_len: u32, + ); + + pub fn ecdsa_recover( + signature_ptr: *const u8, + message_hash_ptr: *const u8, + output_ptr: *mut u8, + ) -> ReturnCode; + + pub fn ecdsa_to_eth_address(public_key_ptr: *const u8, output_ptr: *mut u8) -> ReturnCode; + + pub fn gas_left(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn get_storage( + key_ptr: *const u8, + key_len: u32, + out_ptr: *mut u8, + out_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn hash_blake2_128(input_ptr: *const u8, input_len: u32, output_ptr: *mut u8); + + pub fn hash_blake2_256(input_ptr: *const u8, input_len: u32, output_ptr: *mut u8); + + pub fn hash_keccak_256(input_ptr: *const u8, input_len: u32, output_ptr: *mut u8); + + pub fn hash_sha2_256(input_ptr: *const u8, input_len: u32, output_ptr: *mut u8); + + pub fn input(buf_ptr: *mut u8, buf_len_ptr: *mut u32); + + pub fn instantiation_nonce() -> u64; + + pub fn is_contract(account_id_ptr: *const u8) -> ReturnCode; + + pub fn minimum_balance(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn now(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn own_code_hash(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn reentrance_count() -> u32; + + pub fn remove_delegate_dependency(code_hash_ptr: *const u8); + + pub fn seal_return(flags: u32, data_ptr: *const u8, data_len: u32) -> !; + + pub fn set_code_hash(code_hash_ptr: *const u8) -> ReturnCode; + + pub fn set_storage( + key_ptr: *const u8, + key_len: u32, + value_ptr: *const u8, + value_len: u32, + ) -> ReturnCode; + + pub fn sr25519_verify( + signature_ptr: *const u8, + public_key_ptr: *const u8, + message_len: u32, + message_ptr: *const u8, + ) -> ReturnCode; + + pub fn take_storage( + key_ptr: *const u8, + key_len: u32, + out_ptr: *mut u8, + out_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn terminate(beneficiary_ptr: *const u8) -> !; + + pub fn transfer( + account_id_ptr: *const u8, + account_id_len: u32, + transferred_value_ptr: *const u8, + transferred_value_len: u32, + ) -> ReturnCode; + + pub fn value_transferred(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn weight_to_fee(gas: u64, output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn xcm_execute(msg_ptr: *const u8, msg_len: u32, output_ptr: *mut u8) -> ReturnCode; + + pub fn xcm_send( + dest_ptr: *const u8, + msg_ptr: *const u8, + msg_len: u32, + output_ptr: *mut u8, + ) -> ReturnCode; + } + + pub mod v1 { + use crate::ReturnCode; + + #[link(wasm_import_module = "seal1")] + extern "C" { + pub fn call( + flags: u32, + callee_ptr: *const u8, + gas: u64, + transferred_value_ptr: *const u8, + input_data_ptr: *const u8, + input_data_len: u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn clear_storage(key_ptr: *const u8, key_len: u32) -> ReturnCode; + + pub fn contains_storage(key_ptr: *const u8, key_len: u32) -> ReturnCode; + + pub fn gas_left(output_ptr: *mut u8, output_len_ptr: *mut u32); + + pub fn get_storage( + key_ptr: *const u8, + key_len: u32, + out_ptr: *mut u8, + out_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn instantiate( + code_hash_ptr: *const u8, + gas: u64, + value_ptr: *const u8, + input_ptr: *const u8, + input_len: u32, + address_ptr: *mut u8, + address_len_ptr: *mut u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + salt_ptr: *const u8, + salt_len: u32, + ) -> ReturnCode; + + pub fn set_storage( + key_ptr: *const u8, + key_len: u32, + value_ptr: *const u8, + value_len: u32, + ) -> ReturnCode; + + pub fn terminate(beneficiary_ptr: *const u8) -> !; + + pub fn weight_to_fee( + ref_time_limit: u64, + proof_time_limit: u64, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ); + } + } + + pub mod v2 { + use crate::ReturnCode; + + #[link(wasm_import_module = "seal2")] + extern "C" { + pub fn call( + flags: u32, + callee_ptr: *const u8, + ref_time_limit: u64, + proof_time_limit: u64, + deposit_ptr: *const u8, + transferred_value_ptr: *const u8, + input_data_ptr: *const u8, + input_data_len: u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + ) -> ReturnCode; + + pub fn instantiate( + code_hash_ptr: *const u8, + ref_time_limit: u64, + proof_time_limit: u64, + deposit_ptr: *const u8, + value_ptr: *const u8, + input_ptr: *const u8, + input_len: u32, + address_ptr: *mut u8, + address_len_ptr: *mut u32, + output_ptr: *mut u8, + output_len_ptr: *mut u32, + salt_ptr: *const u8, + salt_len: u32, + ) -> ReturnCode; + + pub fn set_storage( + key_ptr: *const u8, + key_len: u32, + value_ptr: *const u8, + value_len: u32, + ) -> ReturnCode; + } + } +} + +/// A macro to implement all Host functions with a signature of `fn(&mut &mut [u8])`. +macro_rules! impl_wrapper_for { + (@impl_fn $( $mod:ident )::*, $suffix:literal, $name:ident) => { + paste::paste! { + fn [<$name $suffix>](output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + unsafe { + $( $mod )::*::$name(output.as_mut_ptr(), &mut output_len); + } + } + } + }; + + () => {}; + + (($mod:ident, $suffix:literal) => [$( $name:ident),*], $($tail:tt)*) => { + $(impl_wrapper_for!(@impl_fn sys::$mod, $suffix, $name);)* + impl_wrapper_for!($($tail)*); + }; + + (() => [$( $name:ident),*], $($tail:tt)*) => { + $(impl_wrapper_for!(@impl_fn sys, "", $name);)* + impl_wrapper_for!($($tail)*); + }; +} + +/// A macro to implement all the hash functions Apis. +macro_rules! impl_hash_fn { + ( $name:ident, $bytes_result:literal ) => { + paste::item! { + fn [](input: &[u8], output: &mut [u8; $bytes_result]) { + unsafe { + sys::[]( + input.as_ptr(), + input.len() as u32, + output.as_mut_ptr(), + ) + } + } + } + }; +} + +/// A macro to implement the get_storage functions. +macro_rules! impl_get_storage { + ($fn_name:ident, $sys_get_storage:path) => { + fn $fn_name(key: &[u8], output: &mut &mut [u8]) -> Result { + let mut output_len = output.len() as u32; + let ret_code = { + unsafe { + $sys_get_storage( + key.as_ptr(), + key.len() as u32, + output.as_mut_ptr(), + &mut output_len, + ) + } + }; + extract_from_slice(output, output_len as usize); + ret_code.into() + } + }; +} + +impl HostFn for HostFnImpl { + fn instantiate_v1( + code_hash: &[u8], + gas: u64, + value: &[u8], + input: &[u8], + mut address: Option<&mut [u8]>, + mut output: Option<&mut [u8]>, + salt: &[u8], + ) -> Result { + let (address_ptr, mut address_len) = ptr_len_or_sentinel(&mut address); + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let ret_code = unsafe { + sys::v1::instantiate( + code_hash.as_ptr(), + gas, + value.as_ptr(), + input.as_ptr(), + input.len() as u32, + address_ptr, + &mut address_len, + output_ptr, + &mut output_len, + salt.as_ptr(), + salt.len() as u32, + ) + }; + + if let Some(ref mut address) = address { + extract_from_slice(address, address_len as usize); + } + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + ret_code.into() + } + + fn instantiate_v2( + code_hash: &[u8], + ref_time_limit: u64, + proof_size_limit: u64, + deposit: Option<&[u8]>, + value: &[u8], + input: &[u8], + mut address: Option<&mut [u8]>, + mut output: Option<&mut [u8]>, + salt: &[u8], + ) -> Result { + let (address_ptr, mut address_len) = ptr_len_or_sentinel(&mut address); + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let deposit_ptr = ptr_or_sentinel(&deposit); + + let ret_code = { + unsafe { + sys::v2::instantiate( + code_hash.as_ptr(), + ref_time_limit, + proof_size_limit, + deposit_ptr, + value.as_ptr(), + input.as_ptr(), + input.len() as u32, + address_ptr, + &mut address_len, + output_ptr, + &mut output_len, + salt.as_ptr(), + salt.len() as u32, + ) + } + }; + + if let Some(ref mut address) = address { + extract_from_slice(address, address_len as usize); + } + + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + + ret_code.into() + } + + fn call( + callee: &[u8], + gas: u64, + value: &[u8], + input_data: &[u8], + mut output: Option<&mut [u8]>, + ) -> Result { + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let ret_code = { + unsafe { + sys::call( + callee.as_ptr(), + callee.len() as u32, + gas, + value.as_ptr(), + value.len() as u32, + input_data.as_ptr(), + input_data.len() as u32, + output_ptr, + &mut output_len, + ) + } + }; + + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + + ret_code.into() + } + + fn call_v1( + flags: CallFlags, + callee: &[u8], + gas: u64, + value: &[u8], + input_data: &[u8], + mut output: Option<&mut [u8]>, + ) -> Result { + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let ret_code = { + unsafe { + sys::v1::call( + flags.bits(), + callee.as_ptr(), + gas, + value.as_ptr(), + input_data.as_ptr(), + input_data.len() as u32, + output_ptr, + &mut output_len, + ) + } + }; + + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + + ret_code.into() + } + + fn call_v2( + flags: CallFlags, + callee: &[u8], + ref_time_limit: u64, + proof_time_limit: u64, + deposit: Option<&[u8]>, + value: &[u8], + input_data: &[u8], + mut output: Option<&mut [u8]>, + ) -> Result { + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let deposit_ptr = ptr_or_sentinel(&deposit); + let ret_code = { + unsafe { + sys::v2::call( + flags.bits(), + callee.as_ptr(), + ref_time_limit, + proof_time_limit, + deposit_ptr, + value.as_ptr(), + input_data.as_ptr(), + input_data.len() as u32, + output_ptr, + &mut output_len, + ) + } + }; + + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + + ret_code.into() + } + + fn caller_is_root() -> u32 { + unsafe { sys::caller_is_root() }.into_u32() + } + + fn delegate_call( + flags: CallFlags, + code_hash: &[u8], + input: &[u8], + mut output: Option<&mut [u8]>, + ) -> Result { + let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); + let ret_code = { + unsafe { + sys::delegate_call( + flags.bits(), + code_hash.as_ptr(), + input.as_ptr(), + input.len() as u32, + output_ptr, + &mut output_len, + ) + } + }; + + if let Some(ref mut output) = output { + extract_from_slice(output, output_len as usize); + } + + ret_code.into() + } + + fn transfer(account_id: &[u8], value: &[u8]) -> Result { + let ret_code = unsafe { + sys::transfer( + account_id.as_ptr(), + account_id.len() as u32, + value.as_ptr(), + value.len() as u32, + ) + }; + ret_code.into() + } + + fn deposit_event(topics: &[u8], data: &[u8]) { + unsafe { + sys::deposit_event( + topics.as_ptr(), + topics.len() as u32, + data.as_ptr(), + data.len() as u32, + ) + } + } + + fn set_storage(key: &[u8], value: &[u8]) { + unsafe { + sys::set_storage(key.as_ptr(), key.len() as u32, value.as_ptr(), value.len() as u32) + }; + } + + fn set_storage_v1(key: &[u8], encoded_value: &[u8]) -> Option { + let ret_code = unsafe { + sys::v1::set_storage( + key.as_ptr(), + key.len() as u32, + encoded_value.as_ptr(), + encoded_value.len() as u32, + ) + }; + ret_code.into() + } + + fn set_storage_v2(key: &[u8], encoded_value: &[u8]) -> Option { + let ret_code = unsafe { + sys::v2::set_storage( + key.as_ptr(), + key.len() as u32, + encoded_value.as_ptr(), + encoded_value.len() as u32, + ) + }; + ret_code.into() + } + + fn clear_storage(key: &[u8]) { + unsafe { sys::clear_storage(key.as_ptr(), key.len() as u32) }; + } + + fn clear_storage_v1(key: &[u8]) -> Option { + let ret_code = unsafe { sys::v1::clear_storage(key.as_ptr(), key.len() as u32) }; + ret_code.into() + } + + impl_get_storage!(get_storage, sys::get_storage); + impl_get_storage!(get_storage_v1, sys::v1::get_storage); + + fn take_storage(key: &[u8], output: &mut &mut [u8]) -> Result { + let mut output_len = output.len() as u32; + let ret_code = { + unsafe { + sys::take_storage( + key.as_ptr(), + key.len() as u32, + output.as_mut_ptr(), + &mut output_len, + ) + } + }; + extract_from_slice(output, output_len as usize); + ret_code.into() + } + + fn contains_storage(key: &[u8]) -> Option { + let ret_code = unsafe { sys::contains_storage(key.as_ptr(), key.len() as u32) }; + ret_code.into() + } + + fn contains_storage_v1(key: &[u8]) -> Option { + let ret_code = unsafe { sys::v1::contains_storage(key.as_ptr(), key.len() as u32) }; + ret_code.into() + } + + fn terminate(beneficiary: &[u8]) -> ! { + unsafe { sys::terminate(beneficiary.as_ptr()) } + } + + fn terminate_v1(beneficiary: &[u8]) -> ! { + unsafe { sys::v1::terminate(beneficiary.as_ptr()) } + } + + fn call_chain_extension(func_id: u32, input: &[u8], output: &mut &mut [u8]) -> u32 { + let mut output_len = output.len() as u32; + let ret_code = { + unsafe { + sys::call_chain_extension( + func_id, + input.as_ptr(), + input.len() as u32, + output.as_mut_ptr(), + &mut output_len, + ) + } + }; + extract_from_slice(output, output_len as usize); + ret_code.into_u32() + } + + fn input(output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + { + unsafe { sys::input(output.as_mut_ptr(), &mut output_len) }; + } + extract_from_slice(output, output_len as usize); + } + + fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! { + unsafe { sys::seal_return(flags.bits(), return_value.as_ptr(), return_value.len() as u32) } + } + + fn call_runtime(call: &[u8]) -> Result { + let ret_code = unsafe { sys::call_runtime(call.as_ptr(), call.len() as u32) }; + ret_code.into() + } + + impl_wrapper_for! { + () => [caller, block_number, address, balance, gas_left, value_transferred, now, minimum_balance], + (v1, "_v1") => [gas_left], + } + + fn weight_to_fee(gas: u64, output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + { + unsafe { sys::weight_to_fee(gas, output.as_mut_ptr(), &mut output_len) }; + } + extract_from_slice(output, output_len as usize); + } + + fn weight_to_fee_v1(ref_time_limit: u64, proof_size_limit: u64, output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + { + unsafe { + sys::v1::weight_to_fee( + ref_time_limit, + proof_size_limit, + output.as_mut_ptr(), + &mut output_len, + ) + }; + } + extract_from_slice(output, output_len as usize); + } + + impl_hash_fn!(sha2_256, 32); + impl_hash_fn!(keccak_256, 32); + impl_hash_fn!(blake2_256, 32); + impl_hash_fn!(blake2_128, 16); + + fn ecdsa_recover( + signature: &[u8; 65], + message_hash: &[u8; 32], + output: &mut [u8; 33], + ) -> Result { + let ret_code = unsafe { + sys::ecdsa_recover(signature.as_ptr(), message_hash.as_ptr(), output.as_mut_ptr()) + }; + ret_code.into() + } + + fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result { + let ret_code = unsafe { sys::ecdsa_to_eth_address(pubkey.as_ptr(), output.as_mut_ptr()) }; + ret_code.into() + } + + fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result { + let ret_code = unsafe { + sys::sr25519_verify( + signature.as_ptr(), + pub_key.as_ptr(), + message.len() as u32, + message.as_ptr(), + ) + }; + ret_code.into() + } + + fn is_contract(account_id: &[u8]) -> bool { + let ret_val = unsafe { sys::is_contract(account_id.as_ptr()) }; + ret_val.into_bool() + } + + fn caller_is_origin() -> bool { + let ret_val = unsafe { sys::caller_is_origin() }; + ret_val.into_bool() + } + + fn set_code_hash(code_hash: &[u8]) -> Result { + let ret_val = unsafe { sys::set_code_hash(code_hash.as_ptr()) }; + ret_val.into() + } + + fn code_hash(account_id: &[u8], output: &mut [u8]) -> Result { + let mut output_len = output.len() as u32; + let ret_val = + unsafe { sys::code_hash(account_id.as_ptr(), output.as_mut_ptr(), &mut output_len) }; + ret_val.into() + } + + fn own_code_hash(output: &mut [u8]) { + let mut output_len = output.len() as u32; + unsafe { sys::own_code_hash(output.as_mut_ptr(), &mut output_len) } + } + + fn account_reentrance_count(account: &[u8]) -> u32 { + unsafe { sys::account_reentrance_count(account.as_ptr()) } + } + + fn add_delegate_dependency(code_hash: &[u8]) { + unsafe { sys::add_delegate_dependency(code_hash.as_ptr()) } + } + + fn remove_delegate_dependency(code_hash: &[u8]) { + unsafe { sys::remove_delegate_dependency(code_hash.as_ptr()) } + } + + fn instantiation_nonce() -> u64 { + unsafe { sys::instantiation_nonce() } + } + + fn reentrance_count() -> u32 { + unsafe { sys::reentrance_count() } + } + + fn xcm_execute(msg: &[u8], output: &mut &mut [u8]) -> Result { + let ret_code = + unsafe { sys::xcm_execute(msg.as_ptr(), msg.len() as _, output.as_mut_ptr()) }; + ret_code.into() + } + + fn xcm_send(dest: &[u8], msg: &[u8], output: &mut &mut [u8]) -> Result { + let ret_code = unsafe { + sys::xcm_send(dest.as_ptr(), msg.as_ptr(), msg.len() as _, output.as_mut_ptr()) + }; + ret_code.into() + } +} diff --git a/substrate/frame/contracts/uapi/src/lib.rs b/substrate/frame/contracts/uapi/src/lib.rs new file mode 100644 index 00000000000..3d384bbb85d --- /dev/null +++ b/substrate/frame/contracts/uapi/src/lib.rs @@ -0,0 +1,139 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// 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. + +//! External C API to communicate with substrate contracts runtime module. +//! +//! Refer to substrate FRAME contract module for more documentation. + +#![no_std] + +mod flags; +pub use flags::*; + +#[cfg(any(target_arch = "wasm32", target_arch = "riscv32"))] +mod host; + +#[cfg(any(target_arch = "wasm32", target_arch = "riscv32"))] +pub use host::*; + +macro_rules! define_error_codes { + ( + $( + $( #[$attr:meta] )* + $name:ident = $discr:literal, + )* + ) => { + /// Every error that can be returned to a contract when it calls any of the host functions. + #[derive(Debug)] + #[repr(u32)] + pub enum ReturnErrorCode { + /// API call successful. + Success = 0, + $( + $( #[$attr] )* + $name = $discr, + )* + /// Returns if an unknown error was received from the host module. + Unknown, + } + + impl From for Result { + #[inline] + fn from(return_code: ReturnCode) -> Self { + match return_code.0 { + 0 => Ok(()), + $( + $discr => Err(ReturnErrorCode::$name), + )* + _ => Err(ReturnErrorCode::Unknown), + } + } + } + }; +} + +impl From for u32 { + fn from(code: ReturnErrorCode) -> u32 { + code as u32 + } +} + +define_error_codes! { + /// The called function trapped and has its state changes reverted. + /// In this case no output buffer is returned. + /// Can only be returned from `call` and `instantiate`. + CalleeTrapped = 1, + /// The called function ran to completion but decided to revert its state. + /// An output buffer is returned when one was supplied. + /// Can only be returned from `call` and `instantiate`. + CalleeReverted = 2, + /// The passed key does not exist in storage. + KeyNotFound = 3, + /// Deprecated and no longer returned: There is only the minimum balance. + _BelowSubsistenceThreshold = 4, + /// Transfer failed for other not further specified reason. Most probably + /// reserved or locked balance of the sender that was preventing the transfer. + TransferFailed = 5, + /// Deprecated and no longer returned: Endowment is no longer required. + _EndowmentTooLow = 6, + /// No code could be found at the supplied code hash. + CodeNotFound = 7, + /// The account that was called is no contract. + NotCallable = 8, + /// The call to `debug_message` had no effect because debug message + /// recording was disabled. + LoggingDisabled = 9, + /// The call dispatched by `call_runtime` was executed but returned an error. + CallRuntimeFailed = 10, + /// ECDSA public key recovery failed. Most probably wrong recovery id or signature. + EcdsaRecoveryFailed = 11, + /// sr25519 signature verification failed. + Sr25519VerifyFailed = 12, + /// The `xcm_execute` call failed. + XcmExecutionFailed = 13, + /// The `xcm_send` call failed. + XcmSendFailed = 14, +} + +/// The raw return code returned by the host side. +#[repr(transparent)] +pub struct ReturnCode(u32); + +/// Used as a sentinel value when reading and writing contract memory. +/// +/// We use this value to signal `None` to a contract when only a primitive is +/// allowed and we don't want to go through encoding a full Rust type. +/// Using `u32::Max` is a safe sentinel because contracts are never +/// allowed to use such a large amount of resources. So this value doesn't +/// make sense for a memory location or length. +const SENTINEL: u32 = u32::MAX; + +impl From for Option { + fn from(code: ReturnCode) -> Self { + (code.0 < SENTINEL).then_some(code.0) + } +} + +impl ReturnCode { + /// Returns the raw underlying `u32` representation. + pub fn into_u32(self) -> u32 { + self.0 + } + /// Returns the underlying `u32` converted into `bool`. + pub fn into_bool(self) -> bool { + self.0.ne(&0) + } +} + +type Result = core::result::Result<(), ReturnErrorCode>; -- GitLab From e41a0e728bc300a3f384414559bb906adedc5125 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Thu, 30 Nov 2023 09:03:47 +0100 Subject: [PATCH 622/633] upgraded review bot to 2.3.0 (#2549) Upgraded to version 2.3.0 which includes: - paritytech/review-bot#103 - paritytech/review-bot#102 --- .github/workflows/review-bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index 5970989cde0..0a7e80f007c 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -23,7 +23,7 @@ jobs: app_id: ${{ secrets.REVIEW_APP_ID }} private_key: ${{ secrets.REVIEW_APP_KEY }} - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v2.2.0 + uses: paritytech/review-bot@v2.3.0 with: repo-token: ${{ steps.app_token.outputs.token }} team-token: ${{ steps.app_token.outputs.token }} -- GitLab From 180a6ad9b0e7f6225304b811f4accf1d13c5dd11 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:52:20 +0200 Subject: [PATCH 623/633] Register metrics for the notification handles (#2562) Add metrics for notification handles so substream events are correctly reported to Prometheus --- substrate/client/network/src/protocol.rs | 11 ++++++++--- .../client/network/src/protocol/notifications.rs | 2 +- .../network/src/protocol/notifications/behaviour.rs | 6 ++---- .../network/src/protocol/notifications/tests.rs | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index ea7977cc9ae..73b1cd97279 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -43,7 +43,7 @@ use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, iter, task::Poll}; -use notifications::{Notifications, NotificationsOut}; +use notifications::{metrics, Notifications, NotificationsOut}; pub(crate) use notifications::ProtocolHandle; @@ -95,7 +95,7 @@ impl Protocol { // NOTE: Block announcement protocol is still very much hardcoded into // `Protocol`. This protocol must be the first notification protocol given to // `Notifications` - let (protocol_configs, handles): (Vec<_>, Vec<_>) = iter::once({ + let (protocol_configs, mut handles): (Vec<_>, Vec<_>) = iter::once({ let config = notifications::ProtocolConfig { name: block_announces_protocol.protocol_name().clone(), fallback_names: block_announces_protocol.fallback_names().cloned().collect(), @@ -122,11 +122,16 @@ impl Protocol { })) .unzip(); + let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); + handles.iter_mut().for_each(|handle| { + handle.set_metrics(metrics.clone()); + }); + ( Notifications::new( protocol_controller_handles, from_protocol_controllers, - registry, + metrics, protocol_configs.into_iter(), ), installed_protocols, diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index 10fa329097d..8becc1390e7 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -25,7 +25,7 @@ pub use self::{ service::{notification_service, ProtocolHandlePair}, }; -pub(crate) use self::service::ProtocolHandle; +pub(crate) use self::service::{metrics, ProtocolHandle}; mod behaviour; mod handler; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index ef0c6540eee..cdbf2a71b93 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -40,7 +40,6 @@ use libp2p::{ }; use log::{debug, error, trace, warn}; use parking_lot::RwLock; -use prometheus_endpoint::Registry; use rand::distributions::{Distribution as _, Uniform}; use sc_utils::mpsc::TracingUnboundedReceiver; use smallvec::SmallVec; @@ -405,7 +404,7 @@ impl Notifications { pub(crate) fn new( protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - registry: &Option, + metrics: Option, notif_protocols: impl Iterator< Item = ( ProtocolConfig, @@ -429,7 +428,6 @@ impl Notifications { .unzip(); assert!(!notif_protocols.is_empty()); - let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); let (mut protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handles .into_iter() .enumerate() @@ -2452,7 +2450,7 @@ mod tests { Notifications::new( vec![handle], from_controller, - &None, + None, iter::once(( ProtocolConfig { name: "/foo".into(), diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index 92d269f89c3..0178bd75e8b 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -99,7 +99,7 @@ fn build_nodes() -> (Swarm, Swarm) { inner: Notifications::new( vec![controller_handle], from_controller, - &None, + None, iter::once(( ProtocolConfig { name: "/foo".into(), -- GitLab From eaf1bc5633ebbacce97e4f167ebe1d0d268c4b24 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:15:46 +0300 Subject: [PATCH 624/633] Introduce Polkadot-Sdk `developer_hub` (#2102) This PR introduces the new crate `developer_hub` into the polkadot-sdk repo. The vision for the developer-hub crate is detailed in [this document](https://docs.google.com/document/d/1XLLkFNE8v8HLvZpI2rzsa8N2IN1FcKntc8q-Sc4xBAk/edit?usp=sharing). Screenshot 2023-11-02 at 10 45 48 Other than adding the new crate, it also does the following: * Remove the `substrate` crate, as there is now a unique umbrella crate for multiple things in `developer_hub::polkadot_sdk`. * (backport candidate) A minor change to `frame-support` macros that allows `T::RuntimeOrigin` to also be acceptable as the origin type. * (backport candidate) A minor change to `frame-system` that allows us to deposit events at genesis because now the real genesis config is generated via wasm, and we can safely assume `cfg!(feature = "std")` means only testing. related to #62. * (backport candidate) Introduces a small `read_events_for_pallet` to `frame_system` for easier event reading in tests. * From https://github.com/paritytech/polkadot-sdk-docs/issues/31, it takes action on improving the `pallet::call` docs. * From https://github.com/paritytech/polkadot-sdk-docs/issues/31, it takes action on improving the `UncheckedExtrinsic` docs. ## Way Forward First, a version of this is deployed temporarily [here](https://blog.kianenigma.nl/polkadot-sdk/developer_hub/index.html). I will keep it up to date on a daily basis. ### This Pull Request I see two ways forward: 1. We acknowledge that everything in `developer-hub` is going to be WIP, and merge this asap. We should not yet use links to this crate anywhere. 2. We make this be the feature branch, make PRs against this, and either gradually backport it, or only merge to master once it is done. I am personally in favor of option 1. If we stick to option 2, we need a better way to deploy a staging version of this to gh-pages. ### Issue Tracking The main issues related to the future of `developer_hub` are: - https://github.com/paritytech/polkadot-sdk-docs/issues/31 - https://github.com/paritytech/polkadot-sdk-docs/issues/4 - https://github.com/paritytech/polkadot-sdk-docs/issues/26 - https://github.com/paritytech/polkadot-sdk-docs/issues/32 - https://github.com/paritytech/polkadot-sdk-docs/issues/36 ### After This Pull Request - [ ] create a redirect for https://paritytech.github.io/polkadot-sdk/master/substrate/ - [x] analytics - [ ] link checker - [ ] the matter of publishing, and how all of these relative links for when we do, that is still an open question. There is section on this in the landing page. - [ ] updated https://paritytech.github.io/ --------- Co-authored-by: Liam Aharon Co-authored-by: Juan Girini Co-authored-by: bader y Co-authored-by: Sebastian Kunert Co-authored-by: James Wilson Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- .gitlab/pipeline/build.yml | 2 +- Cargo.lock | 76 +- Cargo.toml | 5 +- cumulus/parachain-template/runtime/src/lib.rs | 3 +- developer-hub/Cargo.toml | 66 ++ developer-hub/headers/toc.html | 54 ++ .../src/guides/changing_consensus.rs | 1 + .../src/guides/cumulus_enabled_parachain.rs | 1 + developer-hub/src/guides/mod.rs | 25 + .../src/guides/xcm_enabled_parachain.rs | 1 + developer-hub/src/guides/your_first_node.rs | 1 + .../src/guides/your_first_pallet/mod.rs | 738 ++++++++++++++++++ .../guides/your_first_pallet/with_event.rs | 101 +++ .../src/guides/your_first_runtime.rs | 1 + developer-hub/src/lib.rs | 43 + developer-hub/src/meta_contributing.rs | 146 ++++ developer-hub/src/polkadot_sdk/cumulus.rs | 130 +++ .../src/polkadot_sdk/frame_runtime.rs | 179 +++++ developer-hub/src/polkadot_sdk/mod.rs | 134 ++++ developer-hub/src/polkadot_sdk/polkadot.rs | 87 +++ .../src/polkadot_sdk/smart_contracts.rs | 9 + developer-hub/src/polkadot_sdk/substrate.rs | 151 ++++ developer-hub/src/polkadot_sdk/templates.rs | 45 ++ developer-hub/src/polkadot_sdk/xcm.rs | 5 + .../reference_docs/blockchain_scalibility.rs | 0 .../blockchain_state_machines.rs | 29 + .../src/reference_docs/chain_spec_genesis.rs | 4 + developer-hub/src/reference_docs/cli.rs | 7 + .../src/reference_docs/consensus_swapping.rs | 6 + .../src/reference_docs/extrinsic_encoding.rs | 277 +++++++ .../src/reference_docs/fee_less_runtime.rs | 12 + .../frame_benchmarking_weight.rs | 23 + .../reference_docs/frame_composite_enums.rs | 1 + .../src/reference_docs/frame_currency.rs | 8 + .../src/reference_docs/frame_origin.rs | 14 + .../reference_docs/frame_runtime_migration.rs | 9 + .../reference_docs/frame_system_accounts.rs | 8 + developer-hub/src/reference_docs/glossary.rs | 62 ++ .../src/reference_docs/light_nodes.rs | 7 + developer-hub/src/reference_docs/metadata.rs | 1 + developer-hub/src/reference_docs/mod.rs | 99 +++ .../runtime_vs_smart_contract.rs | 6 + .../safe_defensive_programming.rs | 1 + .../src/reference_docs/signed_extensions.rs | 79 ++ .../reference_docs/trait_based_programming.rs | 229 ++++++ .../src/reference_docs/wasm_memory.rs | 7 + .../src/reference_docs/wasm_meta_protocol.rs | 113 +++ docs/mermaid/IA.mmd | 14 + docs/mermaid/extrinsics.mmd | 5 + docs/mermaid/polkadot_sdk_parachain.mmd | 11 + docs/mermaid/polkadot_sdk_polkadot.mmd | 10 + docs/mermaid/polkadot_sdk_substrate.mmd | 8 + docs/mermaid/state.mmd | 16 + docs/mermaid/stf.mmd | 21 + docs/mermaid/stf_simple.mmd | 4 + docs/mermaid/substrate_client_runtime.mmd | 8 +- docs/mermaid/substrate_dev.mmd | 2 + docs/mermaid/substrate_simple.mmd | 2 +- docs/mermaid/substrate_with_frame.mmd | 6 +- .../protocol/src/request_response/mod.rs | 4 +- polkadot/node/primitives/src/lib.rs | 2 +- substrate/Cargo.toml | 30 - substrate/client/allocator/src/lib.rs | 2 +- substrate/client/executor/src/lib.rs | 2 +- substrate/frame/balances/src/lib.rs | 48 +- substrate/frame/bounties/src/migrations/v4.rs | 4 +- .../frame/collective/src/migrations/v4.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 6 +- .../elections-phragmen/src/migrations/v4.rs | 4 +- .../elections-phragmen/src/migrations/v5.rs | 2 +- .../frame/examples/kitchensink/src/lib.rs | 5 +- substrate/frame/fast-unstake/src/types.rs | 1 + substrate/frame/grandpa/src/migrations/v4.rs | 4 +- .../frame/membership/src/migrations/v4.rs | 4 +- .../frame/session/src/historical/offchain.rs | 10 +- substrate/frame/src/lib.rs | 36 +- substrate/frame/support/procedural/src/lib.rs | 46 +- .../procedural/src/pallet/parse/call.rs | 34 +- substrate/frame/support/src/dispatch.rs | 3 +- substrate/frame/support/src/lib.rs | 152 +++- substrate/frame/support/src/migrations.rs | 3 +- substrate/frame/support/src/storage/child.rs | 6 +- substrate/frame/support/src/storage/mod.rs | 6 +- .../deprecated_where_block.stderr | 8 +- .../pallet_ui/call_invalid_origin_type.stderr | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/system/src/lib.rs | 24 +- substrate/frame/tips/src/migrations/v4.rs | 4 +- substrate/primitives/api/src/lib.rs | 16 +- .../primitives/npos-elections/src/lib.rs | 5 +- .../runtime-interface/src/pass_by.rs | 2 +- substrate/primitives/runtime/Cargo.toml | 3 + .../runtime/src/generic/checked_extrinsic.rs | 8 +- .../src/generic/unchecked_extrinsic.rs | 32 +- .../runtime/src/offchain/storage_lock.rs | 2 +- substrate/src/lib.rs | 242 ------ 96 files changed, 3410 insertions(+), 471 deletions(-) create mode 100644 developer-hub/Cargo.toml create mode 100644 developer-hub/headers/toc.html create mode 100644 developer-hub/src/guides/changing_consensus.rs create mode 100644 developer-hub/src/guides/cumulus_enabled_parachain.rs create mode 100644 developer-hub/src/guides/mod.rs create mode 100644 developer-hub/src/guides/xcm_enabled_parachain.rs create mode 100644 developer-hub/src/guides/your_first_node.rs create mode 100644 developer-hub/src/guides/your_first_pallet/mod.rs create mode 100644 developer-hub/src/guides/your_first_pallet/with_event.rs create mode 100644 developer-hub/src/guides/your_first_runtime.rs create mode 100644 developer-hub/src/lib.rs create mode 100644 developer-hub/src/meta_contributing.rs create mode 100644 developer-hub/src/polkadot_sdk/cumulus.rs create mode 100644 developer-hub/src/polkadot_sdk/frame_runtime.rs create mode 100644 developer-hub/src/polkadot_sdk/mod.rs create mode 100644 developer-hub/src/polkadot_sdk/polkadot.rs create mode 100644 developer-hub/src/polkadot_sdk/smart_contracts.rs create mode 100644 developer-hub/src/polkadot_sdk/substrate.rs create mode 100644 developer-hub/src/polkadot_sdk/templates.rs create mode 100644 developer-hub/src/polkadot_sdk/xcm.rs create mode 100644 developer-hub/src/reference_docs/blockchain_scalibility.rs create mode 100644 developer-hub/src/reference_docs/blockchain_state_machines.rs create mode 100644 developer-hub/src/reference_docs/chain_spec_genesis.rs create mode 100644 developer-hub/src/reference_docs/cli.rs create mode 100644 developer-hub/src/reference_docs/consensus_swapping.rs create mode 100644 developer-hub/src/reference_docs/extrinsic_encoding.rs create mode 100644 developer-hub/src/reference_docs/fee_less_runtime.rs create mode 100644 developer-hub/src/reference_docs/frame_benchmarking_weight.rs create mode 100644 developer-hub/src/reference_docs/frame_composite_enums.rs create mode 100644 developer-hub/src/reference_docs/frame_currency.rs create mode 100644 developer-hub/src/reference_docs/frame_origin.rs create mode 100644 developer-hub/src/reference_docs/frame_runtime_migration.rs create mode 100644 developer-hub/src/reference_docs/frame_system_accounts.rs create mode 100644 developer-hub/src/reference_docs/glossary.rs create mode 100644 developer-hub/src/reference_docs/light_nodes.rs create mode 100644 developer-hub/src/reference_docs/metadata.rs create mode 100644 developer-hub/src/reference_docs/mod.rs create mode 100644 developer-hub/src/reference_docs/runtime_vs_smart_contract.rs create mode 100644 developer-hub/src/reference_docs/safe_defensive_programming.rs create mode 100644 developer-hub/src/reference_docs/signed_extensions.rs create mode 100644 developer-hub/src/reference_docs/trait_based_programming.rs create mode 100644 developer-hub/src/reference_docs/wasm_memory.rs create mode 100644 developer-hub/src/reference_docs/wasm_meta_protocol.rs create mode 100644 docs/mermaid/IA.mmd create mode 100644 docs/mermaid/extrinsics.mmd create mode 100644 docs/mermaid/polkadot_sdk_parachain.mmd create mode 100644 docs/mermaid/polkadot_sdk_polkadot.mmd create mode 100644 docs/mermaid/polkadot_sdk_substrate.mmd create mode 100644 docs/mermaid/state.mmd create mode 100644 docs/mermaid/stf.mmd create mode 100644 docs/mermaid/stf_simple.mmd create mode 100644 docs/mermaid/substrate_dev.mmd delete mode 100644 substrate/Cargo.toml delete mode 100644 substrate/src/lib.rs diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 5c13045706c..d6918173d49 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -125,7 +125,7 @@ build-rustdoc: find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {} } inject_simple_analytics "./crate-docs" - - echo "" > ./crate-docs/index.html + - echo "" > ./crate-docs/index.html build-implementers-guide: stage: build diff --git a/Cargo.lock b/Cargo.lock index 346ce2f933f..de4471783ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4366,6 +4366,45 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "developer-hub" +version = "0.0.1" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-parachain-system", + "docify", + "frame", + "kitchensink-runtime", + "pallet-aura", + "pallet-default-config-example", + "pallet-examples", + "pallet-timestamp", + "parity-scale-codec", + "sc-cli", + "sc-client-db", + "sc-consensus-aura", + "sc-consensus-babe", + "sc-consensus-beefy", + "sc-consensus-grandpa", + "sc-consensus-manual-seal", + "sc-consensus-pow", + "sc-network", + "sc-rpc", + "sc-rpc-api", + "scale-info", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?branch=main)", + "sp-api", + "sp-core", + "sp-io", + "sp-keyring", + "sp-runtime", + "staging-chain-spec-builder", + "staging-node-cli", + "staging-parachain-info", + "subkey", + "substrate-wasm-builder", +] + [[package]] name = "diff" version = "0.1.13" @@ -5201,7 +5240,7 @@ dependencies = [ "pallet-examples", "parity-scale-codec", "scale-info", - "simple-mermaid", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?rev=e48b187bcfd5cc75111acd9d241f1bd36604344b)", "sp-api", "sp-arithmetic", "sp-block-builder", @@ -11175,9 +11214,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -11190,9 +11229,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -16644,6 +16683,11 @@ dependencies = [ "wide", ] +[[package]] +name = "simple-mermaid" +version = "0.1.0" +source = "git+https://github.com/kianenigma/simple-mermaid.git?branch=main#e48b187bcfd5cc75111acd9d241f1bd36604344b" + [[package]] name = "simple-mermaid" version = "0.1.0" @@ -17497,6 +17541,7 @@ dependencies = [ name = "sp-runtime" version = "24.0.0" dependencies = [ + "docify", "either", "hash256-std-hasher", "impl-trait-for-tuples", @@ -17507,6 +17552,7 @@ dependencies = [ "scale-info", "serde", "serde_json", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?branch=main)", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -18293,26 +18339,6 @@ dependencies = [ "sc-cli", ] -[[package]] -name = "substrate" -version = "1.0.0" -dependencies = [ - "frame-support", - "sc-chain-spec", - "sc-cli", - "sc-consensus-aura", - "sc-consensus-babe", - "sc-consensus-beefy", - "sc-consensus-grandpa", - "sc-consensus-manual-seal", - "sc-consensus-pow", - "sc-service", - "simple-mermaid", - "sp-runtime", - "staging-chain-spec-builder", - "subkey", -] - [[package]] name = "substrate-bip39" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index ac474ae5686..a295aca819c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "GPL-3.0-only" resolver = "2" members = [ + "developer-hub", "bridges/bin/runtime-common", "bridges/modules/grandpa", "bridges/modules/messages", @@ -186,7 +187,6 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", - "substrate", "substrate/bin/minimal/node", "substrate/bin/minimal/runtime", "substrate/bin/node-template/node", @@ -476,8 +476,7 @@ default-members = [ "polkadot", "substrate/bin/node/cli" ] panic = "unwind" opt-level = 3 -# make sure dev builds with backtrace do -# not slow us down +# make sure dev builds with backtrace do not slow us down [profile.dev.package.backtrace] inherits = "release" diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index 7a064e227d4..be76855c05b 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -513,8 +513,7 @@ impl pallet_parachain_template::Config for Runtime { // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( - pub enum Runtime - { + pub struct Runtime { // System support stuff. System: frame_system = 0, ParachainSystem: cumulus_pallet_parachain_system = 1, diff --git a/developer-hub/Cargo.toml b/developer-hub/Cargo.toml new file mode 100644 index 00000000000..c19d5480ec4 --- /dev/null +++ b/developer-hub/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "developer-hub" +description = "The one stop shop for developers of the polakdot-sdk" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "paritytech.github.io" +repository.workspace = true +authors.workspace = true +edition.workspace = true +# This crate is not publish-able to crates.io for now because of docify. +publish = false +version = "0.0.1" + +[dependencies] +# Needed for all FRAME-based code +parity-scale-codec = { version = "3.0.0", default-features = false } +scale-info = { version = "2.6.0", default-features = false } +frame = { path = "../substrate/frame", features = ["runtime", "experimental"] } +pallet-examples = { path = "../substrate/frame/examples" } +pallet-default-config-example = { path = "../substrate/frame/examples/default-config" } + +# How we build docs in rust-docs +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } +docify = "0.2.6" + +# Polkadot SDK deps, typically all should only be scope such that we can link to their doc item. +node-cli = { package = "staging-node-cli", path = "../substrate/bin/node/cli" } +kitchensink-runtime = { path = "../substrate/bin/node/runtime" } +chain-spec-builder = { package = "staging-chain-spec-builder", path = "../substrate/bin/utils/chain-spec-builder" } +subkey = { path = "../substrate/bin/utils/subkey" } + +# Substrate +sc-network = { path = "../substrate/client/network" } +sc-rpc-api = { path = "../substrate/client/rpc-api" } +sc-rpc = { path = "../substrate/client/rpc" } +sc-client-db = { path = "../substrate/client/db" } +sc-cli = { path = "../substrate/client/cli" } +sc-consensus-aura = { path = "../substrate/client/consensus/aura" } +sc-consensus-babe = { path = "../substrate/client/consensus/babe" } +sc-consensus-grandpa = { path = "../substrate/client/consensus/grandpa" } +sc-consensus-beefy = { path = "../substrate/client/consensus/beefy" } +sc-consensus-manual-seal = { path = "../substrate/client/consensus/manual-seal" } +sc-consensus-pow = { path = "../substrate/client/consensus/pow" } +substrate-wasm-builder = { path = "../substrate/utils/wasm-builder" } + +# Cumulus +cumulus-pallet-aura-ext = { path = "../cumulus/pallets/aura-ext" } +cumulus-pallet-parachain-system = { path = "../cumulus/pallets/parachain-system", features = [ + "parameterized-consensus-hook", +] } +parachain-info = { package = "staging-parachain-info", path = "../cumulus/parachains/pallets/parachain-info" } +pallet-aura = { path = "../substrate/frame/aura", default-features = false } +pallet-timestamp = { path = "../substrate/frame/timestamp" } + +# Primitives +sp-io = { path = "../substrate/primitives/io" } +sp-api = { path = "../substrate/primitives/api" } +sp-core = { path = "../substrate/primitives/core" } +sp-keyring = { path = "../substrate/primitives/keyring" } +sp-runtime = { path = "../substrate/primitives/runtime" } + +[dev-dependencies] +parity-scale-codec = "3.6.5" +scale-info = "2.9.0" + +[features] +experimental = [ "pallet-aura/experimental" ] diff --git a/developer-hub/headers/toc.html b/developer-hub/headers/toc.html new file mode 100644 index 00000000000..d4d017eb207 --- /dev/null +++ b/developer-hub/headers/toc.html @@ -0,0 +1,54 @@ + + diff --git a/developer-hub/src/guides/changing_consensus.rs b/developer-hub/src/guides/changing_consensus.rs new file mode 100644 index 00000000000..7ba742f1072 --- /dev/null +++ b/developer-hub/src/guides/changing_consensus.rs @@ -0,0 +1 @@ +//! # Changing Consensus diff --git a/developer-hub/src/guides/cumulus_enabled_parachain.rs b/developer-hub/src/guides/cumulus_enabled_parachain.rs new file mode 100644 index 00000000000..fafd97feb82 --- /dev/null +++ b/developer-hub/src/guides/cumulus_enabled_parachain.rs @@ -0,0 +1 @@ +//! # Cumulus Enabled Parachain diff --git a/developer-hub/src/guides/mod.rs b/developer-hub/src/guides/mod.rs new file mode 100644 index 00000000000..21de220a3b8 --- /dev/null +++ b/developer-hub/src/guides/mod.rs @@ -0,0 +1,25 @@ +//! # Polkadot Developer Hub Guides +//! +//! This crate contains a collection of guides that are foundational to the developers of +//! Polkadot SDK. They common user-journeys that are traversed in the Polkadot ecosystem. + +/// Write your first simple pallet, learning the most most basic features of FRAME along the way. +pub mod your_first_pallet; + +/// Writing your first real [runtime](`crate::reference_docs::wasm_meta_protocol`), and successfully +/// compiling it to [WASM](crate::polkadot_sdk::substrate#wasm-build). +pub mod your_first_runtime; + +/// Running the given runtime with a node. No specific consensus mechanism is used at this stage. +pub mod your_first_node; + +/// How to change the consensus engine of both the node and the runtime. +pub mod changing_consensus; + +/// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain and connect +/// it to a relay-chain. +pub mod cumulus_enabled_parachain; + +/// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between itself +/// and the relay chain to which it is connected. +pub mod xcm_enabled_parachain; diff --git a/developer-hub/src/guides/xcm_enabled_parachain.rs b/developer-hub/src/guides/xcm_enabled_parachain.rs new file mode 100644 index 00000000000..4518cab9342 --- /dev/null +++ b/developer-hub/src/guides/xcm_enabled_parachain.rs @@ -0,0 +1 @@ +//! # XCM Enabled Parachain diff --git a/developer-hub/src/guides/your_first_node.rs b/developer-hub/src/guides/your_first_node.rs new file mode 100644 index 00000000000..d12349c9906 --- /dev/null +++ b/developer-hub/src/guides/your_first_node.rs @@ -0,0 +1 @@ +//! # Your first Node diff --git a/developer-hub/src/guides/your_first_pallet/mod.rs b/developer-hub/src/guides/your_first_pallet/mod.rs new file mode 100644 index 00000000000..0d2cc26d757 --- /dev/null +++ b/developer-hub/src/guides/your_first_pallet/mod.rs @@ -0,0 +1,738 @@ +//! # Currency Pallet +//! +//! By the end of this guide, you will write a small FRAME pallet (see +//! [`crate::polkadot_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency. +//! This pallet will: +//! +//! 1. Allow anyone to mint new tokens into accounts (which is obviously not a great idea for a real +//! system). +//! 2. Allow any user that owns tokens to transfer them to others. +//! 3. Track the total issuance of all tokens at all times. +//! +//! > This guide will build a currency pallet from scratch using only the lowest primitives of +//! > FRAME, and is mainly intended for education, not *applicability*. For example, almost all +//! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing +//! > one. Further advance FRAME related topics are discussed in [`crate::reference_docs`]. +//! +//! ## Topics Covered +//! +//! The following FRAME topics are covered in this guide. See the documentation of the +//! associated items to know more. +//! +//! - [Storage](frame::pallet_macros::storage) +//! - [Call](frame::pallet_macros::call) +//! - [Event](frame::pallet_macros::event) +//! - [Error](frame::pallet_macros::error) +//! - Basics of testing a pallet +//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime) +//! +//! ## Writing Your First Pallet +//! +//! You should have studied the following modules as a prelude to this guide: +//! +//! - [`crate::reference_docs::blockchain_state_machines`] +//! - [`crate::reference_docs::trait_based_programming`] +//! - [`crate::polkadot_sdk::frame_runtime`] +//! +//! ### Shell Pallet +//! +//! Consider the following as a "shell pallet". We continue building the rest of this pallet based +//! on this template. +//! +//! [`pallet::config`](frame::pallet_macros::config) and +//! [`pallet::pallet`](frame::pallet_macros::pallet) are both mandatory parts of any pallet. Refer +//! to the documentation of each to get an overview of what they do. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", shell_pallet)] +//! +//! ### Storage +//! +//! First, we will need to create two onchain storage declarations. +//! +//! One should be a mapping from account-ids to a balance type, and one value that is the total +//! issuance. +// +// For the rest of this guide, we will opt for a balance type of u128. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balance)] +//! +//! The definition of these two storage items, based on [`frame::pallet_macros::storage`] details, +//! is as follows: +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", TotalIssuance)] +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balances)] +//! +//! ### Dispatchables +//! +//! Next, we will define the dispatchable functions. As per [`frame::pallet_macros::call`], these +//! will be defined as normal `fn`s attached to `struct Pallet`. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_pallet)] +//! +//! The logic of the functions is self-explanatory. Instead, we will focus on the FRAME-related +//! details: +//! +//! - Where do `T::AccountId` and `T::RuntimeOrigin` come from? These are both defined in +//! [`frame::prelude::frame_system::Config`], therefore we can access them in `T`. +//! - What is `ensure_signed`, and what does it do with the aforementioned `T::RuntimeOrigin`? This +//! is outside the scope of this guide, and you can learn more about it in the origin reference +//! document ([`crate::reference_docs::frame_origin`]). For now, you should only know the +//! signature of the function: it takes a generic `T::RuntimeOrigin` and returns a +//! `Result`. So by the end of this function call, we know that this dispatchable +//! was signed by `who`. +#![doc = docify::embed!("../substrate/frame/system/src/lib.rs", ensure_signed)] +//! +//! +//! - Where does `mutate`, `get` and `insert` and other storage APIs come from? All of them are +//! explained in the corresponding `type`, for example, for `Balances::::insert`, you can look +//! into [`frame::prelude::StorageMap::insert`]. +//! +//! - The return type of all dispatchable functions is [`frame::prelude::DispatchResult`]: +#![doc = docify::embed!("../substrate/frame/support/src/dispatch.rs", DispatchResult)] +//! +//! Which is more or less a normal Rust `Result`, with a custom [`frame::prelude::DispatchError`] as +//! the `Err` variant. We won't cover this error in detail here, but importantly you should know +//! that there is an `impl From<&'static string> for DispatchError` provided (see +//! [here](`frame::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError`)). Therefore, +//! we can use basic string literals as our error type and `.into()` them into `DispatchError`. +//! +//! - Why are all `get` and `mutate` functions returning an `Option`? This is the default behavior +//! of FRAME storage APIs. You can learn more about how to override this by looking into +//! [`frame::pallet_macros::storage`], and +//! [`frame::prelude::ValueQuery`]/[`frame::prelude::OptionQuery`] +//! +//! ### Improving Errors +//! +//! How we handle error in the above snippets is fairly rudimentary. Let's look at how this can be +//! improved. First, we can use [`frame::prelude::ensure`] to express the error slightly better. +//! This macro will call `.into()` under the hood. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better)] +//! +//! Moreover, you will learn in the [Safe Defensive Programming +//! section](crate::reference_docs::safe_defensive_programming) that it is always recommended to use +//! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not +//! only take a step in that direction, but also improve the error handing and make it slightly more +//! ergonomic. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better_checked)] +//! +//! This is more or less all the logic that there is this basic currency pallet! +//! +//! ### Your First (Test) Runtime +//! +//! Next, we create a "test runtime" in order to test our pallet. Recall from +//! [`crate::polkadot_sdk::frame_runtime`] that a runtime is a collection of pallets, expressed +//! through [`frame::runtime::prelude::construct_runtime`]. All runtimes also have to include +//! [`frame::prelude::frame_system`]. So we expect to see a runtime with two pallet, `frame_system` +//! and the one we just wrote. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", runtime)] +//! +//! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have +//! > defaults for associated types. +//! +//! Recall that within our pallet, (almost) all blocks of code are generic over ``. And, +//! because `trait Config: frame_system::Config`, we can get access to all items in `Config` (or +//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how Rust +//! traits and generics work. If unfamiliar with this pattern, read +//! [`crate::reference_docs::trait_based_programming`] before going further. +//! +//! Crucially, a typical FRAME runtime contains a `struct Runtime`. The main role of this `struct` +//! is to implement the `trait Config` of all pallets. That is, anywhere within your pallet code +//! where you see `` (read: *"some type `T` that implements `Config`"*), in the runtime, +//! it can be replaced with ``, because `Runtime` implements `Config` of all pallets, as we +//! see above. +//! +//! Another way to think about this is that within a pallet, a lot of types are "unknown" and, we +//! only know that they will be provided at some later point. For example, when you write +//! `T::AccountId` (which is short for `::AccountId`) in your pallet, +//! you are in fact saying "*Some type `AccountId` that will be known later*". That "later" is in +//! fact when you specify these types when you implement all `Config` traits for `Runtime`. +//! +//! As you see above, `frame_system::Config` is setting the `AccountId` to `u64`. Of course, a real +//! runtime will not use this type, and instead reside to a proper type like a 32-byte standard +//! public key. This is a HUGE benefit that FRAME developers can tap into: through the framework +//! being so generic, different types can always be customized to simple things when needed. +//! +//! > Imagine how hard it would have been if all tests had to use a real 32-byte account id, as +//! > opposed to just a u64 number 🙈. +//! +//! ### Your First Test +//! +//! The above is all you need to execute the dispatchables of your pallet. The last thing you need +//! to learn is that all of your pallet testing code should be wrapped in +//! [`frame::testing_prelude::TestState`]. This is a type that provides access to an in-memory state +//! to be used in our tests. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", first_test)] +//! +//! In the first test, we simply assert that there is no total issuance, and no balance associated +//! with account `1`. Then, we mint some balance into `1`, and re-check. +//! +//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing ``. +//! This is why for example you see `Balances::::get(..)`. Finally, notice that the +//! dispatchables are simply functions that can be called on top of the `Pallet` struct. +//! +//! TODO: hard to explain exactly `RuntimeOrigin::signed(1)` at this point. +//! +//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional +//! steps to improve our pallet. +//! +//! ## Improving the Currency Pallet +//! +//! ### Better Test Setup +//! +//! Idiomatic FRAME pallets often use Builder pattern to define their initial state. +//! +//! > The Polkadot Blockchain Academy's Rust entrance exam has a +//! > [section](https://github.com/Polkadot-Blockchain-Academy/pba-qualifier-exam/blob/main/src/m_builder.rs) +//! > on this that you can use to learn the Builder Pattern. +//! +//! Let's see how we can implement a better test setup using this pattern. First, we define a +//! `struct StateBuilder`. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", StateBuilder)] +//! +//! This struct is meant to contain the same list of accounts and balances that we want to have at +//! the beginning of each block. We hardcoded this to `let accounts = vec![(1, 100), (2, 100)];` so +//! far. Then, if desired, we attach a default value for this struct. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", default_state_builder)] +//! +//! Like any other builder pattern, we attach functions to the type to mutate its internal +//! properties. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_state_builder_add)] +//! +//! Finally --the useful part-- we write our own custom `build_and_execute` function on +//! this type. This function will do multiple things: +//! +//! 1. It would consume `self` to produce our `TestState` based on the properties that we attached +//! to `self`. +//! 2. It would execute any test function that we pass in as closure. +//! 3. A nifty trick, this allows our test setup to have some code that is executed both before and +//! after each test. For example, in this test, we do some additional checking about the +//! correctness of the `TotalIssuance`. We leave it up to you as an exercise to learn why the +//! assertion should always hold, and how it is checked. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_state_builder_build)] +//! +//! We can write tests that specifically check the initial state, and making sure our `StateBuilder` +//! is working exactly as intended. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", state_builder_works)] +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", state_builder_add_balance)] +//! +//! ### More Tests +//! +//! Now that we have a more ergonomic test setup, let's see how a well written test for transfer and +//! mint would look like. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_works)] +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", mint_works)] +//! +//! It is always a good idea to build a mental model where you write *at least* one test for each +//! "success path" of a dispatchable, and one test for each "failure path", such as: +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_from_non_existent_fails)] +//! +//! We leave it up to you to write a test that triggers to `InsufficientBalance` error. +//! +//! ### Event and Error +//! +//! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and +//! Errors. First, let's understand what each is. +//! +//! - **Error**: The static string-based error scheme we used so far is good for readability, but it +//! has a few drawbacks. These string literals will bloat the final wasm blob, and are relatively +//! heavy to transmit and encode/decode. Moreover, it is easy to mistype them by one character. +//! FRAME errors are exactly a solution to maintain readability, whilst fixing the drawbacks +//! mentioned. In short, we use an enum to represent different variants of our error. These +//! variants are then mapped in an efficient way (using only `u8` indices) to +//! [`sp_runtime::DispatchError::Module`] Read more about this in [`frame::pallet_macros::error`]. +//! +//! - **Event**: Events are akin to the return type of dispatchables. They should represent what +//! happened at the end of a dispatch operation. Therefore, the convention is to use passive tense +//! for event names (eg. `SomethingHappened`). This allows other sub-systems or external parties +//! (eg. a light-node, a DApp) to listen to particular events happening, without needing to +//! re-execute the whole state transition function. +//! +//! TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation +//! of event is probably not the best. +//! +//! With the explanation out of the way, let's see how these components can be added. Both follow a +//! fairly familiar syntax: normal Rust enums, with an extra `#[frame::event/error]` attribute +//! attached. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Event)] +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Error)] +//! +//! One slightly custom part of this is the `#[pallet::generate_deposit(pub(super) fn +//! deposit_event)]` part. Without going into too much detail, in order for a pallet to emit events +//! to the rest of the system, it needs to do two things: +//! +//! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In +//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent: +//! From>`. Read: a `RuntimeEvent` exists, and it can be created from the local `enum +//! Event` of this pallet. This enables the pallet to convert its `Event` into `RuntimeEvent`, and +//! store it where needed. +//! +//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME +//! provides a default way of storing events, and this is what `pallet::generate_deposit` is doing. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", config_v2)] +//! +//! > These `Runtime*` types are better explained in +//! > [`crate::reference_docs::frame_composite_enums`]. +//! +//! Then, we can rewrite the `transfer` dispatchable as such: +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_v2)] +//! +//! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime +//! setup. +#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", runtime_v2)] +//! +//! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent = +//! RuntimeEvent`) is generated by `construct_runtime`. An interesting way to inspect this type is +//! to see its definition in rust-docs: +//! [`crate::guides::your_first_pallet::pallet_v2::tests::runtime_v2::RuntimeEvent`]. +//! +//! +//! +//! ## What Next? +//! +//! The following topics where used in this guide, but not covered in depth. It is suggested to +//! study them subsequently: +//! +//! - [`crate::reference_docs::safe_defensive_programming`]. +//! - [`crate::reference_docs::frame_origin`]. +//! - [`crate::reference_docs::frame_composite_enums`]. +//! - The pallet we wrote in this guide was using `dev_mode`, learn more in +//! [`frame::pallet_macros::config`]. +//! - Learn more about the individual pallet items/macros, such as event and errors and call, in +//! [`frame::pallet_macros`]. + +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod shell_pallet { + use frame::prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} + +#[frame::pallet(dev_mode)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub type Balance = u128; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export] + /// Single storage item, of type `Balance`. + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + /// A mapping from `T::AccountId` to `Balance` + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[docify::export(impl_pallet)] + #[pallet::call] + impl Pallet { + /// An unsafe mint that can be called by anyone. Not a great idea. + pub fn mint_unsafe( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + // ensure that this is a signed account, but we don't really check `_anyone`. + let _anyone = ensure_signed(origin)?; + + // update the balances map. Notice how all `` remains as ``. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + // update total issuance. + TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); + + Ok(()) + } + + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + if sender_balance < amount { + return Err("InsufficientBalance".into()) + } + let reminder = sender_balance - amount; + + // update sender and dest balances. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Ok(()) + } + } + + #[allow(unused)] + impl Pallet { + #[docify::export] + pub fn transfer_better( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + ensure!(sender_balance >= amount, "InsufficientBalance"); + let reminder = sender_balance - amount; + + // .. snip + Ok(()) + } + + #[docify::export] + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer_better_checked( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + let reminder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?; + + // .. snip + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub(crate) mod tests { + use crate::guides::your_first_pallet::pallet::*; + use frame::testing_prelude::*; + + #[docify::export] + mod runtime { + use super::*; + // we need to reference our `mod pallet` as an identifier to pass to + // `construct_runtime`. + use crate::guides::your_first_pallet::pallet as pallet_currency; + + construct_runtime!( + pub struct Runtime { + // ---^^^^^^ This is where `struct Runtime` is defined. + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + // within pallet we just said `::AccountId`, now we + // finally specified it. + type AccountId = u64; + } + + // our simple pallet has nothing to be configured. + impl pallet_currency::Config for Runtime {} + } + + pub(crate) use runtime::*; + + #[allow(unused)] + #[docify::export] + fn new_test_state_basic() -> TestState { + let mut state = TestState::new_empty(); + let accounts = vec![(1, 100), (2, 100)]; + state.execute_with(|| { + for (who, amount) in &accounts { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + state + } + + #[docify::export] + pub(crate) struct StateBuilder { + balances: Vec<(::AccountId, Balance)>, + } + + #[docify::export(default_state_builder)] + impl Default for StateBuilder { + fn default() -> Self { + Self { balances: vec![(1, 100), (2, 100)] } + } + } + + #[docify::export(impl_state_builder_add)] + impl StateBuilder { + fn add_balance( + mut self, + who: ::AccountId, + amount: Balance, + ) -> Self { + self.balances.push((who, amount)); + self + } + } + + #[docify::export(impl_state_builder_build)] + impl StateBuilder { + pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = TestState::new_empty(); + ext.execute_with(|| { + for (who, amount) in &self.balances { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + ext.execute_with(test); + + // assertions that must always hold + ext.execute_with(|| { + assert_eq!( + Balances::::iter().map(|(_, x)| x).sum::(), + TotalIssuance::::get().unwrap_or_default() + ); + }) + } + } + + #[docify::export] + #[test] + fn first_test() { + TestState::new_empty().execute_with(|| { + // We expect account 1 to have no funds. + assert_eq!(Balances::::get(&1), None); + assert_eq!(TotalIssuance::::get(), None); + + // mint some funds into 1 + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 1, 100)); + + // re-check the above + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(100)); + }) + } + + #[docify::export] + #[test] + fn state_builder_works() { + StateBuilder::default().build_and_execute(|| { + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn state_builder_add_balance() { + StateBuilder::default().add_balance(3, 42).build_and_execute(|| { + assert_eq!(Balances::::get(&3), Some(42)); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[test] + #[should_panic] + fn state_builder_duplicate_genesis_fails() { + StateBuilder::default() + .add_balance(3, 42) + .add_balance(3, 43) + .build_and_execute(|| { + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[docify::export] + #[test] + fn mint_works() { + StateBuilder::default().build_and_execute(|| { + // given the initial state, when: + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 2, 100)); + + // then: + assert_eq!(Balances::::get(&2), Some(200)); + assert_eq!(TotalIssuance::::get(), Some(300)); + + // given: + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 3, 100)); + + // then: + assert_eq!(Balances::::get(&3), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(400)); + }); + } + + #[docify::export] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // given the the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(50)); + assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(2), 1, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn transfer_from_non_existent_fails() { + StateBuilder::default().build_and_execute(|| { + // given the the initial state, when: + assert_err!( + Pallet::::transfer(RuntimeOrigin::signed(3), 1, 10), + "NonExistentAccount" + ); + + // then nothing has changed. + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + } +} + +#[frame::pallet(dev_mode)] +pub mod pallet_v2 { + use super::pallet::Balance; + use frame::prelude::*; + + #[docify::export(config_v2)] + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type of the runtime. + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + #[pallet::error] + pub enum Error { + /// Account does not exist. + NonExistentAccount, + /// Account does not have enough balance. + InsufficientBalance, + } + + #[docify::export] + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transfer succeeded. + Transferred { from: T::AccountId, to: T::AccountId, amount: Balance }, + } + + #[pallet::call] + impl Pallet { + #[docify::export(transfer_v2)] + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = + Balances::::get(&sender).ok_or(Error::::NonExistentAccount)?; + let reminder = + sender_balance.checked_sub(amount).ok_or(Error::::InsufficientBalance)?; + + Balances::::mutate(&dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Self::deposit_event(Event::::Transferred { from: sender, to: dest, amount }); + + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub mod tests { + use super::{super::pallet::tests::StateBuilder, *}; + use frame::testing_prelude::*; + + #[docify::export] + pub mod runtime_v2 { + use super::*; + use crate::guides::your_first_pallet::pallet_v2 as pallet_currency; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + type AccountId = u64; + } + + impl pallet_currency::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + } + } + + pub(crate) use runtime_v2::*; + + #[docify::export(transfer_works_v2)] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // skip the genesis block, as events are not deposited there and we need them for + // the final assertion. + System::set_block_number(1); + + // given the the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(50)); + assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // now we can also check that an event has been deposited: + assert_eq!( + System::read_events_for_pallet::>(), + vec![Event::Transferred { from: 1, to: 2, amount: 50 }] + ); + }); + } + } +} diff --git a/developer-hub/src/guides/your_first_pallet/with_event.rs b/developer-hub/src/guides/your_first_pallet/with_event.rs new file mode 100644 index 00000000000..a65aac324f0 --- /dev/null +++ b/developer-hub/src/guides/your_first_pallet/with_event.rs @@ -0,0 +1,101 @@ +#[frame::pallet(dev_mode)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub type Balance = u128; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export] + /// Single storage item, of type `Balance`. + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + /// A mapping from `T::AccountId` to `Balance` + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[docify::export(impl_pallet)] + #[pallet::call] + impl Pallet { + /// An unsafe mint that can be called by anyone. Not a great idea. + pub fn mint_unsafe( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + // ensure that this is a signed account, but we don't really check `_anyone`. + let _anyone = ensure_signed(origin)?; + + // update the balances map. Notice how all `` remains as ``. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + // update total issuance. + TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); + + Ok(()) + } + + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + if sender_balance < amount { + return Err("NotEnoughBalance".into()) + } + let reminder = sender_balance - amount; + + // update sender and dest balances. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Ok(()) + } + } + + #[allow(unused)] + impl Pallet { + #[docify::export] + pub fn transfer_better( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + ensure!(sender_balance >= amount, "NotEnoughBalance"); + let reminder = sender_balance - amount; + + // .. snip + Ok(()) + } + + #[docify::export] + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer_better_checked( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + let reminder = sender_balance.checked_sub(amount).ok_or("NotEnoughBalance")?; + + // .. snip + Ok(()) + } + } +} diff --git a/developer-hub/src/guides/your_first_runtime.rs b/developer-hub/src/guides/your_first_runtime.rs new file mode 100644 index 00000000000..3e02ef1b1b2 --- /dev/null +++ b/developer-hub/src/guides/your_first_runtime.rs @@ -0,0 +1 @@ +//! # Your first Runtime diff --git a/developer-hub/src/lib.rs b/developer-hub/src/lib.rs new file mode 100644 index 00000000000..eb71865ca44 --- /dev/null +++ b/developer-hub/src/lib.rs @@ -0,0 +1,43 @@ +//! # Developer Hub +//! +//! The Polkadot SDK Developer Hub. +//! +//! This crate is a *minimal*, but *always-accurate* source of information for those wishing to +//! build on the Polkadot SDK. +//! +//! > **Work in Progress**: This crate is under heavy development. Expect content to be moved and +//! > changed. Do not use links to this crate yet. See [`meta_contributing`] for more information. +//! +//! ## Getting Started +//! +//! We suggest the following reading sequence: +//! +//! - Start by learning about the the [`polkadot_sdk`], its structure and context. +//! - Then, head over the [`guides`]. This modules contains in-depth guides about the most important +//! user-journeys of the Polkadot SDK. +//! - Whilst reading the guides, you might find back-links to [`crate::reference_docs`]. +//! - Finally, is the parent website of this crate that contains the +//! list of further tools related to the Polkadot SDK. +//! +//! ## Information Architecture +//! +//! This section paints a picture over the high-level information architecture of this crate. +#![doc = simple_mermaid::mermaid!("../../docs/mermaid/IA.mmd")] +#![allow(rustdoc::invalid_html_tags)] // TODO: remove later. https://github.com/paritytech/polkadot-sdk-docs/issues/65 +#![allow(rustdoc::bare_urls)] // TODO: remove later. https://github.com/paritytech/polkadot-sdk-docs/issues/65 +#![warn(rustdoc::broken_intra_doc_links)] +#![warn(rustdoc::private_intra_doc_links)] + +/// Meta information about this crate, how it is built, what principles dictates its evolution and +/// how one can contribute to it. +pub mod meta_contributing; + +/// In-depth guides about the most common components of the Polkadot SDK. They are slightly more +/// high level and broad than reference docs. +pub mod guides; +/// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, +/// the tools that are provided as a part of it, and to gain a high level understanding of each. +pub mod polkadot_sdk; +/// Reference documents covering in-depth topics across the Polkadot SDK. It is suggested to read +/// these on-demand, while you are going through the [`guides`] or other content. +pub mod reference_docs; diff --git a/developer-hub/src/meta_contributing.rs b/developer-hub/src/meta_contributing.rs new file mode 100644 index 00000000000..70a23f82583 --- /dev/null +++ b/developer-hub/src/meta_contributing.rs @@ -0,0 +1,146 @@ +//! # Contribution +//! +//! The following sections cover more detailed information about this crate and how it should be +//! maintained. +//! +//! ## Why Rust Docs? +//! +//! We acknowledge that blockchain based systems, particularly a cutting-edge one like Polkadot SDK +//! is a software artifact that is complex, and rapidly evolving. This makes the task of documenting +//! it externally extremely difficult, especially with regards to making sure it is up-to-date. +//! +//! Consequently, we argue that the best hedge against this is to move as much of the documentation +//! near the source code as possible. This would further incentivize developers to keep the +//! documentation up-to-date, as the overhead is reduced by making sure everything is in one +//! repository, and everything being in `.rs` files. +//! +//! > This is not say that a more visually appealing version of this crate (for example as an +//! > `md-book`) cannot exist, but it would be outside the scope of this crate. +//! +//! Moreover, we acknowledge that a major pain point has been not only outdated *concepts*, but also +//! *outdated code*. For this, we commit to making sure no code-snippet in this crate is left as +//! `///ignore` or `///no_compile`, making sure all code snippets are self-contained, compile-able, +//! and correct at every single revision of the entire repository. +//! +//! > This also allows us to have a clear versioning on the entire content of this crate. For every +//! commit of the Polkadot SDK, there would be one version of this crate that is guaranteed to be +//! correct. +//! +//! > To achieve this, we often use [`docify`](https://github.com/sam0x17/docify), a nifty invention +//! > of `@sam0x17`. +//! +//! Also see: . +//! +//! ## Scope +//! +//! The above would NOT be attainable if we don't acknowledge that the scope of this crate MUST be +//! limited, or else its maintenance burden would be infeasible or not worthwhile. In short, future +//! maintainers should always strive to keep the content of this repository as minimal as possible. +//! Some of the following principles are specifically there to be the guidance for this. +//! +//! ## Principles +//! +//! The following guidelines are meant to be the guiding torch of those who contribute to this +//! crate. +//! +//! 1. 🔺 Ground Up: Information should be layed out in the most ground-up fashion. The lowest level +//! (i.e. "ground") is Rust-docs. The highest level (i.e. "up") is "outside of this crate". In +//! between lies [`reference_docs`] and [`guides`], from low to high. The point of this principle +//! is to document as much of the information as possible in the lower level media, as it is +//! easier to maintain and more reachable. Then, use excessive linking to back-link when writing +//! in a more high level. +//! +//! > A prime example of this, the details of the FRAME storage APIs should NOT be explained in a +//! > high level tutorial. They should be explained in the rust-doc of the corresponding type or +//! > macro. +//! +//! 2. 🧘 Less is More: For reasons mentioned [above](#crate::why-rust-docs), the more concise this +//! crate is, the better. +//! 3. √ Don’t Repeat Yourself – DRY: A summary of the above two points. Authors should always +//! strive to avoid any duplicate information. Every concept should ideally be documented in +//! *ONE* place and one place only. This makes the task of maintaining topics significantly +//! easier. +//! +//! > A prime example of this, the list of CLI arguments of a particular binary should not be +//! > documented in multiple places across this crate. It should be only be documented in the +//! > corresponding crate (e.g. `sc_cli`). +//! +//! > Moreover, this means that as a contributor, **it is your responsibility to have a grasp over +//! > what topics are already covered in this crate, and how you can build on top of the information +//! > that they already pose, rather than repeating yourself**. +//! +//! For more details about documenting guidelines, see: +//! +//! +//! #### Example: Explaining `#[pallet::call]` +//! +//!

+//! +//! Let's consider the seemingly simple example of explaining to someone dead-simple code of a FRAME +//! call and see how we can use the above principles. +//! +//! +//! +//! ``` +//! #[frame::pallet(dev_mode)] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[pallet::call] +//! impl Pallet { +//! pub fn a_simple_call(origin: OriginFor, data: u32) -> DispatchResult { +//! ensure!(data > 10, "SomeStaticString"); +//! todo!(); +//! } +//! } +//! } +//! ``` +//! +//! * Before even getting started, what is with all of this ``? We link to +//! [`crate::reference_docs::trait_based_programming`]. +//! * First, the name. Why is this called `pallet::call`? This goes back to `enum Call`, which is +//! explained in [`crate::reference_docs::frame_composite_enums`]. Build on top of this! +//! * Then, what is `origin`? Just an account id? [`crate::reference_docs::frame_origin`]. +//! * Then, what is `DispatchResult`? Why is this called *dispatch*? Probably something that can be +//! explained in the documentation of [`frame::prelude::DispatchResult`]. +//! * Why is `"SomeStaticString"` a valid error? Because there is implementation for it that you can +//! see [here](frame::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError). +//! +//! +//! All of these are examples of underlying information that a contributor should: +//! +//! 1. Try and create and they are going along. +//! 2. Back-link to if they already exist. +//! +//! Of course, all of this is not set in stone as a either/or rule. Sometimes, it is necessary to +//! rephrase a concept in a new context. +//! +//!
+//! +//! ## `docs.substrate.io` +//! +//! This crate is meant to gradually replace `docs.substrate.io`. As any content is added here, the +//! corresponding counter-part should be marked as deprecated, as described +//! [here](https://github.com/paritytech/polkadot-sdk-docs/issues/26). +//! +//! ## `crates.io` and Publishing +//! +//! As it stands now, this crate cannot be published to crates.io because of its use of +//! [workspace-level `docify`](https://github.com/sam0x17/docify/issues/22). For now, we accept this +//! compromise, but in the long term, we should work towards finding a way to maintain different +//! revisions of this crate. +//! +//! ## How to Build +//! +//! To build this crate properly, with with right HTML headers injected, run: +//! +//! ```no_compile +//! RUSTDOCFLAGS="--html-in-header $(pwd)/developer-hub/headers/toc.html" cargo doc -p developer-hub +//! ``` +//! +//! adding `--no-deps` would speed up the process while development. If even faster build time for +//! docs is needed, you can temporarily remove most of the substrate/cumulus dependencies that are +//! only used for linking purposes. diff --git a/developer-hub/src/polkadot_sdk/cumulus.rs b/developer-hub/src/polkadot_sdk/cumulus.rs new file mode 100644 index 00000000000..07a48c92d80 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/cumulus.rs @@ -0,0 +1,130 @@ +//! # Cumulus +//! +//! Substrate provides a framework ([FRAME]) through which a blockchain node and runtime can easily +//! be created. Cumulus aims to extend the same approach to creation of Polkadot parachains. +//! +//! > Cumulus clouds are shaped sort of like dots; together they form a system that is intricate, +//! > beautiful and functional. +//! +//! ## Example: Runtime +//! +//! A Cumulus-based runtime is fairly similar to other [FRAME]-based runtimes. Most notably, the +//! following changes are applied to a normal FRAME-based runtime to make it a Cumulus-based +//! runtime: +//! +//! #### Cumulus Pallets +//! +//! A parachain runtime should use a number of pallets that are provided by Cumulus and Substrate. +//! Notably: +//! +//! - [`frame-system`](frame::prelude::frame_system), like all FRAME-based runtimes. +//! - [`cumulus_pallet_parachain_system`] +//! - [`parachain_info`] +#![doc = docify::embed!("./src/polkadot_sdk/cumulus.rs", system_pallets)] +//! +//! Given that all Cumulus-based runtimes use a simple Aura-based consensus mechanism, the following +//! pallets also need to be added: +//! +//! - [`pallet_timestamp`] +//! - [`pallet_aura`] +//! - [`cumulus_pallet_aura_ext`] +#![doc = docify::embed!("./src/polkadot_sdk/cumulus.rs", consensus_pallets)] +//! +//! +//! Finally, a separate macro, similar to +//! [`impl_runtime_api`](frame::runtime::prelude::impl_runtime_apis), which creates the default set +//! of runtime APIs, will generate the parachain runtime's validation runtime API, also known as +//! parachain validation function (PVF). Without this API, the relay chain is unable to validate +//! blocks produced by our parachain. +#![doc = docify::embed!("./src/polkadot_sdk/cumulus.rs", validate_block)] +//! +//! --- +//! +//! [FRAME]: crate::polkadot_sdk::frame_runtime + +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] + +#[cfg(test)] +mod tests { + mod runtime { + pub use frame::{ + deps::sp_consensus_aura::sr25519::AuthorityId as AuraId, prelude::*, + runtime::prelude::*, testing_prelude::*, + }; + + #[docify::export(CR)] + construct_runtime!( + pub struct Runtime { + // system-level pallets. + System: frame_system, + Timestamp: pallet_timestamp, + ParachainSystem: cumulus_pallet_parachain_system, + ParachainInfo: parachain_info, + + // parachain consensus support -- mandatory. + Aura: pallet_aura, + AuraExt: cumulus_pallet_aura_ext, + } + ); + + #[docify::export] + mod system_pallets { + use super::*; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + } + + impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = (); + type XcmpMessageHandler = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + 6000, // relay chain block time + 1, + 1, + >; + type WeightInfo = (); + type DmpQueue = frame::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; + } + + impl parachain_info::Config for Runtime {} + } + + #[docify::export] + mod consensus_pallets { + use super::*; + + 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; + } + + #[docify::export(timestamp)] + #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig as pallet_timestamp::DefaultConfig)] + impl pallet_timestamp::Config for Runtime {} + + impl cumulus_pallet_aura_ext::Config for Runtime {} + } + + #[docify::export(validate_block)] + cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + } + } +} diff --git a/developer-hub/src/polkadot_sdk/frame_runtime.rs b/developer-hub/src/polkadot_sdk/frame_runtime.rs new file mode 100644 index 00000000000..d9cb1fd531b --- /dev/null +++ b/developer-hub/src/polkadot_sdk/frame_runtime.rs @@ -0,0 +1,179 @@ +//! # FRAME +//! +//! ```no_compile +//! ______ ______ ________ ___ __ __ ______ +//! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ +//! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ +//! \:\/___/\\:(_) ) )_\::(_) \ \\:. \ \\:\/___/\ +//! \:::._\/ \: __ `\ \\:: __ \ \\:.\-/\ \ \\::___\/_ +//! \:\ \ \ \ `\ \ \\:.\ \ \ \\. \ \ \ \\:\____/\ +//! \_\/ \_\/ \_\/ \__\/\__\/ \__\/ \__\/ \_____\/ +//! ``` +//! +//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's +//! > State Transition Function (Runtime) Framework. +//! +//! ## Introduction +//! +//! As described in [`crate::reference_docs::wasm_meta_protocol`], at a high-level Substrate-based +//! blockchains are composed of two parts: +//! +//! 1. A *runtime* which represents the state transition function (i.e. "Business Logic") of a +//! blockchain, and is encoded as a WASM blob. +//! 2. A node whose primary purpose is to execute the given runtime. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_simple.mmd")] +//! +//! *FRAME is the Substrate's framework of choice to build a runtime.* +//! +//! FRAME is composed of two major components, **pallets** and a **runtime**. +//! +//! ## Pallets +//! +//! A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be +//! linked to other pallets. In order to be reusable, pallets shipped with FRAME strive to only care +//! about its own responsibilities and make as few assumptions about the general runtime as +//! possible. A pallet is analogous to a _module_ in the runtime. +//! +//! A pallet is defined as a `mod pallet` wrapped by the [`frame::pallet`] macro. Within this macro, +//! pallet components/parts can be defined. Most notable of these parts are: +//! +//! - [Config](frame::pallet_macros::config), allowing a pallet to make itself configurable and +//! generic over types, values and such. +//! - [Storage](frame::pallet_macros::storage), allowing a pallet to define onchain storage. +//! - [Dispatchable function](frame::pallet_macros::call), allowing a pallet to define extrinsics +//! that are callable by end users, from the outer world. +//! - [Events](frame::pallet_macros::event), allowing a pallet to emit events. +//! - [Errors](frame::pallet_macros::error), allowing a pallet to emit well-formed errors. +//! +//! Some of these pallet components resemble the building blocks of a smart contract. While both +//! models are programming state transition functions of blockchains, there are crucial differences +//! between the two. See [`crate::reference_docs::runtime_vs_smart_contract`] for more. +//! +//! Most of these components are defined using macros, the full list of which can be found in +//! [`frame::pallet_macros`]. +//! +//! ### Example +//! +//! The following examples showcases a minimal pallet. +#![doc = docify::embed!("src/polkadot_sdk/frame_runtime.rs", pallet)] +//! +//! +//! A runtime is a collection of pallets that are amalgamated together. Each pallet typically has +//! some configurations (exposed as a `trait Config`) that needs to be *specified* in the runtime. +//! This is done with [`frame::runtime::prelude::construct_runtime`]. +//! +//! A (real) runtime that actually wishes to compile to WASM needs to also implement a set of +//! runtime-apis. These implementation can be specified using the +//! [`frame::runtime::prelude::impl_runtime_apis`] macro. +//! +//! ### Example +//! +//! The following example shows a (test) runtime that is composing the pallet demonstrated above, +//! next to the [`frame::prelude::frame_system`] pallet, into a runtime. +#![doc = docify::embed!("src/polkadot_sdk/frame_runtime.rs", runtime)] +//! +//! ## More Examples +//! +//! You can find more FRAME examples that revolve around specific features at [`pallet_examples`]. +//! +//! ## Alternatives 🌈 +//! +//! There is nothing in the Substrate's node side code-base that mandates the use of FRAME. While +//! FRAME makes it very simple to write Substrate-based runtimes, it is by no means intended to be +//! the only one. At the end of the day, any WASM blob that exposes the right set of runtime APIs is +//! a valid Runtime form the point of view of a Substrate client (see +//! [`crate::reference_docs::wasm_meta_protocol`]). Notable examples are: +//! +//! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template). +//! * writing a runtime in AssemblyScript,as explored in [this project](https://github.com/LimeChain/subsembly). + +#[cfg(test)] +mod tests { + use frame::prelude::*; + + /// A FRAME based pallet. This `mod` is the entry point for everything else. All + /// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an + /// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for + /// more. + #[docify::export] + #[frame::pallet(dev_mode)] + pub mod pallet { + use super::*; + + /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a + /// later point from the runtime that wishes to contain it. It allows the pallet to be + /// parameterized over both types and values. + #[pallet::config] + pub trait Config: frame_system::Config { + /// A type that is not known now, but the runtime that will contain this pallet will + /// know it later, therefore we define it here as an associated type. + type RuntimeEvent: IsType<::RuntimeEvent> + + From>; + + /// A parameterize-able value that we receive later via the `Get<_>` trait. + type ValueParameter: Get; + + /// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally + /// equal, but offer different tradeoffs. + const ANOTHER_VALUE_PARAMETER: u32; + } + + /// A mandatory struct in each pallet. All functions callable by external users (aka. + /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For + /// convenience, internal (private) functions can also be attached to this type. + #[pallet::pallet] + pub struct Pallet(PhantomData); + + /// The events tha this pallet can emit. + #[pallet::event] + pub enum Event {} + + /// A storage item that this pallet contains. This will be part of the state root trie/root + /// of the blockchain. + #[pallet::storage] + pub type Value = StorageValue; + + /// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a + /// `impl` block. + #[pallet::call] + impl Pallet { + /// This will be callable by external users, and has two u32s as a parameter. + pub fn some_dispatchable( + _origin: OriginFor, + _param: u32, + _other_para: u32, + ) -> DispatchResult { + Ok(()) + } + } + } + + /// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of + /// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real* + /// runtime. + #[docify::export] + pub mod runtime { + use super::pallet as pallet_example; + use frame::{prelude::*, testing_prelude::*}; + + // The major macro that amalgamates pallets into `struct Runtime` + construct_runtime!( + pub struct Runtime { + System: frame_system, + Example: pallet_example, + } + ); + + // These `impl` blocks specify the parameters of each pallet's `trait Config`. + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_example::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValueParameter = ConstU32<42>; + const ANOTHER_VALUE_PARAMETER: u32 = 42; + } + } +} diff --git a/developer-hub/src/polkadot_sdk/mod.rs b/developer-hub/src/polkadot_sdk/mod.rs new file mode 100644 index 00000000000..38ce5c404ff --- /dev/null +++ b/developer-hub/src/polkadot_sdk/mod.rs @@ -0,0 +1,134 @@ +//! # Polkadot SDK +//! +//! [Polkadot SDK](https://github.com/paritytech/polkadot-sdk) provides the main resources needed to +//! start building on the [Polkadot network](https://polkadot.network), a scalable, multi-chain +//! blockchain platform that enables different blockchains to securely interoperate. +//! +//! [![StackExchange](https://img.shields.io/badge/StackExchange-Polkadot%20and%20Substrate-222222?logo=stackexchange)](https://substrate.stackexchange.com/) +//! +//! [![awesomeDot](https://img.shields.io/badge/polkadot-awesome-e6007a?logo=polkadot)](https://github.com/Awsmdot/awesome-dot) +//! [![wiki](https://img.shields.io/badge/polkadot-wiki-e6007a?logo=polkadot)](https://wiki.polkadot.network/) +//! [![forum](https://img.shields.io/badge/polkadot-forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) +//! +//! [![RFCs](https://img.shields.io/badge/fellowship-RFCs-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/rfcs) +//! [![Runtime](https://img.shields.io/badge/fellowship-runtimes-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/runtimes) +//! [![Manifesto](https://img.shields.io/badge/fellowship-manifesto-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/manifesto) +//! +//! ## Getting Started +//! +//! The primary way to get started with the Polkadot SDK is to start writing a FRAME-based runtime. +//! See: +//! +//! * [`polkadot`], to understand what is Polkadot as a development platform. +//! * [`substrate`], for an overview of what Substrate as the main blockchain framework of Polkadot +//! SDK. +//! * [`frame`], to learn about how to write blockchain applications aka. "App Chains". +//! * Continue with the [`developer_hub`'s "getting started"](crate#getting-started). +//! +//! ## Components +//! +//! #### Substrate +//! +//! [![Substrate-license](https://img.shields.io/badge/License-GPL3%2FApache2.0-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/LICENSE-APACHE2) +//! [![GitHub +//! Repo](https://img.shields.io/badge/github-substrate-2324CC85)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate) +//! +//! [`substrate`] is the base blockchain framework used to power the Polkadot SDK. It is a full +//! toolkit to create sovereign blockchains, including but not limited to those who connect to +//! Polkadot as parachains. +//! +//! #### FRAME +//! +//! [![Substrate-license](https://img.shields.io/badge/License-Apache2.0-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/LICENSE-APACHE2) +//! [![GitHub +//! Repo](https://img.shields.io/badge/github-frame-2324CC85)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame) +//! +//! [`frame`] is the framework used to create Substrate-based application logic, aka. runtimes. +//! Learn more about the distinction of a runtime and node in +//! [`reference_docs::wasm_meta_protocol`]. +//! +//! #### Cumulus +//! +//! [![Cumulus-license](https://img.shields.io/badge/License-GPL3-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/LICENSE) +//! [![GitHub +//! Repo](https://img.shields.io/badge/github-cumulus-white)](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus) +//! +//! [`cumulus`] transforms FRAME-based runtimes into Polkadot-compatible parachain runtimes, and +//! Substrate-based nodes into Polkadot/Parachain-compatible nodes. +//! +//! #### XCM +//! +//! [![XCM-license](https://img.shields.io/badge/License-GPL3-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE) +//! [![GitHub +//! Repo](https://img.shields.io/badge/github-XCM-e6007a?logo=polkadot)](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm) +//! +//! [`xcm`], short for "cross consensus message", is the primary format that is used for +//! communication between parachains, but is intended to be extensible to other use cases as well. +//! +//! #### Polkadot +//! +//! [![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE) +//! [![GitHub +//! Repo](https://img.shields.io/badge/github-polkadot-e6007a?logo=polkadot)](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot) +//! +//! [`polkadot`] is an implementation of a Polkadot node in Rust, by `@paritytech`. The Polkadot +//! runtimes are located under the +//! [`polkadot-fellows/runtimes`](https://github.com/polkadot-fellows/runtimes) repository. +//! +//! ### Summary +//! +//! The following diagram summarizes how some of the components of Polkadot SDK work together: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/polkadot_sdk_substrate.mmd")] +//! +//! A Substrate-based chain is a blockchain composed of a runtime and a node. As noted above, the +//! runtime is the application logic of the blockchain, and the node is everything else. +//! See [`crate::reference_docs::wasm_meta_protocol`] for an in-depth explanation of this. The +//! former is built with [`frame`], and the latter is built with rest of Substrate. +//! +//! > You can think of a Substrate-based chain as a white-labeled blockchain. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/polkadot_sdk_polkadot.mmd")] +//! Polkadot is itself a Substrate-based chain, composed of the exact same two components. It has +//! specialized logic in both the node and the runtime side, but it is not "special" in any way. +//! +//! A parachain is a "special" Substrate-based chain, whereby both the node and the runtime +//! components have became "Polkadot-aware" using Cumulus. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/polkadot_sdk_parachain.mmd")] +//! +//! ## Notable Upstream Crates +//! +//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) +//! - [`parity-db`](https://github.com/paritytech/parity-db) +//! - [`trie`](https://github.com/paritytech/trie) +//! - [`parity-common`](https://github.com/paritytech/parity-common) +//! +//! ## Trophy Section: Notable Downstream Projects +//! +//! A list of projects and tools in the blockchain ecosystem that one way or another parts of the +//! Polkadot SDK: +//! +//! * [Polygon's spin-off, Avail](https://github.com/availproject/avail) +//! * [Cardano Partner Chains](https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/) +//! * [Starknet's Madara Sequencer](https://github.com/keep-starknet-strange/madara) +//! +//! [`substrate`]: crate::polkadot_sdk::substrate +//! [`frame`]: crate::polkadot_sdk::frame_runtime +//! [`cumulus`]: crate::polkadot_sdk::cumulus +//! [`polkadot`]: crate::polkadot_sdk::polkadot +//! [`xcm`]: crate::polkadot_sdk::xcm + +/// Lean about Cumulus, the framework that transforms [`substrate`]-based chains into +/// [`polkadot`]-enabled parachains. +pub mod cumulus; +/// Learn about FRAME, the framework used to build Substrate runtimes. +pub mod frame_runtime; +/// Learn about Polkadot as a platform. +pub mod polkadot; +/// Learn about different ways through which smart contracts can be utilized on top of Substrate, +/// and in the Polkadot ecosystem. +pub mod smart_contracts; +/// Learn about Substrate, the main blockchain framework used in the Polkadot ecosystem. +pub mod substrate; +/// Index of all the templates that can act as first scaffold for a new project. +pub mod templates; +/// Learn about XCM, the de-facto communication language between different consensus systems. +pub mod xcm; diff --git a/developer-hub/src/polkadot_sdk/polkadot.rs b/developer-hub/src/polkadot_sdk/polkadot.rs new file mode 100644 index 00000000000..d157a660e56 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/polkadot.rs @@ -0,0 +1,87 @@ +//! # Polkadot +//! +//! Implementation of the Polkadot node/host in Rust. +//! +//! ## Learn More and Get Involved +//! +//! - [Polkadot Forum](https://forum.polkadot.network/) +//! - [Polkadot Parachains](https://parachains.info/) +//! - [Polkadot (multi-chain) Explorer](https://subscan.io/) +//! - Polkadot Fellowship +//! - [Manifesto](https://github.com/polkadot-fellows/manifesto) +//! - [Runtimes](https://github.com/polkadot-fellows/runtimes) +//! - [RFCs](https://github.com/polkadot-fellows/rfcs) +//! - [Polkadot Specs](spec.polkadot.network) +//! - [The Polkadot Parachain Host Implementers' Guide](https://paritytech.github.io/polkadot-sdk/book/) +//! - [Whitepaper](https://www.polkadot.network/whitepaper/) +//! +//! ## Alternative Node Implementations 🌈 +//! +//! - [Smoldot](https://crates.io/crates/smoldot-light). Polkadot light node/client. +//! - [KAGOME](https://github.com/qdrvm/kagome). C++ implementation of the Polkadot host. +//! - [Gossamer](https://github.com/ChainSafe/gossamer). Golang implementation of the Polkadot host. +//! +//! ## Platform +//! +//! In this section, we examine what what platform Polkadot exactly provides to developers. +//! +//! ### Polkadot White Paper +//! +//! The original vision of Polkadot (everything in the whitepaper, which was eventually called +//! **Polkadot 1.0**) revolves around the following arguments: +//! +//! * Future is multi-chain, because we need different chains with different specialization to +//! achieve widespread goals. +//! * In other words, no single chain is good enough to achieve all goals. +//! * A multi-chain future will inadvertently suffer from fragmentation of economic security. +//! * This stake fragmentation will make communication over consensus system with varying security +//! levels inherently unsafe. +//! +//! Polkadot's answer to the above is: +//! +//! > The chains of the future must have a way to share their economic security, whilst maintaining +//! > their execution and governance sovereignty. These chains are called "Parachains". +//! +//! * Shared Security: The idea of shared economic security sits at the core of Polkadot. Polkadot +//! enables different parachains* to pool their economic security from Polkadot (i.e. "*Relay +//! Chain*"). +//! * (heterogenous) Sharded Execution: Yet, each parachain is free to have its own execution logic +//! (runtime), which also encompasses governance and sovereignty. Moreover, Polkadot ensures the +//! correct execution of all parachain, without having all of its validators re-execute all +//! parachain blocks. When seen from this perspective, the fact that Polkadot executes different +//! parachains means it is a platform that has fully delivered (the holy grail of) "Full Execution +//! Sharding". TODO: link to approval checking article. https://github.com/paritytech/polkadot-sdk-docs/issues/66 +//! * A framework to build blockchains: In order to materialize the ecosystem of parachains, an easy +//! blockchain framework must exist. This is [Substrate](crate::polkadot_sdk::substrate), +//! [FRAME](crate::polkadot_sdk::frame_runtime) and [Cumulus](crate::polkadot_sdk::cumulus). +//! * A communication language between blockchains: In order for these blockchains to communicate, +//! they need a shared language. [XCM](crate::polkadot_sdk::xcm) is one such language, and the one +//! that is most endorsed in the Polkadot ecosystem. +//! +//! > Note that the interoperability promised by Polkadot is unparalleled in that any two parachains +//! > connected to Polkadot have the same security and can have much better guarantees about the +//! > security of the recipient of any message. TODO: weakest link in bridges systems. https://github.com/paritytech/polkadot-sdk-docs/issues/66 +//! +//! Polkadot delivers the above vision, alongside a flexible means for parachains to schedule +//! themselves with the Relay Chain. To achieve this, Polkadot has been developed with an +//! architecture similar to that of a computer. Polkadot Relay Chain has a number of "cores". Each +//! core is (in simple terms) capable of progressing 1 parachain at a time. For example, a parachain +//! can schedule itself on a single core for 5 relay chain blocks. +//! +//! Within the scope of Polkadot 1.x, two main scheduling ways have been considered: +//! +//! * Long term Parachains, obtained through locking a sum of DOT in an auction system. +//! * on-demand Parachains, purchased through paying DOT to the relay-chain whenever needed. +//! +//! ### The Future +//! +//! After delivering Polkadot 1.x, the future of Polkadot as a protocol and platform is in the hands +//! of the community and the fellowship. This is happening most notable through the RFC process. +//! Some of the RFCs that do alter Polkadot as a platform and have already passed are as follows: +//! +//! - RFC#1: [Agile-coretime](https://github.com/polkadot-fellows/RFCs/blob/main/text/0001-agile-coretime.md): +//! Agile periodic-sale-based model for assigning Coretime on the Polkadot Ubiquitous Computer. +//! - RFC#5: [Coretime-interface](https://github.com/polkadot-fellows/RFCs/blob/main/text/0005-coretime-interface.md): +//! Interface for manipulating the usage of cores on the Polkadot Ubiquitous Computer. +// TODO: add more context and explanations about Polkadot as the Ubiquitous Computer and related +// tech. https://github.com/paritytech/polkadot-sdk-docs/issues/66 diff --git a/developer-hub/src/polkadot_sdk/smart_contracts.rs b/developer-hub/src/polkadot_sdk/smart_contracts.rs new file mode 100644 index 00000000000..a4916f9c921 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/smart_contracts.rs @@ -0,0 +1,9 @@ +//! # Smart Contracts +//! +//! TODO: @cmichi https://github.com/paritytech/polkadot-sdk-docs/issues/56 +//! +//! - WASM and EVM based, pallet-contracts and pallet-evm. +//! - single-daap-chain, transition from ink! to FRAME. +//! - Link to `use.ink` +//! - Link to [`crate::reference_docs::runtime_vs_smart_contract`]. +//! - https://use.ink/migrate-ink-contracts-to-polkadot-frame-parachain/ diff --git a/developer-hub/src/polkadot_sdk/substrate.rs b/developer-hub/src/polkadot_sdk/substrate.rs new file mode 100644 index 00000000000..399f18d03be --- /dev/null +++ b/developer-hub/src/polkadot_sdk/substrate.rs @@ -0,0 +1,151 @@ +//! # Substrate +//! +//! 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. +//! +//! ## Overview, Philosophy +//! +//! Substrate approaches blockchain development with an acknowledgement of a few self-evident +//! truths: +//! +//! 1. Society and technology evolves. +//! 2. Humans are fallible. +//! +//! This, makes the task of designing a correct, safe and long-lasting blockchain system hard. +//! +//! Nonetheless, in strive towards achieve this goal, Substrate embraces the following: +//! +//! 1. Use of **Rust** as a modern and safe programming language, which limits human error through +//! various means, most notably memory and type safety. +//! 2. Substrate is written from the ground-up with a *generic, modular and extensible* design. This +//! ensures that software components can be easily swapped and upgraded. Examples of this is +//! multiple consensus mechanisms provided by Substrate, as listed below. +//! 3. Lastly, the final blockchain system created with the above properties needs to be +//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the +//! application logic of the blockchain (called "Runtime") is encoded as a WASM blob, and is +//! stored in the state. The rest of the system (called "node") acts as the executor of the WASM +//! blob. +//! +//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as WASM blob" +//! accord. This enables the Runtime to become inherently upgradeable, crucially without forks. The +//! upgrade is merely a matter of the WASM blob being changed in the state, which is, in principle, +//! same as updating an account's balance. Learn more about this in detail in +//! [`crate::reference_docs::wasm_meta_protocol`]. +//! +//! > A great analogy for substrate is the following: Substrate node is a gaming console, and a WASM +//! > runtime, possibly created with FRAME is the game being inserted into the console. +//! +//! [`frame`], Substrate's default runtime development library, takes the above safety practices +//! even further by embracing a declarative programming model whereby correctness is enhanced and +//! the system is highly configurable through parameterization. Learn more about this in +//! [`crate::reference_docs::trait_based_programming`]. +//! +//! ## How to Get Started +//! +//! Substrate offers different options at the spectrum of technical freedom <-> development ease. +//! +//! * The easiest way to use Substrate is to use one of the templates (some of which listed at +//! [`crate::polkadot_sdk::templates`]) and only tweak the parameters of the runtime or node. This +//! allows you to launch a blockchain in minutes, but is limited in technical freedom. +//! * Next, most developers wish to develop their custom runtime modules, for which the de-facto way +//! is [`frame`](crate::polkadot_sdk::frame_runtime). +//! * Finally, Substrate is highly configurable at the node side as well, but this is the most +//! technically demanding. +//! +//! > A notable Substrate-based blockchain that has built both custom FRAME pallets and custom +//! > node-side components is . +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_dev.mmd")] +//! +//! ## Structure +//! +//! Substrate contains a large number of crates, therefore it is useful to have an overview of what +//! they are, and how they are organized. In broad terms, these crates are divided into three +//! categories: +//! +//! * `sc-*` (short for *Substrate-client*) crates, located under `./client` folder. These are all +//! the crates that lead to the node software. Notable examples [`sc_network`], various consensus +//! crates, RPC ([`sc_rpc_api`]) and database ([`sc_client_db`]), all of which are expected to +//! reside in the node side. +//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These +//! are crates that facilitate both the node and the runtime, but are not opinionated about what +//! framework is using for building the runtime. Notable examples are [`sp_api`] and [`sp_io`], +//! which form the communication bridge between the node and runtime. +//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related +//! to FRAME. See [`frame`] for more information. +//! +//! ### WASM Build +//! +//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both WASM (when a WASM +//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate +//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a +//! crate is being built with the standard library, and is built for native. Otherwise, it is built +//! for `no_std`. +//! +//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find +//! in any Substrate-based runtime. +//! +//! Substrate-based runtimes use [`substrate_wasm_builder`] in their `build.rs` to automatically +//! build their WASM files as a part of normal build command (e.g. `cargo build`). Once built, the +//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}.wasm`. +//! +//! ### Binaries +//! +//! Multiple binaries are shipped with substrate, the most important of which are located in the +//! [`./bin`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin) folder. +//! +//! * [`node_cli`] is an extensive substrate node that contains the superset of all runtime and node +//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the +//! modules that are provided with `FRAME`. This node and runtime is only used for testing and +//! demonstration. +//! * [`chain_spec_builder`]: Utility to build more detailed chain-specs for the aforementioned +//! node. Other projects typically contain a `build-spec` subcommand that does the same. +//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template): +//! a template node that contains a minimal set of features and can act as a starting point of a +//! project. +//! * [`subkey`]: Substrate's key management utility. +//! +//! ### Anatomy of a Binary Crate +//! +//! From the above, [`node_cli`]/[`kitchensink_runtime`] and `node-template` are essentially +//! blueprints of a Substrate-based project, as the name of the latter is implying. Each +//! Substrate-based project typically contains the following: +//! +//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file. +//! This file typically contains the [`frame::runtime::prelude::construct_runtime`] and +//! [`frame::runtime::prelude::impl_runtime_apis`] macro calls, which is the final definition of a +//! runtime. +//! +//! * Under `./node`, a `main.rs`, which is the starting point, and a `./service.rs`, which contains +//! all the node side components. Skimming this file yields an overview of the networking, +//! database, consensus and similar node side components. +//! +//! > The above two are conventions, not rules. +//! +//! > See for an update on how the node side +//! > components are being amalgamated. +//! +//! ## Parachain? +//! +//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways +//! 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](crate::polkadot_sdk::cumulus), the library on +//! top of Substrate, empowering any substrate-based chain to be a Polkadot parachain. +//! +//! ## Where To Go Next? +//! +//! Additional noteworthy crates within substrate: +//! +//! - RPC APIs of a Substrate node: [`sc_rpc_api`]/[`sc_rpc`] +//! - CLI Options of a Substrate node: [`sc_cli`] +//! - All of the consensus related crates provided by Substrate: +//! - [`sc_consensus_aura`] +//! - [`sc_consensus_babe`] +//! - [`sc_consensus_grandpa`] +//! - [`sc_consensus_beefy`] (TODO: @adrian, add some high level docs https://github.com/paritytech/polkadot-sdk-docs/issues/57) +//! - [`sc_consensus_manual_seal`] +//! - [`sc_consensus_pow`] + +#[doc(hidden)] +pub use crate::polkadot_sdk; diff --git a/developer-hub/src/polkadot_sdk/templates.rs b/developer-hub/src/polkadot_sdk/templates.rs new file mode 100644 index 00000000000..f60c75b8f21 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/templates.rs @@ -0,0 +1,45 @@ +//! # Templates +//! +//! ### Internal +//! +//! The following templates are maintained as a part of the `polkadot-sdk` repository: +//! +//! - classic [`substrate-node-template`]: is a white-labeled substrate-based blockchain with a +//! moderate amount of features. It can act as a great starting point for those who want to learn +//! Substrate/FRAME and want to have a template that is already doing something. +//! - [`substrate-minimal-template`]: Same as the above, but it contains the least amount of code in +//! both the node and runtime. It is a great starting point for those who want to deeply learn +//! Substrate and FRAME. +//! - classic [`cumulus-parachain-template`], which is the de-facto parachain template shipped with +//! Cumulus. It is the parachain-enabled version of [`substrate-node-template`]. +//! +//! ### External Templates +//! +//! Noteworthy templates outside of this repository. +//! +//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template): A +//! parachain template that contains more built-in functionality such as assets and NFTs. +//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template): A +//! parachain template for launching EVM-compatible parachains. +//! +//! [`substrate-node-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/node-template/ +//! [`substrate-minimal-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/minimal/ +//! [`cumulus-parachain-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/parachain-template/ + +// TODO: in general, we need to make a deliberate choice here of moving a few key templates to this +// repo (nothing stays in `substrate-developer-hub`) and the everything else should be community +// maintained. https://github.com/paritytech/polkadot-sdk-docs/issues/67 + +// TODO: we should rename `substrate-node-template` to `substrate-basic-template`, +// `substrate-blockchain-template`. `node` is confusing in the name. +// `substrate-blockchain-template` and `cumulus-parachain-template` go well together 🤝. https://github.com/paritytech/polkadot-sdk-docs/issues/67 + +// NOTE: a super important detail that I am looking forward to here is +// and +// . Meaning that I would not spend time on +// teaching someone too much detail about the ugly thing we call "node" nowadays. In the future, I +// am sure we will either have a better "node-builder" code that can actually be tested, or an +// "omni-node" that can run (almost) any wasm file. We should already build tutorials in this +// direction IMO. This also affects all the templates. If we have a good neat runtime file, which we +// are moving toward, and a good node-builder, we don't need all of these damn templates. These +// templates are only there because the boilerplate is super horrible atm. diff --git a/developer-hub/src/polkadot_sdk/xcm.rs b/developer-hub/src/polkadot_sdk/xcm.rs new file mode 100644 index 00000000000..0d600f751c8 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/xcm.rs @@ -0,0 +1,5 @@ +//! # XCM +//! +//! @KiChjang @franciscoaguirre +//! TODO: RFCs, xcm-spec, the future of the repo, minimal example perhaps, forward to where actual +//! docs are hosted. https://github.com/paritytech/polkadot-sdk-docs/issues/58 diff --git a/developer-hub/src/reference_docs/blockchain_scalibility.rs b/developer-hub/src/reference_docs/blockchain_scalibility.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/developer-hub/src/reference_docs/blockchain_state_machines.rs b/developer-hub/src/reference_docs/blockchain_state_machines.rs new file mode 100644 index 00000000000..611ca2b778a --- /dev/null +++ b/developer-hub/src/reference_docs/blockchain_state_machines.rs @@ -0,0 +1,29 @@ +//! # State Transition Function +//! +//! This document briefly explains how in the context of Substrate-based blockchains, we view the +//! blockchain as a **decentralized state transition function**. +//! +//! Recall that a blockchain's main purpose is to help a permissionless set of entities to agree on +//! a shared data-set, and how it evolves. This is called the **State**, also referred to as +//! "onchain" data, or *Storage* in the context of FRAME. The state is where the account balance of +//! each user is, for example, stored, and there is a canonical version of it that everyone agrees +//! upon. +//! +//! Then, recall that a typical blockchain system will alter its state through execution of blocks. +//! *The component that dictates how this state alteration can happen is called the state transition +//! function*. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/stf_simple.mmd")] +//! +//! In Substrate-based blockchains, the state transition function is called the *Runtime*. This is +//! explained further in [`crate::reference_docs::wasm_meta_protocol`]. +//! +//! With this in mind, we can paint a complete picture of a blockchain as a state machine: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/stf.mmd")] +//! +//! In essence, the state of the blockchain at block N is the outcome of applying the state +//! transition function to the the previous state, and the current block as input. This can be +//! mathematically represented as: +//! +//! ```math +//! STF = F(State_N, Block_N) -> State_{N+1} +//! ``` diff --git a/developer-hub/src/reference_docs/chain_spec_genesis.rs b/developer-hub/src/reference_docs/chain_spec_genesis.rs new file mode 100644 index 00000000000..2ac51a91f2d --- /dev/null +++ b/developer-hub/src/reference_docs/chain_spec_genesis.rs @@ -0,0 +1,4 @@ +//! Chain spec and genesis build. +//! +//! What is chain-spec. +//! What is genesis state and how to build it. diff --git a/developer-hub/src/reference_docs/cli.rs b/developer-hub/src/reference_docs/cli.rs new file mode 100644 index 00000000000..9274e86b04e --- /dev/null +++ b/developer-hub/src/reference_docs/cli.rs @@ -0,0 +1,7 @@ +//! # Command Line Arguments +//! +//! +//! Notes: +//! +//! - Command line arguments of a typical substrate based chain, and how to find and learn them. +//! - How to extend them with your custom stuff. diff --git a/developer-hub/src/reference_docs/consensus_swapping.rs b/developer-hub/src/reference_docs/consensus_swapping.rs new file mode 100644 index 00000000000..e639761ee97 --- /dev/null +++ b/developer-hub/src/reference_docs/consensus_swapping.rs @@ -0,0 +1,6 @@ +//! Consensus Swapping +//! +//! Notes: +//! +//! - The typical workshop done by Joshy in some places where he swaps out the consensus to be PoW. +//! - This could also be a tutorial rather than a ref doc, depending on the size. diff --git a/developer-hub/src/reference_docs/extrinsic_encoding.rs b/developer-hub/src/reference_docs/extrinsic_encoding.rs new file mode 100644 index 00000000000..b10b100bfbb --- /dev/null +++ b/developer-hub/src/reference_docs/extrinsic_encoding.rs @@ -0,0 +1,277 @@ +//! # Constructing and Signing Extrinsics +//! +//! Extrinsics are payloads that are stored in blocks which are responsible for altering the state +//! of a blockchain via the [_state transition +//! function_][crate::reference_docs::blockchain_state_machines]. +//! +//! Substrate is configurable enough that extrinsics can take any format. In practice, runtimes +//! tend to use our [`sp_runtime::generic::UncheckedExtrinsic`] type to represent extrinsics, +//! because it's generic enough to cater for most (if not all) use cases. In Polkadot, this is +//! configured [here](https://github.com/polkadot-fellows/runtimes/blob/94b2798b69ba6779764e20a50f056e48db78ebef/relay/polkadot/src/lib.rs#L1478) +//! at the time of writing. +//! +//! What follows is a description of how extrinsics based on this +//! [`sp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are +//! looking at how extrinsics with a format version of 4 are encoded. This version is itself a part +//! of the payload, and if it changes, it indicates that something about the encoding may have +//! changed. +//! +//! # Encoding an Extrinsic +//! +//! At a high level, all extrinsics compatible with [`sp_runtime::generic::UncheckedExtrinsic`] +//! are formed from concatenating some details together, as in the following pseudo-code: +//! +//! ```text +//! extrinsic_bytes = concat( +//! compact_encoded_length, +//! version_and_maybe_signature, +//! call_data +//! ) +//! ``` +//! +//! For clarity, the actual implementation in Substrate looks like this: +#![doc = docify::embed!("../substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs", unchecked_extrinsic_encode_impl)] +//! +//! Let's look at how each of these details is constructed: +//! +//! ## compact_encoded_length +//! +//! This is a [SCALE compact encoded][frame::deps::codec::Compact] integer which is equal to the +//! length, in bytes, of the rest of the extrinsic details. +//! +//! To obtain this value, we must encode and concatenate together the rest of the extrinsic details +//! first, and then obtain the byte length of these. We can then compact encode that length, and +//! prepend it to the rest of the details. +//! +//! ## version_and_maybe_signature +//! +//! If the extrinsic is _unsigned_, then `version_and_maybe_signature` will be just one byte +//! denoting the _transaction protocol version_, which is 4 (or `0b0000_0100`). +//! +//! If the extrinsic is _signed_ (all extrinsics submitted from users must be signed), then +//! `version_and_maybe_signature` is obtained by concatenating some details together, ie: +//! +//! ```text +//! version_and_maybe_signature = concat( +//! version_and_signed, +//! from_address, +//! signature, +//! signed_extensions_extra, +//! ) +//! ``` +//! +//! Each of the details to be concatenated together is explained below: +//! +//! ### version_and_signed +//! +//! This is one byte, equal to `0x84` or `0b1000_0100` (i.e. an upper 1 bit to denote that it is +//! signed, and then the transaction version, 4, in the lower bits). +//! +//! ### from_address +//! +//! This is the [SCALE encoded][frame::deps::codec] address of the sender of the extrinsic. The +//! address is the first generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], and so +//! can vary from chain to chain. +//! +//! The address type used on the Polkadot relay chain is [`sp_runtime::MultiAddress`], +//! where `AccountId32` is defined [here][`sp_core::crypto::AccountId32`]. When constructing a +//! signed extrinsic to be submitted to a Polkadot node, you'll always use the +//! [`sp_runtime::MultiAddress::Id`] variant to wrap your `AccountId32`. +//! +//! ### signature +//! +//! This is the [SCALE encoded][frame::deps::codec] signature. The signature type is configured via +//! the third generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], which determines the +//! shape of the signature and signing algorithm that should be used. +//! +//! The signature is obtained by signing the _signed payload_ bytes (see below on how this is +//! constructed) using the private key associated with the address and correct algorithm. +//! +//! The signature type used on the Polkadot relay chain is [`sp_runtime::MultiSignature`]; the +//! variants there are the types of signature that can be provided. +//! +//! ### signed_extensions_extra +//! +//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing each of +//! the [_signed extensions_][sp_runtime::traits::SignedExtension], and are configured by the +//! fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about +//! signed extensions [here][crate::reference_docs::signed_extensions]. +//! +//! When it comes to constructing an extrinsic, each signed extension has two things that we are +//! interested in here: +//! +//! - The actual SCALE encoding of the signed extension type itself; this is what will form our +//! `signed_extensions_extra` bytes. +//! - An `AdditionalSigned` type. This is SCALE encoded into the `signed_extensions_additional` data +//! of the _signed payload_ (see below). +//! +//! Either (or both) of these can encode to zero bytes. +//! +//! Each chain configures the set of signed extensions that it uses in its runtime configuration. +//! At the time of writing, Polkadot configures them +//! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25). +//! Some of the common signed extensions are defined +//! [here][frame::deps::frame_system#signed-extensions]. +//! +//! Information about exactly which signed extensions are present on a chain and in what order is +//! also a part of the metadata for the chain. For V15 metadata, it can be +//! [found here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. +//! +//! ## call_data +//! +//! This is the main payload of the extrinsic, which is used to determine how the chain's state is +//! altered. This is defined by the second generic parameter of +//! [`sp_runtime::generic::UncheckedExtrinsic`]. +//! +//! A call can be anything that implements [`Encode`][frame::deps::codec::Encode]. In FRAME-based +//! runtimes, a call is represented as an enum of enums, where the outer enum represents the FRAME +//! pallet being called, and the inner enum represents the call being made within that pallet, and +//! any arguments to it. Read more about the call enum +//! [here][crate::reference_docs::frame_composite_enums]. +//! +//! FRAME `Call` enums are automatically generated, and end up looking something like this: +#![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", call_data)] +//! +//! In pseudo-code, this `Call` enum encodes equivalently to: +//! +//! ```text +//! call_data = concat( +//! pallet_index, +//! call_index, +//! call_args +//! ) +//! ``` +//! +//! - `pallet_index` is a single byte denoting the index of the pallet that we are calling into, and +//! is what the tag of the outermost enum will encode to. +//! - `call_index` is a single byte denoting the index of the call that we are making the pallet, +//! and is what the tag of the inner enum will encode to. +//! - `call_args` are the SCALE encoded bytes for each of the arguments that the call expects, and +//! are typically provided as values to the inner enum. +//! +//! Information about the pallets that exist for a chain (including their indexes), the calls +//! available in each pallet (including their indexes), and the arguments required for each call +//! can be found in the metadata for the chain. For V15 metadata, this information +//! [is here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata]. +//! +//! # The Signed Payload Format +//! +//! All extrinsics submitted to a node from the outside world (also known as _transactions_) need to +//! be _signed_. The data that needs to be signed for some extrinsic is called the _signed payload_, +//! and its shape is described by the following pseudo-code: +//! +//! ```text +//! signed_payload = concat( +//! call_data, +//! signed_extensions_extra, +//! signed_extensions_additional, +//! ) +//! +//! if length(signed_payload) > 256 { +//! signed_payload = blake2_256(signed_payload) +//! } +//! ``` +//! +//! The bytes representing `call_data` and `signed_extensions_extra` can be obtained as descibed +//! above. `signed_extensions_additional` is constructed by SCALE encoding the +//! ["additional signed" data][sp_runtime::traits::SignedExtension::AdditionalSigned] for each +//! signed extension that the chain is using, in order. +//! +//! Once we've concatenated those together, we hash the result if it's greater than 256 bytes in +//! length using a Blake2 256bit hasher. +//! +//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload +//! for us, given `call_data` and a tuple of signed extensions. +//! +//! # Example Encoding +//! +//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic +//! as follows: +#![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", encoding_example)] + +#[docify::export] +pub mod call_data { + use parity_scale_codec::{Decode, Encode}; + + // The outer enum composes calls within + // different pallets together. We have two + // pallets, "PalletA" and "PalletB". + #[derive(Encode, Decode)] + pub enum Call { + #[codec(index = 0)] + PalletA(PalletACall), + #[codec(index = 7)] + PalletB(PalletBCall), + } + + // An inner enum represents the calls within + // a specific pallet. "PalletA" has one call, + // "Foo". + #[derive(Encode, Decode)] + pub enum PalletACall { + #[codec(index = 0)] + Foo(String), + } + + #[derive(Encode, Decode)] + pub enum PalletBCall { + #[codec(index = 0)] + Bar(String), + } +} + +#[docify::export] +pub mod encoding_example { + use super::call_data::{Call, PalletACall}; + use crate::reference_docs::signed_extensions::signed_extensions_example; + use parity_scale_codec::Encode; + use sp_core::crypto::AccountId32; + use sp_keyring::sr25519::Keyring; + use sp_runtime::{ + generic::{SignedPayload, UncheckedExtrinsic}, + MultiAddress, MultiSignature, + }; + + // Define some signed extensions to use. We'll use a couple of examples + // from the signed extensions reference doc. + type SignedExtensions = + (signed_extensions_example::AddToPayload, signed_extensions_example::AddToSignaturePayload); + + // We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set + // the address and signature type to those used on Polkadot, use our custom + // `Call` type, and use our custom set of `SignedExtensions`. + type Extrinsic = + UncheckedExtrinsic, Call, MultiSignature, SignedExtensions>; + + pub fn encode_demo_extrinsic() -> Vec { + // The "from" address will be our Alice dev account. + let from_address = MultiAddress::::Id(Keyring::Alice.to_account_id()); + + // We provide some values for our expected signed extensions. + let signed_extensions = ( + signed_extensions_example::AddToPayload(1), + signed_extensions_example::AddToSignaturePayload, + ); + + // Construct our call data: + let call_data = Call::PalletA(PalletACall::Foo("Hello".to_string())); + + // The signed payload. This takes care of encoding the call_data, + // signed_extensions_extra and signed_extensions_additional, and hashing + // the result if it's > 256 bytes: + let signed_payload = SignedPayload::new(&call_data, signed_extensions.clone()); + + // Sign the signed payload with our Alice dev account's private key, + // and wrap the signature into the expected type: + let signature = { + let sig = Keyring::Alice.sign(&signed_payload.encode()); + MultiSignature::Sr25519(sig) + }; + + // Now, we can build and encode our extrinsic: + let ext = Extrinsic::new_signed(call_data, from_address, signature, signed_extensions); + + let encoded_ext = ext.encode(); + encoded_ext + } +} diff --git a/developer-hub/src/reference_docs/fee_less_runtime.rs b/developer-hub/src/reference_docs/fee_less_runtime.rs new file mode 100644 index 00000000000..43a761a6c52 --- /dev/null +++ b/developer-hub/src/reference_docs/fee_less_runtime.rs @@ -0,0 +1,12 @@ +//! # Fee-Less Runtime +//! +//! +//! Notes: +//! +//! - An extension of [`runtime_vs_smart_contract`], showcasing the tools needed to build a safe +//! runtime that is fee-less. +//! - Would need to use unsigned origins, custom validate_unsigned, check the existence of some NFT +//! and some kind of rate limiting (eg. any account gets 5 free tx per day). +//! - The rule of thumb is that as long as the unsigned validate does one storage read, similar to +//! nonce, it is fine. +//! - This could possibly be a good tutorial/template, rather than a reference doc. diff --git a/developer-hub/src/reference_docs/frame_benchmarking_weight.rs b/developer-hub/src/reference_docs/frame_benchmarking_weight.rs new file mode 100644 index 00000000000..f65f4174ec6 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_benchmarking_weight.rs @@ -0,0 +1,23 @@ +//! # FRAME Benchmarking and Weights. +//! +//! Notes: +//! +//! On Weight as a concept. +//! +//! - Why we need it. Super important. People hate this. We need to argue why it is worth it. +//! - Axis of weight: PoV + Time. +//! - pre dispatch weight vs. metering and post dispatch correction. +//! - mention that we will do this for PoV +//! - you can manually refund using `DispatchResultWithPostInfo`. +//! - Technically you can have weights with any benchmarking framework. You just need one number to +//! be computed pre-dispatch. But FRAME gives you a framework for this. +//! - improve documentation of `#[weight = ..]` and `#[pallet::weight(..)]`. All syntax variation +//! should be covered. +//! +//! on FRAME benchmarking machinery: +//! +//! - component analysis, why everything must be linear. +//! - how to write benchmarks, how you must think of worst case. +//! - how to run benchmarks. +//! +//! - https://www.shawntabrizi.com/substrate/substrate-storage-deep-dive/ diff --git a/developer-hub/src/reference_docs/frame_composite_enums.rs b/developer-hub/src/reference_docs/frame_composite_enums.rs new file mode 100644 index 00000000000..6051cd53446 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_composite_enums.rs @@ -0,0 +1 @@ +//! # FRAME Composite Enums diff --git a/developer-hub/src/reference_docs/frame_currency.rs b/developer-hub/src/reference_docs/frame_currency.rs new file mode 100644 index 00000000000..ba181373062 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_currency.rs @@ -0,0 +1,8 @@ +//! FRAME Currency Abstractions and Traits +//! +//! Notes: +//! +//! - History, `Currency` trait. +//! - `Hold` and `Freeze` with diagram. +//! - `HoldReason` and `FreezeReason` +//! - This footgun: https://github.com/paritytech/polkadot-sdk/pull/1900#discussion_r1363783609 diff --git a/developer-hub/src/reference_docs/frame_origin.rs b/developer-hub/src/reference_docs/frame_origin.rs new file mode 100644 index 00000000000..a4078377cd7 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_origin.rs @@ -0,0 +1,14 @@ +//! # FRAME Origin +//! +//! Notes: +//! +//! - Def talk about account abstraction and how it is a solved issue in frame. See Gav's talk in +//! Protocol Berg 2023 +//! - system's raw origin, how it is amalgamated with other origins into one type +//! [`frame_composite_enums`] +//! - signed origin +//! - unsigned origin, link to [`fee_less_runtime`] +//! - Root origin, how no one can obtain it. +//! - Abstract origin: how FRAME allows you to express "origin is 2/3 of the this body or 1/2 of +//! that body or half of the token holders". +//! - `type CustomOrigin: EnsureOrigin<_>` in pallets. diff --git a/developer-hub/src/reference_docs/frame_runtime_migration.rs b/developer-hub/src/reference_docs/frame_runtime_migration.rs new file mode 100644 index 00000000000..0616ccbb6f5 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_runtime_migration.rs @@ -0,0 +1,9 @@ +//! # Runtime Runtime Upgrade and Testing +//! +//! +//! Notes: +//! +//! - Flow of things, when does `on_runtime_upgrade` get called. Link to to `Hooks` and its diagram +//! as source of truth. +//! - Data migration and when it is needed. +//! - Look into the pba-lecture. diff --git a/developer-hub/src/reference_docs/frame_system_accounts.rs b/developer-hub/src/reference_docs/frame_system_accounts.rs new file mode 100644 index 00000000000..ae9d2c9e0cb --- /dev/null +++ b/developer-hub/src/reference_docs/frame_system_accounts.rs @@ -0,0 +1,8 @@ +//! # FRAME Accounts +//! +//! How `frame_system` handles accountIds. Nonce. Consumers and Providers, reference counting. + +// - poorly understood topics, needs one great article to rul them all. +// - https://github.com/paritytech/substrate/issues/14425 +// - https://github.com/paritytech/substrate/pull/12951 +// - https://substrate.stackexchange.com/questions/263/what-is-the-meaning-of-the-account-provider-sufficients-and-consumer diff --git a/developer-hub/src/reference_docs/glossary.rs b/developer-hub/src/reference_docs/glossary.rs new file mode 100644 index 00000000000..d0bd6accce6 --- /dev/null +++ b/developer-hub/src/reference_docs/glossary.rs @@ -0,0 +1,62 @@ +//! # Glossary +//! +//! #### State +//! +//! The data around which the blockchain network wishes to come to consensus. Also +//! referred to as "onchain data", "onchain storage" or sometimes just "storage". In UTXO based +//! blockchains, is referred to as "ledger". +//! +//! **Synonyms**: Onchain data, Onchain storage, Storage, Ledger +//! +//! #### State Transition Function +//! +//! The WASM Blob that dictates how the blockchain should transition its state upon encountering new +//! blocks. +//! +//! #### Host +//! +//! The environment that hosts and executes the [state transition function's WASM +//! blob](#state-transition-function). +//! +//! #### Node +//! +//! The full software artifact that contains the [host](#host), but importantly also all the other +//! modules needed to be part of a blockchain network, such as peer-to-peer networking, database and +//! such. +//! +//! **Synonyms**: Client +//! +//! #### Light Node +//! +//! Same as [node](#nodes), but when capable of following the network only through listening to +//! block headers. Usually capable of running in more constrained environments, such as an embedded +//! device, phone, or a web browser. +//! +//! **Synonyms**: Light Client +//! +//! #### Offchain +//! +//! #### Host Function: +//! +//! #### Runtime API: +//! +//! #### Dispatchable: +//! +//! Callable +//! +//! #### Extrinsic +//! +//! +//! #### Pallet +//! +//! #### Full Node +//! +//! #### Archive Node +//! +//! #### Validator +//! +//! #### Collator +//! +//! #### Parachain +//! +//! aka. AppChain. diff --git a/developer-hub/src/reference_docs/light_nodes.rs b/developer-hub/src/reference_docs/light_nodes.rs new file mode 100644 index 00000000000..a6a0a828ef5 --- /dev/null +++ b/developer-hub/src/reference_docs/light_nodes.rs @@ -0,0 +1,7 @@ +//! # Light Clients +//! +//! +//! Notes: should contain only high level information about light clients, then link to how to set +//! it up in PAPI and SubXT +//! https://docs.substrate.io/learn/light-clients-in-substrate-connect/ +//! https://github.com/substrate-developer-hub/substrate-front-end-template/pull/277 diff --git a/developer-hub/src/reference_docs/metadata.rs b/developer-hub/src/reference_docs/metadata.rs new file mode 100644 index 00000000000..702c1c30fd9 --- /dev/null +++ b/developer-hub/src/reference_docs/metadata.rs @@ -0,0 +1 @@ +//! # Metadata diff --git a/developer-hub/src/reference_docs/mod.rs b/developer-hub/src/reference_docs/mod.rs new file mode 100644 index 00000000000..44284394000 --- /dev/null +++ b/developer-hub/src/reference_docs/mod.rs @@ -0,0 +1,99 @@ +//! # Polkadot SDK Reference Docs. +//! +//! This is the entry point for all reference documents that enhance one's learning experience in +//! the Polkadot SDK. +//! +//! Note that this module also contains the [glossary](crate::reference_docs::glossary). +//! +//! ## What is a "reference document"? +//! +//! First, see [why we use rust-docs for everything](crate#why-rust-docs) and our documentation +//! [principles](crate#principles). We acknowledge that as much of the crucial information should be +//! embedded in the low level rust-docs. Then, high level scenarios should be covered in +//! [`crate::guides`]. Finally, we acknowledge that there is a category of information that is: +//! +//! 1. crucial to know. +//! 2. is too high level to be in the rust-doc of any one `type`, `trait` or `fn`. +//! 3. is too low level to be encompassed in a [`crate::guides`]. +//! +//! We call this class of documents "reference documents". Our goal should be to minimize the number +//! of "reference" docs, as they incur maintenance burden. + +/// Learn how Substrate and FRAME use traits and associated types to make modules generic in a +/// type-safe manner. +pub mod trait_based_programming; + +/// Learn about the way Substrate and FRAME view their blockchains as state machines. +pub mod blockchain_state_machines; + +/// The glossary. +pub mod glossary; + +/// Learn about the WASM meta-protocol of all Substrate-based chains. +pub mod wasm_meta_protocol; + +/// Learn about the differences between smart contracts and a FRAME-based runtime. They are both +/// "code stored onchain", but how do they differ? +pub mod runtime_vs_smart_contract; + +/// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks. +pub mod extrinsic_encoding; + +/// Learn about the signed extensions that form a part of extrinsics. +// TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/42 +pub mod signed_extensions; + +/// Learn about *"Origin"* A topic in FRAME that enables complex account abstractions to be built. +// TODO: @shawntabrizi https://github.com/paritytech/polkadot-sdk-docs/issues/43 +pub mod frame_origin; + +/// Learn about how to write safe and defensive code in your FRAME runtime. +// TODO: @CrackTheCode016 https://github.com/paritytech/polkadot-sdk-docs/issues/44 +pub mod safe_defensive_programming; + +/// Learn about composite enums in FRAME-based runtimes, such as "RuntimeEvent" and "RuntimeCall". +pub mod frame_composite_enums; + +/// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to +/// control usage and sybil attacks. +pub mod fee_less_runtime; + +/// Learn about metadata, the main means through which an upgradeable runtime communicates its +/// properties to the outside world. +// TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/47 +pub mod metadata; + +/// Learn about how frame-system handles `account-ids`, nonces, consumers and providers. +pub mod frame_system_accounts; + +/// Learn about the currency-related abstractions provided in FRAME. +pub mod frame_currency; + +/// Learn about benchmarking and weight. +// TODO: @shawntabrizi @ggwpez https://github.com/paritytech/polkadot-sdk-docs/issues/50 +pub mod frame_benchmarking_weight; + +/// Learn about chain specification file and the genesis state of the blockchain. +// TODO: @michalkucharczyk https://github.com/paritytech/polkadot-sdk-docs/issues/51 +pub mod chain_spec_genesis; + +/// Learn about all the memory limitations of the WASM runtime when it comes to memory usage. +// TODO: @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/52 +pub mod wasm_memory; + +/// Learn about Substrate's CLI, and how it can be extended. +// TODO: @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/53 +pub mod cli; + +/// Learn about Substrate's consensus algorithms, and how you can switch between two. +// TODO: @JoshOrndorff @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/54 +pub mod consensus_swapping; + +/// Learn about all the advance ways to test your coordinate a rutnime upgrade and data migration. +// TODO: @liamaharon https://github.com/paritytech/polkadot-sdk-docs/issues/55 +pub mod frame_runtime_migration; + +/// Learn about light nodes, how they function, and how Substrate-based chains come +/// light-node-first out of the box. +// TODO: @jsdw @josepot https://github.com/paritytech/polkadot-sdk-docs/issues/68 +pub mod light_nodes; diff --git a/developer-hub/src/reference_docs/runtime_vs_smart_contract.rs b/developer-hub/src/reference_docs/runtime_vs_smart_contract.rs new file mode 100644 index 00000000000..7f96fa1800a --- /dev/null +++ b/developer-hub/src/reference_docs/runtime_vs_smart_contract.rs @@ -0,0 +1,6 @@ +//! Runtime vs. Smart Contracts +//! +//! Notes: +//! +//! Why one can be weighed, and one MUST be metered. +//! https://forum.polkadot.network/t/where-contracts-fail-and-runtimes-chains-are-needed/4464/3 diff --git a/developer-hub/src/reference_docs/safe_defensive_programming.rs b/developer-hub/src/reference_docs/safe_defensive_programming.rs new file mode 100644 index 00000000000..9d0f028e570 --- /dev/null +++ b/developer-hub/src/reference_docs/safe_defensive_programming.rs @@ -0,0 +1 @@ +//! diff --git a/developer-hub/src/reference_docs/signed_extensions.rs b/developer-hub/src/reference_docs/signed_extensions.rs new file mode 100644 index 00000000000..28b1426536b --- /dev/null +++ b/developer-hub/src/reference_docs/signed_extensions.rs @@ -0,0 +1,79 @@ +//! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic +//! format with custom data that can be checked by the runtime. +//! +//! # Example +//! +//! Defining a couple of very simple signed extensions looks like the following: +#![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] + +#[docify::export] +pub mod signed_extensions_example { + use parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::traits::SignedExtension; + + // This doesn't actually check anything, but simply allows + // some arbitrary `u32` to be added to the extrinsic payload + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToPayload(pub u32); + + impl SignedExtension for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + // This is the opposite; nothing will be added to the extrinsic payload, + // but the AdditionalSigned type (`1234u32`) will be added to the + // payload to be signed. + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToSignaturePayload; + + impl SignedExtension for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = u32; + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(1234) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } +} diff --git a/developer-hub/src/reference_docs/trait_based_programming.rs b/developer-hub/src/reference_docs/trait_based_programming.rs new file mode 100644 index 00000000000..249f4bcbce0 --- /dev/null +++ b/developer-hub/src/reference_docs/trait_based_programming.rs @@ -0,0 +1,229 @@ +//! # Trait-based Programming +//! +//! This document walks you over a peculiar way of using Rust's `trait` items. This pattern is +//! abundantly used within [`frame`] and is therefore paramount important for a smooth transition +//! into it. +//! +//! The rest of this document assumes familiarity with the +//! [Rust book's Advanced Traits](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html) +//! section. +//! Moreover, we use the [`frame::traits::Get`]. +//! +//! First, imagine we are writing a FRAME pallet. We represent this pallet with a `struct Pallet`, +//! and this pallet wants to implement the functionalities of that pallet, for example a simple +//! `transfer` function. For the sake of education, we are interested in having a `MinTransfer` +//! amount, expressed as a [`frame::traits::Get`], which will dictate what is the minimum amount +//! that can be transferred. +//! +//! We can foremost write this as simple as the following snippet: +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", basic)] +//! +//! +//! In this example, we use arbitrary choices for `AccountId`, `Balance` and the `MinTransfer` type. +//! This works great for **one team's purposes** but we have to remember that Substrate and FRAME +//! are written as generic frameworks, intended to be highly configurable. +//! +//! In a broad sense, there are two avenues in exposing configurability: +//! +//! 1. For *values* that need to be generic, for example `MinTransfer`, we attach them to the +//! `Pallet` struct as fields: +//! +//! ``` +//! struct Pallet { +//! min_transfer: u128, +//! } +//! ``` +//! +//! 2. For *types* that need to be generic, we would have to use generic or associated types, such +//! as: +//! +//! ``` +//! struct Pallet { +//! min_transfer: u128, +//! _marker: std::marker::PhantomData, +//! } +//! ``` +//! +//! Substrate and FRAME, for various reasons (performance, correctness, type safety) has opted to +//! use *types* to declare both *values* and *types* as generic. This is the essence of why the +//! `Get` trait exists. +//! +//! This would bring us to the second iteration of the pallet, which would look like: +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", generic)] +//! +//! In this example, we managed to make all 3 of our types generic. Taking the example of the +//! `AccountId`, one should read the above as following: +//! +//! > The `Pallet` does not know what type `AccountId` concretely is, but it knows that it is +//! > something that adheres to being `From<[u8; 32]>`. +//! +//! This method would work, but it suffers from two downsides: +//! +//! 1. It is verbose, each `impl` block would have to reiterate all of the trait bounds. +//! 2. It cannot easily share/inherit generic types. Imagine multiple pallets wanting to be generic +//! over a single `AccountId`. There is no easy way to express that in this model. +//! +//! Finally, this brings us to using traits and associated types on traits to express the above. +//! Trait associated types have the benefit of: +//! +//! 1. Being less verbose, as in effect they can *group multiple `type`s together*. +//! 2. Can inherit from one another by declaring +//! [supertraits](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html). +//! +//! > Interestingly, one downside of associated types is that declaring defaults on them is not +//! > stable yet. In the meantime, we have built our own custom mechanics around declaring defaults +//! for associated types, see [`pallet_default_config_example`]. +//! +//! The last iteration of our code would look like this: +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", trait_based)] +//! +//! Notice how instead of having multiple generics, everything is generic over a single ``, and all types are fetched through `T`, for example `T::AccountId`, `T::MinTransfer`. +//! +//! Finally, imagine all pallets wanting to be generic over `AccountId`. This can be achieved by +//! having individual `trait Configs` declare a shared `trait SystemConfig` as their +//! [supertrait](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html). +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", with_system)] +//! In FRAME, this shared supertrait is [`frame::prelude::frame_system`]. +//! +//! Notice how this made no difference in the syntax of the rest of the code. `T::AccountId` is +//! still a valid type, since `T` implements `Config` and `Config` implies `SystemConfig`, which +//! has a `type AccountId`. +//! +//! Note, in some instances one would need to use what is known as the fully-qualified-syntax to +//! access a type to help the Rust compiler disambiguate. +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", fully_qualified)] +//! +//! This syntax can sometimes become more complicated when you are dealing with nested traits. +//! Consider the following example, in which we fetch the `type Balance` from another trait +//! `CurrencyTrait`. +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", fully_qualified_complicated)] +//! +//! Notice the final `type BalanceOf` and how it is defined. Using such aliases to shorten the +//! length of fully qualified syntax is a common pattern in FRAME. +//! +//! The above example is almost identical to the well-known (and somewhat notorious) `type +//! BalanceOf` that is often used in the context of [`frame::traits::fungible`]. +#![doc = docify::embed!("../substrate/frame/fast-unstake/src/types.rs", BalanceOf)] +//! +//! ## Additional Resources +//! +//! - +//! - [Substrate Seminar - Traits and Generic Types](https://www.youtube.com/watch?v=6cp10jVWNl4) +//! - +#![allow(unused)] + +use frame::traits::Get; + +#[docify::export] +mod basic { + struct Pallet; + + type AccountId = frame::deps::sp_runtime::AccountId32; + type Balance = u128; + type MinTransfer = frame::traits::ConstU128<10>; + + impl Pallet { + fn transfer(_from: AccountId, _to: AccountId, _amount: Balance) { + todo!() + } + } +} + +#[docify::export] +mod generic { + use super::*; + + struct Pallet { + _marker: std::marker::PhantomData<(AccountId, Balance, MinTransfer)>, + } + + impl Pallet + where + Balance: frame::traits::AtLeast32BitUnsigned, + MinTransfer: frame::traits::Get, + AccountId: From<[u8; 32]>, + { + fn transfer(_from: AccountId, _to: AccountId, amount: Balance) { + assert!(amount >= MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod trait_based { + use super::*; + + trait Config { + type AccountId: From<[u8; 32]>; + type Balance: frame::traits::AtLeast32BitUnsigned; + type MinTransfer: frame::traits::Get; + } + + struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) { + assert!(amount >= T::MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod with_system { + use super::*; + + pub trait SystemConfig { + type AccountId: From<[u8; 32]>; + } + + pub trait Config: SystemConfig { + type Balance: frame::traits::AtLeast32BitUnsigned; + type MinTransfer: frame::traits::Get; + } + + pub struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) { + assert!(amount >= T::MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod fully_qualified { + use super::with_system::*; + + // Simple of using fully qualified syntax. + type AccountIdOf = ::AccountId; +} + +#[docify::export] +mod fully_qualified_complicated { + use super::with_system::*; + + trait CurrencyTrait { + type Balance: frame::traits::AtLeast32BitUnsigned; + fn more_stuff() {} + } + + trait Config: SystemConfig { + type Currency: CurrencyTrait; + } + + struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer( + _from: T::AccountId, + _to: T::AccountId, + _amount: <::Currency as CurrencyTrait>::Balance, + ) { + unimplemented!(); + } + } + + /// A common pattern in FRAME. + type BalanceOf = <::Currency as CurrencyTrait>::Balance; +} diff --git a/developer-hub/src/reference_docs/wasm_memory.rs b/developer-hub/src/reference_docs/wasm_memory.rs new file mode 100644 index 00000000000..4f4cda31094 --- /dev/null +++ b/developer-hub/src/reference_docs/wasm_memory.rs @@ -0,0 +1,7 @@ +//! # WASM Memory Limitations. +//! +//! Notes: +//! +//! - Stack: Need to use `Box<_>` +//! - Heap: Substrate imposes a limit. PvF execution has its own limits +//! - Heap: There is also a maximum amount that a single allocation can have. diff --git a/developer-hub/src/reference_docs/wasm_meta_protocol.rs b/developer-hub/src/reference_docs/wasm_meta_protocol.rs new file mode 100644 index 00000000000..f45f4c8fa3c --- /dev/null +++ b/developer-hub/src/reference_docs/wasm_meta_protocol.rs @@ -0,0 +1,113 @@ +//! # WASM Meta Protocol +//! +//! All Substrate based chains adhere to a unique architectural design novel to the Polkadot +//! ecosystem. We refer to this design as the "WASM Meta Protocol". +//! +//! Consider the fact that a traditional blockchain software is usually a monolithic artifact. +//! Upgrading any part of the system implies upgrading the entire system. This has historically led +//! to cumbersome forkful upgrades to be the status quo in the blockchain ecosystem. +//! +//! Moreover, the idea of "storing code in the state" is explored in the context of smart contracts +//! platforms, but has not been expanded further. +//! +//! Substrate mixes these two ideas together, and takes the novel approach of storing the +//! blockchain's main "state transition function" in the main blockchain state, in the same fashion +//! that a smart contract platform stores the code of individual contracts in its state. As noted in +//! [`crate::reference_docs::blockchain_state_machines`], this state transition function is called +//! the **Runtime**, and WASM is chosen as the bytecode. The Runtime is stored under a special key +//! in the state (see +//! [`sp_core::storage::well_known_keys`](../../../sp_core/index.html)) and can be +//! updated as a part of the state transition function's execution, just like a user's account +//! balance can be updated. +//! +//! > Note that while we drew an analogy between smart contracts and runtimes in the above, there +//! > are fundamental differences between the two, explained in +//! > [`crate::reference_docs::runtime_vs_smart_contract`]. +//! +//! The rest of the system that is NOT the state transition function is called the **node**, and +//! is a normal binary that is compiled from Rust to different hardware targets. +//! +//! This design enables all Substrate-based chains to be fork-less-ly upgradeable, because the +//! Runtime can be updates on the fly, within the execution of a block, and the node is (for the +//! most part) oblivious to the change that is happening. +//! +//! Therefore, the high-level architecture of a any Substrate-based chain can be demonstrated as +//! follows: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_simple.mmd")] +//! +//! The node and the runtime need to communicate. This is done through two concepts: +//! +//! 1. **Host functions**: a way for the (WASM) runtime to talk to the node. All host functions are +//! defined in [`sp_io`]. For example, [`sp_io::storage`] are the set of host functions that +//! allow the runtime to read and write data to the on-chain state. +//! 2. **Runtime APIs**: a way for the node to talk to the WASM runtime. Runtime APIs are defined +//! using macros and utilities in [`sp_api`]. For example, [`sp_api::Core`] is the most +//! fundamental runtime API that any blockchain must implement in order to be able to (re) +//! execute blocks. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_client_runtime.mmd")] +//! +//! A runtime must have a set of runtime APIs in order to have any meaningful blockchain +//! functionality, but it can also expose more APIs. See TODO as an example of how to add custom +//! runtime APIs to your FRAME-based runtime. +//! +//! Similarly, for a runtime to be "compatible" with a node, the node must implement the full set of +//! host functions that the runtime at any point in time requires. Given the fact that a runtime can +//! evolve in time, and a blockchain node (typically) wishes to be capable of re-executing all the +//! previous blocks, this means that a node must always maintain support for the old host functions. +//! This also implies that adding a new host function is a big commitment and should be done with +//! care. This is why, for example, adding a new host function to Polkadot always requires an RFC. +//! +//! ## Node vs. Runtime +//! +//! A common question is: which components of the system end up being part of the node, and which +//! ones of the runtime? +//! +//! Recall from [`crate::reference_docs::blockchain_state_machines`] that the runtime is the state +//! transition function. Anything that needs to influence how your blockchain's state is updated, +//! should be a part of the runtime. For example, the logic around currency, governance, identity or +//! any other application-specific logic that has to do with the state is part of the runtime. +//! +//! Anything that does not have to do with the state-transition function and will only +//! facilitate/enable it is part of the node. For example, the database, networking, and even +//! consensus algorithm are all node-side components. +//! +//! > The consensus is to your runtime what HTTP is to a web-application. It is the underlying +//! > engine that enables trustless execution of the runtime in a distributed manner whilst +//! > maintaining a canonical outcome of that execution. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_with_frame.mmd")] +//! +//! ## State +//! +//! From the previous sections, we know that the a database component is part of the node, not the +//! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime +//! issues commands to the node to read/write to the state. Let's dive deeper into this. +//! +//! The state of the blockchain, what we seek to come to consensus about, is indeed *kept* in the +//! node side. Nonetheless, the runtime is the only component that: +//! +//! 1. Can update the state. +//! 2. Can fully interpret the state. +//! +//! In fact, [`sp_core::storage::well_known_keys`] are the only state keys that the node side is +//! aware of. The rest of the state, including what logic the runtime has, what balance each user +//! has and such are all only comprehensible to the runtime. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/state.mmd")] +//! +//! In the above diagram, all of the state keys and values are opaque bytes to the node. The node +//! does not know what they mean, and it does not now what is the type of the corresponding value +//! (e.g. if it is a number of a vector). Contrary, the runtime knows both the meaning of their +//! keys, and the type of the values. +//! +//! This opaque-ness is the fundamental reason why Substrate-based chains can fork-less-ly upgrade: +//! because the node side code is kept oblivious to all of the details of the state transition +//! function. Therefore, the state transition function can freely upgrade without the node needing +//! to know. +//! +//! ## Native Runtime +//! +//! TODO +//! +//! +//! ## Example: Block Execution. +//! +//! TODO diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd new file mode 100644 index 00000000000..8fcb74fa0a9 --- /dev/null +++ b/docs/mermaid/IA.mmd @@ -0,0 +1,14 @@ +flowchart + parity[paritytech.github.io] --> devhub[developer_hub] + + devhub --> polkadot_sdk + devhub --> reference_docs + devhub --> tutorial + + polkadot_sdk --> substrate + polkadot_sdk --> frame + polkadot_sdk --> cumulus + polkadot_sdk --> polkadot + polkadot_sdk --> xcm + + diff --git a/docs/mermaid/extrinsics.mmd b/docs/mermaid/extrinsics.mmd new file mode 100644 index 00000000000..4afd4ab8f75 --- /dev/null +++ b/docs/mermaid/extrinsics.mmd @@ -0,0 +1,5 @@ +flowchart TD + E(Extrinsic) ---> I(Inherent); + E --> T(Transaction) + T --> ST("Signed (aka. Transaction)") + T --> UT(Unsigned) diff --git a/docs/mermaid/polkadot_sdk_parachain.mmd b/docs/mermaid/polkadot_sdk_parachain.mmd new file mode 100644 index 00000000000..3f38fce046c --- /dev/null +++ b/docs/mermaid/polkadot_sdk_parachain.mmd @@ -0,0 +1,11 @@ +flowchart LR + subgraph Parachain[A Polkadot Parachain] + ParachainNode[Parachain Node] + ParachainRuntime[Parachain Runtime] + end + + FRAME -.-> ParachainRuntime + Substrate[Substrate Node Libraries] -.-> ParachainNoe + + CumulusC[Cumulus Node Libraries] -.-> ParachainNode + CumulusR[Cumulus Runtime Libraries] -.-> ParachainRuntime diff --git a/docs/mermaid/polkadot_sdk_polkadot.mmd b/docs/mermaid/polkadot_sdk_polkadot.mmd new file mode 100644 index 00000000000..3326cc59383 --- /dev/null +++ b/docs/mermaid/polkadot_sdk_polkadot.mmd @@ -0,0 +1,10 @@ +flowchart LR + + subgraph Polkadot[The Polkadot Relay Chain] + PolkadotNode[Polkadot Node] + PolkadotRuntime[Polkadot Runtime] + end + + FRAME -.-> PolkadotRuntime + Substrate[Substrate Node Libraries] -.-> PolkadotNode + diff --git a/docs/mermaid/polkadot_sdk_substrate.mmd b/docs/mermaid/polkadot_sdk_substrate.mmd new file mode 100644 index 00000000000..dfaf20d241f --- /dev/null +++ b/docs/mermaid/polkadot_sdk_substrate.mmd @@ -0,0 +1,8 @@ +flowchart LR + subgraph SubstrateChain[A Substrate-based blockchain] + Node + Runtime + end + + FRAME -.-> Runtime + Substrate[Substrate Node Libraries] -.-> Node diff --git a/docs/mermaid/state.mmd b/docs/mermaid/state.mmd new file mode 100644 index 00000000000..c72ecbfd156 --- /dev/null +++ b/docs/mermaid/state.mmd @@ -0,0 +1,16 @@ +flowchart TB + subgraph Node[Node's View Of The State 🙈] + direction LR + 0x1234 --> 0x2345 + 0x3456 --> 0x4567 + 0x5678 --> 0x6789 + :code --> code[wasm code] + end + + subgraph Runtime[Runtime's View Of The State 🙉] + direction LR + ab[alice's balance] --> abv[known value] + bb[bob's balance] --> bbv[known value] + cb[charlie's balance] --> cbv[known value] + c2[:code] --> c22[wasm code] + end diff --git a/docs/mermaid/stf.mmd b/docs/mermaid/stf.mmd new file mode 100644 index 00000000000..dd6c7c36de6 --- /dev/null +++ b/docs/mermaid/stf.mmd @@ -0,0 +1,21 @@ +flowchart LR + %%{init: {'flowchart' : {'curve' : 'linear'}}}%% + subgraph BData[Blockchain Database] + direction LR + BN[Block N] -.-> BN1[Block N+1] + end + + subgraph SData[State Database] + direction LR + SN[State N] -.-> SN1[State N+1] -.-> SN2[State N+2] + end + + BN --> STFN[STF] + SN --> STFN[STF] + STFN[STF] --> SN1 + + BN1 --> STFN1[STF] + SN1 --> STFN1[STF] + STFN1[STF] --> SN2 + + diff --git a/docs/mermaid/stf_simple.mmd b/docs/mermaid/stf_simple.mmd new file mode 100644 index 00000000000..5db20cf6156 --- /dev/null +++ b/docs/mermaid/stf_simple.mmd @@ -0,0 +1,4 @@ +flowchart LR + B[Block] --> STF + S[State] --> STF + STF --> NS[New State] diff --git a/docs/mermaid/substrate_client_runtime.mmd b/docs/mermaid/substrate_client_runtime.mmd index 23c3f849224..caab2b62302 100644 --- a/docs/mermaid/substrate_client_runtime.mmd +++ b/docs/mermaid/substrate_client_runtime.mmd @@ -1,10 +1,12 @@ graph TB subgraph Substrate direction LR - subgraph Client + subgraph Node end + subgraph Runtime end - Client --runtime-api--> Runtime - Runtime --host-functions--> Client + + Node --runtime-api--> Runtime + Runtime --host-functions--> Node end diff --git a/docs/mermaid/substrate_dev.mmd b/docs/mermaid/substrate_dev.mmd new file mode 100644 index 00000000000..fc331ce311f --- /dev/null +++ b/docs/mermaid/substrate_dev.mmd @@ -0,0 +1,2 @@ +flowchart LR + T[Using a Template] --> P[Writing Your Own FRAME-Based Pallet] --> C[Custom Node] diff --git a/docs/mermaid/substrate_simple.mmd b/docs/mermaid/substrate_simple.mmd index 475d8be5ef8..a752eaba625 100644 --- a/docs/mermaid/substrate_simple.mmd +++ b/docs/mermaid/substrate_simple.mmd @@ -1,7 +1,7 @@ graph TB subgraph Substrate direction LR - subgraph Client + subgraph Node end subgraph Runtime end diff --git a/docs/mermaid/substrate_with_frame.mmd b/docs/mermaid/substrate_with_frame.mmd index 12d072a3360..173c1757b95 100644 --- a/docs/mermaid/substrate_with_frame.mmd +++ b/docs/mermaid/substrate_with_frame.mmd @@ -1,7 +1,7 @@ graph TB subgraph Substrate direction LR - subgraph Client + subgraph Node Database Networking Consensus @@ -15,6 +15,6 @@ subgraph Substrate Identity end end - Client --runtime-api--> Runtime - Runtime --host-functions--> Client + Node --runtime-api--> Runtime + Runtime --host-functions--> Node end diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index 96f7adeb29b..2df3021343d 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -248,8 +248,8 @@ impl Protocol { name, fallback_names, max_request_size: 1_000, - /// Responses are just confirmation, in essence not even a bit. So 100 seems - /// plenty. + // Responses are just confirmation, in essence not even a bit. So 100 seems + // plenty. max_response_size: 100, request_timeout: DISPUTE_REQUEST_TIMEOUT, inbound_queue: tx, diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index dab72bb2a5e..be62145b999 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -442,7 +442,7 @@ pub struct CollationSecondedSignal { pub relay_parent: Hash, /// The statement about seconding the collation. /// - /// Anything else than [`Statement::Seconded`](Statement::Seconded) is forbidden here. + /// Anything else than [`Statement::Seconded`] is forbidden here. pub statement: SignedFullStatement, } diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml deleted file mode 100644 index 8fb1be5821b..00000000000 --- a/substrate/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[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" -publish = false - -# The dependencies are only needed for docs. -[dependencies] -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } - -subkey = { path = "bin/utils/subkey" } -chain-spec-builder = { package = "staging-chain-spec-builder", path = "bin/utils/chain-spec-builder" } - -sc-service = { path = "client/service" } -sc-chain-spec = { path = "client/chain-spec" } -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/client/allocator/src/lib.rs b/substrate/client/allocator/src/lib.rs index e50d7d54c8e..70ed764bef8 100644 --- a/substrate/client/allocator/src/lib.rs +++ b/substrate/client/allocator/src/lib.rs @@ -18,7 +18,7 @@ //! Collection of allocator implementations. //! //! This crate provides the following allocator implementations: -//! - A freeing-bump allocator: [`FreeingBumpHeapAllocator`](freeing_bump::FreeingBumpHeapAllocator) +//! - A freeing-bump allocator: [`FreeingBumpHeapAllocator`] #![warn(missing_docs)] diff --git a/substrate/client/executor/src/lib.rs b/substrate/client/executor/src/lib.rs index 6ee0ab3512a..25bad81938f 100644 --- a/substrate/client/executor/src/lib.rs +++ b/substrate/client/executor/src/lib.rs @@ -58,7 +58,7 @@ pub use sc_executor_wasmtime::InstantiationStrategy as WasmtimeInstantiationStra /// Extracts the runtime version of a given runtime code. pub trait RuntimeVersionOf { - /// Extract [`RuntimeVersion`](sp_version::RuntimeVersion) of the given `runtime_code`. + /// Extract [`RuntimeVersion`] of the given `runtime_code`. fn runtime_version( &self, ext: &mut dyn Externalities, diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index d518f933df8..843bc351494 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -49,8 +49,7 @@ //! - **Total Issuance:** The total number of units in existence in a system. //! //! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after -//! its -//! total balance has become zero (or, strictly speaking, less than the Existential Deposit). +//! its total balance has become zero (or, strictly speaking, less than the Existential Deposit). //! //! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only //! balance that matters for most operations. @@ -59,24 +58,23 @@ //! Reserved balance can still be slashed, but only after all the free balance has been slashed. //! //! - **Imbalance:** A condition when some funds were credited or debited without equal and opposite -//! accounting -//! (i.e. a difference between total issuance and account balances). Functions that result in an -//! imbalance will return an object of the `Imbalance` trait that can be managed within your runtime -//! logic. (If an imbalance is simply dropped, it should automatically maintain any book-keeping -//! such as total issuance.) +//! accounting (i.e. a difference between total issuance and account balances). Functions that +//! result in an imbalance will return an object of the `Imbalance` trait that can be managed within +//! your runtime logic. (If an imbalance is simply dropped, it should automatically maintain any +//! book-keeping such as total issuance.) //! //! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block -//! number. Multiple -//! locks always operate over the same funds, so they "overlay" rather than "stack". +//! number. Multiple locks always operate over the same funds, so they "overlay" rather than +//! "stack". //! //! ### Implementations //! //! The Balances pallet provides implementations for the following traits. If these traits provide //! the functionality that you need, then you can avoid coupling with the Balances pallet. //! -//! - [`Currency`](frame_support::traits::Currency): Functions for dealing with a +//! - [`Currency`]: Functions for dealing with a //! fungible assets system. -//! - [`ReservableCurrency`](frame_support::traits::ReservableCurrency): +//! - [`ReservableCurrency`] //! - [`NamedReservableCurrency`](frame_support::traits::NamedReservableCurrency): //! Functions for dealing with assets that can be reserved from an account. //! - [`LockableCurrency`](frame_support::traits::LockableCurrency): Functions for @@ -105,7 +103,7 @@ //! ``` //! use frame_support::traits::Currency; //! # pub trait Config: frame_system::Config { -//! # type Currency: Currency; +//! # type Currency: Currency; //! # } //! //! pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -120,26 +118,26 @@ //! use frame_support::traits::{WithdrawReasons, LockableCurrency}; //! use sp_runtime::traits::Bounded; //! pub trait Config: frame_system::Config { -//! type Currency: LockableCurrency>; +//! type Currency: LockableCurrency>; //! } //! # struct StakingLedger { -//! # stash: ::AccountId, -//! # total: <::Currency as frame_support::traits::Currency<::AccountId>>::Balance, -//! # phantom: std::marker::PhantomData, +//! # stash: ::AccountId, +//! # total: <::Currency as frame_support::traits::Currency<::AccountId>>::Balance, +//! # phantom: std::marker::PhantomData, //! # } //! # const STAKING_ID: [u8; 8] = *b"staking "; //! //! fn update_ledger( -//! controller: &T::AccountId, -//! ledger: &StakingLedger +//! controller: &T::AccountId, +//! ledger: &StakingLedger //! ) { -//! T::Currency::set_lock( -//! STAKING_ID, -//! &ledger.stash, -//! ledger.total, -//! WithdrawReasons::all() -//! ); -//! // >::insert(controller, ledger); // Commented out as we don't have access to Staking's storage here. +//! T::Currency::set_lock( +//! STAKING_ID, +//! &ledger.stash, +//! ledger.total, +//! WithdrawReasons::all() +//! ); +//! // >::insert(controller, ledger); // Commented out as we don't have access to Staking's storage here. //! } //! # fn main() {} //! ``` diff --git a/substrate/frame/bounties/src/migrations/v4.rs b/substrate/frame/bounties/src/migrations/v4.rs index 936bac11700..4e6ba934481 100644 --- a/substrate/frame/bounties/src/migrations/v4.rs +++ b/substrate/frame/bounties/src/migrations/v4.rs @@ -110,7 +110,7 @@ pub fn migrate< } /// Some checks prior to migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::pre_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn pre_migration>( @@ -164,7 +164,7 @@ pub fn pre_migration>( diff --git a/substrate/frame/collective/src/migrations/v4.rs b/substrate/frame/collective/src/migrations/v4.rs index b3326b4251c..300dff23d8e 100644 --- a/substrate/frame/collective/src/migrations/v4.rs +++ b/substrate/frame/collective/src/migrations/v4.rs @@ -76,7 +76,7 @@ pub fn migrate>(old_pallet_name: N) { @@ -104,7 +104,7 @@ pub fn pre_migrate>(old_p } /// Some checks for after migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn post_migrate>(old_pallet_name: N) { diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 15a50165ff3..7bdd329d9b0 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -80,11 +80,7 @@ frame_election_provider_support::generate_solution_type!( /// All events of this pallet. pub(crate) fn multi_phase_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::MultiPhase(inner) = e { Some(inner) } else { None }) - .collect::>() + System::read_events_for_pallet::>() } /// To from `now` to block `n`. diff --git a/substrate/frame/elections-phragmen/src/migrations/v4.rs b/substrate/frame/elections-phragmen/src/migrations/v4.rs index 7e946371f5c..e78465cd618 100644 --- a/substrate/frame/elections-phragmen/src/migrations/v4.rs +++ b/substrate/frame/elections-phragmen/src/migrations/v4.rs @@ -69,7 +69,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { } /// Some checks prior to migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::pre_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn pre_migration>(new: N) { @@ -97,7 +97,7 @@ pub fn pre_migration>(new: N) { } /// Some checks for after migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn post_migration() { diff --git a/substrate/frame/elections-phragmen/src/migrations/v5.rs b/substrate/frame/elections-phragmen/src/migrations/v5.rs index 6fac923703f..6e360aa8b8c 100644 --- a/substrate/frame/elections-phragmen/src/migrations/v5.rs +++ b/substrate/frame/elections-phragmen/src/migrations/v5.rs @@ -71,7 +71,7 @@ pub fn pre_migrate_fn(to_migrate: Vec) -> Box() { diff --git a/substrate/frame/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 89759dd0bf6..18429bc967d 100644 --- a/substrate/frame/examples/kitchensink/src/lib.rs +++ b/substrate/frame/examples/kitchensink/src/lib.rs @@ -292,9 +292,8 @@ pub mod pallet { } } - /// Allows you to define an enum on the pallet which will then instruct - /// `construct_runtime` to amalgamate all similarly-named enums from other - /// pallets into an aggregate enum. + /// Allows you to define an enum on the pallet which will then instruct `construct_runtime` to + /// amalgamate all similarly-named enums from other pallets into an aggregate enum. #[pallet::composite_enum] pub enum HoldReason { Staking, diff --git a/substrate/frame/fast-unstake/src/types.rs b/substrate/frame/fast-unstake/src/types.rs index 15d0a327e91..3fb5720861f 100644 --- a/substrate/frame/fast-unstake/src/types.rs +++ b/substrate/frame/fast-unstake/src/types.rs @@ -39,6 +39,7 @@ impl frame_support::traits::Get for MaxChecking { } } +#[docify::export] pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; /// An unstake request. diff --git a/substrate/frame/grandpa/src/migrations/v4.rs b/substrate/frame/grandpa/src/migrations/v4.rs index 8604296b6e5..9daa818071f 100644 --- a/substrate/frame/grandpa/src/migrations/v4.rs +++ b/substrate/frame/grandpa/src/migrations/v4.rs @@ -63,7 +63,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { } /// Some checks prior to migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::pre_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn pre_migration>(new: N) { @@ -99,7 +99,7 @@ pub fn pre_migration>(new: N) { } /// Some checks for after migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn post_migration() { diff --git a/substrate/frame/membership/src/migrations/v4.rs b/substrate/frame/membership/src/migrations/v4.rs index 38e97af51a0..9b80aca8684 100644 --- a/substrate/frame/membership/src/migrations/v4.rs +++ b/substrate/frame/membership/src/migrations/v4.rs @@ -77,7 +77,7 @@ pub fn migrate>(old_pallet_name: N, new_pallet_name: N) { @@ -105,7 +105,7 @@ pub fn pre_migrate>(old_pallet_name: N, new_ } /// Some checks for after migration. This can be linked to -/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// `frame_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing. /// /// Panics if anything goes wrong. pub fn post_migrate>(old_pallet_name: N, new_pallet_name: N) { diff --git a/substrate/frame/session/src/historical/offchain.rs b/substrate/frame/session/src/historical/offchain.rs index 1b4d53b74b4..95f4d762949 100644 --- a/substrate/frame/session/src/historical/offchain.rs +++ b/substrate/frame/session/src/historical/offchain.rs @@ -17,13 +17,11 @@ //! Off-chain logic for creating a proof based data provided by on-chain logic. //! -//! Validator-set extracting an iterator from an off-chain worker stored list containing -//! historical validator-sets. -//! Based on the logic of historical slashing, but the validation is done off-chain. +//! Validator-set extracting an iterator from an off-chain worker stored list containing historical +//! validator-sets. Based on the logic of historical slashing, but the validation is done off-chain. //! Use [`fn store_current_session_validator_set_to_offchain()`](super::onchain) to store the -//! required data to the offchain validator set. -//! This is used in conjunction with [`ProvingTrie`](super::ProvingTrie) and -//! the off-chain indexing API. +//! required data to the offchain validator set. This is used in conjunction with [`ProvingTrie`] +//! and the off-chain indexing API. use sp_runtime::{ offchain::storage::{MutateStorageError, StorageRetrievalError, StorageValueRef}, diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 1a8350405a8..59cd9237888 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -15,10 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! > Made for [![polkadot]](https://polkadot.network) -//! -//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white -//! //! # FRAME //! //! ```no_compile @@ -34,14 +30,21 @@ //! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's //! > State Transition Function (Runtime) Framework. //! +//! ## Documentation +//! +//! See [`polkadot_sdk::frame`](../developer_hub/polkadot_sdk/frame_runtime/index.html). +//! //! ## Warning: Experimental //! //! This crate and all of its content is experimental, and should not yet be used in production. //! -//! ## Getting Started +//! ## Underlying dependencies //! -//! TODO: link to `developer_hub::polkadot_sdk::frame`. The `developer_hub` hasn't been published -//! yet, this can be updated once it is linkable. +//! This crate is an amalgamation of multiple other crates that are often used together to compose a +//! pallet. It is not necessary to use it, and it may fall short for certain purposes. +//! +//! In short, this crate only re-exports types and traits from multiple sources. All of these +//! sources are listed (and re-exported again) in [`deps`]. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] @@ -54,9 +57,19 @@ /// `#[pallet::bar]` inside the mod. pub use frame_support::pallet; +pub use frame_support::pallet_macros::{import_section, pallet_section}; + /// The logging library of the runtime. Can normally be the classic `log` crate. pub use log; +/// A list of all macros used within the main [`pallet`] macro. +/// +/// Note: All of these macros are "stubs" and not really usable outside `#[pallet] mod pallet { .. +/// }`. They are mainly provided for documentation and IDE support. +pub mod pallet_macros { + pub use frame_support::{derive_impl, pallet, pallet_macros::*}; +} + /// The main prelude of FRAME. /// /// This prelude should almost always be the first line of code in any pallet or runtime. @@ -78,9 +91,6 @@ pub mod prelude { /// Pallet prelude of `frame-support`. /// /// Note: this needs to revised once `frame-support` evolves. - // `frame-support` will be break down https://github.com/paritytech/polkadot-sdk/issues/127 and its reexports will - // most likely change. These wildcard reexportings can be optimized once `frame-support` has - // changed. #[doc(no_inline)] pub use frame_support::pallet_prelude::*; @@ -156,6 +166,9 @@ pub mod runtime { /// Types to define your runtime version. pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; + /// Macro to implement runtime APIs. + pub use sp_api::impl_runtime_apis; + #[cfg(feature = "std")] pub use sp_version::NativeVersion; } @@ -180,9 +193,6 @@ pub mod runtime { pub use sp_inherents::{CheckInherentsResult, InherentData}; pub use sp_runtime::ApplyExtrinsicResult; - /// Macro to implement runtime APIs. - pub use sp_api::impl_runtime_apis; - pub use frame_system_rpc_runtime_api::*; pub use sp_api::{self, *}; pub use sp_block_builder::*; diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index ec411891885..682b135fa14 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1097,8 +1097,11 @@ pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must -/// return a `DispatchResultWithPostInfo` or `DispatchResult`. +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). #[proc_macro_attribute] pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1108,7 +1111,7 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { /// --- /// /// **Rust-Analyzer users**: See the documentation of the Rust item in -/// `frame_support::pallet_macros::call`. +/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). #[proc_macro_attribute] pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1117,41 +1120,10 @@ pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { /// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, /// which explicitly defines the codec index for the dispatchable function in the `Call` enum. /// -/// All call indexes start from 0, until it encounters a dispatchable function with a defined -/// call index. The dispatchable function that lexically follows the function with a defined -/// call index will have that call index, but incremented by 1, e.g. if there are 3 -/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` -/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. -/// -/// All arguments must implement [`Debug`], [`PartialEq`], [`Eq`], `Decode`, `Encode`, and -/// [`Clone`]. For ease of use, bound by the trait `frame_support::pallet_prelude::Member`. -/// -/// If no `#[pallet::call]` exists, then a default implementation corresponding to the -/// following code is automatically generated: -/// -/// ```ignore -/// #[pallet::call] -/// impl Pallet {} -/// ``` -/// -/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be -/// done with care. Indeed this will change the outer runtime call type (which is an enum with -/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the -/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so -/// that the `Call` enum encoding does not change after modification. As a general rule of -/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain -/// the existing order of calls. -/// -/// ### Macro expansion -/// -/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: -/// [`Clone`], [`Eq`], [`PartialEq`], [`Debug`] (with stripped implementation in `not("std")`), -/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `GetCallIndex` and -/// `UnfilteredDispatchable`. +/// --- /// -/// The macro implements the `Callable` trait on `Pallet` and a function `call_functions` -/// which returns the dispatchable metadata. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). #[proc_macro_attribute] pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 519e1e61895..f78f2baa9d1 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -26,6 +26,7 @@ use syn::{spanned::Spanned, ExprClosure}; mod keyword { syn::custom_keyword!(Call); syn::custom_keyword!(OriginFor); + syn::custom_keyword!(RuntimeOrigin); syn::custom_keyword!(weight); syn::custom_keyword!(call_index); syn::custom_keyword!(compact); @@ -158,10 +159,10 @@ impl syn::parse::Parse for ArgAttrIsCompact { } } -/// Check the syntax is `OriginFor` or `&OriginFor`. +/// Check the syntax is `OriginFor`, `&OriginFor` or `T::RuntimeOrigin`. pub fn check_dispatchable_first_arg_type(ty: &syn::Type, is_ref: bool) -> syn::Result<()> { - pub struct CheckDispatchableFirstArg(bool); - impl syn::parse::Parse for CheckDispatchableFirstArg { + pub struct CheckOriginFor(bool); + impl syn::parse::Parse for CheckOriginFor { fn parse(input: syn::parse::ParseStream) -> syn::Result { let is_ref = input.parse::().is_ok(); input.parse::()?; @@ -173,14 +174,27 @@ pub fn check_dispatchable_first_arg_type(ty: &syn::Type, is_ref: bool) -> syn::R } } - let result = syn::parse2::(ty.to_token_stream()); - return match result { - Ok(CheckDispatchableFirstArg(has_ref)) if is_ref == has_ref => Ok(()), - _ => { + pub struct CheckRuntimeOrigin; + impl syn::parse::Parse for CheckRuntimeOrigin { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + input.parse::()?; + input.parse::()?; + + Ok(Self) + } + } + + let result_origin_for = syn::parse2::(ty.to_token_stream()); + let result_runtime_origin = syn::parse2::(ty.to_token_stream()); + return match (result_origin_for, result_runtime_origin) { + (Ok(CheckOriginFor(has_ref)), _) if is_ref == has_ref => Ok(()), + (_, Ok(_)) => Ok(()), + (_, _) => { let msg = if is_ref { "Invalid type: expected `&OriginFor`" } else { - "Invalid type: expected `OriginFor`" + "Invalid type: expected `OriginFor` or `T::RuntimeOrigin`" }; return Err(syn::Error::new(ty.span(), msg)) }, @@ -282,8 +296,8 @@ impl CallDef { 0 if dev_mode => CallWeightDef::DevModeDefault, 0 => return Err(syn::Error::new( method.sig.span(), - "A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an - inherited weight from the `#[pallet:call(weight($type))]` attribute, but + "A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an + inherited weight from the `#[pallet:call(weight($type))]` attribute, but none were given.", )), 1 => match weight_attrs.pop().unwrap() { diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index e57227f9b40..c81dba12766 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -36,7 +36,8 @@ use sp_weights::Weight; /// returned from a dispatch. pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo; -/// Unaugmented version of `DispatchResultWithPostInfo` that can be returned from +#[docify::export] +/// Un-augmented version of `DispatchResultWithPostInfo` that can be returned from /// dispatchable functions and is automatically converted to the augmented type. Should be /// used whenever the `PostDispatchInfo` does not need to be overwritten. As this should /// be the common case it is the implicit return type when none is specified. diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 2ec3b24db0c..fd348f62b4f 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -47,6 +47,8 @@ pub mod __private { pub use sp_core::{OpaqueMetadata, Void}; pub use sp_core_hashing_proc_macro; pub use sp_inherents; + #[cfg(feature = "std")] + pub use sp_io::TestExternalities; pub use sp_io::{self, hashing, storage::root as storage_root}; pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] @@ -2226,13 +2228,159 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros pub mod pallet_macros { pub use frame_support_procedural::{ - call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error, - event, extra_constants, feeless_if, generate_deposit, generate_store, getter, hooks, + composite_enum, config, disable_frame_system_supertrait_check, error, event, + extra_constants, feeless_if, generate_deposit, generate_store, getter, hooks, import_section, inherent, no_default, no_default_bounds, origin, pallet_section, storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; + /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. In + /// slightly simplified terms, this macro declares the set of "transactions" of a pallet. + /// + /// > The exact definition of **extrinsic** can be found in + /// > [`sp_runtime::generic::UncheckedExtrinsic`]. + /// + /// A **dispatchable** is a common term in FRAME, referring to process of constructing a + /// function, and dispatching it with the correct inputs. This is commonly used with + /// extrinsics, for example "an extrinsic has been dispatched". See + /// [`sp_runtime::traits::Dispatchable`] and [`crate::traits::UnfilteredDispatchable`]. + /// + /// ## Call Enum + /// + /// The macro is called `call` (rather than `#[pallet::extrinsics]`) because of the + /// generation of a `enum Call`. This enum contains only the encoding of the function + /// arguments of the dispatchable, alongside the information needed to route it to the + /// correct function. + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// pub mod custom_pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::BuildGenesisConfig; + /// #[pallet::call] + /// impl Pallet { + /// pub fn some_dispatchable(_origin: OriginFor, _input: u32) -> DispatchResult { + /// Ok(()) + /// } + /// pub fn other(_origin: OriginFor, _input: u64) -> DispatchResult { + /// Ok(()) + /// } + /// } + /// + /// // generates something like: + /// // enum Call { + /// // some_dispatchable { input: u32 } + /// // other { input: u64 } + /// // } + /// } + /// + /// fn main() { + /// # use frame_support::{derive_impl, construct_runtime}; + /// # use frame_support::__private::codec::Encode; + /// # use frame_support::__private::TestExternalities; + /// # use frame_support::traits::UnfilteredDispatchable; + /// # impl custom_pallet::Config for Runtime {} + /// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + /// # impl frame_system::Config for Runtime { + /// # type Block = frame_system::mocking::MockBlock; + /// # } + /// construct_runtime! { + /// pub struct Runtime { + /// System: frame_system, + /// Custom: custom_pallet + /// } + /// } + /// + /// # TestExternalities::new_empty().execute_with(|| { + /// let origin: RuntimeOrigin = frame_system::RawOrigin::Signed(10).into(); + /// // calling into a dispatchable from within the runtime is simply a function call. + /// let _ = custom_pallet::Pallet::::some_dispatchable(origin.clone(), 10); + /// + /// // calling into a dispatchable from the outer world involves constructing the bytes of + /// let call = custom_pallet::Call::::some_dispatchable { input: 10 }; + /// let _ = call.clone().dispatch_bypass_filter(origin); + /// + /// // the routing of a dispatchable is simply done through encoding of the `Call` enum, + /// // which is the index of the variant, followed by the arguments. + /// assert_eq!(call.encode(), vec![0u8, 10, 0, 0, 0]); + /// + /// // notice how in the encoding of the second function, the first byte is different and + /// // referring to the second variant of `enum Call`. + /// let call = custom_pallet::Call::::other { input: 10 }; + /// assert_eq!(call.encode(), vec![1u8, 10, 0, 0, 0, 0, 0, 0, 0]); + /// # }); + /// } + /// ``` + /// + /// Further properties of dispatchable functions are as follows: + /// + /// - Unless if annotated by `dev_mode`, it must contain [`weight`] to denote the + /// pre-dispatch weight consumed. + /// - The dispatchable must declare its index via [`call_index`], which can override the + /// position of a function in `enum Call`. + /// - The first argument is always an `OriginFor` (or `T::RuntimeOrigin`). + /// - The return type is always [`crate::dispatch::DispatchResult`] (or + /// [`crate::dispatch::DispatchResultWithPostInfo`]). + /// + /// **WARNING**: modifying dispatchables, changing their order (i.e. using [`call_index`]), + /// removing some, etc., must be done with care. This will change the encoding of the , and + /// the call can be stored on-chain (e.g. in `pallet-scheduler`). Thus, migration might be + /// needed. This is why the use of `call_index` is mandatory by default in FRAME. + /// + /// ## Default Behavior + /// + /// If no `#[pallet::call]` exists, then a default implementation corresponding to the + /// following code is automatically generated: + /// + /// ```ignore + /// #[pallet::call] + /// impl Pallet {} + /// ``` + pub use frame_support_procedural::call; + + /// Enforce the index of a variant in the generated `enum Call`. See [`call`] for more + /// information. + /// + /// All call indexes start from 0, until it encounters a dispatchable function with a + /// defined call index. The dispatchable function that lexically follows the function with + /// a defined call index will have that call index, but incremented by 1, e.g. if there are + /// 3 dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn + /// bar` has a call index of 10, then `fn qux` will have an index of 11, instead of 1. + pub use frame_support_procedural::call_index; + + /// Declares the arguments of a [`call`] function to be encoded using + /// [`codec::Compact`]. This will results in smaller extrinsic encoding. + /// + /// A common example of `compact` is for numeric values that are often times far far away + /// from their theoretical maximum. For example, in the context of a crypto-currency, the + /// balance of an individual account is oftentimes way less than what the numeric type + /// allows. In all such cases, using `compact` is sensible. + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// pub mod custom_pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::BuildGenesisConfig; + /// #[pallet::call] + /// impl Pallet { + /// pub fn some_dispatchable(_origin: OriginFor, #[pallet::compact] _input: u32) -> DispatchResult { + /// Ok(()) + /// } + /// } + /// } + pub use frame_support_procedural::compact; + /// 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 diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index a9eb460421f..bfd62c8611c 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -224,8 +224,7 @@ impl PalletVersionToStorageVersionHelper for T { } } -/// Migrate from the `PalletVersion` struct to the new -/// [`StorageVersion`](crate::traits::StorageVersion) struct. +/// Migrate from the `PalletVersion` struct to the new [`StorageVersion`] struct. /// /// This will remove all `PalletVersion's` from the state and insert the current storage version. pub fn migrate_from_pallet_version_to_storage_version< diff --git a/substrate/frame/support/src/storage/child.rs b/substrate/frame/support/src/storage/child.rs index e54002d18db..76e6f4ee402 100644 --- a/substrate/frame/support/src/storage/child.rs +++ b/substrate/frame/support/src/storage/child.rs @@ -165,9 +165,9 @@ pub fn kill_storage(child_info: &ChildInfo, limit: Option) -> KillStorageRe /// guarantee that the subsequent call is in a new block; in this case the previous call's result /// cursor need not be passed in an a `None` may be passed instead. This exception may be useful /// then making this call solely from a block-hook such as `on_initialize`. -/// -/// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once the -/// resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + +/// Returns [`MultiRemovalResults`] to inform about the result. Once the resultant `maybe_cursor` +/// field is `None`, then no further items remain to be deleted. /// /// NOTE: After the initial call for any given child storage, it is important that no keys further /// keys are inserted. If so, then they may or may not be deleted by subsequent calls. diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index 7f39a3fdad8..c77de1f976f 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -1583,7 +1583,7 @@ pub trait StorageTryAppend: StorageDecodeLength + private::Sealed { fn bound() -> usize; } -/// Storage value that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage value that is capable of [`StorageTryAppend`]. pub trait TryAppendValue, I: Encode> { /// Try and append the `item` into the storage item. /// @@ -1612,7 +1612,7 @@ where } } -/// Storage map that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage map that is capable of [`StorageTryAppend`]. pub trait TryAppendMap, I: Encode> { /// Try and append the `item` into the storage map at the given `key`. /// @@ -1646,7 +1646,7 @@ where } } -/// Storage double map that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage double map that is capable of [`StorageTryAppend`]. pub trait TryAppendDoubleMap, I: Encode> { /// Try and append the `item` into the storage double map at the given `key`. /// 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 08954bb6ab5..a791c313b4a 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 @@ -97,7 +97,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -129,7 +129,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` @@ -301,7 +301,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -334,7 +334,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr index c04729a2438..1f814eaa407 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr @@ -1,4 +1,4 @@ -error: Invalid type: expected `OriginFor` +error: Invalid type: expected `OriginFor` or `T::RuntimeOrigin` --> tests/pallet_ui/call_invalid_origin_type.rs:34:22 | 34 | pub fn foo(origin: u8) {} diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index b61b4d531e2..8f7e0052fe0 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false, feat sp-std = { path = "../../primitives/std", default-features = false} sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } -docify = "0.2.0" +docify = "0.2.6" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 1b8dd6a9367..15dd047fdb0 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -1018,6 +1018,7 @@ impl_ensure_origin_with_arg_ignoring_arg! { {} } +#[docify::export] /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed(o: OuterOrigin) -> Result @@ -1372,6 +1373,7 @@ impl Pallet { /// NOTE: Events not registered at the genesis block and quietly omitted. pub fn deposit_event_indexed(topics: &[T::Hash], event: T::RuntimeEvent) { let block_number = Self::block_number(); + // Don't populate events on genesis. if block_number.is_zero() { return @@ -1555,12 +1557,7 @@ impl Pallet { /// NOTE: Events not registered at the genesis block and quietly omitted. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn events() -> Vec> { - debug_assert!( - !Self::block_number().is_zero(), - "events not registered at the genesis block" - ); - // Dereferencing the events here is fine since we are not in the - // memory-restricted runtime. + // Dereferencing the events here is fine since we are not in the memory-restricted runtime. Self::read_events_no_consensus().map(|e| *e).collect() } @@ -1581,6 +1578,21 @@ impl Pallet { Events::::stream_iter() } + /// Read and return the events of a specific pallet, as denoted by `E`. + /// + /// This is useful for a pallet that wishes to read only the events it has deposited into + /// `frame_system` using the standard `fn deposit_event`. + pub fn read_events_for_pallet() -> Vec + where + T::RuntimeEvent: TryInto, + { + Events::::get() + .into_iter() + .map(|er| er.event) + .filter_map(|e| e.try_into().ok()) + .collect::<_>() + } + /// Set the block number to something in particular. Can be used as an alternative to /// `initialize` for tests that don't need to bother with the other environment entries. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] diff --git a/substrate/frame/tips/src/migrations/v4.rs b/substrate/frame/tips/src/migrations/v4.rs index 35569633d1b..2404c6de1a1 100644 --- a/substrate/frame/tips/src/migrations/v4.rs +++ b/substrate/frame/tips/src/migrations/v4.rs @@ -90,7 +90,7 @@ pub fn migrate { /// Who this purports to be from and the number of extrinsics have come before diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 1cdc0b8e405..6ac381babee 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -43,16 +43,37 @@ const EXTRINSIC_FORMAT_VERSION: u8 = 4; /// The `SingaturePayload` of `UncheckedExtrinsic`. type UncheckedSignaturePayload = (Address, Signature, Extra); -/// A extrinsic right from the external world. This is unchecked and so -/// can contain a signature. +/// An extrinsic right from the external world. This is unchecked and so can contain a signature. +/// +/// An extrinsic is formally described as any external data that is originating from the outside of +/// the runtime and fed into the runtime as a part of the block-body. +/// +/// Inherents are special types of extrinsics that are placed into the block by the block-builder. +/// They are unsigned because the assertion is that they are "inherently true" by virtue of getting +/// past all validators. +/// +/// Transactions are all other statements provided by external entities that the chain deems values +/// and decided to include in the block. This value is typically in the form of fee payment, but it +/// could in principle be any other interaction. Transactions are either signed or unsigned. A +/// sensible transaction pool should ensure that only transactions that are worthwhile are +/// considered for block-building. +#[doc = simple_mermaid::mermaid!("../../../../../docs/mermaid/extrinsics.mmd")] +/// This type is by no means enforced within Substrate, but given its genericness, it is highly +/// likely that for most use-cases it will suffice. Thus, the encoding of this type will dictate +/// exactly what bytes should be sent to a runtime to transact with it. +/// +/// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the +/// counterpart of this type after its signature (and other non-negotiable validity checks) have +/// passed. #[derive(PartialEq, Eq, Clone)] pub struct UncheckedExtrinsic where Extra: SignedExtension, { - /// The signature, address, number of extrinsics have come before from - /// the same signer and an era describing the longevity of this transaction, - /// if this is a signed extrinsic. + /// The signature, address, number of extrinsics have come before from the same signer and an + /// era describing the longevity of this transaction, if this is a signed extrinsic. + /// + /// `None` if it is unsigned or an inherent. pub signature: Option>, /// The function that should be called. pub function: Call, @@ -286,6 +307,7 @@ where } } +#[docify::export(unchecked_extrinsic_encode_impl)] impl Encode for UncheckedExtrinsic where Address: Encode, diff --git a/substrate/primitives/runtime/src/offchain/storage_lock.rs b/substrate/primitives/runtime/src/offchain/storage_lock.rs index 1b795978447..116e1578815 100644 --- a/substrate/primitives/runtime/src/offchain/storage_lock.rs +++ b/substrate/primitives/runtime/src/offchain/storage_lock.rs @@ -250,7 +250,7 @@ impl Lockable for BlockAndTime { /// /// A lock that is persisted in the DB and provides the ability to guard against /// concurrent access in an off-chain worker, with a defined expiry deadline -/// based on the concrete [`Lockable`](Lockable) implementation. +/// based on the concrete [`Lockable`] implementation. pub struct StorageLock<'a, L = Time> { // A storage value ref which defines the DB entry representing the lock. value_ref: StorageValueRef<'a>, diff --git a/substrate/src/lib.rs b/substrate/src/lib.rs deleted file mode 100644 index b5a583fcfcf..00000000000 --- a/substrate/src/lib.rs +++ /dev/null @@ -1,242 +0,0 @@ -// 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 -//! -//! 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/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. -//! -//! ## Overview -//! -//! Substrate approaches blockchain development with an acknowledgement of a few self-evident -//! truths: -//! -//! 1. Society and technology evolves. -//! 2. Humans are fallible. -//! -//! This, specifically, makes the task of designing a correct, safe and long-lasting blockchain -//! system hard. -//! -//! Nonetheless, in order to achieve this goal, substrate embraces the following: -//! -//! 1. Use of **Rust** as a modern, and safe programming language, which limits human error through -//! various means, most notably memory safety. -//! 2. Substrate is written from the ground-up with a generic, modular and extensible design. This -//! ensures that software components can be easily swapped and upgraded. Examples of this is -//! multiple consensus mechanisms provided by Substrate, as listed below. -//! 3. Lastly, the final blockchain system created with the above properties needs to be -//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the -//! application logic of the blockchain (called "Runtime") is encoded as a Wasm blob, and is -//! stored onchain. The rest of the system (called "Client") acts as the executor of the Wasm -//! blob. -//! -//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as Wasm blob" -//! accord. This enables the Runtime to become inherently upgradeable (without forks). The upgrade -//! is merely a matter of the Wasm blob being changed in the chain state, which is, in principle, -//! same as updating an account's balance. -//! -//! ### Architecture -//! -//! Therefore, Substrate can be visualized as follows: -#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_simple.mmd")] -//! -//! The client and the runtime of course need to communicate. This is done through two concepts: -//! -//! 1. Host functions: a way for the (Wasm) runtime to talk to the client. All host functions are -//! defined in [`sp-io`]. For example, [`sp-io::storage`] are the set of host functions that -//! allow the runtime to read and write data to the on-chain state. -//! 2. Runtime APIs: a way for the client to talk to the Wasm runtime. Runtime APIs are defined -//! using macros and utilities in [`sp-api`]. For example, [`sp-api::Core`] is the most basic -//! runtime API that any blockchain must implement in order to be able to (re) execute blocks. -#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_client_runtime.mmd")] -//! -//! [`FRAME`], Substrate's default runtime development library takes the above even further by -//! embracing a declarative programming model whereby correctness is enhanced and the system is -//! highly configurable through parameterization. -//! -//! All in all, this design enables all substrate-based chains to achieve forkless, self-enacting -//! upgrades out of the box. Combined with governance abilities that are shipped with `FRAME`, this -//! enables a chain to survive the test of time. -//! -//! ## How to Get Stared -//! -//! Most developers want to leave the client side code as-is, and focus on the runtime. To do so, -//! look into the [`frame`] crate, which is the entry point crate into runtime development with -//! FRAME. -//! -//! > Side note, it is entirely possible to craft a substrate-based runtime without FRAME, an -//! > example of which can be found [here](https://github.com/JoshOrndorff/frameless-node-template). -//! -//! In more broad terms, the following avenues exist into developing with substrate: -//! -//! * **Templates**: A number of substrate-based templates exist and they can be used for various -//! purposes, with zero to little additional code needed. All of these templates contain runtimes -//! that are highly configurable and are likely suitable for basic needs. -//! * [`FRAME`]: If need, one can customize that runtime even further, by using `FRAME` and -//! developing custom modules. -//! * **Core**: To the contrary, some developers may want to customize the client side software to -//! achieve novel goals such as a new consensus engine, or a new database backend. While -//! Substrate's main configurability is in the runtime, the client is also highly generic and can -//! be customized to a great extent. -//! -//! ## Structure -//! -//! Substrate is a massive cargo workspace with hundreds of crates, therefore it is useful to know -//! how to navigate its crates. -//! -//! In broad terms, it is divided into three categories: -//! -//! * `sc-*` (short for *substrate-client*) crates, located under `./client` folder. These are all -//! the client crates. Notable examples are crates such as [`sc-network`], various consensus -//! crates, [`sc-rpc-api`] and [`sc-client-db`], all of which are expected to reside in the client -//! side. -//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These -//! are the traits that glue the client and runtime together, but are not opinionated about what -//! framework is using for building the runtime. Notable examples are [`sp-api`] and [`sp-io`], -//! which form the communication bridge between the client and runtime. -//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related -//! to FRAME. See [`frame`] for more information. -//! -//! ### Wasm Build -//! -//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both Wasm (when a Wasm -//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate -//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a -//! crate is being built with the standard library, and is built for native. Otherwise, it is built -//! for `no_std`. -//! -//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find -//! in any Substrate-based runtime. -//! -//! Substrate-based runtimes use [`substrate-wasm-builder`] in their `build.rs` to automatically -//! build their Wasm files as a part of normal build commandsOnce built, the wasm file is placed in -//! `./target/{debug|release}/wbuild/{runtime_name}.wasm`. -//! -//! ### Binaries -//! -//! Multiple binaries are shipped with substrate, the most important of which are located in the -//! `./bin` folder. -//! -//! * [`node`] is an extensive substrate node that contains the superset of all runtime and client -//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the -//! modules that are provided with `FRAME`. This node and runtime is only used for testing and -//! demonstration. -//! * [`chain-spec-builder`]: Utility to build more detailed [chain-spec][`sc-chain-spec`] for the -//! aforementioned node. Other projects typically contain a `build-spec` subcommand that does the -//! same. -//! * [`node-template`]: a template node that contains a minimal set of features and can act as a -//! starting point of a project. -//! * [`subkey`]: Substrate's key management utility. -//! -//! ### Anatomy of a Binary Crate -//! -//! From the above, [`node`] and [`node-template`] are essentially blueprints of a substrate-based -//! project, as the name of the latter is implying. Each substrate-based project typically contains -//! the following: -//! -//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file. -//! This file typically contains the [`frame_support::construct_runtime`] macro, which is the -//! final definition of a runtime. -//! -//! * Under `./node`, a `main.rs`, which is the point, and a `./service.rs`, which contains all the -//! client side components. Skimming this file yields an overview of the networking, database, -//! consensus and similar client side components. -//! -//! > The above two are conventions, not rules. -//! -//! ## Parachain? -//! -//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways -//! 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/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? -//! -//! Additional noteworthy crates within substrate: -//! -//! - Chain specification of a Substrate node: -//! - [`sc-chain-spec`] -//! - RPC APIs of a Substrate node: [`sc-rpc-api`]/[`sc-rpc`] -//! - CLI Options of a Substrate node: [`sc-cli`] -//! - All of the consensus related crates provided by Substrate: -//! - [`sc-consensus-aura`] -//! - [`sc-consensus-babe`] -//! - [`sc-consensus-grandpa`] -//! - [`sc-consensus-beefy`] -//! - [`sc-consensus-manual-seal`] -//! - [`sc-consensus-pow`] -//! -//! Additional noteworthy external resources: -//! -//! - [Substrate Developer Hub](https://substrate.dev) -//! - [Parity Tech's Documentation Hub](https://paritytech.github.io/) -//! - [Frontier: Substrate's Ethereum Compatibility Library](https://paritytech.github.io/frontier/) -//! - [Polkadot Wiki](https://wiki.polkadot.network/en/) -//! -//! Notable upstream crates: -//! -//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) -//! - [`parity-db`](https://github.com/paritytech/parity-db) -//! - [`trie`](https://github.com/paritytech/trie) -//! - [`parity-common`](https://github.com/paritytech/parity-common) -//! -//! Templates: -//! -//! - classic [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) -//! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) -//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) -//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) -//! -//! [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 -//! [`FRAME`]: ../frame/index.html -//! [`sp-io`]: ../sp_io/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sc-client-db`]: ../sc_client_db/index.html -//! [`sc-chain-spec`]: ../sc_chain_spec/index.html -//! [`sc-network`]: ../sc_network/index.html -//! [`sc-rpc-api`]: ../sc_rpc_api/index.html -//! [`sc-rpc`]: ../sc_rpc/index.html -//! [`sc-cli`]: ../sc_cli/index.html -//! [`sc-consensus-aura`]: ../sc_consensus_aura/index.html -//! [`sc-consensus-babe`]: ../sc_consensus_babe/index.html -//! [`sc-consensus-grandpa`]: ../sc_consensus_grandpa/index.html -//! [`sc-consensus-beefy`]: ../sc_consensus_beefy/index.html -//! [`sc-consensus-manual-seal`]: ../sc_consensus_manual_seal/index.html -//! [`sc-consensus-pow`]: ../sc_consensus_pow/index.html -//! [`node`]: ../node_cli/index.html -//! [`node-template`]: ../node_template/index.html -//! [`kitchensink_runtime`]: ../kitchensink_runtime/index.html -//! [`subkey`]: ../subkey/index.html -//! [`chain-spec-builder`]: ../chain_spec_builder/index.html -//! [`substrate-wasm-builder`]: https://crates.io/crates/substrate-wasm-builder - -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::private_intra_doc_links)] -- GitLab From 64361ac19a3c74ec50329403e45a3a98fc40ac5b Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:58:39 +0100 Subject: [PATCH 625/633] Withdraw Assets Before Checking Out in `OnReapIdentity` impl (#2552) Follow up to fix a bug from #1814 discovered in XCM emulator testing. I mistakenly thought that checking out an asset would withdraw it from the sender. This actually withdraws the asset before checking out. --------- Co-authored-by: Adrian Catangiu Co-authored-by: Liam Aharon --- polkadot/runtime/rococo/src/impls.rs | 24 +++++++++++++++++++++++- polkadot/runtime/westend/src/impls.rs | 24 +++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index 71b1091eeb6..eddbfacc3b1 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -79,6 +79,8 @@ impl ToParachainIdentityReaper { } } +// Note / Warning: This implementation should only be used in a transactional context. If not, then +// an error could result in assets being burned. impl OnReapIdentity for ToParachainIdentityReaper where Runtime: frame_system::Config + pallet_xcm::Config, @@ -100,6 +102,19 @@ where // Do `check_out` accounting since the XCM Executor's `InitiateTeleport` doesn't support // unpaid teleports. + // withdraw the asset from `who` + let who_origin = + Junction::AccountId32 { network: None, id: who.clone().into() }.into_location(); + let _withdrawn = xcm_config::LocalAssetTransactor::withdraw_asset(&roc, &who_origin, None) + .map_err(|err| { + log::error!( + target: "runtime::on_reap_identity", + "withdraw_asset(what: {:?}, who_origin: {:?}) error: {:?}", + roc, who_origin, err + ); + pallet_xcm::Error::::LowBalance + })?; + // check out xcm_config::LocalAssetTransactor::can_check_out( &destination, @@ -107,7 +122,14 @@ where // not used in AssetTransactor &XcmContext { origin: None, message_id: [0; 32], topic: None }, ) - .map_err(|_| pallet_xcm::Error::::CannotCheckOutTeleport)?; + .map_err(|err| { + log::error!( + target: "runtime::on_reap_identity", + "can_check_out(destination: {:?}, asset: {:?}, _) error: {:?}", + destination, roc, err + ); + pallet_xcm::Error::::CannotCheckOutTeleport + })?; xcm_config::LocalAssetTransactor::check_out( &destination, &roc, diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index 80105594965..5f23bd373b1 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -79,6 +79,8 @@ impl ToParachainIdentityReaper { } } +// Note / Warning: This implementation should only be used in a transactional context. If not, then +// an error could result in assets being burned. impl OnReapIdentity for ToParachainIdentityReaper where Runtime: frame_system::Config + pallet_xcm::Config, @@ -100,6 +102,19 @@ where // Do `check_out` accounting since the XCM Executor's `InitiateTeleport` doesn't support // unpaid teleports. + // withdraw the asset from `who` + let who_origin = + Junction::AccountId32 { network: None, id: who.clone().into() }.into_location(); + let _withdrawn = xcm_config::LocalAssetTransactor::withdraw_asset(&wnd, &who_origin, None) + .map_err(|err| { + log::error!( + target: "runtime::on_reap_identity", + "withdraw_asset(what: {:?}, who_origin: {:?}) error: {:?}", + wnd, who_origin, err + ); + pallet_xcm::Error::::LowBalance + })?; + // check out xcm_config::LocalAssetTransactor::can_check_out( &destination, @@ -107,7 +122,14 @@ where // not used in AssetTransactor &XcmContext { origin: None, message_id: [0; 32], topic: None }, ) - .map_err(|_| pallet_xcm::Error::::CannotCheckOutTeleport)?; + .map_err(|err| { + log::error!( + target: "runtime::on_reap_identity", + "can_check_out(destination: {:?}, asset: {:?}, _) error: {:?}", + destination, wnd, err + ); + pallet_xcm::Error::::CannotCheckOutTeleport + })?; xcm_config::LocalAssetTransactor::check_out( &destination, &wnd, -- GitLab From 9a650c46fdf52809bd9b5d687a4e1f77748521d4 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 30 Nov 2023 15:56:34 +0100 Subject: [PATCH 626/633] PoV Reclaim (Clawback) Node Side (#1462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR provides the infrastructure for the pov-reclaim mechanism discussed in #209. The goal is to provide the current proof size to the runtime so it can be used to reclaim storage weight. ## New Host Function - A new host function is provided [here](https://github.com/skunert/polkadot-sdk/blob/5b317fda3be205f4136f10d4490387ccd4f9765d/cumulus/primitives/pov-reclaim/src/lib.rs#L23). It returns the size of the current proof size to the runtime. If recording is not enabled, it returns 0. ## Implementation Overview - Implement option to enable proof recording during import in the client. This is currently enabled for `polkadot-parachain`, `parachain-template` and the cumulus test node. - Make the proof recorder ready for no-std. It was previously only enabled for std environments, but we need to record the proof size in `validate_block` too. - Provide a recorder implementation that only the records the size of incoming nodes and does not store the nodes itself. - Fix benchmarks that were broken by async backing changes - Provide new externalities extension that is registered by default if proof recording is enabled. - I think we should discuss the naming, pov-reclaim was more intuitive to me, but we could also go with clawback like in the issue. ## Impact of proof recording during import With proof recording: 6.3058 Kelem/s Without proof recording: 6.3427 Kelem/s The measured impact on the importing performance is quite low on my machine using the block import benchmark. With proof recording I am seeing a performance hit of 0.585%. --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi Co-authored-by: Bastian Köcher --- Cargo.lock | 19 ++ Cargo.toml | 1 + cumulus/client/service/Cargo.toml | 1 + cumulus/client/service/src/lib.rs | 2 + cumulus/pallets/parachain-system/Cargo.toml | 3 + .../src/validate_block/mod.rs | 4 + .../src/validate_block/trie_recorder.rs | 286 ++++++++++++++++++ .../proof-size-hostfunction/Cargo.toml | 21 ++ .../proof-size-hostfunction/src/lib.rs | 107 +++++++ cumulus/test/client/Cargo.toml | 1 + cumulus/test/client/src/lib.rs | 3 +- cumulus/test/service/benches/block_import.rs | 92 +++--- .../service/benches/block_import_glutton.rs | 37 ++- .../test/service/benches/validate_block.rs | 15 +- cumulus/test/service/src/bench_utils.rs | 7 +- cumulus/test/service/src/lib.rs | 54 ++-- cumulus/test/service/src/main.rs | 3 +- .../client/api/src/execution_extensions.rs | 5 +- substrate/client/block-builder/Cargo.toml | 1 + substrate/client/block-builder/src/lib.rs | 5 + substrate/client/service/src/builder.rs | 26 +- substrate/client/service/src/client/client.rs | 15 +- substrate/client/service/src/lib.rs | 7 +- .../procedural/src/construct_runtime/mod.rs | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 2 +- .../api/proc-macro/src/impl_runtime_apis.rs | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 1 + .../proc-macro/src/runtime_interface/mod.rs | 6 + .../state-machine/src/trie_backend.rs | 150 +++++---- .../state-machine/src/trie_backend_essence.rs | 154 +++++----- substrate/primitives/trie/Cargo.toml | 2 + substrate/primitives/trie/src/lib.rs | 26 ++ .../trie/src/proof_size_extension.rs | 39 +++ substrate/primitives/trie/src/recorder.rs | 41 ++- 34 files changed, 899 insertions(+), 241 deletions(-) create mode 100644 cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs create mode 100644 cumulus/primitives/proof-size-hostfunction/Cargo.toml create mode 100644 cumulus/primitives/proof-size-hostfunction/src/lib.rs create mode 100644 substrate/primitives/trie/src/proof_size_extension.rs diff --git a/Cargo.lock b/Cargo.lock index de4471783ab..e7caa46cad8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3495,6 +3495,7 @@ dependencies = [ "cumulus-client-network", "cumulus-client-pov-recovery", "cumulus-primitives-core", + "cumulus-primitives-proof-size-hostfunction", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", @@ -3564,6 +3565,7 @@ dependencies = [ "cumulus-pallet-parachain-system-proc-macro", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", "cumulus-test-client", "cumulus-test-relay-sproof-builder", "environmental", @@ -3595,6 +3597,7 @@ dependencies = [ "sp-version", "staging-xcm", "trie-db", + "trie-standardmap", ] [[package]] @@ -3743,6 +3746,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "cumulus-primitives-proof-size-hostfunction" +version = "0.1.0" +dependencies = [ + "sp-core", + "sp-externalities 0.19.0", + "sp-io", + "sp-runtime-interface 17.0.0", + "sp-state-machine", + "sp-trie", +] + [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" @@ -3903,6 +3918,7 @@ version = "0.1.0" dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", "cumulus-test-relay-sproof-builder", "cumulus-test-runtime", "cumulus-test-service", @@ -14766,6 +14782,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", + "sp-trie", "substrate-test-runtime-client", ] @@ -17612,6 +17629,7 @@ name = "sp-runtime-interface-proc-macro" version = "11.0.0" dependencies = [ "Inflector", + "expander 2.0.0", "proc-macro-crate", "proc-macro2", "quote", @@ -17864,6 +17882,7 @@ dependencies = [ "scale-info", "schnellru", "sp-core", + "sp-externalities 0.19.0", "sp-runtime", "sp-std 8.0.0", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index a295aca819c..b585ceb5b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ members = [ "cumulus/primitives/aura", "cumulus/primitives/core", "cumulus/primitives/parachain-inherent", + "cumulus/primitives/proof-size-hostfunction", "cumulus/primitives/timestamp", "cumulus/primitives/utility", "cumulus/test/client", diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index f80c65128d5..cc2f22e6565 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -38,6 +38,7 @@ cumulus-client-consensus-common = { path = "../consensus/common" } cumulus-client-pov-recovery = { path = "../pov-recovery" } cumulus-client-network = { path = "../network" } cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction" } 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" } diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index f8ebca11c8c..950e59aff24 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -52,6 +52,8 @@ use sp_core::{traits::SpawnNamed, Decode}; use sp_runtime::traits::{Block as BlockT, BlockIdTo, Header}; use std::{sync::Arc, time::Duration}; +pub use cumulus_primitives_proof_size_hostfunction::storage_proof_size; + // Given the sporadic nature of the explicit recovery operation and the // possibility to retry infinite times this value is more than enough. // In practice here we expect no more than one queued messages. diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 5600c95a2a6..cf6af4b4786 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -39,11 +39,13 @@ xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-feature cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false } +cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction", default-features = false } [dev-dependencies] assert_matches = "1.5" hex-literal = "0.4.1" lazy_static = "1.4" +trie-standardmap = "0.16.0" rand = "0.8.5" futures = "0.3.28" @@ -65,6 +67,7 @@ std = [ "cumulus-pallet-parachain-system-proc-macro/std", "cumulus-primitives-core/std", "cumulus-primitives-parachain-inherent/std", + "cumulus-primitives-proof-size-hostfunction/std", "environmental/std", "frame-benchmarking/std", "frame-support/std", diff --git a/cumulus/pallets/parachain-system/src/validate_block/mod.rs b/cumulus/pallets/parachain-system/src/validate_block/mod.rs index db149401638..763a4cffd77 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/mod.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/mod.rs @@ -26,6 +26,10 @@ mod tests; #[doc(hidden)] mod trie_cache; +#[cfg(any(test, not(feature = "std")))] +#[doc(hidden)] +mod trie_recorder; + #[cfg(not(feature = "std"))] #[doc(hidden)] pub use bytes; diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs new file mode 100644 index 00000000000..e73aef70aa4 --- /dev/null +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs @@ -0,0 +1,286 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Provide a specialized trie-recorder and provider for use in validate-block. +//! +//! This file defines two main structs, [`SizeOnlyRecorder`] and +//! [`SizeOnlyRecorderProvider`]. They are used to track the current +//! proof-size without actually recording the accessed nodes themselves. + +use codec::Encode; + +use sp_std::{ + cell::{RefCell, RefMut}, + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + rc::Rc, +}; +use sp_trie::{NodeCodec, ProofSizeProvider, StorageProof}; +use trie_db::{Hasher, RecordedForKey, TrieAccess}; + +/// A trie recorder that only keeps track of the proof size. +/// +/// The internal size counting logic should align +/// with ['sp_trie::recorder::Recorder']. +pub(crate) struct SizeOnlyRecorder<'a, H: Hasher> { + seen_nodes: RefMut<'a, BTreeSet>, + encoded_size: RefMut<'a, usize>, + recorded_keys: RefMut<'a, BTreeMap, RecordedForKey>>, +} + +impl<'a, H: trie_db::Hasher> trie_db::TrieRecorder for SizeOnlyRecorder<'a, H> { + fn record(&mut self, access: TrieAccess<'_, H::Out>) { + let mut encoded_size_update = 0; + match access { + TrieAccess::NodeOwned { hash, node_owned } => + if self.seen_nodes.insert(hash) { + let node = node_owned.to_encoded::>(); + encoded_size_update += node.encoded_size(); + }, + TrieAccess::EncodedNode { hash, encoded_node } => + if self.seen_nodes.insert(hash) { + encoded_size_update += encoded_node.encoded_size(); + }, + TrieAccess::Value { hash, value, full_key } => { + if self.seen_nodes.insert(hash) { + encoded_size_update += value.encoded_size(); + } + self.recorded_keys + .entry(full_key.into()) + .and_modify(|e| *e = RecordedForKey::Value) + .or_insert_with(|| RecordedForKey::Value); + }, + TrieAccess::Hash { full_key } => { + self.recorded_keys + .entry(full_key.into()) + .or_insert_with(|| RecordedForKey::Hash); + }, + TrieAccess::NonExisting { full_key } => { + self.recorded_keys + .entry(full_key.into()) + .and_modify(|e| *e = RecordedForKey::Value) + .or_insert_with(|| RecordedForKey::Value); + }, + TrieAccess::InlineValue { full_key } => { + self.recorded_keys + .entry(full_key.into()) + .and_modify(|e| *e = RecordedForKey::Value) + .or_insert_with(|| RecordedForKey::Value); + }, + }; + + *self.encoded_size += encoded_size_update; + } + + fn trie_nodes_recorded_for_key(&self, key: &[u8]) -> RecordedForKey { + self.recorded_keys.get(key).copied().unwrap_or(RecordedForKey::None) + } +} + +#[derive(Clone)] +pub(crate) struct SizeOnlyRecorderProvider { + seen_nodes: Rc>>, + encoded_size: Rc>, + recorded_keys: Rc, RecordedForKey>>>, +} + +impl SizeOnlyRecorderProvider { + pub fn new() -> Self { + Self { + seen_nodes: Default::default(), + encoded_size: Default::default(), + recorded_keys: Default::default(), + } + } +} + +impl sp_trie::TrieRecorderProvider for SizeOnlyRecorderProvider { + type Recorder<'a> = SizeOnlyRecorder<'a, H> where H: 'a; + + fn drain_storage_proof(self) -> Option { + None + } + + fn as_trie_recorder(&self, _storage_root: H::Out) -> Self::Recorder<'_> { + SizeOnlyRecorder { + encoded_size: self.encoded_size.borrow_mut(), + seen_nodes: self.seen_nodes.borrow_mut(), + recorded_keys: self.recorded_keys.borrow_mut(), + } + } +} + +impl ProofSizeProvider for SizeOnlyRecorderProvider { + fn estimate_encoded_size(&self) -> usize { + *self.encoded_size.borrow() + } +} + +// This is safe here since we are single-threaded in WASM +unsafe impl Send for SizeOnlyRecorderProvider {} +unsafe impl Sync for SizeOnlyRecorderProvider {} + +#[cfg(test)] +mod tests { + use rand::Rng; + use sp_trie::{ + cache::{CacheSize, SharedTrieCache}, + MemoryDB, ProofSizeProvider, TrieRecorderProvider, + }; + use trie_db::{Trie, TrieDBBuilder, TrieDBMutBuilder, TrieHash, TrieMut, TrieRecorder}; + use trie_standardmap::{Alphabet, StandardMap, ValueMode}; + + use super::*; + + type Recorder = sp_trie::recorder::Recorder; + + fn create_trie() -> ( + sp_trie::MemoryDB, + TrieHash>, + Vec<(Vec, Vec)>, + ) { + let mut db = MemoryDB::default(); + let mut root = Default::default(); + + let mut seed = Default::default(); + let test_data: Vec<(Vec, Vec)> = StandardMap { + alphabet: Alphabet::Low, + min_key: 16, + journal_key: 0, + value_mode: ValueMode::Random, + count: 1000, + } + .make_with(&mut seed) + .into_iter() + .map(|(k, v)| { + // Double the length so we end up with some values of 2 bytes and some of 64 + let v = [v.clone(), v].concat(); + (k, v) + }) + .collect(); + + // Fill database with values + { + let mut trie = TrieDBMutBuilder::>::new( + &mut db, &mut root, + ) + .build(); + for (k, v) in &test_data { + trie.insert(k, v).expect("Inserts data"); + } + } + + (db, root, test_data) + } + + #[test] + fn recorder_equivalence_cache() { + let (db, root, test_data) = create_trie(); + + let mut rng = rand::thread_rng(); + for _ in 1..10 { + let reference_recorder = Recorder::default(); + let recorder_for_test: SizeOnlyRecorderProvider = + SizeOnlyRecorderProvider::new(); + let reference_cache: SharedTrieCache = + SharedTrieCache::new(CacheSize::new(1024 * 5)); + let cache_for_test: SharedTrieCache = + SharedTrieCache::new(CacheSize::new(1024 * 5)); + { + let local_cache = cache_for_test.local_cache(); + let mut trie_cache_for_reference = local_cache.as_trie_db_cache(root); + let mut reference_trie_recorder = reference_recorder.as_trie_recorder(root); + let reference_trie = + TrieDBBuilder::>::new(&db, &root) + .with_recorder(&mut reference_trie_recorder) + .with_cache(&mut trie_cache_for_reference) + .build(); + + let local_cache_for_test = reference_cache.local_cache(); + let mut trie_cache_for_test = local_cache_for_test.as_trie_db_cache(root); + let mut trie_recorder_under_test = recorder_for_test.as_trie_recorder(root); + let test_trie = + TrieDBBuilder::>::new(&db, &root) + .with_recorder(&mut trie_recorder_under_test) + .with_cache(&mut trie_cache_for_test) + .build(); + + // Access random values from the test data + for _ in 0..100 { + let index: usize = rng.gen_range(0..test_data.len()); + test_trie.get(&test_data[index].0).unwrap().unwrap(); + reference_trie.get(&test_data[index].0).unwrap().unwrap(); + } + + // Check that we have the same nodes recorded for both recorders + for (key, _) in test_data.iter() { + let reference = reference_trie_recorder.trie_nodes_recorded_for_key(key); + let test_value = trie_recorder_under_test.trie_nodes_recorded_for_key(key); + assert_eq!(format!("{:?}", reference), format!("{:?}", test_value)); + } + } + + // Check that we have the same size recorded for both recorders + assert_eq!( + reference_recorder.estimate_encoded_size(), + recorder_for_test.estimate_encoded_size() + ); + } + } + + #[test] + fn recorder_equivalence_no_cache() { + let (db, root, test_data) = create_trie(); + + let mut rng = rand::thread_rng(); + for _ in 1..10 { + let reference_recorder = Recorder::default(); + let recorder_for_test: SizeOnlyRecorderProvider = + SizeOnlyRecorderProvider::new(); + { + let mut reference_trie_recorder = reference_recorder.as_trie_recorder(root); + let reference_trie = + TrieDBBuilder::>::new(&db, &root) + .with_recorder(&mut reference_trie_recorder) + .build(); + + let mut trie_recorder_under_test = recorder_for_test.as_trie_recorder(root); + let test_trie = + TrieDBBuilder::>::new(&db, &root) + .with_recorder(&mut trie_recorder_under_test) + .build(); + + for _ in 0..200 { + let index: usize = rng.gen_range(0..test_data.len()); + test_trie.get(&test_data[index].0).unwrap().unwrap(); + reference_trie.get(&test_data[index].0).unwrap().unwrap(); + } + + // Check that we have the same nodes recorded for both recorders + for (key, _) in test_data.iter() { + let reference = reference_trie_recorder.trie_nodes_recorded_for_key(key); + let test_value = trie_recorder_under_test.trie_nodes_recorded_for_key(key); + assert_eq!(format!("{:?}", reference), format!("{:?}", test_value)); + } + } + + // Check that we have the same size recorded for both recorders + assert_eq!( + reference_recorder.estimate_encoded_size(), + recorder_for_test.estimate_encoded_size() + ); + } + } +} diff --git a/cumulus/primitives/proof-size-hostfunction/Cargo.toml b/cumulus/primitives/proof-size-hostfunction/Cargo.toml new file mode 100644 index 00000000000..83dad428d00 --- /dev/null +++ b/cumulus/primitives/proof-size-hostfunction/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cumulus-primitives-proof-size-hostfunction" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +description = "Hostfunction exposing storage proof size to the runtime." +license = "Apache-2.0" + +[dependencies] +sp-runtime-interface = { path = "../../../substrate/primitives/runtime-interface", default-features = false } +sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } + +[dev-dependencies] +sp-state-machine = { path = "../../../substrate/primitives/state-machine" } +sp-core = { path = "../../../substrate/primitives/core" } +sp-io = { path = "../../../substrate/primitives/io" } + +[features] +default = [ "std" ] +std = [ "sp-externalities/std", "sp-runtime-interface/std", "sp-trie/std" ] diff --git a/cumulus/primitives/proof-size-hostfunction/src/lib.rs b/cumulus/primitives/proof-size-hostfunction/src/lib.rs new file mode 100644 index 00000000000..6da6235e585 --- /dev/null +++ b/cumulus/primitives/proof-size-hostfunction/src/lib.rs @@ -0,0 +1,107 @@ +// 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. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 . + +//! Tools for reclaiming PoV weight in parachain runtimes. + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_externalities::ExternalitiesExt; + +use sp_runtime_interface::runtime_interface; + +#[cfg(feature = "std")] +use sp_trie::proof_size_extension::ProofSizeExt; + +pub const PROOF_RECORDING_DISABLED: u64 = u64::MAX; + +/// Interface that provides access to the current storage proof size. +/// +/// Should return the current storage proof size if [`ProofSizeExt`] is registered. Otherwise, needs +/// to return u64::MAX. +#[runtime_interface] +pub trait StorageProofSize { + /// Returns the current storage proof size. + fn storage_proof_size(&mut self) -> u64 { + self.extension::().map_or(u64::MAX, |e| e.storage_proof_size()) + } +} + +#[cfg(test)] +mod tests { + use sp_core::Blake2Hasher; + use sp_state_machine::TestExternalities; + use sp_trie::{ + proof_size_extension::ProofSizeExt, recorder::Recorder, LayoutV1, PrefixedMemoryDB, + TrieDBMutBuilder, TrieMut, + }; + + use crate::{storage_proof_size, PROOF_RECORDING_DISABLED}; + + const TEST_DATA: &[(&[u8], &[u8])] = &[(b"key1", &[1; 64]), (b"key2", &[2; 64])]; + + type TestLayout = LayoutV1; + + fn get_prepared_test_externalities() -> (TestExternalities, Recorder) + { + let mut db = PrefixedMemoryDB::default(); + let mut root = Default::default(); + + { + let mut trie = TrieDBMutBuilder::::new(&mut db, &mut root).build(); + for (k, v) in TEST_DATA { + trie.insert(k, v).expect("Inserts data"); + } + } + + let recorder: sp_trie::recorder::Recorder = Default::default(); + let trie_backend = sp_state_machine::TrieBackendBuilder::new(db, root) + .with_recorder(recorder.clone()) + .build(); + + let mut ext: TestExternalities = TestExternalities::default(); + ext.backend = trie_backend; + (ext, recorder) + } + + #[test] + fn host_function_returns_size_from_recorder() { + let (mut ext, recorder) = get_prepared_test_externalities(); + ext.register_extension(ProofSizeExt::new(recorder)); + + ext.execute_with(|| { + assert_eq!(storage_proof_size::storage_proof_size(), 0); + sp_io::storage::get(b"key1"); + assert_eq!(storage_proof_size::storage_proof_size(), 175); + sp_io::storage::get(b"key2"); + assert_eq!(storage_proof_size::storage_proof_size(), 275); + sp_io::storage::get(b"key2"); + assert_eq!(storage_proof_size::storage_proof_size(), 275); + }); + } + + #[test] + fn host_function_returns_max_without_extension() { + let (mut ext, _) = get_prepared_test_externalities(); + + ext.execute_with(|| { + assert_eq!(storage_proof_size::storage_proof_size(), PROOF_RECORDING_DISABLED); + sp_io::storage::get(b"key1"); + assert_eq!(storage_proof_size::storage_proof_size(), PROOF_RECORDING_DISABLED); + sp_io::storage::get(b"key2"); + assert_eq!(storage_proof_size::storage_proof_size(), PROOF_RECORDING_DISABLED); + }); + } +} diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index b760b796ec9..6ab873d320c 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -36,6 +36,7 @@ cumulus-test-runtime = { path = "../runtime" } cumulus-test-service = { path = "../service" } cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } [features] diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index a3c79158f49..df63f683de6 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -44,7 +44,8 @@ mod local_executor { pub struct LocalExecutor; impl sc_executor::NativeExecutionDispatch for LocalExecutor { - type ExtendHostFunctions = (); + type ExtendHostFunctions = + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions; fn dispatch(method: &str, data: &[u8]) -> Option> { cumulus_test_runtime::api::dispatch(method, data) diff --git a/cumulus/test/service/benches/block_import.rs b/cumulus/test/service/benches/block_import.rs index 254e03b9263..9d6485d74c5 100644 --- a/cumulus/test/service/benches/block_import.rs +++ b/cumulus/test/service/benches/block_import.rs @@ -24,7 +24,7 @@ use core::time::Duration; use cumulus_primitives_core::ParaId; use sp_api::{Core, ProvideRuntimeApi}; -use sp_keyring::Sr25519Keyring::Alice; +use sp_keyring::Sr25519Keyring::{Alice, Bob}; use cumulus_test_service::bench_utils as utils; @@ -32,51 +32,69 @@ fn benchmark_block_import(c: &mut Criterion) { sp_tracing::try_init_simple(); let runtime = tokio::runtime::Runtime::new().expect("creating tokio runtime doesn't fail; qed"); - let para_id = ParaId::from(100); + + let para_id = ParaId::from(cumulus_test_runtime::PARACHAIN_ID); let tokio_handle = runtime.handle(); // Create enough accounts to fill the block with transactions. // Each account should only be included in one transfer. let (src_accounts, dst_accounts, account_ids) = utils::create_benchmark_accounts(); - let alice = runtime.block_on( - cumulus_test_service::TestNodeBuilder::new(para_id, tokio_handle.clone(), Alice) + for bench_parameters in &[(true, Alice), (false, Bob)] { + let node = runtime.block_on( + cumulus_test_service::TestNodeBuilder::new( + para_id, + tokio_handle.clone(), + bench_parameters.1, + ) // Preload all accounts with funds for the transfers - .endowed_accounts(account_ids) + .endowed_accounts(account_ids.clone()) + .import_proof_recording(bench_parameters.0) .build(), - ); - - let client = alice.client; - - let (max_transfer_count, extrinsics) = - utils::create_benchmarking_transfer_extrinsics(&client, &src_accounts, &dst_accounts); - - let parent_hash = client.usage_info().chain.best_hash; - let mut block_builder = BlockBuilderBuilder::new(&*client) - .on_parent_block(parent_hash) - .fetch_parent_block_number(&*client) - .unwrap() - .build() - .unwrap(); - for extrinsic in extrinsics { - block_builder.push(extrinsic).unwrap(); - } - let benchmark_block = block_builder.build().unwrap(); - - let mut group = c.benchmark_group("Block import"); - group.sample_size(20); - group.measurement_time(Duration::from_secs(120)); - group.throughput(Throughput::Elements(max_transfer_count as u64)); - - group.bench_function(format!("(transfers = {}) block import", max_transfer_count), |b| { - b.iter_batched( - || benchmark_block.block.clone(), - |block| { - client.runtime_api().execute_block(parent_hash, block).unwrap(); + ); + + let client = node.client; + let backend = node.backend; + + let (max_transfer_count, extrinsics) = + utils::create_benchmarking_transfer_extrinsics(&client, &src_accounts, &dst_accounts); + + let parent_hash = client.usage_info().chain.best_hash; + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .fetch_parent_block_number(&*client) + .unwrap() + .build() + .unwrap(); + for extrinsic in extrinsics { + block_builder.push(extrinsic).unwrap(); + } + let benchmark_block = block_builder.build().unwrap(); + + let mut group = c.benchmark_group("Block import"); + group.sample_size(20); + group.measurement_time(Duration::from_secs(120)); + group.throughput(Throughput::Elements(max_transfer_count as u64)); + + group.bench_function( + format!( + "(transfers = {max_transfer_count}, proof_recording = {}) block import", + bench_parameters.0 + ), + |b| { + b.iter_batched( + || { + backend.reset_trie_cache(); + benchmark_block.block.clone() + }, + |block| { + client.runtime_api().execute_block(parent_hash, block).unwrap(); + }, + BatchSize::SmallInput, + ) }, - BatchSize::SmallInput, - ) - }); + ); + } } criterion_group!(benches, benchmark_block_import); diff --git a/cumulus/test/service/benches/block_import_glutton.rs b/cumulus/test/service/benches/block_import_glutton.rs index aeaf0722e72..6295fd68286 100644 --- a/cumulus/test/service/benches/block_import_glutton.rs +++ b/cumulus/test/service/benches/block_import_glutton.rs @@ -27,7 +27,7 @@ use core::time::Duration; use cumulus_primitives_core::ParaId; use sc_block_builder::BlockBuilderBuilder; -use sp_keyring::Sr25519Keyring::Alice; +use sp_keyring::Sr25519Keyring::{Alice, Bob, Charlie, Ferdie}; use cumulus_test_service::bench_utils as utils; @@ -38,17 +38,29 @@ fn benchmark_block_import(c: &mut Criterion) { let para_id = ParaId::from(100); let tokio_handle = runtime.handle(); - let alice = runtime.block_on( - cumulus_test_service::TestNodeBuilder::new(para_id, tokio_handle.clone(), Alice).build(), - ); - let client = alice.client; + let mut initialize_glutton_pallet = true; + for (compute_ratio, storage_ratio, proof_on_import, keyring_identity) in &[ + (One::one(), Zero::zero(), true, Alice), + (One::one(), One::one(), true, Bob), + (One::one(), Zero::zero(), false, Charlie), + (One::one(), One::one(), false, Ferdie), + ] { + let node = runtime.block_on( + cumulus_test_service::TestNodeBuilder::new( + para_id, + tokio_handle.clone(), + *keyring_identity, + ) + .import_proof_recording(*proof_on_import) + .build(), + ); + let client = node.client; + let backend = node.backend; - let mut group = c.benchmark_group("Block import"); - group.sample_size(20); - group.measurement_time(Duration::from_secs(120)); + let mut group = c.benchmark_group("Block import"); + group.sample_size(20); + group.measurement_time(Duration::from_secs(120)); - let mut initialize_glutton_pallet = true; - for (compute_ratio, storage_ratio) in &[(One::one(), Zero::zero()), (One::one(), One::one())] { let block = utils::set_glutton_parameters( &client, initialize_glutton_pallet, @@ -82,7 +94,10 @@ fn benchmark_block_import(c: &mut Criterion) { ), |b| { b.iter_batched( - || benchmark_block.block.clone(), + || { + backend.reset_trie_cache(); + benchmark_block.block.clone() + }, |block| { client.runtime_api().execute_block(parent_hash, block).unwrap(); }, diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index 11a7c4376d4..a614863803e 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -18,7 +18,9 @@ use codec::{Decode, Encode}; use core::time::Duration; use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; -use cumulus_primitives_core::{relay_chain::AccountId, PersistedValidationData, ValidationParams}; +use cumulus_primitives_core::{ + relay_chain::AccountId, ParaId, PersistedValidationData, ValidationParams, +}; use cumulus_test_client::{ generate_extrinsic_with_pair, BuildParachainBlockData, InitBlockBuilder, TestClientBuilder, ValidationResult, @@ -83,6 +85,7 @@ fn benchmark_block_validation(c: &mut Criterion) { // Each account should only be included in one transfer. let (src_accounts, dst_accounts, account_ids) = utils::create_benchmark_accounts(); + let para_id = ParaId::from(cumulus_test_runtime::PARACHAIN_ID); let mut test_client_builder = TestClientBuilder::with_default_backend(); let genesis_init = test_client_builder.genesis_init_mut(); *genesis_init = cumulus_test_client::GenesisParameters { endowed_accounts: account_ids }; @@ -98,7 +101,14 @@ fn benchmark_block_validation(c: &mut Criterion) { ..Default::default() }; - let mut block_builder = client.init_block_builder(Some(validation_data), Default::default()); + let sproof_builder = RelayStateSproofBuilder { + included_para_head: Some(parent_header.clone().encode().into()), + para_id, + ..Default::default() + }; + + let mut block_builder = + client.init_block_builder(Some(validation_data), sproof_builder.clone()); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } @@ -108,7 +118,6 @@ fn benchmark_block_validation(c: &mut Criterion) { let proof_size_in_kb = parachain_block.storage_proof().encode().len() as f64 / 1024f64; let runtime = utils::get_wasm_module(); - let sproof_builder: RelayStateSproofBuilder = Default::default(); let (relay_parent_storage_root, _) = sproof_builder.into_state_root_and_proof(); let encoded_params = ValidationParams { block_data: cumulus_test_client::BlockData(parachain_block.encode()), diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 82142f21695..1894835caec 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -81,8 +81,13 @@ pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic { pub fn extrinsic_set_validation_data( parent_header: cumulus_test_runtime::Header, ) -> OpaqueExtrinsic { - let sproof_builder = RelayStateSproofBuilder { para_id: 100.into(), ..Default::default() }; let parent_head = HeadData(parent_header.encode()); + let sproof_builder = RelayStateSproofBuilder { + para_id: cumulus_test_runtime::PARACHAIN_ID.into(), + included_para_head: parent_head.clone().into(), + ..Default::default() + }; + let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof(); let data = ParachainInherentData { validation_data: PersistedValidationData { diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index fb858ce0b71..627d060d8a0 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -187,6 +187,7 @@ impl RecoveryHandle for FailingRecoveryHandle { /// be able to perform chain operations. pub fn new_partial( config: &mut Configuration, + enable_import_proof_record: bool, ) -> Result< PartialComponents< Client, @@ -214,7 +215,12 @@ pub fn new_partial( sc_executor::NativeElseWasmExecutor::::new_with_wasm_executor(wasm); let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts::(config, None, executor)?; + sc_service::new_full_parts_record_import::( + config, + None, + executor, + enable_import_proof_record, + )?; let client = Arc::new(client); let block_import = @@ -309,19 +315,21 @@ pub async fn start_node_impl( rpc_ext_builder: RB, consensus: Consensus, collator_options: CollatorOptions, + proof_recording_during_import: bool, ) -> sc_service::error::Result<( TaskManager, Arc, Arc>, RpcHandlers, TransactionPool, + Arc, )> where RB: Fn(Arc) -> Result, sc_service::Error> + Send + 'static, { let mut parachain_config = prepare_node_config(parachain_config); - let params = new_partial(&mut parachain_config)?; + let params = new_partial(&mut parachain_config, proof_recording_during_import)?; let transaction_pool = params.transaction_pool.clone(); let mut task_manager = params.task_manager; @@ -477,7 +485,7 @@ where start_network.start_network(); - Ok((task_manager, client, network, rpc_handlers, transaction_pool)) + Ok((task_manager, client, network, rpc_handlers, transaction_pool, backend)) } /// A Cumulus test node instance used for testing. @@ -495,6 +503,8 @@ pub struct TestNode { pub rpc_handlers: RpcHandlers, /// Node's transaction pool pub transaction_pool: TransactionPool, + /// Node's backend + pub backend: Arc, } #[allow(missing_docs)] @@ -520,6 +530,7 @@ pub struct TestNodeBuilder { consensus: Consensus, relay_chain_mode: RelayChainMode, endowed_accounts: Vec, + record_proof_during_import: bool, } impl TestNodeBuilder { @@ -544,6 +555,7 @@ impl TestNodeBuilder { consensus: Consensus::RelayChain, endowed_accounts: Default::default(), relay_chain_mode: RelayChainMode::Embedded, + record_proof_during_import: true, } } @@ -656,6 +668,12 @@ impl TestNodeBuilder { self } + /// Record proofs during import. + pub fn import_proof_recording(mut self, should_record_proof: bool) -> TestNodeBuilder { + self.record_proof_during_import = should_record_proof; + self + } + /// Build the [`TestNode`]. pub async fn build(self) -> TestNode { let parachain_config = node_config( @@ -684,24 +702,26 @@ impl TestNodeBuilder { format!("{} (relay chain)", relay_chain_config.network.node_name); let multiaddr = parachain_config.network.listen_addresses[0].clone(); - let (task_manager, client, network, rpc_handlers, transaction_pool) = start_node_impl( - parachain_config, - self.collator_key, - relay_chain_config, - self.para_id, - self.wrap_announce_block, - false, - |_| Ok(jsonrpsee::RpcModule::new(())), - self.consensus, - collator_options, - ) - .await - .expect("could not create Cumulus test service"); + let (task_manager, client, network, rpc_handlers, transaction_pool, backend) = + start_node_impl( + parachain_config, + self.collator_key, + relay_chain_config, + self.para_id, + self.wrap_announce_block, + false, + |_| Ok(jsonrpsee::RpcModule::new(())), + self.consensus, + collator_options, + self.record_proof_during_import, + ) + .await + .expect("could not create Cumulus test service"); let peer_id = network.local_peer_id(); let addr = MultiaddrWithPeerId { multiaddr, peer_id }; - TestNode { task_manager, client, network, addr, rpc_handlers, transaction_pool } + TestNode { task_manager, client, network, addr, rpc_handlers, transaction_pool, backend } } } diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index 16b68796bd3..55a0f12d671 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -128,7 +128,7 @@ fn main() -> Result<(), sc_cli::Error> { }) .unwrap_or(cumulus_test_service::Consensus::RelayChain); - let (mut task_manager, _, _, _, _) = tokio_runtime + let (mut task_manager, _, _, _, _, _) = tokio_runtime .block_on(cumulus_test_service::start_node_impl( config, collator_key, @@ -139,6 +139,7 @@ fn main() -> Result<(), sc_cli::Error> { |_| Ok(jsonrpsee::RpcModule::new(())), consensus, collator_options, + true, )) .expect("could not create Cumulus test service"); diff --git a/substrate/client/api/src/execution_extensions.rs b/substrate/client/api/src/execution_extensions.rs index 6f927105df0..26d3ae73f69 100644 --- a/substrate/client/api/src/execution_extensions.rs +++ b/substrate/client/api/src/execution_extensions.rs @@ -91,7 +91,6 @@ impl ExtensionsFactory /// /// This crate aggregates extensions available for the offchain calls /// and is responsible for producing a correct `Extensions` object. -/// for each call, based on required `Capabilities`. pub struct ExecutionExtensions { extensions_factory: RwLock>>, read_runtime_version: Arc, @@ -116,8 +115,7 @@ impl ExecutionExtensions { *self.extensions_factory.write() = Box::new(maker); } - /// Based on the execution context and capabilities it produces - /// the extensions object to support desired set of APIs. + /// Produces default extensions based on the input parameters. pub fn extensions( &self, block_hash: Block::Hash, @@ -127,7 +125,6 @@ impl ExecutionExtensions { self.extensions_factory.read().extensions_for(block_hash, block_number); extensions.register(ReadRuntimeVersionExt::new(self.read_runtime_version.clone())); - extensions } } diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 2492c4101b2..852ee84f89b 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -20,6 +20,7 @@ sp-api = { path = "../../primitives/api" } sp-block-builder = { path = "../../primitives/block-builder" } sp-blockchain = { path = "../../primitives/blockchain" } sp-core = { path = "../../primitives/core" } +sp-trie = { path = "../../primitives/trie" } sp-inherents = { path = "../../primitives/inherents" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/client/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index f62b941fdb1..258e39d962b 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -42,6 +42,7 @@ use sp_runtime::{ use std::marker::PhantomData; pub use sp_block_builder::BlockBuilder as BlockBuilderApi; +use sp_trie::proof_size_extension::ProofSizeExt; /// A builder for creating an instance of [`BlockBuilder`]. pub struct BlockBuilderBuilder<'a, B, C> { @@ -235,6 +236,10 @@ where if record_proof { api.record_proof(); + let recorder = api + .proof_recorder() + .expect("Proof recording is enabled in the line above; qed."); + api.register_extension(ProofSizeExt::new(recorder)); } api.set_call_context(CallContext::Onchain); diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index d078f44f198..1a3a679c519 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -130,10 +130,11 @@ where } /// Create the initial parts of a full node with the default genesis block builder. -pub fn new_full_parts( +pub fn new_full_parts_record_import( config: &Configuration, telemetry: Option, executor: TExec, + enable_import_proof_recording: bool, ) -> Result, Error> where TBl: BlockT, @@ -148,7 +149,26 @@ where executor.clone(), )?; - new_full_parts_with_genesis_builder(config, telemetry, executor, backend, genesis_block_builder) + new_full_parts_with_genesis_builder( + config, + telemetry, + executor, + backend, + genesis_block_builder, + enable_import_proof_recording, + ) +} +/// Create the initial parts of a full node with the default genesis block builder. +pub fn new_full_parts( + config: &Configuration, + telemetry: Option, + executor: TExec, +) -> Result, Error> +where + TBl: BlockT, + TExec: CodeExecutor + RuntimeVersionOf + Clone, +{ + new_full_parts_record_import(config, telemetry, executor, false) } /// Create the initial parts of a full node. @@ -158,6 +178,7 @@ pub fn new_full_parts_with_genesis_builder>, genesis_block_builder: TBuildGenesisBlock, + enable_import_proof_recording: bool, ) -> Result, Error> where TBl: BlockT, @@ -225,6 +246,7 @@ where SyncMode::LightState { .. } | SyncMode::Warp { .. } ), wasm_runtime_substitutes, + enable_import_proof_recording, }, )?; diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 9d51aae55b2..aa9c1b80a29 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -77,7 +77,7 @@ use sp_state_machine::{ ChildStorageCollection, KeyValueStates, KeyValueStorageLevel, StorageCollection, MAX_NESTED_TRIE_DEPTH, }; -use sp_trie::{CompactProof, MerkleValue, StorageProof}; +use sp_trie::{proof_size_extension::ProofSizeExt, CompactProof, MerkleValue, StorageProof}; use std::{ collections::{HashMap, HashSet}, marker::PhantomData, @@ -184,7 +184,7 @@ where ) } -/// Relevant client configuration items relevant for the client. +/// Client configuration items. #[derive(Debug, Clone)] pub struct ClientConfig { /// Enable the offchain worker db. @@ -198,6 +198,8 @@ pub struct ClientConfig { /// Map of WASM runtime substitute starting at the child of the given block until the runtime /// version doesn't match anymore. pub wasm_runtime_substitutes: HashMap, Vec>, + /// Enable recording of storage proofs during block import + pub enable_import_proof_recording: bool, } impl Default for ClientConfig { @@ -208,6 +210,7 @@ impl Default for ClientConfig { wasm_runtime_overrides: None, no_genesis: false, wasm_runtime_substitutes: HashMap::new(), + enable_import_proof_recording: false, } } } @@ -858,6 +861,14 @@ where runtime_api.set_call_context(CallContext::Onchain); + if self.config.enable_import_proof_recording { + runtime_api.record_proof(); + let recorder = runtime_api + .proof_recorder() + .expect("Proof recording is enabled in the line above; qed."); + runtime_api.register_extension(ProofSizeExt::new(recorder)); + } + runtime_api.execute_block( *parent_hash, Block::new(import_block.header.clone(), body.clone()), diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index ff9eb982b86..0c7e138ce90 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -53,9 +53,10 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; pub use self::{ builder::{ build_network, new_client, new_db_backend, new_full_client, new_full_parts, - new_full_parts_with_genesis_builder, new_native_or_wasm_executor, new_wasm_executor, - spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, - TFullBackend, TFullCallExecutor, TFullClient, + new_full_parts_record_import, new_full_parts_with_genesis_builder, + new_native_or_wasm_executor, new_wasm_executor, spawn_tasks, BuildNetworkParams, + KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, + TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index d1d6040d33a..010143574ed 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -253,7 +253,7 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { let res = res.unwrap_or_else(|e| e.to_compile_error()); let res = expander::Expander::new("construct_runtime") - .dry(std::env::var("FRAME_EXPAND").is_err()) + .dry(std::env::var("EXPAND_MACROS").is_err()) .verbose(true) .write_to_out_dir(res) .expect("Does not fail because of IO in OUT_DIR; qed"); diff --git a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs index 370735819f9..2b1e65ec885 100644 --- a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -729,7 +729,7 @@ fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result }; let decl = expander::Expander::new("decl_runtime_apis") - .dry(std::env::var("SP_API_EXPAND").is_err()) + .dry(std::env::var("EXPAND_MACROS").is_err()) .verbose(true) .write_to_out_dir(decl) .expect("Does not fail because of IO in OUT_DIR; qed"); 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 e97291bc58a..fd81fdb624c 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -846,7 +846,7 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { ); let impl_ = expander::Expander::new("impl_runtime_apis") - .dry(std::env::var("SP_API_EXPAND").is_err()) + .dry(std::env::var("EXPAND_MACROS").is_err()) .verbose(true) .write_to_out_dir(impl_) .expect("Does not fail because of IO in OUT_DIR; qed"); diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index fbc49785ae9..11236de91ce 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -20,4 +20,5 @@ Inflector = "0.11.4" proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" +expander = "2.0.0" syn = { version = "2.0.38", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs index 008d69b3210..d0cc9e7b96b 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs @@ -68,5 +68,11 @@ pub fn runtime_interface_impl( } }; + let res = expander::Expander::new("runtime_interface") + .dry(std::env::var("EXPAND_MACROS").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + Ok(res) } diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index 7b337b5fd54..7496463e642 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -33,12 +33,12 @@ use sp_core::storage::{ChildInfo, StateVersion}; #[cfg(feature = "std")] use sp_trie::{ cache::{LocalTrieCache, TrieCache}, - recorder::Recorder, - MemoryDB, StorageProof, + MemoryDB, }; #[cfg(not(feature = "std"))] use sp_trie::{Error, NodeCodec}; -use sp_trie::{MerkleValue, PrefixedMemoryDB}; +use sp_trie::{MerkleValue, PrefixedMemoryDB, StorageProof, TrieRecorderProvider}; + use trie_db::TrieCache as TrieCacheT; #[cfg(not(feature = "std"))] use trie_db::{node::NodeOwned, CachedValue}; @@ -112,8 +112,6 @@ pub struct UnimplementedCacheProvider { // Not strictly necessary, but the H bound allows to use this as a drop-in // replacement for the `LocalTrieCache` in no-std contexts. _phantom: core::marker::PhantomData, - // Statically prevents construction. - _infallible: core::convert::Infallible, } #[cfg(not(feature = "std"))] @@ -156,52 +154,83 @@ impl TrieCacheProvider for UnimplementedCacheProvider { } } +/// Recorder provider that allows construction of a [`TrieBackend`] and satisfies the requirements, +/// but can never be instantiated. +#[cfg(not(feature = "std"))] +pub struct UnimplementedRecorderProvider { + // Not strictly necessary, but the H bound allows to use this as a drop-in + // replacement for the [`sp_trie::recorder::Recorder`] in no-std contexts. + _phantom: core::marker::PhantomData, +} + +#[cfg(not(feature = "std"))] +impl trie_db::TrieRecorder for UnimplementedRecorderProvider { + fn record<'a>(&mut self, _access: trie_db::TrieAccess<'a, H::Out>) { + unimplemented!() + } + + fn trie_nodes_recorded_for_key(&self, _key: &[u8]) -> trie_db::RecordedForKey { + unimplemented!() + } +} + +#[cfg(not(feature = "std"))] +impl TrieRecorderProvider for UnimplementedRecorderProvider { + type Recorder<'a> = UnimplementedRecorderProvider where H: 'a; + + fn drain_storage_proof(self) -> Option { + unimplemented!() + } + + fn as_trie_recorder(&self, _storage_root: H::Out) -> Self::Recorder<'_> { + unimplemented!() + } +} + #[cfg(feature = "std")] type DefaultCache = LocalTrieCache; #[cfg(not(feature = "std"))] type DefaultCache = UnimplementedCacheProvider; +#[cfg(feature = "std")] +type DefaultRecorder = sp_trie::recorder::Recorder; + +#[cfg(not(feature = "std"))] +type DefaultRecorder = UnimplementedRecorderProvider; + /// Builder for creating a [`TrieBackend`]. -pub struct TrieBackendBuilder, H: Hasher, C = DefaultCache> { +pub struct TrieBackendBuilder< + S: TrieBackendStorage, + H: Hasher, + C = DefaultCache, + R = DefaultRecorder, +> { storage: S, root: H::Out, - #[cfg(feature = "std")] - recorder: Option>, + recorder: Option, cache: Option, } -impl TrieBackendBuilder> +impl TrieBackendBuilder where S: TrieBackendStorage, H: Hasher, { /// Create a new builder instance. pub fn new(storage: S, root: H::Out) -> Self { - Self { - storage, - root, - #[cfg(feature = "std")] - recorder: None, - cache: None, - } + Self { storage, root, recorder: None, cache: None } } } -impl TrieBackendBuilder +impl TrieBackendBuilder where S: TrieBackendStorage, H: Hasher, { /// Create a new builder instance. pub fn new_with_cache(storage: S, root: H::Out, cache: C) -> Self { - Self { - storage, - root, - #[cfg(feature = "std")] - recorder: None, - cache: Some(cache), - } + Self { storage, root, recorder: None, cache: Some(cache) } } /// Wrap the given [`TrieBackend`]. /// @@ -210,53 +239,47 @@ where /// backend. /// /// The backend storage and the cache will be taken from `other`. - pub fn wrap(other: &TrieBackend) -> TrieBackendBuilder<&S, H, &C> { + pub fn wrap(other: &TrieBackend) -> TrieBackendBuilder<&S, H, &C, R> { TrieBackendBuilder { storage: other.essence.backend_storage(), root: *other.essence.root(), - #[cfg(feature = "std")] recorder: None, cache: other.essence.trie_node_cache.as_ref(), } } /// Use the given optional `recorder` for the to be configured [`TrieBackend`]. - #[cfg(feature = "std")] - pub fn with_optional_recorder(self, recorder: Option>) -> Self { + pub fn with_optional_recorder(self, recorder: Option) -> Self { Self { recorder, ..self } } /// Use the given `recorder` for the to be configured [`TrieBackend`]. - #[cfg(feature = "std")] - pub fn with_recorder(self, recorder: Recorder) -> Self { + pub fn with_recorder(self, recorder: R) -> Self { Self { recorder: Some(recorder), ..self } } /// Use the given optional `cache` for the to be configured [`TrieBackend`]. - pub fn with_optional_cache(self, cache: Option) -> TrieBackendBuilder { + pub fn with_optional_cache(self, cache: Option) -> TrieBackendBuilder { TrieBackendBuilder { cache, root: self.root, storage: self.storage, - #[cfg(feature = "std")] recorder: self.recorder, } } /// Use the given `cache` for the to be configured [`TrieBackend`]. - pub fn with_cache(self, cache: LC) -> TrieBackendBuilder { + pub fn with_cache(self, cache: LC) -> TrieBackendBuilder { TrieBackendBuilder { cache: Some(cache), root: self.root, storage: self.storage, - #[cfg(feature = "std")] recorder: self.recorder, } } /// Build the configured [`TrieBackend`]. - #[cfg(feature = "std")] - pub fn build(self) -> TrieBackend { + pub fn build(self) -> TrieBackend { TrieBackend { essence: TrieBackendEssence::new_with_cache_and_recorder( self.storage, @@ -267,27 +290,18 @@ where next_storage_key_cache: Default::default(), } } - - /// Build the configured [`TrieBackend`]. - #[cfg(not(feature = "std"))] - pub fn build(self) -> TrieBackend { - TrieBackend { - essence: TrieBackendEssence::new_with_cache(self.storage, self.root, self.cache), - next_storage_key_cache: Default::default(), - } - } } /// A cached iterator. -struct CachedIter +struct CachedIter where H: Hasher, { last_key: sp_std::vec::Vec, - iter: RawIter, + iter: RawIter, } -impl Default for CachedIter +impl Default for CachedIter where H: Hasher, { @@ -313,23 +327,32 @@ fn access_cache(cell: &CacheCell, callback: impl FnOnce(&mut T) -> R) - } /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. -pub struct TrieBackend, H: Hasher, C = DefaultCache> { - pub(crate) essence: TrieBackendEssence, - next_storage_key_cache: CacheCell>>, +pub struct TrieBackend< + S: TrieBackendStorage, + H: Hasher, + C = DefaultCache, + R = DefaultRecorder, +> { + pub(crate) essence: TrieBackendEssence, + next_storage_key_cache: CacheCell>>, } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> - TrieBackend +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > TrieBackend where H::Out: Codec, { #[cfg(test)] - pub(crate) fn from_essence(essence: TrieBackendEssence) -> Self { + pub(crate) fn from_essence(essence: TrieBackendEssence) -> Self { Self { essence, next_storage_key_cache: Default::default() } } /// Get backend essence reference. - pub fn essence(&self) -> &TrieBackendEssence { + pub fn essence(&self) -> &TrieBackendEssence { &self.essence } @@ -361,28 +384,31 @@ where /// Extract the [`StorageProof`]. /// /// This only returns `Some` when there was a recorder set. - #[cfg(feature = "std")] pub fn extract_proof(mut self) -> Option { - self.essence.recorder.take().map(|r| r.drain_storage_proof()) + self.essence.recorder.take().and_then(|r| r.drain_storage_proof()) } } -impl, H: Hasher, C: TrieCacheProvider> sp_std::fmt::Debug - for TrieBackend +impl, H: Hasher, C: TrieCacheProvider, R: TrieRecorderProvider> + sp_std::fmt::Debug for TrieBackend { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { write!(f, "TrieBackend") } } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> Backend - for TrieBackend +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > Backend for TrieBackend where H::Out: Ord + Codec, { type Error = crate::DefaultError; type TrieBackendStorage = S; - type RawIter = crate::trie_backend_essence::RawIter; + type RawIter = crate::trie_backend_essence::RawIter; fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { self.essence.storage_hash(key) diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index ad7aeab899c..3f789111dee 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -28,19 +28,19 @@ use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; use sp_core::storage::{ChildInfo, ChildType, StateVersion}; -use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; #[cfg(feature = "std")] -use sp_trie::recorder::Recorder; +use sp_std::sync::Arc; +use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_first_descedant_value, read_child_trie_hash, read_child_trie_value, read_trie_first_descedant_value, read_trie_value, trie_types::{TrieDBBuilder, TrieError}, DBValue, KeySpacedDB, MerkleValue, NodeCodec, PrefixedMemoryDB, Trie, TrieCache, - TrieDBRawIterator, TrieRecorder, + TrieDBRawIterator, TrieRecorder, TrieRecorderProvider, }; #[cfg(feature = "std")] -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; // In this module, we only use layout for read operation and empty root, // where V1 and V0 are equivalent. use sp_trie::LayoutV1 as Layout; @@ -83,7 +83,7 @@ enum IterState { } /// A raw iterator over the storage. -pub struct RawIter +pub struct RawIter where H: Hasher, { @@ -93,25 +93,26 @@ where child_info: Option, trie_iter: TrieDBRawIterator>, state: IterState, - _phantom: PhantomData<(S, C)>, + _phantom: PhantomData<(S, C, R)>, } -impl RawIter +impl RawIter where H: Hasher, S: TrieBackendStorage, H::Out: Codec + Ord, C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, { #[inline] - fn prepare( + fn prepare( &mut self, - backend: &TrieBackendEssence, + backend: &TrieBackendEssence, callback: impl FnOnce( &sp_trie::TrieDB>, &mut TrieDBRawIterator>, - ) -> Option::Out>>>>, - ) -> Option> { + ) -> Option::Out>>>>, + ) -> Option> { if !matches!(self.state, IterState::Pending) { return None } @@ -139,7 +140,7 @@ where } } -impl Default for RawIter +impl Default for RawIter where H: Hasher, { @@ -156,14 +157,15 @@ where } } -impl StorageIterator for RawIter +impl StorageIterator for RawIter where H: Hasher, S: TrieBackendStorage, H::Out: Codec + Ord, C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, { - type Backend = crate::TrieBackend; + type Backend = crate::TrieBackend; type Error = crate::DefaultError; #[inline] @@ -204,18 +206,17 @@ where } /// Patricia trie-based pairs storage essence. -pub struct TrieBackendEssence, H: Hasher, C> { +pub struct TrieBackendEssence, H: Hasher, C, R> { storage: S, root: H::Out, empty: H::Out, #[cfg(feature = "std")] pub(crate) cache: Arc>>, pub(crate) trie_node_cache: Option, - #[cfg(feature = "std")] - pub(crate) recorder: Option>, + pub(crate) recorder: Option, } -impl, H: Hasher, C> TrieBackendEssence { +impl, H: Hasher, C, R> TrieBackendEssence { /// Create new trie-based backend. pub fn new(storage: S, root: H::Out) -> Self { Self::new_with_cache(storage, root, None) @@ -230,23 +231,22 @@ impl, H: Hasher, C> TrieBackendEssence { #[cfg(feature = "std")] cache: Arc::new(RwLock::new(Cache::new())), trie_node_cache: cache, - #[cfg(feature = "std")] recorder: None, } } /// Create new trie-based backend. - #[cfg(feature = "std")] pub fn new_with_cache_and_recorder( storage: S, root: H::Out, cache: Option, - recorder: Option>, + recorder: Option, ) -> Self { TrieBackendEssence { storage, root, empty: H::hash(&[0u8]), + #[cfg(feature = "std")] cache: Arc::new(RwLock::new(Cache::new())), trie_node_cache: cache, recorder, @@ -289,37 +289,31 @@ impl, H: Hasher, C> TrieBackendEssence { } } -impl, H: Hasher, C: TrieCacheProvider> TrieBackendEssence { +impl, H: Hasher, C: TrieCacheProvider, R: TrieRecorderProvider> + TrieBackendEssence +{ /// Call the given closure passing it the recorder and the cache. /// /// If the given `storage_root` is `None`, `self.root` will be used. #[inline] - fn with_recorder_and_cache( + fn with_recorder_and_cache( &self, storage_root: Option, callback: impl FnOnce( Option<&mut dyn TrieRecorder>, Option<&mut dyn TrieCache>>, - ) -> R, - ) -> R { + ) -> RE, + ) -> RE { let storage_root = storage_root.unwrap_or_else(|| self.root); let mut cache = self.trie_node_cache.as_ref().map(|c| c.as_trie_db_cache(storage_root)); let cache = cache.as_mut().map(|c| c as _); - #[cfg(feature = "std")] - { - let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder(storage_root)); - let recorder = match recorder.as_mut() { - Some(recorder) => Some(recorder as &mut dyn TrieRecorder), - None => None, - }; - callback(recorder, cache) - } - - #[cfg(not(feature = "std"))] - { - callback(None, cache) - } + let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder(storage_root)); + let recorder = match recorder.as_mut() { + Some(recorder) => Some(recorder as &mut dyn TrieRecorder), + None => None, + }; + callback(recorder, cache) } /// Call the given closure passing it the recorder and the cache. @@ -329,15 +323,14 @@ impl, H: Hasher, C: TrieCacheProvider> TrieBackendEs /// the new storage root. This is required to register the changes in the cache /// for the correct storage root. The given `storage_root` corresponds to the root of the "old" /// trie. If the value is not given, `self.root` is used. - #[cfg(feature = "std")] - fn with_recorder_and_cache_for_storage_root( + fn with_recorder_and_cache_for_storage_root( &self, storage_root: Option, callback: impl FnOnce( Option<&mut dyn TrieRecorder>, Option<&mut dyn TrieCache>>, - ) -> (Option, R), - ) -> R { + ) -> (Option, RE), + ) -> RE { let storage_root = storage_root.unwrap_or_else(|| self.root); let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder(storage_root)); let recorder = match recorder.as_mut() { @@ -361,46 +354,26 @@ impl, H: Hasher, C: TrieCacheProvider> TrieBackendEs result } - - #[cfg(not(feature = "std"))] - fn with_recorder_and_cache_for_storage_root( - &self, - _storage_root: Option, - callback: impl FnOnce( - Option<&mut dyn TrieRecorder>, - Option<&mut dyn TrieCache>>, - ) -> (Option, R), - ) -> R { - if let Some(local_cache) = self.trie_node_cache.as_ref() { - let mut cache = local_cache.as_trie_db_mut_cache(); - - let (new_root, r) = callback(None, Some(&mut cache)); - - if let Some(new_root) = new_root { - local_cache.merge(cache, new_root); - } - - r - } else { - callback(None, None).1 - } - } } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> - TrieBackendEssence +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > TrieBackendEssence where H::Out: Codec + Ord, { /// Calls the given closure with a [`TrieDb`] constructed for the given /// storage root and (optionally) child trie. #[inline] - fn with_trie_db( + fn with_trie_db( &self, root: H::Out, child_info: Option<&ChildInfo>, - callback: impl FnOnce(&sp_trie::TrieDB>) -> R, - ) -> R { + callback: impl FnOnce(&sp_trie::TrieDB>) -> RE, + ) -> RE { let backend = self as &dyn HashDBRef>; let db = child_info .as_ref() @@ -609,7 +582,7 @@ where } /// Create a raw iterator over the storage. - pub fn raw_iter(&self, args: IterArgs) -> Result> { + pub fn raw_iter(&self, args: IterArgs) -> Result> { let root = if let Some(child_info) = args.child_info.as_ref() { let root = match self.child_root(&child_info)? { Some(root) => root, @@ -831,19 +804,28 @@ where } } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> - AsHashDB for TrieBackendEssence +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > AsHashDB for TrieBackendEssence { fn as_hash_db<'b>(&'b self) -> &'b (dyn HashDB + 'b) { self } + fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB + 'b) { self } } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> HashDB - for TrieBackendEssence +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > HashDB for TrieBackendEssence { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { if *key == self.empty { @@ -875,8 +857,12 @@ impl, H: Hasher, C: TrieCacheProvider + Send + Sync> } } -impl, H: Hasher, C: TrieCacheProvider + Send + Sync> - HashDBRef for TrieBackendEssence +impl< + S: TrieBackendStorage, + H: Hasher, + C: TrieCacheProvider + Send + Sync, + R: TrieRecorderProvider + Send + Sync, + > HashDBRef for TrieBackendEssence { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { HashDB::get(self, key, prefix) @@ -928,7 +914,10 @@ mod test { .expect("insert failed"); }; - let essence_1 = TrieBackendEssence::<_, _, LocalTrieCache<_>>::new(mdb, root_1); + let essence_1 = + TrieBackendEssence::<_, _, LocalTrieCache<_>, sp_trie::recorder::Recorder<_>>::new( + mdb, root_1, + ); let mdb = essence_1.backend_storage().clone(); let essence_1 = TrieBackend::from_essence(essence_1); @@ -938,7 +927,10 @@ mod test { assert_eq!(essence_1.next_storage_key(b"5"), Ok(Some(b"6".to_vec()))); assert_eq!(essence_1.next_storage_key(b"6"), Ok(None)); - let essence_2 = TrieBackendEssence::<_, _, LocalTrieCache<_>>::new(mdb, root_2); + let essence_2 = + TrieBackendEssence::<_, _, LocalTrieCache<_>, sp_trie::recorder::Recorder<_>>::new( + mdb, root_2, + ); assert_eq!(essence_2.next_child_storage_key(child_info, b"2"), Ok(Some(b"3".to_vec()))); assert_eq!(essence_2.next_child_storage_key(child_info, b"3"), Ok(Some(b"4".to_vec()))); diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 0822d84a76e..931ccce2044 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -34,6 +34,7 @@ trie-db = { version = "0.28.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } sp-core = { path = "../core", default-features = false} sp-std = { path = "../std", default-features = false} +sp-externalities = { path = "../externalities", default-features = false } schnellru = { version = "0.2.1", optional = true } [dev-dependencies] @@ -58,6 +59,7 @@ std = [ "scale-info/std", "schnellru", "sp-core/std", + "sp-externalities/std", "sp-runtime/std", "sp-std/std", "thiserror", diff --git a/substrate/primitives/trie/src/lib.rs b/substrate/primitives/trie/src/lib.rs index 1a1ed670454..fd1320b3fbc 100644 --- a/substrate/primitives/trie/src/lib.rs +++ b/substrate/primitives/trie/src/lib.rs @@ -30,6 +30,9 @@ mod storage_proof; mod trie_codec; mod trie_stream; +#[cfg(feature = "std")] +pub mod proof_size_extension; + /// Our `NodeCodec`-specific error. pub use error::Error; /// Various re-exports from the `hash-db` crate. @@ -146,6 +149,29 @@ where } } +/// Type that is able to provide a [`trie_db::TrieRecorder`]. +/// +/// Types implementing this trait can be used to maintain recorded state +/// across operations on different [`trie_db::TrieDB`] instances. +pub trait TrieRecorderProvider { + /// Recorder type that is going to be returned by implementors of this trait. + type Recorder<'a>: trie_db::TrieRecorder + 'a + where + Self: 'a; + + /// Create a [`StorageProof`] derived from the internal state. + fn drain_storage_proof(self) -> Option; + + /// Provide a recorder implementing [`trie_db::TrieRecorder`]. + fn as_trie_recorder(&self, storage_root: H::Out) -> Self::Recorder<'_>; +} + +/// Type that is able to provide a proof size estimation. +pub trait ProofSizeProvider { + /// Returns the storage proof size. + fn estimate_encoded_size(&self) -> usize; +} + /// TrieDB error over `TrieConfiguration` trait. pub type TrieError = trie_db::TrieError, CError>; /// Reexport from `hash_db`, with genericity set for `Hasher` trait. diff --git a/substrate/primitives/trie/src/proof_size_extension.rs b/substrate/primitives/trie/src/proof_size_extension.rs new file mode 100644 index 00000000000..c97f334494a --- /dev/null +++ b/substrate/primitives/trie/src/proof_size_extension.rs @@ -0,0 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Externalities extension that provides access to the current proof size +//! of the underlying recorder. + +use crate::ProofSizeProvider; + +sp_externalities::decl_extension! { + /// The proof size extension to fetch the current storage proof size + /// in externalities. + pub struct ProofSizeExt(Box); +} + +impl ProofSizeExt { + /// Creates a new instance of [`ProofSizeExt`]. + pub fn new(recorder: T) -> Self { + ProofSizeExt(Box::new(recorder)) + } + + /// Returns the storage proof size. + pub fn storage_proof_size(&self) -> u64 { + self.0.estimate_encoded_size() as _ + } +} diff --git a/substrate/primitives/trie/src/recorder.rs b/substrate/primitives/trie/src/recorder.rs index 154cee3f37d..b236f281bb1 100644 --- a/substrate/primitives/trie/src/recorder.rs +++ b/substrate/primitives/trie/src/recorder.rs @@ -23,7 +23,7 @@ use crate::{NodeCodec, StorageProof}; use codec::Encode; use hash_db::Hasher; -use parking_lot::Mutex; +use parking_lot::{Mutex, MutexGuard}; use std::{ collections::{HashMap, HashSet}, marker::PhantomData, @@ -80,7 +80,9 @@ impl Default for RecorderInner { /// The trie recorder. /// -/// It can be used to record accesses to the trie and then to convert them into a [`StorageProof`]. +/// Owns the recorded data. Is used to transform data into a storage +/// proof and to provide transaction support. The `as_trie_recorder` method provides a +/// [`trie_db::TrieDB`] compatible recorder that implements the actual recording logic. pub struct Recorder { inner: Arc>>, /// The estimated encoded size of the storage proof this recorder will produce. @@ -112,11 +114,8 @@ impl Recorder { /// /// NOTE: This locks a mutex that stays locked until the return value is dropped. #[inline] - pub fn as_trie_recorder( - &self, - storage_root: H::Out, - ) -> impl trie_db::TrieRecorder + '_ { - TrieRecorder:: { + pub fn as_trie_recorder(&self, storage_root: H::Out) -> TrieRecorder<'_, H> { + TrieRecorder:: { inner: self.inner.lock(), storage_root, encoded_size_estimation: self.encoded_size_estimation.clone(), @@ -231,15 +230,33 @@ impl Recorder { } } +impl crate::ProofSizeProvider for Recorder { + fn estimate_encoded_size(&self) -> usize { + Recorder::estimate_encoded_size(self) + } +} + /// The [`TrieRecorder`](trie_db::TrieRecorder) implementation. -struct TrieRecorder { - inner: I, +pub struct TrieRecorder<'a, H: Hasher> { + inner: MutexGuard<'a, RecorderInner>, storage_root: H::Out, encoded_size_estimation: Arc, _phantom: PhantomData, } -impl>> TrieRecorder { +impl crate::TrieRecorderProvider for Recorder { + type Recorder<'a> = TrieRecorder<'a, H> where H: 'a; + + fn drain_storage_proof(self) -> Option { + Some(Recorder::drain_storage_proof(self)) + } + + fn as_trie_recorder(&self, storage_root: H::Out) -> Self::Recorder<'_> { + Recorder::as_trie_recorder(&self, storage_root) + } +} + +impl<'a, H: Hasher> TrieRecorder<'a, H> { /// Update the recorded keys entry for the given `full_key`. fn update_recorded_keys(&mut self, full_key: &[u8], access: RecordedForKey) { let inner = self.inner.deref_mut(); @@ -283,9 +300,7 @@ impl>> TrieRecorder } } -impl>> trie_db::TrieRecorder - for TrieRecorder -{ +impl<'a, H: Hasher> trie_db::TrieRecorder for TrieRecorder<'a, H> { fn record(&mut self, access: TrieAccess) { let mut encoded_size_update = 0; -- GitLab From c30ed6f2ff0b88c37b690884d9049ce05ebd34a4 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Thu, 30 Nov 2023 17:36:14 +0100 Subject: [PATCH 627/633] Add missing glossary to ref docs (#2572) This PR is the same as https://github.com/paritytech/polkadot-sdk/pull/2273, but that one had too many conflicts after a base change. As it is a just one file PR I decided to start over with a clean slate. --- This PR adds some missing glossary definitions to the Developer Hub ref docs FIxes https://github.com/paritytech/polkadot-sdk-docs/issues/40 --- developer-hub/src/reference_docs/glossary.rs | 64 +++++++++++++++++++- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/developer-hub/src/reference_docs/glossary.rs b/developer-hub/src/reference_docs/glossary.rs index d0bd6accce6..56f5ef5aeb5 100644 --- a/developer-hub/src/reference_docs/glossary.rs +++ b/developer-hub/src/reference_docs/glossary.rs @@ -36,27 +36,85 @@ //! //! #### Offchain //! -//! #### Host Function: +//! Refers to operations conducted outside the blockchain's consensus mechanism. They are essential +//! for enhancing scalability and efficiency, enabling activities like data fetching and computation +//! without bloating the blockchain state. +//! +//! #### Host Functions: +//! +//! Host functions are the node's API, these are functions provided by the runtime environment (the +//! [host](#host)) to the Wasm runtime. These functions allow the Wasm code to interact with and +//! perform operations on the [node](#node), like accessing the blockchain state. //! //! #### Runtime API: //! +//! This is the API of the runtime, it acts as a communication bridge between the runtime and the +//! node, serving as the exposed interface that facilitates their interactions. +//! //! #### Dispatchable: //! -//! Callable +//! Dispatchables are [function objects](https://en.wikipedia.org/wiki/Function_object) that act as +//! the entry points in [FRAME](frame) pallets. They can be called by internal or external entities +//! to interact with the blockchain's state. They are a core aspect of the runtime logic, handling +//! transactions and other state-changing operations. +//! +//! **Synonyms**: Callable //! //! #### Extrinsic //! +//! An extrinsic is a general term for a piece of data that is originated outside of the runtime, +//! included into a block and leads to some action. This includes user-initiated transactions as +//! well as inherents which are placed into the block by the block-builder. //! //! #### Pallet //! +//! Similar to software modules in traditional programming, [FRAME](frame) pallets in Substrate are +//! modular components that encapsulate distinct functionalities or business logic. Just as +//! libraries or modules are used to build and extend the capabilities of a software application, +//! pallets are the foundational building blocks for constructing a blockchain's runtime with frame. +//! They enable the creation of customizable and upgradeable networks, offering a composable +//! framework for a Substrate-based blockchain. Each pallet can be thought of as a plug-and-play +//! module, enhancing the blockchain's functionality in a cohesive and integrated manner. +//! //! #### Full Node //! +//! It is a node that prunes historical states, keeping only recent finalized block states to reduce +//! storage needs. Full nodes provide current chain state access and allow direct submission and +//! validation of extrinsics, maintaining network decentralization. +//! //! #### Archive Node //! +//! An archive node is a specialized node that maintains a complete history of all block states and +//! transactions. Unlike a full node, it does not prune historical data, ensuring full access to the +//! entire blockchain history. This makes it essential for detailed blockchain analysis and +//! historical queries, but requires significantly more storage capacity. +//! //! #### Validator //! +//! A validator is a node that participates in the consensus mechanism of the network. +//! Its role includes block production, transaction validation, network integrity and security +//! maintenance. +//! //! #### Collator //! +//! A collator is a node that is responsible for producing candidate blocks for the validators. +//! Collators are similar to validators on any other blockchain but, they do not need to provide +//! security guarantees as the Relay Chain handles this. +//! //! #### Parachain //! -//! aka. AppChain. +//! Short for "parallelized chain" a parachain is a specialized blockchain that runs in parallel to +//! the Relay Chain (Polkadot, Kusama, etc.), benefiting from the shared security and +//! interoperability features of it. +//! +//! **Synonyms**: AppChain +//! +//! #### PVF +//! The Parachain Validation Function (PVF) is the current runtime Wasm for a parachain that is +//! stored on the Relay chain. It is an essential component in the Polkadot ecosystem, encapsulating +//! the validation logic for each parachain. The PVF is executed by validators to verify the +//! correctness of parachain blocks. This is critical for ensuring that each block follows the logic +//! set by its respective parachain, thus maintaining the integrity and security of the entire +//! network. +//! +//! **Synonyms**: Parachain Validation Function -- GitLab From 6742aba05f21da1c890450a666d0fa27c87ca7c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:04:12 +0100 Subject: [PATCH 628/633] Bump the known_good_semver group with 2 updates (#2570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the known_good_semver group with 2 updates: [serde](https://github.com/serde-rs/serde) and [clap](https://github.com/clap-rs/clap). Updates `serde` from 1.0.188 to 1.0.193
Release notes

Sourced from serde's releases.

v1.0.193

v1.0.192

v1.0.191

  • Documentation improvements

v1.0.190

  • Preserve NaN sign when deserializing f32 from f64 or vice versa (#2637)

v1.0.189

  • Fix "cannot infer type" error when internally tagged enum contains untagged variant (#2613, thanks @​ahl)
Commits
  • 44613c7 Release 1.0.193
  • c706281 Merge pull request #2655 from dtolnay/rangestartend
  • 65d75b8 Add RangeFrom and RangeTo tests
  • 332b0cb Merge pull request #2654 from dtolnay/rangestartend
  • 8c4af41 Fix more RangeFrom / RangeEnd mixups
  • 24a78f0 Merge pull request #2653 from emilbonnek/fix/range-to-from-de-mixup
  • c91c334 Fix Range{From,To} deserialize mixup
  • 2083f43 Update ui test suite to nightly-2023-11-19
  • 4676abd Release 1.0.192
  • 35700eb Merge pull request #2646 from robsdedude/fix/2643/allow-tag-field-in-untagged
  • Additional commits viewable in compare view

Updates `clap` from 4.4.6 to 4.4.10
Release notes

Sourced from clap's releases.

v4.4.10

[4.4.10] - 2023-11-28

Documentation

  • Link out to changelog
  • Cross link derive's attribute reference to derive tutorial

v4.4.9

[4.4.9] - 2023-11-27

Fixes

  • (help) Show correct Command::about under flattened headings
  • (help) Respect hide when flattening subcommands

v4.4.8

[4.4.8] - 2023-11-10

Features

  • Add Command::flatten_help to allow git stash -h like help for subcommands
Changelog

Sourced from clap's changelog.

[4.4.10] - 2023-11-28

Documentation

  • Link out to changelog
  • Cross link derive's attribute reference to derive tutorial

[4.4.9] - 2023-11-27

Fixes

  • (help) Show correct Command::about under flattened headings
  • (help) Respect hide when flattening subcommands

[4.4.8] - 2023-11-10

Features

  • Add Command::flatten_help to allow git stash -h like help for subcommands

[4.4.7] - 2023-10-24

Performance

  • Reduced code size
Commits
  • c0a1814 chore: Release
  • c83e681 docs: Update changelog
  • 91bcac4 Merge pull request #5230 from epage/migrate
  • 030d875 docs: Link out to the changelog at the relevant tag
  • b661a9d Merge pull request #5229 from epage/derive
  • a08587b docs(derive): Link to tutorial sections for attributes
  • 21b671f chore: Release
  • 93ba76d docs: Update changelog
  • c1c55b3 Merge pull request #5228 from epage/flat
  • b13f6d9 fix(help): Hide 'help' if only flattened subcommand
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 84 +++++++++---------- cumulus/client/cli/Cargo.toml | 2 +- .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 4 +- .../pallets/template/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 4 +- cumulus/test/service/Cargo.toml | 4 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 2 +- polkadot/parachain/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 2 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- substrate/bin/minimal/node/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 4 +- substrate/bin/node/cli/Cargo.toml | 6 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 4 +- .../client/consensus/babe/rpc/Cargo.toml | 2 +- substrate/client/consensus/beefy/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/grandpa/Cargo.toml | 2 +- .../client/consensus/grandpa/rpc/Cargo.toml | 2 +- .../merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 2 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/service/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/tracing/Cargo.toml | 2 +- substrate/client/transaction-pool/Cargo.toml | 2 +- .../client/transaction-pool/api/Cargo.toml | 2 +- substrate/frame/beefy-mmr/Cargo.toml | 2 +- substrate/frame/beefy/Cargo.toml | 2 +- substrate/frame/benchmarking/Cargo.toml | 2 +- substrate/frame/conviction-voting/Cargo.toml | 2 +- substrate/frame/democracy/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- substrate/frame/message-queue/Cargo.toml | 2 +- substrate/frame/mixnet/Cargo.toml | 2 +- substrate/frame/offences/Cargo.toml | 2 +- substrate/frame/referenda/Cargo.toml | 2 +- substrate/frame/remark/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- .../frame/state-trie-migration/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 2 +- .../frame/support/test/pallet/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/tips/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../frame/transaction-storage/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- .../primitives/application-crypto/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- .../primitives/consensus/babe/Cargo.toml | 2 +- .../primitives/consensus/beefy/Cargo.toml | 2 +- .../primitives/consensus/grandpa/Cargo.toml | 2 +- .../primitives/consensus/sassafras/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- .../merkle-mountain-range/Cargo.toml | 2 +- .../primitives/npos-elections/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- substrate/primitives/rpc/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/primitives/staking/Cargo.toml | 2 +- substrate/primitives/storage/Cargo.toml | 2 +- .../primitives/test-primitives/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/primitives/weights/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 2 +- substrate/test-utils/runtime/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 4 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../frame/remote-externalities/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 4 +- 98 files changed, 148 insertions(+), 148 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7caa46cad8..05715ad8dfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2497,23 +2497,23 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" dependencies = [ "clap_builder", - "clap_derive 4.4.2", + "clap_derive 4.4.7", ] [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.1", + "clap_lex 0.6.0", "strsim", "terminal_size", ] @@ -2524,7 +2524,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", ] [[package]] @@ -2542,9 +2542,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -2563,9 +2563,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "coarsetime" @@ -3099,7 +3099,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.6", + "clap 4.4.10", "criterion-plot", "futures", "is-terminal", @@ -3274,7 +3274,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3995,7 +3995,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.6", + "clap 4.4.10", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -5307,7 +5307,7 @@ dependencies = [ "Inflector", "array-bytes 6.1.0", "chrono", - "clap 4.4.6", + "clap 4.4.10", "comfy-table", "frame-benchmarking", "frame-support", @@ -5399,7 +5399,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -7977,7 +7977,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-node" version = "4.0.0-dev" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame", "futures", "futures-timer", @@ -8383,7 +8383,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes 6.1.0", - "clap 4.4.6", + "clap 4.4.10", "derive_more", "fs_extra", "futures", @@ -8458,7 +8458,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "generate-bags", "kitchensink-runtime", ] @@ -8467,7 +8467,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8511,7 +8511,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "flate2", "fs_extra", "glob", @@ -11029,7 +11029,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11779,7 +11779,7 @@ dependencies = [ name = "polkadot-cli" version = "1.1.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame-benchmarking-cli", "futures", "log", @@ -12616,7 +12616,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.4.6", + "clap 4.4.10", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13110,7 +13110,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.6", + "clap 4.4.10", "color-eyre", "futures", "futures-timer", @@ -13257,7 +13257,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "generate-bags", "sp-io", "westend-runtime", @@ -14058,7 +14058,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -14831,7 +14831,7 @@ dependencies = [ "array-bytes 6.1.0", "bip39", "chrono", - "clap 4.4.6", + "clap 4.4.10", "fdlimit", "futures", "futures-timer", @@ -15975,7 +15975,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "fs4", "log", "sc-client-db", @@ -16431,18 +16431,18 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -17519,7 +17519,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -18027,7 +18027,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "log", "sc-chain-spec", "serde_json", @@ -18040,7 +18040,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes 6.1.0", "assert_cmd", - "clap 4.4.6", + "clap 4.4.10", "clap_complete", "criterion 0.4.0", "frame-benchmarking", @@ -18145,7 +18145,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -18354,7 +18354,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "sc-cli", ] @@ -18396,7 +18396,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "frame-support", "frame-system", "sc-cli", @@ -18871,7 +18871,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "futures", "futures-timer", "log", @@ -18919,7 +18919,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.6", + "clap 4.4.10", "futures", "futures-timer", "log", @@ -19594,7 +19594,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.6", + "clap 4.4.10", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 0f942feb595..35945bf4052 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -7,7 +7,7 @@ description = "Parachain node CLI utilities." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 0159cade23f..67ee3571c04 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -36,7 +36,7 @@ tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" serde_json = "1.0.108" -serde = "1.0.188" +serde = "1.0.193" schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 73bbbb6d771..ba4060f54f9 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -11,10 +11,10 @@ build = "build.rs" publish = false [dependencies] -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.28" serde_json = "1.0.108" diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index 92545783934..4267341a2d7 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -21,7 +21,7 @@ frame-support = { path = "../../../../substrate/frame/support", default-features frame-system = { path = "../../../../substrate/frame/system", default-features = false} [dev-dependencies] -serde = { version = "1.0.188" } +serde = { version = "1.0.193" } # Substrate sp-core = { path = "../../../../substrate/primitives/core", default-features = false} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 42ea63bfea5..809e952ccb9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4.20", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = [ "derive", ] } -serde = { version = "1.0.188", optional = true, features = ["derive"] } +serde = { version = "1.0.193", optional = true, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 4d2e60d971d..90d72ea3edc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -14,7 +14,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = hex-literal = { version = "0.4.1" } log = { version = "0.4.20", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true, features = ["derive"] } +serde = { version = "1.0.193", optional = true, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index a7fdfb5d6c9..cae9b3b6889 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -13,12 +13,12 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.20" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" # Local diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index ed8c8748cc8..e35173ecf16 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -11,12 +11,12 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", 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"] } rand = "0.8.5" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" tokio = { version = "1.32.0", features = ["macros"] } tracing = "0.1.37" diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 0c2925c76e8..768077b8bf2 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.6", features = ["derive"], optional = true } +clap = { version = "4.4.10", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.48" futures = "0.3.21" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index f52f0cc0282..cd0a25d7593 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index c39fd5947b0..6c37ebb986f 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -21,7 +21,7 @@ polkadot-parachain-primitives = { path = "../../parachain", default-features = f schnorrkel = "0.9.1" thiserror = "1.0.48" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.12.4", default-features = false } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 19efd1b66c4..b5aa46a41dc 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -82,7 +82,7 @@ is_executable = "1.0.1" gum = { package = "tracing-gum", path = "../gum" } log = "0.4.17" schnellru = "0.2.1" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" thiserror = "1.0.48" kvdb = "0.13.0" diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 27aa117a87f..9aa4dc10a5f 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -21,7 +21,7 @@ derive_more = "0.99.11" bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } # all optional crates. -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } [features] default = [ "std" ] diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 70f2ae769a8..eeb367f8aee 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 578c3d6715d..b7eab13bb9c 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 316644a372d..78a25d67081 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -11,7 +11,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "se hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } application-crypto = { package = "sp-application-crypto", path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } inherents = { package = "sp-inherents", path = "../../substrate/primitives/inherents", default-features = false } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 4391b6d81eb..053eb88967f 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc"] } serde_derive = { version = "1.0.117" } static_assertions = "1.1.0" diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index b6800fc0844..9e8c9a5c759 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } derive_more = "0.99.17" bitflags = "1.3.2" diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 9693d351cf4..926768e9748 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.188", default-features = false } +serde = { version = "1.0.193", default-features = false } serde_derive = { version = "1.0.117", optional = true } static_assertions = "1.1.0" smallvec = "1.8.0" diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 29debad7b53..85e452d1bd4 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false } +serde = { version = "1.0.193", default-features = false } serde_derive = { version = "1.0.117", optional = true } smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index eaebf01e3a7..c31db2703c1 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ scale-info = { version = "2.10.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 = { version = "1.0.193", default-features = false } serde_derive = { version = "1.0.117", optional = true } smallvec = "1.8.0" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index ed29001aa4f..1cd7b057c87 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true description = "CLI to generate voter bags for Polkadot runtimes" [dependencies] -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index e305edc039b..7f0c49f0c26 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -15,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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 60c27f7fcfc..8190b812bf6 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -14,7 +14,7 @@ log = { version = "0.4.17", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len" ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } -serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } xcm-procedural = { path = "procedural" } environmental = { version = "1.1.4", default-features = false } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index cc5d7d97c45..209c826b8f8 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true bounded-collections = { version = "0.1.8", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true, features = ["derive"] } +serde = { version = "1.0.193", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } frame-support = { path = "../../../substrate/frame/support", default-features = false} diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 0506d0838f1..56f123a4719 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "minimal-node" [dependencies] -clap = { version = "4.0.9", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.16.2", features = ["server"] } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 61953631d79..ed1980fbb82 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} serde_json = "1.0.108" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index ee429ee8c0c..a3fb8b43030 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } @@ -21,7 +21,7 @@ kitchensink-runtime = { path = "../runtime" } sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 656d6f86505..3e8ffdf83d0 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -38,9 +38,9 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.4.6", features = ["derive"], optional = true } +clap = { version = "4.4.10", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.21" log = "0.4.17" @@ -157,7 +157,7 @@ sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } [build-dependencies] -clap = { version = "4.4.6", optional = true } +clap = { version = "4.4.10", optional = true } clap_complete = { version = "4.0.2", optional = true } node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index cfdec6af5de..a5187d8f265 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index f587989e003..bfa2951cf00 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -20,7 +20,7 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } log = "0.4.17" sc-chain-spec = { path = "../../../client/chain-spec" } serde_json = "1.0.108" diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 6606d8ac365..1769afd865b 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 5b7cdda8ebe..009f8cef957 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } memmap2 = "0.5.0" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index c4464c5f787..54280d4bf15 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.6", features = ["derive", "string", "wrap_help"] } +clap = { version = "4.4.10", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" @@ -26,7 +26,7 @@ parity-scale-codec = "3.6.1" rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" thiserror = "1.0.48" bip39 = "2.0.0" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index c95d95ae427..f6551b2ed54 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } futures = "0.3.21" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0" sc-consensus-babe = { path = ".." } sc-consensus-epochs = { path = "../../epochs" } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index aae5a44d7fa..6ee70b523bc 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -38,7 +38,7 @@ sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] -serde = "1.0.188" +serde = "1.0.193" tempfile = "3.1.0" tokio = "1.22.0" sc-block-builder = { path = "../../block-builder" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index c7464fdc653..c077908c93c 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4" parking_lot = "0.12.1" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0" sc-consensus-beefy = { path = ".." } sp-consensus-beefy = { path = "../../../../primitives/consensus/beefy" } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 85f98e7546e..e1baff3bbf2 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -53,7 +53,7 @@ sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } -serde = "1.0.188" +serde = "1.0.193" tokio = "1.22.0" sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index e2f9e40afb2..2e808ac0bdd 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -15,7 +15,7 @@ futures = "0.3.16" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.6.1", features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0" sc-client-api = { path = "../../../api" } sc-consensus-grandpa = { path = ".." } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index e75c5f1baa8..c64354abaaf 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 8b599f058f7..2a14ef2dd84 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -33,7 +33,7 @@ parking_lot = "0.12.1" partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" smallvec = "1.11.0" thiserror = "1.0" diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index e72bbe48ee3..baf94f342ef 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index de69c50702a..63c498964fe 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -34,7 +34,7 @@ log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 4c1f2e46504..66302982bee 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.6", features = ["derive", "string"] } +clap = { version = "4.4.10", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.7.0" sc-client-db = { path = "../db", default-features = false} diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 569cd067f27..da5d22c2b9a 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" thiserror = "1.0.48" sc-chain-spec = { path = "../chain-spec" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 86f03050c44..4cd1b222bc6 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -21,7 +21,7 @@ rand = "0.8.5" rand_pcg = "0.3.1" derive_more = "0.99" regex = "1" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index a693a2884b5..71119df1153 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -22,7 +22,7 @@ parking_lot = "0.12.1" pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" thiserror = "1.0.48" wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index 796d4f1d826..844969c5ce2 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -23,7 +23,7 @@ log = { version = "0.4.17" } parking_lot = "0.12.1" regex = "1.6.0" rustc-hash = "1.1.0" -serde = "1.0.188" +serde = "1.0.193" thiserror = "1.0.48" tracing = "0.1.29" tracing-log = "0.1.3" diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index b893dc839ed..3e90304497f 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -20,7 +20,7 @@ futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" parking_lot = "0.12.1" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0.48" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index f5760c271ad..dad1e52bb54 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -13,7 +13,7 @@ async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" log = "0.4.17" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0.48" sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core", default-features = false} diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index fe0321bea51..ee2c13e7ffd 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -13,7 +13,7 @@ array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 1da09321342..9a88de1df15 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-authorship = { path = "../authorship", default-features = false} diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 79f35f62625..c3a17bc82b3 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ linregress = { version = "0.5.1", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-support = { path = "../support", default-features = false} frame-support-procedural = { path = "../support/procedural", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index 1dc723576dc..bc0ff0f9dc5 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "max-encoded-len", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"], optional = true } +serde = { version = "1.0.193", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 870bfaa9b89..5be38214cf8 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"], optional = true } +serde = { version = "1.0.193", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index cc90ed119ad..50f5bd908c7 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 48304cd882c..98ca3f60cc8 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -11,7 +11,7 @@ description = "FRAME pallet to queue and process messages" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true, features = ["derive"] } +serde = { version = "1.0.193", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index 665c606fc37..12597b8b5d5 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -19,7 +19,7 @@ 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.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive"] } +serde = { version = "1.0.193", 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" } diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index ac204a7813a..c1cb950069a 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} pallet-balances = { path = "../balances", default-features = false} diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 4f53e2bc002..d892fa32a6a 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"], optional = true } +serde = { version = "1.0.193", features = ["derive"], optional = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index ad04140ae9f..fe80d03c8d2 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index c5cac9fefa7..8fb0025e58f 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"]} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"]} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 9e81397fadd..93e4d80b9ac 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index b8e21e60761..887128e9561 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", default-features = false } -serde = { version = "1.0.188", default-features = false, features = ["alloc", "derive"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index fc10725e814..54f14df75bc 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" -serde = { version = "1.0.188", default-features = false, features = ["derive"] } +serde = { version = "1.0.193", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index c96e22ff1ab..8d0f252326d 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive"] } +serde = { version = "1.0.193", default-features = false, features = ["derive"] } frame-support = { path = "../..", default-features = false} frame-system = { path = "../../../system", default-features = false} sp-runtime = { path = "../../../../primitives/runtime", default-features = false} diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 8f7e0052fe0..8de44947dc0 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } frame-support = { path = "../support", default-features = false} sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-io = { path = "../../primitives/io", default-features = false} diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 6df886b93d7..a189c6691af 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"], optional = true } +serde = { version = "1.0.193", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index ad384755614..407740cfc0f 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} sp-core = { path = "../../primitives/core", default-features = false} diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index ae236728cd5..59232a72b99 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -27,7 +27,7 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } [dev-dependencies] serde_json = "1.0.108" diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index e90f063427b..a847ca6a790 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", optional = true } +serde = { version = "1.0.193", optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 6fb23380f82..c9fdb3d5b90 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = docify = "0.2.0" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive"], optional = true } +serde = { version = "1.0.193", features = ["derive"], optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} frame-support = { path = "../support", default-features = false} frame-system = { path = "../system", default-features = false} diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index a4a1bc44a69..7896df94913 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { path = "../core", default-features = false} codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } sp-std = { path = "../std", default-features = false} sp-io = { path = "../io", default-features = false} diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 249aebec68f..ff938795aa3 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index db8bb8cb154..f952a8ab4ee 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-consensus-slots = { path = "../slots", default-features = false} diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index e78323c8980..67c6ad57e2d 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-core = { path = "../../core", default-features = false } diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index 8757869995d..ffba6490823 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } +serde = { version = "1.0.193", features = ["derive", "alloc"], default-features = false, optional = true } sp-api = { path = "../../api", default-features = false} sp-application-crypto = { path = "../../application-crypto", default-features = false} sp-core = { path = "../../core", default-features = false} diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 696e0a64596..2c5971e919e 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive"], optional = true } 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" } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 34485c72ab0..fe82a2cd62e 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.188", optional = true, default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", optional = true, default-features = false, features = ["derive", "alloc"] } bounded-collections = { version = "0.1.8", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 5216765825f..89e03f1cabf 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } -serde = { version = "1.0.188", features = ["derive", "alloc"], default-features = false, optional = true } +serde = { version = "1.0.193", features = ["derive", "alloc"], default-features = false, optional = true } sp-api = { path = "../api", default-features = false} sp-core = { path = "../core", default-features = false} sp-debug-derive = { path = "../debug-derive", default-features = false} diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 90418e561f2..44a53e856ba 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 5e75f926f87..8bba69a7543 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index 77bdcc4f89a..cf10af31977 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rustc-hash = "1.1.0" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } sp-core = { path = "../core" } [dev-dependencies] diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 40a53d8d9e3..9e2dc8b0265 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index ef96276a003..bc69e2f61c1 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 11e574f1c4c..95fa27e9cfb 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } sp-debug-derive = { path = "../debug-derive", default-features = false} sp-std = { path = "../std", default-features = false} diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index a3775d7f61f..cacc3d86d17 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive"], optional = true } sp-application-crypto = { path = "../application-crypto", default-features = false} sp-core = { path = "../core", default-features = false} sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 41a83f01f66..7f272ead8d9 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } thiserror = { version = "1.0.48", optional = true } sp-core-hashing-proc-macro = { path = "../core/hashing/proc-macro" } sp-runtime = { path = "../runtime", default-features = false} diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 6642f97029f..c36714a76a3 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.188", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false} sp-core = { path = "../core", default-features = false} diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 73ffce8645b..59c53e952b9 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 032fbaf4e65..dc034de876a 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -17,7 +17,7 @@ array-bytes = "6.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 2f1e192eded..88f8a1b572d 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -58,7 +58,7 @@ sp-consensus = { path = "../../primitives/consensus/common" } substrate-test-runtime-client = { path = "client" } sp-tracing = { path = "../../primitives/tracing" } json-patch = { version = "1.0.0", default-features = false } -serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } +serde = { version = "1.0.193", features = ["alloc", "derive"], default-features = false } serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } [build-dependencies] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index b67d08a85c2..a6f6264b65c 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.0.1", default-features = false } handlebars = "4.2.2" @@ -26,7 +26,7 @@ linked-hash-map = "0.5.4" log = "0.4.17" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" thiserror = "1.0.48" thousands = "0.2.0" diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 24c04f47391..6e33ed88e0a 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.6", features = ["derive"] } +clap = { version = "4.4.10", 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 13e61138356..a2ee3883786 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.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 7067aed238a..88071f7d634 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] jsonrpsee = { version = "0.16.2", features = ["http-client"] } codec = { package = "parity-scale-codec", version = "3.6.1" } log = "0.4.17" -serde = "1.0.188" +serde = "1.0.193" sp-core = { path = "../../../primitives/core" } sp-state-machine = { path = "../../../primitives/state-machine" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 6be4306193c..97efa0e6624 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -35,11 +35,11 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true} substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.57" -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.10", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -serde = "1.0.188" +serde = "1.0.193" serde_json = "1.0.108" zstd = { version = "0.12.4", default-features = false } -- GitLab From 1f2ccaea05c8508f5cc916f8ae0ba60c102c5cf3 Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Thu, 30 Nov 2023 11:55:33 -0600 Subject: [PATCH 629/633] Remove dependency on rand's SliceRandom shuffle implementation in gossip-support (#2555) In gossip-support, we shuffled the list of authorities using the `rand::seq::SliceRandom::shuffle`. This function's behavior is unspecified beyond being `O(n)` and could change in the future, leading to network issues between nodes using different shuffling algorithms. In practice, the implementation was a Fisher-Yates shuffle. This PR replaces the call with a re-implementation of Fisher-Yates and adds a test to ensure the behavior is the same between the two at the moment. --- Cargo.lock | 13 +++++++++++ .../node/network/gossip-support/Cargo.toml | 1 + .../node/network/gossip-support/src/lib.rs | 14 ++++++++++-- .../node/network/gossip-support/src/tests.rs | 22 +++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05715ad8dfb..c83eeb050df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4844,6 +4844,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -11905,6 +11915,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-primitives", + "quickcheck", "rand 0.8.5", "rand_chacha 0.3.1", "sc-network", @@ -13731,6 +13742,8 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ + "env_logger 0.8.4", + "log", "rand 0.8.5", ] diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index a9f68261add..64a9743d1db 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -35,3 +35,4 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" async-trait = "0.1.57" lazy_static = "1.4.0" +quickcheck = "1.0.3" diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 674c86e5ce2..0d1b04f2ba2 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -32,7 +32,7 @@ use std::{ use futures::{channel::oneshot, select, FutureExt as _}; use futures_timer::Delay; -use rand::{seq::SliceRandom as _, SeedableRng}; +use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use sc_network::{config::parse_addr, Multiaddr}; @@ -607,7 +607,7 @@ async fn update_gossip_topology( .map(|(i, a)| (a.clone(), ValidatorIndex(i as _))) .collect(); - canonical_shuffling.shuffle(&mut rng); + fisher_yates_shuffle(&mut rng, &mut canonical_shuffling[..]); for (i, (_, validator_index)) in canonical_shuffling.iter().enumerate() { shuffled_indices[validator_index.0 as usize] = i; } @@ -627,6 +627,16 @@ async fn update_gossip_topology( Ok(()) } +// Durstenfeld algorithm for the Fisher-Yates shuffle +// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm +fn fisher_yates_shuffle(rng: &mut R, items: &mut [T]) { + for i in (1..items.len()).rev() { + // invariant: elements with index > i have been locked in place. + let index = rng.gen_range(0u32..(i as u32 + 1)); + items.swap(i, index as usize); + } +} + #[overseer::subsystem(GossipSupport, error = SubsystemError, prefix = self::overseer)] impl GossipSupport where diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 2e909bb0a67..e5ee101c31d 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -22,6 +22,8 @@ use assert_matches::assert_matches; use async_trait::async_trait; use futures::{executor, future, Future}; use lazy_static::lazy_static; +use quickcheck::quickcheck; +use rand::seq::SliceRandom as _; use sc_network::multiaddr::Protocol; use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; @@ -710,3 +712,23 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { assert_eq!(state.last_session_index, Some(1)); assert!(state.last_failure.is_none()); } + +// note: this test was added at a time where the default `rand::SliceRandom::shuffle` +// function was used to shuffle authorities for the topology and ensures backwards compatibility. +// +// in the same commit, an explicit fisher-yates implementation was added in place of the unspecified +// behavior of that function. If this test begins to fail at some point in the future, it can simply +// be removed as the desired behavior has been preserved. +quickcheck! { + fn rng_shuffle_equals_fisher_yates(x: Vec, seed_base: u8) -> bool { + let mut rng1: ChaCha20Rng = SeedableRng::from_seed([seed_base; 32]); + let mut rng2: ChaCha20Rng = SeedableRng::from_seed([seed_base; 32]); + + let mut data1 = x.clone(); + let mut data2 = x; + + data1.shuffle(&mut rng1); + crate::fisher_yates_shuffle(&mut rng2, &mut data2[..]); + data1 == data2 + } +} -- GitLab From 52132636d99e61b9bd9718f6afb28972b7cd3cde Mon Sep 17 00:00:00 2001 From: Parth Date: Fri, 1 Dec 2023 04:31:02 +0400 Subject: [PATCH 630/633] Add `recorded_keys` function to get recorded keys from the proof recorder (#2561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description - What does this PR do? This PR adds function to get recorded keys from proof recorder instance - Why are these changes needed? This change is required to get the keys accessed by the trie backend during the runtime execution. The keys are already tracked by proof recorder, just aren't exposed publicly. - How were these changes implemented and what do they affect? The changes are implemented by adding a public function in proof recorder that simply clones the `recorded_keys` field. It is pure addition of function and AFAIK does not affect anything. # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` 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) --------- Co-authored-by: Bastian Köcher --- substrate/primitives/trie/src/recorder.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substrate/primitives/trie/src/recorder.rs b/substrate/primitives/trie/src/recorder.rs index b236f281bb1..22a22b33b37 100644 --- a/substrate/primitives/trie/src/recorder.rs +++ b/substrate/primitives/trie/src/recorder.rs @@ -107,6 +107,13 @@ impl Clone for Recorder { } impl Recorder { + /// Returns [`RecordedForKey`] per recorded key per trie. + /// + /// There are multiple tries when working with e.g. child tries. + pub fn recorded_keys(&self) -> HashMap<::Out, HashMap, RecordedForKey>> { + self.inner.lock().recorded_keys.clone() + } + /// Returns the recorder as [`TrieRecorder`](trie_db::TrieRecorder) compatible type. /// /// - `storage_root`: The storage root of the trie for which accesses are recorded. This is -- GitLab From 4a293bc5a25be637c06ce950a34490706597615b Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 1 Dec 2023 11:38:02 +0400 Subject: [PATCH 631/633] Enforce consistent and correct toml formatting (#2518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using taplo, fixes all our broken and inconsistent toml formatting and adds CI to keep them tidy. If people want we can customise the format rules as described here https://taplo.tamasfe.dev/configuration/formatter-options.html @ggwpez, I suggest zepter is used only for checking features are propagated, and leave formatting for taplo to avoid duplicate work and conflicts. TODO - [x] Use `exclude = [...]` syntax in taplo file to ignore zombienet tests instead of deleting the dir --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- .cargo/config.toml | 52 ++--- .config/lychee.toml | 56 ++--- .config/taplo.toml | 33 +++ .config/zepter.yaml | 5 +- .gitlab/pipeline/check.yml | 10 + .gitlab/spellcheck.toml | 18 +- Cargo.toml | 28 +-- bridges/bin/runtime-common/Cargo.toml | 4 +- bridges/modules/grandpa/Cargo.toml | 2 +- bridges/modules/messages/Cargo.toml | 2 +- bridges/modules/parachains/Cargo.toml | 2 +- bridges/modules/relayers/Cargo.toml | 2 +- .../modules/xcm-bridge-hub-router/Cargo.toml | 2 +- .../chain-asset-hub-rococo/Cargo.toml | 2 +- .../chain-asset-hub-westend/Cargo.toml | 2 +- .../chain-bridge-hub-cumulus/Cargo.toml | 2 +- .../chain-bridge-hub-kusama/Cargo.toml | 2 +- .../chain-bridge-hub-polkadot/Cargo.toml | 2 +- .../chain-bridge-hub-rococo/Cargo.toml | 2 +- .../chain-bridge-hub-westend/Cargo.toml | 2 +- bridges/primitives/chain-kusama/Cargo.toml | 2 +- .../chain-polkadot-bulletin/Cargo.toml | 2 +- bridges/primitives/chain-polkadot/Cargo.toml | 2 +- bridges/primitives/chain-rococo/Cargo.toml | 2 +- bridges/primitives/chain-westend/Cargo.toml | 2 +- bridges/primitives/header-chain/Cargo.toml | 2 +- bridges/primitives/messages/Cargo.toml | 4 +- bridges/primitives/parachains/Cargo.toml | 2 +- bridges/primitives/polkadot-core/Cargo.toml | 2 +- bridges/primitives/relayers/Cargo.toml | 4 +- bridges/primitives/runtime/Cargo.toml | 2 +- bridges/primitives/test-utils/Cargo.toml | 6 +- .../xcm-bridge-hub-router/Cargo.toml | 6 +- cumulus/client/collator/Cargo.toml | 2 +- cumulus/client/consensus/aura/Cargo.toml | 2 +- cumulus/client/consensus/common/Cargo.toml | 2 +- cumulus/client/network/Cargo.toml | 2 +- cumulus/client/pov-recovery/Cargo.toml | 2 +- .../Cargo.toml | 2 +- .../relay-chain-minimal-node/Cargo.toml | 1 - .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/client/service/Cargo.toml | 1 - cumulus/pallets/aura-ext/Cargo.toml | 18 +- cumulus/pallets/collator-selection/Cargo.toml | 20 +- cumulus/pallets/dmp-queue/Cargo.toml | 4 +- cumulus/pallets/parachain-system/Cargo.toml | 30 +-- .../parachain-system/proc-macro/Cargo.toml | 2 +- .../pallets/session-benchmarking/Cargo.toml | 14 +- cumulus/pallets/solo-to-para/Cargo.toml | 16 +- cumulus/pallets/xcm/Cargo.toml | 14 +- cumulus/pallets/xcmp-queue/Cargo.toml | 18 +- cumulus/parachain-template/node/Cargo.toml | 3 +- .../pallets/template/Cargo.toml | 14 +- cumulus/parachain-template/runtime/Cargo.toml | 72 +++---- cumulus/parachains/common/Cargo.toml | 20 +- .../emulated/common/Cargo.toml | 28 +-- .../tests/assets/asset-hub-rococo/Cargo.toml | 18 +- .../tests/assets/asset-hub-westend/Cargo.toml | 28 +-- .../bridges/bridge-hub-rococo/Cargo.toml | 16 +- .../bridges/bridge-hub-westend/Cargo.toml | 16 +- .../pallets/collective-content/Cargo.toml | 2 +- .../pallets/parachain-info/Cargo.toml | 10 +- cumulus/parachains/pallets/ping/Cargo.toml | 12 +- .../assets/asset-hub-rococo/Cargo.toml | 31 +-- .../assets/asset-hub-westend/Cargo.toml | 8 +- .../runtimes/assets/common/Cargo.toml | 18 +- .../runtimes/assets/test-utils/Cargo.toml | 24 +-- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 6 +- .../bridge-hubs/test-utils/Cargo.toml | 30 +-- .../collectives-westend/Cargo.toml | 15 +- .../contracts/contracts-rococo/Cargo.toml | 70 +++---- .../glutton/glutton-westend/Cargo.toml | 56 ++--- .../runtimes/starters/seedling/Cargo.toml | 38 ++-- .../runtimes/starters/shell/Cargo.toml | 40 ++-- .../parachains/runtimes/test-utils/Cargo.toml | 34 +-- .../runtimes/testing/penpal/Cargo.toml | 80 +++---- .../testing/rococo-parachain/Cargo.toml | 62 +++--- cumulus/parachains/testnets-common/Cargo.toml | 8 +- cumulus/polkadot-parachain/Cargo.toml | 4 +- cumulus/primitives/aura/Cargo.toml | 16 +- cumulus/primitives/core/Cargo.toml | 20 +- .../primitives/parachain-inherent/Cargo.toml | 22 +- .../proof-size-hostfunction/Cargo.toml | 4 +- cumulus/primitives/timestamp/Cargo.toml | 10 +- cumulus/primitives/utility/Cargo.toml | 16 +- cumulus/test/client/Cargo.toml | 2 +- cumulus/test/relay-sproof-builder/Cargo.toml | 14 +- cumulus/test/runtime/Cargo.toml | 46 ++-- cumulus/test/service/Cargo.toml | 6 +- developer-hub/Cargo.toml | 4 +- docs/CONTRIBUTING.md | 4 + docs/STYLE_GUIDE.md | 34 +-- polkadot/Cargo.toml | 24 +-- polkadot/cli/Cargo.toml | 20 +- polkadot/core-primitives/Cargo.toml | 4 +- polkadot/erasure-coding/Cargo.toml | 2 +- polkadot/node/collation-generation/Cargo.toml | 2 +- polkadot/node/core/approval-voting/Cargo.toml | 3 +- polkadot/node/core/provisioner/Cargo.toml | 2 +- polkadot/node/core/pvf/Cargo.toml | 4 +- .../node/core/pvf/execute-worker/Cargo.toml | 2 +- .../node/core/pvf/prepare-worker/Cargo.toml | 2 +- polkadot/node/core/runtime-api/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 4 +- polkadot/node/metrics/Cargo.toml | 6 +- .../network/approval-distribution/Cargo.toml | 3 +- polkadot/node/overseer/Cargo.toml | 14 +- polkadot/node/service/Cargo.toml | 10 +- polkadot/node/subsystem-types/Cargo.toml | 2 +- polkadot/node/subsystem-util/Cargo.toml | 4 +- polkadot/node/test/client/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 4 +- polkadot/parachain/Cargo.toml | 8 +- polkadot/parachain/test-parachains/Cargo.toml | 4 +- .../test-parachains/adder/Cargo.toml | 10 +- .../parachain/test-parachains/halt/Cargo.toml | 2 +- .../test-parachains/undying/Cargo.toml | 8 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 4 +- polkadot/roadmap/implementers-guide/book.toml | 2 +- polkadot/roadmap/phase-1.toml | 14 +- polkadot/runtime/common/Cargo.toml | 10 +- .../common/slot_range_helper/Cargo.toml | 4 +- polkadot/runtime/metrics/Cargo.toml | 6 +- polkadot/runtime/parachains/Cargo.toml | 12 +- polkadot/runtime/rococo/Cargo.toml | 12 +- polkadot/runtime/rococo/constants/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- .../runtime/test-runtime/constants/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 10 +- polkadot/runtime/westend/constants/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 6 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 14 +- polkadot/xcm/pallet-xcm/Cargo.toml | 14 +- polkadot/xcm/xcm-builder/Cargo.toml | 2 +- polkadot/xcm/xcm-executor/Cargo.toml | 2 +- .../xcm-executor/integration-tests/Cargo.toml | 4 +- substrate/bin/minimal/node/Cargo.toml | 8 +- substrate/bin/minimal/runtime/Cargo.toml | 8 +- substrate/bin/node-template/node/Cargo.toml | 6 +- .../node-template/pallets/template/Cargo.toml | 10 +- .../bin/node-template/runtime/Cargo.toml | 46 ++-- .../bin/node-template/rust-toolchain.toml | 4 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 28 +-- substrate/bin/node/inspect/Cargo.toml | 2 +- substrate/bin/node/primitives/Cargo.toml | 8 +- substrate/bin/node/runtime/Cargo.toml | 196 +++++++++--------- substrate/bin/node/testing/Cargo.toml | 8 +- substrate/client/api/Cargo.toml | 4 +- .../client/authority-discovery/Cargo.toml | 4 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 12 +- .../client/consensus/babe/rpc/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/Cargo.toml | 4 +- substrate/client/consensus/common/Cargo.toml | 2 +- .../client/consensus/grandpa/rpc/Cargo.toml | 4 +- .../client/consensus/manual-seal/Cargo.toml | 4 +- substrate/client/db/Cargo.toml | 2 +- substrate/client/executor/Cargo.toml | 2 +- .../client/executor/runtime-test/Cargo.toml | 12 +- substrate/client/executor/wasmtime/Cargo.toml | 4 +- .../merkle-mountain-range/rpc/Cargo.toml | 2 +- substrate/client/network-gossip/Cargo.toml | 2 +- substrate/client/network/Cargo.toml | 4 +- substrate/client/network/bitswap/Cargo.toml | 2 +- substrate/client/network/light/Cargo.toml | 2 +- substrate/client/network/sync/Cargo.toml | 2 +- substrate/client/network/test/Cargo.toml | 2 +- substrate/client/offchain/Cargo.toml | 4 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-spec-v2/Cargo.toml | 4 +- substrate/client/service/Cargo.toml | 8 +- substrate/client/service/test/Cargo.toml | 4 +- substrate/client/storage-monitor/Cargo.toml | 2 +- substrate/client/sync-state-rpc/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../client/transaction-pool/api/Cargo.toml | 4 +- substrate/client/utils/Cargo.toml | 4 +- substrate/frame/Cargo.toml | 10 +- substrate/frame/alliance/Cargo.toml | 16 +- substrate/frame/asset-conversion/Cargo.toml | 20 +- substrate/frame/asset-rate/Cargo.toml | 16 +- substrate/frame/assets/Cargo.toml | 12 +- substrate/frame/atomic-swap/Cargo.toml | 14 +- substrate/frame/aura/Cargo.toml | 18 +- .../frame/authority-discovery/Cargo.toml | 16 +- substrate/frame/authorship/Cargo.toml | 10 +- substrate/frame/babe/Cargo.toml | 20 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/bags-list/fuzzer/Cargo.toml | 6 +- .../frame/bags-list/remote-tests/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 12 +- substrate/frame/beefy-mmr/Cargo.toml | 28 +-- substrate/frame/beefy/Cargo.toml | 16 +- substrate/frame/benchmarking/Cargo.toml | 24 +-- substrate/frame/benchmarking/pov/Cargo.toml | 14 +- substrate/frame/bounties/Cargo.toml | 18 +- substrate/frame/broker/Cargo.toml | 18 +- substrate/frame/child-bounties/Cargo.toml | 20 +- substrate/frame/collective/Cargo.toml | 16 +- substrate/frame/contracts/Cargo.toml | 26 +-- substrate/frame/contracts/fixtures/Cargo.toml | 2 - .../fixtures/contracts/common/Cargo.toml | 1 - .../frame/contracts/mock-network/Cargo.toml | 36 ++-- .../frame/contracts/primitives/Cargo.toml | 33 +++ substrate/frame/contracts/uapi/Cargo.toml | 7 +- substrate/frame/conviction-voting/Cargo.toml | 14 +- substrate/frame/core-fellowship/Cargo.toml | 18 +- substrate/frame/democracy/Cargo.toml | 16 +- .../election-provider-multi-phase/Cargo.toml | 26 +-- .../test-staking-e2e/Cargo.toml | 2 +- .../election-provider-support/Cargo.toml | 18 +- .../benchmarking/Cargo.toml | 14 +- .../solution-type/fuzzer/Cargo.toml | 4 +- substrate/frame/elections-phragmen/Cargo.toml | 20 +- substrate/frame/examples/Cargo.toml | 14 +- substrate/frame/examples/basic/Cargo.toml | 18 +- .../frame/examples/default-config/Cargo.toml | 12 +- substrate/frame/examples/dev-mode/Cargo.toml | 16 +- .../frame/examples/frame-crate/Cargo.toml | 6 +- .../frame/examples/kitchensink/Cargo.toml | 18 +- .../frame/examples/offchain-worker/Cargo.toml | 16 +- substrate/frame/examples/split/Cargo.toml | 16 +- substrate/frame/executive/Cargo.toml | 18 +- substrate/frame/fast-unstake/Cargo.toml | 20 +- substrate/frame/glutton/Cargo.toml | 16 +- substrate/frame/grandpa/Cargo.toml | 18 +- substrate/frame/identity/Cargo.toml | 14 +- substrate/frame/im-online/Cargo.toml | 14 +- substrate/frame/indices/Cargo.toml | 18 +- .../Cargo.toml | 10 +- substrate/frame/lottery/Cargo.toml | 12 +- substrate/frame/membership/Cargo.toml | 12 +- .../frame/merkle-mountain-range/Cargo.toml | 18 +- substrate/frame/message-queue/Cargo.toml | 20 +- substrate/frame/mixnet/Cargo.toml | 2 +- substrate/frame/multisig/Cargo.toml | 14 +- .../frame/nft-fractionalization/Cargo.toml | 16 +- substrate/frame/nfts/Cargo.toml | 16 +- substrate/frame/nfts/runtime-api/Cargo.toml | 4 +- substrate/frame/nicks/Cargo.toml | 12 +- substrate/frame/nis/Cargo.toml | 16 +- substrate/frame/node-authorization/Cargo.toml | 14 +- substrate/frame/nomination-pools/Cargo.toml | 18 +- .../nomination-pools/benchmarking/Cargo.toml | 26 +-- .../nomination-pools/runtime-api/Cargo.toml | 10 +- substrate/frame/offences/Cargo.toml | 14 +- .../frame/offences/benchmarking/Cargo.toml | 30 +-- substrate/frame/paged-list/Cargo.toml | 18 +- substrate/frame/paged-list/fuzzer/Cargo.toml | 6 +- substrate/frame/preimage/Cargo.toml | 18 +- substrate/frame/proxy/Cargo.toml | 14 +- substrate/frame/ranked-collective/Cargo.toml | 18 +- substrate/frame/recovery/Cargo.toml | 16 +- substrate/frame/referenda/Cargo.toml | 16 +- substrate/frame/remark/Cargo.toml | 18 +- substrate/frame/root-offences/Cargo.toml | 16 +- substrate/frame/root-testing/Cargo.toml | 14 +- substrate/frame/safe-mode/Cargo.toml | 18 +- substrate/frame/salary/Cargo.toml | 18 +- substrate/frame/scheduler/Cargo.toml | 18 +- substrate/frame/scored-pool/Cargo.toml | 12 +- substrate/frame/session/Cargo.toml | 20 +- .../frame/session/benchmarking/Cargo.toml | 18 +- substrate/frame/society/Cargo.toml | 16 +- substrate/frame/staking/Cargo.toml | 18 +- substrate/frame/staking/reward-fn/Cargo.toml | 6 +- .../frame/staking/runtime-api/Cargo.toml | 4 +- .../frame/state-trie-migration/Cargo.toml | 20 +- substrate/frame/statement/Cargo.toml | 20 +- substrate/frame/sudo/Cargo.toml | 14 +- substrate/frame/support/Cargo.toml | 38 ++-- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 34 +-- .../support/test/compile_pass/Cargo.toml | 12 +- .../frame/support/test/pallet/Cargo.toml | 8 +- .../support/test/stg_frame_crate/Cargo.toml | 6 +- substrate/frame/system/Cargo.toml | 12 +- .../frame/system/benchmarking/Cargo.toml | 14 +- .../frame/system/rpc/runtime-api/Cargo.toml | 6 +- substrate/frame/timestamp/Cargo.toml | 20 +- substrate/frame/tips/Cargo.toml | 18 +- .../frame/transaction-payment/Cargo.toml | 14 +- .../asset-conversion-tx-payment/Cargo.toml | 20 +- .../asset-tx-payment/Cargo.toml | 18 +- .../frame/transaction-payment/rpc/Cargo.toml | 2 +- .../rpc/runtime-api/Cargo.toml | 10 +- .../skip-feeless-payment/Cargo.toml | 10 +- .../frame/transaction-storage/Cargo.toml | 24 +-- substrate/frame/treasury/Cargo.toml | 16 +- substrate/frame/try-runtime/Cargo.toml | 14 +- substrate/frame/tx-pause/Cargo.toml | 16 +- substrate/frame/uniques/Cargo.toml | 12 +- substrate/frame/utility/Cargo.toml | 16 +- substrate/frame/vesting/Cargo.toml | 14 +- substrate/frame/whitelist/Cargo.toml | 14 +- substrate/primitives/api/Cargo.toml | 8 +- .../primitives/api/proc-macro/Cargo.toml | 6 +- .../primitives/application-crypto/Cargo.toml | 14 +- .../application-crypto/test/Cargo.toml | 4 +- substrate/primitives/arithmetic/Cargo.toml | 10 +- .../primitives/authority-discovery/Cargo.toml | 10 +- substrate/primitives/block-builder/Cargo.toml | 12 +- .../primitives/consensus/aura/Cargo.toml | 16 +- .../primitives/consensus/babe/Cargo.toml | 20 +- .../primitives/consensus/beefy/Cargo.toml | 4 +- .../primitives/consensus/grandpa/Cargo.toml | 16 +- substrate/primitives/consensus/pow/Cargo.toml | 10 +- .../primitives/consensus/sassafras/Cargo.toml | 2 +- .../primitives/consensus/slots/Cargo.toml | 10 +- substrate/primitives/core/Cargo.toml | 26 +-- substrate/primitives/core/hashing/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- .../primitives/crypto/ec-utils/Cargo.toml | 12 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- substrate/primitives/externalities/Cargo.toml | 8 +- .../primitives/genesis-builder/Cargo.toml | 10 +- substrate/primitives/inherents/Cargo.toml | 6 +- substrate/primitives/io/Cargo.toml | 28 +-- substrate/primitives/keyring/Cargo.toml | 2 +- substrate/primitives/keystore/Cargo.toml | 12 +- .../merkle-mountain-range/Cargo.toml | 16 +- substrate/primitives/metadata-ir/Cargo.toml | 6 +- substrate/primitives/mixnet/Cargo.toml | 2 +- .../primitives/npos-elections/Cargo.toml | 12 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- substrate/primitives/offchain/Cargo.toml | 10 +- .../primitives/runtime-interface/Cargo.toml | 10 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 8 +- .../runtime-interface/test-wasm/Cargo.toml | 10 +- substrate/primitives/runtime/Cargo.toml | 16 +- substrate/primitives/session/Cargo.toml | 12 +- substrate/primitives/staking/Cargo.toml | 12 +- substrate/primitives/state-machine/Cargo.toml | 12 +- .../primitives/statement-store/Cargo.toml | 18 +- substrate/primitives/std/Cargo.toml | 2 +- substrate/primitives/storage/Cargo.toml | 10 +- .../primitives/test-primitives/Cargo.toml | 10 +- substrate/primitives/timestamp/Cargo.toml | 8 +- substrate/primitives/tracing/Cargo.toml | 6 +- .../primitives/transaction-pool/Cargo.toml | 8 +- .../transaction-storage-proof/Cargo.toml | 12 +- substrate/primitives/trie/Cargo.toml | 6 +- substrate/primitives/version/Cargo.toml | 12 +- .../primitives/version/proc-macro/Cargo.toml | 4 +- .../primitives/wasm-interface/Cargo.toml | 8 +- substrate/primitives/weights/Cargo.toml | 14 +- substrate/scripts/ci/deny.toml | 134 ++++++------ substrate/test-utils/Cargo.toml | 2 +- substrate/test-utils/cli/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 4 +- substrate/test-utils/runtime/Cargo.toml | 52 ++--- substrate/utils/binary-merkle-tree/Cargo.toml | 6 +- .../utils/frame/benchmarking-cli/Cargo.toml | 10 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- substrate/utils/frame/rpc/support/Cargo.toml | 2 +- substrate/utils/frame/rpc/system/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 4 +- 364 files changed, 2325 insertions(+), 2287 deletions(-) create mode 100644 .config/taplo.toml create mode 100644 substrate/frame/contracts/primitives/Cargo.toml diff --git a/.cargo/config.toml b/.cargo/config.toml index bd46659f799..8bbf7cdb4d9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ [build] rustdocflags = [ - "-Dwarnings", - "-Arustdoc::redundant_explicit_links", # stylistic + "-Dwarnings", + "-Arustdoc::redundant_explicit_links", # stylistic ] # An auto defined `clippy` feature was introduced, @@ -12,30 +12,30 @@ rustdocflags = [ # RUSTFLAGS= cargo clippy [target.'cfg(feature = "cargo-clippy")'] rustflags = [ - "-Aclippy::all", - "-Dclippy::correctness", - "-Aclippy::if-same-then-else", - "-Asuspicious_double_ref_op", - "-Dclippy::complexity", - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::unit_arg", # styalistic. - "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::derivable_impls", # false positives - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::extra-unused-type-parameters", # stylistic - "-Aclippy::default_constructed_unit_structs", # stylistic + "-Aclippy::all", + "-Dclippy::correctness", + "-Aclippy::if-same-then-else", + "-Asuspicious_double_ref_op", + "-Dclippy::complexity", + "-Aclippy::zero-prefixed-literal", # 00_1000_000 + "-Aclippy::type_complexity", # raison d'etre + "-Aclippy::nonminimal-bool", # maybe + "-Aclippy::borrowed-box", # Reasonable to fix this one + "-Aclippy::too-many-arguments", # (Turning this on would lead to) + "-Aclippy::unnecessary_cast", # Types may change + "-Aclippy::identity-op", # One case where we do 0 + + "-Aclippy::useless_conversion", # Types may change + "-Aclippy::unit_arg", # styalistic. + "-Aclippy::option-map-unit-fn", # styalistic + "-Aclippy::bind_instead_of_map", # styalistic + "-Aclippy::erasing_op", # E.g. 0 * DOLLARS + "-Aclippy::eq_op", # In tests we test equality. + "-Aclippy::while_immutable_condition", # false positives + "-Aclippy::needless_option_as_deref", # false positives + "-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] diff --git a/.config/lychee.toml b/.config/lychee.toml index 9b2ae069931..72c1e66a4df 100644 --- a/.config/lychee.toml +++ b/.config/lychee.toml @@ -15,36 +15,36 @@ accept = [ 200, # Rate limited - GitHub likes to throw this. - 429 + 429, ] -exclude_path = [ "./target" ] +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", + # 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/NPoS/3.%20Balancing.html", + "https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model", + "https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html", + "https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html#-6.-practical-results", + "https://research.web3.foundation/en/latest/polkadot/networking/3-avail-valid.html#topology", + "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html", + "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#inflation-model", + "https://research.web3.foundation/en/latest/polkadot/slashing/npos.html", + "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/.config/taplo.toml b/.config/taplo.toml new file mode 100644 index 00000000000..ffe0417e42b --- /dev/null +++ b/.config/taplo.toml @@ -0,0 +1,33 @@ +# all options https://taplo.tamasfe.dev/configuration/formatter-options.html + +# ignore zombienet as they do some deliberate custom toml stuff +exclude = [ + "cumulus/zombienet/**", + "polkadot/node/malus/integrationtests/**", + "polkadot/zombienet_tests/**", + "substrate/zombienet/**", +] + +# global rules +[formatting] +reorder_arrays = true +inline_table_expand = false +array_auto_expand = false +array_auto_collapse = false +indent_string = " " # tab + +# don't re-order order-dependent deb package metadata +[[rule]] +include = ["polkadot/Cargo.toml"] +keys = ["package.metadata.deb"] + +[rule.formatting] +reorder_arrays = false + +# don't re-order order-dependent rustflags +[[rule]] +include = [".cargo/config.toml"] +keys = ["build", "target.'cfg(feature = \"cargo-clippy\")'"] + +[rule.formatting] +reorder_arrays = false diff --git a/.config/zepter.yaml b/.config/zepter.yaml index 33bf3a044cf..f701392d16b 100644 --- a/.config/zepter.yaml +++ b/.config/zepter.yaml @@ -19,18 +19,15 @@ workflows: '--left-side-outside-workspace=ignore', # Some features imply that they activate a specific dependency as non-optional. Otherwise the default behaviour with a `?` is used. '--feature-enables-dep=try-runtime:frame-try-runtime,runtime-benchmarks:frame-benchmarking', - # Actually modify the files and not just report the issues: + # Auxillary flags: '--offline', '--locked', '--show-path', '--quiet', ] - # Format the features into canonical format: - - ['format', 'features', '--offline', '--locked', '--quiet'] # Same as `check`, but with the `--fix` flag. default: - [ $check.0, '--fix' ] - - [ $check.1, '--fix' ] # Will be displayed when any workflow fails: help: diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 3ef3865aa43..98435248eb4 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -90,6 +90,16 @@ check-rust-feature-propagation: - cargo install --locked --version 0.13.3 -q -f zepter && zepter --version - zepter run check +check-toml-format: + stage: check + extends: + - .kubernetes-env + - .common-refs + script: + - cargo install taplo-cli --locked --version 0.8.1 + - taplo format --check --config .config/taplo.toml + - echo "Please run `taplo format --config .config/taplo.toml` to fix any toml formatting issues" + # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 .check-runtime-migration: stage: check diff --git a/.gitlab/spellcheck.toml b/.gitlab/spellcheck.toml index 025c7a0a461..8c60bf6915d 100644 --- a/.gitlab/spellcheck.toml +++ b/.gitlab/spellcheck.toml @@ -8,20 +8,20 @@ use_builtin = true [hunspell.quirks] # He tagged it as 'TheGreatestOfAllTimes' transform_regex = [ -# `Type`'s + # `Type`'s "^'([^\\s])'$", -# 5x -# 10.7% + # 5x + # 10.7% "^[0-9_]+(?:\\.[0-9]*)?(x|%)$", -# Transforms' + # Transforms' "^(.*)'$", -# backslashes - "^\\+$", + # backslashes "^[0-9]*+k|MB|Mb|ms|Mbit|nd|th|rd$", -# single char `=` `>` `%` .. + "^\\+$", + # single char `=` `>` `%` .. "^=|>|<|%$", -# 22_100 - "^(?:[0-9]+_)+[0-9]+$" + # 22_100 + "^(?:[0-9]+_)+[0-9]+$", ] allow_concatenation = true allow_dashes = true diff --git a/Cargo.toml b/Cargo.toml index b585ceb5b44..0a7bf912e48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ license = "GPL-3.0-only" resolver = "2" members = [ - "developer-hub", "bridges/bin/runtime-common", "bridges/modules/grandpa", "bridges/modules/messages", @@ -23,8 +22,8 @@ members = [ "bridges/primitives/chain-bridge-hub-rococo", "bridges/primitives/chain-bridge-hub-westend", "bridges/primitives/chain-kusama", - "bridges/primitives/chain-polkadot-bulletin", "bridges/primitives/chain-polkadot", + "bridges/primitives/chain-polkadot-bulletin", "bridges/primitives/chain-rococo", "bridges/primitives/chain-westend", "bridges/primitives/header-chain", @@ -70,6 +69,7 @@ members = [ "cumulus/parachains/integration-tests/emulated/chains/relays/westend", "cumulus/parachains/integration-tests/emulated/common", "cumulus/parachains/integration-tests/emulated/networks/rococo-system", + "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system", "cumulus/parachains/integration-tests/emulated/networks/westend-system", "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo", "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend", @@ -106,6 +106,7 @@ members = [ "cumulus/test/runtime", "cumulus/test/service", "cumulus/xcm/xcm-emulator", + "developer-hub", "polkadot", "polkadot/cli", "polkadot/core-primitives", @@ -123,8 +124,8 @@ 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-checker", "polkadot/node/core/pvf/common", "polkadot/node/core/pvf/execute-worker", "polkadot/node/core/pvf/prepare-worker", @@ -147,10 +148,10 @@ 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/service", "polkadot/node/tracking-allocator", @@ -179,8 +180,8 @@ members = [ "polkadot/utils/generate-bags", "polkadot/utils/remote-ext-tests/bags-list", "polkadot/xcm", - "polkadot/xcm/pallet-xcm-benchmarks", "polkadot/xcm/pallet-xcm", + "polkadot/xcm/pallet-xcm-benchmarks", "polkadot/xcm/procedural", "polkadot/xcm/xcm-builder", "polkadot/xcm/xcm-executor", @@ -232,8 +233,8 @@ members = [ "substrate/client/merkle-mountain-range", "substrate/client/merkle-mountain-range/rpc", "substrate/client/mixnet", - "substrate/client/network-gossip", "substrate/client/network", + "substrate/client/network-gossip", "substrate/client/network/bitswap", "substrate/client/network/common", "substrate/client/network/light", @@ -243,10 +244,10 @@ members = [ "substrate/client/network/transactions", "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", @@ -274,8 +275,8 @@ members = [ "substrate/frame/bags-list/fuzzer", "substrate/frame/bags-list/remote-tests", "substrate/frame/balances", - "substrate/frame/beefy-mmr", "substrate/frame/beefy", + "substrate/frame/beefy-mmr", "substrate/frame/benchmarking", "substrate/frame/benchmarking/pov", "substrate/frame/bounties", @@ -285,9 +286,9 @@ members = [ "substrate/frame/contracts", "substrate/frame/contracts/fixtures", "substrate/frame/contracts/fixtures/contracts/common", - "substrate/frame/contracts/uapi", "substrate/frame/contracts/mock-network", "substrate/frame/contracts/proc-macro", + "substrate/frame/contracts/uapi", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", "substrate/frame/democracy", @@ -424,12 +425,12 @@ members = [ "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-wasm-deprecated", - "substrate/primitives/runtime-interface/test-wasm", "substrate/primitives/runtime-interface/test", - "substrate/primitives/runtime", + "substrate/primitives/runtime-interface/test-wasm", + "substrate/primitives/runtime-interface/test-wasm-deprecated", "substrate/primitives/session", "substrate/primitives/staking", "substrate/primitives/state-machine", @@ -468,9 +469,8 @@ members = [ "substrate/utils/frame/try-runtime/cli", "substrate/utils/prometheus", "substrate/utils/wasm-builder", - "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system", ] -default-members = [ "polkadot", "substrate/bin/node/cli" ] +default-members = ["polkadot", "substrate/bin/node/cli"] [profile.release] # Polkadot runtime requires unwinding. diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 0ccf30987e8..a5aa53f2633 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -50,7 +50,7 @@ bp-test-utils = { path = "../../primitives/test-utils" } pallet-balances = { path = "../../../substrate/frame/balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-messages/std", @@ -92,4 +92,4 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", ] -integrity-test = [ "static_assertions" ] +integrity-test = ["static_assertions"] diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index dbbe18febc6..573edbf5a65 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -37,7 +37,7 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-io = { path = "../../../substrate/primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-runtime/std", diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index a5c86693309..751ef45168d 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -31,7 +31,7 @@ pallet-balances = { path = "../../../substrate/frame/balances" } sp-io = { path = "../../../substrate/primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-messages/std", "bp-runtime/std", diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 0d1b61ddea8..4af8997c5f3 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -35,7 +35,7 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-io = { path = "../../../substrate/primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-parachains/std", diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 6ec1971e3f6..3011a11db5c 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -34,7 +34,7 @@ sp-io = { path = "../../../substrate/primitives/io" } sp-runtime = { path = "../../../substrate/primitives/runtime" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-messages/std", "bp-relayers/std", diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 56b9139d7d5..e4d25fae9d3 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -34,7 +34,7 @@ sp-io = { path = "../../../substrate/primitives/io" } sp-std = { path = "../../../substrate/primitives/std" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", "codec/std", diff --git a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml index 088510adcec..889475840b3 100644 --- a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml @@ -17,7 +17,7 @@ frame-support = { path = "../../../substrate/frame/support", default-features = bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", "codec/std", diff --git a/bridges/primitives/chain-asset-hub-westend/Cargo.toml b/bridges/primitives/chain-asset-hub-westend/Cargo.toml index c880f159ac1..84b9604a61b 100644 --- a/bridges/primitives/chain-asset-hub-westend/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-westend/Cargo.toml @@ -17,7 +17,7 @@ frame-support = { path = "../../../substrate/frame/support", default-features = bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", "codec/std", diff --git a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index 46697913674..dab1b065f6f 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -24,7 +24,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-messages/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index c4cd229ef43..8e6364101f2 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -21,7 +21,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 4913d87e5fb..961d4aeb2e2 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", diff --git a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index 05b8163e9fc..28fe3c283bc 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -21,7 +21,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", diff --git a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml index 22daf280868..409f84840a8 100644 --- a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml index 2d63c3f374f..41570d4f9bc 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -21,7 +21,7 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml index 1dd45ba95fd..3be056dd0a7 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-messages/std", diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml index 539b10ef9c6..579e997e0ab 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -21,7 +21,7 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml index 469be1dbd33..dc7c482a4cc 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -21,7 +21,7 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml index 797621bbce2..7c74cb1361b 100644 --- a/bridges/primitives/chain-westend/Cargo.toml +++ b/bridges/primitives/chain-westend/Cargo.toml @@ -21,7 +21,7 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index 19b2819bddc..bc92054e5dc 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -30,7 +30,7 @@ hex = "0.4" hex-literal = "0.4" [features] -default = [ "std" ] +default = ["std"] std = [ "bp-runtime/std", "codec/std", diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 7a61643a0bc..c2f43523aaf 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -7,7 +7,7 @@ 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, features = ["derive", "bit-vec"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } @@ -27,7 +27,7 @@ hex = "0.4" hex-literal = "0.4" [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-runtime/std", diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 11e9336f66a..a339203fd66 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-polkadot-core/std", diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index e2bd4c29522..67fb9af8b21 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -29,7 +29,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false hex = "0.4" [features] -default = [ "std" ] +default = ["std"] std = [ "bp-messages/std", "bp-runtime/std", diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index ffed2debbe6..cf94ca44d00 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -7,7 +7,7 @@ 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, features = ["derive", "bit-vec"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies @@ -26,7 +26,7 @@ hex = "0.4" hex-literal = "0.4" [features] -default = [ "std" ] +default = ["std"] std = [ "bp-messages/std", "bp-runtime/std", diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 48f6722c982..a713f636bb8 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -31,7 +31,7 @@ trie-db = { version = "0.28.0", default-features = false } hex-literal = "0.4" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 9836c1877f0..fac5c5b5896 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -7,9 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -bp-header-chain = { path = "../header-chain", default-features = false } +bp-header-chain = { path = "../header-chain", default-features = false } bp-parachains = { path = "../parachains", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } +bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } ed25519-dalek = { version = "2.0", default-features = false } @@ -22,7 +22,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-header-chain/std", "bp-parachains/std", diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index fb079b48e42..5a49db62fec 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -7,7 +7,7 @@ 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, features = ["derive", "bit-vec"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies @@ -15,5 +15,5 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-core = { path = "../../../substrate/primitives/core", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std" ] +default = ["std"] +std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std"] diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index ad9f01ed083..7ac0bbfe6f1 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] parking_lot = "0.12.1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" tracing = "0.1.25" diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index f440270c982..e07f10d6090 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" tracing = "0.1.37" schnellru = "0.2.1" diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 9dfd14b1cf5..92918cd7b5b 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } dyn-clone = "1.0.12" futures = "0.3.28" log = "0.4.20" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 08956f9f6c6..3893647e7c5 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-trait = "0.1.73" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" parking_lot = "0.12.1" diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index e407b33e0e2..29f793c7328 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" rand = "0.8.5" diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 87f0eabd9b5..1d414736503 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -39,7 +39,7 @@ sp-keyring = { path = "../../../substrate/primitives/keyring" } # Polkadot polkadot-primitives = { path = "../../../polkadot/primitives" } polkadot-test-client = { path = "../../../polkadot/node/test/client" } -metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features = ["futures_channel"] } # Cumulus cumulus-test-service = { path = "../../test/service" } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index ee93df09ce1..acaed5a4f6c 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -48,4 +48,3 @@ tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" parking_lot = "0.12.1" - diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 67ee3571c04..11d8bc9b4df 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -38,7 +38,7 @@ url = "2.4.0" serde_json = "1.0.108" serde = "1.0.193" schnellru = "0.2.1" -smoldot = { version = "0.11.0", default_features = false, features = ["std"]} +smoldot = { version = "0.11.0", default_features = false, features = ["std"] } smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } either = "1.8.1" thiserror = "1.0.48" diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index cc2f22e6565..55623276eaf 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -42,4 +42,3 @@ cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-si 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" } - diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index c9d82ead1eb..16f73aa540e 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -11,14 +11,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -pallet-aura = { path = "../../../substrate/frame/aura", default-features = false} -pallet-timestamp= { path = "../../../substrate/frame/timestamp", default-features = false} -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false} -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-aura = { path = "../../../substrate/frame/aura", default-features = false } +pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } +sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } +sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Cumulus cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false } @@ -29,7 +29,7 @@ cumulus-pallet-parachain-system = { path = "../parachain-system", default-featur cumulus-pallet-parachain-system = { path = "../parachain-system" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-parachain-system/std", diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 68e4a681c2b..76efbf1caf6 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -18,15 +18,15 @@ codec = { default-features = false, features = ["derive"], package = "parity-sca rand = { version = "0.8.5", features = ["std_rng"], default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false} -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false} -pallet-session = { path = "../../../substrate/frame/session", default-features = false} +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } +pallet-session = { path = "../../../substrate/frame/session", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } [dev-dependencies] sp-core = { path = "../../../substrate/primitives/core" } @@ -39,7 +39,7 @@ pallet-balances = { path = "../../../substrate/frame/balances" } pallet-aura = { path = "../../../substrate/frame/aura" } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -75,4 +75,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 43fb131aec2..0b64410433f 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-io = { path = "../../../substrate/primitives/io", default-features = false } # Polkadot -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -33,7 +33,7 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-tracing = { path = "../../../substrate/primitives/tracing" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index cf6af4b4786..187cf21cea6 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -16,24 +16,24 @@ trie-db = { version = "0.28.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false} -sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false} -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false} -sp-version = { path = "../../../substrate/primitives/version", default-features = false} +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false } +sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-version = { path = "../../../substrate/primitives/version", default-features = false } # Polkadot -polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} +polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = ["wasm-api"] } polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } # Cumulus cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false } @@ -60,7 +60,7 @@ cumulus-test-client = { path = "../../test/client" } cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "bytes/std", "codec/std", diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 6accfa92c57..f4bfdf27062 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -16,5 +16,5 @@ quote = "1.0.33" proc-macro-crate = "1.3.1" [features] -default = [ "std" ] +default = ["std"] std = [] diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index a28971d66d3..4c85b3d7171 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -14,15 +14,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] parity-scale-codec = { version = "3.6.4", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} -pallet-session = { path = "../../../substrate/frame/session", default-features = false} +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +pallet-session = { path = "../../../substrate/frame/session", default-features = false } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index e4ef72965c7..dc79d287d4d 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -11,20 +11,20 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} +polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false} +cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-parachain-system/std", diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index c8e819979bd..f36d0aa52de 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -10,18 +10,18 @@ description = "Pallet for stuff specific to parachains' usage of XCM" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} -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} +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +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 } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index fba006e7986..1bc21bbbb58 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -7,17 +7,17 @@ description = "Pallet to queue outbound and inbound XCMP messages." license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { version = "0.4.20", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", 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} +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } # Polkadot @@ -30,7 +30,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm cumulus-primitives-core = { path = "../../primitives/core", default-features = false } # Optional import for benchmarking -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } bounded-collections = { version = "0.1.4", default-features = false } # Bridges @@ -50,7 +50,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x cumulus-pallet-parachain-system = { path = "../parachain-system", features = ["parameterized-consensus-hook"] } [features] -default = [ "std" ] +default = ["std"] std = [ "bounded-collections/std", "bp-xcm-bridge-hub-router?/std", @@ -96,4 +96,4 @@ try-runtime = [ "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -bridging = [ "bp-xcm-bridge-hub-router" ] +bridging = ["bp-xcm-bridge-hub-router"] diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index ba4060f54f9..19ee334cf95 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -57,7 +57,7 @@ substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } # Polkadot polkadot-cli = { path = "../../../polkadot/cli", features = ["rococo-native"] } polkadot-primitives = { path = "../../../polkadot/primitives" } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } # Cumulus cumulus-client-cli = { path = "../../client/cli" } @@ -91,4 +91,3 @@ try-runtime = [ "polkadot-cli/try-runtime", "sp-runtime/try-runtime", ] - diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index 4267341a2d7..71b78a7175c 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -16,20 +16,20 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true} -frame-support = { path = "../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../substrate/frame/system", default-features = false} +frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } [dev-dependencies] serde = { version = "1.0.193" } # Substrate -sp-core = { path = "../../../../substrate/primitives/core", default-features = false} -sp-io = { path = "../../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false} +sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +sp-io = { path = "../../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 01e25007873..d83867a9c7c 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -25,48 +25,48 @@ smallvec = "1.11.0" pallet-parachain-template = { path = "../pallets/template", default-features = false } # 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-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} +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-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-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false} -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false} -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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} +pallet-session = { path = "../../../substrate/frame/session", default-features = false } +pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +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} -sp-session = { path = "../../../substrate/primitives/session", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../substrate/primitives/version", 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-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../substrate/primitives/version", default-features = false } # Polkadot -pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", 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} +pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", 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-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } +cumulus-pallet-session-benchmarking = { path = "../../pallets/session-benchmarking", default-features = false } cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -76,7 +76,7 @@ parachains-common = { path = "../../parachains/common", default-features = false parachain-info = { package = "staging-parachain-info", path = "../../parachains/pallets/parachain-info", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -183,4 +183,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 4aad4dec236..5475fd2aa26 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { version = "0.4.19", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -num-traits = { version = "0.2", default-features = false} +num-traits = { version = "0.2", default-features = false } smallvec = "1.11.0" # Substrate @@ -31,12 +31,12 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot -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} +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 } # Cumulus pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } @@ -45,14 +45,14 @@ cumulus-primitives-utility = { path = "../../primitives/utility", default-featur parachain-info = { package = "staging-parachain-info", path = "../pallets/parachain-info", default-features = false } [dev-dependencies] -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} +pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 08bb284cded..92716083d69 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -13,29 +13,29 @@ serde_json = "1.0.108" # Substrate grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/client/consensus/grandpa" } -sp-authority-discovery = { path = "../../../../../substrate/primitives/authority-discovery", default-features = false} -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} -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-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} -pallet-im-online = { path = "../../../../../substrate/frame/im-online", default-features = false} +sp-authority-discovery = { path = "../../../../../substrate/primitives/authority-discovery", default-features = false } +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 } +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-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } +pallet-im-online = { path = "../../../../../substrate/frame/im-online", default-features = false } beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../substrate/primitives/consensus/beefy" } # Polkadot polkadot-service = { path = "../../../../../polkadot/node/service", default-features = false, features = ["full-node"] } -polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false} +polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false } polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} +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-primitives-core = { path = "../../../../primitives/core" } -xcm-emulator = { path = "../../../../xcm/xcm-emulator", default-features = false} -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false} +xcm-emulator = { path = "../../../../xcm/xcm-emulator", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } asset-test-utils = { path = "../../../runtimes/assets/test-utils" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 23f80f33f78..16e2f736bdf 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -12,17 +12,17 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = assert_matches = "1.5.0" # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false} -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false} -pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false} +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } +pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } # Cumulus @@ -31,4 +31,4 @@ parachains-common = { path = "../../../../../../parachains/common" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } emulated-integration-tests-common = { path = "../../../common", default-features = false } penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } -rococo-system-emulated-network ={ path = "../../../networks/rococo-system" } +rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 4c7537bfd53..74e6660d4d4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -12,22 +12,22 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = assert_matches = "1.5.0" # 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} -pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false} -pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false} +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 } +pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } +pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } -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} +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 } westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants", default-features = false } @@ -37,6 +37,6 @@ asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-w asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } -emulated-integration-tests-common = { path = "../../../common", default-features = false} +emulated-integration-tests-common = { path = "../../../common", default-features = false } penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } -westend-system-emulated-network ={ path = "../../../networks/westend-system" } +westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 00e3af2e4ff..826b55507ed 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -17,19 +17,19 @@ pallet-balances = { path = "../../../../../../../substrate/frame/balances", defa pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } # Bridges -pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false} -bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false} +pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false } +bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false } # Cumulus asset-test-utils = { path = "../../../../../../parachains/runtimes/assets/test-utils" } parachains-common = { path = "../../../../../../parachains/common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} +cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } +cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false } bridge-hub-rococo-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } -emulated-integration-tests-common = { path = "../../../common", default-features = false} +emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index e5b1fce5f2b..cb53d7fc0e1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -17,19 +17,19 @@ pallet-balances = { path = "../../../../../../../substrate/frame/balances", defa pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } # Bridges -pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false} -bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false} +pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false } +bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false } # Cumulus asset-test-utils = { path = "../../../../../../parachains/runtimes/assets/test-utils" } parachains-common = { path = "../../../../../../parachains/common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} +cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } +cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false } bridge-hub-westend-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } -emulated-integration-tests-common = { path = "../../../common", default-features = false} +emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index e3f8023f419..26899a9e774 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -22,7 +22,7 @@ sp-std = { path = "../../../../substrate/primitives/std", default-features = fal sp-io = { path = "../../../../substrate/primitives/io", default-features = false } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 727182dfb8e..b5b6ec304df 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -10,16 +10,16 @@ description = "Pallet to store the parachain ID" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../substrate/frame/system", default-features = false} +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../../substrate/primitives/std", default-features = false} +sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../../substrate/primitives/std", default-features = false } cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 0133befa855..c661e4260c6 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -10,18 +10,18 @@ description = "Ping Pallet for Cumulus XCM/UMP testing." codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false} -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../substrate/frame/system", default-features = false} +sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } cumulus-pallet-xcm = { path = "../../../pallets/xcm", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-xcm/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index f3bdabd9cef..15166de15ae 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -7,15 +7,10 @@ description = "Rococo variant of Asset Hub parachain runtime" license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ - "derive", - "max-encoded-len", -] } +codec = { package = "parity-scale-codec", version = "3.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.10.0", default-features = false, features = [ - "derive", -] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate @@ -60,11 +55,7 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- 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", -] } +primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } # Polkadot rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } @@ -79,14 +70,10 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = [ - "parameterized-consensus-hook", -] } +cumulus-pallet-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-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 } @@ -108,7 +95,7 @@ asset-test-utils = { path = "../test-utils" } substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +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 @@ -116,7 +103,7 @@ default = [ "std" ] # 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" ] +state-trie-version-1 = ["pallet-state-trie-migration"] runtime-benchmarks = [ "assets-common/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", @@ -257,9 +244,9 @@ std = [ "xcm/std", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index bc06c6fe9a1..2eb8e9a55d7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -52,7 +52,7 @@ sp-storage = { path = "../../../../../substrate/primitives/storage", default-fea sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } sp-version = { path = "../../../../../substrate/primitives/version", 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"] } +primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } @@ -94,7 +94,7 @@ asset-test-utils = { path = "../test-utils" } substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "assets-common/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", @@ -232,9 +232,9 @@ std = [ "xcm/std", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 49fc2a0fa5e..e78d8331039 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -13,18 +13,18 @@ log = { version = "0.4.20", default-features = false } impl-trait-for-tuples = "0.2.2" # Substrate -frame-support = { path = "../../../../../substrate/frame/support", default-features = false} -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} +frame-support = { path = "../../../../../substrate/frame/support", default-features = false } +sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } +sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } pallet-asset-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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} +pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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 parachains-common = { path = "../../../common", default-features = false } @@ -34,7 +34,7 @@ cumulus-primitives-core = { path = "../../../../primitives/core", default-featur substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 1dc7cecbb62..c8ea4490d10 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -10,19 +10,19 @@ license = "Apache-2.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } # Substrate -frame-support = { path = "../../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../../substrate/frame/system", default-features = false} -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false} -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +frame-support = { path = "../../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../../substrate/frame/system", default-features = false } +pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } +pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } +sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } +sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } +sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } # Cumulus -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -50,7 +50,7 @@ hex-literal = "0.4.1" substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "assets-common/std", "codec/std", 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 809e952ccb9..08758aaf7bb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -109,7 +109,7 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", fe sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-asset-hub-rococo/std", "bp-asset-hub-westend/std", @@ -245,9 +245,9 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 90d72ea3edc..c6ceb4b4c90 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -98,7 +98,7 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", fe sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] -default = [ "std" ] +default = ["std"] std = [ "bp-asset-hub-westend/std", "bp-bridge-hub-rococo/std", @@ -233,9 +233,9 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index bd171be53bf..7325a87165c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -12,21 +12,21 @@ log = { version = "0.4.20", default-features = false } # 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} -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} +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 } +sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } +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-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} +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 } # Cumulus asset-test-utils = { path = "../../assets/test-utils" } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -34,11 +34,11 @@ parachains-common = { path = "../../../common", default-features = false } parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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 } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm = { 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 } # Bridges bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } @@ -55,7 +55,7 @@ pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", def bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "asset-test-utils/std", "bp-header-chain/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 1801488eeed..06f0a6239e3 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -7,15 +7,10 @@ license = "Apache-2.0" description = "Westend Collectives Parachain Runtime" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ - "derive", - "max-encoded-len", -] } +codec = { package = "parity-scale-codec", version = "3.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.10.0", default-features = false, features = [ - "derive", -] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate @@ -91,7 +86,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", sp-io = { path = "../../../../../substrate/primitives/io", features = ["std"] } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", @@ -228,9 +223,9 @@ std = [ "xcm/std", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index f5626a90f36..ca45f4760d0 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -20,38 +20,38 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive smallvec = "1.11.0" # Substrate -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-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} -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} -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-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} -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false} -pallet-insecure-randomness-collective-flip = { path = "../../../../../substrate/frame/insecure-randomness-collective-flip", default-features = false} -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} -pallet-contracts = { path = "../../../../../substrate/frame/contracts", 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 } +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-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 } +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } +pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } +pallet-insecure-randomness-collective-flip = { path = "../../../../../substrate/frame/insecure-randomness-collective-flip", default-features = false } +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } +pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } +pallet-contracts = { path = "../../../../../substrate/frame/contracts", default-features = false } # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } @@ -67,7 +67,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-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 } @@ -78,7 +78,7 @@ parachain-info = { package = "staging-parachain-info", path = "../../../pallets/ parachains-common = { path = "../../../common", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -196,9 +196,9 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index a30cdf35769..b8efc4fbbcf 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -11,40 +11,40 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # 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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false} -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true} -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true} -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} -pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true} +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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } +frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } +frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } +pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true } pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +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-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-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-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 } # 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} +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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +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 } @@ -56,7 +56,7 @@ parachains-common = { path = "../../../common", default-features = false } substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", @@ -130,9 +130,9 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 65ca58ac8b3..23312172bd7 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -11,29 +11,29 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -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} -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} +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 } +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", 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-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} -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false} -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../../../substrate/primitives/version", 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-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-pallet-solo-to-para = { path = "../../../../pallets/solo-to-para", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false } @@ -44,7 +44,7 @@ parachains-common = { path = "../../../common", default-features = false } substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -77,4 +77,4 @@ std = [ "substrate-wasm-builder", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 77449f977bb..a285d3d977e 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -11,34 +11,34 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -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-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-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +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-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} -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false} -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../../../substrate/primitives/version", 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-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } # 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} +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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +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-core = { path = "../../../../primitives/core", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -48,7 +48,7 @@ parachains-common = { path = "../../../common", default-features = false } substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -97,4 +97,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 62bce02bd35..b4453e7f1a6 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -10,34 +10,34 @@ license = "Apache-2.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } # Substrate -frame-support = { path = "../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../substrate/frame/system", default-features = false} -pallet-assets = { path = "../../../../substrate/frame/assets", default-features = false} -pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false} -pallet-session = { path = "../../../../substrate/frame/session", default-features = false} -sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura", default-features = false} -sp-io = { path = "../../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../../substrate/primitives/std", default-features = false} +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } +pallet-assets = { path = "../../../../substrate/frame/assets", default-features = false } +pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } +pallet-session = { path = "../../../../substrate/frame/session", default-features = false } +sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura", default-features = false } +sp-io = { path = "../../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../../substrate/primitives/std", default-features = false } sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false} +sp-core = { path = "../../../../substrate/primitives/core", default-features = false } # Cumulus -cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue", default-features = false } pallet-collator-selection = { path = "../../../pallets/collator-selection", default-features = false } parachains-common = { path = "../../common", default-features = false } -parachain-info = {package = "staging-parachain-info", path = "../../pallets/parachain-info", default-features = false } +parachain-info = { package = "staging-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 } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false} -pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain-primitives = { path = "../../../../polkadot/parachain", default-features = false} +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false } +polkadot-parachain-primitives = { path = "../../../../polkadot/parachain", default-features = false } [dev-dependencies] hex-literal = "0.4.1" @@ -46,7 +46,7 @@ hex-literal = "0.4.1" substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "assets-common/std", "codec/std", diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index fb66275b025..6e044319d2e 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -22,52 +22,52 @@ scale-info = { version = "2.10.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-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-session = { path = "../../../../../substrate/frame/session", default-features = false} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -pallet-asset-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false} -pallet-assets = { path = "../../../../../substrate/frame/assets", 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} +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-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-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-asset-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } +pallet-assets = { path = "../../../../../substrate/frame/assets", 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-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} -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-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 } # Polkadot -polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false} -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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} +polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false } +pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", 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 } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } +cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } @@ -77,7 +77,7 @@ parachain-info = { package = "staging-parachain-info", path = "../../../pallets/ parachains-common = { path = "../../../common", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -190,4 +190,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 08fa8b69127..3903bbbe31e 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -11,44 +11,44 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # 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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false} -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false} -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false} -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false} -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} +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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } +pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +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} -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false} -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../../../substrate/primitives/version", 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-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", 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} +pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", 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 } polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } cumulus-ping = { path = "../../../pallets/ping", default-features = false } @@ -62,7 +62,7 @@ parachain-info = { package = "staging-parachain-info", path = "../../../pallets/ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-aura-ext/std", @@ -133,4 +133,4 @@ runtime-benchmarks = [ "xcm-executor/runtime-benchmarks", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/testnets-common/Cargo.toml b/cumulus/parachains/testnets-common/Cargo.toml index e39cf91d3ab..87c570d10ea 100644 --- a/cumulus/parachains/testnets-common/Cargo.toml +++ b/cumulus/parachains/testnets-common/Cargo.toml @@ -17,9 +17,9 @@ frame-support = { path = "../../../substrate/frame/support", default-features = sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } # Polkadot -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} +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 } # Cumulus @@ -29,7 +29,7 @@ polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-support/std", "polkadot-core-primitives/std", diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index cae9b3b6889..67ebc244adf 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -39,7 +39,7 @@ parachains-common = { path = "../parachains/common" } # Substrate frame-benchmarking = { path = "../../substrate/frame/benchmarking" } frame-benchmarking-cli = { path = "../../substrate/utils/frame/benchmarking-cli" } -sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false} +sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } sp-io = { path = "../../substrate/primitives/io" } sp-core = { path = "../../substrate/primitives/core" } sp-session = { path = "../../substrate/primitives/session" } @@ -109,7 +109,7 @@ substrate-build-script-utils = { path = "../../substrate/utils/build-script-util assert_cmd = "2.0" nix = { version = "0.26.1", features = ["signal"] } tempfile = "3.8.0" -tokio = { version = "1.32.0", features = ["macros", "time", "parking_lot"] } +tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } wait-timeout = "0.2" [features] diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 19607eb7c18..096ae0a9620 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -7,20 +7,20 @@ license = "Apache-2.0" description = "Core primitives for Aura in Cumulus" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } # Substrate -sp-api = { path = "../../../substrate/primitives/api", default-features = false} -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot -polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false} -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} +polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false } +polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "polkadot-core-primitives/std", diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 23839a10e46..5f68a3546e6 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -7,23 +7,23 @@ license = "Apache-2.0" description = "Cumulus related core primitive types and traits" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -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} -sp-trie = { path = "../../../substrate/primitives/trie", 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 } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } # Polkadot -polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false} -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} +polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false } +polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false } +polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "polkadot-core-primitives/std", diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 46b5da57f38..5d3c72a59f9 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -8,20 +8,20 @@ license = "Apache-2.0" [dependencies] async-trait = { version = "0.1.73", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } tracing = { version = "0.1.37", optional = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api", optional = true} -sp-api = { path = "../../../substrate/primitives/api", optional = true} -sp-core = { path = "../../../substrate/primitives/core", default-features = false} -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", optional = true} -sp-state-machine = { path = "../../../substrate/primitives/state-machine", optional = true} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-storage = { path = "../../../substrate/primitives/storage", optional = true} -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false} +sc-client-api = { path = "../../../substrate/client/api", optional = true } +sp-api = { path = "../../../substrate/primitives/api", optional = true } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", optional = true } +sp-state-machine = { path = "../../../substrate/primitives/state-machine", optional = true } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-storage = { path = "../../../substrate/primitives/storage", optional = true } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } # Cumulus cumulus-primitives-core = { path = "../core", default-features = false } @@ -29,7 +29,7 @@ cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface", o cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/cumulus/primitives/proof-size-hostfunction/Cargo.toml b/cumulus/primitives/proof-size-hostfunction/Cargo.toml index 83dad428d00..576f7f5ae99 100644 --- a/cumulus/primitives/proof-size-hostfunction/Cargo.toml +++ b/cumulus/primitives/proof-size-hostfunction/Cargo.toml @@ -17,5 +17,5 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-io = { path = "../../../substrate/primitives/io" } [features] -default = [ "std" ] -std = [ "sp-externalities/std", "sp-runtime-interface/std", "sp-trie/std" ] +default = ["std"] +std = ["sp-externalities/std", "sp-runtime-interface/std", "sp-trie/std"] diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index a0fea51f8db..ec5cb57419a 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -7,19 +7,19 @@ description = "Provides timestamp related functionality for parachains." license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.28" # Substrate -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-timestamp = { path = "../../../substrate/primitives/timestamp", default-features = false} +sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-timestamp = { path = "../../../substrate/primitives/timestamp", default-features = false } # Cumulus cumulus-primitives-core = { path = "../core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 45ce6701988..5f756c1e361 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -7,28 +7,28 @@ license = "Apache-2.0" description = "Helper datatypes for Cumulus" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.20", default-features = false } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } pallet-xcm-benchmarks = { path = "../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false } # Cumulus cumulus-primitives-core = { path = "../core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 6ab873d320c..037b8600db6 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true publish = false [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } # Substrate sc-service = { path = "../../../substrate/client/service" } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index b24ac308495..262a4ff92b5 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -7,22 +7,22 @@ license = "Apache-2.0" description = "Mocked relay state proof builder for testing Cumulus." [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } # Substrate -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false} -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} +polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-primitives-core/std", diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 3ea51c1973f..7bdb69df2c2 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -10,38 +10,38 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate -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-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false} -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false} +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-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false} -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false} -pallet-glutton = { path = "../../../substrate/frame/glutton", default-features = false} -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false} -sp-api = { path = "../../../substrate/primitives/api", default-features = false} -sp-block-builder = { path = "../../../substrate/primitives/block-builder", 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} -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-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false} -sp-version = { path = "../../../substrate/primitives/version", default-features = false} +pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } +pallet-glutton = { path = "../../../substrate/frame/glutton", default-features = false } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-block-builder = { path = "../../../substrate/primitives/block-builder", 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 } +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-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../substrate/primitives/version", default-features = false } # Cumulus -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "cumulus-pallet-parachain-system/std", diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index e35173ecf16..271c450539b 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" async-trait = "0.1.73" clap = { version = "4.4.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } -criterion = { version = "0.5.1", features = [ "async_tokio" ] } +criterion = { version = "0.5.1", features = ["async_tokio"] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" serde = { version = "1.0.193", features = ["derive"] } @@ -44,7 +44,7 @@ sp-core = { path = "../../../substrate/primitives/core" } sp-io = { path = "../../../substrate/primitives/io" } sp-api = { path = "../../../substrate/primitives/api" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-state-machine = { path = "../../../substrate/primitives/state-machine" } sp-tracing = { path = "../../../substrate/primitives/tracing" } sp-timestamp = { path = "../../../substrate/primitives/timestamp" } @@ -77,7 +77,7 @@ cumulus-test-runtime = { path = "../runtime" } cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-node" } cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } pallet-timestamp = { path = "../../../substrate/frame/timestamp" } [dev-dependencies] diff --git a/developer-hub/Cargo.toml b/developer-hub/Cargo.toml index c19d5480ec4..56f279c7e10 100644 --- a/developer-hub/Cargo.toml +++ b/developer-hub/Cargo.toml @@ -14,7 +14,7 @@ version = "0.0.1" # Needed for all FRAME-based code parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } -frame = { path = "../substrate/frame", features = ["runtime", "experimental"] } +frame = { path = "../substrate/frame", features = ["experimental", "runtime"] } pallet-examples = { path = "../substrate/frame/examples" } pallet-default-config-example = { path = "../substrate/frame/examples/default-config" } @@ -63,4 +63,4 @@ parity-scale-codec = "3.6.5" scale-info = "2.9.0" [features] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 1e05755a9b8..1f68e2979f2 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -153,6 +153,10 @@ Or if you have opened PR and you're member of `paritytech` - you can use command - `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 +## Feature Propagation + +We use [zepter](https://github.com/ggwpez/zepter) to enforce features are propagated between crates correctly. + ## Command Bot If you're member of **paritytech** org - you can use command-bot to run various of common commands in CI: diff --git a/docs/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md index 1ae9bc5003f..3df65d9699a 100644 --- a/docs/STYLE_GUIDE.md +++ b/docs/STYLE_GUIDE.md @@ -2,9 +2,11 @@ title: Style Guide for Rust in the Polkadot-SDK --- -Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo fmt` +Where possible these styles are enforced by settings in `rustfmt.toml` so if you run `cargo +nightly fmt` then you will adhere to most of these style guidelines automatically. +To see exactly which nightly version is used, check our CI job logs. + # Formatting - Indent using tabs. @@ -150,31 +152,13 @@ let mut target_path = # Manifest Formatting -> **TLDR** -> You can use the CLI tool [Zepter](https://crates.io/crates/zepter) to -> format the files: `zepter format features --fix` (or `zepter f f -f`). +We use [taplo](https://taplo.tamasfe.dev/) to enforce consistent TOML formatting. -Rust `Cargo.toml` files need to respect certain formatting rules. All entries -need to be alphabetically sorted. This makes it easier to read them and insert -new entries. The exhaustive list of rules is enforced by the CI. The general -format looks like this: +You can install it with `cargo install taplo-cli` and format your code with `taplo format --config .config/taplo.toml`. -- The feature is written as a single line if it fits within 80 chars: +See the config file for the exact rules. -```toml -[features] -default = [ "std" ] -``` +You may find useful -- Otherwise the feature is broken down into multiple lines with one entry per - line. Each line is padded with one tab and no trailing spaces but a trailing - comma. - -```toml -[features] -default = [ - "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong", - # Comments go here as well ;) - "std", -] -``` +- [Taplo VSCode extension](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +- For NeoVim, [taplo is avaliable with Mason](https://github.com/williamboman/mason-lspconfig.nvim#available-lsp-servers) diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index fb161848fb6..c0227823c6b 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -23,10 +23,10 @@ default-run = "polkadot" [dependencies] color-eyre = { version = "0.6.1", default-features = false } -tikv-jemallocator = { version = "0.5.0", optional = true, features = [ "unprefixed_malloc_on_supported_platforms" ] } +tikv-jemallocator = { version = "0.5.0", optional = true, features = ["unprefixed_malloc_on_supported_platforms"] } # Crates in our workspace, defined as dependencies so we can pass them feature flags. -polkadot-cli = { path = "cli", features = [ "westend-native", "rococo-native" ] } +polkadot-cli = { path = "cli", features = ["rococo-native", "westend-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" } @@ -36,7 +36,7 @@ polkadot-node-core-pvf-common = { path = "node/core/pvf/common" } polkadot-node-core-pvf-execute-worker = { path = "node/core/pvf/execute-worker" } [target.'cfg(target_os = "linux")'.dependencies] -tikv-jemallocator = { version = "0.5.0", features = [ "unprefixed_malloc_on_supported_platforms" ] } +tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_supported_platforms"] } [dev-dependencies] assert_cmd = "2.0.4" @@ -53,23 +53,23 @@ substrate-build-script-utils = { path = "../substrate/utils/build-script-utils" maintenance = { status = "actively-developed" } [features] -runtime-benchmarks = [ "polkadot-cli/runtime-benchmarks" ] -try-runtime = [ "polkadot-cli/try-runtime" ] -fast-runtime = [ "polkadot-cli/fast-runtime" ] -runtime-metrics = [ "polkadot-cli/runtime-metrics" ] -pyroscope = [ "polkadot-cli/pyroscope" ] +runtime-benchmarks = ["polkadot-cli/runtime-benchmarks"] +try-runtime = ["polkadot-cli/try-runtime"] +fast-runtime = ["polkadot-cli/fast-runtime"] +runtime-metrics = ["polkadot-cli/runtime-metrics"] +pyroscope = ["polkadot-cli/pyroscope"] jemalloc-allocator = [ "dep:tikv-jemallocator", "polkadot-node-core-pvf-prepare-worker/jemalloc-allocator", "polkadot-node-core-pvf/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator", ] -network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] +network-protocol-staging = ["polkadot-cli/network-protocol-staging"] # 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" ] +ci-only-tests = ["polkadot-node-core-pvf/ci-only-tests"] # Configuration for building a .deb package - for use with `cargo-deb` [package.metadata.deb] @@ -89,12 +89,12 @@ assets = [ [ "target/release/polkadot-prepare-worker", "/usr/lib/polkadot/", - "755" + "755", ], [ "target/release/polkadot-execute-worker", "/usr/lib/polkadot/", - "755" + "755", ], [ "scripts/packaging/polkadot.service", diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 768077b8bf2..0882d20f2b7 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -43,8 +43,8 @@ sc-storage-monitor = { path = "../../substrate/client/storage-monitor" } substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" } [features] -default = [ "cli", "db", "full-node" ] -db = [ "service/db" ] +default = ["cli", "db", "full-node"] +db = ["service/db"] cli = [ "clap", "frame-benchmarking-cli", @@ -60,19 +60,19 @@ runtime-benchmarks = [ "sc-service?/runtime-benchmarks", "service/runtime-benchmarks", ] -full-node = [ "service/full-node" ] -try-runtime = [ "service/try-runtime", "try-runtime-cli/try-runtime" ] -fast-runtime = [ "service/fast-runtime" ] -pyroscope = [ "pyro", "pyroscope_pprofrs" ] +full-node = ["service/full-node"] +try-runtime = ["service/try-runtime", "try-runtime-cli/try-runtime"] +fast-runtime = ["service/fast-runtime"] +pyroscope = ["pyro", "pyroscope_pprofrs"] # Configure the native runtimes to use. -westend-native = [ "service/westend-native" ] -rococo-native = [ "service/rococo-native" ] +westend-native = ["service/westend-native"] +rococo-native = ["service/rococo-native"] -malus = [ "full-node", "service/malus" ] +malus = ["full-node", "service/malus"] runtime-metrics = [ "polkadot-node-metrics/runtime-metrics", "service/runtime-metrics", ] -network-protocol-staging = [ "service/network-protocol-staging" ] +network-protocol-staging = ["service/network-protocol-staging"] diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index f843ec17943..1b8da759c15 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -11,10 +11,10 @@ sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive" ] } +parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } [features] -default = [ "std" ] +default = ["std"] std = [ "parity-scale-codec/std", "scale-info/std", diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index ccfe7f14eb4..c965f5d70aa 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true polkadot-primitives = { path = "../primitives" } polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" } novelpoly = { package = "reed-solomon-novelpoly", version = "1.0.0" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["std", "derive"] } +parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "std"] } sp-core = { path = "../../substrate/primitives/core" } sp-trie = { path = "../../substrate/primitives/trie" } thiserror = "1.0.48" diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index c1848f47fc6..e0c86d233f9 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -15,7 +15,7 @@ polkadot-node-subsystem = { path = "../subsystem" } polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-primitives = { path = "../../primitives" } sp-core = { path = "../../../substrate/primitives/core" } -sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } +sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } thiserror = "1.0.48" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 59a6708f17e..9516dc52a30 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -39,7 +39,8 @@ rand = "0.8.5" [dev-dependencies] async-trait = "0.1.57" parking_lot = "0.12.0" -rand_core = "0.5.1" # should match schnorrkel +# rand_core should match schnorrkel +rand_core = "0.5.1" sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } sp-core = { path = "../../../../substrate/primitives/core" } diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 13ecb356f2c..d27e2343925 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-provisioner" version = "1.0.0" -description="Responsible for assembling a relay chain block from a set of available parachain candidates" +description = "Responsible for assembling a relay chain block from a set of available parachain candidates" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 05509a5f853..2d15a25b887 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -39,7 +39,7 @@ polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = tr [dev-dependencies] assert_matches = "1.4.0" -criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support", "async_tokio"] } +criterion = { version = "0.4.0", default-features = false, features = ["async_tokio", "cargo_bench_support"] } hex-literal = "0.4.1" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } @@ -62,7 +62,7 @@ harness = false [features] ci-only-tests = [] -jemalloc-allocator = [ "polkadot-node-core-pvf-common/jemalloc-allocator" ] +jemalloc-allocator = ["polkadot-node-core-pvf-common/jemalloc-allocator"] # This feature is used to export test code to other crates without putting it in the production build. test-utils = [ "polkadot-node-core-pvf-execute-worker", diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 40e0ff4f0a1..6e6206cf1b9 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true cpu-time = "1.0.0" gum = { package = "tracing-gum", path = "../../../gum" } os_pipe = "1.1.4" -nix = { version = "0.27.1", features = ["resource", "process"]} +nix = { version = "0.27.1", features = ["process", "resource"] } libc = "0.2.139" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 005f2e93511..4e53f7f46ca 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -16,7 +16,7 @@ tracking-allocator = { package = "staging-tracking-allocator", path = "../../../ tikv-jemalloc-ctl = { version = "0.5.0", optional = true } tikv-jemallocator = { version = "0.5.0", optional = true } os_pipe = "1.1.4" -nix = { version = "0.27.1", features = ["resource", "process"]} +nix = { version = "0.27.1", features = ["process", "resource"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index f324f1e79c4..965b280a747 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-runtime-api" version = "1.0.0" -description="Wrapper around the parachain-related runtime APIs" +description = "Wrapper around the parachain-related runtime APIs" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 1ffaf6160ba..cd6e19b3dd2 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.38", features = ["full", "extra-traits"] } +syn = { version = "2.0.38", features = ["extra-traits", "full"] } 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 cd0a25d7593..1958bcf4620 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", "westend-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" } @@ -62,4 +62,4 @@ substrate-build-script-utils = { path = "../../../substrate/utils/build-script-u [features] default = [] -fast-runtime = [ "polkadot-cli/fast-runtime" ] +fast-runtime = ["polkadot-cli/fast-runtime"] diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index e13ae63199f..e8e00a64c05 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -11,7 +11,7 @@ futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } -metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features = ["futures_channel"] } # Both `sc-service` and `sc-cli` are required by runtime metrics `logger_hook()`. sc-service = { path = "../../../substrate/client/service" } sc-cli = { path = "../../../substrate/client/cli" } @@ -28,11 +28,11 @@ assert_cmd = "2.0.4" tempfile = "3.2.0" hyper = { version = "0.14.20", default-features = false, features = ["http1", "tcp"] } tokio = "1.24.2" -polkadot-test-service = { path = "../test/service", features=["runtime-metrics"]} +polkadot-test-service = { path = "../test/service", features = ["runtime-metrics"] } substrate-test-utils = { path = "../../../substrate/test-utils" } sc-service = { path = "../../../substrate/client/service" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -prometheus-parse = {version = "0.2.2"} +prometheus-parse = { version = "0.2.2" } [features] default = [] diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index f8a7cc15f87..7db4aa77b7a 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -31,7 +31,8 @@ polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } assert_matches = "1.4.0" schnorrkel = { version = "0.9.1", default-features = false } -rand_core = "0.5.1" # should match schnorrkel +# rand_core should match schnorrkel +rand_core = "0.5.1" rand_chacha = "0.3.1" env_logger = "0.9.0" log = "0.4.17" diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index ac1e4443f0c..d9266055a39 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -17,14 +17,14 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-node-subsystem-types = { path = "../subsystem-types" } polkadot-node-metrics = { path = "../metrics" } polkadot-primitives = { path = "../../primitives" } -orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } +orchestra = { version = "0.3.3", default-features = false, features = ["futures_channel"] } gum = { package = "tracing-gum", path = "../gum" } sp-core = { path = "../../../substrate/primitives/core" } async-trait = "0.1.57" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } [dev-dependencies] -metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features = ["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } futures = { version = "0.3.21", features = ["thread-pool"] } femme = "2.2.1" @@ -36,8 +36,8 @@ node-test-helpers = { package = "polkadot-node-subsystem-test-helpers", path = " tikv-jemalloc-ctl = "0.5.0" [features] -default = [ "futures_channel" ] -dotgraph = [ "orchestra/dotgraph" ] -expand = [ "orchestra/expand" ] -futures_channel = [ "metered/futures_channel", "orchestra/futures_channel" ] -jemalloc-allocator = [ "dep:tikv-jemalloc-ctl" ] +default = ["futures_channel"] +dotgraph = ["orchestra/dotgraph"] +expand = ["orchestra/expand"] +futures_channel = ["metered/futures_channel", "orchestra/futures_channel"] +jemalloc-allocator = ["dep:tikv-jemalloc-ctl"] diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index b5aa46a41dc..b48302edf52 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -148,9 +148,9 @@ serial_test = "2.0.0" tempfile = "3.2" [features] -default = [ "db", "full-node" ] +default = ["db", "full-node"] -db = [ "service/rocksdb" ] +db = ["service/rocksdb"] full-node = [ "kvdb-rocksdb", @@ -181,8 +181,8 @@ full-node = [ ] # Configure the native runtimes to use. -westend-native = [ "westend-runtime", "westend-runtime-constants" ] -rococo-native = [ "rococo-runtime", "rococo-runtime-constants" ] +westend-native = ["westend-runtime", "westend-runtime-constants"] +rococo-native = ["rococo-runtime", "rococo-runtime-constants"] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", @@ -219,7 +219,7 @@ fast-runtime = [ "westend-runtime?/fast-runtime", ] -malus = [ "full-node" ] +malus = ["full-node"] runtime-metrics = [ "polkadot-runtime-parachains/runtime-metrics", "rococo-runtime?/runtime-metrics", diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 71e5257cab9..dfda6c1b3c5 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -14,7 +14,7 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-statement-table = { path = "../../statement-table" } polkadot-node-jaeger = { path = "../jaeger" } -orchestra = { version = "0.3.3", default-features = false, features=["futures_channel"] } +orchestra = { version = "0.3.3", default-features = false, features = ["futures_channel"] } sc-network = { path = "../../../substrate/client/network" } sp-api = { path = "../../../substrate/primitives/api" } sp-blockchain = { path = "../../../substrate/primitives/blockchain" } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index d9364e2c2c0..94e1f5a3f12 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -29,7 +29,7 @@ polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } polkadot-overseer = { path = "../overseer" } -metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features=["futures_channel"] } +metered = { package = "prioritized-metered-channel", version = "0.5.1", default-features = false, features = ["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } @@ -37,7 +37,7 @@ sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-client-api = { path = "../../../substrate/client/api" } kvdb = "0.13.0" -parity-db = { version = "0.4.8"} +parity-db = { version = "0.4.8" } [dev-dependencies] assert_matches = "1.4.0" diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index bc4ff74be4b..646f1ea9732 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -38,7 +38,7 @@ sp-keyring = { path = "../../../../substrate/primitives/keyring" } futures = "0.3.21" [features] -runtime-benchmarks= [ +runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-test-runtime/runtime-benchmarks", diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 437fa66b75a..aa143f40300 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -63,8 +63,8 @@ substrate-test-utils = { path = "../../../../substrate/test-utils" } tokio = { version = "1.24.2", features = ["macros"] } [features] -runtime-metrics=[ "polkadot-test-runtime/runtime-metrics" ] -runtime-benchmarks= [ +runtime-metrics = ["polkadot-test-runtime/runtime-metrics"] +runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-staking/runtime-benchmarks", diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 9aa4dc10a5f..7c8935d987e 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -10,7 +10,7 @@ version = "1.0.0" # note: special care is taken to avoid inclusion of `sp-io` externals when compiling # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. -parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive" ] } +parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } @@ -21,10 +21,10 @@ derive_more = "0.99.11" bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } # all optional crates. -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } [features] -default = [ "std" ] +default = ["std"] wasm-api = [] std = [ "bounded-collections/std", @@ -37,4 +37,4 @@ std = [ "sp-std/std", "sp-weights/std", ] -runtime-benchmarks = [ "sp-runtime/runtime-benchmarks" ] +runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index 3252d1f83cd..7bbeda4893b 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -18,5 +18,5 @@ halt = { package = "test-parachain-halt", path = "halt" } sp-core = { path = "../../../substrate/primitives/core" } [features] -default = [ "std" ] -std = [ "adder/std", "halt/std", "parity-scale-codec/std" ] +default = ["std"] +std = ["adder/std", "halt/std", "parity-scale-codec/std"] diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index 1a47328b28e..ee0f6f551af 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -9,18 +9,18 @@ authors.workspace = true publish = false [dependencies] -parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = [ "wasm-api" ] } +parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } -dlmalloc = { version = "0.2.4", features = [ "global" ] } +dlmalloc = { version = "0.2.4", features = ["global"] } # We need to make sure the global allocator is disabled until we have support of full substrate externalities -sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = [ "disable_allocator" ] } +sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = ["disable_allocator"] } [build-dependencies] substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] -std = [ "parachain/std", "parity-scale-codec/std", "sp-io/std", "sp-std/std" ] +default = ["std"] +std = ["parachain/std", "parity-scale-codec/std", "sp-io/std", "sp-std/std"] diff --git a/polkadot/parachain/test-parachains/halt/Cargo.toml b/polkadot/parachain/test-parachains/halt/Cargo.toml index cb2918273eb..428f33f730e 100644 --- a/polkadot/parachain/test-parachains/halt/Cargo.toml +++ b/polkadot/parachain/test-parachains/halt/Cargo.toml @@ -15,5 +15,5 @@ substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } rustversion = "1.0.6" [features] -default = [ "std" ] +default = ["std"] std = [] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 273eef4b63a..e763b65cfdd 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -9,21 +9,21 @@ edition.workspace = true license.workspace = true [dependencies] -parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = [ "wasm-api" ] } +parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } -dlmalloc = { version = "0.2.4", features = [ "global" ] } +dlmalloc = { version = "0.2.4", features = ["global"] } log = { version = "0.4.17", default-features = false } # We need to make sure the global allocator is disabled until we have support of full substrate externalities -sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = [ "disable_allocator" ] } +sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = ["disable_allocator"] } [build-dependencies] substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "log/std", "parachain/std", diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index b7eab13bb9c..0de349eac01 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -41,4 +41,4 @@ sp-keyring = { path = "../../../../../substrate/primitives/keyring" } tokio = { version = "1.24.2", features = ["macros"] } [features] -network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] +network-protocol-staging = ["polkadot-cli/network-protocol-staging"] diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 78a25d67081..5e746c622cf 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -11,7 +11,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "se hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } application-crypto = { package = "sp-application-crypto", path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } inherents = { package = "sp-inherents", path = "../../substrate/primitives/inherents", default-features = false } @@ -30,7 +30,7 @@ polkadot-core-primitives = { path = "../core-primitives", default-features = fal polkadot-parachain-primitives = { path = "../parachain", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "application-crypto/std", "bitvec/std", diff --git a/polkadot/roadmap/implementers-guide/book.toml b/polkadot/roadmap/implementers-guide/book.toml index f677c0d59c0..f91591ff170 100644 --- a/polkadot/roadmap/implementers-guide/book.toml +++ b/polkadot/roadmap/implementers-guide/book.toml @@ -15,7 +15,7 @@ renderer = ["html"] [output.html] additional-css = ["last-changed.css"] -additional-js = ["mermaid.min.js", "mermaid-init.js"] +additional-js = ["mermaid-init.js", "mermaid.min.js"] # Repository URL used in the last-changed link. git-repository-url = "https://github.com/paritytech/polkadot-sdk" diff --git a/polkadot/roadmap/phase-1.toml b/polkadot/roadmap/phase-1.toml index 50ef1f741fe..3a5f0d752de 100644 --- a/polkadot/roadmap/phase-1.toml +++ b/polkadot/roadmap/phase-1.toml @@ -14,7 +14,7 @@ requires = ["phase-0"] items = [ { label = "Buffer submitted parachain candidate until considered available." }, { label = "Validators submit signed bitfields re: availability of parachains" }, - { label = "relay chain fully includes candidate once considered available" } + { label = "relay chain fully includes candidate once considered available" }, ] [[group]] @@ -23,8 +23,8 @@ label = "Secondary checks and self-selection by validators" requires = ["two-phase-inclusion"] items = [ { label = "Extract #VCheck for all checkable candidates" }, - { label = "Maintain a frontier of candidates that are likely to be checked soon" }, { label = "Listen for new reports on candidates and new checks to update frontier" }, + { label = "Maintain a frontier of candidates that are likely to be checked soon" }, ] [[group]] @@ -32,8 +32,8 @@ name = "runtime-availability-validity-slashing" label = "Availability and Validity slashing in the runtime" requires = ["two-phase-inclusion"] items = [ + { label = "Submit secondary checks to runtime", port = "submitsecondary", requires = ["secondary-checking"] }, { label = "Track all candidates within the slash period as well as their session" }, - { label = "Submit secondary checks to runtime", port = "submitsecondary", requires = ["secondary-checking"]}, { label = "Track reports and attestatations for candidates" }, ] @@ -41,10 +41,10 @@ items = [ name = "non-direct-ancestor" label = "Allow candidates with non-direct ancestor" items = [ - { label = "Extend GlobalValidationData with random seed and session index"}, { label = "Block author can provide minimally-attested candidate with older relay parent" }, - { label = "Runtime can accept and process candidates with older relay-parent" }, + { label = "Extend GlobalValidationData with random seed and session index" }, { label = "Revise availability-store pruning to ensure only needed data is kept" }, + { label = "Runtime can accept and process candidates with older relay-parent" }, ] [[group]] @@ -52,13 +52,13 @@ name = "grandpa-voting-rule" label = "GRANDPA voting rule to follow valid/available chains" requires = ["runtime-availability-validity-slashing"] items = [ - { label = "Add a utility to flag a block and all of its ancestors as abandoned" }, { label = "Accept new blocks on abandoned but mark them abandoned as well." }, + { label = "Add a utility to flag a block and all of its ancestors as abandoned" }, { label = "Do not vote or build on abandoned chains" }, ] [[group]] name = "phase-1" label = "Phase 1: Availability and Validity" -requires = ["non-direct-ancestor", "grandpa-voting-rule", "runtime-availability-validity-slashing"] +requires = ["grandpa-voting-rule", "non-direct-ancestor", "runtime-availability-validity-slashing"] items = [] diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 053eb88967f..7e8461c73ef 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -21,11 +21,11 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false inherents = { package = "sp-inherents", path = "../../../substrate/primitives/inherents", 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-runtime = { path = "../../../substrate/primitives/runtime", default-features = false , features=["serde"]} +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features=["serde"] } -sp-core = { path = "../../../substrate/primitives/core", default-features = false , features=["serde"]} -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false, features=["serde"] } +sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features = ["serde"] } +sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } +sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false, features = ["serde"] } pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } @@ -70,7 +70,7 @@ libsecp256k1 = "0.7.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } [features] -default = [ "std" ] +default = ["std"] no_std = [] std = [ "bitvec/std", diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index 59c76a6cabb..f31811c1272 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -14,5 +14,5 @@ sp-std = { package = "sp-std", path = "../../../../substrate/primitives/std", de sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } [features] -default = [ "std" ] -std = [ "parity-scale-codec/std", "sp-runtime/std", "sp-std/std" ] +default = ["std"] +std = ["parity-scale-codec/std", "sp-runtime/std", "sp-std/std"] diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index cdfab82d00c..ad4a2fa9207 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true description = "Runtime metric interface for the Polkadot node" [dependencies] -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false} +sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } @@ -16,7 +16,7 @@ frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-f bs58 = { version = "0.5.0", default-features = false, features = ["alloc"] } [features] -default = [ "std" ] +default = ["std"] std = [ "bs58/std", "frame-benchmarking?/std", @@ -25,4 +25,4 @@ std = [ "sp-std/std", "sp-tracing/std", ] -runtime-metrics = [ "frame-benchmarking", "sp-tracing/with-tracing" ] +runtime-metrics = ["frame-benchmarking", "sp-tracing/with-tracing"] diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 9e8c9a5c759..2627bc9ef49 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -13,7 +13,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } derive_more = "0.99.17" bitflags = "1.3.2" @@ -21,10 +21,10 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false inherents = { package = "sp-inherents", path = "../../../substrate/primitives/inherents", 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-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features=["serde"] } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features=["serde"] } -sp-core = { path = "../../../substrate/primitives/core", default-features = false, features=["serde"] } +sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features = ["serde"] } +sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } sp-keystore = { path = "../../../substrate/primitives/keystore", optional = true } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false, optional = true } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false, optional = true } @@ -50,7 +50,7 @@ rand = { version = "0.8.5", default-features = false } rand_chacha = { version = "0.3.1", default-features = false } static_assertions = { version = "1.1.0", optional = true } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } -polkadot-runtime-metrics = { path = "../metrics", default-features = false} +polkadot-runtime-metrics = { path = "../metrics", default-features = false } polkadot-core-primitives = { path = "../../core-primitives", default-features = false } [dev-dependencies] @@ -66,7 +66,7 @@ assert_matches = "1" serde_json = "1.0.108" [features] -default = [ "std" ] +default = ["std"] no_std = [] std = [ "bitvec/std", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 926768e9748..1edce2aa44d 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -53,7 +53,7 @@ pallet-collective = { path = "../../../substrate/frame/collective", default-feat 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 } +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 } @@ -105,7 +105,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", [dev-dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } +remote-externalities = { package = "frame-remote-externalities", path = "../../../substrate/utils/frame/remote-externalities" } sp-trie = { path = "../../../substrate/primitives/trie" } separator = "0.4.1" serde_json = "1.0.108" @@ -116,7 +116,7 @@ tokio = { version = "1.24.2", features = ["macros"] } substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] no_std = [] std = [ "authority-discovery-primitives/std", @@ -313,11 +313,11 @@ try-runtime = [ ] # Set timing constants (e.g. session period) to faster versions to speed up testing. -fast-runtime = [ "rococo-runtime-constants/fast-runtime" ] +fast-runtime = ["rococo-runtime-constants/fast-runtime"] -runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] +runtime-metrics = ["runtime-parachains/runtime-metrics", "sp-io/with-tracing"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index 8ff6d57ea5b..e052c89311f 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -19,7 +19,7 @@ sp-core = { path = "../../../../substrate/primitives/core", default-features = f xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-support/std", "primitives/std", diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 85e452d1bd4..850047c83bc 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -77,7 +77,7 @@ serde_json = "1.0.108" substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] no_std = [] only-staking = [] runtime-metrics = [ diff --git a/polkadot/runtime/test-runtime/constants/Cargo.toml b/polkadot/runtime/test-runtime/constants/Cargo.toml index d83e92a6ce8..88cd441f73b 100644 --- a/polkadot/runtime/test-runtime/constants/Cargo.toml +++ b/polkadot/runtime/test-runtime/constants/Cargo.toml @@ -17,7 +17,7 @@ sp-weights = { path = "../../../../substrate/primitives/weights", default-featur sp-core = { path = "../../../../substrate/primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-support/std", "primitives/std", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index c31db2703c1..d8402ff39ee 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -46,7 +46,7 @@ frame-support = { path = "../../../substrate/frame/support", default-features = 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-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 } @@ -117,7 +117,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } serde_json = "1.0.108" -remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } +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 } @@ -125,7 +125,7 @@ sp-tracing = { path = "../../../substrate/primitives/tracing", default-features substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] no_std = [] only-staking = [] std = [ @@ -339,9 +339,9 @@ try-runtime = [ # 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" ] +runtime-metrics = ["runtime-parachains/runtime-metrics", "sp-io/with-tracing"] # A feature that should be enabled when the runtime should be built 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" ] +on-chain-release-build = ["sp-api/disable-logging"] diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index 2243210975b..24f0da63b04 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -19,7 +19,7 @@ sp-core = { path = "../../../../substrate/primitives/core", default-features = f xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-support/std", "primitives/std", diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 8190b812bf6..8fa0d128950 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -8,10 +8,10 @@ license.workspace = true [dependencies] bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } -derivative = { version = "2.2.0", default-features = false, features = [ "use_core" ] } +derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -parity-scale-codec = { version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len" ] } +parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } @@ -24,7 +24,7 @@ hex = "0.4.3" hex-literal = "0.4.1" [features] -default = [ "std" ] +default = ["std"] wasm-api = [] std = [ "bounded-collections/std", diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 5be0bbe4ae5..5438279c673 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -12,13 +12,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../substrate/frame/system", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} -sp-io = { path = "../../../substrate/primitives/io", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false} +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } log = "0.4.17" @@ -36,7 +36,7 @@ polkadot-runtime-common = { path = "../../runtime/common" } polkadot-primitives = { path = "../../primitives" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 209c826b8f8..645ac8f9941 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -13,12 +13,12 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.193", optional = true, features = ["derive"] } log = { version = "0.4.17", 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-io = { path = "../../../substrate/primitives/io", default-features = false} -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} -sp-std = { path = "../../../substrate/primitives/std", default-features = false} +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } @@ -34,7 +34,7 @@ polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } [features] -default = [ "std" ] +default = ["std"] std = [ "bounded-collections/std", "codec/std", diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 7d6c40eb841..53743066720 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -37,7 +37,7 @@ assert_matches = "1.5.0" polkadot-test-runtime = { path = "../../runtime/test-runtime" } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index d5edb1ea0f5..b435c2d510a 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -23,7 +23,7 @@ log = { version = "0.4.17", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index ddb45965ee4..0818d16a262 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -26,5 +26,5 @@ xcm-executor = { package = "staging-xcm-executor", path = ".." } sp-tracing = { path = "../../../../substrate/primitives/tracing" } [features] -default = [ "std" ] -std = [ "frame-support/std", "sp-runtime/std", "xcm/std" ] +default = ["std"] +std = ["frame-support/std", "sp-runtime/std", "xcm/std"] diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 56f123a4719..d8c8c7740b0 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -24,9 +24,9 @@ jsonrpsee = { version = "0.16.2", features = ["server"] } serde_json = "1.0.108" sc-cli = { path = "../../../client/cli" } -sc-executor = { path = "../../../client/executor" } -sc-network = { path = "../../../client/network" } -sc-service = { path = "../../../client/service" } +sc-executor = { path = "../../../client/executor" } +sc-network = { path = "../../../client/network" } +sc-service = { path = "../../../client/service" } sc-telemetry = { path = "../../../client/telemetry" } sc-transaction-pool = { path = "../../../client/transaction-pool" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } @@ -47,7 +47,7 @@ sp-runtime = { path = "../../../primitives/runtime" } substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } -frame = { path = "../../../frame", features = ["runtime", "experimental"] } +frame = { path = "../../../frame", features = ["experimental", "runtime"] } runtime = { package = "minimal-runtime", path = "../runtime" } [build-dependencies] diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index 85d56d0638a..f7685642d27 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -13,8 +13,8 @@ parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { path = "../../../frame", default-features = false, features = ["runtime", "experimental"] } -frame-support = { path = "../../../frame/support", default-features = false} +frame = { path = "../../../frame", default-features = false, features = ["experimental", "runtime"] } +frame-support = { path = "../../../frame/support", default-features = false } # pallets that we want to use pallet-balances = { path = "../../../frame/balances", default-features = false } @@ -24,14 +24,14 @@ pallet-transaction-payment = { path = "../../../frame/transaction-payment", defa pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } # genesis builder that allows us to interacto with runtime genesis config -sp-genesis-builder = { path = "../../../primitives/genesis-builder", default-features = false} +sp-genesis-builder = { path = "../../../primitives/genesis-builder", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-support/std", "frame/std", diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index ed1980fbb82..a76aaf2a631 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -18,7 +18,7 @@ name = "node-template" [dependencies] clap = { version = "4.4.10", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"]} +futures = { version = "0.3.21", features = ["thread-pool"] } serde_json = "1.0.108" sc-cli = { path = "../../../client/cli" } @@ -42,7 +42,7 @@ sp-timestamp = { path = "../../../primitives/timestamp" } sp-inherents = { path = "../../../primitives/inherents" } sp-keyring = { path = "../../../primitives/keyring" } frame-system = { path = "../../../frame/system" } -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false} +pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } # These dependencies are used for the node template's RPCs jsonrpsee = { version = "0.16.2", features = ["server"] } @@ -62,7 +62,7 @@ frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli" } node-template-runtime = { path = "../runtime" } # CLI-specific dependencies -try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} +try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true } [build-dependencies] substrate-build-script-utils = { path = "../../../utils/build-script-utils" } diff --git a/substrate/bin/node-template/pallets/template/Cargo.toml b/substrate/bin/node-template/pallets/template/Cargo.toml index 77183c42cd6..405d9c229f8 100644 --- a/substrate/bin/node-template/pallets/template/Cargo.toml +++ b/substrate/bin/node-template/pallets/template/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../../../frame/benchmarking", default-features = false, optional = true} -frame-support = { path = "../../../../frame/support", default-features = false} -frame-system = { path = "../../../../frame/system", default-features = false} -sp-std = { path = "../../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../../../frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../../frame/support", default-features = false } +frame-system = { path = "../../../../frame/system", default-features = false } +sp-std = { path = "../../../../primitives/std", default-features = false } [dev-dependencies] sp-core = { path = "../../../../primitives/core" } @@ -28,7 +28,7 @@ sp-io = { path = "../../../../primitives/io" } sp-runtime = { path = "../../../../primitives/runtime" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 7711ddba34d..55fb03159ab 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -16,48 +16,48 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -pallet-aura = { path = "../../../frame/aura", default-features = false} -pallet-balances = { path = "../../../frame/balances", default-features = false} -frame-support = { path = "../../../frame/support", default-features = false} -pallet-grandpa = { path = "../../../frame/grandpa", default-features = false} -pallet-sudo = { path = "../../../frame/sudo", default-features = false} -frame-system = { path = "../../../frame/system", default-features = false} +pallet-aura = { path = "../../../frame/aura", default-features = false } +pallet-balances = { path = "../../../frame/balances", default-features = false } +frame-support = { path = "../../../frame/support", default-features = false } +pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } +pallet-sudo = { path = "../../../frame/sudo", default-features = false } +frame-system = { path = "../../../frame/system", default-features = false } frame-try-runtime = { path = "../../../frame/try-runtime", default-features = false, optional = true } -pallet-timestamp = { path = "../../../frame/timestamp", default-features = false} -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false} -frame-executive = { path = "../../../frame/executive", default-features = false} -sp-api = { path = "../../../primitives/api", default-features = false} -sp-block-builder = { path = "../../../primitives/block-builder", default-features = false} +pallet-timestamp = { path = "../../../frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } +frame-executive = { path = "../../../frame/executive", default-features = false } +sp-api = { path = "../../../primitives/api", default-features = false } +sp-block-builder = { path = "../../../primitives/block-builder", default-features = false } sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false, features = ["serde"] } sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"]} -sp-inherents = { path = "../../../primitives/inherents", default-features = false} -sp-offchain = { path = "../../../primitives/offchain", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"] } +sp-inherents = { path = "../../../primitives/inherents", default-features = false } +sp-offchain = { path = "../../../primitives/offchain", default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../../primitives/session", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} -sp-storage = { path = "../../../primitives/storage", default-features = false} -sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false} +sp-session = { path = "../../../primitives/session", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-storage = { path = "../../../primitives/storage", default-features = false } +sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false } sp-version = { path = "../../../primitives/version", default-features = false, features = ["serde"] } serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } # Used for the node template's RPCs -frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false} +frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } # Used for runtime benchmarking frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false, optional = true } frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true } # Local Dependencies -pallet-template = { path = "../pallets/template", default-features = false} +pallet-template = { path = "../pallets/template", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", @@ -119,4 +119,4 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "sp-runtime/try-runtime", ] -experimental = [ "pallet-aura/experimental" ] +experimental = ["pallet-aura/experimental"] diff --git a/substrate/bin/node-template/rust-toolchain.toml b/substrate/bin/node-template/rust-toolchain.toml index 64daeff6836..2a35c6ed07c 100644 --- a/substrate/bin/node-template/rust-toolchain.toml +++ b/substrate/bin/node-template/rust-toolchain.toml @@ -6,9 +6,9 @@ components = [ "rust-analyzer", "rust-src", "rust-std", - "rustc-dev", "rustc", + "rustc-dev", "rustfmt", ] -targets = [ "wasm32-unknown-unknown" ] +targets = ["wasm32-unknown-unknown"] profile = "minimal" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index a3fb8b43030..5ce91dc3c44 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { path = "../../../primitives/core" } sp-consensus = { path = "../../../primitives/consensus/common" } sc-basic-authorship = { path = "../../../client/basic-authorship" } sp-inherents = { path = "../../../primitives/inherents" } -sp-timestamp = { path = "../../../primitives/timestamp", default-features = false} +sp-timestamp = { path = "../../../primitives/timestamp", default-features = false } sp-tracing = { path = "../../../primitives/tracing" } hash-db = "0.16.0" tempfile = "3.1.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 3e8ffdf83d0..e511633ff50 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -79,7 +79,7 @@ sc-consensus-babe = { path = "../../../client/consensus/babe" } grandpa = { package = "sc-consensus-grandpa", path = "../../../client/consensus/grandpa" } sc-rpc = { path = "../../../client/rpc" } sc-basic-authorship = { path = "../../../client/basic-authorship" } -sc-service = { path = "../../../client/service", default-features = false} +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" } @@ -96,8 +96,8 @@ frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api" pallet-assets = { path = "../../../frame/assets" } pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment" } pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment" } -pallet-im-online = { path = "../../../frame/im-online", default-features = false} -pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false} +pallet-im-online = { path = "../../../frame/im-online", default-features = false } +pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false } # node-specific dependencies kitchensink-runtime = { path = "../runtime" } @@ -105,10 +105,10 @@ node-rpc = { path = "../rpc" } node-primitives = { path = "../primitives" } # CLI-specific dependencies -sc-cli = { path = "../../../client/cli", optional = true} -frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} -node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} -try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} +sc-cli = { path = "../../../client/cli", optional = true } +frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } +node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } +try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true } serde_json = "1.0.108" [dev-dependencies] @@ -129,7 +129,7 @@ regex = "1.6.0" platforms = "3.0" soketto = "0.7.1" criterion = { version = "0.4.0", features = ["async_tokio"] } -tokio = { version = "1.22.0", features = ["macros", "time", "parking_lot"] } +tokio = { version = "1.22.0", features = ["macros", "parking_lot", "time"] } tokio-util = { version = "0.7.4", features = ["compat"] } wait-timeout = "0.2" substrate-rpc-client = { path = "../../../utils/frame/rpc/client" } @@ -159,17 +159,17 @@ sp-state-machine = { path = "../../../primitives/state-machine" } [build-dependencies] clap = { version = "4.4.10", optional = true } clap_complete = { version = "4.0.2", optional = true } -node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true} -frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} -substrate-build-script-utils = { path = "../../../utils/build-script-utils", optional = true} -substrate-frame-cli = { path = "../../../utils/frame/frame-utilities-cli", optional = true} -try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true} +node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } +frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } +substrate-build-script-utils = { path = "../../../utils/build-script-utils", optional = true } +substrate-frame-cli = { path = "../../../utils/frame/frame-utilities-cli", optional = true } +try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true } sc-cli = { path = "../../../client/cli", optional = true } pallet-balances = { path = "../../../frame/balances" } sc-storage-monitor = { path = "../../../client/storage-monitor" } [features] -default = [ "cli" ] +default = ["cli"] cli = [ "clap", "clap_complete", diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index a5187d8f265..cdf4b1ff146 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } sc-client-api = { path = "../../../client/api" } -sc-service = { path = "../../../client/service", default-features = false} +sc-service = { path = "../../../client/service", default-features = false } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index 77bf7ad4676..40735ff21d4 100644 --- a/substrate/bin/node/primitives/Cargo.toml +++ b/substrate/bin/node/primitives/Cargo.toml @@ -13,9 +13,9 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } [features] -default = [ "std" ] -std = [ "sp-core/std", "sp-runtime/std" ] +default = ["std"] +std = ["sp-core/std", "sp-runtime/std"] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index cb4970e7c9d..e53646c0ef4 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -26,122 +26,122 @@ log = { version = "0.4.17", default-features = false } serde_json = { version = "1.0.108", default-features = false, features = ["alloc", "arbitrary_precision"] } # pallet-asset-conversion: turn on "num-traits" feature -primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "num-traits"] } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } # primitives -sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false, features=["serde"] } -sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false, features=["serde"] } -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features=["serde"] } -sp-block-builder = { path = "../../../primitives/block-builder", default-features = false} +sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false, features = ["serde"] } +sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false, features = ["serde"] } +sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } +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-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, features=["serde"] } -sp-std = { path = "../../../primitives/std", default-features = false} -sp-api = { path = "../../../primitives/api", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false, features=["serde"] } -sp-staking = { path = "../../../primitives/staking", default-features = false, features=["serde"] } -sp-storage = { path = "../../../primitives/storage", default-features = false} -sp-session = { path = "../../../primitives/session", default-features = false} -sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false} -sp-statement-store = { path = "../../../primitives/statement-store", default-features = false, features=["serde"] } -sp-version = { path = "../../../primitives/version", default-features = false, features=["serde"] } -sp-io = { path = "../../../primitives/io", default-features = false} +sp-offchain = { path = "../../../primitives/offchain", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"] } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-api = { path = "../../../primitives/api", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false, features = ["serde"] } +sp-staking = { path = "../../../primitives/staking", default-features = false, features = ["serde"] } +sp-storage = { path = "../../../primitives/storage", default-features = false } +sp-session = { path = "../../../primitives/session", default-features = false } +sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false } +sp-statement-store = { path = "../../../primitives/statement-store", default-features = false, features = ["serde"] } +sp-version = { path = "../../../primitives/version", default-features = false, features = ["serde"] } +sp-io = { path = "../../../primitives/io", default-features = false } # frame dependencies -frame-executive = { path = "../../../frame/executive", default-features = false} -frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false} -frame-benchmarking-pallet-pov = { path = "../../../frame/benchmarking/pov", default-features = false} +frame-executive = { path = "../../../frame/executive", default-features = false } +frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false } +frame-benchmarking-pallet-pov = { path = "../../../frame/benchmarking/pov", default-features = false } frame-support = { path = "../../../frame/support", default-features = false, features = ["tuples-96"] } -frame-system = { path = "../../../frame/system", default-features = false} +frame-system = { path = "../../../frame/system", default-features = false } frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true } -frame-election-provider-support = { path = "../../../frame/election-provider-support", default-features = false} -frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false} +frame-election-provider-support = { path = "../../../frame/election-provider-support", default-features = false } +frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false } frame-try-runtime = { path = "../../../frame/try-runtime", default-features = false, optional = true } -pallet-alliance = { path = "../../../frame/alliance", default-features = false} -pallet-asset-conversion = { path = "../../../frame/asset-conversion", default-features = false} -pallet-asset-rate = { path = "../../../frame/asset-rate", default-features = false} -pallet-assets = { path = "../../../frame/assets", default-features = false} -pallet-authority-discovery = { path = "../../../frame/authority-discovery", default-features = false} -pallet-authorship = { path = "../../../frame/authorship", default-features = false} -pallet-babe = { path = "../../../frame/babe", default-features = false} -pallet-bags-list = { path = "../../../frame/bags-list", default-features = false} -pallet-balances = { path = "../../../frame/balances", default-features = false} -pallet-bounties = { path = "../../../frame/bounties", default-features = false} -pallet-broker = { path = "../../../frame/broker", default-features = false} -pallet-child-bounties = { path = "../../../frame/child-bounties", default-features = false} -pallet-collective = { path = "../../../frame/collective", default-features = false} -pallet-contracts = { path = "../../../frame/contracts", default-features = false} -pallet-conviction-voting = { path = "../../../frame/conviction-voting", default-features = false} -pallet-core-fellowship = { path = "../../../frame/core-fellowship", default-features = false} -pallet-democracy = { path = "../../../frame/democracy", default-features = false} -pallet-election-provider-multi-phase = { path = "../../../frame/election-provider-multi-phase", default-features = false} +pallet-alliance = { path = "../../../frame/alliance", default-features = false } +pallet-asset-conversion = { path = "../../../frame/asset-conversion", default-features = false } +pallet-asset-rate = { path = "../../../frame/asset-rate", default-features = false } +pallet-assets = { path = "../../../frame/assets", default-features = false } +pallet-authority-discovery = { path = "../../../frame/authority-discovery", default-features = false } +pallet-authorship = { path = "../../../frame/authorship", default-features = false } +pallet-babe = { path = "../../../frame/babe", default-features = false } +pallet-bags-list = { path = "../../../frame/bags-list", default-features = false } +pallet-balances = { path = "../../../frame/balances", default-features = false } +pallet-bounties = { path = "../../../frame/bounties", default-features = false } +pallet-broker = { path = "../../../frame/broker", default-features = false } +pallet-child-bounties = { path = "../../../frame/child-bounties", default-features = false } +pallet-collective = { path = "../../../frame/collective", default-features = false } +pallet-contracts = { path = "../../../frame/contracts", default-features = false } +pallet-conviction-voting = { path = "../../../frame/conviction-voting", default-features = false } +pallet-core-fellowship = { path = "../../../frame/core-fellowship", default-features = false } +pallet-democracy = { path = "../../../frame/democracy", default-features = false } +pallet-election-provider-multi-phase = { path = "../../../frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "../../../frame/election-provider-support/benchmarking", default-features = false, optional = true } -pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", default-features = false} -pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false} -pallet-nis = { path = "../../../frame/nis", default-features = false} -pallet-grandpa = { path = "../../../frame/grandpa", default-features = false} -pallet-im-online = { path = "../../../frame/im-online", default-features = false} -pallet-indices = { path = "../../../frame/indices", default-features = false} -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-elections-phragmen = { path = "../../../frame/elections-phragmen", default-features = false } +pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false } +pallet-nis = { path = "../../../frame/nis", default-features = false } +pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } +pallet-im-online = { path = "../../../frame/im-online", default-features = false } +pallet-indices = { path = "../../../frame/indices", default-features = false } +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} -pallet-nfts-runtime-api = { path = "../../../frame/nfts/runtime-api", default-features = false} -pallet-nft-fractionalization = { path = "../../../frame/nft-fractionalization", default-features = false} -pallet-nomination-pools = { path = "../../../frame/nomination-pools", default-features = false} -pallet-nomination-pools-benchmarking = { path = "../../../frame/nomination-pools/benchmarking", default-features = false, optional = true} -pallet-nomination-pools-runtime-api = { path = "../../../frame/nomination-pools/runtime-api", default-features = false} -pallet-offences = { path = "../../../frame/offences", 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 } +pallet-nfts-runtime-api = { path = "../../../frame/nfts/runtime-api", default-features = false } +pallet-nft-fractionalization = { path = "../../../frame/nft-fractionalization", default-features = false } +pallet-nomination-pools = { path = "../../../frame/nomination-pools", default-features = false } +pallet-nomination-pools-benchmarking = { path = "../../../frame/nomination-pools/benchmarking", default-features = false, optional = true } +pallet-nomination-pools-runtime-api = { path = "../../../frame/nomination-pools/runtime-api", default-features = false } +pallet-offences = { path = "../../../frame/offences", default-features = false } pallet-offences-benchmarking = { path = "../../../frame/offences/benchmarking", default-features = false, optional = true } -pallet-glutton = { path = "../../../frame/glutton", default-features = false} -pallet-preimage = { path = "../../../frame/preimage", default-features = false} -pallet-proxy = { path = "../../../frame/proxy", default-features = false} -pallet-insecure-randomness-collective-flip = { path = "../../../frame/insecure-randomness-collective-flip", default-features = false} -pallet-ranked-collective = { path = "../../../frame/ranked-collective", default-features = false} -pallet-recovery = { path = "../../../frame/recovery", default-features = false} -pallet-referenda = { path = "../../../frame/referenda", default-features = false} -pallet-remark = { path = "../../../frame/remark", default-features = false} -pallet-root-testing = { path = "../../../frame/root-testing", default-features = false} -pallet-salary = { path = "../../../frame/salary", default-features = false} -pallet-session = { path = "../../../frame/session", default-features = false , features = [ "historical" ]} +pallet-glutton = { path = "../../../frame/glutton", default-features = false } +pallet-preimage = { path = "../../../frame/preimage", default-features = false } +pallet-proxy = { path = "../../../frame/proxy", default-features = false } +pallet-insecure-randomness-collective-flip = { path = "../../../frame/insecure-randomness-collective-flip", default-features = false } +pallet-ranked-collective = { path = "../../../frame/ranked-collective", default-features = false } +pallet-recovery = { path = "../../../frame/recovery", default-features = false } +pallet-referenda = { path = "../../../frame/referenda", default-features = false } +pallet-remark = { path = "../../../frame/remark", default-features = false } +pallet-root-testing = { path = "../../../frame/root-testing", default-features = false } +pallet-salary = { path = "../../../frame/salary", default-features = false } +pallet-session = { path = "../../../frame/session", default-features = false, features = ["historical"] } pallet-session-benchmarking = { path = "../../../frame/session/benchmarking", default-features = false, optional = true } -pallet-staking = { path = "../../../frame/staking", default-features = false} -pallet-staking-reward-curve = { path = "../../../frame/staking/reward-curve", default-features = false} -pallet-staking-runtime-api = { path = "../../../frame/staking/runtime-api", default-features = false} -pallet-state-trie-migration = { path = "../../../frame/state-trie-migration", default-features = false} -pallet-statement = { path = "../../../frame/statement", default-features = false} -pallet-scheduler = { path = "../../../frame/scheduler", default-features = false} -pallet-society = { path = "../../../frame/society", default-features = false} -pallet-sudo = { path = "../../../frame/sudo", default-features = false} -pallet-timestamp = { path = "../../../frame/timestamp", default-features = false} -pallet-tips = { path = "../../../frame/tips", default-features = false} -pallet-treasury = { path = "../../../frame/treasury", default-features = false} -pallet-utility = { path = "../../../frame/utility", default-features = false} -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false} -pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false} -pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment", default-features = false} -pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment", default-features = false} -pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false} -pallet-transaction-storage = { path = "../../../frame/transaction-storage", default-features = false} -pallet-uniques = { path = "../../../frame/uniques", default-features = false} -pallet-vesting = { path = "../../../frame/vesting", default-features = false} -pallet-whitelist = { path = "../../../frame/whitelist", default-features = false} -pallet-tx-pause = { path = "../../../frame/tx-pause", default-features = false} -pallet-safe-mode = { path = "../../../frame/safe-mode", default-features = false} +pallet-staking = { path = "../../../frame/staking", default-features = false } +pallet-staking-reward-curve = { path = "../../../frame/staking/reward-curve", default-features = false } +pallet-staking-runtime-api = { path = "../../../frame/staking/runtime-api", default-features = false } +pallet-state-trie-migration = { path = "../../../frame/state-trie-migration", default-features = false } +pallet-statement = { path = "../../../frame/statement", default-features = false } +pallet-scheduler = { path = "../../../frame/scheduler", default-features = false } +pallet-society = { path = "../../../frame/society", default-features = false } +pallet-sudo = { path = "../../../frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../frame/timestamp", default-features = false } +pallet-tips = { path = "../../../frame/tips", default-features = false } +pallet-treasury = { path = "../../../frame/treasury", default-features = false } +pallet-utility = { path = "../../../frame/utility", default-features = false } +pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment", default-features = false } +pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment", default-features = false } +pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false } +pallet-transaction-storage = { path = "../../../frame/transaction-storage", default-features = false } +pallet-uniques = { path = "../../../frame/uniques", default-features = false } +pallet-vesting = { path = "../../../frame/vesting", default-features = false } +pallet-whitelist = { path = "../../../frame/whitelist", default-features = false } +pallet-tx-pause = { path = "../../../frame/tx-pause", default-features = false } +pallet-safe-mode = { path = "../../../frame/safe-mode", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] -with-tracing = [ "frame-executive/with-tracing" ] +default = ["std"] +with-tracing = ["frame-executive/with-tracing"] std = [ "codec/std", "frame-benchmarking-pallet-pov/std", diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index dba5016fb3e..513cb22b6a2 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -29,13 +29,13 @@ pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx- pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment" } sc-block-builder = { path = "../../../client/block-builder" } sc-client-api = { path = "../../../client/api" } -sc-client-db = { path = "../../../client/db", features = ["rocksdb"]} +sc-client-db = { path = "../../../client/db", features = ["rocksdb"] } sc-consensus = { path = "../../../client/consensus/common" } sc-executor = { path = "../../../client/executor" } sc-service = { path = "../../../client/service", features = [ - "test-helpers", "rocksdb", -]} + "test-helpers", +] } sp-api = { path = "../../../primitives/api" } sp-block-builder = { path = "../../../primitives/block-builder" } sp-blockchain = { path = "../../../primitives/blockchain" } @@ -45,5 +45,5 @@ sp-inherents = { path = "../../../primitives/inherents" } sp-io = { path = "../../../primitives/io" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } -sp-timestamp = { path = "../../../primitives/timestamp", default-features = false} +sp-timestamp = { path = "../../../primitives/timestamp", default-features = false } substrate-test-client = { path = "../../../test-utils/client" } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 2b64c86038d..57a364e791f 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -28,10 +28,10 @@ sc-utils = { path = "../utils" } sp-api = { path = "../../primitives/api" } sp-blockchain = { path = "../../primitives/blockchain" } sp-consensus = { path = "../../primitives/consensus/common" } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } sp-database = { path = "../../primitives/database" } sp-externalities = { path = "../../primitives/externalities" } -sp-runtime = { path = "../../primitives/runtime", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-state-machine = { path = "../../primitives/state-machine" } sp-statement-store = { path = "../../primitives/statement-store" } sp-storage = { path = "../../primitives/storage" } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index ef2fdcfd485..4013c8951c4 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -21,8 +21,8 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.51.3", features = ["kad", "ed25519"] } -multihash = { version = "0.17.0", default-features = false, features = ["std", "sha2"] } +libp2p = { version = "0.51.3", features = ["ed25519", "kad"] } +multihash = { version = "0.17.0", default-features = false, features = ["sha2", "std"] } log = "0.4.17" prost = "0.11" rand = "0.8.5" diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 009f8cef957..d041d5bfd2b 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -35,5 +35,5 @@ docify = "0.2.0" [dev-dependencies] substrate-test-runtime = { path = "../../test-utils/runtime" } sp-keyring = { path = "../../primitives/keyring" } -sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto", features = ["serde"] } +sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto", features = ["serde"] } sp-consensus-babe = { default-features = false, path = "../../primitives/consensus/babe", features = ["serde"] } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 54280d4bf15..d75eac1ac98 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -19,7 +19,7 @@ clap = { version = "4.4.10", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" -libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} +libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.6.1" @@ -30,13 +30,13 @@ serde = "1.0.193" serde_json = "1.0.108" thiserror = "1.0.48" bip39 = "2.0.0" -tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "signal"] } sc-client-api = { path = "../api" } -sc-client-db = { path = "../db", default-features = false} +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-service = { path = "../service", default-features = false } sc-telemetry = { path = "../telemetry" } sc-tracing = { path = "../tracing" } sc-utils = { path = "../utils" } @@ -54,5 +54,5 @@ futures-timer = "3.0.1" sp-tracing = { path = "../../primitives/tracing" } [features] -default = [ "rocksdb" ] -rocksdb = [ "sc-client-db/rocksdb" ] +default = ["rocksdb"] +rocksdb = ["sc-client-db/rocksdb"] diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index f6551b2ed54..913dd990fd3 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } futures = "0.3.21" serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0" diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index c077908c93c..35041a1208f 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } log = "0.4" parking_lot = "0.12.1" serde = { version = "1.0.193", features = ["derive"] } @@ -24,6 +24,6 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.108" -sc-rpc = { path = "../../../rpc", features = ["test-helpers"]} +sc-rpc = { path = "../../../rpc", features = ["test-helpers"] } substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index f269e3752d4..95ee02a9262 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.57" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"] } +libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = "0.4.17" mockall = "0.11.3" parking_lot = "0.12.1" diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 2e808ac0bdd..2a0d51dd616 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } log = "0.4.8" parity-scale-codec = { version = "3.6.1", features = ["derive"] } serde = { version = "1.0.193", features = ["derive"] } @@ -26,7 +26,7 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] sc-block-builder = { path = "../../../block-builder" } -sc-rpc = { path = "../../../rpc", features = ["test-helpers"]} +sc-rpc = { path = "../../../rpc", features = ["test-helpers"] } sp-core = { path = "../../../../primitives/core" } sp-consensus-grandpa = { path = "../../../../primitives/consensus/grandpa" } sp-keyring = { path = "../../../../primitives/keyring" } diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index a6430fdf1de..b0b9c1ee6eb 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } assert_matches = "1.3.0" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } @@ -43,7 +43,7 @@ sp-runtime = { path = "../../../primitives/runtime" } sp-timestamp = { path = "../../../primitives/timestamp" } [dev-dependencies] -tokio = { version = "1.22.0", features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } sc-basic-authorship = { path = "../../basic-authorship" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool" } diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index cb9560b6cb6..867e2908d6c 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -53,7 +53,7 @@ runtime-benchmarks = [ "kitchensink-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -rocksdb = [ "kvdb-rocksdb" ] +rocksdb = ["kvdb-rocksdb"] [[bench]] name = "state_access" diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 9f41b742373..50aedf8a348 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -55,7 +55,7 @@ name = "bench" harness = false [features] -default = [ "std" ] +default = ["std"] # This crate does not have `no_std` support, we just require this for tests std = [ "sc-runtime-test/std", diff --git a/substrate/client/executor/runtime-test/Cargo.toml b/substrate/client/executor/runtime-test/Cargo.toml index 046e59c08e0..84ed458fb1c 100644 --- a/substrate/client/executor/runtime-test/Cargo.toml +++ b/substrate/client/executor/runtime-test/Cargo.toml @@ -13,17 +13,17 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false, features = ["improved_panic_error_reporting"]} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-runtime-interface = { path = "../../../primitives/runtime-interface", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false, features = ["improved_panic_error_reporting"] } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-runtime-interface = { path = "../../../primitives/runtime-interface", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "sp-core/std", "sp-io/std", diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index 261d52c0ede..b1434ef7c52 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -25,7 +25,7 @@ wasmtime = { version = "8.0.1", default-features = false, features = [ "cranelift", "jitdump", "parallel-compilation", - "pooling-allocator" + "pooling-allocator", ] } anyhow = "1.0.68" sc-allocator = { path = "../../allocator" } @@ -39,7 +39,7 @@ sp-wasm-interface = { path = "../../../primitives/wasm-interface", features = [" # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix = { version = "0.36.7", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } +rustix = { version = "0.36.7", default-features = false, features = ["fs", "mm", "param", "std", "use-libc"] } [dev-dependencies] wat = "1.0" diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index c64354abaaf..d978d3cd2ed 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } serde = { version = "1.0.193", features = ["derive"] } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 5006d5d0e3e..0ad9dec4651 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -30,6 +30,6 @@ sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] tokio = "1.22.0" async-trait = "0.1.73" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 2a14ef2dd84..ff8046868d5 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -25,7 +25,7 @@ fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" -libp2p = { version = "0.51.3", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux", "websocket", "request-response"] } +libp2p = { version = "0.51.3", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"] } linked_hash_set = "0.1.3" log = "0.4.17" mockall = "0.11.3" @@ -39,7 +39,7 @@ smallvec = "1.11.0" thiserror = "1.0" tokio = { version = "1.22.0", features = ["macros", "sync"] } tokio-stream = "0.1.7" -unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } +unsigned-varint = { version = "0.7.1", features = ["asynchronous_codec", "futures"] } zeroize = "1.4.3" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index 412d603163d..f4ad4b3a0e9 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -23,7 +23,7 @@ libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = "0.4.17" prost = "0.11" thiserror = "1.0" -unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } +unsigned-varint = { version = "0.7.1", features = ["asynchronous_codec", "futures"] } sc-client-api = { path = "../../api" } sc-network = { path = ".." } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index f426cda7fc8..17b21432811 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -19,7 +19,7 @@ prost-build = "0.11" async-channel = "1.8.0" array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = [ - "derive", + "derive", ] } futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid"] } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index a1ea39a852f..a9b8ec577e3 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -30,7 +30,7 @@ schnellru = "0.2.1" smallvec = "1.11.0" thiserror = "1.0" tokio-stream = "0.1.14" -tokio = { version = "1.32.0", features = ["time", "macros"] } +tokio = { version = "1.32.0", features = ["macros", "time"] } 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/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index 09f8f1fa9ef..a11ed2a3ec8 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -29,7 +29,7 @@ sc-network-common = { path = "../common" } sc-utils = { path = "../../utils" } sc-network-light = { path = "../light" } sc-network-sync = { path = "../sync" } -sc-service = { path = "../../service", default-features = false, features = ["test-helpers"]} +sc-service = { path = "../../service", default-features = false, features = ["test-helpers"] } sp-blockchain = { path = "../../../primitives/blockchain" } sp-consensus = { path = "../../../primitives/consensus/common" } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 83397f52879..01deb322134 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" -hyper = { version = "0.14.16", features = ["stream", "http2"] } +hyper = { version = "0.14.16", features = ["http2", "stream"] } hyper-rustls = { version = "0.24.0", features = ["http2"] } libp2p = "0.51.3" num_cpus = "1.13" @@ -45,7 +45,7 @@ log = "0.4.17" lazy_static = "1.4.0" tokio = "1.22.0" sc-block-builder = { path = "../block-builder" } -sc-client-db = { path = "../db", default-features = true} +sc-client-db = { path = "../db", default-features = true } sc-transaction-pool = { path = "../transaction-pool" } sc-transaction-pool-api = { path = "../transaction-pool/api" } sp-consensus = { path = "../../primitives/consensus/common" } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index baf94f342ef..b5c0f70d94c 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -25,4 +25,4 @@ sp-core = { path = "../../primitives/core" } sp-rpc = { path = "../../primitives/rpc" } sp-runtime = { path = "../../primitives/runtime" } sp-version = { path = "../../primitives/version" } -jsonrpsee = { version = "0.16.2", features = ["server", "client-core", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 8ca4f321f71..45a1d862f04 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } # Internal chain structures for "chain_spec". sc-chain-spec = { path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" @@ -47,6 +47,6 @@ sp-consensus = { path = "../../primitives/consensus/common" } sp-externalities = { path = "../../primitives/externalities" } sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } sc-block-builder = { path = "../block-builder" } -sc-service = { path = "../service", features = ["test-helpers"]} +sc-service = { path = "../service", features = ["test-helpers"] } assert_matches = "1.3.0" pretty_assertions = "1.2.1" diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 63c498964fe..ae03a5dab36 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [features] -default = [ "rocksdb" ] +default = ["rocksdb"] # The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass # a path to a database, an error will be produced at runtime. -rocksdb = [ "sc-client-db/rocksdb" ] +rocksdb = ["sc-client-db/rocksdb"] # exposes the client type test-helpers = [] runtime-benchmarks = [ @@ -59,7 +59,7 @@ sc-network-transactions = { path = "../network/transactions" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } sp-api = { path = "../../primitives/api" } -sc-client-db = { path = "../db", default-features = false} +sc-client-db = { path = "../db", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1" } sc-executor = { path = "../executor" } sc-transaction-pool = { path = "../transaction-pool" } @@ -77,7 +77,7 @@ sc-sysinfo = { path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } async-trait = "0.1.57" -tokio = { version = "1.22.0", features = ["time", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "time"] } tempfile = "3.1.0" directories = "5.0.1" static_init = "1.0.3" diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index c6091f97d63..93576be9b59 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -23,12 +23,12 @@ tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["time"] } sc-block-builder = { path = "../../block-builder" } sc-client-api = { path = "../../api" } -sc-client-db = { path = "../../db", default-features = false} +sc-client-db = { path = "../../db", default-features = false } sc-consensus = { path = "../../consensus/common" } sc-executor = { path = "../../executor" } sc-network = { path = "../../network" } sc-network-sync = { path = "../../network/sync" } -sc-service = { path = "..", features = ["test-helpers"]} +sc-service = { path = "..", features = ["test-helpers"] } sc-transaction-pool-api = { path = "../../transaction-pool/api" } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 66302982bee..c0eb9d94b92 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" clap = { version = "4.4.10", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.7.0" -sc-client-db = { path = "../db", default-features = false} +sc-client-db = { path = "../db", default-features = false } sp-core = { path = "../../primitives/core" } tokio = "1.22.0" thiserror = "1.0.48" diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index da5d22c2b9a..746f1c754f9 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" thiserror = "1.0.48" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index b134cbce3cc..2e4a0c8f3ee 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.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index dad1e52bb54..89981c27511 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -16,8 +16,8 @@ log = "0.4.17" serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0.48" sp-blockchain = { path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } [dev-dependencies] serde_json = "1.0.108" diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index 885b1d26a8e..da618b0259e 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -17,10 +17,10 @@ lazy_static = "1.4.0" log = "0.4" parking_lot = "0.12.1" prometheus = { version = "0.13.0", default-features = false } -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } [features] -default = [ "metered" ] +default = ["metered"] metered = [] [dev-dependencies] diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 9f2f73ffb15..93306e8af3d 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # external deps parity-scale-codec = { version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.6.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.6.0", default-features = false, features = ["derive"] } # primitive deps, used for developing FRAME pallets. sp-runtime = { default-features = false, path = "../primitives/runtime" } @@ -27,8 +27,8 @@ sp-core = { default-features = false, path = "../primitives/core" } sp-arithmetic = { default-features = false, path = "../primitives/arithmetic" } # frame deps, for developing FRAME pallets. -frame-support = { default-features = false, path = "support" } -frame-system = { default-features = false, path = "system" } +frame-support = { default-features = false, path = "support" } +frame-system = { default-features = false, path = "system" } # primitive types used for developing FRAME runtimes. sp-version = { default-features = false, path = "../primitives/version", optional = true } @@ -52,8 +52,8 @@ log = { version = "0.4.20", default-features = false } pallet-examples = { path = "./examples" } [features] -default = [ "runtime", "std" ] -experimental = [ "frame-support/experimental", "frame-system/experimental" ] +default = ["runtime", "std"] +experimental = ["frame-support/experimental", "frame-system/experimental"] runtime = [ "frame-executive", "frame-system-rpc-runtime-api", diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index d7d7352975a..1afff8ad43e 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -19,27 +19,27 @@ log = { version = "0.4.14", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../primitives/std", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } sp-core-hashing = { path = "../../primitives/core/hashing", default-features = false, optional = true } -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } pallet-identity = { path = "../identity", default-features = false } pallet-collective = { path = "../collective", default-features = false, optional = true } [dev-dependencies] array-bytes = "6.1" -sp-core-hashing = { path = "../../primitives/core/hashing", default-features = false} +sp-core-hashing = { path = "../../primitives/core/hashing", default-features = false } pallet-balances = { path = "../balances" } pallet-collective = { path = "../collective" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index de898d4ccde..5df86d402e0 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -14,24 +14,24 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../../primitives/api", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} +sp-api = { path = "../../primitives/api", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } pallet-assets = { path = "../assets" } -primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "num-traits"] } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 734bc5ef43f..af2776bba5f 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -16,20 +16,20 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", 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} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", 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] pallet-balances = { path = "../balances" } sp-io = { path = "../../primitives/io" } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index a48964f1366..87709af2727 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { path = "../../primitives/runtime", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false } # Needed for type-safe access to storage DB. -frame-support = { path = "../support", default-features = false} +frame-support = { path = "../support", default-features = false } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. -frame-system = { path = "../system", default-features = false} +frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } [dev-dependencies] sp-std = { path = "../../primitives/std" } @@ -32,7 +32,7 @@ sp-io = { path = "../../primitives/io" } pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 8315330d7fe..0a0f20eb8e8 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -15,18 +15,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index bfe9193e9b5..321a19f74f9 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -16,20 +16,20 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-timestamp = { path = "../timestamp", default-features = false} -sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false} -sp-consensus-aura = { path = "../../primitives/consensus/aura", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-timestamp = { path = "../timestamp", default-features = false } +sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false } +sp-consensus-aura = { path = "../../primitives/consensus/aura", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index eb30ed3007c..7051276ad88 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -17,22 +17,22 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ "historical", -]} -sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false} -sp-authority-discovery = { path = "../../primitives/authority-discovery", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +] } +sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false } +sp-authority-discovery = { path = "../../primitives/authority-discovery", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index bc1e6221a45..737c8da1361 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -18,17 +18,17 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 2dc414a784d..defa89b4f28 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -16,20 +16,20 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-authorship = { path = "../authorship", default-features = false} -pallet-session = { path = "../session", default-features = false} -pallet-timestamp = { path = "../timestamp", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-authorship = { path = "../authorship", default-features = false } +pallet-session = { path = "../session", default-features = false } +pallet-timestamp = { path = "../timestamp", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features = false, features = ["serde"] } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../primitives/session", default-features = false} +sp-session = { path = "../../primitives/session", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] frame-election-provider-support = { path = "../election-provider-support" } @@ -40,7 +40,7 @@ pallet-staking-reward-curve = { path = "../staking/reward-curve" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index cb07ef94ff5..b99726ebf2d 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -50,7 +50,7 @@ frame-election-provider-support = { path = "../election-provider-support" } frame-benchmarking = { path = "../benchmarking" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/bags-list/fuzzer/Cargo.toml b/substrate/frame/bags-list/fuzzer/Cargo.toml index 9944c886554..f3785dd1bef 100644 --- a/substrate/frame/bags-list/fuzzer/Cargo.toml +++ b/substrate/frame/bags-list/fuzzer/Cargo.toml @@ -11,9 +11,9 @@ publish = false [dependencies] honggfuzz = "0.5" -rand = { version = "0.8", features = ["std", "small_rng"] } -frame-election-provider-support = { path = "../../election-provider-support", features = ["fuzz"]} -pallet-bags-list = { path = "..", features = ["fuzz"]} +rand = { version = "0.8", features = ["small_rng", "std"] } +frame-election-provider-support = { path = "../../election-provider-support", features = ["fuzz"] } +pallet-bags-list = { path = "..", features = ["fuzz"] } [[bin]] name = "bags-list" diff --git a/substrate/frame/bags-list/remote-tests/Cargo.toml b/substrate/frame/bags-list/remote-tests/Cargo.toml index b7408e08d55..169dd19db9a 100644 --- a/substrate/frame/bags-list/remote-tests/Cargo.toml +++ b/substrate/frame/bags-list/remote-tests/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { path = "../../../primitives/runtime" } sp-std = { path = "../../../primitives/std" } # utils -remote-externalities = { package = "frame-remote-externalities" , path = "../../../utils/frame/remote-externalities" } +remote-externalities = { package = "frame-remote-externalities", path = "../../../utils/frame/remote-externalities" } # others log = "0.4.17" diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index b91257df7b2..a148684e1fb 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-transaction-payment = { path = "../transaction-payment" } @@ -29,7 +29,7 @@ sp-io = { path = "../../primitives/io" } paste = "1.0.12" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index ee2c13e7ffd..ee336def85c 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -14,26 +14,26 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-beefy = { path = "../beefy", default-features = false} -pallet-mmr = { path = "../merkle-mountain-range", default-features = false} -pallet-session = { path = "../session", default-features = false} -sp-consensus-beefy = { path = "../../primitives/consensus/beefy", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} -sp-state-machine = { path = "../../primitives/state-machine", default-features = false} +binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-beefy = { path = "../beefy", default-features = false } +pallet-mmr = { path = "../merkle-mountain-range", default-features = false } +pallet-session = { path = "../session", default-features = false } +sp-consensus-beefy = { path = "../../primitives/consensus/beefy", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } +sp-state-machine = { path = "../../primitives/state-machine", default-features = false } [dev-dependencies] array-bytes = "6.1" sp-staking = { path = "../../primitives/staking" } [features] -default = [ "std" ] +default = ["std"] std = [ "array-bytes", "binary-merkle-tree/std", diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 9a88de1df15..4a77dd0e2ff 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -13,15 +13,15 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } serde = { version = "1.0.193", optional = true } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-authorship = { path = "../authorship", default-features = false} -pallet-session = { path = "../session", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-authorship = { path = "../authorship", default-features = false } +pallet-session = { path = "../session", default-features = false } sp-consensus-beefy = { path = "../../primitives/consensus/beefy", default-features = false, features = ["serde"] } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../primitives/session", default-features = false} +sp-session = { path = "../../primitives/session", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] frame-election-provider-support = { path = "../election-provider-support" } @@ -33,10 +33,10 @@ pallet-timestamp = { path = "../timestamp" } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } sp-staking = { path = "../../primitives/staking" } -sp-state-machine = { path = "../../primitives/state-machine", default-features = false} +sp-state-machine = { path = "../../primitives/state-machine", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-election-provider-support/std", diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index c3a17bc82b3..9cfaac1abfd 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -19,17 +19,17 @@ log = { version = "0.4.17", default-features = false } paste = "1.0" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -frame-support = { path = "../support", default-features = false} -frame-support-procedural = { path = "../support/procedural", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} -sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-runtime-interface = { path = "../../primitives/runtime-interface", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-storage = { path = "../../primitives/storage", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-support-procedural = { path = "../support/procedural", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } +sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-runtime-interface = { path = "../../primitives/runtime-interface", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-storage = { path = "../../primitives/storage", default-features = false } static_assertions = "1.1.0" [dev-dependencies] @@ -38,7 +38,7 @@ rusty-fork = { version = "0.3.0", default-features = false } sp-keystore = { path = "../../primitives/keystore" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support-procedural/std", diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index 0d935063e9e..1ec02828558 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -14,15 +14,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "..", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "..", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 7da21140542..3b77a8448e3 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -18,20 +18,20 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-treasury = { path = "../treasury", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-treasury = { path = "../treasury", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 142d0a0e35e..3470cf55b78 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -12,22 +12,22 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } bitvec = { version = "1.0.0", default-features = false } -sp-std = { path = "../../primitives/std", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } [dev-dependencies] sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "bitvec/std", diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index ac29bc4997b..8e9d9c17238 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -18,21 +18,21 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-bounties = { path = "../bounties", default-features = false} -pallet-treasury = { path = "../treasury", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-bounties = { path = "../bounties", default-features = false } +pallet-treasury = { path = "../treasury", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 7f5e305e4f5..672468450c2 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 417f719d803..80856bef3fd 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for WASM contracts" readme = "README.md" -include = ["src/**/*", "benchmarks/**", "build.rs", "README.md", "CHANGELOG.md"] +include = ["CHANGELOG.md", "README.md", "benchmarks/**", "build.rs", "src/**/*"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -37,19 +37,19 @@ rand_pcg = { version = "0.3", optional = true } # Substrate Dependencies environmental = { version = "1.1.4", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-balances = { path = "../balances", default-features = false , optional = true} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-balances = { path = "../balances", default-features = false, optional = true } pallet-contracts-uapi = { path = "uapi" } pallet-contracts-proc-macro = { path = "proc-macro" } -sp-api = { path = "../../primitives/api", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-api = { path = "../../primitives/api", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } -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 = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } [dev-dependencies] array-bytes = "6.1" @@ -60,7 +60,7 @@ wat = "1" pallet-contracts-fixtures = { path = "./fixtures" } # Polkadot Dependencies -xcm-builder = {package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder"} +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder" } # Substrate Dependencies pallet-balances = { path = "../balances" } @@ -74,7 +74,7 @@ sp-keystore = { path = "../../primitives/keystore" } sp-tracing = { path = "../../primitives/tracing" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "environmental/std", diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 257e01e50fa..2e95354ddc9 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -20,5 +20,3 @@ toml = "0.8.8" twox-hash = "1.6.3" anyhow = "1.0.0" cfg-if = { version = "1.0", default-features = false } - - diff --git a/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml index b70db7cde45..127bb575088 100644 --- a/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml +++ b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml @@ -6,4 +6,3 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Common utilities for pallet-contracts-fixtures." - diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 28e24dd15e4..9c6231a783a 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -9,36 +9,36 @@ repository.workspace = true description = "A mock network for testing pallet-contracts" [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } pallet-assets = { path = "../../assets" } pallet-balances = { path = "../../balances" } pallet-contracts = { path = ".." } -pallet-contracts-uapi = { path = "../uapi", default-features = false} +pallet-contracts-uapi = { path = "../uapi", default-features = false } pallet-contracts-proc-macro = { path = "../proc-macro" } pallet-insecure-randomness-collective-flip = { path = "../../insecure-randomness-collective-flip" } pallet-message-queue = { path = "../../message-queue" } pallet-proxy = { path = "../../proxy" } pallet-timestamp = { path = "../../timestamp" } pallet-utility = { path = "../../utility" } -pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false} -polkadot-parachain-primitives = { path = "../../../../polkadot/parachain" } -polkadot-primitives = { path = "../../../../polkadot/primitives" } -polkadot-runtime-parachains = {path = "../../../../polkadot/runtime/parachains"} +pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false } +polkadot-parachain-primitives = { path = "../../../../polkadot/parachain" } +polkadot-primitives = { path = "../../../../polkadot/primitives" } +polkadot-runtime-parachains = { path = "../../../../polkadot/runtime/parachains" } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../../../primitives/api", default-features = false} -sp-core = { path = "../../../primitives/core", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} +sp-api = { path = "../../../primitives/api", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } sp-tracing = { path = "../../../primitives/tracing" } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} -xcm-builder = {package = "staging-xcm-builder", path = "../../../../polkadot/xcm/xcm-builder"} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false} -xcm-simulator = {path = "../../../../polkadot/xcm/xcm-simulator"} +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../../polkadot/xcm/xcm-builder" } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm-simulator = { path = "../../../../polkadot/xcm/xcm-simulator" } [dev-dependencies] assert_matches = "1" @@ -46,7 +46,7 @@ pretty_assertions = "1" pallet-contracts-fixtures = { path = "../fixtures" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/contracts/primitives/Cargo.toml b/substrate/frame/contracts/primitives/Cargo.toml new file mode 100644 index 00000000000..f821797c923 --- /dev/null +++ b/substrate/frame/contracts/primitives/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "pallet-contracts-primitives" +version = "24.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "A crate that hosts a common definitions that are relevant for the pallet-contracts." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +bitflags = "1.0" +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } + +# Substrate Dependencies (This crate should not rely on frame) +sp-std = { path = "../../../primitives/std", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-weights = { path = "../../../primitives/weights", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + "sp-weights/std", +] diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index 6717d574dfe..df45872349d 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -11,13 +11,12 @@ description = "Exposes all the host functions that a contract can import." [dependencies] paste = { version = "1.0", default-features = false } bitflags = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"], optional = true } scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len", ], optional = true } [features] -default = [ "scale" ] -scale = [ "dep:scale", "scale-info" ] - +default = ["scale"] +scale = ["dep:scale", "scale-info"] diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index bc0ff0f9dc5..19eb6d09fc1 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -20,12 +20,12 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", features = ["derive"], optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -33,7 +33,7 @@ pallet-scheduler = { path = "../scheduler" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 523a5bb90a0..c6f99cdaab2 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 5be38214cf8..061eee106d4 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -18,13 +18,13 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", features = ["derive"], optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] @@ -33,7 +33,7 @@ pallet-scheduler = { path = "../scheduler" } pallet-preimage = { path = "../preimage" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index 91be97d3e35..f1640f7cc70 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -20,35 +20,35 @@ scale-info = { version = "2.10.0", default-features = false, features = [ ] } log = { version = "0.4.17", default-features = false } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } -sp-io = { path = "../../primitives/io", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +frame-election-provider-support = { path = "../election-provider-support", default-features = false } # Optional imports for benchmarking frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } pallet-election-provider-support-benchmarking = { path = "../election-provider-support/benchmarking", default-features = false, optional = true } rand = { version = "0.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } -strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } +strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } [dev-dependencies] parking_lot = "0.12.1" rand = "0.8.5" -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io" } -sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false} +sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false } sp-tracing = { path = "../../primitives/tracing" } pallet-balances = { path = "../balances" } frame-benchmarking = { path = "../benchmarking" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index f5d1991d199..44295d5e20d 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -23,7 +23,7 @@ sp-io = { path = "../../../primitives/io" } sp-std = { path = "../../../primitives/std" } sp-staking = { path = "../../../primitives/staking" } sp-core = { path = "../../../primitives/core" } -sp-npos-elections = { path = "../../../primitives/npos-elections", default-features = false} +sp-npos-elections = { path = "../../../primitives/npos-elections", default-features = false } sp-tracing = { path = "../../../primitives/tracing" } frame-system = { path = "../../system" } diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index ed36630d0d0..7062e54cdbc 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = "solution-type" } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-npos-elections = { path = "../../primitives/npos-elections", 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} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-npos-elections = { path = "../../primitives/npos-elections", 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 } [dev-dependencies] rand = { version = "0.8.5", features = ["small_rng"] } @@ -29,8 +29,8 @@ sp-io = { path = "../../primitives/io" } sp-npos-elections = { path = "../../primitives/npos-elections" } [features] -default = [ "std" ] -fuzz = [ "default" ] +default = ["std"] +fuzz = ["default"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/election-provider-support/benchmarking/Cargo.toml b/substrate/frame/election-provider-support/benchmarking/Cargo.toml index a8c56b425fd..b1e3564b4d4 100644 --- a/substrate/frame/election-provider-support/benchmarking/Cargo.toml +++ b/substrate/frame/election-provider-support/benchmarking/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true} -frame-election-provider-support = { path = "..", default-features = false} -frame-system = { path = "../../system", default-features = false} -sp-npos-elections = { path = "../../../primitives/npos-elections", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } +frame-election-provider-support = { path = "..", default-features = false } +frame-system = { path = "../../system", default-features = false } +sp-npos-elections = { path = "../../../primitives/npos-elections", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", 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 50f5bd908c7..144ed8b18c5 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.4.10", features = ["derive"] } honggfuzz = "0.5" -rand = { version = "0.8", features = ["std", "small_rng"] } +rand = { version = "0.8", features = ["small_rng", "std"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } @@ -24,7 +24,7 @@ frame-election-provider-support = { path = "../.." } sp-arithmetic = { path = "../../../../primitives/arithmetic" } sp-runtime = { path = "../../../../primitives/runtime" } # used by generate_solution_type: -sp-npos-elections = { path = "../../../../primitives/npos-elections", default-features = false} +sp-npos-elections = { path = "../../../../primitives/npos-elections", default-features = false } frame-support = { path = "../../../support" } [[bin]] diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index cb8bc1035a5..ffb939fa4d2 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } log = { version = "0.4.14", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-staking = { path = "../../primitives/staking", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-npos-elections = { path = "../../primitives/npos-elections", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -35,7 +35,7 @@ sp-tracing = { path = "../../primitives/tracing" } substrate-test-utils = { path = "../../test-utils" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 1b215022715..779baa432fc 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -13,16 +13,16 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -pallet-default-config-example = { path = "default-config", default-features = false} -pallet-dev-mode = { path = "dev-mode", default-features = false} -pallet-example-basic = { path = "basic", default-features = false} +pallet-default-config-example = { path = "default-config", default-features = false } +pallet-dev-mode = { path = "dev-mode", default-features = false } +pallet-example-basic = { path = "basic", default-features = false } pallet-example-frame-crate = { path = "frame-crate", default-features = false } -pallet-example-kitchensink = { path = "kitchensink", default-features = false} -pallet-example-offchain-worker = { path = "offchain-worker", default-features = false} -pallet-example-split = { path = "split", default-features = false} +pallet-example-kitchensink = { path = "kitchensink", default-features = false } +pallet-example-offchain-worker = { path = "offchain-worker", default-features = false } +pallet-example-split = { path = "split", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "pallet-default-config-example/std", "pallet-dev-mode/std", diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index d39a93e7abb..53da9ac2eba 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -16,19 +16,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-balances = { path = "../../balances", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-balances = { path = "../../balances", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 13b6ce74543..0d80e6838f0 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index 806af334bb0..ce558fe087b 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -16,18 +16,18 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-balances = { path = "../../balances", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-balances = { path = "../../balances", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index ceb8c7bfb81..586b6c0216e 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -frame = { path = "../..", default-features = false, features = ["runtime", "experimental"] } +frame = { path = "../..", default-features = false, features = ["experimental", "runtime"] } [features] -default = [ "std" ] -std = [ "codec/std", "frame/std", "scale-info/std" ] +default = ["std"] +std = ["codec/std", "frame/std", "scale-info/std"] diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 1275ef0b53f..e63e1192458 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -16,22 +16,22 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } -pallet-balances = { path = "../../balances", default-features = false} +pallet-balances = { path = "../../balances", default-features = false } [dev-dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index e6b7715655d..9d0b682ee02 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -17,16 +17,16 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = lite-json = { version = "0.2.0", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -sp-core = { path = "../../../primitives/core", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-keystore = { path = "../../../primitives/keystore", optional = true} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-keystore = { path = "../../../primitives/keystore", optional = true } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index db2a75e388d..b6b9ea86dfe 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -17,19 +17,19 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } -sp-io = { path = "../../../primitives/io", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-io = { path = "../../../primitives/io", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } [dev-dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", @@ -46,4 +46,4 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] -try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime" ] +try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime"] diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 32983a32c4f..c2a92ad3d72 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -18,14 +18,14 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } frame-try-runtime = { path = "../try-runtime", default-features = false, optional = true } -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-tracing = { path = "../../primitives/tracing", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-tracing = { path = "../../primitives/tracing", default-features = false } [dev-dependencies] array-bytes = "6.1" @@ -37,8 +37,8 @@ sp-io = { path = "../../primitives/io" } sp-version = { path = "../../primitives/version" } [features] -default = [ "std" ] -with-tracing = [ "sp-tracing/with-tracing" ] +default = ["std"] +with-tracing = ["sp-tracing/with-tracing"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 2aa2e918f3e..4440a0c0f64 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -16,22 +16,22 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-staking = { path = "../../primitives/staking", default-features = false} -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } +frame-election-provider-support = { path = "../election-provider-support", default-features = false } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } docify = "0.2.6" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } substrate-test-utils = { path = "../../test-utils" } sp-tracing = { path = "../../primitives/tracing" } pallet-staking = { path = "../staking" } @@ -39,7 +39,7 @@ pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 368fcab65cc..81388d0e0f5 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -17,19 +17,19 @@ blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "blake2/std", "codec/std", diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 5eacc21721b..b4444d4580c 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -16,19 +16,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-authorship = { path = "../authorship", default-features = false} -pallet-session = { path = "../session", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-authorship = { path = "../authorship", default-features = false } +pallet-session = { path = "../session", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } sp-consensus-grandpa = { path = "../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../primitives/session", default-features = false} +sp-session = { path = "../../primitives/session", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] grandpa = { package = "finality-grandpa", version = "0.16.2", features = ["derive-codec"] } @@ -42,7 +42,7 @@ pallet-timestamp = { path = "../timestamp" } sp-keyring = { path = "../../primitives/keyring" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 309c0aab550..894365748ce 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -16,19 +16,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "enumflags2/std", diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index d83ff540648..5ec260c9b5b 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -16,22 +16,22 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-authorship = { path = "../authorship", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-authorship = { path = "../authorship", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-session = { path = "../session" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index d392522718a..4f12ecfcce3 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -15,20 +15,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-keyring = { path = "../../primitives/keyring", optional = true} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-keyring = { path = "../../primitives/keyring", optional = true } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index 07c5e3997d2..f7afbb95397 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index a4942abf243..bba17d2718c 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -16,11 +16,11 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] frame-support-test = { path = "../support/test" } @@ -29,7 +29,7 @@ sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 18c771bf72c..f90d70e911d 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 2c30af43b67..1f31e704928 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-mmr-primitives = { path = "../../primitives/merkle-mountain-range", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-mmr-primitives = { path = "../../primitives/merkle-mountain-range", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] array-bytes = "6.1" @@ -30,7 +30,7 @@ env_logger = "0.9" itertools = "0.10.3" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 98ca3f60cc8..148848f2bf0 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -14,16 +14,16 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.193", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-weights = { path = "../../primitives/weights", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-weights = { path = "../../primitives/weights", default-features = false } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } [dev-dependencies] sp-tracing = { path = "../../primitives/tracing" } @@ -31,7 +31,7 @@ rand = "0.8.5" rand_distr = "0.4.3" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index 12597b8b5d5..de5f7411015 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { default-features = false, path = "../../primitives/runtime" } sp-std = { default-features = false, path = "../../primitives/std" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index a2ee608c33c..f1ff19c0e34 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } # third party log = { version = "0.4.17", default-features = false } @@ -29,7 +29,7 @@ log = { version = "0.4.17", default-features = false } pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index a2cb9a4aec9..19814d67d79 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-assets = { path = "../assets", default-features = false} -pallet-nfts = { path = "../nfts", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-assets = { path = "../assets", default-features = false } +pallet-nfts = { path = "../nfts", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -31,7 +31,7 @@ sp-io = { path = "../../primitives/io" } sp-std = { path = "../../primitives/std" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 2a3b2921c75..a70b55bc45e 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -17,20 +17,20 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = enumflags2 = { version = "0.7.7" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-keystore = { path = "../../primitives/keystore" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "enumflags2/std", diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index 092edaaaa89..8e1424a588a 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -19,5 +19,5 @@ sp-api = { path = "../../../primitives/api", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "pallet-nfts/std", "sp-api/std", "sp-std/std" ] +default = ["std"] +std = ["codec/std", "pallet-nfts/std", "sp-api/std", "sp-std/std"] diff --git a/substrate/frame/nicks/Cargo.toml b/substrate/frame/nicks/Cargo.toml index b8100d07435..8636ac34a13 100644 --- a/substrate/frame/nicks/Cargo.toml +++ b/substrate/frame/nicks/Cargo.toml @@ -15,18 +15,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index 986568ea722..ec251ef6536 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -15,20 +15,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index e5a504e2a0f..abc03a8b0f4 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 3c55822b9a5..bc24deb6f15 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -17,13 +17,13 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # FRAME -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-staking = { path = "../../primitives/staking", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } log = { version = "0.4.0", default-features = false } # Optional: use for testing and/or fuzzing @@ -35,8 +35,8 @@ pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } [features] -default = [ "std" ] -fuzzing = [ "pallet-balances", "sp-tracing" ] +default = ["std"] +fuzzing = ["pallet-balances", "sp-tracing"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index e8b18666815..d522dff82ba 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -18,29 +18,29 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # FRAME -frame-benchmarking = { path = "../../benchmarking", default-features = false} -frame-election-provider-support = { path = "../../election-provider-support", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-bags-list = { path = "../../bags-list", default-features = false} -pallet-staking = { path = "../../staking", default-features = false} -pallet-nomination-pools = { path = "..", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false } +frame-election-provider-support = { path = "../../election-provider-support", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-bags-list = { path = "../../bags-list", default-features = false } +pallet-staking = { path = "../../staking", default-features = false } +pallet-nomination-pools = { path = "..", default-features = false } # Substrate Primitives -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-runtime-interface = { path = "../../../primitives/runtime-interface", default-features = false} -sp-staking = { path = "../../../primitives/staking", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-runtime-interface = { path = "../../../primitives/runtime-interface", default-features = false } +sp-staking = { path = "../../../primitives/staking", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] -pallet-balances = { path = "../../balances", default-features = false} +pallet-balances = { path = "../../balances", default-features = false } pallet-timestamp = { path = "../../timestamp" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } sp-core = { path = "../../../primitives/core" } sp-io = { path = "../../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml index c3aa8035c95..86d1496a41b 100644 --- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml +++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -sp-api = { path = "../../../primitives/api", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} -pallet-nomination-pools = { path = "..", default-features = false} +sp-api = { path = "../../../primitives/api", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +pallet-nomination-pools = { path = "..", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "pallet-nomination-pools/std", "sp-api/std", "sp-std/std" ] +default = ["std"] +std = ["codec/std", "pallet-nomination-pools/std", "sp-api/std", "sp-std/std"] diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index c1cb950069a..0f153d9eca6 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -17,19 +17,19 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-balances = { path = "../balances", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-staking = { path = "../../primitives/staking", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-balances = { path = "../balances", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index acd8447c054..4de239296a9 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -15,20 +15,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../benchmarking", default-features = false} -frame-election-provider-support = { path = "../../election-provider-support", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-babe = { path = "../../babe", default-features = false} -pallet-balances = { path = "../../balances", default-features = false} -pallet-grandpa = { path = "../../grandpa", default-features = false} -pallet-im-online = { path = "../../im-online", default-features = false} -pallet-offences = { path = "..", default-features = false} -pallet-session = { path = "../../session", default-features = false} -pallet-staking = { path = "../../staking", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-staking = { path = "../../../primitives/staking", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false } +frame-election-provider-support = { path = "../../election-provider-support", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-babe = { path = "../../babe", default-features = false } +pallet-balances = { path = "../../balances", default-features = false } +pallet-grandpa = { path = "../../grandpa", default-features = false } +pallet-im-online = { path = "../../im-online", default-features = false } +pallet-offences = { path = "..", default-features = false } +pallet-session = { path = "../../session", default-features = false } +pallet-staking = { path = "../../staking", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-staking = { path = "../../../primitives/staking", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] @@ -38,7 +38,7 @@ sp-core = { path = "../../../primitives/core" } sp-io = { path = "../../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 4bc3dd6a3c7..676e1866a43 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -12,22 +12,22 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } docify = "0.2.6" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", 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 } sp-io = { path = "../../primitives/io", default-features = false } -sp-metadata-ir = { path = "../../primitives/metadata-ir", default-features = false, optional = true} +sp-metadata-ir = { path = "../../primitives/metadata-ir", default-features = false, optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", @@ -55,4 +55,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -frame-metadata = [ "sp-metadata-ir" ] +frame-metadata = ["sp-metadata-ir"] diff --git a/substrate/frame/paged-list/fuzzer/Cargo.toml b/substrate/frame/paged-list/fuzzer/Cargo.toml index d96c0348cf4..d6590373813 100644 --- a/substrate/frame/paged-list/fuzzer/Cargo.toml +++ b/substrate/frame/paged-list/fuzzer/Cargo.toml @@ -17,6 +17,6 @@ path = "src/paged_list.rs" arbitrary = "1.3.0" honggfuzz = "0.5.49" -frame-support = { path = "../../support", default-features = false, features = [ "std" ]} -sp-io = { path = "../../../primitives/io", default-features = false, features = [ "std" ] } -pallet-paged-list = { path = "..", default-features = false, features = [ "std" ] } +frame-support = { path = "../../support", default-features = false, features = ["std"] } +sp-io = { path = "../../../primitives/io", default-features = false, features = ["std"] } +pallet-paged-list = { path = "..", default-features = false, features = ["std"] } diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index a80ccd5a40d..1806976ac96 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -11,21 +11,21 @@ description = "FRAME pallet for storing preimages of hashes" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false, optional = true} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false, optional = true } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking", "frame-benchmarking/runtime-benchmarks", diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 647193fad8a..00a2692a820 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -28,7 +28,7 @@ pallet-utility = { path = "../utility" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 236489c54b5..145eff3b0ee 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 8e240546fdd..d2cd2d1a4ca 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -15,26 +15,26 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ - 'frame-benchmarking', "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + 'frame-benchmarking', ] std = [ "codec/std", diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index d892fa32a6a..1747d0ac22b 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -19,13 +19,13 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", features = ["derive"], optional = true } -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] @@ -36,7 +36,7 @@ pallet-scheduler = { path = "../scheduler" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index fe80d03c8d2..9b0c6870d05 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -16,19 +16,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index 8e6fddb4335..a17bd51684e 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -pallet-session = { path = "../session", default-features = false , features = [ "historical" ]} -pallet-staking = { path = "../staking", default-features = false} +pallet-session = { path = "../session", default-features = false, features = ["historical"] } +pallet-staking = { path = "../staking", default-features = false } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime" } -sp-staking = { path = "../../primitives/staking", default-features = false} +sp-staking = { path = "../../primitives/staking", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -30,8 +30,8 @@ pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "../staking/reward-curve" } sp-core = { path = "../../primitives/core" } -sp-io = { path = "../../primitives/io", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } frame-election-provider-support = { path = "../election-provider-support" } @@ -56,7 +56,7 @@ try-runtime = [ "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", ] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-election-provider-support/std", diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index 7837289cec5..f4e914c86b1 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] try-runtime = [ @@ -28,7 +28,7 @@ try-runtime = [ "frame-system/try-runtime", "sp-runtime/try-runtime", ] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index f7b4ea4dd8c..d33e0b7144a 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -14,16 +14,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } docify = "0.2.6" -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } pallet-balances = { path = "../balances", default-features = false, optional = true } -pallet-utility = { path = "../utility", default-features = false, optional = true } -pallet-proxy = { path = "../proxy", default-features = false, optional = true } +pallet-utility = { path = "../utility", default-features = false, optional = true } +pallet-proxy = { path = "../proxy", default-features = false, optional = true } [dev-dependencies] sp-core = { path = "../../primitives/core" } @@ -34,7 +34,7 @@ pallet-proxy = { path = "../proxy" } frame-support = { path = "../support", features = ["experimental"] } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 6c66f01082d..18636a60cdb 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 6aa81baf7ac..1dd2e53d054 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -13,22 +13,22 @@ readme = "README.md" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-weights = { path = "../../primitives/weights", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +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.6" [dev-dependencies] pallet-preimage = { path = "../preimage" } -sp-core = { path = "../../primitives/core", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false } substrate-test-utils = { path = "../../test-utils" } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking", "frame-benchmarking/runtime-benchmarks", diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index 81707382693..8293c81f590 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -15,18 +15,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 246dec63bba..0a997f6ddb3 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -17,21 +17,21 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-timestamp = { path = "../timestamp", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-timestamp = { path = "../timestamp", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../primitives/session", default-features = false} +sp-session = { path = "../../primitives/session", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} -sp-trie = { path = "../../primitives/trie", default-features = false, optional = true} -sp-state-machine = { path = "../../primitives/state-machine", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +sp-trie = { path = "../../primitives/trie", default-features = false, optional = true } +sp-state-machine = { path = "../../primitives/state-machine", default-features = false } [features] -default = [ "historical", "std" ] -historical = [ "sp-trie" ] +default = ["historical", "std"] +historical = ["sp-trie"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index 87f08985138..db2b8b72209 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["std_rng"] } -frame-benchmarking = { path = "../../benchmarking", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-session = { path = "..", default-features = false} -pallet-staking = { path = "../../staking", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-session = { path = "../../../primitives/session", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-session = { path = "..", default-features = false } +pallet-staking = { path = "../../staking", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-session = { path = "../../../primitives/session", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } @@ -35,7 +35,7 @@ sp-core = { path = "../../../primitives/core" } sp-io = { path = "../../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "frame-benchmarking/std", "frame-election-provider-support/std", diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 654447e6893..045993290af 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -18,13 +18,13 @@ rand_chacha = { version = "0.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -sp-std = { path = "../../primitives/std", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } [dev-dependencies] frame-support-test = { path = "../support/test" } @@ -33,7 +33,7 @@ sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 8fb0025e58f..1510d90ed58 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -13,23 +13,23 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"]} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ "historical", -]} -pallet-authorship = { path = "../authorship", default-features = false} +] } +pallet-authorship = { path = "../authorship", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +frame-election-provider-support = { path = "../election-provider-support", default-features = false } log = { version = "0.4.17", default-features = false } # Optional imports for benchmarking @@ -50,7 +50,7 @@ frame-election-provider-support = { path = "../election-provider-support" } rand_chacha = { version = "0.2" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/staking/reward-fn/Cargo.toml b/substrate/frame/staking/reward-fn/Cargo.toml index 25f4c33dd62..001c2b62656 100644 --- a/substrate/frame/staking/reward-fn/Cargo.toml +++ b/substrate/frame/staking/reward-fn/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.17", default-features = false } -sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false} +sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } [features] -default = [ "std" ] -std = [ "log/std", "sp-arithmetic/std" ] +default = ["std"] +std = ["log/std", "sp-arithmetic/std"] diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml index 746b463b8ce..061124fd184 100644 --- a/substrate/frame/staking/runtime-api/Cargo.toml +++ b/substrate/frame/staking/runtime-api/Cargo.toml @@ -18,5 +18,5 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../pri sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } [features] -default = [ "std" ] -std = [ "codec/std", "sp-api/std", "sp-staking/std" ] +default = ["std"] +std = ["codec/std", "sp-api/std", "sp-staking/std"] diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 93e4d80b9ac..a3e6edd5aee 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -18,15 +18,15 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.193", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -remote-externalities = { package = "frame-remote-externalities" , path = "../../utils/frame/remote-externalities", optional = true} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -substrate-state-trie-migration-rpc = { path = "../../utils/frame/rpc/state-trie-migration-rpc", optional = true} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +remote-externalities = { package = "frame-remote-externalities", path = "../../utils/frame/remote-externalities", optional = true } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +substrate-state-trie-migration-rpc = { path = "../../utils/frame/rpc/state-trie-migration-rpc", optional = true } [dev-dependencies] parking_lot = "0.12.1" @@ -35,7 +35,7 @@ pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index a5c8cf5b8de..e4caf241233 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -12,23 +12,23 @@ description = "FRAME pallet for statement store" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"]} +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-statement-store = { path = "../../primitives/statement-store", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-statement-store = { path = "../../primitives/statement-store", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index ef507a95316..70323590085 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } docify = "0.2.6" @@ -28,7 +28,7 @@ docify = "0.2.6" sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 887128e9561..6d253f29c3f 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -18,23 +18,23 @@ serde = { version = "1.0.193", default-features = false, features = ["alloc", "d codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -sp-api = { path = "../../primitives/api", default-features = false, features = [ "frame-metadata" ] } -sp-std = { path = "../../primitives/std", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-tracing = { path = "../../primitives/tracing", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false} -sp-inherents = { path = "../../primitives/inherents", default-features = false} -sp-staking = { path = "../../primitives/staking", default-features = false} -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} +sp-api = { path = "../../primitives/api", default-features = false, features = ["frame-metadata"] } +sp-std = { path = "../../primitives/std", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-tracing = { path = "../../primitives/tracing", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } +sp-inherents = { path = "../../primitives/inherents", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } +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.5.0" -frame-support-procedural = { path = "procedural", default-features = false} +frame-support-procedural = { path = "procedural", default-features = false } paste = "1.0" -sp-state-machine = { path = "../../primitives/state-machine", default-features = false, optional = true} +sp-state-machine = { path = "../../primitives/state-machine", default-features = false, optional = true } bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.11.0" @@ -42,7 +42,7 @@ log = { version = "0.4.17", default-features = false } sp-core-hashing-proc-macro = { path = "../../primitives/core/hashing/proc-macro" } k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } -sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features=false} +sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } docify = "0.2.6" static_assertions = "1.1.0" @@ -55,7 +55,7 @@ pretty_assertions = "1.2.1" frame-system = { path = "../system" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "environmental/std", @@ -101,8 +101,8 @@ no-metadata-docs = [ ] # By default some types have documentation, `full-metadata-docs` allows to add documentation to # more types in the metadata. -full-metadata-docs = [ "scale-info/docs" ] +full-metadata-docs = ["scale-info/docs"] # Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of # pallets in a runtime grows. Does increase the compile time! -tuples-96 = [ "frame-support-procedural/tuples-96" ] -tuples-128 = [ "frame-support-procedural/tuples-128" ] +tuples-96 = ["frame-support-procedural/tuples-96"] +tuples-128 = ["frame-support-procedural/tuples-128"] diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 45ed1750a52..5422ca0635c 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -29,7 +29,7 @@ expander = "2.0.0" sp-core-hashing = { path = "../../../primitives/core/hashing" } [features] -default = [ "std" ] +default = ["std"] std = [] no-metadata-docs = [] # Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index fd42e18180d..836e55b8a63 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.38", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.38", features = ["extra-traits", "full", "visit"] } 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 06f8e0f3d53..c943de998f4 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.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 54f14df75bc..b88a459d92f 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -17,27 +17,27 @@ serde = { version = "1.0.193", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -sp-api = { path = "../../../primitives/api", default-features = false} -sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false} +sp-api = { path = "../../../primitives/api", default-features = false } +sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } -sp-state-machine = { path = "../../../primitives/state-machine", optional = true} -frame-support = { path = "..", default-features = false} -frame-benchmarking = { path = "../../benchmarking", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-core = { path = "../../../primitives/core", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} -sp-version = { path = "../../../primitives/version", default-features = false} -sp-metadata-ir = { path = "../../../primitives/metadata-ir", default-features = false} -trybuild = { version = "1.0.74", features = [ "diff" ] } +sp-state-machine = { path = "../../../primitives/state-machine", optional = true } +frame-support = { path = "..", default-features = false } +frame-benchmarking = { path = "../../benchmarking", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-version = { path = "../../../primitives/version", default-features = false } +sp-metadata-ir = { path = "../../../primitives/metadata-ir", default-features = false } +trybuild = { version = "1.0.74", features = ["diff"] } pretty_assertions = "1.3.0" rustversion = "1.0.6" -frame-system = { path = "../../system", default-features = false} -frame-executive = { path = "../../executive", default-features = false} +frame-system = { path = "../../system", default-features = false } +frame-executive = { path = "../../executive", default-features = false } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message -test-pallet = { package = "frame-support-test-pallet", path = "pallet", default-features = false} +test-pallet = { package = "frame-support-test-pallet", path = "pallet", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", @@ -58,7 +58,7 @@ std = [ "sp-version/std", "test-pallet/std", ] -experimental = [ "frame-support/experimental" ] +experimental = ["frame-support/experimental"] try-runtime = [ "frame-executive/try-runtime", "frame-support/try-runtime", @@ -72,4 +72,4 @@ frame-feature-testing = [] frame-feature-testing-2 = [] # Disable ui tests disable-ui-tests = [] -no-metadata-docs = [ "frame-support/no-metadata-docs" ] +no-metadata-docs = ["frame-support/no-metadata-docs"] diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 19465d924ec..916771bd471 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -14,14 +14,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -renamed-frame-support = { package = "frame-support", path = "../..", 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} +renamed-frame-support = { package = "frame-support", path = "../..", 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 } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "renamed-frame-support/std", diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 8d0f252326d..e1136d5bc02 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", default-features = false, features = ["derive"] } -frame-support = { path = "../..", default-features = false} -frame-system = { path = "../../../system", default-features = false} -sp-runtime = { path = "../../../../primitives/runtime", default-features = false} +frame-support = { path = "../..", default-features = false } +frame-system = { path = "../../../system", default-features = false } +sp-runtime = { path = "../../../../primitives/runtime", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 0f9617c0368..0b3b584910a 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -13,9 +13,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame = { path = "../../..", default-features = false, features = ["runtime", "experimental"]} +frame = { path = "../../..", default-features = false, features = ["experimental", "runtime"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [features] -default = [ "std" ] -std = [ "codec/std", "frame/std", "scale-info/std" ] +default = ["std"] +std = ["codec/std", "frame/std", "scale-info/std"] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 8de44947dc0..0ddff8bf41e 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -17,12 +17,12 @@ cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"] } -frame-support = { path = "../support", default-features = false} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } +frame-support = { path = "../support", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../primitives/std", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } docify = "0.2.6" @@ -33,7 +33,7 @@ sp-externalities = { path = "../../primitives/externalities" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", @@ -52,7 +52,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -try-runtime = [ "frame-support/try-runtime", "sp-runtime/try-runtime" ] +try-runtime = ["frame-support/try-runtime", "sp-runtime/try-runtime"] experimental = [] [[bench]] diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index c1d241f4bec..3e92c56408e 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../benchmarking", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "..", default-features = false} -sp-core = { path = "../../../primitives/core", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +frame-benchmarking = { path = "../../benchmarking", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "..", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] sp-io = { path = "../../../primitives/io" } @@ -28,7 +28,7 @@ sp-externalities = { path = "../../../primitives/externalities" } sp-version = { path = "../../../primitives/version" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/system/rpc/runtime-api/Cargo.toml b/substrate/frame/system/rpc/runtime-api/Cargo.toml index 81b6d946d46..68dc7fc9905 100644 --- a/substrate/frame/system/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/system/rpc/runtime-api/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -sp-api = { path = "../../../../primitives/api", default-features = false} +sp-api = { path = "../../../../primitives/api", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "sp-api/std" ] +default = ["std"] +std = ["codec/std", "sp-api/std"] diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index e23ded725d8..fd14216bdb3 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -17,15 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-inherents = { path = "../../primitives/inherents", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false, optional = true} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-storage = { path = "../../primitives/storage", default-features = false} -sp-timestamp = { path = "../../primitives/timestamp", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-inherents = { path = "../../primitives/inherents", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false, optional = true } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +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.6" @@ -34,7 +34,7 @@ sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index a189c6691af..a86034d92f5 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -17,21 +17,21 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", features = ["derive"], optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-treasury = { path = "../treasury", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-treasury = { path = "../treasury", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-storage = { path = "../../primitives/storage" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 407740cfc0f..c431f7f8243 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -18,19 +18,19 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] serde_json = "1.0.108" pallet-balances = { path = "../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 2cac47fb3b7..7d15740e824 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -14,24 +14,24 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-asset-conversion = { path = "../../asset-conversion", default-features = false} -pallet-transaction-payment = { path = "..", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } +pallet-transaction-payment = { path = "..", default-features = false } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } [dev-dependencies] -sp-core = { path = "../../../primitives/core", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-storage = { path = "../../../primitives/storage", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-storage = { path = "../../../primitives/storage", default-features = false } pallet-assets = { path = "../../assets" } pallet-balances = { path = "../../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 59232a72b99..9a614316e53 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,14 +14,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { path = "../../../primitives/core", default-features = false} -sp-io = { path = "../../../primitives/io", default-features = false} -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} -pallet-transaction-payment = { path = "..", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +pallet-transaction-payment = { path = "..", default-features = false } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } # Other dependencies @@ -32,14 +32,14 @@ serde = { version = "1.0.193", optional = true } [dev-dependencies] serde_json = "1.0.108" -sp-storage = { path = "../../../primitives/storage", default-features = false} +sp-storage = { path = "../../../primitives/storage", default-features = false } pallet-assets = { path = "../../assets" } pallet-authorship = { path = "../../authorship" } pallet-balances = { path = "../../balances" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index 8a0052e0337..048b7da63f6 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } pallet-transaction-payment-rpc-runtime-api = { path = "runtime-api" } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml index af098fd34ed..17213392e1c 100644 --- a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -pallet-transaction-payment = { path = "../..", default-features = false} -sp-api = { path = "../../../../primitives/api", default-features = false} -sp-runtime = { path = "../../../../primitives/runtime", default-features = false} -sp-weights = { path = "../../../../primitives/weights", default-features = false} +pallet-transaction-payment = { path = "../..", default-features = false } +sp-api = { path = "../../../../primitives/api", default-features = false } +sp-runtime = { path = "../../../../primitives/runtime", default-features = false } +sp-weights = { path = "../../../../primitives/weights", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "pallet-transaction-payment/std", diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml index cfb814e2e38..25a708d69de 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml @@ -12,18 +12,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-runtime = { path = "../../../primitives/runtime", default-features = false} -sp-std = { path = "../../../primitives/std", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } -frame-support = { path = "../../support", default-features = false} -frame-system = { path = "../../system", default-features = false} +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index a847ca6a790..a2df1a3ce2a 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -17,23 +17,23 @@ array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -pallet-balances = { path = "../balances", default-features = false} -sp-inherents = { path = "../../primitives/inherents", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-proof", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +pallet-balances = { path = "../balances", default-features = false } +sp-inherents = { path = "../../primitives/inherents", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-proof", default-features = false } log = { version = "0.4.17", default-features = false } [dev-dependencies] -sp-core = { path = "../../primitives/core", default-features = false} -sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-proof", default-features = true} +sp-core = { path = "../../primitives/core", default-features = false } +sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-proof", default-features = true } [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "array-bytes", "frame-benchmarking/runtime-benchmarks", diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index c9fdb3d5b90..298c52d0e48 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -21,13 +21,13 @@ docify = "0.2.0" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", features = ["derive"], optional = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -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} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +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-io = { path = "../../primitives/io" } @@ -35,7 +35,7 @@ pallet-utility = { path = "../utility" } sp-core = { path = "../../primitives/core", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/try-runtime/Cargo.toml b/substrate/frame/try-runtime/Cargo.toml index 1bb3283b1de..4dd51647174 100644 --- a/substrate/frame/try-runtime/Cargo.toml +++ b/substrate/frame/try-runtime/Cargo.toml @@ -12,14 +12,14 @@ description = "FRAME pallet for democracy" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"]} -frame-support = { path = "../support", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +frame-support = { path = "../support", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-support/std", @@ -27,4 +27,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] -try-runtime = [ "frame-support/try-runtime", "sp-runtime/try-runtime" ] +try-runtime = ["frame-support/try-runtime", "sp-runtime/try-runtime"] diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index bf0641f5b6d..60623bb9d38 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -14,15 +14,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } docify = "0.2.6" -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } pallet-balances = { path = "../balances", default-features = false, optional = true } -pallet-utility = { path = "../utility", default-features = false, optional = true } -pallet-proxy = { path = "../proxy", default-features = false, optional = true } +pallet-utility = { path = "../utility", default-features = false, optional = true } +pallet-proxy = { path = "../proxy", default-features = false, optional = true } [dev-dependencies] sp-core = { path = "../../primitives/core" } @@ -32,7 +32,7 @@ pallet-utility = { path = "../utility" } pallet-proxy = { path = "../proxy" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking/std", diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 4c1bcca573d..300b319ede0 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -29,7 +29,7 @@ sp-io = { path = "../../primitives/io" } sp-std = { path = "../../primitives/std" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index 8f7a368709b..73c25a60daf 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -31,7 +31,7 @@ pallet-timestamp = { path = "../timestamp" } sp-core = { path = "../../primitives/core" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index ed13a15bc97..37339d87aea 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -18,19 +18,19 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } sp-core = { path = "../../primitives/core" } -sp-io = { path = "../../primitives/io", default-features = false} +sp-io = { path = "../../primitives/io", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index c5246615320..0d7ab6c2967 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -14,12 +14,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -28,7 +28,7 @@ sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index e95333c9eeb..1be131a7b4f 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -32,7 +32,7 @@ log = { version = "0.4.17", default-features = false } sp-test-primitives = { path = "../test-primitives" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "hash-db", @@ -58,7 +58,7 @@ std = [ # building a runtime for registering it on chain. # # This sets the max logging level to `off` for `log`. -disable-logging = [ "log/max_level_off" ] +disable-logging = ["log/max_level_off"] # Do not report the documentation in the metadata. -no-metadata-docs = [ "sp-api-proc-macro/no-metadata-docs" ] -frame-metadata = [ "sp-api-proc-macro/frame-metadata", "sp-metadata-ir" ] +no-metadata-docs = ["sp-api-proc-macro/no-metadata-docs"] +frame-metadata = ["sp-api-proc-macro/frame-metadata", "sp-metadata-ir"] diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index d60b9f1bb4e..8188299f533 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.38", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.38", features = ["extra-traits", "fold", "full", "visit"] } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" @@ -29,7 +29,7 @@ assert_matches = "1.3.0" [features] # Required for the doc tests -default = [ "std" ] -std = [ "blake2/std" ] +default = ["std"] +std = ["blake2/std"] no-metadata-docs = [] frame-metadata = [] diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 7896df94913..a6c937a3469 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../core", default-features = false} +sp-core = { path = "../core", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } -sp-std = { path = "../std", default-features = false} -sp-io = { path = "../io", default-features = false} +serde = { version = "1.0.193", default-features = false, optional = true, features = ["alloc", "derive"] } +sp-std = { path = "../std", default-features = false } +sp-io = { path = "../io", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "full_crypto", @@ -35,7 +35,7 @@ std = [ ] # Serde support without relying on std features. -serde = [ "dep:serde", "scale-info/serde", "sp-core/serde" ] +serde = ["dep:serde", "scale-info/serde", "sp-core/serde"] # This feature enables all crypto primitives for `no_std` builds like microcontrollers # or Intel SGX. @@ -51,7 +51,7 @@ full_crypto = [ # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bls-experimental = [ "sp-core/bls-experimental", "sp-io/bls-experimental" ] +bls-experimental = ["sp-core/bls-experimental", "sp-io/bls-experimental"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still diff --git a/substrate/primitives/application-crypto/test/Cargo.toml b/substrate/primitives/application-crypto/test/Cargo.toml index a6f4f108c8f..d9fb743e8cd 100644 --- a/substrate/primitives/application-crypto/test/Cargo.toml +++ b/substrate/primitives/application-crypto/test/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { path = "../../api" } sp-application-crypto = { path = ".." } -sp-core = { path = "../../core", default-features = false} -sp-keystore = { path = "../../keystore", default-features = false} +sp-core = { path = "../../core", default-features = false } +sp-keystore = { path = "../../keystore", default-features = false } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index ff938795aa3..8634dabe854 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -21,18 +21,18 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } static_assertions = "1.1.0" -sp-std = { path = "../std", default-features = false} +sp-std = { path = "../std", default-features = false } [dev-dependencies] criterion = "0.4.0" primitive-types = "0.12.0" -sp-core = { path = "../core", features = ["full_crypto"]} +sp-core = { path = "../core", features = ["full_crypto"] } rand = "0.8.5" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "num-traits/std", @@ -42,7 +42,7 @@ std = [ "sp-std/std", ] # Serde support without relying on std features. -serde = [ "dep:serde", "scale-info/serde" ] +serde = ["dep:serde", "scale-info/serde"] [[bench]] name = "bench" diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index e4f44e9da38..c8a93980be2 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../api", default-features = false} -sp-application-crypto = { path = "../application-crypto", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-application-crypto = { path = "../application-crypto", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", diff --git a/substrate/primitives/block-builder/Cargo.toml b/substrate/primitives/block-builder/Cargo.toml index 269eb539532..a574689811b 100644 --- a/substrate/primitives/block-builder/Cargo.toml +++ b/substrate/primitives/block-builder/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { path = "../api", default-features = false} -sp-inherents = { path = "../inherents", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-inherents = { path = "../inherents", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] -std = [ "sp-api/std", "sp-inherents/std", "sp-runtime/std", "sp-std/std" ] +default = ["std"] +std = ["sp-api/std", "sp-inherents/std", "sp-runtime/std", "sp-std/std"] diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 26f02bc3119..4a19999a469 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../../api", default-features = false} -sp-application-crypto = { path = "../../application-crypto", default-features = false} -sp-consensus-slots = { path = "../slots", default-features = false} -sp-inherents = { path = "../../inherents", default-features = false} -sp-runtime = { path = "../../runtime", default-features = false} -sp-std = { path = "../../std", default-features = false} -sp-timestamp = { path = "../../timestamp", default-features = false} +sp-api = { path = "../../api", default-features = false } +sp-application-crypto = { path = "../../application-crypto", default-features = false } +sp-consensus-slots = { path = "../slots", default-features = false } +sp-inherents = { path = "../../inherents", default-features = false } +sp-runtime = { path = "../../runtime", default-features = false } +sp-std = { path = "../../std", default-features = false } +sp-timestamp = { path = "../../timestamp", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index f952a8ab4ee..6ec50ea022b 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -16,18 +16,18 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } -sp-api = { path = "../../api", default-features = false} -sp-application-crypto = { path = "../../application-crypto", default-features = false} -sp-consensus-slots = { path = "../slots", default-features = false} -sp-core = { path = "../../core", default-features = false} -sp-inherents = { path = "../../inherents", default-features = false} -sp-runtime = { path = "../../runtime", default-features = false} -sp-std = { path = "../../std", default-features = false} -sp-timestamp = { path = "../../timestamp", optional = true} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } +sp-api = { path = "../../api", default-features = false } +sp-application-crypto = { path = "../../application-crypto", default-features = false } +sp-consensus-slots = { path = "../slots", default-features = false } +sp-core = { path = "../../core", default-features = false } +sp-inherents = { path = "../../inherents", default-features = false } +sp-runtime = { path = "../../runtime", default-features = false } +sp-std = { path = "../../std", default-features = false } +sp-timestamp = { path = "../../timestamp", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 67c6ad57e2d..916125d783d 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, optional = true, features = ["alloc", "derive"] } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-core = { path = "../../core", default-features = false } @@ -30,7 +30,7 @@ array-bytes = "6.1" w3f-bls = { version = "0.1.3", features = ["std"] } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index ffba6490823..1ddc89df983 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -18,16 +18,16 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", features = ["derive", "alloc"], default-features = false, optional = true } -sp-api = { path = "../../api", default-features = false} -sp-application-crypto = { path = "../../application-crypto", default-features = false} -sp-core = { path = "../../core", default-features = false} -sp-keystore = { path = "../../keystore", default-features = false, optional = true} -sp-runtime = { path = "../../runtime", default-features = false} -sp-std = { path = "../../std", default-features = false} +serde = { version = "1.0.193", features = ["alloc", "derive"], default-features = false, optional = true } +sp-api = { path = "../../api", default-features = false } +sp-application-crypto = { path = "../../application-crypto", default-features = false } +sp-core = { path = "../../core", default-features = false } +sp-keystore = { path = "../../keystore", default-features = false, optional = true } +sp-runtime = { path = "../../runtime", default-features = false } +sp-std = { path = "../../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "grandpa/std", diff --git a/substrate/primitives/consensus/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index cc4e961dbb6..5e134eb2a29 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -sp-api = { path = "../../api", default-features = false} -sp-core = { path = "../../core", default-features = false} -sp-runtime = { path = "../../runtime", default-features = false} -sp-std = { path = "../../std", default-features = false} +sp-api = { path = "../../api", default-features = false } +sp-core = { path = "../../core", default-features = false } +sp-runtime = { path = "../../runtime", default-features = false } +sp-std = { path = "../../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "sp-api/std", diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 2c5971e919e..67f09e2b904 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { default-features = false, path = "../../runtime" } sp-std = { default-features = false, path = "../../std" } [features] -default = [ "std" ] +default = ["std"] std = [ "scale-codec/std", "scale-info/std", diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index aa899d86e72..12940583757 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } -sp-std = { path = "../../std", default-features = false} -sp-timestamp = { path = "../../timestamp", default-features = false} +serde = { version = "1.0", default-features = false, features = ["alloc", "derive"], optional = true } +sp-std = { path = "../../std", default-features = false } +sp-timestamp = { path = "../../timestamp", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", @@ -30,4 +30,4 @@ std = [ ] # Serde support without relying on std features. -serde = [ "dep:serde", "scale-info/serde" ] +serde = ["dep:serde", "scale-info/serde"] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index fe82a2cd62e..9c556c07736 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -13,27 +13,27 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.193", optional = true, default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.193", optional = true, default-features = false, features = ["alloc", "derive"] } bounded-collections = { version = "0.1.8", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } -rand = { version = "0.8.5", features = ["small_rng"], optional = true } +rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } bip39 = { version = "2.0.0", default-features = false } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } parking_lot = { version = "0.12.1", optional = true } ss58-registry = { version = "1.34.0", default-features = false } -sp-std = { path = "../std", default-features = false} -sp-debug-derive = { path = "../debug-derive", default-features = false} -sp-storage = { path = "../storage", default-features = false} -sp-externalities = { path = "../externalities", optional = true} +sp-std = { path = "../std", default-features = false } +sp-debug-derive = { path = "../debug-derive", default-features = false } +sp-storage = { path = "../storage", default-features = false } +sp-externalities = { path = "../externalities", optional = true } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.48", optional = true } @@ -49,12 +49,12 @@ blake2 = { version = "0.10.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -secp256k1 = { version = "0.28.0", default-features = false, features = ["recovery", "alloc"], optional = true } +secp256k1 = { version = "0.28.0", default-features = false, features = ["alloc", "recovery"], optional = true } sp-core-hashing = { path = "hashing", default-features = false, optional = true } -sp-runtime-interface = { path = "../runtime-interface", default-features = false} +sp-runtime-interface = { path = "../runtime-interface", default-features = false } # bls crypto -w3f-bls = { version = "0.1.3", default-features = false, optional = true} +w3f-bls = { version = "0.1.3", default-features = false, optional = true } # bandersnatch crypto bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "3ddc205", default-features = false, optional = true } @@ -73,7 +73,7 @@ harness = false bench = false [features] -default = [ "std" ] +default = ["std"] std = [ "array-bytes", "bandersnatch_vrfs?/std", @@ -153,9 +153,9 @@ full_crypto = [ # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bls-experimental = [ "w3f-bls" ] +bls-experimental = ["w3f-bls"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = [ "bandersnatch_vrfs" ] +bandersnatch-experimental = ["bandersnatch_vrfs"] diff --git a/substrate/primitives/core/hashing/Cargo.toml b/substrate/primitives/core/hashing/Cargo.toml index bd22bd79e7d..7b4f4bc7438 100644 --- a/substrate/primitives/core/hashing/Cargo.toml +++ b/substrate/primitives/core/hashing/Cargo.toml @@ -21,7 +21,7 @@ sha3 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.6.3", default-features = false, features = ["digest_0_10"] } [features] -default = [ "std" ] +default = ["std"] std = [ "blake2b_simd/std", "byteorder/std", diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index 187b5559b93..e34e20472bf 100644 --- a/substrate/primitives/core/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true [dependencies] quote = "1.0.28" syn = { version = "2.0.38", features = ["full", "parsing"] } -sp-core-hashing = { path = "..", default-features = false} +sp-core-hashing = { path = "..", default-features = false } diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 1484406e7b2..548328fec3c 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime-interface = { path = "../../runtime-interface", default-features = fa sp-std = { path = "../../std", default-features = false, optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "ark-bls12-377-ext?/std", "ark-bls12-377?/std", @@ -46,11 +46,11 @@ std = [ "sp-runtime-interface?/std", "sp-std?/std", ] -common = [ "ark-ec", "ark-scale", "sp-runtime-interface", "sp-std" ] -bls12-377 = [ "ark-bls12-377", "ark-bls12-377-ext", "common" ] -bls12-381 = [ "ark-bls12-381", "ark-bls12-381-ext", "common" ] -bw6-761 = [ "ark-bw6-761", "ark-bw6-761-ext", "common" ] -ed-on-bls12-377 = [ "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "common" ] +common = ["ark-ec", "ark-scale", "sp-runtime-interface", "sp-std"] +bls12-377 = ["ark-bls12-377", "ark-bls12-377-ext", "common"] +bls12-381 = ["ark-bls12-381", "ark-bls12-381-ext", "common"] +bw6-761 = ["ark-bw6-761", "ark-bw6-761-ext", "common"] +ed-on-bls12-377 = ["ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "common"] ed-on-bls12-381-bandersnatch = [ "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index c97c8a0a399..217bcfa98d5 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -22,7 +22,7 @@ syn = "2.0.38" proc-macro2 = "1.0.56" [features] -default = [ "std" ] +default = ["std"] std = [] # By default `RuntimeDebug` implements `Debug` that outputs `` when `std` is # disabled. However, sometimes downstream users need to have the real `Debug` implementation for diff --git a/substrate/primitives/externalities/Cargo.toml b/substrate/primitives/externalities/Cargo.toml index 417eb363867..86d31c31cba 100644 --- a/substrate/primitives/externalities/Cargo.toml +++ b/substrate/primitives/externalities/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } environmental = { version = "1.1.3", default-features = false } -sp-std = { path = "../std", default-features = false} -sp-storage = { path = "../storage", default-features = false} +sp-std = { path = "../std", default-features = false } +sp-storage = { path = "../storage", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "environmental/std", "sp-std/std", "sp-storage/std" ] +default = ["std"] +std = ["codec/std", "environmental/std", "sp-std/std", "sp-storage/std"] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index cf7ce995711..00b3bc876ac 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { path = "../api", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } serde_json = { version = "1.0.108", default-features = false, features = ["alloc"] } [features] -default = [ "std" ] -std = [ "serde_json/std", "sp-api/std", "sp-runtime/std", "sp-std/std" ] +default = ["std"] +std = ["serde_json/std", "sp-api/std", "sp-runtime/std", "sp-std/std"] diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 4a511c653fd..2b5bad5d746 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -19,14 +19,14 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.48", optional = true } -sp-runtime = { path = "../runtime", default-features = false, optional = true} -sp-std = { path = "../std", default-features = false} +sp-runtime = { path = "../runtime", default-features = false, optional = true } +sp-std = { path = "../std", default-features = false } [dev-dependencies] futures = "0.3.21" [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 59df8895bb7..e95a9302d24 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -18,19 +18,19 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } -sp-core = { path = "../core", default-features = false} -sp-keystore = { path = "../keystore", default-features = false, optional = true} -sp-std = { path = "../std", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-keystore = { path = "../keystore", default-features = false, optional = true } +sp-std = { path = "../std", default-features = false } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { path = "../state-machine", default-features = false, optional = true} -sp-runtime-interface = { path = "../runtime-interface", default-features = false} -sp-trie = { path = "../trie", default-features = false, optional = true} -sp-externalities = { path = "../externalities", default-features = false} -sp-tracing = { path = "../tracing", default-features = false} +sp-state-machine = { path = "../state-machine", default-features = false, optional = true } +sp-runtime-interface = { path = "../runtime-interface", default-features = false } +sp-trie = { path = "../trie", default-features = false, optional = true } +sp-externalities = { path = "../externalities", default-features = false } +sp-tracing = { path = "../tracing", default-features = false } log = { version = "0.4.17", optional = true } -secp256k1 = { version = "0.28.0", features = ["recovery", "global-context"], optional = true } +secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"], optional = true } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.28", default-features = false} +tracing-core = { version = "0.1.28", default-features = false } # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "2.0", default-features = false, optional = true } @@ -39,7 +39,7 @@ ed25519-dalek = { version = "2.0", default-features = false, optional = true } rustversion = "1.0.6" [features] -default = [ "std" ] +default = ["std"] std = [ "bytes/std", "codec/std", @@ -60,7 +60,7 @@ std = [ "tracing/std", ] -with-tracing = [ "sp-tracing/with-tracing" ] +with-tracing = ["sp-tracing/with-tracing"] # These two features are used for `no_std` builds for the environments which already provides # `#[panic_handler]`, `#[alloc_error_handler]` and `#[global_allocator]`. @@ -92,9 +92,9 @@ improved_panic_error_reporting = [] # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bls-experimental = [ "sp-keystore/bls-experimental" ] +bls-experimental = ["sp-keystore/bls-experimental"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = [ "sp-keystore/bandersnatch-experimental" ] +bandersnatch-experimental = ["sp-keystore/bandersnatch-experimental"] diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 1ab78eeed45..a504cda756e 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -23,4 +23,4 @@ sp-runtime = { path = "../runtime" } # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = [ "sp-core/bandersnatch-experimental" ] +bandersnatch-experimental = ["sp-core/bandersnatch-experimental"] diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index ff7c27bf565..819b2c518a0 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -16,23 +16,23 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } parking_lot = { version = "0.12.1", default-features = false } thiserror = "1.0" -sp-core = { path = "../core", default-features = false} -sp-externalities = { path = "../externalities", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-externalities = { path = "../externalities", default-features = false } [dev-dependencies] rand = "0.7.2" rand_chacha = "0.2.2" [features] -default = [ "std" ] -std = [ "codec/std", "sp-core/std", "sp-externalities/std" ] +default = ["std"] +std = ["codec/std", "sp-core/std", "sp-externalities/std"] # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bls-experimental = [ "sp-core/bls-experimental" ] +bls-experimental = ["sp-core/bls-experimental"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = [ "sp-core/bandersnatch-experimental" ] +bandersnatch-experimental = ["sp-core/bandersnatch-experimental"] diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 89e03f1cabf..82a00935b30 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,19 +16,19 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } -serde = { version = "1.0.193", features = ["derive", "alloc"], default-features = false, optional = true } -sp-api = { path = "../api", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-debug-derive = { path = "../debug-derive", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +serde = { version = "1.0.193", features = ["alloc", "derive"], default-features = false, optional = true } +sp-api = { path = "../api", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-debug-derive = { path = "../debug-derive", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } thiserror = "1.0" [dev-dependencies] array-bytes = "6.1" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "log/std", @@ -43,4 +43,4 @@ std = [ ] # Serde support without relying on std features. -serde = [ "dep:serde", "scale-info/serde", "sp-core/serde", "sp-runtime/serde" ] +serde = ["dep:serde", "scale-info/serde", "sp-core/serde", "sp-runtime/serde"] diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index 77c21b920f2..f73a1d7b380 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../std", default-features = false} +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "frame-metadata/std", "scale-info/std", "sp-std/std" ] +default = ["std"] +std = ["codec/std", "frame-metadata/std", "scale-info/std", "sp-std/std"] diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index bc6878086cf..a03fdab8741 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -20,7 +20,7 @@ sp-application-crypto = { default-features = false, path = "../application-crypt sp-std = { default-features = false, path = "../std" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 44a53e856ba..1ab6c2adf82 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -15,18 +15,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } -sp-arithmetic = { path = "../arithmetic", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } +sp-arithmetic = { path = "../arithmetic", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [dev-dependencies] rand = "0.8.5" substrate-test-utils = { path = "../../test-utils" } [features] -default = [ "std" ] +default = ["std"] bench = [] std = [ "codec/std", diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 8bba69a7543..bd1fa856813 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.4.10", features = ["derive"] } honggfuzz = "0.5" -rand = { version = "0.8", features = ["std", "small_rng"] } +rand = { version = "0.8", features = ["small_rng", "std"] } sp-npos-elections = { path = ".." } sp-runtime = { path = "../../runtime" } diff --git a/substrate/primitives/offchain/Cargo.toml b/substrate/primitives/offchain/Cargo.toml index 5f8821b43c7..201e75802cf 100644 --- a/substrate/primitives/offchain/Cargo.toml +++ b/substrate/primitives/offchain/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { path = "../api", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } [features] -default = [ "std" ] -std = [ "sp-api/std", "sp-core/std", "sp-runtime/std" ] +default = ["std"] +std = ["sp-api/std", "sp-core/std", "sp-runtime/std"] diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index 69a0d112a16..80565420f6b 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } sp-wasm-interface = { path = "../wasm-interface", default-features = false } -sp-std = { path = "../std", default-features = false} -sp-tracing = { path = "../tracing", default-features = false} +sp-std = { path = "../std", default-features = false } +sp-tracing = { path = "../tracing", default-features = false } sp-runtime-interface-proc-macro = { path = "proc-macro" } -sp-externalities = { path = "../externalities", default-features = false} +sp-externalities = { path = "../externalities", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" primitive-types = { version = "0.12.0", default-features = false } -sp-storage = { path = "../storage", default-features = false} +sp-storage = { path = "../storage", default-features = false } impl-trait-for-tuples = "0.2.2" [dev-dependencies] @@ -35,7 +35,7 @@ rustversion = "1.0.6" trybuild = "1.0.74" [features] -default = [ "std" ] +default = ["std"] std = [ "bytes/std", "codec/std", diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 11236de91ce..6a06bb95654 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -21,4 +21,4 @@ proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" expander = "2.0.0" -syn = { version = "2.0.38", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.38", features = ["extra-traits", "fold", "full", "visit"] } diff --git a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 8e06aac851f..07c820c0601 100644 --- a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,15 +13,15 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../../core", default-features = false} -sp-io = { path = "../../io", default-features = false} -sp-runtime-interface = { path = "..", default-features = false} +sp-core = { path = "../../core", default-features = false } +sp-io = { path = "../../io", default-features = false } +sp-runtime-interface = { path = "..", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "sp-core/std", "sp-io/std", diff --git a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml index 7729f89fa39..79e79857341 100644 --- a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml @@ -14,16 +14,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } -sp-core = { path = "../../core", default-features = false} -sp-io = { path = "../../io", default-features = false} -sp-runtime-interface = { path = "..", default-features = false} -sp-std = { path = "../../std", default-features = false} +sp-core = { path = "../../core", default-features = false } +sp-io = { path = "../../io", default-features = false } +sp-runtime-interface = { path = "..", default-features = false } +sp-std = { path = "../../std", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "bytes/std", "sp-core/std", diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 9e2dc8b0265..827ccdbddbb 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -22,13 +22,13 @@ log = { version = "0.4.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } -sp-application-crypto = { path = "../application-crypto", default-features = false} -sp-arithmetic = { path = "../arithmetic", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-io = { path = "../io", default-features = false} -sp-std = { path = "../std", default-features = false} -sp-weights = { path = "../weights", default-features = false} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } +sp-application-crypto = { path = "../application-crypto", default-features = false } +sp-arithmetic = { path = "../arithmetic", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-io = { path = "../io", default-features = false } +sp-std = { path = "../std", default-features = false } +sp-weights = { path = "../weights", default-features = false } docify = { version = "0.2.6" } simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } @@ -45,7 +45,7 @@ substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } [features] runtime-benchmarks = [] try-runtime = [] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "either/use_std", diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 4c11762ffb7..b7e43f97300 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../api", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", optional = true} -sp-staking = { path = "../staking", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", optional = true } +sp-staking = { path = "../staking", default-features = false } +sp-std = { path = "../std", default-features = false } sp-keystore = { path = "../keystore", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index bc69e2f61c1..f52bf3316db 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -13,17 +13,17 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", @@ -32,4 +32,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] -runtime-benchmarks = [ "sp-runtime/runtime-benchmarks" ] +runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index ec5d9b5ea14..ab07d83af6a 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -22,11 +22,11 @@ rand = { version = "0.8.5", optional = true } smallvec = "1.11.0" thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } -sp-core = { path = "../core", default-features = false} -sp-externalities = { path = "../externalities", default-features = false} -sp-panic-handler = { path = "../panic-handler", optional = true} -sp-std = { path = "../std", default-features = false} -sp-trie = { path = "../trie", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-externalities = { path = "../externalities", default-features = false } +sp-panic-handler = { path = "../panic-handler", optional = true } +sp-std = { path = "../std", default-features = false } +sp-trie = { path = "../trie", default-features = false } trie-db = { version = "0.28.0", default-features = false } [dev-dependencies] @@ -37,7 +37,7 @@ sp-runtime = { path = "../runtime" } assert_matches = "1.5" [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "hash-db/std", diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 658229cef22..089af92f062 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} -sp-api = { path = "../api", default-features = false} -sp-application-crypto = { path = "../application-crypto", default-features = false} -sp-runtime-interface = { path = "../runtime-interface", default-features = false} -sp-externalities = { path = "../externalities", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } +sp-api = { path = "../api", default-features = false } +sp-application-crypto = { path = "../application-crypto", default-features = false } +sp-runtime-interface = { path = "../runtime-interface", default-features = false } +sp-externalities = { path = "../externalities", default-features = false } thiserror = { version = "1.0", optional = true } # ECIES dependencies @@ -31,10 +31,10 @@ curve25519-dalek = { version = "4.0.0", optional = true } aes-gcm = { version = "0.10", optional = true } hkdf = { version = "0.12.0", optional = true } sha2 = { version = "0.10.7", optional = true } -rand = { version = "0.8.5", features = ["small_rng"], optional = true } +rand = { version = "0.8.5", features = ["small_rng"], optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "aes-gcm", "aes-gcm?/std", diff --git a/substrate/primitives/std/Cargo.toml b/substrate/primitives/std/Cargo.toml index 2283a4a97a4..eae37c6dfe3 100644 --- a/substrate/primitives/std/Cargo.toml +++ b/substrate/primitives/std/Cargo.toml @@ -14,5 +14,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [features] -default = [ "std" ] +default = ["std"] std = [] diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 95fa27e9cfb..b7ff48cdd63 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -17,12 +17,12 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } -sp-debug-derive = { path = "../debug-derive", default-features = false} -sp-std = { path = "../std", default-features = false} +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } +sp-debug-derive = { path = "../debug-derive", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "impl-serde/std", @@ -32,4 +32,4 @@ std = [ ] # Serde support without relying on std features. -serde = [ "dep:serde", "impl-serde" ] +serde = ["dep:serde", "impl-serde"] diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index cacc3d86d17..0f2a399bffb 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", default-features = false, features = ["derive"], optional = true } -sp-application-crypto = { path = "../application-crypto", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-application-crypto = { path = "../application-crypto", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 44b0fdd831c..41afab0dcc2 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -16,12 +16,12 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.48", optional = true } -sp-inherents = { path = "../inherents", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-inherents = { path = "../inherents", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index 0f7e217ec38..43b3683fb06 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -15,7 +15,7 @@ default-target = "wasm32-unknown-unknown" # with the tracing enabled features = ["with-tracing"] # allowing for linux-gnu here, too, allows for `std` to show up as well -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"] [dependencies] sp-std = { path = "../std", default-features = false } @@ -29,8 +29,8 @@ tracing-subscriber = { version = "0.2.25", optional = true, features = [ ] } [features] -default = [ "std" ] -with-tracing = [ "codec/derive", "codec/full" ] +default = ["std"] +with-tracing = ["codec/derive", "codec/full"] std = [ "codec/std", "sp-std/std", diff --git a/substrate/primitives/transaction-pool/Cargo.toml b/substrate/primitives/transaction-pool/Cargo.toml index d1d38ffa1af..136d3200202 100644 --- a/substrate/primitives/transaction-pool/Cargo.toml +++ b/substrate/primitives/transaction-pool/Cargo.toml @@ -14,9 +14,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { path = "../api", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} +sp-api = { path = "../api", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } [features] -default = [ "std" ] -std = [ "sp-api/std", "sp-runtime/std" ] +default = ["std"] +std = ["sp-api/std", "sp-runtime/std"] diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index 5a35dd8f11f..e3bb80b2562 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-core = { path = "../core", optional = true} -sp-inherents = { path = "../inherents", default-features = false} -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} -sp-trie = { path = "../trie", optional = true} +sp-core = { path = "../core", optional = true } +sp-inherents = { path = "../inherents", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } +sp-trie = { path = "../trie", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "async-trait", "codec/std", diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 931ccce2044..1b1e40c9458 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -32,8 +32,8 @@ thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } -sp-core = { path = "../core", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-core = { path = "../core", default-features = false } +sp-std = { path = "../std", default-features = false } sp-externalities = { path = "../externalities", default-features = false } schnellru = { version = "0.2.1", optional = true } @@ -45,7 +45,7 @@ trie-standardmap = "0.16.0" sp-runtime = { path = "../runtime" } [features] -default = [ "std" ] +default = ["std"] std = [ "ahash", "codec/std", diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 7f272ead8d9..9860ef54c2d 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } thiserror = { version = "1.0.48", optional = true } sp-core-hashing-proc-macro = { path = "../core/hashing/proc-macro" } -sp-runtime = { path = "../runtime", default-features = false} -sp-std = { path = "../std", default-features = false} -sp-version-proc-macro = { path = "proc-macro", default-features = false} +sp-runtime = { path = "../runtime", default-features = false } +sp-std = { path = "../std", default-features = false } +sp-version-proc-macro = { path = "proc-macro", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "impl-serde/std", @@ -39,4 +39,4 @@ std = [ ] # Serde support without relying on std features. -serde = [ "dep:serde", "impl-serde", "sp-runtime/serde" ] +serde = ["dep:serde", "impl-serde", "sp-runtime/serde"] diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 7fce559e3ed..88f7193f50e 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.38", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.38", features = ["extra-traits", "fold", "full", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index c7413fec43c..e997f558c9d 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -19,9 +19,9 @@ impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } -sp-std = { path = "../std", default-features = false} +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] -std = [ "codec/std", "log/std", "sp-std/std", "wasmtime" ] -wasmtime = [ "anyhow", "dep:wasmtime" ] +default = ["std"] +std = ["codec/std", "log/std", "sp-std/std", "wasmtime"] +wasmtime = ["anyhow", "dep:wasmtime"] diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index c36714a76a3..a573495ff91 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.193", default-features = false, optional = true, features = ["derive", "alloc"] } +serde = { version = "1.0.193", default-features = false, optional = true, features = ["alloc", "derive"] } smallvec = "1.11.0" -sp-arithmetic = { path = "../arithmetic", default-features = false} -sp-core = { path = "../core", default-features = false} -sp-debug-derive = { path = "../debug-derive", default-features = false} -sp-std = { path = "../std", default-features = false} +sp-arithmetic = { path = "../arithmetic", default-features = false } +sp-core = { path = "../core", default-features = false } +sp-debug-derive = { path = "../debug-derive", default-features = false } +sp-std = { path = "../std", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "scale-info/std", @@ -35,7 +35,7 @@ std = [ ] # By default some types have documentation, `full-metadata-docs` allows to add documentation to # more types in the metadata. -full-metadata-docs = [ "scale-info/docs" ] +full-metadata-docs = ["scale-info/docs"] # Serde support without relying on std features. serde = [ diff --git a/substrate/scripts/ci/deny.toml b/substrate/scripts/ci/deny.toml index 1afb4a4f693..b1dbf773e31 100644 --- a/substrate/scripts/ci/deny.toml +++ b/substrate/scripts/ci/deny.toml @@ -5,7 +5,7 @@ unlicensed = "deny" # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. allow = [ - "MPL-2.0", + "MPL-2.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses @@ -34,70 +34,70 @@ confidence-threshold = 0.8 # Allow 1 or more licenses on a per-crate basis, so that particular licenses # aren't accepted for every possible crate as with the normal allow list exceptions = [ - # Each entry is the crate and version constraint, and its specific allow list - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "chain-spec-builder" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "mmr-gadget" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-bench" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "staging-node-cli" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-inspect" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-template-release" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-testing" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-authority-discovery" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-basic-authorship" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-block-builder" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec-derive" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-cli" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-api" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-db" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-aura" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe-rpc" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy-rpc" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-epochs" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa-rpc" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-manual-seal" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-pow" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-slots" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-common" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-wasmi" }, - { 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" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-gossip" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-light" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-sync" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-test" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-transactions" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-statement" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-offchain" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-peerset" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-proposer-metrics" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-api" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-server" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-spec-v2" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-runtime-test" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service-test" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-state-db" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-statement-store" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-storage-monitor" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-sysinfo" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-telemetry" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-tracing" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool-api" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "subkey" }, - { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "substrate" }, + # Each entry is the crate and version constraint, and its specific allow list + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "chain-spec-builder" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "mmr-gadget" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-bench" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-inspect" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-template-release" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-testing" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-authority-discovery" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-basic-authorship" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-block-builder" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec-derive" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-cli" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-db" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-aura" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-epochs" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-manual-seal" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-pow" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-slots" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-common" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-wasmi" }, + { 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" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-gossip" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-light" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-statement" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-sync" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-transactions" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-offchain" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-peerset" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-proposer-metrics" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-server" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-spec-v2" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-runtime-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-state-db" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-statement-store" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-storage-monitor" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-sysinfo" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-telemetry" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-tracing" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "staging-node-cli" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "subkey" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "substrate" }, ] # Some crates don't have (easily) machine readable licensing information, @@ -114,6 +114,6 @@ expression = "MIT AND ISC AND OpenSSL" # and the crate will be checked normally, which may produce warnings or errors # depending on the rest of your configuration license-files = [ - # Each entry is a crate relative path, and the (opaque) hash of its contents - { path = "LICENSE", hash = 0xbd0eed23 } + # Each entry is a crate relative path, and the (opaque) hash of its contents + { path = "LICENSE", hash = 0xbd0eed23 }, ] diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index 31bdc0f663a..17696e8229c 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -17,5 +17,5 @@ futures = "0.3.16" tokio = { version = "1.22.0", features = ["macros", "time"] } [dev-dependencies] -trybuild = { version = "1.0.74", features = [ "diff" ] } +trybuild = { version = "1.0.74", features = ["diff"] } sc-service = { path = "../client/service" } diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index 022db32c34f..4f20e9e2ce5 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -26,4 +26,4 @@ sc-service = { path = "../../client/service" } futures = "0.3.28" [features] -try-runtime = [ "node-cli/try-runtime" ] +try-runtime = ["node-cli/try-runtime"] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index dc034de876a..9829ae531fe 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -22,13 +22,13 @@ serde_json = "1.0.108" sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ "test-helpers", -]} +] } sc-consensus = { path = "../../client/consensus/common" } sc-executor = { path = "../../client/executor" } sc-offchain = { path = "../../client/offchain" } sc-service = { path = "../../client/service", default-features = false, features = [ "test-helpers", -]} +] } sp-blockchain = { path = "../../primitives/blockchain" } sp-consensus = { path = "../../primitives/consensus/common" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 88f8a1b572d..655c7f0fec1 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -13,37 +13,37 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } +sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } sp-consensus-aura = { path = "../../primitives/consensus/aura", default-features = false, features = ["serde"] } sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features = false, features = ["serde"] } -sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false} -sp-block-builder = { path = "../../primitives/block-builder", default-features = false} +sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } +sp-block-builder = { path = "../../primitives/block-builder", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-inherents = { path = "../../primitives/inherents", default-features = false} -sp-keyring = { path = "../../primitives/keyring", optional = true} -sp-offchain = { path = "../../primitives/offchain", default-features = false} -sp-core = { path = "../../primitives/core", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} -sp-io = { path = "../../primitives/io", default-features = false} -frame-support = { path = "../../frame/support", default-features = false} -sp-version = { path = "../../primitives/version", default-features = false} -sp-session = { path = "../../primitives/session", default-features = false} -sp-api = { path = "../../primitives/api", default-features = false} +sp-inherents = { path = "../../primitives/inherents", default-features = false } +sp-keyring = { path = "../../primitives/keyring", optional = true } +sp-offchain = { path = "../../primitives/offchain", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-io = { path = "../../primitives/io", default-features = false } +frame-support = { path = "../../frame/support", default-features = false } +sp-version = { path = "../../primitives/version", default-features = false } +sp-session = { path = "../../primitives/session", default-features = false } +sp-api = { path = "../../primitives/api", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } -pallet-babe = { path = "../../frame/babe", default-features = false} -pallet-balances = { path = "../../frame/balances", default-features = false} -frame-executive = { path = "../../frame/executive", default-features = false} -frame-system = { path = "../../frame/system", default-features = false} -frame-system-rpc-runtime-api = { path = "../../frame/system/rpc/runtime-api", default-features = false} -pallet-timestamp = { path = "../../frame/timestamp", default-features = false} +pallet-babe = { path = "../../frame/babe", default-features = false } +pallet-balances = { path = "../../frame/balances", default-features = false } +frame-executive = { path = "../../frame/executive", default-features = false } +frame-system = { path = "../../frame/system", default-features = false } +frame-system-rpc-runtime-api = { path = "../../frame/system/rpc/runtime-api", default-features = false } +pallet-timestamp = { path = "../../frame/timestamp", default-features = false } sp-consensus-grandpa = { path = "../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-trie = { path = "../../primitives/trie", default-features = false} -sp-transaction-pool = { path = "../../primitives/transaction-pool", default-features = false} +sp-trie = { path = "../../primitives/trie", default-features = false } +sp-transaction-pool = { path = "../../primitives/transaction-pool", default-features = false } trie-db = { version = "0.28.0", default-features = false } -sc-service = { path = "../../client/service", default-features = false, features = ["test-helpers"], optional = true} -sp-state-machine = { path = "../../primitives/state-machine", default-features = false} -sp-externalities = { path = "../../primitives/externalities", default-features = false} +sc-service = { path = "../../client/service", default-features = false, features = ["test-helpers"], optional = true } +sp-state-machine = { path = "../../primitives/state-machine", default-features = false } +sp-externalities = { path = "../../primitives/externalities", default-features = false } # 3rd party array-bytes = { version = "6.1", optional = true } @@ -65,7 +65,7 @@ serde_json = { version = "1.0.108", default-features = false, features = ["alloc substrate-wasm-builder = { path = "../../utils/wasm-builder", optional = true } [features] -default = [ "std" ] +default = ["std"] std = [ "array-bytes", @@ -108,4 +108,4 @@ std = [ "trie-db/std", ] # Special feature to disable logging -disable-logging = [ "sp-api/disable-logging" ] +disable-logging = ["sp-api/disable-logging"] diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index 6bb1d5f0f1e..f36e4f4e0b6 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -20,6 +20,6 @@ sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } [features] -debug = [ "array-bytes", "log" ] -default = [ "debug", "std" ] -std = [ "hash-db/std", "log/std", "sp-core/std", "sp-runtime/std" ] +debug = ["array-bytes", "log"] +default = ["debug", "std"] +std = ["hash-db/std", "log/std", "sp-core/std", "sp-runtime/std"] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index a6f6264b65c..b6eca132067 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -34,11 +34,11 @@ frame-benchmarking = { path = "../../../frame/benchmarking" } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-block-builder = { path = "../../../client/block-builder" } -sc-cli = { path = "../../../client/cli", default-features = false} +sc-cli = { path = "../../../client/cli", default-features = false } sc-client-api = { path = "../../../client/api" } -sc-client-db = { path = "../../../client/db", default-features = false} +sc-client-db = { path = "../../../client/db", default-features = false } sc-executor = { path = "../../../client/executor" } -sc-service = { path = "../../../client/service", default-features = false} +sc-service = { path = "../../../client/service", default-features = false } sc-sysinfo = { path = "../../../client/sysinfo" } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } @@ -56,7 +56,7 @@ sp-wasm-interface = { path = "../../../primitives/wasm-interface" } gethostname = "0.2.3" [features] -default = [ "rocksdb" ] +default = ["rocksdb"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -65,4 +65,4 @@ runtime-benchmarks = [ "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -rocksdb = [ "sc-cli/rocksdb", "sc-client-db/rocksdb" ] +rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index d25e6ec67c9..6d3cb545efb 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -21,7 +21,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = "0.28.0" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } # Substrate Dependencies sc-client-api = { path = "../../../../client/api" } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 22283fbf450..da56297c82f 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -21,7 +21,7 @@ sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.10.0" -jsonrpsee = { version = "0.16.2", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.16.2", features = ["jsonrpsee-types", "ws-client"] } tokio = "1.22.0" sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 77c3b7eeee3..636f2cd0485 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "macros", "server"] } futures = "0.3.21" log = "0.4.17" frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 97efa0e6624..31e95a8be41 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -12,7 +12,7 @@ description = "Cli command runtime testing and dry-running" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -remote-externalities = { package = "frame-remote-externalities" , path = "../../remote-externalities" } +remote-externalities = { package = "frame-remote-externalities", path = "../../remote-externalities" } sc-cli = { path = "../../../../client/cli" } sc-executor = { path = "../../../../client/executor" } sp-consensus-aura = { path = "../../../../primitives/consensus/aura" } @@ -31,7 +31,7 @@ sp-version = { path = "../../../../primitives/version" } sp-debug-derive = { path = "../../../../primitives/debug-derive" } sp-api = { path = "../../../../primitives/api" } sp-weights = { path = "../../../../primitives/weights" } -frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true} +frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.57" -- GitLab From dfd7b15effce7ee28a379f2aa0f21498393fa3e7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 1 Dec 2023 11:19:09 +0000 Subject: [PATCH 632/633] Contracts: make benchmark dependencies optional in `std` feature (#2576) `wasm-instrument` and `rand` are optional and only used in benchmarking, so should not be pulled in by default as part of the `std` feature. --- substrate/frame/contracts/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 80856bef3fd..29c39c047a3 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -88,7 +88,7 @@ std = [ "pallet-proxy/std", "pallet-timestamp/std", "pallet-utility/std", - "rand/std", + "rand?/std", "scale-info/std", "serde", "sp-api/std", @@ -97,7 +97,7 @@ std = [ "sp-keystore/std", "sp-runtime/std", "sp-std/std", - "wasm-instrument/std", + "wasm-instrument?/std", "wasmi/std", "xcm-builder/std", "xcm/std", -- GitLab From 7f0beaf2a57654259ee19b492e627d56bf90bfd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:04:12 +0100 Subject: [PATCH 633/633] Bump proc-macro-crate from 1.3.1 to 2.0.0 (#2557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [proc-macro-crate](https://github.com/bkchr/proc-macro-crate) from 1.3.1 to 2.0.0.
Release notes

Sourced from proc-macro-crate's releases.

v2.0.0

What's Changed

Full Changelog: https://github.com/bkchr/proc-macro-crate/compare/v1.3.1...v2.0.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=proc-macro-crate&package-manager=cargo&previous-version=1.3.1&new-version=2.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 52 +++++++++++++------ .../parachain-system/proc-macro/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- 10 files changed, 45 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c83eeb050df..9c5a2c57da0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3604,7 +3604,7 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -5054,7 +5054,7 @@ checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" dependencies = [ "expander 0.0.4", "indexmap 1.9.3", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -5378,7 +5378,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "scale-info", @@ -5543,7 +5543,7 @@ name = "frame-support-procedural-tools" version = "4.0.0-dev" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -6768,7 +6768,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44e8ab85614a08792b9bff6c8feee23be78c98d0182d4c622c05256ab553892a" dependencies = [ "heck", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -8199,7 +8199,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -8843,7 +8843,7 @@ dependencies = [ "itertools 0.11.0", "layout-rs", "petgraph", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -10654,7 +10654,7 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "sp-runtime", @@ -11259,7 +11259,7 @@ version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -13490,6 +13490,15 @@ dependencies = [ "toml_edit 0.19.14", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -14831,7 +14840,7 @@ dependencies = [ name = "sc-chain-spec-derive" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -16087,7 +16096,7 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -16177,7 +16186,7 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -16966,7 +16975,7 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander 2.0.0", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -17643,7 +17652,7 @@ version = "11.0.0" dependencies = [ "Inflector", "expander 2.0.0", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", @@ -17655,7 +17664,7 @@ version = "11.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.38", @@ -19337,6 +19346,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow", +] + [[package]] name = "toml_edit" version = "0.21.0" @@ -19451,7 +19471,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "expander 2.0.0", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.38", diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index f4bfdf27062..ed85b718f50 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -13,7 +13,7 @@ proc-macro = true syn = "2.0.38" proc-macro2 = "1.0.64" quote = "1.0.33" -proc-macro-crate = "1.3.1" +proc-macro-crate = "2.0.0" [features] default = ["std"] diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index cd6e19b3dd2..c775c570705 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true syn = { version = "2.0.38", features = ["extra-traits", "full"] } quote = "1.0.28" proc-macro2 = "1.0.56" -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" expander = "2.0.0" [dev-dependencies] diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 74b8b656a40..c200d84244d 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" proc-macro2 = "1.0.56" quote = "1.0.28" syn = "2.0.38" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 2e4a0c8f3ee..f0cca5c41b6 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } syn = { version = "2.0.38", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 1e3002d5dc4..e5d59685661 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true syn = { version = "2.0.38", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" [dev-dependencies] parity-scale-codec = "3.6.1" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 0a725996115..2d57dc60fff 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.38", features = ["full", "visit"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 836e55b8a63..4921a2a9428 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -12,7 +12,7 @@ description = "Proc macro helpers for procedural macros" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.38", features = ["extra-traits", "full", "visit"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 8188299f533..232b988124b 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -20,7 +20,7 @@ quote = "1.0.28" syn = { version = "2.0.38", features = ["extra-traits", "fold", "full", "visit"] } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" expander = "2.0.0" Inflector = "0.11.4" diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 6a06bb95654..6018ef6c2d4 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] Inflector = "0.11.4" -proc-macro-crate = "1.1.3" +proc-macro-crate = "2.0.0" proc-macro2 = "1.0.56" quote = "1.0.28" expander = "2.0.0" -- GitLab

(); + crate::storage::unhashed::exists(&key) + } } impl PartialEq for StorageVersion { diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 83ae5b9253c..00e7adafb0b 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -21,7 +21,7 @@ use frame_support::{ dispatch_context::with_context, pallet_prelude::{StorageInfoTrait, ValueQuery}, parameter_types, - storage::unhashed, + storage::{unhashed, unhashed::contains_prefixed_key}, traits::{ ConstU32, GetCallIndex, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, @@ -2330,6 +2330,58 @@ fn test_storage_alias() { }) } +#[test] +fn pallet_on_chain_storage_version_initializes_correctly() { + type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + >; + + // Simple example of a pallet with current version 10 being added to the runtime for the first + // time. + TestExternalities::default().execute_with(|| { + let current_version = Example::current_storage_version(); + + // Check the pallet has no storage items set. + let pallet_hashed_prefix = twox_128(Example::name().as_bytes()); + let exists = contains_prefixed_key(&pallet_hashed_prefix); + assert_eq!(exists, false); + + // [`frame_support::traits::BeforeAllRuntimeMigrations`] hook should initialize the storage + // version. + Executive::execute_on_runtime_upgrade(); + + // Check that the storage version was initialized to the current version + let on_chain_version_after = StorageVersion::get::(); + assert_eq!(on_chain_version_after, current_version); + }); + + // Pallet with no current storage version should have the on-chain version initialized to 0. + TestExternalities::default().execute_with(|| { + // Example4 current_storage_version is NoStorageVersionSet. + + // Check the pallet has no storage items set. + let pallet_hashed_prefix = twox_128(Example4::name().as_bytes()); + let exists = contains_prefixed_key(&pallet_hashed_prefix); + assert_eq!(exists, false); + + // Confirm the storage version is implicitly 0. + let on_chain_version_before = StorageVersion::get::(); + assert_eq!(on_chain_version_before, StorageVersion::new(0)); + + // [`frame_support::traits::BeforeAllRuntimeMigrations`] initializes the storage version. + Executive::execute_on_runtime_upgrade(); + + // Check that the storage version now exists and was initialized to 0. + let on_chain_version_after = StorageVersion::get::(); + assert_eq!(StorageVersion::exists::(), true); + assert_eq!(on_chain_version_after, StorageVersion::new(0)); + }); +} + #[cfg(feature = "try-runtime")] #[test] fn post_runtime_upgrade_detects_storage_version_issues() { @@ -2382,8 +2434,10 @@ fn post_runtime_upgrade_detects_storage_version_issues() { >; TestExternalities::default().execute_with(|| { - // Call `on_genesis` to put the storage version of `Example` into the storage. - Example::on_genesis(); + // Set the on-chain version to one less than the current version for `Example`, simulating a + // forgotten migration + StorageVersion::new(9).put::(); + // The version isn't changed, we should detect it. assert!( Executive::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost).unwrap_err() == -- GitLab From f5e9827fdaca12a1bb4223c7848ca3423dcc4c3a Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:10:19 +0200 Subject: [PATCH 455/633] zombienet_tests: Fix genesis error in 0006-parachains-max-tranche0.toml (#2191) There was a race in merging between https://github.com/paritytech/polkadot-sdk/pull/1256 and https://github.com/paritytech/polkadot-sdk/pull/1178, so this newly added tests wasn't updated with the new path for the configuration, so fix that. Signed-off-by: Alexandru Gheorghe --- .../functional/0006-parachains-max-tranche0.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml index 68ac90f5a7e..bef54cb8ca4 100644 --- a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml +++ b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml @@ -2,7 +2,7 @@ timeout = 1000 bootnode = true -[relaychain.genesis.runtime.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config] max_validators_per_core = 1 needed_approvals = 7 relay_vrf_modulo_samples = 5 -- GitLab From 295a8483017da3a556ee7bf2b126aa2436467ab9 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 7 Nov 2023 23:46:57 +1300 Subject: [PATCH 456/633] mark pallet-asset-rate optional in polkadot-runtime-common (#2187) Part of #2186 The only usage of pallet-asset-rate is guarded by `runtime-benchmarks` feature. I don't want ORML to be forced to include this pallet in deps for no good reason. --- polkadot/runtime/common/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index a6642f9c9c7..0882e555aaf 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -39,7 +39,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-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false, optional = true } 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 } @@ -80,7 +80,7 @@ std = [ "inherents/std", "libsecp256k1/std", "log/std", - "pallet-asset-rate/std", + "pallet-asset-rate?/std", "pallet-authorship/std", "pallet-balances/std", "pallet-election-provider-multi-phase/std", -- GitLab From 4caa3d8d8e6f90b2689cd2666c94044394712abf Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Tue, 7 Nov 2023 20:11:06 +0800 Subject: [PATCH 457/633] docs: fix typos (#2193) --- bridges/zombienet/README.md | 2 +- cumulus/parachains/runtimes/assets/README.md | 2 +- polkadot/roadmap/implementers-guide/src/disputes-flow.md | 2 +- .../src/node/backing/statement-distribution-legacy.md | 2 +- .../src/node/backing/statement-distribution.md | 2 +- .../src/node/disputes/dispute-distribution.md | 2 +- .../src/node/utility/candidate-validation.md | 2 +- .../src/node/utility/pvf-host-and-workers.md | 2 +- .../implementers-guide/src/node/utility/pvf-prechecker.md | 2 +- polkadot/roadmap/implementers-guide/src/protocol-approval.md | 2 +- polkadot/roadmap/implementers-guide/src/runtime/hrmp.md | 2 +- polkadot/roadmap/implementers-guide/src/runtime/inclusion.md | 2 +- polkadot/roadmap/implementers-guide/src/runtime/paras.md | 2 +- polkadot/roadmap/implementers-guide/src/runtime/scheduler.md | 2 +- polkadot/roadmap/implementers-guide/src/types/backing.md | 2 +- substrate/bin/utils/subkey/README.md | 4 ++-- substrate/client/consensus/beefy/README.md | 4 ++-- substrate/client/transaction-pool/README.md | 2 +- substrate/docs/CHANGELOG.md | 2 +- substrate/docs/Upgrading-2.0-to-3.0.md | 2 +- substrate/frame/root-testing/README.md | 2 +- substrate/primitives/maybe-compressed-blob/README.md | 2 +- substrate/test-utils/runtime/res/README.md | 2 +- 23 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bridges/zombienet/README.md b/bridges/zombienet/README.md index 2da3093f4f0..7f7de770814 100644 --- a/bridges/zombienet/README.md +++ b/bridges/zombienet/README.md @@ -2,7 +2,7 @@ This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both onchain and offchain bridges code. Due to some -[technical diffuculties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we +[technical difficulties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we are using native zombienet provider, which means that you need to build some binaries locally. To start those tests, you need to: diff --git a/cumulus/parachains/runtimes/assets/README.md b/cumulus/parachains/runtimes/assets/README.md index 78145395cbf..05466e537f4 100644 --- a/cumulus/parachains/runtimes/assets/README.md +++ b/cumulus/parachains/runtimes/assets/README.md @@ -8,7 +8,7 @@ Asset Hub allows users to: - Deploy promise-backed assets, both fungible and non-fungible, with a DOT/KSM deposit. - Set admin roles to manage assets and asset classes. - Register assets as "self-sufficient" if the Relay Chain agrees, i.e. gain the ability for an - asset to justify the existance of accounts sans DOT/KSM. + asset to justify the existence of accounts sans DOT/KSM. - Pay transaction fees using sufficient assets. - Transfer (and approve transfer) assets. - Interact with the chain via its transactional API or XCM. diff --git a/polkadot/roadmap/implementers-guide/src/disputes-flow.md b/polkadot/roadmap/implementers-guide/src/disputes-flow.md index f9fd8dcce35..b5cc5611c6f 100644 --- a/polkadot/roadmap/implementers-guide/src/disputes-flow.md +++ b/polkadot/roadmap/implementers-guide/src/disputes-flow.md @@ -52,7 +52,7 @@ stateDiagram-v2 IncomingRequestDisputeAvailabilityData --> RespondUnavailable IncomingRequestDisputeAvailabilityData --> DisputeDataAvail DisputeDataAvail --> RespondWithDisputeAvailabilityData: Send - VoteGossipReceived --> Track: implies source peer has
dispute availablity data + VoteGossipReceived --> Track: implies source peer has
dispute availability data ``` --- diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md index e10a55010b9..71005514466 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md @@ -149,7 +149,7 @@ The receiver of such a message needs to request the actual payload via request/r This is necessary as distribution of a large payload (mega bytes) via gossip would make the network collapse and timely distribution of statements would no longer be possible. By using request/response it is ensured that each peer only -transferes large data once. We only take good care to detect an overloaded peer early and immediately move on to a +transfers large data once. We only take good care to detect an overloaded peer early and immediately move on to a different peer for fetching the data. This mechanism should result in a good load distribution and therefore a rather optimal distribution path. diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md index 24f2785f829..86a1bf12141 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md @@ -3,7 +3,7 @@ This subsystem is responsible for distributing signed statements that we have generated and forwarding statements generated by our peers. Received candidate receipts and statements are passed to the [Candidate Backing subsystem](candidate-backing.md) to handle producing local statements. On receiving -`StatementDistributionMessage::Share`, this subsystem distributes the message across the network with redundency to +`StatementDistributionMessage::Share`, this subsystem distributes the message across the network with redundancy to ensure a fast backing process. ## Overview diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md index 4547e02352e..e916d246060 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-distribution.md @@ -297,7 +297,7 @@ is `500ms` and above `RATE_LIMIT` is `100ms`. 1/3 of validators are malicious, so for 1000 this means around 330 malicious actors worst case. All those actors can send a message every `100ms`, that is 10 per second. This -means at the begining of an attack they can open up around 3300 batches. Each +means at the beginning of an attack they can open up around 3300 batches. Each containing two votes. So memory usage is still negligible. In reality it is even less, as we also demand 10 new votes to trickle in per batch in order to keep it alive, every `500ms`. Hence for the first second, each batch requires 20 votes diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md index 376fa187de1..e252ec237b7 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md @@ -31,7 +31,7 @@ all the necessary parameters to the validation function. These are: * The [`ValidationData`](../../types/candidate.md#validationdata). * The [`PoV`](../../types/availability.md#proofofvalidity). -The second category is for PVF pre-checking. This is primarly used by the [PVF pre-checker](pvf-prechecker.md) +The second category is for PVF pre-checking. This is primarily used by the [PVF pre-checker](pvf-prechecker.md) subsystem. ### Determining Parameters 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 0cefeb1f77c..52129f9eb80 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 @@ -44,7 +44,7 @@ execution request: We use timeouts for both preparation and execution jobs to limit the amount of time they can take. As the time for a job can vary depending on the machine and load on the machine, this can potentially lead to disputes where some validators -successfuly execute a PVF and others don't. +successfully execute a PVF and others don't. One dispute mitigation we have in place is a more lenient timeout for preparation during execution than during pre-checking. The rationale is that the diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md index b722bdc6539..f0de50f2267 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md @@ -24,7 +24,7 @@ relevant. When a PVF just becomes relevant, the subsystem will send a message to the [Candidate Validation] subsystem asking for the pre-check. -Upon receving a message from the candidate-validation subsystem, the pre-checker will note down that the PVF has its +Upon receiving a message from the candidate-validation subsystem, the pre-checker will note down that the PVF has its judgement and will also sign and submit a [`PvfCheckStatement`][PvfCheckStatement] via the [`submit_pvf_check_statement` runtime API][PVF pre-checking runtime API]. In case, a judgement was received for a PVF that is no longer in view it is ignored. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-approval.md b/polkadot/roadmap/implementers-guide/src/protocol-approval.md index 4fac8459145..70bc0233d65 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-approval.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-approval.md @@ -330,7 +330,7 @@ We prefer doing approval checkers assignments under `RelayVRFModulo` or `RelayVR assignments benefit security the most. We suggest assigning at least 16 checkers under `RelayVRFModulo` or `RelayVRFModuloCompact` although assignment levels have never been properly analyzed. -Our delay criteria `RelayVRFDelay` and `RelayEquivocation` both have two primary paramaters, expected checkers per +Our delay criteria `RelayVRFDelay` and `RelayEquivocation` both have two primary parameters, expected checkers per tranche and the zeroth delay tranche width. We require expected checkers per tranche to be less than three because otherwise an adversary with 1/3 stake could force diff --git a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md index aa31491d72f..69d33ca8670 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md @@ -108,7 +108,7 @@ HrmpEgressChannelsIndex: map ParaId => Vec; /// Invariant: cannot be non-empty if the corresponding channel in `HrmpChannels` is `None`. HrmpChannelContents: map HrmpChannelId => Vec; /// Maintains a mapping that can be used to answer the question: -/// What paras sent a message at the given block number for a given reciever. +/// What paras sent a message at the given block number for a given receiver. /// Invariants: /// - The inner `Vec` is never empty. /// - The inner `Vec` cannot store two same `ParaId`. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index f73df209981..f6a32a01d50 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -133,7 +133,7 @@ All failed checks should lead to an unrecoverable error making the block invalid [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments). 1. call `Dmp::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`. - 1. call `Hrmp::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`. + 1. call `Hrmp::prune_hrmp` with the para id of the candidate and the candidate's `hrmp_watermark`. 1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment, 1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/paras.md b/polkadot/roadmap/implementers-guide/src/runtime/paras.md index ac9b1520c3d..e6e0b53512f 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/paras.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/paras.md @@ -189,7 +189,7 @@ UpgradeGoAheadSignal: map hasher(twox_64_concat) ParaId => Option)`: indicate previosuly-occupied cores which are to be considered returned +- `free_cores(Vec<(CoreIndex, FreedReason)>)`: indicate previously-occupied cores which are to be considered returned and why they are being returned. - All freed lease holding parachain cores should be assigned to their respective parachain - All freed on-demand parachain cores whose reason for freeing was `FreedReason::Concluded` should have the claim diff --git a/polkadot/roadmap/implementers-guide/src/types/backing.md b/polkadot/roadmap/implementers-guide/src/types/backing.md index 7e43325ec5c..bfe182383fd 100644 --- a/polkadot/roadmap/implementers-guide/src/types/backing.md +++ b/polkadot/roadmap/implementers-guide/src/types/backing.md @@ -30,7 +30,7 @@ work, we extract a signed wrapper. ```rust,ignore /// A signed type which encapsulates the common desire to sign some data and validate a signature. /// -/// Note that the internal fields are not public; they are all accessable by immutable getters. +/// Note that the internal fields are not public; they are all accessible by immutable getters. /// This reduces the chance that they are accidentally mutated, invalidating the signature. struct Signed { /// The payload is part of the signed data. The rest is the signing context, diff --git a/substrate/bin/utils/subkey/README.md b/substrate/bin/utils/subkey/README.md index 60e5a9ca935..3232c829587 100644 --- a/substrate/bin/utils/subkey/README.md +++ b/substrate/bin/utils/subkey/README.md @@ -74,7 +74,7 @@ The output above shows a **secret phrase** (also called **mnemonic phrase**) and **Private Key**). Those 2 secrets are the pieces of information you MUST keep safe and secret. All the other information below can be derived from those secrets. -The output above also show the **public key** and the **Account ID**. Those are the independant from the network where +The output above also show the **public key** and the **Account ID**. Those are the independent from the network where you will use the key. The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for @@ -163,7 +163,7 @@ This time, we properly recovered `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6ia ### Inspecting a key -If you have *some data* about a key, `subkey inpsect` will help you discover more information about it. +If you have *some data* about a key, `subkey inspect` will help you discover more information about it. If you have **secrets** that you would like to verify for instance, you can use: diff --git a/substrate/client/consensus/beefy/README.md b/substrate/client/consensus/beefy/README.md index 1a5a9667fdb..13f88303a97 100644 --- a/substrate/client/consensus/beefy/README.md +++ b/substrate/client/consensus/beefy/README.md @@ -104,7 +104,7 @@ shortcuts: ## Mental Model BEEFY should be considered as an extra voting round done by GRANDPA validators for the current -best finalized block. Similarily to how GRANDPA is lagging behind best produced (non-finalized) +best finalized block. Similarly to how GRANDPA is lagging behind best produced (non-finalized) block, BEEFY is going to lag behind best GRANDPA (finalized) block. ``` @@ -302,7 +302,7 @@ periodically on the global topic. Let's now dive into description of the message ## Misbehavior -Similarily to other PoS protocols, BEEFY considers casting two different votes in the same round a +Similarly to other PoS protocols, BEEFY considers casting two different votes in the same round a misbehavior. I.e. for a particular `round_number`, the validator produces signatures for 2 different `Commitment`s and broadcasts them. This is called **equivocation**. diff --git a/substrate/client/transaction-pool/README.md b/substrate/client/transaction-pool/README.md index b34b623b26e..b55dc6482d6 100644 --- a/substrate/client/transaction-pool/README.md +++ b/substrate/client/transaction-pool/README.md @@ -227,7 +227,7 @@ transactions that are prepared for block inclusion. Propagation is best effort, especially for block authors and is not directly incentivised. However the networking protocol might penalise peers that send invalid or useless transactions so we should be nice to others. Also see below a proposal -to instead of gossiping everyting have other peers request transactions they +to instead of gossiping everything have other peers request transactions they are interested in. Since the pool is expected to store more transactions than what can fit diff --git a/substrate/docs/CHANGELOG.md b/substrate/docs/CHANGELOG.md index 8a1b245a5b0..042b7b8a2f0 100644 --- a/substrate/docs/CHANGELOG.md +++ b/substrate/docs/CHANGELOG.md @@ -45,7 +45,7 @@ board](https://github.com/paritytech/substrate/discussions). * Allow validators to block and kick their nominator set. (#7930) * Decouple Staking and Election - Part1: Support traits (#7908) * Introduces account existence providers reference counting (#7363) -* contracts: Cap the surcharge reward by the amount of rent that way payed by a contract (#7870) +* contracts: Cap the surcharge reward by the amount of rent that way paid by a contract (#7870) * Use checked math when calculating storage size (#7885) * Fix clear prefix check to avoid erasing child trie roots. (#7848) * contracts: Collect rent for the first block during deployment (#7847) diff --git a/substrate/docs/Upgrading-2.0-to-3.0.md b/substrate/docs/Upgrading-2.0-to-3.0.md index 3f2a3e7c5be..1be41a34ef3 100644 --- a/substrate/docs/Upgrading-2.0-to-3.0.md +++ b/substrate/docs/Upgrading-2.0-to-3.0.md @@ -113,7 +113,7 @@ And update the overall definition for weights on frame and a few related types a ```diff= -const AVERAGE_ON_INITIALIZE_WEIGHT: Perbill = Perbill::from_percent(10); -+/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. ++/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. +/// This is used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used diff --git a/substrate/frame/root-testing/README.md b/substrate/frame/root-testing/README.md index aa231e3ef20..a0eeda5cc6a 100644 --- a/substrate/frame/root-testing/README.md +++ b/substrate/frame/root-testing/README.md @@ -1,5 +1,5 @@ # Root Testing Pallet -Pallet that contains extrinsics that can be usefull in testing. +Pallet that contains extrinsics that can be useful in testing. NOTE: This pallet should only be used for testing purposes and should not be used in production runtimes! diff --git a/substrate/primitives/maybe-compressed-blob/README.md b/substrate/primitives/maybe-compressed-blob/README.md index b5bb869c30e..a2f6a1c5343 100644 --- a/substrate/primitives/maybe-compressed-blob/README.md +++ b/substrate/primitives/maybe-compressed-blob/README.md @@ -1,3 +1,3 @@ -Handling of blobs, typicaly validation code, which may be compressed. +Handling of blobs, typically validation code, which may be compressed. License: Apache-2.0 diff --git a/substrate/test-utils/runtime/res/README.md b/substrate/test-utils/runtime/res/README.md index 6d6ae55c346..fdf94fd9d87 100644 --- a/substrate/test-utils/runtime/res/README.md +++ b/substrate/test-utils/runtime/res/README.md @@ -20,5 +20,5 @@ comparing keys, not the values. `renamed_authorities`. -`default_genesis_config_invalid.json` is just an imcomplete copy of +`default_genesis_config_invalid.json` is just an incomplete copy of `default_genesis_config.json` with `babe::authorities` field removed. -- GitLab From 44c7a5eb8c375d77f685abf585961421e5f8b228 Mon Sep 17 00:00:00 2001 From: Bill Laboon Date: Tue, 7 Nov 2023 16:20:36 +0100 Subject: [PATCH 458/633] Fix "slashaed" typo (#2205) # Description This merely fixes a typo in the documentation, replacing the typo "slashaed" with "slashed". Since external entities use the comments for explanations of events, this will then be shown externally. I noticed this when reviewing [this event](https://polkadot.subscan.io/extrinsic/0xb6bc1e3abde0c2ed9c500c74cfc64cdb8179e5d9af97f4bf53242ce4cdd15a1d?event=18064194-6) on Subscan. This is not related to any other issues or PRs. --- substrate/frame/referenda/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index be21375f526..8912f9ad217 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -305,7 +305,7 @@ pub mod pallet { /// The amount placed by the account. amount: BalanceOf, }, - /// A deposit has been slashaed. + /// A deposit has been slashed. DepositSlashed { /// The account who placed the deposit. who: T::AccountId, -- GitLab From 8ebb5c3319fa52d68f2d76f90f5787a96de254be Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 7 Nov 2023 17:21:24 +0100 Subject: [PATCH 459/633] Disable incoming light-client connections for minimal relay node (#2202) When running with `--relay-chain-rpc-url` we received multiple reports of high traffic that disappears when `--in-peers-light 0` is set. Indeed it does not make much sense for light clients to connect to the minimal node since it is not running the block announce protocol and the request/response protocol for light clients. This is intended to alleviate the traffic issues for now. closes #1896 probably related https://github.com/paritytech/cumulus/issues/2563 --- .../relay-chain-minimal-node/src/network.rs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index f39d7a26dd8..813dca47a03 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -19,7 +19,8 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; use sc_network::{ config::{ - NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, + ProtocolId, SetConfig, }, peer_store::PeerStore, NetworkService, @@ -35,7 +36,7 @@ use std::{iter, sync::Arc}; /// Build the network service, the network status sinks and an RPC sender. pub(crate) fn build_collator_network( config: &Configuration, - network_config: FullNetworkConfiguration, + mut full_network_config: FullNetworkConfiguration, spawn_handle: SpawnTaskHandle, genesis_hash: Hash, best_header: Header, @@ -53,8 +54,12 @@ pub(crate) fn build_collator_network( genesis_hash, ); + // Since this node has no syncing, we do not want light-clients to connect to it. + // Here we set any potential light-client slots to 0. + adjust_network_config_light_in_peers(&mut full_network_config.network_config); + let peer_store = PeerStore::new( - network_config + full_network_config .network_config .boot_nodes .iter() @@ -75,7 +80,7 @@ pub(crate) fn build_collator_network( }) }, fork_id: None, - network_config, + network_config: full_network_config, peer_store: peer_store_handle, genesis_hash, protocol_id, @@ -114,6 +119,18 @@ pub(crate) fn build_collator_network( Ok((network_service, network_starter, Box::new(SyncOracle {}))) } +fn adjust_network_config_light_in_peers(config: &mut NetworkConfiguration) { + let light_client_in_peers = (config.default_peers_set.in_peers + + config.default_peers_set.out_peers) + .saturating_sub(config.default_peers_set_num_full); + if light_client_in_peers > 0 { + tracing::debug!(target: crate::LOG_TARGET, "Detected {light_client_in_peers} peer slots for light clients. Since this minimal node does support\ + neither syncing nor light-client request/response, we are setting them to 0."); + } + config.default_peers_set.in_peers = + config.default_peers_set.in_peers.saturating_sub(light_client_in_peers); +} + struct SyncOracle; impl sp_consensus::SyncOracle for SyncOracle { -- GitLab From 0524aa51d3b253dd94a60a026c7b7c5a850bf297 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 8 Nov 2023 06:39:40 +0100 Subject: [PATCH 460/633] XCM builder pattern (#2107) Added a proc macro to be able to write XCMs using the builder pattern. This means we go from having to do this: ```rust let message: Xcm<()> = Xcm(vec![ WithdrawAsset(assets), BuyExecution { fees: asset, weight_limit: Unlimited }, DepositAsset { assets, beneficiary }, ]); ``` to this: ```rust let message: Xcm<()> = Xcm::builder() .withdraw_asset(assets) .buy_execution(asset, Unlimited), .deposit_asset(assets, beneficiary) .build(); ``` --------- Co-authored-by: Keith Yeung Co-authored-by: command-bot <> --- Cargo.lock | 1 + polkadot/xcm/procedural/Cargo.toml | 5 + .../xcm/procedural/src/builder_pattern.rs | 115 ++++++++++++++++++ polkadot/xcm/procedural/src/lib.rs | 13 ++ polkadot/xcm/procedural/tests/ui.rs | 32 +++++ .../procedural/tests/ui/builder_pattern.rs | 25 ++++ .../tests/ui/builder_pattern.stderr | 5 + polkadot/xcm/src/v3/mod.rs | 9 +- polkadot/xcm/xcm-simulator/example/src/lib.rs | 19 +++ prdoc/pr_2107.prdoc | 24 ++++ 10 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 polkadot/xcm/procedural/src/builder_pattern.rs create mode 100644 polkadot/xcm/procedural/tests/ui.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern.rs create mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern.stderr create mode 100644 prdoc/pr_2107.prdoc diff --git a/Cargo.lock b/Cargo.lock index 764d4ed01aa..70b0d43120f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21176,6 +21176,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.38", + "trybuild", ] [[package]] diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 56df0d94f58..33c2a94be0e 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "xcm-procedural" +description = "Procedural macros for XCM" authors.workspace = true edition.workspace = true license.workspace = true version = "1.0.0" +publish = true [lib] proc-macro = true @@ -13,3 +15,6 @@ proc-macro2 = "1.0.56" quote = "1.0.28" syn = "2.0.38" Inflector = "0.11.4" + +[dev-dependencies] +trybuild = { version = "1.0.74", features = ["diff"] } diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs new file mode 100644 index 00000000000..ebad54e972b --- /dev/null +++ b/polkadot/xcm/procedural/src/builder_pattern.rs @@ -0,0 +1,115 @@ +// 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 . + +//! Derive macro for creating XCMs with a builder pattern + +use inflector::Inflector; +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use syn::{ + parse_macro_input, Data, DeriveInput, Error, Expr, ExprLit, Fields, Lit, Meta, MetaNameValue, +}; + +pub fn derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let builder_impl = match &input.data { + Data::Enum(data_enum) => generate_methods_for_enum(input.ident, data_enum), + _ => + return Error::new_spanned(&input, "Expected the `Instruction` enum") + .to_compile_error() + .into(), + }; + let output = quote! { + pub struct XcmBuilder(Vec>); + impl Xcm { + pub fn builder() -> XcmBuilder { + XcmBuilder::(Vec::new()) + } + } + #builder_impl + }; + output.into() +} + +fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> TokenStream2 { + let methods = data_enum.variants.iter().map(|variant| { + let variant_name = &variant.ident; + let method_name_string = &variant_name.to_string().to_snake_case(); + let method_name = syn::Ident::new(&method_name_string, variant_name.span()); + let docs: Vec<_> = variant + .attrs + .iter() + .filter_map(|attr| match &attr.meta { + Meta::NameValue(MetaNameValue { + value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }), + .. + }) if attr.path().is_ident("doc") => Some(literal.value()), + _ => None, + }) + .map(|doc| syn::parse_str::(&format!("/// {}", doc)).unwrap()) + .collect(); + let method = match &variant.fields { + Fields::Unit => { + quote! { + pub fn #method_name(mut self) -> Self { + self.0.push(#name::::#variant_name); + self + } + } + }, + Fields::Unnamed(fields) => { + let arg_names: Vec<_> = fields + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("arg{}", index)) + .collect(); + let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); + quote! { + pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self { + self.0.push(#name::::#variant_name(#(#arg_names),*)); + self + } + } + }, + Fields::Named(fields) => { + let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); + let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); + quote! { + pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self { + self.0.push(#name::::#variant_name { #(#arg_names),* }); + self + } + } + }, + }; + quote! { + #(#docs)* + #method + } + }); + let output = quote! { + impl XcmBuilder { + #(#methods)* + + pub fn build(self) -> Xcm { + Xcm(self.0) + } + } + }; + output +} diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs index 2ebccadf50b..83cc6cdf98f 100644 --- a/polkadot/xcm/procedural/src/lib.rs +++ b/polkadot/xcm/procedural/src/lib.rs @@ -18,6 +18,7 @@ use proc_macro::TokenStream; +mod builder_pattern; mod v2; mod v3; mod weight_info; @@ -47,3 +48,15 @@ pub fn impl_conversion_functions_for_junctions_v3(input: TokenStream) -> TokenSt .unwrap_or_else(syn::Error::into_compile_error) .into() } + +/// This is called on the `Instruction` enum, not on the `Xcm` struct, +/// and allows for the following syntax for building XCMs: +/// let message = Xcm::builder() +/// .withdraw_asset(assets) +/// .buy_execution(fees, weight_limit) +/// .deposit_asset(assets, beneficiary) +/// .build(); +#[proc_macro_derive(Builder)] +pub fn derive_builder(input: TokenStream) -> TokenStream { + builder_pattern::derive(input) +} diff --git a/polkadot/xcm/procedural/tests/ui.rs b/polkadot/xcm/procedural/tests/ui.rs new file mode 100644 index 00000000000..a6ec35d0862 --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui.rs @@ -0,0 +1,32 @@ +// 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 . + +//! UI tests for XCM procedural macros + +#[cfg(not(feature = "disable-ui-tests"))] +#[test] +fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return; + } + + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("SKIP_WASM_BUILD", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern.rs new file mode 100644 index 00000000000..e4bcda572ad --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern.rs @@ -0,0 +1,25 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test error when attaching the derive builder macro to something +//! other than the XCM `Instruction` enum. + +use xcm_procedural::Builder; + +#[derive(Builder)] +struct SomeStruct; + +fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern.stderr new file mode 100644 index 00000000000..439b40f31ca --- /dev/null +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern.stderr @@ -0,0 +1,5 @@ +error: Expected the `Instruction` enum + --> tests/ui/builder_pattern.rs:23:1 + | +23 | struct SomeStruct; + | ^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index aa5bfe169ac..7ec3f6f40af 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -404,7 +404,14 @@ impl XcmContext { /// /// This is the inner XCM format and is version-sensitive. Messages are typically passed using the /// outer XCM format, known as `VersionedXcm`. -#[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)] +#[derive( + Derivative, + Encode, + Decode, + TypeInfo, + xcm_procedural::XcmWeightInfoTrait, + xcm_procedural::Builder, +)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] #[codec(decode_bound())] diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index 85b8ad1c5cb..03e7c19a914 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -649,4 +649,23 @@ mod tests { ); }); } + + #[test] + fn builder_pattern_works() { + let asset: MultiAsset = (Here, 100u128).into(); + let beneficiary: MultiLocation = AccountId32 { id: [0u8; 32], network: None }.into(); + let message: Xcm<()> = Xcm::builder() + .withdraw_asset(asset.clone().into()) + .buy_execution(asset.clone(), Unlimited) + .deposit_asset(asset.clone().into(), beneficiary) + .build(); + assert_eq!( + message, + Xcm(vec![ + WithdrawAsset(asset.clone().into()), + BuyExecution { fees: asset.clone(), weight_limit: Unlimited }, + DepositAsset { assets: asset.into(), beneficiary }, + ]) + ); + } } diff --git a/prdoc/pr_2107.prdoc b/prdoc/pr_2107.prdoc new file mode 100644 index 00000000000..0e33680555a --- /dev/null +++ b/prdoc/pr_2107.prdoc @@ -0,0 +1,24 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Add a builder pattern to create XCM programs + +doc: + - audience: Core Dev + description: | + XCMs can now be built using a builder pattern like so: + Xcm::builder() + .withdraw_asset(assets) + .buy_execution(fees, weight_limit) + .deposit_asset(assets, beneficiary) + .build(); + +migrations: + db: [] + + runtime: [] + +crates: + - name: xcm + +host_functions: [] -- GitLab From 2e2a75ff81907975e990202378a0adc93ce02fd3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 8 Nov 2023 11:40:57 +0200 Subject: [PATCH 461/633] [testnets][xcm-emulator] add bridge-hub-westend and hook it up to emulator (#2204) `bridge-hub-westend-runtime` was added to cumulus/parachains, but wasn't hooked up to xcm-emulator to run tests against it. This commit addresses that ^. Signed-off-by: Adrian Catangiu --- Cargo.lock | 30 ++++++++ Cargo.toml | 1 + .../bridges/bridge-hub-westend/Cargo.toml | 41 ++++++++++ .../bridges/bridge-hub-westend/src/lib.rs | 67 +++++++++++++++++ .../bridge-hub-westend/src/tests/example.rs | 74 +++++++++++++++++++ .../bridge-hub-westend/src/tests/mod.rs | 17 +++++ .../bridge-hub-westend/src/tests/teleport.rs | 30 ++++++++ .../emulated/common/Cargo.toml | 2 + .../emulated/common/src/constants.rs | 57 ++++++++++++++ .../emulated/common/src/lib.rs | 27 ++++++- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- 11 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs create mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs diff --git a/Cargo.lock b/Cargo.lock index 70b0d43120f..06ab9ed7e2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2298,6 +2298,35 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "bridge-hub-westend-integration-tests" +version = "1.0.0" +dependencies = [ + "asset-test-utils", + "bp-messages", + "bridge-hub-westend-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-xcmp-queue", + "frame-support", + "frame-system", + "integration-tests-common", + "pallet-assets", + "pallet-balances", + "pallet-bridge-messages", + "pallet-message-queue", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-parachains", + "sp-core", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", + "xcm-emulator", +] + [[package]] name = "bridge-hub-westend-runtime" version = "0.1.0" @@ -6717,6 +6746,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", + "bridge-hub-westend-runtime", "bridge-runtime-common", "collectives-polkadot-runtime", "cumulus-pallet-parachain-system", diff --git a/Cargo.toml b/Cargo.toml index ccb952cc963..2344a24a5d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ members = [ "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/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/common", "cumulus/parachains/pallets/collective-content", "cumulus/parachains/pallets/parachain-info", diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml new file mode 100644 index 00000000000..af5408b888b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "bridge-hub-westend-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Westend runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +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-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} +pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} +pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} +pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", 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" } +xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} +pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} + +# Cumulus +asset-test-utils = { path = "../../../../../parachains/runtimes/assets/test-utils", default-features = false } +parachains-common = { path = "../../../../common" } +cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} +pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} +bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} +bridge-hub-westend-runtime = { path = "../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } + +# 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/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs new file mode 100644 index 00000000000..8b17ce53eb0 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs @@ -0,0 +1,67 @@ +// 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 bp_messages::LaneId; +pub use frame_support::assert_ok; +pub use integration_tests_common::{ + constants::{ + bridge_hub_westend::ED as BRIDGE_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}, + AssetHubRococo, AssetHubWestend, AssetHubWestendReceiver, BridgeHubRococo, BridgeHubWestend, + BridgeHubWestendPallet, BridgeHubWestendSender, PenpalWestendA, Westend, WestendPallet, +}; +pub use parachains_common::{AccountId, Balance}; +pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3::{ + Error, + NetworkId::{Rococo as RococoId, Westend as WestendId}, + }, +}; +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; +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: Westend::child_location_of(AssetHubWestend::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubWestendReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs new file mode 100644 index 00000000000..e15a0dedab9 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs @@ -0,0 +1,74 @@ +// 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 example() { + // Init tests variables + // XcmPallet send arguments + let sudo_origin = ::RuntimeOrigin::root(); + let destination = Westend::child_location_of(BridgeHubWestend::para_id()).into(); + let weight_limit = WeightLimit::Unlimited; + let check_origin = None; + + let remote_xcm = Xcm(vec![ClearOrigin]); + + let xcm = VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit, check_origin }, + ExportMessage { + network: RococoId, + destination: X1(Parachain(AssetHubRococo::para_id().into())), + xcm: remote_xcm, + }, + ])); + + // Westend Global Consensus + // Send XCM message from Relay Chain to Bridge Hub source Parachain + Westend::execute_with(|| { + assert_ok!(::XcmPallet::send( + sudo_origin, + bx!(destination), + bx!(xcm), + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + // Receive XCM message in Bridge Hub source Parachain + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: true, + .. + }) => {}, + RuntimeEvent::BridgeRococoMessages(pallet_bridge_messages::Event::MessageAccepted { + lane_id: LaneId([0, 0, 0, 2]), + nonce: 1, + }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs new file mode 100644 index 00000000000..1eef05c6b92 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs @@ -0,0 +1,17 @@ +// 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. + +mod example; +mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs new file mode 100644 index 00000000000..8dff6c29295 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs @@ -0,0 +1,30 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::*; +use bridge_hub_westend_runtime::xcm_config::XcmConfig; + +#[test] +fn teleport_to_other_system_parachains_works() { + let amount = BRIDGE_HUB_WESTEND_ED * 100; + let native_asset: MultiAssets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + BridgeHubWestend, // Origin + XcmConfig, // XCM configuration + vec![AssetHubWestend], // Destinations + (native_asset, amount) + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 6688c80eb9a..16a37e94be5 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -52,6 +52,7 @@ collectives-polkadot-runtime = { path = "../../../runtimes/collectives/collectiv bridge-hub-kusama-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-kusama" } bridge-hub-polkadot-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-polkadot" } bridge-hub-rococo-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-rococo" } +bridge-hub-westend-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-westend" } xcm-emulator = { default-features = false, path = "../../../../xcm/xcm-emulator" } cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../pallets/xcmp-queue" } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } @@ -68,6 +69,7 @@ runtime-benchmarks = [ "bridge-hub-kusama-runtime/runtime-benchmarks", "bridge-hub-polkadot-runtime/runtime-benchmarks", "bridge-hub-rococo-runtime/runtime-benchmarks", + "bridge-hub-westend-runtime/runtime-benchmarks", "bridge-runtime-common/runtime-benchmarks", "collectives-polkadot-runtime/runtime-benchmarks", "cumulus-pallet-parachain-system/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 86027229c59..1dffbccbba3 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -1160,3 +1160,60 @@ pub mod bridge_hub_rococo { } } } + +// Bridge Hub Westend +pub mod bridge_hub_westend { + use super::*; + pub const PARA_ID: u32 = 1013; + pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = serde_json::json!({ + "balances": { + "balances": accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect::>(), + }, + "parachainInfo": { + "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), + }, + "collatorSelection": { + "invulnerables": collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect::>(), + "candidacyBond": ED * 16, + }, + "session": { + "keys": collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect::>(), + }, + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + }, + "bridgeRococoGrandpa": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), + }, + "bridgeRococoMessages": { + "owner": Some(get_account_id_from_seed::(accounts::BOB)), + } + }); + + build_genesis_storage( + genesis_config, + bridge_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) + } +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 2cb90650b94..1debd50d609 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -20,8 +20,8 @@ pub mod xcm_helpers; use constants::{ accounts::{ALICE, BOB}, - asset_hub_rococo, asset_hub_westend, asset_hub_wococo, bridge_hub_rococo, penpal, rococo, - westend, + asset_hub_rococo, asset_hub_westend, asset_hub_wococo, bridge_hub_rococo, bridge_hub_westend, + penpal, rococo, westend, }; use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; pub use paste; @@ -118,6 +118,23 @@ decl_test_parachains! { AssetConversion: asset_hub_westend_runtime::AssetConversion, } }, + pub struct BridgeHubWestend { + genesis = bridge_hub_westend::genesis(), + on_init = { + bridge_hub_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = bridge_hub_westend_runtime, + core = { + XcmpMessageHandler: bridge_hub_westend_runtime::XcmpQueue, + LocationToAccountId: bridge_hub_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: bridge_hub_westend_runtime::ParachainInfo, + MessageProcessor: DefaultParaMessageProcessor, + }, + pallets = { + PolkadotXcm: bridge_hub_westend_runtime::PolkadotXcm, + Balances: bridge_hub_westend_runtime::Balances, + } + }, pub struct PenpalWestendA { genesis = penpal::genesis(penpal::PARA_ID_A), on_init = { @@ -257,6 +274,7 @@ decl_test_networks! { relay_chain = Westend, parachains = vec![ AssetHubWestend, + BridgeHubWestend, PenpalWestendA, ], bridge = () @@ -323,6 +341,10 @@ impl_assert_events_helpers_for_parachain!(AssetHubRococo); // PenpalWestendA implementation impl_assert_events_helpers_for_parachain!(PenpalWestendA); +// BridgeHubWestend implementation +impl_accounts_helpers_for_parachain!(BridgeHubWestend); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend); + // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo); @@ -343,6 +365,7 @@ decl_test_sender_receiver_accounts_parameter_types! { // Bridged Hubs BridgeHubRococo { sender: ALICE, receiver: BOB }, BridgeHubWococo { sender: ALICE, receiver: BOB }, + BridgeHubWestend { sender: ALICE, receiver: BOB }, // Penpals PenpalWestendA { sender: ALICE, receiver: BOB }, PenpalRococoA { sender: ALICE, receiver: BOB }, 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 76ff63db4da..671d38e808f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -29,6 +29,7 @@ pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false} pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false} pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false} @@ -62,7 +63,6 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} -- GitLab From 640e385aec02ee8b80284febe679ce785ade66b9 Mon Sep 17 00:00:00 2001 From: benluelo <57334811+benluelo@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:51:40 +0000 Subject: [PATCH 462/633] feat(frame-support-procedural): add `automaticaly_derived` attr to `NoBound` derives (#2197) fixes #2196 --- substrate/frame/support/procedural/src/no_bound/clone.rs | 1 + substrate/frame/support/procedural/src/no_bound/debug.rs | 1 + substrate/frame/support/procedural/src/no_bound/default.rs | 1 + substrate/frame/support/procedural/src/no_bound/partial_eq.rs | 1 + substrate/frame/support/test/tests/derive_no_bound.rs | 3 +++ 5 files changed, 7 insertions(+) diff --git a/substrate/frame/support/procedural/src/no_bound/clone.rs b/substrate/frame/support/procedural/src/no_bound/clone.rs index 2c9037984f5..8e57a10d34c 100644 --- a/substrate/frame/support/procedural/src/no_bound/clone.rs +++ b/substrate/frame/support/procedural/src/no_bound/clone.rs @@ -98,6 +98,7 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke quote::quote!( const _: () = { + #[automatically_derived] 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 88f5dfe7bec..dd14b9cd564 100644 --- a/substrate/frame/support/procedural/src/no_bound/debug.rs +++ b/substrate/frame/support/procedural/src/no_bound/debug.rs @@ -112,6 +112,7 @@ pub fn derive_debug_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke quote::quote!( const _: () = { + #[automatically_derived] 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 ddaab26c441..0524247d24e 100644 --- a/substrate/frame/support/procedural/src/no_bound/default.rs +++ b/substrate/frame/support/procedural/src/no_bound/default.rs @@ -149,6 +149,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To quote!( const _: () = { + #[automatically_derived] 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 1a4a4e50b39..7cf5701b193 100644 --- a/substrate/frame/support/procedural/src/no_bound/partial_eq.rs +++ b/substrate/frame/support/procedural/src/no_bound/partial_eq.rs @@ -128,6 +128,7 @@ pub fn derive_partial_eq_no_bound(input: proc_macro::TokenStream) -> proc_macro: quote::quote!( const _: () = { + #[automatically_derived] 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/test/tests/derive_no_bound.rs b/substrate/frame/support/test/tests/derive_no_bound.rs index dc78027f22e..af2633dc53c 100644 --- a/substrate/frame/support/test/tests/derive_no_bound.rs +++ b/substrate/frame/support/test/tests/derive_no_bound.rs @@ -136,6 +136,7 @@ struct StructNoGenerics { field2: u64, } +#[allow(dead_code)] #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum EnumNoGenerics { #[default] @@ -162,6 +163,7 @@ enum Enum { } // enum that will have a named default. +#[allow(dead_code)] #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum Enum2 { #[default] @@ -175,6 +177,7 @@ enum Enum2 { VariantUnit2, } +#[allow(dead_code)] // enum that will have a unit default. #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum Enum3 { -- GitLab From 9adb46c868ab408a97077dc967143e178b2b48e8 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 8 Nov 2023 12:59:55 +0100 Subject: [PATCH 463/633] Add `sudo::remove_key` (#2165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Adds a new call `remove_key` to the sudo pallet to permanently remove the sudo key. - Remove some clones and general maintenance --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- .../runtime/rococo/src/weights/pallet_sudo.rs | 55 ++++++---- .../westend/src/weights/pallet_sudo.rs | 58 +++++----- prdoc/pr_2165.prdoc | 17 +++ substrate/frame/sudo/src/benchmarking.rs | 44 +++++--- substrate/frame/sudo/src/lib.rs | 92 ++++++++-------- substrate/frame/sudo/src/mock.rs | 4 +- substrate/frame/sudo/src/tests.rs | 28 ++--- substrate/frame/sudo/src/weights.rs | 102 +++++++++++------- 8 files changed, 240 insertions(+), 160 deletions(-) create mode 100644 prdoc/pr_2165.prdoc diff --git a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs index 83215af5b8a..694174954fc 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs @@ -17,24 +17,25 @@ //! Autogenerated weights for `pallet_sudo` //! //! 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-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --pallet=pallet_sudo // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_sudo +// --chain=rococo-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,38 +48,50 @@ use core::marker::PhantomData; /// Weight functions for `pallet_sudo`. pub struct WeightInfo(PhantomData); impl pallet_sudo::WeightInfo for WeightInfo { - /// Storage: Sudo Key (r:1 w:1) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 13_047_000 picoseconds. - Weight::from_parts(13_325_000, 0) + // Minimum execution time: 8_432_000 picoseconds. + Weight::from_parts(8_757_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 13_250_000 picoseconds. - Weight::from_parts(13_544_000, 0) + // Minimum execution time: 9_167_000 picoseconds. + Weight::from_parts(9_397_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 13_424_000 picoseconds. - Weight::from_parts(13_801_000, 0) + // Minimum execution time: 9_133_000 picoseconds. + Weight::from_parts(9_573_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `132` + // Estimated: `1517` + // Minimum execution time: 7_374_000 picoseconds. + Weight::from_parts(7_702_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_sudo.rs b/polkadot/runtime/westend/src/weights/pallet_sudo.rs index 8a220173ee5..e9ab3ad37a4 100644 --- a/polkadot/runtime/westend/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/westend/src/weights/pallet_sudo.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_sudo` //! //! 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-11-07, 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-yprdrvc7-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_sudo // --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_sudo +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,38 +48,50 @@ use core::marker::PhantomData; /// Weight functions for `pallet_sudo`. pub struct WeightInfo(PhantomData); impl pallet_sudo::WeightInfo for WeightInfo { - /// Storage: Sudo Key (r:1 w:1) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 12_360_000 picoseconds. - Weight::from_parts(12_803_000, 0) + // Minimum execution time: 8_750_000 picoseconds. + Weight::from_parts(9_102_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 12_158_000 picoseconds. - Weight::from_parts(12_506_000, 0) + // Minimum execution time: 9_607_000 picoseconds. + Weight::from_parts(10_139_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 12_286_000 picoseconds. - Weight::from_parts(12_664_000, 0) + // Minimum execution time: 9_886_000 picoseconds. + Weight::from_parts(10_175_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `132` + // Estimated: `1517` + // Minimum execution time: 7_843_000 picoseconds. + Weight::from_parts(8_152_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/prdoc/pr_2165.prdoc b/prdoc/pr_2165.prdoc new file mode 100644 index 00000000000..31cb691c43a --- /dev/null +++ b/prdoc/pr_2165.prdoc @@ -0,0 +1,17 @@ +title: Add sudo::remove_key + +doc: + - audience: Core Dev + description: | + Pallet `Sudo` now has the ability to remove the sudo key via `remove_key`. This is a less-invasive way of rendering the sudo pallet useless without needing a code upgrade. + +migrations: + db: [] + + runtime: [] + +crates: + - name: pallet-sudo + semver: minor + +host_functions: [] diff --git a/substrate/frame/sudo/src/benchmarking.rs b/substrate/frame/sudo/src/benchmarking.rs index 6a365c1873c..e64233fe748 100644 --- a/substrate/frame/sudo/src/benchmarking.rs +++ b/substrate/frame/sudo/src/benchmarking.rs @@ -22,41 +22,40 @@ use crate::Pallet; use frame_benchmarking::v2::*; use frame_system::RawOrigin; -const SEED: u32 = 0; - -fn assert_last_event(generic_event: ::RuntimeEvent) { - frame_system::Pallet::::assert_last_event(generic_event.into()); +fn assert_last_event(generic_event: crate::Event) { + let re: ::RuntimeEvent = generic_event.into(); + frame_system::Pallet::::assert_last_event(re.into()); } -#[benchmarks( where ::RuntimeCall: From>)] +#[benchmarks(where ::RuntimeCall: From>)] mod benchmarks { use super::*; #[benchmark] fn set_key() { let caller: T::AccountId = whitelisted_caller(); - Key::::put(caller.clone()); + Key::::put(&caller); - let new_sudoer: T::AccountId = account("sudoer", 0, SEED); + let new_sudoer: T::AccountId = account("sudoer", 0, 0); let new_sudoer_lookup = T::Lookup::unlookup(new_sudoer.clone()); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), new_sudoer_lookup); - assert_last_event::(Event::KeyChanged { old_sudoer: Some(caller) }.into()); + assert_last_event::(Event::KeyChanged { old: Some(caller), new: new_sudoer }); } #[benchmark] fn sudo() { let caller: T::AccountId = whitelisted_caller(); - Key::::put(caller.clone()); + Key::::put(&caller); - let call: ::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + let call = frame_system::Call::remark { remark: vec![] }.into(); #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), Box::new(call.clone())); + _(RawOrigin::Signed(caller), Box::new(call)); - assert_last_event::(Event::Sudid { sudo_result: Ok(()) }.into()) + assert_last_event::(Event::Sudid { sudo_result: Ok(()) }) } #[benchmark] @@ -64,15 +63,26 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); Key::::put(caller.clone()); - let call: ::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + let call = frame_system::Call::remark { remark: vec![] }.into(); + + let who: T::AccountId = account("as", 0, 0); + let who_lookup = T::Lookup::unlookup(who); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), who_lookup, Box::new(call)); + + assert_last_event::(Event::SudoAsDone { sudo_result: Ok(()) }) + } - let who: T::AccountId = account("as", 0, SEED); - let who_lookup = T::Lookup::unlookup(who.clone()); + #[benchmark] + fn remove_key() { + let caller: T::AccountId = whitelisted_caller(); + Key::::put(&caller); #[extrinsic_call] - _(RawOrigin::Signed(caller), who_lookup, Box::new(call.clone())); + _(RawOrigin::Signed(caller.clone())); - assert_last_event::(Event::SudoAsDone { sudo_result: Ok(()) }.into()) + assert_last_event::(Event::KeyRemoved {}); } impl_benchmark_test_suite!(Pallet, crate::mock::new_bench_ext(), crate::mock::Test); diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 36de44d9d72..d556c5eb6ae 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -146,7 +146,7 @@ type AccountIdLookupOf = <::Lookup as StaticLookup pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; + use frame_system::{pallet_prelude::*, RawOrigin}; /// Default preludes for [`Config`]. pub mod config_preludes { @@ -190,11 +190,6 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Authenticates the sudo key and dispatches a function call with `Root` origin. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// ## Complexity - /// - O(1). #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); @@ -207,12 +202,11 @@ pub mod pallet { origin: OriginFor, call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - // This is a public call, so we ensure that the origin is some signed account. - let sender = ensure_signed(origin)?; - ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); + Self::ensure_sudo(origin)?; - let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); + let res = call.dispatch_bypass_filter(RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) }); + // Sudo user does not pay a fee. Ok(Pays::No.into()) } @@ -222,9 +216,6 @@ pub mod pallet { /// Sudo user to specify the weight of the call. /// /// The dispatch origin for this call must be _Signed_. - /// - /// ## Complexity - /// - O(1). #[pallet::call_index(1)] #[pallet::weight((*weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( @@ -232,37 +223,30 @@ pub mod pallet { call: Box<::RuntimeCall>, weight: Weight, ) -> DispatchResultWithPostInfo { - // This is a public call, so we ensure that the origin is some signed account. - let sender = ensure_signed(origin)?; + Self::ensure_sudo(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()); + let res = call.dispatch_bypass_filter(RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) }); + // Sudo user does not pay a fee. Ok(Pays::No.into()) } /// Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo /// key. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// ## Complexity - /// - O(1). #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::set_key())] pub fn set_key( origin: OriginFor, new: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { - // This is a public call, so we ensure that the origin is some signed account. - let sender = ensure_signed(origin)?; - ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); + Self::ensure_sudo(origin)?; + let new = T::Lookup::lookup(new)?; + Self::deposit_event(Event::KeyChanged { old: Key::::get(), new: new.clone() }); + Key::::put(new); - Self::deposit_event(Event::KeyChanged { old_sudoer: Key::::get() }); - Key::::put(&new); // Sudo user does not pay a fee. Ok(Pays::No.into()) } @@ -271,9 +255,6 @@ pub mod pallet { /// a given account. /// /// The dispatch origin for this call must be _Signed_. - /// - /// ## Complexity - /// - O(1). #[pallet::call_index(3)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); @@ -287,17 +268,29 @@ pub mod pallet { who: AccountIdLookupOf, call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - // This is a public call, so we ensure that the origin is some signed account. - let sender = ensure_signed(origin)?; - ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); + Self::ensure_sudo(origin)?; let who = T::Lookup::lookup(who)?; - - let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Signed(who).into()); - + let res = call.dispatch_bypass_filter(RawOrigin::Signed(who).into()); Self::deposit_event(Event::SudoAsDone { sudo_result: res.map(|_| ()).map_err(|e| e.error), }); + + // Sudo user does not pay a fee. + Ok(Pays::No.into()) + } + + /// Permanently removes the sudo key. + /// + /// **This cannot be un-done.** + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::remove_key())] + pub fn remove_key(origin: OriginFor) -> DispatchResultWithPostInfo { + Self::ensure_sudo(origin)?; + + Self::deposit_event(Event::KeyRemoved {}); + Key::::kill(); + // Sudo user does not pay a fee. Ok(Pays::No.into()) } @@ -313,9 +306,13 @@ pub mod pallet { }, /// The sudo key has been updated. KeyChanged { - /// The old sudo key if one was previously set. - old_sudoer: Option, + /// The old sudo key (if one was previously set). + old: Option, + /// The new sudo key (if one was set). + new: T::AccountId, }, + /// The key was permanently removed. + KeyRemoved, /// A [sudo_as](Pallet::sudo_as) call just took place. SudoAsDone { /// The result of the call made by the sudo user. @@ -324,9 +321,9 @@ pub mod pallet { } #[pallet::error] - /// Error for the Sudo pallet + /// Error for the Sudo pallet. pub enum Error { - /// Sender must be the Sudo account + /// Sender must be the Sudo account. RequireSudo, } @@ -345,8 +342,19 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { - if let Some(ref key) = self.key { - Key::::put(key); + Key::::set(self.key.clone()); + } + } + + impl Pallet { + /// Ensure that the caller is the sudo key. + pub(crate) fn ensure_sudo(origin: OriginFor) -> DispatchResult { + let sender = ensure_signed(origin)?; + + if Self::key().map_or(false, |k| k == sender) { + Ok(()) + } else { + Err(Error::::RequireSudo.into()) } } } diff --git a/substrate/frame/sudo/src/mock.rs b/substrate/frame/sudo/src/mock.rs index 427bda6d99e..6f123b7c82b 100644 --- a/substrate/frame/sudo/src/mock.rs +++ b/substrate/frame/sudo/src/mock.rs @@ -156,7 +156,9 @@ pub fn new_test_ext(root_key: u64) -> sp_io::TestExternalities { sudo::GenesisConfig:: { key: Some(root_key) } .assimilate_storage(&mut t) .unwrap(); - t.into() + let mut ext: sp_io::TestExternalities = t.into(); + ext.execute_with(|| System::set_block_number(1)); + ext } #[cfg(feature = "runtime-benchmarks")] diff --git a/substrate/frame/sudo/src/tests.rs b/substrate/frame/sudo/src/tests.rs index 6963ba2e6a0..13dc069ddef 100644 --- a/substrate/frame/sudo/src/tests.rs +++ b/substrate/frame/sudo/src/tests.rs @@ -59,9 +59,6 @@ fn sudo_basics() { #[test] fn sudo_emits_events_correctly() { new_test_ext(1).execute_with(|| { - // Set block number to 1 because events are not emitted on block 0. - System::set_block_number(1); - // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, @@ -118,9 +115,6 @@ fn sudo_unchecked_weight_basics() { #[test] fn sudo_unchecked_weight_emits_events_correctly() { new_test_ext(1).execute_with(|| { - // Set block number to 1 because events are not emitted on block 0. - System::set_block_number(1); - // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, @@ -154,15 +148,24 @@ fn set_key_basics() { #[test] fn set_key_emits_events_correctly() { new_test_ext(1).execute_with(|| { - // Set block number to 1 because events are not emitted on block 0. - System::set_block_number(1); - // A root `key` can change the root `key`. assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); - System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(1) })); + System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old: Some(1), new: 2 })); // Double check. assert_ok!(Sudo::set_key(RuntimeOrigin::signed(2), 4)); - System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(2) })); + System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old: Some(2), new: 4 })); + }); +} + +#[test] +fn remove_key_works() { + new_test_ext(1).execute_with(|| { + assert_ok!(Sudo::remove_key(RuntimeOrigin::signed(1))); + assert!(Sudo::key().is_none()); + System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {})); + + assert_noop!(Sudo::remove_key(RuntimeOrigin::signed(1)), Error::::RequireSudo); + assert_noop!(Sudo::set_key(RuntimeOrigin::signed(1), 1), Error::::RequireSudo); }); } @@ -201,9 +204,6 @@ fn sudo_as_basics() { #[test] fn sudo_as_emits_events_correctly() { new_test_ext(1).execute_with(|| { - // Set block number to 1 because events are not emitted on block 0. - System::set_block_number(1); - // A non-privileged function will work when passed to `sudo_as` with the root `key`. let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index 0cdd0c8a81f..10d1a9f7a51 100644 --- a/substrate/frame/sudo/src/weights.rs +++ b/substrate/frame/sudo/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_sudo. +//! Autogenerated weights for `pallet_sudo` //! //! 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-11-07, 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-yprdrvc7-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_sudo -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/sudo/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_sudo +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/sudo/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,80 +47,103 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_sudo. +/// Weight functions needed for `pallet_sudo`. pub trait WeightInfo { fn set_key() -> Weight; fn sudo() -> Weight; fn sudo_as() -> Weight; + fn remove_key() -> Weight; } -/// Weights for pallet_sudo using the Substrate node and recommended hardware. +/// Weights for `pallet_sudo` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Sudo Key (r:1 w:1) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_918_000 picoseconds. - Weight::from_parts(13_403_000, 1517) + // Minimum execution time: 9_600_000 picoseconds. + Weight::from_parts(10_076_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_693_000 picoseconds. - Weight::from_parts(13_001_000, 1517) + // Minimum execution time: 10_453_000 picoseconds. + Weight::from_parts(10_931_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_590_000 picoseconds. - Weight::from_parts(12_994_000, 1517) + // Minimum execution time: 10_202_000 picoseconds. + Weight::from_parts(10_800_000, 1517) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `165` + // Estimated: `1517` + // Minimum execution time: 8_555_000 picoseconds. + Weight::from_parts(8_846_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Sudo Key (r:1 w:1) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_918_000 picoseconds. - Weight::from_parts(13_403_000, 1517) + // Minimum execution time: 9_600_000 picoseconds. + Weight::from_parts(10_076_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_693_000 picoseconds. - Weight::from_parts(13_001_000, 1517) + // Minimum execution time: 10_453_000 picoseconds. + Weight::from_parts(10_931_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Sudo Key (r:1 w:0) - /// Proof: Sudo Key (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 12_590_000 picoseconds. - Weight::from_parts(12_994_000, 1517) + // Minimum execution time: 10_202_000 picoseconds. + Weight::from_parts(10_800_000, 1517) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `165` + // Estimated: `1517` + // Minimum execution time: 8_555_000 picoseconds. + Weight::from_parts(8_846_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } -- GitLab From 9673fbfa32b7f89c687c175470a766317664e847 Mon Sep 17 00:00:00 2001 From: Yuri Volkov <0@mcornholio.ru> Date: Wed, 8 Nov 2023 14:19:13 +0100 Subject: [PATCH 464/633] Adding gitspiegel-trigger workflow (#2135) GitHub has a setting that requires manual click for executing GHA on the branch, for the first-time contributors: https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks. After this PR, gitspiegel will respect that setting. So, for PRs from first-time contributors, gitspiegel won't do mirroring until the button in PR is clicked. More info: https://github.com/paritytech/gitspiegel/issues/169 --- .github/workflows/gitspiegel-trigger.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/gitspiegel-trigger.yml diff --git a/.github/workflows/gitspiegel-trigger.yml b/.github/workflows/gitspiegel-trigger.yml new file mode 100644 index 00000000000..dce3aaf2fec --- /dev/null +++ b/.github/workflows/gitspiegel-trigger.yml @@ -0,0 +1,22 @@ +name: gitspiegel sync + +# This workflow doesn't do anything, it's only use is to trigger "workflow_run" +# webhook, that'll be consumed by gitspiegel +# This way, gitspiegel won't do mirroring, unless this workflow runs, +# and running the workflow is protected by GitHub + +on: + pull_request: + types: + - opened + - synchronize + - unlocked + - ready_for_review + - reopened + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Do nothing + run: echo "let's go" -- GitLab From 1bc08858292b88b6c834fbc9f72d61e692363e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 8 Nov 2023 14:33:19 +0100 Subject: [PATCH 465/633] validate-block: Fix `TrieCache` implementation (#2214) The trie cache implementation was ignoring the `storage_root` when setting up the value cache. The problem with this is that the value cache works using `storage_keys` and these keys are not unique across different tries. A block can actually have different tries (main trie and multiple child tries). This pull request fixes the issue by not ignoring the `storage_root` and returning an unique `value_cache` per `storage_root`. It also adds a test for the seen bug and improves documentation that this doesn't happen again. --- Cargo.lock | 1 + cumulus/pallets/parachain-system/Cargo.toml | 1 + .../src/validate_block/tests.rs | 48 +++++++++++++++++-- .../src/validate_block/trie_cache.rs | 24 +++++++--- cumulus/test/runtime/src/test_pallet.rs | 24 ++++++++++ .../state-machine/src/trie_backend.rs | 5 +- substrate/test-utils/client/src/client_ext.rs | 4 +- substrate/test-utils/client/src/lib.rs | 2 +- 8 files changed, 95 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06ab9ed7e2f..8c7121e235c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3868,6 +3868,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "futures", "hex-literal", "impl-trait-for-tuples", "lazy_static", diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 1c26b3a7486..5600c95a2a6 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -45,6 +45,7 @@ assert_matches = "1.5" hex-literal = "0.4.1" lazy_static = "1.4" rand = "0.8.5" +futures = "0.3.28" # Substrate sc-client-api = { path = "../../../substrate/client/api" } diff --git a/cumulus/pallets/parachain-system/src/validate_block/tests.rs b/cumulus/pallets/parachain-system/src/validate_block/tests.rs index 0cf68f25cc3..f17ac6007a0 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/tests.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/tests.rs @@ -21,12 +21,13 @@ use cumulus_test_client::{ runtime::{ self as test_runtime, Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY, }, - transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData, - InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams, + transfer, BlockData, BlockOrigin, BuildParachainBlockData, Client, ClientBlockImportExt, + DefaultTestClientBuilderExt, HeadData, InitBlockBuilder, TestClientBuilder, + TestClientBuilderExt, ValidationParams, }; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use sp_keyring::AccountKeyring::*; -use sp_runtime::traits::Header as HeaderT; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{env, process::Command}; use crate::validate_block::MemoryOptimizedValidationParams; @@ -100,7 +101,7 @@ fn build_block_with_witness( } #[test] -fn validate_block_no_extra_extrinsics() { +fn validate_block_works() { sp_tracing::try_init_simple(); let (client, parent_head) = create_test_client(); @@ -290,3 +291,42 @@ fn validation_params_and_memory_optimized_validation_params_encode_and_decode() let decoded = ValidationParams::decode_all(&mut &encoded[..]).unwrap(); assert_eq!(decoded, validation_params); } + +/// Test for ensuring that we are differentiating in the `validation::trie_cache` between different +/// child tries. +/// +/// This is achieved by first building a block using `read_and_write_child_tries` that should set +/// the values in the child tries. In the second step we are building a second block with the same +/// extrinsic that reads the values from the child tries and it asserts that we read the correct +/// data from the state. +#[test] +fn validate_block_works_with_child_tries() { + sp_tracing::try_init_simple(); + + let (mut client, parent_head) = create_test_client(); + let TestBlockData { block, .. } = build_block_with_witness( + &client, + vec![generate_extrinsic(&client, Charlie, TestPalletCall::read_and_write_child_tries {})], + parent_head.clone(), + Default::default(), + ); + let block = block.into_block(); + + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + + let parent_head = block.header().clone(); + + let TestBlockData { block, validation_data } = build_block_with_witness( + &client, + vec![generate_extrinsic(&client, Alice, TestPalletCall::read_and_write_child_tries {})], + parent_head.clone(), + Default::default(), + ); + + let header = block.header().clone(); + + let res_header = + call_validate_block(parent_head, block, validation_data.relay_parent_storage_root) + .expect("Calls `validate_block`"); + assert_eq!(header, res_header); +} diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs index 57876b87876..5d785910fbe 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs @@ -67,7 +67,13 @@ impl<'a, H: Hasher> trie_db::TrieCache> for TrieCache<'a, H> { /// Provider of [`TrieCache`] instances. pub(crate) struct CacheProvider { node_cache: RefCell>>, - value_cache: RefCell, trie_db::CachedValue>>, + /// Cache: `storage_root` => `storage_key` => `value`. + /// + /// One `block` can for example use multiple tries (child tries) and we need to distinguish the + /// cached (`storage_key`, `value`) between them. For this we are using the `storage_root` to + /// distinguish them (even if the storage root is the same for two child tries, it just means + /// that both are exactly the same trie and there would happen no collision). + value_cache: RefCell, trie_db::CachedValue>>>, } impl CacheProvider { @@ -81,22 +87,26 @@ impl CacheProvider { impl TrieCacheProvider for CacheProvider { type Cache<'a> = TrieCache<'a, H> where H: 'a; - fn as_trie_db_cache(&self, _storage_root: ::Out) -> Self::Cache<'_> { + fn as_trie_db_cache(&self, storage_root: ::Out) -> Self::Cache<'_> { TrieCache { - value_cache: Some(self.value_cache.borrow_mut()), + value_cache: Some(RefMut::map(self.value_cache.borrow_mut(), |c| { + c.entry(storage_root).or_default() + })), node_cache: self.node_cache.borrow_mut(), } } fn as_trie_db_mut_cache(&self) -> Self::Cache<'_> { // This method is called when we calculate the storage root. - // Since we are using a simplified cache architecture, - // we do not have separate key spaces for different storage roots. - // The value cache is therefore disabled here. + // We are not interested in caching new values (as we would throw them away directly after a + // block is validated) and thus, we don't pass any `value_cache`. TrieCache { value_cache: None, node_cache: self.node_cache.borrow_mut() } } - fn merge<'a>(&'a self, _other: Self::Cache<'a>, _new_root: ::Out) {} + fn merge<'a>(&'a self, _other: Self::Cache<'a>, _new_root: ::Out) { + // This is called to merge the `value_cache` from `as_trie_db_mut_cache`, which is not + // activated, so we don't need to do anything here. + } } // This is safe here since we are single-threaded in WASM diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index a0763c9069c..5d11b7f490c 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -49,6 +49,30 @@ pub mod pallet { ); Ok(()) } + + /// A dispatchable that first reads two values from two different child tries, asserts they + /// are the expected values (if the values exist in the state) and then writes two different + /// values to these child tries. + #[pallet::weight(0)] + pub fn read_and_write_child_tries(_: OriginFor) -> DispatchResult { + let key = &b"hello"[..]; + let first_trie = &b"first"[..]; + let second_trie = &b"second"[..]; + let first_value = "world1".encode(); + let second_value = "world2".encode(); + + if let Some(res) = sp_io::default_child_storage::get(first_trie, key) { + assert_eq!(first_value, res); + } + if let Some(res) = sp_io::default_child_storage::get(second_trie, key) { + assert_eq!(second_value, res); + } + + sp_io::default_child_storage::set(first_trie, key, &first_value); + sp_io::default_child_storage::set(second_trie, key, &second_value); + + Ok(()) + } } #[derive(frame_support::DefaultNoBound)] diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index afa80addd2b..7b337b5fd54 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -52,7 +52,10 @@ pub trait TrieCacheProvider { /// Return a [`trie_db::TrieDB`] compatible cache. /// - /// The `storage_root` parameter should be the storage root of the used trie. + /// The `storage_root` parameter *must* be the storage root of the trie this cache is used for. + /// + /// NOTE: Implementors should use the `storage_root` to differentiate between storage keys that + /// may belong to different tries. fn as_trie_db_cache(&self, storage_root: H::Out) -> Self::Cache<'_>; /// Returns a cache that can be used with a [`trie_db::TrieDBMut`]. diff --git a/substrate/test-utils/client/src/client_ext.rs b/substrate/test-utils/client/src/client_ext.rs index 8efa7b5f07f..73581a4f0ef 100644 --- a/substrate/test-utils/client/src/client_ext.rs +++ b/substrate/test-utils/client/src/client_ext.rs @@ -20,9 +20,11 @@ use sc_client_api::{backend::Finalizer, client::BlockBackend}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_service::client::Client; -use sp_consensus::{BlockOrigin, Error as ConsensusError}; +use sp_consensus::Error as ConsensusError; use sp_runtime::{traits::Block as BlockT, Justification, Justifications}; +pub use sp_consensus::BlockOrigin; + /// Extension trait for a test client. pub trait ClientExt: Sized { /// Finalize a block. diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index 90e15e0f8d5..084dd2a1861 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -21,7 +21,7 @@ pub mod client_ext; -pub use self::client_ext::{ClientBlockImportExt, ClientExt}; +pub use self::client_ext::{BlockOrigin, ClientBlockImportExt, ClientExt}; pub use sc_client_api::{execution_extensions::ExecutionExtensions, BadBlocks, ForkBlocks}; pub use sc_client_db::{self, Backend, BlocksPruning}; pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod, WasmExecutor}; -- GitLab From 50390950d87fb745ec5ff46be698cac93113efb7 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:21:58 +0100 Subject: [PATCH 466/633] Refactor candidate validation messages (#2219) --- polkadot/node/core/approval-voting/src/lib.rs | 14 +- .../node/core/approval-voting/src/tests.rs | 8 +- polkadot/node/core/backing/src/lib.rs | 16 +- polkadot/node/core/backing/src/tests/mod.rs | 369 +++++++++--------- .../src/tests/prospective_parachains.rs | 69 ++-- .../node/core/candidate-validation/src/lib.rs | 27 +- .../src/participation/mod.rs | 16 +- .../src/participation/tests.rs | 26 +- polkadot/node/core/pvf-checker/src/lib.rs | 6 +- polkadot/node/core/pvf-checker/src/tests.rs | 7 +- polkadot/node/malus/src/variants/common.rs | 84 ++-- .../node/overseer/examples/minimal-example.rs | 12 +- polkadot/node/overseer/src/tests.rs | 24 +- polkadot/node/subsystem-types/src/messages.rs | 60 +-- 14 files changed, 384 insertions(+), 354 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index e7cbde56739..94f7fcaf941 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -2861,15 +2861,15 @@ async fn launch_approval( let (val_tx, val_rx) = oneshot::channel(); sender - .send_message(CandidateValidationMessage::ValidateFromExhaustive( - available_data.validation_data, + .send_message(CandidateValidationMessage::ValidateFromExhaustive { + validation_data: available_data.validation_data, validation_code, - candidate.clone(), - available_data.pov, + candidate_receipt: candidate.clone(), + pov: available_data.pov, executor_params, - PvfExecTimeoutKind::Approval, - val_tx, - )) + exec_timeout_kind: PvfExecTimeoutKind::Approval, + response_sender: val_tx, + }) .await; match val_rx.await { diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 13213c158cd..0c0dcfde9b6 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -2704,8 +2704,12 @@ async fn handle_double_assignment_import( assert_matches!( overseer_recv(virtual_overseer).await, - AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)) if timeout == PvfExecTimeoutKind::Approval => { - tx.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + exec_timeout_kind, + response_sender, + .. + }) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) .unwrap(); } ); diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 27b5972d982..a91eefe5e04 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -551,8 +551,8 @@ async fn request_pov( async fn request_candidate_validation( sender: &mut impl overseer::CandidateBackingSenderTrait, - pvd: PersistedValidationData, - code: ValidationCode, + validation_data: PersistedValidationData, + validation_code: ValidationCode, candidate_receipt: CandidateReceipt, pov: Arc, executor_params: ExecutorParams, @@ -560,15 +560,15 @@ async fn request_candidate_validation( let (tx, rx) = oneshot::channel(); sender - .send_message(CandidateValidationMessage::ValidateFromExhaustive( - pvd, - code, + .send_message(CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, pov, executor_params, - PvfExecTimeoutKind::Backing, - tx, - )) + exec_timeout_kind: PvfExecTimeoutKind::Backing, + response_sender: tx, + }) .await; match rx.await { diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 35d17f3d905..caa85c12989 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -329,32 +329,32 @@ async fn assert_validation_requests( async fn assert_validate_from_exhaustive( virtual_overseer: &mut VirtualOverseer, - pvd: &PersistedValidationData, - pov: &PoV, - validation_code: &ValidationCode, - candidate: &CommittedCandidateReceipt, + assert_pvd: &PersistedValidationData, + assert_pov: &PoV, + assert_validation_code: &ValidationCode, + assert_candidate: &CommittedCandidateReceipt, expected_head_data: &HeadData, result_validation_data: PersistedValidationData, ) { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + pov, + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == *pvd && - _validation_code == *validation_code && - *_pov == *pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && - candidate.commitments.hash() == candidate_receipt.commitments_hash => + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == *assert_pvd && + validation_code == *assert_validation_code && + *pov == *assert_pov && &candidate_receipt.descriptor == assert_candidate.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && + candidate_receipt.commitments_hash == assert_candidate.commitments.hash() => { - tx.send(Ok(ValidationResult::Valid( + response_sender.send(Ok(ValidationResult::Valid( CandidateCommitments { head_data: expected_head_data.clone(), horizontal_messages: Default::default(), @@ -461,11 +461,11 @@ fn backing_works() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_ab = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pvd_ab = dummy_pvd(); + let validation_code_ab = ValidationCode(vec![1, 2, 3]); - let pov_hash = pov.hash(); + let pov_hash = pov_ab.hash(); let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); @@ -474,8 +474,8 @@ fn backing_works() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - validation_code: validation_code.0.clone(), + erasure_root: make_erasure_root(&test_state, pov_ab.clone(), pvd_ab.clone()), + validation_code: validation_code_ab.0.clone(), ..Default::default() } .build(); @@ -498,7 +498,7 @@ fn backing_works() { let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd_ab.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -523,7 +523,7 @@ fn backing_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_ab.clone()).await; // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is the PoV. @@ -536,7 +536,7 @@ fn backing_works() { .. } ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_ab.clone()).unwrap(); } ); @@ -545,22 +545,22 @@ fn backing_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && - timeout == PvfExecTimeoutKind::Backing && - candidate_a_commitments_hash == candidate_receipt.commitments_hash => + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_ab && + validation_code == validation_code_ab && + *pov == pov_ab && &candidate_receipt.descriptor == candidate_a.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && + candidate_receipt.commitments_hash == candidate_a_commitments_hash => { - tx.send(Ok( + response_sender.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), upward_messages: Default::default(), @@ -623,11 +623,11 @@ fn backing_works_while_validation_ongoing() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_abc = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pvd_abc = dummy_pvd(); + let validation_code_abc = ValidationCode(vec![1, 2, 3]); - let pov_hash = pov.hash(); + let pov_hash = pov_abc.hash(); let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); @@ -636,8 +636,8 @@ fn backing_works_while_validation_ongoing() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - validation_code: validation_code.0.clone(), + erasure_root: make_erasure_root(&test_state, pov_abc.clone(), pvd_abc.clone()), + validation_code: validation_code_abc.0.clone(), ..Default::default() } .build(); @@ -666,7 +666,7 @@ fn backing_works_while_validation_ongoing() { let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd_abc.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -701,7 +701,7 @@ fn backing_works_while_validation_ongoing() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_abc.clone()).await; // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is PoV from the @@ -715,7 +715,7 @@ fn backing_works_while_validation_ongoing() { .. } ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_abc.clone()).unwrap(); } ); @@ -724,24 +724,24 @@ fn backing_works_while_validation_ongoing() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_abc && + validation_code == validation_code_abc && + *pov == pov_abc && &candidate_receipt.descriptor == candidate_a.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { // we never validate the candidate. our local node // shouldn't issue any statements. - std::mem::forget(tx); + std::mem::forget(response_sender); } ); @@ -812,11 +812,11 @@ fn backing_misbehavior_works() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pov_a = PoV { block_data: BlockData(vec![1, 2, 3]) }; - let pov_hash = pov.hash(); - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_hash = pov_a.hash(); + let pvd_a = dummy_pvd(); + let validation_code_a = ValidationCode(vec![1, 2, 3]); let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); @@ -824,9 +824,9 @@ fn backing_misbehavior_works() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), head_data: expected_head_data.clone(), - validation_code: validation_code.0.clone(), + validation_code: validation_code_a.0.clone(), ..Default::default() } .build(); @@ -842,7 +842,7 @@ fn backing_misbehavior_works() { .expect("Insert key into keystore"); let seconded_2 = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd_a.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -867,7 +867,7 @@ fn backing_misbehavior_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -878,29 +878,29 @@ fn backing_misbehavior_works() { .. } ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_a.clone()).unwrap(); } ); assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_a && + validation_code == validation_code_a && + *pov == pov_a && &candidate_receipt.descriptor == candidate_a.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { - tx.send(Ok( + response_sender.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), upward_messages: Default::default(), @@ -1052,22 +1052,22 @@ fn backing_dont_second_invalid() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd_a && - _validation_code == validation_code_a && - *_pov == pov_block_a && &candidate_receipt.descriptor == candidate_a.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_a && + validation_code == validation_code_a && + *pov == pov_block_a && &candidate_receipt.descriptor == candidate_a.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate_a.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); + response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1092,22 +1092,22 @@ fn backing_dont_second_invalid() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if pvd == pvd_b && - _validation_code == validation_code_b && - *_pov == pov_block_b && &candidate_receipt.descriptor == candidate_b.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_b && + validation_code == validation_code_b && + *pov == pov_block_b && &candidate_receipt.descriptor == candidate_b.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate_b.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Ok( + response_sender.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), upward_messages: Default::default(), @@ -1158,19 +1158,19 @@ fn backing_second_after_first_fails_works() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = dummy_pvd(); + let validation_code_a = ValidationCode(vec![1, 2, 3]); - let pov_hash = pov.hash(); + let pov_hash = pov_a.hash(); let candidate = TestCandidateBuilder { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + persisted_validation_data_hash: pvd_a.hash(), + validation_code: validation_code_a.0.clone(), ..Default::default() } .build(); @@ -1184,7 +1184,7 @@ fn backing_second_after_first_fails_works() { let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd_a.clone()), &test_state.signing_context, ValidatorIndex(2), &validator2.into(), @@ -1199,7 +1199,7 @@ fn backing_second_after_first_fails_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1211,7 +1211,7 @@ fn backing_second_after_first_fails_works() { .. } ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_a.clone()).unwrap(); } ); @@ -1219,22 +1219,22 @@ fn backing_second_after_first_fails_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_a && + validation_code == validation_code_a && + *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); + response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1243,8 +1243,8 @@ fn backing_second_after_first_fails_works() { let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate.to_plain(), - pvd.clone(), - pov.clone(), + pvd_a.clone(), + pov_a.clone(), ); virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; @@ -1287,7 +1287,7 @@ fn backing_second_after_first_fails_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, pov, ..), + CandidateValidationMessage::ValidateFromExhaustive { pov, .. }, ) => { assert_eq!(&*pov, &pov_to_second); } @@ -1304,18 +1304,18 @@ fn backing_works_after_failed_validation() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = dummy_pvd(); + let validation_code_a = ValidationCode(vec![1, 2, 3]); - let pov_hash = pov.hash(); + let pov_hash = pov_a.hash(); let candidate = TestCandidateBuilder { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - validation_code: validation_code.0.clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + validation_code: validation_code_a.0.clone(), ..Default::default() } .build(); @@ -1328,7 +1328,7 @@ fn backing_works_after_failed_validation() { .expect("Insert key into keystore"); let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd_a.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -1343,7 +1343,7 @@ fn backing_works_after_failed_validation() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1355,7 +1355,7 @@ fn backing_works_after_failed_validation() { .. } ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_a.clone()).unwrap(); } ); @@ -1363,22 +1363,22 @@ fn backing_works_after_failed_validation() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + pov, + exec_timeout_kind, + response_sender, + .. + }, + ) if validation_data == pvd_a && + validation_code == validation_code_a && + *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); + response_sender.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); } ); @@ -1475,19 +1475,19 @@ fn retry_works() { test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = dummy_pvd(); + let validation_code_a = ValidationCode(vec![1, 2, 3]); - let pov_hash = pov.hash(); + let pov_hash = pov_a.hash(); let candidate = TestCandidateBuilder { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + persisted_validation_data_hash: pvd_a.hash(), + validation_code: validation_code_a.0.clone(), ..Default::default() } .build(); @@ -1512,7 +1512,7 @@ fn retry_works() { .expect("Insert key into keystore"); let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd_a.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -1546,7 +1546,7 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. // We cancel - should mean retry on next backing statement. @@ -1584,8 +1584,8 @@ fn retry_works() { AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, RuntimeApiRequest::ValidationCodeByHash(hash, tx), - )) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); + )) if hash == validation_code_a.hash() => { + tx.send(Ok(Some(validation_code_a.clone()))).unwrap(); }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, @@ -1609,7 +1609,7 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_c.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; + assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1622,26 +1622,25 @@ fn retry_works() { // Subsystem requests PoV and requests validation. // Now we pass. ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(pov_a.clone()).unwrap(); } ); assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, + pov, + exec_timeout_kind, .. - ), - ) if _pvd == pvd && - _validation_code == validation_code && - *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + }, + ) if validation_data == pvd_a && + validation_code == validation_code_a && + *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer @@ -1863,9 +1862,9 @@ fn cannot_second_multiple_candidates_per_parent() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(.., tx), + CandidateValidationMessage::ValidateFromExhaustive { response_sender, .. }, ) => { - tx.send(Ok(ValidationResult::Valid( + response_sender.send(Ok(ValidationResult::Valid( CandidateCommitments { head_data: expected_head_data.clone(), horizontal_messages: Default::default(), diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index b79515ed37a..fc4bd7d98e7 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -202,13 +202,13 @@ async fn assert_validate_seconded_candidate( virtual_overseer: &mut VirtualOverseer, relay_parent: Hash, candidate: &CommittedCandidateReceipt, - pov: &PoV, - pvd: &PersistedValidationData, - validation_code: &ValidationCode, + assert_pov: &PoV, + assert_pvd: &PersistedValidationData, + assert_validation_code: &ValidationCode, expected_head_data: &HeadData, fetch_pov: bool, ) { - assert_validation_requests(virtual_overseer, validation_code.clone()).await; + assert_validation_requests(virtual_overseer, assert_validation_code.clone()).await; if fetch_pov { assert_matches!( @@ -220,29 +220,29 @@ async fn assert_validate_seconded_candidate( .. } ) if hash == relay_parent => { - tx.send(pov.clone()).unwrap(); + tx.send(assert_pov.clone()).unwrap(); } ); } assert_matches!( virtual_overseer.recv().await, - AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive( - _pvd, - _validation_code, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + validation_data, + validation_code, candidate_receipt, - _pov, - _, - timeout, - tx, - )) if &_pvd == pvd && - &_validation_code == validation_code && - &*_pov == pov && + pov, + exec_timeout_kind, + response_sender, + .. + }) if &validation_data == assert_pvd && + &validation_code == assert_validation_code && + &*pov == assert_pov && &candidate_receipt.descriptor == candidate.descriptor() && - timeout == PvfExecTimeoutKind::Backing && + exec_timeout_kind == PvfExecTimeoutKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Ok(ValidationResult::Valid( + response_sender.send(Ok(ValidationResult::Valid( CandidateCommitments { head_data: expected_head_data.clone(), horizontal_messages: Default::default(), @@ -251,7 +251,7 @@ async fn assert_validate_seconded_candidate( processed_downward_messages: 0, hrmp_watermark: 0, }, - pvd.clone(), + assert_pvd.clone(), ))) .unwrap(); } @@ -1293,9 +1293,13 @@ fn concurrent_dependent_candidates() { tx.send(pov.clone()).unwrap(); }, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, _, tx), + CandidateValidationMessage::ValidateFromExhaustive { + candidate_receipt, + response_sender, + .. + }, ) => { - let candidate_hash = candidate.hash(); + let candidate_hash = candidate_receipt.hash(); let (head_data, pvd) = if candidate_hash == candidate_a_hash { (&head_data[1], &pvd_a) } else if candidate_hash == candidate_b_hash { @@ -1303,18 +1307,19 @@ fn concurrent_dependent_candidates() { } else { panic!("unknown candidate hash") }; - tx.send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - pvd.clone(), - ))) - .unwrap(); + response_sender + .send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + pvd.clone(), + ))) + .unwrap(); }, AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { tx, diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 93db7d11cee..89ea0272884 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -159,13 +159,14 @@ async fn run( FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), FromOrchestra::Communication { msg } => match msg { - CandidateValidationMessage::ValidateFromChainState( + CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ) => { + .. + } => { let bg = { let mut sender = ctx.sender().clone(); let metrics = metrics.clone(); @@ -179,7 +180,7 @@ async fn run( candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, &metrics, ) .await; @@ -191,15 +192,16 @@ async fn run( ctx.spawn("validate-from-chain-state", bg.boxed())?; }, - CandidateValidationMessage::ValidateFromExhaustive( - persisted_validation_data, + CandidateValidationMessage::ValidateFromExhaustive { + validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ) => { + .. + } => { let bg = { let metrics = metrics.clone(); let validation_host = validation_host.clone(); @@ -208,12 +210,12 @@ async fn run( let _timer = metrics.time_validate_from_exhaustive(); let res = validate_candidate_exhaustive( validation_host, - persisted_validation_data, + validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, &metrics, ) .await; @@ -225,11 +227,12 @@ async fn run( ctx.spawn("validate-from-exhaustive", bg.boxed())?; }, - CandidateValidationMessage::PreCheck( + CandidateValidationMessage::PreCheck { relay_parent, validation_code_hash, response_sender, - ) => { + .. + } => { let bg = { let mut sender = ctx.sender().clone(); let validation_host = validation_host.clone(); diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index 35d07b411e8..90268516e9d 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -380,15 +380,15 @@ async fn participate( // same level of leeway. let (validation_tx, validation_rx) = oneshot::channel(); sender - .send_message(CandidateValidationMessage::ValidateFromExhaustive( - available_data.validation_data, + .send_message(CandidateValidationMessage::ValidateFromExhaustive { + validation_data: available_data.validation_data, validation_code, - req.candidate_receipt().clone(), - available_data.pov, - req.executor_params(), - PvfExecTimeoutKind::Approval, - validation_tx, - )) + candidate_receipt: req.candidate_receipt().clone(), + pov: available_data.pov, + executor_params: req.executor_params(), + exec_timeout_kind: PvfExecTimeoutKind::Approval, + response_sender: validation_tx, + }) .await; // we cast votes (either positive or negative) depending on the outcome of diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index ee6b950720e..0aa0d772005 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -115,12 +115,12 @@ pub async fn participation_full_happy_path( assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, _, timeout, tx) - ) if timeout == PvfExecTimeoutKind::Approval => { + CandidateValidationMessage::ValidateFromExhaustive { candidate_receipt, exec_timeout_kind, response_sender, .. } + ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { if expected_commitments_hash != candidate_receipt.commitments_hash { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); + response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { - tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); + response_sender.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); } }, "overseer did not receive candidate validation message", @@ -450,9 +450,9 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) - ) if timeout == PvfExecTimeoutKind::Approval => { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); + CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } + ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, "overseer did not receive candidate validation message", ); @@ -487,9 +487,9 @@ fn cast_invalid_vote_if_commitments_dont_match() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) - ) if timeout == PvfExecTimeoutKind::Approval => { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); + CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } + ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", ); @@ -524,9 +524,9 @@ fn cast_valid_vote_if_validation_passes() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx) - ) if timeout == PvfExecTimeoutKind::Approval => { - tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); + CandidateValidationMessage::ValidateFromExhaustive { exec_timeout_kind, response_sender, .. } + ) if exec_timeout_kind == PvfExecTimeoutKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, "overseer did not receive candidate validation message", ); diff --git a/polkadot/node/core/pvf-checker/src/lib.rs b/polkadot/node/core/pvf-checker/src/lib.rs index 2946f3f7886..043da00eba1 100644 --- a/polkadot/node/core/pvf-checker/src/lib.rs +++ b/polkadot/node/core/pvf-checker/src/lib.rs @@ -535,7 +535,11 @@ async fn initiate_precheck( let (tx, rx) = oneshot::channel(); sender - .send_message(CandidateValidationMessage::PreCheck(relay_parent, validation_code_hash, tx)) + .send_message(CandidateValidationMessage::PreCheck { + relay_parent, + validation_code_hash, + response_sender: tx, + }) .await; let timer = metrics.time_pre_check_judgement(); diff --git a/polkadot/node/core/pvf-checker/src/tests.rs b/polkadot/node/core/pvf-checker/src/tests.rs index 4ac6e5eba31..b0401ecdc3b 100644 --- a/polkadot/node/core/pvf-checker/src/tests.rs +++ b/polkadot/node/core/pvf-checker/src/tests.rs @@ -267,11 +267,12 @@ impl TestState { handle: &mut VirtualOverseer, ) -> ExpectCandidatePrecheck { match self.recv_timeout(handle).await.expect("timeout waiting for a message") { - AllMessages::CandidateValidation(CandidateValidationMessage::PreCheck( + AllMessages::CandidateValidation(CandidateValidationMessage::PreCheck { relay_parent, validation_code_hash, - tx, - )) => ExpectCandidatePrecheck { relay_parent, validation_code_hash, tx }, + response_sender, + .. + }) => ExpectCandidatePrecheck { relay_parent, validation_code_hash, tx: response_sender }, msg => panic!("Unexpected message was received: {:#?}", msg), } } diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 365b2f16ac2..474887ee8df 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -273,30 +273,31 @@ where // Message sent by the approval voting subsystem FromOrchestra::Communication { msg: - CandidateValidationMessage::ValidateFromExhaustive( + CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, - sender, - ), + exec_timeout_kind, + response_sender, + .. + }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(timeout) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_timeout_kind) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromExhaustive( + msg: CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, - sender, - ), + exec_timeout_kind, + response_sender, + }, }) } // Create the fake response with probability `p` if the `PoV` is malicious, @@ -313,7 +314,7 @@ where create_validation_response( validation_data, candidate_receipt.descriptor, - sender, + response_sender, ); None }, @@ -326,20 +327,20 @@ where ); Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromExhaustive( + msg: CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, - sender, - ), + exec_timeout_kind, + response_sender, + }, }) }, } }, - x if x.misbehaves_invalid() && x.should_misbehave(timeout) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_timeout_kind) => { // Set the validation result to invalid with probability `p` and trigger a // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -358,7 +359,7 @@ where // We're not even checking the candidate, this makes us appear // faster than honest validators. - sender.send(Ok(validation_result)).unwrap(); + response_sender.send(Ok(validation_result)).unwrap(); None }, false => { @@ -366,56 +367,57 @@ where gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",); Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromExhaustive( + msg: CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, - sender, - ), + exec_timeout_kind, + response_sender, + }, }) }, } }, // Handle FakeCandidateValidation::Disabled _ => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromExhaustive( + msg: CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, candidate_receipt, pov, executor_params, - timeout, - sender, - ), + exec_timeout_kind, + response_sender, + }, }), } }, // Behaviour related to the backing subsystem FromOrchestra::Communication { msg: - CandidateValidationMessage::ValidateFromChainState( + CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ), + .. + }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(timeout) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_timeout_kind) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( + msg: CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ), + }, }) } // If the `PoV` is malicious, back the candidate with some probability `p`, @@ -439,17 +441,17 @@ where // If the `PoV` is malicious, we behave normally with some probability // `(1-p)` false => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( + msg: CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ), + }, }), } }, - x if x.misbehaves_invalid() && x.should_misbehave(timeout) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_timeout_kind) => { // Maliciously set the validation result to invalid for a valid candidate // with probability `p` let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -473,25 +475,25 @@ where gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",); Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( + msg: CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ), + }, }) }, } }, _ => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( + msg: CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, executor_params, - timeout, + exec_timeout_kind, response_sender, - ), + }, }), } }, diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index cffdfd9f8aa..b2c0ea2f75a 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -73,13 +73,13 @@ impl Subsystem1 { commitments_hash: Hash::zero(), }; - let msg = CandidateValidationMessage::ValidateFromChainState( + let msg = CandidateValidationMessage::ValidateFromChainState { candidate_receipt, - PoV { block_data: BlockData(Vec::new()) }.into(), - Default::default(), - PvfExecTimeoutKind::Backing, - tx, - ); + pov: PoV { block_data: BlockData(Vec::new()) }.into(), + executor_params: Default::default(), + exec_timeout_kind: PvfExecTimeoutKind::Backing, + response_sender: tx, + }; ctx.send_message(msg).await; } () diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index c17613fb7ea..254f5fe4512 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -102,13 +102,13 @@ where }; let (tx, _) = oneshot::channel(); - ctx.send_message(CandidateValidationMessage::ValidateFromChainState( + ctx.send_message(CandidateValidationMessage::ValidateFromChainState { candidate_receipt, - PoV { block_data: BlockData(Vec::new()) }.into(), - Default::default(), - PvfExecTimeoutKind::Backing, - tx, - )) + pov: PoV { block_data: BlockData(Vec::new()) }.into(), + executor_params: Default::default(), + exec_timeout_kind: PvfExecTimeoutKind::Backing, + response_sender: tx, + }) .await; c += 1; continue @@ -793,20 +793,20 @@ where } fn test_candidate_validation_msg() -> CandidateValidationMessage { - let (sender, _) = oneshot::channel(); + let (response_sender, _) = oneshot::channel(); let pov = Arc::new(PoV { block_data: BlockData(Vec::new()) }); let candidate_receipt = CandidateReceipt { descriptor: dummy_candidate_descriptor(dummy_hash()), commitments_hash: Hash::zero(), }; - CandidateValidationMessage::ValidateFromChainState( + CandidateValidationMessage::ValidateFromChainState { candidate_receipt, pov, - Default::default(), - PvfExecTimeoutKind::Backing, - sender, - ) + executor_params: Default::default(), + exec_timeout_kind: PvfExecTimeoutKind::Backing, + response_sender, + } } fn test_candidate_backing_msg() -> CandidateBackingMessage { diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index ce4fa6633dc..4ddffc6dc5e 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -143,14 +143,18 @@ pub enum CandidateValidationMessage { /// /// If there is no state available which can provide this data or the core for /// the para is not free at the relay-parent, an error is returned. - ValidateFromChainState( - CandidateReceipt, - Arc, - ExecutorParams, - /// Execution timeout - PvfExecTimeoutKind, - oneshot::Sender>, - ), + ValidateFromChainState { + /// The candidate receipt + candidate_receipt: CandidateReceipt, + /// The proof-of-validity + pov: Arc, + /// Session's executor parameters + executor_params: ExecutorParams, + /// Execution timeout kind (backing/approvals) + exec_timeout_kind: PvfExecTimeoutKind, + /// The sending side of the response channel + response_sender: oneshot::Sender>, + }, /// Validate a candidate with provided, exhaustive parameters for validation. /// /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full @@ -160,27 +164,35 @@ pub enum CandidateValidationMessage { /// cases where the validity of the candidate is established. This is the case for the typical /// use-case: secondary checkers would use this request relying on the full prior checks /// performed by the relay-chain. - ValidateFromExhaustive( - PersistedValidationData, - ValidationCode, - CandidateReceipt, - Arc, - ExecutorParams, - /// Execution timeout - PvfExecTimeoutKind, - oneshot::Sender>, - ), + ValidateFromExhaustive { + /// Persisted validation data + validation_data: PersistedValidationData, + /// Validation code + validation_code: ValidationCode, + /// The candidate receipt + candidate_receipt: CandidateReceipt, + /// The proof-of-validity + pov: Arc, + /// Session's executor parameters + executor_params: ExecutorParams, + /// Execution timeout kind (backing/approvals) + exec_timeout_kind: PvfExecTimeoutKind, + /// The sending side of the response channel + response_sender: oneshot::Sender>, + }, /// Try to compile the given validation code and send back /// the outcome. /// /// The validation code is specified by the hash and will be queried from the runtime API at /// the given relay-parent. - PreCheck( - // Relay-parent - Hash, - ValidationCodeHash, - oneshot::Sender, - ), + PreCheck { + /// Relay-parent + relay_parent: Hash, + /// Validation code hash + validation_code_hash: ValidationCodeHash, + /// The sending side of the response channel + response_sender: oneshot::Sender, + }, } /// Messages received by the Collator Protocol subsystem. -- GitLab From ffa0e30e58234d85e24a3a55b088fb676ef71bfd Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Wed, 8 Nov 2023 16:02:03 +0100 Subject: [PATCH 467/633] [xcm-emulator] Chains generic over Network & Integration tests restructure (#2092) Closes: - #1383 - Declared chains can be now be imported and reused in a different crate. - Chain declaration are now generic over a generic type `N` (the Network) - #1389 - Solved #1383, chains and networks declarations can be restructure to avoid having to compile all chains when running integrations tests where are not needed. - Chains are now declared on its own crate (removed from `integration-tests-common`) - Networks are now declared on its own crate (removed from `integration-tests-common`) - Integration tests will import only the relevant Network crate - `integration-tests-common` is renamed to `emulated-integration-tests-common` All this is necessary to be able to implement what is described here: https://github.com/paritytech/roadmap/issues/56#issuecomment-1777010553 --------- Co-authored-by: command-bot <> --- .gitignore | 1 - Cargo.lock | 332 +++-- Cargo.toml | 20 +- .../src/tests/reserve_transfer.rs | 412 ------ .../assets/asset-hub-rococo/Cargo.toml | 56 - .../assets/asset-hub-westend/Cargo.toml | 71 - .../bridges/bridge-hub-rococo/Cargo.toml | 41 - .../bridges/bridge-hub-rococo/src/lib.rs | 67 - .../bridges/bridge-hub-westend/Cargo.toml | 41 - .../bridges/bridge-hub-westend/src/lib.rs | 67 - .../assets/asset-hub-rococo/Cargo.toml | 25 + .../assets/asset-hub-rococo/src/genesis.rs | 70 + .../assets/asset-hub-rococo/src/lib.rs | 55 + .../assets/asset-hub-westend/Cargo.toml | 25 + .../assets/asset-hub-westend/src/genesis.rs | 67 + .../assets/asset-hub-westend/src/lib.rs | 55 + .../assets/asset-hub-wococo/Cargo.toml | 26 + .../assets/asset-hub-wococo/src/lib.rs | 53 + .../bridges/bridge-hub-rococo/Cargo.toml | 24 + .../bridges/bridge-hub-rococo/src/genesis.rs | 83 ++ .../bridges/bridge-hub-rococo/src/lib.rs | 49 + .../bridges/bridge-hub-westend/Cargo.toml | 24 + .../bridges/bridge-hub-westend/src/genesis.rs | 75 + .../bridges/bridge-hub-westend/src/lib.rs | 49 + .../bridges/bridge-hub-wococo/Cargo.toml | 25 + .../bridges/bridge-hub-wococo/src/lib.rs | 47 + .../parachains/testing/penpal/Cargo.toml | 24 + .../parachains/testing/penpal/src/genesis.rs | 71 + .../parachains/testing/penpal/src/lib.rs | 65 + .../emulated/chains/relays/rococo/Cargo.toml | 29 + .../chains/relays/rococo/src/genesis.rs | 101 ++ .../emulated/chains/relays/rococo/src/lib.rs | 48 + .../emulated/chains/relays/westend/Cargo.toml | 30 + .../chains/relays/westend/src/genesis.rs | 109 ++ .../emulated/chains/relays/westend/src/lib.rs | 50 + .../emulated/chains/relays/wococo/Cargo.toml | 30 + .../emulated/chains/relays/wococo/src/lib.rs | 46 + .../emulated/common/Cargo.toml | 62 +- .../emulated/common/src/constants.rs | 1219 ----------------- .../emulated/common/src/impls.rs | 121 +- .../emulated/common/src/lib.rs | 470 ++----- .../emulated/common/src/macros.rs | 49 +- .../emulated/common/src/xcm_helpers.rs | 3 + .../networks/rococo-system/Cargo.toml | 16 + .../networks/rococo-system/src/lib.rs | 51 + .../networks/rococo-wococo-system/Cargo.toml | 18 + .../networks/rococo-wococo-system/src/lib.rs | 94 ++ .../networks/westend-system/Cargo.toml | 16 + .../networks/westend-system/src/lib.rs | 51 + .../networks/wococo-system/Cargo.toml | 16 + .../networks/wococo-system/src/lib.rs | 50 + .../tests/assets/asset-hub-rococo/Cargo.toml | 32 + .../assets/asset-hub-rococo/src/lib.rs | 48 +- .../assets/asset-hub-rococo/src/tests/mod.rs | 0 .../src/tests/reserve_transfer.rs | 24 +- .../assets/asset-hub-rococo/src/tests/send.rs | 13 +- .../src/tests/set_xcm_versions.rs | 0 .../assets/asset-hub-rococo/src/tests/swap.rs | 24 +- .../asset-hub-rococo/src/tests/teleport.rs | 0 .../tests/assets/asset-hub-westend/Cargo.toml | 41 + .../assets/asset-hub-westend/src/lib.rs | 46 +- .../assets/asset-hub-westend/src/tests/mod.rs | 0 .../src/tests/reserve_transfer.rs | 24 +- .../asset-hub-westend/src/tests/send.rs | 13 +- .../src/tests/set_xcm_versions.rs | 0 .../asset-hub-westend/src/tests/swap.rs | 26 +- .../asset-hub-westend/src/tests/teleport.rs | 2 - .../asset-hub-westend/src/tests/treasury.rs | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 33 + .../bridges/bridge-hub-rococo/src/lib.rs | 60 + .../bridge-hub-rococo/src/tests/example.rs | 0 .../bridge-hub-rococo/src/tests/mod.rs | 0 .../bridge-hub-rococo/src/tests/teleport.rs | 0 .../bridges/bridge-hub-westend/Cargo.toml | 33 + .../bridges/bridge-hub-westend/src/lib.rs | 56 + .../bridge-hub-westend/src/tests/example.rs | 2 +- .../bridge-hub-westend/src/tests/mod.rs | 0 .../bridge-hub-westend/src/tests/teleport.rs | 2 +- cumulus/xcm/xcm-emulator/src/lib.rs | 234 ++-- 79 files changed, 2669 insertions(+), 2745 deletions(-) delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/common/src/constants.rs create mode 100644 cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/lib.rs (67%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/mod.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/reserve_transfer.rs (95%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/send.rs (88%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/swap.rs (94%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-rococo/src/tests/teleport.rs (100%) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/lib.rs (69%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/mod.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/reserve_transfer.rs (95%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/send.rs (87%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/set_xcm_versions.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/swap.rs (92%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/teleport.rs (99%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/assets/asset-hub-westend/src/tests/treasury.rs (98%) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-rococo/src/tests/example.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-rococo/src/tests/mod.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-rococo/src/tests/teleport.rs (100%) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-westend/src/tests/example.rs (96%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-westend/src/tests/mod.rs (100%) rename cumulus/parachains/integration-tests/emulated/{ => tests}/bridges/bridge-hub-westend/src/tests/teleport.rs (95%) diff --git a/.gitignore b/.gitignore index 7feea8ada5c..581c417cb85 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ **/._* **/.criterion/ **/*.rs.bk -**/chains/ **/hfuzz_target/ **/hfuzz_workspace/ **/node_modules diff --git a/Cargo.lock b/Cargo.lock index 8c7121e235c..18eb00a13c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,6 +874,21 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "asset-hub-rococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "asset-hub-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "rococo-emulated-chain", + "serde_json", + "sp-core", + "sp-runtime", +] + [[package]] name = "asset-hub-rococo-integration-tests" version = "1.0.0" @@ -881,23 +896,19 @@ dependencies = [ "assert_matches", "asset-hub-rococo-runtime", "asset-test-utils", + "emulated-integration-tests-common", "frame-support", - "frame-system", - "integration-tests-common", "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-xcm", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", "rococo-runtime", + "rococo-system-emulated-network", "sp-runtime", "staging-xcm", "staging-xcm-executor", - "xcm-emulator", ] [[package]] @@ -982,6 +993,21 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "asset-hub-westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "asset-hub-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", + "westend-emulated-chain", +] + [[package]] name = "asset-hub-westend-integration-tests" version = "1.0.0" @@ -991,9 +1017,9 @@ dependencies = [ "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", + "emulated-integration-tests-common", "frame-support", "frame-system", - "integration-tests-common", "pallet-asset-conversion", "pallet-asset-rate", "pallet-assets", @@ -1003,17 +1029,14 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "westend-runtime", "westend-runtime-constants", - "xcm-emulator", + "westend-system-emulated-network", ] [[package]] @@ -1094,6 +1117,22 @@ dependencies = [ "westend-runtime-constants", ] +[[package]] +name = "asset-hub-wococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "asset-hub-rococo-emulated-chain", + "asset-hub-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", + "wococo-emulated-chain", +] + [[package]] name = "asset-test-utils" version = "1.0.0" @@ -2136,6 +2175,20 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "bridge-hub-rococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "bridge-hub-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", +] + [[package]] name = "bridge-hub-rococo-integration-tests" version = "1.0.0" @@ -2145,24 +2198,16 @@ dependencies = [ "bridge-hub-rococo-runtime", "cumulus-pallet-dmp-queue", "cumulus-pallet-xcmp-queue", + "emulated-integration-tests-common", "frame-support", - "frame-system", - "integration-tests-common", - "pallet-assets", - "pallet-balances", "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", - "sp-core", - "sp-weights", + "rococo-wococo-system-emulated-network", "staging-xcm", "staging-xcm-executor", - "xcm-emulator", ] [[package]] @@ -2298,6 +2343,20 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "bridge-hub-westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "bridge-hub-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", +] + [[package]] name = "bridge-hub-westend-integration-tests" version = "1.0.0" @@ -2307,24 +2366,16 @@ dependencies = [ "bridge-hub-westend-runtime", "cumulus-pallet-dmp-queue", "cumulus-pallet-xcmp-queue", + "emulated-integration-tests-common", "frame-support", - "frame-system", - "integration-tests-common", - "pallet-assets", - "pallet-balances", "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", - "sp-core", - "sp-weights", "staging-xcm", "staging-xcm-executor", - "xcm-emulator", + "westend-system-emulated-network", ] [[package]] @@ -2410,6 +2461,21 @@ dependencies = [ "westend-runtime-constants", ] +[[package]] +name = "bridge-hub-wococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "bridge-hub-rococo-emulated-chain", + "bridge-hub-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", +] + [[package]] name = "bridge-runtime-common" version = "0.1.0" @@ -4988,6 +5054,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "emulated-integration-tests-common" +version = "1.0.0" +dependencies = [ + "asset-test-utils", + "bp-messages", + "bridge-runtime-common", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "frame-support", + "pallet-assets", + "pallet-balances", + "pallet-bridge-messages", + "pallet-im-online", + "pallet-message-queue", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "paste", + "polkadot-primitives", + "polkadot-runtime-parachains", + "polkadot-service", + "sc-consensus-grandpa", + "serde_json", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", + "staging-xcm", + "xcm-emulator", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -6735,57 +6835,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "integration-tests-common" -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", - "bridge-hub-polkadot-runtime", - "bridge-hub-rococo-runtime", - "bridge-hub-westend-runtime", - "bridge-runtime-common", - "collectives-polkadot-runtime", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-support", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-im-online", - "pallet-message-queue", - "pallet-staking", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "paste", - "penpal-runtime", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", - "polkadot-service", - "rococo-runtime", - "rococo-runtime-constants", - "sc-chain-spec", - "sc-consensus-grandpa", - "serde_json", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core", - "sp-runtime", - "staging-xcm", - "westend-runtime", - "westend-runtime-constants", - "xcm-emulator", -] - [[package]] name = "interceptor" version = "0.8.2" @@ -11547,6 +11596,20 @@ dependencies = [ "base64ct", ] +[[package]] +name = "penpal-emulated-chain" +version = "0.0.0" +dependencies = [ + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "penpal-runtime", + "serde_json", + "sp-core", + "sp-runtime", +] + [[package]] name = "penpal-runtime" version = "0.9.27" @@ -14288,6 +14351,25 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "emulated-integration-tests-common", + "pallet-im-online", + "parachains-common", + "polkadot-primitives", + "rococo-runtime", + "rococo-runtime-constants", + "sc-consensus-grandpa", + "serde_json", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", +] + [[package]] name = "rococo-parachain-runtime" version = "0.1.0" @@ -14455,6 +14537,30 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "rococo-system-emulated-network" +version = "0.0.0" +dependencies = [ + "asset-hub-rococo-emulated-chain", + "bridge-hub-rococo-emulated-chain", + "emulated-integration-tests-common", + "penpal-emulated-chain", + "rococo-emulated-chain", +] + +[[package]] +name = "rococo-wococo-system-emulated-network" +version = "0.0.0" +dependencies = [ + "asset-hub-rococo-emulated-chain", + "asset-hub-wococo-emulated-chain", + "bridge-hub-rococo-emulated-chain", + "bridge-hub-wococo-emulated-chain", + "emulated-integration-tests-common", + "rococo-emulated-chain", + "wococo-emulated-chain", +] + [[package]] name = "rpassword" version = "7.2.0" @@ -20682,6 +20788,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "emulated-integration-tests-common", + "pallet-im-online", + "pallet-staking", + "parachains-common", + "polkadot-primitives", + "sc-consensus-grandpa", + "serde_json", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", + "westend-runtime", + "westend-runtime-constants", +] + [[package]] name = "westend-runtime" version = "1.0.0" @@ -20807,6 +20933,17 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "westend-system-emulated-network" +version = "0.0.0" +dependencies = [ + "asset-hub-westend-emulated-chain", + "bridge-hub-westend-emulated-chain", + "emulated-integration-tests-common", + "penpal-emulated-chain", + "westend-emulated-chain", +] + [[package]] name = "which" version = "4.4.0" @@ -21068,6 +21205,37 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "emulated-integration-tests-common", + "pallet-im-online", + "parachains-common", + "polkadot-primitives", + "rococo-emulated-chain", + "rococo-runtime", + "rococo-runtime-constants", + "sc-consensus-grandpa", + "serde_json", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "wococo-system-emulated-network" +version = "0.0.0" +dependencies = [ + "asset-hub-wococo-emulated-chain", + "bridge-hub-wococo-emulated-chain", + "emulated-integration-tests-common", + "penpal-emulated-chain", + "wococo-emulated-chain", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 2344a24a5d9..3b3469e5483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,11 +65,23 @@ members = [ "cumulus/parachain-template/pallets/template", "cumulus/parachain-template/runtime", "cumulus/parachains/common", - "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/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo", + "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend", + "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo", + "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/common", + "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", + "cumulus/parachains/integration-tests/emulated/chains/relays/wococo", + "cumulus/parachains/integration-tests/emulated/chains/relays/westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo", + "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo", + "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", + "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/networks/rococo-system", + "cumulus/parachains/integration-tests/emulated/networks/wococo-system", + "cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system", + "cumulus/parachains/integration-tests/emulated/networks/westend-system", "cumulus/parachains/pallets/collective-content", "cumulus/parachains/pallets/parachain-info", "cumulus/parachains/pallets/ping", 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 312df8f7a33..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs +++ /dev/null @@ -1,412 +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) { - // Errors with `UntrustedReserveLocation`, but the MQ pallet does not report back errors. - AssetHubPolkadot::assert_dmp_queue_incomplete(Some(Weight::from_parts(1_000_000_000, 0))); -} - -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-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml deleted file mode 100644 index db58d8d3303..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "asset-hub-rococo-integration-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Rococo runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -assert_matches = "1.5.0" - -# Substrate -sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} -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" } -xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} -rococo-runtime = { path = "../../../../../../polkadot/runtime/rococo", default-features = false } - -# Cumulus -asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } -parachains-common = { path = "../../../../common" } -asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } - -# Local -xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} -integration-tests-common = { path = "../../common", default-features = false} - -[features] -runtime-benchmarks = [ - "asset-hub-rococo-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", - "rococo-runtime/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] 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 deleted file mode 100644 index 2043431dcc2..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml +++ /dev/null @@ -1,71 +0,0 @@ -[package] -name = "asset-hub-westend-integration-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Westend runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -assert_matches = "1.5.0" - -# Substrate -sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} -frame-system = { path = "../../../../../../substrate/frame/system", default-features = false} -pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} -pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} -pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conversion", default-features = false} -pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", 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" } -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} -westend-runtime = { path = "../../../../../../polkadot/runtime/westend", default-features = false } -westend-runtime-constants = { path = "../../../../../../polkadot/runtime/westend/constants", default-features = false } - -# Cumulus -parachains-common = { path = "../../../../common" } -asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } -asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } -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} -integration-tests-common = { path = "../../common", default-features = false} - -[features] -runtime-benchmarks = [ - "asset-hub-westend-runtime/runtime-benchmarks", - "cumulus-pallet-dmp-queue/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-message-queue/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", - "sp-runtime/runtime-benchmarks", - "westend-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] 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 deleted file mode 100644 index b969c27aab9..00000000000 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "bridge-hub-rococo-integration-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } - -# Substrate -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-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} -pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} -pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} -pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", 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" } -xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} - -# Cumulus -asset-test-utils = { path = "../../../../../parachains/runtimes/assets/test-utils", default-features = false } -parachains-common = { path = "../../../../common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} -pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} -bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} -bridge-hub-rococo-runtime = { path = "../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } - -# 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/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs deleted file mode 100644 index 3c4dbe18a9a..00000000000 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs +++ /dev/null @@ -1,67 +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 bp_messages::LaneId; -pub use frame_support::assert_ok; -pub use integration_tests_common::{ - constants::{ - 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, BridgeHubRococoPallet, - BridgeHubRococoSender, BridgeHubWococo, PenpalRococoA, Rococo, RococoPallet, -}; -pub use parachains_common::{AccountId, Balance}; -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{ - Error, - NetworkId::{Rococo as RococoId, Wococo as WococoId}, - }, -}; -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; -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: Rococo::child_location_of(AssetHubRococo::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubRococoReceiver::get().into(), - } - .into(), - amount, - assets: (Here, amount).into(), - asset_id: None, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -#[cfg(test)] -mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml deleted file mode 100644 index af5408b888b..00000000000 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "bridge-hub-westend-integration-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Westend runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } - -# Substrate -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-weights = { path = "../../../../../../substrate/primitives/weights", default-features = false} -pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} -pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} -pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", 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" } -xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} - -# Cumulus -asset-test-utils = { path = "../../../../../parachains/runtimes/assets/test-utils", default-features = false } -parachains-common = { path = "../../../../common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} -pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} -bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} -bridge-hub-westend-runtime = { path = "../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } - -# 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/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs deleted file mode 100644 index 8b17ce53eb0..00000000000 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/lib.rs +++ /dev/null @@ -1,67 +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 bp_messages::LaneId; -pub use frame_support::assert_ok; -pub use integration_tests_common::{ - constants::{ - bridge_hub_westend::ED as BRIDGE_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}, - AssetHubRococo, AssetHubWestend, AssetHubWestendReceiver, BridgeHubRococo, BridgeHubWestend, - BridgeHubWestendPallet, BridgeHubWestendSender, PenpalWestendA, Westend, WestendPallet, -}; -pub use parachains_common::{AccountId, Balance}; -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{ - Error, - NetworkId::{Rococo as RococoId, Westend as WestendId}, - }, -}; -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; -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: Westend::child_location_of(AssetHubWestend::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubWestendReceiver::get().into(), - } - .into(), - amount, - assets: (Here, amount).into(), - asset_id: None, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -#[cfg(test)] -mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..dbf7e9c9a70 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "asset-hub-rococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Asset Hub Rococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +asset-hub-rococo-runtime = { path = "../../../../../../runtimes/assets/asset-hub-rococo" } +rococo-emulated-chain = { path = "../../../relays/rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs new file mode 100644 index 00000000000..efc94722d90 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -0,0 +1,70 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1000; +pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig::default(), + balances: asset_hub_rococo_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096 * 4096)) + .collect(), + }, + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..0580d61eae9 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -0,0 +1,55 @@ +// 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 genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, +}; +use rococo_emulated_chain::Rococo; + +// AssetHubRococo Parachain declaration +decl_test_parachains! { + pub struct AssetHubRococo { + genesis = genesis::genesis(), + on_init = { + asset_hub_rococo_runtime::AuraExt::on_initialize(1); + }, + runtime = asset_hub_rococo_runtime, + core = { + XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, + LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, + }, + pallets = { + 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, + } + }, +} + +// AssetHubRococo implementation +impl_accounts_helpers_for_parachain!(AssetHubRococo); +impl_assert_events_helpers_for_parachain!(AssetHubRococo); +impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml new file mode 100644 index 00000000000..0ff817b6b96 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "asset-hub-westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Asset Hub Westend emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +asset-hub-westend-runtime = { path = "../../../../../../runtimes/assets/asset-hub-westend" } +westend-emulated-chain = { path = "../../../relays/westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs new file mode 100644 index 00000000000..19e7a60b030 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs @@ -0,0 +1,67 @@ +// 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. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1000; +pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { + system: asset_hub_westend_runtime::SystemConfig::default(), + balances: asset_hub_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: asset_hub_westend_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 + ) + }) + .collect(), + }, + polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + asset_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs new file mode 100644 index 00000000000..804b727c33f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -0,0 +1,55 @@ +// 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 genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, +}; +use westend_emulated_chain::Westend; + +// AssetHubWestend Parachain declaration +decl_test_parachains! { + pub struct AssetHubWestend { + genesis = genesis::genesis(), + on_init = { + asset_hub_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = asset_hub_westend_runtime, + core = { + XcmpMessageHandler: asset_hub_westend_runtime::XcmpQueue, + 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, + } + }, +} + +// AssetHubWestend implementation +impl_accounts_helpers_for_parachain!(AssetHubWestend); +impl_assert_events_helpers_for_parachain!(AssetHubWestend); +impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml new file mode 100644 index 00000000000..0f212c15999 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "asset-hub-wococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Asset Hub Wococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +asset-hub-rococo-runtime = { path = "../../../../../../runtimes/assets/asset-hub-rococo" } +wococo-emulated-chain = { path = "../../../relays/wococo" } +asset-hub-rococo-emulated-chain = { path = "../asset-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs new file mode 100644 index 00000000000..677ca1763cf --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs @@ -0,0 +1,53 @@ +// 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. + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, +}; +use wococo_emulated_chain::Wococo; + +// AssetHubWococo Parachain declaration +decl_test_parachains! { + pub struct AssetHubWococo { + genesis = asset_hub_rococo_emulated_chain::genesis::genesis(), + on_init = { + asset_hub_rococo_runtime::AuraExt::on_initialize(1); + }, + runtime = asset_hub_rococo_runtime, + core = { + XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, + LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, + }, + pallets = { + 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, + } + }, +} + +// AssetHubWococo implementation +impl_accounts_helpers_for_parachain!(AssetHubWococo); +impl_assert_events_helpers_for_parachain!(AssetHubWococo); +impl_assets_helpers_for_system_parachain!(AssetHubWococo, Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..43c0f5fd14c --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "bridge-hub-rococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Rococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +bridge-hub-rococo-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs new file mode 100644 index 00000000000..299c5909670 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -0,0 +1,83 @@ +// 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. + +// Substrate +use sp_core::{sr25519, storage::Storage}; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1013; +pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { + system: bridge_hub_rococo_runtime::SystemConfig::default(), + balances: bridge_hub_rococo_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: bridge_hub_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + bridge_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..d7630954c86 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -0,0 +1,49 @@ +// 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 genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + xcm_emulator::decl_test_parachains, +}; + +// BridgeHubRococo Parachain declaration +decl_test_parachains! { + pub struct BridgeHubRococo { + genesis = genesis::genesis(), + on_init = { + bridge_hub_rococo_runtime::AuraExt::on_initialize(1); + }, + runtime = bridge_hub_rococo_runtime, + core = { + XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, + 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, + } + }, +} + +// BridgeHubRococo implementation +impl_accounts_helpers_for_parachain!(BridgeHubRococo); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml new file mode 100644 index 00000000000..e5e6fd70739 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "bridge-hub-westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Westend emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +bridge-hub-westend-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs new file mode 100644 index 00000000000..5acd3eb2c60 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -0,0 +1,75 @@ +// 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. + +// Substrate +use sp_core::{sr25519, storage::Storage}; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1013; +pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = bridge_hub_westend_runtime::RuntimeGenesisConfig { + system: bridge_hub_westend_runtime::SystemConfig::default(), + balances: bridge_hub_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: bridge_hub_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: bridge_hub_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: bridge_hub_westend_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig { + owner: Some(get_account_id_from_seed::(accounts::BOB)), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + bridge_hub_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs new file mode 100644 index 00000000000..436b65cb916 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -0,0 +1,49 @@ +// 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 genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + xcm_emulator::decl_test_parachains, +}; + +// BridgeHubWestend Parachain declaration +decl_test_parachains! { + pub struct BridgeHubWestend { + genesis = genesis::genesis(), + on_init = { + bridge_hub_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = bridge_hub_westend_runtime, + core = { + XcmpMessageHandler: bridge_hub_westend_runtime::XcmpQueue, + LocationToAccountId: bridge_hub_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: bridge_hub_westend_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: bridge_hub_westend_runtime::PolkadotXcm, + Balances: bridge_hub_westend_runtime::Balances, + } + }, +} + +// BridgeHubWestend implementation +impl_accounts_helpers_for_parachain!(BridgeHubWestend); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml new file mode 100644 index 00000000000..0b02730a50c --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "bridge-hub-wococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Wococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +bridge-hub-rococo-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-rococo" } +bridge-hub-rococo-emulated-chain = { path = "../bridge-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs new file mode 100644 index 00000000000..6807a2ab8c8 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs @@ -0,0 +1,47 @@ +// 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. + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + xcm_emulator::decl_test_parachains, +}; + +// BridgeHubWococo Parachain declaration +decl_test_parachains! { + pub struct BridgeHubWococo { + genesis = bridge_hub_rococo_emulated_chain::genesis::genesis(), + on_init = { + bridge_hub_rococo_runtime::AuraExt::on_initialize(1); + }, + runtime = bridge_hub_rococo_runtime, + core = { + XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, + 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, + } + }, +} + +// BridgeHubWococo implementation +impl_accounts_helpers_for_parachain!(BridgeHubWococo); +impl_assert_events_helpers_for_parachain!(BridgeHubWococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml new file mode 100644 index 00000000000..42aaee3f102 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "penpal-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Penpal emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs new file mode 100644 index 00000000000..8b03b599d5f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -0,0 +1,71 @@ +// 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. + +// Substrate +use sp_core::{sr25519, storage::Storage}; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +// Penpal +pub const PARA_ID_A: u32 = 2000; +pub const PARA_ID_B: u32 = 2001; +pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; + +pub fn genesis(para_id: u32) -> Storage { + let genesis_config = penpal_runtime::RuntimeGenesisConfig { + system: penpal_runtime::SystemConfig::default(), + balances: penpal_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: penpal_runtime::ParachainInfoConfig { + parachain_id: para_id.into(), + ..Default::default() + }, + collator_selection: penpal_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: penpal_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + penpal_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: penpal_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + sudo: penpal_runtime::SudoConfig { + key: Some(get_account_id_from_seed::("Alice")), + }, + ..Default::default() + }; + + build_genesis_storage_legacy( + &genesis_config, + penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs new file mode 100644 index 00000000000..8709d4e9196 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -0,0 +1,65 @@ +// 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. + +mod genesis; +pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_assert_events_helpers_for_parachain, xcm_emulator::decl_test_parachains, +}; + +// Penpal Parachain declaration +decl_test_parachains! { + pub struct PenpalA { + genesis = genesis(PARA_ID_A), + on_init = { + penpal_runtime::AuraExt::on_initialize(1); + }, + runtime = penpal_runtime, + core = { + XcmpMessageHandler: penpal_runtime::XcmpQueue, + LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, + ParachainInfo: penpal_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, + pub struct PenpalB { + genesis = genesis(PARA_ID_B), + on_init = { + penpal_runtime::AuraExt::on_initialize(1); + }, + runtime = penpal_runtime, + core = { + XcmpMessageHandler: penpal_runtime::XcmpQueue, + LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, + ParachainInfo: penpal_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, +} + +// Penpal implementation +impl_assert_events_helpers_for_parachain!(PenpalA); +impl_assert_events_helpers_for_parachain!(PenpalB); diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml new file mode 100644 index 00000000000..325c7229517 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "rococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Rococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } +sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } +beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../../../substrate/primitives/consensus/beefy" } +grandpa = { package = "sc-consensus-grandpa", path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } +pallet-im-online = { path = "../../../../../../../substrate/frame/im-online", default-features = false } + +# Polkadot +polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } +rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants", default-features = false } +rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } + +# Cumulus +parachains-common = { path = "../../../../../../parachains/common" } +emulated-integration-tests-common = { path = "../../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs new file mode 100644 index 00000000000..876df212e4c --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs @@ -0,0 +1,101 @@ +// 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. + +// Substrate +use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; +use grandpa::AuthorityId as GrandpaId; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_core::{sr25519, storage::Storage}; + +// Polkadot +use polkadot_primitives::{AssignmentId, ValidatorId}; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, get_account_id_from_seed, get_from_seed, + get_host_config, validators, +}; +use parachains_common::Balance; +use rococo_runtime_constants::currency::UNITS as ROC; + +pub const ED: Balance = rococo_runtime_constants::currency::EXISTENTIAL_DEPOSIT; +const ENDOWMENT: u128 = 1_000_000 * ROC; + +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::default(), + balances: rococo_runtime::BalancesConfig { + balances: accounts::init_balances().iter().map(|k| (k.clone(), ENDOWMENT)).collect(), + }, + 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() + }, + ..Default::default() + }; + + build_genesis_storage_legacy(&genesis_config, rococo_runtime::WASM_BINARY.unwrap()) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs new file mode 100644 index 00000000000..f806f4a5d9e --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs @@ -0,0 +1,48 @@ +// 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 genesis; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, + impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, + xcm_emulator::decl_test_relay_chains, +}; + +// Rococo declaration +decl_test_relay_chains! { + #[api_version(8)] + pub struct Rococo { + genesis = genesis::genesis(), + on_init = (), + runtime = rococo_runtime, + core = { + SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, + }, + pallets = { + XcmPallet: rococo_runtime::XcmPallet, + Sudo: rococo_runtime::Sudo, + Balances: rococo_runtime::Balances, + Hrmp: rococo_runtime::Hrmp, + } + }, +} + +// 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); diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml new file mode 100644 index 00000000000..20b9737735f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Westend emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } +sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } +beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../../../substrate/primitives/consensus/beefy" } +grandpa = { package = "sc-consensus-grandpa", path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } +pallet-im-online = { path = "../../../../../../../substrate/frame/im-online", default-features = false } +pallet-staking = { path = "../../../../../../../substrate/frame/staking", default-features = false } + +# Polkadot +polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } +westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants", default-features = false } +westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } + +# Cumulus +parachains-common = { path = "../../../../../../parachains/common" } +emulated-integration-tests-common = { path = "../../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs new file mode 100644 index 00000000000..8bdc34f0eed --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -0,0 +1,109 @@ +// 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. + +// Substrate +use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; +use grandpa::AuthorityId as GrandpaId; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_core::storage::Storage; +use sp_runtime::Perbill; + +// Polkadot +use polkadot_primitives::{AssignmentId, ValidatorId}; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage_legacy, get_from_seed, get_host_config, validators, +}; +use parachains_common::Balance; +use westend_runtime_constants::currency::UNITS as WND; + +pub const ED: Balance = westend_runtime_constants::currency::EXISTENTIAL_DEPOSIT; +const ENDOWMENT: u128 = 1_000_000 * WND; +const STASH: u128 = 100 * WND; + +fn session_keys( + babe: BabeId, + grandpa: GrandpaId, + im_online: ImOnlineId, + para_validator: ValidatorId, + para_assignment: AssignmentId, + authority_discovery: AuthorityDiscoveryId, + beefy: BeefyId, +) -> westend_runtime::SessionKeys { + westend_runtime::SessionKeys { + babe, + grandpa, + im_online, + para_validator, + para_assignment, + authority_discovery, + beefy, + } +} + +pub fn genesis() -> Storage { + let genesis_config = westend_runtime::RuntimeGenesisConfig { + system: westend_runtime::SystemConfig::default(), + balances: westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), + }, + session: westend_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::>(), + }, + staking: westend_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, westend_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: westend_runtime::BabeConfig { + authorities: Default::default(), + epoch_config: Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), + ..Default::default() + }, + configuration: westend_runtime::ConfigurationConfig { config: get_host_config() }, + ..Default::default() + }; + + build_genesis_storage_legacy(&genesis_config, westend_runtime::WASM_BINARY.unwrap()) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs new file mode 100644 index 00000000000..af45d8db4e6 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -0,0 +1,50 @@ +// 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 genesis; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, + impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, + xcm_emulator::decl_test_relay_chains, +}; + +// Westend declaration +decl_test_relay_chains! { + #[api_version(8)] + pub struct Westend { + genesis = genesis::genesis(), + on_init = (), + runtime = westend_runtime, + core = { + SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, + }, + pallets = { + XcmPallet: westend_runtime::XcmPallet, + Sudo: westend_runtime::Sudo, + Balances: westend_runtime::Balances, + Treasury: westend_runtime::Treasury, + AssetRate: westend_runtime::AssetRate, + Hrmp: westend_runtime::Hrmp, + } + }, +} + +// Westend implementation +impl_accounts_helpers_for_relay_chain!(Westend); +impl_assert_events_helpers_for_relay_chain!(Westend); +impl_hrmp_channels_helpers_for_relay_chain!(Westend); +impl_send_transact_helpers_for_relay_chain!(Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml new file mode 100644 index 00000000000..51a87954b8c --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "wococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Wococo emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } +sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } +beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../../../substrate/primitives/consensus/beefy" } +grandpa = { package = "sc-consensus-grandpa", path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } +pallet-im-online = { path = "../../../../../../../substrate/frame/im-online", default-features = false } + +# Polkadot +polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } +rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants", default-features = false } +rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } + +# Cumulus +parachains-common = { path = "../../../../../../parachains/common" } +emulated-integration-tests-common = { path = "../../../common", default-features = false } +rococo-emulated-chain = { path = "../rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs new file mode 100644 index 00000000000..a04deee330f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs @@ -0,0 +1,46 @@ +// 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. + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, + impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, + xcm_emulator::decl_test_relay_chains, +}; + +// Wococo declaration +decl_test_relay_chains! { + #[api_version(8)] + pub struct Wococo { + genesis = rococo_emulated_chain::genesis::genesis(), + on_init = (), + runtime = rococo_runtime, + core = { + SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, + }, + pallets = { + XcmPallet: rococo_runtime::XcmPallet, + Sudo: rococo_runtime::Sudo, + Balances: rococo_runtime::Balances, + Hrmp: rococo_runtime::Hrmp, + } + }, +} + +// Wococo implementation +impl_accounts_helpers_for_relay_chain!(Wococo); +impl_assert_events_helpers_for_relay_chain!(Wococo); +impl_hrmp_channels_helpers_for_relay_chain!(Wococo); +impl_send_transact_helpers_for_relay_chain!(Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 16a37e94be5..08bb284cded 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -1,11 +1,10 @@ [package] -name = "integration-tests-common" +name = "emulated-integration-tests-common" version = "1.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Common resources for integration testing with xcm-emulator" -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } @@ -21,75 +20,26 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features 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} beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../substrate/primitives/consensus/beefy" } -sc-chain-spec = { path = "../../../../../substrate/client/chain-spec", default-features = false } # Polkadot -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} 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" } -rococo-runtime = { path = "../../../../../polkadot/runtime/rococo" } -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants" } -westend-runtime = { path = "../../../../../polkadot/runtime/westend" } -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants" } 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-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" } -bridge-hub-polkadot-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-polkadot" } -bridge-hub-rococo-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-rococo" } -bridge-hub-westend-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-westend" } -xcm-emulator = { default-features = false, path = "../../../../xcm/xcm-emulator" } -cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../pallets/xcmp-queue" } +xcm-emulator = { path = "../../../../xcm/xcm-emulator", default-features = false} +cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } +asset-test-utils = { path = "../../../runtimes/assets/test-utils" } + +# Bridges bp-messages = { path = "../../../../../bridges/primitives/messages" } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages" } bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common" } - -[features] -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", - "bridge-hub-rococo-runtime/runtime-benchmarks", - "bridge-hub-westend-runtime/runtime-benchmarks", - "bridge-runtime-common/runtime-benchmarks", - "collectives-polkadot-runtime/runtime-benchmarks", - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "frame-support/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", - "pallet-staking/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "penpal-runtime/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-service/runtime-benchmarks", - "rococo-runtime/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "westend-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 deleted file mode 100644 index 1dffbccbba3..00000000000 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ /dev/null @@ -1,1219 +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. - -// Substrate -use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; -use grandpa::AuthorityId as GrandpaId; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; -use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; -use sp_consensus_babe::AuthorityId as BabeId; -use sp_core::{sr25519, storage::Storage, Pair, Public}; -#[cfg(test)] -use sp_runtime::BuildStorage; -use sp_runtime::{ - traits::{IdentifyAccount, Verify}, - MultiSignature, Perbill, -}; - -// Cumulus -use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; -use polkadot_parachain_primitives::primitives::{HeadData, ValidationCode}; -use polkadot_primitives::{AssignmentId, ValidatorId}; -use polkadot_runtime_parachains::{ - configuration::HostConfiguration, - paras::{ParaGenesisArgs, ParaKind}, -}; -use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; -use xcm; - -pub const XCM_V2: u32 = 3; -pub const XCM_V3: u32 = 2; -pub const REF_TIME_THRESHOLD: u64 = 33; -pub const PROOF_SIZE_THRESHOLD: u64 = 33; - -type AccountPublic = ::Signer; - -/// Helper function to generate a crypto pair from seed -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed. -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - -/// Helper function to build the genesis storage using given json patch and code -fn build_genesis_storage(patch: serde_json::Value, code: &[u8]) -> Storage { - let mut storage = GenesisConfigBuilderRuntimeCaller::new(code) - .get_storage_for_patch(patch) - .unwrap(); - storage - .top - .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.into()); - storage -} - -#[cfg(test)] -/// Helper function used in tests to build the genesis storage using given RuntimeGenesisConfig and -/// code Used in `legacy_vs_json_check` submods to verify storage building with JSON patch against -/// building with RuntimeGenesisConfig struct. -fn build_genesis_storage_legacy(builder: &dyn BuildStorage, code: &[u8]) -> Storage { - let mut storage = builder.build_storage().unwrap(); - storage - .top - .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.into()); - storage -} - -pub mod accounts { - use super::*; - pub const ALICE: &str = "Alice"; - pub const BOB: &str = "Bob"; - pub const CHARLIE: &str = "Charlie"; - pub const DAVE: &str = "Dave"; - pub const EVE: &str = "Eve"; - pub const FERDIE: &str = "Ferdei"; - pub const ALICE_STASH: &str = "Alice//stash"; - pub const BOB_STASH: &str = "Bob//stash"; - pub const CHARLIE_STASH: &str = "Charlie//stash"; - pub const DAVE_STASH: &str = "Dave//stash"; - pub const EVE_STASH: &str = "Eve//stash"; - pub const FERDIE_STASH: &str = "Ferdie//stash"; - pub const FERDIE_BEEFY: &str = "Ferdie//stash"; - - pub fn init_balances() -> Vec { - vec![ - get_account_id_from_seed::(ALICE), - get_account_id_from_seed::(BOB), - get_account_id_from_seed::(CHARLIE), - get_account_id_from_seed::(DAVE), - get_account_id_from_seed::(EVE), - get_account_id_from_seed::(FERDIE), - get_account_id_from_seed::(ALICE_STASH), - get_account_id_from_seed::(BOB_STASH), - get_account_id_from_seed::(CHARLIE_STASH), - get_account_id_from_seed::(DAVE_STASH), - get_account_id_from_seed::(EVE_STASH), - get_account_id_from_seed::(FERDIE_STASH), - ] - } -} - -pub mod collators { - use super::*; - - pub fn invulnerables_asset_hub_polkadot() -> Vec<(AccountId, AssetHubPolkadotAuraId)> { - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), - ] - } - - pub fn invulnerables() -> Vec<(AccountId, AuraId)> { - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - (get_account_id_from_seed::("Bob"), get_from_seed::("Bob")), - ] - } -} - -pub mod validators { - use super::*; - - pub fn initial_authorities() -> Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ImOnlineId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - )> { - vec![get_authority_keys_from_seed_no_beefy("Alice")] - } -} - -/// The default XCM version to set in genesis config. -const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; - -// Westend -pub mod westend { - use super::*; - use westend_runtime_constants::currency::UNITS as WND; - pub const ED: Balance = westend_runtime_constants::currency::EXISTENTIAL_DEPOSIT; - const ENDOWMENT: u128 = 1_000_000 * WND; - const STASH: u128 = 100 * WND; - - 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, - beefy: BeefyId, - ) -> westend_runtime::SessionKeys { - westend_runtime::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - beefy, - } - } - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ENDOWMENT)) - .collect::>(), - }, - "session": { - "keys": validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - westend::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::>(), - }, - "staking": { - "validatorCount": validators::initial_authorities().len() as u32, - "minimumValidatorCount": 1, - "stakers": validators::initial_authorities() - .iter() - .map(|x| { - (x.0.clone(), x.1.clone(), STASH, westend_runtime::StakerStatus::::Validator) - }) - .collect::>(), - "invulnerables": validators::initial_authorities() - .iter() - .map(|x| x.0.clone()) - .collect::>(), - "forceEra": pallet_staking::Forcing::ForceNone, - "slashRewardFraction": Perbill::from_percent(10), - }, - "babe": { - "epochConfig": Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), - }, - "configuration": { "config": get_host_config() }, - }); - - build_genesis_storage(genesis_config, westend_runtime::WASM_BINARY.unwrap()) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - fn genesis() -> Storage { - let genesis_config = westend_runtime::RuntimeGenesisConfig { - system: westend_runtime::SystemConfig::default(), - balances: westend_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ENDOWMENT)) - .collect(), - }, - session: westend_runtime::SessionConfig { - keys: validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - westend::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::>(), - }, - staking: westend_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, - westend_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: westend_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - configuration: westend_runtime::ConfigurationConfig { config: get_host_config() }, - ..Default::default() - }; - - build_genesis_storage_legacy(&genesis_config, westend_runtime::WASM_BINARY.unwrap()) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -// 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 = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .map(|k| (k.clone(), ENDOWMENT)) - .collect::>(), - }, - // indices: rococo_runtime::IndicesConfig { indices: vec![] }, - "session": { - "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": { - "epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), - }, - "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), - }, - "configuration": { "config": get_host_config() }, - "paras": rococo_runtime::ParasConfig { - paras: vec![ - ( - asset_hub_rococo::PARA_ID.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - asset_hub_rococo_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() - }, - "registrar": { - "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, - }, - }); - - build_genesis_storage(genesis_config, rococo_runtime::WASM_BINARY.unwrap()) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - fn genesis() -> Storage { - let genesis_config = rococo_runtime::RuntimeGenesisConfig { - system: rococo_runtime::SystemConfig::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() }, - paras: rococo_runtime::ParasConfig { - paras: vec![ - ( - asset_hub_rococo::PARA_ID.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - asset_hub_rococo_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() - }, - registrar: rococo_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage_legacy(&genesis_config, rococo_runtime::WASM_BINARY.unwrap()) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -// Asset Hub Westend -pub mod asset_hub_westend { - use super::*; - pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_westend_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }); - - build_genesis_storage( - genesis_config, - asset_hub_westend_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - fn genesis() -> Storage { - let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { - system: asset_hub_westend_runtime::SystemConfig::default(), - balances: asset_hub_westend_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_westend_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 - ) - }) - .collect(), - }, - polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage_legacy( - &genesis_config, - asset_hub_westend_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -pub mod asset_hub_rococo { - use super::*; - pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096 * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }); - - build_genesis_storage( - genesis_config, - asset_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - pub fn genesis() -> Storage { - let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { - system: asset_hub_rococo_runtime::SystemConfig::default(), - balances: asset_hub_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096 * 4096)) - .collect(), - }, - parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage_legacy( - &genesis_config, - asset_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -pub mod asset_hub_wococo { - use super::*; - pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_westend_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }); - - build_genesis_storage( - genesis_config, - asset_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - pub fn genesis() -> Storage { - let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { - system: asset_hub_rococo_runtime::SystemConfig::default(), - balances: asset_hub_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage_legacy( - &genesis_config, - asset_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -// Penpal -pub mod penpal { - use super::*; - pub const PARA_ID_A: u32 = 2000; - pub const PARA_ID_B: u32 = 2001; - pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; - - pub fn genesis(para_id: u32) -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(para_id), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - penpal_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), - }, - }); - - build_genesis_storage( - genesis_config, - penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - fn genesis(para_id: u32) -> Storage { - let genesis_config = penpal_runtime::RuntimeGenesisConfig { - system: penpal_runtime::SystemConfig::default(), - balances: penpal_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: penpal_runtime::ParachainInfoConfig { - parachain_id: para_id.into(), - ..Default::default() - }, - collator_selection: penpal_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: penpal_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - penpal_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: penpal_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - sudo: penpal_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), - }, - ..Default::default() - }; - - build_genesis_storage_legacy( - &genesis_config, - penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(101); - let j2 = genesis(101); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -// Bridge Hub Rococo & Bridge Hub Wococo -pub mod bridge_hub_rococo { - use super::*; - pub const PARA_ID: u32 = 1013; - pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "bridgeWococoGrandpa": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - }, - "bridgeRococoGrandpa": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - }, - "bridgeRococoMessages": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - }, - "bridgeWococoMessages": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - } - }); - - build_genesis_storage( - genesis_config, - bridge_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[cfg(test)] - mod legacy_vs_json_check { - use super::*; - fn genesis() -> Storage { - let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { - system: bridge_hub_rococo_runtime::SystemConfig::default(), - balances: bridge_hub_rococo_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: bridge_hub_rococo_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage_legacy( - &genesis_config, - bridge_hub_rococo_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } - - #[test] - fn test_genesis() { - let j1 = super::genesis(); - let j2 = genesis(); - - assert_eq!(j1.top, j2.top); - assert_eq!(j1.children_default, j2.children_default); - } - } -} - -// Bridge Hub Westend -pub mod bridge_hub_westend { - use super::*; - pub const PARA_ID: u32 = 1013; - pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = serde_json::json!({ - "balances": { - "balances": accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": cumulus_primitives_core::ParaId::from(PARA_ID), - }, - "collatorSelection": { - "invulnerables": collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - "candidacyBond": ED * 16, - }, - "session": { - "keys": collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_westend_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "bridgeRococoGrandpa": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - }, - "bridgeRococoMessages": { - "owner": Some(get_account_id_from_seed::(accounts::BOB)), - } - }); - - build_genesis_storage( - genesis_config, - bridge_hub_westend_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) - } -} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 613bb302e56..6c99c1614db 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -17,50 +17,53 @@ pub use codec::{Decode, Encode}; pub use paste; pub use crate::{ - constants::{PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD}, - xcm_helpers::xcm_transact_unpaid_execution, - BridgeHubRococo, BridgeHubWococo, + xcm_helpers::xcm_transact_unpaid_execution, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, }; // Substrate pub use frame_support::{ assert_ok, + sp_runtime::AccountId32, traits::fungibles::Inspect, weights::{Weight, WeightMeter}, }; pub use pallet_assets; pub use pallet_message_queue; +pub use pallet_xcm; use sp_core::Get; -// Cumulus -use bp_messages::{ - target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, MessageKey, OutboundLaneData, +// Polkadot +pub use polkadot_runtime_parachains::{ + dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, }; -use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; +pub use xcm::{ + prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm}, + v3::Error, + DoubleEncoded, +}; + +// Cumulus pub use cumulus_pallet_parachain_system; pub use cumulus_pallet_xcmp_queue; pub use cumulus_primitives_core::{ relay_chain::HrmpChannelId, DmpMessageHandler, ParaId, XcmpMessageHandler, }; -use pallet_bridge_messages::{Config, Instance1, Instance2, OutboundLanes, Pallet}; pub use parachains_common::{AccountId, Balance}; pub use xcm_emulator::{ assert_expected_events, bx, helpers::weight_within_threshold, BridgeMessage, - BridgeMessageDispatchError, BridgeMessageHandler, Chain, Parachain, RelayChain, TestExt, + BridgeMessageDispatchError, BridgeMessageHandler, Chain, Network, Parachain, RelayChain, + TestExt, }; -// Polkadot -pub use pallet_xcm; -pub use polkadot_runtime_parachains::{ - dmp, hrmp, - inclusion::{AggregateMessageOrigin, UmpQueueId}, -}; -pub use xcm::{ - prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm}, - v3::Error, - DoubleEncoded, +// Bridges +use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + LaneId, MessageKey, OutboundLaneData, }; +use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; +pub use pallet_bridge_messages::Instance2 as BridgeMessagesInstance2; +use pallet_bridge_messages::{Config, Instance1, OutboundLanes, Pallet}; pub struct BridgeHubMessageHandler { _marker: std::marker::PhantomData<(S, T, I)>, @@ -80,14 +83,6 @@ impl From for LaneIdWrapper { } } -type BridgeHubRococoRuntime = ::Runtime; -type BridgeHubWococoRuntime = ::Runtime; - -pub type RococoWococoMessageHandler = - BridgeHubMessageHandler; -pub type WococoRococoMessageHandler = - BridgeHubMessageHandler; - impl BridgeMessageHandler for BridgeHubMessageHandler where S: Config, @@ -171,12 +166,12 @@ where macro_rules! impl_accounts_helpers_for_relay_chain { ( $chain:ident ) => { $crate::impls::paste::paste! { - impl $chain { + impl $chain { /// Fund a set of accounts with a balance pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { - $crate::impls::assert_ok!(]>::Balances::force_set_balance( + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), account.0.into(), account.1, @@ -185,7 +180,7 @@ macro_rules! impl_accounts_helpers_for_relay_chain { }); } /// Fund a sovereign account based on its Parachain Id - pub fn fund_para_sovereign(amount: $crate::impls::Balance, para_id: $crate::impls::ParaId) -> sp_runtime::AccountId32 { + pub fn fund_para_sovereign(amount: $crate::impls::Balance, para_id: $crate::impls::ParaId) -> $crate::impls::AccountId32 { let sovereign_account = ::sovereign_account_id_of_child_para(para_id); Self::fund_accounts(vec![(sovereign_account.clone(), amount)]); sovereign_account @@ -199,15 +194,15 @@ macro_rules! impl_accounts_helpers_for_relay_chain { macro_rules! impl_assert_events_helpers_for_relay_chain { ( $chain:ident ) => { $crate::impls::paste::paste! { - type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; + type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; - impl $chain { + impl $chain { /// Asserts a dispatchable is completely executed and XCM sent pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::XcmPallet( + [<$chain RuntimeEvent>]::::XcmPallet( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { weight: $crate::impls::weight_within_threshold( @@ -229,7 +224,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { Self, vec![ // Dispatchable is properly executed and XCM message sent - [<$chain RuntimeEvent>]::XcmPallet( + [<$chain RuntimeEvent>]::::XcmPallet( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { weight: $crate::impls::weight_within_threshold( @@ -248,7 +243,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::XcmPallet($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, + [<$chain RuntimeEvent>]::::XcmPallet($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, ] ); } @@ -263,7 +258,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { Self, vec![ // XCM is succesfully received and proccessed - [<$chain RuntimeEvent>]::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { + [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)), weight_used, success, @@ -289,7 +284,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { macro_rules! impl_hrmp_channels_helpers_for_relay_chain { ( $chain:ident ) => { $crate::impls::paste::paste! { - impl $chain { + impl $chain { /// Init open channel request with another Parachain pub fn init_open_channel_call( recipient_para_id: $crate::impls::ParaId, @@ -329,7 +324,7 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { let relay_root_origin = ::RuntimeOrigin::root(); // Force process HRMP open channel requests without waiting for the next session - $crate::impls::assert_ok!(]>::Hrmp::force_process_hrmp_open( + $crate::impls::assert_ok!(]>::Hrmp::force_process_hrmp_open( relay_root_origin, 0 )); @@ -353,7 +348,7 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { macro_rules! impl_send_transact_helpers_for_relay_chain { ( $chain:ident ) => { $crate::impls::paste::paste! { - impl $chain { + 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, @@ -367,7 +362,7 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser); // Send XCM `Transact` - $crate::impls::assert_ok!(]>::XcmPallet::send( + $crate::impls::assert_ok!(]>::XcmPallet::send( root_origin, bx!(destination.into()), bx!(xcm), @@ -384,12 +379,12 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { macro_rules! impl_accounts_helpers_for_parachain { ( $chain:ident ) => { $crate::impls::paste::paste! { - impl $chain { + impl $chain { /// Fund a set of accounts with a balance pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { - $crate::impls::assert_ok!(]>::Balances::force_set_balance( + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), account.0.into(), account.1, @@ -406,15 +401,15 @@ macro_rules! impl_accounts_helpers_for_parachain { macro_rules! impl_assert_events_helpers_for_parachain { ( $chain:ident ) => { $crate::impls::paste::paste! { - type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; + type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; - impl $chain { + impl $chain { /// Asserts a dispatchable is completely executed and XCM sent pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::PolkadotXcm( + [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { weight: $crate::impls::weight_within_threshold( @@ -436,7 +431,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { Self, vec![ // Dispatchable is properly executed and XCM message sent - [<$chain RuntimeEvent>]::PolkadotXcm( + [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { weight: $crate::impls::weight_within_threshold( @@ -456,7 +451,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { Self, vec![ // Execution fails in the origin with `Barrier` - [<$chain RuntimeEvent>]::PolkadotXcm( + [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error(error) } ) => { error: *error == expected_error.unwrap_or(*error), @@ -470,7 +465,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, + [<$chain RuntimeEvent>]::::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {}, ] ); } @@ -480,7 +475,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::ParachainSystem( + [<$chain RuntimeEvent>]::::ParachainSystem( $crate::impls::cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } ) => {}, ] @@ -492,7 +487,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { + [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }) => { weight: $crate::impls::weight_within_threshold( @@ -512,7 +507,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { + [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: false, weight_used: weight, .. }) => { weight: $crate::impls::weight_within_threshold( @@ -530,7 +525,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed { + [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed { .. }) => { @@ -544,7 +539,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } + [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } ) => { weight: $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), @@ -561,10 +556,10 @@ macro_rules! impl_assert_events_helpers_for_parachain { } #[macro_export] -macro_rules! impl_assets_helpers_for_parachain { +macro_rules! impl_assets_helpers_for_system_parachain { ( $chain:ident, $relay_chain:ident ) => { $crate::impls::paste::paste! { - impl $chain { + impl $chain { /// Returns the encoded call for `force_create` from the assets pallet pub fn force_create_asset_call( asset_id: u32, @@ -607,19 +602,19 @@ macro_rules! impl_assets_helpers_for_parachain { amount_to_mint: u128, ) { ::execute_with(|| { - $crate::impls::assert_ok!(]>::Assets::mint( + $crate::impls::assert_ok!(]>::Assets::mint( signed_origin, id.into(), beneficiary.clone().into(), amount_to_mint )); - type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; $crate::impls::assert_expected_events!( Self, vec![ - RuntimeEvent::Assets($crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }) => { + RuntimeEvent::::Assets($crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }) => { asset_id: *asset_id == id, owner: *owner == beneficiary.clone().into(), amount: *amount == amount_to_mint, @@ -664,28 +659,28 @@ macro_rules! impl_assets_helpers_for_parachain { ) { use $crate::impls::{Parachain, Inspect, TestExt}; - <$relay_chain>::send_unpaid_transact_to_parachain_as_root( + <$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; + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; Self::assert_dmp_queue_complete(dmp_weight_threshold); $crate::impls::assert_expected_events!( Self, vec![ - RuntimeEvent::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => { + RuntimeEvent::::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => { asset_id: *asset_id == id, owner: *owner == asset_owner, }, ] ); - assert!(]>::Assets::asset_exists(id.into())); + assert!(]>::Assets::asset_exists(id.into())); }); } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 1debd50d609..74db02db003 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -13,361 +13,161 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod constants; pub mod impls; pub mod macros; pub mod xcm_helpers; -use constants::{ - accounts::{ALICE, BOB}, - asset_hub_rococo, asset_hub_westend, asset_hub_wococo, bridge_hub_rococo, bridge_hub_westend, - penpal, rococo, westend, -}; -use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; -pub use paste; +pub use xcm_emulator; // Substrate -use frame_support::traits::OnInitialize; -pub use pallet_balances; -pub use pallet_message_queue; +use grandpa::AuthorityId as GrandpaId; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_core::{sr25519, storage::Storage, Pair, Public}; +use sp_runtime::{ + traits::{IdentifyAccount, Verify}, + BuildStorage, MultiSignature, +}; + +// Polakdot +use parachains_common::BlockNumber; +use polkadot_runtime_parachains::configuration::HostConfiguration; +use xcm; // 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, DefaultParaMessageProcessor, - DefaultRelayMessageProcessor, Parachain, TestExt, -}; +use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId}; +use polkadot_primitives::{AssignmentId, ValidatorId}; +use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; -// Polkadot -pub use pallet_xcm; -pub use xcm::prelude::{AccountId32, WeightLimit}; +pub const XCM_V2: u32 = 2; +pub const XCM_V3: u32 = 3; +pub const REF_TIME_THRESHOLD: u64 = 33; +pub const PROOF_SIZE_THRESHOLD: u64 = 33; -decl_test_relay_chains! { - #[api_version(8)] - pub struct Westend { - genesis = westend::genesis(), - on_init = (), - runtime = westend_runtime, - core = { - MessageProcessor: DefaultRelayMessageProcessor, - SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - }, - pallets = { - XcmPallet: westend_runtime::XcmPallet, - Sudo: westend_runtime::Sudo, - Balances: westend_runtime::Balances, - Treasury: westend_runtime::Treasury, - AssetRate: westend_runtime::AssetRate, - } - }, - #[api_version(8)] - pub struct Rococo { - genesis = rococo::genesis(), - on_init = (), - runtime = rococo_runtime, - core = { - MessageProcessor: DefaultRelayMessageProcessor, - SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - }, - pallets = { - XcmPallet: rococo_runtime::XcmPallet, - Sudo: rococo_runtime::Sudo, - Balances: rococo_runtime::Balances, - Hrmp: rococo_runtime::Hrmp, - } - }, - #[api_version(8)] - pub struct Wococo { - genesis = rococo::genesis(), - on_init = (), - runtime = rococo_runtime, - core = { - MessageProcessor: DefaultRelayMessageProcessor, - SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - }, - pallets = { - XcmPallet: rococo_runtime::XcmPallet, - Sudo: rococo_runtime::Sudo, - Balances: rococo_runtime::Balances, - } - } -} +/// The default XCM version to set in genesis config. +pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -decl_test_parachains! { - // 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, - LocationToAccountId: asset_hub_westend_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_westend_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - 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 BridgeHubWestend { - genesis = bridge_hub_westend::genesis(), - on_init = { - bridge_hub_westend_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_westend_runtime, - core = { - XcmpMessageHandler: bridge_hub_westend_runtime::XcmpQueue, - LocationToAccountId: bridge_hub_westend_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_westend_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: bridge_hub_westend_runtime::PolkadotXcm, - Balances: bridge_hub_westend_runtime::Balances, - } - }, - 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, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - Balances: penpal_runtime::Balances, - } - }, - // 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, - LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, - Balances: bridge_hub_rococo_runtime::Balances, - } - }, - // AssetHubRococo - pub struct AssetHubRococo { - genesis = asset_hub_rococo::genesis(), - on_init = { - asset_hub_rococo_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_rococo_runtime, - core = { - XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, - LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - 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 PenpalRococoA { - genesis = penpal::genesis(penpal::PARA_ID_A), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - } - }, - pub struct PenpalRococoB { - genesis = penpal::genesis(penpal::PARA_ID_B), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_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 = { - XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, - LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, - } - }, - pub struct AssetHubWococo { - genesis = asset_hub_wococo::genesis(), - on_init = { - asset_hub_rococo_runtime::AuraExt::on_initialize(1); - // TODO: manage to set_wococo_flavor with `set_storage` - }, - runtime = asset_hub_rococo_runtime, - core = { - XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, - LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, - MessageProcessor: DefaultParaMessageProcessor, - }, - pallets = { - 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, - } - } +type AccountPublic = ::Signer; + +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() } -decl_test_networks! { - pub struct WestendMockNet { - relay_chain = Westend, - parachains = vec![ - AssetHubWestend, - BridgeHubWestend, - PenpalWestendA, - ], - bridge = () - }, - pub struct RococoMockNet { - relay_chain = Rococo, - parachains = vec![ - AssetHubRococo, - BridgeHubRococo, - PenpalRococoA, - PenpalRococoB, - ], - bridge = RococoWococoMockBridge - }, - pub struct WococoMockNet { - relay_chain = Wococo, - parachains = vec![ - AssetHubWococo, - BridgeHubWococo, - ], - bridge = WococoRococoMockBridge - } +/// Helper function to generate an account ID from seed. +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() } -decl_test_bridges! { - pub struct RococoWococoMockBridge { - source = BridgeHubRococo, - target = BridgeHubWococo, - handler = RococoWococoMessageHandler - }, - pub struct WococoRococoMockBridge { - source = BridgeHubWococo, - target = BridgeHubRococo, - handler = WococoRococoMessageHandler +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() } } -// 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); -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); - -// 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); +/// Helper function used in tests to build the genesis storage using given RuntimeGenesisConfig and +/// code Used in `legacy_vs_json_check` submods to verify storage building with JSON patch against +/// building with RuntimeGenesisConfig struct. +pub fn build_genesis_storage_legacy(builder: &dyn BuildStorage, code: &[u8]) -> Storage { + let mut storage = builder.build_storage().unwrap(); + storage + .top + .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.into()); + storage +} -// BridgeHubWestend implementation -impl_accounts_helpers_for_parachain!(BridgeHubWestend); -impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +pub mod accounts { + use super::*; + pub const ALICE: &str = "Alice"; + pub const BOB: &str = "Bob"; + pub const CHARLIE: &str = "Charlie"; + pub const DAVE: &str = "Dave"; + pub const EVE: &str = "Eve"; + pub const FERDIE: &str = "Ferdei"; + pub const ALICE_STASH: &str = "Alice//stash"; + pub const BOB_STASH: &str = "Bob//stash"; + pub const CHARLIE_STASH: &str = "Charlie//stash"; + pub const DAVE_STASH: &str = "Dave//stash"; + pub const EVE_STASH: &str = "Eve//stash"; + pub const FERDIE_STASH: &str = "Ferdie//stash"; + pub const FERDIE_BEEFY: &str = "Ferdie//stash"; + + pub fn init_balances() -> Vec { + vec![ + get_account_id_from_seed::(ALICE), + get_account_id_from_seed::(BOB), + get_account_id_from_seed::(CHARLIE), + get_account_id_from_seed::(DAVE), + get_account_id_from_seed::(EVE), + get_account_id_from_seed::(FERDIE), + get_account_id_from_seed::(ALICE_STASH), + get_account_id_from_seed::(BOB_STASH), + get_account_id_from_seed::(CHARLIE_STASH), + get_account_id_from_seed::(DAVE_STASH), + get_account_id_from_seed::(EVE_STASH), + get_account_id_from_seed::(FERDIE_STASH), + ] + } +} -// BridgeHubRococo implementation -impl_accounts_helpers_for_parachain!(BridgeHubRococo); -impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +pub mod collators { + use super::*; + + pub fn invulnerables_asset_hub_polkadot() -> Vec<(AccountId, AssetHubPolkadotAuraId)> { + vec![ + ( + get_account_id_from_seed::("Alice"), + get_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_from_seed::("Bob"), + ), + ] + } -// PenpalRococo implementations -impl_assert_events_helpers_for_parachain!(PenpalRococoA); -impl_assert_events_helpers_for_parachain!(PenpalRococoB); + pub fn invulnerables() -> Vec<(AccountId, AuraId)> { + vec![ + ( + get_account_id_from_seed::("Alice"), + get_from_seed::("Alice"), + ), + (get_account_id_from_seed::("Bob"), get_from_seed::("Bob")), + ] + } +} -decl_test_sender_receiver_accounts_parameter_types! { - // Relays - Westend { sender: ALICE, receiver: BOB }, - Rococo { sender: ALICE, receiver: BOB }, - Wococo { sender: ALICE, receiver: BOB }, - // Asset Hubs - AssetHubWestend { sender: ALICE, receiver: BOB }, - AssetHubRococo { sender: ALICE, receiver: BOB }, - AssetHubWococo { sender: ALICE, receiver: BOB }, - // Bridged Hubs - BridgeHubRococo { sender: ALICE, receiver: BOB }, - BridgeHubWococo { sender: ALICE, receiver: BOB }, - BridgeHubWestend { sender: ALICE, receiver: BOB }, - // Penpals - PenpalWestendA { sender: ALICE, receiver: BOB }, - PenpalRococoA { sender: ALICE, receiver: BOB }, - PenpalRococoB { sender: ALICE, receiver: BOB } +pub mod validators { + use super::*; + + pub fn initial_authorities() -> Vec<( + AccountId, + AccountId, + BabeId, + GrandpaId, + ImOnlineId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + )> { + vec![get_authority_keys_from_seed_no_beefy("Alice")] + } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6efe7f1731e..6ea3524ed4a 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -13,28 +13,43 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use paste; + +// Substrate +pub use pallet_balances; +pub use pallet_message_queue; +pub use pallet_xcm; + +// Polkadot +pub use xcm::prelude::{AccountId32, WeightLimit}; + +// Cumulus +pub use asset_test_utils; +pub use cumulus_pallet_xcmp_queue; +pub use xcm_emulator::Chain; + #[macro_export] macro_rules! test_parachain_is_trusted_teleporter { ( $sender_para:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { - $crate::paste::paste! { + $crate::macros::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()); + <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free; + let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone()); let fee_asset_item = 0; - let weight_limit = $crate::WeightLimit::Unlimited; + let weight_limit = $crate::macros::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; + <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; let para_destination = <$sender_para>::sibling_location_of(<$receiver_para>::para_id()); let beneficiary: MultiLocation = - $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); + $crate::macros::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 @@ -49,19 +64,19 @@ macro_rules! test_parachain_is_trusted_teleporter { weight_limit.clone(), )); - type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; + type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent; assert_expected_events!( $sender_para, vec![ RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } + $crate::macros::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } ) => {}, RuntimeEvent::XcmpQueue( - $crate::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + $crate::macros::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } ) => {}, RuntimeEvent::Balances( - $crate::pallet_balances::Event::Withdraw { who: sender, amount } + $crate::macros::pallet_balances::Event::Withdraw { who: sender, amount } ) => {}, ] ); @@ -69,16 +84,16 @@ macro_rules! test_parachain_is_trusted_teleporter { // Receive XCM message in Destination Parachain <$receiver_para>::execute_with(|| { - type RuntimeEvent = <$receiver_para as $crate::Chain>::RuntimeEvent; + type RuntimeEvent = <$receiver_para as $crate::macros::Chain>::RuntimeEvent; assert_expected_events!( $receiver_para, vec![ RuntimeEvent::Balances( - $crate::pallet_balances::Event::Deposit { who: receiver, .. } + $crate::macros::pallet_balances::Event::Deposit { who: receiver, .. } ) => {}, RuntimeEvent::MessageQueue( - $crate::pallet_message_queue::Event::Processed { success: true, .. } + $crate::macros::pallet_message_queue::Event::Processed { success: true, .. } ) => {}, ] ); @@ -86,11 +101,11 @@ macro_rules! test_parachain_is_trusted_teleporter { // 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; + <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free; let para_receiver_balance_after = - <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; + <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; let delivery_fees = <$sender_para>::execute_with(|| { - asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< + $crate::macros::asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< <$sender_xcm_config as xcm_executor::Config>::XcmSender, >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) }); @@ -99,7 +114,7 @@ macro_rules! test_parachain_is_trusted_teleporter { 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; + para_sender_balance_before = <$sender_para as $crate::macros::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 dc6d19d06f4..47e92ed075f 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -13,7 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Cumulus use parachains_common::AccountId; + +// Polkadot use xcm::{prelude::*, DoubleEncoded}; /// Helper method to build a XCM with a `Transact` instruction and paying for its execution diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml new file mode 100644 index 00000000000..713cc2ecdbb --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rococo-system-emulated-network" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Rococo System emulated network" +publish = false + +[dependencies] +# Cumulus +emulated-integration-tests-common = { path = "../../common", default-features = false } +rococo-emulated-chain = { path = "../../chains/relays/rococo" } +asset-hub-rococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-rococo" } +bridge-hub-rococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-rococo" } +penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs new file mode 100644 index 00000000000..ad22185fa70 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs @@ -0,0 +1,51 @@ +// 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 asset_hub_rococo_emulated_chain; +pub use bridge_hub_rococo_emulated_chain; +pub use penpal_emulated_chain; +pub use rococo_emulated_chain; + +use asset_hub_rococo_emulated_chain::AssetHubRococo; +use bridge_hub_rococo_emulated_chain::BridgeHubRococo; +use penpal_emulated_chain::{PenpalA, PenpalB}; +use rococo_emulated_chain::Rococo; + +// Cumulus +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, +}; + +decl_test_networks! { + pub struct RococoMockNet { + relay_chain = Rococo, + parachains = vec![ + AssetHubRococo, + BridgeHubRococo, + PenpalA, + PenpalB, + ], + bridge = () + }, +} + +decl_test_sender_receiver_accounts_parameter_types! { + RococoRelay { sender: ALICE, receiver: BOB }, + AssetHubRococoPara { sender: ALICE, receiver: BOB }, + BridgeHubRococoPara { sender: ALICE, receiver: BOB }, + PenpalAPara { sender: ALICE, receiver: BOB }, + PenpalBPara { sender: ALICE, receiver: BOB } +} diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml new file mode 100644 index 00000000000..53a6f0840a5 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rococo-wococo-system-emulated-network" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Rococo<>Wococo emulated bridged network" +publish = false + +[dependencies] +# Cumulus +emulated-integration-tests-common = { path = "../../common", default-features = false } +rococo-emulated-chain = { path = "../../chains/relays/rococo" } +wococo-emulated-chain = { path = "../../chains/relays/wococo" } +asset-hub-rococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-rococo" } +asset-hub-wococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-wococo" } +bridge-hub-rococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-rococo" } +bridge-hub-wococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-wococo" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs new file mode 100644 index 00000000000..e20dcfa6b32 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs @@ -0,0 +1,94 @@ +// 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 asset_hub_rococo_emulated_chain; +pub use asset_hub_wococo_emulated_chain; +pub use bridge_hub_rococo_emulated_chain; +pub use bridge_hub_wococo_emulated_chain; +pub use rococo_emulated_chain; +pub use wococo_emulated_chain; + +use asset_hub_rococo_emulated_chain::AssetHubRococo; +use asset_hub_wococo_emulated_chain::AssetHubWococo; +use bridge_hub_rococo_emulated_chain::BridgeHubRococo; +use bridge_hub_wococo_emulated_chain::BridgeHubWococo; +use rococo_emulated_chain::Rococo; +use wococo_emulated_chain::Wococo; + +// Cumulus +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + impls::{BridgeHubMessageHandler, BridgeMessagesInstance2}, + xcm_emulator::{ + decl_test_bridges, decl_test_networks, decl_test_sender_receiver_accounts_parameter_types, + Chain, + }, +}; + +decl_test_networks! { + pub struct RococoMockNet { + relay_chain = Rococo, + parachains = vec![ + AssetHubRococo, + BridgeHubRococo, + ], + bridge = RococoWococoMockBridge + + }, + pub struct WococoMockNet { + relay_chain = Wococo, + parachains = vec![ + AssetHubWococo, + BridgeHubWococo, + ], + bridge = WococoRococoMockBridge + }, +} + +decl_test_bridges! { + pub struct RococoWococoMockBridge { + source = BridgeHubRococoPara, + target = BridgeHubWococoPara, + handler = RococoWococoMessageHandler + }, + pub struct WococoRococoMockBridge { + source = BridgeHubWococoPara, + target = BridgeHubRococoPara, + handler = WococoRococoMessageHandler + } +} + +type BridgeHubRococoRuntime = ::Runtime; +type BridgeHubWococoRuntime = ::Runtime; + +pub type RococoWococoMessageHandler = BridgeHubMessageHandler< + BridgeHubRococoRuntime, + BridgeHubWococoRuntime, + BridgeMessagesInstance2, +>; +pub type WococoRococoMessageHandler = BridgeHubMessageHandler< + BridgeHubWococoRuntime, + BridgeHubRococoRuntime, + BridgeMessagesInstance2, +>; + +decl_test_sender_receiver_accounts_parameter_types! { + RococoRelay { sender: ALICE, receiver: BOB }, + AssetHubRococoPara { sender: ALICE, receiver: BOB }, + BridgeHubRococoPara { sender: ALICE, receiver: BOB }, + WococoRelay { sender: ALICE, receiver: BOB }, + AssetHubWococoPara { sender: ALICE, receiver: BOB }, + BridgeHubWococoPara { sender: ALICE, receiver: BOB } +} diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml new file mode 100644 index 00000000000..a4360076d6b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "westend-system-emulated-network" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Westend System emulated network" +publish = false + +[dependencies] +# Cumulus +emulated-integration-tests-common = { path = "../../common", default-features = false } +westend-emulated-chain = { path = "../../chains/relays/westend", default-features = false } +asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } +bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } +penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs new file mode 100644 index 00000000000..667b44a6986 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs @@ -0,0 +1,51 @@ +// 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 asset_hub_westend_emulated_chain; +pub use bridge_hub_westend_emulated_chain; +pub use penpal_emulated_chain; +pub use westend_emulated_chain; + +use asset_hub_westend_emulated_chain::AssetHubWestend; +use bridge_hub_westend_emulated_chain::BridgeHubWestend; +use penpal_emulated_chain::{PenpalA, PenpalB}; +use westend_emulated_chain::Westend; + +// Cumulus +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, +}; + +decl_test_networks! { + pub struct WestendMockNet { + relay_chain = Westend, + parachains = vec![ + AssetHubWestend, + BridgeHubWestend, + PenpalA, + PenpalB, + ], + bridge = () + }, +} + +decl_test_sender_receiver_accounts_parameter_types! { + WestendRelay { sender: ALICE, receiver: BOB }, + AssetHubWestendPara { sender: ALICE, receiver: BOB }, + BridgeHubWestendPara { sender: ALICE, receiver: BOB }, + PenpalAPara { sender: ALICE, receiver: BOB }, + PenpalBPara { sender: ALICE, receiver: BOB } +} diff --git a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml new file mode 100644 index 00000000000..a596617e82b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "wococo-system-emulated-network" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Wococo System emulated network" +publish = false + +[dependencies] +# Cumulus +emulated-integration-tests-common = { path = "../../common", default-features = false } +wococo-emulated-chain = { path = "../../chains/relays/wococo" } +asset-hub-wococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-wococo" } +bridge-hub-wococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-wococo" } +penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs new file mode 100644 index 00000000000..5369afe7dff --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs @@ -0,0 +1,50 @@ +// 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 asset_hub_wococo_emulated_chain; +pub use bridge_hub_wococo_emulated_chain; +pub use wococo_emulated_chain; + +use asset_hub_wococo_emulated_chain::AssetHubWococo; +use bridge_hub_wococo_emulated_chain::BridgeHubWococo; +use penpal_emulated_chain::{PenpalA, PenpalB}; +use wococo_emulated_chain::Wococo; + +// Cumulus +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, +}; + +decl_test_networks! { + pub struct WococoMockNet { + relay_chain = Wococo, + parachains = vec![ + AssetHubWococo, + BridgeHubWococo, + PenpalA, + PenpalB, + ], + bridge = () + }, +} + +decl_test_sender_receiver_accounts_parameter_types! { + WococoRelay { sender: ALICE, receiver: BOB }, + AssetHubWococoPara { sender: ALICE, receiver: BOB }, + BridgeHubWococoPara { sender: ALICE, receiver: BOB }, + PenpalAPara { sender: ALICE, receiver: BOB }, + PenpalBPara { sender: ALICE, receiver: BOB } +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..6e592f04ba1 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "asset-hub-rococo-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Asset Hub Rococo runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +assert_matches = "1.5.0" + +# Substrate +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false} +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false} +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false} +pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false} + +# Polkadot +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} +rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } + +# Cumulus +asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } +parachains-common = { path = "../../../../../../parachains/common" } +asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } +emulated-integration-tests-common = { path = "../../../common", default-features = false} +rococo-system-emulated-network ={ path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs similarity index 67% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 42f54bdf49d..11380cd1e2d 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -13,34 +13,46 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use asset_test_utils::xcm_helpers; pub use codec::Encode; + +// Substrate 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_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}, - AssetHubRococo, AssetHubRococoPallet, AssetHubRococoReceiver, AssetHubRococoSender, - BridgeHubRococo, BridgeHubRococoReceiver, PenpalRococoA, PenpalRococoAPallet, - PenpalRococoAReceiver, PenpalRococoASender, PenpalRococoB, PenpalRococoBPallet, Rococo, - RococoPallet, RococoReceiver, RococoSender, -}; -pub use parachains_common::{AccountId, Balance}; + +// Polkadot pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Rococo as RococoId}, }; -pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + +// Cumulus +pub use asset_test_utils::xcm_helpers; +pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, +}; +pub use parachains_common::{AccountId, Balance}; +pub use rococo_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, + RococoRelaySender as RococoSender, }; pub const ASSET_ID: u32 = 1; @@ -50,7 +62,7 @@ pub const ASSETS_PALLET_ID: u8 = 50; pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = 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 { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs similarity index 95% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 9c3378de226..76d93b2dbdb 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -294,14 +294,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 = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -332,14 +332,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 = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -380,8 +380,8 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { ); // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) @@ -389,7 +389,7 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { let system_para_test_args = TestContext { sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -416,8 +416,8 @@ fn reserve_transfer_asset_from_system_para_to_para() { ); // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) @@ -425,7 +425,7 @@ fn reserve_transfer_asset_from_system_para_to_para() { let system_para_test_args = TestContext { sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs similarity index 88% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 195afcd34c7..7be0463d2ec 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -33,7 +33,7 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { #[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()), + AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); // Force create and mint assets for Parachain's sovereign account @@ -60,9 +60,8 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { 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 root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()).into(); let xcm = xcm_transact_paid_execution( call, origin_kind, @@ -70,14 +69,14 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { para_sovereign_account.clone(), ); - PenpalRococoA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), bx!(xcm), )); - PenpalRococoA::assert_xcm_pallet_sent(); + PenpalA::assert_xcm_pallet_sent(); }); AssetHubRococo::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs similarity index 94% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index f9da0bf946e..e08af50c14e 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -125,7 +125,7 @@ fn swap_locally_on_chain_using_foreign_assets() { let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation { parents: 1, interior: X3( - Parachain(PenpalRococoA::para_id().into()), + Parachain(PenpalA::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), @@ -136,18 +136,18 @@ fn swap_locally_on_chain_using_foreign_assets() { .into(); let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalRococoA::para_id().into())) }; + MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }; // 1. Create asset on penpal: - PenpalRococoA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalRococoASender::get()), + PenpalA::execute_with(|| { + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(PenpalASender::get()), ASSET_ID.into(), - PenpalRococoASender::get().into(), + PenpalASender::get().into(), 1000, )); - assert!(::Assets::asset_exists(ASSET_ID)); + assert!(::Assets::asset_exists(ASSET_ID)); }); // 2. Create foreign asset on asset_hub_rococo: @@ -202,18 +202,18 @@ fn swap_locally_on_chain_using_foreign_assets() { ])); // Send XCM message from penpal => asset_hub_rococo - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalRococoA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + let sudo_penpal_origin = ::RuntimeOrigin::root(); + PenpalA::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!( - PenpalRococoA, + PenpalA, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml new file mode 100644 index 00000000000..7080abc0a44 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "asset-hub-westend-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Asset Hub Westend runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +assert_matches = "1.5.0" + +# Substrate +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false} +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +frame-system = { path = "../../../../../../../substrate/frame/system", default-features = false} +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false} +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false} +pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false} +pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false} +pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false} +pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } + +# Polkadot +polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } +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} +westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } +westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants", default-features = false } + +# Cumulus +parachains-common = { path = "../../../../../../parachains/common" } +asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } +asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } +cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } +cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } +emulated-integration-tests-common = { path = "../../../common", default-features = false} +westend-system-emulated-network ={ path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs similarity index 69% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 0133cdbed5c..e52ad448c0b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -13,8 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use asset_test_utils::xcm_helpers; pub use codec::Encode; + +// Substrate pub use frame_support::{ assert_err, assert_ok, instances::Instance2, @@ -23,25 +24,36 @@ pub use frame_support::{ traits::fungibles::Inspect, BoundedVec, }; -pub use integration_tests_common::{ - constants::{ - 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, - WestendPallet, WestendReceiver, WestendSender, -}; -pub use parachains_common::{AccountId, Balance}; + +// Polkadot pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, v3::{Error, NetworkId::Westend as WestendId}, }; -pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + +// Cumulus +pub use asset_test_utils::xcm_helpers; +pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, +}; +pub use parachains_common::{AccountId, Balance}; +pub use westend_system_emulated_network::{ + asset_hub_westend_emulated_chain::{ + genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + }, + penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, + AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, + WestendRelaySender as WestendSender, }; pub const ASSET_ID: u32 = 1; @@ -51,7 +63,7 @@ pub const ASSETS_PALLET_ID: u8 = 50; pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = 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 { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs similarity index 95% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 9b646035c29..19a203897ad 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -294,14 +294,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 = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); 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: PenpalWestendAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -336,14 +336,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 = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); 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: PenpalWestendAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -388,8 +388,8 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { ); // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) @@ -397,7 +397,7 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { let system_para_test_args = TestContext { sender: AssetHubWestendSender::get(), - receiver: PenpalWestendAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -424,8 +424,8 @@ fn reserve_transfer_asset_from_system_para_to_para() { ); // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) @@ -433,7 +433,7 @@ fn reserve_transfer_asset_from_system_para_to_para() { let system_para_test_args = TestContext { sender: AssetHubWestendSender::get(), - receiver: PenpalWestendAReceiver::get(), + receiver: PenpalAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs similarity index 87% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index e603af685bb..bda9a3e69c4 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -33,7 +33,7 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { #[test] fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()), + AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); // Force create and mint assets for Parachain's sovereign account @@ -60,9 +60,8 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let native_asset = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = - PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into(); + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into(); let xcm = xcm_transact_paid_execution( call, origin_kind, @@ -70,14 +69,14 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { para_sovereign_account.clone(), ); - PenpalWestendA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), bx!(xcm), )); - PenpalWestendA::assert_xcm_pallet_sent(); + PenpalA::assert_xcm_pallet_sent(); }); AssetHubWestend::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs similarity index 92% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index 88d44d9a4fb..a8e19f9ef4b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -114,7 +114,7 @@ fn swap_locally_on_chain_using_foreign_assets() { let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation { parents: 1, interior: X3( - Parachain(PenpalWestendA::para_id().into()), + Parachain(PenpalA::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), @@ -125,18 +125,18 @@ fn swap_locally_on_chain_using_foreign_assets() { .into(); let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalWestendA::para_id().into())) }; + MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }; // 1. Create asset on penpal: - PenpalWestendA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalWestendASender::get()), + PenpalA::execute_with(|| { + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(PenpalASender::get()), ASSET_ID.into(), - PenpalWestendASender::get().into(), + PenpalASender::get().into(), 1000, )); - assert!(::Assets::asset_exists(ASSET_ID)); + assert!(::Assets::asset_exists(ASSET_ID)); }); // 2. Create foreign asset on asset_hub_westend: @@ -190,26 +190,24 @@ fn swap_locally_on_chain_using_foreign_assets() { ])); // Send XCM message from penpal => asset_hub_westend - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalWestendA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + let sudo_penpal_origin = ::RuntimeOrigin::root(); + PenpalA::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!( - PenpalWestendA, + PenpalA, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, ] ); }); - // One block for the MessageQueue to process the message. - AssetHubWestend::execute_with(|| {}); // Receive XCM message in Assets Parachain in the next block. AssetHubWestend::execute_with(|| { assert!(::ForeignAssets::asset_exists( diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs similarity index 99% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 4fe0062dafc..57e1b93f349 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(dead_code)] // - use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs similarity index 98% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs index 7040d061f5b..32089f7ecec 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs @@ -14,8 +14,8 @@ // limitations under the License. use crate::*; +use emulated_integration_tests_common::accounts::{ALICE, BOB}; 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; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..035d9c10793 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "bridge-hub-rococo-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } + +# Polkadot +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} + +# Bridges +pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false} +bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false} + +# Cumulus +asset-test-utils = { path = "../../../../../../parachains/runtimes/assets/test-utils" } +parachains-common = { path = "../../../../../../parachains/common" } +cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false} +cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} +bridge-hub-rococo-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } +emulated-integration-tests-common = { path = "../../../common", default-features = false} +rococo-wococo-system-emulated-network ={ path = "../../../networks/rococo-wococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..19e10d23bbb --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -0,0 +1,60 @@ +// 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. + +// Substrate +pub use frame_support::assert_ok; + +// Polkadot +pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3::{ + Error, + NetworkId::{Rococo as RococoId, Wococo as WococoId}, + }, +}; + +// Bridges +pub use bp_messages::LaneId; + +// Cumulus +pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, +}; +pub use parachains_common::{AccountId, Balance}; +pub use rococo_wococo_system_emulated_network::{ + bridge_hub_rococo_emulated_chain::{ + genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, + }, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWococoPara as AssetHubWococo, + BridgeHubRococoPara as BridgeHubRococo, BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, + BridgeHubRococoParaSender as BridgeHubRococoSender, BridgeHubWococoPara as BridgeHubWococo, + RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, + RococoRelaySender as RococoSender, +}; + +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +pub const ASSETS_PALLET_ID: u8 = 50; + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/example.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/example.rs diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml new file mode 100644 index 00000000000..62b969b682f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "bridge-hub-westend-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Bridge Hub Westend runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } + +# Polkadot +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false} + +# Bridges +pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false} +bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false} + +# Cumulus +asset-test-utils = { path = "../../../../../../parachains/runtimes/assets/test-utils" } +parachains-common = { path = "../../../../../../parachains/common" } +cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false} +cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} +bridge-hub-westend-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } +emulated-integration-tests-common = { path = "../../../common", default-features = false} +westend-system-emulated-network ={ path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs new file mode 100644 index 00000000000..f406a73d18d --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -0,0 +1,56 @@ +// 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. + +// Substrate +pub use frame_support::assert_ok; + +// Polkadot +pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3::{Error, NetworkId::Rococo as RococoId}, +}; + +// Bridges +pub use bp_messages::LaneId; + +// Cumulus +pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, +}; +pub use parachains_common::{AccountId, Balance}; +pub use westend_system_emulated_network::{ + bridge_hub_westend_emulated_chain::{ + genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubWestendParaPallet as BridgeHubWestendPallet, + }, + westend_emulated_chain::{genesis::ED as ROCOCO_ED, WestendRelayPallet as WestendPallet}, + AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, + BridgeHubWestendParaSender as BridgeHubWestendSender, WestendRelay as Westend, + WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, +}; + +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +pub const ASSETS_PALLET_ID: u8 = 50; + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs similarity index 96% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs index e15a0dedab9..1fdd9441e48 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs @@ -30,7 +30,7 @@ fn example() { UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: RococoId, - destination: X1(Parachain(AssetHubRococo::para_id().into())), + destination: X1(Parachain(AssetHubWestend::para_id().into())), xcm: remote_xcm, }, ])); diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs similarity index 100% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/mod.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs similarity index 95% rename from cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs index 8dff6c29295..32639b8614b 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs @@ -18,7 +18,7 @@ use bridge_hub_westend_runtime::xcm_config::XcmConfig; #[test] fn teleport_to_other_system_parachains_works() { - let amount = BRIDGE_HUB_WESTEND_ED * 100; + let amount = BRIDGE_HUB_ROCOCO_ED * 100; let native_asset: MultiAssets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index f11a3d5c5af..7ff5512d214 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -170,30 +170,21 @@ pub trait Network { relay_parent_number: u32, parent_head_data: HeadData, ) -> ParachainInherentData; -} - -pub trait NetworkComponent { - type Network: Network; - fn send_horizontal_messages)>>( to_para_id: u32, iter: I, ) { HORIZONTAL_MESSAGES.with(|b| { b.borrow_mut() - .get_mut(Self::Network::name()) + .get_mut(Self::name()) .unwrap() .push_back((to_para_id, iter.collect())) }); } fn send_upward_message(from_para_id: u32, msg: Vec) { - UPWARD_MESSAGES.with(|b| { - b.borrow_mut() - .get_mut(Self::Network::name()) - .unwrap() - .push_back((from_para_id, msg)) - }); + UPWARD_MESSAGES + .with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((from_para_id, msg))); } fn send_downward_messages( @@ -202,19 +193,19 @@ pub trait NetworkComponent { ) { DOWNWARD_MESSAGES.with(|b| { b.borrow_mut() - .get_mut(Self::Network::name()) + .get_mut(Self::name()) .unwrap() .push_back((to_para_id, iter.collect())) }); } fn send_bridged_messages(msg: BridgeMessage) { - BRIDGED_MESSAGES - .with(|b| b.borrow_mut().get_mut(Self::Network::name()).unwrap().push_back(msg)); + BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back(msg)); } } -pub trait Chain: TestExt + NetworkComponent { +pub trait Chain: TestExt { + type Network: Network; type Runtime: SystemConfig; type RuntimeCall; type RuntimeOrigin; @@ -234,6 +225,8 @@ pub trait RelayChain: Chain { type SovereignAccountOf: ConvertLocation>; type MessageProcessor: ProcessMessage + ServiceQueues; + fn init(); + fn child_location_of(id: ParaId) -> MultiLocation { (Ancestor(0), ParachainJunction(id.into())).into() } @@ -348,7 +341,6 @@ macro_rules! decl_test_relay_chains { on_init = $on_init:expr, runtime = $runtime:ident, core = { - MessageProcessor: $mp:path, SovereignAccountOf: $sovereign_acc_of:path, }, pallets = { @@ -361,9 +353,10 @@ macro_rules! decl_test_relay_chains { ) => { $( #[derive(Clone)] - pub struct $name; + pub struct $name($crate::PhantomData); - impl $crate::Chain for $name { + impl $crate::Chain for $name { + type Network = N; type Runtime = $runtime::Runtime; type RuntimeCall = $runtime::RuntimeCall; type RuntimeOrigin = $runtime::RuntimeOrigin; @@ -382,27 +375,35 @@ macro_rules! decl_test_relay_chains { } } - impl $crate::RelayChain for $name { + impl $crate::RelayChain for $name { type SovereignAccountOf = $sovereign_acc_of; - type MessageProcessor = $mp; + type MessageProcessor = $crate::DefaultRelayMessageProcessor<$name>; + + fn init() { + use $crate::TestExt; + // Initialize the thread local variable + $crate::paste::paste! { + [].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis)); + } + } } $crate::paste::paste! { - pub trait [<$name Pallet>] { + pub trait [<$name RelayPallet>] { $( type $pallet_name; )? } - impl [<$name Pallet>] for $name { + impl [<$name RelayPallet>] for $name { $( type $pallet_name = $pallet_path; )? } } - $crate::__impl_test_ext_for_relay_chain!($name, $genesis, $on_init, $api_version); - $crate::__impl_check_assertion!($name); + $crate::__impl_test_ext_for_relay_chain!($name, N, $genesis, $on_init, $api_version); + $crate::__impl_check_assertion!($name, N); )+ }; } @@ -410,10 +411,11 @@ macro_rules! decl_test_relay_chains { #[macro_export] macro_rules! __impl_test_ext_for_relay_chain { // entry point: generate ext name - ($name:ident, $genesis:expr, $on_init:expr, $api_version:tt) => { + ($name:ident, $network:ident, $genesis:expr, $on_init:expr, $api_version:tt) => { $crate::paste::paste! { $crate::__impl_test_ext_for_relay_chain!( @impl $name, + $network, $genesis, $on_init, [], @@ -423,10 +425,10 @@ macro_rules! __impl_test_ext_for_relay_chain { } }; // impl - (@impl $name:ident, $genesis:expr, $on_init:expr, $api_version:ident, $local_ext:ident, $global_ext:ident) => { + (@impl $name:ident, $network:ident, $genesis:expr, $on_init:expr, $api_version:ident, $local_ext:ident, $global_ext:ident) => { thread_local! { pub static $local_ext: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new(<$name as $crate::TestExt>::build_new_ext($genesis)); + = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } $crate::lazy_static! { @@ -434,9 +436,9 @@ macro_rules! __impl_test_ext_for_relay_chain { = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); } - impl $crate::TestExt for $name { + impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { - use $crate::{sp_tracing, NetworkComponent, Network, Chain, TestExternalities}; + use $crate::{sp_tracing, Network, Chain, TestExternalities}; let mut ext = TestExternalities::new(storage); @@ -453,7 +455,7 @@ macro_rules! __impl_test_ext_for_relay_chain { } fn new_ext() -> $crate::TestExternalities { - <$name>::build_new_ext($genesis) + Self::build_new_ext($genesis) } fn move_ext_out(id: &'static str) { @@ -504,13 +506,13 @@ macro_rules! __impl_test_ext_for_relay_chain { } fn reset_ext() { - $local_ext.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); + $local_ext.with(|v| *v.borrow_mut() = Self::build_new_ext($genesis)); } fn execute_with(execute: impl FnOnce() -> R) -> R { - use $crate::{Chain, NetworkComponent, Network}; + use $crate::{Chain, Network}; // Make sure the Network is initialized - <$name as NetworkComponent>::Network::init(); + <$network>::init(); // Execute let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); @@ -521,7 +523,7 @@ macro_rules! __impl_test_ext_for_relay_chain { use $crate::polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::$api_version; //TODO: mark sent count & filter out sent msg - for para_id in<$name as NetworkComponent>::Network::para_ids() { + for para_id in <$network>::para_ids() { // downward messages let downward_messages = ::Runtime::dmq_contents(para_id.into()) .into_iter() @@ -529,7 +531,7 @@ macro_rules! __impl_test_ext_for_relay_chain { if downward_messages.len() == 0 { continue; } - <$name>::send_downward_messages(para_id, downward_messages.into_iter()); + <$network>::send_downward_messages(para_id, downward_messages.into_iter()); // Note: no need to handle horizontal messages, as the // simulator directly sends them to dest (not relayed). @@ -545,7 +547,7 @@ macro_rules! __impl_test_ext_for_relay_chain { }) }); - <$name as NetworkComponent>::Network::process_messages(); + <$network>::process_messages(); r } @@ -574,7 +576,7 @@ macro_rules! decl_test_parachains { XcmpMessageHandler: $xcmp_message_handler:path, LocationToAccountId: $location_to_account:path, ParachainInfo: $parachain_info:path, - MessageProcessor: $message_processor:path, + // MessageProcessor: $message_processor:path, }, pallets = { $($pallet_name:ident: $pallet_path:path,)* @@ -586,14 +588,15 @@ macro_rules! decl_test_parachains { ) => { $( #[derive(Clone)] - pub struct $name; + pub struct $name($crate::PhantomData); - impl $crate::Chain for $name { + impl $crate::Chain for $name { type Runtime = $runtime::Runtime; type RuntimeCall = $runtime::RuntimeCall; type RuntimeOrigin = $runtime::RuntimeOrigin; type RuntimeEvent = $runtime::RuntimeEvent; type System = $crate::SystemPallet::; + type Network = N; fn account_data_of(account: $crate::AccountIdOf) -> $crate::AccountData<$crate::Balance> { ::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) @@ -607,17 +610,21 @@ macro_rules! decl_test_parachains { } } - impl $crate::Parachain for $name { + impl $crate::Parachain for $name { type XcmpMessageHandler = $xcmp_message_handler; type LocationToAccountId = $location_to_account; type ParachainSystem = $crate::ParachainSystemPallet<::Runtime>; type ParachainInfo = $parachain_info; - type MessageProcessor = $message_processor; + type MessageProcessor = $crate::DefaultParaMessageProcessor<$name>; // We run an empty block during initialisation to open HRMP channels // and have them ready for the next block fn init() { - use $crate::{Chain, HeadData, Network, NetworkComponent, Hooks, Encode, Parachain, TestExt}; + use $crate::{Chain, HeadData, Network, Hooks, Encode, Parachain, TestExt}; + // Initialize the thread local variable + $crate::paste::paste! { + [].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis)); + } // Set the last block head for later use in the next block Self::set_last_head(); // Initialize a new block @@ -627,21 +634,21 @@ macro_rules! decl_test_parachains { } fn new_block() { - use $crate::{Chain, HeadData, Network, NetworkComponent, Hooks, Encode, Parachain, TestExt}; + use $crate::{Chain, HeadData, Network, Hooks, Encode, Parachain, TestExt}; let para_id = Self::para_id().into(); Self::ext_wrapper(|| { // Increase Relay Chain block number - let mut relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); + let mut relay_block_number = N::relay_block_number(); relay_block_number += 1; - <$name as NetworkComponent>::Network::set_relay_block_number(relay_block_number); + N::set_relay_block_number(relay_block_number); // Initialize a new Parachain block let mut block_number = ::System::block_number(); block_number += 1; let parent_head_data = $crate::LAST_HEAD.with(|b| b.borrow_mut() - .get_mut(::Network::name()) + .get_mut(N::name()) .expect("network not initialized?") .get(¶_id) .expect("network not initialized?") @@ -652,13 +659,13 @@ macro_rules! decl_test_parachains { let _ = ::ParachainSystem::set_validation_data( ::RuntimeOrigin::none(), - <$name as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), + N::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), ); }); } fn finalize_block() { - use $crate::{Chain, Encode, Hooks, Network, NetworkComponent, Parachain, TestExt}; + use $crate::{Chain, Encode, Hooks, Network, Parachain, TestExt}; Self::ext_wrapper(|| { let block_number = ::System::block_number(); @@ -670,7 +677,7 @@ macro_rules! decl_test_parachains { fn set_last_head() { - use $crate::{Chain, Encode, HeadData, Network, NetworkComponent, Parachain, TestExt}; + use $crate::{Chain, Encode, HeadData, Network, Parachain, TestExt}; let para_id = Self::para_id().into(); @@ -678,7 +685,7 @@ macro_rules! decl_test_parachains { // Store parent head data for use later. let created_header = ::System::finalize(); $crate::LAST_HEAD.with(|b| b.borrow_mut() - .get_mut(::Network::name()) + .get_mut(N::name()) .expect("network not initialized?") .insert(para_id, HeadData(created_header.encode())) ); @@ -687,21 +694,21 @@ macro_rules! decl_test_parachains { } $crate::paste::paste! { - pub trait [<$name Pallet>] { + pub trait [<$name ParaPallet>] { $( type $pallet_name; )* } - impl [<$name Pallet>] for $name { + impl [<$name ParaPallet>] for $name { $( type $pallet_name = $pallet_path; )* } } - $crate::__impl_test_ext_for_parachain!($name, $genesis, $on_init); - $crate::__impl_check_assertion!($name); + $crate::__impl_test_ext_for_parachain!($name, N, $genesis, $on_init); + $crate::__impl_check_assertion!($name, N); )+ }; } @@ -709,16 +716,16 @@ macro_rules! decl_test_parachains { #[macro_export] macro_rules! __impl_test_ext_for_parachain { // entry point: generate ext name - ($name:ident, $genesis:expr, $on_init:expr) => { + ($name:ident, $network:ident, $genesis:expr, $on_init:expr) => { $crate::paste::paste! { - $crate::__impl_test_ext_for_parachain!(@impl $name, $genesis, $on_init, [], []); + $crate::__impl_test_ext_for_parachain!(@impl $name, $network, $genesis, $on_init, [], []); } }; // impl - (@impl $name:ident, $genesis:expr, $on_init:expr, $local_ext:ident, $global_ext:ident) => { + (@impl $name:ident, $network:ident, $genesis:expr, $on_init:expr, $local_ext:ident, $global_ext:ident) => { thread_local! { pub static $local_ext: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new(<$name as $crate::TestExt>::build_new_ext($genesis)); + = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } $crate::lazy_static! { @@ -726,7 +733,7 @@ macro_rules! __impl_test_ext_for_parachain { = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); } - impl $crate::TestExt for $name { + impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { let mut ext = $crate::TestExternalities::new(storage); @@ -743,7 +750,7 @@ macro_rules! __impl_test_ext_for_parachain { } fn new_ext() -> $crate::TestExternalities { - <$name>::build_new_ext($genesis) + Self::build_new_ext($genesis) } fn move_ext_out(id: &'static str) { @@ -794,14 +801,14 @@ macro_rules! __impl_test_ext_for_parachain { } fn reset_ext() { - $local_ext.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); + $local_ext.with(|v| *v.borrow_mut() = Self::build_new_ext($genesis)); } fn execute_with(execute: impl FnOnce() -> R) -> R { - use $crate::{Chain, Get, Hooks, NetworkComponent, Network, Parachain, Encode}; + use $crate::{Chain, Get, Hooks, Network, Parachain, Encode}; // Make sure the Network is initialized - <$name as NetworkComponent>::Network::init(); + <$network>::init(); // Initialize a new block Self::new_block(); @@ -812,7 +819,7 @@ macro_rules! __impl_test_ext_for_parachain { // Finalize the block Self::finalize_block(); - let para_id = <$name>::para_id().into(); + let para_id = Self::para_id().into(); // Send messages if needed $local_ext.with(|v| { @@ -828,27 +835,27 @@ macro_rules! __impl_test_ext_for_parachain { let collation_info = ::ParachainSystem::collect_collation_info(&mock_header); // send upward messages - let relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); + let relay_block_number = <$network>::relay_block_number(); for msg in collation_info.upward_messages.clone() { - <$name>::send_upward_message(para_id, msg); + <$network>::send_upward_message(para_id, msg); } // send horizontal messages for msg in collation_info.horizontal_messages { - <$name>::send_horizontal_messages( + <$network>::send_horizontal_messages( msg.recipient.into(), vec![(para_id.into(), relay_block_number, msg.data)].into_iter(), ); } // get bridge messages - type NetworkBridge = <<$name as NetworkComponent>::Network as $crate::Network>::Bridge; + type NetworkBridge<$network> = <$network as $crate::Network>::Bridge; - let bridge_messages = <::Handler as $crate::BridgeMessageHandler>::get_source_outbound_messages(); + let bridge_messages = < as $crate::Bridge>::Handler as $crate::BridgeMessageHandler>::get_source_outbound_messages(); // send bridged messages for msg in bridge_messages { - <$name>::send_bridged_messages(msg); + <$network>::send_bridged_messages(msg); } // log events @@ -864,7 +871,7 @@ macro_rules! __impl_test_ext_for_parachain { // provide inbound DMP/HRMP messages through a side-channel. // normally this would come through the `set_validation_data`, // but we go around that. - <$name as NetworkComponent>::Network::process_messages(); + <$network>::process_messages(); r } @@ -886,8 +893,8 @@ macro_rules! decl_test_networks { ( $( pub struct $name:ident { - relay_chain = $relay_chain:ty, - parachains = vec![ $( $parachain:ty, )* ], + relay_chain = $relay_chain:ident, + parachains = vec![ $( $parachain:ident, )* ], bridge = $bridge:ty } ), @@ -895,10 +902,11 @@ macro_rules! decl_test_networks { $(,)? ) => { $( + #[derive(Clone)] pub struct $name; impl $crate::Network for $name { - type Relay = $relay_chain; + type Relay = $relay_chain; type Bridge = $bridge; fn name() -> &'static str { @@ -916,8 +924,8 @@ macro_rules! decl_test_networks { $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); $crate::LAST_HEAD.with(|b| b.borrow_mut().remove(Self::name())); - <$relay_chain>::reset_ext(); - $( <$parachain>::reset_ext(); )* + <$relay_chain>::reset_ext(); + $( <$parachain>::reset_ext(); )* } fn init() { @@ -932,13 +940,14 @@ macro_rules! decl_test_networks { $crate::PARA_IDS.with(|b| b.borrow_mut().insert(Self::name().to_string(), Self::para_ids())); $crate::LAST_HEAD.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::HashMap::new())); - $( <$parachain as $crate::Parachain>::init(); )* + <$relay_chain as $crate::RelayChain>::init(); + $( <$parachain as $crate::Parachain>::init(); )* } } fn para_ids() -> Vec { vec![$( - <$parachain as $crate::Parachain>::para_id().into(), + <$parachain as $crate::Parachain>::para_id().into(), )*] } @@ -976,7 +985,7 @@ macro_rules! decl_test_networks { while let Some((to_para_id, messages)) = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { $( - let para_id: u32 = <$parachain>::para_id().into(); + let para_id: u32 = <$parachain>::para_id().into(); if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id { let mut msg_dedup: Vec<(RelayChainBlockNumber, Vec)> = Vec::new(); @@ -986,21 +995,21 @@ macro_rules! decl_test_networks { msg_dedup.dedup(); let msgs = msg_dedup.clone().into_iter().filter(|m| { - !$crate::DMP_DONE.with(|b| b.borrow().get(stringify!($name)) + !$crate::DMP_DONE.with(|b| b.borrow().get(Self::name()) .unwrap_or(&mut $crate::VecDeque::new()) .contains(&(to_para_id, m.0, m.1.clone())) ) }).collect::)>>(); - use $crate::{ProcessMessage, CumulusAggregateMessageOrigin, BoundedSlice, WeightMeter, TestExt}; + use $crate::{ProcessMessage, CumulusAggregateMessageOrigin, BoundedSlice, WeightMeter}; for (block, msg) in msgs.clone().into_iter() { let mut weight_meter = WeightMeter::new(); - <$parachain>::ext_wrapper(|| { - let _ = <$parachain as Parachain>::MessageProcessor::process_message( + <$parachain>::ext_wrapper(|| { + let _ = <$parachain as Parachain>::MessageProcessor::process_message( &msg[..], $crate::CumulusAggregateMessageOrigin::Parent, &mut weight_meter, - &mut msg.using_encoded(sp_core::blake2_256), + &mut msg.using_encoded($crate::blake2_256), ); }); $crate::log::debug!(target: concat!("dmp::", stringify!($name)) , "DMP messages processed {:?} to para_id {:?}", msgs.clone(), &to_para_id); @@ -1012,19 +1021,19 @@ macro_rules! decl_test_networks { } fn process_horizontal_messages() { - use $crate::{XcmpMessageHandler, ServiceQueues, Bounded}; + use $crate::{XcmpMessageHandler, ServiceQueues, Bounded, Parachain, TestExt}; while let Some((to_para_id, messages)) = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { let iter = messages.iter().map(|(p, b, m)| (*p, *b, &m[..])).collect::>().into_iter(); $( - let para_id: u32 = <$parachain>::para_id().into(); + let para_id: u32 = <$parachain>::para_id().into(); if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id { - <$parachain>::ext_wrapper(|| { - <$parachain as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::MAX); + <$parachain>::ext_wrapper(|| { + <$parachain as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::MAX); // Nudge the MQ pallet to process immediately instead of in the next block. - let _ = <$parachain as Parachain>::MessageProcessor::service_queues($crate::Weight::MAX); + let _ = <$parachain as Parachain>::MessageProcessor::service_queues($crate::Weight::MAX); }); $crate::log::debug!(target: concat!("hrmp::", stringify!($name)) , "HRMP messages processed {:?} to para_id {:?}", &messages, &to_para_id); } @@ -1037,8 +1046,8 @@ macro_rules! decl_test_networks { while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { let mut weight_meter = WeightMeter::new(); - <$relay_chain>::ext_wrapper(|| { - let _ = <$relay_chain as $crate::RelayChain>::MessageProcessor::process_message( + <$relay_chain>::ext_wrapper(|| { + let _ = <$relay_chain as $crate::RelayChain>::MessageProcessor::process_message( &msg[..], from_para_id.into(), &mut weight_meter, @@ -1121,13 +1130,13 @@ macro_rules! decl_test_networks { } } - impl $crate::NetworkComponent for $relay_chain { - type Network = $name; + $crate::paste::paste! { + pub type [<$relay_chain Relay>] = $relay_chain<$name>; } $( - impl $crate::NetworkComponent for $parachain { - type Network = $name; + $crate::paste::paste! { + pub type [<$parachain Para>] = $parachain<$name>; } )* )+ @@ -1139,9 +1148,9 @@ macro_rules! decl_test_bridges { ( $( pub struct $name:ident { - source = $source:ty, - target = $target:ty, - handler = $handler:ty + source = $source:ident, + target = $target:ident, + handler = $handler:ident } ), + @@ -1157,10 +1166,10 @@ macro_rules! decl_test_bridges { type Handler = $handler; fn init() { - use $crate::{NetworkComponent, Network}; + use $crate::{Network, Parachain}; // Make sure source and target `Network` have been initialized - <$source as NetworkComponent>::Network::init(); - <$target as NetworkComponent>::Network::init(); + <$source as Chain>::Network::init(); + <$target as Chain>::Network::init(); } } )+ @@ -1169,10 +1178,11 @@ macro_rules! decl_test_bridges { #[macro_export] macro_rules! __impl_check_assertion { - ($chain:ident) => { - impl - $crate::CheckAssertion for $chain + ($chain:ident, $network:ident) => { + impl<$network, Origin, Destination, Hops, Args> + $crate::CheckAssertion for $chain<$network> where + $network: $crate::Network, Origin: $crate::Chain + Clone, Destination: $crate::Chain + Clone, Origin::RuntimeOrigin: @@ -1185,9 +1195,9 @@ macro_rules! __impl_check_assertion { fn check_assertion(test: $crate::Test) { use $crate::TestExt; - let chain_name = std::any::type_name::<$chain>(); + let chain_name = std::any::type_name::<$chain<$network>>(); - <$chain>::execute_with(|| { + <$chain<$network>>::execute_with(|| { if let Some(dispatchable) = test.hops_dispatchable.get(chain_name) { $crate::assert_ok!(dispatchable(test.clone())); } @@ -1213,7 +1223,6 @@ macro_rules! assert_expected_events { let mut event_message: Vec = Vec::new(); for (index, event) in events.iter().enumerate() { - $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); // Have to reset the variable to override a previous partial match meet_conditions = true; match event { @@ -1259,7 +1268,14 @@ macro_rules! assert_expected_events { ) ); } else if !event_received { - message.push(format!("\n\n{}::\x1b[31m{}\x1b[0m was never received. All events:\n{:#?}", stringify!($chain), stringify!($event_pat), <$chain>::events())); + message.push( + format!( + "\n\n{}::\x1b[31m{}\x1b[0m was never received. All events:\n{:#?}", + stringify!($chain), + stringify!($event_pat), + <$chain as $crate::Chain>::events(), + ) + ); } else { // If we find a perfect match we remove the event to avoid being potentially assessed multiple times events.remove(index_match); -- GitLab From b8acc57c503f0b8fa12bb0c01517f63fc7ea6996 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:31:37 +0100 Subject: [PATCH 468/633] `sc-chain-spec`: add support for custom host functions (#2190) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Genesis building in runtime may involve calling some custom host functions. This PR allows to pass `HostFunctions` into the `ChainSpec` struct, which in turn are passed to `WasmExecutor`. The `ChainSpec` now has extended host functions type parameter: ``` pub struct ChainSpec ``` which will be combined with the default set (`sp_io::SubstrateHostFunctions`) in an instance of `WasmExecutor` used to build the genesis config. Fix for #2188 --------- Co-authored-by: Davide Galassi Co-authored-by: Bastian Köcher --- .../bin/utils/chain-spec-builder/src/lib.rs | 3 +- substrate/client/chain-spec/src/chain_spec.rs | 86 ++++++++++++------- .../chain-spec/src/genesis_config_builder.rs | 27 ++++-- 3 files changed, 79 insertions(+), 37 deletions(-) diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 50a8dd08996..6f21b68c368 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -338,7 +338,8 @@ pub fn generate_chain_spec_for_runtime(cmd: &RuntimeCmd) -> Result { - let caller = GenesisConfigBuilderRuntimeCaller::new(&code[..]); + let caller: GenesisConfigBuilderRuntimeCaller = + GenesisConfigBuilderRuntimeCaller::new(&code[..]); let default_config = caller .get_default_config() .map_err(|e| format!("getting default config from runtime should work: {e}"))?; diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index a44a3b4fbd9..8d97d941022 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -19,8 +19,8 @@ //! Substrate chain configurations. #![warn(missing_docs)] use crate::{ - extension::GetExtension, ChainType, GenesisConfigBuilderRuntimeCaller as RuntimeCaller, - Properties, RuntimeGenesis, + extension::GetExtension, genesis_config_builder::HostFunctions, ChainType, + GenesisConfigBuilderRuntimeCaller as RuntimeCaller, Properties, RuntimeGenesis, }; use sc_network::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; @@ -122,7 +122,10 @@ impl GenesisSource { } } -impl BuildStorage for ChainSpec { +impl BuildStorage for ChainSpec +where + EHF: HostFunctions, +{ fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { match self.genesis.resolve()? { #[allow(deprecated)] @@ -158,7 +161,7 @@ impl BuildStorage for ChainSpec { json_blob: RuntimeGenesisConfigJson::Config(config), code, }) => { - RuntimeCaller::new(&code[..]) + RuntimeCaller::::new(&code[..]) .get_storage_for_config(config)? .assimilate_storage(storage)?; storage @@ -169,7 +172,7 @@ impl BuildStorage for ChainSpec { json_blob: RuntimeGenesisConfigJson::Patch(patch), code, }) => { - RuntimeCaller::new(&code[..]) + RuntimeCaller::::new(&code[..]) .get_storage_for_patch(patch)? .assimilate_storage(storage)?; storage @@ -322,7 +325,7 @@ struct ClientSpec { pub type NoExtension = Option<()>; /// Builder for creating [`ChainSpec`] instances. -pub struct ChainSpecBuilder { +pub struct ChainSpecBuilder { code: Vec, extensions: E, name: String, @@ -334,10 +337,10 @@ pub struct ChainSpecBuilder { protocol_id: Option, fork_id: Option, properties: Option, - _genesis: PhantomData, + _genesis: PhantomData<(G, EHF)>, } -impl ChainSpecBuilder { +impl ChainSpecBuilder { /// Creates a new builder instance with no defaults. pub fn new(code: &[u8], extensions: E) -> Self { Self { @@ -429,7 +432,7 @@ impl ChainSpecBuilder { } /// Builds a [`ChainSpec`] instance using the provided settings. - pub fn build(self) -> ChainSpec { + pub fn build(self) -> ChainSpec { let client_spec = ClientSpec { name: self.name, id: self.id, @@ -448,23 +451,33 @@ impl ChainSpecBuilder { ChainSpec { client_spec, genesis: GenesisSource::GenesisBuilderApi(self.genesis_build_action, self.code.into()), + _host_functions: Default::default(), } } } /// A configuration of a chain. Can be used to build a genesis block. -pub struct ChainSpec { +/// +/// The chain spec is generic over the native `RuntimeGenesisConfig` struct (`G`). It is also +/// possible to parametrize chain spec over the extended host functions (EHF). It should be use if +/// runtime is using the non-standard host function during genesis state creation. +pub struct ChainSpec { client_spec: ClientSpec, genesis: GenesisSource, + _host_functions: PhantomData, } -impl Clone for ChainSpec { +impl Clone for ChainSpec { fn clone(&self) -> Self { - ChainSpec { client_spec: self.client_spec.clone(), genesis: self.genesis.clone() } + ChainSpec { + client_spec: self.client_spec.clone(), + genesis: self.genesis.clone(), + _host_functions: self._host_functions, + } } } -impl ChainSpec { +impl ChainSpec { /// A list of bootnode addresses. pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] { &self.client_spec.boot_nodes @@ -553,6 +566,7 @@ impl ChainSpec { ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor), code.into()), + _host_functions: Default::default(), } } @@ -562,19 +576,23 @@ impl ChainSpec { } /// Provides a `ChainSpec` builder. - pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder { + pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder { ChainSpecBuilder::new(code, extensions) } } -impl ChainSpec { +impl ChainSpec { /// Parse json content into a `ChainSpec` pub fn from_json_bytes(json: impl Into>) -> Result { let json = json.into(); let client_spec = json::from_slice(json.as_ref()) .map_err(|e| format!("Error parsing spec file: {}", e))?; - Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) }) + Ok(ChainSpec { + client_spec, + genesis: GenesisSource::Binary(json), + _host_functions: Default::default(), + }) } /// Parse json file into a `ChainSpec` @@ -593,7 +611,11 @@ impl ChainSpec { genesis: Genesis, } -impl ChainSpec { +impl ChainSpec +where + EHF: HostFunctions, +{ fn json_container(&self, raw: bool) -> Result, String> { let raw_genesis = match (raw, self.genesis.resolve()?) { ( @@ -618,7 +643,8 @@ impl ChainSpec { code, }), ) => { - let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_config(config)?; + let mut storage = + RuntimeCaller::::new(&code[..]).get_storage_for_config(config)?; storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); RawGenesis::from(storage) }, @@ -629,7 +655,8 @@ impl ChainSpec { code, }), ) => { - let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_patch(patch)?; + let mut storage = + RuntimeCaller::::new(&code[..]).get_storage_for_patch(patch)?; storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code); RawGenesis::from(storage) }, @@ -664,10 +691,11 @@ impl ChainSpec { } } -impl crate::ChainSpec for ChainSpec +impl crate::ChainSpec for ChainSpec where G: RuntimeGenesis + 'static, E: GetExtension + serde::Serialize + Clone + Send + Sync + 'static, + EHF: HostFunctions, { fn boot_nodes(&self) -> &[MultiaddrWithPeerId] { ChainSpec::boot_nodes(self) @@ -953,7 +981,7 @@ mod tests { #[docify::export] #[test] fn build_chain_spec_with_patch_works() { - let output: ChainSpec<()> = ChainSpec::builder( + let output = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -986,7 +1014,7 @@ mod tests { #[docify::export] #[test] fn generate_chain_spec_with_patch_works() { - let output: ChainSpec<()> = ChainSpec::builder( + let output = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1033,7 +1061,7 @@ mod tests { #[test] fn generate_chain_spec_with_full_config_works() { let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); - let output: ChainSpec<()> = ChainSpec::builder( + let output = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1065,7 +1093,7 @@ mod tests { fn chain_spec_as_json_fails_with_invalid_config() { let j = include_str!("../../../test-utils/runtime/res/default_genesis_config_invalid_2.json"); - let output: ChainSpec<()> = ChainSpec::builder( + let output = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1083,7 +1111,7 @@ mod tests { #[test] fn chain_spec_as_json_fails_with_invalid_patch() { - let output: ChainSpec<()> = ChainSpec::builder( + let output = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1139,7 +1167,7 @@ mod tests { #[test] fn update_code_works_with_runtime_genesis_config() { let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); - let chain_spec: ChainSpec<()> = ChainSpec::builder( + let chain_spec = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1162,7 +1190,7 @@ mod tests { #[test] fn update_code_works_for_raw() { let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json"); - let chain_spec: ChainSpec<()> = ChainSpec::builder( + let chain_spec = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) @@ -1184,7 +1212,7 @@ mod tests { #[test] fn update_code_works_with_runtime_genesis_patch() { - let chain_spec: ChainSpec<()> = ChainSpec::builder( + let chain_spec = ChainSpec::<()>::builder( substrate_test_runtime::wasm_binary_unwrap().into(), Default::default(), ) diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index c2c6249563f..9ccf6b4efb2 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -19,6 +19,7 @@ //! A helper module for calling the GenesisBuilder API from arbitrary runtime wasm blobs. use codec::{Decode, Encode}; +pub use sc_executor::sp_wasm_interface::HostFunctions; use sc_executor::{error::Result, WasmExecutor}; use serde_json::{from_slice, Value}; use sp_core::{ @@ -30,19 +31,31 @@ use sp_state_machine::BasicExternalities; use std::borrow::Cow; /// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob. -pub struct GenesisConfigBuilderRuntimeCaller<'a> { +/// +/// `EHF` type allows to specify the extended host function required for building runtime's genesis +/// config. The type will be compbined with default `sp_io::SubstrateHostFunctions`. +pub struct GenesisConfigBuilderRuntimeCaller<'a, EHF = ()> +where + EHF: HostFunctions, +{ code: Cow<'a, [u8]>, code_hash: Vec, - executor: WasmExecutor, + executor: WasmExecutor<(sp_io::SubstrateHostFunctions, EHF)>, } -impl<'a> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a> { +impl<'a, EHF> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a, EHF> +where + EHF: HostFunctions, +{ fn fetch_runtime_code(&self) -> Option> { Some(self.code.as_ref().into()) } } -impl<'a> GenesisConfigBuilderRuntimeCaller<'a> { +impl<'a, EHF> GenesisConfigBuilderRuntimeCaller<'a, EHF> +where + EHF: HostFunctions, +{ /// Creates new instance using the provided code blob. /// /// This code is later referred to as `runtime`. @@ -50,7 +63,7 @@ impl<'a> GenesisConfigBuilderRuntimeCaller<'a> { GenesisConfigBuilderRuntimeCaller { code: code.into(), code_hash: sp_core::blake2_256(code).to_vec(), - executor: WasmExecutor::::builder() + executor: WasmExecutor::<(sp_io::SubstrateHostFunctions, EHF)>::builder() .with_allow_missing_host_functions(true) .build(), } @@ -134,7 +147,7 @@ mod tests { #[test] fn get_default_config_works() { let config = - GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap()) + ::new(substrate_test_runtime::wasm_binary_unwrap()) .get_default_config() .unwrap(); let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; @@ -156,7 +169,7 @@ mod tests { }); let storage = - GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap()) + ::new(substrate_test_runtime::wasm_binary_unwrap()) .get_storage_for_patch(patch) .unwrap(); -- GitLab From eabf9fb89771d997e1cd9f93c429d2c505a3401d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:10:40 +0100 Subject: [PATCH 469/633] integrations-test: `build_genesis_storage` name fix (#2232) Some legacy tests were mistakenly merged in #1256 for `emulated-integration-tests-common` crate. This PR fixes the function name `build_genesis_storage` (no need to use `legacy` suffix, even though the genesis is built from `RuntimeGenesisConfig`). --- .../parachains/assets/asset-hub-rococo/src/genesis.rs | 4 ++-- .../parachains/assets/asset-hub-westend/src/genesis.rs | 4 ++-- .../parachains/bridges/bridge-hub-rococo/src/genesis.rs | 4 ++-- .../parachains/bridges/bridge-hub-westend/src/genesis.rs | 4 ++-- .../chains/parachains/testing/penpal/src/genesis.rs | 4 ++-- .../emulated/chains/relays/rococo/src/genesis.rs | 6 +++--- .../emulated/chains/relays/westend/src/genesis.rs | 4 ++-- .../parachains/integration-tests/emulated/common/src/lib.rs | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index efc94722d90..c19d05ec730 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -18,7 +18,7 @@ use sp_core::storage::Storage; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, collators, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; @@ -63,7 +63,7 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy( + build_genesis_storage( &genesis_config, asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), ) diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs index 19e7a60b030..78d6478fdf1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs @@ -18,7 +18,7 @@ use sp_core::storage::Storage; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, collators, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; @@ -59,7 +59,7 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy( + build_genesis_storage( &genesis_config, asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs index 299c5909670..4af84c82e98 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -18,7 +18,7 @@ use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::Balance; @@ -75,7 +75,7 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy( + build_genesis_storage( &genesis_config, bridge_hub_rococo_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs index 5acd3eb2c60..cd578d6862f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -18,7 +18,7 @@ use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::Balance; @@ -67,7 +67,7 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy( + build_genesis_storage( &genesis_config, bridge_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 8b03b599d5f..9ab32a977d7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -18,7 +18,7 @@ use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::Balance; @@ -64,7 +64,7 @@ pub fn genesis(para_id: u32) -> Storage { ..Default::default() }; - build_genesis_storage_legacy( + build_genesis_storage( &genesis_config, penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), ) diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs index 876df212e4c..6f5f3923ead 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs @@ -26,8 +26,8 @@ use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, get_account_id_from_seed, get_from_seed, - get_host_config, validators, + accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, get_host_config, + validators, }; use parachains_common::Balance; use rococo_runtime_constants::currency::UNITS as ROC; @@ -97,5 +97,5 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy(&genesis_config, rococo_runtime::WASM_BINARY.unwrap()) + build_genesis_storage(&genesis_config, rococo_runtime::WASM_BINARY.unwrap()) } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index 8bdc34f0eed..e87b85881d3 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -27,7 +27,7 @@ use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage_legacy, get_from_seed, get_host_config, validators, + accounts, build_genesis_storage, get_from_seed, get_host_config, validators, }; use parachains_common::Balance; use westend_runtime_constants::currency::UNITS as WND; @@ -105,5 +105,5 @@ pub fn genesis() -> Storage { ..Default::default() }; - build_genesis_storage_legacy(&genesis_config, westend_runtime::WASM_BINARY.unwrap()) + build_genesis_storage(&genesis_config, westend_runtime::WASM_BINARY.unwrap()) } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 74db02db003..952b053f2aa 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -86,7 +86,7 @@ pub fn get_host_config() -> HostConfiguration { /// Helper function used in tests to build the genesis storage using given RuntimeGenesisConfig and /// code Used in `legacy_vs_json_check` submods to verify storage building with JSON patch against /// building with RuntimeGenesisConfig struct. -pub fn build_genesis_storage_legacy(builder: &dyn BuildStorage, code: &[u8]) -> Storage { +pub fn build_genesis_storage(builder: &dyn BuildStorage, code: &[u8]) -> Storage { let mut storage = builder.build_storage().unwrap(); storage .top -- GitLab From 69494ea70ba9082b2f8494695361b15db25ec29d Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 8 Nov 2023 18:33:45 +0100 Subject: [PATCH 470/633] Add prospective-parachain subsystem to minimal-relay-node + QoL improvements (#2223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains some fixes and cleanups for parachain nodes: 1. When using async backing, node no longer complains about being unable to reach the prospective-parachain subsystem. 2. Parachain warp sync now informs users that the finalized para block has been retrieved. ``` 2023-11-08 13:24:42 [Parachain] 🎉 Received finalized parachain header #5747719 (0xa0aa…674b) from the relay chain. ``` 3. When a user supplied an invalid `--relay-chain-rpc-url`, we were crashing with a very verbose message. Removed the `expect` and improved the error message. ``` 2023-11-08 13:57:56 [Parachain] No valid RPC url found. Stopping RPC worker. 2023-11-08 13:57:56 [Parachain] Essential task `relay-chain-rpc-worker` failed. Shutting down service. Error: Service(Application(WorkerCommunicationError("RPC worker channel closed. This can hint and connectivity issues with the supplied RPC endpoints. Message: oneshot canceled"))) ``` --- Cargo.lock | 1 + .../client/relay-chain-minimal-node/Cargo.toml | 1 + .../src/collator_overseer.rs | 3 ++- .../client/relay-chain-minimal-node/src/lib.rs | 7 +------ .../src/rpc_client.rs | 2 +- cumulus/client/service/src/lib.rs | 18 +++++++++++------- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18eb00a13c1..54fa7c6485b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4198,6 +4198,7 @@ dependencies = [ "polkadot-core-primitives", "polkadot-network-bridge", "polkadot-node-collation-generation", + "polkadot-node-core-prospective-parachains", "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 6518e09cbb5..8c196f66b72 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -18,6 +18,7 @@ polkadot-collator-protocol = { path = "../../../polkadot/node/network/collator-p polkadot-network-bridge = { path = "../../../polkadot/node/network/bridge" } polkadot-node-collation-generation = { path = "../../../polkadot/node/collation-generation" } polkadot-node-core-runtime-api = { path = "../../../polkadot/node/core/runtime-api" } +polkadot-node-core-prospective-parachains = { path = "../../../polkadot/node/core/prospective-parachains" } # substrate deps sc-authority-discovery = { path = "../../../substrate/client/authority-discovery" } diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index 216ca0d3965..379217e4a63 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -24,6 +24,7 @@ use polkadot_network_bridge::{ NetworkBridgeTx as NetworkBridgeTxSubsystem, }; use polkadot_node_collation_generation::CollationGenerationSubsystem; +use polkadot_node_core_prospective_parachains::ProspectiveParachainsSubsystem; use polkadot_node_core_runtime_api::RuntimeApiSubsystem; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, @@ -144,7 +145,7 @@ fn build_overseer( spawner.clone(), )) .statement_distribution(DummySubsystem) - .prospective_parachains(DummySubsystem) + .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) .approval_distribution(DummySubsystem) .approval_voting(DummySubsystem) .gossip_support(DummySubsystem) diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index c8fba923dde..8801f93640c 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -171,12 +171,7 @@ async fn new_minimal_relay_chain( ); } - let genesis_hash = relay_chain_rpc_client - .block_get_hash(Some(0)) - .await - .expect("Genesis block hash is always available; qed") - .unwrap_or_default(); - + let genesis_hash = relay_chain_rpc_client.block_get_hash(Some(0)).await?.unwrap_or_default(); let peer_set_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; 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 5924716adcb..90af334e133 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -201,7 +201,7 @@ impl RelayChainRpcClient { let value = rx.await.map_err(|err| { RelayChainError::WorkerCommunicationError(format!( - "Unexpected channel close on RPC worker side: {}", + "RPC worker channel closed. This can hint and connectivity issues with the supplied RPC endpoints. Message: {}", err )) })??; diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 82890666eba..f8ebca11c8c 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -49,7 +49,7 @@ use sc_utils::mpsc::TracingUnboundedSender; use sp_api::ProvideRuntimeApi; use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_core::{traits::SpawnNamed, Decode}; -use sp_runtime::traits::{Block as BlockT, BlockIdTo}; +use sp_runtime::traits::{Block as BlockT, BlockIdTo, Header}; use std::{sync::Arc, time::Duration}; // Given the sporadic nature of the explicit recovery operation and the @@ -505,11 +505,11 @@ where None, async move { log::debug!( - target: "cumulus-network", + target: LOG_TARGET_SYNC, "waiting for announce block in a background task...", ); - let _ = wait_for_target_block::(sender, para_id, relay_chain_interface) + let _ = wait_for_finalized_para_head::(sender, para_id, relay_chain_interface) .await .map_err(|e| { log::error!( @@ -527,7 +527,7 @@ where /// Waits for the relay chain to have finished syncing and then gets the parachain header that /// corresponds to the last finalized relay chain block. -async fn wait_for_target_block( +async fn wait_for_finalized_para_head( sender: oneshot::Sender<::Header>, para_id: ParaId, relay_chain_interface: RCInterface, @@ -560,11 +560,15 @@ where .map_err(|e| format!("{e:?}"))? .ok_or("Could not find parachain head in relay chain")?; - let target_block = B::Header::decode(&mut &validation_data.parent_head.0[..]) + let finalized_header = B::Header::decode(&mut &validation_data.parent_head.0[..]) .map_err(|e| format!("Failed to decode parachain head: {e}"))?; - log::debug!(target: LOG_TARGET_SYNC, "Target block reached {:?}", target_block); - let _ = sender.send(target_block); + log::info!( + "🎉 Received target parachain header #{} ({}) from the relay chain.", + finalized_header.number(), + finalized_header.hash() + ); + let _ = sender.send(finalized_header); return Ok(()) } } -- GitLab From 37bb02ef62cee28dd67a0075cd424aa6aa1c6b18 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 8 Nov 2023 18:35:54 +0100 Subject: [PATCH 471/633] Make PalletInfo fields public (#2231) PalletInfo fields were private, preventing a user from actually using the QueryPallet instruction in a meaningful way since they couldn't read the received data. --- polkadot/xcm/src/v3/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 7ec3f6f40af..4217528f227 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -243,15 +243,15 @@ parameter_types! { #[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct PalletInfo { #[codec(compact)] - index: u32, - name: BoundedVec, - module_name: BoundedVec, + pub index: u32, + pub name: BoundedVec, + pub module_name: BoundedVec, #[codec(compact)] - major: u32, + pub major: u32, #[codec(compact)] - minor: u32, + pub minor: u32, #[codec(compact)] - patch: u32, + pub patch: u32, } impl PalletInfo { -- GitLab From 3f7c743d73afc72593ea1a3af139706e7e0782d9 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 21:18:41 +0200 Subject: [PATCH 472/633] BridgeHub Runtimes: Change registration order of `MessageQueue` pallet (#2230) This PR changes the registration order of the `MessageQueue` pallet so that it is registered last. This is necessary so that the [on_initialize](https://github.com/Snowfork/snowbridge/blob/df8d5da82e517a65fb0858a4f2ead533290336b5/parachain/pallets/outbound-queue/src/lib.rs#L267) hooks for Snowbridge can run before `MessageQueue` delivers messages using its own `on_initialize`. Generally, I think this is preferable regardless of Snowbridge's particular requirements. Other pallets may want to do housekeeping before MessageQueue starts delivering messages. I'm hoping this PR, if accepted, can be included in the same release as https://github.com/paritytech/polkadot-sdk/pull/1246. As otherwise, changing the order of pallet registration is an ABI-breaking change. --- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 5 ++++- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) 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 b533f7adc2a..e5d38bcac23 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 @@ -524,7 +524,6 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -564,6 +563,10 @@ construct_runtime!( BridgeWestendMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 51, BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 47, + + // Message Queue. Importantly, is registered last so that messages are processed after + // the `on_initialize` hooks of bridging pallets. + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 250, } ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index c0b0bf87180..458876ce46c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -500,7 +500,6 @@ construct_runtime!( PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Handy utilities. Utility: pallet_utility::{Pallet, Call, Event} = 40, @@ -511,6 +510,10 @@ construct_runtime!( BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 42, BridgeRococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 43, BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 44, + + // Message Queue. Importantly, is registered last so that messages are processed after + // the `on_initialize` hooks of bridging pallets. + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 250, } ); -- GitLab From e4f5f3c9c512d15193d99697795e4adfc641a6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 8 Nov 2023 23:30:41 +0100 Subject: [PATCH 473/633] Rococo: Build two versions of the wasm binary (#2229) One for local networks with `fast-runtime` feature activated (1 minute sessions) and one without the feature activated that will be the default that runs with 1 hour long sessions. --- polkadot/node/service/src/chain_spec.rs | 2 +- polkadot/runtime/rococo/build.rs | 11 +++++++---- polkadot/runtime/rococo/constants/src/lib.rs | 7 ++++--- polkadot/runtime/rococo/src/lib.rs | 8 ++++++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 04e142230b4..871d7e82911 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -1068,7 +1068,7 @@ fn rococo_local_testnet_genesis() -> serde_json::Value { #[cfg(feature = "rococo-native")] pub fn rococo_local_testnet_config() -> Result { Ok(RococoChainSpec::builder( - rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?, + rococo::fast_runtime_binary::WASM_BINARY.ok_or("Rococo development wasm not available")?, Default::default(), ) .with_name("Rococo Local Testnet") diff --git a/polkadot/runtime/rococo/build.rs b/polkadot/runtime/rococo/build.rs index ed32d33105b..0b7ee77b0d0 100644 --- a/polkadot/runtime/rococo/build.rs +++ b/polkadot/runtime/rococo/build.rs @@ -16,16 +16,19 @@ #[cfg(feature = "std")] fn main() { - // 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(); - println!("cargo:rerun-if-env-changed={}", ROCOCO_EPOCH_DURATION_ENV); + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .set_file_name("fast_runtime_binary.rs") + .enable_feature("fast-runtime") + .import_memory() + .export_heap_base() + .build(); } #[cfg(not(feature = "std"))] diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 84594cffcf3..2f641d60fc8 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -37,14 +37,15 @@ pub mod currency { /// Time and blocks. pub mod time { + use runtime_common::prod_or_fast; + use primitives::{BlockNumber, Moment}; pub const MILLISECS_PER_BLOCK: Moment = 6000; pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; frame_support::parameter_types! { - 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); + pub EpochDurationInBlocks: BlockNumber = + prod_or_fast!(1 * HOURS, 1 * MINUTES, "ROCOCO_EPOCH_DURATION"); } // These time units are defined in number of blocks. diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 257f364dca0..4f542354346 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -131,6 +131,14 @@ impl_runtime_weights!(rococo_runtime_constants); #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +/// Provides the `WASM_BINARY` build with `fast-runtime` feature enabled. +/// +/// This is for example useful for local test chains. +#[cfg(feature = "std")] +pub mod fast_runtime_binary { + include!(concat!(env!("OUT_DIR"), "/fast_runtime_binary.rs")); +} + /// Runtime version (Rococo). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { -- GitLab From 6a23c2316280d16986d59f7e1fdc3311a0bccf89 Mon Sep 17 00:00:00 2001 From: RadiumBlock Date: Wed, 8 Nov 2023 16:43:25 -0600 Subject: [PATCH 474/633] Add RadiumBlock Bootnodes for parachains (#2224) # Description We would like to add our bootnodes to the following parachains: Westend: Westmint, Bridgehub Kusama: Statemine, Bridgehub Polkadot: Statemint, Bridgehub, Collectives Thank you. --------- Co-authored-by: Oliver Tale-Yazdi --- cumulus/parachains/chain-specs/asset-hub-kusama.json | 4 +++- cumulus/parachains/chain-specs/asset-hub-polkadot.json | 4 +++- cumulus/parachains/chain-specs/asset-hub-westend.json | 4 +++- cumulus/parachains/chain-specs/bridge-hub-kusama.json | 4 +++- cumulus/parachains/chain-specs/bridge-hub-polkadot.json | 4 +++- cumulus/parachains/chain-specs/bridge-hub-westend.json | 4 +++- cumulus/parachains/chain-specs/collectives-polkadot.json | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 519811f5ec8..946bfc5983d 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -20,7 +20,9 @@ "/dns/statemine.bootnode.amforc.com/tcp/30336/p2p/12D3KooWHmSyrBWsc6fdpq8HtCFWasmLVLYGKWA2a78m4xAHKyBq", "/dns/statemine.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWHmSyrBWsc6fdpq8HtCFWasmLVLYGKWA2a78m4xAHKyBq", "/dns/statemine-boot-ng.dwellir.com/tcp/30343/p2p/12D3KooWQNJKBaNfW6Nn7HZDi5pSSEFmHL2Qz7chr9RksQUDR1Wk", - "/dns/statemine-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWQNJKBaNfW6Nn7HZDi5pSSEFmHL2Qz7chr9RksQUDR1Wk" + "/dns/statemine-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWQNJKBaNfW6Nn7HZDi5pSSEFmHL2Qz7chr9RksQUDR1Wk", + "/dns/statemine-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL", + "/dns/statemine-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index bbf90693ca3..c26506eb995 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -20,7 +20,9 @@ "/dns/statemint.bootnode.amforc.com/tcp/30341/p2p/12D3KooWByohP9FXn7ao8syS167qJsbFdpa7fY2Y24xbKtt3r7Ls", "/dns/statemint.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWByohP9FXn7ao8syS167qJsbFdpa7fY2Y24xbKtt3r7Ls", "/dns/statemint-boot-ng.dwellir.com/tcp/30344/p2p/12D3KooWEFrNuNk8fPdQS2hf34Gmqi6dGSvrETshGJUrqrvfRDZr", - "/dns/statemint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWEFrNuNk8fPdQS2hf34Gmqi6dGSvrETshGJUrqrvfRDZr" + "/dns/statemint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWEFrNuNk8fPdQS2hf34Gmqi6dGSvrETshGJUrqrvfRDZr", + "/dns/statemint-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx", + "/dns/statemint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index f6cdccee10a..f0e71981e7a 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -18,7 +18,9 @@ "/dns/westmint.bootnode.amforc.com/tcp/30339/p2p/12D3KooWNjKeaANaeZxBAPctmx8jugSYzuw4vnSCJmEDPB5mtRd6", "/dns/westmint.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWNjKeaANaeZxBAPctmx8jugSYzuw4vnSCJmEDPB5mtRd6", "/dns/westmint-boot-ng.dwellir.com/tcp/30345/p2p/12D3KooWFZ9xqApB1wnFYkbe1qJ5Jqwxe2f3i8W25F3tKNXy59ux", - "/dns/westmint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWFZ9xqApB1wnFYkbe1qJ5Jqwxe2f3i8W25F3tKNXy59ux" + "/dns/westmint-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWFZ9xqApB1wnFYkbe1qJ5Jqwxe2f3i8W25F3tKNXy59ux", + "/dns/westmint-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk", + "/dns/westmint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index c4a7d6358f7..9daa60fa263 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -20,7 +20,9 @@ "/dns/bridge-hub-kusama.bootnode.amforc.com/tcp/30337/p2p/12D3KooWGNeQJ5rXnEJkVUuQqwHd8aV5GkTAheaRoCaK8ZwW94id", "/dns/bridge-hub-kusama.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWGNeQJ5rXnEJkVUuQqwHd8aV5GkTAheaRoCaK8ZwW94id", "/dns/kusama-bridge-hub-boot-ng.dwellir.com/tcp/30337/p2p/12D3KooWBFskNCQDVjuUeBh6vrszWrUvYMBBhtZRLnoTZDdLYbW5", - "/dns/kusama-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBFskNCQDVjuUeBh6vrszWrUvYMBBhtZRLnoTZDdLYbW5" + "/dns/kusama-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBFskNCQDVjuUeBh6vrszWrUvYMBBhtZRLnoTZDdLYbW5", + "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW", + "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index e44a4dacd48..d3e884284b4 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -16,7 +16,9 @@ "/dns/boot.metaspan.io/tcp/16032/p2p/12D3KooWQTfRnrK3FfbrotpSP5RVJbjBHVBSu8VSzhj9qcvjaqnZ", "/dns/boot.metaspan.io/tcp/16036/wss/p2p/12D3KooWQTfRnrK3FfbrotpSP5RVJbjBHVBSu8VSzhj9qcvjaqnZ", "/dns/boot-node.helikon.io/tcp/8220/p2p/12D3KooWC38TZJA8ZBXZgAYVrceoJ56jNNLJPdpk3ojeFkTAwZVp", - "/dns/boot-node.helikon.io/tcp/8222/wss/p2p/12D3KooWC38TZJA8ZBXZgAYVrceoJ56jNNLJPdpk3ojeFkTAwZVp" + "/dns/boot-node.helikon.io/tcp/8222/wss/p2p/12D3KooWC38TZJA8ZBXZgAYVrceoJ56jNNLJPdpk3ojeFkTAwZVp", + "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi", + "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index 0a441b3a295..dde3d437f41 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -14,7 +14,9 @@ "/dns/boot.metaspan.io/tcp/36032/p2p/12D3KooWPaLsu3buByBnGFQnp5UP4q1S652dGVft92TFeChizFir", "/dns/boot.metaspan.io/tcp/36036/wss/p2p/12D3KooWPaLsu3buByBnGFQnp5UP4q1S652dGVft92TFeChizFir", "/dns/boot-node.helikon.io/tcp/9220/p2p/12D3KooWK3K1Mu5Jjg96Lt9DUzg84KsWnZo44V4KB7mvhGqi6xnp", - "/dns/boot-node.helikon.io/tcp/9222/wss/p2p/12D3KooWK3K1Mu5Jjg96Lt9DUzg84KsWnZo44V4KB7mvhGqi6xnp" + "/dns/boot-node.helikon.io/tcp/9222/wss/p2p/12D3KooWK3K1Mu5Jjg96Lt9DUzg84KsWnZo44V4KB7mvhGqi6xnp", + "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke", + "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index 974be338857..003c6373429 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -20,7 +20,9 @@ "/dns/collectives-polkadot.bootnode.amforc.com/tcp/30335/p2p/12D3KooWQeAjDnGkrPe5vtpfnB6ydZfWyMxyrXLkBFmA6o4k9aiU", "/dns/collectives-polkadot.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWQeAjDnGkrPe5vtpfnB6ydZfWyMxyrXLkBFmA6o4k9aiU", "/dns/polkadot-collectives-boot-ng.dwellir.com/tcp/30341/p2p/12D3KooWDMFYCNRAQcSRNV7xu2xv8319goSEbSHW4TnXRz6EpPKc", - "/dns/polkadot-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWDMFYCNRAQcSRNV7xu2xv8319goSEbSHW4TnXRz6EpPKc" + "/dns/polkadot-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWDMFYCNRAQcSRNV7xu2xv8319goSEbSHW4TnXRz6EpPKc", + "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c", + "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c" ], "telemetryEndpoints": null, "protocolId": null, -- GitLab From d347d68868a38841ba51f2e91cef945a7ea50dd4 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 9 Nov 2023 16:30:37 +0800 Subject: [PATCH 475/633] Remove unnecessary map_error (#2239) This was discovered during a debugging session, and it only served to mask the underlying error, which was not great. --- polkadot/xcm/xcm-builder/src/routing.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index 39e9eab410b..f4c18adddb3 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -49,8 +49,7 @@ impl SendXcm for WithUniqueTopic { message.0.push(SetTopic(unique_id)); unique_id }; - let (ticket, assets) = Inner::validate(destination, &mut Some(message)) - .map_err(|_| SendError::NotApplicable)?; + let (ticket, assets) = Inner::validate(destination, &mut Some(message))?; Ok(((ticket, unique_id), assets)) } -- GitLab From 48ea86f0e86c0cef21a8df978307d93d7fbc19f6 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 9 Nov 2023 16:37:28 +0100 Subject: [PATCH 476/633] Add descriptions to all published crates (#2029) Missing descriptions (47): - [x] `cumulus/client/collator/Cargo.toml` - [x] `cumulus/client/relay-chain-inprocess-interface/Cargo.toml` - [x] `cumulus/client/cli/Cargo.toml` - [x] `cumulus/client/service/Cargo.toml` - [x] `cumulus/client/relay-chain-rpc-interface/Cargo.toml` - [x] `cumulus/client/relay-chain-interface/Cargo.toml` - [x] `cumulus/client/relay-chain-minimal-node/Cargo.toml` - [x] `cumulus/parachains/pallets/parachain-info/Cargo.toml` - [x] `cumulus/parachains/pallets/ping/Cargo.toml` - [x] `cumulus/primitives/utility/Cargo.toml` - [x] `cumulus/primitives/aura/Cargo.toml` - [x] `cumulus/primitives/core/Cargo.toml` - [x] `cumulus/primitives/parachain-inherent/Cargo.toml` - [x] `cumulus/test/relay-sproof-builder/Cargo.toml` - [x] `cumulus/pallets/xcmp-queue/Cargo.toml` - [x] `cumulus/pallets/dmp-queue/Cargo.toml` - [x] `cumulus/pallets/xcm/Cargo.toml` - [x] `polkadot/erasure-coding/Cargo.toml` - [x] `polkadot/statement-table/Cargo.toml` - [x] `polkadot/primitives/Cargo.toml` - [x] `polkadot/rpc/Cargo.toml` - [x] `polkadot/node/service/Cargo.toml` - [x] `polkadot/node/core/parachains-inherent/Cargo.toml` - [x] `polkadot/node/core/approval-voting/Cargo.toml` - [x] `polkadot/node/core/dispute-coordinator/Cargo.toml` - [x] `polkadot/node/core/av-store/Cargo.toml` - [x] `polkadot/node/core/chain-api/Cargo.toml` - [x] `polkadot/node/core/prospective-parachains/Cargo.toml` - [x] `polkadot/node/core/backing/Cargo.toml` - [x] `polkadot/node/core/provisioner/Cargo.toml` - [x] `polkadot/node/core/runtime-api/Cargo.toml` - [x] `polkadot/node/core/bitfield-signing/Cargo.toml` - [x] `polkadot/node/network/dispute-distribution/Cargo.toml` - [x] `polkadot/node/network/bridge/Cargo.toml` - [x] `polkadot/node/network/collator-protocol/Cargo.toml` - [x] `polkadot/node/network/approval-distribution/Cargo.toml` - [x] `polkadot/node/network/availability-distribution/Cargo.toml` - [x] `polkadot/node/network/bitfield-distribution/Cargo.toml` - [x] `polkadot/node/network/gossip-support/Cargo.toml` - [x] `polkadot/node/network/availability-recovery/Cargo.toml` - [x] `polkadot/node/collation-generation/Cargo.toml` - [x] `polkadot/node/overseer/Cargo.toml` - [x] `polkadot/runtime/parachains/Cargo.toml` - [x] `polkadot/runtime/common/slot_range_helper/Cargo.toml` - [x] `polkadot/runtime/metrics/Cargo.toml` - [x] `polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml` - [x] `polkadot/utils/generate-bags/Cargo.toml` - [x] `substrate/bin/minimal/runtime/Cargo.toml` --------- Signed-off-by: Oliver Tale-Yazdi Signed-off-by: alindima Co-authored-by: ordian Co-authored-by: Tsvetomir Dimitrov Co-authored-by: Marcin S Co-authored-by: alindima Co-authored-by: Sebastian Kunert Co-authored-by: Dmitry Markin Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Liam Aharon --- cumulus/client/cli/Cargo.toml | 1 + cumulus/client/collator/Cargo.toml | 1 + cumulus/client/relay-chain-inprocess-interface/Cargo.toml | 1 + cumulus/client/relay-chain-interface/Cargo.toml | 1 + cumulus/client/relay-chain-minimal-node/Cargo.toml | 1 + cumulus/client/relay-chain-rpc-interface/Cargo.toml | 1 + cumulus/client/service/Cargo.toml | 1 + cumulus/pallets/xcm/Cargo.toml | 1 + cumulus/pallets/xcmp-queue/Cargo.toml | 1 + cumulus/parachains/pallets/parachain-info/Cargo.toml | 1 + cumulus/parachains/pallets/ping/Cargo.toml | 1 + cumulus/primitives/aura/Cargo.toml | 1 + cumulus/primitives/core/Cargo.toml | 1 + cumulus/primitives/parachain-inherent/Cargo.toml | 1 + cumulus/primitives/utility/Cargo.toml | 1 + cumulus/test/relay-sproof-builder/Cargo.toml | 1 + polkadot/erasure-coding/Cargo.toml | 1 + polkadot/node/collation-generation/Cargo.toml | 1 + polkadot/node/core/approval-voting/Cargo.toml | 1 + polkadot/node/core/av-store/Cargo.toml | 1 + polkadot/node/core/backing/Cargo.toml | 1 + polkadot/node/core/bitfield-signing/Cargo.toml | 1 + polkadot/node/core/chain-api/Cargo.toml | 1 + polkadot/node/core/dispute-coordinator/Cargo.toml | 1 + polkadot/node/core/parachains-inherent/Cargo.toml | 1 + polkadot/node/core/prospective-parachains/Cargo.toml | 1 + polkadot/node/core/provisioner/Cargo.toml | 1 + polkadot/node/core/runtime-api/Cargo.toml | 1 + polkadot/node/network/approval-distribution/Cargo.toml | 1 + polkadot/node/network/availability-distribution/Cargo.toml | 1 + polkadot/node/network/availability-recovery/Cargo.toml | 1 + polkadot/node/network/bitfield-distribution/Cargo.toml | 1 + polkadot/node/network/bridge/Cargo.toml | 1 + polkadot/node/network/collator-protocol/Cargo.toml | 1 + polkadot/node/network/dispute-distribution/Cargo.toml | 1 + polkadot/node/network/gossip-support/Cargo.toml | 1 + polkadot/node/overseer/Cargo.toml | 1 + polkadot/node/service/Cargo.toml | 1 + polkadot/primitives/Cargo.toml | 1 + polkadot/rpc/Cargo.toml | 1 + polkadot/runtime/common/slot_range_helper/Cargo.toml | 1 + polkadot/runtime/metrics/Cargo.toml | 1 + polkadot/runtime/parachains/Cargo.toml | 1 + polkadot/statement-table/Cargo.toml | 1 + polkadot/utils/generate-bags/Cargo.toml | 1 + polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 1 + substrate/bin/minimal/runtime/Cargo.toml | 6 +++++- 47 files changed, 51 insertions(+), 1 deletion(-) diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 5d9752dbb20..0f942feb595 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-cli" version = "0.1.0" authors.workspace = true edition.workspace = true +description = "Parachain node CLI utilities." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 30798f84800..ad9f01ed083 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-collator" version = "0.1.0" authors.workspace = true edition.workspace = true +description = "Common node-side functionality and glue code to collate parachain blocks." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 19c99c5cb72..87f0eabd9b5 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" edition.workspace = true +description = "Implementation of the RelayChainInterface trait for Polkadot full-nodes." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 803df7d302b..c9d50afe8fa 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-interface" version = "0.1.0" edition.workspace = true +description = "Common interface for different relay chain datasources." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 8c196f66b72..53173fb4118 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-minimal-node" version = "0.1.0" edition.workspace = true +description = "Minimal node implementation to be used in tandem with RPC or light-client mode." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 9e5a8f1eccb..93fe57145b0 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -3,6 +3,7 @@ authors.workspace = true name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" edition.workspace = true +description = "Implementation of the RelayChainInterface trait that connects to a remote RPC-node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index 314aebdcb9c..f80c65128d5 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-client-service" version = "0.1.0" authors.workspace = true edition.workspace = true +description = "Common functions used to assemble the components of a parachain node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index d79e57bceac..c8e819979bd 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -4,6 +4,7 @@ edition.workspace = true name = "cumulus-pallet-xcm" version = "0.1.0" license = "Apache-2.0" +description = "Pallet for stuff specific to parachains' usage of XCM" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index e526a28d084..fba006e7986 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" authors.workspace = true edition.workspace = true +description = "Pallet to queue outbound and inbound XCMP messages." license = "Apache-2.0" [dependencies] diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 40f1a07c2dd..727182dfb8e 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -4,6 +4,7 @@ edition.workspace = true name = "staging-parachain-info" version = "0.1.0" license = "Apache-2.0" +description = "Pallet to store the parachain ID" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 0ea424e1a2d..0133befa855 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -4,6 +4,7 @@ edition.workspace = true name = "cumulus-ping" version = "0.1.0" license = "Apache-2.0" +description = "Ping Pallet for Cumulus XCM/UMP testing." [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 168c85b2efb..19607eb7c18 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" +description = "Core primitives for Aura in Cumulus" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index e7bf15252f2..23839a10e46 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" +description = "Cumulus related core primitive types and traits" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 5a448f65ada..46b5da57f38 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -3,6 +3,7 @@ name = "cumulus-primitives-parachain-inherent" version = "0.1.0" authors.workspace = true edition.workspace = true +description = "Inherent that needs to be present in every parachain block. Contains messages and a relay chain storage-proof." license = "Apache-2.0" [dependencies] diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 23e2287d1fe..45ce6701988 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" +description = "Helper datatypes for Cumulus" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index 8807e4e2858..b24ac308495 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" +description = "Mocked relay state proof builder for testing Cumulus." [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index d07b77ec4dd..ccfe7f14eb4 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-erasure-coding" version = "1.0.0" +description = "Erasure coding used for Polkadot's availability system" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index b110540140f..c1848f47fc6 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Collator-side subsystem that handles incoming candidate submissions from the parachain." [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index f7ea1d21077..59a6708f17e 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Approval Voting Subsystem of the Polkadot node" [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 955fe37d7c3..3fa81d064a8 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-av-store" +description = "The Availability Store subsystem. Wrapper over the DB that stores availability data and chunks." version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index e7e6358e8a4..7a6ce5de8cb 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "The Candidate Backing Subsystem. Tracks parachain candidates that can be backed, as well as the issuance of statements about candidates." [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index de38d18d970..712a01b46b1 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Bitfield signing subsystem for the Polkadot node" [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index 2178be028bd..154fa20e75d 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "The Chain API subsystem provides access to chain related utility functions like block number to hash conversions." [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 6061c52b7e8..e2086db708f 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-node-core-dispute-coordinator" version = "1.0.0" +description = "The node-side components that participate in disputes" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 18d91dcfb56..c783f21e24d 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Parachains inherent data provider for Polkadot node" [dependencies] futures = "0.3.21" diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 77a59d87f3f..9db1259e61d 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "The Prospective Parachains subsystem. Tracks and handles prospective parachain fragments." [dependencies] futures = "0.3.19" diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 05ea92caa97..13ecb356f2c 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-node-core-provisioner" version = "1.0.0" +description="Responsible for assembling a relay chain block from a set of available parachain candidates" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index b16a501686d..f324f1e79c4 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-node-core-runtime-api" version = "1.0.0" +description="Wrapper around the parachain-related runtime APIs" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 32b7f489efa..f8a7cc15f87 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-approval-distribution" version = "1.0.0" +description = "Polkadot Approval Distribution subsystem for the distribution of assignments and approvals for approval checks on candidates over the network." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index c3c7aa4e0ea..91ed1026e41 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-availability-distribution" +description = "The Availability Distribution subsystem. Requests the required availability data. Also distributes availability data and chunks to requesters." version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 42c3abef547..6048e6323cb 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-availability-recovery" +description = "The Availability Recovery subsystem. Handles requests for recovering the availability data of included candidates." version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 32b0ba2545e..0e61e9cf620 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-availability-bitfield-distribution" version = "1.0.0" +description = "Polkadot Bitfiled Distribution subsystem, which gossips signed availability bitfields used to compactly determine which backed candidates are available or not based on a 2/3+ quorum." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index df8e881234d..6ae765c252f 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-network-bridge" version = "1.0.0" +description = "The Network Bridge Subsystem — protocol multiplexer for Polkadot." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index e5328cf1662..367a97f35d9 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-collator-protocol" version = "1.0.0" +description = "Polkadot Collator Protocol subsystem. Allows collators and validators to talk to each other." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 5d8e245d289..f4ea358c41b 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-dispute-distribution" version = "1.0.0" +description = "Polkadot Dispute Distribution subsystem, which ensures all concerned validators are aware of a dispute and have the relevant votes." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index a5bfda73833..a9f68261add 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-gossip-support" version = "1.0.0" +description = "Polkadot Gossip Support subsystem. Responsible for keeping track of session changes and issuing a connection request to the relevant validators on every new session." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 376ebe0375b..ac1e4443f0c 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "System overseer of the Polkadot node" [dependencies] client = { package = "sc-client-api", path = "../../../substrate/client/api" } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 0ed50086f86..e7a4f4a825c 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -5,6 +5,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Utils to tie different Polkadot components together and allow instantiation of a node." [dependencies] # Substrate Client diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index c7c081e2f0e..b318c2d4be7 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Shared primitives used by Polkadot runtime" [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index b5f155b5a65..ce11b26e554 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Polkadot specific RPC functionality." [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index f65717519d5..59c76a6cabb 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Helper crate for generating slot ranges for the Polkadot runtime." [dependencies] paste = "1.0" diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index cfa6bf3dafb..cdfab82d00c 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Runtime metric interface for the Polkadot node" [dependencies] sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false} diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 004a0545d55..b6800fc0844 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-runtime-parachains" version = "1.0.0" +description = "Relay Chain runtime code responsible for Parachains." authors.workspace = true edition.workspace = true license.workspace = true diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 91ca2015af3..d2518591d26 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "Stores messages other authorities issue about candidates in Polkadot." [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 95ca57ea728..ed29001aa4f 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true +description = "CLI to generate voter bags for Polkadot runtimes" [dependencies] clap = { version = "4.4.6", features = ["derive"] } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 88df81a3dad..5be0bbe4ae5 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -4,6 +4,7 @@ authors.workspace = true edition.workspace = true license.workspace = true version = "1.0.0" +description = "Benchmarks for the XCM pallet" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index b75816a5ea3..e7e67ce889a 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -1,7 +1,11 @@ [package] name = "minimal-runtime" version = "0.1.0" -edition = "2021" +authors.workspace = true +description = "A minimal Substrate example runtime" +edition.workspace = true +repository.workspace = true +license.workspace = true [dependencies] parity-scale-codec = { version = "3.0.0", default-features = false } -- GitLab From 0abbd60de1b9c65647c3962f368a5a34d31803d5 Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 9 Nov 2023 20:23:34 +0100 Subject: [PATCH 477/633] Add license to tracking-allocator and add staging-prefix (#2259) --- polkadot/node/tracking-allocator/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/node/tracking-allocator/Cargo.toml b/polkadot/node/tracking-allocator/Cargo.toml index 2ea3f69c7d0..a7842a3e62e 100644 --- a/polkadot/node/tracking-allocator/Cargo.toml +++ b/polkadot/node/tracking-allocator/Cargo.toml @@ -4,3 +4,4 @@ description = "Tracking allocator to control the amount of memory consumed by th version = "1.0.0" authors.workspace = true edition.workspace = true +license.workspace = true -- GitLab From e8029a776196ab2339eb47b6be4cc3ce4b041967 Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 9 Nov 2023 21:17:48 +0100 Subject: [PATCH 478/633] Don't publish frame and deps (#2260) --- substrate/bin/minimal/runtime/Cargo.toml | 1 + substrate/frame/Cargo.toml | 1 + substrate/frame/examples/Cargo.toml | 1 + substrate/frame/examples/frame-crate/Cargo.toml | 1 + 4 files changed, 4 insertions(+) diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index e7e67ce889a..85d56d0638a 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -6,6 +6,7 @@ description = "A minimal Substrate example runtime" edition.workspace = true repository.workspace = true license.workspace = true +publish = false [dependencies] parity-scale-codec = { version = "3.0.0", default-features = false } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index f7b35aba358..9f2f73ffb15 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" homepage = "paritytech.github.io" repository.workspace = true description = "The single package to get you started with building frame pallets and runtimes" +publish = false [package.metadata.docs.rs] # enable `experimental` feature for docs diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 98c4e51889b..1b215022715 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true description = "The single package with examples of various types of FRAME pallets" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 854ee8b55c8..ceb8c7bfb81 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT-0" homepage = "https://substrate.io" repository.workspace = true description = "FRAME example pallet with umbrella crate" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -- GitLab From b0d0fb31d8758602387e4ba1cb712e90dff8b2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Nov 2023 21:44:23 +0100 Subject: [PATCH 479/633] sc-state-db: Keep track of `LAST_PRUNED` after warp syncing (#2228) When warp syncing we import the target block with all its state. However, we didn't store the `LAST_PRUNED` block which would then lead to `pruning` to forget about the imported block after a restart of the node. We just set `LAST_PRUNED` to the parent block of the warp sync target block to fix this issue. --- substrate/client/state-db/src/pruning.rs | 42 ++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/substrate/client/state-db/src/pruning.rs b/substrate/client/state-db/src/pruning.rs index 7bee2b1d99a..623d30b098b 100644 --- a/substrate/client/state-db/src/pruning.rs +++ b/substrate/client/state-db/src/pruning.rs @@ -406,12 +406,24 @@ impl RefWindow { commit: &mut CommitSet, ) -> Result<(), Error> { if self.base == 0 && self.is_empty() && number > 0 { - // assume that parent was canonicalized + // This branch is taken if the node imports the target block of a warp sync. + // assume that the block was canonicalized self.base = number; + // The parent of the block was the last block that got pruned. + commit + .meta + .inserted + .push((to_meta_key(LAST_PRUNED, &()), (number - 1).encode())); } else if (self.base + self.window_size()) != number { return Err(Error::StateDb(StateDbError::InvalidBlockNumber)) } - trace!(target: "state-db", "Adding to pruning window: {:?} ({} inserted, {} deleted)", hash, commit.data.inserted.len(), commit.data.deleted.len()); + trace!( + target: "state-db", + "Adding to pruning window: {:?} ({} inserted, {} deleted)", + hash, + commit.data.inserted.len(), + commit.data.deleted.len(), + ); let inserted = if matches!(self.queue, DeathRowQueue::Mem { .. }) { commit.data.inserted.iter().map(|(k, _)| k.clone()).collect() } else { @@ -869,4 +881,30 @@ mod tests { pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); } + + /// Ensure that after warp syncing the state is stored correctly in the db. The warp sync target + /// block is imported with all its state at once. This test ensures that after a restart + /// `pruning` still knows that this block was imported. + #[test] + fn store_correct_state_after_warp_syncing() { + for count_insertions in [true, false] { + let mut db = make_db(&[]); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, count_insertions).unwrap(); + let block = 10000; + + // import blocks + let mut commit = make_commit(&[], &[]); + pruning.note_canonical(&block, block, &mut commit).unwrap(); + push_last_canonicalized(block, &mut commit); + db.commit(&commit); + + // load a new queue from db + // `cache` should be the same + let pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, count_insertions).unwrap(); + + assert_eq!(HaveBlock::Yes, pruning.have_block(&block, block)); + } + } } -- GitLab From 03ee44d9e12ba1a88b4e55757b402039d80bed2e Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 9 Nov 2023 23:27:08 +0100 Subject: [PATCH 480/633] Add license to tracking-allocator and add staging-prefix (#2261) The staging- rename commit was missing from the last PR for some reason. --- Cargo.lock | 10 +++++----- polkadot/node/core/pvf/prepare-worker/Cargo.toml | 2 +- polkadot/node/tracking-allocator/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54fa7c6485b..5c1bc13b72f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12545,10 +12545,10 @@ dependencies = [ "sc-executor-common", "sc-executor-wasmtime", "sp-maybe-compressed-blob", + "staging-tracking-allocator", "tikv-jemalloc-ctl", "tikv-jemallocator", "tracing-gum", - "tracking-allocator", ] [[package]] @@ -18328,6 +18328,10 @@ dependencies = [ "sp-std 8.0.0", ] +[[package]] +name = "staging-tracking-allocator" +version = "1.0.0" + [[package]] name = "staging-xcm" version = "1.0.0" @@ -19622,10 +19626,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "tracking-allocator" -version = "1.0.0" - [[package]] name = "trie-bench" version = "0.38.0" diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index dae88afc555..e21583ecc8b 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -11,7 +11,7 @@ cfg-if = "1.0" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" rayon = "1.5.1" -tracking-allocator = { path = "../../../tracking-allocator" } +tracking-allocator = { package = "staging-tracking-allocator", path = "../../../tracking-allocator" } tikv-jemalloc-ctl = { version = "0.5.0", optional = true } tikv-jemallocator = { version = "0.5.0", optional = true } diff --git a/polkadot/node/tracking-allocator/Cargo.toml b/polkadot/node/tracking-allocator/Cargo.toml index a7842a3e62e..b1b33091344 100644 --- a/polkadot/node/tracking-allocator/Cargo.toml +++ b/polkadot/node/tracking-allocator/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tracking-allocator" +name = "staging-tracking-allocator" description = "Tracking allocator to control the amount of memory consumed by the process" version = "1.0.0" authors.workspace = true -- GitLab From 64effd0e6f49f0c935af2a7790b230e46d46d4f8 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 10 Nov 2023 12:22:47 +0100 Subject: [PATCH 481/633] Contracts move fixtures to new crate (#2246) Small PR that introduce a new crate that will host RISC-V & wasm fixtures for testing pallet-contracts --- Cargo.lock | 10 +++++ Cargo.toml | 1 + substrate/frame/contracts/Cargo.toml | 2 + substrate/frame/contracts/fixtures/Cargo.toml | 18 ++++++++ .../account_reentrance_count_call.wat | 0 .../add_remove_delegate_dependency.wat | 0 .../contracts/fixtures/{ => data}/balance.wat | 0 .../contracts/fixtures/{ => data}/call.wat | 0 .../fixtures/{ => data}/call_return_code.wat | 0 .../fixtures/{ => data}/call_runtime.wat | 0 .../{ => data}/call_runtime_and_call.wat | 0 .../fixtures/{ => data}/call_with_limit.wat | 0 .../fixtures/{ => data}/caller_contract.wat | 0 .../fixtures/{ => data}/chain_extension.wat | 0 .../chain_extension_temp_storage.wat | 0 .../{ => data}/create_storage_and_call.wat | 0 .../create_storage_and_instantiate.wat | 0 .../fixtures/{ => data}/crypto_hashes.wat | 0 .../{ => data}/debug_message_invalid_utf8.wat | 0 .../debug_message_logging_disabled.wat | 0 .../{ => data}/debug_message_works.wat | 0 .../fixtures/{ => data}/delegate_call.wat | 0 .../fixtures/{ => data}/delegate_call_lib.wat | 0 .../{ => data}/delegate_call_simple.wat | 0 .../{ => data}/destroy_and_transfer.wat | 0 .../contracts/fixtures/{ => data}/drain.wat | 0 .../contracts/fixtures/{ => data}/dummy.wat | 0 .../fixtures/{ => data}/ecdsa_recover.wat | 0 .../{ => data}/event_and_return_on_deploy.wat | 0 .../fixtures/{ => data}/event_size.wat | 0 .../fixtures/{ => data}/float_instruction.wat | 0 .../{ => data}/instantiate_return_code.wat | 0 .../{ => data}/invalid_contract_no_call.wat | 0 .../{ => data}/invalid_contract_no_memory.wat | 0 .../fixtures/{ => data}/invalid_module.wat | 0 .../fixtures/{ => data}/multi_store.wat | 0 .../{ => data}/new_set_code_hash_contract.wat | 0 .../fixtures/{ => data}/ok_trap_revert.wat | 0 .../{ => data}/reentrance_count_call.wat | 0 .../reentrance_count_delegated_call.wat | 0 .../fixtures/{ => data}/return_with_data.wat | 0 .../fixtures/{ => data}/run_out_of_gas.wat | 0 .../{ => data}/run_out_of_gas_start_fn.wat | 0 .../fixtures/{ => data}/seal_input_noop.wat | 0 .../fixtures/{ => data}/seal_input_once.wat | 0 .../fixtures/{ => data}/seal_input_twice.wat | 0 .../fixtures/{ => data}/self_destruct.wat | 0 .../self_destructing_constructor.wat | 0 .../fixtures/{ => data}/set_code_hash.wat | 0 .../fixtures/{ => data}/set_empty_storage.wat | 0 .../fixtures/{ => data}/sr25519_verify.wat | 0 .../fixtures/{ => data}/storage_size.wat | 0 .../fixtures/{ => data}/store_call.wat | 0 .../fixtures/{ => data}/store_deploy.wat | 0 .../{ => data}/transfer_return_code.wat | 0 substrate/frame/contracts/fixtures/src/lib.rs | 42 +++++++++++++++++++ substrate/frame/contracts/src/tests.rs | 24 +---------- 57 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 substrate/frame/contracts/fixtures/Cargo.toml rename substrate/frame/contracts/fixtures/{ => data}/account_reentrance_count_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/add_remove_delegate_dependency.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/balance.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/call_return_code.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/call_runtime.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/call_runtime_and_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/call_with_limit.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/caller_contract.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/chain_extension.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/chain_extension_temp_storage.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/create_storage_and_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/create_storage_and_instantiate.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/crypto_hashes.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/debug_message_invalid_utf8.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/debug_message_logging_disabled.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/debug_message_works.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/delegate_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/delegate_call_lib.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/delegate_call_simple.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/destroy_and_transfer.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/drain.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/dummy.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/ecdsa_recover.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/event_and_return_on_deploy.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/event_size.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/float_instruction.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/instantiate_return_code.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/invalid_contract_no_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/invalid_contract_no_memory.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/invalid_module.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/multi_store.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/new_set_code_hash_contract.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/ok_trap_revert.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/reentrance_count_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/reentrance_count_delegated_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/return_with_data.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/run_out_of_gas.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/run_out_of_gas_start_fn.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/seal_input_noop.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/seal_input_once.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/seal_input_twice.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/self_destruct.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/self_destructing_constructor.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/set_code_hash.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/set_empty_storage.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/sr25519_verify.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/storage_size.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/store_call.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/store_deploy.wat (100%) rename substrate/frame/contracts/fixtures/{ => data}/transfer_return_code.wat (100%) create mode 100644 substrate/frame/contracts/fixtures/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 5c1bc13b72f..2a091ce6817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9701,6 +9701,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-balances", + "pallet-contracts-fixtures", "pallet-contracts-primitives", "pallet-contracts-proc-macro", "pallet-insecure-randomness-collective-flip", @@ -9725,6 +9726,15 @@ dependencies = [ "wat", ] +[[package]] +name = "pallet-contracts-fixtures" +version = "1.0.0" +dependencies = [ + "frame-system", + "sp-runtime", + "wat", +] + [[package]] name = "pallet-contracts-primitives" version = "24.0.0" diff --git a/Cargo.toml b/Cargo.toml index 3b3469e5483..42bbac37a6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -293,6 +293,7 @@ members = [ "substrate/frame/child-bounties", "substrate/frame/collective", "substrate/frame/contracts", + "substrate/frame/contracts/fixtures", "substrate/frame/contracts/primitives", "substrate/frame/contracts/proc-macro", "substrate/frame/conviction-voting", diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index d80577f9d44..0eb50c2b0ba 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -54,6 +54,7 @@ assert_matches = "1" env_logger = "0.9" pretty_assertions = "1" wat = "1" +pallet-contracts-fixtures = { path = "./fixtures" } # Substrate Dependencies pallet-balances = { path = "../balances" } @@ -73,6 +74,7 @@ std = [ "frame-system/std", "log/std", "pallet-balances?/std", + "pallet-contracts-fixtures/std", "pallet-contracts-primitives/std", "pallet-contracts-proc-macro/full", "pallet-insecure-randomness-collective-flip/std", diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml new file mode 100644 index 00000000000..b44f36f2a5f --- /dev/null +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "pallet-contracts-fixtures" +publish = false +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +description = "Fixtures for testing contracts pallet." + +[dependencies] +wat = "1" +frame-system = { path = "../../system", default-features = false} +sp-runtime = { path = "../../../primitives/runtime", default-features = false} + +[features] +default = [ "std" ] +std = [ "frame-system/std", "sp-runtime/std" ] + diff --git a/substrate/frame/contracts/fixtures/account_reentrance_count_call.wat b/substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/account_reentrance_count_call.wat rename to substrate/frame/contracts/fixtures/data/account_reentrance_count_call.wat diff --git a/substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat b/substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat similarity index 100% rename from substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat rename to substrate/frame/contracts/fixtures/data/add_remove_delegate_dependency.wat diff --git a/substrate/frame/contracts/fixtures/balance.wat b/substrate/frame/contracts/fixtures/data/balance.wat similarity index 100% rename from substrate/frame/contracts/fixtures/balance.wat rename to substrate/frame/contracts/fixtures/data/balance.wat diff --git a/substrate/frame/contracts/fixtures/call.wat b/substrate/frame/contracts/fixtures/data/call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/call.wat rename to substrate/frame/contracts/fixtures/data/call.wat diff --git a/substrate/frame/contracts/fixtures/call_return_code.wat b/substrate/frame/contracts/fixtures/data/call_return_code.wat similarity index 100% rename from substrate/frame/contracts/fixtures/call_return_code.wat rename to substrate/frame/contracts/fixtures/data/call_return_code.wat diff --git a/substrate/frame/contracts/fixtures/call_runtime.wat b/substrate/frame/contracts/fixtures/data/call_runtime.wat similarity index 100% rename from substrate/frame/contracts/fixtures/call_runtime.wat rename to substrate/frame/contracts/fixtures/data/call_runtime.wat diff --git a/substrate/frame/contracts/fixtures/call_runtime_and_call.wat b/substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/call_runtime_and_call.wat rename to substrate/frame/contracts/fixtures/data/call_runtime_and_call.wat diff --git a/substrate/frame/contracts/fixtures/call_with_limit.wat b/substrate/frame/contracts/fixtures/data/call_with_limit.wat similarity index 100% rename from substrate/frame/contracts/fixtures/call_with_limit.wat rename to substrate/frame/contracts/fixtures/data/call_with_limit.wat diff --git a/substrate/frame/contracts/fixtures/caller_contract.wat b/substrate/frame/contracts/fixtures/data/caller_contract.wat similarity index 100% rename from substrate/frame/contracts/fixtures/caller_contract.wat rename to substrate/frame/contracts/fixtures/data/caller_contract.wat diff --git a/substrate/frame/contracts/fixtures/chain_extension.wat b/substrate/frame/contracts/fixtures/data/chain_extension.wat similarity index 100% rename from substrate/frame/contracts/fixtures/chain_extension.wat rename to substrate/frame/contracts/fixtures/data/chain_extension.wat diff --git a/substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat b/substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat similarity index 100% rename from substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat rename to substrate/frame/contracts/fixtures/data/chain_extension_temp_storage.wat diff --git a/substrate/frame/contracts/fixtures/create_storage_and_call.wat b/substrate/frame/contracts/fixtures/data/create_storage_and_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/create_storage_and_call.wat rename to substrate/frame/contracts/fixtures/data/create_storage_and_call.wat diff --git a/substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat b/substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat similarity index 100% rename from substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat rename to substrate/frame/contracts/fixtures/data/create_storage_and_instantiate.wat diff --git a/substrate/frame/contracts/fixtures/crypto_hashes.wat b/substrate/frame/contracts/fixtures/data/crypto_hashes.wat similarity index 100% rename from substrate/frame/contracts/fixtures/crypto_hashes.wat rename to substrate/frame/contracts/fixtures/data/crypto_hashes.wat diff --git a/substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat b/substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat similarity index 100% rename from substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat rename to substrate/frame/contracts/fixtures/data/debug_message_invalid_utf8.wat diff --git a/substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat b/substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat similarity index 100% rename from substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat rename to substrate/frame/contracts/fixtures/data/debug_message_logging_disabled.wat diff --git a/substrate/frame/contracts/fixtures/debug_message_works.wat b/substrate/frame/contracts/fixtures/data/debug_message_works.wat similarity index 100% rename from substrate/frame/contracts/fixtures/debug_message_works.wat rename to substrate/frame/contracts/fixtures/data/debug_message_works.wat diff --git a/substrate/frame/contracts/fixtures/delegate_call.wat b/substrate/frame/contracts/fixtures/data/delegate_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/delegate_call.wat rename to substrate/frame/contracts/fixtures/data/delegate_call.wat diff --git a/substrate/frame/contracts/fixtures/delegate_call_lib.wat b/substrate/frame/contracts/fixtures/data/delegate_call_lib.wat similarity index 100% rename from substrate/frame/contracts/fixtures/delegate_call_lib.wat rename to substrate/frame/contracts/fixtures/data/delegate_call_lib.wat diff --git a/substrate/frame/contracts/fixtures/delegate_call_simple.wat b/substrate/frame/contracts/fixtures/data/delegate_call_simple.wat similarity index 100% rename from substrate/frame/contracts/fixtures/delegate_call_simple.wat rename to substrate/frame/contracts/fixtures/data/delegate_call_simple.wat diff --git a/substrate/frame/contracts/fixtures/destroy_and_transfer.wat b/substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat similarity index 100% rename from substrate/frame/contracts/fixtures/destroy_and_transfer.wat rename to substrate/frame/contracts/fixtures/data/destroy_and_transfer.wat diff --git a/substrate/frame/contracts/fixtures/drain.wat b/substrate/frame/contracts/fixtures/data/drain.wat similarity index 100% rename from substrate/frame/contracts/fixtures/drain.wat rename to substrate/frame/contracts/fixtures/data/drain.wat diff --git a/substrate/frame/contracts/fixtures/dummy.wat b/substrate/frame/contracts/fixtures/data/dummy.wat similarity index 100% rename from substrate/frame/contracts/fixtures/dummy.wat rename to substrate/frame/contracts/fixtures/data/dummy.wat diff --git a/substrate/frame/contracts/fixtures/ecdsa_recover.wat b/substrate/frame/contracts/fixtures/data/ecdsa_recover.wat similarity index 100% rename from substrate/frame/contracts/fixtures/ecdsa_recover.wat rename to substrate/frame/contracts/fixtures/data/ecdsa_recover.wat diff --git a/substrate/frame/contracts/fixtures/event_and_return_on_deploy.wat b/substrate/frame/contracts/fixtures/data/event_and_return_on_deploy.wat similarity index 100% rename from substrate/frame/contracts/fixtures/event_and_return_on_deploy.wat rename to substrate/frame/contracts/fixtures/data/event_and_return_on_deploy.wat diff --git a/substrate/frame/contracts/fixtures/event_size.wat b/substrate/frame/contracts/fixtures/data/event_size.wat similarity index 100% rename from substrate/frame/contracts/fixtures/event_size.wat rename to substrate/frame/contracts/fixtures/data/event_size.wat diff --git a/substrate/frame/contracts/fixtures/float_instruction.wat b/substrate/frame/contracts/fixtures/data/float_instruction.wat similarity index 100% rename from substrate/frame/contracts/fixtures/float_instruction.wat rename to substrate/frame/contracts/fixtures/data/float_instruction.wat diff --git a/substrate/frame/contracts/fixtures/instantiate_return_code.wat b/substrate/frame/contracts/fixtures/data/instantiate_return_code.wat similarity index 100% rename from substrate/frame/contracts/fixtures/instantiate_return_code.wat rename to substrate/frame/contracts/fixtures/data/instantiate_return_code.wat diff --git a/substrate/frame/contracts/fixtures/invalid_contract_no_call.wat b/substrate/frame/contracts/fixtures/data/invalid_contract_no_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/invalid_contract_no_call.wat rename to substrate/frame/contracts/fixtures/data/invalid_contract_no_call.wat diff --git a/substrate/frame/contracts/fixtures/invalid_contract_no_memory.wat b/substrate/frame/contracts/fixtures/data/invalid_contract_no_memory.wat similarity index 100% rename from substrate/frame/contracts/fixtures/invalid_contract_no_memory.wat rename to substrate/frame/contracts/fixtures/data/invalid_contract_no_memory.wat diff --git a/substrate/frame/contracts/fixtures/invalid_module.wat b/substrate/frame/contracts/fixtures/data/invalid_module.wat similarity index 100% rename from substrate/frame/contracts/fixtures/invalid_module.wat rename to substrate/frame/contracts/fixtures/data/invalid_module.wat diff --git a/substrate/frame/contracts/fixtures/multi_store.wat b/substrate/frame/contracts/fixtures/data/multi_store.wat similarity index 100% rename from substrate/frame/contracts/fixtures/multi_store.wat rename to substrate/frame/contracts/fixtures/data/multi_store.wat diff --git a/substrate/frame/contracts/fixtures/new_set_code_hash_contract.wat b/substrate/frame/contracts/fixtures/data/new_set_code_hash_contract.wat similarity index 100% rename from substrate/frame/contracts/fixtures/new_set_code_hash_contract.wat rename to substrate/frame/contracts/fixtures/data/new_set_code_hash_contract.wat diff --git a/substrate/frame/contracts/fixtures/ok_trap_revert.wat b/substrate/frame/contracts/fixtures/data/ok_trap_revert.wat similarity index 100% rename from substrate/frame/contracts/fixtures/ok_trap_revert.wat rename to substrate/frame/contracts/fixtures/data/ok_trap_revert.wat diff --git a/substrate/frame/contracts/fixtures/reentrance_count_call.wat b/substrate/frame/contracts/fixtures/data/reentrance_count_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/reentrance_count_call.wat rename to substrate/frame/contracts/fixtures/data/reentrance_count_call.wat diff --git a/substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat b/substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat rename to substrate/frame/contracts/fixtures/data/reentrance_count_delegated_call.wat diff --git a/substrate/frame/contracts/fixtures/return_with_data.wat b/substrate/frame/contracts/fixtures/data/return_with_data.wat similarity index 100% rename from substrate/frame/contracts/fixtures/return_with_data.wat rename to substrate/frame/contracts/fixtures/data/return_with_data.wat diff --git a/substrate/frame/contracts/fixtures/run_out_of_gas.wat b/substrate/frame/contracts/fixtures/data/run_out_of_gas.wat similarity index 100% rename from substrate/frame/contracts/fixtures/run_out_of_gas.wat rename to substrate/frame/contracts/fixtures/data/run_out_of_gas.wat diff --git a/substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat b/substrate/frame/contracts/fixtures/data/run_out_of_gas_start_fn.wat similarity index 100% rename from substrate/frame/contracts/fixtures/run_out_of_gas_start_fn.wat rename to substrate/frame/contracts/fixtures/data/run_out_of_gas_start_fn.wat diff --git a/substrate/frame/contracts/fixtures/seal_input_noop.wat b/substrate/frame/contracts/fixtures/data/seal_input_noop.wat similarity index 100% rename from substrate/frame/contracts/fixtures/seal_input_noop.wat rename to substrate/frame/contracts/fixtures/data/seal_input_noop.wat diff --git a/substrate/frame/contracts/fixtures/seal_input_once.wat b/substrate/frame/contracts/fixtures/data/seal_input_once.wat similarity index 100% rename from substrate/frame/contracts/fixtures/seal_input_once.wat rename to substrate/frame/contracts/fixtures/data/seal_input_once.wat diff --git a/substrate/frame/contracts/fixtures/seal_input_twice.wat b/substrate/frame/contracts/fixtures/data/seal_input_twice.wat similarity index 100% rename from substrate/frame/contracts/fixtures/seal_input_twice.wat rename to substrate/frame/contracts/fixtures/data/seal_input_twice.wat diff --git a/substrate/frame/contracts/fixtures/self_destruct.wat b/substrate/frame/contracts/fixtures/data/self_destruct.wat similarity index 100% rename from substrate/frame/contracts/fixtures/self_destruct.wat rename to substrate/frame/contracts/fixtures/data/self_destruct.wat diff --git a/substrate/frame/contracts/fixtures/self_destructing_constructor.wat b/substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat similarity index 100% rename from substrate/frame/contracts/fixtures/self_destructing_constructor.wat rename to substrate/frame/contracts/fixtures/data/self_destructing_constructor.wat diff --git a/substrate/frame/contracts/fixtures/set_code_hash.wat b/substrate/frame/contracts/fixtures/data/set_code_hash.wat similarity index 100% rename from substrate/frame/contracts/fixtures/set_code_hash.wat rename to substrate/frame/contracts/fixtures/data/set_code_hash.wat diff --git a/substrate/frame/contracts/fixtures/set_empty_storage.wat b/substrate/frame/contracts/fixtures/data/set_empty_storage.wat similarity index 100% rename from substrate/frame/contracts/fixtures/set_empty_storage.wat rename to substrate/frame/contracts/fixtures/data/set_empty_storage.wat diff --git a/substrate/frame/contracts/fixtures/sr25519_verify.wat b/substrate/frame/contracts/fixtures/data/sr25519_verify.wat similarity index 100% rename from substrate/frame/contracts/fixtures/sr25519_verify.wat rename to substrate/frame/contracts/fixtures/data/sr25519_verify.wat diff --git a/substrate/frame/contracts/fixtures/storage_size.wat b/substrate/frame/contracts/fixtures/data/storage_size.wat similarity index 100% rename from substrate/frame/contracts/fixtures/storage_size.wat rename to substrate/frame/contracts/fixtures/data/storage_size.wat diff --git a/substrate/frame/contracts/fixtures/store_call.wat b/substrate/frame/contracts/fixtures/data/store_call.wat similarity index 100% rename from substrate/frame/contracts/fixtures/store_call.wat rename to substrate/frame/contracts/fixtures/data/store_call.wat diff --git a/substrate/frame/contracts/fixtures/store_deploy.wat b/substrate/frame/contracts/fixtures/data/store_deploy.wat similarity index 100% rename from substrate/frame/contracts/fixtures/store_deploy.wat rename to substrate/frame/contracts/fixtures/data/store_deploy.wat diff --git a/substrate/frame/contracts/fixtures/transfer_return_code.wat b/substrate/frame/contracts/fixtures/data/transfer_return_code.wat similarity index 100% rename from substrate/frame/contracts/fixtures/transfer_return_code.wat rename to substrate/frame/contracts/fixtures/data/transfer_return_code.wat diff --git a/substrate/frame/contracts/fixtures/src/lib.rs b/substrate/frame/contracts/fixtures/src/lib.rs new file mode 100644 index 00000000000..32f4023e644 --- /dev/null +++ b/substrate/frame/contracts/fixtures/src/lib.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_runtime::traits::Hash; +use std::{env::var, path::PathBuf}; + +fn fixtures_root_dir() -> PathBuf { + match (var("CARGO_MANIFEST_DIR"), var("CARGO_PKG_NAME")) { + // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder + (Err(_), _) => "substrate/frame/contracts/fixtures/data".into(), + (Ok(path), Ok(s)) if s == "pallet-contracts" => PathBuf::from(path).join("fixtures/data"), + (Ok(_), pkg_name) => panic!("Failed to resolve fixture dir for tests from {pkg_name:?}."), + } +} + +/// Load a given wasm module represented by a .wat file and returns a wasm binary contents along +/// with it's hash. +/// +/// The fixture files are located under the `fixtures/` directory. +pub fn compile_module(fixture_name: &str) -> wat::Result<(Vec, ::Output)> +where + T: frame_system::Config, +{ + let fixture_path = fixtures_root_dir().join(format!("{fixture_name}.wat")); + let wasm_binary = wat::parse_file(fixture_path)?; + let code_hash = T::Hashing::hash(&wasm_binary); + Ok((wasm_binary, code_hash)) +} diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 3cc5e7cf4a1..e7784b02b74 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -53,6 +53,7 @@ use frame_support::{ weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use frame_system::{EventRecord, Phase}; +use pallet_contracts_fixtures::compile_module; use pallet_contracts_primitives::CodeUploadReturnValue; use pretty_assertions::{assert_eq, assert_ne}; use sp_core::ByteArray; @@ -555,29 +556,6 @@ impl ExtBuilder { } } -/// Load a given wasm module represented by a .wat file and returns a wasm binary contents along -/// with it's hash. -/// -/// The fixture files are located under the `fixtures/` directory. -fn compile_module(fixture_name: &str) -> wat::Result<(Vec, ::Output)> -where - T: frame_system::Config, -{ - let fixture_path = [ - // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder - std::env::var("CARGO_MANIFEST_DIR") - .as_deref() - .unwrap_or("substrate/frame/contracts"), - "/fixtures/", - fixture_name, - ".wat", - ] - .concat(); - let wasm_binary = wat::parse_file(fixture_path)?; - let code_hash = T::Hashing::hash(&wasm_binary); - Ok((wasm_binary, code_hash)) -} - fn initialize_block(number: u64) { System::reset_events(); System::initialize(&number, &[0u8; 32].into(), &Default::default()); -- GitLab From 3f0383a5b8b6861c0ee0c64a17bed78c07956ba5 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Fri, 10 Nov 2023 15:12:47 +0200 Subject: [PATCH 482/633] [pallet-message-queue] Implement impl_trait_for_tuples for QueuePausedQuery (#2227) These changes are required so that the bridgehub system runtimes can more easily be configured with multiple message processors Example usage: ```rust use frame_support::traits::QueuePausedQuery; impl pallet_message_queue::Config for Runtime { type QueuePausedQuery = (A, B, C) } --- substrate/frame/support/src/traits/messages.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index 654380dbb0a..58815b107c8 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -240,8 +240,14 @@ pub trait QueuePausedQuery { fn is_paused(origin: &Origin) -> bool; } -impl QueuePausedQuery for () { - fn is_paused(_: &Origin) -> bool { +#[impl_trait_for_tuples::impl_for_tuples(8)] +impl QueuePausedQuery for Tuple { + fn is_paused(origin: &Origin) -> bool { + for_tuples!( #( + if Tuple::is_paused(origin) { + return true; + } + )* ); false } } -- GitLab From 84ddbaf68445fed23a88a086ee37bdcdbcb7356a Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 10 Nov 2023 17:14:05 +0400 Subject: [PATCH 483/633] Improve `VersionedMigration` naming conventions (#2264) As suggested by @ggwpez (https://github.com/paritytech/polkadot-sdk/pull/2142#discussion_r1388145872), remove the `VersionChecked` prefix from version checked migrations (but leave `VersionUnchecked` prefixes) --------- Co-authored-by: command-bot <> --- .../common/src/assigned_slots/migration.rs | 10 +++++----- .../common/src/paras_registrar/migration.rs | 15 +++++++-------- polkadot/runtime/rococo/src/lib.rs | 6 +++--- polkadot/runtime/westend/src/lib.rs | 4 ++-- polkadot/xcm/pallet-xcm/src/migration.rs | 4 ++-- substrate/frame/society/src/migrations.rs | 15 +++++++-------- substrate/frame/support/src/migrations.rs | 4 ++-- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index 0e88b27a1ff..ba3108c0aa3 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -25,8 +25,8 @@ use sp_std::vec::Vec; pub mod v1 { use super::*; - pub struct MigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { + pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { let onchain_version = Pallet::::on_chain_storage_version(); @@ -60,13 +60,13 @@ pub mod v1 { } } - /// [`MigrateToV1`] wrapped in a + /// [`VersionUncheckedMigrateToV1`] wrapped in a /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the /// migration is only performed when on-chain version is 0. - pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< + pub type MigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, - MigrateToV1, + VersionUncheckedMigrateToV1, Pallet, ::DbWeight, >; diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs index b767985489d..f977674a1e4 100644 --- a/polkadot/runtime/common/src/paras_registrar/migration.rs +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -60,11 +60,10 @@ impl> OnRuntimeUpgrade } } -pub type VersionCheckedMigrateToV1 = - frame_support::migrations::VersionedMigration< - 0, - 1, - VersionUncheckedMigrateToV1, - super::Pallet, - ::DbWeight, - >; +pub type MigrateToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + VersionUncheckedMigrateToV1, + super::Pallet, + ::DbWeight, +>; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 4f542354346..697d22c311a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1472,14 +1472,14 @@ pub mod migrations { /// Unreleased migrations. Add new ones here: pub type Unreleased = ( - pallet_society::migrations::VersionCheckedMigrateToV2, + pallet_society::migrations::MigrateToV2, pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, - assigned_slots::migration::v1::VersionCheckedMigrateToV1, + assigned_slots::migration::v1::MigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, parachains_configuration::migration::v9::MigrateToV9, - paras_registrar::migration::VersionCheckedMigrateToV1, + paras_registrar::migration::MigrateToV1, pallet_referenda::migration::v1::MigrateV0ToV1, pallet_referenda::migration::v1::MigrateV0ToV1, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index ec94973af4f..fe9ed22f437 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1549,12 +1549,12 @@ pub mod migrations { pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, pallet_staking::migrations::v14::MigrateToV14, - assigned_slots::migration::v1::VersionCheckedMigrateToV1, + assigned_slots::migration::v1::MigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, - paras_registrar::migration::VersionCheckedMigrateToV1, + paras_registrar::migration::MigrateToV1, pallet_nomination_pools::migration::versioned_migrations::V5toV6, pallet_referenda::migration::v1::MigrateV0ToV1, pallet_nomination_pools::migration::versioned_migrations::V6ToV7, diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index ba3cdb5c51e..2793afcc910 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -31,7 +31,7 @@ pub mod v1 { /// checking, the version checking is not complete as it will begin failing after the upgrade is /// enacted on-chain. /// - /// Use experimental [`VersionCheckedMigrateToV1`] instead. + /// Use experimental [`MigrateToV1`] instead. pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { @@ -65,7 +65,7 @@ pub mod v1 { /// /// Wrapped in [`frame_support::migrations::VersionedMigration`] so the pre/post checks don't /// begin failing after the upgrade is enacted on-chain. - pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedMigration< + pub type MigrateToV1 = frame_support::migrations::VersionedMigration< 0, 1, VersionUncheckedMigrateToV1, diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index 553eea1a795..a995c9d7be7 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -95,14 +95,13 @@ impl< /// [`VersionUncheckedMigrateToV2`] wrapped in a [`frame_support::migrations::VersionedMigration`], /// ensuring the migration is only performed when on-chain version is 0. -pub type VersionCheckedMigrateToV2 = - frame_support::migrations::VersionedMigration< - 0, - 2, - VersionUncheckedMigrateToV2, - crate::pallet::Pallet, - ::DbWeight, - >; +pub type MigrateToV2 = frame_support::migrations::VersionedMigration< + 0, + 2, + VersionUncheckedMigrateToV2, + crate::pallet::Pallet, + ::DbWeight, +>; pub(crate) mod old { use super::*; diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 22471e883a7..a9eb460421f 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -51,7 +51,7 @@ use sp_std::marker::PhantomData; /// // OnRuntimeUpgrade implementation... /// } /// -/// pub type VersionCheckedMigrateV5ToV6 = +/// pub type MigrateV5ToV6 = /// VersionedMigration< /// 5, /// 6, @@ -63,7 +63,7 @@ use sp_std::marker::PhantomData; /// // Migrations tuple to pass to the Executive pallet: /// pub type Migrations = ( /// // other migrations... -/// VersionCheckedMigrateV5ToV6, +/// MigrateV5ToV6, /// // other migrations... /// ); /// ``` -- GitLab From 6b7be115fd523057d01cea46e9680a62a0b08d97 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 10 Nov 2023 16:38:24 +0100 Subject: [PATCH 484/633] Contracts: Add XCM traits to interface with contracts (#2086) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are introducing a new set of `XcmController` traits (final name yet to be determined). These traits are implemented by `pallet-xcm` and allows other pallets, such as `pallet_contracts`, to rely on these traits instead of tight coupling them to `pallet-xcm`. Using only the existing Xcm traits would mean duplicating the logic from `pallet-xcm` in these other pallets, which we aim to avoid. Our objective is to ensure that when these APIs are called from `pallet-contracts`, they produce the exact same outcomes as if called directly from `pallet-xcm`. The other benefits is that we can also expose return values to `pallet-contracts` instead of just calling `pallet-xcm` dispatchable and getting a `DispatchResult` back. See traits integration in this PR https://github.com/paritytech/polkadot-sdk/pull/1248, where the traits are used as follow to define and implement `pallet-contracts` Config. ```rs // Contracts config: pub trait Config: frame_system::Config { // ... /// A type that exposes XCM APIs, allowing contracts to interact with other parachains, and /// execute XCM programs. type Xcm: xcm_executor::traits::Controller< OriginFor, ::RuntimeCall, BlockNumberFor, >; } // implementation impl pallet_contracts::Config for Runtime { // ... type Xcm = pallet_xcm::Pallet; } ``` --------- Co-authored-by: Alexander Theißen Co-authored-by: command-bot <> --- .../src/weights/pallet_xcm.rs | 187 ++++++---- .../src/weights/pallet_xcm.rs | 163 +++++---- .../src/weights/pallet_xcm.rs | 182 ++++++---- .../src/weights/pallet_xcm.rs | 161 +++++---- .../src/weights/pallet_xcm.rs | 151 +++++--- .../src/weights/pallet_xcm.rs | 159 +++++---- .../src/weights/pallet_xcm.rs | 163 +++++---- .../src/weights/pallet_xcm.rs | 27 ++ .../src/weights/pallet_xcm.rs | 215 ++++++----- .../runtime/rococo/src/weights/pallet_xcm.rs | 329 ++++++++--------- .../runtime/westend/src/weights/pallet_xcm.rs | 333 +++++++++--------- polkadot/xcm/pallet-xcm/Cargo.toml | 3 +- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 27 ++ polkadot/xcm/pallet-xcm/src/lib.rs | 157 +++++++-- polkadot/xcm/xcm-builder/src/controller.rs | 187 ++++++++++ polkadot/xcm/xcm-builder/src/lib.rs | 6 + polkadot/xcm/xcm-builder/src/tests/mock.rs | 2 +- .../xcm-executor/src/traits/on_response.rs | 46 ++- prdoc/pr_2086.prdoc | 15 + 19 files changed, 1602 insertions(+), 911 deletions(-) create mode 100644 polkadot/xcm/xcm-builder/src/controller.rs create mode 100644 prdoc/pr_2086.prdoc diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs index becfca7a891..1e4a723e10f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, 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-yprdrvc7-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 -// --chain=asset-hub-kusama-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-kusama/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -61,12 +62,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 25_043_000 picoseconds. + Weight::from_parts(25_670_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) @@ -75,8 +76,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 24_785_000 picoseconds. - Weight::from_parts(25_097_000, 0) + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_261_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -86,8 +87,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 18_561_000 picoseconds. - Weight::from_parts(19_121_000, 0) + // Minimum execution time: 14_107_000 picoseconds. + Weight::from_parts(14_500_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -107,8 +108,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_298_000 picoseconds. - Weight::from_parts(9_721_000, 0) + // Minimum execution time: 7_175_000 picoseconds. + Weight::from_parts(7_493_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,8 +119,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_912_000 picoseconds. - Weight::from_parts(3_262_000, 0) + // Minimum execution time: 2_162_000 picoseconds. + Weight::from_parts(2_278_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -127,6 +128,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -141,16 +144,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 29_144_000 picoseconds. + Weight::from_parts(30_134_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -165,12 +170,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `363` + // Estimated: `3828` + // Minimum execution time: 31_522_000 picoseconds. + Weight::from_parts(32_679_000, 0) + .saturating_add(Weight::from_parts(0, 3828)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -179,8 +184,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_940_000 picoseconds. - Weight::from_parts(3_085_000, 0) + // Minimum execution time: 2_338_000 picoseconds. + Weight::from_parts(2_494_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -190,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 17_400_000 picoseconds. - Weight::from_parts(17_759_000, 0) + // Minimum execution time: 17_315_000 picoseconds. + Weight::from_parts(17_787_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -202,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 17_287_000 picoseconds. - Weight::from_parts(17_678_000, 0) + // Minimum execution time: 17_273_000 picoseconds. + Weight::from_parts(17_712_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -214,13 +219,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 18_941_000 picoseconds. - Weight::from_parts(19_285_000, 0) + // Minimum execution time: 18_395_000 picoseconds. + Weight::from_parts(19_095_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -233,12 +240,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 27_343_000 picoseconds. + Weight::from_parts(28_068_000, 0) + .saturating_add(Weight::from_parts(0, 6152)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -247,8 +254,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_182_000 picoseconds. - Weight::from_parts(9_498_000, 0) + // Minimum execution time: 9_156_000 picoseconds. + Weight::from_parts(9_552_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -258,14 +265,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 17_519_000 picoseconds. - Weight::from_parts(17_943_000, 0) + // Minimum execution time: 17_454_000 picoseconds. + Weight::from_parts(17_831_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -278,12 +287,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `215` + // Estimated: `11105` + // Minimum execution time: 34_299_000 picoseconds. + Weight::from_parts(35_156_000, 0) + .saturating_add(Weight::from_parts(0, 11105)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 4_508_000 picoseconds. + Weight::from_parts(4_702_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7740` + // Estimated: `11205` + // Minimum execution time: 26_557_000 picoseconds. + Weight::from_parts(26_980_000, 0) + .saturating_add(Weight::from_parts(0, 11205)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs index 0d3fe0adb1b..27867e278ed 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, 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-yprdrvc7-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 -// --chain=asset-hub-polkadot-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-polkadot/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=asset-hub-polkadot-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -63,10 +64,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3540` - // Minimum execution time: 28_284_000 picoseconds. - Weight::from_parts(29_186_000, 0) + // Minimum execution time: 25_203_000 picoseconds. + Weight::from_parts(25_927_000, 0) .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) @@ -75,8 +76,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 24_830_000 picoseconds. - Weight::from_parts(26_312_000, 0) + // Minimum execution time: 20_113_000 picoseconds. + Weight::from_parts(20_439_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -86,8 +87,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 18_584_000 picoseconds. - Weight::from_parts(19_083_000, 0) + // Minimum execution time: 14_959_000 picoseconds. + Weight::from_parts(15_264_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -107,8 +108,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_415_000 picoseconds. - Weight::from_parts(9_821_000, 0) + // Minimum execution time: 7_399_000 picoseconds. + Weight::from_parts(7_674_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,8 +119,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_902_000 picoseconds. - Weight::from_parts(3_377_000, 0) + // Minimum execution time: 2_388_000 picoseconds. + Weight::from_parts(2_522_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -127,6 +128,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -143,14 +146,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3540` - // Minimum execution time: 32_730_000 picoseconds. - Weight::from_parts(33_879_000, 0) + // Minimum execution time: 28_791_000 picoseconds. + Weight::from_parts(29_443_000, 0) .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -165,12 +170,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `257` - // Estimated: `3722` - // Minimum execution time: 34_053_000 picoseconds. - Weight::from_parts(34_506_000, 0) - .saturating_add(Weight::from_parts(0, 3722)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 30_880_000 picoseconds. + Weight::from_parts(31_675_000, 0) + .saturating_add(Weight::from_parts(0, 3757)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -179,8 +184,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_824_000 picoseconds. - Weight::from_parts(2_986_000, 0) + // Minimum execution time: 2_365_000 picoseconds. + Weight::from_parts(2_550_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -190,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `129` // Estimated: `11019` - // Minimum execution time: 17_011_000 picoseconds. - Weight::from_parts(17_488_000, 0) + // Minimum execution time: 17_185_000 picoseconds. + Weight::from_parts(17_680_000, 0) .saturating_add(Weight::from_parts(0, 11019)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -202,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `133` // Estimated: `11023` - // Minimum execution time: 17_191_000 picoseconds. - Weight::from_parts(17_784_000, 0) + // Minimum execution time: 16_974_000 picoseconds. + Weight::from_parts(17_660_000, 0) .saturating_add(Weight::from_parts(0, 11023)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -214,13 +219,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `140` // Estimated: `13505` - // Minimum execution time: 18_625_000 picoseconds. - Weight::from_parts(19_177_000, 0) + // Minimum execution time: 18_536_000 picoseconds. + Weight::from_parts(19_292_000, 0) .saturating_add(Weight::from_parts(0, 13505)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -235,10 +242,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 30_762_000 picoseconds. - Weight::from_parts(31_481_000, 0) + // Minimum execution time: 27_368_000 picoseconds. + Weight::from_parts(28_161_000, 0) .saturating_add(Weight::from_parts(0, 6082)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -247,8 +254,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `172` // Estimated: `8587` - // Minimum execution time: 9_025_000 picoseconds. - Weight::from_parts(9_423_000, 0) + // Minimum execution time: 9_553_000 picoseconds. + Weight::from_parts(9_899_000, 0) .saturating_add(Weight::from_parts(0, 8587)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -258,14 +265,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `140` // Estimated: `11030` - // Minimum execution time: 17_550_000 picoseconds. - Weight::from_parts(17_939_000, 0) + // Minimum execution time: 17_445_000 picoseconds. + Weight::from_parts(18_206_000, 0) .saturating_add(Weight::from_parts(0, 11030)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -280,10 +289,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `146` // Estimated: `11036` - // Minimum execution time: 36_922_000 picoseconds. - Weight::from_parts(37_709_000, 0) + // Minimum execution time: 34_200_000 picoseconds. + Weight::from_parts(35_198_000, 0) .saturating_add(Weight::from_parts(0, 11036)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `1554` + // Minimum execution time: 4_679_000 picoseconds. + Weight::from_parts(4_841_000, 0) + .saturating_add(Weight::from_parts(0, 1554)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7706` + // Estimated: `11171` + // Minimum execution time: 27_281_000 picoseconds. + Weight::from_parts(27_694_000, 0) + .saturating_add(Weight::from_parts(0, 11171)) + .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_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index 909d7f28907..afe85fdaf28 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -17,27 +17,25 @@ //! 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: `[]` +//! DATE: 2023-11-10, 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 +//! HOSTNAME: `runner-yprdrvc7-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 +// 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/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=asset-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -62,35 +62,39 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 24_498_000 picoseconds. + Weight::from_parts(25_385_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + /// 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`) 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)) + // Measured: `39` + // Estimated: `3504` + // Minimum execution time: 19_746_000 picoseconds. + Weight::from_parts(20_535_000, 0) + .saturating_add(Weight::from_parts(0, 3504)) + .saturating_add(T::DbWeight::get().reads(2)) } + /// 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`) 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)) + // Measured: `39` + // Estimated: `3504` + // Minimum execution time: 15_059_000 picoseconds. + Weight::from_parts(15_386_000, 0) + .saturating_add(Weight::from_parts(0, 3504)) + .saturating_add(T::DbWeight::get().reads(2)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -108,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_298_000 picoseconds. - Weight::from_parts(9_721_000, 0) + // Minimum execution time: 7_108_000 picoseconds. + Weight::from_parts(7_458_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -119,8 +123,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_912_000 picoseconds. - Weight::from_parts(3_262_000, 0) + // Minimum execution time: 2_205_000 picoseconds. + Weight::from_parts(2_360_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -128,6 +132,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -142,16 +148,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 29_099_000 picoseconds. + Weight::from_parts(29_580_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -166,12 +174,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `363` + // Estimated: `3828` + // Minimum execution time: 31_161_000 picoseconds. + Weight::from_parts(31_933_000, 0) + .saturating_add(Weight::from_parts(0, 3828)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -180,8 +188,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_940_000 picoseconds. - Weight::from_parts(3_085_000, 0) + // Minimum execution time: 2_158_000 picoseconds. + Weight::from_parts(2_316_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -191,8 +199,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 17_400_000 picoseconds. - Weight::from_parts(17_759_000, 0) + // Minimum execution time: 16_934_000 picoseconds. + Weight::from_parts(17_655_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -203,8 +211,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 17_287_000 picoseconds. - Weight::from_parts(17_678_000, 0) + // Minimum execution time: 17_658_000 picoseconds. + Weight::from_parts(17_973_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -215,13 +223,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 18_941_000 picoseconds. - Weight::from_parts(19_285_000, 0) + // Minimum execution time: 18_673_000 picoseconds. + Weight::from_parts(19_027_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -234,12 +244,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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)) + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 27_171_000 picoseconds. + Weight::from_parts(27_802_000, 0) + .saturating_add(Weight::from_parts(0, 6152)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -248,8 +258,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_182_000 picoseconds. - Weight::from_parts(9_498_000, 0) + // Minimum execution time: 9_423_000 picoseconds. + Weight::from_parts(9_636_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -259,14 +269,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 17_519_000 picoseconds. - Weight::from_parts(17_943_000, 0) + // Minimum execution time: 17_442_000 picoseconds. + Weight::from_parts(17_941_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -279,12 +291,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `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)) + // Measured: `215` + // Estimated: `11105` + // Minimum execution time: 34_340_000 picoseconds. + Weight::from_parts(34_934_000, 0) + .saturating_add(Weight::from_parts(0, 11105)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 5_496_000 picoseconds. + Weight::from_parts(5_652_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7740` + // Estimated: `11205` + // Minimum execution time: 26_140_000 picoseconds. + Weight::from_parts(26_824_000, 0) + .saturating_add(Weight::from_parts(0, 11205)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 5c97d358591..340edafb0b0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, 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-yprdrvc7-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 -// --chain=asset-hub-westend-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-westend/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=asset-hub-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -63,10 +64,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 29_833_000 picoseconds. - Weight::from_parts(30_472_000, 0) + // Minimum execution time: 25_534_000 picoseconds. + Weight::from_parts(26_413_000, 0) .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) @@ -75,8 +76,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 22_922_000 picoseconds. - Weight::from_parts(23_650_000, 0) + // Minimum execution time: 20_513_000 picoseconds. + Weight::from_parts(20_837_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -86,8 +87,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 17_468_000 picoseconds. - Weight::from_parts(18_068_000, 0) + // Minimum execution time: 14_977_000 picoseconds. + Weight::from_parts(15_207_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -95,8 +96,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_780_000 picoseconds. - Weight::from_parts(9_201_000, 0) + // Minimum execution time: 7_440_000 picoseconds. + Weight::from_parts(7_651_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -105,8 +106,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_886_000 picoseconds. - Weight::from_parts(9_102_000, 0) + // Minimum execution time: 7_253_000 picoseconds. + Weight::from_parts(7_584_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -116,8 +117,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_665_000 picoseconds. - Weight::from_parts(2_884_000, 0) + // Minimum execution time: 2_299_000 picoseconds. + Weight::from_parts(2_435_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -125,6 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -141,14 +144,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 34_513_000 picoseconds. - Weight::from_parts(36_207_000, 0) + // Minimum execution time: 29_440_000 picoseconds. + Weight::from_parts(30_675_000, 0) .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -165,10 +170,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 35_770_000 picoseconds. - Weight::from_parts(36_462_000, 0) + // Minimum execution time: 31_876_000 picoseconds. + Weight::from_parts(32_588_000, 0) .saturating_add(Weight::from_parts(0, 3828)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -177,8 +182,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_763_000 picoseconds. - Weight::from_parts(3_079_000, 0) + // Minimum execution time: 2_385_000 picoseconds. + Weight::from_parts(2_607_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -188,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 17_170_000 picoseconds. - Weight::from_parts(17_674_000, 0) + // Minimum execution time: 16_927_000 picoseconds. + Weight::from_parts(17_554_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -200,8 +205,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 16_857_000 picoseconds. - Weight::from_parts(17_407_000, 0) + // Minimum execution time: 16_965_000 picoseconds. + Weight::from_parts(17_807_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -212,13 +217,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 19_040_000 picoseconds. - Weight::from_parts(19_550_000, 0) + // Minimum execution time: 18_763_000 picoseconds. + Weight::from_parts(19_359_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -233,10 +240,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 31_623_000 picoseconds. - Weight::from_parts(32_646_000, 0) + // Minimum execution time: 27_371_000 picoseconds. + Weight::from_parts(28_185_000, 0) .saturating_add(Weight::from_parts(0, 6152)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -245,8 +252,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_148_000 picoseconds. - Weight::from_parts(9_402_000, 0) + // Minimum execution time: 9_165_000 picoseconds. + Weight::from_parts(9_539_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -256,14 +263,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 17_630_000 picoseconds. - Weight::from_parts(17_941_000, 0) + // Minimum execution time: 17_384_000 picoseconds. + Weight::from_parts(17_777_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -278,10 +287,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `11105` - // Minimum execution time: 38_425_000 picoseconds. - Weight::from_parts(39_219_000, 0) + // Minimum execution time: 34_260_000 picoseconds. + Weight::from_parts(35_428_000, 0) .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 4_710_000 picoseconds. + Weight::from_parts(4_900_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7740` + // Estimated: `11205` + // Minimum execution time: 26_843_000 picoseconds. + Weight::from_parts(27_404_000, 0) + .saturating_add(Weight::from_parts(0, 11205)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs index 730bc492684..7f4c2026f2b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-09, 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-yprdrvc7-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 -// --chain=bridge-hub-kusama-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/bridge-hubs/bridge-hub-kusama/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=bridge-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -63,10 +64,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 27_523_000 picoseconds. - Weight::from_parts(28_238_000, 0) + // Minimum execution time: 22_520_000 picoseconds. + Weight::from_parts(23_167_000, 0) .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) @@ -75,8 +76,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1489` - // Minimum execution time: 24_139_000 picoseconds. - Weight::from_parts(24_806_000, 0) + // Minimum execution time: 19_639_000 picoseconds. + Weight::from_parts(20_230_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -106,8 +107,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_988_000 picoseconds. - Weight::from_parts(9_227_000, 0) + // Minimum execution time: 7_175_000 picoseconds. + Weight::from_parts(7_496_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_571_000 picoseconds. - Weight::from_parts(2_667_000, 0) + // Minimum execution time: 2_126_000 picoseconds. + Weight::from_parts(2_359_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,6 +127,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -142,14 +145,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 33_194_000 picoseconds. - Weight::from_parts(34_089_000, 0) + // Minimum execution time: 27_229_000 picoseconds. + Weight::from_parts(27_673_000, 0) .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -166,10 +171,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 35_413_000 picoseconds. - Weight::from_parts(36_359_000, 0) + // Minimum execution time: 29_812_000 picoseconds. + Weight::from_parts(30_649_000, 0) .saturating_add(Weight::from_parts(0, 3720)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -178,8 +183,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_679_000 picoseconds. - Weight::from_parts(2_823_000, 0) + // Minimum execution time: 2_212_000 picoseconds. + Weight::from_parts(2_367_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -189,8 +194,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `95` // Estimated: `10985` - // Minimum execution time: 15_117_000 picoseconds. - Weight::from_parts(15_603_000, 0) + // Minimum execution time: 14_768_000 picoseconds. + Weight::from_parts(15_036_000, 0) .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -201,8 +206,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `99` // Estimated: `10989` - // Minimum execution time: 14_978_000 picoseconds. - Weight::from_parts(15_370_000, 0) + // Minimum execution time: 14_662_000 picoseconds. + Weight::from_parts(15_155_000, 0) .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -213,13 +218,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 16_549_000 picoseconds. - Weight::from_parts(16_944_000, 0) + // Minimum execution time: 16_198_000 picoseconds. + Weight::from_parts(16_456_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -234,10 +241,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 30_111_000 picoseconds. - Weight::from_parts(30_795_000, 0) + // Minimum execution time: 25_825_000 picoseconds. + Weight::from_parts(26_744_000, 0) .saturating_add(Weight::from_parts(0, 6046)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -247,7 +254,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Measured: `136` // Estimated: `8551` // Minimum execution time: 8_622_000 picoseconds. - Weight::from_parts(8_865_000, 0) + Weight::from_parts(8_931_000, 0) .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -257,14 +264,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `10996` - // Minimum execution time: 15_194_000 picoseconds. - Weight::from_parts(15_646_000, 0) + // Minimum execution time: 15_397_000 picoseconds. + Weight::from_parts(15_650_000, 0) .saturating_add(Weight::from_parts(0, 10996)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -279,10 +288,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `112` // Estimated: `11002` - // Minimum execution time: 36_625_000 picoseconds. - Weight::from_parts(37_571_000, 0) + // Minimum execution time: 32_330_000 picoseconds. + Weight::from_parts(33_255_000, 0) .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 4_142_000 picoseconds. + Weight::from_parts(4_308_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 25_814_000 picoseconds. + Weight::from_parts(26_213_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs index 98dd7e36f07..b73c009cbda 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, 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-yprdrvc7-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 -// --chain=bridge-hub-polkadot-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/bridge-hubs/bridge-hub-polkadot/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=bridge-hub-polkadot-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -63,10 +64,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_510_000 picoseconds. - Weight::from_parts(25_755_000, 0) + // Minimum execution time: 22_442_000 picoseconds. + Weight::from_parts(23_346_000, 0) .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) @@ -75,8 +76,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1489` - // Minimum execution time: 24_125_000 picoseconds. - Weight::from_parts(25_559_000, 0) + // Minimum execution time: 19_655_000 picoseconds. + Weight::from_parts(20_086_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -106,8 +107,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_625_000 picoseconds. - Weight::from_parts(9_232_000, 0) + // Minimum execution time: 6_858_000 picoseconds. + Weight::from_parts(7_225_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_690_000 picoseconds. - Weight::from_parts(2_906_000, 0) + // Minimum execution time: 2_099_000 picoseconds. + Weight::from_parts(2_190_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,6 +127,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -142,14 +145,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 30_131_000 picoseconds. - Weight::from_parts(31_138_000, 0) + // Minimum execution time: 27_073_000 picoseconds. + Weight::from_parts(27_584_000, 0) .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -164,12 +169,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 32_411_000 picoseconds. - Weight::from_parts(33_009_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `255` + // Estimated: `3720` + // Minimum execution time: 29_949_000 picoseconds. + Weight::from_parts(30_760_000, 0) + .saturating_add(Weight::from_parts(0, 3720)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -178,8 +183,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_548_000 picoseconds. - Weight::from_parts(2_727_000, 0) + // Minimum execution time: 2_192_000 picoseconds. + Weight::from_parts(2_276_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -189,8 +194,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `95` // Estimated: `10985` - // Minimum execution time: 15_298_000 picoseconds. - Weight::from_parts(15_964_000, 0) + // Minimum execution time: 14_681_000 picoseconds. + Weight::from_parts(15_131_000, 0) .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -201,8 +206,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `99` // Estimated: `10989` - // Minimum execution time: 14_927_000 picoseconds. - Weight::from_parts(15_528_000, 0) + // Minimum execution time: 14_523_000 picoseconds. + Weight::from_parts(15_113_000, 0) .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -213,13 +218,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 16_409_000 picoseconds. - Weight::from_parts(16_960_000, 0) + // Minimum execution time: 15_989_000 picoseconds. + Weight::from_parts(16_518_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -234,10 +241,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 28_204_000 picoseconds. - Weight::from_parts(28_641_000, 0) + // Minimum execution time: 25_127_000 picoseconds. + Weight::from_parts(25_773_000, 0) .saturating_add(Weight::from_parts(0, 6046)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -246,8 +253,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `8551` - // Minimum execution time: 8_576_000 picoseconds. - Weight::from_parts(8_895_000, 0) + // Minimum execution time: 8_352_000 picoseconds. + Weight::from_parts(8_592_000, 0) .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -257,14 +264,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `10996` - // Minimum execution time: 15_263_000 picoseconds. - Weight::from_parts(15_726_000, 0) + // Minimum execution time: 14_658_000 picoseconds. + Weight::from_parts(15_345_000, 0) .saturating_add(Weight::from_parts(0, 10996)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -279,10 +288,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `112` // Estimated: `11002` - // Minimum execution time: 34_186_000 picoseconds. - Weight::from_parts(35_204_000, 0) + // Minimum execution time: 31_478_000 picoseconds. + Weight::from_parts(32_669_000, 0) .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 4_066_000 picoseconds. + Weight::from_parts(4_267_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 25_260_000 picoseconds. + Weight::from_parts(25_570_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index a6e093c4b94..5aa4999c624 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, 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-yprdrvc7-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 -// --chain=bridge-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/bridge-hubs/bridge-hub-rococo/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -63,22 +64,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3540` - // Minimum execution time: 29_724_000 picoseconds. - Weight::from_parts(30_440_000, 0) + // Minimum execution time: 24_179_000 picoseconds. + Weight::from_parts(24_684_000, 0) .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + /// 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`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 26_779_000 picoseconds. - Weight::from_parts(27_249_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 21_093_000 picoseconds. + Weight::from_parts(21_523_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(2)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -106,8 +109,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_170_000 picoseconds. - Weight::from_parts(9_629_000, 0) + // Minimum execution time: 6_938_000 picoseconds. + Weight::from_parts(7_243_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,8 +120,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_769_000 picoseconds. - Weight::from_parts(2_933_000, 0) + // Minimum execution time: 2_159_000 picoseconds. + Weight::from_parts(2_290_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,6 +129,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -142,14 +147,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3540` - // Minimum execution time: 34_547_000 picoseconds. - Weight::from_parts(35_653_000, 0) + // Minimum execution time: 28_337_000 picoseconds. + Weight::from_parts(29_265_000, 0) .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -166,10 +173,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 36_274_000 picoseconds. - Weight::from_parts(37_281_000, 0) + // Minimum execution time: 30_599_000 picoseconds. + Weight::from_parts(31_272_000, 0) .saturating_add(Weight::from_parts(0, 3757)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -178,8 +185,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_749_000 picoseconds. - Weight::from_parts(2_917_000, 0) + // Minimum execution time: 2_132_000 picoseconds. + Weight::from_parts(2_280_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -189,8 +196,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `187` // Estimated: `11077` - // Minimum execution time: 17_649_000 picoseconds. - Weight::from_parts(17_964_000, 0) + // Minimum execution time: 18_262_000 picoseconds. + Weight::from_parts(18_640_000, 0) .saturating_add(Weight::from_parts(0, 11077)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -201,8 +208,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `191` // Estimated: `11081` - // Minimum execution time: 17_551_000 picoseconds. - Weight::from_parts(18_176_000, 0) + // Minimum execution time: 18_512_000 picoseconds. + Weight::from_parts(18_888_000, 0) .saturating_add(Weight::from_parts(0, 11081)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -213,13 +220,15 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `198` // Estimated: `13563` - // Minimum execution time: 19_261_000 picoseconds. - Weight::from_parts(19_714_000, 0) + // Minimum execution time: 19_362_000 picoseconds. + Weight::from_parts(20_056_000, 0) .saturating_add(Weight::from_parts(0, 13563)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -234,10 +243,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 31_630_000 picoseconds. - Weight::from_parts(32_340_000, 0) + // Minimum execution time: 27_318_000 picoseconds. + Weight::from_parts(28_075_000, 0) .saturating_add(Weight::from_parts(0, 6082)) - .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) @@ -246,8 +255,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `172` // Estimated: `8587` - // Minimum execution time: 9_218_000 picoseconds. - Weight::from_parts(9_558_000, 0) + // Minimum execution time: 9_930_000 picoseconds. + Weight::from_parts(10_192_000, 0) .saturating_add(Weight::from_parts(0, 8587)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -257,14 +266,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `198` // Estimated: `11088` - // Minimum execution time: 18_133_000 picoseconds. - Weight::from_parts(18_663_000, 0) + // Minimum execution time: 18_305_000 picoseconds. + Weight::from_parts(18_738_000, 0) .saturating_add(Weight::from_parts(0, 11088)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -279,10 +290,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `204` // Estimated: `11094` - // Minimum execution time: 38_878_000 picoseconds. - Weight::from_parts(39_779_000, 0) + // Minimum execution time: 34_559_000 picoseconds. + Weight::from_parts(35_241_000, 0) .saturating_add(Weight::from_parts(0, 11094)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `1554` + // Minimum execution time: 4_512_000 picoseconds. + Weight::from_parts(4_671_000, 0) + .saturating_add(Weight::from_parts(0, 1554)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7706` + // Estimated: `11171` + // Minimum execution time: 26_473_000 picoseconds. + Weight::from_parts(26_960_000, 0) + .saturating_add(Weight::from_parts(0, 11171)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index 72bdb282585..9f17d327024 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -286,4 +286,31 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 4_142_000 picoseconds. + Weight::from_parts(4_308_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 25_814_000 picoseconds. + Weight::from_parts(26_213_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } + diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs index 26e668854f2..57e50284147 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_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: `[]` +//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=collectives-polkadot-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -61,22 +62,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `3576` - // Minimum execution time: 27_795_000 picoseconds. - Weight::from_parts(28_215_000, 0) - .saturating_add(Weight::from_parts(0, 3576)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 25_050_000 picoseconds. + Weight::from_parts(26_382_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `32` + // Measured: `69` // Estimated: `1489` - // Minimum execution time: 23_847_000 picoseconds. - Weight::from_parts(24_332_000, 0) + // Minimum execution time: 21_625_000 picoseconds. + Weight::from_parts(22_076_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -106,8 +107,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_885_000 picoseconds. - Weight::from_parts(9_128_000, 0) + // Minimum execution time: 7_076_000 picoseconds. + Weight::from_parts(7_378_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_670_000 picoseconds. - Weight::from_parts(2_815_000, 0) + // Minimum execution time: 2_327_000 picoseconds. + Weight::from_parts(2_454_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,6 +127,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -140,16 +143,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `3576` - // Minimum execution time: 32_214_000 picoseconds. - Weight::from_parts(32_989_000, 0) - .saturating_add(Weight::from_parts(0, 3576)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 29_080_000 picoseconds. + Weight::from_parts(29_886_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -164,12 +169,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `294` - // Estimated: `3759` - // Minimum execution time: 33_638_000 picoseconds. - Weight::from_parts(34_206_000, 0) - .saturating_add(Weight::from_parts(0, 3759)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `363` + // Estimated: `3828` + // Minimum execution time: 30_746_000 picoseconds. + Weight::from_parts(31_631_000, 0) + .saturating_add(Weight::from_parts(0, 3828)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -178,8 +183,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_602_000 picoseconds. - Weight::from_parts(2_730_000, 0) + // Minimum execution time: 2_208_000 picoseconds. + Weight::from_parts(2_341_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -187,11 +192,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `129` - // Estimated: `11019` - // Minimum execution time: 16_199_000 picoseconds. - Weight::from_parts(16_833_000, 0) - .saturating_add(Weight::from_parts(0, 11019)) + // Measured: `162` + // Estimated: `11052` + // Minimum execution time: 16_239_000 picoseconds. + Weight::from_parts(16_881_000, 0) + .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,11 +204,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `133` - // Estimated: `11023` - // Minimum execution time: 16_561_000 picoseconds. - Weight::from_parts(16_872_000, 0) - .saturating_add(Weight::from_parts(0, 11023)) + // Measured: `166` + // Estimated: `11056` + // Minimum execution time: 16_711_000 picoseconds. + Weight::from_parts(16_944_000, 0) + .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -211,15 +216,17 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `13505` - // Minimum execution time: 17_812_000 picoseconds. - Weight::from_parts(20_036_000, 0) - .saturating_add(Weight::from_parts(0, 13505)) + // Measured: `173` + // Estimated: `13538` + // Minimum execution time: 18_142_000 picoseconds. + Weight::from_parts(18_470_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -232,39 +239,41 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `178` - // Estimated: `6118` - // Minimum execution time: 30_153_000 picoseconds. - Weight::from_parts(31_366_000, 0) - .saturating_add(Weight::from_parts(0, 6118)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 27_687_000 picoseconds. + Weight::from_parts(28_250_000, 0) + .saturating_add(Weight::from_parts(0, 6152)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `172` - // Estimated: `8587` - // Minimum execution time: 9_465_000 picoseconds. - Weight::from_parts(9_743_000, 0) - .saturating_add(Weight::from_parts(0, 8587)) + // Measured: `206` + // Estimated: `8621` + // Minimum execution time: 9_675_000 picoseconds. + Weight::from_parts(9_992_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: `140` - // Estimated: `11030` - // Minimum execution time: 16_954_000 picoseconds. - Weight::from_parts(19_772_000, 0) - .saturating_add(Weight::from_parts(0, 11030)) + // Measured: `173` + // Estimated: `11063` + // Minimum execution time: 16_597_000 picoseconds. + Weight::from_parts(17_248_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -277,12 +286,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `182` - // Estimated: `11072` - // Minimum execution time: 37_302_000 picoseconds. - Weight::from_parts(38_124_000, 0) - .saturating_add(Weight::from_parts(0, 11072)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `215` + // Estimated: `11105` + // Minimum execution time: 34_649_000 picoseconds. + Weight::from_parts(35_475_000, 0) + .saturating_add(Weight::from_parts(0, 11105)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 4_619_000 picoseconds. + Weight::from_parts(4_756_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7740` + // Estimated: `11205` + // Minimum execution time: 26_721_000 picoseconds. + Weight::from_parts(27_412_000, 0) + .saturating_add(Weight::from_parts(0, 11205)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 43b4358b890..aafded3f731 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_xcm` //! //! 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-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot @@ -29,14 +29,13 @@ // --steps=50 // --repeat=20 // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm // --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,58 +48,56 @@ 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) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 37_039_000 picoseconds. - Weight::from_parts(37_605_000, 0) - .saturating_add(Weight::from_parts(0, 4030)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `142` + // Estimated: `3607` + // Minimum execution time: 27_328_000 picoseconds. + Weight::from_parts(27_976_000, 0) + .saturating_add(Weight::from_parts(0, 3607)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) } fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_646_000 picoseconds. - Weight::from_parts(22_119_000, 0) + // Minimum execution time: 16_280_000 picoseconds. + Weight::from_parts(16_904_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_353_000 picoseconds. - Weight::from_parts(21_768_000, 0) + // Minimum execution time: 15_869_000 picoseconds. + Weight::from_parts(16_264_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_942_000 picoseconds. - Weight::from_parts(10_110_000, 0) + // Minimum execution time: 6_923_000 picoseconds. + Weight::from_parts(7_432_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) + /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_951_000 picoseconds. - Weight::from_parts(10_182_000, 0) + // Minimum execution time: 7_333_000 picoseconds. + Weight::from_parts(7_566_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -108,171 +105,189 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_163_000 picoseconds. - Weight::from_parts(3_298_000, 0) + // Minimum execution time: 2_219_000 picoseconds. + Weight::from_parts(2_375_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) + /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 41_207_000 picoseconds. - Weight::from_parts(41_879_000, 0) - .saturating_add(Weight::from_parts(0, 4030)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `142` + // Estimated: `3607` + // Minimum execution time: 30_650_000 picoseconds. + Weight::from_parts(31_683_000, 0) + .saturating_add(Weight::from_parts(0, 3607)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// 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) + /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `4302` - // Minimum execution time: 44_763_000 picoseconds. - Weight::from_parts(45_368_000, 0) - .saturating_add(Weight::from_parts(0, 4302)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `322` + // Estimated: `3787` + // Minimum execution time: 37_666_000 picoseconds. + Weight::from_parts(38_920_000, 0) + .saturating_add(Weight::from_parts(0, 3787)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `XcmPallet::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `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: 3_089_000 picoseconds. - Weight::from_parts(3_246_000, 0) + // Minimum execution time: 2_244_000 picoseconds. + Weight::from_parts(2_425_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) + /// Storage: `XcmPallet::SupportedVersion` (r:4 w:2) + /// Proof: `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: 16_733_000 picoseconds. - Weight::from_parts(17_354_000, 0) - .saturating_add(Weight::from_parts(0, 11119)) + // Measured: `26` + // Estimated: `10916` + // Minimum execution time: 14_710_000 picoseconds. + Weight::from_parts(15_156_000, 0) + .saturating_add(Weight::from_parts(0, 10916)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifiers` (r:4 w:2) + /// Proof: `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_959_000 picoseconds. - Weight::from_parts(17_306_000, 0) - .saturating_add(Weight::from_parts(0, 11123)) + // Measured: `30` + // Estimated: `10920` + // Minimum execution time: 14_630_000 picoseconds. + Weight::from_parts(15_290_000, 0) + .saturating_add(Weight::from_parts(0, 10920)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) + /// Proof: `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: 17_964_000 picoseconds. - Weight::from_parts(18_548_000, 0) - .saturating_add(Weight::from_parts(0, 13608)) + // Measured: `40` + // Estimated: `13405` + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_332_000, 0) + .saturating_add(Weight::from_parts(0, 13405)) .saturating_add(T::DbWeight::get().reads(5)) } - /// 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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `635` - // Estimated: `6575` - // Minimum execution time: 39_436_000 picoseconds. - Weight::from_parts(39_669_000, 0) - .saturating_add(Weight::from_parts(0, 6575)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `178` + // Estimated: `6118` + // Minimum execution time: 30_180_000 picoseconds. + Weight::from_parts(31_351_000, 0) + .saturating_add(Weight::from_parts(0, 6118)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:3 w:0) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `8687` - // Minimum execution time: 8_991_000 picoseconds. - Weight::from_parts(9_248_000, 0) - .saturating_add(Weight::from_parts(0, 8687)) + // Measured: `69` + // Estimated: `8484` + // Minimum execution time: 9_624_000 picoseconds. + Weight::from_parts(10_029_000, 0) + .saturating_add(Weight::from_parts(0, 8484)) .saturating_add(T::DbWeight::get().reads(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `240` - // Estimated: `11130` - // Minimum execution time: 17_614_000 picoseconds. - Weight::from_parts(17_948_000, 0) - .saturating_add(Weight::from_parts(0, 11130)) + // Measured: `37` + // Estimated: `10927` + // Minimum execution time: 15_139_000 picoseconds. + Weight::from_parts(15_575_000, 0) + .saturating_add(Weight::from_parts(0, 10927)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `639` - // Estimated: `11529` - // Minimum execution time: 45_531_000 picoseconds. - Weight::from_parts(46_533_000, 0) - .saturating_add(Weight::from_parts(0, 11529)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `182` + // Estimated: `11072` + // Minimum execution time: 37_871_000 picoseconds. + Weight::from_parts(38_940_000, 0) + .saturating_add(Weight::from_parts(0, 11072)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 2_732_000 picoseconds. + Weight::from_parts(2_892_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `XcmPallet::Queries` (r:1 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7576` + // Estimated: `11041` + // Minimum execution time: 23_813_000 picoseconds. + Weight::from_parts(24_201_000, 0) + .saturating_add(Weight::from_parts(0, 11041)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 7f2a1de44e9..cca4bdbd91e 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -17,15 +17,16 @@ //! Autogenerated weights for `pallet_xcm` //! //! 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-11-07, 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-yprdrvc7-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 @@ -35,12 +36,8 @@ // --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=westend-dev -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,44 +50,42 @@ 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) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 33_628_000 picoseconds. - Weight::from_parts(34_633_000, 0) - .saturating_add(Weight::from_parts(0, 3634)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 28_098_000 picoseconds. + Weight::from_parts(28_887_000, 0) + .saturating_add(Weight::from_parts(0, 3574)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) } fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_535_000 picoseconds. - Weight::from_parts(21_936_000, 0) + // Minimum execution time: 17_609_000 picoseconds. + Weight::from_parts(18_000_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_576_000 picoseconds. - Weight::from_parts(21_942_000, 0) + // Minimum execution time: 17_007_000 picoseconds. + Weight::from_parts(17_471_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -99,14 +94,14 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: XcmPallet SupportedVersion (r:0 w:1) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_764_000 picoseconds. - Weight::from_parts(9_927_000, 0) + // Minimum execution time: 7_444_000 picoseconds. + Weight::from_parts(7_671_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -114,171 +109,189 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_824_000 picoseconds. - Weight::from_parts(2_935_000, 0) + // Minimum execution time: 2_126_000 picoseconds. + Weight::from_parts(2_253_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) + /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 38_436_000 picoseconds. - Weight::from_parts(39_300_000, 0) - .saturating_add(Weight::from_parts(0, 3634)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 31_318_000 picoseconds. + Weight::from_parts(32_413_000, 0) + .saturating_add(Weight::from_parts(0, 3574)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// 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) + /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `361` - // Estimated: `3826` - // Minimum execution time: 41_600_000 picoseconds. - Weight::from_parts(42_703_000, 0) - .saturating_add(Weight::from_parts(0, 3826)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `289` + // Estimated: `3754` + // Minimum execution time: 35_282_000 picoseconds. + Weight::from_parts(35_969_000, 0) + .saturating_add(Weight::from_parts(0, 3754)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `XcmPallet::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `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_792_000 picoseconds. - Weight::from_parts(2_958_000, 0) + // Minimum execution time: 2_247_000 picoseconds. + Weight::from_parts(2_381_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) + /// Storage: `XcmPallet::SupportedVersion` (r:4 w:2) + /// Proof: `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_640_000 picoseconds. - Weight::from_parts(18_011_000, 0) - .saturating_add(Weight::from_parts(0, 11119)) + // Measured: `26` + // Estimated: `10916` + // Minimum execution time: 14_512_000 picoseconds. + Weight::from_parts(15_042_000, 0) + .saturating_add(Weight::from_parts(0, 10916)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifiers` (r:4 w:2) + /// Proof: `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_325_000 picoseconds. - Weight::from_parts(17_896_000, 0) - .saturating_add(Weight::from_parts(0, 11123)) + // Measured: `30` + // Estimated: `10920` + // Minimum execution time: 14_659_000 picoseconds. + Weight::from_parts(15_164_000, 0) + .saturating_add(Weight::from_parts(0, 10920)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) + /// Proof: `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_295_000 picoseconds. - Weight::from_parts(19_840_000, 0) - .saturating_add(Weight::from_parts(0, 13608)) + // Measured: `40` + // Estimated: `13405` + // Minimum execution time: 16_261_000 picoseconds. + Weight::from_parts(16_986_000, 0) + .saturating_add(Weight::from_parts(0, 13405)) .saturating_add(T::DbWeight::get().reads(5)) } - /// 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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `6179` - // Minimum execution time: 35_819_000 picoseconds. - Weight::from_parts(36_708_000, 0) - .saturating_add(Weight::from_parts(0, 6179)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `145` + // Estimated: `6085` + // Minimum execution time: 30_539_000 picoseconds. + Weight::from_parts(31_117_000, 0) + .saturating_add(Weight::from_parts(0, 6085)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:3 w:0) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `8687` - // Minimum execution time: 9_572_000 picoseconds. - Weight::from_parts(9_907_000, 0) - .saturating_add(Weight::from_parts(0, 8687)) + // Measured: `69` + // Estimated: `8484` + // Minimum execution time: 9_463_000 picoseconds. + Weight::from_parts(9_728_000, 0) + .saturating_add(Weight::from_parts(0, 8484)) .saturating_add(T::DbWeight::get().reads(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `240` - // Estimated: `11130` - // Minimum execution time: 17_376_000 picoseconds. - Weight::from_parts(17_870_000, 0) - .saturating_add(Weight::from_parts(0, 11130)) + // Measured: `37` + // Estimated: `10927` + // Minimum execution time: 15_169_000 picoseconds. + Weight::from_parts(15_694_000, 0) + .saturating_add(Weight::from_parts(0, 10927)) .saturating_add(T::DbWeight::get().reads(4)) .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) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `243` - // Estimated: `11133` - // Minimum execution time: 43_468_000 picoseconds. - Weight::from_parts(44_327_000, 0) - .saturating_add(Weight::from_parts(0, 11133)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `149` + // Estimated: `11039` + // Minimum execution time: 37_549_000 picoseconds. + Weight::from_parts(38_203_000, 0) + .saturating_add(Weight::from_parts(0, 11039)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 2_947_000 picoseconds. + Weight::from_parts(3_117_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `XcmPallet::Queries` (r:1 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7576` + // Estimated: `11041` + // Minimum execution time: 24_595_000 picoseconds. + Weight::from_parts(24_907_000, 0) + .saturating_add(Weight::from_parts(0, 11041)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index da472fbe6db..6b5d5e75de8 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -23,12 +23,12 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false} xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } [dev-dependencies] pallet-balances = { path = "../../../substrate/frame/balances" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } -xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } [features] default = [ "std" ] @@ -45,6 +45,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "xcm-builder/std", "xcm-executor/std", "xcm/std", ] diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index aca4bd1fb3f..3eecbfec518 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -190,6 +190,33 @@ benchmarks! { Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } + new_query { + let responder = MultiLocation::from(Parent); + let timeout = 1u32.into(); + let match_querier = MultiLocation::from(Here); + }: { + Pallet::::new_query(responder, timeout, match_querier); + } + + take_response { + let responder = MultiLocation::from(Parent); + let timeout = 1u32.into(); + let match_querier = MultiLocation::from(Here); + let query_id = Pallet::::new_query(responder, timeout, match_querier); + let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new( + u32::MAX, + (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), + (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), + u32::MAX, + u32::MAX, + u32::MAX, + ).unwrap()).collect::>(); + Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); + + }: { + as QueryHandler>::take_response(query_id); + } + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext_with_balances(Vec::new()), diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 321bb294b88..2d969fb870c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -28,9 +28,17 @@ mod tests; pub mod migration; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use frame_support::traits::{ - Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, OriginTrait, +use frame_support::{ + dispatch::GetDispatchInfo, + pallet_prelude::*, + traits::{ + Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, + OriginTrait, WithdrawReasons, + }, + PalletId, }; +use frame_system::pallet_prelude::{BlockNumberFor, *}; +pub use pallet::*; use scale_info::TypeInfo; use sp_runtime::{ traits::{ @@ -41,17 +49,15 @@ use sp_runtime::{ }; use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; -use xcm_executor::traits::{ConvertOrigin, Properties}; - -use frame_support::{ - dispatch::GetDispatchInfo, pallet_prelude::*, traits::WithdrawReasons, PalletId, +use xcm_builder::{ + ExecuteController, ExecuteControllerWeightInfo, QueryController, QueryControllerWeightInfo, + SendController, SendControllerWeightInfo, }; -use frame_system::pallet_prelude::*; -pub use pallet::*; use xcm_executor::{ traits::{ - CheckSuspension, ClaimAssets, ConvertLocation, DropAssets, MatchesFungible, OnResponse, - QueryHandler, QueryResponseStatus, VersionChangeNotifier, WeightBounds, + CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, DropAssets, MatchesFungible, + OnResponse, Properties, QueryHandler, QueryResponseStatus, VersionChangeNotifier, + WeightBounds, }, Assets, }; @@ -73,6 +79,8 @@ pub trait WeightInfo { fn notify_target_migration_fail() -> Weight; fn migrate_version_notify_targets() -> Weight; fn migrate_and_notify_old_targets() -> Weight; + fn new_query() -> Weight; + fn take_response() -> Weight; } /// fallback implementation @@ -141,6 +149,14 @@ impl WeightInfo for TestWeightInfo { fn migrate_and_notify_old_targets() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn new_query() -> Weight { + Weight::from_parts(100_000_000, 0) + } + + fn take_response() -> Weight { + Weight::from_parts(100_000_000, 0) + } } #[frame_support::pallet] @@ -267,6 +283,93 @@ pub mod pallet { type ReachableDest: Get>; } + impl ExecuteControllerWeightInfo for Pallet { + fn execute() -> Weight { + T::WeightInfo::execute() + } + } + + impl ExecuteController, ::RuntimeCall> for Pallet { + type WeightInfo = Self; + fn execute( + origin: OriginFor, + message: Box::RuntimeCall>>, + max_weight: Weight, + ) -> Result { + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let hash = message.using_encoded(sp_io::hashing::blake2_256); + let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; + let value = (origin_location, message); + ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); + let (origin_location, message) = value; + let outcome = T::XcmExecutor::execute_xcm_in_credit( + origin_location, + message, + hash, + max_weight, + max_weight, + ); + Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); + Ok(outcome) + } + } + + impl SendControllerWeightInfo for Pallet { + fn send() -> Weight { + T::WeightInfo::send() + } + } + + impl SendController> for Pallet { + type WeightInfo = Self; + fn send( + origin: OriginFor, + dest: Box, + message: Box>, + ) -> Result { + let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; + let interior: Junctions = + origin_location.try_into().map_err(|_| Error::::InvalidOrigin)?; + let dest = MultiLocation::try_from(*dest).map_err(|()| Error::::BadVersion)?; + let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; + + let message_id = + Self::send_xcm(interior, dest, message.clone()).map_err(Error::::from)?; + let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; + Self::deposit_event(e); + Ok(message_id) + } + } + + impl QueryControllerWeightInfo for Pallet { + fn query() -> Weight { + T::WeightInfo::new_query() + } + fn take_response() -> Weight { + T::WeightInfo::take_response() + } + } + + impl QueryController, BlockNumberFor> for Pallet { + type WeightInfo = Self; + + fn query( + origin: OriginFor, + timeout: BlockNumberFor, + match_querier: VersionedMultiLocation, + ) -> Result { + let responder = ::ExecuteXcmOrigin::ensure_origin(origin)?; + let query_id = ::new_query( + responder, + timeout, + MultiLocation::try_from(match_querier) + .map_err(|_| Into::::into(Error::::BadVersion))?, + ); + + Ok(query_id) + } + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -771,16 +874,7 @@ pub mod pallet { dest: Box, message: Box>, ) -> DispatchResult { - let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - let interior: Junctions = - origin_location.try_into().map_err(|_| Error::::InvalidOrigin)?; - let dest = MultiLocation::try_from(*dest).map_err(|()| Error::::BadVersion)?; - let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; - - let message_id = - Self::send_xcm(interior, dest, message.clone()).map_err(Error::::from)?; - let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; - Self::deposit_event(e); + >::send(origin, dest, message)?; Ok(()) } @@ -896,7 +990,7 @@ pub mod pallet { /// execution attempt will be made. /// /// NOTE: A successful return to this does *not* imply that the `msg` was executed - /// successfully to completion; only that *some* of it was executed. + /// successfully to completion; only that it was attempted. #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( @@ -904,23 +998,8 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; - let value = (origin_location, message); - ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); - let (origin_location, message) = value; - let outcome = T::XcmExecutor::execute_xcm_in_credit( - origin_location, - message, - hash, - max_weight, - max_weight, - ); - let result = - Ok(Some(outcome.weight_used().saturating_add(T::WeightInfo::execute())).into()); - Self::deposit_event(Event::Attempted { outcome }); - result + let outcome = >::execute(origin, message, max_weight)?; + Ok(Some(outcome.weight_used().saturating_add(T::WeightInfo::execute())).into()) } /// Extoll that a particular destination can be communicated with through a particular @@ -1145,7 +1224,7 @@ impl QueryHandler for Pallet { timeout: BlockNumberFor, match_querier: impl Into, ) -> Self::QueryId { - Self::do_new_query(responder, None, timeout, match_querier).into() + Self::do_new_query(responder, None, timeout, match_querier) } /// To check the status of the query, use `fn query()` passing the resultant `QueryId` diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs new file mode 100644 index 00000000000..0ee638b73e1 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -0,0 +1,187 @@ +// 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 set of traits that define how a pallet interface with XCM. +//! Controller traits defined in this module are high-level traits that will rely on other traits +//! from `xcm-executor` to perform their tasks. + +use frame_support::pallet_prelude::DispatchError; +use sp_std::boxed::Box; +use xcm::prelude::*; +use xcm_executor::traits::QueryHandler; + +/// Umbrella trait for all Controller traits. +pub trait Controller: + ExecuteController + SendController + QueryController +{ +} + +impl Controller for T where + T: ExecuteController + + SendController + + QueryController +{ +} + +/// Weight functions needed for [`ExecuteController`]. +pub trait ExecuteControllerWeightInfo { + /// Weight for [`ExecuteController::execute`] + fn execute() -> Weight; +} + +/// Execute an XCM locally, for a given origin. +/// +/// An implementation of that trait will handle the low-level details of the execution, such as: +/// - Validating and Converting the origin to a MultiLocation. +/// - Handling versioning. +/// - Calling the internal executor, which implements [`ExecuteXcm`]. +pub trait ExecuteController { + /// Weight information for ExecuteController functions. + type WeightInfo: ExecuteControllerWeightInfo; + + /// Attempt to execute an XCM locally, and return the outcome. + /// + /// # Parameters + /// + /// - `origin`: the origin of the call. + /// - `message`: the XCM program to be executed. + /// - `max_weight`: the maximum weight that can be consumed by the execution. + fn execute( + origin: Origin, + message: Box>, + max_weight: Weight, + ) -> Result; +} + +/// Weight functions needed for [`SendController`]. +pub trait SendControllerWeightInfo { + /// Weight for [`SendController::send`] + fn send() -> Weight; +} + +/// Send an XCM from a given origin. +/// +/// An implementation of that trait will handle the low-level details of dispatching an XCM, such +/// as: +/// - Validating and Converting the origin to an interior location. +/// - Handling versioning. +/// - Calling the internal router, which implements [`SendXcm`]. +pub trait SendController { + /// Weight information for SendController functions. + type WeightInfo: SendControllerWeightInfo; + + /// Send an XCM to be executed by a remote location. + /// + /// # Parameters + /// + /// - `origin`: the origin of the call. + /// - `dest`: the destination of the message. + /// - `msg`: the XCM to be sent. + fn send( + origin: Origin, + dest: Box, + message: Box>, + ) -> Result; +} + +/// Weight functions needed for [`QueryController`]. +pub trait QueryControllerWeightInfo { + /// Weight for [`QueryController::query`] + fn query() -> Weight; + + /// Weight for [`QueryHandler::take_response`] + fn take_response() -> Weight; +} + +/// Query a remote location, from a given origin. +/// +/// An implementation of that trait will handle the low-level details of querying a remote location, +/// such as: +/// - Validating and Converting the origin to an interior location. +/// - Handling versioning. +/// - Calling the [`QueryHandler`] to register the query. +pub trait QueryController: QueryHandler { + /// Weight information for QueryController functions. + type WeightInfo: QueryControllerWeightInfo; + + /// Query a remote location. + /// + /// # Parameters + /// + /// - `origin`: the origin of the call, used to determine the responder. + /// - `timeout`: the maximum block number that the query should be responded to. + /// - `match_querier`: the querier that the query should be responded to. + fn query( + origin: Origin, + timeout: Timeout, + match_querier: VersionedMultiLocation, + ) -> Result; +} + +impl ExecuteController for () { + type WeightInfo = (); + fn execute( + _origin: Origin, + _message: Box>, + _max_weight: Weight, + ) -> Result { + Ok(Outcome::Error(XcmError::Unimplemented)) + } +} + +impl ExecuteControllerWeightInfo for () { + fn execute() -> Weight { + Weight::zero() + } +} + +impl SendController for () { + type WeightInfo = (); + fn send( + _origin: Origin, + _dest: Box, + _message: Box>, + ) -> Result { + Ok(Default::default()) + } +} + +impl SendControllerWeightInfo for () { + fn send() -> Weight { + Weight::zero() + } +} + +impl QueryControllerWeightInfo for () { + fn query() -> Weight { + Weight::zero() + } + fn take_response() -> Weight { + Weight::zero() + } +} + +impl QueryController for () { + type WeightInfo = (); + + fn query( + _origin: Origin, + _timeout: Timeout, + _match_querier: VersionedMultiLocation, + ) -> Result { + Ok(Default::default()) + } +} diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 0a74b3f579a..35f95b85c89 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -115,3 +115,9 @@ pub use origin_aliases::AliasForeignAccountId32; mod pay; pub use pay::{FixedLocation, LocatableAssetId, PayAccountId32OnChainOverXcm, PayOverXcm}; + +mod controller; +pub use controller::{ + Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController, + QueryControllerWeightInfo, SendController, SendControllerWeightInfo, +}; diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 543b00e0118..189274eb5f5 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -414,7 +414,7 @@ pub fn response(query_id: u64) -> Option { /// Mock implementation of the [`QueryHandler`] trait for creating XCM success queries and expecting /// responses. pub struct TestQueryHandler(core::marker::PhantomData<(T, BlockNumber)>); -impl QueryHandler +impl QueryHandler for TestQueryHandler { type QueryId = u64; diff --git a/polkadot/xcm/xcm-executor/src/traits/on_response.rs b/polkadot/xcm/xcm-executor/src/traits/on_response.rs index 3558160dc87..ea41f242a97 100644 --- a/polkadot/xcm/xcm-executor/src/traits/on_response.rs +++ b/polkadot/xcm/xcm-executor/src/traits/on_response.rs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::Xcm; +use crate::{Junctions::Here, Xcm}; use core::result; -use frame_support::pallet_prelude::{Get, TypeInfo}; -use parity_scale_codec::{FullCodec, MaxEncodedLen}; +use frame_support::{ + pallet_prelude::{Get, TypeInfo}, + parameter_types, +}; +use parity_scale_codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::Zero; use sp_std::fmt::Debug; use xcm::latest::{ @@ -103,7 +106,7 @@ impl VersionChangeNotifier for () { } /// The possible state of an XCM query response. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Encode, Decode)] pub enum QueryResponseStatus { /// The response has arrived, and includes the inner Response and the block number it arrived /// at. @@ -129,7 +132,7 @@ pub trait QueryHandler { + PartialEq + Debug + Copy; - type BlockNumber: Zero; + type BlockNumber: Zero + Encode; type Error; type UniversalLocation: Get; @@ -165,3 +168,36 @@ pub trait QueryHandler { #[cfg(feature = "runtime-benchmarks")] fn expect_response(id: Self::QueryId, response: Response); } + +parameter_types! { + pub UniversalLocation: InteriorMultiLocation = Here; +} + +impl QueryHandler for () { + type BlockNumber = u64; + type Error = (); + type QueryId = u64; + type UniversalLocation = UniversalLocation; + + fn take_response(_query_id: Self::QueryId) -> QueryResponseStatus { + QueryResponseStatus::NotFound + } + fn new_query( + _responder: impl Into, + _timeout: Self::BlockNumber, + _match_querier: impl Into, + ) -> Self::QueryId { + 0u64 + } + + fn report_outcome( + _message: &mut Xcm<()>, + _responder: impl Into, + _timeout: Self::BlockNumber, + ) -> Result { + Err(()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn expect_response(_id: Self::QueryId, _response: crate::Response) {} +} diff --git a/prdoc/pr_2086.prdoc b/prdoc/pr_2086.prdoc new file mode 100644 index 00000000000..a9bbd0729d5 --- /dev/null +++ b/prdoc/pr_2086.prdoc @@ -0,0 +1,15 @@ +title: "Contracts: Add XCM traits to interface with contracts" + +doc: + - audience: Core Dev + description: | + We are introducing a new set of `XcmController` traits in `pallet-xcm`. + These traits extract functionality from `pallet-xcm` and provide high-level interaction with XCM. + They enable other pallets, like `pallet_contracts`, to rely on these traits instead of tight coupling to `pallet-xcm` itself. + +crates: + - name: "pallet-xcm" + semver: patch + - name: "xcm-executor" + semver: patch + -- GitLab From 0c5dcca9e3cef6b2f456fccefd9f6c5e43444053 Mon Sep 17 00:00:00 2001 From: Daniel Olano Date: Sat, 11 Nov 2023 20:34:08 +0100 Subject: [PATCH 485/633] Add `s` utility function to frame support (#2275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A utility function I consider quite useful to declare string literals that are backed by an array. --------- Co-authored-by: Bastian Köcher Co-authored-by: Davide Galassi --- substrate/primitives/runtime/src/lib.rs | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index 0e1d4c31fd7..ddf92554c83 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -954,6 +954,32 @@ pub fn print(print: impl traits::Printable) { print.print(); } +/// Utility function to declare string literals backed by an array of length N. +/// +/// The input can be shorter than N, in that case the end of the array is padded with zeros. +/// +/// [`str_array`] is useful when converting strings that end up in the storage as fixed size arrays +/// or in const contexts where static data types have strings that could also end up in the storage. +/// +/// # Example +/// +/// ```rust +/// # use sp_runtime::str_array; +/// const MY_STR: [u8; 6] = str_array("data"); +/// assert_eq!(MY_STR, *b"data\0\0"); +/// ``` +pub const fn str_array(s: &str) -> [u8; N] { + debug_assert!(s.len() <= N, "String literal doesn't fit in array"); + let mut i = 0; + let mut arr = [0; N]; + let s = s.as_bytes(); + while i < s.len() { + arr[i] = s[i]; + i += 1; + } + arr +} + /// Describes on what should happen with a storage transaction. pub enum TransactionOutcome { /// Commit the transaction. -- GitLab From 951bcceba085f1d3f5d022b1c211e5150fe8d2b2 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 13 Nov 2023 07:33:37 +0200 Subject: [PATCH 486/633] Unify `ChainSync` actions under one enum (#2180) All `ChainSync` actions that `SyncingEngine` should perform are unified under one `ChainSyncAction`. Processing of these actions put into a single place after `select!` in `SyncingEngine::run` instead of multiple places where calling `ChainSync` methods. --- .../client/network/sync/src/chain_sync.rs | 277 +++++++----------- .../network/sync/src/chain_sync/test.rs | 202 ++++++++----- substrate/client/network/sync/src/engine.rs | 163 +++++------ 3 files changed, 314 insertions(+), 328 deletions(-) diff --git a/substrate/client/network/sync/src/chain_sync.rs b/substrate/client/network/sync/src/chain_sync.rs index 858125f93f1..2adc6d42341 100644 --- a/substrate/client/network/sync/src/chain_sync.rs +++ b/substrate/client/network/sync/src/chain_sync.rs @@ -184,90 +184,26 @@ struct GapSync { target: NumberFor, } -/// Action that the parent of [`ChainSync`] should perform after reporting imported blocks with -/// [`ChainSync::on_blocks_processed`]. -pub enum BlockRequestAction { +/// Action that the parent of [`ChainSync`] should perform after reporting a network or block event. +#[derive(Debug)] +pub enum ChainSyncAction { /// Send block request to peer. Always implies dropping a stale block request to the same peer. - SendRequest { peer_id: PeerId, request: BlockRequest }, + SendBlockRequest { peer_id: PeerId, request: BlockRequest }, /// Drop stale block request. - RemoveStale { peer_id: PeerId }, -} - -/// 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>, -} - -/// Action that the parent of [`ChainSync`] should perform if we want to import justifications. -pub struct ImportJustificationsAction { - pub peer_id: PeerId, - pub hash: B::Hash, - pub number: NumberFor, - pub justifications: Justifications, -} - -/// Result of [`ChainSync::on_block_data`]. -#[derive(Debug, Clone, PartialEq, Eq)] -enum OnBlockData { - /// The block should be imported. - Import(ImportBlocksAction), - /// A new block request needs to be made to the given peer. - Request(PeerId, BlockRequest), - /// Continue processing events. - Continue, -} - -/// Result of [`ChainSync::on_block_justification`]. -#[derive(Debug, Clone, PartialEq, Eq)] -enum OnBlockJustification { - /// The justification needs no further handling. - Nothing, - /// The justification should be imported. - Import { + CancelBlockRequest { peer_id: PeerId }, + /// Peer misbehaved. Disconnect, report it and cancel the block request to it. + DropPeer(BadPeer), + /// Import blocks. + ImportBlocks { origin: BlockOrigin, blocks: Vec> }, + /// Import justifications. + ImportJustifications { peer_id: PeerId, - hash: Block::Hash, - number: NumberFor, + hash: B::Hash, + number: NumberFor, justifications: Justifications, }, } -// Result of [`ChainSync::on_state_data`]. -#[derive(Debug)] -enum OnStateData { - /// The block and state that should be imported. - Import(BlockOrigin, IncomingBlock), - /// A new state request needs to be made to the given peer. - Continue, -} - -/// Action that the parent of [`ChainSync`] should perform after reporting block response with -/// [`ChainSync::on_block_response`]. -pub enum OnBlockResponse { - /// Nothing to do. - Nothing, - /// Perform block request. - SendBlockRequest { peer_id: PeerId, request: BlockRequest }, - /// Import blocks. - ImportBlocks(ImportBlocksAction), - /// Import justifications. - ImportJustifications(ImportJustificationsAction), - /// Invalid block response, the peer should be disconnected and reported. - DisconnectPeer(BadPeer), -} - -/// Action that the parent of [`ChainSync`] should perform after reporting state response with -/// [`ChainSync::on_state_response`]. -pub enum OnStateResponse { - /// Nothing to do. - Nothing, - /// Import blocks. - ImportBlocks(ImportBlocksAction), - /// Invalid state response, the peer should be disconnected and reported. - DisconnectPeer(BadPeer), -} - /// The main data structure which contains all the state for a chains /// active syncing strategy. pub struct ChainSync { @@ -313,6 +249,8 @@ pub struct ChainSync { import_existing: bool, /// Gap download process. gap_sync: Option>, + /// Pending actions. + actions: Vec>, } /// All the data we have about a Peer that we are trying to sync with @@ -427,6 +365,7 @@ where gap_sync: None, warp_sync_config, warp_sync_target_block_header: None, + actions: Vec::new(), }; sync.reset_sync_start_point()?; @@ -509,8 +448,17 @@ where } /// Notify syncing state machine that a new sync peer has connected. + pub fn new_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { + match self.new_peer_inner(peer_id, best_hash, best_number) { + Ok(Some(request)) => + self.actions.push(ChainSyncAction::SendBlockRequest { peer_id, request }), + Ok(None) => {}, + Err(bad_peer) => self.actions.push(ChainSyncAction::DropPeer(bad_peer)), + } + } + #[must_use] - pub fn new_peer( + fn new_peer_inner( &mut self, peer_id: PeerId, best_hash: B::Hash, @@ -727,7 +675,7 @@ where peer_id: &PeerId, request: Option>, response: BlockResponse, - ) -> Result, BadPeer> { + ) -> Result<(), BadPeer> { self.downloaded_blocks += response.blocks.len(); let mut gap = false; let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(peer_id) { @@ -892,10 +840,12 @@ where start: *start, state: next_state, }; - return Ok(OnBlockData::Request( - *peer_id, - ancestry_request::(next_num), - )) + let request = ancestry_request::(next_num); + self.actions.push(ChainSyncAction::SendBlockRequest { + peer_id: *peer_id, + request, + }); + return Ok(()) } else { // Ancestry search is complete. Check if peer is on a stale fork unknown // to us and add it to sync targets if necessary. @@ -929,7 +879,7 @@ where .insert(*peer_id); } peer.state = PeerSyncState::Available; - Vec::new() + return Ok(()) } }, PeerSyncState::DownloadingWarpTargetBlock => { @@ -940,8 +890,7 @@ where match warp_sync.import_target_block( blocks.pop().expect("`blocks` len checked above."), ) { - warp::TargetBlockImportResult::Success => - return Ok(OnBlockData::Continue), + warp::TargetBlockImportResult::Success => return Ok(()), warp::TargetBlockImportResult::BadResponse => return Err(BadPeer(*peer_id, rep::VERIFICATION_FAIL)), } @@ -963,7 +912,7 @@ where "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", peer_id, ); - return Ok(OnBlockData::Continue) + return Ok(()) } }, PeerSyncState::Available | @@ -1000,7 +949,9 @@ where return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) }; - Ok(OnBlockData::Import(self.validate_and_queue_blocks(new_blocks, gap))) + self.validate_and_queue_blocks(new_blocks, gap); + + Ok(()) } /// Submit a justification response for processing. @@ -1009,7 +960,7 @@ where &mut self, peer_id: PeerId, response: BlockResponse, - ) -> Result, BadPeer> { + ) -> Result<(), BadPeer> { let peer = if let Some(peer) = self.peers.get_mut(&peer_id) { peer } else { @@ -1017,7 +968,7 @@ where target: LOG_TARGET, "💔 Called on_block_justification with a peer ID of an unknown peer", ); - return Ok(OnBlockJustification::Nothing) + return Ok(()) }; self.allowed_requests.add(&peer_id); @@ -1054,11 +1005,17 @@ where if let Some((peer_id, hash, number, justifications)) = self.extra_justifications.on_response(peer_id, justification) { - return Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) + self.actions.push(ChainSyncAction::ImportJustifications { + peer_id, + hash, + number, + justifications, + }); + return Ok(()) } } - Ok(OnBlockJustification::Nothing) + Ok(()) } /// Report a justification import (successful or not). @@ -1196,8 +1153,7 @@ where } /// Notify that a sync peer has disconnected. - #[must_use] - pub fn peer_disconnected(&mut self, peer_id: &PeerId) -> Option> { + pub fn peer_disconnected(&mut self, peer_id: &PeerId) { self.blocks.clear_peer_download(peer_id); if let Some(gap_sync) = &mut self.gap_sync { gap_sync.blocks.clear_peer_download(peer_id) @@ -1212,7 +1168,9 @@ where let blocks = self.ready_blocks(); - (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) + if !blocks.is_empty() { + self.validate_and_queue_blocks(blocks, false); + } } /// Get prometheus metrics. @@ -1259,11 +1217,7 @@ where } } - fn validate_and_queue_blocks( - &mut self, - mut new_blocks: Vec>, - gap: bool, - ) -> ImportBlocksAction { + fn validate_and_queue_blocks(&mut self, mut new_blocks: Vec>, gap: bool) { let orig_len = new_blocks.len(); new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); if new_blocks.len() != orig_len { @@ -1295,7 +1249,7 @@ where } self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); - ImportBlocksAction { origin, blocks: new_blocks } + self.actions.push(ChainSyncAction::ImportBlocks { origin, blocks: new_blocks }) } fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { @@ -1346,7 +1300,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) { self.blocks.clear(); if let Err(e) = self.reset_sync_start_point() { warn!(target: LOG_TARGET, "💔 Unable to restart sync: {e}"); @@ -1360,7 +1314,7 @@ where ); let old_peers = std::mem::take(&mut self.peers); - old_peers.into_iter().filter_map(move |(peer_id, mut p)| { + old_peers.into_iter().for_each(|(peer_id, mut p)| { // peers that were downloading justifications // should be kept in that state. if let PeerSyncState::DownloadingJustification(_) = p.state { @@ -1374,19 +1328,21 @@ where ); p.common_number = self.best_queued_number; self.peers.insert(peer_id, p); - return None + return } // handle peers that were in other states. - match self.new_peer(peer_id, p.best_hash, p.best_number) { + let action = match self.new_peer_inner(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 })), + Ok(None) => ChainSyncAction::CancelBlockRequest { peer_id }, // update the request if the new one is available - Ok(Some(request)) => Some(Ok(BlockRequestAction::SendRequest { peer_id, request })), + Ok(Some(request)) => ChainSyncAction::SendBlockRequest { peer_id, request }, // this implies that we need to drop pending response from the peer - Err(e) => Some(Err(e)), - } - }) + Err(bad_peer) => ChainSyncAction::DropPeer(bad_peer), + }; + + self.actions.push(action); + }); } /// Find a block to start sync from. If we sync with state, that's the latest block we have @@ -1534,13 +1490,12 @@ where } /// Submit blocks received in a response. - #[must_use] pub fn on_block_response( &mut self, peer_id: PeerId, request: BlockRequest, blocks: Vec>, - ) -> OnBlockResponse { + ) { let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( @@ -1563,41 +1518,21 @@ where blocks_range(), ); - if request.fields == BlockAttributes::JUSTIFICATION { - match self.on_block_justification(peer_id, block_response) { - Ok(OnBlockJustification::Nothing) => OnBlockResponse::Nothing, - Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) => - OnBlockResponse::ImportJustifications(ImportJustificationsAction { - peer_id, - hash, - number, - justifications, - }), - Err(bad_peer) => OnBlockResponse::DisconnectPeer(bad_peer), - } + let res = if request.fields == BlockAttributes::JUSTIFICATION { + self.on_block_justification(peer_id, block_response) } else { - match self.on_block_data(&peer_id, Some(request), block_response) { - Ok(OnBlockData::Import(action)) => OnBlockResponse::ImportBlocks(action), - Ok(OnBlockData::Request(peer_id, request)) => - OnBlockResponse::SendBlockRequest { peer_id, request }, - Ok(OnBlockData::Continue) => OnBlockResponse::Nothing, - Err(bad_peer) => OnBlockResponse::DisconnectPeer(bad_peer), - } + self.on_block_data(&peer_id, Some(request), block_response) + }; + + if let Err(bad_peer) = res { + self.actions.push(ChainSyncAction::DropPeer(bad_peer)); } } /// Submit a state received in a response. - #[must_use] - pub fn on_state_response( - &mut self, - peer_id: PeerId, - response: OpaqueStateResponse, - ) -> OnStateResponse { - match self.on_state_data(&peer_id, response) { - Ok(OnStateData::Import(origin, block)) => - OnStateResponse::ImportBlocks(ImportBlocksAction { origin, blocks: vec![block] }), - Ok(OnStateData::Continue) => OnStateResponse::Nothing, - Err(bad_peer) => OnStateResponse::DisconnectPeer(bad_peer), + pub fn on_state_response(&mut self, peer_id: PeerId, response: OpaqueStateResponse) { + if let Err(bad_peer) = self.on_state_data(&peer_id, response) { + self.actions.push(ChainSyncAction::DropPeer(bad_peer)); } } @@ -1833,11 +1768,12 @@ where None } + #[must_use] fn on_state_data( &mut self, peer_id: &PeerId, response: OpaqueStateResponse, - ) -> Result, BadPeer> { + ) -> Result<(), BadPeer> { let response: Box = response.0.downcast().map_err(|_error| { error!( target: LOG_TARGET, @@ -1892,9 +1828,10 @@ where state: Some(state), }; debug!(target: LOG_TARGET, "State download is complete. Import is queued"); - Ok(OnStateData::Import(origin, block)) + self.actions.push(ChainSyncAction::ImportBlocks { origin, blocks: vec![block] }); + Ok(()) }, - ImportResult::Continue => Ok(OnStateData::Continue), + ImportResult::Continue => Ok(()), ImportResult::BadResponse => { debug!(target: LOG_TARGET, "Bad state data received from {peer_id}"); Err(BadPeer(*peer_id, rep::BAD_BLOCK)) @@ -1903,12 +1840,7 @@ where } /// Submit a warp proof response received. - #[must_use] - pub fn on_warp_sync_response( - &mut self, - peer_id: &PeerId, - response: EncodedProof, - ) -> Result<(), BadPeer> { + pub fn on_warp_sync_response(&mut self, peer_id: &PeerId, response: EncodedProof) { if let Some(peer) = self.peers.get_mut(peer_id) { if let PeerSyncState::DownloadingWarpProof = peer.state { peer.state = PeerSyncState::Available; @@ -1925,14 +1857,16 @@ where sync.import_warp_proof(response) } else { debug!(target: LOG_TARGET, "Ignored obsolete warp sync response from {peer_id}"); - return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)) + self.actions + .push(ChainSyncAction::DropPeer(BadPeer(*peer_id, rep::NOT_REQUESTED))); + return }; match import_result { - WarpProofImportResult::Success => Ok(()), + WarpProofImportResult::Success => {}, WarpProofImportResult::BadResponse => { debug!(target: LOG_TARGET, "Bad proof data received from {peer_id}"); - Err(BadPeer(*peer_id, rep::BAD_BLOCK)) + self.actions.push(ChainSyncAction::DropPeer(BadPeer(*peer_id, rep::BAD_BLOCK))); }, } } @@ -1942,17 +1876,14 @@ where /// Call this when a batch of blocks have been processed by the import /// queue, with or without errors. If an error is returned, the pending response /// from the peer must be dropped. - #[must_use] pub fn on_blocks_processed( &mut self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) -> Box, BadPeer>>> { + ) { trace!(target: LOG_TARGET, "Imported {imported} of {count}"); - let mut output = Vec::new(); - let mut has_error = false; for (_, hash) in &results { self.queue_blocks.remove(hash); @@ -1993,7 +1924,10 @@ where if aux.bad_justification { if let Some(ref peer) = peer_id { warn!("💔 Sent block with bad justification to import"); - output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); + self.actions.push(ChainSyncAction::DropPeer(BadPeer( + *peer, + rep::BAD_JUSTIFICATION, + ))); } } @@ -2010,7 +1944,7 @@ where ); self.state_sync = None; self.mode = SyncMode::Full; - output.extend(self.restart()); + self.restart(); } let warp_sync_complete = self .warp_sync @@ -2024,7 +1958,7 @@ where ); self.warp_sync = None; self.mode = SyncMode::Full; - output.extend(self.restart()); + self.restart(); } let gap_sync_complete = self.gap_sync.as_ref().map_or(false, |s| s.target == number); @@ -2042,8 +1976,9 @@ where target: LOG_TARGET, "💔 Peer sent block with incomplete header to import", ); - output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); - output.extend(self.restart()); + self.actions + .push(ChainSyncAction::DropPeer(BadPeer(peer, rep::INCOMPLETE_HEADER))); + self.restart(); }, Err(BlockImportError::VerificationFailed(peer_id, e)) => { let extra_message = peer_id @@ -2055,10 +1990,11 @@ where ); if let Some(peer) = peer_id { - output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); + self.actions + .push(ChainSyncAction::DropPeer(BadPeer(peer, rep::VERIFICATION_FAIL))); } - output.extend(self.restart()); + self.restart(); }, Err(BlockImportError::BadBlock(peer_id)) => if let Some(peer) = peer_id { @@ -2066,7 +2002,7 @@ where target: LOG_TARGET, "💔 Block {hash:?} received from peer {peer} has been blacklisted", ); - output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); + self.actions.push(ChainSyncAction::DropPeer(BadPeer(peer, rep::BAD_BLOCK))); }, Err(BlockImportError::MissingState) => { // This may happen if the chain we were requesting upon has been discarded @@ -2078,14 +2014,19 @@ where warn!(target: LOG_TARGET, "💔 Error importing block {hash:?}: {}", e.unwrap_err()); self.state_sync = None; self.warp_sync = None; - output.extend(self.restart()); + self.restart(); }, Err(BlockImportError::Cancelled) => {}, }; } self.allowed_requests.set_all(); - Box::new(output.into_iter()) + } + + /// Get pending actions to perform. + #[must_use] + pub fn take_actions(&mut self) -> impl Iterator> { + std::mem::take(&mut self.actions).into_iter() } } diff --git a/substrate/client/network/sync/src/chain_sync/test.rs b/substrate/client/network/sync/src/chain_sync/test.rs index 2eefd2ad13e..15b2a95a07c 100644 --- a/substrate/client/network/sync/src/chain_sync/test.rs +++ b/substrate/client/network/sync/src/chain_sync/test.rs @@ -53,7 +53,7 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { }; // add a new peer with the same best block - sync.new_peer(peer_id, a1_hash, a1_number).unwrap(); + sync.new_peer(peer_id, a1_hash, a1_number); // and request a justification for the block sync.request_justification(&a1_hash, a1_number); @@ -74,10 +74,8 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { // if the peer replies with an empty response (i.e. it doesn't know the block), // the active request should be cleared. - assert_eq!( - sync.on_block_justification(peer_id, BlockResponse:: { id: 0, blocks: vec![] }), - Ok(OnBlockJustification::Nothing), - ); + sync.on_block_justification(peer_id, BlockResponse:: { id: 0, blocks: vec![] }) + .unwrap(); // there should be no in-flight requests assert_eq!(sync.extra_justifications.active_requests().count(), 0); @@ -119,8 +117,8 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { let (b1_hash, b1_number) = new_blocks(50); // add 2 peers at blocks that we don't have locally - sync.new_peer(peer_id1, Hash::random(), 42).unwrap(); - sync.new_peer(peer_id2, Hash::random(), 10).unwrap(); + sync.new_peer(peer_id1, Hash::random(), 42); + sync.new_peer(peer_id2, Hash::random(), 10); // we wil send block requests to these peers // for these blocks we don't know about @@ -130,7 +128,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); // add a new peer at a known block - sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); + sync.new_peer(peer_id3, b1_hash, b1_number); // we request a justification for a block we have locally sync.request_justification(&b1_hash, b1_number); @@ -148,14 +146,19 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { PeerSyncState::DownloadingJustification(b1_hash), ); + // clear old actions + let _ = sync.take_actions(); + // we restart the sync state - let block_requests = sync.restart(); + sync.restart(); + let actions = sync.take_actions().collect::>(); // which should make us send out block requests to the first two peers - 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, + assert_eq!(actions.len(), 2); + assert!(actions.iter().all(|action| match action { + ChainSyncAction::SendBlockRequest { peer_id, .. } => + peer_id == &peer_id1 || peer_id == &peer_id2, + _ => false, })); // peer 3 should be unaffected it was downloading finality data @@ -166,7 +169,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { // Set common block to something that we don't have (e.g. failed import) sync.peers.get_mut(&peer_id3).unwrap().common_number = 100; - let _ = sync.restart().count(); + sync.restart(); assert_eq!(sync.peers.get(&peer_id3).unwrap().common_number, 50); } @@ -280,9 +283,8 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { let best_block = blocks.last().unwrap().clone(); let max_blocks_to_request = sync.max_blocks_per_request; // Connect the node we will sync from - sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) - .unwrap(); - sync.new_peer(peer_id2, info.best_hash, 0).unwrap(); + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()); + sync.new_peer(peer_id2, info.best_hash, 0); let mut best_block_num = 0; while best_block_num < MAX_DOWNLOAD_AHEAD { @@ -300,11 +302,17 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { let response = create_block_response(resp_blocks.clone()); - let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + // Clear old actions to not deal with them + let _ = sync.take_actions(); + + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + assert_eq!(actions.len(), 1); assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize - ),); + &actions[0], + ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == max_blocks_to_request as usize, + )); best_block_num += max_blocks_to_request as u32; @@ -356,11 +364,14 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { assert_eq!(FromBlock::Number(best_block_num as u64), peer2_req.from); let response = create_block_response(vec![blocks[(best_block_num - 1) as usize].clone()]); - let res = sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap(); - assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() - ),); + + // Clear old actions to not deal with them + let _ = sync.take_actions(); + + sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + assert!(actions.is_empty()); let peer1_from = unwrap_from_block_number(peer1_req.unwrap().from); @@ -421,25 +432,34 @@ fn can_sync_huge_fork() { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()); send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); let mut request = get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); + // Discard old actions we are not interested in + let _ = sync.take_actions(); + // Do the ancestor search loop { let block = &fork_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_id1, Some(request), response).unwrap(); - request = if let OnBlockData::Request(_peer, request) = on_block_data { - request - } else { + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + + request = if actions.is_empty() { // We found the ancenstor break + } else { + assert_eq!(actions.len(), 1); + match &actions[0] { + ChainSyncAction::SendBlockRequest { peer_id: _, request } => request.clone(), + action @ _ => panic!("Unexpected action: {action:?}"), + } }; log::trace!(target: LOG_TARGET, "Request: {request:?}"); @@ -463,15 +483,18 @@ fn can_sync_huge_fork() { let response = create_block_response(resp_blocks.clone()); - let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + assert_eq!(actions.len(), 1); assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == sync.max_blocks_per_request as usize - ),); + &actions[0], + ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == sync.max_blocks_per_request as usize + )); best_block_num += sync.max_blocks_per_request as u32; - let _ = sync.on_blocks_processed( + sync.on_blocks_processed( max_blocks_to_request as usize, max_blocks_to_request as usize, resp_blocks @@ -490,6 +513,9 @@ fn can_sync_huge_fork() { .collect(), ); + // Discard pending actions + let _ = sync.take_actions(); + resp_blocks .into_iter() .rev() @@ -539,25 +565,34 @@ fn syncs_fork_without_duplicate_requests() { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()); send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); let mut request = get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); + // Discard pending actions + let _ = sync.take_actions(); + // Do the ancestor search loop { let block = &fork_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_id1, Some(request), response).unwrap(); - request = if let OnBlockData::Request(_peer, request) = on_block_data { - request - } else { + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + + request = if actions.is_empty() { // We found the ancenstor break + } else { + assert_eq!(actions.len(), 1); + match &actions[0] { + ChainSyncAction::SendBlockRequest { peer_id: _, request } => request.clone(), + action @ _ => panic!("Unexpected action: {action:?}"), + } }; log::trace!(target: LOG_TARGET, "Request: {request:?}"); @@ -582,11 +617,17 @@ fn syncs_fork_without_duplicate_requests() { let response = create_block_response(resp_blocks.clone()); - let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + // Discard old actions + let _ = sync.take_actions(); + + sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + + let actions = sync.take_actions().collect::>(); + assert_eq!(actions.len(), 1); assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize - ),); + &actions[0], + ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == max_blocks_to_request as usize + )); best_block_num += max_blocks_to_request as u32; @@ -653,8 +694,7 @@ fn removes_target_fork_on_disconnect() { let peer_id1 = PeerId::random(); let common_block = blocks[1].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()); // Create a "new" header and announce it let mut header = blocks[0].header().clone(); @@ -678,8 +718,7 @@ fn can_import_response_with_missing_blocks() { let peer_id1 = PeerId::random(); let best_block = blocks[3].clone(); - sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) - .unwrap(); + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()); sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; sync.peers.get_mut(&peer_id1).unwrap().common_number = 0; @@ -730,7 +769,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { let (b1_hash, b1_number) = new_blocks(50); // add new peer and request blocks from them - sync.new_peer(peers[0], Hash::random(), 42).unwrap(); + sync.new_peer(peers[0], Hash::random(), 42); // we don't actually perform any requests, just keep track of peers waiting for a response let mut pending_responses = HashSet::new(); @@ -743,7 +782,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { } // add a new peer at a known block - sync.new_peer(peers[1], b1_hash, b1_number).unwrap(); + sync.new_peer(peers[1], b1_hash, b1_number); // we request a justification for a block we have locally sync.request_justification(&b1_hash, b1_number); @@ -766,24 +805,29 @@ fn sync_restart_removes_block_but_not_justification_requests() { ); assert_eq!(pending_responses.len(), 2); + // discard old actions + let _ = sync.take_actions(); + // restart sync - let request_events = sync.restart().collect::>(); - for event in request_events.iter() { - match event.as_ref().unwrap() { - BlockRequestAction::RemoveStale { peer_id } => { + sync.restart(); + let actions = sync.take_actions().collect::>(); + for action in actions.iter() { + match action { + ChainSyncAction::CancelBlockRequest { peer_id } => { pending_responses.remove(&peer_id); }, - BlockRequestAction::SendRequest { peer_id, .. } => { + ChainSyncAction::SendBlockRequest { peer_id, .. } => { // we drop obsolete response, but don't register a new request, it's checked in // the `assert!` below pending_responses.remove(&peer_id); }, + action @ _ => panic!("Unexpected action: {action:?}"), } } - assert!(request_events.iter().any(|event| { - match event.as_ref().unwrap() { - BlockRequestAction::RemoveStale { .. } => false, - BlockRequestAction::SendRequest { peer_id, .. } => peer_id == &peers[0], + assert!(actions.iter().any(|action| { + match action { + ChainSyncAction::SendBlockRequest { peer_id, .. } => peer_id == &peers[0], + _ => false, } })); @@ -848,11 +892,9 @@ fn request_across_forks() { // Add the peers, all at the common ancestor 100. let common_block = blocks.last().unwrap(); let peer_id1 = PeerId::random(); - sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) - .unwrap(); + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()); let peer_id2 = PeerId::random(); - sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number()) - .unwrap(); + sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number()); // Peer 1 announces 107 from fork 1, 100-107 get downloaded. { @@ -864,11 +906,17 @@ fn request_across_forks() { let mut resp_blocks = fork_a_blocks[100_usize..107_usize].to_vec(); resp_blocks.reverse(); let response = create_block_response(resp_blocks.clone()); - let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + + // Drop old actions + let _ = sync.take_actions(); + + sync.on_block_data(&peer, Some(request), response).unwrap(); + let actions = sync.take_actions().collect::>(); + assert_eq!(actions.len(), 1); assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 7_usize - ),); + &actions[0], + ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == 7_usize + )); assert_eq!(sync.best_queued_number, 107); assert_eq!(sync.best_queued_hash, block.hash()); assert!(sync.is_known(&block.header.parent_hash())); @@ -903,11 +951,17 @@ fn request_across_forks() { // block is announced. let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 1, &peer); let response = create_block_response(vec![block.clone()]); - let res = sync.on_block_data(&peer, Some(request), response).unwrap(); + + // Drop old actions we are not going to check + let _ = sync.take_actions(); + + sync.on_block_data(&peer, Some(request), response).unwrap(); + let actions = sync.take_actions().collect::>(); + assert_eq!(actions.len(), 1); assert!(matches!( - res, - OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 1_usize - ),); + &actions[0], + ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == 1_usize + )); assert!(sync.is_known(&block.header.parent_hash())); } } diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 560887132e3..58a9fdc49f2 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -25,10 +25,7 @@ use crate::{ }, block_relay_protocol::{BlockDownloader, BlockResponseError}, block_request_handler::MAX_BLOCKS_IN_RESPONSE, - chain_sync::{ - BlockRequestAction, ChainSync, ImportBlocksAction, ImportJustificationsAction, - OnBlockResponse, OnStateResponse, - }, + chain_sync::{ChainSync, ChainSyncAction}, pending_responses::{PendingResponses, ResponseEvent}, schema::v1::{StateRequest, StateResponse}, service::{ @@ -58,7 +55,7 @@ use schnellru::{ByLength, LruMap}; use tokio::time::{Interval, MissedTickBehavior}; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; -use sc_consensus::import_queue::ImportQueueService; +use sc_consensus::{import_queue::ImportQueueService, IncomingBlock}; use sc_network::{ config::{ FullNetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, @@ -74,8 +71,11 @@ use sc_network_common::{ }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::{Error as ClientError, HeaderMetadata}; -use sp_consensus::block_validation::BlockAnnounceValidator; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; +use sp_consensus::{block_validation::BlockAnnounceValidator, BlockOrigin}; +use sp_runtime::{ + traits::{Block as BlockT, Header, NumberFor, Zero}, + Justifications, +}; use std::{ collections::{HashMap, HashSet}, @@ -713,11 +713,67 @@ where self.is_major_syncing .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); + // Process actions requested by `ChainSync` during `select!`. + self.process_chain_sync_actions(); + // Send outbound requests on `ChanSync`'s behalf. self.send_chain_sync_requests(); } } + fn process_chain_sync_actions(&mut self) { + self.chain_sync.take_actions().for_each(|action| match action { + ChainSyncAction::SendBlockRequest { peer_id, request } => { + // Sending block request implies dropping obsolete pending response as we are not + // interested in it anymore (see [`ChainSyncAction::SendBlockRequest`]). + // Furthermore, only one request at a time is allowed to any peer. + let removed = self.pending_responses.remove(&peer_id); + self.send_block_request(peer_id, request.clone()); + + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::SendBlockRequest` to {} with {:?}, stale response removed: {}.", + peer_id, + request, + removed, + ) + }, + ChainSyncAction::CancelBlockRequest { peer_id } => { + let removed = self.pending_responses.remove(&peer_id); + + trace!(target: LOG_TARGET, "Processed {action:?}., response removed: {removed}."); + }, + ChainSyncAction::DropPeer(BadPeer(peer_id, rep)) => { + 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, rep); + + trace!(target: LOG_TARGET, "Processed {action:?}."); + }, + ChainSyncAction::ImportBlocks { origin, blocks } => { + let count = blocks.len(); + self.import_blocks(origin, blocks); + + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::ImportBlocks` with {count} blocks.", + ); + }, + ChainSyncAction::ImportJustifications { peer_id, hash, number, justifications } => { + self.import_justifications(peer_id, hash, number, justifications); + + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::ImportJustifications` from peer {} for block {} ({}).", + peer_id, + hash, + number, + ) + }, + }); + } + fn perform_periodic_actions(&mut self) { self.report_metrics(); @@ -766,28 +822,7 @@ where ToServiceCommand::ClearJustificationRequests => self.chain_sync.clear_justification_requests(), ToServiceCommand::BlocksProcessed(imported, count, results) => { - for result in self.chain_sync.on_blocks_processed(imported, count, results) { - match result { - 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) - }, - } - } + self.chain_sync.on_blocks_processed(imported, count, results); }, ToServiceCommand::JustificationImported(peer_id, hash, number, success) => { self.chain_sync.on_justification_import(hash, number, success); @@ -940,9 +975,7 @@ where } } - if let Some(import_blocks_action) = self.chain_sync.peer_disconnected(&peer_id) { - self.import_blocks(import_blocks_action) - } + self.chain_sync.peer_disconnected(&peer_id); self.pending_responses.remove(&peer_id); self.event_streams.retain(|stream| { @@ -1053,17 +1086,7 @@ where inbound, }; - let req = if peer.info.roles.is_full() { - match self.chain_sync.new_peer(peer_id, peer.info.best_hash, peer.info.best_number) { - Ok(req) => req, - Err(BadPeer(id, repu)) => { - self.network_service.report_peer(id, repu); - return Err(()) - }, - } - } else { - None - }; + self.chain_sync.new_peer(peer_id, peer.info.best_hash, peer.info.best_number); log::debug!(target: LOG_TARGET, "Connected {peer_id}"); @@ -1075,10 +1098,6 @@ where self.num_in_peers += 1; } - if let Some(req) = req { - self.send_block_request(peer_id, req); - } - self.event_streams .retain(|stream| stream.unbounded_send(SyncEvent::PeerConnected(peer_id)).is_ok()); @@ -1202,22 +1221,7 @@ where 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 => {}, - OnBlockResponse::DisconnectPeer(BadPeer(peer_id, rep)) => { - self.network_service.disconnect_peer( - peer_id, - self.block_announce_protocol_name.clone(), - ); - self.network_service.report_peer(peer_id, rep); - }, - } + self.chain_sync.on_block_response(peer_id, req, blocks); }, Err(BlockResponseError::DecodeFailed(e)) => { debug!( @@ -1262,27 +1266,10 @@ where }, }; - match self.chain_sync.on_state_response(peer_id, response) { - OnStateResponse::ImportBlocks(import_blocks_action) => - self.import_blocks(import_blocks_action), - OnStateResponse::DisconnectPeer(BadPeer(peer_id, rep)) => { - self.network_service.disconnect_peer( - peer_id, - self.block_announce_protocol_name.clone(), - ); - self.network_service.report_peer(peer_id, rep); - }, - OnStateResponse::Nothing => {}, - } + self.chain_sync.on_state_response(peer_id, response); }, PeerRequest::WarpProof => { - if let Err(BadPeer(peer_id, rep)) = - self.chain_sync.on_warp_sync_response(&peer_id, EncodedProof(resp)) - { - self.network_service - .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(peer_id, rep); - } + self.chain_sync.on_warp_sync_response(&peer_id, EncodedProof(resp)); }, }, Ok(Err(e)) => { @@ -1388,7 +1375,7 @@ where } /// Import blocks. - fn import_blocks(&mut self, ImportBlocksAction { origin, blocks }: ImportBlocksAction) { + fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { if let Some(metrics) = &self.metrics { metrics.import_queue_blocks_submitted.inc(); } @@ -1397,13 +1384,17 @@ where } /// Import justifications. - fn import_justifications(&mut self, action: ImportJustificationsAction) { + fn import_justifications( + &mut self, + peer_id: PeerId, + hash: B::Hash, + number: NumberFor, + justifications: Justifications, + ) { 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); } } -- GitLab From 5f4ce8026693b537beaee3aea5161ee34bac7ace Mon Sep 17 00:00:00 2001 From: Marcin S Date: Mon, 13 Nov 2023 11:21:16 +0100 Subject: [PATCH 487/633] PVF host: Make unavailable security features print a warning (#2244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- polkadot/node/core/pvf/src/host.rs | 19 +- polkadot/node/core/pvf/src/security.rs | 275 +++++++++++++++++-------- 2 files changed, 189 insertions(+), 105 deletions(-) diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index dd0bd858198..7b383e8034a 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -29,12 +29,11 @@ use crate::{ use always_assert::never; use futures::{ channel::{mpsc, oneshot}, - join, Future, FutureExt, SinkExt, StreamExt, + Future, FutureExt, SinkExt, StreamExt, }; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, pvf::PvfPrepData, - SecurityStatus, }; use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ @@ -208,21 +207,7 @@ pub async fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Fu gum::debug!(target: LOG_TARGET, ?config, "starting PVF validation host"); // Run checks for supported security features once per host startup. Warn here if not enabled. - let security_status = { - // TODO: add check that syslog is available and that seccomp violations are logged? - let (can_enable_landlock, can_enable_seccomp, can_unshare_user_namespace_and_change_root) = join!( - security::check_landlock(&config.prepare_worker_program_path), - security::check_seccomp(&config.prepare_worker_program_path), - security::check_can_unshare_user_namespace_and_change_root( - &config.prepare_worker_program_path - ) - ); - SecurityStatus { - can_enable_landlock, - can_enable_seccomp, - can_unshare_user_namespace_and_change_root, - } - }; + let security_status = security::check_security_status(&config).await; let (to_host_tx, to_host_rx) = mpsc::channel(10); diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index decd321e415..295dd7df94d 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -14,22 +14,142 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::LOG_TARGET; -use std::path::Path; +use crate::{Config, SecurityStatus, LOG_TARGET}; +use futures::join; +use std::{fmt, path::Path}; use tokio::{ fs::{File, OpenOptions}, io::{AsyncReadExt, AsyncSeekExt, SeekFrom}, }; -/// Check if we can sandbox the root and emit a warning if not. +const SECURE_MODE_ANNOUNCEMENT: &'static str = + "In the next release this will be a hard error by default. + \nMore information: https://wiki.polkadot.network/docs/maintain-guides-secure-validator#secure-validator-mode"; + +/// Run checks for supported security features. +pub async fn check_security_status(config: &Config) -> SecurityStatus { + let Config { prepare_worker_program_path, .. } = config; + + // TODO: add check that syslog is available and that seccomp violations are logged? + let (landlock, seccomp, change_root) = join!( + check_landlock(prepare_worker_program_path), + check_seccomp(prepare_worker_program_path), + check_can_unshare_user_namespace_and_change_root(prepare_worker_program_path) + ); + + let security_status = SecurityStatus { + can_enable_landlock: landlock.is_ok(), + can_enable_seccomp: seccomp.is_ok(), + can_unshare_user_namespace_and_change_root: change_root.is_ok(), + }; + + let errs: Vec = [landlock, seccomp, change_root] + .into_iter() + .filter_map(|result| result.err()) + .collect(); + let err_occurred = print_secure_mode_message(errs); + if err_occurred { + gum::error!( + target: LOG_TARGET, + "{}", + SECURE_MODE_ANNOUNCEMENT, + ); + } + + security_status +} + +type SecureModeResult = std::result::Result<(), SecureModeError>; + +/// Errors related to enabling Secure Validator Mode. +#[derive(Debug)] +enum SecureModeError { + CannotEnableLandlock(String), + CannotEnableSeccomp(String), + CannotUnshareUserNamespaceAndChangeRoot(String), +} + +impl SecureModeError { + /// Whether this error is allowed with Secure Validator Mode enabled. + fn is_allowed_in_secure_mode(&self) -> bool { + use SecureModeError::*; + match self { + CannotEnableLandlock(_) => true, + CannotEnableSeccomp(_) => false, + CannotUnshareUserNamespaceAndChangeRoot(_) => false, + } + } +} + +impl fmt::Display for SecureModeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use SecureModeError::*; + match self { + CannotEnableLandlock(err) => write!(f, "Cannot enable landlock, a Linux 5.13+ kernel security feature: {err}"), + CannotEnableSeccomp(err) => write!(f, "Cannot enable seccomp, a Linux-specific kernel security feature: {err}"), + CannotUnshareUserNamespaceAndChangeRoot(err) => write!(f, "Cannot unshare user namespace and change root, which are Linux-specific kernel security features: {err}"), + } + } +} + +/// Errors if Secure Validator Mode and some mandatory errors occurred, warn otherwise. +/// +/// # Returns +/// +/// `true` if an error was printed, `false` otherwise. +fn print_secure_mode_message(errs: Vec) -> bool { + // Trying to run securely and some mandatory errors occurred. + const SECURE_MODE_ERROR: &'static str = "🚨 Your system cannot securely run a validator. \ + \nRunning validation of malicious PVF code has a higher risk of compromising this machine."; + // Some errors occurred when running insecurely, or some optional errors occurred when running + // securely. + const SECURE_MODE_WARNING: &'static str = "🚨 Some security issues have been detected. \ + \nRunning validation of malicious PVF code has a higher risk of compromising this machine."; + + if errs.is_empty() { + return false + } + + let errs_allowed = errs.iter().all(|err| err.is_allowed_in_secure_mode()); + let errs_string: String = errs + .iter() + .map(|err| { + format!( + "\n - {}{}", + if err.is_allowed_in_secure_mode() { "Optional: " } else { "" }, + err + ) + }) + .collect(); + + if errs_allowed { + gum::warn!( + target: LOG_TARGET, + "{}{}", + SECURE_MODE_WARNING, + errs_string, + ); + false + } else { + gum::error!( + target: LOG_TARGET, + "{}{}", + SECURE_MODE_ERROR, + errs_string, + ); + true + } +} + +/// Check if we can change root to a new, sandboxed root and return an error 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. -pub async fn check_can_unshare_user_namespace_and_change_root( +async fn check_can_unshare_user_namespace_and_change_root( #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] prepare_worker_program_path: &Path, -) -> bool { +) -> SecureModeResult { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { match tokio::process::Command::new(prepare_worker_program_path) @@ -37,50 +157,37 @@ pub async fn check_can_unshare_user_namespace_and_change_root( .output() .await { - Ok(output) if output.status.success() => true, + Ok(output) if output.status.success() => Ok(()), 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 + Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + format!("not available: {}", stderr) + )) }, + Err(err) => + Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + format!("could not start child process: {}", err) + )), } } else { - gum::warn!( - target: LOG_TARGET, - "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 + Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + "only available on Linux".into() + )) } } } -/// Check if landlock is supported and emit a warning if not. +/// Check if landlock is supported and return an error 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. -pub async fn check_landlock( +async fn check_landlock( #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] prepare_worker_program_path: &Path, -) -> bool { +) -> SecureModeResult { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { match tokio::process::Command::new(prepare_worker_program_path) @@ -88,81 +195,73 @@ pub async fn check_landlock( .status() .await { - Ok(status) if status.success() => true, - Ok(status) => { + Ok(status) if status.success() => Ok(()), + 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 + Err(SecureModeError::CannotEnableLandlock( + format!("landlock ABI {} not available", abi) + )) }, + Err(err) => + Err(SecureModeError::CannotEnableLandlock( + format!("could not start child process: {}", err) + )), } } 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 + Err(SecureModeError::CannotEnableLandlock( + "only available on Linux".into() + )) } } } -/// Check if seccomp is supported and emit a warning if not. +/// Check if seccomp is supported and return an error 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. -pub async fn check_seccomp( +async fn check_seccomp( #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] prepare_worker_program_path: &Path, -) -> bool { +) -> SecureModeResult { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - match tokio::process::Command::new(prepare_worker_program_path) - .arg("--check-can-enable-seccomp") - .status() - .await - { - Ok(status) if status.success() => true, - Ok(status) => { - gum::warn!( - target: LOG_TARGET, - ?prepare_worker_program_path, - ?status, - "Cannot fully enable seccomp, 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 - }, + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + match tokio::process::Command::new(prepare_worker_program_path) + .arg("--check-can-enable-seccomp") + .status() + .await + { + Ok(status) if status.success() => Ok(()), + Ok(_status) => + Err(SecureModeError::CannotEnableSeccomp( + "not available".into() + )), + Err(err) => + Err(SecureModeError::CannotEnableSeccomp( + format!("could not start child process: {}", err) + )), + } + } else { + Err(SecureModeError::CannotEnableSeccomp( + "only supported on CPUs from the x86_64 family (usually Intel or AMD)".into() + )) + } } } else { - gum::warn!( - target: LOG_TARGET, - "Cannot enable seccomp, 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 seccomp support for maximum security." - ); - false + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + Err(SecureModeError::CannotEnableSeccomp( + "only supported on Linux".into() + )) + } else { + Err(SecureModeError::CannotEnableSeccomp( + "only supported on Linux and on CPUs from the x86_64 family (usually Intel or AMD).".into() + )) + } + } } } } -- GitLab From 604704a84ce690eca93fd053abec1bb0a2b0ee32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Nov 2023 13:57:52 +0100 Subject: [PATCH 488/633] wasm-builder: Optimize `rerun-if-changed` logic (#2282) Optimizes the `rerun-if-changed` logic by ignoring `dev-dependencies` and also not outputting paths. Because outputting paths could lead to include unwanted crates in the rerun checks. --- substrate/utils/wasm-builder/src/wasm_project.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index c41e0935d75..2e6f671c45e 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -18,7 +18,7 @@ use crate::{write_file_if_changed, CargoCommandVersioned, OFFLINE}; use build_helper::rerun_if_changed; -use cargo_metadata::{CargoOpt, Metadata, MetadataCommand}; +use cargo_metadata::{DependencyKind, Metadata, MetadataCommand}; use parity_wasm::elements::{deserialize_buffer, Module}; use std::{ borrow::ToOwned, @@ -89,8 +89,7 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { cargo_manifest.to_path_buf() }; - let mut crate_metadata_command = create_metadata_command(cargo_manifest); - crate_metadata_command.features(CargoOpt::AllFeatures); + let crate_metadata_command = create_metadata_command(cargo_manifest); let crate_metadata = crate_metadata_command .exec() @@ -915,6 +914,11 @@ fn generate_rerun_if_changed_instructions( packages.insert(DeduplicatePackage::from(package)); while let Some(dependency) = dependencies.pop() { + // Ignore all dev dependencies + if dependency.kind == DependencyKind::Development { + continue; + } + let path_or_git_dep = dependency.source.as_ref().map(|s| s.starts_with("git+")).unwrap_or(true); @@ -967,9 +971,7 @@ fn package_rerun_if_changed(package: &DeduplicatePackage) { p.path() == manifest_path || !p.path().is_dir() || !p.path().join("Cargo.toml").exists() }) .filter_map(|p| p.ok().map(|p| p.into_path())) - .filter(|p| { - p.is_dir() || p.extension().map(|e| e == "rs" || e == "toml").unwrap_or_default() - }) + .filter(|p| p.extension().map(|e| e == "rs" || e == "toml").unwrap_or_default()) .for_each(rerun_if_changed); } -- GitLab From ebcf0a0f1cab2d43718ba96d26e5687f4d14580a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Nov 2023 14:32:02 +0100 Subject: [PATCH 489/633] pallet-grandpa: Remove `GRANDPA_AUTHORITIES_KEY` (#2181) Remove the `GRANDPA_AUTHORITIES_KEY` key and its usage. Apparently this was used in the early days to communicate the grandpa authorities to the node. However, we have now a runtime api that does this for us. So, this pull request is moving from the custom managed storage item to a FRAME managed storage item. This pr also includes a migration for doing the switch on a running chain. --------- Co-authored-by: Davide Galassi --- polkadot/runtime/rococo/src/lib.rs | 2 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/client/consensus/grandpa/src/lib.rs | 3 - substrate/frame/grandpa/src/lib.rs | 37 +++---- substrate/frame/grandpa/src/migrations.rs | 3 + substrate/frame/grandpa/src/migrations/v5.rs | 96 +++++++++++++++++++ .../primitives/consensus/grandpa/src/lib.rs | 65 +------------ 7 files changed, 124 insertions(+), 83 deletions(-) create mode 100644 substrate/frame/grandpa/src/migrations/v5.rs diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 697d22c311a..57767b70d23 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1497,6 +1497,8 @@ pub mod migrations { frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, + + pallet_grandpa::migrations::MigrateV4ToV5, ); } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index fe9ed22f437..1c97e54da48 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1558,6 +1558,7 @@ pub mod migrations { pallet_nomination_pools::migration::versioned_migrations::V5toV6, pallet_referenda::migration::v1::MigrateV0ToV1, pallet_nomination_pools::migration::versioned_migrations::V6ToV7, + pallet_grandpa::migrations::MigrateV4ToV5, ); } diff --git a/substrate/client/consensus/grandpa/src/lib.rs b/substrate/client/consensus/grandpa/src/lib.rs index da621abd254..a4584e6fc80 100644 --- a/substrate/client/consensus/grandpa/src/lib.rs +++ b/substrate/client/consensus/grandpa/src/lib.rs @@ -471,9 +471,6 @@ where Client: ExecutorProvider + HeaderBackend, { fn get(&self) -> Result { - // This implementation uses the Grandpa runtime API instead of reading directly from the - // `GRANDPA_AUTHORITIES_KEY` as the data may have been migrated since the genesis block of - // the chain, whereas the runtime API is backwards compatible. self.executor() .call( self.expect_block_hash_from_id(&BlockId::Number(Zero::zero()))?, diff --git a/substrate/frame/grandpa/src/lib.rs b/substrate/frame/grandpa/src/lib.rs index 95d1c8aa609..0b9f2b35827 100644 --- a/substrate/frame/grandpa/src/lib.rs +++ b/substrate/frame/grandpa/src/lib.rs @@ -30,14 +30,13 @@ // Re-export since this is necessary for `impl_apis` in runtime. pub use sp_consensus_grandpa::{ - self as fg_primitives, AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList, + self as fg_primitives, AuthorityId, AuthorityList, AuthorityWeight, }; -use codec::{self as codec, Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays}, pallet_prelude::Get, - storage, traits::OneSessionHandler, weights::Weight, WeakBoundedVec, @@ -45,8 +44,8 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; use sp_consensus_grandpa::{ - ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_AUTHORITIES_KEY, - GRANDPA_ENGINE_ID, RUNTIME_LOG_TARGET as LOG_TARGET, + ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_ENGINE_ID, + RUNTIME_LOG_TARGET as LOG_TARGET, }; use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult}; use sp_session::{GetSessionNumber, GetValidatorCount}; @@ -75,7 +74,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -145,7 +144,7 @@ pub mod pallet { // enact the change if we've reached the enacting block if block_number == pending_change.scheduled_at + pending_change.delay { - Self::set_grandpa_authorities(&pending_change.next_authorities); + Authorities::::put(&pending_change.next_authorities); Self::deposit_event(Event::NewAuthorities { authority_set: pending_change.next_authorities.into_inner(), }); @@ -342,6 +341,11 @@ pub mod pallet { #[pallet::getter(fn session_for_set)] pub(super) type SetIdSession = StorageMap<_, Twox64Concat, SetId, SessionIndex>; + /// The current list of authorities. + #[pallet::storage] + pub(crate) type Authorities = + StorageValue<_, BoundedAuthorityList, ValueQuery>; + #[derive(frame_support::DefaultNoBound)] #[pallet::genesis_config] pub struct GenesisConfig { @@ -354,7 +358,7 @@ pub mod pallet { impl BuildGenesisConfig for GenesisConfig { fn build(&self) { CurrentSetId::::put(SetId::default()); - Pallet::::initialize(&self.authorities) + Pallet::::initialize(self.authorities.clone()) } } @@ -428,12 +432,7 @@ pub enum StoredState { impl Pallet { /// Get the current set of authorities, along with their respective weights. pub fn grandpa_authorities() -> AuthorityList { - storage::unhashed::get_or_default::(GRANDPA_AUTHORITIES_KEY).into() - } - - /// Set the current set of authorities, along with their respective weights. - fn set_grandpa_authorities(authorities: &AuthorityList) { - storage::unhashed::put(GRANDPA_AUTHORITIES_KEY, &VersionedAuthorityList::from(authorities)); + Authorities::::get().into_inner() } /// Schedule GRANDPA to pause starting in the given number of blocks. @@ -522,10 +521,14 @@ impl Pallet { // Perform module initialization, abstracted so that it can be called either through genesis // config builder or through `on_genesis_session`. - fn initialize(authorities: &AuthorityList) { + fn initialize(authorities: AuthorityList) { if !authorities.is_empty() { assert!(Self::grandpa_authorities().is_empty(), "Authorities are already initialized!"); - Self::set_grandpa_authorities(authorities); + Authorities::::put( + &BoundedAuthorityList::::try_from(authorities).expect( + "Grandpa: `Config::MaxAuthorities` is smaller than the number of genesis authorities!", + ), + ); } // NOTE: initialize first session of first set. this is necessary for @@ -568,7 +571,7 @@ where I: Iterator, { let authorities = validators.map(|(_, k)| (k, 1)).collect::>(); - Self::initialize(&authorities); + Self::initialize(authorities); } fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I) diff --git a/substrate/frame/grandpa/src/migrations.rs b/substrate/frame/grandpa/src/migrations.rs index 6307cbdd3b0..3a484eb60d2 100644 --- a/substrate/frame/grandpa/src/migrations.rs +++ b/substrate/frame/grandpa/src/migrations.rs @@ -22,8 +22,11 @@ use frame_support::{ use crate::{Config, CurrentSetId, SetIdSession, LOG_TARGET}; +pub use v5::MigrateV4ToV5; + /// Version 4. pub mod v4; +mod v5; /// This migration will clean up all stale set id -> session entries from the /// `SetIdSession` storage map, only the latest `max_set_id_session_entries` diff --git a/substrate/frame/grandpa/src/migrations/v5.rs b/substrate/frame/grandpa/src/migrations/v5.rs new file mode 100644 index 00000000000..24cfc34104b --- /dev/null +++ b/substrate/frame/grandpa/src/migrations/v5.rs @@ -0,0 +1,96 @@ +// 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::{BoundedAuthorityList, Pallet}; +use codec::Decode; +use frame_support::{ + migrations::VersionedMigration, + storage, + traits::{Get, OnRuntimeUpgrade}, + weights::Weight, +}; +use sp_consensus_grandpa::AuthorityList; +use sp_std::{marker::PhantomData, vec::Vec}; + +const GRANDPA_AUTHORITIES_KEY: &[u8] = b":grandpa_authorities"; + +fn load_authority_list() -> AuthorityList { + storage::unhashed::get_raw(GRANDPA_AUTHORITIES_KEY).map_or_else( + || Vec::new(), + |l| <(u8, AuthorityList)>::decode(&mut &l[..]).unwrap_or_default().1, + ) +} + +/// Actual implementation of [`MigrateV4ToV5`]. +pub struct MigrateImpl(PhantomData); + +impl OnRuntimeUpgrade for MigrateImpl { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + use codec::Encode; + + let authority_list_len = load_authority_list().len() as u32; + + if authority_list_len > T::MaxAuthorities::get() { + return Err( + "Grandpa: `Config::MaxAuthorities` is smaller than the actual number of authorities.".into() + ) + } + + if authority_list_len == 0 { + return Err("Grandpa: Authority list is empty!".into()) + } + + Ok(authority_list_len.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let len = u32::decode(&mut &state[..]).unwrap(); + + frame_support::ensure!( + len == crate::Pallet::::grandpa_authorities().len() as u32, + "Grandpa: pre-migrated and post-migrated list should have the same length" + ); + + frame_support::ensure!( + load_authority_list().is_empty(), + "Old authority list shouldn't exist anymore" + ); + + Ok(()) + } + + fn on_runtime_upgrade() -> Weight { + crate::Authorities::::put( + &BoundedAuthorityList::::force_from( + load_authority_list(), + Some("Grandpa: `Config::MaxAuthorities` is smaller than the actual number of authorities.") + ) + ); + + storage::unhashed::kill(GRANDPA_AUTHORITIES_KEY); + + T::DbWeight::get().reads_writes(1, 2) + } +} + +/// Migrate the storage from V4 to V5. +/// +/// Switches from `GRANDPA_AUTHORITIES_KEY` to a normal FRAME storage item. +pub type MigrateV4ToV5 = + VersionedMigration<4, 5, MigrateImpl, Pallet, ::DbWeight>; diff --git a/substrate/primitives/consensus/grandpa/src/lib.rs b/substrate/primitives/consensus/grandpa/src/lib.rs index baeaee4738e..1cf5504c5e7 100644 --- a/substrate/primitives/consensus/grandpa/src/lib.rs +++ b/substrate/primitives/consensus/grandpa/src/lib.rs @@ -19,13 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(not(feature = "std"))] -extern crate alloc; - #[cfg(feature = "serde")] use serde::Serialize; -use codec::{Codec, Decode, Encode, Input}; +use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] use sp_keystore::KeystorePtr; @@ -33,7 +30,7 @@ use sp_runtime::{ traits::{Header as HeaderT, NumberFor}, ConsensusEngineId, RuntimeDebug, }; -use sp_std::{borrow::Cow, vec::Vec}; +use sp_std::vec::Vec; /// The log target to be used by client code. pub const CLIENT_LOG_TARGET: &str = "grandpa"; @@ -62,10 +59,6 @@ pub type AuthoritySignature = app::Signature; /// The `ConsensusEngineId` of GRANDPA. pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; -/// The storage key for the current set of weighted Grandpa authorities. -/// The value stored is an encoded VersionedAuthorityList. -pub const GRANDPA_AUTHORITIES_KEY: &[u8] = b":grandpa_authorities"; - /// The weight of an authority. pub type AuthorityWeight = u64; @@ -464,60 +457,6 @@ where Some(grandpa::SignedMessage { message, signature, id: public }) } -/// WASM function call to check for pending changes. -pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; -/// WASM function call to get current GRANDPA authorities. -pub const AUTHORITIES_CALL: &str = "grandpa_authorities"; - -/// The current version of the stored AuthorityList type. The encoding version MUST be updated any -/// time the AuthorityList type changes. -const AUTHORITIES_VERSION: u8 = 1; - -/// An AuthorityList that is encoded with a version specifier. The encoding version is updated any -/// time the AuthorityList type changes. This ensures that encodings of different versions of an -/// AuthorityList are differentiable. Attempting to decode an authority list with an unknown -/// version will fail. -#[derive(Default)] -pub struct VersionedAuthorityList<'a>(Cow<'a, AuthorityList>); - -impl<'a> From for VersionedAuthorityList<'a> { - fn from(authorities: AuthorityList) -> Self { - VersionedAuthorityList(Cow::Owned(authorities)) - } -} - -impl<'a> From<&'a AuthorityList> for VersionedAuthorityList<'a> { - fn from(authorities: &'a AuthorityList) -> Self { - VersionedAuthorityList(Cow::Borrowed(authorities)) - } -} - -impl<'a> Into for VersionedAuthorityList<'a> { - fn into(self) -> AuthorityList { - self.0.into_owned() - } -} - -impl<'a> Encode for VersionedAuthorityList<'a> { - fn size_hint(&self) -> usize { - (AUTHORITIES_VERSION, self.0.as_ref()).size_hint() - } - - fn using_encoded R>(&self, f: F) -> R { - (AUTHORITIES_VERSION, self.0.as_ref()).using_encoded(f) - } -} - -impl<'a> Decode for VersionedAuthorityList<'a> { - fn decode(value: &mut I) -> Result { - let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?; - if version != AUTHORITIES_VERSION { - return Err("unknown Grandpa authorities version".into()) - } - Ok(authorities.into()) - } -} - /// An opaque type used to represent the key ownership proof at the runtime API /// boundary. The inner value is an encoded representation of the actual key /// ownership proof which will be parameterized when defining the runtime. At -- GitLab From 60c77a2e9a0e611a227fd2aa82bba1491ea8ba9c Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Mon, 13 Nov 2023 19:14:41 +0530 Subject: [PATCH 490/633] Adds syntax for marking calls feeless (#1926) Fixes https://github.com/paritytech/polkadot-sdk/issues/1725 This PR adds the following changes: 1. An attribute `pallet::feeless_if` that can be optionally attached to a call like so: ```rust #[pallet::feeless_if(|_origin: &OriginFor, something: &u32| -> bool { *something == 0 })] pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { .... } ``` The closure passed accepts references to arguments as specified in the call fn. It returns a boolean that denotes the conditions required for this call to be "feeless". 2. A signed extension `SkipCheckIfFeeless` that wraps a transaction payment processor such as `pallet_transaction_payment::ChargeTransactionPayment`. It checks for all calls annotated with `pallet::feeless_if` to see if the conditions are met. If so, the wrapped signed extension is not called, essentially making the call feeless. In order to use this, you can simply replace your existing signed extension that manages transaction payment like so: ```diff - pallet_transaction_payment::ChargeTransactionPayment, + pallet_skip_feeless_payment::SkipCheckIfFeeless< + Runtime, + pallet_transaction_payment::ChargeTransactionPayment, + >, ``` ### Todo - [x] Tests - [x] Docs - [x] Prdoc --------- Co-authored-by: Nikhil Gupta <> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Francisco Aguirre Co-authored-by: Liam Aharon --- Cargo.lock | 15 ++ Cargo.toml | 1 + prdoc/pr_1926.prdoc | 30 ++++ substrate/bin/node/cli/Cargo.toml | 3 + substrate/bin/node/cli/src/service.rs | 38 +++-- substrate/bin/node/runtime/Cargo.toml | 4 + substrate/bin/node/runtime/src/lib.rs | 16 +- substrate/bin/node/testing/Cargo.toml | 1 + substrate/bin/node/testing/src/keyring.rs | 4 +- .../frame/examples/kitchensink/src/lib.rs | 4 + .../src/construct_runtime/expand/call.rs | 12 ++ substrate/frame/support/procedural/src/lib.rs | 30 ++++ .../procedural/src/pallet/expand/call.rs | 27 ++++ .../procedural/src/pallet/parse/call.rs | 147 +++++++++++++++--- substrate/frame/support/src/dispatch.rs | 14 ++ substrate/frame/support/src/lib.rs | 7 +- .../call_feeless_invalid_closure_arg1.rs | 37 +++++ .../call_feeless_invalid_closure_arg1.stderr | 5 + .../call_feeless_invalid_closure_arg2.rs | 37 +++++ .../call_feeless_invalid_closure_arg2.stderr | 5 + .../call_feeless_invalid_closure_arg3.rs | 37 +++++ .../call_feeless_invalid_closure_arg3.stderr | 5 + .../call_feeless_invalid_closure_return.rs | 37 +++++ ...call_feeless_invalid_closure_return.stderr | 5 + .../pallet_ui/call_feeless_invalid_type.rs | 37 +++++ .../call_feeless_invalid_type.stderr | 11 ++ .../tests/pallet_ui/call_invalid_attr.stderr | 2 +- .../pallet_ui/call_invalid_origin_type.stderr | 6 - .../test/tests/pallet_ui/pass/feeless_call.rs | 37 +++++ .../skip-feeless-payment/Cargo.toml | 44 ++++++ .../skip-feeless-payment/src/lib.rs | 145 +++++++++++++++++ .../skip-feeless-payment/src/mock.rs | 92 +++++++++++ .../skip-feeless-payment/src/tests.rs | 33 ++++ 33 files changed, 874 insertions(+), 54 deletions(-) create mode 100644 prdoc/pr_1926.prdoc create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/pass/feeless_call.rs create mode 100644 substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml create mode 100644 substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs create mode 100644 substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs create mode 100644 substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 2a091ce6817..dbdc2f856c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7224,6 +7224,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", + "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", @@ -8853,6 +8854,7 @@ dependencies = [ "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", "pallet-assets", + "pallet-skip-feeless-payment", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -10795,6 +10797,18 @@ dependencies = [ "sp-std 8.0.0", ] +[[package]] +name = "pallet-skip-feeless-payment" +version = "1.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 8.0.0", +] + [[package]] name = "pallet-society" version = "4.0.0-dev" @@ -18203,6 +18217,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-im-online", + "pallet-skip-feeless-payment", "pallet-timestamp", "parity-scale-codec", "platforms", diff --git a/Cargo.toml b/Cargo.toml index 42bbac37a6c..30445bd5945 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -382,6 +382,7 @@ members = [ "substrate/frame/transaction-payment/asset-tx-payment", "substrate/frame/transaction-payment/rpc", "substrate/frame/transaction-payment/rpc/runtime-api", + "substrate/frame/transaction-payment/skip-feeless-payment", "substrate/frame/transaction-storage", "substrate/frame/treasury", "substrate/frame/try-runtime", diff --git a/prdoc/pr_1926.prdoc b/prdoc/pr_1926.prdoc new file mode 100644 index 00000000000..9dc656f1260 --- /dev/null +++ b/prdoc/pr_1926.prdoc @@ -0,0 +1,30 @@ +title: Adds syntax for marking calls feeless + +doc: + - audience: Core Dev + description: | + 1. Adds an attribute `#[pallet::feeless_if]` that can be optionally attached to a `pallet::call`. + 2. Adds a signed extension SkipCheckIfFeeless that wraps a transaction + payment processor to potentially skip payment fees for such calls. + Note that both the attribute and the signed extension are needed to make the call feeless. + +migrations: + db: [] + + runtime: [] + +crates: + - name: "frame-support-procedural" + semver: minor + - name: "pallet-skip-feeless-payment" + semver: major + - pallet-example-kitchensink + semver: patch + - kitchensink-runtime + semver: major + - node-testing + semver: patch + - node-cli + semver: patch + +host_functions: [] diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 5e7ffebaa8e..8f3c2185deb 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -96,6 +96,7 @@ pallet-assets = { path = "../../../frame/assets" } pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment" } pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment" } pallet-im-online = { path = "../../../frame/im-online", default-features = false} +pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false} # node-specific dependencies kitchensink-runtime = { path = "../runtime" } @@ -168,6 +169,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", + "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", @@ -183,6 +185,7 @@ try-runtime = [ "pallet-assets/try-runtime", "pallet-balances/try-runtime", "pallet-im-online/try-runtime", + "pallet-skip-feeless-payment/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", "substrate-cli-test-utils/try-runtime", diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 153dda5c0a5..1c71b5a3956 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -91,21 +91,24 @@ pub fn create_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: kitchensink_runtime::SignedExtra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(generic::Era::mortal( - period, - best_block.saturated_into(), - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from( - tip, None, - ), - ); + let extra: kitchensink_runtime::SignedExtra = + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_skip_feeless_payment::SkipCheckIfFeeless::from( + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::< + kitchensink_runtime::Runtime, + >::from(tip, None), + ), + ); let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), @@ -879,8 +882,9 @@ mod tests { let check_era = frame_system::CheckEra::from(Era::Immortal); let check_nonce = frame_system::CheckNonce::from(index); let check_weight = frame_system::CheckWeight::new(); - let tx_payment = - pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None); + let tx_payment = pallet_skip_feeless_payment::SkipCheckIfFeeless::from( + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), + ); let extra = ( check_non_zero_sender, check_spec_version, diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 836f90e7654..2414358b60b 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -129,6 +129,7 @@ pallet-transaction-payment = { path = "../../../frame/transaction-payment", defa pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false} pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment", default-features = false} pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment", default-features = false} +pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment", default-features = false} pallet-transaction-storage = { path = "../../../frame/transaction-storage", default-features = false} pallet-uniques = { path = "../../../frame/uniques", default-features = false} pallet-vesting = { path = "../../../frame/vesting", default-features = false} @@ -212,6 +213,7 @@ std = [ "pallet-scheduler/std", "pallet-session-benchmarking?/std", "pallet-session/std", + "pallet-skip-feeless-payment/std", "pallet-society/std", "pallet-staking-runtime-api/std", "pallet-staking/std", @@ -308,6 +310,7 @@ runtime-benchmarks = [ "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", + "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", @@ -381,6 +384,7 @@ try-runtime = [ "pallet-salary/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", + "pallet-skip-feeless-payment/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", "pallet-state-trie-migration/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 620e89a65e5..e9adc48ff9c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -569,6 +569,10 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { pallet_asset_conversion_tx_payment::AssetConversionAdapter; } +impl pallet_skip_feeless_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + parameter_types! { pub const MinimumPeriod: Moment = SLOT_DURATION / 2; } @@ -1394,7 +1398,11 @@ where frame_system::CheckEra::::from(era), frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), - pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from(tip, None), + pallet_skip_feeless_payment::SkipCheckIfFeeless::from( + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from( + tip, None, + ), + ), ); let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { @@ -2134,6 +2142,7 @@ construct_runtime!( Statement: pallet_statement, Broker: pallet_broker, Mixnet: pallet_mixnet, + SkipFeelessPayment: pallet_skip_feeless_payment, } ); @@ -2160,7 +2169,10 @@ pub type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, - pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + pallet_skip_feeless_payment::SkipCheckIfFeeless< + Runtime, + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + >, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 68f80ab6e83..e4fb06b5dcd 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -26,6 +26,7 @@ pallet-asset-conversion = { path = "../../../frame/asset-conversion" } pallet-assets = { path = "../../../frame/assets" } pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment" } pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment" } +pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment" } sc-block-builder = { path = "../../../client/block-builder" } sc-client-api = { path = "../../../client/api" } sc-client-db = { path = "../../../client/db", features = ["rocksdb"]} diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index 22a8f5deb19..9940077c9da 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -78,7 +78,9 @@ pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { frame_system::CheckEra::from(Era::mortal(256, 0)), frame_system::CheckNonce::from(nonce), frame_system::CheckWeight::new(), - pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), + pallet_skip_feeless_payment::SkipCheckIfFeeless::from( + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), + ), ) } diff --git a/substrate/frame/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 56117c59dc6..89759dd0bf6 100644 --- a/substrate/frame/examples/kitchensink/src/lib.rs +++ b/substrate/frame/examples/kitchensink/src/lib.rs @@ -206,6 +206,10 @@ pub mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::set_foo_benchmark())] + /// Marks this call as feeless if `new_foo` is zero. + #[pallet::feeless_if(|_origin: &OriginFor, new_foo: &u32, _other_compact: &u128| -> bool { + *new_foo == 0 + })] pub fn set_foo( _: OriginFor, new_foo: u32, diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs index 859b9a327e4..ce2aa094279 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -124,6 +124,18 @@ pub fn expand_outer_dispatch( } } + impl #scrate::dispatch::CheckIfFeeless for RuntimeCall { + type Origin = #system_path::pallet_prelude::OriginFor<#runtime>; + fn is_feeless(&self, origin: &Self::Origin) -> bool { + match self { + #( + #pallet_attrs + #variant_patterns => call.is_feeless(origin), + )* + } + } + } + impl #scrate::traits::GetCallMetadata for RuntimeCall { fn get_call_metadata(&self) -> #scrate::traits::CallMetadata { use #scrate::traits::GetCallName; diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 68bf3e4874b..ec411891885 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1157,6 +1157,36 @@ pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// Each dispatchable may be annotated with the `#[pallet::feeless_if($closure)]` attribute, +/// which explicitly defines the condition for the dispatchable to be feeless. +/// +/// The arguments for the closure must be the referenced arguments of the dispatchable function. +/// +/// The closure must return `bool`. +/// +/// ### Example +/// ```ignore +/// #[pallet::feeless_if(|_origin: &OriginFor, something: &u32| -> bool { +/// *something == 0 +/// })] +/// pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { +/// .... +/// } +/// ``` +/// +/// Please note that this only works for signed dispatchables and requires a signed extension +/// such as `SkipCheckIfFeeless` as defined in `pallet-skip-feeless-payment` to wrap the existing +/// payment extension. Else, this is completely ignored and the dispatchable is still charged. +/// +/// ### Macro expansion +/// +/// The macro implements the `CheckIfFeeless` trait on the dispatchable and calls the corresponding +/// closure in the implementation. +#[proc_macro_attribute] +pub fn feeless_if(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Allows you to define some extra constants to be added into constant metadata. /// /// Item must be defined as: diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index ed6335159cd..cf302faafc7 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -241,6 +241,16 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { }) .collect::>(); + let feeless_check = methods.iter().map(|method| &method.feeless_check).collect::>(); + let feeless_check_result = + feeless_check.iter().zip(args_name.iter()).map(|(feeless_check, arg_name)| { + if let Some(feeless_check) = feeless_check { + quote::quote!(#feeless_check(origin, #( #arg_name, )*)) + } else { + quote::quote!(false) + } + }); + quote::quote_spanned!(span => mod warnings { #( @@ -347,6 +357,23 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } + impl<#type_impl_gen> #frame_support::dispatch::CheckIfFeeless for #call_ident<#type_use_gen> + #where_clause + { + type Origin = #frame_system::pallet_prelude::OriginFor; + #[allow(unused_variables)] + fn is_feeless(&self, origin: &Self::Origin) -> bool { + match *self { + #( + Self::#fn_name { #( #args_name_pattern_ref, )* } => { + #feeless_check_result + }, + )* + Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"), + } + } + } + impl<#type_impl_gen> #frame_support::traits::GetCallName for #call_ident<#type_use_gen> #where_clause { diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 90631f264b9..519e1e61895 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -17,9 +17,10 @@ use super::{helper, InheritedCallWeightAttr}; use frame_support_procedural_tools::get_doc_literals; +use proc_macro2::Span; use quote::ToTokens; use std::collections::HashMap; -use syn::spanned::Spanned; +use syn::{spanned::Spanned, ExprClosure}; /// List of additional token to be used for parsing. mod keyword { @@ -30,6 +31,7 @@ mod keyword { syn::custom_keyword!(compact); syn::custom_keyword!(T); syn::custom_keyword!(pallet); + syn::custom_keyword!(feeless_if); } /// Definition of dispatchables typically `impl Pallet { ... }` @@ -82,13 +84,18 @@ pub struct CallVariantDef { pub docs: Vec, /// Attributes annotated at the top of the dispatchable function. pub attrs: Vec, + /// The optional `feeless_if` attribute on the `pallet::call`. + pub feeless_check: Option, } /// Attributes for functions in call impl block. -/// Parse for `#[pallet::weight(expr)]` or `#[pallet::call_index(expr)] pub enum FunctionAttr { + /// Parse for `#[pallet::call_index(expr)]` CallIndex(u8), + /// Parse for `#[pallet::weight(expr)]` Weight(syn::Expr), + /// Parse for `#[pallet::feeless_if(expr)]` + FeelessIf(Span, syn::ExprClosure), } impl syn::parse::Parse for FunctionAttr { @@ -115,6 +122,19 @@ impl syn::parse::Parse for FunctionAttr { return Err(syn::Error::new(index.span(), msg)) } Ok(FunctionAttr::CallIndex(index.base10_parse()?)) + } else if lookahead.peek(keyword::feeless_if) { + content.parse::()?; + let closure_content; + syn::parenthesized!(closure_content in content); + Ok(FunctionAttr::FeelessIf( + closure_content.span(), + closure_content.parse::().map_err(|e| { + let msg = "Invalid feeless_if attribute: expected a closure"; + let mut err = syn::Error::new(closure_content.span(), msg); + err.combine(e); + err + })?, + )) } else { Err(lookahead.error()) } @@ -138,28 +158,33 @@ impl syn::parse::Parse for ArgAttrIsCompact { } } -/// Check the syntax is `OriginFor` -pub fn check_dispatchable_first_arg_type(ty: &syn::Type) -> syn::Result<()> { - pub struct CheckDispatchableFirstArg; +/// Check the syntax is `OriginFor` or `&OriginFor`. +pub fn check_dispatchable_first_arg_type(ty: &syn::Type, is_ref: bool) -> syn::Result<()> { + pub struct CheckDispatchableFirstArg(bool); impl syn::parse::Parse for CheckDispatchableFirstArg { fn parse(input: syn::parse::ParseStream) -> syn::Result { + let is_ref = input.parse::().is_ok(); input.parse::()?; input.parse::()?; input.parse::()?; input.parse::]>()?; - Ok(Self) + Ok(Self(is_ref)) } } - syn::parse2::(ty.to_token_stream()).map_err(|e| { - let msg = "Invalid type: expected `OriginFor`"; - let mut err = syn::Error::new(ty.span(), msg); - err.combine(e); - err - })?; - - Ok(()) + let result = syn::parse2::(ty.to_token_stream()); + return match result { + Ok(CheckDispatchableFirstArg(has_ref)) if is_ref == has_ref => Ok(()), + _ => { + let msg = if is_ref { + "Invalid type: expected `&OriginFor`" + } else { + "Invalid type: expected `OriginFor`" + }; + return Err(syn::Error::new(ty.span(), msg)) + }, + } } impl CallDef { @@ -215,7 +240,7 @@ impl CallDef { return Err(syn::Error::new(method.sig.span(), msg)) }, Some(syn::FnArg::Typed(arg)) => { - check_dispatchable_first_arg_type(&arg.ty)?; + check_dispatchable_first_arg_type(&arg.ty, false)?; }, } @@ -227,16 +252,22 @@ impl CallDef { return Err(syn::Error::new(method.sig.span(), msg)) } - let (mut weight_attrs, mut call_idx_attrs): (Vec, Vec) = - helper::take_item_pallet_attrs(&mut method.attrs)?.into_iter().partition( - |attr| { - if let FunctionAttr::Weight(_) = attr { - true - } else { - false - } + let mut call_idx_attrs = vec![]; + let mut weight_attrs = vec![]; + let mut feeless_attrs = vec![]; + for attr in helper::take_item_pallet_attrs(&mut method.attrs)?.into_iter() { + match attr { + FunctionAttr::CallIndex(_) => { + call_idx_attrs.push(attr); }, - ); + FunctionAttr::Weight(_) => { + weight_attrs.push(attr); + }, + FunctionAttr::FeelessIf(span, _) => { + feeless_attrs.push((span, attr)); + }, + } + } if weight_attrs.is_empty() && dev_mode { // inject a default O(1) weight when dev mode is enabled and no weight has @@ -323,6 +354,73 @@ impl CallDef { let docs = get_doc_literals(&method.attrs); + if feeless_attrs.len() > 1 { + let msg = "Invalid pallet::call, there can only be one feeless_if attribute"; + return Err(syn::Error::new(feeless_attrs[1].0, msg)) + } + let feeless_check: Option = + feeless_attrs.pop().map(|(_, attr)| match attr { + FunctionAttr::FeelessIf(_, closure) => closure, + _ => unreachable!("checked during creation of the let binding"), + }); + + if let Some(ref feeless_check) = feeless_check { + if feeless_check.inputs.len() != args.len() + 1 { + let msg = "Invalid pallet::call, feeless_if closure must have same \ + number of arguments as the dispatchable function"; + return Err(syn::Error::new(feeless_check.span(), msg)) + } + + match feeless_check.inputs.first() { + None => { + let msg = "Invalid pallet::call, feeless_if closure must have at least origin arg"; + return Err(syn::Error::new(feeless_check.span(), msg)) + }, + Some(syn::Pat::Type(arg)) => { + check_dispatchable_first_arg_type(&arg.ty, true)?; + }, + _ => { + let msg = "Invalid pallet::call, feeless_if closure first argument must be a typed argument, \ + e.g. `origin: OriginFor`"; + return Err(syn::Error::new(feeless_check.span(), msg)) + }, + } + + for (feeless_arg, arg) in feeless_check.inputs.iter().skip(1).zip(args.iter()) { + let feeless_arg_type = + if let syn::Pat::Type(syn::PatType { ty, .. }) = feeless_arg.clone() { + if let syn::Type::Reference(pat) = *ty { + pat.elem.clone() + } else { + let msg = "Invalid pallet::call, feeless_if closure argument must be a reference"; + return Err(syn::Error::new(ty.span(), msg)) + } + } else { + let msg = "Invalid pallet::call, feeless_if closure argument must be a type ascription pattern"; + return Err(syn::Error::new(feeless_arg.span(), msg)) + }; + + if feeless_arg_type != arg.2 { + let msg = + "Invalid pallet::call, feeless_if closure argument must have \ + a reference to the same type as the dispatchable function argument"; + return Err(syn::Error::new(feeless_arg.span(), msg)) + } + } + + let valid_return = match &feeless_check.output { + syn::ReturnType::Type(_, type_) => match *(type_.clone()) { + syn::Type::Path(syn::TypePath { path, .. }) => path.is_ident("bool"), + _ => false, + }, + _ => false, + }; + if !valid_return { + let msg = "Invalid pallet::call, feeless_if closure must return `bool`"; + return Err(syn::Error::new(feeless_check.output.span(), msg)) + } + } + methods.push(CallVariantDef { name: method.sig.ident.clone(), weight, @@ -331,6 +429,7 @@ impl CallDef { args, docs, attrs: method.attrs.clone(), + feeless_check, }); } else { let msg = "Invalid pallet::call, only method accepted"; diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index e6a090ebcae..e57227f9b40 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -54,6 +54,20 @@ pub trait Callable { // https://github.com/rust-lang/rust/issues/51331 pub type CallableCallFor =
>::RuntimeCall; +/// Means to checks if the dispatchable is feeless. +/// +/// This is automatically implemented for all dispatchables during pallet expansion. +/// If a call is marked by [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`) +/// attribute, the corresponding closure is checked. +pub trait CheckIfFeeless { + /// The Origin type of the runtime. + type Origin; + + /// Checks if the dispatchable satisfies the feeless condition as defined by + /// [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`) + fn is_feeless(&self, origin: &Self::Origin) -> bool; +} + /// Origin for the System pallet. #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RawOrigin { diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index a01f3a01593..2ec3b24db0c 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2227,9 +2227,10 @@ pub use frame_support_procedural::pallet; pub mod pallet_macros { pub use frame_support_procedural::{ call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error, - event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, - inherent, no_default, no_default_bounds, origin, pallet_section, storage_prefix, - storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, + event, extra_constants, feeless_if, generate_deposit, generate_store, getter, hooks, + import_section, inherent, no_default, no_default_bounds, origin, pallet_section, + storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight, + whitelist_storage, }; /// Allows you to define the genesis configuration for the pallet. diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.rs b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.rs new file mode 100644 index 00000000000..08aaf06a7ef --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(|| -> bool { true })] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.stderr b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.stderr new file mode 100644 index 00000000000..9c13d59d793 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg1.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::call, feeless_if closure must have same number of arguments as the dispatchable function + --> tests/pallet_ui/call_feeless_invalid_closure_arg1.rs:31:24 + | +31 | #[pallet::feeless_if(|| -> bool { true })] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.rs b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.rs new file mode 100644 index 00000000000..b16b4b3ffd9 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(|_: bool| -> bool { true })] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.stderr new file mode 100644 index 00000000000..1c38ec23683 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg2.stderr @@ -0,0 +1,5 @@ +error: Invalid type: expected `&OriginFor` + --> tests/pallet_ui/call_feeless_invalid_closure_arg2.rs:31:28 + | +31 | #[pallet::feeless_if(|_: bool| -> bool { true })] + | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.rs b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.rs new file mode 100644 index 00000000000..5f2230744ff --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(|_: &OriginFor, _s: &u32| -> bool { true })] + pub fn foo(_: OriginFor, _something: u64) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.stderr new file mode 100644 index 00000000000..1ad9588cead --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_arg3.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::call, feeless_if closure argument must have a reference to the same type as the dispatchable function argument + --> tests/pallet_ui/call_feeless_invalid_closure_arg3.rs:31:43 + | +31 | #[pallet::feeless_if(|_: &OriginFor, _s: &u32| -> bool { true })] + | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.rs b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.rs new file mode 100644 index 00000000000..1f0399a123c --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(|_: &OriginFor| -> u32 { 0 })] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.stderr b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.stderr new file mode 100644 index 00000000000..a8c05242bde --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_closure_return.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::call, feeless_if closure must return `bool` + --> tests/pallet_ui/call_feeless_invalid_closure_return.rs:31:43 + | +31 | #[pallet::feeless_if(|_: &OriginFor| -> u32 { 0 })] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.rs b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.rs new file mode 100644 index 00000000000..26bd8a600ab --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(0)] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.stderr b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.stderr new file mode 100644 index 00000000000..add3decbf16 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_feeless_invalid_type.stderr @@ -0,0 +1,11 @@ +error: Invalid feeless_if attribute: expected a closure + --> tests/pallet_ui/call_feeless_invalid_type.rs:31:24 + | +31 | #[pallet::feeless_if(0)] + | ^ + +error: expected `|` + --> tests/pallet_ui/call_feeless_invalid_type.rs:31:24 + | +31 | #[pallet::feeless_if(0)] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr index eec5e33ccbd..1809fcb6ed9 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr @@ -1,4 +1,4 @@ -error: expected `weight` or `call_index` +error: expected one of: `weight`, `call_index`, `feeless_if` --> tests/pallet_ui/call_invalid_attr.rs:31:13 | 31 | #[pallet::weird_attr] diff --git a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr index 99146c0563a..c04729a2438 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_invalid_origin_type.stderr @@ -3,9 +3,3 @@ error: Invalid type: expected `OriginFor` | 34 | pub fn foo(origin: u8) {} | ^^ - -error: expected `OriginFor` - --> tests/pallet_ui/call_invalid_origin_type.rs:34:22 - | -34 | pub fn foo(origin: u8) {} - | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/feeless_call.rs b/substrate/frame/support/test/tests/pallet_ui/pass/feeless_call.rs new file mode 100644 index 00000000000..566b7c65cc7 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/feeless_call.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet(dev_mode)] +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::feeless_if(|_: &OriginFor| -> bool { true })] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml new file mode 100644 index 00000000000..cfb814e2e38 --- /dev/null +++ b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "pallet-skip-feeless-payment" +version = "1.0.0-dev" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "Pallet to skip payments for calls annotated with `feeless_if` if the respective conditions are satisfied." + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# Substrate dependencies +sp-runtime = { path = "../../../primitives/runtime", default-features = false} +sp-std = { path = "../../../primitives/std", default-features = false} + +frame-support = { path = "../../support", default-features = false} +frame-system = { path = "../../system", default-features = false} + +# Other dependencies +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", +] +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/transaction-payment/skip-feeless-payment/src/lib.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs new file mode 100644 index 00000000000..923c7e7ebc2 --- /dev/null +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -0,0 +1,145 @@ +// 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. +// +//! # Skip Feeless Payment Pallet +//! +//! This pallet allows runtimes that include it to skip payment of transaction fees for +//! dispatchables marked by [`#[pallet::feeless_if]`](`macro@ +//! frame_support::pallet_prelude::feeless_if`). +//! +//! ## Overview +//! +//! It does this by wrapping an existing [`SignedExtension`] implementation (e.g. +//! [`pallet-transaction-payment`]) and checking if the dispatchable is feeless before applying the +//! wrapped extension. If the dispatchable is indeed feeless, the extension is skipped and a custom +//! event is emitted instead. Otherwise, the extension is applied as usual. +//! +//! +//! ## Integration +//! +//! This pallet wraps an existing transaction payment pallet. This means you should both pallets +//! in your `construct_runtime` macro and include this pallet's +//! [`SignedExtension`] ([`SkipCheckIfFeeless`]) that would accept the existing one as an argument. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::{CheckIfFeeless, DispatchResult}, + traits::{IsType, OriginTrait}, +}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{DispatchInfoOf, PostDispatchInfoOf, SignedExtension}, + transaction_validity::TransactionValidityError, +}; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transaction fee was skipped. + FeeSkipped { who: T::AccountId }, + } +} + +/// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless. +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct SkipCheckIfFeeless(pub S, sp_std::marker::PhantomData); + +impl sp_std::fmt::Debug for SkipCheckIfFeeless { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "SkipCheckIfFeeless<{:?}>", self.0.encode()) + } + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl SkipCheckIfFeeless { + /// utility constructor. Used only in client/factory code. + pub fn from(s: S) -> Self { + Self(s, sp_std::marker::PhantomData) + } +} + +impl> SignedExtension + for SkipCheckIfFeeless +where + S::Call: CheckIfFeeless>, +{ + type AccountId = T::AccountId; + type Call = S::Call; + type AdditionalSigned = S::AdditionalSigned; + type Pre = (Self::AccountId, Option<::Pre>); + const IDENTIFIER: &'static str = "SkipCheckIfFeeless"; + + fn additional_signed(&self) -> Result { + self.0.additional_signed() + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + if call.is_feeless(&::RuntimeOrigin::signed(who.clone())) { + Ok((who.clone(), None)) + } else { + Ok((who.clone(), Some(self.0.pre_dispatch(who, call, info, len)?))) + } + } + + fn post_dispatch( + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + if let Some(pre) = pre { + if let Some(pre) = pre.1 { + S::post_dispatch(Some(pre), info, post_info, len, result)?; + } else { + Pallet::::deposit_event(Event::::FeeSkipped { who: pre.0 }); + } + } + Ok(()) + } +} diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs new file mode 100644 index 00000000000..5c540c3e459 --- /dev/null +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs @@ -0,0 +1,92 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate as pallet_skip_feeless_payment; + +use frame_support::{derive_impl, parameter_types}; +use frame_system as system; + +type Block = frame_system::mocking::MockBlock; +type AccountId = u64; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + pub static PreDispatchCount: u32 = 0; +} + +#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] +pub struct DummyExtension; + +impl SignedExtension for DummyExtension { + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + const IDENTIFIER: &'static str = "DummyExtension"; + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + PreDispatchCount::mutate(|c| *c += 1); + Ok(()) + } +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet_dummy { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::feeless_if(|_origin: &OriginFor, data: &u32| -> bool { + *data == 0 + })] + pub fn aux(_origin: OriginFor, #[pallet::compact] _data: u32) -> DispatchResult { + unreachable!() + } + } +} + +impl pallet_dummy::Config for Runtime {} + +frame_support::construct_runtime!( + pub struct Runtime { + System: system, + SkipFeeless: pallet_skip_feeless_payment, + DummyPallet: pallet_dummy, + } +); diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs new file mode 100644 index 00000000000..4b4dd699741 --- /dev/null +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs @@ -0,0 +1,33 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::mock::{pallet_dummy::Call, DummyExtension, PreDispatchCount, Runtime, RuntimeCall}; +use frame_support::dispatch::DispatchInfo; + +#[test] +fn skip_feeless_payment_works() { + let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); + SkipCheckIfFeeless::::from(DummyExtension) + .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) + .unwrap(); + assert_eq!(PreDispatchCount::get(), 1); + + let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); + SkipCheckIfFeeless::::from(DummyExtension) + .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) + .unwrap(); + assert_eq!(PreDispatchCount::get(), 1); +} -- GitLab From 29654a4d7154296e8e6cb2a067896490d67d96a1 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Mon, 13 Nov 2023 19:56:33 +0530 Subject: [PATCH 491/633] Skip zombienet CI job until PolkadotJS includes `SkipCheckIfFeeless` extension (#2294) --- .gitlab/pipeline/zombienet/substrate.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 9fb2f161ad7..9e14ebe0852 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -38,13 +38,14 @@ tags: - zombienet-polkadot-integration-test -zombienet-substrate-0000-block-building: - extends: - - .zombienet-substrate-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh - --local-dir="${LOCAL_DIR}/0000-block-building" - --test="block-building.zndsl" +# Skip this one until PolkadotJS includes `SkipCheckIfFeeless` extension +# zombienet-substrate-0000-block-building: +# extends: +# - .zombienet-substrate-common +# script: +# - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh +# --local-dir="${LOCAL_DIR}/0000-block-building" +# --test="block-building.zndsl" zombienet-substrate-0001-basic-warp-sync: extends: -- GitLab From 18257373b313fcfad4f7a2ab2cb02cb8bfc5b8f1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 13 Nov 2023 17:16:55 +0200 Subject: [PATCH 492/633] pallet-xcm: enhance `reserve_transfer_assets` to support remote reserves (#1672) ## Motivation `pallet-xcm` is the main user-facing interface for XCM functionality, including assets manipulation functions like `teleportAssets()` and `reserve_transfer_assets()` calls. While `teleportAsset()` works both ways, `reserve_transfer_assets()` works only for sending reserve-based assets to a remote destination and beneficiary when the reserve is the _local chain_. ## Solution This PR enhances `pallet_xcm::(limited_)reserve_withdraw_assets` to support transfers when reserves are other chains. This will allow complete, **bi-directional** reserve-based asset transfers user stories using `pallet-xcm`. Enables following scenarios: - transferring assets with local reserve (was previously supported iff asset used as fee also had local reserve - now it works in all cases), - transferring assets with reserve on destination, - transferring assets with reserve on remote/third-party chain (iff assets and fees have same remote reserve), - transferring assets with reserve different than the reserve of the asset to be used as fees - meaning can be used to transfer random asset with local/dest reserve while using DOT for fees on all involved chains, even if DOT local/dest reserve doesn't match asset reserve, - transferring assets with any type of local/dest reserve while using fees which can be teleported between involved chains. All of the above is done by pallet inner logic without the user having to specify which scenario/reserves/teleports/etc. The correct scenario and corresponding XCM programs are identified, and respectively, built automatically based on runtime configuration of trusted teleporters and trusted reserves. #### Current limitations: - while `fees` and "non-fee" `assets` CAN have different reserves (or fees CAN be teleported), the remaining "non-fee" `assets` CANNOT, among themselves, have different reserve locations (this is also implicitly enforced by `MAX_ASSETS_FOR_TRANSFER=2`, but this can be safely increased in the future). - `fees` and "non-fee" `assets` CANNOT have **different remote** reserves (this could also be supported in the future, but adds even more complexity while possibly not being worth it - we'll see what the future holds). Fixes https://github.com/paritytech/polkadot-sdk/issues/1584 Fixes https://github.com/paritytech/polkadot-sdk/issues/2055 --------- Co-authored-by: Francisco Aguirre Co-authored-by: Branislav Kontur --- Cargo.lock | 5 + .../runtime/src/xcm_config.rs | 7 - .../assets/asset-hub-rococo/src/lib.rs | 6 +- .../assets/asset-hub-westend/src/lib.rs | 6 +- .../assets/asset-hub-wococo/src/lib.rs | 6 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../bridges/bridge-hub-westend/src/lib.rs | 2 +- .../bridges/bridge-hub-wococo/src/lib.rs | 2 +- .../parachains/testing/penpal/Cargo.toml | 1 + .../parachains/testing/penpal/src/lib.rs | 12 +- .../emulated/chains/relays/westend/src/lib.rs | 2 +- .../emulated/common/src/impls.rs | 14 +- .../tests/assets/asset-hub-rococo/Cargo.toml | 4 +- .../tests/assets/asset-hub-rococo/src/lib.rs | 25 +- .../src/tests/reserve_transfer.rs | 495 +++--- .../asset-hub-rococo/src/tests/teleport.rs | 18 +- .../tests/assets/asset-hub-westend/src/lib.rs | 4 +- .../src/tests/reserve_transfer.rs | 359 +---- .../asset-hub-westend/src/tests/teleport.rs | 2 +- .../assets/asset-hub-kusama/src/lib.rs | 36 +- .../assets/asset-hub-kusama/src/xcm_config.rs | 7 - .../assets/asset-hub-kusama/tests/tests.rs | 40 +- .../assets/asset-hub-polkadot/src/lib.rs | 36 +- .../asset-hub-polkadot/src/xcm_config.rs | 7 - .../assets/asset-hub-polkadot/tests/tests.rs | 40 +- .../assets/asset-hub-rococo/src/lib.rs | 36 +- .../assets/asset-hub-rococo/src/xcm_config.rs | 7 - .../assets/asset-hub-rococo/tests/tests.rs | 35 +- .../assets/asset-hub-westend/src/lib.rs | 36 +- .../asset-hub-westend/src/xcm_config.rs | 7 - .../assets/asset-hub-westend/tests/tests.rs | 35 +- .../runtimes/assets/test-utils/src/lib.rs | 15 + .../assets/test-utils/src/test_cases.rs | 288 +++- .../test-utils/src/test_cases_over_bridge.rs | 88 +- .../parachains/runtimes/bridge-hubs/README.md | 16 +- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 26 +- .../bridge-hub-kusama/src/xcm_config.rs | 7 - .../bridge-hub-kusama/tests/tests.rs | 6 - .../bridge-hub-polkadot/src/lib.rs | 26 +- .../bridge-hub-polkadot/src/xcm_config.rs | 7 - .../bridge-hub-polkadot/tests/tests.rs | 6 - .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 26 +- .../bridge-hub-rococo/src/xcm_config.rs | 7 - .../bridge-hub-rococo/tests/tests.rs | 12 - .../bridge-hubs/bridge-hub-westend/src/lib.rs | 26 +- .../bridge-hub-westend/src/xcm_config.rs | 7 - .../bridge-hub-westend/tests/tests.rs | 6 - .../collectives-polkadot/src/lib.rs | 26 +- .../collectives-polkadot/src/xcm_config.rs | 7 - .../contracts/contracts-rococo/src/lib.rs | 27 +- .../contracts-rococo/src/xcm_config.rs | 7 - .../runtimes/testing/penpal/src/lib.rs | 11 +- .../runtimes/testing/penpal/src/xcm_config.rs | 84 +- .../testing/rococo-parachain/src/lib.rs | 7 - cumulus/scripts/bridges_rococo_westend.sh | 28 +- cumulus/xcm/xcm-emulator/src/lib.rs | 8 +- polkadot/runtime/parachains/src/paras/mod.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 32 +- polkadot/runtime/rococo/src/xcm_config.rs | 7 - .../runtime/test-runtime/src/xcm_config.rs | 7 - polkadot/runtime/westend/src/lib.rs | 28 +- polkadot/runtime/westend/src/xcm_config.rs | 7 - polkadot/xcm/pallet-xcm/Cargo.toml | 10 +- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 165 +- polkadot/xcm/pallet-xcm/src/lib.rs | 551 ++++++- polkadot/xcm/pallet-xcm/src/mock.rs | 203 ++- .../pallet-xcm/src/tests/assets_transfer.rs | 1405 +++++++++++++++++ .../pallet-xcm/src/{tests.rs => tests/mod.rs} | 375 +---- polkadot/xcm/src/v3/multilocation.rs | 66 + polkadot/xcm/xcm-builder/src/barriers.rs | 13 +- .../xcm/xcm-builder/src/tests/pay/mock.rs | 7 - polkadot/xcm/xcm-builder/tests/mock/mod.rs | 7 - polkadot/xcm/xcm-executor/Cargo.toml | 2 + polkadot/xcm/xcm-executor/src/lib.rs | 8 +- .../xcm-executor/src/traits/asset_transfer.rs | 90 ++ polkadot/xcm/xcm-executor/src/traits/mod.rs | 6 +- .../xcm-simulator/example/src/parachain.rs | 7 - .../xcm-simulator/example/src/relay_chain.rs | 7 - .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 7 - .../xcm-simulator/fuzzer/src/relay_chain.rs | 7 - 80 files changed, 3650 insertions(+), 1437 deletions(-) create mode 100644 polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs rename polkadot/xcm/pallet-xcm/src/{tests.rs => tests/mod.rs} (68%) create mode 100644 polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs diff --git a/Cargo.lock b/Cargo.lock index dbdc2f856c4..4a45d5c602e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -901,9 +901,11 @@ dependencies = [ "pallet-asset-conversion", "pallet-assets", "pallet-balances", + "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "rococo-runtime", "rococo-system-emulated-network", "sp-runtime", @@ -11183,6 +11185,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "pallet-assets", "pallet-balances", "parity-scale-codec", "polkadot-parachain-primitives", @@ -11630,6 +11633,7 @@ dependencies = [ "frame-support", "parachains-common", "penpal-runtime", + "rococo-emulated-chain", "serde_json", "sp-core", "sp-runtime", @@ -18416,6 +18420,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", + "scale-info", "sp-arithmetic", "sp-core", "sp-io", diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index 353f68d22e3..752137c96f1 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -150,11 +150,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -180,8 +175,6 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 0580d61eae9..f94c4c3d255 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -51,5 +51,5 @@ decl_test_parachains! { // AssetHubRococo implementation impl_accounts_helpers_for_parachain!(AssetHubRococo); -impl_assert_events_helpers_for_parachain!(AssetHubRococo); -impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); +impl_assert_events_helpers_for_parachain!(AssetHubRococo, false); +impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 804b727c33f..73d777247a5 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -51,5 +51,5 @@ decl_test_parachains! { // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); -impl_assert_events_helpers_for_parachain!(AssetHubWestend); -impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); +impl_assert_events_helpers_for_parachain!(AssetHubWestend, false); +impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs index 677ca1763cf..38a6ece3472 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs @@ -19,7 +19,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use wococo_emulated_chain::Wococo; @@ -49,5 +49,5 @@ decl_test_parachains! { // AssetHubWococo implementation impl_accounts_helpers_for_parachain!(AssetHubWococo); -impl_assert_events_helpers_for_parachain!(AssetHubWococo); -impl_assets_helpers_for_system_parachain!(AssetHubWococo, Wococo); +impl_assert_events_helpers_for_parachain!(AssetHubWococo, false); +impl_assets_helpers_for_parachain!(AssetHubWococo, Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index d7630954c86..f4557021f62 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); -impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index 436b65cb916..1f1126d4565 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); -impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs index 6807a2ab8c8..e643f104aa3 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs @@ -44,4 +44,4 @@ decl_test_parachains! { // BridgeHubWococo implementation impl_accounts_helpers_for_parachain!(BridgeHubWococo); -impl_assert_events_helpers_for_parachain!(BridgeHubWococo); +impl_assert_events_helpers_for_parachain!(BridgeHubWococo, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 42aaee3f102..c55b10d7180 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -22,3 +22,4 @@ parachains-common = { path = "../../../../../../../parachains/common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } +rococo-emulated-chain = { path = "../../../relays/rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 8709d4e9196..537f96f45b4 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -21,8 +21,10 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ - impl_assert_events_helpers_for_parachain, xcm_emulator::decl_test_parachains, + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; +use rococo_emulated_chain::Rococo; // Penpal Parachain declaration decl_test_parachains! { @@ -40,6 +42,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, pub struct PenpalB { @@ -56,10 +59,13 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, } // Penpal implementation -impl_assert_events_helpers_for_parachain!(PenpalA); -impl_assert_events_helpers_for_parachain!(PenpalB); +impl_accounts_helpers_for_parachain!(PenpalA); +impl_assets_helpers_for_parachain!(PenpalA, Rococo); +impl_assert_events_helpers_for_parachain!(PenpalA, true); +impl_assert_events_helpers_for_parachain!(PenpalB, true); diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs index af45d8db4e6..d4ba1b6cfe7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -30,7 +30,7 @@ decl_test_relay_chains! { on_init = (), runtime = westend_runtime, core = { - SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, + SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, }, pallets = { XcmPallet: westend_runtime::XcmPallet, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 6c99c1614db..82f27b93200 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -399,7 +399,7 @@ macro_rules! impl_accounts_helpers_for_parachain { #[macro_export] macro_rules! impl_assert_events_helpers_for_parachain { - ( $chain:ident ) => { + ( $chain:ident, $ignore_weight:expr ) => { $crate::impls::paste::paste! { type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; @@ -412,7 +412,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -434,7 +434,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -490,7 +490,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -510,7 +510,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: false, weight_used: weight, .. }) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -541,7 +541,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { vec![ [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -556,7 +556,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { } #[macro_export] -macro_rules! impl_assets_helpers_for_system_parachain { +macro_rules! impl_assets_helpers_for_parachain { ( $chain:ident, $relay_chain:ident ) => { $crate::impls::paste::paste! { impl $chain { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 6e592f04ba1..23f80f33f78 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default 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-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} @@ -28,5 +29,6 @@ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } parachains-common = { path = "../../../../../../parachains/common" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } -emulated-integration-tests-common = { path = "../../../common", default-features = false} +emulated-integration-tests-common = { path = "../../../common", default-features = false } +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } rococo-system-emulated-network ={ path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 11380cd1e2d..3ff8c37c646 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -61,18 +61,20 @@ pub const ASSET_MIN_BALANCE: u128 = 1000; pub const ASSETS_PALLET_ID: u8 = 50; pub type RelayToSystemParaTest = Test; +pub type RelayToParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; +pub type ParaToSystemParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests -pub fn relay_test_args(amount: Balance) -> TestArgs { +/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests +pub fn relay_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, +) -> TestArgs { TestArgs { - dest: Rococo::child_location_of(AssetHubRococo::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubRococoReceiver::get().into(), - } - .into(), + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), amount, assets: (Here, amount).into(), asset_id: None, @@ -81,13 +83,14 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests -pub fn system_para_test_args( +/// Returns a `TestArgs` instance to be used by parachains across integration tests +pub fn para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, amount: Balance, assets: MultiAssets, asset_id: Option, + fee_asset_item: u32, ) -> TestArgs { TestArgs { dest, @@ -95,7 +98,7 @@ pub fn system_para_test_args( amount, assets, asset_id, - fee_asset_item: 0, + fee_asset_item, weight_limit: WeightLimit::Unlimited, } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 76d93b2dbdb..d0e9b72176b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -15,37 +15,45 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use penpal_runtime::xcm_config::XcmConfig as PenpalRococoXcmConfig; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -fn relay_origin_assertions(t: RelayToSystemParaTest) { +fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; - Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); assert_expected_events!( Rococo, vec![ - // Amount to reserve transfer is transferred to System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { from: *from == t.sender.account_id, to: *to == Rococo::sovereign_account_id_of( t.args.dest ), - amount: *amount == t.args.amount, + amount: *amount == t.args.amount, }, ] ); } -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubRococo::assert_dmp_queue_incomplete(Some(Weight::from_parts(57_185_000, 3504))); -} - -fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubRococo::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) +fn relay_to_para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); } -fn system_para_to_para_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -56,7 +64,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Transfer { from, to, amount } ) => { @@ -70,7 +78,64 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { ); } -fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + + assert_expected_events!( + PenpalA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + amount: *amount == t.args.amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -81,7 +146,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { @@ -96,29 +161,22 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } -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_to_para_assets_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); } -fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( +fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { + ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -128,16 +186,6 @@ fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> Disp ) } -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, @@ -149,101 +197,108 @@ 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( +fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> 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, ) } -/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't -/// work +/// 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 +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); + let destination = Rococo::child_location_of(AssetHubRococo::para_id()); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); let amount_to_send: Balance = ROCOCO_ED * 1000; - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::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 delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + let assets: MultiAssets = (Here, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + Rococo::execute_with(|| { + let result = ::XcmPallet::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 99, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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 +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); let destination = AssetHubRococo::parent_location(); let beneficiary_id = RococoReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - 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::(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); + let assets: MultiAssets = (Parent, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + AssetHubRococo::execute_with(|| { + let result = + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); } -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +/// Reserve Transfers of native asset from Relay to Parachain should work #[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain +fn reserve_transfer_native_asset_from_relay_to_para() { + // Init values for Relay + let destination = Rococo::child_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; + let test_args = TestContext { sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: relay_test_args(amount_to_send), + receiver: PenpalAReceiver::get(), + args: relay_test_args(destination, beneficiary_id, amount_to_send), }; - let mut test = RelayToSystemParaTest::new(test_args); + let mut test = RelayToParaTest::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.set_assertion::(relay_to_para_sender_assertions); + test.set_assertion::(relay_to_para_receiver_assertions); + test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); test.assert(); let delivery_fees = Rococo::execute_with(|| { @@ -255,44 +310,15 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { 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 - delivery_fees, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } -/// 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 = 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: 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::(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 +/// Reserve Transfers of native asset from System Parachain to Parachain should work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_para() { +fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let beneficiary_id = PenpalAReceiver::get(); @@ -302,20 +328,21 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToParaTest::new(test_args); let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< @@ -323,117 +350,153 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } -/// Reserve Transfers of native asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from Parachain to System Parachain should work #[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); +fn reserve_transfer_native_asset_from_para_to_system_para() { + // Init values for Penpal Parachain + let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let beneficiary_id = AssetHubRococoReceiver::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + sender: PenpalASender::get(), + receiver: AssetHubRococoReceiver::get(), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; - let mut test = SystemParaToParaTest::new(test_args); + let mut test = ParaToSystemParaTest::new(test_args); let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - 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); + // fund the Penpal's SA on AHR with the native tokens held in reserve + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + + test.set_assertion::(para_to_system_para_sender_assertions); + test.set_assertion::(para_to_system_para_receiver_assertions); + test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; - let delivery_fees = AssetHubRococo::execute_with(|| { + let delivery_fees = PenpalA::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, + ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +/// Reserve Transfers of a local asset and native 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 +fn reserve_transfer_assets_from_system_para_to_para() { + // Force create asset on AssetHubRococo and PenpalA from Relay Chain AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, - true, + false, AssetHubRococoSender::get(), Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, + ASSET_MIN_BALANCE * 1_000_000, + ); + PenpalA::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + false, + PenpalASender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + 0, ); // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let beneficiary_id = PenpalAReceiver::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 { + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), asset_amount_to_send) + .into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + let para_test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args( + destination, + beneficiary_id, + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), }; - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + let mut test = SystemParaToParaTest::new(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(); -} + // Create SA-of-Penpal-on-AHR with ED. + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]); -/// 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 - AssetHubRococo::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubRococoSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, - ); + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; - // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::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 sender_assets_before = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubRococoSender::get()) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalAReceiver::get()) + }); - let system_para_test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; + test.set_assertion::(system_para_to_para_assets_sender_assertions); + test.set_assertion::(system_para_to_para_assets_receiver_assertions); + test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert!(sender_balance_after < sender_balance_before); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); + + let sender_assets_after = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubRococoSender::get()) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalAReceiver::get()) + }); - 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(); + // Sender's balance is reduced + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 0d2ca685247..f8017f7a1c5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -51,7 +51,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { assert_expected_events!( Rococo, vec![ - // Amount is witdrawn from Relay Chain's `CheckAccount` + // Amount is withdrawn from Relay Chain's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, @@ -157,10 +157,12 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { fn limited_teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = ROCOCO_ED * 1000; + let dest = Rococo::child_location_of(AssetHubRococo::para_id()); + let beneficiary_id = AssetHubRococoReceiver::get(); let test_args = TestContext { sender: RococoSender::get(), receiver: AssetHubRococoReceiver::get(), - args: relay_test_args(amount_to_send), + args: relay_test_args(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -204,7 +206,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -245,7 +247,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -278,10 +280,12 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { fn teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = ROCOCO_ED * 1000; + let dest = Rococo::child_location_of(AssetHubRococo::para_id()); + let beneficiary_id = AssetHubRococoReceiver::get(); let test_args = TestContext { sender: RococoSender::get(), receiver: AssetHubRococoReceiver::get(), - args: relay_test_args(amount_to_send), + args: relay_test_args(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -325,7 +329,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -366,7 +370,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index e52ad448c0b..83a867e6ae3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -65,7 +65,7 @@ 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 +/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { dest: Westend::child_location_of(AssetHubWestend::para_id()), @@ -82,7 +82,7 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +/// Returns a `TestArgs` instance to be used for the System Parachain across integration tests pub fn system_para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 19a203897ad..5b2c648b7b0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -15,37 +15,8 @@ use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig; -use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196))); - - assert_expected_events!( - Westend, - 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 == Westend::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_dest_assertions(_t: RelayToSystemParaTest) { - AssetHubWestend::assert_dmp_queue_incomplete(Some(Weight::from_parts(31_352_000, 1489))); -} - -fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubWestend::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) -} - -fn system_para_to_para_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -56,7 +27,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Transfer { from, to, amount } ) => { @@ -70,6 +41,19 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { ); } +fn para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -81,7 +65,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { @@ -96,48 +80,6 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } -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, @@ -149,187 +91,72 @@ 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( - 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 = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::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); - test.set_dispatchable::(relay_limited_reserve_transfer_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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 = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - 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(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 signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); + let destination = Westend::child_location_of(AssetHubWestend::para_id()); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); let amount_to_send: Balance = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::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); - test.set_dispatchable::(relay_reserve_transfer_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + let assets: MultiAssets = (Here, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + Westend::execute_with(|| { + let result = ::XcmPallet::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 99, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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 signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); let destination = AssetHubWestend::parent_location(); let beneficiary_id = WestendReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); 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(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 = AssetHubWestend::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - 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: PenpalAReceiver::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; - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( - test.args.assets.clone(), - 0, - test.args.weight_limit, - test.args.beneficiary, - test.args.dest, - ) + let assets: MultiAssets = (Parent, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + AssetHubWestend::execute_with(|| { + let result = + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); }); - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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 @@ -350,14 +177,15 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let mut test = SystemParaToParaTest::new(test_args); let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.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.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(para_receiver_assertions); + test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( @@ -369,45 +197,10 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { ) }); + // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, 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 - AssetHubWestend::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubWestendSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::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: AssetHubWestendSender::get(), - receiver: PenpalAReceiver::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(); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } /// Reserve Transfers of a local asset from System Parachain to Parachain should work @@ -442,6 +235,6 @@ fn reserve_transfer_asset_from_system_para_to_para() { 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_limited_reserve_transfer_assets); system_para_test.assert(); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 57e1b93f349..d618cd2fe04 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -51,7 +51,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { assert_expected_events!( Westend, vec![ - // Amount is witdrawn from Relay Chain's `CheckAccount` + // Amount is withdrawn from Relay Chain's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, 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 52ad3241e51..e4ed77884bf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -962,7 +962,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1200,6 +1200,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1243,6 +1244,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + ParentThen(Parachain(random_para_id).into()).into(), + )) + } + } + use xcm::latest::prelude::*; use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; 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 d63c126f082..05262e07410 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 @@ -552,11 +552,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[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. @@ -586,8 +581,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs index 7d49b56e461..cdd4290770f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs @@ -18,13 +18,14 @@ //! Tests for the Statemine (Kusama Assets Hub) chain. use asset_hub_kusama_runtime::xcm_config::{ - AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation, + AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, LocationToAccountId, + TrustBackedAssetsPalletLocation, }; pub use asset_hub_kusama_runtime::{ xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig}, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, + RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use codec::{Decode, Encode}; @@ -518,12 +519,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); @@ -632,3 +627,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p assert_eq!(ForeignAssets::asset_ids().collect::>().len(), 1); }) ); + +#[test] +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< + 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, + } + }), + WeightLimit::Unlimited, + ); +} 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 57a1150bc88..6f853b6f56e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -868,7 +868,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1082,6 +1082,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1124,6 +1125,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + ParentThen(Parachain(random_para_id).into()).into(), + )) + } + } + use xcm::latest::prelude::*; use xcm_config::{DotLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; 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 6035789a1ae..b3c2ce4da76 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 @@ -476,11 +476,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[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. @@ -510,8 +505,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index 7200ebc16a2..b7e44646ece 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -19,12 +19,13 @@ use asset_hub_polkadot_runtime::xcm_config::{ AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation, - ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation, XcmConfig, + ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation, + XcmConfig, }; pub use asset_hub_polkadot_runtime::{ AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, + RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use codec::{Decode, Encode}; @@ -531,12 +532,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); @@ -657,3 +652,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p assert_eq!(ForeignAssets::asset_ids().collect::>().len(), 1); }) ); + +#[test] +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< + 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, + } + }), + WeightLimit::Unlimited, + ); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index f649ebedeff..06dcfb99a65 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1077,7 +1077,7 @@ mod benches { [pallet_xcm_bridge_hub_router, ToWestend] [pallet_xcm_bridge_hub_router, ToRococo] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1315,6 +1315,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; // This is defined once again in dispatch_benchmark, because list_benchmarks! @@ -1368,6 +1369,39 @@ impl_runtime_apis! { Config as XcmBridgeHubRouterConfig, }; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + ParentThen(Parachain(random_para_id).into()).into(), + )) + } + } + impl XcmBridgeHubRouterConfig for Runtime { fn make_congested() { cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index ff37ff74e75..b0bf9e82729 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -667,11 +667,6 @@ pub type XcmRouter = WithUniqueTopic<( 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. @@ -701,8 +696,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index c3d3c4abbbb..b4f4e828dde 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -529,12 +529,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); @@ -930,6 +924,35 @@ mod asset_hub_rococo_tests { actual ); } + + #[test] + fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< + 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, + } + }), + WeightLimit::Unlimited, + ); + } } mod asset_hub_wococo_tests { 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 f1a15265b90..d88aa2607e2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1013,7 +1013,7 @@ mod benches { [cumulus_pallet_dmp_queue, DmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1297,6 +1297,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; // This is defined once again in dispatch_benchmark, because list_benchmarks! @@ -1343,6 +1344,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + ParentThen(Parachain(random_para_id).into()).into(), + )) + } + } + use pallet_xcm_bridge_hub_router::benchmarking::{ Pallet as XcmBridgeHubRouterBench, Config as XcmBridgeHubRouterConfig, 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 ec42618513a..17312c0f46e 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 @@ -636,11 +636,6 @@ pub type XcmRouter = WithUniqueTopic<( ToRococoXcmRouter, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -666,8 +661,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index de87a98fb0b..7922b04e807 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -525,12 +525,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); @@ -815,3 +809,32 @@ fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { }, ) } + +#[test] +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< + 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, + } + }), + WeightLimit::Unlimited, + ); +} diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 471b1f09b56..872ad06ddd5 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -27,6 +27,21 @@ use std::fmt::Debug; use xcm::latest::prelude::*; use xcm_builder::{CreateMatcher, MatchXcm}; +/// Given a message, a sender, and a destination, it returns the delivery fees +fn get_fungible_delivery_fees(destination: MultiLocation, message: Xcm<()>) -> u128 { + let Ok((_, delivery_fees)) = validate_send::(destination, message) else { + unreachable!("message can be sent; qed") + }; + if let Some(delivery_fee) = delivery_fees.inner().first() { + let Fungible(delivery_fee_amount) = delivery_fee.fun else { + unreachable!("asset is fungible; qed"); + }; + delivery_fee_amount + } else { + 0 + } +} + /// Helper function to verify `xcm` contains all relevant instructions expected on destination /// chain as part of a reserve-asset-transfer. pub(crate) fn assert_matches_reserve_asset_deposited_instructions( 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 5fb34e7a571..f1cc76350a0 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -16,25 +16,28 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. use super::xcm_helpers; +use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees}; use codec::Encode; +use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ assert_noop, assert_ok, traits::{ - fungible::Mutate, fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait, + fungible::Mutate, fungibles::InspectEnumerable, Currency, Get, OnFinalize, OnInitialize, + OriginTrait, }, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::{AccountId, Balance}; use parachains_runtimes_test_utils::{ - assert_metadata, assert_total, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, - ValidatorIdOf, XcmReceivedFrom, + assert_metadata, assert_total, mock_open_hrmp_channel, AccountIdOf, BalanceOf, + CollatorSessionKeys, ExtBuilder, ValidatorIdOf, XcmReceivedFrom, }; use sp_runtime::{ traits::{MaybeEquivalence, StaticLookup, Zero}, DispatchError, Saturating, }; -use xcm::latest::prelude::*; +use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; type RuntimeHelper = @@ -43,8 +46,8 @@ type RuntimeHelper = // Re-export test_case from `parachains-runtimes-test-utils` pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; -/// Test-case makes sure that `Runtime` can receive native asset from relay chain -/// and can teleport it back and to the other parachains +/// Test-case makes sure that `Runtime` can receive native asset from relay chain and can teleport +/// it back pub fn teleports_for_native_asset_works< Runtime, AllPalletsWithoutSystem, @@ -57,9 +60,6 @@ pub fn teleports_for_native_asset_works< existential_deposit: BalanceOf, target_account: AccountIdOf, unwrap_pallet_xcm_event: Box) -> Option>>, - unwrap_xcmp_queue_event: Box< - dyn Fn(Vec) -> Option>, - >, runtime_para_id: u32, ) where Runtime: frame_system::Config @@ -164,12 +164,13 @@ pub fn teleports_for_native_asset_works< // 2. try to teleport asset back to the relaychain { let dest = MultiLocation::parent(); - let dest_beneficiary = MultiLocation::parent() + let mut dest_beneficiary = MultiLocation::parent() .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); @@ -223,65 +224,53 @@ pub fn teleports_for_native_asset_works< ); } - // 3. try to teleport asset away to other parachain (1234) + // 3. try to teleport assets away to other parachain (2345): should not work as we don't + // trust `IsTeleporter` for `(relay-native-asset, para(2345))` pair { - let other_para_id = 1234; + let other_para_id = 2345; let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); - let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); + let native_asset_to_teleport_away = native_asset_amount_unit * 3.into(); assert!( native_asset_to_teleport_away < target_account_balance_before_teleport - existential_deposit ); - - assert_ok!(RuntimeHelper::::do_teleport_assets::( - RuntimeHelper::::origin_of(target_account.clone()), - dest, - dest_beneficiary, - (native_asset_id, native_asset_to_teleport_away.into()), - Some((runtime_para_id, other_para_id)), - included_head, - &alice, - )); - - let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( - (native_asset_id, native_asset_to_teleport_away.into()).into(), - 0, - Unlimited, - dest_beneficiary, + assert_eq!( + RuntimeHelper::::do_teleport_assets::( + RuntimeHelper::::origin_of(target_account.clone()), dest, - ); + dest_beneficiary, + (native_asset_id, native_asset_to_teleport_away.into()), + Some((runtime_para_id, other_para_id)), + included_head, + &alice, + ), + Err(DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0,], + message: Some("Filtered",), + },),) + ); // check balances assert_eq!( >::free_balance(&target_account), - target_account_balance_before_teleport - - native_asset_to_teleport_away - - delivery_fees.into() + target_account_balance_before_teleport ); assert_eq!( >::free_balance(&CheckingAccount::get()), 0.into() ); - - // check events - RuntimeHelper::::assert_pallet_xcm_event_outcome( - &unwrap_pallet_xcm_event, - |outcome| { - assert_ok!(outcome.ensure_complete()); - }, - ); - assert!(RuntimeHelper::::xcmp_queue_message_sent(unwrap_xcmp_queue_event) - .is_some()); } }) } @@ -298,7 +287,6 @@ macro_rules! include_teleports_for_native_asset_works( $collator_session_key:expr, $existential_deposit:expr, $unwrap_pallet_xcm_event:expr, - $unwrap_xcmp_queue_event:expr, $runtime_para_id:expr ) => { #[test] @@ -318,15 +306,14 @@ macro_rules! include_teleports_for_native_asset_works( $existential_deposit, target_account, $unwrap_pallet_xcm_event, - $unwrap_xcmp_queue_event, $runtime_para_id ) } } ); -/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain relay -/// chain +/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain, and +/// can teleport it back pub fn teleports_for_foreign_assets_works< Runtime, AllPalletsWithoutSystem, @@ -381,7 +368,7 @@ pub fn teleports_for_foreign_assets_works< ::AccountId: From, ForeignAssetsPalletInstance: 'static, { - // foreign parachain with the same consenus currency as asset + // foreign parachain with the same consensus currency as asset let foreign_para_id = 2222; let foreign_asset_id_multilocation = MultiLocation { parents: 1, @@ -473,7 +460,7 @@ pub fn teleports_for_foreign_assets_works< >(foreign_asset_id_multilocation, 0, 0); assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance); - // 1. process received teleported assets from relaychain + // 1. process received teleported assets from sibling parachain (foreign_para_id) let xcm = Xcm(vec![ // BuyExecution with relaychain native token WithdrawAsset(buy_execution_fee.clone().into()), @@ -551,12 +538,13 @@ pub fn teleports_for_foreign_assets_works< // 2. try to teleport asset back to source parachain (foreign_para_id) { let dest = MultiLocation::new(1, X1(Parachain(foreign_para_id))); - let dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id))) + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id))) .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::balance( @@ -1108,7 +1096,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor AssetId: Clone + Copy, AssetIdConverter: MaybeEquivalence, { - // foreign parachain with the same consenus currency as asset + // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = MultiLocation { parents: 1, interior: X2(Parachain(2222), GeneralIndex(1234567)) }; let asset_id = AssetIdConverter::convert(&foreign_asset_id_multilocation).unwrap(); @@ -1388,3 +1376,199 @@ macro_rules! include_create_and_manage_foreign_assets_for_local_consensus_parach } } ); + +/// Test-case makes sure that `Runtime` can reserve-transfer asset to other parachains (where +/// teleport is not trusted) +pub fn reserve_transfer_native_asset_to_non_teleport_para_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>, + >, + weight_limit: WeightLimit, +) 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(), + ); + + // reserve-transfer native asset with local reserve to remote parachain (2345) + + let other_para_id = 2345; + let native_asset = MultiLocation::parent(); + let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) + .appended_with(AccountId32 { + network: None, + id: sp_runtime::AccountId32::new([3; 32]).into(), + }) + .unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); + + let reserve_account = LocationToAccountId::convert_location(&dest) + .expect("Sovereign account for reserves"); + let balance_to_transfer = 1_000_000_000_000_u128; + + // open HRMP to other parachain + mock_open_hrmp_channel::( + runtime_para_id.into(), + other_para_id.into(), + included_head, + &alice, + ); + + // we calculate exact delivery fees _after_ sending the message by weighing the sent + // xcm, and this delivery fee varies for different runtimes, so just add enough buffer, + // then verify the arithmetics check out on final balance. + let delivery_fees_buffer = 40_000_000_000u128; + // drip 2xED + transfer_amount + delivery_fees_buffer to Alice account + let alice_account_init_balance = existential_deposit.saturating_mul(2.into()) + + balance_to_transfer.into() + + delivery_fees_buffer.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), + }; + + // pallet_xcm call reserve transfer + assert_ok!(>::limited_reserve_transfer_assets( + RuntimeHelper::::origin_of(alice_account.clone()), + Box::new(dest.into_versioned()), + Box::new(dest_beneficiary.into_versioned()), + Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), + 0, + weight_limit, + )); + + // 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( + other_para_id.into(), + ) + .unwrap(); + + let delivery_fees = get_fungible_delivery_fees::< + ::XcmSender, + >(dest, Xcm::try_from(xcm_sent.clone()).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 Program to other parachain + println!("reserve_transfer_native_asset_works sent xcm: {:?}", xcm_sent); + let reserve_assets_deposited = MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(1000000000000), + }]); + + assert_matches_reserve_asset_deposited_instructions( + &mut xcm_sent, + &reserve_assets_deposited, + &dest_beneficiary, + ); + + // check alice account decreased by balance_to_transfer ( + delivery_fees) + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance - balance_to_transfer.into() - delivery_fees.into() + ); + + // check reserve account + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.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 index 6c8ac8c6452..851fcd5c7d6 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -16,7 +16,7 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets transferred //! over a bridge. -use crate::assert_matches_reserve_asset_deposited_instructions; +use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees}; use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ @@ -32,10 +32,7 @@ use parachains_runtimes_test_utils::{ use sp_runtime::{traits::StaticLookup, Saturating}; use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_builder::{CreateMatcher, MatchXcm}; -use xcm_executor::{ - traits::{ConvertLocation, TransactAsset}, - XcmExecutor, -}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; pub struct TestBridgingConfig { pub bridged_network: NetworkId, @@ -129,8 +126,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< &alice, ); - // drip ED to account - let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); + // we calculate exact delivery fees _after_ sending the message by weighing the sent + // xcm, and this delivery fee varies for different runtimes, so just add enough buffer, + // then verify the arithmetics check out on final balance. + let delivery_fees_buffer = 8_000_000_000_000u128; + // drip ED + transfer_amount + delivery_fees_buffer to Alice account + let alice_account_init_balance = + existential_deposit + balance_to_transfer.into() + delivery_fees_buffer.into(); let _ = >::deposit_creating( &alice_account, alice_account_init_balance, @@ -183,56 +185,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< let expected_beneficiary = target_destination_account; - // Make sure sender has enough funds for paying delivery fees - let handling_delivery_fees = { - // Probable XCM with `ReserveAssetDeposited`. - let mut expected_reserve_asset_deposited_message = Xcm(vec![ - ReserveAssetDeposited(MultiAssets::from(expected_assets.clone())), - ClearOrigin, - BuyExecution { - fees: MultiAsset { - id: Concrete(Default::default()), - fun: Fungible(balance_to_transfer), - }, - weight_limit: Unlimited, - }, - DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary }, - 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_reserve_asset_deposited_instructions( - &mut expected_reserve_asset_deposited_message, - &expected_assets, - &expected_beneficiary, - ); - - // Call `SendXcm::validate` to get delivery fees. - let (_, delivery_fees): (_, MultiAssets) = XcmConfig::XcmSender::validate( - &mut Some(target_location_from_different_consensus), - &mut Some(expected_reserve_asset_deposited_message), - ) - .expect("validate passes"); - // Drip delivery fee to Alice account. - let mut delivery_fees_added = false; - for delivery_fee in delivery_fees.inner() { - assert_ok!(::deposit_asset( - &delivery_fee, - &MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: None, - id: alice_account.clone().into(), - }), - }, - None, - )); - delivery_fees_added = true; - } - delivery_fees_added - }; - // do pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), @@ -275,6 +227,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< // check sent XCM ExportMessage to BridgeHub + let mut delivery_fees = 0; // 1. check paid or unpaid if let Some(expected_fee_asset_id) = maybe_paid_export_message { xcm_sent @@ -315,6 +268,10 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< .split_global() .expect("split works"); assert_eq!(destination, &target_location_junctions_without_global_consensus); + // Call `SendXcm::validate` to get delivery fees. + delivery_fees = get_fungible_delivery_fees::< + ::XcmSender, + >(target_location_from_different_consensus, inner_xcm.clone()); assert_matches_reserve_asset_deposited_instructions( inner_xcm, &expected_assets, @@ -330,8 +287,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< assert_eq!( >::free_balance(&alice_account), alice_account_init_balance - .saturating_sub(existential_deposit) .saturating_sub(balance_to_transfer.into()) + .saturating_sub(delivery_fees.into()) ); // check reserve account increased by balance_to_transfer @@ -341,14 +298,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< ); // check dedicated account increased by delivery fees (if configured) - if handling_delivery_fees { - if let Some(delivery_fees_account) = delivery_fees_account { - let delivery_fees_account_balance_after = - >::free_balance(&delivery_fees_account); - assert!( - delivery_fees_account_balance_after > delivery_fees_account_balance_before - ); - } + if let Some(delivery_fees_account) = delivery_fees_account { + let delivery_fees_account_balance_after = + >::free_balance(&delivery_fees_account); + assert!( + delivery_fees_account_balance_after - delivery_fees.into() >= + delivery_fees_account_balance_before + ); } }) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index 9bd6557f350..b2a14a0405d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -270,7 +270,7 @@ cd ### Send messages - transfer asset over bridge (ROCs/WNDs) -Do (asset) transfers: +Do reserve-backed transfers: ``` cd @@ -291,6 +291,20 @@ cd - AssetHubWestend (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer - BridgeHubRocococ (see `bridgeWestendMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer +Do reserve withdraw transfers: (when previous is finished) +``` +cd + +# wrappedWNDs from Rococo's Asset Hub to Westend's. +./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-rococo-local +``` +``` +cd + +# wrappedROCs from Westend's Asset Hub to Rococo's. +./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-westend-local +``` + ### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend **Accounts of BridgeHub parachains:** 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 bd95ec3fda7..b3750700084 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 @@ -490,7 +490,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -670,6 +670,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -705,6 +706,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::KsmRelayLocation; 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 727735c9285..b3703eee830 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 @@ -241,11 +241,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[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. @@ -274,8 +269,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs index 893524e12f6..36d8f0846af 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1002 ); 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 4744dc08e8e..841bb4ee861 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 @@ -491,7 +491,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -671,6 +671,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -706,6 +707,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::DotRelayLocation; 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 ac7e00fc427..61eee1c4c5a 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 @@ -245,11 +245,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[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. @@ -278,8 +273,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs index 0be87bd46fa..3156a5fe68e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1002 ); 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 e5d38bcac23..b17d308b891 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 @@ -595,7 +595,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -933,6 +933,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -980,6 +981,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::TokenLocation; 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 d98012e061b..1b1e6f8ba71 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 @@ -349,11 +349,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -381,8 +376,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); 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 65cca67dac1..39ee2576f5b 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 @@ -133,12 +133,6 @@ mod bridge_hub_rococo_tests { _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID ); @@ -517,12 +511,6 @@ mod bridge_hub_wococo_tests { _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 458876ce46c..9e8fd84e712 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -544,7 +544,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -772,6 +772,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -813,6 +814,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::WestendLocation; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index a6abca42215..7084882c41f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -284,11 +284,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -316,8 +311,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 16dcd10a2ca..4d477e1413e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -118,12 +118,6 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID ); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index b7bfc9f9c6a..206f4614060 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -751,7 +751,7 @@ mod benches { [cumulus_pallet_dmp_queue, DmpQueue] [pallet_alliance, Alliance] [pallet_collective, AllianceMotion] - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] [pallet_preimage, Preimage] [pallet_scheduler, Scheduler] [pallet_referenda, FellowshipReferenda] @@ -939,6 +939,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -968,6 +969,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between Collectives and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on Collectives. + None + } + } + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), 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 c0b3108d2fb..71845650bd6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -293,11 +293,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - /// Type to convert the Fellows origin to a Plurality `MultiLocation` value. pub type FellowsToPlurality = OriginToPluralityVoice; @@ -325,8 +320,6 @@ impl pallet_xcm::Config for Runtime { 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 = (); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index e41db7d9213..2a2f4141033 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -433,7 +433,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [pallet_contracts, Contracts] - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] ); } @@ -678,6 +678,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -707,6 +708,30 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use xcm::latest::prelude::*; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between Contracts-System-Para and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on Contracts-System-Para. + None + } + } + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), 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 4c9f357e111..faee1c68fe6 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -227,11 +227,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[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. @@ -258,8 +253,6 @@ impl pallet_xcm::Config for Runtime { type MaxLockers = ConstU32<8>; // FIXME: Replace with benchmarked weight info type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 5ef9af7c712..1ddad31920a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -434,7 +434,7 @@ parameter_types! { // pub type AssetsForceOrigin = // EnsureOneOf, EnsureXcm>>; -impl pallet_assets::Config for Runtime { +impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = AssetId; @@ -577,7 +577,12 @@ impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, + pallet_assets::BalanceToAssetBalance< + Balances, + Runtime, + ConvertInto, + pallet_assets::Instance1, + >, AssetsToBlockAuthor, >; } @@ -619,7 +624,7 @@ construct_runtime!( MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // The main stage. - Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, + Assets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 710dfd79877..74d9a0b071d 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -38,6 +38,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_asset_tx_payment::HandleCredit; +use pallet_assets::Instance1; use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; @@ -48,9 +49,10 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -126,6 +128,9 @@ pub type XcmOriginToTransactDispatchOrigin = ( // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when // recognized. 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, @@ -182,14 +187,25 @@ pub type Barrier = TrailingSetTopicAsId< /// Type alias to conveniently refer to `frame_system`'s `Config::AccountId`. pub type AccountIdOf = ::AccountId; -/// Asset filter that allows all assets from a certain location. +/// Asset filter that allows all assets from a certain location matching asset id. pub struct AssetsFrom(PhantomData); impl> ContainsPair for AssetsFrom { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { let loc = T::get(); &loc == origin && matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } - if asset_loc.match_and_split(&loc).is_some()) + if asset_loc.starts_with(&loc)) + } +} + +/// Asset filter that allows native/relay asset if coming from a certain location. +pub struct NativeAssetFrom(PhantomData); +impl> ContainsPair for NativeAssetFrom { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + let loc = T::get(); + &loc == origin && + matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } + if *asset_loc == MultiLocation::from(Parent)) } } @@ -208,56 +224,19 @@ where /// A `HandleCredit` implementation that naively transfers the fees to the block author. /// Will drop and burn the assets in case the transfer fails. pub struct AssetsToBlockAuthor(PhantomData); -impl HandleCredit, pallet_assets::Pallet> for AssetsToBlockAuthor +impl HandleCredit, pallet_assets::Pallet> for AssetsToBlockAuthor where - R: pallet_authorship::Config + pallet_assets::Config, + R: pallet_authorship::Config + pallet_assets::Config, AccountIdOf: From + Into, { - fn handle_credit(credit: Credit, pallet_assets::Pallet>) { + fn handle_credit(credit: Credit, pallet_assets::Pallet>) { if let Some(author) = pallet_authorship::Pallet::::author() { // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. - let _ = pallet_assets::Pallet::::resolve(&author, credit); + let _ = pallet_assets::Pallet::::resolve(&author, credit); } } } -pub trait Reserve { - /// Returns assets reserve location. - fn reserve(&self) -> Option; -} - -// Takes the chain part of a MultiAsset -impl Reserve for MultiAsset { - fn reserve(&self) -> Option { - if let AssetId::Concrete(location) = self.id { - let first_interior = location.first_interior(); - let parents = location.parent_count(); - match (parents, first_interior) { - (0, Some(Parachain(id))) => Some(MultiLocation::new(0, X1(Parachain(*id)))), - (1, Some(Parachain(id))) => Some(MultiLocation::new(1, X1(Parachain(*id)))), - (1, _) => Some(MultiLocation::parent()), - _ => None, - } - } else { - None - } - } -} - -/// A `FilterAssetLocation` implementation. Filters multi native assets whose -/// reserve is same with `origin`. -pub struct MultiNativeAsset; -impl ContainsPair for MultiNativeAsset { - fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { - if let Some(ref reserve) = asset.reserve() { - if reserve == origin { - return true - } - } - false - } -} - parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); @@ -268,7 +247,8 @@ parameter_types! { pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } -pub type Reserves = (NativeAsset, AssetsFrom); +pub type Reserves = + (NativeAsset, AssetsFrom, NativeAssetFrom); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { @@ -277,7 +257,8 @@ impl xcm_executor::Config for XcmConfig { // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = MultiNativeAsset; // TODO: maybe needed to be replaced by Reserves + type IsReserve = Reserves; + // no teleport trust established with other chains type IsTeleporter = NativeAsset; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -312,11 +293,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -342,8 +318,6 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 4cb83ccf820..6df00d43e8d 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -492,11 +492,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -518,8 +513,6 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh index ce8480685aa..82b5f1942b2 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -301,9 +301,21 @@ case "$1" in 0 \ "Unlimited" ;; + withdraw-reserve-assets-from-asset-hub-rococo-local) + ensure_polkadot_js_api + # send back only 100000000000 wrappedWNDs to Alice account on AHW + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": 140000000000 } } ] }')" \ + 0 \ + "Unlimited" + ;; reserve-transfer-assets-from-asset-hub-westend-local) ensure_polkadot_js_api - # send WOCs to Alice account on AHR + # send WNDs to Alice account on AHR limited_reserve_transfer_assets \ "ws://127.0.0.1:9010" \ "//Alice" \ @@ -313,6 +325,18 @@ case "$1" in 0 \ "Unlimited" ;; + withdraw-reserve-assets-from-asset-hub-westend-local) + ensure_polkadot_js_api + # send back only 100000000000 wrappedROCs 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": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": 100000000000 } } ] }')" \ + 0 \ + "Unlimited" + ;; claim-rewards-bridge-hub-rococo-local) ensure_polkadot_js_api # bhwd -> [62, 68, 77, 64] -> 0x62687764 @@ -360,7 +384,9 @@ case "$1" in - init-asset-hub-westend-local - init-bridge-hub-westend-local - reserve-transfer-assets-from-asset-hub-rococo-local + - withdraw-reserve-assets-from-asset-hub-rococo-local - reserve-transfer-assets-from-asset-hub-westend-local + - withdraw-reserve-assets-from-asset-hub-westend-local - claim-rewards-bridge-hub-rococo-local - claim-rewards-bridge-hub-westend-local"; exit 1 diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 7ff5512d214..f2e4ff397c4 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1443,9 +1443,9 @@ pub struct TestContext { /// These arguments can be easily reused and shared between the assertion functions /// and dispatchable functions, which are also stored in `Test`. /// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. -/// `Destination` corresponds to the last chain where an effect of the intial execution is expected -/// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke -/// some effect. +/// `Destination` corresponds to the last chain where an effect of the initial execution is expected +/// to happen. `Hops` refer to all the ordered intermediary chains an initial XCM execution can +/// provoke some effect on. #[derive(Clone)] pub struct Test where @@ -1499,7 +1499,7 @@ where let chain_name = std::any::type_name::(); self.hops_assertion.insert(chain_name.to_string(), assertion); } - /// Stores an assertion in a particular Chain + /// Stores a dispatchable in a particular Chain pub fn set_dispatchable(&mut self, dispatchable: fn(Self) -> DispatchResult) { let chain_name = std::any::type_name::(); self.hops_dispatchable.insert(chain_name.to_string(), dispatchable); diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index cd73d23bdad..ef9dfedd735 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -2064,7 +2064,7 @@ impl Pallet { } /// Submits a given PVF check statement with corresponding signature as an unsigned transaction - /// into the memory pool. Ultimately, that disseminates the transaction accross the network. + /// into the memory pool. Ultimately, that disseminates the transaction across the network. /// /// This function expects an offchain context and cannot be callable from the on-chain logic. /// diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 57767b70d23..40ef22107a7 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1588,7 +1588,7 @@ mod benches { [pallet_asset_rate, AssetRate] [pallet_whitelist, Whitelist] // XCM - [pallet_xcm, XcmPallet] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::] ); @@ -2064,6 +2064,8 @@ sp_api::impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -2081,6 +2083,7 @@ sp_api::impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use sp_storage::TrackedStorageKey; use xcm::latest::prelude::*; use xcm_config::{ @@ -2097,6 +2100,33 @@ sp_api::impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {} + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(crate::xcm_config::AssetHub::get()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported to/from AH. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }, + crate::xcm_config::AssetHub::get(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay can reserve transfer native token to some random parachain. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }, + Parachain(43211234).into(), + )) + } + } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = XcmConfig; type AccountIdConverter = LocationConverter; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 0814b77414f..c8f8f59dae9 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -211,11 +211,6 @@ parameter_types! { pub const FellowsBodyId: BodyId = BodyId::Technical; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); -} - /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( @@ -269,7 +264,5 @@ impl pallet_xcm::Config for Runtime { 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/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index 400658b1386..ae4faecf700 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -127,11 +127,6 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(xcm::latest::Junctions::Here.into()); -} - impl pallet_xcm::Config for crate::Runtime { // The config types here are entirely configurable, since the only one that is sorely needed // is `XcmExecutor`, which will be used in unit tests located in xcm-executor. @@ -157,7 +152,5 @@ impl pallet_xcm::Config for crate::Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 1c97e54da48..d80640c016f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1626,7 +1626,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_asset_rate, AssetRate] // XCM - [pallet_xcm, XcmPallet] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -2145,6 +2145,7 @@ sp_api::impl_runtime_apis! { 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_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -2172,12 +2173,37 @@ sp_api::impl_runtime_apis! { 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_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} impl pallet_election_provider_support_benchmarking::Config for Runtime {} + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(crate::xcm_config::AssetHub::get()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported to/from AH. + Some(( + MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }, + crate::xcm_config::AssetHub::get(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay can reserve transfer native token to some random parachain. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }, + crate::Junction::Parachain(43211234).into(), + )) + } + } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 64e07317fc7..9ab6470f6da 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -119,11 +119,6 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); -} - pub type TrustedTeleporters = ( xcm_builder::Case, xcm_builder::Case, @@ -265,7 +260,5 @@ impl pallet_xcm::Config for Runtime { 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/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 6b5d5e75de8..cc5d7d97c45 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -13,7 +13,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} sp-core = { path = "../../../substrate/primitives/core", default-features = false} @@ -25,8 +24,12 @@ xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } +# marked optional, used in benchmarking +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false, optional = true } + [dev-dependencies] -pallet-balances = { path = "../../../substrate/frame/balances" } +pallet-assets = { path = "../../../substrate/frame/assets" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } @@ -39,6 +42,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "scale-info/std", "serde", "sp-core/std", @@ -53,6 +57,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", @@ -63,6 +68,7 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-assets/try-runtime", "pallet-balances/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index 3eecbfec518..3aca24791fc 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -16,15 +16,56 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; -use frame_benchmarking::{benchmarks, BenchmarkError, BenchmarkResult}; -use frame_support::weights::Weight; +use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; +use frame_support::{traits::Currency, weights::Weight}; use frame_system::RawOrigin; use sp_std::prelude::*; use xcm::{latest::prelude::*, v2}; type RuntimeOrigin = ::RuntimeOrigin; +// existential deposit multiplier +const ED_MULTIPLIER: u32 = 100; + +/// Pallet we're benchmarking here. +pub struct Pallet(crate::Pallet); + +/// Trait that must be implemented by runtime to be able to benchmark pallet properly. +pub trait Config: crate::Config { + /// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks. + /// + /// If `None`, the benchmarks that depend on a reachable destination will be skipped. + fn reachable_dest() -> Option { + None + } + + /// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be + /// teleported to. Used only in benchmarks. + /// + /// Implementation should also make sure `dest` is reachable/connected. + /// + /// If `None`, the benchmarks that depend on this will be skipped. + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + None + } + + /// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be + /// reserve-transferred to. Used only in benchmarks. + /// + /// Implementation should also make sure `dest` is reachable/connected. + /// + /// If `None`, the benchmarks that depend on this will be skipped. + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + None + } +} + benchmarks! { + where_clause { + where + T: pallet_balances::Config, + ::Balance: From + Into, + } send { let send_origin = T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -32,7 +73,7 @@ benchmarks! { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let msg = Xcm(vec![ClearOrigin]); - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( + let versioned_dest: VersionedMultiLocation = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )? .into(); @@ -40,44 +81,82 @@ benchmarks! { }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) teleport_assets { - let asset: MultiAsset = (Here, 10).into(); - let send_origin = - T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) + let (asset, destination) = T::teleportable_asset_and_dest().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )?; + + let transferred_amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), + }.into(); + let assets: MultiAssets = asset.into(); + + let existential_deposit = T::ExistentialDeposit::get(); + let caller = whitelisted_caller(); + + // Give some multiple of the existential deposit + let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + assert!(balance >= transferred_amount); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + // verify initial balance + assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); + + let send_origin = RawOrigin::Signed(caller.clone()); + let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmTeleportFilter::contains(&(origin_location, vec![asset.clone()])) { + if !T::XcmTeleportFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let recipient = [0u8; 32]; - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); + let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = asset.into(); - }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + let versioned_assets: VersionedMultiAssets = assets.into(); + }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + verify { + // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) + assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); + } reserve_transfer_assets { - let asset: MultiAsset = (Here, 10).into(); - let send_origin = - T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) + let (asset, destination) = T::reserve_transferable_asset_and_dest().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )?; + + let transferred_amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), + }.into(); + let assets: MultiAssets = asset.into(); + + let existential_deposit = T::ExistentialDeposit::get(); + let caller = whitelisted_caller(); + + // Give some multiple of the existential deposit + let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + assert!(balance >= transferred_amount); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + // verify initial balance + assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); + + let send_origin = RawOrigin::Signed(caller.clone()); + let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmReserveTransferFilter::contains(&(origin_location, vec![asset.clone()])) { + if !T::XcmReserveTransferFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let recipient = [0u8; 32]; - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); + let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = asset.into(); - }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + let versioned_assets: VersionedMultiAssets = assets.into(); + }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + verify { + // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) + assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); + } execute { let execute_origin = @@ -92,7 +171,7 @@ benchmarks! { }: _>(execute_origin, Box::new(versioned_msg), Weight::zero()) force_xcm_version { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; let xcm_version = 2; @@ -101,18 +180,18 @@ benchmarks! { force_default_xcm_version {}: _(RawOrigin::Root, Some(2)) force_subscribe_version_notify { - let versioned_loc: VersionedMultiLocation = T::ReachableDest::get().ok_or( + let versioned_loc: VersionedMultiLocation = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )? .into(); }: _(RawOrigin::Root, Box::new(versioned_loc)) force_unsubscribe_version_notify { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; let versioned_loc: VersionedMultiLocation = loc.into(); - let _ = Pallet::::request_version_notify(loc); + let _ = crate::Pallet::::request_version_notify(loc); }: _(RawOrigin::Root, Box::new(versioned_loc)) force_suspension {}: _(RawOrigin::Root, true) @@ -122,7 +201,7 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); SupportedVersion::::insert(old_version, loc, old_version); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); } migrate_version_notifiers { @@ -130,22 +209,22 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); VersionNotifiers::::insert(old_version, loc, 0); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); } already_notified_target { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))), )?; let loc = VersionedMultiLocation::from(loc); let current_version = T::AdvertisedXcmVersion::get(); VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); } notify_current_targets { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), )?; let loc = VersionedMultiLocation::from(loc); @@ -153,7 +232,7 @@ benchmarks! { let old_version = current_version - 1; VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), old_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); } notify_target_migration_fail { @@ -167,7 +246,7 @@ benchmarks! { let current_version = T::AdvertisedXcmVersion::get(); VersionNotifyTargets::::insert(current_version, bad_loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } migrate_version_notify_targets { @@ -176,18 +255,18 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } migrate_and_notify_old_targets { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), )?; let loc = VersionedMultiLocation::from(loc); let old_version = T::AdvertisedXcmVersion::get() - 1; VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), old_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } new_query { @@ -195,14 +274,14 @@ benchmarks! { let timeout = 1u32.into(); let match_querier = MultiLocation::from(Here); }: { - Pallet::::new_query(responder, timeout, match_querier); + crate::Pallet::::new_query(responder, timeout, match_querier); } take_response { let responder = MultiLocation::from(Parent); let timeout = 1u32.into(); let match_querier = MultiLocation::from(Here); - let query_id = Pallet::::new_query(responder, timeout, match_querier); + let query_id = crate::Pallet::::new_query(responder, timeout, match_querier); let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new( u32::MAX, (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), @@ -211,10 +290,10 @@ benchmarks! { u32::MAX, u32::MAX, ).unwrap()).collect::>(); - Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); + crate::Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); }: { - as QueryHandler>::take_response(query_id); + as QueryHandler>::take_response(query_id); } impl_benchmark_test_suite!( diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 2d969fb870c..8157620465f 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -19,7 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "runtime-benchmarks")] -mod benchmarking; +pub mod benchmarking; #[cfg(test)] mod mock; #[cfg(test)] @@ -55,9 +55,9 @@ use xcm_builder::{ }; use xcm_executor::{ traits::{ - CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, DropAssets, MatchesFungible, - OnResponse, Properties, QueryHandler, QueryResponseStatus, VersionChangeNotifier, - WeightBounds, + AssetTransferError, CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, + DropAssets, MatchesFungible, OnResponse, Properties, QueryHandler, QueryResponseStatus, + TransactAsset, TransferType, VersionChangeNotifier, WeightBounds, XcmAssetTransfers, }, Assets, }; @@ -222,7 +222,7 @@ pub mod pallet { type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall>; + type XcmExecutor: ExecuteXcm<::RuntimeCall> + XcmAssetTransfers; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; @@ -275,12 +275,6 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - /// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks. - /// - /// If `None`, the benchmarks that depend on a reachable destination will be skipped. - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest: Get>; } impl ExecuteControllerWeightInfo for Pallet { @@ -531,8 +525,8 @@ pub mod pallet { NoSubscription, /// The location is invalid since it already has a subscription from us. AlreadySubscribed, - /// Invalid asset for the operation. - InvalidAsset, + /// Could not check-out the assets for teleportation to the destination chain. + CannotCheckOutTeleport, /// The owner does not own (all) of the asset that they wish to do the operation on. LowBalance, /// The asset owner has too many locks on the asset. @@ -545,6 +539,16 @@ pub mod pallet { LockNotFound, /// The unlock operation cannot succeed because there are still consumers of the lock. InUse, + /// Invalid non-concrete asset. + InvalidAssetNotConcrete, + /// Invalid asset, reserve chain could not be determined for it. + InvalidAssetUnknownReserve, + /// Invalid asset, do not support remote asset reserves with different fees reserves. + InvalidAssetUnsupportedReserve, + /// Too many assets with different reserve locations have been attempted for transfer. + TooManyReserves, + /// Local XCM execution of asset transfer incomplete. + LocalExecutionIncomplete, } impl From for Error { @@ -557,6 +561,15 @@ pub mod pallet { } } + impl From for Error { + fn from(e: AssetTransferError) -> Self { + match e { + AssetTransferError::NotConcrete => Error::::InvalidAssetNotConcrete, + AssetTransferError::UnknownReserve => Error::::InvalidAssetUnknownReserve, + } + } + } + /// The status of a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum QueryStatus { @@ -907,11 +920,7 @@ pub mod pallet { let mut message = Xcm(vec![ WithdrawAsset(assets), SetFeesMode { jit_withdraw: true }, - InitiateTeleport { - assets: Wild(AllCounted(count)), - dest, - xcm: Xcm(vec![]), - }, + InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, ]); T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) } @@ -954,6 +963,8 @@ pub mod pallet { match (maybe_assets, maybe_dest) { (Ok(assets), Ok(dest)) => { use sp_std::vec; + // heaviest version of locally executed XCM program: equivalent in weight to + // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM let mut message = Xcm(vec![ SetFeesMode { jit_withdraw: true }, TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } @@ -1114,6 +1125,8 @@ pub mod pallet { match (maybe_assets, maybe_dest) { (Ok(assets), Ok(dest)) => { use sp_std::vec; + // heaviest version of locally executed XCM program: equivalent in weight to + // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM let mut message = Xcm(vec![ SetFeesMode { jit_withdraw: true }, TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } @@ -1273,6 +1286,33 @@ impl QueryHandler for Pallet { } impl Pallet { + /// Validate `assets` to be reserve-transferred and return their reserve location. + fn validate_assets_and_find_reserve( + assets: &[MultiAsset], + dest: &MultiLocation, + ) -> Result> { + let mut reserve = None; + for asset in assets.iter() { + if let Fungible(x) = asset.fun { + // If fungible asset, ensure non-zero amount. + ensure!(!x.is_zero(), Error::::Empty); + } + let transfer_type = + T::XcmExecutor::determine_for(&asset, dest).map_err(Error::::from)?; + // Ensure asset is not teleportable to `dest`. + ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); + if let Some(reserve) = reserve.as_ref() { + // Ensure transfer for multiple assets uses same reserve location (only fee may have + // different reserve location) + ensure!(reserve == &transfer_type, Error::::TooManyReserves); + } else { + // asset reserve identified + reserve = Some(transfer_type); + } + } + reserve.ok_or(Error::::Empty) + } + fn do_reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1286,35 +1326,75 @@ impl Pallet { let beneficiary: MultiLocation = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + log::trace!( + target: "xcm::pallet_xcm::do_reserve_transfer_assets", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}", + origin_location, dest, beneficiary, assets, fee_asset_item, + ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let value = (origin_location, assets.into_inner()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); - let (origin_location, assets) = value; - let context = T::UniversalLocation::get(); - let fees = assets - .get(fee_asset_item as usize) - .ok_or(Error::::Empty)? - .clone() - .reanchored(&dest, context) - .map_err(|_| Error::::CannotReanchor)?; - let max_assets = assets.len() as u32; - let assets: MultiAssets = assets.into(); - let xcm = Xcm(vec![ - BuyExecution { fees, weight_limit }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ]); - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm }, - ]); - let weight = - T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let outcome = - T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); - Self::deposit_event(Event::Attempted { outcome }); - Ok(()) + let (origin_location, mut assets) = value; + + if fee_asset_item as usize >= assets.len() { + return Err(Error::::Empty.into()) + } + let fees = assets.swap_remove(fee_asset_item as usize); + let fees_transfer_type = + T::XcmExecutor::determine_for(&fees, &dest).map_err(Error::::from)?; + let assets_transfer_type = if assets.is_empty() { + // Single asset to transfer (one used for fees where transfer type is determined above). + ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); + fees_transfer_type + } else { + // Find reserve for non-fee assets. + Self::validate_assets_and_find_reserve(&assets, &dest)? + }; + + // local and remote XCM programs to potentially handle fees separately + let separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; + if fees_transfer_type == assets_transfer_type { + // Same reserve location (fees not teleportable), we can batch together fees and assets + // in same reserve-based-transfer. + assets.push(fees.clone()); + // no need for custom fees instructions, fees are batched with assets + separate_fees_instructions = None; + } else { + // Disallow _remote reserves_ unless assets & fees have same remote reserve (covered by + // branch above). The reason for this is that we'd need to send XCMs to separate chains + // with no guarantee of delivery order on final destination; therefore we cannot + // guarantee to have fees in place on final destination chain to pay for assets + // transfer. + ensure!( + !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), + Error::::InvalidAssetUnsupportedReserve + ); + let fees = fees.clone(); + let weight_limit = weight_limit.clone(); + // build fees transfer instructions to be added to assets transfers XCM programs + separate_fees_instructions = Some(match fees_transfer_type { + TransferType::LocalReserve => + Self::local_reserve_fees_instructions(dest, fees, weight_limit)?, + TransferType::DestinationReserve => + Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?, + TransferType::Teleport => + Self::teleport_fees_instructions(dest, fees, weight_limit)?, + TransferType::RemoteReserve(_) => + return Err(Error::::InvalidAssetUnsupportedReserve.into()), + }); + }; + + Self::build_and_execute_xcm_transfer_type( + origin_location, + dest, + beneficiary, + assets, + assets_transfer_type, + fees, + separate_fees_instructions, + weight_limit, + ) } fn do_teleport_assets( @@ -1335,31 +1415,384 @@ impl Pallet { let value = (origin_location, assets.into_inner()); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); let (origin_location, assets) = value; + for asset in assets.iter() { + let transfer_type = + T::XcmExecutor::determine_for(asset, &dest).map_err(Error::::from)?; + ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); + } + let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); + + Self::build_and_execute_xcm_transfer_type( + origin_location, + dest, + beneficiary, + assets, + TransferType::Teleport, + fees, + None, + weight_limit, + ) + } + + fn build_and_execute_xcm_transfer_type( + origin: MultiLocation, + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + transfer_type: TransferType, + fees: MultiAsset, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + weight_limit: WeightLimit, + ) -> DispatchResult { + log::trace!( + target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ + fees {:?}, fees_xcm: {:?}, weight_limit: {:?}", + origin, dest, beneficiary, assets, transfer_type, fees, separate_fees_instructions, weight_limit, + ); + let (mut local_xcm, remote_xcm) = match transfer_type { + TransferType::LocalReserve => { + let (local, remote) = Self::local_reserve_transfer_programs( + dest, + beneficiary, + assets, + fees, + separate_fees_instructions, + weight_limit, + )?; + (local, Some(remote)) + }, + TransferType::DestinationReserve => { + let (local, remote) = Self::destination_reserve_transfer_programs( + dest, + beneficiary, + assets, + fees, + separate_fees_instructions, + weight_limit, + )?; + (local, Some(remote)) + }, + TransferType::RemoteReserve(reserve) => ( + Self::remote_reserve_transfer_program( + reserve, + dest, + beneficiary, + assets, + fees, + weight_limit, + )?, + None, + ), + TransferType::Teleport => ( + Self::teleport_assets_program(dest, beneficiary, assets, fees, weight_limit)?, + None, + ), + }; + let weight = + T::Weigher::weight(&mut local_xcm).map_err(|()| Error::::UnweighableMessage)?; + let hash = local_xcm.using_encoded(sp_io::hashing::blake2_256); + let outcome = + T::XcmExecutor::execute_xcm_in_credit(origin, local_xcm, hash, weight, weight); + Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); + if let Some(remote_xcm) = remote_xcm { + outcome.ensure_complete().map_err(|_| Error::::LocalExecutionIncomplete)?; + + let (ticket, price) = validate_send::(dest, remote_xcm.clone()) + .map_err(Error::::from)?; + if origin != Here.into_location() { + Self::charge_fees(origin, price).map_err(|_| Error::::FeesNotMet)?; + } + let message_id = T::XcmRouter::deliver(ticket).map_err(Error::::from)?; + + let e = Event::Sent { origin, destination: dest, message: remote_xcm, message_id }; + Self::deposit_event(e); + } + Ok(()) + } + + fn local_reserve_fees_instructions( + dest: MultiLocation, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let context = T::UniversalLocation::get(); - let fees = assets - .get(fee_asset_item as usize) - .ok_or(Error::::Empty)? + let reanchored_fees = fees .clone() .reanchored(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let max_assets = assets.len() as u32; + + let local_execute_xcm = Xcm(vec![ + // move `fees` to `dest`s local sovereign account + TransferAsset { assets: fees.into(), beneficiary: dest }, + ]); + let xcm_on_dest = Xcm(vec![ + // let (dest) chain know `fees` are in its SA on reserve + ReserveAssetDeposited(reanchored_fees.clone().into()), + // buy exec using `fees` in holding deposited in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + + fn local_reserve_transfer_programs( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + weight_limit: WeightLimit, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + // max assets is `assets` (+ potentially separately handled fee) + let max_assets = + assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); + let assets: MultiAssets = assets.into(); + let context = T::UniversalLocation::get(); + let mut reanchored_assets = assets.clone(); + reanchored_assets + .reanchor(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + // fees are either handled through dedicated instructions, or batched together with assets + let fees_already_handled = separate_fees_instructions.is_some(); + let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions + .map(|(local, remote)| (local.into_inner(), remote.into_inner())) + .unwrap_or_default(); + + // start off with any necessary local fees specific instructions + let mut local_execute_xcm = fees_local_xcm; + // move `assets` to `dest`s local sovereign account + local_execute_xcm.push(TransferAsset { assets, beneficiary: dest }); + + // on destination chain, start off with custom fee instructions + let mut xcm_on_dest = fees_remote_xcm; + // continue with rest of assets + xcm_on_dest.extend_from_slice(&[ + // let (dest) chain know assets are in its SA on reserve + ReserveAssetDeposited(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + ]); + if !fees_already_handled { + // no custom fees instructions, they are batched together with `assets` transfer; + // BuyExecution happens after receiving all `assets` + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // buy execution using `fees` batched together with above `reanchored_assets` + xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); + } + // deposit all remaining assets in holding to `beneficiary` location + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) + } + + fn destination_reserve_fees_instructions( + dest: MultiLocation, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let context = T::UniversalLocation::get(); + let reanchored_fees = fees + .clone() + .reanchored(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + let fees: MultiAssets = fees.into(); + + let local_execute_xcm = Xcm(vec![ + // withdraw reserve-based fees (derivatives) + WithdrawAsset(fees.clone()), + // burn derivatives + BurnAsset(fees), + ]); + let xcm_on_dest = Xcm(vec![ + // withdraw `fees` from origin chain's sovereign account + WithdrawAsset(reanchored_fees.clone().into()), + // buy exec using `fees` in holding withdrawn in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + + fn destination_reserve_transfer_programs( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + weight_limit: WeightLimit, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + // max assets is `assets` (+ potentially separately handled fee) + let max_assets = + assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); let assets: MultiAssets = assets.into(); - let xcm = Xcm(vec![ + let context = T::UniversalLocation::get(); + let mut reanchored_assets = assets.clone(); + reanchored_assets + .reanchor(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + // fees are either handled through dedicated instructions, or batched together with assets + let fees_already_handled = separate_fees_instructions.is_some(); + let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions + .map(|(local, remote)| (local.into_inner(), remote.into_inner())) + .unwrap_or_default(); + + // start off with any necessary local fees specific instructions + let mut local_execute_xcm = fees_local_xcm; + // continue with rest of assets + local_execute_xcm.extend_from_slice(&[ + // withdraw reserve-based assets + WithdrawAsset(assets.clone()), + // burn reserve-based assets + BurnAsset(assets), + ]); + + // on destination chain, start off with custom fee instructions + let mut xcm_on_dest = fees_remote_xcm; + // continue with rest of assets + xcm_on_dest.extend_from_slice(&[ + // withdraw `assets` from origin chain's sovereign account + WithdrawAsset(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + ]); + if !fees_already_handled { + // no custom fees instructions, they are batched together with `assets` transfer; + // BuyExecution happens after receiving all `assets` + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // buy execution using `fees` batched together with above `reanchored_assets` + xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); + } + // deposit all remaining assets in holding to `beneficiary` location + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) + } + + // function assumes fees and assets have the same remote reserve + fn remote_reserve_transfer_program( + reserve: MultiLocation, + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result::RuntimeCall>, Error> { + let max_assets = assets.len() as u32; + let context = T::UniversalLocation::get(); + // we spend up to half of fees for execution on reserve and other half for execution on + // destination + let (fees_half_1, fees_half_2) = Self::halve_fees(fees)?; + // identifies fee item as seen by `reserve` - to be used at reserve chain + let reserve_fees = fees_half_1 + .reanchored(&reserve, context) + .map_err(|_| Error::::CannotReanchor)?; + // identifies fee item as seen by `dest` - to be used at destination chain + let dest_fees = + fees_half_2.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // identifies `dest` as seen by `reserve` + let dest = dest.reanchored(&reserve, context).map_err(|_| Error::::CannotReanchor)?; + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }, + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ]); + // xcm to be executed on reserve + let xcm_on_reserve = Xcm(vec![ + BuyExecution { fees: reserve_fees, weight_limit }, + DepositReserveAsset { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, + ]); + Ok(Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(AllCounted(max_assets)), + reserve, + xcm: xcm_on_reserve, + }, + ])) + } + + fn teleport_fees_instructions( + dest: MultiLocation, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let context = T::UniversalLocation::get(); + let reanchored_fees = fees + .clone() + .reanchored(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + // XcmContext irrelevant in teleports checks + let dummy_context = + XcmContext { origin: None, message_id: Default::default(), topic: None }; + // We should check that the asset can actually be teleported out (for this to + // be in error, there would need to be an accounting violation by ourselves, + // so it's unlikely, but we don't want to allow that kind of bug to leak into + // a trusted chain. + ::AssetTransactor::can_check_out( + &dest, + &fees, + &dummy_context, + ) + .map_err(|_| Error::::CannotCheckOutTeleport)?; + ::AssetTransactor::check_out( + &dest, + &fees, + &dummy_context, + ); + + let fees: MultiAssets = fees.into(); + let local_execute_xcm = Xcm(vec![ + // withdraw fees + WithdrawAsset(fees.clone()), + // burn fees + BurnAsset(fees), + ]); + let xcm_on_dest = Xcm(vec![ + // (dest) chain receive teleported assets burned on origin chain + ReceiveTeleportedAsset(reanchored_fees.clone().into()), + // buy exec using `fees` in holding received in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + + fn teleport_assets_program( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + mut fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result::RuntimeCall>, Error> { + let context = T::UniversalLocation::get(); + fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; + let max_assets = assets.len() as u32; + let xcm_on_dest = Xcm(vec![ BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ]); - let mut message = Xcm(vec![ - WithdrawAsset(assets), + Ok(Xcm(vec![ + WithdrawAsset(assets.into()), SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm }, - ]); - let weight = - T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let outcome = - T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); - Self::deposit_event(Event::Attempted { outcome }); - Ok(()) + InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, + ])) + } + + /// Halve `fees` fungible amount. + pub(crate) fn halve_fees(fees: MultiAsset) -> Result<(MultiAsset, MultiAsset), Error> { + match fees.fun { + Fungible(amount) => { + let fee1 = amount.saturating_div(2); + let fee2 = amount.saturating_sub(fee1); + ensure!(fee1 > 0, Error::::FeesNotMet); + ensure!(fee2 > 0, Error::::FeesNotMet); + Ok((MultiAsset::from((fees.id, fee1)), MultiAsset::from((fees.id, fee2)))) + }, + NonFungible(_) => Err(Error::::FeesNotMet), + } } /// Will always make progress, and will do its best not to use much more than `weight_cutoff` diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 3b41ad90ec9..026838993f1 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -17,7 +17,9 @@ use codec::Encode; use frame_support::{ construct_runtime, match_types, parameter_types, - traits::{ConstU32, Everything, EverythingBut, Nothing}, + traits::{ + AsEnsureOriginWithArg, ConstU128, ConstU32, Equals, Everything, EverythingBut, Nothing, + }, weights::Weight, }; use frame_system::EnsureRoot; @@ -32,11 +34,15 @@ use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, - ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, - FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, + ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal, + FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, HashedDescription, IsConcrete, + MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{ + traits::{Identity, JustTry}, + XcmExecutor, +}; use crate::{self as pallet_xcm, TestWeightInfo}; @@ -137,6 +143,7 @@ construct_runtime!( { System: frame_system::{Pallet, Call, Storage, Config, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Config, Event}, ParasOrigin: origin::{Pallet, Origin}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config}, TestNotifier: pallet_test_notifier::{Pallet, Call, Event}, @@ -179,13 +186,13 @@ impl SendXcm for TestSendXcmErrX8 { type Ticket = (MultiLocation, Xcm<()>); fn validate( dest: &mut Option, - msg: &mut Option>, + _: &mut Option>, ) -> SendResult<(MultiLocation, Xcm<()>)> { - let (dest, msg) = (dest.take().unwrap(), msg.take().unwrap()); - if dest.len() == 8 { + if dest.as_ref().unwrap().len() == 8 { + dest.take(); Err(SendError::Transport("Destination location full")) } else { - Ok(((dest, msg), MultiAssets::new())) + Err(SendError::NotApplicable) } } fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result { @@ -280,18 +287,135 @@ impl pallet_balances::Config for Test { type MaxFreezes = ConstU32<0>; } +#[cfg(feature = "runtime-benchmarks")] +/// 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)) } + } +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = MultiLocation; + type AssetIdParameter = MultiLocation; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = XcmBenchmarkHelper; +} + +// This child parachain is a system parachain trusted to teleport native token. +pub const SOME_SYSTEM_PARA: u32 = 1001; + +// This child parachain acts as trusted reserve for its assets in tests. +// USDT allowed to teleport to/from here. +pub const FOREIGN_ASSET_RESERVE_PARA_ID: u32 = 2001; +// Inner junction of reserve asset on `FOREIGN_ASSET_RESERVE_PARA_ID`. +pub const FOREIGN_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567); + +// This child parachain acts as trusted reserve for say.. USDC that can be used for fees. +pub const USDC_RESERVE_PARA_ID: u32 = 2002; +// Inner junction of reserve asset on `USDC_RESERVE_PARA_ID`. +pub const USDC_INNER_JUNCTION: Junction = PalletInstance(42); + +// This child parachain is a trusted teleporter for say.. USDT (T from Teleport :)). +// We'll use USDT in tests that teleport fees. +pub const USDT_PARA_ID: u32 = 2003; + +// This child parachain is not configured as trusted reserve or teleport location for any assets. +pub const OTHER_PARA_ID: u32 = 2009; + parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); + pub const NativeAsset: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(Here.into_location()), + }; + pub const SystemParachainLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(SOME_SYSTEM_PARA)) + }; + pub const ForeignReserveLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + }; + pub const ForeignAsset: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X2(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID), FOREIGN_ASSET_INNER_JUNCTION), + }), + }; + pub const UsdcReserveLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(USDC_RESERVE_PARA_ID)) + }; + pub const Usdc: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X2(Parachain(USDC_RESERVE_PARA_ID), USDC_INNER_JUNCTION), + }), + }; + pub const UsdtTeleportLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(USDT_PARA_ID)) + }; + pub const Usdt: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X1(Parachain(USDT_PARA_ID)), + }), + }; pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorMultiLocation = Here; pub UnitWeightCost: u64 = 1_000; + pub CheckingAccount: AccountId = XcmPallet::check_account(); } -pub type SovereignAccountOf = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + HashedDescription, +); -pub type LocalAssetTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; +pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId< + MultiLocation, + Balance, + // Excludes relay/parent chain currency + EverythingBut<(Equals,)>, + Identity, + JustTry, +>; + +pub type AssetTransactors = ( + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>, + FungiblesAdapter< + Assets, + ForeignAssetsConvertedConcreteId, + SovereignAccountOf, + AccountId, + NoChecking, + CheckingAccount, + >, +); type LocalOriginConverter = ( SovereignSignedViaLocation, @@ -303,7 +427,12 @@ type LocalOriginConverter = ( parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); - pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); + pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); + pub TrustedSystemPara: (MultiAssetFilter, MultiLocation) = (NativeAsset::get().into(), SystemParachainLocation::get()); + pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), UsdtTeleportLocation::get()); + pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), ForeignReserveLocation::get()); + pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (ForeignAsset::get().into(), ForeignReserveLocation::get()); + pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (Usdc::get().into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]); @@ -323,14 +452,21 @@ pub type Barrier = ( AllowSubscriptionsFrom, ); +pub type XcmRouter = (TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = (TestPaidForPara3000SendXcm, TestSendXcm); - type AssetTransactor = LocalAssetTransactor; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; - type IsReserve = (); - type IsTeleporter = Case; + type IsReserve = (Case, Case); + type IsTeleporter = ( + Case, + Case, + Case, + Case, + ); type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; @@ -360,15 +496,10 @@ parameter_types! { pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); -} - impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = (TestSendXcmErrX8, TestPaidForPara3000SendXcm, TestSendXcm); + type XcmRouter = XcmRouter; type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; @@ -380,6 +511,7 @@ impl pallet_xcm::Config for Test { type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = AdvertisedXcmVersion; + type AdminOrigin = EnsureRoot; type TrustedLockers = (); type SovereignAccountOf = AccountId32Aliases<(), AccountId32>; type Currency = Balances; @@ -388,9 +520,6 @@ impl pallet_xcm::Config for Test { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; } impl origin::Config for Test {} @@ -401,6 +530,24 @@ impl pallet_test_notifier::Config for Test { type RuntimeCall = RuntimeCall; } +#[cfg(feature = "runtime-benchmarks")] +impl super::benchmarking::Config for Test { + fn reachable_dest() -> Option { + Some(Parachain(1000).into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + Some((NativeAsset::get(), SystemParachainLocation::get())) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into_location()) }, + Parachain(OTHER_PARA_ID).into(), + )) + } +} + pub(crate) fn last_event() -> RuntimeEvent { System::events().pop().expect("RuntimeEvent expected").event } @@ -416,10 +563,10 @@ pub(crate) fn buy_execution(fees: impl Into) -> Instruction { pub(crate) fn buy_limited_execution( fees: impl Into, - weight: Weight, + weight_limit: WeightLimit, ) -> Instruction { use xcm::latest::prelude::*; - BuyExecution { fees: fees.into(), weight_limit: Limited(weight) } + BuyExecution { fees: fees.into(), weight_limit } } pub(crate) fn new_test_ext_with_balances( diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs new file mode 100644 index 00000000000..b02b0fd33c3 --- /dev/null +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -0,0 +1,1405 @@ +// 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(test)] + +use crate::{ + mock::*, + tests::{ALICE, BOB, FEE_AMOUNT, INITIAL_BALANCE, SEND_AMOUNT}, +}; +use frame_support::{ + assert_ok, + traits::{tokens::fungibles::Inspect, Currency}, + weights::Weight, +}; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use sp_runtime::{traits::AccountIdConversion, DispatchError, ModuleError}; +use xcm::prelude::*; +use xcm_executor::traits::ConvertLocation; + +// Helper function to deduplicate testing different teleport types. +fn do_test_and_verify_teleport_assets( + expected_beneficiary: MultiLocation, + call: Call, + expected_weight_limit: WeightLimit, +) { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let weight = BaseXcmWeight::get() * 3; + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + // call extrinsic + call(); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); + assert_eq!( + sent_xcm(), + vec![( + RelayLocation::get().into(), + Xcm(vec![ + ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), + ClearOrigin, + buy_limited_execution((Here, SEND_AMOUNT), expected_weight_limit), + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary + }, + ]), + )] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + }); +} + +/// Test `teleport_assets` +/// +/// Asserts that the sender's balance is decreased as a result of execution of +/// local effects. +#[test] +fn teleport_assets_works() { + let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + do_test_and_verify_teleport_assets( + beneficiary, + || { + assert_ok!(XcmPallet::teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(beneficiary.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + )); + }, + Unlimited, + ); +} + +/// Test `limited_teleport_assets` +/// +/// Asserts that the sender's balance is decreased as a result of execution of +/// local effects. +#[test] +fn limited_teleport_assets_works() { + let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + do_test_and_verify_teleport_assets( + beneficiary, + || { + assert_ok!(XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(beneficiary.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); + }, + expected_weight_limit, + ); +} + +/// Test `reserve_transfer_assets_with_paid_router_works` +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +/// Verifies that XCM router fees (`SendXcm::validate` -> `MultiAssets`) are withdrawn from correct +/// user account and deposited to a correct target account (`XcmFeesTargetAccount`). +#[test] +fn reserve_transfer_assets_with_paid_router_works() { + let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT); + let paid_para_id = Para3000::get(); + let balances = vec![ + (user_account.clone(), INITIAL_BALANCE), + (ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE), + (XcmFeesTargetAccount::get(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let xcm_router_fee_amount = Para3000PaymentAmount::get(); + let weight = BaseXcmWeight::get(); + let dest: MultiLocation = + Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); + assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); + assert_ok!(XcmPallet::reserve_transfer_assets( + RuntimeOrigin::signed(user_account.clone()), + Box::new(Parachain(paid_para_id).into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + )); + + // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount + assert_eq!( + Balances::free_balance(user_account), + INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount + ); + + // Destination account (parachain account) has amount + let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating(); + assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); + + // XcmFeesTargetAccount where should lend xcm_router_fee_amount + assert_eq!( + Balances::free_balance(XcmFeesTargetAccount::get()), + INITIAL_BALANCE + xcm_router_fee_amount + ); + + let dest_para: MultiLocation = Parachain(paid_para_id).into(); + assert_eq!( + sent_xcm(), + vec![( + dest_para, + Xcm(vec![ + ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), + ClearOrigin, + buy_execution((Parent, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]), + )] + ); + let mut last_events = last_events(5).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + // balances events + last_events.next().unwrap(); + last_events.next().unwrap(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: dest, + fees: Para3000PaymentMultiAssets::get(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + }); +} + +fn set_up_foreign_asset( + reserve_para_id: u32, + inner_junction: Option, + initial_amount: u128, + is_sufficient: bool, +) -> (MultiLocation, AccountId, MultiLocation) { + let reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(reserve_para_id)).unwrap(); + let reserve_sovereign_account = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + let foreign_asset_id_multilocation = if let Some(junction) = inner_junction { + reserve_location.pushed_with_interior(junction).unwrap() + } else { + reserve_location + }; + + // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + is_sufficient, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + initial_amount + )); + + (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) +} + +// Helper function that provides correct `fee_index` after `sort()` done by +// `vec![MultiAsset, MultiAsset].into()`. +fn into_multiassets_checked( + fee_asset: MultiAsset, + transfer_asset: MultiAsset, +) -> (MultiAssets, usize, MultiAsset, MultiAsset) { + let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset.clone()].into(); + let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; + (assets, fee_index, fee_asset, transfer_asset) +} + +/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. +/// +/// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). +/// Using native asset for fees as well. +/// +/// ```nocompile +/// Here (source) OTHER_PARA_ID (destination) +/// | `assets` reserve +/// | `fees` reserve +/// | +/// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` +/// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +#[test] +fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + let expected_beneficiary = beneficiary; + let dest: MultiLocation = Parachain(OTHER_PARA_ID).into(); + + new_test_ext_with_balances(balances).execute_with(|| { + let weight = BaseXcmWeight::get(); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + // call extrinsic + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); + // Alice spent amount + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Destination account (parachain account) has amount + let para_acc: AccountId = ParaId::from(OTHER_PARA_ID).into_account_truncating(); + assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); + assert_eq!( + sent_xcm(), + vec![( + dest, + Xcm(vec![ + ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), + ClearOrigin, + buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit), + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary + }, + ]), + )] + ); + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: expected_beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + }); +} + +/// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. +/// +/// Transferring foreign asset (`FOREIGN_ASSET_RESERVE_PARA_ID` reserve) to +/// `FOREIGN_ASSET_RESERVE_PARA_ID` (no teleport trust). +/// Using native asset (local reserve) for fees. +/// +/// ```nocompile +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` reserve `assets` reserve +/// | +/// | 1. execute `TransferReserveAsset(fees)` +/// | \-> sends `ReserveAssetDeposited(fees), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `InitiateReserveWithdraw(assets)` +/// | \--> sends `WithdrawAsset(assets), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { + let weight = BaseXcmWeight::get() * 3; + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is reserve location (no teleport trust) + let dest = reserve_location; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // native asset for fee - local reserve + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_initial_amount - SEND_AMOUNT + ); + // Alice used native asset for fees + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); + // Destination account (parachain account) added native reserve used as fee to balances + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), FEE_AMOUNT); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + // `fees` are being sent through local-reserve transfer because fee reserve is + // local chain; `assets` are burned on source and withdrawn from SA here + Xcm(vec![ + ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), + buy_limited_execution(expected_fee, Unlimited), + WithdrawAsset(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + }); +} + +/// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. +/// +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `OTHER_PARA_ID`. +/// Using native (local reserve) as fee should be disallowed. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is OTHER_PARA_ID (foreign asset needs to go through its reserve + // chain) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let (assets, fee_index, _, _) = into_multiassets_checked( + // native asset for fee - local reserve + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // try the transfer + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) + ); + + // Alice transferred nothing + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + // Alice spent native asset for fees + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) + let expected_issuance = foreign_initial_amount; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); + }); +} + +/// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. +/// +/// Transferring native asset (local reserve) to `USDC_RESERVE_PARA_ID` (no teleport trust). Using +/// foreign asset (`USDC_RESERVE_PARA_ID` reserve) for fees. +/// +/// ```nocompile +/// Here (source) USDC_RESERVE_PARA_ID (destination) +/// | `assets` reserve `fees` reserve +/// | +/// | 1. execute `InitiateReserveWithdraw(fees)` +/// | \--> sends `WithdrawAsset(fees), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `TransferReserveAsset(assets)` +/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 142; + let (usdc_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // native assets transfer to fee reserve location (no teleport trust) + let dest = usdc_reserve_location; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // usdc for fees (is sufficient on local chain too) - destination reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + let weight = BaseXcmWeight::get() * 3; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + + // Alice spent (fees) amount + assert_eq!( + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - FEE_AMOUNT + ); + // Alice used native asset for transfer + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), SEND_AMOUNT); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) + let expected_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + Xcm(vec![ + // fees are being sent through destination-reserve transfer because fee reserve + // is destination chain + WithdrawAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), + // transfer is through local-reserve transfer because `assets` (native asset) + // have local reserve + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + }); +} + +/// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. +/// +/// ```nocompile +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` reserve +/// | `assets` reserve +/// | +/// | 1. execute `InitiateReserveWithdraw(assets_and_fees_batched_together)` +/// | \--> sends `WithdrawAsset(batch), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // we'll send just this foreign asset back to its reserve location and use it for fees as + // well + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + true, + ); + + // transfer destination is reserve location + let dest = reserve_location; + let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; + + // reanchor according to test-case + let mut expected_assets = assets.clone(); + expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index, + Unlimited, + )); + + let weight = BaseXcmWeight::get() * 2; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_initial_amount - SEND_AMOUNT + ); + // Alice's native asset balance is untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Reserve sovereign account has same balances + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + Parachain(FOREIGN_ASSET_RESERVE_PARA_ID).into(), + Xcm(vec![ + WithdrawAsset(expected_assets.clone()), + ClearOrigin, + buy_limited_execution(expected_assets.get(0).unwrap().clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]), + )] + ); + }); +} + +/// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve is +/// disallowed. +/// +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to +/// `USDC_RESERVE_PARA_ID`. Using USDC (destination reserve) as fee. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 42; + let (usdc_chain, _, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is USDC chain (foreign asset BLA needs to go through its separate + // reserve chain) + let dest = usdc_chain; + + let (assets, fee_index, _, _) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - destination reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) + ); + + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + let expected_usdc_issuance = usdc_initial_local_amount; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); + let expected_bla_issuance = foreign_initial_amount; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + }); +} + +/// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve is disallowed. +/// +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 142; + let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // transfer destination is some other parachain != fee reserve location (no teleport trust) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + + let (assets, fee_index, _, _) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) + ); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Sovereign account of reserve parachain is unchanged + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + assert_eq!(Balances::free_balance(dest_sovereign_account), 0); + let expected_usdc_issuance = usdc_initial_local_amount; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); + }); +} + +/// Test `reserve_transfer_assets` with destination asset reserve and remote fee reserve is +/// disallowed. +/// +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 42; + let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = foreign_sovereign_account; + + let (assets, fee_index, _, _) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) + ); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + let expected_usdc_issuance = usdc_initial_local_amount; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); + let expected_bla_issuance = foreign_initial_amount; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + }); +} + +/// Test `reserve_transfer_assets` with remote asset reserve and (same) remote fee reserve. +/// +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +/// +/// ```nocompile +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) +/// | | `fees` reserve | +/// | | `assets` reserve | +/// | +/// | 1. `A` executes `InitiateReserveWithdraw(both)` dest `C` +/// | -----------------> `C` executes `DepositReserveAsset(both)` dest `B` +/// | --------------------------> `DepositAsset(both)` +/// ``` +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 142; + let (usdc_chain, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // transfer destination is some other parachain + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&usdc_chain, context).unwrap(); + let fees = assets.get(fee_index).unwrap().clone(); + let (fees_half_1, fees_half_2) = XcmPallet::halve_fees(fees).unwrap(); + let mut expected_assets_on_reserve = assets.clone(); + expected_assets_on_reserve.reanchor(&usdc_chain, context).unwrap(); + let expected_fee_on_reserve = fees_half_1.reanchored(&usdc_chain, context).unwrap(); + let expected_fee_on_dest = fees_half_2.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - SEND_AMOUNT + ); + // Alice's native asset balance is untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Destination account (parachain account) has expected (same) balances + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) + let expected_usdc_issuance = usdc_initial_local_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + // first message sent to reserve chain + usdc_chain, + Xcm(vec![ + WithdrawAsset(expected_assets_on_reserve), + ClearOrigin, + BuyExecution { fees: expected_fee_on_reserve, weight_limit: Unlimited }, + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to `dest` + xcm: Xcm(vec![ + buy_limited_execution(expected_fee_on_dest, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + )], + ); + }); +} + +/// Test `reserve_transfer_assets` with local asset reserve and teleported fee. +/// +/// Transferring native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for +/// fees. +/// +/// ```nocompile +/// Here (source) USDT_PARA_ID (destination) +/// | `assets` reserve `fees` teleport-trust +/// | +/// | 1. execute `InitiateTeleport(fees)` +/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | 2. execute `TransferReserveAsset(assets)` +/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // native assets transfer destination is USDT chain (teleport trust only for USDT) + let dest = usdt_chain; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + let weight = BaseXcmWeight::get() * 3; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + // Alice spent (fees) amount + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Alice used native asset for transfer + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), SEND_AMOUNT); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance have decreased (teleported) + let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + Xcm(vec![ + // fees are teleported to destination chain + ReceiveTeleportedAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), + // transfer is through local-reserve transfer because `assets` (native + // asset) have local reserve + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + }); +} + +/// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. +/// +/// Transferring foreign asset (destination reserve) to `FOREIGN_ASSET_RESERVE_PARA_ID`. Using +/// teleport-trusted USDT for fees. +/// +/// ```nocompile +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` (USDT) teleport-trust +/// | `assets` reserve +/// | +/// | 1. execute `InitiateTeleport(fees)` +/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | 2. execute `InitiateReserveWithdraw(assets)` +/// | \--> sends `WithdrawAsset(asset), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + let usdt_initial_local_amount = 42; + let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = foreign_sovereign_account; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + let weight = BaseXcmWeight::get() * 4; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDT for fees + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_initial_amount - SEND_AMOUNT + ); + // Verify balances of USDT reserve parachain + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify balances of transferred-asset reserve parachain + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + // Verify total and active issuance of USDT have decreased (teleported) + let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) + let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + Xcm(vec![ + // fees are teleported to destination chain + ReceiveTeleportedAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), + // assets are withdrawn from origin's local SA + WithdrawAsset(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + }); +} + +/// Test `reserve_transfer_assets` with remote asset reserve and teleported fee is disallowed. +/// +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. +/// Using teleport-trusted USDT for fees. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (_, reserve_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + + let (assets, fee_index, _, _) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) + ); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); + let expected_usdt_issuance = usdt_initial_local_amount; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); + let expected_bla_issuance = foreign_initial_amount; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + }); +} + +/// Test `reserve_transfer_assets` single asset which is teleportable - should fail. +/// +/// Attempting to reserve-transfer teleport-trusted USDT to `USDT_PARA_ID` should fail. +#[test] +fn reserve_transfer_assets_with_teleportable_asset_fails() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + let assets: MultiAssets = vec![(usdt_id_multilocation, FEE_AMOUNT).into()].into(); + let fee_index = 0; + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let res = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + res, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered") + })) + ); + // Alice native asset is still same + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice USDT balance is still same + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + // No USDT moved to sovereign account of reserve parachain + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance of USDT are still the same + assert_eq!(Assets::total_issuance(usdt_id_multilocation), usdt_initial_local_amount); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); + }); +} diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs similarity index 68% rename from polkadot/xcm/pallet-xcm/src/tests.rs rename to polkadot/xcm/pallet-xcm/src/tests/mod.rs index d267eece2c0..72814e507f2 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +#![cfg(test)] + +mod assets_transfer; + use crate::{ mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, @@ -35,15 +39,15 @@ use xcm_executor::{ const ALICE: AccountId = AccountId::new([0u8; 32]); const BOB: AccountId = AccountId::new([1u8; 32]); -const PARA_ID: u32 = 2000; const INITIAL_BALANCE: u128 = 100; const SEND_AMOUNT: u128 = 10; +const FEE_AMOUNT: u128 = 2; #[test] fn report_outcome_notify_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let mut message = @@ -56,7 +60,7 @@ fn report_outcome_notify_works() { new_test_ext_with_balances(balances).execute_with(|| { XcmPallet::report_outcome_notify( &mut message, - Parachain(PARA_ID).into_location(), + Parachain(OTHER_PARA_ID).into_location(), notify, 100, ) @@ -74,8 +78,8 @@ fn report_outcome_notify_works() { ); let querier: MultiLocation = Here.into(); let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(PARA_ID)).into(), - maybe_notify: Some((4, 2)), + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), + maybe_notify: Some((5, 2)), timeout: 100, maybe_match_querier: Some(querier.into()), }; @@ -89,7 +93,7 @@ fn report_outcome_notify_works() { }]); let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm( - Parachain(PARA_ID), + Parachain(OTHER_PARA_ID), message, hash, Weight::from_parts(1_000_000_000, 1_000_000_000), @@ -99,13 +103,13 @@ fn report_outcome_notify_works() { last_events(2), vec![ RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived( - Parachain(PARA_ID).into(), + Parachain(OTHER_PARA_ID).into(), 0, Response::ExecutionResult(None), )), RuntimeEvent::XcmPallet(crate::Event::Notified { query_id: 0, - pallet_index: 4, + pallet_index: 5, call_index: 2 }), ] @@ -118,13 +122,14 @@ fn report_outcome_notify_works() { fn report_outcome_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let mut message = Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); new_test_ext_with_balances(balances).execute_with(|| { - XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into_location(), 100).unwrap(); + XcmPallet::report_outcome(&mut message, Parachain(OTHER_PARA_ID).into_location(), 100) + .unwrap(); assert_eq!( message, Xcm(vec![ @@ -138,7 +143,7 @@ fn report_outcome_works() { ); let querier: MultiLocation = Here.into(); let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(PARA_ID)).into(), + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), maybe_notify: None, timeout: 100, maybe_match_querier: Some(querier.into()), @@ -153,7 +158,7 @@ fn report_outcome_works() { }]); let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm( - Parachain(PARA_ID), + Parachain(OTHER_PARA_ID), message, hash, Weight::from_parts(1_000_000_000, 1_000_000_000), @@ -177,7 +182,7 @@ fn report_outcome_works() { fn custom_querier_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let querier: MultiLocation = @@ -281,7 +286,7 @@ fn custom_querier_works() { fn send_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); @@ -325,7 +330,7 @@ fn send_works() { fn send_fails_when_xcm_router_blocks() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: MultiLocation = @@ -346,344 +351,6 @@ fn send_fails_when_xcm_router_blocks() { }); } -/// Test `teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn teleport_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - RelayLocation::get().into(), - Xcm(vec![ - ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `limited_teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn limited_teleport_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Limited(Weight::from_parts(5000, 5000)), - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - RelayLocation::get().into(), - Xcm(vec![ - ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), - ClearOrigin, - buy_limited_execution((Here, SEND_AMOUNT), Weight::from_parts(5000, 5000)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `limited_teleport_assets` with unlimited weight -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn unlimited_teleport_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Unlimited, - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - RelayLocation::get().into(), - Xcm(vec![ - ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `reserve_transfer_assets` -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. -#[test] -fn reserve_transfer_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - // Alice spent amount - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - Parachain(PARA_ID).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `reserve_transfer_assets_with_paid_router_works` -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. -/// Verifies that XCM router fees (`SendXcm::validate` -> `MultiAssets`) are withdrawn from correct -/// user account and deposited to a correct target account (`XcmFeesTargetAccount`). -#[test] -fn reserve_transfer_assets_with_paid_router_works() { - let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT); - let paid_para_id = Para3000::get(); - let balances = vec![ - (user_account.clone(), INITIAL_BALANCE), - (ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE), - (XcmFeesTargetAccount::get(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let xcm_router_fee_amount = Para3000PaymentAmount::get(); - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = - Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); - assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( - RuntimeOrigin::signed(user_account.clone()), - Box::new(Parachain(paid_para_id).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - // check event - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - - // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount - assert_eq!( - Balances::free_balance(user_account), - INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount - ); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - // XcmFeesTargetAccount where should lend xcm_router_fee_amount - assert_eq!( - Balances::free_balance(XcmFeesTargetAccount::get()), - INITIAL_BALANCE + xcm_router_fee_amount - ); - assert_eq!( - sent_xcm(), - vec![( - Parachain(paid_para_id).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `limited_reserve_transfer_assets` -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. -#[test] -fn limited_reserve_transfer_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Limited(Weight::from_parts(5000, 5000)), - )); - // Alice spent amount - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - Parachain(PARA_ID).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_limited_execution((Parent, SEND_AMOUNT), Weight::from_parts(5000, 5000)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test `limited_reserve_transfer_assets` with unlimited weight purchasing -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. -#[test] -fn unlimited_reserve_transfer_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Unlimited, - )); - // Alice spent amount - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - Parachain(PARA_ID).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - /// Test local execution of XCM /// /// Asserts that the sender's balance is decreased and the beneficiary's balance @@ -692,7 +359,7 @@ fn unlimited_reserve_transfer_assets_works() { fn execute_withdraw_to_deposit_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 3; diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 8a1575d9bc9..89e25984443 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -444,6 +444,21 @@ impl MultiLocation { } } } + + /// Return the MultiLocation subsection identifying the chain that `self` points to. + pub fn chain_location(&self) -> MultiLocation { + let mut clone = *self; + // start popping junctions until we reach chain identifier + while let Some(j) = clone.last() { + if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) { + // return chain subsection + return clone + } else { + (clone, _) = clone.split_last_interior(); + } + } + MultiLocation::new(clone.parents, Junctions::Here) + } } impl TryFrom for MultiLocation { @@ -674,6 +689,57 @@ mod tests { assert_eq!(iter.next_back(), None); } + #[test] + fn chain_location_works() { + // Relay-chain or parachain context pointing to local resource, + let relay_to_local = MultiLocation::new(0, (PalletInstance(42), GeneralIndex(42))); + assert_eq!(relay_to_local.chain_location(), MultiLocation::here()); + + // Relay-chain context pointing to child parachain, + let relay_to_child = + MultiLocation::new(0, (Parachain(42), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(0, Parachain(42)); + assert_eq!(relay_to_child.chain_location(), expected); + + // Relay-chain context pointing to different consensus relay, + let relay_to_remote_relay = + MultiLocation::new(1, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(1, GlobalConsensus(Kusama)); + assert_eq!(relay_to_remote_relay.chain_location(), expected); + + // Relay-chain context pointing to different consensus parachain, + let relay_to_remote_para = MultiLocation::new( + 1, + (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)), + ); + let expected = MultiLocation::new(1, (GlobalConsensus(Kusama), Parachain(42))); + assert_eq!(relay_to_remote_para.chain_location(), expected); + + // Parachain context pointing to relay chain, + let para_to_relay = MultiLocation::new(1, (PalletInstance(42), GeneralIndex(42))); + assert_eq!(para_to_relay.chain_location(), MultiLocation::parent()); + + // Parachain context pointing to sibling parachain, + let para_to_sibling = + MultiLocation::new(1, (Parachain(42), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(1, Parachain(42)); + assert_eq!(para_to_sibling.chain_location(), expected); + + // Parachain context pointing to different consensus relay, + let para_to_remote_relay = + MultiLocation::new(2, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(2, GlobalConsensus(Kusama)); + assert_eq!(para_to_remote_relay.chain_location(), expected); + + // Parachain context pointing to different consensus parachain, + let para_to_remote_para = MultiLocation::new( + 2, + (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)), + ); + let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42))); + assert_eq!(para_to_remote_para.chain_location(), expected); + } + #[test] fn conversion_from_other_types_works() { use crate::v2; diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 3b13cab2c1e..c2b62751c68 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -81,10 +81,15 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro instructions[..end] .matcher() .match_next_inst(|inst| match inst { - ReceiveTeleportedAsset(..) | ReserveAssetDeposited(..) => Ok(()), - WithdrawAsset(ref assets) if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), - ClaimAsset { ref assets, .. } if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => - Ok(()), + ReceiveTeleportedAsset(ref assets) | + ReserveAssetDeposited(ref assets) | + WithdrawAsset(ref assets) | + ClaimAsset { ref assets, .. } => + if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION { + Ok(()) + } else { + Err(ProcessMessageError::BadFormat) + }, _ => Err(ProcessMessageError::BadFormat), })? .skip_inst_while(|inst| matches!(inst, ClearOrigin))? diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index e51bd952177..78b9284c689 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -246,11 +246,6 @@ type SovereignAccountOf = ( HashedDescription>, ); -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); -} - impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -274,8 +269,6 @@ impl pallet_xcm::Config for Test { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 5fcba5e2f54..4f183c7a15b 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -210,11 +210,6 @@ impl xcm_executor::Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Here.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UniversalLocation = UniversalLocation; @@ -239,8 +234,6 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 9f0caa80617..d5edb1ea0f5 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -10,6 +10,7 @@ version = "1.0.0" impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } @@ -34,6 +35,7 @@ std = [ "frame-support/std", "log/std", "parity-scale-codec/std", + "scale-info/std", "sp-arithmetic/std", "sp-core/std", "sp-io/std", diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index e43d7a04899..ac256ea1489 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -32,7 +32,7 @@ pub mod traits; use traits::{ validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute, - TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, + TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers, }; mod assets; @@ -254,6 +254,12 @@ impl ExecuteXcm for XcmExecutor XcmAssetTransfers for XcmExecutor { + type IsReserve = Config::IsReserve; + type IsTeleporter = Config::IsTeleporter; + type AssetTransactor = Config::AssetTransactor; +} + #[derive(Debug)] pub struct ExecutorError { pub index: u32, diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs new file mode 100644 index 00000000000..5fdc9b15e01 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -0,0 +1,90 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::traits::TransactAsset; +use frame_support::traits::ContainsPair; +use scale_info::TypeInfo; +use sp_runtime::codec::{Decode, Encode}; +use xcm::prelude::*; + +/// Errors related to determining asset transfer support. +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Invalid non-concrete asset. + NotConcrete, + /// Reserve chain could not be determined for assets. + UnknownReserve, +} + +/// Specify which type of asset transfer is required for a particular `(asset, dest)` combination. +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum TransferType { + /// should teleport `asset` to `dest` + Teleport, + /// should reserve-transfer `asset` to `dest`, using local chain as reserve + LocalReserve, + /// should reserve-transfer `asset` to `dest`, using `dest` as reserve + DestinationReserve, + /// should reserve-transfer `asset` to `dest`, using remote chain `MultiLocation` as reserve + RemoteReserve(MultiLocation), +} + +/// A trait for identifying asset transfer type based on `IsTeleporter` and `IsReserve` +/// configurations. +pub trait XcmAssetTransfers { + /// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning + /// reserve-based-transfers are to be used for assets matching this filter. + type IsReserve: ContainsPair; + + /// Combinations of (Asset, Location) pairs which we trust as teleporters. Meaning teleports are + /// to be used for assets matching this filter. + type IsTeleporter: ContainsPair; + + /// How to withdraw and deposit an asset. + type AssetTransactor: TransactAsset; + + /// Determine transfer type to be used for transferring `asset` from local chain to `dest`. + fn determine_for(asset: &MultiAsset, dest: &MultiLocation) -> Result { + if Self::IsTeleporter::contains(asset, dest) { + // we trust destination for teleporting asset + return Ok(TransferType::Teleport) + } else if Self::IsReserve::contains(asset, dest) { + // we trust destination as asset reserve location + return Ok(TransferType::DestinationReserve) + } + + // try to determine reserve location based on asset id/location + let asset_location = match asset.id { + Concrete(location) => Ok(location.chain_location()), + _ => Err(Error::NotConcrete), + }?; + if asset_location == MultiLocation::here() || + Self::IsTeleporter::contains(asset, &asset_location) + { + // if the asset is local, then it's a local reserve + // it's also a local reserve if the asset's location is not `here` but it's a location + // where it can be teleported to `here` => local reserve + Ok(TransferType::LocalReserve) + } else if Self::IsReserve::contains(asset, &asset_location) { + // remote location that is recognized as reserve location for asset + Ok(TransferType::RemoteReserve(asset_location)) + } else { + // remote location that is not configured either as teleporter or reserve => cannot + // determine asset reserve + Err(Error::UnknownReserve) + } + } +} diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index a9439968fa6..71e75c77e93 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -20,10 +20,12 @@ mod conversion; pub use conversion::{CallDispatcher, ConvertLocation, ConvertOrigin, WithOriginFilter}; mod drop_assets; pub use drop_assets::{ClaimAssets, DropAssets}; -mod asset_lock; -pub use asset_lock::{AssetLock, Enact, LockError}; mod asset_exchange; pub use asset_exchange::AssetExchange; +mod asset_lock; +pub use asset_lock::{AssetLock, Enact, LockError}; +mod asset_transfer; +pub use asset_transfer::{Error as AssetTransferError, TransferType, XcmAssetTransfers}; mod export; pub use export::{export_xcm, validate_export, ExportXcm}; mod fee_manager; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index fa9d3300619..9f0411970ce 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -399,11 +399,6 @@ impl mock_msg_queue::Config for Runtime { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - pub struct TrustedLockerCase(PhantomData); impl> ContainsPair for TrustedLockerCase @@ -443,8 +438,6 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 0fba4cb270d..bdd7ff6d3ea 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -199,11 +199,6 @@ impl Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1).into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -228,8 +223,6 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index f9ad0252285..41234837aca 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -313,11 +313,6 @@ impl mock_msg_queue::Config for Runtime { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -341,8 +336,6 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 756cf4803b1..c9a57db970a 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -163,11 +163,6 @@ impl Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1).into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -192,8 +187,6 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; } -- GitLab From c7bd8804389e4b9b7f9d0c39b06094aebb303e5d Mon Sep 17 00:00:00 2001 From: Lulu Date: Mon, 13 Nov 2023 19:10:12 +0000 Subject: [PATCH 493/633] Add CI to claim crates (#2299) --- .github/workflows/claim-crates.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/claim-crates.yml diff --git a/.github/workflows/claim-crates.yml b/.github/workflows/claim-crates.yml new file mode 100644 index 00000000000..a1d28d42828 --- /dev/null +++ b/.github/workflows/claim-crates.yml @@ -0,0 +1,25 @@ +name: Claim Crates + +on: + push: + branches: + - master + +jobs: + claim-crates: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + + - name: Rust Cache + uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 # v2.7.1 + with: + cache-on-failure: true + + - name: install parity-publish + run: cargo install parity-publish@0.2.0 + + - name: parity-publish claim + env: + PARITY_PUBLISH_CRATESIO_TOKEN: ${{ secrets.CRATESIO_PUBLISH_CLAIM_TOKEN }} + run: parity-publish claim -- GitLab From f332d6881d4275886f5d738ae9eee96d1ced9c94 Mon Sep 17 00:00:00 2001 From: Assem Date: Mon, 13 Nov 2023 20:34:27 +0100 Subject: [PATCH 494/633] =?UTF-8?q?doc(client/cli/src/arg=5Fenums.rs):=20f?= =?UTF-8?q?ix=20typo=20=E2=9C=8D=EF=B8=8F=20(#2298)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- substrate/client/cli/src/arg_enums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index c55b97675da..d4a4b7cfdf6 100644 --- a/substrate/client/cli/src/arg_enums.rs +++ b/substrate/client/cli/src/arg_enums.rs @@ -225,7 +225,7 @@ pub enum OffchainWorkerEnabled { #[derive(Debug, Clone, Copy, ValueEnum, PartialEq)] #[value(rename_all = "kebab-case")] pub enum SyncMode { - /// Full sync. Download end verify all blocks. + /// Full sync. Download and verify all blocks. Full, /// Download blocks without executing them. Download latest state with proofs. Fast, -- GitLab From 8d2637905ba920dd1f0e8f1212ec98e45420f514 Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Mon, 13 Nov 2023 21:17:36 +0100 Subject: [PATCH 495/633] review-bot: trigger only on review approvals (#2289) Moved the review event of review-bot to only be triggered in approvals. Because we only update the required reviews when someone approves, this will stop the bot from immediately requesting a new review when someone comments or request changes as they should have been already notified in the first batch. --- .github/workflows/review-trigger.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml index 1ae6b79ffbd..2810ea356e6 100644 --- a/.github/workflows/review-trigger.yml +++ b/.github/workflows/review-trigger.yml @@ -13,7 +13,8 @@ on: jobs: trigger-review-bot: - if: github.event.pull_request.draft != true + # (It is not a draft) && (it is not a review || it is an approving review) + if: ${{ github.event.pull_request.draft != true && (github.event_name != 'pull_request_review' || (github.event.review && github.event.review.state == 'APPROVED')) }} runs-on: ubuntu-latest name: trigger review bot steps: -- GitLab From 689b9d91c7e95660682302510b89a5f296098a10 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Tue, 14 Nov 2023 10:37:41 +0200 Subject: [PATCH 496/633] cumulus-pov-recovery: check pov_hash instead of reencoding data (#2287) Collators were previously reencoding the available data and checking the erasure root. Replace that with just checking the PoV hash, which consumes much less CPU and takes less time. We also don't need to check the `PersistedValidationData` hash, as collators don't use it. Reason: https://github.com/paritytech/polkadot-sdk/issues/575#issuecomment-1806572230 After systematic chunks recovery is merged, collators will no longer do any reed-solomon encoding/decoding, which has proven to be a great CPU consumer. Signed-off-by: alindima --- .../src/active_candidate_recovery.rs | 15 +- cumulus/client/pov-recovery/src/lib.rs | 38 ++--- .../src/collator_overseer.rs | 2 +- .../network/availability-recovery/src/lib.rs | 39 ++++- .../network/availability-recovery/src/task.rs | 138 +++++++++++------- 5 files changed, 141 insertions(+), 91 deletions(-) diff --git a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs index 322b19c796a..2c635320ff4 100644 --- a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs +++ b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs @@ -16,12 +16,12 @@ use sp_runtime::traits::Block as BlockT; -use polkadot_node_primitives::AvailableData; +use polkadot_node_primitives::PoV; use polkadot_node_subsystem::messages::AvailabilityRecoveryMessage; use futures::{channel::oneshot, stream::FuturesUnordered, Future, FutureExt, StreamExt}; -use std::{collections::HashSet, pin::Pin}; +use std::{collections::HashSet, pin::Pin, sync::Arc}; use crate::RecoveryHandle; @@ -30,9 +30,8 @@ use crate::RecoveryHandle; /// This handles the candidate recovery and tracks the activate recoveries. pub(crate) struct ActiveCandidateRecovery { /// The recoveries that are currently being executed. - recoveries: FuturesUnordered< - Pin)> + Send>>, - >, + recoveries: + FuturesUnordered>)> + Send>>>, /// The block hashes of the candidates currently being recovered. candidates: HashSet, recovery_handle: Box, @@ -68,7 +67,7 @@ impl ActiveCandidateRecovery { self.recoveries.push( async move { match rx.await { - Ok(Ok(res)) => (block_hash, Some(res)), + Ok(Ok(res)) => (block_hash, Some(res.pov)), Ok(Err(error)) => { tracing::debug!( target: crate::LOG_TARGET, @@ -93,8 +92,8 @@ impl ActiveCandidateRecovery { /// Waits for the next recovery. /// - /// If the returned [`AvailableData`] is `None`, it means that the recovery failed. - pub async fn wait_for_recovery(&mut self) -> (Block::Hash, Option) { + /// If the returned [`PoV`] is `None`, it means that the recovery failed. + pub async fn wait_for_recovery(&mut self) -> (Block::Hash, Option>) { loop { if let Some(res) = self.recoveries.next().await { self.candidates.remove(&res.0); diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index b050bc66799..b9a140f55c6 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -51,7 +51,7 @@ use sc_consensus::import_queue::{ImportQueueService, IncomingBlock}; use sp_consensus::{BlockOrigin, BlockStatus, SyncOracle}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use polkadot_node_primitives::{AvailableData, POV_BOMB_LIMIT}; +use polkadot_node_primitives::{PoV, POV_BOMB_LIMIT}; use polkadot_node_subsystem::messages::AvailabilityRecoveryMessage; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{ @@ -346,15 +346,11 @@ where } /// Handle a recovered candidate. - async fn handle_candidate_recovered( - &mut self, - block_hash: Block::Hash, - available_data: Option, - ) { - let available_data = match available_data { - Some(data) => { + async fn handle_candidate_recovered(&mut self, block_hash: Block::Hash, pov: Option<&PoV>) { + let pov = match pov { + Some(pov) => { self.candidates_in_retry.remove(&block_hash); - data + pov }, None => if self.candidates_in_retry.insert(block_hash) { @@ -373,18 +369,16 @@ where }, }; - let raw_block_data = match sp_maybe_compressed_blob::decompress( - &available_data.pov.block_data.0, - POV_BOMB_LIMIT, - ) { - Ok(r) => r, - Err(error) => { - tracing::debug!(target: LOG_TARGET, ?error, "Failed to decompress PoV"); + let raw_block_data = + match sp_maybe_compressed_blob::decompress(&pov.block_data.0, POV_BOMB_LIMIT) { + Ok(r) => r, + Err(error) => { + tracing::debug!(target: LOG_TARGET, ?error, "Failed to decompress PoV"); - self.reset_candidate(block_hash); - return - }, - }; + self.reset_candidate(block_hash); + return + }, + }; let block_data = match ParachainBlockData::::decode(&mut &raw_block_data[..]) { Ok(d) => d, @@ -595,10 +589,10 @@ where next_to_recover = self.candidate_recovery_queue.next_recovery().fuse() => { self.recover_candidate(next_to_recover).await; }, - (block_hash, available_data) = + (block_hash, pov) = self.active_candidate_recovery.wait_for_recovery().fuse() => { - self.handle_candidate_recovered(block_hash, available_data).await; + self.handle_candidate_recovered(block_hash, pov.as_deref()).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 379217e4a63..945344f85e9 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -102,7 +102,7 @@ fn build_overseer( let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; let builder = Overseer::builder() .availability_distribution(DummySubsystem) - .availability_recovery(AvailabilityRecoverySubsystem::with_availability_store_skip( + .availability_recovery(AvailabilityRecoverySubsystem::for_collator( available_data_req_receiver, Metrics::register(registry)?, )) diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index 9acc48ea92e..4a658449f09 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -105,6 +105,17 @@ pub struct AvailabilityRecoverySubsystem { req_receiver: IncomingRequestReceiver, /// Metrics for this subsystem. metrics: Metrics, + /// The type of check to perform after available data was recovered. + post_recovery_check: PostRecoveryCheck, +} + +#[derive(Clone, PartialEq, Debug)] +/// The type of check to perform after available data was recovered. +pub enum PostRecoveryCheck { + /// Reencode the data and check erasure root. For validators. + Reencode, + /// Only check the pov hash. For collators only. + PovHash, } /// Expensive erasure coding computations that we want to run on a blocking thread. @@ -344,6 +355,7 @@ async fn launch_recovery_task( metrics: &Metrics, recovery_strategies: VecDeque::Sender>>>, bypass_availability_store: bool, + post_recovery_check: PostRecoveryCheck, ) -> error::Result<()> { let candidate_hash = receipt.hash(); let params = RecoveryParams { @@ -354,6 +366,8 @@ async fn launch_recovery_task( erasure_root: receipt.descriptor.erasure_root, metrics: metrics.clone(), bypass_availability_store, + post_recovery_check, + pov_hash: receipt.descriptor.pov_hash, }; let recovery_task = RecoveryTask::new(ctx.sender().clone(), params, recovery_strategies); @@ -390,6 +404,7 @@ async fn handle_recover( erasure_task_tx: futures::channel::mpsc::Sender, recovery_strategy_kind: RecoveryStrategyKind, bypass_availability_store: bool, + post_recovery_check: PostRecoveryCheck, ) -> error::Result<()> { let candidate_hash = receipt.hash(); @@ -486,6 +501,7 @@ async fn handle_recover( metrics, recovery_strategies, bypass_availability_store, + post_recovery_check, ) .await }, @@ -527,15 +543,17 @@ async fn query_chunk_size( #[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)] impl AvailabilityRecoverySubsystem { - /// Create a new instance of `AvailabilityRecoverySubsystem` which never requests the - /// `AvailabilityStoreSubsystem` subsystem. - pub fn with_availability_store_skip( + /// Create a new instance of `AvailabilityRecoverySubsystem` suitable for collator nodes, + /// which never requests the `AvailabilityStoreSubsystem` subsystem and only checks the POV hash + /// instead of reencoding the available data. + pub fn for_collator( req_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> Self { Self { recovery_strategy_kind: RecoveryStrategyKind::BackersFirstIfSizeLower(SMALL_POV_LIMIT), bypass_availability_store: true, + post_recovery_check: PostRecoveryCheck::PovHash, req_receiver, metrics, } @@ -550,6 +568,7 @@ impl AvailabilityRecoverySubsystem { Self { recovery_strategy_kind: RecoveryStrategyKind::BackersFirstAlways, bypass_availability_store: false, + post_recovery_check: PostRecoveryCheck::Reencode, req_receiver, metrics, } @@ -563,6 +582,7 @@ impl AvailabilityRecoverySubsystem { Self { recovery_strategy_kind: RecoveryStrategyKind::ChunksAlways, bypass_availability_store: false, + post_recovery_check: PostRecoveryCheck::Reencode, req_receiver, metrics, } @@ -577,6 +597,7 @@ impl AvailabilityRecoverySubsystem { Self { recovery_strategy_kind: RecoveryStrategyKind::BackersFirstIfSizeLower(SMALL_POV_LIMIT), bypass_availability_store: false, + post_recovery_check: PostRecoveryCheck::Reencode, req_receiver, metrics, } @@ -584,8 +605,13 @@ impl AvailabilityRecoverySubsystem { async fn run(self, mut ctx: Context) -> SubsystemResult<()> { let mut state = State::default(); - let Self { mut req_receiver, metrics, recovery_strategy_kind, bypass_availability_store } = - self; + let Self { + mut req_receiver, + metrics, + recovery_strategy_kind, + bypass_availability_store, + post_recovery_check, + } = self; let (erasure_task_tx, erasure_task_rx) = futures::channel::mpsc::channel(16); let mut erasure_task_rx = erasure_task_rx.fuse(); @@ -675,7 +701,8 @@ impl AvailabilityRecoverySubsystem { &metrics, erasure_task_tx.clone(), recovery_strategy_kind.clone(), - bypass_availability_store + bypass_availability_store, + post_recovery_check.clone() ).await { gum::warn!( target: LOG_TARGET, diff --git a/polkadot/node/network/availability-recovery/src/task.rs b/polkadot/node/network/availability-recovery/src/task.rs index d5bc2da8494..f705d5c0e4c 100644 --- a/polkadot/node/network/availability-recovery/src/task.rs +++ b/polkadot/node/network/availability-recovery/src/task.rs @@ -20,7 +20,7 @@ use crate::{ futures_undead::FuturesUndead, is_chunk_valid, is_unavailable, metrics::Metrics, ErasureTask, - LOG_TARGET, + PostRecoveryCheck, LOG_TARGET, }; use futures::{channel::oneshot, SinkExt}; #[cfg(not(test))] @@ -95,6 +95,12 @@ pub struct RecoveryParams { /// Do not request data from availability-store. Useful for collators. pub bypass_availability_store: bool, + + /// The type of check to perform after available data was recovered. + pub post_recovery_check: PostRecoveryCheck, + + /// The blake2-256 hash of the PoV. + pub pov_hash: Hash, } /// Intermediate/common data that must be passed between `RecoveryStrategy`s belonging to the @@ -501,39 +507,48 @@ impl RecoveryStrategy 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", - ); + let maybe_data = match common_params.post_recovery_check { + PostRecoveryCheck::Reencode => { + 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)?; + + reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)? + }, + PostRecoveryCheck::PovHash => + (data.pov.hash() == common_params.pov_hash).then_some(data), + }; - return Ok(data) - } else { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?common_params.candidate_hash, - ?validator_index, - "Invalid data response", - ); + match maybe_data { + Some(data) => { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + "Received full data", + ); - // it doesn't help to report the peer with req/res. - } + return Ok(data) + }, + None => { + 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. + // we'll try the next backer. + }, + }; }, Ok(req_res::v1::AvailableDataFetchingResponse::NoSuchData) => {}, Err(e) => gum::debug!( @@ -647,22 +662,43 @@ impl FetchChunks { 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 { + let maybe_data = match common_params.post_recovery_check { + PostRecoveryCheck::Reencode => { + // 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)?; + + reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)?.or_else(|| { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + erasure_root = ?common_params.erasure_root, + "Data recovery error - root mismatch", + ); + None + }) + }, + PostRecoveryCheck::PovHash => + (data.pov.hash() == common_params.pov_hash).then_some(data).or_else(|| { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + pov_hash = ?common_params.pov_hash, + "Data recovery error - PoV hash mismatch", + ); + None + }), + }; + + if let Some(data) = maybe_data { gum::trace!( target: LOG_TARGET, candidate_hash = ?common_params.candidate_hash, @@ -673,12 +709,6 @@ impl FetchChunks { 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) } -- GitLab From b371c3574190ace0d8dd89b7970a388ad3fa8a6a Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Tue, 14 Nov 2023 08:39:44 +0000 Subject: [PATCH 497/633] Fix `ecdsa_bls` verify in BEEFY primitives (#2066) BEEFY ECDSA signatures are on keccak has of the messages. As such we can not simply call `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` because that invokes ecdsa default verification which perfoms blake2 hash which we don't want. This bring up the second issue makes: This makes `sign` and `verify` function in `pair_crypto` useless, at least for BEEFY use case. Moreover, there is no obvious clean way to generate the signature given that pair_crypto does not exposes `sign_prehashed`. You could in theory query the keystore for the pair (could you?), invoke `to_raw` and re-generate each sub-pair and sign using each. But that sounds extremely anticlimactic and will be frow upon by auditors . So I appreciate any alternative suggestion. --------- Co-authored-by: Davide Galassi Co-authored-by: Robert Hambrock --- .../primitives/consensus/beefy/src/lib.rs | 34 ++++++--- .../primitives/core/src/paired_crypto.rs | 76 ++++++++++++++++++- 2 files changed, 96 insertions(+), 14 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 5bdf8ce010a..e31c53237be 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -133,7 +133,7 @@ pub mod bls_crypto { ::Output: Into<[u8; 32]>, { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // `w3f-bls` library uses IETF hashing standard and as such does not expose // a choice of hash to field function. // We are directly calling into the library to avoid introducing new host call. // and because BeefyAuthorityId::verify is being called in the runtime so we don't have @@ -157,7 +157,7 @@ pub mod bls_crypto { pub mod ecdsa_bls_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; + use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair}; app_crypto!(ecdsa_bls377, KEY_TYPE); @@ -167,17 +167,24 @@ pub mod ecdsa_bls_crypto { /// Signature for a BEEFY authority using (ECDSA,BLS) as its crypto. pub type AuthoritySignature = Signature; - impl BeefyAuthorityId for AuthorityId + impl BeefyAuthorityId for AuthorityId where - ::Output: Into<[u8; 32]>, + H: Hash, + H::Output: Into<[u8; 32]>, { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // `w3f-bls` library uses IETF hashing standard and as such does not exposes - // a choice of hash to field function. - // We are directly calling into the library to avoid introducing new host call. - // and because BeefyAuthorityId::verify is being called in the runtime so we don't have - - EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + // We can not simply call + // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` + // because that invokes ECDSA default verification which perfoms Blake2b hash + // which we don't want. This is because ECDSA signatures are meant to be verified + // on Ethereum network where Keccak hasher is significantly cheaper than Blake2b. + // See Figure 3 of [OnSc21](https://www.scitepress.org/Papers/2021/106066/106066.pdf) + // for comparison. + EcdsaBlsPair::verify_with_hasher::( + signature.as_inner_ref(), + msg, + self.as_inner_ref(), + ) } } } @@ -257,6 +264,7 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. +// TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { /// Commit to information extracted from a finalized block @@ -507,11 +515,15 @@ mod tests { let msg = &b"test-message"[..]; let (pair, _) = ecdsa_bls_crypto::Pair::generate(); - let signature: ecdsa_bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + let signature: ecdsa_bls_crypto::Signature = + pair.as_inner_ref().sign_with_hasher::(&msg).into(); // Verification works if same hashing function is used when signing and verifying. assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); + // Verification doesn't work if we verify function provided by pair_crypto implementation + assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &pair.public())); + // Other public key doesn't work let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a97b657e757..edf6156f268 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -39,7 +39,13 @@ use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { - use crate::{bls377, crypto::CryptoTypeId, ecdsa}; + #[cfg(feature = "full_crypto")] + use crate::Hasher; + use crate::{ + bls377, + crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom}, + ecdsa, + }; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); @@ -71,6 +77,60 @@ pub mod ecdsa_bls377 { impl super::CryptoType for Pair { type Pair = Pair; } + + #[cfg(feature = "full_crypto")] + impl Pair { + /// Hashes the `message` with the specified [`Hasher`] before signing sith the ECDSA secret + /// component. + /// + /// The hasher does not affect the BLS12-377 component. This generates BLS12-377 Signature + /// according to IETF standard. + pub fn sign_with_hasher(&self, message: &[u8]) -> Signature + where + H: Hasher, + H::Out: Into<[u8; 32]>, + { + let msg_hash = H::hash(message).into(); + + let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE] + .copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref()); + raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..] + .copy_from_slice(self.right.sign(message).as_ref()); + ::Signature::unchecked_from(raw) + } + + /// Hashes the `message` with the specified [`Hasher`] before verifying with the ECDSA + /// public component. + /// + /// The hasher does not affect the the BLS12-377 component. This verifies whether the + /// BLS12-377 signature was hashed and signed according to IETF standard + pub fn verify_with_hasher(sig: &Signature, message: &[u8], public: &Public) -> bool + where + H: Hasher, + H::Out: Into<[u8; 32]>, + { + let msg_hash = H::hash(message).into(); + + let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else { + return false + }; + let Ok(left_sig) = sig.0[0..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else { + return false + }; + if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) { + return false + } + + let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else { + return false + }; + let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else { + return false + }; + bls377::Pair::verify(&right_sig, message.as_ref(), &right_pub) + } + } } /// Secure seed length. @@ -455,12 +515,12 @@ where #[cfg(all(test, feature = "bls-experimental"))] mod test { use super::*; - use crate::crypto::DEV_PHRASE; + use crate::{crypto::DEV_PHRASE, KeccakHasher}; use ecdsa_bls377::{Pair, Signature}; use crate::{bls377, ecdsa}; - #[test] + #[test] fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() { assert_eq!( ::Public::LEN, @@ -617,6 +677,16 @@ mod test { assert_eq!(cmp, public); } + #[test] + fn sign_and_verify_with_hasher_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign_with_hasher::(&message[..]); + + assert!(Pair::verify_with_hasher::(&signature, &message[..], &pair.public())); + } + #[test] fn signature_serialization_works() { let pair = -- GitLab From ae1bdcfb91a26c5f65c5ca534aa8a04523ca2277 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 14 Nov 2023 10:43:40 +0100 Subject: [PATCH 498/633] Fix `expect_pallet` benchmarks not relaying on hard-coded `frame_system` dependency version (#2288) ## Problem/Motivation The benchmark for the `ExpectPallet` XCM instruction uses a hard-coded version `4.0.0` for the `frame_system` pallet. Unfortunately, this doesn't work for the `polkadot-fellows/runtimes` repository, where we use dependencies from `crates.io`, e.g., [frame-system::23.0.0.0](https://github.com/polkadot-fellows/runtimes/blob/dd7f86f0d50064481ed0b7c0218494a5cfad997e/relay/kusama/Cargo.toml#L83). Closes: https://github.com/paritytech/polkadot-sdk/issues/2284 ## Solution This PR fixes the benchmarks that require pallet information and enables the runtime to provide the correct/custom pallet information. The default implementation provides `frame_system::Pallet` with index `0`, where the version is not hard-coded but read from the runtime. ## Local testing Added log for `T::valid_pallet` to the benchmarks like: ``` let valid_pallet = T::valid_pallet(); log::info!( target: "frame::benchmark::pallet", "valid_pallet: {}::{}::{}::{}::{}", valid_pallet.index, valid_pallet.module_name, valid_pallet.crate_version.major, valid_pallet.crate_version.minor, valid_pallet.crate_version.patch, ); ``` Run benchmarks for `westend`: ``` cargo run --bin=polkadot --features=runtime-benchmarks -- benchmark pallet --steps=2 --repeat=1 --extrinsic=* --heap-pages=4096 --json-file=./bench.json --chain=westend-dev --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs --pallet=pallet_xcm_benchmarks::generic --output=./polkadot/runtime/westend/src/weights/xcm ``` --- For actual `frame_system` version: ``` [package] name = "frame-system" version = "4.0.0-dev" ``` Log dump: ``` 2023-11-13 12:56:45 Starting benchmark: pallet_xcm_benchmarks::generic::query_pallet 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 2023-11-13 12:56:45 Starting benchmark: pallet_xcm_benchmarks::generic::expect_pallet 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 2023-11-13 12:56:45 valid_pallet: 0::frame_system::4::0::0 ``` For changed `frame_system` version: ``` [package] name = "frame-system" version = "5.1.3-dev" ``` Log dump: ``` 2023-11-13 12:51:51 Starting benchmark: pallet_xcm_benchmarks::generic::query_pallet 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 2023-11-13 12:51:51 Starting benchmark: pallet_xcm_benchmarks::generic::expect_pallet 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 2023-11-13 12:51:51 valid_pallet: 0::frame_system::5::1::3 ``` ## References Closes: https://github.com/paritytech/polkadot-sdk/issues/2284 --- .../src/generic/benchmarking.rs | 15 ++++++++------- .../xcm/pallet-xcm-benchmarks/src/generic/mod.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index 4a997666027..f1c48ba9b83 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -413,8 +413,9 @@ benchmarks! { executor.set_holding(expected_assets_in_holding.into()); } + let valid_pallet = T::valid_pallet(); let instruction = Instruction::QueryPallet { - module_name: b"frame_system".to_vec(), + module_name: valid_pallet.module_name.as_bytes().to_vec(), response_info: QueryResponseInfo { destination, query_id, max_weight }, }; let xcm = Xcm(vec![instruction]); @@ -428,13 +429,13 @@ benchmarks! { expect_pallet { let mut executor = new_executor::(Default::default()); - + let valid_pallet = T::valid_pallet(); let instruction = Instruction::ExpectPallet { - index: 0, - name: b"System".to_vec(), - module_name: b"frame_system".to_vec(), - crate_major: 4, - min_crate_minor: 0, + index: valid_pallet.index as u32, + name: valid_pallet.name.as_bytes().to_vec(), + module_name: valid_pallet.module_name.as_bytes().to_vec(), + crate_major: valid_pallet.crate_version.major.into(), + min_crate_minor: valid_pallet.crate_version.minor.into(), }; let xcm = Xcm(vec![instruction]); }: { diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs index cbdfa8d0112..11f7bba19a9 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mod.rs @@ -91,6 +91,18 @@ pub mod pallet { /// /// If set to `Err`, benchmarks which rely on a universal alias will be skipped. fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError>; + + /// Returns a valid pallet info for `ExpectPallet` or `QueryPallet` benchmark. + /// + /// By default returns `frame_system::Pallet` info with expected pallet index `0`. + fn valid_pallet() -> frame_support::traits::PalletInfoData { + frame_support::traits::PalletInfoData { + index: as frame_support::traits::PalletInfoAccess>::index(), + name: as frame_support::traits::PalletInfoAccess>::name(), + module_name: as frame_support::traits::PalletInfoAccess>::module_name(), + crate_version: as frame_support::traits::PalletInfoAccess>::crate_version(), + } + } } #[pallet::pallet] -- GitLab From 54ca4f131b82f45b0c2d1f316d65d7c97ad9a99b Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 14 Nov 2023 15:01:15 +0400 Subject: [PATCH 499/633] Delete undecodable Westend Asset Hub `Balances::Hold` and `Nfts::ItemMetadataOf` (#2309) Closes https://github.com/paritytech/polkadot-sdk/issues/2241 See issue comments for more details about this storage. --- .../assets/asset-hub-westend/src/lib.rs | 78 ++++++++++++++++++- 1 file changed, 75 insertions(+), 3 deletions(-) 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 d88aa2607e2..cd17b9d86f7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -54,7 +54,7 @@ use frame_system::{ EnsureRoot, EnsureSigned, EnsureSignedBy, }; use pallet_asset_conversion_tx_payment::AssetConversionAdapter; -use pallet_nfts::PalletFeatures; +use pallet_nfts::{DestroyWitness, PalletFeatures}; use pallet_xcm::EnsureXcm; pub use parachains_common as common; use parachains_common::{ @@ -69,7 +69,9 @@ 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}, + traits::{ + AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Saturating, Verify, + }, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, Permill, RuntimeDebug, }; @@ -944,8 +946,79 @@ pub type Migrations = ( pallet_multisig::migrations::v1::MigrateToV1, // unreleased InitStorageVersions, + // unreleased + DeleteUndecodableStorage, ); +/// Asset Hub Westend has some undecodable storage, delete it. +/// See for more info. +/// +/// First we remove the bad Hold, then the bad NFT collection. +pub struct DeleteUndecodableStorage; + +impl frame_support::traits::OnRuntimeUpgrade for DeleteUndecodableStorage { + fn on_runtime_upgrade() -> Weight { + use sp_core::crypto::Ss58Codec; + + let mut writes = 0; + + // Remove Holds for account with undecodable hold + // Westend doesn't have any HoldReasons implemented yet, so it's safe to just blanket remove + // any for this account. + match AccountId::from_ss58check("5GCCJthVSwNXRpbeg44gysJUx9vzjdGdfWhioeM7gCg6VyXf") { + Ok(a) => { + log::info!("Removing holds for account with bad hold"); + pallet_balances::Holds::::remove(a); + writes.saturating_inc(); + }, + Err(_) => { + log::error!("CleanupUndecodableStorage: Somehow failed to convert valid SS58 address into an AccountId!"); + }, + }; + + // Destroy undecodable NFT item 1 + writes.saturating_inc(); + match pallet_nfts::Pallet::::do_burn(3, 1, |_| Ok(())) { + Ok(_) => { + log::info!("Destroyed undecodable NFT item 1"); + }, + Err(e) => { + log::error!("Failed to destroy undecodable NFT item: {:?}", e); + return ::DbWeight::get().reads_writes(0, writes) + }, + } + + // Destroy undecodable NFT item 2 + writes.saturating_inc(); + match pallet_nfts::Pallet::::do_burn(3, 2, |_| Ok(())) { + Ok(_) => { + log::info!("Destroyed undecodable NFT item 2"); + }, + Err(e) => { + log::error!("Failed to destroy undecodable NFT item: {:?}", e); + return ::DbWeight::get().reads_writes(0, writes) + }, + } + + // Finally, we can destroy the collection + writes.saturating_inc(); + match pallet_nfts::Pallet::::do_destroy_collection( + 3, + DestroyWitness { attributes: 0, item_metadatas: 1, item_configs: 0 }, + None, + ) { + Ok(_) => { + log::info!("Destroyed undecodable NFT collection"); + }, + Err(e) => { + log::error!("Failed to destroy undecodable NFT collection: {:?}", e); + }, + }; + + ::DbWeight::get().reads_writes(0, writes) + } +} + /// Migration to initialize storage versions for pallets added after genesis. /// /// Ideally this would be done automatically (see @@ -957,7 +1030,6 @@ 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; -- GitLab From a393cfcb28282cd2147134b8968fba3b41681ea9 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux Date: Tue, 14 Nov 2023 12:57:39 +0100 Subject: [PATCH 500/633] Add details in `--dev` cli flag documentation (#2305) add details in `--dev` flag to tell that it disables local peer discovery ### Context When adding automated end-to-end tests, we replaced `--dev` by ``` `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, `--alice`, and `--tmp` flags ``` as stated in the command line documentation. But the tests started failing due to the nodes connecting to each other. ### Fix This PR includes additional command line documentation to explain more in detail what `--dev` flag inludes. --- substrate/client/cli/src/params/shared_params.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/client/cli/src/params/shared_params.rs b/substrate/client/cli/src/params/shared_params.rs index 6419e15c62a..465372fba17 100644 --- a/substrate/client/cli/src/params/shared_params.rs +++ b/substrate/client/cli/src/params/shared_params.rs @@ -35,6 +35,7 @@ pub struct SharedParams { /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. + /// It also disables local peer discovery (see --no-mdns and --discover-local) #[arg(long, conflicts_with_all = &["chain"])] pub dev: bool, -- GitLab From 39cc95740aa03f53a0e8bfb8537f0ddb5fa3e19e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 14 Nov 2023 14:47:04 +0200 Subject: [PATCH 501/633] xcm-emulator: add Rococo<>Westend bridge and add tests for assets transfers over the bridge (#2251) - switch from Rococo<>Wococo to Rococo<>Westend bridge - add bidirectional simple tests - remove Wococo chains from xcm-emulator - added tests for assets transfers over Rococo<>Westend bridge fixes https://github.com/paritytech/parity-bridges-common/issues/2405 --- Cargo.lock | 78 +------ Cargo.toml | 5 +- .../assets/asset-hub-rococo/src/lib.rs | 4 +- .../assets/asset-hub-westend/src/lib.rs | 4 +- .../assets/asset-hub-wococo/Cargo.toml | 26 --- .../assets/asset-hub-wococo/src/lib.rs | 53 ----- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../bridges/bridge-hub-westend/src/genesis.rs | 2 +- .../bridges/bridge-hub-westend/src/lib.rs | 2 +- .../bridges/bridge-hub-wococo/Cargo.toml | 25 -- .../bridges/bridge-hub-wococo/src/lib.rs | 47 ---- .../parachains/testing/penpal/src/lib.rs | 2 +- .../emulated/chains/relays/wococo/Cargo.toml | 30 --- .../emulated/chains/relays/wococo/src/lib.rs | 46 ---- .../emulated/common/src/impls.rs | 151 ++++++++++-- .../Cargo.toml | 10 +- .../src/lib.rs | 60 ++--- .../networks/wococo-system/Cargo.toml | 16 -- .../networks/wococo-system/src/lib.rs | 50 ---- .../bridges/bridge-hub-rococo/Cargo.toml | 6 +- .../bridges/bridge-hub-rococo/src/lib.rs | 23 +- .../src/tests/asset_transfers.rs | 219 ++++++++++++++++++ .../bridge-hub-rococo/src/tests/mod.rs | 3 +- .../src/tests/{example.rs => send_xcm.rs} | 28 +-- .../bridges/bridge-hub-westend/Cargo.toml | 6 +- .../bridges/bridge-hub-westend/src/lib.rs | 27 ++- .../src/tests/asset_transfers.rs | 218 +++++++++++++++++ .../bridge-hub-westend/src/tests/mod.rs | 3 +- .../src/tests/{example.rs => send_xcm.rs} | 30 ++- .../bridge-hub-westend/src/tests/teleport.rs | 2 +- 30 files changed, 710 insertions(+), 468 deletions(-) delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs rename cumulus/parachains/integration-tests/emulated/networks/{rococo-wococo-system => rococo-westend-system}/Cargo.toml (57%) rename cumulus/parachains/integration-tests/emulated/networks/{rococo-wococo-system => rococo-westend-system}/src/lib.rs (57%) delete mode 100644 cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml delete mode 100644 cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs rename cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/{example.rs => send_xcm.rs} (77%) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs rename cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/{example.rs => send_xcm.rs} (71%) diff --git a/Cargo.lock b/Cargo.lock index 4a45d5c602e..32d9099b386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1119,22 +1119,6 @@ dependencies = [ "westend-runtime-constants", ] -[[package]] -name = "asset-hub-wococo-emulated-chain" -version = "0.0.0" -dependencies = [ - "asset-hub-rococo-emulated-chain", - "asset-hub-rococo-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "serde_json", - "sp-core", - "sp-runtime", - "wococo-emulated-chain", -] - [[package]] name = "asset-test-utils" version = "1.0.0" @@ -2202,12 +2186,14 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", + "pallet-assets", + "pallet-balances", "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", - "rococo-wococo-system-emulated-network", + "rococo-westend-system-emulated-network", "staging-xcm", "staging-xcm-executor", ] @@ -2370,14 +2356,16 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", + "pallet-assets", + "pallet-balances", "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", + "rococo-westend-system-emulated-network", "staging-xcm", "staging-xcm-executor", - "westend-system-emulated-network", ] [[package]] @@ -2463,21 +2451,6 @@ dependencies = [ "westend-runtime-constants", ] -[[package]] -name = "bridge-hub-wococo-emulated-chain" -version = "0.0.0" -dependencies = [ - "bridge-hub-rococo-emulated-chain", - "bridge-hub-rococo-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "serde_json", - "sp-core", - "sp-runtime", -] - [[package]] name = "bridge-runtime-common" version = "0.1.0" @@ -14578,16 +14551,16 @@ dependencies = [ ] [[package]] -name = "rococo-wococo-system-emulated-network" +name = "rococo-westend-system-emulated-network" version = "0.0.0" dependencies = [ "asset-hub-rococo-emulated-chain", - "asset-hub-wococo-emulated-chain", + "asset-hub-westend-emulated-chain", "bridge-hub-rococo-emulated-chain", - "bridge-hub-wococo-emulated-chain", + "bridge-hub-westend-emulated-chain", "emulated-integration-tests-common", "rococo-emulated-chain", - "wococo-emulated-chain", + "westend-emulated-chain", ] [[package]] @@ -21236,37 +21209,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wococo-emulated-chain" -version = "0.0.0" -dependencies = [ - "emulated-integration-tests-common", - "pallet-im-online", - "parachains-common", - "polkadot-primitives", - "rococo-emulated-chain", - "rococo-runtime", - "rococo-runtime-constants", - "sc-consensus-grandpa", - "serde_json", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core", - "sp-runtime", -] - -[[package]] -name = "wococo-system-emulated-network" -version = "0.0.0" -dependencies = [ - "asset-hub-wococo-emulated-chain", - "bridge-hub-wococo-emulated-chain", - "emulated-integration-tests-common", - "penpal-emulated-chain", - "wococo-emulated-chain", -] - [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 30445bd5945..15a7d5c35bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,16 +71,13 @@ members = [ "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/common", "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", - "cumulus/parachains/integration-tests/emulated/chains/relays/wococo", "cumulus/parachains/integration-tests/emulated/chains/relays/westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo", - "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/networks/rococo-system", - "cumulus/parachains/integration-tests/emulated/networks/wococo-system", - "cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system", + "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system", "cumulus/parachains/integration-tests/emulated/networks/westend-system", "cumulus/parachains/pallets/collective-content", "cumulus/parachains/pallets/parachain-info", diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index f94c4c3d255..1ed22b3cc4f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,7 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, + xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -53,3 +54,4 @@ decl_test_parachains! { impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo, false); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 73d777247a5..4dcdb613ac2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,7 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, + xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -53,3 +54,4 @@ decl_test_parachains! { impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend, false); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml deleted file mode 100644 index 0f212c15999..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "asset-hub-wococo-emulated-chain" -version = "0.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Wococo emulated chain" -publish = false - -[dependencies] -serde_json = "1.0.104" - -# Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } - -# Polakadot -parachains-common = { path = "../../../../../../../parachains/common" } - -# Cumulus -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -asset-hub-rococo-runtime = { path = "../../../../../../runtimes/assets/asset-hub-rococo" } -wococo-emulated-chain = { path = "../../../relays/wococo" } -asset-hub-rococo-emulated-chain = { path = "../asset-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs deleted file mode 100644 index 38a6ece3472..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs +++ /dev/null @@ -1,53 +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. - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, -}; -use wococo_emulated_chain::Wococo; - -// AssetHubWococo Parachain declaration -decl_test_parachains! { - pub struct AssetHubWococo { - genesis = asset_hub_rococo_emulated_chain::genesis::genesis(), - on_init = { - asset_hub_rococo_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_rococo_runtime, - core = { - XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, - LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, - }, - pallets = { - 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, - } - }, -} - -// AssetHubWococo implementation -impl_accounts_helpers_for_parachain!(AssetHubWococo); -impl_assert_events_helpers_for_parachain!(AssetHubWococo, false); -impl_assets_helpers_for_parachain!(AssetHubWococo, Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index f4557021f62..ea0c9513abc 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - xcm_emulator::decl_test_parachains, + impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubRococo Parachain declaration diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs index cd578d6862f..2eb7e0ddbd2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -22,7 +22,7 @@ use emulated_integration_tests_common::{ }; use parachains_common::Balance; -pub const PARA_ID: u32 = 1013; +pub const PARA_ID: u32 = 1002; pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index 1f1126d4565..4a130ac1f27 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - xcm_emulator::decl_test_parachains, + impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubWestend Parachain declaration diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml deleted file mode 100644 index 0b02730a50c..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "bridge-hub-wococo-emulated-chain" -version = "0.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Wococo emulated chain" -publish = false - -[dependencies] -serde_json = "1.0.104" - -# Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } - -# Polakadot -parachains-common = { path = "../../../../../../../parachains/common" } - -# Cumulus -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -bridge-hub-rococo-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-rococo" } -bridge-hub-rococo-emulated-chain = { path = "../bridge-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs deleted file mode 100644 index e643f104aa3..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs +++ /dev/null @@ -1,47 +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. - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - xcm_emulator::decl_test_parachains, -}; - -// BridgeHubWococo Parachain declaration -decl_test_parachains! { - pub struct BridgeHubWococo { - genesis = bridge_hub_rococo_emulated_chain::genesis::genesis(), - on_init = { - bridge_hub_rococo_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_rococo_runtime, - core = { - XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, - 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, - } - }, -} - -// BridgeHubWococo implementation -impl_accounts_helpers_for_parachain!(BridgeHubWococo); -impl_assert_events_helpers_for_parachain!(BridgeHubWococo, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 537f96f45b4..f9a422bfcba 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -22,7 +22,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml deleted file mode 100644 index 51a87954b8c..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "wococo-emulated-chain" -version = "0.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Wococo emulated chain" -publish = false - -[dependencies] -serde_json = "1.0.104" - -# Substrate -sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } -beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../../../substrate/primitives/consensus/beefy" } -grandpa = { package = "sc-consensus-grandpa", path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } -pallet-im-online = { path = "../../../../../../../substrate/frame/im-online", default-features = false } - -# Polkadot -polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } -rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants", default-features = false } -rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } - -# Cumulus -parachains-common = { path = "../../../../../../parachains/common" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -rococo-emulated-chain = { path = "../rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs deleted file mode 100644 index a04deee330f..00000000000 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/wococo/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, - impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, - xcm_emulator::decl_test_relay_chains, -}; - -// Wococo declaration -decl_test_relay_chains! { - #[api_version(8)] - pub struct Wococo { - genesis = rococo_emulated_chain::genesis::genesis(), - on_init = (), - runtime = rococo_runtime, - core = { - SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, - }, - pallets = { - XcmPallet: rococo_runtime::XcmPallet, - Sudo: rococo_runtime::Sudo, - Balances: rococo_runtime::Balances, - Hrmp: rococo_runtime::Hrmp, - } - }, -} - -// Wococo implementation -impl_accounts_helpers_for_relay_chain!(Wococo); -impl_assert_events_helpers_for_relay_chain!(Wococo); -impl_hrmp_channels_helpers_for_relay_chain!(Wococo); -impl_send_transact_helpers_for_relay_chain!(Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 82f27b93200..8c94df6d888 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -47,7 +47,8 @@ pub use xcm::{ pub use cumulus_pallet_parachain_system; pub use cumulus_pallet_xcmp_queue; pub use cumulus_primitives_core::{ - relay_chain::HrmpChannelId, DmpMessageHandler, ParaId, XcmpMessageHandler, + relay_chain::HrmpChannelId, DmpMessageHandler, Junction, Junctions, NetworkId, ParaId, + XcmpMessageHandler, }; pub use parachains_common::{AccountId, Balance}; pub use xcm_emulator::{ @@ -62,11 +63,14 @@ use bp_messages::{ LaneId, MessageKey, OutboundLaneData, }; use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; -pub use pallet_bridge_messages::Instance2 as BridgeMessagesInstance2; -use pallet_bridge_messages::{Config, Instance1, OutboundLanes, Pallet}; +use pallet_bridge_messages::{Config, OutboundLanes, Pallet}; +pub use pallet_bridge_messages::{ + Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2, + Instance3 as BridgeMessagesInstance3, +}; -pub struct BridgeHubMessageHandler { - _marker: std::marker::PhantomData<(S, T, I)>, +pub struct BridgeHubMessageHandler { + _marker: std::marker::PhantomData<(S, SI, T, TI)>, } struct LaneIdWrapper(LaneId); @@ -83,13 +87,14 @@ impl From for LaneIdWrapper { } } -impl BridgeMessageHandler for BridgeHubMessageHandler +impl BridgeMessageHandler for BridgeHubMessageHandler where - S: Config, - T: Config, - I: 'static, - >::InboundPayload: From>, - >::MessageDispatch: + S: Config, + SI: 'static, + T: Config, + TI: 'static, + >::InboundPayload: From>, + >::MessageDispatch: MessageDispatch, { fn get_source_outbound_messages() -> Vec { @@ -100,16 +105,13 @@ where // collect messages from `OutboundMessages` for each active outbound lane in the source for lane in active_lanes { - let latest_generated_nonce = - OutboundLanes::::get(lane).latest_generated_nonce; - let latest_received_nonce = - OutboundLanes::::get(lane).latest_received_nonce; + let latest_generated_nonce = OutboundLanes::::get(lane).latest_generated_nonce; + let latest_received_nonce = OutboundLanes::::get(lane).latest_received_nonce; (latest_received_nonce + 1..=latest_generated_nonce).for_each(|nonce| { - let encoded_payload: Vec = - Pallet::::outbound_message_data(*lane, nonce) - .expect("Bridge message does not exist") - .into(); + let encoded_payload: Vec = Pallet::::outbound_message_data(*lane, nonce) + .expect("Bridge message does not exist") + .into(); let payload = Vec::::decode(&mut &encoded_payload[..]) .expect("Decodign XCM message failed"); let id: u32 = LaneIdWrapper(*lane).into(); @@ -133,9 +135,9 @@ where // Directly dispatch outbound messages assuming everything is correct // and bypassing the `Relayers` and `InboundLane` logic - let dispatch_result = TargetMessageDispatch::::dispatch(DispatchMessage { + let dispatch_result = TargetMessageDispatch::::dispatch(DispatchMessage { key: MessageKey { lane_id, nonce }, - data: DispatchMessageData::> { payload }, + data: DispatchMessageData::> { payload }, }); let result = match dispatch_result.dispatch_level_result { @@ -151,14 +153,14 @@ where } fn notify_source_message_delivery(lane_id: u32) { - let data = OutboundLanes::::get(LaneIdWrapper::from(lane_id).0); + let data = OutboundLanes::::get(LaneIdWrapper::from(lane_id).0); let new_data = OutboundLaneData { oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1, latest_received_nonce: data.latest_received_nonce + 1, ..data }; - OutboundLanes::::insert(LaneIdWrapper::from(lane_id).0, new_data); + OutboundLanes::::insert(LaneIdWrapper::from(lane_id).0, new_data); } } @@ -392,6 +394,23 @@ macro_rules! impl_accounts_helpers_for_parachain { } }); } + + /// Return local sovereign account of `para_id` on other `network_id` + pub fn sovereign_account_of_parachain_on_other_global_consensus( + network_id: $crate::impls::NetworkId, + para_id: $crate::impls::ParaId, + ) -> $crate::impls::AccountId { + let remote_location = $crate::impls::MultiLocation { + parents: 2, + interior: $crate::impls::Junctions::X2( + $crate::impls::Junction::GlobalConsensus(network_id), + $crate::impls::Junction::Parachain(para_id.into()), + ), + }; + ::execute_with(|| { + Self::sovereign_account_id_of(remote_location) + }) + } } } }; @@ -614,7 +633,9 @@ macro_rules! impl_assets_helpers_for_parachain { $crate::impls::assert_expected_events!( Self, vec![ - RuntimeEvent::::Assets($crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }) => { + RuntimeEvent::::Assets( + $crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount } + ) => { asset_id: *asset_id == id, owner: *owner == beneficiary.clone().into(), amount: *amount == amount_to_mint, @@ -687,3 +708,85 @@ macro_rules! impl_assets_helpers_for_parachain { } }; } + +#[macro_export] +macro_rules! impl_foreign_assets_helpers_for_parachain { + ( $chain:ident, $relay_chain:ident ) => { + $crate::impls::paste::paste! { + impl $chain { + /// Create foreign assets using sudo `ForeignAssets::force_create()` + pub fn force_create_foreign_asset( + id: $crate::impls::MultiLocation, + owner: $crate::impls::AccountId, + is_sufficient: bool, + min_balance: u128, + prefund_accounts: Vec<($crate::impls::AccountId, u128)>, + ) { + use $crate::impls::Inspect; + let sudo_origin = <$chain as $crate::impls::Chain>::RuntimeOrigin::root(); + ::execute_with(|| { + $crate::impls::assert_ok!( + ]>::ForeignAssets::force_create( + sudo_origin, + id, + owner.clone().into(), + is_sufficient, + min_balance, + ) + ); + assert!(]>::ForeignAssets::asset_exists(id)); + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + $crate::impls::assert_expected_events!( + Self, + vec![ + RuntimeEvent::::ForeignAssets( + $crate::impls::pallet_assets::Event::ForceCreated { + asset_id, + .. + } + ) => { asset_id: *asset_id == id, }, + ] + ); + }); + for (beneficiary, amount) in prefund_accounts.into_iter() { + let signed_origin = + <$chain as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone()); + Self::mint_foreign_asset(signed_origin, id, beneficiary, amount); + } + } + + /// Mint assets making use of the ForeignAssets pallet-assets instance + pub fn mint_foreign_asset( + signed_origin: ::RuntimeOrigin, + id: $crate::impls::MultiLocation, + beneficiary: $crate::impls::AccountId, + amount_to_mint: u128, + ) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::ForeignAssets::mint( + signed_origin, + id.into(), + beneficiary.clone().into(), + amount_to_mint + )); + + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + + $crate::impls::assert_expected_events!( + Self, + vec![ + RuntimeEvent::::ForeignAssets( + $crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount } + ) => { + asset_id: *asset_id == id, + owner: *owner == beneficiary.clone().into(), + amount: *amount == amount_to_mint, + }, + ] + ); + }); + } + } + } + }; +} diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml similarity index 57% rename from cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml rename to cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml index 53a6f0840a5..34713f5b48e 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml @@ -1,18 +1,18 @@ [package] -name = "rococo-wococo-system-emulated-network" +name = "rococo-westend-system-emulated-network" version = "0.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" -description = "Rococo<>Wococo emulated bridged network" +description = "Rococo<>Westend emulated bridged network" publish = false [dependencies] # Cumulus emulated-integration-tests-common = { path = "../../common", default-features = false } rococo-emulated-chain = { path = "../../chains/relays/rococo" } -wococo-emulated-chain = { path = "../../chains/relays/wococo" } +westend-emulated-chain = { path = "../../chains/relays/westend" } asset-hub-rococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-rococo" } -asset-hub-wococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-wococo" } +asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } bridge-hub-rococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-rococo" } -bridge-hub-wococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-wococo" } +bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs similarity index 57% rename from cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs rename to cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs index e20dcfa6b32..b03ff692b95 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-wococo-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs @@ -14,23 +14,23 @@ // limitations under the License. pub use asset_hub_rococo_emulated_chain; -pub use asset_hub_wococo_emulated_chain; +pub use asset_hub_westend_emulated_chain; pub use bridge_hub_rococo_emulated_chain; -pub use bridge_hub_wococo_emulated_chain; +pub use bridge_hub_westend_emulated_chain; pub use rococo_emulated_chain; -pub use wococo_emulated_chain; +pub use westend_emulated_chain; use asset_hub_rococo_emulated_chain::AssetHubRococo; -use asset_hub_wococo_emulated_chain::AssetHubWococo; +use asset_hub_westend_emulated_chain::AssetHubWestend; use bridge_hub_rococo_emulated_chain::BridgeHubRococo; -use bridge_hub_wococo_emulated_chain::BridgeHubWococo; +use bridge_hub_westend_emulated_chain::BridgeHubWestend; use rococo_emulated_chain::Rococo; -use wococo_emulated_chain::Wococo; +use westend_emulated_chain::Westend; // Cumulus use emulated_integration_tests_common::{ accounts::{ALICE, BOB}, - impls::{BridgeHubMessageHandler, BridgeMessagesInstance2}, + impls::{BridgeHubMessageHandler, BridgeMessagesInstance1, BridgeMessagesInstance3}, xcm_emulator::{ decl_test_bridges, decl_test_networks, decl_test_sender_receiver_accounts_parameter_types, Chain, @@ -44,51 +44,53 @@ decl_test_networks! { AssetHubRococo, BridgeHubRococo, ], - bridge = RococoWococoMockBridge + bridge = RococoWestendMockBridge }, - pub struct WococoMockNet { - relay_chain = Wococo, + pub struct WestendMockNet { + relay_chain = Westend, parachains = vec![ - AssetHubWococo, - BridgeHubWococo, + AssetHubWestend, + BridgeHubWestend, ], - bridge = WococoRococoMockBridge + bridge = WestendRococoMockBridge }, } decl_test_bridges! { - pub struct RococoWococoMockBridge { + pub struct RococoWestendMockBridge { source = BridgeHubRococoPara, - target = BridgeHubWococoPara, - handler = RococoWococoMessageHandler + target = BridgeHubWestendPara, + handler = RococoWestendMessageHandler }, - pub struct WococoRococoMockBridge { - source = BridgeHubWococoPara, + pub struct WestendRococoMockBridge { + source = BridgeHubWestendPara, target = BridgeHubRococoPara, - handler = WococoRococoMessageHandler + handler = WestendRococoMessageHandler } } type BridgeHubRococoRuntime = ::Runtime; -type BridgeHubWococoRuntime = ::Runtime; +type BridgeHubWestendRuntime = ::Runtime; -pub type RococoWococoMessageHandler = BridgeHubMessageHandler< +pub type RococoWestendMessageHandler = BridgeHubMessageHandler< BridgeHubRococoRuntime, - BridgeHubWococoRuntime, - BridgeMessagesInstance2, + BridgeMessagesInstance3, + BridgeHubWestendRuntime, + BridgeMessagesInstance1, >; -pub type WococoRococoMessageHandler = BridgeHubMessageHandler< - BridgeHubWococoRuntime, +pub type WestendRococoMessageHandler = BridgeHubMessageHandler< + BridgeHubWestendRuntime, + BridgeMessagesInstance1, BridgeHubRococoRuntime, - BridgeMessagesInstance2, + BridgeMessagesInstance3, >; decl_test_sender_receiver_accounts_parameter_types! { RococoRelay { sender: ALICE, receiver: BOB }, AssetHubRococoPara { sender: ALICE, receiver: BOB }, BridgeHubRococoPara { sender: ALICE, receiver: BOB }, - WococoRelay { sender: ALICE, receiver: BOB }, - AssetHubWococoPara { sender: ALICE, receiver: BOB }, - BridgeHubWococoPara { sender: ALICE, receiver: BOB } + WestendRelay { sender: ALICE, receiver: BOB }, + AssetHubWestendPara { sender: ALICE, receiver: BOB }, + BridgeHubWestendPara { sender: ALICE, receiver: BOB } } diff --git a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml deleted file mode 100644 index a596617e82b..00000000000 --- a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "wococo-system-emulated-network" -version = "0.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Wococo System emulated network" -publish = false - -[dependencies] -# Cumulus -emulated-integration-tests-common = { path = "../../common", default-features = false } -wococo-emulated-chain = { path = "../../chains/relays/wococo" } -asset-hub-wococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-wococo" } -bridge-hub-wococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-wococo" } -penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs deleted file mode 100644 index 5369afe7dff..00000000000 --- a/cumulus/parachains/integration-tests/emulated/networks/wococo-system/src/lib.rs +++ /dev/null @@ -1,50 +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 asset_hub_wococo_emulated_chain; -pub use bridge_hub_wococo_emulated_chain; -pub use wococo_emulated_chain; - -use asset_hub_wococo_emulated_chain::AssetHubWococo; -use bridge_hub_wococo_emulated_chain::BridgeHubWococo; -use penpal_emulated_chain::{PenpalA, PenpalB}; -use wococo_emulated_chain::Wococo; - -// Cumulus -use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, -}; - -decl_test_networks! { - pub struct WococoMockNet { - relay_chain = Wococo, - parachains = vec![ - AssetHubWococo, - BridgeHubWococo, - PenpalA, - PenpalB, - ], - bridge = () - }, -} - -decl_test_sender_receiver_accounts_parameter_types! { - WococoRelay { sender: ALICE, receiver: BOB }, - AssetHubWococoPara { sender: ALICE, receiver: BOB }, - BridgeHubWococoPara { sender: ALICE, receiver: BOB }, - PenpalAPara { sender: ALICE, receiver: BOB }, - PenpalBPara { sender: ALICE, receiver: BOB } -} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 035d9c10793..00e3af2e4ff 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -11,7 +11,9 @@ publish = false codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } # Substrate -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } # Polkadot @@ -30,4 +32,4 @@ cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", def cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} bridge-hub-rococo-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } emulated-integration-tests-common = { path = "../../../common", default-features = false} -rococo-wococo-system-emulated-network ={ path = "../../../networks/rococo-wococo-system" } +rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 19e10d23bbb..53665437887 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, - NetworkId::{Rococo as RococoId, Wococo as WococoId}, + NetworkId::{Rococo as RococoId, Westend as WestendId}, }, }; @@ -30,6 +30,8 @@ pub use bp_messages::LaneId; // Cumulus pub use emulated_integration_tests_common::{ + accounts::ALICE, + impls::Inspect, test_parachain_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, @@ -39,17 +41,22 @@ pub use emulated_integration_tests_common::{ PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; pub use parachains_common::{AccountId, Balance}; -pub use rococo_wococo_system_emulated_network::{ +pub use rococo_westend_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + asset_hub_westend_emulated_chain::{ + genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + }, bridge_hub_rococo_emulated_chain::{ genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, }, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + rococo_emulated_chain::RococoRelayPallet as RococoPallet, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, - AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWococoPara as AssetHubWococo, - BridgeHubRococoPara as BridgeHubRococo, BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, - BridgeHubRococoParaSender as BridgeHubRococoSender, BridgeHubWococoPara as BridgeHubWococo, - RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, - RococoRelaySender as RococoSender, + AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, + AssetHubWestendParaReceiver as AssetHubWestendReceiver, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaSender as BridgeHubRococoSender, BridgeHubWestendPara as BridgeHubWestend, + RococoRelay as Rococo, }; pub const ASSET_ID: u32 = 1; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs new file mode 100644 index 00000000000..c55613f2826 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -0,0 +1,219 @@ +// 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 send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: MultiLocation, amount: u128) { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + let asset_hub_westend_para_id = AssetHubWestend::para_id().into(); + let destination = MultiLocation { + parents: 2, + interior: X2(GlobalConsensus(NetworkId::Westend), Parachain(asset_hub_westend_para_id)), + }; + let beneficiary_id = AssetHubWestendReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + // fund the AHR's SA on BHR for paying bridge transport fees + let ahr_as_seen_by_bhr = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); + let sov_ahr_on_bhr = BridgeHubRococo::sovereign_account_id_of(ahr_as_seen_by_bhr); + BridgeHubRococo::fund_accounts(vec![(sov_ahr_on_bhr.into(), 10_000_000_000_000u128)]); + + AssetHubRococo::execute_with(|| { + assert_ok!( + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + ); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeWestendMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + // message dispatched successfully + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); +} + +#[test] +fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { + let roc_at_asset_hub_rococo: MultiLocation = Parent.into(); + let roc_at_asset_hub_westend = + MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Rococo)) }; + let owner: AccountId = AssetHubWestend::account_id_of(ALICE); + AssetHubWestend::force_create_foreign_asset( + roc_at_asset_hub_westend, + owner, + true, + ASSET_MIN_BALANCE, + vec![], + ); + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Westend, + AssetHubWestend::para_id(), + ); + + let rocs_in_reserve_on_ahr_before = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + let sender_rocs_before = + ::account_data_of(AssetHubRococoSender::get()).free; + let receiver_rocs_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) + }); + + let amount = ASSET_HUB_ROCOCO_ED * 1_000; + send_asset_from_asset_hub_rococo_to_asset_hub_westend(roc_at_asset_hub_rococo, amount); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // issue ROCs on AHW + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == roc_at_asset_hub_rococo, + owner: *owner == AssetHubWestendReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_rocs_after = + ::account_data_of(AssetHubRococoSender::get()).free; + let receiver_rocs_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) + }); + let rocs_in_reserve_on_ahr_after = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + + // Sender's balance is reduced + assert!(sender_rocs_before > sender_rocs_after); + // Receiver's balance is increased + assert!(receiver_rocs_after > receiver_rocs_before); + // Reserve balance is reduced by sent amount + assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount); +} + +#[test] +fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { + let prefund_amount = 10_000_000_000_000u128; + let wnd_at_asset_hub_rococo = + MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Westend)) }; + let owner: AccountId = AssetHubWestend::account_id_of(ALICE); + AssetHubRococo::force_create_foreign_asset( + wnd_at_asset_hub_rococo, + owner, + true, + ASSET_MIN_BALANCE, + vec![(AssetHubRococoSender::get(), prefund_amount)], + ); + + // fund the AHR's SA on AHW with the WND tokens held in reserve + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Rococo, + AssetHubRococo::para_id(), + ); + AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]); + + let wnds_in_reserve_on_ahw_before = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + assert_eq!(wnds_in_reserve_on_ahw_before, prefund_amount); + let sender_wnds_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoSender::get()) + }); + assert_eq!(sender_wnds_before, prefund_amount); + let receiver_wnds_before = + ::account_data_of(AssetHubWestendReceiver::get()).free; + + let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000; + send_asset_from_asset_hub_rococo_to_asset_hub_westend(wnd_at_asset_hub_rococo, amount_to_send); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // WND is withdrawn from AHR's SA on AHW + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_ahr_on_ahw, + amount: *amount == amount_to_send, + }, + // WNDs deposited to beneficiary + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == AssetHubWestendReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_wnds_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoSender::get()) + }); + let receiver_wnds_after = + ::account_data_of(AssetHubWestendReceiver::get()).free; + let wnds_in_reserve_on_ahw_after = + ::account_data_of(sov_ahr_on_ahw).free; + + // Sender's balance is reduced + assert!(sender_wnds_before > sender_wnds_after); + // Receiver's balance is increased + assert!(receiver_wnds_after > receiver_wnds_before); + // Reserve balance is reduced by sent amount + assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index 1eef05c6b92..4e2ef1434fd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -13,5 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod example; +mod asset_transfers; +mod send_xcm; mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs similarity index 77% rename from cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/example.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 35cfa394174..4e61f7ce0dd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -16,7 +16,7 @@ use crate::*; #[test] -fn example() { +fn send_xcm_from_rococo_relay_to_westend_asset_hub() { // Init tests variables // XcmPallet send arguments let sudo_origin = ::RuntimeOrigin::root(); @@ -29,13 +29,13 @@ fn example() { let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { - network: WococoId, - destination: X1(Parachain(AssetHubWococo::para_id().into())), + network: WestendId, + destination: X1(Parachain(AssetHubWestend::para_id().into())), xcm: remote_xcm, }, ])); - //Rococo Global Consensus + // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { assert_ok!(::XcmPallet::send( @@ -64,32 +64,32 @@ fn example() { success: true, .. }) => {}, - RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted { - lane_id: LaneId([0, 0, 0, 1]), + RuntimeEvent::BridgeWestendMessages(pallet_bridge_messages::Event::MessageAccepted { + lane_id: LaneId([0, 0, 0, 2]), nonce: 1, }) => {}, ] ); }); - // Wococo GLobal Consensus + // Westend Global Consensus // Receive XCM message in Bridge Hub target Parachain - BridgeHubWococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - BridgeHubWococo, + BridgeHubWestend, vec![ RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, ] ); }); - // Receive embeded XCM message within `ExportMessage` in Parachain destination - AssetHubWococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + // Receive embedded XCM message within `ExportMessage` in Parachain destination + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - AssetHubWococo, + AssetHubWestend, vec![ RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { .. diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 62b969b682f..e5b1fce5f2b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -11,7 +11,9 @@ publish = false codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } # Substrate -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false} +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } # Polkadot @@ -30,4 +32,4 @@ cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", def cumulus-pallet-dmp-queue = { path = "../../../../../../pallets/dmp-queue", default-features = false} bridge-hub-westend-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } emulated-integration-tests-common = { path = "../../../common", default-features = false} -westend-system-emulated-network ={ path = "../../../networks/westend-system" } +rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index f406a73d18d..04746aa8670 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -19,7 +19,10 @@ pub use frame_support::assert_ok; // Polkadot pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Rococo as RococoId}, + v3::{ + Error, + NetworkId::{Rococo as RococoId, Westend as WestendId}, + }, }; // Bridges @@ -27,6 +30,8 @@ pub use bp_messages::LaneId; // Cumulus pub use emulated_integration_tests_common::{ + accounts::ALICE, + impls::Inspect, test_parachain_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, @@ -36,16 +41,22 @@ pub use emulated_integration_tests_common::{ PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; pub use parachains_common::{AccountId, Balance}; -pub use westend_system_emulated_network::{ +pub use rococo_westend_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + asset_hub_westend_emulated_chain::{ + genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + }, bridge_hub_westend_emulated_chain::{ - genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubWestendParaPallet as BridgeHubWestendPallet, + genesis::ED as BRIDGE_HUB_WESTEND_ED, BridgeHubWestendParaPallet as BridgeHubWestendPallet, }, - westend_emulated_chain::{genesis::ED as ROCOCO_ED, WestendRelayPallet as WestendPallet}, + westend_emulated_chain::WestendRelayPallet as WestendPallet, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, - AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, - BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, - BridgeHubWestendParaSender as BridgeHubWestendSender, WestendRelay as Westend, - WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, + AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubWestendPara as BridgeHubWestend, BridgeHubWestendParaSender as BridgeHubWestendSender, + WestendRelay as Westend, }; pub const ASSET_ID: u32 = 1; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs new file mode 100644 index 00000000000..f90514f80c3 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -0,0 +1,218 @@ +// 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 send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: MultiLocation, amount: u128) { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + let asset_hub_rococo_para_id = AssetHubRococo::para_id().into(); + let destination = MultiLocation { + parents: 2, + interior: X2(GlobalConsensus(NetworkId::Rococo), Parachain(asset_hub_rococo_para_id)), + }; + let beneficiary_id = AssetHubRococoReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + // fund the AHW's SA on BHW for paying bridge transport fees + let ahw_as_seen_by_bhw = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); + let sov_ahw_on_bhw = BridgeHubWestend::sovereign_account_id_of(ahw_as_seen_by_bhw); + BridgeHubWestend::fund_accounts(vec![(sov_ahw_on_bhw.into(), 10_000_000_000_000u128)]); + + AssetHubWestend::execute_with(|| { + assert_ok!( + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + ); + }); + + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeRococoMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + // message dispatched successfully + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); +} + +#[test] +fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { + let wnd_at_asset_hub_westend: MultiLocation = Parent.into(); + let wnd_at_asset_hub_rococo = + MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Westend)) }; + let owner: AccountId = AssetHubRococo::account_id_of(ALICE); + AssetHubRococo::force_create_foreign_asset( + wnd_at_asset_hub_rococo, + owner, + true, + ASSET_MIN_BALANCE, + vec![], + ); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Rococo, + AssetHubRococo::para_id(), + ); + + let wnds_in_reserve_on_ahw_before = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + let sender_wnds_before = + ::account_data_of(AssetHubWestendSender::get()).free; + let receiver_wnds_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) + }); + + let amount = ASSET_HUB_WESTEND_ED * 1_000; + send_asset_from_asset_hub_westend_to_asset_hub_rococo(wnd_at_asset_hub_westend, amount); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // issue WNDs on AHR + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == wnd_at_asset_hub_rococo, + owner: *owner == AssetHubRococoReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_wnds_after = + ::account_data_of(AssetHubWestendSender::get()).free; + let receiver_wnds_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) + }); + let wnds_in_reserve_on_ahw_after = + ::account_data_of(sov_ahr_on_ahw).free; + + // Sender's balance is reduced + assert!(sender_wnds_before > sender_wnds_after); + // Receiver's balance is increased + assert!(receiver_wnds_after > receiver_wnds_before); + // Reserve balance is increased by sent amount + assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before + amount); +} + +#[test] +fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { + let prefund_amount = 10_000_000_000_000u128; + let roc_at_asset_hub_westend = + MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Rococo)) }; + let owner: AccountId = AssetHubWestend::account_id_of(ALICE); + AssetHubWestend::force_create_foreign_asset( + roc_at_asset_hub_westend, + owner, + true, + ASSET_MIN_BALANCE, + vec![(AssetHubWestendSender::get(), prefund_amount)], + ); + + // fund the AHW's SA on AHR with the ROC tokens held in reserve + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Westend, + AssetHubWestend::para_id(), + ); + AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), prefund_amount)]); + + let rocs_in_reserve_on_ahr_before = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + assert_eq!(rocs_in_reserve_on_ahr_before, prefund_amount); + let sender_rocs_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendSender::get()) + }); + assert_eq!(sender_rocs_before, prefund_amount); + let receiver_rocs_before = + ::account_data_of(AssetHubRococoReceiver::get()).free; + + let amount_to_send = ASSET_HUB_ROCOCO_ED * 1_000; + send_asset_from_asset_hub_westend_to_asset_hub_rococo(roc_at_asset_hub_westend, amount_to_send); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // ROC is withdrawn from AHW's SA on AHR + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_ahw_on_ahr, + amount: *amount == amount_to_send, + }, + // ROCs deposited to beneficiary + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == AssetHubRococoReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_rocs_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendSender::get()) + }); + let receiver_rocs_after = + ::account_data_of(AssetHubRococoReceiver::get()).free; + let rocs_in_reserve_on_ahr_after = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + + // Sender's balance is reduced + assert!(sender_rocs_before > sender_rocs_after); + // Receiver's balance is increased + assert!(receiver_rocs_after > receiver_rocs_before); + // Reserve balance is reduced by sent amount + assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 1eef05c6b92..4e2ef1434fd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -13,5 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod example; +mod asset_transfers; +mod send_xcm; mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs similarity index 71% rename from cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs rename to cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index 1fdd9441e48..4b21d758cd9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -16,7 +16,7 @@ use crate::*; #[test] -fn example() { +fn send_xcm_from_westend_relay_to_rococo_asset_hub() { // Init tests variables // XcmPallet send arguments let sudo_origin = ::RuntimeOrigin::root(); @@ -30,7 +30,7 @@ fn example() { UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: RococoId, - destination: X1(Parachain(AssetHubWestend::para_id().into())), + destination: X1(Parachain(AssetHubRococo::para_id().into())), xcm: remote_xcm, }, ])); @@ -71,4 +71,30 @@ fn example() { ] ); }); + + // Rococo Global Consensus + // Receive XCM message in Bridge Hub target Parachain + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + // Receive embedded XCM message within `ExportMessage` in Parachain destination + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { + .. + }) => {}, + ] + ); + }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs index 32639b8614b..8dff6c29295 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs @@ -18,7 +18,7 @@ use bridge_hub_westend_runtime::xcm_config::XcmConfig; #[test] fn teleport_to_other_system_parachains_works() { - let amount = BRIDGE_HUB_ROCOCO_ED * 100; + let amount = BRIDGE_HUB_WESTEND_ED * 100; let native_asset: MultiAssets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( -- GitLab From 7cfc233cdc6e6c709594ff26640a350c2e6fb6a8 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 14 Nov 2023 15:03:19 +0100 Subject: [PATCH 502/633] PVF: fix detection of unshare-and-change-root security capability (#2304) --- Cargo.lock | 1 + .../node/core/candidate-validation/src/lib.rs | 2 +- polkadot/node/core/pvf/Cargo.toml | 1 + .../benches/host_prepare_rococo_runtime.rs | 2 +- .../node/core/pvf/common/src/worker/mod.rs | 6 +++--- polkadot/node/core/pvf/src/host.rs | 8 ++++++-- polkadot/node/core/pvf/src/security.rs | 20 +++++++++++++++++-- polkadot/node/core/pvf/tests/it/main.rs | 2 +- 8 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32d9099b386..a9b6c68b50f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12453,6 +12453,7 @@ dependencies = [ "polkadot-node-core-pvf-prepare-worker", "polkadot-node-metrics", "polkadot-node-primitives", + "polkadot-node-subsystem", "polkadot-parachain-primitives", "polkadot-primitives", "procfs", diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 89ea0272884..4232e5f1cdd 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -150,7 +150,7 @@ async fn run( ), pvf_metrics, ) - .await; + .await?; ctx.spawn_blocking("pvf-validation-host", task.boxed())?; loop { diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 430f7cd5e8e..3e72ca9e532 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -27,6 +27,7 @@ polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-node-core-pvf-common = { path = "common" } polkadot-node-metrics = { path = "../../metrics" } polkadot-node-primitives = { path = "../../primitives" } +polkadot-node-subsystem = { path = "../../subsystem" } polkadot-primitives = { path = "../../../primitives" } sp-core = { path = "../../../../substrate/primitives/core" } diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index acd80526262..d0cefae6cdb 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -47,7 +47,7 @@ impl TestHost { execute_worker_path, ); f(&mut config); - let (host, task) = start(config, Metrics::default()).await; + let (host, task) = start(config, Metrics::default()).await.unwrap(); let _ = handle.spawn(task); Self { host: Mutex::new(host) } } diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index 274a2fc8039..f6a67b98321 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -92,13 +92,13 @@ macro_rules! decl_worker_main { std::process::exit(status) }, "--check-can-unshare-user-namespace-and-change-root" => { + #[cfg(target_os = "linux")] + let cache_path_tempdir = std::path::Path::new(&args[2]); #[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(), + &cache_path_tempdir, ) { // Write the error to stderr, log it on the host-side. eprintln!("{}", err); diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 7b383e8034a..5919b9ba32c 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -35,6 +35,7 @@ use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, pvf::PvfPrepData, }; +use polkadot_node_subsystem::SubsystemResult; use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ collections::HashMap, @@ -203,7 +204,10 @@ impl Config { /// The future should not return normally but if it does then that indicates an unrecoverable error. /// In that case all pending requests will be canceled, dropping the result senders and new ones /// will be rejected. -pub async fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Future) { +pub async fn start( + config: Config, + metrics: Metrics, +) -> SubsystemResult<(ValidationHost, impl Future)> { gum::debug!(target: LOG_TARGET, ?config, "starting PVF validation host"); // Run checks for supported security features once per host startup. Warn here if not enabled. @@ -273,7 +277,7 @@ pub async fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Fu }; }; - (validation_host, task) + Ok((validation_host, task)) } /// A mapping from an artifact ID which is in preparation state to the list of pending execution diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index 295dd7df94d..0c0c5f40166 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -27,14 +27,19 @@ const SECURE_MODE_ANNOUNCEMENT: &'static str = \nMore information: https://wiki.polkadot.network/docs/maintain-guides-secure-validator#secure-validator-mode"; /// Run checks for supported security features. +/// +/// # Return +/// +/// Returns the set of security features that we were able to enable. If an error occurs while +/// enabling a security feature we set the corresponding status to `false`. pub async fn check_security_status(config: &Config) -> SecurityStatus { - let Config { prepare_worker_program_path, .. } = config; + let Config { prepare_worker_program_path, cache_path, .. } = config; // TODO: add check that syslog is available and that seccomp violations are logged? let (landlock, seccomp, change_root) = join!( check_landlock(prepare_worker_program_path), check_seccomp(prepare_worker_program_path), - check_can_unshare_user_namespace_and_change_root(prepare_worker_program_path) + check_can_unshare_user_namespace_and_change_root(prepare_worker_program_path, cache_path) ); let security_status = SecurityStatus { @@ -149,11 +154,22 @@ fn print_secure_mode_message(errs: Vec) -> bool { async fn check_can_unshare_user_namespace_and_change_root( #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] prepare_worker_program_path: &Path, + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] cache_path: &Path, ) -> SecureModeResult { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { + let cache_dir_tempdir = + crate::worker_intf::tmppath_in("check-can-unshare", cache_path) + .await + .map_err( + |err| + SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( + format!("could not create a temporary directory in {:?}: {}", cache_path, err) + ) + )?; match tokio::process::Command::new(prepare_worker_program_path) .arg("--check-can-unshare-user-namespace-and-change-root") + .arg(cache_dir_tempdir) .output() .await { diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index f4fd7f802f5..801b60884fa 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -61,7 +61,7 @@ impl TestHost { execute_worker_path, ); f(&mut config); - let (host, task) = start(config, Metrics::default()).await; + let (host, task) = start(config, Metrics::default()).await.unwrap(); let _ = tokio::task::spawn(task); Self { cache_dir, host: Mutex::new(host) } } -- GitLab From b70d418f89a722b0543ba2fb1c014d5ba6e65186 Mon Sep 17 00:00:00 2001 From: Lulu Date: Tue, 14 Nov 2023 14:23:08 +0000 Subject: [PATCH 503/633] Add environment to claim workflow (#2318) Turns out to access environment secrets the workflow must explicitly opt in to the environment. --- .github/workflows/claim-crates.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/claim-crates.yml b/.github/workflows/claim-crates.yml index a1d28d42828..345d24c7566 100644 --- a/.github/workflows/claim-crates.yml +++ b/.github/workflows/claim-crates.yml @@ -8,6 +8,7 @@ on: jobs: claim-crates: runs-on: ubuntu-latest + environment: master steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 -- GitLab From cfe5e62626ac61e452a77ea0545aaeaa2cc1176e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:54:36 +0200 Subject: [PATCH 504/633] chainHead: Support multiple hashes for `chainHead_unpin` method (#2295) This PR adds support for multiple hashes being passed to the `chainHeda_unpin` parameters. The `hash` parameter is renamed to `hash_or_hashes` per https://github.com/paritytech/json-rpc-interface-spec/pull/111. While at it, a new integration test is added to check the unpinning of multiple hashes. The API is checked against a hash or a vector of hashes. cc @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- Cargo.lock | 1 + substrate/client/rpc-spec-v2/Cargo.toml | 1 + .../client/rpc-spec-v2/src/chain_head/api.rs | 11 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 12 +- .../src/chain_head/subscription/inner.rs | 38 ++-- .../src/chain_head/subscription/mod.rs | 17 +- .../rpc-spec-v2/src/chain_head/tests.rs | 173 +++++++++++++++++- 7 files changed, 224 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9b6c68b50f..c57a5ce1393 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15970,6 +15970,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-maybe-compressed-blob", + "sp-rpc", "sp-runtime", "sp-version", "substrate-test-runtime", diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index cfe7f8a117d..ca61286ddfa 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -21,6 +21,7 @@ sc-transaction-pool-api = { path = "../transaction-pool/api" } sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } sp-api = { path = "../../primitives/api" } +sp-rpc = { path = "../../primitives/rpc" } sp-blockchain = { path = "../../primitives/blockchain" } sp-version = { path = "../../primitives/version" } sc-client-api = { path = "../api" } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index d93c4018b60..427b5499bc1 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -21,6 +21,7 @@ //! API trait of the chain head. use crate::chain_head::event::{FollowEvent, MethodResponse, StorageQuery}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sp_rpc::list::ListOrValue; #[rpc(client, server)] pub trait ChainHeadApi { @@ -109,16 +110,22 @@ pub trait ChainHeadApi { call_parameters: String, ) -> RpcResult; - /// Unpin a block reported by the `follow` method. + /// Unpin a block or multiple blocks reported by the `follow` method. /// /// Ongoing operations that require the provided block /// will continue normally. /// + /// When this method returns an error, it is guaranteed that no blocks have been unpinned. + /// /// # Unstable /// /// This method is unstable and subject to change in the future. #[method(name = "chainHead_unstable_unpin", blocking)] - fn chain_head_unstable_unpin(&self, follow_subscription: String, hash: Hash) -> RpcResult<()>; + fn chain_head_unstable_unpin( + &self, + follow_subscription: String, + hash_or_hashes: ListOrValue, + ) -> RpcResult<()>; /// Resumes a storage fetch started with `chainHead_storage` after it has generated an /// `operationWaitingForContinue` event. diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index a8c1c4f7e08..2d01c302037 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -48,6 +48,7 @@ use sc_client_api::{ use sp_api::CallApiAt; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::{traits::CallContext, Bytes}; +use sp_rpc::list::ListOrValue; use sp_runtime::traits::Block as BlockT; use std::{marker::PhantomData, sync::Arc, time::Duration}; @@ -432,9 +433,16 @@ where fn chain_head_unstable_unpin( &self, follow_subscription: String, - hash: Block::Hash, + hash_or_hashes: ListOrValue, ) -> RpcResult<()> { - match self.subscriptions.unpin_block(&follow_subscription, hash) { + let result = match hash_or_hashes { + ListOrValue::Value(hash) => + self.subscriptions.unpin_blocks(&follow_subscription, [hash]), + ListOrValue::List(hashes) => + self.subscriptions.unpin_blocks(&follow_subscription, hashes), + }; + + match result { Ok(()) => Ok(()), Err(SubscriptionManagementError::SubscriptionAbsent) => { // Invalid invalid subscription ID. diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index 8a75029a994..abd42ad9678 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -750,22 +750,36 @@ impl> SubscriptionsInner { } } - pub fn unpin_block( + pub fn unpin_blocks( &mut self, sub_id: &str, - hash: Block::Hash, + hashes: impl IntoIterator + Clone, ) -> Result<(), SubscriptionManagementError> { let Some(sub) = self.subs.get_mut(sub_id) else { return Err(SubscriptionManagementError::SubscriptionAbsent) }; - // Check that unpin was not called before and the block was pinned - // for this subscription. - if !sub.unregister_block(hash) { - return Err(SubscriptionManagementError::BlockHashAbsent) + // Ensure that all blocks are part of the subscription before removing individual + // blocks. + for hash in hashes.clone() { + if !sub.contains_block(hash) { + return Err(SubscriptionManagementError::BlockHashAbsent); + } + } + + // Note: this needs to be separate from the global mappings to avoid barrow checker + // thinking we borrow `&mut self` twice: once from `self.subs.get_mut` and once from + // `self.global_unregister_block`. Although the borrowing is correct, since different + // fields of the structure are borrowed, one at a time. + for hash in hashes.clone() { + sub.unregister_block(hash); + } + + // Block have been removed from the subscription. Remove them from the global tracking. + for hash in hashes { + self.global_unregister_block(hash); } - self.global_unregister_block(hash); Ok(()) } @@ -1029,11 +1043,11 @@ mod tests { assert_eq!(block.has_runtime(), true); let invalid_id = "abc-invalid".to_string(); - let err = subs.unpin_block(&invalid_id, hash).unwrap_err(); + let err = subs.unpin_blocks(&invalid_id, vec![hash]).unwrap_err(); assert_eq!(err, SubscriptionManagementError::SubscriptionAbsent); // Unpin the block. - subs.unpin_block(&id, hash).unwrap(); + subs.unpin_blocks(&id, vec![hash]).unwrap(); let err = subs.lock_block(&id, hash, 1).unwrap_err(); assert_eq!(err, SubscriptionManagementError::BlockHashAbsent); } @@ -1077,13 +1091,13 @@ mod tests { // Ensure the block propagated to the subscription. subs.subs.get(&id_second).unwrap().blocks.get(&hash).unwrap(); - subs.unpin_block(&id, hash).unwrap(); + subs.unpin_blocks(&id, vec![hash]).unwrap(); assert_eq!(*subs.global_blocks.get(&hash).unwrap(), 1); // Cannot unpin a block twice for the same subscription. - let err = subs.unpin_block(&id, hash).unwrap_err(); + let err = subs.unpin_blocks(&id, vec![hash]).unwrap_err(); assert_eq!(err, SubscriptionManagementError::BlockHashAbsent); - subs.unpin_block(&id_second, hash).unwrap(); + subs.unpin_blocks(&id_second, vec![hash]).unwrap(); // Block unregistered from the memory. assert!(subs.global_blocks.get(&hash).is_none()); } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs index b25b1a4913b..c830e662da2 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs @@ -94,22 +94,23 @@ impl> SubscriptionManagement { inner.pin_block(sub_id, hash) } - /// Unpin the block from the subscription. + /// Unpin the blocks from the subscription. /// - /// The last subscription that unpins the block is also unpinning the block - /// from the backend. + /// Blocks are reference counted and when the last subscription unpins a given block, the block + /// is also unpinned from the backend. /// /// This method is called only once per subscription. /// - /// Returns an error if the block is not pinned for the subscription or - /// the subscription ID is invalid. - pub fn unpin_block( + /// Returns an error if the subscription ID is invalid, or any of the blocks are not pinned + /// for the subscriptions. When an error is returned, it is guaranteed that no blocks have + /// been unpinned. + pub fn unpin_blocks( &self, sub_id: &str, - hash: Block::Hash, + hashes: impl IntoIterator + Clone, ) -> Result<(), SubscriptionManagementError> { let mut inner = self.inner.write(); - inner.unpin_block(sub_id, hash) + inner.unpin_blocks(sub_id, hashes) } /// Ensure the block remains pinned until the return object is dropped. 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 c3f5564ebc4..15b258c4756 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1591,14 +1591,17 @@ async fn follow_with_unpin() { // Unpin an invalid subscription ID must return Ok(()). let invalid_hash = hex_string(&INVALID_HASH); let _res: () = api - .call("chainHead_unstable_unpin", ["invalid_sub_id", &invalid_hash]) + .call("chainHead_unstable_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) .await .unwrap(); // Valid subscription with invalid block hash. let invalid_hash = hex_string(&INVALID_HASH); let err = api - .call::<_, serde_json::Value>("chainHead_unstable_unpin", [&sub_id, &invalid_hash]) + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, &invalid_hash], + ) .await .unwrap_err(); assert_matches!(err, @@ -1606,7 +1609,10 @@ async fn follow_with_unpin() { ); // To not exceed the number of pinned blocks, we need to unpin before the next import. - let _res: () = api.call("chainHead_unstable_unpin", [&sub_id, &block_hash]).await.unwrap(); + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_hash]) + .await + .unwrap(); // Block tree: // finalized_block -> block -> block2 @@ -1645,6 +1651,160 @@ async fn follow_with_unpin() { assert!(sub.next::>().await.is_none()); } +#[tokio::test] +async fn follow_with_multiple_unpin_hashes() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + + // Import 3 blocks. + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_2_hash = block_2.header.hash(); + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + let block_3 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_2.hash()) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Unpin an invalid subscription ID must return Ok(()). + let invalid_hash = hex_string(&INVALID_HASH); + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) + .await + .unwrap(); + + // Valid subscription with invalid block hash. + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, &invalid_hash], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_1_hash]) + .await + .unwrap(); + + // One block hash is invalid. Block 1 is already unpinned. + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, vec![&block_1_hash, &block_2_hash, &block_3_hash]], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // Unpin multiple blocks. + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params![&sub_id, vec![&block_2_hash, &block_3_hash]]) + .await + .unwrap(); + + // Check block 2 and 3 are unpinned. + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, &block_2_hash], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, &block_3_hash], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); +} + #[tokio::test] async fn follow_prune_best_block() { let builder = TestClientBuilder::new(); @@ -1828,7 +1988,7 @@ async fn follow_prune_best_block() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); let hash = format!("{:?}", block_2_hash); - let _res: () = api.call("chainHead_unstable_unpin", [&sub_id, &hash]).await.unwrap(); + let _res: () = api.call("chainHead_unstable_unpin", rpc_params![&sub_id, &hash]).await.unwrap(); } #[tokio::test] @@ -2305,7 +2465,10 @@ async fn pin_block_references() { wait_pinned_references(&backend, &hash, 1).await; // To not exceed the number of pinned blocks, we need to unpin before the next import. - let _res: () = api.call("chainHead_unstable_unpin", [&sub_id, &block_hash]).await.unwrap(); + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_hash]) + .await + .unwrap(); // Make sure unpin clears out the reference. let refs = backend.pin_refs(&hash).unwrap(); -- GitLab From cd38ccff7ff49b8f00bbaf799b2056c97ee6e0e9 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:54:54 +0200 Subject: [PATCH 505/633] chainHead: Remove `chainHead_genesis` method (#2296) The method has been removed from the spec (https://github.com/paritytech/json-rpc-interface-spec/tree/main/src), this PR keeps the `chainHead` in sync with that change. @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile --- .../client/rpc-spec-v2/src/chain_head/api.rs | 8 ---- .../rpc-spec-v2/src/chain_head/chain_head.rs | 11 +---- .../rpc-spec-v2/src/chain_head/tests.rs | 44 +------------------ substrate/client/service/src/builder.rs | 1 - 4 files changed, 2 insertions(+), 62 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index 427b5499bc1..9ae80137955 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -74,14 +74,6 @@ pub trait ChainHeadApi { hash: Hash, ) -> RpcResult>; - /// Get the chain's genesis hash. - /// - /// # Unstable - /// - /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_genesisHash", blocking)] - fn chain_head_unstable_genesis_hash(&self) -> RpcResult; - /// Returns storage entries at a specific block's state. /// /// # Unstable diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 2d01c302037..866701a7dbf 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -107,8 +107,6 @@ pub struct ChainHead, Block: BlockT, Client> { executor: SubscriptionTaskExecutor, /// Keep track of the pinned blocks for each subscription. subscriptions: Arc>, - /// The hexadecimal encoded hash of the genesis block. - genesis_hash: String, /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. operation_max_storage_items: usize, @@ -118,14 +116,12 @@ pub struct ChainHead, Block: BlockT, Client> { impl, Block: BlockT, Client> ChainHead { /// Create a new [`ChainHead`]. - pub fn new>( + pub fn new( client: Arc, backend: Arc, executor: SubscriptionTaskExecutor, - genesis_hash: GenesisHash, config: ChainHeadConfig, ) -> Self { - let genesis_hash = hex_string(&genesis_hash.as_ref()); Self { client, backend: backend.clone(), @@ -137,7 +133,6 @@ impl, Block: BlockT, Client> ChainHead { backend, )), operation_max_storage_items: config.operation_max_storage_items, - genesis_hash, _phantom: PhantomData, } } @@ -315,10 +310,6 @@ where .map_err(Into::into) } - fn chain_head_unstable_genesis_hash(&self) -> RpcResult { - Ok(self.genesis_hash.clone()) - } - fn chain_head_unstable_storage( &self, follow_subscription: String, 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 15b258c4756..11c6798bf0a 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -28,7 +28,7 @@ use futures::Future; use jsonrpsee::{ core::{error::Error, server::rpc_module::Subscription as RpcSubscription}, rpc_params, - types::{error::CallError, EmptyServerParams as EmptyParams}, + types::error::CallError, RpcModule, }; use sc_block_builder::BlockBuilderBuilder; @@ -61,7 +61,6 @@ const MAX_PINNED_BLOCKS: usize = 32; const MAX_PINNED_SECS: u64 = 60; const MAX_OPERATIONS: usize = 16; const MAX_PAGINATION_LIMIT: usize = 5; -const CHAIN_GENESIS: [u8; 32] = [0; 32]; const INVALID_HASH: [u8; 32] = [1; 32]; const KEY: &[u8] = b":mock"; const VALUE: &[u8] = b"hello world"; @@ -111,7 +110,6 @@ async fn setup_api() -> ( client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -162,7 +160,6 @@ async fn follow_subscription_produces_blocks() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -231,7 +228,6 @@ async fn follow_with_runtime() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -345,31 +341,6 @@ async fn follow_with_runtime() { assert_eq!(event, expected); } -#[tokio::test] -async fn get_genesis() { - let builder = TestClientBuilder::new(); - let backend = builder.backend(); - let client = Arc::new(builder.build()); - - let api = ChainHead::new( - client.clone(), - backend, - Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, - ChainHeadConfig { - global_max_pinned_blocks: MAX_PINNED_BLOCKS, - subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), - subscription_max_ongoing_operations: MAX_OPERATIONS, - operation_max_storage_items: MAX_PAGINATION_LIMIT, - }, - ) - .into_rpc(); - - let genesis: String = - api.call("chainHead_unstable_genesisHash", EmptyParams::new()).await.unwrap(); - assert_eq!(genesis, hex_string(&CHAIN_GENESIS)); -} - #[tokio::test] async fn get_header() { let (_client, api, _sub, sub_id, block) = setup_api().await; @@ -569,7 +540,6 @@ async fn call_runtime_without_flag() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -1228,7 +1198,6 @@ async fn separate_operation_ids_for_subscriptions() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -1316,7 +1285,6 @@ async fn follow_generates_initial_blocks() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -1472,7 +1440,6 @@ async fn follow_exceeding_pinned_blocks() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: 2, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -1549,7 +1516,6 @@ async fn follow_with_unpin() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: 2, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -1815,7 +1781,6 @@ async fn follow_prune_best_block() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2001,7 +1966,6 @@ async fn follow_forks_pruned_block() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2153,7 +2117,6 @@ async fn follow_report_multiple_pruned_block() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2399,7 +2362,6 @@ async fn pin_block_references() { client.clone(), backend.clone(), Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: 3, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2537,7 +2499,6 @@ async fn follow_finalized_before_new_block() { client_mock.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2652,7 +2613,6 @@ async fn ensure_operation_limits_works() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2757,7 +2717,6 @@ async fn check_continue_operation() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), @@ -2940,7 +2899,6 @@ async fn stop_storage_operation() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 3838accde02..25f998385ba 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -637,7 +637,6 @@ where client.clone(), backend.clone(), task_executor.clone(), - client.info().genesis_hash, // Defaults to sensible limits for the `ChainHead`. sc_rpc_spec_v2::chain_head::ChainHeadConfig::default(), ) -- GitLab From 7d735fc8ae8c9dde906457e27c9d2694892adc8b Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:22:30 +0200 Subject: [PATCH 506/633] Add simple collator election mechanism (#1340) Fixes https://github.com/paritytech/polkadot-sdk/issues/106 Port of cumulus PR https://github.com/paritytech/cumulus/pull/2960 This PR adds the ability to bid for collator slots even after the max number of collators have already registered. This eliminates the first come, first served mechanism that was in place before. Key changes: - added `update_bond` extrinsic to allow registered candidates to adjust their bonds in order to dynamically control their bids - added `take_candidate_slot` extrinsic to try to replace an already existing candidate by bidding more than them - candidates are now kept in a sorted list in the pallet storage, where the top `DesiredCandidates` out of `MaxCandidates` candidates in the list will be selected by the session pallet as collators - if the candidacy bond is increased through a `set_candidacy_bond` call, candidates which don't meet the new bond requirements are kicked # Checklist - [ ] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#process) of this project (at minimum one label for `T` 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) --------- Signed-off-by: georgepisaltu --- .../collator-selection/src/benchmarking.rs | 153 ++- cumulus/pallets/collator-selection/src/lib.rs | 437 ++++-- .../pallets/collator-selection/src/tests.rs | 1210 +++++++++++++++-- .../pallets/collator-selection/src/weights.rs | 36 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 26 +- 13 files changed, 1819 insertions(+), 251 deletions(-) diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index 49999dc114d..fa95303495d 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -25,14 +25,11 @@ use codec::Decode; use frame_benchmarking::{ account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, }; -use frame_support::{ - dispatch::DispatchResult, - traits::{Currency, EnsureOrigin, Get, ReservableCurrency}, -}; +use frame_support::traits::{Currency, EnsureOrigin, Get, ReservableCurrency}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, RawOrigin}; use pallet_authorship::EventHandler; use pallet_session::{self as session, SessionManager}; -use sp_std::prelude::*; +use sp_std::{cmp, prelude::*}; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -94,7 +91,7 @@ fn register_candidates(count: u32) { assert!(>::get() > 0u32.into(), "Bond cannot be zero!"); for who in candidates { - T::Currency::make_free_balance_be(&who, >::get() * 2u32.into()); + T::Currency::make_free_balance_be(&who, >::get() * 3u32.into()); >::register_as_candidate(RawOrigin::Signed(who).into()).unwrap(); } } @@ -107,8 +104,11 @@ fn min_candidates() -> u32 { fn min_invulnerables() -> u32 { let min_collators = T::MinEligibleCollators::get(); - let candidates_length = >::get().len(); - min_collators.saturating_sub(candidates_length.try_into().unwrap()) + let candidates_length = >::decode_len() + .unwrap_or_default() + .try_into() + .unwrap_or_default(); + min_collators.saturating_sub(candidates_length) } #[benchmarks(where T: pallet_authorship::Config + session::Config)] @@ -160,22 +160,19 @@ mod benchmarks { .unwrap(); } // ... and register them. - for (who, _) in candidates { + for (who, _) in candidates.iter() { let deposit = >::get(); - T::Currency::make_free_balance_be(&who, deposit * 1000_u32.into()); - let incoming = CandidateInfo { who: who.clone(), deposit }; - >::try_mutate(|candidates| -> DispatchResult { - if !candidates.iter().any(|candidate| candidate.who == who) { - T::Currency::reserve(&who, deposit)?; - candidates.try_push(incoming).expect("we've respected the bounded vec limit"); - >::insert( - who.clone(), - frame_system::Pallet::::block_number() + T::KickThreshold::get(), - ); - } - Ok(()) + T::Currency::make_free_balance_be(who, deposit * 1000_u32.into()); + >::try_mutate(|list| { + list.try_push(CandidateInfo { who: who.clone(), deposit }).unwrap(); + Ok::<(), BenchmarkError>(()) }) - .expect("only returns ok"); + .unwrap(); + T::Currency::reserve(who, deposit)?; + >::insert( + who.clone(), + frame_system::Pallet::::block_number() + T::KickThreshold::get(), + ); } // now we need to fill up invulnerables @@ -226,10 +223,27 @@ mod benchmarks { } #[benchmark] - fn set_candidacy_bond() -> Result<(), BenchmarkError> { - let bond_amount: BalanceOf = T::Currency::minimum_balance() * 10u32.into(); + fn set_candidacy_bond( + c: Linear<0, { T::MaxCandidates::get() }>, + k: Linear<0, { T::MaxCandidates::get() }>, + ) -> Result<(), BenchmarkError> { + let initial_bond_amount: BalanceOf = T::Currency::minimum_balance() * 2u32.into(); + >::put(initial_bond_amount); + register_validators::(c); + register_candidates::(c); + let kicked = cmp::min(k, c); let origin = T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let bond_amount = if k > 0 { + >::mutate(|candidates| { + for info in candidates.iter_mut().skip(kicked as usize) { + info.deposit = T::Currency::minimum_balance() * 3u32.into(); + } + }); + T::Currency::minimum_balance() * 3u32.into() + } else { + T::Currency::minimum_balance() + }; #[extrinsic_call] _(origin as T::RuntimeOrigin, bond_amount); @@ -238,6 +252,35 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn update_bond( + c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>, + ) -> Result<(), BenchmarkError> { + >::put(T::Currency::minimum_balance()); + >::put(c); + + register_validators::(c); + register_candidates::(c); + + let caller = >::get()[0].who.clone(); + v2::whitelist!(caller); + + let bond_amount: BalanceOf = + T::Currency::minimum_balance() + T::Currency::minimum_balance(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), bond_amount); + + assert_last_event::( + Event::CandidateBondUpdated { account_id: caller, deposit: bond_amount }.into(), + ); + assert!( + >::get().iter().last().unwrap().deposit == + T::Currency::minimum_balance() * 2u32.into() + ); + Ok(()) + } + // worse case is when we have all the max-candidate slots filled except one, and we fill that // one. #[benchmark] @@ -267,6 +310,36 @@ mod benchmarks { ); } + #[benchmark] + fn take_candidate_slot(c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>) { + >::put(T::Currency::minimum_balance()); + >::put(1); + + register_validators::(c); + register_candidates::(c); + + let caller: T::AccountId = whitelisted_caller(); + let bond: BalanceOf = T::Currency::minimum_balance() * 10u32.into(); + T::Currency::make_free_balance_be(&caller, bond); + + >::set_keys( + RawOrigin::Signed(caller.clone()).into(), + keys::(c + 1), + Vec::new(), + ) + .unwrap(); + + let target = >::get().iter().last().unwrap().who.clone(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), bond / 2u32.into(), target.clone()); + + assert_last_event::( + Event::CandidateReplaced { old: target, new: caller, deposit: bond / 2u32.into() } + .into(), + ); + } + // worse case is the last candidate leaving. #[benchmark] fn leave_intent(c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>) { @@ -276,7 +349,7 @@ mod benchmarks { register_validators::(c); register_candidates::(c); - let leaving = >::get().last().unwrap().who.clone(); + let leaving = >::get().iter().last().unwrap().who.clone(); v2::whitelist!(leaving); #[extrinsic_call] @@ -323,31 +396,37 @@ mod benchmarks { let new_block: BlockNumberFor = 1800u32.into(); let zero_block: BlockNumberFor = 0u32.into(); - let candidates = >::get(); + let candidates: Vec = >::get() + .iter() + .map(|candidate_info| candidate_info.who.clone()) + .collect(); let non_removals = c.saturating_sub(r); for i in 0..c { - >::insert(candidates[i as usize].who.clone(), zero_block); + >::insert(candidates[i as usize].clone(), zero_block); } if non_removals > 0 { for i in 0..non_removals { - >::insert(candidates[i as usize].who.clone(), new_block); + >::insert(candidates[i as usize].clone(), new_block); } } else { for i in 0..c { - >::insert(candidates[i as usize].who.clone(), new_block); + >::insert(candidates[i as usize].clone(), new_block); } } let min_candidates = min_candidates::(); - let pre_length = >::get().len(); + let pre_length = >::decode_len().unwrap_or_default(); frame_system::Pallet::::set_block_number(new_block); - assert!(>::get().len() == c as usize); - + let current_length: u32 = >::decode_len() + .unwrap_or_default() + .try_into() + .unwrap_or_default(); + assert!(c == current_length); #[block] { as SessionManager<_>>::new_session(0); @@ -357,16 +436,20 @@ mod benchmarks { // candidates > removals and remaining candidates > min candidates // => remaining candidates should be shorter than before removal, i.e. some were // actually removed. - assert!(>::get().len() < pre_length); + assert!(>::decode_len().unwrap_or_default() < pre_length); } else if c > r && non_removals < min_candidates { // candidates > removals and remaining candidates would be less than min candidates // => remaining candidates should equal min candidates, i.e. some were removed up to // the minimum, but then any more were "forced" to stay in candidates. - assert!(>::get().len() == min_candidates as usize); + let current_length: u32 = >::decode_len() + .unwrap_or_default() + .try_into() + .unwrap_or_default(); + assert!(min_candidates == current_length); } else { // removals >= candidates, non removals must == 0 // can't remove more than exist - assert!(>::get().len() == pre_length); + assert!(>::decode_len().unwrap_or_default() == pre_length); } } diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 24493ce9d9c..7449f4d68c7 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -35,16 +35,36 @@ //! //! 1. [`Invulnerables`]: a set of collators appointed by governance. These accounts will always be //! collators. -//! 2. [`Candidates`]: these are *candidates to the collation task* and may or may not be elected as -//! a final collator. +//! 2. [`CandidateList`]: these are *candidates to the collation task* and may or may not be elected +//! as a final collator. //! -//! The current implementation resolves congestion of [`Candidates`] in a first-come-first-serve -//! manner. +//! The current implementation resolves congestion of [`CandidateList`] through a simple auction +//! mechanism. Candidates bid for the collator slots and at the end of the session, the auction ends +//! and the top candidates are selected to become collators. The number of selected candidates is +//! determined by the value of `DesiredCandidates`. +//! +//! Before the list reaches full capacity, candidates can register by placing the minimum bond +//! through `register_as_candidate`. Then, if an account wants to participate in the collator slot +//! auction, they have to replace an existing candidate by placing a greater deposit through +//! `take_candidate_slot`. Existing candidates can increase their bids through `update_bond`. +//! +//! At any point, an account can take the place of another account in the candidate list if they put +//! up a greater deposit than the target. While new joiners would like to deposit as little as +//! possible to participate in the auction, the replacement threat incentivizes candidates to bid as +//! close to their budget as possible in order to avoid being replaced. +//! +//! Candidates which are not on "winning" slots in the list can also decrease their deposits through +//! `update_bond`, but candidates who are on top slots and try to decrease their deposits will fail +//! in order to enforce auction mechanics and have meaningful bids. //! //! Candidates will not be allowed to get kicked or `leave_intent` if the total number of collators //! would fall below `MinEligibleCollators`. This is to ensure that some collators will always //! exist, i.e. someone is eligible to produce a block. //! +//! When a new session starts, candidates with the highest deposits will be selected in order until +//! the desired number of collators is reached. Candidates can increase or decrease their deposits +//! between sessions in order to ensure they receive a slot in the collator list. +//! //! ### Rewards //! //! The Collator Selection pallet maintains an on-chain account (the "Pot"). In each block, the @@ -56,8 +76,8 @@ //! //! To initiate rewards, an ED needs to be transferred to the pot address. //! -//! Note: Eventually the Pot distribution may be modified as discussed in -//! [this issue](https://github.com/paritytech/statemint/issues/21#issuecomment-810481073). +//! Note: Eventually the Pot distribution may be modified as discussed in [this +//! issue](https://github.com/paritytech/statemint/issues/21#issuecomment-810481073). #![cfg_attr(not(feature = "std"), no_std)] @@ -182,9 +202,12 @@ pub mod pallet { /// The (community, limited) collation candidates. `Candidates` and `Invulnerables` should be /// mutually exclusive. + /// + /// This list is sorted in ascending order by deposit and when the deposits are equal, the least + /// recently updated is considered greater. #[pallet::storage] - #[pallet::getter(fn candidates)] - pub type Candidates = StorageValue< + #[pallet::getter(fn candidate_list)] + pub type CandidateList = StorageValue< _, BoundedVec>, T::MaxCandidates>, ValueQuery, @@ -261,8 +284,12 @@ pub mod pallet { NewCandidacyBond { bond_amount: BalanceOf }, /// A new candidate joined. CandidateAdded { account_id: T::AccountId, deposit: BalanceOf }, + /// Bond of a candidate updated. + CandidateBondUpdated { account_id: T::AccountId, deposit: BalanceOf }, /// A candidate was removed. CandidateRemoved { account_id: T::AccountId }, + /// An account was replaced in the candidate list by another one. + CandidateReplaced { old: T::AccountId, new: T::AccountId, deposit: BalanceOf }, /// An account was unable to be added to the Invulnerables because they did not have keys /// registered. Other Invulnerables may have been set. InvalidInvulnerableSkipped { account_id: T::AccountId }, @@ -288,12 +315,38 @@ pub mod pallet { NoAssociatedValidatorId, /// Validator ID is not yet registered. ValidatorNotRegistered, + /// Could not insert in the candidate list. + InsertToCandidateListFailed, + /// Could not remove from the candidate list. + RemoveFromCandidateListFailed, + /// New deposit amount would be below the minimum candidacy bond. + DepositTooLow, + /// Could not update the candidate list. + UpdateCandidateListFailed, + /// Deposit amount is too low to take the target's slot in the candidate list. + InsufficientBond, + /// The target account to be replaced in the candidate list is not a candidate. + TargetIsNotCandidate, + /// The updated deposit amount is equal to the amount already reserved. + IdenticalDeposit, + /// Cannot lower candidacy bond while occupying a future collator slot in the list. + InvalidUnreserve, } #[pallet::hooks] impl Hooks> for Pallet { fn integrity_test() { assert!(T::MinEligibleCollators::get() > 0, "chain must require at least one collator"); + assert!( + T::MaxInvulnerables::get().saturating_add(T::MaxCandidates::get()) >= + T::MinEligibleCollators::get(), + "invulnerables and candidates must be able to satisfy collator demand" + ); + } + + #[cfg(feature = "try-runtime")] + fn try_state(_: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() } } @@ -307,8 +360,8 @@ pub mod pallet { /// acceptable Invulnerables, and is not proposing a _set_ of new Invulnerables. /// /// This call does not maintain mutual exclusivity of `Invulnerables` and `Candidates`. It - /// is recommended to use a batch of `add_invulnerable` and `remove_invulnerable` instead. - /// A `batch_all` can also be used to enforce atomicity. If any candidates are included in + /// is recommended to use a batch of `add_invulnerable` and `remove_invulnerable` instead. A + /// `batch_all` can also be used to enforce atomicity. If any candidates are included in /// `new`, they should be removed with `remove_invulnerable_candidate` after execution. /// /// Must be called by the `UpdateOrigin`. @@ -319,8 +372,9 @@ pub mod pallet { // don't wipe out the collator set if new.is_empty() { + // Casting `u32` to `usize` should be safe on all machines running this. ensure!( - Candidates::::decode_len().unwrap_or_default() >= + CandidateList::::decode_len().unwrap_or_default() >= T::MinEligibleCollators::get() as usize, Error::::TooFewEligibleCollators ); @@ -401,17 +455,47 @@ pub mod pallet { /// Set the candidacy bond amount. /// + /// If the candidacy bond is increased by this call, all current candidates which have a + /// deposit lower than the new bond will be kicked from the list and get their deposits + /// back. + /// /// The origin for this call must be the `UpdateOrigin`. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::set_candidacy_bond())] + #[pallet::weight(T::WeightInfo::set_candidacy_bond( + T::MaxCandidates::get(), + T::MaxCandidates::get() + ))] pub fn set_candidacy_bond( origin: OriginFor, bond: BalanceOf, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - >::put(bond); + let bond_increased = >::mutate(|old_bond| -> bool { + let bond_increased = *old_bond < bond; + *old_bond = bond; + bond_increased + }); + let initial_len = >::decode_len().unwrap_or_default(); + let kicked = (bond_increased && initial_len > 0) + .then(|| { + // Closure below returns the number of candidates which were kicked because + // their deposits were lower than the new candidacy bond. + >::mutate(|candidates| -> usize { + let first_safe_candidate = candidates + .iter() + .position(|candidate| candidate.deposit >= bond) + .unwrap_or(initial_len); + let kicked_candidates = candidates.drain(..first_safe_candidate); + for candidate in kicked_candidates { + T::Currency::unreserve(&candidate.who, candidate.deposit); + >::remove(candidate.who); + } + first_safe_candidate + }) + }) + .unwrap_or_default(); Self::deposit_event(Event::NewCandidacyBond { bond_amount: bond }); - Ok(().into()) + Ok(Some(T::WeightInfo::set_candidacy_bond(initial_len as u32, kicked as u32)).into()) } /// Register this account as a collator candidate. The account must (a) already have @@ -424,8 +508,11 @@ pub mod pallet { let who = ensure_signed(origin)?; // ensure we are below limit. - let length = >::decode_len().unwrap_or_default(); - ensure!((length as u32) < Self::desired_candidates(), Error::::TooManyCandidates); + let length: u32 = >::decode_len() + .unwrap_or_default() + .try_into() + .unwrap_or_default(); + ensure!(length < T::MaxCandidates::get(), Error::::TooManyCandidates); ensure!(!Self::invulnerables().contains(&who), Error::::AlreadyInvulnerable); let validator_key = T::ValidatorIdOf::convert(who.clone()) @@ -437,25 +524,27 @@ pub mod pallet { let deposit = Self::candidacy_bond(); // First authored block is current block plus kick threshold to handle session delay - let incoming = CandidateInfo { who: who.clone(), deposit }; - - let current_count = - >::try_mutate(|candidates| -> Result { - if candidates.iter().any(|candidate| candidate.who == who) { - Err(Error::::AlreadyCandidate)? - } else { - T::Currency::reserve(&who, deposit)?; - candidates.try_push(incoming).map_err(|_| Error::::TooManyCandidates)?; - >::insert( - who.clone(), - frame_system::Pallet::::block_number() + T::KickThreshold::get(), - ); - Ok(candidates.len()) - } - })?; + >::try_mutate(|candidates| -> Result<(), DispatchError> { + ensure!( + !candidates.iter().any(|candidate_info| candidate_info.who == who), + Error::::AlreadyCandidate + ); + T::Currency::reserve(&who, deposit)?; + >::insert( + who.clone(), + frame_system::Pallet::::block_number() + T::KickThreshold::get(), + ); + candidates + .try_insert(0, CandidateInfo { who: who.clone(), deposit }) + .map_err(|_| Error::::InsertToCandidateListFailed)?; + Ok(()) + })?; Self::deposit_event(Event::CandidateAdded { account_id: who, deposit }); - Ok(Some(T::WeightInfo::register_as_candidate(current_count as u32)).into()) + // Safe to do unchecked add here because we ensure above that `length < + // T::MaxCandidates::get()`, and since `T::MaxCandidates` is `u32` it can be at most + // `u32::MAX`, therefore `length + 1` cannot overflow. + Ok(Some(T::WeightInfo::register_as_candidate(length + 1)).into()) } /// Deregister `origin` as a collator candidate. Note that the collator can only leave on @@ -468,13 +557,14 @@ pub mod pallet { pub fn leave_intent(origin: OriginFor) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; ensure!( - Self::eligible_collators() > T::MinEligibleCollators::get() as usize, + Self::eligible_collators() > T::MinEligibleCollators::get(), Error::::TooFewEligibleCollators ); + let length = >::decode_len().unwrap_or_default(); // Do remove their last authored block. - let current_count = Self::try_remove_candidate(&who, true)?; + Self::try_remove_candidate(&who, true)?; - Ok(Some(T::WeightInfo::leave_intent(current_count as u32)).into()) + Ok(Some(T::WeightInfo::leave_intent(length.saturating_sub(1) as u32)).into()) } /// Add a new account `who` to the list of `Invulnerables` collators. `who` must have @@ -521,7 +611,7 @@ pub mod pallet { .unwrap_or_default() .try_into() .unwrap_or(T::MaxInvulnerables::get().saturating_sub(1)), - Candidates::::decode_len() + >::decode_len() .unwrap_or_default() .try_into() .unwrap_or(T::MaxCandidates::get()), @@ -540,7 +630,7 @@ pub mod pallet { T::UpdateOrigin::ensure_origin(origin)?; ensure!( - Self::eligible_collators() > T::MinEligibleCollators::get() as usize, + Self::eligible_collators() > T::MinEligibleCollators::get(), Error::::TooFewEligibleCollators ); @@ -554,6 +644,154 @@ pub mod pallet { Self::deposit_event(Event::InvulnerableRemoved { account_id: who }); Ok(()) } + + /// Update the candidacy bond of collator candidate `origin` to a new amount `new_deposit`. + /// + /// Setting a `new_deposit` that is lower than the current deposit while `origin` is + /// occupying a top-`DesiredCandidates` slot is not allowed. + /// + /// This call will fail if `origin` is not a collator candidate, the updated bond is lower + /// than the minimum candidacy bond, and/or the amount cannot be reserved. + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::update_bond(T::MaxCandidates::get()))] + pub fn update_bond( + origin: OriginFor, + new_deposit: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(new_deposit >= >::get(), Error::::DepositTooLow); + // The function below will try to mutate the `CandidateList` entry for the caller to + // update their deposit to the new value of `new_deposit`. The return value is the + // position of the entry in the list, used for weight calculation. + let length = + >::try_mutate(|candidates| -> Result { + let idx = candidates + .iter() + .position(|candidate_info| candidate_info.who == who) + .ok_or_else(|| Error::::NotCandidate)?; + let candidate_count = candidates.len(); + // Remove the candidate from the list. + let mut info = candidates.remove(idx); + let old_deposit = info.deposit; + if new_deposit > old_deposit { + T::Currency::reserve(&who, new_deposit - old_deposit)?; + } else if new_deposit < old_deposit { + // Casting `u32` to `usize` should be safe on all machines running this. + ensure!( + idx.saturating_add(>::get() as usize) < + candidate_count, + Error::::InvalidUnreserve + ); + T::Currency::unreserve(&who, old_deposit - new_deposit); + } else { + return Err(Error::::IdenticalDeposit.into()) + } + + // Update the deposit and insert the candidate in the correct spot in the list. + info.deposit = new_deposit; + let new_pos = candidates + .iter() + .position(|candidate| candidate.deposit >= new_deposit) + .unwrap_or_else(|| candidates.len()); + candidates + .try_insert(new_pos, info) + .map_err(|_| Error::::InsertToCandidateListFailed)?; + + Ok(candidate_count) + })?; + + Self::deposit_event(Event::CandidateBondUpdated { + account_id: who, + deposit: new_deposit, + }); + Ok(Some(T::WeightInfo::update_bond(length as u32)).into()) + } + + /// The caller `origin` replaces a candidate `target` in the collator candidate list by + /// reserving `deposit`. The amount `deposit` reserved by the caller must be greater than + /// the existing bond of the target it is trying to replace. + /// + /// This call will fail if the caller is already a collator candidate or invulnerable, the + /// caller does not have registered session keys, the target is not a collator candidate, + /// and/or the `deposit` amount cannot be reserved. + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::take_candidate_slot(T::MaxCandidates::get()))] + pub fn take_candidate_slot( + origin: OriginFor, + deposit: BalanceOf, + target: T::AccountId, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + ensure!(!Self::invulnerables().contains(&who), Error::::AlreadyInvulnerable); + ensure!(deposit >= Self::candidacy_bond(), Error::::InsufficientBond); + + let validator_key = T::ValidatorIdOf::convert(who.clone()) + .ok_or(Error::::NoAssociatedValidatorId)?; + ensure!( + T::ValidatorRegistration::is_registered(&validator_key), + Error::::ValidatorNotRegistered + ); + + let length = >::decode_len().unwrap_or_default(); + // The closure below iterates through all elements of the candidate list to ensure that + // the caller isn't already a candidate and to find the target it's trying to replace in + // the list. The return value is a tuple of the position of the candidate to be replaced + // in the list along with its candidate information. + let target_info = >::try_mutate( + |candidates| -> Result>, DispatchError> { + // Find the position in the list of the candidate that is being replaced. + let mut target_info_idx = None; + let mut new_info_idx = None; + for (idx, candidate_info) in candidates.iter().enumerate() { + // While iterating through the candidates trying to find the target, + // also ensure on the same pass that our caller isn't already a + // candidate. + ensure!(candidate_info.who != who, Error::::AlreadyCandidate); + // If we find our target, update the position but do not stop the + // iteration since we're also checking that the caller isn't already a + // candidate. + if candidate_info.who == target { + target_info_idx = Some(idx); + } + // Find the spot where the new candidate would be inserted in the current + // version of the list. + if new_info_idx.is_none() && candidate_info.deposit >= deposit { + new_info_idx = Some(idx); + } + } + let target_info_idx = + target_info_idx.ok_or(Error::::TargetIsNotCandidate)?; + + // Remove the old candidate from the list. + let target_info = candidates.remove(target_info_idx); + ensure!(deposit > target_info.deposit, Error::::InsufficientBond); + + // We have removed one element before `new_info_idx`, so the position we have to + // insert to is reduced by 1. + let new_pos = new_info_idx + .map(|i| i.saturating_sub(1)) + .unwrap_or_else(|| candidates.len()); + let new_info = CandidateInfo { who: who.clone(), deposit }; + // Insert the new candidate in the correct spot in the list. + candidates + .try_insert(new_pos, new_info) + .expect("candidate count previously decremented; qed"); + + Ok(target_info) + }, + )?; + T::Currency::reserve(&who, deposit)?; + T::Currency::unreserve(&target_info.who, target_info.deposit); + >::remove(target_info.who.clone()); + >::insert( + who.clone(), + frame_system::Pallet::::block_number() + T::KickThreshold::get(), + ); + + Self::deposit_event(Event::CandidateReplaced { old: target, new: who, deposit }); + Ok(Some(T::WeightInfo::take_candidate_slot(length as u32)).into()) + } } impl Pallet { @@ -564,84 +802,122 @@ pub mod pallet { /// Return the total number of accounts that are eligible collators (candidates and /// invulnerables). - fn eligible_collators() -> usize { - Candidates::::decode_len() + fn eligible_collators() -> u32 { + >::decode_len() .unwrap_or_default() .saturating_add(Invulnerables::::decode_len().unwrap_or_default()) + .try_into() + .unwrap_or(u32::MAX) } /// Removes a candidate if they exist and sends them back their deposit. fn try_remove_candidate( who: &T::AccountId, remove_last_authored: bool, - ) -> Result { - let current_count = - >::try_mutate(|candidates| -> Result { - let index = candidates - .iter() - .position(|candidate| candidate.who == *who) - .ok_or(Error::::NotCandidate)?; - let candidate = candidates.remove(index); - T::Currency::unreserve(who, candidate.deposit); - if remove_last_authored { - >::remove(who.clone()) - }; - Ok(candidates.len()) - })?; + ) -> Result<(), DispatchError> { + >::try_mutate(|candidates| -> Result<(), DispatchError> { + let idx = candidates + .iter() + .position(|candidate_info| candidate_info.who == *who) + .ok_or(Error::::NotCandidate)?; + let deposit = candidates[idx].deposit; + T::Currency::unreserve(who, deposit); + candidates.remove(idx); + if remove_last_authored { + >::remove(who.clone()) + }; + Ok(()) + })?; Self::deposit_event(Event::CandidateRemoved { account_id: who.clone() }); - Ok(current_count) + Ok(()) } /// Assemble the current set of candidates and invulnerables into the next collator set. /// /// This is done on the fly, as frequent as we are told to do so, as the session manager. - pub fn assemble_collators( - candidates: BoundedVec, - ) -> Vec { + pub fn assemble_collators() -> Vec { + // Casting `u32` to `usize` should be safe on all machines running this. + let desired_candidates = >::get() as usize; let mut collators = Self::invulnerables().to_vec(); - collators.extend(candidates); + collators.extend( + >::get() + .iter() + .rev() + .cloned() + .take(desired_candidates) + .map(|candidate_info| candidate_info.who), + ); collators } /// Kicks out candidates that did not produce a block in the kick threshold and refunds /// their deposits. - pub fn kick_stale_candidates( - candidates: BoundedVec>, T::MaxCandidates>, - ) -> BoundedVec { + /// + /// Return value is the number of candidates left in the list. + pub fn kick_stale_candidates(candidates: impl IntoIterator) -> u32 { let now = frame_system::Pallet::::block_number(); let kick_threshold = T::KickThreshold::get(); let min_collators = T::MinEligibleCollators::get(); candidates .into_iter() .filter_map(|c| { - let last_block = >::get(c.who.clone()); + let last_block = >::get(c.clone()); let since_last = now.saturating_sub(last_block); - let is_invulnerable = Self::invulnerables().contains(&c.who); + let is_invulnerable = Self::invulnerables().contains(&c); let is_lazy = since_last >= kick_threshold; if is_invulnerable { - // They are invulnerable. No reason for them to be in Candidates also. + // They are invulnerable. No reason for them to be in `CandidateList` also. // We don't even care about the min collators here, because an Account // should not be a collator twice. - let _ = Self::try_remove_candidate(&c.who, false); + let _ = Self::try_remove_candidate(&c, false); None } else { - if Self::eligible_collators() <= min_collators as usize || !is_lazy { + if Self::eligible_collators() <= min_collators || !is_lazy { // Either this is a good collator (not lazy) or we are at the minimum // that the system needs. They get to stay. - Some(c.who) + Some(c) } else { // This collator has not produced a block recently enough. Bye bye. - let _ = Self::try_remove_candidate(&c.who, true); + let _ = Self::try_remove_candidate(&c, true); None } } }) - .collect::>() + .count() .try_into() .expect("filter_map operation can't result in a bounded vec larger than its original; qed") } + + /// Ensure the correctness of the state of this pallet. + /// + /// This should be valid before or after each state transition of this pallet. + /// + /// # Invariants + /// + /// ## `DesiredCandidates` + /// + /// * The current desired candidate count should not exceed the candidate list capacity. + /// * The number of selected candidates together with the invulnerables must be greater than + /// or equal to the minimum number of eligible collators. + #[cfg(any(test, feature = "try-runtime"))] + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + let desired_candidates = >::get(); + + frame_support::ensure!( + desired_candidates <= T::MaxCandidates::get(), + "Shouldn't demand more candidates than the pallet config allows." + ); + + frame_support::ensure!( + desired_candidates.saturating_add(T::MaxInvulnerables::get()) >= + T::MinEligibleCollators::get(), + "Invulnerable set together with desired candidates should be able to meet the collator quota." + ); + + Ok(()) + } } /// Keep track of number of authored blocks per authority, uncles are counted as well since @@ -677,14 +953,23 @@ pub mod pallet { >::block_number(), ); - let candidates = Self::candidates(); - let candidates_len_before = candidates.len(); - let active_candidates = Self::kick_stale_candidates(candidates); - let removed = candidates_len_before - active_candidates.len(); - let result = Self::assemble_collators(active_candidates); + // The `expect` below is safe because the list is a `BoundedVec` with a max size of + // `T::MaxCandidates`, which is a `u32`. When `decode_len` returns `Some(len)`, `len` + // must be valid and at most `u32::MAX`, which must always be able to convert to `u32`. + let candidates_len_before: u32 = >::decode_len() + .unwrap_or_default() + .try_into() + .expect("length is at most `T::MaxCandidates`, so it must fit in `u32`; qed"); + let active_candidates_count = Self::kick_stale_candidates( + >::get() + .iter() + .map(|candidate_info| candidate_info.who.clone()), + ); + let removed = candidates_len_before.saturating_sub(active_candidates_count); + let result = Self::assemble_collators(); frame_system::Pallet::::register_extra_weight_unchecked( - T::WeightInfo::new_session(candidates_len_before as u32, removed as u32), + T::WeightInfo::new_session(candidates_len_before, removed), DispatchClass::Mandatory, ); Some(result) diff --git a/cumulus/pallets/collator-selection/src/tests.rs b/cumulus/pallets/collator-selection/src/tests.rs index d4dae513df3..ed2044ccdfa 100644 --- a/cumulus/pallets/collator-selection/src/tests.rs +++ b/cumulus/pallets/collator-selection/src/tests.rs @@ -28,7 +28,7 @@ fn basic_setup_works() { assert_eq!(CollatorSelection::desired_candidates(), 2); assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert!(CollatorSelection::candidates().is_empty()); + assert_eq!(>::get().iter().count(), 0); // genesis should sort input assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); }); @@ -202,7 +202,8 @@ fn candidate_to_invulnerable_works() { initialize_to_block(1); assert_eq!(CollatorSelection::desired_candidates(), 2); assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert_eq!(CollatorSelection::candidates(), Vec::new()); + + assert_eq!(>::get().iter().count(), 0); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); assert_eq!(Balances::free_balance(3), 100); @@ -226,7 +227,7 @@ fn candidate_to_invulnerable_works() { )); assert!(CollatorSelection::invulnerables().to_vec().contains(&3)); assert_eq!(Balances::free_balance(3), 100); - assert_eq!(CollatorSelection::candidates().len(), 1); + assert_eq!(>::get().iter().count(), 1); assert_ok!(CollatorSelection::add_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -240,7 +241,8 @@ fn candidate_to_invulnerable_works() { )); assert!(CollatorSelection::invulnerables().to_vec().contains(&4)); assert_eq!(Balances::free_balance(4), 100); - assert_eq!(CollatorSelection::candidates().len(), 0); + + assert_eq!(>::get().iter().count(), 0); }); } @@ -266,42 +268,230 @@ fn set_desired_candidates_works() { } #[test] -fn set_candidacy_bond() { +fn set_candidacy_bond_empty_candidate_list() { new_test_ext().execute_with(|| { // given assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert!(>::get().is_empty()); - // can set + // can decrease without candidates assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 7 )); assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert!(>::get().is_empty()); // rejects bad origin. assert_noop!(CollatorSelection::set_candidacy_bond(RuntimeOrigin::signed(1), 8), BadOrigin); + + // can increase without candidates + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 20 + )); + assert!(>::get().is_empty()); + assert_eq!(CollatorSelection::candidacy_bond(), 20); }); } #[test] -fn cannot_register_candidate_if_too_many() { +fn set_candidacy_bond_with_one_candidate() { new_test_ext().execute_with(|| { - // reset desired candidates: - >::put(0); + // given + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert!(>::get().is_empty()); - // can't accept anyone anymore. - assert_noop!( - CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)), - Error::::TooManyCandidates, + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_eq!(>::get(), vec![candidate_3.clone()]); + + // can decrease with one candidate + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 7 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert_eq!(>::get(), vec![candidate_3.clone()]); + + // can increase up to initial deposit + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 10 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(>::get(), vec![candidate_3.clone()]); + + // can increase past initial deposit, should kick existing candidate + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 20 + )); + assert!(>::get().is_empty()); + }); +} + +#[test] +fn set_candidacy_bond_with_many_candidates_same_deposit() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert!(>::get().is_empty()); + + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 10 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 10 }; + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + assert_eq!( + >::get(), + vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] ); - // reset desired candidates: - >::put(1); + // can decrease with multiple candidates + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 7 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert_eq!( + >::get(), + vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] + ); + + // can increase up to initial deposit + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 10 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!( + >::get(), + vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] + ); + + // can increase past initial deposit, should kick existing candidates + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 20 + )); + assert!(>::get().is_empty()); + }); +} + +#[test] +fn set_candidacy_bond_with_many_candidates_different_deposits() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert!(>::get().is_empty()); + + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 20 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 30 }; + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 30)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20)); + assert_eq!( + >::get(), + vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] + ); + + // can decrease with multiple candidates + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 7 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert_eq!( + >::get(), + vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] + ); + // can increase up to initial deposit + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 10 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!( + >::get(), + vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] + ); + + // can increase to 4's deposit, should kick 3 + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 20 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 20); + assert_eq!( + >::get(), + vec![candidate_4.clone(), candidate_5.clone()] + ); + + // can increase past 4's deposit, should kick 4 + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 25 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 25); + assert_eq!(>::get(), vec![candidate_5.clone()]); + + // lowering the minimum deposit should have no effect + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 5 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 5); + assert_eq!(>::get(), vec![candidate_5.clone()]); + + // add 3 and 4 back but with higher deposits than minimum + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20)); + assert_eq!( + >::get(), + vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] + ); + + // can increase the deposit above the current max in the list, all candidates should be + // kicked + assert_ok!(CollatorSelection::set_candidacy_bond( + RuntimeOrigin::signed(RootAccount::get()), + 40 + )); + assert_eq!(CollatorSelection::candidacy_bond(), 40); + assert!(>::get().is_empty()); + }); +} + +#[test] +fn cannot_register_candidate_if_too_many() { + new_test_ext().execute_with(|| { + >::put(1); + + // MaxCandidates: u32 = 20 + // Aside from 3, 4, and 5, create enough accounts to have 21 potential + // candidates. + for i in 6..=23 { + Balances::make_free_balance_be(&i, 100); + let key = MockSessionKeys { aura: UintAuthorityId(i) }; + Session::set_keys(RuntimeOrigin::signed(i).into(), key, Vec::new()).unwrap(); + } + + for c in 3..=22 { + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(c))); + } - // but no more assert_noop!( - CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)), + CollatorSelection::register_as_candidate(RuntimeOrigin::signed(23)), Error::::TooManyCandidates, ); }) @@ -310,7 +500,7 @@ fn cannot_register_candidate_if_too_many() { #[test] fn cannot_unregister_candidate_if_too_few() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::candidates(), Vec::new()); + assert_eq!(>::get().iter().count(), 0); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); assert_ok!(CollatorSelection::remove_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -368,8 +558,12 @@ fn cannot_register_dupe_candidate() { new_test_ext().execute_with(|| { // can add 3 as candidate assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + // tuple of (id, deposit). let addition = CandidateInfo { who: 3, deposit: 10 }; - assert_eq!(CollatorSelection::candidates(), vec![addition]); + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![addition] + ); assert_eq!(CollatorSelection::last_authored_block(3), 10); assert_eq!(Balances::free_balance(3), 90); @@ -404,7 +598,8 @@ fn register_as_candidate_works() { // given assert_eq!(CollatorSelection::desired_candidates(), 2); assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert_eq!(CollatorSelection::candidates(), Vec::new()); + + assert_eq!(>::get().iter().count(), 0); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); // take two endowed, non-invulnerables accounts. @@ -417,140 +612,888 @@ fn register_as_candidate_works() { assert_eq!(Balances::free_balance(3), 90); assert_eq!(Balances::free_balance(4), 90); - assert_eq!(CollatorSelection::candidates().len(), 2); + assert_eq!(>::get().iter().count(), 2); }); } #[test] -fn leave_intent() { +fn cannot_take_candidate_slot_if_invulnerable() { new_test_ext().execute_with(|| { - // register a candidate. - assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); - assert_eq!(Balances::free_balance(3), 90); - - // register too so can leave above min candidates - assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); - assert_eq!(Balances::free_balance(5), 90); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); - // cannot leave if not candidate. + // can't 1 because it is invulnerable. assert_noop!( - CollatorSelection::leave_intent(RuntimeOrigin::signed(4)), - Error::::NotCandidate + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(1), 50u64.into(), 2), + Error::::AlreadyInvulnerable, ); - - // bond is returned - assert_ok!(CollatorSelection::leave_intent(RuntimeOrigin::signed(3))); - assert_eq!(Balances::free_balance(3), 100); - assert_eq!(CollatorSelection::last_authored_block(3), 0); - }); + }) } #[test] -fn authorship_event_handler() { +fn cannot_take_candidate_slot_if_keys_not_registered() { new_test_ext().execute_with(|| { - // put 100 in the pot + 5 for ED - Balances::make_free_balance_be(&CollatorSelection::account_id(), 105); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(42), 50u64.into(), 3), + Error::::ValidatorNotRegistered + ); + }) +} - // 4 is the default author. - assert_eq!(Balances::free_balance(4), 100); +#[test] +fn cannot_take_candidate_slot_if_duplicate() { + new_test_ext().execute_with(|| { + // can add 3 as candidate + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); - // triggers `note_author` - Authorship::on_initialize(1); + // tuple of (id, deposit). + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 10 }; + let actual_candidates = + >::get().iter().cloned().collect::>(); + assert_eq!(actual_candidates, vec![candidate_4, candidate_3]); + assert_eq!(CollatorSelection::last_authored_block(3), 10); + assert_eq!(CollatorSelection::last_authored_block(4), 10); + assert_eq!(Balances::free_balance(3), 90); - let collator = CandidateInfo { who: 4, deposit: 10 }; + // but no more + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(3), 50u64.into(), 4), + Error::::AlreadyCandidate, + ); + }) +} - assert_eq!(CollatorSelection::candidates(), vec![collator]); - assert_eq!(CollatorSelection::last_authored_block(4), 0); +#[test] +fn cannot_take_candidate_slot_if_target_invalid() { + new_test_ext().execute_with(|| { + // can add 3 as candidate + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + // tuple of (id, deposit). + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![candidate_3] + ); + assert_eq!(CollatorSelection::last_authored_block(3), 10); + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 100); - // half of the pot goes to the collator who's the author (4 in tests). - assert_eq!(Balances::free_balance(4), 140); - // half + ED stays. - assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55); - }); + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 50u64.into(), 5), + Error::::TargetIsNotCandidate, + ); + }) } #[test] -fn fees_edgecases() { +fn cannot_take_candidate_slot_if_poor() { new_test_ext().execute_with(|| { - // Nothing panics, no reward when no ED in balance - Authorship::on_initialize(1); - // put some money into the pot at ED - Balances::make_free_balance_be(&CollatorSelection::account_id(), 5); - // 4 is the default author. - assert_eq!(Balances::free_balance(4), 100); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); - // triggers `note_author` - Authorship::on_initialize(1); + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(33), 0); - let collator = CandidateInfo { who: 4, deposit: 10 }; + // works + assert_ok!(CollatorSelection::take_candidate_slot( + RuntimeOrigin::signed(3), + 20u64.into(), + 4 + )); - assert_eq!(CollatorSelection::candidates(), vec![collator]); - assert_eq!(CollatorSelection::last_authored_block(4), 0); - // Nothing received - assert_eq!(Balances::free_balance(4), 90); - // all fee stays - assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5); + // poor + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(33), 30u64.into(), 3), + BalancesError::::InsufficientBalance, + ); }); } #[test] -fn session_management_works() { +fn cannot_take_candidate_slot_if_insufficient_deposit() { new_test_ext().execute_with(|| { - initialize_to_block(1); - - assert_eq!(SessionChangeBlock::get(), 0); - assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); - - initialize_to_block(4); - - assert_eq!(SessionChangeBlock::get(), 0); - assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); - - // add a new collator assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); - - // session won't see this. - assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); - // but we have a new candidate. - assert_eq!(CollatorSelection::candidates().len(), 1); - - initialize_to_block(10); - assert_eq!(SessionChangeBlock::get(), 10); - // pallet-session has 1 session delay; current validators are the same. - assert_eq!(Session::validators(), vec![1, 2]); - // queued ones are changed, and now we have 3. - assert_eq!(Session::queued_keys().len(), 3); - // session handlers (aura, et. al.) cannot see this yet. - assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); - - initialize_to_block(20); - assert_eq!(SessionChangeBlock::get(), 20); - // changed are now reflected to session handlers. - assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3]); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60u64.into())); + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 100); + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 5u64.into(), 3), + Error::::InsufficientBond, + ); + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 100); }); } #[test] -fn kick_mechanism() { +fn cannot_take_candidate_slot_if_deposit_less_than_target() { new_test_ext().execute_with(|| { - // add a new collator assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); - assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); - initialize_to_block(10); - assert_eq!(CollatorSelection::candidates().len(), 2); - initialize_to_block(20); - assert_eq!(SessionChangeBlock::get(), 20); - // 4 authored this block, gets to stay 3 was kicked - assert_eq!(CollatorSelection::candidates().len(), 1); - // 3 will be kicked after 1 session delay - assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]); - let collator = CandidateInfo { who: 4, deposit: 10 }; - assert_eq!(CollatorSelection::candidates(), vec![collator]); - assert_eq!(CollatorSelection::last_authored_block(4), 20); - initialize_to_block(30); - // 3 gets kicked after 1 session delay - assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]); - // kicked collator gets funds back + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60u64.into())); + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 100); + assert_noop!( + CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 20u64.into(), 3), + Error::::InsufficientBond, + ); + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 100); + }); +} + +#[test] +fn take_candidate_slot_works() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take two endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 90); + assert_eq!(Balances::free_balance(5), 90); + + assert_eq!(>::get().iter().count(), 3); + + Balances::make_free_balance_be(&6, 100); + let key = MockSessionKeys { aura: UintAuthorityId(6) }; + Session::set_keys(RuntimeOrigin::signed(6).into(), key, Vec::new()).unwrap(); + + assert_ok!(CollatorSelection::take_candidate_slot( + RuntimeOrigin::signed(6), + 50u64.into(), + 4 + )); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 90); + assert_eq!(Balances::free_balance(6), 50); + + // tuple of (id, deposit). + let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; + let candidate_6 = CandidateInfo { who: 6, deposit: 50 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 10 }; + let mut actual_candidates = + >::get().iter().cloned().collect::>(); + actual_candidates.sort_by(|info_1, info_2| info_1.deposit.cmp(&info_2.deposit)); + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![candidate_5, candidate_3, candidate_6] + ); + }); +} + +#[test] +fn increase_candidacy_bond_non_candidate_account() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(5), 20), + Error::::NotCandidate + ); + }); +} + +#[test] +fn increase_candidacy_bond_insufficient_balance() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take two endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 90); + assert_eq!(Balances::free_balance(5), 90); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(3), 110), + BalancesError::::InsufficientBalance + ); + + assert_eq!(Balances::free_balance(3), 90); + }); +} + +#[test] +fn increase_candidacy_bond_works() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take three endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 90); + assert_eq!(Balances::free_balance(5), 90); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); + + assert_eq!(>::get().iter().count(), 3); + assert_eq!(Balances::free_balance(3), 80); + assert_eq!(Balances::free_balance(4), 70); + assert_eq!(Balances::free_balance(5), 60); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 40)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 60)); + + assert_eq!(>::get().iter().count(), 3); + assert_eq!(Balances::free_balance(3), 60); + assert_eq!(Balances::free_balance(4), 40); + assert_eq!(Balances::free_balance(5), 60); + }); +} + +#[test] +fn decrease_candidacy_bond_non_candidate_account() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + + assert_eq!(Balances::free_balance(5), 100); + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10), + Error::::NotCandidate + ); + assert_eq!(Balances::free_balance(5), 100); + }); +} + +#[test] +fn decrease_candidacy_bond_insufficient_funds() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take two endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 60)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60)); + + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 40); + assert_eq!(Balances::free_balance(5), 40); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(3), 0), + Error::::DepositTooLow + ); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(4), 5), + Error::::DepositTooLow + ); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(5), 9), + Error::::DepositTooLow + ); + + assert_eq!(Balances::free_balance(3), 40); + assert_eq!(Balances::free_balance(4), 40); + assert_eq!(Balances::free_balance(5), 40); + }); +} + +#[test] +fn decrease_candidacy_bond_occupying_top_slot() { + new_test_ext().execute_with(|| { + assert_eq!(CollatorSelection::desired_candidates(), 2); + // Register 3 candidates. + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + // And update their bids. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 30u64.into())); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30u64.into())); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60u64.into())); + + // tuple of (id, deposit). + let candidate_3 = CandidateInfo { who: 3, deposit: 30 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 30 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 60 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![candidate_4, candidate_3, candidate_5] + ); + + // Candidates 5 and 3 can't decrease their deposits because they are the 2 top candidates. + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(5), 29), + Error::::InvalidUnreserve, + ); + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(3), 29), + Error::::InvalidUnreserve, + ); + // But candidate 4 should have be able to decrease the deposit up to the minimum. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 29u64.into())); + + // Make candidate 4 outbid candidate 3, taking their spot as the second highest bid. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 35u64.into())); + + // tuple of (id, deposit). + let candidate_3 = CandidateInfo { who: 3, deposit: 30 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 35 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 60 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![candidate_3, candidate_4, candidate_5] + ); + + // Now candidates 5 and 4 are the 2 top candidates, so they can't decrease their deposits. + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(5), 34), + Error::::InvalidUnreserve, + ); + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(4), 34), + Error::::InvalidUnreserve, + ); + // Candidate 3 should have be able to decrease the deposit up to the minimum now that + // they've fallen out of the top spots. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10u64.into())); + }); +} + +#[test] +fn decrease_candidacy_bond_works() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take three endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 90); + assert_eq!(Balances::free_balance(5), 90); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); + + assert_eq!(>::get().iter().count(), 3); + assert_eq!(Balances::free_balance(3), 80); + assert_eq!(Balances::free_balance(4), 70); + assert_eq!(Balances::free_balance(5), 60); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10)); + + assert_eq!(>::get().iter().count(), 3); + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 70); + assert_eq!(Balances::free_balance(5), 60); + }); +} + +#[test] +fn update_candidacy_bond_with_identical_amount() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take three endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_eq!(Balances::free_balance(3), 90); + assert_eq!(Balances::free_balance(4), 90); + assert_eq!(Balances::free_balance(5), 90); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); + + assert_eq!(>::get().iter().count(), 3); + assert_eq!(Balances::free_balance(3), 80); + assert_eq!(Balances::free_balance(4), 70); + assert_eq!(Balances::free_balance(5), 60); + + assert_noop!( + CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20), + Error::::IdenticalDeposit + ); + assert_eq!(Balances::free_balance(3), 80); + }); +} + +#[test] +fn candidate_list_works() { + new_test_ext().execute_with(|| { + // given + assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(CollatorSelection::candidacy_bond(), 10); + + assert_eq!(>::get().iter().count(), 0); + assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + + // take three endowed, non-invulnerables accounts. + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(4), 100); + assert_eq!(Balances::free_balance(5), 100); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 20)); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 30)); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 25)); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10)); + + let candidate_3 = CandidateInfo { who: 3, deposit: 30 }; + let candidate_4 = CandidateInfo { who: 4, deposit: 25 }; + let candidate_5 = CandidateInfo { who: 5, deposit: 10 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![candidate_5, candidate_4, candidate_3] + ); + }); +} + +#[test] +fn leave_intent() { + new_test_ext().execute_with(|| { + // register a candidate. + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_eq!(Balances::free_balance(3), 90); + + // register too so can leave above min candidates + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + assert_eq!(Balances::free_balance(5), 90); + + // cannot leave if not candidate. + assert_noop!( + CollatorSelection::leave_intent(RuntimeOrigin::signed(4)), + Error::::NotCandidate + ); + + // bond is returned + assert_ok!(CollatorSelection::leave_intent(RuntimeOrigin::signed(3))); + assert_eq!(Balances::free_balance(3), 100); + assert_eq!(CollatorSelection::last_authored_block(3), 0); + }); +} + +#[test] +fn authorship_event_handler() { + new_test_ext().execute_with(|| { + // put 100 in the pot + 5 for ED + Balances::make_free_balance_be(&CollatorSelection::account_id(), 105); + + // 4 is the default author. + assert_eq!(Balances::free_balance(4), 100); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + // triggers `note_author` + Authorship::on_initialize(1); + + // tuple of (id, deposit). + let collator = CandidateInfo { who: 4, deposit: 10 }; + + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![collator] + ); + assert_eq!(CollatorSelection::last_authored_block(4), 0); + + // half of the pot goes to the collator who's the author (4 in tests). + assert_eq!(Balances::free_balance(4), 140); + // half + ED stays. + assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55); + }); +} + +#[test] +fn fees_edgecases() { + new_test_ext().execute_with(|| { + // Nothing panics, no reward when no ED in balance + Authorship::on_initialize(1); + // put some money into the pot at ED + Balances::make_free_balance_be(&CollatorSelection::account_id(), 5); + // 4 is the default author. + assert_eq!(Balances::free_balance(4), 100); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + // triggers `note_author` + Authorship::on_initialize(1); + + // tuple of (id, deposit). + let collator = CandidateInfo { who: 4, deposit: 10 }; + + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![collator] + ); + assert_eq!(CollatorSelection::last_authored_block(4), 0); + // Nothing received + assert_eq!(Balances::free_balance(4), 90); + // all fee stays + assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5); + }); +} + +#[test] +fn session_management_single_candidate() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + // add a new collator + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 1); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 3. + assert_eq!(Session::queued_keys().len(), 3); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3]); + }); +} + +#[test] +fn session_management_max_candidates() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 3); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 4. + assert_eq!(Session::queued_keys().len(), 4); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]); + }); +} + +#[test] +fn session_management_increase_bid_with_list_update() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60)); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 3); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 4. + assert_eq!(Session::queued_keys().len(), 4); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5, 3]); + }); +} + +#[test] +fn session_management_candidate_list_eager_sort() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60)); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 3); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 4. + assert_eq!(Session::queued_keys().len(), 4); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5, 3]); + }); +} + +#[test] +fn session_management_reciprocal_outbidding() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60)); + + initialize_to_block(5); + + // candidates 3 and 4 saw they were outbid and preemptively bid more + // than 5 in the next block. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 70)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 70)); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 3); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 4. + assert_eq!(Session::queued_keys().len(), 4); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4, 3]); + }); +} + +#[test] +fn session_management_decrease_bid_after_auction() { + new_test_ext().execute_with(|| { + initialize_to_block(1); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(4); + + assert_eq!(SessionChangeBlock::get(), 0); + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60)); + + initialize_to_block(5); + + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 70)); + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 70)); + + initialize_to_block(5); + + // candidate 5 saw it was outbid and wants to take back its bid, but + // not entirely so they still keep their place in the candidate list + // in case there is an opportunity in the future. + assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10)); + + // session won't see this. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + // but we have a new candidate. + assert_eq!(>::get().iter().count(), 3); + + initialize_to_block(10); + assert_eq!(SessionChangeBlock::get(), 10); + // pallet-session has 1 session delay; current validators are the same. + assert_eq!(Session::validators(), vec![1, 2]); + // queued ones are changed, and now we have 4. + assert_eq!(Session::queued_keys().len(), 4); + // session handlers (aura, et. al.) cannot see this yet. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); + + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // changed are now reflected to session handlers. + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4, 3]); + }); +} + +#[test] +fn kick_mechanism() { + new_test_ext().execute_with(|| { + // add a new collator + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); + assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); + initialize_to_block(10); + assert_eq!(>::get().iter().count(), 2); + initialize_to_block(20); + assert_eq!(SessionChangeBlock::get(), 20); + // 4 authored this block, gets to stay 3 was kicked + assert_eq!(>::get().iter().count(), 1); + // 3 will be kicked after 1 session delay + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]); + // tuple of (id, deposit). + let collator = CandidateInfo { who: 4, deposit: 10 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![collator] + ); + assert_eq!(CollatorSelection::last_authored_block(4), 20); + initialize_to_block(30); + // 3 gets kicked after 1 session delay + assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]); + // kicked collator gets funds back assert_eq!(Balances::free_balance(3), 100); }); } @@ -559,7 +1502,8 @@ fn kick_mechanism() { fn should_not_kick_mechanism_too_few() { new_test_ext().execute_with(|| { // remove the invulnerables and add new collators 3 and 5 - assert_eq!(CollatorSelection::candidates(), Vec::new()); + + assert_eq!(>::get().iter().count(), 0); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); assert_ok!(CollatorSelection::remove_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -573,30 +1517,34 @@ fn should_not_kick_mechanism_too_few() { )); initialize_to_block(10); - assert_eq!(CollatorSelection::candidates().len(), 2); + assert_eq!(>::get().iter().count(), 2); initialize_to_block(20); assert_eq!(SessionChangeBlock::get(), 20); // 4 authored this block, 3 is kicked, 5 stays because of too few collators - assert_eq!(CollatorSelection::candidates().len(), 1); + assert_eq!(>::get().iter().count(), 1); // 3 will be kicked after 1 session delay assert_eq!(SessionHandlerCollators::get(), vec![3, 5]); - let collator = CandidateInfo { who: 5, deposit: 10 }; - assert_eq!(CollatorSelection::candidates(), vec![collator]); + // tuple of (id, deposit). + let collator = CandidateInfo { who: 3, deposit: 10 }; + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![collator] + ); assert_eq!(CollatorSelection::last_authored_block(4), 20); initialize_to_block(30); // 3 gets kicked after 1 session delay - assert_eq!(SessionHandlerCollators::get(), vec![5]); + assert_eq!(SessionHandlerCollators::get(), vec![3]); // kicked collator gets funds back - assert_eq!(Balances::free_balance(3), 100); + assert_eq!(Balances::free_balance(5), 100); }); } #[test] fn should_kick_invulnerables_from_candidates_on_session_change() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::candidates(), Vec::new()); + assert_eq!(>::get().iter().count(), 0); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); assert_eq!(Balances::free_balance(3), 90); @@ -606,16 +1554,22 @@ fn should_kick_invulnerables_from_candidates_on_session_change() { vec![1, 2, 3] )); + // tuple of (id, deposit). let collator_3 = CandidateInfo { who: 3, deposit: 10 }; let collator_4 = CandidateInfo { who: 4, deposit: 10 }; - assert_eq!(CollatorSelection::candidates(), vec![collator_3, collator_4.clone()]); + let actual_candidates = + >::get().iter().cloned().collect::>(); + assert_eq!(actual_candidates, vec![collator_4.clone(), collator_3]); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3]); // session change initialize_to_block(10); // 3 is removed from candidates - assert_eq!(CollatorSelection::candidates(), vec![collator_4]); + assert_eq!( + >::get().iter().cloned().collect::>(), + vec![collator_4] + ); // but not from invulnerables assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3]); // and it got its deposit back diff --git a/cumulus/pallets/collator-selection/src/weights.rs b/cumulus/pallets/collator-selection/src/weights.rs index f8f86fb7dec..1c01ad6cd6f 100644 --- a/cumulus/pallets/collator-selection/src/weights.rs +++ b/cumulus/pallets/collator-selection/src/weights.rs @@ -30,9 +30,11 @@ pub trait WeightInfo { fn add_invulnerable(_b: u32, _c: u32) -> Weight; fn remove_invulnerable(_b: u32) -> Weight; fn set_desired_candidates() -> Weight; - fn set_candidacy_bond() -> Weight; + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight; fn register_as_candidate(_c: u32) -> Weight; fn leave_intent(_c: u32) -> Weight; + fn update_bond(_c: u32) -> Weight; + fn take_candidate_slot(_c: u32) -> Weight; fn note_author() -> Weight; fn new_session(_c: u32, _r: u32) -> Weight; } @@ -49,7 +51,7 @@ impl WeightInfo for SubstrateWeight { fn set_desired_candidates() -> Weight { Weight::from_parts(16_363_000_u64, 0).saturating_add(T::DbWeight::get().writes(1_u64)) } - fn set_candidacy_bond() -> Weight { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { Weight::from_parts(16_840_000_u64, 0).saturating_add(T::DbWeight::get().writes(1_u64)) } fn register_as_candidate(c: u32) -> Weight { @@ -66,6 +68,20 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + fn update_bond(c: u32) -> Weight { + Weight::from_parts(55_336_000_u64, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(151_000_u64, 0).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + fn take_candidate_slot(c: u32) -> Weight { + Weight::from_parts(71_196_000_u64, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(198_000_u64, 0).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } fn note_author() -> Weight { Weight::from_parts(71_461_000_u64, 0) .saturating_add(T::DbWeight::get().reads(3_u64)) @@ -136,7 +152,7 @@ impl WeightInfo for () { fn set_desired_candidates() -> Weight { Weight::from_parts(16_363_000_u64, 0).saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn set_candidacy_bond() -> Weight { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { Weight::from_parts(16_840_000_u64, 0).saturating_add(RocksDbWeight::get().writes(1_u64)) } fn register_as_candidate(c: u32) -> Weight { @@ -158,6 +174,20 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } + fn update_bond(c: u32) -> Weight { + Weight::from_parts(55_336_000_u64, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(151_000_u64, 0).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + fn take_candidate_slot(c: u32) -> Weight { + Weight::from_parts(71_196_000_u64, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(198_000_u64, 0).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } fn new_session(r: u32, c: u32) -> Weight { Weight::from_parts(0_u64, 0) // Standard Error: 1_010_000 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs index 5c5a31eb348..c686bd6134a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_collator_selection.rs @@ -123,7 +123,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -177,6 +177,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs index c33e79970ff..b3062984baf 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -121,7 +121,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -175,6 +175,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) 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 index d98abbbc2d3..aeda7bbbb6a 100644 --- 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 @@ -124,7 +124,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -178,6 +178,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs index 095e784cf66..1fac2d59ab9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_collator_selection.rs @@ -123,7 +123,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -177,6 +177,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs index cccb7c60924..72d8ba4045a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs @@ -123,7 +123,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -177,6 +177,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs index 6ed2c429186..f7c78f7db82 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -123,7 +123,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -177,6 +177,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs index 1fb0b765c06..f7e233189ab 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs @@ -123,7 +123,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -177,6 +177,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs index 9cbfa6ce80e..9dcee77082b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_collator_selection.rs @@ -124,7 +124,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -178,6 +178,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs index 2c729e8dc10..03f3ff602a5 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs @@ -121,7 +121,7 @@ impl pallet_collator_selection::WeightInfo for WeightIn } /// 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 { + fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -175,6 +175,30 @@ impl pallet_collator_selection::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + fn update_bond(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)) + } + fn take_candidate_slot(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) -- GitLab From 1cd38c2cd12fda156c755bcb9375e01a1e077bd8 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Tue, 14 Nov 2023 18:24:45 +0100 Subject: [PATCH 507/633] Contracts: Bump contracts rococo (#2286) --- .../contracts/contracts-rococo/src/contracts.rs | 11 ++--------- .../runtimes/contracts/contracts-rococo/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index 1c99393d5e5..b86f797ee03 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -22,9 +22,7 @@ use frame_support::{ traits::{ConstBool, ConstU32, Nothing}, }; use pallet_contracts::{ - migration::{v12, v13, v14, v15}, - weights::SubstrateWeight, - Config, DebugInfo, DefaultAddressGenerator, Frame, Schedule, + weights::SubstrateWeight, Config, DebugInfo, DefaultAddressGenerator, Frame, Schedule, }; use sp_runtime::Perbill; @@ -70,12 +68,7 @@ impl Config for Runtime { type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type MaxDelegateDependencies = ConstU32<32>; type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; - type Migrations = ( - v12::Migration, - v13::Migration, - v14::Migration, - v15::Migration, - ); + type Migrations = (); type RuntimeHoldReason = RuntimeHoldReason; type Debug = (); type Environment = (); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 2a2f4141033..4c66e780ba9 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -131,7 +131,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 10000, + spec_version: 10001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, -- GitLab From 3a87390b30929dffdf015c31cadea4dfce9f34eb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 14 Nov 2023 19:35:02 +0200 Subject: [PATCH 508/633] chainHead/tests: Fix clippy (#2325) Remove the genesis hash from tests: - Clippy was passing on the PR: https://github.com/paritytech/polkadot-sdk/pull/2296 - Clippy fails on master: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4328487 This was a race with merging: https://github.com/paritytech/polkadot-sdk/pull/2295, which introduced another test that used the `CHAIN_GENESIS` Signed-off-by: Alexandru Vasile --- substrate/client/rpc-spec-v2/src/chain_head/tests.rs | 1 - 1 file changed, 1 deletion(-) 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 11c6798bf0a..4e6775fe280 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1627,7 +1627,6 @@ async fn follow_with_multiple_unpin_hashes() { client.clone(), backend, Arc::new(TaskExecutor::default()), - CHAIN_GENESIS, ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), -- GitLab From 54f84285bf863c75d9383f7d9d3e7612410f23a4 Mon Sep 17 00:00:00 2001 From: jserrat <35823283+Jpserrat@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:50:18 -0300 Subject: [PATCH 509/633] change prepare worker to use fork instead of threads (#1685) Co-authored-by: Marcin S --- Cargo.lock | 26 + .../node/core/candidate-validation/src/lib.rs | 24 +- .../core/candidate-validation/src/tests.rs | 12 +- .../benches/host_prepare_rococo_runtime.rs | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- polkadot/node/core/pvf/common/src/error.rs | 55 +- polkadot/node/core/pvf/common/src/execute.rs | 51 +- .../node/core/pvf/common/src/worker/mod.rs | 12 +- .../node/core/pvf/execute-worker/Cargo.toml | 3 + .../node/core/pvf/execute-worker/src/lib.rs | 399 ++++++++--- .../node/core/pvf/prepare-worker/Cargo.toml | 2 + .../node/core/pvf/prepare-worker/src/lib.rs | 634 ++++++++++++------ polkadot/node/core/pvf/src/error.rs | 53 +- polkadot/node/core/pvf/src/execute/queue.rs | 15 +- .../node/core/pvf/src/execute/worker_intf.rs | 49 +- polkadot/node/core/pvf/src/prepare/pool.rs | 21 +- .../node/core/pvf/src/prepare/worker_intf.rs | 24 +- polkadot/node/core/pvf/src/testing.rs | 34 +- polkadot/node/core/pvf/tests/it/main.rs | 135 +--- polkadot/node/core/pvf/tests/it/process.rs | 383 +++++++++++ .../node/core/pvf/tests/it/worker_common.rs | 8 +- .../src/node/utility/pvf-host-and-workers.md | 47 +- .../list-syscalls/execute-worker-syscalls | 6 + .../list-syscalls/prepare-worker-syscalls | 5 + 24 files changed, 1468 insertions(+), 534 deletions(-) create mode 100644 polkadot/node/core/pvf/tests/it/process.rs diff --git a/Cargo.lock b/Cargo.lock index c57a5ce1393..d8308086822 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8627,6 +8627,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "libc", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -9103,6 +9114,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "os_pipe" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "os_str_bytes" version = "6.5.1" @@ -12525,6 +12546,9 @@ name = "polkadot-node-core-pvf-execute-worker" version = "1.0.0" dependencies = [ "cpu-time", + "libc", + "nix 0.27.1", + "os_pipe", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-parachain-primitives", @@ -12539,6 +12563,8 @@ dependencies = [ "cfg-if", "criterion 0.4.0", "libc", + "nix 0.27.1", + "os_pipe", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-primitives", diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 4232e5f1cdd..a3d6f047313 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -642,14 +642,19 @@ async fn validate_candidate_exhaustive( }, Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout)) => Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::WorkerReportedError(e))) => + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::WorkerReportedInvalid(e))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e))), Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError( "ambiguous worker death".to_string(), ))), - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic(err))) => + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError(err))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(err))), + + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath(err))) => + Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(format!( + "ambiguous job death: {err}" + )))), Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::PrepareError(e))) => { // In principle if preparation of the `WASM` fails, the current candidate can not be the // reason for that. So we can't say whether it is invalid or not. In addition, with @@ -741,9 +746,9 @@ trait ValidationBackend { }; // Allow limited retries for each kind of error. + let mut num_death_retries_left = 1; + let mut num_job_error_retries_left = 1; let mut num_internal_retries_left = 1; - let mut num_awd_retries_left = 1; - let mut num_panic_retries_left = 1; loop { // Stop retrying if we exceeded the timeout. if total_time_start.elapsed() + retry_delay > exec_timeout { @@ -752,11 +757,12 @@ trait ValidationBackend { match validation_result { Err(ValidationError::InvalidCandidate( - WasmInvalidCandidate::AmbiguousWorkerDeath, - )) if num_awd_retries_left > 0 => num_awd_retries_left -= 1, - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic(_))) - if num_panic_retries_left > 0 => - num_panic_retries_left -= 1, + WasmInvalidCandidate::AmbiguousWorkerDeath | + WasmInvalidCandidate::AmbiguousJobDeath(_), + )) if num_death_retries_left > 0 => num_death_retries_left -= 1, + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError(_))) + if num_job_error_retries_left > 0 => + num_job_error_retries_left -= 1, Err(ValidationError::InternalError(_)) if num_internal_retries_left > 0 => num_internal_retries_left -= 1, _ => break, diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index af530a20c4e..cab823e1e63 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -695,11 +695,13 @@ fn candidate_validation_retry_panic_errors() { let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result_list(vec![ - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("foo".into()))), - // Throw an AWD error, we should still retry again. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)), + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("foo".into()))), + // Throw an AJD error, we should still retry again. + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousJobDeath( + "baz".into(), + ))), // Throw another panic error. - Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("bar".into()))), + Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::JobError("bar".into()))), ]), validation_data, validation_code, @@ -1216,7 +1218,7 @@ fn precheck_properly_classifies_outcomes() { inner(Err(PrepareError::Prevalidation("foo".to_owned())), PreCheckOutcome::Invalid); inner(Err(PrepareError::Preparation("bar".to_owned())), PreCheckOutcome::Invalid); - inner(Err(PrepareError::Panic("baz".to_owned())), PreCheckOutcome::Invalid); + inner(Err(PrepareError::JobError("baz".to_owned())), PreCheckOutcome::Invalid); inner(Err(PrepareError::TimedOut), PreCheckOutcome::Failed); inner(Err(PrepareError::IoErr("fizz".to_owned())), PreCheckOutcome::Failed); diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index d0cefae6cdb..378374a10b3 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -37,7 +37,7 @@ impl TestHost { where F: FnOnce(&mut Config), { - let (prepare_worker_path, execute_worker_path) = testing::get_and_check_worker_paths(); + let (prepare_worker_path, execute_worker_path) = testing::build_workers_and_get_paths(true); let cache_dir = tempfile::tempdir().unwrap(); let mut config = Config::new( diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 7dc8d307026..e3fda06963e 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -12,6 +12,7 @@ cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" +thiserror = "1.0.31" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -30,7 +31,6 @@ sp-tracing = { path = "../../../../../substrate/primitives/tracing" } [target.'cfg(target_os = "linux")'.dependencies] landlock = "0.3.0" seccompiler = "0.4.0" -thiserror = "1.0.31" [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 82b56562d8c..34475c481f7 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -35,9 +35,9 @@ pub enum PrepareError { /// Instantiation of the WASM module instance failed. #[codec(index = 2)] RuntimeConstruction(String), - /// An unexpected panic has occurred in the preparation worker. + /// An unexpected error has occurred in the preparation job. #[codec(index = 3)] - Panic(String), + JobError(String), /// Failed to prepare the PVF due to the time limit. #[codec(index = 4)] TimedOut, @@ -48,12 +48,12 @@ pub enum PrepareError { /// The temporary file for the artifact could not be created at the given cache path. This /// state is reported by the validation host (not by the worker). #[codec(index = 6)] - CreateTmpFileErr(String), + CreateTmpFile(String), /// 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). #[codec(index = 7)] - RenameTmpFileErr { + RenameTmpFile { err: String, // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible // conversion to `Option`. @@ -68,11 +68,14 @@ pub enum PrepareError { /// reported by the validation host (not by the worker). #[codec(index = 9)] ClearWorkerDir(String), + /// The preparation job process died, due to OOM, a seccomp violation, or some other factor. + JobDied(String), + #[codec(index = 10)] + /// Some error occurred when interfacing with the kernel. + #[codec(index = 11)] + Kernel(String), } -/// Pre-encoded length-prefixed `PrepareResult::Err(PrepareError::OutOfMemory)` -pub const OOM_PAYLOAD: &[u8] = b"\x02\x00\x00\x00\x00\x00\x00\x00\x01\x08"; - impl PrepareError { /// Returns whether this is a deterministic error, i.e. one that should trigger reliably. Those /// errors depend on the PVF itself and the sc-executor/wasmtime logic. @@ -83,12 +86,15 @@ impl PrepareError { pub fn is_deterministic(&self) -> bool { use PrepareError::*; match self { - Prevalidation(_) | Preparation(_) | Panic(_) | OutOfMemory => true, - TimedOut | + Prevalidation(_) | Preparation(_) | JobError(_) | OutOfMemory => true, IoErr(_) | - CreateTmpFileErr(_) | - RenameTmpFileErr { .. } | - ClearWorkerDir(_) => false, + JobDied(_) | + CreateTmpFile(_) | + RenameTmpFile { .. } | + ClearWorkerDir(_) | + Kernel(_) => false, + // Can occur due to issues with the PVF, but also due to factors like local load. + TimedOut => false, // Can occur due to issues with the PVF, but also due to local errors. RuntimeConstruction(_) => false, } @@ -102,14 +108,16 @@ impl fmt::Display for PrepareError { Prevalidation(err) => write!(f, "prevalidation: {}", err), Preparation(err) => write!(f, "preparation: {}", err), RuntimeConstruction(err) => write!(f, "runtime construction: {}", err), - Panic(err) => write!(f, "panic: {}", err), + JobError(err) => write!(f, "panic: {}", err), 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, src, dest } => + JobDied(err) => write!(f, "prepare: prepare job died: {}", err), + CreateTmpFile(err) => write!(f, "prepare: error creating tmp file: {}", err), + RenameTmpFile { err, src, dest } => write!(f, "prepare: error renaming tmp file ({:?} -> {:?}): {}", src, dest, err), OutOfMemory => write!(f, "prepare: out of memory"), ClearWorkerDir(err) => write!(f, "prepare: error clearing worker cache: {}", err), + Kernel(err) => write!(f, "prepare: error interfacing with the kernel: {}", err), } } } @@ -133,9 +141,9 @@ pub enum InternalValidationError { // conversion to `Option`. path: Option, }, - /// An error occurred in the CPU time monitor thread. Should be totally unrelated to - /// validation. - CpuTimeMonitorThread(String), + /// Some error occurred when interfacing with the kernel. + Kernel(String), + /// Some non-deterministic preparation error occurred. NonDeterministicPrepareError(PrepareError), } @@ -158,17 +166,8 @@ impl fmt::Display for InternalValidationError { "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), + Kernel(err) => write!(f, "validation: error interfacing with the kernel: {}", err), NonDeterministicPrepareError(err) => write!(f, "validation: prepare: {}", err), } } } - -#[test] -fn pre_encoded_payloads() { - let oom_enc = PrepareResult::Err(PrepareError::OutOfMemory).encode(); - let mut oom_payload = oom_enc.len().to_le_bytes().to_vec(); - oom_payload.extend(oom_enc); - assert_eq!(oom_payload, OOM_PAYLOAD); -} diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index b89ab089af1..89e7c8e471a 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -28,9 +28,9 @@ pub struct Handshake { pub executor_params: ExecutorParams, } -/// The response from an execution job on the worker. +/// The response from the execution worker. #[derive(Debug, Encode, Decode)] -pub enum Response { +pub enum WorkerResponse { /// The job completed successfully. Ok { /// The result of parachain validation. @@ -41,14 +41,38 @@ pub enum Response { /// The candidate is invalid. InvalidCandidate(String), /// The job timed out. - TimedOut, - /// An unexpected panic has occurred in the execution worker. - Panic(String), + JobTimedOut, + /// The job process has died. We must kill the worker just in case. + /// + /// We cannot treat this as an internal error because malicious code may have killed the job. + /// We still retry it, because in the non-malicious case it is likely spurious. + JobDied(String), + /// An unexpected error occurred in the job process, e.g. failing to spawn a thread, panic, + /// etc. + /// + /// Because malicious code can cause a job error, we must not treat it as an internal error. We + /// still retry it, because in the non-malicious case it is likely spurious. + JobError(String), + /// Some internal error occurred. InternalError(InternalValidationError), } -impl Response { +/// The result of a job on the execution worker. +pub type JobResult = Result; + +/// The successful response from a job on the execution worker. +#[derive(Debug, Encode, Decode)] +pub enum JobResponse { + Ok { + /// The result of parachain validation. + result_descriptor: ValidationResult, + }, + /// The candidate is invalid. + InvalidCandidate(String), +} + +impl JobResponse { /// Creates an invalid response from a context `ctx` and a message `msg` (which can be empty). pub fn format_invalid(ctx: &'static str, msg: &str) -> Self { if msg.is_empty() { @@ -58,3 +82,18 @@ impl Response { } } } + +/// An unexpected error occurred in the execution job process. Because this comes from the job, +/// which executes untrusted code, this error must likewise be treated as untrusted. That is, we +/// cannot raise an internal error based on this. +#[derive(thiserror::Error, Debug, Encode, Decode)] +pub enum JobError { + #[error("The job timed out")] + TimedOut, + #[error("An unexpected panic has occurred in the execution job: {0}")] + Panic(String), + #[error("Could not spawn the requested thread: {0}")] + CouldNotSpawnThread(String), + #[error("An error occurred in the CPU time monitor thread: {0}")] + CpuTimeMonitorThread(String), +} diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index f6a67b98321..86f47acccac 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -205,9 +205,15 @@ impl fmt::Display for WorkerKind { } } -// 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( +// NOTE: 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. +// +// NOTE: This must not spawn any threads due to safety requirements in `event_loop` and to avoid +// errors in [`security::unshare_user_namespace_and_change_root`]. +// +/// Initializes the worker process, then runs the given event loop, which spawns a new job process +/// to securely handle each incoming request. +pub fn run_worker( worker_kind: WorkerKind, socket_path: PathBuf, #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] mut worker_dir_path: PathBuf, diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 77a9420961c..40e0ff4f0a1 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -9,6 +9,9 @@ license.workspace = true [dependencies] cpu-time = "1.0.0" gum = { package = "tracing-gum", path = "../../../gum" } +os_pipe = "1.1.4" +nix = { version = "0.27.1", features = ["resource", "process"]} +libc = "0.2.139" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 8872f9bc8dd..9ec811686b8 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -25,23 +25,33 @@ pub use polkadot_node_core_pvf_common::{ const LOG_TARGET: &str = "parachain::pvf-execute-worker"; use cpu_time::ProcessTime; +use nix::{ + errno::Errno, + sys::{ + resource::{Usage, UsageWho}, + wait::WaitStatus, + }, + unistd::{ForkResult, Pid}, +}; +use os_pipe::{self, PipeReader, PipeWriter}; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, - execute::{Handshake, Response}, + execute::{Handshake, JobError, JobResponse, JobResult, WorkerResponse}, framed_recv_blocking, framed_send_blocking, worker::{ - cpu_time_monitor_loop, stringify_panic_payload, + cpu_time_monitor_loop, run_worker, stringify_panic_payload, thread::{self, WaitOutcome}, - worker_event_loop, WorkerKind, + WorkerKind, }, }; use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::{executor_params::DEFAULT_NATIVE_STACK_MAX, ExecutorParams}; use std::{ - io, + io::{self, Read}, os::unix::net::UnixStream, path::PathBuf, + process, sync::{mpsc::channel, Arc}, time::Duration, }; @@ -105,7 +115,7 @@ fn recv_request(stream: &mut UnixStream) -> io::Result<(Vec, Duration)> { Ok((params, execution_timeout)) } -fn send_response(stream: &mut UnixStream, response: Response) -> io::Result<()> { +fn send_response(stream: &mut UnixStream, response: WorkerResponse) -> io::Result<()> { framed_send_blocking(stream, &response.encode()) } @@ -131,7 +141,7 @@ pub fn worker_entrypoint( worker_version: Option<&str>, security_status: SecurityStatus, ) { - worker_event_loop( + run_worker( WorkerKind::Execute, socket_path, worker_dir_path, @@ -139,7 +149,7 @@ pub fn worker_entrypoint( worker_version, &security_status, |mut stream, worker_dir_path| { - let worker_pid = std::process::id(); + let worker_pid = process::id(); let artifact_path = worker_dir::execute_artifact(&worker_dir_path); let Handshake { executor_params } = recv_handshake(&mut stream)?; @@ -157,7 +167,7 @@ pub fn worker_entrypoint( let compiled_artifact_blob = match std::fs::read(&artifact_path) { Ok(bytes) => bytes, Err(err) => { - let response = Response::InternalError( + let response = WorkerResponse::InternalError( InternalValidationError::CouldNotOpenFile(err.to_string()), ); send_response(&mut stream, response)?; @@ -165,82 +175,51 @@ pub fn worker_entrypoint( }, }; - // Conditional variable to notify us when a thread is done. - let condvar = thread::get_condvar(); + let (pipe_reader, pipe_writer) = os_pipe::pipe()?; - let cpu_time_start = ProcessTime::now(); + let usage_before = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { + Ok(usage) => usage, + Err(errno) => { + let response = internal_error_from_errno("getrusage before", errno); + send_response(&mut stream, response)?; + continue + }, + }; + + // SAFETY: new process is spawned within a single threaded process. This invariant + // is enforced by tests. + let response = match unsafe { nix::unistd::fork() } { + Err(errno) => internal_error_from_errno("fork", errno), + Ok(ForkResult::Child) => { + // Dropping the stream closes the underlying socket. We want to make sure + // that the sandboxed child can't get any kind of information from the + // outside world. The only IPC it should be able to do is sending its + // response over the pipe. + drop(stream); + // Drop the read end so we don't have too many FDs open. + drop(pipe_reader); - // Spawn a new thread that runs the CPU time monitor. - let (cpu_time_monitor_tx, cpu_time_monitor_rx) = channel::<()>(); - let cpu_time_monitor_thread = thread::spawn_worker_thread( - "cpu time monitor thread", - move || { - cpu_time_monitor_loop( - cpu_time_start, + handle_child_process( + pipe_writer, + compiled_artifact_blob, + executor_params, + params, execution_timeout, - cpu_time_monitor_rx, - ) - }, - Arc::clone(&condvar), - WaitOutcome::TimedOut, - )?; - - let executor_params_2 = executor_params.clone(); - let execute_thread = thread::spawn_worker_thread_with_stack_size( - "execute thread", - move || { - validate_using_artifact( - &compiled_artifact_blob, - &executor_params_2, - ¶ms, - cpu_time_start, ) }, - Arc::clone(&condvar), - WaitOutcome::Finished, - EXECUTE_THREAD_STACK_SIZE, - )?; - - let outcome = thread::wait_for_threads(condvar); - - let response = match outcome { - WaitOutcome::Finished => { - let _ = cpu_time_monitor_tx.send(()); - 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. - WaitOutcome::TimedOut => { - match cpu_time_monitor_thread.join() { - Ok(Some(cpu_time_elapsed)) => { - // Log if we exceed the timeout and the other thread hasn't - // finished. - gum::warn!( - target: LOG_TARGET, - %worker_pid, - "execute job took {}ms cpu time, exceeded execute timeout {}ms", - cpu_time_elapsed.as_millis(), - execution_timeout.as_millis(), - ); - Response::TimedOut - }, - Ok(None) => Response::InternalError( - InternalValidationError::CpuTimeMonitorThread( - "error communicating over finished channel".into(), - ), - ), - Err(e) => Response::InternalError( - InternalValidationError::CpuTimeMonitorThread( - stringify_panic_payload(e), - ), - ), - } + Ok(ForkResult::Parent { child }) => { + // the read end will wait until all write ends have been closed, + // this drop is necessary to avoid deadlock + drop(pipe_writer); + + handle_parent_process( + pipe_reader, + child, + worker_pid, + usage_before, + execution_timeout, + )? }, - WaitOutcome::Pending => unreachable!( - "we run wait_while until the outcome is no longer pending; qed" - ), }; gum::trace!( @@ -259,27 +238,275 @@ fn validate_using_artifact( compiled_artifact_blob: &[u8], executor_params: &ExecutorParams, params: &[u8], - cpu_time_start: ProcessTime, -) -> Response { +) -> JobResponse { 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`]. execute_artifact(compiled_artifact_blob, executor_params, params) } { - Err(err) => return Response::format_invalid("execute", &err), + Err(err) => return JobResponse::format_invalid("execute", &err), Ok(d) => d, }; let result_descriptor = match ValidationResult::decode(&mut &descriptor_bytes[..]) { Err(err) => - return Response::format_invalid("validation result decoding failed", &err.to_string()), + return JobResponse::format_invalid( + "validation result decoding failed", + &err.to_string(), + ), Ok(r) => r, }; - // Include the decoding in the measured time, to prevent any potential attacks exploiting some - // bug in decoding. - let duration = cpu_time_start.elapsed(); + JobResponse::Ok { result_descriptor } +} + +/// This is used to handle child process during pvf execute worker. +/// It execute the artifact and pipes back the response to the parent process +/// +/// # Arguments +/// +/// - `pipe_write`: A `PipeWriter` structure, the writing end of a pipe. +/// +/// - `compiled_artifact_blob`: The artifact bytes from compiled by the prepare worker`. +/// +/// - `executor_params`: Deterministically serialized execution environment semantics. +/// +/// - `params`: Validation parameters. +/// +/// - `execution_timeout`: The timeout in `Duration`. +/// +/// # Returns +/// +/// - pipe back `JobResponse` to the parent process. +fn handle_child_process( + mut pipe_write: PipeWriter, + compiled_artifact_blob: Vec, + executor_params: ExecutorParams, + params: Vec, + execution_timeout: Duration, +) -> ! { + gum::debug!( + target: LOG_TARGET, + worker_job_pid = %process::id(), + "worker job: executing artifact", + ); + + // Conditional variable to notify us when a thread is done. + let condvar = thread::get_condvar(); + let cpu_time_start = ProcessTime::now(); + + // Spawn a new thread that runs the CPU time monitor. + let (cpu_time_monitor_tx, cpu_time_monitor_rx) = channel::<()>(); + let cpu_time_monitor_thread = thread::spawn_worker_thread( + "cpu time monitor thread", + move || cpu_time_monitor_loop(cpu_time_start, execution_timeout, cpu_time_monitor_rx), + Arc::clone(&condvar), + WaitOutcome::TimedOut, + ) + .unwrap_or_else(|err| { + send_child_response(&mut pipe_write, Err(JobError::CouldNotSpawnThread(err.to_string()))) + }); + + let executor_params_2 = executor_params.clone(); + let execute_thread = thread::spawn_worker_thread_with_stack_size( + "execute thread", + move || validate_using_artifact(&compiled_artifact_blob, &executor_params_2, ¶ms), + Arc::clone(&condvar), + WaitOutcome::Finished, + EXECUTE_THREAD_STACK_SIZE, + ) + .unwrap_or_else(|err| { + send_child_response(&mut pipe_write, Err(JobError::CouldNotSpawnThread(err.to_string()))) + }); + + let outcome = thread::wait_for_threads(condvar); + + let response = match outcome { + WaitOutcome::Finished => { + let _ = cpu_time_monitor_tx.send(()); + execute_thread.join().map_err(|e| JobError::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. + WaitOutcome::TimedOut => match cpu_time_monitor_thread.join() { + Ok(Some(_cpu_time_elapsed)) => Err(JobError::TimedOut), + Ok(None) => Err(JobError::CpuTimeMonitorThread( + "error communicating over finished channel".into(), + )), + Err(e) => Err(JobError::CpuTimeMonitorThread(stringify_panic_payload(e))), + }, + WaitOutcome::Pending => + unreachable!("we run wait_while until the outcome is no longer pending; qed"), + }; + + send_child_response(&mut pipe_write, response); +} + +/// Waits for child process to finish and handle child response from pipe. +/// +/// # Arguments +/// +/// - `pipe_read`: A `PipeReader` used to read data from the child process. +/// +/// - `child`: The child pid. +/// +/// - `usage_before`: Resource usage statistics before executing the child process. +/// +/// - `timeout`: The maximum allowed time for the child process to finish, in `Duration`. +/// +/// # Returns +/// +/// - The response, either `Ok` or some error state. +fn handle_parent_process( + mut pipe_read: PipeReader, + child: Pid, + worker_pid: u32, + usage_before: Usage, + timeout: Duration, +) -> io::Result { + // Read from the child. Don't decode unless the process exited normally, which we check later. + let mut received_data = Vec::new(); + pipe_read + .read_to_end(&mut received_data) + // Could not decode job response. There is either a bug or the job was hijacked. + // Should retry at any rate. + .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?; + + let status = nix::sys::wait::waitpid(child, None); + gum::trace!( + target: LOG_TARGET, + %worker_pid, + "execute worker received wait status from job: {:?}", + status, + ); + + let usage_after = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { + Ok(usage) => usage, + Err(errno) => return Ok(internal_error_from_errno("getrusage after", errno)), + }; + + // Using `getrusage` is needed to check whether child has timedout since we cannot rely on + // child to report its own time. + // As `getrusage` returns resource usage from all terminated child processes, + // it is necessary to subtract the usage before the current child process to isolate its cpu + // time + let cpu_tv = get_total_cpu_usage(usage_after) - get_total_cpu_usage(usage_before); + if cpu_tv >= timeout { + gum::warn!( + target: LOG_TARGET, + %worker_pid, + "execute job took {}ms cpu time, exceeded execute timeout {}ms", + cpu_tv.as_millis(), + timeout.as_millis(), + ); + return Ok(WorkerResponse::JobTimedOut) + } + + match status { + Ok(WaitStatus::Exited(_, exit_status)) => { + let mut reader = io::BufReader::new(received_data.as_slice()); + let result = match recv_child_response(&mut reader) { + Ok(result) => result, + Err(err) => return Ok(WorkerResponse::JobError(err.to_string())), + }; + + match result { + Ok(JobResponse::Ok { result_descriptor }) => { + // The exit status should have been zero if no error occurred. + if exit_status != 0 { + return Ok(WorkerResponse::JobError(format!( + "unexpected exit status: {}", + exit_status + ))) + } + + Ok(WorkerResponse::Ok { result_descriptor, duration: cpu_tv }) + }, + Ok(JobResponse::InvalidCandidate(err)) => Ok(WorkerResponse::InvalidCandidate(err)), + Err(job_error) => { + gum::warn!( + target: LOG_TARGET, + %worker_pid, + "execute job error: {}", + job_error, + ); + if matches!(job_error, JobError::TimedOut) { + Ok(WorkerResponse::JobTimedOut) + } else { + Ok(WorkerResponse::JobError(job_error.to_string())) + } + }, + } + }, + // The job was killed by the given signal. + // + // The job gets SIGSYS on seccomp violations, but this signal may have been sent for some + // other reason, so we still need to check for seccomp violations elsewhere. + Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => + Ok(WorkerResponse::JobDied(format!("received signal: {signal:?}"))), + Err(errno) => Ok(internal_error_from_errno("waitpid", errno)), + + // It is within an attacker's power to send an unexpected exit status. So we cannot treat + // this as an internal error (which would make us abstain), but must vote against. + Ok(unexpected_wait_status) => Ok(WorkerResponse::JobDied(format!( + "unexpected status from wait: {unexpected_wait_status:?}" + ))), + } +} + +/// Calculate the total CPU time from the given `usage` structure, returned from +/// [`nix::sys::resource::getrusage`], and calculates the total CPU time spent, including both user +/// and system time. +/// +/// # Arguments +/// +/// - `rusage`: Contains resource usage information. +/// +/// # Returns +/// +/// Returns a `Duration` representing the total CPU time. +fn get_total_cpu_usage(rusage: Usage) -> Duration { + let micros = (((rusage.user_time().tv_sec() + rusage.system_time().tv_sec()) * 1_000_000) + + (rusage.system_time().tv_usec() + rusage.user_time().tv_usec()) as i64) as u64; + + return Duration::from_micros(micros) +} + +/// Get a job response. +fn recv_child_response(received_data: &mut io::BufReader<&[u8]>) -> io::Result { + let response_bytes = framed_recv_blocking(received_data)?; + JobResult::decode(&mut response_bytes.as_slice()).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("execute pvf recv_child_response: decode error: {:?}", e), + ) + }) +} + +/// Write response to the pipe and exit process after. +/// +/// # Arguments +/// +/// - `pipe_write`: A `PipeWriter` structure, the writing end of a pipe. +/// +/// - `response`: Child process response, or error. +fn send_child_response(pipe_write: &mut PipeWriter, response: JobResult) -> ! { + framed_send_blocking(pipe_write, response.encode().as_slice()) + .unwrap_or_else(|_| process::exit(libc::EXIT_FAILURE)); + + if response.is_ok() { + process::exit(libc::EXIT_SUCCESS) + } else { + process::exit(libc::EXIT_FAILURE) + } +} - Response::Ok { result_descriptor, duration } +fn internal_error_from_errno(context: &'static str, errno: Errno) -> WorkerResponse { + WorkerResponse::InternalError(InternalValidationError::Kernel(format!( + "{}: {}: {}", + context, + errno, + io::Error::last_os_error() + ))) } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index e21583ecc8b..1cd221533f4 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -14,6 +14,8 @@ rayon = "1.5.1" tracking-allocator = { package = "staging-tracking-allocator", path = "../../../tracking-allocator" } tikv-jemalloc-ctl = { version = "0.5.0", optional = true } tikv-jemallocator = { version = "0.5.0", optional = true } +os_pipe = "1.1.4" +nix = { version = "0.27.1", features = ["resource", "process"]} parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index 37a4dd06075..151b54efc2d 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -28,28 +28,40 @@ const LOG_TARGET: &str = "parachain::pvf-prepare-worker"; use crate::memory_stats::max_rss_stat::{extract_max_rss_stat, get_max_rss_thread}; #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] use crate::memory_stats::memory_tracker::{get_memory_tracker_loop_stats, memory_tracker_loop}; +use libc; +use nix::{ + errno::Errno, + sys::{ + resource::{Usage, UsageWho}, + wait::WaitStatus, + }, + unistd::{ForkResult, Pid}, +}; +use os_pipe::{self, PipeReader, PipeWriter}; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ - error::{PrepareError, PrepareResult, OOM_PAYLOAD}, + error::{PrepareError, PrepareResult}, executor_intf::create_runtime_from_artifact_bytes, framed_recv_blocking, framed_send_blocking, prepare::{MemoryStats, PrepareJobKind, PrepareStats}, pvf::PvfPrepData, worker::{ - cpu_time_monitor_loop, stringify_panic_payload, - thread::{self, WaitOutcome}, - worker_event_loop, WorkerKind, + cpu_time_monitor_loop, run_worker, stringify_panic_payload, + thread::{self, spawn_worker_thread, WaitOutcome}, + WorkerKind, }, worker_dir, ProcessTime, SecurityStatus, }; use polkadot_primitives::ExecutorParams; use std::{ - fs, io, + fs, + io::{self, Read}, os::{ fd::{AsRawFd, RawFd}, unix::net::UnixStream, }, path::PathBuf, + process, sync::{mpsc::channel, Arc}, time::Duration, }; @@ -65,6 +77,7 @@ static ALLOC: TrackingAllocator = static ALLOC: TrackingAllocator = TrackingAllocator(std::alloc::System); /// Contains the bytes for a successfully compiled artifact. +#[derive(Encode, Decode)] pub struct CompiledArtifact(Vec); impl CompiledArtifact { @@ -80,6 +93,7 @@ impl AsRef<[u8]> for CompiledArtifact { } } +/// Get a worker request. fn recv_request(stream: &mut UnixStream) -> io::Result { let pvf = framed_recv_blocking(stream)?; let pvf = PvfPrepData::decode(&mut &pvf[..]).map_err(|e| { @@ -91,6 +105,7 @@ fn recv_request(stream: &mut UnixStream) -> io::Result { Ok(pvf) } +/// Send a worker response. fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<()> { framed_send_blocking(stream, &result.encode()) } @@ -111,18 +126,22 @@ fn start_memory_tracking(fd: RawFd, limit: Option) { // Syscalls never allocate or deallocate, so this is safe. libc::syscall(libc::SYS_write, fd, OOM_PAYLOAD.as_ptr(), OOM_PAYLOAD.len()); libc::syscall(libc::SYS_close, fd); - libc::syscall(libc::SYS_exit, 1); + // Make sure we exit from all threads. Copied from glibc. + libc::syscall(libc::SYS_exit_group, 1); + loop { + libc::syscall(libc::SYS_exit, 1); + } } #[cfg(not(target_os = "linux"))] { // Syscalls are not available on MacOS, so we have to use `libc` wrappers. - // Technicaly, there may be allocations inside, although they shouldn't be + // Technically, there may be allocations inside, although they shouldn't be // there. In that case, we'll see deadlocks on MacOS after the OOM condition // triggered. As we consider running a validator on MacOS unsafe, and this // code is only run by a validator, it's a lesser evil. libc::write(fd, OOM_PAYLOAD.as_ptr().cast(), OOM_PAYLOAD.len()); libc::close(fd); - std::process::exit(1); + libc::_exit(1); } })), ); @@ -155,17 +174,19 @@ fn end_memory_tracking() -> isize { /// /// 1. Get the code and parameters for preparation from the host. /// -/// 2. Start a memory tracker in a separate thread. +/// 2. Start a new child process /// -/// 3. Start the CPU time monitor loop and the actual preparation in two separate threads. +/// 3. Start the memory tracker and the actual preparation in two separate threads. /// /// 4. Wait on the two threads created in step 3. /// /// 5. Stop the memory tracker and get the stats. /// -/// 6. If compilation succeeded, write the compiled artifact into a temporary file. +/// 6. Pipe the result back to the parent process and exit from child process. /// -/// 7. Send the result of preparation back to the host. If any error occurred in the above steps, we +/// 7. If compilation succeeded, write the compiled artifact into a temporary file. +/// +/// 8. 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: PathBuf, @@ -174,7 +195,7 @@ pub fn worker_entrypoint( worker_version: Option<&str>, security_status: SecurityStatus, ) { - worker_event_loop( + run_worker( WorkerKind::Prepare, socket_path, worker_dir_path, @@ -182,7 +203,7 @@ pub fn worker_entrypoint( worker_version, &security_status, |mut stream, worker_dir_path| { - let worker_pid = std::process::id(); + let worker_pid = process::id(); let temp_artifact_dest = worker_dir::prepare_tmp_artifact(&worker_dir_path); loop { @@ -197,186 +218,58 @@ pub fn worker_entrypoint( let prepare_job_kind = pvf.prep_kind(); let executor_params = pvf.executor_params(); - // Conditional variable to notify us when a thread is done. - let condvar = thread::get_condvar(); - - // Run the memory tracker in a regular, non-worker thread. - #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] - let condvar_memory = Arc::clone(&condvar); - #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] - let memory_tracker_thread = std::thread::spawn(|| memory_tracker_loop(condvar_memory)); + let (pipe_reader, pipe_writer) = os_pipe::pipe()?; - let cpu_time_start = ProcessTime::now(); - - // Spawn a new thread that runs the CPU time monitor. - let (cpu_time_monitor_tx, cpu_time_monitor_rx) = channel::<()>(); - let cpu_time_monitor_thread = thread::spawn_worker_thread( - "cpu time monitor thread", - move || { - cpu_time_monitor_loop( - cpu_time_start, - preparation_timeout, - cpu_time_monitor_rx, - ) + let usage_before = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { + Ok(usage) => usage, + Err(errno) => { + let result = Err(error_from_errno("getrusage before", errno)); + send_response(&mut stream, result)?; + continue }, - Arc::clone(&condvar), - WaitOutcome::TimedOut, - )?; - - start_memory_tracking( - stream.as_raw_fd(), - executor_params.prechecking_max_memory().map(|v| { - v.try_into().unwrap_or_else(|_| { - gum::warn!( - LOG_TARGET, - %worker_pid, - "Illegal pre-checking max memory value {} discarded", - v, - ); - 0 - }) - }), - ); - - // Spawn another thread for preparation. - let prepare_thread = thread::spawn_worker_thread( - "prepare thread", - move || { - #[allow(unused_mut)] - let mut result = prepare_artifact(pvf, cpu_time_start); - - // Get the `ru_maxrss` stat. If supported, call getrusage for the thread. - #[cfg(target_os = "linux")] - let mut result = result - .map(|(artifact, elapsed)| (artifact, elapsed, get_max_rss_thread())); - - // If we are pre-checking, check for runtime construction errors. - // - // As pre-checking is more strict than just preparation in terms of memory - // and time, it is okay to do extra checks here. This takes negligible time - // anyway. - if let PrepareJobKind::Prechecking = prepare_job_kind { - result = result.and_then(|output| { - runtime_construction_check( - output.0.as_ref(), - executor_params.as_ref(), - )?; - Ok(output) - }); - } - - result - }, - Arc::clone(&condvar), - WaitOutcome::Finished, - )?; - - let outcome = thread::wait_for_threads(condvar); - - let peak_alloc = { - let peak = end_memory_tracking(); - gum::debug!( - target: LOG_TARGET, - %worker_pid, - "prepare job peak allocation is {} bytes", - peak, - ); - peak }; - let result = match outcome { - WaitOutcome::Finished => { - let _ = cpu_time_monitor_tx.send(()); - - match prepare_thread.join().unwrap_or_else(|err| { - Err(PrepareError::Panic(stringify_panic_payload(err))) - }) { - Err(err) => { - // Serialized error will be written into the socket. - Err(err) - }, - 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"))] - let memory_tracker_stats = get_memory_tracker_loop_stats(memory_tracker_thread, worker_pid); - let memory_stats = MemoryStats { - #[cfg(any( - target_os = "linux", - feature = "jemalloc-allocator" - ))] - memory_tracker_stats, - #[cfg(target_os = "linux")] - max_rss: extract_max_rss_stat(max_rss, worker_pid), - // Negative peak allocation values are legit; they are narrow - // corner cases and shouldn't affect overall statistics - // significantly - peak_tracked_alloc: if peak_alloc > 0 { - peak_alloc as u64 - } else { - 0u64 - }, - }; - - // Write the serialized artifact into a temp file. - // - // PVF host only keeps artifacts statuses in its memory, - // successfully compiled code gets stored on the disk (and - // consequently deserialized by execute-workers). The prepare worker - // is only required to send `Ok` to the pool to indicate the - // success. - - gum::debug!( - target: LOG_TARGET, - %worker_pid, - "worker: writing artifact to {}", - temp_artifact_dest.display(), - ); - fs::write(&temp_artifact_dest, &artifact)?; - - Ok(PrepareStats { cpu_time_elapsed, memory_stats }) - }, - } + // SAFETY: new process is spawned within a single threaded process. This invariant + // is enforced by tests. + let result = match unsafe { nix::unistd::fork() } { + Err(errno) => Err(error_from_errno("fork", errno)), + Ok(ForkResult::Child) => { + // Dropping the stream closes the underlying socket. We want to make sure + // that the sandboxed child can't get any kind of information from the + // outside world. The only IPC it should be able to do is sending its + // response over the pipe. + drop(stream); + // Drop the read end so we don't have too many FDs open. + drop(pipe_reader); + + handle_child_process( + pvf, + pipe_writer, + preparation_timeout, + prepare_job_kind, + executor_params, + ) }, - // 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. - WaitOutcome::TimedOut => { - match cpu_time_monitor_thread.join() { - Ok(Some(cpu_time_elapsed)) => { - // Log if we exceed the timeout and the other thread hasn't - // finished. - gum::warn!( - target: LOG_TARGET, - %worker_pid, - "prepare job took {}ms cpu time, exceeded prepare timeout {}ms", - cpu_time_elapsed.as_millis(), - preparation_timeout.as_millis(), - ); - Err(PrepareError::TimedOut) - }, - Ok(None) => Err(PrepareError::IoErr( - "error communicating over closed channel".into(), - )), - // Errors in this thread are independent of the PVF. - Err(err) => Err(PrepareError::IoErr(stringify_panic_payload(err))), - } + Ok(ForkResult::Parent { child }) => { + // the read end will wait until all write ends have been closed, + // this drop is necessary to avoid deadlock + drop(pipe_writer); + + handle_parent_process( + pipe_reader, + child, + temp_artifact_dest.clone(), + worker_pid, + usage_before, + preparation_timeout, + ) }, - WaitOutcome::Pending => unreachable!( - "we run wait_while until the outcome is no longer pending; qed" - ), }; gum::trace!( target: LOG_TARGET, %worker_pid, - "worker: sending response to host: {:?}", + "worker: sending result to host: {:?}", result ); send_response(&mut stream, result)?; @@ -385,10 +278,7 @@ pub fn worker_entrypoint( ); } -fn prepare_artifact( - pvf: PvfPrepData, - cpu_time_start: ProcessTime, -) -> Result<(CompiledArtifact, Duration), PrepareError> { +fn prepare_artifact(pvf: PvfPrepData) -> Result { let blob = match prevalidate(&pvf.code()) { Err(err) => return Err(PrepareError::Prevalidation(format!("{:?}", err))), Ok(b) => b, @@ -398,7 +288,6 @@ fn prepare_artifact( Ok(compiled_artifact) => Ok(CompiledArtifact::new(compiled_artifact)), Err(err) => Err(PrepareError::Preparation(format!("{:?}", err))), } - .map(|artifact| (artifact, cpu_time_start.elapsed())) } /// Try constructing the runtime to catch any instantiation errors during pre-checking. @@ -412,3 +301,372 @@ fn runtime_construction_check( .map(|_runtime| ()) .map_err(|err| PrepareError::RuntimeConstruction(format!("{:?}", err))) } + +#[derive(Encode, Decode)] +struct JobResponse { + artifact: CompiledArtifact, + memory_stats: MemoryStats, +} + +/// This is used to handle child process during pvf prepare worker. +/// It prepares the artifact and tracks memory stats during preparation +/// and pipes back the response to the parent process +/// +/// # Arguments +/// +/// - `pvf`: `PvfPrepData` structure, containing data to prepare the artifact +/// +/// - `pipe_write`: A `PipeWriter` structure, the writing end of a pipe. +/// +/// - `preparation_timeout`: The timeout in `Duration`. +/// +/// - `prepare_job_kind`: The kind of prepare job. +/// +/// - `executor_params`: Deterministically serialized execution environment semantics. +/// +/// # Returns +/// +/// - If any error occur, pipe response back with `PrepareError`. +/// +/// - If success, pipe back `JobResponse`. +fn handle_child_process( + pvf: PvfPrepData, + mut pipe_write: PipeWriter, + preparation_timeout: Duration, + prepare_job_kind: PrepareJobKind, + executor_params: Arc, +) -> ! { + let worker_job_pid = process::id(); + gum::debug!( + target: LOG_TARGET, + %worker_job_pid, + ?prepare_job_kind, + ?preparation_timeout, + "worker job: preparing artifact", + ); + + // Conditional variable to notify us when a thread is done. + let condvar = thread::get_condvar(); + + // Run the memory tracker in a regular, non-worker thread. + #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] + let condvar_memory = Arc::clone(&condvar); + #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] + let memory_tracker_thread = std::thread::spawn(|| memory_tracker_loop(condvar_memory)); + + start_memory_tracking( + pipe_write.as_raw_fd(), + executor_params.prechecking_max_memory().map(|v| { + v.try_into().unwrap_or_else(|_| { + gum::warn!( + LOG_TARGET, + %worker_job_pid, + "Illegal pre-checking max memory value {} discarded", + v, + ); + 0 + }) + }), + ); + + let cpu_time_start = ProcessTime::now(); + + // Spawn a new thread that runs the CPU time monitor. + let (cpu_time_monitor_tx, cpu_time_monitor_rx) = channel::<()>(); + let cpu_time_monitor_thread = thread::spawn_worker_thread( + "cpu time monitor thread", + move || cpu_time_monitor_loop(cpu_time_start, preparation_timeout, cpu_time_monitor_rx), + Arc::clone(&condvar), + WaitOutcome::TimedOut, + ) + .unwrap_or_else(|err| { + send_child_response(&mut pipe_write, Err(PrepareError::IoErr(err.to_string()))) + }); + + let prepare_thread = spawn_worker_thread( + "prepare worker", + move || { + #[allow(unused_mut)] + let mut result = prepare_artifact(pvf); + + // Get the `ru_maxrss` stat. If supported, call getrusage for the thread. + #[cfg(target_os = "linux")] + let mut result = result.map(|artifact| (artifact, get_max_rss_thread())); + + // If we are pre-checking, check for runtime construction errors. + // + // As pre-checking is more strict than just preparation in terms of memory + // and time, it is okay to do extra checks here. This takes negligible time + // anyway. + if let PrepareJobKind::Prechecking = prepare_job_kind { + result = result.and_then(|output| { + runtime_construction_check(output.0.as_ref(), &executor_params)?; + Ok(output) + }); + } + result + }, + Arc::clone(&condvar), + WaitOutcome::Finished, + ) + .unwrap_or_else(|err| { + send_child_response(&mut pipe_write, Err(PrepareError::IoErr(err.to_string()))) + }); + + let outcome = thread::wait_for_threads(condvar); + + let peak_alloc = { + let peak = end_memory_tracking(); + gum::debug!( + target: LOG_TARGET, + %worker_job_pid, + "prepare job peak allocation is {} bytes", + peak, + ); + peak + }; + + let result = match outcome { + WaitOutcome::Finished => { + let _ = cpu_time_monitor_tx.send(()); + + match prepare_thread.join().unwrap_or_else(|err| { + send_child_response( + &mut pipe_write, + Err(PrepareError::JobError(stringify_panic_payload(err))), + ) + }) { + Err(err) => Err(err), + Ok(ok) => { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + let (artifact, max_rss) = ok; + } else { + let artifact = ok; + } + } + + // Stop the memory stats worker and get its observed memory stats. + #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] + let memory_tracker_stats = get_memory_tracker_loop_stats(memory_tracker_thread, process::id()); + + let memory_stats = MemoryStats { + #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] + memory_tracker_stats, + #[cfg(target_os = "linux")] + max_rss: extract_max_rss_stat(max_rss, process::id()), + // Negative peak allocation values are legit; they are narrow + // corner cases and shouldn't affect overall statistics + // significantly + peak_tracked_alloc: if peak_alloc > 0 { peak_alloc as u64 } else { 0u64 }, + }; + + Ok(JobResponse { artifact, memory_stats }) + }, + } + }, + + // 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. + WaitOutcome::TimedOut => match cpu_time_monitor_thread.join() { + Ok(Some(_cpu_time_elapsed)) => Err(PrepareError::TimedOut), + Ok(None) => Err(PrepareError::IoErr("error communicating over closed channel".into())), + Err(err) => Err(PrepareError::IoErr(stringify_panic_payload(err))), + }, + WaitOutcome::Pending => + unreachable!("we run wait_while until the outcome is no longer pending; qed"), + }; + + send_child_response(&mut pipe_write, result); +} + +/// Waits for child process to finish and handle child response from pipe. +/// +/// # Arguments +/// +/// - `pipe_read`: A `PipeReader` used to read data from the child process. +/// +/// - `child`: The child pid. +/// +/// - `temp_artifact_dest`: The destination `PathBuf` to write the temporary artifact file. +/// +/// - `worker_pid`: The PID of the child process. +/// +/// - `usage_before`: Resource usage statistics before executing the child process. +/// +/// - `timeout`: The maximum allowed time for the child process to finish, in `Duration`. +/// +/// # Returns +/// +/// - If the child send response without an error, this function returns `Ok(PrepareStats)` +/// containing memory and CPU usage statistics. +/// +/// - If the child send response with an error, it returns a `PrepareError` with that error. +/// +/// - If the child process timeout, it returns `PrepareError::TimedOut`. +fn handle_parent_process( + mut pipe_read: PipeReader, + child: Pid, + temp_artifact_dest: PathBuf, + worker_pid: u32, + usage_before: Usage, + timeout: Duration, +) -> Result { + // Read from the child. Don't decode unless the process exited normally, which we check later. + let mut received_data = Vec::new(); + pipe_read + .read_to_end(&mut received_data) + .map_err(|err| PrepareError::IoErr(err.to_string()))?; + + let status = nix::sys::wait::waitpid(child, None); + gum::trace!( + target: LOG_TARGET, + %worker_pid, + "prepare worker received wait status from job: {:?}", + status, + ); + + let usage_after = nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) + .map_err(|errno| error_from_errno("getrusage after", errno))?; + + // Using `getrusage` is needed to check whether child has timedout since we cannot rely on + // child to report its own time. + // As `getrusage` returns resource usage from all terminated child processes, + // it is necessary to subtract the usage before the current child process to isolate its cpu + // time + let cpu_tv = get_total_cpu_usage(usage_after) - get_total_cpu_usage(usage_before); + if cpu_tv >= timeout { + gum::warn!( + target: LOG_TARGET, + %worker_pid, + "prepare job took {}ms cpu time, exceeded prepare timeout {}ms", + cpu_tv.as_millis(), + timeout.as_millis(), + ); + return Err(PrepareError::TimedOut) + } + + match status { + Ok(WaitStatus::Exited(_pid, exit_status)) => { + let mut reader = io::BufReader::new(received_data.as_slice()); + let result = recv_child_response(&mut reader) + .map_err(|err| PrepareError::JobError(err.to_string()))?; + + match result { + Err(err) => Err(err), + Ok(response) => { + // The exit status should have been zero if no error occurred. + if exit_status != 0 { + return Err(PrepareError::JobError(format!( + "unexpected exit status: {}", + exit_status + ))) + } + + // Write the serialized artifact into a temp file. + // + // PVF host only keeps artifacts statuses in its memory, + // successfully compiled code gets stored on the disk (and + // consequently deserialized by execute-workers). The prepare worker + // is only required to send `Ok` to the pool to indicate the + // success. + gum::debug!( + target: LOG_TARGET, + %worker_pid, + "worker: writing artifact to {}", + temp_artifact_dest.display(), + ); + // Write to the temp file created by the host. + if let Err(err) = fs::write(&temp_artifact_dest, &response.artifact) { + return Err(PrepareError::IoErr(err.to_string())) + }; + + Ok(PrepareStats { + memory_stats: response.memory_stats, + cpu_time_elapsed: cpu_tv, + }) + }, + } + }, + // The job was killed by the given signal. + // + // The job gets SIGSYS on seccomp violations, but this signal may have been sent for some + // other reason, so we still need to check for seccomp violations elsewhere. + Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => + Err(PrepareError::JobDied(format!("received signal: {signal:?}"))), + Err(errno) => Err(error_from_errno("waitpid", errno)), + + // An attacker can make the child process return any exit status it wants. So we can treat + // all unexpected cases the same way. + Ok(unexpected_wait_status) => Err(PrepareError::JobDied(format!( + "unexpected status from wait: {unexpected_wait_status:?}" + ))), + } +} + +/// Calculate the total CPU time from the given `usage` structure, returned from +/// [`nix::sys::resource::getrusage`], and calculates the total CPU time spent, including both user +/// and system time. +/// +/// # Arguments +/// +/// - `rusage`: Contains resource usage information. +/// +/// # Returns +/// +/// Returns a `Duration` representing the total CPU time. +fn get_total_cpu_usage(rusage: Usage) -> Duration { + let micros = (((rusage.user_time().tv_sec() + rusage.system_time().tv_sec()) * 1_000_000) + + (rusage.system_time().tv_usec() + rusage.user_time().tv_usec()) as i64) as u64; + + return Duration::from_micros(micros) +} + +/// Get a job response. +fn recv_child_response(received_data: &mut io::BufReader<&[u8]>) -> io::Result { + let response_bytes = framed_recv_blocking(received_data)?; + JobResult::decode(&mut response_bytes.as_slice()).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("prepare pvf recv_child_response: decode error: {:?}", e), + ) + }) +} + +/// Write a job response to the pipe and exit process after. +/// +/// # Arguments +/// +/// - `pipe_write`: A `PipeWriter` structure, the writing end of a pipe. +/// +/// - `response`: Child process response +fn send_child_response(pipe_write: &mut PipeWriter, response: JobResult) -> ! { + framed_send_blocking(pipe_write, response.encode().as_slice()) + .unwrap_or_else(|_| process::exit(libc::EXIT_FAILURE)); + + if response.is_ok() { + process::exit(libc::EXIT_SUCCESS) + } else { + process::exit(libc::EXIT_FAILURE) + } +} + +fn error_from_errno(context: &'static str, errno: Errno) -> PrepareError { + PrepareError::Kernel(format!("{}: {}: {}", context, errno, io::Error::last_os_error())) +} + +type JobResult = Result; + +/// Pre-encoded length-prefixed `Result::Err(PrepareError::OutOfMemory)` +const OOM_PAYLOAD: &[u8] = b"\x02\x00\x00\x00\x00\x00\x00\x00\x01\x08"; + +#[test] +fn pre_encoded_payloads() { + // NOTE: This must match the type of `response` in `send_child_response`. + let oom_unencoded: JobResult = Result::Err(PrepareError::OutOfMemory); + let oom_encoded = oom_unencoded.encode(); + // The payload is prefixed with its length in `framed_send`. + let mut oom_payload = oom_encoded.len().to_le_bytes().to_vec(); + oom_payload.extend(oom_encoded); + assert_eq!(oom_payload, OOM_PAYLOAD); +} diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index 87ef0b54a04..7fdb8c56ec9 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -33,36 +33,37 @@ pub enum ValidationError { pub enum InvalidCandidate { /// PVF preparation ended up with a deterministic error. PrepareError(String), - /// The failure is reported by the execution worker. The string contains the error message. - WorkerReportedError(String), - /// The worker has died during validation of a candidate. That may fall in one of the following - /// categories, which we cannot distinguish programmatically: + /// The candidate is reported to be invalid by the execution worker. The string contains the + /// error message. + WorkerReportedInvalid(String), + /// The worker process (not the job) has died during validation of a candidate. /// - /// (a) Some sort of transient glitch caused the worker process to abort. An example would be - /// that the host machine ran out of free memory and the OOM killer started killing the - /// processes, and in order to save the parent it will "sacrifice child" first. - /// - /// (b) The candidate triggered a code path that has lead to the process death. For example, - /// the PVF found a way to consume unbounded amount of resources and then it either - /// exceeded an `rlimit` (if set) or, again, invited OOM killer. Another possibility is a - /// bug in wasmtime allowed the PVF to gain control over the execution worker. - /// - /// We attribute such an event to an *invalid candidate* in either case. - /// - /// The rationale for this is that a glitch may lead to unfair rejecting candidate by a single - /// validator. If the glitch is somewhat more persistent the validator will reject all - /// candidate thrown at it and hopefully the operator notices it by decreased reward - /// performance of the validator. On the other hand, if the worker died because of (b) we would - /// have better chances to stop the attack. + /// It's unlikely that this is caused by malicious code since workers spawn separate job + /// processes, and those job processes are sandboxed. But, it is possible. We retry in this + /// case, and if the error persists, we assume it's caused by the candidate and vote against. AmbiguousWorkerDeath, /// PVF execution (compilation is not included) took more time than was allotted. HardTimeout, - /// A panic occurred and we can't be sure whether the candidate is really invalid or some - /// internal glitch occurred. Whenever we are unsure, we can never treat an error as internal - /// as we would abstain from voting. This is bad because if the issue was due to the candidate, - /// then all validators would abstain, stalling finality on the chain. So we will first retry - /// the candidate, and if the issue persists we are forced to vote invalid. - Panic(String), + /// The job process (not the worker) has died for one of the following reasons: + /// + /// (a) A seccomp violation occurred, most likely due to an attempt by malicious code to + /// execute arbitrary code. Note that there is no foolproof way to detect this if the operator + /// has seccomp auditing disabled. + /// + /// (b) The host machine ran out of free memory and the OOM killer started killing the + /// processes, and in order to save the parent it will "sacrifice child" first. + /// + /// (c) Some other reason, perhaps transient or perhaps caused by malicious code. + /// + /// We cannot treat this as an internal error because malicious code may have caused this. + AmbiguousJobDeath(String), + /// An unexpected error occurred in the job process and we can't be sure whether the candidate + /// is really invalid or some internal glitch occurred. Whenever we are unsure, we can never + /// treat an error as internal as we would abstain from voting. This is bad because if the + /// issue was due to the candidate, then all validators would abstain, stalling finality on the + /// chain. So we will first retry the candidate, and if the issue persists we are forced to + /// vote invalid. + JobError(String), } impl From for ValidationError { diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index aca604f0de2..257377df3f4 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -342,20 +342,27 @@ fn handle_job_finish( }, Outcome::InvalidCandidate { err, idle_worker } => ( Some(idle_worker), - Err(ValidationError::InvalidCandidate(InvalidCandidate::WorkerReportedError(err))), + Err(ValidationError::InvalidCandidate(InvalidCandidate::WorkerReportedInvalid(err))), None, ), Outcome::InternalError { err } => (None, Err(ValidationError::InternalError(err)), None), + // Either the worker or the job timed out. Kill the worker in either case. Treated as + // definitely-invalid, because if we timed out, there's no time left for a retry. Outcome::HardTimeout => (None, Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)), None), // "Maybe invalid" errors (will retry). - Outcome::IoErr => ( + Outcome::WorkerIntfErr => ( None, Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)), None, ), - Outcome::Panic { err } => - (None, Err(ValidationError::InvalidCandidate(InvalidCandidate::Panic(err))), None), + Outcome::JobDied { err } => ( + None, + Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousJobDeath(err))), + None, + ), + Outcome::JobError { err } => + (None, Err(ValidationError::InvalidCandidate(InvalidCandidate::JobError(err))), None), }; queue.metrics.execute_finished(); diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index 61264f7d517..bf44ba01725 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -30,7 +30,7 @@ use futures_timer::Delay; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, - execute::{Handshake, Response}, + execute::{Handshake, WorkerResponse}, worker_dir, SecurityStatus, }; use polkadot_parachain_primitives::primitives::ValidationResult; @@ -88,19 +88,26 @@ pub enum Outcome { /// a trap. Errors related to the preparation process are not expected to be encountered by the /// execution workers. InvalidCandidate { err: String, idle_worker: IdleWorker }, + /// The execution time exceeded the hard limit. The worker is terminated. + HardTimeout, + /// An I/O error happened during communication with the worker. This may mean that the worker + /// process already died. The token is not returned in any case. + WorkerIntfErr, + /// The job process has died. We must kill the worker just in case. + /// + /// We cannot treat this as an internal error because malicious code may have caused this. + JobDied { err: String }, + /// An unexpected error occurred in the job process. + /// + /// Because malicious code can cause a job error, we must not treat it as an internal error. + JobError { err: String }, + /// An internal error happened during the validation. Such an error is most likely related to /// some transient glitch. /// /// Should only ever be used for errors independent of the candidate and PVF. Therefore it may /// be a problem with the worker, so we terminate it. InternalError { err: InternalValidationError }, - /// The execution time exceeded the hard limit. The worker is terminated. - HardTimeout, - /// An I/O error happened during communication with the worker. This may mean that the worker - /// process already died. The token is not returned in any case. - IoErr, - /// An unexpected panic has occurred in the execution worker. - Panic { err: String }, } /// Given the idle token of a worker and parameters of work, communicates with the worker and @@ -137,7 +144,7 @@ pub async fn start_work( ?error, "failed to send an execute request", ); - return Outcome::IoErr + return Outcome::WorkerIntfErr } // We use a generous timeout here. This is in addition to the one in the child process, in @@ -173,7 +180,7 @@ pub async fn start_work( ); } - return Outcome::IoErr + return Outcome::WorkerIntfErr }, Ok(response) => { // Check if any syscall violations occurred during the job. For now this is @@ -189,7 +196,7 @@ pub async fn start_work( ); } - if let Response::Ok{duration, ..} = response { + if let WorkerResponse::Ok{duration, ..} = response { if duration > execution_timeout { // The job didn't complete within the timeout. gum::warn!( @@ -201,7 +208,7 @@ pub async fn start_work( ); // Return a timeout error. - return Outcome::HardTimeout; + return Outcome::HardTimeout } } @@ -216,23 +223,25 @@ pub async fn start_work( validation_code_hash = ?artifact.id.code_hash, "execution worker exceeded lenient timeout for execution, child worker likely stalled", ); - Response::TimedOut + WorkerResponse::JobTimedOut }, }; match response { - Response::Ok { result_descriptor, duration } => Outcome::Ok { + WorkerResponse::Ok { result_descriptor, duration } => Outcome::Ok { result_descriptor, duration, idle_worker: IdleWorker { stream, pid, worker_dir }, }, - Response::InvalidCandidate(err) => Outcome::InvalidCandidate { + WorkerResponse::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 }, + WorkerResponse::JobTimedOut => Outcome::HardTimeout, + WorkerResponse::JobDied(err) => Outcome::JobDied { err }, + WorkerResponse::JobError(err) => Outcome::JobError { err }, + + WorkerResponse::InternalError(err) => Outcome::InternalError { err }, } }) .await @@ -306,9 +315,9 @@ async fn send_request( framed_send(stream, &execution_timeout.encode()).await } -async fn recv_response(stream: &mut UnixStream) -> io::Result { +async fn recv_response(stream: &mut UnixStream) -> io::Result { let response_bytes = framed_recv(stream).await?; - Response::decode(&mut &response_bytes[..]).map_err(|e| { + WorkerResponse::decode(&mut response_bytes.as_slice()).map_err(|e| { io::Error::new( io::ErrorKind::Other, format!("execute pvf recv_response: decode error: {:?}", e), diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 6bb6ca5b644..8e02f540d32 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -339,17 +339,17 @@ fn handle_mux( spawned, worker, idle, - Err(PrepareError::CreateTmpFileErr(err)), + Err(PrepareError::CreateTmpFile(err)), ), // Return `Concluded`, but do not kill the worker since the error was on the host // side. - Outcome::RenameTmpFileErr { worker: idle, result: _, err, src, dest } => + Outcome::RenameTmpFile { worker: idle, result: _, err, src, dest } => handle_concluded_no_rip( from_pool, spawned, worker, idle, - Err(PrepareError::RenameTmpFileErr { err, src, dest }), + Err(PrepareError::RenameTmpFile { err, src, dest }), ), // Could not clear worker cache. Kill the worker so other jobs can't see the data. Outcome::ClearWorkerDir { err } => { @@ -387,6 +387,21 @@ fn handle_mux( Ok(()) }, + // The worker might still be usable, but we kill it just in case. + Outcome::JobDied(err) => { + if attempt_retire(metrics, spawned, worker) { + reply( + from_pool, + FromPool::Concluded { + worker, + rip: true, + result: Err(PrepareError::JobDied(err)), + }, + )?; + } + + Ok(()) + }, Outcome::TimedOut => { if attempt_retire(metrics, spawned, worker) { reply( diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index 0e50caf1feb..a22fa74b2fe 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -79,7 +79,7 @@ pub enum Outcome { CreateTmpFileErr { worker: IdleWorker, err: String }, /// The response from the worker is received, but the tmp file cannot be renamed (moved) to the /// final destination location. - RenameTmpFileErr { + RenameTmpFile { worker: IdleWorker, result: PrepareResult, err: String, @@ -100,6 +100,10 @@ pub enum Outcome { IoErr(String), /// The worker ran out of memory and is aborting. The worker should be ripped. OutOfMemory, + /// The preparation job process died, due to OOM, a seccomp violation, or some other factor. + /// + /// The worker might still be usable, but we kill it just in case. + JobDied(String), } /// Given the idle token of a worker and parameters of work, communicates with the worker and @@ -187,21 +191,6 @@ pub async fn start_work( "failed to recv a prepare response: {:?}", err, ); - - // The worker died. Check if it was due to a seccomp violation. - // - // NOTE: Log, but don't change the outcome. Not all validators may have auditing - // enabled, so we don't want attackers to abuse a non-deterministic outcome. - for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await { - gum::error!( - target: LOG_TARGET, - worker_pid = %pid, - %syscall, - ?pvf, - "A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!" - ); - } - Outcome::IoErr(err.to_string()) }, Err(_) => { @@ -236,6 +225,7 @@ async fn handle_response( Ok(result) => result, // Timed out on the child. This should already be logged by the child. Err(PrepareError::TimedOut) => return Outcome::TimedOut, + Err(PrepareError::JobDied(err)) => return Outcome::JobDied(err), Err(PrepareError::OutOfMemory) => return Outcome::OutOfMemory, Err(_) => return Outcome::Concluded { worker, result }, }; @@ -272,7 +262,7 @@ async fn handle_response( artifact_path.display(), err, ); - Outcome::RenameTmpFileErr { + Outcome::RenameTmpFile { worker, result, err: format!("{:?}", err), diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 4c038896f7f..400b65bfe7d 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Various things for testing other crates. +//! Various utilities for testing. pub use crate::{ host::{EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME}, @@ -59,27 +59,33 @@ pub fn validate_candidate( /// /// NOTE: This should only be called in dev code (tests, benchmarks) as it relies on the relative /// paths of the built workers. -pub fn get_and_check_worker_paths() -> (PathBuf, PathBuf) { +pub fn build_workers_and_get_paths(is_bench: bool) -> (PathBuf, PathBuf) { // Only needs to be called once for the current process. static WORKER_PATHS: OnceLock> = OnceLock::new(); - fn build_workers() { - let build_args = vec![ + fn build_workers(is_bench: bool) { + let mut build_args = vec![ "build", "--package=polkadot", "--bin=polkadot-prepare-worker", "--bin=polkadot-execute-worker", ]; - let exit_status = std::process::Command::new("cargo") + if is_bench { + // Benches require --release. Regular tests are debug (no flag needed). + build_args.push("--release"); + } + let mut cargo = std::process::Command::new("cargo"); + let cmd = cargo // wasm runtime not needed .env("SKIP_WASM_BUILD", "1") .args(build_args) - .stdout(std::process::Stdio::piped()) - .status() - .expect("Failed to run the build program"); + .stdout(std::process::Stdio::piped()); + + println!("INFO: calling `{cmd:?}`"); + let exit_status = cmd.status().expect("Failed to run the build program"); if !exit_status.success() { - eprintln!("Failed to build workers: {}", exit_status.code().unwrap()); + eprintln!("ERROR: Failed to build workers: {}", exit_status.code().unwrap()); std::process::exit(1); } } @@ -95,23 +101,23 @@ pub fn get_and_check_worker_paths() -> (PathBuf, PathBuf) { // explain why a build happens if !prepare_worker_path.is_executable() { - eprintln!("Prepare worker does not exist or is not executable. Workers directory: {:?}", workers_path); + println!("WARN: Prepare worker does not exist or is not executable. Workers directory: {:?}", workers_path); } if !execute_worker_path.is_executable() { - eprintln!("Execute worker does not exist or is not executable. Workers directory: {:?}", workers_path); + println!("WARN: Execute worker does not exist or is not executable. Workers directory: {:?}", workers_path); } if let Ok(ver) = get_worker_version(&prepare_worker_path) { if ver != NODE_VERSION { - eprintln!("Prepare worker version {ver} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}"); + println!("WARN: Prepare worker version {ver} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}"); } } if let Ok(ver) = get_worker_version(&execute_worker_path) { if ver != NODE_VERSION { - eprintln!("Execute worker version {ver} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}"); + println!("WARN: Execute worker version {ver} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}"); } } - build_workers(); + build_workers(is_bench); Mutex::new((prepare_worker_path, execute_worker_path)) }); diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 801b60884fa..d2d842cf84a 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -19,23 +19,23 @@ use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ - start, testing::get_and_check_worker_paths, Config, InvalidCandidate, Metrics, PrepareError, + start, testing::build_workers_and_get_paths, 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::{ExecutorParam, ExecutorParams}; -#[cfg(target_os = "linux")] -use rusty_fork::rusty_fork_test; use std::time::Duration; use tokio::sync::Mutex; mod adder; +#[cfg(target_os = "linux")] +mod process; mod worker_common; -const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); -const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(3); +const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(6); +const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(6); struct TestHost { cache_dir: tempfile::TempDir, @@ -51,7 +51,7 @@ impl TestHost { where F: FnOnce(&mut Config), { - let (prepare_worker_path, execute_worker_path) = get_and_check_worker_paths(); + let (prepare_worker_path, execute_worker_path) = build_workers_and_get_paths(false); let cache_dir = tempfile::tempdir().unwrap(); let mut config = Config::new( @@ -126,7 +126,26 @@ impl TestHost { } #[tokio::test] -async fn terminates_on_timeout() { +async fn prepare_job_terminates_on_timeout() { + let host = TestHost::new().await; + + let start = std::time::Instant::now(); + let result = host + .precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()) + .await; + + match result { + Err(PrepareError::TimedOut) => {}, + r => panic!("{:?}", r), + } + + let duration = std::time::Instant::now().duration_since(start); + assert!(duration >= TEST_PREPARATION_TIMEOUT); + assert!(duration < TEST_PREPARATION_TIMEOUT * JOB_TIMEOUT_WALL_CLOCK_FACTOR); +} + +#[tokio::test] +async fn execute_job_terminates_on_timeout() { let host = TestHost::new().await; let start = std::time::Instant::now(); @@ -153,108 +172,6 @@ async fn terminates_on_timeout() { assert!(duration < TEST_EXECUTION_TIMEOUT * JOB_TIMEOUT_WALL_CLOCK_FACTOR); } -#[cfg(target_os = "linux")] -fn kill_by_sid_and_name(sid: i32, exe_name: &'static str) { - use procfs::process; - - let all_processes: Vec = process::all_processes() - .expect("Can't read /proc") - .filter_map(|p| match p { - Ok(p) => Some(p), // happy path - Err(e) => match e { - // process vanished during iteration, ignore it - procfs::ProcError::NotFound(_) => None, - x => { - panic!("some unknown error: {}", x); - }, - }, - }) - .collect(); - - for process in all_processes { - if process.stat().unwrap().session == sid && - process.exe().unwrap().to_str().unwrap().contains(exe_name) - { - assert_eq!(unsafe { libc::kill(process.pid(), 9) }, 0); - } - } -} - -// Run these tests in their own processes with rusty-fork. They work by each creating a new session, -// then killing the worker process that matches the session ID and expected worker name. -#[cfg(target_os = "linux")] -rusty_fork_test! { - // What happens when the prepare worker dies in the middle of a job? - #[test] - fn prepare_worker_killed_during_job() { - const PROCESS_NAME: &'static str = "polkadot-prepare-worker"; - - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let host = TestHost::new().await; - - // Create a new session and get the session ID. - let sid = unsafe { libc::setsid() }; - assert!(sid > 0); - - let (result, _) = futures::join!( - // Choose a job that would normally take the entire timeout. - host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), - // Run a future that kills the job in the middle of the timeout. - async { - tokio::time::sleep(TEST_PREPARATION_TIMEOUT / 2).await; - kill_by_sid_and_name(sid, PROCESS_NAME); - } - ); - - assert_matches!(result, Err(PrepareError::IoErr(_))); - }) - } - - // What happens when the execute worker dies in the middle of a job? - #[test] - fn execute_worker_killed_during_job() { - const PROCESS_NAME: &'static str = "polkadot-execute-worker"; - - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let host = TestHost::new().await; - - // Create a new session and get the session ID. - let sid = unsafe { libc::setsid() }; - assert!(sid > 0); - - // Prepare the artifact ahead of time. - let binary = halt::wasm_binary_unwrap(); - host.precheck_pvf(binary, Default::default()).await.unwrap(); - - let (result, _) = futures::join!( - // Choose an job that would normally take the entire timeout. - host.validate_candidate( - binary, - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, - Default::default(), - ), - // Run a future that kills the job in the middle of the timeout. - async { - tokio::time::sleep(TEST_EXECUTION_TIMEOUT / 2).await; - kill_by_sid_and_name(sid, PROCESS_NAME); - } - ); - - assert_matches!( - result, - Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) - ); - }) - } -} - #[cfg(feature = "ci-only-tests")] #[tokio::test] async fn ensure_parallel_execution() { diff --git a/polkadot/node/core/pvf/tests/it/process.rs b/polkadot/node/core/pvf/tests/it/process.rs new file mode 100644 index 00000000000..725d060ab91 --- /dev/null +++ b/polkadot/node/core/pvf/tests/it/process.rs @@ -0,0 +1,383 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test unexpected behaviors of the spawned processes. We test both worker processes (directly +//! spawned by the host) and job processes (spawned by the workers to securely perform PVF jobs). + +use super::TestHost; +use assert_matches::assert_matches; +use polkadot_node_core_pvf::{InvalidCandidate, PrepareError, ValidationError}; +use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams}; +use procfs::process; +use rusty_fork::rusty_fork_test; +use std::time::Duration; + +const PREPARE_PROCESS_NAME: &'static str = "polkadot-prepare-worker"; +const EXECUTE_PROCESS_NAME: &'static str = "polkadot-execute-worker"; + +const SIGNAL_KILL: i32 = 9; +const SIGNAL_STOP: i32 = 19; + +fn send_signal_by_sid_and_name( + sid: i32, + exe_name: &'static str, + is_direct_child: bool, + signal: i32, +) { + let process = find_process_by_sid_and_name(sid, exe_name, is_direct_child); + assert_eq!(unsafe { libc::kill(process.pid(), signal) }, 0); +} +fn get_num_threads_by_sid_and_name(sid: i32, exe_name: &'static str, is_direct_child: bool) -> i64 { + let process = find_process_by_sid_and_name(sid, exe_name, is_direct_child); + process.stat().unwrap().num_threads +} + +fn find_process_by_sid_and_name( + sid: i32, + exe_name: &'static str, + is_direct_child: bool, +) -> process::Process { + let all_processes: Vec = process::all_processes() + .expect("Can't read /proc") + .filter_map(|p| match p { + Ok(p) => Some(p), // happy path + Err(e) => match e { + // process vanished during iteration, ignore it + procfs::ProcError::NotFound(_) => None, + x => { + panic!("some unknown error: {}", x); + }, + }, + }) + .collect(); + + let mut found = None; + for process in all_processes { + let stat = process.stat().unwrap(); + + if stat.session != sid || !process.exe().unwrap().to_str().unwrap().contains(exe_name) { + continue + } + // The workers are direct children of the current process, the worker job processes are not + // (they are children of the workers). + let process_is_direct_child = stat.ppid as u32 == std::process::id(); + if is_direct_child != process_is_direct_child { + continue + } + + if found.is_some() { + panic!("Found more than one process") + } + found = Some(process); + } + found.expect("Should have found the expected process") +} + +// Run these tests in their own processes with rusty-fork. They work by each creating a new session, +// then doing something with the child process that matches the session ID and expected process +// name. +rusty_fork_test! { + // What happens when the prepare worker (not the job) times out? + #[test] + fn prepare_worker_timeout() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + let (result, _) = futures::join!( + // Choose a job that would normally take the entire timeout. + host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), + // Send a stop signal to pause the worker. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, PREPARE_PROCESS_NAME, true, SIGNAL_STOP); + } + ); + + assert_matches!(result, Err(PrepareError::TimedOut)); + }) + } + + // What happens when the execute worker (not the job) times out? + #[test] + fn execute_worker_timeout() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + // Prepare the artifact ahead of time. + let binary = halt::wasm_binary_unwrap(); + host.precheck_pvf(binary, Default::default()).await.unwrap(); + + let (result, _) = futures::join!( + // Choose an job that would normally take the entire timeout. + host.validate_candidate( + binary, + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ), + // Send a stop signal to pause the worker. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, true, SIGNAL_STOP); + } + ); + + assert_matches!( + result, + Err(ValidationError::InvalidCandidate(InvalidCandidate::HardTimeout)) + ); + }) + } + + // What happens when the prepare worker dies in the middle of a job? + #[test] + fn prepare_worker_killed_during_job() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + let (result, _) = futures::join!( + // Choose a job that would normally take the entire timeout. + host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), + // Run a future that kills the job while it's running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, PREPARE_PROCESS_NAME, true, SIGNAL_KILL); + } + ); + + assert_matches!(result, Err(PrepareError::IoErr(_))); + }) + } + + // What happens when the execute worker dies in the middle of a job? + #[test] + fn execute_worker_killed_during_job() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + // Prepare the artifact ahead of time. + let binary = halt::wasm_binary_unwrap(); + host.precheck_pvf(binary, Default::default()).await.unwrap(); + + let (result, _) = futures::join!( + // Choose an job that would normally take the entire timeout. + host.validate_candidate( + binary, + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ), + // Run a future that kills the job while it's running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, true, SIGNAL_KILL); + } + ); + + assert_matches!( + result, + Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousWorkerDeath)) + ); + }) + } + + // What happens when the forked prepare job dies in the middle of its job? + #[test] + fn forked_prepare_job_killed_during_job() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + let (result, _) = futures::join!( + // Choose a job that would normally take the entire timeout. + host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), + // Run a future that kills the job while it's running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, PREPARE_PROCESS_NAME, false, SIGNAL_KILL); + } + ); + + // Note that we get a more specific error if the job died than if the whole worker died. + assert_matches!( + result, + Err(PrepareError::JobDied(err)) if err == "received signal: SIGKILL" + ); + }) + } + + // What happens when the forked execute job dies in the middle of its job? + #[test] + fn forked_execute_job_killed_during_job() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + // Prepare the artifact ahead of time. + let binary = halt::wasm_binary_unwrap(); + host.precheck_pvf(binary, Default::default()).await.unwrap(); + + let (result, _) = futures::join!( + // Choose a job that would normally take the entire timeout. + host.validate_candidate( + binary, + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ), + // Run a future that kills the job while it's running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + send_signal_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, false, SIGNAL_KILL); + } + ); + + // Note that we get a more specific error if the job died than if the whole worker died. + assert_matches!( + result, + Err(ValidationError::InvalidCandidate(InvalidCandidate::AmbiguousJobDeath(err))) + if err == "received signal: SIGKILL" + ); + }) + } + + // Ensure that the spawned prepare worker is single-threaded. + // + // See `run_worker` for why we need this invariant. + #[test] + fn ensure_prepare_processes_have_correct_num_threads() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + let _ = futures::join!( + // Choose a job that would normally take the entire timeout. + host.precheck_pvf(rococo_runtime::WASM_BINARY.unwrap(), Default::default()), + // Run a future that kills the job while it's running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + assert_eq!( + get_num_threads_by_sid_and_name(sid, PREPARE_PROCESS_NAME, true), + 1 + ); + // Child job should have three threads: main thread, execute thread, CPU time + // monitor, and memory tracking. + assert_eq!( + get_num_threads_by_sid_and_name(sid, PREPARE_PROCESS_NAME, false), + 4 + ); + + // End the test. + send_signal_by_sid_and_name(sid, PREPARE_PROCESS_NAME, true, SIGNAL_KILL); + } + ); + }) + } + + // Ensure that the spawned execute worker is single-threaded. + // + // See `run_worker` for why we need this invariant. + #[test] + fn ensure_execute_processes_have_correct_num_threads() { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let host = TestHost::new().await; + + // Create a new session and get the session ID. + let sid = unsafe { libc::setsid() }; + assert!(sid > 0); + + // Prepare the artifact ahead of time. + let binary = halt::wasm_binary_unwrap(); + host.precheck_pvf(binary, Default::default()).await.unwrap(); + + let _ = futures::join!( + // Choose a job that would normally take the entire timeout. + host.validate_candidate( + binary, + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ), + // Run a future that tests the thread count while the worker is running. + async { + tokio::time::sleep(Duration::from_secs(1)).await; + assert_eq!( + get_num_threads_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, true), + 1 + ); + // Child job should have three threads: main thread, execute thread, and CPU + // time monitor. + assert_eq!( + get_num_threads_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, false), + 3 + ); + + // End the test. + send_signal_by_sid_and_name(sid, EXECUTE_PROCESS_NAME, true, SIGNAL_KILL); + } + ); + }) + } +} diff --git a/polkadot/node/core/pvf/tests/it/worker_common.rs b/polkadot/node/core/pvf/tests/it/worker_common.rs index df64980dc80..0d33af7e096 100644 --- a/polkadot/node/core/pvf/tests/it/worker_common.rs +++ b/polkadot/node/core/pvf/tests/it/worker_common.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use polkadot_node_core_pvf::{ - testing::{get_and_check_worker_paths, spawn_with_program_path, SpawnErr}, + testing::{build_workers_and_get_paths, spawn_with_program_path, SpawnErr}, SecurityStatus, }; use std::{env, time::Duration}; @@ -23,7 +23,7 @@ use std::{env, time::Duration}; // Test spawning a program that immediately exits with a failure code. #[tokio::test] async fn spawn_immediate_exit() { - let (prepare_worker_path, _) = get_and_check_worker_paths(); + let (prepare_worker_path, _) = build_workers_and_get_paths(false); // There's no explicit `exit` subcommand in the worker; it will panic on an unknown // subcommand anyway @@ -41,7 +41,7 @@ async fn spawn_immediate_exit() { #[tokio::test] async fn spawn_timeout() { - let (_, execute_worker_path) = get_and_check_worker_paths(); + let (_, execute_worker_path) = build_workers_and_get_paths(false); let result = spawn_with_program_path( "integration-test", @@ -57,7 +57,7 @@ async fn spawn_timeout() { #[tokio::test] async fn should_connect() { - let (prepare_worker_path, _) = get_and_check_worker_paths(); + let (prepare_worker_path, _) = build_workers_and_get_paths(false); let _ = spawn_with_program_path( "integration-test", 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 52129f9eb80..4dbb7980c1b 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 @@ -1,7 +1,11 @@ # PVF Host and Workers The PVF host is responsible for handling requests to prepare and execute PVF -code blobs, which it sends to PVF workers running in their own child processes. +code blobs, which it sends to PVF **workers** running in their own child +processes. + +While the workers are generally long-living, they also spawn one-off secure +**job processes** that perform the jobs. See "Job Processes" section below. This system has two high-levels goals that we will touch on here: *determinism* and *security*. @@ -36,8 +40,11 @@ execution request: not successful. 2. **Artifact missing:** The prepared artifact might have been deleted due to operator error or some bug in the system. -3. **Panic:** The worker thread panicked for some indeterminate reason, which - may or may not be independent of the candidate or PVF. +3. **Job errors:** For example, the worker thread panicked for some + indeterminate reason, which may or may not be independent of the candidate or + PVF. +4. **Internal errors:** See "Internal Errors" section. In this case, after the + retry we abstain from voting. ### Preparation timeouts @@ -62,10 +69,16 @@ more than the CPU time. ### Internal errors +An internal, or local, error is one that we treat as independent of the PVF +and/or candidate, i.e. local to the running machine. If this happens, then we +will first retry the job and if the errors persists, then we simply do not vote. +This prevents slashes, since otherwise our vote may not agree with that of the +other validators. + In general, for errors not raising a dispute we have to be very careful. This is -only sound, if we either: +only sound, if either: -1. Ruled out that error in pre-checking. If something is not checked in +1. We ruled out that error in pre-checking. If something is not checked in pre-checking, even if independent of the candidate and PVF, we must raise a dispute. 2. We are 100% confident that it is a hardware/local issue: Like corrupted file, @@ -75,11 +88,11 @@ Reasoning: Otherwise it would be possible to register a PVF where candidates can not be checked, but we don't get a dispute - so nobody gets punished. Second, we end up with a finality stall that is not going to resolve! -There are some error conditions where we can't be sure whether the candidate is -really invalid or some internal glitch occurred, e.g. panics. Whenever we are -unsure, we can never treat an error as internal as we would abstain from voting. -So we will first retry the candidate, and if the issue persists we are forced to -vote invalid. +Note that any error from the job process we cannot treat as internal. The job +runs untrusted code and an attacker can therefore return arbitrary errors. If +they were to return errors that we treat as internal, they could make us abstain +from voting. Since we are unsure if such errors are legitimate, we will first +retry the candidate, and if the issue persists we are forced to vote invalid. ## Security @@ -119,6 +132,20 @@ So what are we actually worried about? Things that come to mind: 6. **Intercepting and manipulating packages** - Effect very similar to the above, hard to do without also being able to do 4 or 5. +### Job Processes + +As mentioned above, our architecture includes long-living **worker processes** +and one-off **job processes*. This separation is important so that the handling +of untrusted code can be limited to the job processes. A hijacked job process +can therefore not interfere with other jobs running in separate processes. + +Furthermore, if an unexpected execution error occurred in the worker and not the +job, we generally can be confident that it has nothing to do with the candidate, +so we can abstain from voting. On the other hand, a hijacked job can send back +erroneous responses for candidates, so we know that we should not abstain from +voting on such errors from jobs. Otherwise, an attacker could trigger a finality +stall. (See "Internal Errors" section above.) + ### Restricting file-system access A basic security mechanism is to make sure that any process directly interfacing diff --git a/polkadot/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls index 4a7a6618129..349af783cf1 100644 --- a/polkadot/scripts/list-syscalls/execute-worker-syscalls +++ b/polkadot/scripts/list-syscalls/execute-worker-syscalls @@ -16,6 +16,7 @@ 16 (ioctl) 19 (readv) 20 (writev) +22 (pipe) 24 (sched_yield) 25 (mremap) 28 (madvise) @@ -25,7 +26,9 @@ 45 (recvfrom) 46 (sendmsg) 56 (clone) +57 (fork) 60 (exit) +61 (wait4) 62 (kill) 72 (fcntl) 79 (getcwd) @@ -36,6 +39,7 @@ 89 (readlink) 96 (gettimeofday) 97 (getrlimit) +98 (getrusage) 99 (sysinfo) 102 (getuid) 110 (getppid) @@ -47,6 +51,7 @@ 158 (arch_prctl) 165 (mount) 166 (umount2) +186 (gettid) 200 (tkill) 202 (futex) 204 (sched_getaffinity) @@ -60,6 +65,7 @@ 263 (unlinkat) 272 (unshare) 273 (set_robust_list) +293 (pipe2) 302 (prlimit64) 318 (getrandom) 319 (memfd_create) diff --git a/polkadot/scripts/list-syscalls/prepare-worker-syscalls b/polkadot/scripts/list-syscalls/prepare-worker-syscalls index cab58e06692..05281b61591 100644 --- a/polkadot/scripts/list-syscalls/prepare-worker-syscalls +++ b/polkadot/scripts/list-syscalls/prepare-worker-syscalls @@ -16,6 +16,7 @@ 16 (ioctl) 19 (readv) 20 (writev) +22 (pipe) 24 (sched_yield) 25 (mremap) 28 (madvise) @@ -25,7 +26,9 @@ 45 (recvfrom) 46 (sendmsg) 56 (clone) +57 (fork) 60 (exit) +61 (wait4) 62 (kill) 72 (fcntl) 79 (getcwd) @@ -48,6 +51,7 @@ 158 (arch_prctl) 165 (mount) 166 (umount2) +186 (gettid) 200 (tkill) 202 (futex) 203 (sched_setaffinity) @@ -62,6 +66,7 @@ 263 (unlinkat) 272 (unshare) 273 (set_robust_list) +293 (pipe2) 302 (prlimit64) 309 (getcpu) 318 (getrandom) -- GitLab From 31c38cea3def97044c328f3a9717eeb471c261fe Mon Sep 17 00:00:00 2001 From: Kristian Sosnin <48099298+slumber@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:14:59 +0400 Subject: [PATCH 510/633] statement-distribution: support inactive local validator in grid (#1571) Fixes #1437 Co-authored-by: Sophia Gold --- .../statement-distribution/src/v2/mod.rs | 335 +++++++++++------- .../src/v2/tests/cluster.rs | 70 ++-- .../src/v2/tests/grid.rs | 241 ++++++++++--- .../src/v2/tests/mod.rs | 51 ++- .../src/v2/tests/requests.rs | 76 ++-- 5 files changed, 514 insertions(+), 259 deletions(-) diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 6f39a5c504d..406f1130590 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -142,8 +142,27 @@ struct PerRelayParentState { session: SessionIndex, } +impl PerRelayParentState { + fn active_validator_state(&self) -> Option<&ActiveValidatorState> { + self.local_validator.as_ref().and_then(|local| local.active.as_ref()) + } + + fn active_validator_state_mut(&mut self) -> Option<&mut ActiveValidatorState> { + self.local_validator.as_mut().and_then(|local| local.active.as_mut()) + } +} + // per-relay-parent local validator state. struct LocalValidatorState { + // the grid-level communication at this relay-parent. + grid_tracker: GridTracker, + // additional fields in case local node is an active validator. + active: Option, + // local index actually exists in case node is inactive validator, however, + // it's not needed outside of `build_session_topology`, where it's known. +} + +struct ActiveValidatorState { // The index of the validator. index: ValidatorIndex, // our validator group @@ -152,8 +171,14 @@ struct LocalValidatorState { assignment: Option, // the 'direct-in-group' communication at this relay-parent. cluster_tracker: ClusterTracker, - // the grid-level communication at this relay-parent. - grid_tracker: GridTracker, +} + +#[derive(Debug, Copy, Clone)] +enum LocalValidatorIndex { + // Local node is an active validator. + Active(ValidatorIndex), + // Local node is not in active validator set. + Inactive, } #[derive(Debug)] @@ -164,7 +189,7 @@ struct PerSessionState { // is only `None` in the time between seeing a session and // getting the topology from the gossip-support subsystem grid_view: Option, - local_validator: Option, + local_validator: Option, } impl PerSessionState { @@ -178,15 +203,10 @@ impl PerSessionState { let local_validator = polkadot_node_subsystem_util::signing_key_and_index( session_info.validators.iter(), keystore, - ); + ) + .map(|(_, index)| LocalValidatorIndex::Active(index)); - PerSessionState { - session_info, - groups, - authority_lookup, - grid_view: None, - local_validator: local_validator.map(|(_key, index)| index), - } + PerSessionState { session_info, groups, authority_lookup, grid_view: None, local_validator } } fn supply_topology( @@ -204,6 +224,16 @@ impl PerSessionState { ); self.grid_view = Some(grid_view); + if local_index.is_some() { + self.local_validator.get_or_insert(LocalValidatorIndex::Inactive); + } + } + + /// Returns `true` if local is neither active or inactive validator node. + /// + /// `false` is also returned if session topology is not known yet. + fn is_not_validator(&self) -> bool { + self.grid_view.is_some() && self.local_validator.is_none() } } @@ -554,13 +584,17 @@ pub(crate) async fn handle_active_leaves_update( .expect("either existed or just inserted; qed"); let local_validator = per_session.local_validator.and_then(|v| { - find_local_validator_state( - v, - &per_session.groups, - &availability_cores, - &group_rotation_info, - seconding_limit, - ) + if let LocalValidatorIndex::Active(idx) = v { + find_active_validator_state( + idx, + &per_session.groups, + &availability_cores, + &group_rotation_info, + seconding_limit, + ) + } else { + Some(LocalValidatorState { grid_tracker: GridTracker::default(), active: None }) + } }); state.per_relay_parent.insert( @@ -607,7 +641,7 @@ pub(crate) async fn handle_active_leaves_update( Ok(()) } -fn find_local_validator_state( +fn find_active_validator_state( validator_index: ValidatorIndex, groups: &Groups, availability_cores: &[CoreState], @@ -628,11 +662,13 @@ fn find_local_validator_state( let group_validators = groups.get(our_group)?.to_owned(); Some(LocalValidatorState { - index: validator_index, - group: our_group, - assignment: para, - cluster_tracker: ClusterTracker::new(group_validators, seconding_limit) - .expect("group is non-empty because we are in it; qed"), + active: Some(ActiveValidatorState { + index: validator_index, + group: our_group, + assignment: para, + cluster_tracker: ClusterTracker::new(group_validators, seconding_limit) + .expect("group is non-empty because we are in it; qed"), + }), grid_tracker: GridTracker::default(), }) } @@ -725,13 +761,17 @@ async fn send_peer_messages_for_relay_parent( for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { per_session_state.authority_lookup.get(a) }) { - if let Some(local_validator_state) = relay_parent_state.local_validator.as_mut() { + if let Some(active) = relay_parent_state + .local_validator + .as_mut() + .and_then(|local| local.active.as_mut()) + { send_pending_cluster_statements( ctx, relay_parent, &(peer, peer_data.protocol_version), validator_id, - &mut local_validator_state.cluster_tracker, + &mut active.cluster_tracker, &state.candidates, &relay_parent_state.statement_store, ) @@ -1009,7 +1049,7 @@ pub(crate) async fn share_local_statement( }; let (local_index, local_assignment, local_group) = - match per_relay_parent.local_validator.as_ref() { + match per_relay_parent.active_validator_state() { None => return Err(JfyiError::InvalidShare), Some(l) => (l.index, l.assignment, l.group), }; @@ -1086,7 +1126,7 @@ pub(crate) async fn share_local_statement( } { - let l = per_relay_parent.local_validator.as_mut().expect("checked above; qed"); + let l = per_relay_parent.active_validator_state_mut().expect("checked above; qed"); l.cluster_tracker.note_issued(local_index, compact_statement.payload().clone()); } @@ -1173,31 +1213,41 @@ async fn circulate_statement( // We're not meant to circulate statements in the cluster until we have the confirmed // candidate. - let cluster_relevant = Some(local_validator.group) == statement_group; - let cluster_targets = if is_confirmed && cluster_relevant { - Some( - local_validator - .cluster_tracker - .targets() - .iter() - .filter(|&&v| { - local_validator + // + // Cluster is only relevant if local node is an active validator. + let (cluster_relevant, cluster_targets, all_cluster_targets) = local_validator + .active + .as_mut() + .map(|active| { + let cluster_relevant = Some(active.group) == statement_group; + let cluster_targets = if is_confirmed && cluster_relevant { + Some( + active .cluster_tracker - .can_send(v, originator, compact_statement.clone()) - .is_ok() - }) - .filter(|&v| v != &local_validator.index) - .map(|v| (*v, DirectTargetKind::Cluster)), - ) - } else { - None - }; + .targets() + .iter() + .filter(|&&v| { + active + .cluster_tracker + .can_send(v, originator, compact_statement.clone()) + .is_ok() + }) + .filter(|&v| v != &active.index) + .map(|v| (*v, DirectTargetKind::Cluster)), + ) + } else { + None + }; + let all_cluster_targets = active.cluster_tracker.targets(); + (cluster_relevant, cluster_targets, all_cluster_targets) + }) + .unwrap_or((false, None, &[])); let grid_targets = local_validator .grid_tracker .direct_statement_targets(&per_session.groups, originator, &compact_statement) .into_iter() - .filter(|v| !cluster_relevant || !local_validator.cluster_tracker.targets().contains(v)) + .filter(|v| !cluster_relevant || !all_cluster_targets.contains(v)) .map(|v| (v, DirectTargetKind::Grid)); let targets = cluster_targets @@ -1229,18 +1279,17 @@ async fn circulate_statement( match kind { DirectTargetKind::Cluster => { + let active = local_validator + .active + .as_mut() + .expect("cluster target means local is active validator; qed"); + // At this point, all peers in the cluster should 'know' // the candidate, so we don't expect for this to fail. - if let Ok(()) = local_validator.cluster_tracker.can_send( - target, - originator, - compact_statement.clone(), - ) { - local_validator.cluster_tracker.note_sent( - target, - originator, - compact_statement.clone(), - ); + if let Ok(()) = + active.cluster_tracker.can_send(target, originator, compact_statement.clone()) + { + active.cluster_tracker.note_sent(target, originator, compact_statement.clone()); statement_to_peers.push(peer_id); } }, @@ -1387,7 +1436,9 @@ async fn handle_incoming_statement( None => { // we shouldn't be receiving statements unless we're a validator // this session. - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + if per_session.is_not_validator() { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + } return }, Some(l) => l, @@ -1402,73 +1453,81 @@ async fn handle_incoming_statement( }, }; - let cluster_sender_index = { + let (active, cluster_sender_index) = { // This block of code only returns `Some` when both the originator and // the sending peer are in the cluster. + let active = local_validator.active.as_mut(); - let allowed_senders = local_validator - .cluster_tracker - .senders_for_originator(statement.unchecked_validator_index()); + let allowed_senders = active + .as_ref() + .map(|active| { + active + .cluster_tracker + .senders_for_originator(statement.unchecked_validator_index()) + }) + .unwrap_or_default(); - allowed_senders + let idx = allowed_senders .iter() .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (*i, ad))) .filter(|(_, ad)| peer_state.is_authority(ad)) .map(|(i, _)| i) - .next() - }; - - let checked_statement = if let Some(cluster_sender_index) = cluster_sender_index { - match handle_cluster_statement( - relay_parent, - &mut local_validator.cluster_tracker, - per_relay_parent.session, - &per_session.session_info, - statement, - cluster_sender_index, - ) { - Ok(Some(s)) => s, - Ok(None) => return, - Err(rep) => { - modify_reputation(reputation, ctx.sender(), peer, rep).await; - return - }, - } - } else { - let grid_sender_index = local_validator - .grid_tracker - .direct_statement_providers( - &per_session.groups, - statement.unchecked_validator_index(), - statement.unchecked_payload(), - ) - .into_iter() - .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad))) - .filter(|(_, ad)| peer_state.is_authority(ad)) - .map(|(i, _)| i) .next(); + (active, idx) + }; - if let Some(grid_sender_index) = grid_sender_index { - match handle_grid_statement( + let checked_statement = + if let Some((active, cluster_sender_index)) = active.zip(cluster_sender_index) { + match handle_cluster_statement( relay_parent, - &mut local_validator.grid_tracker, + &mut active.cluster_tracker, per_relay_parent.session, - &per_session, + &per_session.session_info, statement, - grid_sender_index, + cluster_sender_index, ) { - Ok(s) => s, + Ok(Some(s)) => s, + Ok(None) => return, Err(rep) => { modify_reputation(reputation, ctx.sender(), peer, rep).await; return }, } } else { - // Not a cluster or grid peer. - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; - return - } - }; + let grid_sender_index = local_validator + .grid_tracker + .direct_statement_providers( + &per_session.groups, + statement.unchecked_validator_index(), + statement.unchecked_payload(), + ) + .into_iter() + .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad))) + .filter(|(_, ad)| peer_state.is_authority(ad)) + .map(|(i, _)| i) + .next(); + + if let Some(grid_sender_index) = grid_sender_index { + match handle_grid_statement( + relay_parent, + &mut local_validator.grid_tracker, + per_relay_parent.session, + &per_session, + statement, + grid_sender_index, + ) { + Ok(s) => s, + Err(rep) => { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + return + }, + } + } else { + // Not a cluster or grid peer. + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + return + } + }; let statement = checked_statement.payload().clone(); let originator_index = checked_statement.validator_index(); @@ -1536,7 +1595,7 @@ async fn handle_incoming_statement( local_validator.grid_tracker.learned_fresh_statement( &per_session.groups, session_topology, - local_validator.index, + originator_index, &statement, ); } @@ -1834,7 +1893,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, - local_validator = ?local_validator.index, + local_validator = ?per_session.local_validator, n_peers = manifest_peers_v2.len(), "Sending manifest to v2 peers" ); @@ -1853,7 +1912,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, - local_validator = ?local_validator.index, + local_validator = ?per_session.local_validator, n_peers = manifest_peers_vstaging.len(), "Sending manifest to vstaging peers" ); @@ -1874,7 +1933,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, - local_validator = ?local_validator.index, + local_validator = ?per_session.local_validator, n_peers = ack_peers_v2.len(), "Sending acknowledgement to v2 peers" ); @@ -1893,7 +1952,7 @@ async fn provide_candidate_to_grid( gum::debug!( target: LOG_TARGET, ?candidate_hash, - local_validator = ?local_validator.index, + local_validator = ?per_session.local_validator, n_peers = ack_peers_vstaging.len(), "Sending acknowledgement to vstaging peers" ); @@ -2086,13 +2145,15 @@ async fn handle_incoming_manifest_common<'a, Context>( let local_validator = match relay_parent_state.local_validator.as_mut() { None => { - modify_reputation( - reputation, - ctx.sender(), - peer, - COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE, - ) - .await; + if per_session.is_not_validator() { + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE, + ) + .await; + } return None }, Some(x) => x, @@ -2188,7 +2249,7 @@ async fn handle_incoming_manifest_common<'a, Context>( target: LOG_TARGET, ?candidate_hash, from = ?sender_index, - local_index = ?local_validator.index, + local_index = ?per_session.local_validator, ?manifest_kind, "immediate ack, known candidate" ); @@ -2593,7 +2654,7 @@ async fn send_cluster_candidate_statements( Some(s) => s, }; - let local_group = match relay_parent_state.local_validator.as_mut() { + let local_group = match relay_parent_state.active_validator_state_mut() { None => return, Some(v) => v.group, }; @@ -2680,11 +2741,10 @@ pub(crate) async fn dispatch_requests(ctx: &mut Context, state: &mut St }) { // For cluster members, they haven't advertised any statements in particular, // but have surely sent us some. - if local_validator - .cluster_tracker - .knows_candidate(validator_id, identifier.candidate_hash) - { - return Some(StatementFilter::blank(local_validator.cluster_tracker.targets().len())) + if let Some(active) = local_validator.active.as_ref() { + if active.cluster_tracker.knows_candidate(validator_id, identifier.candidate_hash) { + return Some(StatementFilter::blank(active.cluster_tracker.targets().len())) + } } let filter = local_validator @@ -2715,7 +2775,11 @@ pub(crate) async fn dispatch_requests(ctx: &mut Context, state: &mut St } // don't require a backing threshold for cluster candidates. - let require_backing = relay_parent_state.local_validator.as_ref()?.group != group_index; + let local_validator = relay_parent_state.local_validator.as_ref()?; + let require_backing = local_validator + .active + .as_ref() + .map_or(true, |active| active.group != group_index); Some(RequestProperties { unwanted_mask, @@ -2973,7 +3037,11 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { for v in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { per_session.authority_lookup.get(a) }) { - if local_validator.cluster_tracker.can_request(v, *candidate_hash) { + if local_validator + .active + .as_ref() + .map_or(false, |active| active.cluster_tracker.can_request(v, *candidate_hash)) + { validator_id = Some(v); is_cluster = true; break @@ -3015,11 +3083,16 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { // Update bookkeeping about which statements peers have received. for statement in &statements { if is_cluster { - local_validator.cluster_tracker.note_sent( - validator_id, - statement.unchecked_validator_index(), - statement.unchecked_payload().clone(), - ); + local_validator + .active + .as_mut() + .expect("cluster peer means local is active validator; qed") + .cluster_tracker + .note_sent( + validator_id, + statement.unchecked_validator_index(), + statement.unchecked_payload().clone(), + ); } else { local_validator.grid_tracker.sent_or_received_direct_statement( &per_session.groups, diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs index 80dec1d75ab..a9f5b537b32 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -23,7 +23,7 @@ fn share_seconded_circulated_to_cluster() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -34,7 +34,8 @@ fn share_seconded_circulated_to_cluster() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -52,7 +53,7 @@ fn share_seconded_circulated_to_cluster() { // peer B is in group, has no relay parent in view. // peer C is not in group, has relay parent in view. { - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); connect_peer( &mut overseer, @@ -130,7 +131,7 @@ fn cluster_valid_statement_before_seconded_ignored() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -139,12 +140,13 @@ fn cluster_valid_statement_before_seconded_ignored() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); let candidate_hash = CandidateHash(Hash::repeat_byte(42)); let test_leaf = state.make_dummy_leaf(relay_parent); // peer A is in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; connect_peer( &mut overseer, @@ -197,7 +199,7 @@ fn cluster_statement_bad_signature() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -206,12 +208,13 @@ fn cluster_statement_bad_signature() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); let candidate_hash = CandidateHash(Hash::repeat_byte(42)); let test_leaf = state.make_dummy_leaf(relay_parent); // peer A is in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; @@ -277,7 +280,7 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -286,13 +289,13 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); let candidate_hash = CandidateHash(Hash::repeat_byte(42)); let test_leaf = state.make_dummy_leaf(relay_parent); // peer A is not in group, has relay parent in view. - let not_our_group = - if local_validator.group_index.0 == 0 { GroupIndex(1) } else { GroupIndex(0) }; + let not_our_group = if local_group_index.0 == 0 { GroupIndex(1) } else { GroupIndex(0) }; let that_group_validators = state.group_validators(not_our_group, false); let v_non = that_group_validators[0]; @@ -346,7 +349,7 @@ fn statement_from_non_cluster_originator_unexpected() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -355,12 +358,13 @@ fn statement_from_non_cluster_originator_unexpected() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); let candidate_hash = CandidateHash(Hash::repeat_byte(42)); let test_leaf = state.make_dummy_leaf(relay_parent); // peer A is not in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; connect_peer(&mut overseer, peer_a.clone(), None).await; @@ -408,7 +412,7 @@ fn seconded_statement_leads_to_request() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -417,7 +421,8 @@ fn seconded_statement_leads_to_request() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -432,7 +437,7 @@ fn seconded_statement_leads_to_request() { let candidate_hash = candidate.hash(); // peer A is in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; connect_peer( @@ -503,7 +508,7 @@ fn cluster_statements_shared_seconded_first() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -512,7 +517,8 @@ fn cluster_statements_shared_seconded_first() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -528,7 +534,7 @@ fn cluster_statements_shared_seconded_first() { // peer A is in group, no relay parent in view. { - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); connect_peer( &mut overseer, @@ -624,7 +630,7 @@ fn cluster_accounts_for_implicit_view() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -634,7 +640,8 @@ fn cluster_accounts_for_implicit_view() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -651,7 +658,7 @@ fn cluster_accounts_for_implicit_view() { // peer A is in group, has relay parent in view. // peer B is in group, has no relay parent in view. { - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); connect_peer( &mut overseer, @@ -775,7 +782,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -784,7 +791,8 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -799,7 +807,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { let candidate_hash = candidate.hash(); // peer A is in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; { connect_peer( @@ -907,7 +915,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -916,7 +924,8 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -931,7 +940,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { let candidate_hash = candidate.hash(); // peer A is in group, has relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; { connect_peer( @@ -1048,7 +1057,7 @@ fn ensure_seconding_limit_is_respected() { let config = TestConfig { validator_count: 20, group_size: 4, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: Some(AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 3, @@ -1060,7 +1069,8 @@ fn ensure_seconding_limit_is_respected() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1092,7 +1102,7 @@ fn ensure_seconding_limit_is_respected() { let candidate_hash_2 = candidate_2.hash(); let candidate_hash_3 = candidate_3.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; // peers A,B,C are in group, have relay parent in view. diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 5b1dabfc8a0..9802db06082 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -29,7 +29,7 @@ fn backed_candidate_leads_to_advertisement() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -41,7 +41,8 @@ fn backed_candidate_leads_to_advertisement() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -55,9 +56,9 @@ fn backed_candidate_leads_to_advertisement() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let target_group_validators = - state.group_validators((local_validator.group_index.0 + 1).into(), true); + state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; let v_c = target_group_validators[0]; @@ -219,7 +220,7 @@ fn backed_candidate_leads_to_advertisement() { assert_eq!(manifest, BackedCandidateManifest { relay_parent, candidate_hash, - group_index: local_validator.group_index, + group_index: local_group_index, para_id: local_para, parent_head_data_hash: pvd.parent_head.hash(), statement_knowledge: StatementFilter { @@ -244,7 +245,7 @@ fn received_advertisement_before_confirmation_leads_to_request() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -256,9 +257,9 @@ fn received_advertisement_before_confirmation_leads_to_request() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -273,7 +274,7 @@ fn received_advertisement_before_confirmation_leads_to_request() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let target_group_validators = state.group_validators(other_group, true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; @@ -424,7 +425,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -435,9 +436,9 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -672,7 +673,7 @@ fn received_advertisement_after_confirmation_before_backing() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -683,9 +684,9 @@ fn received_advertisement_after_confirmation_before_backing() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -858,7 +859,7 @@ fn additional_statements_are_shared_after_manifest_exchange() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -869,9 +870,9 @@ fn additional_statements_are_shared_after_manifest_exchange() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1155,7 +1156,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1167,7 +1168,8 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1181,9 +1183,9 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let target_group_validators = - state.group_validators((local_validator.group_index.0 + 1).into(), true); + state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; let v_c = target_group_validators[0]; @@ -1336,7 +1338,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { let expected_manifest = BackedCandidateManifest { relay_parent, candidate_hash, - group_index: local_validator.group_index, + group_index: local_group_index, para_id: local_para, parent_head_data_hash: pvd.parent_head.hash(), statement_knowledge: StatementFilter { @@ -1377,7 +1379,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1389,7 +1391,8 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1403,9 +1406,9 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let target_group_validators = - state.group_validators((local_validator.group_index.0 + 1).into(), true); + state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; let v_c = target_group_validators[0]; @@ -1567,7 +1570,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { assert_eq!(manifest, BackedCandidateManifest { relay_parent, candidate_hash, - group_index: local_validator.group_index, + group_index: local_group_index, para_id: local_para, parent_head_data_hash: pvd.parent_head.hash(), statement_knowledge: StatementFilter { @@ -1599,7 +1602,7 @@ fn grid_statements_imported_to_backing() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1610,9 +1613,9 @@ fn grid_statements_imported_to_backing() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1803,7 +1806,7 @@ fn advertisements_rejected_from_incorrect_peers() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1815,9 +1818,9 @@ fn advertisements_rejected_from_incorrect_peers() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1832,12 +1835,12 @@ fn advertisements_rejected_from_incorrect_peers() { ); let candidate_hash = candidate.hash(); - let target_group_validators = state.group_validators(local_validator.group_index, true); - let other_group_validators = state.group_validators(other_group, true); - let v_a = target_group_validators[0]; - let v_b = target_group_validators[1]; - let v_c = other_group_validators[0]; - let v_d = other_group_validators[1]; + let other_group_validators = state.group_validators(local_group_index, true); + let target_group_validators = state.group_validators(other_group, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; // peer A is in group, has relay parent in view. // peer B is in group, has no relay parent in view. @@ -1948,7 +1951,7 @@ fn manifest_rejected_with_unknown_relay_parent() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1959,9 +1962,9 @@ fn manifest_rejected_with_unknown_relay_parent() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -2054,7 +2057,7 @@ fn manifest_rejected_when_not_a_validator() { let config = TestConfig { validator_count, group_size, - local_validator: false, + local_validator: LocalRole::None, async_backing_params: None, }; @@ -2156,7 +2159,7 @@ fn manifest_rejected_when_group_does_not_match_para() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -2166,9 +2169,9 @@ fn manifest_rejected_when_group_does_not_match_para() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); // Create a mismatch between group and para. let other_para = next_group_index(other_group, validator_count, group_size); let other_para = ParaId::from(other_para.0); @@ -2263,7 +2266,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -2274,9 +2277,9 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -2454,3 +2457,141 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { overseer }); } + +#[test] +fn inactive_local_participates_in_grid() { + let validator_count = 11; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: LocalRole::InactiveValidator, + async_backing_params: None, + }; + + let dummy_relay_parent = Hash::repeat_byte(2); + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + assert_eq!(local_validator.validator_index.0, validator_count as u32); + + let group_idx = GroupIndex::from(0); + let para = ParaId::from(0); + + // Dummy leaf is needed to update topology. + let dummy_leaf = state.make_dummy_leaf(Hash::repeat_byte(2)); + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + para, + test_leaf.para_data(para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let first_group = state.group_validators(group_idx, true); + let v_a = first_group.last().unwrap().clone(); + let v_b = first_group.first().unwrap().clone(); + + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &dummy_leaf, &state, true).await; + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(dummy_relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + activate_leaf(&mut overseer, &test_leaf, &state, false).await; + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Receive an advertisement from A. + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: group_idx, + para_id: para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }; + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ) + .await; + + let statements = vec![ + state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + // Inactive node requests this candidate. + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + for _ in 0..2 { + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + } + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + }); +} diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 4150377a0c6..4e626977524 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -61,19 +61,30 @@ const DEFAULT_ASYNC_BACKING_PARAMETERS: AsyncBackingParams = // Some deterministic genesis hash for req/res protocol names const GENESIS_HASH: Hash = Hash::repeat_byte(0xff); +#[derive(Debug, Copy, Clone)] +enum LocalRole { + /// Active validator. + Validator, + /// Authority, not in active validator set. + InactiveValidator, + /// Not a validator. + None, +} + struct TestConfig { + // number of active validators. validator_count: usize, // how many validators to place in each group. group_size: usize, // whether the local node should be a validator - local_validator: bool, + local_validator: LocalRole, async_backing_params: Option, } #[derive(Debug, Clone)] struct TestLocalValidator { validator_index: ValidatorIndex, - group_index: GroupIndex, + group_index: Option, } struct TestState { @@ -99,7 +110,7 @@ impl TestState { let mut assignment_keys = Vec::new(); let mut validator_groups = Vec::new(); - let local_validator_pos = if config.local_validator { + let local_validator_pos = if let LocalRole::Validator = config.local_validator { // ensure local validator is always in a full group. Some(rng.gen_range(0..config.validator_count).saturating_sub(config.group_size - 1)) } else { @@ -128,13 +139,19 @@ impl TestState { } } - let local = if let Some(local_pos) = local_validator_pos { - Some(TestLocalValidator { + let local = match (config.local_validator, local_validator_pos) { + (LocalRole::Validator, Some(local_pos)) => Some(TestLocalValidator { validator_index: ValidatorIndex(local_pos as _), - group_index: GroupIndex((local_pos / config.group_size) as _), - }) - } else { - None + group_index: Some(GroupIndex((local_pos / config.group_size) as _)), + }), + (LocalRole::InactiveValidator, None) => { + discovery_keys.push(AuthorityDiscoveryPair::generate().0.public()); + Some(TestLocalValidator { + validator_index: ValidatorIndex(config.validator_count as u32), + group_index: None, + }) + }, + _ => None, }; let validator_public = validator_pubkeys(&validators); @@ -181,15 +198,23 @@ impl TestState { fn make_dummy_topology(&self) -> NewGossipTopology { let validator_count = self.config.validator_count; + let is_local_inactive = matches!(self.config.local_validator, LocalRole::InactiveValidator); + + let mut indices: Vec = (0..validator_count).collect(); + if is_local_inactive { + indices.push(validator_count); + } + NewGossipTopology { session: 1, topology: SessionGridTopology::new( - (0..validator_count).collect(), - (0..validator_count) + indices.clone(), + indices + .into_iter() .map(|i| TopologyPeerInfo { peer_ids: Vec::new(), validator_index: ValidatorIndex(i as u32), - discovery_id: AuthorityDiscoveryPair::generate().0.public(), + discovery_id: self.session_info.discovery_keys[i].clone(), }) .collect(), ), @@ -276,7 +301,7 @@ fn test_harness>( test: impl FnOnce(TestState, VirtualOverseer) -> T, ) { let pool = sp_core::testing::TaskExecutor::new(); - let keystore = if config.local_validator { + let keystore = if let LocalRole::Validator = config.local_validator { test_helpers::mock::make_ferdie_keystore() } else { Arc::new(LocalKeystore::in_memory()) as KeystorePtr diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs index 4734d7a0f96..1eec8290fab 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs @@ -32,7 +32,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -43,7 +43,8 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -57,7 +58,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; @@ -188,7 +189,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: Some(AsyncBackingParams { // Makes `seconding_limit: 2` (easier to hit the limit). max_candidate_depth: 1, @@ -203,9 +204,9 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -475,7 +476,7 @@ fn peer_reported_for_not_enough_statements() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -486,9 +487,9 @@ fn peer_reported_for_not_enough_statements() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -670,7 +671,7 @@ fn peer_reported_for_duplicate_statements() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -681,7 +682,8 @@ fn peer_reported_for_duplicate_statements() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -695,7 +697,7 @@ fn peer_reported_for_duplicate_statements() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; @@ -830,7 +832,7 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -841,7 +843,8 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -855,8 +858,8 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); - state.group_validators((local_validator.group_index.0 + 1).into(), true); + let other_group_validators = state.group_validators(local_group_index, true); + state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; @@ -968,7 +971,7 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { let config = TestConfig { validator_count: 20, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -979,7 +982,8 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -993,9 +997,8 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); - let next_group_validators = - state.group_validators((local_validator.group_index.0 + 1).into(), true); + let other_group_validators = state.group_validators(local_group_index, true); + let next_group_validators = state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_c = next_group_validators[0]; @@ -1105,7 +1108,7 @@ fn local_node_sanity_checks_incoming_requests() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1117,7 +1120,8 @@ fn local_node_sanity_checks_incoming_requests() { test_harness(config, |mut state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1135,7 +1139,7 @@ fn local_node_sanity_checks_incoming_requests() { // peer B is in group, has no relay parent in view. // peer C is not in group, has relay parent in view. { - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); connect_peer( &mut overseer, @@ -1311,7 +1315,7 @@ fn local_node_checks_that_peer_can_request_before_responding() { let config = TestConfig { validator_count: 20, group_size: 3, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1321,7 +1325,8 @@ fn local_node_checks_that_peer_can_request_before_responding() { test_harness(config, |mut state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1336,7 +1341,7 @@ fn local_node_checks_that_peer_can_request_before_responding() { let candidate_hash = candidate.hash(); // Peers A and B are in group and have relay parent in view. - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); connect_peer( &mut overseer, @@ -1515,7 +1520,7 @@ fn local_node_respects_statement_mask() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1527,7 +1532,8 @@ fn local_node_respects_statement_mask() { test_harness(config, |mut state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); - let local_para = ParaId::from(local_validator.group_index.0); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); let test_leaf = state.make_dummy_leaf(relay_parent); @@ -1541,9 +1547,9 @@ fn local_node_respects_statement_mask() { ); let candidate_hash = candidate.hash(); - let other_group_validators = state.group_validators(local_validator.group_index, true); + let other_group_validators = state.group_validators(local_group_index, true); let target_group_validators = - state.group_validators((local_validator.group_index.0 + 1).into(), true); + state.group_validators((local_group_index.0 + 1).into(), true); let v_a = other_group_validators[0]; let v_b = other_group_validators[1]; let v_c = target_group_validators[0]; @@ -1707,7 +1713,7 @@ fn local_node_respects_statement_mask() { assert_eq!(manifest, BackedCandidateManifest { relay_parent, candidate_hash, - group_index: local_validator.group_index, + group_index: local_group_index, para_id: local_para, parent_head_data_hash: pvd.parent_head.hash(), statement_knowledge: StatementFilter { @@ -1761,7 +1767,7 @@ fn should_delay_before_retrying_dropped_requests() { let config = TestConfig { validator_count, group_size, - local_validator: true, + local_validator: LocalRole::Validator, async_backing_params: None, }; @@ -1772,9 +1778,9 @@ fn should_delay_before_retrying_dropped_requests() { test_harness(config, |state, mut overseer| async move { let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); - let other_group = - next_group_index(local_validator.group_index, validator_count, group_size); + let other_group = next_group_index(local_group_index, validator_count, group_size); let other_para = ParaId::from(other_group.0); let test_leaf = state.make_dummy_leaf(relay_parent); -- GitLab From fc12f435e3796d33018aab93a9e8cd851d4431d5 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Tue, 14 Nov 2023 20:48:32 +0200 Subject: [PATCH 511/633] add NodeFeatures field to HostConfiguration and runtime API (#2177) Adds a `NodeFeatures` bitfield value to the runtime `HostConfiguration`, with the purpose of coordinating the enabling of node-side features, such as: https://github.com/paritytech/polkadot-sdk/issues/628 and https://github.com/paritytech/polkadot-sdk/issues/598. These are features that require all validators enable them at the same time, assuming all/most nodes have upgraded their node versions. This PR doesn't add any feature yet. These are coming in future PRs. Also adds a runtime API for querying the state of the client features and an extrinsic for setting/unsetting a feature by its index in the bitfield. Note: originally part of: https://github.com/paritytech/polkadot-sdk/pull/1644, but posted as standalone to be reused by other PRs until the initial PR is merged --- Cargo.lock | 1 + .../src/blockchain_rpc_client.rs | 5 + .../src/rpc_client.rs | 12 +- .../emulated/chains/relays/rococo/src/lib.rs | 2 +- .../emulated/chains/relays/westend/src/lib.rs | 2 +- polkadot/node/core/runtime-api/src/cache.rs | 20 +- polkadot/node/core/runtime-api/src/lib.rs | 23 +- polkadot/node/core/runtime-api/src/tests.rs | 16 +- polkadot/node/subsystem-types/src/messages.rs | 17 +- .../subsystem-types/src/runtime_client.rs | 22 +- .../node/subsystem-util/src/runtime/mod.rs | 33 ++- polkadot/primitives/Cargo.toml | 2 +- polkadot/primitives/src/runtime_api.rs | 15 +- polkadot/primitives/src/vstaging/mod.rs | 5 + .../runtime/parachains/src/configuration.rs | 53 +++- .../src/configuration/benchmarking.rs | 2 + .../parachains/src/configuration/migration.rs | 1 + .../src/configuration/migration/v10.rs | 277 ++++++++++++++++++ .../src/configuration/migration/v9.rs | 107 ++++++- .../parachains/src/configuration/tests.rs | 8 + .../src/runtime_api_impl/vstaging.rs | 9 +- polkadot/runtime/rococo/src/lib.rs | 17 +- .../runtime_parachains_configuration.rs | 86 +++--- polkadot/runtime/westend/src/lib.rs | 19 +- .../runtime_parachains_configuration.rs | 86 +++--- 25 files changed, 709 insertions(+), 131 deletions(-) create mode 100644 polkadot/runtime/parachains/src/configuration/migration/v10.rs diff --git a/Cargo.lock b/Cargo.lock index d8308086822..196f580e0d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1527,6 +1527,7 @@ checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", + "serde", "tap", "wyz", ] 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 1e78df71154..a473b3bced0 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 @@ -24,6 +24,7 @@ use polkadot_overseer::RuntimeApiSubsystemClient; use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, slashing, + vstaging::NodeFeatures, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sp_api::{ApiError, RuntimeApiInfo}; @@ -364,6 +365,10 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { ) -> Result, ApiError> { Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?) } + + async fn node_features(&self, at: Hash) -> Result { + Ok(self.rpc_client.parachain_host_node_features(at).await?) + } } #[async_trait::async_trait] 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 90af334e133..cc993c6ff9f 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -31,7 +31,9 @@ use parity_scale_codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain::{ async_backing::{AsyncBackingParams, BackingState}, - slashing, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + slashing, + vstaging::NodeFeatures, + BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, @@ -597,6 +599,14 @@ impl RelayChainRpcClient { .await } + pub async fn parachain_host_node_features( + &self, + at: RelayHash, + ) -> Result { + self.call_remote_runtime_function("ParachainHost_node_features", at, None::<()>) + .await + } + pub async fn parachain_host_disabled_validators( &self, at: RelayHash, diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs index f806f4a5d9e..7ace9614710 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{ // Rococo declaration decl_test_relay_chains! { - #[api_version(8)] + #[api_version(9)] pub struct Rococo { genesis = genesis::genesis(), on_init = (), diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs index d4ba1b6cfe7..2ba47250d56 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{ // Westend declaration decl_test_relay_chains! { - #[api_version(8)] + #[api_version(9)] pub struct Westend { genesis = genesis::genesis(), on_init = (), diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 69eea22b23b..8a7a3dc08b8 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,7 +20,7 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - async_backing, slashing, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, + async_backing, slashing, vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, @@ -67,6 +67,7 @@ pub(crate) struct RequestResultCache { disabled_validators: LruMap>, para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, + node_features: LruMap, } impl Default for RequestResultCache { @@ -100,6 +101,7 @@ impl Default for RequestResultCache { 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)), + node_features: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } } } @@ -446,6 +448,21 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } + pub(crate) fn node_features( + &mut self, + session_index: SessionIndex, + ) -> Option<&vstaging::NodeFeatures> { + self.node_features.get(&session_index).map(|f| &*f) + } + + pub(crate) fn cache_node_features( + &mut self, + session_index: SessionIndex, + features: vstaging::NodeFeatures, + ) { + self.node_features.insert(session_index, features); + } + pub(crate) fn disabled_validators( &mut self, relay_parent: &Hash, @@ -540,4 +557,5 @@ pub(crate) enum RequestResult { DisabledValidators(Hash, Vec), ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), + NodeFeatures(SessionIndex, vstaging::NodeFeatures), } diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index bdcca08b10d..8689355c413 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -173,6 +173,8 @@ where .cache_para_backing_state((relay_parent, para_id), constraints), AsyncBackingParams(relay_parent, params) => self.requests_cache.cache_async_backing_params(relay_parent, params), + NodeFeatures(session_index, params) => + self.requests_cache.cache_node_features(session_index, params), } } @@ -313,6 +315,15 @@ where Some(Request::MinimumBackingVotes(index, sender)) } }, + Request::NodeFeatures(index, sender) => { + if let Some(value) = self.requests_cache.node_features(index) { + self.metrics.on_cached_request(); + let _ = sender.send(Ok(value.clone())); + None + } else { + Some(Request::NodeFeatures(index, sender)) + } + }, } } @@ -408,6 +419,9 @@ where macro_rules! query { ($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr) => {{ + query!($req_variant, $api_name($($param),*), ver = $version, $sender, result = ( relay_parent $(, $param )* ) ) + }}; + ($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr, result = ( $($results:expr),* ) ) => {{ let sender = $sender; let version: u32 = $version; // enforce type for the version expression let runtime_version = client.api_version_parachain_host(relay_parent).await @@ -441,7 +455,7 @@ where metrics.on_request(res.is_ok()); let _ = sender.send(res.clone()); - res.ok().map(|res| RequestResult::$req_variant(relay_parent, $( $param, )* res)) + res.ok().map(|res| RequestResult::$req_variant($( $results, )* res)) }} } @@ -591,5 +605,12 @@ where sender ) }, + Request::NodeFeatures(index, sender) => query!( + NodeFeatures, + node_features(), + ver = Request::NODE_FEATURES_RUNTIME_REQUIREMENT, + sender, + result = (index) + ), } } diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index 979b3587d26..b939bffb0e7 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,12 +20,12 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - async_backing, slashing, 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, + async_backing, slashing, vstaging::NodeFeatures, 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, }; use sp_api::ApiError; use sp_core::testing::TaskExecutor; @@ -269,6 +269,10 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { todo!("Not required for tests") } + async fn node_features(&self, _: Hash) -> Result { + todo!("Not required for tests") + } + async fn disabled_validators(&self, _: Hash) -> Result, ApiError> { todo!("Not required for tests") } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 4ddffc6dc5e..43456daec30 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -42,12 +42,12 @@ use polkadot_node_primitives::{ ValidationResult, }; use polkadot_primitives::{ - 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, + async_backing, slashing, vstaging::NodeFeatures, 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, }; @@ -718,6 +718,8 @@ pub enum RuntimeApiRequest { /// /// If it's not supported by the Runtime, the async backing is said to be disabled. AsyncBackingParams(RuntimeApiSender), + /// Get the node features. + NodeFeatures(SessionIndex, RuntimeApiSender), } impl RuntimeApiRequest { @@ -746,6 +748,9 @@ impl RuntimeApiRequest { /// `DisabledValidators` pub const DISABLED_VALIDATORS_RUNTIME_REQUIREMENT: u32 = 8; + + /// `Node features` + pub const NODE_FEATURES_RUNTIME_REQUIREMENT: u32 = 9; } /// 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 f7adcf9862b..8369fd215f4 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,12 +16,12 @@ use async_trait::async_trait; use polkadot_primitives::{ - 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, + async_backing, runtime_api::ParachainHost, slashing, vstaging, 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, }; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_api::{ApiError, ApiExt, ProvideRuntimeApi}; @@ -257,8 +257,14 @@ pub trait RuntimeApiSubsystemClient { ) -> Result, ApiError>; // === v8 === + /// Gets the disabled validators at a specific block height async fn disabled_validators(&self, at: Hash) -> Result, ApiError>; + + // === v9 === + + /// Get the node features. + async fn node_features(&self, at: Hash) -> Result; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -508,6 +514,10 @@ where self.client.runtime_api().async_backing_params(at) } + async fn node_features(&self, at: Hash) -> Result { + self.client.runtime_api().node_features(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/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 8d7cef88a70..aada7a5d77a 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,8 +30,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - slashing, AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs, - ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, + slashing, vstaging::NodeFeatures, 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, }; @@ -507,3 +507,32 @@ pub async fn request_min_backing_votes( min_backing_votes_res } } + +/// Request the node features enabled in the runtime. +/// Pass in the session index for caching purposes, as it should only change on session boundaries. +/// Prior to runtime API version 9, just return `None`. +pub async fn request_node_features( + parent: Hash, + session_index: SessionIndex, + sender: &mut impl overseer::SubsystemSender, +) -> Result> { + let res = recv_runtime( + request_from_runtime(parent, sender, |tx| { + RuntimeApiRequest::NodeFeatures(session_index, tx) + }) + .await, + ) + .await; + + if let Err(Error::RuntimeRequest(RuntimeApiError::NotSupported { .. })) = res { + gum::trace!( + target: LOG_TARGET, + ?parent, + "Querying the node features from the runtime is not supported by the current Runtime API", + ); + + Ok(None) + } else { + res.map(Some) + } +} diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index b318c2d4be7..316644a372d 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true description = "Shared primitives used by Polkadot runtime" [dependencies] -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } +bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 5ec897c8cbb..e4c1d590f45 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -114,10 +114,10 @@ //! separated from the stable primitives. use crate::{ - async_backing, slashing, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + async_backing, slashing, vstaging, 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}; @@ -264,5 +264,12 @@ sp_api::decl_runtime_apis! { /// Returns a list of all disabled validators at the given block. #[api_version(8)] fn disabled_validators() -> Vec; + + /***** Added in v9 *****/ + + /// Get node features. + /// This is a staging method! Do not use on production runtimes! + #[api_version(9)] + fn node_features() -> vstaging::NodeFeatures; } } diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 1429b0c326a..083e0f42d56 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -17,3 +17,8 @@ //! Staging Primitives. // Put any primitives used by staging APIs functions here + +use bitvec::vec::BitVec; + +/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. +pub type NodeFeatures = BitVec; diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index d85c267496f..bff9cc34b4f 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,8 +26,8 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, - LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, + vstaging::NodeFeatures, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, + SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; @@ -261,6 +261,8 @@ pub struct HostConfiguration { /// The minimum number of valid backing statements required to consider a parachain candidate /// backable. pub minimum_backing_votes: u32, + /// Node features enablement. + pub node_features: NodeFeatures, } impl> Default for HostConfiguration { @@ -312,6 +314,7 @@ impl> Default for HostConfiguration Weight; fn set_config_with_executor_params() -> Weight; fn set_config_with_perbill() -> Weight; + fn set_node_feature() -> Weight; } pub struct TestWeightInfo; @@ -488,6 +492,9 @@ impl WeightInfo for TestWeightInfo { fn set_config_with_perbill() -> Weight { Weight::MAX } + fn set_node_feature() -> Weight { + Weight::MAX + } } #[frame_support::pallet] @@ -496,18 +503,19 @@ pub mod pallet { /// The current storage version. /// - /// v0-v1: - /// v1-v2: - /// v2-v3: - /// v3-v4: - /// v4-v5: - /// + - /// + - /// v5-v6: (remove UMP dispatch queue) - /// v6-v7: - /// v7-v8: - /// v8-v9: - const STORAGE_VERSION: StorageVersion = StorageVersion::new(9); + /// v0-v1: + /// v1-v2: + /// v2-v3: + /// v3-v4: + /// v4-v5: + /// + + /// + + /// v5-v6: (remove UMP dispatch queue) + /// v6-v7: + /// v7-v8: + /// v8-v9: + /// v9-v10: + const STORAGE_VERSION: StorageVersion = StorageVersion::new(10); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1195,6 +1203,23 @@ pub mod pallet { config.minimum_backing_votes = new; }) } + /// Set/Unset a node feature. + #[pallet::call_index(53)] + #[pallet::weight(( + T::WeightInfo::set_node_feature(), + DispatchClass::Operational + ))] + pub fn set_node_feature(origin: OriginFor, index: u8, value: bool) -> DispatchResult { + ensure_root(origin)?; + + Self::schedule_config_update(|config| { + let index = usize::from(index); + if config.node_features.len() <= index { + config.node_features.resize(index + 1, false); + } + config.node_features.set(index, value); + }) + } } #[pallet::hooks] diff --git a/polkadot/runtime/parachains/src/configuration/benchmarking.rs b/polkadot/runtime/parachains/src/configuration/benchmarking.rs index d9d11ab56e4..508e0579a09 100644 --- a/polkadot/runtime/parachains/src/configuration/benchmarking.rs +++ b/polkadot/runtime/parachains/src/configuration/benchmarking.rs @@ -49,6 +49,8 @@ benchmarks! { set_config_with_perbill {}: set_on_demand_fee_variability(RawOrigin::Root, Perbill::from_percent(100)) + set_node_feature{}: set_node_feature(RawOrigin::Root, 255, true) + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(Default::default()), diff --git a/polkadot/runtime/parachains/src/configuration/migration.rs b/polkadot/runtime/parachains/src/configuration/migration.rs index 26f8a85b496..db323d3aad9 100644 --- a/polkadot/runtime/parachains/src/configuration/migration.rs +++ b/polkadot/runtime/parachains/src/configuration/migration.rs @@ -16,6 +16,7 @@ //! A module that is responsible for migration of storage. +pub mod v10; pub mod v6; pub mod v7; pub mod v8; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs new file mode 100644 index 00000000000..3c934082dc1 --- /dev/null +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -0,0 +1,277 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::configuration::{self, Config, Pallet}; +use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::{vstaging::NodeFeatures, SessionIndex}; +use sp_std::vec::Vec; + +use frame_support::traits::OnRuntimeUpgrade; + +use super::v9::V9HostConfiguration; + +type V10HostConfiguration = configuration::HostConfiguration; + +mod v9 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V9HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V9HostConfiguration>)>, + OptionQuery, + >; +} + +mod v10 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V10HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V10HostConfiguration>)>, + OptionQuery, + >; +} + +pub struct VersionUncheckedMigrateToV10(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for VersionUncheckedMigrateToV10 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV10"); + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + migrate_to_v10::() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade() for HostConfiguration MigrateToV10"); + ensure!( + Pallet::::on_chain_storage_version() >= StorageVersion::new(10), + "Storage version should be >= 10 after the migration" + ); + + Ok(()) + } +} + +pub type MigrateToV10 = frame_support::migrations::VersionedMigration< + 9, + 10, + VersionUncheckedMigrateToV10, + Pallet, + ::DbWeight, +>; + +// Unusual formatting is justified: +// - make it easier to verify that fields assign what they supposed to assign. +// - this code is transient and will be removed after all migrations are done. +// - this code is important enough to optimize for legibility sacrificing consistency. +#[rustfmt::skip] +fn translate(pre: V9HostConfiguration>) -> V10HostConfiguration> { + V10HostConfiguration { + max_code_size : pre.max_code_size, + max_head_data_size : pre.max_head_data_size, + max_upward_queue_count : pre.max_upward_queue_count, + max_upward_queue_size : pre.max_upward_queue_size, + max_upward_message_size : pre.max_upward_message_size, + max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate, + hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate, + validation_upgrade_cooldown : pre.validation_upgrade_cooldown, + validation_upgrade_delay : pre.validation_upgrade_delay, + max_pov_size : pre.max_pov_size, + max_downward_message_size : pre.max_downward_message_size, + hrmp_sender_deposit : pre.hrmp_sender_deposit, + hrmp_recipient_deposit : pre.hrmp_recipient_deposit, + hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity, + hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size, + hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels, + hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels, + hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size, + code_retention_period : pre.code_retention_period, + on_demand_cores : pre.on_demand_cores, + on_demand_retries : pre.on_demand_retries, + group_rotation_frequency : pre.group_rotation_frequency, + paras_availability_period : pre.paras_availability_period, + scheduling_lookahead : pre.scheduling_lookahead, + max_validators_per_core : pre.max_validators_per_core, + max_validators : pre.max_validators, + dispute_period : pre.dispute_period, + dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period, + no_show_slots : pre.no_show_slots, + n_delay_tranches : pre.n_delay_tranches, + zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width, + needed_approvals : pre.needed_approvals, + relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, + pvf_voting_ttl : pre.pvf_voting_ttl, + minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, + async_backing_params : pre.async_backing_params, + executor_params : pre.executor_params, + on_demand_queue_max_size : pre.on_demand_queue_max_size, + on_demand_base_fee : pre.on_demand_base_fee, + on_demand_fee_variability : pre.on_demand_fee_variability, + on_demand_target_queue_utilization : pre.on_demand_target_queue_utilization, + on_demand_ttl : pre.on_demand_ttl, + minimum_backing_votes : pre.minimum_backing_votes, + node_features : NodeFeatures::EMPTY + } +} + +fn migrate_to_v10() -> Weight { + let v9 = v9::ActiveConfig::::get() + .defensive_proof("Could not decode old config") + .unwrap_or_default(); + let v10 = translate::(v9); + v10::ActiveConfig::::set(Some(v10)); + + // Allowed to be empty. + let pending_v9 = v9::PendingConfigs::::get().unwrap_or_default(); + let mut pending_v10 = Vec::new(); + + for (session, v9) in pending_v9.into_iter() { + let v10 = translate::(v9); + pending_v10.push((session, v10)); + } + v10::PendingConfigs::::set(Some(pending_v10.clone())); + + let num_configs = (pending_v10.len() + 1) as u64; + T::DbWeight::get().reads_writes(num_configs, num_configs) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{new_test_ext, Test}; + use primitives::LEGACY_MIN_BACKING_VOTES; + + #[test] + fn v10_deserialized_from_actual_data() { + // Example how to get new `raw_config`: + // We'll obtain the raw_config at a specified a block + // Steps: + // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate + // 2. Set these parameters: + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration + // 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of + // the block) + // 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the + // referenced block. + // 2.4. You'll also need the decoded values to update the test. + // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage + // 3.1 Enter the encoded storage key and you get the raw config. + + // This exceeds the maximal line width length, but that's fine, since this is not code and + // doesn't need to be read and also leaving it as one line allows to easily copy it. + let raw_config = + hex_literal::hex![" + 0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000000000000000001027000080b2e60e80c3c90180969800000000000000000000000000050000001400000004000000010000000101000000000600000064000000020000001900000000000000020000000200000002000000050000000200000000" + ]; + + let v10 = + V10HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); + + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. + assert_eq!(v10.max_code_size, 3_145_728); + assert_eq!(v10.validation_upgrade_cooldown, 2); + assert_eq!(v10.max_pov_size, 5_242_880); + assert_eq!(v10.hrmp_channel_max_message_size, 1_048_576); + assert_eq!(v10.n_delay_tranches, 25); + assert_eq!(v10.minimum_validation_upgrade_delay, 5); + assert_eq!(v10.group_rotation_frequency, 20); + assert_eq!(v10.on_demand_cores, 0); + assert_eq!(v10.on_demand_base_fee, 10_000_000); + assert_eq!(v10.minimum_backing_votes, LEGACY_MIN_BACKING_VOTES); + assert_eq!(v10.node_features, NodeFeatures::EMPTY); + } + + // Test that `migrate_to_v10`` correctly applies the `translate` function to current and pending + // configs. + #[test] + fn test_migrate_to_v10() { + // Host configuration has lots of fields. However, in this migration we only add one + // field. The most important part to check are a couple of the last fields. We also pick + // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and + // also their type. + // + // We specify only the picked fields and the rest should be provided by the `Default` + // implementation. That implementation is copied over between the two types and should work + // fine. + let v9 = V9HostConfiguration:: { + needed_approvals: 69, + paras_availability_period: 55, + hrmp_recipient_deposit: 1337, + max_pov_size: 1111, + minimum_validation_upgrade_delay: 20, + ..Default::default() + }; + + let mut pending_configs = Vec::new(); + pending_configs.push((100, v9.clone())); + pending_configs.push((300, v9.clone())); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v9 version in the state. + v9::ActiveConfig::::set(Some(v9.clone())); + v9::PendingConfigs::::set(Some(pending_configs)); + + migrate_to_v10::(); + + let v10 = translate::(v9); + let mut configs_to_check = v10::PendingConfigs::::get().unwrap(); + configs_to_check.push((0, v10::ActiveConfig::::get().unwrap())); + + for (_, config) in configs_to_check { + assert_eq!(config, v10); + assert_eq!(config.node_features, NodeFeatures::EMPTY); + } + }); + } + + // Test that migration doesn't panic in case there're no pending configurations upgrades in + // pallet's storage. + #[test] + fn test_migrate_to_v10_no_pending() { + let v9 = V9HostConfiguration::::default(); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v9 version in the state. + v9::ActiveConfig::::set(Some(v9)); + // Ensure there're no pending configs. + v9::PendingConfigs::::set(None); + + // Shouldn't fail. + migrate_to_v10::(); + }); + } +} diff --git a/polkadot/runtime/parachains/src/configuration/migration/v9.rs b/polkadot/runtime/parachains/src/configuration/migration/v9.rs index e37f0b9b0e3..ca4bbd9dace 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v9.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v9.rs @@ -23,13 +23,116 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{SessionIndex, LEGACY_MIN_BACKING_VOTES}; +use primitives::{ + AsyncBackingParams, Balance, ExecutorParams, SessionIndex, LEGACY_MIN_BACKING_VOTES, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, +}; +use sp_runtime::Perbill; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use super::v8::V8HostConfiguration; -type V9HostConfiguration = configuration::HostConfiguration; +/// All configuration of the runtime with respect to paras. +#[derive(Clone, Encode, Decode, Debug)] +pub struct V9HostConfiguration { + pub max_code_size: u32, + pub max_head_data_size: u32, + pub max_upward_queue_count: u32, + pub max_upward_queue_size: u32, + pub max_upward_message_size: u32, + pub max_upward_message_num_per_candidate: u32, + pub hrmp_max_message_num_per_candidate: u32, + pub validation_upgrade_cooldown: BlockNumber, + pub validation_upgrade_delay: BlockNumber, + pub async_backing_params: AsyncBackingParams, + pub max_pov_size: u32, + pub max_downward_message_size: u32, + pub hrmp_max_parachain_outbound_channels: u32, + pub hrmp_sender_deposit: Balance, + pub hrmp_recipient_deposit: Balance, + pub hrmp_channel_max_capacity: u32, + pub hrmp_channel_max_total_size: u32, + pub hrmp_max_parachain_inbound_channels: u32, + pub hrmp_channel_max_message_size: u32, + pub executor_params: ExecutorParams, + pub code_retention_period: BlockNumber, + pub on_demand_cores: u32, + pub on_demand_retries: u32, + pub on_demand_queue_max_size: u32, + pub on_demand_target_queue_utilization: Perbill, + pub on_demand_fee_variability: Perbill, + pub on_demand_base_fee: Balance, + pub on_demand_ttl: BlockNumber, + pub group_rotation_frequency: BlockNumber, + pub paras_availability_period: BlockNumber, + pub scheduling_lookahead: u32, + pub max_validators_per_core: Option, + pub max_validators: Option, + pub dispute_period: SessionIndex, + pub dispute_post_conclusion_acceptance_period: BlockNumber, + pub no_show_slots: u32, + pub n_delay_tranches: u32, + pub zeroth_delay_tranche_width: u32, + pub needed_approvals: u32, + pub relay_vrf_modulo_samples: u32, + pub pvf_voting_ttl: SessionIndex, + pub minimum_validation_upgrade_delay: BlockNumber, + pub minimum_backing_votes: u32, +} + +impl> Default for V9HostConfiguration { + fn default() -> Self { + Self { + async_backing_params: AsyncBackingParams { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + no_show_slots: 1u32.into(), + validation_upgrade_cooldown: Default::default(), + validation_upgrade_delay: 2u32.into(), + code_retention_period: Default::default(), + max_code_size: Default::default(), + max_pov_size: Default::default(), + max_head_data_size: Default::default(), + on_demand_cores: Default::default(), + on_demand_retries: Default::default(), + scheduling_lookahead: 1, + max_validators_per_core: Default::default(), + max_validators: None, + dispute_period: 6, + dispute_post_conclusion_acceptance_period: 100.into(), + n_delay_tranches: Default::default(), + zeroth_delay_tranche_width: Default::default(), + needed_approvals: Default::default(), + relay_vrf_modulo_samples: Default::default(), + max_upward_queue_count: Default::default(), + max_upward_queue_size: Default::default(), + max_downward_message_size: Default::default(), + max_upward_message_size: Default::default(), + max_upward_message_num_per_candidate: Default::default(), + hrmp_sender_deposit: Default::default(), + hrmp_recipient_deposit: Default::default(), + hrmp_channel_max_capacity: Default::default(), + hrmp_channel_max_total_size: Default::default(), + hrmp_max_parachain_inbound_channels: Default::default(), + hrmp_channel_max_message_size: Default::default(), + hrmp_max_parachain_outbound_channels: Default::default(), + hrmp_max_message_num_per_candidate: Default::default(), + pvf_voting_ttl: 2u32.into(), + minimum_validation_upgrade_delay: 2.into(), + executor_params: Default::default(), + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_ttl: 5u32.into(), + minimum_backing_votes: LEGACY_MIN_BACKING_VOTES, + } + } +} mod v8 { use super::*; diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index ea39628c958..b62a45355e1 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -16,6 +16,7 @@ use super::*; use crate::mock::{new_test_ext, Configuration, ParasShared, RuntimeOrigin, Test}; +use bitvec::{bitvec, prelude::Lsb0}; use frame_support::{assert_err, assert_noop, assert_ok}; fn on_new_session(session_index: SessionIndex) -> (HostConfiguration, HostConfiguration) { @@ -318,6 +319,7 @@ fn setting_pending_config_members() { on_demand_target_queue_utilization: Perbill::from_percent(25), on_demand_ttl: 5u32, minimum_backing_votes: 5, + node_features: bitvec![u8, Lsb0; 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], }; Configuration::set_validation_upgrade_cooldown( @@ -473,6 +475,12 @@ fn setting_pending_config_members() { new_config.minimum_backing_votes, ) .unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 1, true).unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 1, true).unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 3, true).unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 10, true).unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 10, false).unwrap(); + Configuration::set_node_feature(RuntimeOrigin::root(), 11, true).unwrap(); assert_eq!(PendingConfigs::::get(), vec![(shared::SESSION_DELAY, new_config)],); }) diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 24a076f3a44..200fd57915f 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -16,8 +16,8 @@ //! Put implementations of functions from staging APIs here. -use crate::shared; -use primitives::ValidatorIndex; +use crate::{configuration, initializer, shared}; +use primitives::{vstaging::NodeFeatures, ValidatorIndex}; use sp_std::{collections::btree_map::BTreeMap, prelude::Vec}; /// Implementation for `DisabledValidators` @@ -42,3 +42,8 @@ where .filter_map(|v| reverse_index.get(v).cloned()) .collect() } + +/// Returns the current state of the node features. +pub fn node_features() -> NodeFeatures { + >::config().node_features +} diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 40ef22107a7..5a1e170862e 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -23,11 +23,12 @@ 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, PARACHAIN_KEY_TYPE_ID, + slashing, vstaging::NodeFeatures, 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, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, claims, crowdloan, impl_runtime_weights, @@ -1499,6 +1500,7 @@ pub mod migrations { frame_support::migrations::RemovePallet::DbWeight>, pallet_grandpa::migrations::MigrateV4ToV5, + parachains_configuration::migration::v10::MigrateToV10, ); } @@ -1660,7 +1662,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(8)] + #[api_version(9)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1808,6 +1810,9 @@ sp_api::impl_runtime_apis! { parachains_staging_runtime_api_impl::disabled_validators::() } + fn node_features() -> NodeFeatures { + parachains_staging_runtime_api_impl::node_features::() + } } #[api_version(3)] diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs index 29f38765778..34541b83597 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs @@ -17,9 +17,9 @@ //! 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: `[]` +//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -31,11 +31,11 @@ // --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=runtime_parachains::configuration // --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,11 +56,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_051_000 picoseconds. - Weight::from_parts(9_496_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_793_000 picoseconds. + Weight::from_parts(8_192_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -72,11 +72,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_104_000 picoseconds. - Weight::from_parts(9_403_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_819_000 picoseconds. + Weight::from_parts(8_004_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -88,11 +88,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_112_000 picoseconds. - Weight::from_parts(9_495_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_760_000 picoseconds. + Weight::from_parts(8_174_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -114,11 +114,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_011_000 picoseconds. - Weight::from_parts(9_460_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_814_000 picoseconds. + Weight::from_parts(8_098_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,11 +130,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_940_000 picoseconds. - Weight::from_parts(10_288_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 10_028_000 picoseconds. + Weight::from_parts(10_386_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -146,11 +146,27 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_192_000 picoseconds. - Weight::from_parts(9_595_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_867_000 picoseconds. + Weight::from_parts(8_191_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_node_feature() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 10_158_000 picoseconds. + Weight::from_parts(10_430_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d80640c016f..d3862aff257 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -46,12 +46,12 @@ use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, 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, PvfCheckStatement, ScrapedOnChainVotes, - SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, PARACHAIN_KEY_TYPE_ID, + slashing, vstaging::NodeFeatures, AccountId, AccountIndex, Balance, BlockNumber, + CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, crowdloan, @@ -1559,6 +1559,7 @@ pub mod migrations { pallet_referenda::migration::v1::MigrateV0ToV1, pallet_nomination_pools::migration::versioned_migrations::V6ToV7, pallet_grandpa::migrations::MigrateV4ToV5, + parachains_configuration::migration::v10::MigrateToV10, ); } @@ -1699,7 +1700,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(8)] + #[api_version(9)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1846,6 +1847,10 @@ sp_api::impl_runtime_apis! { fn disabled_validators() -> Vec { parachains_staging_runtime_api_impl::disabled_validators::() } + + fn node_features() -> NodeFeatures { + parachains_staging_runtime_api_impl::node_features::() + } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs index 585dc9058f2..3a4813b667c 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs @@ -17,9 +17,9 @@ //! 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: `[]` +//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -31,11 +31,11 @@ // --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=runtime_parachains::configuration // --chain=westend-dev -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,11 +56,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_616_000 picoseconds. - Weight::from_parts(9_961_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 8_065_000 picoseconds. + Weight::from_parts(8_389_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -72,11 +72,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_587_000 picoseconds. - Weight::from_parts(9_964_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 8_038_000 picoseconds. + Weight::from_parts(8_463_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -88,11 +88,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_650_000 picoseconds. - Weight::from_parts(9_960_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_843_000 picoseconds. + Weight::from_parts(8_216_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -114,11 +114,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_545_000 picoseconds. - Weight::from_parts(9_845_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_969_000 picoseconds. + Weight::from_parts(8_362_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,11 +130,11 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_258_000 picoseconds. - Weight::from_parts(10_607_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 10_084_000 picoseconds. + Weight::from_parts(10_451_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -146,11 +146,27 @@ impl runtime_parachains::configuration::WeightInfo for /// 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_502_000 picoseconds. - Weight::from_parts(9_902_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_948_000 picoseconds. + Weight::from_parts(8_268_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_node_feature() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 10_257_000 picoseconds. + Weight::from_parts(10_584_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } -- GitLab From f517900a48ada81764e9d75d1e9d598ea4b84719 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Tue, 14 Nov 2023 21:32:14 +0100 Subject: [PATCH 512/633] Contracts expose pallet-xcm (#1248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces: - XCM host functions `xcm_send`, `xcm_execute` - An Xcm trait into the config. that proxy these functions to to `pallet_xcm`, or disable their usage by using `()`. - A mock_network and xcm_test files to test the newly added xcm-related functions. --------- Co-authored-by: Keith Yeung Co-authored-by: Sasha Gryaznov Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre Co-authored-by: Alexander Theißen --- Cargo.lock | 43 +++ Cargo.toml | 1 + .../contracts-rococo/src/contracts.rs | 1 + polkadot/xcm/xcm-builder/src/controller.rs | 2 +- polkadot/xcm/xcm-builder/src/lib.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/contracts/Cargo.toml | 16 + .../contracts/fixtures/data/xcm_execute.wat | 52 +++ .../contracts/fixtures/data/xcm_send.wat | 59 +++ substrate/frame/contracts/fixtures/src/lib.rs | 2 + .../frame/contracts/mock-network/Cargo.toml | 91 +++++ .../frame/contracts/mock-network/src/lib.rs | 151 ++++++++ .../frame/contracts/mock-network/src/mocks.rs | 18 + .../mock-network/src/mocks/msg_queue.rs | 168 +++++++++ .../src/mocks/relay_message_queue.rs | 52 +++ .../contracts/mock-network/src/parachain.rs | 353 ++++++++++++++++++ .../src/parachain/contracts_config.rs | 98 +++++ .../contracts/mock-network/src/primitives.rs | 23 ++ .../contracts/mock-network/src/relay_chain.rs | 236 ++++++++++++ .../frame/contracts/mock-network/src/tests.rs | 239 ++++++++++++ substrate/frame/contracts/src/lib.rs | 10 + substrate/frame/contracts/src/tests.rs | 1 + substrate/frame/contracts/src/wasm/runtime.rs | 193 +++++++++- 23 files changed, 1797 insertions(+), 15 deletions(-) create mode 100644 substrate/frame/contracts/fixtures/data/xcm_execute.wat create mode 100644 substrate/frame/contracts/fixtures/data/xcm_send.wat create mode 100644 substrate/frame/contracts/mock-network/Cargo.toml create mode 100644 substrate/frame/contracts/mock-network/src/lib.rs create mode 100644 substrate/frame/contracts/mock-network/src/mocks.rs create mode 100644 substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs create mode 100644 substrate/frame/contracts/mock-network/src/mocks/relay_message_queue.rs create mode 100644 substrate/frame/contracts/mock-network/src/parachain.rs create mode 100644 substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs create mode 100644 substrate/frame/contracts/mock-network/src/primitives.rs create mode 100644 substrate/frame/contracts/mock-network/src/relay_chain.rs create mode 100644 substrate/frame/contracts/mock-network/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 196f580e0d5..9ae1bb905b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9699,11 +9699,13 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", + "pallet-assets", "pallet-balances", "pallet-contracts-fixtures", "pallet-contracts-primitives", "pallet-contracts-proc-macro", "pallet-insecure-randomness-collective-flip", + "pallet-message-queue", "pallet-proxy", "pallet-timestamp", "pallet-utility", @@ -9720,6 +9722,9 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-std 8.0.0", + "sp-tracing 10.0.0", + "staging-xcm", + "staging-xcm-builder", "wasm-instrument 0.4.0", "wasmi", "wat", @@ -9734,6 +9739,44 @@ dependencies = [ "wat", ] +[[package]] +name = "pallet-contracts-mock-network" +version = "1.0.0" +dependencies = [ + "assert_matches", + "frame-support", + "frame-system", + "pallet-assets", + "pallet-balances", + "pallet-contracts", + "pallet-contracts-fixtures", + "pallet-contracts-primitives", + "pallet-contracts-proc-macro", + "pallet-insecure-randomness-collective-flip", + "pallet-message-queue", + "pallet-proxy", + "pallet-timestamp", + "pallet-utility", + "pallet-xcm", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", + "polkadot-runtime-parachains", + "pretty_assertions", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std 8.0.0", + "sp-tracing 10.0.0", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-simulator", +] + [[package]] name = "pallet-contracts-primitives" version = "24.0.0" diff --git a/Cargo.toml b/Cargo.toml index 15a7d5c35bf..f9779681cae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -293,6 +293,7 @@ members = [ "substrate/frame/contracts/fixtures", "substrate/frame/contracts/primitives", "substrate/frame/contracts/proc-macro", + "substrate/frame/contracts/mock-network", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", "substrate/frame/democracy", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index b86f797ee03..6c100deaa9e 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -72,4 +72,5 @@ impl Config for Runtime { type RuntimeHoldReason = RuntimeHoldReason; type Debug = (); type Environment = (); + type Xcm = pallet_xcm::Pallet; } diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 0ee638b73e1..931d812eaaf 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -21,7 +21,7 @@ use frame_support::pallet_prelude::DispatchError; use sp_std::boxed::Box; use xcm::prelude::*; -use xcm_executor::traits::QueryHandler; +pub use xcm_executor::traits::QueryHandler; /// Umbrella trait for all Controller traits. pub trait Controller: diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 35f95b85c89..455f17a5348 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -119,5 +119,5 @@ pub use pay::{FixedLocation, LocatableAssetId, PayAccountId32OnChainOverXcm, Pay mod controller; pub use controller::{ Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController, - QueryControllerWeightInfo, SendController, SendControllerWeightInfo, + QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo, }; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index e9adc48ff9c..90946b71311 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1353,6 +1353,7 @@ impl pallet_contracts::Config for Runtime { type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; type Debug = (); type Environment = (); + type Xcm = (); } impl pallet_sudo::Config for Runtime { diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 0eb50c2b0ba..239b0865e0f 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -48,6 +48,9 @@ sp-io = { path = "../../primitives/io", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", 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} + [dev-dependencies] array-bytes = "6.1" assert_matches = "1" @@ -56,13 +59,19 @@ pretty_assertions = "1" wat = "1" pallet-contracts-fixtures = { path = "./fixtures" } +# Polkadot Dependencies +xcm-builder = {package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder"} + # Substrate Dependencies pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } +pallet-message-queue = { path = "../message-queue" } pallet-insecure-randomness-collective-flip = { path = "../insecure-randomness-collective-flip" } pallet-utility = { path = "../utility" } +pallet-assets = { path = "../assets" } pallet-proxy = { path = "../proxy" } sp-keystore = { path = "../../primitives/keystore" } +sp-tracing = { path = "../../primitives/tracing" } [features] default = [ "std" ] @@ -92,12 +101,16 @@ std = [ "sp-std/std", "wasm-instrument/std", "wasmi/std", + "xcm-builder/std", + "xcm/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -105,12 +118,15 @@ runtime-benchmarks = [ "rand_pcg", "sp-runtime/runtime-benchmarks", "wasm-instrument", + "xcm-builder/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-assets/try-runtime", "pallet-balances/try-runtime", "pallet-insecure-randomness-collective-flip/try-runtime", + "pallet-message-queue/try-runtime", "pallet-proxy/try-runtime", "pallet-timestamp/try-runtime", "pallet-utility/try-runtime", diff --git a/substrate/frame/contracts/fixtures/data/xcm_execute.wat b/substrate/frame/contracts/fixtures/data/xcm_execute.wat new file mode 100644 index 00000000000..b3459996a2e --- /dev/null +++ b/substrate/frame/contracts/fixtures/data/xcm_execute.wat @@ -0,0 +1,52 @@ +;; This passes its input to `seal_xcm_execute` and returns the return value to its caller. +(module + (import "seal0" "xcm_execute" (func $xcm_execute (param i32 i32 i32) (result i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; 0x1000 = 4k in little endian + ;; Size of input buffer + (data (i32.const 0) "\00\10") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; Receive the encoded call + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Pointer to the buffer length (before call) and to the copied data length (after call) + ) + ;; Input data layout. + ;; [0..4) - size of the call + ;; [4..) - message + + ;; Call xcm_execute with provided input. + (call $assert + (i32.eq + (call $xcm_execute + (i32.const 4) ;; Pointer where the message is stored + (i32.load (i32.const 0)) ;; Size of the message + (i32.const 100) ;; Pointer to the where the outcome is stored + ) + (i32.const 0) + ) + ) + + (call $seal_return + (i32.const 0) ;; flags + (i32.const 100) ;; Pointer to returned value + (i32.const 10) ;; length of returned value + ) + ) + + (func (export "deploy")) +) + diff --git a/substrate/frame/contracts/fixtures/data/xcm_send.wat b/substrate/frame/contracts/fixtures/data/xcm_send.wat new file mode 100644 index 00000000000..9eec6388de9 --- /dev/null +++ b/substrate/frame/contracts/fixtures/data/xcm_send.wat @@ -0,0 +1,59 @@ +;; This passes its input to `seal_xcm_send` and returns the return value to its caller. +(module + (import "seal0" "xcm_send" (func $xcm_send (param i32 i32 i32 i32) (result i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; 0x1000 = 4k in little endian + ;; size of input buffer + (data (i32.const 0) "\00\10") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + + ;; Receive the encoded call + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + + ;; Input data layout. + ;; [0..4) - size of the call + ;; [4..7) - dest + ;; [7..) - message + + ;; Call xcm_send with provided input. + (call $assert + (i32.eq + (call $xcm_send + (i32.const 4) ;; Pointer where the dest is stored + (i32.const 7) ;; Pointer where the message is stored + (i32.sub + (i32.load (i32.const 0)) ;; length of the input buffer + (i32.const 3) ;; Size of the XCM dest + ) + (i32.const 100) ;; Pointer to the where the message_id is stored + ) + (i32.const 0) + ) + ) + + ;; Return the the message_id + (call $seal_return + (i32.const 0) ;; flags + (i32.const 100) ;; Pointer to returned value + (i32.const 32) ;; length of returned value + ) + ) + + (func (export "deploy")) +) diff --git a/substrate/frame/contracts/fixtures/src/lib.rs b/substrate/frame/contracts/fixtures/src/lib.rs index 32f4023e644..48117f7ca94 100644 --- a/substrate/frame/contracts/fixtures/src/lib.rs +++ b/substrate/frame/contracts/fixtures/src/lib.rs @@ -23,6 +23,8 @@ fn fixtures_root_dir() -> PathBuf { // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder (Err(_), _) => "substrate/frame/contracts/fixtures/data".into(), (Ok(path), Ok(s)) if s == "pallet-contracts" => PathBuf::from(path).join("fixtures/data"), + (Ok(path), Ok(s)) if s == "pallet-contracts-mock-network" => + PathBuf::from(path).parent().unwrap().join("fixtures/data"), (Ok(_), pkg_name) => panic!("Failed to resolve fixture dir for tests from {pkg_name:?}."), } } diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml new file mode 100644 index 00000000000..9d5fe1aaf4e --- /dev/null +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -0,0 +1,91 @@ +[package] +name = "pallet-contracts-mock-network" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage = "https://substrate.io" +repository.workspace = true +description = "A mock network for testing pallet-contracts" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len"] } + +frame-support = { path = "../../support", default-features = false} +frame-system = { path = "../../system", default-features = false} +pallet-assets = { path = "../../assets" } +pallet-balances = { path = "../../balances" } +pallet-contracts = { path = ".." } +pallet-contracts-primitives = { path = "../primitives", default-features = false} +pallet-contracts-proc-macro = { path = "../proc-macro" } +pallet-insecure-randomness-collective-flip = { path = "../../insecure-randomness-collective-flip" } +pallet-message-queue = { path = "../../message-queue" } +pallet-proxy = { path = "../../proxy" } +pallet-timestamp = { path = "../../timestamp" } +pallet-utility = { path = "../../utility" } +pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false} +polkadot-parachain-primitives = { path = "../../../../polkadot/parachain" } +polkadot-primitives = { path = "../../../../polkadot/primitives" } +polkadot-runtime-parachains = {path = "../../../../polkadot/runtime/parachains"} +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +sp-api = { path = "../../../primitives/api", default-features = false} +sp-core = { path = "../../../primitives/core", default-features = false} +sp-io = { path = "../../../primitives/io", default-features = false} +sp-keystore = { path = "../../../primitives/keystore" } +sp-runtime = { path = "../../../primitives/runtime", default-features = false} +sp-std = { path = "../../../primitives/std", default-features = false} +sp-tracing = { path = "../../../primitives/tracing" } +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} +xcm-builder = {package = "staging-xcm-builder", path = "../../../../polkadot/xcm/xcm-builder"} +xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false} +xcm-simulator = {path = "../../../../polkadot/xcm/xcm-simulator"} + +[dev-dependencies] +assert_matches = "1" +pretty_assertions = "1" +pallet-contracts-fixtures = { path = "../fixtures" } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "pallet-balances/std", + "pallet-contracts-primitives/std", + "pallet-contracts-proc-macro/full", + "pallet-contracts/std", + "pallet-insecure-randomness-collective-flip/std", + "pallet-proxy/std", + "pallet-timestamp/std", + "pallet-utility/std", + "pallet-xcm/std", + "scale-info/std", + "sp-api/std", + "sp-core/std", + "sp-io/std", + "sp-keystore/std", + "sp-runtime/std", + "sp-std/std", + "xcm-executor/std", + "xcm/std", +] + +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] diff --git a/substrate/frame/contracts/mock-network/src/lib.rs b/substrate/frame/contracts/mock-network/src/lib.rs new file mode 100644 index 00000000000..345c69541b6 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/lib.rs @@ -0,0 +1,151 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +pub mod mocks; +pub mod parachain; +pub mod primitives; +pub mod relay_chain; + +#[cfg(test)] +mod tests; + +use crate::primitives::{AccountId, UNITS}; +use sp_runtime::BuildStorage; +use xcm::latest::{prelude::*, MultiLocation}; +use xcm_executor::traits::ConvertLocation; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +// Accounts +pub const ADMIN: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); +pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([1u8; 32]); +pub const BOB: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([2u8; 32]); + +// Balances +pub const INITIAL_BALANCE: u128 = 1_000_000_000 * UNITS; + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + ], + } +} + +pub fn relay_sovereign_account_id() -> AccountId { + let location: MultiLocation = (Parent,).into(); + parachain::SovereignAccountOf::convert_location(&location).unwrap() +} + +pub fn parachain_sovereign_account_id(para: u32) -> AccountId { + let location: MultiLocation = (Parachain(para),).into(); + relay_chain::SovereignAccountOf::convert_location(&location).unwrap() +} + +pub fn parachain_account_sovereign_account_id( + para: u32, + who: sp_runtime::AccountId32, +) -> AccountId { + let location: MultiLocation = ( + Parachain(para), + AccountId32 { network: Some(relay_chain::RelayNetwork::get()), id: who.into() }, + ) + .into(); + relay_chain::SovereignAccountOf::convert_location(&location).unwrap() +} + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, INITIAL_BALANCE), + (relay_sovereign_account_id(), INITIAL_BALANCE), + (BOB, INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_assets::GenesisConfig:: { + assets: vec![ + (0u128, ADMIN, false, 1u128), // Create derivative asset for relay's native token + ], + metadata: Default::default(), + accounts: vec![ + (0u128, ALICE, INITIAL_BALANCE), + (0u128, relay_sovereign_account_id(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + sp_tracing::try_init_simple(); + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext() -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, INITIAL_BALANCE), + (parachain_sovereign_account_id(1), INITIAL_BALANCE), + (parachain_account_sovereign_account_id(1, ALICE), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +pub type ParachainPalletXcm = pallet_xcm::Pallet; +pub type ParachainBalances = pallet_balances::Pallet; diff --git a/substrate/frame/contracts/mock-network/src/mocks.rs b/substrate/frame/contracts/mock-network/src/mocks.rs new file mode 100644 index 00000000000..bf3baec7a52 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/mocks.rs @@ -0,0 +1,18 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +pub mod msg_queue; +pub mod relay_message_queue; diff --git a/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs b/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs new file mode 100644 index 00000000000..82fb8590e26 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs @@ -0,0 +1,168 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Parachain runtime mock. + +use codec::{Decode, Encode}; + +use frame_support::weights::Weight; +use polkadot_parachain_primitives::primitives::{ + DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler, +}; +use polkadot_primitives::BlockNumber as RelayBlockNumber; +use sp_runtime::traits::{Get, Hash}; + +use sp_std::prelude::*; +use xcm::{latest::prelude::*, VersionedXcm}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn received_dmp)] + /// A queue of received DMP messages + pub(super) type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = (Parent, Parachain(sender.into())); + match T::XcmExecutor::execute_xcm(location, xcm, message_hash, max_weight) { + Outcome::Error(e) => (Err(e), Event::Fail(Some(hash), e)), + Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete(w, e) => (Ok(w), Event::Fail(Some(hash), e)), + } + }, + Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = data_ref; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let id = sp_io::hashing::blake2_256(&data[..]); + let maybe_versioned = VersionedXcm::::decode(&mut &data[..]); + match maybe_versioned { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + }, + Ok(versioned) => match Xcm::try_from(versioned) { + Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)), + Ok(x) => { + let outcome = T::XcmExecutor::execute_xcm(Parent, x.clone(), id, limit); + >::append(x); + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + }, + }, + } + } + limit + } + } +} diff --git a/substrate/frame/contracts/mock-network/src/mocks/relay_message_queue.rs b/substrate/frame/contracts/mock-network/src/mocks/relay_message_queue.rs new file mode 100644 index 00000000000..14099965e3f --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/mocks/relay_message_queue.rs @@ -0,0 +1,52 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::{parameter_types, weights::Weight}; +use xcm::latest::prelude::*; +use xcm_simulator::{ + AggregateMessageOrigin, ProcessMessage, ProcessMessageError, UmpQueueId, WeightMeter, +}; + +use crate::relay_chain::{RuntimeCall, XcmConfig}; + +parameter_types! { + /// Amount of weight that can be spent per block to service messages. + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet. +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + xcm_builder::ProcessXcmMessage::< + Junction, + xcm_executor::XcmExecutor, + RuntimeCall, + >::process_message(message, Junction::Parachain(para.into()), meter, id) + } +} diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs new file mode 100644 index 00000000000..1465b02f903 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -0,0 +1,353 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Parachain runtime mock. + +mod contracts_config; +use crate::{ + mocks::msg_queue::pallet as mock_msg_queue, + primitives::{AccountId, AssetIdForAssets, Balance}, +}; +use core::marker::PhantomData; +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, EverythingBut, Nothing}, + weights::{ + constants::{WEIGHT_PROOF_SIZE_PER_MB, WEIGHT_REF_TIME_PER_SECOND}, + Weight, + }, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +use pallet_xcm::XcmPassthrough; +use sp_core::{ConstU32, ConstU64, H256}; +use sp_runtime::traits::{Get, IdentityLookup, MaybeEquivalence}; + +use sp_std::prelude::*; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, + ConvertedConcreteId, CurrencyAdapter as XcmCurrencyAdapter, EnsureXcmOrigin, + FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, + ParentAsSuperuser, ParentIsPreset, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +pub type SovereignAccountOf = + (AccountId32Aliases, ParentIsPreset); + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type MaxHolds = ConstU32<1>; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = (); +} + +parameter_types! { + pub const AssetDeposit: u128 = 1_000_000; + pub const MetadataDepositBase: u128 = 1_000_000; + pub const MetadataDepositPerByte: u128 = 100_000; + pub const AssetAccountDeposit: u128 = 1_000_000; + pub const ApprovalDeposit: u128 = 1_000_000; + pub const AssetsStringLimit: u32 = 50; + pub const RemoveItemsLimit: u32 = 50; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetIdForAssets; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type AssetAccountDeposit = AssetAccountDeposit; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = (); + type RemoveItemsLimit = RemoveItemsLimit; + type AssetIdParameter = AssetIdForAssets; + type CallbackHandle = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); + pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); +} + +parameter_types! { + pub const KsmLocation: MultiLocation = MultiLocation::parent(); + pub const TokenLocation: MultiLocation = Here.into_location(); + pub const RelayNetwork: NetworkId = ByGenesis([0; 32]); + pub UniversalLocation: InteriorMultiLocation = Parachain(MsgQueue::parachain_id().into()).into(); +} + +pub type XcmOriginToCallOrigin = ( + SovereignSignedViaLocation, + ParentAsSuperuser, + SignedAccountId32AsNative, + XcmPassthrough, +); + +parameter_types! { + pub const XcmInstructionWeight: Weight = Weight::from_parts(1_000, 1_000); + pub TokensPerSecondPerMegabyte: (AssetId, u128, u128) = (Concrete(Parent.into()), 1_000_000_000_000, 1024 * 1024); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub ForeignPrefix: MultiLocation = (Parent,).into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub TrustedLockPairs: (MultiLocation, MultiAssetFilter) = + (Parent.into(), Wild(AllOf { id: Concrete(Parent.into()), fun: WildFungible })); +} + +pub fn estimate_message_fee(number_of_instructions: u64) -> u128 { + let weight = estimate_weight(number_of_instructions); + + estimate_fee_for_weight(weight) +} + +pub fn estimate_weight(number_of_instructions: u64) -> Weight { + XcmInstructionWeight::get().saturating_mul(number_of_instructions) +} + +pub fn estimate_fee_for_weight(weight: Weight) -> u128 { + let (_, units_per_second, units_per_mb) = TokensPerSecondPerMegabyte::get(); + + units_per_second * (weight.ref_time() as u128) / (WEIGHT_REF_TIME_PER_SECOND as u128) + + units_per_mb * (weight.proof_size() as u128) / (WEIGHT_PROOF_SIZE_PER_MB as u128) +} + +pub type LocalBalancesTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +pub struct FromMultiLocationToAsset(PhantomData<(MultiLocation, AssetId)>); +impl MaybeEquivalence + for FromMultiLocationToAsset +{ + fn convert(value: &MultiLocation) -> Option { + match *value { + MultiLocation { parents: 1, interior: Here } => Some(0 as AssetIdForAssets), + MultiLocation { parents: 1, interior: X1(Parachain(para_id)) } => + Some(para_id as AssetIdForAssets), + _ => None, + } + } + + fn convert_back(_id: &AssetIdForAssets) -> Option { + None + } +} + +pub type ForeignAssetsTransactor = FungiblesAdapter< + Assets, + ConvertedConcreteId< + AssetIdForAssets, + Balance, + FromMultiLocationToAsset, + JustTry, + >, + SovereignAccountOf, + AccountId, + NoChecking, + CheckingAccount, +>; + +/// Means for transacting assets on this chain +pub type AssetTransactors = (LocalBalancesTransactor, ForeignAssetsTransactor); + +pub struct ParentRelay; +impl Contains for ParentRelay { + fn contains(location: &MultiLocation) -> bool { + location.contains_parents_only(1) + } +} +pub struct ThisParachain; +impl Contains for ThisParachain { + fn contains(location: &MultiLocation) -> bool { + matches!( + location, + MultiLocation { parents: 0, interior: Junctions::X1(Junction::AccountId32 { .. }) } + ) + } +} + +pub type XcmRouter = crate::ParachainXcmRouter; + +pub type Barrier = ( + xcm_builder::AllowUnpaidExecutionFrom, + WithComputedOrigin< + (AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom), + UniversalLocation, + ConstU32<1>, + >, +); + +parameter_types! { + pub NftCollectionOne: MultiAssetFilter + = Wild(AllOf { fun: WildNonFungible, id: Concrete((Parent, GeneralIndex(1)).into()) }); + pub NftCollectionOneForRelay: (MultiAssetFilter, MultiLocation) + = (NftCollectionOne::get(), Parent.into()); + pub RelayNativeAsset: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete((Parent, Here).into()) }); + pub RelayNativeAssetForRelay: (MultiAssetFilter, MultiLocation) = (RelayNativeAsset::get(), Parent.into()); +} +pub type TrustedTeleporters = + (xcm_builder::Case, xcm_builder::Case); +pub type TrustedReserves = EverythingBut>; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToCallOrigin; + type IsReserve = (NativeAsset, TrustedReserves); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetLocker = PolkadotXcm; + type AssetExchanger = (); + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = AllPalletsWithSystem; + type FeeManager = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +pub struct TrustedLockerCase(PhantomData); +impl> ContainsPair + for TrustedLockerCase +{ + fn contains(origin: &MultiLocation, asset: &MultiAsset) -> bool { + let (o, a) = T::get(); + a.matches(asset) && &o == origin + } +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = TrustedLockerCase; + type SovereignAccountOf = SovereignAccountOf; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlock; + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<1>; + type WeightInfo = (); +} + +construct_runtime!( + pub enum Runtime + { + System: frame_system, + Balances: pallet_balances, + Timestamp: pallet_timestamp, + MsgQueue: mock_msg_queue, + PolkadotXcm: pallet_xcm, + Contracts: pallet_contracts, + Assets: pallet_assets, + } +); diff --git a/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs b/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs new file mode 100644 index 00000000000..dadba394e26 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs @@ -0,0 +1,98 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::{Balances, Runtime, RuntimeCall, RuntimeEvent}; +use crate::{ + parachain, + parachain::RuntimeHoldReason, + primitives::{Balance, CENTS}, +}; +use frame_support::{ + parameter_types, + traits::{ConstBool, ConstU32, Contains, Randomness}, + weights::Weight, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_xcm::BalanceOf; +use sp_runtime::{traits::Convert, Perbill}; + +pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * CENTS + (bytes as Balance) * 1 * CENTS +} + +parameter_types! { + pub const DepositPerItem: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); + pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024); + pub Schedule: pallet_contracts::Schedule = Default::default(); + pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0); + pub const MaxDelegateDependencies: u32 = 32; +} + +pub struct DummyRandomness(sp_std::marker::PhantomData); + +impl Randomness> for DummyRandomness { + fn random(_subject: &[u8]) -> (T::Hash, BlockNumberFor) { + (Default::default(), Default::default()) + } +} + +impl Convert> for Runtime { + fn convert(w: Weight) -> BalanceOf { + w.ref_time().into() + } +} + +#[derive(Clone, Default)] +pub struct Filters; + +impl Contains for Filters { + fn contains(call: &RuntimeCall) -> bool { + match call { + parachain::RuntimeCall::Contracts(_) => true, + _ => false, + } + } +} + +impl pallet_contracts::Config for Runtime { + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type CallFilter = Filters; + type CallStack = [pallet_contracts::Frame; 5]; + type ChainExtension = (); + type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; + type Currency = Balances; + type DefaultDepositLimit = DefaultDepositLimit; + type DepositPerByte = DepositPerByte; + type DepositPerItem = DepositPerItem; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; + type MaxDelegateDependencies = MaxDelegateDependencies; + type MaxStorageKeyLen = ConstU32<128>; + type Migrations = (); + type Randomness = DummyRandomness; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type Schedule = Schedule; + type Time = super::Timestamp; + type UnsafeUnstableInterface = ConstBool; + type WeightInfo = (); + type WeightPrice = Self; + type Debug = (); + type Environment = (); + type Xcm = pallet_xcm::Pallet; +} diff --git a/substrate/frame/contracts/mock-network/src/primitives.rs b/substrate/frame/contracts/mock-network/src/primitives.rs new file mode 100644 index 00000000000..efc42772f88 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/primitives.rs @@ -0,0 +1,23 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +pub type Balance = u128; + +pub const UNITS: Balance = 10_000_000_000; +pub const CENTS: Balance = UNITS / 100; // 100_000_000 + +pub type AccountId = sp_runtime::AccountId32; +pub type AssetIdForAssets = u128; diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs new file mode 100644 index 00000000000..c59c8e4bfa8 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -0,0 +1,236 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Contains, Everything, Nothing}, + weights::Weight, +}; + +use frame_system::EnsureRoot; +use sp_core::{ConstU32, H256}; +use sp_runtime::traits::IdentityLookup; + +use polkadot_parachain_primitives::primitives::Id as ParaId; +use polkadot_runtime_parachains::{configuration, origin, shared}; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal, + DescribeFamily, FixedRateOfFungible, FixedWeightBounds, HashedDescription, IsConcrete, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; + +use super::{ + mocks::relay_message_queue::*, + primitives::{AccountId, Balance}, +}; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Block = Block; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; +} + +impl shared::Config for Runtime {} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub RelayNetwork: NetworkId = ByGenesis([0; 32]); + pub const TokenLocation: MultiLocation = Here.into_location(); + pub UniversalLocation: InteriorMultiLocation = Here; + pub UnitWeightCost: u64 = 1_000; +} + +pub type SovereignAccountOf = ( + HashedDescription>, + AccountId32Aliases, + ChildParachainConvertsVia, +); + +pub type LocalBalancesTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +pub type AssetTransactors = LocalBalancesTransactor; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const XcmInstructionWeight: Weight = Weight::from_parts(1_000, 1_000); + pub TokensPerSecondPerMegabyte: (AssetId, u128, u128) = + (Concrete(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct ChildrenParachains; +impl Contains for ChildrenParachains { + fn contains(location: &MultiLocation) -> bool { + matches!(location, MultiLocation { parents: 0, interior: X1(Parachain(_)) }) + } +} + +pub type XcmRouter = crate::RelayChainXcmRouter; +pub type Barrier = WithComputedOrigin< + ( + AllowExplicitUnpaidExecutionFrom, + AllowTopLevelPaidExecutionFrom, + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<1>, +>; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetLocker = XcmPallet; + type AssetExchanger = (); + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type PalletInstancesInfo = AllPalletsWithSystem; + type FeeManager = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = SovereignAccountOf; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl origin::Config for Runtime {} + +type Block = frame_system::mocking::MockBlock; + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); +} + +construct_runtime!( + pub enum Runtime { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + ParasOrigin: origin::{Pallet, Origin}, + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + MessageQueue: pallet_message_queue::{Pallet, Event}, + } +); diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs new file mode 100644 index 00000000000..5193f657055 --- /dev/null +++ b/substrate/frame/contracts/mock-network/src/tests.rs @@ -0,0 +1,239 @@ +// 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::{ + parachain::{self, Runtime}, + parachain_account_sovereign_account_id, + primitives::{AccountId, CENTS}, + relay_chain, MockNet, ParaA, ParachainBalances, Relay, ALICE, BOB, INITIAL_BALANCE, +}; +use assert_matches::assert_matches; +use codec::{Decode, Encode}; +use frame_support::{ + assert_err, + pallet_prelude::Weight, + traits::{fungibles::Mutate, Currency}, +}; +use pallet_balances::{BalanceLock, Reasons}; +use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; +use pallet_contracts_fixtures::compile_module; +use pallet_contracts_primitives::Code; +use xcm::{v3::prelude::*, VersionedMultiLocation, VersionedXcm}; +use xcm_simulator::TestExt; + +type ParachainContracts = pallet_contracts::Pallet; + +/// Instantiate the tests contract, and fund it with some balance and assets. +fn instantiate_test_contract(name: &str) -> AccountId { + let (wasm, _) = compile_module::(name).unwrap(); + + // Instantiate contract. + let contract_addr = ParaA::execute_with(|| { + ParachainContracts::bare_instantiate( + ALICE, + 0, + Weight::MAX, + None, + Code::Upload(wasm), + vec![], + vec![], + DebugInfo::UnsafeDebug, + CollectEvents::Skip, + ) + .result + .unwrap() + .account_id + }); + + // Funds contract account with some balance and assets. + ParaA::execute_with(|| { + parachain::Balances::make_free_balance_be(&contract_addr, INITIAL_BALANCE); + parachain::Assets::mint_into(0u32.into(), &contract_addr, INITIAL_BALANCE).unwrap(); + }); + Relay::execute_with(|| { + let sovereign_account = parachain_account_sovereign_account_id(1u32, contract_addr.clone()); + relay_chain::Balances::make_free_balance_be(&sovereign_account, INITIAL_BALANCE); + }); + + contract_addr +} + +#[test] +fn test_xcm_execute() { + MockNet::reset(); + + let contract_addr = instantiate_test_contract("xcm_execute"); + + // Execute XCM instructions through the contract. + ParaA::execute_with(|| { + let amount: u128 = 10 * CENTS; + + // The XCM used to transfer funds to Bob. + let message: xcm_simulator::Xcm<()> = Xcm(vec![ + WithdrawAsset(vec![(Here, amount).into()].into()), + DepositAsset { + assets: All.into(), + beneficiary: AccountId32 { network: None, id: BOB.clone().into() }.into(), + }, + ]); + + let result = ParachainContracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + Weight::MAX, + None, + VersionedXcm::V3(message).encode(), + DebugInfo::UnsafeDebug, + CollectEvents::UnsafeCollect, + Determinism::Enforced, + ) + .result + .unwrap(); + + let mut data = &result.data[..]; + let outcome = Outcome::decode(&mut data).expect("Failed to decode xcm_execute Outcome"); + assert_matches!(outcome, Outcome::Complete(_)); + + // Check if the funds are subtracted from the account of Alice and added to the account of + // Bob. + let initial = INITIAL_BALANCE; + assert_eq!(parachain::Assets::balance(0, contract_addr), initial); + assert_eq!(ParachainBalances::free_balance(BOB), initial + amount); + }); +} + +#[test] +fn test_xcm_execute_filtered_call() { + MockNet::reset(); + + let contract_addr = instantiate_test_contract("xcm_execute"); + + ParaA::execute_with(|| { + // `remark` should be rejected, as it is not allowed by our CallFilter. + let call = parachain::RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); + let message: Xcm = Xcm(vec![Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: Weight::MAX, + call: call.encode().into(), + }]); + + let result = ParachainContracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + Weight::MAX, + None, + VersionedXcm::V3(message).encode(), + DebugInfo::UnsafeDebug, + CollectEvents::UnsafeCollect, + Determinism::Enforced, + ); + + assert_err!(result.result, frame_system::Error::::CallFiltered); + }); +} + +#[test] +fn test_xcm_execute_reentrant_call() { + MockNet::reset(); + + let contract_addr = instantiate_test_contract("xcm_execute"); + + ParaA::execute_with(|| { + let transact_call = parachain::RuntimeCall::Contracts(pallet_contracts::Call::call { + dest: contract_addr.clone(), + gas_limit: 1_000_000.into(), + storage_deposit_limit: None, + data: vec![], + value: 0u128, + }); + + // The XCM used to transfer funds to Bob. + let message: Xcm = Xcm(vec![ + Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: 1_000_000_000.into(), + call: transact_call.encode().into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]); + + let result = ParachainContracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + Weight::MAX, + None, + VersionedXcm::V3(message).encode(), + DebugInfo::UnsafeDebug, + CollectEvents::UnsafeCollect, + Determinism::Enforced, + ) + .result + .unwrap(); + + let mut data = &result.data[..]; + let outcome = Outcome::decode(&mut data).expect("Failed to decode xcm_execute Outcome"); + assert_matches!(outcome, Outcome::Incomplete(_, XcmError::ExpectationFalse)); + + // Funds should not change hands as the XCM transact failed. + assert_eq!(ParachainBalances::free_balance(BOB), INITIAL_BALANCE); + }); +} + +#[test] +fn test_xcm_send() { + MockNet::reset(); + let contract_addr = instantiate_test_contract("xcm_send"); + let fee = parachain::estimate_message_fee(4); // Accounts for the `DescendOrigin` instruction added by `send_xcm` + + // Send XCM instructions through the contract, to lock some funds on the relay chain. + ParaA::execute_with(|| { + let dest = MultiLocation::from(Parent); + let dest = VersionedMultiLocation::V3(dest); + + let message: xcm_simulator::Xcm<()> = Xcm(vec![ + WithdrawAsset((Here, fee).into()), + BuyExecution { fees: (Here, fee).into(), weight_limit: WeightLimit::Unlimited }, + LockAsset { asset: (Here, 5 * CENTS).into(), unlocker: (Parachain(1)).into() }, + ]); + let message = VersionedXcm::V3(message); + let exec = ParachainContracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + Weight::MAX, + None, + (dest, message).encode(), + DebugInfo::UnsafeDebug, + CollectEvents::UnsafeCollect, + Determinism::Enforced, + ); + + let mut data = &exec.result.unwrap().data[..]; + XcmHash::decode(&mut data).expect("Failed to decode xcm_send message_id"); + }); + + Relay::execute_with(|| { + // Check if the funds are locked on the relay chain. + assert_eq!( + relay_chain::Balances::locks(¶chain_account_sovereign_account_id(1, contract_addr)), + vec![BalanceLock { id: *b"py/xcmlk", amount: 5 * CENTS, reasons: Reasons::All }] + ); + }); +} diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 7d516fbe249..188679dbf49 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -403,6 +403,14 @@ pub mod pallet { /// its type appears in the metadata. Only valid value is `()`. #[pallet::constant] type Environment: Get>; + + /// A type that exposes XCM APIs, allowing contracts to interact with other parachains, and + /// execute XCM programs. + type Xcm: xcm_builder::Controller< + OriginFor, + ::RuntimeCall, + BlockNumberFor, + >; } #[pallet::hooks] @@ -1004,6 +1012,8 @@ pub mod pallet { /// in this error. Note that this usually shouldn't happen as deploying such contracts /// is rejected. NoChainExtension, + /// Failed to decode the XCM program. + XCMDecodeFailed, /// A contract with the same AccountId already exists. DuplicateContract, /// A contract self destructed in its constructor. diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index e7784b02b74..76fd012852a 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -486,6 +486,7 @@ impl Config for Test { type MaxDelegateDependencies = MaxDelegateDependencies; type Debug = TestDebug; type Environment = (); + type Xcm = (); } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 4fd52b471a0..b3013adb790 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -23,10 +23,16 @@ use crate::{ schedule::HostFnWeights, BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL, }; - use bitflags::bitflags; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; -use frame_support::{ensure, traits::Get, weights::Weight}; +use frame_support::{ + dispatch::DispatchInfo, + ensure, + pallet_prelude::{DispatchResult, DispatchResultWithPostInfo}, + parameter_types, + traits::Get, + weights::Weight, +}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; @@ -36,6 +42,9 @@ use sp_runtime::{ }; use sp_std::{fmt, prelude::*}; use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store}; +use xcm::VersionedXcm; + +type CallOf = ::RuntimeCall; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; @@ -113,6 +122,17 @@ pub enum ReturnCode { EcdsaRecoverFailed = 11, /// sr25519 signature verification failed. Sr25519VerifyFailed = 12, + /// The `xcm_execute` call failed. + XcmExecutionFailed = 13, + /// The `xcm_send` call failed. + XcmSendFailed = 14, +} + +parameter_types! { + /// Getter types used by [`crate::api_doc::Current::call_runtime`] + const CallRuntimeFailed: ReturnCode = ReturnCode::CallRuntimeFailed; + /// Getter types used by [`crate::api_doc::Current::xcm_execute`] + const XcmExecutionFailed: ReturnCode = ReturnCode::XcmExecutionFailed; } impl From for ReturnCode { @@ -461,6 +481,29 @@ fn already_charged(_: u32) -> Option { None } +/// Ensure that the XCM program is executable, by checking that it does not contain any [`Transact`] +/// instruction with a call that is not allowed by the CallFilter. +fn ensure_executable(message: &VersionedXcm>) -> DispatchResult { + use frame_support::traits::Contains; + use xcm::prelude::{Transact, Xcm}; + + let mut message: Xcm> = + message.clone().try_into().map_err(|_| Error::::XCMDecodeFailed)?; + + message.iter_mut().try_for_each(|inst| -> DispatchResult { + let Transact { ref mut call, .. } = inst else { return Ok(()) }; + let call = call.ensure_decoded().map_err(|_| Error::::XCMDecodeFailed)?; + + if !::CallFilter::contains(call) { + return Err(frame_system::Error::::CallFiltered.into()) + } + + Ok(()) + })?; + + Ok(()) +} + /// Can only be used for one call. pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, @@ -558,6 +601,32 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { self.ext.gas_meter_mut().adjust_gas(charged, token); } + /// Charge, Run and adjust gas, for executing the given dispatchable. + fn call_dispatchable< + ErrorReturnCode: Get, + F: FnOnce(&mut Self) -> DispatchResultWithPostInfo, + >( + &mut self, + dispatch_info: DispatchInfo, + run: F, + ) -> Result { + use frame_support::dispatch::extract_actual_weight; + let charged = self.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; + let result = run(self); + let actual_weight = extract_actual_weight(&result, &dispatch_info); + self.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight)); + match result { + Ok(_) => Ok(ReturnCode::Success), + Err(e) => { + if self.ext.append_debug_buffer("") { + self.ext.append_debug_buffer("call failed with: "); + self.ext.append_debug_buffer(e.into()); + }; + Ok(ErrorReturnCode::get()) + }, + } + } + /// Read designated chunk from the sandbox memory. /// /// Returns `Err` if one of the following conditions occurs: @@ -633,8 +702,10 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { let ptr = ptr as usize; let mut bound_checked = memory.get(ptr..ptr + len as usize).ok_or_else(|| Error::::OutOfBounds)?; + let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; + Ok(decoded) } @@ -1023,6 +1094,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { // for every function. #[define_env(doc)] pub mod env { + /// Set the value at the given key in the contract storage. /// /// Equivalent to the newer [`seal1`][`super::api_doc::Version1::set_storage`] version with the @@ -2584,7 +2656,7 @@ pub mod env { /// # Return Value /// /// Returns `ReturnCode::Success` when the dispatchable was successfully executed and - /// returned `Ok`. When the dispatchable was exeuted but returned an error + /// returned `Ok`. When the dispatchable was executed but returned an error /// `ReturnCode::CallRuntimeFailed` is returned. The full error is not /// provided because it is not guaranteed to be stable. /// @@ -2605,23 +2677,118 @@ pub mod env { call_ptr: u32, call_len: u32, ) -> Result { - use frame_support::dispatch::{extract_actual_weight, GetDispatchInfo}; + use frame_support::dispatch::GetDispatchInfo; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::RuntimeCall = ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?; - let dispatch_info = call.get_dispatch_info(); - let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; - let result = ctx.ext.call_runtime(call); - let actual_weight = extract_actual_weight(&result, &dispatch_info); - ctx.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight)); - match result { - Ok(_) => Ok(ReturnCode::Success), + ctx.call_dispatchable::(call.get_dispatch_info(), |ctx| { + ctx.ext.call_runtime(call) + }) + } + + /// Execute an XCM program locally, using the contract's address as the origin. + /// This is equivalent to dispatching `pallet_xcm::execute` through call_runtime, except that + /// the function is called directly instead of being dispatched. + /// + /// # Parameters + /// + /// - `msg_ptr`: the pointer into the linear memory where the [`xcm::prelude::VersionedXcm`] is + /// placed. + /// - `msg_len`: the length of the message in bytes. + /// - `output_ptr`: the pointer into the linear memory where the [`xcm::prelude::Outcome`] + /// message id is placed. + /// + /// # Return Value + /// + /// Returns `ReturnCode::Success` when the XCM was successfully executed. When the XCM + /// execution fails, `ReturnCode::XcmExecutionFailed` is returned. + #[unstable] + fn xcm_execute( + ctx: _, + memory: _, + msg_ptr: u32, + msg_len: u32, + output_ptr: u32, + ) -> Result { + use frame_support::dispatch::DispatchInfo; + use xcm::VersionedXcm; + use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; + + ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; + let message: VersionedXcm> = + ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + + let execute_weight = + <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); + let weight = ctx.ext.gas_meter().gas_left().max(execute_weight); + let dispatch_info = DispatchInfo { weight, ..Default::default() }; + + ensure_executable::(&message)?; + ctx.call_dispatchable::(dispatch_info, |ctx| { + let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); + let outcome = <::Xcm>::execute( + origin, + Box::new(message), + weight.saturating_sub(execute_weight), + )?; + + ctx.write_sandbox_memory(memory, output_ptr, &outcome.encode())?; + let pre_dispatch_weight = + <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); + Ok(Some(outcome.weight_used().saturating_add(pre_dispatch_weight)).into()) + }) + } + + /// Send an XCM program from the contract to the specified destination. + /// This is equivalent to dispatching `pallet_xcm::send` through `call_runtime`, except that + /// the function is called directly instead of being dispatched. + /// + /// # Parameters + /// + /// - `dest_ptr`: the pointer into the linear memory where the + /// [`xcm::prelude::VersionedMultiLocation`] is placed. + /// - `msg_ptr`: the pointer into the linear memory where the [`xcm::prelude::VersionedXcm`] is + /// placed. + /// - `msg_len`: the length of the message in bytes. + /// - `output_ptr`: the pointer into the linear memory where the [`xcm::v3::XcmHash`] message id + /// is placed. + /// + /// # Return Value + /// + /// Returns `ReturnCode::Success` when the message was successfully sent. When the XCM + /// execution fails, `ReturnCode::CallRuntimeFailed` is returned. + #[unstable] + fn xcm_send( + ctx: _, + memory: _, + dest_ptr: u32, + msg_ptr: u32, + msg_len: u32, + output_ptr: u32, + ) -> Result { + use xcm::{VersionedMultiLocation, VersionedXcm}; + use xcm_builder::{SendController, SendControllerWeightInfo}; + + ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; + let dest: VersionedMultiLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?; + + let message: VersionedXcm<()> = + ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + let weight = <::Xcm as SendController<_>>::WeightInfo::send(); + ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?; + let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); + + match <::Xcm>::send(origin, dest.into(), message.into()) { + Ok(message_id) => { + ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?; + Ok(ReturnCode::Success) + }, Err(e) => { if ctx.ext.append_debug_buffer("") { - ctx.ext.append_debug_buffer("seal0::call_runtime failed with: "); + ctx.ext.append_debug_buffer("seal0::xcm_send failed with: "); ctx.ext.append_debug_buffer(e.into()); }; - Ok(ReturnCode::CallRuntimeFailed) + Ok(ReturnCode::XcmSendFailed) }, } } -- GitLab From f53604362c98d596d829f37dbdf87fecbd05b7a5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 15 Nov 2023 10:23:59 +0200 Subject: [PATCH 513/633] pallet-xcm: use XcmTeleportFilter for teleported fees in reserve transfers (#2322) Disallow reserve transfers that use teleportable fees if `(origin, fees)` matches `XcmTeleportFilter`. Add regression tests for filtering based on `XcmTeleportFilter` for both `(limited_)reserve_transfer_assets()` and `(limited_)teleport_assets` extrinsics. --- polkadot/xcm/pallet-xcm/src/lib.rs | 6 ++- polkadot/xcm/pallet-xcm/src/mock.rs | 29 +++++++++- .../pallet-xcm/src/tests/assets_transfer.rs | 54 +++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 8157620465f..38ea7555fc3 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1379,7 +1379,7 @@ impl Pallet { TransferType::DestinationReserve => Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?, TransferType::Teleport => - Self::teleport_fees_instructions(dest, fees, weight_limit)?, + Self::teleport_fees_instructions(origin_location, dest, fees, weight_limit)?, TransferType::RemoteReserve(_) => return Err(Error::::InvalidAssetUnsupportedReserve.into()), }); @@ -1715,10 +1715,14 @@ impl Pallet { } fn teleport_fees_instructions( + origin: MultiLocation, dest: MultiLocation, fees: MultiAsset, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, vec![fees.clone()]); + ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); + let context = T::UniversalLocation::get(); let reanchored_fees = fees .clone() diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 026838993f1..e744cefb162 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -18,7 +18,8 @@ use codec::Encode; use frame_support::{ construct_runtime, match_types, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, Equals, Everything, EverythingBut, Nothing, + AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Equals, Everything, EverythingBut, + Nothing, }, weights::Weight, }; @@ -341,6 +342,9 @@ pub const USDT_PARA_ID: u32 = 2003; // This child parachain is not configured as trusted reserve or teleport location for any assets. pub const OTHER_PARA_ID: u32 = 2009; +// This child parachain is used for filtered/disallowed assets. +pub const FILTERED_PARA_ID: u32 = 2010; + parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); pub const NativeAsset: MultiAsset = MultiAsset { @@ -384,6 +388,17 @@ parameter_types! { interior: X1(Parachain(USDT_PARA_ID)), }), }; + pub const FilteredTeleportLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(FILTERED_PARA_ID)) + }; + pub const FilteredTeleportAsset: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X1(Parachain(FILTERED_PARA_ID)), + }), + }; pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorMultiLocation = Here; pub UnitWeightCost: u64 = 1_000; @@ -430,6 +445,7 @@ parameter_types! { pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub TrustedSystemPara: (MultiAssetFilter, MultiLocation) = (NativeAsset::get().into(), SystemParachainLocation::get()); pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), UsdtTeleportLocation::get()); + pub TrustedFilteredTeleport: (MultiAssetFilter, MultiLocation) = (FilteredTeleportAsset::get().into(), FilteredTeleportLocation::get()); pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), ForeignReserveLocation::get()); pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (ForeignAsset::get().into(), ForeignReserveLocation::get()); pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (Usdc::get().into(), UsdcReserveLocation::get()); @@ -466,6 +482,7 @@ impl xcm_executor::Config for XcmConfig { Case, Case, Case, + Case, ); type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -496,6 +513,14 @@ parameter_types! { pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3; } +pub struct XcmTeleportFiltered; +impl Contains<(MultiLocation, Vec)> for XcmTeleportFiltered { + fn contains(t: &(MultiLocation, Vec)) -> bool { + let filtered = FilteredTeleportAsset::get(); + t.1.iter().any(|asset| asset == &filtered) + } +} + impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -503,7 +528,7 @@ impl pallet_xcm::Config for Test { type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; + type XcmTeleportFilter = EverythingBut; type XcmReserveTransferFilter = Everything; type Weigher = FixedWeightBounds; type UniversalLocation = UniversalLocation; diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index b02b0fd33c3..bf39e1ca288 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -117,6 +117,30 @@ fn limited_teleport_assets_works() { ); } +/// `limited_teleport_assets` should fail for filtered assets +#[test] +fn limited_teleport_filtered_assets_disallowed() { + let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| { + let result = XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(FilteredTeleportLocation::get().into()), + Box::new(beneficiary.into()), + Box::new(FilteredTeleportAsset::get().into()), + 0, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered") + })) + ); + }); +} + /// Test `reserve_transfer_assets_with_paid_router_works` /// /// Asserts that the sender's balance is decreased and the beneficiary's balance @@ -1403,3 +1427,33 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() { assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); }); } + +/// Test `reserve_transfer_assets` with teleportable fee that is filtered - should fail. +#[test] +fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() { + let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| { + let (assets, fee_index, _, _) = into_multiassets_checked( + // FilteredTeleportAsset for fees - teleportable but filtered + FilteredTeleportAsset::get().into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(FilteredTeleportLocation::get().into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered") + })) + ); + }); +} -- GitLab From 18165ebba88d41b4ba314685e5468ec0e809d799 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 15 Nov 2023 10:33:58 +0200 Subject: [PATCH 514/633] Unify `ChainSync` actions under one enum (follow-up) (#2317) Get rid of public `ChainSync::..._requests()` functions and return all requests as actions. --------- Co-authored-by: Sebastian Kunert --- .../client/network/sync/src/chain_sync.rs | 50 +++++++++++++---- substrate/client/network/sync/src/engine.rs | 55 +++++++++---------- substrate/client/network/sync/src/lib.rs | 2 +- .../client/network/sync/src/service/mod.rs | 4 +- .../{chain_sync.rs => syncing_service.rs} | 6 +- substrate/client/network/sync/src/warp.rs | 2 +- substrate/client/network/test/src/lib.rs | 2 +- 7 files changed, 74 insertions(+), 47 deletions(-) rename substrate/client/network/sync/src/service/{chain_sync.rs => syncing_service.rs} (98%) diff --git a/substrate/client/network/sync/src/chain_sync.rs b/substrate/client/network/sync/src/chain_sync.rs index 2adc6d42341..3825cfa33f7 100644 --- a/substrate/client/network/sync/src/chain_sync.rs +++ b/substrate/client/network/sync/src/chain_sync.rs @@ -191,6 +191,10 @@ pub enum ChainSyncAction { SendBlockRequest { peer_id: PeerId, request: BlockRequest }, /// Drop stale block request. CancelBlockRequest { peer_id: PeerId }, + /// Send state request to peer. + SendStateRequest { peer_id: PeerId, request: OpaqueStateRequest }, + /// Send warp proof request to peer. + SendWarpProofRequest { peer_id: PeerId, request: WarpProofRequest }, /// Peer misbehaved. Disconnect, report it and cancel the block request to it. DropPeer(BadPeer), /// Import blocks. @@ -1420,11 +1424,6 @@ where .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) } - /// Check if the peer is known to the sync state machine. Used for sanity checks. - 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> { self.blocks @@ -1537,7 +1536,7 @@ where } /// Get justification requests scheduled by sync to be sent out. - pub fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { + fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); std::iter::from_fn(move || { @@ -1564,7 +1563,7 @@ where } /// Get block requests scheduled by sync to be sent out. - pub fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { + fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { if self.mode == SyncMode::Warp { return self .warp_target_block_request() @@ -1691,7 +1690,7 @@ where } /// Get a state request scheduled by sync to be sent out (if any). - pub fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { if self.allowed_requests.is_empty() { return None } @@ -1737,7 +1736,7 @@ where } /// Get a warp proof request scheduled by sync to be sent out (if any). - pub fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { if let Some(sync) = &self.warp_sync { if self.allowed_requests.is_empty() || sync.is_complete() || @@ -2025,7 +2024,38 @@ where /// Get pending actions to perform. #[must_use] - pub fn take_actions(&mut self) -> impl Iterator> { + pub fn actions(&mut self) -> impl Iterator> { + let block_requests = self + .block_requests() + .into_iter() + .map(|(peer_id, request)| ChainSyncAction::SendBlockRequest { peer_id, request }); + self.actions.extend(block_requests); + + let justification_requests = self + .justification_requests() + .into_iter() + .map(|(peer_id, request)| ChainSyncAction::SendBlockRequest { peer_id, request }); + self.actions.extend(justification_requests); + + let state_request = self + .state_request() + .into_iter() + .map(|(peer_id, request)| ChainSyncAction::SendStateRequest { peer_id, request }); + self.actions.extend(state_request); + + let warp_proof_request = self + .warp_sync_request() + .into_iter() + .map(|(peer_id, request)| ChainSyncAction::SendWarpProofRequest { peer_id, request }); + self.actions.extend(warp_proof_request); + + std::mem::take(&mut self.actions).into_iter() + } + + /// A version of `actions()` that doesn't schedule extra requests. For testing only. + #[cfg(test)] + #[must_use] + fn take_actions(&mut self) -> impl Iterator> { std::mem::take(&mut self.actions).into_iter() } } diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 58a9fdc49f2..2cb8eab22f7 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -30,7 +30,7 @@ use crate::{ schema::v1::{StateRequest, StateResponse}, service::{ self, - chain_sync::{SyncingService, ToServiceCommand}, + syncing_service::{SyncingService, ToServiceCommand}, }, types::{ BadPeer, ExtendedPeerInfo, OpaqueStateRequest, OpaqueStateResponse, PeerRequest, SyncEvent, @@ -713,16 +713,13 @@ where self.is_major_syncing .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); - // Process actions requested by `ChainSync` during `select!`. + // Process actions requested by `ChainSync`. self.process_chain_sync_actions(); - - // Send outbound requests on `ChanSync`'s behalf. - self.send_chain_sync_requests(); } } fn process_chain_sync_actions(&mut self) { - self.chain_sync.take_actions().for_each(|action| match action { + self.chain_sync.actions().for_each(|action| match action { ChainSyncAction::SendBlockRequest { peer_id, request } => { // Sending block request implies dropping obsolete pending response as we are not // interested in it anymore (see [`ChainSyncAction::SendBlockRequest`]). @@ -741,7 +738,25 @@ where ChainSyncAction::CancelBlockRequest { peer_id } => { let removed = self.pending_responses.remove(&peer_id); - trace!(target: LOG_TARGET, "Processed {action:?}., response removed: {removed}."); + trace!(target: LOG_TARGET, "Processed {action:?}, response removed: {removed}."); + }, + ChainSyncAction::SendStateRequest { peer_id, request } => { + self.send_state_request(peer_id, request); + + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::SendBlockRequest` to {peer_id}.", + ); + }, + ChainSyncAction::SendWarpProofRequest { peer_id, request } => { + self.send_warp_proof_request(peer_id, request.clone()); + + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::SendWarpProofRequest` to {}, request: {:?}.", + peer_id, + request, + ); }, ChainSyncAction::DropPeer(BadPeer(peer_id, rep)) => { self.pending_responses.remove(&peer_id); @@ -1104,26 +1119,8 @@ 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) { + if !self.peers.contains_key(&peer_id) { trace!(target: LOG_TARGET, "Cannot send block request to unknown peer {peer_id}"); debug_assert!(false); return @@ -1139,7 +1136,7 @@ where } fn send_state_request(&mut self, peer_id: PeerId, request: OpaqueStateRequest) { - if !self.chain_sync.is_peer_known(&peer_id) { + if !self.peers.contains_key(&peer_id) { trace!(target: LOG_TARGET, "Cannot send state request to unknown peer {peer_id}"); debug_assert!(false); return @@ -1168,8 +1165,8 @@ where } } - fn send_warp_sync_request(&mut self, peer_id: PeerId, request: WarpProofRequest) { - if !self.chain_sync.is_peer_known(&peer_id) { + fn send_warp_proof_request(&mut self, peer_id: PeerId, request: WarpProofRequest) { + if !self.peers.contains_key(&peer_id) { trace!(target: LOG_TARGET, "Cannot send warp proof request to unknown peer {peer_id}"); debug_assert!(false); return diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index c42b0601e65..1a7e773c95f 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -18,7 +18,7 @@ //! Blockchain syncing implementation in Substrate. -pub use service::chain_sync::SyncingService; +pub use service::syncing_service::SyncingService; pub use types::{SyncEvent, SyncEventStream, SyncState, SyncStatus, SyncStatusProvider}; mod block_announce_validator; diff --git a/substrate/client/network/sync/src/service/mod.rs b/substrate/client/network/sync/src/service/mod.rs index 18331d63ed2..d045af26e70 100644 --- a/substrate/client/network/sync/src/service/mod.rs +++ b/substrate/client/network/sync/src/service/mod.rs @@ -16,8 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! `ChainSync`-related service code +//! `SyncingEngine`-related service code -pub mod chain_sync; pub mod mock; pub mod network; +pub mod syncing_service; diff --git a/substrate/client/network/sync/src/service/chain_sync.rs b/substrate/client/network/sync/src/service/syncing_service.rs similarity index 98% rename from substrate/client/network/sync/src/service/chain_sync.rs rename to substrate/client/network/sync/src/service/syncing_service.rs index 3d11880c511..92d649d65dc 100644 --- a/substrate/client/network/sync/src/service/chain_sync.rs +++ b/substrate/client/network/sync/src/service/syncing_service.rs @@ -34,7 +34,7 @@ use std::{ }, }; -/// Commands send to `ChainSync` +/// Commands send to `SyncingEngine` pub enum ToServiceCommand { SetSyncForkRequest(Vec, B::Hash, NumberFor), RequestJustification(B::Hash, NumberFor), @@ -63,7 +63,7 @@ pub enum ToServiceCommand { // }, } -/// Handle for communicating with `ChainSync` asynchronously +/// Handle for communicating with `SyncingEngine` asynchronously #[derive(Clone)] pub struct SyncingService { tx: TracingUnboundedSender>, @@ -148,7 +148,7 @@ impl SyncingService { /// Get sync status /// - /// Returns an error if `ChainSync` has terminated. + /// Returns an error if `SyncingEngine` has terminated. pub async fn status(&self) -> Result, ()> { let (tx, rx) = oneshot::channel(); let _ = self.tx.unbounded_send(ToServiceCommand::Status(tx)); diff --git a/substrate/client/network/sync/src/warp.rs b/substrate/client/network/sync/src/warp.rs index 2c0adc856c1..169b3de35aa 100644 --- a/substrate/client/network/sync/src/warp.rs +++ b/substrate/client/network/sync/src/warp.rs @@ -42,7 +42,7 @@ const LOG_TARGET: &'static str = "sync"; pub struct EncodedProof(pub Vec); /// Warp sync request -#[derive(Encode, Decode, Debug)] +#[derive(Encode, Decode, Debug, Clone)] pub struct WarpProofRequest { /// Start collecting proofs from this block. pub begin: B::Hash, diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index f869e3a171a..cfc3cb7af3f 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -64,7 +64,7 @@ use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, - service::{chain_sync::SyncingService, network::NetworkServiceProvider}, + service::{network::NetworkServiceProvider, syncing_service::SyncingService}, state_request_handler::StateRequestHandler, warp::{ AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, -- GitLab From 5b0622bc4d0cf5f0f57904874ea90eb08de79c52 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:28:32 +0100 Subject: [PATCH 515/633] [CI] Prepare CI for Merge Queues (#2308) PR prepares CI to the GitHub Merge Queues. All github actions that were running in PR adjusted so they can run in the merge queues. Zombienet jobs will do nothing during PRs but they will run during merge queues. Jobs that will be skipped during PR: - all zombienet jobs - all publish docker jobs Jobs that will be skipped during merge queue: - check-labels - check-prdoc - pr-custom-review - review trigger cc https://github.com/paritytech/ci_cd/issues/862 --- .github/workflows/check-labels.yml | 4 ++++ .github/workflows/check-licenses.yml | 1 + .github/workflows/check-links.yml | 1 + .github/workflows/check-markdown.yml | 5 +++-- .github/workflows/check-prdoc.yml | 4 ++++ .github/workflows/check-publish.yml | 1 + .github/workflows/fmt-check.yml | 1 + .github/workflows/gitspiegel-trigger.yml | 1 + .github/workflows/pr-custom-review.yml | 4 ++++ .github/workflows/review-trigger.yml | 6 +++++- .gitlab-ci.yml | 8 +++++++- .gitlab/pipeline/publish.yml | 4 ++-- .gitlab/pipeline/zombienet/cumulus.yml | 2 ++ .gitlab/pipeline/zombienet/polkadot.yml | 18 +++++++++++++----- .gitlab/pipeline/zombienet/substrate.yml | 2 ++ 15 files changed, 51 insertions(+), 11 deletions(-) diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 83b52e82313..97562f0da09 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -3,11 +3,15 @@ name: Check labels on: pull_request: types: [labeled, opened, synchronize, unlabeled] + merge_group: jobs: check-labels: runs-on: ubuntu-latest steps: + - name: Skip merge queue + if: ${{ contains(github.ref, 'gh-readonly-queue') }} + run: exit 0 - name: Pull image env: IMAGE: paritytech/ruled_labels:0.4.0 diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 50dd10a6d3c..a66e3a53998 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -2,6 +2,7 @@ name: Check licenses on: pull_request: + merge_group: permissions: packages: read diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 3ed6ba84b82..0932d38c9ad 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -8,6 +8,7 @@ on: - ".github/workflows/check-links.yml" - ".config/lychee.toml" types: [opened, synchronize, reopened, ready_for_review] + merge_group: permissions: packages: read diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index 05b5d898d67..2108f942090 100644 --- a/.github/workflows/check-markdown.yml +++ b/.github/workflows/check-markdown.yml @@ -3,6 +3,7 @@ name: Check Markdown on: pull_request: types: [opened, synchronize, reopened, ready_for_review] + merge_group: permissions: packages: read @@ -23,8 +24,8 @@ jobs: - name: Install tooling run: | - npm install -g markdownlint-cli - markdownlint --version + npm install -g markdownlint-cli + markdownlint --version - name: Check Markdown env: diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index 690f7a3f133..54e4d2b9680 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -3,6 +3,7 @@ name: Check PRdoc on: pull_request: types: [labeled, opened, synchronize, unlabeled] + merge_group: env: IMAGE: paritytech/prdoc:v0.0.5 @@ -17,6 +18,9 @@ jobs: check-prdoc: runs-on: ubuntu-latest steps: + - name: Skip merge queue + if: ${{ contains(github.ref, 'gh-readonly-queue') }} + run: exit 0 - name: Pull image run: | echo "Pulling $IMAGE" diff --git a/.github/workflows/check-publish.yml b/.github/workflows/check-publish.yml index 9ab47dba51b..c0d2b889381 100644 --- a/.github/workflows/check-publish.yml +++ b/.github/workflows/check-publish.yml @@ -6,6 +6,7 @@ on: - master pull_request: types: [opened, synchronize, reopened, ready_for_review] + merge_group: jobs: check-publish: diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index 7ca4413bb05..e4d39acabfd 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -6,6 +6,7 @@ on: - master pull_request: types: [opened, synchronize, reopened, ready_for_review] + merge_group: jobs: quick_check: diff --git a/.github/workflows/gitspiegel-trigger.yml b/.github/workflows/gitspiegel-trigger.yml index dce3aaf2fec..59347fad6d6 100644 --- a/.github/workflows/gitspiegel-trigger.yml +++ b/.github/workflows/gitspiegel-trigger.yml @@ -13,6 +13,7 @@ on: - unlocked - ready_for_review - reopened + merge_group: jobs: sync: diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml index b15d20c696f..4e0809cbfdc 100644 --- a/.github/workflows/pr-custom-review.yml +++ b/.github/workflows/pr-custom-review.yml @@ -14,11 +14,15 @@ on: - ready_for_review - converted_to_draft pull_request_review: + merge_group: jobs: pr-custom-review: runs-on: ubuntu-latest steps: + - name: Skip merge queue + if: ${{ contains(github.ref, 'gh-readonly-queue') }} + run: exit 0 - 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 diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml index 2810ea356e6..e5fcb434fd3 100644 --- a/.github/workflows/review-trigger.yml +++ b/.github/workflows/review-trigger.yml @@ -1,6 +1,6 @@ name: Review-Trigger -on: +on: pull_request_target: types: - opened @@ -10,6 +10,7 @@ on: - review_request_removed - ready_for_review pull_request_review: + merge_group: jobs: trigger-review-bot: @@ -18,6 +19,9 @@ jobs: runs-on: ubuntu-latest name: trigger review bot steps: + - name: Skip merge queue + if: ${{ contains(github.ref, 'gh-readonly-queue') }} + run: exit 0 - name: Get PR number env: PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f507afda23e..1dc483004f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,7 +31,7 @@ variables: NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.79" - DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" + DOCKER_IMAGES_VERSION: "${CI_COMMIT_SHA}" default: retry: @@ -136,11 +136,13 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 .test-pr-refs: rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues # handle the specific case where benches could store incorrect bench data because of the downstream staging runs # exclude cargo-check-benches from such runs @@ -152,6 +154,7 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 .test-refs-no-trigger: @@ -162,6 +165,7 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ @@ -172,6 +176,7 @@ default: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues .publish-refs: rules: @@ -192,6 +197,7 @@ default: - 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 + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues .zombienet-refs: extends: .build-refs diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index a03d407c040..f2308c334e0 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -71,8 +71,8 @@ publish-rustdoc: DOCKERFILE: "" # docker/path-to.Dockerfile IMAGE_NAME: "" # docker.io/paritypr/image_name script: - # - test "$PARITYPR_USER" -a "$PARITYPR_PASS" || - # ( echo "no docker credentials provided"; exit 1 ) + # Exit if the job is not running in a merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - $BUILDAH_COMMAND build --format=docker --build-arg VCS_REF="${CI_COMMIT_SHA}" diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 3f2c6f64fbf..c8a1df004e3 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -3,6 +3,8 @@ .zombienet-before-script: before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - echo "Zombie-net Tests Config" - echo "${ZOMBIENET_IMAGE}" - echo "${POLKADOT_IMAGE}" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 8fc8b280bba..cc960557298 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -4,6 +4,8 @@ # common settings for all zombienet jobs .zombienet-polkadot-common: before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" # from build-linux-stable job - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} @@ -12,12 +14,12 @@ - export MALUS_IMAGE="${MALUS_IMAGE}":${PIPELINE_IMAGE_TAG} - IMAGE_AVAILABLE=$(curl -o /dev/null -w "%{http_code}" -I -L -s https://registry.hub.docker.com/v2/repositories/parity/polkadot/tags/${BUILD_RELEASE_VERSION}) - if [ $IMAGE_AVAILABLE -eq 200 ]; then - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}"; + export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}"; else - echo "Getting the image to use as SECONDARY, using ${BUILD_RELEASE_VERSION} as base"; - VERSIONS=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/parity/polkadot/tags/' | jq -r '.results[].name'| grep -E "v[0-9]" |grep -vE "[0-9]-"); - VERSION_TO_USE=$(echo "${BUILD_RELEASE_VERSION}\n$VERSIONS"|sort -r|grep -A1 "${BUILD_RELEASE_VERSION}"|tail -1); - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${VERSION_TO_USE}"; + echo "Getting the image to use as SECONDARY, using ${BUILD_RELEASE_VERSION} as base"; + VERSIONS=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/parity/polkadot/tags/' | jq -r '.results[].name'| grep -E "v[0-9]" |grep -vE "[0-9]-"); + VERSION_TO_USE=$(echo "${BUILD_RELEASE_VERSION}\n$VERSIONS"|sort -r|grep -A1 "${BUILD_RELEASE_VERSION}"|tail -1); + export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${VERSION_TO_USE}"; fi - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" @@ -117,6 +119,8 @@ zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - echo "Zombienet Tests Config" @@ -134,6 +138,8 @@ zombienet-polkadot-smoke-0002-parachains-parachains-upgrade-smoke: extends: - .zombienet-polkadot-common before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" - echo "Zombienet Tests Config" @@ -176,6 +182,8 @@ zombienet-polkadot-misc-0002-upgrade-node: - job: build-linux-stable artifacts: true before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="docker.io/parity/polkadot:latest" - echo "Overrided poladot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 9e14ebe0852..e627575a31a 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -4,6 +4,8 @@ # common settings for all zombienet jobs .zombienet-substrate-common: before_script: + # Exit if the job is not merge queue + - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - echo "Zombienet Tests Config" - echo "${ZOMBIENET_IMAGE}" - echo "${GH_DIR}" -- GitLab From c79b234b3bb9d02ee5145c8d65a497104b5d3ea7 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:22:28 +0100 Subject: [PATCH 516/633] Identity Deposits Relay to Parachain Migration (#1814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal of this PR is to migrate Identity deposits from the Relay Chain to a system parachain. The problem I want to solve is that `IdentityOf` and `SubsOf` both store an amount that's held in reserve as a storage deposit. When migrating to a parachain, we can take a snapshot of the actual `IdentityInfo` and sub-account mappings, but should migrate (off chain) the `deposit`s to zero, since the chain (and by extension, accounts) won't have any funds at genesis. The good news is that we expect parachain deposits to be significantly lower (possibly 100x) on the parachain. That is, a deposit of 21 DOT on the Relay Chain would need 0.21 DOT on a parachain. This PR proposes to migrate the deposits in the following way: 1. Introduces a new pallet with two extrinsics: - `reap_identity`: Has a configurable `ReapOrigin`, which would be set to `EnsureSigned` on the Relay Chain (i.e. callable by anyone) and `EnsureRoot` on the parachain (we don't want identities reaped from there). - `poke_deposit`: Checks what deposit the pallet holds (at genesis, zero) and attempts to update the amount based on the calculated deposit for storage data. 2. `reap_identity` clears all storage data for a `target` account and unreserves their deposit. 3. A `ReapIdentityHandler` teleports the necessary DOT to the parachain and calls `poke_deposit`. Since the parachain deposit is much lower, and was just unreserved, we know we have enough. One awkwardness I ran into was that the XCMv3 instruction set does not provide a way for the system to teleport assets without a fee being deducted on reception. Users shouldn't have to pay a fee for the system to migrate their info to a more efficient location. So I wrote my own program and did the `InitiateTeleport` accounting on my own to send a program with `UnpaidExecution`. Have discussed an `InitiateUnpaidTeleport` instruction with @franciscoaguirre . Obviously any chain executing this would have to pass a `Barrier` for free execution. TODO: - [x] Confirm People Chain ParaId - [x] Confirm People Chain deposit rates (determined in https://github.com/paritytech/polkadot-sdk/pull/2281) - [x] Add pallet to Westend --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + polkadot/runtime/common/Cargo.toml | 4 + .../runtime/common/src/identity_migrator.rs | 305 ++++++++++++++++++ .../runtime/common/src/integration_tests.rs | 29 +- polkadot/runtime/common/src/lib.rs | 1 + polkadot/runtime/rococo/src/impls.rs | 158 +++++++++ polkadot/runtime/rococo/src/lib.rs | 39 ++- polkadot/runtime/rococo/src/weights/mod.rs | 1 + .../runtime_common_identity_migrator.rs | 97 ++++++ polkadot/runtime/westend/src/impls.rs | 158 +++++++++ polkadot/runtime/westend/src/lib.rs | 33 +- polkadot/runtime/westend/src/weights/mod.rs | 1 + .../runtime_common_identity_migrator.rs | 97 ++++++ substrate/frame/identity/src/lib.rs | 133 +++++++- substrate/frame/identity/src/tests.rs | 67 ++++ 15 files changed, 1111 insertions(+), 13 deletions(-) create mode 100644 polkadot/runtime/common/src/identity_migrator.rs create mode 100644 polkadot/runtime/rococo/src/impls.rs create mode 100644 polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs create mode 100644 polkadot/runtime/westend/src/impls.rs create mode 100644 polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs diff --git a/Cargo.lock b/Cargo.lock index 9ae1bb905b2..b1a46a88f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13047,6 +13047,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-multi-phase", "pallet-fast-unstake", + "pallet-identity", "pallet-session", "pallet-staking", "pallet-staking-reward-fn", diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 0882e555aaf..4391b6d81eb 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -30,6 +30,7 @@ sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", def pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } +pallet-identity = { path = "../../../substrate/frame/identity", 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 } @@ -85,6 +86,7 @@ std = [ "pallet-balances/std", "pallet-election-provider-multi-phase/std", "pallet-fast-unstake/std", + "pallet-identity/std", "pallet-session/std", "pallet-staking-reward-fn/std", "pallet-staking/std", @@ -124,6 +126,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", @@ -147,6 +150,7 @@ try-runtime = [ "pallet-balances/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-fast-unstake/try-runtime", + "pallet-identity/try-runtime", "pallet-session/try-runtime", "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", diff --git a/polkadot/runtime/common/src/identity_migrator.rs b/polkadot/runtime/common/src/identity_migrator.rs new file mode 100644 index 00000000000..cc2c3ce7773 --- /dev/null +++ b/polkadot/runtime/common/src/identity_migrator.rs @@ -0,0 +1,305 @@ +// 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 designed to go into a source chain and destination chain to migrate data. The +//! design motivations are: +//! +//! - Call some function on the source chain that executes some migration (clearing state, +//! forwarding an XCM program). +//! - Call some function (probably from an XCM program) on the destination chain. +//! - Avoid cluttering the source pallet with new dispatchables that are unrelated to its +//! functionality and only used for migration. +//! +//! After the migration is complete, the pallet may be removed from both chains' runtimes as well as +//! the `polkadot-runtime-common` crate. + +use frame_support::{dispatch::DispatchResult, traits::Currency, weights::Weight}; +pub use pallet::*; +use pallet_identity; +use sp_core::Get; + +#[cfg(feature = "runtime-benchmarks")] +use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; + +pub trait WeightInfo { + fn reap_identity(r: u32, s: u32) -> Weight; + fn poke_deposit() -> Weight; +} + +impl WeightInfo for () { + fn reap_identity(_r: u32, _s: u32) -> Weight { + Weight::MAX + } + fn poke_deposit() -> Weight { + Weight::MAX + } +} + +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn reap_identity(_r: u32, _s: u32) -> Weight { + Weight::zero() + } + fn poke_deposit() -> Weight { + Weight::zero() + } +} + +// Must use the same `Balance` as `T`'s Identity pallet to handle deposits. +type BalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{ + dispatch::{DispatchResultWithPostInfo, PostDispatchInfo}, + pallet_prelude::*, + traits::EnsureOrigin, + }; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_identity::Config { + /// Overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The origin that can reap identities. Expected to be `EnsureSigned` on the + /// source chain such that anyone can all this function. + type Reaper: EnsureOrigin; + + /// A handler for what to do when an identity is reaped. + type ReapIdentityHandler: OnReapIdentity; + + /// Weight information for the extrinsics in the pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// The identity and all sub accounts were reaped for `who`. + IdentityReaped { who: T::AccountId }, + /// The deposits held for `who` were updated. `identity` is the new deposit held for + /// identity info, and `subs` is the new deposit held for the sub-accounts. + DepositUpdated { who: T::AccountId, identity: BalanceOf, subs: BalanceOf }, + } + + #[pallet::call] + impl Pallet { + /// Reap the `IdentityInfo` of `who` from the Identity pallet of `T`, unreserving any + /// deposits held and removing storage items associated with `who`. + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::reap_identity( + T::MaxRegistrars::get(), + T::MaxSubAccounts::get() + ))] + pub fn reap_identity( + origin: OriginFor, + who: T::AccountId, + ) -> DispatchResultWithPostInfo { + T::Reaper::ensure_origin(origin)?; + // - number of registrars (required to calculate weight) + // - byte size of `IdentityInfo` (required to calculate remote deposit) + // - number of sub accounts (required to calculate both weight and remote deposit) + let (registrars, bytes, subs) = pallet_identity::Pallet::::reap_identity(&who)?; + T::ReapIdentityHandler::on_reap_identity(&who, bytes, subs)?; + Self::deposit_event(Event::IdentityReaped { who }); + let post = PostDispatchInfo { + actual_weight: Some(::WeightInfo::reap_identity( + registrars, subs, + )), + pays_fee: Pays::No, + }; + Ok(post) + } + + /// Update the deposit of `who`. Meant to be called by the system with an XCM `Transact` + /// Instruction. + #[pallet::call_index(1)] + #[pallet::weight(::WeightInfo::poke_deposit())] + pub fn poke_deposit(origin: OriginFor, who: T::AccountId) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let (id_deposit, subs_deposit) = pallet_identity::Pallet::::poke_deposit(&who)?; + Self::deposit_event(Event::DepositUpdated { + who, + identity: id_deposit, + subs: subs_deposit, + }); + Ok(Pays::No.into()) + } + } +} + +/// Trait to handle reaping identity from state. +pub trait OnReapIdentity { + /// What to do when an identity is reaped. For example, the implementation could send an XCM + /// program to another chain. Concretely, a type implementing this trait in the Polkadot + /// runtime would teleport enough DOT to the People Chain to cover the Identity deposit there. + /// + /// This could also directly include `Transact { poke_deposit(..), ..}`. + /// + /// Inputs + /// - `who`: Whose identity was reaped. + /// - `bytes`: The byte size of `IdentityInfo`. + /// - `subs`: The number of sub-accounts they had. + fn on_reap_identity(who: &AccountId, bytes: u32, subs: u32) -> DispatchResult; +} + +impl OnReapIdentity for () { + fn on_reap_identity(_who: &AccountId, _bytes: u32, _subs: u32) -> DispatchResult { + Ok(()) + } +} + +#[cfg(feature = "runtime-benchmarks")] +#[benchmarks] +mod benchmarks { + use super::*; + use frame_support::traits::EnsureOrigin; + use frame_system::RawOrigin; + use pallet_identity::{Data, IdentityInformationProvider, Judgement, Pallet as Identity}; + use parity_scale_codec::Encode; + use sp_runtime::{ + traits::{Bounded, Hash, StaticLookup}, + Saturating, + }; + use sp_std::{boxed::Box, vec::Vec, *}; + + const SEED: u32 = 0; + + fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); + } + + #[benchmark] + fn reap_identity( + r: Linear<0, { T::MaxRegistrars::get() }>, + s: Linear<0, { T::MaxSubAccounts::get() }>, + ) -> Result<(), BenchmarkError> { + // set up target + let target: T::AccountId = account("target", 0, SEED); + let target_origin = + ::RuntimeOrigin::from(RawOrigin::Signed(target.clone())); + let target_lookup = T::Lookup::unlookup(target.clone()); + let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); + + // set identity + let info = ::IdentityInformation::create_identity_info(); + Identity::::set_identity( + RawOrigin::Signed(target.clone()).into(), + Box::new(info.clone()), + )?; + + // create and set subs + let mut subs = Vec::new(); + let data = Data::Raw(vec![0; 32].try_into().unwrap()); + for ii in 0..s { + let sub_account = account("sub", ii, SEED); + subs.push((sub_account, data.clone())); + } + Identity::::set_subs(target_origin.clone(), subs.clone())?; + + // add registrars and provide judgements + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); + for ii in 0..r { + // registrar account + let registrar: T::AccountId = account("registrar", ii, SEED); + let registrar_lookup = T::Lookup::unlookup(registrar.clone()); + let _ = ::Currency::make_free_balance_be( + ®istrar, + ::Currency::minimum_balance(), + ); + + // add registrar + Identity::::add_registrar(registrar_origin.clone(), registrar_lookup)?; + Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), ii, 10u32.into())?; + let fields = ::IdentityInformation::all_fields(); + Identity::::set_fields(RawOrigin::Signed(registrar.clone()).into(), ii, fields)?; + + // request and provide judgement + Identity::::request_judgement(target_origin.clone(), ii, 10u32.into())?; + Identity::::provide_judgement( + RawOrigin::Signed(registrar).into(), + ii, + target_lookup.clone(), + Judgement::Reasonable, + ::Hashing::hash_of(&info), + )?; + } + + let origin = T::Reaper::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, target.clone()); + + assert_last_event::(Event::::IdentityReaped { who: target.clone() }.into()); + + let fields = ::IdentityInformation::all_fields(); + assert!(!Identity::::has_identity(&target, fields)); + assert_eq!(Identity::::subs(&target).len(), 0); + + Ok(()) + } + + #[benchmark] + fn poke_deposit() -> Result<(), BenchmarkError> { + let target: T::AccountId = account("target", 0, SEED); + let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); + let info = ::IdentityInformation::create_identity_info(); + + let _ = Identity::::set_identity_no_deposit(&target, info.clone()); + + let sub_account: T::AccountId = account("sub", 0, SEED); + let _ = Identity::::set_sub_no_deposit(&target, sub_account.clone()); + + // expected deposits + let expected_id_deposit = ::BasicDeposit::get() + .saturating_add( + ::ByteDeposit::get() + .saturating_mul(>::from(info.encoded_size() as u32)), + ); + // only 1 sub + let expected_sub_deposit = ::SubAccountDeposit::get(); + + #[extrinsic_call] + _(RawOrigin::Root, target.clone()); + + assert_last_event::( + Event::::DepositUpdated { + who: target, + identity: expected_id_deposit, + subs: expected_sub_deposit, + } + .into(), + ); + + Ok(()) + } + + impl_benchmark_test_suite!( + Pallet, + crate::integration_tests::new_test_ext(), + crate::integration_tests::Test, + ); +} diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index d5a32775fd4..793f75e79cd 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -17,7 +17,7 @@ //! Mocking utilities for testing with real pallets. use crate::{ - auctions, crowdloan, + auctions, crowdloan, identity_migrator, mock::{conclude_pvf_checking, validators_public_keys}, paras_registrar, slot_range::SlotRange, @@ -32,6 +32,7 @@ use frame_support::{ }; use frame_support_test::TestRandomness; use frame_system::EnsureRoot; +use pallet_identity::{self, legacy::IdentityInfo}; use parity_scale_codec::Encode; use primitives::{ BlockNumber, HeadData, Id as ParaId, SessionIndex, ValidationCode, LOWEST_PUBLIC_ID, @@ -88,6 +89,10 @@ frame_support::construct_runtime!( Auctions: auctions::{Pallet, Call, Storage, Event}, Crowdloan: crowdloan::{Pallet, Call, Storage, Event}, Slots: slots::{Pallet, Call, Storage, Event}, + + // Migrators + Identity: pallet_identity::{Pallet, Call, Storage, Event}, + IdentityMigrator: identity_migrator::{Pallet, Call, Event}, } ); @@ -274,6 +279,28 @@ impl crowdloan::Config for Test { type WeightInfo = crate::crowdloan::TestWeightInfo; } +impl pallet_identity::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Slashed = (); + type BasicDeposit = ConstU32<100>; + type ByteDeposit = ConstU32<10>; + type SubAccountDeposit = ConstU32<100>; + type MaxSubAccounts = ConstU32<2>; + type IdentityInformation = IdentityInfo>; + type MaxRegistrars = ConstU32<20>; + type RegistrarOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; + type WeightInfo = (); +} + +impl identity_migrator::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Reaper = EnsureRoot; + type ReapIdentityHandler = (); + type WeightInfo = crate::identity_migrator::TestWeightInfo; +} + /// Create a new set of test externalities. pub fn new_test_ext() -> TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 70722d50988..bd49d3cccc9 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/src/lib.rs @@ -23,6 +23,7 @@ pub mod auctions; pub mod claims; pub mod crowdloan; pub mod elections; +pub mod identity_migrator; pub mod impls; pub mod paras_registrar; pub mod paras_sudo_wrapper; diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs new file mode 100644 index 00000000000..71b1091eeb6 --- /dev/null +++ b/polkadot/runtime/rococo/src/impls.rs @@ -0,0 +1,158 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::xcm_config; +use frame_support::pallet_prelude::DispatchResult; +use frame_system::RawOrigin; +use parity_scale_codec::{Decode, Encode}; +use primitives::Balance; +use rococo_runtime_constants::currency::*; +use runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; +use sp_std::{marker::PhantomData, prelude::*}; +use xcm::{latest::prelude::*, VersionedMultiLocation, VersionedXcm}; +use xcm_executor::traits::TransactAsset; + +/// A type containing the encoding of the People Chain pallets in its runtime. Used to construct any +/// remote calls. The codec index must correspond to the index of `IdentityMigrator` in the +/// `construct_runtime` of the remote chain. +#[derive(Encode, Decode)] +enum PeopleRuntimePallets { + #[codec(index = 248)] + IdentityMigrator(IdentityMigratorCalls), +} + +/// Call encoding for the calls needed from the Identity Migrator pallet. +#[derive(Encode, Decode)] +enum IdentityMigratorCalls { + #[codec(index = 1)] + PokeDeposit(AccountId), +} + +/// Type that implements `OnReapIdentity` that will send the deposit needed to store the same +/// information on a parachain, sends the deposit there, and then updates it. +pub struct ToParachainIdentityReaper(PhantomData<(Runtime, AccountId)>); +impl ToParachainIdentityReaper { + /// Calculate the balance needed on the remote chain based on the `IdentityInfo` and `Subs` on + /// this chain. The total includes: + /// + /// - Identity basic deposit + /// - `IdentityInfo` byte deposit + /// - Sub accounts deposit + /// - 2x existential deposit (1 for account existence, 1 such that the user can transact) + fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance { + // Remote deposit constants. Parachain uses `deposit / 100` + // Source: + // https://github.com/paritytech/polkadot-sdk/blob/a146918/cumulus/parachains/common/src/rococo.rs#L29 + // + // Parachain Deposit Configuration: + // + // pub const BasicDeposit: Balance = deposit(1, 17); + // pub const ByteDeposit: Balance = deposit(0, 1); + // pub const SubAccountDeposit: Balance = deposit(1, 53); + // pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; + let para_basic_deposit = deposit(1, 17) / 100; + let para_byte_deposit = deposit(0, 1) / 100; + let para_sub_account_deposit = deposit(1, 53) / 100; + let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10; + + // pallet deposits + let id_deposit = + para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance)); + let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance); + + id_deposit + .saturating_add(subs_deposit) + .saturating_add(para_existential_deposit.saturating_mul(2)) + } +} + +impl OnReapIdentity for ToParachainIdentityReaper +where + Runtime: frame_system::Config + pallet_xcm::Config, + AccountId: Into<[u8; 32]> + Clone + Encode, +{ + fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { + use crate::{ + impls::IdentityMigratorCalls::PokeDeposit, + weights::runtime_common_identity_migrator::WeightInfo as MigratorWeights, + }; + + let total_to_send = Self::calculate_remote_deposit(fields, subs); + + // define asset / destination from relay perspective + let roc = MultiAsset { id: Concrete(Here.into_location()), fun: Fungible(total_to_send) }; + // People Chain: ParaId 1004 + let destination: MultiLocation = MultiLocation::new(0, Parachain(1004)); + + // Do `check_out` accounting since the XCM Executor's `InitiateTeleport` doesn't support + // unpaid teleports. + + // check out + xcm_config::LocalAssetTransactor::can_check_out( + &destination, + &roc, + // not used in AssetTransactor + &XcmContext { origin: None, message_id: [0; 32], topic: None }, + ) + .map_err(|_| pallet_xcm::Error::::CannotCheckOutTeleport)?; + xcm_config::LocalAssetTransactor::check_out( + &destination, + &roc, + // not used in AssetTransactor + &XcmContext { origin: None, message_id: [0; 32], topic: None }, + ); + + // reanchor + let roc_reanchored: MultiAssets = vec![MultiAsset { + id: Concrete(MultiLocation::new(1, Here)), + fun: Fungible(total_to_send), + }] + .into(); + + let poke = PeopleRuntimePallets::::IdentityMigrator(PokeDeposit(who.clone())); + let remote_weight_limit = MigratorWeights::::poke_deposit().saturating_mul(2); + + // Actual program to execute on People Chain. + let program: Xcm<()> = Xcm(vec![ + // Unpaid as this is constructed by the system, once per user. The user shouldn't have + // their balance reduced by teleport fees for the favor of migrating. + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + // Receive the asset into holding. + ReceiveTeleportedAsset(roc_reanchored), + // Deposit into the user's account. + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: Junction::AccountId32 { network: None, id: who.clone().into() } + .into_location() + .into(), + }, + // Poke the deposit to reserve the appropriate amount on the parachain. + Transact { + origin_kind: OriginKind::Superuser, + require_weight_at_most: remote_weight_limit, + call: poke.encode().into(), + }, + ]); + + // send + let _ = >::send( + RawOrigin::Root.into(), + Box::new(VersionedMultiLocation::V3(destination)), + Box::new(VersionedXcm::V3(program)), + )?; + Ok(()) + } +} diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5a1e170862e..277c9981dab 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -31,7 +31,7 @@ use primitives::{ ValidatorIndex, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ - assigned_slots, auctions, claims, crowdloan, impl_runtime_weights, + assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights, impls::{ LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter, }, @@ -68,9 +68,9 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, EitherOf, EitherOfDiverse, Everything, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, + ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -114,6 +114,10 @@ mod weights; // XCM configurations. pub mod xcm_config; +// Implemented types. +mod impls; +use impls::ToParachainIdentityReaper; + // Governance and configurations. pub mod governance; use governance::{ @@ -166,13 +170,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 IsIdentityCall; +impl Contains for IsIdentityCall { + 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 = Everything; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type DbWeight = RocksDbWeight; @@ -1079,6 +1094,14 @@ impl auctions::Config for Runtime { type WeightInfo = weights::runtime_common_auctions::WeightInfo; } +impl identity_migrator::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // To be changed to `EnsureSigned` once there is a People Chain to migrate to. + type Reaper = EnsureRoot; + type ReapIdentityHandler = ToParachainIdentityReaper; + type WeightInfo = weights::runtime_common_identity_migrator::WeightInfo; +} + type NisCounterpartInstance = pallet_balances::Instance2; impl pallet_balances::Config for Runtime { type Balance = Balance; @@ -1340,7 +1363,7 @@ construct_runtime! { // NIS pallet. Nis: pallet_nis::{Pallet, Call, Storage, Event, HoldReason} = 38, -// pub type NisCounterpartInstance = pallet_balances::Instance2; + // pub type NisCounterpartInstance = pallet_balances::Instance2; NisCounterpartBalances: pallet_balances:: = 45, // Parachains pallets. Start indices at 50 to leave room. @@ -1371,6 +1394,9 @@ construct_runtime! { // Pallet for sending XCM. XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, + // Pallet for migrating Identity to a parachain. To be removed post-migration. + IdentityMigrator: identity_migrator::{Pallet, Call, Event} = 248, + ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 250, AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 251, @@ -1551,6 +1577,7 @@ mod benches { [runtime_common::auctions, Auctions] [runtime_common::crowdloan, Crowdloan] [runtime_common::claims, Claims] + [runtime_common::identity_migrator, IdentityMigrator] [runtime_common::slots, Slots] [runtime_common::paras_registrar, Registrar] [runtime_parachains::configuration, Configuration] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 9c563a67d98..bd2079ce827 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -46,6 +46,7 @@ pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; pub mod runtime_common_claims; pub mod runtime_common_crowdloan; +pub mod runtime_common_identity_migrator; pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; pub mod runtime_parachains_assigner_on_demand; diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs b/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs new file mode 100644 index 00000000000..cec357453b6 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs @@ -0,0 +1,97 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `runtime_common::identity_migrator` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `sbtb`, CPU: `13th Gen Intel(R) Core(TM) i7-1365U` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=2 +// --repeat=1 +// --pallet=runtime_common::identity_migrator +// --extrinsic=* +// --output=./migrator-release.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::identity_migrator`. +pub struct WeightInfo(PhantomData); +impl runtime_common::identity_migrator::WeightInfo for WeightInfo { + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// 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`) + /// 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 `[0, 20]`. + /// The range of component `s` is `[0, 100]`. + fn reap_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7292 + r * (8 ±0) + s * (32 ±0)` + // Estimated: `11003 + r * (8 ±0) + s * (33 ±0)` + // Minimum execution time: 163_756_000 picoseconds. + Weight::from_parts(158_982_500, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 1_143_629 + .saturating_add(Weight::from_parts(238_675, 0).saturating_mul(r.into())) + // Standard Error: 228_725 + .saturating_add(Weight::from_parts(1_529_645, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(s.into())) + } + /// 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::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + fn poke_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `7229` + // Estimated: `11003` + // Minimum execution time: 137_570_000 picoseconds. + Weight::from_parts(137_570_000, 0) + .saturating_add(Weight::from_parts(0, 11003)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs new file mode 100644 index 00000000000..80105594965 --- /dev/null +++ b/polkadot/runtime/westend/src/impls.rs @@ -0,0 +1,158 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::xcm_config; +use frame_support::pallet_prelude::DispatchResult; +use frame_system::RawOrigin; +use parity_scale_codec::{Decode, Encode}; +use primitives::Balance; +use runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; +use sp_std::{marker::PhantomData, prelude::*}; +use westend_runtime_constants::currency::*; +use xcm::{latest::prelude::*, VersionedMultiLocation, VersionedXcm}; +use xcm_executor::traits::TransactAsset; + +/// A type containing the encoding of the People Chain pallets in its runtime. Used to construct any +/// remote calls. The codec index must correspond to the index of `IdentityMigrator` in the +/// `construct_runtime` of the remote chain. +#[derive(Encode, Decode)] +enum PeopleRuntimePallets { + #[codec(index = 248)] + IdentityMigrator(IdentityMigratorCalls), +} + +/// Call encoding for the calls needed from the Identity Migrator pallet. +#[derive(Encode, Decode)] +enum IdentityMigratorCalls { + #[codec(index = 1)] + PokeDeposit(AccountId), +} + +/// Type that implements `OnReapIdentity` that will send the deposit needed to store the same +/// information on a parachain, sends the deposit there, and then updates it. +pub struct ToParachainIdentityReaper(PhantomData<(Runtime, AccountId)>); +impl ToParachainIdentityReaper { + /// Calculate the balance needed on the remote chain based on the `IdentityInfo` and `Subs` on + /// this chain. The total includes: + /// + /// - Identity basic deposit + /// - `IdentityInfo` byte deposit + /// - Sub accounts deposit + /// - 2x existential deposit (1 for account existence, 1 such that the user can transact) + fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance { + // Remote deposit constants. Parachain uses `deposit / 100` + // Source: + // https://github.com/paritytech/polkadot-sdk/blob/a146918/cumulus/parachains/common/src/westend.rs#L28 + // + // Parachain Deposit Configuration: + // + // pub const BasicDeposit: Balance = deposit(1, 17); + // pub const ByteDeposit: Balance = deposit(0, 1); + // pub const SubAccountDeposit: Balance = deposit(1, 53); + // pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; + let para_basic_deposit = deposit(1, 17) / 100; + let para_byte_deposit = deposit(0, 1) / 100; + let para_sub_account_deposit = deposit(1, 53) / 100; + let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10; + + // pallet deposits + let id_deposit = + para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance)); + let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance); + + id_deposit + .saturating_add(subs_deposit) + .saturating_add(para_existential_deposit.saturating_mul(2)) + } +} + +impl OnReapIdentity for ToParachainIdentityReaper +where + Runtime: frame_system::Config + pallet_xcm::Config, + AccountId: Into<[u8; 32]> + Clone + Encode, +{ + fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { + use crate::{ + impls::IdentityMigratorCalls::PokeDeposit, + weights::runtime_common_identity_migrator::WeightInfo as MigratorWeights, + }; + + let total_to_send = Self::calculate_remote_deposit(fields, subs); + + // define asset / destination from relay perspective + let wnd = MultiAsset { id: Concrete(Here.into_location()), fun: Fungible(total_to_send) }; + // People Chain: ParaId 1004 + let destination: MultiLocation = MultiLocation::new(0, Parachain(1004)); + + // Do `check_out` accounting since the XCM Executor's `InitiateTeleport` doesn't support + // unpaid teleports. + + // check out + xcm_config::LocalAssetTransactor::can_check_out( + &destination, + &wnd, + // not used in AssetTransactor + &XcmContext { origin: None, message_id: [0; 32], topic: None }, + ) + .map_err(|_| pallet_xcm::Error::::CannotCheckOutTeleport)?; + xcm_config::LocalAssetTransactor::check_out( + &destination, + &wnd, + // not used in AssetTransactor + &XcmContext { origin: None, message_id: [0; 32], topic: None }, + ); + + // reanchor + let wnd_reanchored: MultiAssets = vec![MultiAsset { + id: Concrete(MultiLocation::new(1, Here)), + fun: Fungible(total_to_send), + }] + .into(); + + let poke = PeopleRuntimePallets::::IdentityMigrator(PokeDeposit(who.clone())); + let remote_weight_limit = MigratorWeights::::poke_deposit().saturating_mul(2); + + // Actual program to execute on People Chain. + let program: Xcm<()> = Xcm(vec![ + // Unpaid as this is constructed by the system, once per user. The user shouldn't have + // their balance reduced by teleport fees for the favor of migrating. + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + // Receive the asset into holding. + ReceiveTeleportedAsset(wnd_reanchored), + // Deposit into the user's account. + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: Junction::AccountId32 { network: None, id: who.clone().into() } + .into_location() + .into(), + }, + // Poke the deposit to reserve the appropriate amount on the parachain. + Transact { + origin_kind: OriginKind::Superuser, + require_weight_at_most: remote_weight_limit, + call: poke.encode().into(), + }, + ]); + + // send + let _ = >::send( + RawOrigin::Root.into(), + Box::new(VersionedMultiLocation::V3(destination)), + Box::new(VersionedXcm::V3(program)), + )?; + Ok(()) + } +} diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d3862aff257..2e8394b0ee4 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, EitherOf, EitherOfDiverse, Everything, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, }, @@ -56,7 +56,7 @@ use primitives::{ use runtime_common::{ assigned_slots, auctions, crowdloan, elections::OnChainAccuracy, - impl_runtime_weights, + identity_migrator, impl_runtime_weights, impls::{ LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter, }, @@ -119,6 +119,10 @@ mod bag_thresholds; mod weights; pub mod xcm_config; +// Implemented types. +mod impls; +use impls::ToParachainIdentityReaper; + // Governance and configurations. pub mod governance; use governance::{ @@ -161,13 +165,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 IsIdentityCall; +impl Contains for IsIdentityCall { + 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 = Everything; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; @@ -1328,6 +1343,14 @@ impl auctions::Config for Runtime { type WeightInfo = weights::runtime_common_auctions::WeightInfo; } +impl identity_migrator::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // To be changed to `EnsureSigned` once there is a People Chain to migrate to. + type Reaper = EnsureRoot; + type ReapIdentityHandler = ToParachainIdentityReaper; + type WeightInfo = weights::runtime_common_identity_migrator::WeightInfo; +} + parameter_types! { pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); pub const MaxPointsToBalance: u8 = 10; @@ -1491,6 +1514,9 @@ construct_runtime! { // Root testing pallet. RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 102, + + // Pallet for migrating Identity to a parachain. To be removed post-migration. + IdentityMigrator: identity_migrator::{Pallet, Call, Event} = 248, } } @@ -1587,6 +1613,7 @@ mod benches { [runtime_common::assigned_slots, AssignedSlots] [runtime_common::auctions, Auctions] [runtime_common::crowdloan, Crowdloan] + [runtime_common::identity_migrator, IdentityMigrator] [runtime_common::paras_registrar, Registrar] [runtime_common::slots, Slots] [runtime_parachains::configuration, Configuration] diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 9ae6798d70b..3841579088a 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -46,6 +46,7 @@ pub mod pallet_xcm; pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; pub mod runtime_common_crowdloan; +pub mod runtime_common_identity_migrator; pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; pub mod runtime_parachains_configuration; diff --git a/polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs b/polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs new file mode 100644 index 00000000000..cec357453b6 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs @@ -0,0 +1,97 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `runtime_common::identity_migrator` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `sbtb`, CPU: `13th Gen Intel(R) Core(TM) i7-1365U` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=2 +// --repeat=1 +// --pallet=runtime_common::identity_migrator +// --extrinsic=* +// --output=./migrator-release.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::identity_migrator`. +pub struct WeightInfo(PhantomData); +impl runtime_common::identity_migrator::WeightInfo for WeightInfo { + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// 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`) + /// 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 `[0, 20]`. + /// The range of component `s` is `[0, 100]`. + fn reap_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7292 + r * (8 ±0) + s * (32 ±0)` + // Estimated: `11003 + r * (8 ±0) + s * (33 ±0)` + // Minimum execution time: 163_756_000 picoseconds. + Weight::from_parts(158_982_500, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 1_143_629 + .saturating_add(Weight::from_parts(238_675, 0).saturating_mul(r.into())) + // Standard Error: 228_725 + .saturating_add(Weight::from_parts(1_529_645, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(s.into())) + } + /// 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::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + fn poke_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `7229` + // Estimated: `11003` + // Minimum execution time: 137_570_000 picoseconds. + Weight::from_parts(137_570_000, 0) + .saturating_add(Weight::from_parts(0, 11003)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 264ea3ddb41..133f9eeb4be 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -79,8 +79,10 @@ mod tests; mod types; pub mod weights; +use codec::Encode; use frame_support::{ - pallet_prelude::DispatchResult, + ensure, + pallet_prelude::{DispatchError, DispatchResult}, traits::{BalanceStatus, Currency, Get, OnUnbalanced, ReservableCurrency}, }; use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero}; @@ -395,8 +397,7 @@ pub mod pallet { ); let (old_deposit, old_ids) = >::get(&sender); - let new_deposit = - T::SubAccountDeposit::get().saturating_mul(>::from(subs.len() as u32)); + let new_deposit = Self::subs_deposit(subs.len() as u32); let not_other_sub = subs.iter().filter_map(|i| SuperOf::::get(&i.0)).all(|i| i.0 == sender); @@ -898,6 +899,26 @@ impl Pallet { .collect() } + /// Calculate the deposit required for a number of `sub` accounts. + fn subs_deposit(subs: u32) -> BalanceOf { + T::SubAccountDeposit::get().saturating_mul(>::from(subs)) + } + + /// Take the `current` deposit that `who` is holding, and update it to a `new` one. + fn rejig_deposit( + who: &T::AccountId, + current: BalanceOf, + new: BalanceOf, + ) -> DispatchResult { + if new > current { + T::Currency::reserve(who, new - current)?; + } else if new < current { + let err_amount = T::Currency::unreserve(who, current - new); + debug_assert!(err_amount.is_zero()); + } + Ok(()) + } + /// Check if the account has corresponding identity information by the identity field. pub fn has_identity( who: &T::AccountId, @@ -906,4 +927,110 @@ impl Pallet { IdentityOf::::get(who) .map_or(false, |registration| (registration.info.has_identity(fields))) } + + /// Reap an identity, clearing associated storage items and refunding any deposits. This + /// function is very similar to (a) `clear_identity`, but called on a `target` account instead + /// of self; and (b) `kill_identity`, but without imposing a slash. + /// + /// Parameters: + /// - `target`: The account for which to reap identity state. + /// + /// Return type is a tuple of the number of registrars, `IdentityInfo` bytes, and sub accounts, + /// respectively. + /// + /// NOTE: This function is here temporarily for migration of Identity info from the Polkadot + /// Relay Chain into a system parachain. It will be removed after the migration. + pub fn reap_identity(who: &T::AccountId) -> Result<(u32, u32, u32), DispatchError> { + // `take` any storage items keyed by `target` + // identity + let id = >::take(&who).ok_or(Error::::NotNamed)?; + let registrars = id.judgements.len() as u32; + let encoded_byte_size = id.info.encoded_size() as u32; + + // subs + let (subs_deposit, sub_ids) = >::take(&who); + let actual_subs = sub_ids.len() as u32; + for sub in sub_ids.iter() { + >::remove(sub); + } + + // unreserve any deposits + let deposit = id.total_deposit().saturating_add(subs_deposit); + let err_amount = T::Currency::unreserve(&who, deposit); + debug_assert!(err_amount.is_zero()); + Ok((registrars, encoded_byte_size, actual_subs)) + } + + /// Update the deposits held by `target` for its identity info. + /// + /// Parameters: + /// - `target`: The account for which to update deposits. + /// + /// Return type is a tuple of the new Identity and Subs deposits, respectively. + /// + /// NOTE: This function is here temporarily for migration of Identity info from the Polkadot + /// Relay Chain into a system parachain. It will be removed after the migration. + pub fn poke_deposit( + target: &T::AccountId, + ) -> Result<(BalanceOf, BalanceOf), DispatchError> { + // Identity Deposit + let new_id_deposit = IdentityOf::::try_mutate( + &target, + |registration| -> Result, DispatchError> { + let reg = registration.as_mut().ok_or(Error::::NoIdentity)?; + // Calculate what deposit should be + let encoded_byte_size = reg.info.encoded_size() as u32; + let byte_deposit = + T::ByteDeposit::get().saturating_mul(>::from(encoded_byte_size)); + let new_id_deposit = T::BasicDeposit::get().saturating_add(byte_deposit); + + // Update account + Self::rejig_deposit(&target, reg.deposit, new_id_deposit)?; + + reg.deposit = new_id_deposit; + Ok(new_id_deposit) + }, + )?; + + // Subs Deposit + let new_subs_deposit = SubsOf::::try_mutate( + &target, + |(current_subs_deposit, subs_of)| -> Result, DispatchError> { + let new_subs_deposit = Self::subs_deposit(subs_of.len() as u32); + Self::rejig_deposit(&target, *current_subs_deposit, new_subs_deposit)?; + *current_subs_deposit = new_subs_deposit; + Ok(new_subs_deposit) + }, + )?; + Ok((new_id_deposit, new_subs_deposit)) + } + + /// Set an identity with zero deposit. Only used for benchmarking that involves `rejig_deposit`. + #[cfg(feature = "runtime-benchmarks")] + pub fn set_identity_no_deposit( + who: &T::AccountId, + info: T::IdentityInformation, + ) -> DispatchResult { + IdentityOf::::insert( + &who, + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: info.clone(), + }, + ); + Ok(()) + } + + /// Set subs with zero deposit. Only used for benchmarking that involves `rejig_deposit`. + #[cfg(feature = "runtime-benchmarks")] + pub fn set_sub_no_deposit(who: &T::AccountId, sub: T::AccountId) -> DispatchResult { + use frame_support::BoundedVec; + let subs = BoundedVec::<_, T::MaxSubAccounts>::try_from(vec![sub]).unwrap(); + SubsOf::::insert::< + &T::AccountId, + (BalanceOf, BoundedVec), + >(&who, (Zero::zero(), subs)); + Ok(()) + } } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 71192ea65a8..78074df933a 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -712,3 +712,70 @@ fn test_has_identity() { )); }); } + +#[test] +fn reap_identity_works() { + new_test_ext().execute_with(|| { + let ten_info = ten(); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten_info.clone()))); + assert_ok!(Identity::set_subs( + RuntimeOrigin::signed(10), + vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] + )); + // deposit is correct + let id_deposit = id_deposit(&ten_info); + let subs_deposit: u64 = <::SubAccountDeposit as Get>::get(); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - subs_deposit); + // reap + assert_ok!(Identity::reap_identity(&10)); + // no identity or subs + assert!(Identity::identity(10).is_none()); + assert!(Identity::super_of(20).is_none()); + // balance is unreserved + assert_eq!(Balances::free_balance(10), 1000); + }); +} + +#[test] +fn poke_deposit_works() { + new_test_ext().execute_with(|| { + let ten_info = ten(); + // Set a custom registration with 0 deposit + IdentityOf::::insert( + &10, + Registration { + judgements: BoundedVec::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, + ); + assert!(Identity::identity(10).is_some()); + // Set a sub with zero deposit + SubsOf::::insert::<&u64, (u64, BoundedVec>)>( + &10, + (0, vec![20].try_into().unwrap()), + ); + SuperOf::::insert(&20, (&10, Data::Raw(vec![1; 1].try_into().unwrap()))); + // Balance is free + assert_eq!(Balances::free_balance(10), 1000); + + // poke + assert_ok!(Identity::poke_deposit(&10)); + + // free balance reduced correctly + let id_deposit = id_deposit(&ten_info); + let subs_deposit: u64 = <::SubAccountDeposit as Get>::get(); + assert_eq!(Balances::free_balance(10), 1000 - id_deposit - subs_deposit); + // new registration deposit is 10 + assert_eq!( + Identity::identity(&10), + Some(Registration { + judgements: BoundedVec::default(), + deposit: id_deposit, + info: ten() + }) + ); + // new subs deposit is 10 vvvvvvvvvvvv + assert_eq!(Identity::subs_of(10), (subs_deposit, vec![20].try_into().unwrap())); + }); +} -- GitLab From 0226b55f9ffff28821458a71c84eb5d3e75f1794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Wed, 15 Nov 2023 15:01:55 +0000 Subject: [PATCH 517/633] Add `collectives-westend` and `glutton-westend` runtimes (#2024) Add collectives and glutton parachain westend runtimes to prepare for #1737. The removal of system parachain native runtimes #1737 is blocked until chainspecs and runtime APIs can be dealt with cleanly (merge of #1256 and follow up PRs). In the meantime, these additions are ready to be merged to `master`, so I have separated them out into this PR. Also marked `bridge-hub-westend` as unimplemented in line with [this issue](https://github.com/paritytech/parity-bridges-common/issues/2602). TODO - [x] add to `command-bot` benchmarks - [x] add to `command-bot-scripts` benchmarks - [x] generate weights --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Muharem Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Branislav Kontur --- .../build-and-attach-release-runtimes.yml | 2 + .gitlab/pipeline/check.yml | 13 + .gitlab/pipeline/short-benchmarks.yml | 10 + Cargo.lock | 134 +++ Cargo.toml | 2 + .../collectives-westend/Cargo.toml | 230 ++++ .../collectives/collectives-westend/build.rs | 26 + .../collectives-westend/src/ambassador/mod.rs | 262 +++++ .../src/ambassador/origins.rs | 135 +++ .../src/ambassador/tracks.rs | 282 +++++ .../collectives-westend/src/fellowship/mod.rs | 238 ++++ .../src/fellowship/origins.rs | 247 ++++ .../src/fellowship/tracks.rs | 532 +++++++++ .../collectives-westend/src/impls.rs | 229 ++++ .../collectives-westend/src/lib.rs | 1023 +++++++++++++++++ .../src/weights/block_weights.rs | 53 + .../src/weights/cumulus_pallet_dmp_queue.rs | 131 +++ .../cumulus_pallet_parachain_system.rs | 80 ++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 148 +++ .../src/weights/extrinsic_weights.rs | 53 + .../src/weights/frame_system.rs | 154 +++ .../collectives-westend/src/weights/mod.rs | 50 + .../src/weights/pallet_alliance.rs | 494 ++++++++ .../src/weights/pallet_balances.rs | 152 +++ .../src/weights/pallet_collator_selection.rs | 246 ++++ .../src/weights/pallet_collective.rs | 304 +++++ .../src/weights/pallet_collective_content.rs | 93 ++ .../pallet_core_fellowship_ambassador_core.rs | 223 ++++ .../pallet_core_fellowship_fellowship_core.rs | 222 ++++ .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_multisig.rs | 164 +++ .../src/weights/pallet_preimage.rs | 232 ++++ .../src/weights/pallet_proxy.rs | 225 ++++ ...ranked_collective_ambassador_collective.rs | 177 +++ ...ranked_collective_fellowship_collective.rs | 176 +++ .../pallet_referenda_ambassador_referenda.rs | 536 +++++++++ .../pallet_referenda_fellowship_referenda.rs | 535 +++++++++ .../pallet_salary_ambassador_salary.rs | 190 +++ .../pallet_salary_fellowship_salary.rs | 189 +++ .../src/weights/pallet_scheduler.rs | 206 ++++ .../src/weights/pallet_session.rs | 80 ++ .../src/weights/pallet_timestamp.rs | 74 ++ .../src/weights/pallet_utility.rs | 101 ++ .../src/weights/pallet_xcm.rs | 323 ++++++ .../src/weights/paritydb_weights.rs | 63 + .../src/weights/rocksdb_weights.rs | 63 + .../collectives-westend/src/xcm_config.rs | 364 ++++++ .../glutton/glutton-westend/Cargo.toml | 138 +++ .../runtimes/glutton/glutton-westend/build.rs | 24 + .../glutton/glutton-westend/src/lib.rs | 532 +++++++++ .../cumulus_pallet_parachain_system.rs | 75 ++ .../src/weights/frame_system.rs | 153 +++ .../glutton-westend/src/weights/mod.rs | 19 + .../src/weights/pallet_glutton.rs | 178 +++ .../src/weights/pallet_message_queue.rs | 179 +++ .../src/weights/pallet_timestamp.rs | 73 ++ .../glutton/glutton-westend/src/xcm_config.rs | 92 ++ cumulus/parachains/testnets-common/Cargo.toml | 44 + cumulus/parachains/testnets-common/src/lib.rs | 30 + .../parachains/testnets-common/src/rococo.rs | 119 ++ .../parachains/testnets-common/src/westend.rs | 140 +++ .../parachains/testnets-common/src/wococo.rs | 17 + cumulus/polkadot-parachain/Cargo.toml | 6 + .../src/chain_spec/collectives.rs | 133 +++ .../src/chain_spec/glutton.rs | 69 ++ cumulus/polkadot-parachain/src/command.rs | 101 +- cumulus/polkadot-parachain/src/service.rs | 30 + cumulus/scripts/benchmarks.sh | 2 + 68 files changed, 11792 insertions(+), 7 deletions(-) create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/build.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/origins.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/origins.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_alliance.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collator_selection.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective_content.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_multisig.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_preimage.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_proxy.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_ranked_collective_ambassador_collective.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_ranked_collective_fellowship_collective.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_ambassador_referenda.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_fellowship_referenda.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_salary_ambassador_salary.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_salary_fellowship_salary.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_session.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_timestamp.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/build.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/mod.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_glutton.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_message_queue.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_timestamp.rs create mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs create mode 100644 cumulus/parachains/testnets-common/Cargo.toml create mode 100644 cumulus/parachains/testnets-common/src/lib.rs create mode 100644 cumulus/parachains/testnets-common/src/rococo.rs create mode 100644 cumulus/parachains/testnets-common/src/westend.rs create mode 100644 cumulus/parachains/testnets-common/src/wococo.rs diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml index c7cd4b34384..db0175c6855 100644 --- a/.github/workflows/build-and-attach-release-runtimes.yml +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -19,6 +19,8 @@ jobs: - { name: asset-hub-westend, package: asset-hub-westend-runtime, path: cumulus/parachains/runtimes/assets/asset-hub-westend } - { name: bridge-hub-rococo, package: bridge-hub-rococo-runtime, path: cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo } - { name: contracts-rococo, package: contracts-rococo-runtime, path: cumulus/parachains/runtimes/contracts/contracts-rococo } + - { name: collectives-westend, package: collectives-westend-runtime, path: cumulus/parachains/runtimes/collectives/collectives-westend } + - { name: glutton-westend, package: glutton-westend-runtime, path: cumulus/parachains/runtimes/glutton/glutton-westend } build_config: # Release build has logging disabled and no dev features - { type: on-chain-release, opts: --features on-chain-release-build } diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index cbb3baf277c..4071fdf9758 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -177,6 +177,19 @@ check-runtime-migration-contracts-rococo: WASM: "contracts_rococo_runtime.compact.compressed.wasm" URI: "wss://rococo-contracts-rpc.polkadot.io:443" +# Check runtime migrations for Parity managed collectives chains +check-runtime-migration-collectives-westend: + stage: check + extends: + - .docker-env + - .test-pr-refs + - .check-runtime-migration + variables: + NETWORK: "collectives-westend" + PACKAGE: "collectives-westend-runtime" + WASM: "collectives_westend_runtime.compact.compressed.wasm" + URI: "wss://westend-collectives-rpc.polkadot.io:443" + find-fail-ci-phrase: stage: check variables: diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 76c75e815ce..0218d3fdac0 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -94,7 +94,17 @@ short-benchmark-collectives-polkadot: variables: RUNTIME_CHAIN: collectives-polkadot-dev +short-benchmark-collectives-westend: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: collectives-westend-dev + short-benchmark-glutton-kusama: <<: *short-bench-cumulus variables: RUNTIME_CHAIN: glutton-kusama-dev-1300 + +short-benchmark-glutton-westend: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: glutton-westend-dev-1300 diff --git a/Cargo.lock b/Cargo.lock index b1a46a88f38..6b52e62d742 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3001,6 +3001,80 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "collectives-westend-runtime" +version = "1.0.0" +dependencies = [ + "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", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal", + "log", + "pallet-alliance", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-collective", + "pallet-collective-content", + "pallet-core-fellowship", + "pallet-message-queue", + "pallet-multisig", + "pallet-preimage", + "pallet-proxy", + "pallet-ranked-collective", + "pallet-referenda", + "pallet-salary", + "pallet-scheduler", + "pallet-session", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "scale-info", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-transaction-pool", + "sp-version", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", + "testnets-common", + "westend-runtime-constants", +] + [[package]] name = "color-eyre" version = "0.6.2" @@ -6280,6 +6354,51 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "glutton-westend-runtime" +version = "1.0.0" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-primitives-aura", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "pallet-aura", + "pallet-glutton", + "pallet-message-queue", + "pallet-sudo", + "pallet-timestamp", + "parachains-common", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-transaction-pool", + "sp-version", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", +] + [[package]] name = "group" version = "0.12.1" @@ -12872,6 +12991,7 @@ dependencies = [ "bridge-hub-westend-runtime", "clap 4.4.6", "collectives-polkadot-runtime", + "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", "cumulus-client-cli", @@ -12889,6 +13009,7 @@ dependencies = [ "frame-benchmarking-cli", "futures", "glutton-runtime", + "glutton-westend-runtime", "hex-literal", "jsonrpsee", "log", @@ -19217,6 +19338,19 @@ dependencies = [ "sp-weights", ] +[[package]] +name = "testnets-common" +version = "1.0.0" +dependencies = [ + "frame-support", + "polkadot-core-primitives", + "rococo-runtime-constants", + "smallvec", + "sp-runtime", + "substrate-wasm-builder", + "westend-runtime-constants", +] + [[package]] name = "textwrap" version = "0.16.0" diff --git a/Cargo.toml b/Cargo.toml index f9779681cae..27351c09581 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,8 +94,10 @@ members = [ "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", "cumulus/parachains/runtimes/bridge-hubs/test-utils", "cumulus/parachains/runtimes/collectives/collectives-polkadot", + "cumulus/parachains/runtimes/collectives/collectives-westend", "cumulus/parachains/runtimes/contracts/contracts-rococo", "cumulus/parachains/runtimes/glutton/glutton-kusama", + "cumulus/parachains/runtimes/glutton/glutton-westend", "cumulus/parachains/runtimes/starters/seedling", "cumulus/parachains/runtimes/starters/shell", "cumulus/parachains/runtimes/test-utils", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml new file mode 100644 index 00000000000..94f2de33e90 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -0,0 +1,230 @@ +[package] +name = "collectives-westend-runtime" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Westend Collectives 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.10.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-alliance = { path = "../../../../../substrate/frame/alliance", 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-collective = { path = "../../../../../substrate/frame/collective", default-features = false} +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} +pallet-preimage = { path = "../../../../../substrate/frame/preimage", default-features = false } +pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false} +pallet-scheduler = { path = "../../../../../substrate/frame/scheduler", default-features = false } +pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} +pallet-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-utility = { path = "../../../../../substrate/frame/utility", default-features = false} +pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false} +pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false} +pallet-core-fellowship = { path = "../../../../../substrate/frame/core-fellowship", default-features = false} +pallet-salary = { path = "../../../../../substrate/frame/salary", default-features = false} +sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} +sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", 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} +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} + +# Polkadot +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} +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} +westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} + +# Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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 } +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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } +parachains-common = { path = "../../../common", default-features = false } +testnets-common = { path = "../../../testnets-common", default-features = false } + +[build-dependencies] +substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } + +[dev-dependencies] +sp-io = { path = "../../../../../substrate/primitives/io", features = [ "std" ]} + +[features] +default = [ "std" ] +runtime-benchmarks = [ + "cumulus-pallet-dmp-queue/runtime-benchmarks", + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "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-message-queue/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-ranked-collective/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-salary/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "testnets-common/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-alliance/try-runtime", + "pallet-aura/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-message-queue/try-runtime", + "pallet-multisig/try-runtime", + "pallet-preimage/try-runtime", + "pallet-proxy/try-runtime", + "pallet-ranked-collective/try-runtime", + "pallet-referenda/try-runtime", + "pallet-salary/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-session/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/try-runtime", +] +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-alliance/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-collective-content/std", + "pallet-collective/std", + "pallet-core-fellowship/std", + "pallet-message-queue/std", + "pallet-multisig/std", + "pallet-preimage/std", + "pallet-proxy/std", + "pallet-ranked-collective/std", + "pallet-referenda/std", + "pallet-salary/std", + "pallet-scheduler/std", + "pallet-session/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-core-primitives/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "scale-info/std", + "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-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + "substrate-wasm-builder", + "testnets-common/std", + "westend-runtime-constants/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] + +experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs new file mode 100644 index 00000000000..60f8a125129 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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/collectives/collectives-westend/src/ambassador/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs new file mode 100644 index 00000000000..18c1466bf36 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs @@ -0,0 +1,262 @@ +// 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::{FellowshipAdminBodyId, WndAssetHub}; +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 demote 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 temporary 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< + EnsureRoot, + 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< + EnsureRoot, + 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 WND. +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-westend/src/ambassador/origins.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/origins.rs new file mode 100644 index 00000000000..3ce8a6b9e5d --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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-westend/src/ambassador/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs new file mode 100644 index 00000000000..d4a2d3bbf1c --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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: 1 * 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: 1 * 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: 1 * 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: 1 * 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: 1 * 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: 1 * 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: 1 * 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: 1 * 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: 1 * 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-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs new file mode 100644 index 00000000000..b7412705dde --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -0,0 +1,238 @@ +// 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 . + +//! The Westend Technical Fellowship. + +mod origins; +mod tracks; +use crate::{ + impls::ToParentTreasury, + weights, + xcm_config::{FellowshipAdminBodyId, UsdtAssetHub}, + AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, +}; +use frame_support::{ + parameter_types, + traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg}, +}; +use frame_system::EnsureRootWithSuccess; +pub use origins::{ + pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt, + EnsureFellowship, Fellows, Masters, Members, ToVoice, +}; +use pallet_ranked_collective::EnsureOfRank; +use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use parachains_common::{polkadot::account, HOURS}; +use sp_core::{ConstU128, ConstU32}; +use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; +use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; + +#[cfg(feature = "runtime-benchmarks")] +use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure}; + +/// The Fellowship members' ranks. +pub mod ranks { + use pallet_ranked_collective::Rank; + + pub const DAN_1: Rank = 1; // aka Members. + pub const DAN_2: Rank = 2; + pub const DAN_3: Rank = 3; // aka Fellows. + pub const DAN_4: Rank = 4; // aka Architects. + pub const DAN_5: Rank = 5; + pub const DAN_6: Rank = 6; + pub const DAN_7: Rank = 7; // aka Masters. + pub const DAN_8: Rank = 8; + pub const DAN_9: Rank = 9; +} + +parameter_types! { + // Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting. + pub ReferendaPalletAccount: AccountId = account::REFERENDA_PALLET_ID.into_account_truncating(); +} + +impl pallet_fellowship_origins::Config for Runtime {} + +pub type FellowshipReferendaInstance = pallet_referenda::Instance1; + +impl pallet_referenda::Config for Runtime { + type WeightInfo = weights::pallet_referenda_fellowship_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + // Fellows can submit proposals. + type SubmitOrigin = EitherOf< + pallet_ranked_collective::EnsureMember, + MapSuccess< + TryWithMorphedArg< + RuntimeOrigin, + ::PalletsOrigin, + ToVoice, + EnsureOfRank, + (AccountId, u16), + >, + TakeFirst, + >, + >; + type CancelOrigin = Architects; + type KillOrigin = Masters; + type Slash = ToParentTreasury; + type Votes = pallet_ranked_collective::Votes; + type Tally = pallet_ranked_collective::TallyOf; + type SubmissionDeposit = ConstU128<0>; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = ConstU32<{ 7 * DAYS }>; + type AlarmInterval = ConstU32<1>; + type Tracks = tracks::TracksInfo; + type Preimages = Preimage; +} + +pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; + +impl pallet_ranked_collective::Config for Runtime { + type WeightInfo = weights::pallet_ranked_collective_fellowship_collective::WeightInfo; + type RuntimeEvent = RuntimeEvent; + + #[cfg(not(feature = "runtime-benchmarks"))] + // Promotions and the induction of new members are serviced by `FellowshipCore` pallet instance. + type PromoteOrigin = frame_system::EnsureNever; + #[cfg(feature = "runtime-benchmarks")] + // The maximum value of `u16` set as a success value for the root to ensure the benchmarks will + // pass. + type PromoteOrigin = EnsureRootWithSuccess>; + + // Demotion is by any of: + // - Root can demote arbitrarily. + // - the FellowshipAdmin origin (i.e. token holder referendum); + // + // The maximum value of `u16` set as a success value for the root to ensure the benchmarks will + // pass. + type DemoteOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + EnsureXcm>, + Replace>, + >, + >; + type Polls = FellowshipReferenda; + type MinRankOfClass = tracks::MinRankOfClass; + type VoteWeight = pallet_ranked_collective::Geometric; +} + +pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1; + +impl pallet_core_fellowship::Config for Runtime { + type WeightInfo = weights::pallet_core_fellowship_fellowship_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 Fellows. + type ParamsOrigin = EitherOfDiverse< + EnsureXcm>, + Fellows, + >; + // Induction (creating a candidate) is by any of: + // - Root; + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a single Fellow; + // - a vote among all Members. + type InductOrigin = EitherOfDiverse< + EnsureXcm>, + EitherOfDiverse< + pallet_ranked_collective::EnsureMember< + Runtime, + FellowshipCollectiveInstance, + { ranks::DAN_3 }, + >, + Members, + >, + >; + // Approval (rank-retention) of a Member's current rank is by any of: + // - Root; + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a vote by the rank two above the current rank for all retention up to the Master rank. + type ApproveOrigin = EitherOf< + MapSuccess< + EnsureXcm>, + Replace>, + >, + EnsureCanRetainAt, + >; + // Promotion is by any of: + // - Root can promote arbitrarily. + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a vote by the rank two above the new rank for all promotions up to the Master rank. + type PromoteOrigin = EitherOf< + MapSuccess< + EnsureXcm>, + Replace>, + >, + EnsureCanPromoteTo, + >; + type EvidenceSize = ConstU32<65536>; +} + +pub type FellowshipSalaryInstance = pallet_salary::Instance1; + +use xcm::prelude::*; + +parameter_types! { + // 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(); +} + +const USDT_UNITS: u128 = 1_000_000; + +/// [`PayOverXcm`] setup to pay the Fellowship salary on the AssetHub in USDT. +pub type FellowshipSalaryPaymaster = PayOverXcm< + Interior, + crate::xcm_config::XcmRouter, + crate::PolkadotXcm, + ConstU32<{ 6 * HOURS }>, + AccountId, + (), + ConvertToValue, + AliasesIntoAccountId32<(), AccountId>, +>; + +impl pallet_salary::Config for Runtime { + type WeightInfo = weights::pallet_salary_fellowship_salary::WeightInfo; + type RuntimeEvent = RuntimeEvent; + + #[cfg(not(feature = "runtime-benchmarks"))] + type Paymaster = FellowshipSalaryPaymaster; + #[cfg(feature = "runtime-benchmarks")] + type Paymaster = PayWithEnsure>>; + 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<{ 100_000 * USDT_UNITS }>; +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/origins.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/origins.rs new file mode 100644 index 00000000000..5ed2c19f79e --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/origins.rs @@ -0,0 +1,247 @@ +// 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 . + +//! Fellowship custom origins. + +use super::ranks; +pub use pallet_origins::*; + +#[frame_support::pallet] +pub mod pallet_origins { + use super::ranks; + use frame_support::pallet_prelude::*; + use pallet_ranked_collective::Rank; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Origin aggregated through weighted votes of those with rank 1 or above; `Success` is 1. + /// Aka the "voice" of all Members. + Members, + /// Origin aggregated through weighted votes of those with rank 2 or above; `Success` is 2. + /// Aka the "voice" of members at least II Dan. + Fellowship2Dan, + /// Origin aggregated through weighted votes of those with rank 3 or above; `Success` is 3. + /// Aka the "voice" of all Fellows. + Fellows, + /// Origin aggregated through weighted votes of those with rank 4 or above; `Success` is 4. + /// Aka the "voice" of members at least IV Dan. + Architects, + /// Origin aggregated through weighted votes of those with rank 5 or above; `Success` is 5. + /// Aka the "voice" of members at least V Dan. + Fellowship5Dan, + /// Origin aggregated through weighted votes of those with rank 6 or above; `Success` is 6. + /// Aka the "voice" of members at least VI Dan. + Fellowship6Dan, + /// Origin aggregated through weighted votes of those with rank 7 or above; `Success` is 7. + /// Aka the "voice" of all Masters. + Masters, + /// Origin aggregated through weighted votes of those with rank 8 or above; `Success` is 8. + /// Aka the "voice" of members at least VIII Dan. + Fellowship8Dan, + /// Origin aggregated through weighted votes of those with rank 9 or above; `Success` is 9. + /// Aka the "voice" of members at least IX Dan. + Fellowship9Dan, + + /// Origin aggregated through weighted votes of those with rank 3 or above when voting on + /// a fortnight-long track; `Success` is 1. + RetainAt1Dan, + /// Origin aggregated through weighted votes of those with rank 4 or above when voting on + /// a fortnight-long track; `Success` is 2. + RetainAt2Dan, + /// Origin aggregated through weighted votes of those with rank 5 or above when voting on + /// a fortnight-long track; `Success` is 3. + RetainAt3Dan, + /// Origin aggregated through weighted votes of those with rank 6 or above when voting on + /// a fortnight-long track; `Success` is 4. + RetainAt4Dan, + /// Origin aggregated through weighted votes of those with rank 7 or above when voting on + /// a fortnight-long track; `Success` is 5. + RetainAt5Dan, + /// Origin aggregated through weighted votes of those with rank 8 or above when voting on + /// a fortnight-long track; `Success` is 6. + RetainAt6Dan, + + /// Origin aggregated through weighted votes of those with rank 3 or above when voting on + /// a month-long track; `Success` is 1. + PromoteTo1Dan, + /// Origin aggregated through weighted votes of those with rank 4 or above when voting on + /// a month-long track; `Success` is 2. + PromoteTo2Dan, + /// Origin aggregated through weighted votes of those with rank 5 or above when voting on + /// a month-long track; `Success` is 3. + PromoteTo3Dan, + /// Origin aggregated through weighted votes of those with rank 6 or above when voting on + /// a month-long track; `Success` is 4. + PromoteTo4Dan, + /// Origin aggregated through weighted votes of those with rank 7 or above when voting on + /// a month-long track; `Success` is 5. + PromoteTo5Dan, + /// Origin aggregated through weighted votes of those with rank 8 or above when voting on + /// a month-long track; `Success` is 6. + PromoteTo6Dan, + } + + impl Origin { + /// Returns the rank that the origin `self` speaks for, or `None` if it doesn't speak for + /// any. + /// + /// `Some` will be returned only for the first 9 elements of [Origin]. + pub fn as_voice(&self) -> Option { + Some(match &self { + Origin::Members => ranks::DAN_1, + Origin::Fellowship2Dan => ranks::DAN_2, + Origin::Fellows => ranks::DAN_3, + Origin::Architects => ranks::DAN_4, + Origin::Fellowship5Dan => ranks::DAN_5, + Origin::Fellowship6Dan => ranks::DAN_6, + Origin::Masters => ranks::DAN_7, + Origin::Fellowship8Dan => ranks::DAN_8, + Origin::Fellowship9Dan => ranks::DAN_9, + _ => return None, + }) + } + } + + /// A `TryMorph` implementation which is designed to convert an aggregate `RuntimeOrigin` + /// value into the Fellowship voice it represents if it is a Fellowship pallet origin an + /// appropriate variant. See also [Origin::as_voice]. + pub struct ToVoice; + impl<'a, O: 'a + TryInto<&'a Origin>> sp_runtime::traits::TryMorph for ToVoice { + type Outcome = pallet_ranked_collective::Rank; + fn try_morph(o: O) -> Result { + o.try_into().ok().and_then(Origin::as_voice).ok_or(()) + } + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + Members: Rank = ranks::DAN_1, + Fellows: Rank = ranks::DAN_3, + Architects: Rank = ranks::DAN_4, + Masters: Rank = ranks::DAN_7, + ); + + macro_rules! decl_ensure { + ( + $vis:vis type $name:ident: EnsureOrigin { + $( $item:ident = $success:expr, )* + } + ) => { + $vis struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + $( + Origin::$item => Ok($success), + )* + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // By convention the more privileged origins go later, so for greatest chance + // of success, we want the last one. + let _result: Result = Err(()); + $( + let _result: Result = Ok(O::from(Origin::$item)); + )* + _result + } + } + } + } + + // Fellowship origin indicating weighted voting from at least the rank of `Success` on a + // week-long track. + decl_ensure! { + pub type EnsureFellowship: EnsureOrigin { + Members = ranks::DAN_1, + Fellowship2Dan = ranks::DAN_2, + Fellows = ranks::DAN_3, + Architects = ranks::DAN_4, + Fellowship5Dan = ranks::DAN_5, + Fellowship6Dan = ranks::DAN_6, + Masters = ranks::DAN_7, + Fellowship8Dan = ranks::DAN_8, + Fellowship9Dan = ranks::DAN_9, + } + } + + // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on + // a fortnight-long track; needed for Fellowship retention voting. + decl_ensure! { + pub type EnsureCanRetainAt: EnsureOrigin { + RetainAt1Dan = ranks::DAN_1, + RetainAt2Dan = ranks::DAN_2, + RetainAt3Dan = ranks::DAN_3, + RetainAt4Dan = ranks::DAN_4, + RetainAt5Dan = ranks::DAN_5, + RetainAt6Dan = ranks::DAN_6, + } + } + + // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on + // a month-long track; needed for Fellowship promotion voting. + decl_ensure! { + pub type EnsureCanPromoteTo: EnsureOrigin { + PromoteTo1Dan = ranks::DAN_1, + PromoteTo2Dan = ranks::DAN_2, + PromoteTo3Dan = ranks::DAN_3, + PromoteTo4Dan = ranks::DAN_4, + PromoteTo5Dan = ranks::DAN_5, + PromoteTo6Dan = ranks::DAN_6, + } + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs new file mode 100644 index 00000000000..099bdf4cf75 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs @@ -0,0 +1,532 @@ +// 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 . + +//! Track configurations for Fellowship. + +use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS, MINUTES}; +use pallet_ranked_collective::Rank; +use sp_runtime::{traits::Convert, Perbill}; + +/// Referendum `TrackId` type. +pub type TrackId = u16; + +/// Referendum track IDs. +pub mod constants { + use super::TrackId; + + // Regular tracks (7 days) used for general operations. The required rank for voting is the + // same as that which is named (and also the track ID). + pub const MEMBERS: TrackId = 1; + pub const PROFICIENTS: TrackId = 2; + pub const FELLOWS: TrackId = 3; + pub const ARCHITECTS: TrackId = 4; + pub const ARCHITECTS_ADEPT: TrackId = 5; + pub const GRAND_ARCHITECTS: TrackId = 6; + pub const MASTERS: TrackId = 7; + pub const MASTERS_CONSTANT: TrackId = 8; + pub const GRAND_MASTERS: TrackId = 9; + + // Longer tracks (14 days) used for rank retention. These require a rank of two more than the + // grade at which they retain (as per the whitepaper). This works out as the track ID minus 8. + pub const RETAIN_AT_1DAN: TrackId = 11; + pub const RETAIN_AT_2DAN: TrackId = 12; + pub const RETAIN_AT_3DAN: TrackId = 13; + pub const RETAIN_AT_4DAN: TrackId = 14; + pub const RETAIN_AT_5DAN: TrackId = 15; + pub const RETAIN_AT_6DAN: TrackId = 16; + + // Longest tracks (30 days) used for promotions. These require a rank of two more than the + // grade to which they promote (as per the whitepaper). This works out as the track ID minus 18. + pub const PROMOTE_TO_1DAN: TrackId = 21; + pub const PROMOTE_TO_2DAN: TrackId = 22; + pub const PROMOTE_TO_3DAN: TrackId = 23; + pub const PROMOTE_TO_4DAN: TrackId = 24; + pub const PROMOTE_TO_5DAN: TrackId = 25; + pub const PROMOTE_TO_6DAN: TrackId = 26; +} + +/// Convert the track ID (defined above) into the minimum rank (i.e. fellowship Dan grade) required +/// to vote on the track. +pub struct MinRankOfClass; +impl Convert for MinRankOfClass { + fn convert(a: TrackId) -> Rank { + match a { + // Just a regular vote: the track ID is conveniently the same as the minimum rank. + regular @ 1..=9 => regular, + // A retention vote; the track ID turns out to be 8 more than the minimum required rank. + retention @ 11..=16 => retention - 8, + // A promotion vote; the track ID turns out to be 18 more than the minimum required + // rank. + promotion @ 21..=26 => promotion - 18, + _ => Rank::max_value(), + } + } +} + +const RETAIN_MAX_DECIDING: u32 = 25; +const RETAIN_DECISION_DEPOSIT: Balance = 5 * DOLLARS; +const RETAIN_PREPARE_PERIOD: BlockNumber = 0; +const RETAIN_DECISION_PERIOD: BlockNumber = 14 * DAYS; +const RETAIN_CONFIRM_PERIOD: BlockNumber = 1 * HOURS; +const RETAIN_MIN_ENACTMENT_PERIOD: BlockNumber = 0; +const RETAIN_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(60), + ceil: Perbill::from_percent(100), +}; +const RETAIN_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(100), +}; + +const PROMOTE_MAX_DECIDING: u32 = 10; +const PROMOTE_DECISION_DEPOSIT: Balance = 5 * DOLLARS; +const PROMOTE_PREPARE_PERIOD: BlockNumber = 0; +const PROMOTE_DECISION_PERIOD: BlockNumber = 30 * DAYS; +const PROMOTE_CONFIRM_PERIOD: BlockNumber = 1 * HOURS; +const PROMOTE_MIN_ENACTMENT_PERIOD: BlockNumber = 0; +const PROMOTE_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(60), + ceil: Perbill::from_percent(100), +}; +const PROMOTE_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(100), +}; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = TrackId; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + use constants as tracks; + static DATA: [(TrackId, pallet_referenda::TrackInfo); 21] = [ + ( + tracks::MEMBERS, + pallet_referenda::TrackInfo { + name: "members", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::PROFICIENTS, + pallet_referenda::TrackInfo { + name: "proficient members", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::FELLOWS, + pallet_referenda::TrackInfo { + name: "fellows", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::ARCHITECTS, + pallet_referenda::TrackInfo { + name: "architects", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::ARCHITECTS_ADEPT, + pallet_referenda::TrackInfo { + name: "architects adept", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::GRAND_ARCHITECTS, + pallet_referenda::TrackInfo { + name: "grand architects", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::MASTERS, + pallet_referenda::TrackInfo { + name: "masters", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::MASTERS_CONSTANT, + pallet_referenda::TrackInfo { + name: "masters constant", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::GRAND_MASTERS, + pallet_referenda::TrackInfo { + name: "grand masters", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 30 * MINUTES, + decision_period: 1 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 5 * MINUTES, + 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(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + tracks::RETAIN_AT_1DAN, + pallet_referenda::TrackInfo { + name: "retain at I Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::RETAIN_AT_2DAN, + pallet_referenda::TrackInfo { + name: "retain at II Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::RETAIN_AT_3DAN, + pallet_referenda::TrackInfo { + name: "retain at III Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::RETAIN_AT_4DAN, + pallet_referenda::TrackInfo { + name: "retain at IV Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::RETAIN_AT_5DAN, + pallet_referenda::TrackInfo { + name: "retain at V Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::RETAIN_AT_6DAN, + pallet_referenda::TrackInfo { + name: "retain at VI Dan", + max_deciding: RETAIN_MAX_DECIDING, + decision_deposit: RETAIN_DECISION_DEPOSIT, + prepare_period: RETAIN_PREPARE_PERIOD, + decision_period: RETAIN_DECISION_PERIOD, + confirm_period: RETAIN_CONFIRM_PERIOD, + min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD, + min_approval: RETAIN_MIN_APPROVAL, + min_support: RETAIN_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_1DAN, + pallet_referenda::TrackInfo { + name: "promote to I Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_2DAN, + pallet_referenda::TrackInfo { + name: "promote to II Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_3DAN, + pallet_referenda::TrackInfo { + name: "promote to III Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_4DAN, + pallet_referenda::TrackInfo { + name: "promote to IV Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_5DAN, + pallet_referenda::TrackInfo { + name: "promote to V Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ( + tracks::PROMOTE_TO_6DAN, + pallet_referenda::TrackInfo { + name: "promote to VI Dan", + max_deciding: PROMOTE_MAX_DECIDING, + decision_deposit: PROMOTE_DECISION_DEPOSIT, + prepare_period: PROMOTE_PREPARE_PERIOD, + decision_period: PROMOTE_DECISION_PERIOD, + confirm_period: PROMOTE_CONFIRM_PERIOD, + min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD, + min_approval: PROMOTE_MIN_APPROVAL, + min_support: PROMOTE_MIN_SUPPORT, + }, + ), + ]; + &DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + use super::origins::Origin; + use constants as tracks; + + #[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(tracks::GRAND_MASTERS) + } + } + + match Origin::try_from(id.clone()) { + Ok(Origin::Members) => Ok(tracks::MEMBERS), + Ok(Origin::Fellowship2Dan) => Ok(tracks::PROFICIENTS), + Ok(Origin::Fellows) => Ok(tracks::FELLOWS), + Ok(Origin::Architects) => Ok(tracks::ARCHITECTS), + Ok(Origin::Fellowship5Dan) => Ok(tracks::ARCHITECTS_ADEPT), + Ok(Origin::Fellowship6Dan) => Ok(tracks::GRAND_ARCHITECTS), + Ok(Origin::Masters) => Ok(tracks::MASTERS), + Ok(Origin::Fellowship8Dan) => Ok(tracks::MASTERS_CONSTANT), + Ok(Origin::Fellowship9Dan) => Ok(tracks::GRAND_MASTERS), + + Ok(Origin::RetainAt1Dan) => Ok(tracks::RETAIN_AT_1DAN), + Ok(Origin::RetainAt2Dan) => Ok(tracks::RETAIN_AT_2DAN), + Ok(Origin::RetainAt3Dan) => Ok(tracks::RETAIN_AT_3DAN), + Ok(Origin::RetainAt4Dan) => Ok(tracks::RETAIN_AT_4DAN), + Ok(Origin::RetainAt5Dan) => Ok(tracks::RETAIN_AT_5DAN), + Ok(Origin::RetainAt6Dan) => Ok(tracks::RETAIN_AT_6DAN), + + Ok(Origin::PromoteTo1Dan) => Ok(tracks::PROMOTE_TO_1DAN), + Ok(Origin::PromoteTo2Dan) => Ok(tracks::PROMOTE_TO_2DAN), + Ok(Origin::PromoteTo3Dan) => Ok(tracks::PROMOTE_TO_3DAN), + Ok(Origin::PromoteTo4Dan) => Ok(tracks::PROMOTE_TO_4DAN), + Ok(Origin::PromoteTo5Dan) => Ok(tracks::PROMOTE_TO_5DAN), + Ok(Origin::PromoteTo6Dan) => Ok(tracks::PROMOTE_TO_6DAN), + + _ => Err(()), + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs new file mode 100644 index 00000000000..9f4c2a6a4c9 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs @@ -0,0 +1,229 @@ +// 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::OriginCaller; +use frame_support::{ + dispatch::DispatchResultWithPostInfo, + traits::{Currency, Get, Imbalance, OnUnbalanced, OriginTrait, PrivilegeCmp}, + weights::Weight, +}; +use log; +use pallet_alliance::{ProposalIndex, ProposalProvider}; +use parachains_common::impls::NegativeImbalance; +use sp_runtime::DispatchError; +use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; +use xcm::latest::{Fungibility, Junction, Parent}; + +type AccountIdOf = ::AccountId; + +type ProposalOf = >::Proposal; + +type HashOf = ::Hash; + +/// Type alias to conveniently refer to the `Currency::Balance` associated type. +pub type BalanceOf = + as Currency<::AccountId>>::Balance; + +/// Implements `OnUnbalanced::on_unbalanced` to teleport slashed assets to relay chain treasury +/// account. +pub struct ToParentTreasury( + PhantomData<(TreasuryAccount, PalletAccount, T)>, +); + +impl OnUnbalanced> + for ToParentTreasury +where + T: pallet_balances::Config + pallet_xcm::Config + frame_system::Config, + <::RuntimeOrigin as OriginTrait>::AccountId: From>, + [u8; 32]: From<::AccountId>, + TreasuryAccount: Get>, + PalletAccount: Get>, + BalanceOf: Into, +{ + fn on_unbalanced(amount: NegativeImbalance) { + let amount = match amount.drop_zero() { + Ok(..) => return, + Err(amount) => amount, + }; + let imbalance = amount.peek(); + let pallet_acc: AccountIdOf = PalletAccount::get(); + let treasury_acc: AccountIdOf = TreasuryAccount::get(); + + >::resolve_creating(&pallet_acc, amount); + + let result = >::teleport_assets( + <::RuntimeOrigin>::signed(pallet_acc.into()), + Box::new(Parent.into()), + Box::new( + Junction::AccountId32 { network: None, id: treasury_acc.into() } + .into_location() + .into(), + ), + Box::new((Parent, imbalance).into()), + 0, + ); + + if let Err(err) = result { + log::warn!("Failed to teleport slashed assets: {:?}", err); + } + } +} + +/// Proposal provider for alliance pallet. +/// Adapter from collective pallet to alliance proposal provider trait. +pub struct AllianceProposalProvider(PhantomData<(T, I)>); + +impl ProposalProvider, HashOf, ProposalOf> + for AllianceProposalProvider +where + T: pallet_collective::Config + frame_system::Config, + I: 'static, +{ + fn propose_proposal( + who: AccountIdOf, + threshold: u32, + proposal: Box>, + length_bound: u32, + ) -> Result<(u32, u32), DispatchError> { + pallet_collective::Pallet::::do_propose_proposed( + who, + threshold, + proposal, + length_bound, + ) + } + + fn vote_proposal( + who: AccountIdOf, + proposal: HashOf, + index: ProposalIndex, + approve: bool, + ) -> Result { + pallet_collective::Pallet::::do_vote(who, proposal, index, approve) + } + + fn close_proposal( + proposal_hash: HashOf, + proposal_index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + pallet_collective::Pallet::::do_close( + proposal_hash, + proposal_index, + proposal_weight_bound, + length_bound, + ) + } + + fn proposal_of(proposal_hash: HashOf) -> Option> { + pallet_collective::Pallet::::proposal_of(proposal_hash) + } +} + +/// Used to compare the privilege of an origin inside the scheduler. +pub struct EqualOrGreatestRootCmp; + +impl PrivilegeCmp for EqualOrGreatestRootCmp { + 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), + _ => None, + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarks { + use super::*; + use crate::ParachainSystem; + use cumulus_primitives_core::{ChannelStatus, GetChannelInfo}; + use frame_support::traits::{ + fungible, + tokens::{Pay, PaymentStatus}, + }; + use pallet_ranked_collective::Rank; + use parachains_common::{AccountId, Balance}; + use sp_runtime::traits::Convert; + + /// Rank to salary conversion helper type. + pub struct RankToSalary(PhantomData); + impl Convert for RankToSalary + where + Fungible: fungible::Inspect, + { + fn convert(r: Rank) -> Balance { + Balance::from(r).saturating_mul(Fungible::minimum_balance()) + } + } + + /// Trait for setting up any prerequisites for successful execution of benchmarks. + pub trait EnsureSuccessful { + fn ensure_successful(); + } + + /// Implementation of the [`EnsureSuccessful`] trait which opens an HRMP channel between + /// the Collectives and a parachain with a given ID. + pub struct OpenHrmpChannel(PhantomData); + impl> EnsureSuccessful for OpenHrmpChannel { + fn ensure_successful() { + if let ChannelStatus::Closed = ParachainSystem::get_channel_status(I::get().into()) { + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(I::get().into()) + } + } + } + + /// Type that wraps a type implementing the [`Pay`] trait to decorate its + /// [`Pay::ensure_successful`] function with a provided implementation of the + /// [`EnsureSuccessful`] trait. + pub struct PayWithEnsure(PhantomData<(O, E)>); + impl Pay for PayWithEnsure + where + O: Pay, + E: EnsureSuccessful, + { + type AssetKind = O::AssetKind; + type Balance = O::Balance; + type Beneficiary = O::Beneficiary; + type Error = O::Error; + type Id = O::Id; + + fn pay( + who: &Self::Beneficiary, + asset_kind: Self::AssetKind, + amount: Self::Balance, + ) -> Result { + O::pay(who, asset_kind, amount) + } + fn check_payment(id: Self::Id) -> PaymentStatus { + O::check_payment(id) + } + fn ensure_successful( + who: &Self::Beneficiary, + asset_kind: Self::AssetKind, + amount: Self::Balance, + ) { + E::ensure_successful(); + O::ensure_successful(who, asset_kind, amount) + } + fn ensure_concluded(id: Self::Id) { + O::ensure_concluded(id) + } + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs new file mode 100644 index 00000000000..8c5593e154d --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -0,0 +1,1023 @@ +// 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. + +//! # Collectives Parachain +//! +//! This parachain is for collectives that serve the Westend network. +//! Each collective is defined by a specialized (possibly instanced) pallet. +//! +//! ### Governance +//! +//! As a system parachain, Collectives defers its governance (namely, its `Root` origin), to +//! its Relay Chain parent, Westend. +//! +//! ### Collator Selection +//! +//! Collectives uses `pallet-collator-selection`, a simple first-come-first-served registration +//! system where collators can reserve a small bond to join the block producer set. There is no +//! slashing. Collective members are generally expected to run collators. + +#![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")); + +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::{pallet_fellowship_origins, Fellows}; +use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp, ToParentTreasury}; +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}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, Perbill, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use codec::{Decode, Encode, MaxEncodedLen}; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +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, + EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, + }, + weights::{ConstantMultiplier, Weight}, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +pub use parachains_common as common; +use parachains_common::{ + impls::DealWithFees, message_queue::*, AccountId, AuraId, Balance, BlockNumber, Hash, Header, + Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, + NORMAL_DISPATCH_RATIO, SLOT_DURATION, +}; +use sp_runtime::RuntimeDebug; +use testnets_common::westend::{account::*, consensus::*, currency::*, fee::WeightToFee}; +use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; + +#[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::{prelude::*, BodyId}; + +use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("collectives-westend"), + impl_name: create_runtime_str!("collectives-westend"), + authoring_version: 1, + spec_version: 1_003_000, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 5, + 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() } +} + +/// Privileged origin that represents Root or more than two thirds of the Alliance. +pub type RootOrAllianceTwoThirdsMajority = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +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(); +} + +// 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 = ConstU16<0>; + 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 RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + 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! { + // 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); +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = ConstU32<100>; + 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); + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); +} + +/// 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. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, + /// Alliance proxy. Allows calls related to the Alliance. + 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 { + Self::Any + } +} +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!(c, RuntimeCall::Balances { .. }), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Alliance => matches!( + c, + RuntimeCall::AllianceMotion { .. } | + RuntimeCall::Alliance { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Fellowship => matches!( + 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 { .. } + ), + } + } + 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 = ConstU32<32>; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + 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 WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + 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 {} + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetId = Concrete(xcm_config::WndLocation::get()); + /// The base fee for the message delivery fees. + pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EitherOfDiverse, Fellows>; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type WeightInfo = weights::cumulus_pallet_dmp_queue::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; +} + +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, ConstU32>; + type NextSessionRotation = pallet_session::PeriodicSessions, ConstU32>; + 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 = ConstU32; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = weights::pallet_collator_selection::WeightInfo; +} + +pub const ALLIANCE_MOTION_DURATION: BlockNumber = 5 * DAYS; + +parameter_types! { + pub const AllianceMotionDuration: BlockNumber = ALLIANCE_MOTION_DURATION; + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} +pub const ALLIANCE_MAX_PROPOSALS: u32 = 100; +pub const ALLIANCE_MAX_MEMBERS: u32 = 100; + +type AllianceCollective = pallet_collective::Instance1; +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = AllianceMotionDuration; + type MaxProposals = ConstU32; + type MaxMembers = ConstU32; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type SetMembersOrigin = EnsureRoot; + type WeightInfo = weights::pallet_collective::WeightInfo; + type MaxProposalWeight = MaxProposalWeight; +} + +pub const MAX_FELLOWS: u32 = ALLIANCE_MAX_MEMBERS; +pub const MAX_ALLIES: u32 = 100; + +parameter_types! { + pub const AllyDeposit: Balance = 1_000 * UNITS; // 1,000 WND bond to join as an Ally + // The Alliance pallet account, used as a temporary place to deposit a slashed imbalance + // before the teleport to the Treasury. + pub AlliancePalletAccount: AccountId = ALLIANCE_PALLET_ID.into_account_truncating(); + pub WestendTreasuryAccount: AccountId = WESTEND_TREASURY_PALLET_ID.into_account_truncating(); + // The number of blocks a member must wait between giving a retirement notice and retiring. + // Supposed to be greater than time required to `kick_member` with alliance motion. + pub const AllianceRetirementPeriod: BlockNumber = (90 * DAYS) + ALLIANCE_MOTION_DURATION; +} + +impl pallet_alliance::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + type AdminOrigin = RootOrAllianceTwoThirdsMajority; + type MembershipManager = RootOrAllianceTwoThirdsMajority; + type AnnouncementOrigin = RootOrAllianceTwoThirdsMajority; + type Currency = Balances; + type Slashed = ToParentTreasury; + type InitializeMembers = AllianceMotion; + type MembershipChanged = AllianceMotion; + type RetirementPeriod = AllianceRetirementPeriod; + type IdentityVerifier = (); // Don't block accounts on identity criteria + type ProposalProvider = AllianceProposalProvider; + type MaxProposals = ConstU32; + type MaxFellows = ConstU32; + type MaxAllies = ConstU32; + type MaxUnscrupulousItems = ConstU32<100>; + type MaxWebsiteUrlLength = ConstU32<255>; + type MaxAnnouncementsCount = ConstU32<100>; + type MaxMembersCount = ConstU32; + type AllyDeposit = AllyDeposit; + type WeightInfo = weights::pallet_alliance::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +#[cfg(not(feature = "runtime-benchmarks"))] +parameter_types! { + pub const MaxScheduledPerBlock: u32 = 50; +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub const MaxScheduledPerBlock: u32 = 200; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualOrGreatestRootCmp; + 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, + >; +} + +// 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} = 2, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, + + // 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, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, + + // 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, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 43, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 44, + + // The main stage. + + // The Alliance. + Alliance: pallet_alliance::{Pallet, Call, Storage, Event, Config} = 50, + AllianceMotion: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 51, + + // The Fellowship. + // pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; + FellowshipCollective: pallet_ranked_collective::::{Pallet, Call, Storage, Event} = 60, + // pub type FellowshipReferendaInstance = pallet_referenda::Instance1; + FellowshipReferenda: pallet_referenda::::{Pallet, Call, Storage, Event} = 61, + FellowshipOrigins: pallet_fellowship_origins::{Origin} = 62, + // pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1; + 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, + } +); + +/// 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, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +/// All migrations executed on runtime upgrade as a nested tuple of types implementing +/// `OnRuntimeUpgrade`. Included migrations must be idempotent. +type Migrations = ( + // unreleased + 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")] +mod benches { + frame_benchmarking::define_benchmarks!( + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_message_queue, MessageQueue] + [pallet_multisig, Multisig] + [pallet_proxy, Proxy] + [pallet_session, SessionBench::] + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [cumulus_pallet_dmp_queue, DmpQueue] + [pallet_alliance, Alliance] + [pallet_collective, AllianceMotion] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_preimage, Preimage] + [pallet_scheduler, Scheduler] + [pallet_referenda, FellowshipReferenda] + [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] + ); +} + +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_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 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + + 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::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between Collectives and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on Collectives. + None + } + } + + 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(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + 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! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs new file mode 100644 index 00000000000..e7fdb2aae2a --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs new file mode 100644 index 00000000000..cc41dcd6cbb --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_dmp_queue.rs @@ -0,0 +1,131 @@ +// 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_dmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-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=cumulus_pallet_dmp_queue +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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 `cumulus_pallet_dmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_dmp_queue::WeightInfo for WeightInfo { + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65696` + // Estimated: `69161` + // Minimum execution time: 124_651_000 picoseconds. + Weight::from_parts(127_857_000, 0) + .saturating_add(Weight::from_parts(0, 69161)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca7d95d3e948effbeccff2de2c182672836` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65659` + // Estimated: `69124` + // Minimum execution time: 65_684_000 picoseconds. + Weight::from_parts(68_039_000, 0) + .saturating_add(Weight::from_parts(0, 69124)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_overweight_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65726` + // Estimated: `69191` + // Minimum execution time: 117_657_000 picoseconds. + Weight::from_parts(122_035_000, 0) + .saturating_add(Weight::from_parts(0, 69191)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `DmpQueue::MigrationStatus` (r:1 w:1) + /// Proof: `DmpQueue::MigrationStatus` (`max_values`: Some(1), `max_size`: Some(1028), added: 1523, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca754904d6d8c6fe06c4e5965f9b8397421` (r:1 w:0) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca70f923ef3252d0166429d36d20ed665a8` (r:1 w:1) + /// Storage: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xcd5c1f6df63bc97f4a8ce37f14a50ca772275f64c354954352b71eea39cfaca2` (r:1 w:1) + fn on_idle_overweight_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65689` + // Estimated: `69154` + // Minimum execution time: 59_799_000 picoseconds. + Weight::from_parts(61_354_000, 0) + .saturating_add(Weight::from_parts(0, 69154)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..0b7a2fc21cd --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// collectives-polkadot-dev +// --pallet +// cumulus_pallet_parachain_system +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/collectives/collectives-polkadot/src/weights +// --steps +// 50 +// --repeat +// 20 + +#![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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) + /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) + /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) + /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MessageQueue Pages (r:0 w:16) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `48` + // Estimated: `8121` + // Minimum execution time: 1_988_000 picoseconds. + Weight::from_parts(2_039_000, 0) + .saturating_add(Weight::from_parts(0, 8121)) + // Standard Error: 30_660 + .saturating_add(Weight::from_parts(24_419_204, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 00000000000..e68c075bffc --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -0,0 +1,148 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Olivers-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --pallet +// cumulus-pallet-xcmp-queue +// --chain +// collectives-polkadot-dev +// --output +// cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +// --extrinsic +// + +#![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: `142` + // Estimated: `1627` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) + .saturating_add(Weight::from_parts(0, 1627)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `148` + // Estimated: `3517` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1627` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 0) + .saturating_add(Weight::from_parts(0, 1627)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `177` + // Estimated: `1662` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(Weight::from_parts(0, 1662)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) + /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65777` + // Estimated: `69242` + // Minimum execution time: 60_000_000 picoseconds. + Weight::from_parts(63_000_000, 0) + .saturating_add(Weight::from_parts(0, 69242)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65776` + // Estimated: `69241` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 69241)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs new file mode 100644 index 00000000000..1a4adb968bb --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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/collectives/collectives-westend/src/weights/frame_system.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system.rs new file mode 100644 index 00000000000..b6f1dc8dc08 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system.rs @@ -0,0 +1,154 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-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/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 `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_926_000 picoseconds. + Weight::from_parts(1_929_666, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) + } + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_221_000 picoseconds. + Weight::from_parts(34_449_539, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_706, 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_681_000 picoseconds. + Weight::from_parts(3_857_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: `156` + // Estimated: `1641` + // Minimum execution time: 101_899_621_000 picoseconds. + Weight::from_parts(106_377_672_000, 0) + .saturating_add(Weight::from_parts(0, 1641)) + .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_039_000 picoseconds. + Weight::from_parts(2_094_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_124 + .saturating_add(Weight::from_parts(754_465, 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_103_000 picoseconds. + Weight::from_parts(2_182_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_031 + .saturating_add(Weight::from_parts(570_563, 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: `82 + p * (69 ±0)` + // Estimated: `78 + p * (70 ±0)` + // Minimum execution time: 3_728_000 picoseconds. + Weight::from_parts(3_836_000, 0) + .saturating_add(Weight::from_parts(0, 78)) + // Standard Error: 1_802 + .saturating_add(Weight::from_parts(1_199_345, 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/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs new file mode 100644 index 00000000000..1d877fdbd2b --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -0,0 +1,50 @@ +// 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 block_weights; +pub mod cumulus_pallet_dmp_queue; +pub mod cumulus_pallet_parachain_system; +pub mod cumulus_pallet_xcmp_queue; +pub mod extrinsic_weights; +pub mod frame_system; +pub mod pallet_alliance; +pub mod pallet_balances; +pub mod pallet_collator_selection; +pub mod pallet_collective; +pub mod pallet_collective_content; +pub mod pallet_core_fellowship_ambassador_core; +pub mod pallet_core_fellowship_fellowship_core; +pub mod pallet_message_queue; +pub mod pallet_multisig; +pub mod pallet_preimage; +pub mod pallet_proxy; +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; +pub mod pallet_utility; +pub mod pallet_xcm; +pub mod paritydb_weights; +pub mod rocksdb_weights; + +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/collectives/collectives-westend/src/weights/pallet_alliance.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_alliance.rs new file mode 100644 index 00000000000..d8ede609a67 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_alliance.rs @@ -0,0 +1,494 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_alliance` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_alliance +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![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_alliance`. +pub struct WeightInfo(PhantomData); +impl pallet_alliance::WeightInfo for WeightInfo { + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `439 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` + // Minimum execution time: 32_783_000 picoseconds. + Weight::from_parts(32_174_037, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 198 + .saturating_add(Weight::from_parts(1_220, 0).saturating_mul(b.into())) + // Standard Error: 2_074 + .saturating_add(Weight::from_parts(40_945, 0).saturating_mul(m.into())) + // Standard Error: 2_048 + .saturating_add(Weight::from_parts(181_087, 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, 32).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `868 + m * (64 ±0)` + // Estimated: `6676 + m * (64 ±0)` + // Minimum execution time: 28_520_000 picoseconds. + Weight::from_parts(29_661_024, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 2_336 + .saturating_add(Weight::from_parts(89_873, 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: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` + // Minimum execution time: 39_353_000 picoseconds. + Weight::from_parts(33_028_008, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 2_137 + .saturating_add(Weight::from_parts(90_946, 0).saturating_mul(m.into())) + // Standard Error: 2_084 + .saturating_add(Weight::from_parts(175_827, 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, 97).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(_b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `762 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` + // Minimum execution time: 52_835_000 picoseconds. + Weight::from_parts(45_963_292, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 3_189 + .saturating_add(Weight::from_parts(111_627, 0).saturating_mul(m.into())) + // Standard Error: 3_109 + .saturating_add(Weight::from_parts(207_923, 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, 97).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) + } + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::Rule` (r:0 w:1) + /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `518 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `6676 + m * (109 ±0) + p * (43 ±0)` + // Minimum execution time: 49_980_000 picoseconds. + Weight::from_parts(48_110_301, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 5_057 + .saturating_add(Weight::from_parts(169_065, 0).saturating_mul(m.into())) + // Standard Error: 4_995 + .saturating_add(Weight::from_parts(201_349, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 109).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(p.into())) + } + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[5, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `417 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `6676 + m * (96 ±0) + p * (36 ±0)` + // Minimum execution time: 40_646_000 picoseconds. + Weight::from_parts(36_865_909, 0) + .saturating_add(Weight::from_parts(0, 6676)) + // Standard Error: 2_136 + .saturating_add(Weight::from_parts(74_341, 0).saturating_mul(m.into())) + // Standard Error: 2_059 + .saturating_add(Weight::from_parts(170_035, 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, 96).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:1 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[1, 100]`. + /// The range of component `z` is `[0, 100]`. + fn init_members(m: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `12362` + // Minimum execution time: 29_710_000 picoseconds. + Weight::from_parts(17_762_170, 0) + .saturating_add(Weight::from_parts(0, 12362)) + // Standard Error: 1_652 + .saturating_add(Weight::from_parts(156_967, 0).saturating_mul(m.into())) + // Standard Error: 1_632 + .saturating_add(Weight::from_parts(130_352, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:200 w:50) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:50 w:50) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 100]`. + /// The range of component `y` is `[0, 100]`. + /// The range of component `z` is `[0, 50]`. + fn disband(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (52 ±0) + y * (53 ±0) + z * (250 ±0)` + // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` + // Minimum execution time: 294_258_000 picoseconds. + Weight::from_parts(295_116_000, 0) + .saturating_add(Weight::from_parts(0, 12362)) + // Standard Error: 23_663 + .saturating_add(Weight::from_parts(553_978, 0).saturating_mul(x.into())) + // Standard Error: 23_549 + .saturating_add(Weight::from_parts(567_024, 0).saturating_mul(y.into())) + // Standard Error: 47_055 + .saturating_add(Weight::from_parts(15_439_056, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) + } + /// Storage: `Alliance::Rule` (r:0 w:1) + /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) + fn set_rule() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_538_000 picoseconds. + Weight::from_parts(8_752_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Alliance::Announcements` (r:1 w:1) + /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + fn announce() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `10187` + // Minimum execution time: 11_213_000 picoseconds. + Weight::from_parts(11_792_000, 0) + .saturating_add(Weight::from_parts(0, 10187)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Alliance::Announcements` (r:1 w:1) + /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + fn remove_announcement() -> Weight { + // Proof Size summary in bytes: + // Measured: `149` + // Estimated: `10187` + // Minimum execution time: 12_477_000 picoseconds. + Weight::from_parts(12_942_000, 0) + .saturating_add(Weight::from_parts(0, 10187)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:0 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn join_alliance() -> Weight { + // Proof Size summary in bytes: + // Measured: `294` + // Estimated: `18048` + // Minimum execution time: 41_517_000 picoseconds. + Weight::from_parts(42_433_000, 0) + .saturating_add(Weight::from_parts(0, 18048)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + fn nominate_ally() -> Weight { + // Proof Size summary in bytes: + // Measured: `193` + // Estimated: `18048` + // Minimum execution time: 25_950_000 picoseconds. + Weight::from_parts(26_631_000, 0) + .saturating_add(Weight::from_parts(0, 18048)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn elevate_ally() -> Weight { + // Proof Size summary in bytes: + // Measured: `236` + // Estimated: `12362` + // Minimum execution time: 24_470_000 picoseconds. + Weight::from_parts(25_222_000, 0) + .saturating_add(Weight::from_parts(0, 12362)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Alliance::Members` (r:4 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::RetiringMembers` (r:0 w:1) + /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn give_retirement_notice() -> Weight { + // Proof Size summary in bytes: + // Measured: `236` + // Estimated: `23734` + // Minimum execution time: 31_519_000 picoseconds. + Weight::from_parts(32_827_000, 0) + .saturating_add(Weight::from_parts(0, 23734)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Alliance::RetiringMembers` (r:1 w:1) + /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Alliance::Members` (r:1 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn retire() -> Weight { + // Proof Size summary in bytes: + // Measured: `517` + // Estimated: `6676` + // Minimum execution time: 38_799_000 picoseconds. + Weight::from_parts(39_634_000, 0) + .saturating_add(Weight::from_parts(0, 6676)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r: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`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn kick_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `643` + // Estimated: `18048` + // Minimum execution time: 137_442_000 picoseconds. + Weight::from_parts(142_142_000, 0) + .saturating_add(Weight::from_parts(0, 18048)) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. + fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `27187` + // Minimum execution time: 7_189_000 picoseconds. + Weight::from_parts(7_387_000, 0) + .saturating_add(Weight::from_parts(0, 27187)) + // Standard Error: 3_417 + .saturating_add(Weight::from_parts(1_581_413, 0).saturating_mul(n.into())) + // Standard Error: 1_338 + .saturating_add(Weight::from_parts(67_739, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + l * (100 ±0) + n * (289 ±0)` + // Estimated: `27187` + // Minimum execution time: 7_201_000 picoseconds. + Weight::from_parts(7_325_000, 0) + .saturating_add(Weight::from_parts(0, 27187)) + // Standard Error: 183_302 + .saturating_add(Weight::from_parts(16_886_382, 0).saturating_mul(n.into())) + // Standard Error: 71_789 + .saturating_add(Weight::from_parts(352_937, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Alliance::Members` (r:3 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn abdicate_fellow_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `236` + // Estimated: `18048` + // Minimum execution time: 29_653_000 picoseconds. + Weight::from_parts(30_365_000, 0) + .saturating_add(Weight::from_parts(0, 18048)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs new file mode 100644 index 00000000000..6c1cf072257 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs @@ -0,0 +1,152 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_balances` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_balances +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![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_696_000 picoseconds. + Weight::from_parts(56_582_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: 40_885_000 picoseconds. + Weight::from_parts(41_993_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: `103` + // Estimated: `3593` + // Minimum execution time: 14_565_000 picoseconds. + Weight::from_parts(15_080_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: `103` + // Estimated: `3593` + // Minimum execution time: 22_158_000 picoseconds. + Weight::from_parts(22_715_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_957_000 picoseconds. + Weight::from_parts(58_618_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: 52_018_000 picoseconds. + Weight::from_parts(52_795_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: `103` + // Estimated: `3593` + // Minimum execution time: 17_469_000 picoseconds. + Weight::from_parts(18_030_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `System::Account` (r:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 17_223_000 picoseconds. + Weight::from_parts(17_587_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 16_201 + .saturating_add(Weight::from_parts(15_360_967, 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/collectives/collectives-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collator_selection.rs new file mode 100644 index 00000000000..03f3ff602a5 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collator_selection.rs @@ -0,0 +1,246 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-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/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_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: 14_616_000 picoseconds. + Weight::from_parts(12_150_410, 0) + .saturating_add(Weight::from_parts(0, 1154)) + // Standard Error: 6_270 + .saturating_add(Weight::from_parts(3_256_932, 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: 48_450_000 picoseconds. + Weight::from_parts(51_166_679, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_588 + .saturating_add(Weight::from_parts(167_219, 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: 15_830_000 picoseconds. + Weight::from_parts(15_792_847, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 5_343 + .saturating_add(Weight::from_parts(167_955, 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_424_000 picoseconds. + Weight::from_parts(7_767_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(_c: u32, _k: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_388_000 picoseconds. + Weight::from_parts(7_677_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: 41_241_000 picoseconds. + Weight::from_parts(46_090_319, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_918 + .saturating_add(Weight::from_parts(161_140, 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_221_000 picoseconds. + Weight::from_parts(36_183_872, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(168_742, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + fn update_bond(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)) + } + fn take_candidate_slot(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: 43_910_000 picoseconds. + Weight::from_parts(44_796_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_092_000 picoseconds. + Weight::from_parts(17_635_000, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 351_635 + .saturating_add(Weight::from_parts(15_162_192, 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/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs new file mode 100644 index 00000000000..9133baa6120 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs @@ -0,0 +1,304 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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: `[]` +//! 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 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_collective +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![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: `AllianceMotion::Members` (r:1 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:100 w:100) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `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: `15691 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 16_410_000 picoseconds. + Weight::from_parts(16_816_000, 0) + .saturating_add(Weight::from_parts(0, 15691)) + // Standard Error: 59_812 + .saturating_add(Weight::from_parts(4_516_537, 0).saturating_mul(m.into())) + // Standard Error: 59_812 + .saturating_add(Weight::from_parts(7_992_168, 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: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::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]`. + fn execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32 + m * (32 ±0)` + // Estimated: `1518 + m * (32 ±0)` + // Minimum execution time: 14_418_000 picoseconds. + Weight::from_parts(13_588_617, 0) + .saturating_add(Weight::from_parts(0, 1518)) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_711, 0).saturating_mul(b.into())) + // Standard Error: 223 + .saturating_add(Weight::from_parts(13_836, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) + } + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:0) + /// Proof: `AllianceMotion::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]`. + fn propose_execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32 + m * (32 ±0)` + // Estimated: `3498 + m * (32 ±0)` + // Minimum execution time: 17_174_000 picoseconds. + Weight::from_parts(16_192_764, 0) + .saturating_add(Weight::from_parts(0, 3498)) + // Standard Error: 27 + .saturating_add(Weight::from_parts(1_672, 0).saturating_mul(b.into())) + // Standard Error: 280 + .saturating_add(Weight::from_parts(24_343, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) + } + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[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: `322 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3714 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 23_970_000 picoseconds. + Weight::from_parts(23_004_052, 0) + .saturating_add(Weight::from_parts(0, 3714)) + // Standard Error: 123 + .saturating_add(Weight::from_parts(2_728, 0).saturating_mul(b.into())) + // Standard Error: 1_291 + .saturating_add(Weight::from_parts(32_731, 0).saturating_mul(m.into())) + // Standard Error: 1_275 + .saturating_add(Weight::from_parts(199_537, 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: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `771 + m * (64 ±0)` + // Estimated: `4235 + m * (64 ±0)` + // Minimum execution time: 25_843_000 picoseconds. + Weight::from_parts(26_092_578, 0) + .saturating_add(Weight::from_parts(0, 4235)) + // Standard Error: 1_785 + .saturating_add(Weight::from_parts(67_298, 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: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `360 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3805 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 27_543_000 picoseconds. + Weight::from_parts(26_505_473, 0) + .saturating_add(Weight::from_parts(0, 3805)) + // Standard Error: 1_054 + .saturating_add(Weight::from_parts(35_295, 0).saturating_mul(m.into())) + // Standard Error: 1_028 + .saturating_add(Weight::from_parts(190_508, 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: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `662 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `3979 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 40_375_000 picoseconds. + Weight::from_parts(34_081_294, 0) + .saturating_add(Weight::from_parts(0, 3979)) + // Standard Error: 196 + .saturating_add(Weight::from_parts(3_796, 0).saturating_mul(b.into())) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(50_954, 0).saturating_mul(m.into())) + // Standard Error: 2_020 + .saturating_add(Weight::from_parts(246_000, 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: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `458 + m * (48 ±0) + p * (36 ±0)` + // Estimated: `3898 + m * (49 ±0) + p * (36 ±0)` + // Minimum execution time: 28_793_000 picoseconds. + Weight::from_parts(29_656_832, 0) + .saturating_add(Weight::from_parts(0, 3898)) + // Standard Error: 1_214 + .saturating_add(Weight::from_parts(22_148, 0).saturating_mul(m.into())) + // Standard Error: 1_184 + .saturating_add(Weight::from_parts(189_860, 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, 49).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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: `682 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `3999 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 40_887_000 picoseconds. + Weight::from_parts(39_529_567, 0) + .saturating_add(Weight::from_parts(0, 3999)) + // Standard Error: 191 + .saturating_add(Weight::from_parts(2_802, 0).saturating_mul(b.into())) + // Standard Error: 2_021 + .saturating_add(Weight::from_parts(35_956, 0).saturating_mul(m.into())) + // Standard Error: 1_970 + .saturating_add(Weight::from_parts(235_154, 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: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[1, 100]`. + fn disapprove_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `189 + p * (32 ±0)` + // Estimated: `1674 + p * (32 ±0)` + // Minimum execution time: 14_040_000 picoseconds. + Weight::from_parts(15_075_964, 0) + .saturating_add(Weight::from_parts(0, 1674)) + // Standard Error: 854 + .saturating_add(Weight::from_parts(159_597, 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/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective_content.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective_content.rs new file mode 100644 index 00000000000..6be94db22db --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective_content.rs @@ -0,0 +1,93 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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-westend/src/weights/pallet_core_fellowship_ambassador_core.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs new file mode 100644 index 00000000000..f40940a8b25 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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-westend/src/weights/pallet_core_fellowship_fellowship_core.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs new file mode 100644 index 00000000000..471ee82ead7 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs @@ -0,0 +1,222 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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: `FellowshipCore::Params` (r:0 w:1) + /// Proof: `FellowshipCore::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(12_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Params` (r:1 w:0) + /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, 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:0) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn bump_offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `66144` + // Estimated: `69046` + // 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)) + } + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Params` (r:1 w:0) + /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, 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:0) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn bump_demote() -> Weight { + // Proof Size summary in bytes: + // Measured: `66254` + // Estimated: `69046` + // 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)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + fn set_active() -> Weight { + // Proof Size summary in bytes: + // Measured: `493` + // Estimated: `3514` + // 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)) + } + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// 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 induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `3514` + // 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)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Params` (r:1 w:0) + /// Proof: `FellowshipCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:1) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, 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 promote() -> Weight { + // Proof Size summary in bytes: + // Measured: `66122` + // Estimated: `69046` + // 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)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:0 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `464` + // Estimated: `3514` + // 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)) + } + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + fn import() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `3514` + // 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)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::Member` (r:1 w:1) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn approve() -> Weight { + // Proof Size summary in bytes: + // Measured: `66100` + // Estimated: `69046` + // 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)) + } + /// Storage: `FellowshipCore::Member` (r:1 w:0) + /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCore::MemberEvidence` (r:1 w:1) + /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn submit_evidence() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `69046` + // 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-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..4bd71c4e7d4 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-24, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// collectives-polkadot-dev +// --pallet +// pallet_message_queue +// --extrinsic +// * +// --execution +// wasm +// --wasm-execution +// compiled +// --output +// parachains/runtimes/collectives/collectives-polkadot/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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `7534` + // Minimum execution time: 11_440_000 picoseconds. + Weight::from_parts(11_440_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `184` + // Estimated: `7534` + // Minimum execution time: 11_077_000 picoseconds. + Weight::from_parts(11_077_000, 0) + .saturating_add(Weight::from_parts(0, 7534)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 3_977_000 picoseconds. + Weight::from_parts(3_977_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 4_831_000 picoseconds. + Weight::from_parts(4_831_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_192_000 picoseconds. + Weight::from_parts(5_192_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 58_750_000 picoseconds. + Weight::from_parts(58_750_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(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `99` + // Estimated: `5007` + // Minimum execution time: 5_107_000 picoseconds. + Weight::from_parts(5_107_000, 0) + .saturating_add(Weight::from_parts(0, 5007)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 46_814_000 picoseconds. + Weight::from_parts(46_814_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 52_510_000 picoseconds. + Weight::from_parts(52_510_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `72567` + // Minimum execution time: 71_930_000 picoseconds. + Weight::from_parts(71_930_000, 0) + .saturating_add(Weight::from_parts(0, 72567)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_multisig.rs new file mode 100644 index 00000000000..a7827b72009 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_multisig.rs @@ -0,0 +1,164 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_multisig` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_multisig +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_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_288_000 picoseconds. + Weight::from_parts(14_235_741, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 5 + .saturating_add(Weight::from_parts(500, 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: `328 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 44_865_000 picoseconds. + Weight::from_parts(33_468_056, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_513 + .saturating_add(Weight::from_parts(130_544, 0).saturating_mul(s.into())) + // Standard Error: 14 + .saturating_add(Weight::from_parts(1_422, 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: `348` + // Estimated: `6811` + // Minimum execution time: 29_284_000 picoseconds. + Weight::from_parts(18_708_967, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 916 + .saturating_add(Weight::from_parts(119_202, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_447, 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: `451 + s * (33 ±0)` + // Estimated: `6811` + // Minimum execution time: 49_462_000 picoseconds. + Weight::from_parts(34_470_286, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(178_227, 0).saturating_mul(s.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_644, 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: `329 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 30_749_000 picoseconds. + Weight::from_parts(31_841_438, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_033 + .saturating_add(Weight::from_parts(123_126, 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: `348` + // Estimated: `6811` + // Minimum execution time: 17_436_000 picoseconds. + Weight::from_parts(18_036_002, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 829 + .saturating_add(Weight::from_parts(109_450, 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: `520 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 31_532_000 picoseconds. + Weight::from_parts(32_818_015, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 977 + .saturating_add(Weight::from_parts(123_121, 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/collectives/collectives-westend/src/weights/pallet_preimage.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_preimage.rs new file mode 100644 index 00000000000..9b45c875818 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_preimage.rs @@ -0,0 +1,232 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_preimage` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_preimage +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![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: `177` + // Estimated: `3556` + // Minimum execution time: 29_323_000 picoseconds. + Weight::from_parts(29_793_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_504, 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: `140` + // Estimated: `3556` + // Minimum execution time: 15_581_000 picoseconds. + Weight::from_parts(15_659_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_500, 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: `140` + // Estimated: `3556` + // Minimum execution time: 15_028_000 picoseconds. + Weight::from_parts(15_150_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_560, 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: `323` + // Estimated: `3556` + // Minimum execution time: 55_113_000 picoseconds. + Weight::from_parts(59_127_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: `178` + // Estimated: `3556` + // Minimum execution time: 38_033_000 picoseconds. + Weight::from_parts(41_203_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: `222` + // Estimated: `3556` + // Minimum execution time: 31_482_000 picoseconds. + Weight::from_parts(34_726_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: `178` + // Estimated: `3556` + // Minimum execution time: 20_724_000 picoseconds. + Weight::from_parts(22_928_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: `76` + // Estimated: `3556` + // Minimum execution time: 27_015_000 picoseconds. + Weight::from_parts(29_240_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: `140` + // Estimated: `3556` + // Minimum execution time: 10_712_000 picoseconds. + Weight::from_parts(11_317_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: `178` + // Estimated: `3556` + // Minimum execution time: 34_528_000 picoseconds. + Weight::from_parts(35_982_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: `140` + // Estimated: `3556` + // Minimum execution time: 11_059_000 picoseconds. + Weight::from_parts(12_458_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: `140` + // Estimated: `3556` + // Minimum execution time: 11_502_000 picoseconds. + Weight::from_parts(12_180_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/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_proxy.rs new file mode 100644 index 00000000000..59d9f912bf1 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_proxy.rs @@ -0,0 +1,225 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-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/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_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: 15_597_000 picoseconds. + Weight::from_parts(16_231_993, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(29_818, 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: 36_685_000 picoseconds. + Weight::from_parts(36_376_358, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 3_003 + .saturating_add(Weight::from_parts(133_776, 0).saturating_mul(a.into())) + // Standard Error: 3_103 + .saturating_add(Weight::from_parts(60_315, 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: 23_835_000 picoseconds. + Weight::from_parts(24_154_219, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_580 + .saturating_add(Weight::from_parts(125_884, 0).saturating_mul(a.into())) + // Standard Error: 1_632 + .saturating_add(Weight::from_parts(21_563, 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: 23_997_000 picoseconds. + Weight::from_parts(24_301_638, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_658 + .saturating_add(Weight::from_parts(133_005, 0).saturating_mul(a.into())) + // Standard Error: 1_713 + .saturating_add(Weight::from_parts(20_237, 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_604_000 picoseconds. + Weight::from_parts(33_322_880, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_840 + .saturating_add(Weight::from_parts(114_037, 0).saturating_mul(a.into())) + // Standard Error: 1_901 + .saturating_add(Weight::from_parts(45_629, 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_634_000 picoseconds. + Weight::from_parts(25_509_118, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_278 + .saturating_add(Weight::from_parts(38_401, 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: 24_855_000 picoseconds. + Weight::from_parts(25_753_505, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_819 + .saturating_add(Weight::from_parts(44_357, 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_211_000 picoseconds. + Weight::from_parts(23_094_124, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_597 + .saturating_add(Weight::from_parts(36_725, 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_764_000 picoseconds. + Weight::from_parts(27_667_535, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_111 + .saturating_add(Weight::from_parts(3_422, 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: 22_632_000 picoseconds. + Weight::from_parts(23_678_772, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_136 + .saturating_add(Weight::from_parts(26_492, 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/collectives/collectives-westend/src/weights/pallet_ranked_collective_ambassador_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_ranked_collective_ambassador_collective.rs new file mode 100644 index 00000000000..a6372c4b89d --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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-westend/src/weights/pallet_ranked_collective_fellowship_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_ranked_collective_fellowship_collective.rs new file mode 100644 index 00000000000..9c773c56ac3 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_ranked_collective_fellowship_collective.rs @@ -0,0 +1,176 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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: `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: `142` + // Estimated: `3507` + // 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)) + } + /// 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]`. + /// The range of component `r` is `[0, 10]`. + fn remove_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `608 + r * (281 ±0)` + // Estimated: `3519 + r * (2529 ±0)` + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_500_000, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // 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)) + .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]`. + /// The range of component `r` is `[0, 10]`. + fn promote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `310 + r * (17 ±0)` + // Estimated: `3507` + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(25_500_000, 0) + .saturating_add(Weight::from_parts(0, 3507)) + // 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)) + } + /// 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]`. + /// The range of component `r` is `[0, 10]`. + fn demote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `608 + r * (71 ±0)` + // Estimated: `3519` + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(37_500_000, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `317568` + // 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)) + } + /// 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]`. + /// The range of component `n` is `[0, 100]`. + fn cleanup_poll(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // 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: 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, 2550).saturating_mul(n.into())) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_ambassador_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_ambassador_referenda.rs new file mode 100644 index 00000000000..fdc451c5d31 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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-westend/src/weights/pallet_referenda_fellowship_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_fellowship_referenda.rs new file mode 100644 index 00000000000..63f68833795 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_referenda_fellowship_referenda.rs @@ -0,0 +1,535 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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: `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(155814), added: 158289, 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: `389` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `317568` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2038` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2079` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `836` + // Estimated: `317568` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `735` + // Estimated: `317568` + // 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)) + } + /// 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: 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)) + } + /// 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: 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `345` + // Estimated: `317568` + // 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)) + } + /// 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(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: `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: `587` + // Estimated: `317568` + // 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)) + } + /// 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: 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2452` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2452` + // Estimated: `159279` + // 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)) + } + /// 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: 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)) + } + /// 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: 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)) + } + /// 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_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)) + } + /// 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: 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `297` + // 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: `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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `345` + // Estimated: `159279` + // 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)) + } + /// 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: 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `680` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `781` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `834` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `817` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `834` + // Estimated: `159279` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `159279` + // 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)) + } + /// 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(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: `838` + // Estimated: `317568` + // 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)) + } + /// 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(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `834` + // 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: `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: `453` + // Estimated: `4365` + // 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)) + } + /// 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: 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-westend/src/weights/pallet_salary_ambassador_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_salary_ambassador_salary.rs new file mode 100644 index 00000000000..0522420f2f5 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/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-westend/src/weights/pallet_salary_fellowship_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_salary_fellowship_salary.rs new file mode 100644 index 00000000000..37680b4e5df --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_salary_fellowship_salary.rs @@ -0,0 +1,189 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + fn init() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1541` + // 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)) + } + /// Storage: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + fn bump() -> Weight { + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `1541` + // 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)) + } + /// Storage: `FellowshipSalary::Status` (r:1 w:0) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) + /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `395` + // Estimated: `3551` + // 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)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) + /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `462` + // Estimated: `3551` + // 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)) + } + /// Storage: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) + /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::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: `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)) + } + /// Storage: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) + /// Proof: `FellowshipSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::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: `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)) + } + /// Storage: `FellowshipSalary::Status` (r:1 w:1) + /// Proof: `FellowshipSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `FellowshipSalary::Claimant` (r:1 w:1) + /// Proof: `FellowshipSalary::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: `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-westend/src/weights/pallet_scheduler.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs new file mode 100644 index 00000000000..cf5610df665 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs @@ -0,0 +1,206 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_scheduler` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_scheduler +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![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: `31` + // Estimated: `1489` + // Minimum execution time: 3_441_000 picoseconds. + Weight::from_parts(3_604_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(155814), added: 158289, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 200]`. + fn service_agenda_base(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + s * (177 ±0)` + // Estimated: `159279` + // Minimum execution time: 2_879_000 picoseconds. + Weight::from_parts(2_963_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 3_764 + .saturating_add(Weight::from_parts(909_557, 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_172_000 picoseconds. + Weight::from_parts(5_294_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: `213 + s * (1 ±0)` + // Estimated: `3678 + s * (1 ±0)` + // Minimum execution time: 19_704_000 picoseconds. + Weight::from_parts(19_903_000, 0) + .saturating_add(Weight::from_parts(0, 3678)) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_394, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .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: 6_359_000 picoseconds. + Weight::from_parts(6_599_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_217_000 picoseconds. + Weight::from_parts(5_333_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn execute_dispatch_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_406_000 picoseconds. + Weight::from_parts(2_541_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn execute_dispatch_unsigned() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_370_000 picoseconds. + Weight::from_parts(2_561_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 199]`. + fn schedule(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + s * (177 ±0)` + // Estimated: `159279` + // Minimum execution time: 11_784_000 picoseconds. + Weight::from_parts(5_574_404, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 7_217 + .saturating_add(Weight::from_parts(1_035_248, 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(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 200]`. + fn cancel(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + s * (177 ±0)` + // Estimated: `159279` + // Minimum execution time: 16_373_000 picoseconds. + Weight::from_parts(3_088_135, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 7_095 + .saturating_add(Weight::from_parts(1_745_270, 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(155814), added: 158289, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 199]`. + fn schedule_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `468 + s * (179 ±0)` + // Estimated: `159279` + // Minimum execution time: 14_822_000 picoseconds. + Weight::from_parts(9_591_402, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 7_151 + .saturating_add(Weight::from_parts(1_058_408, 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(155814), added: 158289, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 200]`. + fn cancel_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `509 + s * (179 ±0)` + // Estimated: `159279` + // Minimum execution time: 18_541_000 picoseconds. + Weight::from_parts(6_522_239, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 8_349 + .saturating_add(Weight::from_parts(1_760_431, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_session.rs new file mode 100644 index 00000000000..2ac0804df89 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_session.rs @@ -0,0 +1,80 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-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/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_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_663_000 picoseconds. + Weight::from_parts(17_246_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: 11_850_000 picoseconds. + Weight::from_parts(12_204_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/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000000..ca06f43f92e --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_timestamp.rs @@ -0,0 +1,74 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_timestamp` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_timestamp +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `49` + // Estimated: `1493` + // Minimum execution time: 7_863_000 picoseconds. + Weight::from_parts(8_183_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: `57` + // Estimated: `0` + // Minimum execution time: 3_460_000 picoseconds. + Weight::from_parts(3_577_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs new file mode 100644 index 00000000000..c60a79d91da --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs @@ -0,0 +1,101 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_utility` +//! +//! 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("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_utility +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_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_650_000 picoseconds. + Weight::from_parts(7_474_437, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_625 + .saturating_add(Weight::from_parts(4_996_146, 0).saturating_mul(c.into())) + } + fn as_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_612_000 picoseconds. + Weight::from_parts(4_774_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_744_000 picoseconds. + Weight::from_parts(10_889_913, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_281 + .saturating_add(Weight::from_parts(5_218_293, 0).saturating_mul(c.into())) + } + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_673_000 picoseconds. + Weight::from_parts(8_980_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_744_000 picoseconds. + Weight::from_parts(7_801_721, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_395 + .saturating_add(Weight::from_parts(5_000_971, 0).saturating_mul(c.into())) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs new file mode 100644 index 00000000000..a3b42cb86c4 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -0,0 +1,323 @@ +// 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-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-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 +// --chain=collectives-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 25_746_000 picoseconds. + Weight::from_parts(26_349_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `1489` + // Minimum execution time: 22_660_000 picoseconds. + Weight::from_parts(23_173_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 reserve_transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn 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: 7_321_000 picoseconds. + Weight::from_parts(7_542_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_232_000 picoseconds. + Weight::from_parts(2_395_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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: `145` + // Estimated: `3610` + // Minimum execution time: 29_006_000 picoseconds. + Weight::from_parts(29_777_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) + .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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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: `363` + // Estimated: `3828` + // Minimum execution time: 31_245_000 picoseconds. + Weight::from_parts(32_125_000, 0) + .saturating_add(Weight::from_parts(0, 3828)) + .saturating_add(T::DbWeight::get().reads(7)) + .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_255_000 picoseconds. + Weight::from_parts(2_399_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: 16_521_000 picoseconds. + Weight::from_parts(17_001_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: 16_486_000 picoseconds. + Weight::from_parts(16_729_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_037_000 picoseconds. + Weight::from_parts(18_310_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_current_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 27_901_000 picoseconds. + Weight::from_parts(28_566_000, 0) + .saturating_add(Weight::from_parts(0, 6152)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// 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_299_000 picoseconds. + Weight::from_parts(9_547_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: 16_768_000 picoseconds. + Weight::from_parts(17_215_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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn migrate_and_notify_old_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `11105` + // Minimum execution time: 35_134_000 picoseconds. + Weight::from_parts(35_883_000, 0) + .saturating_add(Weight::from_parts(0, 11105)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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 new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 4_562_000 picoseconds. + Weight::from_parts(4_802_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7740` + // Estimated: `11205` + // Minimum execution time: 26_865_000 picoseconds. + Weight::from_parts(27_400_000, 0) + .saturating_add(Weight::from_parts(0, 11205)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs new file mode 100644 index 00000000000..25679703831 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 50_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs new file mode 100644 index 00000000000..3dd817aa6f1 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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 { + read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 100_000 * 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 sane() { + // 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/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs new file mode 100644 index 00000000000..d58995827fa --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -0,0 +1,364 @@ +// 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, Balances, BaseDeliveryFee, FeeAssetId, Fellows, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + TransactionByteFee, WeightToFee, WestendTreasuryAccount, XcmpQueue, +}; +use frame_support::{ + match_types, parameter_types, + traits::{ConstU32, Contains, Equals, Everything, Nothing}, + weights::Weight, +}; +use frame_system::EnsureRoot; +use pallet_xcm::XcmPassthrough; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, +}; +use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use westend_runtime_constants::system_parachain; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, + LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, +}; +use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; + +const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + +parameter_types! { + pub const WndLocation: MultiLocation = MultiLocation::parent(); + pub const RelayNetwork: Option = Some(NetworkId::Westend); + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); + pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_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 WndAssetHub: LocatableAssetId = LocatableAssetId { + location: AssetHub::get(), + asset_id: WndLocation::get().into(), + }; +} + +/// 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, +); + +/// 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`. + (), +>; + +/// 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! { + /// 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); + /// A temporary weight value for each XCM instruction. + /// NOTE: This should be removed after we account for PoV weights. + pub const TempFixedXcmWeight: Weight = Weight::from_parts(1_000_000_000, 0); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + // Fellows pluralistic body. + pub const FellowsBodyId: BodyId = BodyId::Technical; +} + +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(_) } + }; +} + +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains for SafeCallFilter { + fn contains(call: &RuntimeCall) -> bool { + #[cfg(feature = "runtime-benchmarks")] + { + if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { + return true + } + } + + matches!( + call, + RuntimeCall::System( + frame_system::Call::set_heap_pages { .. } | + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::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::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | + RuntimeCall::XcmpQueue(..) | + RuntimeCall::MessageQueue(..) | + RuntimeCall::Alliance( + // `init_members` accepts unbounded vecs as arguments, + // but the call can be initiated only by root origin. + pallet_alliance::Call::init_members { .. } | + pallet_alliance::Call::vote { .. } | + pallet_alliance::Call::disband { .. } | + pallet_alliance::Call::set_rule { .. } | + pallet_alliance::Call::announce { .. } | + pallet_alliance::Call::remove_announcement { .. } | + pallet_alliance::Call::join_alliance { .. } | + pallet_alliance::Call::nominate_ally { .. } | + pallet_alliance::Call::elevate_ally { .. } | + pallet_alliance::Call::give_retirement_notice { .. } | + pallet_alliance::Call::retire { .. } | + pallet_alliance::Call::kick_member { .. } | + pallet_alliance::Call::close { .. } | + pallet_alliance::Call::abdicate_fellow_status { .. }, + ) | RuntimeCall::AllianceMotion( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | RuntimeCall::FellowshipCollective( + pallet_ranked_collective::Call::add_member { .. } | + pallet_ranked_collective::Call::promote_member { .. } | + pallet_ranked_collective::Call::demote_member { .. } | + pallet_ranked_collective::Call::remove_member { .. }, + ) | RuntimeCall::FellowshipCore( + pallet_core_fellowship::Call::bump { .. } | + pallet_core_fellowship::Call::set_params { .. } | + pallet_core_fellowship::Call::set_active { .. } | + pallet_core_fellowship::Call::approve { .. } | + pallet_core_fellowship::Call::induct { .. } | + pallet_core_fellowship::Call::promote { .. } | + pallet_core_fellowship::Call::offboard { .. } | + pallet_core_fellowship::Call::submit_evidence { .. } | + pallet_core_fellowship::Call::import { .. }, + ) + ) + } +} + +pub type Barrier = TrailingSetTopicAsId< + DenyThenTry< + DenyReserveTransferToRelayChain, + ( + // Allow local users to buy weight credit. + 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 and its pluralities (i.e. governance bodies) get free execution. + AllowExplicitUnpaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, + ), + >, +>; + +match_types! { + pub type SystemParachains: impl Contains = { + MultiLocation { + parents: 1, + interior: X1(Parachain( + system_parachain::ASSET_HUB_ID | + system_parachain::BRIDGE_HUB_ID | + system_parachain::COLLECTIVES_ID + )), + } + }; +} + +/// Locations that will not be charged fees in the executor, +/// either execution or delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = + (RelayOrOtherSystemParachains, Equals); + +/// 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; + type XcmSender = XcmRouter; + type AssetTransactor = CurrencyTransactor; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Collectives does not recognize a reserve location for any asset. Users must teleport WND + // where allowed (e.g. with the Relay Chain). + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = + UsingComponents>; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = XcmFeeManagerFromComponents< + WaivedLocations, + XcmFeeToAccount, + >; + type MessageExporter = (); + type UniversalAliases = Nothing; + 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; + +pub type PriceForParentDelivery = + ExponentialPrice; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = WithUniqueTopic<( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +)>; + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parent.into()); +} + +/// Type to convert the Fellows origin to a Plurality `MultiLocation` value. +pub type FellowsToPlurality = OriginToPluralityVoice; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // We only allow the Fellows to send messages. + 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 are allowed. + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type WeightInfo = crate::weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml new file mode 100644 index 00000000000..a30cdf35769 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -0,0 +1,138 @@ +[package] +name = "glutton-westend-runtime" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Glutton parachain runtime." + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } + +# 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-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false} +frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true} +frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true} +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} +pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true} +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true} +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} +sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +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} +pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", 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} + +# 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} + +# Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-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 = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } +parachains-common = { path = "../../../common", default-features = false } + +[build-dependencies] +substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } + +[features] +default = [ "std" ] +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-glutton/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] +std = [ + "codec/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", + "frame-executive/std", + "frame-support/std", + "frame-system-benchmarking?/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "frame-try-runtime?/std", + "pallet-aura/std", + "pallet-glutton/std", + "pallet-message-queue/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "parachain-info/std", + "parachains-common/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", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] +try-runtime = [ + "cumulus-pallet-aura-ext/try-runtime", + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", + "pallet-glutton/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", + "parachain-info/try-runtime", + "sp-runtime/try-runtime", +] + +experimental = [ "pallet-aura/experimental" ] + +# A feature that should be enabled when the runtime should be built 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/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs new file mode 100644 index 00000000000..1580e6f07be --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs @@ -0,0 +1,24 @@ +// 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 substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs new file mode 100644 index 00000000000..60107281c22 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -0,0 +1,532 @@ +// 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. + +//! # Glutton Westend Runtime +//! +//! The purpose of the Glutton parachain is to do stress testing on the Kusama +//! network. This runtime targets the Westend runtime to allow development +//! separate to the Kusama runtime. +//! +//! There may be multiple instances of the Glutton parachain deployed and +//! connected to its parent relay chain. +//! +//! These parachains are not holding any real value. Their purpose is to stress +//! test the network. +//! +//! ### Governance +//! +//! Glutton defers its governance (namely, its `Root` origin), to its Relay +//! Chain parent, Kusama (or Westend for development purposes). +//! +//! ### XCM +//! +//! Since the main goal of Glutton is solely stress testing, the parachain will +//! only be able receive XCM messages from the Relay Chain via DMP. This way the +//! Glutton parachains will be able to listen for upgrades that are coming from +//! the Relay chain. + +#![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")); + +pub mod weights; +pub mod xcm_config; + +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; +use sp_api::impl_runtime_apis; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use cumulus_primitives_core::AggregateMessageOrigin; +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, + }, + weights::{ + constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, + }, + IdentityFee, Weight, + }, + PalletId, StorageValue, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +use parachains_common::{AccountId, Signature}; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{Perbill, Permill}; + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("glutton-westend"), + impl_name: create_runtime_str!("glutton-westend"), + authoring_version: 1, + spec_version: 10000, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +/// 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() } +} + +/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. +/// This is used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used +/// by Operational extrinsics. +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_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; + 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; +} + +impl frame_system::Config for Runtime { + 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 Version = Version; + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = frame_support::traits::Everything; + type SystemWeightInfo = (); + type BlockWeights = RuntimeBlockWeights; + type BlockLength = RuntimeBlockLength; + type SS58Prefix = SS58Prefix; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + // We do anything the parent chain tells us in this runtime. + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(2); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +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 = (); + type SelfParaId = parachain_info::Pallet; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = (); + type ReservedXcmpWeight = (); + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + type ConsensusHook = ConsensusHook; + type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; +} + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(80) * + RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_message_queue::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + type QueueChangeHandler = (); + type QueuePausedQuery = (); // No XCMP queue pallet deployed. + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; +} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = Aura; + #[cfg(feature = "experimental")] + type MinimumPeriod = ConstU64<0>; + #[cfg(not(feature = "experimental"))] + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = weights::pallet_timestamp::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 = ConstU64; +} + +impl pallet_glutton::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_glutton::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); +} + +construct_runtime! { + pub enum Runtime + { + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{ + Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, + } = 1, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 2, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + + // DMP handler. + CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 10, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 11, + + // The main stage. + Glutton: pallet_glutton::{Pallet, Call, Storage, Event, Config} = 20, + + // Collator support + Aura: pallet_aura::{Pallet, Storage, Config} = 30, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 31, + + // Sudo. + Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, + } +} + +/// Index of a transaction in the chain. +pub type Nonce = u32; +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; +/// An index to a block. +pub type BlockNumber = u32; +/// 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 = ( + pallet_sudo::CheckOnlySudoAccount, + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, +); +/// 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, +>; + +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [cumulus_pallet_parachain_system, ParachainSystem] + [frame_system, SystemBench::] + [pallet_glutton, Glutton] + [pallet_message_queue, MessageQueue] + [pallet_timestamp, Timestamp] + ); +} + +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 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 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, + ) -> 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 cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + #[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; + + 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 frame_support::traits::WhitelistedStorageKeys; + let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + 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! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000000..bc8299ab1bd --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,75 @@ +// 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_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, 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=cumulus_pallet_parachain_system +// --chain=glutton-westend-dev-1300 +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-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 `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::LastDmqMqcHead` (r:1 w:1) + /// Proof: `ParachainSystem::LastDmqMqcHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ProcessedDownwardMessages` (r:0 w:1) + /// Proof: `ParachainSystem::ProcessedDownwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1000) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `3517` + // Minimum execution time: 1_745_000 picoseconds. + Weight::from_parts(1_859_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + // Standard Error: 53_384 + .saturating_add(Weight::from_parts(196_309_089, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system.rs new file mode 100644 index 00000000000..6f8cf4f39df --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system.rs @@ -0,0 +1,153 @@ +// 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-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, 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=frame_system +// --chain=glutton-westend-dev-1300 +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-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 `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_570_000 picoseconds. + Weight::from_parts(1_626_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) + } + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_200_000 picoseconds. + Weight::from_parts(4_262_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_791, 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: 2_680_000 picoseconds. + Weight::from_parts(2_936_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: `127` + // Estimated: `1612` + // Minimum execution time: 119_097_302_000 picoseconds. + Weight::from_parts(120_914_576_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .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: 1_606_000 picoseconds. + Weight::from_parts(1_704_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_090 + .saturating_add(Weight::from_parts(765_829, 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: 1_646_000 picoseconds. + Weight::from_parts(1_719_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_067 + .saturating_add(Weight::from_parts(578_598, 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: `58 + p * (69 ±0)` + // Estimated: `53 + p * (70 ±0)` + // Minimum execution time: 2_933_000 picoseconds. + Weight::from_parts(3_069_000, 0) + .saturating_add(Weight::from_parts(0, 53)) + // Standard Error: 1_844 + .saturating_add(Weight::from_parts(1_214_377, 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/glutton/glutton-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/mod.rs new file mode 100644 index 00000000000..47f9d1ee105 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/mod.rs @@ -0,0 +1,19 @@ +// 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 cumulus_pallet_parachain_system; +pub mod pallet_glutton; +pub mod pallet_message_queue; +pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_glutton.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_glutton.rs new file mode 100644 index 00000000000..9345458a704 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_glutton.rs @@ -0,0 +1,178 @@ +// 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_glutton` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, 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_glutton +// --chain=glutton-westend-dev-1300 +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-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_glutton`. +pub struct WeightInfo(PhantomData); +impl pallet_glutton::WeightInfo for WeightInfo { + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_grow(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `87` + // Estimated: `1489` + // Minimum execution time: 6_453_000 picoseconds. + Weight::from_parts(6_629_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + // Standard Error: 3_416 + .saturating_add(Weight::from_parts(9_938_610, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_shrink(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `120` + // Estimated: `1489` + // Minimum execution time: 6_456_000 picoseconds. + Weight::from_parts(6_564_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + // Standard Error: 1_336 + .saturating_add(Weight::from_parts(1_141_705, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// The range of component `i` is `[0, 100000]`. + fn waste_ref_time_iter(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 679_000 picoseconds. + Weight::from_parts(3_310_101, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 10 + .saturating_add(Weight::from_parts(103_703, 0).saturating_mul(i.into())) + } + /// Storage: `Glutton::TrashData` (r:5000 w:0) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5000]`. + fn waste_proof_size_some(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119115 + i * (1022 ±0)` + // Estimated: `990 + i * (3016 ±0)` + // Minimum execution time: 765_000 picoseconds. + Weight::from_parts(1_004_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 4_008 + .saturating_add(Weight::from_parts(6_130_770, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) + } + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:1737 w:0) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + fn on_idle_high_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `1900498` + // Estimated: `5239782` + // Minimum execution time: 97_248_614_000 picoseconds. + Weight::from_parts(97_728_420_000, 0) + .saturating_add(Weight::from_parts(0, 5239782)) + .saturating_add(T::DbWeight::get().reads(1739)) + } + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:5 w:0) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + fn on_idle_low_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `9548` + // Estimated: `16070` + // Minimum execution time: 97_305_112_000 picoseconds. + Weight::from_parts(97_427_728_000, 0) + .saturating_add(Weight::from_parts(0, 16070)) + .saturating_add(T::DbWeight::get().reads(7)) + } + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn empty_on_idle() -> Weight { + // Proof Size summary in bytes: + // Measured: `87` + // Estimated: `1493` + // Minimum execution time: 4_125_000 picoseconds. + Weight::from_parts(4_339_000, 0) + .saturating_add(Weight::from_parts(0, 1493)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `Glutton::Compute` (r:0 w:1) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set_compute() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_879_000 picoseconds. + Weight::from_parts(4_211_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Glutton::Storage` (r:0 w:1) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set_storage() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_920_000 picoseconds. + Weight::from_parts(4_081_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000000..eab6c15a40d --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_message_queue.rs @@ -0,0 +1,179 @@ +// 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_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, 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_message_queue +// --chain=glutton-westend-dev-1300 +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-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_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `223` + // Estimated: `6044` + // Minimum execution time: 10_833_000 picoseconds. + Weight::from_parts(11_237_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `218` + // Estimated: `6044` + // Minimum execution time: 9_399_000 picoseconds. + Weight::from_parts(9_773_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3517` + // Minimum execution time: 3_277_000 picoseconds. + Weight::from_parts(3_358_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_429_000 picoseconds. + Weight::from_parts(5_667_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `69050` + // Minimum execution time: 5_538_000 picoseconds. + Weight::from_parts(5_803_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .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: 89_888_000 picoseconds. + Weight::from_parts(90_929_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(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3517` + // Minimum execution time: 6_129_000 picoseconds. + Weight::from_parts(6_414_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `69050` + // Minimum execution time: 52_366_000 picoseconds. + Weight::from_parts(53_500_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `69050` + // Minimum execution time: 67_848_000 picoseconds. + Weight::from_parts(68_910_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `65667` + // Estimated: `69050` + // Minimum execution time: 107_564_000 picoseconds. + Weight::from_parts(109_377_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000000..4218dcc73f4 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/pallet_timestamp.rs @@ -0,0 +1,73 @@ +// 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_timestamp` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, 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_timestamp +// --chain=glutton-westend-dev-1300 +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-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_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `86` + // Estimated: `1493` + // Minimum execution time: 6_306_000 picoseconds. + Weight::from_parts(6_592_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: `57` + // Estimated: `0` + // Minimum execution time: 2_900_000 picoseconds. + Weight::from_parts(3_030_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs new file mode 100644 index 00000000000..5ebb0ade123 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -0,0 +1,92 @@ +// 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, ParachainInfo, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, +}; +use frame_support::{ + match_types, parameter_types, + traits::{Everything, Nothing}, + weights::Weight, +}; +use xcm::latest::prelude::*; +use xcm_builder::{ + AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, ParentAsSuperuser, ParentIsPreset, + SovereignSignedViaLocation, +}; + +parameter_types! { + pub const WestendLocation: MultiLocation = MultiLocation::parent(); + pub const WestendNetwork: Option = Some(NetworkId::Westend); + pub UniversalLocation: InteriorMultiLocation = X1(Parachain(ParachainInfo::parachain_id().into())); +} + +/// 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 +/// bias 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, RuntimeOrigin>, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, +); + +match_types! { + pub type JustTheParent: impl Contains = { MultiLocation { parents:1, interior: Here } }; +} + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); // sending XCM not supported + type AssetTransactor = (); // balances not supported + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = (); // balances not supported + type IsTeleporter = (); // balances not supported + type UniversalLocation = UniversalLocation; + type Barrier = AllowExplicitUnpaidExecutionFrom; + type Weigher = FixedWeightBounds; // balances not supported + type Trader = (); // balances not supported + type ResponseHandler = (); // Don't handle responses for now. + type AssetTrap = (); // don't trap for now + type AssetClaims = (); // don't claim for now + type SubscriptionService = (); // don't handle subscriptions for now + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = xcm_executor::XcmExecutor; +} diff --git a/cumulus/parachains/testnets-common/Cargo.toml b/cumulus/parachains/testnets-common/Cargo.toml new file mode 100644 index 00000000000..e39cf91d3ab --- /dev/null +++ b/cumulus/parachains/testnets-common/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "testnets-common" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +description = "Logic and configuration specific to testnet parachain runtimes" +license = "Apache-2.0" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +smallvec = "1.11.0" + +# Substrate +frame-support = { path = "../../../substrate/frame/support", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } + +# Polkadot +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} + +# Cumulus + +[dev-dependencies] + +[build-dependencies] +substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } + +[features] +default = [ "std" ] +std = [ + "frame-support/std", + "polkadot-core-primitives/std", + "rococo-runtime-constants/std", + "sp-runtime/std", + "westend-runtime-constants/std", +] + +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/cumulus/parachains/testnets-common/src/lib.rs b/cumulus/parachains/testnets-common/src/lib.rs new file mode 100644 index 00000000000..42d367bff27 --- /dev/null +++ b/cumulus/parachains/testnets-common/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +/// Since the parachains-common package is now published to crates.io, SP runtimes for testnets +/// will be adapted to use this package, and their config removed from the published common +/// package. Only the configs specific to rococo, westend and wococo will be moved here, and the +/// truly common logic will still be sourced from the parachains-common package. +/// +/// In practice this just means that instead of using e.g. `[parachains_common::westend::*]`, now +/// the westend configs will be in `[testnets_common::westend::*]`. +/// +/// TODO: edit all runtimes to remove the testnet configs as part of PR #1737 +/// +pub mod rococo; +pub mod westend; +pub mod wococo; diff --git a/cumulus/parachains/testnets-common/src/rococo.rs b/cumulus/parachains/testnets-common/src/rococo.rs new file mode 100644 index 00000000000..6e31def4b55 --- /dev/null +++ b/cumulus/parachains/testnets-common/src/rococo.rs @@ -0,0 +1,119 @@ +// 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 currency { + use polkadot_core_primitives::Balance; + use rococo_runtime_constants as constants; + + /// The existential deposit. Set to 1/10 of its parent Relay Chain (v9010). + pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; + + pub const UNITS: Balance = constants::currency::UNITS; + pub const CENTS: Balance = constants::currency::CENTS; + pub const MILLICENTS: Balance = constants::currency::MILLICENTS; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + // map to 1/100 of what the rococo relay chain charges + constants::currency::deposit(items, bytes) / 100 + } +} + +pub mod fee { + use frame_support::{ + pallet_prelude::Weight, + weights::{ + constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + }; + use polkadot_core_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 frame_support::weights::WeightToFee for WeightToFee { + type Balance = Balance; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); + let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); + + // Take the maximum instead of the sum to charge by the more scarce resource. + time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) + } + } + + /// Maps the reference time component of `Weight` to a fee. + pub struct RefTimeToFee; + impl WeightToFeePolynomial for RefTimeToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // In Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. + let p = super::currency::CENTS; + let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); + + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } + } + + /// Maps the proof size component of `Weight` to a fee. + pub struct ProofSizeToFee; + impl WeightToFeePolynomial for ProofSizeToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // Map 10kb proof to 1 CENT. + let p = super::currency::CENTS; + let q = 10_000; + + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } + } +} + +/// Consensus-related. +pub mod consensus { + /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included + /// into the relay chain. + pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; + /// How many parachain blocks are processed by the relay chain per parent. Limits the + /// number of blocks authored per slot. + pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; + /// Relay chain slot duration, in milliseconds. + pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +} diff --git a/cumulus/parachains/testnets-common/src/westend.rs b/cumulus/parachains/testnets-common/src/westend.rs new file mode 100644 index 00000000000..0ae21e23454 --- /dev/null +++ b/cumulus/parachains/testnets-common/src/westend.rs @@ -0,0 +1,140 @@ +// 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. + +/// Universally recognized accounts. +pub mod account { + use frame_support::PalletId; + + /// Westend treasury pallet id, used to convert into AccountId - in Westend as a destination for + /// slashed funds. + pub const WESTEND_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); + /// Alliance pallet ID - used as a temporary place to deposit a slashed imbalance before the + /// teleport to the Treasury. + pub const ALLIANCE_PALLET_ID: PalletId = PalletId(*b"py/allia"); + /// Referenda pallet ID - used as a temporary 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 - used as a temporary place to deposit a slashed imbalance + /// before the teleport to the Treasury. + pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); +} + +pub mod currency { + use polkadot_core_primitives::Balance; + use westend_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 UNITS: Balance = constants::currency::UNITS; + pub const DOLLARS: Balance = UNITS; // 1_000_000_000_000 + pub const CENTS: Balance = constants::currency::CENTS; + pub const MILLICENTS: Balance = constants::currency::MILLICENTS; + pub const GRAND: Balance = constants::currency::GRAND; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + // 1/100 of Westend testnet + constants::currency::deposit(items, bytes) / 100 + } +} + +/// Fee-related. +pub mod fee { + use frame_support::{ + pallet_prelude::Weight, + weights::{ + constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + }; + use polkadot_core_primitives::Balance; + use smallvec::smallvec; + pub use sp_runtime::Perbill; + + /// The block saturation level. Fees will be updated 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 frame_support::weights::WeightToFee for WeightToFee { + type Balance = Balance; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); + let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); + + // Take the maximum instead of the sum to charge by the more scarce resource. + time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) + } + } + + /// Maps the reference time component of `Weight` to a fee. + pub struct RefTimeToFee; + impl WeightToFeePolynomial for RefTimeToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // In Westend, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. + let p = super::currency::CENTS; + let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); + + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } + } + + /// Maps the proof size component of `Weight` to a fee. + pub struct ProofSizeToFee; + impl WeightToFeePolynomial for ProofSizeToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // Map 10kb proof to 1 CENT. + let p = super::currency::CENTS; + let q = 10_000; + + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } + } +} + +/// Consensus-related. +pub mod consensus { + /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the + /// relay chain. + pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; + /// How many parachain blocks are processed by the relay chain per parent. Limits the number of + /// blocks authored per slot. + pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; + /// Relay chain slot duration, in milliseconds. + pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +} diff --git a/cumulus/parachains/testnets-common/src/wococo.rs b/cumulus/parachains/testnets-common/src/wococo.rs new file mode 100644 index 00000000000..5cd6121135a --- /dev/null +++ b/cumulus/parachains/testnets-common/src/wococo.rs @@ -0,0 +1,17 @@ +// 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. + +// re-export rococo +pub use crate::rococo::{consensus, currency, fee}; diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index f7252a39a38..d5deda9e7bf 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -24,6 +24,7 @@ serde_json = "1.0.108" # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } shell-runtime = { path = "../parachains/runtimes/starters/shell" } +glutton-westend-runtime = { path = "../parachains/runtimes/glutton/glutton-westend" } 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" } @@ -31,6 +32,7 @@ asset-hub-kusama-runtime = { path = "../parachains/runtimes/assets/asset-hub-kus 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" } +collectives-westend-runtime = { path = "../parachains/runtimes/collectives/collectives-westend" } contracts-rococo-runtime = { path = "../parachains/runtimes/contracts/contracts-rococo" } bridge-hub-rococo-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-rococo" } bridge-hub-kusama-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-kusama" } @@ -119,11 +121,13 @@ runtime-benchmarks = [ "bridge-hub-rococo-runtime/runtime-benchmarks", "bridge-hub-westend-runtime/runtime-benchmarks", "collectives-polkadot-runtime/runtime-benchmarks", + "collectives-westend-runtime/runtime-benchmarks", "contracts-rococo-runtime/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "glutton-runtime/runtime-benchmarks", + "glutton-westend-runtime/runtime-benchmarks", "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", @@ -143,8 +147,10 @@ try-runtime = [ "bridge-hub-rococo-runtime/try-runtime", "bridge-hub-westend-runtime/try-runtime", "collectives-polkadot-runtime/try-runtime", + "collectives-westend-runtime/try-runtime", "contracts-rococo-runtime/try-runtime", "glutton-runtime/try-runtime", + "glutton-westend-runtime/try-runtime", "penpal-runtime/try-runtime", "polkadot-cli/try-runtime", "polkadot-service/try-runtime", diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 0a8064f50ca..07bd742fa8e 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -23,9 +23,12 @@ use sc_service::ChainType; use sp_core::sr25519; pub type CollectivesPolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>; +pub type CollectivesWestendChainSpec = sc_service::GenericChainSpec<(), Extensions>; const COLLECTIVES_POLKADOT_ED: CollectivesBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; +const COLLECTIVES_WESTEND_ED: CollectivesBalance = + parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; /// Generate the session keys from individual elements. /// @@ -158,3 +161,133 @@ fn collectives_polkadot_genesis( }, }) } + +/// 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 collectives_westend_session_keys(keys: AuraId) -> collectives_westend_runtime::SessionKeys { + collectives_westend_runtime::SessionKeys { aura: keys } +} + +pub fn collectives_westend_development_config() -> CollectivesWestendChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "WND".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + CollectivesWestendChainSpec::builder( + collectives_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "westend-dev".into(), para_id: 1002 }, + ) + .with_name("Westend Collectives Development") + .with_id("collectives_westend_dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(collectives_westend_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"), + ], + // 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever + // be a collective para on Kusama. + 1002.into(), + )) + .with_boot_nodes(Vec::new()) + .with_properties(properties) + .build() +} + +/// Collectives Westend Local Config. +pub fn collectives_westend_local_config() -> CollectivesWestendChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "WND".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + CollectivesWestendChainSpec::builder( + collectives_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "westend-local".into(), para_id: 1002 }, + ) + .with_name("Westend Collectives Local") + .with_id("collectives_westend_local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(collectives_westend_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + 1002.into(), + )) + .with_boot_nodes(Vec::new()) + .with_properties(properties) + .build() +} + +fn collectives_westend_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, +) -> serde_json::Value { + serde_json::json!( { + "balances": { + "balances": endowed_accounts + .iter() + .cloned() + .map(|k| (k, COLLECTIVES_WESTEND_ED * 4096)) + .collect::>(), + }, + "parachainInfo": { + "parachainId": id, + }, + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + "candidacyBond": COLLECTIVES_WESTEND_ED * 16, + }, + "session": { + "keys": invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + collectives_westend_session_keys(aura), // session keys + ) + }) + .collect::>(), + }, + // no need to pass anything to aura, in fact it will panic if we do. Session will take care + // of this. + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + }, + }) +} diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 1a0a06404c5..aff1358d1ae 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -24,6 +24,7 @@ use super::get_collator_keys_from_seed; /// Specialized `ChainSpec` for the Glutton parachain runtime. pub type GluttonChainSpec = sc_service::GenericChainSpec<(), Extensions>; +pub type GluttonWestendChainSpec = sc_service::GenericChainSpec<(), Extensions>; pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec { GluttonChainSpec::builder( @@ -92,3 +93,71 @@ fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json:: "aura": { "authorities": collators }, }) } + +pub fn glutton_westend_development_config(para_id: ParaId) -> GluttonWestendChainSpec { + GluttonWestendChainSpec::builder( + glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "westend-dev".into(), para_id: para_id.into() }, + ) + .with_name("Glutton Development") + .with_id("glutton_westend_dev") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(glutton_genesis( + para_id, + vec![get_collator_keys_from_seed::("Alice")], + )) + .build() +} + +pub fn glutton_westend_local_config(para_id: ParaId) -> GluttonWestendChainSpec { + GluttonWestendChainSpec::builder( + glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "westend-local".into(), para_id: para_id.into() }, + ) + .with_name("Glutton Local") + .with_id("glutton_westend_local") + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(glutton_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + )) + .build() +} + +pub fn glutton_westend_config(para_id: ParaId) -> GluttonWestendChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + + GluttonChainSpec::builder( + glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + Extensions { relay_chain: "westend".into(), para_id: para_id.into() }, + ) + .with_name(format!("Glutton {}", para_id).as_str()) + .with_id(format!("glutton-westend-{}", para_id).as_str()) + .with_chain_type(ChainType::Live) + .with_genesis_config_patch(glutton_westend_genesis( + para_id, + vec![ + get_collator_keys_from_seed::("Alice"), + get_collator_keys_from_seed::("Bob"), + ], + )) + .with_protocol_id(format!("glutton-westend-{}", para_id).as_str()) + .with_properties(properties) + .build() +} + +fn glutton_westend_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { + serde_json::json!( { + "parachainInfo": { + "parachainId": parachain_id + }, + "sudo": { + "key": Some(get_account_id_from_seed::("Alice")), + }, + "aura": { "authorities": collators }, + }) +} diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 3f93c90558a..2799175b8ee 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -50,6 +50,7 @@ enum Runtime { CollectivesPolkadot, CollectivesWestend, Glutton, + GluttonWestend, BridgeHub(chain_spec::bridge_hubs::BridgeHubRuntimeType), } @@ -111,6 +112,8 @@ fn runtime(id: &str) -> Runtime { id.parse::() .expect("Invalid value"), ) + } else if id.starts_with("glutton-westend") { + Runtime::GluttonWestend } else if id.starts_with("glutton") { Runtime::Glutton } else { @@ -219,8 +222,12 @@ fn load_spec(id: &str) -> std::result::Result, String> { Box::new(chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_bytes( &include_bytes!("../chain-specs/collectives-polkadot.json")[..], )?), + "collectives-westend-dev" => + Box::new(chain_spec::collectives::collectives_westend_development_config()), + "collectives-westend-local" => + Box::new(chain_spec::collectives::collectives_westend_local_config()), "collectives-westend" => - Box::new(chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_bytes( + Box::new(chain_spec::collectives::CollectivesWestendChainSpec::from_json_bytes( &include_bytes!("../chain-specs/collectives-westend.json")[..], )?), @@ -254,6 +261,18 @@ fn load_spec(id: &str) -> std::result::Result, String> { "polkadot-local", )), + // -- Glutton Westend + "glutton-westend-dev" => Box::new(chain_spec::glutton::glutton_westend_development_config( + para_id.expect("Must specify parachain id"), + )), + "glutton-westend-local" => Box::new(chain_spec::glutton::glutton_westend_local_config( + para_id.expect("Must specify parachain id"), + )), + // the chain spec as used for generating the upgrade genesis values + "glutton-westend-genesis" => Box::new(chain_spec::glutton::glutton_westend_config( + para_id.expect("Must specify parachain id"), + )), + // -- Glutton "glutton-kusama-dev" => Box::new(chain_spec::glutton::glutton_development_config( para_id.expect("Must specify parachain id"), @@ -288,9 +307,12 @@ fn load_spec(id: &str) -> std::result::Result, String> { Runtime::AssetHubWestend => Box::new( chain_spec::asset_hubs::AssetHubWestendChainSpec::from_json_file(path)?, ), - Runtime::CollectivesPolkadot | Runtime::CollectivesWestend => Box::new( + Runtime::CollectivesPolkadot => Box::new( chain_spec::collectives::CollectivesPolkadotChainSpec::from_json_file(path)?, ), + Runtime::CollectivesWestend => Box::new( + chain_spec::collectives::CollectivesWestendChainSpec::from_json_file(path)?, + ), Runtime::Shell => Box::new(chain_spec::shell::ShellChainSpec::from_json_file(path)?), Runtime::Seedling => @@ -301,6 +323,8 @@ fn load_spec(id: &str) -> std::result::Result, String> { bridge_hub_runtime_type.chain_spec_from_json_file(path)?, Runtime::Penpal(_para_id) => Box::new(chain_spec::penpal::PenpalChainSpec::from_json_file(path)?), + Runtime::GluttonWestend => + Box::new(chain_spec::glutton::GluttonChainSpec::from_json_file(path)?), Runtime::Glutton => Box::new(chain_spec::glutton::GluttonChainSpec::from_json_file(path)?), Runtime::Default => Box::new( @@ -322,6 +346,10 @@ fn extract_parachain_id(id: &str) -> (&str, &str, Option) { const GLUTTON_PARA_LOCAL_PREFIX: &str = "glutton-kusama-local-"; const GLUTTON_PARA_GENESIS_PREFIX: &str = "glutton-kusama-genesis-"; + const GLUTTON_WESTEND_PARA_DEV_PREFIX: &str = "glutton-westend-dev-"; + const GLUTTON_WESTEND_PARA_LOCAL_PREFIX: &str = "glutton-westend-local-"; + const GLUTTON_WESTEND_PARA_GENESIS_PREFIX: &str = "glutton-westend-genesis-"; + let (norm_id, orig_id, para) = if let Some(suffix) = id.strip_prefix(KUSAMA_TEST_PARA_PREFIX) { let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); (&id[..KUSAMA_TEST_PARA_PREFIX.len() - 1], id, Some(para_id)) @@ -337,6 +365,15 @@ fn extract_parachain_id(id: &str) -> (&str, &str, Option) { } else if let Some(suffix) = id.strip_prefix(GLUTTON_PARA_GENESIS_PREFIX) { let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); (&id[..GLUTTON_PARA_GENESIS_PREFIX.len() - 1], id, Some(para_id)) + } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_DEV_PREFIX) { + let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); + (&id[..GLUTTON_WESTEND_PARA_DEV_PREFIX.len() - 1], id, Some(para_id)) + } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_LOCAL_PREFIX) { + let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); + (&id[..GLUTTON_WESTEND_PARA_LOCAL_PREFIX.len() - 1], id, Some(para_id)) + } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_GENESIS_PREFIX) { + let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); + (&id[..GLUTTON_WESTEND_PARA_GENESIS_PREFIX.len() - 1], id, Some(para_id)) } else { (id, id, None) }; @@ -494,13 +531,20 @@ macro_rules! construct_partials { $code }, }, - Runtime::CollectivesPolkadot | Runtime::CollectivesWestend => { + Runtime::CollectivesPolkadot => { let $partials = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AuraId>, )?; $code }, + Runtime::CollectivesWestend => { + let $partials = new_partial::( + &$config, + crate::service::aura_build_import_queue::<_, AuraId>, + )?; + $code + }, Runtime::Shell => { let $partials = new_partial::( &$config, @@ -529,6 +573,13 @@ macro_rules! construct_partials { )?; $code }, + Runtime::GluttonWestend => { + let $partials = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + $code + }, Runtime::Glutton => { let $partials = new_partial::( &$config, @@ -584,7 +635,7 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::CollectivesPolkadot | Runtime::CollectivesWestend => { + Runtime::CollectivesPolkadot => { runner.async_run(|$config| { let $components = new_partial::( &$config, @@ -594,6 +645,16 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, + Runtime::CollectivesWestend => { + 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::Shell => { runner.async_run(|$config| { let $components = new_partial::( @@ -705,6 +766,16 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, + Runtime::GluttonWestend => { + runner.async_run(|$config| { + let $components = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }, Runtime::Glutton => { runner.async_run(|$config| { let $components = new_partial::( @@ -836,7 +907,7 @@ pub fn run() -> Result<()> { // that both file paths exist, the node will exit, as the user must decide (by // deleting one path) the information that they want to use as their DB. let old_name = match config.chain_spec.id() { - "asset-hub-polkadot" => Some("statemint"), + "asset-hub-polkadot" => Some("statemint"), "asset-hub-kusama" => Some("statemine"), "asset-hub-westend" => Some("westmint"), "asset-hub-rococo" => Some("rockmine"), @@ -921,7 +992,7 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), - Runtime::CollectivesPolkadot | Runtime::CollectivesWestend => + Runtime::CollectivesPolkadot => crate::service::start_generic_aura_node::< collectives_polkadot_runtime::RuntimeApi, AuraId, @@ -929,6 +1000,14 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), + Runtime::CollectivesWestend => + crate::service::start_generic_aura_node::< + collectives_westend_runtime::RuntimeApi, + AuraId, + >(config, polkadot_config, collator_options, id, hwbench) + .await + .map(|r| r.0) + .map_err(Into::into), Runtime::Shell => crate::service::start_shell_node::( config, @@ -962,7 +1041,7 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into), Runtime::BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { - chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | +chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotDevelopment => crate::service::start_generic_aura_node::< @@ -1019,6 +1098,14 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), + Runtime::GluttonWestend => + crate::service::start_basic_lookahead_node::< + glutton_westend_runtime::RuntimeApi, + AuraId, + >(config, polkadot_config, collator_options, id, hwbench) + .await + .map(|r| r.0) + .map_err(Into::into), Runtime::Glutton => crate::service::start_basic_lookahead_node::< glutton_runtime::RuntimeApi, diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 3bcc9b7f60d..3884fce246c 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -156,6 +156,21 @@ impl sc_executor::NativeExecutionDispatch for CollectivesPolkadotRuntimeExecutor } } +/// Native Westend Collectives executor instance. +pub struct CollectivesWestendRuntimeExecutor; + +impl sc_executor::NativeExecutionDispatch for CollectivesWestendRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + collectives_westend_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + collectives_westend_runtime::native_version() + } +} + /// Native BridgeHubPolkadot executor instance. pub struct BridgeHubPolkadotRuntimeExecutor; @@ -216,6 +231,21 @@ impl sc_executor::NativeExecutionDispatch for ContractsRococoRuntimeExecutor { } } +/// Native Westend Glutton executor instance. +pub struct GluttonWestendRuntimeExecutor; + +impl sc_executor::NativeExecutionDispatch for GluttonWestendRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + glutton_westend_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + glutton_westend_runtime::native_version() + } +} + /// Native Glutton executor instance. pub struct GluttonRuntimeExecutor; diff --git a/cumulus/scripts/benchmarks.sh b/cumulus/scripts/benchmarks.sh index 29d06905925..7da18d9440e 100755 --- a/cumulus/scripts/benchmarks.sh +++ b/cumulus/scripts/benchmarks.sh @@ -7,6 +7,7 @@ repeat=${3:-20} __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ${__dir}/benchmarks-ci.sh collectives collectives-polkadot target/$target $steps $repeat +${__dir}/benchmarks-ci.sh collectives collectives-westend target/$target $steps $repeat ${__dir}/benchmarks-ci.sh assets asset-hub-kusama target/$target $steps $repeat ${__dir}/benchmarks-ci.sh assets asset-hub-polkadot target/$target $steps $repeat @@ -17,3 +18,4 @@ ${__dir}/benchmarks-ci.sh bridge-hubs bridge-hub-kusama target/$target $steps $r ${__dir}/benchmarks-ci.sh bridge-hubs bridge-hub-rococo target/$target $steps $repeat ${__dir}/benchmarks-ci.sh glutton glutton-kusama target/$target $steps $repeat +${__dir}/benchmarks-ci.sh glutton glutton-westend target/$target $steps $repeat -- GitLab From 824b782390b16b433df89dd3ff451ea3f0ea03a1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 15 Nov 2023 17:36:14 +0200 Subject: [PATCH 518/633] xcm: SovereignPaidRemoteExporter: remove unused RefundSurplus instruction (#2312) Refunding surplus happens anyway on xcm_executor::post_process(), automatically refunding surplus to original_origin at the end of execution. Since SovereignPaidRemoteExporter doesn't ClearOrigin, it can simply rely on the automatic mechanism. Furthermore, RefundSurplus instruction refunds _surplus_. Surplus exists only as a result of Transact, SetErrorHandler or SetAppendix instructions, none of which being part of the SovereignPaidRemoteExporter XCM program. So surplus is always zero here anyway. --- .../bridge-hubs/test-utils/src/test_cases.rs | 1 - .../src/tests/bridging/local_para_para.rs | 6 +++--- .../src/tests/bridging/local_relay_relay.rs | 4 ++-- .../tests/bridging/paid_remote_relay_relay.rs | 21 +++++++++---------- .../xcm/xcm-builder/src/universal_exports.rs | 1 - 5 files changed, 15 insertions(+), 18 deletions(-) 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 b421eea6bcf..7a86d85c86f 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 @@ -909,7 +909,6 @@ where ]), ]), }, - RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(1000)) }, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs index 406843a0fe8..de08dbee953 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs @@ -44,7 +44,7 @@ fn sending_to_bridged_chain_works() { maybe_with_topic(|| { let msg = Xcm(vec![Trap(1)]); let dest = (Parent, Parent, Remote::get(), Parachain(1)).into(); - assert_eq!(send_xcm::(dest, msg).unwrap().1, (Here, 100).into()); + assert_eq!(send_xcm::(dest, msg).unwrap().1, Price::get()); assert_eq!(TheBridge::service(), 1); assert_eq!( take_received_remote_messages(), @@ -78,7 +78,7 @@ fn sending_to_parachain_of_bridged_chain_works() { maybe_with_topic(|| { let msg = Xcm(vec![Trap(1)]); let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into(); - assert_eq!(send_xcm::(dest, msg).unwrap().1, (Here, 100).into()); + assert_eq!(send_xcm::(dest, msg).unwrap().1, Price::get()); assert_eq!(TheBridge::service(), 1); let expected = vec![( (Parent, Parachain(1000)).into(), @@ -110,7 +110,7 @@ fn sending_to_relay_chain_of_bridged_chain_works() { maybe_with_topic(|| { let msg = Xcm(vec![Trap(1)]); let dest = (Parent, Parent, Remote::get()).into(); - assert_eq!(send_xcm::(dest, msg).unwrap().1, (Here, 100).into()); + assert_eq!(send_xcm::(dest, msg).unwrap().1, Price::get()); assert_eq!(TheBridge::service(), 1); let expected = vec![( Parent.into(), diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs index 02c454bb212..8433b6e0212 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs @@ -41,7 +41,7 @@ fn sending_to_bridged_chain_works() { let msg = Xcm(vec![Trap(1)]); assert_eq!( send_xcm::((Parent, Remote::get()).into(), msg).unwrap().1, - (Here, 100).into() + Price::get() ); assert_eq!(TheBridge::service(), 1); let expected = vec![( @@ -68,7 +68,7 @@ fn sending_to_parachain_of_bridged_chain_works() { maybe_with_topic(|| { let msg = Xcm(vec![Trap(1)]); let dest = (Parent, Remote::get(), Parachain(1000)).into(); - assert_eq!(send_xcm::(dest, msg).unwrap().1, (Here, 100).into()); + assert_eq!(send_xcm::(dest, msg).unwrap().1, Price::get()); assert_eq!(TheBridge::service(), 1); let expected = vec![( Parachain(1000).into(), 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 45dc2d4a3b9..23d6eb99a90 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 @@ -24,6 +24,9 @@ use super::*; parameter_types! { + // 100 to use the bridge (export) and 80 for the remote execution weight (4 instructions x (10 + + // 10) weight each). + pub SendOverBridgePrice: u128 = 180u128 + if UsingTopic::get() { 20 } else { 0 }; pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); @@ -32,11 +35,9 @@ parameter_types! { Remote::get(), None, MultiLocation::parent(), - Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()) + Some((Parent, SendOverBridgePrice::get()).into()) ) ]; - // ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions - // x (10 + 10) weight each). } type TheBridge = TestBridge>; @@ -68,7 +69,7 @@ fn sending_to_bridged_chain_works() { clear_assets(Parachain(100)); add_asset(Parachain(100), (Here, 1000u128)); - let price = 200u128 + if UsingTopic::get() { 20 } else { 0 }; + let price = SendOverBridgePrice::get(); let msg = Xcm(vec![Trap(1)]); assert_eq!(send_xcm::(dest, msg).unwrap().1, (Parent, price).into()); @@ -86,7 +87,7 @@ fn sending_to_bridged_chain_works() { )]; assert_eq!(take_received_remote_messages(), expected); - // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of + // The export cost 40 ref time and 40 proof size weight units (and thus 80 units of // balance). assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]); @@ -104,11 +105,10 @@ fn sending_to_bridged_chain_works() { destination: Here, xcm: xcm_with_topic([0; 32], vec![Trap(1)]), }, - RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() }, ], ), - outcome: Outcome::Complete(test_weight(5)), + outcome: Outcome::Complete(test_weight(4)), paid: true, }; assert_eq!(RoutingLog::take(), vec![entry]); @@ -143,7 +143,7 @@ fn sending_to_parachain_of_bridged_chain_works() { clear_assets(Parachain(100)); add_asset(Parachain(100), (Here, 1000u128)); - let price = 200u128 + if UsingTopic::get() { 20 } else { 0 }; + let price = SendOverBridgePrice::get(); let msg = Xcm(vec![Trap(1)]); assert_eq!(send_xcm::(dest, msg).unwrap().1, (Parent, price).into()); @@ -161,7 +161,7 @@ fn sending_to_parachain_of_bridged_chain_works() { )]; assert_eq!(take_received_remote_messages(), expected); - // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of + // The export cost 40 ref time and 40 proof size weight units (and thus 80 units of // balance). assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]); @@ -179,11 +179,10 @@ fn sending_to_parachain_of_bridged_chain_works() { destination: Parachain(100).into(), xcm: xcm_with_topic([0; 32], vec![Trap(1)]), }, - RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() }, ], ), - outcome: Outcome::Complete(test_weight(5)), + outcome: Outcome::Complete(test_weight(4)), paid: true, }; assert_eq!(RoutingLog::take(), vec![entry]); diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index dbe9571d461..8e2cf88b3c3 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -305,7 +305,6 @@ impl Date: Wed, 15 Nov 2023 16:40:07 +0100 Subject: [PATCH 519/633] [testnet] Remove Wococo stuff from BridgeHubRococo/AssetHubRococo (#2300) Rococo<>Wococo bridge is replaced by Rococo Co-authored-by: Svyatoslav Nikolsky --- Cargo.lock | 66 --- Cargo.toml | 5 - bridges/README.md | 175 +------- bridges/bin/runtime-common/src/lib.rs | 41 +- bridges/bin/runtime-common/src/mock.rs | 46 +- .../runtime-common/src/priority_calculator.rs | 1 + bridges/docs/high-level-overview.md | 2 +- bridges/modules/grandpa/src/mock.rs | 40 +- bridges/modules/grandpa/src/weights.rs | 62 +-- bridges/modules/messages/Cargo.toml | 2 - bridges/modules/messages/src/mock.rs | 54 +-- bridges/modules/messages/src/weights.rs | 226 +++++----- bridges/modules/parachains/src/mock.rs | 41 +- bridges/modules/parachains/src/weights.rs | 122 +++--- bridges/modules/parachains/src/weights_ext.rs | 2 +- bridges/modules/relayers/Cargo.toml | 1 - bridges/modules/relayers/src/mock.rs | 44 +- bridges/modules/relayers/src/weights.rs | 2 +- .../modules/xcm-bridge-hub-router/src/mock.rs | 31 +- .../xcm-bridge-hub-router/src/weights.rs | 2 +- .../chain-asset-hub-kusama/Cargo.toml | 26 -- .../chain-asset-hub-kusama/src/lib.rs | 49 --- .../chain-asset-hub-polkadot/Cargo.toml | 28 -- .../chain-asset-hub-polkadot/src/lib.rs | 49 --- .../chain-asset-hub-rococo/src/lib.rs | 3 - .../chain-asset-hub-wococo/Cargo.toml | 26 -- .../chain-asset-hub-wococo/src/lib.rs | 48 --- .../chain-bridge-hub-cumulus/Cargo.toml | 2 +- .../chain-bridge-hub-kusama/Cargo.toml | 2 +- .../chain-bridge-hub-polkadot/Cargo.toml | 2 +- .../chain-bridge-hub-rococo/src/lib.rs | 3 - .../chain-bridge-hub-wococo/Cargo.toml | 34 -- .../chain-bridge-hub-wococo/src/lib.rs | 90 ---- bridges/primitives/chain-wococo/Cargo.toml | 34 -- bridges/primitives/chain-wococo/src/lib.rs | 68 --- bridges/primitives/runtime/src/chain.rs | 6 +- bridges/primitives/runtime/src/extensions.rs | 2 +- bridges/primitives/runtime/src/lib.rs | 35 -- bridges/scripts/verify-pallets-build.sh | 9 - bridges/zombienet/README.md | 4 +- .../helpers/wait-hrmp-channel-opened.js | 22 + bridges/zombienet/run-tests.sh | 4 +- bridges/zombienet/scripts/invoke-script.sh | 2 +- ...set-transfer-works-rococo-to-westend.zndsl | 26 ++ ...sset-transfer-works-rococo-to-wococo.zndsl | 25 -- ...et-transfer-works-westend-to-rococo.zndsl} | 19 +- bridges/zombienet/tests/0001-start-relay.sh | 2 +- .../bridges/bridge-hub-rococo/src/genesis.rs | 12 +- .../assets/asset-hub-rococo/Cargo.toml | 4 - .../assets/asset-hub-rococo/src/lib.rs | 120 +----- .../asset-hub-rococo/src/weights/mod.rs | 4 +- ...end.rs => pallet_xcm_bridge_hub_router.rs} | 56 ++- .../pallet_xcm_bridge_hub_router_to_rococo.rs | 130 ------ .../pallet_xcm_bridge_hub_router_to_wococo.rs | 130 ------ .../xcm/pallet_xcm_benchmarks_fungible.rs | 64 ++- .../xcm/pallet_xcm_benchmarks_generic.rs | 144 +++---- .../assets/asset-hub-rococo/src/xcm_config.rs | 213 +--------- .../assets/asset-hub-rococo/tests/tests.rs | 287 +------------ .../parachains/runtimes/bridge-hubs/README.md | 127 +----- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 6 - .../src/bridge_common_config.rs | 54 +-- .../src/bridge_to_rococo_config.rs | 317 -------------- .../src/bridge_to_westend_config.rs | 2 +- .../src/bridge_to_wococo_config.rs | 318 -------------- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 329 +-------------- .../bridge-hub-rococo/src/weights/mod.rs | 73 +--- .../src/weights/pallet_bridge_grandpa.rs | 89 ++-- .../pallet_bridge_grandpa_rococo_finality.rs | 82 ---- .../pallet_bridge_grandpa_westend_finality.rs | 83 ---- .../pallet_bridge_grandpa_wococo_finality.rs | 82 ---- .../src/weights/pallet_bridge_messages.rs | 312 +++++++------- ...allet_bridge_messages_rococo_to_westend.rs | 245 ----------- ...pallet_bridge_messages_rococo_to_wococo.rs | 244 ----------- ...pallet_bridge_messages_wococo_to_rococo.rs | 244 ----------- .../src/weights/pallet_bridge_parachains.rs | 128 +++--- .../pallet_bridge_parachains_within_rococo.rs | 113 ----- ...pallet_bridge_parachains_within_westend.rs | 116 ------ .../pallet_bridge_parachains_within_wococo.rs | 115 ----- .../src/weights/pallet_bridge_relayers.rs | 49 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 87 ++-- .../xcm/pallet_xcm_benchmarks_generic.rs | 209 +++++----- .../bridge-hub-rococo/src/xcm_config.rs | 54 +-- .../bridge-hub-rococo/tests/tests.rs | 393 +----------------- .../bridge-hubs/test-utils/Cargo.toml | 4 - .../src/chain_spec/asset_hubs.rs | 87 +--- .../src/chain_spec/bridge_hubs.rs | 62 --- cumulus/polkadot-parachain/src/command.rs | 52 +-- cumulus/scripts/bridges_rococo_westend.sh | 22 +- cumulus/scripts/bridges_rococo_wococo.sh | 386 ----------------- .../bridge_hub_rococo_local_network.toml | 12 +- .../bridge_hub_westend_local_network.toml | 12 +- .../bridge_hub_wococo_local_network.toml | 94 ----- 92 files changed, 962 insertions(+), 6389 deletions(-) delete mode 100644 bridges/primitives/chain-asset-hub-kusama/Cargo.toml delete mode 100644 bridges/primitives/chain-asset-hub-kusama/src/lib.rs delete mode 100644 bridges/primitives/chain-asset-hub-polkadot/Cargo.toml delete mode 100644 bridges/primitives/chain-asset-hub-polkadot/src/lib.rs delete mode 100644 bridges/primitives/chain-asset-hub-wococo/Cargo.toml delete mode 100644 bridges/primitives/chain-asset-hub-wococo/src/lib.rs delete mode 100644 bridges/primitives/chain-bridge-hub-wococo/Cargo.toml delete mode 100644 bridges/primitives/chain-bridge-hub-wococo/src/lib.rs delete mode 100644 bridges/primitives/chain-wococo/Cargo.toml delete mode 100644 bridges/primitives/chain-wococo/src/lib.rs create mode 100644 bridges/zombienet/helpers/wait-hrmp-channel-opened.js create mode 100644 bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl delete mode 100644 bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl rename bridges/zombienet/tests/{0001-asset-transfer-works-wococo-to-rococo.zndsl => 0001-asset-transfer-works-westend-to-rococo.zndsl} (64%) mode change 100644 => 100755 bridges/zombienet/tests/0001-start-relay.sh rename cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/{pallet_xcm_bridge_hub_router_to_westend.rs => pallet_xcm_bridge_hub_router.rs} (75%) delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_rococo_config.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_wococo_config.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs delete mode 100755 cumulus/scripts/bridges_rococo_wococo.sh delete mode 100644 cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml diff --git a/Cargo.lock b/Cargo.lock index 6b52e62d742..0c374a90a18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,10 +921,8 @@ dependencies = [ "assets-common", "bp-asset-hub-rococo", "bp-asset-hub-westend", - "bp-asset-hub-wococo", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "bp-bridge-hub-wococo", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -1690,27 +1688,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "bp-asset-hub-kusama" -version = "0.1.0" -dependencies = [ - "bp-xcm-bridge-hub-router", - "frame-support", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "bp-asset-hub-polkadot" -version = "0.1.0" -dependencies = [ - "bp-xcm-bridge-hub-router", - "frame-support", - "parity-scale-codec", - "scale-info", - "sp-runtime", -] - [[package]] name = "bp-asset-hub-rococo" version = "0.1.0" @@ -1731,16 +1708,6 @@ dependencies = [ "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" @@ -1807,19 +1774,6 @@ dependencies = [ "sp-std 8.0.0", ] -[[package]] -name = "bp-bridge-hub-wococo" -version = "0.1.0" -dependencies = [ - "bp-bridge-hub-cumulus", - "bp-messages", - "bp-runtime", - "frame-support", - "sp-api", - "sp-runtime", - "sp-std 8.0.0", -] - [[package]] name = "bp-header-chain" version = "0.1.0" @@ -2011,19 +1965,6 @@ dependencies = [ "sp-std 8.0.0", ] -[[package]] -name = "bp-wococo" -version = "0.1.0" -dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-rococo", - "bp-runtime", - "frame-support", - "sp-api", - "sp-std 8.0.0", -] - [[package]] name = "bp-xcm-bridge-hub-router" version = "0.1.0" @@ -2205,10 +2146,8 @@ version = "0.1.0" dependencies = [ "bp-asset-hub-rococo", "bp-asset-hub-westend", - "bp-asset-hub-wococo", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "bp-bridge-hub-wococo", "bp-header-chain", "bp-messages", "bp-parachains", @@ -2217,7 +2156,6 @@ dependencies = [ "bp-rococo", "bp-runtime", "bp-westend", - "bp-wococo", "bridge-hub-test-utils", "bridge-runtime-common", "cumulus-pallet-aura-ext", @@ -2291,8 +2229,6 @@ name = "bridge-hub-test-utils" version = "0.1.0" dependencies = [ "asset-test-utils", - "bp-bridge-hub-rococo", - "bp-bridge-hub-wococo", "bp-header-chain", "bp-messages", "bp-parachains", @@ -9661,7 +9597,6 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", "sp-io", "sp-runtime", "sp-std 8.0.0", @@ -9706,7 +9641,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-arithmetic", - "sp-core", "sp-io", "sp-runtime", "sp-std 8.0.0", diff --git a/Cargo.toml b/Cargo.toml index 27351c09581..ed252e07053 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,23 +14,18 @@ members = [ "bridges/modules/parachains", "bridges/modules/relayers", "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-westend", - "bridges/primitives/chain-asset-hub-wococo", "bridges/primitives/chain-bridge-hub-cumulus", "bridges/primitives/chain-bridge-hub-kusama", "bridges/primitives/chain-bridge-hub-polkadot", "bridges/primitives/chain-bridge-hub-rococo", "bridges/primitives/chain-bridge-hub-westend", - "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-westend", - "bridges/primitives/chain-wococo", "bridges/primitives/header-chain", "bridges/primitives/messages", "bridges/primitives/parachains", diff --git a/bridges/README.md b/bridges/README.md index da46fe67d92..a2ce213d254 100644 --- a/bridges/README.md +++ b/bridges/README.md @@ -68,7 +68,7 @@ For example, consider the case below where we want to bridge two Substrate based ``` +---------------+ +---------------+ | | | | -| Rialto | | Millau | +| Rococo | | Westend | | | | | +-------+-------+ +-------+-------+ ^ ^ @@ -79,9 +79,9 @@ For example, consider the case below where we want to bridge two Substrate based +---------------+ ``` -The Millau chain must be able to accept Rialto headers and verify their integrity. It does this by using a runtime +The Rococo chain must be able to accept Westend headers and verify their integrity. It does this by using a runtime module designed to track GRANDPA finality. Since two blockchains can't interact directly they need an external service, -called a relayer, to communicate. The relayer will subscribe to new Rialto headers via RPC and submit them to the Millau +called a relayer, to communicate. The relayer will subscribe to new Rococo headers via RPC and submit them to the Westend chain for verification. Take a look at [Bridge High Level Documentation](./docs/high-level-overview.md) for more in-depth description of the @@ -94,164 +94,23 @@ Here's an overview of how the project is laid out. The main bits are the `bin`, messages between chains. ``` -├── bin // Node and Runtime for the various Substrate chains -│ └── ... -├── deployments // Useful tools for deploying test networks +├── modules // Substrate Runtime Modules (a.k.a Pallets) +│ ├── beefy // On-Chain BEEFY Light Client (in progress) +│ ├── grandpa // On-Chain GRANDPA Light Client +│ ├── messages // Cross Chain Message Passing +│ ├── parachains // On-Chain Parachains Light Client +│ ├── relayers // Relayer Rewards Registry +│ ├── xcm-bridge-hub // Multiple Dynamic Bridges Support +│ ├── xcm-bridge-hub-router // XCM Router that may be used to Connect to XCM Bridge Hub +├── primitives // Code shared between modules, runtimes, and relays │ └── ... -├── modules // Substrate Runtime Modules (a.k.a Pallets) -│ ├── beefy // On-Chain BEEFY Light Client (in progress) -│ ├── grandpa // On-Chain GRANDPA Light Client -│ ├── messages // Cross Chain Message Passing -│ ├── parachains // On-Chain Parachains Light Client -│ ├── relayers // Relayer rewards registry +├── relays // Application for sending finality proofs and messages between chains │ └── ... -├── primitives // Code shared between modules, runtimes, and relays -│ └── ... -├── relays // Application for sending finality proofs and messages between chains -│ └── ... -└── scripts // Useful development and maintenance scripts +└── scripts // Useful development and maintenance scripts ``` ## Running the Bridge -To run the Bridge you need to be able to connect the bridge relay node to the RPC interface of nodes on each side of the -bridge (source and target chain). - -There are 2 ways to run the bridge, described below: - -- building & running from source: with this option, you'll be able to run the bridge between two standalone chains that -are running GRANDPA finality gadget to achieve finality; - -- running a Docker Compose setup: this is a recommended option, where you'll see bridges with parachains, complex relays -and more. - -### Using the Source - -First you'll need to build the bridge nodes and relay. This can be done as follows: - -```bash -# In `parity-bridges-common` folder -cargo build -p rialto-bridge-node -cargo build -p millau-bridge-node -cargo build -p substrate-relay -``` - -### Running a Dev network - -We will launch a dev network to demonstrate how to relay a message between two Substrate based chains (named Rialto and -Millau). - -To do this we will need two nodes, two relayers which will relay headers, and two relayers which will relay messages. - -#### Running from local scripts - -To run a simple dev network you can use the scripts located in the [`deployments/local-scripts` -folder](./deployments/local-scripts). - -First, we must run the two Substrate nodes. - -```bash -# In `parity-bridges-common` folder -./deployments/local-scripts/run-rialto-node.sh -./deployments/local-scripts/run-millau-node.sh -``` - -After the nodes are up we can run the header relayers. - -```bash -./deployments/local-scripts/relay-millau-to-rialto.sh -./deployments/local-scripts/relay-rialto-to-millau.sh -``` - -At this point you should see the relayer submitting headers from the Millau Substrate chain to the Rialto Substrate -chain. - -``` -# Header Relayer Logs -[Millau_to_Rialto_Sync] [date] DEBUG bridge Going to submit finality proof of Millau header #147 to Rialto -[...] [date] INFO bridge Synced 147 of 147 headers -[...] [date] DEBUG bridge Going to submit finality proof of Millau header #148 to Rialto -[...] [date] INFO bridge Synced 148 of 149 headers -``` - -Finally, we can run the message relayers. - -```bash -./deployments/local-scripts/relay-messages-millau-to-rialto.sh -./deployments/local-scripts/relay-messages-rialto-to-millau.sh -``` - -You will also see the message lane relayers listening for new messages. - -``` -# Message Relayer Logs -[Millau_to_Rialto_MessageLane_00000000] [date] DEBUG bridge Asking Millau::ReceivingConfirmationsDelivery about best message nonces -[...] [date] INFO bridge Synced Some(2) of Some(3) nonces in Millau::MessagesDelivery -> Rialto::MessagesDelivery race -[...] [date] DEBUG bridge Asking Millau::MessagesDelivery about message nonces -[...] [date] DEBUG bridge Received best nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { - latest_nonce: 0, nonces_data: () } -[...] [date] DEBUG bridge Asking Millau::ReceivingConfirmationsDelivery about finalized message nonces -[...] [date] DEBUG bridge Received finalized nonces from Millau::ReceivingConfirmationsDelivery: TargetClientNonces { - latest_nonce: 0, nonces_data: () } -[...] [date] DEBUG bridge Received nonces from Millau::MessagesDelivery: SourceClientNonces { new_nonces: {}, confirmed_nonce: Some(0) } -[...] [date] DEBUG bridge Asking Millau node about its state -[...] [date] DEBUG bridge Received state from Millau node: ClientState { best_self: HeaderId(1593, 0xacac***), best_finalized_self: - HeaderId(1590, 0x0be81d...), best_finalized_peer_at_best_self: HeaderId(0, 0xdcdd89...) } -``` - -To send a message see the ["How to send a message" section](#how-to-send-a-message). - -### How to send a message - -In this section we'll show you how to quickly send a bridge message. The message is just an encoded XCM `Trap(43)` -message. - -```bash -# In `parity-bridges-common` folder -./scripts/send-message-from-millau-rialto.sh -``` - -After sending a message you will see the following logs showing a message was successfully sent: - -``` -INFO bridge Sending message to Rialto. Size: 11. -TRACE bridge Sent transaction to Millau node: 0x5e68... -``` - -And at the Rialto node logs you'll something like this: - -``` -... runtime::bridge-messages: Received messages: total=1, valid=1. Weight used: Weight(ref_time: 1215065371, proof_size: - 48559)/Weight(ref_time: 1215065371, proof_size: 54703). -``` - -It means that the message has been delivered and dispatched. Message may be dispatched with an error, though - the goal -of our test bridge is to ensure that messages are successfully delivered and all involved components are working. - -## Full Network Docker Compose Setup - -For a more sophisticated deployment which includes bidirectional header sync, message passing, monitoring dashboards, -etc. see the [Deployments README](./deployments/README.md). - -You should note that you can find images for all the bridge components published on [Docker -Hub](https://hub.docker.com/u/paritytech). - -To run a Rialto node for example, you can use the following command: - -```bash -docker run -p 30333:30333 -p 9933:9933 -p 9944:9944 \ - -it paritytech/rialto-bridge-node --dev --tmp \ - --rpc-cors=all --unsafe-rpc-external -``` - -## Community - -Main hangout for the community is [Element](https://element.io/) (formerly Riot). Element is a chat server like, for -example, Discord. Most discussions around Polkadot and Substrate happen in various Element "rooms" (channels). So, -joining Element might be a good idea, anyway. - -If you are interested in information exchange and development of Polkadot related bridges please feel free to join the -[Polkadot Bridges](https://app.element.io/#/room/#bridges:web3.foundation) Element channel. - -The [Substrate Technical](https://app.element.io/#/room/#substrate-technical:matrix.org) Element channel is most suited -for discussions regarding Substrate itself. +Apart from live Rococo <> Westend bridge, you may spin up local networks and test see how it works locally. More +details may be found in +[this document](https://github.com/paritytech/polkadot-sdk/tree/master//cumulus/parachains/runtimes/bridge-hubs/README.md). diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index ae6f40b1421..d3b3b21061d 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -22,7 +22,6 @@ use crate::messages_call_ext::MessagesCallSubType; use pallet_bridge_grandpa::CallSubType as GrandpaCallSubType; use pallet_bridge_parachains::CallSubType as ParachainsCallSubtype; use sp_runtime::transaction_validity::TransactionValidity; -use xcm::v3::NetworkId; pub mod messages; pub mod messages_api; @@ -92,8 +91,8 @@ where /// ```nocompile /// generate_bridge_reject_obsolete_headers_and_messages!{ /// Call, AccountId -/// BridgeRialtoGrandpa, BridgeWestendGrandpa, -/// BridgeRialtoParachains +/// BridgeRococoGrandpa, BridgeRococoMessages, +/// BridgeRococoParachains /// } /// ``` /// @@ -147,42 +146,6 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { }; } -/// A mapping over `NetworkId`. -/// Since `NetworkId` doesn't include `Millau`, `Rialto` and `RialtoParachain`, we create some -/// synthetic associations between these chains and `NetworkId` chains. -pub enum CustomNetworkId { - /// The Millau network ID, associated with Kusama. - Millau, - /// The Rialto network ID, associated with Polkadot. - Rialto, - /// The RialtoParachain network ID, associated with Westend. - RialtoParachain, -} - -impl TryFrom for CustomNetworkId { - type Error = (); - - fn try_from(chain: bp_runtime::ChainId) -> Result { - Ok(match chain { - bp_runtime::MILLAU_CHAIN_ID => Self::Millau, - bp_runtime::RIALTO_CHAIN_ID => Self::Rialto, - bp_runtime::RIALTO_PARACHAIN_CHAIN_ID => Self::RialtoParachain, - _ => return Err(()), - }) - } -} - -impl CustomNetworkId { - /// Converts self to XCM' network id. - pub const fn as_network_id(&self) -> NetworkId { - match *self { - CustomNetworkId::Millau => NetworkId::Kusama, - CustomNetworkId::Rialto => NetworkId::Polkadot, - CustomNetworkId::RialtoParachain => NetworkId::Westend, - } - } -} - #[cfg(test)] mod tests { use crate::BridgeRuntimeFilterCall; diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 67ae974668e..ffabf7f6e2f 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -14,12 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! A mock runtime for testing different stuff in the crate. We've been using Millau -//! runtime for that before, but it has two drawbacks: -//! -//! - circular dependencies between this crate and Millau runtime; -//! -//! - we can't use (e.g. as git subtree or by copying) this crate in repo without Millau. +//! A mock runtime for testing different stuff in the crate. #![cfg(test)] @@ -44,13 +39,13 @@ use bp_runtime::{ }; use codec::{Decode, Encode}; use frame_support::{ - parameter_types, + derive_impl, parameter_types, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, }; use pallet_transaction_payment::Multiplier; use sp_runtime::{ testing::H256, - traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8, IdentityLookup}, + traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8}, FixedPointNumber, Perquintill, }; @@ -146,30 +141,14 @@ parameter_types! { pub const ReserveId: [u8; 8] = *b"brdgrlrs"; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; type Hash = ThisChainHash; type Hashing = ThisChainHasher; type AccountId = ThisChainAccountId; - type Lookup = IdentityLookup; type Block = ThisChainBlock; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU32<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = DbWeight; - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type BlockHashCount = ConstU32<250>; } impl pallet_utility::Config for TestRuntime { @@ -179,21 +158,10 @@ impl pallet_utility::Config for TestRuntime { type WeightInfo = (); } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for TestRuntime { - type Balance = ThisChainBalance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type AccountStore = System; } impl pallet_transaction_payment::Config for TestRuntime { diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index fd103448125..a597fb9e2f4 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -27,6 +27,7 @@ use frame_support::traits::Get; use sp_runtime::transaction_validity::TransactionPriority; // reexport everything from `integrity_tests` module +#[allow(unused_imports)] pub use integrity_tests::*; /// Compute priority boost for message delivery transaction that delivers diff --git a/bridges/docs/high-level-overview.md b/bridges/docs/high-level-overview.md index 42efc8100bd..d6d6fb3f099 100644 --- a/bridges/docs/high-level-overview.md +++ b/bridges/docs/high-level-overview.md @@ -1,7 +1,7 @@ # High-Level Bridge Documentation This document gives a brief, abstract description of main components that may be found in this repository. If you want -to see how we're using them to build Rococo <> Wococo (Kusama <> Polkadot) bridge, please refer to the [Polkadot <> +to see how we're using them to build Rococo <> Westend (Kusama <> Polkadot) bridge, please refer to the [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md). ## Purpose diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index f88a0a3e6a6..7efa84971fe 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -20,16 +20,9 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::Chain; use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstU32, ConstU64, Hooks}, - weights::Weight, + construct_runtime, derive_impl, parameter_types, traits::Hooks, weights::Weight, }; use sp_core::sr25519::Signature; -use sp_runtime::{ - testing::H256, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; pub type AccountId = u64; pub type TestHeader = sp_runtime::testing::Header; @@ -49,43 +42,14 @@ construct_runtime! { } } -parameter_types! { - pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); -} - +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type DbWeight = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { pub const MaxFreeMandatoryHeadersPerBlock: u32 = 2; pub const HeadersToKeep: u32 = 5; - pub const SessionLength: u64 = 5; - pub const NumValidators: u32 = 5; } impl grandpa::Config for TestRuntime { diff --git a/bridges/modules/grandpa/src/weights.rs b/bridges/modules/grandpa/src/weights.rs index 89ed70d13ac..a75e7b5a8e4 100644 --- a/bridges/modules/grandpa/src/weights.rs +++ b/bridges/modules/grandpa/src/weights.rs @@ -23,7 +23,7 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/millau-bridge-node +// target/release/unknown-bridge-node // benchmark // pallet // --chain=dev @@ -58,39 +58,39 @@ pub trait WeightInfo { /// Those weights are test only and must never be used in production. pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { - /// Storage: BridgeRialtoGrandpa PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownGrandpa PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa RequestCount (r:1 w:1) + /// Storage: BridgeUnknownGrandpa RequestCount (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: 499, - /// mode: MaxEncodedLen) + /// Proof: BridgeUnknownGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: + /// 499, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa BestFinalized (r:1 w:1) + /// Storage: BridgeUnknownGrandpa BestFinalized (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: + /// Proof: BridgeUnknownGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: /// 531, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa CurrentAuthoritySet (r:1 w:0) + /// Storage: BridgeUnknownGrandpa CurrentAuthoritySet (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), + /// Proof: BridgeUnknownGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), /// added: 704, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHashesPointer (r:1 w:1) + /// Storage: BridgeUnknownGrandpa ImportedHashesPointer (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), + /// Proof: BridgeUnknownGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), /// added: 499, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHashes (r:1 w:1) + /// Storage: BridgeUnknownGrandpa ImportedHashes (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), + /// Proof: BridgeUnknownGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), /// added: 2016, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:0 w:2) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:0 w:2) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 4]`. @@ -113,39 +113,39 @@ impl WeightInfo for BridgeWeight { // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: BridgeRialtoGrandpa PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownGrandpa PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa RequestCount (r:1 w:1) + /// Storage: BridgeUnknownGrandpa RequestCount (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: 499, - /// mode: MaxEncodedLen) + /// Proof: BridgeUnknownGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: + /// 499, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa BestFinalized (r:1 w:1) + /// Storage: BridgeUnknownGrandpa BestFinalized (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: + /// Proof: BridgeUnknownGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: /// 531, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa CurrentAuthoritySet (r:1 w:0) + /// Storage: BridgeUnknownGrandpa CurrentAuthoritySet (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), + /// Proof: BridgeUnknownGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), /// added: 704, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHashesPointer (r:1 w:1) + /// Storage: BridgeUnknownGrandpa ImportedHashesPointer (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), + /// Proof: BridgeUnknownGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), /// added: 499, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHashes (r:1 w:1) + /// Storage: BridgeUnknownGrandpa ImportedHashes (r:1 w:1) /// - /// Proof: BridgeRialtoGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), + /// Proof: BridgeUnknownGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), /// added: 2016, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:0 w:2) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:0 w:2) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 4]`. diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index d3d68b33802..a5c86693309 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -22,7 +22,6 @@ bp-runtime = { path = "../../primitives/runtime", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } @@ -43,7 +42,6 @@ std = [ "log/std", "num-traits/std", "scale-info/std", - "sp-core/std", "sp-runtime/std", "sp-std/std", ] diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs index e98f9e1f5de..648acad772d 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/mock.rs @@ -34,16 +34,11 @@ use bp_messages::{ use bp_runtime::{messages::MessageDispatchResult, Size}; use codec::{Decode, Encode}; use frame_support::{ - parameter_types, - traits::ConstU64, + derive_impl, parameter_types, weights::{constants::RocksDbWeight, Weight}, }; use scale_info::TypeInfo; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, ConstU32, IdentityLookup}, - BuildStorage, Perbill, -}; +use sp_runtime::BuildStorage; use std::{ collections::{BTreeMap, VecDeque}, ops::RangeInclusive, @@ -84,56 +79,19 @@ frame_support::construct_runtime! { } } -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); -} - pub type DbWeight = RocksDbWeight; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); type DbWeight = DbWeight; - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for TestRuntime { - type MaxLocks = (); - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU64<1>; - type AccountStore = frame_system::Pallet; - type WeightInfo = (); - type MaxReserves = (); - type ReserveIdentifier = (); - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type ReserveIdentifier = [u8; 8]; + type AccountStore = System; } parameter_types! { diff --git a/bridges/modules/messages/src/weights.rs b/bridges/modules/messages/src/weights.rs index 5b6863984ec..5bf7d567560 100644 --- a/bridges/modules/messages/src/weights.rs +++ b/bridges/modules/messages/src/weights.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Autogenerated weights for RialtoMessages +//! Autogenerated weights for pallet_bridge_messages //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -23,13 +23,13 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/millau-bridge-node +// target/release/unknown-bridge-node // benchmark // pallet // --chain=dev // --steps=50 // --repeat=20 -// --pallet=RialtoMessages +// --pallet=pallet_bridge_messages // --extrinsic=* // --execution=wasm // --wasm-execution=Compiled @@ -48,7 +48,7 @@ use frame_support::{ }; use sp_std::marker::PhantomData; -/// Weight functions needed for RialtoMessages. +/// Weight functions needed for pallet_bridge_messages. pub trait WeightInfo { fn receive_single_message_proof() -> Weight; fn receive_two_messages_proof() -> Weight; @@ -61,24 +61,24 @@ pub trait WeightInfo { fn receive_single_message_proof_with_dispatch(i: u32) -> Weight; } -/// Weights for `RialtoMessages` that are generated using one of the Bridge testnets. +/// Weights for `pallet_bridge_messages` that are generated using one of the Bridge testnets. /// /// Those weights are test only and must never be used in production. pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: @@ -89,19 +89,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: @@ -112,19 +112,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: @@ -135,19 +135,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: @@ -158,19 +158,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: @@ -181,19 +181,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) @@ -209,19 +209,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) @@ -237,19 +237,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) @@ -265,19 +265,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) /// /// The range of component `i` is `[128, 2048]`. @@ -296,19 +296,19 @@ impl WeightInfo for BridgeWeight { // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: @@ -319,19 +319,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: @@ -342,19 +342,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: @@ -365,19 +365,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: @@ -388,19 +388,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: @@ -411,19 +411,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) @@ -439,19 +439,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) @@ -467,19 +467,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages OutboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// Proof: BridgeUnknownMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: /// 539, mode: MaxEncodedLen) /// /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) @@ -495,19 +495,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) /// /// The range of component `i` is `[128, 2048]`. diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index 14afe384171..d95e76f3108 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -17,17 +17,18 @@ use bp_header_chain::ChainWithGrandpa; use bp_polkadot_core::parachains::ParaId; use bp_runtime::{Chain, Parachain}; -use frame_support::{construct_runtime, parameter_types, traits::ConstU32, weights::Weight}; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, traits::ConstU32, weights::Weight, +}; use sp_runtime::{ testing::H256, - traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, - MultiSignature, Perbill, + traits::{BlakeTwo256, Header as HeaderT}, + MultiSignature, }; use crate as pallet_bridge_parachains; pub type AccountId = u64; -pub type TestNumber = u64; pub type RelayBlockHeader = sp_runtime::generic::Header; @@ -152,42 +153,12 @@ construct_runtime! { } } -parameter_types! { - pub const BlockHashCount: TestNumber = 250; - pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); -} - +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; type Block = Block; - type Hash = H256; - type Hashing = RegularParachainHasher; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type DbWeight = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { - pub const SessionLength: u64 = 5; - pub const NumValidators: u32 = 5; pub const HeadersToKeep: u32 = 5; } diff --git a/bridges/modules/parachains/src/weights.rs b/bridges/modules/parachains/src/weights.rs index 9182ec46611..abddc876894 100644 --- a/bridges/modules/parachains/src/weights.rs +++ b/bridges/modules/parachains/src/weights.rs @@ -23,7 +23,7 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/millau-bridge-node +// target/release/unknown-bridge-node // benchmark // pallet // --chain=dev @@ -60,29 +60,29 @@ pub trait WeightInfo { /// Those weights are test only and must never be used in production. pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 2]`. @@ -97,29 +97,29 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: @@ -130,29 +130,29 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: @@ -167,29 +167,29 @@ impl WeightInfo for BridgeWeight { // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 2]`. @@ -204,29 +204,29 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: @@ -237,29 +237,29 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// Storage: BridgeUnknownParachains PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// Proof: BridgeUnknownParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), /// added: 496, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// Storage: BridgeUnknownParachains ParasInfo (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// Proof: BridgeUnknownParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: /// 555, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHashes (r:1 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHashes (max_values: Some(1024), max_size: /// Some(64), added: 1549, mode: MaxEncodedLen) /// - /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// Storage: BridgeUnknownParachains ImportedParaHeads (r:0 w:1) /// - /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Proof: BridgeUnknownParachains ImportedParaHeads (max_values: Some(1024), max_size: /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: diff --git a/bridges/modules/parachains/src/weights_ext.rs b/bridges/modules/parachains/src/weights_ext.rs index 13bc9ad2bbc..393086a8569 100644 --- a/bridges/modules/parachains/src/weights_ext.rs +++ b/bridges/modules/parachains/src/weights_ext.rs @@ -31,7 +31,7 @@ use frame_support::weights::{RuntimeDbWeight, Weight}; pub const DEFAULT_PARACHAIN_HEAD_SIZE: u32 = 384; /// Number of extra bytes (excluding size of storage value itself) of storage proof, built at -/// the Rialto chain. +/// some generic chain. pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Extended weight info. diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 10b60c3006b..6ec1971e3f6 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -30,7 +30,6 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false [dev-dependencies] bp-runtime = { path = "../../primitives/runtime" } pallet-balances = { path = "../../../substrate/frame/balances" } -sp-core = { path = "../../../substrate/primitives/core" } sp-io = { path = "../../../substrate/primitives/io" } sp-runtime = { path = "../../../substrate/primitives/runtime" } diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index d19d47eec5c..667b10e5c12 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -22,12 +22,10 @@ use bp_messages::LaneId; use bp_relayers::{ PayRewardFromAccount, PaymentProcedure, RewardsAccountOwner, RewardsAccountParams, }; -use frame_support::{parameter_types, traits::fungible::Mutate, weights::RuntimeDbWeight}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, ConstU32, IdentityLookup}, - BuildStorage, +use frame_support::{ + derive_impl, parameter_types, traits::fungible::Mutate, weights::RuntimeDbWeight, }; +use sp_runtime::BuildStorage; pub type AccountId = u64; pub type Balance = u64; @@ -61,47 +59,17 @@ parameter_types! { pub const Lease: BlockNumber = 8; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; type Block = Block; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = frame_support::traits::ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); type DbWeight = DbWeight; - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for TestRuntime { - type MaxLocks = (); - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = frame_system::Pallet; - type WeightInfo = (); - type MaxReserves = ConstU32<1>; type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type AccountStore = System; } impl pallet_bridge_relayers::Config for TestRuntime { diff --git a/bridges/modules/relayers/src/weights.rs b/bridges/modules/relayers/src/weights.rs index 2e064a3936d..c2c065b0c0a 100644 --- a/bridges/modules/relayers/src/weights.rs +++ b/bridges/modules/relayers/src/weights.rs @@ -23,7 +23,7 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/millau-bridge-node +// target/release/rip-bridge-node // benchmark // pallet // --chain=dev diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 2152b4eb28f..2d173ebc045 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -19,13 +19,9 @@ use crate as pallet_xcm_bridge_hub_router; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; -use frame_support::{construct_runtime, parameter_types}; +use frame_support::{construct_runtime, derive_impl, parameter_types}; use frame_system::EnsureRoot; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, ConstU128, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::{traits::ConstU128, BuildStorage}; use xcm::prelude::*; use xcm_builder::{NetworkExportTable, NetworkExportTableItem}; @@ -64,30 +60,9 @@ parameter_types! { ]; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for TestRuntime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; type Block = Block; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = frame_support::traits::ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index 62936e997f3..b0c8fc6252c 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -23,7 +23,7 @@ //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/millau-bridge-node +// target/release/rip-bridge-node // benchmark // pallet // --chain=dev diff --git a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml b/bridges/primitives/chain-asset-hub-kusama/Cargo.toml deleted file mode 100644 index 3e53f9407ff..00000000000 --- a/bridges/primitives/chain-asset-hub-kusama/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "bp-asset-hub-kusama" -description = "Primitives of AssetHubKusama 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.10.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-kusama/src/lib.rs b/bridges/primitives/chain-asset-hub-kusama/src/lib.rs deleted file mode 100644 index 94016c1da0c..00000000000 --- a/bridges/primitives/chain-asset-hub-kusama/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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 AssetHubKusama 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; - -/// `AssetHubKusama` Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to `AssetHubKusama` 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 -/// `AssetHubKusama` `construct_runtime`, so that we maintain SCALE-compatibility. -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// `ToPolkadotXcmRouter` bridge pallet. - #[codec(index = 43)] - ToPolkadotXcmRouter(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 `BridgeHubKusama`. - /// (initially was calculated `170733333` + `10%` by test `BridgeHubKusama::can_calculate_weight_for_paid_export_message_with_reserve_transfer`) - pub const BridgeHubKusamaBaseFeeInDots: u128 = 187806666; -} diff --git a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml b/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml deleted file mode 100644 index 9c1b1a1f326..00000000000 --- a/bridges/primitives/chain-asset-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "bp-asset-hub-polkadot" -description = "Primitives of AssetHubPolkadot 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.10.0", default-features = false, features = ["derive"] } - -# Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", 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", - "sp-runtime/std", -] diff --git a/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs b/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs deleted file mode 100644 index 486fba60e1f..00000000000 --- a/bridges/primitives/chain-asset-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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 AssetHubPolkadot 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; - -/// `AssetHubPolkadot` Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to `AssetHubPolkadot` 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 -/// `AssetHubPolkadot` `construct_runtime`, so that we maintain SCALE-compatibility. -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// `ToKusamaXcmRouter` bridge pallet. - #[codec(index = 43)] - ToKusamaXcmRouter(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 `BridgeHubPolkadot`. - /// (initially was calculated `51220000` + `10%` by test `BridgeHubPolkadot::can_calculate_weight_for_paid_export_message_with_reserve_transfer`) - pub const BridgeHubPolkadotBaseFeeInDots: u128 = 56342000; -} diff --git a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs index 6216b24d75c..de2e9ae856d 100644 --- a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs @@ -34,9 +34,6 @@ pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; #[allow(clippy::large_enum_variant)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum Call { - /// `ToWococoXcmRouter` bridge pallet. - #[codec(index = 43)] - ToWococoXcmRouter(XcmBridgeHubRouterCall), /// `ToWestendXcmRouter` bridge pallet. #[codec(index = 45)] ToWestendXcmRouter(XcmBridgeHubRouterCall), diff --git a/bridges/primitives/chain-asset-hub-wococo/Cargo.toml b/bridges/primitives/chain-asset-hub-wococo/Cargo.toml deleted file mode 100644 index e1a5a262157..00000000000 --- a/bridges/primitives/chain-asset-hub-wococo/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[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.10.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 deleted file mode 100644 index c04eb04cce7..00000000000 --- a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -// 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); -} - -/// 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/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index 24cf7236d45..46697913674 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bp-bridge-hub-cumulus" -description = "Primitives of BridgeHubRococo parachain runtime." +description = "Primitives for BridgeHub parachain runtimes." version = "0.1.0" authors.workspace = true edition.workspace = true diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index 387f5e8ade6..c4cd229ef43 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bp-bridge-hub-kusama" -description = "Primitives of BridgeHubRococo parachain runtime." +description = "Primitives of BridgeHubKusama parachain runtime." version = "0.1.0" authors.workspace = true edition.workspace = true diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 40b386e22d2..4913d87e5fb 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bp-bridge-hub-polkadot" -description = "Primitives of BridgeHubWococo parachain runtime." +description = "Primitives of BridgeHubPolkadot parachain runtime." version = "0.1.0" authors.workspace = true edition.workspace = true diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index e72e711de92..59d293edf1c 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -74,9 +74,6 @@ 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_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_INDEX: u8 = 46; - /// Pallet index of `BridgeWestendMessages: pallet_bridge_messages::`. pub const WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX: u8 = 51; diff --git a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml deleted file mode 100644 index 17c134f4412..00000000000 --- a/bridges/primitives/chain-bridge-hub-wococo/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "bp-bridge-hub-wococo" -description = "Primitives of BridgeHubWococo parachain runtime." -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" - -[dependencies] - -# Bridge Dependencies - -bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-messages = { path = "../messages", default-features = false } - -# Substrate Based Dependencies - -frame-support = { path = "../../../substrate/frame/support", 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-bridge-hub-cumulus/std", - "bp-messages/std", - "bp-runtime/std", - "frame-support/std", - "sp-api/std", - "sp-runtime/std", - "sp-std/std", -] diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs deleted file mode 100644 index c8bd397cec5..00000000000 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ /dev/null @@ -1,90 +0,0 @@ -// 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 BridgeHubWococo runtime setup -//! (AccountId, Headers, Hashes...) - -#![cfg_attr(not(feature = "std"), no_std)] - -pub use bp_bridge_hub_cumulus::*; -use bp_messages::*; -use bp_runtime::{ - decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, Parachain, -}; -use frame_support::dispatch::DispatchClass; -use sp_runtime::RuntimeDebug; - -/// BridgeHubWococo parachain. -#[derive(RuntimeDebug)] -pub struct BridgeHubWococo; - -impl Chain for BridgeHubWococo { - type BlockNumber = BlockNumber; - type Hash = Hash; - type Hasher = Hasher; - type Header = Header; - - type AccountId = AccountId; - 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 Parachain for BridgeHubWococo { - const PARACHAIN_ID: u32 = BRIDGE_HUB_WOCOCO_PARACHAIN_ID; -} - -/// Identifier of BridgeHubWococo in the Wococo relay chain. -pub const BRIDGE_HUB_WOCOCO_PARACHAIN_ID: u32 = 1014; - -/// Name of the With-BridgeHubWococo messages pallet instance that is deployed at bridged chains. -pub const WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; - -/// Name of the With-BridgeHubWococo bridge-relayers pallet instance that is deployed at bridged -/// chains. -pub const WITH_BRIDGE_HUB_WOCOCO_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; - -/// Pallet index of `BridgeRococoMessages: pallet_bridge_messages::`. -pub const WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 45; - -decl_bridge_finality_runtime_apis!(bridge_hub_wococo); -decl_bridge_messages_runtime_apis!(bridge_hub_wococo); - -frame_support::parameter_types! { - /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Wococo - /// BridgeHub. - /// (initially was calculated by test `BridgeHubWococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubWococoBaseXcmFeeInWocs: u128 = 1624803349; - - /// Transaction fee that is paid at the Wococo BridgeHub for delivering single inbound message. - /// (initially was calculated by test `BridgeHubWococo::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) - pub const BridgeHubWococoBaseDeliveryFeeInWocs: u128 = 6417262881; - - /// Transaction fee that is paid at the Wococo BridgeHub for delivering single outbound message confirmation. - /// (initially was calculated by test `BridgeHubWococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubWococoBaseConfirmationFeeInWocs: u128 = 6159996668; -} diff --git a/bridges/primitives/chain-wococo/Cargo.toml b/bridges/primitives/chain-wococo/Cargo.toml deleted file mode 100644 index 05901821b36..00000000000 --- a/bridges/primitives/chain-wococo/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "bp-wococo" -description = "Primitives of Wococo runtime." -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" - -[dependencies] - -# Bridge Dependencies - -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-rococo = { path = "../chain-rococo", default-features = false } - -# Substrate Based Dependencies - -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } - -[features] -default = [ "std" ] -std = [ - "bp-header-chain/std", - "bp-polkadot-core/std", - "bp-rococo/std", - "bp-runtime/std", - "frame-support/std", - "sp-api/std", - "sp-std/std", -] diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs deleted file mode 100644 index b1df65630be..00000000000 --- a/bridges/primitives/chain-wococo/src/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -// 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 . - -#![cfg_attr(not(feature = "std"), no_std)] -// RuntimeApi generated functions -#![allow(clippy::too_many_arguments)] - -pub use bp_polkadot_core::*; -pub use bp_rococo::{ - SS58Prefix, MAX_AUTHORITIES_COUNT, MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE, PARAS_PALLET_NAME, -}; - -use bp_header_chain::ChainWithGrandpa; -use bp_runtime::{decl_bridge_finality_runtime_apis, Chain}; -use frame_support::weights::Weight; - -/// Wococo Chain -pub struct Wococo; - -impl Chain for Wococo { - type BlockNumber = ::BlockNumber; - type Hash = ::Hash; - type Hasher = ::Hasher; - type Header = ::Header; - - type AccountId = ::AccountId; - type Balance = ::Balance; - type Nonce = ::Nonce; - type Signature = ::Signature; - - fn max_extrinsic_size() -> u32 { - PolkadotLike::max_extrinsic_size() - } - - fn max_extrinsic_weight() -> Weight { - PolkadotLike::max_extrinsic_weight() - } -} - -impl ChainWithGrandpa for Wococo { - const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_WOCOCO_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; -} - -// The SignedExtension used by Wococo. -pub use bp_rococo::CommonSignedExtension as SignedExtension; - -/// Name of the With-Wococo GRANDPA pallet instance that is deployed at bridged chains. -pub const WITH_WOCOCO_GRANDPA_PALLET_NAME: &str = "BridgeWococoGrandpa"; - -decl_bridge_finality_runtime_apis!(wococo, grandpa); diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index e1809e14524..b78023efb1b 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -280,7 +280,7 @@ pub type TransactionEraOf = crate::TransactionEra, HashOf /// - constants that are stringified names of runtime API methods: /// - `BEST_FINALIZED__HEADER_METHOD` /// - `_ACCEPTED__FINALITY_PROOFS_METHOD` -/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_finality_runtime_apis { ($chain: ident $(, $consensus: ident => $justification_type: ty)?) => { @@ -332,7 +332,7 @@ macro_rules! decl_bridge_finality_runtime_apis { /// - `FromInboundLaneApi` /// - constants that are stringified names of runtime API methods: /// - `FROM__MESSAGE_DETAILS_METHOD`, -/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_messages_runtime_apis { ($chain: ident) => { @@ -390,7 +390,7 @@ macro_rules! decl_bridge_messages_runtime_apis { /// Convenience macro that declares bridge finality runtime apis, bridge messages runtime apis /// and related constants for a chain. -/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_runtime_apis { ($chain: ident $(, $consensus: ident)?) => { diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index 44eeaad93c9..8a618721b23 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -88,7 +88,7 @@ pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<( /// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), /// ())` is the same. So runtime can contains any kind of tuple: /// `(BridgeRefundBridgeHubRococoMessages)` -/// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWococoMessages)` +/// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)` /// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index e5277d8db6a..0513cfa2a6c 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -61,15 +61,6 @@ pub use sp_runtime::paste; /// Use this when something must be shared among all instances. pub const NO_INSTANCE_ID: ChainId = [0, 0, 0, 0]; -/// Rialto chain id. -pub const RIALTO_CHAIN_ID: ChainId = *b"rlto"; - -/// RialtoParachain chain id. -pub const RIALTO_PARACHAIN_CHAIN_ID: ChainId = *b"rlpa"; - -/// Millau chain id. -pub const MILLAU_CHAIN_ID: ChainId = *b"mlau"; - /// Polkadot chain id. pub const POLKADOT_CHAIN_ID: ChainId = *b"pdot"; @@ -88,15 +79,9 @@ pub const ASSET_HUB_WESTEND_CHAIN_ID: ChainId = *b"ahwe"; /// Rococo chain id. pub const ROCOCO_CHAIN_ID: ChainId = *b"roco"; -/// Wococo chain id. -pub const WOCOCO_CHAIN_ID: ChainId = *b"woco"; - /// BridgeHubRococo chain id. pub const BRIDGE_HUB_ROCOCO_CHAIN_ID: ChainId = *b"bhro"; -/// BridgeHubWococo chain id. -pub const BRIDGE_HUB_WOCOCO_CHAIN_ID: ChainId = *b"bhwo"; - /// BridgeHubWestend chain id. pub const BRIDGE_HUB_WESTEND_CHAIN_ID: ChainId = *b"bhwd"; @@ -277,18 +262,6 @@ pub fn storage_map_final_key( StorageKey(final_key) } -/// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false; -/// }`) is computed. -/// -/// Copied from `frame_support::parameter_types` macro. -pub fn storage_parameter_key(parameter_name: &str) -> StorageKey { - let mut buffer = Vec::with_capacity(1 + parameter_name.len() + 1); - buffer.push(b':'); - buffer.extend_from_slice(parameter_name.as_bytes()); - buffer.push(b':'); - StorageKey(sp_io::hashing::twox_128(&buffer).to_vec()) -} - /// This is how a storage key of storage value is computed. /// /// Copied from `frame_support::storage::storage_prefix`. @@ -574,14 +547,6 @@ where mod tests { use super::*; - #[test] - fn storage_parameter_key_works() { - assert_eq!( - storage_parameter_key("MillauToRialtoConversionRate"), - StorageKey(hex_literal::hex!("58942375551bb0af1682f72786b59d04").to_vec()), - ); - } - #[test] fn storage_value_key_works() { assert_eq!( diff --git a/bridges/scripts/verify-pallets-build.sh b/bridges/scripts/verify-pallets-build.sh index e797f77d026..b96bbf1833b 100755 --- a/bridges/scripts/verify-pallets-build.sh +++ b/bridges/scripts/verify-pallets-build.sh @@ -61,19 +61,12 @@ trap revert_to_clean_state EXIT rm -rf $BRIDGES_FOLDER/.config rm -rf $BRIDGES_FOLDER/.github rm -rf $BRIDGES_FOLDER/.maintain -rm -rf $BRIDGES_FOLDER/bin/millau -rm -rf $BRIDGES_FOLDER/bin/rialto -rm -rf $BRIDGES_FOLDER/bin/rialto-parachain -rm -rf $BRIDGES_FOLDER/bin/.keep rm -rf $BRIDGES_FOLDER/deployments rm -f $BRIDGES_FOLDER/docs/dockerhub-* rm -rf $BRIDGES_FOLDER/fuzz rm -rf $BRIDGES_FOLDER/modules/beefy rm -rf $BRIDGES_FOLDER/modules/shift-session-manager rm -rf $BRIDGES_FOLDER/primitives/beefy -rm -rf $BRIDGES_FOLDER/primitives/chain-millau -rm -rf $BRIDGES_FOLDER/primitives/chain-rialto -rm -rf $BRIDGES_FOLDER/primitives/chain-rialto-parachain rm -rf $BRIDGES_FOLDER/relays rm -rf $BRIDGES_FOLDER/scripts/add_license.sh rm -rf $BRIDGES_FOLDER/scripts/build-containers.sh @@ -81,8 +74,6 @@ rm -rf $BRIDGES_FOLDER/scripts/ci-cache.sh rm -rf $BRIDGES_FOLDER/scripts/dump-logs.sh rm -rf $BRIDGES_FOLDER/scripts/license_header rm -rf $BRIDGES_FOLDER/scripts/regenerate_runtimes.sh -rm -rf $BRIDGES_FOLDER/scripts/send-message-from-millau-rialto.sh -rm -rf $BRIDGES_FOLDER/scripts/send-message-from-rialto-millau.sh rm -rf $BRIDGES_FOLDER/scripts/update-weights.sh rm -rf $BRIDGES_FOLDER/scripts/update-weights-setup.sh rm -rf $BRIDGES_FOLDER/scripts/update_substrate.sh diff --git a/bridges/zombienet/README.md b/bridges/zombienet/README.md index 7f7de770814..b601154b624 100644 --- a/bridges/zombienet/README.md +++ b/bridges/zombienet/README.md @@ -1,4 +1,4 @@ -# Bridges Tests for Local Rococo <> Wococo Bridge +# Bridges Tests for Local Rococo <> Westend Bridge This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both onchain and offchain bridges code. Due to some @@ -9,7 +9,7 @@ To start those tests, you need to: - download latest [zombienet release](https://github.com/paritytech/zombienet/releases); -- build Polkadot binary by running `cargo build -p polkadot --release` command in the +- build Polkadot binary by running `cargo build -p polkadot --release --features fast-runtime` command in the [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; - build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the diff --git a/bridges/zombienet/helpers/wait-hrmp-channel-opened.js b/bridges/zombienet/helpers/wait-hrmp-channel-opened.js new file mode 100644 index 00000000000..e700cab1d74 --- /dev/null +++ b/bridges/zombienet/helpers/wait-hrmp-channel-opened.js @@ -0,0 +1,22 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + const sibling = args[0]; + + while (true) { + const messagingStateAsObj = await api.query.parachainSystem.relevantMessagingState(); + const messagingState = api.createType("Option", messagingStateAsObj); + if (messagingState.isSome) { + const egressChannels = messagingState.unwrap().egressChannels; + if (egressChannels.find(x => x[0] == sibling)) { + return; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 12000)); + } +} + +module.exports = { run } diff --git a/bridges/zombienet/run-tests.sh b/bridges/zombienet/run-tests.sh index 1fdbc6b8d61..22fefd09360 100755 --- a/bridges/zombienet/run-tests.sh +++ b/bridges/zombienet/run-tests.sh @@ -11,11 +11,11 @@ export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_FOLDER/bridges/zombienet/tests export POLKADOT_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot export POLKADOT_PARACHAIN_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot-parachain export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=$POLKADOT_PARACHAIN_BINARY_PATH -export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO=$POLKADOT_PARACHAIN_BINARY_PATH +export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=$POLKADOT_PARACHAIN_BINARY_PATH export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux # bridge configuration -export LANE_ID="00000001" +export LANE_ID="00000002" # tests configuration ALL_TESTS_FOLDER=`mktemp -d` diff --git a/bridges/zombienet/scripts/invoke-script.sh b/bridges/zombienet/scripts/invoke-script.sh index cb21d61ab91..6a3754a8824 100755 --- a/bridges/zombienet/scripts/invoke-script.sh +++ b/bridges/zombienet/scripts/invoke-script.sh @@ -1,5 +1,5 @@ #!/bin/bash pushd $POLKADOT_SDK_FOLDER/cumulus/scripts -./bridges_rococo_wococo.sh $1 +./bridges_rococo_westend.sh $1 popd diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl new file mode 100644 index 00000000000..f68d658cdac --- /dev/null +++ b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl @@ -0,0 +1,26 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub +Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +Creds: config + +# step 1: initialize Westend asset hub +asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-westend-local" within 240 seconds +asset-hub-westend-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1002" within 400 seconds + +# step 2: initialize Westend bridge hub +bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 120 seconds + +# step 3: relay is started elsewhere - let's wait until with-Rococo GRANPDA pallet is initialized at Westend +bridge-hub-westend-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds + +# step 2: send WOC to Rococo +asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-westend-local" within 60 seconds + +# step 3: elsewhere Rococo has sent ROC to //Alice - let's wait for it +asset-hub-westend-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Rococo" within 600 seconds + +# step 4: check that the relayer //Charlie is rewarded by both our AH and target AH +bridge-hub-westend-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726f,BridgedChain,0" within 300 seconds +bridge-hub-westend-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726F,ThisChain,0" within 300 seconds + +# wait until other network test has completed OR exit with an error too +asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl deleted file mode 100644 index a1af2625c1c..00000000000 --- a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl +++ /dev/null @@ -1,25 +0,0 @@ -Description: User is able to transfer ROC from Rococo Asset Hub to Wococo Asset Hub -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml -Creds: config - -# step 1: initialize Wococo asset hub -asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-wococo-local" within 120 seconds - -# step 2: initialize Wococo bridge hub -bridge-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-wococo-local" within 120 seconds - -# step 3: relay is started elsewhere - let's wait until with-Rococo GRANPDA pallet is initialized at Wococo -bridge-hub-wococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds - -# step 2: send WOC to Rococo -asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-wococo-local" within 60 seconds - -# step 3: elsewhere Rococo has sent ROC to //Alice - let's wait for it -asset-hub-wococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Rococo" within 600 seconds - -# step 4: check that the relayer //Charlie is rewarded by both our AH and target AH -bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,BridgedChain,0" within 300 seconds -bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,ThisChain,0" within 300 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-wococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl similarity index 64% rename from bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl rename to bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl index ad2446d58ce..c862fa6d176 100644 --- a/bridges/zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl +++ b/bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl @@ -1,25 +1,26 @@ -Description: User is able to transfer WOC from Wococo Asset Hub to Rococo Asset Hub +Description: User is able to transfer WOC from Westend Asset Hub to Rococo Asset Hub Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml Creds: config # step 1: initialize Rococo asset hub -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 120 seconds +asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 240 seconds +asset-hub-rococo-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1013" within 400 seconds # step 2: initialize Rococo bridge hub bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 120 seconds -# step 3: relay is started elsewhere - let's wait until with-Wococo GRANPDA pallet is initialized at Rococo -bridge-hub-rococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Wococo,0" within 400 seconds +# step 3: relay is started elsewhere - let's wait until with-Westend GRANPDA pallet is initialized at Rococo +bridge-hub-rococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Westend,0" within 400 seconds -# step 4: send ROC to Wococo +# step 4: send ROC to Westend asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds -# step 5: elsewhere Wococo has sent WOC to //Alice - let's wait for it -asset-hub-rococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Wococo" within 600 seconds +# step 5: elsewhere Westend has sent WOC to //Alice - let's wait for it +asset-hub-rococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Westend" within 600 seconds # step 6: check that the relayer //Charlie is rewarded by both our AH and target AH -bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,BridgedChain,0" within 300 seconds -bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,ThisChain,0" within 300 seconds +bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,BridgedChain,0" within 300 seconds +bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,ThisChain,0" within 300 seconds # wait until other network test has completed OR exit with an error too asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-start-relay.sh b/bridges/zombienet/tests/0001-start-relay.sh old mode 100644 new mode 100755 index fc231fba895..7be2cf4d593 --- a/bridges/zombienet/tests/0001-start-relay.sh +++ b/bridges/zombienet/tests/0001-start-relay.sh @@ -1,5 +1,5 @@ #!/bin/bash pushd $POLKADOT_SDK_FOLDER/cumulus/scripts -./bridges_rococo_wococo.sh run-relay +./bridges_rococo_westend.sh run-relay popd diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs index 4af84c82e98..fa9a287adf8 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -56,19 +56,11 @@ pub fn genesis() -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, - bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig { + bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, - bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig { + bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index f4f33677d4a..0773eb0c8eb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -86,9 +86,7 @@ assets-common = { path = "../common", default-features = false } 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", 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-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } [dev-dependencies] @@ -180,10 +178,8 @@ std = [ "assets-common/std", "bp-asset-hub-rococo/std", "bp-asset-hub-westend/std", - "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-westend/std", - "bp-bridge-hub-wococo/std", "codec/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 06dcfb99a65..4492971566b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -16,12 +16,6 @@ //! # 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"] @@ -106,15 +100,6 @@ use crate::xcm_config::{ }; 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, @@ -866,73 +851,11 @@ impl pallet_nfts::Config for Runtime { type Helper = (); } -/// XCM router instance to BridgeHub with bridging capabilities for `Wococo` global -/// consensus with dynamic fees and back-pressure. -pub type ToWococoXcmRouterInstance = pallet_xcm_bridge_hub_router::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::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_xcm_bridge_hub_router::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::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 `Westend` global /// consensus with dynamic fees and back-pressure. pub type ToWestendXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance3; impl pallet_xcm_bridge_hub_router::Config for Runtime { - type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_westend::WeightInfo; + type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; @@ -996,8 +919,6 @@ construct_runtime!( 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, ToWestendXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 45, // The main stage. @@ -1073,9 +994,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] - [pallet_xcm_bridge_hub_router, ToWococo] [pallet_xcm_bridge_hub_router, ToWestend] - [pallet_xcm_bridge_hub_router, ToRococo] // XCM [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. @@ -1332,9 +1251,7 @@ impl_runtime_apis! { type Foreign = pallet_assets::Pallet::; type Pool = pallet_assets::Pallet::; - type ToWococo = XcmBridgeHubRouterBench; type ToWestend = XcmBridgeHubRouterBench; - type ToRococo = XcmBridgeHubRouterBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1402,19 +1319,6 @@ impl_runtime_apis! { } } - 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::( @@ -1428,20 +1332,6 @@ impl_runtime_apis! { xcm_config::bridging::to_westend::AssetHubWestend::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}; @@ -1498,11 +1388,11 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(UNITS), id: Concrete(TokenLocation::get()) }, )); pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; - // AssetHubRococo trusts AssetHubWococo as reserve for WOCs + // AssetHubRococo trusts AssetHubWestend as reserve for WNDs pub TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some( ( - xcm_config::bridging::to_wococo::AssetHubWococo::get(), - MultiAsset::from((xcm_config::bridging::to_wococo::WocLocation::get(), 1000000000000 as u128)) + xcm_config::bridging::to_westend::AssetHubWestend::get(), + MultiAsset::from((xcm_config::bridging::to_westend::WndLocation::get(), 1000000000000 as u128)) ) ); } @@ -1577,9 +1467,7 @@ impl_runtime_apis! { type Foreign = pallet_assets::Pallet::; type Pool = pallet_assets::Pallet::; - type ToWococo = XcmBridgeHubRouterBench; type ToWestend = XcmBridgeHubRouterBench; - type ToRococo = XcmBridgeHubRouterBench; let whitelist: Vec = vec![ // Block Number diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index 0fc36d74ff0..252cf2630f4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -36,9 +36,7 @@ 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_westend; -pub mod pallet_xcm_bridge_hub_router_to_wococo; +pub mod pallet_xcm_bridge_hub_router; pub mod paritydb_weights; pub mod rocksdb_weights; pub mod xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs similarity index 75% rename from cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 8c344b44f78..7e12453583d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_westend.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-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: @@ -48,38 +48,34 @@ 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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `193` - // Estimated: `3658` - // Minimum execution time: 8_528_000 picoseconds. - Weight::from_parts(8_886_000, 0) - .saturating_add(Weight::from_parts(0, 3658)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `154` + // Estimated: `1639` + // Minimum execution time: 7_924_000 picoseconds. + Weight::from_parts(8_199_000, 0) + .saturating_add(Weight::from_parts(0, 1639)) + .saturating_add(T::DbWeight::get().reads(3)) .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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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: `183` - // Estimated: `3648` - // Minimum execution time: 5_170_000 picoseconds. - Weight::from_parts(5_433_000, 0) - .saturating_add(Weight::from_parts(0, 3648)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `144` + // Estimated: `1629` + // Minimum execution time: 4_265_000 picoseconds. + Weight::from_parts(4_417_000, 0) + .saturating_add(Weight::from_parts(0, 1629)) + .saturating_add(T::DbWeight::get().reads(2)) } /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) @@ -87,16 +83,16 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_283_000 picoseconds. - Weight::from_parts(10_762_000, 0) + // Minimum execution time: 10_292_000 picoseconds. + Weight::from_parts(10_797_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 `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) @@ -113,16 +109,16 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`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: `387` // Estimated: `3852` - // Minimum execution time: 52_040_000 picoseconds. - Weight::from_parts(53_500_000, 0) + // Minimum execution time: 61_995_000 picoseconds. + Weight::from_parts(65_137_000, 0) .saturating_add(Weight::from_parts(0, 3852)) .saturating_add(T::DbWeight::get().reads(11)) .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 deleted file mode 100644 index ff00ace25b8..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! 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-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`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: `265` - // Estimated: `3730` - // Minimum execution time: 9_084_000 picoseconds. - Weight::from_parts(9_441_000, 0) - .saturating_add(Weight::from_parts(0, 3730)) - .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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `202` - // Estimated: `3667` - // Minimum execution time: 5_971_000 picoseconds. - Weight::from_parts(6_260_000, 0) - .saturating_add(Weight::from_parts(0, 3667)) - .saturating_add(T::DbWeight::get().reads(3)) - } - /// 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: 10_231_000 picoseconds. - Weight::from_parts(10_861_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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`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: `478` - // Estimated: `3943` - // Minimum execution time: 53_966_000 picoseconds. - Weight::from_parts(55_224_000, 0) - .saturating_add(Weight::from_parts(0, 3943)) - .saturating_add(T::DbWeight::get().reads(11)) - .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 deleted file mode 100644 index ca371f1e6ce..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! 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-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`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: `231` - // Estimated: `3696` - // Minimum execution time: 9_115_000 picoseconds. - Weight::from_parts(9_522_000, 0) - .saturating_add(Weight::from_parts(0, 3696)) - .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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// 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: `183` - // Estimated: `3648` - // Minimum execution time: 5_207_000 picoseconds. - Weight::from_parts(5_534_000, 0) - .saturating_add(Weight::from_parts(0, 3648)) - .saturating_add(T::DbWeight::get().reads(3)) - } - /// 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: 10_437_000 picoseconds. - Weight::from_parts(10_956_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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`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: `425` - // Estimated: `3890` - // Minimum execution time: 52_176_000 picoseconds. - Weight::from_parts(54_067_000, 0) - .saturating_add(Weight::from_parts(0, 3890)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index fe5123a427c..7fab3584250 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 20_940_000 picoseconds. - Weight::from_parts(21_453_000, 3593) + // Minimum execution time: 21_643_000 picoseconds. + Weight::from_parts(22_410_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,15 +65,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 44_310_000 picoseconds. - Weight::from_parts(44_948_000, 6196) + // Minimum execution time: 43_758_000 picoseconds. + Weight::from_parts(44_654_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -92,25 +90,21 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 87_226_000 picoseconds. - Weight::from_parts(89_399_000, 8799) - .saturating_add(T::DbWeight::get().reads(11)) + // Minimum execution time: 87_978_000 picoseconds. + Weight::from_parts(88_517_000, 8799) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } - // 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`) pub fn reserve_asset_deposited() -> Weight { // Proof Size summary in bytes: - // Measured: `39` - // Estimated: `3504` - // Minimum execution time: 7_320_000 picoseconds. - Weight::from_parts(7_453_000, 3504) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 6_883_000 picoseconds. + Weight::from_parts(6_979_000, 1489) + .saturating_add(T::DbWeight::get().reads(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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -131,17 +125,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 183_539_000 picoseconds. - Weight::from_parts(190_968_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 198_882_000 picoseconds. + Weight::from_parts(199_930_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_068_000 picoseconds. - Weight::from_parts(3_228_000, 0) + // Minimum execution time: 3_343_000 picoseconds. + Weight::from_parts(3_487_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -149,15 +143,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 18_788_000 picoseconds. - Weight::from_parts(19_240_000, 3593) + // Minimum execution time: 19_399_000 picoseconds. + Weight::from_parts(19_659_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: `System::Account` (r:2 w:2) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // Storage: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -176,13 +168,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 58_577_000 picoseconds. - Weight::from_parts(59_729_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 59_017_000 picoseconds. + Weight::from_parts(60_543_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -203,9 +193,9 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 45_804_000 picoseconds. - Weight::from_parts(46_702_000, 3610) - .saturating_add(T::DbWeight::get().reads(9)) + // Minimum execution time: 45_409_000 picoseconds. + Weight::from_parts(47_041_000, 3610) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index e2fe122a12d..4454494badc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-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: @@ -48,8 +48,6 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -70,17 +68,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 415_688_000 picoseconds. - Weight::from_parts(433_876_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 440_298_000 picoseconds. + Weight::from_parts(446_508_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_209_000 picoseconds. - Weight::from_parts(3_465_000, 0) + // Minimum execution time: 3_313_000 picoseconds. + Weight::from_parts(3_422_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -88,61 +86,59 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 7_940_000 picoseconds. - Weight::from_parts(8_208_000, 3568) + // Minimum execution time: 9_691_000 picoseconds. + Weight::from_parts(9_948_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: 9_336_000 picoseconds. - Weight::from_parts(9_733_000, 0) + // Minimum execution time: 10_384_000 picoseconds. + Weight::from_parts(11_085_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_368_000 picoseconds. - Weight::from_parts(3_700_000, 0) + // Minimum execution time: 3_438_000 picoseconds. + Weight::from_parts(3_577_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(2_034_000, 0) + // Minimum execution time: 2_126_000 picoseconds. + Weight::from_parts(2_243_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_870_000 picoseconds. - Weight::from_parts(1_972_000, 0) + // Minimum execution time: 2_126_000 picoseconds. + Weight::from_parts(2_207_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_890_000 picoseconds. - Weight::from_parts(1_962_000, 0) + // Minimum execution time: 2_105_000 picoseconds. + Weight::from_parts(2_193_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_660_000 picoseconds. - Weight::from_parts(2_744_000, 0) + // Minimum execution time: 2_999_000 picoseconds. + Weight::from_parts(3_056_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_845_000 picoseconds. - Weight::from_parts(1_945_000, 0) + // Minimum execution time: 2_091_000 picoseconds. + Weight::from_parts(2_176_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -163,9 +159,9 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 54_283_000 picoseconds. - Weight::from_parts(54_969_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 55_728_000 picoseconds. + Weight::from_parts(56_704_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) @@ -174,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 11_850_000 picoseconds. - Weight::from_parts(12_328_000, 3625) + // Minimum execution time: 12_839_000 picoseconds. + Weight::from_parts(13_457_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -183,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_891_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 2_116_000 picoseconds. + Weight::from_parts(2_219_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -204,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 23_644_000 picoseconds. - Weight::from_parts(24_296_000, 3610) + // Minimum execution time: 24_891_000 picoseconds. + Weight::from_parts(25_583_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -215,47 +211,45 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_719_000 picoseconds. - Weight::from_parts(3_896_000, 0) + // Minimum execution time: 3_968_000 picoseconds. + Weight::from_parts(4_122_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: 125_710_000 picoseconds. - Weight::from_parts(132_434_000, 0) + // Minimum execution time: 136_220_000 picoseconds. + Weight::from_parts(137_194_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_650_000 picoseconds. - Weight::from_parts(12_277_000, 0) + // Minimum execution time: 12_343_000 picoseconds. + Weight::from_parts(12_635_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_978_000 picoseconds. - Weight::from_parts(2_070_000, 0) + // Minimum execution time: 2_237_000 picoseconds. + Weight::from_parts(2_315_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_899_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 2_094_000 picoseconds. + Weight::from_parts(2_231_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_133_000 picoseconds. - Weight::from_parts(2_194_000, 0) + // Minimum execution time: 2_379_000 picoseconds. + Weight::from_parts(2_455_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -276,20 +270,18 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 58_644_000 picoseconds. - Weight::from_parts(60_614_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 60_734_000 picoseconds. + Weight::from_parts(61_964_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_185_000 picoseconds. - Weight::from_parts(5_366_000, 0) + // Minimum execution time: 5_500_000 picoseconds. + Weight::from_parts(5_720_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -310,56 +302,54 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 54_443_000 picoseconds. - Weight::from_parts(55_873_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 55_767_000 picoseconds. + Weight::from_parts(56_790_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_909_000 picoseconds. - Weight::from_parts(2_011_000, 0) + // Minimum execution time: 2_201_000 picoseconds. + Weight::from_parts(2_291_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_814_000 picoseconds. - Weight::from_parts(1_956_000, 0) + // Minimum execution time: 2_164_000 picoseconds. + Weight::from_parts(2_241_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_875_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 2_127_000 picoseconds. + Weight::from_parts(2_236_000, 0) } - // 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`) pub fn universal_origin() -> Weight { // Proof Size summary in bytes: - // Measured: `39` - // Estimated: `3504` - // Minimum execution time: 7_376_000 picoseconds. - Weight::from_parts(7_620_000, 3504) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 4_275_000 picoseconds. + Weight::from_parts(4_381_000, 1489) + .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_863_000 picoseconds. - Weight::from_parts(1_964_000, 0) + // Minimum execution time: 2_132_000 picoseconds. + Weight::from_parts(2_216_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_956_000 picoseconds. - Weight::from_parts(2_057_000, 0) + // Minimum execution time: 2_265_000 picoseconds. + Weight::from_parts(2_332_000, 0) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index b0bf9e82729..b85cb76642f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -16,9 +16,8 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, - PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, - ToRococoXcmRouter, ToWestendXcmRouter, ToWococoXcmRouter, TransactionByteFee, - TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ToWestendXcmRouter, + TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, @@ -26,7 +25,7 @@ use assets_common::{ }; use frame_support::{ match_types, parameter_types, - traits::{ConstU32, Contains, Equals, Everything, Get, Nothing, PalletInfoAccess}, + traits::{ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; @@ -61,8 +60,8 @@ use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use cumulus_primitives_core::ParaId; parameter_types! { - pub storage Flavor: RuntimeFlavor = RuntimeFlavor::default(); pub const TokenLocation: MultiLocation = MultiLocation::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); @@ -79,22 +78,6 @@ parameter_types! { pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } -/// 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. @@ -285,8 +268,7 @@ impl Contains for SafeCallFilter { if items.iter().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) || items .iter() - .all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterBaseFee::key())) || - items.iter().all(|(k, _)| k.eq(&Flavor::key())) => + .all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterBaseFee::key())) => return true, _ => (), }; @@ -475,12 +457,8 @@ impl Contains for SafeCallFilter { 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::ToWestendXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) | RuntimeCall::ToRococoXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) ) } @@ -572,11 +550,7 @@ impl xcm_executor::Config for XcmConfig { // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being // held). 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_westend::IsTrustedBridgedReserveLocationForConcreteAsset, - bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset, - ); + type IsReserve = (bridging::to_westend::IsTrustedBridgedReserveLocationForConcreteAsset,); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -627,11 +601,7 @@ impl xcm_executor::Config for XcmConfig { XcmFeeToAccount, >; type MessageExporter = (); - type UniversalAliases = ( - bridging::to_wococo::UniversalAliases, - bridging::to_rococo::UniversalAliases, - bridging::to_westend::UniversalAliases, - ); + type UniversalAliases = (bridging::to_westend::UniversalAliases,); type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; @@ -656,15 +626,9 @@ type LocalXcmRouter = ( /// 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 Westend // GlobalConsensus ToWestendXcmRouter, - // Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo - // GlobalConsensus - ToRococoXcmRouter, )>; impl pallet_xcm::Config for Runtime { @@ -731,7 +695,7 @@ impl pallet_asset_conversion::BenchmarkHelper> for BenchmarkMultiLocationConverter where - SelfParaId: Get, + SelfParaId: frame_support::traits::Get, { fn asset_id(asset_id: u32) -> MultiLocation { MultiLocation { @@ -754,7 +718,7 @@ pub mod bridging { use assets_common::matching; use sp_std::collections::btree_set::BTreeSet; - // common/shared parameters for Wococo/Rococo + // common/shared parameters parameter_types! { /// Base price of every byte of the Rococo -> Westend message. Can be adjusted via /// governance `set_storage` call. @@ -775,10 +739,7 @@ pub mod bridging { /// governance `set_storage` call. pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); - 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 SiblingBridgeHubParaId: u32 = bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_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`) @@ -786,90 +747,12 @@ pub mod bridging { pub BridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() - .chain(to_wococo::BridgeTable::get()) .chain(to_westend::BridgeTable::get()) - .chain(to_rococo::BridgeTable::get()) .collect(); } pub type NetworkExportTable = xcm_builder::NetworkExportTable; - 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_ROCOCO_TO_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(), - XcmBridgeHubRouterBaseFee::get(), - ).into()) - ) - ]; - - /// 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) - } - } - - /// 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 - ), - >; - - 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_westend { use super::*; @@ -946,82 +829,6 @@ pub mod bridging { } } - 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_WOCOCO_TO_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(), - XcmBridgeHubRouterBaseFee::get(), - ).into()) - ) - ]; - - /// 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) - } - } - - /// 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 - ), - >; - - 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; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index b4f4e828dde..7bb71a77de7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -28,8 +28,8 @@ pub use asset_hub_rococo_runtime::{ }, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, RuntimeFlavor, SessionKeys, System, ToRococoXcmRouterInstance, - ToWestendXcmRouterInstance, ToWococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + RuntimeCall, RuntimeEvent, SessionKeys, System, ToWestendXcmRouterInstance, + TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, @@ -674,15 +674,6 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( mod asset_hub_rococo_tests { use super::*; - fn bridging_to_asset_hub_wococo() -> 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(), - } - } - fn bridging_to_asset_hub_westend() -> TestBridgingConfig { asset_test_utils::test_cases_over_bridge::TestBridgingConfig { bridged_network: bridging::to_westend::WestendNetwork::get(), @@ -692,13 +683,6 @@ mod asset_hub_rococo_tests { } } - #[test] - fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_wococo_works() { - limited_reserve_transfer_assets_for_native_asset_over_bridge_works( - bridging_to_asset_hub_wococo, - ) - } - #[test] fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_westend_works() { limited_reserve_transfer_assets_for_native_asset_over_bridge_works( @@ -706,31 +690,6 @@ mod asset_hub_rococo_tests { ) } - #[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_ROCOCO_TO_WOCOCO_MESSAGES_PALLET_INDEX)), - GlobalConsensus(Wococo), - X1(Parachain(1000)) - ) - ) - } - #[test] fn receive_reserve_asset_deposited_wnd_from_asset_hub_westend_works() { const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; @@ -756,58 +715,6 @@ mod asset_hub_rococo_tests { ) } - #[test] - fn report_bridge_status_from_xcm_bridge_router_for_wococo_works() { - asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - LocationToAccountId, - ToWococoXcmRouterInstance, - >( - collator_session_keys(), - bridging_to_asset_hub_wococo, - || { - 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 report_bridge_status_from_xcm_bridge_router_for_westend_works() { asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< @@ -863,22 +770,6 @@ mod asset_hub_rococo_tests { #[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() - ); assert_eq!( RuntimeCall::ToWestendXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { @@ -897,19 +788,6 @@ mod asset_hub_rococo_tests { ); } - #[test] - fn check_sane_weight_report_bridge_status_for_wococo() { - use pallet_xcm_bridge_hub_router::WeightInfo; - let actual = >::WeightInfo::report_bridge_status(); - let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); - assert!( - actual.all_lte(max_weight), - "max_weight: {:?} should be adjusted to actual {:?}", - max_weight, - actual - ); - } - #[test] fn check_sane_weight_report_bridge_status_for_westend() { use pallet_xcm_bridge_hub_router::WeightInfo; @@ -955,167 +833,6 @@ mod asset_hub_rococo_tests { } } -mod asset_hub_wococo_tests { - use super::*; - - fn bridging_to_asset_hub_rococo() -> TestBridgingConfig { - 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() -> TestBridgingConfig { - set_wococo_flavor(); - bridging_to_asset_hub_rococo() - } - - #[test] - fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_rococo_works() { - limited_reserve_transfer_assets_for_native_asset_over_bridge_works( - with_wococo_flavor_bridging_to_asset_hub_rococo, - ) - } - - #[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_WOCOCO_TO_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, - LocationToAccountId, - ToRococoXcmRouterInstance, - >( - collator_session_keys(), - with_wococo_flavor_bridging_to_asset_hub_rococo, - || { - 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 - ); - } -} - #[test] fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { asset_test_utils::test_cases::change_storage_constant_by_governance_works::< diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index b2a14a0405d..cf617db730d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -1,14 +1,5 @@ - [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 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 Rococo <-> Westend bridge](#how-to-test-local-rococo---westend-bridge) - [Run Rococo/Westend chains with zombienet](#run-rococowestend-chains-with-zombienet) - [Init bridge and run relayer between BridgeHubRococo and @@ -53,17 +44,7 @@ Copy the apropriate binary (zombienet-linux) from the latest release to ~/local_ --- # 2. Build polkadot binary -# 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 +We need polkadot binary with "fast-runtime" feature: cd cargo build --release --features fast-runtime --bin polkadot @@ -100,112 +81,6 @@ cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-paracha cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain-asset-hub ``` - -## How to test local Rococo <-> Wococo bridge - -### 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 ./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 ./cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml -``` - -### Init bridge and run relayer between BridgeHubRococo and BridgeHubWococo - -**Accounts of BridgeHub parachains:** -- `Bob` is pallet owner of all bridge pallets - -#### Run with script -``` -cd - -./cumulus/scripts/bridges_rococo_wococo.sh run-relay -``` - -**Check relay-chain headers relaying:** -- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: - **bridgeWococoGrandpa** - Keys: **bestFinalized()** -- Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: - **bridgeRococoGrandpa** - Keys: **bestFinalized()** - -**Check parachain headers relaying:** -- Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: - **bridgeWococoParachains** - Keys: **parasInfo(None)** -- Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: - **bridgeRococoParachains** - Keys: **parasInfo(None)** - -### Initialize configuration for transfer asset over bridge (ROCs/WOCs) - -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 - -# 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 Rococo <-> Westend bridge ### Run Rococo/Westend chains with zombienet 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 671d38e808f..c475768d5dd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -77,10 +77,8 @@ 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-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", 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-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", 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 } bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } @@ -89,7 +87,6 @@ bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-fea bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } bp-westend = { path = "../../../../../bridges/primitives/chain-westend", default-features = false } -bp-wococo = { path = "../../../../../bridges/primitives/chain-wococo", default-features = false } pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } @@ -107,10 +104,8 @@ default = [ "std" ] std = [ "bp-asset-hub-rococo/std", "bp-asset-hub-westend/std", - "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-westend/std", - "bp-bridge-hub-wococo/std", "bp-header-chain/std", "bp-messages/std", "bp-parachains/std", @@ -119,7 +114,6 @@ std = [ "bp-rococo/std", "bp-runtime/std", "bp-westend/std", - "bp-wococo/std", "bridge-runtime-common/std", "codec/std", "cumulus-pallet-aura-ext/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index 296ec88a856..8153e52beac 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -29,10 +29,6 @@ parameter_types! { pub const RelayChainHeadersToKeep: u32 = 1024; pub const ParachainHeadsToKeep: u32 = 64; - pub const RococoBridgeParachainPalletName: &'static str = "Paras"; - pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; - pub const WococoBridgeParachainPalletName: &'static str = "Paras"; - pub const MaxWococoParaHeadDataSize: u32 = bp_wococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; pub const WestendBridgeParachainPalletName: &'static str = "Paras"; pub const MaxWestendParaHeadDataSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; @@ -43,52 +39,6 @@ parameter_types! { pub storage DeliveryRewardInBalance: u64 = 1_000_000; } -/// Add GRANDPA bridge pallet to track Wococo relay chain. -pub type BridgeGrandpaWococoInstance = pallet_bridge_grandpa::Instance1; -impl pallet_bridge_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BridgedChain = bp_wococo::Wococo; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; - type HeadersToKeep = RelayChainHeadersToKeep; - type WeightInfo = weights::pallet_bridge_grandpa_wococo_finality::WeightInfo; -} - -/// 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; - type WeightInfo = weights::pallet_bridge_parachains_within_wococo::WeightInfo; - type BridgesGrandpaPalletInstance = BridgeGrandpaWococoInstance; - type ParasPalletName = WococoBridgeParachainPalletName; - type ParaStoredHeaderDataBuilder = - SingleParaStoredHeaderDataBuilder; - type HeadsToKeep = ParachainHeadsToKeep; - type MaxParaHeadDataSize = MaxWococoParaHeadDataSize; -} - -/// Add GRANDPA bridge pallet to track Rococo relay chain. -pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance2; -impl pallet_bridge_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BridgedChain = bp_rococo::Rococo; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; - type HeadersToKeep = RelayChainHeadersToKeep; - type WeightInfo = weights::pallet_bridge_grandpa_rococo_finality::WeightInfo; -} - -/// 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; - type WeightInfo = weights::pallet_bridge_parachains_within_rococo::WeightInfo; - type BridgesGrandpaPalletInstance = BridgeGrandpaRococoInstance; - type ParasPalletName = RococoBridgeParachainPalletName; - type ParaStoredHeaderDataBuilder = - SingleParaStoredHeaderDataBuilder; - type HeadsToKeep = ParachainHeadsToKeep; - type MaxParaHeadDataSize = MaxRococoParaHeadDataSize; -} - /// Add GRANDPA bridge pallet to track Westend relay chain. pub type BridgeGrandpaWestendInstance = pallet_bridge_grandpa::Instance3; impl pallet_bridge_grandpa::Config for Runtime { @@ -96,14 +46,14 @@ impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_westend::Westend; type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = RelayChainHeadersToKeep; - type WeightInfo = weights::pallet_bridge_grandpa_westend_finality::WeightInfo; + type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo; } /// Add parachain bridge pallet to track Westend BridgeHub parachain pub type BridgeParachainWestendInstance = pallet_bridge_parachains::Instance3; impl pallet_bridge_parachains::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_parachains_within_westend::WeightInfo; + type WeightInfo = weights::pallet_bridge_parachains::WeightInfo; type BridgesGrandpaPalletInstance = BridgeGrandpaWestendInstance; type ParasPalletName = WestendBridgeParachainPalletName; type ParaStoredHeaderDataBuilder = diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_rococo_config.rs deleted file mode 100644 index 35497c84068..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_rococo_config.rs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Bridge definitions used on BridgeHub with the Wococo flavor for bridging to BridgeHubRococo. - -use crate::{ - bridge_common_config::{BridgeParachainRococoInstance, DeliveryRewardInBalance}, - weights, AccountId, BridgeRococoMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, - XcmRouter, -}; -use bp_messages::LaneId; -use bridge_runtime_common::{ - messages, - messages::{ - source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, - MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, - }, - refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, RefundableParachain, - }, -}; -use codec::Encode; -use frame_support::{parameter_types, traits::PalletInfoAccess}; -use sp_runtime::RuntimeDebug; -use xcm::{ - latest::prelude::*, - prelude::{InteriorMultiLocation, NetworkId}, -}; -use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; - -parameter_types! { - pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; - pub BridgeHubWococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Wococo), Parachain(ParachainInfo::parachain_id().into())); - pub BridgeWococoToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); - pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; - pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO]; - pub const AssetHubWococoToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO; - // 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 AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - - pub FromAssetHubWococoToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen(X1(Parachain(AssetHubWococoParaId::get().into()))).into(), - XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, - ); - - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); -} -pub const XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 1]); - -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 RococoBridge Hub -> Wococo BridgeHub messages. -pub type ToRococoBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; - -/// Dispatches received XCM messages from other bridge -type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher< - XcmRouter, - BridgeHubWococoUniversalLocation, - BridgeWococoToRococoMessagesPalletInstance, ->; - -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubRococoHaulBlobExporter = HaulBlobExporter< - XcmBlobHaulerAdapter, - RococoGlobalConsensusNetwork, - (), ->; -pub struct ToBridgeHubRococoXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubRococoMessagesInstance; - type SenderAndLane = FromAssetHubWococoToAssetHubRococoRoute; - - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDelivered = XcmBlobHaulerAdapter; - -/// Messaging Bridge configuration for BridgeHubWococo -> BridgeHubRococo -pub struct WithBridgeHubRococoMessageBridge; -impl MessageBridge for WithBridgeHubRococoMessageBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME; - type ThisChain = BridgeHubWococo; - type BridgedChain = BridgeHubRococo; - type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< - Runtime, - BridgeParachainRococoInstance, - bp_bridge_hub_rococo::BridgeHubRococo, - >; -} - -/// Message verifier for BridgeHubRococo messages sent from BridgeHubWococo -pub type ToBridgeHubRococoMessageVerifier = - messages::source::FromThisChainMessageVerifier; - -/// Maximal outbound payload size of BridgeHubWococo -> BridgeHubRococo messages. -pub type ToBridgeHubRococoMaximalOutboundPayloadSize = - messages::source::FromThisChainMaximalOutboundPayloadSize; - -/// BridgeHubRococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubRococo; - -impl UnderlyingChainProvider for BridgeHubRococo { - type Chain = bp_bridge_hub_rococo::BridgeHubRococo; -} - -impl messages::BridgedChainWithMessages for BridgeHubRococo {} - -/// BridgeHubWococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubWococo; - -impl UnderlyingChainProvider for BridgeHubWococo { - type Chain = bp_bridge_hub_wococo::BridgeHubWococo; -} - -impl ThisChainWithMessages for BridgeHubWococo { - type RuntimeOrigin = RuntimeOrigin; -} - -/// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWococoRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< - RefundBridgedParachainMessages< - Runtime, - RefundableParachain, - RefundableMessagesLane< - WithBridgeHubRococoMessagesInstance, - AssetHubWococoToAssetHubRococoMessagesLane, - >, - ActualFeeRefund, - PriorityBoostPerMessage, - StrOnBridgeHubWococoRefundBridgeHubRococoMessages, - >, ->; -bp_runtime::generate_static_str_provider!(OnBridgeHubWococoRefundBridgeHubRococoMessages); - -/// Add XCM messages support for BridgeHubWococo to support Wococo->Rococo XCM messages -pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance2; -impl pallet_bridge_messages::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_messages_wococo_to_rococo::WeightInfo; - type BridgedChainId = BridgeHubRococoChainId; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - - type MaximalOutboundPayloadSize = ToBridgeHubRococoMaximalOutboundPayloadSize; - type OutboundPayload = XcmAsPlainPayload; - - type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; - type DeliveryPayments = (); - - type TargetHeaderChain = TargetHeaderChainAdapter; - type LaneMessageVerifier = ToBridgeHubRococoMessageVerifier; - type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< - Runtime, - WithBridgeHubRococoMessagesInstance, - DeliveryRewardInBalance, - >; - - type SourceHeaderChain = SourceHeaderChainAdapter; - type MessageDispatch = XcmBlobMessageDispatch< - FromRococoMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubWococoParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDelivered; -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::bridge_common_config::BridgeGrandpaRococoInstance; - use bridge_runtime_common::{ - assert_complete_bridge_types, - integrity::{ - assert_complete_bridge_constants, check_message_lane_weights, - AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, - 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() { - check_message_lane_weights::< - bp_bridge_hub_wococo::BridgeHubWococo, - Runtime, - WithBridgeHubRococoMessagesInstance, - >( - bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE, - bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - true, - ); - } - - #[test] - fn ensure_bridge_integrity() { - assert_complete_bridge_types!( - runtime: Runtime, - with_bridged_chain_grandpa_instance: BridgeGrandpaRococoInstance, - with_bridged_chain_messages_instance: WithBridgeHubRococoMessagesInstance, - bridge: WithBridgeHubRococoMessageBridge, - this_chain: bp_wococo::Wococo, - bridged_chain: bp_rococo::Rococo, - ); - - assert_complete_bridge_constants::< - Runtime, - BridgeGrandpaRococoInstance, - WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, - >(AssertCompleteBridgeConstants { - this_chain_constants: AssertChainConstants { - block_length: bp_bridge_hub_wococo::BlockLength::get(), - block_weights: bp_bridge_hub_wococo::BlockWeights::get(), - }, - messages_pallet_constants: AssertBridgeMessagesPalletConstants { - max_unrewarded_relayers_in_bridged_confirmation_tx: - bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - max_unconfirmed_messages_in_bridged_confirmation_tx: - bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - bridged_chain_id: bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID, - }, - pallet_names: AssertBridgePalletNames { - with_this_chain_messages_pallet_name: - bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, - with_bridged_chain_grandpa_pallet_name: bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME, - with_bridged_chain_messages_pallet_name: - 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!( - BridgeWococoToRococoMessagesPalletInstance::get(), - X1(PalletInstance( - bp_bridge_hub_wococo::WITH_BRIDGE_WOCOCO_TO_ROCOCO_MESSAGES_PALLET_INDEX - )) - ); - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 36dcab09dea..f3c1c9597b5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -196,7 +196,7 @@ bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWesten pub type WithBridgeHubWestendMessagesInstance = pallet_bridge_messages::Instance3; impl pallet_bridge_messages::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_messages_rococo_to_westend::WeightInfo; + type WeightInfo = weights::pallet_bridge_messages::WeightInfo; type BridgedChainId = BridgeHubWestendChainId; type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWestend; type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_wococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_wococo_config.rs deleted file mode 100644 index 7780b02632c..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_wococo_config.rs +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Bridge definitions used on BridgeHub with the Rococo flavor for bridging to BridgeHubWococo. - -use crate::{ - bridge_common_config::{BridgeParachainWococoInstance, DeliveryRewardInBalance}, - weights, AccountId, BridgeWococoMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, - XcmRouter, -}; -use bp_messages::LaneId; -use bridge_runtime_common::{ - messages, - messages::{ - source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, - MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, - }, - refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, RefundableParachain, - }, -}; - -use codec::Encode; -use frame_support::{parameter_types, traits::PalletInfoAccess}; -use sp_runtime::RuntimeDebug; -use xcm::{ - latest::prelude::*, - prelude::{InteriorMultiLocation, NetworkId}, -}; -use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; - -parameter_types! { - pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - pub const BridgeHubWococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; - pub BridgeRococoToWococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); - pub BridgeHubRococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(ParachainInfo::parachain_id().into())); - pub WococoGlobalConsensusNetwork: NetworkId = NetworkId::Wococo; - pub ActiveOutboundLanesToBridgeHubWococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO]; - pub const AssetHubRococoToAssetHubWococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO; - // 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 AssetHubWococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_wococo::ASSET_HUB_WOCOCO_PARACHAIN_ID.into(); - - pub FromAssetHubRococoToAssetHubWococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen(X1(Parachain(AssetHubRococoParaId::get().into()))).into(), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, - ); - - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); -} -pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO: LaneId = LaneId([0, 0, 0, 1]); - -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. -pub type FromWococoBridgeHubMessagesProof = - FromBridgedChainMessagesProof; -/// Messages delivery proof for Rococo Bridge Hub -> Wococo Bridge Hub messages. -pub type ToWococoBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; - -/// Dispatches received XCM messages from other bridge -type FromWococoMessageBlobDispatcher = BridgeBlobDispatcher< - XcmRouter, - BridgeHubRococoUniversalLocation, - BridgeRococoToWococoMessagesPalletInstance, ->; - -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubWococoHaulBlobExporter = HaulBlobExporter< - XcmBlobHaulerAdapter, - WococoGlobalConsensusNetwork, - (), ->; -pub struct ToBridgeHubWococoXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubWococoXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubWococoMessagesInstance; - type SenderAndLane = FromAssetHubRococoToAssetHubWococoRoute; - - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDeliveredFromWococo = XcmBlobHaulerAdapter; - -/// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWococo -pub struct WithBridgeHubWococoMessageBridge; -impl MessageBridge for WithBridgeHubWococoMessageBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; - type ThisChain = BridgeHubRococo; - type BridgedChain = BridgeHubWococo; - type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< - Runtime, - BridgeParachainWococoInstance, - bp_bridge_hub_wococo::BridgeHubWococo, - >; -} - -/// Message verifier for BridgeHubWococo messages sent from BridgeHubRococo -pub type ToBridgeHubWococoMessageVerifier = - messages::source::FromThisChainMessageVerifier; - -/// Maximal outbound payload size of BridgeHubRococo -> BridgeHubWococo messages. -pub type ToBridgeHubWococoMaximalOutboundPayloadSize = - messages::source::FromThisChainMaximalOutboundPayloadSize; - -/// BridgeHubWococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubWococo; - -impl UnderlyingChainProvider for BridgeHubWococo { - type Chain = bp_bridge_hub_wococo::BridgeHubWococo; -} - -impl messages::BridgedChainWithMessages for BridgeHubWococo {} - -/// BridgeHubRococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubRococo; - -impl UnderlyingChainProvider for BridgeHubRococo { - type Chain = bp_bridge_hub_rococo::BridgeHubRococo; -} - -impl ThisChainWithMessages for BridgeHubRococo { - type RuntimeOrigin = RuntimeOrigin; -} - -/// Signed extension that refunds relayers that are delivering messages from the Wococo parachain. -pub type OnBridgeHubRococoRefundBridgeHubWococoMessages = RefundSignedExtensionAdapter< - RefundBridgedParachainMessages< - Runtime, - RefundableParachain, - RefundableMessagesLane< - WithBridgeHubWococoMessagesInstance, - AssetHubRococoToAssetHubWococoMessagesLane, - >, - ActualFeeRefund, - PriorityBoostPerMessage, - StrOnBridgeHubRococoRefundBridgeHubWococoMessages, - >, ->; -bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWococoMessages); - -/// Add XCM messages support for BridgeHubRococo to support Rococo->Wococo XCM messages -pub type WithBridgeHubWococoMessagesInstance = pallet_bridge_messages::Instance1; -impl pallet_bridge_messages::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_bridge_messages_rococo_to_wococo::WeightInfo; - type BridgedChainId = BridgeHubWococoChainId; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWococo; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - - type MaximalOutboundPayloadSize = ToBridgeHubWococoMaximalOutboundPayloadSize; - type OutboundPayload = XcmAsPlainPayload; - - type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; - type DeliveryPayments = (); - - type TargetHeaderChain = TargetHeaderChainAdapter; - type LaneMessageVerifier = ToBridgeHubWococoMessageVerifier; - type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< - Runtime, - WithBridgeHubWococoMessagesInstance, - DeliveryRewardInBalance, - >; - - type SourceHeaderChain = SourceHeaderChainAdapter; - type MessageDispatch = XcmBlobMessageDispatch< - FromWococoMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubRococoParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDeliveredFromWococo; -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::bridge_common_config::BridgeGrandpaWococoInstance; - use bridge_runtime_common::{ - assert_complete_bridge_types, - integrity::{ - assert_complete_bridge_constants, check_message_lane_weights, - AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, - 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() { - check_message_lane_weights::< - bp_bridge_hub_rococo::BridgeHubRococo, - Runtime, - WithBridgeHubWococoMessagesInstance, - >( - bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE, - bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - true, - ); - } - - #[test] - fn ensure_bridge_integrity() { - assert_complete_bridge_types!( - runtime: Runtime, - with_bridged_chain_grandpa_instance: BridgeGrandpaWococoInstance, - with_bridged_chain_messages_instance: WithBridgeHubWococoMessagesInstance, - bridge: WithBridgeHubWococoMessageBridge, - this_chain: bp_rococo::Rococo, - bridged_chain: bp_wococo::Wococo, - ); - - assert_complete_bridge_constants::< - Runtime, - BridgeGrandpaWococoInstance, - WithBridgeHubWococoMessagesInstance, - WithBridgeHubWococoMessageBridge, - >(AssertCompleteBridgeConstants { - this_chain_constants: AssertChainConstants { - block_length: bp_bridge_hub_rococo::BlockLength::get(), - block_weights: bp_bridge_hub_rococo::BlockWeights::get(), - }, - messages_pallet_constants: AssertBridgeMessagesPalletConstants { - max_unrewarded_relayers_in_bridged_confirmation_tx: - bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - max_unconfirmed_messages_in_bridged_confirmation_tx: - bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - bridged_chain_id: bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID, - }, - pallet_names: AssertBridgePalletNames { - with_this_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, - with_bridged_chain_grandpa_pallet_name: bp_wococo::WITH_WOCOCO_GRANDPA_PALLET_NAME, - with_bridged_chain_messages_pallet_name: - 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!( - BridgeRococoToWococoMessagesPalletInstance::get(), - X1(PalletInstance( - bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WOCOCO_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 b17d308b891..b8fc2fffc88 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 @@ -16,14 +16,7 @@ //! # Bridge Hub Rococo Runtime //! -//! This runtime is also used for Bridge Hub Wococo. 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`. -//! //! This runtime currently supports bridging between: -//! - Rococo <> Wococo //! - Rococo <> Westend #![cfg_attr(not(feature = "std"), no_std)] @@ -35,13 +28,10 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod bridge_common_config; -pub mod bridge_to_rococo_config; pub mod bridge_to_westend_config; -pub mod bridge_to_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}; @@ -93,15 +83,6 @@ use parachains_common::{ HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; -/// 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; @@ -125,11 +106,7 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages, - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, - bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages, - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages,), ); /// Unchecked extrinsic type as expected by this runtime. @@ -529,37 +506,19 @@ construct_runtime!( Utility: pallet_utility::{Pallet, Call, Event} = 40, Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, - // Rococo, Wococo and Westend BridgeHubs are sharing the runtime, so this runtime has several sets of - // bridge pallets. - // // BridgeHubRococo uses: - // - BridgeWococoGrandpa // - BridgeWestendGrandpa - // - BridgeWococoParachains // - BridgeWestendParachains - // - BridgeWococoMessages // - BridgeWestendMessages // - BridgeRelayers - // - // BridgeHubWococo uses: - // - BridgeRococoGrandpa - // - BridgeRococoParachains - // - BridgeRococoMessages - // - BridgeRelayers // GRANDPA bridge modules. - BridgeWococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 41, - BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 43, BridgeWestendGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 48, // Parachain bridge modules. - BridgeWococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 42, - BridgeRococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 44, BridgeWestendParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 49, // Messaging bridge modules. - BridgeWococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 46, - BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 45, BridgeWestendMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 51, BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 47, @@ -573,11 +532,11 @@ construct_runtime!( bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { RuntimeCall, AccountId, // Grandpa - BridgeRococoGrandpa, BridgeWococoGrandpa, BridgeWestendGrandpa, + BridgeWestendGrandpa, // Parachains - BridgeRococoParachains, BridgeWococoParachains, BridgeWestendParachains, + BridgeWestendParachains, // Messages - BridgeRococoMessages, BridgeWococoMessages, BridgeWestendMessages + BridgeWestendMessages } #[cfg(feature = "runtime-benchmarks")] @@ -600,15 +559,9 @@ mod benches { [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] // Bridge pallets - [pallet_bridge_grandpa, WococoFinality] [pallet_bridge_grandpa, WestendFinality] - [pallet_bridge_grandpa, RococoFinality] - [pallet_bridge_parachains, WithinWococo] [pallet_bridge_parachains, WithinWestend] - [pallet_bridge_parachains, WithinRococo] - [pallet_bridge_messages, RococoToWococo] [pallet_bridge_messages, RococoToWestend] - [pallet_bridge_messages, WococoToRococo] [pallet_bridge_relayers, BridgeRelayersBench::] ); } @@ -757,26 +710,6 @@ impl_runtime_apis! { } } - impl bp_rococo::RococoFinalityApi for Runtime { - fn best_finalized() -> Option> { - BridgeRococoGrandpa::best_finalized() - } - fn synced_headers_grandpa_info( - ) -> Vec> { - BridgeRococoGrandpa::synced_headers_grandpa_info() - } - } - - impl bp_wococo::WococoFinalityApi for Runtime { - fn best_finalized() -> Option> { - BridgeWococoGrandpa::best_finalized() - } - fn synced_headers_grandpa_info( - ) -> Vec> { - BridgeWococoGrandpa::synced_headers_grandpa_info() - } - } - impl bp_westend::WestendFinalityApi for Runtime { fn best_finalized() -> Option> { BridgeWestendGrandpa::best_finalized() @@ -787,22 +720,6 @@ impl_runtime_apis! { } } - impl bp_bridge_hub_rococo::BridgeHubRococoFinalityApi for Runtime { - fn best_finalized() -> Option> { - BridgeRococoParachains::best_parachain_head_id::< - bp_bridge_hub_rococo::BridgeHubRococo - >().unwrap_or(None) - } - } - - impl bp_bridge_hub_wococo::BridgeHubWococoFinalityApi for Runtime { - fn best_finalized() -> Option> { - BridgeWococoParachains::best_parachain_head_id::< - bp_bridge_hub_wococo::BridgeHubWococo - >().unwrap_or(None) - } - } - impl bp_bridge_hub_westend::BridgeHubWestendFinalityApi for Runtime { fn best_finalized() -> Option> { BridgeWestendParachains::best_parachain_head_id::< @@ -811,33 +728,6 @@ impl_runtime_apis! { } } - // This is exposed by BridgeHubRococo - impl bp_bridge_hub_wococo::FromBridgeHubWococoInboundLaneApi for Runtime { - fn message_details( - lane: bp_messages::LaneId, - messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, - ) -> Vec { - bridge_runtime_common::messages_api::inbound_message_details::< - Runtime, - bridge_to_wococo_config::WithBridgeHubWococoMessagesInstance, - >(lane, messages) - } - } - - // This is exposed by BridgeHubRococo - impl bp_bridge_hub_wococo::ToBridgeHubWococoOutboundLaneApi for Runtime { - fn message_details( - lane: bp_messages::LaneId, - begin: bp_messages::MessageNonce, - end: bp_messages::MessageNonce, - ) -> Vec { - bridge_runtime_common::messages_api::outbound_message_details::< - Runtime, - bridge_to_wococo_config::WithBridgeHubWococoMessagesInstance, - >(lane, begin, end) - } - } - // This is exposed by BridgeHubRococo impl bp_bridge_hub_westend::FromBridgeHubWestendInboundLaneApi for Runtime { fn message_details( @@ -865,45 +755,6 @@ impl_runtime_apis! { } } - // This is exposed by BridgeHubWococo - impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { - fn message_details( - lane: bp_messages::LaneId, - messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, - ) -> Vec { - // use different instance according to flavor - match xcm_config::Flavor::get() { - RuntimeFlavor::Wococo => { - bridge_runtime_common::messages_api::inbound_message_details::< - Runtime, - bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >(lane, messages) - }, - flavor @ _ => unimplemented!("Unsupported `FromBridgeHubRococoInboundLaneApi` for flavor: {:?}", flavor) - } - } - } - - // This is exposed by BridgeHubWococo and BridgeHubWestend - impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { - fn message_details( - lane: bp_messages::LaneId, - begin: bp_messages::MessageNonce, - end: bp_messages::MessageNonce, - ) -> Vec { - // use different instance according to flavor - match xcm_config::Flavor::get() { - RuntimeFlavor::Wococo => { - bridge_runtime_common::messages_api::outbound_message_details::< - Runtime, - bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >(lane, begin, end) - }, - flavor @ _ => unimplemented!("Unsupported `ToBridgeHubRococoOutboundLaneApi` for flavor: {:?}", flavor) - } - } - } - #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -943,15 +794,9 @@ impl_runtime_apis! { use pallet_bridge_relayers::benchmarking::Pallet as BridgeRelayersBench; // Change weight file names. - type WococoFinality = BridgeWococoGrandpa; type WestendFinality = BridgeWestendGrandpa; - type RococoFinality = BridgeRococoGrandpa; - type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; - type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; - type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; - type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1098,7 +943,7 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - Ok((TokenLocation::get(), NetworkId::Wococo, X1(Parachain(100)))) + Ok((TokenLocation::get(), NetworkId::Westend, X1(Parachain(100)))) } fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { @@ -1109,15 +954,9 @@ impl_runtime_apis! { type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; - type WococoFinality = BridgeWococoGrandpa; type WestendFinality = BridgeWestendGrandpa; - type RococoFinality = BridgeRococoGrandpa; - type WithinWococo = pallet_bridge_parachains::benchmarking::Pallet::; type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; - type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; - type RococoToWococo = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; - type WococoToRococo = pallet_bridge_messages::benchmarking::Pallet ::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_parachain, @@ -1130,49 +969,6 @@ impl_runtime_apis! { MessageProofParams, }; - impl BridgeMessagesConfig for Runtime { - fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; - pallet_bridge_relayers::Pallet::::relayer_reward( - relayer, - bp_relayers::RewardsAccountParams::new( - bench_lane_id, - bridged_chain_id, - bp_relayers::RewardsAccountOwner::BridgedChain - ) - ).is_some() - } - - fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_wococo_config::FromWococoBridgeHubMessagesProof, Weight) { - use cumulus_primitives_core::XcmpMessageSource; - assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - prepare_message_proof_from_parachain::< - Runtime, - bridge_common_config::BridgeGrandpaWococoInstance, - bridge_to_wococo_config::WithBridgeHubWococoMessageBridge, - >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Rococo), Parachain(42)))) - } - - fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_wococo_config::ToWococoBridgeHubMessagesDeliveryProof { - prepare_message_delivery_proof_from_parachain::< - Runtime, - bridge_common_config::BridgeGrandpaWococoInstance, - bridge_to_wococo_config::WithBridgeHubWococoMessageBridge, - >(params) - } - - fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool { - use cumulus_primitives_core::XcmpMessageSource; - !XcmpQueue::take_outbound_messages(usize::MAX).is_empty() - } - } - impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); @@ -1216,49 +1012,6 @@ impl_runtime_apis! { } } - impl BridgeMessagesConfig for Runtime { - fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; - pallet_bridge_relayers::Pallet::::relayer_reward( - relayer, - bp_relayers::RewardsAccountParams::new( - bench_lane_id, - bridged_chain_id, - bp_relayers::RewardsAccountOwner::BridgedChain - ) - ).is_some() - } - - fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { - use cumulus_primitives_core::XcmpMessageSource; - assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - prepare_message_proof_from_parachain::< - Runtime, - bridge_common_config::BridgeGrandpaRococoInstance, - bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, - >(params, generate_xcm_builder_bridge_message_sample(X2(GlobalConsensus(Wococo), Parachain(42)))) - } - - fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { - prepare_message_delivery_proof_from_parachain::< - Runtime, - bridge_common_config::BridgeGrandpaRococoInstance, - bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, - >(params) - } - - fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool { - use cumulus_primitives_core::XcmpMessageSource; - !XcmpQueue::take_outbound_messages(usize::MAX).is_empty() - } - } - use bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof; use pallet_bridge_parachains::benchmarking::Config as BridgeParachainsConfig; use pallet_bridge_relayers::benchmarking::{ @@ -1266,30 +1019,6 @@ impl_runtime_apis! { Config as BridgeRelayersConfig, }; - impl BridgeParachainsConfig for Runtime { - fn parachains() -> Vec { - use bp_runtime::Parachain; - vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_wococo::BridgeHubWococo::PARACHAIN_ID)] - } - - fn prepare_parachain_heads_proof( - parachains: &[bp_polkadot_core::parachains::ParaId], - parachain_head_size: u32, - proof_size: bp_runtime::StorageProofSize, - ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, - bp_polkadot_core::parachains::ParaHeadsProof, - Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, - ) { - prepare_parachain_heads_proof::( - parachains, - parachain_head_size, - proof_size, - ) - } - } - impl BridgeParachainsConfig for Runtime { fn parachains() -> Vec { use bp_runtime::Parachain; @@ -1314,30 +1043,6 @@ impl_runtime_apis! { } } - impl BridgeParachainsConfig for Runtime { - fn parachains() -> Vec { - use bp_runtime::Parachain; - vec![bp_polkadot_core::parachains::ParaId(bp_bridge_hub_rococo::BridgeHubRococo::PARACHAIN_ID)] - } - - fn prepare_parachain_heads_proof( - parachains: &[bp_polkadot_core::parachains::ParaId], - parachain_head_size: u32, - proof_size: bp_runtime::StorageProofSize, - ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, - bp_polkadot_core::parachains::ParaHeadsProof, - Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, - ) { - prepare_parachain_heads_proof::( - parachains, - parachain_head_size, - proof_size, - ) - } - } - impl BridgeRelayersConfig for Runtime { fn prepare_rewards_account( account_params: bp_relayers::RewardsAccountParams, @@ -1418,11 +1123,7 @@ mod tests { frame_system::CheckWeight::new(), pallet_transaction_payment::ChargeTransactionPayment::from(10), BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages::default(), - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages::default(), - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),) ); // for BridgeHubRococo @@ -1442,24 +1143,6 @@ mod tests { bhr_indirect_payload.additional_signed().unwrap().encode() ) } - - // for BridgeHubWococo - { - let bhw_indirect_payload = bp_bridge_hub_wococo::SignedExtension::from_params( - VERSION.spec_version, - VERSION.transaction_version, - bp_runtime::TransactionEra::Immortal, - System::block_hash(BlockNumber::zero()), - 10, - 10, - (((), ()), ((), ())), - ); - assert_eq!(payload.encode(), bhw_indirect_payload.encode()); - assert_eq!( - payload.additional_signed().unwrap().encode(), - bhw_indirect_payload.additional_signed().unwrap().encode() - ) - } }); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 66f8f1edf3c..a615f539547 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -17,6 +17,9 @@ //! Expose the auto generated weight files. +use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; +use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; + pub mod block_weights; pub mod cumulus_pallet_dmp_queue; pub mod cumulus_pallet_parachain_system; @@ -24,15 +27,9 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_balances; -pub mod pallet_bridge_grandpa_rococo_finality; -pub mod pallet_bridge_grandpa_westend_finality; -pub mod pallet_bridge_grandpa_wococo_finality; -pub mod pallet_bridge_messages_rococo_to_westend; -pub mod pallet_bridge_messages_rococo_to_wococo; -pub mod pallet_bridge_messages_wococo_to_rococo; -pub mod pallet_bridge_parachains_within_rococo; -pub mod pallet_bridge_parachains_within_westend; -pub mod pallet_bridge_parachains_within_wococo; +pub mod pallet_bridge_grandpa; +pub mod pallet_bridge_messages; +pub mod pallet_bridge_parachains; pub mod pallet_bridge_relayers; pub mod pallet_collator_selection; pub mod pallet_message_queue; @@ -56,43 +53,7 @@ use frame_support::weights::Weight; // import trait from dependency module use ::pallet_bridge_relayers::WeightInfoExt as _; -impl pallet_bridge_messages::WeightInfoExt - for pallet_bridge_messages_wococo_to_rococo::WeightInfo -{ - fn expected_extra_storage_proof_size() -> u32 { - bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE - } - - fn receive_messages_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( - ) - } - - fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_delivery_proof_overhead_from_runtime() - } -} - -impl pallet_bridge_messages::WeightInfoExt - for pallet_bridge_messages_rococo_to_wococo::WeightInfo -{ - fn expected_extra_storage_proof_size() -> u32 { - bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE - } - - fn receive_messages_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_proof_overhead_from_runtime( - ) - } - - fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { - pallet_bridge_relayers::WeightInfo::::receive_messages_delivery_proof_overhead_from_runtime() - } -} - -impl pallet_bridge_messages::WeightInfoExt - for pallet_bridge_messages_rococo_to_westend::WeightInfo -{ +impl MessagesWeightInfoExt for pallet_bridge_messages::WeightInfo { fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE } @@ -107,26 +68,8 @@ impl pallet_bridge_messages::WeightInfoExt } } -impl pallet_bridge_parachains::WeightInfoExt - for pallet_bridge_parachains_within_rococo::WeightInfo -{ - fn expected_extra_storage_proof_size() -> u32 { - bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE - } -} - -impl pallet_bridge_parachains::WeightInfoExt - for pallet_bridge_parachains_within_westend::WeightInfo -{ +impl ParachainsWeightInfoExt for pallet_bridge_parachains::WeightInfo { fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE } } - -impl pallet_bridge_parachains::WeightInfoExt - for pallet_bridge_parachains_within_wococo::WeightInfo -{ - fn expected_extra_storage_proof_size() -> u32 { - bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index 8ef05f17856..aaa6a3e0622 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -1,40 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-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: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_grandpa -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_grandpa +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,33 +48,31 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_grandpa`. pub struct WeightInfo(PhantomData); impl pallet_bridge_grandpa::WeightInfo for WeightInfo { - /// Storage: BridgeRococoGrandpa PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa BestFinalized (r:1 w:1) - /// Proof: BridgeRococoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa CurrentAuthoritySet (r:1 w:0) - /// Proof: BridgeRococoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(50250), added: 50745, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHashesPointer (r:1 w:1) - /// Proof: BridgeRococoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHashes (r:1 w:1) - /// Proof: BridgeRococoGrandpa ImportedHashes (max_values: Some(1024), max_size: Some(36), added: 1521, mode: MaxEncodedLen) - /// Storage: BridgeRococoGrandpa ImportedHeaders (r:0 w:2) - /// Proof: BridgeRococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. + /// Storage: `BridgeWestendGrandpa::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::BestFinalized` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::CurrentAuthoritySet` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHashesPointer` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHashes` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:0 w:2) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 838]`. /// The range of component `v` is `[50, 100]`. fn submit_finality_proof(p: u32, v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (60 ±0)` + // Measured: `335 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 241_332_000 picoseconds. - Weight::from_parts(69_790_821, 0) + // Minimum execution time: 311_267_000 picoseconds. + Weight::from_parts(313_903_000, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 6_013 - .saturating_add(Weight::from_parts(47_580_554, 0).saturating_mul(p.into())) - // Standard Error: 100_298 - .saturating_add(Weight::from_parts(1_213_475, 0).saturating_mul(v.into())) + // Standard Error: 4_779 + .saturating_add(Weight::from_parts(55_265_953, 0).saturating_mul(p.into())) + // Standard Error: 36_883 + .saturating_add(Weight::from_parts(153_660, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs deleted file mode 100644 index 0bb798bd9ec..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_rococo_finality.rs +++ /dev/null @@ -1,82 +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. - -//! Autogenerated weights for `pallet_bridge_grandpa` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_grandpa -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_grandpa`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_grandpa::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoGrandpa::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::BestFinalized` (r:1 w:1) - /// Proof: `BridgeRococoGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::CurrentAuthoritySet` (r:1 w:0) - /// Proof: `BridgeRococoGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHashesPointer` (r:1 w:1) - /// Proof: `BridgeRococoGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHashes` (r:1 w:1) - /// Proof: `BridgeRococoGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:0 w:2) - /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - fn submit_finality_proof(p: u32, v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `268 + p * (60 ±0)` - // Estimated: `51735` - // Minimum execution time: 304_726_000 picoseconds. - Weight::from_parts(16_868_060, 0) - .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 2_802 - .saturating_add(Weight::from_parts(55_200_017, 0).saturating_mul(p.into())) - // Standard Error: 46_745 - .saturating_add(Weight::from_parts(2_689_151, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs deleted file mode 100644 index 4ed140b7d17..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_westend_finality.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_grandpa` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_grandpa -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_grandpa`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_grandpa::WeightInfo for WeightInfo { - /// Storage: `BridgeWestendGrandpa::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::BestFinalized` (r:1 w:1) - /// Proof: `BridgeWestendGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::CurrentAuthoritySet` (r:1 w:0) - /// Proof: `BridgeWestendGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHashesPointer` (r:1 w:1) - /// Proof: `BridgeWestendGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHashes` (r:1 w:1) - /// Proof: `BridgeWestendGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:0 w:2) - /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - fn submit_finality_proof(p: u32, v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `335 + p * (60 ±0)` - // Estimated: `51735` - // Minimum execution time: 305_905_000 picoseconds. - Weight::from_parts(2_636_863, 0) - .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 2_724 - .saturating_add(Weight::from_parts(55_199_477, 0).saturating_mul(p.into())) - // Standard Error: 45_444 - .saturating_add(Weight::from_parts(2_835_596, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs deleted file mode 100644 index a82854e0c67..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa_wococo_finality.rs +++ /dev/null @@ -1,82 +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. - -//! Autogenerated weights for `pallet_bridge_grandpa` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_grandpa -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_grandpa`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_grandpa::WeightInfo for WeightInfo { - /// Storage: `BridgeWococoGrandpa::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoGrandpa::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::BestFinalized` (r:1 w:1) - /// Proof: `BridgeWococoGrandpa::BestFinalized` (`max_values`: Some(1), `max_size`: Some(36), added: 531, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::CurrentAuthoritySet` (r:1 w:0) - /// Proof: `BridgeWococoGrandpa::CurrentAuthoritySet` (`max_values`: Some(1), `max_size`: Some(50250), added: 50745, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHashesPointer` (r:1 w:1) - /// Proof: `BridgeWococoGrandpa::ImportedHashesPointer` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHashes` (r:1 w:1) - /// Proof: `BridgeWococoGrandpa::ImportedHashes` (`max_values`: Some(1024), `max_size`: Some(36), added: 1521, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHeaders` (r:0 w:2) - /// Proof: `BridgeWococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - /// The range of component `p` is `[1, 838]`. - /// The range of component `v` is `[50, 100]`. - fn submit_finality_proof(p: u32, v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `302 + p * (60 ±0)` - // Estimated: `51735` - // Minimum execution time: 305_146_000 picoseconds. - Weight::from_parts(308_711_000, 0) - .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 2_651 - .saturating_add(Weight::from_parts(55_082_480, 0).saturating_mul(p.into())) - // Standard Error: 20_462 - .saturating_add(Weight::from_parts(298_367, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs index 319a4de8e96..17a45df5bfb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs @@ -1,40 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-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: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_messages -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_messages +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,184 +48,195 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_messages`. pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `538` // Estimated: `52645` - // Minimum execution time: 43_187_000 picoseconds. - Weight::from_parts(43_681_000, 0) + // Minimum execution time: 41_577_000 picoseconds. + Weight::from_parts(42_621_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `538` // Estimated: `52645` - // Minimum execution time: 54_131_000 picoseconds. - Weight::from_parts(54_813_000, 0) + // Minimum execution time: 52_880_000 picoseconds. + Weight::from_parts(53_697_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `538` // Estimated: `52645` - // Minimum execution time: 48_120_000 picoseconds. - Weight::from_parts(48_733_000, 0) + // Minimum execution time: 47_424_000 picoseconds. + Weight::from_parts(48_445_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `506` // Estimated: `52645` - // Minimum execution time: 41_028_000 picoseconds. - Weight::from_parts(41_635_000, 0) + // Minimum execution time: 40_619_000 picoseconds. + Weight::from_parts(42_262_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, mode: MaxEncodedLen) + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `506` // Estimated: `52645` - // Minimum execution time: 68_499_000 picoseconds. - Weight::from_parts(69_263_000, 0) + // Minimum execution time: 74_603_000 picoseconds. + Weight::from_parts(78_209_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 32_277_000 picoseconds. - Weight::from_parts(32_880_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) + // Measured: `377` + // Estimated: `3842` + // Minimum execution time: 33_762_000 picoseconds. + Weight::from_parts(34_405_000, 0) + .saturating_add(Weight::from_parts(0, 3842)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `3804` - // Minimum execution time: 32_504_000 picoseconds. - Weight::from_parts(33_085_000, 0) - .saturating_add(Weight::from_parts(0, 3804)) + // Measured: `377` + // Estimated: `3842` + // Minimum execution time: 33_805_000 picoseconds. + Weight::from_parts(35_051_000, 0) + .saturating_add(Weight::from_parts(0, 3842)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages OutboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: 539, mode: MaxEncodedLen) - /// Storage: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof Skipped: unknown `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) + /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `339` + // Measured: `377` // Estimated: `6086` - // Minimum execution time: 34_963_000 picoseconds. - Weight::from_parts(35_473_000, 0) + // Minimum execution time: 38_612_000 picoseconds. + Weight::from_parts(39_412_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: BridgeRococoMessages PalletOperatingMode (r:1 w:0) - /// Proof: BridgeRococoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) - /// Storage: BridgeRococoParachain ImportedParaHeads (r:1 w:0) - /// Proof: BridgeRococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// Storage: BridgeRococoMessages InboundLanes (r:1 w:1) - /// Proof: BridgeRococoMessages InboundLanes (max_values: None, max_size: Some(49180), added: 51655, 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 Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem RelevantMessagingState (r:1 w:0) - /// Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) - /// Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) - /// Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[128, 2048]`. + /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `635` + // Measured: `669` // Estimated: `52645` - // Minimum execution time: 129_978_000 picoseconds. - Weight::from_parts(98_246_356, 0) + // Minimum execution time: 69_285_000 picoseconds. + Weight::from_parts(70_867_498, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 2_554 - .saturating_add(Weight::from_parts(544_728, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Standard Error: 111 + .saturating_add(Weight::from_parts(7_489, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs deleted file mode 100644 index 6513b63474a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_messages` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_messages -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_messages`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `643` - // Estimated: `52645` - // Minimum execution time: 41_873_000 picoseconds. - Weight::from_parts(43_434_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `643` - // Estimated: `52645` - // Minimum execution time: 53_328_000 picoseconds. - Weight::from_parts(54_592_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `643` - // Estimated: `52645` - // Minimum execution time: 47_486_000 picoseconds. - Weight::from_parts(48_721_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `52645` - // Minimum execution time: 41_093_000 picoseconds. - Weight::from_parts(42_050_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `52645` - // Minimum execution time: 71_947_000 picoseconds. - Weight::from_parts(74_564_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_single_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `3947` - // Minimum execution time: 31_235_000 picoseconds. - Weight::from_parts(32_051_000, 0) - .saturating_add(Weight::from_parts(0, 3947)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `3947` - // Minimum execution time: 31_320_000 picoseconds. - Weight::from_parts(31_973_000, 0) - .saturating_add(Weight::from_parts(0, 3947)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `6086` - // Minimum execution time: 33_656_000 picoseconds. - Weight::from_parts(34_779_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeRococoToWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `772` - // Estimated: `52645` - // Minimum execution time: 61_671_000 picoseconds. - Weight::from_parts(62_656_321, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 25 - .saturating_add(Weight::from_parts(6_641, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs deleted file mode 100644 index e2f58cdfad5..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_wococo.rs +++ /dev/null @@ -1,244 +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. - -//! Autogenerated weights for `pallet_bridge_messages` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_messages -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_messages`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `609` - // Estimated: `52645` - // Minimum execution time: 42_407_000 picoseconds. - Weight::from_parts(43_917_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `609` - // Estimated: `52645` - // Minimum execution time: 53_258_000 picoseconds. - Weight::from_parts(55_144_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `609` - // Estimated: `52645` - // Minimum execution time: 47_950_000 picoseconds. - Weight::from_parts(49_315_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `577` - // Estimated: `52645` - // Minimum execution time: 41_383_000 picoseconds. - Weight::from_parts(42_898_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `577` - // Estimated: `52645` - // Minimum execution time: 72_118_000 picoseconds. - Weight::from_parts(74_643_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_single_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `3913` - // Minimum execution time: 30_993_000 picoseconds. - Weight::from_parts(31_793_000, 0) - .saturating_add(Weight::from_parts(0, 3913)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `3913` - // Minimum execution time: 30_894_000 picoseconds. - Weight::from_parts(31_925_000, 0) - .saturating_add(Weight::from_parts(0, 3913)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `6086` - // Minimum execution time: 33_804_000 picoseconds. - Weight::from_parts(34_560_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoToWococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoToWococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `811` - // Estimated: `52645` - // Minimum execution time: 62_616_000 picoseconds. - Weight::from_parts(64_073_891, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 43 - .saturating_add(Weight::from_parts(6_525, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs deleted file mode 100644 index d9c0fd15468..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_wococo_to_rococo.rs +++ /dev/null @@ -1,244 +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. - -//! Autogenerated weights for `pallet_bridge_messages` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_messages -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_messages`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `537` - // Estimated: `52645` - // Minimum execution time: 42_086_000 picoseconds. - Weight::from_parts(42_833_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `537` - // Estimated: `52645` - // Minimum execution time: 51_927_000 picoseconds. - Weight::from_parts(53_847_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `537` - // Estimated: `52645` - // Minimum execution time: 47_218_000 picoseconds. - Weight::from_parts(48_380_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `52645` - // Minimum execution time: 40_585_000 picoseconds. - Weight::from_parts(41_714_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `52645` - // Minimum execution time: 71_197_000 picoseconds. - Weight::from_parts(73_983_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_single_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `376` - // Estimated: `3841` - // Minimum execution time: 30_823_000 picoseconds. - Weight::from_parts(31_501_000, 0) - .saturating_add(Weight::from_parts(0, 3841)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - // Proof Size summary in bytes: - // Measured: `376` - // Estimated: `3841` - // Minimum execution time: 30_854_000 picoseconds. - Weight::from_parts(31_663_000, 0) - .saturating_add(Weight::from_parts(0, 3841)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) - /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - // Proof Size summary in bytes: - // Measured: `376` - // Estimated: `6086` - // Minimum execution time: 33_463_000 picoseconds. - Weight::from_parts(34_290_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeWococoToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWococoToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`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`) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `739` - // Estimated: `52645` - // Minimum execution time: 61_523_000 picoseconds. - Weight::from_parts(62_686_055, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 26 - .saturating_add(Weight::from_parts(6_563, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index bd7384a05fe..5c7c4a63682 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -1,40 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-yprdrvc7-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: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-rococo-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_bridge_parachains -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bridge_parachains +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,64 +48,63 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_parachains`. pub struct WeightInfo(PhantomData); impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 2]`. + /// Storage: `BridgeWestendParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `434` // Estimated: `2543` - // Minimum execution time: 34_759_000 picoseconds. - Weight::from_parts(35_709_034, 0) + // Minimum execution time: 31_987_000 picoseconds. + Weight::from_parts(33_060_534, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: `BridgeWestendParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `434` // Estimated: `2543` - // Minimum execution time: 36_005_000 picoseconds. - Weight::from_parts(36_492_000, 0) + // Minimum execution time: 33_360_000 picoseconds. + Weight::from_parts(34_182_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: BridgeWococoParachain PalletOperatingMode (r:1 w:0) - /// Proof: BridgeWococoParachain PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: BridgeWococoGrandpa ImportedHeaders (r:1 w:0) - /// Proof: BridgeWococoGrandpa ImportedHeaders (max_values: Some(1024), max_size: Some(68), added: 1553, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ParasInfo (r:1 w:1) - /// Proof: BridgeWococoParachain ParasInfo (max_values: Some(1), max_size: Some(60), added: 555, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHashes (r:1 w:1) - /// Proof: BridgeWococoParachain ImportedParaHashes (max_values: Some(64), max_size: Some(64), added: 1054, mode: MaxEncodedLen) - /// Storage: BridgeWococoParachain ImportedParaHeads (r:0 w:1) - /// Proof: BridgeWococoParachain ImportedParaHeads (max_values: Some(64), max_size: Some(196), added: 1186, mode: MaxEncodedLen) + /// Storage: `BridgeWestendParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeWestendParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) + /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `434` // Estimated: `2543` - // Minimum execution time: 62_374_000 picoseconds. - Weight::from_parts(62_977_000, 0) + // Minimum execution time: 65_246_000 picoseconds. + Weight::from_parts(65_985_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs deleted file mode 100644 index e36bbcca42e..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_rococo.rs +++ /dev/null @@ -1,113 +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. - -//! Autogenerated weights for `pallet_bridge_parachains` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_parachains -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_parachains`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 31_241_000 picoseconds. - Weight::from_parts(32_488_584, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_1kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 32_962_000 picoseconds. - Weight::from_parts(33_658_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_16kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `2543` - // Minimum execution time: 62_685_000 picoseconds. - Weight::from_parts(64_589_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs deleted file mode 100644 index bfe93b4c36a..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_westend.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_bridge_parachains` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_parachains -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_parachains`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `468` - // Estimated: `2543` - // Minimum execution time: 31_493_000 picoseconds. - Weight::from_parts(32_511_270, 0) - .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 33_650 - .saturating_add(Weight::from_parts(20_764, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_1kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `468` - // Estimated: `2543` - // Minimum execution time: 32_976_000 picoseconds. - Weight::from_parts(33_647_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeWestendParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWestendGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWestendParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_16kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `468` - // Estimated: `2543` - // Minimum execution time: 62_898_000 picoseconds. - Weight::from_parts(64_463_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs deleted file mode 100644 index d685daf930f..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains_within_wococo.rs +++ /dev/null @@ -1,115 +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. - -//! Autogenerated weights for `pallet_bridge_parachains` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-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_bridge_parachains -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-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_bridge_parachains`. -pub struct WeightInfo(PhantomData); -impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: `BridgeWococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `435` - // Estimated: `2543` - // Minimum execution time: 31_573_000 picoseconds. - Weight::from_parts(32_739_400, 0) - .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 49_518 - .saturating_add(Weight::from_parts(5_166, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeWococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_1kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `435` - // Estimated: `2543` - // Minimum execution time: 32_780_000 picoseconds. - Weight::from_parts(33_797_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `BridgeWococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgeWococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeWococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeWococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - fn submit_parachain_heads_with_16kb_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `435` - // Estimated: `2543` - // Minimum execution time: 62_847_000 picoseconds. - Weight::from_parts(63_991_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index 48f0c1f949b..70af694645d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -1,24 +1,25 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-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: @@ -55,8 +56,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `207` // Estimated: `3593` - // Minimum execution time: 45_338_000 picoseconds. - Weight::from_parts(45_836_000, 0) + // Minimum execution time: 46_579_000 picoseconds. + Weight::from_parts(48_298_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -71,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `61` // Estimated: `4714` - // Minimum execution time: 23_561_000 picoseconds. - Weight::from_parts(24_012_000, 0) + // Minimum execution time: 24_219_000 picoseconds. + Weight::from_parts(24_993_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -85,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `160` // Estimated: `4714` - // Minimum execution time: 25_133_000 picoseconds. - Weight::from_parts(25_728_000, 0) + // Minimum execution time: 26_279_000 picoseconds. + Weight::from_parts(26_810_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -101,8 +102,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `263` // Estimated: `4714` - // Minimum execution time: 27_356_000 picoseconds. - Weight::from_parts(27_828_000, 0) + // Minimum execution time: 27_672_000 picoseconds. + Weight::from_parts(28_946_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -113,8 +114,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `6` // Estimated: `3538` - // Minimum execution time: 2_955_000 picoseconds. - Weight::from_parts(3_084_000, 0) + // Minimum execution time: 5_487_000 picoseconds. + Weight::from_parts(5_725_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/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 cb7ad7a7803..d7e8c41ff8a 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 @@ -1,24 +1,25 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-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: @@ -53,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 19_037_000 picoseconds. - Weight::from_parts(19_602_000, 3593) + // Minimum execution time: 19_610_000 picoseconds. + Weight::from_parts(19_980_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,15 +65,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 43_115_000 picoseconds. - Weight::from_parts(43_897_000, 6196) + // Minimum execution time: 44_411_000 picoseconds. + Weight::from_parts(45_110_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -89,11 +88,11 @@ 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: `294` + // Measured: `223` // Estimated: `8799` - // Minimum execution time: 90_267_000 picoseconds. - Weight::from_parts(91_460_000, 8799) - .saturating_add(T::DbWeight::get().reads(11)) + // Minimum execution time: 89_739_000 picoseconds. + Weight::from_parts(91_256_000, 8799) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } // Storage: `Benchmark::Override` (r:0 w:0) @@ -105,8 +104,6 @@ impl WeightInfo { // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. Weight::from_parts(18_446_744_073_709_551_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -125,19 +122,19 @@ 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: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_477_000 picoseconds. - Weight::from_parts(61_314_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 60_045_000 picoseconds. + Weight::from_parts(60_710_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_996_000 picoseconds. - Weight::from_parts(3_107_000, 0) + // Minimum execution time: 3_257_000 picoseconds. + Weight::from_parts(3_392_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -145,15 +142,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 18_907_000 picoseconds. - Weight::from_parts(19_475_000, 3593) + // Minimum execution time: 19_423_000 picoseconds. + Weight::from_parts(19_823_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: `System::Account` (r:2 w:2) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // Storage: 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -170,15 +165,13 @@ 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: `193` + // Measured: `122` // Estimated: `6196` - // Minimum execution time: 59_143_000 picoseconds. - Weight::from_parts(60_316_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 60_484_000 picoseconds. + Weight::from_parts(61_634_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -197,11 +190,11 @@ 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: `141` - // Estimated: `3606` - // Minimum execution time: 44_459_000 picoseconds. - Weight::from_parts(45_365_000, 3606) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `70` + // Estimated: `3593` + // Minimum execution time: 44_863_000 picoseconds. + Weight::from_parts(45_549_000, 3593) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 4eee8f0e613..0ae6d0b5623 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,24 +1,25 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-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: @@ -47,8 +48,6 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -67,81 +66,79 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 62_732_000 picoseconds. - Weight::from_parts(64_581_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 63_453_000 picoseconds. + Weight::from_parts(64_220_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_987_000 picoseconds. - Weight::from_parts(2_107_000, 0) + // Minimum execution time: 2_238_000 picoseconds. + Weight::from_parts(2_351_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3568` - // Minimum execution time: 8_098_000 picoseconds. - Weight::from_parts(8_564_000, 3568) + // Measured: `32` + // Estimated: `3497` + // Minimum execution time: 7_953_000 picoseconds. + Weight::from_parts(8_162_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_539_000 picoseconds. - Weight::from_parts(9_085_000, 0) + // Minimum execution time: 9_080_000 picoseconds. + Weight::from_parts(9_333_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_205_000 picoseconds. - Weight::from_parts(2_369_000, 0) + // Minimum execution time: 2_415_000 picoseconds. + Weight::from_parts(2_519_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_828_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 2_045_000 picoseconds. + Weight::from_parts(2_184_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(1_946_000, 0) + // Minimum execution time: 2_065_000 picoseconds. + Weight::from_parts(2_125_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_842_000 picoseconds. - Weight::from_parts(1_949_000, 0) + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_164_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_460_000 picoseconds. - Weight::from_parts(2_593_000, 0) + // Minimum execution time: 2_868_000 picoseconds. + Weight::from_parts(2_933_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 2_058_000 picoseconds. + Weight::from_parts(2_164_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -160,21 +157,21 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_813_000 picoseconds. - Weight::from_parts(57_728_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 55_971_000 picoseconds. + Weight::from_parts(56_869_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } // 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: 11_364_000 picoseconds. - Weight::from_parts(11_872_000, 3625) + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 11_382_000 picoseconds. + Weight::from_parts(11_672_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -182,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_821_000 picoseconds. - Weight::from_parts(1_936_000, 0) + // Minimum execution time: 2_071_000 picoseconds. + Weight::from_parts(2_193_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -201,10 +198,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 23_081_000 picoseconds. - Weight::from_parts(23_512_000, 3574) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 22_573_000 picoseconds. + Weight::from_parts(23_423_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -214,47 +211,45 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_747_000 picoseconds. - Weight::from_parts(4_068_000, 0) + // Minimum execution time: 3_870_000 picoseconds. + Weight::from_parts(3_993_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_045_000 picoseconds. - Weight::from_parts(3_208_000, 0) + // Minimum execution time: 3_483_000 picoseconds. + Weight::from_parts(3_598_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_962_000 picoseconds. - Weight::from_parts(2_284_000, 0) + // Minimum execution time: 2_241_000 picoseconds. + Weight::from_parts(2_297_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_951_000 picoseconds. - Weight::from_parts(2_026_000, 0) + // Minimum execution time: 2_230_000 picoseconds. + Weight::from_parts(2_318_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(2_084_000, 0) + // Minimum execution time: 2_051_000 picoseconds. + Weight::from_parts(2_153_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_042_000 picoseconds. - Weight::from_parts(2_145_000, 0) + // Minimum execution time: 2_306_000 picoseconds. + Weight::from_parts(2_380_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -273,22 +268,20 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 61_350_000 picoseconds. - Weight::from_parts(62_440_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 60_201_000 picoseconds. + Weight::from_parts(61_132_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_993_000 picoseconds. - Weight::from_parts(5_309_000, 0) + // Minimum execution time: 4_554_000 picoseconds. + Weight::from_parts(4_704_000, 0) } - // 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: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -307,70 +300,68 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 57_133_000 picoseconds. - Weight::from_parts(58_100_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 56_071_000 picoseconds. + Weight::from_parts(56_889_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_899_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 2_093_000 picoseconds. + Weight::from_parts(2_169_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 2_027_000 picoseconds. + Weight::from_parts(2_172_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_825_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 2_035_000 picoseconds. + Weight::from_parts(2_164_000, 0) } - // 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: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) + // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) + // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + // Storage: `BridgeWestendMessages::OutboundLanesCongestedSignals` (r:1 w:0) + // Proof: `BridgeWestendMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) + // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `139` - // Estimated: `3604` - // Minimum execution time: 28_419_000 picoseconds. - Weight::from_parts(29_387_791, 3604) - // Standard Error: 552 - .saturating_add(Weight::from_parts(316_277, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `96` + // Estimated: `1529` + // Minimum execution time: 25_636_000 picoseconds. + Weight::from_parts(25_405_640, 1529) + // Standard Error: 321 + .saturating_add(Weight::from_parts(365_002, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_903_000 picoseconds. - Weight::from_parts(2_023_000, 0) + // Minimum execution time: 2_036_000 picoseconds. + Weight::from_parts(2_136_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_143_000, 0) + // Minimum execution time: 2_147_000 picoseconds. + Weight::from_parts(2_276_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 1b1e6f8ba71..1436c5b96a3 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 @@ -16,12 +16,11 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; use crate::bridge_common_config::{ - BridgeGrandpaRococoInstance, BridgeGrandpaWestendInstance, BridgeGrandpaWococoInstance, - DeliveryRewardInBalance, RequiredStakeForStakeAndSlash, + BridgeGrandpaWestendInstance, DeliveryRewardInBalance, RequiredStakeForStakeAndSlash, }; use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; @@ -60,9 +59,9 @@ use xcm_executor::{ }; parameter_types! { - pub storage Flavor: RuntimeFlavor = RuntimeFlavor::default(); pub const TokenLocation: MultiLocation = MultiLocation::parent(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub RelayNetwork: NetworkId = NetworkId::Rococo; pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; @@ -71,22 +70,6 @@ parameter_types! { pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); } -/// 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. @@ -170,8 +153,7 @@ impl Contains for SafeCallFilter { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().all(|(k, _)| { k.eq(&DeliveryRewardInBalance::key()) | - k.eq(&RequiredStakeForStakeAndSlash::key()) | - k.eq(&Flavor::key()) + k.eq(&RequiredStakeForStakeAndSlash::key()) }) => return true, _ => (), @@ -199,17 +181,9 @@ impl Contains for SafeCallFilter { ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | RuntimeCall::MessageQueue(..) | - RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaRococoInstance, - >::initialize { .. }) | RuntimeCall::BridgeWestendGrandpa(pallet_bridge_grandpa::Call::< Runtime, BridgeGrandpaWestendInstance, - >::initialize { .. }) | - RuntimeCall::BridgeWococoGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaWococoInstance, >::initialize { .. }) ) } @@ -298,13 +272,6 @@ impl xcm_executor::Config for XcmConfig { type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, ( - XcmExportFeeToRelayerRewardAccounts< - Self::AssetTransactor, - crate::bridge_to_wococo_config::WococoGlobalConsensusNetwork, - crate::bridge_to_wococo_config::AssetHubWococoParaId, - crate::bridge_to_wococo_config::BridgeHubWococoChainId, - crate::bridge_to_wococo_config::AssetHubRococoToAssetHubWococoMessagesLane, - >, XcmExportFeeToRelayerRewardAccounts< Self::AssetTransactor, crate::bridge_to_westend_config::WestendGlobalConsensusNetwork, @@ -312,21 +279,10 @@ impl xcm_executor::Config for XcmConfig { crate::bridge_to_westend_config::BridgeHubWestendChainId, crate::bridge_to_westend_config::AssetHubRococoToAssetHubWestendMessagesLane, >, - XcmExportFeeToRelayerRewardAccounts< - Self::AssetTransactor, - crate::bridge_to_rococo_config::RococoGlobalConsensusNetwork, - crate::bridge_to_rococo_config::AssetHubRococoParaId, - crate::bridge_to_rococo_config::BridgeHubRococoChainId, - crate::bridge_to_rococo_config::AssetHubWococoToAssetHubRococoMessagesLane, - >, XcmFeeToAccount, ), >; - type MessageExporter = ( - crate::bridge_to_westend_config::ToBridgeHubWestendHaulBlobExporter, - crate::bridge_to_wococo_config::ToBridgeHubWococoHaulBlobExporter, - crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter, - ); + type MessageExporter = (crate::bridge_to_westend_config::ToBridgeHubWestendHaulBlobExporter,); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; 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 39ee2576f5b..9597d71f6b2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -18,8 +18,7 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_common_config, bridge_to_rococo_config, bridge_to_westend_config, - bridge_to_wococo_config, + bridge_common_config, bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, @@ -57,11 +56,7 @@ fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), - ( - bridge_to_wococo_config::OnBridgeHubRococoRefundBridgeHubWococoMessages::default(), - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_rococo_config::OnBridgeHubWococoRefundBridgeHubRococoMessages::default(), - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); @@ -105,18 +100,13 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - Box::new(|call| RuntimeCall::BridgeWococoGrandpa(call).encode()), - ); // for Westend finality bridge_hub_test_utils::test_cases::initialize_bridge_by_governance_works::< Runtime, @@ -195,28 +176,6 @@ mod bridge_hub_rococo_tests { #[test] fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { - // for Wococo - bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< - Runtime, - XcmConfig, - WithBridgeHubWococoMessagesInstance, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeWococoMessages(event)) => Some(event), - _ => None, - } - }), - || ExportMessage { network: Wococo, destination: X1(Parachain(1234)), xcm: Xcm(vec![]) }, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_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_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), - || (), - ); // for Westend bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< Runtime, @@ -243,41 +202,13 @@ mod bridge_hub_rococo_tests { #[test] fn message_dispatch_routing_works() { - // from Wococo - bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - WithBridgeHubWococoMessagesInstance, - RelayNetwork, - WococoGlobalConsensusNetwork, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), - _ => None, - } - }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, - || (), - ); // from Westend bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, ParachainSystem, - WithBridgeHubWococoMessagesInstance, + WithBridgeHubWestendMessagesInstance, RelayNetwork, WestendGlobalConsensusNetwork, >( @@ -303,25 +234,6 @@ mod bridge_hub_rococo_tests { #[test] fn relayed_incoming_message_works() { - // from Wococo - bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - BridgeGrandpaWococoInstance, - BridgeParachainWococoInstance, - WithBridgeHubWococoMessagesInstance, - WithBridgeHubWococoMessageBridge, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Rococo, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, - || (), - ); // from Westend bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< Runtime, @@ -345,29 +257,6 @@ mod bridge_hub_rococo_tests { #[test] pub fn complex_relay_extrinsic_works() { - // for Wococo - bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - BridgeGrandpaWococoInstance, - BridgeParachainWococoInstance, - WithBridgeHubWococoMessagesInstance, - WithBridgeHubWococoMessageBridge, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - BridgeHubWococoChainId::get(), - Rococo, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WOCOCO, - ExistentialDeposit::get(), - executive_init_block, - construct_and_apply_extrinsic, - || (), - ); // for Westend bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< Runtime, @@ -457,275 +346,3 @@ mod bridge_hub_rococo_tests { ); } } - -mod bridge_hub_wococo_tests { - use super::*; - use bridge_common_config::{ - BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, DeliveryRewardInBalance, - RequiredStakeForStakeAndSlash, - }; - use bridge_hub_rococo_runtime::{xcm_config, AllPalletsWithoutSystem, RuntimeFlavor}; - use bridge_to_rococo_config::{ - BridgeHubRococoChainId, RococoGlobalConsensusNetwork, WithBridgeHubRococoMessageBridge, - WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_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, - 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, - } - }), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID - ); - - #[test] - fn initialize_bridge_by_governance_works() { - bridge_hub_test_utils::test_cases::initialize_bridge_by_governance_works::< - Runtime, - BridgeGrandpaRococoInstance, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - Box::new(|call| RuntimeCall::BridgeRococoGrandpa(call).encode()), - ) - } - - #[test] - fn change_delivery_reward_by_governance_works() { - bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< - Runtime, - DeliveryRewardInBalance, - u64, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - Box::new(|call| RuntimeCall::System(call).encode()), - || (DeliveryRewardInBalance::key().to_vec(), DeliveryRewardInBalance::get()), - |old_value| old_value.checked_mul(2).unwrap(), - ) - } - - #[test] - fn change_required_stake_by_governance_works() { - bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< - Runtime, - RequiredStakeForStakeAndSlash, - Balance, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - Box::new(|call| RuntimeCall::System(call).encode()), - || { - ( - RequiredStakeForStakeAndSlash::key().to_vec(), - RequiredStakeForStakeAndSlash::get(), - ) - }, - |old_value| old_value.checked_mul(2).unwrap(), - ) - } - - #[test] - fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { - bridge_hub_test_utils::test_cases::handle_export_message_from_system_parachain_to_outbound_queue_works::< - Runtime, - XcmConfig, - WithBridgeHubRococoMessagesInstance, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::BridgeRococoMessages(event)) => Some(event), - _ => None, - } - }), - || ExportMessage { network: Rococo, destination: X1(Parachain(4321)), xcm: Xcm(vec![]) }, - XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_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_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs::get()).into()), - set_wococo_flavor, - ) - } - - #[test] - fn message_dispatch_routing_works() { - bridge_hub_test_utils::test_cases::message_dispatch_routing_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - WithBridgeHubRococoMessagesInstance, - RelayNetwork, - RococoGlobalConsensusNetwork, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), - _ => None, - } - }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), - XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, - set_wococo_flavor, - ) - } - - #[test] - fn relayed_incoming_message_works() { - bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - BridgeGrandpaRococoInstance, - BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - Wococo, - XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, - set_wococo_flavor, - ) - } - - #[test] - pub fn complex_relay_extrinsic_works() { - bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - ParachainSystem, - BridgeGrandpaRococoInstance, - BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, - >( - collator_session_keys(), - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - BridgeHubRococoChainId::get(), - Wococo, - XCM_LANE_FOR_ASSET_HUB_WOCOCO_TO_ASSET_HUB_ROCOCO, - 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_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs::get(); - assert!( - estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseXcmFeeInWocs` value", - estimated, - max_expected - ); - } - - #[test] - pub fn can_calculate_fee_for_complex_message_delivery_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< - Runtime, - BridgeGrandpaRococoInstance, - BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, - >( - collator_session_keys(), - construct_and_estimate_extrinsic_fee - ); - - // check if estimated value is sane - let max_expected = bp_bridge_hub_wococo::BridgeHubWococoBaseDeliveryFeeInWocs::get(); - assert!( - estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseDeliveryFeeInWocs` value", - estimated, - max_expected - ); - } - - #[test] - pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< - Runtime, - BridgeGrandpaRococoInstance, - BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, - >( - collator_session_keys(), - construct_and_estimate_extrinsic_fee - ); - - // check if estimated value is sane - let max_expected = bp_bridge_hub_wococo::BridgeHubWococoBaseConfirmationFeeInWocs::get(); - assert!( - estimated <= max_expected, - "calculated: {:?}, max_expected: {:?}, please adjust `bp_bridge_hub_wococo::BridgeHubWococoBaseConfirmationFeeInWocs` 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 18181ed3e05..bd171be53bf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -41,8 +41,6 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} # Bridges -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 } bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } @@ -60,8 +58,6 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", de default = [ "std" ] std = [ "asset-test-utils/std", - "bp-bridge-hub-rococo/std", - "bp-bridge-hub-wococo/std", "bp-header-chain/std", "bp-messages/std", "bp-parachains/std", diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index b4a73ff8aaa..a8d3d2975ad 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -32,7 +32,6 @@ 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; @@ -433,6 +432,7 @@ pub fn asset_hub_westend_development_config() -> AssetHubWestendChainSpec { get_account_id_from_seed::("Alice//stash"), get_account_id_from_seed::("Bob//stash"), ], + parachains_common::westend::currency::UNITS * 1_000_000, 1000.into(), )) .with_properties(properties) @@ -478,6 +478,7 @@ pub fn asset_hub_westend_local_config() -> AssetHubWestendChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], + parachains_common::westend::currency::UNITS * 1_000_000, 1000.into(), )) .with_properties(properties) @@ -522,6 +523,7 @@ pub fn asset_hub_westend_config() -> AssetHubWestendChainSpec { ), ], Vec::new(), + ASSET_HUB_WESTEND_ED * 4096, 1000.into(), )) .with_properties(properties) @@ -531,6 +533,7 @@ pub fn asset_hub_westend_config() -> AssetHubWestendChainSpec { fn asset_hub_westend_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, + endowment: AssetHubBalance, id: ParaId, ) -> serde_json::Value { serde_json::json!({ @@ -538,7 +541,7 @@ fn asset_hub_westend_genesis( "balances": endowed_accounts .iter() .cloned() - .map(|k| (k, ASSET_HUB_WESTEND_ED * 4096)) + .map(|k| (k, endowment)) .collect::>(), }, "parachainInfo": { @@ -579,19 +582,6 @@ pub fn asset_hub_rococo_development_config() -> AssetHubRococoChainSpec { ) } -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, @@ -617,6 +607,7 @@ fn asset_hub_rococo_like_development_config( get_account_id_from_seed::("Alice//stash"), get_account_id_from_seed::("Bob//stash"), ], + parachains_common::rococo::currency::UNITS * 1_000_000, para_id.into(), )) .with_properties(properties) @@ -636,19 +627,6 @@ pub fn asset_hub_rococo_local_config() -> AssetHubRococoChainSpec { ) } -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, @@ -688,6 +666,7 @@ fn asset_hub_rococo_like_local_config( get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], + parachains_common::rococo::currency::UNITS * 1_000_000, para_id.into(), )) .with_properties(properties) @@ -735,54 +714,7 @@ pub fn asset_hub_rococo_genesis_config() -> AssetHubRococoChainSpec { ), ], Vec::new(), - para_id.into(), - )) - .with_properties(properties) - .build() -} - -pub fn asset_hub_wococo_genesis_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()); - let para_id = 1000; - AssetHubRococoChainSpec::builder( - asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "wococo".into(), para_id }, - ) - .with_name("Wococo Asset Hub") - .with_id("asset-hub-wococo") - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(asset_hub_rococo_genesis( - // initial collators. - vec![ - // 5C8RGkS8t5K93fB2hkgKbvSYs5iG6AknJMuQmbBDeazon9Lj - ( - hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534").into(), - hex!("02d526f43cf27e94f478f9db785dc86052a77c695e7c855211839d3fde3ce534") - .unchecked_into(), - ), - // 5GePeDZQeBagXH7kH5QPKnQKi39Z5hoYFB5FmUtEvc4yxKej - ( - hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814").into(), - hex!("caa1f623ca183296c4521b56cc29c484ca017830f8cb538f30f2d4664d631814") - .unchecked_into(), - ), - // 5CfnTTb9NMJDNKDntA83mHKoedZ7wjDC8ypLCTDd4NwUx3zv - ( - hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965").into(), - hex!("1ac112d635db2bd34e79ae2b99486cf7c0b71a928668e4feb3dc4633d368f965") - .unchecked_into(), - ), - // 5EqheiwiG22gvGpN7cvrbeaQzhg7rzsYYVkYK4yj5vRrTQRQ - ( - hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66").into(), - hex!("7ac9d11be07334cd27e9eb849f5fc7677a10ad36b6ab38b377d3c8b2c0b08b66") - .unchecked_into(), - ), - ], - Vec::new(), + ASSET_HUB_ROCOCO_ED * 524_288, para_id.into(), )) .with_properties(properties) @@ -792,6 +724,7 @@ pub fn asset_hub_wococo_genesis_config() -> AssetHubWococoChainSpec { fn asset_hub_rococo_genesis( invulnerables: Vec<(AccountId, AuraId)>, endowed_accounts: Vec, + endowment: AssetHubBalance, id: ParaId, ) -> serde_json::Value { serde_json::json!({ @@ -799,7 +732,7 @@ fn asset_hub_rococo_genesis( balances: endowed_accounts .iter() .cloned() - .map(|k| (k, ASSET_HUB_ROCOCO_ED * 524_288)) + .map(|k| (k, endowment)) .collect(), }, "parachainInfo": asset_hub_rococo_runtime::ParachainInfoConfig { diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 71fb9e5b140..94cef106001 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -29,9 +29,6 @@ pub enum BridgeHubRuntimeType { // used by benchmarks RococoDevelopment, - Wococo, - WococoLocal, - Kusama, KusamaLocal, // used by benchmarks @@ -66,8 +63,6 @@ impl FromStr for BridgeHubRuntimeType { rococo::BRIDGE_HUB_ROCOCO => Ok(BridgeHubRuntimeType::Rococo), rococo::BRIDGE_HUB_ROCOCO_LOCAL => Ok(BridgeHubRuntimeType::RococoLocal), rococo::BRIDGE_HUB_ROCOCO_DEVELOPMENT => Ok(BridgeHubRuntimeType::RococoDevelopment), - wococo::BRIDGE_HUB_WOCOCO => Ok(BridgeHubRuntimeType::Wococo), - wococo::BRIDGE_HUB_WOCOCO_LOCAL => Ok(BridgeHubRuntimeType::WococoLocal), _ => Err(format!("Value '{}' is not configured yet", value)), } } @@ -94,8 +89,6 @@ impl BridgeHubRuntimeType { BridgeHubRuntimeType::RococoLocal | BridgeHubRuntimeType::RococoDevelopment => Ok(Box::new(rococo::BridgeHubChainSpec::from_json_file(path)?)), - BridgeHubRuntimeType::Wococo | BridgeHubRuntimeType::WococoLocal => - Ok(Box::new(wococo::BridgeHubChainSpec::from_json_file(path)?)), } } @@ -171,17 +164,6 @@ impl BridgeHubRuntimeType { Some("Bob".to_string()), |_| (), ))), - BridgeHubRuntimeType::Wococo => - Ok(Box::new(wococo::BridgeHubChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/bridge-hub-wococo.json")[..], - )?)), - BridgeHubRuntimeType::WococoLocal => Ok(Box::new(wococo::local_config( - wococo::BRIDGE_HUB_WOCOCO_LOCAL, - "Wococo BridgeHub Local", - "wococo-local", - ParaId::new(1014), - Some("Bob".to_string()), - ))), } } } @@ -309,22 +291,9 @@ pub mod rococo { "polkadotXcm": { "safeXcmVersion": Some(SAFE_XCM_VERSION), }, - - "bridgeWococoGrandpa": { - "owner": bridges_pallet_owner.clone(), - }, "bridgeWestendGrandpa": { "owner": bridges_pallet_owner.clone(), }, - "bridgeRococoGrandpa": { - "owner": bridges_pallet_owner.clone(), - }, - "bridgeRococoMessages": { - "owner": bridges_pallet_owner.clone(), - }, - "bridgeWococoMessages": { - "owner": bridges_pallet_owner.clone(), - }, "bridgeWestendMessages": { "owner": bridges_pallet_owner.clone(), }, @@ -332,37 +301,6 @@ pub mod rococo { } } -/// Sub-module for Wococo setup (reuses stuff from Rococo) -pub mod wococo { - use super::ParaId; - use crate::chain_spec::bridge_hubs::rococo; - - pub(crate) const BRIDGE_HUB_WOCOCO: &str = "bridge-hub-wococo"; - pub(crate) const BRIDGE_HUB_WOCOCO_LOCAL: &str = "bridge-hub-wococo-local"; - - pub type BridgeHubChainSpec = rococo::BridgeHubChainSpec; - pub type RuntimeApi = rococo::RuntimeApi; - - pub fn local_config( - id: &str, - chain_name: &str, - relay_chain: &str, - para_id: ParaId, - bridges_pallet_owner_seed: Option, - ) -> BridgeHubChainSpec { - rococo::local_config( - id, - chain_name, - relay_chain, - para_id, - bridges_pallet_owner_seed, - |properties| { - properties.insert("tokenSymbol".into(), "WOOK".into()); - }, - ) - } -} - /// Sub-module for Kusama setup pub mod kusama { use super::{BridgeHubBalance, ParaId}; diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 2799175b8ee..7bede22fea7 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -43,7 +43,6 @@ enum Runtime { AssetHubPolkadot, AssetHubKusama, AssetHubRococo, - AssetHubWococo, AssetHubWestend, Penpal(ParaId), ContractsRococo, @@ -95,8 +94,6 @@ fn runtime(id: &str) -> Runtime { 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") { @@ -186,19 +183,6 @@ fn load_spec(id: &str) -> std::result::Result, String> { &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_genesis_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()), @@ -302,8 +286,6 @@ fn load_spec(id: &str) -> std::result::Result, String> { 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)?, ), @@ -464,7 +446,7 @@ macro_rules! construct_partials { )?; $code }, - Runtime::AssetHubRococo | Runtime::AssetHubWococo => { + Runtime::AssetHubRococo => { let $partials = new_partial::( &$config, crate::service::aura_build_import_queue::<_, AuraId>, @@ -522,14 +504,6 @@ macro_rules! construct_partials { )?; $code }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Wococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WococoLocal => { - let $partials = new_partial::( - &$config, - crate::service::aura_build_import_queue::<_, AuraId>, - )?; - $code - }, }, Runtime::CollectivesPolkadot => { let $partials = new_partial::( @@ -605,7 +579,7 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - Runtime::AssetHubRococo | Runtime::AssetHubWococo => { + Runtime::AssetHubRococo => { runner.async_run(|$config| { let $components = new_partial::( &$config, @@ -739,18 +713,6 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, - chain_spec::bridge_hubs::BridgeHubRuntimeType::Wococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WococoLocal => { - 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::Penpal(_) | Runtime::Default => { @@ -978,7 +940,7 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), - Runtime::AssetHubRococo | Runtime::AssetHubWococo => crate::service::start_asset_hub_node::< + Runtime::AssetHubRococo => crate::service::start_asset_hub_node::< asset_hub_rococo_runtime::RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) @@ -1077,14 +1039,6 @@ chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), - chain_spec::bridge_hubs::BridgeHubRuntimeType::Wococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WococoLocal => - crate::service::start_generic_aura_node::< - chain_spec::bridge_hubs::wococo::RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) - .await - .map(|r| r.0), } .map_err(Into::into), Runtime::Penpal(_) | Runtime::Default => diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh index 82b5f1942b2..9b3bd350276 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -170,8 +170,6 @@ function run_relay() { --bridge-hub-rococo-port 8943 \ --bridge-hub-rococo-version-mode Auto \ --bridge-hub-rococo-signer //Charlie \ - --westend-headers-to-bridge-hub-rococo-signer //Bob \ - --westend-parachains-to-bridge-hub-rococo-signer //Bob \ --bridge-hub-rococo-transactions-mortality 4 \ --westend-host localhost \ --westend-port 9945 \ @@ -180,8 +178,6 @@ function run_relay() { --bridge-hub-westend-port 8945 \ --bridge-hub-westend-version-mode Auto \ --bridge-hub-westend-signer //Charlie \ - --rococo-headers-to-bridge-hub-westend-signer //Bob \ - --rococo-parachains-to-bridge-hub-westend-signer //Bob \ --bridge-hub-westend-transactions-mortality 4 \ --lane "${LANE_ID}" } @@ -209,7 +205,7 @@ case "$1" in "ws://127.0.0.1:9910" \ "//Alice" \ "$GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000 + 50000000000 * 20)) + $((1000000000000 + 50000000000 * 20)) # HRMP open_hrmp_channels \ "ws://127.0.0.1:9942" \ @@ -227,19 +223,19 @@ case "$1" in "ws://127.0.0.1:8943" \ "//Alice" \ "$ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO" \ - $((1000000000 + 50000000000 * 20)) + $((1000000000000 + 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_00000002_bhwd_ThisChain" \ - $((1000000000 + 2000000000000)) + $((1000000000000 + 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_00000002_bhwd_BridgedChain" \ - $((1000000000 + 2000000000000)) + $((1000000000000 + 2000000000000)) ;; init-asset-hub-westend-local) ensure_polkadot_js_api @@ -258,7 +254,7 @@ case "$1" in "ws://127.0.0.1:9010" \ "//Alice" \ "$GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000 + 50000000000 * 20)) + $((1000000000000000 + 50000000000 * 20)) # HRMP open_hrmp_channels \ "ws://127.0.0.1:9945" \ @@ -275,19 +271,19 @@ case "$1" in "ws://127.0.0.1:8945" \ "//Alice" \ "$ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND" \ - $((1000000000 + 50000000000 * 20)) + $((1000000000000000 + 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_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain" \ - $((1000000000 + 2000000000000)) + $((1000000000000000 + 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_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain" \ - $((1000000000 + 2000000000000)) + $((1000000000000000 + 2000000000000)) ;; reserve-transfer-assets-from-asset-hub-rococo-local) ensure_polkadot_js_api @@ -309,7 +305,7 @@ case "$1" in "//Alice" \ "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": 140000000000 } } ] }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": 40000000000 } } ] }')" \ 0 \ "Unlimited" ;; diff --git a/cumulus/scripts/bridges_rococo_wococo.sh b/cumulus/scripts/bridges_rococo_wococo.sh deleted file mode 100755 index dd7c7062a3b..00000000000 --- a/cumulus/scripts/bridges_rococo_wococo.sh +++ /dev/null @@ -1,386 +0,0 @@ -#!/bin/bash - -# import common functions -source "$(dirname "$0")"/bridges_common.sh - -# Expected sovereign accounts. -# -# 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 bp_messages::LaneId; -# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -# 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 init_ro_wo() { - ensure_relayer - - 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 -} - -function init_wo_ro() { - ensure_relayer - - 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 -} - -function run_relay() { - ensure_relayer - - 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 "${LANE_ID}" -} - -case "$1" in - run-relay) - init_ro_wo - init_wo_ro - run_relay - ;; - init-asset-hub-rococo-local) - ensure_polkadot_js_api - # 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" \ - "$(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)) - ;; - init-asset-hub-wococo-local) - ensure_polkadot_js_api - # 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" \ - "$(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" \ - "$(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" \ - "$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 - ;; - 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)) - ;; - reserve-transfer-assets-from-asset-hub-rococo-local) - ensure_polkadot_js_api - # send ROCs to Alice account on AHW - limited_reserve_transfer_assets \ - "ws://127.0.0.1:9910" \ - "//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" - ;; - reserve-transfer-assets-from-asset-hub-wococo-local) - ensure_polkadot_js_api - # 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" - ;; - claim-rewards-bridge-hub-rococo-local) - ensure_polkadot_js_api - # 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" - ;; - 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 - pkill -f parachain - ;; - import) - # to avoid trigger anything here - ;; - *) - echo "A command is require. Supported commands for: - Local (zombienet) run: - - run-relay - - 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/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml index a117942858e..99a7d0035b5 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml @@ -41,8 +41,7 @@ cumulus_based = true ws_port = 8943 args = [ "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring", - "--", "--rpc-port 48933" + "--force-authoring" ] # run bob as parachain collator @@ -54,8 +53,7 @@ cumulus_based = true ws_port = 8944 args = [ "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring", - "--", "--rpc-port 48934" + "--force-authoring" ] [[parachains]] @@ -69,16 +67,14 @@ cumulus_based = true ws_port = 9910 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--rpc-port 58933" + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] [[parachains.collators]] name = "asset-hub-rococo-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--rpc-port 58833" + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] #[[hrmp_channels]] diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml index 4c345d3825c..1919d1c63f2 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml @@ -41,8 +41,7 @@ cumulus_based = true ws_port = 8945 args = [ "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring", - "--", "--rpc-port 48935" + "--force-authoring" ] # run bob as parachain collator @@ -54,8 +53,7 @@ cumulus_based = true ws_port = 8946 args = [ "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring", - "--", "--rpc-port 48936" + "--force-authoring" ] [[parachains]] @@ -69,16 +67,14 @@ cumulus_based = true ws_port = 9010 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--rpc-port 38933" + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] [[parachains.collators]] name = "asset-hub-westend-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - "--", "--rpc-port 38833" + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] #[[hrmp_channels]] diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml deleted file mode 100644 index ae5cf641f66..00000000000 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml +++ /dev/null @@ -1,94 +0,0 @@ -[settings] -node_spawn_timeout = 240 - -[relaychain] -default_command = "{{POLKADOT_BINARY_PATH}}" -default_args = [ "-lparachain=debug,xcm=trace" ] -chain = "wococo-local" - - [[relaychain.nodes]] - name = "alice-wococo-validator" - validator = true - rpc_port = 9935 - ws_port = 9945 - balance = 2000000000000 - - [[relaychain.nodes]] - name = "bob-wococo-validator" - validator = true - rpc_port = 9936 - ws_port = 9946 - balance = 2000000000000 - - [[relaychain.nodes]] - name = "charlie-wococo-validator" - validator = true - rpc_port = 9937 - ws_port = 9947 - balance = 2000000000000 - -[[parachains]] -id = 1014 -chain = "bridge-hub-wococo-local" -cumulus_based = true - - # run alice as parachain collator - [[parachains.collators]] - 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", - "--force-authoring", - "--", "--port 41335", "--rpc-port 48935" - ] - - # run bob as parachain collator - [[parachains.collators]] - 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", - "--force-authoring", - "--", "--port 41336", "--rpc-port 48936" - ] - -[[parachains]] -id = 1000 -chain = "asset-hub-wococo-local" -cumulus_based = true - - [[parachains.collators]] - 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", - "--", "--port 31333", "--rpc-port 38933" - ] - - [[parachains.collators]] - 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" - ] - -#[[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 -- GitLab From ea4085ab7448bb557a1558a25af164cf364e88d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 15 Nov 2023 23:54:08 +0100 Subject: [PATCH 520/633] frame-system: Add `last_runtime_upgrade_spec_version` (#2351) Adds a function for querying the last runtime upgrade spec version. This can be useful for when writing runtime level migrations to ensure that they are not executed multiple times. An example would be a session key migration. --------- Co-authored-by: Liam Aharon Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + substrate/frame/executive/src/lib.rs | 52 ++++++++++++++-------------- substrate/frame/system/Cargo.toml | 1 + substrate/frame/system/src/lib.rs | 19 ++++++++++ substrate/frame/system/src/tests.rs | 25 ++++++++++++- 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c374a90a18..7854042ddbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5904,6 +5904,7 @@ version = "4.0.0-dev" dependencies = [ "cfg-if", "criterion 0.4.0", + "docify", "frame-support", "log", "parity-scale-codec", diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index e2c906c1bf6..dec1fe158bd 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -487,6 +487,12 @@ where let mut weight = Weight::zero(); if Self::runtime_upgraded() { weight = weight.saturating_add(Self::execute_on_runtime_upgrade()); + + frame_system::LastRuntimeUpgrade::::put( + frame_system::LastRuntimeUpgradeInfo::from( + >::get(), + ), + ); } >::initialize(block_number, parent_hash, digest); weight = weight.saturating_add(::note_finished_initialize(); } - /// Returns if the runtime was upgraded since the last time this function was called. + /// Returns if the runtime has been upgraded, based on [`frame_system::LastRuntimeUpgrade`]. fn runtime_upgraded() -> bool { let last = frame_system::LastRuntimeUpgrade::::get(); let current = >::get(); - if last.map(|v| v.was_upgraded(¤t)).unwrap_or(true) { - frame_system::LastRuntimeUpgrade::::put( - frame_system::LastRuntimeUpgradeInfo::from(current), - ); - true - } else { - false - } + last.map(|v| v.was_upgraded(¤t)).unwrap_or(true) } fn initial_checks(block: &Block) { @@ -755,7 +754,7 @@ mod tests { traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; - use frame_system::{ChainContext, LastRuntimeUpgradeInfo}; + use frame_system::{ChainContext, LastRuntimeUpgrade, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; @@ -994,6 +993,9 @@ mod tests { sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); System::deposit_event(frame_system::Event::CodeUpdated); + + assert_eq!(0, System::last_runtime_upgrade_spec_version()); + Weight::from_parts(100, 0) } } @@ -1356,17 +1358,13 @@ mod tests { new_test_ext(1).execute_with(|| { RuntimeVersionTestValues::mutate(|v| *v = Default::default()); // It should be added at genesis - assert!(frame_system::LastRuntimeUpgrade::::exists()); + assert!(LastRuntimeUpgrade::::exists()); assert!(!Executive::runtime_upgraded()); RuntimeVersionTestValues::mutate(|v| { *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); assert!(Executive::runtime_upgraded()); - assert_eq!( - Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "".into() }), - frame_system::LastRuntimeUpgrade::::get(), - ); RuntimeVersionTestValues::mutate(|v| { *v = sp_version::RuntimeVersion { @@ -1376,27 +1374,18 @@ mod tests { } }); assert!(Executive::runtime_upgraded()); - assert_eq!( - Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), - frame_system::LastRuntimeUpgrade::::get(), - ); RuntimeVersionTestValues::mutate(|v| { *v = sp_version::RuntimeVersion { - spec_version: 1, - spec_name: "test".into(), + spec_version: 0, impl_version: 2, ..Default::default() } }); assert!(!Executive::runtime_upgraded()); - frame_system::LastRuntimeUpgrade::::take(); + LastRuntimeUpgrade::::take(); assert!(Executive::runtime_upgraded()); - assert_eq!( - Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), - frame_system::LastRuntimeUpgrade::::get(), - ); }) } @@ -1444,6 +1433,10 @@ mod tests { assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); + assert_eq!( + Some(RuntimeVersionTestValues::get().into()), + LastRuntimeUpgrade::::get(), + ) }); } @@ -1519,6 +1512,9 @@ mod tests { #[test] fn all_weights_are_recorded_correctly() { + // Reset to get the correct new genesis below. + RuntimeVersionTestValues::take(); + new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called for maximum complexity RuntimeVersionTestValues::mutate(|v| { @@ -1535,6 +1531,10 @@ mod tests { Digest::default(), )); + // Reset the last runtime upgrade info, to make the second call to `on_runtime_upgrade` + // succeed. + LastRuntimeUpgrade::::take(); + // All weights that show up in the `initialize_block_impl` let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); let runtime_upgrade_weight = diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index f7733e312c3..b61b4d531e2 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -25,6 +25,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false, feat sp-std = { path = "../../primitives/std", default-features = false} sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } +docify = "0.2.0" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 0e394a11041..1b8dd6a9367 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -1094,6 +1094,25 @@ pub enum DecRefStatus { } impl Pallet { + /// Returns the `spec_version` of the last runtime upgrade. + /// + /// This function is useful for writing guarded runtime migrations in the runtime. A runtime + /// migration can use the `spec_version` to ensure that it isn't applied twice. This works + /// similar as the storage version for pallets. + /// + /// This functions returns the `spec_version` of the last runtime upgrade while executing the + /// runtime migrations + /// [`on_runtime_upgrade`](frame_support::traits::OnRuntimeUpgrade::on_runtime_upgrade) + /// function. After all migrations are executed, this will return the `spec_version` of the + /// current runtime until there is another runtime upgrade. + /// + /// Example: + #[doc = docify::embed!("src/tests.rs", last_runtime_upgrade_spec_version_usage)] + pub fn last_runtime_upgrade_spec_version() -> u32 { + LastRuntimeUpgrade::::get().map_or(0, |l| l.spec_version.0) + } + + /// Returns true if the given account exists. pub fn account_exists(who: &T::AccountId) -> bool { Account::::contains_key(who) } diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index 165df688b1c..6fbddaaf229 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -19,7 +19,7 @@ use crate::*; use frame_support::{ assert_noop, assert_ok, dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, - traits::WhitelistedStorageKeys, + traits::{OnRuntimeUpgrade, WhitelistedStorageKeys}, }; use std::collections::BTreeSet; @@ -773,3 +773,26 @@ pub fn from_actual_ref_time(ref_time: Option) -> PostDispatchInfo { pub fn from_post_weight_info(ref_time: Option, pays_fee: Pays) -> PostDispatchInfo { PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee } } + +#[docify::export] +#[test] +fn last_runtime_upgrade_spec_version_usage() { + struct Migration; + + impl OnRuntimeUpgrade for Migration { + fn on_runtime_upgrade() -> Weight { + // Ensure to compare the spec version against some static version to prevent applying + // the same migration multiple times. + // + // `1337` here is the spec version of the runtime running on chain. If there is maybe + // a runtime upgrade in the pipeline of being applied, you should use the spec version + // of this upgrade. + if System::last_runtime_upgrade_spec_version() > 1337 { + return Weight::zero(); + } + + // Do the migration. + Weight::zero() + } + } +} -- GitLab From d4c426afd46f43b81115911657ccc0002a361ddb Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:59:06 +0100 Subject: [PATCH 521/633] [ci] Enable zombienet jobs in PRs (#2361) Since preparation for the merge queues needs more time I'm enabling zombienet jobs in PRs CI back. --- .gitlab/pipeline/publish.yml | 2 +- .gitlab/pipeline/zombienet/cumulus.yml | 2 +- .gitlab/pipeline/zombienet/polkadot.yml | 8 ++++---- .gitlab/pipeline/zombienet/substrate.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index f2308c334e0..3cc2002cc1c 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -72,7 +72,7 @@ publish-rustdoc: IMAGE_NAME: "" # docker.io/paritypr/image_name script: # Exit if the job is not running in a merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - $BUILDAH_COMMAND build --format=docker --build-arg VCS_REF="${CI_COMMIT_SHA}" diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index c8a1df004e3..3cac67c2966 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -4,7 +4,7 @@ .zombienet-before-script: before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - echo "Zombie-net Tests Config" - echo "${ZOMBIENET_IMAGE}" - echo "${POLKADOT_IMAGE}" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index cc960557298..995dd982532 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -5,7 +5,7 @@ .zombienet-polkadot-common: before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" # from build-linux-stable job - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} @@ -120,7 +120,7 @@ zombienet-polkadot-smoke-0001-parachains-smoke-test: - .zombienet-polkadot-common before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - echo "Zombienet Tests Config" @@ -139,7 +139,7 @@ zombienet-polkadot-smoke-0002-parachains-parachains-upgrade-smoke: - .zombienet-polkadot-common before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" - echo "Zombienet Tests Config" @@ -183,7 +183,7 @@ zombienet-polkadot-misc-0002-upgrade-node: artifacts: true before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - export ZOMBIENET_INTEGRATION_TEST_IMAGE="docker.io/parity/polkadot:latest" - echo "Overrided poladot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index e627575a31a..6334e7db9a3 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -5,7 +5,7 @@ .zombienet-substrate-common: before_script: # Exit if the job is not merge queue - - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi + # - if [[ $CI_COMMIT_REF_NAME != *"gh-readonly-queue"* ]]; then echo "I will run only in a merge queue"; exit 0; fi - echo "Zombienet Tests Config" - echo "${ZOMBIENET_IMAGE}" - echo "${GH_DIR}" -- GitLab From 02e8061bbadf51bce2f8c419c8645555532c7489 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 16 Nov 2023 17:36:37 +0200 Subject: [PATCH 522/633] westend: remove SessionKeys migration already applied on-chain (#2363) Westend now successfully updated to `spec: 103000`, we **have to remove** the session keys migration before the next release as it doesn't gracefully handle reapplying it. --- polkadot/runtime/westend/src/lib.rs | 48 ----------------------------- 1 file changed, 48 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 2e8394b0ee4..4d537832ae3 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -425,17 +425,6 @@ parameter_types! { pub const Offset: BlockNumber = 0; } -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, @@ -448,32 +437,6 @@ impl_opaque_keys! { } } -// 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; @@ -1560,16 +1523,6 @@ pub type Migrations = migrations::Unreleased; pub mod migrations { use super::*; - /// 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 - } - } - /// Unreleased migrations. Add new ones here: pub type Unreleased = ( pallet_im_online::migration::v1::Migration, @@ -1578,7 +1531,6 @@ pub mod migrations { assigned_slots::migration::v1::MigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, - UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::MigrateToV1, pallet_nomination_pools::migration::versioned_migrations::V5toV6, -- GitLab From 5e98803f032a7c0ac2d8fae6b0cfc76417917e2a Mon Sep 17 00:00:00 2001 From: ordian Date: Thu, 16 Nov 2023 21:13:04 +0100 Subject: [PATCH 523/633] implementers-guide: update github link (#2368) cc @joepetrowski --- polkadot/roadmap/implementers-guide/book.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/roadmap/implementers-guide/book.toml b/polkadot/roadmap/implementers-guide/book.toml index 1e6680f6f4b..f677c0d59c0 100644 --- a/polkadot/roadmap/implementers-guide/book.toml +++ b/polkadot/roadmap/implementers-guide/book.toml @@ -17,6 +17,6 @@ renderer = ["html"] additional-css = ["last-changed.css"] additional-js = ["mermaid.min.js", "mermaid-init.js"] # Repository URL used in the last-changed link. -git-repository-url = "https://github.com/paritytech/polkadot" +git-repository-url = "https://github.com/paritytech/polkadot-sdk" [output.linkcheck] -- GitLab From 4ac2db8095e55a68f9b3d843d4e4689759fcc9d5 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Fri, 17 Nov 2023 00:02:56 +0100 Subject: [PATCH 524/633] Fix Typo: `PalletXcmExtrinsicsBenchmark` (#2354) Missed in https://github.com/paritytech/polkadot-sdk/pull/1672 --- .../parachains/runtimes/assets/asset-hub-kusama/src/lib.rs | 6 +++--- .../runtimes/assets/asset-hub-polkadot/src/lib.rs | 6 +++--- .../parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 6 +++--- .../parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 6 +++--- .../runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs | 6 +++--- .../runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs | 6 +++--- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 6 +++--- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 6 +++--- .../runtimes/collectives/collectives-polkadot/src/lib.rs | 6 +++--- .../runtimes/contracts/contracts-rococo/src/lib.rs | 6 +++--- polkadot/runtime/rococo/src/lib.rs | 6 +++--- polkadot/runtime/westend/src/lib.rs | 6 +++--- 12 files changed, 36 insertions(+), 36 deletions(-) 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 e4ed77884bf..af0116d7014 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -962,7 +962,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1200,7 +1200,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1244,7 +1244,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) 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 6f853b6f56e..1b7ef10f485 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -868,7 +868,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1082,7 +1082,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1125,7 +1125,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 4492971566b..4b4ae61a3e8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -996,7 +996,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToWestend] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1234,7 +1234,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; // This is defined once again in dispatch_benchmark, because list_benchmarks! @@ -1286,7 +1286,7 @@ impl_runtime_apis! { Config as XcmBridgeHubRouterConfig, }; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index cd17b9d86f7..d52edfe479c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1085,7 +1085,7 @@ mod benches { [cumulus_pallet_dmp_queue, DmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1369,7 +1369,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; // This is defined once again in dispatch_benchmark, because list_benchmarks! @@ -1416,7 +1416,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) 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 b3750700084..d2db0340790 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 @@ -490,7 +490,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -670,7 +670,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -706,7 +706,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) 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 841bb4ee861..02f05a8bb87 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 @@ -491,7 +491,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -671,7 +671,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -707,7 +707,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index b8fc2fffc88..5a44ccbb75a 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 @@ -554,7 +554,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_dmp_queue, DmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -784,7 +784,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -826,7 +826,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 9e8fd84e712..d1d2b4a4159 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -544,7 +544,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -772,7 +772,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -814,7 +814,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 206f4614060..c3d671c9085 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -751,7 +751,7 @@ mod benches { [cumulus_pallet_dmp_queue, DmpQueue] [pallet_alliance, Alliance] [pallet_collective, AllianceMotion] - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_preimage, Preimage] [pallet_scheduler, Scheduler] [pallet_referenda, FellowshipReferenda] @@ -939,7 +939,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -969,7 +969,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 4c66e780ba9..5b828bad0c7 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -433,7 +433,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [pallet_contracts, Contracts] - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] ); } @@ -678,7 +678,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -709,7 +709,7 @@ impl_runtime_apis! { impl cumulus_pallet_session_benchmarking::Config for Runtime {} use xcm::latest::prelude::*; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { fn reachable_dest() -> Option { Some(Parent.into()) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 277c9981dab..675e0a20b2b 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1617,7 +1617,7 @@ mod benches { [pallet_asset_rate, AssetRate] [pallet_whitelist, Whitelist] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::] ); @@ -2096,7 +2096,7 @@ sp_api::impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -2115,7 +2115,7 @@ sp_api::impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use sp_storage::TrackedStorageKey; use xcm::latest::prelude::*; use xcm_config::{ diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 4d537832ae3..16a0b112a0b 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1606,7 +1606,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_asset_rate, AssetRate] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -2129,7 +2129,7 @@ sp_api::impl_runtime_apis! { 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_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -2157,7 +2157,7 @@ sp_api::impl_runtime_apis! { 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_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; -- GitLab From 596088a273eff13fbefe6fa20a5fef6507b329cb Mon Sep 17 00:00:00 2001 From: Bruno Galvao Date: Fri, 17 Nov 2023 01:31:31 -0500 Subject: [PATCH 525/633] add pallet nomination-pools versioned migration to kitchensink (#2167) The versioned migrations are already there in pallet nomination-pools: https://github.com/paritytech/polkadot-sdk/blob/f6ee4781f633f0f89598f7b230595afe401da8dc/substrate/frame/nomination-pools/src/migration.rs#L27-L48 Just updating the kitchensink runtime to point to them. This is also nice because it points the dev to an example of how to use `VersionedMigration`. --- polkadot/runtime/westend/src/lib.rs | 4 ++-- substrate/bin/node/runtime/src/lib.rs | 5 +++-- substrate/frame/nomination-pools/src/migration.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 16a0b112a0b..29183fdfe00 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1533,9 +1533,9 @@ pub mod migrations { parachains_configuration::migration::v8::MigrateToV8, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::MigrateToV1, - pallet_nomination_pools::migration::versioned_migrations::V5toV6, + pallet_nomination_pools::migration::versioned::V5toV6, pallet_referenda::migration::v1::MigrateV0ToV1, - pallet_nomination_pools::migration::versioned_migrations::V6ToV7, + pallet_nomination_pools::migration::versioned::V6ToV7, pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, ); diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 90946b71311..d7beb29becf 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2194,9 +2194,10 @@ pub type Executive = frame_executive::Executive< >; // All migrations executed on runtime upgrade as a nested tuple of types implementing -// `OnRuntimeUpgrade`. +// `OnRuntimeUpgrade`. Note: These are examples and do not need to be run directly +// after the genesis block. type Migrations = ( - pallet_nomination_pools::migration::v2::MigrateToV2, + pallet_nomination_pools::migration::versioned::V6ToV7, pallet_alliance::migration::Migration, pallet_contracts::Migration, ); diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index eef2a976f1a..3d68fee1dca 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -24,7 +24,7 @@ use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; use sp_runtime::TryRuntimeError; /// Exports for versioned migration `type`s for this pallet. -pub mod versioned_migrations { +pub mod versioned { use super::*; /// Migration V6 to V7 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring -- GitLab From b85c64aa5fa945027c7a2bfe1788e09309febc7a Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Thu, 16 Nov 2023 23:20:09 -0800 Subject: [PATCH 526/633] fix typo (#2377) --- substrate/frame/proxy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/proxy/README.md b/substrate/frame/proxy/README.md index bfe26d9aefb..c52a881c590 100644 --- a/substrate/frame/proxy/README.md +++ b/substrate/frame/proxy/README.md @@ -2,7 +2,7 @@ A module allowing accounts to give permission to other accounts to dispatch types of calls from their signed origin. -The accounts to which permission is delegated may be requied to announce the action that they +The accounts to which permission is delegated may be required to announce the action that they wish to execute some duration prior to execution happens. In this case, the target account may reject the announcement and in doing so, veto the execution. -- GitLab From 20723ea80e0f442487764a9bcde1d4c989958e56 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 17 Nov 2023 08:21:42 -0300 Subject: [PATCH 527/633] bump zombienet version `v1.3.80` (#2376) New release includes logic to move all jobs to `spot instances`. Thx! --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1dc483004f2..b485ca3317e 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.79" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.80" DOCKER_IMAGES_VERSION: "${CI_COMMIT_SHA}" default: -- GitLab From 2e001de9346257321a8e2447d22e86d7c71a917a Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:48:31 +0100 Subject: [PATCH 528/633] [NPoS] Check if staker is exposed in paged exposure storage entries (#2369) Addresses a bug caused by https://github.com/paritytech/polkadot-sdk/pull/1189. The changes are still not released yet, so would like to push the fix soon so it can go together with the release of the above PR. `fast_unstake` checks if a staker is exposed in an era. However, this fn is still returning whether the staker is exposed based on the old storage item. This PR fixes that by looking in both old and new exposure storages. Also adds some integrity tests for paged exposures. --- substrate/frame/staking/src/pallet/impls.rs | 74 ++++++++++++++++++++- substrate/frame/staking/src/tests.rs | 16 +++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9c36c94b87b..40f30735258 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -794,7 +794,7 @@ impl Pallet { stash: T::AccountId, exposure: Exposure>, ) { - >::insert(¤t_era, &stash, &exposure); + EraInfo::::set_exposure(current_era, &stash, exposure); } #[cfg(feature = "runtime-benchmarks")] @@ -1745,9 +1745,16 @@ impl StakingInterface for Pallet { } fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { + // look in the non paged exposures + // FIXME: Can be cleaned up once non paged exposures are cleared (https://github.com/paritytech/polkadot-sdk/issues/433) ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { validator == *who || exposures.others.iter().any(|i| i.who == *who) }) + || + // look in the paged exposures + ErasStakersPaged::::iter_prefix((era,)).any(|((validator, _), exposure_page)| { + validator == *who || exposure_page.others.iter().any(|i| i.who == *who) + }) } fn status( who: &Self::AccountId, @@ -1812,6 +1819,7 @@ impl Pallet { Self::check_nominators()?; Self::check_exposures()?; + Self::check_paged_exposures()?; Self::check_ledgers()?; Self::check_count() } @@ -1860,6 +1868,70 @@ impl Pallet { .collect::>() } + fn check_paged_exposures() -> Result<(), TryRuntimeError> { + use sp_staking::PagedExposureMetadata; + use sp_std::collections::btree_map::BTreeMap; + + // Sanity check for the paged exposure of the active era. + let mut exposures: BTreeMap>> = + BTreeMap::new(); + let era = Self::active_era().unwrap().index; + let accumulator_default = PagedExposureMetadata { + total: Zero::zero(), + own: Zero::zero(), + nominator_count: 0, + page_count: 0, + }; + + ErasStakersPaged::::iter_prefix((era,)) + .map(|((validator, _page), expo)| { + ensure!( + expo.page_total == + expo.others.iter().map(|e| e.value).fold(Zero::zero(), |acc, x| acc + x), + "wrong total exposure for the page.", + ); + + let metadata = exposures.get(&validator).unwrap_or(&accumulator_default); + exposures.insert( + validator, + PagedExposureMetadata { + total: metadata.total + expo.page_total, + own: metadata.own, + nominator_count: metadata.nominator_count + expo.others.len() as u32, + page_count: metadata.page_count + 1, + }, + ); + + Ok(()) + }) + .collect::>()?; + + exposures + .iter() + .map(|(validator, metadata)| { + let actual_overview = ErasStakersOverview::::get(era, validator); + + ensure!(actual_overview.is_some(), "No overview found for a paged exposure"); + let actual_overview = actual_overview.unwrap(); + + ensure!( + actual_overview.total == metadata.total + actual_overview.own, + "Exposure metadata does not have correct total exposed stake." + ); + ensure!( + actual_overview.nominator_count == metadata.nominator_count, + "Exposure metadata does not have correct count of nominators." + ); + ensure!( + actual_overview.page_count == metadata.page_count, + "Exposure metadata does not have correct count of pages." + ); + + Ok(()) + }) + .collect::>() + } + fn check_nominators() -> Result<(), TryRuntimeError> { // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ee6f67adf14..bac2530b19b 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6637,6 +6637,14 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); assert_eq!(EraInfo::::get_page_count(1, &11), 2); + // validator is exposed + assert!(::is_exposed_in_era(&11, &1)); + // nominators are exposed + for i in 10..15 { + let who: AccountId = 1000 + i; + assert!(::is_exposed_in_era(&who, &1)); + } + // case 2: exposure exist in ErasStakers and ErasStakersClipped (legacy). // delete paged storage and add exposure to clipped storage >::remove((1, 11, 0)); @@ -6672,6 +6680,14 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( assert_eq!(actual_exposure_full.own, 1000); assert_eq!(actual_exposure_full.total, total_exposure); + // validator is exposed + assert!(::is_exposed_in_era(&11, &1)); + // nominators are exposed + for i in 10..15 { + let who: AccountId = 1000 + i; + assert!(::is_exposed_in_era(&who, &1)); + } + // for pages other than 0, clipped storage returns empty exposure assert_eq!(EraInfo::::get_paged_exposure(1, &11, 1), None); // page size is 1 for clipped storage -- GitLab From 3ab2bc9ff3c6ecf14694f01e3c7e8f394219585a Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Fri, 17 Nov 2023 15:24:20 +0200 Subject: [PATCH 529/633] Beefy: small fixes (#2378) Related to #2285 - save the state of the BEEFY gadget after processing a finality proof. We need this in order to avoid skipping blocks. - avoid reprocessing the old state when not necessary --- .../client/consensus/beefy/src/worker.rs | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 309d8c5135b..966c7410365 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -456,6 +456,7 @@ where .filter(|genesis| *genesis == self.persisted_state.pallet_genesis) .ok_or(Error::ConsensusReset)?; + let mut new_session_added = false; if *header.number() > self.best_grandpa_block() { // update best GRANDPA finalized block we have seen self.persisted_state.set_best_grandpa(header.clone()); @@ -475,9 +476,15 @@ where { if let Some(new_validator_set) = find_authorities_change::(&header) { self.init_session_at(new_validator_set, *header.number()); + new_session_added = true; } } + if new_session_added { + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) + .map_err(|e| Error::Backend(e.to_string()))?; + } + // Update gossip validator votes filter. if let Err(e) = self .persisted_state @@ -848,15 +855,10 @@ where .fuse(), ); + self.process_new_state(); let error = loop { - // Act on changed 'state'. - self.process_new_state(); - // Mutable reference used to drive the gossip engine. let mut gossip_engine = &mut self.comms.gossip_engine; - // Use temp val and report after async section, - // to avoid having to Mutex-wrap `gossip_engine`. - let mut gossip_report: Option = None; // Wait for, and handle external events. // The branches below only change 'state', actual voting happens afterwards, @@ -884,10 +886,15 @@ where if let Err(err) = self.triage_incoming_justif(justif) { debug!(target: LOG_TARGET, "🥩 {}", err); } - gossip_report = Some(peer_report); + self.comms.gossip_engine.report(peer_report.who, peer_report.cost_benefit); + }, + ResponseInfo::PeerReport(peer_report) => { + self.comms.gossip_engine.report(peer_report.who, peer_report.cost_benefit); + continue; + }, + ResponseInfo::Pending => { + continue; }, - ResponseInfo::PeerReport(peer_report) => gossip_report = Some(peer_report), - ResponseInfo::Pending => (), } }, justif = block_import_justif.next() => { @@ -924,12 +931,15 @@ where }, // Process peer reports. report = self.comms.gossip_report_stream.next() => { - gossip_report = report; + if let Some(PeerReport { who, cost_benefit }) = report { + self.comms.gossip_engine.report(who, cost_benefit); + } + continue; }, } - if let Some(PeerReport { who, cost_benefit }) = gossip_report { - self.comms.gossip_engine.report(who, cost_benefit); - } + + // Act on changed 'state'. + self.process_new_state(); }; // return error _and_ `comms` that can be reused -- GitLab From 5007e2dd5cb5514fe11ad1bdb21ea9c7fb0ae5ca Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 17 Nov 2023 14:43:37 +0100 Subject: [PATCH 530/633] crypto: `lazy_static` removed, light parser for address URI added (#2250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `lazy_static` package does not work well in `no-std`: it requires `spin_no_std` feature, which also will propagate into `std` if enabled. This is not what we want. This PR provides simple address uri parser which allows to get rid of _regex_ which was used to parse the address uri, what in turns allows to remove lazy_static. Three regular expressions (`SS58_REGEX`,`SECRET_PHRASE_REGEX`,`JUNCTION_REGEX`) were replaced with the parser which unifies all of them. The new parser does not support Unicode, it is ASCII only. Related to: #2044 --------- Co-authored-by: Bastian Köcher Co-authored-by: Koute Co-authored-by: command-bot <> --- Cargo.lock | 45 +- Cargo.toml | 1 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 12 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 12 +- substrate/primitives/core/Cargo.toml | 6 +- substrate/primitives/core/fuzz/Cargo.toml | 20 + .../fuzz/fuzz_targets/fuzz_address_uri.rs | 53 +++ substrate/primitives/core/src/address_uri.rs | 432 ++++++++++++++++++ substrate/primitives/core/src/crypto.rs | 85 ++-- substrate/primitives/core/src/lib.rs | 2 + 10 files changed, 601 insertions(+), 67 deletions(-) create mode 100644 substrate/primitives/core/fuzz/Cargo.toml create mode 100644 substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs create mode 100644 substrate/primitives/core/src/address_uri.rs diff --git a/Cargo.lock b/Cargo.lock index 7854042ddbc..64da4b8996c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7408,6 +7408,17 @@ dependencies = [ "rle-decode-fast", ] +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + [[package]] name = "libloading" version = "0.7.4" @@ -8182,9 +8193,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memfd" @@ -14297,14 +14308,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -14321,10 +14332,16 @@ name = "regex-automata" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -14335,9 +14352,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "remote-ext-tests-bags-list" @@ -17535,6 +17552,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core-fuzz" +version = "0.0.0" +dependencies = [ + "lazy_static", + "libfuzzer-sys", + "regex", + "sp-core", +] + [[package]] name = "sp-core-hashing" version = "9.0.0" diff --git a/Cargo.toml b/Cargo.toml index ed252e07053..57079aa4d03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -405,6 +405,7 @@ members = [ "substrate/primitives/consensus/sassafras", "substrate/primitives/consensus/slots", "substrate/primitives/core", + "substrate/primitives/core/fuzz", "substrate/primitives/core/hashing", "substrate/primitives/core/hashing/proc-macro", "substrate/primitives/crypto/ec-utils", 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 7375bcd2f16..b5d10827524 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 @@ -6,8 +6,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -44,8 +44,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others @@ -81,8 +81,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -119,8 +119,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others @@ -137,8 +137,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -177,8 +177,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others 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 3a0a25712aa..b58902590b8 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 @@ -6,8 +6,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -44,8 +44,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others @@ -81,8 +81,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -119,8 +119,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others @@ -137,8 +137,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -177,8 +177,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Arc Vec and $N others diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 79df81e62c6..9ecce0a22f5 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -26,10 +26,8 @@ bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } bip39 = { version = "2.0.0", default-features = false } -regex = { version = "1.6.0", optional = true } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } -lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.12.1", optional = true } ss58-registry = { version = "1.34.0", default-features = false } sp-std = { path = "../std", default-features = false} @@ -63,6 +61,8 @@ bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "cbc342e", [dev-dependencies] criterion = "0.4.0" serde_json = "1.0.108" +lazy_static = "1.4.0" +regex = "1.6.0" sp-core-hashing-proc-macro = { path = "hashing/proc-macro" } [[bench]] @@ -92,7 +92,6 @@ std = [ "hash256-std-hasher/std", "impl-serde/std", "itertools", - "lazy_static", "libsecp256k1/std", "log/std", "merlin/std", @@ -102,7 +101,6 @@ std = [ "primitive-types/serde", "primitive-types/std", "rand", - "regex", "scale-info/std", "schnorrkel/std", "secp256k1/global-context", diff --git a/substrate/primitives/core/fuzz/Cargo.toml b/substrate/primitives/core/fuzz/Cargo.toml new file mode 100644 index 00000000000..9a094b07d4a --- /dev/null +++ b/substrate/primitives/core/fuzz/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "sp-core-fuzz" +version = "0.0.0" +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies] +lazy_static = "1.4.0" +libfuzzer-sys = "0.4" +regex = "1.10.2" + +sp-core = { path = ".." } + +[[bin]] +name = "fuzz_address_uri" +path = "fuzz_targets/fuzz_address_uri.rs" +test = false +doc = false diff --git a/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs new file mode 100644 index 00000000000..e2d9e2fc8b0 --- /dev/null +++ b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.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. + +#![no_main] + +extern crate libfuzzer_sys; +extern crate regex; +extern crate sp_core; + +use libfuzzer_sys::fuzz_target; +use regex::Regex; +use sp_core::crypto::AddressUri; + +lazy_static::lazy_static! { + static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") + .expect("constructed from known-good static value; qed"); +} + +fuzz_target!(|input: &str| { + let regex_result = SECRET_PHRASE_REGEX.captures(input); + let manual_result = AddressUri::parse(input); + assert_eq!(regex_result.is_some(), manual_result.is_ok()); + if manual_result.is_err() { + let _ = format!("{}", manual_result.as_ref().err().unwrap()); + } + if let (Some(regex_result), Ok(manual_result)) = (regex_result, manual_result) { + assert_eq!(regex_result.name("phrase").map(|p| p.as_str()), manual_result.phrase); + + let manual_paths = manual_result + .paths + .iter() + .map(|s| "/".to_string() + s) + .collect::>() + .join(""); + + assert_eq!(regex_result.name("path").unwrap().as_str().to_string(), manual_paths); + assert_eq!(regex_result.name("password").map(|pass| pass.as_str()), manual_result.pass); + } +}); diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs new file mode 100644 index 00000000000..862747c9a4b --- /dev/null +++ b/substrate/primitives/core/src/address_uri.rs @@ -0,0 +1,432 @@ +// 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. + +//! Little util for parsing an address URI. Replaces regular expressions. + +#[cfg(all(not(feature = "std"), any(feature = "serde", feature = "full_crypto")))] +use sp_std::{ + alloc::string::{String, ToString}, + vec::Vec, +}; + +/// A container for results of parsing the address uri string. +/// +/// Intended to be equivalent of: +/// `Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$")` +/// which also handles soft and hard derivation paths: +/// `Regex::new(r"/(/?[^/]+)")` +/// +/// Example: +/// ``` +/// use sp_core::crypto::AddressUri; +/// let manual_result = AddressUri::parse("hello world/s//h///pass"); +/// assert_eq!( +/// manual_result.unwrap(), +/// AddressUri { phrase: Some("hello world"), paths: vec!["s", "/h"], pass: Some("pass") } +/// ); +/// ``` +#[derive(Debug, PartialEq)] +pub struct AddressUri<'a> { + /// Phrase, hexadecimal string, or ss58-compatible string. + pub phrase: Option<&'a str>, + /// Key derivation paths, ordered as in input string, + pub paths: Vec<&'a str>, + /// Password. + pub pass: Option<&'a str>, +} + +/// Errors that are possible during parsing the address URI. +#[allow(missing_docs)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Error { + #[cfg_attr(feature = "std", error("Invalid character in phrase:\n{0}"))] + InvalidCharacterInPhrase(InvalidCharacterInfo), + #[cfg_attr(feature = "std", error("Invalid character in password:\n{0}"))] + InvalidCharacterInPass(InvalidCharacterInfo), + #[cfg_attr(feature = "std", error("Missing character in hard path:\n{0}"))] + MissingCharacterInHardPath(InvalidCharacterInfo), + #[cfg_attr(feature = "std", error("Missing character in soft path:\n{0}"))] + MissingCharacterInSoftPath(InvalidCharacterInfo), +} + +impl Error { + /// Creates an instance of `Error::InvalidCharacterInPhrase` using given parameters. + pub fn in_phrase(input: &str, pos: usize) -> Self { + Self::InvalidCharacterInPhrase(InvalidCharacterInfo::new(input, pos)) + } + /// Creates an instance of `Error::InvalidCharacterInPass` using given parameters. + pub fn in_pass(input: &str, pos: usize) -> Self { + Self::InvalidCharacterInPass(InvalidCharacterInfo::new(input, pos)) + } + /// Creates an instance of `Error::MissingCharacterInHardPath` using given parameters. + pub fn in_hard_path(input: &str, pos: usize) -> Self { + Self::MissingCharacterInHardPath(InvalidCharacterInfo::new(input, pos)) + } + /// Creates an instance of `Error::MissingCharacterInSoftPath` using given parameters. + pub fn in_soft_path(input: &str, pos: usize) -> Self { + Self::MissingCharacterInSoftPath(InvalidCharacterInfo::new(input, pos)) + } +} + +/// Complementary error information. +/// +/// Strucutre contains complementary information about parsing address URI string. +/// String contains a copy of an original URI string, 0-based integer indicates position of invalid +/// character. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct InvalidCharacterInfo(String, usize); + +impl InvalidCharacterInfo { + fn new(info: &str, pos: usize) -> Self { + Self(info.to_string(), pos) + } +} + +impl sp_std::fmt::Display for InvalidCharacterInfo { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let (s, pos) = escape_string(&self.0, self.1); + write!(f, "{s}\n{i}^", i = sp_std::iter::repeat(" ").take(pos).collect::()) + } +} + +/// Escapes the control characters in given string, and recomputes the position if some characters +/// were actually escaped. +fn escape_string(input: &str, pos: usize) -> (String, usize) { + let mut out = String::with_capacity(2 * input.len()); + let mut out_pos = 0; + input + .chars() + .enumerate() + .map(|(i, c)| { + let esc = |c| (i, Some('\\'), c, 2); + match c { + '\t' => esc('t'), + '\n' => esc('n'), + '\r' => esc('r'), + '\x07' => esc('a'), + '\x08' => esc('b'), + '\x0b' => esc('v'), + '\x0c' => esc('f'), + _ => (i, None, c, 1), + } + }) + .for_each(|(i, maybe_escape, c, increment)| { + maybe_escape.map(|e| out.push(e)); + out.push(c); + if i < pos { + out_pos += increment; + } + }); + (out, out_pos) +} + +fn extract_prefix<'a>(input: &mut &'a str, is_allowed: &dyn Fn(char) -> bool) -> Option<&'a str> { + let output = input.trim_start_matches(is_allowed); + let prefix_len = input.len() - output.len(); + let prefix = if prefix_len > 0 { Some(&input[..prefix_len]) } else { None }; + *input = output; + prefix +} + +fn strip_prefix(input: &mut &str, prefix: &str) -> bool { + if let Some(stripped_input) = input.strip_prefix(prefix) { + *input = stripped_input; + true + } else { + false + } +} + +impl<'a> AddressUri<'a> { + /// Parses the given string. + pub fn parse(mut input: &'a str) -> Result { + let initial_input = input; + let initial_input_len = input.len(); + let phrase = extract_prefix(&mut input, &|ch: char| { + ch.is_ascii_digit() || ch.is_ascii_alphabetic() || ch == ' ' + }); + + let mut pass = None; + let mut paths = Vec::new(); + while !input.is_empty() { + let unstripped_input = input; + if strip_prefix(&mut input, "///") { + pass = Some(extract_prefix(&mut input, &|ch: char| ch != '\n').unwrap_or("")); + } else if strip_prefix(&mut input, "//") { + let path = extract_prefix(&mut input, &|ch: char| ch != '/') + .ok_or(Error::in_hard_path(initial_input, initial_input_len - input.len()))?; + assert!(path.len() > 0); + // hard path shall contain leading '/', so take it from unstripped input. + paths.push(&unstripped_input[1..path.len() + 2]); + } else if strip_prefix(&mut input, "/") { + paths.push( + extract_prefix(&mut input, &|ch: char| ch != '/').ok_or( + Error::in_soft_path(initial_input, initial_input_len - input.len()), + )?, + ); + } else { + return Err(if pass.is_some() { + Error::in_pass(initial_input, initial_input_len - input.len()) + } else { + Error::in_phrase(initial_input, initial_input_len - input.len()) + }); + } + } + + Ok(Self { phrase, paths, pass }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use regex::Regex; + + lazy_static::lazy_static! { + static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") + .expect("constructed from known-good static value; qed"); + } + + fn check_with_regex(input: &str) { + let regex_result = SECRET_PHRASE_REGEX.captures(input); + let manual_result = AddressUri::parse(input); + assert_eq!(regex_result.is_some(), manual_result.is_ok()); + if let (Some(regex_result), Ok(manual_result)) = (regex_result, manual_result) { + assert_eq!( + regex_result.name("phrase").map(|phrase| phrase.as_str()), + manual_result.phrase + ); + + let manual_paths = manual_result + .paths + .iter() + .map(|s| "/".to_string() + s) + .collect::>() + .join(""); + + assert_eq!(regex_result.name("path").unwrap().as_str().to_string(), manual_paths); + assert_eq!( + regex_result.name("password").map(|phrase| phrase.as_str()), + manual_result.pass + ); + } + } + + fn check(input: &str, result: Result) { + let manual_result = AddressUri::parse(input); + assert_eq!(manual_result, result); + check_with_regex(input); + } + + #[test] + fn test00() { + check("///", Ok(AddressUri { phrase: None, pass: Some(""), paths: vec![] })); + } + + #[test] + fn test01() { + check("////////", Ok(AddressUri { phrase: None, pass: Some("/////"), paths: vec![] })) + } + + #[test] + fn test02() { + check( + "sdasd///asda", + Ok(AddressUri { phrase: Some("sdasd"), pass: Some("asda"), paths: vec![] }), + ); + } + + #[test] + fn test03() { + check( + "sdasd//asda", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["/asda"] }), + ); + } + + #[test] + fn test04() { + check("sdasd//a", Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["/a"] })); + } + + #[test] + fn test05() { + let input = "sdasd//"; + check(input, Err(Error::in_hard_path(input, 7))); + } + + #[test] + fn test06() { + check( + "sdasd/xx//asda", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["xx", "/asda"] }), + ); + } + + #[test] + fn test07() { + check( + "sdasd/xx//a/b//c///pass", + Ok(AddressUri { + phrase: Some("sdasd"), + pass: Some("pass"), + paths: vec!["xx", "/a", "b", "/c"], + }), + ); + } + + #[test] + fn test08() { + check( + "sdasd/xx//a", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["xx", "/a"] }), + ); + } + + #[test] + fn test09() { + let input = "sdasd/xx//"; + check(input, Err(Error::in_hard_path(input, 10))); + } + + #[test] + fn test10() { + check( + "sdasd/asda", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["asda"] }), + ); + } + + #[test] + fn test11() { + check( + "sdasd/asda//x", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["asda", "/x"] }), + ); + } + + #[test] + fn test12() { + check("sdasd/a", Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["a"] })); + } + + #[test] + fn test13() { + let input = "sdasd/"; + check(input, Err(Error::in_soft_path(input, 6))); + } + + #[test] + fn test14() { + check("sdasd", Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec![] })); + } + + #[test] + fn test15() { + let input = "sdasd."; + check(input, Err(Error::in_phrase(input, 5))); + } + + #[test] + fn test16() { + let input = "sd.asd/asd.a"; + check(input, Err(Error::in_phrase(input, 2))); + } + + #[test] + fn test17() { + let input = "sd.asd//asd.a"; + check(input, Err(Error::in_phrase(input, 2))); + } + + #[test] + fn test18() { + check( + "sdasd/asd.a", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["asd.a"] }), + ); + } + + #[test] + fn test19() { + check( + "sdasd//asd.a", + Ok(AddressUri { phrase: Some("sdasd"), pass: None, paths: vec!["/asd.a"] }), + ); + } + + #[test] + fn test20() { + let input = "///\n"; + check(input, Err(Error::in_pass(input, 3))); + } + + #[test] + fn test21() { + let input = "///a\n"; + check(input, Err(Error::in_pass(input, 4))); + } + + #[test] + fn test22() { + let input = "sd asd///asd.a\n"; + check(input, Err(Error::in_pass(input, 14))); + } + + #[test] + fn test_invalid_char_info_1() { + let expected = "01234\n^"; + let f = format!("{}", InvalidCharacterInfo::new("01234", 0)); + assert_eq!(expected, f); + } + + #[test] + fn test_invalid_char_info_2() { + let expected = "01\n ^"; + let f = format!("{}", InvalidCharacterInfo::new("01", 1)); + assert_eq!(expected, f); + } + + #[test] + fn test_invalid_char_info_3() { + let expected = "01234\n ^"; + let f = format!("{}", InvalidCharacterInfo::new("01234", 2)); + assert_eq!(expected, f); + } + + #[test] + fn test_invalid_char_info_4() { + let expected = "012\\n456\n ^"; + let f = format!("{}", InvalidCharacterInfo::new("012\n456", 3)); + assert_eq!(expected, f); + } + + #[test] + fn test_invalid_char_info_5() { + let expected = "012\\n456\n ^"; + let f = format!("{}", InvalidCharacterInfo::new("012\n456", 5)); + assert_eq!(expected, f); + } + + #[test] + fn test_invalid_char_info_6() { + let expected = "012\\f456\\t89\n ^"; + let f = format!("{}", InvalidCharacterInfo::new("012\x0c456\t89", 9)); + assert_eq!(expected, f); + } +} diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index d369de5a1c0..c9719e344d3 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -25,8 +25,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use itertools::Itertools; #[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; -#[cfg(feature = "std")] -use regex::Regex; use scale_info::TypeInfo; #[cfg(feature = "std")] pub use secrecy::{ExposeSecret, SecretString}; @@ -43,6 +41,11 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; +#[cfg(feature = "std")] +pub use crate::address_uri::AddressUri; +#[cfg(any(feature = "std", feature = "full_crypto"))] +pub use crate::address_uri::Error as AddressUriError; + /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; @@ -82,8 +85,8 @@ impl> UncheckedInto for S { #[cfg(feature = "full_crypto")] pub enum SecretStringError { /// The overall format was invalid (e.g. the seed phrase contained symbols). - #[cfg_attr(feature = "std", error("Invalid format"))] - InvalidFormat, + #[cfg_attr(feature = "std", error("Invalid format {0}"))] + InvalidFormat(AddressUriError), /// The seed phrase provided is not a valid BIP39 phrase. #[cfg_attr(feature = "std", error("Invalid phrase"))] InvalidPhrase, @@ -101,6 +104,13 @@ pub enum SecretStringError { InvalidPath, } +#[cfg(any(feature = "std", feature = "full_crypto"))] +impl From for SecretStringError { + fn from(e: AddressUriError) -> Self { + Self::InvalidFormat(e) + } +} + /// An error when deriving a key. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] @@ -208,7 +218,7 @@ impl> From for DeriveJunction { /// An error type for SS58 decoding. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[cfg_attr(not(feature = "std"), derive(Debug))] -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq)] #[allow(missing_docs)] #[cfg(any(feature = "full_crypto", feature = "serde"))] pub enum PublicError { @@ -235,6 +245,11 @@ pub enum PublicError { InvalidPath, #[cfg_attr(feature = "std", error("Disallowed SS58 Address Format for this datatype."))] FormatNotAllowed, + #[cfg_attr(feature = "std", error("Password not allowed."))] + PasswordNotAllowed, + #[cfg(feature = "std")] + #[cfg_attr(feature = "std", error("Incorrect URI syntax {0}."))] + MalformedUri(#[from] AddressUriError), } #[cfg(feature = "std")] @@ -414,47 +429,40 @@ pub fn set_default_ss58_version(new_default: Ss58AddressFormat) { DEFAULT_VERSION.store(new_default.into(), core::sync::atomic::Ordering::Relaxed); } -#[cfg(feature = "std")] -lazy_static::lazy_static! { - static ref SS58_REGEX: Regex = Regex::new(r"^(?P[\w\d ]+)?(?P(//?[^/]+)*)$") - .expect("constructed from known-good static value; qed"); - static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P[\d\w ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") - .expect("constructed from known-good static value; qed"); - static ref JUNCTION_REGEX: Regex = Regex::new(r"/(/?[^/]+)") - .expect("constructed from known-good static value; qed"); -} - #[cfg(feature = "std")] impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { fn from_string(s: &str) -> Result { - let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?; - let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS); + let cap = AddressUri::parse(s)?; + if cap.pass.is_some() { + return Err(PublicError::PasswordNotAllowed); + } + let s = cap.phrase.unwrap_or(DEV_ADDRESS); let addr = if let Some(stripped) = s.strip_prefix("0x") { let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?; Self::from_slice(&d).map_err(|()| PublicError::BadLength)? } else { Self::from_ss58check(s)? }; - if cap["path"].is_empty() { + if cap.paths.is_empty() { Ok(addr) } else { - let path = - JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1])); - addr.derive(path).ok_or(PublicError::InvalidPath) + addr.derive(cap.paths.iter().map(DeriveJunction::from)) + .ok_or(PublicError::InvalidPath) } } fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { - let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?; - let (addr, v) = Self::from_ss58check_with_version( - cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS), - )?; - if cap["path"].is_empty() { + let cap = AddressUri::parse(s)?; + if cap.pass.is_some() { + return Err(PublicError::PasswordNotAllowed); + } + let (addr, v) = Self::from_ss58check_with_version(cap.phrase.unwrap_or(DEV_ADDRESS))?; + if cap.paths.is_empty() { Ok((addr, v)) } else { - let path = - JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1])); - addr.derive(path).ok_or(PublicError::InvalidPath).map(|a| (a, v)) + addr.derive(cap.paths.iter().map(DeriveJunction::from)) + .ok_or(PublicError::InvalidPath) + .map(|a| (a, v)) } } } @@ -817,22 +825,15 @@ impl sp_std::str::FromStr for SecretUri { type Err = SecretStringError; fn from_str(s: &str) -> Result { - let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?; - - let junctions = JUNCTION_REGEX - .captures_iter(&cap["path"]) - .map(|f| DeriveJunction::from(&f[1])) - .collect::>(); - - let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE); - let password = cap.name("password"); + let cap = AddressUri::parse(s)?; + let phrase = cap.phrase.unwrap_or(DEV_PHRASE); Ok(Self { phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"), - password: password.map(|v| { - SecretString::from_str(v.as_str()).expect("Returns infallible error; qed") - }), - junctions, + password: cap + .pass + .map(|v| SecretString::from_str(v).expect("Returns infallible error; qed")), + junctions: cap.paths.iter().map(DeriveJunction::from).collect::>(), }) } } diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index ec0641c5466..4873d1a2112 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -55,6 +55,8 @@ pub mod crypto; pub mod hexdisplay; pub use paste; +#[cfg(any(feature = "full_crypto", feature = "std"))] +mod address_uri; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; #[cfg(feature = "bls-experimental")] -- GitLab From 490fb66537c60e1a391350b3f0a786efb7c17373 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 17 Nov 2023 16:40:49 +0200 Subject: [PATCH 531/633] [trivial] asset-hubs runtimes: fix incorrect doc-comments (#2384) Fix some incorrect doc-comments --- .../runtimes/assets/asset-hub-rococo/src/xcm_config.rs | 4 ++-- .../runtimes/assets/asset-hub-westend/src/xcm_config.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index b85cb76642f..6e04924f038 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -109,7 +109,7 @@ pub type CurrencyTransactor = CurrencyAdapter< (), >; -/// `AssetId`/`Balance` converter for `PoolAssets`. +/// `AssetId`/`Balance` converter for `TrustBackedAssets`. pub type TrustBackedAssetsConvertedConcreteId = assets_common::TrustBackedAssetsConvertedConcreteId; @@ -130,7 +130,7 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; -/// `AssetId/Balance` converter for `TrustBackedAssets` +/// `AssetId`/`Balance` converter for `ForeignAssets`. pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< ( // Ignore `TrustBackedAssets` explicitly 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 17312c0f46e..6942559671b 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 @@ -109,7 +109,7 @@ pub type CurrencyTransactor = CurrencyAdapter< (), >; -/// `AssetId/Balance` converter for `TrustBackedAssets` +/// `AssetId`/`Balance` converter for `TrustBackedAssets`. pub type TrustBackedAssetsConvertedConcreteId = assets_common::TrustBackedAssetsConvertedConcreteId; @@ -130,7 +130,7 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; -/// `AssetId/Balance` converter for `TrustBackedAssets` +/// `AssetId`/`Balance` converter for `ForeignAssets`. pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< ( // Ignore `TrustBackedAssets` explicitly -- GitLab From 079b14f624bef9dd901f93c29424cba0ebbd325d Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 17 Nov 2023 18:01:08 +0200 Subject: [PATCH 532/633] Do not panic if the `fdlimit` call to increase the file descriptor limit fails (#2155) # Description Sometimes changing file descriptor limits is not allowed, but there is no need to crash the node if/when this happens. Since `fdlimit`'s author decided to use panics instead of returning `Result`, we need to catch it. # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` 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) --------- Co-authored-by: Koute --- Cargo.lock | 13 +++++++------ substrate/client/cli/Cargo.toml | 2 +- substrate/client/cli/src/config.rs | 23 +++++++++++++++++------ substrate/client/service/test/Cargo.toml | 2 +- substrate/client/service/test/src/lib.rs | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64da4b8996c..da266eb5d47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5342,11 +5342,12 @@ dependencies = [ [[package]] name = "fdlimit" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4c9e43643f5a3be4ca5b67d26b98031ff9db6806c3440ae32e02e3ceac3f1b" +checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5" dependencies = [ "libc", + "thiserror", ] [[package]] @@ -19321,9 +19322,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] @@ -19350,9 +19351,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index c415527c372..c4464c5f787 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "6.1" chrono = "0.4.27" clap = { version = "4.4.6", features = ["derive", "string", "wrap_help"] } -fdlimit = "0.2.1" +fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 4d218da6aa8..b842df5a690 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -605,14 +605,25 @@ pub trait CliConfiguration: Sized { logger.init()?; - if let Some(new_limit) = fdlimit::raise_fd_limit() { - if new_limit < RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT { + match fdlimit::raise_fd_limit() { + Ok(fdlimit::Outcome::LimitRaised { to, .. }) => + if to < RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT { + warn!( + "Low open file descriptor limit configured for the process. \ + Current value: {:?}, recommended value: {:?}.", + to, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT, + ); + }, + Ok(fdlimit::Outcome::Unsupported) => { + // Unsupported platform (non-Linux) + }, + Err(error) => { warn!( - "Low open file descriptor limit configured for the process. \ - Current value: {:?}, recommended value: {:?}.", - new_limit, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT, + "Failed to configure file descriptor limit for the process: \ + {}, recommended value: {:?}.", + error, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT, ); - } + }, } Ok(()) diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index 670312e4161..c6091f97d63 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-channel = "1.8.0" array-bytes = "6.1" -fdlimit = "0.2.1" +fdlimit = "0.3.0" futures = "0.3.21" log = "0.4.17" parity-scale-codec = "3.6.1" diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs index 9700c7643c4..456df73459a 100644 --- a/substrate/client/service/test/src/lib.rs +++ b/substrate/client/service/test/src/lib.rs @@ -285,7 +285,7 @@ where base_port: u16, ) -> TestNet { sp_tracing::try_init_simple(); - fdlimit::raise_fd_limit(); + fdlimit::raise_fd_limit().unwrap(); let runtime = Runtime::new().expect("Error creating tokio runtime"); let mut net = TestNet { runtime, -- GitLab From 0385902cd05523155832b155fe7ce4d1eaf7b779 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 17 Nov 2023 17:06:45 +0100 Subject: [PATCH 533/633] Relax `force_default_xcm_version` for testnet system parachains (#2385) This PR fixes two things: - relax `force_default_xcm_version` for testnet system parachains (e.g. BridgeHubWestend has now 2 and there is no way to change it to 3, so we need to call `force_xcm_version(3)` for every parachain that it is connected to, because we send XCMv3 messages) - add `Storage` item to `PolkadotXcm` pallet definition (now we cannot see storage items for `pallet_xcm` in PJS) ## TODO - [ ] when merged open PR to `polkadot-fellows/runtimes` repo --- .../assets/asset-hub-rococo/src/xcm_config.rs | 16 +++++++++------- .../assets/asset-hub-westend/src/xcm_config.rs | 16 +++++++++------- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../bridge-hub-rococo/src/xcm_config.rs | 16 +++++++++------- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../bridge-hub-westend/src/xcm_config.rs | 16 +++++++++------- .../collectives-westend/src/xcm_config.rs | 6 ++++-- 7 files changed, 42 insertions(+), 32 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 6e04924f038..4da0a2500a5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -275,13 +275,15 @@ impl Contains for SafeCallFilter { 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::PolkadotXcm( + pallet_xcm::Call::force_xcm_version { .. } | + pallet_xcm::Call::force_default_xcm_version { .. } + ) | RuntimeCall::System( + frame_system::Call::set_heap_pages { .. } | + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::kill_prefix { .. }, + ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( 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 6942559671b..4760e087e24 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 @@ -272,13 +272,15 @@ impl Contains for SafeCallFilter { 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::PolkadotXcm( + pallet_xcm::Call::force_xcm_version { .. } | + pallet_xcm::Call::force_default_xcm_version { .. } + ) | RuntimeCall::System( + frame_system::Call::set_heap_pages { .. } | + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::kill_prefix { .. }, + ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( 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 5a44ccbb75a..8e138822696 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 @@ -498,7 +498,7 @@ construct_runtime!( // XCM helpers. XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, + 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, 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 1436c5b96a3..de7b5315c88 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 @@ -161,13 +161,15 @@ impl Contains for SafeCallFilter { 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::PolkadotXcm( + pallet_xcm::Call::force_xcm_version { .. } | + pallet_xcm::Call::force_default_xcm_version { .. } + ) | RuntimeCall::System( + frame_system::Call::set_heap_pages { .. } | + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::kill_prefix { .. }, + ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index d1d2b4a4159..9c97728058f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -497,7 +497,7 @@ construct_runtime!( // XCM helpers. XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, + 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, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 7084882c41f..c89ee91c5e4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -150,13 +150,15 @@ impl Contains for SafeCallFilter { 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::PolkadotXcm( + pallet_xcm::Call::force_xcm_version { .. } | + pallet_xcm::Call::force_default_xcm_version { .. } + ) | RuntimeCall::System( + frame_system::Call::set_heap_pages { .. } | + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::kill_prefix { .. }, + ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index d58995827fa..cefc099c96f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -178,8 +178,10 @@ impl Contains for SafeCallFilter { pallet_collator_selection::Call::add_invulnerable { .. } | pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | - RuntimeCall::XcmpQueue(..) | + RuntimeCall::PolkadotXcm( + pallet_xcm::Call::force_xcm_version { .. } | + pallet_xcm::Call::force_default_xcm_version { .. } + ) | RuntimeCall::XcmpQueue(..) | RuntimeCall::MessageQueue(..) | RuntimeCall::Alliance( // `init_members` accepts unbounded vecs as arguments, -- GitLab From 9e34163aca9d58d7351451833d9cd214b266e7f0 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 17 Nov 2023 17:10:46 +0100 Subject: [PATCH 534/633] Make collator RPC mode non-experimental (#2381) The `--relay-chain-rpc-urls` CLI flag has been available for a while now. We have collators with this running and parachain teams are also using it. It should be fine now to remove the experimental status. --- cumulus/client/cli/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index 1b18ed06437..a2238b73b2b 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -296,7 +296,14 @@ pub struct RunCmd { #[arg(long, conflicts_with = "validator")] pub collator: bool, - /// EXPERIMENTAL: Specify an URL to a relay chain full node to communicate with. + /// Creates a less resource-hungry node that retrieves relay chain data from an RPC endpoint. + /// + /// The provided URLs should point to RPC endpoints of the relay chain. + /// This node connects to the remote nodes following the order they were specified in. If the + /// connection fails, it attempts to connect to the next endpoint in the list. + /// + /// Note: This option doesn't stop the node from connecting to the relay chain network but + /// reduces bandwidth use. #[arg( long, value_parser = validate_relay_chain_url, -- GitLab From 82912acb33a9030c0ef3bf590a34fca09b72dc5f Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 17 Nov 2023 20:14:45 +0400 Subject: [PATCH 535/633] Fix migrations and add CI check for new system chains (#2336) Westend Collectives migration CI check can be fixed once we have https://github.com/paritytech/try-runtime-cli/pull/58, will open another PR once it is available. - [x] Remove deprecated `DmpQueue` pallet from Rococo Contracts, the migration is complete - [x] Fix Asset Hub Rococo storage versions - [x] Add migration check CI for Asset Hub Rococo and Westend Bridge Hub --- .gitlab/pipeline/check.yml | 25 ++++++++ .../assets/asset-hub-rococo/src/lib.rs | 59 ++++++++++++++++++- .../contracts/contracts-rococo/src/lib.rs | 1 - .../contracts-rococo/src/xcm_config.rs | 6 -- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 4071fdf9758..429491fb174 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -151,6 +151,31 @@ check-runtime-migration-asset-hub-westend: PACKAGE: "asset-hub-westend-runtime" WASM: "asset_hub_westend_runtime.compact.compressed.wasm" URI: "wss://westend-asset-hub-rpc.polkadot.io:443" + +check-runtime-migration-asset-hub-rococo: + stage: check + extends: + - .docker-env + - .test-pr-refs + - .check-runtime-migration + variables: + NETWORK: "asset-hub-rococo" + PACKAGE: "asset-hub-rococo-runtime" + WASM: "asset_hub_rococo_runtime.compact.compressed.wasm" + URI: "wss://rococo-asset-hub-rpc.polkadot.io:443" + +# Check runtime migrations for Parity managed bridge hub chains +check-runtime-migration-bridge-hub-westend: + stage: check + extends: + - .docker-env + - .test-pr-refs + - .check-runtime-migration + variables: + NETWORK: "bridge-hub-westend" + PACKAGE: "bridge-hub-westend-runtime" + WASM: "bridge_hub_westend_runtime.compact.compressed.wasm" + URI: "wss://westend-bridge-hub-rpc.polkadot.io:443" check-runtime-migration-bridge-hub-rococo: stage: check diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 4b4ae61a3e8..b274f45877b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -39,7 +39,9 @@ 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}, + traits::{ + AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Saturating, Verify, + }, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Permill, }; @@ -959,7 +961,60 @@ pub type SignedExtra = ( 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, InitStorageVersions); + +/// Migration to initialize storage versions for pallets added after genesis. +/// +/// This is now done automatically (see ), +/// but some pallets had made it in and had storage set in them for this parachain before it was +/// merged. +pub struct InitStorageVersions; + +impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { + fn on_runtime_upgrade() -> Weight { + use frame_support::traits::{GetStorageVersion, StorageVersion}; + + let mut writes = 0; + + if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { + PolkadotXcm::current_storage_version().put::(); + writes.saturating_inc(); + } + + if Multisig::on_chain_storage_version() == StorageVersion::new(0) { + Multisig::current_storage_version().put::(); + writes.saturating_inc(); + } + + if Assets::on_chain_storage_version() == StorageVersion::new(0) { + Assets::current_storage_version().put::(); + writes.saturating_inc(); + } + + if Uniques::on_chain_storage_version() == StorageVersion::new(0) { + Uniques::current_storage_version().put::(); + writes.saturating_inc(); + } + + if Nfts::on_chain_storage_version() == StorageVersion::new(0) { + Nfts::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(7, writes) + } +} /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 5b828bad0c7..9d6a53c5ed3 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -405,7 +405,6 @@ construct_runtime!( 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, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 34, // Smart Contracts. 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 faee1c68fe6..2ac93aed3f8 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -304,9 +304,3 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; - type RuntimeEvent = crate::RuntimeEvent; - type DmpSink = frame_support::traits::EnqueueWithOrigin; -} -- GitLab From 1d1c3719487c8b9f9b770e5c33e8e8b237bd8824 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 17 Nov 2023 23:48:34 +0100 Subject: [PATCH 536/633] Bump bandersnatch VRF revision (#2389) Closes https://github.com/paritytech/polkadot-sdk/issues/2327 cc @burdges --- Cargo.lock | 40 ++++++++++++++-------------- substrate/primitives/core/Cargo.toml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da266eb5d47..ed9997101fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -544,7 +544,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" +source = "git+https://github.com/w3f/ring-vrf?rev=3ddc205#3ddc2051066c4b3f0eadd0ba5700df12500d9754" dependencies = [ "ark-ec", "ark-ff", @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" +source = "git+https://github.com/w3f/ring-vrf?rev=3ddc205#3ddc2051066c4b3f0eadd0ba5700df12500d9754" dependencies = [ "ark-ff", "ark-serialize", @@ -1369,8 +1369,8 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" -version = "0.0.3" -source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" +version = "0.0.4" +source = "git+https://github.com/w3f/ring-vrf?rev=3ddc205#3ddc2051066c4b3f0eadd0ba5700df12500d9754" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1493,8 +1493,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "rand_core 0.6.4", + "rand 0.7.3", + "rand_core 0.5.1", "serde", "unicode-normalization", ] @@ -3065,7 +3065,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" +source = "git+https://github.com/burdges/ring-proof?branch=patch-1#05a756076cb20f981a52afea3a620168de49f95f" dependencies = [ "ark-ec", "ark-ff", @@ -4814,7 +4814,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" +source = "git+https://github.com/w3f/ring-vrf?rev=3ddc205#3ddc2051066c4b3f0eadd0ba5700df12500d9754" dependencies = [ "ark-ec", "ark-ff", @@ -5389,7 +5389,7 @@ dependencies = [ [[package]] name = "fflonk" version = "0.1.0" -source = "git+https://github.com/w3f/fflonk#26a5045b24e169cffc1f9328ca83d71061145c40" +source = "git+https://github.com/w3f/fflonk#1beb0585e1c8488956fac7f05da061f9b41e8948" dependencies = [ "ark-ec", "ark-ff", @@ -14445,7 +14445,7 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" +source = "git+https://github.com/burdges/ring-proof?branch=patch-1#05a756076cb20f981a52afea3a620168de49f95f" dependencies = [ "ark-ec", "ark-ff", @@ -17607,7 +17607,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -17645,7 +17645,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "proc-macro2", "quote", @@ -17665,7 +17665,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "environmental", "parity-scale-codec", @@ -17897,7 +17897,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -17926,7 +17926,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", "proc-macro-crate", @@ -18054,7 +18054,7 @@ version = "8.0.0" [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" [[package]] name = "sp-storage" @@ -18071,7 +18071,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "impl-serde", "parity-scale-codec", @@ -18120,7 +18120,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "parity-scale-codec", "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", @@ -18221,7 +18221,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#fe9435db2fda7c9e2f4e29521564c72cac38f59b" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -20008,7 +20008,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 9ecce0a22f5..25478bed2d9 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -56,7 +56,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 = "cbc342e", default-features = false, optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "3ddc205", default-features = false, optional = true } [dev-dependencies] criterion = "0.4.0" -- GitLab From 794ee98049f546d39923b7f34ffcb7e719ae349d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 13:58:16 +0200 Subject: [PATCH 537/633] Bump secp256k1 from 0.24.3 to 0.28.0 (#2357) Bumps [secp256k1](https://github.com/rust-bitcoin/rust-secp256k1) from 0.24.3 to 0.28.0.